diff --git a/NuGet.config b/NuGet.config index cf37d041..4d736c19 100644 --- a/NuGet.config +++ b/NuGet.config @@ -1,7 +1,7 @@ - + diff --git a/README.md b/README.md index d2c06e17..33fe45ea 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,6 @@ THE SPRING.NET FRAMEWORK --------------------------------------------------------- http://www.springframework.net/ - ## INTRODUCTION Spring.NET contains: @@ -19,23 +18,29 @@ Spring.NET contains: * ASP.NET MVC and ASP.NET WebAPI Framework * Dependency Injection for MVC (includin WebAPI). * Declarative transaction management abstraction - * Declarative transaction management via use of common XML configuration and attributes across different transaction APIs + * Declarative transaction management via use of common XML configuration and attributes across different transaction + APIs * ADO.NET framework - * Simplifies use of ADO.NET. DAO support classes and integration with Spring's declarative transaction management functionality + * Simplifies use of ADO.NET. DAO support classes and integration with Spring's declarative transaction management + functionality * Portable Service Abstractions - * Export plain .NET objects via .NET Remoting, Web Service or .NET Serviced Component and create client side proxies based on endpoint URL and service interface. + * Export plain .NET objects via .NET Remoting, Web Service or .NET Serviced Component and create client side proxies + based on endpoint URL and service interface. * NHibernate Integation - * NHibernate 5 integration to simplify use of NHibernate and participate in Spring's declarative transaction management functionality. + * NHibernate 5 integration to simplify use of NHibernate and participate in Spring's declarative transaction + management functionality. * ASP.NET AJAX Integration * Exporter to expose plain object on which Dependency Injection and AOP have been applied to JavaScript. * NUnit and MSTest integration - * Provides Dependency Injection of test cases and Spring container loading and caching. . Data access and transaction management features aid with integration testing. + * Provides Dependency Injection of test cases and Spring container loading and caching. . Data access and + transaction management features aid with integration testing. * WCF integration * Provides Dependency Injection and applicatin of AOP advice to WCF services * Quartz integration * Configure Quartz jobs using dependency injection and Spring's transactional support to persist job details * MSMQ integration - * Simplifies the use MSMQ by providing helper classes for message sending and receiving. Integrates with Spring's transaction management features. + * Simplifies the use MSMQ by providing helper classes for message sending and receiving. Integrates with Spring's + transaction management features. * NMS integration * Simplifies the use of NMS by providing helper classes for message sending and receiving. * TIBCO EMS integration @@ -43,7 +48,8 @@ Spring.NET contains: * NVelocity integration * Simplifies the use of configuring NVelocity -Spring.NET is a port of the Java based Spring Framework. In turn, the Java/J2EE Spring Framework is based on code published in "Expert One-on-One J2EE Design and Development" by Rod Johnson (Wrox, 2002). +Spring.NET is a port of the Java based Spring Framework. In turn, the Java/J2EE Spring Framework is based on code +published in "Expert One-on-One J2EE Design and Development" by Rod Johnson (Wrox, 2002). ## SUPPORTED .NET FRAMEWORK VERSIONS @@ -64,7 +70,7 @@ Release contents: * `doc` contains reference documentation, MSDN-style API help, and the Spring.NET xsd. * `examples` contains sample applications. * `build-support` contains additonal applications need to build using NAnt as some convenience - VS.NET solution files. + VS.NET solution files. * `dev-support` contains 'developer support' tools and code, such as solution templates for VS.NET debug build is done using /DEBUG:full and release build using /DEBUG:pdbonly flags. @@ -75,74 +81,89 @@ Latest info is available at the public website: http://www.springframework.net/ The Spring Framework is released under the terms of the Apache Software License (see license.txt). - ## DISTRIBUTION DLLs -The "bin" directory contains the following distinct dll files for use in applications. Dependencies are those other than on the .NET BCL. +The "bin" directory contains the following distinct dll files for use in applications. Dependencies are those other than +on the .NET BCL. -* __Spring.Core__ (~765 KB) [![NuGet](http://img.shields.io/nuget/v/Spring.Core.svg)](https://www.nuget.org/packages/Spring.Core/) [![Downloads](https://img.shields.io/nuget/dt/Spring.Core)](#) +* __Spring.Core__ (~765 + KB) [![NuGet](http://img.shields.io/nuget/v/Spring.Core.svg)](https://www.nuget.org/packages/Spring.Core/) [![Downloads](https://img.shields.io/nuget/dt/Spring.Core)](#) * Contents: Inversion of control container. Collection classes. * Dependencies: Common.Logging -* __Spring.Aop__ (~150 KB) [![NuGet](http://img.shields.io/nuget/v/Spring.Aop.svg)](https://www.nuget.org/packages/Spring.Aop/) [![Downloads](https://img.shields.io/nuget/dt/Spring.Aop)](#) +* __Spring.Aop__ (~150 + KB) [![NuGet](http://img.shields.io/nuget/v/Spring.Aop.svg)](https://www.nuget.org/packages/Spring.Aop/) [![Downloads](https://img.shields.io/nuget/dt/Spring.Aop)](#) * Contents: Abstract Oriented Programming Framework. * Dependencies: Spring.Core, Common.Logging -* __Spring.Data__ (~320 KB) [![NuGet](http://img.shields.io/nuget/v/Spring.Data.svg)](https://www.nuget.org/packages/Spring.Data/) [![Downloads](https://img.shields.io/nuget/dt/Spring.Data)](#) +* __Spring.Data__ (~320 + KB) [![NuGet](http://img.shields.io/nuget/v/Spring.Data.svg)](https://www.nuget.org/packages/Spring.Data/) [![Downloads](https://img.shields.io/nuget/dt/Spring.Data)](#) * Contents: Transaction and ADO.NET Framework. * Dependencies: Spring.Core, Spring.Aop -* __Spring.Data.NHibernate5__ (~90 KB) [![NuGet](http://img.shields.io/nuget/v/Spring.Data.NHibernate5.svg)](https://www.nuget.org/packages/Spring.Data.NHibernate5/) [![Downloads](https://img.shields.io/nuget/dt/Spring.Data.NHibernate5)](#) +* __Spring.Data.NHibernate5__ (~90 + KB) [![NuGet](http://img.shields.io/nuget/v/Spring.Data.NHibernate5.svg)](https://www.nuget.org/packages/Spring.Data.NHibernate5/) [![Downloads](https://img.shields.io/nuget/dt/Spring.Data.NHibernate5)](#) * Contents: NHibernate 5.x integration * Dependencies: Spring.Core, Spring.Aop, Spring.Data, NHibernate -* __Spring.Services__ (~70 KB) [![NuGet](http://img.shields.io/nuget/v/Spring.Services.svg)](https://www.nuget.org/packages/Spring.Services/) [![Downloads](https://img.shields.io/nuget/dt/Spring.Services)](#) +* __Spring.Services__ (~70 + KB) [![NuGet](http://img.shields.io/nuget/v/Spring.Services.svg)](https://www.nuget.org/packages/Spring.Services/) [![Downloads](https://img.shields.io/nuget/dt/Spring.Services)](#) * Contents: Web Services, Remoting, and Enterprise Component based services. * Dependencies: Spring.Core, Spring.Aop -* __Spring.Web__ (~165 KB) [![NuGet](http://img.shields.io/nuget/v/Spring.Web.svg)](https://www.nuget.org/packages/Spring.Web/) [![Downloads](https://img.shields.io/nuget/dt/Spring.Web)](#) +* __Spring.Web__ (~165 + KB) [![NuGet](http://img.shields.io/nuget/v/Spring.Web.svg)](https://www.nuget.org/packages/Spring.Web/) [![Downloads](https://img.shields.io/nuget/dt/Spring.Web)](#) * Contents: ASP.NET based Web Application Framework. * Dependencies: Spring.Core, Spring.Aop -* __Spring.Web.Extensions__ (~8 KB) [![NuGet](http://img.shields.io/nuget/v/Spring.Web.Extensions.svg)](https://www.nuget.org/packages/Spring.Web.Extensions/) [![Downloads](https://img.shields.io/nuget/dt/Spring.Web.Extensions)](#) +* __Spring.Web.Extensions__ (~8 + KB) [![NuGet](http://img.shields.io/nuget/v/Spring.Web.Extensions.svg)](https://www.nuget.org/packages/Spring.Web.Extensions/) [![Downloads](https://img.shields.io/nuget/dt/Spring.Web.Extensions)](#) * Contents: ASP.NET AJAX Integartion * Dependencies: Spring.Core, Spring.Aop, System.Web.Extensions -* __Spring.Web.Mvc5__ (~8 KB) [![NuGet](http://img.shields.io/nuget/v/Spring.Web.Mvc5.svg)](https://www.nuget.org/packages/Spring.Web.Mvc5/) [![Downloads](https://img.shields.io/nuget/dt/Spring.Web.Mvc5)](#) +* __Spring.Web.Mvc5__ (~8 + KB) [![NuGet](http://img.shields.io/nuget/v/Spring.Web.Mvc5.svg)](https://www.nuget.org/packages/Spring.Web.Mvc5/) [![Downloads](https://img.shields.io/nuget/dt/Spring.Web.Mvc5)](#) * Contents: ASP.NET MVC5 and WebAPI Integartion * Dependencies: Spring.Core, Spring.Web -* __Spring.Testing.NUnit__ (~24 KB) [![NuGet](http://img.shields.io/nuget/v/Spring.Testing.NUnit.svg)](https://www.nuget.org/packages/Spring.Testing.NUnit/) [![Downloads](https://img.shields.io/nuget/dt/Spring.Testing.NUnit)](#) +* __Spring.Testing.NUnit__ (~24 + KB) [![NuGet](http://img.shields.io/nuget/v/Spring.Testing.NUnit.svg)](https://www.nuget.org/packages/Spring.Testing.NUnit/) [![Downloads](https://img.shields.io/nuget/dt/Spring.Testing.NUnit)](#) * Contents: NUnit Integration * Dependencies: Spring.Core, Spring.Data, NUnit -* __Spring.Testing.Microsoft__ (~24 KB) [![NuGet](http://img.shields.io/nuget/v/Spring.Testing.Microsoft.svg)](https://www.nuget.org/packages/Spring.Testing.Microsoft/) [![Downloads](https://img.shields.io/nuget/dt/Spring.Testing.Microsoft)](#) +* __Spring.Testing.Microsoft__ (~24 + KB) [![NuGet](http://img.shields.io/nuget/v/Spring.Testing.Microsoft.svg)](https://www.nuget.org/packages/Spring.Testing.Microsoft/) [![Downloads](https://img.shields.io/nuget/dt/Spring.Testing.Microsoft)](#) * Contents: MSTest Integration * Dependencies: Spring.Core, Spring.Data, MSTest -* __Spring.Messaging__ (~65 KB) [![NuGet](http://img.shields.io/nuget/v/Spring.Messaging.svg)](https://www.nuget.org/packages/Spring.Messaging/) [![Downloads](https://img.shields.io/nuget/dt/Spring.Messaging)](#) +* __Spring.Messaging__ (~65 + KB) [![NuGet](http://img.shields.io/nuget/v/Spring.Messaging.svg)](https://www.nuget.org/packages/Spring.Messaging/) [![Downloads](https://img.shields.io/nuget/dt/Spring.Messaging)](#) * Contents: MSMQ Integration * Dependencies: Spring.Core, Spring.Data, System.Messaging -* __Spring.Messaging.Nms__ (~100 KB) [![NuGet](http://img.shields.io/nuget/v/Spring.Messaging.Nms.svg)](https://www.nuget.org/packages/Spring.Messaging.Nms/) [![Downloads](https://img.shields.io/nuget/dt/Spring.Messaging.Nms)](#) +* __Spring.Messaging.Nms__ (~100 + KB) [![NuGet](http://img.shields.io/nuget/v/Spring.Messaging.Nms.svg)](https://www.nuget.org/packages/Spring.Messaging.Nms/) [![Downloads](https://img.shields.io/nuget/dt/Spring.Messaging.Nms)](#) * Contents: NMS Integration * Dependencies: Spring.Core, Spring.Data, Apache NMS -* __Spring.Scheduling.Quartz3__ (~44 KB) [![NuGet](http://img.shields.io/nuget/v/Spring.Scheduling.Quartz3.svg)](https://www.nuget.org/packages/Spring.Scheduling.Quartz3/) [![Downloads](https://img.shields.io/nuget/dt/Spring.Scheduling.Quartz3)](#) +* __Spring.Scheduling.Quartz3__ (~44 + KB) [![NuGet](http://img.shields.io/nuget/v/Spring.Scheduling.Quartz3.svg)](https://www.nuget.org/packages/Spring.Scheduling.Quartz3/) [![Downloads](https://img.shields.io/nuget/dt/Spring.Scheduling.Quartz3)](#) * Contents: Quartz32.x Integration * Dependencies: Spring.Core, Spring.Data, Quartz -* __Spring.Template.Velocity__ (~44 KB) [![NuGet](http://img.shields.io/nuget/v/Spring.Template.Velocity.svg)](https://www.nuget.org/packages/Spring.Template.Velocity/) [![Downloads](https://img.shields.io/nuget/dt/Spring.Template.Velocity)](#) +* __Spring.Template.Velocity__ (~44 + KB) [![NuGet](http://img.shields.io/nuget/v/Spring.Template.Velocity.svg)](https://www.nuget.org/packages/Spring.Template.Velocity/) [![Downloads](https://img.shields.io/nuget/dt/Spring.Template.Velocity)](#) * Contents: NVelocity Integration * Dependencies: Spring.Core, NVelocity - ## WHERE TO START? Documentation can be found in the "docs" directory: + * The Spring reference documentation Documented sample applications can be found in "examples": + * IoCQuickStart.MovieFinder - A simple example demonstrating basic IoC container behavior. * IoCQuickStart.AppContext - Show use of various IApplicationContext features. * IoCQuickStart.EventRegistry - Show use of loosely coupled eventing features. @@ -166,7 +187,8 @@ Documented sample applications can be found in "examples": VS.NET ------ -Visual Studio 2022 is required to open and build the solution. The free community version of Visual Studio should suffice. +Visual Studio 2022 is required to open and build the solution. The free community version of Visual Studio should +suffice. ## Acknowledgements diff --git a/build-support/nuke-build/Build.GitHubActions.cs b/build-support/nuke-build/Build.GitHubActions.cs index 698e3186..f61ff311 100644 --- a/build-support/nuke-build/Build.GitHubActions.cs +++ b/build-support/nuke-build/Build.GitHubActions.cs @@ -5,4 +5,4 @@ public partial class Build Target Ci => _ => _ .DependsOn(Compile, Test, Pack) .Executes(); -} \ No newline at end of file +} diff --git a/build-support/nuke-build/Build.Publish.cs b/build-support/nuke-build/Build.Publish.cs index 4bf63ae0..205568b6 100644 --- a/build-support/nuke-build/Build.Publish.cs +++ b/build-support/nuke-build/Build.Publish.cs @@ -3,7 +3,6 @@ using Nuke.Common; using Nuke.Common.IO; using Nuke.Common.Tooling; using Nuke.Common.Tools.DotNet; - using static Nuke.Common.Tools.DotNet.DotNetTasks; public partial class Build @@ -39,5 +38,4 @@ public partial class Build bool PushCompleteOnFailure => true; int PushDegreeOfParallelism => 5; - } diff --git a/build-support/nuke-build/Build.Test.cs b/build-support/nuke-build/Build.Test.cs index cfdc1622..fd1a0f5e 100644 --- a/build-support/nuke-build/Build.Test.cs +++ b/build-support/nuke-build/Build.Test.cs @@ -1,21 +1,15 @@ using System.Linq; using Nuke.Common; using Nuke.Common.Tools.DotNet; - using static Nuke.Common.Tools.DotNet.DotNetTasks; public partial class Build { - [Parameter] - readonly bool TestFull = false; - [Parameter] - readonly bool TestIntegrationData = false; - [Parameter] - readonly bool TestIntegrationEms = false; - [Parameter] - readonly bool TestIntegrationNms = false; - [Parameter] - readonly bool TestIntegrationMsMq = false; + [Parameter] readonly bool TestFull = false; + [Parameter] readonly bool TestIntegrationData = false; + [Parameter] readonly bool TestIntegrationEms = false; + [Parameter] readonly bool TestIntegrationNms = false; + [Parameter] readonly bool TestIntegrationMsMq = false; Target Test => _ => _ .DependsOn(Restore) @@ -55,5 +49,4 @@ public partial class Build }); } }); - -} \ No newline at end of file +} diff --git a/build-support/nuke-build/Build.cs b/build-support/nuke-build/Build.cs index 412f9552..995fb056 100644 --- a/build-support/nuke-build/Build.cs +++ b/build-support/nuke-build/Build.cs @@ -27,17 +27,13 @@ partial class Build : NukeBuild /// - JetBrains Rider https://nuke.build/rider /// - Microsoft VisualStudio https://nuke.build/visualstudio /// - Microsoft VSCode https://nuke.build/vscode + public static int Main() => Execute(x => x.Compile); - public static int Main () => Execute(x => x.Compile); + [Parameter("Configuration to build - Default is 'Debug' (local) or 'Release' (server)")] readonly Configuration Configuration = IsLocalBuild ? Configuration.Debug : Configuration.Release; - [Parameter("Configuration to build - Default is 'Debug' (local) or 'Release' (server)")] - readonly Configuration Configuration = IsLocalBuild ? Configuration.Debug : Configuration.Release; + [Parameter("Build EMS")] readonly bool BuildEms = false; - [Parameter("Build EMS")] - readonly bool BuildEms = false; - - [Parameter("Version")] - readonly string ProjectVersion = "3.1.0"; + [Parameter("Version")] readonly string ProjectVersion = "3.1.0"; [Solution] readonly Solution Solution; [GitRepository] readonly GitRepository GitRepository; @@ -180,35 +176,10 @@ partial class Build : NukeBuild var binDirectory = RootDirectory / "bin"; binDirectory.CreateOrCleanDirectory(); - var moduleNames = new[] - { - "Common.Logging", - "Common.Logging.Core", - "Spring.Core", - "Spring.Aop", - "Spring.Data", - "Spring.Data.NHibernate*", - "Spring.Web", - "Spring.Web.Mvc5", - "Spring.Web.Extensions", - "Spring.Services", - "Spring.Testing.NUnit", - "Spring.Testing.Microsoft", - "Spring.Messaging.Ems", - "Spring.Messaging.Nms", - "Spring.Messaging", - "Spring.Scheduling.Quartz3", - "Spring.Template.Velocity", - "Spring.Web.Conversation.NHibernate5", - }; + var moduleNames = new[] { "Common.Logging", "Common.Logging.Core", "Spring.Core", "Spring.Aop", "Spring.Data", "Spring.Data.NHibernate*", "Spring.Web", "Spring.Web.Mvc5", "Spring.Web.Extensions", "Spring.Services", "Spring.Testing.NUnit", "Spring.Testing.Microsoft", "Spring.Messaging.Ems", "Spring.Messaging.Nms", "Spring.Messaging", "Spring.Scheduling.Quartz3", "Spring.Template.Velocity", "Spring.Web.Conversation.NHibernate5", }; var patterns = moduleNames - .SelectMany(x => new [] - { - "**/" + Configuration + "/**/" + x + ".dll", - "**/" + Configuration + "/**/" + x + ".xml", - "**/" + Configuration + "/**/" + x + ".pdb" - }) + .SelectMany(x => new[] { "**/" + Configuration + "/**/" + x + ".dll", "**/" + Configuration + "/**/" + x + ".xml", "**/" + Configuration + "/**/" + x + ".pdb" }) .ToArray(); foreach (var file in BuildDirectory.GlobFiles(patterns)) diff --git a/examples/Directory.Build.props b/examples/Directory.Build.props index 298ab058..8169e2e2 100644 --- a/examples/Directory.Build.props +++ b/examples/Directory.Build.props @@ -2,8 +2,8 @@ - $(MSBuildProjectName.Replace('.2010', '')) - + $(MSBuildProjectName.Replace('.2010', '')) + $(CleanedProjectName) $(CleanedProjectName) Spring diff --git a/src/Spring/Spring.Aop/Aop/Config/AopNamespaceParser.cs b/src/Spring/Spring.Aop/Aop/Config/AopNamespaceParser.cs index d75f05e7..5fd5d311 100644 --- a/src/Spring/Spring.Aop/Aop/Config/AopNamespaceParser.cs +++ b/src/Spring/Spring.Aop/Aop/Config/AopNamespaceParser.cs @@ -20,35 +20,34 @@ using Spring.Objects.Factory.Xml; -namespace Spring.Aop.Config +namespace Spring.Aop.Config; + +/// +/// Namespace parser for the aop namespace. +/// +/// +/// Using the advisor tag you can configure an and have it +/// applied to all the relevant objects in your application context automatically. The +/// advisor tag supports only referenced s. +/// +/// Rob harrop +/// Adrian Colyer +/// Rod Johnson +/// Mark Pollack (.NET) +[ + NamespaceParser( + Namespace = "http://www.springframework.net/aop", + SchemaLocationAssemblyHint = typeof(AopNamespaceParser), + SchemaLocation = "/Spring.Aop.Config/spring-aop-1.1.xsd" + ) +] +public class AopNamespaceParser : NamespaceParserSupport { /// - /// Namespace parser for the aop namespace. + /// Register the for the 'config' tag. /// - /// - /// Using the advisor tag you can configure an and have it - /// applied to all the relevant objects in your application context automatically. The - /// advisor tag supports only referenced s. - /// - /// Rob harrop - /// Adrian Colyer - /// Rod Johnson - /// Mark Pollack (.NET) - [ - NamespaceParser( - Namespace = "http://www.springframework.net/aop", - SchemaLocationAssemblyHint = typeof (AopNamespaceParser), - SchemaLocation = "/Spring.Aop.Config/spring-aop-1.1.xsd" - ) - ] - public class AopNamespaceParser : NamespaceParserSupport + public override void Init() { - /// - /// Register the for the 'config' tag. - /// - public override void Init() - { - RegisterObjectDefinitionParser("config", new ConfigObjectDefinitionParser()); - } + RegisterObjectDefinitionParser("config", new ConfigObjectDefinitionParser()); } } \ No newline at end of file diff --git a/src/Spring/Spring.Aop/Aop/Config/AopNamespaceUtils.cs b/src/Spring/Spring.Aop/Aop/Config/AopNamespaceUtils.cs index 9bb596c0..e96ccd6f 100644 --- a/src/Spring/Spring.Aop/Aop/Config/AopNamespaceUtils.cs +++ b/src/Spring/Spring.Aop/Aop/Config/AopNamespaceUtils.cs @@ -29,67 +29,66 @@ using Spring.Util; #endregion -namespace Spring.Aop.Config +namespace Spring.Aop.Config; + +/// +/// Utility class for handling registration of auto-proxy creators used internally by the +/// aop and tx namespace tags. +/// +/// Rob Harrop +/// Juergen Hoeller +/// Mark Pollack (.NET) +/// Erich Eichinger (.NET) +public class AopNamespaceUtils { /// - /// Utility class for handling registration of auto-proxy creators used internally by the - /// aop and tx namespace tags. + /// The object name of the internally managed auto-proxy creator. /// - /// Rob Harrop - /// Juergen Hoeller - /// Mark Pollack (.NET) - /// Erich Eichinger (.NET) - public class AopNamespaceUtils + public static readonly string AUTO_PROXY_CREATOR_OBJECT_NAME = "Spring.Aop.Config.InternalAutoProxyCreator"; + + /// + /// The type of the APC that handles advisors with object role . + /// + private static readonly Type InfrastructureAutoProxyCreatorType = typeof(InfrastructureAdvisorAutoProxyCreator); + + /// + /// Registers the internal auto proxy creator if necessary. + /// + /// The parser context. + /// The source element. + public static void RegisterAutoProxyCreatorIfNecessary(ParserContext parserContext, XmlElement sourceElement) { - /// - /// The object name of the internally managed auto-proxy creator. - /// - public static readonly string AUTO_PROXY_CREATOR_OBJECT_NAME = "Spring.Aop.Config.InternalAutoProxyCreator"; + AssertUtils.ArgumentNotNull(parserContext, "parserContext"); + IObjectDefinitionRegistry registry = parserContext.Registry; + RegisterAutoProxyCreatorIfNecessary(registry); + } - /// - /// The type of the APC that handles advisors with object role . - /// - private static readonly Type InfrastructureAutoProxyCreatorType = typeof(InfrastructureAdvisorAutoProxyCreator); + /// + /// Registers the internal auto proxy creator if necessary. + /// + public static void RegisterAutoProxyCreatorIfNecessary(IObjectDefinitionRegistry registry) + { + AssertUtils.ArgumentNotNull(registry, "registry"); - /// - /// Registers the internal auto proxy creator if necessary. - /// - /// The parser context. - /// The source element. - public static void RegisterAutoProxyCreatorIfNecessary(ParserContext parserContext, XmlElement sourceElement) + if (!registry.ContainsObjectDefinition(AUTO_PROXY_CREATOR_OBJECT_NAME)) { - AssertUtils.ArgumentNotNull(parserContext, "parserContext"); - IObjectDefinitionRegistry registry = parserContext.Registry; - RegisterAutoProxyCreatorIfNecessary(registry); + RootObjectDefinition objectDefinition = new RootObjectDefinition(InfrastructureAutoProxyCreatorType); + objectDefinition.Role = ObjectRole.ROLE_INFRASTRUCTURE; + objectDefinition.PropertyValues.Add("order", int.MaxValue); + registry.RegisterObjectDefinition(AUTO_PROXY_CREATOR_OBJECT_NAME, objectDefinition); } + } - /// - /// Registers the internal auto proxy creator if necessary. - /// - public static void RegisterAutoProxyCreatorIfNecessary(IObjectDefinitionRegistry registry) + /// + /// Forces the auto proxy creator to use decorator proxy. + /// + /// The registry. + public static void ForceAutoProxyCreatorToUseDecoratorProxy(IObjectDefinitionRegistry registry) + { + if (registry.ContainsObjectDefinition(AUTO_PROXY_CREATOR_OBJECT_NAME)) { - AssertUtils.ArgumentNotNull(registry, "registry"); - - if (!registry.ContainsObjectDefinition(AUTO_PROXY_CREATOR_OBJECT_NAME)) - { - RootObjectDefinition objectDefinition = new RootObjectDefinition(InfrastructureAutoProxyCreatorType); - objectDefinition.Role = ObjectRole.ROLE_INFRASTRUCTURE; - objectDefinition.PropertyValues.Add("order", int.MaxValue); - registry.RegisterObjectDefinition(AUTO_PROXY_CREATOR_OBJECT_NAME, objectDefinition); - } - } - - /// - /// Forces the auto proxy creator to use decorator proxy. - /// - /// The registry. - public static void ForceAutoProxyCreatorToUseDecoratorProxy(IObjectDefinitionRegistry registry) - { - if (registry.ContainsObjectDefinition(AUTO_PROXY_CREATOR_OBJECT_NAME)) - { - IObjectDefinition definition = registry.GetObjectDefinition(AUTO_PROXY_CREATOR_OBJECT_NAME); - definition.PropertyValues.Add("ProxyTargetType", true); - } + IObjectDefinition definition = registry.GetObjectDefinition(AUTO_PROXY_CREATOR_OBJECT_NAME); + definition.PropertyValues.Add("ProxyTargetType", true); } } } diff --git a/src/Spring/Spring.Aop/Aop/Config/ConfigObjectDefinitionParser.cs b/src/Spring/Spring.Aop/Aop/Config/ConfigObjectDefinitionParser.cs index 7366d35b..d092ae04 100644 --- a/src/Spring/Spring.Aop/Aop/Config/ConfigObjectDefinitionParser.cs +++ b/src/Spring/Spring.Aop/Aop/Config/ConfigObjectDefinitionParser.cs @@ -18,7 +18,6 @@ #endregion - using System.Xml; using Spring.Aop.Support; using Spring.Objects.Factory.Config; @@ -26,134 +25,129 @@ using Spring.Objects.Factory.Support; using Spring.Objects.Factory.Xml; using Spring.Util; -namespace Spring.Aop.Config +namespace Spring.Aop.Config; + +/// +/// The for the <aop:config> tag. +/// +/// Mark Pollack (.NET) +public class ConfigObjectDefinitionParser : IObjectDefinitionParser { /// - /// The for the <aop:config> tag. + /// The 'proxy-target-type' attribute /// - /// Mark Pollack (.NET) - public class ConfigObjectDefinitionParser : IObjectDefinitionParser + private static readonly string PROXY_TARGET_TYPE = "proxy-target-type"; + + private static readonly string ID = "id"; + + private static readonly string ORDER_PROPERTY = "order"; + + private static readonly string ADVICE_REF = "advice-ref"; + + private static readonly string ADVICE_OBJECT_NAME = "adviceObjectName"; + + private static readonly string POINTCUT_REF = "pointcut-ref"; + + #region IObjectDefinitionParser Members + + /// + /// Parse the specified XmlElement and register the resulting + /// ObjectDefinitions with the IObjectDefinitionRegistry + /// embedded in the supplied + /// + /// The element to be parsed. + /// The object encapsulating the current state of the parsing process. + /// Provides access to a IObjectDefinitionRegistry + /// The primary object definition. + /// + ///

+ /// This method is never invoked if the parser is namespace aware + /// and was called to process the root node. + ///

+ ///
+ public IObjectDefinition ParseElement(XmlElement element, ParserContext parserContext) { - /// - /// The 'proxy-target-type' attribute - /// - private static readonly string PROXY_TARGET_TYPE = "proxy-target-type"; + ConfigureAutoProxyCreator(parserContext, element); + XmlNodeList advisorNodes = element.GetElementsByTagName("advisor", element.NamespaceURI); - private static readonly string ID = "id"; - - private static readonly string ORDER_PROPERTY = "order"; - - private static readonly string ADVICE_REF = "advice-ref"; - - private static readonly string ADVICE_OBJECT_NAME = "adviceObjectName"; - - private static readonly string POINTCUT_REF = "pointcut-ref"; - - - #region IObjectDefinitionParser Members - - /// - /// Parse the specified XmlElement and register the resulting - /// ObjectDefinitions with the IObjectDefinitionRegistry - /// embedded in the supplied - /// - /// The element to be parsed. - /// The object encapsulating the current state of the parsing process. - /// Provides access to a IObjectDefinitionRegistry - /// The primary object definition. - /// - ///

- /// This method is never invoked if the parser is namespace aware - /// and was called to process the root node. - ///

- ///
- public IObjectDefinition ParseElement(XmlElement element, ParserContext parserContext) + //XmlNodeList advisorNodes = element.SelectNodes("*[local-name()='advisor' and namespace-uri()='" + element.NamespaceURI + "']"); + foreach (XmlElement advisorElement in advisorNodes) { - ConfigureAutoProxyCreator(parserContext, element); - XmlNodeList advisorNodes = element.GetElementsByTagName("advisor", element.NamespaceURI); + ParseAdvisor(advisorElement, parserContext); + } - //XmlNodeList advisorNodes = element.SelectNodes("*[local-name()='advisor' and namespace-uri()='" + element.NamespaceURI + "']"); - foreach (XmlElement advisorElement in advisorNodes) + return null; + } + + /// + /// Parses the supplied advisor element and registers the resulting + /// + /// The advisor element. + /// The parser context. + private void ParseAdvisor(XmlElement advisorElement, ParserContext parserContext) + { + AbstractObjectDefinition advisorDef = CreateAdvisorObjectDefinition(advisorElement, parserContext); + string id = advisorElement.GetAttribute(ID); + + string pointcutObjectName = ParsePointcutProperty(advisorElement, parserContext); + advisorDef.PropertyValues.Add(POINTCUT_REF, new RuntimeObjectReference(pointcutObjectName)); + string advisorObjectName = id; + if (StringUtils.HasText(advisorObjectName)) + { + parserContext.Registry.RegisterObjectDefinition(advisorObjectName, advisorDef); + } + else + { + parserContext.ReaderContext.RegisterWithGeneratedName(advisorDef); + } + } + + private string ParsePointcutProperty(XmlElement element, ParserContext parserContext) + { + if (element.HasAttribute(POINTCUT_REF)) + { + string pointcutRef = element.GetAttribute(POINTCUT_REF); + if (!StringUtils.HasText(pointcutRef)) { - ParseAdvisor(advisorElement, parserContext); + parserContext.ReaderContext.ReportException(element, "advisor", "'pointcut-ref' attribute contains empty value."); } + return pointcutRef; + } + else + { + parserContext.ReaderContext.ReportException(element, "advisor", "'must define 'pointcut-ref' on tag."); return null; } - - /// - /// Parses the supplied advisor element and registers the resulting - /// - /// The advisor element. - /// The parser context. - private void ParseAdvisor(XmlElement advisorElement, ParserContext parserContext) - { - AbstractObjectDefinition advisorDef = CreateAdvisorObjectDefinition(advisorElement, parserContext); - string id = advisorElement.GetAttribute(ID); - - string pointcutObjectName = ParsePointcutProperty(advisorElement, parserContext); - advisorDef.PropertyValues.Add(POINTCUT_REF, new RuntimeObjectReference(pointcutObjectName)); - string advisorObjectName = id; - if (StringUtils.HasText(advisorObjectName)) - { - parserContext.Registry.RegisterObjectDefinition(advisorObjectName, advisorDef); - } - else - { - parserContext.ReaderContext.RegisterWithGeneratedName(advisorDef); - } - } - - - private string ParsePointcutProperty(XmlElement element, ParserContext parserContext) - { - if (element.HasAttribute(POINTCUT_REF)) - { - string pointcutRef = element.GetAttribute(POINTCUT_REF); - if (!StringUtils.HasText(pointcutRef)) - { - parserContext.ReaderContext.ReportException(element, "advisor", "'pointcut-ref' attribute contains empty value."); - } - return pointcutRef; - } - else - { - parserContext.ReaderContext.ReportException(element, "advisor", "'must define 'pointcut-ref' on tag."); - return null; - } - } - - - private AbstractObjectDefinition CreateAdvisorObjectDefinition(XmlElement advisorElement, ParserContext parserContext) - { - ObjectDefinitionBuilder advisorDefinitionBuilder = - parserContext.ParserHelper.CreateRootObjectDefinitionBuilder(typeof(DefaultObjectFactoryPointcutAdvisor)); - advisorDefinitionBuilder.RawObjectDefinition.Role = ObjectRole.ROLE_INFRASTRUCTURE; - - if (advisorElement.HasAttribute(ORDER_PROPERTY)) - { - advisorDefinitionBuilder.AddPropertyValue(ORDER_PROPERTY, advisorElement.GetAttribute(ORDER_PROPERTY)); - } - - advisorDefinitionBuilder.AddPropertyValue(ADVICE_OBJECT_NAME, advisorElement.GetAttribute(ADVICE_REF)); - - - return advisorDefinitionBuilder.ObjectDefinition; - } - - - private static void ConfigureAutoProxyCreator(ParserContext parserContext, XmlElement element) - { - AopNamespaceUtils.RegisterAutoProxyCreatorIfNecessary(parserContext, element); - - bool proxyTargetClass = - parserContext.ParserHelper.IsTrueStringValue(element.GetAttribute(PROXY_TARGET_TYPE)); - if (proxyTargetClass) - { - AopNamespaceUtils.ForceAutoProxyCreatorToUseDecoratorProxy(parserContext.Registry); - } - } - - #endregion } -} \ No newline at end of file + + private AbstractObjectDefinition CreateAdvisorObjectDefinition(XmlElement advisorElement, ParserContext parserContext) + { + ObjectDefinitionBuilder advisorDefinitionBuilder = + parserContext.ParserHelper.CreateRootObjectDefinitionBuilder(typeof(DefaultObjectFactoryPointcutAdvisor)); + advisorDefinitionBuilder.RawObjectDefinition.Role = ObjectRole.ROLE_INFRASTRUCTURE; + + if (advisorElement.HasAttribute(ORDER_PROPERTY)) + { + advisorDefinitionBuilder.AddPropertyValue(ORDER_PROPERTY, advisorElement.GetAttribute(ORDER_PROPERTY)); + } + + advisorDefinitionBuilder.AddPropertyValue(ADVICE_OBJECT_NAME, advisorElement.GetAttribute(ADVICE_REF)); + + return advisorDefinitionBuilder.ObjectDefinition; + } + + private static void ConfigureAutoProxyCreator(ParserContext parserContext, XmlElement element) + { + AopNamespaceUtils.RegisterAutoProxyCreatorIfNecessary(parserContext, element); + + bool proxyTargetClass = + parserContext.ParserHelper.IsTrueStringValue(element.GetAttribute(PROXY_TARGET_TYPE)); + if (proxyTargetClass) + { + AopNamespaceUtils.ForceAutoProxyCreatorToUseDecoratorProxy(parserContext.Registry); + } + } + + #endregion +} diff --git a/src/Spring/Spring.Aop/Aop/Config/spring-aop-1.1.xsd b/src/Spring/Spring.Aop/Aop/Config/spring-aop-1.1.xsd index 552faf60..71997f68 100644 --- a/src/Spring/Spring.Aop/Aop/Config/spring-aop-1.1.xsd +++ b/src/Spring/Spring.Aop/Aop/Config/spring-aop-1.1.xsd @@ -1,99 +1,99 @@ + xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:objects="http://www.springframework.net" + xmlns:tool="http://www.springframework.net/tool" + targetNamespace="http://www.springframework.net/aop" + elementFormDefault="qualified" + attributeFormDefault="unqualified"> - - + + - - + - + - - - + + - - - - - - + + + + + - - + + - - - - + + + - - - - + + + + - - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + - - - - - + + + + - - - + + + - - - - - - - - - - + + + + + + + + + + diff --git a/src/Spring/Spring.Aop/Aop/Framework/AbstractMethodInvocation.cs b/src/Spring/Spring.Aop/Aop/Framework/AbstractMethodInvocation.cs index e8fffbfb..f0059f2b 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/AbstractMethodInvocation.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/AbstractMethodInvocation.cs @@ -23,300 +23,302 @@ using System.Collections; using System.Reflection; using System.Text; - using AopAlliance.Intercept; using Spring.Util; #endregion -namespace Spring.Aop.Framework +namespace Spring.Aop.Framework; + +/// +/// Convenience base class for +/// implementations. +/// +/// +///

+/// Subclasses can override the +/// +/// method to change this behavior, so this is a useful/ base class for +/// implementations. +///

+///
+/// Rod Johnson +/// Aleksandar Seovic (.NET) +/// Rick Evans (.NET) +/// Bruno Baia (.NET) +[Serializable] +public abstract class AbstractMethodInvocation : IMethodInvocation { - /// - /// Convenience base class for - /// implementations. - /// - /// - ///

- /// Subclasses can override the - /// - /// method to change this behavior, so this is a useful/ base class for - /// implementations. - ///

- ///
- /// Rod Johnson - /// Aleksandar Seovic (.NET) - /// Rick Evans (.NET) - /// Bruno Baia (.NET) - [Serializable] - public abstract class AbstractMethodInvocation : IMethodInvocation - { - /// - /// The arguments (if any = may be ) to the method - /// that is to be invoked. - /// - private object[] arguments; + /// + /// The arguments (if any = may be ) to the method + /// that is to be invoked. + /// + private object[] arguments; - /// - /// The target object that the method is to be invoked on. - /// - private readonly object target; + /// + /// The target object that the method is to be invoked on. + /// + private readonly object target; - /// - /// The AOP proxy for the target object. - /// - private object proxy; + /// + /// The AOP proxy for the target object. + /// + private object proxy; - /// - /// The method invocation that is to be invoked. - /// - private MethodInfo method; + /// + /// The method invocation that is to be invoked. + /// + private MethodInfo method; - /// - /// The list of and - /// - /// that need dynamic checks. - /// - private IList interceptors; + /// + /// The list of and + /// + /// that need dynamic checks. + /// + private IList interceptors; - /// - /// The declaring type of the method that is to be invoked. - /// - private Type targetType; + /// + /// The declaring type of the method that is to be invoked. + /// + private Type targetType; - /// - /// The index from 0 of the current interceptor we're invoking. - /// - private int currentInterceptorIndex; + /// + /// The index from 0 of the current interceptor we're invoking. + /// + private int currentInterceptorIndex; - /// - /// Creates a new instance of the - /// class. - /// - /// - ///

- /// This is an abstract class, and as such exposes no publicly visible - /// constructors. - ///

- ///

- /// - /// The list can also contain any - /// s - /// that need evaluation at runtime. - /// s included in an - /// - /// must already have been found to have matched as far as was possible - /// statically. Passing an array might be about 10% faster, but - /// would complicate the code, and it would work only for static - /// pointcuts. - /// - ///

- ///
- /// The AOP proxy. - /// The target object. - /// the target method. - /// The target method's arguments. - /// - /// The of the target object. - /// - /// The list of interceptors that are to be applied. May be - /// . - /// - /// - /// If the is . - /// - protected AbstractMethodInvocation(object proxy, object target, - MethodInfo method, object[] arguments, Type targetType, IList interceptors) - { - // EE: There is not necessarily always a target - e.g. for DynamicEntities - // moved this check to InvokeJoinpoint() - AssertUtils.ArgumentNotNull(method, "method"); + /// + /// Creates a new instance of the + /// class. + /// + /// + ///

+ /// This is an abstract class, and as such exposes no publicly visible + /// constructors. + ///

+ ///

+ /// + /// The list can also contain any + /// s + /// that need evaluation at runtime. + /// s included in an + /// + /// must already have been found to have matched as far as was possible + /// statically. Passing an array might be about 10% faster, but + /// would complicate the code, and it would work only for static + /// pointcuts. + /// + ///

+ ///
+ /// The AOP proxy. + /// The target object. + /// the target method. + /// The target method's arguments. + /// + /// The of the target object. + /// + /// The list of interceptors that are to be applied. May be + /// . + /// + /// + /// If the is . + /// + protected AbstractMethodInvocation(object proxy, object target, + MethodInfo method, object[] arguments, Type targetType, IList interceptors) + { + // EE: There is not necessarily always a target - e.g. for DynamicEntities + // moved this check to InvokeJoinpoint() + AssertUtils.ArgumentNotNull(method, "method"); - this.proxy = proxy; - this.target = target; - this.method = method; - this.targetType = targetType; - this.arguments = arguments; - this.interceptors = interceptors; - } + this.proxy = proxy; + this.target = target; + this.method = method; + this.targetType = targetType; + this.arguments = arguments; + this.interceptors = interceptors; + } - /// - /// Gets the method invocation that is to be invoked. - /// - /// - ///

- /// May or may not correspond with a method invoked on an underlying - /// implementation of that interface. - ///

- ///
- /// - public virtual MethodInfo Method - { - get { return method; } - protected set { method = value; } - } + /// + /// Gets the method invocation that is to be invoked. + /// + /// + ///

+ /// May or may not correspond with a method invoked on an underlying + /// implementation of that interface. + ///

+ ///
+ /// + public virtual MethodInfo Method + { + get { return method; } + protected set { method = value; } + } - /// - /// Gets the static part of this joinpoint. - /// - /// - /// The proxied member's information. - /// - /// - public virtual MemberInfo StaticPart - { - get { return Method; } - } + /// + /// Gets the static part of this joinpoint. + /// + /// + /// The proxied member's information. + /// + /// + public virtual MemberInfo StaticPart + { + get { return Method; } + } - /// - /// Gets the proxy that this interception was made through. - /// - /// - /// The proxy that this interception was made through. - /// - public virtual object Proxy - { - get { return this.proxy; } - protected set { this.proxy = value; } - } - /// - /// Gets the target object for the invocation. - /// - /// - /// The target object for this method invocation. - /// - public virtual object Target - { - get { return this.target; } - } - /// - /// Gets the type of the target object. - /// - /// - /// The type of the target object. - /// - public virtual Type TargetType - { - get { return this.targetType; } - protected set { this.targetType = value; } - } + /// + /// Gets the proxy that this interception was made through. + /// + /// + /// The proxy that this interception was made through. + /// + public virtual object Proxy + { + get { return this.proxy; } + protected set { this.proxy = value; } + } - /// - /// Gets and sets the arguments (if any - may be ) - /// to the method that is to be invoked. - /// - /// - /// The arguments (if any - may be ) to the - /// method that is to be invoked. - /// - /// - public virtual object[] Arguments - { - get { return this.arguments; } - set { this.arguments = value; } - } + /// + /// Gets the target object for the invocation. + /// + /// + /// The target object for this method invocation. + /// + public virtual object Target + { + get { return this.target; } + } - /// - /// The list of method interceptors. - /// - /// - ///

- /// May be . - ///

- ///
- public virtual IList Interceptors - { - get { return this.interceptors; } - set { this.interceptors = value; } - } + /// + /// Gets the type of the target object. + /// + /// + /// The type of the target object. + /// + public virtual Type TargetType + { + get { return this.targetType; } + protected set { this.targetType = value; } + } - /// - /// Gets the target object. - /// - public virtual object This - { - get { return this.target; } - } + /// + /// Gets and sets the arguments (if any - may be ) + /// to the method that is to be invoked. + /// + /// + /// The arguments (if any - may be ) to the + /// method that is to be invoked. + /// + /// + public virtual object[] Arguments + { + get { return this.arguments; } + set { this.arguments = value; } + } - /// - /// The index from 0 of the current interceptor we're invoking. - /// - protected int CurrentInterceptorIndex - { - get { return currentInterceptorIndex; } - set { currentInterceptorIndex = value; } - } + /// + /// The list of method interceptors. + /// + /// + ///

+ /// May be . + ///

+ ///
+ public virtual IList Interceptors + { + get { return this.interceptors; } + set { this.interceptors = value; } + } - /// - /// Proceeds to the next interceptor in the chain. - /// - /// - /// The return value of the method invocation. - /// - /// - /// If any of the interceptors at the joinpoint throws an exception. - /// - /// - public virtual object Proceed() - { - if (this.interceptors == null || - this.currentInterceptorIndex == this.interceptors.Count) - { - AssertJoinpoint(); - return InvokeJoinpoint(); - } - object interceptor = this.interceptors[this.currentInterceptorIndex]; - InterceptorAndDynamicMethodMatcher dynamicMatcher - = interceptor as InterceptorAndDynamicMethodMatcher; - IMethodInvocation nextInvocation = PrepareMethodInvocationForProceed(this); - if (dynamicMatcher != null) - { - // evaluate dynamic method matcher here: static part will already have - // been evaluated and found to match... - if (dynamicMatcher.MethodMatcher.Matches( + /// + /// Gets the target object. + /// + public virtual object This + { + get { return this.target; } + } + + /// + /// The index from 0 of the current interceptor we're invoking. + /// + protected int CurrentInterceptorIndex + { + get { return currentInterceptorIndex; } + set { currentInterceptorIndex = value; } + } + + /// + /// Proceeds to the next interceptor in the chain. + /// + /// + /// The return value of the method invocation. + /// + /// + /// If any of the interceptors at the joinpoint throws an exception. + /// + /// + public virtual object Proceed() + { + if (this.interceptors == null || + this.currentInterceptorIndex == this.interceptors.Count) + { + AssertJoinpoint(); + return InvokeJoinpoint(); + } + + object interceptor = this.interceptors[this.currentInterceptorIndex]; + InterceptorAndDynamicMethodMatcher dynamicMatcher + = interceptor as InterceptorAndDynamicMethodMatcher; + IMethodInvocation nextInvocation = PrepareMethodInvocationForProceed(this); + if (dynamicMatcher != null) + { + // evaluate dynamic method matcher here: static part will already have + // been evaluated and found to match... + if (dynamicMatcher.MethodMatcher.Matches( nextInvocation.Method, nextInvocation.TargetType, nextInvocation.Arguments)) - { - return dynamicMatcher.Interceptor.Invoke(nextInvocation); - } - else - { - // dynamic match failed; skip this interceptor and invoke the next in the chain... - return nextInvocation.Proceed(); - } + { + return dynamicMatcher.Interceptor.Invoke(nextInvocation); } else { - // it's an interceptor so we just invoke it: the pointcut will have - // been evaluated statically before this object was constructed... - return ((IMethodInterceptor)interceptor).Invoke(nextInvocation); + // dynamic match failed; skip this interceptor and invoke the next in the chain... + return nextInvocation.Proceed(); } - } - - /// - /// Retrieves a new instance - /// for the next Proceed method call. - /// - /// - /// The current instance. - /// - /// - /// The new instance to use. - /// - /// - protected abstract IMethodInvocation PrepareMethodInvocationForProceed( - IMethodInvocation invocation); - - /// - /// Performs sanity checks, whether the actual joinpoint may be invoked - /// - /// - /// By default checks that the underlying target is not null and the called method is implemented - /// by the target's type. - /// - /// if is null. - /// if the 's type does not implement . - protected virtual void AssertJoinpoint() + } + else { - AssertUtils.ArgumentNotNull(target, "target"); + // it's an interceptor so we just invoke it: the pointcut will have + // been evaluated statically before this object was constructed... + return ((IMethodInterceptor) interceptor).Invoke(nextInvocation); + } + } + + /// + /// Retrieves a new instance + /// for the next Proceed method call. + /// + /// + /// The current instance. + /// + /// + /// The new instance to use. + /// + /// + protected abstract IMethodInvocation PrepareMethodInvocationForProceed( + IMethodInvocation invocation); + + /// + /// Performs sanity checks, whether the actual joinpoint may be invoked + /// + /// + /// By default checks that the underlying target is not null and the called method is implemented + /// by the target's type. + /// + /// if is null. + /// if the 's type does not implement . + protected virtual void AssertJoinpoint() + { + AssertUtils.ArgumentNotNull(target, "target"); // if (this.method != null // && !this.method.DeclaringType.IsAssignableFrom(target.GetType())) // { @@ -324,56 +326,56 @@ namespace Spring.Aop.Framework // // Since no interceptor has handled the call, we throw a sensible exception here. // throw new NotSupportedException(string.Format("Interface method '{0}.{1}()' was not handled by any interceptor and the underlying target type '{2}' does not implement this method.", method.DeclaringType.FullName, method.Name, target.GetType().FullName)); // } + } + + /// + /// Invokes the joinpoint. + /// + /// + ///

+ /// Subclasses can override this to use custom invocation. + ///

+ ///
+ /// + /// The return value of the invocation of the joinpoint. + /// + /// + /// If invoking the joinpoint resulted in an exception. + /// + /// + protected abstract object InvokeJoinpoint(); + + /// + /// A that represents the current + /// invocation. + /// + /// + ///

+ /// + /// Does not invoke on the + /// target + /// object, as that too may be proxied. + /// + ///

+ ///
+ /// + /// A that represents the current invocation. + /// + public override string ToString() + { + StringBuilder buffer = new StringBuilder("Invocation: method '"); + buffer.Append(Method.Name).Append("', ").Append("arguments "); + buffer.Append(Arguments != null ? StringUtils.CollectionToCommaDelimitedString(Arguments) : "[none]"); + buffer.Append("; "); + if (Target == null) + { + buffer.Append("target is null."); + } + else + { + buffer.Append("target is of Type [").Append(TargetType.FullName).Append(']'); } - /// - /// Invokes the joinpoint. - /// - /// - ///

- /// Subclasses can override this to use custom invocation. - ///

- ///
- /// - /// The return value of the invocation of the joinpoint. - /// - /// - /// If invoking the joinpoint resulted in an exception. - /// - /// - protected abstract object InvokeJoinpoint(); - - /// - /// A that represents the current - /// invocation. - /// - /// - ///

- /// - /// Does not invoke on the - /// target - /// object, as that too may be proxied. - /// - ///

- ///
- /// - /// A that represents the current invocation. - /// - public override string ToString() - { - StringBuilder buffer = new StringBuilder("Invocation: method '"); - buffer.Append(Method.Name).Append("', ").Append("arguments "); - buffer.Append(Arguments != null ? StringUtils.CollectionToCommaDelimitedString(Arguments) : "[none]"); - buffer.Append("; "); - if (Target == null) - { - buffer.Append("target is null."); - } - else - { - buffer.Append("target is of Type [").Append(TargetType.FullName).Append(']'); - } - return buffer.ToString(); - } - } + return buffer.ToString(); + } } diff --git a/src/Spring/Spring.Aop/Aop/Framework/Adapter/AdvisorAdapterRegistrationManager.cs b/src/Spring/Spring.Aop/Aop/Framework/Adapter/AdvisorAdapterRegistrationManager.cs index b68b51ed..6942e57e 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/Adapter/AdvisorAdapterRegistrationManager.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/Adapter/AdvisorAdapterRegistrationManager.cs @@ -24,85 +24,85 @@ using Spring.Objects.Factory.Config; #endregion -namespace Spring.Aop.Framework.Adapter +namespace Spring.Aop.Framework.Adapter; + +/// +/// implementation +/// that registers instances of any non-default +/// instances with the +/// +/// singleton. +/// +/// +///

+/// The only requirement for it to work is that it needs to be defined +/// in an application context along with any arbitrary "non-native" Spring.NET +/// instances that need +/// to be recognized by Spring.NET's AOP framework. +///

+///
+/// Dmitriy Kopylenko +/// Aleksandar Seovic (.NET) +public class AdvisorAdapterRegistrationManager : IObjectPostProcessor { /// - /// implementation - /// that registers instances of any non-default - /// instances with the - /// - /// singleton. + /// Apply this + /// to the given new object instance before any object initialization callbacks. /// /// ///

- /// The only requirement for it to work is that it needs to be defined - /// in an application context along with any arbitrary "non-native" Spring.NET - /// instances that need - /// to be recognized by Spring.NET's AOP framework. + /// Does nothing, simply returns the supplied as is. ///

///
- /// Dmitriy Kopylenko - /// Aleksandar Seovic (.NET) - public class AdvisorAdapterRegistrationManager : IObjectPostProcessor + /// + /// The new object instance. + /// + /// + /// The name of the object. + /// + /// + /// The object instance to use, either the original or a wrapped one. + /// + /// + /// In case of errors. + /// + public virtual object PostProcessBeforeInitialization(object instance, string name) { - /// - /// Apply this - /// to the given new object instance before any object initialization callbacks. - /// - /// - ///

- /// Does nothing, simply returns the supplied as is. - ///

- ///
- /// - /// The new object instance. - /// - /// - /// The name of the object. - /// - /// - /// The object instance to use, either the original or a wrapped one. - /// - /// - /// In case of errors. - /// - public virtual object PostProcessBeforeInitialization(object instance, string name) + return instance; + } + + /// + /// Apply this to the + /// given new object instance after any object initialization callbacks. + /// + /// + ///

+ /// Registers the supplied with the + /// + /// singleton if it is an + /// instance. + ///

+ ///
+ /// + /// The new object instance. + /// + /// + /// The name of the object. + /// + /// + /// The object instance to use, either the original or a wrapped one. + /// + /// + /// In case of errors. + /// + public virtual object PostProcessAfterInitialization(object instance, string objectName) + { + IAdvisorAdapter adapter = instance as IAdvisorAdapter; + if (adapter != null) { - return instance; + GlobalAdvisorAdapterRegistry.Instance.RegisterAdvisorAdapter(adapter); } - /// - /// Apply this to the - /// given new object instance after any object initialization callbacks. - /// - /// - ///

- /// Registers the supplied with the - /// - /// singleton if it is an - /// instance. - ///

- ///
- /// - /// The new object instance. - /// - /// - /// The name of the object. - /// - /// - /// The object instance to use, either the original or a wrapped one. - /// - /// - /// In case of errors. - /// - public virtual object PostProcessAfterInitialization(object instance, string objectName) - { - IAdvisorAdapter adapter = instance as IAdvisorAdapter; - if (adapter != null) - { - GlobalAdvisorAdapterRegistry.Instance.RegisterAdvisorAdapter(adapter); - } - return instance; - } + return instance; } -} \ No newline at end of file +} diff --git a/src/Spring/Spring.Aop/Aop/Framework/Adapter/AfterReturningAdviceAdapter.cs b/src/Spring/Spring.Aop/Aop/Framework/Adapter/AfterReturningAdviceAdapter.cs index f9d0ef0f..afa91d1e 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/Adapter/AfterReturningAdviceAdapter.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/Adapter/AfterReturningAdviceAdapter.cs @@ -25,55 +25,54 @@ using AopAlliance.Intercept; #endregion -namespace Spring.Aop.Framework.Adapter +namespace Spring.Aop.Framework.Adapter; + +/// +/// implementation +/// to enable to be used in the +/// Spring.NET AOP framework. +/// +/// Rod Johnson +/// Aleksandar Seovic (.NET) +[Serializable] +internal class AfterReturningAdviceAdapter : IAdvisorAdapter { /// - /// implementation - /// to enable to be used in the - /// Spring.NET AOP framework. + /// Returns if the supplied + /// is an instance of the + /// interface. /// - /// Rod Johnson - /// Aleksandar Seovic (.NET) - [Serializable] - internal class AfterReturningAdviceAdapter : IAdvisorAdapter + /// The advice to check. + /// + /// if the supplied is + /// an instance of the interface; + /// if not or if the supplied + /// is . + /// + public virtual bool SupportsAdvice(IAdvice advice) { - /// - /// Returns if the supplied - /// is an instance of the - /// interface. - /// - /// The advice to check. - /// - /// if the supplied is - /// an instance of the interface; - /// if not or if the supplied - /// is . - /// - public virtual bool SupportsAdvice(IAdvice advice) - { - return advice is IAfterReturningAdvice; - } + return advice is IAfterReturningAdvice; + } - /// - /// Wraps the supplied 's - /// within a - /// - /// instance. - /// - /// - /// The advisor exposing the that - /// is to be wrapped. - /// - /// - /// The supplied 's - /// wrapped within a - /// - /// instance. - /// - public virtual IInterceptor GetInterceptor(IAdvisor advisor) - { - IAfterReturningAdvice advice = (IAfterReturningAdvice) advisor.Advice; - return new AfterReturningAdviceInterceptor(advice); - } + /// + /// Wraps the supplied 's + /// within a + /// + /// instance. + /// + /// + /// The advisor exposing the that + /// is to be wrapped. + /// + /// + /// The supplied 's + /// wrapped within a + /// + /// instance. + /// + public virtual IInterceptor GetInterceptor(IAdvisor advisor) + { + IAfterReturningAdvice advice = (IAfterReturningAdvice) advisor.Advice; + return new AfterReturningAdviceInterceptor(advice); } } diff --git a/src/Spring/Spring.Aop/Aop/Framework/Adapter/AfterReturningAdviceInterceptor.cs b/src/Spring/Spring.Aop/Aop/Framework/Adapter/AfterReturningAdviceInterceptor.cs index 4eaa8a96..2fde088f 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/Adapter/AfterReturningAdviceInterceptor.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/Adapter/AfterReturningAdviceInterceptor.cs @@ -25,71 +25,70 @@ using Spring.Util; #endregion -namespace Spring.Aop.Framework.Adapter +namespace Spring.Aop.Framework.Adapter; + +/// +/// Interceptor to wrap an +/// instance. +/// +/// +///

+/// A more efficient alternative solution in cases where there is no +/// interception advice and therefore no need to create an +/// object may be +/// offered in future. +///

+///

+/// Used internally by the AOP framework: application developers should not need +/// to use this class directly. +///

+///
+/// Rod Johnson +/// Aleksandar Seovic (.NET) +[Serializable] +public sealed class AfterReturningAdviceInterceptor : IMethodInterceptor { - /// - /// Interceptor to wrap an - /// instance. - /// - /// - ///

- /// A more efficient alternative solution in cases where there is no - /// interception advice and therefore no need to create an - /// object may be - /// offered in future. - ///

- ///

- /// Used internally by the AOP framework: application developers should not need - /// to use this class directly. - ///

- ///
- /// Rod Johnson - /// Aleksandar Seovic (.NET) - [Serializable] - public sealed class AfterReturningAdviceInterceptor : IMethodInterceptor - { - private IAfterReturningAdvice advice; + private IAfterReturningAdvice advice; - /// - /// Creates a new instance of the - /// - /// class. - /// - /// - /// The advice to be applied after a target method successfully - /// returns. - /// - /// - /// If the supplied is . - /// - public AfterReturningAdviceInterceptor(IAfterReturningAdvice advice) - { - AssertUtils.ArgumentNotNull(advice, "advice"); - this.advice = advice; - } + /// + /// Creates a new instance of the + /// + /// class. + /// + /// + /// The advice to be applied after a target method successfully + /// returns. + /// + /// + /// If the supplied is . + /// + public AfterReturningAdviceInterceptor(IAfterReturningAdvice advice) + { + AssertUtils.ArgumentNotNull(advice, "advice"); + this.advice = advice; + } - /// - /// Executes interceptor after the target method successfully returns. - /// - /// - /// The method invocation that is being intercepted. - /// - /// - /// The result of the call to the - /// method of - /// the supplied ; this return value may - /// well have been intercepted by the interceptor. - /// - /// - /// If any of the interceptors in the chain or the target object itself - /// throws an exception. - /// - public object Invoke(IMethodInvocation invocation) - { - object returnValue = invocation.Proceed(); - advice.AfterReturning( - returnValue, invocation.Method, invocation.Arguments, invocation.This); - return returnValue; - } - } + /// + /// Executes interceptor after the target method successfully returns. + /// + /// + /// The method invocation that is being intercepted. + /// + /// + /// The result of the call to the + /// method of + /// the supplied ; this return value may + /// well have been intercepted by the interceptor. + /// + /// + /// If any of the interceptors in the chain or the target object itself + /// throws an exception. + /// + public object Invoke(IMethodInvocation invocation) + { + object returnValue = invocation.Proceed(); + advice.AfterReturning( + returnValue, invocation.Method, invocation.Arguments, invocation.This); + return returnValue; + } } diff --git a/src/Spring/Spring.Aop/Aop/Framework/Adapter/BeforeAdviceAdapter.cs b/src/Spring/Spring.Aop/Aop/Framework/Adapter/BeforeAdviceAdapter.cs index bafefeaf..bce90c60 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/Adapter/BeforeAdviceAdapter.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/Adapter/BeforeAdviceAdapter.cs @@ -25,55 +25,54 @@ using AopAlliance.Intercept; #endregion -namespace Spring.Aop.Framework.Adapter +namespace Spring.Aop.Framework.Adapter; + +/// +/// implementation +/// to enable to be used in the +/// Spring.NET AOP framework. +/// +/// Rod Johnson +/// Aleksandar Seovic (.NET) +[Serializable] +internal class BeforeAdviceAdapter : IAdvisorAdapter { /// - /// implementation - /// to enable to be used in the - /// Spring.NET AOP framework. + /// Returns if the supplied + /// is an instance of the + /// interface. /// - /// Rod Johnson - /// Aleksandar Seovic (.NET) - [Serializable] - internal class BeforeAdviceAdapter : IAdvisorAdapter + /// The advice to check. + /// + /// if the supplied is + /// an instance of the interface; + /// if not or if the supplied + /// is . + /// + public virtual bool SupportsAdvice(IAdvice advice) { - /// - /// Returns if the supplied - /// is an instance of the - /// interface. - /// - /// The advice to check. - /// - /// if the supplied is - /// an instance of the interface; - /// if not or if the supplied - /// is . - /// - public virtual bool SupportsAdvice(IAdvice advice) - { - return advice is IMethodBeforeAdvice; - } + return advice is IMethodBeforeAdvice; + } - /// - /// Wraps the supplied 's - /// within a - /// - /// instance. - /// - /// - /// The advisor exposing the that - /// is to be wrapped. - /// - /// - /// The supplied 's - /// wrapped within a - /// - /// instance. - /// - public virtual IInterceptor GetInterceptor(IAdvisor advisor) - { - IMethodBeforeAdvice advice = (IMethodBeforeAdvice) advisor.Advice; - return new MethodBeforeAdviceInterceptor(advice); - } + /// + /// Wraps the supplied 's + /// within a + /// + /// instance. + /// + /// + /// The advisor exposing the that + /// is to be wrapped. + /// + /// + /// The supplied 's + /// wrapped within a + /// + /// instance. + /// + public virtual IInterceptor GetInterceptor(IAdvisor advisor) + { + IMethodBeforeAdvice advice = (IMethodBeforeAdvice) advisor.Advice; + return new MethodBeforeAdviceInterceptor(advice); } } diff --git a/src/Spring/Spring.Aop/Aop/Framework/Adapter/DefaultAdvisorAdapterRegistry.cs b/src/Spring/Spring.Aop/Aop/Framework/Adapter/DefaultAdvisorAdapterRegistry.cs index 14519368..1c1beba5 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/Adapter/DefaultAdvisorAdapterRegistry.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/Adapter/DefaultAdvisorAdapterRegistry.cs @@ -26,126 +26,131 @@ using Spring.Aop.Support; #endregion -namespace Spring.Aop.Framework.Adapter -{ - /// - /// Default implementation of the - /// - /// interface. - /// - /// Rod Johnson - /// Aleksandar Seovic (.NET) - [Serializable] - public class DefaultAdvisorAdapterRegistry : IAdvisorAdapterRegistry - { - private readonly IList adapters = new List(); +namespace Spring.Aop.Framework.Adapter; - /// - /// Creates a new instance of the - /// class. - /// - /// - ///

- /// This constructor will also register the well-known - /// types. - ///

- ///
- /// - public DefaultAdvisorAdapterRegistry() +/// +/// Default implementation of the +/// +/// interface. +/// +/// Rod Johnson +/// Aleksandar Seovic (.NET) +[Serializable] +public class DefaultAdvisorAdapterRegistry : IAdvisorAdapterRegistry +{ + private readonly IList adapters = new List(); + + /// + /// Creates a new instance of the + /// class. + /// + /// + ///

+ /// This constructor will also register the well-known + /// types. + ///

+ ///
+ /// + public DefaultAdvisorAdapterRegistry() + { + // register well-known adapters... + RegisterAdvisorAdapter(new BeforeAdviceAdapter()); + RegisterAdvisorAdapter(new AfterReturningAdviceAdapter()); + RegisterAdvisorAdapter(new ThrowsAdviceAdapter()); + } + + /// + /// Returns an wrapping the supplied + /// . + /// + /// + /// The object that should be an advice, such as + /// or + /// . + /// + /// + /// An wrapping the supplied + /// . Never returns . If + /// the parameter is an + /// , it will simply be returned. + /// + /// + /// If no registered + /// can wrap + /// the supplied . + /// + public virtual IAdvisor Wrap(object advice) + { + if (advice is IAdvisor) { - // register well-known adapters... - RegisterAdvisorAdapter(new BeforeAdviceAdapter()); - RegisterAdvisorAdapter(new AfterReturningAdviceAdapter()); - RegisterAdvisorAdapter(new ThrowsAdviceAdapter()); + return (IAdvisor) advice; } - /// - /// Returns an wrapping the supplied - /// . - /// - /// - /// The object that should be an advice, such as - /// or - /// . - /// - /// - /// An wrapping the supplied - /// . Never returns . If - /// the parameter is an - /// , it will simply be returned. - /// - /// - /// If no registered - /// can wrap - /// the supplied . - /// - public virtual IAdvisor Wrap(object advice) - { - if (advice is IAdvisor) - { - return (IAdvisor) advice; - } - if (!(advice is IAdvice)) - { - throw new UnknownAdviceTypeException(advice); - } - IAdvice adviceObject = (IAdvice) advice; - if (adviceObject is IInterceptor) - { - // so well-known it doesn't even need an adapter... - return new DefaultPointcutAdvisor(adviceObject); - } - foreach (IAdvisorAdapter adapter in this.adapters) - { - // check that it is supported... - if (adapter.SupportsAdvice(adviceObject)) - { - return new DefaultPointcutAdvisor(adviceObject); - } - } - throw new UnknownAdviceTypeException(advice); - } + if (!(advice is IAdvice)) + { + throw new UnknownAdviceTypeException(advice); + } - /// - /// Returns an to - /// allow the use of the supplied in an - /// interception-based framework. - /// - /// The advisor to find an interceptor for. - /// - /// An interceptor to expose this advisor's behaviour. - /// - /// - /// If the advisor type is not understood by any registered - /// . - /// - public virtual IInterceptor GetInterceptor(IAdvisor advisor) - { - IAdvice advice = advisor.Advice; - if (advice is IInterceptor) - { - return (IInterceptor) advice; - } - foreach (IAdvisorAdapter adapter in this.adapters) - { - if (adapter.SupportsAdvice(advice)) - { - return adapter.GetInterceptor(advisor); - } - } - throw new UnknownAdviceTypeException(advice); - } + IAdvice adviceObject = (IAdvice) advice; + if (adviceObject is IInterceptor) + { + // so well-known it doesn't even need an adapter... + return new DefaultPointcutAdvisor(adviceObject); + } - /// - /// Register the given . - /// - /// - /// An that - /// understands the particular advisor and advice types. - /// - public virtual void RegisterAdvisorAdapter(IAdvisorAdapter adapter) - { - this.adapters.Add(adapter); - } - } + foreach (IAdvisorAdapter adapter in this.adapters) + { + // check that it is supported... + if (adapter.SupportsAdvice(adviceObject)) + { + return new DefaultPointcutAdvisor(adviceObject); + } + } + + throw new UnknownAdviceTypeException(advice); + } + + /// + /// Returns an to + /// allow the use of the supplied in an + /// interception-based framework. + /// + /// The advisor to find an interceptor for. + /// + /// An interceptor to expose this advisor's behaviour. + /// + /// + /// If the advisor type is not understood by any registered + /// . + /// + public virtual IInterceptor GetInterceptor(IAdvisor advisor) + { + IAdvice advice = advisor.Advice; + if (advice is IInterceptor) + { + return (IInterceptor) advice; + } + + foreach (IAdvisorAdapter adapter in this.adapters) + { + if (adapter.SupportsAdvice(advice)) + { + return adapter.GetInterceptor(advisor); + } + } + + throw new UnknownAdviceTypeException(advice); + } + + /// + /// Register the given . + /// + /// + /// An that + /// understands the particular advisor and advice types. + /// + public virtual void RegisterAdvisorAdapter(IAdvisorAdapter adapter) + { + this.adapters.Add(adapter); + } } diff --git a/src/Spring/Spring.Aop/Aop/Framework/Adapter/GlobalAdvisorAdapterRegistry.cs b/src/Spring/Spring.Aop/Aop/Framework/Adapter/GlobalAdvisorAdapterRegistry.cs index 21395ccb..d65a8116 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/Adapter/GlobalAdvisorAdapterRegistry.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/Adapter/GlobalAdvisorAdapterRegistry.cs @@ -18,48 +18,47 @@ #endregion -namespace Spring.Aop.Framework.Adapter +namespace Spring.Aop.Framework.Adapter; + +/// +/// Provides Singleton-style access to the default +/// instance. +/// +/// Rod Johnson +/// Aleksandar Seovic (.NET) +[Serializable] +public sealed class GlobalAdvisorAdapterRegistry : DefaultAdvisorAdapterRegistry { + private static readonly GlobalAdvisorAdapterRegistry instance + = new GlobalAdvisorAdapterRegistry(); + /// - /// Provides Singleton-style access to the default - /// instance. + /// The default instance. /// - /// Rod Johnson - /// Aleksandar Seovic (.NET) - [Serializable] - public sealed class GlobalAdvisorAdapterRegistry : DefaultAdvisorAdapterRegistry + public static GlobalAdvisorAdapterRegistry Instance { - private static readonly GlobalAdvisorAdapterRegistry instance - = new GlobalAdvisorAdapterRegistry(); - - /// - /// The default instance. - /// - public static GlobalAdvisorAdapterRegistry Instance - { - get { return instance; } - } - - #region Constructor (s) / Destructor - - // CLOVER:OFF - - /// - /// Creates a new instance of the - /// class. - /// - /// - ///

- /// This contructor is marked as to enforce the - /// Singleton pattern - ///

- ///
- private GlobalAdvisorAdapterRegistry() - { - } - - // CLOVER:ON - - #endregion + get { return instance; } } + + #region Constructor (s) / Destructor + + // CLOVER:OFF + + /// + /// Creates a new instance of the + /// class. + /// + /// + ///

+ /// This contructor is marked as to enforce the + /// Singleton pattern + ///

+ ///
+ private GlobalAdvisorAdapterRegistry() + { + } + + // CLOVER:ON + + #endregion } diff --git a/src/Spring/Spring.Aop/Aop/Framework/Adapter/IAdvisorAdapter.cs b/src/Spring/Spring.Aop/Aop/Framework/Adapter/IAdvisorAdapter.cs index 8ac7f40a..8e8ceee6 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/Adapter/IAdvisorAdapter.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/Adapter/IAdvisorAdapter.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -25,74 +25,73 @@ using AopAlliance.Intercept; #endregion -namespace Spring.Aop.Framework.Adapter -{ - /// - /// Permits the handling of new advisors and advice types as extensions to - /// the Spring AOP framework. - /// - /// - ///

- /// Implementors can create AOP Alliance - /// s from custom advice - /// types, enabling these advice types to be used in the Spring.NET AOP - /// framework, which uses interception under the covers. - ///

- ///

- /// There is no need for most Spring.NET users to implement this interface; - /// do so only if you need to introduce more - /// or - /// types to Spring.NET. - ///

- ///
- /// Rod Johnson - /// Aleksandar Seovic (.NET) - public interface IAdvisorAdapter - { - /// - /// Does this adapter understand the supplied ? - /// - /// - ///

- /// Is it valid to invoke the - /// - /// method with the given advice as an argument? - ///

- ///
- /// - /// such as - /// . - /// - /// if this adapter understands the - /// supplied . - /// - bool SupportsAdvice(IAdvice advice); +namespace Spring.Aop.Framework.Adapter; - /// - /// Return an AOP Alliance - /// exposing the - /// behaviour of the given advice to an interception-based AOP - /// framework. - /// - /// - ///

- /// Don't worry about any - /// contained in the supplied ; - /// the AOP framework will take care of checking the pointcut. - ///

- ///
- /// - /// The advice. The - /// - /// method must have previously returned on the - /// supplied . - /// - /// - /// An AOP Alliance - /// exposing the - /// behaviour of the given advice to an interception-based AOP - /// framework. - /// - IInterceptor GetInterceptor(IAdvisor advisor); - } -} \ No newline at end of file +/// +/// Permits the handling of new advisors and advice types as extensions to +/// the Spring AOP framework. +/// +/// +///

+/// Implementors can create AOP Alliance +/// s from custom advice +/// types, enabling these advice types to be used in the Spring.NET AOP +/// framework, which uses interception under the covers. +///

+///

+/// There is no need for most Spring.NET users to implement this interface; +/// do so only if you need to introduce more +/// or +/// types to Spring.NET. +///

+///
+/// Rod Johnson +/// Aleksandar Seovic (.NET) +public interface IAdvisorAdapter +{ + /// + /// Does this adapter understand the supplied ? + /// + /// + ///

+ /// Is it valid to invoke the + /// + /// method with the given advice as an argument? + ///

+ ///
+ /// + /// such as + /// . + /// + /// if this adapter understands the + /// supplied . + /// + bool SupportsAdvice(IAdvice advice); + + /// + /// Return an AOP Alliance + /// exposing the + /// behaviour of the given advice to an interception-based AOP + /// framework. + /// + /// + ///

+ /// Don't worry about any + /// contained in the supplied ; + /// the AOP framework will take care of checking the pointcut. + ///

+ ///
+ /// + /// The advice. The + /// + /// method must have previously returned on the + /// supplied . + /// + /// + /// An AOP Alliance + /// exposing the + /// behaviour of the given advice to an interception-based AOP + /// framework. + /// + IInterceptor GetInterceptor(IAdvisor advisor); +} diff --git a/src/Spring/Spring.Aop/Aop/Framework/Adapter/IAdvisorAdapterRegistry.cs b/src/Spring/Spring.Aop/Aop/Framework/Adapter/IAdvisorAdapterRegistry.cs index 83549c50..7d87e392 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/Adapter/IAdvisorAdapterRegistry.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/Adapter/IAdvisorAdapterRegistry.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -24,89 +24,88 @@ using AopAlliance.Intercept; #endregion -namespace Spring.Aop.Framework.Adapter +namespace Spring.Aop.Framework.Adapter; + +/// +/// A registry of +/// instances. +/// +/// +///

+/// Implementations must also automatically register adapters for +/// types. +///

+/// +/// This is an SPI interface, that should not need to be implemented by any +/// Spring.NET user. +/// +///
+/// Rod Johnson +/// Aleksandar Seovic (.NET) +public interface IAdvisorAdapterRegistry { /// - /// A registry of - /// instances. + /// Returns an wrapping the supplied + /// . + /// + /// + /// The object that should be an advice, such as + /// or + /// . + /// + /// + /// An wrapping the supplied + /// . Never returns . If + /// the parameter is an + /// , it will simply be returned. + /// + /// + /// If no registered + /// can wrap + /// the supplied . + /// + IAdvisor Wrap(object advice); + + /// + /// Returns an to + /// allow the use of the supplied in an + /// interception-based framework. /// /// ///

- /// Implementations must also automatically register adapters for - /// types. + /// Don't worry about the pointcut associated with the + /// ; if it's an + /// , just return an + /// interceptor. ///

- /// - /// This is an SPI interface, that should not need to be implemented by any - /// Spring.NET user. - /// ///
- /// Rod Johnson - /// Aleksandar Seovic (.NET) - public interface IAdvisorAdapterRegistry - { - /// - /// Returns an wrapping the supplied - /// . - /// - /// - /// The object that should be an advice, such as - /// or - /// . - /// - /// - /// An wrapping the supplied - /// . Never returns . If - /// the parameter is an - /// , it will simply be returned. - /// - /// - /// If no registered - /// can wrap - /// the supplied . - /// - IAdvisor Wrap(object advice); + /// + /// The advisor to find an interceptor for. + /// + /// + /// An interceptor to expose this advisor's behaviour. + /// + /// + /// If the advisor type is not understood by any registered + /// . + /// + IInterceptor GetInterceptor(IAdvisor advisor); - /// - /// Returns an to - /// allow the use of the supplied in an - /// interception-based framework. - /// - /// - ///

- /// Don't worry about the pointcut associated with the - /// ; if it's an - /// , just return an - /// interceptor. - ///

- ///
- /// - /// The advisor to find an interceptor for. - /// - /// - /// An interceptor to expose this advisor's behaviour. - /// - /// - /// If the advisor type is not understood by any registered - /// . - /// - IInterceptor GetInterceptor(IAdvisor advisor); - - /// - /// Register the given . - /// - /// - ///

- /// Note that it is not necessary to register adapters for - /// instances: these - /// must be automatically recognized by an - /// - /// implementation. - ///

- ///
- /// - /// An that - /// understands the particular advisor and advice types. - /// - void RegisterAdvisorAdapter(IAdvisorAdapter adapter); - } -} \ No newline at end of file + /// + /// Register the given . + /// + /// + ///

+ /// Note that it is not necessary to register adapters for + /// instances: these + /// must be automatically recognized by an + /// + /// implementation. + ///

+ ///
+ /// + /// An that + /// understands the particular advisor and advice types. + /// + void RegisterAdvisorAdapter(IAdvisorAdapter adapter); +} diff --git a/src/Spring/Spring.Aop/Aop/Framework/Adapter/MethodBeforeAdviceInterceptor.cs b/src/Spring/Spring.Aop/Aop/Framework/Adapter/MethodBeforeAdviceInterceptor.cs index cafc93ed..347b7e57 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/Adapter/MethodBeforeAdviceInterceptor.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/Adapter/MethodBeforeAdviceInterceptor.cs @@ -25,67 +25,66 @@ using Spring.Util; #endregion -namespace Spring.Aop.Framework.Adapter +namespace Spring.Aop.Framework.Adapter; + +/// +/// implementation that +/// wraps instances. +/// +/// +///

+/// In the future Spring.NET may also offer a more efficient alternative +/// solution in cases where there is no interception advice and therefore +/// no need to create an +/// object. +///

+///

+/// Used internally by the Spring.NET AOP framework: application developers +/// should not need to use this class directly. +///

+///
+/// Rod Johnson +/// Aleksandar Seovic (.NET) +[Serializable] +internal sealed class MethodBeforeAdviceInterceptor : IMethodInterceptor { + private IMethodBeforeAdvice advice; + /// - /// implementation that - /// wraps instances. + /// Creates a new instance of the + /// + /// class. /// - /// - ///

- /// In the future Spring.NET may also offer a more efficient alternative - /// solution in cases where there is no interception advice and therefore - /// no need to create an - /// object. - ///

- ///

- /// Used internally by the Spring.NET AOP framework: application developers - /// should not need to use this class directly. - ///

- ///
- /// Rod Johnson - /// Aleksandar Seovic (.NET) - [Serializable] - internal sealed class MethodBeforeAdviceInterceptor : IMethodInterceptor + /// + /// The that is to be wrapped. + /// + /// + /// If the supplied is . + /// + public MethodBeforeAdviceInterceptor(IMethodBeforeAdvice advice) { - private IMethodBeforeAdvice advice; + AssertUtils.ArgumentNotNull(advice, "advice"); + this.advice = advice; + } - /// - /// Creates a new instance of the - /// - /// class. - /// - /// - /// The that is to be wrapped. - /// - /// - /// If the supplied is . - /// - public MethodBeforeAdviceInterceptor(IMethodBeforeAdvice advice) - { - AssertUtils.ArgumentNotNull(advice, "advice"); - this.advice = advice; - } - - /// - /// Executes interceptor before the target method successfully returns. - /// - /// - /// The method invocation that is being intercepted. - /// - /// - /// The result of the call to the - /// method of - /// the supplied . - /// - /// - /// If any of the interceptors in the chain or the target object itself - /// throws an exception. - /// - public object Invoke(IMethodInvocation invocation) - { - advice.Before(invocation.Method, invocation.Arguments, invocation.This); - return invocation.Proceed(); - } + /// + /// Executes interceptor before the target method successfully returns. + /// + /// + /// The method invocation that is being intercepted. + /// + /// + /// The result of the call to the + /// method of + /// the supplied . + /// + /// + /// If any of the interceptors in the chain or the target object itself + /// throws an exception. + /// + public object Invoke(IMethodInvocation invocation) + { + advice.Before(invocation.Method, invocation.Arguments, invocation.This); + return invocation.Proceed(); } } diff --git a/src/Spring/Spring.Aop/Aop/Framework/Adapter/ThrowsAdviceAdapter.cs b/src/Spring/Spring.Aop/Aop/Framework/Adapter/ThrowsAdviceAdapter.cs index 28bdd9b0..d089b81f 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/Adapter/ThrowsAdviceAdapter.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/Adapter/ThrowsAdviceAdapter.cs @@ -25,54 +25,53 @@ using AopAlliance.Intercept; #endregion -namespace Spring.Aop.Framework.Adapter +namespace Spring.Aop.Framework.Adapter; + +/// +/// implementation +/// to enable to be used in the +/// Spring.NET AOP framework. +/// +/// Rod Johnson +/// Aleksandar Seovic (.NET) +[Serializable] +internal class ThrowsAdviceAdapter : IAdvisorAdapter { /// - /// implementation - /// to enable to be used in the - /// Spring.NET AOP framework. + /// Returns if the supplied + /// is an instance of the + /// interface. /// - /// Rod Johnson - /// Aleksandar Seovic (.NET) - [Serializable] - internal class ThrowsAdviceAdapter : IAdvisorAdapter + /// The advice to check. + /// + /// if the supplied is + /// an instance of the interface; + /// if not or if the supplied + /// is . + /// + public virtual bool SupportsAdvice(IAdvice advice) { - /// - /// Returns if the supplied - /// is an instance of the - /// interface. - /// - /// The advice to check. - /// - /// if the supplied is - /// an instance of the interface; - /// if not or if the supplied - /// is . - /// - public virtual bool SupportsAdvice(IAdvice advice) - { - return advice is IThrowsAdvice; - } + return advice is IThrowsAdvice; + } - /// - /// Wraps the supplied 's - /// within a - /// - /// instance. - /// - /// - /// The advisor exposing the that - /// is to be wrapped. - /// - /// - /// The supplied 's - /// wrapped within a - /// - /// instance. - /// - public virtual IInterceptor GetInterceptor(IAdvisor advisor) - { - return new ThrowsAdviceInterceptor(advisor.Advice); - } + /// + /// Wraps the supplied 's + /// within a + /// + /// instance. + /// + /// + /// The advisor exposing the that + /// is to be wrapped. + /// + /// + /// The supplied 's + /// wrapped within a + /// + /// instance. + /// + public virtual IInterceptor GetInterceptor(IAdvisor advisor) + { + return new ThrowsAdviceInterceptor(advisor.Advice); } } diff --git a/src/Spring/Spring.Aop/Aop/Framework/Adapter/ThrowsAdviceInterceptor.cs b/src/Spring/Spring.Aop/Aop/Framework/Adapter/ThrowsAdviceInterceptor.cs index 787d5df8..bd37fae5 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/Adapter/ThrowsAdviceInterceptor.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/Adapter/ThrowsAdviceInterceptor.cs @@ -28,290 +28,292 @@ using Spring.Util; #endregion -namespace Spring.Aop.Framework.Adapter +namespace Spring.Aop.Framework.Adapter; + +/// Interceptor to wrap an after throwing advice. +/// +///

+/// Implementations of the interface +/// must define methods of the form... +/// +/// AfterThrowing([MethodInfo method, Object[] args, Object target], Exception subclass); +/// +/// The method name is fixed (i.e. your methods must be named +/// AfterThrowing. The first three arguments (as a whole) are +/// optional, and only useful if futher information about the joinpoint is +/// required. The return type can be anything, but is almost always +/// by convention. +///

+///

+/// Please note that the object encapsulating the throws advice does not +/// need to implement the interface. +/// Throws advice methods are discovered via reflection... the +/// interface serves merely to +/// discover objects that are to be considered as throws advice. +/// Other mechanisms for discovering throws advice such as attributes are +/// also equally valid... all that this class cares about is that a throws +/// advice object implement one or more methods with a valid throws advice +/// signature (see above, and the examples below). +///

+///

+/// This is a framework class that should not normally need to be used +/// directly by Spring.NET users. +///

+///
+/// +///

+/// Find below some examples of valid +/// method signatures... +///

+/// +/// public class GlobalExceptionHandlingAdvice : IThrowsAdvice +/// { +/// public void AfterThrowing(Exception ex) { +/// // handles absolutely any and every Exception... +/// } +/// } +/// +/// +/// public class RemotingExceptionHandlingAdvice : IThrowsAdvice +/// { +/// public void AfterThrowing(RemotingException ex) { +/// // handles any and every RemotingException (and subclasses of RemotingException)... +/// } +/// } +/// +/// +/// using System.Data; +/// +/// public class DataExceptionHandlingAdvice +/// { +/// public void AfterThrowing(ConstraintException ex) { +/// // specialised handling of ConstraintExceptions +/// } +/// +/// public void AfterThrowing(NoNullAllowedException ex) { +/// // specialised handling of NoNullAllowedExceptions +/// } +/// +/// public void AfterThrowing(DataException ex) { +/// // handles all other DataExceptions... +/// } +/// } +/// +///
+/// Rod Johnson +/// Aleksandar Seovic (.NET) +/// +[Serializable] +public sealed class ThrowsAdviceInterceptor : IMethodInterceptor { - /// Interceptor to wrap an after throwing advice. + private static readonly ILogger log = LogManager.GetLogger(); + + private const string SpecialThrowingMethodName = "AfterThrowing"; + + private readonly object throwsAdvice; + + /// + /// The mapping of exception Types to MethodInfo handlers. + /// + private readonly IDictionary exceptionHandlers; + + /// + /// Creates a new instance of the + /// class. + /// /// - ///

- /// Implementations of the interface - /// must define methods of the form... - /// - /// AfterThrowing([MethodInfo method, Object[] args, Object target], Exception subclass); - /// - /// The method name is fixed (i.e. your methods must be named - /// AfterThrowing. The first three arguments (as a whole) are - /// optional, and only useful if futher information about the joinpoint is - /// required. The return type can be anything, but is almost always - /// by convention. - ///

- ///

- /// Please note that the object encapsulating the throws advice does not - /// need to implement the interface. - /// Throws advice methods are discovered via reflection... the - /// interface serves merely to - /// discover objects that are to be considered as throws advice. - /// Other mechanisms for discovering throws advice such as attributes are - /// also equally valid... all that this class cares about is that a throws - /// advice object implement one or more methods with a valid throws advice - /// signature (see above, and the examples below). - ///

- ///

- /// This is a framework class that should not normally need to be used - /// directly by Spring.NET users. - ///

///
- /// - ///

- /// Find below some examples of valid - /// method signatures... - ///

- /// - /// public class GlobalExceptionHandlingAdvice : IThrowsAdvice - /// { - /// public void AfterThrowing(Exception ex) { - /// // handles absolutely any and every Exception... - /// } - /// } - /// - /// - /// public class RemotingExceptionHandlingAdvice : IThrowsAdvice - /// { - /// public void AfterThrowing(RemotingException ex) { - /// // handles any and every RemotingException (and subclasses of RemotingException)... - /// } - /// } - /// - /// - /// using System.Data; - /// - /// public class DataExceptionHandlingAdvice - /// { - /// public void AfterThrowing(ConstraintException ex) { - /// // specialised handling of ConstraintExceptions - /// } - /// - /// public void AfterThrowing(NoNullAllowedException ex) { - /// // specialised handling of NoNullAllowedExceptions - /// } - /// - /// public void AfterThrowing(DataException ex) { - /// // handles all other DataExceptions... - /// } - /// } - /// - ///
- /// Rod Johnson - /// Aleksandar Seovic (.NET) - /// - [Serializable] - public sealed class ThrowsAdviceInterceptor : IMethodInterceptor + /// + /// The throws advice to check for exception handler methods. + /// + /// + /// If the supplied is . + /// + /// + /// If no (0) handler methods were discovered on the supplied ; + /// or if more than one handler method suitable for a particular + /// type was discovered on the supplied + /// . + /// + public ThrowsAdviceInterceptor(object advice) { - private static readonly ILogger log = LogManager.GetLogger(); - - private const string SpecialThrowingMethodName = "AfterThrowing"; - - private readonly object throwsAdvice; - - /// - /// The mapping of exception Types to MethodInfo handlers. - /// - private readonly IDictionary exceptionHandlers; - - /// - /// Creates a new instance of the - /// class. - /// - /// - /// - /// - /// The throws advice to check for exception handler methods. - /// - /// - /// If the supplied is . - /// - /// - /// If no (0) handler methods were discovered on the supplied ; - /// or if more than one handler method suitable for a particular - /// type was discovered on the supplied - /// . - /// - public ThrowsAdviceInterceptor(object advice) + AssertUtils.ArgumentNotNull(advice, "advice"); + this.exceptionHandlers = new Hashtable(); + this.throwsAdvice = advice; + MapAllExceptionHandlingMethods(advice); + if (exceptionHandlers.Count == 0) { - AssertUtils.ArgumentNotNull(advice, "advice"); - this.exceptionHandlers = new Hashtable(); - this.throwsAdvice = advice; - MapAllExceptionHandlingMethods(advice); - if (exceptionHandlers.Count == 0) - { - throw new ArgumentException( - "At least one handler method must be found in class [" - + advice.GetType().FullName + "]."); - } + throw new ArgumentException( + "At least one handler method must be found in class [" + + advice.GetType().FullName + "]."); } + } - private void MapAllExceptionHandlingMethods(object advice) + private void MapAllExceptionHandlingMethods(object advice) + { + MethodInfo[] methods = advice.GetType().GetMethods(); + foreach (MethodInfo method in methods) { - MethodInfo[] methods = advice.GetType().GetMethods(); - foreach (MethodInfo method in methods) + int numParams = method.GetParameters().Length; + if (method.Name.Equals(SpecialThrowingMethodName) + && (numParams == 1 || numParams == 4)) { - int numParams = method.GetParameters().Length; - if (method.Name.Equals(SpecialThrowingMethodName) - && (numParams == 1 || numParams == 4)) + Type lastParametersType = method.GetParameters()[numParams - 1].ParameterType; + if (typeof(Exception).IsAssignableFrom(lastParametersType)) { - Type lastParametersType = method.GetParameters()[numParams - 1].ParameterType; - if (typeof (Exception).IsAssignableFrom(lastParametersType)) + #region Instrumentation + + if (log.IsEnabled(LogLevel.Debug)) { - #region Instrumentation - - if(log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug("Found exception handler method: " + method); - } - - #endregion - - if(this.exceptionHandlers.Contains(lastParametersType)) - { - throw new ArgumentException( - "Throws advice handler method for the [" + - lastParametersType + "] type already exists; don't define " + - "both single and multiple argument methods for the same " + - "Exception type in the same class."); - } - this.exceptionHandlers[lastParametersType] = method; + log.LogDebug("Found exception handler method: " + method); } + + #endregion + + if (this.exceptionHandlers.Contains(lastParametersType)) + { + throw new ArgumentException( + "Throws advice handler method for the [" + + lastParametersType + "] type already exists; don't define " + + "both single and multiple argument methods for the same " + + "Exception type in the same class."); + } + + this.exceptionHandlers[lastParametersType] = method; } } } + } - /// - /// Convenience property that returns the number of exception handler - /// methods managed by this interceptor. - /// - /// - /// The number of exception handler methods managed by this interceptor. - /// - public int HandlerMethodCount + /// + /// Convenience property that returns the number of exception handler + /// methods managed by this interceptor. + /// + /// + /// The number of exception handler methods managed by this interceptor. + /// + public int HandlerMethodCount + { + get { return exceptionHandlers.Count; } + } + + /// + /// Executes interceptor if (and only if) the supplied + /// throws an exception that is mapped to + /// an appropriate exception handler. + /// + /// + /// The method invocation that is being intercepted. + /// + /// + /// The result of the call to the + /// method of + /// the supplied (this assumes no + /// exception was thrown by the call to the supplied . + /// + /// + /// If any of the interceptors in the chain or the target object itself + /// throws an exception. + /// + /// + public object Invoke(IMethodInvocation invocation) + { + try { - get { return exceptionHandlers.Count; } + return invocation.Proceed(); + } + catch (TargetInvocationException ex) + { + // bah, this is a tad gross... + Exception realException = ex.InnerException; + LookupAndInvokeAnyHandler(realException, invocation); + throw realException; + } + catch (Exception ex) + { + LookupAndInvokeAnyHandler(ex, invocation); + throw; + } + } + + private void LookupAndInvokeAnyHandler(Exception ex, IMethodInvocation invocation) + { + MethodInfo handlerMethod = GetExceptionHandler(ex); + if (handlerMethod != null) + { + InvokeHandlerMethod(invocation, ex, handlerMethod); + } + } + + /// + /// Gets the exception handler (if any) that has been mapped to the + /// supplied . + /// + /// + ///

+ /// Will return if not found. + ///

+ ///
+ /// + /// The exception handler for the of the + /// supplied given exception. + /// + /// exception that was thrown + private MethodInfo GetExceptionHandler(Exception exception) + { + Type exceptionClass = exception.GetType(); + + #region Instrumentation + + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug("Trying to find handler for exception of type [" + exception.GetType().Name + "]."); } - /// - /// Executes interceptor if (and only if) the supplied - /// throws an exception that is mapped to - /// an appropriate exception handler. - /// - /// - /// The method invocation that is being intercepted. - /// - /// - /// The result of the call to the - /// method of - /// the supplied (this assumes no - /// exception was thrown by the call to the supplied . - /// - /// - /// If any of the interceptors in the chain or the target object itself - /// throws an exception. - /// - /// - public object Invoke(IMethodInvocation invocation) + #endregion + + MethodInfo handler = (MethodInfo) this.exceptionHandlers[exceptionClass]; + while (handler == null && !exceptionClass.Equals(typeof(Exception))) { - try - { - return invocation.Proceed(); - } - catch (TargetInvocationException ex) - { - // bah, this is a tad gross... - Exception realException = ex.InnerException; - LookupAndInvokeAnyHandler(realException, invocation); - throw realException; - } - catch (Exception ex) - { - LookupAndInvokeAnyHandler(ex, invocation); - throw; - } + exceptionClass = exceptionClass.BaseType; + handler = (MethodInfo) this.exceptionHandlers[exceptionClass]; } - private void LookupAndInvokeAnyHandler(Exception ex, IMethodInvocation invocation) + return handler; + } + + /// + /// Invokes handler method with appropriate number of parameters + /// + /// + /// The original method invocation that was intercepted. + /// + /// + /// The exception that triggered this interceptor. + /// + /// + /// The exception handler method to invoke. + /// + private void InvokeHandlerMethod( + IMethodInvocation invocation, Exception triggeringException, MethodInfo handlerMethod) + { + object[] handlerArgs; + if (handlerMethod.GetParameters().Length == 1) { - MethodInfo handlerMethod = GetExceptionHandler(ex); - if (handlerMethod != null) - { - InvokeHandlerMethod(invocation, ex, handlerMethod); - } + handlerArgs = new object[] { triggeringException }; + } + else + { + handlerArgs = new object[] { invocation.Method, invocation.Arguments, invocation.This, triggeringException }; } - /// - /// Gets the exception handler (if any) that has been mapped to the - /// supplied . - /// - /// - ///

- /// Will return if not found. - ///

- ///
- /// - /// The exception handler for the of the - /// supplied given exception. - /// - /// exception that was thrown - private MethodInfo GetExceptionHandler(Exception exception) + try { - Type exceptionClass = exception.GetType(); - - #region Instrumentation - - if(log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug("Trying to find handler for exception of type [" + exception.GetType().Name + "]."); - } - - #endregion - - MethodInfo handler = (MethodInfo) this.exceptionHandlers[exceptionClass]; - while (handler == null && !exceptionClass.Equals(typeof(Exception))) - { - exceptionClass = exceptionClass.BaseType; - handler = (MethodInfo) this.exceptionHandlers[exceptionClass]; - } - return handler; + handlerMethod.Invoke(this.throwsAdvice, handlerArgs); } - - /// - /// Invokes handler method with appropriate number of parameters - /// - /// - /// The original method invocation that was intercepted. - /// - /// - /// The exception that triggered this interceptor. - /// - /// - /// The exception handler method to invoke. - /// - private void InvokeHandlerMethod( - IMethodInvocation invocation, Exception triggeringException, MethodInfo handlerMethod) + catch (TargetInvocationException ex) { - object[] handlerArgs; - if (handlerMethod.GetParameters().Length == 1) - { - handlerArgs = new object[] {triggeringException}; - } - else - { - handlerArgs = new object[] {invocation.Method, invocation.Arguments, invocation.This, triggeringException}; - } - try - { - handlerMethod.Invoke(this.throwsAdvice, handlerArgs); - } - catch (TargetInvocationException ex) - { - throw ReflectionUtils.UnwrapTargetInvocationException(ex); - } + throw ReflectionUtils.UnwrapTargetInvocationException(ex); } } } diff --git a/src/Spring/Spring.Aop/Aop/Framework/Adapter/UnknownAdviceTypeException.cs b/src/Spring/Spring.Aop/Aop/Framework/Adapter/UnknownAdviceTypeException.cs index ffc69489..3a31b6c7 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/Adapter/UnknownAdviceTypeException.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/Adapter/UnknownAdviceTypeException.cs @@ -24,69 +24,68 @@ using System.Runtime.Serialization; #endregion -namespace Spring.Aop.Framework.Adapter +namespace Spring.Aop.Framework.Adapter; + +/// +/// Exception thrown when an attempt is made to use an unsupported +/// or +/// type. +/// +/// Rod Johnson +/// Aleksandar Seovic (.NET) +[Serializable] +public class UnknownAdviceTypeException : ArgumentException { /// - /// Exception thrown when an attempt is made to use an unsupported - /// or - /// type. + /// Creates a new instance of the + /// class. /// - /// Rod Johnson - /// Aleksandar Seovic (.NET) - [Serializable] - public class UnknownAdviceTypeException : ArgumentException + public UnknownAdviceTypeException() { - /// - /// Creates a new instance of the - /// class. - /// - public UnknownAdviceTypeException() - { - } + } - /// - /// Creates a new instance of the - /// class. - /// - /// The advice that caused the exception. - public UnknownAdviceTypeException(object advice) - : base("No adapter for IAdvice of type [" - + (advice != null ? advice.GetType().FullName : "null") + "].") - { - } + /// + /// Creates a new instance of the + /// class. + /// + /// The advice that caused the exception. + public UnknownAdviceTypeException(object advice) + : base("No adapter for IAdvice of type [" + + (advice != null ? advice.GetType().FullName : "null") + "].") + { + } - /// - /// Creates a new instance of the - /// class with - /// the specified message. - /// - /// - /// A message about the exception. - /// - public UnknownAdviceTypeException(string message) : base(message) - { - } + /// + /// Creates a new instance of the + /// class with + /// the specified message. + /// + /// + /// A message about the exception. + /// + public UnknownAdviceTypeException(string message) : base(message) + { + } - /// - /// Creates a new instance of the - /// class with - /// the specified message and root cause. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception that is being wrapped. - /// - public UnknownAdviceTypeException(string message, Exception rootCause) - : base(message, rootCause) - { - } + /// + /// Creates a new instance of the + /// class with + /// the specified message and root cause. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception that is being wrapped. + /// + public UnknownAdviceTypeException(string message, Exception rootCause) + : base(message, rootCause) + { + } - /// - protected UnknownAdviceTypeException(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } + /// + protected UnknownAdviceTypeException(SerializationInfo info, StreamingContext context) + : base(info, context) + { } } diff --git a/src/Spring/Spring.Aop/Aop/Framework/AdvisedSupport.cs b/src/Spring/Spring.Aop/Aop/Framework/AdvisedSupport.cs index 904a07ed..822d38ff 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/AdvisedSupport.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/AdvisedSupport.cs @@ -21,1638 +21,1665 @@ using System.Reflection; using System.Runtime.Serialization; using System.Text; - using AopAlliance.Aop; using AopAlliance.Intercept; - using Spring.Aop.Support; using Spring.Aop.Target; using Spring.Util; -namespace Spring.Aop.Framework +namespace Spring.Aop.Framework; + +/// +/// Superclass for AOP proxy configuration managers. +/// +/// +///

+/// Instances of this class are not themselves AOP proxies, but +/// subclasses of this class are normally factories from which AOP proxy +/// instances are obtained directly. +///

+///

+/// This class frees subclasses of the housekeeping of +/// and +/// instances, but doesn't actually +/// implement proxy creation methods, the functionality for which +/// is provided by subclasses. +///

+///
+/// Rod Johnson +/// Aleksandar Seovic (.NET) +/// +[Serializable] +public class AdvisedSupport : ProxyConfig, IAdvised { + /// The list of advice. + /// + ///

+ /// If an is added, it + /// will be wrapped in an advice before being added to this list. + ///

+ ///
+ private List _advisors = new List(); + /// - /// Superclass for AOP proxy configuration managers. + /// Array updated on changes to the advisors list, which is easier to + /// manipulate internally + /// + private volatile IAdvisor[] _advisorsArray = new IAdvisor[] { }; + + /// + /// List of introductions. + /// + private List _introductions = new List(); + + /// + /// Interface map specifying which object should interface methods be + /// delegated to. /// /// ///

- /// Instances of this class are not themselves AOP proxies, but - /// subclasses of this class are normally factories from which AOP proxy - /// instances are obtained directly. - ///

- ///

- /// This class frees subclasses of the housekeeping of - /// and - /// instances, but doesn't actually - /// implement proxy creation methods, the functionality for which - /// is provided by subclasses. + /// If entry value is methods should be delegated + /// to the target object. ///

///
- /// Rod Johnson - /// Aleksandar Seovic (.NET) - /// - [Serializable] - public class AdvisedSupport : ProxyConfig, IAdvised + private readonly Dictionary interfaceMap = new Dictionary(); + + /// + /// The for this instance. + /// + protected internal ITargetSource m_targetSource = EmptyTargetSource.Empty; + + /// + /// Set to when the first AOP proxy has been + /// created, meaning that we must track advice changes via the + /// OnAdviceChange() callback. + /// + private bool isActive; + + private Type cachedProxyType; + private ConstructorInfo cachedProxyConstructor; + + /// + /// The list of event listeners. + /// + private readonly List listeners = new List(); + + /// + /// The advisor chain factory. + /// + private IAdvisorChainFactory advisorChainFactory; + + /// + /// If no explicit interfaces are specified, interfaces will be automatically determined + /// from the target type + /// + private bool autoDetectInterfaces; + + /// + /// Creates a new instance of the + /// class using the + /// default advisor chain factory. + /// + public AdvisedSupport() { - /// The list of advice. - /// - ///

- /// If an is added, it - /// will be wrapped in an advice before being added to this list. - ///

- ///
- private List _advisors = new List(); + this.advisorChainFactory = new HashtableCachingAdvisorChainFactory(); + this.AddListener(this.advisorChainFactory); + this.autoDetectInterfaces = true; + } - /// - /// Array updated on changes to the advisors list, which is easier to - /// manipulate internally - /// - private volatile IAdvisor[] _advisorsArray = new IAdvisor[] { }; - - /// - /// List of introductions. - /// - private List _introductions = new List(); - - /// - /// Interface map specifying which object should interface methods be - /// delegated to. - /// - /// - ///

- /// If entry value is methods should be delegated - /// to the target object. - ///

- ///
- private readonly Dictionary interfaceMap = new Dictionary(); - - /// - /// The for this instance. - /// - protected internal ITargetSource m_targetSource = EmptyTargetSource.Empty; - - /// - /// Set to when the first AOP proxy has been - /// created, meaning that we must track advice changes via the - /// OnAdviceChange() callback. - /// - private bool isActive; - - private Type cachedProxyType; - private ConstructorInfo cachedProxyConstructor; - - /// - /// The list of event listeners. - /// - private readonly List listeners = new List(); - - /// - /// The advisor chain factory. - /// - private IAdvisorChainFactory advisorChainFactory; - - /// - /// If no explicit interfaces are specified, interfaces will be automatically determined - /// from the target type - /// - private bool autoDetectInterfaces; - - /// - /// Creates a new instance of the - /// class using the - /// default advisor chain factory. - /// - public AdvisedSupport() + /// + /// Creates a new instance of the + /// class. + /// + /// The interfaces that are to be proxied. + /// + /// If this + /// + public AdvisedSupport(Type[] interfaces) + : this() + { + if (interfaces != null) { - this.advisorChainFactory = new HashtableCachingAdvisorChainFactory(); - this.AddListener(this.advisorChainFactory); - this.autoDetectInterfaces = true; - } - - /// - /// Creates a new instance of the - /// class. - /// - /// The interfaces that are to be proxied. - /// - /// If this - /// - public AdvisedSupport(Type[] interfaces) - : this() - { - if (interfaces != null) - { - foreach (Type intf in interfaces) - { - AddInterfaceInternal(intf); - } - } - } - - /// - /// Creates a new instance of the - /// class that proxys all of the interfaces exposed by the supplied - /// . - /// - /// The object to proxy. - /// - /// If the is . - /// - public AdvisedSupport(object target) - : this(GetInterfaces(target)) - { - Target = target; - } - - /// - /// Creates a new instance of the - /// class that proxys all of the interfaces exposed by the supplied - /// 's target. - /// - /// The providing access to the object to proxy. - /// - /// If the is . - /// - public AdvisedSupport(ITargetSource targetSource) - : this(GetInterfaces(targetSource != null ? targetSource.TargetType : null)) - { - TargetSource = targetSource; - } - - /// - protected AdvisedSupport(SerializationInfo info, StreamingContext context) - : base(info, context) - { - _advisors = (List) info.GetValue("advisors", typeof(List)); - _advisorsArray = (IAdvisor[]) info.GetValue("advisorsArray", typeof(IAdvisor[])); - _introductions = (List) info.GetValue("introductions", typeof(List)); - - var map = (Dictionary) info.GetValue("interfaceMap", typeof(Dictionary)); - interfaceMap = new Dictionary(); - foreach (var pair in map) - { - interfaceMap[Type.GetType(pair.Key)] = pair.Value; - } - m_targetSource = (ITargetSource) info.GetValue("targetSource", typeof(ITargetSource)); - isActive = info.GetBoolean("isActive"); - listeners = (List) info.GetValue("listeners", typeof(List)); - advisorChainFactory = (IAdvisorChainFactory) info.GetValue("advisorChainFactory", typeof(IAdvisorChainFactory)); - autoDetectInterfaces = info.GetBoolean("autoDetectInterfaces"); - } - - /// - public override void GetObjectData(SerializationInfo info, StreamingContext context) - { - base.GetObjectData(info, context); - info.AddValue("advisors", _advisors); - info.AddValue("advisorsArray", _advisorsArray); - info.AddValue("introductions", _introductions); - var map = new Dictionary(); - foreach (var pair in interfaceMap) - { - map.Add(pair.Key.AssemblyQualifiedName, pair.Value); - } - info.AddValue("interfaceMap", map); - info.AddValue("targetSource", m_targetSource); - info.AddValue("isActive", isActive); - info.AddValue("listeners", listeners); - info.AddValue("advisorChainFactory", advisorChainFactory); - info.AddValue("autoDetectInterfaces", autoDetectInterfaces); - } - - /// - /// Gets and sets the - /// - /// implementation that will be used to get the interceptor - /// chains for the advised - /// . - /// - /// - /// The - /// implementation that will be used to get the interceptor - /// chains for the advised - /// . - /// - public virtual IAdvisorChainFactory AdvisorChainFactory - { - get - { - lock (this.SyncRoot) - { - return this.advisorChainFactory; - } - } - set - { - AssertUtils.ArgumentNotNull(value, "AdvisorChainFactory"); - lock (this.SyncRoot) - { - if (this.advisorChainFactory != null) - { - RemoveListener(this.advisorChainFactory); - } - this.advisorChainFactory = value; - AddListener(this.advisorChainFactory); - } - } - } - - /// - /// Returns the current used - /// by this object. - /// - /// - /// The used by this - /// object. - /// - /// - public ITargetSource TargetSource - { - get { return this.m_targetSource; } - set - { - m_targetSource= (value != null) ? value : EmptyTargetSource.Empty; - } - } - - /// - /// Returns a boolean specifying if this - /// instance can be serialized. - /// - /// - /// true if this instance can be serialized, false otherwise. - /// - public virtual bool IsSerializable - { - get - { - bool canBeSerialized = TargetSource.TargetType.IsSerializable; - if (!canBeSerialized) return false; - - lock (this.SyncRoot) - { - IAdvisor[] advisorsArray = this._advisorsArray; - - for (int i = 0; i < advisorsArray.Length; i++) - { - IAdvisor advisor = advisorsArray[i]; - canBeSerialized = advisor.GetType().IsSerializable - && advisor.Advice.GetType().IsSerializable; - if (!canBeSerialized) return false; - } - - for (int i = 0; i < this._introductions.Count; i++) - { - IIntroductionAdvisor advisor = this._introductions[i]; - canBeSerialized = advisor.GetType().IsSerializable - && advisor.Advice.GetType().IsSerializable; - if (!canBeSerialized) return false; - } - } - - return true; - } - } - - /// - /// Returns the collection of interface s - /// to be (or that are being) proxied by this proxy. - /// - /// - /// The collection of interface s - /// to be (or that are being) proxied by this proxy. - /// - /// - public virtual IList Interfaces - { - get - { - lock (this.SyncRoot) - { - Type[] proxiedInterfaces = new Type[this.interfaceMap.Keys.Count]; - this.interfaceMap.Keys.CopyTo(proxiedInterfaces, 0); - return proxiedInterfaces; - } - } - set - { - lock (this.SyncRoot) - { - DieIfFrozen("Cannot change interface list if frozen"); - SetInterfacesInternal(value); - } - } - } - - /// - /// Set interfaces to be proxied, bypassing locking and - /// - protected void SetInterfacesInternal(IList value) - { - this.interfaceMap.Clear(); - if (value != null) - { - for (int i = 0; i < value.Count; i++) - { - AddInterfaceInternal(value[i]); - } - } - InterfacesChanged(); - } - - /// - /// Returns the mapping of the proxied interface - /// s to their delegates. - /// - /// - /// The mapping of the proxied interface - /// s to their delegates. - /// - /// - public virtual IDictionary InterfaceMap - { - get - { - lock (SyncRoot) - { - var dictionary = new Dictionary(interfaceMap.Count); - foreach (var entry in interfaceMap) - { - dictionary[entry.Key] = entry.Value; - } - return dictionary; - } - } - } - - /// - /// Is the supplied (interface) - /// proxied? - /// - /// - /// The interface to test. - /// - /// - /// if the supplied - /// (interface) is proxied; - /// if not or the supplied - /// is . - /// - /// - public virtual bool IsInterfaceProxied(Type intf) - { - if (intf != null) - { - lock (this.SyncRoot) - { - foreach (Type proxyInterface in this.interfaceMap.Keys) - { - if (intf.IsAssignableFrom(proxyInterface)) - { - return true; - } - } - } - } - return false; - } - - /// - /// Returns the collection of - /// instances that have been applied to this proxy. - /// - /// - /// The collection of - /// instances that have been applied to this proxy. - /// - /// - public virtual IList Advisors - { - get { return _advisorsArray; } - } - - /// - /// Returns the collection of - /// instances that have been applied to this proxy. - /// - /// - ///

- /// Will never return , but may return an - /// empty array (in the case where no - /// instances have been - /// applied to this proxy). - ///

- ///
- /// - /// The collection of - /// instances that have been applied to this proxy. - /// - /// - public virtual IList Introductions - { - get - { - lock (this.SyncRoot) - { - return this._introductions; - } - } - } - - /// - /// Adds the supplied to the end (or tail) - /// of the advice (interceptor) chain. - /// - /// - /// The to be added. - /// - /// - /// - public void AddAdvice(IAdvice advice) - { - //int position = this._advisors != null ? this._advisors.Count : 0; - AddAdvice(-1, advice); - } - - /// - /// Adds the supplied to the supplied - /// in the advice (interceptor) chain. - /// - /// - /// The zero (0) indexed position (from the head) at which the - /// supplied is to be inserted into the - /// advice (interceptor) chain. - /// - /// - /// The to be added. - /// - /// - /// If the supplied is ; - /// or is not an - /// reference; or if the supplied is a - /// . - /// - /// - /// - public void AddAdvice(int position, IAdvice advice) - { - if (advice is IInterceptor && !(advice is IMethodInterceptor)) - { - throw new AopConfigException( - GetType().FullName + " can only handle AOP Alliance IMethodInterceptor advice."); - } - if (advice is IIntroductionInterceptor) - { - throw - new AopConfigException( - "IIntroductionInterceptors may only be added as part of IIntroductionAdvisor."); - } - - AddAdvisor(position, new DefaultPointcutAdvisor(advice)); - } - - /// - /// Return the index (0 based) of the supplied - /// in the interceptor - /// (advice) chain for this proxy. - /// - /// - /// The to search for. - /// - /// - /// The zero (0) based index of this advisor, or -1 if the - /// supplied is not an advisor for this - /// proxy. - /// - public virtual int IndexOf(IAdvisor advisor) - { - lock (this.SyncRoot) - { - return IndexOfInternal(advisor); - } - } - - /// - /// Return the index (0 based) of the supplied - /// in the introductions - /// for this proxy. - /// - /// - /// The to search for. - /// - /// - /// The zero (0) based index of this advisor, or -1 if the - /// supplied is not an introduction advisor - /// for this proxy. - /// - public virtual int IndexOf(IIntroductionAdvisor advisor) - { - lock (this.SyncRoot) - { - return IndexOfInternal(advisor); - } - } - - /// - /// Removes the supplied the list of advisors - /// for this proxy. - /// - /// The advisor to remove. - /// - /// if advisor was found in the list of - /// for this - /// proxy and was successfully removed; if not - /// or if the supplied is . - /// - /// - /// If this proxy configuration is frozen and the - /// cannot be removed. - /// - public bool RemoveAdvisor(IAdvisor advisor) - { - DieIfFrozen("Cannot remove advisor: config is frozen"); - bool wasRemoved = false; - if (advisor != null) - { - lock (this.SyncRoot) - { - int index = IndexOf(advisor); - if (index == -1) - { - wasRemoved = false; - } - else - { - RemoveAdvisorInternal(index); - wasRemoved = true; - } - } - } - return wasRemoved; - } - - /// - /// Removes the at the supplied - /// in the - /// list - /// from the list of - /// for this proxy. - /// - /// - /// The index of the to remove. - /// - /// - /// If this proxy configuration is frozen and the - /// at the supplied - /// cannot be removed; or if the supplied is out of - /// range. - /// - public virtual void RemoveAdvisor(int index) - { - DieIfFrozen("Cannot remove advisor: config is frozen"); - lock (this.SyncRoot) - { - RemoveAdvisorInternal(index); - } - } - - /// - /// Removes the supplied from the list - /// of . - /// - /// - /// The to remove. - /// - /// - /// if the supplied was - /// found in the list of - /// and successfully removed. - /// - /// - /// If this proxy configuration is frozen and the - /// cannot be removed. - /// - public bool RemoveAdvice(IAdvice advice) - { - lock (this.SyncRoot) - { - int index = IndexOf(advice); - if (index == -1) - { - return false; - } - RemoveAdvisorInternal(index); - return true; - } - } - - /// - /// Removes the supplied from the list - /// of . - /// - /// - /// The to remove. - /// - /// - /// if the supplied was - /// found in the list of - /// and successfully removed. - /// - /// - /// If this proxy configuration is frozen and the - /// cannot be removed. - /// - public bool RemoveIntroduction(IIntroductionAdvisor introduction) - { - DieIfFrozen("Cannot remove introduction: config is frozen"); - bool wasRemoved = false; - if (introduction != null) - { - lock (this.SyncRoot) - { - int index = IndexOf(introduction); - if (index == -1) - { - wasRemoved = false; - } - else - { - RemoveIntroduction(index); - wasRemoved = true; - } - } - } - return wasRemoved; - } - - /// - /// Removes the at the supplied - /// in the list of - /// for this proxy. - /// - /// The index of the advisor to remove. - /// - /// - /// If this proxy configuration is frozen and the - /// at the supplied - /// cannot be removed; or if the supplied - /// is out of range. - /// - public virtual void RemoveIntroduction(int index) - { - DieIfFrozen("Cannot remove introduction: config is frozen"); - lock (this.SyncRoot) - { - if (index < 0 || index >= _introductions.Count) - { - throw new AopConfigException( - "Introduction index " + index + " is out of bounds: Only have " + _introductions.Count + - " introductions."); - } - IIntroductionAdvisor advisor = _introductions[index]; - // remove all interfaces introduced by the advisor... - foreach (Type intf in advisor.Interfaces) - { - RemoveInterface(intf); - } - this._introductions.RemoveAt(index); - } - } - - /// - /// Adds the supplied to the list - /// of . - /// - /// - /// The index in the - /// list at which the supplied - /// is to be inserted. If -1, appends to the end of the list. - /// - /// - /// The to add. - /// - /// - /// If this proxy configuration is frozen and the - /// cannot be added. - /// - public virtual void AddAdvisor(int index, IAdvisor advisor) - { - DieIfFrozen("Cannot add advisor: config is frozen"); - lock (this.SyncRoot) - { - // advisor already in list (SPRNET-846) - if (_advisors.Contains(advisor)) return; - - if (index == -1) - { - this._advisors.Add(advisor); - } - else - { - this._advisors.Insert(index, advisor); - } - UpdateAdvisorsArray(); - AdviceChanged(); - } - } - - /// - /// Adds the supplied to the list - /// of . - /// - /// - /// The to add. - /// - /// - /// If this proxy configuration is frozen and the - /// cannot be added. - /// - public virtual void AddAdvisor(IAdvisor advisor) - { - AddAdvisor(this._advisors.Count, advisor); - } - - /// - /// Adds the advisors from the supplied - /// to the list of . - /// - /// - /// The to add advisors from. - /// - /// - /// If this proxy configuration is frozen and the - /// cannot be added. - /// - public void AddAdvisors(IAdvisors advisors) - { - foreach (IAdvisor advisor in advisors.Advisors) - { - if (advisor is IIntroductionAdvisor) - { - AddIntroduction((IIntroductionAdvisor)advisor); - } - else - { - AddAdvisor(advisor); - } - } - } - - /// - /// Adds the supplied to the list - /// of . - /// - /// - /// The index in the - /// list at which the supplied - /// is to be inserted. - /// - /// - /// The to add. - /// - /// - /// If this proxy configuration is frozen and the - /// cannot be added. - /// - public virtual void AddIntroduction(int index, IIntroductionAdvisor introductionAdvisor) - { - DieIfFrozen("Cannot add introduction: config is frozen"); - introductionAdvisor.ValidateInterfaces(); - - lock (this.SyncRoot) - { - if (index < this._introductions.Count) - { - this._introductions.RemoveAt(index); - } - this._introductions.Insert(index, introductionAdvisor); - - int intfCount = this.interfaceMap.Count; - // If the advisor passed validation we can make the change - foreach (Type intf in introductionAdvisor.Interfaces) - { - this.interfaceMap[intf] = introductionAdvisor; - } - if (this.interfaceMap.Count != intfCount) - { - InterfacesChanged(); - } - } - } - - /// - /// Adds the supplied to the list - /// of . - /// - /// - /// The to add. - /// - /// - /// If this proxy configuration is frozen and the - /// cannot be added. - /// - public virtual void AddIntroduction(IIntroductionAdvisor introductionAdvisor) - { - Type introductionType = introductionAdvisor.Advice.GetType(); - lock (this.SyncRoot) - { - int pos = this._introductions.Count; - for (int i = 0; i < pos; i++) - { - IIntroductionAdvisor introduction = this._introductions[i]; - if (introduction.Advice.GetType() == introductionType) - { - pos = i; - } - } - AddIntroduction(pos, introductionAdvisor); - } - } - - /// - /// Replaces the that - /// exists at the supplied in the list of - /// - /// with the supplied . - /// - /// - /// The index of the - /// in the list of - /// - /// that is to be replaced. - /// - /// - /// The new (replacement) . - /// - /// - /// If the supplied is out of range. - /// - public virtual void ReplaceIntroduction(int index, IIntroductionAdvisor introduction) - { - lock (this.SyncRoot) - { - if (index < 0 || index >= _introductions.Count) - { - throw new AopConfigException( - "Introduction index " + index + " is out of bounds:" + - " there are currently " + _introductions.Count + - " introductions."); - } - - _introductions[index] = introduction; - } - } - - /// - /// Replaces the with the - /// . - /// - /// - /// The original (old) advisor to be replaced. - /// - /// - /// The new advisor to replace the with. - /// - /// - /// if the was - /// replaced; if the was not found in the - /// advisors collection (or the is - /// , this method returns - /// and (effectively) does nothing. - /// - /// - /// If this proxy configuration is frozen and the - /// cannot be replaced. - /// - /// - public bool ReplaceAdvisor(IAdvisor oldAdvisor, IAdvisor newAdvisor) - { - DieIfFrozen("Cannot replace advisor: config is frozen."); - lock (this.SyncRoot) - { - int index = IndexOf(oldAdvisor); - if (index == -1 || newAdvisor == null) - { - return false; - } - RemoveAdvisor(index); - AddAdvisor(index, newAdvisor); - } - return true; - } - - /// - /// As will normally be passed straight through - /// to the advised target, this method returns the - /// equivalent for the AOP proxy itself. - /// - /// To override this format, override - /// - /// A description of the proxy configuration. - /// - public string ToProxyConfigString() - { - lock (this.SyncRoot) - { - return ToProxyConfigStringInternal(); - } - } - - /// - /// Returns textual information about this configuration object - /// - /// - protected virtual string ToProxyConfigStringInternal() - { - StringBuilder buffer = new StringBuilder(this.GetType().FullName + ":\n"); - buffer.Append(this.interfaceMap.Count + " interfaces=["); - this.InterfacesToString(buffer); - buffer.Append("];\n"); - buffer.Append(this._advisors.Count + " pointcuts=["); - this.AdvisorsToString(buffer); - buffer.Append("];\n"); - buffer.Append("targetSource=[" + this.m_targetSource + "];\n"); - buffer.Append("advisorChainFactory=" + this.advisorChainFactory + ";\n"); - buffer.Append(base.ToString()); - return buffer.ToString(); - } - - /// - /// Gets the target type behind the implementing object. - /// Ttypically a proxy configuration or an actual proxy. - /// - /// The type of the target or null if not known. - public Type TargetType - { - get { return TargetSource.TargetType; } - } - - /// - /// If no explicit interfaces are specified, interfaces will be automatically determined - /// from the target type on proxy creation. Defaults to true - /// - public bool AutoDetectInterfaces - { - get { return autoDetectInterfaces; } - set { autoDetectInterfaces = value; } - } - - /// - /// Sets the target object that is to be advised. - /// - /// - ///

- /// This is a convenience write-only property that allows client code - /// to set the target object... the target object will be implicitly - /// wrapped within a new - /// instance. - ///

- ///
- public virtual object Target - { - set { TargetSource = new SingletonTargetSource(value); } - } - - /// - /// Called by subclasses to get a value indicating whether any AOP proxies have been created yet. - /// - /// true if this AOp proxies have been created; otherwise, false. - protected bool IsActive - { - get { return isActive; } - } - - /// - /// Specifies the of proxies that are to be - /// created for this instance of proxy config. - /// - /// - ///

- /// If this property value is it simply means that - /// no proxies have been created yet. Only when the first proxy is - /// created will this property value be set by the AOP framework. - ///

- ///

- /// Users will be able to add interceptors dynamically without proxy - /// regeneration, but if they add introductions the proxy - /// will have to be regenerated. - ///

- ///
- /// - /// The of proxies that are to be - /// created for this instance of proxy config; if - /// no proxies have been created yet. - /// - internal Type ProxyType - { - get { return this.cachedProxyType; } - set { this.cachedProxyType = value; } - } - - /// - /// Caches proxy constructor for performance reasons. - /// - internal ConstructorInfo ProxyConstructor - { - get { return this.cachedProxyConstructor; } - set { this.cachedProxyConstructor = value; } - } - - /// - /// Registers the supplied as a listener for - /// notifications. - /// - /// - /// The to - /// register. - /// - public virtual void AddListener(IAdvisedSupportListener listener) - { - lock (this.SyncRoot) - { - this.listeners.Add(listener); - } - } - - /// - /// Removes the supplied . - /// - /// - /// The to - /// be removed. - /// - public virtual void RemoveListener(IAdvisedSupportListener listener) - { - lock (this.SyncRoot) - { - this.listeners.Remove(listener); - } - } - - /// - /// Adds a new interface to the list of interfaces that are proxied by this proxy. - /// - /// - /// The interface to be proxied by this proxy. - /// - /// - /// If this proxy configuration is frozen - /// (); - /// - /// - /// If the supplied is . - /// - public virtual void AddInterface(Type intf) - { - DieIfFrozen("Cannot add interface: configuration is frozen."); - AssertUtils.ArgumentNotNull(intf, "intf", "Cannot proxy a null interface."); - - lock (this.SyncRoot) + foreach (Type intf in interfaces) { AddInterfaceInternal(intf); - InterfacesChanged(); } } + } - /// - /// Adds a new interface to the list of interfaces that are proxied by this proxy. - /// - /// - /// The interface to be proxied by this proxy. - /// - /// - /// Access is not synchronized. - /// - protected virtual void AddInterfaceInternal(Type intf) + /// + /// Creates a new instance of the + /// class that proxys all of the interfaces exposed by the supplied + /// . + /// + /// The object to proxy. + /// + /// If the is . + /// + public AdvisedSupport(object target) + : this(GetInterfaces(target)) + { + Target = target; + } + + /// + /// Creates a new instance of the + /// class that proxys all of the interfaces exposed by the supplied + /// 's target. + /// + /// The providing access to the object to proxy. + /// + /// If the is . + /// + public AdvisedSupport(ITargetSource targetSource) + : this(GetInterfaces(targetSource != null ? targetSource.TargetType : null)) + { + TargetSource = targetSource; + } + + /// + protected AdvisedSupport(SerializationInfo info, StreamingContext context) + : base(info, context) + { + _advisors = (List) info.GetValue("advisors", typeof(List)); + _advisorsArray = (IAdvisor[]) info.GetValue("advisorsArray", typeof(IAdvisor[])); + _introductions = (List) info.GetValue("introductions", typeof(List)); + + var map = (Dictionary) info.GetValue("interfaceMap", typeof(Dictionary)); + interfaceMap = new Dictionary(); + foreach (var pair in map) { - this.interfaceMap[intf] = null; + interfaceMap[Type.GetType(pair.Key)] = pair.Value; } - /// - /// Removes the supplied (proxied) . - /// - /// - ///

- /// Does nothing if the supplied (proxied) - /// isn't proxied. - ///

- ///
- /// The interface to remove. - /// - /// if the interface was removed. - public virtual bool RemoveInterface(Type intf) + m_targetSource = (ITargetSource) info.GetValue("targetSource", typeof(ITargetSource)); + isActive = info.GetBoolean("isActive"); + listeners = (List) info.GetValue("listeners", typeof(List)); + advisorChainFactory = (IAdvisorChainFactory) info.GetValue("advisorChainFactory", typeof(IAdvisorChainFactory)); + autoDetectInterfaces = info.GetBoolean("autoDetectInterfaces"); + } + + /// + public override void GetObjectData(SerializationInfo info, StreamingContext context) + { + base.GetObjectData(info, context); + info.AddValue("advisors", _advisors); + info.AddValue("advisorsArray", _advisorsArray); + info.AddValue("introductions", _introductions); + var map = new Dictionary(); + foreach (var pair in interfaceMap) { - DieIfFrozen("Cannot remove interface: configuration is frozen."); - lock (this.SyncRoot) - { - if (intf != null && this.interfaceMap.ContainsKey(intf)) - { - this.interfaceMap.Remove(intf); - InterfacesChanged(); - return true; - } - } - return false; + map.Add(pair.Key.AssemblyQualifiedName, pair.Value); } - /// - /// Return the index (0 based) of the supplied - /// in the interceptor - /// (advice) chain for this proxy. - /// - /// - ///

- /// The return value of this method can be used to index into - /// the - /// list. - ///

- ///
- /// - /// The to search for. - /// - /// - /// The zero (0) based index of this interceptor, or -1 if the - /// supplied is not an advice for this - /// proxy. - /// - public virtual int IndexOf(IAdvice advice) + info.AddValue("interfaceMap", map); + info.AddValue("targetSource", m_targetSource); + info.AddValue("isActive", isActive); + info.AddValue("listeners", listeners); + info.AddValue("advisorChainFactory", advisorChainFactory); + info.AddValue("autoDetectInterfaces", autoDetectInterfaces); + } + + /// + /// Gets and sets the + /// + /// implementation that will be used to get the interceptor + /// chains for the advised + /// . + /// + /// + /// The + /// implementation that will be used to get the interceptor + /// chains for the advised + /// . + /// + public virtual IAdvisorChainFactory AdvisorChainFactory + { + get { lock (this.SyncRoot) { - return IndexOfInternal(advice); + return this.advisorChainFactory; } } - - /// - /// Return the index (0 based) of the supplied - /// in the interceptor - /// (advice) chain for this proxy. - /// - /// - ///

Acces is not synchronized

- ///

- /// The return value of this method can be used to index into - /// the - /// list. - ///

- ///
- /// - /// The to search for. - /// - /// - /// The zero (0) based index of this interceptor, or -1 if the - /// supplied is not an advice for this - /// proxy. - /// - private int IndexOfInternal(IAdvice advice) + set { - if (this._advisors != null) - { - for (int i = 0; i < this._advisors.Count; ++i) - { - IAdvisor advisor = this._advisors[i]; - if (advisor.Advice == advice) - { - return i; - } - } - } - return -1; - } - - /// - /// Return the index (0 based) of the supplied - /// in the interceptor - /// (advice) chain for this proxy. - /// - /// - /// The to search for. - /// - /// - /// The zero (0) based index of this advisor, or -1 if the - /// supplied is not an advisor for this - /// proxy. - /// - /// - /// Access is not synchronized. - /// - private int IndexOfInternal(IAdvisor advisor) - { - return this._advisors != null ? this._advisors.IndexOf(advisor) : -1; - } - - /// - /// Return the index (0 based) of the supplied - /// in the introductions - /// for this proxy. - /// - /// - /// The to search for. - /// - /// - /// The zero (0) based index of this advisor, or -1 if the - /// supplied is not an introduction advisor - /// for this proxy. - /// - /// - /// Access is not synchronized - /// - private int IndexOfInternal(IIntroductionAdvisor advisor) - { - return this._introductions.IndexOf(advisor); - } - - /// - /// Removes the at the supplied - /// in the - /// list - /// from the list of - /// for this proxy. - /// - /// - /// The index of the to remove. - /// - /// - /// If this proxy configuration is frozen and the - /// at the supplied - /// cannot be removed; or if the supplied is out of - /// range. - /// - /// - /// Does not synchronize access. - /// - private void RemoveAdvisorInternal(int index) - { - if (index < 0 || index >= this._advisors.Count) - { - throw - new AopConfigException( - "Advisor index " + index + " is out of bounds: Only have " + this._advisors.Count + " advisors"); - } - this._advisors.RemoveAt(index); - this.UpdateAdvisorsArray(); - this.AdviceChanged(); - } - - /// - /// Is the supplied included in any - /// advisor? - /// - /// - /// The to check for the - /// inclusion of. - /// - /// - /// if the supplied - /// could be run in an invocation (this does not imply that said - /// will be run). - /// - public bool AdviceIncluded(IAdvice advice) - { - return (IndexOf(advice) != -1); - } - - /// - /// Returns a count of all of the - /// type-compatible with the supplied . - /// - /// - /// The of the - /// to check. - /// - /// - /// A count of all of the - /// type-compatible with the supplied . - /// - public int CountAdviceOfType(Type interceptorType) - { - int count = 0; + AssertUtils.ArgumentNotNull(value, "AdvisorChainFactory"); lock (this.SyncRoot) { - foreach (IAdvisor advisor in this._advisors) + if (this.advisorChainFactory != null) { - if (interceptorType.IsAssignableFrom(advisor.Advice.GetType())) - { - ++count; - } + RemoveListener(this.advisorChainFactory); + } + + this.advisorChainFactory = value; + AddListener(this.advisorChainFactory); + } + } + } + + /// + /// Returns the current used + /// by this object. + /// + /// + /// The used by this + /// object. + /// + /// + public ITargetSource TargetSource + { + get { return this.m_targetSource; } + set + { + m_targetSource = (value != null) ? value : EmptyTargetSource.Empty; + } + } + + /// + /// Returns a boolean specifying if this + /// instance can be serialized. + /// + /// + /// true if this instance can be serialized, false otherwise. + /// + public virtual bool IsSerializable + { + get + { + bool canBeSerialized = TargetSource.TargetType.IsSerializable; + if (!canBeSerialized) return false; + + lock (this.SyncRoot) + { + IAdvisor[] advisorsArray = this._advisorsArray; + + for (int i = 0; i < advisorsArray.Length; i++) + { + IAdvisor advisor = advisorsArray[i]; + canBeSerialized = advisor.GetType().IsSerializable + && advisor.Advice.GetType().IsSerializable; + if (!canBeSerialized) return false; + } + + for (int i = 0; i < this._introductions.Count; i++) + { + IIntroductionAdvisor advisor = this._introductions[i]; + canBeSerialized = advisor.GetType().IsSerializable + && advisor.Advice.GetType().IsSerializable; + if (!canBeSerialized) return false; } } - return count; - } - /// - /// Throws an if - /// this instances proxy configuration data is frozen. - /// - /// - /// The message that will be passed through to the constructor of any - /// thrown . - /// - /// - /// If the configuration for this proxy is frozen. - /// - /// - private void DieIfFrozen(string message) - { - if (IsFrozen) - { - throw new AopConfigException(message); - } + return true; } + } - /// - /// Bring the advisors array up to date with the list. - /// - private void UpdateAdvisorsArray() - { - IAdvisor[] advisorsArray = new IAdvisor[this._advisors.Count]; - this._advisors.CopyTo(advisorsArray, 0); - this._advisorsArray = advisorsArray; - } - - /// - /// Callback method that is invoked when the list of proxied interfaces - /// has changed. - /// - /// - ///

- /// An example of such a change would be when a new introduction is - /// added. Resetting - /// to - /// will cause a new proxy - /// to be generated on the next call to get a proxy. - ///

- ///
- protected virtual void InterfacesChanged() - { - this.cachedProxyType = null; - this.cachedProxyConstructor = null; - if (this.isActive) - { - foreach (IAdvisedSupportListener listener in this.listeners) - { - listener.InterfacesChanged(this); - } - } - } - - /// - /// Callback method that is invoked when the interceptor list has changed. - /// - protected virtual void AdviceChanged() - { - if (this.isActive) - { - foreach (IAdvisedSupportListener listener in this.listeners) - { - listener.AdviceChanged(this); - } - } - } - - /// - /// Activates this instance. - /// - protected void Activate() + /// + /// Returns the collection of interface s + /// to be (or that are being) proxied by this proxy. + /// + /// + /// The collection of interface s + /// to be (or that are being) proxied by this proxy. + /// + /// + public virtual IList Interfaces + { + get { lock (this.SyncRoot) { - this.isActive = true; - foreach (IAdvisedSupportListener listener in this.listeners) - { - listener.Activated(this); - } + Type[] proxiedInterfaces = new Type[this.interfaceMap.Keys.Count]; + this.interfaceMap.Keys.CopyTo(proxiedInterfaces, 0); + return proxiedInterfaces; } } - - /// - /// Creates an AOP proxy using this instance's configuration data. - /// - /// - ///

- /// Subclasses must not create a proxy by any other means (at least - /// without having a well thought out and cogent reason for doing so). - /// This is because the implementation of this method performs some - /// required housekeeping logic prior to creating an AOP proxy. - ///

- ///
- /// - protected internal virtual IAopProxy CreateAopProxy() + set { lock (this.SyncRoot) { - if (this.autoDetectInterfaces && CountNonIntroductionInterfaces() == 0 -// && !this.ProxyTargetType - ) - { - this.interfaceMap.Clear(); - // add all target interfaces - Type[] targetInterfaces = ReflectionUtils.GetInterfaces(this.TargetType); - foreach(Type targetInterface in targetInterfaces ) - { - this.interfaceMap[targetInterface] = null; - } - // add introduced interfaces - foreach(IIntroductionAdvisor introduction in this._introductions) - { - foreach(Type introducedInterface in introduction.Interfaces) - { - this.interfaceMap[introducedInterface] = introduction; - } - } + DieIfFrozen("Cannot change interface list if frozen"); + SetInterfacesInternal(value); + } + } + } - if (targetInterfaces.Length > 0) - { - InterfacesChanged(); - } - } - - if (!this.isActive) - { - Activate(); - } - return AopProxyFactory.CreateAopProxy(this); + /// + /// Set interfaces to be proxied, bypassing locking and + /// + protected void SetInterfacesInternal(IList value) + { + this.interfaceMap.Clear(); + if (value != null) + { + for (int i = 0; i < value.Count; i++) + { + AddInterfaceInternal(value[i]); } } - /// - /// Calculates the number of not delegating to one of the . - /// - private int CountNonIntroductionInterfaces() + InterfacesChanged(); + } + + /// + /// Returns the mapping of the proxied interface + /// s to their delegates. + /// + /// + /// The mapping of the proxied interface + /// s to their delegates. + /// + /// + public virtual IDictionary InterfaceMap + { + get { - int c = 0; - foreach(Type interfaceType in this.interfaceMap.Keys) + lock (SyncRoot) { - if (this.interfaceMap[interfaceType] == null) + var dictionary = new Dictionary(interfaceMap.Count); + foreach (var entry in interfaceMap) { - c++; + dictionary[entry.Key] = entry.Value; + } + + return dictionary; + } + } + } + + /// + /// Is the supplied (interface) + /// proxied? + /// + /// + /// The interface to test. + /// + /// + /// if the supplied + /// (interface) is proxied; + /// if not or the supplied + /// is . + /// + /// + public virtual bool IsInterfaceProxied(Type intf) + { + if (intf != null) + { + lock (this.SyncRoot) + { + foreach (Type proxyInterface in this.interfaceMap.Keys) + { + if (intf.IsAssignableFrom(proxyInterface)) + { + return true; + } } } - return c; } - /// - /// Copies the configuration from the supplied other - /// into this instance. - /// - /// - ///

- /// Useful when this instance has been created using the no-argument - /// constructor, and needs to get all of its confiuration data from - /// another (most - /// usually to have an independant copy of said configuration data). - ///

- ///
- /// - /// The instance - /// containing the configiration data that is to be copied into this - /// instance. - /// - protected internal virtual void CopyConfigurationFrom(AdvisedSupport other) + return false; + } + + /// + /// Returns the collection of + /// instances that have been applied to this proxy. + /// + /// + /// The collection of + /// instances that have been applied to this proxy. + /// + /// + public virtual IList Advisors + { + get { return _advisorsArray; } + } + + /// + /// Returns the collection of + /// instances that have been applied to this proxy. + /// + /// + ///

+ /// Will never return , but may return an + /// empty array (in the case where no + /// instances have been + /// applied to this proxy). + ///

+ ///
+ /// + /// The collection of + /// instances that have been applied to this proxy. + /// + /// + public virtual IList Introductions + { + get { - CopyConfigurationFrom(other, other.TargetSource, new List(other.Advisors), new List(other.Introductions)); + lock (this.SyncRoot) + { + return this._introductions; + } + } + } + + /// + /// Adds the supplied to the end (or tail) + /// of the advice (interceptor) chain. + /// + /// + /// The to be added. + /// + /// + /// + public void AddAdvice(IAdvice advice) + { + //int position = this._advisors != null ? this._advisors.Count : 0; + AddAdvice(-1, advice); + } + + /// + /// Adds the supplied to the supplied + /// in the advice (interceptor) chain. + /// + /// + /// The zero (0) indexed position (from the head) at which the + /// supplied is to be inserted into the + /// advice (interceptor) chain. + /// + /// + /// The to be added. + /// + /// + /// If the supplied is ; + /// or is not an + /// reference; or if the supplied is a + /// . + /// + /// + /// + public void AddAdvice(int position, IAdvice advice) + { + if (advice is IInterceptor && !(advice is IMethodInterceptor)) + { + throw new AopConfigException( + GetType().FullName + " can only handle AOP Alliance IMethodInterceptor advice."); } - /// - /// Copies the configuration from the supplied other - /// into this instance. - /// - /// - ///

- /// Useful when this instance has been created using the no-argument - /// constructor, and needs to get all of its confiuration data from - /// another (most - /// usually to have an independant copy of said configuration data). - ///

- ///
- /// - /// The instance - /// containing the configiration data that is to be copied into this - /// instance. - /// - /// the new target source - /// the advisors for the chain - /// the introductions for the chain - protected internal virtual void CopyConfigurationFrom(AdvisedSupport other, ITargetSource targetSource, IList advisors, IList introductions) + if (advice is IIntroductionInterceptor) { - CopyFrom(other); - this.AdvisorChainFactory = other.advisorChainFactory; - this.m_targetSource = targetSource; -// this.cachedProxyType = other.cachedProxyType; -// this.cachedProxyConstructor = other.cachedProxyConstructor; - this.Interfaces = new List(other.Interfaces); - foreach (Type intf in other.interfaceMap.Keys) + throw + new AopConfigException( + "IIntroductionInterceptors may only be added as part of IIntroductionAdvisor."); + } + + AddAdvisor(position, new DefaultPointcutAdvisor(advice)); + } + + /// + /// Return the index (0 based) of the supplied + /// in the interceptor + /// (advice) chain for this proxy. + /// + /// + /// The to search for. + /// + /// + /// The zero (0) based index of this advisor, or -1 if the + /// supplied is not an advisor for this + /// proxy. + /// + public virtual int IndexOf(IAdvisor advisor) + { + lock (this.SyncRoot) + { + return IndexOfInternal(advisor); + } + } + + /// + /// Return the index (0 based) of the supplied + /// in the introductions + /// for this proxy. + /// + /// + /// The to search for. + /// + /// + /// The zero (0) based index of this advisor, or -1 if the + /// supplied is not an introduction advisor + /// for this proxy. + /// + public virtual int IndexOf(IIntroductionAdvisor advisor) + { + lock (this.SyncRoot) + { + return IndexOfInternal(advisor); + } + } + + /// + /// Removes the supplied the list of advisors + /// for this proxy. + /// + /// The advisor to remove. + /// + /// if advisor was found in the list of + /// for this + /// proxy and was successfully removed; if not + /// or if the supplied is . + /// + /// + /// If this proxy configuration is frozen and the + /// cannot be removed. + /// + public bool RemoveAdvisor(IAdvisor advisor) + { + DieIfFrozen("Cannot remove advisor: config is frozen"); + bool wasRemoved = false; + if (advisor != null) + { + lock (this.SyncRoot) { - this.interfaceMap[intf] = other.interfaceMap[intf]; + int index = IndexOf(advisor); + if (index == -1) + { + wasRemoved = false; + } + else + { + RemoveAdvisorInternal(index); + wasRemoved = true; + } } - this._advisors = new List(); - foreach (IAdvisor advisor in advisors) + } + + return wasRemoved; + } + + /// + /// Removes the at the supplied + /// in the + /// list + /// from the list of + /// for this proxy. + /// + /// + /// The index of the to remove. + /// + /// + /// If this proxy configuration is frozen and the + /// at the supplied + /// cannot be removed; or if the supplied is out of + /// range. + /// + public virtual void RemoveAdvisor(int index) + { + DieIfFrozen("Cannot remove advisor: config is frozen"); + lock (this.SyncRoot) + { + RemoveAdvisorInternal(index); + } + } + + /// + /// Removes the supplied from the list + /// of . + /// + /// + /// The to remove. + /// + /// + /// if the supplied was + /// found in the list of + /// and successfully removed. + /// + /// + /// If this proxy configuration is frozen and the + /// cannot be removed. + /// + public bool RemoveAdvice(IAdvice advice) + { + lock (this.SyncRoot) + { + int index = IndexOf(advice); + if (index == -1) { - AssertUtils.ArgumentNotNull(advisor, "Advisor must not be null"); - AddAdvisor(advisor); + return false; } - this._introductions = new List(); - foreach (IIntroductionAdvisor advisor in introductions) + + RemoveAdvisorInternal(index); + return true; + } + } + + /// + /// Removes the supplied from the list + /// of . + /// + /// + /// The to remove. + /// + /// + /// if the supplied was + /// found in the list of + /// and successfully removed. + /// + /// + /// If this proxy configuration is frozen and the + /// cannot be removed. + /// + public bool RemoveIntroduction(IIntroductionAdvisor introduction) + { + DieIfFrozen("Cannot remove introduction: config is frozen"); + bool wasRemoved = false; + if (introduction != null) + { + lock (this.SyncRoot) { - // TODO (EE): implement -// ValidateIntroductionAdvisor((IIntroductionAdvisor) advisor); - AssertUtils.ArgumentNotNull(advisor, "IntroductionAdvisor must not be null"); - AddIntroduction(advisor); + int index = IndexOf(introduction); + if (index == -1) + { + wasRemoved = false; + } + else + { + RemoveIntroduction(index); + wasRemoved = true; + } } + } + + return wasRemoved; + } + + /// + /// Removes the at the supplied + /// in the list of + /// for this proxy. + /// + /// The index of the advisor to remove. + /// + /// + /// If this proxy configuration is frozen and the + /// at the supplied + /// cannot be removed; or if the supplied + /// is out of range. + /// + public virtual void RemoveIntroduction(int index) + { + DieIfFrozen("Cannot remove introduction: config is frozen"); + lock (this.SyncRoot) + { + if (index < 0 || index >= _introductions.Count) + { + throw new AopConfigException( + "Introduction index " + index + " is out of bounds: Only have " + _introductions.Count + + " introductions."); + } + + IIntroductionAdvisor advisor = _introductions[index]; + // remove all interfaces introduced by the advisor... + foreach (Type intf in advisor.Interfaces) + { + RemoveInterface(intf); + } + + this._introductions.RemoveAt(index); + } + } + + /// + /// Adds the supplied to the list + /// of . + /// + /// + /// The index in the + /// list at which the supplied + /// is to be inserted. If -1, appends to the end of the list. + /// + /// + /// The to add. + /// + /// + /// If this proxy configuration is frozen and the + /// cannot be added. + /// + public virtual void AddAdvisor(int index, IAdvisor advisor) + { + DieIfFrozen("Cannot add advisor: config is frozen"); + lock (this.SyncRoot) + { + // advisor already in list (SPRNET-846) + if (_advisors.Contains(advisor)) return; + + if (index == -1) + { + this._advisors.Add(advisor); + } + else + { + this._advisors.Insert(index, advisor); + } + UpdateAdvisorsArray(); AdviceChanged(); } + } - /// - /// A that represents the current - /// configuration. - /// - /// - /// A that represents the current - /// configuration. - /// - public override string ToString() + /// + /// Adds the supplied to the list + /// of . + /// + /// + /// The to add. + /// + /// + /// If this proxy configuration is frozen and the + /// cannot be added. + /// + public virtual void AddAdvisor(IAdvisor advisor) + { + AddAdvisor(this._advisors.Count, advisor); + } + + /// + /// Adds the advisors from the supplied + /// to the list of . + /// + /// + /// The to add advisors from. + /// + /// + /// If this proxy configuration is frozen and the + /// cannot be added. + /// + public void AddAdvisors(IAdvisors advisors) + { + foreach (IAdvisor advisor in advisors.Advisors) { - lock (this.SyncRoot) + if (advisor is IIntroductionAdvisor) { - return ToProxyConfigString(); + AddIntroduction((IIntroductionAdvisor) advisor); + } + else + { + AddAdvisor(advisor); + } + } + } + + /// + /// Adds the supplied to the list + /// of . + /// + /// + /// The index in the + /// list at which the supplied + /// is to be inserted. + /// + /// + /// The to add. + /// + /// + /// If this proxy configuration is frozen and the + /// cannot be added. + /// + public virtual void AddIntroduction(int index, IIntroductionAdvisor introductionAdvisor) + { + DieIfFrozen("Cannot add introduction: config is frozen"); + introductionAdvisor.ValidateInterfaces(); + + lock (this.SyncRoot) + { + if (index < this._introductions.Count) + { + this._introductions.RemoveAt(index); + } + + this._introductions.Insert(index, introductionAdvisor); + + int intfCount = this.interfaceMap.Count; + // If the advisor passed validation we can make the change + foreach (Type intf in introductionAdvisor.Interfaces) + { + this.interfaceMap[intf] = introductionAdvisor; + } + + if (this.interfaceMap.Count != intfCount) + { + InterfacesChanged(); + } + } + } + + /// + /// Adds the supplied to the list + /// of . + /// + /// + /// The to add. + /// + /// + /// If this proxy configuration is frozen and the + /// cannot be added. + /// + public virtual void AddIntroduction(IIntroductionAdvisor introductionAdvisor) + { + Type introductionType = introductionAdvisor.Advice.GetType(); + lock (this.SyncRoot) + { + int pos = this._introductions.Count; + for (int i = 0; i < pos; i++) + { + IIntroductionAdvisor introduction = this._introductions[i]; + if (introduction.Advice.GetType() == introductionType) + { + pos = i; + } + } + + AddIntroduction(pos, introductionAdvisor); + } + } + + /// + /// Replaces the that + /// exists at the supplied in the list of + /// + /// with the supplied . + /// + /// + /// The index of the + /// in the list of + /// + /// that is to be replaced. + /// + /// + /// The new (replacement) . + /// + /// + /// If the supplied is out of range. + /// + public virtual void ReplaceIntroduction(int index, IIntroductionAdvisor introduction) + { + lock (this.SyncRoot) + { + if (index < 0 || index >= _introductions.Count) + { + throw new AopConfigException( + "Introduction index " + index + " is out of bounds:" + + " there are currently " + _introductions.Count + + " introductions."); + } + + _introductions[index] = introduction; + } + } + + /// + /// Replaces the with the + /// . + /// + /// + /// The original (old) advisor to be replaced. + /// + /// + /// The new advisor to replace the with. + /// + /// + /// if the was + /// replaced; if the was not found in the + /// advisors collection (or the is + /// , this method returns + /// and (effectively) does nothing. + /// + /// + /// If this proxy configuration is frozen and the + /// cannot be replaced. + /// + /// + public bool ReplaceAdvisor(IAdvisor oldAdvisor, IAdvisor newAdvisor) + { + DieIfFrozen("Cannot replace advisor: config is frozen."); + lock (this.SyncRoot) + { + int index = IndexOf(oldAdvisor); + if (index == -1 || newAdvisor == null) + { + return false; + } + + RemoveAdvisor(index); + AddAdvisor(index, newAdvisor); + } + + return true; + } + + /// + /// As will normally be passed straight through + /// to the advised target, this method returns the + /// equivalent for the AOP proxy itself. + /// + /// To override this format, override + /// + /// A description of the proxy configuration. + /// + public string ToProxyConfigString() + { + lock (this.SyncRoot) + { + return ToProxyConfigStringInternal(); + } + } + + /// + /// Returns textual information about this configuration object + /// + /// + protected virtual string ToProxyConfigStringInternal() + { + StringBuilder buffer = new StringBuilder(this.GetType().FullName + ":\n"); + buffer.Append(this.interfaceMap.Count + " interfaces=["); + this.InterfacesToString(buffer); + buffer.Append("];\n"); + buffer.Append(this._advisors.Count + " pointcuts=["); + this.AdvisorsToString(buffer); + buffer.Append("];\n"); + buffer.Append("targetSource=[" + this.m_targetSource + "];\n"); + buffer.Append("advisorChainFactory=" + this.advisorChainFactory + ";\n"); + buffer.Append(base.ToString()); + return buffer.ToString(); + } + + /// + /// Gets the target type behind the implementing object. + /// Ttypically a proxy configuration or an actual proxy. + /// + /// The type of the target or null if not known. + public Type TargetType + { + get { return TargetSource.TargetType; } + } + + /// + /// If no explicit interfaces are specified, interfaces will be automatically determined + /// from the target type on proxy creation. Defaults to true + /// + public bool AutoDetectInterfaces + { + get { return autoDetectInterfaces; } + set { autoDetectInterfaces = value; } + } + + /// + /// Sets the target object that is to be advised. + /// + /// + ///

+ /// This is a convenience write-only property that allows client code + /// to set the target object... the target object will be implicitly + /// wrapped within a new + /// instance. + ///

+ ///
+ public virtual object Target + { + set { TargetSource = new SingletonTargetSource(value); } + } + + /// + /// Called by subclasses to get a value indicating whether any AOP proxies have been created yet. + /// + /// true if this AOp proxies have been created; otherwise, false. + protected bool IsActive + { + get { return isActive; } + } + + /// + /// Specifies the of proxies that are to be + /// created for this instance of proxy config. + /// + /// + ///

+ /// If this property value is it simply means that + /// no proxies have been created yet. Only when the first proxy is + /// created will this property value be set by the AOP framework. + ///

+ ///

+ /// Users will be able to add interceptors dynamically without proxy + /// regeneration, but if they add introductions the proxy + /// will have to be regenerated. + ///

+ ///
+ /// + /// The of proxies that are to be + /// created for this instance of proxy config; if + /// no proxies have been created yet. + /// + internal Type ProxyType + { + get { return this.cachedProxyType; } + set { this.cachedProxyType = value; } + } + + /// + /// Caches proxy constructor for performance reasons. + /// + internal ConstructorInfo ProxyConstructor + { + get { return this.cachedProxyConstructor; } + set { this.cachedProxyConstructor = value; } + } + + /// + /// Registers the supplied as a listener for + /// notifications. + /// + /// + /// The to + /// register. + /// + public virtual void AddListener(IAdvisedSupportListener listener) + { + lock (this.SyncRoot) + { + this.listeners.Add(listener); + } + } + + /// + /// Removes the supplied . + /// + /// + /// The to + /// be removed. + /// + public virtual void RemoveListener(IAdvisedSupportListener listener) + { + lock (this.SyncRoot) + { + this.listeners.Remove(listener); + } + } + + /// + /// Adds a new interface to the list of interfaces that are proxied by this proxy. + /// + /// + /// The interface to be proxied by this proxy. + /// + /// + /// If this proxy configuration is frozen + /// (); + /// + /// + /// If the supplied is . + /// + public virtual void AddInterface(Type intf) + { + DieIfFrozen("Cannot add interface: configuration is frozen."); + AssertUtils.ArgumentNotNull(intf, "intf", "Cannot proxy a null interface."); + + lock (this.SyncRoot) + { + AddInterfaceInternal(intf); + InterfacesChanged(); + } + } + + /// + /// Adds a new interface to the list of interfaces that are proxied by this proxy. + /// + /// + /// The interface to be proxied by this proxy. + /// + /// + /// Access is not synchronized. + /// + protected virtual void AddInterfaceInternal(Type intf) + { + this.interfaceMap[intf] = null; + } + + /// + /// Removes the supplied (proxied) . + /// + /// + ///

+ /// Does nothing if the supplied (proxied) + /// isn't proxied. + ///

+ ///
+ /// The interface to remove. + /// + /// if the interface was removed. + public virtual bool RemoveInterface(Type intf) + { + DieIfFrozen("Cannot remove interface: configuration is frozen."); + lock (this.SyncRoot) + { + if (intf != null && this.interfaceMap.ContainsKey(intf)) + { + this.interfaceMap.Remove(intf); + InterfacesChanged(); + return true; } } - /// - /// Helper method that adds the names of all of the proxied interfaces - /// to the buffer of the supplied . - /// - /// - /// The to append the proxied interface - /// names to. - /// - private void InterfacesToString(StringBuilder buffer) + return false; + } + + /// + /// Return the index (0 based) of the supplied + /// in the interceptor + /// (advice) chain for this proxy. + /// + /// + ///

+ /// The return value of this method can be used to index into + /// the + /// list. + ///

+ ///
+ /// + /// The to search for. + /// + /// + /// The zero (0) based index of this interceptor, or -1 if the + /// supplied is not an advice for this + /// proxy. + /// + public virtual int IndexOf(IAdvice advice) + { + lock (this.SyncRoot) { - string separator = string.Empty; - foreach (Type intf in this.interfaceMap.Keys) + return IndexOfInternal(advice); + } + } + + /// + /// Return the index (0 based) of the supplied + /// in the interceptor + /// (advice) chain for this proxy. + /// + /// + ///

Acces is not synchronized

+ ///

+ /// The return value of this method can be used to index into + /// the + /// list. + ///

+ ///
+ /// + /// The to search for. + /// + /// + /// The zero (0) based index of this interceptor, or -1 if the + /// supplied is not an advice for this + /// proxy. + /// + private int IndexOfInternal(IAdvice advice) + { + if (this._advisors != null) + { + for (int i = 0; i < this._advisors.Count; ++i) { - buffer.Append(separator).Append("[").Append(intf.FullName).Append("] -> "); - IIntroductionAdvisor advisor = this.interfaceMap[intf]; - if (advisor == null) + IAdvisor advisor = this._advisors[i]; + if (advisor.Advice == advice) { - if (TargetSource.TargetType != null) + return i; + } + } + } + + return -1; + } + + /// + /// Return the index (0 based) of the supplied + /// in the interceptor + /// (advice) chain for this proxy. + /// + /// + /// The to search for. + /// + /// + /// The zero (0) based index of this advisor, or -1 if the + /// supplied is not an advisor for this + /// proxy. + /// + /// + /// Access is not synchronized. + /// + private int IndexOfInternal(IAdvisor advisor) + { + return this._advisors != null ? this._advisors.IndexOf(advisor) : -1; + } + + /// + /// Return the index (0 based) of the supplied + /// in the introductions + /// for this proxy. + /// + /// + /// The to search for. + /// + /// + /// The zero (0) based index of this advisor, or -1 if the + /// supplied is not an introduction advisor + /// for this proxy. + /// + /// + /// Access is not synchronized + /// + private int IndexOfInternal(IIntroductionAdvisor advisor) + { + return this._introductions.IndexOf(advisor); + } + + /// + /// Removes the at the supplied + /// in the + /// list + /// from the list of + /// for this proxy. + /// + /// + /// The index of the to remove. + /// + /// + /// If this proxy configuration is frozen and the + /// at the supplied + /// cannot be removed; or if the supplied is out of + /// range. + /// + /// + /// Does not synchronize access. + /// + private void RemoveAdvisorInternal(int index) + { + if (index < 0 || index >= this._advisors.Count) + { + throw + new AopConfigException( + "Advisor index " + index + " is out of bounds: Only have " + this._advisors.Count + " advisors"); + } + + this._advisors.RemoveAt(index); + this.UpdateAdvisorsArray(); + this.AdviceChanged(); + } + + /// + /// Is the supplied included in any + /// advisor? + /// + /// + /// The to check for the + /// inclusion of. + /// + /// + /// if the supplied + /// could be run in an invocation (this does not imply that said + /// will be run). + /// + public bool AdviceIncluded(IAdvice advice) + { + return (IndexOf(advice) != -1); + } + + /// + /// Returns a count of all of the + /// type-compatible with the supplied . + /// + /// + /// The of the + /// to check. + /// + /// + /// A count of all of the + /// type-compatible with the supplied . + /// + public int CountAdviceOfType(Type interceptorType) + { + int count = 0; + lock (this.SyncRoot) + { + foreach (IAdvisor advisor in this._advisors) + { + if (interceptorType.IsAssignableFrom(advisor.Advice.GetType())) + { + ++count; + } + } + } + + return count; + } + + /// + /// Throws an if + /// this instances proxy configuration data is frozen. + /// + /// + /// The message that will be passed through to the constructor of any + /// thrown . + /// + /// + /// If the configuration for this proxy is frozen. + /// + /// + private void DieIfFrozen(string message) + { + if (IsFrozen) + { + throw new AopConfigException(message); + } + } + + /// + /// Bring the advisors array up to date with the list. + /// + private void UpdateAdvisorsArray() + { + IAdvisor[] advisorsArray = new IAdvisor[this._advisors.Count]; + this._advisors.CopyTo(advisorsArray, 0); + this._advisorsArray = advisorsArray; + } + + /// + /// Callback method that is invoked when the list of proxied interfaces + /// has changed. + /// + /// + ///

+ /// An example of such a change would be when a new introduction is + /// added. Resetting + /// to + /// will cause a new proxy + /// to be generated on the next call to get a proxy. + ///

+ ///
+ protected virtual void InterfacesChanged() + { + this.cachedProxyType = null; + this.cachedProxyConstructor = null; + if (this.isActive) + { + foreach (IAdvisedSupportListener listener in this.listeners) + { + listener.InterfacesChanged(this); + } + } + } + + /// + /// Callback method that is invoked when the interceptor list has changed. + /// + protected virtual void AdviceChanged() + { + if (this.isActive) + { + foreach (IAdvisedSupportListener listener in this.listeners) + { + listener.AdviceChanged(this); + } + } + } + + /// + /// Activates this instance. + /// + protected void Activate() + { + lock (this.SyncRoot) + { + this.isActive = true; + foreach (IAdvisedSupportListener listener in this.listeners) + { + listener.Activated(this); + } + } + } + + /// + /// Creates an AOP proxy using this instance's configuration data. + /// + /// + ///

+ /// Subclasses must not create a proxy by any other means (at least + /// without having a well thought out and cogent reason for doing so). + /// This is because the implementation of this method performs some + /// required housekeeping logic prior to creating an AOP proxy. + ///

+ ///
+ /// + protected internal virtual IAopProxy CreateAopProxy() + { + lock (this.SyncRoot) + { + if (this.autoDetectInterfaces && CountNonIntroductionInterfaces() == 0 +// && !this.ProxyTargetType + ) + { + this.interfaceMap.Clear(); + // add all target interfaces + Type[] targetInterfaces = ReflectionUtils.GetInterfaces(this.TargetType); + foreach (Type targetInterface in targetInterfaces) + { + this.interfaceMap[targetInterface] = null; + } + + // add introduced interfaces + foreach (IIntroductionAdvisor introduction in this._introductions) + { + foreach (Type introducedInterface in introduction.Interfaces) { - buffer.Append("target[").Append(TargetSource.TargetType.FullName).Append("]"); - } - else - { - buffer.Append("target[NOT SPECIFIED (=null)]"); + this.interfaceMap[introducedInterface] = introduction; } } + + if (targetInterfaces.Length > 0) + { + InterfacesChanged(); + } + } + + if (!this.isActive) + { + Activate(); + } + + return AopProxyFactory.CreateAopProxy(this); + } + } + + /// + /// Calculates the number of not delegating to one of the . + /// + private int CountNonIntroductionInterfaces() + { + int c = 0; + foreach (Type interfaceType in this.interfaceMap.Keys) + { + if (this.interfaceMap[interfaceType] == null) + { + c++; + } + } + + return c; + } + + /// + /// Copies the configuration from the supplied other + /// into this instance. + /// + /// + ///

+ /// Useful when this instance has been created using the no-argument + /// constructor, and needs to get all of its confiuration data from + /// another (most + /// usually to have an independant copy of said configuration data). + ///

+ ///
+ /// + /// The instance + /// containing the configiration data that is to be copied into this + /// instance. + /// + protected internal virtual void CopyConfigurationFrom(AdvisedSupport other) + { + CopyConfigurationFrom(other, other.TargetSource, new List(other.Advisors), new List(other.Introductions)); + } + + /// + /// Copies the configuration from the supplied other + /// into this instance. + /// + /// + ///

+ /// Useful when this instance has been created using the no-argument + /// constructor, and needs to get all of its confiuration data from + /// another (most + /// usually to have an independant copy of said configuration data). + ///

+ ///
+ /// + /// The instance + /// containing the configiration data that is to be copied into this + /// instance. + /// + /// the new target source + /// the advisors for the chain + /// the introductions for the chain + protected internal virtual void CopyConfigurationFrom(AdvisedSupport other, ITargetSource targetSource, IList advisors, IList introductions) + { + CopyFrom(other); + this.AdvisorChainFactory = other.advisorChainFactory; + this.m_targetSource = targetSource; +// this.cachedProxyType = other.cachedProxyType; +// this.cachedProxyConstructor = other.cachedProxyConstructor; + this.Interfaces = new List(other.Interfaces); + foreach (Type intf in other.interfaceMap.Keys) + { + this.interfaceMap[intf] = other.interfaceMap[intf]; + } + + this._advisors = new List(); + foreach (IAdvisor advisor in advisors) + { + AssertUtils.ArgumentNotNull(advisor, "Advisor must not be null"); + AddAdvisor(advisor); + } + + this._introductions = new List(); + foreach (IIntroductionAdvisor advisor in introductions) + { + // TODO (EE): implement +// ValidateIntroductionAdvisor((IIntroductionAdvisor) advisor); + AssertUtils.ArgumentNotNull(advisor, "IntroductionAdvisor must not be null"); + AddIntroduction(advisor); + } + + UpdateAdvisorsArray(); + AdviceChanged(); + } + + /// + /// A that represents the current + /// configuration. + /// + /// + /// A that represents the current + /// configuration. + /// + public override string ToString() + { + lock (this.SyncRoot) + { + return ToProxyConfigString(); + } + } + + /// + /// Helper method that adds the names of all of the proxied interfaces + /// to the buffer of the supplied . + /// + /// + /// The to append the proxied interface + /// names to. + /// + private void InterfacesToString(StringBuilder buffer) + { + string separator = string.Empty; + foreach (Type intf in this.interfaceMap.Keys) + { + buffer.Append(separator).Append("[").Append(intf.FullName).Append("] -> "); + IIntroductionAdvisor advisor = this.interfaceMap[intf]; + if (advisor == null) + { + if (TargetSource.TargetType != null) + { + buffer.Append("target[").Append(TargetSource.TargetType.FullName).Append("]"); + } else { - buffer.Append("introduction[").Append(advisor.Advice.GetType().FullName).Append("]"); + buffer.Append("target[NOT SPECIFIED (=null)]"); } - separator = ", "; } - } - - /// - /// Helper method that adds advisor's - /// to the buffer of the supplied . - /// - /// - /// The to append the advisor details to. - /// - private void AdvisorsToString(StringBuilder buffer) - { - string separator = string.Empty; - foreach (IAdvisor advisor in this._advisors) + else { - buffer.Append(separator).Append(advisor); - separator = ", "; + buffer.Append("introduction[").Append(advisor.Advice.GetType().FullName).Append("]"); } - } - /// - /// Gets all of the interfaces implemented by the - /// of the supplied - /// . - /// - /// - /// The object to get the interfaces of. - /// - /// - /// All of the interfaces implemented by the - /// of the supplied - /// . - /// - /// - /// If the supplied is . - /// - protected static Type[] GetInterfaces(object target) - { - if (target == null) - { - throw new AopConfigException("Can't proxy null object"); - } - return ReflectionUtils.GetInterfaces(target is Type ? (Type)target : target.GetType()); + separator = ", "; } } + + /// + /// Helper method that adds advisor's + /// to the buffer of the supplied . + /// + /// + /// The to append the advisor details to. + /// + private void AdvisorsToString(StringBuilder buffer) + { + string separator = string.Empty; + foreach (IAdvisor advisor in this._advisors) + { + buffer.Append(separator).Append(advisor); + separator = ", "; + } + } + + /// + /// Gets all of the interfaces implemented by the + /// of the supplied + /// . + /// + /// + /// The object to get the interfaces of. + /// + /// + /// All of the interfaces implemented by the + /// of the supplied + /// . + /// + /// + /// If the supplied is . + /// + protected static Type[] GetInterfaces(object target) + { + if (target == null) + { + throw new AopConfigException("Can't proxy null object"); + } + + return ReflectionUtils.GetInterfaces(target is Type ? (Type) target : target.GetType()); + } } diff --git a/src/Spring/Spring.Aop/Aop/Framework/AdvisorChainFactoryUtils.cs b/src/Spring/Spring.Aop/Aop/Framework/AdvisorChainFactoryUtils.cs index 339a9bfe..05ac2258 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/AdvisorChainFactoryUtils.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/AdvisorChainFactoryUtils.cs @@ -21,101 +21,99 @@ #region Imports using System.Reflection; - using AopAlliance.Intercept; - using Spring.Aop.Framework.Adapter; #endregion -namespace Spring.Aop.Framework +namespace Spring.Aop.Framework; + +/// +/// Utility methods for use by +/// implementations. +/// +/// +///

+/// Not intended to be used directly by applications. +///

+///
+/// Rod Johnson +/// Aleksandar Seovic (.NET) +public sealed class AdvisorChainFactoryUtils { - /// - /// Utility methods for use by - /// implementations. - /// - /// - ///

- /// Not intended to be used directly by applications. - ///

- ///
- /// Rod Johnson - /// Aleksandar Seovic (.NET) - public sealed class AdvisorChainFactoryUtils - { - /// - /// Gets the list of - /// interceptors and dynamic interception - /// advice that may apply to the supplied - /// invocation. - /// - /// The proxy configuration. - /// The object proxy. - /// - /// The method to evaluate interceptors for. - /// - /// - /// The of the target object. - /// - /// - /// A of - /// (if there's - /// a dynamic method matcher that needs evaluation at runtime). - /// - public static IList CalculateInterceptors( - IAdvised config, object proxy, MethodInfo method, Type targetType) - { - IList interceptors = new List(config.Advisors.Count); - foreach (IAdvisor advisor in config.Advisors) - { - if (advisor is IPointcutAdvisor) - { - IPointcutAdvisor pointcutAdvisor = (IPointcutAdvisor) advisor; - if (pointcutAdvisor.Pointcut.TypeFilter.Matches(targetType)) - { - IMethodInterceptor interceptor = - (IMethodInterceptor) GlobalAdvisorAdapterRegistry.Instance.GetInterceptor(advisor); - IMethodMatcher mm = pointcutAdvisor.Pointcut.MethodMatcher; - if (mm.Matches(method, targetType)) - { - if (mm.IsRuntime) - { - // Creating a new object instance in the GetInterceptor() method - // isn't a problem as we normally cache created chains... - interceptors.Add(new InterceptorAndDynamicMethodMatcher(interceptor, mm)); - } - else - { - interceptors.Add(interceptor); - } - } - } - } - } - return interceptors; - } + /// + /// Gets the list of + /// interceptors and dynamic interception + /// advice that may apply to the supplied + /// invocation. + /// + /// The proxy configuration. + /// The object proxy. + /// + /// The method to evaluate interceptors for. + /// + /// + /// The of the target object. + /// + /// + /// A of + /// (if there's + /// a dynamic method matcher that needs evaluation at runtime). + /// + public static IList CalculateInterceptors( + IAdvised config, object proxy, MethodInfo method, Type targetType) + { + IList interceptors = new List(config.Advisors.Count); + foreach (IAdvisor advisor in config.Advisors) + { + if (advisor is IPointcutAdvisor) + { + IPointcutAdvisor pointcutAdvisor = (IPointcutAdvisor) advisor; + if (pointcutAdvisor.Pointcut.TypeFilter.Matches(targetType)) + { + IMethodInterceptor interceptor = + (IMethodInterceptor) GlobalAdvisorAdapterRegistry.Instance.GetInterceptor(advisor); + IMethodMatcher mm = pointcutAdvisor.Pointcut.MethodMatcher; + if (mm.Matches(method, targetType)) + { + if (mm.IsRuntime) + { + // Creating a new object instance in the GetInterceptor() method + // isn't a problem as we normally cache created chains... + interceptors.Add(new InterceptorAndDynamicMethodMatcher(interceptor, mm)); + } + else + { + interceptors.Add(interceptor); + } + } + } + } + } - #region Constructor (s) / Destructor + return interceptors; + } - // CLOVER:OFF + #region Constructor (s) / Destructor - /// - /// Creates a new instance of the - /// - /// class. - /// - /// - ///

- /// This is a utility class, and as such has no publicly visible - /// constructors. - ///

- ///
- private AdvisorChainFactoryUtils() - { - } + // CLOVER:OFF - // CLOVER:ON + /// + /// Creates a new instance of the + /// + /// class. + /// + /// + ///

+ /// This is a utility class, and as such has no publicly visible + /// constructors. + ///

+ ///
+ private AdvisorChainFactoryUtils() + { + } - #endregion - } + // CLOVER:ON + + #endregion } diff --git a/src/Spring/Spring.Aop/Aop/Framework/AopConfigException.cs b/src/Spring/Spring.Aop/Aop/Framework/AopConfigException.cs index 4a6e4b12..36aa9eed 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/AopConfigException.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/AopConfigException.cs @@ -24,57 +24,56 @@ using System.Runtime.Serialization; #endregion -namespace Spring.Aop.Framework +namespace Spring.Aop.Framework; + +/// +/// Thrown in response to the misconfiguration of an AOP proxy. +/// +/// Rod Johnson +/// Aleksandar Seovic (.NET) +[Serializable] +public class AopConfigException : ApplicationException { - /// - /// Thrown in response to the misconfiguration of an AOP proxy. - /// - /// Rod Johnson - /// Aleksandar Seovic (.NET) - [Serializable] - public class AopConfigException : ApplicationException - { - /// - /// Creates a new instance of the - /// class. - /// - public AopConfigException () - { - } + /// + /// Creates a new instance of the + /// class. + /// + public AopConfigException() + { + } - /// - /// Creates a new instance of the - /// class with - /// the specified message. - /// - /// - /// A message about the exception. - /// - public AopConfigException (string message) : base(message) - { - } + /// + /// Creates a new instance of the + /// class with + /// the specified message. + /// + /// + /// A message about the exception. + /// + public AopConfigException(string message) : base(message) + { + } - /// - /// Creates a new instance of the - /// class with - /// the specified message and root cause. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception that is being wrapped. - /// - public AopConfigException (string message, Exception rootCause) - : base(message, rootCause) - { - } + /// + /// Creates a new instance of the + /// class with + /// the specified message and root cause. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception that is being wrapped. + /// + public AopConfigException(string message, Exception rootCause) + : base(message, rootCause) + { + } - /// - protected AopConfigException ( - SerializationInfo info, StreamingContext context) - : base (info, context) - { - } - } + /// + protected AopConfigException( + SerializationInfo info, StreamingContext context) + : base(info, context) + { + } } diff --git a/src/Spring/Spring.Aop/Aop/Framework/AopContext.cs b/src/Spring/Spring.Aop/Aop/Framework/AopContext.cs index 5a5d289a..decbaec6 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/AopContext.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/AopContext.cs @@ -24,165 +24,166 @@ using System.Collections; #endregion -namespace Spring.Aop.Framework +namespace Spring.Aop.Framework; + +/// +/// This class contains various methods used to +/// obtain information about the current AOP invocation. +/// +/// +///

+/// The +/// property is +/// usable if the AOP framework is configured to expose the current proxy +/// (not the default)... it returns the AOP proxy in use. Target objects or +/// advice can use this to make advised calls. They can also use it to find +/// advice configuration. +///

+///

+/// To expose the current proxy, set the +/// property on the controlling proxy to . +/// The default value for the property +/// is , for performance reasons. +///

+/// +/// The AOP framework does not expose proxies by default, as there is a +/// performance cost in doing so. +/// +///

+/// The functionality in this class might be used by a target object that +/// needed access to resources on the invocation. However, this approach +/// should not be used when there is a reasonable alternative, as it makes +/// application code dependent on usage under AOP and the Spring.NET AOP +/// framework. +///

+///
+/// Rod Johnson +/// Aleksandar Seovic (.NET) +public sealed class AopContext { - /// - /// This class contains various methods used to - /// obtain information about the current AOP invocation. - /// - /// - ///

- /// The - /// property is - /// usable if the AOP framework is configured to expose the current proxy - /// (not the default)... it returns the AOP proxy in use. Target objects or - /// advice can use this to make advised calls. They can also use it to find - /// advice configuration. - ///

+ [ThreadStatic] private static Stack tls_ProxyStack; + + /// + /// The AOP proxy stack associated with this thread. + /// + private static Stack ProxyStack + { + get + { + if (tls_ProxyStack == null) + { + tls_ProxyStack = new Stack(); + } + + return tls_ProxyStack; + } + } + + /// + /// Indicates if the current call is executed under control of an AOP proxy. + /// + /// ///

- /// To expose the current proxy, set the - /// property on the controlling proxy to . - /// The default value for the property + /// Will be unless the + /// property + /// on the controlling proxy has been set to . + ///

+ ///

+ /// The default value for the + /// property /// is , for performance reasons. ///

- /// - /// The AOP framework does not expose proxies by default, as there is a - /// performance cost in doing so. - /// - ///

- /// The functionality in this class might be used by a target object that - /// needed access to resources on the invocation. However, this approach - /// should not be used when there is a reasonable alternative, as it makes - /// application code dependent on usage under AOP and the Spring.NET AOP - /// framework. - ///

- ///
- /// Rod Johnson - /// Aleksandar Seovic (.NET) - public sealed class AopContext - { - [ThreadStatic] - private static Stack tls_ProxyStack; - - /// - /// The AOP proxy stack associated with this thread. - /// - private static Stack ProxyStack + ///
+ public static bool IsActive + { + get { - get + return (tls_ProxyStack != null && tls_ProxyStack.Count > 0); + } + } + + /// + /// Gets the current AOP proxy. + /// + /// + /// If the proxy stack is empty. + /// + public static object CurrentProxy + { + get + { + Stack proxyStack = ProxyStack; + if (proxyStack.Count == 0) { - if (tls_ProxyStack == null) - { - tls_ProxyStack = new Stack(); - } - return tls_ProxyStack; + throw new AopConfigException( + "Cannot find proxy: Set the 'ExposeProxy' property " + + "to 'true' on IAdvised to make it available."); } + + return proxyStack.Peek(); + } + } + + /// + /// Sets the current proxy by pushing it to the proxy stack. + /// + /// + ///

+ /// This method is for internal use only, and should never be called by + /// client code. + ///

+ ///
+ /// + /// The proxy to put on top of the proxy stack. + /// + public static void PushProxy(object proxy) + { + ProxyStack.Push(proxy); + } + + /// + /// Removes the current proxy from the proxy stack, making the previous + /// proxy (if any) the current proxy. + /// + /// + ///

+ /// This method is for internal use only, and should never be called by + /// client code. + ///

+ ///
+ /// + /// If the proxy stack is empty. + /// + public static void PopProxy() + { + Stack proxyStack = ProxyStack; + if (proxyStack.Count == 0) + { + throw new AopConfigException( + "Proxy stack empty. Always call 'PushProxy' before 'PopProxy'."); } - /// - /// Indicates if the current call is executed under control of an AOP proxy. - /// - /// - ///

- /// Will be unless the - /// property - /// on the controlling proxy has been set to . - ///

- ///

- /// The default value for the - /// property - /// is , for performance reasons. - ///

- ///
- public static bool IsActive - { - get - { - return (tls_ProxyStack != null && tls_ProxyStack.Count > 0); - } - } + proxyStack.Pop(); + } - /// - /// Gets the current AOP proxy. - /// - /// - /// If the proxy stack is empty. - /// - public static object CurrentProxy - { - get - { - Stack proxyStack = ProxyStack; - if (proxyStack.Count == 0) - { - throw new AopConfigException( - "Cannot find proxy: Set the 'ExposeProxy' property " + - "to 'true' on IAdvised to make it available."); - } - return proxyStack.Peek(); - } - } + #region Constructor (s) / Destructor - /// - /// Sets the current proxy by pushing it to the proxy stack. - /// - /// - ///

- /// This method is for internal use only, and should never be called by - /// client code. - ///

- ///
- /// - /// The proxy to put on top of the proxy stack. - /// - public static void PushProxy(object proxy) - { - ProxyStack.Push(proxy); - } + // CLOVER:OFF - /// - /// Removes the current proxy from the proxy stack, making the previous - /// proxy (if any) the current proxy. - /// - /// - ///

- /// This method is for internal use only, and should never be called by - /// client code. - ///

- ///
- /// - /// If the proxy stack is empty. - /// - public static void PopProxy() - { - Stack proxyStack = ProxyStack; - if (proxyStack.Count == 0) - { - throw new AopConfigException( - "Proxy stack empty. Always call 'PushProxy' before 'PopProxy'."); - } - proxyStack.Pop(); - } + /// + /// Creates a new instance of the + /// class. + /// + /// + ///

+ /// This is a utility class, and as such exposes no public constructors. + ///

+ ///
+ private AopContext() + { + } - #region Constructor (s) / Destructor + // CLOVER:ON - // CLOVER:OFF - - /// - /// Creates a new instance of the - /// class. - /// - /// - ///

- /// This is a utility class, and as such exposes no public constructors. - ///

- ///
- private AopContext() - { - } - - // CLOVER:ON - - #endregion - } + #endregion } diff --git a/src/Spring/Spring.Aop/Aop/Framework/AopUtils.cs b/src/Spring/Spring.Aop/Aop/Framework/AopUtils.cs index b26b275e..1f721f63 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/AopUtils.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/AopUtils.cs @@ -21,389 +21,395 @@ #region Imports using System.Reflection; - using Spring.Collections; using Spring.Util; #endregion -namespace Spring.Aop.Framework +namespace Spring.Aop.Framework; + +/// +/// Utility methods used by the AOP framework. +/// +/// +///

+/// Not intended to be used directly by applications. +///

+///
+/// Rod Johnson +/// Juergen Hoeller +/// Aleksandar Seovic (.NET) +public sealed class AopUtils { + // This is a leaky abstraction as we have hardcoded known IAopProxyFactory implementations. + private const string COMPOSITION_PROXY_TYPE_NAME = "CompositionAopProxy"; + + private const string DECORATOR_PROXY_TYPE_NAME = "DecoratorAopProxy"; + + private const string INHERITANCE_PROXY_TYPE_NAME = "InheritanceAopProxy"; + /// - /// Utility methods used by the AOP framework. + /// Is the supplied an AOP proxy? + /// + /// + /// Return whether the given type is either a composition-based or a decorator-based proxy type. + /// + /// The type to be checked. + /// if the supplied is an AOP proxy type. + public static bool IsAopProxyType(Type objectType) + { + return IsCompositionAopProxyType(objectType) || IsDecoratorAopProxyType(objectType) || IsInheritanceAopProxyType(objectType); + } + + /// + /// Is the supplied an AOP proxy? + /// + /// + /// Return whether the given object is either + /// a composition-based proxy or a decorator-based proxy. + /// + /// The instance to be checked. + /// + /// if the supplied is + /// an AOP proxy. + /// + public static bool IsAopProxy(object instance) + { + return IsCompositionAopProxy(instance) || IsDecoratorAopProxy(instance) || IsInheritanceAopProxy(instance); + } + + /// + /// Is the supplied a composition-based AOP proxy? + /// + /// The instance to be checked. + /// + /// if the supplied is + /// an composition-based AOP proxy. + /// + public static bool IsCompositionAopProxy(Object instance) + { + return ((instance != null) && IsCompositionAopProxyType(instance.GetType())); + } + + /// + /// Is the supplied a composition based AOP proxy type? + /// + /// + /// Return whether the given type is a composition-based proxy type. + /// + /// The type to be checked. + /// if the supplied is a composition based AOP proxy type. + public static bool IsCompositionAopProxyType(Type objectType) + { + return ((objectType != null) && objectType.FullName.StartsWith(COMPOSITION_PROXY_TYPE_NAME)); + } + + /// + /// Is the supplied a decorator-based AOP proxy? + /// + /// The instance to be checked. + /// + /// if the supplied is + /// an decorator-based AOP proxy. + /// + public static bool IsDecoratorAopProxy(Object instance) + { + return ((instance != null) && IsDecoratorAopProxyType(instance.GetType())); + } + + /// + /// Is the supplied a composition based AOP proxy type? + /// + /// + /// Return whether the given type is a composition-based proxy type. + /// + /// The type to be checked. + /// if the supplied is a composition based AOP proxy type. + public static bool IsDecoratorAopProxyType(Type objectType) + { + return ((objectType != null) && objectType.FullName.StartsWith(DECORATOR_PROXY_TYPE_NAME)); + } + + /// + /// Is the supplied an inheritance based AOP proxy? + /// + /// The instance to be checked. + /// + /// if the supplied is + /// an inheritacne based AOP proxy. + /// + public static bool IsInheritanceAopProxy(Object instance) + { + return instance != null && IsInheritanceAopProxyType(instance.GetType()); + } + + /// + /// Is the supplied an inheritance based AOP proxy type? + /// + /// The type to be checked. + /// if the supplied is an inheritance based AOP proxy type. + public static bool IsInheritanceAopProxyType(Type objectType) + { + return ((objectType != null) && objectType.FullName.StartsWith(INHERITANCE_PROXY_TYPE_NAME)); + } + + /// + /// Gets all of the interfaces that the of the + /// supplied implements. /// /// ///

- /// Not intended to be used directly by applications. + /// This includes interfaces implemented by any superclasses. ///

///
- /// Rod Johnson - /// Juergen Hoeller - /// Aleksandar Seovic (.NET) - public sealed class AopUtils + /// + /// The object to analyse for interfaces. + /// + /// + /// All of the interfaces that the of the + /// supplied implements; or an empty + /// array if the supplied is + /// . + /// + public static Type[] GetAllInterfaces(object instance) { - // This is a leaky abstraction as we have hardcoded known IAopProxyFactory implementations. - private const string COMPOSITION_PROXY_TYPE_NAME = "CompositionAopProxy"; - - private const string DECORATOR_PROXY_TYPE_NAME = "DecoratorAopProxy"; - - private const string INHERITANCE_PROXY_TYPE_NAME = "InheritanceAopProxy"; - - /// - /// Is the supplied an AOP proxy? - /// - /// - /// Return whether the given type is either a composition-based or a decorator-based proxy type. - /// - /// The type to be checked. - /// if the supplied is an AOP proxy type. - public static bool IsAopProxyType(Type objectType) + if (instance != null) { - return IsCompositionAopProxyType(objectType) || IsDecoratorAopProxyType(objectType) || IsInheritanceAopProxyType(objectType); + Type type = instance.GetType(); + return GetAllInterfacesFromType(type); } - /// - /// Is the supplied an AOP proxy? - /// - /// - /// Return whether the given object is either - /// a composition-based proxy or a decorator-based proxy. - /// - /// The instance to be checked. - /// - /// if the supplied is - /// an AOP proxy. - /// - public static bool IsAopProxy(object instance) - { - return IsCompositionAopProxy(instance) || IsDecoratorAopProxy(instance) || IsInheritanceAopProxy(instance); - } + return Type.EmptyTypes; + } - /// - /// Is the supplied a composition-based AOP proxy? - /// - /// The instance to be checked. - /// - /// if the supplied is - /// an composition-based AOP proxy. - /// - public static bool IsCompositionAopProxy(Object instance) + /// + /// Gets all of the interfaces that the + /// supplied implements. + /// + /// + /// This includes interfaces implemented by any superclasses. + /// + /// + /// The type to analyse for interfaces. + /// + /// + /// All of the interfaces that the supplied implements. + /// + public static Type[] GetAllInterfacesFromType(Type type) + { + AssertUtils.ArgumentNotNull(type, "type"); + ISet interfaces = new HybridSet(); + do { - return ((instance != null) && IsCompositionAopProxyType(instance.GetType())); - } - - /// - /// Is the supplied a composition based AOP proxy type? - /// - /// - /// Return whether the given type is a composition-based proxy type. - /// - /// The type to be checked. - /// if the supplied is a composition based AOP proxy type. - public static bool IsCompositionAopProxyType(Type objectType) - { - return ((objectType != null) && objectType.FullName.StartsWith(COMPOSITION_PROXY_TYPE_NAME)); - } - - /// - /// Is the supplied a decorator-based AOP proxy? - /// - /// The instance to be checked. - /// - /// if the supplied is - /// an decorator-based AOP proxy. - /// - public static bool IsDecoratorAopProxy(Object instance) - { - return ((instance != null) && IsDecoratorAopProxyType(instance.GetType())); - } - - /// - /// Is the supplied a composition based AOP proxy type? - /// - /// - /// Return whether the given type is a composition-based proxy type. - /// - /// The type to be checked. - /// if the supplied is a composition based AOP proxy type. - public static bool IsDecoratorAopProxyType(Type objectType) - { - return ((objectType != null) && objectType.FullName.StartsWith(DECORATOR_PROXY_TYPE_NAME)); - } - - - /// - /// Is the supplied an inheritance based AOP proxy? - /// - /// The instance to be checked. - /// - /// if the supplied is - /// an inheritacne based AOP proxy. - /// - public static bool IsInheritanceAopProxy(Object instance) - { - return instance != null && IsInheritanceAopProxyType(instance.GetType()); - } - - /// - /// Is the supplied an inheritance based AOP proxy type? - /// - /// The type to be checked. - /// if the supplied is an inheritance based AOP proxy type. - public static bool IsInheritanceAopProxyType(Type objectType) - { - return ((objectType != null) && objectType.FullName.StartsWith(INHERITANCE_PROXY_TYPE_NAME)); - } - - /// - /// Gets all of the interfaces that the of the - /// supplied implements. - /// - /// - ///

- /// This includes interfaces implemented by any superclasses. - ///

- ///
- /// - /// The object to analyse for interfaces. - /// - /// - /// All of the interfaces that the of the - /// supplied implements; or an empty - /// array if the supplied is - /// . - /// - public static Type[] GetAllInterfaces(object instance) - { - if (instance != null) + Type[] ifcs = type.GetInterfaces(); + foreach (Type ifc in ifcs) { - Type type = instance.GetType(); - return GetAllInterfacesFromType(type); - } - return Type.EmptyTypes; - } - - /// - /// Gets all of the interfaces that the - /// supplied implements. - /// - /// - /// This includes interfaces implemented by any superclasses. - /// - /// - /// The type to analyse for interfaces. - /// - /// - /// All of the interfaces that the supplied implements. - /// - public static Type[] GetAllInterfacesFromType(Type type) - { - AssertUtils.ArgumentNotNull(type, "type"); - ISet interfaces = new HybridSet(); - do - { - Type[] ifcs = type.GetInterfaces(); - foreach (Type ifc in ifcs) - { - interfaces.Add(ifc); - } - type = type.BaseType; - } while (type != null); - - if (interfaces.Count > 0) - { - Type[] types = new Type[interfaces.Count]; - interfaces.CopyTo(types, 0); - return types; - } - return Type.EmptyTypes; - } - - /// - /// Can the supplied apply at all on the - /// supplied ? - /// - /// - ///

- /// This is an important test as it can be used to optimize out a - /// pointcut for a class. - ///

- ///

- /// Invoking this method with a that is - /// an interface type will always yield a - /// return value. - ///

- ///
- /// The pointcut being tested. - /// The class being tested. - /// - /// The interfaces being proxied. If , all - /// methods on a class may be proxied. - /// - /// - /// if the pointcut can apply on any method. - /// - public static bool CanApply(IPointcut pointcut, Type targetType, Type[] proxyInterfaces) - { - return CanApply(pointcut, targetType, proxyInterfaces, false); - } - /// - /// Can the supplied apply at all on the - /// supplied ? - /// - /// - ///

- /// This is an important test as it can be used to optimize out a - /// pointcut for a class. - ///

- ///

- /// Invoking this method with a that is - /// an interface type will always yield a - /// return value. - ///

- ///
- /// The pointcut being tested. - /// The class being tested. - /// - /// The interfaces being proxied. If , all - /// methods on a class may be proxied. - /// - /// whether or not the advisor chain for the target object includes any introductions. - /// - /// if the pointcut can apply on any method. - /// - public static bool CanApply(IPointcut pointcut, Type targetType, Type[] proxyInterfaces, bool hasIntroductions) - { - if (!pointcut.TypeFilter.Matches(targetType)) - { - return false; + interfaces.Add(ifc); } - // It may apply to the class - // Check whether it can apply on any method - // Checks public methods, including inherited methods - MethodInfo[] methods = targetType.GetMethods(); - for (int i = 0; i < methods.Length; ++i) - { - MethodInfo m = methods[i]; - // If we're looking only at interfaces and this method - // isn't on any of them, skip it - if (proxyInterfaces != null - && !ReflectionUtils.MethodIsOnOneOfTheseInterfaces(m, proxyInterfaces)) - { - continue; - } - if (pointcut.MethodMatcher.Matches(m, targetType)) - { - return true; - } - } + type = type.BaseType; + } while (type != null); + + if (interfaces.Count > 0) + { + Type[] types = new Type[interfaces.Count]; + interfaces.CopyTo(types, 0); + return types; + } + + return Type.EmptyTypes; + } + + /// + /// Can the supplied apply at all on the + /// supplied ? + /// + /// + ///

+ /// This is an important test as it can be used to optimize out a + /// pointcut for a class. + ///

+ ///

+ /// Invoking this method with a that is + /// an interface type will always yield a + /// return value. + ///

+ ///
+ /// The pointcut being tested. + /// The class being tested. + /// + /// The interfaces being proxied. If , all + /// methods on a class may be proxied. + /// + /// + /// if the pointcut can apply on any method. + /// + public static bool CanApply(IPointcut pointcut, Type targetType, Type[] proxyInterfaces) + { + return CanApply(pointcut, targetType, proxyInterfaces, false); + } + + /// + /// Can the supplied apply at all on the + /// supplied ? + /// + /// + ///

+ /// This is an important test as it can be used to optimize out a + /// pointcut for a class. + ///

+ ///

+ /// Invoking this method with a that is + /// an interface type will always yield a + /// return value. + ///

+ ///
+ /// The pointcut being tested. + /// The class being tested. + /// + /// The interfaces being proxied. If , all + /// methods on a class may be proxied. + /// + /// whether or not the advisor chain for the target object includes any introductions. + /// + /// if the pointcut can apply on any method. + /// + public static bool CanApply(IPointcut pointcut, Type targetType, Type[] proxyInterfaces, bool hasIntroductions) + { + if (!pointcut.TypeFilter.Matches(targetType)) + { return false; } - /// - /// Can the supplied apply at all on the - /// supplied ? - /// - /// - ///

- /// This is an important test as it can be used to optimize out an - /// advisor for a class. - ///

- ///
- /// The advisor to check. - /// The class being tested. - /// - /// The interfaces being proxied. If , all - /// methods on a class may be proxied. - /// - /// - /// if the advisor can apply on any method. - /// - public static bool CanApply(IAdvisor advisor, Type targetType, Type[] proxyInterfaces) + // It may apply to the class + // Check whether it can apply on any method + // Checks public methods, including inherited methods + MethodInfo[] methods = targetType.GetMethods(); + for (int i = 0; i < methods.Length; ++i) { - return CanApply(advisor, targetType, proxyInterfaces, false); + MethodInfo m = methods[i]; + // If we're looking only at interfaces and this method + // isn't on any of them, skip it + if (proxyInterfaces != null + && !ReflectionUtils.MethodIsOnOneOfTheseInterfaces(m, proxyInterfaces)) + { + continue; + } + + if (pointcut.MethodMatcher.Matches(m, targetType)) + { + return true; + } } - /// - /// Can the supplied apply at all on the - /// supplied ? - /// - /// - ///

- /// This is an important test as it can be used to optimize out an - /// advisor for a class. - ///

- ///
- /// The advisor to check. - /// The class being tested. - /// - /// The interfaces being proxied. If , all - /// methods on a class may be proxied. - /// - /// whether or not the advisor chain for the target object includes any introductions. - /// - /// if the advisor can apply on any method. - /// - public static bool CanApply(IAdvisor advisor, Type targetType, Type[] proxyInterfaces, bool hasIntroductions) + return false; + } + + /// + /// Can the supplied apply at all on the + /// supplied ? + /// + /// + ///

+ /// This is an important test as it can be used to optimize out an + /// advisor for a class. + ///

+ ///
+ /// The advisor to check. + /// The class being tested. + /// + /// The interfaces being proxied. If , all + /// methods on a class may be proxied. + /// + /// + /// if the advisor can apply on any method. + /// + public static bool CanApply(IAdvisor advisor, Type targetType, Type[] proxyInterfaces) + { + return CanApply(advisor, targetType, proxyInterfaces, false); + } + + /// + /// Can the supplied apply at all on the + /// supplied ? + /// + /// + ///

+ /// This is an important test as it can be used to optimize out an + /// advisor for a class. + ///

+ ///
+ /// The advisor to check. + /// The class being tested. + /// + /// The interfaces being proxied. If , all + /// methods on a class may be proxied. + /// + /// whether or not the advisor chain for the target object includes any introductions. + /// + /// if the advisor can apply on any method. + /// + public static bool CanApply(IAdvisor advisor, Type targetType, Type[] proxyInterfaces, bool hasIntroductions) + { + if (advisor is IIntroductionAdvisor) { - if (advisor is IIntroductionAdvisor) - { - return ((IIntroductionAdvisor)advisor).TypeFilter.Matches(targetType); - } - else if (advisor is IPointcutAdvisor) - { - IPointcutAdvisor pca = (IPointcutAdvisor)advisor; - return CanApply(pca.Pointcut, targetType, proxyInterfaces, hasIntroductions); - } - // no pointcut specified so assume it applies... - return true; + return ((IIntroductionAdvisor) advisor).TypeFilter.Matches(targetType); + } + else if (advisor is IPointcutAdvisor) + { + IPointcutAdvisor pca = (IPointcutAdvisor) advisor; + return CanApply(pca.Pointcut, targetType, proxyInterfaces, hasIntroductions); } - #region Constructor (s) / Destructor + // no pointcut specified so assume it applies... + return true; + } - // CLOVER:OFF + #region Constructor (s) / Destructor - /// - /// Creates a new instance of the - /// class. - /// - /// - ///

- /// This is a utility class, and as such has no publicly - /// visible constructors. - ///

- ///
- private AopUtils() + // CLOVER:OFF + + /// + /// Creates a new instance of the + /// class. + /// + /// + ///

+ /// This is a utility class, and as such has no publicly + /// visible constructors. + ///

+ ///
+ private AopUtils() + { + } + + // CLOVER:ON + + #endregion + + /// + /// Gets the type of the target. + /// + /// The candidate. + /// + public static Type GetTargetType(object candidate) + { + AssertUtils.ArgumentNotNull(candidate, "candidate", "Candidate object must not be null"); + if (candidate is ITargetSource) { + return ((ITargetSource) candidate).TargetType; } - // CLOVER:ON - - #endregion - - /// - /// Gets the type of the target. - /// - /// The candidate. - /// - public static Type GetTargetType(object candidate) + if (candidate is IAdvised) { - AssertUtils.ArgumentNotNull(candidate, "candidate", "Candidate object must not be null"); - if (candidate is ITargetSource) - { - return ((ITargetSource)candidate).TargetType; - } - if (candidate is IAdvised) - { - return ((IAdvised)candidate).TargetSource.TargetType; - } - if (IsDecoratorAopProxy(candidate)) - { - return candidate.GetType().BaseType; - } - return candidate.GetType(); + return ((IAdvised) candidate).TargetSource.TargetType; } + if (IsDecoratorAopProxy(candidate)) + { + return candidate.GetType().BaseType; + } + + return candidate.GetType(); } } diff --git a/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/AbstractAdvisorAutoProxyCreator.cs b/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/AbstractAdvisorAutoProxyCreator.cs index 48a2b639..130c510a 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/AbstractAdvisorAutoProxyCreator.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/AbstractAdvisorAutoProxyCreator.cs @@ -23,242 +23,246 @@ using Spring.Core; using Spring.Objects.Factory; using Spring.Objects.Factory.Config; -namespace Spring.Aop.Framework.AutoProxy +namespace Spring.Aop.Framework.AutoProxy; + +/// +/// Abstract IObjectPostProcessor implementation that creates AOP proxies. +/// This class is completely generic; it contains no special code to handle +/// any particular aspects, such as pooling aspects. +/// +/// +///

Subclasses must implement the abstract FindCandidateAdvisors() method +/// to return a list of Advisors applying to any object. Subclasses can also +/// override the inherited ShouldSkip() method to exclude certain objects +/// from autoproxying, but they must be careful to invoke the ShouldSkip() +/// method of this class, which tries to avoid circular reference problems +/// and infinite loops.

+///

Advisors or advices requiring ordering should implement the Ordered interface. +/// This class sorts advisors by Ordered order value. Advisors that don't implement +/// the Ordered interface will be considered to be unordered, and will appear +/// at the end of the advisor chain in undefined order.

+///
+/// +/// Rod Johnson +/// Adhari C Mahendra (.NET) +/// Erich Eichinger +public abstract class AbstractAdvisorAutoProxyCreator : AbstractAutoProxyCreator { + private IAdvisorRetrievalHelper _advisorRetrievalHelper; + /// - /// Abstract IObjectPostProcessor implementation that creates AOP proxies. - /// This class is completely generic; it contains no special code to handle - /// any particular aspects, such as pooling aspects. + /// We override this method to ensure that all candidate advisors are materialized + /// under a stack trace including this object. Otherwise, the dependencies won't + /// be apparent to the circular-reference prevention strategy in AbstractObjectFactory. + /// + public override IObjectFactory ObjectFactory + { + set + { + if (!(value is IConfigurableListableObjectFactory)) + { + throw new InvalidOperationException("Can not use AdvisorAutoProxyCreator without a ConfigurableListableObjectFactory"); + } + + base.ObjectFactory = value; + InitObjectFactory((IConfigurableListableObjectFactory) value); + } + } + + /// + /// An new was set. Initialize this creator instance + /// according to the specified object factory. + /// + /// + protected virtual void InitObjectFactory(IConfigurableListableObjectFactory objectFactory) + { + _advisorRetrievalHelper = CreateAdvisorRetrievalHelper(objectFactory); + } + + /// + /// Create the for retrieving the list of + /// applicable advisor objects. The default implementation calls back into + /// thus it usually is sufficient to just + /// override . Override + /// only if you know what you are doing! + /// + /// + /// + protected virtual IAdvisorRetrievalHelper CreateAdvisorRetrievalHelper(IConfigurableListableObjectFactory objectFactory) + { + return new ObjectFactoryAdvisorRetrievalHelperAdapter(this, objectFactory); + } + + /// + /// Return whether the given object is to be proxied, what additional + /// advices (e.g. AOP Alliance interceptors) and advisors to apply. /// /// - ///

Subclasses must implement the abstract FindCandidateAdvisors() method - /// to return a list of Advisors applying to any object. Subclasses can also - /// override the inherited ShouldSkip() method to exclude certain objects - /// from autoproxying, but they must be careful to invoke the ShouldSkip() - /// method of this class, which tries to avoid circular reference problems - /// and infinite loops.

- ///

Advisors or advices requiring ordering should implement the Ordered interface. - /// This class sorts advisors by Ordered order value. Advisors that don't implement - /// the Ordered interface will be considered to be unordered, and will appear - /// at the end of the advisor chain in undefined order.

+ ///

The previous targetName of this method was "GetInterceptorAndAdvisorForObject". + /// It has been renamed in the course of general terminology clarification + /// in Spring 1.1. An AOP Alliance Interceptor is just a special form of + /// Advice, so the generic Advice term is preferred now.

+ ///

The third parameter, customTargetSource, is new in Spring 1.1; + /// add it to existing implementations of this method.

///
- /// - /// Rod Johnson - /// Adhari C Mahendra (.NET) - /// Erich Eichinger - public abstract class AbstractAdvisorAutoProxyCreator : AbstractAutoProxyCreator + /// the type of the target object + /// the name of the target object + /// targetSource returned by TargetSource property: + /// may be ignored. Will be null unless a custom target source is in use. + /// + /// an array of additional interceptors for the particular object; + /// or an empty array if no additional interceptors but just the common ones; + /// or null if no proxy at all, not even with the common interceptors. + /// + protected override IList GetAdvicesAndAdvisorsForObject(Type targetType, string targetName, ITargetSource customTargetSource) { - private IAdvisorRetrievalHelper _advisorRetrievalHelper; - - /// - /// We override this method to ensure that all candidate advisors are materialized - /// under a stack trace including this object. Otherwise, the dependencies won't - /// be apparent to the circular-reference prevention strategy in AbstractObjectFactory. - /// - public override IObjectFactory ObjectFactory + IList advisors = FindEligibleAdvisors(targetType, targetName); + if (advisors.Count == 0) { - set + return DO_NOT_PROXY; + } + + return advisors.Cast().ToArray(); + } + + /// + /// Find all eligible advices and for autoproxying this class. + /// + /// the type of the object to be advised + /// the name of the object to be advised + /// + /// the empty list, not null, if there are no pointcuts or interceptors. + /// The by-order sorted list of advisors otherwise + /// + protected IList FindEligibleAdvisors(Type targetType, string targetName) + { + List candidateAdvisors = FindCandidateAdvisors(targetType, targetName); + List eligibleAdvisors = FindAdvisorsThatCanApply(candidateAdvisors, targetType, targetName); + + ExtendAdvisors(eligibleAdvisors, targetType, targetName); + SortAdvisors(eligibleAdvisors); + + return eligibleAdvisors; + } + + /// + /// Find all possible advisor candidates to use in auto-proxying + /// + /// the type of the object to be advised + /// the name of the object to be advised + /// the list of candidate advisors + protected virtual List FindCandidateAdvisors(Type targetType, string targetName) + { + return _advisorRetrievalHelper.FindAdvisorObjects(targetType, targetName); + } + + /// + /// From the given list of candidate advisors, select the ones that are applicable + /// to the given target specified by targetType and name. + /// + /// the list of candidate advisors to date + /// the target object's type + /// the target object's name + /// the list of applicable advisors + protected virtual List FindAdvisorsThatCanApply(List candidateAdvisors, Type targetType, string targetName) + { + if (candidateAdvisors.Count == 0) + { + return candidateAdvisors; + } + + List eligibleAdvisors = new List(); + foreach (IAdvisor candidate in candidateAdvisors) + { + if (candidate is IIntroductionAdvisor && AopUtils.CanApply(candidate, targetType, null)) { - if (!(value is IConfigurableListableObjectFactory)) + if (logger.IsEnabled(LogLevel.Information)) { - throw new InvalidOperationException("Can not use AdvisorAutoProxyCreator without a ConfigurableListableObjectFactory"); + logger.LogInformation($"Candidate advisor [{candidate}] accepted for targetType [{targetType}]"); } - base.ObjectFactory = value; - InitObjectFactory((IConfigurableListableObjectFactory)value); + + eligibleAdvisors.Add(candidate); } } - /// - /// An new was set. Initialize this creator instance - /// according to the specified object factory. - /// - /// - protected virtual void InitObjectFactory(IConfigurableListableObjectFactory objectFactory) + bool hasIntroductions = eligibleAdvisors.Count > 0; + foreach (IAdvisor candidate in candidateAdvisors) { - _advisorRetrievalHelper = CreateAdvisorRetrievalHelper(objectFactory); - } + if (candidate is IIntroductionAdvisor) continue; - /// - /// Create the for retrieving the list of - /// applicable advisor objects. The default implementation calls back into - /// thus it usually is sufficient to just - /// override . Override - /// only if you know what you are doing! - /// - /// - /// - protected virtual IAdvisorRetrievalHelper CreateAdvisorRetrievalHelper(IConfigurableListableObjectFactory objectFactory) - { - return new ObjectFactoryAdvisorRetrievalHelperAdapter(this, objectFactory); - } - - /// - /// Return whether the given object is to be proxied, what additional - /// advices (e.g. AOP Alliance interceptors) and advisors to apply. - /// - /// - ///

The previous targetName of this method was "GetInterceptorAndAdvisorForObject". - /// It has been renamed in the course of general terminology clarification - /// in Spring 1.1. An AOP Alliance Interceptor is just a special form of - /// Advice, so the generic Advice term is preferred now.

- ///

The third parameter, customTargetSource, is new in Spring 1.1; - /// add it to existing implementations of this method.

- ///
- /// the type of the target object - /// the name of the target object - /// targetSource returned by TargetSource property: - /// may be ignored. Will be null unless a custom target source is in use. - /// - /// an array of additional interceptors for the particular object; - /// or an empty array if no additional interceptors but just the common ones; - /// or null if no proxy at all, not even with the common interceptors. - /// - protected override IList GetAdvicesAndAdvisorsForObject(Type targetType, string targetName, ITargetSource customTargetSource) - { - IList advisors = FindEligibleAdvisors(targetType, targetName); - if (advisors.Count == 0) + if (AopUtils.CanApply(candidate, targetType, null, hasIntroductions)) { - return DO_NOT_PROXY; - } - return advisors.Cast().ToArray(); - } - - /// - /// Find all eligible advices and for autoproxying this class. - /// - /// the type of the object to be advised - /// the name of the object to be advised - /// - /// the empty list, not null, if there are no pointcuts or interceptors. - /// The by-order sorted list of advisors otherwise - /// - protected IList FindEligibleAdvisors(Type targetType, string targetName) - { - List candidateAdvisors = FindCandidateAdvisors(targetType, targetName); - List eligibleAdvisors = FindAdvisorsThatCanApply(candidateAdvisors, targetType, targetName); - - ExtendAdvisors(eligibleAdvisors, targetType, targetName); - SortAdvisors(eligibleAdvisors); - - return eligibleAdvisors; - } - - /// - /// Find all possible advisor candidates to use in auto-proxying - /// - /// the type of the object to be advised - /// the name of the object to be advised - /// the list of candidate advisors - protected virtual List FindCandidateAdvisors(Type targetType, string targetName) - { - return _advisorRetrievalHelper.FindAdvisorObjects(targetType, targetName); - } - - /// - /// From the given list of candidate advisors, select the ones that are applicable - /// to the given target specified by targetType and name. - /// - /// the list of candidate advisors to date - /// the target object's type - /// the target object's name - /// the list of applicable advisors - protected virtual List FindAdvisorsThatCanApply(List candidateAdvisors, Type targetType, string targetName) - { - if (candidateAdvisors.Count==0) - { - return candidateAdvisors; - } - - List eligibleAdvisors = new List(); - foreach(IAdvisor candidate in candidateAdvisors) - { - if (candidate is IIntroductionAdvisor && AopUtils.CanApply(candidate, targetType, null)) + if (logger.IsEnabled(LogLevel.Information)) { - if (logger.IsEnabled(LogLevel.Information)) - { - logger.LogInformation($"Candidate advisor [{candidate}] accepted for targetType [{targetType}]"); - } - eligibleAdvisors.Add(candidate); + logger.LogInformation($"Candidate advisor [{candidate}] accepted for targetType [{targetType}]"); + } + + eligibleAdvisors.Add(candidate); + } + else + { + if (logger.IsEnabled(LogLevel.Information)) + { + logger.LogInformation($"Candidate advisor [{candidate}] rejected for targetType [{targetType}]"); } } - - bool hasIntroductions = eligibleAdvisors.Count > 0; - foreach(IAdvisor candidate in candidateAdvisors) - { - if (candidate is IIntroductionAdvisor) continue; - - if (AopUtils.CanApply(candidate, targetType, null, hasIntroductions)) - { - if (logger.IsEnabled(LogLevel.Information)) - { - logger.LogInformation($"Candidate advisor [{candidate}] accepted for targetType [{targetType}]"); - } - eligibleAdvisors.Add(candidate); - } - else - { - if (logger.IsEnabled(LogLevel.Information)) - { - logger.LogInformation($"Candidate advisor [{candidate}] rejected for targetType [{targetType}]"); - } - } - } - return eligibleAdvisors; } + return eligibleAdvisors; + } - /// - /// Sorts the advisors. - /// - /// The advisors. - /// - protected virtual void SortAdvisors(List advisors) + /// + /// Sorts the advisors. + /// + /// The advisors. + /// + protected virtual void SortAdvisors(List advisors) + { + advisors.Sort(OrderComparator.Instance); + } + + /// + /// Extension hook that subclasses can override to add additional advisors for the given object, + /// given the sorted advisors obtained to date.
+ /// The default implementation does nothing.
+ /// Typically used to add advisors that expose contextual information required by some of the later advisors. + ///
+ /// + /// The advisor list passed into this method is already reduced to advisors applying to this particular object. + /// If you want to register additional common advisor candidates, override . + /// + /// Advisors that have already been identified as applying to a given object + /// the type of the object to be advised + /// the name of the object to be advised + protected virtual void ExtendAdvisors(IList advisors, Type objectType, string objectName) + { + } + + /// + /// Whether the given advisor is eligible for the specified target. The default implementation + /// always returns true. + /// + /// the advisor name + /// the target object's type + /// the target object's name + protected virtual bool IsEligibleAdvisorObject(string advisorName, Type targetType, string targetName) + { + return true; + } + + private class ObjectFactoryAdvisorRetrievalHelperAdapter : ObjectFactoryAdvisorRetrievalHelper + { + private readonly AbstractAdvisorAutoProxyCreator _owner; + + public ObjectFactoryAdvisorRetrievalHelperAdapter(AbstractAdvisorAutoProxyCreator owner, IConfigurableListableObjectFactory owningFactory) : base(owningFactory) { - advisors.Sort(OrderComparator.Instance); + _owner = owner; } - /// - /// Extension hook that subclasses can override to add additional advisors for the given object, - /// given the sorted advisors obtained to date.
- /// The default implementation does nothing.
- /// Typically used to add advisors that expose contextual information required by some of the later advisors. - ///
- /// - /// The advisor list passed into this method is already reduced to advisors applying to this particular object. - /// If you want to register additional common advisor candidates, override . - /// - /// Advisors that have already been identified as applying to a given object - /// the type of the object to be advised - /// the name of the object to be advised - protected virtual void ExtendAdvisors(IList advisors, Type objectType, string objectName) - {} - - /// - /// Whether the given advisor is eligible for the specified target. The default implementation - /// always returns true. - /// - /// the advisor name - /// the target object's type - /// the target object's name - protected virtual bool IsEligibleAdvisorObject(string advisorName, Type targetType, string targetName) + protected override bool IsEligibleObject(string advisorName, Type objectType, string objectName) { - return true; - } - - private class ObjectFactoryAdvisorRetrievalHelperAdapter : ObjectFactoryAdvisorRetrievalHelper - { - private readonly AbstractAdvisorAutoProxyCreator _owner; - - public ObjectFactoryAdvisorRetrievalHelperAdapter(AbstractAdvisorAutoProxyCreator owner, IConfigurableListableObjectFactory owningFactory) : base(owningFactory) - { - _owner = owner; - } - - protected override bool IsEligibleObject(string advisorName, Type objectType, string objectName) - { - return base.IsEligibleObject(advisorName, objectType, objectName) - && _owner.IsEligibleAdvisorObject(advisorName, objectType, objectName); - } + return base.IsEligibleObject(advisorName, objectType, objectName) + && _owner.IsEligibleAdvisorObject(advisorName, objectType, objectName); } } } diff --git a/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/AbstractAutoProxyCreator.cs b/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/AbstractAutoProxyCreator.cs index 59292dbc..7deae59a 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/AbstractAutoProxyCreator.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/AbstractAutoProxyCreator.cs @@ -16,7 +16,6 @@ using System.Collections; using System.Reflection; - using AopAlliance.Aop; using Microsoft.Extensions.Logging; using Spring.Aop.Framework.Adapter; @@ -27,211 +26,549 @@ using Spring.Objects; using Spring.Objects.Factory; using Spring.Objects.Factory.Config; -namespace Spring.Aop.Framework.AutoProxy +namespace Spring.Aop.Framework.AutoProxy; + +/// +/// ObjectPostProcessor implementation that wraps a group of objects with AOP proxies +/// that delegate to the given interceptors before invoking the object itself. +/// +/// +///

This class distinguishes between "common" interceptors: shared for all proxies it +/// creates, and "specific" interceptors: unique per object instance. There need not +/// be any common interceptors. If there are, they are set using the interceptorNames +/// property. As with ProxyFactoryObject, interceptors names in the current factory +/// are used rather than object references to allow correct handling of prototype +/// advisors and interceptors: for example, to support stateful mixins. +/// Any advice type is supported for "interceptorNames" entries.

+///

Such autoproxying is particularly useful if there's a large number of objects that need +/// to be wrapped with similar proxies, i.e. delegating to the same interceptors. +/// Instead of x repetitive proxy definitions for x target objects, you can register +/// one single such post processor with the object factory to achieve the same effect.

+///

Subclasses can apply any strategy to decide if a object is to be proxied, +/// e.g. by type, by name, by definition details, etc. They can also return +/// additional interceptors that should just be applied to the specific object +/// instance. The default concrete implementation is ObjectNameAutoProxyCreator, +/// identifying the objects to be proxied via a list of object names.

+///

Any number of TargetSourceCreator implementations can be used with any subclass, +/// to create a custom target source - for example, to pool prototype objects. +/// Autoproxying will occur even if there is no advice if a TargetSourceCreator specifies +/// a custom TargetSource. If there are no TargetSourceCreators set, or if none matches, +/// a SingletonTargetSource will be used by default to wrap the object to be autoproxied.

+///
+/// Juergen Hoeller +/// Rod Johnson +/// Adhari C Mahendra (.NET) +/// +/// +public abstract class AbstractAutoProxyCreator : ProxyConfig, IInstantiationAwareObjectPostProcessor, IObjectFactoryAware, IOrdered { /// - /// ObjectPostProcessor implementation that wraps a group of objects with AOP proxies - /// that delegate to the given interceptors before invoking the object itself. + /// The logger for this class hierarchy. + /// + protected readonly ILogger logger; + + /// + /// Convenience constant for subclasses: Return value for "do not proxy". + /// + protected static readonly IList DO_NOT_PROXY = null; + + /// + /// Convenience constant for subclasses: Return value for + /// "proxy without additional interceptors, just the common ones". + /// + protected static readonly IList PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS = new List(0); + + /// + /// Default value is same as non-ordered + /// + private int order = int.MaxValue; + + /// + /// Default is global AdvisorAdapterRegistry + /// + private IAdvisorAdapterRegistry advisorAdapterRegistry = GlobalAdvisorAdapterRegistry.Instance; + + /// + /// Indicates whether to mark the create proxy as immutable. /// /// - ///

This class distinguishes between "common" interceptors: shared for all proxies it - /// creates, and "specific" interceptors: unique per object instance. There need not - /// be any common interceptors. If there are, they are set using the interceptorNames - /// property. As with ProxyFactoryObject, interceptors names in the current factory - /// are used rather than object references to allow correct handling of prototype - /// advisors and interceptors: for example, to support stateful mixins. - /// Any advice type is supported for "interceptorNames" entries.

- ///

Such autoproxying is particularly useful if there's a large number of objects that need - /// to be wrapped with similar proxies, i.e. delegating to the same interceptors. - /// Instead of x repetitive proxy definitions for x target objects, you can register - /// one single such post processor with the object factory to achieve the same effect.

- ///

Subclasses can apply any strategy to decide if a object is to be proxied, - /// e.g. by type, by name, by definition details, etc. They can also return - /// additional interceptors that should just be applied to the specific object - /// instance. The default concrete implementation is ObjectNameAutoProxyCreator, - /// identifying the objects to be proxied via a list of object names.

- ///

Any number of TargetSourceCreator implementations can be used with any subclass, - /// to create a custom target source - for example, to pool prototype objects. - /// Autoproxying will occur even if there is no advice if a TargetSourceCreator specifies - /// a custom TargetSource. If there are no TargetSourceCreators set, or if none matches, - /// a SingletonTargetSource will be used by default to wrap the object to be autoproxied.

+ /// Setting this to true effectively disables modifying the generated + /// proxy's advisor configuration ///
- /// Juergen Hoeller - /// Rod Johnson - /// Adhari C Mahendra (.NET) - /// - /// - public abstract class AbstractAutoProxyCreator : ProxyConfig, IInstantiationAwareObjectPostProcessor, IObjectFactoryAware, IOrdered + private bool freezeProxy = false; + + /// + /// Names of common interceptors. + /// We must use object name rather than object references + /// to handle prototype advisors/interceptors. + /// Default is the empty array: no common interceptors. + /// + private string[] interceptorNames = new string[0]; + + private bool applyCommonInterceptorsFirst = true; + private IList customTargetSourceCreators = new ArrayList(); + private IObjectFactory owningObjectFactory; + + /// + /// Set of object type + name strings, referring to all objects that this auto-proxy + /// creator created a custom TargetSource for. Used to detect own pre-built proxies + /// (from "PostProcessBeforeInstantiation") in the "PostProcessAfterInitialization" method. + /// + private ISet targetSourcedObjects = new SynchronizedSet(new HashedSet()); + + private ISet advisedObjects = new SynchronizedSet(new HashedSet()); + + private ISet nonAdvisedObjects = new SynchronizedSet(new HashedSet()); + + /// + /// Sets the AdvisorAdapterRegistry to use. + /// + /// + /// Default is the global AdvisorAdapterRegistry. + /// + public IAdvisorAdapterRegistry AdvisorAdapterRegistry { - /// - /// The logger for this class hierarchy. - /// - protected readonly ILogger logger; + set { advisorAdapterRegistry = value; } + } - /// - /// Convenience constant for subclasses: Return value for "do not proxy". - /// - protected static readonly IList DO_NOT_PROXY = null; + /// + /// Sets custom TargetSourceCreators to be applied in this order. + /// + /// + /// + /// If the list is empty, or they all return null, a SingletonTargetSource + /// will be created. + /// + /// + /// TargetSourceCreators can only be invoked if this post processor is used + /// in a IObjectFactory, and its ObjectFactoryAware callback is used. + /// + /// + public IList CustomTargetSourceCreators + { + set { customTargetSourceCreators = value; } + } - /// - /// Convenience constant for subclasses: Return value for - /// "proxy without additional interceptors, just the common ones". - /// - protected static readonly IList PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS = new List(0); + /// + /// Sets the common interceptors, a list of , + /// and introduction object names. + /// + /// + /// + /// If this property isn't set, there will be zero common interceptors. + /// This is perfectly valid, if "specific" interceptors such as + /// matching Advisors are all we want. + /// + /// + /// + /// The list of , + /// and introduction object names. + /// + /// + /// + public string[] InterceptorNames + { + set { interceptorNames = value; } + } - /// - /// Default value is same as non-ordered - /// - private int order = int.MaxValue; + /// + /// Sets whether the common interceptors should be applied before + /// object-specific ones. + /// + /// + /// Default is true; else, object-specific interceptors will get applied first. + /// + public bool ApplyCommonInterceptorsFirst + { + set { applyCommonInterceptorsFirst = value; } + } - /// - /// Default is global AdvisorAdapterRegistry - /// - private IAdvisorAdapterRegistry advisorAdapterRegistry = GlobalAdvisorAdapterRegistry.Instance; + /// + /// Set whether or not the proxy should be frozen, preventing advice + /// from being added to it once it is created. + /// + /// + ///

Overridden from the super class to prevent the proxy configuration + /// from being frozen before the proxy is created. The default is not frozen. + ///

+ ///
+ public override bool IsFrozen + { + get { return freezeProxy; } + set { this.freezeProxy = value; } + } - /// - /// Indicates whether to mark the create proxy as immutable. - /// - /// - /// Setting this to true effectively disables modifying the generated - /// proxy's advisor configuration - /// - private bool freezeProxy = false; + /// + /// Create a new instance of this AutoProxyCreator + /// + protected AbstractAutoProxyCreator() + { + logger = LogManager.GetLogger(this.GetType()); + } - /// - /// Names of common interceptors. - /// We must use object name rather than object references - /// to handle prototype advisors/interceptors. - /// Default is the empty array: no common interceptors. - /// - private string[] interceptorNames = new string[0]; - - private bool applyCommonInterceptorsFirst = true; - private IList customTargetSourceCreators = new ArrayList(); - private IObjectFactory owningObjectFactory; - - /// - /// Set of object type + name strings, referring to all objects that this auto-proxy - /// creator created a custom TargetSource for. Used to detect own pre-built proxies - /// (from "PostProcessBeforeInstantiation") in the "PostProcessAfterInitialization" method. - /// - private ISet targetSourcedObjects = new SynchronizedSet(new HashedSet()); - - private ISet advisedObjects = new SynchronizedSet(new HashedSet()); - - private ISet nonAdvisedObjects = new SynchronizedSet(new HashedSet()); - - /// - /// Sets the AdvisorAdapterRegistry to use. - /// - /// - /// Default is the global AdvisorAdapterRegistry. - /// - public IAdvisorAdapterRegistry AdvisorAdapterRegistry + /// + /// Create a proxy with the configured interceptors if the object is + /// identified as one to proxy by the subclass. + /// + public virtual object PostProcessAfterInitialization(object obj, string objectName) + { + if (targetSourcedObjects.Contains(objectName)) { - set { advisorAdapterRegistry = value; } + return obj; } - /// - /// Sets custom TargetSourceCreators to be applied in this order. - /// - /// - /// - /// If the list is empty, or they all return null, a SingletonTargetSource - /// will be created. - /// - /// - /// TargetSourceCreators can only be invoked if this post processor is used - /// in a IObjectFactory, and its ObjectFactoryAware callback is used. - /// - /// - public IList CustomTargetSourceCreators - { - set { customTargetSourceCreators = value; } - } - - /// - /// Sets the common interceptors, a list of , - /// and introduction object names. - /// - /// - /// - /// If this property isn't set, there will be zero common interceptors. - /// This is perfectly valid, if "specific" interceptors such as - /// matching Advisors are all we want. - /// - /// - /// - /// The list of , - /// and introduction object names. - /// - /// - /// - public string[] InterceptorNames - { - set { interceptorNames = value; } - } - - /// - /// Sets whether the common interceptors should be applied before - /// object-specific ones. - /// - /// - /// Default is true; else, object-specific interceptors will get applied first. - /// - public bool ApplyCommonInterceptorsFirst - { - set { applyCommonInterceptorsFirst = value; } - } - - /// - /// Set whether or not the proxy should be frozen, preventing advice - /// from being added to it once it is created. - /// - /// - ///

Overridden from the super class to prevent the proxy configuration - /// from being frozen before the proxy is created. The default is not frozen. - ///

- ///
- public override bool IsFrozen - { - get { return freezeProxy; } - set { this.freezeProxy = value; } - } - - /// - /// Create a new instance of this AutoProxyCreator - /// - protected AbstractAutoProxyCreator() - { - logger = LogManager.GetLogger(this.GetType()); - } - - /// - /// Create a proxy with the configured interceptors if the object is - /// identified as one to proxy by the subclass. - /// - public virtual object PostProcessAfterInitialization(object obj, string objectName) - { - if (targetSourcedObjects.Contains(objectName)) - { - return obj; - } - #if NETSTANDARD var isTransparentProxy = false; #else - var isTransparentProxy = System.Runtime.Remoting.RemotingServices.IsTransparentProxy(obj); + var isTransparentProxy = System.Runtime.Remoting.RemotingServices.IsTransparentProxy(obj); #endif - Type objectType = isTransparentProxy - ? ObjectFactory.GetType(objectName) - : obj.GetType(); + Type objectType = isTransparentProxy + ? ObjectFactory.GetType(objectName) + : obj.GetType(); - object cacheKey = GetCacheKey(objectType, objectName); - if (nonAdvisedObjects.Contains(cacheKey)) + object cacheKey = GetCacheKey(objectType, objectName); + if (nonAdvisedObjects.Contains(cacheKey)) + { + return obj; + } + + if (IsInfrastructureType(objectType, objectName)) + { + if (logger.IsEnabled(LogLevel.Debug)) { - return obj; + logger.LogDebug(string.Format("Did not attempt to autoproxy infrastructure type [{0}]", objectType)); + } + + nonAdvisedObjects.Add(cacheKey); + return obj; + } + + if (ShouldSkip(objectType, objectName)) + { + if (logger.IsEnabled(LogLevel.Debug)) + { + logger.LogDebug(string.Format("Skipping type [{0}]", objectType)); + } + + nonAdvisedObjects.Add(cacheKey); + return obj; + } + + //ITargetSource targetSource = GetCustomTargetSource(obj.GetType(), objectName); + IList specificInterceptors = GetAdvicesAndAdvisorsForObject(objectType, objectName, null); + + // proxy if we have advice or if a TargetSourceCreator wants to do some + // fancy stuff such as pooling + if (specificInterceptors != DO_NOT_PROXY) + { + advisedObjects.Add(cacheKey); + return CreateProxy(objectType, objectName, specificInterceptors, new SingletonTargetSource(obj, objectType)); + } + + nonAdvisedObjects.Add(cacheKey); + return obj; + } + + /// + /// No-op for before initialization. + /// + /// The obj. + /// The name. + /// + public virtual object PostProcessBeforeInitialization(object obj, string name) + { + return obj; + } + + /// + /// Callback that supplies the owning factory to an object instance. + /// + /// + /// Owning + /// (may not be ). The object can immediately + /// call methods on the factory. + /// + /// + ///

+ /// Invoked after population of normal object properties but before an init + /// callback like 's + /// + /// method or a custom init-method. + ///

+ ///
+ /// + /// In case of initialization errors. + /// + public virtual IObjectFactory ObjectFactory + { + get { return owningObjectFactory; } + set { owningObjectFactory = value; } + } + + /// + /// Propery Order + /// + /// + /// Ordering which will apply to this class's implementation + /// of Ordered, used when applying multiple ObjectPostProcessors. + /// Default value is int.MaxValue, meaning that it's non-ordered. + /// + public virtual int Order + { + get { return order; } + set { order = value; } + } + + /// + /// Subclasses should override this method to return true if this + /// object should not be considered for autoproxying by this post processor. + /// Sometimes we need to be able to avoid this happening if it will lead to + /// a circular reference. This implementation returns false. + /// + /// the type of the object + /// the name of the object + /// if remarkable to skip + protected virtual bool ShouldSkip(Type targetType, string targetName) + { + return false; + } + + /// + /// Subclasses may choose to implement this: for example, + /// to change the interfaces exposed + /// + /// + /// ProxyFactory that will be used to create the proxy immediably after this method returns. + /// + protected virtual void CustomizeProxyFactory(ProxyFactory pf) + { + // This implementation does nothing + } + + /// + /// Determines whether the object is an infrastructure type, + /// IAdvisor, IAdvice, IAdvisors or AbstractAutoProxyCreator + /// + /// The object type to compare + /// The name of the object + /// + /// true if [is infrastructure type] [the specified obj]; otherwise, false. + /// + protected virtual bool IsInfrastructureType(Type type, String name) + { + return typeof(IAdvisor).IsAssignableFrom(type) + || typeof(IAdvice).IsAssignableFrom(type) + || typeof(IAdvisors).IsAssignableFrom(type) + || typeof(AbstractAutoProxyCreator).IsAssignableFrom(type); + } + + /// + /// Create a target source for object instances. Uses any + /// TargetSourceCreators if set. Returns null if no Custom TargetSource + /// should be used. + /// This implementation uses the customTargetSourceCreators property. + /// Subclasses can override this method to use a different mechanism. + /// + /// the type of the object to create a TargetSource for + /// the name of the object + /// a TargetSource for this object + protected virtual ITargetSource GetCustomTargetSource(Type objectType, string name) + { + // We can't create fancy target sources for directly registered singletons. + if (customTargetSourceCreators != null && + owningObjectFactory != null && owningObjectFactory.ContainsObject(name)) + { + for (int i = 0; i < customTargetSourceCreators.Count; i++) + { + ITargetSourceCreator tsc = (ITargetSourceCreator) customTargetSourceCreators[i]; + ITargetSource ts = tsc.GetTargetSource(objectType, name, owningObjectFactory); + if (ts != null) + { + // found a match + if (logger.IsEnabled(LogLevel.Information)) + { + logger.LogInformation(string.Format("TargetSourceCreator [{0} found custom TargetSource for object with objectName '{1}'", tsc, name)); + } + + return ts; + } + } + } + + // no custom TargetSource found + return null; + } + + /// + /// Return whether the given object is to be proxied, what additional + /// advices (e.g. AOP Alliance interceptors) and advisors to apply. + /// + /// + ///

The previous targetName of this method was "GetInterceptorAndAdvisorForObject". + /// It has been renamed in the course of general terminology clarification + /// in Spring 1.1. An AOP Alliance Interceptor is just a special form of + /// Advice, so the generic Advice term is preferred now.

+ ///

The third parameter, customTargetSource, is new in Spring 1.1; + /// add it to existing implementations of this method.

+ ///
+ /// the new object instance + /// the name of the object + /// targetSource returned by TargetSource property: + /// may be ignored. Will be null unless a custom target source is in use. + /// an array of additional interceptors for the particular object; + /// or an empty array if no additional interceptors but just the common ones; + /// or null if no proxy at all, not even with the common interceptors. + protected abstract IList GetAdvicesAndAdvisorsForObject(Type targetType, string targetName, ITargetSource customTargetSource); + + /// + /// Create an AOP proxy for the given object. + /// + /// Type of the object. + /// The name of the object. + /// The set of interceptors that is specific to this + /// object (may be empty but not null) + /// The target source for the proxy, already pre-configured to access the object. + /// The AOP Proxy for the object. + protected virtual object CreateProxy(Type targetType, string targetName, IList specificInterceptors, ITargetSource targetSource) + { + ProxyFactory proxyFactory = CreateProxyFactory(); + // copy our properties (proxyTargetClass) inherited from ProxyConfig + proxyFactory.CopyFrom(this); + + object target = targetSource.GetTarget(); + + if (!ProxyTargetType) + { + // Must allow for introductions; can't just set interfaces to + // the target's interfaces only. + Type[] targetInterfaceTypes = AopUtils.GetAllInterfacesFromType(targetType); + foreach (Type interfaceType in targetInterfaceTypes) + { + proxyFactory.AddInterface(interfaceType); + } + } + + IList advisors = BuildAdvisors(targetName, specificInterceptors); + + foreach (IAdvisor advisor in advisors) + { + if (advisor is IIntroductionAdvisor) + { + proxyFactory.AddIntroduction((IIntroductionAdvisor) advisor); + } + else + { + proxyFactory.AddAdvisor(advisor); + } + } + + proxyFactory.TargetSource = targetSource; + CustomizeProxyFactory(proxyFactory); + + proxyFactory.IsFrozen = freezeProxy; + return proxyFactory.GetProxy(); + } + + /// + /// Obtain a new proxy factory instance to be used for proxying a particular object + /// + /// A proxy factory instance for proxying a particular object + protected virtual ProxyFactory CreateProxyFactory() + { + return new ProxyFactory(); + } + + /// + /// Determines the advisors for the given object, including the specific interceptors + /// as well as the common interceptor, all adapted to the Advisor interface. + /// + /// The name of the object. + /// The set of interceptors that is specific to this + /// object (may be empty, but not null) + /// The list of Advisors for the given object + protected virtual IList BuildAdvisors(string targetName, IList specificInterceptors) + { + // handle prototypes correctly + IList commonInterceptors = ResolveInterceptorNames(); + + List allInterceptors = new List(); + if (specificInterceptors != null) + { + allInterceptors.AddRange(specificInterceptors); + if (commonInterceptors != null) + { + if (applyCommonInterceptorsFirst) + { + allInterceptors.InsertRange(0, commonInterceptors.Cast()); + } + else + { + allInterceptors.AddRange(commonInterceptors.Cast()); + } + } + } + + if (logger.IsEnabled(LogLevel.Information)) + { + int nrOfCommonInterceptors = commonInterceptors != null ? commonInterceptors.Count : 0; + int nrOfSpecificInterceptors = specificInterceptors != null ? specificInterceptors.Count : 0; + logger.LogInformation(string.Format("Creating implicit proxy for object '{0}' with {1} common interceptors and {2} specific interceptors", targetName, nrOfCommonInterceptors, nrOfSpecificInterceptors)); + } + + List advisors = new List(allInterceptors.Count); + for (int i = 0; i < allInterceptors.Count; i++) + { + advisors.Add(advisorAdapterRegistry.Wrap(allInterceptors[i])); + } + + return advisors; + } + + /// + /// Build a cache key for the given object type and object name + /// + /// The object type. + /// The object name. + /// The cache key for the given type and name + protected virtual object GetCacheKey(Type objectType, string objectName) + { + return objectType.FullName + "_" + objectName; + } + + private IList ResolveInterceptorNames() + { + List advisors = new List(); + foreach (string name in interceptorNames) + { + object next = owningObjectFactory.GetObject(name); + if (next is IAdvisors) + { + advisors.AddRange(((IAdvisors) next).Advisors); + } + else + { + advisors.Add(advisorAdapterRegistry.Wrap(next)); + } + } + + return advisors; + } + + /// + /// Create the proxy if have a custom TargetSource + /// + /// The object type + /// The object name + /// null if not creating a proxy, otherwise return the proxy. + public object PostProcessBeforeInstantiation(Type objectType, string objectName) + { + object cacheKey = GetCacheKey(objectType, objectName); + if (!targetSourcedObjects.Contains(cacheKey)) + { + if (advisedObjects.Contains(cacheKey) || nonAdvisedObjects.Contains(cacheKey)) + { + return null; } if (IsInfrastructureType(objectType, objectName)) @@ -242,7 +579,7 @@ namespace Spring.Aop.Framework.AutoProxy } nonAdvisedObjects.Add(cacheKey); - return obj; + return null; } if (ShouldSkip(objectType, objectName)) @@ -253,385 +590,47 @@ namespace Spring.Aop.Framework.AutoProxy } nonAdvisedObjects.Add(cacheKey); - return obj; + return null; } - - //ITargetSource targetSource = GetCustomTargetSource(obj.GetType(), objectName); - IList specificInterceptors = GetAdvicesAndAdvisorsForObject(objectType, objectName, null); - - - // proxy if we have advice or if a TargetSourceCreator wants to do some - // fancy stuff such as pooling - if (specificInterceptors != DO_NOT_PROXY) - { - advisedObjects.Add(cacheKey); - return CreateProxy(objectType, objectName, specificInterceptors, new SingletonTargetSource(obj, objectType)); - } - nonAdvisedObjects.Add(cacheKey); - return obj; } - /// - /// No-op for before initialization. - /// - /// The obj. - /// The name. - /// - public virtual object PostProcessBeforeInitialization(object obj, string name) + // Create proxy here if we have a custom TargetSource. + // Suppresses unnecessary default instantiation of the target object: + // The TargetSource will handle target instances in a custom fashion. + ITargetSource targetSource = GetCustomTargetSource(objectType, objectName); + if (targetSource != null) { - return obj; + targetSourcedObjects.Add(objectName); + IList specificInterceptors = GetAdvicesAndAdvisorsForObject(objectType, objectName, targetSource); + return CreateProxy(objectType, objectName, specificInterceptors, targetSource); } - /// - /// Callback that supplies the owning factory to an object instance. - /// - /// - /// Owning - /// (may not be ). The object can immediately - /// call methods on the factory. - /// - /// - ///

- /// Invoked after population of normal object properties but before an init - /// callback like 's - /// - /// method or a custom init-method. - ///

- ///
- /// - /// In case of initialization errors. - /// - public virtual IObjectFactory ObjectFactory - { - get { return owningObjectFactory; } - set { owningObjectFactory = value; } - } + return null; + } - /// - /// Propery Order - /// - /// - /// Ordering which will apply to this class's implementation - /// of Ordered, used when applying multiple ObjectPostProcessors. - /// Default value is int.MaxValue, meaning that it's non-ordered. - /// - public virtual int Order - { - get { return order; } - set { order = value; } - } + /// + /// Default behavior, return true and continue processing. + /// + /// The object instance + /// The object name. + /// true + public bool PostProcessAfterInstantiation(object objectInstance, string objectName) + { + return true; + } - /// - /// Subclasses should override this method to return true if this - /// object should not be considered for autoproxying by this post processor. - /// Sometimes we need to be able to avoid this happening if it will lead to - /// a circular reference. This implementation returns false. - /// - /// the type of the object - /// the name of the object - /// if remarkable to skip - protected virtual bool ShouldSkip(Type targetType, string targetName) - { - return false; - } - - /// - /// Subclasses may choose to implement this: for example, - /// to change the interfaces exposed - /// - /// - /// ProxyFactory that will be used to create the proxy immediably after this method returns. - /// - protected virtual void CustomizeProxyFactory(ProxyFactory pf) - { - // This implementation does nothing - } - - /// - /// Determines whether the object is an infrastructure type, - /// IAdvisor, IAdvice, IAdvisors or AbstractAutoProxyCreator - /// - /// The object type to compare - /// The name of the object - /// - /// true if [is infrastructure type] [the specified obj]; otherwise, false. - /// - protected virtual bool IsInfrastructureType(Type type, String name) - { - return typeof(IAdvisor).IsAssignableFrom(type) - || typeof(IAdvice).IsAssignableFrom(type) - || typeof(IAdvisors).IsAssignableFrom(type) - || typeof(AbstractAutoProxyCreator).IsAssignableFrom(type); - } - - - /// - /// Create a target source for object instances. Uses any - /// TargetSourceCreators if set. Returns null if no Custom TargetSource - /// should be used. - /// This implementation uses the customTargetSourceCreators property. - /// Subclasses can override this method to use a different mechanism. - /// - /// the type of the object to create a TargetSource for - /// the name of the object - /// a TargetSource for this object - protected virtual ITargetSource GetCustomTargetSource(Type objectType, string name) - { - // We can't create fancy target sources for directly registered singletons. - if (customTargetSourceCreators != null && - owningObjectFactory != null && owningObjectFactory.ContainsObject(name)) - { - for (int i = 0; i < customTargetSourceCreators.Count; i++) - { - ITargetSourceCreator tsc = (ITargetSourceCreator)customTargetSourceCreators[i]; - ITargetSource ts = tsc.GetTargetSource(objectType, name, owningObjectFactory); - if (ts != null) - { - // found a match - if (logger.IsEnabled(LogLevel.Information)) - { - logger.LogInformation(string.Format("TargetSourceCreator [{0} found custom TargetSource for object with objectName '{1}'", tsc, name)); - } - return ts; - } - } - } - - // no custom TargetSource found - return null; - } - - /// - /// Return whether the given object is to be proxied, what additional - /// advices (e.g. AOP Alliance interceptors) and advisors to apply. - /// - /// - ///

The previous targetName of this method was "GetInterceptorAndAdvisorForObject". - /// It has been renamed in the course of general terminology clarification - /// in Spring 1.1. An AOP Alliance Interceptor is just a special form of - /// Advice, so the generic Advice term is preferred now.

- ///

The third parameter, customTargetSource, is new in Spring 1.1; - /// add it to existing implementations of this method.

- ///
- /// the new object instance - /// the name of the object - /// targetSource returned by TargetSource property: - /// may be ignored. Will be null unless a custom target source is in use. - /// an array of additional interceptors for the particular object; - /// or an empty array if no additional interceptors but just the common ones; - /// or null if no proxy at all, not even with the common interceptors. - protected abstract IList GetAdvicesAndAdvisorsForObject(Type targetType, string targetName, ITargetSource customTargetSource); - - /// - /// Create an AOP proxy for the given object. - /// - /// Type of the object. - /// The name of the object. - /// The set of interceptors that is specific to this - /// object (may be empty but not null) - /// The target source for the proxy, already pre-configured to access the object. - /// The AOP Proxy for the object. - protected virtual object CreateProxy(Type targetType, string targetName, IList specificInterceptors, ITargetSource targetSource) - { - ProxyFactory proxyFactory = CreateProxyFactory(); - // copy our properties (proxyTargetClass) inherited from ProxyConfig - proxyFactory.CopyFrom(this); - - object target = targetSource.GetTarget(); - - - if (!ProxyTargetType) - { - // Must allow for introductions; can't just set interfaces to - // the target's interfaces only. - Type[] targetInterfaceTypes = AopUtils.GetAllInterfacesFromType(targetType); - foreach (Type interfaceType in targetInterfaceTypes) - { - proxyFactory.AddInterface(interfaceType); - } - } - - - IList advisors = BuildAdvisors(targetName, specificInterceptors); - - foreach (IAdvisor advisor in advisors) - { - if (advisor is IIntroductionAdvisor) - { - proxyFactory.AddIntroduction((IIntroductionAdvisor)advisor); - } - else - { - proxyFactory.AddAdvisor(advisor); - } - } - proxyFactory.TargetSource = targetSource; - CustomizeProxyFactory(proxyFactory); - - proxyFactory.IsFrozen = freezeProxy; - return proxyFactory.GetProxy(); - } - - /// - /// Obtain a new proxy factory instance to be used for proxying a particular object - /// - /// A proxy factory instance for proxying a particular object - protected virtual ProxyFactory CreateProxyFactory() - { - return new ProxyFactory(); - } - - /// - /// Determines the advisors for the given object, including the specific interceptors - /// as well as the common interceptor, all adapted to the Advisor interface. - /// - /// The name of the object. - /// The set of interceptors that is specific to this - /// object (may be empty, but not null) - /// The list of Advisors for the given object - protected virtual IList BuildAdvisors(string targetName, IList specificInterceptors) - { - // handle prototypes correctly - IList commonInterceptors = ResolveInterceptorNames(); - - List allInterceptors = new List(); - if (specificInterceptors != null) - { - allInterceptors.AddRange(specificInterceptors); - if (commonInterceptors != null) - { - if (applyCommonInterceptorsFirst) - { - allInterceptors.InsertRange(0, commonInterceptors.Cast()); - } - else - { - allInterceptors.AddRange(commonInterceptors.Cast()); - } - } - } - if (logger.IsEnabled(LogLevel.Information)) - { - int nrOfCommonInterceptors = commonInterceptors != null ? commonInterceptors.Count : 0; - int nrOfSpecificInterceptors = specificInterceptors != null ? specificInterceptors.Count : 0; - logger.LogInformation(string.Format("Creating implicit proxy for object '{0}' with {1} common interceptors and {2} specific interceptors", targetName, nrOfCommonInterceptors, nrOfSpecificInterceptors)); - } - - - List advisors = new List(allInterceptors.Count); - for (int i = 0; i < allInterceptors.Count; i++) - { - advisors.Add(advisorAdapterRegistry.Wrap(allInterceptors[i])); - } - return advisors; - } - - /// - /// Build a cache key for the given object type and object name - /// - /// The object type. - /// The object name. - /// The cache key for the given type and name - protected virtual object GetCacheKey(Type objectType, string objectName) - { - return objectType.FullName + "_" + objectName; - } - - - private IList ResolveInterceptorNames() - { - List advisors = new List(); - foreach (string name in interceptorNames) - { - object next = owningObjectFactory.GetObject(name); - if (next is IAdvisors) - { - advisors.AddRange(((IAdvisors)next).Advisors); - } - else - { - advisors.Add(advisorAdapterRegistry.Wrap(next)); - } - } - return advisors; - } - - /// - /// Create the proxy if have a custom TargetSource - /// - /// The object type - /// The object name - /// null if not creating a proxy, otherwise return the proxy. - public object PostProcessBeforeInstantiation(Type objectType, string objectName) - { - object cacheKey = GetCacheKey(objectType, objectName); - if (!targetSourcedObjects.Contains(cacheKey)) - { - if (advisedObjects.Contains(cacheKey) || nonAdvisedObjects.Contains(cacheKey)) - { - return null; - } - - if (IsInfrastructureType(objectType, objectName)) - { - if (logger.IsEnabled(LogLevel.Debug)) - { - logger.LogDebug(string.Format("Did not attempt to autoproxy infrastructure type [{0}]", objectType)); - } - - nonAdvisedObjects.Add(cacheKey); - return null; - } - - if (ShouldSkip(objectType, objectName)) - { - if (logger.IsEnabled(LogLevel.Debug)) - { - logger.LogDebug(string.Format("Skipping type [{0}]", objectType)); - } - - nonAdvisedObjects.Add(cacheKey); - return null; - } - } - // Create proxy here if we have a custom TargetSource. - // Suppresses unnecessary default instantiation of the target object: - // The TargetSource will handle target instances in a custom fashion. - ITargetSource targetSource = GetCustomTargetSource(objectType, objectName); - if (targetSource != null) - { - targetSourcedObjects.Add(objectName); - IList specificInterceptors = GetAdvicesAndAdvisorsForObject(objectType, objectName, targetSource); - return CreateProxy(objectType, objectName, specificInterceptors, targetSource); - } - return null; - } - - - /// - /// Default behavior, return true and continue processing. - /// - /// The object instance - /// The object name. - /// true - public bool PostProcessAfterInstantiation(object objectInstance, string objectName) - { - return true; - } - - /// - /// Default behavior, return passed in PropertyValues - /// - /// The property values that the factory is about to apply (never null). - /// he relevant property infos for the target object (with ignored - /// dependency types - which the factory handles specifically - already filtered out) - /// The object instance created, but whose properties have not yet - /// been set. - /// Name of the object. - /// The passed in PropertyValues - public IPropertyValues PostProcessPropertyValues(IPropertyValues pvs, IList pis, object objectInstance, string objectName) - { - return pvs; - } + /// + /// Default behavior, return passed in PropertyValues + /// + /// The property values that the factory is about to apply (never null). + /// he relevant property infos for the target object (with ignored + /// dependency types - which the factory handles specifically - already filtered out) + /// The object instance created, but whose properties have not yet + /// been set. + /// Name of the object. + /// The passed in PropertyValues + public IPropertyValues PostProcessPropertyValues(IPropertyValues pvs, IList pis, object objectInstance, string objectName) + { + return pvs; } } diff --git a/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/AbstractFilteringAutoProxyCreator.cs b/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/AbstractFilteringAutoProxyCreator.cs index ed80d290..41005504 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/AbstractFilteringAutoProxyCreator.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/AbstractFilteringAutoProxyCreator.cs @@ -22,55 +22,54 @@ #endregion -namespace Spring.Aop.Framework.AutoProxy +namespace Spring.Aop.Framework.AutoProxy; + +/// +/// The base class for AutoProxyCreator implementations that mark objects +/// eligible for proxying based on arbitrary criteria. +/// +/// Erich Eichinger +public abstract class AbstractFilteringAutoProxyCreator : AbstractAutoProxyCreator { /// - /// The base class for AutoProxyCreator implementations that mark objects - /// eligible for proxying based on arbitrary criteria. + ///Overridden to call . /// - /// Erich Eichinger - public abstract class AbstractFilteringAutoProxyCreator : AbstractAutoProxyCreator + /// the type of the object + /// the name of the object + /// if remarkable to skip + protected override bool ShouldSkip(Type targetType, string targetName) { - /// - ///Overridden to call . - /// - /// the type of the object - /// the name of the object - /// if remarkable to skip - protected override bool ShouldSkip( Type targetType, string targetName ) - { - bool shouldSkip = !IsEligibleForProxying( targetType, targetName ); - return shouldSkip; - } - - /// - /// Override to always return . - /// - /// - /// Whether an object shall be proxied or not is determined by the result of . - /// - /// ingored - /// ignored - /// ignored - /// - /// Always to indicate, that the object shall be proxied. - /// - /// - protected override IList GetAdvicesAndAdvisorsForObject(Type targetType, string targetName, ITargetSource customTargetSource) - { - return PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS; - } - - /// - /// Decide, whether the given object is eligible for proxying. - /// - /// - /// Override this method to allow or reject proxying for the given object. - /// - /// the object's type - /// the name of the object - /// - /// whether the given object shall be proxied. - protected abstract bool IsEligibleForProxying( Type targetType, string targetName ); + bool shouldSkip = !IsEligibleForProxying(targetType, targetName); + return shouldSkip; } + + /// + /// Override to always return . + /// + /// + /// Whether an object shall be proxied or not is determined by the result of . + /// + /// ingored + /// ignored + /// ignored + /// + /// Always to indicate, that the object shall be proxied. + /// + /// + protected override IList GetAdvicesAndAdvisorsForObject(Type targetType, string targetName, ITargetSource customTargetSource) + { + return PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS; + } + + /// + /// Decide, whether the given object is eligible for proxying. + /// + /// + /// Override this method to allow or reject proxying for the given object. + /// + /// the object's type + /// the name of the object + /// + /// whether the given object shall be proxied. + protected abstract bool IsEligibleForProxying(Type targetType, string targetName); } diff --git a/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/AttributeAutoProxyCreator.cs b/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/AttributeAutoProxyCreator.cs index 60599f52..a11c9072 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/AttributeAutoProxyCreator.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/AttributeAutoProxyCreator.cs @@ -24,89 +24,89 @@ using Spring.Util; #endregion -namespace Spring.Aop.Framework.AutoProxy +namespace Spring.Aop.Framework.AutoProxy; + +/// +/// An AutoProxyCreator, that identifies objects to be proxied by checking s defined on their type. +/// +/// Erich Eichinger +public class AttributeAutoProxyCreator : AbstractFilteringAutoProxyCreator { + private bool _checkInherited = false; + private Type[] _attributeTypes = null; + /// - /// An AutoProxyCreator, that identifies objects to be proxied by checking s defined on their type. + /// Indicates, whether to consider base types for filtering when checking declared attributes. Defaults to false. /// - /// Erich Eichinger - public class AttributeAutoProxyCreator : AbstractFilteringAutoProxyCreator + public bool CheckInherited { - private bool _checkInherited = false; - private Type[] _attributeTypes = null; + get { return _checkInherited; } + set { _checkInherited = value; } + } - /// - /// Indicates, whether to consider base types for filtering when checking declared attributes. Defaults to false. - /// - public bool CheckInherited + /// + /// The list of attribute types marking object types as eligible for auto-proxying by this AutoProxyCreator. Must not be null. + /// + public Type[] AttributeTypes + { + get { return _attributeTypes; } + set { - get { return _checkInherited; } - set { _checkInherited = value; } - } - - /// - /// The list of attribute types marking object types as eligible for auto-proxying by this AutoProxyCreator. Must not be null. - /// - public Type[] AttributeTypes - { - get { return _attributeTypes; } - set - { - AssertUtils.ArgumentNotNull( value, "AttributeTypes" ); - _attributeTypes = value; - } - } - - /// - /// Determines, whether the given object shall be proxied by matching against . - /// - /// the object's type - /// the name of the object - protected override bool IsEligibleForProxying( Type targetType, string targetName ) - { - AssertUtils.ArgumentNotNull(this.AttributeTypes, "AttributeTypes"); - - bool shallProxy = IsAnnotatedWithAnyOfAttribute( targetType, this.AttributeTypes, this.CheckInherited ); - return shallProxy; - } - - /// - /// Checks if is annotated with any of the attributes within the given list of . - /// - /// the object's type - /// the list of types to match agains. - /// whether to check base classes and intefaces for any of the given attributes. - /// if any of the attributes is found - protected virtual bool IsAnnotatedWithAnyOfAttribute( Type objectType, Type[] attributeTypes, bool checkInherited ) - { - foreach(Type attributeType in attributeTypes) - { - if (IsAnnotatedWithAttribute(objectType, attributeType, checkInherited)) - { - return true; - } - } - return false; - } - - /// - /// Checks if is annotated with the specified . - /// - /// the object's type - /// the type to match agains. - /// whether to check base classes and intefaces for the specified attribute. - /// if the attributes is found - protected virtual bool IsAnnotatedWithAttribute( Type objectType, Type attributeType, bool checkInherited ) - { - if (checkInherited) - { - return AttributeUtils.FindAttribute( objectType, attributeType ) != null; - } - else - { - object[] atts = objectType.GetCustomAttributes( attributeType, false ); - return ArrayUtils.HasLength( atts ); - } + AssertUtils.ArgumentNotNull(value, "AttributeTypes"); + _attributeTypes = value; } } -} + + /// + /// Determines, whether the given object shall be proxied by matching against . + /// + /// the object's type + /// the name of the object + protected override bool IsEligibleForProxying(Type targetType, string targetName) + { + AssertUtils.ArgumentNotNull(this.AttributeTypes, "AttributeTypes"); + + bool shallProxy = IsAnnotatedWithAnyOfAttribute(targetType, this.AttributeTypes, this.CheckInherited); + return shallProxy; + } + + /// + /// Checks if is annotated with any of the attributes within the given list of . + /// + /// the object's type + /// the list of types to match agains. + /// whether to check base classes and intefaces for any of the given attributes. + /// if any of the attributes is found + protected virtual bool IsAnnotatedWithAnyOfAttribute(Type objectType, Type[] attributeTypes, bool checkInherited) + { + foreach (Type attributeType in attributeTypes) + { + if (IsAnnotatedWithAttribute(objectType, attributeType, checkInherited)) + { + return true; + } + } + + return false; + } + + /// + /// Checks if is annotated with the specified . + /// + /// the object's type + /// the type to match agains. + /// whether to check base classes and intefaces for the specified attribute. + /// if the attributes is found + protected virtual bool IsAnnotatedWithAttribute(Type objectType, Type attributeType, bool checkInherited) + { + if (checkInherited) + { + return AttributeUtils.FindAttribute(objectType, attributeType) != null; + } + else + { + object[] atts = objectType.GetCustomAttributes(attributeType, false); + return ArrayUtils.HasLength(atts); + } + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/DefaultAdvisorAutoProxyCreator.cs b/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/DefaultAdvisorAutoProxyCreator.cs index 81e3ca4f..4078be15 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/DefaultAdvisorAutoProxyCreator.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/DefaultAdvisorAutoProxyCreator.cs @@ -24,116 +24,117 @@ using Spring.Objects.Factory; #endregion -namespace Spring.Aop.Framework.AutoProxy +namespace Spring.Aop.Framework.AutoProxy; + +/// +/// ObjectPostProcessor implementation that creates AOP proxies based on all candidate +/// Advisors in the current IObjectFactory. This class is completely generic; it contains +/// no special code to handle any particular aspects, such as pooling aspects. +/// +/// Rod Johnson +/// Adhari C Mahendra (.NET) +/// Erich Eichinger (.NET) +public class DefaultAdvisorAutoProxyCreator : AbstractAdvisorAutoProxyCreator, IObjectNameAware, IInitializingObject { /// - /// ObjectPostProcessor implementation that creates AOP proxies based on all candidate - /// Advisors in the current IObjectFactory. This class is completely generic; it contains - /// no special code to handle any particular aspects, such as pooling aspects. + /// Separator between prefix and remainder of object name /// - /// Rod Johnson - /// Adhari C Mahendra (.NET) - /// Erich Eichinger (.NET) - public class DefaultAdvisorAutoProxyCreator : AbstractAdvisorAutoProxyCreator, IObjectNameAware, IInitializingObject + public const string Separator = "."; + + private bool usePrefix; + private string advisorObjectNamePrefix; + private List cachedAdvisors; + + #region Properties + + /// + /// Gets or sets a value indicating whether to exclude + /// advisors with a certain prefix. + /// + /// true if [use prefix]; otherwise, false. + public bool UsePrefix { - /// - /// Separator between prefix and remainder of object name - /// - public const string Separator = "."; + get { return usePrefix; } + set { usePrefix = value; } + } - private bool usePrefix; - private string advisorObjectNamePrefix; - private List cachedAdvisors; + /// + /// Set the prefix for object names that will cause them to be included for + /// auto-proxying by this object. This prefix should be set to avoid circular + /// references. Default value is the object name of this object + a dot. + /// + /// The advisor object name prefix. + public string AdvisorObjectNamePrefix + { + get { return advisorObjectNamePrefix; } + set { advisorObjectNamePrefix = value; } + } - #region Properties + #endregion - /// - /// Gets or sets a value indicating whether to exclude - /// advisors with a certain prefix. - /// - /// true if [use prefix]; otherwise, false. - public bool UsePrefix + #region IObjectNameAware Members + + /// + /// Set the name of the object in the object factory that created this object. + /// + /// The name of the object in the factory. + /// + ///

+ /// Invoked after population of normal object properties but before an init + /// callback like 's + /// + /// method or a custom init-method. + ///

+ ///
+ public string ObjectName + { + set { - get { return usePrefix; } - set { usePrefix = value; } - } - - /// - /// Set the prefix for object names that will cause them to be included for - /// auto-proxying by this object. This prefix should be set to avoid circular - /// references. Default value is the object name of this object + a dot. - /// - /// The advisor object name prefix. - public string AdvisorObjectNamePrefix - { - get { return advisorObjectNamePrefix; } - set { advisorObjectNamePrefix = value; } - } - - #endregion - - #region IObjectNameAware Members - - /// - /// Set the name of the object in the object factory that created this object. - /// - /// The name of the object in the factory. - /// - ///

- /// Invoked after population of normal object properties but before an init - /// callback like 's - /// - /// method or a custom init-method. - ///

- ///
- public string ObjectName - { - set + // If no infrastructure object name prefix has been set, override it. + if (advisorObjectNamePrefix == null) { - // If no infrastructure object name prefix has been set, override it. - if (advisorObjectNamePrefix == null) - { - advisorObjectNamePrefix = value + Separator; - } + advisorObjectNamePrefix = value + Separator; } } - - #endregion - - /// - /// Find all possible advisor candidates to use in auto-proxying - /// - /// the type of the object to be advised - /// the name of the object to be advised - /// the list of candidate advisors - protected override List FindCandidateAdvisors(Type targetType, string targetName) - { - if (cachedAdvisors == null) { - cachedAdvisors = base.FindCandidateAdvisors(targetType, targetName); - } - return cachedAdvisors; - } - - /// - /// Whether the given advisor is eligible for the specified target. - /// - /// the advisor name - /// the target object's type - /// the target object's name - protected override bool IsEligibleAdvisorObject(string advisorName, Type targetType, string targetName) - { - return (!usePrefix || advisorName.StartsWith(advisorObjectNamePrefix)) - && base.IsEligibleAdvisorObject(advisorName, targetType, targetName); - } - - /// - /// Validate configuration - /// - public virtual void AfterPropertiesSet() - { - // eagerly resolve advisors at this stage already to prevent circular dep problems. - // TODO (EE): fix instantiation process to make test "AdvisorAutoProxyCreatorCircularReferencesTests" work. - cachedAdvisors = base.FindCandidateAdvisors(null, null); - } + } + + #endregion + + /// + /// Find all possible advisor candidates to use in auto-proxying + /// + /// the type of the object to be advised + /// the name of the object to be advised + /// the list of candidate advisors + protected override List FindCandidateAdvisors(Type targetType, string targetName) + { + if (cachedAdvisors == null) + { + cachedAdvisors = base.FindCandidateAdvisors(targetType, targetName); + } + + return cachedAdvisors; + } + + /// + /// Whether the given advisor is eligible for the specified target. + /// + /// the advisor name + /// the target object's type + /// the target object's name + protected override bool IsEligibleAdvisorObject(string advisorName, Type targetType, string targetName) + { + return (!usePrefix || advisorName.StartsWith(advisorObjectNamePrefix)) + && base.IsEligibleAdvisorObject(advisorName, targetType, targetName); + } + + /// + /// Validate configuration + /// + public virtual void AfterPropertiesSet() + { + // eagerly resolve advisors at this stage already to prevent circular dep problems. + // TODO (EE): fix instantiation process to make test "AdvisorAutoProxyCreatorCircularReferencesTests" work. + cachedAdvisors = base.FindCandidateAdvisors(null, null); } } diff --git a/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/IAdvisorRetrievalHelper.cs b/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/IAdvisorRetrievalHelper.cs index f97af4c6..3387c49d 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/IAdvisorRetrievalHelper.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/IAdvisorRetrievalHelper.cs @@ -1,15 +1,14 @@ -namespace Spring.Aop.Framework.AutoProxy +namespace Spring.Aop.Framework.AutoProxy; + +/// +/// Interface encapsulating the advisor retrieval strategy used by +/// an to retrieve the +/// applicable list of advisor objects. +/// +public interface IAdvisorRetrievalHelper { /// - /// Interface encapsulating the advisor retrieval strategy used by - /// an to retrieve the - /// applicable list of advisor objects. + /// Get the list of advisor objects to apply on the target. /// - public interface IAdvisorRetrievalHelper - { - /// - /// Get the list of advisor objects to apply on the target. - /// - List FindAdvisorObjects(Type targetType, string targetName); - } + List FindAdvisorObjects(Type targetType, string targetName); } diff --git a/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/ITargetSourceCreator.cs b/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/ITargetSourceCreator.cs index 79089a4a..51720bd6 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/ITargetSourceCreator.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/ITargetSourceCreator.cs @@ -24,28 +24,27 @@ using Spring.Objects.Factory; #endregion -namespace Spring.Aop.Framework.AutoProxy +namespace Spring.Aop.Framework.AutoProxy; + +/// +/// Implementations can create special target sources, such as pooling target +/// sources, for particular objects. For example, they may base their choice +/// on attributes, such as a pooling attribute, on the target type. +/// +///

AbstractAutoProxyCreator can support a number of TargetSourceCreators, +/// which will be applied in order.

+///
+/// Rod Johnson +/// Adhari C Mahendra (.NET) +public interface ITargetSourceCreator { /// - /// Implementations can create special target sources, such as pooling target - /// sources, for particular objects. For example, they may base their choice - /// on attributes, such as a pooling attribute, on the target type. + /// Create a special TargetSource for the given object, if any. /// - ///

AbstractAutoProxyCreator can support a number of TargetSourceCreators, - /// which will be applied in order.

- ///
- /// Rod Johnson - /// Adhari C Mahendra (.NET) - public interface ITargetSourceCreator - { - /// - /// Create a special TargetSource for the given object, if any. - /// - /// The type of the object to create a TargetSource for - /// the name of the object - /// the containing factory - /// a special TargetSource or null if this TargetSourceCreator isn't - /// interested in the particular object - ITargetSource GetTargetSource(Type objectType, string objectName, IObjectFactory factory); - } + /// The type of the object to create a TargetSource for + /// the name of the object + /// the containing factory + /// a special TargetSource or null if this TargetSourceCreator isn't + /// interested in the particular object + ITargetSource GetTargetSource(Type objectType, string objectName, IObjectFactory factory); } diff --git a/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/InfrastructureAdvisorAutoProxyCreator.cs b/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/InfrastructureAdvisorAutoProxyCreator.cs index ddfa2762..571f8052 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/InfrastructureAdvisorAutoProxyCreator.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/InfrastructureAdvisorAutoProxyCreator.cs @@ -20,41 +20,40 @@ using Spring.Objects.Factory.Config; -namespace Spring.Aop.Framework.AutoProxy +namespace Spring.Aop.Framework.AutoProxy; + +/// +/// A special version of an APC that explicitely cares for infrastructure (=internal) +/// advisors only +/// +/// Erich Eichinger +public class InfrastructureAdvisorAutoProxyCreator : AbstractAdvisorAutoProxyCreator { /// - /// A special version of an APC that explicitely cares for infrastructure (=internal) - /// advisors only + /// Overridden to create a special version of an + /// that accepts only infrastructure advisor definitions /// - /// Erich Eichinger - public class InfrastructureAdvisorAutoProxyCreator : AbstractAdvisorAutoProxyCreator + /// + /// + protected override IAdvisorRetrievalHelper CreateAdvisorRetrievalHelper(IConfigurableListableObjectFactory objectFactory) { - /// - /// Overridden to create a special version of an - /// that accepts only infrastructure advisor definitions - /// - /// - /// - protected override IAdvisorRetrievalHelper CreateAdvisorRetrievalHelper(IConfigurableListableObjectFactory objectFactory) + return new InfrastructurAdvisorRetrievalHelper(this, objectFactory); + } + + private class InfrastructurAdvisorRetrievalHelper : ObjectFactoryAdvisorRetrievalHelper + { + private readonly InfrastructureAdvisorAutoProxyCreator _owner; + + public InfrastructurAdvisorRetrievalHelper(InfrastructureAdvisorAutoProxyCreator owner, IConfigurableListableObjectFactory objectFactory) + : base(objectFactory) { - return new InfrastructurAdvisorRetrievalHelper(this, objectFactory); + _owner = owner; } - private class InfrastructurAdvisorRetrievalHelper : ObjectFactoryAdvisorRetrievalHelper + protected override bool IsEligibleObject(string advisorName, Type objectType, string objectName) { - private readonly InfrastructureAdvisorAutoProxyCreator _owner; - - public InfrastructurAdvisorRetrievalHelper(InfrastructureAdvisorAutoProxyCreator owner, IConfigurableListableObjectFactory objectFactory) - : base(objectFactory) - { - _owner = owner; - } - - protected override bool IsEligibleObject(string advisorName, Type objectType, string objectName) - { - return this.ObjectFactory.ContainsObjectDefinition(advisorName) - && this.ObjectFactory.GetObjectDefinition(advisorName).Role == ObjectRole.ROLE_INFRASTRUCTURE; - } + return this.ObjectFactory.ContainsObjectDefinition(advisorName) + && this.ObjectFactory.GetObjectDefinition(advisorName).Role == ObjectRole.ROLE_INFRASTRUCTURE; } } } diff --git a/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/InheritanceBasedAopConfigurer.cs b/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/InheritanceBasedAopConfigurer.cs index 260f4f25..bbd6a246 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/InheritanceBasedAopConfigurer.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/InheritanceBasedAopConfigurer.cs @@ -16,9 +16,7 @@ using System.Collections; using System.Runtime.Serialization; - using AopAlliance.Aop; - using Spring.Util; using Spring.Objects.Factory; using Spring.Objects.Factory.Config; @@ -27,310 +25,310 @@ using Spring.Aop.Framework.Adapter; using Spring.Aop.Framework.DynamicProxy; using Spring.Core; -namespace Spring.Aop.Framework.AutoProxy +namespace Spring.Aop.Framework.AutoProxy; + +/// +/// implementation that replaces a group of objects +/// with a 'true' inheritance based AOP mechanism that delegates +/// to the given interceptors before invoking the object itself. +/// +/// Bruno Baia +public class InheritanceBasedAopConfigurer : IObjectFactoryPostProcessor, IObjectFactoryAware, IOrdered { + private IList objectNames; + private string[] interceptorNames = new string[0]; + private bool proxyTargetAttributes = true; + private bool proxyDeclaredMembersOnly = true; + private bool proxyInterfaces = false; + + private IObjectFactory objectFactory; + private int order = int.MaxValue; + private IAdvisorAdapterRegistry advisorAdapterRegistry = GlobalAdvisorAdapterRegistry.Instance; + /// - /// implementation that replaces a group of objects - /// with a 'true' inheritance based AOP mechanism that delegates - /// to the given interceptors before invoking the object itself. + /// Set the names of the objects in IList fashioned way + /// that should automatically get intercepted. /// - /// Bruno Baia - public class InheritanceBasedAopConfigurer : IObjectFactoryPostProcessor, IObjectFactoryAware, IOrdered + /// + /// A name can specify a prefix to match by ending with "*", e.g. "myObject,tx*" + /// will match the object named "myObject" and all objects whose name start with "tx". + /// + public virtual IList ObjectNames { - private IList objectNames; - private string[] interceptorNames = new string[0]; - private bool proxyTargetAttributes = true; - private bool proxyDeclaredMembersOnly = true; - private bool proxyInterfaces = false; + set { objectNames = value; } + } - private IObjectFactory objectFactory; - private int order = int.MaxValue; - private IAdvisorAdapterRegistry advisorAdapterRegistry = GlobalAdvisorAdapterRegistry.Instance; + /// + /// Sets the common interceptors, a list of , + /// and introduction object names. + /// + /// + /// + /// If this property isn't set, there will be zero common interceptors. + /// This is perfectly valid, if "specific" interceptors such as + /// matching Advisors are all we want. + /// + /// + /// + /// The list of , + /// and introduction object names. + /// + /// + /// + public virtual string[] InterceptorNames + { + set { interceptorNames = value; } + } - /// - /// Set the names of the objects in IList fashioned way - /// that should automatically get intercepted. - /// - /// - /// A name can specify a prefix to match by ending with "*", e.g. "myObject,tx*" - /// will match the object named "myObject" and all objects whose name start with "tx". - /// - public virtual IList ObjectNames + /// + /// Is target type attributes, method attributes, method's return type attributes + /// and method's parameter attributes to be proxied in addition + /// to any interfaces declared on the proxied ? + /// + public virtual bool ProxyTargetAttributes + { + get { return this.proxyTargetAttributes; } + set { this.proxyTargetAttributes = value; } + } + + /// + /// Gets or sets a value indicating whether inherited members should be proxied. + /// + /// + /// if inherited members should be proxied; + /// otherwise, . + /// + public bool ProxyDeclaredMembersOnly + { + get { return proxyDeclaredMembersOnly; } + set { proxyDeclaredMembersOnly = value; } + } + + /// + /// Gets or sets a value indicating whether interfaces members should be proxied. + /// + /// + /// if interfaces members should be proxied; + /// otherwise, . + /// + public bool ProxyInterfaces + { + get { return proxyInterfaces; } + set { proxyInterfaces = value; } + } + + /// + /// Callback that supplies the owning factory to an object instance. + /// + /// + /// Owning + /// (may not be ). The object can immediately + /// call methods on the factory. + /// + /// + ///

+ /// Invoked after population of normal object properties but before an init + /// callback like 's + /// + /// method or a custom init-method. + ///

+ ///
+ /// + /// In case of initialization errors. + /// + public IObjectFactory ObjectFactory + { + set { objectFactory = value; } + } + + /// + /// Allows for custom modification of an application context's object definitions. + /// + /// + ///

+ /// If the object name matches, replaces the type by a AOP proxied type based on inheritance. + ///

+ ///
+ public void PostProcessObjectFactory(IConfigurableListableObjectFactory factory) + { + var objectDefinitionNames = factory.GetObjectDefinitionNames(); + for (int i = 0; i < objectDefinitionNames.Count; ++i) { - set { objectNames = value; } - } - - /// - /// Sets the common interceptors, a list of , - /// and introduction object names. - /// - /// - /// - /// If this property isn't set, there will be zero common interceptors. - /// This is perfectly valid, if "specific" interceptors such as - /// matching Advisors are all we want. - /// - /// - /// - /// The list of , - /// and introduction object names. - /// - /// - /// - public virtual string[] InterceptorNames - { - set { interceptorNames = value; } - } - - /// - /// Is target type attributes, method attributes, method's return type attributes - /// and method's parameter attributes to be proxied in addition - /// to any interfaces declared on the proxied ? - /// - public virtual bool ProxyTargetAttributes - { - get { return this.proxyTargetAttributes; } - set { this.proxyTargetAttributes = value; } - } - - /// - /// Gets or sets a value indicating whether inherited members should be proxied. - /// - /// - /// if inherited members should be proxied; - /// otherwise, . - /// - public bool ProxyDeclaredMembersOnly - { - get { return proxyDeclaredMembersOnly; } - set { proxyDeclaredMembersOnly = value; } - } - - /// - /// Gets or sets a value indicating whether interfaces members should be proxied. - /// - /// - /// if interfaces members should be proxied; - /// otherwise, . - /// - public bool ProxyInterfaces - { - get { return proxyInterfaces; } - set { proxyInterfaces = value; } - } - - /// - /// Callback that supplies the owning factory to an object instance. - /// - /// - /// Owning - /// (may not be ). The object can immediately - /// call methods on the factory. - /// - /// - ///

- /// Invoked after population of normal object properties but before an init - /// callback like 's - /// - /// method or a custom init-method. - ///

- ///
- /// - /// In case of initialization errors. - /// - public IObjectFactory ObjectFactory - { - set { objectFactory = value; } - } - - /// - /// Allows for custom modification of an application context's object definitions. - /// - /// - ///

- /// If the object name matches, replaces the type by a AOP proxied type based on inheritance. - ///

- ///
- public void PostProcessObjectFactory(IConfigurableListableObjectFactory factory) - { - var objectDefinitionNames = factory.GetObjectDefinitionNames(); - for (int i = 0; i < objectDefinitionNames.Count; ++i) + string name = objectDefinitionNames[i]; + if (IsObjectNameMatch(name)) { - string name = objectDefinitionNames[i]; - if (IsObjectNameMatch(name)) + var definition = factory.GetObjectDefinition(name) as IConfigurableObjectDefinition; + + if (definition == null || IsInfrastructureType(definition.ObjectType, name)) { - var definition = factory.GetObjectDefinition(name) as IConfigurableObjectDefinition; - - if (definition == null || IsInfrastructureType(definition.ObjectType, name)) - { - continue; - } - - ProxyFactory pf = CreateProxyFactory(definition.ObjectType, name); - - InheritanceAopProxyTypeBuilder iaptb = new InheritanceAopProxyTypeBuilder(pf); - iaptb.ProxyDeclaredMembersOnly = this.ProxyDeclaredMembersOnly; - Type type = iaptb.BuildProxyType(); - - definition.ObjectType = type; - definition.ConstructorArgumentValues.AddIndexedArgumentValue(definition.ConstructorArgumentValues.ArgumentCount, pf); + continue; } - } - } - /// - /// Return the order value of this object, where a higher value means greater in - /// terms of sorting. - /// - /// - /// Ordering which will apply to this class's implementation - /// of Ordered, used when applying multiple ObjectPostProcessors. - /// Default value is int.MaxValue, meaning that it's non-ordered. - /// - /// The order value. - public virtual int Order - { - get { return order; } - set { order = value; } - } + ProxyFactory pf = CreateProxyFactory(definition.ObjectType, name); - /// - /// Determines whether the object is an infrastructure type, - /// IAdvisor, IAdvice, IAdvisors, AbstractAutoProxyCreator or InheritanceBasedAopConfigurer. - /// - /// The object type to compare - /// The name of the object - /// - /// true if [is infrastructure type] [the specified obj]; otherwise, false. - /// - protected virtual bool IsInfrastructureType(Type type, String name) - { - return typeof(IAdvisor).IsAssignableFrom(type) - || typeof(IAdvice).IsAssignableFrom(type) - || typeof(IAdvisors).IsAssignableFrom(type) - || typeof(AbstractAutoProxyCreator).IsAssignableFrom(type) - || typeof(InheritanceBasedAopConfigurer).IsAssignableFrom(type); - } + InheritanceAopProxyTypeBuilder iaptb = new InheritanceAopProxyTypeBuilder(pf); + iaptb.ProxyDeclaredMembersOnly = this.ProxyDeclaredMembersOnly; + Type type = iaptb.BuildProxyType(); - /// - /// Create an AOP proxy for the given object. - /// - /// Type of the object. - /// The name of the object. - /// The AOP Proxy for the object. - protected virtual ProxyFactory CreateProxyFactory(Type objectType, string objectName) - { - ProxyFactory proxyFactory = new ProxyFactory(); - proxyFactory.ProxyTargetAttributes = this.ProxyTargetAttributes; - proxyFactory.TargetSource = new InheritanceBasedAopTargetSource(objectType); - if (!ProxyInterfaces) - { - proxyFactory.Interfaces = Type.EmptyTypes; - } - - IList advisors = ResolveInterceptorNames(); - foreach (IAdvisor advisor in advisors) - { - if (advisor is IIntroductionAdvisor) - { - proxyFactory.AddIntroduction((IIntroductionAdvisor)advisor); - } - else - { - proxyFactory.AddAdvisor(advisor); - } - } - - return proxyFactory; - } - - /// - /// Return if the given object name matches one of the object names specified. - /// - /// - ///

- /// The default implementation checks for "xxx*", "*xxx" and "*xxx*" matches, - /// as well as direct equality. Can be overridden in subclasses. - ///

- ///
- /// the object name to check - /// if the names match - protected virtual bool IsObjectNameMatch(string objectName) - { - if (objectNames != null) - { - for (int i = 0; i < objectNames.Count; i++) - { - string mappedName = String.Copy((string)objectNames[i]); - if (PatternMatchUtils.SimpleMatch(mappedName, objectName)) - { - return true; - } - } - } - return false; - } - - private IList ResolveInterceptorNames() - { - List advisors = new List(); - foreach (string name in interceptorNames) - { - object next = objectFactory.GetObject(name); - if (next is IAdvisors) - { - advisors.AddRange(((IAdvisors)next).Advisors); - } - else - { - advisors.Add(advisorAdapterRegistry.Wrap(next)); - } - } - return advisors; - } - - [Serializable] - private class InheritanceBasedAopTargetSource : ITargetSource, ISerializable - { - private readonly Type _targetType; - - public InheritanceBasedAopTargetSource(Type targetType) - { - _targetType = targetType; - } - - - /// - private InheritanceBasedAopTargetSource(SerializationInfo info, StreamingContext context) - { - var type = info.GetString("TargetType"); - _targetType = type != null ? Type.GetType(type) : null; - } - - /// - public void GetObjectData(SerializationInfo info, StreamingContext context) - { - info.AddValue("TargetType", _targetType?.AssemblyQualifiedName); - } - - public object GetTarget() - { - return null; - } - - public bool IsStatic - { - get { return true; } - } - - public void ReleaseTarget(object target) - { - } - - public Type TargetType - { - get { return _targetType; } + definition.ObjectType = type; + definition.ConstructorArgumentValues.AddIndexedArgumentValue(definition.ConstructorArgumentValues.ArgumentCount, pf); } } } + + /// + /// Return the order value of this object, where a higher value means greater in + /// terms of sorting. + /// + /// + /// Ordering which will apply to this class's implementation + /// of Ordered, used when applying multiple ObjectPostProcessors. + /// Default value is int.MaxValue, meaning that it's non-ordered. + /// + /// The order value. + public virtual int Order + { + get { return order; } + set { order = value; } + } + + /// + /// Determines whether the object is an infrastructure type, + /// IAdvisor, IAdvice, IAdvisors, AbstractAutoProxyCreator or InheritanceBasedAopConfigurer. + /// + /// The object type to compare + /// The name of the object + /// + /// true if [is infrastructure type] [the specified obj]; otherwise, false. + /// + protected virtual bool IsInfrastructureType(Type type, String name) + { + return typeof(IAdvisor).IsAssignableFrom(type) + || typeof(IAdvice).IsAssignableFrom(type) + || typeof(IAdvisors).IsAssignableFrom(type) + || typeof(AbstractAutoProxyCreator).IsAssignableFrom(type) + || typeof(InheritanceBasedAopConfigurer).IsAssignableFrom(type); + } + + /// + /// Create an AOP proxy for the given object. + /// + /// Type of the object. + /// The name of the object. + /// The AOP Proxy for the object. + protected virtual ProxyFactory CreateProxyFactory(Type objectType, string objectName) + { + ProxyFactory proxyFactory = new ProxyFactory(); + proxyFactory.ProxyTargetAttributes = this.ProxyTargetAttributes; + proxyFactory.TargetSource = new InheritanceBasedAopTargetSource(objectType); + if (!ProxyInterfaces) + { + proxyFactory.Interfaces = Type.EmptyTypes; + } + + IList advisors = ResolveInterceptorNames(); + foreach (IAdvisor advisor in advisors) + { + if (advisor is IIntroductionAdvisor) + { + proxyFactory.AddIntroduction((IIntroductionAdvisor) advisor); + } + else + { + proxyFactory.AddAdvisor(advisor); + } + } + + return proxyFactory; + } + + /// + /// Return if the given object name matches one of the object names specified. + /// + /// + ///

+ /// The default implementation checks for "xxx*", "*xxx" and "*xxx*" matches, + /// as well as direct equality. Can be overridden in subclasses. + ///

+ ///
+ /// the object name to check + /// if the names match + protected virtual bool IsObjectNameMatch(string objectName) + { + if (objectNames != null) + { + for (int i = 0; i < objectNames.Count; i++) + { + string mappedName = String.Copy((string) objectNames[i]); + if (PatternMatchUtils.SimpleMatch(mappedName, objectName)) + { + return true; + } + } + } + + return false; + } + + private IList ResolveInterceptorNames() + { + List advisors = new List(); + foreach (string name in interceptorNames) + { + object next = objectFactory.GetObject(name); + if (next is IAdvisors) + { + advisors.AddRange(((IAdvisors) next).Advisors); + } + else + { + advisors.Add(advisorAdapterRegistry.Wrap(next)); + } + } + + return advisors; + } + + [Serializable] + private class InheritanceBasedAopTargetSource : ITargetSource, ISerializable + { + private readonly Type _targetType; + + public InheritanceBasedAopTargetSource(Type targetType) + { + _targetType = targetType; + } + + /// + private InheritanceBasedAopTargetSource(SerializationInfo info, StreamingContext context) + { + var type = info.GetString("TargetType"); + _targetType = type != null ? Type.GetType(type) : null; + } + + /// + public void GetObjectData(SerializationInfo info, StreamingContext context) + { + info.AddValue("TargetType", _targetType?.AssemblyQualifiedName); + } + + public object GetTarget() + { + return null; + } + + public bool IsStatic + { + get { return true; } + } + + public void ReleaseTarget(object target) + { + } + + public Type TargetType + { + get { return _targetType; } + } + } } diff --git a/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/ObjectFactoryAdvisorRetrievalHelper.cs b/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/ObjectFactoryAdvisorRetrievalHelper.cs index 516e2a58..5f5853a9 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/ObjectFactoryAdvisorRetrievalHelper.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/ObjectFactoryAdvisorRetrievalHelper.cs @@ -23,152 +23,155 @@ using Spring.Objects.Factory; using Spring.Objects.Factory.Config; using Spring.Util; -namespace Spring.Aop.Framework.AutoProxy +namespace Spring.Aop.Framework.AutoProxy; + +/// +/// Helper for retrieving standard Spring advisors from an for +/// use with auto-proxying. +/// +/// Erich Eichinger +public class ObjectFactoryAdvisorRetrievalHelper : IAdvisorRetrievalHelper { + private readonly ILogger _log; + private readonly IConfigurableListableObjectFactory _objectFactory; + private List _cachedObjectNames; + /// - /// Helper for retrieving standard Spring advisors from an for - /// use with auto-proxying. + /// The object factory to lookup advisors from /// - /// Erich Eichinger - public class ObjectFactoryAdvisorRetrievalHelper : IAdvisorRetrievalHelper + public IConfigurableListableObjectFactory ObjectFactory { - private readonly ILogger _log; - private readonly IConfigurableListableObjectFactory _objectFactory; - private List _cachedObjectNames; + get { return _objectFactory; } + } - /// - /// The object factory to lookup advisors from - /// - public IConfigurableListableObjectFactory ObjectFactory + /// + /// Create a new helper for the specified . + /// + public ObjectFactoryAdvisorRetrievalHelper(IConfigurableListableObjectFactory objectFactory) + { + AssertUtils.ArgumentNotNull(objectFactory, "objectFactory"); + _log = LogManager.GetLogger(this.GetType()); + _objectFactory = objectFactory; + } + + /// + /// Find all all eligible advisor objects in the current object factory. + /// + /// the type of the object to be advised + /// the name of the object to be advised + /// A list of eligible instances + public virtual List FindAdvisorObjects(Type targetType, string targetName) + { + IList advisorNames = GetAdvisorCandidateNames(targetType, targetName); + + List advisors = new List(); + + if (advisorNames.Count == 0) { - get { return _objectFactory; } - } - - /// - /// Create a new helper for the specified . - /// - public ObjectFactoryAdvisorRetrievalHelper(IConfigurableListableObjectFactory objectFactory ) - { - AssertUtils.ArgumentNotNull(objectFactory, "objectFactory"); - _log = LogManager.GetLogger(this.GetType()); - _objectFactory = objectFactory; - } - - /// - /// Find all all eligible advisor objects in the current object factory. - /// - /// the type of the object to be advised - /// the name of the object to be advised - /// A list of eligible instances - public virtual List FindAdvisorObjects(Type targetType, string targetName) - { - IList advisorNames = GetAdvisorCandidateNames(targetType, targetName); - - List advisors = new List(); - - if (advisorNames.Count == 0) - { - return advisors; - } - - for (int i = 0; i < advisorNames.Count; i++) - { - string name = advisorNames[i]; - if (IsEligibleObject(name, targetType, targetName) && !_objectFactory.IsCurrentlyInCreation(name)) - { - try - { - AddAdvisorCandidate(advisors, name); - } - catch (ObjectCreationException ex) - { - Exception rootEx = ex.GetBaseException(); - if (rootEx is ObjectCurrentlyInCreationException) - { - ObjectCurrentlyInCreationException oce = (ObjectCurrentlyInCreationException)rootEx; - if (_objectFactory.IsCurrentlyInCreation(oce.ObjectName)) - { - if (_log.IsEnabled(LogLevel.Debug)) - { - _log.LogDebug(string.Format("Ignoring currently created advisor '{0}': exception message = {1}", - name, ex.Message)); - } - continue; - } - } - throw; - } - } - } - return advisors; } - /// - /// Add the named advisor instance to the list of advisors. - /// - /// the advisor list - /// the object name of the advisor to add - private void AddAdvisorCandidate(List advisors, string advisorName) + for (int i = 0; i < advisorNames.Count; i++) { - object advisorCandidate = _objectFactory.GetObject(advisorName); - if (advisorCandidate is IAdvisor) + string name = advisorNames[i]; + if (IsEligibleObject(name, targetType, targetName) && !_objectFactory.IsCurrentlyInCreation(name)) { - advisors.Add((IAdvisor) advisorCandidate); - } - else if (advisorCandidate is IAdvisors) - { - advisors.AddRange(((IAdvisors)advisorCandidate).Advisors); - } - else - { - throw new InvalidOperationException("expected type IAdvisor or IAdvisors but was " + - advisorCandidate.GetType().FullName); - } - } - - /// - /// Gets the names of advisor candidates - /// - /// the type of the object to be advised - /// the name of the object to be advised - /// a non-null string array of advisor candidate names - protected virtual IList GetAdvisorCandidateNames(Type targetType, string targetName) - { - if (_cachedObjectNames == null) - { - lock(this) + try { - if (_cachedObjectNames == null) + AddAdvisorCandidate(advisors, name); + } + catch (ObjectCreationException ex) + { + Exception rootEx = ex.GetBaseException(); + if (rootEx is ObjectCurrentlyInCreationException) { - List candidateNameList = new List(); - IList advisorCandidateNames = ObjectFactoryUtils.ObjectNamesForTypeIncludingAncestors( _objectFactory, typeof(IAdvisor), true, false); - candidateNameList.AddRange(advisorCandidateNames); - IList advisorsCandidateNames = ObjectFactoryUtils.ObjectNamesForTypeIncludingAncestors(_objectFactory, typeof(IAdvisors), true, false); - candidateNameList.AddRange(advisorsCandidateNames); - _cachedObjectNames = candidateNameList; + ObjectCurrentlyInCreationException oce = (ObjectCurrentlyInCreationException) rootEx; + if (_objectFactory.IsCurrentlyInCreation(oce.ObjectName)) + { + if (_log.IsEnabled(LogLevel.Debug)) + { + _log.LogDebug(string.Format("Ignoring currently created advisor '{0}': exception message = {1}", + name, ex.Message)); + } + + continue; + } } + + throw; } } - return _cachedObjectNames; } - /// - /// Determine, whether the specified aspect object is eligible. - /// The default implementation accepts all except for advisors that are - /// part of the internal infrastructure. - /// - /// the name of the candidate advisor - /// the type of the object to be advised - /// the name of the object to be advised - protected virtual bool IsEligibleObject(string advisorName, Type objectType, string objectName ) + return advisors; + } + + /// + /// Add the named advisor instance to the list of advisors. + /// + /// the advisor list + /// the object name of the advisor to add + private void AddAdvisorCandidate(List advisors, string advisorName) + { + object advisorCandidate = _objectFactory.GetObject(advisorName); + if (advisorCandidate is IAdvisor) { - bool containsObjectDefinition = this.ObjectFactory.ContainsObjectDefinition(advisorName); - if (containsObjectDefinition) + advisors.Add((IAdvisor) advisorCandidate); + } + else if (advisorCandidate is IAdvisors) + { + advisors.AddRange(((IAdvisors) advisorCandidate).Advisors); + } + else + { + throw new InvalidOperationException("expected type IAdvisor or IAdvisors but was " + + advisorCandidate.GetType().FullName); + } + } + + /// + /// Gets the names of advisor candidates + /// + /// the type of the object to be advised + /// the name of the object to be advised + /// a non-null string array of advisor candidate names + protected virtual IList GetAdvisorCandidateNames(Type targetType, string targetName) + { + if (_cachedObjectNames == null) + { + lock (this) { - return this.ObjectFactory.GetObjectDefinition(advisorName).Role != ObjectRole.ROLE_INFRASTRUCTURE; + if (_cachedObjectNames == null) + { + List candidateNameList = new List(); + IList advisorCandidateNames = ObjectFactoryUtils.ObjectNamesForTypeIncludingAncestors(_objectFactory, typeof(IAdvisor), true, false); + candidateNameList.AddRange(advisorCandidateNames); + IList advisorsCandidateNames = ObjectFactoryUtils.ObjectNamesForTypeIncludingAncestors(_objectFactory, typeof(IAdvisors), true, false); + candidateNameList.AddRange(advisorsCandidateNames); + _cachedObjectNames = candidateNameList; + } } - return this.ObjectFactory.ContainsObject(advisorName); - } + } + + return _cachedObjectNames; + } + + /// + /// Determine, whether the specified aspect object is eligible. + /// The default implementation accepts all except for advisors that are + /// part of the internal infrastructure. + /// + /// the name of the candidate advisor + /// the type of the object to be advised + /// the name of the object to be advised + protected virtual bool IsEligibleObject(string advisorName, Type objectType, string objectName) + { + bool containsObjectDefinition = this.ObjectFactory.ContainsObjectDefinition(advisorName); + if (containsObjectDefinition) + { + return this.ObjectFactory.GetObjectDefinition(advisorName).Role != ObjectRole.ROLE_INFRASTRUCTURE; + } + + return this.ObjectFactory.ContainsObject(advisorName); } } diff --git a/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/ObjectNameAutoProxyCreator.cs b/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/ObjectNameAutoProxyCreator.cs index 6cf4e4bd..6eb0fac2 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/ObjectNameAutoProxyCreator.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/ObjectNameAutoProxyCreator.cs @@ -22,114 +22,117 @@ using System.Collections; using Spring.Objects.Factory; using Spring.Util; -namespace Spring.Aop.Framework.AutoProxy +namespace Spring.Aop.Framework.AutoProxy; + +/// +/// AutoProxyCreator that identifies objects to proxy via a list of names. +/// +/// +/// +/// Auto proxy creator that identifies objects to proxy via a list of names. +/// Checks for direct, "xxx*", "*xxx" and "*xxx*" matches. +/// +/// In case of a IFactoryObject, only the objects created by the +/// FactoryBean will get proxied. If you intend to proxy a IFactoryObject instance itself +/// specify the object name of the IFactoryObject including +/// the factory-object prefix "&" e.g. "&MyFactoryObject". +/// +/// +/// +/// Juergen Hoeller +/// Adhari C Mahendra (.NET) +/// Erich Eichinger +public class ObjectNameAutoProxyCreator : AbstractFilteringAutoProxyCreator { + private IList objectNames; + /// - /// AutoProxyCreator that identifies objects to proxy via a list of names. + /// Initializes a new instance of . /// - /// - /// - /// Auto proxy creator that identifies objects to proxy via a list of names. - /// Checks for direct, "xxx*", "*xxx" and "*xxx*" matches. - /// - /// In case of a IFactoryObject, only the objects created by the - /// FactoryBean will get proxied. If you intend to proxy a IFactoryObject instance itself - /// specify the object name of the IFactoryObject including - /// the factory-object prefix "&" e.g. "&MyFactoryObject". - /// - /// - /// - /// Juergen Hoeller - /// Adhari C Mahendra (.NET) - /// Erich Eichinger - public class ObjectNameAutoProxyCreator : AbstractFilteringAutoProxyCreator + public ObjectNameAutoProxyCreator() { - private IList objectNames; + } - /// - /// Initializes a new instance of . - /// - public ObjectNameAutoProxyCreator() - {} - - /// - /// Set the names of the objects in IList fashioned way that should automatically - /// get wrapped with proxies. - /// A name can specify a prefix to match by ending with "*", e.g. "myObject,tx*" - /// will match the object named "myObject" and all objects whose name start with "tx". - /// - public IList ObjectNames + /// + /// Set the names of the objects in IList fashioned way that should automatically + /// get wrapped with proxies. + /// A name can specify a prefix to match by ending with "*", e.g. "myObject,tx*" + /// will match the object named "myObject" and all objects whose name start with "tx". + /// + public IList ObjectNames + { + set { - set - { - AssertUtils.ArgumentHasElements(value, "ObjectNames"); - objectNames = value; - } - get - { - return objectNames; - } + AssertUtils.ArgumentHasElements(value, "ObjectNames"); + objectNames = value; } - - /// - /// Identify as object to proxy if the object name is in the configured list of names. - /// - protected override bool IsEligibleForProxying( Type targetType, string targetName ) + get { - bool shallProxy = IsObjectNameMatch(targetType, targetName, this.ObjectNames); - return shallProxy; - } - - /// - /// Return if the given object name matches the mapped name. - /// - /// - ///

- /// The default implementation checks for "xxx*", "*xxx" and "*xxx*" matches, - /// as well as direct equality. Can be overridden in subclasses. - ///

- ///
- /// the object name to check - /// the name in the configured list of names - /// if the names match - protected virtual bool IsMatch( string objectName, string mappedName ) - { - return PatternMatchUtils.SimpleMatch( mappedName, objectName ); - } - - /// - /// Convenience method that may be used by derived classes. Iterates over the list of to match against. - /// - /// the object's type. Must not be null. - /// the name of the object Must not be null. - /// the list of patterns, that shall be matched against. Must not be null. - /// - /// If is null, will always return true, otherwise - /// if matches any of the patterns specified in . - /// - protected bool IsObjectNameMatch(Type objType, string objectName, IList objectNamePatterns) - { - AssertUtils.ArgumentNotNull(objType, "objType"); - AssertUtils.ArgumentNotNull(objectName, "objectName" ); - AssertUtils.ArgumentNotNull(objectNamePatterns, "objectNamePatterns"); - - for (int i = 0; i < objectNamePatterns.Count; i++) - { - string mappedName = (string)objectNamePatterns[i]; - if (typeof(IFactoryObject).IsAssignableFrom(objType)) - { - if (!objectName.StartsWith(ObjectFactoryUtils.FactoryObjectPrefix)) - { - continue; - } - mappedName = mappedName.Substring(ObjectFactoryUtils.FactoryObjectPrefix.Length); - } - if (IsMatch(objectName, mappedName)) - { - return true; - } - } - return false; + return objectNames; } } + + /// + /// Identify as object to proxy if the object name is in the configured list of names. + /// + protected override bool IsEligibleForProxying(Type targetType, string targetName) + { + bool shallProxy = IsObjectNameMatch(targetType, targetName, this.ObjectNames); + return shallProxy; + } + + /// + /// Return if the given object name matches the mapped name. + /// + /// + ///

+ /// The default implementation checks for "xxx*", "*xxx" and "*xxx*" matches, + /// as well as direct equality. Can be overridden in subclasses. + ///

+ ///
+ /// the object name to check + /// the name in the configured list of names + /// if the names match + protected virtual bool IsMatch(string objectName, string mappedName) + { + return PatternMatchUtils.SimpleMatch(mappedName, objectName); + } + + /// + /// Convenience method that may be used by derived classes. Iterates over the list of to match against. + /// + /// the object's type. Must not be null. + /// the name of the object Must not be null. + /// the list of patterns, that shall be matched against. Must not be null. + /// + /// If is null, will always return true, otherwise + /// if matches any of the patterns specified in . + /// + protected bool IsObjectNameMatch(Type objType, string objectName, IList objectNamePatterns) + { + AssertUtils.ArgumentNotNull(objType, "objType"); + AssertUtils.ArgumentNotNull(objectName, "objectName"); + AssertUtils.ArgumentNotNull(objectNamePatterns, "objectNamePatterns"); + + for (int i = 0; i < objectNamePatterns.Count; i++) + { + string mappedName = (string) objectNamePatterns[i]; + if (typeof(IFactoryObject).IsAssignableFrom(objType)) + { + if (!objectName.StartsWith(ObjectFactoryUtils.FactoryObjectPrefix)) + { + continue; + } + + mappedName = mappedName.Substring(ObjectFactoryUtils.FactoryObjectPrefix.Length); + } + + if (IsMatch(objectName, mappedName)) + { + return true; + } + } + + return false; + } } diff --git a/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/PointcutFilteringAutoProxyCreator.cs b/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/PointcutFilteringAutoProxyCreator.cs index 5cb949a7..00e534eb 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/PointcutFilteringAutoProxyCreator.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/PointcutFilteringAutoProxyCreator.cs @@ -24,34 +24,33 @@ using Spring.Util; #endregion -namespace Spring.Aop.Framework.AutoProxy +namespace Spring.Aop.Framework.AutoProxy; + +/// +/// This AutoProxyCreator only proxies objects matching the specified . +/// +/// Erich Eichinger +public class PointcutFilteringAutoProxyCreator : AbstractFilteringAutoProxyCreator { + private IPointcut _pointcut; + /// - /// This AutoProxyCreator only proxies objects matching the specified . + /// Set the pointcut used to filter objects that should automatically get wrapped with proxies. /// - /// Erich Eichinger - public class PointcutFilteringAutoProxyCreator : AbstractFilteringAutoProxyCreator + public IPointcut Pointcut { - private IPointcut _pointcut; + set { _pointcut = value; } + get { return _pointcut; } + } - /// - /// Set the pointcut used to filter objects that should automatically get wrapped with proxies. - /// - public IPointcut Pointcut - { - set { _pointcut = value; } - get { return _pointcut; } - } + /// + /// Determines, whether the given object shall be proxied. + /// + protected override bool IsEligibleForProxying(Type targetType, string targetName) + { + AssertUtils.ArgumentNotNull(_pointcut, "Pointcut"); - /// - /// Determines, whether the given object shall be proxied. - /// - protected override bool IsEligibleForProxying( Type targetType, string targetName ) - { - AssertUtils.ArgumentNotNull(_pointcut, "Pointcut"); - - bool shallProxy = AopUtils.CanApply( _pointcut, targetType, null ); - return shallProxy; - } + bool shallProxy = AopUtils.CanApply(_pointcut, targetType, null); + return shallProxy; } } diff --git a/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/Target/AbstractPrototypeTargetSourceCreator.cs b/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/Target/AbstractPrototypeTargetSourceCreator.cs index 7ac1fe80..f01e05b9 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/Target/AbstractPrototypeTargetSourceCreator.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/Target/AbstractPrototypeTargetSourceCreator.cs @@ -27,80 +27,79 @@ using Spring.Objects.Factory.Support; #endregion -namespace Spring.Aop.Framework.AutoProxy.Target +namespace Spring.Aop.Framework.AutoProxy.Target; + +/// +/// Summary description for AbstractPrototypeBasedTargetSourceCreator. +/// +public abstract class AbstractPrototypeTargetSourceCreator : ITargetSourceCreator { /// - /// Summary description for AbstractPrototypeBasedTargetSourceCreator. + /// The logger /// - public abstract class AbstractPrototypeTargetSourceCreator : ITargetSourceCreator + protected readonly ILogger logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + + #region ITargetSourceCreator Members + + /// + /// Create a special TargetSource for the given object, if any. + /// + /// the type of the object to create a TargetSource for + /// the name of the object + /// the containing factory + /// + /// a special TargetSource or null if this TargetSourceCreator isn't + /// interested in the particular object + /// + public ITargetSource GetTargetSource(Type objectType, string name, IObjectFactory factory) { - /// - /// The logger - /// - protected readonly ILogger logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); - - #region ITargetSourceCreator Members - - /// - /// Create a special TargetSource for the given object, if any. - /// - /// the type of the object to create a TargetSource for - /// the name of the object - /// the containing factory - /// - /// a special TargetSource or null if this TargetSourceCreator isn't - /// interested in the particular object - /// - public ITargetSource GetTargetSource(Type objectType, string name, IObjectFactory factory) + AbstractPrototypeTargetSource prototypeTargetSource = CreatePrototypeTargetSource(objectType, name, factory); + if (prototypeTargetSource == null) { - AbstractPrototypeTargetSource prototypeTargetSource = CreatePrototypeTargetSource(objectType, name, factory); - if (prototypeTargetSource == null) + return null; + } + else + { + if (!(factory is IObjectDefinitionRegistry)) { + if (logger.IsEnabled(LogLevel.Warning)) + logger.LogWarning("Cannot do autopooling with a IObjectFactory that doesn't implement IObjectDefinitionRegistry"); return null; } - else - { - if (!(factory is IObjectDefinitionRegistry)) - { - if (logger.IsEnabled(LogLevel.Warning)) - logger.LogWarning("Cannot do autopooling with a IObjectFactory that doesn't implement IObjectDefinitionRegistry"); - return null; - } - IObjectDefinitionRegistry definitionRegistry = (IObjectDefinitionRegistry) factory; - RootObjectDefinition definition = (RootObjectDefinition) definitionRegistry.GetObjectDefinition(name); - if (logger.IsEnabled(LogLevel.Information)) - logger.LogInformation("Configuring AbstractPrototypeBasedTargetSource..."); + IObjectDefinitionRegistry definitionRegistry = (IObjectDefinitionRegistry) factory; + RootObjectDefinition definition = (RootObjectDefinition) definitionRegistry.GetObjectDefinition(name); - // Infinite cycle will result if we don't use a different factory, - // because a GetObject() call with this objectName will go through the autoproxy - // infrastructure again. - // We to override just this object definition, as it may reference other objects - // and we're happy to take the parent's definition for those. - DefaultListableObjectFactory objectFactory = new DefaultListableObjectFactory(factory); + if (logger.IsEnabled(LogLevel.Information)) + logger.LogInformation("Configuring AbstractPrototypeBasedTargetSource..."); - // Override the prototype object - objectFactory.RegisterObjectDefinition(name, definition); + // Infinite cycle will result if we don't use a different factory, + // because a GetObject() call with this objectName will go through the autoproxy + // infrastructure again. + // We to override just this object definition, as it may reference other objects + // and we're happy to take the parent's definition for those. + DefaultListableObjectFactory objectFactory = new DefaultListableObjectFactory(factory); - // Complete configuring the PrototypeTargetSource - prototypeTargetSource.TargetObjectName = name; - prototypeTargetSource.ObjectFactory = objectFactory; + // Override the prototype object + objectFactory.RegisterObjectDefinition(name, definition); - return prototypeTargetSource; - } + // Complete configuring the PrototypeTargetSource + prototypeTargetSource.TargetObjectName = name; + prototypeTargetSource.ObjectFactory = objectFactory; + + return prototypeTargetSource; } - - #endregion - - /// - /// Creates the prototype target source. - /// - /// The type of the object to create a target source for. - /// The name. - /// The factory. - /// - protected abstract AbstractPrototypeTargetSource CreatePrototypeTargetSource(Type objectType, string name, - IObjectFactory factory); - } + + #endregion + + /// + /// Creates the prototype target source. + /// + /// The type of the object to create a target source for. + /// The name. + /// The factory. + /// + protected abstract AbstractPrototypeTargetSource CreatePrototypeTargetSource(Type objectType, string name, + IObjectFactory factory); } diff --git a/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/TypeNameAutoProxyCreator.cs b/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/TypeNameAutoProxyCreator.cs index 0a5e2420..3c4354eb 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/TypeNameAutoProxyCreator.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/TypeNameAutoProxyCreator.cs @@ -25,52 +25,52 @@ using Spring.Util; #endregion -namespace Spring.Aop.Framework.AutoProxy +namespace Spring.Aop.Framework.AutoProxy; + +/// +/// AutoProxyCreator, that identifies objects to proxy by matching their against a list of patterns. +/// +/// Erich Eichinger +public class TypeNameAutoProxyCreator : AbstractFilteringAutoProxyCreator { - /// - /// AutoProxyCreator, that identifies objects to proxy by matching their against a list of patterns. - /// - /// Erich Eichinger - public class TypeNameAutoProxyCreator : AbstractFilteringAutoProxyCreator + private TypeNameTypeFilter _typeNameFilter = null; + + /// + /// The list of patterns to match against. For pattern syntax, see + /// + public string[] TypeNames { - private TypeNameTypeFilter _typeNameFilter = null; - - /// - /// The list of patterns to match against. For pattern syntax, see - /// - public string[] TypeNames + get { - get + if (_typeNameFilter != null) { - if (_typeNameFilter != null) - { - return _typeNameFilter.TypeNamePatterns; - } - return null; - } - set - { - AssertUtils.ArgumentNotNull(value, "TypeNames"); - _typeNameFilter = new TypeNameTypeFilter(value); + return _typeNameFilter.TypeNamePatterns; } + + return null; } - - /// - /// Decide, whether the given object is eligible for proxying. - /// - /// - /// Override this method to allow or reject proxying for the given object. - /// - /// the object's type - /// the name of the object - /// - /// whether the given object shall be proxied. - protected override bool IsEligibleForProxying(Type targetType, string targetName) + set { - AssertUtils.ArgumentNotNull(_typeNameFilter, "TypeNames"); - - bool shallProxy = _typeNameFilter.Matches(targetType); - return shallProxy; + AssertUtils.ArgumentNotNull(value, "TypeNames"); + _typeNameFilter = new TypeNameTypeFilter(value); } } + + /// + /// Decide, whether the given object is eligible for proxying. + /// + /// + /// Override this method to allow or reject proxying for the given object. + /// + /// the object's type + /// the name of the object + /// + /// whether the given object shall be proxied. + protected override bool IsEligibleForProxying(Type targetType, string targetName) + { + AssertUtils.ArgumentNotNull(_typeNameFilter, "TypeNames"); + + bool shallProxy = _typeNameFilter.Matches(targetType); + return shallProxy; + } } diff --git a/src/Spring/Spring.Aop/Aop/Framework/DynamicMethodInvocation.cs b/src/Spring/Spring.Aop/Aop/Framework/DynamicMethodInvocation.cs index 69d5a140..f57d177a 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/DynamicMethodInvocation.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/DynamicMethodInvocation.cs @@ -22,115 +22,113 @@ using System.Collections; using System.Reflection; - using Spring.Util; using Spring.Reflection.Dynamic; using AopAlliance.Intercept; #endregion -namespace Spring.Aop.Framework +namespace Spring.Aop.Framework; + +/// +/// Invokes a target method using dynamic reflection. +/// +/// +/// Aleksandar Seovic +/// Bruno Baia +[Serializable] +public class DynamicMethodInvocation : AbstractMethodInvocation { /// - /// Invokes a target method using dynamic reflection. + /// The method invocation that is to be invoked on the proxy. /// - /// - /// Aleksandar Seovic - /// Bruno Baia - [Serializable] - public class DynamicMethodInvocation : AbstractMethodInvocation + private MethodInfo proxyMethod; + + /// + /// Creates a new instance of the + /// class. + /// + /// The AOP proxy. + /// The target object. + /// The target method proxied. + /// The method to invoke on proxy. + /// The target method's arguments. + /// + /// The of the target object. + /// + /// The list of interceptors that are to be applied. May be + /// . + /// + /// + /// If any of the or + /// parameters is . + /// + public DynamicMethodInvocation( + object proxy, object target, MethodInfo method, MethodInfo proxyMethod, + object[] arguments, Type targetType, IList interceptors) + : base(proxy, target, method, arguments, targetType, interceptors) { - /// - /// The method invocation that is to be invoked on the proxy. - /// - private MethodInfo proxyMethod; + this.proxyMethod = proxyMethod; + } - /// - /// Creates a new instance of the - /// class. - /// - /// The AOP proxy. - /// The target object. - /// The target method proxied. - /// The method to invoke on proxy. - /// The target method's arguments. - /// - /// The of the target object. - /// - /// The list of interceptors that are to be applied. May be - /// . - /// - /// - /// If any of the or - /// parameters is . - /// - public DynamicMethodInvocation( - object proxy, object target, MethodInfo method, MethodInfo proxyMethod, - object[] arguments, Type targetType, IList interceptors) - : base(proxy, target, method, arguments, targetType, interceptors) + /// + /// The method invocation that is to be invoked on the proxy. + /// + protected MethodInfo ProxyMethod + { + get { return proxyMethod; } + set { proxyMethod = value; } + } + + /// + /// Invokes the joinpoint using dynamic reflection. + /// + /// + ///

+ /// Subclasses can override this to use custom invocation. + ///

+ ///
+ /// + /// The return value of the invocation of the joinpoint. + /// + /// + /// If invoking the joinpoint resulted in an exception. + /// + /// + protected override object InvokeJoinpoint() + { + MethodInfo targetMethodInfo = this.proxyMethod ?? Method; + + IDynamicMethod targetMethod = new SafeMethod(targetMethodInfo); + + try { - this.proxyMethod = proxyMethod; + AssertUtils.Understands(Target, "target", targetMethodInfo); + return targetMethod.Invoke(Target, Arguments); } - - /// - /// The method invocation that is to be invoked on the proxy. - /// - protected MethodInfo ProxyMethod + // Only happens if fallback to standard reflection. + catch (TargetInvocationException ex) { - get { return proxyMethod; } - set { proxyMethod = value; } - } - - /// - /// Invokes the joinpoint using dynamic reflection. - /// - /// - ///

- /// Subclasses can override this to use custom invocation. - ///

- ///
- /// - /// The return value of the invocation of the joinpoint. - /// - /// - /// If invoking the joinpoint resulted in an exception. - /// - /// - protected override object InvokeJoinpoint() - { - MethodInfo targetMethodInfo = this.proxyMethod ?? Method; - - IDynamicMethod targetMethod = new SafeMethod(targetMethodInfo); - - try - { - AssertUtils.Understands(Target, "target", targetMethodInfo); - return targetMethod.Invoke(Target, Arguments); - } - // Only happens if fallback to standard reflection. - catch (TargetInvocationException ex) - { - throw ReflectionUtils.UnwrapTargetInvocationException(ex); - } - } - - /// - /// Creates a new instance - /// from the specified and - /// increments the interceptor index. - /// - /// - /// The current instance. - /// - /// - /// The new instance to use. - /// - protected override IMethodInvocation PrepareMethodInvocationForProceed(IMethodInvocation invocation) - { - var rmi = new DynamicMethodInvocation(Proxy, Target, Method, ProxyMethod, Arguments, TargetType, Interceptors); - rmi.CurrentInterceptorIndex = CurrentInterceptorIndex + 1; - - return rmi; + throw ReflectionUtils.UnwrapTargetInvocationException(ex); } } + + /// + /// Creates a new instance + /// from the specified and + /// increments the interceptor index. + /// + /// + /// The current instance. + /// + /// + /// The new instance to use. + /// + protected override IMethodInvocation PrepareMethodInvocationForProceed(IMethodInvocation invocation) + { + var rmi = new DynamicMethodInvocation(Proxy, Target, Method, ProxyMethod, Arguments, TargetType, Interceptors); + rmi.CurrentInterceptorIndex = CurrentInterceptorIndex + 1; + + return rmi; + } } diff --git a/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/AbstractAopProxyFactory.cs b/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/AbstractAopProxyFactory.cs index c7f60b63..51ed18b7 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/AbstractAopProxyFactory.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/AbstractAopProxyFactory.cs @@ -1,88 +1,88 @@ using Spring.Aop.Support; using Spring.Aop.Target; -namespace Spring.Aop.Framework.DynamicProxy +namespace Spring.Aop.Framework.DynamicProxy; + +/// +/// A reusable base implementation of , providing +/// some useful default implementations +/// +/// Erich Eichinger +[Serializable] +public abstract class AbstractAopProxyFactory : IAopProxyFactory { /// - /// A reusable base implementation of , providing - /// some useful default implementations + /// Creates an for the + /// supplied configuration. /// - /// Erich Eichinger - [Serializable] - public abstract class AbstractAopProxyFactory : IAopProxyFactory + /// The AOP configuration. + /// An . + /// + /// If the supplied configuration is + /// invalid. + /// + /// + public IAopProxy CreateAopProxy(AdvisedSupport advisedSupport) { - /// - /// Creates an for the - /// supplied configuration. - /// - /// The AOP configuration. - /// An . - /// - /// If the supplied configuration is - /// invalid. - /// - /// - public IAopProxy CreateAopProxy(AdvisedSupport advisedSupport) + if (advisedSupport == null) { - if (advisedSupport == null) - { - throw new AopConfigException("Cannot create IAopProxy with null ProxyConfig"); - } - if (advisedSupport.Advisors.Count == 0 && advisedSupport.TargetSource == EmptyTargetSource.Empty) - { - throw new AopConfigException("Cannot create IAopProxy with no advisors and no target source"); - } - - EliminateDuplicateAdvisors(advisedSupport); - - return DoCreateAopProxyInstance(advisedSupport); + throw new AopConfigException("Cannot create IAopProxy with null ProxyConfig"); } - /// - /// Actually creates the proxy instance based on the supplied . - /// - /// the proxy instance described by . Must not be null - protected abstract IAopProxy DoCreateAopProxyInstance(AdvisedSupport advisedSupport); - - /// - /// If possible, checks for advisor duplicates on the supplied and - /// eliminates them. - /// - protected virtual void EliminateDuplicateAdvisors(AdvisedSupport advisedSupport) + if (advisedSupport.Advisors.Count == 0 && advisedSupport.TargetSource == EmptyTargetSource.Empty) { - if (advisedSupport.TargetSource is SingletonTargetSource - && IsAopProxyType(advisedSupport.TargetSource)) + throw new AopConfigException("Cannot create IAopProxy with no advisors and no target source"); + } + + EliminateDuplicateAdvisors(advisedSupport); + + return DoCreateAopProxyInstance(advisedSupport); + } + + /// + /// Actually creates the proxy instance based on the supplied . + /// + /// the proxy instance described by . Must not be null + protected abstract IAopProxy DoCreateAopProxyInstance(AdvisedSupport advisedSupport); + + /// + /// If possible, checks for advisor duplicates on the supplied and + /// eliminates them. + /// + protected virtual void EliminateDuplicateAdvisors(AdvisedSupport advisedSupport) + { + if (advisedSupport.TargetSource is SingletonTargetSource + && IsAopProxyType(advisedSupport.TargetSource)) + { + IAdvised innerProxy = (IAdvised) advisedSupport.TargetSource.GetTarget(); + // eliminate duplicate advisors + List thisAdvisors = new List(advisedSupport.Advisors); + foreach (IAdvisor innerAdvisor in innerProxy.Advisors) { - IAdvised innerProxy = (IAdvised)advisedSupport.TargetSource.GetTarget(); - // eliminate duplicate advisors - List thisAdvisors = new List(advisedSupport.Advisors); - foreach (IAdvisor innerAdvisor in innerProxy.Advisors) + foreach (IAdvisor thisAdvisor in thisAdvisors) { - foreach (IAdvisor thisAdvisor in thisAdvisors) + if (ReferenceEquals(thisAdvisor, innerAdvisor) + || (thisAdvisor.GetType() == typeof(DefaultPointcutAdvisor) + && thisAdvisor.Equals(innerAdvisor) + ) + ) { - if (ReferenceEquals(thisAdvisor, innerAdvisor) - || (thisAdvisor.GetType() == typeof(DefaultPointcutAdvisor) - && thisAdvisor.Equals(innerAdvisor) - ) - ) - { - advisedSupport.RemoveAdvisor(thisAdvisor); - } + advisedSupport.RemoveAdvisor(thisAdvisor); } } - - // elimination of duplicate introductions is not necessary - // since they do not propagate to nested proxy anyway } - } - /// - /// Checks, if the given holds a proxy generated by this factory. - /// - /// - protected virtual bool IsAopProxyType(ITargetSource targetSource) - { - return AopUtils.IsAopProxyType(targetSource.TargetType); + // elimination of duplicate introductions is not necessary + // since they do not propagate to nested proxy anyway } } + + /// + /// Checks, if the given holds a proxy generated by this factory. + /// + /// + protected virtual bool IsAopProxyType(ITargetSource targetSource) + { + return AopUtils.IsAopProxyType(targetSource.TargetType); + } } diff --git a/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/AbstractAopProxyMethodBuilder.cs b/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/AbstractAopProxyMethodBuilder.cs index 3a4c44cd..30c32350 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/AbstractAopProxyMethodBuilder.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/AbstractAopProxyMethodBuilder.cs @@ -21,345 +21,347 @@ using System.Reflection; using System.Reflection.Emit; using System.Runtime.Serialization; - using Spring.Proxy; -namespace Spring.Aop.Framework.DynamicProxy +namespace Spring.Aop.Framework.DynamicProxy; + +/// +/// Base class for AOP method builders that contains common functionalities. +/// +/// Aleksandar Seovic +/// Bruno Baia +public abstract class AbstractAopProxyMethodBuilder : AbstractProxyMethodBuilder { /// - /// Base class for AOP method builders that contains common functionalities. + /// The implementation to use. /// - /// Aleksandar Seovic - /// Bruno Baia - public abstract class AbstractAopProxyMethodBuilder : AbstractProxyMethodBuilder + protected IAopProxyTypeGenerator aopProxyGenerator; + + /// + /// The dictionary to cache the list of target + /// s. + /// + protected IDictionary targetMethods; + + /// + /// The dictionary to cache the list of target + /// s defined on the proxy. + /// + protected IDictionary onProxyTargetMethods; + + // variables + + /// + /// The local variable to store the list of method interceptors. + /// + protected LocalBuilder interceptors; + + /// + /// The local variable to store the target type being proxied. + /// + protected LocalBuilder targetType; + + /// + /// The local variable to store method arguments. + /// + protected LocalBuilder arguments; + + /// + /// The local variable to store the return value. + /// + protected LocalBuilder returnValue; + + /// + /// The local variable to store the closed generic method + /// when the target method is generic. + /// + protected LocalBuilder genericTargetMethod; + + /// + /// The local variable to store the closed generic method + /// when the target method defined on the proxy is generic. + /// + protected LocalBuilder genericOnProxyTargetMethod; + + /// + /// The field to cache the target . + /// + protected FieldBuilder targetMethodCacheField; + + /// + /// The field to cache the target + /// defined on the proxy. + /// + protected FieldBuilder onProxyTargetMethodCacheField; + + // convinience fields + + /// + /// Indicates if the method returns a value. + /// + protected bool methodReturnsValue; + + // private fields + + private static Dictionary ldindOpCodes; + + static AbstractAopProxyMethodBuilder() { - /// - /// The implementation to use. - /// - protected IAopProxyTypeGenerator aopProxyGenerator; + ldindOpCodes = new Dictionary(); + ldindOpCodes[typeof(sbyte)] = OpCodes.Ldind_I1; + ldindOpCodes[typeof(short)] = OpCodes.Ldind_I2; + ldindOpCodes[typeof(int)] = OpCodes.Ldind_I4; + ldindOpCodes[typeof(long)] = OpCodes.Ldind_I8; + ldindOpCodes[typeof(byte)] = OpCodes.Ldind_U1; + ldindOpCodes[typeof(ushort)] = OpCodes.Ldind_U2; + ldindOpCodes[typeof(uint)] = OpCodes.Ldind_U4; + ldindOpCodes[typeof(ulong)] = OpCodes.Ldind_I8; + ldindOpCodes[typeof(float)] = OpCodes.Ldind_R4; + ldindOpCodes[typeof(double)] = OpCodes.Ldind_R8; + ldindOpCodes[typeof(char)] = OpCodes.Ldind_U2; + ldindOpCodes[typeof(bool)] = OpCodes.Ldind_I1; + } - /// - /// The dictionary to cache the list of target - /// s. - /// - protected IDictionary targetMethods; + /// + /// Creates a new instance of the method builder. + /// + /// The type builder to use. + /// + /// The implementation to use. + /// + /// + /// if the interface is to be + /// implemented explicitly; otherwise . + /// + /// + /// The dictionary to cache the list of target + /// s. + /// + protected AbstractAopProxyMethodBuilder( + TypeBuilder typeBuilder, IAopProxyTypeGenerator aopProxyGenerator, + bool explicitImplementation, IDictionary targetMethods) + : this(typeBuilder, aopProxyGenerator, explicitImplementation, targetMethods, new Dictionary()) + { + } - /// - /// The dictionary to cache the list of target - /// s defined on the proxy. - /// - protected IDictionary onProxyTargetMethods; + /// + /// Creates a new instance of the method builder. + /// + /// The type builder to use. + /// + /// The implementation to use. + /// + /// + /// if the interface is to be + /// implemented explicitly; otherwise . + /// + /// + /// The dictionary to cache the list of target + /// s. + /// + /// + /// The dictionary to cache the list of target + /// s defined on the proxy. + /// + protected AbstractAopProxyMethodBuilder( + TypeBuilder typeBuilder, IAopProxyTypeGenerator aopProxyGenerator, + bool explicitImplementation, IDictionary targetMethods, IDictionary onProxyTargetMethods) + : base(typeBuilder, aopProxyGenerator, explicitImplementation) + { + this.aopProxyGenerator = aopProxyGenerator; + this.targetMethods = targetMethods; + this.onProxyTargetMethods = onProxyTargetMethods; + } - // variables + /// + /// Generates the proxy method. + /// + /// The IL generator to use. + /// The method to proxy. + /// + /// The interface definition of the method, if applicable. + /// + protected override void GenerateMethod( + ILGenerator il, MethodInfo method, MethodInfo interfaceMethod) + { + methodReturnsValue = (method.ReturnType != typeof(void)); - /// - /// The local variable to store the list of method interceptors. - /// - protected LocalBuilder interceptors; + DeclareLocals(il, method); - /// - /// The local variable to store the target type being proxied. - /// - protected LocalBuilder targetType; + GenerateTargetMethodCacheField(il, method); + GenerateOnProxyTargetMethodCacheField(il, method); - /// - /// The local variable to store method arguments. - /// - protected LocalBuilder arguments; + BeginMethod(il, method); + GenerateMethodLogic(il, method, interfaceMethod); + EndMethod(il, method); + } - /// - /// The local variable to store the return value. - /// - protected LocalBuilder returnValue; + /// + /// Generates unique method id for the cache field. + /// + /// The target method. + /// An unique method name. + protected virtual string GenerateMethodCacheFieldId(MethodInfo method) + { + return "_m" + Guid.NewGuid().ToString("N"); + } - /// - /// The local variable to store the closed generic method - /// when the target method is generic. - /// - protected LocalBuilder genericTargetMethod; + /// + /// Create static field that will cache target method. + /// + /// The IL generator to use. + /// The target method. + protected virtual void GenerateTargetMethodCacheField( + ILGenerator il, MethodInfo method) + { + string methodId = GenerateMethodCacheFieldId(method); + targetMethods.Add(methodId, method); - /// - /// The local variable to store the closed generic method - /// when the target method defined on the proxy is generic. - /// - protected LocalBuilder genericOnProxyTargetMethod; + targetMethodCacheField = typeBuilder.DefineField(methodId, typeof(MethodInfo), + FieldAttributes.Private | FieldAttributes.Static); - /// - /// The field to cache the target . - /// - protected FieldBuilder targetMethodCacheField; + MakeGenericMethod(il, method, targetMethodCacheField, genericTargetMethod); + } - /// - /// The field to cache the target - /// defined on the proxy. - /// - protected FieldBuilder onProxyTargetMethodCacheField; + /// + /// Create static field that will cache target method when defined on the proxy. + /// + /// The IL generator to use. + /// The target method. + protected virtual void GenerateOnProxyTargetMethodCacheField( + ILGenerator il, MethodInfo method) + { + } - // convinience fields - - /// - /// Indicates if the method returns a value. - /// - protected bool methodReturnsValue; - - // private fields - - private static Dictionary ldindOpCodes; - - static AbstractAopProxyMethodBuilder() + /// + /// Create a closed generic method for the current call + /// if target method is a generic definition. + /// + /// The IL generator to use. + /// The target method. + /// + /// The field that contains the method generic definition + /// + /// + /// The local variable to store the closed generic method. + /// + protected void MakeGenericMethod(ILGenerator il, MethodInfo method, + FieldBuilder methodCacheField, LocalBuilder localMethod) + { + // if target method is a generic definition, + // create a closed generic method for the current call. + if (method.IsGenericMethodDefinition) { - ldindOpCodes = new Dictionary(); - ldindOpCodes[typeof(sbyte)] = OpCodes.Ldind_I1; - ldindOpCodes[typeof(short)] = OpCodes.Ldind_I2; - ldindOpCodes[typeof(int)] = OpCodes.Ldind_I4; - ldindOpCodes[typeof(long)] = OpCodes.Ldind_I8; - ldindOpCodes[typeof(byte)] = OpCodes.Ldind_U1; - ldindOpCodes[typeof(ushort)] = OpCodes.Ldind_U2; - ldindOpCodes[typeof(uint)] = OpCodes.Ldind_U4; - ldindOpCodes[typeof(ulong)] = OpCodes.Ldind_I8; - ldindOpCodes[typeof(float)] = OpCodes.Ldind_R4; - ldindOpCodes[typeof(double)] = OpCodes.Ldind_R8; - ldindOpCodes[typeof(char)] = OpCodes.Ldind_U2; - ldindOpCodes[typeof(bool)] = OpCodes.Ldind_I1; - } + Type[] genericArgs = method.GetGenericArguments(); - /// - /// Creates a new instance of the method builder. - /// - /// The type builder to use. - /// - /// The implementation to use. - /// - /// - /// if the interface is to be - /// implemented explicitly; otherwise . - /// - /// - /// The dictionary to cache the list of target - /// s. - /// - protected AbstractAopProxyMethodBuilder( - TypeBuilder typeBuilder, IAopProxyTypeGenerator aopProxyGenerator, - bool explicitImplementation, IDictionary targetMethods) - : this(typeBuilder, aopProxyGenerator, explicitImplementation, targetMethods, new Dictionary()) - { - } + LocalBuilder typeArgs = il.DeclareLocal(typeof(Type[])); - /// - /// Creates a new instance of the method builder. - /// - /// The type builder to use. - /// - /// The implementation to use. - /// - /// - /// if the interface is to be - /// implemented explicitly; otherwise . - /// - /// - /// The dictionary to cache the list of target - /// s. - /// - /// - /// The dictionary to cache the list of target - /// s defined on the proxy. - /// - protected AbstractAopProxyMethodBuilder( - TypeBuilder typeBuilder, IAopProxyTypeGenerator aopProxyGenerator, - bool explicitImplementation, IDictionary targetMethods, IDictionary onProxyTargetMethods) - : base(typeBuilder, aopProxyGenerator, explicitImplementation) - { - this.aopProxyGenerator = aopProxyGenerator; - this.targetMethods = targetMethods; - this.onProxyTargetMethods = onProxyTargetMethods; - } + il.Emit(OpCodes.Ldsfld, methodCacheField); - /// - /// Generates the proxy method. - /// - /// The IL generator to use. - /// The method to proxy. - /// - /// The interface definition of the method, if applicable. - /// - protected override void GenerateMethod( - ILGenerator il, MethodInfo method, MethodInfo interfaceMethod) - { - methodReturnsValue = (method.ReturnType != typeof(void)); + // specify array size and create an array + il.Emit(OpCodes.Ldc_I4, genericArgs.Length); + il.Emit(OpCodes.Newarr, typeof(Type)); + il.Emit(OpCodes.Stloc, typeArgs); - DeclareLocals(il, method); - - GenerateTargetMethodCacheField(il, method); - GenerateOnProxyTargetMethodCacheField(il, method); - - BeginMethod(il, method); - GenerateMethodLogic(il, method, interfaceMethod); - EndMethod(il, method); - } - - /// - /// Generates unique method id for the cache field. - /// - /// The target method. - /// An unique method name. - protected virtual string GenerateMethodCacheFieldId(MethodInfo method) - { - return "_m" + Guid.NewGuid().ToString("N"); - } - - /// - /// Create static field that will cache target method. - /// - /// The IL generator to use. - /// The target method. - protected virtual void GenerateTargetMethodCacheField( - ILGenerator il, MethodInfo method) - { - string methodId = GenerateMethodCacheFieldId(method); - targetMethods.Add(methodId, method); - - targetMethodCacheField = typeBuilder.DefineField(methodId, typeof(MethodInfo), - FieldAttributes.Private | FieldAttributes.Static); - - MakeGenericMethod(il, method, targetMethodCacheField, genericTargetMethod); - } - - /// - /// Create static field that will cache target method when defined on the proxy. - /// - /// The IL generator to use. - /// The target method. - protected virtual void GenerateOnProxyTargetMethodCacheField( - ILGenerator il, MethodInfo method) - { - } - - /// - /// Create a closed generic method for the current call - /// if target method is a generic definition. - /// - /// The IL generator to use. - /// The target method. - /// - /// The field that contains the method generic definition - /// - /// - /// The local variable to store the closed generic method. - /// - protected void MakeGenericMethod(ILGenerator il, MethodInfo method, - FieldBuilder methodCacheField, LocalBuilder localMethod) - { - // if target method is a generic definition, - // create a closed generic method for the current call. - if (method.IsGenericMethodDefinition) + // populate array with type arguments + for (int i = 0; i < genericArgs.Length; i++) { - Type[] genericArgs = method.GetGenericArguments(); - - LocalBuilder typeArgs = il.DeclareLocal(typeof(Type[])); - - il.Emit(OpCodes.Ldsfld, methodCacheField); - - // specify array size and create an array - il.Emit(OpCodes.Ldc_I4, genericArgs.Length); - il.Emit(OpCodes.Newarr, typeof(Type)); - il.Emit(OpCodes.Stloc, typeArgs); - - // populate array with type arguments - for (int i = 0; i < genericArgs.Length; i++) - { - il.Emit(OpCodes.Ldloc, typeArgs); - il.Emit(OpCodes.Ldc_I4, i); - il.Emit(OpCodes.Ldtoken, genericArgs[i]); - il.EmitCall(OpCodes.Call, References.GetTypeFromHandle, null); - il.Emit(OpCodes.Stelem_Ref); - } - il.Emit(OpCodes.Ldloc, typeArgs); - il.Emit(OpCodes.Callvirt, References.MakeGenericMethod); - il.Emit(OpCodes.Stloc, localMethod); + il.Emit(OpCodes.Ldc_I4, i); + il.Emit(OpCodes.Ldtoken, genericArgs[i]); + il.EmitCall(OpCodes.Call, References.GetTypeFromHandle, null); + il.Emit(OpCodes.Stelem_Ref); } - } - /// - /// Generates the IL instructions that pushes - /// the target type on stack. - /// - /// The IL generator to use. - protected virtual void PushTargetType(ILGenerator il) + il.Emit(OpCodes.Ldloc, typeArgs); + il.Emit(OpCodes.Callvirt, References.MakeGenericMethod); + il.Emit(OpCodes.Stloc, localMethod); + } + } + + /// + /// Generates the IL instructions that pushes + /// the target type on stack. + /// + /// The IL generator to use. + protected virtual void PushTargetType(ILGenerator il) + { + aopProxyGenerator.PushAdvisedProxy(il); + il.Emit(OpCodes.Ldfld, References.TargetTypeField); + } + + /// + /// Generates the IL instructions that pushes + /// the current + /// instance on stack. + /// + /// The IL generator to use. + protected virtual void PushAdvisedProxy(ILGenerator il) + { + aopProxyGenerator.PushAdvisedProxy(il); + } + + /// + /// Pushes the target to stack. + /// + /// The IL generator to use. + /// The method to proxy. + protected virtual void PushTargetMethodInfo(ILGenerator il, MethodInfo method) + { + if (method.IsGenericMethodDefinition) { - aopProxyGenerator.PushAdvisedProxy(il); - il.Emit(OpCodes.Ldfld, References.TargetTypeField); + il.Emit(OpCodes.Ldloc, genericTargetMethod); + return; } - /// - /// Generates the IL instructions that pushes - /// the current - /// instance on stack. - /// - /// The IL generator to use. - protected virtual void PushAdvisedProxy(ILGenerator il) - { - aopProxyGenerator.PushAdvisedProxy(il); - } + il.Emit(OpCodes.Ldsfld, targetMethodCacheField); + } - /// - /// Pushes the target to stack. - /// - /// The IL generator to use. - /// The method to proxy. - protected virtual void PushTargetMethodInfo(ILGenerator il, MethodInfo method) + /// + /// Pushes the target defined on the proxy to stack. + /// + /// The IL generator to use. + /// The method to proxy. + protected virtual void PushOnProxyTargetMethodInfo(ILGenerator il, MethodInfo method) + { + if (onProxyTargetMethodCacheField != null) { if (method.IsGenericMethodDefinition) { - il.Emit(OpCodes.Ldloc, genericTargetMethod); + il.Emit(OpCodes.Ldloc, genericOnProxyTargetMethod); return; } - il.Emit(OpCodes.Ldsfld, targetMethodCacheField); + + il.Emit(OpCodes.Ldsfld, onProxyTargetMethodCacheField); + } + else + { + il.Emit(OpCodes.Ldnull); + } + } + + /// + /// Creates local variable declarations. + /// + /// The IL generator to use. + /// The method to proxy. + protected virtual void DeclareLocals(ILGenerator il, MethodInfo method) + { + interceptors = il.DeclareLocal(typeof(System.Collections.IList)); + targetType = il.DeclareLocal(typeof(Type)); + arguments = il.DeclareLocal(typeof(Object[])); + + if (method.IsGenericMethodDefinition) + { + genericTargetMethod = il.DeclareLocal(typeof(MethodInfo)); + genericOnProxyTargetMethod = il.DeclareLocal(typeof(MethodInfo)); } - /// - /// Pushes the target defined on the proxy to stack. - /// - /// The IL generator to use. - /// The method to proxy. - protected virtual void PushOnProxyTargetMethodInfo(ILGenerator il, MethodInfo method) + if (methodReturnsValue) { - if (onProxyTargetMethodCacheField != null) - { - if (method.IsGenericMethodDefinition) - { - il.Emit(OpCodes.Ldloc, genericOnProxyTargetMethod); - return; - } - il.Emit(OpCodes.Ldsfld, onProxyTargetMethodCacheField); - } - else - { - il.Emit(OpCodes.Ldnull); - } + returnValue = il.DeclareLocal(method.ReturnType); } - /// - /// Creates local variable declarations. - /// - /// The IL generator to use. - /// The method to proxy. - protected virtual void DeclareLocals(ILGenerator il, MethodInfo method) - { - interceptors = il.DeclareLocal(typeof(System.Collections.IList)); - targetType = il.DeclareLocal(typeof(Type)); - arguments = il.DeclareLocal(typeof(Object[])); - - if (method.IsGenericMethodDefinition) - { - genericTargetMethod = il.DeclareLocal(typeof(MethodInfo)); - genericOnProxyTargetMethod = il.DeclareLocal(typeof(MethodInfo)); - } - if (methodReturnsValue) - { - returnValue = il.DeclareLocal(method.ReturnType); - } - #if DEBUG && !NETSTANDARD interceptors.SetLocalSymInfo("interceptors"); targetType.SetLocalSymInfo("targetType"); @@ -376,363 +378,363 @@ namespace Spring.Aop.Framework.DynamicProxy returnValue.SetLocalSymInfo("returnValue"); } #endif + } + + /// + /// Initializes local variables + /// + /// The IL generator to use. + /// The method to proxy. + protected virtual void BeginMethod(ILGenerator il, MethodInfo method) + { + Label jmpProxyNotExposed = il.DefineLabel(); + + // set current proxy to this object + PushAdvisedProxy(il); + il.Emit(OpCodes.Ldfld, References.AdvisedField); + il.EmitCall(OpCodes.Callvirt, References.ExposeProxyProperty, null); + il.Emit(OpCodes.Brfalse_S, jmpProxyNotExposed); + il.Emit(OpCodes.Ldarg_0); + il.EmitCall(OpCodes.Call, References.PushProxyMethod, null); + + il.MarkLabel(jmpProxyNotExposed); + + // initialize targetType + PushTargetType(il); + il.Emit(OpCodes.Stloc, targetType); + + // initialize interceptors + PushAdvisedProxy(il); + il.Emit(OpCodes.Ldloc, targetType); + PushTargetMethodInfo(il, method); + il.EmitCall(OpCodes.Call, References.GetInterceptorsMethod, null); + il.Emit(OpCodes.Stloc, interceptors); + } + + /// + /// Generates method logic. + /// + /// The IL generator to use. + /// The method to proxy. + /// + /// The interface definition of the method, if applicable. + /// + protected virtual void GenerateMethodLogic( + ILGenerator il, MethodInfo method, MethodInfo interfaceMethod) + { + Label jmpDirectCall = il.DefineLabel(); + Label jmpEndIf = il.DefineLabel(); + + // check if there are any interceptors + il.Emit(OpCodes.Ldloc, interceptors); + il.EmitCall(OpCodes.Callvirt, References.CountProperty, null); + il.Emit(OpCodes.Ldc_I4_0); + + // if not jump to direct call + il.Emit(OpCodes.Ble, jmpDirectCall); + + // otherwise call Invoke and jump to method end + CallInvoke(il, method); + il.Emit(OpCodes.Br, jmpEndIf); + + // call method directly + il.MarkLabel(jmpDirectCall); + CallDirectProxiedMethod(il, method, interfaceMethod); + if (methodReturnsValue) + { + // store return value, unboxing is not necessary because we called method directly + il.Emit(OpCodes.Stloc, returnValue); } - /// - /// Initializes local variables - /// - /// The IL generator to use. - /// The method to proxy. - protected virtual void BeginMethod(ILGenerator il, MethodInfo method) + il.MarkLabel(jmpEndIf); + + if (methodReturnsValue) { - Label jmpProxyNotExposed = il.DefineLabel(); - - // set current proxy to this object - PushAdvisedProxy(il); - il.Emit(OpCodes.Ldfld, References.AdvisedField); - il.EmitCall(OpCodes.Callvirt, References.ExposeProxyProperty, null); - il.Emit(OpCodes.Brfalse_S, jmpProxyNotExposed); - il.Emit(OpCodes.Ldarg_0); - il.EmitCall(OpCodes.Call, References.PushProxyMethod, null); - - il.MarkLabel(jmpProxyNotExposed); - - // initialize targetType - PushTargetType(il); - il.Emit(OpCodes.Stloc, targetType); - - // initialize interceptors - PushAdvisedProxy(il); - il.Emit(OpCodes.Ldloc, targetType); - PushTargetMethodInfo(il, method); - il.EmitCall(OpCodes.Call, References.GetInterceptorsMethod, null); - il.Emit(OpCodes.Stloc, interceptors); - } - - /// - /// Generates method logic. - /// - /// The IL generator to use. - /// The method to proxy. - /// - /// The interface definition of the method, if applicable. - /// - protected virtual void GenerateMethodLogic( - ILGenerator il, MethodInfo method, MethodInfo interfaceMethod) - { - Label jmpDirectCall = il.DefineLabel(); - Label jmpEndIf = il.DefineLabel(); - - // check if there are any interceptors - il.Emit(OpCodes.Ldloc, interceptors); - il.EmitCall(OpCodes.Callvirt, References.CountProperty, null); - il.Emit(OpCodes.Ldc_I4_0); - - // if not jump to direct call - il.Emit(OpCodes.Ble, jmpDirectCall); - - // otherwise call Invoke and jump to method end - CallInvoke(il, method); - il.Emit(OpCodes.Br, jmpEndIf); - - // call method directly - il.MarkLabel(jmpDirectCall); - CallDirectProxiedMethod(il, method, interfaceMethod); - if (methodReturnsValue) + if (!method.ReturnType.IsValueType) { - // store return value, unboxing is not necessary because we called method directly - il.Emit(OpCodes.Stloc, returnValue); - } - - il.MarkLabel(jmpEndIf); - - if (methodReturnsValue) - { - if (!method.ReturnType.IsValueType) - { - ProcessReturnValue(il, returnValue); - } + ProcessReturnValue(il, returnValue); } } + } - /// - /// Calls method using Invoke - /// - /// The IL generator to use. - /// The method to proxy. - protected virtual void CallInvoke(ILGenerator il, MethodInfo method) + /// + /// Calls method using Invoke + /// + /// The IL generator to use. + /// The method to proxy. + protected virtual void CallInvoke(ILGenerator il, MethodInfo method) + { + ParameterInfo[] parameters = method.GetParameters(); + + SetupMethodArguments(il, method, parameters); + + PushAdvisedProxy(il); + + // setup parameters for call + il.Emit(OpCodes.Ldarg_0); // proxy + PushTarget(il); // target + il.Emit(OpCodes.Ldloc, targetType); // target type + PushTargetMethodInfo(il, method); // method + PushOnProxyTargetMethodInfo(il, method); // method defined on proxy + il.Emit(OpCodes.Ldloc, arguments); // args + il.Emit(OpCodes.Ldloc, interceptors); // interceptors + + // call Invoke + il.EmitCall(OpCodes.Call, References.InvokeMethod, null); + + // process return value + if (methodReturnsValue) { - ParameterInfo[] parameters = method.GetParameters(); + EmitUnboxIfNeeded(il, method.ReturnType); + il.Emit(OpCodes.Stloc, returnValue); + } + else + { + il.Emit(OpCodes.Pop); + } - SetupMethodArguments(il, method, parameters); - - PushAdvisedProxy(il); - - // setup parameters for call - il.Emit(OpCodes.Ldarg_0); // proxy - PushTarget(il); // target - il.Emit(OpCodes.Ldloc, targetType); // target type - PushTargetMethodInfo(il, method); // method - PushOnProxyTargetMethodInfo(il, method); // method defined on proxy - il.Emit(OpCodes.Ldloc, arguments); // args - il.Emit(OpCodes.Ldloc, interceptors); // interceptors - - // call Invoke - il.EmitCall(OpCodes.Call, References.InvokeMethod, null); - - // process return value - if (methodReturnsValue) + // process byRef arguments + for (int i = 0; i < parameters.Length; i++) + { + if (parameters[i].ParameterType.IsByRef) { - EmitUnboxIfNeeded(il, method.ReturnType); - il.Emit(OpCodes.Stloc, returnValue); - } - else - { - il.Emit(OpCodes.Pop); + il.Emit(OpCodes.Ldarg_S, i + 1); + il.Emit(OpCodes.Ldloc, arguments); + il.Emit(OpCodes.Ldc_I4_S, i); + il.Emit(OpCodes.Ldelem_Ref); + Type type = parameters[i].ParameterType.GetElementType(); + EmitUnboxIfNeeded(il, type); + EmitStoreValueIndirect(il, type); } + } + } - // process byRef arguments + /// + /// Setup proxied method arguments. + /// + /// The IL generator to use. + /// The method to proxy. + /// The method's parameters. + protected void SetupMethodArguments( + ILGenerator il, MethodInfo method, ParameterInfo[] parameters) + { + if (parameters.Length > 0) + { + // specify array size and create an array + il.Emit(OpCodes.Ldc_I4, parameters.Length); + il.Emit(OpCodes.Newarr, typeof(Object)); + il.Emit(OpCodes.Stloc, arguments); + + // populate array with params for (int i = 0; i < parameters.Length; i++) { - if (parameters[i].ParameterType.IsByRef) + Type type = parameters[i].ParameterType; + + il.Emit(OpCodes.Ldloc, arguments); + il.Emit(OpCodes.Ldc_I4, i); + il.Emit(OpCodes.Ldarg_S, i + 1); + + // setup byRef arguments + if (type.IsByRef) { - il.Emit(OpCodes.Ldarg_S, i + 1); - il.Emit(OpCodes.Ldloc, arguments); - il.Emit(OpCodes.Ldc_I4_S, i); - il.Emit(OpCodes.Ldelem_Ref); - Type type = parameters[i].ParameterType.GetElementType(); - EmitUnboxIfNeeded(il, type); - EmitStoreValueIndirect(il, type); + type = type.GetElementType(); + EmitLoadValueIndirect(il, type); } - } - } - /// - /// Setup proxied method arguments. - /// - /// The IL generator to use. - /// The method to proxy. - /// The method's parameters. - protected void SetupMethodArguments( - ILGenerator il, MethodInfo method, ParameterInfo[] parameters) - { - if (parameters.Length > 0) - { - // specify array size and create an array - il.Emit(OpCodes.Ldc_I4, parameters.Length); - il.Emit(OpCodes.Newarr, typeof(Object)); - il.Emit(OpCodes.Stloc, arguments); - - // populate array with params - for (int i = 0; i < parameters.Length; i++) + if (type.IsValueType || type.IsGenericParameter) { - Type type = parameters[i].ParameterType; - - il.Emit(OpCodes.Ldloc, arguments); - il.Emit(OpCodes.Ldc_I4, i); - il.Emit(OpCodes.Ldarg_S, i + 1); - - // setup byRef arguments - if (type.IsByRef) - { - type = type.GetElementType(); - EmitLoadValueIndirect(il, type); - } - - if (type.IsValueType || type.IsGenericParameter) - { - il.Emit(OpCodes.Box, type); - } - - il.Emit(OpCodes.Stelem_Ref); + il.Emit(OpCodes.Box, type); } - } - else - { - il.Emit(OpCodes.Ldnull); - il.Emit(OpCodes.Stloc, arguments); + + il.Emit(OpCodes.Stelem_Ref); } } - - /// - /// Calls proxied method directly. - /// - /// The IL generator to use. - /// The method to proxy. - /// - /// The interface definition of the method, if applicable. - /// - protected abstract void CallDirectProxiedMethod( - ILGenerator il, MethodInfo method, MethodInfo interfaceMethod); - - /// - /// Ends method by returning return value if appropriate. - /// - /// The IL generator to use. - /// The method to proxy. - protected virtual void EndMethod(ILGenerator il, MethodInfo method) + else { - Label jmpProxyNotExposed = il.DefineLabel(); - - // reset current proxy to old value - PushAdvisedProxy(il); - il.Emit(OpCodes.Ldfld, References.AdvisedField); - il.EmitCall(OpCodes.Callvirt, References.ExposeProxyProperty, null); - il.Emit(OpCodes.Brfalse_S, jmpProxyNotExposed); - il.EmitCall(OpCodes.Call, References.PopProxyMethod, null); - - il.MarkLabel(jmpProxyNotExposed); - - if (methodReturnsValue) - { - il.Emit(OpCodes.Ldloc, returnValue); - } - } - - /// - /// Emits MSIL instructions to load a value of the specified - /// onto the evaluation stack indirectly. - /// - /// The IL generator to use. - /// The type of the value. - protected static void EmitLoadValueIndirect(ILGenerator il, Type type) - { - if (type.IsValueType) - { - if (type == typeof(int)) il.Emit(OpCodes.Ldind_I4); - else if (type == typeof(uint)) il.Emit(OpCodes.Ldind_U4); - else if (type == typeof(char)) il.Emit(OpCodes.Ldind_I2); - else if (type == typeof(bool)) il.Emit(OpCodes.Ldind_I1); - else if (type == typeof(float)) il.Emit(OpCodes.Ldind_R4); - else if (type == typeof(double)) il.Emit(OpCodes.Ldind_R8); - else if (type == typeof(short)) il.Emit(OpCodes.Ldind_I2); - else if (type == typeof(ushort)) il.Emit(OpCodes.Ldind_U2); - else if (type == typeof(long) || type == typeof(ulong)) il.Emit(OpCodes.Ldind_I8); - else il.Emit(OpCodes.Ldobj, type); - } - else - { - il.Emit(OpCodes.Ldind_Ref); - } - } - - /// - /// Emit MSIL instructions to store a value of the specified - /// at a supplied address. - /// - /// The IL generator to use. - /// The type of the value. - protected static void EmitStoreValueIndirect(ILGenerator il, Type type) - { - if (type.IsValueType) - { - if (type.IsEnum) EmitStoreValueIndirect(il, Enum.GetUnderlyingType(type)); - else if (type == typeof(int)) il.Emit(OpCodes.Stind_I4); - else if (type == typeof(short)) il.Emit(OpCodes.Stind_I2); - else if (type == typeof(long) || type == typeof(ulong)) il.Emit(OpCodes.Stind_I8); - else if (type == typeof(char)) il.Emit(OpCodes.Stind_I2); - else if (type == typeof(bool)) il.Emit(OpCodes.Stind_I1); - else if (type == typeof(float)) il.Emit(OpCodes.Stind_R4); - else if (type == typeof(double)) il.Emit(OpCodes.Stind_R8); - else il.Emit(OpCodes.Stobj, type); - } - else - { - il.Emit(OpCodes.Stind_Ref); - } - } - - /// - /// Emits MSIL instructions to convert the boxed representation - /// of the supplied to its unboxed form. - /// - /// The IL generator to use. - /// The type specified in the instruction. - protected static void EmitUnboxIfNeeded(ILGenerator il, Type type) - { - if (type.IsValueType || type.IsGenericParameter) - { - il.Emit(OpCodes.Unbox_Any, type); - } + il.Emit(OpCodes.Ldnull); + il.Emit(OpCodes.Stloc, arguments); } } - internal struct References + /// + /// Calls proxied method directly. + /// + /// The IL generator to use. + /// The method to proxy. + /// + /// The interface definition of the method, if applicable. + /// + protected abstract void CallDirectProxiedMethod( + ILGenerator il, MethodInfo method, MethodInfo interfaceMethod); + + /// + /// Ends method by returning return value if appropriate. + /// + /// The IL generator to use. + /// The method to proxy. + protected virtual void EndMethod(ILGenerator il, MethodInfo method) { - // fields - public static readonly FieldInfo AdvisedField = - typeof(AdvisedProxy).GetField("m_advised", BindingFlags.Instance | BindingFlags.Public); + Label jmpProxyNotExposed = il.DefineLabel(); - public static readonly FieldInfo TargetTypeField = - typeof(AdvisedProxy).GetField("m_targetType", BindingFlags.Instance | BindingFlags.Public); + // reset current proxy to old value + PushAdvisedProxy(il); + il.Emit(OpCodes.Ldfld, References.AdvisedField); + il.EmitCall(OpCodes.Callvirt, References.ExposeProxyProperty, null); + il.Emit(OpCodes.Brfalse_S, jmpProxyNotExposed); + il.EmitCall(OpCodes.Call, References.PopProxyMethod, null); - public static readonly FieldInfo IntroductionsField = - typeof(AdvisedProxy).GetField("m_introductions", BindingFlags.Instance | BindingFlags.Public); + il.MarkLabel(jmpProxyNotExposed); - public static readonly FieldInfo TargetSourceField = - typeof(AdvisedProxy).GetField("m_targetSource", BindingFlags.Instance | BindingFlags.Public); + if (methodReturnsValue) + { + il.Emit(OpCodes.Ldloc, returnValue); + } + } - // constructors - public static readonly ConstructorInfo BaseCompositionAopProxyConstructor = - typeof(BaseCompositionAopProxy).GetConstructor(new Type[] { typeof(IAdvised) }); + /// + /// Emits MSIL instructions to load a value of the specified + /// onto the evaluation stack indirectly. + /// + /// The IL generator to use. + /// The type of the value. + protected static void EmitLoadValueIndirect(ILGenerator il, Type type) + { + if (type.IsValueType) + { + if (type == typeof(int)) il.Emit(OpCodes.Ldind_I4); + else if (type == typeof(uint)) il.Emit(OpCodes.Ldind_U4); + else if (type == typeof(char)) il.Emit(OpCodes.Ldind_I2); + else if (type == typeof(bool)) il.Emit(OpCodes.Ldind_I1); + else if (type == typeof(float)) il.Emit(OpCodes.Ldind_R4); + else if (type == typeof(double)) il.Emit(OpCodes.Ldind_R8); + else if (type == typeof(short)) il.Emit(OpCodes.Ldind_I2); + else if (type == typeof(ushort)) il.Emit(OpCodes.Ldind_U2); + else if (type == typeof(long) || type == typeof(ulong)) il.Emit(OpCodes.Ldind_I8); + else il.Emit(OpCodes.Ldobj, type); + } + else + { + il.Emit(OpCodes.Ldind_Ref); + } + } - public static readonly ConstructorInfo BaseCompositionAopProxySerializationConstructor = - typeof(BaseCompositionAopProxy).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, - new Type[] {typeof(SerializationInfo), typeof(StreamingContext)}, - null); + /// + /// Emit MSIL instructions to store a value of the specified + /// at a supplied address. + /// + /// The IL generator to use. + /// The type of the value. + protected static void EmitStoreValueIndirect(ILGenerator il, Type type) + { + if (type.IsValueType) + { + if (type.IsEnum) EmitStoreValueIndirect(il, Enum.GetUnderlyingType(type)); + else if (type == typeof(int)) il.Emit(OpCodes.Stind_I4); + else if (type == typeof(short)) il.Emit(OpCodes.Stind_I2); + else if (type == typeof(long) || type == typeof(ulong)) il.Emit(OpCodes.Stind_I8); + else if (type == typeof(char)) il.Emit(OpCodes.Stind_I2); + else if (type == typeof(bool)) il.Emit(OpCodes.Stind_I1); + else if (type == typeof(float)) il.Emit(OpCodes.Stind_R4); + else if (type == typeof(double)) il.Emit(OpCodes.Stind_R8); + else il.Emit(OpCodes.Stobj, type); + } + else + { + il.Emit(OpCodes.Stind_Ref); + } + } - public static readonly ConstructorInfo AdvisedProxyConstructor = - typeof(AdvisedProxy).GetConstructor(new Type[] { typeof(IAdvised), typeof(IAopProxy) }); - - public static readonly ConstructorInfo AdvisedProxySerializationConstructor = - typeof(AdvisedProxy).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, - new Type[] {typeof (SerializationInfo), typeof (StreamingContext)}, - null); - public static readonly ConstructorInfo ObjectConstructor = - typeof(Object).GetConstructor(Type.EmptyTypes); - - // methods - public static readonly MethodInfo PushProxyMethod = - typeof(AopContext).GetMethod("PushProxy", BindingFlags.Static | BindingFlags.Public, null, new Type[] { typeof(Object) }, null); - - public static readonly MethodInfo PopProxyMethod = - typeof(AopContext).GetMethod("PopProxy", BindingFlags.Static | BindingFlags.Public, null, Type.EmptyTypes, null); - - public static readonly MethodInfo InvokeMethod = - typeof(AdvisedProxy).GetMethod("Invoke", BindingFlags.Instance | BindingFlags.Public, null, new Type[] { typeof(Object), typeof(Object), typeof(Type), typeof(MethodInfo), typeof(MethodInfo), typeof(Object[]), typeof(System.Collections.IList) }, null); - - public static readonly MethodInfo GetInterceptorsMethod = - typeof(AdvisedProxy).GetMethod("GetInterceptors", BindingFlags.Instance | BindingFlags.Public, null, new Type[] { typeof(Type), typeof(MethodInfo) }, null); - - public static readonly MethodInfo GetTargetMethod = - typeof(ITargetSource).GetMethod("GetTarget", Type.EmptyTypes); - - public static readonly MethodInfo GetReleaseTargetMethod = - typeof(ITargetSource).GetMethod("ReleaseTarget", BindingFlags.Instance | BindingFlags.Public, null, new Type[] { typeof(Object) }, null); - - public static readonly MethodInfo GetTypeMethod = - typeof(Object).GetMethod("GetType", Type.EmptyTypes); - - public static readonly MethodInfo GetTypeFromHandle = - typeof(Type).GetMethod("GetTypeFromHandle", new Type[] { typeof(RuntimeTypeHandle) }); - - public static readonly MethodInfo MakeGenericMethod = - typeof(MethodInfo).GetMethod("MakeGenericMethod", new Type[] { typeof(Type[]) }); - - public static readonly MethodInfo DisposeMethod = - typeof(IDisposable).GetMethod("Dispose", Type.EmptyTypes); - - public static readonly MethodInfo AddSerializationValue = - typeof(SerializationInfo).GetMethod("AddValue", new Type[] { typeof(string), typeof(object) }); - - public static readonly MethodInfo GetSerializationValue = - typeof(SerializationInfo).GetMethod("GetValue", new Type[] { typeof(string), typeof(Type) }); - - // properties - public static readonly MethodInfo ExposeProxyProperty = - typeof(IAdvised).GetProperty("ExposeProxy", typeof(Boolean)).GetGetMethod(); - - public static readonly MethodInfo CountProperty = - typeof(System.Collections.ICollection).GetProperty("Count", typeof(Int32)).GetGetMethod(); + /// + /// Emits MSIL instructions to convert the boxed representation + /// of the supplied to its unboxed form. + /// + /// The IL generator to use. + /// The type specified in the instruction. + protected static void EmitUnboxIfNeeded(ILGenerator il, Type type) + { + if (type.IsValueType || type.IsGenericParameter) + { + il.Emit(OpCodes.Unbox_Any, type); + } } } + +internal struct References +{ + // fields + public static readonly FieldInfo AdvisedField = + typeof(AdvisedProxy).GetField("m_advised", BindingFlags.Instance | BindingFlags.Public); + + public static readonly FieldInfo TargetTypeField = + typeof(AdvisedProxy).GetField("m_targetType", BindingFlags.Instance | BindingFlags.Public); + + public static readonly FieldInfo IntroductionsField = + typeof(AdvisedProxy).GetField("m_introductions", BindingFlags.Instance | BindingFlags.Public); + + public static readonly FieldInfo TargetSourceField = + typeof(AdvisedProxy).GetField("m_targetSource", BindingFlags.Instance | BindingFlags.Public); + + // constructors + public static readonly ConstructorInfo BaseCompositionAopProxyConstructor = + typeof(BaseCompositionAopProxy).GetConstructor(new Type[] { typeof(IAdvised) }); + + public static readonly ConstructorInfo BaseCompositionAopProxySerializationConstructor = + typeof(BaseCompositionAopProxy).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, + new Type[] { typeof(SerializationInfo), typeof(StreamingContext) }, + null); + + public static readonly ConstructorInfo AdvisedProxyConstructor = + typeof(AdvisedProxy).GetConstructor(new Type[] { typeof(IAdvised), typeof(IAopProxy) }); + + public static readonly ConstructorInfo AdvisedProxySerializationConstructor = + typeof(AdvisedProxy).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, + new Type[] { typeof(SerializationInfo), typeof(StreamingContext) }, + null); + + public static readonly ConstructorInfo ObjectConstructor = + typeof(Object).GetConstructor(Type.EmptyTypes); + + // methods + public static readonly MethodInfo PushProxyMethod = + typeof(AopContext).GetMethod("PushProxy", BindingFlags.Static | BindingFlags.Public, null, new Type[] { typeof(Object) }, null); + + public static readonly MethodInfo PopProxyMethod = + typeof(AopContext).GetMethod("PopProxy", BindingFlags.Static | BindingFlags.Public, null, Type.EmptyTypes, null); + + public static readonly MethodInfo InvokeMethod = + typeof(AdvisedProxy).GetMethod("Invoke", BindingFlags.Instance | BindingFlags.Public, null, new Type[] { typeof(Object), typeof(Object), typeof(Type), typeof(MethodInfo), typeof(MethodInfo), typeof(Object[]), typeof(System.Collections.IList) }, null); + + public static readonly MethodInfo GetInterceptorsMethod = + typeof(AdvisedProxy).GetMethod("GetInterceptors", BindingFlags.Instance | BindingFlags.Public, null, new Type[] { typeof(Type), typeof(MethodInfo) }, null); + + public static readonly MethodInfo GetTargetMethod = + typeof(ITargetSource).GetMethod("GetTarget", Type.EmptyTypes); + + public static readonly MethodInfo GetReleaseTargetMethod = + typeof(ITargetSource).GetMethod("ReleaseTarget", BindingFlags.Instance | BindingFlags.Public, null, new Type[] { typeof(Object) }, null); + + public static readonly MethodInfo GetTypeMethod = + typeof(Object).GetMethod("GetType", Type.EmptyTypes); + + public static readonly MethodInfo GetTypeFromHandle = + typeof(Type).GetMethod("GetTypeFromHandle", new Type[] { typeof(RuntimeTypeHandle) }); + + public static readonly MethodInfo MakeGenericMethod = + typeof(MethodInfo).GetMethod("MakeGenericMethod", new Type[] { typeof(Type[]) }); + + public static readonly MethodInfo DisposeMethod = + typeof(IDisposable).GetMethod("Dispose", Type.EmptyTypes); + + public static readonly MethodInfo AddSerializationValue = + typeof(SerializationInfo).GetMethod("AddValue", new Type[] { typeof(string), typeof(object) }); + + public static readonly MethodInfo GetSerializationValue = + typeof(SerializationInfo).GetMethod("GetValue", new Type[] { typeof(string), typeof(Type) }); + + // properties + public static readonly MethodInfo ExposeProxyProperty = + typeof(IAdvised).GetProperty("ExposeProxy", typeof(Boolean)).GetGetMethod(); + + public static readonly MethodInfo CountProperty = + typeof(System.Collections.ICollection).GetProperty("Count", typeof(Int32)).GetGetMethod(); +} diff --git a/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/AbstractAopProxyTypeBuilder.cs b/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/AbstractAopProxyTypeBuilder.cs index 21f97ae4..e18c0dba 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/AbstractAopProxyTypeBuilder.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/AbstractAopProxyTypeBuilder.cs @@ -22,73 +22,69 @@ using System.Collections; using System.Reflection.Emit; - using Spring.Proxy; - #endregion -namespace Spring.Aop.Framework.DynamicProxy +namespace Spring.Aop.Framework.DynamicProxy; + +/// +/// Base class for proxy builders that can be used +/// to create an AOP proxy for any object. +/// +/// Bruno Baia +public abstract class AbstractAopProxyTypeBuilder : + AbstractProxyTypeBuilder, IAopProxyTypeGenerator { - /// - /// Base class for proxy builders that can be used - /// to create an AOP proxy for any object. - /// - /// Bruno Baia - public abstract class AbstractAopProxyTypeBuilder : - AbstractProxyTypeBuilder, IAopProxyTypeGenerator + #region IProxyTypeGenerator Members + + /// + /// Generates the IL instructions that pushes + /// the target instance on which calls should be delegated to. + /// + /// The IL generator to use. + public override void PushTarget(ILGenerator il) { - #region IProxyTypeGenerator Members - - /// - /// Generates the IL instructions that pushes - /// the target instance on which calls should be delegated to. - /// - /// The IL generator to use. - public override void PushTarget(ILGenerator il) - { - PushAdvisedProxy(il); - il.Emit(OpCodes.Ldfld, References.TargetSourceField); - il.EmitCall(OpCodes.Callvirt, References.GetTargetMethod, null); - } - - #endregion - - #region IAopProxyTypeGenerator Members - - /// - /// Generates the IL instructions that pushes - /// the current - /// instance on stack. - /// - /// The IL generator to use. - public abstract void PushAdvisedProxy(ILGenerator il); - - #endregion - - #region Protected Methods - - /// - protected override IList GetTypeAttributes(Type type) - { - IList attrs = base.GetTypeAttributes(type); - int i = 0; - while (i < attrs.Count) - { - if (IsAttributeMatchingType(attrs[i], typeof(SerializableAttribute))) - { - attrs.RemoveAt(i); - } - else - { - i++; - } - } - - return attrs; - } - - - #endregion + PushAdvisedProxy(il); + il.Emit(OpCodes.Ldfld, References.TargetSourceField); + il.EmitCall(OpCodes.Callvirt, References.GetTargetMethod, null); } + + #endregion + + #region IAopProxyTypeGenerator Members + + /// + /// Generates the IL instructions that pushes + /// the current + /// instance on stack. + /// + /// The IL generator to use. + public abstract void PushAdvisedProxy(ILGenerator il); + + #endregion + + #region Protected Methods + + /// + protected override IList GetTypeAttributes(Type type) + { + IList attrs = base.GetTypeAttributes(type); + int i = 0; + while (i < attrs.Count) + { + if (IsAttributeMatchingType(attrs[i], typeof(SerializableAttribute))) + { + attrs.RemoveAt(i); + } + else + { + i++; + } + } + + return attrs; + } + + #endregion } diff --git a/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/AdvisedProxy.cs b/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/AdvisedProxy.cs index a4ce5f5f..bb91b855 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/AdvisedProxy.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/AdvisedProxy.cs @@ -24,368 +24,369 @@ using AopAlliance.Aop; using AopAlliance.Intercept; using Spring.Util; -namespace Spring.Aop.Framework.DynamicProxy +namespace Spring.Aop.Framework.DynamicProxy; + +/// +/// Represents the AOP configuration data built-in with the proxy. +/// +/// Bruno Baia +[Serializable] +public class AdvisedProxy : IAdvised, ISerializable { /// - /// Represents the AOP configuration data built-in with the proxy. + /// Should we use dynamic reflection for method invocation ? /// - /// Bruno Baia - [Serializable] - public class AdvisedProxy : IAdvised, ISerializable + public static bool UseDynamicReflection; + + /// + /// Optimization fields + /// + private static IList EmptyList = new ReadOnlyCollection(new object[0]); + + /// + /// IAdvised delegate + /// + public IAdvised m_advised; + + /// + /// Array of introduction delegates + /// + public IAdvice[] m_introductions; + + /// + /// Target source + /// + public ITargetSource m_targetSource; + + /// + /// Type of target object. + /// + public Type m_targetType; + + /// + /// Creates a new instance of the class. + /// + static AdvisedProxy() { - /// - /// Should we use dynamic reflection for method invocation ? - /// - public static bool UseDynamicReflection; + string appSettingsKey = typeof(AdvisedProxy).FullName + ".UseDynamicReflection"; + NameValueCollection appSettings = + ConfigurationUtils.GetSection("appSettings") as NameValueCollection; - /// - /// Optimization fields - /// - private static IList EmptyList = new ReadOnlyCollection(new object[0]); - - /// - /// IAdvised delegate - /// - public IAdvised m_advised; - - /// - /// Array of introduction delegates - /// - public IAdvice[] m_introductions; - - /// - /// Target source - /// - public ITargetSource m_targetSource; - - /// - /// Type of target object. - /// - public Type m_targetType; - - /// - /// Creates a new instance of the class. - /// - static AdvisedProxy() + if (appSettings != null && StringUtils.HasLength(appSettings[appSettingsKey])) { - string appSettingsKey = typeof(AdvisedProxy).FullName + ".UseDynamicReflection"; - NameValueCollection appSettings = - ConfigurationUtils.GetSection("appSettings") as NameValueCollection; - - if (appSettings != null && StringUtils.HasLength(appSettings[appSettingsKey])) - { - UseDynamicReflection = bool.Parse(appSettings[appSettingsKey]); - } - else - { - UseDynamicReflection = true; - } + UseDynamicReflection = bool.Parse(appSettings[appSettingsKey]); } - - /// - /// Creates a new instance of the class. - /// - public AdvisedProxy() - { } - - /// - /// Creates a new instance of the class. - /// - /// The proxy configuration. - protected AdvisedProxy(IAdvised advised) + else { - m_advised = advised; - } - - /// - /// Creates a new instance of the - /// class. - /// - /// The proxy configuration. - /// The proxy. - public AdvisedProxy(IAdvised advised, IAopProxy proxy) - { - Initialize(advised, proxy); - } - - /// - /// Deserialization constructor. - /// - /// Serialization data. - /// Serialization context. - protected AdvisedProxy(SerializationInfo info, StreamingContext context) - { - m_advised = (IAdvised)info.GetValue("advised", typeof(IAdvised)); - m_introductions = (IAdvice[])info.GetValue("introductions", typeof(IAdvice[])); - m_targetSource = (ITargetSource)info.GetValue("targetSource", typeof(ITargetSource)); - - var type = info.GetString("targetType"); - m_targetType = type != null ? Type.GetType(type) : null; - } - - /// - /// Serializes this instance. - /// - /// Serialization data. - /// Serialization context. - [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)] - public virtual void GetObjectData(SerializationInfo info, StreamingContext context) - { - info.AddValue("advised", m_advised); - info.AddValue("introductions", m_introductions); - info.AddValue("targetSource", m_targetSource); - info.AddValue("targetType", m_targetType?.AssemblyQualifiedName); - } - - /// - /// Initialization method. - /// - /// The proxy configuration. - /// - /// The current implementation. - /// - protected void Initialize(IAdvised advised, IAopProxy proxy) - { - this.m_advised = advised; - this.m_targetSource = advised.TargetSource; - this.m_targetType = advised.TargetSource.TargetType; - - // initialize introduction advice - this.m_introductions = new IAdvice[advised.Introductions.Count]; - for (int i = 0; i < advised.Introductions.Count; i++) - { - this.m_introductions[i] = advised.Introductions[i].Advice; - - // set target proxy on introduction instance if it implements ITargetAware - if (this.m_introductions[i] is ITargetAware) - { - ((ITargetAware)this.m_introductions[i]).TargetProxy = proxy; - } - } - } - - /// - /// Invokes intercepted methods using reflection - /// - /// proxy object - /// target object to invoke method on - /// target type - /// taget method to invoke - /// The method to invoke on proxy. - /// method arguments - /// interceptor chain - /// value returned by invocation chain - public object Invoke(object proxy, object target, Type targetType, - MethodInfo targetMethod, MethodInfo proxyMethod, object[] args, IList interceptors) - { - IMethodInvocation invocation = null; - if (UseDynamicReflection) - { - invocation = new DynamicMethodInvocation( - proxy, target, targetMethod, proxyMethod, args, targetType, interceptors); - } - else - { - invocation = new ReflectiveMethodInvocation( - proxy, target, targetMethod, proxyMethod, args, targetType, interceptors); - } - return invocation.Proceed(); - } - - /// - /// Returns a list of method interceptors - /// - /// target type - /// target method - /// list of inteceptors for the specified method - public IList GetInterceptors(Type targetType, MethodInfo method) - { - if (m_advised.Advisors.Count == 0) - { - return EmptyList; - } - else - { - return m_advised.AdvisorChainFactory.GetInterceptors(m_advised, this, method, targetType); - } - } - - bool IAdvised.ExposeProxy - { - get { return m_advised.ExposeProxy; } - } - - IAdvisorChainFactory IAdvised.AdvisorChainFactory - { - get { return m_advised.AdvisorChainFactory; } - } - - bool IAdvised.ProxyTargetType - { - get { return m_advised.ProxyTargetType; } - } - - bool IAdvised.ProxyTargetAttributes - { - get { return m_advised.ProxyTargetAttributes; } - } - - IList IAdvised.Advisors - { - get { return m_advised.Advisors; } - } - - IList IAdvised.Introductions - { - get { return m_advised.Introductions; } - } - - IList IAdvised.Interfaces - { - get { return m_advised.Interfaces; } - } - - IDictionary IAdvised.InterfaceMap - { - get { return m_advised.InterfaceMap; } - } - - bool IAdvised.IsFrozen - { - get { return m_advised.IsFrozen; } - } - - ITargetSource IAdvised.TargetSource - { - get { return m_advised.TargetSource; } - } - - bool IAdvised.IsSerializable - { - get { return m_advised.IsSerializable; } - } - - /// - /// Adds the supplied to the end (or tail) - /// of the advice (interceptor) chain. - /// - /// - /// The to be added. - /// - /// - /// - public void AddAdvice(IAdvice advice) - { - this.m_advised.AddAdvice(advice); - } - - /// - /// Adds the supplied to the supplied - /// in the advice (interceptor) chain. - /// - /// - /// The zero (0) indexed position (from the head) at which the - /// supplied is to be inserted into the - /// advice (interceptor) chain. - /// - /// - /// The to be added. - /// - /// - /// - public void AddAdvice(int position, IAdvice advice) - { - this.m_advised.AddAdvice(position, advice); - } - - bool IAdvised.IsInterfaceProxied(Type intf) - { - return m_advised.IsInterfaceProxied(intf); - } - - void IAdvised.AddAdvisors(IAdvisors advisors) - { - m_advised.AddAdvisors(advisors); - } - - void IAdvised.AddAdvisor(IAdvisor advisor) - { - m_advised.AddAdvisor(advisor); - } - - void IAdvised.AddAdvisor(int pos, IAdvisor advisor) - { - m_advised.AddAdvisor(pos, advisor); - } - - void IAdvised.AddIntroduction(IIntroductionAdvisor advisor) - { - m_advised.AddIntroduction(advisor); - } - - void IAdvised.AddIntroduction(int pos, IIntroductionAdvisor advisor) - { - m_advised.AddIntroduction(pos, advisor); - } - - int IAdvised.IndexOf(IAdvisor advisor) - { - return m_advised.IndexOf(advisor); - } - - int IAdvised.IndexOf(IIntroductionAdvisor advisor) - { - return m_advised.IndexOf(advisor); - } - - bool IAdvised.RemoveAdvisor(IAdvisor advisor) - { - return m_advised.RemoveAdvisor(advisor); - } - - void IAdvised.RemoveAdvisor(int index) - { - m_advised.RemoveAdvisor(index); - } - - bool IAdvised.RemoveAdvice(IAdvice advice) - { - return m_advised.RemoveAdvice(advice); - } - - bool IAdvised.RemoveIntroduction(IIntroductionAdvisor advisor) - { - return m_advised.RemoveIntroduction(advisor); - } - - void IAdvised.RemoveIntroduction(int index) - { - m_advised.RemoveIntroduction(index); - } - - void IAdvised.ReplaceIntroduction(int index, IIntroductionAdvisor advisor) - { - m_advised.ReplaceIntroduction(index, advisor); - } - - bool IAdvised.ReplaceAdvisor(IAdvisor a, IAdvisor b) - { - return m_advised.ReplaceAdvisor(a, b); - } - - string IAdvised.ToProxyConfigString() - { - return m_advised.ToProxyConfigString(); - } - - /// - /// Gets the target type behind the implementing object. - /// Ttypically a proxy configuration or an actual proxy. - /// - /// The type of the target or null if not known. - public Type TargetType - { - get { return m_targetType; } + UseDynamicReflection = true; } } + + /// + /// Creates a new instance of the class. + /// + public AdvisedProxy() + { + } + + /// + /// Creates a new instance of the class. + /// + /// The proxy configuration. + protected AdvisedProxy(IAdvised advised) + { + m_advised = advised; + } + + /// + /// Creates a new instance of the + /// class. + /// + /// The proxy configuration. + /// The proxy. + public AdvisedProxy(IAdvised advised, IAopProxy proxy) + { + Initialize(advised, proxy); + } + + /// + /// Deserialization constructor. + /// + /// Serialization data. + /// Serialization context. + protected AdvisedProxy(SerializationInfo info, StreamingContext context) + { + m_advised = (IAdvised) info.GetValue("advised", typeof(IAdvised)); + m_introductions = (IAdvice[]) info.GetValue("introductions", typeof(IAdvice[])); + m_targetSource = (ITargetSource) info.GetValue("targetSource", typeof(ITargetSource)); + + var type = info.GetString("targetType"); + m_targetType = type != null ? Type.GetType(type) : null; + } + + /// + /// Serializes this instance. + /// + /// Serialization data. + /// Serialization context. + [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)] + public virtual void GetObjectData(SerializationInfo info, StreamingContext context) + { + info.AddValue("advised", m_advised); + info.AddValue("introductions", m_introductions); + info.AddValue("targetSource", m_targetSource); + info.AddValue("targetType", m_targetType?.AssemblyQualifiedName); + } + + /// + /// Initialization method. + /// + /// The proxy configuration. + /// + /// The current implementation. + /// + protected void Initialize(IAdvised advised, IAopProxy proxy) + { + this.m_advised = advised; + this.m_targetSource = advised.TargetSource; + this.m_targetType = advised.TargetSource.TargetType; + + // initialize introduction advice + this.m_introductions = new IAdvice[advised.Introductions.Count]; + for (int i = 0; i < advised.Introductions.Count; i++) + { + this.m_introductions[i] = advised.Introductions[i].Advice; + + // set target proxy on introduction instance if it implements ITargetAware + if (this.m_introductions[i] is ITargetAware) + { + ((ITargetAware) this.m_introductions[i]).TargetProxy = proxy; + } + } + } + + /// + /// Invokes intercepted methods using reflection + /// + /// proxy object + /// target object to invoke method on + /// target type + /// taget method to invoke + /// The method to invoke on proxy. + /// method arguments + /// interceptor chain + /// value returned by invocation chain + public object Invoke(object proxy, object target, Type targetType, + MethodInfo targetMethod, MethodInfo proxyMethod, object[] args, IList interceptors) + { + IMethodInvocation invocation = null; + if (UseDynamicReflection) + { + invocation = new DynamicMethodInvocation( + proxy, target, targetMethod, proxyMethod, args, targetType, interceptors); + } + else + { + invocation = new ReflectiveMethodInvocation( + proxy, target, targetMethod, proxyMethod, args, targetType, interceptors); + } + + return invocation.Proceed(); + } + + /// + /// Returns a list of method interceptors + /// + /// target type + /// target method + /// list of inteceptors for the specified method + public IList GetInterceptors(Type targetType, MethodInfo method) + { + if (m_advised.Advisors.Count == 0) + { + return EmptyList; + } + else + { + return m_advised.AdvisorChainFactory.GetInterceptors(m_advised, this, method, targetType); + } + } + + bool IAdvised.ExposeProxy + { + get { return m_advised.ExposeProxy; } + } + + IAdvisorChainFactory IAdvised.AdvisorChainFactory + { + get { return m_advised.AdvisorChainFactory; } + } + + bool IAdvised.ProxyTargetType + { + get { return m_advised.ProxyTargetType; } + } + + bool IAdvised.ProxyTargetAttributes + { + get { return m_advised.ProxyTargetAttributes; } + } + + IList IAdvised.Advisors + { + get { return m_advised.Advisors; } + } + + IList IAdvised.Introductions + { + get { return m_advised.Introductions; } + } + + IList IAdvised.Interfaces + { + get { return m_advised.Interfaces; } + } + + IDictionary IAdvised.InterfaceMap + { + get { return m_advised.InterfaceMap; } + } + + bool IAdvised.IsFrozen + { + get { return m_advised.IsFrozen; } + } + + ITargetSource IAdvised.TargetSource + { + get { return m_advised.TargetSource; } + } + + bool IAdvised.IsSerializable + { + get { return m_advised.IsSerializable; } + } + + /// + /// Adds the supplied to the end (or tail) + /// of the advice (interceptor) chain. + /// + /// + /// The to be added. + /// + /// + /// + public void AddAdvice(IAdvice advice) + { + this.m_advised.AddAdvice(advice); + } + + /// + /// Adds the supplied to the supplied + /// in the advice (interceptor) chain. + /// + /// + /// The zero (0) indexed position (from the head) at which the + /// supplied is to be inserted into the + /// advice (interceptor) chain. + /// + /// + /// The to be added. + /// + /// + /// + public void AddAdvice(int position, IAdvice advice) + { + this.m_advised.AddAdvice(position, advice); + } + + bool IAdvised.IsInterfaceProxied(Type intf) + { + return m_advised.IsInterfaceProxied(intf); + } + + void IAdvised.AddAdvisors(IAdvisors advisors) + { + m_advised.AddAdvisors(advisors); + } + + void IAdvised.AddAdvisor(IAdvisor advisor) + { + m_advised.AddAdvisor(advisor); + } + + void IAdvised.AddAdvisor(int pos, IAdvisor advisor) + { + m_advised.AddAdvisor(pos, advisor); + } + + void IAdvised.AddIntroduction(IIntroductionAdvisor advisor) + { + m_advised.AddIntroduction(advisor); + } + + void IAdvised.AddIntroduction(int pos, IIntroductionAdvisor advisor) + { + m_advised.AddIntroduction(pos, advisor); + } + + int IAdvised.IndexOf(IAdvisor advisor) + { + return m_advised.IndexOf(advisor); + } + + int IAdvised.IndexOf(IIntroductionAdvisor advisor) + { + return m_advised.IndexOf(advisor); + } + + bool IAdvised.RemoveAdvisor(IAdvisor advisor) + { + return m_advised.RemoveAdvisor(advisor); + } + + void IAdvised.RemoveAdvisor(int index) + { + m_advised.RemoveAdvisor(index); + } + + bool IAdvised.RemoveAdvice(IAdvice advice) + { + return m_advised.RemoveAdvice(advice); + } + + bool IAdvised.RemoveIntroduction(IIntroductionAdvisor advisor) + { + return m_advised.RemoveIntroduction(advisor); + } + + void IAdvised.RemoveIntroduction(int index) + { + m_advised.RemoveIntroduction(index); + } + + void IAdvised.ReplaceIntroduction(int index, IIntroductionAdvisor advisor) + { + m_advised.ReplaceIntroduction(index, advisor); + } + + bool IAdvised.ReplaceAdvisor(IAdvisor a, IAdvisor b) + { + return m_advised.ReplaceAdvisor(a, b); + } + + string IAdvised.ToProxyConfigString() + { + return m_advised.ToProxyConfigString(); + } + + /// + /// Gets the target type behind the implementing object. + /// Ttypically a proxy configuration or an actual proxy. + /// + /// The type of the target or null if not known. + public Type TargetType + { + get { return m_targetType; } + } } diff --git a/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/BaseAopProxyMethodBuilder.cs b/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/BaseAopProxyMethodBuilder.cs index 9abe70ff..9e4dbbc9 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/BaseAopProxyMethodBuilder.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/BaseAopProxyMethodBuilder.cs @@ -20,94 +20,93 @@ using System.Reflection; using System.Reflection.Emit; - using Spring.Util; -namespace Spring.Aop.Framework.DynamicProxy +namespace Spring.Aop.Framework.DynamicProxy; + +/// +/// implementation +/// that delegates method calls to the base method. +/// +/// Bruno Baia +public class BaseAopProxyMethodBuilder : AbstractAopProxyMethodBuilder { /// - /// implementation - /// that delegates method calls to the base method. + /// Creates a new instance of the method builder. /// - /// Bruno Baia - public class BaseAopProxyMethodBuilder : AbstractAopProxyMethodBuilder + /// The type builder to use. + /// + /// The implementation to use. + /// + /// + /// The dictionary to cache the list of target + /// s. + /// + /// + /// The dictionary to cache the list of target + /// s defined on the proxy. + /// + public BaseAopProxyMethodBuilder( + TypeBuilder typeBuilder, IAopProxyTypeGenerator aopProxyGenerator, + IDictionary targetMethods, IDictionary onProxyTargetMethods) + : base(typeBuilder, aopProxyGenerator, false, targetMethods, onProxyTargetMethods) { - /// - /// Creates a new instance of the method builder. - /// - /// The type builder to use. - /// - /// The implementation to use. - /// - /// - /// The dictionary to cache the list of target - /// s. - /// - /// - /// The dictionary to cache the list of target - /// s defined on the proxy. - /// - public BaseAopProxyMethodBuilder( - TypeBuilder typeBuilder, IAopProxyTypeGenerator aopProxyGenerator, - IDictionary targetMethods, IDictionary onProxyTargetMethods) - : base(typeBuilder, aopProxyGenerator, false, targetMethods, onProxyTargetMethods) - { - } + } - /// - /// Create static field that will cache target method when defined on the proxy. - /// - /// The IL generator to use. - /// The target method. - protected override void GenerateOnProxyTargetMethodCacheField( - ILGenerator il, MethodInfo method) + /// + /// Create static field that will cache target method when defined on the proxy. + /// + /// The IL generator to use. + /// The target method. + protected override void GenerateOnProxyTargetMethodCacheField( + ILGenerator il, MethodInfo method) + { + if (method.IsVirtual && !method.IsFinal) { - if (method.IsVirtual && !method.IsFinal) + string methodId = GenerateMethodCacheFieldId(method); + + // generate proxy method + MethodBuilder baseMethod = typeBuilder.DefineMethod("proxy_" + methodId, + MethodAttributes.Public | MethodAttributes.HideBySig, + CallingConventions.Standard, + method.ReturnType, ReflectionUtils.GetParameterTypes(method)); + + DefineGenericParameters(baseMethod, method); + //DefineParameters(baseMethod, method); + + ILGenerator localIL = baseMethod.GetILGenerator(); + + localIL.Emit(OpCodes.Ldarg_0); + // setup parameters for call + for (int i = 0; i < method.GetParameters().Length; i++) { - string methodId = GenerateMethodCacheFieldId(method); - - // generate proxy method - MethodBuilder baseMethod = typeBuilder.DefineMethod("proxy_" + methodId, - MethodAttributes.Public | MethodAttributes.HideBySig, - CallingConventions.Standard, - method.ReturnType, ReflectionUtils.GetParameterTypes(method)); - - DefineGenericParameters(baseMethod, method); - //DefineParameters(baseMethod, method); - - ILGenerator localIL = baseMethod.GetILGenerator(); - - localIL.Emit(OpCodes.Ldarg_0); - // setup parameters for call - for (int i = 0; i < method.GetParameters().Length; i++) - { - localIL.Emit(OpCodes.Ldarg_S, i + 1); - } - localIL.EmitCall(OpCodes.Call, method, null); - localIL.Emit(OpCodes.Ret); - - // create static field that will cache proxy method - onProxyTargetMethods.Add(methodId, method); - - onProxyTargetMethodCacheField = typeBuilder.DefineField( - methodId, typeof(MethodInfo), FieldAttributes.Private | FieldAttributes.Static); - - MakeGenericMethod(il, method, onProxyTargetMethodCacheField, genericOnProxyTargetMethod); + localIL.Emit(OpCodes.Ldarg_S, i + 1); } - } - /// - /// Calls target method directly. - /// - /// The IL generator to use. - /// The method to proxy. - /// - /// The interface definition of the method, if applicable. - /// - protected override void CallDirectProxiedMethod( - ILGenerator il, MethodInfo method, MethodInfo interfaceMethod) - { - CallDirectBaseMethod(il, method); + localIL.EmitCall(OpCodes.Call, method, null); + localIL.Emit(OpCodes.Ret); + + // create static field that will cache proxy method + onProxyTargetMethods.Add(methodId, method); + + onProxyTargetMethodCacheField = typeBuilder.DefineField( + methodId, typeof(MethodInfo), FieldAttributes.Private | FieldAttributes.Static); + + MakeGenericMethod(il, method, onProxyTargetMethodCacheField, genericOnProxyTargetMethod); } } + + /// + /// Calls target method directly. + /// + /// The IL generator to use. + /// The method to proxy. + /// + /// The interface definition of the method, if applicable. + /// + protected override void CallDirectProxiedMethod( + ILGenerator il, MethodInfo method, MethodInfo interfaceMethod) + { + CallDirectBaseMethod(il, method); + } } diff --git a/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/BaseCompositionAopProxy.cs b/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/BaseCompositionAopProxy.cs index 9ec14d0e..9f9ed19e 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/BaseCompositionAopProxy.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/BaseCompositionAopProxy.cs @@ -24,142 +24,147 @@ using System.Runtime.Serialization; #endregion -namespace Spring.Aop.Framework.DynamicProxy +namespace Spring.Aop.Framework.DynamicProxy; + +/// +/// Base class that each dynamic composition proxy has to extend. +/// +/// Aleksandar Seovic +/// Bruno Baia +[Serializable] +public abstract class BaseCompositionAopProxy : AdvisedProxy, IAopProxy, ISerializable { - /// - /// Base class that each dynamic composition proxy has to extend. - /// - /// Aleksandar Seovic - /// Bruno Baia - [Serializable] - public abstract class BaseCompositionAopProxy : AdvisedProxy, IAopProxy, ISerializable + #region Constructor (s) / Destructor + + /// + /// Default constructor. + /// + public BaseCompositionAopProxy() { - #region Constructor (s) / Destructor - - /// - /// Default constructor. - /// - public BaseCompositionAopProxy() - {} - - /// - /// Creates a new instance of the - /// class. - /// - /// The proxy configuration. - public BaseCompositionAopProxy(IAdvised advised) : base(advised) - { - base.Initialize(advised, this); - } - - /// - /// Deserialization constructor. - /// - /// Serialization data. - /// Serialization context. - protected BaseCompositionAopProxy(SerializationInfo info, StreamingContext context) : base(info, context) - {} - - /// - ///Populates a with the data needed to serialize the target object. - /// - void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) - { - base.GetObjectData(info, context); - } - - #endregion - - #region IAopProxy Members - - /// - /// Returns this proxy instance - /// - /// - object IAopProxy.GetProxy() - { - return this; - } - - #endregion - - #region Equal, HashCode and ToString overrides - - /// - /// Delegate to target object handling of equals method. - /// - /// The object to compare with the current target object - /// true if the specified Object is equal to the current target object; otherwise, false - public override bool Equals(object obj) - { - bool equals = false; - object target = m_targetSource.GetTarget(); - AdvisedProxy otherProxy = obj as AdvisedProxy; - object otherTarget = null; - if (otherProxy != null) - { - otherTarget = otherProxy.m_targetSource.GetTarget(); - if (target == null) - { - equals = (otherTarget == null); - } - else - { - equals = target.Equals(otherTarget); - } - } - else if (target == null) - { - equals = (obj == null); - } - else - { - equals = target.Equals(obj); - } - m_targetSource.ReleaseTarget(target); - if (otherProxy != null) - { - otherProxy.m_targetSource.ReleaseTarget(otherTarget); - } - return equals; - } - - /// - /// Delgate to the target object generation of the hash code. - /// - /// A hash code for the target object. - public override int GetHashCode() - { - int hashCode = 0; - object target = m_targetSource.GetTarget(); - if (target != null) - { - hashCode = target.GetHashCode(); - } - m_targetSource.ReleaseTarget(target); - return hashCode; - } - - /// - /// Returns a String the represents the target object. - /// - /// A String that represents the target object - public override string ToString() - { - string str; - object target = m_targetSource.GetTarget(); - if (target != null) - { - str = target.ToString(); - } - else - { - str = base.ToString(); - } - m_targetSource.ReleaseTarget(target); - return str; - } - - #endregion } + + /// + /// Creates a new instance of the + /// class. + /// + /// The proxy configuration. + public BaseCompositionAopProxy(IAdvised advised) : base(advised) + { + base.Initialize(advised, this); + } + + /// + /// Deserialization constructor. + /// + /// Serialization data. + /// Serialization context. + protected BaseCompositionAopProxy(SerializationInfo info, StreamingContext context) : base(info, context) + { + } + + /// + ///Populates a with the data needed to serialize the target object. + /// + void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) + { + base.GetObjectData(info, context); + } + + #endregion + + #region IAopProxy Members + + /// + /// Returns this proxy instance + /// + /// + object IAopProxy.GetProxy() + { + return this; + } + + #endregion + + #region Equal, HashCode and ToString overrides + + /// + /// Delegate to target object handling of equals method. + /// + /// The object to compare with the current target object + /// true if the specified Object is equal to the current target object; otherwise, false + public override bool Equals(object obj) + { + bool equals = false; + object target = m_targetSource.GetTarget(); + AdvisedProxy otherProxy = obj as AdvisedProxy; + object otherTarget = null; + if (otherProxy != null) + { + otherTarget = otherProxy.m_targetSource.GetTarget(); + if (target == null) + { + equals = (otherTarget == null); + } + else + { + equals = target.Equals(otherTarget); + } + } + else if (target == null) + { + equals = (obj == null); + } + else + { + equals = target.Equals(obj); + } + + m_targetSource.ReleaseTarget(target); + if (otherProxy != null) + { + otherProxy.m_targetSource.ReleaseTarget(otherTarget); + } + + return equals; + } + + /// + /// Delgate to the target object generation of the hash code. + /// + /// A hash code for the target object. + public override int GetHashCode() + { + int hashCode = 0; + object target = m_targetSource.GetTarget(); + if (target != null) + { + hashCode = target.GetHashCode(); + } + + m_targetSource.ReleaseTarget(target); + return hashCode; + } + + /// + /// Returns a String the represents the target object. + /// + /// A String that represents the target object + public override string ToString() + { + string str; + object target = m_targetSource.GetTarget(); + if (target != null) + { + str = target.ToString(); + } + else + { + str = base.ToString(); + } + + m_targetSource.ReleaseTarget(target); + return str; + } + + #endregion } diff --git a/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/CachedAopProxyFactory.cs b/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/CachedAopProxyFactory.cs index 14a0fbee..f45de77c 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/CachedAopProxyFactory.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/CachedAopProxyFactory.cs @@ -27,184 +27,193 @@ using Spring.Proxy; #endregion -namespace Spring.Aop.Framework.DynamicProxy +namespace Spring.Aop.Framework.DynamicProxy; + +/// +/// Implementation of the +/// interface that caches the AOP proxy instance. +/// +/// +///

+/// Caches against a key based on : +/// - the base type +/// - the target type +/// - the interfaces to proxy +///

+///
+/// Bruno Baia +/// Erich Eichinger +/// +/// +[Serializable] +public class CachedAopProxyFactory : DefaultAopProxyFactory { /// - /// Implementation of the - /// interface that caches the AOP proxy instance. + /// The shared instance for this class. /// - /// - ///

- /// Caches against a key based on : - /// - the base type - /// - the target type - /// - the interfaces to proxy - ///

- ///
- /// Bruno Baia - /// Erich Eichinger - /// - /// - [Serializable] - public class CachedAopProxyFactory : DefaultAopProxyFactory + private static readonly ILogger logger = LogManager.GetLogger(); + + private static readonly Hashtable typeCache = new Hashtable(); + + /// + /// Returns the number of proxy types in the cache + /// + public static int CountCachedTypes { - /// - /// The shared instance for this class. - /// - private static readonly ILogger logger = LogManager.GetLogger(); + get { return typeCache.Count; } + } - private static readonly Hashtable typeCache = new Hashtable(); + /// + /// Clears the type cache + /// + public static void ClearCache() + { + typeCache.Clear(); + } - /// - /// Returns the number of proxy types in the cache - /// - public static int CountCachedTypes + /// + /// Creates a new instance + /// + public CachedAopProxyFactory() + { + } + + /// + /// Generates the proxy type and caches the + /// instance against the base type and the interfaces to proxy. + /// + /// + /// The to use + /// + /// The generated or cached proxy class. + protected override Type BuildProxyType(IProxyTypeBuilder typeBuilder) + { + ProxyTypeCacheKey cacheKey = new ProxyTypeCacheKey( + typeBuilder.BaseType, typeBuilder.TargetType, typeBuilder.Interfaces, typeBuilder.ProxyTargetAttributes); + Type proxyType = null; + lock (typeCache) { - get { return typeCache.Count; } + proxyType = typeCache[cacheKey] as Type; + if (proxyType == null) + { + proxyType = typeBuilder.BuildProxyType(); + typeCache[cacheKey] = proxyType; + } + else + { + #region Instrumentation + + if (logger.IsEnabled(LogLevel.Debug)) + { + logger.LogDebug("AOP proxy type found in cache for {CacheKey}", cacheKey); + } + + #endregion + } } - /// - /// Clears the type cache - /// - public static void ClearCache() + return proxyType; + } + + #region ProxyTypeCacheKey inner class implementation + + /// + /// Uniquely identifies a proxytype in the cache + /// + private sealed class ProxyTypeCacheKey + { + private sealed class HashCodeComparer : IComparer { - typeCache.Clear(); + public int Compare(Type x, Type y) + { + return x.GetHashCode().CompareTo(y.GetHashCode()); + } } - /// - /// Creates a new instance - /// - public CachedAopProxyFactory() - {} + private static HashCodeComparer interfaceComparer = new HashCodeComparer(); - /// - /// Generates the proxy type and caches the - /// instance against the base type and the interfaces to proxy. - /// - /// - /// The to use - /// - /// The generated or cached proxy class. - protected override Type BuildProxyType(IProxyTypeBuilder typeBuilder) + private Type baseType; + private Type targetType; + private List interfaceTypes; + private bool proxyTargetAttributes; + + public ProxyTypeCacheKey(Type baseType, Type targetType, IList interfaceTypes, bool proxyTargetAttributes) { - ProxyTypeCacheKey cacheKey = new ProxyTypeCacheKey( - typeBuilder.BaseType, typeBuilder.TargetType, typeBuilder.Interfaces, typeBuilder.ProxyTargetAttributes); - Type proxyType = null; - lock (typeCache) - { - proxyType = typeCache[cacheKey] as Type; - if (proxyType == null) - { - proxyType = typeBuilder.BuildProxyType(); - typeCache[cacheKey] = proxyType; - } - else - { - #region Instrumentation - - if (logger.IsEnabled(LogLevel.Debug)) - { - logger.LogDebug("AOP proxy type found in cache for {CacheKey}", cacheKey); - } - - #endregion - } - } - return proxyType; + this.baseType = baseType; + this.targetType = targetType; + this.interfaceTypes = new List(interfaceTypes); + this.interfaceTypes.Sort(interfaceComparer); // sort by GetHashcode()? to have a defined order + this.proxyTargetAttributes = proxyTargetAttributes; } - #region ProxyTypeCacheKey inner class implementation - - /// - /// Uniquely identifies a proxytype in the cache - /// - private sealed class ProxyTypeCacheKey + public override bool Equals(object obj) { - private sealed class HashCodeComparer : IComparer + if (this == obj) { - public int Compare(Type x, Type y) - { - return x.GetHashCode().CompareTo(y.GetHashCode()); - } - } - - private static HashCodeComparer interfaceComparer = new HashCodeComparer(); - - private Type baseType; - private Type targetType; - private List interfaceTypes; - private bool proxyTargetAttributes; - - public ProxyTypeCacheKey(Type baseType, Type targetType, IList interfaceTypes, bool proxyTargetAttributes) - { - this.baseType = baseType; - this.targetType = targetType; - this.interfaceTypes = new List(interfaceTypes); - this.interfaceTypes.Sort(interfaceComparer); // sort by GetHashcode()? to have a defined order - this.proxyTargetAttributes = proxyTargetAttributes; - } - - public override bool Equals(object obj) - { - if (this == obj) - { - return true; - } - ProxyTypeCacheKey proxyTypeCacheKey = obj as ProxyTypeCacheKey; - if (proxyTypeCacheKey == null) - { - return false; - } - if (!Equals(targetType, proxyTypeCacheKey.targetType)) - { - return false; - } - if (!Equals(baseType, proxyTypeCacheKey.baseType)) - { - return false; - } - for (int i = 0; i < interfaceTypes.Count; i++) - { - if (!Equals(interfaceTypes[i], proxyTypeCacheKey.interfaceTypes[i])) - { - return false; - } - } - if (proxyTargetAttributes != proxyTypeCacheKey.proxyTargetAttributes) - { - return false; - } return true; } - public override int GetHashCode() + ProxyTypeCacheKey proxyTypeCacheKey = obj as ProxyTypeCacheKey; + if (proxyTypeCacheKey == null) { - int result = baseType.GetHashCode(); - result = 29*result + targetType.GetHashCode(); - for (int i = 0; i < interfaceTypes.Count; i++) - { - result = 29 * result + interfaceTypes[i].GetHashCode(); - } - result = 29 * result + proxyTargetAttributes.GetHashCode(); - return result; + return false; } - public override string ToString() + if (!Equals(targetType, proxyTypeCacheKey.targetType)) { - StringBuilder buffer = new StringBuilder(); - buffer.Append("baseType=" + baseType + "; "); - buffer.Append("targetType=" + targetType + "; "); - buffer.Append("interfaceTypes=["); - foreach (Type intf in interfaceTypes) - { - buffer.Append(intf + ";"); - } - buffer.Append("]; "); - buffer.Append("proxyTargetAttributes=" + proxyTargetAttributes + "; "); - return buffer.ToString(); + return false; } + + if (!Equals(baseType, proxyTypeCacheKey.baseType)) + { + return false; + } + + for (int i = 0; i < interfaceTypes.Count; i++) + { + if (!Equals(interfaceTypes[i], proxyTypeCacheKey.interfaceTypes[i])) + { + return false; + } + } + + if (proxyTargetAttributes != proxyTypeCacheKey.proxyTargetAttributes) + { + return false; + } + + return true; } - #endregion + public override int GetHashCode() + { + int result = baseType.GetHashCode(); + result = 29 * result + targetType.GetHashCode(); + for (int i = 0; i < interfaceTypes.Count; i++) + { + result = 29 * result + interfaceTypes[i].GetHashCode(); + } + + result = 29 * result + proxyTargetAttributes.GetHashCode(); + return result; + } + + public override string ToString() + { + StringBuilder buffer = new StringBuilder(); + buffer.Append("baseType=" + baseType + "; "); + buffer.Append("targetType=" + targetType + "; "); + buffer.Append("interfaceTypes=["); + foreach (Type intf in interfaceTypes) + { + buffer.Append(intf + ";"); + } + + buffer.Append("]; "); + buffer.Append("proxyTargetAttributes=" + proxyTargetAttributes + "; "); + return buffer.ToString(); + } } + + #endregion } diff --git a/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/CompositionAopProxyTypeBuilder.cs b/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/CompositionAopProxyTypeBuilder.cs index 788e9f44..41960954 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/CompositionAopProxyTypeBuilder.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/CompositionAopProxyTypeBuilder.cs @@ -21,161 +21,159 @@ using System.Reflection; using System.Reflection.Emit; using System.Runtime.Serialization; - using Spring.Util; -namespace Spring.Aop.Framework.DynamicProxy +namespace Spring.Aop.Framework.DynamicProxy; + +/// +/// Builds an AOP proxy type using composition. +/// +/// Aleksandar Seovic +/// Bruno Baia +public class CompositionAopProxyTypeBuilder : AbstractAopProxyTypeBuilder { - /// - /// Builds an AOP proxy type using composition. - /// - /// Aleksandar Seovic - /// Bruno Baia - public class CompositionAopProxyTypeBuilder : AbstractAopProxyTypeBuilder + private const string PROXY_TYPE_NAME = "CompositionAopProxy"; + + private readonly IAdvised advised; + + /// + /// Creates a new instance of the + /// class. + /// + /// The proxy configuration. + public CompositionAopProxyTypeBuilder(IAdvised advised) { - private const string PROXY_TYPE_NAME = "CompositionAopProxy"; + this.advised = advised; - private readonly IAdvised advised; + Name = PROXY_TYPE_NAME; + BaseType = typeof(BaseCompositionAopProxy); + TargetType = advised.TargetSource.TargetType.IsInterface ? typeof(object) : advised.TargetSource.TargetType; + Interfaces = GetProxiableInterfaces(advised.Interfaces); + ProxyTargetAttributes = advised.ProxyTargetAttributes; + } - /// - /// Creates a new instance of the - /// class. - /// - /// The proxy configuration. - public CompositionAopProxyTypeBuilder(IAdvised advised) + /// + /// Creates the proxy type. + /// + /// The generated proxy type. + public override Type BuildProxyType() + { + Dictionary targetMethods = new Dictionary(); + + TypeBuilder typeBuilder = CreateTypeBuilder(Name, BaseType); + + // apply custom attributes to the proxy type. + ApplyTypeAttributes(typeBuilder, TargetType); + + if (advised.IsSerializable) { - this.advised = advised; - - Name = PROXY_TYPE_NAME; - BaseType = typeof(BaseCompositionAopProxy); - TargetType = advised.TargetSource.TargetType.IsInterface ? typeof(object) : advised.TargetSource.TargetType; - Interfaces = GetProxiableInterfaces(advised.Interfaces); - ProxyTargetAttributes = advised.ProxyTargetAttributes; + typeBuilder.SetCustomAttribute( + ReflectionUtils.CreateCustomAttribute(typeof(SerializableAttribute))); + ImplementSerializationConstructor(typeBuilder); } - /// - /// Creates the proxy type. - /// - /// The generated proxy type. - public override Type BuildProxyType() - { - Dictionary targetMethods = new Dictionary(); + // create constructors + ImplementConstructors(typeBuilder); - TypeBuilder typeBuilder = CreateTypeBuilder(Name, BaseType); - - // apply custom attributes to the proxy type. - ApplyTypeAttributes(typeBuilder, TargetType); - - if (advised.IsSerializable) + // implement interfaces + IDictionary interfaceMap = advised.InterfaceMap; + foreach (Type intf in Interfaces) + { + interfaceMap.TryGetValue(intf, out var target); + if (target is null) { - typeBuilder.SetCustomAttribute( - ReflectionUtils.CreateCustomAttribute(typeof(SerializableAttribute))); - ImplementSerializationConstructor(typeBuilder); + // implement interface + ImplementInterface(typeBuilder, + new TargetAopProxyMethodBuilder(typeBuilder, this, false, targetMethods), + intf, TargetType); + } + else if (target is IIntroductionAdvisor) + { + // implement introduction + ImplementInterface(typeBuilder, + new IntroductionProxyMethodBuilder(typeBuilder, this, targetMethods, advised.IndexOf((IIntroductionAdvisor) target)), + intf, TargetType); } - - // create constructors - ImplementConstructors(typeBuilder); - - // implement interfaces - IDictionary interfaceMap = advised.InterfaceMap; - foreach (Type intf in Interfaces) - { - interfaceMap.TryGetValue(intf, out var target); - if (target is null) - { - // implement interface - ImplementInterface(typeBuilder, - new TargetAopProxyMethodBuilder(typeBuilder, this, false, targetMethods), - intf, TargetType); - } - else if (target is IIntroductionAdvisor) - { - // implement introduction - ImplementInterface(typeBuilder, - new IntroductionProxyMethodBuilder(typeBuilder, this, targetMethods, advised.IndexOf((IIntroductionAdvisor) target)), - intf, TargetType); - } - } - - Type proxyType = typeBuilder.CreateTypeInfo(); - - // set target method references - foreach (KeyValuePair entry in targetMethods) - { - FieldInfo field = proxyType.GetField(entry.Key, BindingFlags.NonPublic | BindingFlags.Static); - field.SetValue(proxyType, entry.Value); - } - - return proxyType; - } - - /// - /// Generates the IL instructions that pushes - /// the current - /// instance on stack. - /// - /// The IL generator to use. - public override void PushAdvisedProxy(ILGenerator il) - { - il.Emit(OpCodes.Ldarg_0); } - /// - /// Implements serialization constructor. - /// - /// Type builder to use. - private void ImplementSerializationConstructor(TypeBuilder typeBuilder) - { - ConstructorBuilder cb = - typeBuilder.DefineConstructor(MethodAttributes.Family, - CallingConventions.Standard, - new Type[] { typeof(SerializationInfo), typeof(StreamingContext) }); + Type proxyType = typeBuilder.CreateTypeInfo(); - ILGenerator il = cb.GetILGenerator(); - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Ldarg_1); - il.Emit(OpCodes.Ldarg_2); - il.Emit(OpCodes.Call, References.BaseCompositionAopProxySerializationConstructor); - il.Emit(OpCodes.Ret); + // set target method references + foreach (KeyValuePair entry in targetMethods) + { + FieldInfo field = proxyType.GetField(entry.Key, BindingFlags.NonPublic | BindingFlags.Static); + field.SetValue(proxyType, entry.Value); } - /// - /// Implements constructors for the proxy class. - /// - /// - ///

- /// This implementation calls the base constructor. - ///

- ///
- /// - /// The builder to use. - /// - protected override void ImplementConstructors(TypeBuilder typeBuilder) - { - ConstructorBuilder cb = - typeBuilder.DefineConstructor(References.BaseCompositionAopProxyConstructor.Attributes, - References.BaseCompositionAopProxyConstructor.CallingConvention, - new Type[] { typeof(IAdvised) }); + return proxyType; + } - ILGenerator il = cb.GetILGenerator(); - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Ldarg_1); - il.Emit(OpCodes.Call, References.BaseCompositionAopProxyConstructor); - il.Emit(OpCodes.Ret); - } + /// + /// Generates the IL instructions that pushes + /// the current + /// instance on stack. + /// + /// The IL generator to use. + public override void PushAdvisedProxy(ILGenerator il) + { + il.Emit(OpCodes.Ldarg_0); + } - /// - /// Determines if the specified - /// is one of those generated by this builder. - /// - /// The type to check. - /// - /// if the type is a composition-based proxy; - /// otherwise . - /// - public static bool IsCompositionProxy(Type type) - { - return type.FullName.StartsWith(PROXY_TYPE_NAME); - } + /// + /// Implements serialization constructor. + /// + /// Type builder to use. + private void ImplementSerializationConstructor(TypeBuilder typeBuilder) + { + ConstructorBuilder cb = + typeBuilder.DefineConstructor(MethodAttributes.Family, + CallingConventions.Standard, + new Type[] { typeof(SerializationInfo), typeof(StreamingContext) }); + + ILGenerator il = cb.GetILGenerator(); + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldarg_1); + il.Emit(OpCodes.Ldarg_2); + il.Emit(OpCodes.Call, References.BaseCompositionAopProxySerializationConstructor); + il.Emit(OpCodes.Ret); + } + + /// + /// Implements constructors for the proxy class. + /// + /// + ///

+ /// This implementation calls the base constructor. + ///

+ ///
+ /// + /// The builder to use. + /// + protected override void ImplementConstructors(TypeBuilder typeBuilder) + { + ConstructorBuilder cb = + typeBuilder.DefineConstructor(References.BaseCompositionAopProxyConstructor.Attributes, + References.BaseCompositionAopProxyConstructor.CallingConvention, + new Type[] { typeof(IAdvised) }); + + ILGenerator il = cb.GetILGenerator(); + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldarg_1); + il.Emit(OpCodes.Call, References.BaseCompositionAopProxyConstructor); + il.Emit(OpCodes.Ret); + } + + /// + /// Determines if the specified + /// is one of those generated by this builder. + /// + /// The type to check. + /// + /// if the type is a composition-based proxy; + /// otherwise . + /// + public static bool IsCompositionProxy(Type type) + { + return type.FullName.StartsWith(PROXY_TYPE_NAME); } } diff --git a/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/DecoratorAopProxyTypeBuilder.cs b/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/DecoratorAopProxyTypeBuilder.cs index 72a9acbd..a4ff0a70 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/DecoratorAopProxyTypeBuilder.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/DecoratorAopProxyTypeBuilder.cs @@ -21,265 +21,264 @@ using System.Reflection; using System.Reflection.Emit; using System.Runtime.Serialization; - using Spring.Util; using Spring.Proxy; -namespace Spring.Aop.Framework.DynamicProxy +namespace Spring.Aop.Framework.DynamicProxy; + +/// +/// Builds an AOP proxy type using the decorator pattern. +/// +/// Bruno Baia +public class DecoratorAopProxyTypeBuilder : AbstractAopProxyTypeBuilder { + private const string PROXY_TYPE_NAME = "DecoratorAopProxy"; + + private IAdvised advised; + /// - /// Builds an AOP proxy type using the decorator pattern. + /// AdvisedProxy instance calls should be delegated to. /// - /// Bruno Baia - public class DecoratorAopProxyTypeBuilder : AbstractAopProxyTypeBuilder + protected FieldBuilder advisedProxyField; + + /// + /// Creates a new instance of the + /// class. + /// + /// The proxy configuration. + public DecoratorAopProxyTypeBuilder(IAdvised advised) { - private const string PROXY_TYPE_NAME = "DecoratorAopProxy"; - - private IAdvised advised; - - /// - /// AdvisedProxy instance calls should be delegated to. - /// - protected FieldBuilder advisedProxyField; - - /// - /// Creates a new instance of the - /// class. - /// - /// The proxy configuration. - public DecoratorAopProxyTypeBuilder(IAdvised advised) + if (!ReflectionUtils.IsTypeVisible(advised.TargetSource.TargetType, DynamicProxyManager.ASSEMBLY_NAME)) { - if (!ReflectionUtils.IsTypeVisible(advised.TargetSource.TargetType, DynamicProxyManager.ASSEMBLY_NAME)) + throw new AopConfigException(String.Format( + "Cannot create decorator-based IAopProxy for a non visible class [{0}]", + advised.TargetSource.TargetType.FullName)); + } + + if (advised.TargetSource.TargetType.IsSealed) + { + throw new AopConfigException(String.Format( + "Cannot create decorator-based IAopProxy for a sealed class [{0}]", + advised.TargetSource.TargetType.FullName)); + } + + this.advised = advised; + + Name = PROXY_TYPE_NAME; + TargetType = advised.TargetSource.TargetType.IsInterface ? typeof(object) : advised.TargetSource.TargetType; + BaseType = TargetType; + Interfaces = GetProxiableInterfaces(advised.Interfaces); + ProxyTargetAttributes = advised.ProxyTargetAttributes; + } + + /// + /// Creates the proxy type. + /// + /// The generated proxy class. + public override Type BuildProxyType() + { + var targetMethods = new Dictionary(); + + TypeBuilder typeBuilder = CreateTypeBuilder(Name, BaseType); + + // apply custom attributes to the proxy type. + ApplyTypeAttributes(typeBuilder, TargetType); + + // declare fields + DeclareAdvisedProxyInstanceField(typeBuilder); + + // implement ISerializable if possible + if (advised.IsSerializable) + { + typeBuilder.SetCustomAttribute( + ReflectionUtils.CreateCustomAttribute(typeof(SerializableAttribute))); + ImplementSerializationConstructor(typeBuilder); + ImplementGetObjectDataMethod(typeBuilder); + } + + // create constructors + ImplementConstructors(typeBuilder); + + // implement interfaces + var interfaceMap = advised.InterfaceMap; + foreach (Type intf in Interfaces) + { + interfaceMap.TryGetValue(intf, out var target); + if (target is null) { - throw new AopConfigException(String.Format( - "Cannot create decorator-based IAopProxy for a non visible class [{0}]", - advised.TargetSource.TargetType.FullName)); + // implement interface (proxy only final methods) + ImplementInterface(typeBuilder, + new TargetAopProxyMethodBuilder(typeBuilder, this, true, targetMethods), + intf, TargetType, false); } - if (advised.TargetSource.TargetType.IsSealed) + else if (target is IIntroductionAdvisor) { - throw new AopConfigException(String.Format( - "Cannot create decorator-based IAopProxy for a sealed class [{0}]", - advised.TargetSource.TargetType.FullName)); + // implement introduction + ImplementInterface(typeBuilder, + new IntroductionProxyMethodBuilder(typeBuilder, this, targetMethods, advised.IndexOf((IIntroductionAdvisor) target)), + intf, TargetType); } - this.advised = advised; - - Name = PROXY_TYPE_NAME; - TargetType = advised.TargetSource.TargetType.IsInterface ? typeof(object) : advised.TargetSource.TargetType; - BaseType = TargetType; - Interfaces = GetProxiableInterfaces(advised.Interfaces); - ProxyTargetAttributes = advised.ProxyTargetAttributes; } - /// - /// Creates the proxy type. - /// - /// The generated proxy class. - public override Type BuildProxyType() + // inherit from target type + InheritType(typeBuilder, + new TargetAopProxyMethodBuilder(typeBuilder, this, false, targetMethods), + TargetType); + + // implement IAdvised interface + ImplementInterface(typeBuilder, + new IAdvisedProxyMethodBuilder(typeBuilder, this), + typeof(IAdvised), TargetType); + + // implement IAopProxy interface + ImplementIAopProxy(typeBuilder); + + Type proxyType = typeBuilder.CreateTypeInfo(); + + // set target method references + foreach (var entry in targetMethods) { - var targetMethods = new Dictionary(); - - TypeBuilder typeBuilder = CreateTypeBuilder(Name, BaseType); - - // apply custom attributes to the proxy type. - ApplyTypeAttributes(typeBuilder, TargetType); - - // declare fields - DeclareAdvisedProxyInstanceField(typeBuilder); - - // implement ISerializable if possible - if (advised.IsSerializable) - { - typeBuilder.SetCustomAttribute( - ReflectionUtils.CreateCustomAttribute(typeof(SerializableAttribute))); - ImplementSerializationConstructor(typeBuilder); - ImplementGetObjectDataMethod(typeBuilder); - } - - // create constructors - ImplementConstructors(typeBuilder); - - // implement interfaces - var interfaceMap = advised.InterfaceMap; - foreach (Type intf in Interfaces) - { - interfaceMap.TryGetValue(intf, out var target); - if (target is null) - { - // implement interface (proxy only final methods) - ImplementInterface(typeBuilder, - new TargetAopProxyMethodBuilder(typeBuilder, this, true, targetMethods), - intf, TargetType, false); - } - else if (target is IIntroductionAdvisor) - { - // implement introduction - ImplementInterface(typeBuilder, - new IntroductionProxyMethodBuilder(typeBuilder, this, targetMethods, advised.IndexOf((IIntroductionAdvisor)target)), - intf, TargetType); - } - } - - // inherit from target type - InheritType(typeBuilder, - new TargetAopProxyMethodBuilder(typeBuilder, this, false, targetMethods), - TargetType); - - // implement IAdvised interface - ImplementInterface(typeBuilder, - new IAdvisedProxyMethodBuilder(typeBuilder, this), - typeof(IAdvised), TargetType); - - // implement IAopProxy interface - ImplementIAopProxy(typeBuilder); - - Type proxyType = typeBuilder.CreateTypeInfo(); - - // set target method references - foreach (var entry in targetMethods) - { - FieldInfo field = proxyType.GetField(entry.Key, BindingFlags.NonPublic | BindingFlags.Static); - field.SetValue(proxyType, entry.Value); - } - - return proxyType; + FieldInfo field = proxyType.GetField(entry.Key, BindingFlags.NonPublic | BindingFlags.Static); + field.SetValue(proxyType, entry.Value); } - /// - /// Generates the IL instructions that pushes - /// the current - /// instance on stack. - /// - /// The IL generator to use. - public override void PushAdvisedProxy(ILGenerator il) - { - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Ldfld, advisedProxyField); - } + return proxyType; + } - /// - /// Declares field that holds the - /// instance used by the proxy. - /// - /// - /// The builder to use for code generation. - /// - protected virtual void DeclareAdvisedProxyInstanceField(TypeBuilder builder) - { - advisedProxyField = builder.DefineField("__advisedProxy", typeof(AdvisedProxy), FieldAttributes.Private); - } + /// + /// Generates the IL instructions that pushes + /// the current + /// instance on stack. + /// + /// The IL generator to use. + public override void PushAdvisedProxy(ILGenerator il) + { + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldfld, advisedProxyField); + } - /// - /// Implements serialization method. - /// - /// - private void ImplementGetObjectDataMethod(TypeBuilder typeBuilder) - { - typeBuilder.AddInterfaceImplementation(typeof(ISerializable)); + /// + /// Declares field that holds the + /// instance used by the proxy. + /// + /// + /// The builder to use for code generation. + /// + protected virtual void DeclareAdvisedProxyInstanceField(TypeBuilder builder) + { + advisedProxyField = builder.DefineField("__advisedProxy", typeof(AdvisedProxy), FieldAttributes.Private); + } - MethodBuilder mb = - typeBuilder.DefineMethod("GetObjectData", - MethodAttributes.Public | MethodAttributes.HideBySig | - MethodAttributes.NewSlot | MethodAttributes.Virtual, - typeof (void), - new Type[] {typeof (SerializationInfo), typeof (StreamingContext)}); + /// + /// Implements serialization method. + /// + /// + private void ImplementGetObjectDataMethod(TypeBuilder typeBuilder) + { + typeBuilder.AddInterfaceImplementation(typeof(ISerializable)); - ILGenerator il = mb.GetILGenerator(); - il.Emit(OpCodes.Ldarg_1); - il.Emit(OpCodes.Ldstr, "advisedProxy"); - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Ldfld, advisedProxyField); - il.EmitCall(OpCodes.Callvirt, References.AddSerializationValue, null); - il.Emit(OpCodes.Ret); + MethodBuilder mb = + typeBuilder.DefineMethod("GetObjectData", + MethodAttributes.Public | MethodAttributes.HideBySig | + MethodAttributes.NewSlot | MethodAttributes.Virtual, + typeof(void), + new Type[] { typeof(SerializationInfo), typeof(StreamingContext) }); - //typeBuilder.DefineMethodOverride(mb, typeof(ISerializable).GetMethod("GetObjectData")); - } + ILGenerator il = mb.GetILGenerator(); + il.Emit(OpCodes.Ldarg_1); + il.Emit(OpCodes.Ldstr, "advisedProxy"); + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldfld, advisedProxyField); + il.EmitCall(OpCodes.Callvirt, References.AddSerializationValue, null); + il.Emit(OpCodes.Ret); + //typeBuilder.DefineMethodOverride(mb, typeof(ISerializable).GetMethod("GetObjectData")); + } - /// - /// Implements serialization constructor. - /// - /// Type builder to use. - private void ImplementSerializationConstructor(TypeBuilder typeBuilder) - { - ConstructorBuilder cb = - typeBuilder.DefineConstructor(MethodAttributes.Family, - CallingConventions.Standard, - new Type[] { typeof(SerializationInfo), typeof(StreamingContext) }); + /// + /// Implements serialization constructor. + /// + /// Type builder to use. + private void ImplementSerializationConstructor(TypeBuilder typeBuilder) + { + ConstructorBuilder cb = + typeBuilder.DefineConstructor(MethodAttributes.Family, + CallingConventions.Standard, + new Type[] { typeof(SerializationInfo), typeof(StreamingContext) }); - ILGenerator il = cb.GetILGenerator(); - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Ldarg_1); - il.Emit(OpCodes.Ldstr, "advisedProxy"); - il.Emit(OpCodes.Ldtoken, typeof(AdvisedProxy)); - il.EmitCall(OpCodes.Call, References.GetTypeFromHandle, null); - il.EmitCall(OpCodes.Callvirt, References.GetSerializationValue, null); - il.Emit(OpCodes.Castclass, typeof(AdvisedProxy)); - il.Emit(OpCodes.Stfld, advisedProxyField); - il.Emit(OpCodes.Ret); - } + ILGenerator il = cb.GetILGenerator(); + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldarg_1); + il.Emit(OpCodes.Ldstr, "advisedProxy"); + il.Emit(OpCodes.Ldtoken, typeof(AdvisedProxy)); + il.EmitCall(OpCodes.Call, References.GetTypeFromHandle, null); + il.EmitCall(OpCodes.Callvirt, References.GetSerializationValue, null); + il.Emit(OpCodes.Castclass, typeof(AdvisedProxy)); + il.Emit(OpCodes.Stfld, advisedProxyField); + il.Emit(OpCodes.Ret); + } - /// - /// Implements constructors for the proxy class. - /// - /// - ///

- /// This implementation creates a new instance - /// of the class. - ///

- ///
- /// - /// The builder to use. - /// - protected override void ImplementConstructors(TypeBuilder typeBuilder) - { - ConstructorBuilder cb = - typeBuilder.DefineConstructor(References.ObjectConstructor.Attributes, - References.ObjectConstructor.CallingConvention, - new Type[] { typeof(IAdvised) }); + /// + /// Implements constructors for the proxy class. + /// + /// + ///

+ /// This implementation creates a new instance + /// of the class. + ///

+ ///
+ /// + /// The builder to use. + /// + protected override void ImplementConstructors(TypeBuilder typeBuilder) + { + ConstructorBuilder cb = + typeBuilder.DefineConstructor(References.ObjectConstructor.Attributes, + References.ObjectConstructor.CallingConvention, + new Type[] { typeof(IAdvised) }); - ILGenerator il = cb.GetILGenerator(); - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Ldarg_1); - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Newobj, References.AdvisedProxyConstructor); - il.Emit(OpCodes.Stfld, advisedProxyField); - il.Emit(OpCodes.Ret); - } + ILGenerator il = cb.GetILGenerator(); + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldarg_1); + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Newobj, References.AdvisedProxyConstructor); + il.Emit(OpCodes.Stfld, advisedProxyField); + il.Emit(OpCodes.Ret); + } - /// - /// Implements interface. - /// - /// The type builder to use. - protected virtual void ImplementIAopProxy(TypeBuilder typeBuilder) - { - Type intf = typeof(IAopProxy); - MethodInfo getProxyMethod = intf.GetMethod("GetProxy", Type.EmptyTypes); + /// + /// Implements interface. + /// + /// The type builder to use. + protected virtual void ImplementIAopProxy(TypeBuilder typeBuilder) + { + Type intf = typeof(IAopProxy); + MethodInfo getProxyMethod = intf.GetMethod("GetProxy", Type.EmptyTypes); - typeBuilder.AddInterfaceImplementation(intf); + typeBuilder.AddInterfaceImplementation(intf); - MethodBuilder mb = typeBuilder.DefineMethod(typeof(IAdvised).FullName + "." + getProxyMethod.Name, - MethodAttributes.Private | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual | MethodAttributes.Final, - getProxyMethod.CallingConvention, getProxyMethod.ReturnType, Type.EmptyTypes); + MethodBuilder mb = typeBuilder.DefineMethod(typeof(IAdvised).FullName + "." + getProxyMethod.Name, + MethodAttributes.Private | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual | MethodAttributes.Final, + getProxyMethod.CallingConvention, getProxyMethod.ReturnType, Type.EmptyTypes); - ILGenerator il = mb.GetILGenerator(); - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Ret); + ILGenerator il = mb.GetILGenerator(); + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ret); - typeBuilder.DefineMethodOverride(mb, getProxyMethod); - } + typeBuilder.DefineMethodOverride(mb, getProxyMethod); + } - /// - /// Determines if the specified - /// is one of those generated by this builder. - /// - /// The type to check. - /// - /// if the type is a decorator-based proxy; - /// otherwise . - /// - public static bool IsDecoratorProxy(Type type) - { - return type.FullName.StartsWith(PROXY_TYPE_NAME); - } + /// + /// Determines if the specified + /// is one of those generated by this builder. + /// + /// The type to check. + /// + /// if the type is a decorator-based proxy; + /// otherwise . + /// + public static bool IsDecoratorProxy(Type type) + { + return type.FullName.StartsWith(PROXY_TYPE_NAME); } } diff --git a/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/DefaultAopProxyFactory.cs b/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/DefaultAopProxyFactory.cs index 7dde4460..dc137d8a 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/DefaultAopProxyFactory.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/DefaultAopProxyFactory.cs @@ -22,76 +22,77 @@ using System.Reflection; using Spring.Proxy; using Spring.Util; -namespace Spring.Aop.Framework.DynamicProxy +namespace Spring.Aop.Framework.DynamicProxy; + +/// +/// Default implementation of the +/// interface, +/// either creating a decorator-based dynamic proxy or +/// a composition-based dynamic proxy. +/// +/// +///

+/// Creates a decorator-base proxy if one the following is true : +/// - the "ProxyTargetType" property is set +/// - no interfaces have been specified +///

+///

+/// In general, specify "ProxyTargetType" to enforce a decorator-based proxy, +/// or specify one or more interfaces to use a composition-based proxy. +///

+///
+/// Rod Johnson +/// Aleksandar Seovic (.NET) +/// Bruno Baia (.NET) +/// Erich Eichinger (.NET) +/// +[Serializable] +public class DefaultAopProxyFactory : AbstractAopProxyFactory { /// - /// Default implementation of the - /// interface, - /// either creating a decorator-based dynamic proxy or - /// a composition-based dynamic proxy. + /// Force transient assemblies to be resolvable by . /// - /// - ///

- /// Creates a decorator-base proxy if one the following is true : - /// - the "ProxyTargetType" property is set - /// - no interfaces have been specified - ///

- ///

- /// In general, specify "ProxyTargetType" to enforce a decorator-based proxy, - /// or specify one or more interfaces to use a composition-based proxy. - ///

- ///
- /// Rod Johnson - /// Aleksandar Seovic (.NET) - /// Bruno Baia (.NET) - /// Erich Eichinger (.NET) - /// - [Serializable] - public class DefaultAopProxyFactory : AbstractAopProxyFactory + static DefaultAopProxyFactory() { - /// - /// Force transient assemblies to be resolvable by . - /// - static DefaultAopProxyFactory() - { - SystemUtils.RegisterLoadedAssemblyResolver(); - } + SystemUtils.RegisterLoadedAssemblyResolver(); + } - /// - /// Creates an actual proxy instance based on the supplied - /// - /// - /// - protected override IAopProxy DoCreateAopProxyInstance(AdvisedSupport advisedSupport) + /// + /// Creates an actual proxy instance based on the supplied + /// + /// + /// + protected override IAopProxy DoCreateAopProxyInstance(AdvisedSupport advisedSupport) + { + if (advisedSupport.ProxyType == null) { - if (advisedSupport.ProxyType == null) + IProxyTypeBuilder typeBuilder; + if ((advisedSupport.ProxyTargetType) || + (advisedSupport.Interfaces.Count == 0)) { - IProxyTypeBuilder typeBuilder; - if ((advisedSupport.ProxyTargetType) || - (advisedSupport.Interfaces.Count == 0)) - { - typeBuilder = new DecoratorAopProxyTypeBuilder(advisedSupport); - } - else - { - typeBuilder = new CompositionAopProxyTypeBuilder(advisedSupport); - } - advisedSupport.ProxyType = BuildProxyType(typeBuilder); - advisedSupport.ProxyConstructor = advisedSupport.ProxyType.GetConstructor(new Type[] { typeof(IAdvised) }); + typeBuilder = new DecoratorAopProxyTypeBuilder(advisedSupport); } - return (IAopProxy)advisedSupport.ProxyConstructor.Invoke(new object[] { advisedSupport }); + else + { + typeBuilder = new CompositionAopProxyTypeBuilder(advisedSupport); + } + + advisedSupport.ProxyType = BuildProxyType(typeBuilder); + advisedSupport.ProxyConstructor = advisedSupport.ProxyType.GetConstructor(new Type[] { typeof(IAdvised) }); } - /// - /// Generates the proxy type. - /// - /// - /// The to use - /// - /// The generated proxy class. - protected virtual Type BuildProxyType(IProxyTypeBuilder typeBuilder) - { - return typeBuilder.BuildProxyType(); - } + return (IAopProxy) advisedSupport.ProxyConstructor.Invoke(new object[] { advisedSupport }); + } + + /// + /// Generates the proxy type. + /// + /// + /// The to use + /// + /// The generated proxy class. + protected virtual Type BuildProxyType(IProxyTypeBuilder typeBuilder) + { + return typeBuilder.BuildProxyType(); } } diff --git a/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/IAdvisedProxyMethodBuilder.cs b/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/IAdvisedProxyMethodBuilder.cs index 7de3b874..44d39df1 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/IAdvisedProxyMethodBuilder.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/IAdvisedProxyMethodBuilder.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -21,59 +21,57 @@ #region Imports using System.Reflection.Emit; - using Spring.Proxy; #endregion -namespace Spring.Aop.Framework.DynamicProxy +namespace Spring.Aop.Framework.DynamicProxy; + +/// +/// implementation that delegates +/// method calls to an instance. +/// +/// Bruno Baia +public class IAdvisedProxyMethodBuilder : TargetProxyMethodBuilder { + #region Fields + /// - /// implementation that delegates - /// method calls to an instance. + /// The implementation to use. /// - /// Bruno Baia - public class IAdvisedProxyMethodBuilder : TargetProxyMethodBuilder + private IAopProxyTypeGenerator _aopProxyGenerator; + + #endregion + + #region Constructor(s) / Destructor + + /// + /// Creates a new instance of the method builder. + /// + /// The type builder to use. + /// + /// The implementation to use. + /// + public IAdvisedProxyMethodBuilder( + TypeBuilder typeBuilder, IAopProxyTypeGenerator aopProxyGenerator) + : base(typeBuilder, aopProxyGenerator, true) { - #region Fields - - /// - /// The implementation to use. - /// - private IAopProxyTypeGenerator _aopProxyGenerator; - - #endregion - - #region Constructor(s) / Destructor - - /// - /// Creates a new instance of the method builder. - /// - /// The type builder to use. - /// - /// The implementation to use. - /// - public IAdvisedProxyMethodBuilder( - TypeBuilder typeBuilder, IAopProxyTypeGenerator aopProxyGenerator) - : base(typeBuilder, aopProxyGenerator, true) - { - this._aopProxyGenerator = aopProxyGenerator; - } - - #endregion - - #region Protected Methods - - /// - /// Generates the IL instructions that pushes - /// the target instance on which calls should be delegated to. - /// - /// The IL generator to use. - protected override void PushTarget(ILGenerator il) - { - _aopProxyGenerator.PushAdvisedProxy(il); - } - - #endregion + this._aopProxyGenerator = aopProxyGenerator; } + + #endregion + + #region Protected Methods + + /// + /// Generates the IL instructions that pushes + /// the target instance on which calls should be delegated to. + /// + /// The IL generator to use. + protected override void PushTarget(ILGenerator il) + { + _aopProxyGenerator.PushAdvisedProxy(il); + } + + #endregion } diff --git a/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/IAopProxyTypeGenerator.cs b/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/IAopProxyTypeGenerator.cs index 42bf076a..965806bc 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/IAopProxyTypeGenerator.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/IAopProxyTypeGenerator.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -21,26 +21,24 @@ #region Imports using System.Reflection.Emit; - using Spring.Proxy; #endregion -namespace Spring.Aop.Framework.DynamicProxy +namespace Spring.Aop.Framework.DynamicProxy; + +/// +/// Describes the operations that generates IL instructions +/// used to build the Aop proxy type. +/// +/// Bruno Baia +public interface IAopProxyTypeGenerator : IProxyTypeGenerator { - /// - /// Describes the operations that generates IL instructions - /// used to build the Aop proxy type. - /// - /// Bruno Baia - public interface IAopProxyTypeGenerator : IProxyTypeGenerator - { - /// - /// Generates the IL instructions that pushes - /// the current - /// instance on stack. - /// - /// The IL generator to use. - void PushAdvisedProxy(ILGenerator il); - } -} \ No newline at end of file + /// + /// Generates the IL instructions that pushes + /// the current + /// instance on stack. + /// + /// The IL generator to use. + void PushAdvisedProxy(ILGenerator il); +} diff --git a/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/InheritanceAopProxyTypeBuilder.cs b/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/InheritanceAopProxyTypeBuilder.cs index 0664da06..effdcc62 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/InheritanceAopProxyTypeBuilder.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/InheritanceAopProxyTypeBuilder.cs @@ -21,315 +21,316 @@ using System.Runtime.Serialization; using System.Reflection; using System.Reflection.Emit; - using Spring.Proxy; using Spring.Util; -namespace Spring.Aop.Framework.DynamicProxy +namespace Spring.Aop.Framework.DynamicProxy; + +/// +/// Builds an AOP proxy type using inheritance. +/// +/// Bruno Baia +public class InheritanceAopProxyTypeBuilder : AbstractAopProxyTypeBuilder { + private const string PROXY_TYPE_NAME = "InheritanceAopProxy"; + + private IAdvised advised; + private bool proxyDeclaredMembersOnly = true; + /// - /// Builds an AOP proxy type using inheritance. + /// AdvisedProxy instance calls should be delegated to. /// - /// Bruno Baia - public class InheritanceAopProxyTypeBuilder : AbstractAopProxyTypeBuilder + protected FieldBuilder advisedProxyField; + + /// + /// Gets or sets a value indicating whether inherited members should be proxied. + /// + /// + /// if inherited members should be proxied; + /// otherwise, . + /// + public bool ProxyDeclaredMembersOnly { - private const string PROXY_TYPE_NAME = "InheritanceAopProxy"; + get { return proxyDeclaredMembersOnly; } + set { proxyDeclaredMembersOnly = value; } + } - private IAdvised advised; - private bool proxyDeclaredMembersOnly = true; - - /// - /// AdvisedProxy instance calls should be delegated to. - /// - protected FieldBuilder advisedProxyField; - - /// - /// Gets or sets a value indicating whether inherited members should be proxied. - /// - /// - /// if inherited members should be proxied; - /// otherwise, . - /// - public bool ProxyDeclaredMembersOnly + /// + /// Creates a new instance of the + /// class. + /// + /// The proxy configuration. + public InheritanceAopProxyTypeBuilder(IAdvised advised) + { + if (!ReflectionUtils.IsTypeVisible(advised.TargetSource.TargetType, DynamicProxyManager.ASSEMBLY_NAME)) { - get { return proxyDeclaredMembersOnly; } - set { proxyDeclaredMembersOnly = value; } + throw new AopConfigException(String.Format( + "Cannot create inheritance-based IAopProxy for a non visible class [{0}]", + advised.TargetSource.TargetType.FullName)); } - /// - /// Creates a new instance of the - /// class. - /// - /// The proxy configuration. - public InheritanceAopProxyTypeBuilder(IAdvised advised) + if (advised.TargetSource.TargetType.IsSealed) { - if (!ReflectionUtils.IsTypeVisible(advised.TargetSource.TargetType, DynamicProxyManager.ASSEMBLY_NAME)) + throw new AopConfigException(String.Format( + "Cannot create inheritance-based IAopProxy for a sealed class [{0}]", + advised.TargetSource.TargetType.FullName)); + } + + this.advised = advised; + + Name = PROXY_TYPE_NAME; + TargetType = advised.TargetSource.TargetType; + BaseType = TargetType; + Interfaces = GetProxiableInterfaces(advised.Interfaces); + ProxyTargetAttributes = advised.ProxyTargetAttributes; + } + + /// + /// Creates the proxy type. + /// + /// The generated proxy class. + public override Type BuildProxyType() + { + var targetMethods = new Dictionary(); + var proxyMethods = new Dictionary(); + + TypeBuilder typeBuilder = CreateTypeBuilder(Name, BaseType); + + // apply custom attributes to the proxy type. + ApplyTypeAttributes(typeBuilder, TargetType); + + // declare fields + DeclareAdvisedProxyInstanceField(typeBuilder); + + // implement ISerializable if possible + if (advised.IsSerializable) + { + typeBuilder.SetCustomAttribute( + ReflectionUtils.CreateCustomAttribute(typeof(SerializableAttribute))); + ImplementSerializationConstructor(typeBuilder); + ImplementGetObjectDataMethod(typeBuilder); + } + + // create constructors + ImplementConstructors(typeBuilder); + + // implement interfaces + var interfaceMap = advised.InterfaceMap; + foreach (Type intf in Interfaces) + { + object target = interfaceMap[intf]; + if (target == null) { - throw new AopConfigException(String.Format( - "Cannot create inheritance-based IAopProxy for a non visible class [{0}]", - advised.TargetSource.TargetType.FullName)); + // implement interface (proxy only final methods) + ImplementInterface(typeBuilder, + new BaseAopProxyMethodBuilder(typeBuilder, this, targetMethods, proxyMethods), + intf, TargetType, false); } - if (advised.TargetSource.TargetType.IsSealed) + else if (target is IIntroductionAdvisor) { - throw new AopConfigException(String.Format( - "Cannot create inheritance-based IAopProxy for a sealed class [{0}]", - advised.TargetSource.TargetType.FullName)); + // implement introduction + ImplementInterface(typeBuilder, + new IntroductionProxyMethodBuilder(typeBuilder, this, targetMethods, advised.IndexOf((IIntroductionAdvisor) target)), + intf, TargetType); } - this.advised = advised; - - Name = PROXY_TYPE_NAME; - TargetType = advised.TargetSource.TargetType; - BaseType = TargetType; - Interfaces = GetProxiableInterfaces(advised.Interfaces); - ProxyTargetAttributes = advised.ProxyTargetAttributes; } - /// - /// Creates the proxy type. - /// - /// The generated proxy class. - public override Type BuildProxyType() + // inherit from target type + InheritType(typeBuilder, + new BaseAopProxyMethodBuilder(typeBuilder, this, targetMethods, proxyMethods), + TargetType, ProxyDeclaredMembersOnly); + + // implement IAdvised interface + ImplementInterface(typeBuilder, + new IAdvisedProxyMethodBuilder(typeBuilder, this), + typeof(IAdvised), TargetType); + + // implement IAopProxy interface + ImplementIAopProxy(typeBuilder); + + Type proxyType; + proxyType = typeBuilder.CreateTypeInfo(); + + // set target method references + foreach (var entry in targetMethods) { - var targetMethods = new Dictionary(); - var proxyMethods = new Dictionary(); - - TypeBuilder typeBuilder = CreateTypeBuilder(Name, BaseType); - - // apply custom attributes to the proxy type. - ApplyTypeAttributes(typeBuilder, TargetType); - - // declare fields - DeclareAdvisedProxyInstanceField(typeBuilder); - - // implement ISerializable if possible - if (advised.IsSerializable) - { - typeBuilder.SetCustomAttribute( - ReflectionUtils.CreateCustomAttribute(typeof(SerializableAttribute))); - ImplementSerializationConstructor(typeBuilder); - ImplementGetObjectDataMethod(typeBuilder); - } - - // create constructors - ImplementConstructors(typeBuilder); - - // implement interfaces - var interfaceMap = advised.InterfaceMap; - foreach (Type intf in Interfaces) - { - object target = interfaceMap[intf]; - if (target == null) - { - // implement interface (proxy only final methods) - ImplementInterface(typeBuilder, - new BaseAopProxyMethodBuilder(typeBuilder, this, targetMethods, proxyMethods), - intf, TargetType, false); - } - else if (target is IIntroductionAdvisor) - { - // implement introduction - ImplementInterface(typeBuilder, - new IntroductionProxyMethodBuilder(typeBuilder, this, targetMethods, advised.IndexOf((IIntroductionAdvisor)target)), - intf, TargetType); - } - } - - // inherit from target type - InheritType(typeBuilder, - new BaseAopProxyMethodBuilder(typeBuilder, this, targetMethods, proxyMethods), - TargetType, ProxyDeclaredMembersOnly); - - // implement IAdvised interface - ImplementInterface(typeBuilder, - new IAdvisedProxyMethodBuilder(typeBuilder, this), - typeof(IAdvised), TargetType); - - // implement IAopProxy interface - ImplementIAopProxy(typeBuilder); - - Type proxyType; - proxyType = typeBuilder.CreateTypeInfo(); - - // set target method references - foreach (var entry in targetMethods) - { - FieldInfo field = proxyType.GetField(entry.Key, BindingFlags.NonPublic | BindingFlags.Static); - field.SetValue(proxyType, entry.Value); - } - - // set proxy method references - foreach (var entry in proxyMethods) - { - FieldInfo field = proxyType.GetField(entry.Key, BindingFlags.NonPublic | BindingFlags.Static); - MethodInfo proxyMethod = proxyType.GetMethod("proxy_" + entry.Key, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); - field.SetValue(proxyType, proxyMethod); - } - - return proxyType; + FieldInfo field = proxyType.GetField(entry.Key, BindingFlags.NonPublic | BindingFlags.Static); + field.SetValue(proxyType, entry.Value); } - /// - /// Generates the IL instructions that pushes - /// the target instance on which calls should be delegated to. - /// - /// The IL generator to use. - public override void PushTarget(ILGenerator il) + // set proxy method references + foreach (var entry in proxyMethods) { - il.Emit(OpCodes.Ldarg_0); + FieldInfo field = proxyType.GetField(entry.Key, BindingFlags.NonPublic | BindingFlags.Static); + MethodInfo proxyMethod = proxyType.GetMethod("proxy_" + entry.Key, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + field.SetValue(proxyType, proxyMethod); } - /// - /// Generates the IL instructions that pushes - /// the current - /// instance on stack. - /// - /// The IL generator to use. - public override void PushAdvisedProxy(ILGenerator il) + return proxyType; + } + + /// + /// Generates the IL instructions that pushes + /// the target instance on which calls should be delegated to. + /// + /// The IL generator to use. + public override void PushTarget(ILGenerator il) + { + il.Emit(OpCodes.Ldarg_0); + } + + /// + /// Generates the IL instructions that pushes + /// the current + /// instance on stack. + /// + /// The IL generator to use. + public override void PushAdvisedProxy(ILGenerator il) + { + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldfld, advisedProxyField); + } + + /// + /// Declares field that holds the + /// instance used by the proxy. + /// + /// + /// The builder to use for code generation. + /// + protected virtual void DeclareAdvisedProxyInstanceField(TypeBuilder builder) + { + advisedProxyField = builder.DefineField("__advisedProxy", typeof(AdvisedProxy), FieldAttributes.Private); + } + + /// + /// Implements serialization method. + /// + /// + private void ImplementGetObjectDataMethod(TypeBuilder typeBuilder) + { + typeBuilder.AddInterfaceImplementation(typeof(ISerializable)); + + MethodBuilder mb = + typeBuilder.DefineMethod("GetObjectData", + MethodAttributes.Public | MethodAttributes.HideBySig | + MethodAttributes.NewSlot | MethodAttributes.Virtual, + typeof(void), + new Type[] { typeof(SerializationInfo), typeof(StreamingContext) }); + + ILGenerator il = mb.GetILGenerator(); + il.Emit(OpCodes.Ldarg_1); + il.Emit(OpCodes.Ldstr, "advisedProxy"); + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldfld, advisedProxyField); + il.EmitCall(OpCodes.Callvirt, References.AddSerializationValue, null); + il.Emit(OpCodes.Ret); + + //typeBuilder.DefineMethodOverride(mb, typeof(ISerializable).GetMethod("GetObjectData")); + } + + /// + /// Implements serialization constructor. + /// + /// Type builder to use. + private void ImplementSerializationConstructor(TypeBuilder typeBuilder) + { + ConstructorBuilder cb = + typeBuilder.DefineConstructor(MethodAttributes.Family, + CallingConventions.Standard, + new Type[] { typeof(SerializationInfo), typeof(StreamingContext) }); + + ILGenerator il = cb.GetILGenerator(); + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldarg_1); + il.Emit(OpCodes.Ldstr, "advisedProxy"); + il.Emit(OpCodes.Ldtoken, typeof(AdvisedProxy)); + il.EmitCall(OpCodes.Call, References.GetTypeFromHandle, null); + il.EmitCall(OpCodes.Callvirt, References.GetSerializationValue, null); + il.Emit(OpCodes.Castclass, typeof(AdvisedProxy)); + il.Emit(OpCodes.Stfld, advisedProxyField); + il.Emit(OpCodes.Ret); + } + + /// + /// Defines the types of the parameters for the specified constructor. + /// + /// The constructor to use. + /// The types for constructor's parameters. + protected override Type[] DefineConstructorParameters(ConstructorInfo constructor) + { + Type[] currentParams = ReflectionUtils.GetParameterTypes(constructor.GetParameters()); + Type[] newParams = new Type[currentParams.Length + 1]; + + newParams[currentParams.Length] = typeof(IAdvised); + currentParams.CopyTo(newParams, 0); + + return newParams; + } + + /// + /// Generates the proxy constructor. + /// + /// + ///

+ /// This implementation creates instance of the AdvisedProxy object. + ///

+ ///
+ /// The constructor builder to use. + /// The IL generator to use. + /// The constructor to delegate the creation to. + protected override void GenerateConstructor( + ConstructorBuilder builder, ILGenerator il, ConstructorInfo constructor) + { + int paramCount = constructor.GetParameters().Length; + il.Emit(OpCodes.Ldarg_0); + for (int i = 0; i < paramCount; i++) { - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Ldfld, advisedProxyField); + il.Emit(OpCodes.Ldarg_S, i + 1); } - /// - /// Declares field that holds the - /// instance used by the proxy. - /// - /// - /// The builder to use for code generation. - /// - protected virtual void DeclareAdvisedProxyInstanceField(TypeBuilder builder) - { - advisedProxyField = builder.DefineField("__advisedProxy", typeof(AdvisedProxy), FieldAttributes.Private); - } + il.Emit(OpCodes.Call, constructor); - /// - /// Implements serialization method. - /// - /// - private void ImplementGetObjectDataMethod(TypeBuilder typeBuilder) - { - typeBuilder.AddInterfaceImplementation(typeof(ISerializable)); + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldarg_S, paramCount + 1); + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Newobj, References.AdvisedProxyConstructor); + il.Emit(OpCodes.Stfld, advisedProxyField); + } - MethodBuilder mb = - typeBuilder.DefineMethod("GetObjectData", - MethodAttributes.Public | MethodAttributes.HideBySig | - MethodAttributes.NewSlot | MethodAttributes.Virtual, - typeof(void), - new Type[] { typeof(SerializationInfo), typeof(StreamingContext) }); + /// + /// Implements interface. + /// + /// The type builder to use. + protected virtual void ImplementIAopProxy(TypeBuilder typeBuilder) + { + Type intf = typeof(IAopProxy); + MethodInfo getProxyMethod = intf.GetMethod("GetProxy", Type.EmptyTypes); - ILGenerator il = mb.GetILGenerator(); - il.Emit(OpCodes.Ldarg_1); - il.Emit(OpCodes.Ldstr, "advisedProxy"); - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Ldfld, advisedProxyField); - il.EmitCall(OpCodes.Callvirt, References.AddSerializationValue, null); - il.Emit(OpCodes.Ret); + typeBuilder.AddInterfaceImplementation(intf); - //typeBuilder.DefineMethodOverride(mb, typeof(ISerializable).GetMethod("GetObjectData")); - } + MethodBuilder mb = typeBuilder.DefineMethod(typeof(IAdvised).FullName + "." + getProxyMethod.Name, + MethodAttributes.Private | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual | MethodAttributes.Final, + getProxyMethod.CallingConvention, getProxyMethod.ReturnType, Type.EmptyTypes); - /// - /// Implements serialization constructor. - /// - /// Type builder to use. - private void ImplementSerializationConstructor(TypeBuilder typeBuilder) - { - ConstructorBuilder cb = - typeBuilder.DefineConstructor(MethodAttributes.Family, - CallingConventions.Standard, - new Type[] { typeof(SerializationInfo), typeof(StreamingContext) }); + ILGenerator il = mb.GetILGenerator(); + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ret); - ILGenerator il = cb.GetILGenerator(); - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Ldarg_1); - il.Emit(OpCodes.Ldstr, "advisedProxy"); - il.Emit(OpCodes.Ldtoken, typeof(AdvisedProxy)); - il.EmitCall(OpCodes.Call, References.GetTypeFromHandle, null); - il.EmitCall(OpCodes.Callvirt, References.GetSerializationValue, null); - il.Emit(OpCodes.Castclass, typeof(AdvisedProxy)); - il.Emit(OpCodes.Stfld, advisedProxyField); - il.Emit(OpCodes.Ret); - } + typeBuilder.DefineMethodOverride(mb, getProxyMethod); + } - /// - /// Defines the types of the parameters for the specified constructor. - /// - /// The constructor to use. - /// The types for constructor's parameters. - protected override Type[] DefineConstructorParameters(ConstructorInfo constructor) - { - Type[] currentParams = ReflectionUtils.GetParameterTypes(constructor.GetParameters()); - Type[] newParams = new Type[currentParams.Length + 1]; - - newParams[currentParams.Length] = typeof(IAdvised); - currentParams.CopyTo(newParams, 0); - - return newParams; - } - - /// - /// Generates the proxy constructor. - /// - /// - ///

- /// This implementation creates instance of the AdvisedProxy object. - ///

- ///
- /// The constructor builder to use. - /// The IL generator to use. - /// The constructor to delegate the creation to. - protected override void GenerateConstructor( - ConstructorBuilder builder, ILGenerator il, ConstructorInfo constructor) - { - int paramCount = constructor.GetParameters().Length; - il.Emit(OpCodes.Ldarg_0); - for (int i = 0; i < paramCount; i++) - { - il.Emit(OpCodes.Ldarg_S, i + 1); - } - il.Emit(OpCodes.Call, constructor); - - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Ldarg_S, paramCount + 1); - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Newobj, References.AdvisedProxyConstructor); - il.Emit(OpCodes.Stfld, advisedProxyField); - } - - /// - /// Implements interface. - /// - /// The type builder to use. - protected virtual void ImplementIAopProxy(TypeBuilder typeBuilder) - { - Type intf = typeof(IAopProxy); - MethodInfo getProxyMethod = intf.GetMethod("GetProxy", Type.EmptyTypes); - - typeBuilder.AddInterfaceImplementation(intf); - - MethodBuilder mb = typeBuilder.DefineMethod(typeof(IAdvised).FullName + "." + getProxyMethod.Name, - MethodAttributes.Private | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual | MethodAttributes.Final, - getProxyMethod.CallingConvention, getProxyMethod.ReturnType, Type.EmptyTypes); - - ILGenerator il = mb.GetILGenerator(); - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Ret); - - typeBuilder.DefineMethodOverride(mb, getProxyMethod); - } - - /// - /// Determines if the specified - /// is one of those generated by this builder. - /// - /// The type to check. - /// - /// if the type is a inheritance-based proxy; - /// otherwise . - /// - public static bool IsInheritanceProxy(Type type) - { - return type.FullName.StartsWith(PROXY_TYPE_NAME); - } + /// + /// Determines if the specified + /// is one of those generated by this builder. + /// + /// The type to check. + /// + /// if the type is a inheritance-based proxy; + /// otherwise . + /// + public static bool IsInheritanceProxy(Type type) + { + return type.FullName.StartsWith(PROXY_TYPE_NAME); } } diff --git a/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/IntroductionProxyMethodBuilder.cs b/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/IntroductionProxyMethodBuilder.cs index eaac84b2..38723567 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/IntroductionProxyMethodBuilder.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/IntroductionProxyMethodBuilder.cs @@ -21,76 +21,75 @@ using System.Reflection; using System.Reflection.Emit; -namespace Spring.Aop.Framework.DynamicProxy +namespace Spring.Aop.Framework.DynamicProxy; + +/// +/// implementation +/// that delegates method calls to introduction object. +/// +/// Aleksandar Seovic +/// Bruno Baia +public class IntroductionProxyMethodBuilder : AbstractAopProxyMethodBuilder { /// - /// implementation - /// that delegates method calls to introduction object. + /// The index of the introduction to delegate call to. /// - /// Aleksandar Seovic - /// Bruno Baia - public class IntroductionProxyMethodBuilder : AbstractAopProxyMethodBuilder + protected int index; + + /// + /// Creates a new instance of the method builder. + /// + /// The type builder to use. + /// + /// The implementation to use. + /// + /// + /// + /// + /// index of the introduction to delegate call to + public IntroductionProxyMethodBuilder( + TypeBuilder typeBuilder, IAopProxyTypeGenerator aopProxyGenerator, + IDictionary targetMethods, int index) + : base(typeBuilder, aopProxyGenerator, true, targetMethods) { - /// - /// The index of the introduction to delegate call to. - /// - protected int index; + this.index = index; + } - /// - /// Creates a new instance of the method builder. - /// - /// The type builder to use. - /// - /// The implementation to use. - /// - /// - /// - /// - /// index of the introduction to delegate call to - public IntroductionProxyMethodBuilder( - TypeBuilder typeBuilder, IAopProxyTypeGenerator aopProxyGenerator, - IDictionary targetMethods, int index) - : base(typeBuilder, aopProxyGenerator, true, targetMethods) - { - this.index = index; - } + /// + /// Generates the IL instructions that pushes + /// the introduction type on stack. + /// + /// The IL generator to use. + protected override void PushTargetType(ILGenerator il) + { + PushTarget(il); + il.EmitCall(OpCodes.Call, References.GetTypeMethod, null); + } - /// - /// Generates the IL instructions that pushes - /// the introduction type on stack. - /// - /// The IL generator to use. - protected override void PushTargetType(ILGenerator il) - { - PushTarget(il); - il.EmitCall(OpCodes.Call, References.GetTypeMethod, null); - } + /// + /// Generates the IL instructions that pushes + /// the introduction instance on stack. + /// + /// The IL generator to use. + protected override void PushTarget(ILGenerator il) + { + PushAdvisedProxy(il); + il.Emit(OpCodes.Ldfld, References.IntroductionsField); + il.Emit(OpCodes.Ldc_I4, index); + il.Emit(OpCodes.Ldelem_Ref); + } - /// - /// Generates the IL instructions that pushes - /// the introduction instance on stack. - /// - /// The IL generator to use. - protected override void PushTarget(ILGenerator il) - { - PushAdvisedProxy(il); - il.Emit(OpCodes.Ldfld, References.IntroductionsField); - il.Emit(OpCodes.Ldc_I4, index); - il.Emit(OpCodes.Ldelem_Ref); - } - - /// - /// Calls proxied method directly. - /// - /// The IL generator to use. - /// The method to proxy. - /// - /// The interface definition of the method, if applicable. - /// - protected override void CallDirectProxiedMethod( - ILGenerator il, MethodInfo method, MethodInfo interfaceMethod) - { - CallDirectTargetMethod(il, interfaceMethod); - } + /// + /// Calls proxied method directly. + /// + /// The IL generator to use. + /// The method to proxy. + /// + /// The interface definition of the method, if applicable. + /// + protected override void CallDirectProxiedMethod( + ILGenerator il, MethodInfo method, MethodInfo interfaceMethod) + { + CallDirectTargetMethod(il, interfaceMethod); } } diff --git a/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/TargetAopProxyMethodBuilder.cs b/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/TargetAopProxyMethodBuilder.cs index 44f29965..d27c6224 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/TargetAopProxyMethodBuilder.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/TargetAopProxyMethodBuilder.cs @@ -21,106 +21,105 @@ using System.Reflection; using System.Reflection.Emit; -namespace Spring.Aop.Framework.DynamicProxy +namespace Spring.Aop.Framework.DynamicProxy; + +/// +/// implementation +/// that delegates method calls to target object. +/// +/// Aleksandar Seovic +/// Bruno Baia +public class TargetAopProxyMethodBuilder : AbstractAopProxyMethodBuilder { /// - /// implementation - /// that delegates method calls to target object. + /// The local variable to store the target instance. /// - /// Aleksandar Seovic - /// Bruno Baia - public class TargetAopProxyMethodBuilder : AbstractAopProxyMethodBuilder + protected LocalBuilder target; + + /// + /// Creates a new instance of the method builder. + /// + /// The type builder to use. + /// + /// The implementation to use. + /// + /// + /// if the interface is to be + /// implemented explicitly; otherwise . + /// + /// + /// The dictionary to cache the list of target + /// s. + /// + public TargetAopProxyMethodBuilder(TypeBuilder typeBuilder, + IAopProxyTypeGenerator aopProxyGenerator, bool explicitImplementation, IDictionary targetMethods) + : base(typeBuilder, aopProxyGenerator, explicitImplementation, targetMethods) { - /// - /// The local variable to store the target instance. - /// - protected LocalBuilder target; + } - /// - /// Creates a new instance of the method builder. - /// - /// The type builder to use. - /// - /// The implementation to use. - /// - /// - /// if the interface is to be - /// implemented explicitly; otherwise . - /// - /// - /// The dictionary to cache the list of target - /// s. - /// - public TargetAopProxyMethodBuilder(TypeBuilder typeBuilder, - IAopProxyTypeGenerator aopProxyGenerator, bool explicitImplementation, IDictionary targetMethods) - : base(typeBuilder, aopProxyGenerator, explicitImplementation, targetMethods) - { - } - - /// - /// Creates local variable declarations. - /// - /// The IL generator to use. - /// The method to proxy. - protected override void DeclareLocals(ILGenerator il, MethodInfo method) - { - base.DeclareLocals(il, method); - target = il.DeclareLocal(typeof(object)); + /// + /// Creates local variable declarations. + /// + /// The IL generator to use. + /// The method to proxy. + protected override void DeclareLocals(ILGenerator il, MethodInfo method) + { + base.DeclareLocals(il, method); + target = il.DeclareLocal(typeof(object)); #if DEBUG && !NETSTANDARD - target.SetLocalSymInfo("target"); + target.SetLocalSymInfo("target"); #endif - } + } - /// - /// Generates the IL instructions that pushes - /// the target instance on which calls should be delegated to. - /// - /// The IL generator to use. - protected override void PushTarget(ILGenerator il) - { - il.Emit(OpCodes.Ldloc, target); - } + /// + /// Generates the IL instructions that pushes + /// the target instance on which calls should be delegated to. + /// + /// The IL generator to use. + protected override void PushTarget(ILGenerator il) + { + il.Emit(OpCodes.Ldloc, target); + } - /// - /// Generates method logic. - /// - /// The IL generator to use. - /// The method to proxy. - /// - /// The interface definition of the method, if applicable. - /// - protected override void GenerateMethodLogic( - ILGenerator il, MethodInfo method, MethodInfo interfaceMethod) - { - PushAdvisedProxy(il); - il.Emit(OpCodes.Ldfld, References.TargetSourceField); - il.EmitCall(OpCodes.Callvirt, References.GetTargetMethod, null); - il.Emit(OpCodes.Stloc, target); + /// + /// Generates method logic. + /// + /// The IL generator to use. + /// The method to proxy. + /// + /// The interface definition of the method, if applicable. + /// + protected override void GenerateMethodLogic( + ILGenerator il, MethodInfo method, MethodInfo interfaceMethod) + { + PushAdvisedProxy(il); + il.Emit(OpCodes.Ldfld, References.TargetSourceField); + il.EmitCall(OpCodes.Callvirt, References.GetTargetMethod, null); + il.Emit(OpCodes.Stloc, target); - base.GenerateMethodLogic(il, method, interfaceMethod); + base.GenerateMethodLogic(il, method, interfaceMethod); - PushAdvisedProxy(il); - il.Emit(OpCodes.Ldfld, References.TargetSourceField); - PushTarget(il); - il.EmitCall(OpCodes.Callvirt, References.GetReleaseTargetMethod, null); - } + PushAdvisedProxy(il); + il.Emit(OpCodes.Ldfld, References.TargetSourceField); + PushTarget(il); + il.EmitCall(OpCodes.Callvirt, References.GetReleaseTargetMethod, null); + } - /// - /// Calls proxied method directly. - /// - /// The IL generator to use. - /// The method to proxy. - /// - /// The interface definition of the method, if applicable. - /// - protected override void CallDirectProxiedMethod( - ILGenerator il, MethodInfo method, MethodInfo interfaceMethod) - { - if (interfaceMethod != null) - CallDirectTargetMethod(il, interfaceMethod); - else - CallDirectTargetMethod(il, method); - } + /// + /// Calls proxied method directly. + /// + /// The IL generator to use. + /// The method to proxy. + /// + /// The interface definition of the method, if applicable. + /// + protected override void CallDirectProxiedMethod( + ILGenerator il, MethodInfo method, MethodInfo interfaceMethod) + { + if (interfaceMethod != null) + CallDirectTargetMethod(il, interfaceMethod); + else + CallDirectTargetMethod(il, method); } } diff --git a/src/Spring/Spring.Aop/Aop/Framework/HashtableCachingAdvisorChainFactory.cs b/src/Spring/Spring.Aop/Aop/Framework/HashtableCachingAdvisorChainFactory.cs index f15b3a36..be651284 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/HashtableCachingAdvisorChainFactory.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/HashtableCachingAdvisorChainFactory.cs @@ -21,89 +21,88 @@ using System.Reflection; using System.Runtime.Serialization; -namespace Spring.Aop.Framework +namespace Spring.Aop.Framework; + +/// +/// implementation +/// that caches advisor chains on a per-advised-method basis. +/// +/// Rod Johnson +/// Aleksandar Seovic (.NET) +[Serializable] +public sealed class HashtableCachingAdvisorChainFactory : IAdvisorChainFactory { - /// - /// implementation - /// that caches advisor chains on a per-advised-method basis. - /// - /// Rod Johnson - /// Aleksandar Seovic (.NET) - [Serializable] - public sealed class HashtableCachingAdvisorChainFactory : IAdvisorChainFactory + [NonSerialized] private Dictionary> methodCache = new Dictionary>(); + + [OnDeserializing] + private void OnDeserializing(StreamingContext c) { - [NonSerialized] - private Dictionary> methodCache = new Dictionary>(); + methodCache = new Dictionary>(); + } - [OnDeserializing] - private void OnDeserializing(StreamingContext c) + /// + /// Gets the list of and + /// + /// instances for the supplied . + /// + /// The proxy configuration object. + /// The object proxy. + /// + /// The method for which the interceptors are to be evaluated. + /// + /// + /// The of the target object. + /// + /// + /// The list of and + /// + /// instances for the supplied . + /// + public IList GetInterceptors(IAdvised advised, object proxy, MethodInfo method, Type targetType) + { + if (!methodCache.TryGetValue(method, out var interceptors)) { - methodCache = new Dictionary>(); - } - - /// - /// Gets the list of and - /// - /// instances for the supplied . - /// - /// The proxy configuration object. - /// The object proxy. - /// - /// The method for which the interceptors are to be evaluated. - /// - /// - /// The of the target object. - /// - /// - /// The list of and - /// - /// instances for the supplied . - /// - public IList GetInterceptors(IAdvised advised, object proxy, MethodInfo method, Type targetType) - { - if (!methodCache.TryGetValue(method, out var interceptors)) + lock (methodCache) { - lock (methodCache) + if (!methodCache.TryGetValue(method, out interceptors)) { - if (!methodCache.TryGetValue(method, out interceptors)) - { - interceptors = AdvisorChainFactoryUtils.CalculateInterceptors(advised, proxy, method, targetType); - methodCache[method] = interceptors; - } + interceptors = AdvisorChainFactoryUtils.CalculateInterceptors(advised, proxy, method, targetType); + methodCache[method] = interceptors; } } - return interceptors; } - /// - /// Invoked when the first proxy is created. - /// - /// - /// The relevant source. - /// - public void Activated(AdvisedSupport source) - { - } + return interceptors; + } - /// - /// Invoked when advice is changed after a proxy is created. - /// - /// - /// The relevant source. - /// - public void AdviceChanged(AdvisedSupport source) - { - methodCache.Clear(); - } + /// + /// Invoked when the first proxy is created. + /// + /// + /// The relevant source. + /// + public void Activated(AdvisedSupport source) + { + } - /// - /// Invoked when interfaces are changed after a proxy is created. - /// - /// - /// The relevant source. - /// - public void InterfacesChanged(AdvisedSupport source) - { - } + /// + /// Invoked when advice is changed after a proxy is created. + /// + /// + /// The relevant source. + /// + public void AdviceChanged(AdvisedSupport source) + { + methodCache.Clear(); + } + + /// + /// Invoked when interfaces are changed after a proxy is created. + /// + /// + /// The relevant source. + /// + public void InterfacesChanged(AdvisedSupport source) + { } } diff --git a/src/Spring/Spring.Aop/Aop/Framework/IAdvised.cs b/src/Spring/Spring.Aop/Aop/Framework/IAdvised.cs index e96ab0c4..e14c401c 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/IAdvised.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/IAdvised.cs @@ -19,474 +19,472 @@ #endregion using AopAlliance.Aop; - using Spring.Proxy; -namespace Spring.Aop.Framework +namespace Spring.Aop.Framework; + +/// +/// Configuration data for an AOP proxy factory. +/// +/// +///

+/// This configuration includes the +/// s, +/// s, and (any) proxied interfaces. +///

+///

+/// Any AOP proxy obtained from Spring.NET can be cast to this interface to +/// allow the manipulation of said proxy's AOP advice. +///

+///
+/// Rod Johnson +/// Aleksandar Seovic (.NET) +/// +[ProxyIgnore] +public interface IAdvised { /// - /// Configuration data for an AOP proxy factory. + /// Should proxies obtained from this configuration expose + /// the AOP proxy to the + /// class? /// /// ///

- /// This configuration includes the - /// s, - /// s, and (any) proxied interfaces. - ///

- ///

- /// Any AOP proxy obtained from Spring.NET can be cast to this interface to - /// allow the manipulation of said proxy's AOP advice. + /// This is useful if an advised object needs to call another advised + /// method on itself. (If it uses the this reference (Me + /// in Visual Basic.NET), the invocation will not be advised). ///

///
- /// Rod Johnson - /// Aleksandar Seovic (.NET) - /// - [ProxyIgnore] - public interface IAdvised - { - /// - /// Should proxies obtained from this configuration expose - /// the AOP proxy to the - /// class? - /// - /// - ///

- /// This is useful if an advised object needs to call another advised - /// method on itself. (If it uses the this reference (Me - /// in Visual Basic.NET), the invocation will not be advised). - ///

- ///
- bool ExposeProxy { get; } + bool ExposeProxy { get; } - /// - /// Gets the - /// - /// implementation that will be used to get the interceptor - /// chains for the advised - /// . - /// - /// - /// The - /// implementation that will be used to get the interceptor - /// chains for the advised - /// . - /// - IAdvisorChainFactory AdvisorChainFactory { get; } + /// + /// Gets the + /// + /// implementation that will be used to get the interceptor + /// chains for the advised + /// . + /// + /// + /// The + /// implementation that will be used to get the interceptor + /// chains for the advised + /// . + /// + IAdvisorChainFactory AdvisorChainFactory { get; } - /// - /// Is the target to be proxied in addition - /// to any interfaces declared on the proxied ? - /// - bool ProxyTargetType { get; } + /// + /// Is the target to be proxied in addition + /// to any interfaces declared on the proxied ? + /// + bool ProxyTargetType { get; } - /// - /// Is target type attributes, method attributes, method's return type attributes - /// and method's parameter attributes to be proxied in addition - /// to any interfaces declared on the proxied ? - /// - bool ProxyTargetAttributes { get; } + /// + /// Is target type attributes, method attributes, method's return type attributes + /// and method's parameter attributes to be proxied in addition + /// to any interfaces declared on the proxied ? + /// + bool ProxyTargetAttributes { get; } - /// - /// Returns the collection of - /// instances that have been applied to this proxy. - /// - /// - ///

- /// Will never return , but may return an - /// empty array (in the case where no - /// instances have been applied to - /// this proxy). - ///

- ///
- /// - /// The collection of - /// instances that have been applied to this proxy. - /// - IList Advisors { get; } + /// + /// Returns the collection of + /// instances that have been applied to this proxy. + /// + /// + ///

+ /// Will never return , but may return an + /// empty array (in the case where no + /// instances have been applied to + /// this proxy). + ///

+ ///
+ /// + /// The collection of + /// instances that have been applied to this proxy. + /// + IList Advisors { get; } - /// - /// Returns the collection of - /// instances that have been applied to this proxy. - /// - /// - ///

- /// Will never return , but may return an - /// empty array (in the case where no - /// instances have been - /// applied to this proxy). - ///

- ///
- /// - /// The collection of - /// instances that have been applied to this proxy. - /// - IList Introductions { get; } + /// + /// Returns the collection of + /// instances that have been applied to this proxy. + /// + /// + ///

+ /// Will never return , but may return an + /// empty array (in the case where no + /// instances have been + /// applied to this proxy). + ///

+ ///
+ /// + /// The collection of + /// instances that have been applied to this proxy. + /// + IList Introductions { get; } - /// - /// Returns the collection of interface s - /// to be (or that are being) proxied by this proxy. - /// - /// - /// The collection of interface s - /// to be (or that are being) proxied by this proxy. - /// - IList Interfaces { get; } + /// + /// Returns the collection of interface s + /// to be (or that are being) proxied by this proxy. + /// + /// + /// The collection of interface s + /// to be (or that are being) proxied by this proxy. + /// + IList Interfaces { get; } - /// - /// Returns the mapping of the proxied interface - /// s to their delegates. - /// - /// - /// The mapping of the proxied interface - /// s to their delegates. - /// - IDictionary InterfaceMap { get; } + /// + /// Returns the mapping of the proxied interface + /// s to their delegates. + /// + /// + /// The mapping of the proxied interface + /// s to their delegates. + /// + IDictionary InterfaceMap { get; } - /// - /// Is this configuration frozen? - /// - /// - ///

- /// When a config is frozen, no advice changes can be made. This is - /// useful for optimization, and useful when we don't want callers - /// to be able to manipulate configuration after casting to - /// . - ///

- ///
- bool IsFrozen { get; } + /// + /// Is this configuration frozen? + /// + /// + ///

+ /// When a config is frozen, no advice changes can be made. This is + /// useful for optimization, and useful when we don't want callers + /// to be able to manipulate configuration after casting to + /// . + ///

+ ///
+ bool IsFrozen { get; } - /// - /// Returns the used by this - /// object. - /// - /// - /// The used by this - /// object. - /// - ITargetSource TargetSource { get; } + /// + /// Returns the used by this + /// object. + /// + /// + /// The used by this + /// object. + /// + ITargetSource TargetSource { get; } - /// - /// Returns a boolean specifying if this - /// instance can be serialized. - /// - /// - /// true if this instance can be serialized, false otherwise. - /// - bool IsSerializable { get; } + /// + /// Returns a boolean specifying if this + /// instance can be serialized. + /// + /// + /// true if this instance can be serialized, false otherwise. + /// + bool IsSerializable { get; } - /// - /// Adds the supplied to the end (or tail) - /// of the advice (interceptor) chain. - /// - /// - ///

- /// Please be aware that Spring.NET's AOP implementation only supports - /// method advice (as encapsulated by the - /// interface). - ///

- ///
- /// - /// The to be added. - /// - /// - /// - void AddAdvice(IAdvice advice); + /// + /// Adds the supplied to the end (or tail) + /// of the advice (interceptor) chain. + /// + /// + ///

+ /// Please be aware that Spring.NET's AOP implementation only supports + /// method advice (as encapsulated by the + /// interface). + ///

+ ///
+ /// + /// The to be added. + /// + /// + /// + void AddAdvice(IAdvice advice); - /// - /// Adds the supplied to the supplied - /// in the advice (interceptor) chain. - /// - /// - ///

- /// Please be aware that Spring.NET's AOP implementation only supports - /// method advice (as encapsulated by the - /// interface). - ///

- ///
- /// - /// The zero (0) indexed position (from the head) at which the - /// supplied is to be inserted into the - /// advice (interceptor) chain. - /// - /// - /// The to be added. - /// - /// - /// - void AddAdvice(int position, IAdvice advice); + /// + /// Adds the supplied to the supplied + /// in the advice (interceptor) chain. + /// + /// + ///

+ /// Please be aware that Spring.NET's AOP implementation only supports + /// method advice (as encapsulated by the + /// interface). + ///

+ ///
+ /// + /// The zero (0) indexed position (from the head) at which the + /// supplied is to be inserted into the + /// advice (interceptor) chain. + /// + /// + /// The to be added. + /// + /// + /// + void AddAdvice(int position, IAdvice advice); - /// - /// Is the supplied (interface) - /// proxied? - /// - /// - /// The interface to test. - /// - /// - /// if the supplied - /// (interface) is proxied; - /// if not or the supplied - /// is . - /// - bool IsInterfaceProxied(Type intf); + /// + /// Is the supplied (interface) + /// proxied? + /// + /// + /// The interface to test. + /// + /// + /// if the supplied + /// (interface) is proxied; + /// if not or the supplied + /// is . + /// + bool IsInterfaceProxied(Type intf); - /// - /// Adds the advisors from the supplied - /// to the list of . - /// - /// - /// The to add advisors from. - /// - /// - /// If this proxy configuration is frozen and the - /// cannot be added. - /// - void AddAdvisors(IAdvisors advisors); + /// + /// Adds the advisors from the supplied + /// to the list of . + /// + /// + /// The to add advisors from. + /// + /// + /// If this proxy configuration is frozen and the + /// cannot be added. + /// + void AddAdvisors(IAdvisors advisors); - /// - /// Adds the supplied to the list - /// of . - /// - /// - /// The to add. - /// - /// - /// If this proxy configuration is frozen and the - /// cannot be added. - /// - void AddAdvisor(IAdvisor advisor); + /// + /// Adds the supplied to the list + /// of . + /// + /// + /// The to add. + /// + /// + /// If this proxy configuration is frozen and the + /// cannot be added. + /// + void AddAdvisor(IAdvisor advisor); - /// - /// Adds the supplied to the list - /// of . - /// - /// - /// The index in the - /// list at which the supplied - /// is to be inserted. - /// - /// - /// The to add. - /// - /// - /// If this proxy configuration is frozen and the - /// cannot be added. - /// - void AddAdvisor(int index, IAdvisor advisor); + /// + /// Adds the supplied to the list + /// of . + /// + /// + /// The index in the + /// list at which the supplied + /// is to be inserted. + /// + /// + /// The to add. + /// + /// + /// If this proxy configuration is frozen and the + /// cannot be added. + /// + void AddAdvisor(int index, IAdvisor advisor); - /// - /// Adds the supplied to the list - /// of . - /// - /// - /// The to add. - /// - /// - /// If this proxy configuration is frozen and the - /// cannot be added. - /// - void AddIntroduction(IIntroductionAdvisor introductionAdvisor); + /// + /// Adds the supplied to the list + /// of . + /// + /// + /// The to add. + /// + /// + /// If this proxy configuration is frozen and the + /// cannot be added. + /// + void AddIntroduction(IIntroductionAdvisor introductionAdvisor); - /// - /// Adds the supplied to the list - /// of . - /// - /// - /// The index in the - /// list at which the supplied - /// is to be inserted. - /// - /// - /// The to add. - /// - /// - /// If this proxy configuration is frozen and the - /// cannot be added. - /// - void AddIntroduction(int index, IIntroductionAdvisor introductionAdvisor); + /// + /// Adds the supplied to the list + /// of . + /// + /// + /// The index in the + /// list at which the supplied + /// is to be inserted. + /// + /// + /// The to add. + /// + /// + /// If this proxy configuration is frozen and the + /// cannot be added. + /// + void AddIntroduction(int index, IIntroductionAdvisor introductionAdvisor); - /// - /// Return the index (0 based) of the supplied - /// in the interceptor - /// (advice) chain for this proxy. - /// - /// - ///

- /// The return value of this method can be used to index into - /// the - /// list. - ///

- ///
- /// - /// The to search for. - /// - /// - /// The zero (0) based index of this advisor, or -1 if the - /// supplied is not an advisor for this - /// proxy. - /// - int IndexOf(IAdvisor advisor); + /// + /// Return the index (0 based) of the supplied + /// in the interceptor + /// (advice) chain for this proxy. + /// + /// + ///

+ /// The return value of this method can be used to index into + /// the + /// list. + ///

+ ///
+ /// + /// The to search for. + /// + /// + /// The zero (0) based index of this advisor, or -1 if the + /// supplied is not an advisor for this + /// proxy. + /// + int IndexOf(IAdvisor advisor); - /// - /// Return the index (0 based) of the supplied - /// in the introductions - /// for this proxy. - /// - /// - ///

- /// The return value of this method can be used to index into - /// the - /// list. - ///

- ///
- /// - /// The to search for. - /// - /// - /// The zero (0) based index of this advisor, or -1 if the - /// supplied is not an introduction advisor - /// for this proxy. - /// - int IndexOf(IIntroductionAdvisor advisor); + /// + /// Return the index (0 based) of the supplied + /// in the introductions + /// for this proxy. + /// + /// + ///

+ /// The return value of this method can be used to index into + /// the + /// list. + ///

+ ///
+ /// + /// The to search for. + /// + /// + /// The zero (0) based index of this advisor, or -1 if the + /// supplied is not an introduction advisor + /// for this proxy. + /// + int IndexOf(IIntroductionAdvisor advisor); - /// - /// Removes the supplied the list of advisors - /// for this proxy. - /// - /// The advisor to remove. - /// - /// if advisor was found in the list of - /// for this - /// proxy and was successfully removed; if not - /// or if the supplied is . - /// - /// - /// If this proxy configuration is frozen and the - /// cannot be removed. - /// - bool RemoveAdvisor(IAdvisor advisor); + /// + /// Removes the supplied the list of advisors + /// for this proxy. + /// + /// The advisor to remove. + /// + /// if advisor was found in the list of + /// for this + /// proxy and was successfully removed; if not + /// or if the supplied is . + /// + /// + /// If this proxy configuration is frozen and the + /// cannot be removed. + /// + bool RemoveAdvisor(IAdvisor advisor); - /// - /// Removes the at the supplied - /// in the - /// list - /// from the list of - /// for this proxy. - /// - /// - /// The index of the to remove. - /// - /// - /// If this proxy configuration is frozen and the - /// at the supplied - /// cannot be removed; or if the supplied is out of - /// range. - /// - void RemoveAdvisor(int index); + /// + /// Removes the at the supplied + /// in the + /// list + /// from the list of + /// for this proxy. + /// + /// + /// The index of the to remove. + /// + /// + /// If this proxy configuration is frozen and the + /// at the supplied + /// cannot be removed; or if the supplied is out of + /// range. + /// + void RemoveAdvisor(int index); - /// - /// Removes the supplied from the list - /// of . - /// - /// - /// The to remove. - /// - /// - /// if the supplied was - /// found in the list of - /// and successfully removed. - /// - /// - /// If this proxy configuration is frozen and the - /// cannot be removed. - /// - bool RemoveAdvice(IAdvice advice); + /// + /// Removes the supplied from the list + /// of . + /// + /// + /// The to remove. + /// + /// + /// if the supplied was + /// found in the list of + /// and successfully removed. + /// + /// + /// If this proxy configuration is frozen and the + /// cannot be removed. + /// + bool RemoveAdvice(IAdvice advice); - /// - /// Removes the supplied from the list - /// of . - /// - /// - /// The to remove. - /// - /// - /// if the supplied was - /// found in the list of - /// and successfully removed. - /// - /// - /// If this proxy configuration is frozen and the - /// cannot be removed. - /// - bool RemoveIntroduction(IIntroductionAdvisor introduction); + /// + /// Removes the supplied from the list + /// of . + /// + /// + /// The to remove. + /// + /// + /// if the supplied was + /// found in the list of + /// and successfully removed. + /// + /// + /// If this proxy configuration is frozen and the + /// cannot be removed. + /// + bool RemoveIntroduction(IIntroductionAdvisor introduction); - /// - /// Removes the at the supplied - /// in the list of - /// for this proxy. - /// - /// The index of the advisor to remove. - /// - /// - /// If this proxy configuration is frozen and the - /// at the supplied - /// cannot be removed; or if the supplied - /// is out of range. - /// - void RemoveIntroduction(int index); + /// + /// Removes the at the supplied + /// in the list of + /// for this proxy. + /// + /// The index of the advisor to remove. + /// + /// + /// If this proxy configuration is frozen and the + /// at the supplied + /// cannot be removed; or if the supplied + /// is out of range. + /// + void RemoveIntroduction(int index); - /// - /// Replaces the that - /// exists at the supplied in the list of - /// - /// with the supplied . - /// - /// - /// The index of the - /// in the list of - /// - /// that is to be replaced. - /// - /// - /// The new (replacement) . - /// - /// - /// If the supplied is out of range. - /// - void ReplaceIntroduction(int index, IIntroductionAdvisor introduction); + /// + /// Replaces the that + /// exists at the supplied in the list of + /// + /// with the supplied . + /// + /// + /// The index of the + /// in the list of + /// + /// that is to be replaced. + /// + /// + /// The new (replacement) . + /// + /// + /// If the supplied is out of range. + /// + void ReplaceIntroduction(int index, IIntroductionAdvisor introduction); - /// - /// Replaces the with the - /// . - /// - /// - /// The original (old) advisor to be replaced. - /// - /// - /// The new advisor to replace the with. - /// - /// - /// if the was - /// replaced; if the was not found in the - /// advisors collection, this method returns - /// and (effectively) does nothing. - /// - /// - /// If this proxy configuration is frozen and the - /// cannot be replaced. - /// - /// - bool ReplaceAdvisor(IAdvisor oldAdvisor, IAdvisor newAdvisor); + /// + /// Replaces the with the + /// . + /// + /// + /// The original (old) advisor to be replaced. + /// + /// + /// The new advisor to replace the with. + /// + /// + /// if the was + /// replaced; if the was not found in the + /// advisors collection, this method returns + /// and (effectively) does nothing. + /// + /// + /// If this proxy configuration is frozen and the + /// cannot be replaced. + /// + /// + bool ReplaceAdvisor(IAdvisor oldAdvisor, IAdvisor newAdvisor); - /// - /// As will normally be passed - /// straight through to the advised target, this method returns the - /// equivalent for the AOP - /// proxy itself. - /// - /// - /// A description of the proxy configuration. - /// - string ToProxyConfigString(); - } + /// + /// As will normally be passed + /// straight through to the advised target, this method returns the + /// equivalent for the AOP + /// proxy itself. + /// + /// + /// A description of the proxy configuration. + /// + string ToProxyConfigString(); } diff --git a/src/Spring/Spring.Aop/Aop/Framework/IAdvisedSupportListener.cs b/src/Spring/Spring.Aop/Aop/Framework/IAdvisedSupportListener.cs index 8ad1ee2e..d02ae011 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/IAdvisedSupportListener.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/IAdvisedSupportListener.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -18,46 +18,45 @@ #endregion -namespace Spring.Aop.Framework +namespace Spring.Aop.Framework; + +/// +/// Callback interface for +/// listeners. +/// +/// +///

+/// Allows +/// implementations to be notified of notable lifecycle events relating +/// to the creation of a proxy, and changes to the configuration data of a +/// proxy. +///

+///
+/// Rod Johnson +/// Aleksandar Seovic (.NET) +public interface IAdvisedSupportListener { - /// - /// Callback interface for - /// listeners. - /// - /// - ///

- /// Allows - /// implementations to be notified of notable lifecycle events relating - /// to the creation of a proxy, and changes to the configuration data of a - /// proxy. - ///

- ///
- /// Rod Johnson - /// Aleksandar Seovic (.NET) - public interface IAdvisedSupportListener - { - /// - /// Invoked when the first proxy is created. - /// - /// - /// The relevant source. - /// - void Activated(AdvisedSupport source); + /// + /// Invoked when the first proxy is created. + /// + /// + /// The relevant source. + /// + void Activated(AdvisedSupport source); - /// - /// Invoked when advice is changed after a proxy is created. - /// - /// - /// The relevant source. - /// - void AdviceChanged(AdvisedSupport source); + /// + /// Invoked when advice is changed after a proxy is created. + /// + /// + /// The relevant source. + /// + void AdviceChanged(AdvisedSupport source); - /// - /// Invoked when interfaces are changed after a proxy is created. - /// - /// - /// The relevant source. - /// - void InterfacesChanged(AdvisedSupport source); - } -} \ No newline at end of file + /// + /// Invoked when interfaces are changed after a proxy is created. + /// + /// + /// The relevant source. + /// + void InterfacesChanged(AdvisedSupport source); +} diff --git a/src/Spring/Spring.Aop/Aop/Framework/IAdvisorChainFactory.cs b/src/Spring/Spring.Aop/Aop/Framework/IAdvisorChainFactory.cs index 8e93b624..5bd4d218 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/IAdvisorChainFactory.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/IAdvisorChainFactory.cs @@ -24,33 +24,32 @@ using System.Reflection; #endregion -namespace Spring.Aop.Framework +namespace Spring.Aop.Framework; + +/// +/// Factory interface for advisor chains. +/// +/// Rod Johnson +/// Aleksandar Seovic (.NET) +public interface IAdvisorChainFactory : IAdvisedSupportListener { - /// - /// Factory interface for advisor chains. - /// - /// Rod Johnson - /// Aleksandar Seovic (.NET) - public interface IAdvisorChainFactory : IAdvisedSupportListener - { - /// - /// Gets the list of and - /// - /// instances for the supplied . - /// - /// The proxy configuration object. - /// The object proxy. - /// - /// The method for which the interceptors are to be evaluated. - /// - /// - /// The of the target object. - /// - /// - /// The list of and - /// - /// instances for the supplied . - /// - IList GetInterceptors(IAdvised advised, object proxy, MethodInfo method, Type targetType); - } + /// + /// Gets the list of and + /// + /// instances for the supplied . + /// + /// The proxy configuration object. + /// The object proxy. + /// + /// The method for which the interceptors are to be evaluated. + /// + /// + /// The of the target object. + /// + /// + /// The list of and + /// + /// instances for the supplied . + /// + IList GetInterceptors(IAdvised advised, object proxy, MethodInfo method, Type targetType); } diff --git a/src/Spring/Spring.Aop/Aop/Framework/IAopProxy.cs b/src/Spring/Spring.Aop/Aop/Framework/IAopProxy.cs index a50830c4..9915b8cd 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/IAopProxy.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/IAopProxy.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -24,19 +24,18 @@ using Spring.Proxy; #endregion -namespace Spring.Aop.Framework +namespace Spring.Aop.Framework; + +/// +/// The central interface for Spring.NET based AOP proxies. +/// +/// Rod Johnson +/// Aleksandar Seovic (.NET) +[ProxyIgnore] +public interface IAopProxy { - /// - /// The central interface for Spring.NET based AOP proxies. - /// - /// Rod Johnson - /// Aleksandar Seovic (.NET) - [ProxyIgnore] - public interface IAopProxy - { - /// - /// Creates a new proxy object. - /// - object GetProxy(); - } -} \ No newline at end of file + /// + /// Creates a new proxy object. + /// + object GetProxy(); +} diff --git a/src/Spring/Spring.Aop/Aop/Framework/IAopProxyFactory.cs b/src/Spring/Spring.Aop/Aop/Framework/IAopProxyFactory.cs index 4e46be92..30f282e1 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/IAopProxyFactory.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/IAopProxyFactory.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -18,27 +18,26 @@ #endregion -namespace Spring.Aop.Framework +namespace Spring.Aop.Framework; + +/// +/// Factory interface for the creation of AOP proxies based on +/// configuration +/// objects. +/// +/// Rod Johnson +/// Aleksandar Seovic (.NET) +public interface IAopProxyFactory { - /// - /// Factory interface for the creation of AOP proxies based on - /// configuration - /// objects. - /// - /// Rod Johnson - /// Aleksandar Seovic (.NET) - public interface IAopProxyFactory - { - /// - /// Creates an for the - /// supplied configuration. - /// - /// The AOP configuration. - /// An . - /// - /// If the supplied configuration is - /// invalid. - /// - IAopProxy CreateAopProxy(AdvisedSupport advisedSupport); - } -} \ No newline at end of file + /// + /// Creates an for the + /// supplied configuration. + /// + /// The AOP configuration. + /// An . + /// + /// If the supplied configuration is + /// invalid. + /// + IAopProxy CreateAopProxy(AdvisedSupport advisedSupport); +} diff --git a/src/Spring/Spring.Aop/Aop/Framework/ITargetAware.cs b/src/Spring/Spring.Aop/Aop/Framework/ITargetAware.cs index 155913b7..629c42d8 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/ITargetAware.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/ITargetAware.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -18,26 +18,25 @@ #endregion -namespace Spring.Aop.Framework +namespace Spring.Aop.Framework; + +/// +/// Provides access to the target object of an AOP proxy. +/// +/// +///

+/// To be implemented by introduction aspects in order to obtain access to +/// the target object. +///

+///
+/// Aleksandar Seovic +public interface ITargetAware { /// - /// Provides access to the target object of an AOP proxy. + /// Sets the target object. /// - /// - ///

- /// To be implemented by introduction aspects in order to obtain access to - /// the target object. - ///

- ///
- /// Aleksandar Seovic - public interface ITargetAware + IAopProxy TargetProxy { - /// - /// Sets the target object. - /// - IAopProxy TargetProxy - { - set; - } + set; } -} \ No newline at end of file +} diff --git a/src/Spring/Spring.Aop/Aop/Framework/InterceptorAndDynamicMethodMatcher.cs b/src/Spring/Spring.Aop/Aop/Framework/InterceptorAndDynamicMethodMatcher.cs index 17be5ef6..caf33e75 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/InterceptorAndDynamicMethodMatcher.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/InterceptorAndDynamicMethodMatcher.cs @@ -20,26 +20,24 @@ using AopAlliance.Intercept; -namespace Spring.Aop.Framework +namespace Spring.Aop.Framework; + +/// Internal framework class. +/// This class is required because if we put an interceptor that implements IInterceptionAdvice +/// in the interceptor list passed to MethodInvocation, it may be mistaken for an +/// advice that requires dynamic method matching. +/// +/// Rod Johnson +/// Aleksandar Seovic (.Net) +[Serializable] +internal class InterceptorAndDynamicMethodMatcher { - - /// Internal framework class. - /// This class is required because if we put an interceptor that implements IInterceptionAdvice - /// in the interceptor list passed to MethodInvocation, it may be mistaken for an - /// advice that requires dynamic method matching. - /// - /// Rod Johnson - /// Aleksandar Seovic (.Net) - [Serializable] - internal class InterceptorAndDynamicMethodMatcher - { - internal IMethodMatcher MethodMatcher; - internal IMethodInterceptor Interceptor; - - public InterceptorAndDynamicMethodMatcher(IMethodInterceptor interceptor, IMethodMatcher methodMatcher) - { - this.Interceptor = interceptor; - this.MethodMatcher = methodMatcher; - } - } + internal IMethodMatcher MethodMatcher; + internal IMethodInterceptor Interceptor; + + public InterceptorAndDynamicMethodMatcher(IMethodInterceptor interceptor, IMethodMatcher methodMatcher) + { + this.Interceptor = interceptor; + this.MethodMatcher = methodMatcher; + } } diff --git a/src/Spring/Spring.Aop/Aop/Framework/ProxyConfig.cs b/src/Spring/Spring.Aop/Aop/Framework/ProxyConfig.cs index ca0c266b..ac432c5b 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/ProxyConfig.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/ProxyConfig.cs @@ -16,222 +16,220 @@ using System.Runtime.Serialization; using System.Text; - using Spring.Util; using Spring.Reflection.Dynamic; -namespace Spring.Aop.Framework +namespace Spring.Aop.Framework; + +/// +/// Convenience superclass for configuration used in creating proxies, +/// to ensure that all proxy creators have consistent properties. +/// +/// +///

+/// Note that it is no longer possible to configure subclasses to +/// expose the . +/// Interceptors should normally manage their own thread locals if they +/// need to make resources available to advised objects. If it is +/// absolutely necessary to expose the +/// , use an +/// interceptor to do so. +///

+///
+/// Rod Johnson +/// Aleksandar Seovic (.NET) +[Serializable] +public class ProxyConfig : ISerializable { - /// - /// Convenience superclass for configuration used in creating proxies, - /// to ensure that all proxy creators have consistent properties. - /// - /// - ///

- /// Note that it is no longer possible to configure subclasses to - /// expose the . - /// Interceptors should normally manage their own thread locals if they - /// need to make resources available to advised objects. If it is - /// absolutely necessary to expose the - /// , use an - /// interceptor to do so. - ///

- ///
- /// Rod Johnson - /// Aleksandar Seovic (.NET) - [Serializable] - public class ProxyConfig : ISerializable + private static readonly IDynamicConstructor cachedAopProxyFactoryDynCtor = + new SafeConstructor(typeof(ProxyConfig).Assembly.GetType("Spring.Aop.Framework.DynamicProxy.CachedAopProxyFactory", false, false).GetConstructor(Type.EmptyTypes)); + + private bool proxyTargetType; + private bool proxyTargetAttributes = true; + private bool optimize; + private bool frozen; + + private IAopProxyFactory aopProxyFactory = cachedAopProxyFactoryDynCtor.Invoke(ObjectUtils.EmptyObjects) as IAopProxyFactory; + + private bool exposeProxy; + private readonly object syncRoot = new object(); + + /// + public ProxyConfig() { - private static readonly IDynamicConstructor cachedAopProxyFactoryDynCtor = - new SafeConstructor(typeof(ProxyConfig).Assembly.GetType("Spring.Aop.Framework.DynamicProxy.CachedAopProxyFactory", false, false).GetConstructor(Type.EmptyTypes)); + } - private bool proxyTargetType; - private bool proxyTargetAttributes = true; - private bool optimize; - private bool frozen; + /// + protected ProxyConfig(SerializationInfo info, StreamingContext context) + { + proxyTargetType = info.GetBoolean("proxyTargetType"); + proxyTargetAttributes = info.GetBoolean("proxyTargetAttributes"); + optimize = info.GetBoolean("optimize"); + frozen = info.GetBoolean("frozen"); + exposeProxy = info.GetBoolean("exposeProxy"); + syncRoot = info.GetValue("syncRoot", typeof(object)); + } - private IAopProxyFactory aopProxyFactory = cachedAopProxyFactoryDynCtor.Invoke(ObjectUtils.EmptyObjects) as IAopProxyFactory; + /// + public virtual void GetObjectData(SerializationInfo info, StreamingContext context) + { + info.AddValue("proxyTargetType", proxyTargetType); + info.AddValue("proxyTargetAttributes", proxyTargetAttributes); + info.AddValue("optimize", optimize); + info.AddValue("frozen", frozen); + info.AddValue("exposeProxy", exposeProxy); + info.AddValue("syncRoot", syncRoot); + } - private bool exposeProxy; - private readonly object syncRoot = new object(); + /// + /// Use to synchronize access to this ProxyConfig instance + /// + public object SyncRoot + { + get { return syncRoot; } + } - /// - public ProxyConfig() - { - } + /// + /// Is the target to be proxied in addition + /// to any interfaces declared on the proxied ? + /// + public virtual bool ProxyTargetType + { + get { return this.proxyTargetType; } + set { this.proxyTargetType = value; } + } - /// - protected ProxyConfig(SerializationInfo info, StreamingContext context) - { - proxyTargetType = info.GetBoolean("proxyTargetType"); - proxyTargetAttributes = info.GetBoolean("proxyTargetAttributes"); - optimize = info.GetBoolean("optimize"); - frozen = info.GetBoolean("frozen"); - exposeProxy = info.GetBoolean("exposeProxy"); - syncRoot = info.GetValue("syncRoot", typeof(object)); - } + /// + /// Is target type attributes, method attributes, method's return type attributes + /// and method's parameter attributes to be proxied in addition + /// to any interfaces declared on the proxied ? + /// + public virtual bool ProxyTargetAttributes + { + get { return this.proxyTargetAttributes; } + set { this.proxyTargetAttributes = value; } + } - /// - public virtual void GetObjectData(SerializationInfo info, StreamingContext context) - { - info.AddValue("proxyTargetType", proxyTargetType); - info.AddValue("proxyTargetAttributes", proxyTargetAttributes); - info.AddValue("optimize", optimize); - info.AddValue("frozen", frozen); - info.AddValue("exposeProxy", exposeProxy); - info.AddValue("syncRoot", syncRoot); - } + /// + /// Are any agressive optimizations to be performed? + /// + /// + ///

+ /// The exact meaning of agressive optimizations will differ + /// between proxies, but there is usually some tradeoff. + ///

+ ///

+ /// For example, optimization will usually mean that advice changes + /// won't take effect after a proxy has been created. For this reason, + /// optimization is disabled by default. An optimize value of + /// may be ignored if other settings preclude + /// optimization: for example, if the + /// property + /// is set to and such a value is not compatible + /// with the optimization. + ///

+ ///

+ /// The default is . + ///

+ ///
+ public virtual bool Optimize + { + get { return this.optimize; } + set { this.optimize = value; } + } - /// - /// Use to synchronize access to this ProxyConfig instance - /// - public object SyncRoot - { - get { return syncRoot; } - } + /// + /// Should proxies obtained from this configuration expose + /// the AOP proxy to the + /// class? + /// + /// + ///

+ /// The default is , as enabling this property + /// may impair performance. + ///

+ ///
+ public bool ExposeProxy + { + get { return this.exposeProxy; } + set { this.exposeProxy = value; } + } - /// - /// Is the target to be proxied in addition - /// to any interfaces declared on the proxied ? - /// - public virtual bool ProxyTargetType - { - get { return this.proxyTargetType; } - set { this.proxyTargetType = value; } - } + /// + /// Gets and set the factory to be used to create AOP proxies. + /// + /// + ///

+ /// This obviously allows one to customise the + /// implementation, + /// allowing different strategies to be dropped in without changing the + /// core framework. For example, an + /// implementation + /// could return an + /// using remoting proxies, Reflection.Emit or a code generation + /// strategy. + ///

+ ///
+ public virtual IAopProxyFactory AopProxyFactory + { + get { return this.aopProxyFactory; } + set { this.aopProxyFactory = value; } + } - /// - /// Is target type attributes, method attributes, method's return type attributes - /// and method's parameter attributes to be proxied in addition - /// to any interfaces declared on the proxied ? - /// - public virtual bool ProxyTargetAttributes - { - get { return this.proxyTargetAttributes; } - set { this.proxyTargetAttributes = value; } - } + /// + /// Is this configuration frozen? + /// + /// + ///

+ /// The default is not frozen. + ///

+ ///
+ public virtual bool IsFrozen + { + get { return this.frozen; } + set { this.frozen = value; } + } - /// - /// Are any agressive optimizations to be performed? - /// - /// - ///

- /// The exact meaning of agressive optimizations will differ - /// between proxies, but there is usually some tradeoff. - ///

- ///

- /// For example, optimization will usually mean that advice changes - /// won't take effect after a proxy has been created. For this reason, - /// optimization is disabled by default. An optimize value of - /// may be ignored if other settings preclude - /// optimization: for example, if the - /// property - /// is set to and such a value is not compatible - /// with the optimization. - ///

- ///

- /// The default is . - ///

- ///
- public virtual bool Optimize - { - get { return this.optimize; } - set { this.optimize = value; } - } + /// + /// Copies the configuration from the supplied + /// into this instance. + /// + /// + /// The configuration to be copied. + /// + /// + /// If the supplied is + /// . + /// + public virtual void CopyFrom(ProxyConfig otherConfiguration) + { + AssertUtils.ArgumentNotNull(otherConfiguration, "otherConfiguration"); - /// - /// Should proxies obtained from this configuration expose - /// the AOP proxy to the - /// class? - /// - /// - ///

- /// The default is , as enabling this property - /// may impair performance. - ///

- ///
- public bool ExposeProxy - { - get { return this.exposeProxy; } - set { this.exposeProxy = value; } - } + this.optimize = otherConfiguration.optimize; + this.proxyTargetType = otherConfiguration.proxyTargetType; + this.proxyTargetAttributes = otherConfiguration.proxyTargetAttributes; + this.exposeProxy = otherConfiguration.exposeProxy; + this.frozen = otherConfiguration.frozen; + this.aopProxyFactory = otherConfiguration.aopProxyFactory; + } - /// - /// Gets and set the factory to be used to create AOP proxies. - /// - /// - ///

- /// This obviously allows one to customise the - /// implementation, - /// allowing different strategies to be dropped in without changing the - /// core framework. For example, an - /// implementation - /// could return an - /// using remoting proxies, Reflection.Emit or a code generation - /// strategy. - ///

- ///
- public virtual IAopProxyFactory AopProxyFactory - { - get { return this.aopProxyFactory; } - set { this.aopProxyFactory = value; } - } - - /// - /// Is this configuration frozen? - /// - /// - ///

- /// The default is not frozen. - ///

- ///
- public virtual bool IsFrozen - { - get { return this.frozen; } - set { this.frozen = value; } - } - - /// - /// Copies the configuration from the supplied - /// into this instance. - /// - /// - /// The configuration to be copied. - /// - /// - /// If the supplied is - /// . - /// - public virtual void CopyFrom(ProxyConfig otherConfiguration) - { - AssertUtils.ArgumentNotNull(otherConfiguration, "otherConfiguration"); - - this.optimize = otherConfiguration.optimize; - this.proxyTargetType = otherConfiguration.proxyTargetType; - this.proxyTargetAttributes = otherConfiguration.proxyTargetAttributes; - this.exposeProxy = otherConfiguration.exposeProxy; - this.frozen = otherConfiguration.frozen; - this.aopProxyFactory = otherConfiguration.aopProxyFactory; - } - - /// - /// A that represents the current - /// configuration. - /// - /// - /// A that represents the current - /// configuration. - /// - public override string ToString() - { - StringBuilder buffer = new StringBuilder(); - buffer.Append("proxyTargetType=" + ProxyTargetType + "; "); - buffer.Append("proxyTargetAttributes=" + ProxyTargetAttributes + "; "); - buffer.Append("exposeProxy=" + ExposeProxy + "; "); - buffer.Append("isFrozen=" + IsFrozen + "; "); - buffer.Append("optimize=" + Optimize + "; "); - buffer.Append("aopProxyFactory=" + AopProxyFactory.GetType().FullName + "; "); - return buffer.ToString(); - } - } + /// + /// A that represents the current + /// configuration. + /// + /// + /// A that represents the current + /// configuration. + /// + public override string ToString() + { + StringBuilder buffer = new StringBuilder(); + buffer.Append("proxyTargetType=" + ProxyTargetType + "; "); + buffer.Append("proxyTargetAttributes=" + ProxyTargetAttributes + "; "); + buffer.Append("exposeProxy=" + ExposeProxy + "; "); + buffer.Append("isFrozen=" + IsFrozen + "; "); + buffer.Append("optimize=" + Optimize + "; "); + buffer.Append("aopProxyFactory=" + AopProxyFactory.GetType().FullName + "; "); + return buffer.ToString(); + } } diff --git a/src/Spring/Spring.Aop/Aop/Framework/ProxyFactory.cs b/src/Spring/Spring.Aop/Aop/Framework/ProxyFactory.cs index 885ea4f6..15a8fcc8 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/ProxyFactory.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/ProxyFactory.cs @@ -19,144 +19,141 @@ #endregion using System.Runtime.Serialization; - using AopAlliance.Intercept; -namespace Spring.Aop.Framework +namespace Spring.Aop.Framework; + +/// +/// Factory for AOP proxies for programmatic use, rather than via a +/// Spring.NET IoC container. +/// +/// +///

+/// This class provides a simple way of obtaining and configuring AOP +/// proxies in code. +///

+///
+/// Rod Johnson +/// Aleksandar Seovic (.NET) +[Serializable] +public class ProxyFactory : AdvisedSupport { - /// - /// Factory for AOP proxies for programmatic use, rather than via a - /// Spring.NET IoC container. - /// - /// - ///

- /// This class provides a simple way of obtaining and configuring AOP - /// proxies in code. - ///

- ///
- /// Rod Johnson - /// Aleksandar Seovic (.NET) - [Serializable] - public class ProxyFactory : AdvisedSupport - { - /// - /// Creates a new instance of the - /// class. - /// - public ProxyFactory() - { - } + /// + /// Creates a new instance of the + /// class. + /// + public ProxyFactory() + { + } - /// - /// Creates a new instance of the - /// class that proxys all of the interfaces exposed by the supplied - /// . - /// - /// The object to proxy. - /// - /// If the is . - /// - public ProxyFactory(object target) : base(target) - { - } + /// + /// Creates a new instance of the + /// class that proxys all of the interfaces exposed by the supplied + /// . + /// + /// The object to proxy. + /// + /// If the is . + /// + public ProxyFactory(object target) : base(target) + { + } - /// - /// Creates a new instance of the - /// class that has no target object, only interfaces. - /// - /// - ///

- /// Interceptors must be added if this factory is to do anything useful. - ///

- ///
- /// The interfaces to implement. - public ProxyFactory(Type[] interfaces) : base(interfaces) - { - } + /// + /// Creates a new instance of the + /// class that has no target object, only interfaces. + /// + /// + ///

+ /// Interceptors must be added if this factory is to do anything useful. + ///

+ ///
+ /// The interfaces to implement. + public ProxyFactory(Type[] interfaces) : base(interfaces) + { + } - /// - /// Creates a new instance of the class for the - /// given interface and interceptor. - /// - /// Convenience method for creating a proxy for a single interceptor - /// , assuming that the interceptor handles all calls itself rather than delegating - /// to a target, like in the case of remoting proxies. - /// The interface that the proxy should implement. - /// The interceptor that the proxy should invoke. - public ProxyFactory(Type proxyInterface, IInterceptor interceptor) - { - AddInterface(proxyInterface); - AddAdvice(interceptor); - } + /// + /// Creates a new instance of the class for the + /// given interface and interceptor. + /// + /// Convenience method for creating a proxy for a single interceptor + /// , assuming that the interceptor handles all calls itself rather than delegating + /// to a target, like in the case of remoting proxies. + /// The interface that the proxy should implement. + /// The interceptor that the proxy should invoke. + public ProxyFactory(Type proxyInterface, IInterceptor interceptor) + { + AddInterface(proxyInterface); + AddAdvice(interceptor); + } + /// + /// Create a new instance of the class for the specified + /// making the proxy implement the specified interface. + /// + /// + /// The interface that the proxy should implement. + /// The target source that the proxy should invoek. + public ProxyFactory(Type proxyInterface, ITargetSource targetSource) + { + AddInterface(proxyInterface); + TargetSource = targetSource; + } - /// - /// Create a new instance of the class for the specified - /// making the proxy implement the specified interface. - /// - /// - /// The interface that the proxy should implement. - /// The target source that the proxy should invoek. - public ProxyFactory(Type proxyInterface, ITargetSource targetSource) - { - AddInterface(proxyInterface); - TargetSource = targetSource; - } + /// + protected ProxyFactory(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } - /// - protected ProxyFactory(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } + /// + public override void GetObjectData(SerializationInfo info, StreamingContext context) + { + base.GetObjectData(info, context); + } - /// - public override void GetObjectData(SerializationInfo info, StreamingContext context) - { - base.GetObjectData(info, context); - } + /// + /// Creates a new proxy according to the settings in this factory. + /// + /// + ///

+ /// Can be called repeatedly; the effect of repeated invocations will + /// (of course) vary if interfaces have been added or removed. + ///

+ ///
+ /// An AOP proxy for target object. + public virtual object GetProxy() + { + IAopProxy proxy = CreateAopProxy(); + return proxy.GetProxy(); + } - /// - /// Creates a new proxy according to the settings in this factory. - /// - /// - ///

- /// Can be called repeatedly; the effect of repeated invocations will - /// (of course) vary if interfaces have been added or removed. - ///

- ///
- /// An AOP proxy for target object. - public virtual object GetProxy() - { - IAopProxy proxy = CreateAopProxy(); - return proxy.GetProxy(); - } - - /// - /// Creates a new proxy for the supplied - /// and . - /// - /// - ///

- /// This is a convenience method for creating a proxy for a single - /// interceptor. - ///

- ///
- /// - /// The interface that the proxy must implement. - /// - /// - /// The interceptor that the proxy must invoke. - /// - /// - /// A new AOP proxy for the supplied - /// and . - /// - public static object GetProxy(Type proxyInterface, IInterceptor interceptor) - { - ProxyFactory proxyFactory = new ProxyFactory(); - proxyFactory.AddInterface(proxyInterface); - proxyFactory.AddAdvice(interceptor); - return proxyFactory.GetProxy(); - } - } + /// + /// Creates a new proxy for the supplied + /// and . + /// + /// + ///

+ /// This is a convenience method for creating a proxy for a single + /// interceptor. + ///

+ ///
+ /// + /// The interface that the proxy must implement. + /// + /// + /// The interceptor that the proxy must invoke. + /// + /// + /// A new AOP proxy for the supplied + /// and . + /// + public static object GetProxy(Type proxyInterface, IInterceptor interceptor) + { + ProxyFactory proxyFactory = new ProxyFactory(); + proxyFactory.AddInterface(proxyInterface); + proxyFactory.AddAdvice(interceptor); + return proxyFactory.GetProxy(); + } } diff --git a/src/Spring/Spring.Aop/Aop/Framework/ProxyFactoryObject.cs b/src/Spring/Spring.Aop/Aop/Framework/ProxyFactoryObject.cs index e2c8bc46..82654498 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/ProxyFactoryObject.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/ProxyFactoryObject.cs @@ -15,7 +15,6 @@ */ using System.Runtime.Serialization; - using AopAlliance.Aop; using AopAlliance.Intercept; using Microsoft.Extensions.Logging; @@ -27,997 +26,1012 @@ using Spring.Core.TypeResolution; using Spring.Objects.Factory; using Spring.Util; -namespace Spring.Aop.Framework +namespace Spring.Aop.Framework; + +/// +/// implementation to +/// source AOP proxies from a Spring.NET IoC container (an +/// ). +/// +/// +///

+/// s and +/// s are identified by a list of object +/// names in the current container.

+///

+/// Global interceptors and advisors can be added at the factory level +/// (that is, outside the context of a +/// definition). The +/// specified interceptors and advisors are expanded in an interceptor list +/// (see +/// ) +/// where an 'xxx*' wildcard-style entry is included in the list, +/// matching the given prefix with the object names. For example, +/// 'global*' would match both 'globalObject1' and +/// 'globalObjectBar', and '*' would match all defined +/// interceptors. The matching interceptors get applied according to their +/// returned order value, if they implement the +/// interface. An interceptor name list +/// may not conclude with a global 'xxx*' pattern, as global +/// interceptors cannot invoke targets. +///

+///

+/// It is possible to cast a proxy obtained from this factory to an +/// reference, or to obtain the +/// reference and +/// programmatically manipulate it. This won't work for existing prototype +/// references, which are independent... however, it will work for prototypes +/// subsequently obtained from the factory. Changes to interception will +/// work immediately on singletons (including existing references). +/// However, to change interfaces or the target it is necessary to obtain a +/// new instance from the surrounding container. This means that singleton +/// instances obtained from the factory do not have the same object +/// identity... however, they do have the same interceptors and target, and +/// changing any reference will change all objects. +///

+///
+/// Rod Johnson +/// Juergen Hoeller +/// Federico Spinazzi (.NET) +/// Choy Rim (.NET) +/// Mark Pollack (.NET) +/// Aleksandar Seovic (.NET) +/// +/// +/// +/// +/// +[Serializable] +public class ProxyFactoryObject + : AdvisedSupport, IFactoryObject, IObjectFactoryAware { /// - /// implementation to - /// source AOP proxies from a Spring.NET IoC container (an - /// ). + /// The instance for this class. + /// + private static readonly ILogger logger = LogManager.GetLogger(); + + /// + /// Is the object managed by this factory a singleton or a prototype? + /// + private bool singleton = true; + + /// + /// This suffix in a value in an interceptor list indicates to expand globals. + /// + public static readonly string GlobalInterceptorSuffix = "*"; + + /// + /// The cached instance if this proxy factory object is a singleton. + /// + private object singletonInstance; + + /// + /// The owning object factory (which cannot be changed after this object is initialized). + /// + private IObjectFactory objectFactory; + + /// + /// The advisor adapter registry for wrapping pure advices and pointcuts according to needs + /// + private IAdvisorAdapterRegistry advisorAdapterRegistry; + + /// + /// Names of interceptors and pointcut objects in the factory. /// /// ///

- /// s and - /// s are identified by a list of object - /// names in the current container.

- ///

- /// Global interceptors and advisors can be added at the factory level - /// (that is, outside the context of a - /// definition). The - /// specified interceptors and advisors are expanded in an interceptor list - /// (see - /// ) - /// where an 'xxx*' wildcard-style entry is included in the list, - /// matching the given prefix with the object names. For example, - /// 'global*' would match both 'globalObject1' and - /// 'globalObjectBar', and '*' would match all defined - /// interceptors. The matching interceptors get applied according to their - /// returned order value, if they implement the - /// interface. An interceptor name list - /// may not conclude with a global 'xxx*' pattern, as global - /// interceptors cannot invoke targets. - ///

- ///

- /// It is possible to cast a proxy obtained from this factory to an - /// reference, or to obtain the - /// reference and - /// programmatically manipulate it. This won't work for existing prototype - /// references, which are independent... however, it will work for prototypes - /// subsequently obtained from the factory. Changes to interception will - /// work immediately on singletons (including existing references). - /// However, to change interfaces or the target it is necessary to obtain a - /// new instance from the surrounding container. This means that singleton - /// instances obtained from the factory do not have the same object - /// identity... however, they do have the same interceptors and target, and - /// changing any reference will change all objects. + /// Default is for globals expansion only. ///

///
- /// Rod Johnson - /// Juergen Hoeller - /// Federico Spinazzi (.NET) - /// Choy Rim (.NET) - /// Mark Pollack (.NET) - /// Aleksandar Seovic (.NET) - /// - /// - /// - /// - /// - [Serializable] - public class ProxyFactoryObject - : AdvisedSupport, IFactoryObject, IObjectFactoryAware + private string[] interceptorNames; + + /// + /// Names of introductions and pointcut objects in the factory. + /// + /// + ///

+ /// Default is for globals expansion only. + ///

+ ///
+ private string[] introductionNames; + + /// + /// The name of the target object(in the enclosing + /// ). + /// + private string targetName; + + /// + /// Indicates if the advisor chain has already been initialized + /// + private bool initialized; + + /// + /// Indicate whether this config shall be frozen upon creation + /// of the first proxy instance + /// + private bool freezeProxy; + + /// + protected ProxyFactoryObject(SerializationInfo info, StreamingContext context) + : base(info, context) { - /// - /// The instance for this class. - /// - private static readonly ILogger logger = LogManager.GetLogger(); + singleton = info.GetBoolean("singleton"); + singletonInstance = info.GetValue("singletonInstance", typeof(object)); + objectFactory = (IObjectFactory) info.GetValue("objectFactory", typeof(IObjectFactory)); + advisorAdapterRegistry = (IAdvisorAdapterRegistry) info.GetValue("advisorAdapterRegistry", typeof(IAdvisorAdapterRegistry)); + interceptorNames = (string[]) info.GetValue("interceptorNames", typeof(string[])); + introductionNames = (string[]) info.GetValue("introductionNames", typeof(string[])); + targetName = info.GetString("targetName"); + initialized = info.GetBoolean("initialized"); + freezeProxy = info.GetBoolean("freezeProxy"); + } - /// - /// Is the object managed by this factory a singleton or a prototype? - /// - private bool singleton = true; + /// + public override void GetObjectData(SerializationInfo info, StreamingContext context) + { + base.GetObjectData(info, context); + info.AddValue("singleton", singleton); + info.AddValue("singletonInstance", singletonInstance); + info.AddValue("objectFactory", objectFactory); + info.AddValue("advisorAdapterRegistry", advisorAdapterRegistry); + info.AddValue("interceptorNames", interceptorNames); + info.AddValue("introductionNames", introductionNames); + info.AddValue("targetName", targetName); + info.AddValue("initialized", initialized); + info.AddValue("freezeProxy", freezeProxy); + } - /// - /// This suffix in a value in an interceptor list indicates to expand globals. - /// - public static readonly string GlobalInterceptorSuffix = "*"; + /// + /// Indicate whether this config shall be frozen upon creation + /// of the first proxy instance + /// + public bool FreezeProxy + { + get { return freezeProxy; } + set { freezeProxy = value; } + } - /// - /// The cached instance if this proxy factory object is a singleton. - /// - private object singletonInstance; - - /// - /// The owning object factory (which cannot be changed after this object is initialized). - /// - private IObjectFactory objectFactory; - - /// - /// The advisor adapter registry for wrapping pure advices and pointcuts according to needs - /// - private IAdvisorAdapterRegistry advisorAdapterRegistry; - - /// - /// Names of interceptors and pointcut objects in the factory. - /// - /// - ///

- /// Default is for globals expansion only. - ///

- ///
- private string[] interceptorNames; - - /// - /// Names of introductions and pointcut objects in the factory. - /// - /// - ///

- /// Default is for globals expansion only. - ///

- ///
- private string[] introductionNames; - - /// - /// The name of the target object(in the enclosing - /// ). - /// - private string targetName; - - /// - /// Indicates if the advisor chain has already been initialized - /// - private bool initialized; - - /// - /// Indicate whether this config shall be frozen upon creation - /// of the first proxy instance - /// - private bool freezeProxy; - - /// - protected ProxyFactoryObject(SerializationInfo info, StreamingContext context) - : base(info, context) + /// + /// If set true, any attempt to modify this proxy configuration will raise an exception + /// + public override bool IsFrozen + { + set { - singleton = info.GetBoolean("singleton"); - singletonInstance = info.GetValue("singletonInstance", typeof(object)); - objectFactory = (IObjectFactory) info.GetValue("objectFactory", typeof(IObjectFactory)); - advisorAdapterRegistry = (IAdvisorAdapterRegistry) info.GetValue("advisorAdapterRegistry", typeof(IAdvisorAdapterRegistry)); - interceptorNames = (string[]) info.GetValue("interceptorNames", typeof(string[])); - introductionNames = (string[]) info.GetValue("introductionNames", typeof(string[])); - targetName = info.GetString("targetName"); - initialized = info.GetBoolean("initialized"); - freezeProxy = info.GetBoolean("freezeProxy"); + // defer freezing this config until the first proxy gets created + freezeProxy = value; } + } - /// - public override void GetObjectData(SerializationInfo info, StreamingContext context) - { - base.GetObjectData(info, context); - info.AddValue("singleton", singleton); - info.AddValue("singletonInstance", singletonInstance); - info.AddValue("objectFactory", objectFactory); - info.AddValue("advisorAdapterRegistry", advisorAdapterRegistry); - info.AddValue("interceptorNames", interceptorNames); - info.AddValue("introductionNames", introductionNames); - info.AddValue("targetName", targetName); - info.AddValue("initialized", initialized); - info.AddValue("freezeProxy", freezeProxy); - } + /// + /// Specify the AdvisorAdapterRegistry to use. Default is the + /// + public IAdvisorAdapterRegistry AdvisorAdapterRegistry + { + get { return advisorAdapterRegistry; } + set { advisorAdapterRegistry = value; } + } - /// - /// Indicate whether this config shall be frozen upon creation - /// of the first proxy instance - /// - public bool FreezeProxy + /// + /// Sets the names of the interfaces that are to be implemented by the proxy. + /// + /// + /// The names of the interfaces that are to be implemented by the proxy. + /// + /// + /// If the supplied value (or any of its elements) is ; + /// or if any of the element values is not the (assembly qualified) name of + /// an interface type. + /// + public virtual string[] ProxyInterfaces + { + set { - get { return freezeProxy; } - set { freezeProxy = value; } - } - - /// - /// If set true, any attempt to modify this proxy configuration will raise an exception - /// - public override bool IsFrozen - { - set + try { - // defer freezing this config until the first proxy gets created - freezeProxy = value; + Interfaces = TypeResolutionUtils.ResolveInterfaceArray(value); + } + catch (Exception ex) + { + throw new AopConfigException("Bad value passed to the ProxyInterfaces property (see inner exception).", ex); } } + } - /// - /// Specify the AdvisorAdapterRegistry to use. Default is the - /// - public IAdvisorAdapterRegistry AdvisorAdapterRegistry + /// + /// Sets the name of the target object being proxied. + /// + /// + ///

+ /// Only works when the + /// + /// property is set; it is a logic error on the part of the programmer + /// if this value is set and the accompanying + /// is not also set. + ///

+ ///
+ /// + /// The name of the target object being proxied. + /// + public virtual string TargetName + { + set { targetName = value; } + } + + /// + /// Sets the list of and + /// object names. + /// + /// + ///

+ /// This property must always be set (configured) when using a + /// in an + /// context. + ///

+ ///
+ /// + /// The list of and + /// object names. + /// + /// + /// + /// + /// + public virtual string[] InterceptorNames + { + set { interceptorNames = value; } + } + + /// + /// Sets the list of introduction object names. + /// + /// + ///

+ /// Only works when the + /// + /// property is set; it is a logic error on the part of the programmer + /// if this value is set and the accompanying + /// is not supplied. + ///

+ ///
+ /// + /// The list of introduction object names. . + /// + public virtual string[] IntroductionNames + { + set { introductionNames = value; } + } + + /// + /// Creates a new instance of ProxyFactoryObject + /// + public ProxyFactoryObject() + { + advisorAdapterRegistry = GlobalAdvisorAdapterRegistry.Instance; + singleton = true; + } + + /// + /// Callback that supplies the owning factory to an object instance. + /// + /// + /// Owning + /// (may not be ). The object can immediately + /// call methods on the factory. + /// + /// + /// In case of initialization errors. + /// + /// + /// + public virtual IObjectFactory ObjectFactory + { + set { - get { return advisorAdapterRegistry; } - set { advisorAdapterRegistry = value; } + objectFactory = value; } + } - /// - /// Sets the names of the interfaces that are to be implemented by the proxy. - /// - /// - /// The names of the interfaces that are to be implemented by the proxy. - /// - /// - /// If the supplied value (or any of its elements) is ; - /// or if any of the element values is not the (assembly qualified) name of - /// an interface type. - /// - public virtual string[] ProxyInterfaces + /// + /// Creates an instance of the AOP proxy to be returned by this factory + /// + /// + ///

+ /// Invoked when clients obtain objects from this factory object. The + /// (proxy) instance will be cached for a singleton, and created on each + /// call to + /// for a prototype. + ///

+ ///
+ /// + /// A fresh AOP proxy reflecting the current state of this factory. + /// + /// + public virtual object GetObject() + { + lock (SyncRoot) { - set + if (!initialized) { - try - { - Interfaces = TypeResolutionUtils.ResolveInterfaceArray(value); - } - catch (Exception ex) - { - throw new AopConfigException("Bad value passed to the ProxyInterfaces property (see inner exception).", ex); - } + Initialize(); + initialized = true; } - } - /// - /// Sets the name of the target object being proxied. - /// - /// - ///

- /// Only works when the - /// - /// property is set; it is a logic error on the part of the programmer - /// if this value is set and the accompanying - /// is not also set. - ///

- ///
- /// - /// The name of the target object being proxied. - /// - public virtual string TargetName - { - set { targetName = value; } - } - - /// - /// Sets the list of and - /// object names. - /// - /// - ///

- /// This property must always be set (configured) when using a - /// in an - /// context. - ///

- ///
- /// - /// The list of and - /// object names. - /// - /// - /// - /// - /// - public virtual string[] InterceptorNames - { - set { interceptorNames = value; } - } - - /// - /// Sets the list of introduction object names. - /// - /// - ///

- /// Only works when the - /// - /// property is set; it is a logic error on the part of the programmer - /// if this value is set and the accompanying - /// is not supplied. - ///

- ///
- /// - /// The list of introduction object names. . - /// - public virtual string[] IntroductionNames - { - set { introductionNames = value; } - } - - /// - /// Creates a new instance of ProxyFactoryObject - /// - public ProxyFactoryObject() - { - advisorAdapterRegistry = GlobalAdvisorAdapterRegistry.Instance; - singleton = true; - } - - /// - /// Callback that supplies the owning factory to an object instance. - /// - /// - /// Owning - /// (may not be ). The object can immediately - /// call methods on the factory. - /// - /// - /// In case of initialization errors. - /// - /// - /// - public virtual IObjectFactory ObjectFactory - { - set + if (IsSingleton) { - objectFactory = value; + return SingletonInstance; } + + if (targetName == null) + { + logger.LogWarning("Using non-singleton proxies with singleton targets is often undesirable. " + + "Enable prototype proxies by setting the 'targetName' property."); + } + + return NewPrototypeInstance(); } + } - - /// - /// Creates an instance of the AOP proxy to be returned by this factory - /// - /// - ///

- /// Invoked when clients obtain objects from this factory object. The - /// (proxy) instance will be cached for a singleton, and created on each - /// call to - /// for a prototype. - ///

- ///
- /// - /// A fresh AOP proxy reflecting the current state of this factory. - /// - /// - public virtual object GetObject() + /// + /// Return the of the proxy. + /// + /// + /// Will check the singleton instance if already created, + /// else fall back to the proxy interface (if a single one), + /// the target bean type, or the TargetSource's target class. + /// + /// Return the of object that this + /// creates, or + /// if not known in advance. + public virtual Type ObjectType + { + get { + // TODO (EE): sync with Java lock (SyncRoot) { - if (!initialized) + if (singletonInstance != null) { - Initialize(); - initialized = true; + return singletonInstance.GetType(); } - - if (IsSingleton) + else if (Interfaces.Count == 1) { - return SingletonInstance; + return Interfaces[0]; } - - if (targetName == null) + else if (targetName != null && objectFactory != null) { - logger.LogWarning("Using non-singleton proxies with singleton targets is often undesirable. " + - "Enable prototype proxies by setting the 'targetName' property."); - } - return NewPrototypeInstance(); - } - } - - /// - /// Return the of the proxy. - /// - /// - /// Will check the singleton instance if already created, - /// else fall back to the proxy interface (if a single one), - /// the target bean type, or the TargetSource's target class. - /// - /// Return the of object that this - /// creates, or - /// if not known in advance. - public virtual Type ObjectType - { - get - { - // TODO (EE): sync with Java - lock (SyncRoot) - { - if (singletonInstance != null) - { - return singletonInstance.GetType(); - } - else if (Interfaces.Count == 1) - { - return Interfaces[0]; - } - else if (targetName != null && objectFactory != null) - { - return objectFactory.GetType(targetName); - } - else - { - return TargetSource.TargetType; - } - } - } - } - - /// - /// Is the object managed by this factory a singleton or a prototype? - /// - public virtual bool IsSingleton - { - get { return singleton; } - set { singleton = value; } - } - - private object SingletonInstance - { - get - { - if (singletonInstance == null) - { - TargetSource = FreshTargetSource(); - singletonInstance = CreateAopProxy().GetProxy(); - base.IsFrozen = freezeProxy; // freeze after creating proxy to allow for interface autodetection - } - return singletonInstance; - } - } - - private object NewPrototypeInstance() - { - // in the case of a prototype, we need to give the proxy - // an independent instance of the configuration... - - if (logger.IsEnabled(LogLevel.Debug)) - { - logger.LogDebug("Creating copy of prototype ProxyFactoryObject config: " + this); - } - - // The copy needs a fresh advisor chain, and a fresh TargetSource. - ITargetSource targetSource = FreshTargetSource(); - IList advisorChain = FreshAdvisorChain(); - IList introductionChain = FreshIntroductionChain(); - AdvisedSupport copy = new AdvisedSupport(); - copy.CopyConfigurationFrom(this, targetSource, advisorChain, introductionChain); - - if (logger.IsEnabled(LogLevel.Debug)) - { - logger.LogDebug("Using ProxyConfig: " + copy); - } - - object generatedProxy = copy.CreateAopProxy().GetProxy(); - base.IsFrozen = freezeProxy; // freeze after creating proxy to allow for interface autodetection - return generatedProxy; - } - - /// - /// Initialize this proxy factory - usually called after all properties are set - /// - private void Initialize() - { - if (logger.IsEnabled(LogLevel.Debug)) - { - logger.LogDebug(string.Format("Initialize: begin configure target, interceptors and introductions for {0}[{1}]", GetType().Name, GetHashCode())); - } - - InitializeAdvisorChain(); - InitializeIntroductionChain(); - - if (logger.IsEnabled(LogLevel.Debug)) - { - logger.LogDebug(string.Format("Initialize: completed configuration for {0}[{1}]: {2}", GetType().Name, GetHashCode(), ToProxyConfigString())); - } - } - - /// Create the advisor (interceptor) chain. - /// - /// The advisors that are sourced from an ObjectFactory will be refreshed each time - /// a new prototype instance is added. Interceptors added programmatically through - /// the factory API are unaffected by such changes. - /// - private void InitializeAdvisorChain() - { - if (ObjectUtils.IsEmpty(interceptorNames)) - { - return; - } - - CheckInterceptorNames(); - - // Globals can't be last unless we specified a targetSource using the property... - if (interceptorNames[interceptorNames.Length - 1] != null - && interceptorNames[interceptorNames.Length - 1].EndsWith(GlobalInterceptorSuffix) - && targetName == null - && TargetSource == EmptyTargetSource.Empty) - { - throw new AopConfigException("Target required after globals"); - } - - // materialize interceptor chain from object names... - foreach (string name in interceptorNames) - { - if (name == null) - { - throw new AopConfigException("Found null interceptor name value in the InterceptorNames list; check your configuration."); - } - - if (name.EndsWith(GlobalInterceptorSuffix)) - { - IListableObjectFactory lof = objectFactory as IListableObjectFactory; - if (lof == null) - { - throw new AopConfigException("Can only use global advisors or interceptors in conjunction with an IListableObjectFactory."); - } - - if (logger.IsEnabled(LogLevel.Debug)) - { - logger.LogDebug("Adding global advisor '" + name + "'"); - } - - AddGlobalAdvisor(lof, name.Substring(0, (name.Length - GlobalInterceptorSuffix.Length))); + return objectFactory.GetType(targetName); } else { - if (logger.IsEnabled(LogLevel.Debug)) - { - logger.LogDebug("resolving advisor name " + "'" + name + "'"); - } - - // If we get here, we need to add a named interceptor. - // We must check if it's a singleton or prototype. - object advice; - if (IsSingleton || objectFactory.IsSingleton(name)) - { - advice = objectFactory.GetObject(name); - AssertUtils.ArgumentNotNull(advice, "advice", "object factory returned a null object"); - } - else - { - advice = new PrototypePlaceholder(name); - } - AddAdvisorOnChainCreation(advice, name); + return TargetSource.TargetType; } } } + } - private void AddAdvisorOnChainCreation(object advice, string name) + /// + /// Is the object managed by this factory a singleton or a prototype? + /// + public virtual bool IsSingleton + { + get { return singleton; } + set { singleton = value; } + } + + private object SingletonInstance + { + get { - if (advice is IAdvisors) + if (singletonInstance == null) { + TargetSource = FreshTargetSource(); + singletonInstance = CreateAopProxy().GetProxy(); + base.IsFrozen = freezeProxy; // freeze after creating proxy to allow for interface autodetection + } + + return singletonInstance; + } + } + + private object NewPrototypeInstance() + { + // in the case of a prototype, we need to give the proxy + // an independent instance of the configuration... + + if (logger.IsEnabled(LogLevel.Debug)) + { + logger.LogDebug("Creating copy of prototype ProxyFactoryObject config: " + this); + } + + // The copy needs a fresh advisor chain, and a fresh TargetSource. + ITargetSource targetSource = FreshTargetSource(); + IList advisorChain = FreshAdvisorChain(); + IList introductionChain = FreshIntroductionChain(); + AdvisedSupport copy = new AdvisedSupport(); + copy.CopyConfigurationFrom(this, targetSource, advisorChain, introductionChain); + + if (logger.IsEnabled(LogLevel.Debug)) + { + logger.LogDebug("Using ProxyConfig: " + copy); + } + + object generatedProxy = copy.CreateAopProxy().GetProxy(); + base.IsFrozen = freezeProxy; // freeze after creating proxy to allow for interface autodetection + return generatedProxy; + } + + /// + /// Initialize this proxy factory - usually called after all properties are set + /// + private void Initialize() + { + if (logger.IsEnabled(LogLevel.Debug)) + { + logger.LogDebug(string.Format("Initialize: begin configure target, interceptors and introductions for {0}[{1}]", GetType().Name, GetHashCode())); + } + + InitializeAdvisorChain(); + InitializeIntroductionChain(); + + if (logger.IsEnabled(LogLevel.Debug)) + { + logger.LogDebug(string.Format("Initialize: completed configuration for {0}[{1}]: {2}", GetType().Name, GetHashCode(), ToProxyConfigString())); + } + } + + /// Create the advisor (interceptor) chain. + /// + /// The advisors that are sourced from an ObjectFactory will be refreshed each time + /// a new prototype instance is added. Interceptors added programmatically through + /// the factory API are unaffected by such changes. + /// + private void InitializeAdvisorChain() + { + if (ObjectUtils.IsEmpty(interceptorNames)) + { + return; + } + + CheckInterceptorNames(); + + // Globals can't be last unless we specified a targetSource using the property... + if (interceptorNames[interceptorNames.Length - 1] != null + && interceptorNames[interceptorNames.Length - 1].EndsWith(GlobalInterceptorSuffix) + && targetName == null + && TargetSource == EmptyTargetSource.Empty) + { + throw new AopConfigException("Target required after globals"); + } + + // materialize interceptor chain from object names... + foreach (string name in interceptorNames) + { + if (name == null) + { + throw new AopConfigException("Found null interceptor name value in the InterceptorNames list; check your configuration."); + } + + if (name.EndsWith(GlobalInterceptorSuffix)) + { + IListableObjectFactory lof = objectFactory as IListableObjectFactory; + if (lof == null) + { + throw new AopConfigException("Can only use global advisors or interceptors in conjunction with an IListableObjectFactory."); + } + if (logger.IsEnabled(LogLevel.Debug)) { - logger.LogDebug(string.Format("Adding advisor list '{0}'", name)); + logger.LogDebug("Adding global advisor '" + name + "'"); } - IAdvisors advisors = (IAdvisors)advice; - foreach (object element in advisors.Advisors) - { - if (logger.IsEnabled(LogLevel.Debug)) - { - logger.LogDebug(string.Format("Adding advisor '{0}' of type {1}", name, element.GetType().FullName)); - } - - IAdvisor advisor = NamedObjectToAdvisor(element); - AddAdvisor(advisor); - } + AddGlobalAdvisor(lof, name.Substring(0, (name.Length - GlobalInterceptorSuffix.Length))); } else { if (logger.IsEnabled(LogLevel.Debug)) { - logger.LogDebug(string.Format("Adding advisor '{0}' of type {1}", name, advice.GetType().FullName)); + logger.LogDebug("resolving advisor name " + "'" + name + "'"); } - IAdvisor advisor = NamedObjectToAdvisor(advice); + // If we get here, we need to add a named interceptor. + // We must check if it's a singleton or prototype. + object advice; + if (IsSingleton || objectFactory.IsSingleton(name)) + { + advice = objectFactory.GetObject(name); + AssertUtils.ArgumentNotNull(advice, "advice", "object factory returned a null object"); + } + else + { + advice = new PrototypePlaceholder(name); + } + + AddAdvisorOnChainCreation(advice, name); + } + } + } + + private void AddAdvisorOnChainCreation(object advice, string name) + { + if (advice is IAdvisors) + { + if (logger.IsEnabled(LogLevel.Debug)) + { + logger.LogDebug(string.Format("Adding advisor list '{0}'", name)); + } + + IAdvisors advisors = (IAdvisors) advice; + foreach (object element in advisors.Advisors) + { + if (logger.IsEnabled(LogLevel.Debug)) + { + logger.LogDebug(string.Format("Adding advisor '{0}' of type {1}", name, element.GetType().FullName)); + } + + IAdvisor advisor = NamedObjectToAdvisor(element); AddAdvisor(advisor); } } - - private bool IsNamedObjectAnAdvisorOrAdvice(string name) + else { - Type namedObjectType = objectFactory.GetType(name); - if (namedObjectType != null) + if (logger.IsEnabled(LogLevel.Debug)) { - return typeof(IAdvisors).IsAssignableFrom(namedObjectType) - || typeof(IAdvisor).IsAssignableFrom(namedObjectType) - || typeof(IAdvice).IsAssignableFrom(namedObjectType); + logger.LogDebug(string.Format("Adding advisor '{0}' of type {1}", name, advice.GetType().FullName)); } - // treat it as an IAdvisor if we can't tell... - return true; + + IAdvisor advisor = NamedObjectToAdvisor(advice); + AddAdvisor(advisor); + } + } + + private bool IsNamedObjectAnAdvisorOrAdvice(string name) + { + Type namedObjectType = objectFactory.GetType(name); + if (namedObjectType != null) + { + return typeof(IAdvisors).IsAssignableFrom(namedObjectType) + || typeof(IAdvisor).IsAssignableFrom(namedObjectType) + || typeof(IAdvice).IsAssignableFrom(namedObjectType); } - /// Add all global interceptors and pointcuts. - private void AddGlobalAdvisor(IListableObjectFactory objectFactory, string prefix) - { - var globalAspectNames = - ObjectFactoryUtils.ObjectNamesForTypeIncludingAncestors(objectFactory, typeof(IAdvisors)); - var globalAdvisorNames = - ObjectFactoryUtils.ObjectNamesForTypeIncludingAncestors(objectFactory, typeof(IAdvisor)); - var globalInterceptorNames = - ObjectFactoryUtils.ObjectNamesForTypeIncludingAncestors(objectFactory, typeof(IInterceptor)); + // treat it as an IAdvisor if we can't tell... + return true; + } - List objects = new List(); - Dictionary names = new Dictionary(); - for (int i = 0; i < globalAspectNames.Count; i++) + /// Add all global interceptors and pointcuts. + private void AddGlobalAdvisor(IListableObjectFactory objectFactory, string prefix) + { + var globalAspectNames = + ObjectFactoryUtils.ObjectNamesForTypeIncludingAncestors(objectFactory, typeof(IAdvisors)); + var globalAdvisorNames = + ObjectFactoryUtils.ObjectNamesForTypeIncludingAncestors(objectFactory, typeof(IAdvisor)); + var globalInterceptorNames = + ObjectFactoryUtils.ObjectNamesForTypeIncludingAncestors(objectFactory, typeof(IInterceptor)); + + List objects = new List(); + Dictionary names = new Dictionary(); + for (int i = 0; i < globalAspectNames.Count; i++) + { + string name = globalAspectNames[i]; + if (name.StartsWith(prefix)) { - string name = globalAspectNames[i]; - if (name.StartsWith(prefix)) + IAdvisors advisors = (IAdvisors) objectFactory.GetObject(name); + foreach (object advisor in advisors.Advisors) { - IAdvisors advisors = (IAdvisors)objectFactory.GetObject(name); - foreach (object advisor in advisors.Advisors) - { - // exclude introduction advisors from interceptor list - if (!(advisor is IIntroductionAdvisor)) - { - objects.Add(advisor); - names[advisor] = name; - } - } - } - } - for (int i = 0; i < globalAdvisorNames.Count; i++) - { - string name = globalAdvisorNames[i]; - if (name.StartsWith(prefix)) - { - object obj = objectFactory.GetObject(name); // exclude introduction advisors from interceptor list - if (!(obj is IIntroductionAdvisor)) + if (!(advisor is IIntroductionAdvisor)) { - objects.Add(obj); - names[obj] = name; + objects.Add(advisor); + names[advisor] = name; } } } - for (int i = 0; i < globalInterceptorNames.Count; i++) + } + + for (int i = 0; i < globalAdvisorNames.Count; i++) + { + string name = globalAdvisorNames[i]; + if (name.StartsWith(prefix)) { - string name = globalInterceptorNames[i]; - if (name.StartsWith(prefix)) + object obj = objectFactory.GetObject(name); + // exclude introduction advisors from interceptor list + if (!(obj is IIntroductionAdvisor)) { - object obj = objectFactory.GetObject(name); objects.Add(obj); names[obj] = name; } } - objects.Sort(OrderComparator.Instance); - foreach (object obj in objects) + } + + for (int i = 0; i < globalInterceptorNames.Count; i++) + { + string name = globalInterceptorNames[i]; + if (name.StartsWith(prefix)) { - string name = names[obj]; - AddAdvisorOnChainCreation(obj, name); + object obj = objectFactory.GetObject(name); + objects.Add(obj); + names[obj] = name; } } - /// - /// Configures introductions for this proxy. - /// - private void InitializeIntroductionChain() + objects.Sort(OrderComparator.Instance); + foreach (object obj in objects) { - if (ObjectUtils.IsEmpty(introductionNames)) - { - return; - } + string name = names[obj]; + AddAdvisorOnChainCreation(obj, name); + } + } - // Materialize introductions from object names... - foreach (string name in introductionNames) - { - if (name == null) - { - throw new AopConfigException("Found null interceptor name value in the InterceptorNames list; check your configuration."); - } - - if (logger.IsEnabled(LogLevel.Debug)) - { - logger.LogDebug("Adding introduction '" + name + "'"); - } - - if (name.EndsWith(GlobalInterceptorSuffix)) - { - if (!(objectFactory is IListableObjectFactory)) - { - throw new AopConfigException("Can only use global introductions with a ListableObjectFactory"); - } - AddGlobalIntroduction((IListableObjectFactory)objectFactory, name.Substring(0, (name.Length - GlobalInterceptorSuffix.Length))); - } - else - { - // add a named introduction - object introduction; - if (IsSingleton || objectFactory.IsSingleton(name)) - { - introduction = objectFactory.GetObject(name); - AssertUtils.ArgumentNotNull(introduction, "introduction", "object factory returned a null object"); - } - else - { - introduction = new PrototypePlaceholder(name); - } - AddIntroductionOnChainCreation(introduction, name); - } - } + /// + /// Configures introductions for this proxy. + /// + private void InitializeIntroductionChain() + { + if (ObjectUtils.IsEmpty(introductionNames)) + { + return; } - /// Add all global introductions. - private void AddGlobalIntroduction(IListableObjectFactory objectFactory, string prefix) + // Materialize introductions from object names... + foreach (string name in introductionNames) { - var globalAspectNames = - ObjectFactoryUtils.ObjectNamesForTypeIncludingAncestors(objectFactory, typeof(IAdvisors)); - var globalAdvisorNames = - ObjectFactoryUtils.ObjectNamesForTypeIncludingAncestors(objectFactory, typeof(IAdvisor)); - var globalIntroductionNames = - ObjectFactoryUtils.ObjectNamesForTypeIncludingAncestors(objectFactory, typeof(IAdvice)); - List objects = new List(); - Dictionary names = new Dictionary(); - - for (int i = 0; i < globalAspectNames.Count; i++) + if (name == null) { - string name = globalAspectNames[i]; - if (name.StartsWith(prefix)) - { - IAdvisors advisors = (IAdvisors)objectFactory.GetObject(name); - foreach (object advisor in advisors.Advisors) - { - // only include introduction advisors - if (advisor is IIntroductionAdvisor) - { - objects.Add(advisor); - names[advisor] = name; - } - } - } + throw new AopConfigException("Found null interceptor name value in the InterceptorNames list; check your configuration."); } - for (int i = 0; i < globalAdvisorNames.Count; i++) - { - string name = globalAdvisorNames[i]; - if (name.StartsWith(prefix)) - { - object obj = objectFactory.GetObject(name); - // only include introduction advisors - if (obj is IIntroductionAdvisor) - { - objects.Add(obj); - names[obj] = name; - } - } - } - for (int i = 0; i < globalIntroductionNames.Count; i++) - { - string name = globalIntroductionNames[i]; - if (name.StartsWith(prefix)) - { - object obj = objectFactory.GetObject(name); - // exclude other advice types - if (!(obj is IInterceptor || obj is IBeforeAdvice || obj is IAfterReturningAdvice)) - { - objects.Add(obj); - names[obj] = name; - } - } - } - objects.Sort(OrderComparator.Instance); - for (var i = 0; i < objects.Count; i++) - { - object obj = objects[i]; - string name = names[obj]; - AddIntroductionOnChainCreation(obj, name); - } - } - - /// Add the introduction to the introduction list. - /// - /// If specified parameter is IIntroducionAdvisor it is added directly, otherwise it is wrapped - /// with DefaultIntroductionAdvisor first. - /// - /// introducion to add - /// object name from which we obtained this object in our owning object factory - private void AddIntroductionOnChainCreation(object introduction, string name) - { - logger.LogDebug($"Adding introduction with name '{name}'"); - IIntroductionAdvisor advisor = NamedObjectToIntroduction(introduction); - AddIntroduction(advisor); - } - - /// - /// Refreshes target object for prototype instances. - /// - private ITargetSource FreshTargetSource() - { - if (StringUtils.IsNullOrEmpty(targetName)) - { - if (logger.IsEnabled(LogLevel.Debug)) - { - logger.LogDebug("Not Refreshing TargetSource: No target name specified"); - } - - return TargetSource; - } - - AssertUtils.ArgumentNotNull(objectFactory, "ObjectFactory"); if (logger.IsEnabled(LogLevel.Debug)) { - logger.LogDebug("Refreshing TargetSource with name '" + targetName + "'"); + logger.LogDebug("Adding introduction '" + name + "'"); } - object target = objectFactory.GetObject(targetName); - ITargetSource targetSource = NamedObjectToTargetSource(target); - return targetSource; - } - - /// Refresh named objects from the interceptor chain. - /// We need to do this every time a new prototype instance is returned, - /// to return distinct instances of prototype interfaces and pointcuts. - /// - private IList FreshAdvisorChain() - { - IList advisors = Advisors; - List freshAdvisors = new List(); - foreach (IAdvisor advisor in advisors) + if (name.EndsWith(GlobalInterceptorSuffix)) { - if (advisor is PrototypePlaceholder) + if (!(objectFactory is IListableObjectFactory)) { - PrototypePlaceholder pa = (PrototypePlaceholder)advisor; - if (logger.IsEnabled(LogLevel.Debug)) - { - logger.LogDebug(string.Format("Refreshing advisor '{0}'", pa.ObjectName)); - } + throw new AopConfigException("Can only use global introductions with a ListableObjectFactory"); + } - AssertUtils.ArgumentNotNull(objectFactory, "ObjectFactory"); - - object advisorObject = objectFactory.GetObject(pa.ObjectName); - IAdvisor freshAdvisor = NamedObjectToAdvisor(advisorObject); - freshAdvisors.Add(freshAdvisor); + AddGlobalIntroduction((IListableObjectFactory) objectFactory, name.Substring(0, (name.Length - GlobalInterceptorSuffix.Length))); + } + else + { + // add a named introduction + object introduction; + if (IsSingleton || objectFactory.IsSingleton(name)) + { + introduction = objectFactory.GetObject(name); + AssertUtils.ArgumentNotNull(introduction, "introduction", "object factory returned a null object"); } else { - freshAdvisors.Add(advisor); + introduction = new PrototypePlaceholder(name); } - } - return freshAdvisors; - } - /// Refresh named objects from the interceptor chain. - /// We need to do this every time a new prototype instance is returned, - /// to return distinct instances of prototype interfaces and pointcuts. - /// - private IList FreshIntroductionChain() - { - IList introductions = Introductions; - List freshIntroductions = new List(); - foreach (IIntroductionAdvisor introduction in introductions) - { - if (introduction is PrototypePlaceholder) - { - PrototypePlaceholder pa = (PrototypePlaceholder)introduction; - if (logger.IsEnabled(LogLevel.Debug)) - { - logger.LogDebug(string.Format("Refreshing introduction '{0}'", pa.ObjectName)); - } - - AssertUtils.ArgumentNotNull(objectFactory, "ObjectFactory"); - - object introductionObject = objectFactory.GetObject(pa.ObjectName); - IIntroductionAdvisor freshIntroduction = NamedObjectToIntroduction(introductionObject); - freshIntroductions.Add(freshIntroduction); - } - else - { - freshIntroductions.Add(introduction); - } - } - return freshIntroductions; - } - - /// Wraps target with SingletonTargetSource if necessary - /// target or target source object - /// target source passed or target wrapped with SingletonTargetSource - private ITargetSource NamedObjectToTargetSource(object target) - { - if (target is ITargetSource) - { - return (ITargetSource)target; - } - // It's an object that needs target source around it. - return new SingletonTargetSource(target); - } - - /// Wraps introduction with IIntroductionAdvisor if necessary - /// Wraps pointcut or interceptor with appropriate advisor - /// pointcut or interceptor that needs to be wrapped with advisor - /// Advisor - private IAdvisor NamedObjectToAdvisor(object next) - { - try - { - return advisorAdapterRegistry.Wrap(next); - } - catch (UnknownAdviceTypeException ex) - { - throw new AopConfigException(string.Format("Unknown advisor type '{0}'; Can only include Advisor or Advice type beans in interceptorNames chain except for last entry,which may also be target or TargetSource", next.GetType().FullName), ex); - } - } - - /// object to wrap - /// Introduction advisor - private IIntroductionAdvisor NamedObjectToIntroduction(object introduction) - { - if (introduction is IIntroductionAdvisor) - { - return (IIntroductionAdvisor)introduction; - } - return new DefaultIntroductionAdvisor((IAdvice)introduction); - } - - /// - /// Callback method that is invoked when the list of proxied interfaces - /// has changed. - /// - /// - ///

- /// An example of such a change would be when a new introduction is - /// added. Resetting - /// to - /// will cause a new proxy - /// to be generated on the next call to get a proxy. - ///

- ///
- protected override void InterfacesChanged() - { - logger.LogInformation("Implemented interfaces have changed; reseting singleton instance"); - singletonInstance = null; - base.InterfacesChanged(); - } - - /// - /// Returns textual information about this configuration object - /// - protected override string ToProxyConfigStringInternal() - { - return string.Format("{0}\ntargetName={1}", base.ToProxyConfigStringInternal(), targetName); - } - - /// - /// Check the interceptorNames list whether it contains a target name as final element. - /// If found, remove the final name from the list and set it as targetName. - /// - private void CheckInterceptorNames() - { - if (!ObjectUtils.IsEmpty(interceptorNames)) - { - String finalName = interceptorNames[interceptorNames.Length - 1]; - if (finalName != null && targetName == null && TargetSource == EmptyTargetSource.Empty) - { - // The last name in the chain may be an Advisor/Advice or a target/TargetSource. - // Unfortunately we don't know; we must look at type of the bean. - if (!finalName.EndsWith(GlobalInterceptorSuffix) - && !IsNamedObjectAnAdvisorOrAdvice(finalName)) - { - // The target isn't an interceptor. - targetName = finalName; - if (logger.IsEnabled(LogLevel.Debug)) - { - logger.LogDebug(string.Format("Object with name '{0}' concluding interceptor chain is not an advisor class: treating it as a target or TargetSource", finalName)); - } - String[] newNames = new String[interceptorNames.Length - 1]; - Array.Copy(interceptorNames, 0, newNames, 0, newNames.Length); - interceptorNames = newNames; - } - } - } - } - - [Serializable] - private class PrototypePlaceholder : IIntroductionAdvisor - { - private readonly string objectName; - private readonly string message; - - public string ObjectName - { - get { return objectName; } - } - - public PrototypePlaceholder(string objectName) - { - this.objectName = objectName; - message = "Placeholder for prototype Advisor/Advice/Introduction with bean name '" + objectName + "'"; - } - - public bool IsPerInstance - { - get { throw new NotSupportedException("Cannot invoke methods: " + message); } - } - - public IAdvice Advice - { - get { throw new NotSupportedException("Cannot invoke methods: " + message); } - } - - public ITypeFilter TypeFilter - { - get { throw new NotSupportedException("Cannot invoke methods: " + message); } - } - - public Type[] Interfaces - { - get { throw new NotSupportedException("Cannot invoke methods: " + message); } - } - - public void ValidateInterfaces() - { - throw new NotSupportedException("Cannot invoke methods: " + message); + AddIntroductionOnChainCreation(introduction, name); } } } + + /// Add all global introductions. + private void AddGlobalIntroduction(IListableObjectFactory objectFactory, string prefix) + { + var globalAspectNames = + ObjectFactoryUtils.ObjectNamesForTypeIncludingAncestors(objectFactory, typeof(IAdvisors)); + var globalAdvisorNames = + ObjectFactoryUtils.ObjectNamesForTypeIncludingAncestors(objectFactory, typeof(IAdvisor)); + var globalIntroductionNames = + ObjectFactoryUtils.ObjectNamesForTypeIncludingAncestors(objectFactory, typeof(IAdvice)); + List objects = new List(); + Dictionary names = new Dictionary(); + + for (int i = 0; i < globalAspectNames.Count; i++) + { + string name = globalAspectNames[i]; + if (name.StartsWith(prefix)) + { + IAdvisors advisors = (IAdvisors) objectFactory.GetObject(name); + foreach (object advisor in advisors.Advisors) + { + // only include introduction advisors + if (advisor is IIntroductionAdvisor) + { + objects.Add(advisor); + names[advisor] = name; + } + } + } + } + + for (int i = 0; i < globalAdvisorNames.Count; i++) + { + string name = globalAdvisorNames[i]; + if (name.StartsWith(prefix)) + { + object obj = objectFactory.GetObject(name); + // only include introduction advisors + if (obj is IIntroductionAdvisor) + { + objects.Add(obj); + names[obj] = name; + } + } + } + + for (int i = 0; i < globalIntroductionNames.Count; i++) + { + string name = globalIntroductionNames[i]; + if (name.StartsWith(prefix)) + { + object obj = objectFactory.GetObject(name); + // exclude other advice types + if (!(obj is IInterceptor || obj is IBeforeAdvice || obj is IAfterReturningAdvice)) + { + objects.Add(obj); + names[obj] = name; + } + } + } + + objects.Sort(OrderComparator.Instance); + for (var i = 0; i < objects.Count; i++) + { + object obj = objects[i]; + string name = names[obj]; + AddIntroductionOnChainCreation(obj, name); + } + } + + /// Add the introduction to the introduction list. + /// + /// If specified parameter is IIntroducionAdvisor it is added directly, otherwise it is wrapped + /// with DefaultIntroductionAdvisor first. + /// + /// introducion to add + /// object name from which we obtained this object in our owning object factory + private void AddIntroductionOnChainCreation(object introduction, string name) + { + logger.LogDebug($"Adding introduction with name '{name}'"); + IIntroductionAdvisor advisor = NamedObjectToIntroduction(introduction); + AddIntroduction(advisor); + } + + /// + /// Refreshes target object for prototype instances. + /// + private ITargetSource FreshTargetSource() + { + if (StringUtils.IsNullOrEmpty(targetName)) + { + if (logger.IsEnabled(LogLevel.Debug)) + { + logger.LogDebug("Not Refreshing TargetSource: No target name specified"); + } + + return TargetSource; + } + + AssertUtils.ArgumentNotNull(objectFactory, "ObjectFactory"); + + if (logger.IsEnabled(LogLevel.Debug)) + { + logger.LogDebug("Refreshing TargetSource with name '" + targetName + "'"); + } + + object target = objectFactory.GetObject(targetName); + ITargetSource targetSource = NamedObjectToTargetSource(target); + return targetSource; + } + + /// Refresh named objects from the interceptor chain. + /// We need to do this every time a new prototype instance is returned, + /// to return distinct instances of prototype interfaces and pointcuts. + /// + private IList FreshAdvisorChain() + { + IList advisors = Advisors; + List freshAdvisors = new List(); + foreach (IAdvisor advisor in advisors) + { + if (advisor is PrototypePlaceholder) + { + PrototypePlaceholder pa = (PrototypePlaceholder) advisor; + if (logger.IsEnabled(LogLevel.Debug)) + { + logger.LogDebug(string.Format("Refreshing advisor '{0}'", pa.ObjectName)); + } + + AssertUtils.ArgumentNotNull(objectFactory, "ObjectFactory"); + + object advisorObject = objectFactory.GetObject(pa.ObjectName); + IAdvisor freshAdvisor = NamedObjectToAdvisor(advisorObject); + freshAdvisors.Add(freshAdvisor); + } + else + { + freshAdvisors.Add(advisor); + } + } + + return freshAdvisors; + } + + /// Refresh named objects from the interceptor chain. + /// We need to do this every time a new prototype instance is returned, + /// to return distinct instances of prototype interfaces and pointcuts. + /// + private IList FreshIntroductionChain() + { + IList introductions = Introductions; + List freshIntroductions = new List(); + foreach (IIntroductionAdvisor introduction in introductions) + { + if (introduction is PrototypePlaceholder) + { + PrototypePlaceholder pa = (PrototypePlaceholder) introduction; + if (logger.IsEnabled(LogLevel.Debug)) + { + logger.LogDebug(string.Format("Refreshing introduction '{0}'", pa.ObjectName)); + } + + AssertUtils.ArgumentNotNull(objectFactory, "ObjectFactory"); + + object introductionObject = objectFactory.GetObject(pa.ObjectName); + IIntroductionAdvisor freshIntroduction = NamedObjectToIntroduction(introductionObject); + freshIntroductions.Add(freshIntroduction); + } + else + { + freshIntroductions.Add(introduction); + } + } + + return freshIntroductions; + } + + /// Wraps target with SingletonTargetSource if necessary + /// target or target source object + /// target source passed or target wrapped with SingletonTargetSource + private ITargetSource NamedObjectToTargetSource(object target) + { + if (target is ITargetSource) + { + return (ITargetSource) target; + } + + // It's an object that needs target source around it. + return new SingletonTargetSource(target); + } + + /// Wraps introduction with IIntroductionAdvisor if necessary + /// Wraps pointcut or interceptor with appropriate advisor + /// pointcut or interceptor that needs to be wrapped with advisor + /// Advisor + private IAdvisor NamedObjectToAdvisor(object next) + { + try + { + return advisorAdapterRegistry.Wrap(next); + } + catch (UnknownAdviceTypeException ex) + { + throw new AopConfigException(string.Format("Unknown advisor type '{0}'; Can only include Advisor or Advice type beans in interceptorNames chain except for last entry,which may also be target or TargetSource", next.GetType().FullName), ex); + } + } + + /// object to wrap + /// Introduction advisor + private IIntroductionAdvisor NamedObjectToIntroduction(object introduction) + { + if (introduction is IIntroductionAdvisor) + { + return (IIntroductionAdvisor) introduction; + } + + return new DefaultIntroductionAdvisor((IAdvice) introduction); + } + + /// + /// Callback method that is invoked when the list of proxied interfaces + /// has changed. + /// + /// + ///

+ /// An example of such a change would be when a new introduction is + /// added. Resetting + /// to + /// will cause a new proxy + /// to be generated on the next call to get a proxy. + ///

+ ///
+ protected override void InterfacesChanged() + { + logger.LogInformation("Implemented interfaces have changed; reseting singleton instance"); + singletonInstance = null; + base.InterfacesChanged(); + } + + /// + /// Returns textual information about this configuration object + /// + protected override string ToProxyConfigStringInternal() + { + return string.Format("{0}\ntargetName={1}", base.ToProxyConfigStringInternal(), targetName); + } + + /// + /// Check the interceptorNames list whether it contains a target name as final element. + /// If found, remove the final name from the list and set it as targetName. + /// + private void CheckInterceptorNames() + { + if (!ObjectUtils.IsEmpty(interceptorNames)) + { + String finalName = interceptorNames[interceptorNames.Length - 1]; + if (finalName != null && targetName == null && TargetSource == EmptyTargetSource.Empty) + { + // The last name in the chain may be an Advisor/Advice or a target/TargetSource. + // Unfortunately we don't know; we must look at type of the bean. + if (!finalName.EndsWith(GlobalInterceptorSuffix) + && !IsNamedObjectAnAdvisorOrAdvice(finalName)) + { + // The target isn't an interceptor. + targetName = finalName; + if (logger.IsEnabled(LogLevel.Debug)) + { + logger.LogDebug(string.Format("Object with name '{0}' concluding interceptor chain is not an advisor class: treating it as a target or TargetSource", finalName)); + } + + String[] newNames = new String[interceptorNames.Length - 1]; + Array.Copy(interceptorNames, 0, newNames, 0, newNames.Length); + interceptorNames = newNames; + } + } + } + } + + [Serializable] + private class PrototypePlaceholder : IIntroductionAdvisor + { + private readonly string objectName; + private readonly string message; + + public string ObjectName + { + get { return objectName; } + } + + public PrototypePlaceholder(string objectName) + { + this.objectName = objectName; + message = "Placeholder for prototype Advisor/Advice/Introduction with bean name '" + objectName + "'"; + } + + public bool IsPerInstance + { + get { throw new NotSupportedException("Cannot invoke methods: " + message); } + } + + public IAdvice Advice + { + get { throw new NotSupportedException("Cannot invoke methods: " + message); } + } + + public ITypeFilter TypeFilter + { + get { throw new NotSupportedException("Cannot invoke methods: " + message); } + } + + public Type[] Interfaces + { + get { throw new NotSupportedException("Cannot invoke methods: " + message); } + } + + public void ValidateInterfaces() + { + throw new NotSupportedException("Cannot invoke methods: " + message); + } + } } diff --git a/src/Spring/Spring.Aop/Aop/Framework/ReflectiveMethodInvocation.cs b/src/Spring/Spring.Aop/Aop/Framework/ReflectiveMethodInvocation.cs index ce91d6fb..6036f324 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/ReflectiveMethodInvocation.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/ReflectiveMethodInvocation.cs @@ -22,112 +22,110 @@ using System.Collections; using System.Reflection; - using Spring.Util; using AopAlliance.Intercept; #endregion -namespace Spring.Aop.Framework +namespace Spring.Aop.Framework; + +/// +/// Invokes a target method using standard reflection. +/// +/// Rod Johnson +/// Aleksandar Seovic (.NET) +/// Rick Evans (.NET) +/// Bruno Baia (.NET) +[Serializable] +public class ReflectiveMethodInvocation : AbstractMethodInvocation { - /// - /// Invokes a target method using standard reflection. - /// - /// Rod Johnson - /// Aleksandar Seovic (.NET) - /// Rick Evans (.NET) - /// Bruno Baia (.NET) - [Serializable] - public class ReflectiveMethodInvocation : AbstractMethodInvocation - { - /// - /// The method invocation that is to be invoked on the proxy. - /// - private MethodInfo proxyMethod; + /// + /// The method invocation that is to be invoked on the proxy. + /// + private MethodInfo proxyMethod; - /// - /// Creates a new instance of the - /// class. - /// - /// The AOP proxy. - /// The target object. - /// The target method proxied. - /// The method to invoke on proxy. - /// The target method's arguments. - /// - /// The of the target object. - /// - /// The list of interceptors that are to be applied. May be - /// . - /// - /// - /// If any of the or - /// parameters is . - /// - public ReflectiveMethodInvocation( - object proxy, object target, MethodInfo method, MethodInfo proxyMethod, - object[] arguments, Type targetType, IList interceptors) - : base(proxy, target, method, arguments, targetType, interceptors) + /// + /// Creates a new instance of the + /// class. + /// + /// The AOP proxy. + /// The target object. + /// The target method proxied. + /// The method to invoke on proxy. + /// The target method's arguments. + /// + /// The of the target object. + /// + /// The list of interceptors that are to be applied. May be + /// . + /// + /// + /// If any of the or + /// parameters is . + /// + public ReflectiveMethodInvocation( + object proxy, object target, MethodInfo method, MethodInfo proxyMethod, + object[] arguments, Type targetType, IList interceptors) + : base(proxy, target, method, arguments, targetType, interceptors) + { + this.proxyMethod = proxyMethod; + } + + /// + /// The method invocation that is to be invoked on the proxy. + /// + protected MethodInfo ProxyMethod + { + get { return proxyMethod; } + set { proxyMethod = value; } + } + + /// + /// Invokes the joinpoint using standard reflection. + /// + /// + ///

+ /// Subclasses can override this to use custom invocation. + ///

+ ///
+ /// + /// The return value of the invocation of the joinpoint. + /// + /// + /// If invoking the joinpoint resulted in an exception. + /// + /// + protected override object InvokeJoinpoint() + { + try { - this.proxyMethod = proxyMethod; + MethodInfo targetMethodInfo = ProxyMethod ?? Method; + + AssertUtils.Understands(Target, "target", targetMethodInfo); + return targetMethodInfo.Invoke(Target, Arguments); } - - /// - /// The method invocation that is to be invoked on the proxy. - /// - protected MethodInfo ProxyMethod - { - get { return proxyMethod; } - set { proxyMethod = value; } - } - - /// - /// Invokes the joinpoint using standard reflection. - /// - /// - ///

- /// Subclasses can override this to use custom invocation. - ///

- ///
- /// - /// The return value of the invocation of the joinpoint. - /// - /// - /// If invoking the joinpoint resulted in an exception. - /// - /// - protected override object InvokeJoinpoint() + catch (TargetInvocationException ex) { - try - { - MethodInfo targetMethodInfo = ProxyMethod ?? Method; - - AssertUtils.Understands(Target, "target", targetMethodInfo); - return targetMethodInfo.Invoke(Target, Arguments); - } - catch (TargetInvocationException ex) - { - throw ReflectionUtils.UnwrapTargetInvocationException(ex); - } + throw ReflectionUtils.UnwrapTargetInvocationException(ex); } + } - /// - /// Creates a new instance - /// from the specified and - /// increments the interceptor index. - /// - /// - /// The current instance. - /// - /// - /// The new instance to use. - /// - protected override IMethodInvocation PrepareMethodInvocationForProceed(IMethodInvocation invocation) - { - var rmi = new ReflectiveMethodInvocation(Proxy, Target, Method, ProxyMethod, Arguments, TargetType, Interceptors); - rmi.CurrentInterceptorIndex = CurrentInterceptorIndex + 1; + /// + /// Creates a new instance + /// from the specified and + /// increments the interceptor index. + /// + /// + /// The current instance. + /// + /// + /// The new instance to use. + /// + protected override IMethodInvocation PrepareMethodInvocationForProceed(IMethodInvocation invocation) + { + var rmi = new ReflectiveMethodInvocation(Proxy, Target, Method, ProxyMethod, Arguments, TargetType, Interceptors); + rmi.CurrentInterceptorIndex = CurrentInterceptorIndex + 1; - return rmi; - } - } + return rmi; + } } diff --git a/src/Spring/Spring.Aop/Aop/IAdvisor.cs b/src/Spring/Spring.Aop/Aop/IAdvisor.cs index 40f15f88..9fa75b0c 100644 --- a/src/Spring/Spring.Aop/Aop/IAdvisor.cs +++ b/src/Spring/Spring.Aop/Aop/IAdvisor.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -24,71 +24,70 @@ using AopAlliance.Aop; #endregion -namespace Spring.Aop -{ - /// - /// Base interface holding AOP advice and a filter determining the - /// applicability of the advice (such as a pointcut). - /// - /// - /// - /// This interface is not for use by Spring.NET users, but exists rather to - /// allow for commonality in the support for different types of advice - /// within the framework. - /// - ///

- /// Spring.NET AOP is centered on around advice delivered via method - /// interception, compliant with the AOP Alliance interception API. - /// The interface allows support for - /// different types of advice, such as before and after - /// advice, which need not be implemented using interception. - ///

- ///
- /// Rod Johnson - /// Aleksandar Seovic (.NET) - /// - /// - /// - /// - public interface IAdvisor - { - /// - /// Is this advice associated with a particular instance? - /// - /// - ///

- /// An advisor that was creating a mixin would be a per instance - /// operation and would thus return . If the - /// advisor is not per instance, it is shared with all instances of the - /// advised class obtained from the same Spring.NET IoC container. - ///

- ///

- /// Use singleton and prototype object definitions or - /// appropriate programmatic proxy creation to ensure that - /// s have the correct lifecycle model. - ///

- /// - /// This method is not currently used by the framework. - /// - ///
- /// - /// if this advice is associated with a - /// particular instance. - /// - bool IsPerInstance { get; } +namespace Spring.Aop; - /// - /// Return the advice part of this aspect. - /// - /// - ///

- /// An advice may be an interceptor, a throws advice, before advice, - /// introduction etc. - ///

- ///
- /// - /// The advice that should apply if the pointcut matches. - /// - IAdvice Advice { get; } - } -} \ No newline at end of file +/// +/// Base interface holding AOP advice and a filter determining the +/// applicability of the advice (such as a pointcut). +/// +/// +/// +/// This interface is not for use by Spring.NET users, but exists rather to +/// allow for commonality in the support for different types of advice +/// within the framework. +/// +///

+/// Spring.NET AOP is centered on around advice delivered via method +/// interception, compliant with the AOP Alliance interception API. +/// The interface allows support for +/// different types of advice, such as before and after +/// advice, which need not be implemented using interception. +///

+///
+/// Rod Johnson +/// Aleksandar Seovic (.NET) +/// +/// +/// +/// +public interface IAdvisor +{ + /// + /// Is this advice associated with a particular instance? + /// + /// + ///

+ /// An advisor that was creating a mixin would be a per instance + /// operation and would thus return . If the + /// advisor is not per instance, it is shared with all instances of the + /// advised class obtained from the same Spring.NET IoC container. + ///

+ ///

+ /// Use singleton and prototype object definitions or + /// appropriate programmatic proxy creation to ensure that + /// s have the correct lifecycle model. + ///

+ /// + /// This method is not currently used by the framework. + /// + ///
+ /// + /// if this advice is associated with a + /// particular instance. + /// + bool IsPerInstance { get; } + + /// + /// Return the advice part of this aspect. + /// + /// + ///

+ /// An advice may be an interceptor, a throws advice, before advice, + /// introduction etc. + ///

+ ///
+ /// + /// The advice that should apply if the pointcut matches. + /// + IAdvice Advice { get; } +} diff --git a/src/Spring/Spring.Aop/Aop/IAdvisors.cs b/src/Spring/Spring.Aop/Aop/IAdvisors.cs index 708a104e..affdb2b2 100644 --- a/src/Spring/Spring.Aop/Aop/IAdvisors.cs +++ b/src/Spring/Spring.Aop/Aop/IAdvisors.cs @@ -22,21 +22,20 @@ #endregion -namespace Spring.Aop +namespace Spring.Aop; + +/// +/// AOP Aspect abstraction, holding a list of s +/// +/// +/// Aleksandar Seovic (.NET) +public interface IAdvisors { - /// - /// AOP Aspect abstraction, holding a list of s - /// - /// - /// Aleksandar Seovic (.NET) - public interface IAdvisors - { - /// - /// Gets or sets a list of advisors. - /// - /// - /// A list of advisors. - /// - IList Advisors { get; set; } - } + /// + /// Gets or sets a list of advisors. + /// + /// + /// A list of advisors. + /// + IList Advisors { get; set; } } diff --git a/src/Spring/Spring.Aop/Aop/IAfterReturningAdvice.cs b/src/Spring/Spring.Aop/Aop/IAfterReturningAdvice.cs index 1ac68e22..28277f54 100644 --- a/src/Spring/Spring.Aop/Aop/IAfterReturningAdvice.cs +++ b/src/Spring/Spring.Aop/Aop/IAfterReturningAdvice.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -21,57 +21,55 @@ #region Imports using System.Reflection; - using AopAlliance.Aop; #endregion -namespace Spring.Aop +namespace Spring.Aop; + +/// +/// Advice that executes after a method returns successfully. +/// +/// +///

+/// After returning advice is invoked only on a normal method +/// return, but not if an exception is thrown. Such advice can see +/// the return value of the advised method invocation, but cannot change it. +///

+///

+/// Possible uses for this type of advice would include performing access +/// control checks on the return value of an advised method invocation, the +/// ubiquitous logging of method invocation return values (useful during +/// development), etc. +///

+///
+/// Rod Johnson +/// Aleksandar Seovic (.NET) +/// +/// +/// +public interface IAfterReturningAdvice : IAdvice { - /// - /// Advice that executes after a method returns successfully. - /// - /// - ///

- /// After returning advice is invoked only on a normal method - /// return, but not if an exception is thrown. Such advice can see - /// the return value of the advised method invocation, but cannot change it. - ///

- ///

- /// Possible uses for this type of advice would include performing access - /// control checks on the return value of an advised method invocation, the - /// ubiquitous logging of method invocation return values (useful during - /// development), etc. - ///

- ///
- /// Rod Johnson - /// Aleksandar Seovic (.NET) - /// - /// - /// - public interface IAfterReturningAdvice : IAdvice - { - /// - /// Executes after - /// returns successfully. - /// - /// - ///

- /// Note that the supplied cannot - /// be changed by this type of advice... use the around advice type - /// () if you - /// need to change the return value of an advised method invocation. - /// The data encapsulated by the supplied - /// can of course be modified though. - ///

- ///
- /// - /// The value returned by the . - /// - /// The intecepted method. - /// The intercepted method's arguments. - /// The target object. - /// - void AfterReturning(object returnValue, MethodInfo method, object[] args, object target); - } -} \ No newline at end of file + /// + /// Executes after + /// returns successfully. + /// + /// + ///

+ /// Note that the supplied cannot + /// be changed by this type of advice... use the around advice type + /// () if you + /// need to change the return value of an advised method invocation. + /// The data encapsulated by the supplied + /// can of course be modified though. + ///

+ ///
+ /// + /// The value returned by the . + /// + /// The intecepted method. + /// The intercepted method's arguments. + /// The target object. + /// + void AfterReturning(object returnValue, MethodInfo method, object[] args, object target); +} diff --git a/src/Spring/Spring.Aop/Aop/IBeforeAdvice.cs b/src/Spring/Spring.Aop/Aop/IBeforeAdvice.cs index b4fe55fd..1f663296 100644 --- a/src/Spring/Spring.Aop/Aop/IBeforeAdvice.cs +++ b/src/Spring/Spring.Aop/Aop/IBeforeAdvice.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -24,30 +24,29 @@ using AopAlliance.Aop; #endregion -namespace Spring.Aop +namespace Spring.Aop; + +/// +/// Superinterface for all before advice. +/// +/// +///

+/// Before advice is advice that executes before a joinpoint, but +/// which does not have the ability to prevent execution flow proceeding to +/// the joinpoint (unless it throws an ). +///

+///

+/// Spring.NET only supports method before advice. Although this +/// is unlikely to change, this API is designed to allow field +/// before advice in future if desired. +///

+///
+/// Rod Johnson +/// Aleksandar Seovic (.NET) +/// +/// +/// +/// +public interface IBeforeAdvice : IAdvice { - /// - /// Superinterface for all before advice. - /// - /// - ///

- /// Before advice is advice that executes before a joinpoint, but - /// which does not have the ability to prevent execution flow proceeding to - /// the joinpoint (unless it throws an ). - ///

- ///

- /// Spring.NET only supports method before advice. Although this - /// is unlikely to change, this API is designed to allow field - /// before advice in future if desired. - ///

- ///
- /// Rod Johnson - /// Aleksandar Seovic (.NET) - /// - /// - /// - /// - public interface IBeforeAdvice : IAdvice - { - } -} \ No newline at end of file +} diff --git a/src/Spring/Spring.Aop/Aop/IIntroductionAdvisor.cs b/src/Spring/Spring.Aop/Aop/IIntroductionAdvisor.cs index b36f249d..3d95d043 100644 --- a/src/Spring/Spring.Aop/Aop/IIntroductionAdvisor.cs +++ b/src/Spring/Spring.Aop/Aop/IIntroductionAdvisor.cs @@ -22,69 +22,68 @@ #endregion -namespace Spring.Aop +namespace Spring.Aop; + +/// +/// Superinterface for advisors that perform one or more AOP +/// introductions. +/// +/// +///

+/// This interface cannot be implemented directly; subinterfaces must +/// provide the advice type implementing the introduction. +///

+///

+/// Introduction is the implementation of additional interfaces (not +/// implemented by a target) via AOP advice. +///

+///
+/// +/// Rod Johnson +/// Aleksandar Seovic (.NET) +public interface IIntroductionAdvisor : IAdvisor { - /// - /// Superinterface for advisors that perform one or more AOP - /// introductions. - /// - /// - ///

- /// This interface cannot be implemented directly; subinterfaces must - /// provide the advice type implementing the introduction. - ///

- ///

- /// Introduction is the implementation of additional interfaces (not - /// implemented by a target) via AOP advice. - ///

- ///
- /// - /// Rod Johnson - /// Aleksandar Seovic (.NET) - public interface IIntroductionAdvisor : IAdvisor - { - /// - /// Returns the filter determining which target classes this - /// introduction should apply to. - /// - /// - ///

- /// This is the part of a pointcut. - /// Be advised that method matching doesn't make sense in the context - /// of introductions. - ///

- ///
- /// - /// The filter determining which target classes this introduction - /// should apply to. - /// - ITypeFilter TypeFilter { get; } + /// + /// Returns the filter determining which target classes this + /// introduction should apply to. + /// + /// + ///

+ /// This is the part of a pointcut. + /// Be advised that method matching doesn't make sense in the context + /// of introductions. + ///

+ ///
+ /// + /// The filter determining which target classes this introduction + /// should apply to. + /// + ITypeFilter TypeFilter { get; } - /// - /// Gets the interfaces introduced by this - /// . - /// - /// - /// The interfaces introduced by this - /// . - /// - Type[] Interfaces { get; } + /// + /// Gets the interfaces introduced by this + /// . + /// + /// + /// The interfaces introduced by this + /// . + /// + Type[] Interfaces { get; } - /// - /// Can the advised interfaces be implemented by the introduction - /// advice? - /// - /// - ///

- /// Invoked before adding an - /// . - ///

- ///
- /// - /// If the advised interfaces cannot be implemented by the introduction - /// advice. - /// - /// - void ValidateInterfaces(); - } + /// + /// Can the advised interfaces be implemented by the introduction + /// advice? + /// + /// + ///

+ /// Invoked before adding an + /// . + ///

+ ///
+ /// + /// If the advised interfaces cannot be implemented by the introduction + /// advice. + /// + /// + void ValidateInterfaces(); } diff --git a/src/Spring/Spring.Aop/Aop/IIntroductionInterceptor.cs b/src/Spring/Spring.Aop/Aop/IIntroductionInterceptor.cs index f68a9603..2a27f087 100644 --- a/src/Spring/Spring.Aop/Aop/IIntroductionInterceptor.cs +++ b/src/Spring/Spring.Aop/Aop/IIntroductionInterceptor.cs @@ -24,37 +24,36 @@ using AopAlliance.Intercept; #endregion -namespace Spring.Aop +namespace Spring.Aop; + +/// +/// Subinterface of the AOP Alliance +/// interface that +/// allows additional interfaces to be implemented by the interceptor, and +/// available via a proxy using that interceptor. +/// +/// +///

+/// This is a fundamental AOP concept called introduction. +///

+///

+/// Introductions are often mixins, enabling the building of composite +/// objects that can achieve many of the goals of multiple inheritance. +///

+///
+/// Rod Johnson +/// Aleksandar Seovic (.NET) +public interface IIntroductionInterceptor : IMethodInterceptor { - /// - /// Subinterface of the AOP Alliance - /// interface that - /// allows additional interfaces to be implemented by the interceptor, and - /// available via a proxy using that interceptor. - /// - /// - ///

- /// This is a fundamental AOP concept called introduction. - ///

- ///

- /// Introductions are often mixins, enabling the building of composite - /// objects that can achieve many of the goals of multiple inheritance. - ///

- ///
- /// Rod Johnson - /// Aleksandar Seovic (.NET) - public interface IIntroductionInterceptor : IMethodInterceptor - { - /// - /// Does this - /// implement the given interface? - /// - /// The interface to check. - /// - /// if this - /// - /// implements the given interface. - /// - bool ImplementsInterface(Type intf); - } + /// + /// Does this + /// implement the given interface? + /// + /// The interface to check. + /// + /// if this + /// + /// implements the given interface. + /// + bool ImplementsInterface(Type intf); } diff --git a/src/Spring/Spring.Aop/Aop/IMethodBeforeAdvice.cs b/src/Spring/Spring.Aop/Aop/IMethodBeforeAdvice.cs index c7c0b04e..9b20ed4f 100644 --- a/src/Spring/Spring.Aop/Aop/IMethodBeforeAdvice.cs +++ b/src/Spring/Spring.Aop/Aop/IMethodBeforeAdvice.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -24,48 +24,47 @@ using System.Reflection; #endregion -namespace Spring.Aop +namespace Spring.Aop; + +/// +/// Advice executed before a method is invoked. +/// +/// +///

+/// Such advice cannot prevent the method call proceeding, short of +/// throwing an . +///

+///

+/// The main advantage of before advice is that there is no +/// possibility of inadvertently failing to proceed down the interceptor +/// chain, since there is no need (and indeed means) to invoke the next +/// interceptor in the call chain. +///

+///

+/// Possible uses for this type of advice would include performing class +/// invariant checks prior to the actual method invocation, the ubiquitous +/// logging of method invocations (useful during development), etc. +///

+///
+/// Rod Johnson +/// Aleksandar Seovic (.NET) +/// +/// +/// +/// +public interface IMethodBeforeAdvice : IBeforeAdvice { - /// - /// Advice executed before a method is invoked. - /// - /// - ///

- /// Such advice cannot prevent the method call proceeding, short of - /// throwing an . - ///

- ///

- /// The main advantage of before advice is that there is no - /// possibility of inadvertently failing to proceed down the interceptor - /// chain, since there is no need (and indeed means) to invoke the next - /// interceptor in the call chain. - ///

- ///

- /// Possible uses for this type of advice would include performing class - /// invariant checks prior to the actual method invocation, the ubiquitous - /// logging of method invocations (useful during development), etc. - ///

- ///
- /// Rod Johnson - /// Aleksandar Seovic (.NET) - /// - /// - /// - /// - public interface IMethodBeforeAdvice : IBeforeAdvice - { - /// - /// The callback before a given method is invoked. - /// - /// The method being invoked. - /// The arguments to the method. - /// - /// The target of the method invocation. May be . - /// - /// - /// Thrown when and if this object wishes to abort the call. Any - /// exception so thrown will be propagated to the caller. - /// - void Before(MethodInfo method, object[] args, object target); - } -} \ No newline at end of file + /// + /// The callback before a given method is invoked. + /// + /// The method being invoked. + /// The arguments to the method. + /// + /// The target of the method invocation. May be . + /// + /// + /// Thrown when and if this object wishes to abort the call. Any + /// exception so thrown will be propagated to the caller. + /// + void Before(MethodInfo method, object[] args, object target); +} diff --git a/src/Spring/Spring.Aop/Aop/IMethodMatcher.cs b/src/Spring/Spring.Aop/Aop/IMethodMatcher.cs index b1bf07f5..eef85187 100644 --- a/src/Spring/Spring.Aop/Aop/IMethodMatcher.cs +++ b/src/Spring/Spring.Aop/Aop/IMethodMatcher.cs @@ -24,126 +24,125 @@ using System.Reflection; #endregion -namespace Spring.Aop +namespace Spring.Aop; + +/// +/// That part of an that checks whether a +/// target method is eligible for advice. +/// +/// +///

+/// An may be evaluated +/// statically or at runtime (dynamically). Static +/// matching involves only the method signature and (possibly) any +/// s that have been applied to a method. +/// Dynamic matching additionally takes into account the actual argument +/// values passed to a method invocation. +///

+///

+/// If the value of the +/// property of an implementation instance returns , +/// evaluation can be performed statically, and the result will be the same +/// for all invocations of this method, whatever their arguments. This +/// means that if the value of the +/// is +/// , the three argument +/// +/// method will never be invoked for the lifetime of the +/// . +///

+///

+/// If an implementation returns in its two argument +/// +/// method, and the value of it's +/// property is +/// , the three argument +/// +/// method will be invoked immediately before each and every potential +/// execution of the related advice, to decide whether the advice +/// should run. All previous advice, such as earlier interceptors in an +/// interceptor chain, will have run, so any state changes they have +/// produced in parameters or thread local storage, will be available at +/// the time of evaluation. +///

+///
+/// Rod Johnson +/// Aleksandar Seovic (.NET) +/// +public interface IMethodMatcher { - /// - /// That part of an that checks whether a - /// target method is eligible for advice. - /// - /// - ///

- /// An may be evaluated - /// statically or at runtime (dynamically). Static - /// matching involves only the method signature and (possibly) any - /// s that have been applied to a method. - /// Dynamic matching additionally takes into account the actual argument - /// values passed to a method invocation. - ///

- ///

- /// If the value of the - /// property of an implementation instance returns , - /// evaluation can be performed statically, and the result will be the same - /// for all invocations of this method, whatever their arguments. This - /// means that if the value of the - /// is - /// , the three argument - /// - /// method will never be invoked for the lifetime of the - /// . - ///

- ///

- /// If an implementation returns in its two argument - /// - /// method, and the value of it's - /// property is - /// , the three argument - /// - /// method will be invoked immediately before each and every potential - /// execution of the related advice, to decide whether the advice - /// should run. All previous advice, such as earlier interceptors in an - /// interceptor chain, will have run, so any state changes they have - /// produced in parameters or thread local storage, will be available at - /// the time of evaluation. - ///

- ///
- /// Rod Johnson - /// Aleksandar Seovic (.NET) - /// - public interface IMethodMatcher - { - /// - /// Is this dynamic? - /// - /// - ///

- /// If , the three argument - /// - /// method will be invoked if the two argument - /// - /// method returns . - ///

- ///

- /// Note that this property can be checked when an AOP proxy is created, - /// and implementations need not check the value of this property again - /// before each method invocation. - ///

- ///
- /// - /// if this - /// is dynamic. - /// - bool IsRuntime { get; } + /// + /// Is this dynamic? + /// + /// + ///

+ /// If , the three argument + /// + /// method will be invoked if the two argument + /// + /// method returns . + ///

+ ///

+ /// Note that this property can be checked when an AOP proxy is created, + /// and implementations need not check the value of this property again + /// before each method invocation. + ///

+ ///
+ /// + /// if this + /// is dynamic. + /// + bool IsRuntime { get; } - /// - /// Does the supplied satisfy this matcher? - /// - /// - ///

- /// This is a static check. If this method invocation returns - /// ,or if the - /// property is - /// , then no runtime check will be made. - ///

- ///
- /// 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. - /// - bool Matches(MethodInfo method, Type targetType); + /// + /// Does the supplied satisfy this matcher? + /// + /// + ///

+ /// This is a static check. If this method invocation returns + /// ,or if the + /// property is + /// , then no runtime check will be made. + ///

+ ///
+ /// 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. + /// + bool Matches(MethodInfo method, Type targetType); - /// - /// Is there a runtime (dynamic) match for the supplied - /// ? - /// - /// - ///

- /// In order for this method to have even been invoked, the supplied - /// must have matched - /// statically. This method is invoked only if the two argument - /// - /// method returns for the supplied - /// and , and - /// if the property - /// is . - ///

- ///

- /// Invoked immediately before any potential running of the - /// advice, and after any advice earlier in the advice chain has - /// run. - ///

- ///
- /// The candidate method. - /// - /// The target . - /// - /// The arguments to the method - /// - /// if there is a runtime match. - bool Matches(MethodInfo method, Type targetType, object[] args); - } + /// + /// Is there a runtime (dynamic) match for the supplied + /// ? + /// + /// + ///

+ /// In order for this method to have even been invoked, the supplied + /// must have matched + /// statically. This method is invoked only if the two argument + /// + /// method returns for the supplied + /// and , and + /// if the property + /// is . + ///

+ ///

+ /// Invoked immediately before any potential running of the + /// advice, and after any advice earlier in the advice chain has + /// run. + ///

+ ///
+ /// The candidate method. + /// + /// The target . + /// + /// The arguments to the method + /// + /// if there is a runtime match. + bool Matches(MethodInfo method, Type targetType, object[] args); } diff --git a/src/Spring/Spring.Aop/Aop/IPointcut.cs b/src/Spring/Spring.Aop/Aop/IPointcut.cs index b503143e..30969ff9 100644 --- a/src/Spring/Spring.Aop/Aop/IPointcut.cs +++ b/src/Spring/Spring.Aop/Aop/IPointcut.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -18,37 +18,36 @@ #endregion -namespace Spring.Aop -{ - /// - /// Spring.NET's core pointcut abstraction. - /// - /// - ///

- /// A pointcut is composed of s and - /// s. Both these basic terms and an - /// itself can be combined to build up - /// sophisticated combinations. - ///

- ///
- /// Rod Johnson - /// Aleksandar Seovic (.NET) - public interface IPointcut - { - /// - /// The for this pointcut. - /// - /// - /// The current . - /// - ITypeFilter TypeFilter { get; } +namespace Spring.Aop; - /// - /// The for this pointcut. - /// - /// - /// The current . - /// - IMethodMatcher MethodMatcher { get; } - } -} \ No newline at end of file +/// +/// Spring.NET's core pointcut abstraction. +/// +/// +///

+/// A pointcut is composed of s and +/// s. Both these basic terms and an +/// itself can be combined to build up +/// sophisticated combinations. +///

+///
+/// Rod Johnson +/// Aleksandar Seovic (.NET) +public interface IPointcut +{ + /// + /// The for this pointcut. + /// + /// + /// The current . + /// + ITypeFilter TypeFilter { get; } + + /// + /// The for this pointcut. + /// + /// + /// The current . + /// + IMethodMatcher MethodMatcher { get; } +} diff --git a/src/Spring/Spring.Aop/Aop/IPointcutAdvisor.cs b/src/Spring/Spring.Aop/Aop/IPointcutAdvisor.cs index afc123a6..b200c1c7 100644 --- a/src/Spring/Spring.Aop/Aop/IPointcutAdvisor.cs +++ b/src/Spring/Spring.Aop/Aop/IPointcutAdvisor.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -18,26 +18,25 @@ #endregion -namespace Spring.Aop +namespace Spring.Aop; + +/// +/// Superinterface for all s that are +/// driven by a pointcut. +/// +/// +///

+/// This covers nearly all advisors except introduction advisors, for which +/// method-level matching does not apply. +///

+///
+/// Rod Johnson +/// Aleksandar Seovic (.NET) +/// +public interface IPointcutAdvisor : IAdvisor { - /// - /// Superinterface for all s that are - /// driven by a pointcut. - /// - /// - ///

- /// This covers nearly all advisors except introduction advisors, for which - /// method-level matching does not apply. - ///

- ///
- /// Rod Johnson - /// Aleksandar Seovic (.NET) - /// - public interface IPointcutAdvisor : IAdvisor - { - /// - /// The that drives this advisor. - /// - IPointcut Pointcut { get; } - } -} \ No newline at end of file + /// + /// The that drives this advisor. + /// + IPointcut Pointcut { get; } +} diff --git a/src/Spring/Spring.Aop/Aop/ITargetSource.cs b/src/Spring/Spring.Aop/Aop/ITargetSource.cs index 7291ccea..2a9c1abd 100644 --- a/src/Spring/Spring.Aop/Aop/ITargetSource.cs +++ b/src/Spring/Spring.Aop/Aop/ITargetSource.cs @@ -22,56 +22,55 @@ #endregion -namespace Spring.Aop +namespace Spring.Aop; + +/// +/// Used to obtain the current "target" of an AOP invocation +/// +/// +///

+/// This target will be invoked via reflection if no around advice chooses +/// to end the interceptor chain itself. +///

+///

+/// If an is "static", it +/// will always return the same target, allowing optimizations in the AOP +/// framework. Dynamic target sources can support pooling, hot swapping etc. +///

+///

+/// Application developers don't usually need to work with target sources +/// directly: this is an AOP framework interface. +///

+///
+/// Rod Johnson +/// Aleksandar Seovic (.NET) +public interface ITargetSource { - /// - /// Used to obtain the current "target" of an AOP invocation - /// - /// - ///

- /// This target will be invoked via reflection if no around advice chooses - /// to end the interceptor chain itself. - ///

- ///

- /// If an is "static", it - /// will always return the same target, allowing optimizations in the AOP - /// framework. Dynamic target sources can support pooling, hot swapping etc. - ///

- ///

- /// Application developers don't usually need to work with target sources - /// directly: this is an AOP framework interface. - ///

- ///
- /// Rod Johnson - /// Aleksandar Seovic (.NET) - public interface ITargetSource - { - /// - /// The of the target object. - /// - Type TargetType { get; } + /// + /// The of the target object. + /// + Type TargetType { get; } - /// - /// Is the target source static? - /// - /// - /// if the target source is static. - /// - bool IsStatic { get; } + /// + /// Is the target source static? + /// + /// + /// if the target source is static. + /// + bool IsStatic { get; } - /// - /// Returns the target object. - /// - /// The target object. - /// - /// If unable to obtain the target object. - /// - object GetTarget(); + /// + /// Returns the target object. + /// + /// The target object. + /// + /// If unable to obtain the target object. + /// + object GetTarget(); - /// - /// Releases the target object. - /// - /// The target object to release. - void ReleaseTarget(object target); - } + /// + /// Releases the target object. + /// + /// The target object to release. + void ReleaseTarget(object target); } diff --git a/src/Spring/Spring.Aop/Aop/IThrowsAdvice.cs b/src/Spring/Spring.Aop/Aop/IThrowsAdvice.cs index ab87d372..7564eafb 100644 --- a/src/Spring/Spring.Aop/Aop/IThrowsAdvice.cs +++ b/src/Spring/Spring.Aop/Aop/IThrowsAdvice.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -24,36 +24,35 @@ using AopAlliance.Aop; #endregion -namespace Spring.Aop +namespace Spring.Aop; + +/// +/// Simple marker interface for throws advice. +/// +/// +///

+/// There are no methods on this interface, as methods are discovered and +/// invoked via reflection. Please do see read the API documentation for the +/// class; +/// said documention describes in detail the signature of the methods that +/// implementations of the interface +/// must adhere to in the specific case of Spring.NET's implementation of +/// throws advice. +///

+///

+/// There are any number of possible uses for this type of advice. Some +/// examples would include the ubiquitous logging of any such exceptions, +/// monitoring the number and type of exceptions and sending emails to +/// a support desk once certain criteria have been met, wrapping generic +/// exceptions such as System.Data.SqlClient.SqlException in +/// exceptions that are more meaningful to your business logic, etc. +///

+///
+/// Rod Johnson +/// Aleksandar Seovic (.NET) +/// +/// +/// +public interface IThrowsAdvice : IAdvice { - /// - /// Simple marker interface for throws advice. - /// - /// - ///

- /// There are no methods on this interface, as methods are discovered and - /// invoked via reflection. Please do see read the API documentation for the - /// class; - /// said documention describes in detail the signature of the methods that - /// implementations of the interface - /// must adhere to in the specific case of Spring.NET's implementation of - /// throws advice. - ///

- ///

- /// There are any number of possible uses for this type of advice. Some - /// examples would include the ubiquitous logging of any such exceptions, - /// monitoring the number and type of exceptions and sending emails to - /// a support desk once certain criteria have been met, wrapping generic - /// exceptions such as System.Data.SqlClient.SqlException in - /// exceptions that are more meaningful to your business logic, etc. - ///

- ///
- /// Rod Johnson - /// Aleksandar Seovic (.NET) - /// - /// - /// - public interface IThrowsAdvice : IAdvice - { - } -} \ No newline at end of file +} diff --git a/src/Spring/Spring.Aop/Aop/ITypeFilter.cs b/src/Spring/Spring.Aop/Aop/ITypeFilter.cs index c7117ea7..5d41fbd0 100644 --- a/src/Spring/Spring.Aop/Aop/ITypeFilter.cs +++ b/src/Spring/Spring.Aop/Aop/ITypeFilter.cs @@ -22,35 +22,34 @@ #endregion -namespace Spring.Aop +namespace Spring.Aop; + +/// +/// A filter that restricts the matching of a pointcut or introduction to +/// a given set of target types. +/// +/// +///

+/// Can be used as part of a pointcut, or for the entire targeting of an +/// introduction. +///

+///
+/// Rod Johnson +/// Aleksandar Seovic (.NET) +/// +/// +public interface ITypeFilter { - /// - /// A filter that restricts the matching of a pointcut or introduction to - /// a given set of target types. - /// - /// - ///

- /// Can be used as part of a pointcut, or for the entire targeting of an - /// introduction. - ///

- ///
- /// Rod Johnson - /// Aleksandar Seovic (.NET) - /// - /// - public interface ITypeFilter - { - /// - /// Should the pointcut apply to the supplied - /// ? - /// - /// - /// The candidate . - /// - /// - /// if the advice should apply to the supplied - /// - /// - bool Matches(Type type); - } -} + /// + /// Should the pointcut apply to the supplied + /// ? + /// + /// + /// The candidate . + /// + /// + /// if the advice should apply to the supplied + /// + /// + bool Matches(Type type); +} \ No newline at end of file diff --git a/src/Spring/Spring.Aop/Aop/Support/AbstractGenericPointcutAdvisor.cs b/src/Spring/Spring.Aop/Aop/Support/AbstractGenericPointcutAdvisor.cs index b6d226d5..302920b8 100644 --- a/src/Spring/Spring.Aop/Aop/Support/AbstractGenericPointcutAdvisor.cs +++ b/src/Spring/Spring.Aop/Aop/Support/AbstractGenericPointcutAdvisor.cs @@ -20,59 +20,58 @@ using AopAlliance.Aop; -namespace Spring.Aop.Support +namespace Spring.Aop.Support; + +/// +/// Abstract PointcutAdvisor that allows for any Advice to be configured. +/// +/// Juergen Hoeller +/// Mark Pollack (.NET) +[Serializable] +public abstract class AbstractGenericPointcutAdvisor : AbstractPointcutAdvisor { + private IAdvice advice; + /// - /// Abstract PointcutAdvisor that allows for any Advice to be configured. + /// Return the advice part of this advisor. /// - /// Juergen Hoeller - /// Mark Pollack (.NET) - [Serializable] - public abstract class AbstractGenericPointcutAdvisor : AbstractPointcutAdvisor + /// + /// The advice that should apply if the pointcut matches. + /// + /// + public override IAdvice Advice { - private IAdvice advice; + get { return this.advice; } + set { this.advice = value; } + } - /// - /// Return the advice part of this advisor. - /// - /// - /// The advice that should apply if the pointcut matches. - /// - /// - public override IAdvice Advice - { - get { return this.advice; } - set { this.advice = value; } - } + /// + /// 2 s are considered equals, if + /// a) their pointcuts are equal + /// b) their advices are equal + /// + public override bool Equals(object obj) + { + return base.Equals(obj as AbstractGenericPointcutAdvisor); + } - /// - /// 2 s are considered equals, if - /// a) their pointcuts are equal - /// b) their advices are equal - /// - public override bool Equals(object obj) - { - return base.Equals(obj as AbstractGenericPointcutAdvisor); - } + /// + /// Calculates a unique hashcode based on advice + pointcut + /// + public override int GetHashCode() + { + return base.GetHashCode(); + } - /// - /// Calculates a unique hashcode based on advice + pointcut - /// - public override int GetHashCode() - { - return base.GetHashCode(); - } - - /// - /// Returns a that represents the current - /// . - /// - /// - /// A representation of this advisor. - /// - public override string ToString() - { - return GetType().Name + ": advice=[" + Advice + "]"; - } + /// + /// Returns a that represents the current + /// . + /// + /// + /// A representation of this advisor. + /// + public override string ToString() + { + return GetType().Name + ": advice=[" + Advice + "]"; } } diff --git a/src/Spring/Spring.Aop/Aop/Support/AbstractObjectFactoryPointcutAdvisor.cs b/src/Spring/Spring.Aop/Aop/Support/AbstractObjectFactoryPointcutAdvisor.cs index 53945a1d..f9ecec5d 100644 --- a/src/Spring/Spring.Aop/Aop/Support/AbstractObjectFactoryPointcutAdvisor.cs +++ b/src/Spring/Spring.Aop/Aop/Support/AbstractObjectFactoryPointcutAdvisor.cs @@ -22,115 +22,114 @@ using AopAlliance.Aop; using Spring.Objects.Factory; using Spring.Util; -namespace Spring.Aop.Support +namespace Spring.Aop.Support; + +/// +/// Abstract ObjectFactory-based IPointcutAdvisor that allows for any Advice to be +/// configured as reference to an Advice object in an ObjectFactory. +/// +/// +/// specifying the name of an advice object instead of the advice object itself +/// (if running within an ObjectFactory/ApplicationContext increses loose coupling +/// at initialization time, in order not to initialize the advice object until the +/// pointcut actually matches. +/// +/// Juergen Hoeller +/// Mark Pollack +public abstract class AbstractObjectFactoryPointcutAdvisor : AbstractPointcutAdvisor, IObjectFactoryAware { + private string adviceObjectName; + + private IObjectFactory objectFactory; + + private IAdvice advice; + + private object adviceMonitor = new object(); + /// - /// Abstract ObjectFactory-based IPointcutAdvisor that allows for any Advice to be - /// configured as reference to an Advice object in an ObjectFactory. + /// Gets or sets the name of the advice object that this advisor should refer to. + /// + /// An instance of the specified object will be obtained on first access of + /// this advisor's advice. This advisor will only ever obtain at most one + /// single instance of the advice object, caching the instance for the lifetime of + /// the advisor. + /// The name of the advice object. + public string AdviceObjectName + { + get { return adviceObjectName; } + set { adviceObjectName = value; } + } + + #region IObjectFactoryAware Members + + /// + /// Callback that supplies the owning factory to an object instance. + /// + /// + /// Owning + /// (may not be ). The object can immediately + /// call methods on the factory. + /// + /// + ///

+ /// Invoked after population of normal object properties but before an init + /// callback like 's + /// + /// method or a custom init-method. + ///

+ ///
+ /// + /// In case of initialization errors. + /// + public IObjectFactory ObjectFactory + { + set { objectFactory = value; } + } + + #endregion + + /// + /// Return the advice part of this aspect. /// /// - /// specifying the name of an advice object instead of the advice object itself - /// (if running within an ObjectFactory/ApplicationContext increses loose coupling - /// at initialization time, in order not to initialize the advice object until the - /// pointcut actually matches. + ///

+ /// An advice may be an interceptor, a throws advice, before advice, + /// introduction etc. + ///

///
- /// Juergen Hoeller - /// Mark Pollack - public abstract class AbstractObjectFactoryPointcutAdvisor : AbstractPointcutAdvisor, IObjectFactoryAware + /// + /// The advice that should apply if the pointcut matches. + /// + public override IAdvice Advice { - private string adviceObjectName; - - private IObjectFactory objectFactory; - - private IAdvice advice; - - private object adviceMonitor = new object(); - - - /// - /// Gets or sets the name of the advice object that this advisor should refer to. - /// - /// An instance of the specified object will be obtained on first access of - /// this advisor's advice. This advisor will only ever obtain at most one - /// single instance of the advice object, caching the instance for the lifetime of - /// the advisor. - /// The name of the advice object. - public string AdviceObjectName + get { - get { return adviceObjectName; } - set { adviceObjectName = value; } - } - - #region IObjectFactoryAware Members - - /// - /// Callback that supplies the owning factory to an object instance. - /// - /// - /// Owning - /// (may not be ). The object can immediately - /// call methods on the factory. - /// - /// - ///

- /// Invoked after population of normal object properties but before an init - /// callback like 's - /// - /// method or a custom init-method. - ///

- ///
- /// - /// In case of initialization errors. - /// - public IObjectFactory ObjectFactory - { - set { objectFactory = value; } - } - - #endregion - - /// - /// Return the advice part of this aspect. - /// - /// - ///

- /// An advice may be an interceptor, a throws advice, before advice, - /// introduction etc. - ///

- ///
- /// - /// The advice that should apply if the pointcut matches. - /// - public override IAdvice Advice - { - get + lock (adviceMonitor) { - lock (adviceMonitor) + if (advice == null && adviceObjectName != null) { - if (advice == null && adviceObjectName != null) - { - AssertUtils.State(objectFactory != null, - "ObjectFactory must be set to resolve 'adviceObjectName'"); - advice = objectFactory.GetObject(adviceObjectName, typeof (IAdvice)) as IAdvice; - } + AssertUtils.State(objectFactory != null, + "ObjectFactory must be set to resolve 'adviceObjectName'"); + advice = objectFactory.GetObject(adviceObjectName, typeof(IAdvice)) as IAdvice; } - return advice; } - set - { - advice = value; - } - } - /// - /// Describe this Advisor, showing name of advice object. - /// - /// - /// Type name and advice object name. - /// - public override string ToString() + return advice; + } + set { - return GetType().Name + ": advice object '" + AdviceObjectName + "'"; + advice = value; } } -} \ No newline at end of file + + /// + /// Describe this Advisor, showing name of advice object. + /// + /// + /// Type name and advice object name. + /// + public override string ToString() + { + return GetType().Name + ": advice object '" + AdviceObjectName + "'"; + } +} diff --git a/src/Spring/Spring.Aop/Aop/Support/AbstractPointcutAdvisor.cs b/src/Spring/Spring.Aop/Aop/Support/AbstractPointcutAdvisor.cs index 0e45713d..c80f1d15 100644 --- a/src/Spring/Spring.Aop/Aop/Support/AbstractPointcutAdvisor.cs +++ b/src/Spring/Spring.Aop/Aop/Support/AbstractPointcutAdvisor.cs @@ -17,136 +17,136 @@ using AopAlliance.Aop; using Spring.Core; -namespace Spring.Aop.Support +namespace Spring.Aop.Support; + +/// +/// Abstract base class for implementations. +/// +/// +/// Can be subclassed for returning a specific pointcut/advice or a freely configurable pointcut/advice. +/// +/// Rod Johnson +/// Juergen Hoeller +/// Mark Pollack (.NET) +[Serializable] +public abstract class AbstractPointcutAdvisor : IPointcutAdvisor, IOrdered { + private int _order = Int32.MaxValue; + /// - /// Abstract base class for implementations. + /// Returns this s order in the + /// interception chain. + /// + /// + /// This s order in the + /// interception chain. + /// + public virtual int Order + { + get { return this._order; } + set { this._order = value; } + } + + /// + /// Return the advice part of this aspect. /// /// - /// Can be subclassed for returning a specific pointcut/advice or a freely configurable pointcut/advice. + ///

+ /// An advice may be an interceptor, a throws advice, before advice, + /// introduction etc. + ///

///
- /// Rod Johnson - /// Juergen Hoeller - /// Mark Pollack (.NET) - [Serializable] - public abstract class AbstractPointcutAdvisor : IPointcutAdvisor, IOrdered + /// + /// The advice that should apply if the pointcut matches. + /// + public abstract IAdvice Advice { get; set; } + + /// + /// Is this advice associated with a particular instance? + /// + /// + ///

+ /// Not supported for dynamic advisors. + ///

+ ///
+ /// + /// if this advice is associated with a + /// particular instance. + /// + /// Always. + /// + public virtual bool IsPerInstance { - private int _order = Int32.MaxValue; - - /// - /// Returns this s order in the - /// interception chain. - /// - /// - /// This s order in the - /// interception chain. - /// - public virtual int Order + get { - get { return this._order; } - set { this._order = value; } - } - - /// - /// Return the advice part of this aspect. - /// - /// - ///

- /// An advice may be an interceptor, a throws advice, before advice, - /// introduction etc. - ///

- ///
- /// - /// The advice that should apply if the pointcut matches. - /// - public abstract IAdvice Advice { get; set; } - - /// - /// Is this advice associated with a particular instance? - /// - /// - ///

- /// Not supported for dynamic advisors. - ///

- ///
- /// - /// if this advice is associated with a - /// particular instance. - /// - /// Always. - /// - public virtual bool IsPerInstance - { - get - { - throw new NotSupportedException( - "The 'IsPerInstance' property of the IAdvisor interface " + - "is not yet supported in Spring.NET."); - } - } - - /// - /// The that drives this advisor. - /// - public abstract IPointcut Pointcut { get; set; } - - /// - /// Determines whether the specified - /// is equal to the current . - /// - /// The advisor to compare with. - /// - /// if this instance is equal to the - /// specified . - /// - public override bool Equals(object o) - { - if (!(o is AbstractPointcutAdvisor)) - { - return false; - } - - if (ReferenceEquals(this, o)) - { - return true; - } - - AbstractPointcutAdvisor otherAdvisor = (AbstractPointcutAdvisor)o; - if (this.Order != otherAdvisor.Order) - { - return false; - } - if (otherAdvisor.Advice == null && otherAdvisor.Pointcut == null) - { - return (this.Advice == null && this.Pointcut == null); - } - else if (otherAdvisor.Advice == null) - { - return (Advice == null && otherAdvisor.Pointcut.Equals(this.Pointcut)); - } - else if (otherAdvisor.Pointcut == null) - { - return (this.Pointcut == null && otherAdvisor.Advice.Equals(this.Advice)); - } - else - { - return otherAdvisor.Advice.Equals(this.Advice) && otherAdvisor.Pointcut.Equals(this.Pointcut); - } - } - - /// - /// Serves as a hash function for a particular type, suitable for use - /// in hashing algorithms and data structures like a hash table. - /// - /// - /// A hash code for the current . - /// - public override int GetHashCode() - { - return 0 // (SPRNET-847) base.GetHashCode() - + 13 * (Pointcut == null ? 0 : Pointcut.GetHashCode()) - + 27 * (Advice == null ? 0 : Advice.GetHashCode()) - + 31 * Order.GetHashCode(); + throw new NotSupportedException( + "The 'IsPerInstance' property of the IAdvisor interface " + + "is not yet supported in Spring.NET."); } } + + /// + /// The that drives this advisor. + /// + public abstract IPointcut Pointcut { get; set; } + + /// + /// Determines whether the specified + /// is equal to the current . + /// + /// The advisor to compare with. + /// + /// if this instance is equal to the + /// specified . + /// + public override bool Equals(object o) + { + if (!(o is AbstractPointcutAdvisor)) + { + return false; + } + + if (ReferenceEquals(this, o)) + { + return true; + } + + AbstractPointcutAdvisor otherAdvisor = (AbstractPointcutAdvisor) o; + if (this.Order != otherAdvisor.Order) + { + return false; + } + + if (otherAdvisor.Advice == null && otherAdvisor.Pointcut == null) + { + return (this.Advice == null && this.Pointcut == null); + } + else if (otherAdvisor.Advice == null) + { + return (Advice == null && otherAdvisor.Pointcut.Equals(this.Pointcut)); + } + else if (otherAdvisor.Pointcut == null) + { + return (this.Pointcut == null && otherAdvisor.Advice.Equals(this.Advice)); + } + else + { + return otherAdvisor.Advice.Equals(this.Advice) && otherAdvisor.Pointcut.Equals(this.Pointcut); + } + } + + /// + /// Serves as a hash function for a particular type, suitable for use + /// in hashing algorithms and data structures like a hash table. + /// + /// + /// A hash code for the current . + /// + public override int GetHashCode() + { + return 0 // (SPRNET-847) base.GetHashCode() + + 13 * (Pointcut == null ? 0 : Pointcut.GetHashCode()) + + 27 * (Advice == null ? 0 : Advice.GetHashCode()) + + 31 * Order.GetHashCode(); + } } diff --git a/src/Spring/Spring.Aop/Aop/Support/AbstractRegularExpressionMethodPointcut.cs b/src/Spring/Spring.Aop/Aop/Support/AbstractRegularExpressionMethodPointcut.cs index c560d87c..3ea379dc 100644 --- a/src/Spring/Spring.Aop/Aop/Support/AbstractRegularExpressionMethodPointcut.cs +++ b/src/Spring/Spring.Aop/Aop/Support/AbstractRegularExpressionMethodPointcut.cs @@ -17,236 +17,233 @@ using System.Reflection; using System.Runtime.Serialization; using System.Security.Permissions; - using AopAlliance.Aop; - using Spring.Util; -namespace Spring.Aop.Support +namespace Spring.Aop.Support; + +/// +/// Abstract base regular expression pointcut object. +/// +/// +///

+/// The regular expressions must be a match. For example, the +/// .*Get.* pattern will match Com.Mycom.Foo.GetBar(), and +/// Get.* will not. +///

+///

+/// This base class is serializable. Subclasses should decorate all +/// fields with the NonSerializedAttribute - the +/// +/// method in this class will be invoked again on the client side on deserialization. +///

+///
+/// Rod Johnson +/// Juergen Hoeller +/// Simon White (.NET) +[Serializable] +public abstract class AbstractRegularExpressionMethodPointcut + : StaticMethodMatcherPointcut, ITypeFilter, ISerializable { + [NonSerialized] private object[] _patterns = ObjectUtils.EmptyObjects; + /// - /// Abstract base regular expression pointcut object. + /// Creates a new instance of the + /// + /// class. /// /// ///

- /// The regular expressions must be a match. For example, the - /// .*Get.* pattern will match Com.Mycom.Foo.GetBar(), and - /// Get.* will not. - ///

- ///

- /// This base class is serializable. Subclasses should decorate all - /// fields with the NonSerializedAttribute - the - /// - /// method in this class will be invoked again on the client side on deserialization. + /// This is an abstract class, and as such has no publicly + /// visible constructors. ///

///
- /// Rod Johnson - /// Juergen Hoeller - /// Simon White (.NET) - [Serializable] - public abstract class AbstractRegularExpressionMethodPointcut - : StaticMethodMatcherPointcut, ITypeFilter, ISerializable + protected AbstractRegularExpressionMethodPointcut() { - [NonSerialized] - private object[] _patterns = ObjectUtils.EmptyObjects; + } - /// - /// Creates a new instance of the - /// - /// class. - /// - /// - ///

- /// This is an abstract class, and as such has no publicly - /// visible constructors. - ///

- ///
- protected AbstractRegularExpressionMethodPointcut() + /// + protected AbstractRegularExpressionMethodPointcut( + SerializationInfo info, StreamingContext context) + { + _patterns = (object[]) info.GetValue("Patterns", typeof(object[])); + if (_patterns == null) { - } - - /// - protected AbstractRegularExpressionMethodPointcut( - SerializationInfo info, StreamingContext context) - { - _patterns = (object[])info.GetValue("Patterns", typeof(object[])); - if (_patterns == null) - { - _patterns = ObjectUtils.EmptyObjects; - } - } - - /// - /// Overridden to ensure proper initialization - /// - protected override void OnDeserialization(object sender) - { - base.OnDeserialization(sender); - try - { - InitPatternRepresentation(_patterns); - } - catch (Exception ex) - { - throw new AspectException( - "Failed to deserialize AOP regular expression pointcut: " + ex.Message); - } - } - - /// - /// The for this pointcut. - /// - /// - /// The current . - /// - public override ITypeFilter TypeFilter - { - get { return this; } - } - - /// - /// Convenience property for setting a single pattern. - /// - /// - /// Use this property or Patterns, not both. - /// - public virtual object Pattern - { - get { return (_patterns.Length > 0 ? _patterns[0] : null); } - set - { - AssertUtils.ArgumentNotNull(value, "Pattern"); - this.Patterns = new object[] { value }; - } - } - - /// - /// The regular expressions defining methods to match. - /// - /// - /// Matching will be the union of all these; if any match, - /// the pointcut matches. - /// - public virtual object[] Patterns - { - get { return _patterns; } - set - { - AssertUtils.ArgumentNotNull(value, "Patterns"); - this._patterns = value; - InitPatternRepresentation(this.Patterns); - } - } - - /// - [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)] - public void GetObjectData(SerializationInfo info, StreamingContext context) - { - info.AddValue("Patterns", _patterns); - } - - /// - /// Subclasses must implement this to initialize regular expression pointcuts. - /// - /// - ///

- /// Can be invoked multiple times. - ///

- ///

- /// This method will be invoked from the property, - /// and also on deserialization. - ///

- ///
- /// - /// The patterns to initialize. - /// - /// - /// In the case of an invalid pattern. - /// - protected abstract void InitPatternRepresentation(object[] patterns); - - /// - /// Does the pattern at the supplied - /// match this ? - /// - /// The pattern to match - /// The index of pattern. - /// - /// if there is a match. - /// - protected abstract bool Matches(string pattern, int patternIndex); - - /// - /// Does the supplied satisfy this matcher? - /// - /// - ///

- /// Try to match the regular expression against the fully qualified name - /// of the method's declaring , plus the name of - /// the supplied . - ///

- ///

- /// Note that the declaring is that - /// that originally declared - /// the method, not necessarily the that is - /// currently exposing it. For example, - /// matches any subclass of 's - /// method. - ///

- ///
- /// 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) - { - string patt = string.Empty; - patt = String.Format("{0}.{1}", method.DeclaringType, method.Name); - - if (method.DeclaringType.IsGenericType) - { - patt = String.Format("{0}.{1}", ReflectionUtils.GetTypeFriendlyName(method.DeclaringType), method.Name); - } - else - { - patt = String.Format("{0}.{1}", method.DeclaringType, method.Name); - } - - for (int i = 0; i < this.Patterns.Length; ++i) - { - bool matched = Matches(patt, i); - if (matched) - { - return true; - } - } - return false; - } - - /// - /// Should the pointcut apply to the supplied - /// ? - /// - /// - ///

- /// In this instance, simply returns . - ///

- ///
- /// - /// The candidate . - /// - /// - /// if the advice should apply to the supplied - /// - /// - public bool Matches(Type type) - { - return true; + _patterns = ObjectUtils.EmptyObjects; } } + + /// + /// Overridden to ensure proper initialization + /// + protected override void OnDeserialization(object sender) + { + base.OnDeserialization(sender); + try + { + InitPatternRepresentation(_patterns); + } + catch (Exception ex) + { + throw new AspectException( + "Failed to deserialize AOP regular expression pointcut: " + ex.Message); + } + } + + /// + /// The for this pointcut. + /// + /// + /// The current . + /// + public override ITypeFilter TypeFilter + { + get { return this; } + } + + /// + /// Convenience property for setting a single pattern. + /// + /// + /// Use this property or Patterns, not both. + /// + public virtual object Pattern + { + get { return (_patterns.Length > 0 ? _patterns[0] : null); } + set + { + AssertUtils.ArgumentNotNull(value, "Pattern"); + this.Patterns = new object[] { value }; + } + } + + /// + /// The regular expressions defining methods to match. + /// + /// + /// Matching will be the union of all these; if any match, + /// the pointcut matches. + /// + public virtual object[] Patterns + { + get { return _patterns; } + set + { + AssertUtils.ArgumentNotNull(value, "Patterns"); + this._patterns = value; + InitPatternRepresentation(this.Patterns); + } + } + + /// + [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)] + public void GetObjectData(SerializationInfo info, StreamingContext context) + { + info.AddValue("Patterns", _patterns); + } + + /// + /// Subclasses must implement this to initialize regular expression pointcuts. + /// + /// + ///

+ /// Can be invoked multiple times. + ///

+ ///

+ /// This method will be invoked from the property, + /// and also on deserialization. + ///

+ ///
+ /// + /// The patterns to initialize. + /// + /// + /// In the case of an invalid pattern. + /// + protected abstract void InitPatternRepresentation(object[] patterns); + + /// + /// Does the pattern at the supplied + /// match this ? + /// + /// The pattern to match + /// The index of pattern. + /// + /// if there is a match. + /// + protected abstract bool Matches(string pattern, int patternIndex); + + /// + /// Does the supplied satisfy this matcher? + /// + /// + ///

+ /// Try to match the regular expression against the fully qualified name + /// of the method's declaring , plus the name of + /// the supplied . + ///

+ ///

+ /// Note that the declaring is that + /// that originally declared + /// the method, not necessarily the that is + /// currently exposing it. For example, + /// matches any subclass of 's + /// method. + ///

+ ///
+ /// 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) + { + string patt = string.Empty; + patt = String.Format("{0}.{1}", method.DeclaringType, method.Name); + + if (method.DeclaringType.IsGenericType) + { + patt = String.Format("{0}.{1}", ReflectionUtils.GetTypeFriendlyName(method.DeclaringType), method.Name); + } + else + { + patt = String.Format("{0}.{1}", method.DeclaringType, method.Name); + } + + for (int i = 0; i < this.Patterns.Length; ++i) + { + bool matched = Matches(patt, i); + if (matched) + { + return true; + } + } + + return false; + } + + /// + /// Should the pointcut apply to the supplied + /// ? + /// + /// + ///

+ /// In this instance, simply returns . + ///

+ ///
+ /// + /// The candidate . + /// + /// + /// if the advice should apply to the supplied + /// + /// + public bool Matches(Type type) + { + return true; + } } diff --git a/src/Spring/Spring.Aop/Aop/Support/AttributeMatchMethodPointcut.cs b/src/Spring/Spring.Aop/Aop/Support/AttributeMatchMethodPointcut.cs index ce4d3f2b..b22f359f 100644 --- a/src/Spring/Spring.Aop/Aop/Support/AttributeMatchMethodPointcut.cs +++ b/src/Spring/Spring.Aop/Aop/Support/AttributeMatchMethodPointcut.cs @@ -1,20 +1,20 @@ #region License /* -* Copyright 2002-2010 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. -*/ + * Copyright 2002-2010 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 @@ -22,210 +22,210 @@ using System.Reflection; using System.Runtime.Serialization; - using Spring.Util; #endregion -namespace Spring.Aop.Support +namespace Spring.Aop.Support; + +/// +/// implementation that matches methods +/// that have been decorated with a specified . +/// +/// Aleksandar Seovic +/// Ronald Wildenberg +[Serializable] +public class AttributeMatchMethodPointcut : StaticMethodMatcherPointcut, ISerializable { - /// - /// implementation that matches methods - /// that have been decorated with a specified . - /// - /// Aleksandar Seovic - /// Ronald Wildenberg - [Serializable] - public class AttributeMatchMethodPointcut : StaticMethodMatcherPointcut, ISerializable - { - private Type _attribute; - private bool _inherit = true; - private bool _checkInterfaces = false; + private Type _attribute; + private bool _inherit = true; + private bool _checkInterfaces = false; - /// - /// Creates a new instance of the - /// class. - /// - public AttributeMatchMethodPointcut() - { - } + /// + /// Creates a new instance of the + /// class. + /// + public AttributeMatchMethodPointcut() + { + } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The to match. - /// - public AttributeMatchMethodPointcut(Type attribute) - : this(attribute, true, false) + /// + /// Creates a new instance of the + /// class. + /// + /// + /// The to match. + /// + public AttributeMatchMethodPointcut(Type attribute) + : this(attribute, true, false) + { + } + + /// + /// Creates a new instance of the + /// + /// class. + /// + /// + /// The to match. + /// + /// + /// Flag that controls whether or not the inheritance tree of the + /// method to be included in the search for the ? + /// + public AttributeMatchMethodPointcut(Type attribute, bool inherit) + : this(attribute, inherit, false) + { + } + + /// + /// Creates a new instance of the + /// + /// class. + /// + /// + /// The to match. + /// + /// + /// Flag that controls whether or not the inheritance tree of the + /// method to be included in the search for the ? + /// + /// + /// Flag that controls whether or not interfaces attributes of the + /// method to be included in the search for the ? + /// + public AttributeMatchMethodPointcut(Type attribute, bool inherit, bool checkInterfaces) + { + Attribute = attribute; + Inherit = inherit; + CheckInterfaces = checkInterfaces; + } + + /// + protected AttributeMatchMethodPointcut(SerializationInfo info, StreamingContext context) + { + Inherit = info.GetBoolean("Inherit"); + CheckInterfaces = info.GetBoolean("CheckInterfaces"); + var type = info.GetString("Attribute"); + Attribute = type != null ? Type.GetType(type) : null; + } + + /// + public virtual void GetObjectData(SerializationInfo info, StreamingContext context) + { + info.AddValue("Attribute", Attribute?.AssemblyQualifiedName); + info.AddValue("Inherit", Inherit); + info.AddValue("CheckInterfaces", CheckInterfaces); + } + + /// + /// The to match. + /// + /// + /// If the supplied value is not a that + /// derives from the class. + /// + public virtual Type Attribute + { + get { return _attribute; } + set { - } - - /// - /// Creates a new instance of the - /// - /// class. - /// - /// - /// The to match. - /// - /// - /// Flag that controls whether or not the inheritance tree of the - /// method to be included in the search for the ? - /// - public AttributeMatchMethodPointcut(Type attribute, bool inherit) - : this(attribute, inherit, false) - { - } - - /// - /// Creates a new instance of the - /// - /// class. - /// - /// - /// The to match. - /// - /// - /// Flag that controls whether or not the inheritance tree of the - /// method to be included in the search for the ? - /// - /// - /// Flag that controls whether or not interfaces attributes of the - /// method to be included in the search for the ? - /// - public AttributeMatchMethodPointcut(Type attribute, bool inherit, bool checkInterfaces) - { - Attribute = attribute; - Inherit = inherit; - CheckInterfaces = checkInterfaces; - } - - /// - protected AttributeMatchMethodPointcut(SerializationInfo info, StreamingContext context) - { - Inherit = info.GetBoolean("Inherit"); - CheckInterfaces = info.GetBoolean("CheckInterfaces"); - var type = info.GetString("Attribute"); - Attribute = type != null ? Type.GetType(type) : null; - } - - /// - public virtual void GetObjectData(SerializationInfo info, StreamingContext context) - { - info.AddValue("Attribute", Attribute?.AssemblyQualifiedName); - info.AddValue("Inherit", Inherit); - info.AddValue("CheckInterfaces", CheckInterfaces); - } - - /// - /// The to match. - /// - /// - /// If the supplied value is not a that - /// derives from the class. - /// - public virtual Type Attribute - { - get { return _attribute; } - set - { - if (value != null) - { - if (!typeof (Attribute).IsAssignableFrom(value)) - { - throw new ArgumentException( - string.Format( - "The [{0}] Type must be derived from the [System.Attribute] class.", - value)); - } - } - _attribute = value; - } - } - - /// - /// Is the inheritance tree of the method to be included in the search for the - /// ? - /// - /// - ///

- /// The default is . - ///

- ///
- public virtual bool Inherit - { - get { return _inherit; } - set { _inherit = value; } - } - - /// - /// Is the interfaces attributes of the method to be included in the search for theg - /// ? - /// - /// - ///

- /// The default is . - ///

- ///
- public virtual bool CheckInterfaces - { - get { return _checkInterfaces; } - set { _checkInterfaces = value; } - } - - /// - /// Does the supplied satisfy this matcher? - /// - /// 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) - { - if (method.IsDefined(Attribute, Inherit)) + if (value != null) { - // Checks whether the attribute is defined on the method or a super definition of the method - // but does not check attributes on implemented interfaces. - return true; - } - else - { - if (CheckInterfaces) + if (!typeof(Attribute).IsAssignableFrom(value)) { - // Also check whether the attribute is defined on a method implemented from an interface. - // First find all interfaces for the type that contains the method. - // Next, check each interface for the presence of the attribute on the corresponding - // method from the interface. - Type[] parameterTypes = ReflectionUtils.GetParameterTypes(method); - foreach (Type interfaceType in method.DeclaringType.GetInterfaces()) - { - // The method may be implemented explicitly, so the method name - // will include the interface name also - string methodName = method.Name; - if (methodName.IndexOf('.') != -1) - { - if (methodName.StartsWith(interfaceType.FullName.Replace('+', '.'))) - { - methodName = methodName.Remove(0, interfaceType.FullName.Length + 1); - } - } + throw new ArgumentException( + string.Format( + "The [{0}] Type must be derived from the [System.Attribute] class.", + value)); + } + } - MethodInfo intfMethod = interfaceType.GetMethod(methodName, parameterTypes); - if (intfMethod != null && intfMethod.IsDefined(Attribute, Inherit)) + _attribute = value; + } + } + + /// + /// Is the inheritance tree of the method to be included in the search for the + /// ? + /// + /// + ///

+ /// The default is . + ///

+ ///
+ public virtual bool Inherit + { + get { return _inherit; } + set { _inherit = value; } + } + + /// + /// Is the interfaces attributes of the method to be included in the search for theg + /// ? + /// + /// + ///

+ /// The default is . + ///

+ ///
+ public virtual bool CheckInterfaces + { + get { return _checkInterfaces; } + set { _checkInterfaces = value; } + } + + /// + /// Does the supplied satisfy this matcher? + /// + /// 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) + { + if (method.IsDefined(Attribute, Inherit)) + { + // Checks whether the attribute is defined on the method or a super definition of the method + // but does not check attributes on implemented interfaces. + return true; + } + else + { + if (CheckInterfaces) + { + // Also check whether the attribute is defined on a method implemented from an interface. + // First find all interfaces for the type that contains the method. + // Next, check each interface for the presence of the attribute on the corresponding + // method from the interface. + Type[] parameterTypes = ReflectionUtils.GetParameterTypes(method); + foreach (Type interfaceType in method.DeclaringType.GetInterfaces()) + { + // The method may be implemented explicitly, so the method name + // will include the interface name also + string methodName = method.Name; + if (methodName.IndexOf('.') != -1) + { + if (methodName.StartsWith(interfaceType.FullName.Replace('+', '.'))) { - return true; + methodName = methodName.Remove(0, interfaceType.FullName.Length + 1); } } + + MethodInfo intfMethod = interfaceType.GetMethod(methodName, parameterTypes); + if (intfMethod != null && intfMethod.IsDefined(Attribute, Inherit)) + { + return true; + } } - return false; } - } - } + + return false; + } + } } diff --git a/src/Spring/Spring.Aop/Aop/Support/AttributeMatchMethodPointcutAdvisor.cs b/src/Spring/Spring.Aop/Aop/Support/AttributeMatchMethodPointcutAdvisor.cs index cfe9276f..76c6e76b 100644 --- a/src/Spring/Spring.Aop/Aop/Support/AttributeMatchMethodPointcutAdvisor.cs +++ b/src/Spring/Spring.Aop/Aop/Support/AttributeMatchMethodPointcutAdvisor.cs @@ -21,133 +21,131 @@ #region Imports using System.Runtime.Serialization; - using AopAlliance.Aop; using Spring.Core; #endregion -namespace Spring.Aop.Support +namespace Spring.Aop.Support; + +/// +/// Convenient class for attribute-match method pointcuts that hold an Interceptor, +/// making them an Advisor. +/// +/// Bruno Baia +[Serializable] +public class AttributeMatchMethodPointcutAdvisor + : AttributeMatchMethodPointcut, IPointcutAdvisor, IOrdered, ISerializable { - /// - /// Convenient class for attribute-match method pointcuts that hold an Interceptor, - /// making them an Advisor. - /// - /// Bruno Baia - [Serializable] - public class AttributeMatchMethodPointcutAdvisor - : AttributeMatchMethodPointcut, IPointcutAdvisor, IOrdered, ISerializable - { - private int _order = Int32.MaxValue; - private IAdvice _advice; + private int _order = Int32.MaxValue; + private IAdvice _advice; - /// - /// Creates a new instance of the - /// class. - /// - public AttributeMatchMethodPointcutAdvisor() - { - } + /// + /// Creates a new instance of the + /// class. + /// + public AttributeMatchMethodPointcutAdvisor() + { + } - /// - /// Creates a new instance of the - /// class - /// for the supplied . - /// - /// the advice to apply if the pointcut matches - public AttributeMatchMethodPointcutAdvisor(IAdvice advice) - { - this._advice = advice; - } + /// + /// Creates a new instance of the + /// class + /// for the supplied . + /// + /// the advice to apply if the pointcut matches + public AttributeMatchMethodPointcutAdvisor(IAdvice advice) + { + this._advice = advice; + } - /// - /// Creates a new instance of the - /// class - /// for the supplied . - /// - /// - /// The to match. - /// - /// - /// Flag that controls whether or not the inheritance tree of the - /// method to be included in the search for the ? - /// - /// the advice to apply if the pointcut matches - public AttributeMatchMethodPointcutAdvisor(Type attribute, bool inherit, IAdvice advice) - :base(attribute, inherit) - { - this._advice = advice; - } + /// + /// Creates a new instance of the + /// class + /// for the supplied . + /// + /// + /// The to match. + /// + /// + /// Flag that controls whether or not the inheritance tree of the + /// method to be included in the search for the ? + /// + /// the advice to apply if the pointcut matches + public AttributeMatchMethodPointcutAdvisor(Type attribute, bool inherit, IAdvice advice) + : base(attribute, inherit) + { + this._advice = advice; + } - /// - private AttributeMatchMethodPointcutAdvisor(SerializationInfo info, StreamingContext context) - : base(info, context) - { - Order = info.GetInt32("Order"); - Advice = (IAdvice) info.GetValue("Advice", typeof(IAdvice)); - } + /// + private AttributeMatchMethodPointcutAdvisor(SerializationInfo info, StreamingContext context) + : base(info, context) + { + Order = info.GetInt32("Order"); + Advice = (IAdvice) info.GetValue("Advice", typeof(IAdvice)); + } - /// - public override void GetObjectData(SerializationInfo info, StreamingContext context) - { - base.GetObjectData(info, context); - info.AddValue("Order", Order); - info.AddValue("Advice", Advice); - } + /// + public override void GetObjectData(SerializationInfo info, StreamingContext context) + { + base.GetObjectData(info, context); + info.AddValue("Order", Order); + info.AddValue("Advice", Advice); + } - /// - /// Is this advice associated with a particular instance? - /// - /// - /// if this advice is associated with a - /// particular instance. - /// - /// - /// Always; this property is not yet supported. - /// - public virtual bool IsPerInstance - { - get - { - throw new NotSupportedException( - "The 'IsPerInstance' property of the IAdvisor interface is " + - "not yet supported in Spring.NET."); - } - } + /// + /// Is this advice associated with a particular instance? + /// + /// + /// if this advice is associated with a + /// particular instance. + /// + /// + /// Always; this property is not yet supported. + /// + public virtual bool IsPerInstance + { + get + { + throw new NotSupportedException( + "The 'IsPerInstance' property of the IAdvisor interface is " + + "not yet supported in Spring.NET."); + } + } - /// - /// Returns this s order in the - /// interception chain. - /// - /// - /// This s order in the - /// interception chain. - /// - public virtual int Order - { - get { return this._order; } - set { this._order = value; } - } + /// + /// Returns this s order in the + /// interception chain. + /// + /// + /// This s order in the + /// interception chain. + /// + public virtual int Order + { + get { return this._order; } + set { this._order = value; } + } - /// - /// Return the advice part of this advisor. - /// - /// - /// The advice that should apply if the pointcut matches. - /// - /// - public virtual IAdvice Advice - { - get { return this._advice; } - set { this._advice = value; } - } + /// + /// Return the advice part of this advisor. + /// + /// + /// The advice that should apply if the pointcut matches. + /// + /// + public virtual IAdvice Advice + { + get { return this._advice; } + set { this._advice = value; } + } - /// - /// The that drives this advisor. - /// - public virtual IPointcut Pointcut - { - get { return this; } - } - } + /// + /// The that drives this advisor. + /// + public virtual IPointcut Pointcut + { + get { return this; } + } } diff --git a/src/Spring/Spring.Aop/Aop/Support/AttributeMatchingPointcut.cs b/src/Spring/Spring.Aop/Aop/Support/AttributeMatchingPointcut.cs index 66adfacb..43969239 100644 --- a/src/Spring/Spring.Aop/Aop/Support/AttributeMatchingPointcut.cs +++ b/src/Spring/Spring.Aop/Aop/Support/AttributeMatchingPointcut.cs @@ -20,102 +20,102 @@ using Spring.Util; -namespace Spring.Aop.Support +namespace Spring.Aop.Support; + +/// +/// Pointcut that looks for a specific attribute being present on a class or +/// method. +/// +/// Juergen Hoeller +/// Mark Pollack (.NET) +[Serializable] +public class AttributeMatchingPointcut : IPointcut { + private readonly ITypeFilter typeFilter; + private readonly IMethodMatcher methodMatcher; + /// - /// Pointcut that looks for a specific attribute being present on a class or - /// method. + /// Initializes a new instance of the class for the + /// given attribute type. /// - /// Juergen Hoeller - /// Mark Pollack (.NET) - [Serializable] - public class AttributeMatchingPointcut : IPointcut + /// Type of the attribute to look for at the class level. + public AttributeMatchingPointcut(Type attributeType) { - private readonly ITypeFilter typeFilter; - private readonly IMethodMatcher methodMatcher; + ValidateAttributeTypeArgument(attributeType); + this.typeFilter = new AttributeTypeFilter(attributeType); + this.methodMatcher = TrueMethodMatcher.True; + } + /// + /// Initializes a new instance of the class for the + /// given attribute type + /// + /// Type of the attribute. + /// if set to true [check inherited]. + public AttributeMatchingPointcut(Type attributeType, bool checkInherited) + { + ValidateAttributeTypeArgument(attributeType); + this.typeFilter = new AttributeTypeFilter(attributeType, checkInherited); + this.methodMatcher = TrueMethodMatcher.True; + } - /// - /// Initializes a new instance of the class for the - /// given attribute type. - /// - /// Type of the attribute to look for at the class level. - public AttributeMatchingPointcut(Type attributeType) + /// + /// Initializes a new instance of the class for the given + /// attribute type + /// + /// The attribute type to look for at the class level. + /// The attribute type to look for at the method attribute. + public AttributeMatchingPointcut(Type classAttributeType, Type methodAttributeType) + { + AssertUtils.IsTrue(classAttributeType != null || methodAttributeType != null, + "Either Type attribute type or Method attribute type needs to be specified (or both)"); + + if (classAttributeType != null) + { + this.typeFilter = new AttributeTypeFilter(classAttributeType); + } + else + { + this.typeFilter = TrueTypeFilter.True; + } + + if (methodAttributeType != null) + { + this.methodMatcher = new AttributeMethodMatcher(methodAttributeType); + } + else { - ValidateAttributeTypeArgument(attributeType); - this.typeFilter = new AttributeTypeFilter(attributeType); this.methodMatcher = TrueMethodMatcher.True; } + } - /// - /// Initializes a new instance of the class for the - /// given attribute type - /// - /// Type of the attribute. - /// if set to true [check inherited]. - public AttributeMatchingPointcut(Type attributeType, bool checkInherited) + /// + /// The for this pointcut. + /// + /// The current . + public ITypeFilter TypeFilter + { + get { return this.typeFilter; } + } + + /// + /// The for this pointcut. + /// + /// The current . + public IMethodMatcher MethodMatcher + { + get { return this.methodMatcher; } + } + + private static void ValidateAttributeTypeArgument(Type attributeType) + { + AssertUtils.ArgumentNotNull(attributeType, "attributeType"); + if (!typeof(Attribute).IsAssignableFrom(attributeType)) { - ValidateAttributeTypeArgument(attributeType); - this.typeFilter = new AttributeTypeFilter(attributeType, checkInherited); - this.methodMatcher = TrueMethodMatcher.True; - } - - /// - /// Initializes a new instance of the class for the given - /// attribute type - /// - /// The attribute type to look for at the class level. - /// The attribute type to look for at the method attribute. - public AttributeMatchingPointcut(Type classAttributeType, Type methodAttributeType) - { - AssertUtils.IsTrue(classAttributeType != null || methodAttributeType != null, - "Either Type attribute type or Method attribute type needs to be specified (or both)"); - - if (classAttributeType != null) - { - this.typeFilter = new AttributeTypeFilter(classAttributeType); - } else - { - this.typeFilter = TrueTypeFilter.True; - } - - if (methodAttributeType != null) - { - this.methodMatcher = new AttributeMethodMatcher(methodAttributeType); - } else - { - this.methodMatcher = TrueMethodMatcher.True; - } - } - - /// - /// The for this pointcut. - /// - /// The current . - public ITypeFilter TypeFilter - { - get { return this.typeFilter; } - } - - /// - /// The for this pointcut. - /// - /// The current . - public IMethodMatcher MethodMatcher - { - get { return this.methodMatcher; } - } - - private static void ValidateAttributeTypeArgument(Type attributeType) - { - AssertUtils.ArgumentNotNull(attributeType, "attributeType"); - if (!typeof(Attribute).IsAssignableFrom(attributeType)) - { - throw new ArgumentException( - string.Format( - "The [{0}] Type must be derived from the [System.Attribute] class.", - attributeType)); - } + throw new ArgumentException( + string.Format( + "The [{0}] Type must be derived from the [System.Attribute] class.", + attributeType)); } } } diff --git a/src/Spring/Spring.Aop/Aop/Support/AttributeMethodMatcher.cs b/src/Spring/Spring.Aop/Aop/Support/AttributeMethodMatcher.cs index 0162fc4a..35f1492c 100644 --- a/src/Spring/Spring.Aop/Aop/Support/AttributeMethodMatcher.cs +++ b/src/Spring/Spring.Aop/Aop/Support/AttributeMethodMatcher.cs @@ -20,105 +20,101 @@ using System.Reflection; using System.Runtime.Serialization; - using Spring.Util; -namespace Spring.Aop.Support +namespace Spring.Aop.Support; + +/// +/// MethodMatcher that looks for a specific attribute being present on the +/// method (checking both the method on the onviked interface, if any and the corresponding +/// method on the target class +/// +/// Juergen hoeller +/// Mark Pollack +/// +[Serializable] +public class AttributeMethodMatcher : StaticMethodMatcher, ISerializable { + private readonly Type attributeType; + /// - /// MethodMatcher that looks for a specific attribute being present on the - /// method (checking both the method on the onviked interface, if any and the corresponding - /// method on the target class + /// Initializes a new instance of the class for the + /// given atribute type. /// - /// Juergen hoeller - /// Mark Pollack - /// - [Serializable] - public class AttributeMethodMatcher : StaticMethodMatcher, ISerializable + /// Type of the attribute to look for. + public AttributeMethodMatcher(Type attributeType) { - private readonly Type attributeType; + ValidateAttributeTypeArgument(attributeType); + this.attributeType = attributeType; + } + /// + private AttributeMethodMatcher(SerializationInfo info, StreamingContext context) + { + var type = info.GetString("AttributeType"); + attributeType = type != null ? Type.GetType(type) : null; + } - /// - /// Initializes a new instance of the class for the - /// given atribute type. - /// - /// Type of the attribute to look for. - public AttributeMethodMatcher(Type attributeType) + /// + public void GetObjectData(SerializationInfo info, StreamingContext context) + { + info.AddValue("AttributeType", attributeType?.AssemblyQualifiedName); + } + + /// + /// Does the supplied satisfy this matcher? + /// + /// 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. + /// + /// + ///

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

+ ///
+ public override bool Matches(MethodInfo method, Type targetType) + { + if (method.IsDefined(attributeType, true)) { - ValidateAttributeTypeArgument(attributeType); - this.attributeType = attributeType; + // Checks whether the attribute is defined on the method or a super definition of the method + // but does not check attributes on implemented interfaces. + return true; } - - /// - private AttributeMethodMatcher(SerializationInfo info, StreamingContext context) + else { - var type = info.GetString("AttributeType"); - attributeType = type != null ? Type.GetType(type) : null; - } + Type[] parameterTypes = ReflectionUtils.GetParameterTypes(method); - /// - public void GetObjectData(SerializationInfo info, StreamingContext context) - { - info.AddValue("AttributeType", attributeType?.AssemblyQualifiedName); - } - - /// - /// Does the supplied satisfy this matcher? - /// - /// 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. - /// - /// - ///

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

- ///
- public override bool Matches(MethodInfo method, Type targetType) - { - if (method.IsDefined(attributeType, true)) + // Also check whether the attribute is defined on a method implemented from an interface. + // First find all interfaces for the type that contains the method. + // Next, check each interface for the presence of the attribute on the corresponding + // method from the interface. + foreach (Type interfaceType in method.DeclaringType.GetInterfaces()) { - // Checks whether the attribute is defined on the method or a super definition of the method - // but does not check attributes on implemented interfaces. - return true; + MethodInfo intfMethod = interfaceType.GetMethod(method.Name, parameterTypes); + if (intfMethod != null && intfMethod.IsDefined(attributeType, true)) + { + return true; + } } - else - { - Type[] parameterTypes = ReflectionUtils.GetParameterTypes(method); - - // Also check whether the attribute is defined on a method implemented from an interface. - // First find all interfaces for the type that contains the method. - // Next, check each interface for the presence of the attribute on the corresponding - // method from the interface. - foreach (Type interfaceType in method.DeclaringType.GetInterfaces()) - { - MethodInfo intfMethod = interfaceType.GetMethod(method.Name, parameterTypes); - if (intfMethod != null && intfMethod.IsDefined(attributeType, true)) - { - return true; - } - } - - return false; - } + return false; } + } - private static void ValidateAttributeTypeArgument(Type attributeType) + private static void ValidateAttributeTypeArgument(Type attributeType) + { + AssertUtils.ArgumentNotNull(attributeType, "attributeType"); + if (!typeof(Attribute).IsAssignableFrom(attributeType)) { - AssertUtils.ArgumentNotNull(attributeType, "attributeType"); - if (!typeof(Attribute).IsAssignableFrom(attributeType)) - { - throw new ArgumentException( - string.Format( - "The [{0}] Type must be derived from the [System.Attribute] class.", - attributeType)); - } + throw new ArgumentException( + string.Format( + "The [{0}] Type must be derived from the [System.Attribute] class.", + attributeType)); } } } diff --git a/src/Spring/Spring.Aop/Aop/Support/AttributeTypeFilter.cs b/src/Spring/Spring.Aop/Aop/Support/AttributeTypeFilter.cs index acd7f7e8..c572fd0f 100644 --- a/src/Spring/Spring.Aop/Aop/Support/AttributeTypeFilter.cs +++ b/src/Spring/Spring.Aop/Aop/Support/AttributeTypeFilter.cs @@ -20,88 +20,86 @@ using Spring.Util; -namespace Spring.Aop.Support +namespace Spring.Aop.Support; + +/// +/// ITypeFilter that looks for a specific attribute being present on a class +/// +/// Juergen Hoeller +/// Mark Pollack (.NET) +public class AttributeTypeFilter : ITypeFilter { + private readonly Type attributeType; + private readonly bool checkInherited; + /// - /// ITypeFilter that looks for a specific attribute being present on a class + /// The attribute for this filter. /// - /// Juergen Hoeller - /// Mark Pollack (.NET) - public class AttributeTypeFilter : ITypeFilter + public Type AttributeType { - private readonly Type attributeType; - private readonly bool checkInherited; + get { return attributeType; } + } - /// - /// The attribute for this filter. - /// - public Type AttributeType + /// + /// Indicates, whether this filter considers base types for filtering. + /// + public bool CheckInherited + { + get { return checkInherited; } + } + + /// + /// Initializes a new instance of the class for the + /// given attribute type. + /// + /// Type of the attribute to look for. + public AttributeTypeFilter(Type attributeType) : this(attributeType, false) + { + } + + /// + /// Initializes a new instance of the class for the + /// given attribute type. + /// + /// Type of the attribute. + /// if set to true [check inherited]. + public AttributeTypeFilter(Type attributeType, bool checkInherited) + { + #region parameter validation + + AssertUtils.ArgumentNotNull(attributeType, "attributeType"); + if (!typeof(Attribute).IsAssignableFrom(attributeType)) { - get { return attributeType; } + throw new ArgumentException( + string.Format( + "The [{0}] Type must be derived from the [System.Attribute] class.", + attributeType)); } - /// - /// Indicates, whether this filter considers base types for filtering. - /// - public bool CheckInherited + #endregion + + this.attributeType = attributeType; + this.checkInherited = checkInherited; + } + + /// + /// Should the pointcut apply to the supplied ? + /// + /// The candidate . + /// + /// if the advice should apply to the supplied + /// + /// + public bool Matches(Type type) + { + if (checkInherited) { - get { return checkInherited; } + return AttributeUtils.FindAttribute(type, attributeType) != null; } - - /// - /// Initializes a new instance of the class for the - /// given attribute type. - /// - /// Type of the attribute to look for. - public AttributeTypeFilter(Type attributeType) : this(attributeType, false) + else { - + object[] atts = type.GetCustomAttributes(attributeType, false); + return ArrayUtils.HasLength(atts); } - - /// - /// Initializes a new instance of the class for the - /// given attribute type. - /// - /// Type of the attribute. - /// if set to true [check inherited]. - public AttributeTypeFilter(Type attributeType, bool checkInherited) - { - #region parameter validation - AssertUtils.ArgumentNotNull(attributeType, "attributeType"); - if (!typeof(Attribute).IsAssignableFrom(attributeType)) - { - throw new ArgumentException( - string.Format( - "The [{0}] Type must be derived from the [System.Attribute] class.", - attributeType)); - } - #endregion - this.attributeType = attributeType; - this.checkInherited = checkInherited; - } - - - /// - /// Should the pointcut apply to the supplied ? - /// - /// The candidate . - /// - /// if the advice should apply to the supplied - /// - /// - public bool Matches(Type type) - { - if (checkInherited) - { - return AttributeUtils.FindAttribute(type, attributeType) != null; - } - else - { - object[] atts = type.GetCustomAttributes(attributeType, false); - return ArrayUtils.HasLength(atts); - } - } - - } } diff --git a/src/Spring/Spring.Aop/Aop/Support/ComposablePointcut.cs b/src/Spring/Spring.Aop/Aop/Support/ComposablePointcut.cs index d97cebca..ade85213 100644 --- a/src/Spring/Spring.Aop/Aop/Support/ComposablePointcut.cs +++ b/src/Spring/Spring.Aop/Aop/Support/ComposablePointcut.cs @@ -22,152 +22,151 @@ #endregion -namespace Spring.Aop.Support +namespace Spring.Aop.Support; + +/// +/// Convenient class for building up pointcuts. +/// +/// +///

+/// All methods return a +/// instance, which facilitates the following concise usage pattern... +///

+/// +/// IPointcut pointcut = new ComposablePointcut() +/// .Union(typeFilter) +/// .Intersection(methodMatcher) +/// .Intersection(pointcut); +/// +///

+/// There is no Union() method on this class. Use the +/// method for such functionality. +///

+///
+/// Rod Johnson +/// Aleksandar Seovic (.NET) +[Serializable] +public class ComposablePointcut : IPointcut { - /// - /// Convenient class for building up pointcuts. - /// - /// - ///

- /// All methods return a - /// instance, which facilitates the following concise usage pattern... - ///

- /// - /// IPointcut pointcut = new ComposablePointcut() - /// .Union(typeFilter) - /// .Intersection(methodMatcher) - /// .Intersection(pointcut); - /// - ///

- /// There is no Union() method on this class. Use the - /// method for such functionality. - ///

- ///
- /// Rod Johnson - /// Aleksandar Seovic (.NET) - [Serializable] - public class ComposablePointcut : IPointcut - { - private ITypeFilter _typeFilter; - private IMethodMatcher _methodMatcher; + private ITypeFilter _typeFilter; + private IMethodMatcher _methodMatcher; - /// - /// Creates a new instance of the - /// class - /// that matches all the methods on all s. - /// - public ComposablePointcut() - { - _typeFilter = TrueTypeFilter.True; - _methodMatcher = TrueMethodMatcher.True; - } + /// + /// Creates a new instance of the + /// class + /// that matches all the methods on all s. + /// + public ComposablePointcut() + { + _typeFilter = TrueTypeFilter.True; + _methodMatcher = TrueMethodMatcher.True; + } - /// - /// Creates a new instance of the - /// class - /// that uses the supplied and - /// . - /// - /// - /// The type filter to use. - /// - /// - /// The method matcher to use. - /// - public ComposablePointcut(ITypeFilter typeFilter, IMethodMatcher methodMatcher) - { - _typeFilter = typeFilter; - _methodMatcher = methodMatcher; - } + /// + /// Creates a new instance of the + /// class + /// that uses the supplied and + /// . + /// + /// + /// The type filter to use. + /// + /// + /// The method matcher to use. + /// + public ComposablePointcut(ITypeFilter typeFilter, IMethodMatcher methodMatcher) + { + _typeFilter = typeFilter; + _methodMatcher = methodMatcher; + } - /// - /// The for this pointcut. - /// - /// - /// The current . - /// - public virtual ITypeFilter TypeFilter - { - get { return _typeFilter; } - } + /// + /// The for this pointcut. + /// + /// + /// The current . + /// + public virtual ITypeFilter TypeFilter + { + get { return _typeFilter; } + } - /// - /// The for this pointcut. - /// - /// - /// The current . - /// - public virtual IMethodMatcher MethodMatcher - { - get { return _methodMatcher; } - } + /// + /// The for this pointcut. + /// + /// + /// The current . + /// + public virtual IMethodMatcher MethodMatcher + { + get { return _methodMatcher; } + } - /// - /// Changes the current type filter to be the union of the existing filter and the - /// supplied . - /// - /// The filter to union with. - /// - /// The union of the existing filter and the supplied . - /// - public virtual ComposablePointcut Union(ITypeFilter filter) - { - _typeFilter = TypeFilters.Union(_typeFilter, filter); - return this; - } + /// + /// Changes the current type filter to be the union of the existing filter and the + /// supplied . + /// + /// The filter to union with. + /// + /// The union of the existing filter and the supplied . + /// + public virtual ComposablePointcut Union(ITypeFilter filter) + { + _typeFilter = TypeFilters.Union(_typeFilter, filter); + return this; + } - /// - /// Changes the current type filter to be the intersection of the existing filter - /// and the supplied . - /// - /// The filter to diff against. - /// - /// The intersection of the existing filter and the supplied . - /// - public virtual ComposablePointcut Intersection(ITypeFilter filter) - { - _typeFilter = TypeFilters.Intersection(_typeFilter, filter); - return this; - } + /// + /// Changes the current type filter to be the intersection of the existing filter + /// and the supplied . + /// + /// The filter to diff against. + /// + /// The intersection of the existing filter and the supplied . + /// + public virtual ComposablePointcut Intersection(ITypeFilter filter) + { + _typeFilter = TypeFilters.Intersection(_typeFilter, filter); + return this; + } - /// - /// Changes the current method matcher to be the union of the existing matcher and the - /// supplied . - /// - /// The matcher to union with. - /// - /// The union of the existing matcher and the supplied . - /// - public virtual ComposablePointcut Union(IMethodMatcher matcher) - { - _methodMatcher = MethodMatchers.Union(_methodMatcher, matcher); - return this; - } + /// + /// Changes the current method matcher to be the union of the existing matcher and the + /// supplied . + /// + /// The matcher to union with. + /// + /// The union of the existing matcher and the supplied . + /// + public virtual ComposablePointcut Union(IMethodMatcher matcher) + { + _methodMatcher = MethodMatchers.Union(_methodMatcher, matcher); + return this; + } - /// - /// Changes the current method matcher to be the intersection of the existing matcher - /// and the supplied . - /// - /// The matcher to diff against. - /// - /// The intersection of the existing matcher and the supplied . - /// - public virtual ComposablePointcut Intersection(IMethodMatcher matcher) - { - _methodMatcher = MethodMatchers.Intersection(_methodMatcher, matcher); - return this; - } + /// + /// Changes the current method matcher to be the intersection of the existing matcher + /// and the supplied . + /// + /// The matcher to diff against. + /// + /// The intersection of the existing matcher and the supplied . + /// + public virtual ComposablePointcut Intersection(IMethodMatcher matcher) + { + _methodMatcher = MethodMatchers.Intersection(_methodMatcher, matcher); + return this; + } - /// - /// Changes current pointcut to intersection of the current and supplied pointcut - /// - /// pointcut to diff against - /// updated pointcut - public virtual ComposablePointcut Intersection(IPointcut other) - { - _typeFilter = TypeFilters.Intersection(_typeFilter, other.TypeFilter); - _methodMatcher = MethodMatchers.Intersection(_methodMatcher, other.MethodMatcher); - return this; - } - } + /// + /// Changes current pointcut to intersection of the current and supplied pointcut + /// + /// pointcut to diff against + /// updated pointcut + public virtual ComposablePointcut Intersection(IPointcut other) + { + _typeFilter = TypeFilters.Intersection(_typeFilter, other.TypeFilter); + _methodMatcher = MethodMatchers.Intersection(_methodMatcher, other.MethodMatcher); + return this; + } } diff --git a/src/Spring/Spring.Aop/Aop/Support/ControlFlowPointcut.cs b/src/Spring/Spring.Aop/Aop/Support/ControlFlowPointcut.cs index f3725bcc..f7e94ae5 100644 --- a/src/Spring/Spring.Aop/Aop/Support/ControlFlowPointcut.cs +++ b/src/Spring/Spring.Aop/Aop/Support/ControlFlowPointcut.cs @@ -16,222 +16,220 @@ using System.Reflection; using System.Runtime.Serialization; - using Spring.Core; -namespace Spring.Aop.Support +namespace Spring.Aop.Support; + +/// +/// Pointcut and method matcher for use in simple cflow-style +/// pointcuts. +/// +/// +///

+/// Evaluating such pointcuts is slower than evaluating normal pointcuts, +/// but can nevertheless be useful in some cases. Of course, your mileage +/// may vary as to what 'slower' actually means. +///

+///
+/// Rod Johnson +/// Simon White (.NET) +[Serializable] +public class ControlFlowPointcut : IPointcut, ITypeFilter, IMethodMatcher, ISerializable { - /// - /// Pointcut and method matcher for use in simple cflow-style - /// pointcuts. - /// - /// - ///

- /// Evaluating such pointcuts is slower than evaluating normal pointcuts, - /// but can nevertheless be useful in some cases. Of course, your mileage - /// may vary as to what 'slower' actually means. - ///

- ///
- /// Rod Johnson - /// Simon White (.NET) - [Serializable] - public class ControlFlowPointcut : IPointcut, ITypeFilter, IMethodMatcher, ISerializable - { - private Type _type; - private string _methodName; - private int _evaluationCount; + private Type _type; + private string _methodName; + private int _evaluationCount; - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The class under which all control flows are to be matched. - /// - public ControlFlowPointcut(Type type) : this(type, null) - { - } + /// + /// Creates a new instance of the + /// class. + /// + /// + /// The class under which all control flows are to be matched. + /// + public ControlFlowPointcut(Type type) : this(type, null) + { + } - /// - /// Construct a new pointcut that matches all calls below the - /// given method in the given class. - /// - /// - ///

- /// If the supplied is - /// , all control flows below the given - /// class will be successfully matched. - ///

- ///
- /// - /// The class under which all control flows are to be matched. - /// - /// - /// The method name under which all control flows are to be matched. - /// - public ControlFlowPointcut(Type type, string methodName) - { - _type = type; - _methodName = methodName; - } + /// + /// Construct a new pointcut that matches all calls below the + /// given method in the given class. + /// + /// + ///

+ /// If the supplied is + /// , all control flows below the given + /// class will be successfully matched. + ///

+ ///
+ /// + /// The class under which all control flows are to be matched. + /// + /// + /// The method name under which all control flows are to be matched. + /// + public ControlFlowPointcut(Type type, string methodName) + { + _type = type; + _methodName = methodName; + } - /// - private ControlFlowPointcut(SerializationInfo info, StreamingContext context) - { - var type = info.GetString("Type"); - _type = type != null ? Type.GetType(type) : null; - _methodName = info.GetString("MethodName"); - _evaluationCount = info.GetInt32("EvaluationCount"); - } + /// + private ControlFlowPointcut(SerializationInfo info, StreamingContext context) + { + var type = info.GetString("Type"); + _type = type != null ? Type.GetType(type) : null; + _methodName = info.GetString("MethodName"); + _evaluationCount = info.GetInt32("EvaluationCount"); + } - /// - public void GetObjectData(SerializationInfo info, StreamingContext context) - { - info.AddValue("Type", _type?.AssemblyQualifiedName); - info.AddValue("MethodName", _methodName); - info.AddValue("EvaluationCount", _evaluationCount); - } + /// + public void GetObjectData(SerializationInfo info, StreamingContext context) + { + info.AddValue("Type", _type?.AssemblyQualifiedName); + info.AddValue("MethodName", _methodName); + info.AddValue("EvaluationCount", _evaluationCount); + } - /// - /// The for this pointcut. - /// - /// - /// The current . - /// - public ITypeFilter TypeFilter - { - get { return this; } - } + /// + /// The for this pointcut. + /// + /// + /// The current . + /// + public ITypeFilter TypeFilter + { + get { return this; } + } - /// - /// Gets the number of times this pointcut has been evaluated. - /// - /// - ///

- /// Useful as a debugging aid. - ///

- ///

- /// Note that this value is distinct from the number of times that this - /// pointcut sucessfully matches a target method, in that a - /// may be evaluated many times but - /// never actually match even once. - ///

- ///
- /// - /// The number of times this pointcut has been evaluated. - /// - public int EvaluationCount - { - get { return _evaluationCount; } - } + /// + /// Gets the number of times this pointcut has been evaluated. + /// + /// + ///

+ /// Useful as a debugging aid. + ///

+ ///

+ /// Note that this value is distinct from the number of times that this + /// pointcut sucessfully matches a target method, in that a + /// may be evaluated many times but + /// never actually match even once. + ///

+ ///
+ /// + /// The number of times this pointcut has been evaluated. + /// + public int EvaluationCount + { + get { return _evaluationCount; } + } - /// - /// The for this pointcut. - /// - /// - /// The current . - /// - public IMethodMatcher MethodMatcher - { - get { return this; } - } + /// + /// The for this pointcut. + /// + /// + /// The current . + /// + public IMethodMatcher MethodMatcher + { + get { return this; } + } - /// - /// Is this a runtime pointcut? - /// - /// - ///

- /// This implementation is a runtime pointcut, and so always returns - /// . - ///

- ///
- /// - /// if this is a runtime pointcut. - /// - /// - public bool IsRuntime - { - get { return true; } - } + /// + /// Is this a runtime pointcut? + /// + /// + ///

+ /// This implementation is a runtime pointcut, and so always returns + /// . + ///

+ ///
+ /// + /// if this is a runtime pointcut. + /// + /// + public bool IsRuntime + { + get { return true; } + } - /// - /// Should the pointcut apply to the supplied ? - /// - /// - ///

- /// Subclasses are encouraged to override this method for greater - /// filtering (and performance). - ///

- ///

- /// This, the default, implementation always matches (returns - /// ). - ///

- ///
- /// The candidate target class. - /// - /// if the advice should apply to the supplied - /// - /// - public virtual bool Matches(Type type) - { - return true; - } + /// + /// Should the pointcut apply to the supplied ? + /// + /// + ///

+ /// Subclasses are encouraged to override this method for greater + /// filtering (and performance). + ///

+ ///

+ /// This, the default, implementation always matches (returns + /// ). + ///

+ ///
+ /// The candidate target class. + /// + /// if the advice should apply to the supplied + /// + /// + public virtual bool Matches(Type type) + { + return true; + } - /// - /// Does the supplied satisfy this matcher? - /// Perform static checking. If this returns false, or if the isRuntime() method - /// returns false, no runtime check will be made. - /// - /// - ///

- /// Subclasses are encouraged to override this method if it is possible - /// to filter out some candidate classes. - ///

- ///

- /// This, the default, implementation always matches (returns - /// ). This means that the three argument - /// - /// method will always be invoked. - ///

- ///
- /// The candidate method. - /// - /// The target class (may be , in which case the - /// candidate class must be taken to be the 's - /// declaring class). - /// - /// - /// if this this method matches statically. - /// - /// - public virtual bool Matches(MethodInfo method, Type targetType) - { - return true; - } + /// + /// Does the supplied satisfy this matcher? + /// Perform static checking. If this returns false, or if the isRuntime() method + /// returns false, no runtime check will be made. + /// + /// + ///

+ /// Subclasses are encouraged to override this method if it is possible + /// to filter out some candidate classes. + ///

+ ///

+ /// This, the default, implementation always matches (returns + /// ). This means that the three argument + /// + /// method will always be invoked. + ///

+ ///
+ /// The candidate method. + /// + /// The target class (may be , in which case the + /// candidate class must be taken to be the 's + /// declaring class). + /// + /// + /// if this this method matches statically. + /// + /// + public virtual bool Matches(MethodInfo method, Type targetType) + { + return true; + } - /// - /// Is there a runtime (dynamic) match for the supplied - /// ? - /// - /// - ///

- /// Subclasses are encouraged to override this method if it is possible - /// to filter out some candidate classes. - ///

- ///
- /// The candidate method. - /// The target class. - /// The arguments to the method - /// - /// if there is a runtime match. - /// - public virtual bool Matches(MethodInfo method, Type targetType, object[] args) - { - ++_evaluationCount; - IControlFlow cflow = ControlFlowFactory.CreateControlFlow(); - return (_methodName != null) - ? cflow.Under(_type, _methodName) - : cflow.Under(_type); - } - } + /// + /// Is there a runtime (dynamic) match for the supplied + /// ? + /// + /// + ///

+ /// Subclasses are encouraged to override this method if it is possible + /// to filter out some candidate classes. + ///

+ ///
+ /// The candidate method. + /// The target class. + /// The arguments to the method + /// + /// if there is a runtime match. + /// + public virtual bool Matches(MethodInfo method, Type targetType, object[] args) + { + ++_evaluationCount; + IControlFlow cflow = ControlFlowFactory.CreateControlFlow(); + return (_methodName != null) + ? cflow.Under(_type, _methodName) + : cflow.Under(_type); + } } diff --git a/src/Spring/Spring.Aop/Aop/Support/DefaultIntroductionAdvisor.cs b/src/Spring/Spring.Aop/Aop/Support/DefaultIntroductionAdvisor.cs index 44de008d..c46ede95 100644 --- a/src/Spring/Spring.Aop/Aop/Support/DefaultIntroductionAdvisor.cs +++ b/src/Spring/Spring.Aop/Aop/Support/DefaultIntroductionAdvisor.cs @@ -25,255 +25,255 @@ using Spring.Collections; #endregion -namespace Spring.Aop.Support +namespace Spring.Aop.Support; + +/// +/// Simple implementation that +/// by default applies to any class. +/// +/// Rod Johnson +/// Aleksandar Seovic (.NET) +[Serializable] +public class DefaultIntroductionAdvisor : IIntroductionAdvisor, ITypeFilter { - /// - /// Simple implementation that - /// by default applies to any class. - /// - /// Rod Johnson - /// Aleksandar Seovic (.NET) - [Serializable] - public class DefaultIntroductionAdvisor : IIntroductionAdvisor, ITypeFilter - { - private readonly IAdvice _introduction; - private readonly ISet _interfaces = new HybridSet(); + private readonly IAdvice _introduction; + private readonly ISet _interfaces = new HybridSet(); - /// - /// Creates a new instance of the - /// class using - /// the supplied - /// - /// - ///

- /// This constructor adds all interfaces implemented by the supplied - /// (except the - /// interface) to the list of - /// interfaces to introduce. - ///

- ///
- /// The introduction to use. - public DefaultIntroductionAdvisor(IAdvice introduction) - : this(introduction, introduction.GetType().GetInterfaces()) - { - } + /// + /// Creates a new instance of the + /// class using + /// the supplied + /// + /// + ///

+ /// This constructor adds all interfaces implemented by the supplied + /// (except the + /// interface) to the list of + /// interfaces to introduce. + ///

+ ///
+ /// The introduction to use. + public DefaultIntroductionAdvisor(IAdvice introduction) + : this(introduction, introduction.GetType().GetInterfaces()) + { + } - /// - /// Creates a new instance of the - /// class using - /// the supplied - /// - /// The introduction to use. - /// - /// The interface to introduce. - /// - public DefaultIntroductionAdvisor(IAdvice introduction, Type intf) - : this(introduction, new Type[] {intf}) - { - } + /// + /// Creates a new instance of the + /// class using + /// the supplied + /// + /// The introduction to use. + /// + /// The interface to introduce. + /// + public DefaultIntroductionAdvisor(IAdvice introduction, Type intf) + : this(introduction, new Type[] { intf }) + { + } - /// - /// Creates a new instance of the - /// class using - /// the supplied - /// - /// The introduction to use. - /// - /// The interfaces to introduce. - /// - /// - /// If the supplied is . - /// - public DefaultIntroductionAdvisor(IAdvice introduction, Type[] interfaces) - { - if (introduction == null) - { - throw new ArgumentNullException("introduction", "Introduction cannot be null"); - } - _introduction = introduction; - foreach (Type intf in interfaces) - { - if (intf != typeof (IAdvice)) - { - AddInterface(intf); - } - } - } + /// + /// Creates a new instance of the + /// class using + /// the supplied + /// + /// The introduction to use. + /// + /// The interfaces to introduce. + /// + /// + /// If the supplied is . + /// + public DefaultIntroductionAdvisor(IAdvice introduction, Type[] interfaces) + { + if (introduction == null) + { + throw new ArgumentNullException("introduction", "Introduction cannot be null"); + } - /// - /// Returns the filter determining which target classes this - /// introduction should apply to. - /// - /// - /// The filter determining which target classes this introduction - /// should apply to. - /// - public virtual ITypeFilter TypeFilter - { - get { return this; } - } + _introduction = introduction; + foreach (Type intf in interfaces) + { + if (intf != typeof(IAdvice)) + { + AddInterface(intf); + } + } + } - /// - /// Gets the interfaces introduced by this - /// . - /// - /// - /// The interfaces introduced by this - /// . - /// - public virtual Type[] Interfaces - { - get - { - Type[] interfaces = new Type[_interfaces.Count]; - _interfaces.CopyTo(interfaces, 0); - return interfaces; - } - } + /// + /// Returns the filter determining which target classes this + /// introduction should apply to. + /// + /// + /// The filter determining which target classes this introduction + /// should apply to. + /// + public virtual ITypeFilter TypeFilter + { + get { return this; } + } - /// - /// Is this advice associated with a particular instance? - /// - /// - ///

- /// Default for an introduction is per-instance interception. - ///

- ///
- /// - /// if this advice is associated with a - /// particular instance. - /// - public virtual bool IsPerInstance - { - get { return true; } - } + /// + /// Gets the interfaces introduced by this + /// . + /// + /// + /// The interfaces introduced by this + /// . + /// + public virtual Type[] Interfaces + { + get + { + Type[] interfaces = new Type[_interfaces.Count]; + _interfaces.CopyTo(interfaces, 0); + return interfaces; + } + } - /// - /// Return the advice part of this aspect. - /// - /// - /// The advice that should apply if the pointcut matches. - /// - public virtual IAdvice Advice - { - get { return this._introduction; } - } + /// + /// Is this advice associated with a particular instance? + /// + /// + ///

+ /// Default for an introduction is per-instance interception. + ///

+ ///
+ /// + /// if this advice is associated with a + /// particular instance. + /// + public virtual bool IsPerInstance + { + get { return true; } + } - /// - /// Adds the supplied to the list of - /// introduced interfaces. - /// - /// The interface to add. - /// - /// If any of the are not interface . - /// - public virtual void AddInterface(Type intf) - { - if(intf != null) - { - BailIfNotAnInterfaceType(intf); - _interfaces.Add(intf); - } - } + /// + /// Return the advice part of this aspect. + /// + /// + /// The advice that should apply if the pointcut matches. + /// + public virtual IAdvice Advice + { + get { return this._introduction; } + } - /// - /// Should the pointcut apply to the supplied - /// ? - /// - /// - ///

- /// This, the default, implementation always returns . - ///

- ///
- /// - /// The candidate . - /// - /// - /// if the advice should apply to the supplied - /// - /// - public virtual bool Matches(Type type) - { - return true; - } + /// + /// Adds the supplied to the list of + /// introduced interfaces. + /// + /// The interface to add. + /// + /// If any of the are not interface . + /// + public virtual void AddInterface(Type intf) + { + if (intf != null) + { + BailIfNotAnInterfaceType(intf); + _interfaces.Add(intf); + } + } - /// - /// Can the advised interfaces be implemented by the introduction - /// advice? - /// - /// - ///

- /// Invoked before adding an - /// . - ///

- ///
- /// - /// If the advised interfaces cannot be implemented by the introduction - /// advice. - /// - /// - /// - /// If any of the are not interface . - /// - public virtual void ValidateInterfaces() - { - foreach (Type intf in _interfaces) - { - BailIfNotAnInterfaceType(intf); - if (! intf.IsAssignableFrom(_introduction.GetType())) - { - throw new ArgumentException("Introduction [" + _introduction.GetType().FullName + "] " + - "does not implement interface '" + intf.FullName + "' specified in introduction advice."); - } - } - } + /// + /// Should the pointcut apply to the supplied + /// ? + /// + /// + ///

+ /// This, the default, implementation always returns . + ///

+ ///
+ /// + /// The candidate . + /// + /// + /// if the advice should apply to the supplied + /// + /// + public virtual bool Matches(Type type) + { + return true; + } - private static void BailIfNotAnInterfaceType(Type intf) - { - if (intf != null && !intf.IsInterface) - { - throw new ArgumentException("Type [" + intf.FullName + "] is not an interface; cannot be used in an introduction."); - } - } + /// + /// Can the advised interfaces be implemented by the introduction + /// advice? + /// + /// + ///

+ /// Invoked before adding an + /// . + ///

+ ///
+ /// + /// If the advised interfaces cannot be implemented by the introduction + /// advice. + /// + /// + /// + /// If any of the are not interface . + /// + public virtual void ValidateInterfaces() + { + foreach (Type intf in _interfaces) + { + BailIfNotAnInterfaceType(intf); + if (!intf.IsAssignableFrom(_introduction.GetType())) + { + throw new ArgumentException("Introduction [" + _introduction.GetType().FullName + "] " + + "does not implement interface '" + intf.FullName + "' specified in introduction advice."); + } + } + } - /// - /// 2 IntroductionAdvisors are considered equal if - /// a) they are of the same type - /// b) their introduction advices are equal - /// c) they introduce the same interfaces - /// - public bool Equals(DefaultIntroductionAdvisor other) - { - if (ReferenceEquals(null, other)) return false; - if (ReferenceEquals(this, other)) return true; - if (other.GetType() != this.GetType()) - return false; - return Equals(other._introduction, _introduction) && Equals(other._interfaces, _interfaces); - } + private static void BailIfNotAnInterfaceType(Type intf) + { + if (intf != null && !intf.IsInterface) + { + throw new ArgumentException("Type [" + intf.FullName + "] is not an interface; cannot be used in an introduction."); + } + } - /// - /// 2 IntroductionAdvisors are considered equal if - /// a) they are of the same type - /// b) their introduction advices are equal - /// c) they introduce the same interfaces - /// - public override bool Equals(object obj) - { - return Equals(obj as DefaultIntroductionAdvisor); - } + /// + /// 2 IntroductionAdvisors are considered equal if + /// a) they are of the same type + /// b) their introduction advices are equal + /// c) they introduce the same interfaces + /// + public bool Equals(DefaultIntroductionAdvisor other) + { + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + if (other.GetType() != this.GetType()) + return false; + return Equals(other._introduction, _introduction) && Equals(other._interfaces, _interfaces); + } - /// - /// 2 IntroductionAdvisors are considered equal if - /// a) they are of the same type - /// b) their introduction advices are equal - /// c) they introduce the same interfaces - /// - public override int GetHashCode() - { - unchecked - { - return ((_introduction != null ? _introduction.GetHashCode() : 0)*397) ^ (_interfaces != null ? _interfaces.GetHashCode() : 0); - } - } - } + /// + /// 2 IntroductionAdvisors are considered equal if + /// a) they are of the same type + /// b) their introduction advices are equal + /// c) they introduce the same interfaces + /// + public override bool Equals(object obj) + { + return Equals(obj as DefaultIntroductionAdvisor); + } + + /// + /// 2 IntroductionAdvisors are considered equal if + /// a) they are of the same type + /// b) their introduction advices are equal + /// c) they introduce the same interfaces + /// + public override int GetHashCode() + { + unchecked + { + return ((_introduction != null ? _introduction.GetHashCode() : 0) * 397) ^ (_interfaces != null ? _interfaces.GetHashCode() : 0); + } + } } diff --git a/src/Spring/Spring.Aop/Aop/Support/DefaultObjectFactoryPointcutAdvisor.cs b/src/Spring/Spring.Aop/Aop/Support/DefaultObjectFactoryPointcutAdvisor.cs index 5979da0f..92af6bbb 100644 --- a/src/Spring/Spring.Aop/Aop/Support/DefaultObjectFactoryPointcutAdvisor.cs +++ b/src/Spring/Spring.Aop/Aop/Support/DefaultObjectFactoryPointcutAdvisor.cs @@ -18,42 +18,40 @@ #endregion -namespace Spring.Aop.Support +namespace Spring.Aop.Support; + +/// +/// Concrete ObjectFactory-based IPointcutAdvisor thta allows for any Advice to be +/// configured as reference to an Advice object in the ObjectFatory, as well as +/// the Pointcut to be configured through an object property. +/// +/// +/// Specifying the name of an advice object instead of the advice object itself +/// (if running within a ObjectFactory/ApplicationContext) increases loose coupling +/// at initialization time, in order to not intialize the advice object until the pointcut +/// actually matches. +/// +/// Juerge Hoeller +/// Mark Pollack +public class DefaultObjectFactoryPointcutAdvisor : AbstractObjectFactoryPointcutAdvisor { + private IPointcut pointcut = TruePointcut.True; + /// - /// Concrete ObjectFactory-based IPointcutAdvisor thta allows for any Advice to be - /// configured as reference to an Advice object in the ObjectFatory, as well as - /// the Pointcut to be configured through an object property. + /// The that drives this advisor. /// - /// - /// Specifying the name of an advice object instead of the advice object itself - /// (if running within a ObjectFactory/ApplicationContext) increases loose coupling - /// at initialization time, in order to not intialize the advice object until the pointcut - /// actually matches. - /// - /// Juerge Hoeller - /// Mark Pollack - public class DefaultObjectFactoryPointcutAdvisor : AbstractObjectFactoryPointcutAdvisor + public override IPointcut Pointcut { - private IPointcut pointcut = TruePointcut.True; - - - /// - /// The that drives this advisor. - /// - public override IPointcut Pointcut - { - get { return pointcut; } - set { pointcut = (pointcut != null ? value : TruePointcut.True); } - } - - /// - /// Describe this Advisor, showing pointcut and name of advice object. - /// - /// Type name , pointcut, and advice object name. - public override string ToString() - { - return GetType().Name + ": pointcut [" + Pointcut + "]; advice object = '" + AdviceObjectName + "'"; - } + get { return pointcut; } + set { pointcut = (pointcut != null ? value : TruePointcut.True); } } -} \ No newline at end of file + + /// + /// Describe this Advisor, showing pointcut and name of advice object. + /// + /// Type name , pointcut, and advice object name. + public override string ToString() + { + return GetType().Name + ": pointcut [" + Pointcut + "]; advice object = '" + AdviceObjectName + "'"; + } +} diff --git a/src/Spring/Spring.Aop/Aop/Support/DefaultPointcutAdvisor.cs b/src/Spring/Spring.Aop/Aop/Support/DefaultPointcutAdvisor.cs index 5ab0f752..90b77924 100644 --- a/src/Spring/Spring.Aop/Aop/Support/DefaultPointcutAdvisor.cs +++ b/src/Spring/Spring.Aop/Aop/Support/DefaultPointcutAdvisor.cs @@ -24,101 +24,99 @@ using AopAlliance.Aop; #endregion -namespace Spring.Aop.Support +namespace Spring.Aop.Support; + +/// +/// Convenient pointcut-driven advisor implementation. +/// +/// +///

+/// This is the most commonly used implementation. +/// It can be used with any pointcut and advice type, except for introductions. +///

+///
+/// Rod Johnson +/// Aleksandar Seovic (.NET) +[Serializable] +public class DefaultPointcutAdvisor : AbstractGenericPointcutAdvisor { - /// - /// Convenient pointcut-driven advisor implementation. - /// - /// - ///

- /// This is the most commonly used implementation. - /// It can be used with any pointcut and advice type, except for introductions. - ///

- ///
- /// Rod Johnson - /// Aleksandar Seovic (.NET) - [Serializable] - public class DefaultPointcutAdvisor : AbstractGenericPointcutAdvisor - { - private IPointcut pointcut = TruePointcut.True; + private IPointcut pointcut = TruePointcut.True; - /// - /// Creates a new instance of the - /// class. - /// - public DefaultPointcutAdvisor() - { - } + /// + /// Creates a new instance of the + /// class. + /// + public DefaultPointcutAdvisor() + { + } - /// - /// Creates a new instance of the - /// - /// class for the supplied , - /// - /// - /// The advice to use. - /// - public DefaultPointcutAdvisor(IAdvice advice) - : this(TruePointcut.True, advice) - { - } + /// + /// Creates a new instance of the + /// + /// class for the supplied , + /// + /// + /// The advice to use. + /// + public DefaultPointcutAdvisor(IAdvice advice) + : this(TruePointcut.True, advice) + { + } - /// - /// Creates a new instance of the - /// - /// class for the supplied and - /// . - /// - /// - /// The advice to use. - /// - /// - /// The pointcut to use. - /// - public DefaultPointcutAdvisor(IPointcut pointcut, IAdvice advice) - { - this.pointcut = pointcut; - Advice = advice; - } + /// + /// Creates a new instance of the + /// + /// class for the supplied and + /// . + /// + /// + /// The advice to use. + /// + /// + /// The pointcut to use. + /// + public DefaultPointcutAdvisor(IPointcut pointcut, IAdvice advice) + { + this.pointcut = pointcut; + Advice = advice; + } - /// - /// The that drives this advisor. - /// - public override IPointcut Pointcut - { - get { return pointcut; } - set { pointcut = value;} - } + /// + /// The that drives this advisor. + /// + public override IPointcut Pointcut + { + get { return pointcut; } + set { pointcut = value; } + } + /// + /// 2 s are considered equal, if + /// a) their pointcuts are equal + /// b) their advices are equal + /// + public override bool Equals(object obj) + { + return base.Equals(obj as DefaultPointcutAdvisor); + } - /// - /// 2 s are considered equal, if - /// a) their pointcuts are equal - /// b) their advices are equal - /// - public override bool Equals(object obj) - { - return base.Equals(obj as DefaultPointcutAdvisor); - } + /// + /// Calculates a unique hashcode based on advice + pointcut + /// + public override int GetHashCode() + { + return base.GetHashCode(); + } - /// - /// Calculates a unique hashcode based on advice + pointcut - /// - public override int GetHashCode() - { - return base.GetHashCode(); - } - - /// - /// Returns a that represents the current - /// . - /// - /// - /// A representation of this advisor. - /// - public override string ToString() - { - return GetType().Name + ": pointcut=[" + pointcut + "] advice=[" + Advice + "]"; - } - } + /// + /// Returns a that represents the current + /// . + /// + /// + /// A representation of this advisor. + /// + public override string ToString() + { + return GetType().Name + ": pointcut=[" + pointcut + "] advice=[" + Advice + "]"; + } } diff --git a/src/Spring/Spring.Aop/Aop/Support/DynamicMethodMatcher.cs b/src/Spring/Spring.Aop/Aop/Support/DynamicMethodMatcher.cs index 4ff9ab31..3127c2b2 100644 --- a/src/Spring/Spring.Aop/Aop/Support/DynamicMethodMatcher.cs +++ b/src/Spring/Spring.Aop/Aop/Support/DynamicMethodMatcher.cs @@ -24,90 +24,89 @@ using System.Reflection; #endregion -namespace Spring.Aop.Support +namespace Spring.Aop.Support; + +/// +/// Convenient abstract superclass for dynamic method matchers that do +/// care about arguments at runtime. +/// +/// Rod Johnson +/// Aleksandar Seovic (.NET) +[Serializable] +public abstract class DynamicMethodMatcher : IMethodMatcher { - /// - /// Convenient abstract superclass for dynamic method matchers that do - /// care about arguments at runtime. - /// - /// Rod Johnson - /// Aleksandar Seovic (.NET) - [Serializable] - public abstract class DynamicMethodMatcher : IMethodMatcher - { - #region Constructor (s) / Destructor + #region Constructor (s) / Destructor - /// - /// Creates a new instance of the - /// - /// class. - /// - /// - ///

- /// This is an class, and as such exposes no - /// public constructors. - ///

- ///
- protected DynamicMethodMatcher() - { - } + /// + /// Creates a new instance of the + /// + /// class. + /// + /// + ///

+ /// This is an class, and as such exposes no + /// public constructors. + ///

+ ///
+ protected DynamicMethodMatcher() + { + } - #endregion + #endregion - /// - /// Is this dynamic? - /// - /// - /// Always returns , to specify that this is a - /// dynamic matcher. - /// - public virtual bool IsRuntime - { - get { return true; } - } + /// + /// Is this dynamic? + /// + /// + /// Always returns , to specify that this is a + /// dynamic matcher. + /// + public virtual bool IsRuntime + { + get { return true; } + } - /// - /// Does the supplied satisfy this matcher? - /// - /// - ///

- /// Derived classes can override this method to add preconditions for - /// dynamic matching. - ///

- ///

- /// This implementation always returns . - ///

- ///
- /// 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 virtual bool Matches(MethodInfo method, Type targetType) - { - return true; - } + /// + /// Does the supplied satisfy this matcher? + /// + /// + ///

+ /// Derived classes can override this method to add preconditions for + /// dynamic matching. + ///

+ ///

+ /// This implementation always returns . + ///

+ ///
+ /// 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 virtual bool Matches(MethodInfo method, Type targetType) + { + return true; + } - /// - /// Is there a runtime (dynamic) match for the supplied - /// ? - /// - /// - ///

- /// Must be overriden by derived classes to provide criteria for dynamic matching. - ///

- ///
- /// The candidate method. - /// - /// The target . - /// - /// The arguments to the method - /// - /// if there is a runtime match. - public abstract bool Matches(MethodInfo method, Type targetType, object[] args); - } + /// + /// Is there a runtime (dynamic) match for the supplied + /// ? + /// + /// + ///

+ /// Must be overriden by derived classes to provide criteria for dynamic matching. + ///

+ ///
+ /// The candidate method. + /// + /// The target . + /// + /// The arguments to the method + /// + /// if there is a runtime match. + public abstract bool Matches(MethodInfo method, Type targetType, object[] args); } diff --git a/src/Spring/Spring.Aop/Aop/Support/DynamicMethodMatcherPointcutAdvisor.cs b/src/Spring/Spring.Aop/Aop/Support/DynamicMethodMatcherPointcutAdvisor.cs index e30a73f9..6b966170 100644 --- a/src/Spring/Spring.Aop/Aop/Support/DynamicMethodMatcherPointcutAdvisor.cs +++ b/src/Spring/Spring.Aop/Aop/Support/DynamicMethodMatcherPointcutAdvisor.cs @@ -25,150 +25,149 @@ using Spring.Core; #endregion -namespace Spring.Aop.Support +namespace Spring.Aop.Support; + +/// +/// Convenient superclass for s +/// that are also dynamic pointcuts. +/// +/// Rod Johnson +/// Aleksandar Seovic (.NET) +[Serializable] +public abstract class DynamicMethodMatcherPointcutAdvisor + : DynamicMethodMatcher, IPointcutAdvisor, IPointcut, IOrdered { - /// - /// Convenient superclass for s - /// that are also dynamic pointcuts. - /// - /// Rod Johnson - /// Aleksandar Seovic (.NET) - [Serializable] - public abstract class DynamicMethodMatcherPointcutAdvisor - : DynamicMethodMatcher, IPointcutAdvisor, IPointcut, IOrdered - { - private int _order = Int32.MaxValue; - private IAdvice _advice; + private int _order = Int32.MaxValue; + private IAdvice _advice; - /// - /// Creates a new instance of the - /// - /// class. - /// - /// - ///

- /// This is an abstract class, and as such has no publicly - /// visible constructors. - ///

- ///
- protected DynamicMethodMatcherPointcutAdvisor() - { - } + /// + /// Creates a new instance of the + /// + /// class. + /// + /// + ///

+ /// This is an abstract class, and as such has no publicly + /// visible constructors. + ///

+ ///
+ protected DynamicMethodMatcherPointcutAdvisor() + { + } - /// - /// Creates a new instance of the - /// - /// class for the supplied . - /// - /// - ///

- /// This is an abstract class, and as such has no publicly - /// visible constructors. - ///

- ///
- /// - /// The advice portion of this advisor. - /// - protected DynamicMethodMatcherPointcutAdvisor(IAdvice advice) - { - this._advice = advice; - } + /// + /// Creates a new instance of the + /// + /// class for the supplied . + /// + /// + ///

+ /// This is an abstract class, and as such has no publicly + /// visible constructors. + ///

+ ///
+ /// + /// The advice portion of this advisor. + /// + protected DynamicMethodMatcherPointcutAdvisor(IAdvice advice) + { + this._advice = advice; + } - /// - /// Is this advice associated with a particular instance? - /// - /// - ///

- /// Not supported for dynamic advisors. - ///

- ///
- /// - /// if this advice is associated with a - /// particular instance. - /// - /// Always. - /// - public virtual bool IsPerInstance - { - get - { - throw new NotSupportedException( - "The 'IsPerInstance' property of the IAdvisor interface " + - "is not yet supported in Spring.NET."); - } - } + /// + /// Is this advice associated with a particular instance? + /// + /// + ///

+ /// Not supported for dynamic advisors. + ///

+ ///
+ /// + /// if this advice is associated with a + /// particular instance. + /// + /// Always. + /// + public virtual bool IsPerInstance + { + get + { + throw new NotSupportedException( + "The 'IsPerInstance' property of the IAdvisor interface " + + "is not yet supported in Spring.NET."); + } + } - /// - /// The for this pointcut. - /// - /// - ///

- /// This implementation always returns a filter that evaluates to - /// for any . - ///

- ///
- /// - /// The current . - /// - public virtual ITypeFilter TypeFilter - { - get { return TrueTypeFilter.True; } - } + /// + /// The for this pointcut. + /// + /// + ///

+ /// This implementation always returns a filter that evaluates to + /// for any . + ///

+ ///
+ /// + /// The current . + /// + public virtual ITypeFilter TypeFilter + { + get { return TrueTypeFilter.True; } + } - /// - /// The for this pointcut. - /// - /// - ///

- /// This implementation always returns itself (this object). - ///

- ///
- /// - /// The current . - /// - public virtual IMethodMatcher MethodMatcher - { - get { return this; } - } + /// + /// The for this pointcut. + /// + /// + ///

+ /// This implementation always returns itself (this object). + ///

+ ///
+ /// + /// The current . + /// + public virtual IMethodMatcher MethodMatcher + { + get { return this; } + } - /// - /// Returns this s order in the - /// interception chain. - /// - /// - /// This s order in the - /// interception chain. - /// - public virtual int Order - { - get { return this._order; } - set { this._order = value; } - } + /// + /// Returns this s order in the + /// interception chain. + /// + /// + /// This s order in the + /// interception chain. + /// + public virtual int Order + { + get { return this._order; } + set { this._order = value; } + } - /// - /// Return the advice part of this aspect. - /// - /// - /// The advice that should apply if the pointcut matches. - /// - /// - public virtual IAdvice Advice - { - get { return this._advice; } - set { this._advice = value; } - } + /// + /// Return the advice part of this aspect. + /// + /// + /// The advice that should apply if the pointcut matches. + /// + /// + public virtual IAdvice Advice + { + get { return this._advice; } + set { this._advice = value; } + } - /// - /// The that drives this advisor. - /// - /// - ///

- /// This implementation always returns itself (this object). - ///

- ///
- public IPointcut Pointcut - { - get { return this; } - } - } + /// + /// The that drives this advisor. + /// + /// + ///

+ /// This implementation always returns itself (this object). + ///

+ ///
+ public IPointcut Pointcut + { + get { return this; } + } } diff --git a/src/Spring/Spring.Aop/Aop/Support/MethodMatchers.cs b/src/Spring/Spring.Aop/Aop/Support/MethodMatchers.cs index 51ebbae1..f6565f54 100644 --- a/src/Spring/Spring.Aop/Aop/Support/MethodMatchers.cs +++ b/src/Spring/Spring.Aop/Aop/Support/MethodMatchers.cs @@ -24,156 +24,155 @@ using System.Reflection; #endregion -namespace Spring.Aop.Support +namespace Spring.Aop.Support; + +/// +/// Various utility methods relating to the composition of +/// s. +/// +/// +///

+/// A method matcher may be evaluated statically (based on method and target +/// class) or need further evaluation dynamically (based on arguments at +/// the time of method invocation). +///

+///
+/// Rod Johnson +/// Aleksandar Seovic (.NET) +public sealed class MethodMatchers { - /// - /// Various utility methods relating to the composition of - /// s. - /// - /// - ///

- /// A method matcher may be evaluated statically (based on method and target - /// class) or need further evaluation dynamically (based on arguments at - /// the time of method invocation). - ///

- ///
- /// Rod Johnson - /// Aleksandar Seovic (.NET) - public sealed class MethodMatchers - { - /// - /// Creates a new that is the - /// union of the two supplied s. - /// - /// - ///

- /// The newly created matcher will match all the methods that either of the two - /// supplied matchers would match. - ///

- ///
- /// The first method matcher. - /// The second method matcher. - /// - /// A new that is the - /// union of the two supplied s - /// - public static IMethodMatcher Union( - IMethodMatcher firstMatcher, IMethodMatcher secondMatcher) - { - return new UnionMethodMatcher(firstMatcher, secondMatcher); - } + /// + /// Creates a new that is the + /// union of the two supplied s. + /// + /// + ///

+ /// The newly created matcher will match all the methods that either of the two + /// supplied matchers would match. + ///

+ ///
+ /// The first method matcher. + /// The second method matcher. + /// + /// A new that is the + /// union of the two supplied s + /// + public static IMethodMatcher Union( + IMethodMatcher firstMatcher, IMethodMatcher secondMatcher) + { + return new UnionMethodMatcher(firstMatcher, secondMatcher); + } - /// - /// Creates a new that is the - /// intersection of the two supplied s. - /// - /// - ///

- /// The newly created matcher will match only those methods that both - /// of the supplied matchers would match. - ///

- ///
- /// The first method matcher. - /// The second method matcher. - /// - /// A new that is the - /// intersection of the two supplied s - /// - public static IMethodMatcher Intersection( - IMethodMatcher firstMatcher, IMethodMatcher secondMatcher) - { - return new IntersectionMethodMatcher(firstMatcher, secondMatcher); - } + /// + /// Creates a new that is the + /// intersection of the two supplied s. + /// + /// + ///

+ /// The newly created matcher will match only those methods that both + /// of the supplied matchers would match. + ///

+ ///
+ /// The first method matcher. + /// The second method matcher. + /// + /// A new that is the + /// intersection of the two supplied s + /// + public static IMethodMatcher Intersection( + IMethodMatcher firstMatcher, IMethodMatcher secondMatcher) + { + return new IntersectionMethodMatcher(firstMatcher, secondMatcher); + } - #region Inner Class : UnionMethodMatcher + #region Inner Class : UnionMethodMatcher - [Serializable] - private sealed class UnionMethodMatcher : IMethodMatcher - { - private IMethodMatcher a; - private IMethodMatcher b; + [Serializable] + private sealed class UnionMethodMatcher : IMethodMatcher + { + private IMethodMatcher a; + private IMethodMatcher b; - public UnionMethodMatcher(IMethodMatcher a, IMethodMatcher b) - { - this.a = a; - this.b = b; - } + public UnionMethodMatcher(IMethodMatcher a, IMethodMatcher b) + { + this.a = a; + this.b = b; + } - public bool IsRuntime - { - get { return a.IsRuntime || b.IsRuntime; } - } + public bool IsRuntime + { + get { return a.IsRuntime || b.IsRuntime; } + } - public bool Matches(MethodInfo m, Type targetType) - { - return a.Matches(m, targetType) || b.Matches(m, targetType); - } + public bool Matches(MethodInfo m, Type targetType) + { + return a.Matches(m, targetType) || b.Matches(m, targetType); + } - public bool Matches(MethodInfo m, Type targetType, object[] args) - { - return a.Matches(m, targetType, args) || b.Matches(m, targetType, args); - } - } + public bool Matches(MethodInfo m, Type targetType, object[] args) + { + return a.Matches(m, targetType, args) || b.Matches(m, targetType, args); + } + } - #endregion + #endregion - #region Inner Class : IntersectionMethodMatcher + #region Inner Class : IntersectionMethodMatcher - [Serializable] - private sealed class IntersectionMethodMatcher : IMethodMatcher - { - private IMethodMatcher a; - private IMethodMatcher b; + [Serializable] + private sealed class IntersectionMethodMatcher : IMethodMatcher + { + private IMethodMatcher a; + private IMethodMatcher b; - public IntersectionMethodMatcher(IMethodMatcher a, IMethodMatcher b) - { - this.a = a; - this.b = b; - } + public IntersectionMethodMatcher(IMethodMatcher a, IMethodMatcher b) + { + this.a = a; + this.b = b; + } - public bool IsRuntime - { - get { return a.IsRuntime || b.IsRuntime; } - } + public bool IsRuntime + { + get { return a.IsRuntime || b.IsRuntime; } + } - public bool Matches(MethodInfo m, Type targetType) - { - return a.Matches(m, targetType) && b.Matches(m, targetType); - } + public bool Matches(MethodInfo m, Type targetType) + { + return a.Matches(m, targetType) && b.Matches(m, targetType); + } - public bool Matches(MethodInfo m, Type targetType, object[] args) - { - // Because a dynamic intersection may be composed of a static and dynamic part, - // we must avoid calling the 3-arg matches method on a dynamic matcher, as - // it will probably be an unsupported operation. - bool aMatches = a.IsRuntime ? a.Matches(m, targetType, args) : a.Matches(m, targetType); - bool bMatches = b.IsRuntime ? b.Matches(m, targetType, args) : b.Matches(m, targetType); - return aMatches && bMatches; - } - } + public bool Matches(MethodInfo m, Type targetType, object[] args) + { + // Because a dynamic intersection may be composed of a static and dynamic part, + // we must avoid calling the 3-arg matches method on a dynamic matcher, as + // it will probably be an unsupported operation. + bool aMatches = a.IsRuntime ? a.Matches(m, targetType, args) : a.Matches(m, targetType); + bool bMatches = b.IsRuntime ? b.Matches(m, targetType, args) : b.Matches(m, targetType); + return aMatches && bMatches; + } + } - #endregion + #endregion - #region Constructor (s) / Destructor + #region Constructor (s) / Destructor - // CLOVER:OFF + // CLOVER:OFF - /// - /// Creates a new instance of the - /// class. - /// - /// - ///

- /// This is a utility class, and as such has no publicly - /// visible constructors. - ///

- ///
- private MethodMatchers() - { - } + /// + /// Creates a new instance of the + /// class. + /// + /// + ///

+ /// This is a utility class, and as such has no publicly + /// visible constructors. + ///

+ ///
+ private MethodMatchers() + { + } - // CLOVER:ON + // CLOVER:ON - #endregion - } + #endregion } diff --git a/src/Spring/Spring.Aop/Aop/Support/NameMatchMethodPointcut.cs b/src/Spring/Spring.Aop/Aop/Support/NameMatchMethodPointcut.cs index cadcfd2c..8d389074 100644 --- a/src/Spring/Spring.Aop/Aop/Support/NameMatchMethodPointcut.cs +++ b/src/Spring/Spring.Aop/Aop/Support/NameMatchMethodPointcut.cs @@ -25,96 +25,96 @@ using Spring.Util; #endregion -namespace Spring.Aop.Support +namespace Spring.Aop.Support; + +/// +/// Pointcut object for simple method name matches, useful as an alternative to pure +/// regular expression based patterns. +/// +/// Juergen Hoeller +/// Aleksandar Seovic (.NET) +[Serializable] +public class NameMatchMethodPointcut : StaticMethodMatcherPointcut { - /// - /// Pointcut object for simple method name matches, useful as an alternative to pure - /// regular expression based patterns. - /// - /// Juergen Hoeller - /// Aleksandar Seovic (.NET) - [Serializable] - public class NameMatchMethodPointcut : StaticMethodMatcherPointcut - { - private string[] _mappedNames = new string[0]; + private string[] _mappedNames = new string[0]; - /// - /// Convenience property when we have only a single method name - /// to match. - /// - /// - /// - /// Use either this property or the - /// property, - /// not both. - /// - /// - public virtual string MappedName - { - set { MappedNames = new string[] {value}; } - } + /// + /// Convenience property when we have only a single method name + /// to match. + /// + /// + /// + /// Use either this property or the + /// property, + /// not both. + /// + /// + public virtual string MappedName + { + set { MappedNames = new string[] { value }; } + } - /// - /// Set the method names defining methods to match. - /// - /// - ///

- /// Matching will be the union of all these; if any match, the pointcut matches. - ///

- ///
- public virtual string[] MappedNames - { - set { this._mappedNames = value; } - } + /// + /// Set the method names defining methods to match. + /// + /// + ///

+ /// Matching will be the union of all these; if any match, the pointcut matches. + ///

+ ///
+ public virtual string[] MappedNames + { + set { this._mappedNames = value; } + } - /// - /// Does the of the supplied - /// matches any of the mapped names? - /// - /// - /// The to check. - /// - /// - /// The of the target class. - /// - /// - /// if the name of the supplied - /// matches one of the mapped names. - /// - public override bool Matches(MethodInfo method, Type targetType) - { - for (int i = 0; i < this._mappedNames.Length; i++) - { - string mappedName = this._mappedNames[i]; - if (mappedName.Equals(method.Name) || IsMatch(method.Name, mappedName)) - { - return true; - } - } - return false; - } + /// + /// Does the of the supplied + /// matches any of the mapped names? + /// + /// + /// The to check. + /// + /// + /// The of the target class. + /// + /// + /// if the name of the supplied + /// matches one of the mapped names. + /// + public override bool Matches(MethodInfo method, Type targetType) + { + for (int i = 0; i < this._mappedNames.Length; i++) + { + string mappedName = this._mappedNames[i]; + if (mappedName.Equals(method.Name) || IsMatch(method.Name, mappedName)) + { + return true; + } + } - /// - /// Does the supplied match the supplied ? - /// - /// - ///

- /// The default implementation checks for "xxx*", "*xxx" and "*xxx*" matches, - /// as well as direct equality. Can be overridden in subclasses. - ///

- ///
- /// - /// The method name of the class. - /// - /// - /// The name in the descriptor. - /// - /// - /// True if the names match. - /// - protected virtual bool IsMatch(string methodName, string mappedName) - { - return PatternMatchUtils.SimpleMatch(mappedName, methodName); - } - } + return false; + } + + /// + /// Does the supplied match the supplied ? + /// + /// + ///

+ /// The default implementation checks for "xxx*", "*xxx" and "*xxx*" matches, + /// as well as direct equality. Can be overridden in subclasses. + ///

+ ///
+ /// + /// The method name of the class. + /// + /// + /// The name in the descriptor. + /// + /// + /// True if the names match. + /// + protected virtual bool IsMatch(string methodName, string mappedName) + { + return PatternMatchUtils.SimpleMatch(mappedName, methodName); + } } diff --git a/src/Spring/Spring.Aop/Aop/Support/NameMatchMethodPointcutAdvisor.cs b/src/Spring/Spring.Aop/Aop/Support/NameMatchMethodPointcutAdvisor.cs index 0d021a1b..0e5c2263 100644 --- a/src/Spring/Spring.Aop/Aop/Support/NameMatchMethodPointcutAdvisor.cs +++ b/src/Spring/Spring.Aop/Aop/Support/NameMatchMethodPointcutAdvisor.cs @@ -21,108 +21,106 @@ #region Imports using AopAlliance.Aop; - using Spring.Util; #endregion -namespace Spring.Aop.Support +namespace Spring.Aop.Support; + +/// +/// Convenient class for name-match method pointcuts that hold an Interceptor, +/// making them an Advisor. +/// +/// Juergen Hoeller +/// Aleksandar Seovic (.NET) +/// Mark Pollack (.NET) +[Serializable] +public class NameMatchMethodPointcutAdvisor : AbstractGenericPointcutAdvisor { - /// - /// Convenient class for name-match method pointcuts that hold an Interceptor, - /// making them an Advisor. - /// - /// Juergen Hoeller - /// Aleksandar Seovic (.NET) - /// Mark Pollack (.NET) - [Serializable] - public class NameMatchMethodPointcutAdvisor : AbstractGenericPointcutAdvisor - { + private NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut(); - private NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut(); + #region Constructor(s) - #region Constructor(s) - - /// - /// Creates a new instance of the - /// class. - /// - public NameMatchMethodPointcutAdvisor() - { - } - - /// - /// Creates a new instance of the - /// class - /// for the supplied . - /// - /// - public NameMatchMethodPointcutAdvisor(IAdvice advice) - { - Advice = advice; - } - - #endregion - - - #region Properties - /// - /// The for this pointcut. - /// - /// Default is - /// - /// The current . - /// - public ITypeFilter TypeFilter { - set - { - pointcut.TypeFilter = value; - } - } - - /// - /// Convenience property when we have only a single method name - /// to match. - /// - /// - /// - /// Use either this property or the - /// property, - /// not both. - /// - /// - public string MappedName - { - set { pointcut.MappedName = value; } - } - - /// - /// Set the method names defining methods to match. - /// - /// - ///

- /// Matching will be the union of all these; if any match, the pointcut matches. - ///

- ///
- public string[] MappedNames - { - set { pointcut.MappedNames = value; } - } - - /// - /// The that drives this advisor. - /// - public override IPointcut Pointcut - { - get { return pointcut; } - set - { - AssertUtils.AssertArgumentType(value, "pointcut", typeof(NameMatchMethodPointcut), - "Pointcut most be compatible with type NameMatchMethodPointcut"); - pointcut = value as NameMatchMethodPointcut; - } - } - - #endregion + /// + /// Creates a new instance of the + /// class. + /// + public NameMatchMethodPointcutAdvisor() + { } + + /// + /// Creates a new instance of the + /// class + /// for the supplied . + /// + /// + public NameMatchMethodPointcutAdvisor(IAdvice advice) + { + Advice = advice; + } + + #endregion + + #region Properties + + /// + /// The for this pointcut. + /// + /// Default is + /// + /// The current . + /// + public ITypeFilter TypeFilter + { + set + { + pointcut.TypeFilter = value; + } + } + + /// + /// Convenience property when we have only a single method name + /// to match. + /// + /// + /// + /// Use either this property or the + /// property, + /// not both. + /// + /// + public string MappedName + { + set { pointcut.MappedName = value; } + } + + /// + /// Set the method names defining methods to match. + /// + /// + ///

+ /// Matching will be the union of all these; if any match, the pointcut matches. + ///

+ ///
+ public string[] MappedNames + { + set { pointcut.MappedNames = value; } + } + + /// + /// The that drives this advisor. + /// + public override IPointcut Pointcut + { + get { return pointcut; } + set + { + AssertUtils.AssertArgumentType(value, "pointcut", typeof(NameMatchMethodPointcut), + "Pointcut most be compatible with type NameMatchMethodPointcut"); + pointcut = value as NameMatchMethodPointcut; + } + } + + #endregion } diff --git a/src/Spring/Spring.Aop/Aop/Support/Pointcuts.cs b/src/Spring/Spring.Aop/Aop/Support/Pointcuts.cs index 03f947e1..28b22b05 100644 --- a/src/Spring/Spring.Aop/Aop/Support/Pointcuts.cs +++ b/src/Spring/Spring.Aop/Aop/Support/Pointcuts.cs @@ -24,121 +24,122 @@ using System.Reflection; #endregion -namespace Spring.Aop.Support +namespace Spring.Aop.Support; + +/// +/// Various related utility methods. +/// +/// +///

+/// These methods are particularly useful for composing pointcuts +/// using the union and intersection methods. +///

+///
+/// Rod Johnson +/// Aleksandar Seovic (.NET) +public sealed class Pointcuts { - /// - /// Various related utility methods. - /// - /// - ///

- /// These methods are particularly useful for composing pointcuts - /// using the union and intersection methods. - ///

- ///
- /// Rod Johnson - /// Aleksandar Seovic (.NET) - public sealed class Pointcuts - { - /// - /// Creates a union of the two supplied pointcuts. - /// - /// The first pointcut. - /// The second pointcut. - /// - /// The union of the two supplied pointcuts. - /// - /// - public static IPointcut Union(IPointcut firstPointcut, IPointcut secondPointcut) - { - return new UnionPointcut(firstPointcut, secondPointcut); - } + /// + /// Creates a union of the two supplied pointcuts. + /// + /// The first pointcut. + /// The second pointcut. + /// + /// The union of the two supplied pointcuts. + /// + /// + public static IPointcut Union(IPointcut firstPointcut, IPointcut secondPointcut) + { + return new UnionPointcut(firstPointcut, secondPointcut); + } - /// - /// Creates an that is the - /// intersection of the two supplied pointcuts. - /// - /// The first pointcut. - /// The second pointcut. - /// - /// An that is the - /// intersection of the two supplied pointcuts. - /// - public static IPointcut Intersection(IPointcut firstPointcut, IPointcut secondPointcut) - { - return new ComposablePointcut( - firstPointcut.TypeFilter, firstPointcut.MethodMatcher) - .Intersection(secondPointcut); - } + /// + /// Creates an that is the + /// intersection of the two supplied pointcuts. + /// + /// The first pointcut. + /// The second pointcut. + /// + /// An that is the + /// intersection of the two supplied pointcuts. + /// + public static IPointcut Intersection(IPointcut firstPointcut, IPointcut secondPointcut) + { + return new ComposablePointcut( + firstPointcut.TypeFilter, firstPointcut.MethodMatcher) + .Intersection(secondPointcut); + } - /// - /// Performs the least expensive check for a match. - /// - /// - /// The to be evaluated. - /// - /// The candidate method. - /// - /// The target . - /// - /// The arguments to the method - /// if there is a runtime match. - /// - public static bool Matches( - IPointcut pointcut, MethodInfo method, Type targetType, object[] args) - { - if(pointcut != null) - { - if (pointcut == TruePointcut.True) - { - return true; - } - if (pointcut.TypeFilter.Matches(targetType)) - { - IMethodMatcher mm = pointcut.MethodMatcher; - if (mm.Matches(method, targetType)) - { - return mm.IsRuntime ? mm.Matches(method, targetType, args) : true; - } - } - } - return false; - } + /// + /// Performs the least expensive check for a match. + /// + /// + /// The to be evaluated. + /// + /// The candidate method. + /// + /// The target . + /// + /// The arguments to the method + /// if there is a runtime match. + /// + public static bool Matches( + IPointcut pointcut, MethodInfo method, Type targetType, object[] args) + { + if (pointcut != null) + { + if (pointcut == TruePointcut.True) + { + return true; + } - /// - /// Are the supplied s equal? - /// - /// The first pointcut. - /// The second pointcut. - /// - /// if the supplied s - /// are equal. - /// - public static bool AreEqual(IPointcut firstPointcut, IPointcut secondPointcut) - { - return firstPointcut.TypeFilter == secondPointcut.TypeFilter - && firstPointcut.MethodMatcher == secondPointcut.MethodMatcher; - } + if (pointcut.TypeFilter.Matches(targetType)) + { + IMethodMatcher mm = pointcut.MethodMatcher; + if (mm.Matches(method, targetType)) + { + return mm.IsRuntime ? mm.Matches(method, targetType, args) : true; + } + } + } - #region Constructor (s) / Destructor + return false; + } - // CLOVER:OFF + /// + /// Are the supplied s equal? + /// + /// The first pointcut. + /// The second pointcut. + /// + /// if the supplied s + /// are equal. + /// + public static bool AreEqual(IPointcut firstPointcut, IPointcut secondPointcut) + { + return firstPointcut.TypeFilter == secondPointcut.TypeFilter + && firstPointcut.MethodMatcher == secondPointcut.MethodMatcher; + } - /// - /// Creates a new instance of the - /// class. - /// - /// - ///

- /// This is a utility class, and as such has no publicly - /// visible constructors. - ///

- ///
- private Pointcuts() - { - } + #region Constructor (s) / Destructor - // CLOVER:ON + // CLOVER:OFF - #endregion - } + /// + /// Creates a new instance of the + /// class. + /// + /// + ///

+ /// This is a utility class, and as such has no publicly + /// visible constructors. + ///

+ ///
+ private Pointcuts() + { + } + + // CLOVER:ON + + #endregion } diff --git a/src/Spring/Spring.Aop/Aop/Support/RegularExpressionMethodPointcutAdvisor.cs b/src/Spring/Spring.Aop/Aop/Support/RegularExpressionMethodPointcutAdvisor.cs index b08fb642..d67111b0 100644 --- a/src/Spring/Spring.Aop/Aop/Support/RegularExpressionMethodPointcutAdvisor.cs +++ b/src/Spring/Spring.Aop/Aop/Support/RegularExpressionMethodPointcutAdvisor.cs @@ -25,115 +25,115 @@ using Spring.Util; #endregion -namespace Spring.Aop.Support +namespace Spring.Aop.Support; + +/// +/// Convenient class for regular expression method pointcuts that hold an +/// , making them an +/// . +/// +/// +///

+/// Configure this class using the and +/// pass-through properties. These are analogous +/// to the and +/// s properties of the +/// class. +///

+///

+/// Can delegate to any type of regular expression pointcut. Currently only +/// pointcuts based on the regular expression classes from the .NET Base +/// Class Library are supported. The +/// +/// property must be a subclass of the +/// class. +///

+///

+/// This should not normally be set directly. +///

+///
+/// Dmitriy Kopylenko +/// Rod Johnson +/// Simon White (.NET) +/// Mark Pollack (.NET) +/// +[Serializable] +public class RegularExpressionMethodPointcutAdvisor : AbstractGenericPointcutAdvisor { + private AbstractRegularExpressionMethodPointcut pointcut; + + #region Constructors + /// - /// Convenient class for regular expression method pointcuts that hold an - /// , making them an - /// . + /// Creates a new instance of the + /// class. /// - /// - ///

- /// Configure this class using the and - /// pass-through properties. These are analogous - /// to the and - /// s properties of the - /// class. - ///

- ///

- /// Can delegate to any type of regular expression pointcut. Currently only - /// pointcuts based on the regular expression classes from the .NET Base - /// Class Library are supported. The - /// - /// property must be a subclass of the - /// class. - ///

- ///

- /// This should not normally be set directly. - ///

- ///
- /// Dmitriy Kopylenko - /// Rod Johnson - /// Simon White (.NET) - /// Mark Pollack (.NET) - /// - [Serializable] - public class RegularExpressionMethodPointcutAdvisor : AbstractGenericPointcutAdvisor + public RegularExpressionMethodPointcutAdvisor() { - private AbstractRegularExpressionMethodPointcut pointcut; + InitPointcut(); + } - #region Constructors + /// + /// Creates a new instance of the + /// class for the supplied . + /// + /// The target advice. + /// + public RegularExpressionMethodPointcutAdvisor(IAdvice advice) + { + Advice = advice; + InitPointcut(); + } - /// - /// Creates a new instance of the - /// class. - /// - public RegularExpressionMethodPointcutAdvisor() + #endregion + + #region Properties + + /// + /// A single pattern to be used during method evaluation. + /// + public string Pattern + { + set { - InitPointcut(); - } - - /// - /// Creates a new instance of the - /// class for the supplied . - /// - /// The target advice. - /// - public RegularExpressionMethodPointcutAdvisor(IAdvice advice) - { - Advice = advice; - InitPointcut(); - } - - #endregion - - #region Properties - - /// - /// A single pattern to be used during method evaluation. - /// - public string Pattern - { - set - { - AbstractRegularExpressionMethodPointcut armp = (AbstractRegularExpressionMethodPointcut) Pointcut; - armp.Pattern = value; - } - } - - /// - /// Multiple patterns to be used during method evaluation. - /// - public string[] Patterns - { - set - { - AbstractRegularExpressionMethodPointcut armp = (AbstractRegularExpressionMethodPointcut) Pointcut; - armp.Patterns = value; - } - } - - /// - /// The that drives this advisor. - /// - public override IPointcut Pointcut - { - get { return pointcut; } - set { - AssertUtils.AssertArgumentType(value, "pointcut", typeof(AbstractRegularExpressionMethodPointcut), - "Pointcut most be compatible with type AbstractRegularExpressionMethodPointuct"); - pointcut = value as AbstractRegularExpressionMethodPointcut; - } - } - - #endregion - - /// - /// Initialises the pointcut. - /// - protected void InitPointcut() - { - pointcut = new SdkRegularExpressionMethodPointcut(); + AbstractRegularExpressionMethodPointcut armp = (AbstractRegularExpressionMethodPointcut) Pointcut; + armp.Pattern = value; } } + + /// + /// Multiple patterns to be used during method evaluation. + /// + public string[] Patterns + { + set + { + AbstractRegularExpressionMethodPointcut armp = (AbstractRegularExpressionMethodPointcut) Pointcut; + armp.Patterns = value; + } + } + + /// + /// The that drives this advisor. + /// + public override IPointcut Pointcut + { + get { return pointcut; } + set + { + AssertUtils.AssertArgumentType(value, "pointcut", typeof(AbstractRegularExpressionMethodPointcut), + "Pointcut most be compatible with type AbstractRegularExpressionMethodPointuct"); + pointcut = value as AbstractRegularExpressionMethodPointcut; + } + } + + #endregion + + /// + /// Initialises the pointcut. + /// + protected void InitPointcut() + { + pointcut = new SdkRegularExpressionMethodPointcut(); + } } diff --git a/src/Spring/Spring.Aop/Aop/Support/RootTypeFilter.cs b/src/Spring/Spring.Aop/Aop/Support/RootTypeFilter.cs index b5112497..7c54023c 100644 --- a/src/Spring/Spring.Aop/Aop/Support/RootTypeFilter.cs +++ b/src/Spring/Spring.Aop/Aop/Support/RootTypeFilter.cs @@ -24,55 +24,54 @@ using Spring.Util; #endregion -namespace Spring.Aop.Support +namespace Spring.Aop.Support; + +/// +/// Simple implementation that matches +/// all classes classes (and any derived subclasses) of a give root +/// . +/// +/// Rod Johnson +/// Aleksandar Seovic (.NET) +[Serializable] +public class RootTypeFilter : ITypeFilter { - /// - /// Simple implementation that matches - /// all classes classes (and any derived subclasses) of a give root - /// . - /// - /// Rod Johnson - /// Aleksandar Seovic (.NET) - [Serializable] - public class RootTypeFilter : ITypeFilter - { - private Type _rootType; + private Type _rootType; - /// - /// Creates a new instance of the - /// for the supplied - /// . - /// - /// The root . - /// - /// If the supplied is . - /// - public RootTypeFilter(Type rootType) - { - AssertUtils.ArgumentNotNull(rootType, "rootType"); - _rootType = rootType; - } + /// + /// Creates a new instance of the + /// for the supplied + /// . + /// + /// The root . + /// + /// If the supplied is . + /// + public RootTypeFilter(Type rootType) + { + AssertUtils.ArgumentNotNull(rootType, "rootType"); + _rootType = rootType; + } - /// - /// Should the pointcut apply to the supplied - /// ? - /// - /// - ///

- /// Returns if the supplied - /// can be assigned to the root . - ///

- ///
- /// - /// The candidate . - /// - /// - /// if the advice should apply to the supplied - /// - /// - public virtual bool Matches(Type type) - { - return _rootType.IsAssignableFrom(type); - } - } + /// + /// Should the pointcut apply to the supplied + /// ? + /// + /// + ///

+ /// Returns if the supplied + /// can be assigned to the root . + ///

+ ///
+ /// + /// The candidate . + /// + /// + /// if the advice should apply to the supplied + /// + /// + public virtual bool Matches(Type type) + { + return _rootType.IsAssignableFrom(type); + } } diff --git a/src/Spring/Spring.Aop/Aop/Support/SdkRegularExpressionMethodPointcut.cs b/src/Spring/Spring.Aop/Aop/Support/SdkRegularExpressionMethodPointcut.cs index 5eca1850..d74f6b02 100644 --- a/src/Spring/Spring.Aop/Aop/Support/SdkRegularExpressionMethodPointcut.cs +++ b/src/Spring/Spring.Aop/Aop/Support/SdkRegularExpressionMethodPointcut.cs @@ -19,152 +19,150 @@ using System.Text.RegularExpressions; using Microsoft.Extensions.Logging; using Spring.Util; -namespace Spring.Aop.Support +namespace Spring.Aop.Support; + +/// +/// Regular expression based pointcut object. +/// +/// +///

+/// Uses the regular expression classes from the .NET Base Class Library. +///

+///

+/// The regular expressions must be a match. For example, the +/// .*Get* pattern will match Com.Mycom.Foo.GetBar(), and +/// Get.* will not. +///

+///
+/// Rod Johnson +/// Simon White (.NET) +[Serializable] +public class SdkRegularExpressionMethodPointcut : AbstractRegularExpressionMethodPointcut { - /// - /// Regular expression based pointcut object. - /// - /// - ///

- /// Uses the regular expression classes from the .NET Base Class Library. - ///

- ///

- /// The regular expressions must be a match. For example, the - /// .*Get* pattern will match Com.Mycom.Foo.GetBar(), and - /// Get.* will not. - ///

- ///
- /// Rod Johnson - /// Simon White (.NET) - [Serializable] - public class SdkRegularExpressionMethodPointcut : AbstractRegularExpressionMethodPointcut - { - [NonSerialized] - private static readonly ILogger _logger = LogManager.GetLogger(); + [NonSerialized] private static readonly ILogger _logger = LogManager.GetLogger(); - private Regex[] _compiledPatterns = new Regex[0]; - private RegexOptions _defaultOptions = RegexOptions.None; + private Regex[] _compiledPatterns = new Regex[0]; + private RegexOptions _defaultOptions = RegexOptions.None; - /// - /// Creates a new instance of the - /// class. - /// - public SdkRegularExpressionMethodPointcut() - { - } + /// + /// Creates a new instance of the + /// class. + /// + public SdkRegularExpressionMethodPointcut() + { + } - /// - /// Creates a new instance of the - /// class, - /// using the supplied pattern or . - /// - /// - /// The intial pattern value(s) to be matched against. - /// - public SdkRegularExpressionMethodPointcut(params string[] patterns) + /// + /// Creates a new instance of the + /// class, + /// using the supplied pattern or . + /// + /// + /// The intial pattern value(s) to be matched against. + /// + public SdkRegularExpressionMethodPointcut(params string[] patterns) + { + Patterns = patterns; + } + + /// + protected SdkRegularExpressionMethodPointcut(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + + /// + /// Gets or sets default options that should be used by + /// regular expressions that don't have options explicitly set. + /// + /// + /// Default options that should be used by regular expressions + /// that don't have options explicitly set. + /// + public RegexOptions DefaultOptions + { + get { return _defaultOptions; } + set { - Patterns = patterns; + _defaultOptions = value; + InitPatternRepresentation(Patterns); } + } - /// - protected SdkRegularExpressionMethodPointcut(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } + /// + /// Initializes the regular expression pointcuts. + /// + /// + ///

+ /// Can be invoked multiple times. + ///

+ ///

+ /// This method will be invoked from the + /// property, + /// and also on deserialization. + ///

+ ///
+ /// + /// The patterns to initialize. + /// + /// + /// In the case of an invalid pattern. + /// + /// + /// If the supplied is . + /// + protected override void InitPatternRepresentation(object[] patterns) + { + AssertUtils.ArgumentNotNull(patterns, "patterns"); - /// - /// Gets or sets default options that should be used by - /// regular expressions that don't have options explicitly set. - /// - /// - /// Default options that should be used by regular expressions - /// that don't have options explicitly set. - /// - public RegexOptions DefaultOptions - { - get { return _defaultOptions; } - set - { - _defaultOptions = value; - InitPatternRepresentation(Patterns); - } - } - - /// - /// Initializes the regular expression pointcuts. - /// - /// - ///

- /// Can be invoked multiple times. - ///

- ///

- /// This method will be invoked from the - /// property, - /// and also on deserialization. - ///

- ///
- /// - /// The patterns to initialize. - /// - /// - /// In the case of an invalid pattern. - /// - /// - /// If the supplied is . - /// - protected override void InitPatternRepresentation(object[] patterns) - { - AssertUtils.ArgumentNotNull(patterns, "patterns"); - - if (patterns.Length > 0) + if (patterns.Length > 0) + { + _compiledPatterns = new Regex[patterns.Length]; + for (int i = 0; i < patterns.Length; i++) { - _compiledPatterns = new Regex[patterns.Length]; - for (int i = 0; i < patterns.Length; i++) + if (patterns[i] == null) { - if (patterns[i] == null) - { - throw new ArgumentNullException( - "Null is not a valid value for an element of the Patterns property."); - } - else if (patterns[i] is Regex) - { - _compiledPatterns[i] = (Regex)patterns[i]; - } - else if (patterns[i] is string) - { - _compiledPatterns[i] = new Regex((string)patterns[i], DefaultOptions); - } - else - { - throw new ArgumentException( - "You can only specify a string value or an instance of a Regex class " + - "as an element of the 'Patterns' property."); - } + throw new ArgumentNullException( + "Null is not a valid value for an element of the Patterns property."); + } + else if (patterns[i] is Regex) + { + _compiledPatterns[i] = (Regex) patterns[i]; + } + else if (patterns[i] is string) + { + _compiledPatterns[i] = new Regex((string) patterns[i], DefaultOptions); + } + else + { + throw new ArgumentException( + "You can only specify a string value or an instance of a Regex class " + + "as an element of the 'Patterns' property."); } } - } + } + } - /// - /// Does the pattern at the supplied - /// match this ? - /// - /// The pattern to match - /// The index of pattern. - /// - /// if there is a match. - /// - protected override bool Matches(string pattern, int patternIndex) - { - Match match = _compiledPatterns[patternIndex].Match(pattern); - bool matched = match.Success; + /// + /// Does the pattern at the supplied + /// match this ? + /// + /// The pattern to match + /// The index of pattern. + /// + /// if there is a match. + /// + protected override bool Matches(string pattern, int patternIndex) + { + Match match = _compiledPatterns[patternIndex].Match(pattern); + bool matched = match.Success; - if (_logger.IsEnabled(LogLevel.Debug)) - { - _logger.LogDebug("Candidate is: '" + pattern + "'; pattern is '" + - _compiledPatterns[patternIndex].ToString() + "'; matched=" + matched); - } + if (_logger.IsEnabled(LogLevel.Debug)) + { + _logger.LogDebug("Candidate is: '" + pattern + "'; pattern is '" + + _compiledPatterns[patternIndex].ToString() + "'; matched=" + matched); + } - return matched; - } - } + return matched; + } } diff --git a/src/Spring/Spring.Aop/Aop/Support/StaticMethodMatcher.cs b/src/Spring/Spring.Aop/Aop/Support/StaticMethodMatcher.cs index a19c981b..c43f49d6 100644 --- a/src/Spring/Spring.Aop/Aop/Support/StaticMethodMatcher.cs +++ b/src/Spring/Spring.Aop/Aop/Support/StaticMethodMatcher.cs @@ -25,91 +25,89 @@ using System.Runtime.Serialization; #endregion -namespace Spring.Aop.Support +namespace Spring.Aop.Support; + +/// +/// Convenient abstract superclass for static method matchers that don't care +/// about arguments at runtime. +/// +/// Rod Johnson +/// Aleksandar Seovic (.NET) +[Serializable] +public abstract class StaticMethodMatcher : IMethodMatcher, IDeserializationCallback { - /// - /// Convenient abstract superclass for static method matchers that don't care - /// about arguments at runtime. - /// - /// Rod Johnson - /// Aleksandar Seovic (.NET) - [Serializable] - public abstract class StaticMethodMatcher : IMethodMatcher, IDeserializationCallback - { - /// - /// Is this dynamic? - /// - /// - ///

- /// Always returns . - ///

- ///
- /// - /// Always returns . - /// - public bool IsRuntime - { - get { return false; } - } + /// + /// Is this dynamic? + /// + /// + ///

+ /// Always returns . + ///

+ ///
+ /// + /// Always returns . + /// + public bool IsRuntime + { + get { return false; } + } - /// - /// Is there a runtime (dynamic) match for the supplied - /// ? - /// - /// - ///

- /// Always throws a . This - /// method should never be called on a static matcher. - ///

- ///
- /// The candidate method. - /// - /// The target . - /// - /// The arguments to the method - /// - /// Always throws a . - /// - /// - /// Always. - /// - public bool Matches(MethodInfo method, Type targetType, object[] args) - { - throw new NotSupportedException( - "Illegal IMethodMatcher usage. Cannot call 3-arg Matches method on a static matcher."); - } + /// + /// Is there a runtime (dynamic) match for the supplied + /// ? + /// + /// + ///

+ /// Always throws a . This + /// method should never be called on a static matcher. + ///

+ ///
+ /// The candidate method. + /// + /// The target . + /// + /// The arguments to the method + /// + /// Always throws a . + /// + /// + /// Always. + /// + public bool Matches(MethodInfo method, Type targetType, object[] args) + { + throw new NotSupportedException( + "Illegal IMethodMatcher usage. Cannot call 3-arg Matches method on a static matcher."); + } - /// - /// 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 abstract bool Matches(MethodInfo method, Type targetType); + /// + /// 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 abstract bool Matches(MethodInfo method, Type targetType); + void IDeserializationCallback.OnDeserialization(object sender) + { + OnDeserialization(sender); + } - void IDeserializationCallback.OnDeserialization(object sender) - { - OnDeserialization(sender); - } - - /// - /// Override in case you need to initialized non-serialized fields on deserialization. - /// - protected virtual void OnDeserialization(object sender) - { - } - } -} + /// + /// Override in case you need to initialized non-serialized fields on deserialization. + /// + protected virtual void OnDeserialization(object sender) + { + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Aop/Aop/Support/StaticMethodMatcherPointcut.cs b/src/Spring/Spring.Aop/Aop/Support/StaticMethodMatcherPointcut.cs index 62148d8e..fa36e639 100644 --- a/src/Spring/Spring.Aop/Aop/Support/StaticMethodMatcherPointcut.cs +++ b/src/Spring/Spring.Aop/Aop/Support/StaticMethodMatcherPointcut.cs @@ -18,64 +18,63 @@ #endregion -namespace Spring.Aop.Support +namespace Spring.Aop.Support; + +/// +/// Convenient superclass when one wants to force subclasses to +/// implement the interface +/// but subclasses will still want to be pointcuts. +/// +/// +///

+/// The +/// property can be overriden to customize filter +/// behavior as well. +///

+///
+/// Rod Johnson +/// Aleksandar Seovic (.NET) +/// Mark Pollack (.NET) +[Serializable] +public abstract class StaticMethodMatcherPointcut : StaticMethodMatcher, IPointcut { - /// - /// Convenient superclass when one wants to force subclasses to - /// implement the interface - /// but subclasses will still want to be pointcuts. - /// - /// - ///

- /// The - /// property can be overriden to customize filter - /// behavior as well. - ///

- ///
- /// Rod Johnson - /// Aleksandar Seovic (.NET) - /// Mark Pollack (.NET) - [Serializable] - public abstract class StaticMethodMatcherPointcut : StaticMethodMatcher, IPointcut - { - private ITypeFilter typeFilter = TrueTypeFilter.True; + private ITypeFilter typeFilter = TrueTypeFilter.True; - /// - /// Creates a new instance of the - /// - /// class. - /// - /// - ///

- /// This is an abstract class, and as such has no publicly - /// visible constructors. - ///

- ///
- protected StaticMethodMatcherPointcut() - { - } + /// + /// Creates a new instance of the + /// + /// class. + /// + /// + ///

+ /// This is an abstract class, and as such has no publicly + /// visible constructors. + ///

+ ///
+ protected StaticMethodMatcherPointcut() + { + } - /// - /// The for this pointcut. - /// - /// - /// The current . - /// - public virtual ITypeFilter TypeFilter - { - get { return typeFilter; } - set { typeFilter = value;} - } + /// + /// The for this pointcut. + /// + /// + /// The current . + /// + public virtual ITypeFilter TypeFilter + { + get { return typeFilter; } + set { typeFilter = value; } + } - /// - /// The for this pointcut. - /// - /// - /// The current . - /// - public virtual IMethodMatcher MethodMatcher - { - get { return this; } - } - } + /// + /// The for this pointcut. + /// + /// + /// The current . + /// + public virtual IMethodMatcher MethodMatcher + { + get { return this; } + } } diff --git a/src/Spring/Spring.Aop/Aop/Support/StaticMethodMatcherPointcutAdvisor.cs b/src/Spring/Spring.Aop/Aop/Support/StaticMethodMatcherPointcutAdvisor.cs index 06286ff1..cc7b41ff 100644 --- a/src/Spring/Spring.Aop/Aop/Support/StaticMethodMatcherPointcutAdvisor.cs +++ b/src/Spring/Spring.Aop/Aop/Support/StaticMethodMatcherPointcutAdvisor.cs @@ -25,108 +25,107 @@ using Spring.Core; #endregion -namespace Spring.Aop.Support +namespace Spring.Aop.Support; + +/// +/// Convenient superclass for s that +/// are also static pointcuts. +/// +/// Rod Johnson +/// Aleksandar Seovic (.Net) +[Serializable] +public abstract class StaticMethodMatcherPointcutAdvisor + : StaticMethodMatcherPointcut, IPointcutAdvisor, IOrdered { - /// - /// Convenient superclass for s that - /// are also static pointcuts. - /// - /// Rod Johnson - /// Aleksandar Seovic (.Net) - [Serializable] - public abstract class StaticMethodMatcherPointcutAdvisor - : StaticMethodMatcherPointcut, IPointcutAdvisor, IOrdered - { - private int _order = Int32.MaxValue; - private IAdvice _advice; + private int _order = Int32.MaxValue; + private IAdvice _advice; - /// - /// Creates a new instance of the - /// - /// class. - /// - /// - ///

- /// This is an abstract class, and as such has no publicly - /// visible constructors. - ///

- ///
- protected StaticMethodMatcherPointcutAdvisor() - { - } + /// + /// Creates a new instance of the + /// + /// class. + /// + /// + ///

+ /// This is an abstract class, and as such has no publicly + /// visible constructors. + ///

+ ///
+ protected StaticMethodMatcherPointcutAdvisor() + { + } - /// - /// Creates a new instance of the - /// - /// class for the supplied - /// - /// - ///

- /// This is an abstract class, and as such has no publicly - /// visible constructors. - ///

- ///
- /// - /// The advice to use. - /// - public StaticMethodMatcherPointcutAdvisor(IAdvice advice) - { - this._advice = advice; - } + /// + /// Creates a new instance of the + /// + /// class for the supplied + /// + /// + ///

+ /// This is an abstract class, and as such has no publicly + /// visible constructors. + ///

+ ///
+ /// + /// The advice to use. + /// + public StaticMethodMatcherPointcutAdvisor(IAdvice advice) + { + this._advice = advice; + } - /// - /// Is this advice associated with a particular instance? - /// - /// - /// if this advice is associated with a - /// particular instance. - /// - /// - /// Always; this property is not yet supported. - /// - public virtual bool IsPerInstance - { - get - { - throw new NotSupportedException( - "The 'IsPerInstance' property of the IAdvisor interface is " + - "not yet supported in Spring.NET."); - } - } + /// + /// Is this advice associated with a particular instance? + /// + /// + /// if this advice is associated with a + /// particular instance. + /// + /// + /// Always; this property is not yet supported. + /// + public virtual bool IsPerInstance + { + get + { + throw new NotSupportedException( + "The 'IsPerInstance' property of the IAdvisor interface is " + + "not yet supported in Spring.NET."); + } + } - /// - /// Returns this s order in the - /// interception chain. - /// - /// - /// This s order in the - /// interception chain. - /// - public virtual int Order - { - get { return this._order; } - set { this._order = value; } - } + /// + /// Returns this s order in the + /// interception chain. + /// + /// + /// This s order in the + /// interception chain. + /// + public virtual int Order + { + get { return this._order; } + set { this._order = value; } + } - /// - /// Return the advice part of this advisor. - /// - /// - /// The advice that should apply if the pointcut matches. - /// - /// - public virtual IAdvice Advice - { - get { return this._advice; } - set { this._advice = value; } - } + /// + /// Return the advice part of this advisor. + /// + /// + /// The advice that should apply if the pointcut matches. + /// + /// + public virtual IAdvice Advice + { + get { return this._advice; } + set { this._advice = value; } + } - /// - /// The that drives this advisor. - /// - public virtual IPointcut Pointcut - { - get { return this; } - } - } + /// + /// The that drives this advisor. + /// + public virtual IPointcut Pointcut + { + get { return this; } + } } diff --git a/src/Spring/Spring.Aop/Aop/Support/TypeFilters.cs b/src/Spring/Spring.Aop/Aop/Support/TypeFilters.cs index 8ad15a88..bec0b888 100644 --- a/src/Spring/Spring.Aop/Aop/Support/TypeFilters.cs +++ b/src/Spring/Spring.Aop/Aop/Support/TypeFilters.cs @@ -22,134 +22,135 @@ #endregion -namespace Spring.Aop.Support +namespace Spring.Aop.Support; + +/// +/// Defines miscellaneous filter operations. +/// +/// Rod Johnson +/// Aleksandar Seovic (.Net) +public sealed class TypeFilters { - /// - /// Defines miscellaneous filter operations. - /// - /// Rod Johnson - /// Aleksandar Seovic (.Net) - public sealed class TypeFilters - { - /// - /// Creates a union of two filters. - /// - /// - ///

- /// The filter arising from the union will match all of the - /// that either of the two supplied filters - /// would match. - ///

- ///
- /// - /// The first filter. - /// - /// - /// The second filter. - /// - /// - /// The union of the supplied filters. - /// - public static ITypeFilter Union(ITypeFilter first, ITypeFilter second) - { - return new UnionTypeFilter(new ITypeFilter[] {first, second}); - } + /// + /// Creates a union of two filters. + /// + /// + ///

+ /// The filter arising from the union will match all of the + /// that either of the two supplied filters + /// would match. + ///

+ ///
+ /// + /// The first filter. + /// + /// + /// The second filter. + /// + /// + /// The union of the supplied filters. + /// + public static ITypeFilter Union(ITypeFilter first, ITypeFilter second) + { + return new UnionTypeFilter(new ITypeFilter[] { first, second }); + } - /// - /// Creates the intersection of two filters. - /// - /// - ///

- /// The filter arising from the intersection will match all of the - /// that both of the two supplied filters - /// would match. - ///

- ///
- /// - /// The first filter. - /// - /// - /// The second filter. - /// - /// - /// The intersection of the supplied filters. - /// - public static ITypeFilter Intersection(ITypeFilter first, ITypeFilter second) - { - return new IntersectionTypeFilter(new ITypeFilter[] {first, second}); - } + /// + /// Creates the intersection of two filters. + /// + /// + ///

+ /// The filter arising from the intersection will match all of the + /// that both of the two supplied filters + /// would match. + ///

+ ///
+ /// + /// The first filter. + /// + /// + /// The second filter. + /// + /// + /// The intersection of the supplied filters. + /// + public static ITypeFilter Intersection(ITypeFilter first, ITypeFilter second) + { + return new IntersectionTypeFilter(new ITypeFilter[] { first, second }); + } - /// - /// Union class filter implementation. - /// - [Serializable] - private sealed class UnionTypeFilter : ITypeFilter - { - private ITypeFilter[] _filters; + /// + /// Union class filter implementation. + /// + [Serializable] + private sealed class UnionTypeFilter : ITypeFilter + { + private ITypeFilter[] _filters; - public UnionTypeFilter(ITypeFilter[] filters) - { - _filters = filters; - } + public UnionTypeFilter(ITypeFilter[] filters) + { + _filters = filters; + } - public bool Matches(Type type) - { - for (int i = 0; i < _filters.Length; i++) - { - if (_filters[i].Matches(type)) - { - return true; - } - } - return false; - } - } + public bool Matches(Type type) + { + for (int i = 0; i < _filters.Length; i++) + { + if (_filters[i].Matches(type)) + { + return true; + } + } - /// - /// Intersection implementation. - /// - [Serializable] - private sealed class IntersectionTypeFilter : ITypeFilter - { - private ITypeFilter[] _filters; + return false; + } + } - public IntersectionTypeFilter(ITypeFilter[] filters) - { - _filters = filters; - } + /// + /// Intersection implementation. + /// + [Serializable] + private sealed class IntersectionTypeFilter : ITypeFilter + { + private ITypeFilter[] _filters; - public bool Matches(Type type) - { - for (int i = 0; i < _filters.Length; i++) - { - if (!_filters[i].Matches(type)) - { - return false; - } - } - return true; - } - } + public IntersectionTypeFilter(ITypeFilter[] filters) + { + _filters = filters; + } - #region Constructor (s) / Destructor + public bool Matches(Type type) + { + for (int i = 0; i < _filters.Length; i++) + { + if (!_filters[i].Matches(type)) + { + return false; + } + } - // CLOVER:OFF + return true; + } + } - /// - /// Creates a new instance of the - /// class. - /// - /// - ///

- /// This is a utility class, and as such has no publicly visible constructors. - ///

- ///
- private TypeFilters() - { - } + #region Constructor (s) / Destructor - // CLOVER:ON + // CLOVER:OFF - #endregion - } + /// + /// Creates a new instance of the + /// class. + /// + /// + ///

+ /// This is a utility class, and as such has no publicly visible constructors. + ///

+ ///
+ private TypeFilters() + { + } + + // CLOVER:ON + + #endregion } diff --git a/src/Spring/Spring.Aop/Aop/Support/TypeNameTypeFilter.cs b/src/Spring/Spring.Aop/Aop/Support/TypeNameTypeFilter.cs index 43463c51..211590e0 100644 --- a/src/Spring/Spring.Aop/Aop/Support/TypeNameTypeFilter.cs +++ b/src/Spring/Spring.Aop/Aop/Support/TypeNameTypeFilter.cs @@ -24,51 +24,50 @@ using Spring.Util; #endregion -namespace Spring.Aop.Support +namespace Spring.Aop.Support; + +/// +/// Simple implementation that matches +/// a given 's against . +/// For a list of supported pattern syntax see . +/// +/// Erich Eichinger +/// +public class TypeNameTypeFilter : ITypeFilter { - /// - /// Simple implementation that matches - /// a given 's against . - /// For a list of supported pattern syntax see . - /// - /// Erich Eichinger + private string[] _typeNamePatterns; + + /// + /// Returns the list of type name patterns for this filter. + /// /// - public class TypeNameTypeFilter : ITypeFilter + public string[] TypeNamePatterns { - private string[] _typeNamePatterns; + get { return _typeNamePatterns; } + } - /// - /// Returns the list of type name patterns for this filter. - /// - /// - public string[] TypeNamePatterns - { - get { return _typeNamePatterns; } - } + /// + ///Creates a new instance of using a list of given . + /// + ///the list patterns to match typenames against. Must not be null. + /// + public TypeNameTypeFilter(string[] patterns) + { + AssertUtils.ArgumentNotNull(patterns, "patterns"); + _typeNamePatterns = patterns; + } - /// - ///Creates a new instance of using a list of given . - /// - ///the list patterns to match typenames against. Must not be null. - /// - public TypeNameTypeFilter(string[] patterns) - { - AssertUtils.ArgumentNotNull(patterns, "patterns"); - _typeNamePatterns = patterns; - } - - /// - /// Does the supplied type's match any of the ? - /// - /// - /// The candidate . - /// - /// - /// if the matches any of the . - /// - public bool Matches(Type type) - { - return PatternMatchUtils.SimpleMatch(_typeNamePatterns, type.FullName); - } + /// + /// Does the supplied type's match any of the ? + /// + /// + /// The candidate . + /// + /// + /// if the matches any of the . + /// + public bool Matches(Type type) + { + return PatternMatchUtils.SimpleMatch(_typeNamePatterns, type.FullName); } } diff --git a/src/Spring/Spring.Aop/Aop/Support/UnionPointcut.cs b/src/Spring/Spring.Aop/Aop/Support/UnionPointcut.cs index f21fb147..b7cabc92 100644 --- a/src/Spring/Spring.Aop/Aop/Support/UnionPointcut.cs +++ b/src/Spring/Spring.Aop/Aop/Support/UnionPointcut.cs @@ -24,100 +24,98 @@ using System.Reflection; #endregion -namespace Spring.Aop.Support +namespace Spring.Aop.Support; + +/// +/// A union. +/// +/// +///

+/// Such pointcut unions are tricky, because one cannot simply OR +/// the respective s: one has to +/// ascertain that each 's +/// is also satisfied. +///

+///
+/// Rod Johnson +/// Aleksandar Seovic (.NET) +[Serializable] +internal class UnionPointcut : IPointcut { - /// - /// A union. - /// - /// - ///

- /// Such pointcut unions are tricky, because one cannot simply OR - /// the respective s: one has to - /// ascertain that each 's - /// is also satisfied. - ///

- ///
- /// Rod Johnson - /// Aleksandar Seovic (.NET) + private IPointcut a; + private IPointcut b; + private IMethodMatcher mm; + + /// + /// Creates a new instance of the + /// class. + /// + /// The first pointcut. + /// The second pointcut. + public UnionPointcut(IPointcut firstPointcut, IPointcut secondPointcut) + { + this.a = firstPointcut; + this.b = secondPointcut; + this.mm = new PointcutUnionMethodMatcher(this); + } + + /// + /// The for this pointcut. + /// + /// + /// The current . + /// + public ITypeFilter TypeFilter + { + get { return TypeFilters.Union(a.TypeFilter, b.TypeFilter); } + } + + /// + /// The for this pointcut. + /// + /// + /// The current . + /// + public IMethodMatcher MethodMatcher + { + get { return mm; } + } + + /// + /// Internal method matcher class for union pointcut. + /// [Serializable] - internal class UnionPointcut : IPointcut - { - private IPointcut a; - private IPointcut b; - private IMethodMatcher mm; + private sealed class PointcutUnionMethodMatcher : IMethodMatcher + { + private UnionPointcut _enclosingInstance; - /// - /// Creates a new instance of the - /// class. - /// - /// The first pointcut. - /// The second pointcut. - public UnionPointcut(IPointcut firstPointcut, IPointcut secondPointcut) - { - this.a = firstPointcut; - this.b = secondPointcut; - this.mm = new PointcutUnionMethodMatcher(this); - } + public PointcutUnionMethodMatcher(UnionPointcut enclosingInstance) + { + this._enclosingInstance = enclosingInstance; + } - /// - /// The for this pointcut. - /// - /// - /// The current . - /// - public ITypeFilter TypeFilter - { - get { return TypeFilters.Union(a.TypeFilter, b.TypeFilter); } + public bool IsRuntime + { + get + { + return _enclosingInstance.a.MethodMatcher.IsRuntime + || _enclosingInstance.b.MethodMatcher.IsRuntime; + } + } - } + public bool Matches(MethodInfo method, Type targetType) + { + return (_enclosingInstance.a.TypeFilter.Matches(targetType) + && _enclosingInstance.a.MethodMatcher.Matches(method, targetType)) + || (_enclosingInstance.b.TypeFilter.Matches(targetType) + && _enclosingInstance.b.MethodMatcher.Matches(method, targetType)); + } - /// - /// The for this pointcut. - /// - /// - /// The current . - /// - public IMethodMatcher MethodMatcher - { - get { return mm; } - } - - /// - /// Internal method matcher class for union pointcut. - /// - [Serializable] - private sealed class PointcutUnionMethodMatcher : IMethodMatcher - { - private UnionPointcut _enclosingInstance; - - public PointcutUnionMethodMatcher(UnionPointcut enclosingInstance) - { - this._enclosingInstance = enclosingInstance; - } - - public bool IsRuntime - { - get - { - return _enclosingInstance.a.MethodMatcher.IsRuntime - || _enclosingInstance.b.MethodMatcher.IsRuntime; - } - } - - public bool Matches(MethodInfo method, Type targetType) - { - return (_enclosingInstance.a.TypeFilter.Matches(targetType) - && _enclosingInstance.a.MethodMatcher.Matches(method, targetType)) - || (_enclosingInstance.b.TypeFilter.Matches(targetType) - && _enclosingInstance.b.MethodMatcher.Matches(method, targetType)); - } - - public bool Matches(MethodInfo method, Type targetType, object[] args) - { - // 2-arg matcher will already have run, so we don't need to do type filtering again... - return _enclosingInstance.a.MethodMatcher.Matches(method, targetType, args) - || _enclosingInstance.b.MethodMatcher.Matches(method, targetType, args); - } - } - } + public bool Matches(MethodInfo method, Type targetType, object[] args) + { + // 2-arg matcher will already have run, so we don't need to do type filtering again... + return _enclosingInstance.a.MethodMatcher.Matches(method, targetType, args) + || _enclosingInstance.b.MethodMatcher.Matches(method, targetType, args); + } + } } diff --git a/src/Spring/Spring.Aop/Aop/Target/AbstractPoolingTargetSource.cs b/src/Spring/Spring.Aop/Aop/Target/AbstractPoolingTargetSource.cs index 1ada25f6..49760b22 100644 --- a/src/Spring/Spring.Aop/Aop/Target/AbstractPoolingTargetSource.cs +++ b/src/Spring/Spring.Aop/Aop/Target/AbstractPoolingTargetSource.cs @@ -27,176 +27,175 @@ using Spring.Objects.Factory; #endregion -namespace Spring.Aop.Target +namespace Spring.Aop.Target; + +/// +/// Abstract superclass for pooling s. +/// +/// +///

+/// Maintains a pool of target instances, acquiring and releasing a target +/// object from the pool for each method invocation. +///

+///

+/// This class is independent of pooling technology. +///

+///

+/// Subclasses must implement the +/// and +/// +/// methods to work with their chosen pool. The +/// +/// method inherited from the +/// base class +/// can be used to create objects to put in the pool. Subclasses must also +/// implement some of the monitoring methods from the +/// interface. This class +/// provides the +/// +/// method to return an +/// making these statistics available on proxied objects. +///

+///

+/// This class implements the interface in +/// order to force subclasses to implement the +/// method to cleanup and close +/// down their pool. +///

+///
+/// Rod Johnson +/// Federico Spinazzi (.NET) +[Serializable] +public abstract class AbstractPoolingTargetSource + : AbstractPrototypeTargetSource, PoolingConfig, IDisposable, IAdvice { - /// - /// Abstract superclass for pooling s. - /// - /// - ///

- /// Maintains a pool of target instances, acquiring and releasing a target - /// object from the pool for each method invocation. - ///

- ///

- /// This class is independent of pooling technology. - ///

- ///

- /// Subclasses must implement the - /// and - /// - /// methods to work with their chosen pool. The - /// - /// method inherited from the - /// base class - /// can be used to create objects to put in the pool. Subclasses must also - /// implement some of the monitoring methods from the - /// interface. This class - /// provides the - /// - /// method to return an - /// making these statistics available on proxied objects. - ///

- ///

- /// This class implements the interface in - /// order to force subclasses to implement the - /// method to cleanup and close - /// down their pool. - ///

- ///
- /// Rod Johnson - /// Federico Spinazzi (.NET) - [Serializable] - public abstract class AbstractPoolingTargetSource - : AbstractPrototypeTargetSource, PoolingConfig, IDisposable, IAdvice - { - #region Constructor (s) / Destructor + #region Constructor (s) / Destructor - /// - /// Creates a new instance of the - /// - /// class. - /// - /// - ///

- /// This is an class, and as such exposes no - /// public constructors. - ///

- ///
- protected AbstractPoolingTargetSource() - { - } + /// + /// Creates a new instance of the + /// + /// class. + /// + /// + ///

+ /// This is an class, and as such exposes no + /// public constructors. + ///

+ ///
+ protected AbstractPoolingTargetSource() + { + } - #endregion + #endregion - /// - /// Returns the target object (acquired from the pool). - /// - /// The target object (acquired from the pool). - /// - /// If unable to obtain the target object. - /// - public abstract override object GetTarget(); + /// + /// Returns the target object (acquired from the pool). + /// + /// The target object (acquired from the pool). + /// + /// If unable to obtain the target object. + /// + public abstract override object GetTarget(); - /// - /// Gets the mixin. - /// - /// - /// An exposing statistics - /// about the pool maintained by this object. - /// - public DefaultIntroductionAdvisor GetPoolingConfigMixin() - { - return new DefaultIntroductionAdvisor(this, typeof (PoolingConfig)); - } + /// + /// Gets the mixin. + /// + /// + /// An exposing statistics + /// about the pool maintained by this object. + /// + public DefaultIntroductionAdvisor GetPoolingConfigMixin() + { + return new DefaultIntroductionAdvisor(this, typeof(PoolingConfig)); + } - /// - /// The maximum number of object instances in this pool. - /// - public int MaxSize - { - get { return _maxSize; } - set { _maxSize = value; } - } + /// + /// The maximum number of object instances in this pool. + /// + public int MaxSize + { + get { return _maxSize; } + set { _maxSize = value; } + } - /// - /// The number of active object instances in this pool. - /// - public abstract int Active { get; } + /// + /// The number of active object instances in this pool. + /// + public abstract int Active { get; } - /// - /// The number of free object instances in this pool. - /// - public abstract int Free { get; } + /// + /// The number of free object instances in this pool. + /// + public abstract int Free { get; } - /// - /// The target factory that will be used to perform the lookup - /// of the object referred to by the - /// - /// property. - /// - /// - /// The owning - /// (will never be ). - /// - /// - /// In case of initialization errors. - /// - /// - public override IObjectFactory ObjectFactory - { - set - { - base.ObjectFactory = value; - try - { - CreatePool(value); - } - catch (ObjectsException) - { - throw; - } - catch (Exception ex) - { - throw new ObjectInitializationException("Could not create instance pool.", ex); - } - } - } + /// + /// The target factory that will be used to perform the lookup + /// of the object referred to by the + /// + /// property. + /// + /// + /// The owning + /// (will never be ). + /// + /// + /// In case of initialization errors. + /// + /// + public override IObjectFactory ObjectFactory + { + set + { + base.ObjectFactory = value; + try + { + CreatePool(value); + } + catch (ObjectsException) + { + throw; + } + catch (Exception ex) + { + throw new ObjectInitializationException("Could not create instance pool.", ex); + } + } + } - /// - /// Create the pool. - /// - /// - /// The owning , in - /// case one needs collaborators from it (normally one's own properties - /// are sufficient). - /// - /// - /// In the case of errors encountered during the creation of the pool. - /// - protected abstract void CreatePool(IObjectFactory factory); + /// + /// Create the pool. + /// + /// + /// The owning , in + /// case one needs collaborators from it (normally one's own properties + /// are sufficient). + /// + /// + /// In the case of errors encountered during the creation of the pool. + /// + protected abstract void CreatePool(IObjectFactory factory); - /// - /// Releases the target object (returns it to the pool). - /// - /// - /// The target object to release (return to the pool). - /// - /// - /// In the case that the could not be released. - /// - public abstract override void ReleaseTarget(object target); + /// + /// Releases the target object (returns it to the pool). + /// + /// + /// The target object to release (return to the pool). + /// + /// + /// In the case that the could not be released. + /// + public abstract override void ReleaseTarget(object target); - /// - /// Performs application-defined tasks associated with freeing, releasing, or - /// resetting unmanaged resources. - /// - /// - ///

- /// Disposes of the pool. - ///

- ///
- public abstract void Dispose(); + /// + /// Performs application-defined tasks associated with freeing, releasing, or + /// resetting unmanaged resources. + /// + /// + ///

+ /// Disposes of the pool. + ///

+ ///
+ public abstract void Dispose(); - private int _maxSize; - } + private int _maxSize; } diff --git a/src/Spring/Spring.Aop/Aop/Target/AbstractPrototypeTargetSource.cs b/src/Spring/Spring.Aop/Aop/Target/AbstractPrototypeTargetSource.cs index 6f9e4a33..231f6a29 100644 --- a/src/Spring/Spring.Aop/Aop/Target/AbstractPrototypeTargetSource.cs +++ b/src/Spring/Spring.Aop/Aop/Target/AbstractPrototypeTargetSource.cs @@ -26,226 +26,226 @@ using Spring.Util; #endregion -namespace Spring.Aop.Target +namespace Spring.Aop.Target; + +/// +/// Base class for dynamic +/// implementations that can create new prototype object instances to +/// support a pooling or new-instance-per-invocation strategy. +/// +/// +///

+/// All such s must run in an +/// , as they need to +/// call the +/// method to create a new prototype instance. +///

+///
+/// Rod Johnson +/// Federico Spinazzi (.NET) +public abstract class AbstractPrototypeTargetSource + : ITargetSource, IObjectFactoryAware, IInitializingObject { - /// - /// Base class for dynamic - /// implementations that can create new prototype object instances to - /// support a pooling or new-instance-per-invocation strategy. - /// - /// - ///

- /// All such s must run in an - /// , as they need to - /// call the - /// method to create a new prototype instance. - ///

- ///
- /// Rod Johnson - /// Federico Spinazzi (.NET) - public abstract class AbstractPrototypeTargetSource - : ITargetSource, IObjectFactoryAware, IInitializingObject - { - #region Constructor (s) / Destructor + #region Constructor (s) / Destructor - /// - /// Creates a new instance of the - /// - /// class. - /// - /// - ///

- /// This is an class, and as such exposes no - /// public constructors. - ///

- ///
- protected AbstractPrototypeTargetSource() - { - } + /// + /// Creates a new instance of the + /// + /// class. + /// + /// + ///

+ /// This is an class, and as such exposes no + /// public constructors. + ///

+ ///
+ protected AbstractPrototypeTargetSource() + { + } - #endregion + #endregion - #region Properties + #region Properties - /// - /// The name of the target object to be created on each invocation. - /// - /// - ///

- /// This object should be a prototype, or the same instance will always - /// be obtained from the owning . - ///

- ///
- public virtual string TargetObjectName - { - get { return _targetObjectName; } - set { - _targetObjectName = value; - } - } + /// + /// The name of the target object to be created on each invocation. + /// + /// + ///

+ /// This object should be a prototype, or the same instance will always + /// be obtained from the owning . + ///

+ ///
+ public virtual string TargetObjectName + { + get { return _targetObjectName; } + set + { + _targetObjectName = value; + } + } - /// - /// The of the target object. - /// - public virtual Type TargetType - { - get { return _targetType; } - } + /// + /// The of the target object. + /// + public virtual Type TargetType + { + get { return _targetType; } + } - /// - /// Is the target source static? - /// - /// - /// if the target source is static. - /// - public virtual bool IsStatic - { - get { return false; } - } + /// + /// Is the target source static? + /// + /// + /// if the target source is static. + /// + public virtual bool IsStatic + { + get { return false; } + } - /// - /// The target factory that will be used to perform the lookup - /// of the object referred to by the - /// property. - /// - /// - ///

- /// Needed so that prototype instances can be created as necessary. - ///

- ///
- /// - /// The owning - /// (will never be ). - /// - /// - /// In case of initialization errors. - /// - /// - public virtual IObjectFactory ObjectFactory - { - get { return _owningObjectFactory; } - set - { - _owningObjectFactory = value; - if (!value.IsPrototype(TargetObjectName)) - { - throw new ObjectDefinitionStoreException( - "Cannot use PrototypeTargetSource against a " + - "Singleton object; instances would not be independent."); - } + /// + /// The target factory that will be used to perform the lookup + /// of the object referred to by the + /// property. + /// + /// + ///

+ /// Needed so that prototype instances can be created as necessary. + ///

+ ///
+ /// + /// The owning + /// (will never be ). + /// + /// + /// In case of initialization errors. + /// + /// + public virtual IObjectFactory ObjectFactory + { + get { return _owningObjectFactory; } + set + { + _owningObjectFactory = value; + if (!value.IsPrototype(TargetObjectName)) + { + throw new ObjectDefinitionStoreException( + "Cannot use PrototypeTargetSource against a " + + "Singleton object; instances would not be independent."); + } - #region Instrumentation + #region Instrumentation - if (logger.IsEnabled(LogLevel.Debug)) - { - logger.LogDebug(string.Format( - "Getting object with name '{0}' to determine class.", - TargetObjectName)); - } - - #endregion - - _targetType = _owningObjectFactory.GetType(TargetObjectName); - } - } - - #endregion - - #region Methods - - /// - /// Subclasses should use this method to create a new prototype instance. - /// - protected virtual object NewPrototypeInstance() - { - #region Instrumentation - - if (logger.IsEnabled(LogLevel.Debug)) - { - logger.LogDebug(string.Format( - "Creating new target from object '{0}'.", + if (logger.IsEnabled(LogLevel.Debug)) + { + logger.LogDebug(string.Format( + "Getting object with name '{0}' to determine class.", TargetObjectName)); - } + } - #endregion + #endregion - return ObjectFactory.GetObject(TargetObjectName); - } + _targetType = _owningObjectFactory.GetType(TargetObjectName); + } + } - /// - /// Returns the target object. - /// - /// The target object. - /// - /// If unable to obtain the target object. - /// - public abstract object GetTarget(); + #endregion - /// - /// Releases the target object. - /// - /// The target object to release. - public virtual void ReleaseTarget(object target) - { - } + #region Methods - /// - /// Invoked by an - /// after it has set all object properties supplied - /// (and satisfied the - /// - /// and - /// interfaces). - /// - /// - ///

- /// Ensures that the property has been - /// set to a valid value (i.e. is not or a string - /// that consists solely of whitespace). - ///

- ///
- /// - /// In the event of misconfiguration (such as failure to set an essential - /// property) or if initialization fails. - /// - /// - public virtual void AfterPropertiesSet() - { - AssertUtils.ArgumentHasText( - TargetObjectName, "TargetObjectName", - "The 'TargetObjectName' property must have a value."); - } + /// + /// Subclasses should use this method to create a new prototype instance. + /// + protected virtual object NewPrototypeInstance() + { + #region Instrumentation - #endregion - - #region Fields - - /// - /// Returns a textual representation of this target source instance. - /// This implementation returns - /// - public override string ToString() + if (logger.IsEnabled(LogLevel.Debug)) { - return GetDescription(); + logger.LogDebug(string.Format( + "Creating new target from object '{0}'.", + TargetObjectName)); } - /// - /// Returns a textual representation of this target source instance - /// - protected virtual string GetDescription() - { - return string.Format("[{0}:{1}]", this.GetType().Name, this.TargetObjectName); - } + #endregion - /// - /// The shared instance for this class (and derived classes). - /// - protected readonly ILogger logger = LogManager.GetLogger(); + return ObjectFactory.GetObject(TargetObjectName); + } - private String _targetObjectName; - private IObjectFactory _owningObjectFactory; - private Type _targetType; + /// + /// Returns the target object. + /// + /// The target object. + /// + /// If unable to obtain the target object. + /// + public abstract object GetTarget(); - #endregion - } + /// + /// Releases the target object. + /// + /// The target object to release. + public virtual void ReleaseTarget(object target) + { + } + + /// + /// Invoked by an + /// after it has set all object properties supplied + /// (and satisfied the + /// + /// and + /// interfaces). + /// + /// + ///

+ /// Ensures that the property has been + /// set to a valid value (i.e. is not or a string + /// that consists solely of whitespace). + ///

+ ///
+ /// + /// In the event of misconfiguration (such as failure to set an essential + /// property) or if initialization fails. + /// + /// + public virtual void AfterPropertiesSet() + { + AssertUtils.ArgumentHasText( + TargetObjectName, "TargetObjectName", + "The 'TargetObjectName' property must have a value."); + } + + #endregion + + #region Fields + + /// + /// Returns a textual representation of this target source instance. + /// This implementation returns + /// + public override string ToString() + { + return GetDescription(); + } + + /// + /// Returns a textual representation of this target source instance + /// + protected virtual string GetDescription() + { + return string.Format("[{0}:{1}]", this.GetType().Name, this.TargetObjectName); + } + + /// + /// The shared instance for this class (and derived classes). + /// + protected readonly ILogger logger = LogManager.GetLogger(); + + private String _targetObjectName; + private IObjectFactory _owningObjectFactory; + private Type _targetType; + + #endregion } diff --git a/src/Spring/Spring.Aop/Aop/Target/EmptyTargetSource.cs b/src/Spring/Spring.Aop/Aop/Target/EmptyTargetSource.cs index 87b81c47..af5af6a2 100644 --- a/src/Spring/Spring.Aop/Aop/Target/EmptyTargetSource.cs +++ b/src/Spring/Spring.Aop/Aop/Target/EmptyTargetSource.cs @@ -25,122 +25,121 @@ using System.Security.Permissions; #endregion -namespace Spring.Aop.Target +namespace Spring.Aop.Target; + +/// +/// The to be used +/// when there is no target object, and behavior is supplied by the +/// advisors. +/// +/// +///

+/// This class is exposed as a singleton. +///

+///
+/// Rod Johnson +/// Aleksandar Seovic (.NET) +[Serializable] +public sealed class EmptyTargetSource : ITargetSource, ISerializable { - /// - /// The to be used - /// when there is no target object, and behavior is supplied by the - /// advisors. - /// - /// - ///

- /// This class is exposed as a singleton. - ///

- ///
- /// Rod Johnson - /// Aleksandar Seovic (.NET) - [Serializable] - public sealed class EmptyTargetSource : ITargetSource, ISerializable - { - /// - /// The to be used - /// when there is no target object, and behavior is supplied by the - /// advisors. - /// - public static readonly ITargetSource Empty = new EmptyTargetSource(); + /// + /// The to be used + /// when there is no target object, and behavior is supplied by the + /// advisors. + /// + public static readonly ITargetSource Empty = new EmptyTargetSource(); - private object _dummyTarget = new object(); + private object _dummyTarget = new object(); - /// - /// Creates a new instance of the - /// class. - /// - /// - ///

- /// This is a utility class, and as such has no publicly visible constructors. - ///

- ///
- private EmptyTargetSource() - { - } + /// + /// Creates a new instance of the + /// class. + /// + /// + ///

+ /// This is a utility class, and as such has no publicly visible constructors. + ///

+ ///
+ private EmptyTargetSource() + { + } - /// - /// The of the target object. - /// - public Type TargetType - { - get { return typeof(object); } - } + /// + /// The of the target object. + /// + public Type TargetType + { + get { return typeof(object); } + } - /// - /// Is the target source static? - /// - /// - ///

- /// The - /// instance is static, and this always returns . - ///

- ///
- /// - /// if the target source is static. - /// - public bool IsStatic - { - get { return true; } - } + /// + /// Is the target source static? + /// + /// + ///

+ /// The + /// instance is static, and this always returns . + ///

+ ///
+ /// + /// if the target source is static. + /// + public bool IsStatic + { + get { return true; } + } - /// - /// Returns the target object. - /// - /// The target object. - /// - /// If unable to obtain the target object. - /// - public object GetTarget() - { - return _dummyTarget; - } + /// + /// Returns the target object. + /// + /// The target object. + /// + /// If unable to obtain the target object. + /// + public object GetTarget() + { + return _dummyTarget; + } - /// - /// Releases the target object. - /// - /// - /// - /// This is a no-op operation in this implementation. - /// - /// - /// The target object to release. - public void ReleaseTarget(object target) - { - } + /// + /// Releases the target object. + /// + /// + /// + /// This is a no-op operation in this implementation. + /// + /// + /// The target object to release. + public void ReleaseTarget(object target) + { + } - /// - /// A that represents the current - /// . - /// - /// - /// A that represents the current - /// . - /// - public override string ToString() - { - return "EmptyTargetSource: no target"; - } + /// + /// A that represents the current + /// . + /// + /// + /// A that represents the current + /// . + /// + public override string ToString() + { + return "EmptyTargetSource: no target"; + } - /// - [SecurityPermission(SecurityAction.Demand, SerializationFormatter=true)] - public void GetObjectData(SerializationInfo info, StreamingContext context) - { - info.SetType(typeof (EmptyTargetSourceObjectReference)); - } + /// + [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)] + public void GetObjectData(SerializationInfo info, StreamingContext context) + { + info.SetType(typeof(EmptyTargetSourceObjectReference)); + } - [Serializable] - private sealed class EmptyTargetSourceObjectReference : IObjectReference - { - public object GetRealObject(StreamingContext context) - { - return EmptyTargetSource.Empty; - } - } - } -} + [Serializable] + private sealed class EmptyTargetSourceObjectReference : IObjectReference + { + public object GetRealObject(StreamingContext context) + { + return EmptyTargetSource.Empty; + } + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Aop/Aop/Target/HotSwappableTargetSource.cs b/src/Spring/Spring.Aop/Aop/Target/HotSwappableTargetSource.cs index 25a659bf..1963b08e 100644 --- a/src/Spring/Spring.Aop/Aop/Target/HotSwappableTargetSource.cs +++ b/src/Spring/Spring.Aop/Aop/Target/HotSwappableTargetSource.cs @@ -24,153 +24,153 @@ using Spring.Util; #endregion -namespace Spring.Aop.Target +namespace Spring.Aop.Target; + +/// +/// implementation that caches a +/// local target object, but allows the target to be swapped while the +/// application is running +/// +/// +///

+/// If configuring an object of this class in a Spring IoC container, +/// use constructor injection to supply the intial target. +///

+///
+/// Rod Johnson +/// Aleksandar Seovic (.Net) +[Serializable] +public class HotSwappableTargetSource : ITargetSource { - /// - /// implementation that caches a - /// local target object, but allows the target to be swapped while the - /// application is running - /// - /// - ///

- /// If configuring an object of this class in a Spring IoC container, - /// use constructor injection to supply the intial target. - ///

- ///
- /// Rod Johnson - /// Aleksandar Seovic (.Net) - [Serializable] - public class HotSwappableTargetSource : ITargetSource - { - private object _target; + private object _target; - /// - /// Creates a new instance of the - /// with the initial target. - /// - /// - /// The initial target. May be . - /// - public HotSwappableTargetSource(object initialTarget) - { - _target = initialTarget; - } + /// + /// Creates a new instance of the + /// with the initial target. + /// + /// + /// The initial target. May be . + /// + public HotSwappableTargetSource(object initialTarget) + { + _target = initialTarget; + } - /// - /// The of the target object. - /// - /// - ///

- /// Can return . - ///

- ///
- public virtual Type TargetType - { - get - { - lock(this) - { - return _target.GetType(); - } - } - } + /// + /// The of the target object. + /// + /// + ///

+ /// Can return . + ///

+ ///
+ public virtual Type TargetType + { + get + { + lock (this) + { + return _target.GetType(); + } + } + } - /// - /// Is the target source static? - /// - /// - /// if the target source is static. - /// - public virtual bool IsStatic - { - get { return false; } - } + /// + /// Is the target source static? + /// + /// + /// if the target source is static. + /// + public virtual bool IsStatic + { + get { return false; } + } - /// - /// Returns the target object. - /// - /// The target object. - /// - /// If unable to obtain the target object. - /// - public object GetTarget() - { - // synchronization around something that takes so little time is fine... - lock (this) - { - return _target; - } - } + /// + /// Returns the target object. + /// + /// The target object. + /// + /// If unable to obtain the target object. + /// + public object GetTarget() + { + // synchronization around something that takes so little time is fine... + lock (this) + { + return _target; + } + } - /// - /// Releases the target object. - /// - /// - ///

- /// No-op implementation. - ///

- ///
- /// The target object to release. - public virtual void ReleaseTarget(Object target) - { - } + /// + /// Releases the target object. + /// + /// + ///

+ /// No-op implementation. + ///

+ ///
+ /// The target object to release. + public virtual void ReleaseTarget(Object target) + { + } - /// - /// Swap the target, returning the old target. - /// - /// The new target. - /// The old target. - /// - /// If the new target is . - /// - public virtual object Swap(object newTarget) - { - AssertUtils.ArgumentNotNull(newTarget, "newTarget", "Cannot swap to null."); - lock (this) - { - // TODO: type checks - object old = _target; - _target = newTarget; - return old; - } - } + /// + /// Swap the target, returning the old target. + /// + /// The new target. + /// The old target. + /// + /// If the new target is . + /// + public virtual object Swap(object newTarget) + { + AssertUtils.ArgumentNotNull(newTarget, "newTarget", "Cannot swap to null."); + lock (this) + { + // TODO: type checks + object old = _target; + _target = newTarget; + return old; + } + } - /// - /// Determines whether the specified - /// is equal to the current . - /// - /// - ///

- /// Two invoker interceptors are equal if they have the same target or - /// if the targets are equal. - ///

- ///
- /// The target source to compare with. - /// - /// if this instance is equal to the - /// specified . - /// - public override bool Equals(object other) - { - HotSwappableTargetSource otherTargetSource = other as HotSwappableTargetSource; - if (other == null) - { - return false; - } - return otherTargetSource._target == _target || otherTargetSource._target.Equals(_target); - } + /// + /// Determines whether the specified + /// is equal to the current . + /// + /// + ///

+ /// Two invoker interceptors are equal if they have the same target or + /// if the targets are equal. + ///

+ ///
+ /// The target source to compare with. + /// + /// if this instance is equal to the + /// specified . + /// + public override bool Equals(object other) + { + HotSwappableTargetSource otherTargetSource = other as HotSwappableTargetSource; + if (other == null) + { + return false; + } - /// - /// Serves as a hash function for a particular type, suitable for use - /// in hashing algorithms and data structures like a hash table. - /// - /// - /// A hash code for the current . - /// - public override int GetHashCode() - { - return base.GetHashCode() + 13 * - (_target == null ? 0 : _target.GetHashCode()); - } - } + return otherTargetSource._target == _target || otherTargetSource._target.Equals(_target); + } + + /// + /// Serves as a hash function for a particular type, suitable for use + /// in hashing algorithms and data structures like a hash table. + /// + /// + /// A hash code for the current . + /// + public override int GetHashCode() + { + return base.GetHashCode() + 13 * + (_target == null ? 0 : _target.GetHashCode()); + } } diff --git a/src/Spring/Spring.Aop/Aop/Target/IThreadLocalTargetSourceStats.cs b/src/Spring/Spring.Aop/Aop/Target/IThreadLocalTargetSourceStats.cs index ef4ae645..ba3b12f6 100644 --- a/src/Spring/Spring.Aop/Aop/Target/IThreadLocalTargetSourceStats.cs +++ b/src/Spring/Spring.Aop/Aop/Target/IThreadLocalTargetSourceStats.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -24,39 +24,38 @@ using AopAlliance.Intercept; #endregion -namespace Spring.Aop.Target +namespace Spring.Aop.Target; + +/// +/// Statistics for a thread local . +/// +/// Rod Johnson +/// Federico Spinazzi (.NET) +public interface IThreadLocalTargetSourceStats { - /// - /// Statistics for a thread local . - /// - /// Rod Johnson - /// Federico Spinazzi (.NET) - public interface IThreadLocalTargetSourceStats - { - /// - /// Gets the number of invocations of the - /// and - /// methods. - /// - /// - /// The number of invocations of the - /// and - /// methods. - /// - int Invocations { get; } + /// + /// Gets the number of invocations of the + /// and + /// methods. + /// + /// + /// The number of invocations of the + /// and + /// methods. + /// + int Invocations { get; } - /// - /// Gets the number of hits that were satisfied by a thread bound object. - /// - /// - /// The number of hits that were satisfied by a thread bound object. - /// - int Hits { get; } + /// + /// Gets the number of hits that were satisfied by a thread bound object. + /// + /// + /// The number of hits that were satisfied by a thread bound object. + /// + int Hits { get; } - /// - /// Gets the number of thread bound objects created. - /// - /// The number of thread bound objects created. - int Objects { get; } - } -} \ No newline at end of file + /// + /// Gets the number of thread bound objects created. + /// + /// The number of thread bound objects created. + int Objects { get; } +} diff --git a/src/Spring/Spring.Aop/Aop/Target/PoolingConfig.cs b/src/Spring/Spring.Aop/Aop/Target/PoolingConfig.cs index b9c3d7b8..f2b98b63 100644 --- a/src/Spring/Spring.Aop/Aop/Target/PoolingConfig.cs +++ b/src/Spring/Spring.Aop/Aop/Target/PoolingConfig.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -18,28 +18,27 @@ #endregion -namespace Spring.Aop.Target +namespace Spring.Aop.Target; + +/// +/// Configuration interface for a pooling invoker. +/// +/// Rod Johnson +/// Aleksandar Seovic (.NET) +public interface PoolingConfig { - /// - /// Configuration interface for a pooling invoker. - /// - /// Rod Johnson - /// Aleksandar Seovic (.NET) - public interface PoolingConfig - { - /// - /// The number of active object instances in a pool. - /// - int Active { get; } + /// + /// The number of active object instances in a pool. + /// + int Active { get; } - /// - /// The number of free object instances in a pool. - /// - int Free { get; } + /// + /// The number of free object instances in a pool. + /// + int Free { get; } - /// - /// The maximum number of object instances in a pool. - /// - int MaxSize { get; } - } -} \ No newline at end of file + /// + /// The maximum number of object instances in a pool. + /// + int MaxSize { get; } +} diff --git a/src/Spring/Spring.Aop/Aop/Target/PrototypeTargetSource.cs b/src/Spring/Spring.Aop/Aop/Target/PrototypeTargetSource.cs index 0e3f49de..cc59061a 100644 --- a/src/Spring/Spring.Aop/Aop/Target/PrototypeTargetSource.cs +++ b/src/Spring/Spring.Aop/Aop/Target/PrototypeTargetSource.cs @@ -22,55 +22,54 @@ #endregion -namespace Spring.Aop.Target +namespace Spring.Aop.Target; + +/// +/// implementation that creates a +/// new instance of the target object for each request. +/// +/// +///

+/// Can only be used in an object factory. +///

+///
+/// Rod Johnson +/// Spinazzi Federico (.NET) +public sealed class PrototypeTargetSource : AbstractPrototypeTargetSource { - /// - /// implementation that creates a - /// new instance of the target object for each request. - /// - /// - ///

- /// Can only be used in an object factory. - ///

- ///
- /// Rod Johnson - /// Spinazzi Federico (.NET) - public sealed class PrototypeTargetSource : AbstractPrototypeTargetSource - { - /// - /// Returns the target object. - /// - /// The target object. - /// - /// If unable to obtain the target object. - /// - public override Object GetTarget() - { - return NewPrototypeInstance(); - } + /// + /// Returns the target object. + /// + /// The target object. + /// + /// If unable to obtain the target object. + /// + public override Object GetTarget() + { + return NewPrototypeInstance(); + } - /// - /// Releases the target object. - /// - /// - ///

- /// No-op implementation. - ///

- ///
- /// The target object to release. - public override void ReleaseTarget(object target) - { - } + /// + /// Releases the target object. + /// + /// + ///

+ /// No-op implementation. + ///

+ ///
+ /// The target object to release. + public override void ReleaseTarget(object target) + { + } - /// - /// Is the target source static? - /// - /// - /// because this target source is never static. - /// - public override bool IsStatic - { - get { return false; } - } - } + /// + /// Is the target source static? + /// + /// + /// because this target source is never static. + /// + public override bool IsStatic + { + get { return false; } + } } diff --git a/src/Spring/Spring.Aop/Aop/Target/SimplePoolTargetSource.cs b/src/Spring/Spring.Aop/Aop/Target/SimplePoolTargetSource.cs index 22b4202c..0dbb6dec 100644 --- a/src/Spring/Spring.Aop/Aop/Target/SimplePoolTargetSource.cs +++ b/src/Spring/Spring.Aop/Aop/Target/SimplePoolTargetSource.cs @@ -1,20 +1,20 @@ #region License /* -* Copyright © 2002-2011 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. -*/ + * Copyright © 2002-2011 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 @@ -27,181 +27,180 @@ using Spring.Pool.Support; #endregion -namespace Spring.Aop.Target +namespace Spring.Aop.Target; + +/// +/// Pooling target source implementation based on the +/// +/// +/// Rod Johnson +/// Federico Spinazzi +[Serializable] +public class SimplePoolTargetSource : AbstractPoolingTargetSource, IPoolableObjectFactory { - /// - /// Pooling target source implementation based on the - /// - /// - /// Rod Johnson - /// Federico Spinazzi - [Serializable] - public class SimplePoolTargetSource : AbstractPoolingTargetSource, IPoolableObjectFactory - { - private IObjectPool objectPool; + private IObjectPool objectPool; - /// - /// Returns the target object (acquired from the pool). - /// - /// - /// The target object (acquired from the pool). - /// - /// - /// If unable to obtain the target object. - /// - public override object GetTarget() - { - return this.objectPool.BorrowObject(); - } + /// + /// Returns the target object (acquired from the pool). + /// + /// + /// The target object (acquired from the pool). + /// + /// + /// If unable to obtain the target object. + /// + public override object GetTarget() + { + return this.objectPool.BorrowObject(); + } - /// - /// Creates the pool. - /// - /// - /// The owning , in - /// case one needs collaborators from it (normally one's own properties - /// are sufficient). - /// - /// - protected override void CreatePool(IObjectFactory factory) - { - #region Instrumentation + /// + /// Creates the pool. + /// + /// + /// The owning , in + /// case one needs collaborators from it (normally one's own properties + /// are sufficient). + /// + /// + protected override void CreatePool(IObjectFactory factory) + { + #region Instrumentation - if(logger.IsEnabled(LogLevel.Debug)) - { - logger.LogDebug("Creating object pool."); - } + if (logger.IsEnabled(LogLevel.Debug)) + { + logger.LogDebug("Creating object pool."); + } - #endregion + #endregion - this.objectPool = CreateObjectPool(); - } + this.objectPool = CreateObjectPool(); + } - /// - /// Creates a new instance of an appropriate - /// implementation. - /// - /// - ///

- /// Subclasses can, of course, override this method if they want to - /// return a different implementation. - ///

- ///
- /// - /// An empty . - /// - protected virtual IObjectPool CreateObjectPool() - { - return new SimplePool(this, MaxSize); - } + /// + /// Creates a new instance of an appropriate + /// implementation. + /// + /// + ///

+ /// Subclasses can, of course, override this method if they want to + /// return a different implementation. + ///

+ ///
+ /// + /// An empty . + /// + protected virtual IObjectPool CreateObjectPool() + { + return new SimplePool(this, MaxSize); + } - /// - /// Releases the target object (returns it to the pool). - /// - /// The target object to release (return to the pool). - /// - /// In the case that the could not be released. - /// - public override void ReleaseTarget(object target) - { - this.objectPool.ReturnObject(target); - } + /// + /// Releases the target object (returns it to the pool). + /// + /// The target object to release (return to the pool). + /// + /// In the case that the could not be released. + /// + public override void ReleaseTarget(object target) + { + this.objectPool.ReturnObject(target); + } - /// - /// The number of active object instances in this pool. - /// - public override int Active - { - get { return this.objectPool.NumActive; } - } + /// + /// The number of active object instances in this pool. + /// + public override int Active + { + get { return this.objectPool.NumActive; } + } - /// - /// The number of free object instances in this pool. - /// - public override int Free - { - get { return this.objectPool.NumIdle; } - } + /// + /// The number of free object instances in this pool. + /// + public override int Free + { + get { return this.objectPool.NumIdle; } + } - /// - /// Performs application-defined tasks associated with freeing, releasing, or - /// resetting unmanaged resources. - /// - /// - ///

- /// Disposes of the pool. - ///

- ///
- public override void Dispose() - { - #region Instrumentation + /// + /// Performs application-defined tasks associated with freeing, releasing, or + /// resetting unmanaged resources. + /// + /// + ///

+ /// Disposes of the pool. + ///

+ ///
+ public override void Dispose() + { + #region Instrumentation - if(logger.IsEnabled(LogLevel.Debug)) - { - logger.LogDebug("Closing pool..."); - } + if (logger.IsEnabled(LogLevel.Debug)) + { + logger.LogDebug("Closing pool..."); + } - #endregion + #endregion - this.objectPool.Close(); - } + this.objectPool.Close(); + } - /// - /// Creates an instance that can be returned by the pool. - /// - /// - /// An instance that can be returned by the pool. - /// - /// - public virtual Object MakeObject() - { - return NewPrototypeInstance(); - } + /// + /// Creates an instance that can be returned by the pool. + /// + /// + /// An instance that can be returned by the pool. + /// + /// + public virtual Object MakeObject() + { + return NewPrototypeInstance(); + } - /// - /// Destroys an instance no longer needed by the pool. - /// - /// The instance to be destroyed. - /// - public virtual void DestroyObject(object obj) - { - if (obj is IDisposable) - { - ((IDisposable) obj).Dispose(); - } - } + /// + /// Destroys an instance no longer needed by the pool. + /// + /// The instance to be destroyed. + /// + public virtual void DestroyObject(object obj) + { + if (obj is IDisposable) + { + ((IDisposable) obj).Dispose(); + } + } - /// - /// Ensures that the instance is safe to be returned by the pool. - /// Returns false if this object should be destroyed. - /// - /// The instance to validate. - /// - /// if this object is not valid and - /// should be dropped from the pool, otherwise . - /// - /// - public virtual bool ValidateObject(object obj) - { - return true; - } + /// + /// Ensures that the instance is safe to be returned by the pool. + /// Returns false if this object should be destroyed. + /// + /// The instance to validate. + /// + /// if this object is not valid and + /// should be dropped from the pool, otherwise . + /// + /// + public virtual bool ValidateObject(object obj) + { + return true; + } - /// - /// Reinitialize an instance to be returned by the pool. - /// - /// The instance to be activated. - /// - public virtual void ActivateObject(object obj) - { - } + /// + /// Reinitialize an instance to be returned by the pool. + /// + /// The instance to be activated. + /// + public virtual void ActivateObject(object obj) + { + } - /// - /// Passivates the object. - /// - /// The instance returned to the pool. - /// - public virtual void PassivateObject(object obj) - { - } - } + /// + /// Passivates the object. + /// + /// The instance returned to the pool. + /// + public virtual void PassivateObject(object obj) + { + } } diff --git a/src/Spring/Spring.Aop/Aop/Target/SingletonTargetSource.cs b/src/Spring/Spring.Aop/Aop/Target/SingletonTargetSource.cs index e8f3a29b..b337fa08 100644 --- a/src/Spring/Spring.Aop/Aop/Target/SingletonTargetSource.cs +++ b/src/Spring/Spring.Aop/Aop/Target/SingletonTargetSource.cs @@ -15,169 +15,169 @@ */ using System.Runtime.Serialization; - using Spring.Util; -namespace Spring.Aop.Target +namespace Spring.Aop.Target; + +/// +/// implementation that holds a local +/// object. +/// +/// +///

+/// This is the default implementation of the +/// interface used by the AOP +/// framework. There should be no need to create objects of this class in +/// application code. +///

+///
+/// Rod Johnson +/// Aleksandar Seovic (.NET) +[Serializable] +public sealed class SingletonTargetSource : ITargetSource, ISerializable { - /// - /// implementation that holds a local - /// object. - /// - /// - ///

- /// This is the default implementation of the - /// interface used by the AOP - /// framework. There should be no need to create objects of this class in - /// application code. - ///

- ///
- /// Rod Johnson - /// Aleksandar Seovic (.NET) - [Serializable] - public sealed class SingletonTargetSource : ITargetSource, ISerializable - { - private readonly object target; - private readonly Type targetType; + private readonly object target; + private readonly Type targetType; - /// - /// Creates a new instance of the - /// - /// for the specified target object. - /// - /// The target object to expose. - /// - /// If the supplied is - /// . - /// - public SingletonTargetSource(object target) - :this(target, target != null ? target.GetType() : null) - {} + /// + /// Creates a new instance of the + /// + /// for the specified target object. + /// + /// The target object to expose. + /// + /// If the supplied is + /// . + /// + public SingletonTargetSource(object target) + : this(target, target != null ? target.GetType() : null) + { + } - /// - /// Creates a new instance of the - /// - /// for the specified target object. - /// - /// The target object to expose. - /// The type of to expose. - /// - /// If the supplied is - /// . - /// - public SingletonTargetSource(object target, Type targetType) - { - AssertUtils.ArgumentNotNull(target, "target"); - AssertUtils.ArgumentNotNull(targetType, "targetType"); - this.target = target; - this.targetType = targetType; - } + /// + /// Creates a new instance of the + /// + /// for the specified target object. + /// + /// The target object to expose. + /// The type of to expose. + /// + /// If the supplied is + /// . + /// + public SingletonTargetSource(object target, Type targetType) + { + AssertUtils.ArgumentNotNull(target, "target"); + AssertUtils.ArgumentNotNull(targetType, "targetType"); + this.target = target; + this.targetType = targetType; + } - /// - private SingletonTargetSource(SerializationInfo info, StreamingContext context) - { - target = info.GetValue("Target", typeof(object)); - var type = info.GetString("TargetTypeName"); - targetType = type != null ? Type.GetType(type) : null; - } + /// + private SingletonTargetSource(SerializationInfo info, StreamingContext context) + { + target = info.GetValue("Target", typeof(object)); + var type = info.GetString("TargetTypeName"); + targetType = type != null ? Type.GetType(type) : null; + } - /// - /// The of the target object. - /// - public Type TargetType - { - get { return targetType; } - } + /// + /// The of the target object. + /// + public Type TargetType + { + get { return targetType; } + } - /// - /// Is the target source static? - /// - /// - /// because this target source is always static. - /// - public bool IsStatic - { - get { return true; } - } + /// + /// Is the target source static? + /// + /// + /// because this target source is always static. + /// + public bool IsStatic + { + get { return true; } + } - /// - /// Returns the target object. - /// - /// The target object. - /// - /// If unable to obtain the target object. - /// - public object GetTarget() - { - return target; - } + /// + /// Returns the target object. + /// + /// The target object. + /// + /// If unable to obtain the target object. + /// + public object GetTarget() + { + return target; + } - /// - /// Releases the target object. - /// - /// - ///

- /// No-op implementation. - ///

- ///
- /// The target object to release. - public void ReleaseTarget(object target) - { + /// + /// Releases the target object. + /// + /// + ///

+ /// No-op implementation. + ///

+ ///
+ /// The target object to release. + public void ReleaseTarget(object target) + { + } - } + /// + public void GetObjectData(SerializationInfo info, StreamingContext context) + { + info.AddValue("TargetTypeName", targetType?.AssemblyQualifiedName); + info.AddValue("Target", target); + } - /// - public void GetObjectData(SerializationInfo info, StreamingContext context) - { - info.AddValue("TargetTypeName", targetType?.AssemblyQualifiedName); - info.AddValue("Target", target); - } + /// + /// Returns a stringified representation of this target source. + /// + /// + /// A stringified representation of this target source. + /// + public override string ToString() + { + return "Singleton target source (not dynamic): target=[" + target + "]"; + } - /// - /// Returns a stringified representation of this target source. - /// - /// - /// A stringified representation of this target source. - /// - public override string ToString() - { - return "Singleton target source (not dynamic): target=[" + target + "]"; - } + /// + /// Determines whether the specified + /// is equal to the current . + /// + /// The target source to compare with. + /// + /// if this instance is equal to the + /// specified . + /// + public override bool Equals(object other) + { + if (this == other) + { + return true; + } - /// - /// Determines whether the specified - /// is equal to the current . - /// - /// The target source to compare with. - /// - /// if this instance is equal to the - /// specified . - /// - public override bool Equals(object other) - { - if (this == other) - { - return true; - } - SingletonTargetSource b = other as SingletonTargetSource; - if (b == null) - { - return false; - } - return target.Equals(b.target); - } + SingletonTargetSource b = other as SingletonTargetSource; + if (b == null) + { + return false; + } - /// - /// Serves as a hash function for a particular type, suitable for use - /// in hashing algorithms and data structures like a hash table. - /// - /// - /// A hash code for the current . - /// - public override int GetHashCode() - { - return base.GetHashCode() + 13 * - (target == null ? 0 : target.GetHashCode()); - } - } + return target.Equals(b.target); + } + + /// + /// Serves as a hash function for a particular type, suitable for use + /// in hashing algorithms and data structures like a hash table. + /// + /// + /// A hash code for the current . + /// + public override int GetHashCode() + { + return base.GetHashCode() + 13 * + (target == null ? 0 : target.GetHashCode()); + } } diff --git a/src/Spring/Spring.Aop/Aop/Target/ThreadLocalTargetSource.cs b/src/Spring/Spring.Aop/Aop/Target/ThreadLocalTargetSource.cs index f5ca120d..540aa784 100644 --- a/src/Spring/Spring.Aop/Aop/Target/ThreadLocalTargetSource.cs +++ b/src/Spring/Spring.Aop/Aop/Target/ThreadLocalTargetSource.cs @@ -28,215 +28,217 @@ using Spring.Util; #endregion -namespace Spring.Aop.Target +namespace Spring.Aop.Target; + +/// +/// implementation that uses a +/// threading model in which every thread has its own copy of the target. +/// +/// +///

+/// Alternative to an object pool. +///

+///

+/// Application code is written as to a normal pool; callers can't assume +/// they will be dealing with the same instance in invocations in different +/// threads. However, state can be relied on during the operations of a +/// single thread: for example, if one caller makes repeated calls on the +/// AOP proxy. +///

+///

+/// This class act both as an introduction and as an interceptor, so it +/// should be added twice, once as an introduction and once as an +/// interceptor. +///

+///
+/// Rod Johnson +/// Federico Spinazzi (.NET) +public sealed class ThreadLocalTargetSource : AbstractPrototypeTargetSource, + IThreadLocalTargetSourceStats, IDisposable, IMethodInterceptor { - /// - /// implementation that uses a - /// threading model in which every thread has its own copy of the target. - /// - /// - ///

- /// Alternative to an object pool. - ///

- ///

- /// Application code is written as to a normal pool; callers can't assume - /// they will be dealing with the same instance in invocations in different - /// threads. However, state can be relied on during the operations of a - /// single thread: for example, if one caller makes repeated calls on the - /// AOP proxy. - ///

- ///

- /// This class act both as an introduction and as an interceptor, so it - /// should be added twice, once as an introduction and once as an - /// interceptor. - ///

- ///
- /// Rod Johnson - /// Federico Spinazzi (.NET) - public sealed class ThreadLocalTargetSource : AbstractPrototypeTargetSource, - IThreadLocalTargetSourceStats, IDisposable, IMethodInterceptor - { - #region Fields + #region Fields - /// - /// ThreadLocal holding the target associated with the current thread. - /// - /// - ///

- /// Unlike most thread local storage which is static, this variable is - /// meant to be per thread per instance of this class. - ///

- ///
- private LocalDataStoreSlot _targetInThread = Thread.AllocateDataSlot(); + /// + /// ThreadLocal holding the target associated with the current thread. + /// + /// + ///

+ /// Unlike most thread local storage which is static, this variable is + /// meant to be per thread per instance of this class. + ///

+ ///
+ private LocalDataStoreSlot _targetInThread = Thread.AllocateDataSlot(); - /// - /// The set of managed targets, enabling us to keep track of the - /// targets we've created. - /// - private ISet _targetSet = new ListSet(); + /// + /// The set of managed targets, enabling us to keep track of the + /// targets we've created. + /// + private ISet _targetSet = new ListSet(); - private int _invocations; - private int _hits; + private int _invocations; + private int _hits; - #endregion + #endregion - #region Properties + #region Properties - /// - /// Gets the number of invocations of the and - /// methods. - /// - /// - /// The number of invocations of the and - /// methods. - /// - public int Invocations - { - get { return _invocations; } - } + /// + /// Gets the number of invocations of the and + /// methods. + /// + /// + /// The number of invocations of the and + /// methods. + /// + public int Invocations + { + get { return _invocations; } + } - /// - /// Gets the number of hits that were satisfied by a thread bound object. - /// - /// - /// The number of hits that were satisfied by a thread bound object. - /// - public int Hits - { - get { return _hits; } - } + /// + /// Gets the number of hits that were satisfied by a thread bound object. + /// + /// + /// The number of hits that were satisfied by a thread bound object. + /// + public int Hits + { + get { return _hits; } + } - /// - /// Gets the number of thread bound objects created. - /// - /// The number of thread bound objects created. - public int Objects - { - get { return _targetSet.Count; } - } + /// + /// Gets the number of thread bound objects created. + /// + /// The number of thread bound objects created. + public int Objects + { + get { return _targetSet.Count; } + } - private object ThreadBoundTarget - { - get { return Thread.GetData(_targetInThread); } - } + private object ThreadBoundTarget + { + get { return Thread.GetData(_targetInThread); } + } - #endregion + #endregion - #region Methods + #region Methods - /// - /// Returns the target object. - /// - /// - ///

- /// Tries to locate the target from thread local storage. If no target - /// is found, a target will be obtained and bound to the thread. - ///

- ///
- /// The target object. - /// - /// If unable to obtain the target object. - /// - /// - public override Object GetTarget() - { - ++_invocations; - object target = ThreadBoundTarget; - if (target == null) - { - #region Instrumentation + /// + /// Returns the target object. + /// + /// + ///

+ /// Tries to locate the target from thread local storage. If no target + /// is found, a target will be obtained and bound to the thread. + ///

+ ///
+ /// The target object. + /// + /// If unable to obtain the target object. + /// + /// + public override Object GetTarget() + { + ++_invocations; + object target = ThreadBoundTarget; + if (target == null) + { + #region Instrumentation - if (logger.IsEnabled(LogLevel.Debug)) - { - logger.LogDebug(string.Format( - "No target for apartment prototype '{0}' " + - "found in thread: creating one and binding it to thread '#{1}'", - TargetObjectName, Thread.CurrentThread.GetHashCode())); - } + if (logger.IsEnabled(LogLevel.Debug)) + { + logger.LogDebug(string.Format( + "No target for apartment prototype '{0}' " + + "found in thread: creating one and binding it to thread '#{1}'", + TargetObjectName, Thread.CurrentThread.GetHashCode())); + } - #endregion + #endregion - target = NewPrototypeInstance(); - Thread.SetData(_targetInThread, target); - _targetSet.Add(target); - } - else - { - ++_hits; - } - return ThreadBoundTarget; - } + target = NewPrototypeInstance(); + Thread.SetData(_targetInThread, target); + _targetSet.Add(target); + } + else + { + ++_hits; + } - /// - /// Return an introduction advisor mixin that allows the AOP proxy to be - /// cast to an reference. - /// - public IIntroductionAdvisor GetStatsMixin() - { - return new DefaultIntroductionAdvisor(this, typeof (IThreadLocalTargetSourceStats)); - } + return ThreadBoundTarget; + } - /// - /// Cleans up this instance's thread storage, and disposes of any - /// targets as necessary. - /// - /// - public void Dispose() - { - #region Instrumentation + /// + /// Return an introduction advisor mixin that allows the AOP proxy to be + /// cast to an reference. + /// + public IIntroductionAdvisor GetStatsMixin() + { + return new DefaultIntroductionAdvisor(this, typeof(IThreadLocalTargetSourceStats)); + } - if (logger.IsEnabled(LogLevel.Debug)) - { - logger.LogDebug("Destroying ThreadLocal bindings"); - } + /// + /// Cleans up this instance's thread storage, and disposes of any + /// targets as necessary. + /// + /// + public void Dispose() + { + #region Instrumentation - #endregion + if (logger.IsEnabled(LogLevel.Debug)) + { + logger.LogDebug("Destroying ThreadLocal bindings"); + } - foreach (object target in _targetSet) - { - if (target is IDisposable) - { - try - { - ((IDisposable) target).Dispose(); - } - catch (Exception ex) - { - #region Instrumentation + #endregion - if (logger.IsEnabled(LogLevel.Warning)) - { - string message = string.Format( - "Thread-bound target of class '{0}' " + - "threw exception from it's IDisposable.Dispose() method.", - target.GetType()); - logger.LogWarning(ex, message); - } + foreach (object target in _targetSet) + { + if (target is IDisposable) + { + try + { + ((IDisposable) target).Dispose(); + } + catch (Exception ex) + { + #region Instrumentation - #endregion - } - } - } - _targetSet.Clear(); - _targetInThread = null; - } + if (logger.IsEnabled(LogLevel.Warning)) + { + string message = string.Format( + "Thread-bound target of class '{0}' " + + "threw exception from it's IDisposable.Dispose() method.", + target.GetType()); + logger.LogWarning(ex, message); + } - /// - /// Increments Invocations and Hits statistics - /// - /// The method invocation joinpoint - /// The result of the call to IJoinpoint.Proceed(), might be intercepted by the interceptor. - /// if the interceptors or the target-object throws an exception. - public object Invoke(IMethodInvocation invocation) - { - if (ReflectionUtils.MethodIsOnOneOfTheseInterfaces( - invocation.Method, new Type[] {typeof (IThreadLocalTargetSourceStats)})) - { - return invocation.Method.Invoke(this, invocation.Arguments); - } - return invocation.Method.Invoke(GetTarget(), invocation.Arguments); - } + #endregion + } + } + } - #endregion - } + _targetSet.Clear(); + _targetInThread = null; + } + + /// + /// Increments Invocations and Hits statistics + /// + /// The method invocation joinpoint + /// The result of the call to IJoinpoint.Proceed(), might be intercepted by the interceptor. + /// if the interceptors or the target-object throws an exception. + public object Invoke(IMethodInvocation invocation) + { + if (ReflectionUtils.MethodIsOnOneOfTheseInterfaces( + invocation.Method, new Type[] { typeof(IThreadLocalTargetSourceStats) })) + { + return invocation.Method.Invoke(this, invocation.Arguments); + } + + return invocation.Method.Invoke(GetTarget(), invocation.Arguments); + } + + #endregion } diff --git a/src/Spring/Spring.Aop/Aop/TrueMethodMatcher.cs b/src/Spring/Spring.Aop/Aop/TrueMethodMatcher.cs index b5b00530..fc857559 100644 --- a/src/Spring/Spring.Aop/Aop/TrueMethodMatcher.cs +++ b/src/Spring/Spring.Aop/Aop/TrueMethodMatcher.cs @@ -26,117 +26,116 @@ using System.Security.Permissions; #endregion -namespace Spring.Aop +namespace Spring.Aop; + +/// +/// Canonical that matches +/// all methods. +/// +/// Rod Johnson +/// Aleksandar Seovic (.NET) +[Serializable] +public sealed class TrueMethodMatcher : IMethodMatcher, ISerializable { - /// - /// Canonical that matches - /// all methods. - /// - /// Rod Johnson - /// Aleksandar Seovic (.NET) - [Serializable] - public sealed class TrueMethodMatcher : IMethodMatcher, ISerializable - { - /// - /// Canonical instance that matches all methods. - /// - /// - ///

- /// It is not dynamic. - ///

- ///
- public static readonly IMethodMatcher True = new TrueMethodMatcher(); + /// + /// Canonical instance that matches all methods. + /// + /// + ///

+ /// It is not dynamic. + ///

+ ///
+ public static readonly IMethodMatcher True = new TrueMethodMatcher(); - /// - /// Creates a new instance of the - /// class. - /// - /// - ///

- /// This is a utility class, and as such has no publicly visible - /// constructors. - ///

- ///
- private TrueMethodMatcher() - { - } + /// + /// Creates a new instance of the + /// class. + /// + /// + ///

+ /// This is a utility class, and as such has no publicly visible + /// constructors. + ///

+ ///
+ private TrueMethodMatcher() + { + } - /// - /// Is this dynamic? - /// - /// - /// if this - /// is dynamic. - /// - /// - public bool IsRuntime - { - get { return false; } - } + /// + /// Is this dynamic? + /// + /// + /// if this + /// is dynamic. + /// + /// + public bool IsRuntime + { + get { return false; } + } - /// - /// Does the supplied satisfy this matcher? - /// Perform static checking. If this returns false, or if the isRuntime() method - /// returns false, no runtime check will be made. - /// - /// The candidate method. - /// - /// The target class (may be , in which case the - /// candidate class must be taken to be the 's - /// declaring class). - /// - /// - /// if this this method matches statically. - /// - /// - public bool Matches(MethodInfo method, Type targetType) - { - return true; - } + /// + /// Does the supplied satisfy this matcher? + /// Perform static checking. If this returns false, or if the isRuntime() method + /// returns false, no runtime check will be made. + /// + /// The candidate method. + /// + /// The target class (may be , in which case the + /// candidate class must be taken to be the 's + /// declaring class). + /// + /// + /// if this this method matches statically. + /// + /// + public bool Matches(MethodInfo method, Type targetType) + { + return true; + } - /// - /// Is there a runtime (dynamic) match for the supplied - /// ? - /// - /// The candidate method. - /// The target class. - /// The arguments to the method - /// - /// if there is a runtime match. - /// - public bool Matches(MethodInfo method, Type targetType, object[] args) - { - // should never be invoked if IsRuntime is false - return true; - } + /// + /// Is there a runtime (dynamic) match for the supplied + /// ? + /// + /// The candidate method. + /// The target class. + /// The arguments to the method + /// + /// if there is a runtime match. + /// + public bool Matches(MethodInfo method, Type targetType, object[] args) + { + // should never be invoked if IsRuntime is false + return true; + } - /// - /// A that represents the current - /// . - /// - /// - /// A that represents the current - /// . - /// - public override string ToString() - { - return "TrueMethodMatcher.True"; - } + /// + /// A that represents the current + /// . + /// + /// + /// A that represents the current + /// . + /// + public override string ToString() + { + return "TrueMethodMatcher.True"; + } - /// - [SecurityPermission (SecurityAction.Demand,SerializationFormatter=true)] - public void GetObjectData(SerializationInfo info, StreamingContext context) - { - info.SetType(typeof (TrueMethodMatcherObjectReference)); - } + /// + [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)] + public void GetObjectData(SerializationInfo info, StreamingContext context) + { + info.SetType(typeof(TrueMethodMatcherObjectReference)); + } - [Serializable] - private sealed class TrueMethodMatcherObjectReference : IObjectReference - { - public object GetRealObject(StreamingContext context) - { - return TrueMethodMatcher.True; - } - } - } + [Serializable] + private sealed class TrueMethodMatcherObjectReference : IObjectReference + { + public object GetRealObject(StreamingContext context) + { + return TrueMethodMatcher.True; + } + } } diff --git a/src/Spring/Spring.Aop/Aop/TruePointcut.cs b/src/Spring/Spring.Aop/Aop/TruePointcut.cs index cf439ca3..1094d917 100644 --- a/src/Spring/Spring.Aop/Aop/TruePointcut.cs +++ b/src/Spring/Spring.Aop/Aop/TruePointcut.cs @@ -25,85 +25,84 @@ using System.Security.Permissions; #endregion -namespace Spring.Aop +namespace Spring.Aop; + +/// +/// Canonical instance that matches +/// everything. +/// +/// Rod Johnson +/// Aleksandar Seovic (.NET) +[Serializable] +public sealed class TruePointcut : IPointcut, ISerializable { - /// - /// Canonical instance that matches - /// everything. - /// - /// Rod Johnson - /// Aleksandar Seovic (.NET) - [Serializable] - public sealed class TruePointcut : IPointcut, ISerializable - { - /// - /// Canonical instance that matches everything. - /// - public static readonly IPointcut True = new TruePointcut(); + /// + /// Canonical instance that matches everything. + /// + public static readonly IPointcut True = new TruePointcut(); - /// - /// Creates a new instance of the - /// class. - /// - /// - ///

- /// This is a utility class, and as such has no publicly - /// visible constructors. - ///

- ///
- private TruePointcut() - { - } + /// + /// Creates a new instance of the + /// class. + /// + /// + ///

+ /// This is a utility class, and as such has no publicly + /// visible constructors. + ///

+ ///
+ private TruePointcut() + { + } - /// - /// The for this pointcut. - /// - /// - /// The current . - /// - public ITypeFilter TypeFilter - { - get { return Aop.TrueTypeFilter.True; } - } + /// + /// The for this pointcut. + /// + /// + /// The current . + /// + public ITypeFilter TypeFilter + { + get { return Aop.TrueTypeFilter.True; } + } - /// - /// The for this pointcut. - /// - /// - /// The current . - /// - public IMethodMatcher MethodMatcher - { - get { return TrueMethodMatcher.True; } - } + /// + /// The for this pointcut. + /// + /// + /// The current . + /// + public IMethodMatcher MethodMatcher + { + get { return TrueMethodMatcher.True; } + } - /// - /// A that represents the current - /// . - /// - /// - /// A that represents the current - /// . - /// - public override string ToString() - { - return "TruePointcut.TRUE"; - } + /// + /// A that represents the current + /// . + /// + /// + /// A that represents the current + /// . + /// + public override string ToString() + { + return "TruePointcut.TRUE"; + } - /// - [SecurityPermission (SecurityAction.Demand,SerializationFormatter=true)] - public void GetObjectData(SerializationInfo info, StreamingContext context) - { - info.SetType(typeof (TruePointcutObjectReference)); - } + /// + [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)] + public void GetObjectData(SerializationInfo info, StreamingContext context) + { + info.SetType(typeof(TruePointcutObjectReference)); + } - [Serializable] - private sealed class TruePointcutObjectReference : IObjectReference - { - public object GetRealObject(StreamingContext context) - { - return TruePointcut.True; - } - } - } + [Serializable] + private sealed class TruePointcutObjectReference : IObjectReference + { + public object GetRealObject(StreamingContext context) + { + return TruePointcut.True; + } + } } diff --git a/src/Spring/Spring.Aop/Aop/TrueTypeFilter.cs b/src/Spring/Spring.Aop/Aop/TrueTypeFilter.cs index 8539a134..49a9a1ac 100644 --- a/src/Spring/Spring.Aop/Aop/TrueTypeFilter.cs +++ b/src/Spring/Spring.Aop/Aop/TrueTypeFilter.cs @@ -25,87 +25,86 @@ using System.Security.Permissions; #endregion -namespace Spring.Aop +namespace Spring.Aop; + +/// +/// Canonical instances. +/// +/// +///

+/// Only one canonical instance is +/// provided out of the box. The +/// matches all classes. +///

+///
+/// Rod Johnson +/// Aleksandar Seovic (.NET) +[Serializable] +public sealed class TrueTypeFilter : ITypeFilter, ISerializable { - /// - /// Canonical instances. - /// - /// - ///

- /// Only one canonical instance is - /// provided out of the box. The - /// matches all classes. - ///

- ///
- /// Rod Johnson - /// Aleksandar Seovic (.NET) - [Serializable] - public sealed class TrueTypeFilter : ITypeFilter, ISerializable - { - /// - /// Canonical instance that - /// matches all classes. - /// - public static readonly ITypeFilter True = new TrueTypeFilter(); + /// + /// Canonical instance that + /// matches all classes. + /// + public static readonly ITypeFilter True = new TrueTypeFilter(); - /// - /// Creates a new instance of the - /// class. - /// - /// - ///

- /// This is a utility class, and as such has no publicly visible - /// constructors. - ///

- ///
- private TrueTypeFilter() - { - } + /// + /// Creates a new instance of the + /// class. + /// + /// + ///

+ /// This is a utility class, and as such has no publicly visible + /// constructors. + ///

+ ///
+ private TrueTypeFilter() + { + } - /// - /// Should the pointcut apply to the supplied - /// ? - /// - /// - /// The candidate . - /// - /// - /// if the advice should apply to the supplied - /// - /// - /// - public bool Matches(Type type) - { - return true; - } + /// + /// Should the pointcut apply to the supplied + /// ? + /// + /// + /// The candidate . + /// + /// + /// if the advice should apply to the supplied + /// + /// + /// + public bool Matches(Type type) + { + return true; + } - /// - /// A that represents the current - /// . - /// - /// - /// A that represents the current - /// . - /// - public override string ToString() - { - return "TrueTypeFilter.True"; - } + /// + /// A that represents the current + /// . + /// + /// + /// A that represents the current + /// . + /// + public override string ToString() + { + return "TrueTypeFilter.True"; + } - /// - [SecurityPermission(SecurityAction.Demand, SerializationFormatter=true)] - public void GetObjectData(SerializationInfo info, StreamingContext context) - { - info.SetType(typeof (TrueTypeFilterObjectReference)); - } + /// + [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)] + public void GetObjectData(SerializationInfo info, StreamingContext context) + { + info.SetType(typeof(TrueTypeFilterObjectReference)); + } - [Serializable] - private sealed class TrueTypeFilterObjectReference : IObjectReference - { - public object GetRealObject(StreamingContext context) - { - return TrueTypeFilter.True; - } - } - } + [Serializable] + private sealed class TrueTypeFilterObjectReference : IObjectReference + { + public object GetRealObject(StreamingContext context) + { + return TrueTypeFilter.True; + } + } } diff --git a/src/Spring/Spring.Aop/AopAlliance/Aop/AspectException.cs b/src/Spring/Spring.Aop/AopAlliance/Aop/AspectException.cs index b399741a..456b1f01 100644 --- a/src/Spring/Spring.Aop/AopAlliance/Aop/AspectException.cs +++ b/src/Spring/Spring.Aop/AopAlliance/Aop/AspectException.cs @@ -2,9 +2,9 @@ /* * All the source code provided by AOP Alliance is Public Domain. - * + * * http://aopalliance.sourceforge.net/ - * + * */ #endregion @@ -15,53 +15,52 @@ using System.Runtime.Serialization; #endregion -namespace AopAlliance.Aop +namespace AopAlliance.Aop; + +/// +/// Superclass for all AOP infrastructure exceptions. +/// +/// Aleksandar Seovic +[Serializable] +public class AspectException : Exception { - /// - /// Superclass for all AOP infrastructure exceptions. - /// - /// Aleksandar Seovic - [Serializable] - public class AspectException : Exception - { - /// - /// Creates a new instance of the - /// class. - /// - public AspectException() - { - } + /// + /// Creates a new instance of the + /// class. + /// + public AspectException() + { + } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - public AspectException(string message) : base(message) - { - } + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + public AspectException(string message) : base(message) + { + } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception that is being wrapped. - /// - public AspectException(string message, Exception innerException) - : base(message, innerException) - { - } + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception that is being wrapped. + /// + public AspectException(string message, Exception innerException) + : base(message, innerException) + { + } - /// - protected AspectException(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } - } + /// + protected AspectException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } } diff --git a/src/Spring/Spring.Aop/AopAlliance/Aop/IAdvice.cs b/src/Spring/Spring.Aop/AopAlliance/Aop/IAdvice.cs index cf37d9eb..a97cd8c0 100644 --- a/src/Spring/Spring.Aop/AopAlliance/Aop/IAdvice.cs +++ b/src/Spring/Spring.Aop/AopAlliance/Aop/IAdvice.cs @@ -2,24 +2,23 @@ /* * All the source code provided by AOP Alliance is Public Domain. - * + * * http://aopalliance.sourceforge.net/ - * + * */ #endregion -namespace AopAlliance.Aop +namespace AopAlliance.Aop; + +/// +/// Tag interface for advice. +/// +/// +///

+/// Implementations can be any type of advice, such as interceptors. +///

+///
+public interface IAdvice { - /// - /// Tag interface for advice. - /// - /// - ///

- /// Implementations can be any type of advice, such as interceptors. - ///

- ///
- public interface IAdvice - { - } -} +} \ No newline at end of file diff --git a/src/Spring/Spring.Aop/AopAlliance/Intercept/IConstructorInterceptor.cs b/src/Spring/Spring.Aop/AopAlliance/Intercept/IConstructorInterceptor.cs index 47321f42..cc3c462e 100644 --- a/src/Spring/Spring.Aop/AopAlliance/Intercept/IConstructorInterceptor.cs +++ b/src/Spring/Spring.Aop/AopAlliance/Intercept/IConstructorInterceptor.cs @@ -2,47 +2,46 @@ /* * All the source code provided by AOP Alliance is Public Domain. - * + * * http://aopalliance.sourceforge.net/ - * + * */ #endregion -namespace AopAlliance.Intercept +namespace AopAlliance.Intercept; + +/// +/// Intercepts the construction of a new object. +/// +/// +///

+/// Such interceptions are nested "on top" of the target. +///

+///
+public interface IConstructorInterceptor : IInterceptor { - /// - /// Intercepts the construction of a new object. - /// - /// - ///

- /// Such interceptions are nested "on top" of the target. - ///

- ///
- public interface IConstructorInterceptor : IInterceptor - { - /// - /// Implement this method to perform extra treatments before and after - /// the consruction of a new object. - /// - /// - ///

- /// Polite implementations would certainly like to invoke - /// . - ///

- ///
- /// - /// The constructor invocation that is being intercepted. - /// - /// - /// The newly created object, which is also the result of the call to - /// , and might be - /// replaced by the interceptor. - /// - /// - /// If any of the interceptors in the chain or the target object itself - /// throws an exception. - /// - object Construct(IConstructorInvocation invocation); - } + /// + /// Implement this method to perform extra treatments before and after + /// the consruction of a new object. + /// + /// + ///

+ /// Polite implementations would certainly like to invoke + /// . + ///

+ ///
+ /// + /// The constructor invocation that is being intercepted. + /// + /// + /// The newly created object, which is also the result of the call to + /// , and might be + /// replaced by the interceptor. + /// + /// + /// If any of the interceptors in the chain or the target object itself + /// throws an exception. + /// + object Construct(IConstructorInvocation invocation); } \ No newline at end of file diff --git a/src/Spring/Spring.Aop/AopAlliance/Intercept/IConstructorInvocation.cs b/src/Spring/Spring.Aop/AopAlliance/Intercept/IConstructorInvocation.cs index ee766145..f50fdc23 100644 --- a/src/Spring/Spring.Aop/AopAlliance/Intercept/IConstructorInvocation.cs +++ b/src/Spring/Spring.Aop/AopAlliance/Intercept/IConstructorInvocation.cs @@ -2,9 +2,9 @@ /* * All the source code provided by AOP Alliance is Public Domain. - * + * * http://aopalliance.sourceforge.net/ - * + * */ #endregion @@ -15,37 +15,36 @@ using System.Reflection; #endregion -namespace AopAlliance.Intercept +namespace AopAlliance.Intercept; + +/// +/// A description of an invocation to a constuctor, given to an interceptor +/// upon constructor-call. +/// +/// +///

+/// A constructor invocation is a joinpoint and can be intercepted by a +/// constructor interceptor. +///

+///
+/// +public interface IConstructorInvocation : IInvocation { - /// - /// A description of an invocation to a constuctor, given to an interceptor - /// upon constructor-call. - /// - /// - ///

- /// A constructor invocation is a joinpoint and can be intercepted by a - /// constructor interceptor. - ///

- ///
- /// - public interface IConstructorInvocation : IInvocation - { - /// - /// Gets the constructor invocation that is to be invoked. - /// - /// - ///

- /// This property is a friendly implementation of the - /// property. - /// It should be used in preference to the - /// property - /// because it provides immediate access to the underlying constructor - /// without the need to resort to a cast. - ///

- ///
- /// - /// The constructor invocation that is to be invoked. - /// - ConstructorInfo Constructor { get; } - } -} \ No newline at end of file + /// + /// Gets the constructor invocation that is to be invoked. + /// + /// + ///

+ /// This property is a friendly implementation of the + /// property. + /// It should be used in preference to the + /// property + /// because it provides immediate access to the underlying constructor + /// without the need to resort to a cast. + ///

+ ///
+ /// + /// The constructor invocation that is to be invoked. + /// + ConstructorInfo Constructor { get; } +} diff --git a/src/Spring/Spring.Aop/AopAlliance/Intercept/IInterceptor.cs b/src/Spring/Spring.Aop/AopAlliance/Intercept/IInterceptor.cs index 70a0457a..3500441e 100644 --- a/src/Spring/Spring.Aop/AopAlliance/Intercept/IInterceptor.cs +++ b/src/Spring/Spring.Aop/AopAlliance/Intercept/IInterceptor.cs @@ -2,9 +2,9 @@ /* * All the source code provided by AOP Alliance is Public Domain. - * + * * http://aopalliance.sourceforge.net/ - * + * */ #endregion @@ -15,24 +15,23 @@ using AopAlliance.Aop; #endregion -namespace AopAlliance.Intercept +namespace AopAlliance.Intercept; + +/// +/// Represents a generic interceptor. +/// +/// +///

+/// A generic interceptor can intercept runtime events that occur within a +/// base program. Those events are materialized by (reified in) joinpoints. +/// Runtime joinpoints can be invocations, field access, exceptions, etc. +///

+///

+/// This interface is not used directly. Use the various derived interfaces +/// to intercept specific events. +///

+///
+/// +public interface IInterceptor : IAdvice { - /// - /// Represents a generic interceptor. - /// - /// - ///

- /// A generic interceptor can intercept runtime events that occur within a - /// base program. Those events are materialized by (reified in) joinpoints. - /// Runtime joinpoints can be invocations, field access, exceptions, etc. - ///

- ///

- /// This interface is not used directly. Use the various derived interfaces - /// to intercept specific events. - ///

- ///
- /// - public interface IInterceptor : IAdvice - { - } } diff --git a/src/Spring/Spring.Aop/AopAlliance/Intercept/IInvocation.cs b/src/Spring/Spring.Aop/AopAlliance/Intercept/IInvocation.cs index 5af05a06..bd66c69c 100644 --- a/src/Spring/Spring.Aop/AopAlliance/Intercept/IInvocation.cs +++ b/src/Spring/Spring.Aop/AopAlliance/Intercept/IInvocation.cs @@ -2,38 +2,37 @@ /* * All the source code provided by AOP Alliance is Public Domain. - * + * * http://aopalliance.sourceforge.net/ - * + * */ #endregion -namespace AopAlliance.Intercept +namespace AopAlliance.Intercept; + +/// +/// Represents an invocation in the program. +/// +/// +///

+/// An invocation is a joinpoint and can be intercepted by an interceptor. +/// Typical examples would be a constructor invocation and a method call. +///

+///
+public interface IInvocation : IJoinpoint { - /// - /// Represents an invocation in the program. - /// - /// - ///

- /// An invocation is a joinpoint and can be intercepted by an interceptor. - /// Typical examples would be a constructor invocation and a method call. - ///

- ///
- public interface IInvocation : IJoinpoint - { - /// - /// Gets the arguments to an invocation. - /// - /// - ///

- /// It is of course possible to change element values within this array - /// to change the arguments to an intercepted invocation. - ///

- ///
- /// - /// The arguments to an invocation. - /// - object[] Arguments { get; } - } + /// + /// Gets the arguments to an invocation. + /// + /// + ///

+ /// It is of course possible to change element values within this array + /// to change the arguments to an intercepted invocation. + ///

+ ///
+ /// + /// The arguments to an invocation. + /// + object[] Arguments { get; } } diff --git a/src/Spring/Spring.Aop/AopAlliance/Intercept/IJoinpoint.cs b/src/Spring/Spring.Aop/AopAlliance/Intercept/IJoinpoint.cs index 98a97f73..67488680 100644 --- a/src/Spring/Spring.Aop/AopAlliance/Intercept/IJoinpoint.cs +++ b/src/Spring/Spring.Aop/AopAlliance/Intercept/IJoinpoint.cs @@ -2,9 +2,9 @@ /* * All the source code provided by AOP Alliance is Public Domain. - * + * * http://aopalliance.sourceforge.net/ - * + * */ #endregion @@ -15,74 +15,73 @@ using System.Reflection; #endregion -namespace AopAlliance.Intercept +namespace AopAlliance.Intercept; + +/// +/// Represents a generic runtime joinpoint (in the AOP terminology). +/// +/// +///

+/// A runtime joinpoint is an event that occurs on a static +/// joinpoint (i.e. a location in a program). For instance, an +/// invocation is the runtime joinpoint on a method (static joinpoint). +/// The static part of a given joinpoint can be generically retrieved +/// using the +/// property. +///

+///

+/// In the context of an interception framework, a runtime joinpoint +/// is then the reification of an access to an accessible object (a +/// method, a constructor, a field), i.e. the static part of the +/// joinpoint. It is passed to the interceptors that are installed on +/// the static joinpoint. +///

+///
+/// +public interface IJoinpoint { - /// - /// Represents a generic runtime joinpoint (in the AOP terminology). - /// - /// - ///

- /// A runtime joinpoint is an event that occurs on a static - /// joinpoint (i.e. a location in a program). For instance, an - /// invocation is the runtime joinpoint on a method (static joinpoint). - /// The static part of a given joinpoint can be generically retrieved - /// using the - /// property. - ///

- ///

- /// In the context of an interception framework, a runtime joinpoint - /// is then the reification of an access to an accessible object (a - /// method, a constructor, a field), i.e. the static part of the - /// joinpoint. It is passed to the interceptors that are installed on - /// the static joinpoint. - ///

- ///
- /// - public interface IJoinpoint - { - /// - /// Gets the static part of this joinpoint. - /// - /// - ///

- /// The static part is an accessible object on which a chain of - /// interceptors are installed. - ///

- ///
- /// - /// The static part of this joinpoint. - /// - MemberInfo StaticPart { get; } + /// + /// Gets the static part of this joinpoint. + /// + /// + ///

+ /// The static part is an accessible object on which a chain of + /// interceptors are installed. + ///

+ ///
+ /// + /// The static part of this joinpoint. + /// + MemberInfo StaticPart { get; } - /// - /// Gets the object that holds the current joinpoint's static part. - /// - /// - ///

- /// For instance, the target object for a method invocation. - ///

- ///
- /// - /// The object that holds the current joinpoint's static part. - /// - object This { get; } + /// + /// Gets the object that holds the current joinpoint's static part. + /// + /// + ///

+ /// For instance, the target object for a method invocation. + ///

+ ///
+ /// + /// The object that holds the current joinpoint's static part. + /// + object This { get; } - /// - /// Proceeds to the next interceptor in the chain. - /// - /// - ///

- /// The implementation and semantics of this method depend on the - /// actual joinpoint type. Consult the derived interfaces of this - /// interface for specifics. - ///

- ///
- /// - /// Consult the derived interfaces of this interface for specifics. - /// - /// - /// If any of the interceptors at the joinpoint throws an exception. - /// - object Proceed(); - } -} \ No newline at end of file + /// + /// Proceeds to the next interceptor in the chain. + /// + /// + ///

+ /// The implementation and semantics of this method depend on the + /// actual joinpoint type. Consult the derived interfaces of this + /// interface for specifics. + ///

+ ///
+ /// + /// Consult the derived interfaces of this interface for specifics. + /// + /// + /// If any of the interceptors at the joinpoint throws an exception. + /// + object Proceed(); +} diff --git a/src/Spring/Spring.Aop/AopAlliance/Intercept/IMethodInterceptor.cs b/src/Spring/Spring.Aop/AopAlliance/Intercept/IMethodInterceptor.cs index a253338b..0ecf6bed 100644 --- a/src/Spring/Spring.Aop/AopAlliance/Intercept/IMethodInterceptor.cs +++ b/src/Spring/Spring.Aop/AopAlliance/Intercept/IMethodInterceptor.cs @@ -2,48 +2,47 @@ /* * All the source code provided by AOP Alliance is Public Domain. - * + * * http://aopalliance.sourceforge.net/ - * + * */ #endregion -namespace AopAlliance.Intercept +namespace AopAlliance.Intercept; + +/// +/// Intercepts calls on an interface on its way to the target. +/// +/// +///

+/// Such interceptions are nested "on top" of the target. +///

+///
+public interface IMethodInterceptor : IInterceptor { - /// - /// Intercepts calls on an interface on its way to the target. - /// - /// - ///

- /// Such interceptions are nested "on top" of the target. - ///

- ///
- public interface IMethodInterceptor : IInterceptor - { - /// - /// Implement this method to perform extra treatments before and after - /// the call to the supplied . - /// - /// - ///

- /// Polite implementations would certainly like to invoke - /// . - ///

- ///
- /// - /// The method invocation that is being intercepted. - /// - /// - /// The result of the call to the - /// method of - /// the supplied ; this return value may - /// well have been intercepted by the interceptor. - /// - /// - /// If any of the interceptors in the chain or the target object itself - /// throws an exception. - /// - object Invoke(IMethodInvocation invocation); - } + /// + /// Implement this method to perform extra treatments before and after + /// the call to the supplied . + /// + /// + ///

+ /// Polite implementations would certainly like to invoke + /// . + ///

+ ///
+ /// + /// The method invocation that is being intercepted. + /// + /// + /// The result of the call to the + /// method of + /// the supplied ; this return value may + /// well have been intercepted by the interceptor. + /// + /// + /// If any of the interceptors in the chain or the target object itself + /// throws an exception. + /// + object Invoke(IMethodInvocation invocation); } diff --git a/src/Spring/Spring.Aop/AopAlliance/Intercept/IMethodInvocation.cs b/src/Spring/Spring.Aop/AopAlliance/Intercept/IMethodInvocation.cs index 0d88f632..1d37141b 100644 --- a/src/Spring/Spring.Aop/AopAlliance/Intercept/IMethodInvocation.cs +++ b/src/Spring/Spring.Aop/AopAlliance/Intercept/IMethodInvocation.cs @@ -15,62 +15,60 @@ using System.Reflection; #endregion -namespace AopAlliance.Intercept +namespace AopAlliance.Intercept; + +/// +/// Description of an invocation to a method, given to an interceptor +/// upon method-call. +/// +/// +///

+/// A method invocation is a joinpoint and can be intercepted by a method +/// interceptor. +///

+///
+/// +public interface IMethodInvocation : IInvocation { - /// - /// Description of an invocation to a method, given to an interceptor - /// upon method-call. - /// - /// - ///

- /// A method invocation is a joinpoint and can be intercepted by a method - /// interceptor. - ///

- ///
- /// - public interface IMethodInvocation : IInvocation - { - /// - /// Gets the method invocation that is to be invoked. - /// - /// - ///

- /// This property is a friendly implementation of the - /// property. - /// It should be used in preference to the - /// property - /// because it provides immediate access to the underlying method - /// without the need to resort to a cast. - ///

- ///
- /// - /// The method invocation that is to be invoked. - /// - MethodInfo Method { get; } + /// + /// Gets the method invocation that is to be invoked. + /// + /// + ///

+ /// This property is a friendly implementation of the + /// property. + /// It should be used in preference to the + /// property + /// because it provides immediate access to the underlying method + /// without the need to resort to a cast. + ///

+ ///
+ /// + /// The method invocation that is to be invoked. + /// + MethodInfo Method { get; } - /// - /// Gets the proxy object for the invocation. - /// - /// - /// The proxy object for this method invocation. - /// - object Proxy { get; } + /// + /// Gets the proxy object for the invocation. + /// + /// + /// The proxy object for this method invocation. + /// + object Proxy { get; } - /// - /// Gets the target object for the invocation. - /// - /// - /// The target object for this method invocation. - /// - object Target { get; } + /// + /// Gets the target object for the invocation. + /// + /// + /// The target object for this method invocation. + /// + object Target { get; } - /// - /// Gets the type of the target object. - /// - /// - /// The type of the target object. - /// - Type TargetType { get; } - - } + /// + /// Gets the type of the target object. + /// + /// + /// The type of the target object. + /// + Type TargetType { get; } } diff --git a/src/Spring/Spring.Aop/Aspects/AbstractExceptionHandler.cs b/src/Spring/Spring.Aop/Aspects/AbstractExceptionHandler.cs index 24dc090a..f4eb40c9 100644 --- a/src/Spring/Spring.Aop/Aspects/AbstractExceptionHandler.cs +++ b/src/Spring/Spring.Aop/Aspects/AbstractExceptionHandler.cs @@ -22,161 +22,163 @@ using System.Collections; using Microsoft.Extensions.Logging; using Spring.Expressions; -namespace Spring.Aspects +namespace Spring.Aspects; + +/// +/// An abstract base class providing all necessary functionality for typical IExceptionHandler implementations. +/// +/// Mark Pollack +public abstract class AbstractExceptionHandler : IExceptionHandler { + #region Fields + /// - /// An abstract base class providing all necessary functionality for typical IExceptionHandler implementations. + /// The logging instance /// - /// Mark Pollack - public abstract class AbstractExceptionHandler : IExceptionHandler + protected readonly ILogger log; + + private IList sourceExceptionNames = new ArrayList(); + private IList sourceExceptionTypes = new ArrayList(); + private string actionExpressionText; + private bool continueProcessing = false; + private string constraintExpressionText; + + #endregion + + #region Constructor(s) + + /// + /// Initializes a new instance of the class. + /// + public AbstractExceptionHandler() { - #region Fields - - /// - /// The logging instance - /// - protected readonly ILogger log; - - private IList sourceExceptionNames = new ArrayList(); - private IList sourceExceptionTypes = new ArrayList(); - private string actionExpressionText; - private bool continueProcessing = false; - private string constraintExpressionText; - - #endregion - - #region Constructor(s) - - /// - /// Initializes a new instance of the class. - /// - public AbstractExceptionHandler() - { - log = LogManager.GetLogger(GetType()); - } - - /// - /// Initializes a new instance of the class. - /// - /// The exception names. - public AbstractExceptionHandler(string[] exceptionNames) - { - log = LogManager.GetLogger(GetType()); - foreach (string exceptionName in exceptionNames) - { - SourceExceptionNames.Add(exceptionName); - } - } - - #endregion - - #region Implementation of IExceptionHandler - - #region Properties - - /// - /// Gets the source exception names. - /// - /// The source exception names. - public virtual IList SourceExceptionNames - { - get { return sourceExceptionNames; } - set { sourceExceptionNames = value; } - } - - /// - /// Gets the source exception types. - /// - /// The source exception types. - public virtual IList SourceExceptionTypes - { - get { return sourceExceptionTypes; } - set { sourceExceptionTypes = value; } - } - - /// - /// Gets the action translation expression text - /// - /// The action translation expression. - public virtual string ActionExpressionText - { - get { return actionExpressionText; } - set { actionExpressionText = value; } - } - - - /// - /// Gets or sets the constraint expression text. - /// - /// The constraint expression text. - public string ConstraintExpressionText - { - get { return constraintExpressionText; } - set { constraintExpressionText = value; } - } - - /// - /// Gets a value indicating whether to continue processing. - /// - /// true if continue processing; otherwise, false. - public bool ContinueProcessing - { - get { return continueProcessing; } - set { continueProcessing = value; } - } - - #endregion - - /// - /// Determines whether this instance can handle the exception the specified exception. - /// - /// The exception. - /// The call context dictionary. - /// - /// true if this instance can handle the specified exception; otherwise, false. - /// - public bool CanHandleException(Exception ex, IDictionary callContextDictionary) - { - if (SourceExceptionNames != null) - { - foreach (string exceptionName in SourceExceptionNames) - { - if (ex.GetType().Name.IndexOf(exceptionName) >= 0) - { - return true; - } - } - } - if (ConstraintExpressionText != null) - { - bool canProcess; - try - { - IExpression expression = Expression.Parse(ConstraintExpressionText); - canProcess = (bool) expression.GetValue(null, callContextDictionary); - } catch (InvalidCastException e) - { - string message = "Was not able to unbox constraint expression to boolean [" + ConstraintExpressionText + "]"; - log.LogWarning(e, message); - return false; - } catch (Exception e) - { - string message = "Was not able to evaluate constraint expression [" + ConstraintExpressionText + "]"; - log.LogWarning(e, message); - return false; - } - return canProcess; - } - - return false; - } - - /// - /// Handles the exception. - /// - /// The return value from handling the exception, if not rethrown or a new exception is thrown. - public abstract object HandleException(IDictionary callContextDictionary); - - #endregion + log = LogManager.GetLogger(GetType()); } + + /// + /// Initializes a new instance of the class. + /// + /// The exception names. + public AbstractExceptionHandler(string[] exceptionNames) + { + log = LogManager.GetLogger(GetType()); + foreach (string exceptionName in exceptionNames) + { + SourceExceptionNames.Add(exceptionName); + } + } + + #endregion + + #region Implementation of IExceptionHandler + + #region Properties + + /// + /// Gets the source exception names. + /// + /// The source exception names. + public virtual IList SourceExceptionNames + { + get { return sourceExceptionNames; } + set { sourceExceptionNames = value; } + } + + /// + /// Gets the source exception types. + /// + /// The source exception types. + public virtual IList SourceExceptionTypes + { + get { return sourceExceptionTypes; } + set { sourceExceptionTypes = value; } + } + + /// + /// Gets the action translation expression text + /// + /// The action translation expression. + public virtual string ActionExpressionText + { + get { return actionExpressionText; } + set { actionExpressionText = value; } + } + + /// + /// Gets or sets the constraint expression text. + /// + /// The constraint expression text. + public string ConstraintExpressionText + { + get { return constraintExpressionText; } + set { constraintExpressionText = value; } + } + + /// + /// Gets a value indicating whether to continue processing. + /// + /// true if continue processing; otherwise, false. + public bool ContinueProcessing + { + get { return continueProcessing; } + set { continueProcessing = value; } + } + + #endregion + + /// + /// Determines whether this instance can handle the exception the specified exception. + /// + /// The exception. + /// The call context dictionary. + /// + /// true if this instance can handle the specified exception; otherwise, false. + /// + public bool CanHandleException(Exception ex, IDictionary callContextDictionary) + { + if (SourceExceptionNames != null) + { + foreach (string exceptionName in SourceExceptionNames) + { + if (ex.GetType().Name.IndexOf(exceptionName) >= 0) + { + return true; + } + } + } + + if (ConstraintExpressionText != null) + { + bool canProcess; + try + { + IExpression expression = Expression.Parse(ConstraintExpressionText); + canProcess = (bool) expression.GetValue(null, callContextDictionary); + } + catch (InvalidCastException e) + { + string message = "Was not able to unbox constraint expression to boolean [" + ConstraintExpressionText + "]"; + log.LogWarning(e, message); + return false; + } + catch (Exception e) + { + string message = "Was not able to evaluate constraint expression [" + ConstraintExpressionText + "]"; + log.LogWarning(e, message); + return false; + } + + return canProcess; + } + + return false; + } + + /// + /// Handles the exception. + /// + /// The return value from handling the exception, if not rethrown or a new exception is thrown. + public abstract object HandleException(IDictionary callContextDictionary); + + #endregion } diff --git a/src/Spring/Spring.Aop/Aspects/AbstractExceptionHandlerAdvice.cs b/src/Spring/Spring.Aop/Aspects/AbstractExceptionHandlerAdvice.cs index 8aa30e13..06bca435 100644 --- a/src/Spring/Spring.Aop/Aspects/AbstractExceptionHandlerAdvice.cs +++ b/src/Spring/Spring.Aop/Aspects/AbstractExceptionHandlerAdvice.cs @@ -24,151 +24,152 @@ using AopAlliance.Intercept; using Spring.Objects.Factory; using Spring.Util; -namespace Spring.Aspects +namespace Spring.Aspects; + +/// +/// This is +/// +/// +/// +/// +/// Mark Pollack +[Serializable] +public abstract class AbstractExceptionHandlerAdvice : IMethodInterceptor, IInitializingObject, IDeserializationCallback { /// - /// This is + /// Gets or sets the Regex string used to parse advice expressions starting with 'on exception name' and subclass specific actions. + /// + /// The regex string to parse advice expressions starting with 'on exception name' and subclass specific actions. + public abstract string OnExceptionNameRegex + { + get; + set; + } + + /// + /// Gets or sets the Regex string used to parse advice expressions starting with 'on exception (constraint)' and subclass specific actions. + /// + /// The regex string to parse advice expressions starting with 'on exception (constraint)' and subclass specific actions. + public abstract string OnExceptionRegex + { + get; + set; + } + + /// + /// Implement this method to perform extra treatments before and after + /// the call to the supplied . /// /// - /// + ///

+ /// Polite implementations would certainly like to invoke + /// . + ///

///
- /// Mark Pollack - [Serializable] - public abstract class AbstractExceptionHandlerAdvice : IMethodInterceptor, IInitializingObject, IDeserializationCallback + /// + /// The method invocation that is being intercepted. + /// + /// + /// The result of the call to the + /// method of + /// the supplied ; this return value may + /// well have been intercepted by the interceptor. + /// + /// + /// If any of the interceptors in the chain or the target object itself + /// throws an exception. + /// + public abstract object Invoke(IMethodInvocation invocation); + + /// + /// Invoked by an + /// after it has injected all of an object's dependencies. + /// + /// + ///

+ /// This method allows the object instance to perform the kind of + /// initialization only possible when all of it's dependencies have + /// been injected (set), and to throw an appropriate exception in the + /// event of misconfiguration. + ///

+ ///

+ /// Please do consult the class level documentation for the + /// interface for a + /// description of exactly when this method is invoked. In + /// particular, it is worth noting that the + /// + /// and + /// callbacks will have been invoked prior to this method being + /// called. + ///

+ ///
+ /// + /// In the event of misconfiguration (such as the failure to set a + /// required property) or if initialization fails. + /// + public abstract void AfterPropertiesSet(); + + /// + /// Parses the advice expression. + /// + /// The advice expression. + /// An instance of ParsedAdviceExpression + protected virtual ParsedAdviceExpression ParseAdviceExpression(string adviceExpression) { - /// - /// Gets or sets the Regex string used to parse advice expressions starting with 'on exception name' and subclass specific actions. - /// - /// The regex string to parse advice expressions starting with 'on exception name' and subclass specific actions. - public abstract string OnExceptionNameRegex + ParsedAdviceExpression parsedAdviceExpression = new ParsedAdviceExpression(adviceExpression); + + Match match = GetMatch(adviceExpression, OnExceptionNameRegex); + if (match.Success) { - get; set; + parsedAdviceExpression.Success = true; + //using exception names for exception filter + parsedAdviceExpression.ExceptionNames = StringUtils.CommaDelimitedListToStringArray(match.Groups[2].Value.Trim()); + parsedAdviceExpression.ActionText = match.Groups[3].Value.Trim(); + parsedAdviceExpression.ActionExpressionText = match.Groups[4].Value.Trim(); } - - /// - /// Gets or sets the Regex string used to parse advice expressions starting with 'on exception (constraint)' and subclass specific actions. - /// - /// The regex string to parse advice expressions starting with 'on exception (constraint)' and subclass specific actions. - public abstract string OnExceptionRegex + else { - get; set; - } - - /// - /// Implement this method to perform extra treatments before and after - /// the call to the supplied . - /// - /// - ///

- /// Polite implementations would certainly like to invoke - /// . - ///

- ///
- /// - /// The method invocation that is being intercepted. - /// - /// - /// The result of the call to the - /// method of - /// the supplied ; this return value may - /// well have been intercepted by the interceptor. - /// - /// - /// If any of the interceptors in the chain or the target object itself - /// throws an exception. - /// - public abstract object Invoke(IMethodInvocation invocation); - - /// - /// Invoked by an - /// after it has injected all of an object's dependencies. - /// - /// - ///

- /// This method allows the object instance to perform the kind of - /// initialization only possible when all of it's dependencies have - /// been injected (set), and to throw an appropriate exception in the - /// event of misconfiguration. - ///

- ///

- /// Please do consult the class level documentation for the - /// interface for a - /// description of exactly when this method is invoked. In - /// particular, it is worth noting that the - /// - /// and - /// callbacks will have been invoked prior to this method being - /// called. - ///

- ///
- /// - /// In the event of misconfiguration (such as the failure to set a - /// required property) or if initialization fails. - /// - public abstract void AfterPropertiesSet(); - - /// - /// Parses the advice expression. - /// - /// The advice expression. - /// An instance of ParsedAdviceExpression - protected virtual ParsedAdviceExpression ParseAdviceExpression(string adviceExpression) - { - ParsedAdviceExpression parsedAdviceExpression = new ParsedAdviceExpression(adviceExpression); - - Match match = GetMatch(adviceExpression, OnExceptionNameRegex); + match = GetMatch(adviceExpression, OnExceptionRegex); if (match.Success) { parsedAdviceExpression.Success = true; - //using exception names for exception filter - parsedAdviceExpression.ExceptionNames = StringUtils.CommaDelimitedListToStringArray(match.Groups[2].Value.Trim()); + //using constratin expression for exception filter + string constraintExpression = match.Groups[2].Value.Trim().Remove(0, 1); + parsedAdviceExpression.ConstraintExpression = constraintExpression.Substring(0, constraintExpression.Length - 1); parsedAdviceExpression.ActionText = match.Groups[3].Value.Trim(); parsedAdviceExpression.ActionExpressionText = match.Groups[4].Value.Trim(); } - else - { - match = GetMatch(adviceExpression, OnExceptionRegex); - if (match.Success) - { - parsedAdviceExpression.Success = true; - //using constratin expression for exception filter - string constraintExpression = match.Groups[2].Value.Trim().Remove(0, 1); - parsedAdviceExpression.ConstraintExpression = constraintExpression.Substring(0, constraintExpression.Length - 1); - parsedAdviceExpression.ActionText = match.Groups[3].Value.Trim(); - parsedAdviceExpression.ActionExpressionText = match.Groups[4].Value.Trim(); - } - } - return parsedAdviceExpression; } - - /// - /// Gets the match using exception constraint expression. - /// - /// The advice expression string. - /// The regex string. - /// The Match object resulting from the regular expression match. - protected virtual Match GetMatch(string adviceExpressionString, string regexString) - { - RegexOptions options = ((RegexOptions.IgnorePatternWhitespace | RegexOptions.Multiline) | RegexOptions.IgnoreCase); - Regex reg = new Regex(regexString, options); - return reg.Match(adviceExpressionString); - } - - #region Serialization - - void IDeserializationCallback.OnDeserialization(object sender) - { - OnDeserialization(sender); - } - - /// - /// Override in case you need to initialized non-serialized fields on deserialization. - /// - protected virtual void OnDeserialization(object sender) - { - } - - #endregion + return parsedAdviceExpression; } + + /// + /// Gets the match using exception constraint expression. + /// + /// The advice expression string. + /// The regex string. + /// The Match object resulting from the regular expression match. + protected virtual Match GetMatch(string adviceExpressionString, string regexString) + { + RegexOptions options = ((RegexOptions.IgnorePatternWhitespace | RegexOptions.Multiline) | RegexOptions.IgnoreCase); + Regex reg = new Regex(regexString, options); + return reg.Match(adviceExpressionString); + } + + #region Serialization + + void IDeserializationCallback.OnDeserialization(object sender) + { + OnDeserialization(sender); + } + + /// + /// Override in case you need to initialized non-serialized fields on deserialization. + /// + protected virtual void OnDeserialization(object sender) + { + } + + #endregion } diff --git a/src/Spring/Spring.Aop/Aspects/Cache/BaseCacheAdvice.cs b/src/Spring/Spring.Aop/Aspects/Cache/BaseCacheAdvice.cs index a5da7f6e..f984955f 100644 --- a/src/Spring/Spring.Aop/Aspects/Cache/BaseCacheAdvice.cs +++ b/src/Spring/Spring.Aop/Aspects/Cache/BaseCacheAdvice.cs @@ -28,177 +28,179 @@ using Spring.Expressions; #endregion -namespace Spring.Aspects.Cache +namespace Spring.Aspects.Cache; + +/// +/// Base class for different cache advice implementations that provide +/// access to common functionality, such as obtaining a cache instance. +/// +/// Aleksandar Seovic +public abstract class BaseCacheAdvice : IApplicationContextAware { /// - /// Base class for different cache advice implementations that provide - /// access to common functionality, such as obtaining a cache instance. + /// Shared logger instance /// - /// Aleksandar Seovic - public abstract class BaseCacheAdvice : IApplicationContextAware + protected readonly ILogger logger; + + private IApplicationContext applicationContext; + + /// + /// Create a new default instance. + /// + protected BaseCacheAdvice() { - /// - /// Shared logger instance - /// - protected readonly ILogger logger; + logger = LogManager.GetLogger(this.GetType()); + } - private IApplicationContext applicationContext; + /// + /// Sets the that this + /// object runs in. + /// + public IApplicationContext ApplicationContext + { + set { applicationContext = value; } + } - /// - /// Create a new default instance. - /// - protected BaseCacheAdvice() + /// + /// Returns an instance based on the cache name. + /// + /// The name of the cache. + /// + /// Cache instance for the specified if one + /// is registered in the application context, or null if it isn't. + /// + /// + /// If there's no cache instance registered for the specified . + /// + /// + /// If the cache instance could not be created. + /// + /// + /// If the cache instance registered does not implement the interface. + /// + public ICache GetCache(string name) + { + ICache cache = applicationContext.GetObject(name) as ICache; + if (cache == null) { - logger = LogManager.GetLogger(this.GetType()); + throw new ArgumentException(String.Format( + "Cache with the specified name [{0}] does not implement the 'Spring.Caching.ICache' interface.", name)); } - /// - /// Sets the that this - /// object runs in. - /// - public IApplicationContext ApplicationContext + return cache; + } + + /// + /// Prepares variables for expression evaluation by packaging all + /// method arguments into a dictionary, keyed by argument name. + /// + /// + /// Method to get parameters info from. + /// + /// + /// Argument values to package. + /// + /// + /// A dictionary containing all method arguments, keyed by method name. + /// + protected static IDictionary PrepareVariables(MethodInfo method, object[] arguments) + { + IDictionary vars = new Dictionary(); + + vars[method.Name] = method; + + ParameterInfo[] parameters = method.GetParameters(); + for (int i = 0; i < parameters.Length; i++) { - set { applicationContext = value; } + ParameterInfo p = parameters[i]; + vars[p.Name] = arguments[i]; } - /// - /// Returns an instance based on the cache name. - /// - /// The name of the cache. - /// - /// Cache instance for the specified if one - /// is registered in the application context, or null if it isn't. - /// - /// - /// If there's no cache instance registered for the specified . - /// - /// - /// If the cache instance could not be created. - /// - /// - /// If the cache instance registered does not implement the interface. - /// - public ICache GetCache(string name) + return vars; + } + + /// + /// Evaluates a SpEL expression as a boolean value. + /// + /// + /// The expression string that should be evaluated. + /// + /// + /// The SpEL expression instance that should be evaluated. + /// + /// + /// The object to evaluate expression against. + /// + /// + /// The expression variables dictionary. + /// + /// + /// The evaluated boolean. + /// + /// + /// If the SpEL expression could not be successfuly resolved to a boolean. + /// + protected static bool EvalCondition(string condition, + IExpression conditionExpression, object context, IDictionary variables) + { + if (conditionExpression == null) { - ICache cache = applicationContext.GetObject(name) as ICache; - if (cache == null) + return true; + } + else + { + object value = conditionExpression.GetValue(context, variables); + if (value is bool) { - throw new ArgumentException(String.Format( - "Cache with the specified name [{0}] does not implement the 'Spring.Caching.ICache' interface.", name)); - } - return cache; - } - - /// - /// Prepares variables for expression evaluation by packaging all - /// method arguments into a dictionary, keyed by argument name. - /// - /// - /// Method to get parameters info from. - /// - /// - /// Argument values to package. - /// - /// - /// A dictionary containing all method arguments, keyed by method name. - /// - protected static IDictionary PrepareVariables(MethodInfo method, object[] arguments) - { - IDictionary vars = new Dictionary(); - - vars[method.Name] = method; - - ParameterInfo[] parameters = method.GetParameters(); - for (int i = 0; i < parameters.Length; i++) - { - ParameterInfo p = parameters[i]; - vars[p.Name] = arguments[i]; - } - return vars; - } - - /// - /// Evaluates a SpEL expression as a boolean value. - /// - /// - /// The expression string that should be evaluated. - /// - /// - /// The SpEL expression instance that should be evaluated. - /// - /// - /// The object to evaluate expression against. - /// - /// - /// The expression variables dictionary. - /// - /// - /// The evaluated boolean. - /// - /// - /// If the SpEL expression could not be successfuly resolved to a boolean. - /// - protected static bool EvalCondition(string condition, - IExpression conditionExpression, object context, IDictionary variables) - { - if (conditionExpression == null) - { - return true; + return (bool) value; } else { - object value = conditionExpression.GetValue(context, variables); - if (value is bool) - { - return (bool)value; - } - else - { - throw new InvalidOperationException(String.Format( - "The SpEL expression '{0}' could not be successfuly resolved to a boolean.", - condition)); - } + throw new InvalidOperationException(String.Format( + "The SpEL expression '{0}' could not be successfuly resolved to a boolean.", + condition)); } } - - /// - /// Retrieves custom attribute for the specified attribute type. - /// - /// - /// Method/Parameter to get attribute from. - /// - /// - /// Attribute type. - /// - /// - /// Attribute instance if one is found, null otherwise. - /// - protected object GetCustomAttribute(ICustomAttributeProvider attributeProvider, Type attributeType) - { - object[] attributes = attributeProvider.GetCustomAttributes(attributeType, false); - if (attributes.Length > 0) - { - return attributes[0]; - } - return null; - } - - /// - /// Retrieves custom attribute for the specified attribute type. - /// - /// - /// Method/Parameter to get attribute from. - /// - /// - /// Attribute type. - /// - /// - /// Attribute instance if one is found, null otherwise. - /// - protected object[] GetCustomAttributes(ICustomAttributeProvider attributeProvider, Type attributeType) - { - object[] attributes = attributeProvider.GetCustomAttributes(attributeType, false); - return attributes; - } + } + + /// + /// Retrieves custom attribute for the specified attribute type. + /// + /// + /// Method/Parameter to get attribute from. + /// + /// + /// Attribute type. + /// + /// + /// Attribute instance if one is found, null otherwise. + /// + protected object GetCustomAttribute(ICustomAttributeProvider attributeProvider, Type attributeType) + { + object[] attributes = attributeProvider.GetCustomAttributes(attributeType, false); + if (attributes.Length > 0) + { + return attributes[0]; + } + + return null; + } + + /// + /// Retrieves custom attribute for the specified attribute type. + /// + /// + /// Method/Parameter to get attribute from. + /// + /// + /// Attribute type. + /// + /// + /// Attribute instance if one is found, null otherwise. + /// + protected object[] GetCustomAttributes(ICustomAttributeProvider attributeProvider, Type attributeType) + { + object[] attributes = attributeProvider.GetCustomAttributes(attributeType, false); + return attributes; } } diff --git a/src/Spring/Spring.Aop/Aspects/Cache/CacheAspect.cs b/src/Spring/Spring.Aop/Aspects/Cache/CacheAspect.cs index 34b35cc4..1deebb8e 100644 --- a/src/Spring/Spring.Aop/Aspects/Cache/CacheAspect.cs +++ b/src/Spring/Spring.Aop/Aspects/Cache/CacheAspect.cs @@ -25,80 +25,79 @@ using Spring.Context; #endregion -namespace Spring.Aspects.Cache +namespace Spring.Aspects.Cache; + +/// +/// Caching aspect implementation. +/// +/// +/// This class encapsulates all the advisors that need to be configured to support +/// Spring's full caching functionality. +/// +/// +/// +/// +/// Aleksandar Seovic +public class CacheAspect : IAdvisors, IApplicationContextAware { - /// - /// Caching aspect implementation. - /// - /// - /// This class encapsulates all the advisors that need to be configured to support - /// Spring's full caching functionality. - /// - /// - /// - /// - /// Aleksandar Seovic - public class CacheAspect : IAdvisors, IApplicationContextAware - { - private IAdvisor[] advisors; - private IApplicationContext applicationContext; + private IAdvisor[] advisors; + private IApplicationContext applicationContext; - /// - /// Creates a new instance. - /// - public CacheAspect() - { - advisors = new IAdvisor[] { new CacheResultAdvisor(), new CacheParameterAdvisor(), new InvalidateCacheAdvisor() }; - } + /// + /// Creates a new instance. + /// + public CacheAspect() + { + advisors = new IAdvisor[] { new CacheResultAdvisor(), new CacheParameterAdvisor(), new InvalidateCacheAdvisor() }; + } - /// - /// Gets or sets a list of advisors for this aspect. - /// - /// - /// A list of advisors for this aspect. - /// - public IList Advisors - { - get { return advisors; } - set { throw new NotSupportedException("Cache aspect advisors cannot be set externally."); } - } + /// + /// Gets or sets a list of advisors for this aspect. + /// + /// + /// A list of advisors for this aspect. + /// + public IList Advisors + { + get { return advisors; } + set { throw new NotSupportedException("Cache aspect advisors cannot be set externally."); } + } - /// - /// Sets the that this - /// object runs in. - /// - /// - ///

- /// Normally this call will be used to initialize the object. - ///

- ///

- /// Invoked after population of normal object properties but before an - /// init callback such as - /// 's - /// - /// or a custom init-method. Invoked after the setting of any - /// 's - /// - /// property. - ///

- ///
- /// - /// In the case of application context initialization errors. - /// - /// - /// If thrown by any application context methods. - /// - /// - public IApplicationContext ApplicationContext - { - set - { - applicationContext = value; - for (int i = 0; i < advisors.Length; i++) - { - ((IApplicationContextAware) advisors[i]).ApplicationContext = applicationContext; - } - } - } - } + /// + /// Sets the that this + /// object runs in. + /// + /// + ///

+ /// Normally this call will be used to initialize the object. + ///

+ ///

+ /// Invoked after population of normal object properties but before an + /// init callback such as + /// 's + /// + /// or a custom init-method. Invoked after the setting of any + /// 's + /// + /// property. + ///

+ ///
+ /// + /// In the case of application context initialization errors. + /// + /// + /// If thrown by any application context methods. + /// + /// + public IApplicationContext ApplicationContext + { + set + { + applicationContext = value; + for (int i = 0; i < advisors.Length; i++) + { + ((IApplicationContextAware) advisors[i]).ApplicationContext = applicationContext; + } + } + } } diff --git a/src/Spring/Spring.Aop/Aspects/Cache/CacheParameterAdvice.cs b/src/Spring/Spring.Aop/Aspects/Cache/CacheParameterAdvice.cs index b6e016e9..d697330d 100644 --- a/src/Spring/Spring.Aop/Aspects/Cache/CacheParameterAdvice.cs +++ b/src/Spring/Spring.Aop/Aspects/Cache/CacheParameterAdvice.cs @@ -29,122 +29,127 @@ using Spring.Util; #endregion -namespace Spring.Aspects.Cache +namespace Spring.Aspects.Cache; + +/// +/// Implementation of a parameter caching advice. +/// +/// +///

+/// This advice can be used to cache the parameter of the method. +///

+///

+/// Information that determines where, how and for how long the return value +/// will be cached are retrieved from the s +/// that are defined on the pointcut. +///

+///

+/// Parameter values are cached *after* the target method is invoked in order to +/// capture any parameter state changes it might make (for example, it is common +/// to set an object identifier within the save method for the persistent entity). +///

+///
+/// +/// Aleksandar Seovic +public class CacheParameterAdvice : BaseCacheAdvice, IAfterReturningAdvice { + #region CacheParameterAttribute caching + + private class CacheParameterInfo + { + public readonly ParameterInfo[] Parameters; + public readonly CacheParameterAttribute[][] CacheParameterAttributes; + + public CacheParameterInfo(ParameterInfo[] parameters, CacheParameterAttribute[][] cacheParameterAttributes) + { + Parameters = parameters; + CacheParameterAttributes = cacheParameterAttributes; + } + } + + private readonly Hashtable _cacheParameterInfoCache = new Hashtable(); + + private CacheParameterInfo GetCacheParameterInfo(MethodInfo method) + { + CacheParameterInfo cpi = (CacheParameterInfo) _cacheParameterInfoCache[method]; + if (cpi == null) + { + ParameterInfo[] parameters = method.GetParameters(); + CacheParameterAttribute[][] parameterInfos = new CacheParameterAttribute[parameters.Length][]; + for (int i = 0; i < parameters.Length; i++) + { + ParameterInfo p = parameters[i]; + CacheParameterAttribute[] paramInfoArray = (CacheParameterAttribute[]) GetCustomAttributes(p, typeof(CacheParameterAttribute)); + parameterInfos[i] = paramInfoArray; + } + + cpi = new CacheParameterInfo(parameters, parameterInfos); + _cacheParameterInfoCache[method] = cpi; + } + + return cpi; + } + + #endregion + /// - /// Implementation of a parameter caching advice. + /// Executes after target + /// returns successfully. /// /// ///

- /// This advice can be used to cache the parameter of the method. - ///

- ///

- /// Information that determines where, how and for how long the return value - /// will be cached are retrieved from the s - /// that are defined on the pointcut. - ///

- ///

- /// Parameter values are cached *after* the target method is invoked in order to - /// capture any parameter state changes it might make (for example, it is common - /// to set an object identifier within the save method for the persistent entity). + /// Note that the supplied cannot + /// be changed by this type of advice... use the around advice type + /// () if you + /// need to change the return value of an advised method invocation. + /// The data encapsulated by the supplied + /// can of course be modified though. ///

///
- /// - /// Aleksandar Seovic - public class CacheParameterAdvice : BaseCacheAdvice, IAfterReturningAdvice + /// + /// The value returned by the . + /// + /// The intecepted method. + /// The intercepted method's arguments. + /// The target object. + /// + public void AfterReturning(object returnValue, MethodInfo method, object[] arguments, object target) { - #region CacheParameterAttribute caching + #region Instrumentation - private class CacheParameterInfo - { - public readonly ParameterInfo[] Parameters; - public readonly CacheParameterAttribute[][] CacheParameterAttributes; - - public CacheParameterInfo(ParameterInfo[] parameters, CacheParameterAttribute[][] cacheParameterAttributes) - { - Parameters = parameters; - CacheParameterAttributes = cacheParameterAttributes; - } - } - - private readonly Hashtable _cacheParameterInfoCache = new Hashtable(); - - private CacheParameterInfo GetCacheParameterInfo(MethodInfo method) - { - CacheParameterInfo cpi = (CacheParameterInfo)_cacheParameterInfoCache[method]; - if (cpi == null) - { - ParameterInfo[] parameters = method.GetParameters(); - CacheParameterAttribute[][] parameterInfos = new CacheParameterAttribute[parameters.Length][]; - for (int i = 0; i < parameters.Length; i++) - { - ParameterInfo p = parameters[i]; - CacheParameterAttribute[] paramInfoArray = (CacheParameterAttribute[])GetCustomAttributes(p, typeof(CacheParameterAttribute)); - parameterInfos[i] = paramInfoArray; - } - cpi = new CacheParameterInfo(parameters, parameterInfos); - _cacheParameterInfoCache[method] = cpi; - } - return cpi; - } + bool isLogDebugEnabled = logger.IsEnabled(LogLevel.Debug); #endregion - /// - /// Executes after target - /// returns successfully. - /// - /// - ///

- /// Note that the supplied cannot - /// be changed by this type of advice... use the around advice type - /// () if you - /// need to change the return value of an advised method invocation. - /// The data encapsulated by the supplied - /// can of course be modified though. - ///

- ///
- /// - /// The value returned by the . - /// - /// The intecepted method. - /// The intercepted method's arguments. - /// The target object. - /// - public void AfterReturning(object returnValue, MethodInfo method, object[] arguments, object target) + CacheParameterInfo cpi = GetCacheParameterInfo(method); + CacheParameterAttribute[][] cacheParameterAttributes = cpi.CacheParameterAttributes; + + if (cacheParameterAttributes.Length > 0) { - #region Instrumentation - bool isLogDebugEnabled = logger.IsEnabled(LogLevel.Debug); - #endregion - - CacheParameterInfo cpi = GetCacheParameterInfo(method); - CacheParameterAttribute[][] cacheParameterAttributes = cpi.CacheParameterAttributes; - - if (cacheParameterAttributes.Length > 0) + IDictionary vars = PrepareVariables(method, arguments); + for (int i = 0; i < cacheParameterAttributes.Length; i++) { - IDictionary vars = PrepareVariables(method, arguments); - for (int i = 0; i < cacheParameterAttributes.Length; i++) + foreach (CacheParameterAttribute paramInfo in cacheParameterAttributes[i]) { - foreach (CacheParameterAttribute paramInfo in cacheParameterAttributes[i]) + AssertUtils.ArgumentNotNull(paramInfo.KeyExpression, "Key", + "The cache attribute is missing the key definition."); + + if (EvalCondition(paramInfo.Condition, paramInfo.ConditionExpression, arguments[i], vars)) { - AssertUtils.ArgumentNotNull(paramInfo.KeyExpression, "Key", - "The cache attribute is missing the key definition."); + ICache cache = GetCache(paramInfo.CacheName); - if (EvalCondition(paramInfo.Condition, paramInfo.ConditionExpression, arguments[i], vars)) + object key = paramInfo.KeyExpression.GetValue(arguments[i], vars); + + #region Instrumentation + + if (isLogDebugEnabled) { - ICache cache = GetCache(paramInfo.CacheName); - - object key = paramInfo.KeyExpression.GetValue(arguments[i], vars); - - #region Instrumentation - if (isLogDebugEnabled) - { - logger.LogDebug(string.Format("Caching parameter for key [{0}] into cache [{1}].", key, paramInfo.CacheName)); - } - #endregion - - cache.Insert(key, arguments[i], paramInfo.TimeToLiveTimeSpan); + logger.LogDebug(string.Format("Caching parameter for key [{0}] into cache [{1}].", key, paramInfo.CacheName)); } + + #endregion + + cache.Insert(key, arguments[i], paramInfo.TimeToLiveTimeSpan); } } } diff --git a/src/Spring/Spring.Aop/Aspects/Cache/CacheParameterAdvisor.cs b/src/Spring/Spring.Aop/Aspects/Cache/CacheParameterAdvisor.cs index ec42fc35..b358fd2e 100644 --- a/src/Spring/Spring.Aop/Aspects/Cache/CacheParameterAdvisor.cs +++ b/src/Spring/Spring.Aop/Aspects/Cache/CacheParameterAdvisor.cs @@ -27,84 +27,83 @@ using Spring.Context; #endregion -namespace Spring.Aspects.Cache +namespace Spring.Aspects.Cache; + +/// +/// Convinience advisor implementation that applies +/// to all the methods that have defined on one or +/// more of their parameters. +/// +/// Aleksandar Seovic +public class CacheParameterAdvisor : AttributeMatchMethodPointcutAdvisor, IApplicationContextAware { /// - /// Convinience advisor implementation that applies - /// to all the methods that have defined on one or - /// more of their parameters. + /// Creates new advisor instance. /// - /// Aleksandar Seovic - public class CacheParameterAdvisor : AttributeMatchMethodPointcutAdvisor, IApplicationContextAware + public CacheParameterAdvisor() { - /// - /// Creates new advisor instance. - /// - public CacheParameterAdvisor() - { - Advice = new CacheParameterAdvice(); - Attribute = typeof(CacheParameterAttribute); - Inherit = false; - } + Advice = new CacheParameterAdvice(); + Attribute = typeof(CacheParameterAttribute); + Inherit = false; + } - /// - /// Sets the that this - /// object runs in. - /// - /// - ///

- /// Normally this call will be used to initialize the object. - ///

- ///

- /// Invoked after population of normal object properties but before an - /// init callback such as - /// 's - /// - /// or a custom init-method. Invoked after the setting of any - /// 's - /// - /// property. - ///

- ///
- /// - /// In the case of application context initialization errors. - /// - /// - /// If thrown by any application context methods. - /// - /// - public IApplicationContext ApplicationContext - { - set { ((IApplicationContextAware)Advice).ApplicationContext = value; } - } + /// + /// Sets the that this + /// object runs in. + /// + /// + ///

+ /// Normally this call will be used to initialize the object. + ///

+ ///

+ /// Invoked after population of normal object properties but before an + /// init callback such as + /// 's + /// + /// or a custom init-method. Invoked after the setting of any + /// 's + /// + /// property. + ///

+ ///
+ /// + /// In the case of application context initialization errors. + /// + /// + /// If thrown by any application context methods. + /// + /// + public IApplicationContext ApplicationContext + { + set { ((IApplicationContextAware) Advice).ApplicationContext = value; } + } - /// - /// Returns true if any of the parameters of the specified - /// has applied. - /// - /// - /// Method to check. - /// - /// - /// Type of target object. - /// - /// - /// true if any of the parameters of the specified - /// has applied; false otherwise. - /// - public override bool Matches(MethodInfo method, Type targetType) + /// + /// Returns true if any of the parameters of the specified + /// has applied. + /// + /// + /// Method to check. + /// + /// + /// Type of target object. + /// + /// + /// true if any of the parameters of the specified + /// has applied; false otherwise. + /// + public override bool Matches(MethodInfo method, Type targetType) + { + ParameterInfo[] parameters = method.GetParameters(); + for (int i = 0; i < parameters.Length; i++) { - ParameterInfo[] parameters = method.GetParameters(); - for (int i = 0; i < parameters.Length; i++) + ParameterInfo p = parameters[i]; + if (p.IsDefined(Attribute, Inherit)) { - ParameterInfo p = parameters[i]; - if (p.IsDefined(Attribute, Inherit)) - { - return true; - } + return true; } - - return false; } + + return false; } } diff --git a/src/Spring/Spring.Aop/Aspects/Cache/CacheResultAdvice.cs b/src/Spring/Spring.Aop/Aspects/Cache/CacheResultAdvice.cs index 9e54d253..91ef534c 100644 --- a/src/Spring/Spring.Aop/Aspects/Cache/CacheResultAdvice.cs +++ b/src/Spring/Spring.Aop/Aspects/Cache/CacheResultAdvice.cs @@ -22,9 +22,7 @@ using System.Collections; using System.Reflection; - using AopAlliance.Intercept; - using Spring.Caching; using Spring.Util; using System.Collections.Concurrent; @@ -32,256 +30,274 @@ using Microsoft.Extensions.Logging; #endregion -namespace Spring.Aspects.Cache +namespace Spring.Aspects.Cache; + +/// +/// Implementation of a result caching advice. +/// +/// +///

+/// This advice can be used to cache the return value of the method. +///

+///

+/// Parameters that determine where, how and for how long the return value +/// will be cached are retrieved from the and/or +/// that are defined on the pointcut. +///

+///
+/// +/// +/// Aleksandar Seovic +public class CacheResultAdvice : BaseCacheAdvice, IMethodInterceptor { + #region CacheResultAttribute & CacheResultItemsAttribute caching + + private class CacheResultInfo + { + public readonly CacheResultAttribute ResultInfo; + public readonly CacheResultItemsAttribute[] ItemInfoArray; + + public CacheResultInfo(CacheResultAttribute resultInfo, CacheResultItemsAttribute[] itemInfoArray) + { + ResultInfo = resultInfo; + ItemInfoArray = itemInfoArray; + } + } + + private readonly ConcurrentDictionary _cacheResultAttributeCache = new(); + + private CacheResultInfo GetCacheResultInfo(MethodInfo method) + { + var cacheResultInfo = _cacheResultAttributeCache.GetOrAdd(method, _ => + { + var resultInfo = (CacheResultAttribute) GetCustomAttribute(method, typeof(CacheResultAttribute)); + var itemInfoArray = (CacheResultItemsAttribute[]) GetCustomAttributes(method, typeof(CacheResultItemsAttribute)); + + return new CacheResultInfo(resultInfo, itemInfoArray); + }); + + return cacheResultInfo; + } + + #endregion + /// - /// Implementation of a result caching advice. + /// Inner class to help cache null values. + /// + [Serializable] + public sealed class NullValueMarkerType + { + /// true when other object is of same type. + public override bool Equals(object obj) + { + return obj is NullValueMarkerType; + } + + /// 13 + public override int GetHashCode() + { + return 13; + } + } + + // NullValue + private static readonly object NullValue = new NullValueMarkerType(); + + /// + /// Applies caching around a method invocation. /// /// ///

- /// This advice can be used to cache the return value of the method. + /// This method tries to retrieve an object from the cache, using the supplied + /// to generate a cache key. If an object is found + /// in the cache, the cached value is returned and the method call does not + /// proceed any further down the invocation chain. ///

///

- /// Parameters that determine where, how and for how long the return value - /// will be cached are retrieved from the and/or - /// that are defined on the pointcut. + /// If object does not exist in the cache, the advised method is called (using + /// ) + /// and any return value is cached for the next method invocation. ///

///
- /// - /// - /// Aleksandar Seovic - public class CacheResultAdvice : BaseCacheAdvice, IMethodInterceptor + /// + /// The method invocation that is being intercepted. + /// + /// + /// A cached object or the result of the + /// call. + /// + /// + /// If any of the interceptors in the chain or the target object itself + /// throws an exception. + /// + public object Invoke(IMethodInvocation invocation) { - #region CacheResultAttribute & CacheResultItemsAttribute caching + CacheResultInfo cacheResultInfo = GetCacheResultInfo(invocation.Method); - private class CacheResultInfo + // prepare variables for SpEL expressions + IDictionary vars = PrepareVariables(invocation.Method, invocation.Arguments); + + bool cacheHit = false; + object returnValue = GetReturnValue(invocation, cacheResultInfo.ResultInfo, vars, out cacheHit); + + if (!cacheHit && cacheResultInfo.ItemInfoArray.Length > 0 && returnValue is IEnumerable) { - public readonly CacheResultAttribute ResultInfo; - public readonly CacheResultItemsAttribute[] ItemInfoArray; - - public CacheResultInfo(CacheResultAttribute resultInfo, CacheResultItemsAttribute[] itemInfoArray) - { - ResultInfo = resultInfo; - ItemInfoArray = itemInfoArray; - } + CacheResultItems((IEnumerable) returnValue, cacheResultInfo.ItemInfoArray, vars); } - private readonly ConcurrentDictionary _cacheResultAttributeCache = new(); + return returnValue; + } - private CacheResultInfo GetCacheResultInfo(MethodInfo method) + /// + /// Obtains return value either from cache or by invoking target method + /// and caches it if necessary. + /// + /// + /// The method invocation that is being intercepted. + /// + /// + /// Attribute specifying where and how to cache return value. Can be null, + /// in which case no caching of the result as a whole will be performed + /// (if the result is collection, individual items could still be cached separately). + /// + /// + /// Variables for expression evaluation. + /// + /// + /// Returns true if the return value was found in cache, false otherwise. + /// + /// + /// Return value for the specified . + /// + private object GetReturnValue(IMethodInvocation invocation, CacheResultAttribute resultInfo, IDictionary vars, out bool cacheHit) + { + if (resultInfo != null) { - var cacheResultInfo = _cacheResultAttributeCache.GetOrAdd(method, _ => + #region Instrumentation + + bool isLogDebugEnabled = logger.IsEnabled(LogLevel.Debug); + + #endregion + + AssertUtils.ArgumentNotNull(resultInfo.KeyExpression, "Key", + "The cache attribute is missing the key definition."); + + object returnValue = null; + object resultKey = resultInfo.KeyExpression.GetValue(null, vars); + + ICache cache = GetCache(resultInfo.CacheName); + returnValue = cache.Get(resultKey); + cacheHit = (returnValue != null); + + if (NullValue.Equals(returnValue)) { - var resultInfo = (CacheResultAttribute) GetCustomAttribute(method, typeof(CacheResultAttribute)); - var itemInfoArray = (CacheResultItemsAttribute[]) GetCustomAttributes(method, typeof(CacheResultItemsAttribute)); - - return new CacheResultInfo(resultInfo, itemInfoArray); - }); - - return cacheResultInfo; - } - - #endregion - - /// - /// Inner class to help cache null values. - /// - [Serializable] public sealed class NullValueMarkerType - { - /// true when other object is of same type. - public override bool Equals(object obj) - { - return obj is NullValueMarkerType; + returnValue = null; } - /// 13 - public override int GetHashCode() + Type returnType = invocation.Method.ReturnType; + if (returnValue != null && !returnType.IsInstanceOfType(returnValue)) { - return 13; + #region Instrumentation + + if (isLogDebugEnabled) + { + logger.LogDebug(String.Format("Object for key [{0}] was of type [{1}] which is not compatible with return type [{2}]. Proceeding...", resultKey, returnValue.GetType(), returnType)); + } + + #endregion + + cacheHit = false; + returnValue = null; } - } - // NullValue - private static readonly object NullValue = new NullValueMarkerType(); - - /// - /// Applies caching around a method invocation. - /// - /// - ///

- /// This method tries to retrieve an object from the cache, using the supplied - /// to generate a cache key. If an object is found - /// in the cache, the cached value is returned and the method call does not - /// proceed any further down the invocation chain. - ///

- ///

- /// If object does not exist in the cache, the advised method is called (using - /// ) - /// and any return value is cached for the next method invocation. - ///

- ///
- /// - /// The method invocation that is being intercepted. - /// - /// - /// A cached object or the result of the - /// call. - /// - /// - /// If any of the interceptors in the chain or the target object itself - /// throws an exception. - /// - public object Invoke(IMethodInvocation invocation) - { - CacheResultInfo cacheResultInfo = GetCacheResultInfo(invocation.Method); - - // prepare variables for SpEL expressions - IDictionary vars = PrepareVariables(invocation.Method, invocation.Arguments); - - bool cacheHit = false; - object returnValue = GetReturnValue(invocation, cacheResultInfo.ResultInfo, vars, out cacheHit); - - if (!cacheHit && cacheResultInfo.ItemInfoArray.Length > 0 && returnValue is IEnumerable) + if (!cacheHit) { - CacheResultItems((IEnumerable)returnValue, cacheResultInfo.ItemInfoArray, vars); + #region Instrumentation + + if (isLogDebugEnabled) + { + logger.LogDebug(String.Format("Object for key [{0}] was not found in cache [{1}]. Proceeding...", resultKey, resultInfo.CacheName)); + } + + #endregion + + returnValue = invocation.Proceed(); + if (EvalCondition(resultInfo.Condition, resultInfo.ConditionExpression, returnValue, vars)) + { + #region Instrumentation + + if (isLogDebugEnabled) + { + logger.LogDebug(String.Format("Caching object for key [{0}] into cache [{1}].", resultKey, resultInfo.CacheName)); + } + + #endregion + + cache.Insert(resultKey, (returnValue == null) ? NullValue : returnValue, resultInfo.TimeToLiveTimeSpan); + } + } + else + { + #region Instrumentation + + if (isLogDebugEnabled) + { + logger.LogDebug(String.Format("Object for key [{0}] found in cache [{1}]. Aborting invocation...", resultKey, resultInfo.CacheName)); + } + + #endregion } return returnValue; } - /// - /// Obtains return value either from cache or by invoking target method - /// and caches it if necessary. - /// - /// - /// The method invocation that is being intercepted. - /// - /// - /// Attribute specifying where and how to cache return value. Can be null, - /// in which case no caching of the result as a whole will be performed - /// (if the result is collection, individual items could still be cached separately). - /// - /// - /// Variables for expression evaluation. - /// - /// - /// Returns true if the return value was found in cache, false otherwise. - /// - /// - /// Return value for the specified . - /// - private object GetReturnValue(IMethodInvocation invocation, CacheResultAttribute resultInfo, IDictionary vars, out bool cacheHit) + cacheHit = false; + return invocation.Proceed(); + } + + /// + /// Caches each item from the collection returned by target method. + /// + /// + /// A collection of items to cache. + /// + /// + /// Attributes specifying where and how to cache each item from the collection. + /// + /// + /// Variables for expression evaluation. + /// + private void CacheResultItems(IEnumerable items, CacheResultItemsAttribute[] itemInfoArray, IDictionary vars) + { + foreach (CacheResultItemsAttribute itemInfo in itemInfoArray) { - if (resultInfo != null) + AssertUtils.ArgumentNotNull(itemInfo.KeyExpression, "Key", + "The cache attribute is missing the key definition."); + + ICache cache = GetCache(itemInfo.CacheName); + + #region Instrumentation + + bool isDebugEnabled = logger.IsEnabled(LogLevel.Debug); + + #endregion + + foreach (object item in items) { - #region Instrumentation - bool isLogDebugEnabled = logger.IsEnabled(LogLevel.Debug); - #endregion - - AssertUtils.ArgumentNotNull(resultInfo.KeyExpression, "Key", - "The cache attribute is missing the key definition."); - - object returnValue = null; - object resultKey = resultInfo.KeyExpression.GetValue(null, vars); - - ICache cache = GetCache(resultInfo.CacheName); - returnValue = cache.Get(resultKey); - cacheHit = (returnValue != null); - - if (NullValue.Equals(returnValue)) + if (EvalCondition(itemInfo.Condition, itemInfo.ConditionExpression, item, vars)) { - returnValue = null; - } + object itemKey = itemInfo.KeyExpression.GetValue(item, vars); - Type returnType = invocation.Method.ReturnType; - if (returnValue != null && !returnType.IsInstanceOfType(returnValue)) - { #region Instrumentation - if (isLogDebugEnabled) + + if (isDebugEnabled) { - logger.LogDebug(String.Format("Object for key [{0}] was of type [{1}] which is not compatible with return type [{2}]. Proceeding...", resultKey, returnValue.GetType(), returnType)); + logger.LogDebug("Caching collection item for key [" + itemKey + "]."); } + #endregion - cacheHit = false; - returnValue = null; - } - - if (!cacheHit) - { - #region Instrumentation - if (isLogDebugEnabled) - { - logger.LogDebug(String.Format("Object for key [{0}] was not found in cache [{1}]. Proceeding...", resultKey, resultInfo.CacheName)); - } - #endregion - - returnValue = invocation.Proceed(); - if (EvalCondition(resultInfo.Condition, resultInfo.ConditionExpression, returnValue, vars)) - { - #region Instrumentation - if (isLogDebugEnabled) - { - logger.LogDebug(String.Format("Caching object for key [{0}] into cache [{1}].", resultKey, resultInfo.CacheName)); - } - #endregion - cache.Insert(resultKey, (returnValue == null) ? NullValue : returnValue, resultInfo.TimeToLiveTimeSpan); - } - } - else - { - #region Instrumentation - if (isLogDebugEnabled) - { - logger.LogDebug(String.Format("Object for key [{0}] found in cache [{1}]. Aborting invocation...", resultKey, resultInfo.CacheName)); - } - #endregion - } - - return returnValue; - } - - cacheHit = false; - return invocation.Proceed(); - } - - /// - /// Caches each item from the collection returned by target method. - /// - /// - /// A collection of items to cache. - /// - /// - /// Attributes specifying where and how to cache each item from the collection. - /// - /// - /// Variables for expression evaluation. - /// - private void CacheResultItems(IEnumerable items, CacheResultItemsAttribute[] itemInfoArray, IDictionary vars) - { - foreach (CacheResultItemsAttribute itemInfo in itemInfoArray) - { - AssertUtils.ArgumentNotNull(itemInfo.KeyExpression, "Key", - "The cache attribute is missing the key definition."); - - ICache cache = GetCache(itemInfo.CacheName); - - #region Instrumentation - bool isDebugEnabled = logger.IsEnabled(LogLevel.Debug); - #endregion - foreach (object item in items) - { - if (EvalCondition(itemInfo.Condition, itemInfo.ConditionExpression, item, vars)) - { - object itemKey = itemInfo.KeyExpression.GetValue(item, vars); - #region Instrumentation - if (isDebugEnabled) - { - logger.LogDebug("Caching collection item for key [" + itemKey + "]."); - } - #endregion - cache.Insert(itemKey, (item == null ? NullValue : item), itemInfo.TimeToLiveTimeSpan); - } + cache.Insert(itemKey, (item == null ? NullValue : item), itemInfo.TimeToLiveTimeSpan); } } } diff --git a/src/Spring/Spring.Aop/Aspects/Cache/CacheResultAdvisor.cs b/src/Spring/Spring.Aop/Aspects/Cache/CacheResultAdvisor.cs index 0c79b9a6..274fcd7a 100644 --- a/src/Spring/Spring.Aop/Aspects/Cache/CacheResultAdvisor.cs +++ b/src/Spring/Spring.Aop/Aspects/Cache/CacheResultAdvisor.cs @@ -26,75 +26,74 @@ using Spring.Context; #endregion -namespace Spring.Aspects.Cache +namespace Spring.Aspects.Cache; + +/// +/// Convinience advisor implementation that applies +/// to all the methods that have defined. +/// +/// Aleksandar Seovic +public class CacheResultAdvisor : AttributeMatchMethodPointcutAdvisor, IApplicationContextAware { /// - /// Convinience advisor implementation that applies - /// to all the methods that have defined. + /// Creates new advisor instance. /// - /// Aleksandar Seovic - public class CacheResultAdvisor : AttributeMatchMethodPointcutAdvisor, IApplicationContextAware + public CacheResultAdvisor() { - /// - /// Creates new advisor instance. - /// - public CacheResultAdvisor() - { - Advice = new CacheResultAdvice(); - Inherit = false; - } + Advice = new CacheResultAdvice(); + Inherit = false; + } - /// - /// Sets the that this - /// object runs in. - /// - /// - ///

- /// Normally this call will be used to initialize the object. - ///

- ///

- /// Invoked after population of normal object properties but before an - /// init callback such as - /// 's - /// - /// or a custom init-method. Invoked after the setting of any - /// 's - /// - /// property. - ///

- ///
- /// - /// In the case of application context initialization errors. - /// - /// - /// If thrown by any application context methods. - /// - /// - public IApplicationContext ApplicationContext - { - set { ((IApplicationContextAware) Advice).ApplicationContext = value; } - } + /// + /// Sets the that this + /// object runs in. + /// + /// + ///

+ /// Normally this call will be used to initialize the object. + ///

+ ///

+ /// Invoked after population of normal object properties but before an + /// init callback such as + /// 's + /// + /// or a custom init-method. Invoked after the setting of any + /// 's + /// + /// property. + ///

+ ///
+ /// + /// In the case of application context initialization errors. + /// + /// + /// If thrown by any application context methods. + /// + /// + public IApplicationContext ApplicationContext + { + set { ((IApplicationContextAware) Advice).ApplicationContext = value; } + } - /// - /// Returns true if either or - /// is applied to the - /// . - /// - /// - /// Method to check. - /// - /// - /// Type of target object. - /// - /// - /// true if either or - /// is applied to the - /// ; false otherwise. - /// - public override bool Matches(System.Reflection.MethodInfo method, Type targetType) - { - return method.IsDefined(typeof (CacheResultAttribute), Inherit) - || method.IsDefined(typeof (CacheResultItemsAttribute), Inherit); - } + /// + /// Returns true if either or + /// is applied to the + /// . + /// + /// + /// Method to check. + /// + /// + /// Type of target object. + /// + /// + /// true if either or + /// is applied to the + /// ; false otherwise. + /// + public override bool Matches(System.Reflection.MethodInfo method, Type targetType) + { + return method.IsDefined(typeof(CacheResultAttribute), Inherit) + || method.IsDefined(typeof(CacheResultItemsAttribute), Inherit); } } diff --git a/src/Spring/Spring.Aop/Aspects/Cache/InvalidateCacheAdvice.cs b/src/Spring/Spring.Aop/Aspects/Cache/InvalidateCacheAdvice.cs index a9d53bb9..219b066c 100644 --- a/src/Spring/Spring.Aop/Aspects/Cache/InvalidateCacheAdvice.cs +++ b/src/Spring/Spring.Aop/Aspects/Cache/InvalidateCacheAdvice.cs @@ -28,122 +28,133 @@ using Spring.Caching; #endregion -namespace Spring.Aspects.Cache +namespace Spring.Aspects.Cache; + +/// +/// Implementation of a cache invalidation advice. +/// +/// +///

+/// This advice can be used to evict items from the cache. +///

+///

+/// Information that determines which items should be evicted and from which cache +/// are retrieved from the s that are defined +/// on the pointcut. +///

+///

+/// Items are evicted *after* target method is invoked. Return value of the method, +/// as well as method arguments, can be used to determine a list of keys for the items +/// that should be evicted (return value will be passed as a context for +/// expression evaluation, and method +/// arguments will be passed as variables, keyed by argument name). +///

+///
+/// +/// Aleksandar Seovic +public class InvalidateCacheAdvice : BaseCacheAdvice, IAfterReturningAdvice { + #region InvalidateCacheAttribute caching + + private readonly Hashtable _invalidateCacheAttributeCache = new Hashtable(); + + private InvalidateCacheAttribute[] GetInvalidateCacheInfo(MethodInfo method) + { + InvalidateCacheAttribute[] cacheInfoArray = (InvalidateCacheAttribute[]) _invalidateCacheAttributeCache[method]; + if (cacheInfoArray == null) + { + cacheInfoArray = (InvalidateCacheAttribute[]) GetCustomAttributes(method, typeof(InvalidateCacheAttribute)); + _invalidateCacheAttributeCache[method] = cacheInfoArray; + } + + return cacheInfoArray; + } + + #endregion + /// - /// Implementation of a cache invalidation advice. + /// Executes after + /// returns successfully. /// /// ///

- /// This advice can be used to evict items from the cache. - ///

- ///

- /// Information that determines which items should be evicted and from which cache - /// are retrieved from the s that are defined - /// on the pointcut. - ///

- ///

- /// Items are evicted *after* target method is invoked. Return value of the method, - /// as well as method arguments, can be used to determine a list of keys for the items - /// that should be evicted (return value will be passed as a context for - /// expression evaluation, and method - /// arguments will be passed as variables, keyed by argument name). + /// Note that the supplied cannot + /// be changed by this type of advice... use the around advice type + /// () if you + /// need to change the return value of an advised method invocation. + /// The data encapsulated by the supplied + /// can of course be modified though. ///

///
- /// - /// Aleksandar Seovic - public class InvalidateCacheAdvice : BaseCacheAdvice, IAfterReturningAdvice + /// + /// The value returned by the . + /// + /// The intecepted method. + /// The intercepted method's arguments. + /// The target object. + /// + public void AfterReturning(object returnValue, MethodInfo method, object[] arguments, object target) { - #region InvalidateCacheAttribute caching + #region Instrumentation - private readonly Hashtable _invalidateCacheAttributeCache = new Hashtable(); - - private InvalidateCacheAttribute[] GetInvalidateCacheInfo(MethodInfo method) - { - InvalidateCacheAttribute[] cacheInfoArray = (InvalidateCacheAttribute[])_invalidateCacheAttributeCache[method]; - if (cacheInfoArray == null) - { - cacheInfoArray = (InvalidateCacheAttribute[])GetCustomAttributes(method, typeof(InvalidateCacheAttribute)); - _invalidateCacheAttributeCache[method] = cacheInfoArray; - } - return cacheInfoArray; - } + bool isLogDebugEnabled = logger.IsEnabled(LogLevel.Debug); #endregion - /// - /// Executes after - /// returns successfully. - /// - /// - ///

- /// Note that the supplied cannot - /// be changed by this type of advice... use the around advice type - /// () if you - /// need to change the return value of an advised method invocation. - /// The data encapsulated by the supplied - /// can of course be modified though. - ///

- ///
- /// - /// The value returned by the . - /// - /// The intecepted method. - /// The intercepted method's arguments. - /// The target object. - /// - public void AfterReturning(object returnValue, MethodInfo method, object[] arguments, object target) + InvalidateCacheAttribute[] cacheInfoArray = GetInvalidateCacheInfo(method); + + if (cacheInfoArray.Length > 0) { - #region Instrumentation - bool isLogDebugEnabled = logger.IsEnabled(LogLevel.Debug); - #endregion - - InvalidateCacheAttribute[] cacheInfoArray = GetInvalidateCacheInfo(method); - - if (cacheInfoArray.Length > 0) + IDictionary vars = PrepareVariables(method, arguments); + foreach (InvalidateCacheAttribute cacheInfo in cacheInfoArray) { - IDictionary vars = PrepareVariables(method, arguments); - foreach (InvalidateCacheAttribute cacheInfo in cacheInfoArray) + if (EvalCondition(cacheInfo.Condition, cacheInfo.ConditionExpression, returnValue, vars)) { - if (EvalCondition(cacheInfo.Condition, cacheInfo.ConditionExpression, returnValue, vars)) - { - ICache cache = GetCache(cacheInfo.CacheName); + ICache cache = GetCache(cacheInfo.CacheName); - if (cacheInfo.KeysExpression != null) + if (cacheInfo.KeysExpression != null) + { + object keys = cacheInfo.KeysExpression.GetValue(returnValue, vars); + if (keys is ICollection) { - object keys = cacheInfo.KeysExpression.GetValue(returnValue, vars); - if (keys is ICollection) + #region Instrumentation + + if (isLogDebugEnabled) { - #region Instrumentation - if (isLogDebugEnabled) - { - logger.LogDebug(string.Format("Removing objects for keys [{0}] from cache [{1}].", keys, cacheInfo.CacheName)); - } - #endregion - cache.RemoveAll((ICollection) keys); - } - else - { - #region Instrumentation - if (isLogDebugEnabled) - { - logger.LogDebug(string.Format("Removing object for key [{0}] from cache [{1}].", keys, cacheInfo.CacheName)); - } - #endregion - cache.Remove(keys); + logger.LogDebug(string.Format("Removing objects for keys [{0}] from cache [{1}].", keys, cacheInfo.CacheName)); } + + #endregion + + cache.RemoveAll((ICollection) keys); } else { #region Instrumentation + if (isLogDebugEnabled) { - logger.LogDebug(string.Format("Invalidate cache [{0}].", cacheInfo.CacheName)); + logger.LogDebug(string.Format("Removing object for key [{0}] from cache [{1}].", keys, cacheInfo.CacheName)); } + #endregion - cache.Clear(); + + cache.Remove(keys); } } + else + { + #region Instrumentation + + if (isLogDebugEnabled) + { + logger.LogDebug(string.Format("Invalidate cache [{0}].", cacheInfo.CacheName)); + } + + #endregion + + cache.Clear(); + } } } } diff --git a/src/Spring/Spring.Aop/Aspects/Cache/InvalidateCacheAdvisor.cs b/src/Spring/Spring.Aop/Aspects/Cache/InvalidateCacheAdvisor.cs index 1a373b73..fec55915 100644 --- a/src/Spring/Spring.Aop/Aspects/Cache/InvalidateCacheAdvisor.cs +++ b/src/Spring/Spring.Aop/Aspects/Cache/InvalidateCacheAdvisor.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -26,54 +26,53 @@ using Spring.Context; #endregion -namespace Spring.Aspects.Cache +namespace Spring.Aspects.Cache; + +/// +/// Convinience advisor implementation that applies +/// to all the methods that have defined. +/// +/// Aleksandar Seovic +public class InvalidateCacheAdvisor : AttributeMatchMethodPointcutAdvisor, IApplicationContextAware { /// - /// Convinience advisor implementation that applies - /// to all the methods that have defined. + /// Creates new advisor instance. /// - /// Aleksandar Seovic - public class InvalidateCacheAdvisor : AttributeMatchMethodPointcutAdvisor, IApplicationContextAware + public InvalidateCacheAdvisor() { - /// - /// Creates new advisor instance. - /// - public InvalidateCacheAdvisor() - { - Advice = new InvalidateCacheAdvice(); - Attribute = typeof(InvalidateCacheAttribute); - Inherit = false; - } - - /// - /// Sets the that this - /// object runs in. - /// - /// - ///

- /// Normally this call will be used to initialize the object. - ///

- ///

- /// Invoked after population of normal object properties but before an - /// init callback such as - /// 's - /// - /// or a custom init-method. Invoked after the setting of any - /// 's - /// - /// property. - ///

- ///
- /// - /// In the case of application context initialization errors. - /// - /// - /// If thrown by any application context methods. - /// - /// - public IApplicationContext ApplicationContext - { - set { ((IApplicationContextAware) Advice).ApplicationContext = value; } - } + Advice = new InvalidateCacheAdvice(); + Attribute = typeof(InvalidateCacheAttribute); + Inherit = false; } -} \ No newline at end of file + + /// + /// Sets the that this + /// object runs in. + /// + /// + ///

+ /// Normally this call will be used to initialize the object. + ///

+ ///

+ /// Invoked after population of normal object properties but before an + /// init callback such as + /// 's + /// + /// or a custom init-method. Invoked after the setting of any + /// 's + /// + /// property. + ///

+ ///
+ /// + /// In the case of application context initialization errors. + /// + /// + /// If thrown by any application context methods. + /// + /// + public IApplicationContext ApplicationContext + { + set { ((IApplicationContextAware) Advice).ApplicationContext = value; } + } +} diff --git a/src/Spring/Spring.Aop/Aspects/Exceptions/ExceptionHandlerAdvice.cs b/src/Spring/Spring.Aop/Aspects/Exceptions/ExceptionHandlerAdvice.cs index 33b0e7a6..2e1f5cf5 100644 --- a/src/Spring/Spring.Aop/Aspects/Exceptions/ExceptionHandlerAdvice.cs +++ b/src/Spring/Spring.Aop/Aspects/Exceptions/ExceptionHandlerAdvice.cs @@ -20,615 +20,621 @@ using System.Collections; using System.Reflection; - using AopAlliance.Intercept; using Microsoft.Extensions.Logging; using Spring.Util; -namespace Spring.Aspects.Exceptions +namespace Spring.Aspects.Exceptions; + +/// +/// Exception advice to perform exception translation, conversion of exceptions to default return values, and +/// exception swallowing. Configuration is via a DSL like string for ease of use in common cases as well as +/// allowing for custom translation logic by leveraging the Spring expression language. +/// +/// +/// +/// The exception handler collection can be filled with either instances of objects that implement the interface +/// or a string that follows a simple syntax for most common exception management +/// needs. The source exceptions to perform processing on are listed immediately after the keyword 'on' and can +/// be comma delmited. Following that is the action to perform, either log, translate, wrap, replace, return, or +/// swallow. Following the action is a Spring expression language (SpEL) fragment that is used to either create the +/// translated/wrapped/replaced exception or specify an alternative return value. The variables available to be +/// used in the expression language fragment are, #method, #args, #target, and #e which are 1) the method that +/// threw the exception, the arguments to the method, the target object itself, and the exception that was thrown. +/// Using SpEL gives you great flexibility in creating a translation of an exception that has access to the calling context. +/// +/// Common translation cases, wrap and rethrow, are supported with a shorter syntax where you can specify only +/// the exception text for the new translated exception. If you ommit the exception text a default value will be +/// used. +/// The exceptionsHandlers are compared to the thrown exception in the order they are listed. logging +/// an exception will continue the evaluation process, in all other cases exceution stops at that point and the +/// appropriate exceptions handler is executed. +/// +/// +/// +/// on FooException1 log 'My Message, Method Name ' + #method.Name +/// on FooException1 translate new BarException('My Message, Method Called = ' + #method.Name", #e) +/// on FooException2,Foo3Exception wrap BarException 'My Bar Message' +/// on FooException4 replace BarException 'My Bar Message' +/// on FooException5 return 32 +/// on FooException6 swallow +/// +/// +/// +/// +/// +/// +/// Mark Pollack +[Serializable] +public class ExceptionHandlerAdvice : AbstractExceptionHandlerAdvice { + #region Fields + /// - /// Exception advice to perform exception translation, conversion of exceptions to default return values, and - /// exception swallowing. Configuration is via a DSL like string for ease of use in common cases as well as - /// allowing for custom translation logic by leveraging the Spring expression language. + /// Log instance available to subclasses + /// + protected static ILogger log = LogManager.GetLogger(); + + private IList exceptionHandlers = new ArrayList(); + + /// + /// Holds shared handler definition templates + /// + private ExceptionHandlerTable exceptionHandlerTable = new ExceptionHandlerTable(); + + private string onExceptionNameRegex = @"^(on\s+exception\s+name)\s+(.*?)\s+(log|translate|wrap|replace|return|swallow|execute)\s*(.*?)$"; + + private string onExceptionRegex = @"^(on\s+exception\s+)(\(.*?\))\s+(log|translate|wrap|replace|return|swallow|execute)\s*(.*?)$"; + + #endregion + + #region Properties + + /// + /// Gets or sets the Regex string used to parse advice expressions starting with 'on exception name' and exception handling actions. + /// + /// The regex string to parse advice expressions starting with 'on exception name' and exception handling actions. + public override string OnExceptionNameRegex + { + get { return onExceptionNameRegex; } + set { onExceptionNameRegex = value; } + } + + /// + /// Gets or sets the Regex string used to parse advice expressions starting with 'on exception (constraint)' and exception handling actions. + /// + /// The regex string to parse advice expressions starting with 'on exception (constraint)' and exception handling actions. + public override string OnExceptionRegex + { + get { return onExceptionRegex; } + set { onExceptionRegex = value; } + } + + /// + /// Gets or sets the exception handler. + /// + /// The exception handler. + public IList ExceptionHandlers + { + get { return exceptionHandlers; } + set { exceptionHandlers = value; } + } + + /// + /// Gets the exception handler dictionary. Allows for registration of a specific handler where the key + /// is the action type. This makes configuration of a custom exception handler easier, for example + /// LogExceptionHandler, in that only 'user friendly' properties such as LogName, etc., need to be configured + /// and not 'user unfriendly' properties such as ConstraintExpressionText and ActionExpressionText. + /// + /// The exception handler dictionary. + public ExceptionHandlerTable ExceptionHandlerDictionary + { + get { return exceptionHandlerTable; } + } + + #endregion + + #region IMethodInterceptor implementation + + /// + /// Implement this method to perform extra treatments before and after + /// the call to the supplied . /// /// - /// - /// The exception handler collection can be filled with either instances of objects that implement the interface - /// or a string that follows a simple syntax for most common exception management - /// needs. The source exceptions to perform processing on are listed immediately after the keyword 'on' and can - /// be comma delmited. Following that is the action to perform, either log, translate, wrap, replace, return, or - /// swallow. Following the action is a Spring expression language (SpEL) fragment that is used to either create the - /// translated/wrapped/replaced exception or specify an alternative return value. The variables available to be - /// used in the expression language fragment are, #method, #args, #target, and #e which are 1) the method that - /// threw the exception, the arguments to the method, the target object itself, and the exception that was thrown. - /// Using SpEL gives you great flexibility in creating a translation of an exception that has access to the calling context. - /// - /// Common translation cases, wrap and rethrow, are supported with a shorter syntax where you can specify only - /// the exception text for the new translated exception. If you ommit the exception text a default value will be - /// used. - /// The exceptionsHandlers are compared to the thrown exception in the order they are listed. logging - /// an exception will continue the evaluation process, in all other cases exceution stops at that point and the - /// appropriate exceptions handler is executed. - /// - /// - /// - /// on FooException1 log 'My Message, Method Name ' + #method.Name - /// on FooException1 translate new BarException('My Message, Method Called = ' + #method.Name", #e) - /// on FooException2,Foo3Exception wrap BarException 'My Bar Message' - /// on FooException4 replace BarException 'My Bar Message' - /// on FooException5 return 32 - /// on FooException6 swallow - /// - /// - /// - /// - /// + ///

+ /// Polite implementations would certainly like to invoke + /// . + ///

///
- /// Mark Pollack - [Serializable] - public class ExceptionHandlerAdvice : AbstractExceptionHandlerAdvice + /// + /// The method invocation that is being intercepted. + /// + /// + /// The result of the call to the + /// method of + /// the supplied ; this return value may + /// well have been intercepted by the interceptor. + /// + /// + /// If any of the interceptors in the chain or the target object itself + /// throws an exception. + /// + public override object Invoke(IMethodInvocation invocation) { - #region Fields - - /// - /// Log instance available to subclasses - /// - protected static ILogger log = LogManager.GetLogger(); - - private IList exceptionHandlers = new ArrayList(); - - /// - /// Holds shared handler definition templates - /// - private ExceptionHandlerTable exceptionHandlerTable = new ExceptionHandlerTable(); - - private string onExceptionNameRegex = @"^(on\s+exception\s+name)\s+(.*?)\s+(log|translate|wrap|replace|return|swallow|execute)\s*(.*?)$"; - - private string onExceptionRegex = @"^(on\s+exception\s+)(\(.*?\))\s+(log|translate|wrap|replace|return|swallow|execute)\s*(.*?)$"; - - #endregion - - #region Properties - - /// - /// Gets or sets the Regex string used to parse advice expressions starting with 'on exception name' and exception handling actions. - /// - /// The regex string to parse advice expressions starting with 'on exception name' and exception handling actions. - public override string OnExceptionNameRegex + try { - get { return onExceptionNameRegex; } - set { onExceptionNameRegex = value; } + return invocation.Proceed(); } - - /// - /// Gets or sets the Regex string used to parse advice expressions starting with 'on exception (constraint)' and exception handling actions. - /// - /// The regex string to parse advice expressions starting with 'on exception (constraint)' and exception handling actions. - public override string OnExceptionRegex + catch (TargetInvocationException ex) { - get { return onExceptionRegex; } - set { onExceptionRegex = value; } + Exception realException = ex.InnerException; + InvokeHandlers(realException, invocation); + throw realException; } - - /// - /// Gets or sets the exception handler. - /// - /// The exception handler. - public IList ExceptionHandlers + catch (Exception ex) { - get { return exceptionHandlers; } - set { exceptionHandlers = value; } - } + object returnVal = InvokeHandlers(ex, invocation); - - /// - /// Gets the exception handler dictionary. Allows for registration of a specific handler where the key - /// is the action type. This makes configuration of a custom exception handler easier, for example - /// LogExceptionHandler, in that only 'user friendly' properties such as LogName, etc., need to be configured - /// and not 'user unfriendly' properties such as ConstraintExpressionText and ActionExpressionText. - /// - /// The exception handler dictionary. - public ExceptionHandlerTable ExceptionHandlerDictionary - { - get { return exceptionHandlerTable; } - } - - #endregion - - #region IMethodInterceptor implementation - - /// - /// Implement this method to perform extra treatments before and after - /// the call to the supplied . - /// - /// - ///

- /// Polite implementations would certainly like to invoke - /// . - ///

- ///
- /// - /// The method invocation that is being intercepted. - /// - /// - /// The result of the call to the - /// method of - /// the supplied ; this return value may - /// well have been intercepted by the interceptor. - /// - /// - /// If any of the interceptors in the chain or the target object itself - /// throws an exception. - /// - public override object Invoke(IMethodInvocation invocation) - { - try + if (returnVal == null) { - return invocation.Proceed(); - } - catch (TargetInvocationException ex) - { - Exception realException = ex.InnerException; - InvokeHandlers(realException, invocation); - throw realException; - } - catch (Exception ex) - { - object returnVal = InvokeHandlers(ex, invocation); - - if (returnVal == null) - { - return null; - } - - // if only logged - if (returnVal.Equals("logged")) - { - throw; - } - - //only here if we only are swallowing, returning alternative value, no matching handler was found. - - // no matching handler. - if (returnVal.Equals("nomatch")) - { - throw; - } - else - { - //TODO make spring specific value. - if (!returnVal.Equals("swallow")) - { - return returnVal; - } - else - { - Type returnType = invocation.Method.ReturnType; - return returnType.IsValueType && !returnType.Equals(typeof(void))? Activator.CreateInstance(returnType) : null; - } - } - } - } - - #endregion - - #region IInitializingObject implementation - - /// - /// Invoked by an - /// after it has injected all of an object's dependencies. - /// - /// - ///

- /// This method allows the object instance to perform the kind of - /// initialization only possible when all of it's dependencies have - /// been injected (set), and to throw an appropriate exception in the - /// event of misconfiguration. - ///

- ///

- /// Please do consult the class level documentation for the - /// interface for a - /// description of exactly when this method is invoked. In - /// particular, it is worth noting that the - /// - /// and - /// callbacks will have been invoked prior to this method being - /// called. - ///

- ///
- /// - /// In the event of misconfiguration (such as the failure to set a - /// required property) or if initialization fails. - /// - public override void AfterPropertiesSet() - { - if (exceptionHandlers.Count == 0) - { - throw new ArgumentException("At least one handler is required"); - } - IList newExceptionHandlers = new ArrayList(); - foreach (object o in exceptionHandlers) - { - string handlerString = o as string; - if (handlerString != null) - { - IExceptionHandler handler = Parse(handlerString); - if (handler == null) - { - throw new ArgumentException("Was not able to parse exception handler string [" + handlerString + - "]"); - } - newExceptionHandlers.Add(handler); - } - //explicitly configured advice, must also configure ConstraintExpressionText and ActionExpressionText! - IExceptionHandler handlerObject = o as IExceptionHandler; - if (handlerObject != null) - { - newExceptionHandlers.Add(handlerObject); - } - - } - //TODO sync. - exceptionHandlers = newExceptionHandlers; - } - - #endregion - - #region Methods - - /// - /// Invokes handlers registered for the passed exception and - /// - /// The exception to be handled - /// The that raised this exception. - /// The output of - protected virtual object InvokeHandlers(Exception ex, IMethodInvocation invocation) - { - Dictionary callContextDictionary = new Dictionary(); - callContextDictionary.Add("method", invocation.Method); - callContextDictionary.Add("args", invocation.Arguments); - callContextDictionary.Add("target", invocation.Target); - callContextDictionary.Add("e", ex); - object retValue = "nomatch"; - foreach (IExceptionHandler handler in exceptionHandlers) - { - if (handler != null) - { - if (handler.CanHandleException(ex, callContextDictionary)) - { - retValue = handler.HandleException(callContextDictionary); - if (!handler.ContinueProcessing) - { - return retValue; - } - } - } - } - return retValue; - } - - /// - /// Parses the specified handler string, creating an instance of IExceptionHander. - /// - /// The handler string. - /// an instance of an exception handler or null if was not able to correctly parse - /// handler string. - protected virtual IExceptionHandler Parse(string handlerString) - { - ParsedAdviceExpression parsedAdviceExpression = ParseAdviceExpression(handlerString); - - if (!parsedAdviceExpression.Success) - { - log.LogWarning("Could not parse exception hander statement " + handlerString); return null; } - return CreateExceptionHandler(parsedAdviceExpression); - } + // if only logged + if (returnVal.Equals("logged")) + { + throw; + } - /// - /// Creates the exception handler. - /// - /// The parsed advice expression. - /// The exception handler instance - protected virtual IExceptionHandler CreateExceptionHandler(ParsedAdviceExpression parsedAdviceExpression) - { - if (parsedAdviceExpression.ActionText.IndexOf("log") >= 0) - { - IExceptionHandler handler; - if (exceptionHandlerTable.ContainsKey("log")) - { - handler = exceptionHandlerTable["log"]; - AddExceptionNames(parsedAdviceExpression, handler); - } else - { - handler = CreateLogExceptionHandler(parsedAdviceExpression.ExceptionNames); - } - handler.ConstraintExpressionText = parsedAdviceExpression.ConstraintExpression; - handler.ActionExpressionText = parsedAdviceExpression.ActionExpressionText; - return handler; - } - else if (parsedAdviceExpression.ActionText.IndexOf("translate") >= 0) - { - IExceptionHandler handler; - if (exceptionHandlerTable.Contains("translate")) - { - handler = exceptionHandlerTable["translate"]; - AddExceptionNames(parsedAdviceExpression, handler); - } - else - { - handler = CreateTranslationExceptionHandler(parsedAdviceExpression.ExceptionNames); - } - handler.ConstraintExpressionText = parsedAdviceExpression.ConstraintExpression; - handler.ActionExpressionText = parsedAdviceExpression.ActionExpressionText; - return handler; - } - else if (parsedAdviceExpression.ActionText.IndexOf("wrap") >= 0) - { + //only here if we only are swallowing, returning alternative value, no matching handler was found. - IExceptionHandler handler; - if (exceptionHandlerTable.Contains("wrap")) - { - handler = exceptionHandlerTable["wrap"]; - AddExceptionNames(parsedAdviceExpression, handler); - } - else - { - handler = CreateTranslationExceptionHandler(parsedAdviceExpression.ExceptionNames); - } - handler.ConstraintExpressionText = parsedAdviceExpression.ConstraintExpression; - handler.ActionExpressionText = ParseWrappedExceptionExpression("wrap", parsedAdviceExpression.AdviceExpression); - return handler; - } - else if (parsedAdviceExpression.ActionText.IndexOf("replace") >= 0) + // no matching handler. + if (returnVal.Equals("nomatch")) { - - IExceptionHandler handler; - if (exceptionHandlerTable.Contains("replace")) - { - handler = exceptionHandlerTable["replace"]; - AddExceptionNames(parsedAdviceExpression, handler); - } else - { - handler = CreateTranslationExceptionHandler(parsedAdviceExpression.ExceptionNames); - } - handler.ConstraintExpressionText = parsedAdviceExpression.ConstraintExpression; - handler.ActionExpressionText = ParseWrappedExceptionExpression("replace", parsedAdviceExpression.AdviceExpression); - return handler; - } - else if (parsedAdviceExpression.ActionText.IndexOf("swallow") >= 0) - { - - IExceptionHandler handler; - if (exceptionHandlerTable.Contains("swallow")) - { - handler = exceptionHandlerTable["swallow"]; - AddExceptionNames(parsedAdviceExpression, handler); - } - else - { - handler = CreateSwallowExceptionHander(parsedAdviceExpression); - } - handler.ConstraintExpressionText = parsedAdviceExpression.ConstraintExpression; - return handler; - } - else if (parsedAdviceExpression.ActionText.IndexOf("return") >= 0) - { - - IExceptionHandler handler; - if (exceptionHandlerTable.Contains("return")) - { - handler = exceptionHandlerTable["return"]; - AddExceptionNames(parsedAdviceExpression, handler); - } - else - { - handler = CreateReturnValueExceptionHandler(parsedAdviceExpression); - } - handler.ConstraintExpressionText = parsedAdviceExpression.ConstraintExpression; - handler.ActionExpressionText = parsedAdviceExpression.ActionExpressionText; - return handler; - } - else if (parsedAdviceExpression.ActionText.IndexOf("execute") >= 0) - { - IExceptionHandler handler; - if (exceptionHandlerTable.Contains("execute")) - { - handler = exceptionHandlerTable["execute"]; - AddExceptionNames(parsedAdviceExpression, handler); - } - else - { - handler = CreateExecuteSpelExceptionHandler(parsedAdviceExpression); - } - handler.ConstraintExpressionText = parsedAdviceExpression.ConstraintExpression; - handler.ActionExpressionText = parsedAdviceExpression.ActionExpressionText; - return handler; + throw; } else { - log.LogWarning("Could not parse exception hander statement " + parsedAdviceExpression.AdviceExpression); - } - return null; - } - - /// - /// Creates the execute spel exception handler. - /// - /// The parsed advice expression. - /// - protected virtual IExceptionHandler CreateExecuteSpelExceptionHandler(ParsedAdviceExpression parsedAdviceExpression) - { - IExceptionHandler handler; - handler = new ExecuteSpelExceptionHandler(parsedAdviceExpression.ExceptionNames); - return handler; - } - - /// - /// Creates the return value exception handler. - /// - /// The parsed advice expression. - /// - protected virtual IExceptionHandler CreateReturnValueExceptionHandler(ParsedAdviceExpression parsedAdviceExpression) - { - IExceptionHandler handler; - handler = new ReturnValueExceptionHandler(parsedAdviceExpression.ExceptionNames); - return handler; - } - - /// - /// Creates the swallow exception hander. - /// - /// The parsed advice expression. - /// - protected virtual IExceptionHandler CreateSwallowExceptionHander(ParsedAdviceExpression parsedAdviceExpression) - { - IExceptionHandler handler; - handler = new SwallowExceptionHandler(parsedAdviceExpression.ExceptionNames); - return handler; - } - - /// - /// Creates the translation exception handler. - /// - /// The exception names. - /// - protected virtual IExceptionHandler CreateTranslationExceptionHandler(string[] exceptionNames) - { - return new TranslationExceptionHandler(exceptionNames); - } - - /// - /// Creates the log exception handler. - /// - /// The exception names. - /// Log exception - protected virtual LogExceptionHandler CreateLogExceptionHandler(string[] exceptionNames) - { - return new LogExceptionHandler(exceptionNames); - } - - /// - /// Parses the wrapped exception expression. - /// - /// The action. - /// The handler string. - /// - protected string ParseWrappedExceptionExpression(string action, string handlerString) - { - int endOfActionIndex = handlerString.IndexOf(action) + action.Length; - string exceptionAndMessage = handlerString.Substring(endOfActionIndex).Trim(); - int endOfExceptionTypeIndex = exceptionAndMessage.IndexOf(" "); - - string rawExpressionTextPart; - string exception; - //Has two pieces. - if (endOfExceptionTypeIndex > 0) - { - exception = exceptionAndMessage.Substring(0, endOfExceptionTypeIndex).Trim(); - rawExpressionTextPart = exceptionAndMessage.Substring(endOfExceptionTypeIndex).Trim(); - } - else - { - exception = exceptionAndMessage; - if (action.Equals("wrap")) + //TODO make spring specific value. + if (!returnVal.Equals("swallow")) { - rawExpressionTextPart = "'Wrapped ' + #e.GetType().Name"; - } else + return returnVal; + } + else { - rawExpressionTextPart = "'Replaced ' + #e.GetType().Name"; + Type returnType = invocation.Method.ReturnType; + return returnType.IsValueType && !returnType.Equals(typeof(void)) ? Activator.CreateInstance(returnType) : null; } } + } + } - if (action.Equals("wrap")) - { - return string.Format("new {0}({1}, #e)", exception, rawExpressionTextPart); - } else - { - return string.Format("new {0}({1})", exception, rawExpressionTextPart); - } + #endregion + + #region IInitializingObject implementation + + /// + /// Invoked by an + /// after it has injected all of an object's dependencies. + /// + /// + ///

+ /// This method allows the object instance to perform the kind of + /// initialization only possible when all of it's dependencies have + /// been injected (set), and to throw an appropriate exception in the + /// event of misconfiguration. + ///

+ ///

+ /// Please do consult the class level documentation for the + /// interface for a + /// description of exactly when this method is invoked. In + /// particular, it is worth noting that the + /// + /// and + /// callbacks will have been invoked prior to this method being + /// called. + ///

+ ///
+ /// + /// In the event of misconfiguration (such as the failure to set a + /// required property) or if initialization fails. + /// + public override void AfterPropertiesSet() + { + if (exceptionHandlers.Count == 0) + { + throw new ArgumentException("At least one handler is required"); } - - private void AddExceptionNames(ParsedAdviceExpression parsedAdviceExpression, IExceptionHandler handler) + IList newExceptionHandlers = new ArrayList(); + foreach (object o in exceptionHandlers) { - foreach (string exceptionName in parsedAdviceExpression.ExceptionNames) + string handlerString = o as string; + if (handlerString != null) { - handler.SourceExceptionNames.Add(exceptionName); - } - } - - #endregion - - #region ExceptionHandlerTable class - - /// - /// A specialized dictionary for key value pairs of (string, IExceptionHandler) - /// - public class ExceptionHandlerTable : Hashtable - { - /// - /// Adds the specified key. - /// - /// The key. - /// The value. - public void Add(string key, IExceptionHandler value) - { - lock (SyncRoot) + IExceptionHandler handler = Parse(handlerString); + if (handler == null) { - base[key] = value; + throw new ArgumentException("Was not able to parse exception handler string [" + handlerString + + "]"); } + + newExceptionHandlers.Add(handler); } - /// - /// Gets the with the specified key. - /// - /// - public IExceptionHandler this[string key] + //explicitly configured advice, must also configure ConstraintExpressionText and ActionExpressionText! + IExceptionHandler handlerObject = o as IExceptionHandler; + if (handlerObject != null) { - get + newExceptionHandlers.Add(handlerObject); + } + } + + //TODO sync. + exceptionHandlers = newExceptionHandlers; + } + + #endregion + + #region Methods + + /// + /// Invokes handlers registered for the passed exception and + /// + /// The exception to be handled + /// The that raised this exception. + /// The output of + protected virtual object InvokeHandlers(Exception ex, IMethodInvocation invocation) + { + Dictionary callContextDictionary = new Dictionary(); + callContextDictionary.Add("method", invocation.Method); + callContextDictionary.Add("args", invocation.Arguments); + callContextDictionary.Add("target", invocation.Target); + callContextDictionary.Add("e", ex); + object retValue = "nomatch"; + foreach (IExceptionHandler handler in exceptionHandlers) + { + if (handler != null) + { + if (handler.CanHandleException(ex, callContextDictionary)) { - lock (SyncRoot) + retValue = handler.HandleException(callContextDictionary); + if (!handler.ContinueProcessing) { - return (IExceptionHandler)base[key]; + return retValue; } } } + } - /// - /// Adds an element with the specified key and value into the . - /// - /// The key of the element to add. - /// The value of the element to add. The value can be null. - /// - /// is null. - /// An element with the same key already exists in the . - /// or key is not a string or value is not an IExceptionHandler. - /// The is read-only.-or- The has a fixed size. - public override void Add(object key, object value) + return retValue; + } + + /// + /// Parses the specified handler string, creating an instance of IExceptionHander. + /// + /// The handler string. + /// an instance of an exception handler or null if was not able to correctly parse + /// handler string. + protected virtual IExceptionHandler Parse(string handlerString) + { + ParsedAdviceExpression parsedAdviceExpression = ParseAdviceExpression(handlerString); + + if (!parsedAdviceExpression.Success) + { + log.LogWarning("Could not parse exception hander statement " + handlerString); + return null; + } + + return CreateExceptionHandler(parsedAdviceExpression); + } + + /// + /// Creates the exception handler. + /// + /// The parsed advice expression. + /// The exception handler instance + protected virtual IExceptionHandler CreateExceptionHandler(ParsedAdviceExpression parsedAdviceExpression) + { + if (parsedAdviceExpression.ActionText.IndexOf("log") >= 0) + { + IExceptionHandler handler; + if (exceptionHandlerTable.ContainsKey("log")) { - AssertUtils.AssertArgumentType(key, "key", typeof(string), "Key must be a string"); - AssertUtils.AssertArgumentType(value, "value", typeof(IExceptionHandler), "Key must be a IExceptionHandler"); - this.Add((string)key, (IExceptionHandler)value); + handler = exceptionHandlerTable["log"]; + AddExceptionNames(parsedAdviceExpression, handler); + } + else + { + handler = CreateLogExceptionHandler(parsedAdviceExpression.ExceptionNames); } - /// - /// Gets the with the specified key. - /// - /// - public override object this[object key] + handler.ConstraintExpressionText = parsedAdviceExpression.ConstraintExpression; + handler.ActionExpressionText = parsedAdviceExpression.ActionExpressionText; + return handler; + } + else if (parsedAdviceExpression.ActionText.IndexOf("translate") >= 0) + { + IExceptionHandler handler; + if (exceptionHandlerTable.Contains("translate")) { - get + handler = exceptionHandlerTable["translate"]; + AddExceptionNames(parsedAdviceExpression, handler); + } + else + { + handler = CreateTranslationExceptionHandler(parsedAdviceExpression.ExceptionNames); + } + + handler.ConstraintExpressionText = parsedAdviceExpression.ConstraintExpression; + handler.ActionExpressionText = parsedAdviceExpression.ActionExpressionText; + return handler; + } + else if (parsedAdviceExpression.ActionText.IndexOf("wrap") >= 0) + { + IExceptionHandler handler; + if (exceptionHandlerTable.Contains("wrap")) + { + handler = exceptionHandlerTable["wrap"]; + AddExceptionNames(parsedAdviceExpression, handler); + } + else + { + handler = CreateTranslationExceptionHandler(parsedAdviceExpression.ExceptionNames); + } + + handler.ConstraintExpressionText = parsedAdviceExpression.ConstraintExpression; + handler.ActionExpressionText = ParseWrappedExceptionExpression("wrap", parsedAdviceExpression.AdviceExpression); + return handler; + } + else if (parsedAdviceExpression.ActionText.IndexOf("replace") >= 0) + { + IExceptionHandler handler; + if (exceptionHandlerTable.Contains("replace")) + { + handler = exceptionHandlerTable["replace"]; + AddExceptionNames(parsedAdviceExpression, handler); + } + else + { + handler = CreateTranslationExceptionHandler(parsedAdviceExpression.ExceptionNames); + } + + handler.ConstraintExpressionText = parsedAdviceExpression.ConstraintExpression; + handler.ActionExpressionText = ParseWrappedExceptionExpression("replace", parsedAdviceExpression.AdviceExpression); + return handler; + } + else if (parsedAdviceExpression.ActionText.IndexOf("swallow") >= 0) + { + IExceptionHandler handler; + if (exceptionHandlerTable.Contains("swallow")) + { + handler = exceptionHandlerTable["swallow"]; + AddExceptionNames(parsedAdviceExpression, handler); + } + else + { + handler = CreateSwallowExceptionHander(parsedAdviceExpression); + } + + handler.ConstraintExpressionText = parsedAdviceExpression.ConstraintExpression; + return handler; + } + else if (parsedAdviceExpression.ActionText.IndexOf("return") >= 0) + { + IExceptionHandler handler; + if (exceptionHandlerTable.Contains("return")) + { + handler = exceptionHandlerTable["return"]; + AddExceptionNames(parsedAdviceExpression, handler); + } + else + { + handler = CreateReturnValueExceptionHandler(parsedAdviceExpression); + } + + handler.ConstraintExpressionText = parsedAdviceExpression.ConstraintExpression; + handler.ActionExpressionText = parsedAdviceExpression.ActionExpressionText; + return handler; + } + else if (parsedAdviceExpression.ActionText.IndexOf("execute") >= 0) + { + IExceptionHandler handler; + if (exceptionHandlerTable.Contains("execute")) + { + handler = exceptionHandlerTable["execute"]; + AddExceptionNames(parsedAdviceExpression, handler); + } + else + { + handler = CreateExecuteSpelExceptionHandler(parsedAdviceExpression); + } + + handler.ConstraintExpressionText = parsedAdviceExpression.ConstraintExpression; + handler.ActionExpressionText = parsedAdviceExpression.ActionExpressionText; + return handler; + } + else + { + log.LogWarning("Could not parse exception hander statement " + parsedAdviceExpression.AdviceExpression); + } + + return null; + } + + /// + /// Creates the execute spel exception handler. + /// + /// The parsed advice expression. + /// + protected virtual IExceptionHandler CreateExecuteSpelExceptionHandler(ParsedAdviceExpression parsedAdviceExpression) + { + IExceptionHandler handler; + handler = new ExecuteSpelExceptionHandler(parsedAdviceExpression.ExceptionNames); + return handler; + } + + /// + /// Creates the return value exception handler. + /// + /// The parsed advice expression. + /// + protected virtual IExceptionHandler CreateReturnValueExceptionHandler(ParsedAdviceExpression parsedAdviceExpression) + { + IExceptionHandler handler; + handler = new ReturnValueExceptionHandler(parsedAdviceExpression.ExceptionNames); + return handler; + } + + /// + /// Creates the swallow exception hander. + /// + /// The parsed advice expression. + /// + protected virtual IExceptionHandler CreateSwallowExceptionHander(ParsedAdviceExpression parsedAdviceExpression) + { + IExceptionHandler handler; + handler = new SwallowExceptionHandler(parsedAdviceExpression.ExceptionNames); + return handler; + } + + /// + /// Creates the translation exception handler. + /// + /// The exception names. + /// + protected virtual IExceptionHandler CreateTranslationExceptionHandler(string[] exceptionNames) + { + return new TranslationExceptionHandler(exceptionNames); + } + + /// + /// Creates the log exception handler. + /// + /// The exception names. + /// Log exception + protected virtual LogExceptionHandler CreateLogExceptionHandler(string[] exceptionNames) + { + return new LogExceptionHandler(exceptionNames); + } + + /// + /// Parses the wrapped exception expression. + /// + /// The action. + /// The handler string. + /// + protected string ParseWrappedExceptionExpression(string action, string handlerString) + { + int endOfActionIndex = handlerString.IndexOf(action) + action.Length; + string exceptionAndMessage = handlerString.Substring(endOfActionIndex).Trim(); + int endOfExceptionTypeIndex = exceptionAndMessage.IndexOf(" "); + + string rawExpressionTextPart; + string exception; + //Has two pieces. + if (endOfExceptionTypeIndex > 0) + { + exception = exceptionAndMessage.Substring(0, endOfExceptionTypeIndex).Trim(); + rawExpressionTextPart = exceptionAndMessage.Substring(endOfExceptionTypeIndex).Trim(); + } + else + { + exception = exceptionAndMessage; + if (action.Equals("wrap")) + { + rawExpressionTextPart = "'Wrapped ' + #e.GetType().Name"; + } + else + { + rawExpressionTextPart = "'Replaced ' + #e.GetType().Name"; + } + } + + if (action.Equals("wrap")) + { + return string.Format("new {0}({1}, #e)", exception, rawExpressionTextPart); + } + else + { + return string.Format("new {0}({1})", exception, rawExpressionTextPart); + } + } + + private void AddExceptionNames(ParsedAdviceExpression parsedAdviceExpression, IExceptionHandler handler) + { + foreach (string exceptionName in parsedAdviceExpression.ExceptionNames) + { + handler.SourceExceptionNames.Add(exceptionName); + } + } + + #endregion + + #region ExceptionHandlerTable class + + /// + /// A specialized dictionary for key value pairs of (string, IExceptionHandler) + /// + public class ExceptionHandlerTable : Hashtable + { + /// + /// Adds the specified key. + /// + /// The key. + /// The value. + public void Add(string key, IExceptionHandler value) + { + lock (SyncRoot) + { + base[key] = value; + } + } + + /// + /// Gets the with the specified key. + /// + /// + public IExceptionHandler this[string key] + { + get + { + lock (SyncRoot) { - return this[(string)key]; + return (IExceptionHandler) base[key]; } } } - #endregion + /// + /// Adds an element with the specified key and value into the . + /// + /// The key of the element to add. + /// The value of the element to add. The value can be null. + /// + /// is null. + /// An element with the same key already exists in the . + /// or key is not a string or value is not an IExceptionHandler. + /// The is read-only.-or- The has a fixed size. + public override void Add(object key, object value) + { + AssertUtils.AssertArgumentType(key, "key", typeof(string), "Key must be a string"); + AssertUtils.AssertArgumentType(value, "value", typeof(IExceptionHandler), "Key must be a IExceptionHandler"); + this.Add((string) key, (IExceptionHandler) value); + } + + /// + /// Gets the with the specified key. + /// + /// + public override object this[object key] + { + get + { + return this[(string) key]; + } + } } - + #endregion } diff --git a/src/Spring/Spring.Aop/Aspects/Exceptions/ExecuteSpelExceptionHandler.cs b/src/Spring/Spring.Aop/Aspects/Exceptions/ExecuteSpelExceptionHandler.cs index ed8d2943..f31ac408 100644 --- a/src/Spring/Spring.Aop/Aspects/Exceptions/ExecuteSpelExceptionHandler.cs +++ b/src/Spring/Spring.Aop/Aspects/Exceptions/ExecuteSpelExceptionHandler.cs @@ -1,46 +1,46 @@ using Microsoft.Extensions.Logging; using Spring.Expressions; -namespace Spring.Aspects.Exceptions +namespace Spring.Aspects.Exceptions; + +/// +/// Executes an abribtrary Spring Expression Language (SpEL) expression as an action when handling an exception. +/// +public class ExecuteSpelExceptionHandler : AbstractExceptionHandler { /// - /// Executes an abribtrary Spring Expression Language (SpEL) expression as an action when handling an exception. + /// Initializes a new instance of the class. /// - public class ExecuteSpelExceptionHandler : AbstractExceptionHandler + public ExecuteSpelExceptionHandler() { - /// - /// Initializes a new instance of the class. - /// - public ExecuteSpelExceptionHandler() + } + + /// + /// Initializes a new instance of the class. + /// + /// The exception names. + public ExecuteSpelExceptionHandler(string[] exceptionNames) + : base(exceptionNames) + { + } + + /// + /// Handles the exception. + /// + /// The return value from handling the exception, if not rethrown or a new exception is thrown. + public override object HandleException(IDictionary callContextDictionary) + { + try { + IExpression expression = Expression.Parse(ActionExpressionText); + expression.GetValue(null, callContextDictionary); + } + catch (Exception e) + { + string message = "Was not able to evaluate action expression [" + ActionExpressionText + "]"; + log.LogWarning(e, message); } - /// - /// Initializes a new instance of the class. - /// - /// The exception names. - public ExecuteSpelExceptionHandler(string[] exceptionNames) - : base(exceptionNames) - { - } - - /// - /// Handles the exception. - /// - /// The return value from handling the exception, if not rethrown or a new exception is thrown. - public override object HandleException(IDictionary callContextDictionary) - { - try - { - IExpression expression = Expression.Parse(ActionExpressionText); - expression.GetValue(null, callContextDictionary); - } - catch (Exception e) - { - string message = "Was not able to evaluate action expression [" + ActionExpressionText + "]"; - log.LogWarning(e, message); - } - return null; - } + return null; } } diff --git a/src/Spring/Spring.Aop/Aspects/Exceptions/LogExceptionHandler.cs b/src/Spring/Spring.Aop/Aspects/Exceptions/LogExceptionHandler.cs index eb04fe34..f987f419 100644 --- a/src/Spring/Spring.Aop/Aspects/Exceptions/LogExceptionHandler.cs +++ b/src/Spring/Spring.Aop/Aspects/Exceptions/LogExceptionHandler.cs @@ -21,132 +21,127 @@ using Microsoft.Extensions.Logging; using Spring.Expressions; -namespace Spring.Aspects.Exceptions +namespace Spring.Aspects.Exceptions; + +/// +/// Log the exceptions. Default log nameis "LogExceptionHandler" and log level is Debug +/// +/// Mark Pollack +public class LogExceptionHandler : AbstractExceptionHandler { + #region Fields + + private string logName = "LogExceptionHandler"; + + private LogLevel logLevel = LogLevel.Trace; + + private bool logMessageOnly = false; + + private bool first = true; + + private string actionExpressionText; + + #endregion + /// - /// Log the exceptions. Default log nameis "LogExceptionHandler" and log level is Debug + /// Initializes a new instance of the class. /// - /// Mark Pollack - public class LogExceptionHandler : AbstractExceptionHandler + public LogExceptionHandler() { - #region Fields - private string logName = "LogExceptionHandler"; + ContinueProcessing = true; + } - private LogLevel logLevel = LogLevel.Trace; + /// + /// Initializes a new instance of the class. + /// + /// The exception names. + public LogExceptionHandler(string[] exceptionNames) : base(exceptionNames) + { + ContinueProcessing = true; + } - private bool logMessageOnly = false; + /// + /// Gets or sets the name of the log. + /// + /// The name of the log. + public string LogName + { + get { return logName; } + set { logName = value; } + } - private bool first = true; + /// + /// Gets or sets the log level. + /// + /// The log level. + public LogLevel LogLevel + { + get { return logLevel; } + set { logLevel = value; } + } - private string actionExpressionText; + /// + /// Gets or sets a value indicating whether to log message only, and not pass in the + /// exception to the logging API + /// + /// true if log message only; otherwise, false. + public bool LogMessageOnly + { + get { return logMessageOnly; } + set { logMessageOnly = value; } + } - #endregion - - - /// - /// Initializes a new instance of the class. - /// - public LogExceptionHandler() + /// + /// Gets the action translation expression text. Overridden to add approprate settings to + /// the SpEL expression that does the logging so that it depends on the values of LogLevel and + /// LogMessageOnly. Those properties must be set to the desired values before calling this method. + /// + /// + /// The action translation expression. + public override string ActionExpressionText + { + get { return actionExpressionText; } + set { - ContinueProcessing = true; - } - - /// - /// Initializes a new instance of the class. - /// - /// The exception names. - public LogExceptionHandler(string[] exceptionNames) : base(exceptionNames) - { - ContinueProcessing = true; - } - - - - /// - /// Gets or sets the name of the log. - /// - /// The name of the log. - public string LogName - { - get { return logName; } - set { logName = value; } - } - - - /// - /// Gets or sets the log level. - /// - /// The log level. - public LogLevel LogLevel - { - get { return logLevel; } - set { logLevel = value; } - } - - /// - /// Gets or sets a value indicating whether to log message only, and not pass in the - /// exception to the logging API - /// - /// true if log message only; otherwise, false. - public bool LogMessageOnly - { - get { return logMessageOnly; } - set { logMessageOnly = value; } - } - - - /// - /// Gets the action translation expression text. Overridden to add approprate settings to - /// the SpEL expression that does the logging so that it depends on the values of LogLevel and - /// LogMessageOnly. Those properties must be set to the desired values before calling this method. - /// - /// - /// The action translation expression. - public override string ActionExpressionText - { - get { return actionExpressionText; } - set + if (first) { - if (first) + first = false; + string textPart1 = "#log." + LogLevel.ToString() + "(" + value; + if (logMessageOnly) { - first = false; - string textPart1 = "#log." + LogLevel.ToString() + "(" + value; - if (logMessageOnly) - { - actionExpressionText = textPart1 + ")"; - } - else - { - actionExpressionText = textPart1 + ", #e)"; - } + actionExpressionText = textPart1 + ")"; + } + else + { + actionExpressionText = textPart1 + ", #e)"; } } } + } - /// - /// Handles the exception. - /// - /// the calling context dictionary - /// - /// The return value from handling the exception, if not rethrown or a new exception is thrown. - /// - public override object HandleException(IDictionary callContextDictionary) + /// + /// Handles the exception. + /// + /// the calling context dictionary + /// + /// The return value from handling the exception, if not rethrown or a new exception is thrown. + /// + public override object HandleException(IDictionary callContextDictionary) + { + //TODO log name is targettype. + ILogger adviceLogger = LogManager.GetLogger(logName); + callContextDictionary.Add("log", adviceLogger); + try { - //TODO log name is targettype. - ILogger adviceLogger = LogManager.GetLogger(logName); - callContextDictionary.Add("log", adviceLogger); - try - { - IExpression expression = Expression.Parse(ActionExpressionText); - expression.GetValue(null, callContextDictionary); - } - catch (Exception e) - { - string message = "Was not able to evaluate action expression [" + ActionExpressionText + "]"; - log.LogWarning(e, message); - } - return "logged"; + IExpression expression = Expression.Parse(ActionExpressionText); + expression.GetValue(null, callContextDictionary); + } + catch (Exception e) + { + string message = "Was not able to evaluate action expression [" + ActionExpressionText + "]"; + log.LogWarning(e, message); } + return "logged"; } } diff --git a/src/Spring/Spring.Aop/Aspects/Exceptions/ReturnValueExceptionHandler.cs b/src/Spring/Spring.Aop/Aspects/Exceptions/ReturnValueExceptionHandler.cs index 224d3290..c75d93e6 100644 --- a/src/Spring/Spring.Aop/Aspects/Exceptions/ReturnValueExceptionHandler.cs +++ b/src/Spring/Spring.Aop/Aspects/Exceptions/ReturnValueExceptionHandler.cs @@ -21,50 +21,47 @@ using Microsoft.Extensions.Logging; using Spring.Expressions; -namespace Spring.Aspects.Exceptions +namespace Spring.Aspects.Exceptions; + +/// +/// Evaluates the expression for the return value of the method. +/// +/// Mark Pollack +public class ReturnValueExceptionHandler : AbstractExceptionHandler { /// - /// Evaluates the expression for the return value of the method. + /// Initializes a new instance of the class. /// - /// Mark Pollack - public class ReturnValueExceptionHandler : AbstractExceptionHandler + public ReturnValueExceptionHandler() { + } - /// - /// Initializes a new instance of the class. - /// - public ReturnValueExceptionHandler() + /// + /// Initializes a new instance of the class. + /// + /// The exception names. + public ReturnValueExceptionHandler(string[] exceptionNames) : base(exceptionNames) + { + } + + /// + /// Returns the result of evaluating the translation expression. + /// + /// The return value from handling the exception, if not rethrown or a new exception is thrown. + public override object HandleException(IDictionary callContextDictionary) + { + object returnVal = null; + try { + IExpression expression = Expression.Parse(ActionExpressionText); + returnVal = expression.GetValue(null, callContextDictionary); + } + catch (Exception e) + { + string message = "Was not able to evaluate action expression [" + ActionExpressionText + "]"; + log.LogWarning(e, message); } - /// - /// Initializes a new instance of the class. - /// - /// The exception names. - public ReturnValueExceptionHandler(string[] exceptionNames) : base(exceptionNames) - { - } - - - - /// - /// Returns the result of evaluating the translation expression. - /// - /// The return value from handling the exception, if not rethrown or a new exception is thrown. - public override object HandleException(IDictionary callContextDictionary) - { - object returnVal = null; - try - { - IExpression expression = Expression.Parse(ActionExpressionText); - returnVal = expression.GetValue(null, callContextDictionary); - } - catch (Exception e) - { - string message = "Was not able to evaluate action expression [" + ActionExpressionText + "]"; - log.LogWarning(e, message); - } - return returnVal; - } + return returnVal; } } diff --git a/src/Spring/Spring.Aop/Aspects/Exceptions/SwallowExceptionHandler.cs b/src/Spring/Spring.Aop/Aspects/Exceptions/SwallowExceptionHandler.cs index 8bc1cc36..f627ec70 100644 --- a/src/Spring/Spring.Aop/Aspects/Exceptions/SwallowExceptionHandler.cs +++ b/src/Spring/Spring.Aop/Aspects/Exceptions/SwallowExceptionHandler.cs @@ -18,38 +18,35 @@ #endregion -namespace Spring.Aspects.Exceptions +namespace Spring.Aspects.Exceptions; + +/// +/// Returns a token to indicate that this exception should be swallowed. +/// +/// Mark Pollack +public class SwallowExceptionHandler : AbstractExceptionHandler { /// - /// Returns a token to indicate that this exception should be swallowed. + /// Initializes a new instance of the class. /// - /// Mark Pollack - public class SwallowExceptionHandler : AbstractExceptionHandler + public SwallowExceptionHandler() { - /// - /// Initializes a new instance of the class. - /// - public SwallowExceptionHandler() - { - } + } - /// - /// Initializes a new instance of the class. - /// - /// The exception names. - public SwallowExceptionHandler(string[] exceptionNames) : base(exceptionNames) - { - } + /// + /// Initializes a new instance of the class. + /// + /// The exception names. + public SwallowExceptionHandler(string[] exceptionNames) : base(exceptionNames) + { + } - - - /// - /// Handles the exception. - /// - /// The return value from handling the exception, if not rethrown or a new exception is thrown. - public override object HandleException(IDictionary callContextDictionary) - { - return "swallow"; - } + /// + /// Handles the exception. + /// + /// The return value from handling the exception, if not rethrown or a new exception is thrown. + public override object HandleException(IDictionary callContextDictionary) + { + return "swallow"; } } diff --git a/src/Spring/Spring.Aop/Aspects/Exceptions/TranslationExceptionHandler.cs b/src/Spring/Spring.Aop/Aspects/Exceptions/TranslationExceptionHandler.cs index 604b004b..41c1f09b 100644 --- a/src/Spring/Spring.Aop/Aspects/Exceptions/TranslationExceptionHandler.cs +++ b/src/Spring/Spring.Aop/Aspects/Exceptions/TranslationExceptionHandler.cs @@ -21,58 +21,58 @@ using Microsoft.Extensions.Logging; using Spring.Expressions; -namespace Spring.Aspects.Exceptions +namespace Spring.Aspects.Exceptions; + +/// +/// Translates from one exception to another based. My wrap or replace exception depending on the expression. +/// +/// Mark Pollack +public class TranslationExceptionHandler : AbstractExceptionHandler { /// - /// Translates from one exception to another based. My wrap or replace exception depending on the expression. + /// Initializes a new instance of the class. /// - /// Mark Pollack - public class TranslationExceptionHandler : AbstractExceptionHandler + public TranslationExceptionHandler() { - /// - /// Initializes a new instance of the class. - /// - public TranslationExceptionHandler() + } + + /// + /// Initializes a new instance of the class. + /// + /// The exception names. + public TranslationExceptionHandler(string[] exceptionNames) : base(exceptionNames) + { + } + + /// + /// Handles the exception. + /// + /// The return value from handling the exception, if not rethrown or a new exception is thrown. + public override object HandleException(IDictionary callContextDictionary) + { + object o = null; + try { + IExpression expression = Expression.Parse(ActionExpressionText); + o = expression.GetValue(null, callContextDictionary); + } + catch (Exception e) + { + string message = "Was not able to evaluate action expression [" + ActionExpressionText + "]"; + log.LogWarning(e, message); } - /// - /// Initializes a new instance of the class. - /// - /// The exception names. - public TranslationExceptionHandler(string[] exceptionNames) : base(exceptionNames) + Exception translatedException = o as Exception; + if (translatedException != null) { + ThrowTranslatedException(translatedException); } + return null; + } - - /// - /// Handles the exception. - /// - /// The return value from handling the exception, if not rethrown or a new exception is thrown. - public override object HandleException(IDictionary callContextDictionary) - { - object o = null; - try { - IExpression expression = Expression.Parse(ActionExpressionText); - o = expression.GetValue(null, callContextDictionary); - } - catch (Exception e) - { - string message = "Was not able to evaluate action expression [" + ActionExpressionText + "]"; - log.LogWarning(e, message); - } - Exception translatedException = o as Exception; - if (translatedException != null) - { - ThrowTranslatedException(translatedException); - } - return null; - } - - private void ThrowTranslatedException(Exception exception) - { - throw exception; - } + private void ThrowTranslatedException(Exception exception) + { + throw exception; } } diff --git a/src/Spring/Spring.Aop/Aspects/IExceptionHandler.cs b/src/Spring/Spring.Aop/Aspects/IExceptionHandler.cs index 1bee57d3..d7047c5a 100644 --- a/src/Spring/Spring.Aop/Aspects/IExceptionHandler.cs +++ b/src/Spring/Spring.Aop/Aspects/IExceptionHandler.cs @@ -20,76 +20,80 @@ using System.Collections; -namespace Spring.Aspects +namespace Spring.Aspects; + +/// +/// Handles a thrown exception providing calling context. +/// +/// Mark Pollack +public interface IExceptionHandler { /// - /// Handles a thrown exception providing calling context. + /// Determines whether this instance can handle the exception the specified exception. /// - /// Mark Pollack - public interface IExceptionHandler + /// The exception. + /// The call context dictionary. + /// + /// true if this instance can handle the specified exception; otherwise, false. + /// + bool CanHandleException(Exception ex, IDictionary callContextDictionary); + + /// + /// Handles the exception. + /// + /// The call context dictionary. + /// + /// The return value from handling the exception, if not rethrown or a new exception is thrown. + /// + object HandleException(IDictionary callContextDictionary); + + /// + /// Gets the source exception names. + /// + /// The source exception names. + IList SourceExceptionNames { - /// - /// Determines whether this instance can handle the exception the specified exception. - /// - /// The exception. - /// The call context dictionary. - /// - /// true if this instance can handle the specified exception; otherwise, false. - /// - bool CanHandleException(Exception ex, IDictionary callContextDictionary); + get; + set; + } - /// - /// Handles the exception. - /// - /// The call context dictionary. - /// - /// The return value from handling the exception, if not rethrown or a new exception is thrown. - /// - object HandleException(IDictionary callContextDictionary); + /// + /// Gets the source exception types. + /// + /// The source exception types. + IList SourceExceptionTypes + { + get; + set; + } - /// - /// Gets the source exception names. - /// - /// The source exception names. - IList SourceExceptionNames - { - get; set; - } + /// + /// Gets the translation expression text + /// + /// The translation expression text + string ActionExpressionText + { + get; + set; + } - /// - /// Gets the source exception types. - /// - /// The source exception types. - IList SourceExceptionTypes - { - get; set; - } + /// + /// Gets or sets the constraint expression text. + /// + /// The constraint expression text. + string ConstraintExpressionText + { + get; + set; + } - /// - /// Gets the translation expression text - /// - /// The translation expression text - string ActionExpressionText - { - get; set; - } - - /// - /// Gets or sets the constraint expression text. - /// - /// The constraint expression text. - string ConstraintExpressionText - { - get; set; - } - - /// - /// Gets a value indicating whether to continue processing. - /// - /// true if continue processing; otherwise, false. - bool ContinueProcessing - { - get; set; - } + /// + /// Gets a value indicating whether to continue processing. + /// + /// true if continue processing; otherwise, false. + bool ContinueProcessing + { + get; + set; } } diff --git a/src/Spring/Spring.Aop/Aspects/Logging/AbstractLoggingAdvice.cs b/src/Spring/Spring.Aop/Aspects/Logging/AbstractLoggingAdvice.cs index 0794b305..fa6b568b 100644 --- a/src/Spring/Spring.Aop/Aspects/Logging/AbstractLoggingAdvice.cs +++ b/src/Spring/Spring.Aop/Aspects/Logging/AbstractLoggingAdvice.cs @@ -24,266 +24,262 @@ using AopAlliance.Intercept; using Microsoft.Extensions.Logging; using Spring.Aop.Framework; -namespace Spring.Aspects.Logging +namespace Spring.Aspects.Logging; + +/// +/// Abstract base class for logging advice +/// +/// +/// +/// +/// Mark Pollack +[Serializable] +public abstract class AbstractLoggingAdvice : IMethodInterceptor, IDeserializationCallback { + #region Fields + /// - /// Abstract base class for logging advice + /// The default ILog instance used to write logging messages. /// - /// - /// - /// - /// Mark Pollack - [Serializable] - public abstract class AbstractLoggingAdvice : IMethodInterceptor, IDeserializationCallback + [NonSerialized] protected ILogger defaultLogger; + + /// + /// The name of the logger instance to use for obtaining from . + /// + private string defaultLoggerName; + + /// + /// Indicates whether or not proxy type names should be hidden when using dynamic loggers. + /// + private bool hideProxyTypeNames = false; + + #endregion + + #region Constructor + + /// + /// Creates a new advice instance using this advice type's name for logging by default. + /// + protected AbstractLoggingAdvice() { - #region Fields + SetDefaultLogger(MethodBase.GetCurrentMethod().DeclaringType.FullName); + } - /// - /// The default ILog instance used to write logging messages. - /// - [NonSerialized] - protected ILogger defaultLogger; + /// + /// Creates a new advice instance using the given logger by default. + /// + protected AbstractLoggingAdvice(ILogger defaultLogger) + { + this.defaultLogger = defaultLogger; + } - /// - /// The name of the logger instance to use for obtaining from . - /// - private string defaultLoggerName; + #endregion - /// - /// Indicates whether or not proxy type names should be hidden when using dynamic loggers. - /// - private bool hideProxyTypeNames = false; + #region Properties - #endregion - - #region Constructor - - /// - /// Creates a new advice instance using this advice type's name for logging by default. - /// - protected AbstractLoggingAdvice() + /// + /// Sets a value indicating whether to use a dynamic logger or static logger + /// + /// Default is to use a static logger. + /// + /// Used to determine which ILog instance should be used to write log messages for + /// a particular method invocation: a dynamic one for the Type getting called, + /// or a static one for the Type of the trace interceptor. + /// + /// + /// Specify either this property or LoggerName, not both. + /// + /// + /// true if use dynamic logger; otherwise, false. + public bool UseDynamicLogger + { + set { - SetDefaultLogger(MethodBase.GetCurrentMethod().DeclaringType.FullName); - } - - /// - /// Creates a new advice instance using the given logger by default. - /// - protected AbstractLoggingAdvice(ILogger defaultLogger) - { - this.defaultLogger = defaultLogger; - } - - #endregion - - #region Properties - - /// - /// Sets a value indicating whether to use a dynamic logger or static logger - /// - /// Default is to use a static logger. - /// - /// Used to determine which ILog instance should be used to write log messages for - /// a particular method invocation: a dynamic one for the Type getting called, - /// or a static one for the Type of the trace interceptor. - /// - /// - /// Specify either this property or LoggerName, not both. - /// - /// - /// true if use dynamic logger; otherwise, false. - public bool UseDynamicLogger - { - set - { - SetDefaultLogger(value ? null : this.GetType().FullName); - } - } - - /// - /// Sets the name of the logger to use. - /// - /// - /// The name will be passed to the underlying logging implementation through Common.Logging, - /// getting interpreted as the log category according to the loggers configuration. - /// - /// This can be specified to not log into the category of a Type (whether this - /// interceptor's class or the class getting called) but rather to a specific named category. - /// - /// - /// Specify either this property or UseDynamicLogger, but not both. - /// - /// - /// The name of the logger. - public string LoggerName - { - set - { - SetDefaultLogger(value); - } - } - - - /// - /// Sets a value indicating whether hide proxy type names (whenever possible) - /// when using dynamic loggers, i.e. property UseDynamicLogger is set to true. - /// - /// true if [hide proxy type names]; otherwise, false. - public bool HideProxyTypeNames - { - set { hideProxyTypeNames = value; } - } - - #endregion - - #region Methods - - /// - /// Adds logging to the method invocation. - /// - /// - /// The method IsInterceptorEnabled is called - /// as an optimization to determine if logging should be applied. If logging should be - /// applied, the method invocation is passed to the InvokeUnderLog method for handling. - /// If not, the method proceeds as normal. - /// - /// - /// The method invocation that is being intercepted. - /// - /// - /// The result of the call to the - /// method of - /// the supplied ; this return value may - /// well have been intercepted by the interceptor. - /// - /// - /// If any of the interceptors in the chain or the target object itself - /// throws an exception. - /// - public object Invoke(IMethodInvocation invocation) - { - object o = invocation.This; - ILogger log = GetLoggerForInvocation(invocation); - if (IsInterceptorEnabled(invocation, log)) - { - return InvokeUnderLog(invocation, log); - } - else - { - return invocation.Proceed(); - } - - } - - /// - /// Determines whether the interceptor is enabled for the specified invocation, that - /// is, whether the method InvokeUnderLog is called. - /// - /// The default behavior is to check whether the given ILog instance - /// is enabled by calling IsLogEnabled, whose default behavior is to check if - /// the TRACE level of logging is enabled. Subclasses - /// The invocation. - /// The log to write messages to - /// - /// true if [is interceptor enabled] [the specified invocation]; otherwise, false. - /// - protected virtual bool IsInterceptorEnabled(IMethodInvocation invocation, ILogger log) - { - return IsLogEnabled(log); - } - - /// - /// Determines whether the given log is enabled. - /// - /// - /// Default is true when the trace level is enabled. Subclasses may override this - /// to change the level at which logging occurs, or return true to ignore level - /// checks. - /// The log instance to check. - /// - /// true if log is for a given log level; otherwise, false. - /// - protected virtual bool IsLogEnabled(ILogger log) - { - return log.IsEnabled(LogLevel.Trace); - } - - /// - /// Subclasses must override this method to perform any tracing around the supplied - /// IMethodInvocation. - /// - /// - /// Subclasses are resonsible for ensuring that the IMethodInvocation actually executes - /// by calling IMethodInvocation.Proceed(). - /// - /// By default, the passed-in ILog instance will have log level - /// "trace" enabled. Subclasses do not have to check for this again, unless - /// they overwrite the IsInterceptorEnabled method to modify - /// the default behavior. - /// - /// - /// The method invocation to log - /// The log to write messages to - /// The result of the call to IMethodInvocation.Proceed() - /// - /// - /// If any of the interceptors in the chain or the target object itself - /// throws an exception. - /// - protected abstract object InvokeUnderLog(IMethodInvocation invocation, ILogger log); - - - /// - /// Gets the appropriate log instance to use for the given IMethodInvocation. - /// - /// - /// If the UseDynamicLogger property is set to true, the ILog instance will be - /// for the target class of the IMethodInvocation, otherwise the log will be the - /// default static logger. - /// - /// The method invocation being logged. - /// The ILog instance to use. - protected virtual ILogger GetLoggerForInvocation(IMethodInvocation invocation) - { - if (defaultLogger != null) - { - return defaultLogger; - } - else - { - object target = invocation.This; - Type logCategoryType = target.GetType(); - if (hideProxyTypeNames) - { - logCategoryType = AopUtils.GetTargetType(target); - } - return LogManager.GetLogger(logCategoryType); - } - } - - #endregion - - /// - /// Sets the default logger to the given name. - /// - /// if null, the default logger is removed. - protected void SetDefaultLogger(string name) - { - defaultLogger = (name == null ? null : LogManager.GetLogger(name)); - defaultLoggerName = name; - } - - void IDeserializationCallback.OnDeserialization(object sender) - { - OnDeserialization(sender); - } - - /// - /// Override in case you need to initialized non-serialized fields on deserialization. - /// - protected virtual void OnDeserialization(object sender) - { - SetDefaultLogger(this.defaultLoggerName); + SetDefaultLogger(value ? null : this.GetType().FullName); } } + + /// + /// Sets the name of the logger to use. + /// + /// + /// The name will be passed to the underlying logging implementation through Common.Logging, + /// getting interpreted as the log category according to the loggers configuration. + /// + /// This can be specified to not log into the category of a Type (whether this + /// interceptor's class or the class getting called) but rather to a specific named category. + /// + /// + /// Specify either this property or UseDynamicLogger, but not both. + /// + /// + /// The name of the logger. + public string LoggerName + { + set + { + SetDefaultLogger(value); + } + } + + /// + /// Sets a value indicating whether hide proxy type names (whenever possible) + /// when using dynamic loggers, i.e. property UseDynamicLogger is set to true. + /// + /// true if [hide proxy type names]; otherwise, false. + public bool HideProxyTypeNames + { + set { hideProxyTypeNames = value; } + } + + #endregion + + #region Methods + + /// + /// Adds logging to the method invocation. + /// + /// + /// The method IsInterceptorEnabled is called + /// as an optimization to determine if logging should be applied. If logging should be + /// applied, the method invocation is passed to the InvokeUnderLog method for handling. + /// If not, the method proceeds as normal. + /// + /// + /// The method invocation that is being intercepted. + /// + /// + /// The result of the call to the + /// method of + /// the supplied ; this return value may + /// well have been intercepted by the interceptor. + /// + /// + /// If any of the interceptors in the chain or the target object itself + /// throws an exception. + /// + public object Invoke(IMethodInvocation invocation) + { + object o = invocation.This; + ILogger log = GetLoggerForInvocation(invocation); + if (IsInterceptorEnabled(invocation, log)) + { + return InvokeUnderLog(invocation, log); + } + else + { + return invocation.Proceed(); + } + } + + /// + /// Determines whether the interceptor is enabled for the specified invocation, that + /// is, whether the method InvokeUnderLog is called. + /// + /// The default behavior is to check whether the given ILog instance + /// is enabled by calling IsLogEnabled, whose default behavior is to check if + /// the TRACE level of logging is enabled. Subclasses + /// The invocation. + /// The log to write messages to + /// + /// true if [is interceptor enabled] [the specified invocation]; otherwise, false. + /// + protected virtual bool IsInterceptorEnabled(IMethodInvocation invocation, ILogger log) + { + return IsLogEnabled(log); + } + + /// + /// Determines whether the given log is enabled. + /// + /// + /// Default is true when the trace level is enabled. Subclasses may override this + /// to change the level at which logging occurs, or return true to ignore level + /// checks. + /// The log instance to check. + /// + /// true if log is for a given log level; otherwise, false. + /// + protected virtual bool IsLogEnabled(ILogger log) + { + return log.IsEnabled(LogLevel.Trace); + } + + /// + /// Subclasses must override this method to perform any tracing around the supplied + /// IMethodInvocation. + /// + /// + /// Subclasses are resonsible for ensuring that the IMethodInvocation actually executes + /// by calling IMethodInvocation.Proceed(). + /// + /// By default, the passed-in ILog instance will have log level + /// "trace" enabled. Subclasses do not have to check for this again, unless + /// they overwrite the IsInterceptorEnabled method to modify + /// the default behavior. + /// + /// + /// The method invocation to log + /// The log to write messages to + /// The result of the call to IMethodInvocation.Proceed() + /// + /// + /// If any of the interceptors in the chain or the target object itself + /// throws an exception. + /// + protected abstract object InvokeUnderLog(IMethodInvocation invocation, ILogger log); + + /// + /// Gets the appropriate log instance to use for the given IMethodInvocation. + /// + /// + /// If the UseDynamicLogger property is set to true, the ILog instance will be + /// for the target class of the IMethodInvocation, otherwise the log will be the + /// default static logger. + /// + /// The method invocation being logged. + /// The ILog instance to use. + protected virtual ILogger GetLoggerForInvocation(IMethodInvocation invocation) + { + if (defaultLogger != null) + { + return defaultLogger; + } + else + { + object target = invocation.This; + Type logCategoryType = target.GetType(); + if (hideProxyTypeNames) + { + logCategoryType = AopUtils.GetTargetType(target); + } + + return LogManager.GetLogger(logCategoryType); + } + } + + #endregion + + /// + /// Sets the default logger to the given name. + /// + /// if null, the default logger is removed. + protected void SetDefaultLogger(string name) + { + defaultLogger = (name == null ? null : LogManager.GetLogger(name)); + defaultLoggerName = name; + } + + void IDeserializationCallback.OnDeserialization(object sender) + { + OnDeserialization(sender); + } + + /// + /// Override in case you need to initialized non-serialized fields on deserialization. + /// + protected virtual void OnDeserialization(object sender) + { + SetDefaultLogger(this.defaultLoggerName); + } } diff --git a/src/Spring/Spring.Aop/Aspects/Logging/SimpleLoggingAdvice.cs b/src/Spring/Spring.Aop/Aspects/Logging/SimpleLoggingAdvice.cs index 0f766a85..11bf5dd4 100644 --- a/src/Spring/Spring.Aop/Aspects/Logging/SimpleLoggingAdvice.cs +++ b/src/Spring/Spring.Aop/Aspects/Logging/SimpleLoggingAdvice.cs @@ -23,442 +23,462 @@ using System.Text; using AopAlliance.Intercept; using Microsoft.Extensions.Logging; -namespace Spring.Aspects.Logging +namespace Spring.Aspects.Logging; + +/// +/// Configurable advice for logging. +/// +/// +/// +/// +/// Mark Pollack +[Serializable] +public class SimpleLoggingAdvice : AbstractLoggingAdvice { + #region Fields + /// - /// Configurable advice for logging. + /// Flag to indicate if unique identifier should be in the log message. /// - /// - /// - /// - /// Mark Pollack - [Serializable] - public class SimpleLoggingAdvice : AbstractLoggingAdvice + private bool logUniqueIdentifier; + + /// + /// Flag to indicate if the execution time should be in the log message. + /// + private bool logExecutionTime; + + /// + /// Flag to indicate if the method arguments should be in the log message. + /// + private bool logMethodArguments; + + /// + /// Flag to indicate if the return value should be in the log message. + /// + private bool logReturnValue; + + /// + /// The separator string to use for delmiting log message fields. + /// + private string separator = ", "; + + /// + /// The log level to use for logging the entry, exit, exception messages. + /// + private LogLevel logLevel = LogLevel.Trace; + + #endregion + + #region Constructor(s) + + /// + /// Initializes a new instance of the class. + /// + public SimpleLoggingAdvice() { - #region Fields + } - /// - /// Flag to indicate if unique identifier should be in the log message. - /// - private bool logUniqueIdentifier; + /// + /// Initializes a new instance of the class. + /// + /// if set to true to use dynamic logger, if + /// false use static logger. + public SimpleLoggingAdvice(bool useDynamicLogger) + { + UseDynamicLogger = useDynamicLogger; + } - /// - /// Flag to indicate if the execution time should be in the log message. - /// - private bool logExecutionTime; + /// + /// Initializes a new instance of the class. + /// + /// the default logger to use + public SimpleLoggingAdvice(ILogger defaultLogger) + : base(defaultLogger) + { + } - /// - /// Flag to indicate if the method arguments should be in the log message. - /// - private bool logMethodArguments; + #endregion - /// - /// Flag to indicate if the return value should be in the log message. - /// - private bool logReturnValue; + #region Properties - /// - /// The separator string to use for delmiting log message fields. - /// - private string separator = ", "; + /// + /// Gets or sets a value indicating whether to log a unique identifier with the log message. + /// + /// true if [log unique identifier]; otherwise, false. + public bool LogUniqueIdentifier + { + get { return logUniqueIdentifier; } + set { logUniqueIdentifier = value; } + } - /// - /// The log level to use for logging the entry, exit, exception messages. - /// - private LogLevel logLevel = LogLevel.Trace; + /// + /// Gets or sets a value indicating whether to log execution time. + /// + /// true if log execution time; otherwise, false. + public bool LogExecutionTime + { + get { return logExecutionTime; } + set { logExecutionTime = value; } + } + /// + /// Gets or sets a value indicating whether log method arguments. + /// + /// true if log method arguments]; otherwise, false. + public bool LogMethodArguments + { + get { return logMethodArguments; } + set { logMethodArguments = value; } + } - #endregion + /// + /// Gets or sets a value indicating whether log return value. + /// + /// true if log return value; otherwise, false. + public bool LogReturnValue + { + get { return logReturnValue; } + set { logReturnValue = value; } + } - #region Constructor(s) + /// + /// Gets or sets the seperator string to use for delmiting log message fields. + /// + /// The seperator. + public string Separator + { + get { return separator; } + set { separator = value; } + } - /// - /// Initializes a new instance of the class. - /// - public SimpleLoggingAdvice() + /// + /// Gets or sets the entry log level. + /// + /// The entry log level. + public LogLevel LogLevel + { + get { return logLevel; } + set { logLevel = value; } + } + + #endregion + + #region Protected Methods + + /// + /// Subclasses must override this method to perform any tracing around the supplied + /// IMethodInvocation. + /// + /// The method invocation to log + /// The log to write messages to + /// + /// The result of the call to IMethodInvocation.Proceed() + /// + /// + /// Subclasses are resonsible for ensuring that the IMethodInvocation actually executes + /// by calling IMethodInvocation.Proceed(). + /// + /// By default, the passed-in ILog instance will have log level + /// "trace" enabled. Subclasses do not have to check for this again, unless + /// they overwrite the IsInterceptorEnabled method to modify + /// the default behavior. + /// + /// + /// + /// If any of the interceptors in the chain or the target object itself + /// throws an exception. + /// + protected override object InvokeUnderLog(IMethodInvocation invocation, ILogger log) + { + object returnValue = null; + bool exitThroughException = false; + + DateTime startTime = DateTime.Now; + string uniqueIdentifier = null; + + if (LogUniqueIdentifier) { + uniqueIdentifier = CreateUniqueIdentifier(); } - - /// - /// Initializes a new instance of the class. - /// - /// if set to true to use dynamic logger, if - /// false use static logger. - public SimpleLoggingAdvice(bool useDynamicLogger) + try { - UseDynamicLogger = useDynamicLogger; + WriteToLog(LogLevel, log, GetEntryMessage(invocation, uniqueIdentifier), null); + returnValue = invocation.Proceed(); + return returnValue; } - - /// - /// Initializes a new instance of the class. - /// - /// the default logger to use - public SimpleLoggingAdvice(ILogger defaultLogger) - : base(defaultLogger) - {} - - #endregion - - #region Properties - - /// - /// Gets or sets a value indicating whether to log a unique identifier with the log message. - /// - /// true if [log unique identifier]; otherwise, false. - public bool LogUniqueIdentifier + catch (Exception e) { - get { return logUniqueIdentifier; } - set { logUniqueIdentifier = value; } + TimeSpan executionTimeSpan = DateTime.Now - startTime; + WriteToLog(LogLevel, log, GetExceptionMessage(invocation, e, executionTimeSpan, uniqueIdentifier), e); + exitThroughException = true; + throw; } - - /// - /// Gets or sets a value indicating whether to log execution time. - /// - /// true if log execution time; otherwise, false. - public bool LogExecutionTime + finally { - get { return logExecutionTime; } - set { logExecutionTime = value; } - } - - /// - /// Gets or sets a value indicating whether log method arguments. - /// - /// true if log method arguments]; otherwise, false. - public bool LogMethodArguments - { - get { return logMethodArguments; } - set { logMethodArguments = value; } - } - - /// - /// Gets or sets a value indicating whether log return value. - /// - /// true if log return value; otherwise, false. - public bool LogReturnValue - { - get { return logReturnValue; } - set { logReturnValue = value; } - } - - /// - /// Gets or sets the seperator string to use for delmiting log message fields. - /// - /// The seperator. - public string Separator - { - get { return separator; } - set { separator = value; } - } - - /// - /// Gets or sets the entry log level. - /// - /// The entry log level. - public LogLevel LogLevel - { - get { return logLevel; } - set { logLevel = value; } - } - - #endregion - - #region Protected Methods - - /// - /// Subclasses must override this method to perform any tracing around the supplied - /// IMethodInvocation. - /// - /// The method invocation to log - /// The log to write messages to - /// - /// The result of the call to IMethodInvocation.Proceed() - /// - /// - /// Subclasses are resonsible for ensuring that the IMethodInvocation actually executes - /// by calling IMethodInvocation.Proceed(). - /// - /// By default, the passed-in ILog instance will have log level - /// "trace" enabled. Subclasses do not have to check for this again, unless - /// they overwrite the IsInterceptorEnabled method to modify - /// the default behavior. - /// - /// - /// - /// If any of the interceptors in the chain or the target object itself - /// throws an exception. - /// - protected override object InvokeUnderLog(IMethodInvocation invocation, ILogger log) - { - object returnValue = null; - bool exitThroughException = false; - - DateTime startTime = DateTime.Now; - string uniqueIdentifier = null; - - if (LogUniqueIdentifier) - { - uniqueIdentifier = CreateUniqueIdentifier(); - } - try - { - WriteToLog(LogLevel, log, GetEntryMessage(invocation, uniqueIdentifier), null); - returnValue = invocation.Proceed(); - return returnValue; - } catch (Exception e) + if (!exitThroughException) { TimeSpan executionTimeSpan = DateTime.Now - startTime; - WriteToLog(LogLevel, log, GetExceptionMessage(invocation, e, executionTimeSpan, uniqueIdentifier), e); - exitThroughException = true; - throw; - } - finally - { - if (!exitThroughException) - { - TimeSpan executionTimeSpan = DateTime.Now - startTime; - WriteToLog(LogLevel, log, GetExitMessage(invocation, returnValue, executionTimeSpan, uniqueIdentifier), null); - } + WriteToLog(LogLevel, log, GetExitMessage(invocation, returnValue, executionTimeSpan, uniqueIdentifier), null); } } - - /// - /// Determines whether the given log is enabled. - /// - /// The log instance to check. - /// - /// true if log is for a given log level; otherwise, false. - /// - /// - /// Default is true when the trace level is enabled. Subclasses may override this - /// to change the level at which logging occurs, or return true to ignore level - /// checks. - protected override bool IsLogEnabled(ILogger log) - { - switch (LogLevel) - { - case LogLevel.Trace: - if (log.IsEnabled(LogLevel.Trace)) - { - return true; - } - break; - case LogLevel.Debug: - if (log.IsEnabled(LogLevel.Debug)) - { - return true; - } - break; - case LogLevel.Error: - if (log.IsEnabled(LogLevel.Error)) - { - return true; - } - break; - case LogLevel.Critical: - if (log.IsEnabled(LogLevel.Critical)) - { - return true; - } - break; - case LogLevel.Information: - if (log.IsEnabled(LogLevel.Information)) - { - return true; - } - break; - case LogLevel.Warning: - if (log.IsEnabled(LogLevel.Warning)) - { - return true; - } - break; - case LogLevel.None: - default: - break; - } - return false; - } - - /// - /// Creates a unique identifier. - /// - /// - /// Default implementation uses Guid.NewGuid(). Subclasses may override to provide an alternative - /// ID generation implementation. - /// - /// A unique identifier - protected virtual string CreateUniqueIdentifier() - { - return Guid.NewGuid().ToString(); - } - - /// - /// Gets the entry message to log - /// - /// The invocation. - /// The id string. - /// The entry log message - protected virtual string GetEntryMessage(IMethodInvocation invocation, string idString) - { - StringBuilder sb = new StringBuilder(128); - sb.Append("Entering "); - AppendCommonInformation(sb, invocation, idString); - if (logMethodArguments) - { - sb.Append(GetMethodArgumentAsString(invocation)); - } - - return RemoveLastSeparator(sb.ToString(), Separator); - } - - /// - /// Gets the exception message. - /// - /// The method invocation. - /// The thown exception. - /// The execution time span. - /// The id string. - /// The exception log message. - protected virtual string GetExceptionMessage(IMethodInvocation invocation, Exception e, TimeSpan executionTimeSpan, string idString) - { - StringBuilder sb = new StringBuilder(128); - sb.Append("Exception thrown in "); - sb.Append(invocation.Method.Name).Append(Separator); - AppendCommonInformation(sb, invocation, idString); - if (LogExecutionTime) - { - sb.Append(executionTimeSpan.TotalMilliseconds).Append(" ms"); - } - - return RemoveLastSeparator(sb.ToString(), Separator); - } - - - /// - /// Gets the exit log message. - /// - /// The method invocation. - /// The return value. - /// The execution time span. - /// The id string. - /// the exit log message - protected virtual string GetExitMessage(IMethodInvocation invocation, object returnValue, TimeSpan executionTimeSpan, string idString) - { - StringBuilder sb = new StringBuilder(128); - sb.Append("Exiting "); - AppendCommonInformation(sb, invocation, idString); - if (LogReturnValue && invocation.Method.ReturnType != typeof(void)) - { - sb.Append("return=").Append(returnValue).Append(Separator); - } - if (LogExecutionTime) - { - sb.Append(executionTimeSpan.TotalMilliseconds).Append(" ms"); - } - return RemoveLastSeparator(sb.ToString(), Separator); - } - - - /// - /// Appends common information across entry,exit, exception logging - /// - /// Add method name and unique identifier if required. - /// The string buffer building logging message. - /// The method invocation. - /// The unique identifier string. - protected virtual void AppendCommonInformation(StringBuilder sb, IMethodInvocation invocation, string idString) - { - sb.Append(invocation.Method.Name); - if (LogUniqueIdentifier) - { - sb.Append(Separator).Append(idString); - } - sb.Append(Separator); - } - - /// - /// Gets the method argument as argumen name/value pairs. - /// - /// The method invocation. - /// string for logging method argument name and values. - protected virtual string GetMethodArgumentAsString(IMethodInvocation invocation) - { - StringBuilder sb = new StringBuilder(128); - ParameterInfo[] parameterInfos = invocation.Method.GetParameters(); - object[] argValues = invocation.Arguments; - for (int i=0; i< parameterInfos.Length; i++) - { - sb.Append(parameterInfos[i].Name).Append("=").Append(argValues[i]); - if (i != parameterInfos.Length) sb.Append("; "); - } - - return RemoveLastSeparator(sb.ToString(), "; "); - } - - #endregion - - #region Private Methods - - private string RemoveLastSeparator(string str, string separator) - { - if (str.EndsWith(separator)) - { - return str.Substring(0, str.Length - separator.Length); - } - else - { - return str; - } - } - - private void WriteToLog(LogLevel logLevel, ILogger log, string text, Exception e) - { - switch (logLevel) - { - case LogLevel.Trace: - if (log.IsEnabled(LogLevel.Trace)) - { - if (e == null) log.LogTrace(text); else log.LogTrace(e, text); - } - break; - case LogLevel.Debug: - if (log.IsEnabled(LogLevel.Debug)) - { - if (e == null) log.LogDebug(text); else log.LogDebug(e, text); - } - break; - case LogLevel.Error: - if (log.IsEnabled(LogLevel.Error)) - { - if (e == null) log.LogError(text); else log.LogError(e, text); - } - break; - case LogLevel.Critical: - if (log.IsEnabled(LogLevel.Critical)) - { - if (e == null) log.LogCritical(text); else log.LogCritical(e, text); - } - break; - case LogLevel.Information: - if (log.IsEnabled(LogLevel.Information)) - { - if (e == null) log.LogInformation(text); else log.LogInformation(e, text); - } - break; - case LogLevel.Warning: - if (log.IsEnabled(LogLevel.Warning)) - { - if (e == null) log.LogWarning(text); else log.LogWarning(e, text); - } - break; - case LogLevel.None: - default: - break; - } - } - - #endregion } -} + + /// + /// Determines whether the given log is enabled. + /// + /// The log instance to check. + /// + /// true if log is for a given log level; otherwise, false. + /// + /// + /// Default is true when the trace level is enabled. Subclasses may override this + /// to change the level at which logging occurs, or return true to ignore level + /// checks. + protected override bool IsLogEnabled(ILogger log) + { + switch (LogLevel) + { + case LogLevel.Trace: + if (log.IsEnabled(LogLevel.Trace)) + { + return true; + } + + break; + case LogLevel.Debug: + if (log.IsEnabled(LogLevel.Debug)) + { + return true; + } + + break; + case LogLevel.Error: + if (log.IsEnabled(LogLevel.Error)) + { + return true; + } + + break; + case LogLevel.Critical: + if (log.IsEnabled(LogLevel.Critical)) + { + return true; + } + + break; + case LogLevel.Information: + if (log.IsEnabled(LogLevel.Information)) + { + return true; + } + + break; + case LogLevel.Warning: + if (log.IsEnabled(LogLevel.Warning)) + { + return true; + } + + break; + case LogLevel.None: + default: + break; + } + + return false; + } + + /// + /// Creates a unique identifier. + /// + /// + /// Default implementation uses Guid.NewGuid(). Subclasses may override to provide an alternative + /// ID generation implementation. + /// + /// A unique identifier + protected virtual string CreateUniqueIdentifier() + { + return Guid.NewGuid().ToString(); + } + + /// + /// Gets the entry message to log + /// + /// The invocation. + /// The id string. + /// The entry log message + protected virtual string GetEntryMessage(IMethodInvocation invocation, string idString) + { + StringBuilder sb = new StringBuilder(128); + sb.Append("Entering "); + AppendCommonInformation(sb, invocation, idString); + if (logMethodArguments) + { + sb.Append(GetMethodArgumentAsString(invocation)); + } + + return RemoveLastSeparator(sb.ToString(), Separator); + } + + /// + /// Gets the exception message. + /// + /// The method invocation. + /// The thown exception. + /// The execution time span. + /// The id string. + /// The exception log message. + protected virtual string GetExceptionMessage(IMethodInvocation invocation, Exception e, TimeSpan executionTimeSpan, string idString) + { + StringBuilder sb = new StringBuilder(128); + sb.Append("Exception thrown in "); + sb.Append(invocation.Method.Name).Append(Separator); + AppendCommonInformation(sb, invocation, idString); + if (LogExecutionTime) + { + sb.Append(executionTimeSpan.TotalMilliseconds).Append(" ms"); + } + + return RemoveLastSeparator(sb.ToString(), Separator); + } + + /// + /// Gets the exit log message. + /// + /// The method invocation. + /// The return value. + /// The execution time span. + /// The id string. + /// the exit log message + protected virtual string GetExitMessage(IMethodInvocation invocation, object returnValue, TimeSpan executionTimeSpan, string idString) + { + StringBuilder sb = new StringBuilder(128); + sb.Append("Exiting "); + AppendCommonInformation(sb, invocation, idString); + if (LogReturnValue && invocation.Method.ReturnType != typeof(void)) + { + sb.Append("return=").Append(returnValue).Append(Separator); + } + + if (LogExecutionTime) + { + sb.Append(executionTimeSpan.TotalMilliseconds).Append(" ms"); + } + + return RemoveLastSeparator(sb.ToString(), Separator); + } + + /// + /// Appends common information across entry,exit, exception logging + /// + /// Add method name and unique identifier if required. + /// The string buffer building logging message. + /// The method invocation. + /// The unique identifier string. + protected virtual void AppendCommonInformation(StringBuilder sb, IMethodInvocation invocation, string idString) + { + sb.Append(invocation.Method.Name); + if (LogUniqueIdentifier) + { + sb.Append(Separator).Append(idString); + } + + sb.Append(Separator); + } + + /// + /// Gets the method argument as argumen name/value pairs. + /// + /// The method invocation. + /// string for logging method argument name and values. + protected virtual string GetMethodArgumentAsString(IMethodInvocation invocation) + { + StringBuilder sb = new StringBuilder(128); + ParameterInfo[] parameterInfos = invocation.Method.GetParameters(); + object[] argValues = invocation.Arguments; + for (int i = 0; i < parameterInfos.Length; i++) + { + sb.Append(parameterInfos[i].Name).Append("=").Append(argValues[i]); + if (i != parameterInfos.Length) sb.Append("; "); + } + + return RemoveLastSeparator(sb.ToString(), "; "); + } + + #endregion + + #region Private Methods + + private string RemoveLastSeparator(string str, string separator) + { + if (str.EndsWith(separator)) + { + return str.Substring(0, str.Length - separator.Length); + } + else + { + return str; + } + } + + private void WriteToLog(LogLevel logLevel, ILogger log, string text, Exception e) + { + switch (logLevel) + { + case LogLevel.Trace: + if (log.IsEnabled(LogLevel.Trace)) + { + if (e == null) log.LogTrace(text); + else log.LogTrace(e, text); + } + + break; + case LogLevel.Debug: + if (log.IsEnabled(LogLevel.Debug)) + { + if (e == null) log.LogDebug(text); + else log.LogDebug(e, text); + } + + break; + case LogLevel.Error: + if (log.IsEnabled(LogLevel.Error)) + { + if (e == null) log.LogError(text); + else log.LogError(e, text); + } + + break; + case LogLevel.Critical: + if (log.IsEnabled(LogLevel.Critical)) + { + if (e == null) log.LogCritical(text); + else log.LogCritical(e, text); + } + + break; + case LogLevel.Information: + if (log.IsEnabled(LogLevel.Information)) + { + if (e == null) log.LogInformation(text); + else log.LogInformation(e, text); + } + + break; + case LogLevel.Warning: + if (log.IsEnabled(LogLevel.Warning)) + { + if (e == null) log.LogWarning(text); + else log.LogWarning(e, text); + } + + break; + case LogLevel.None: + default: + break; + } + } + + #endregion +} \ No newline at end of file diff --git a/src/Spring/Spring.Aop/Aspects/ParsedAdviceExpression.cs b/src/Spring/Spring.Aop/Aspects/ParsedAdviceExpression.cs index 82358ed8..11c1a321 100644 --- a/src/Spring/Spring.Aop/Aspects/ParsedAdviceExpression.cs +++ b/src/Spring/Spring.Aop/Aspects/ParsedAdviceExpression.cs @@ -18,97 +18,94 @@ #endregion -namespace Spring.Aspects +namespace Spring.Aspects; + +/// +/// This class contains the results of parsing an advice expresion of the form +/// on exception name [ExceptionName1,ExceptionName2,...] [action] [action expression] +/// or +/// on exception [constraint expression] [action] [action expression] +/// +/// +/// +/// +/// Mark Pollack +public class ParsedAdviceExpression { + private string adviceExpression; + + private string[] exceptionNames = new string[0]; + private string constraintExpression = null; + private string actionExpressionText = null; + private string actionText = null; + private bool success; + /// - /// This class contains the results of parsing an advice expresion of the form - /// on exception name [ExceptionName1,ExceptionName2,...] [action] [action expression] - /// or - /// on exception [constraint expression] [action] [action expression] + /// Initializes a new instance of the class. /// - /// - /// - /// - /// Mark Pollack - public class ParsedAdviceExpression + /// The advice expression. + public ParsedAdviceExpression(string adviceExpression) { - private string adviceExpression; - - private string[] exceptionNames = new string[0]; - private string constraintExpression = null; - private string actionExpressionText = null; - private string actionText = null; - private bool success; - - - /// - /// Initializes a new instance of the class. - /// - /// The advice expression. - public ParsedAdviceExpression(string adviceExpression) - { - this.adviceExpression = adviceExpression; - } - - - /// - /// Gets or sets the advice expression. - /// - /// The advice expression. - public string AdviceExpression - { - get { return adviceExpression; } - set { adviceExpression = value; } - } - - /// - /// Gets or sets the exception names. - /// - /// The exception names. - public string[] ExceptionNames - { - get { return exceptionNames; } - set { exceptionNames = value; } - } - - /// - /// Gets or sets the constraint expression. - /// - /// The constraint expression. - public string ConstraintExpression - { - get { return constraintExpression; } - set { constraintExpression = value; } - } - - /// - /// Gets or sets the action expression text. - /// - /// The action expression text. - public string ActionExpressionText - { - get { return actionExpressionText; } - set { actionExpressionText = value; } - } - - /// - /// Gets or sets the action text. - /// - /// The action text. - public string ActionText - { - get { return actionText; } - set { actionText = value; } - } - - /// - /// Gets or sets a value indicating whether this is success. - /// - /// true if success; otherwise, false. - public bool Success - { - get { return success; } - set { success = value; } - } + this.adviceExpression = adviceExpression; } -} \ No newline at end of file + + /// + /// Gets or sets the advice expression. + /// + /// The advice expression. + public string AdviceExpression + { + get { return adviceExpression; } + set { adviceExpression = value; } + } + + /// + /// Gets or sets the exception names. + /// + /// The exception names. + public string[] ExceptionNames + { + get { return exceptionNames; } + set { exceptionNames = value; } + } + + /// + /// Gets or sets the constraint expression. + /// + /// The constraint expression. + public string ConstraintExpression + { + get { return constraintExpression; } + set { constraintExpression = value; } + } + + /// + /// Gets or sets the action expression text. + /// + /// The action expression text. + public string ActionExpressionText + { + get { return actionExpressionText; } + set { actionExpressionText = value; } + } + + /// + /// Gets or sets the action text. + /// + /// The action text. + public string ActionText + { + get { return actionText; } + set { actionText = value; } + } + + /// + /// Gets or sets a value indicating whether this is success. + /// + /// true if success; otherwise, false. + public bool Success + { + get { return success; } + set { success = value; } + } +} diff --git a/src/Spring/Spring.Aop/Aspects/RetryAdvice.cs b/src/Spring/Spring.Aop/Aspects/RetryAdvice.cs index 1ef2aa93..1a1cfc54 100644 --- a/src/Spring/Spring.Aop/Aspects/RetryAdvice.cs +++ b/src/Spring/Spring.Aop/Aspects/RetryAdvice.cs @@ -24,332 +24,333 @@ using Microsoft.Extensions.Logging; using Spring.Core.TypeConversion; using Spring.Expressions; -namespace Spring.Aspects +namespace Spring.Aspects; + +/// +/// AOP Advice to retry a method invocation on an exception. The retry semantics are defined by a DSL of the +/// form on exception name [ExceptionName1,ExceptionName2,...] retry [number of times] [delay|rate] [delay time|rate expression]. +/// For example, on exception name ArithmeticException retry 3x delay 1s +/// +/// +/// +/// +/// Mark Pollack +[Serializable] +public class RetryAdvice : AbstractExceptionHandlerAdvice { - /// - /// AOP Advice to retry a method invocation on an exception. The retry semantics are defined by a DSL of the - /// form on exception name [ExceptionName1,ExceptionName2,...] retry [number of times] [delay|rate] [delay time|rate expression]. - /// For example, on exception name ArithmeticException retry 3x delay 1s - /// - /// - /// - /// - /// Mark Pollack - [Serializable] - public class RetryAdvice : AbstractExceptionHandlerAdvice + /// + ///The type of the callback that is called for delaying retries. + /// + public delegate void SleepHandler(TimeSpan duration); + + private static readonly ILogger log; + private static readonly TimeSpanConverter timeSpanConverter; + + static RetryAdvice() { - /// - ///The type of the callback that is called for delaying retries. - /// - public delegate void SleepHandler(TimeSpan duration); + log = LogManager.GetLogger(typeof(RetryAdvice)); + timeSpanConverter = new TimeSpanConverter(); + } - private static readonly ILogger log; - private static readonly TimeSpanConverter timeSpanConverter; + #region Fields - static RetryAdvice() + private SleepHandler sleepHandler; + + [NonSerialized] private RetryExceptionHandler retryExceptionHandler; + + private string retryExpression; + + private string onExceptionNameRegex = @"^(on\s+exception\s+name)\s+(.*?)\s+(retry)\s*(.*?)$"; + + private string onExceptionRegex = @"^(on\s+exception\s+)(\(.*?\))\s+(retry)\s*(.*?)$"; + + //retry 3x delay 10s + private string delayRegex = @"^(\d+)x\s+(delay)\s+(\d+\w+)?$"; + + //retry 3x rate 10n+5 + private string rateRegex = @"^(\d+)x\s+(rate)\s+(\(.*?\))?$"; + + #endregion + + #region Properties + + /// + /// Gets or sets the retry expression. + /// + /// The retry expression. + public string RetryExpression + { + get { return retryExpression; } + set { retryExpression = value; } + } + + /// + /// Gets or sets the Regex string used to parse advice expressions starting with 'on exception name' and exception handling actions. + /// + /// The regex string to parse advice expressions starting with 'on exception name' and exception handling actions. + public override string OnExceptionNameRegex + { + get { return onExceptionNameRegex; } + set { onExceptionNameRegex = value; } + } + + /// + /// Gets or sets the Regex string used to parse advice expressions starting with 'on exception (constraint)' and exception handling actions. + /// + /// The regex string to parse advice expressions starting with 'on exception (constraint)' and exception handling actions. + public override string OnExceptionRegex + { + get { return onExceptionRegex; } + set { onExceptionRegex = value; } + } + + #endregion + + /// + /// Creates a new RetryAdvice instance, using for delaying retries + /// + public RetryAdvice() + : this(new SleepHandler(Thread.Sleep)) + { + } + + /// + /// Creates a new RetryAdvice instance, using any arbitrary callback for delaying retries + /// + public RetryAdvice(SleepHandler sleepHandler) + { + this.sleepHandler = sleepHandler; + } + + #region IMethodInterceptor implementation + + /// + /// Implement this method to perform extra treatments before and after + /// the call to the supplied . + /// + /// The method invocation that is being intercepted. + /// + /// The result of the call to the + /// method of + /// the supplied ; this return value may + /// well have been intercepted by the interceptor. + /// + /// + ///

+ /// Polite implementations would certainly like to invoke + /// . + ///

+ ///
+ /// + /// If any of the interceptors in the chain or the target object itself + /// throws an exception. + /// + public override object Invoke(IMethodInvocation invocation) + { + IDictionary callContextDictionary = new Dictionary(); + callContextDictionary.Add("method", invocation.Method); + callContextDictionary.Add("args", invocation.Arguments); + callContextDictionary.Add("target", invocation.Target); + int numAttempts = 0; + + object returnVal = null; + do { - log = LogManager.GetLogger(typeof(RetryAdvice)); - timeSpanConverter = new TimeSpanConverter(); - } - - #region Fields - - private SleepHandler sleepHandler; - - [NonSerialized] - private RetryExceptionHandler retryExceptionHandler; - - private string retryExpression; - - private string onExceptionNameRegex = @"^(on\s+exception\s+name)\s+(.*?)\s+(retry)\s*(.*?)$"; - - private string onExceptionRegex = @"^(on\s+exception\s+)(\(.*?\))\s+(retry)\s*(.*?)$"; - - //retry 3x delay 10s - private string delayRegex = @"^(\d+)x\s+(delay)\s+(\d+\w+)?$"; - - //retry 3x rate 10n+5 - private string rateRegex = @"^(\d+)x\s+(rate)\s+(\(.*?\))?$"; - #endregion - - #region Properties - - /// - /// Gets or sets the retry expression. - /// - /// The retry expression. - public string RetryExpression - { - get { return retryExpression; } - set { retryExpression = value; } - } - - /// - /// Gets or sets the Regex string used to parse advice expressions starting with 'on exception name' and exception handling actions. - /// - /// The regex string to parse advice expressions starting with 'on exception name' and exception handling actions. - public override string OnExceptionNameRegex - { - get { return onExceptionNameRegex; } - set { onExceptionNameRegex = value; } - } - - /// - /// Gets or sets the Regex string used to parse advice expressions starting with 'on exception (constraint)' and exception handling actions. - /// - /// The regex string to parse advice expressions starting with 'on exception (constraint)' and exception handling actions. - public override string OnExceptionRegex - { - get { return onExceptionRegex; } - set { onExceptionRegex = value; } - } - - #endregion - - /// - /// Creates a new RetryAdvice instance, using for delaying retries - /// - public RetryAdvice() - :this(new SleepHandler(Thread.Sleep)) - { - } - - /// - /// Creates a new RetryAdvice instance, using any arbitrary callback for delaying retries - /// - public RetryAdvice(SleepHandler sleepHandler) - { - this.sleepHandler = sleepHandler; - } - - #region IMethodInterceptor implementation - - /// - /// Implement this method to perform extra treatments before and after - /// the call to the supplied . - /// - /// The method invocation that is being intercepted. - /// - /// The result of the call to the - /// method of - /// the supplied ; this return value may - /// well have been intercepted by the interceptor. - /// - /// - ///

- /// Polite implementations would certainly like to invoke - /// . - ///

- ///
- /// - /// If any of the interceptors in the chain or the target object itself - /// throws an exception. - /// - public override object Invoke(IMethodInvocation invocation) - { - IDictionary callContextDictionary = new Dictionary(); - callContextDictionary.Add("method", invocation.Method); - callContextDictionary.Add("args", invocation.Arguments); - callContextDictionary.Add("target", invocation.Target); - int numAttempts = 0; - - object returnVal = null; - do + try { - try + returnVal = invocation.Proceed(); + break; + } + catch (Exception ex) + { + callContextDictionary["e"] = ex; + if (retryExceptionHandler.CanHandleException(ex, callContextDictionary)) { - returnVal = invocation.Proceed(); - break; - } - catch (Exception ex) - { - callContextDictionary["e"] = ex; - if (retryExceptionHandler.CanHandleException(ex, callContextDictionary)) - { - numAttempts++; - if (numAttempts == retryExceptionHandler.MaximumRetryCount) - { - throw; - } - else - { - if (log.IsEnabled(LogLevel.Trace)) - { - log.LogTrace("Retrying " + invocation.Method.Name); - } - callContextDictionary["n"] = numAttempts; - Sleep(retryExceptionHandler, callContextDictionary, sleepHandler); - } - } - else + numAttempts++; + if (numAttempts == retryExceptionHandler.MaximumRetryCount) { throw; } + else + { + if (log.IsEnabled(LogLevel.Trace)) + { + log.LogTrace("Retrying " + invocation.Method.Name); + } + + callContextDictionary["n"] = numAttempts; + Sleep(retryExceptionHandler, callContextDictionary, sleepHandler); + } + } + else + { + throw; } - } while (numAttempts <= retryExceptionHandler.MaximumRetryCount); - - - log.LogDebug("Invoked successfully after " + numAttempts + " attempt(s)"); - return returnVal; - } - - private static void Sleep(RetryExceptionHandler handler, IDictionary callContextDictionary, SleepHandler sleepHandler) - { - if (handler.IsDelayBased) - { - sleepHandler(handler.DelayTimeSpan); } - else + } while (numAttempts <= retryExceptionHandler.MaximumRetryCount); + + log.LogDebug("Invoked successfully after " + numAttempts + " attempt(s)"); + return returnVal; + } + + private static void Sleep(RetryExceptionHandler handler, IDictionary callContextDictionary, SleepHandler sleepHandler) + { + if (handler.IsDelayBased) + { + sleepHandler(handler.DelayTimeSpan); + } + else + { + try { - try - { - IExpression expression = Expression.Parse(handler.DelayRateExpression); - object result = expression.GetValue(null, callContextDictionary); - decimal d = decimal.Parse(result.ToString()); - decimal rounded = decimal.Round(d*1000,0); - TimeSpan duration = TimeSpan.FromMilliseconds(decimal.ToDouble(rounded)); - sleepHandler(duration); - } - catch (InvalidCastException e) - { - string message = "Was not able to cast expression to decimal [" + handler.DelayRateExpression + "]. Sleeping for 1 second"; - log.LogWarning(e, message); - sleepHandler(new TimeSpan(0,0,1)); - } - catch (Exception e) - { - string message = "Was not able to evaluate rate expression [" + handler.DelayRateExpression + "]. Sleeping for 1 second"; - log.LogWarning(e, message); - sleepHandler(new TimeSpan(0,0,1)); - } + IExpression expression = Expression.Parse(handler.DelayRateExpression); + object result = expression.GetValue(null, callContextDictionary); + decimal d = decimal.Parse(result.ToString()); + decimal rounded = decimal.Round(d * 1000, 0); + TimeSpan duration = TimeSpan.FromMilliseconds(decimal.ToDouble(rounded)); + sleepHandler(duration); + } + catch (InvalidCastException e) + { + string message = "Was not able to cast expression to decimal [" + handler.DelayRateExpression + "]. Sleeping for 1 second"; + log.LogWarning(e, message); + sleepHandler(new TimeSpan(0, 0, 1)); + } + catch (Exception e) + { + string message = "Was not able to evaluate rate expression [" + handler.DelayRateExpression + "]. Sleeping for 1 second"; + log.LogWarning(e, message); + sleepHandler(new TimeSpan(0, 0, 1)); } } + } - #endregion + #endregion - #region IInitializingObject implementation + #region IInitializingObject implementation - /// - /// Invoked by an - /// after it has injected all of an object's dependencies. - /// - /// - ///

- /// This method allows the object instance to perform the kind of - /// initialization only possible when all of it's dependencies have - /// been injected (set), and to throw an appropriate exception in the - /// event of misconfiguration. - ///

- ///

- /// Please do consult the class level documentation for the - /// interface for a - /// description of exactly when this method is invoked. In - /// particular, it is worth noting that the - /// - /// and - /// callbacks will have been invoked prior to this method being - /// called. - ///

- ///
- /// - /// In the event of misconfiguration (such as the failure to set a - /// required property) or if initialization fails. - /// - public override void AfterPropertiesSet() + /// + /// Invoked by an + /// after it has injected all of an object's dependencies. + /// + /// + ///

+ /// This method allows the object instance to perform the kind of + /// initialization only possible when all of it's dependencies have + /// been injected (set), and to throw an appropriate exception in the + /// event of misconfiguration. + ///

+ ///

+ /// Please do consult the class level documentation for the + /// interface for a + /// description of exactly when this method is invoked. In + /// particular, it is worth noting that the + /// + /// and + /// callbacks will have been invoked prior to this method being + /// called. + ///

+ ///
+ /// + /// In the event of misconfiguration (such as the failure to set a + /// required property) or if initialization fails. + /// + public override void AfterPropertiesSet() + { + if (retryExpression == null) { - if (retryExpression == null) - { - throw new ArgumentException("Must specify retry expression."); - } - RetryExceptionHandler handler = Parse(retryExpression); - if (handler == null) - { - throw new ArgumentException("Was not able to parse retry expression string [" + retryExpression + "]"); - } - retryExceptionHandler = handler; + throw new ArgumentException("Must specify retry expression."); } - #endregion - - /// - /// Parses the specified handler string. - /// - /// The handler string. - /// - protected virtual RetryExceptionHandler Parse(string retryExpressionString) + RetryExceptionHandler handler = Parse(retryExpression); + if (handler == null) { + throw new ArgumentException("Was not able to parse retry expression string [" + retryExpression + "]"); + } - ParsedAdviceExpression parsedAdviceExpression = ParseAdviceExpression(retryExpressionString); + retryExceptionHandler = handler; + } - if (!parsedAdviceExpression.Success) + #endregion + + /// + /// Parses the specified handler string. + /// + /// The handler string. + /// + protected virtual RetryExceptionHandler Parse(string retryExpressionString) + { + ParsedAdviceExpression parsedAdviceExpression = ParseAdviceExpression(retryExpressionString); + + if (!parsedAdviceExpression.Success) + { + log.LogWarning("Could not parse retry expression " + retryExpressionString); + return null; + } + + RetryExceptionHandler handler = new RetryExceptionHandler(parsedAdviceExpression.ExceptionNames); + handler.ConstraintExpressionText = parsedAdviceExpression.ConstraintExpression; + handler.ActionExpressionText = parsedAdviceExpression.AdviceExpression; + + Match match = GetMatchForActionExpression(parsedAdviceExpression.ActionExpressionText, delayRegex); + + if (match.Success) + { + handler.MaximumRetryCount = int.Parse(match.Groups[1].Value.Trim()); + handler.IsDelayBased = true; + + try { - log.LogWarning("Could not parse retry expression " + retryExpressionString); + string ts = match.Groups[3].Value.Trim(); + handler.DelayTimeSpan = (TimeSpan) timeSpanConverter.ConvertFrom(null, null, ts); + } + catch (Exception) + { + log.LogWarning("Could not parse timespan " + match.Groups[3].Value.Trim()); return null; } - RetryExceptionHandler handler = new RetryExceptionHandler(parsedAdviceExpression.ExceptionNames); - handler.ConstraintExpressionText = parsedAdviceExpression.ConstraintExpression; - handler.ActionExpressionText = parsedAdviceExpression.AdviceExpression; - - Match match = GetMatchForActionExpression(parsedAdviceExpression.ActionExpressionText, delayRegex); - + return handler; + } + else + { + match = GetMatchForActionExpression(parsedAdviceExpression.ActionExpressionText, rateRegex); if (match.Success) { handler.MaximumRetryCount = int.Parse(match.Groups[1].Value.Trim()); - handler.IsDelayBased = true; - - try - { - string ts = match.Groups[3].Value.Trim(); - handler.DelayTimeSpan = (TimeSpan) timeSpanConverter.ConvertFrom(null, null, ts); - } catch (Exception) - { - log.LogWarning("Could not parse timespan " + match.Groups[3].Value.Trim()); - return null; - } + handler.IsDelayBased = false; + handler.DelayRateExpression = match.Groups[3].Value.Trim(); return handler; } else { - match = GetMatchForActionExpression(parsedAdviceExpression.ActionExpressionText, rateRegex); - if (match.Success) - { - handler.MaximumRetryCount = int.Parse(match.Groups[1].Value.Trim()); - handler.IsDelayBased = false; - handler.DelayRateExpression = match.Groups[3].Value.Trim(); - return handler; - } - else - { - return null; - } - } - - } - - /// - /// Gets the match for action expression. - /// - /// The action expression string. - /// The regex string. - /// The Match object resulting from the regular expression match. - protected virtual Match GetMatchForActionExpression(string actionExpressionString, string regexString) - { - RegexOptions options = ((RegexOptions.IgnorePatternWhitespace | RegexOptions.Multiline) | RegexOptions.IgnoreCase); - Regex reg = new Regex(regexString, options); - return reg.Match(actionExpressionString); - } - - /// - /// Override in case you need to initialized non-serialized fields on deserialization. - /// - protected override void OnDeserialization(object sender) - { - base.OnDeserialization(sender); - if (retryExpression != null) - { - this.AfterPropertiesSet(); + return null; } } } + + /// + /// Gets the match for action expression. + /// + /// The action expression string. + /// The regex string. + /// The Match object resulting from the regular expression match. + protected virtual Match GetMatchForActionExpression(string actionExpressionString, string regexString) + { + RegexOptions options = ((RegexOptions.IgnorePatternWhitespace | RegexOptions.Multiline) | RegexOptions.IgnoreCase); + Regex reg = new Regex(regexString, options); + return reg.Match(actionExpressionString); + } + + /// + /// Override in case you need to initialized non-serialized fields on deserialization. + /// + protected override void OnDeserialization(object sender) + { + base.OnDeserialization(sender); + if (retryExpression != null) + { + this.AfterPropertiesSet(); + } + } } diff --git a/src/Spring/Spring.Aop/Aspects/RetryExceptionHandler.cs b/src/Spring/Spring.Aop/Aspects/RetryExceptionHandler.cs index 418b87fb..3814aba9 100644 --- a/src/Spring/Spring.Aop/Aspects/RetryExceptionHandler.cs +++ b/src/Spring/Spring.Aop/Aspects/RetryExceptionHandler.cs @@ -18,109 +18,107 @@ #endregion -namespace Spring.Aspects +namespace Spring.Aspects; + +/// +/// Sleeps for the appropriate amount of time for an exception. +/// +/// +/// +/// +/// Mark Pollack +public class RetryExceptionHandler : AbstractExceptionHandler { + #region Fields + + private int maximumRetryCount; + + private bool isDelayBased; + + private TimeSpan delayTimeSpan; + private string delayRateExpression; + + #endregion + + #region Constructor + /// - /// Sleeps for the appropriate amount of time for an exception. + /// Initializes a new instance of the class. /// - /// - /// - /// - /// Mark Pollack - public class RetryExceptionHandler : AbstractExceptionHandler + public RetryExceptionHandler() { - #region Fields - - private int maximumRetryCount; - - private bool isDelayBased; - - private TimeSpan delayTimeSpan; - private string delayRateExpression; - - #endregion - - #region Constructor - - /// - /// Initializes a new instance of the class. - /// - public RetryExceptionHandler() - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The exception names. - public RetryExceptionHandler(string[] exceptionNames) : base(exceptionNames) - { - } - - #endregion - - #region Properties - - /// - /// Gets the maximum retry count. - /// - /// The maximum retry count. - public int MaximumRetryCount - { - get { return maximumRetryCount; } - set { maximumRetryCount = value; } - } - - - /// - /// Gets a value indicating whether this instance is delay based. - /// - /// - /// true if this instance is delay based; otherwise, false. - /// - public bool IsDelayBased - { - get { return isDelayBased; } - set { isDelayBased = value; } - } - - /// - /// Gets or sets the delay time span to sleep after an exception is thrown and a rety is - /// attempted. - /// - /// The delay time span. - public TimeSpan DelayTimeSpan - { - get { return delayTimeSpan; } - set { delayTimeSpan = value; } - } - - /// - /// Gets or sets the delay rate expression. - /// - /// The delay rate expression. - public string DelayRateExpression - { - get { return delayRateExpression; } - set { delayRateExpression = value; } - } - - #endregion - - #region Methods - - /// - /// Handles the exception. - /// - /// - /// - /// The return value from handling the exception, if not rethrown or a new exception is thrown. - /// - public override object HandleException(IDictionary callContextDictionary) - { - return null; - } - - #endregion } + + /// + /// Initializes a new instance of the class. + /// + /// The exception names. + public RetryExceptionHandler(string[] exceptionNames) : base(exceptionNames) + { + } + + #endregion + + #region Properties + + /// + /// Gets the maximum retry count. + /// + /// The maximum retry count. + public int MaximumRetryCount + { + get { return maximumRetryCount; } + set { maximumRetryCount = value; } + } + + /// + /// Gets a value indicating whether this instance is delay based. + /// + /// + /// true if this instance is delay based; otherwise, false. + /// + public bool IsDelayBased + { + get { return isDelayBased; } + set { isDelayBased = value; } + } + + /// + /// Gets or sets the delay time span to sleep after an exception is thrown and a rety is + /// attempted. + /// + /// The delay time span. + public TimeSpan DelayTimeSpan + { + get { return delayTimeSpan; } + set { delayTimeSpan = value; } + } + + /// + /// Gets or sets the delay rate expression. + /// + /// The delay rate expression. + public string DelayRateExpression + { + get { return delayRateExpression; } + set { delayRateExpression = value; } + } + + #endregion + + #region Methods + + /// + /// Handles the exception. + /// + /// + /// + /// The return value from handling the exception, if not rethrown or a new exception is thrown. + /// + public override object HandleException(IDictionary callContextDictionary) + { + return null; + } + + #endregion } diff --git a/src/Spring/Spring.Aop/Aspects/Validation/ParameterValidationAdvice.cs b/src/Spring/Spring.Aop/Aspects/Validation/ParameterValidationAdvice.cs index d1b9619a..37ca5c52 100644 --- a/src/Spring/Spring.Aop/Aspects/Validation/ParameterValidationAdvice.cs +++ b/src/Spring/Spring.Aop/Aspects/Validation/ParameterValidationAdvice.cs @@ -3,72 +3,72 @@ using Spring.Aop; using Spring.Context; using Spring.Validation; -namespace Spring.Aspects.Validation -{ - /// - /// This advice is typically applied to service-layer methods in order to validate - /// method arguments. - /// - /// - /// Each argument that should be validated has to be marked with one or more - /// s. - /// If the validation fails, this advice will throw , - /// thus preventing target method invocation. - /// - /// - /// Damjan Tomic - /// Aleksandar Seovic - public class ParameterValidationAdvice : IMethodBeforeAdvice, IApplicationContextAware - { - private IApplicationContext applicationContext; +namespace Spring.Aspects.Validation; - /// - /// Intercepts method invocation and validates arguments. - /// - /// - /// Method invocation. - /// - /// - /// Method arguments. - /// - /// - /// Target object. - /// - /// - /// If one or more method arguments fail validation. - /// - public void Before(MethodInfo method, object[] args, object target) +/// +/// This advice is typically applied to service-layer methods in order to validate +/// method arguments. +/// +/// +/// Each argument that should be validated has to be marked with one or more +/// s. +/// If the validation fails, this advice will throw , +/// thus preventing target method invocation. +/// +/// +/// Damjan Tomic +/// Aleksandar Seovic +public class ParameterValidationAdvice : IMethodBeforeAdvice, IApplicationContextAware +{ + private IApplicationContext applicationContext; + + /// + /// Intercepts method invocation and validates arguments. + /// + /// + /// Method invocation. + /// + /// + /// Method arguments. + /// + /// + /// Target object. + /// + /// + /// If one or more method arguments fail validation. + /// + public void Before(MethodInfo method, object[] args, object target) + { + ValidationErrors errors = new ValidationErrors(); + ParameterInfo[] parameters = method.GetParameters(); + + for (int i = 0; i < parameters.Length; i++) { - ValidationErrors errors = new ValidationErrors(); - ParameterInfo[] parameters = method.GetParameters(); - - for (int i = 0; i < parameters.Length; i++) + ParameterInfo info = parameters[i]; + ValidatedAttribute[] attributes = (ValidatedAttribute[]) info.GetCustomAttributes(typeof(ValidatedAttribute), true); + + foreach (ValidatedAttribute attribute in attributes) { - ParameterInfo info = parameters[i]; - ValidatedAttribute[] attributes = (ValidatedAttribute[]) info.GetCustomAttributes(typeof(ValidatedAttribute), true); - - foreach (ValidatedAttribute attribute in attributes) - { - // throws NoSuchObjectDefinitionException if validator cannot be found - IValidator validator = (IValidator) applicationContext.GetObject(attribute.ValidatorName); - validator.Validate(args[i], errors); - } - } - if (!errors.IsEmpty) - { - throw new ValidationException(errors); + // throws NoSuchObjectDefinitionException if validator cannot be found + IValidator validator = (IValidator) applicationContext.GetObject(attribute.ValidatorName); + validator.Validate(args[i], errors); } } - /// - /// Sets the application context to search for validators in. - /// - /// - /// The application context to search for validators in. - /// - public IApplicationContext ApplicationContext + if (!errors.IsEmpty) { - set { this.applicationContext = value; } + throw new ValidationException(errors); } } -} \ No newline at end of file + + /// + /// Sets the application context to search for validators in. + /// + /// + /// The application context to search for validators in. + /// + public IApplicationContext ApplicationContext + { + set { this.applicationContext = value; } + } +} diff --git a/src/Spring/Spring.Aop/Aspects/Validation/ParameterValidationAdvisor.cs b/src/Spring/Spring.Aop/Aspects/Validation/ParameterValidationAdvisor.cs index 1381d207..647b71b8 100644 --- a/src/Spring/Spring.Aop/Aspects/Validation/ParameterValidationAdvisor.cs +++ b/src/Spring/Spring.Aop/Aspects/Validation/ParameterValidationAdvisor.cs @@ -21,91 +21,89 @@ #region Imports using System.Reflection; - using Spring.Aop.Support; using Spring.Validation; using Spring.Context; #endregion -namespace Spring.Aspects.Validation +namespace Spring.Aspects.Validation; + +/// +/// Convinience advisor implementation that applies +/// to all the methods that have defined on one or +/// more of their parameters. +/// +/// Bruno Baia +public class ParameterValidationAdvisor : AttributeMatchMethodPointcutAdvisor, IApplicationContextAware { /// - /// Convinience advisor implementation that applies - /// to all the methods that have defined on one or - /// more of their parameters. + /// Creates new advisor instance. /// - /// Bruno Baia - public class ParameterValidationAdvisor : AttributeMatchMethodPointcutAdvisor, IApplicationContextAware + public ParameterValidationAdvisor() { - /// - /// Creates new advisor instance. - /// - public ParameterValidationAdvisor() - { - Advice = new ParameterValidationAdvice(); - Attribute = typeof(ValidatedAttribute); - Inherit = false; - } + Advice = new ParameterValidationAdvice(); + Attribute = typeof(ValidatedAttribute); + Inherit = false; + } - /// - /// Sets the that this - /// object runs in. - /// - /// - ///

- /// Normally this call will be used to initialize the object. - ///

- ///

- /// Invoked after population of normal object properties but before an - /// init callback such as - /// 's - /// - /// or a custom init-method. Invoked after the setting of any - /// 's - /// - /// property. - ///

- ///
- /// - /// In the case of application context initialization errors. - /// - /// - /// If thrown by any application context methods. - /// - /// - public IApplicationContext ApplicationContext - { - set { ((IApplicationContextAware)Advice).ApplicationContext = value; } - } + /// + /// Sets the that this + /// object runs in. + /// + /// + ///

+ /// Normally this call will be used to initialize the object. + ///

+ ///

+ /// Invoked after population of normal object properties but before an + /// init callback such as + /// 's + /// + /// or a custom init-method. Invoked after the setting of any + /// 's + /// + /// property. + ///

+ ///
+ /// + /// In the case of application context initialization errors. + /// + /// + /// If thrown by any application context methods. + /// + /// + public IApplicationContext ApplicationContext + { + set { ((IApplicationContextAware) Advice).ApplicationContext = value; } + } - /// - /// Returns true if any of the parameters of the specified - /// has applied. - /// - /// - /// Method to check. - /// - /// - /// Type of target object. - /// - /// - /// true if any of the parameters of the specified - /// has applied; false otherwise. - /// - public override bool Matches(MethodInfo method, Type targetType) + /// + /// Returns true if any of the parameters of the specified + /// has applied. + /// + /// + /// Method to check. + /// + /// + /// Type of target object. + /// + /// + /// true if any of the parameters of the specified + /// has applied; false otherwise. + /// + public override bool Matches(MethodInfo method, Type targetType) + { + ParameterInfo[] parameters = method.GetParameters(); + for (int i = 0; i < parameters.Length; i++) { - ParameterInfo[] parameters = method.GetParameters(); - for (int i = 0; i < parameters.Length; i++) + ParameterInfo p = parameters[i]; + if (p.IsDefined(Attribute, Inherit)) { - ParameterInfo p = parameters[i]; - if (p.IsDefined(Attribute, Inherit)) - { - return true; - } + return true; } - - return false; } + + return false; } } diff --git a/src/Spring/Spring.Aop/AssemblyInfo.cs b/src/Spring/Spring.Aop/AssemblyInfo.cs index 52f74c86..195c7bc7 100644 --- a/src/Spring/Spring.Aop/AssemblyInfo.cs +++ b/src/Spring/Spring.Aop/AssemblyInfo.cs @@ -1,4 +1,4 @@ using System.Reflection; [assembly: AssemblyTitle("Spring.Aop")] -[assembly: AssemblyDescription("Interfaces and classes that provide AOP support in Spring.Net")] \ No newline at end of file +[assembly: AssemblyDescription("Interfaces and classes that provide AOP support in Spring.Net")] diff --git a/src/Spring/Spring.Core/Caching/AbstractCache.cs b/src/Spring/Spring.Core/Caching/AbstractCache.cs index d8ea5b6f..71eb4e3e 100644 --- a/src/Spring/Spring.Core/Caching/AbstractCache.cs +++ b/src/Spring/Spring.Core/Caching/AbstractCache.cs @@ -20,181 +20,178 @@ using System.Collections; -namespace Spring.Caching +namespace Spring.Caching; + +/// +/// An abstract implementation that can +/// be used as base class for concrete implementations. +/// +/// Aleksandar Seovic +/// Erich Eichinger +public abstract class AbstractCache : ICache { + #region Fields + + private bool _enforceTimeToLive = false; + private TimeSpan _timeToLive = TimeSpan.Zero; + + #endregion + + #region Properties + /// - /// An abstract implementation that can - /// be used as base class for concrete implementations. + /// Gets/Set the Default time-to-live (TTL) for items inserted into this cache. + /// Used by /// - /// Aleksandar Seovic - /// Erich Eichinger - public abstract class AbstractCache : ICache + public TimeSpan TimeToLive { - #region Fields - - private bool _enforceTimeToLive = false; - private TimeSpan _timeToLive = TimeSpan.Zero; - - #endregion - - #region Properties - - /// - /// Gets/Set the Default time-to-live (TTL) for items inserted into this cache. - /// Used by - /// - public TimeSpan TimeToLive - { - get { return _timeToLive; } - set { _timeToLive = value; } - } - - /// - /// Gets/Sets a value, whether the this cache instance's - /// shall be applied to all items, regardless of their individual TTL - /// when is called. - /// - public bool EnforceTimeToLive - { - get { return _enforceTimeToLive; } - set { _enforceTimeToLive = value; } - } - - #endregion - - #region ICache Implementation - - #region - - /// - /// Gets the number of items in the cache. - /// - /// - /// May be overridden by subclasses for cache-specific efficient implementation. - /// - public virtual int Count - { - get - { - return Keys.Count; - } - } - - /// - /// Gets a collection of all cache item keys. - /// - public abstract ICollection Keys { get; } - - - - /// - /// Retrieves an item from the cache. - /// - /// - /// Item key. - /// - /// - /// Item for the specified , or null. - /// - public abstract object Get(object key); - - /// - /// Removes an item from the cache. - /// - /// - /// Item key. - /// - public abstract void Remove(object key); - - /// - /// Removes collection of items from the cache. - /// - /// - /// Collection of keys to remove. - /// - public virtual void RemoveAll(ICollection keys) - { - foreach (object key in keys) - { - Remove(key); - } - } - - /// - /// Removes all items from the cache. - /// - public virtual void Clear() - { - RemoveAll(this.Keys); - } - - - /// - /// Inserts an item into the cache. - /// - /// - /// Items inserted using this method use the default - /// - /// - /// Item key. - /// - /// - /// Item value. - /// - public virtual void Insert(object key, object value) - { - Insert(key, value, TimeToLive); - } - - /// - /// Inserts an item into the cache. - /// - /// - /// If equals , - /// or is true, this cache - /// instance's value will be applied. - /// - /// - /// Item key. - /// - /// - /// Item value. - /// - /// - /// Item's time-to-live (TTL). - /// - public virtual void Insert(object key, object value, TimeSpan timeToLive) - { - if (_enforceTimeToLive || (timeToLive < TimeSpan.Zero)) - { - timeToLive = _timeToLive; - } - DoInsert(key, value, timeToLive); - } - - #endregion - - #endregion - - #region Methods - - /// - /// Actually does the cache implementation specific insert operation into the cache. - /// - /// - /// Items inserted using this method have default cache priority. - /// - /// - /// Item key. - /// - /// - /// Item value. - /// - /// - /// Item's time-to-live (TTL). - /// - protected abstract void DoInsert(object key, object value, TimeSpan timeToLive); - - #endregion + get { return _timeToLive; } + set { _timeToLive = value; } } + + /// + /// Gets/Sets a value, whether the this cache instance's + /// shall be applied to all items, regardless of their individual TTL + /// when is called. + /// + public bool EnforceTimeToLive + { + get { return _enforceTimeToLive; } + set { _enforceTimeToLive = value; } + } + + #endregion + + #region ICache Implementation + + #region + + /// + /// Gets the number of items in the cache. + /// + /// + /// May be overridden by subclasses for cache-specific efficient implementation. + /// + public virtual int Count + { + get + { + return Keys.Count; + } + } + + /// + /// Gets a collection of all cache item keys. + /// + public abstract ICollection Keys { get; } + + /// + /// Retrieves an item from the cache. + /// + /// + /// Item key. + /// + /// + /// Item for the specified , or null. + /// + public abstract object Get(object key); + + /// + /// Removes an item from the cache. + /// + /// + /// Item key. + /// + public abstract void Remove(object key); + + /// + /// Removes collection of items from the cache. + /// + /// + /// Collection of keys to remove. + /// + public virtual void RemoveAll(ICollection keys) + { + foreach (object key in keys) + { + Remove(key); + } + } + + /// + /// Removes all items from the cache. + /// + public virtual void Clear() + { + RemoveAll(this.Keys); + } + + /// + /// Inserts an item into the cache. + /// + /// + /// Items inserted using this method use the default + /// + /// + /// Item key. + /// + /// + /// Item value. + /// + public virtual void Insert(object key, object value) + { + Insert(key, value, TimeToLive); + } + + /// + /// Inserts an item into the cache. + /// + /// + /// If equals , + /// or is true, this cache + /// instance's value will be applied. + /// + /// + /// Item key. + /// + /// + /// Item value. + /// + /// + /// Item's time-to-live (TTL). + /// + public virtual void Insert(object key, object value, TimeSpan timeToLive) + { + if (_enforceTimeToLive || (timeToLive < TimeSpan.Zero)) + { + timeToLive = _timeToLive; + } + + DoInsert(key, value, timeToLive); + } + + #endregion + + #endregion + + #region Methods + + /// + /// Actually does the cache implementation specific insert operation into the cache. + /// + /// + /// Items inserted using this method have default cache priority. + /// + /// + /// Item key. + /// + /// + /// Item value. + /// + /// + /// Item's time-to-live (TTL). + /// + protected abstract void DoInsert(object key, object value, TimeSpan timeToLive); + + #endregion } diff --git a/src/Spring/Spring.Core/Caching/BaseCacheAttribute.cs b/src/Spring/Spring.Core/Caching/BaseCacheAttribute.cs index 03fc290d..581f9e40 100644 --- a/src/Spring/Spring.Core/Caching/BaseCacheAttribute.cs +++ b/src/Spring/Spring.Core/Caching/BaseCacheAttribute.cs @@ -1,185 +1,183 @@ using Spring.Core.TypeConversion; using Spring.Expressions; -namespace Spring.Caching +namespace Spring.Caching; + +/// +/// Abstract base class containing shared properties for all cache attributes. +/// +/// Aleksandar Seovic +[Serializable] +public abstract class BaseCacheAttribute : Attribute { + #region Fields + /// - /// Abstract base class containing shared properties for all cache attributes. + /// The instance used to parse values. /// - /// Aleksandar Seovic - [Serializable] - public abstract class BaseCacheAttribute : Attribute + /// + /// + protected static readonly TimeSpanConverter TimeSpanConverter = new TimeSpanConverter(); + + private string cacheName; + private string key; + private IExpression keyExpression; + private string condition; + private IExpression conditionExpression; + private string timeToLive = null; + private TimeSpan timeToLiveTimeSpan = TimeSpan.MinValue; + + #endregion + + #region Constructors + + /// + /// Creates an attribute instance. + /// + public BaseCacheAttribute() { - #region Fields - - /// - /// The instance used to parse values. - /// - /// - /// - protected static readonly TimeSpanConverter TimeSpanConverter = new TimeSpanConverter(); - - private string cacheName; - private string key; - private IExpression keyExpression; - private string condition; - private IExpression conditionExpression; - private string timeToLive = null; - private TimeSpan timeToLiveTimeSpan = TimeSpan.MinValue; - - #endregion - - #region Constructors - - /// - /// Creates an attribute instance. - /// - public BaseCacheAttribute() - { - } - - /// - /// Creates an attribute instance. - /// - /// - /// The name of the cache to use. - /// - /// - /// An expression string that should be evaluated in order to determine - /// the cache key for the item. - /// - /// The cache key cannot evaluate be null or an empty string. - public BaseCacheAttribute(string cacheName, string key) - { - if (null == key) - { - throw new ArgumentNullException("key", "The expression for the Cache Key cannot be null."); - } - - if (key.Trim() == string.Empty) - { - throw new ArgumentOutOfRangeException("key", "The expression for the Cache Key cannot be an empty string."); - } - - this.CacheName = cacheName; - this.Key = key; - } - - #endregion - - #region Properties - - /// - /// Gets or sets the name of the cache to use. - /// - /// - /// The name of the cache to use. - /// - public string CacheName - { - get { return cacheName; } - set { cacheName = value; } - } - - /// - /// Gets or sets a SpEL expression that should be evaluated in order - /// to determine the cache key for the item. - /// - /// - /// An expression string that should be evaluated in order to determine - /// the cache key for the item. - /// - public string Key - { - get { return key; } - set - { - key = value; - keyExpression = Expression.Parse(value); - } - } - - /// - /// Gets an expression instance that should be evaluated in order - /// to determine the cache key for the item. - /// - /// - /// An expression instance that should be evaluated in order to determine - /// the cache key for the item. - /// - public IExpression KeyExpression - { - get { return keyExpression; } - } - - /// - /// Gets or sets a SpEL expression that should be evaluated in order - /// to determine whether the item should be cached. - /// - /// - /// An expression string that should be evaluated in order to determine - /// whether the item should be cached. - /// - public string Condition - { - get { return condition; } - set - { - condition = value; - conditionExpression = Expression.Parse(value); - } - } - - /// - /// Gets an expression instance that should be evaluated in order - /// to determine whether the item should be cached. - /// - /// - /// An expression instance that should be evaluated in order to determine - /// whether the item should be cached. - /// - public IExpression ConditionExpression - { - get { return conditionExpression; } - } - - /// - /// The amount of time an object should remain in the cache. - /// - /// - /// If no TTL is specified, the default TTL defined by the - /// cache's policy will be applied. - /// - /// - /// The amount of time object should remain in the cache - /// formatted to be recognizable by . - /// - public string TimeToLive - { - get { return timeToLive; } - set - { - timeToLive = value; - timeToLiveTimeSpan = (timeToLive == null) ? TimeSpan.MinValue : (TimeSpan)TimeSpanConverter.ConvertFrom(timeToLive); - } - } - - - /// - /// The amount of time an object should remain in the cache (in seconds). - /// - /// - /// If no TTL is specified, the default TTL defined by the - /// cache's policy will be applied. - /// - /// - /// The amount of time object should remain in the cache (in seconds). - /// - public TimeSpan TimeToLiveTimeSpan - { - get { return timeToLiveTimeSpan; } - } - - #endregion } + + /// + /// Creates an attribute instance. + /// + /// + /// The name of the cache to use. + /// + /// + /// An expression string that should be evaluated in order to determine + /// the cache key for the item. + /// + /// The cache key cannot evaluate be null or an empty string. + public BaseCacheAttribute(string cacheName, string key) + { + if (null == key) + { + throw new ArgumentNullException("key", "The expression for the Cache Key cannot be null."); + } + + if (key.Trim() == string.Empty) + { + throw new ArgumentOutOfRangeException("key", "The expression for the Cache Key cannot be an empty string."); + } + + this.CacheName = cacheName; + this.Key = key; + } + + #endregion + + #region Properties + + /// + /// Gets or sets the name of the cache to use. + /// + /// + /// The name of the cache to use. + /// + public string CacheName + { + get { return cacheName; } + set { cacheName = value; } + } + + /// + /// Gets or sets a SpEL expression that should be evaluated in order + /// to determine the cache key for the item. + /// + /// + /// An expression string that should be evaluated in order to determine + /// the cache key for the item. + /// + public string Key + { + get { return key; } + set + { + key = value; + keyExpression = Expression.Parse(value); + } + } + + /// + /// Gets an expression instance that should be evaluated in order + /// to determine the cache key for the item. + /// + /// + /// An expression instance that should be evaluated in order to determine + /// the cache key for the item. + /// + public IExpression KeyExpression + { + get { return keyExpression; } + } + + /// + /// Gets or sets a SpEL expression that should be evaluated in order + /// to determine whether the item should be cached. + /// + /// + /// An expression string that should be evaluated in order to determine + /// whether the item should be cached. + /// + public string Condition + { + get { return condition; } + set + { + condition = value; + conditionExpression = Expression.Parse(value); + } + } + + /// + /// Gets an expression instance that should be evaluated in order + /// to determine whether the item should be cached. + /// + /// + /// An expression instance that should be evaluated in order to determine + /// whether the item should be cached. + /// + public IExpression ConditionExpression + { + get { return conditionExpression; } + } + + /// + /// The amount of time an object should remain in the cache. + /// + /// + /// If no TTL is specified, the default TTL defined by the + /// cache's policy will be applied. + /// + /// + /// The amount of time object should remain in the cache + /// formatted to be recognizable by . + /// + public string TimeToLive + { + get { return timeToLive; } + set + { + timeToLive = value; + timeToLiveTimeSpan = (timeToLive == null) ? TimeSpan.MinValue : (TimeSpan) TimeSpanConverter.ConvertFrom(timeToLive); + } + } + + /// + /// The amount of time an object should remain in the cache (in seconds). + /// + /// + /// If no TTL is specified, the default TTL defined by the + /// cache's policy will be applied. + /// + /// + /// The amount of time object should remain in the cache (in seconds). + /// + public TimeSpan TimeToLiveTimeSpan + { + get { return timeToLiveTimeSpan; } + } + + #endregion } diff --git a/src/Spring/Spring.Core/Caching/CacheParameterAttribute.cs b/src/Spring/Spring.Core/Caching/CacheParameterAttribute.cs index 8f52f4f0..9538c66b 100644 --- a/src/Spring/Spring.Core/Caching/CacheParameterAttribute.cs +++ b/src/Spring/Spring.Core/Caching/CacheParameterAttribute.cs @@ -18,52 +18,51 @@ #endregion -namespace Spring.Caching +namespace Spring.Caching; + +/// +/// This attribute should be used to mark methods whose argument(s) +/// need to be cached. +/// +/// +///

+/// This attribute allows application developers to specify that an argument +/// of the method should be cached, but it will not do any caching by itself. +///

+///

+/// In order to actually cache the result, an application developer +/// must apply a Spring.Aspects.Cache.CacheParameterAdvice to +/// all of the members that have this attribute defined. +///

+///

+/// You can specify this attribute multiple times on the same method in order to +/// cache several method parameters. +///

+///
+/// Aleksandar Seovic +[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = true, Inherited = false)] +[Serializable] +public sealed class CacheParameterAttribute : BaseCacheAttribute { /// - /// This attribute should be used to mark methods whose argument(s) - /// need to be cached. + /// Creates an attribute instance. /// - /// - ///

- /// This attribute allows application developers to specify that an argument - /// of the method should be cached, but it will not do any caching by itself. - ///

- ///

- /// In order to actually cache the result, an application developer - /// must apply a Spring.Aspects.Cache.CacheParameterAdvice to - /// all of the members that have this attribute defined. - ///

- ///

- /// You can specify this attribute multiple times on the same method in order to - /// cache several method parameters. - ///

- ///
- /// Aleksandar Seovic - [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = true, Inherited = false)] - [Serializable] - public sealed class CacheParameterAttribute : BaseCacheAttribute + public CacheParameterAttribute() { - /// - /// Creates an attribute instance. - /// - public CacheParameterAttribute() - { - } + } - /// - /// Creates an attribute instance. - /// - /// - /// The name of the cache to use. - /// - /// - /// An expression string that should be evaluated in order to determine - /// the cache key for the item. - /// - public CacheParameterAttribute(string cacheName, string key) - : base(cacheName, key) - { - } + /// + /// Creates an attribute instance. + /// + /// + /// The name of the cache to use. + /// + /// + /// An expression string that should be evaluated in order to determine + /// the cache key for the item. + /// + public CacheParameterAttribute(string cacheName, string key) + : base(cacheName, key) + { } } diff --git a/src/Spring/Spring.Core/Caching/CacheResultAttribute.cs b/src/Spring/Spring.Core/Caching/CacheResultAttribute.cs index 5757e2b4..8c1a8569 100644 --- a/src/Spring/Spring.Core/Caching/CacheResultAttribute.cs +++ b/src/Spring/Spring.Core/Caching/CacheResultAttribute.cs @@ -18,49 +18,48 @@ #endregion -namespace Spring.Caching +namespace Spring.Caching; + +/// +/// This attribute should be used to mark methods whose result +/// needs to be cached. +/// +/// +///

+/// This attribute allows application developers to mark that a result +/// of the method invocation should be cached, but it will not do any +/// caching by itself. +///

+///

+/// In order to actually cache the result, an application developer +/// must apply a Spring.Aspects.Cache.CacheResultAdvice to +/// all of the members that have this attribute defined. +///

+///
+/// Aleksandar Seovic +[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)] +[Serializable] +public sealed class CacheResultAttribute : BaseCacheAttribute { /// - /// This attribute should be used to mark methods whose result - /// needs to be cached. + /// Creates an attribute instance. /// - /// - ///

- /// This attribute allows application developers to mark that a result - /// of the method invocation should be cached, but it will not do any - /// caching by itself. - ///

- ///

- /// In order to actually cache the result, an application developer - /// must apply a Spring.Aspects.Cache.CacheResultAdvice to - /// all of the members that have this attribute defined. - ///

- ///
- /// Aleksandar Seovic - [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)] - [Serializable] - public sealed class CacheResultAttribute : BaseCacheAttribute + public CacheResultAttribute() { - /// - /// Creates an attribute instance. - /// - public CacheResultAttribute() - { - } + } - /// - /// Creates an attribute instance. - /// - /// - /// The name of the cache to use. - /// - /// - /// An expression string that should be evaluated in order to determine - /// the cache key for the item. - /// - public CacheResultAttribute(string cacheName, string key) - : base(cacheName, key) - { - } + /// + /// Creates an attribute instance. + /// + /// + /// The name of the cache to use. + /// + /// + /// An expression string that should be evaluated in order to determine + /// the cache key for the item. + /// + public CacheResultAttribute(string cacheName, string key) + : base(cacheName, key) + { } } diff --git a/src/Spring/Spring.Core/Caching/CacheResultItemsAttribute.cs b/src/Spring/Spring.Core/Caching/CacheResultItemsAttribute.cs index a7fde887..e33817f7 100644 --- a/src/Spring/Spring.Core/Caching/CacheResultItemsAttribute.cs +++ b/src/Spring/Spring.Core/Caching/CacheResultItemsAttribute.cs @@ -20,49 +20,48 @@ using System.Collections; -namespace Spring.Caching +namespace Spring.Caching; + +/// +/// This attribute should be used with methods that return an +/// in order to cache each item separately. +/// +/// +///

+/// This attribute allows application developers to specify that each item +/// from the collection returned by the method should be cached, +/// but it will not do any caching by itself. +///

+///

+/// In order to actually cache the result, an application developer +/// must apply a Spring.Aspects.Cache.CacheResultAdvice to +/// all of the members that have this attribute defined. +///

+///
+/// Aleksandar Seovic +[AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = false)] +[Serializable] +public sealed class CacheResultItemsAttribute : BaseCacheAttribute { /// - /// This attribute should be used with methods that return an - /// in order to cache each item separately. + /// Creates an attribute instance. /// - /// - ///

- /// This attribute allows application developers to specify that each item - /// from the collection returned by the method should be cached, - /// but it will not do any caching by itself. - ///

- ///

- /// In order to actually cache the result, an application developer - /// must apply a Spring.Aspects.Cache.CacheResultAdvice to - /// all of the members that have this attribute defined. - ///

- ///
- /// Aleksandar Seovic - [AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = false)] - [Serializable] - public sealed class CacheResultItemsAttribute : BaseCacheAttribute + public CacheResultItemsAttribute() { - /// - /// Creates an attribute instance. - /// - public CacheResultItemsAttribute() - { - } + } - /// - /// Creates an attribute instance. - /// - /// - /// The name of the cache to use. - /// - /// - /// An expression string that should be evaluated in order to determine - /// the cache key for the item. - /// - public CacheResultItemsAttribute(string cacheName, string key) - : base(cacheName, key) - { - } + /// + /// Creates an attribute instance. + /// + /// + /// The name of the cache to use. + /// + /// + /// An expression string that should be evaluated in order to determine + /// the cache key for the item. + /// + public CacheResultItemsAttribute(string cacheName, string key) + : base(cacheName, key) + { } } diff --git a/src/Spring/Spring.Core/Caching/ICache.cs b/src/Spring/Spring.Core/Caching/ICache.cs index a3446218..10750b2a 100644 --- a/src/Spring/Spring.Core/Caching/ICache.cs +++ b/src/Spring/Spring.Core/Caching/ICache.cs @@ -20,87 +20,86 @@ using System.Collections; -namespace Spring.Caching +namespace Spring.Caching; + +/// +/// Defines a contract that all cache implementations have to fulfill. +/// +/// Aleksandar Seovic +/// Erich Eichinger +public interface ICache { - /// - /// Defines a contract that all cache implementations have to fulfill. - /// - /// Aleksandar Seovic - /// Erich Eichinger - public interface ICache - { - /// - /// Gets the number of items in the cache. - /// - int Count { get; } + /// + /// Gets the number of items in the cache. + /// + int Count { get; } - /// - /// Gets a collection of all cache item keys. - /// - ICollection Keys { get; } + /// + /// Gets a collection of all cache item keys. + /// + ICollection Keys { get; } - /// - /// Retrieves an item from the cache. - /// - /// - /// Item key. - /// - /// - /// Item for the specified , or null. - /// - object Get(object key); + /// + /// Retrieves an item from the cache. + /// + /// + /// Item key. + /// + /// + /// Item for the specified , or null. + /// + object Get(object key); - /// - /// Removes an item from the cache. - /// - /// - /// Item key. - /// - void Remove(object key); + /// + /// Removes an item from the cache. + /// + /// + /// Item key. + /// + void Remove(object key); - /// - /// Removes collection of items from the cache. - /// - /// - /// Collection of keys to remove. - /// - void RemoveAll(ICollection keys); + /// + /// Removes collection of items from the cache. + /// + /// + /// Collection of keys to remove. + /// + void RemoveAll(ICollection keys); - /// - /// Removes all items from the cache. - /// - void Clear(); + /// + /// Removes all items from the cache. + /// + void Clear(); - /// - /// Inserts an item into the cache. - /// - /// - /// Items inserted using this method have no expiration time - /// and default cache priority. - /// - /// - /// Item key. - /// - /// - /// Item value. - /// - void Insert(object key, object value); + /// + /// Inserts an item into the cache. + /// + /// + /// Items inserted using this method have no expiration time + /// and default cache priority. + /// + /// + /// Item key. + /// + /// + /// Item value. + /// + void Insert(object key, object value); - /// - /// Inserts an item into the cache. - /// - /// - /// Items inserted using this method have default cache priority. - /// - /// - /// Item key. - /// - /// - /// Item value. - /// - /// - /// Item's time-to-live. - /// - void Insert(object key, object value, TimeSpan timeToLive); - } + /// + /// Inserts an item into the cache. + /// + /// + /// Items inserted using this method have default cache priority. + /// + /// + /// Item key. + /// + /// + /// Item value. + /// + /// + /// Item's time-to-live. + /// + void Insert(object key, object value, TimeSpan timeToLive); } diff --git a/src/Spring/Spring.Core/Caching/InvalidateCacheAttribute.cs b/src/Spring/Spring.Core/Caching/InvalidateCacheAttribute.cs index d68bd501..b5f4301f 100644 --- a/src/Spring/Spring.Core/Caching/InvalidateCacheAttribute.cs +++ b/src/Spring/Spring.Core/Caching/InvalidateCacheAttribute.cs @@ -20,125 +20,124 @@ using Spring.Expressions; -namespace Spring.Caching +namespace Spring.Caching; + +/// +/// This attribute should be used to mark method that should +/// invalidate one or more cache items when invoked. +/// +/// +///

+/// This attribute allows application developers to specify that some +/// cache items should be evicted from cache when the method is invoked, +/// but it will not do any eviction by itself. +///

+///

+/// In order to actually evict cache items, an application developer +/// must apply a Spring.Aspects.Cache.InvalidateCacheAdvice to +/// all of the members that have this attribute defined. +///

+///
+/// Aleksandar Seovic +[AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = false)] +[Serializable] +public sealed class InvalidateCacheAttribute : Attribute { + private string cacheName; + private string keys; + private IExpression keysExpression; + private string condition; + private IExpression conditionExpression; + /// - /// This attribute should be used to mark method that should - /// invalidate one or more cache items when invoked. + /// Creates an attribute instance. /// - /// - ///

- /// This attribute allows application developers to specify that some - /// cache items should be evicted from cache when the method is invoked, - /// but it will not do any eviction by itself. - ///

- ///

- /// In order to actually evict cache items, an application developer - /// must apply a Spring.Aspects.Cache.InvalidateCacheAdvice to - /// all of the members that have this attribute defined. - ///

- ///
- /// Aleksandar Seovic - [AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = false)] - [Serializable] - public sealed class InvalidateCacheAttribute : Attribute + public InvalidateCacheAttribute() { - private string cacheName; - private string keys; - private IExpression keysExpression; - private string condition; - private IExpression conditionExpression; + } - /// - /// Creates an attribute instance. - /// - public InvalidateCacheAttribute() - { - } + /// + /// Creates an attribute instance. + /// + /// + /// The name of the cache to use. + /// + public InvalidateCacheAttribute(string cacheName) + { + this.cacheName = cacheName; + } - /// - /// Creates an attribute instance. - /// - /// - /// The name of the cache to use. - /// - public InvalidateCacheAttribute(string cacheName) - { - this.cacheName = cacheName; - } + /// + /// Gets or sets the name of the cache to use. + /// + /// + /// The name of the cache to use. + /// + public string CacheName + { + get { return cacheName; } + set { cacheName = value; } + } - /// - /// Gets or sets the name of the cache to use. - /// - /// - /// The name of the cache to use. - /// - public string CacheName + /// + /// Gets or sets a SpEL expression that should be evaluated in order + /// to determine the keys for the items that should be evicted. + /// + /// + /// An expression string that should be evaluated in order + /// to determine the keys for the items that should be evicted. + /// + public string Keys + { + get { return keys; } + set { - get { return cacheName; } - set { cacheName = value; } - } - - /// - /// Gets or sets a SpEL expression that should be evaluated in order - /// to determine the keys for the items that should be evicted. - /// - /// - /// An expression string that should be evaluated in order - /// to determine the keys for the items that should be evicted. - /// - public string Keys - { - get { return keys; } - set - { - keys = value; - keysExpression = Expression.Parse(value); - } - } - - /// - /// Gets an expression instance that should be evaluated in order - /// to determine the keys for the items that should be evicted. - /// - /// - /// An expression instance that should be evaluated in order - /// to determine the keys for the items that should be evicted. - /// - public IExpression KeysExpression - { - get { return keysExpression; } - } - - /// - /// Gets or sets a SpEL expression that should be evaluated in order - /// to determine whether items should be evicted. - /// - /// - /// An expression string that should be evaluated in order to determine - /// whether items should be evicted. - /// - public string Condition - { - get { return condition; } - set - { - condition = value; - conditionExpression = Expression.Parse(value); - } - } - - /// - /// Gets an expression instance that should be evaluated in order - /// to determine whether items should be evicted. - /// - /// - /// An expression instance that should be evaluated in order to determine - /// whether items should be evicted. - /// - public IExpression ConditionExpression - { - get { return conditionExpression; } + keys = value; + keysExpression = Expression.Parse(value); } } + + /// + /// Gets an expression instance that should be evaluated in order + /// to determine the keys for the items that should be evicted. + /// + /// + /// An expression instance that should be evaluated in order + /// to determine the keys for the items that should be evicted. + /// + public IExpression KeysExpression + { + get { return keysExpression; } + } + + /// + /// Gets or sets a SpEL expression that should be evaluated in order + /// to determine whether items should be evicted. + /// + /// + /// An expression string that should be evaluated in order to determine + /// whether items should be evicted. + /// + public string Condition + { + get { return condition; } + set + { + condition = value; + conditionExpression = Expression.Parse(value); + } + } + + /// + /// Gets an expression instance that should be evaluated in order + /// to determine whether items should be evicted. + /// + /// + /// An expression instance that should be evaluated in order to determine + /// whether items should be evicted. + /// + public IExpression ConditionExpression + { + get { return conditionExpression; } + } } diff --git a/src/Spring/Spring.Core/Caching/NonExpiringCache.cs b/src/Spring/Spring.Core/Caching/NonExpiringCache.cs index 49bb65f1..a9e23385 100644 --- a/src/Spring/Spring.Core/Caching/NonExpiringCache.cs +++ b/src/Spring/Spring.Core/Caching/NonExpiringCache.cs @@ -20,125 +20,124 @@ using System.Collections; -namespace Spring.Caching +namespace Spring.Caching; + +/// +/// A simple implementation backed by a dictionary that +/// never expires cache items. +/// +/// Aleksandar Seovic +public class NonExpiringCache : AbstractCache { + private readonly object syncRoot = new object(); + private readonly IDictionary itemStore = new Dictionary(); + /// - /// A simple implementation backed by a dictionary that - /// never expires cache items. + /// Gets the number of items in the cache. /// - /// Aleksandar Seovic - public class NonExpiringCache : AbstractCache + public override int Count { - private readonly object syncRoot = new object(); - private readonly IDictionary itemStore = new Dictionary(); - - /// - /// Gets the number of items in the cache. - /// - public override int Count - { - get - { - lock (syncRoot) - { - return itemStore.Count; - } - } - } - - /// - /// Gets a collection of all cache item keys. - /// - public override ICollection Keys - { - get - { - lock (syncRoot) - { - return (ICollection) itemStore.Keys; - } - } - } - - /// - /// Retrieves an item from the cache. - /// - /// - /// Item key. - /// - /// - /// Item for the specified , or null. - /// - public override object Get(object key) + get { lock (syncRoot) { - object value; - itemStore.TryGetValue(key, out value); - return value; + return itemStore.Count; } } + } - /// - /// Removes an item from the cache. - /// - /// - /// Item key. - /// - public override void Remove(object key) + /// + /// Gets a collection of all cache item keys. + /// + public override ICollection Keys + { + get { lock (syncRoot) + { + return (ICollection) itemStore.Keys; + } + } + } + + /// + /// Retrieves an item from the cache. + /// + /// + /// Item key. + /// + /// + /// Item for the specified , or null. + /// + public override object Get(object key) + { + lock (syncRoot) + { + object value; + itemStore.TryGetValue(key, out value); + return value; + } + } + + /// + /// Removes an item from the cache. + /// + /// + /// Item key. + /// + public override void Remove(object key) + { + lock (syncRoot) + { + itemStore.Remove(key); + } + } + + /// + /// Removes collection of items from the cache. + /// + /// + /// Collection of keys to remove. + /// + public override void RemoveAll(ICollection keys) + { + lock (syncRoot) + { + foreach (object key in keys) { itemStore.Remove(key); } } + } - /// - /// Removes collection of items from the cache. - /// - /// - /// Collection of keys to remove. - /// - public override void RemoveAll(ICollection keys) + /// + /// Removes all items from the cache. + /// + public override void Clear() + { + lock (syncRoot) { - lock (syncRoot) - { - foreach (object key in keys) - { - itemStore.Remove(key); - } - } - } - - /// - /// Removes all items from the cache. - /// - public override void Clear() - { - lock (syncRoot) - { - itemStore.Clear(); - } - } - - /// - /// Inserts an item into the cache. - /// - /// - /// Item key. - /// - /// - /// Item value. - /// - /// - /// Item's time-to-live (TTL) in milliseconds. - /// - protected override void DoInsert(object key, object value, TimeSpan timeToLive) - { - lock (syncRoot) - { - itemStore[key] = value; - } + itemStore.Clear(); } } -} + + /// + /// Inserts an item into the cache. + /// + /// + /// Item key. + /// + /// + /// Item value. + /// + /// + /// Item's time-to-live (TTL) in milliseconds. + /// + protected override void DoInsert(object key, object value, TimeSpan timeToLive) + { + lock (syncRoot) + { + itemStore[key] = value; + } + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Collections/AbstractQueue.cs b/src/Spring/Spring.Core/Collections/AbstractQueue.cs index 246f1768..04fd6ec0 100644 --- a/src/Spring/Spring.Core/Collections/AbstractQueue.cs +++ b/src/Spring/Spring.Core/Collections/AbstractQueue.cs @@ -20,322 +20,325 @@ using System.Collections; -namespace Spring.Collections +namespace Spring.Collections; + +/// +/// This class provides skeletal implementations of some +/// operations. +/// +/// +///

+/// The implementations in this class are appropriate when the base +/// implementation does not allow elements. The methods +/// , +/// , and +/// are based on +/// the , +/// , and +/// methods +/// respectively but throw exceptions instead of indicating failure via +/// or returns. +///

+/// An implementation that extends this class must +/// minimally define a method +/// which does +/// not permit the insertion of elements, along with methods +/// , and +/// . Typically, +/// additional methods will be overridden as well. If these requirements +/// cannot be met, consider instead subclassing +/// }. +///

+///
+/// Doug Lea +/// Griffin Caprio (.NET) +[Serializable] +public abstract class AbstractQueue : IQueue { - /// - /// This class provides skeletal implementations of some - /// operations. - /// - /// - ///

- /// The implementations in this class are appropriate when the base - /// implementation does not allow elements. The methods - /// , - /// , and - /// are based on - /// the , - /// , and - /// methods - /// respectively but throw exceptions instead of indicating failure via - /// or returns. - ///

- /// An implementation that extends this class must - /// minimally define a method - /// which does - /// not permit the insertion of elements, along with methods - /// , and - /// . Typically, - /// additional methods will be overridden as well. If these requirements - /// cannot be met, consider instead subclassing - /// }. - ///

- ///
- /// Doug Lea - /// Griffin Caprio (.NET) - [Serializable] - public abstract class AbstractQueue : IQueue - { - /// - /// Creates a new instance of the class. - /// - /// - ///

- /// This is an abstract class, and as such has no publicly - /// visible constructors. - ///

- ///
- protected AbstractQueue() - {} + /// + /// Creates a new instance of the class. + /// + /// + ///

+ /// This is an abstract class, and as such has no publicly + /// visible constructors. + ///

+ ///
+ protected AbstractQueue() + { + } - /// - /// Inserts the specified element into this queue if it is possible - /// to do so immediately without violating capacity restrictions. - /// - /// - /// The element to add. - /// - /// - /// if successful. - /// - /// - /// If the element cannot be added at this time due to capacity restrictions. - /// - public virtual bool Add(object objectToAdd) - { - if(Offer(objectToAdd)) - { - return true; - } - else - { - throw new InvalidOperationException("Queue full."); - } - } + /// + /// Inserts the specified element into this queue if it is possible + /// to do so immediately without violating capacity restrictions. + /// + /// + /// The element to add. + /// + /// + /// if successful. + /// + /// + /// If the element cannot be added at this time due to capacity restrictions. + /// + public virtual bool Add(object objectToAdd) + { + if (Offer(objectToAdd)) + { + return true; + } + else + { + throw new InvalidOperationException("Queue full."); + } + } - /// - /// Retrieves and removes the head of this queue. - /// - /// - ///

- /// This method differs from - /// only in that - /// it throws an exception if this queue is empty. - ///

- ///
- /// - /// The head of this queue - /// - /// - /// If this queue is empty. - /// - public virtual object Remove() - { - object element = Poll(); - if(element != null) - { - return element; - } - else - { - throw new NoElementsException("Queue is empty."); - } - } + /// + /// Retrieves and removes the head of this queue. + /// + /// + ///

+ /// This method differs from + /// only in that + /// it throws an exception if this queue is empty. + ///

+ ///
+ /// + /// The head of this queue + /// + /// + /// If this queue is empty. + /// + public virtual object Remove() + { + object element = Poll(); + if (element != null) + { + return element; + } + else + { + throw new NoElementsException("Queue is empty."); + } + } + /// + /// Retrieves, but does not remove, the head of this queue. + /// + /// + ///

+ /// This method differs from + /// only in that it throws an exception if this queue is empty. + ///

+ ///

+ /// ALso note that this implementation returns the result of + /// unless the queue + /// is empty. + ///

+ ///
+ /// The head of this queue. + /// + /// If this queue is empty. + /// + public virtual object Element() + { + object element = Peek(); + if (element != null) + { + return element; + } + else + { + throw new NoElementsException("Queue is empty."); + } + } - /// - /// Retrieves, but does not remove, the head of this queue. - /// - /// - ///

- /// This method differs from - /// only in that it throws an exception if this queue is empty. - ///

- ///

- /// ALso note that this implementation returns the result of - /// unless the queue - /// is empty. - ///

- ///
- /// The head of this queue. - /// - /// If this queue is empty. - /// - public virtual object Element() - { - object element = Peek(); - if(element != null) - { - return element; - } - else - { - throw new NoElementsException("Queue is empty."); - } - } + /// + /// Removes all of the elements from this queue. + /// + /// + ///

+ /// The queue will be empty after this call returns. + ///

+ ///

+ /// This implementation repeatedly invokes + /// until it + /// returns . + ///

+ ///
+ public virtual void Clear() + { + while (Poll() != null) + { + ; + } + } - /// - /// Removes all of the elements from this queue. - /// - /// - ///

- /// The queue will be empty after this call returns. - ///

- ///

- /// This implementation repeatedly invokes - /// until it - /// returns . - ///

- ///
- public virtual void Clear() - { - while(Poll() != null) - { - ; - } - } + /// + /// Adds all of the elements in the supplied + /// to this queue. + /// + /// + ///

+ /// Attempts to + /// + /// of a queue to itself result in . + /// Further, the behavior of this operation is undefined if the specified + /// collection is modified while the operation is in progress. + ///

+ ///

+ /// This implementation iterates over the specified collection, + /// and adds each element returned by the iterator to this queue, in turn. + /// An exception encountered while trying to add an element (including, + /// in particular, a element) may result in only some + /// of the elements having been successfully added when the associated + /// exception is thrown. + ///

+ ///
+ /// + /// The collection containing the elements to be added to this queue. + /// + /// + /// if this queue changed as a result of the call. + /// + /// + /// If the supplied or any one of its elements are . + /// + /// + /// If the collection is the current or + /// the collection size is greater than the queue capacity. + /// + public virtual bool AddAll(ICollection collection) + { + if (collection == null) + { + throw new ArgumentNullException("Collection cannot be null."); + } - /// - /// Adds all of the elements in the supplied - /// to this queue. - /// - /// - ///

- /// Attempts to - /// - /// of a queue to itself result in . - /// Further, the behavior of this operation is undefined if the specified - /// collection is modified while the operation is in progress. - ///

- ///

- /// This implementation iterates over the specified collection, - /// and adds each element returned by the iterator to this queue, in turn. - /// An exception encountered while trying to add an element (including, - /// in particular, a element) may result in only some - /// of the elements having been successfully added when the associated - /// exception is thrown. - ///

- ///
- /// - /// The collection containing the elements to be added to this queue. - /// - /// - /// if this queue changed as a result of the call. - /// - /// - /// If the supplied or any one of its elements are . - /// - /// - /// If the collection is the current or - /// the collection size is greater than the queue capacity. - /// - public virtual bool AddAll(ICollection collection) - { - if(collection == null) - { - throw new ArgumentNullException("Collection cannot be null."); - } - if(collection == this) - { - throw new ArgumentException(); - } - if(collection.Count > Capacity) - { - throw new ArgumentException("Collcation size greater than queue capacity."); - } - bool modified = false; - foreach(object element in collection) - { - if(element == null) - { - throw new ArgumentNullException("Cannot add null elements to this queue."); - } - else if(Add(element)) - { - modified = true; - } - } - return modified; - } + if (collection == this) + { + throw new ArgumentException(); + } - /// - /// Inserts the specified element into this queue if it is possible to do - /// so immediately without violating capacity restrictions. - /// - /// - ///

- /// When using a capacity-restricted queue, this method is generally - /// preferable to , - /// which can fail to insert an element only by throwing an exception. - ///

- ///
- /// - /// The element to add. - /// - /// - /// if the element was added to this queue. - /// - /// - /// If the element cannot be added at this time due to capacity restrictions. - /// - /// - /// If the supplied is - /// . - /// - /// - /// If some property of the supplied prevents - /// it from being added to this queue. - /// - public abstract bool Offer(object objectToAdd); + if (collection.Count > Capacity) + { + throw new ArgumentException("Collcation size greater than queue capacity."); + } - /// - /// Retrieves, but does not remove, the head of this queue, - /// or returns if this queue is empty. - /// - /// - /// The head of this queue, or if this queue is empty. - /// - public abstract object Peek(); + bool modified = false; + foreach (object element in collection) + { + if (element == null) + { + throw new ArgumentNullException("Cannot add null elements to this queue."); + } + else if (Add(element)) + { + modified = true; + } + } - /// - /// Retrieves and removes the head of this queue, - /// or returns if this queue is empty. - /// - /// - /// The head of this queue, or if this queue is empty. - /// - public abstract object Poll(); + return modified; + } - /// - /// Returns if there are no elements in the , otherwise. - /// - public abstract bool IsEmpty { get; } + /// + /// Inserts the specified element into this queue if it is possible to do + /// so immediately without violating capacity restrictions. + /// + /// + ///

+ /// When using a capacity-restricted queue, this method is generally + /// preferable to , + /// which can fail to insert an element only by throwing an exception. + ///

+ ///
+ /// + /// The element to add. + /// + /// + /// if the element was added to this queue. + /// + /// + /// If the element cannot be added at this time due to capacity restrictions. + /// + /// + /// If the supplied is + /// . + /// + /// + /// If some property of the supplied prevents + /// it from being added to this queue. + /// + public abstract bool Offer(object objectToAdd); - /// - /// Returns the current capacity of this queue. - /// - public abstract int Capacity { get; } + /// + /// Retrieves, but does not remove, the head of this queue, + /// or returns if this queue is empty. + /// + /// + /// The head of this queue, or if this queue is empty. + /// + public abstract object Peek(); - /// - ///Copies the elements of the to an , starting at a particular index. - /// - ///The one-dimensional that is the destination of the elements copied from . The must have zero-based indexing. - ///The zero-based index in array at which copying begins. - ///array is null. - ///index is less than zero. - ///array is multidimensional.-or- index is equal to or greater than the length of array.-or- The number of elements in the source is greater than the available space from index to the end of the destination array. - ///The type of the source cannot be cast automatically to the type of the destination array. 2 - public abstract void CopyTo(Array array, int index); + /// + /// Retrieves and removes the head of this queue, + /// or returns if this queue is empty. + /// + /// + /// The head of this queue, or if this queue is empty. + /// + public abstract object Poll(); - /// - ///Gets the number of elements contained in the . - /// - /// - ///The number of elements contained in the . - /// - public abstract int Count { get; } + /// + /// Returns if there are no elements in the , otherwise. + /// + public abstract bool IsEmpty { get; } - /// - ///Gets an object that can be used to synchronize access to the . - /// - /// - ///An object that can be used to synchronize access to the . - /// - public abstract object SyncRoot { get; } + /// + /// Returns the current capacity of this queue. + /// + public abstract int Capacity { get; } - /// - ///Gets a value indicating whether access to the is synchronized (thread safe). - /// - /// - ///true if access to the is synchronized (thread safe); otherwise, false. - /// - public abstract bool IsSynchronized { get; } + /// + ///Copies the elements of the to an , starting at a particular index. + /// + ///The one-dimensional that is the destination of the elements copied from . The must have zero-based indexing. + ///The zero-based index in array at which copying begins. + ///array is null. + ///index is less than zero. + ///array is multidimensional.-or- index is equal to or greater than the length of array.-or- The number of elements in the source is greater than the available space from index to the end of the destination array. + ///The type of the source cannot be cast automatically to the type of the destination array. 2 + public abstract void CopyTo(Array array, int index); - /// - ///Returns an enumerator that iterates through a collection. - /// - /// - ///An object that can be used to iterate through the collection. - /// - public abstract IEnumerator GetEnumerator(); - } -} + /// + ///Gets the number of elements contained in the . + /// + /// + ///The number of elements contained in the . + /// + public abstract int Count { get; } + + /// + ///Gets an object that can be used to synchronize access to the . + /// + /// + ///An object that can be used to synchronize access to the . + /// + public abstract object SyncRoot { get; } + + /// + ///Gets a value indicating whether access to the is synchronized (thread safe). + /// + /// + ///true if access to the is synchronized (thread safe); otherwise, false. + /// + public abstract bool IsSynchronized { get; } + + /// + ///Returns an enumerator that iterates through a collection. + /// + /// + ///An object that can be used to iterate through the collection. + /// + public abstract IEnumerator GetEnumerator(); +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Collections/CaseInsensitiveHashtable.cs b/src/Spring/Spring.Core/Collections/CaseInsensitiveHashtable.cs index ef489754..838b4cbd 100644 --- a/src/Spring/Spring.Core/Collections/CaseInsensitiveHashtable.cs +++ b/src/Spring/Spring.Core/Collections/CaseInsensitiveHashtable.cs @@ -3,108 +3,110 @@ using System.Globalization; using System.Runtime.Serialization; using Spring.Util; -namespace Spring.Collections +namespace Spring.Collections; + +/// +/// Provides a performance improved hashtable with case-insensitive (string-only! based) key handling. +/// +/// Erich Eichinger +[Serializable] +public class CaseInsensitiveHashtable : Hashtable { + private readonly CultureInfo _culture; + /// - /// Provides a performance improved hashtable with case-insensitive (string-only! based) key handling. + /// Creates a case-insensitive hashtable using . /// - /// Erich Eichinger - [Serializable] - public class CaseInsensitiveHashtable : Hashtable + public CaseInsensitiveHashtable() + : this(null, CultureInfo.CurrentCulture) { - private readonly CultureInfo _culture; + } - /// - /// Creates a case-insensitive hashtable using . - /// - public CaseInsensitiveHashtable() - : this(null, CultureInfo.CurrentCulture) - {} + /// + /// Creates a case-insensitive hashtable using the given . + /// + /// the to calculate the hashcode + public CaseInsensitiveHashtable(CultureInfo culture) + : this(null, culture) + { + } - /// - /// Creates a case-insensitive hashtable using the given . - /// - /// the to calculate the hashcode - public CaseInsensitiveHashtable(CultureInfo culture) - : this(null, culture) - {} + /// + /// Creates a case-insensitive hashtable using the given , initially + /// populated with entries from another dictionary. + /// + /// the dictionary to copy entries from + /// the to calculate the hashcode + public CaseInsensitiveHashtable(IDictionary d, CultureInfo culture) + { + AssertUtils.ArgumentNotNull(culture, "culture"); + _culture = culture; - /// - /// Creates a case-insensitive hashtable using the given , initially - /// populated with entries from another dictionary. - /// - /// the dictionary to copy entries from - /// the to calculate the hashcode - public CaseInsensitiveHashtable(IDictionary d, CultureInfo culture) + if (d != null) { - AssertUtils.ArgumentNotNull(culture, "culture"); - _culture = culture; - - if (d != null) + IDictionaryEnumerator enumerator = d.GetEnumerator(); + while (enumerator.MoveNext()) { - IDictionaryEnumerator enumerator = d.GetEnumerator(); - while (enumerator.MoveNext()) - { - this.Add(enumerator.Key, enumerator.Value); - } - } - } - - /// - /// Initializes a new, empty instance of the class that is serializable using the specified and objects. - /// - /// A object containing the source and destination of the serialized stream associated with the . - /// A object containing the information required to serialize the object. - /// info is null. - protected CaseInsensitiveHashtable(SerializationInfo info, StreamingContext context) : base(info, context) - { - string cultureName = info.GetString("_cultureName"); - _culture = new CultureInfo(cultureName); - AssertUtils.ArgumentNotNull(_culture, "Culture"); - } - - /// - ///Implements the interface and returns the data needed to serialize the . - /// - /// - ///A object containing the source and destination of the serialized stream associated with the . - ///A object containing the information required to serialize the . - ///info is null. - public override void GetObjectData(SerializationInfo info, StreamingContext context) - { - base.GetObjectData(info, context); - info.AddValue("_cultureName", _culture.Name); - } - - /// - /// Calculate the hashcode of the given string key, using the configured culture. - /// - /// - /// - protected override int GetHash(object key) - { - if (!(key is string)) return key.GetHashCode(); - return _culture.TextInfo.ToLower((string) key).GetHashCode(); - } - - /// - /// Compares two keys - /// - protected override bool KeyEquals(object item, object key) - { - if (!(key is string)) - { - return Equals(item,key); + this.Add(enumerator.Key, enumerator.Value); } - return 0==_culture.CompareInfo.Compare((string) item, (string) key, CompareOptions.IgnoreCase); - } - - /// - /// Creates a shallow copy of the current instance. - /// - public override object Clone() - { - return new CaseInsensitiveHashtable(this, _culture ); } } + + /// + /// Initializes a new, empty instance of the class that is serializable using the specified and objects. + /// + /// A object containing the source and destination of the serialized stream associated with the . + /// A object containing the information required to serialize the object. + /// info is null. + protected CaseInsensitiveHashtable(SerializationInfo info, StreamingContext context) : base(info, context) + { + string cultureName = info.GetString("_cultureName"); + _culture = new CultureInfo(cultureName); + AssertUtils.ArgumentNotNull(_culture, "Culture"); + } + + /// + ///Implements the interface and returns the data needed to serialize the . + /// + /// + ///A object containing the source and destination of the serialized stream associated with the . + ///A object containing the information required to serialize the . + ///info is null. + public override void GetObjectData(SerializationInfo info, StreamingContext context) + { + base.GetObjectData(info, context); + info.AddValue("_cultureName", _culture.Name); + } + + /// + /// Calculate the hashcode of the given string key, using the configured culture. + /// + /// + /// + protected override int GetHash(object key) + { + if (!(key is string)) return key.GetHashCode(); + return _culture.TextInfo.ToLower((string) key).GetHashCode(); + } + + /// + /// Compares two keys + /// + protected override bool KeyEquals(object item, object key) + { + if (!(key is string)) + { + return Equals(item, key); + } + + return 0 == _culture.CompareInfo.Compare((string) item, (string) key, CompareOptions.IgnoreCase); + } + + /// + /// Creates a shallow copy of the current instance. + /// + public override object Clone() + { + return new CaseInsensitiveHashtable(this, _culture); + } } diff --git a/src/Spring/Spring.Core/Collections/DictionarySet.cs b/src/Spring/Spring.Core/Collections/DictionarySet.cs index 79153d81..64435d48 100644 --- a/src/Spring/Spring.Core/Collections/DictionarySet.cs +++ b/src/Spring/Spring.Core/Collections/DictionarySet.cs @@ -18,337 +18,340 @@ using System.Collections; -namespace Spring.Collections +namespace Spring.Collections; + +/// +/// is an +/// class that supports the creation of new +/// types where the underlying data +/// store is an instance. +/// +/// +///

+/// You can use any object that implements the +/// interface to hold set +/// data. You can define your own, or you can use one of the objects +/// provided in the framework. The type of +/// you +/// choose will affect both the performance and the behavior of the +/// using it. +///

+///

+/// This object overrides the method, +/// but not the method, because +/// the class is mutable. +/// Therefore, it is not safe to use as a key value in a dictionary. +///

+///

+/// To make a typed based on your +/// own , simply derive a new +/// class with a constructor that takes no parameters. Some +/// implmentations cannot be defined +/// with a default constructor. If this is the case for your class, you +/// will need to override clone as well. +///

+///

+/// It is also standard practice that at least one of your constructors +/// takes an or an +/// as an argument. +///

+///
+/// +[Serializable] +public abstract class DictionarySet : Set { + private IDictionary _internalDictionary; + + private static readonly object PlaceholderObject = new object(); + private static readonly object NullPlaceHolderKey = new object(); + /// - /// is an - /// class that supports the creation of new - /// types where the underlying data - /// store is an instance. + /// Provides the storage for elements in the + /// , stored as the key-set + /// of the object. /// /// ///

- /// You can use any object that implements the - /// interface to hold set - /// data. You can define your own, or you can use one of the objects - /// provided in the framework. The type of - /// you - /// choose will affect both the performance and the behavior of the - /// using it. - ///

- ///

- /// This object overrides the method, - /// but not the method, because - /// the class is mutable. - /// Therefore, it is not safe to use as a key value in a dictionary. - ///

- ///

- /// To make a typed based on your - /// own , simply derive a new - /// class with a constructor that takes no parameters. Some - /// implmentations cannot be defined - /// with a default constructor. If this is the case for your class, you - /// will need to override clone as well. - ///

- ///

- /// It is also standard practice that at least one of your constructors - /// takes an or an - /// as an argument. + /// Set this object in the constructor if you create your own + /// class. ///

///
- /// - [Serializable] - public abstract class DictionarySet : Set + protected IDictionary InternalDictionary { - private IDictionary _internalDictionary; + get => _internalDictionary; + set => _internalDictionary = value; + } - private static readonly object PlaceholderObject = new object(); - private static readonly object NullPlaceHolderKey = new object(); + /// + /// The placeholder object used as the value for the + /// instance. + /// + /// + /// There is a single instance of this object globally, used for all + /// s. + /// + protected static object Placeholder => PlaceholderObject; - /// - /// Provides the storage for elements in the - /// , stored as the key-set - /// of the object. - /// - /// - ///

- /// Set this object in the constructor if you create your own - /// class. - ///

- ///
- protected IDictionary InternalDictionary + /// + /// Adds the specified element to this set if it is not already present. + /// + /// The object to add to the set. + /// + /// is the object was added, + /// if the object was already present. + /// + public override bool Add(object element) + { + element = MaskNull(element); + if (_internalDictionary[element] != null) { - get => _internalDictionary; - set => _internalDictionary = value; + return false; } - /// - /// The placeholder object used as the value for the - /// instance. - /// - /// - /// There is a single instance of this object globally, used for all - /// s. - /// - protected static object Placeholder => PlaceholderObject; + //The object we are adding is just a placeholder. The thing we are + //really concerned with is 'o', the key. + _internalDictionary.Add(element, PlaceholderObject); + return true; + } - /// - /// Adds the specified element to this set if it is not already present. - /// - /// The object to add to the set. - /// - /// is the object was added, - /// if the object was already present. - /// - public override bool Add(object element) + /// + /// Adds all the elements in the specified collection to the set if + /// they are not already present. + /// + /// A collection of objects to add to the set. + /// + /// is the set changed as a result of this + /// operation. + /// + public override bool AddAll(ICollection collection) + { + bool changed = false; + foreach (object o in collection) { - element = MaskNull(element); - if (_internalDictionary[element] != null) + changed |= Add(o); + } + + return changed; + } + + /// + /// Removes all objects from this set. + /// + public override void Clear() + { + _internalDictionary.Clear(); + } + + /// + /// Returns if this set contains the specified + /// element. + /// + /// The element to look for. + /// + /// if this set contains the specified element. + /// + public override bool Contains(object element) + { + element = MaskNull(element); + return _internalDictionary[element] != null; + } + + /// + /// Returns if the set contains all the + /// elements in the specified collection. + /// + /// A collection of objects. + /// + /// if the set contains all the elements in the + /// specified collection; also if the + /// supplied is . + /// + public override bool ContainsAll(ICollection collection) + { + if (collection == null) + { + return false; + } + + foreach (object o in collection) + { + if (!Contains(MaskNull(o))) { return false; } - - //The object we are adding is just a placeholder. The thing we are - //really concerned with is 'o', the key. - _internalDictionary.Add(element, PlaceholderObject); - return true; } - /// - /// Adds all the elements in the specified collection to the set if - /// they are not already present. - /// - /// A collection of objects to add to the set. - /// - /// is the set changed as a result of this - /// operation. - /// - public override bool AddAll(ICollection collection) + return true; + } + + /// + /// Returns if this set contains no elements. + /// + public override bool IsEmpty => _internalDictionary.Count == 0; + + /// + /// Removes the specified element from the set. + /// + /// The element to be removed. + /// + /// if the set contained the specified element. + /// + public override bool Remove(object element) + { + element = MaskNull(element); + bool contained = Contains(element); + if (contained) { - bool changed = false; - foreach (object o in collection) + _internalDictionary.Remove(element); + } + + return contained; + } + + /// + /// Remove all the specified elements from this set, if they exist in + /// this set. + /// + /// A collection of elements to remove. + /// + /// if the set was modified as a result of this + /// operation. + /// + public override bool RemoveAll(ICollection collection) + { + bool changed = false; + foreach (object o in collection) + { + changed |= Remove(o); + } + + return changed; + } + + /// + /// Retains only the elements in this set that are contained in the + /// specified collection. + /// + /// + /// The collection that defines the set of elements to be retained. + /// + /// + /// if this set changed as a result of this + /// operation. + /// + public override bool RetainAll(ICollection collection) + { + //Put data from C into a set so we can use the Contains() method. + Set cSet = new HybridSet(collection); + + //We are going to build a set of elements to remove. + Set removeSet = new HybridSet(); + + foreach (object o in this) + { + //If C does not contain O, then we need to remove O from our + //set. We can't do this while iterating through our set, so + //we put it into RemoveSet for later. + if (!cSet.Contains(o)) { - changed |= Add(o); - } - return changed; - } - - /// - /// Removes all objects from this set. - /// - public override void Clear() - { - _internalDictionary.Clear(); - } - - /// - /// Returns if this set contains the specified - /// element. - /// - /// The element to look for. - /// - /// if this set contains the specified element. - /// - public override bool Contains(object element) - { - element = MaskNull(element); - return _internalDictionary[element] != null; - } - - /// - /// Returns if the set contains all the - /// elements in the specified collection. - /// - /// A collection of objects. - /// - /// if the set contains all the elements in the - /// specified collection; also if the - /// supplied is . - /// - public override bool ContainsAll(ICollection collection) - { - if (collection == null) - { - return false; - } - foreach (object o in collection) - { - if (!Contains(MaskNull(o))) - { - return false; - } - } - return true; - } - - /// - /// Returns if this set contains no elements. - /// - public override bool IsEmpty => _internalDictionary.Count == 0; - - /// - /// Removes the specified element from the set. - /// - /// The element to be removed. - /// - /// if the set contained the specified element. - /// - public override bool Remove(object element) - { - element = MaskNull(element); - bool contained = Contains(element); - if (contained) - { - _internalDictionary.Remove(element); - } - return contained; - } - - /// - /// Remove all the specified elements from this set, if they exist in - /// this set. - /// - /// A collection of elements to remove. - /// - /// if the set was modified as a result of this - /// operation. - /// - public override bool RemoveAll(ICollection collection) - { - bool changed = false; - foreach (object o in collection) - { - changed |= Remove(o); - } - return changed; - } - - /// - /// Retains only the elements in this set that are contained in the - /// specified collection. - /// - /// - /// The collection that defines the set of elements to be retained. - /// - /// - /// if this set changed as a result of this - /// operation. - /// - public override bool RetainAll(ICollection collection) - { - //Put data from C into a set so we can use the Contains() method. - Set cSet = new HybridSet(collection); - - //We are going to build a set of elements to remove. - Set removeSet = new HybridSet(); - - foreach (object o in this) - { - //If C does not contain O, then we need to remove O from our - //set. We can't do this while iterating through our set, so - //we put it into RemoveSet for later. - if (!cSet.Contains(o)) - { - removeSet.Add(o); - } - } - return RemoveAll(removeSet); - } - - /// - /// Copies the elements in the to - /// an array. - /// - /// - ///

- /// The type of array needs to be compatible with the objects in the - /// , obviously. - ///

- ///
- /// - /// An array that will be the target of the copy operation. - /// - /// - /// The zero-based index where copying will start. - /// - public override void CopyTo(Array array, int index) - { - int i = index; - foreach (object o in this) - { - array.SetValue(UnmaskNull(o), i++); + removeSet.Add(o); } } - /// - /// The number of elements currently contained in this collection. - /// - public override int Count => _internalDictionary.Count; + return RemoveAll(removeSet); + } - /// - /// Returns if the - /// is synchronized across - /// threads. - /// - /// - public override bool IsSynchronized => false; - - /// - /// An object that can be used to synchronize this collection to make - /// it thread-safe. - /// - /// - /// An object that can be used to synchronize this collection to make - /// it thread-safe. - /// - /// - public override object SyncRoot => _internalDictionary.SyncRoot; - - /// - /// Gets an enumerator for the elements in the - /// . - /// - /// - /// An over the elements - /// in the . - /// - public override IEnumerator GetEnumerator() + /// + /// Copies the elements in the to + /// an array. + /// + /// + ///

+ /// The type of array needs to be compatible with the objects in the + /// , obviously. + ///

+ ///
+ /// + /// An array that will be the target of the copy operation. + /// + /// + /// The zero-based index where copying will start. + /// + public override void CopyTo(Array array, int index) + { + int i = index; + foreach (object o in this) { - return new DictionarySetEnumerator(_internalDictionary.Keys.GetEnumerator()); - } - - - - private static object MaskNull(object key) - { - return key ?? NullPlaceHolderKey; - } - - private static object UnmaskNull(object key) - { - return key == NullPlaceHolderKey ? null : key; - } - - private struct DictionarySetEnumerator : IEnumerator - { - public DictionarySetEnumerator(IEnumerator enumerator) - { - _enumerator = enumerator; - } - - public void Reset() - { - _enumerator.Reset(); - } - - public object Current => UnmaskNull(_enumerator.Current); - - public bool MoveNext() - { - return _enumerator.MoveNext(); - } - - private readonly IEnumerator _enumerator; + array.SetValue(UnmaskNull(o), i++); } } + + /// + /// The number of elements currently contained in this collection. + /// + public override int Count => _internalDictionary.Count; + + /// + /// Returns if the + /// is synchronized across + /// threads. + /// + /// + public override bool IsSynchronized => false; + + /// + /// An object that can be used to synchronize this collection to make + /// it thread-safe. + /// + /// + /// An object that can be used to synchronize this collection to make + /// it thread-safe. + /// + /// + public override object SyncRoot => _internalDictionary.SyncRoot; + + /// + /// Gets an enumerator for the elements in the + /// . + /// + /// + /// An over the elements + /// in the . + /// + public override IEnumerator GetEnumerator() + { + return new DictionarySetEnumerator(_internalDictionary.Keys.GetEnumerator()); + } + + private static object MaskNull(object key) + { + return key ?? NullPlaceHolderKey; + } + + private static object UnmaskNull(object key) + { + return key == NullPlaceHolderKey ? null : key; + } + + private struct DictionarySetEnumerator : IEnumerator + { + public DictionarySetEnumerator(IEnumerator enumerator) + { + _enumerator = enumerator; + } + + public void Reset() + { + _enumerator.Reset(); + } + + public object Current => UnmaskNull(_enumerator.Current); + + public bool MoveNext() + { + return _enumerator.MoveNext(); + } + + private readonly IEnumerator _enumerator; + } } diff --git a/src/Spring/Spring.Core/Collections/Generic/AbstractDictionary.cs b/src/Spring/Spring.Core/Collections/Generic/AbstractDictionary.cs index 6f60cde5..496054c0 100644 --- a/src/Spring/Spring.Core/Collections/Generic/AbstractDictionary.cs +++ b/src/Spring/Spring.Core/Collections/Generic/AbstractDictionary.cs @@ -18,87 +18,91 @@ #endregion -namespace Spring.Collections.Generic +namespace Spring.Collections.Generic; + +/// +/// Partial IDictionary implementation which serves as a common base for final implementations. +/// +/// Zbynek Vyskovsky, kvr@centrum.cz +public abstract class AbstractDictionary : System.Collections.Generic.IDictionary { - /// - /// Partial IDictionary implementation which serves as a common base for final implementations. - /// - /// Zbynek Vyskovsky, kvr@centrum.cz - public abstract class AbstractDictionary: System.Collections.Generic.IDictionary - { - public abstract void Add(TKey key, TValue value); + public abstract void Add(TKey key, TValue value); - public abstract bool ContainsKey(TKey key); + public abstract bool ContainsKey(TKey key); - public abstract bool Remove(TKey key); + public abstract bool Remove(TKey key); - public abstract bool TryGetValue(TKey key, out TValue value); + public abstract bool TryGetValue(TKey key, out TValue value); - public abstract void Clear(); + public abstract void Clear(); - public bool Contains(KeyValuePair item) - { - TValue value; - return TryGetValue(item.Key, out value) && (item.Value == null ? value == null : item.Value.Equals(value)); - } + public bool Contains(KeyValuePair item) + { + TValue value; + return TryGetValue(item.Key, out value) && (item.Value == null ? value == null : item.Value.Equals(value)); + } - public void CopyTo(KeyValuePair[] array, int arrayIndex) - { - } + public void CopyTo(KeyValuePair[] array, int arrayIndex) + { + } - public abstract int Count { get; } + public abstract int Count { get; } - public bool IsReadOnly - { - get { - return false; - } - } + public bool IsReadOnly + { + get + { + return false; + } + } - public abstract bool Remove(KeyValuePair item); + public abstract bool Remove(KeyValuePair item); - public IEnumerator> GetEnumerator() - { - return EntriesSet().GetEnumerator(); - } + public IEnumerator> GetEnumerator() + { + return EntriesSet().GetEnumerator(); + } - System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() - { - return EntriesSet().GetEnumerator(); - } + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return EntriesSet().GetEnumerator(); + } - public ICollection Keys - { - get { - return EntriesSet().Select((KeyValuePair entry) => entry.Key).ToList(); - } - } + public ICollection Keys + { + get + { + return EntriesSet().Select((KeyValuePair entry) => entry.Key).ToList(); + } + } - public ICollection Values - { - get { - return EntriesSet().Select((KeyValuePair entry) => entry.Value).ToList(); - } - } + public ICollection Values + { + get + { + return EntriesSet().Select((KeyValuePair entry) => entry.Value).ToList(); + } + } - public TValue this[TKey key] - { - get { - TValue value; - if (!TryGetValue(key, out value)) - throw new KeyNotFoundException("Key not found in map: "+key); - return value; - } - set { - Add(key, value); - } - } + public TValue this[TKey key] + { + get + { + TValue value; + if (!TryGetValue(key, out value)) + throw new KeyNotFoundException("Key not found in map: " + key); + return value; + } + set + { + Add(key, value); + } + } - public void Add(KeyValuePair item) - { - Add(item.Key, item.Value); - } + public void Add(KeyValuePair item) + { + Add(item.Key, item.Value); + } - protected abstract IEnumerable> EntriesSet(); - } + protected abstract IEnumerable> EntriesSet(); } diff --git a/src/Spring/Spring.Core/Collections/Generic/DictionarySet.cs b/src/Spring/Spring.Core/Collections/Generic/DictionarySet.cs index f53f3eb1..f5db4ade 100644 --- a/src/Spring/Spring.Core/Collections/Generic/DictionarySet.cs +++ b/src/Spring/Spring.Core/Collections/Generic/DictionarySet.cs @@ -2,246 +2,247 @@ using System.Collections; -namespace Spring.Collections.Generic +namespace Spring.Collections.Generic; + +/// +///

DictionarySet is an abstract class that supports the creation of new Set +/// types where the underlying data store is an IDictionary instance.

+/// +///

You can use any object that implements the IDictionary interface to hold set data. +/// You can define your own, or you can use one of the objects provided in the Framework. +/// The type of IDictionary you choose will affect both the performance and the behavior +/// of the Set using it.

+/// +///

To make a Set typed based on your own IDictionary, simply derive a +/// new class with a constructor that takes no parameters. Some Set implmentations +/// cannot be defined with a default constructor. If this is the case for your class, +/// you will need to override Clone() as well.

+/// +///

It is also standard practice that at least one of your constructors takes an ICollection or +/// an ISet as an argument.

+///
+[Serializable] +public abstract class DictionarySet : Set { /// - ///

DictionarySet is an abstract class that supports the creation of new Set - /// types where the underlying data store is an IDictionary instance.

- /// - ///

You can use any object that implements the IDictionary interface to hold set data. - /// You can define your own, or you can use one of the objects provided in the Framework. - /// The type of IDictionary you choose will affect both the performance and the behavior - /// of the Set using it.

- /// - ///

To make a Set typed based on your own IDictionary, simply derive a - /// new class with a constructor that takes no parameters. Some Set implmentations - /// cannot be defined with a default constructor. If this is the case for your class, - /// you will need to override Clone() as well.

- /// - ///

It is also standard practice that at least one of your constructors takes an ICollection or - /// an ISet as an argument.

+ /// Provides the storage for elements in the Set, stored as the key-set + /// of the IDictionary object. Set this object in the constructor + /// if you create your own Set class. ///
- [Serializable] - public abstract class DictionarySet : Set + protected IDictionary InternalDictionary = null; + + private static readonly object PlaceholderObject = new object(); + + /// + /// The placeholder object used as the value for the IDictionary instance. + /// + /// + /// There is a single instance of this object globally, used for all Sets. + /// + protected object Placeholder { - /// - /// Provides the storage for elements in the Set, stored as the key-set - /// of the IDictionary object. Set this object in the constructor - /// if you create your own Set class. - /// - protected IDictionary InternalDictionary = null; + get { return PlaceholderObject; } + } - private static readonly object PlaceholderObject = new object(); - - /// - /// The placeholder object used as the value for the IDictionary instance. - /// - /// - /// There is a single instance of this object globally, used for all Sets. - /// - protected object Placeholder + /// + /// Adds the specified element to this set if it is not already present. + /// + /// The to add to the set. + /// is the object was added, if it was already present. + public override bool Add(T o) + { + if (InternalDictionary.ContainsKey(o)) { - get { return PlaceholderObject; } + return false; + } + else + { + //The object we are adding is just a placeholder. The thing we are + //really concerned with is 'o', the key. + InternalDictionary.Add(o, PlaceholderObject); + return true; + } + } + + /// + /// Adds all the elements in the specified collection to the set if they are not already present. + /// + /// A collection of objects to add to the set. + /// is the set changed as a result of this operation, if not. + public override bool AddAll(ICollection c) + { + bool changed = false; + foreach (T o in c) + { + changed |= this.Add(o); } + return changed; + } - /// - /// Adds the specified element to this set if it is not already present. - /// - /// The to add to the set. - /// is the object was added, if it was already present. - public override bool Add(T o) + /// + /// Removes all objects from the set. + /// + public override void Clear() + { + InternalDictionary.Clear(); + } + + /// + /// Returns if this set contains the specified element. + /// + /// The element to look for. + /// if this set contains the specified element, otherwise. + public override bool Contains(T o) + { + return InternalDictionary.ContainsKey(o); + } + + /// + /// Returns if the set contains all the elements in the specified collection. + /// + /// A collection of objects. + /// if the set contains all the elements in the specified collection, otherwise. + public override bool ContainsAll(ICollection c) + { + foreach (T o in c) { - if (InternalDictionary.ContainsKey(o)) + if (!this.Contains(o)) { return false; } - else - { - //The object we are adding is just a placeholder. The thing we are - //really concerned with is 'o', the key. - InternalDictionary.Add(o, PlaceholderObject); - return true; - } } - /// - /// Adds all the elements in the specified collection to the set if they are not already present. - /// - /// A collection of objects to add to the set. - /// is the set changed as a result of this operation, if not. - public override bool AddAll(ICollection c) + return true; + } + + /// + /// Returns if this set contains no elements. + /// + public override bool IsEmpty + { + get { return InternalDictionary.Count == 0; } + } + + /// + /// Removes the specified element from the set. + /// + /// The element to be removed. + /// if the set contained the specified element, otherwise. + public override bool Remove(T o) + { + bool contained = this.Contains(o); + if (contained) { - bool changed = false; - foreach (T o in c) - { - changed |= this.Add(o); - } - return changed; + InternalDictionary.Remove(o); } - /// - /// Removes all objects from the set. - /// - public override void Clear() + return contained; + } + + /// + /// Remove all the specified elements from this set, if they exist in this set. + /// + /// A collection of elements to remove. + /// if the set was modified as a result of this operation. + public override bool RemoveAll(ICollection c) + { + bool changed = false; + foreach (T o in c) { - InternalDictionary.Clear(); + changed |= this.Remove(o); } - /// - /// Returns if this set contains the specified element. - /// - /// The element to look for. - /// if this set contains the specified element, otherwise. - public override bool Contains(T o) + return changed; + } + + /// + /// Retains only the elements in this set that are contained in the specified collection. + /// + /// Collection that defines the set of elements to be retained. + /// if this set changed as a result of this operation. + public override bool RetainAll(ICollection c) + { + //Put data from C into a set so we can use the Contains() method. + Set cSet = new HashedSet(c); + + //We are going to build a set of elements to remove. + Set removeSet = new HashedSet(); + + foreach (T o in this) { - return InternalDictionary.ContainsKey(o); + //If C does not contain O, then we need to remove O from our + //set. We can't do this while iterating through our set, so + //we put it into RemoveSet for later. + if (!cSet.Contains(o)) + removeSet.Add(o); } - /// - /// Returns if the set contains all the elements in the specified collection. - /// - /// A collection of objects. - /// if the set contains all the elements in the specified collection, otherwise. - public override bool ContainsAll(ICollection c) - { - foreach (T o in c) - { - if (!this.Contains(o)) - { - return false; - } - } - return true; - } + return this.RemoveAll(removeSet); + } - /// - /// Returns if this set contains no elements. - /// - public override bool IsEmpty - { - get { return InternalDictionary.Count == 0; } - } + /// + /// Copies the elements in the Set to an array of T. The type of array needs + /// to be compatible with the objects in the Set, obviously. + /// + /// An array that will be the target of the copy operation. + /// The zero-based index where copying will start. + public override void CopyTo(T[] array, int index) + { + InternalDictionary.Keys.CopyTo(array, index); + } - /// - /// Removes the specified element from the set. - /// - /// The element to be removed. - /// if the set contained the specified element, otherwise. - public override bool Remove(T o) - { - bool contained = this.Contains(o); - if (contained) - { - InternalDictionary.Remove(o); - } - return contained; - } + /// + /// The number of elements contained in this collection. + /// + public override int Count + { + get { return InternalDictionary.Count; } + } - /// - /// Remove all the specified elements from this set, if they exist in this set. - /// - /// A collection of elements to remove. - /// if the set was modified as a result of this operation. - public override bool RemoveAll(ICollection c) - { - bool changed = false; - foreach (T o in c) - { - changed |= this.Remove(o); - } - return changed; - } + /// + /// None of the objects based on DictionarySet are synchronized. Use the + /// SyncRoot property instead. + /// + public override bool IsSynchronized + { + get { return false; } + } - /// - /// Retains only the elements in this set that are contained in the specified collection. - /// - /// Collection that defines the set of elements to be retained. - /// if this set changed as a result of this operation. - public override bool RetainAll(ICollection c) - { - //Put data from C into a set so we can use the Contains() method. - Set cSet = new HashedSet(c); + /// + /// Returns an object that can be used to synchronize the Set between threads. + /// + public override object SyncRoot + { + get { return ((ICollection) InternalDictionary).SyncRoot; } + } - //We are going to build a set of elements to remove. - Set removeSet = new HashedSet(); + /// + /// Gets an enumerator for the elements in the Set. + /// + /// An IEnumerator over the elements in the Set. + public override IEnumerator GetEnumerator() + { + return InternalDictionary.Keys.GetEnumerator(); + } - foreach (T o in this) - { - //If C does not contain O, then we need to remove O from our - //set. We can't do this while iterating through our set, so - //we put it into RemoveSet for later. - if (!cSet.Contains(o)) - removeSet.Add(o); - } + /// + /// Indicates wether the Set is read-only or not + /// + public override bool IsReadOnly + { + get { return InternalDictionary.IsReadOnly; } + } - return this.RemoveAll(removeSet); - } - - - /// - /// Copies the elements in the Set to an array of T. The type of array needs - /// to be compatible with the objects in the Set, obviously. - /// - /// An array that will be the target of the copy operation. - /// The zero-based index where copying will start. - public override void CopyTo(T[] array, int index) - { - InternalDictionary.Keys.CopyTo(array, index); - } - - /// - /// The number of elements contained in this collection. - /// - public override int Count - { - get { return InternalDictionary.Count; } - } - - /// - /// None of the objects based on DictionarySet are synchronized. Use the - /// SyncRoot property instead. - /// - public override bool IsSynchronized - { - get { return false; } - } - - /// - /// Returns an object that can be used to synchronize the Set between threads. - /// - public override object SyncRoot - { - get { return ((ICollection)InternalDictionary).SyncRoot; } - } - - /// - /// Gets an enumerator for the elements in the Set. - /// - /// An IEnumerator over the elements in the Set. - public override IEnumerator GetEnumerator() - { - return InternalDictionary.Keys.GetEnumerator(); - } - - /// - /// Indicates wether the Set is read-only or not - /// - public override bool IsReadOnly - { - get { return InternalDictionary.IsReadOnly; } - } - - /// - /// Copies the elements in the Set to an array. The type of array needs - /// to be compatible with the objects in the Set, obviously. Needed for - /// non-generic ISet methods implementation - /// - /// An array that will be the target of the copy operation. - /// The zero-based index where copying will start. - protected override void NonGenericCopyTo(Array array, int index) - { - ((ICollection)InternalDictionary.Keys).CopyTo(array, index); - } + /// + /// Copies the elements in the Set to an array. The type of array needs + /// to be compatible with the objects in the Set, obviously. Needed for + /// non-generic ISet methods implementation + /// + /// An array that will be the target of the copy operation. + /// The zero-based index where copying will start. + protected override void NonGenericCopyTo(Array array, int index) + { + ((ICollection) InternalDictionary.Keys).CopyTo(array, index); } } diff --git a/src/Spring/Spring.Core/Collections/Generic/HashedSet.cs b/src/Spring/Spring.Core/Collections/Generic/HashedSet.cs index 85bc87ae..d68b5878 100644 --- a/src/Spring/Spring.Core/Collections/Generic/HashedSet.cs +++ b/src/Spring/Spring.Core/Collections/Generic/HashedSet.cs @@ -1,32 +1,31 @@ /* Copyright � 2002-2011 by Aidant Systems, Inc., and by Jason Smith. */ -namespace Spring.Collections.Generic +namespace Spring.Collections.Generic; + +/// +/// Implements a Set based on a Dictionary (which is equivalent of +/// non-genric HashTable) This will give the best lookup, add, and remove +/// performance for very large data-sets, but iteration will occur in no particular order. +/// +[Serializable] +public class HashedSet : DictionarySet { /// - /// Implements a Set based on a Dictionary (which is equivalent of - /// non-genric HashTable) This will give the best lookup, add, and remove - /// performance for very large data-sets, but iteration will occur in no particular order. + /// Creates a new set instance based on a Dictinary. /// - [Serializable] - public class HashedSet : DictionarySet + public HashedSet() { - /// - /// Creates a new set instance based on a Dictinary. - /// - public HashedSet() - { - InternalDictionary = new Dictionary(); - } + InternalDictionary = new Dictionary(); + } - /// - /// Creates a new set instance based on a Dictinary and - /// initializes it based on a collection of elements. - /// - /// A collection of elements that defines the initial set contents. - public HashedSet(ICollection initialValues) - : this() - { - this.AddAll(initialValues); - } + /// + /// Creates a new set instance based on a Dictinary and + /// initializes it based on a collection of elements. + /// + /// A collection of elements that defines the initial set contents. + public HashedSet(ICollection initialValues) + : this() + { + this.AddAll(initialValues); } } diff --git a/src/Spring/Spring.Core/Collections/Generic/ISet.cs b/src/Spring/Spring.Core/Collections/Generic/ISet.cs index 175ba7a1..8ca725af 100644 --- a/src/Spring/Spring.Core/Collections/Generic/ISet.cs +++ b/src/Spring/Spring.Core/Collections/Generic/ISet.cs @@ -20,138 +20,136 @@ using System.Collections; -namespace Spring.Collections.Generic +namespace Spring.Collections.Generic; + +/// +///

A collection that contains no duplicate elements. This interface models the mathematical +/// Set abstraction. +/// The order of elements in a set is dependent on (a)the data-structure implementation, and +/// (b)the implementation of the various Set methods, and thus is not guaranteed.

+/// +///

None of the Set implementations in this library are guaranteed to be thread-safe +/// in any way unless wrapped in a SynchronizedSet.

+/// +///

The following table summarizes the binary operators that are supported by the Set class.

+/// +/// +/// Operation +/// Description +/// Method +/// +/// +/// Union (OR) +/// Element included in result if it exists in either A OR B. +/// Union() +/// +/// +/// Intersection (AND) +/// Element included in result if it exists in both A AND B. +/// InterSect() +/// +/// +/// Exclusive Or (XOR) +/// Element included in result if it exists in one, but not both, of A and B. +/// ExclusiveOr() +/// +/// +/// Minus (n/a) +/// Take all the elements in A. Now, if any of them exist in B, remove +/// them. Note that unlike the other operators, A - B is not the same as B - A. +/// Minus() +/// +/// +///
+public interface ISet : ICollection, IEnumerable, IEnumerable, ICloneable { + // Clear is declared in ICollection, but not in ICollection + // void Clear(); + + // Remove is declared in ICollection, but not in ICollection + // bool Remove(T o); + + // Contains is declared in ICollection, but not in ICollection + // bool Contains(T o); + /// - ///

A collection that contains no duplicate elements. This interface models the mathematical - /// Set abstraction. - /// The order of elements in a set is dependent on (a)the data-structure implementation, and - /// (b)the implementation of the various Set methods, and thus is not guaranteed.

- /// - ///

None of the Set implementations in this library are guaranteed to be thread-safe - /// in any way unless wrapped in a SynchronizedSet.

- /// - ///

The following table summarizes the binary operators that are supported by the Set class.

- /// - /// - /// Operation - /// Description - /// Method - /// - /// - /// Union (OR) - /// Element included in result if it exists in either A OR B. - /// Union() - /// - /// - /// Intersection (AND) - /// Element included in result if it exists in both A AND B. - /// InterSect() - /// - /// - /// Exclusive Or (XOR) - /// Element included in result if it exists in one, but not both, of A and B. - /// ExclusiveOr() - /// - /// - /// Minus (n/a) - /// Take all the elements in A. Now, if any of them exist in B, remove - /// them. Note that unlike the other operators, A - B is not the same as B - A. - /// Minus() - /// - /// + /// Performs a "union" of the two sets, where all the elements + /// in both sets are present. That is, the element is included if it is in either a or b. + /// Neither this set nor the input set are modified during the operation. The return value + /// is a Clone() of this set with the extra elements added in. ///
- public interface ISet : ICollection, IEnumerable, IEnumerable, ICloneable - { - // Clear is declared in ICollection, but not in ICollection - // void Clear(); + /// A collection of elements. + /// A new Set containing the union of this Set with the specified collection. + /// Neither of the input objects is modified by the union. + ISet Union(ISet a); - // Remove is declared in ICollection, but not in ICollection - // bool Remove(T o); + /// + /// Performs an "intersection" of the two sets, where only the elements + /// that are present in both sets remain. That is, the element is included if it exists in + /// both sets. The Intersect() operation does not modify the input sets. It returns + /// a Clone() of this set with the appropriate elements removed. + /// + /// A set of elements. + /// The intersection of this set with a. + ISet Intersect(ISet a); - // Contains is declared in ICollection, but not in ICollection - // bool Contains(T o); + /// + /// Performs a "minus" of set b from set a. This returns a set of all + /// the elements in set a, removing the elements that are also in set b. + /// The original sets are not modified during this operation. The result set is a Clone() + /// of this Set containing the elements from the operation. + /// + /// A set of elements. + /// A set containing the elements from this set with the elements in a removed. + ISet Minus(ISet a); - /// - /// Performs a "union" of the two sets, where all the elements - /// in both sets are present. That is, the element is included if it is in either a or b. - /// Neither this set nor the input set are modified during the operation. The return value - /// is a Clone() of this set with the extra elements added in. - /// - /// A collection of elements. - /// A new Set containing the union of this Set with the specified collection. - /// Neither of the input objects is modified by the union. - ISet Union(ISet a); + /// + /// Performs an "exclusive-or" of the two sets, keeping only the elements that + /// are in one of the sets, but not in both. The original sets are not modified + /// during this operation. The result set is a Clone() of this set containing + /// the elements from the exclusive-or operation. + /// + /// A set of elements. + /// A set containing the result of a ^ b. + ISet ExclusiveOr(ISet a); - /// - /// Performs an "intersection" of the two sets, where only the elements - /// that are present in both sets remain. That is, the element is included if it exists in - /// both sets. The Intersect() operation does not modify the input sets. It returns - /// a Clone() of this set with the appropriate elements removed. - /// - /// A set of elements. - /// The intersection of this set with a. - ISet Intersect(ISet a); + /// + /// Returns if the set contains all the elements in the specified collection. + /// + /// A collection of objects. + /// if the set contains all the elements in the specified collection, otherwise. + bool ContainsAll(ICollection c); - /// - /// Performs a "minus" of set b from set a. This returns a set of all - /// the elements in set a, removing the elements that are also in set b. - /// The original sets are not modified during this operation. The result set is a Clone() - /// of this Set containing the elements from the operation. - /// - /// A set of elements. - /// A set containing the elements from this set with the elements in a removed. - ISet Minus(ISet a); + /// + /// Returns if this set contains no elements. + /// + bool IsEmpty { get; } - /// - /// Performs an "exclusive-or" of the two sets, keeping only the elements that - /// are in one of the sets, but not in both. The original sets are not modified - /// during this operation. The result set is a Clone() of this set containing - /// the elements from the exclusive-or operation. - /// - /// A set of elements. - /// A set containing the result of a ^ b. - ISet ExclusiveOr(ISet a); + /// + /// Adds the specified element to this set if it is not already present. + /// + /// The object to add to the set. + /// is the object was added, if it was already present. + new bool Add(T o); - /// - /// Returns if the set contains all the elements in the specified collection. - /// - /// A collection of objects. - /// if the set contains all the elements in the specified collection, otherwise. - bool ContainsAll(ICollection c); + /// + /// Adds all the elements in the specified collection to the set if they are not already present. + /// + /// A collection of objects to add to the set. + /// is the set changed as a result of this operation, if not. + bool AddAll(ICollection c); - /// - /// Returns if this set contains no elements. - /// - bool IsEmpty { get; } + /// + /// Remove all the specified elements from this set, if they exist in this set. + /// + /// A collection of elements to remove. + /// if the set was modified as a result of this operation. + bool RemoveAll(ICollection c); - /// - /// Adds the specified element to this set if it is not already present. - /// - /// The object to add to the set. - /// is the object was added, if it was already present. - new bool Add(T o); - - /// - /// Adds all the elements in the specified collection to the set if they are not already present. - /// - /// A collection of objects to add to the set. - /// is the set changed as a result of this operation, if not. - bool AddAll(ICollection c); - - /// - /// Remove all the specified elements from this set, if they exist in this set. - /// - /// A collection of elements to remove. - /// if the set was modified as a result of this operation. - bool RemoveAll(ICollection c); - - - /// - /// Retains only the elements in this set that are contained in the specified collection. - /// - /// Collection that defines the set of elements to be retained. - /// if this set changed as a result of this operation. - bool RetainAll(ICollection c); - } + /// + /// Retains only the elements in this set that are contained in the specified collection. + /// + /// Collection that defines the set of elements to be retained. + /// if this set changed as a result of this operation. + bool RetainAll(ICollection c); } diff --git a/src/Spring/Spring.Core/Collections/Generic/ImmutableSet.cs b/src/Spring/Spring.Core/Collections/Generic/ImmutableSet.cs index 8dfe317c..2675d4e3 100644 --- a/src/Spring/Spring.Core/Collections/Generic/ImmutableSet.cs +++ b/src/Spring/Spring.Core/Collections/Generic/ImmutableSet.cs @@ -2,306 +2,305 @@ using System.Collections; -namespace Spring.Collections.Generic +namespace Spring.Collections.Generic; + +/// +///

Implements an immutable (read-only) Set wrapper.

+///

Although this is advertised as immutable, it really isn't. Anyone with access to the +/// basisSet can still change the data-set. So GetHashCode() is not implemented +/// for this Set, as is the case for all Set implementations in this library. +/// This design decision was based on the efficiency of not having to Clone() the +/// basisSet every time you wrap a mutable Set.

+///
+[Serializable] +public sealed class ImmutableSet : Set { - /// - ///

Implements an immutable (read-only) Set wrapper.

- ///

Although this is advertised as immutable, it really isn't. Anyone with access to the - /// basisSet can still change the data-set. So GetHashCode() is not implemented - /// for this Set, as is the case for all Set implementations in this library. - /// This design decision was based on the efficiency of not having to Clone() the - /// basisSet every time you wrap a mutable Set.

- ///
- [Serializable] - public sealed class ImmutableSet : Set + private const string ERROR_MESSAGE = "Object is immutable."; + private ISet mBasisSet; + + internal ISet BasisSet { - private const string ERROR_MESSAGE = "Object is immutable."; - private ISet mBasisSet; + get { return mBasisSet; } + } - internal ISet BasisSet - { - get { return mBasisSet; } - } + /// + /// Constructs an immutable (read-only) Set wrapper. + /// + /// The Set that is wrapped. + public ImmutableSet(ISet basisSet) + { + mBasisSet = basisSet; + } - /// - /// Constructs an immutable (read-only) Set wrapper. - /// - /// The Set that is wrapped. - public ImmutableSet(ISet basisSet) - { - mBasisSet = basisSet; - } + /// + /// Adds the specified element to this set if it is not already present. + /// + /// The object to add to the set. + /// nothing + /// is always thrown + public override sealed bool Add(T o) + { + throw new NotSupportedException(ERROR_MESSAGE); + } - /// - /// Adds the specified element to this set if it is not already present. - /// - /// The object to add to the set. - /// nothing - /// is always thrown - public override sealed bool Add(T o) - { - throw new NotSupportedException(ERROR_MESSAGE); - } + /// + /// Adds all the elements in the specified collection to the set if they are not already present. + /// + /// A collection of objects to add to the set. + /// nothing + /// is always thrown + public override sealed bool AddAll(ICollection c) + { + throw new NotSupportedException(ERROR_MESSAGE); + } - /// - /// Adds all the elements in the specified collection to the set if they are not already present. - /// - /// A collection of objects to add to the set. - /// nothing - /// is always thrown - public override sealed bool AddAll(ICollection c) - { - throw new NotSupportedException(ERROR_MESSAGE); - } + /// + /// Removes all objects from the set. + /// + /// is always thrown + public override sealed void Clear() + { + throw new NotSupportedException(ERROR_MESSAGE); + } - /// - /// Removes all objects from the set. - /// - /// is always thrown - public override sealed void Clear() - { - throw new NotSupportedException(ERROR_MESSAGE); - } + /// + /// Returns if this set contains the specified element. + /// + /// The element to look for. + /// if this set contains the specified element, otherwise. + public override sealed bool Contains(T o) + { + return mBasisSet.Contains(o); + } - /// - /// Returns if this set contains the specified element. - /// - /// The element to look for. - /// if this set contains the specified element, otherwise. - public override sealed bool Contains(T o) - { - return mBasisSet.Contains(o); - } + /// + /// Returns if the set contains all the elements in the specified collection. + /// + /// A collection of objects. + /// if the set contains all the elements in the specified collection, otherwise. + public override sealed bool ContainsAll(ICollection c) + { + return mBasisSet.ContainsAll(c); + } - /// - /// Returns if the set contains all the elements in the specified collection. - /// - /// A collection of objects. - /// if the set contains all the elements in the specified collection, otherwise. - public override sealed bool ContainsAll(ICollection c) - { - return mBasisSet.ContainsAll(c); - } + /// + /// Returns if this set contains no elements. + /// + public override sealed bool IsEmpty + { + get { return mBasisSet.IsEmpty; } + } - /// - /// Returns if this set contains no elements. - /// - public override sealed bool IsEmpty - { - get { return mBasisSet.IsEmpty; } - } + /// + /// Removes the specified element from the set. + /// + /// The element to be removed. + /// nothing + /// is always thrown + public override sealed bool Remove(T o) + { + throw new NotSupportedException(ERROR_MESSAGE); + } - /// - /// Removes the specified element from the set. - /// - /// The element to be removed. - /// nothing - /// is always thrown - public override sealed bool Remove(T o) - { - throw new NotSupportedException(ERROR_MESSAGE); - } + /// + /// Remove all the specified elements from this set, if they exist in this set. + /// + /// A collection of elements to remove. + /// nothing + /// is always thrown + public override sealed bool RemoveAll(ICollection c) + { + throw new NotSupportedException(ERROR_MESSAGE); + } - /// - /// Remove all the specified elements from this set, if they exist in this set. - /// - /// A collection of elements to remove. - /// nothing - /// is always thrown - public override sealed bool RemoveAll(ICollection c) - { - throw new NotSupportedException(ERROR_MESSAGE); - } + /// + /// Retains only the elements in this set that are contained in the specified collection. + /// + /// Collection that defines the set of elements to be retained. + /// nothing + /// is always thrown + public override sealed bool RetainAll(ICollection c) + { + throw new NotSupportedException(ERROR_MESSAGE); + } - /// - /// Retains only the elements in this set that are contained in the specified collection. - /// - /// Collection that defines the set of elements to be retained. - /// nothing - /// is always thrown - public override sealed bool RetainAll(ICollection c) - { - throw new NotSupportedException(ERROR_MESSAGE); - } + /// + /// Copies the elements in the Set to an array of T. The type of array needs + /// to be compatible with the objects in the Set, obviously. + /// + /// An array that will be the target of the copy operation. + /// The zero-based index where copying will start. + public override sealed void CopyTo(T[] array, int index) + { + mBasisSet.CopyTo(array, index); + } - /// - /// Copies the elements in the Set to an array of T. The type of array needs - /// to be compatible with the objects in the Set, obviously. - /// - /// An array that will be the target of the copy operation. - /// The zero-based index where copying will start. - public override sealed void CopyTo(T[] array, int index) - { - mBasisSet.CopyTo(array, index); - } + /// + /// The number of elements contained in this collection. + /// + public override sealed int Count + { + get { return mBasisSet.Count; } + } - /// - /// The number of elements contained in this collection. - /// - public override sealed int Count - { - get { return mBasisSet.Count; } - } + /// + /// Returns an object that can be used to synchronize use of the Set across threads. + /// + public override sealed bool IsSynchronized + { + get { return ((ICollection) mBasisSet).IsSynchronized; } + } - /// - /// Returns an object that can be used to synchronize use of the Set across threads. - /// - public override sealed bool IsSynchronized - { - get { return ((ICollection)mBasisSet).IsSynchronized; } - } + /// + /// Returns an object that can be used to synchronize the Set between threads. + /// + public override sealed object SyncRoot + { + get { return ((ICollection) mBasisSet).SyncRoot; } + } - /// - /// Returns an object that can be used to synchronize the Set between threads. - /// - public override sealed object SyncRoot - { - get { return ((ICollection)mBasisSet).SyncRoot; } - } + /// + /// Gets an enumerator for the elements in the Set. + /// + /// An IEnumerator over the elements in the Set. + public override sealed IEnumerator GetEnumerator() + { + return mBasisSet.GetEnumerator(); + } - /// - /// Gets an enumerator for the elements in the Set. - /// - /// An IEnumerator over the elements in the Set. - public override sealed IEnumerator GetEnumerator() - { - return mBasisSet.GetEnumerator(); - } + /// + /// Returns a clone of the Set instance. + /// + /// A clone of this object. + public override sealed object Clone() + { + return new ImmutableSet(mBasisSet); + } - /// - /// Returns a clone of the Set instance. - /// - /// A clone of this object. - public override sealed object Clone() - { - return new ImmutableSet(mBasisSet); - } + /// + /// Performs a "union" of the two sets, where all the elements + /// in both sets are present. That is, the element is included if it is in either a or b. + /// Neither this set nor the input set are modified during the operation. The return value + /// is a Clone() of this set with the extra elements added in. + /// + /// A collection of elements. + /// A new Set containing the union of this Set with the specified collection. + /// Neither of the input objects is modified by the union. + public override sealed ISet Union(ISet a) + { + ISet m = GetUltimateBasisSet(); + return new ImmutableSet(m.Union(a)); + } - /// - /// Performs a "union" of the two sets, where all the elements - /// in both sets are present. That is, the element is included if it is in either a or b. - /// Neither this set nor the input set are modified during the operation. The return value - /// is a Clone() of this set with the extra elements added in. - /// - /// A collection of elements. - /// A new Set containing the union of this Set with the specified collection. - /// Neither of the input objects is modified by the union. - public override sealed ISet Union(ISet a) - { - ISet m = GetUltimateBasisSet(); - return new ImmutableSet(m.Union(a)); - } + /// + /// Performs an "intersection" of the two sets, where only the elements + /// that are present in both sets remain. That is, the element is included if it exists in + /// both sets. The Intersect() operation does not modify the input sets. It returns + /// a Clone() of this set with the appropriate elements removed. + /// + /// A set of elements. + /// The intersection of this set with a. + public override sealed ISet Intersect(ISet a) + { + ISet m = GetUltimateBasisSet(); + return new ImmutableSet(m.Intersect(a)); + } - /// - /// Performs an "intersection" of the two sets, where only the elements - /// that are present in both sets remain. That is, the element is included if it exists in - /// both sets. The Intersect() operation does not modify the input sets. It returns - /// a Clone() of this set with the appropriate elements removed. - /// - /// A set of elements. - /// The intersection of this set with a. - public override sealed ISet Intersect(ISet a) - { - ISet m = GetUltimateBasisSet(); - return new ImmutableSet(m.Intersect(a)); - } + /// + /// Performs a "minus" of set b from set a. This returns a set of all + /// the elements in set a, removing the elements that are also in set b. + /// The original sets are not modified during this operation. The result set is a Clone() + /// of this Set containing the elements from the operation. + /// + /// A set of elements. + /// A set containing the elements from this set with the elements in a removed. + public override sealed ISet Minus(ISet a) + { + ISet m = GetUltimateBasisSet(); + return new ImmutableSet(m.Minus(a)); + } - /// - /// Performs a "minus" of set b from set a. This returns a set of all - /// the elements in set a, removing the elements that are also in set b. - /// The original sets are not modified during this operation. The result set is a Clone() - /// of this Set containing the elements from the operation. - /// - /// A set of elements. - /// A set containing the elements from this set with the elements in a removed. - public override sealed ISet Minus(ISet a) - { - ISet m = GetUltimateBasisSet(); - return new ImmutableSet(m.Minus(a)); - } + /// + /// Performs an "exclusive-or" of the two sets, keeping only the elements that + /// are in one of the sets, but not in both. The original sets are not modified + /// during this operation. The result set is a Clone() of this set containing + /// the elements from the exclusive-or operation. + /// + /// A set of elements. + /// A set containing the result of a ^ b. + public override sealed ISet ExclusiveOr(ISet a) + { + ISet m = GetUltimateBasisSet(); + return new ImmutableSet(m.ExclusiveOr(a)); + } - /// - /// Performs an "exclusive-or" of the two sets, keeping only the elements that - /// are in one of the sets, but not in both. The original sets are not modified - /// during this operation. The result set is a Clone() of this set containing - /// the elements from the exclusive-or operation. - /// - /// A set of elements. - /// A set containing the result of a ^ b. - public override sealed ISet ExclusiveOr(ISet a) - { - ISet m = GetUltimateBasisSet(); - return new ImmutableSet(m.ExclusiveOr(a)); - } + /// + /// Indicates that the given instance is read-only + /// + public override sealed bool IsReadOnly + { + get { return true; } + } - /// - /// Indicates that the given instance is read-only - /// - public override sealed bool IsReadOnly - { - get { return true; } - } + /// + /// Performs CopyTo when called trhough non-generic ISet (ICollection) interface + /// + /// + /// + protected override void NonGenericCopyTo(Array array, int index) + { + ((ICollection) this.BasisSet).CopyTo(array, index); + } - /// - /// Performs CopyTo when called trhough non-generic ISet (ICollection) interface - /// - /// - /// - protected override void NonGenericCopyTo(Array array, int index) - { - ((ICollection)this.BasisSet).CopyTo(array, index); - } + /// + /// Performs Union when called trhough non-generic ISet interface + /// + /// + /// + protected override sealed ISet NonGenericUnion(ISet a) + { + ISet m = GetUltimateBasisSet(); + return new ImmutableSet(((ISet) m).Union(a)); + } - /// - /// Performs Union when called trhough non-generic ISet interface - /// - /// - /// - protected override sealed ISet NonGenericUnion(ISet a) - { - ISet m = GetUltimateBasisSet(); - return new ImmutableSet(((ISet)m).Union(a)); - } + /// + /// Performs Minus when called trhough non-generic ISet interface + /// + /// + /// + protected override sealed ISet NonGenericMinus(ISet a) + { + ISet m = GetUltimateBasisSet(); + return new ImmutableSet(((ISet) m).Minus(a)); + } - /// - /// Performs Minus when called trhough non-generic ISet interface - /// - /// - /// - protected override sealed ISet NonGenericMinus(ISet a) - { - ISet m = GetUltimateBasisSet(); - return new ImmutableSet(((ISet)m).Minus(a)); - } + /// + /// Performs Intersect when called trhough non-generic ISet interface + /// + /// + /// + protected override sealed ISet NonGenericIntersect(ISet a) + { + ISet m = GetUltimateBasisSet(); + return new ImmutableSet(((ISet) m).Intersect(a)); + } - /// - /// Performs Intersect when called trhough non-generic ISet interface - /// - /// - /// - protected override sealed ISet NonGenericIntersect(ISet a) - { - ISet m = GetUltimateBasisSet(); - return new ImmutableSet(((ISet)m).Intersect(a)); - } + /// + /// Performs ExclusiveOr when called trhough non-generic ISet interface + /// + /// + /// + protected override sealed ISet NonGenericExclusiveOr(ISet a) + { + ISet m = GetUltimateBasisSet(); + return new ImmutableSet(((ISet) m).ExclusiveOr(a)); + } - /// - /// Performs ExclusiveOr when called trhough non-generic ISet interface - /// - /// - /// - protected override sealed ISet NonGenericExclusiveOr(ISet a) - { - ISet m = GetUltimateBasisSet(); - return new ImmutableSet(((ISet)m).ExclusiveOr(a)); - } - - private ISet GetUltimateBasisSet() - { - ISet m = this.mBasisSet; - while (m is ImmutableSet) - m = ((ImmutableSet)m).mBasisSet; - return m; - } + private ISet GetUltimateBasisSet() + { + ISet m = this.mBasisSet; + while (m is ImmutableSet) + m = ((ImmutableSet) m).mBasisSet; + return m; } } diff --git a/src/Spring/Spring.Core/Collections/Generic/LinkedHashDictionary.cs b/src/Spring/Spring.Core/Collections/Generic/LinkedHashDictionary.cs index 20ca7e07..3bc09fdd 100644 --- a/src/Spring/Spring.Core/Collections/Generic/LinkedHashDictionary.cs +++ b/src/Spring/Spring.Core/Collections/Generic/LinkedHashDictionary.cs @@ -18,124 +18,124 @@ #endregion -namespace Spring.Collections.Generic +namespace Spring.Collections.Generic; + +/// +/// IDictionary implementation which preserves the order of inserted items. +/// +/// Zbynek Vyskovsky, kvr@centrum.cz +public class LinkedHashDictionary : AbstractDictionary { - /// - /// IDictionary implementation which preserves the order of inserted items. - /// - /// Zbynek Vyskovsky, kvr@centrum.cz - public class LinkedHashDictionary : AbstractDictionary + public override void Add(TKey key, TValue value) { - public override void Add(TKey key, TValue value) + Node node; + if (items.TryGetValue(key, out node)) { - Node node; - if (items.TryGetValue(key, out node)) - { - node.value = value; - } - else - { - node = new Node(); - node.key = key; - node.value = value; - if ((node.previousLinked = linkedTail) != null) - node.previousLinked.nextLinked = node; - node.nextLinked = null; - linkedTail = node; - if (linkedHead == null) - linkedHead = node; - items.Add(key, node); - } + node.value = value; } - - public override bool ContainsKey(TKey key) + else { - return items.ContainsKey(key); + node = new Node(); + node.key = key; + node.value = value; + if ((node.previousLinked = linkedTail) != null) + node.previousLinked.nextLinked = node; + node.nextLinked = null; + linkedTail = node; + if (linkedHead == null) + linkedHead = node; + items.Add(key, node); } - - public override bool Remove(TKey key) - { - Node node; - if (!items.TryGetValue(key, out node)) - return false; - - if (node.previousLinked != null) - { - node.previousLinked.nextLinked = node.nextLinked; - } - else - { - linkedHead = node.nextLinked; - } - - if (node.nextLinked != null) - { - node.nextLinked.previousLinked = node.previousLinked; - } - else - { - linkedTail = node.previousLinked; - } - - items.Remove(key); - - return true; - } - - public override bool TryGetValue(TKey key, out TValue value) - { - Node node; - if (!items.TryGetValue(key, out node)) - { - value = default(TValue); - return false; - } - value = node.value; - return true; - } - - public override void Clear() - { - items.Clear(); - linkedHead = null; - linkedTail = null; - } - - public override bool Remove(KeyValuePair item) - { - Node node; - if (!items.TryGetValue(item.Key, out node)) - return false; - if (!node.value.Equals(item.Value)) - return false; - return Remove(item.Key); - } - - public override int Count - { - get { return items.Count; } - } - - protected class Node - { - public TKey key; - public TValue value; - - public Node previousLinked; - public Node nextLinked; - } - - protected override IEnumerable> EntriesSet() - { - List> entries = new List>(); - for (Node node = linkedHead; node != null; node = node.nextLinked) - entries.Add(new KeyValuePair(node.key, node.value)); - return entries; - } - - private Node linkedHead = null; - private Node linkedTail = null; - - private Dictionary items = new Dictionary(); } -} + + public override bool ContainsKey(TKey key) + { + return items.ContainsKey(key); + } + + public override bool Remove(TKey key) + { + Node node; + if (!items.TryGetValue(key, out node)) + return false; + + if (node.previousLinked != null) + { + node.previousLinked.nextLinked = node.nextLinked; + } + else + { + linkedHead = node.nextLinked; + } + + if (node.nextLinked != null) + { + node.nextLinked.previousLinked = node.previousLinked; + } + else + { + linkedTail = node.previousLinked; + } + + items.Remove(key); + + return true; + } + + public override bool TryGetValue(TKey key, out TValue value) + { + Node node; + if (!items.TryGetValue(key, out node)) + { + value = default(TValue); + return false; + } + + value = node.value; + return true; + } + + public override void Clear() + { + items.Clear(); + linkedHead = null; + linkedTail = null; + } + + public override bool Remove(KeyValuePair item) + { + Node node; + if (!items.TryGetValue(item.Key, out node)) + return false; + if (!node.value.Equals(item.Value)) + return false; + return Remove(item.Key); + } + + public override int Count + { + get { return items.Count; } + } + + protected class Node + { + public TKey key; + public TValue value; + + public Node previousLinked; + public Node nextLinked; + } + + protected override IEnumerable> EntriesSet() + { + List> entries = new List>(); + for (Node node = linkedHead; node != null; node = node.nextLinked) + entries.Add(new KeyValuePair(node.key, node.value)); + return entries; + } + + private Node linkedHead = null; + private Node linkedTail = null; + + private Dictionary items = new Dictionary(); +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Collections/Generic/OrderedSet.cs b/src/Spring/Spring.Core/Collections/Generic/OrderedSet.cs index 94c6e5a9..9080bf00 100644 --- a/src/Spring/Spring.Core/Collections/Generic/OrderedSet.cs +++ b/src/Spring/Spring.Core/Collections/Generic/OrderedSet.cs @@ -18,30 +18,29 @@ #endregion -namespace Spring.Collections.Generic +namespace Spring.Collections.Generic; + +/// +/// Implements an ordered Set based on a dictionary. +/// +[Serializable] +public class OrderedSet : DictionarySet { /// - /// Implements an ordered Set based on a dictionary. + /// Initializes a new instance of the class. /// - [Serializable] - public class OrderedSet : DictionarySet + public OrderedSet() { - /// - /// Initializes a new instance of the class. - /// - public OrderedSet() - { - InternalDictionary = new Dictionary(); - } + InternalDictionary = new Dictionary(); + } - /// - /// Initializes a new instance of the class. - /// - /// A collection of elements that defines the initial set contents. - public OrderedSet(ICollection initialValues) - : this() - { - AddAll(initialValues); - } + /// + /// Initializes a new instance of the class. + /// + /// A collection of elements that defines the initial set contents. + public OrderedSet(ICollection initialValues) + : this() + { + AddAll(initialValues); } } diff --git a/src/Spring/Spring.Core/Collections/Generic/ReadOnlyDictionary.cs b/src/Spring/Spring.Core/Collections/Generic/ReadOnlyDictionary.cs index e7e8d5a6..edcd7098 100644 --- a/src/Spring/Spring.Core/Collections/Generic/ReadOnlyDictionary.cs +++ b/src/Spring/Spring.Core/Collections/Generic/ReadOnlyDictionary.cs @@ -23,404 +23,402 @@ using System.Collections.ObjectModel; using System.Runtime.Serialization; using Spring.Util; -namespace Spring.Collections.Generic +namespace Spring.Collections.Generic; + +/// +/// Represents a read only wrapper around a generic IDictionary. The design pattern +/// mirrors ReadOnlyCollection, and follows the apparent pattern that write operations +/// do not throw an exception, but simply make no change to the underlying collection. +/// +/// Originally put into the public domain. +/// http://www.simple-talk.com/community/forums/thread/2263.aspx +/// +/// +/// +/// Original from Public Domain +/// Mark Pollack (.NET) +[Serializable] +public class ReadOnlyDictionary : IDictionary, IDictionary, ISerializable, IDeserializationCallback { /// - /// Represents a read only wrapper around a generic IDictionary. The design pattern - /// mirrors ReadOnlyCollection, and follows the apparent pattern that write operations - /// do not throw an exception, but simply make no change to the underlying collection. + /// Inner storage for ReadOnlyDictionary /// - /// Originally put into the public domain. - /// http://www.simple-talk.com/community/forums/thread/2263.aspx - /// - /// - /// - /// Original from Public Domain - /// Mark Pollack (.NET) - [Serializable] - public class ReadOnlyDictionary : IDictionary, IDictionary, ISerializable, IDeserializationCallback + private readonly IDictionary dict; + + /// + /// Easy access to non-generic dictionary API + /// + private readonly IDictionary idict; + + /// + /// Initializes a new instance of the class. + /// + /// The dictionary to wrap. + public ReadOnlyDictionary(IDictionary dictionaryToWrap) { - /// - /// Inner storage for ReadOnlyDictionary - /// - private readonly IDictionary dict; + AssertUtils.ArgumentNotNull(dictionaryToWrap, "dictionaryToWrap"); + dict = dictionaryToWrap; + idict = (IDictionary) dict; + } - /// - /// Easy access to non-generic dictionary API - /// - private readonly IDictionary idict; + /// + /// Add does not change a read only Dictionary + /// + /// The object to use as the key of the element to add. + /// The object to use as the value of the element to add. + /// The is read-only. + public void Add(TKey key, TValue value) + { + throw new NotSupportedException("Dictionary Is ReadOnly"); + } - /// - /// Initializes a new instance of the class. - /// - /// The dictionary to wrap. - public ReadOnlyDictionary(IDictionary dictionaryToWrap) + /// + /// Determines whether the contains an element with the specified key. + /// + /// The key to locate in the . + /// + /// true if the contains an element with the key; otherwise, false. + /// + /// key is null. + public bool ContainsKey(TKey key) + { + return dict.ContainsKey(key); + } + + /// + /// Gets a read only containing the keys of the . + /// + /// + /// An containing the keys of the object that implements . + public ICollection Keys + { + get { - AssertUtils.ArgumentNotNull(dictionaryToWrap, "dictionaryToWrap"); - dict = dictionaryToWrap; - idict = (IDictionary)dict; + return new ReadOnlyCollection(new List(dict.Keys)); } + } - /// - /// Add does not change a read only Dictionary - /// - /// The object to use as the key of the element to add. - /// The object to use as the value of the element to add. - /// The is read-only. - public void Add(TKey key, TValue value) + /// + /// Remove does not change a read only Dictionary, will throw an exception. + /// + /// The is read-only. + public bool Remove(TKey key) + { + throw new NotSupportedException("Dictionary Is ReadOnly"); + } + + /// + /// Tries the get value. + /// + /// The key. + /// The value. + /// + public bool TryGetValue(TKey key, out TValue value) + { + return dict.TryGetValue(key, out value); + } + + /// + /// Gets an containing the values in the . + /// + /// + /// An containing the values in the object that implements . + public ICollection Values + { + get + { + return new ReadOnlyCollection(new List(dict.Values)); + } + } + + /// + /// Gets the value with the specified key. + /// Set will throw an exception + /// + public TValue this[TKey key] + { + get + { + return dict[key]; + } + set { throw new NotSupportedException("Dictionary Is ReadOnly"); } + } - /// - /// Determines whether the contains an element with the specified key. - /// - /// The key to locate in the . - /// - /// true if the contains an element with the key; otherwise, false. - /// - /// key is null. - public bool ContainsKey(TKey key) + /// + /// Add does not change a read only Dictionary + /// + /// The object to add to the . + /// The is read-only. + public void Add(KeyValuePair item) + { + throw new NotSupportedException("Dictionary Is ReadOnly"); + } + + /// + /// Clear does not change a read only Dictionary. + /// + /// The is read-only. + public void Clear() + { + throw new NotSupportedException("Dictionary Is ReadOnly"); + } + + /// + /// Determines whether the contains a specific value. + /// + /// The object to locate in the . + /// + /// true if item is found in the ; otherwise, false. + /// + public bool Contains(KeyValuePair item) + { + return dict.Contains(item); + } + + /// + /// Copies the elements of the to an , starting at a particular index. + /// + /// The one-dimensional that is the destination of the elements copied from . The must have zero-based indexing. + /// The zero-based index in array at which copying begins. + /// arrayIndex is less than 0. + /// array is null. + /// array is multidimensional.-or-arrayIndex is equal to or greater than the length of array.-or-The number of elements in the source is greater than the available space from arrayIndex to the end of the destination array.-or-Type T cannot be cast automatically to the type of the destination array. + public void CopyTo(KeyValuePair[] array, int arrayIndex) + { + dict.CopyTo(array, arrayIndex); + } + + /// + /// Gets the number of elements contained in the . + /// + /// + /// The number of elements contained in the . + public int Count + { + get { - return dict.ContainsKey(key); + return dict.Count; } + } - /// - /// Gets a read only containing the keys of the . - /// - /// - /// An containing the keys of the object that implements . - public ICollection Keys + /// + /// Gets a value indicating whether the is read-only. + /// + /// + /// true if the is read-only; otherwise, false. + public bool IsReadOnly + { + get { - get - { - return new ReadOnlyCollection(new List(dict.Keys)); - } + return true; } + } - /// - /// Remove does not change a read only Dictionary, will throw an exception. - /// - /// The is read-only. - public bool Remove(TKey key) + /// + /// Remove does not change a read only Dictionary. Throws an exception + /// + /// The object to remove from the . + /// + /// true if item was successfully removed from the ; otherwise, false. This method also returns false if item is not found in the original . + /// + /// The is read-only. + public bool Remove(KeyValuePair item) + { + throw new NotSupportedException("Dictionary Is ReadOnly"); + } + + /// + /// Returns an enumerator that iterates through the collection. + /// + /// + /// A that can be used to iterate through the collection. + /// + public IEnumerator> GetEnumerator() + { + return dict.GetEnumerator(); + } + + /// + /// Returns an enumerator that iterates through a collection. + /// + /// + /// An object that can be used to iterate through the collection. + /// + IEnumerator IEnumerable.GetEnumerator() + { + return idict.GetEnumerator(); + } + + /// + /// Add does not change a read only Dictionary. Throws an exception. + /// + /// The to use as the key of the element to add. + /// The to use as the value of the element to add. + /// The is read-only.-or- The has a fixed size. + public void Add(object key, object value) + { + throw new NotSupportedException("Dictionary Is ReadOnly"); + } + + /// + /// Determines whether the object contains an element with the specified key. + /// + /// The key to locate in the object. + /// + /// true if the contains an element with the key; otherwise, false. + /// + /// key is null. + public bool Contains(object key) + { + return idict.Contains(key); + } + + /// + /// Returns an object for the object. + /// + /// + /// An object for the object. + /// + IDictionaryEnumerator IDictionary.GetEnumerator() + { + return idict.GetEnumerator(); + } + + /// + /// Gets a value indicating whether the object has a fixed size. + /// + /// + /// true if the object has a fixed size; otherwise, false. + public bool IsFixedSize + { + get + { + return idict.IsFixedSize; + } + } + + /// + /// Gets an containing the keys of the . + /// + /// + /// An containing the keys of the object that implements . + ICollection IDictionary.Keys + { + get + { + return idict.Keys; + } + } + + /// + /// Remove does not change a read only Dictionary. Throws an exception. + /// + /// The key of the element to remove. + /// The object is read-only.-or- The has a fixed size. + public void Remove(object key) + { + throw new NotSupportedException("Dictionary Is ReadOnly"); + } + + /// + /// Gets an containing the values in the . + /// + /// + /// An containing the values in the object that implements . + ICollection IDictionary.Values + { + get + { + return idict.Values; + } + } + + /// + /// Gets the with the specified key. Set throws an exception. + /// + /// + /// The is read-only. + /// if try to set value + public object this[object key] + { + get + { + return idict[key]; + } + set { throw new NotSupportedException("Dictionary Is ReadOnly"); } + } - /// - /// Tries the get value. - /// - /// The key. - /// The value. - /// - public bool TryGetValue(TKey key, out TValue value) + /// + /// Copies the elements of the to an , starting at a particular index. + /// + /// The one-dimensional that is the destination of the elements copied from . The must have zero-based indexing. + /// The zero-based index in array at which copying begins. + /// array is null. + /// index is less than zero. + /// array is multidimensional.-or- index is equal to or greater than the length of array.-or- The number of elements in the source is greater than the available space from index to the end of the destination array. + /// The type of the source cannot be cast automatically to the type of the destination array. + public void CopyTo(Array array, int index) + { + idict.CopyTo(array, index); + } + + /// + /// Gets a value indicating whether access to the is synchronized (thread safe). + /// + /// + /// true if access to the is synchronized (thread safe); otherwise, false. + public bool IsSynchronized + { + get { - return dict.TryGetValue(key, out value); + return idict.IsSynchronized; } + } - /// - /// Gets an containing the values in the . - /// - /// - /// An containing the values in the object that implements . - public ICollection Values + /// + /// Gets an object that can be used to synchronize access to the . + /// + /// + /// An object that can be used to synchronize access to the . + public object SyncRoot + { + get { - get - { - return new ReadOnlyCollection(new List(dict.Values)); - } + return idict.SyncRoot; } + } - /// - /// Gets the value with the specified key. - /// Set will throw an exception - /// - public TValue this[TKey key] + /// + /// Runs when the entire object graph has been deserialized. + /// + /// The object that initiated the callback. The functionality for this parameter is not currently implemented. + public void OnDeserialization(object sender) + { + IDeserializationCallback callback = dict as IDeserializationCallback; + if (callback != null) { - get - { - return dict[key]; - } - set - { - throw new NotSupportedException("Dictionary Is ReadOnly"); - } + callback.OnDeserialization(sender); } + } - /// - /// Add does not change a read only Dictionary - /// - /// The object to add to the . - /// The is read-only. - public void Add(KeyValuePair item) + /// + /// Populates a with the data needed to serialize the target object. + /// + /// The to populate with data. + /// The destination (see ) for this serialization. + /// The caller does not have the required permission. + public void GetObjectData(SerializationInfo info, StreamingContext context) + { + ISerializable serializable = dict as ISerializable; + if (serializable != null) { - throw new NotSupportedException("Dictionary Is ReadOnly"); - } - - /// - /// Clear does not change a read only Dictionary. - /// - /// The is read-only. - public void Clear() - { - throw new NotSupportedException("Dictionary Is ReadOnly"); - } - - /// - /// Determines whether the contains a specific value. - /// - /// The object to locate in the . - /// - /// true if item is found in the ; otherwise, false. - /// - public bool Contains(KeyValuePair item) - { - return dict.Contains(item); - } - - /// - /// Copies the elements of the to an , starting at a particular index. - /// - /// The one-dimensional that is the destination of the elements copied from . The must have zero-based indexing. - /// The zero-based index in array at which copying begins. - /// arrayIndex is less than 0. - /// array is null. - /// array is multidimensional.-or-arrayIndex is equal to or greater than the length of array.-or-The number of elements in the source is greater than the available space from arrayIndex to the end of the destination array.-or-Type T cannot be cast automatically to the type of the destination array. - public void CopyTo(KeyValuePair[] array, int arrayIndex) - { - dict.CopyTo(array, arrayIndex); - } - - /// - /// Gets the number of elements contained in the . - /// - /// - /// The number of elements contained in the . - public int Count - { - get - { - return dict.Count; - } - } - - /// - /// Gets a value indicating whether the is read-only. - /// - /// - /// true if the is read-only; otherwise, false. - public bool IsReadOnly - { - get - { - return true; - } - } - - /// - /// Remove does not change a read only Dictionary. Throws an exception - /// - /// The object to remove from the . - /// - /// true if item was successfully removed from the ; otherwise, false. This method also returns false if item is not found in the original . - /// - /// The is read-only. - public bool Remove(KeyValuePair item) - { - throw new NotSupportedException("Dictionary Is ReadOnly"); - - } - - /// - /// Returns an enumerator that iterates through the collection. - /// - /// - /// A that can be used to iterate through the collection. - /// - public IEnumerator> GetEnumerator() - { - return dict.GetEnumerator(); - } - - /// - /// Returns an enumerator that iterates through a collection. - /// - /// - /// An object that can be used to iterate through the collection. - /// - IEnumerator IEnumerable.GetEnumerator() - { - return idict.GetEnumerator(); - } - - /// - /// Add does not change a read only Dictionary. Throws an exception. - /// - /// The to use as the key of the element to add. - /// The to use as the value of the element to add. - /// The is read-only.-or- The has a fixed size. - public void Add(object key, object value) - { - throw new NotSupportedException("Dictionary Is ReadOnly"); - } - - /// - /// Determines whether the object contains an element with the specified key. - /// - /// The key to locate in the object. - /// - /// true if the contains an element with the key; otherwise, false. - /// - /// key is null. - public bool Contains(object key) - { - return idict.Contains(key); - } - - /// - /// Returns an object for the object. - /// - /// - /// An object for the object. - /// - IDictionaryEnumerator IDictionary.GetEnumerator() - { - return idict.GetEnumerator(); - } - - /// - /// Gets a value indicating whether the object has a fixed size. - /// - /// - /// true if the object has a fixed size; otherwise, false. - public bool IsFixedSize - { - get - { - return idict.IsFixedSize; - } - } - - /// - /// Gets an containing the keys of the . - /// - /// - /// An containing the keys of the object that implements . - ICollection IDictionary.Keys - { - get - { - return idict.Keys; - } - } - - /// - /// Remove does not change a read only Dictionary. Throws an exception. - /// - /// The key of the element to remove. - /// The object is read-only.-or- The has a fixed size. - public void Remove(object key) - { - throw new NotSupportedException("Dictionary Is ReadOnly"); - } - - /// - /// Gets an containing the values in the . - /// - /// - /// An containing the values in the object that implements . - ICollection IDictionary.Values - { - get - { - return idict.Values; - } - } - - /// - /// Gets the with the specified key. Set throws an exception. - /// - /// - /// The is read-only. - /// if try to set value - public object this[object key] - { - get - { - return idict[key]; - } - set - { - throw new NotSupportedException("Dictionary Is ReadOnly"); - } - } - - /// - /// Copies the elements of the to an , starting at a particular index. - /// - /// The one-dimensional that is the destination of the elements copied from . The must have zero-based indexing. - /// The zero-based index in array at which copying begins. - /// array is null. - /// index is less than zero. - /// array is multidimensional.-or- index is equal to or greater than the length of array.-or- The number of elements in the source is greater than the available space from index to the end of the destination array. - /// The type of the source cannot be cast automatically to the type of the destination array. - public void CopyTo(Array array, int index) - { - idict.CopyTo(array, index); - } - - /// - /// Gets a value indicating whether access to the is synchronized (thread safe). - /// - /// - /// true if access to the is synchronized (thread safe); otherwise, false. - public bool IsSynchronized - { - get - { - return idict.IsSynchronized; - } - } - - /// - /// Gets an object that can be used to synchronize access to the . - /// - /// - /// An object that can be used to synchronize access to the . - public object SyncRoot - { - get - { - return idict.SyncRoot; - } - } - - /// - /// Runs when the entire object graph has been deserialized. - /// - /// The object that initiated the callback. The functionality for this parameter is not currently implemented. - public void OnDeserialization(object sender) - { - IDeserializationCallback callback = dict as IDeserializationCallback; - if (callback != null) - { - callback.OnDeserialization(sender); - } - } - - /// - /// Populates a with the data needed to serialize the target object. - /// - /// The to populate with data. - /// The destination (see ) for this serialization. - /// The caller does not have the required permission. - public void GetObjectData(SerializationInfo info, StreamingContext context) - { - ISerializable serializable = dict as ISerializable; - if (serializable != null) - { - serializable.GetObjectData(info, context); - } + serializable.GetObjectData(info, context); } } } diff --git a/src/Spring/Spring.Core/Collections/Generic/Set.cs b/src/Spring/Spring.Core/Collections/Generic/Set.cs index 3b1d8d5c..4bd2742e 100644 --- a/src/Spring/Spring.Core/Collections/Generic/Set.cs +++ b/src/Spring/Spring.Core/Collections/Generic/Set.cs @@ -2,559 +2,561 @@ using System.Collections; -namespace Spring.Collections.Generic +namespace Spring.Collections.Generic; + +///

A collection that contains no duplicate elements. This class models the mathematical +/// Set abstraction, and is the base class for all other Set implementations. +/// The order of elements in a set is dependant on (a)the data-structure implementation, and +/// (b)the implementation of the various Set methods, and thus is not guaranteed.

+/// +///

None of the Set implementations in this library are guranteed to be thread-safe +/// in any way unless wrapped in a SynchronizedSet.

+/// +///

The following table summarizes the binary operators that are supported by the Set class.

+/// +/// +/// Operation +/// Description +/// Method +/// Operator +/// +/// +/// Union (OR) +/// Element included in result if it exists in either A OR B. +/// Union() +/// | +/// +/// +/// Intersection (AND) +/// Element included in result if it exists in both A AND B. +/// InterSect() +/// & +/// +/// +/// Exclusive Or (XOR) +/// Element included in result if it exists in one, but not both, of A and B. +/// ExclusiveOr() +/// ^ +/// +/// +/// Minus (n/a) +/// Take all the elements in A. Now, if any of them exist in B, remove +/// them. Note that unlike the other operators, A - B is not the same as B - A. +/// Minus() +/// - +/// +/// +///
+[Serializable] +public abstract class Set : ISet, ICollection, IEnumerable, + ISet, ICollection, IEnumerable, ICloneable { - ///

A collection that contains no duplicate elements. This class models the mathematical - /// Set abstraction, and is the base class for all other Set implementations. - /// The order of elements in a set is dependant on (a)the data-structure implementation, and - /// (b)the implementation of the various Set methods, and thus is not guaranteed.

- /// - ///

None of the Set implementations in this library are guranteed to be thread-safe - /// in any way unless wrapped in a SynchronizedSet.

- /// - ///

The following table summarizes the binary operators that are supported by the Set class.

- /// - /// - /// Operation - /// Description - /// Method - /// Operator - /// - /// - /// Union (OR) - /// Element included in result if it exists in either A OR B. - /// Union() - /// | - /// - /// - /// Intersection (AND) - /// Element included in result if it exists in both A AND B. - /// InterSect() - /// & - /// - /// - /// Exclusive Or (XOR) - /// Element included in result if it exists in one, but not both, of A and B. - /// ExclusiveOr() - /// ^ - /// - /// - /// Minus (n/a) - /// Take all the elements in A. Now, if any of them exist in B, remove - /// them. Note that unlike the other operators, A - B is not the same as B - A. - /// Minus() - /// - - /// - /// + /// + /// Performs a "union" of the two sets, where all the elements + /// in both sets are present. That is, the element is included if it is in either a or b. + /// Neither this set nor the input set are modified during the operation. The return value + /// is a Clone() of this set with the extra elements added in. /// - [Serializable] - public abstract class Set : ISet, ICollection, IEnumerable, - ISet, ICollection, IEnumerable, ICloneable + /// A collection of elements. + /// A new Set containing the union of this Set with the specified collection. + /// Neither of the input objects is modified by the union. + public virtual ISet Union(ISet a) { - /// - /// Performs a "union" of the two sets, where all the elements - /// in both sets are present. That is, the element is included if it is in either a or b. - /// Neither this set nor the input set are modified during the operation. The return value - /// is a Clone() of this set with the extra elements added in. - /// - /// A collection of elements. - /// A new Set containing the union of this Set with the specified collection. - /// Neither of the input objects is modified by the union. - public virtual ISet Union(ISet a) + ISet resultSet = (ISet) this.Clone(); + if (a != null) { - ISet resultSet = (ISet)this.Clone(); - if (a != null) - { - resultSet.AddAll(a); - } - return resultSet; + resultSet.AddAll(a); } - /// - /// Performs a "union" of two sets, where all the elements - /// in both are present. That is, the element is included if it is in either a or b. - /// The return value is a Clone() of one of the sets (a if it is not ) with elements of the other set - /// added in. Neither of the input sets is modified by the operation. - /// - /// A set of elements. - /// A set of elements. - /// A set containing the union of the input sets. if both sets are . - public static ISet Union(ISet a, ISet b) - { - if (a == null && b == null) - return null; - else if (a == null) - return (ISet)b.Clone(); - else if (b == null) - return (ISet)a.Clone(); - else - return a.Union(b); - } - - /// - /// Performs a "union" of two sets, where all the elements - /// in both are present. That is, the element is included if it is in either a or b. - /// The return value is a Clone() of one of the sets (a if it is not ) with elements of the other set - /// added in. Neither of the input sets is modified by the operation. - /// - /// A set of elements. - /// A set of elements. - /// A set containing the union of the input sets. if both sets are . - public static Set operator |(Set a, Set b) - { - return (Set)Union(a, b); - } - - /// - /// Performs an "intersection" of the two sets, where only the elements - /// that are present in both sets remain. That is, the element is included if it exists in - /// both sets. The Intersect() operation does not modify the input sets. It returns - /// a Clone() of this set with the appropriate elements removed. - /// - /// A set of elements. - /// The intersection of this set with a. - public virtual ISet Intersect(ISet a) - { - ISet resultSet = (ISet)this.Clone(); - if (a != null) - resultSet.RetainAll(a); - else - resultSet.Clear(); - return resultSet; - } - - /// - /// Performs an "intersection" of the two sets, where only the elements - /// that are present in both sets remain. That is, the element is included only if it exists in - /// both a and b. Neither input object is modified by the operation. - /// The result object is a Clone() of one of the input objects (a if it is not ) containing the - /// elements from the intersect operation. - /// - /// A set of elements. - /// A set of elements. - /// The intersection of the two input sets. if both sets are . - public static ISet Intersect(ISet a, ISet b) - { - if (a == null && b == null) - return null; - else if (a == null) - { - return b.Intersect(a); - } - else - return a.Intersect(b); - } - - /// - /// Performs an "intersection" of the two sets, where only the elements - /// that are present in both sets remain. That is, the element is included only if it exists in - /// both a and b. Neither input object is modified by the operation. - /// The result object is a Clone() of one of the input objects (a if it is not ) containing the - /// elements from the intersect operation. - /// - /// A set of elements. - /// A set of elements. - /// The intersection of the two input sets. if both sets are . - public static Set operator &(Set a, Set b) - { - return (Set)Intersect(a, b); - } - - /// - /// Performs a "minus" of set b from set a. This returns a set of all - /// the elements in set a, removing the elements that are also in set b. - /// The original sets are not modified during this operation. The result set is a Clone() - /// of this Set containing the elements from the operation. - /// - /// A set of elements. - /// A set containing the elements from this set with the elements in a removed. - public virtual ISet Minus(ISet a) - { - ISet resultSet = (ISet)this.Clone(); - if (a != null) - resultSet.RemoveAll(a); - return resultSet; - } - - /// - /// Performs a "minus" of set b from set a. This returns a set of all - /// the elements in set a, removing the elements that are also in set b. - /// The original sets are not modified during this operation. The result set is a Clone() - /// of set a containing the elements from the operation. - /// - /// A set of elements. - /// A set of elements. - /// A set containing A - B elements. if a is . - public static ISet Minus(ISet a, ISet b) - { - if (a == null) - return null; - else - return a.Minus(b); - } - - /// - /// Performs a "minus" of set b from set a. This returns a set of all - /// the elements in set a, removing the elements that are also in set b. - /// The original sets are not modified during this operation. The result set is a Clone() - /// of set a containing the elements from the operation. - /// - /// A set of elements. - /// A set of elements. - /// A set containing A - B elements. if a is . - public static Set operator -(Set a, Set b) - { - return (Set)Minus(a, b); - } - - - /// - /// Performs an "exclusive-or" of the two sets, keeping only the elements that - /// are in one of the sets, but not in both. The original sets are not modified - /// during this operation. The result set is a Clone() of this set containing - /// the elements from the exclusive-or operation. - /// - /// A set of elements. - /// A set containing the result of a ^ b. - public virtual ISet ExclusiveOr(ISet a) - { - ISet resultSet = (ISet)this.Clone(); - foreach (T element in a) - { - if (resultSet.Contains(element)) - resultSet.Remove(element); - else - resultSet.Add(element); - } - return resultSet; - } - - /// - /// Performs an "exclusive-or" of the two sets, keeping only the elements that - /// are in one of the sets, but not in both. The original sets are not modified - /// during this operation. The result set is a Clone() of one of the sets - /// (a if it is not ) containing - /// the elements from the exclusive-or operation. - /// - /// A set of elements. - /// A set of elements. - /// A set containing the result of a ^ b. if both sets are . - public static ISet ExclusiveOr(ISet a, ISet b) - { - if (a == null && b == null) - return null; - else if (a == null) - return (ISet)b.Clone(); - else if (b == null) - return (ISet)a.Clone(); - else - return a.ExclusiveOr(b); - } - - /// - /// Performs an "exclusive-or" of the two sets, keeping only the elements that - /// are in one of the sets, but not in both. The original sets are not modified - /// during this operation. The result set is a Clone() of one of the sets - /// (a if it is not ) containing - /// the elements from the exclusive-or operation. - /// - /// A set of elements. - /// A set of elements. - /// A set containing the result of a ^ b. if both sets are . - public static Set operator ^(Set a, Set b) - { - return (Set)ExclusiveOr(a, b); - } - - /// - /// Adds the specified element to this set if it is not already present. - /// - /// The object to add to the set. - /// is the object was added, if it was already present. - public abstract bool Add(T o); - - /// - /// Adds all the elements in the specified collection to the set if they are not already present. - /// - /// A collection of objects to add to the set. - /// is the set changed as a result of this operation, if not. - public abstract bool AddAll(ICollection c); - - /// - /// Removes all objects from the set. - /// - public abstract void Clear(); - - /// - /// Returns if this set contains the specified element. - /// - /// The element to look for. - /// if this set contains the specified element, otherwise. - public abstract bool Contains(T o); - - /// - /// Returns if the set contains all the elements in the specified collection. - /// - /// A collection of objects. - /// if the set contains all the elements in the specified collection, otherwise. - public abstract bool ContainsAll(ICollection c); - - /// - /// Returns if this set contains no elements. - /// - public abstract bool IsEmpty { get; } - - /// - /// Removes the specified element from the set. - /// - /// The element to be removed. - /// if the set contained the specified element, otherwise. - public abstract bool Remove(T o); - - /// - /// Remove all the specified elements from this set, if they exist in this set. - /// - /// A collection of elements to remove. - /// if the set was modified as a result of this operation. - public abstract bool RemoveAll(ICollection c); - - - /// - /// Retains only the elements in this set that are contained in the specified collection. - /// - /// Collection that defines the set of elements to be retained. - /// if this set changed as a result of this operation. - public abstract bool RetainAll(ICollection c); - - /// - /// Returns a clone of the Set instance. This will work for derived Set - /// classes if the derived class implements a constructor that takes no arguments. - /// - /// A clone of this object. - public virtual object Clone() - { - Set newSet = (Set)Activator.CreateInstance(this.GetType()); - newSet.AddAll(this); - return newSet; - } - - - /// - /// Copies the elements in the Set to an array. The type of array needs - /// to be compatible with the objects in the Set, obviously. - /// - /// An array that will be the target of the copy operation. - /// The zero-based index where copying will start. - public abstract void CopyTo(T[] array, int index); - - /// - /// The number of elements currently contained in this collection. - /// - public abstract int Count { get; } - - /// - /// Returns if the Set is synchronized across threads. Note that - /// enumeration is inherently not thread-safe. Use the SyncRoot to lock the - /// object during enumeration. - /// - public abstract bool IsSynchronized { get; } - - /// - /// An object that can be used to synchronize this collection to make it thread-safe. - /// When implementing this, if your object uses a base object, like an IDictionary, - /// or anything that has a SyncRoot, return that object instead of "this". - /// - public abstract object SyncRoot { get; } - - /// - /// Gets an enumerator for the elements in the Set. - /// - /// An IEnumerator over the elements in the Set. - public abstract IEnumerator GetEnumerator(); - - /// - /// Indicates whether the given instance is read-only or not - /// - /// - /// if the ISet is read-only; otherwise, . - /// In the default implementation of Set, this property always returns false. - /// - public virtual bool IsReadOnly - { - get { return false; } - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - void ICollection.Add(T item) - { - this.Add(item); - } - - #region Protected helpers - - /// - /// Performs CopyTo when called trhough non-generic ISet (ICollection) interface - /// - /// - /// - protected abstract void NonGenericCopyTo(Array array, int index); - - /// - /// Performs Union when called trhough non-generic ISet interface - /// - /// - /// - protected virtual ISet NonGenericUnion(ISet a) - { - ISet resultSet = (ISet)this.Clone(); - if (a != null) - resultSet.AddAll(a); - return resultSet; - } - - /// - /// Performs Minus when called trhough non-generic ISet interface - /// - /// - /// - protected virtual ISet NonGenericMinus(ISet a) - { - ISet resultSet = (ISet)this.Clone(); - if (a != null) - resultSet.RemoveAll(a); - return resultSet; - } - - /// - /// Performs Intersect when called trhough non-generic ISet interface - /// - /// - /// - protected virtual ISet NonGenericIntersect(ISet a) - { - ISet resultSet = (ISet)this.Clone(); - if (a != null) - resultSet.RetainAll(a); - else - resultSet.Clear(); - return resultSet; - } - - /// - /// Performs ExclusiveOr when called trhough non-generic ISet interface - /// - /// - /// - protected virtual ISet NonGenericExclusiveOr(ISet a) - { - ISet resultSet = (ISet)this.Clone(); - foreach (object element in a) - { - if (resultSet.Contains(element)) - resultSet.Remove(element); - else - resultSet.Add(element); - } - return resultSet; - } - - #endregion Protected helpers - - #region ISet implementation - - void ICollection.CopyTo(Array array, int index) - { - this.NonGenericCopyTo(array, index); - } - - ISet ISet.Union(ISet a) - { - return this.NonGenericUnion(a); - } - - ISet ISet.Intersect(ISet a) - { - return NonGenericIntersect(a); - } - - ISet ISet.Minus(ISet a) - { - return NonGenericMinus(a); - } - - ISet ISet.ExclusiveOr(ISet a) - { - return NonGenericExclusiveOr(a); - } - - bool ISet.Contains(object o) - { - if (o is T) - return this.Contains((T)o); - else - return false; - } - - bool ISet.ContainsAll(ICollection c) - { - ICollection col = new List(c.Count); - foreach (object o in c) - { - if (o is T) - col.Add((T)o); - else - return false; - } - return this.ContainsAll(col); - } - - bool ISet.Add(object o) - { - return this.Add((T)o); - } - - bool ISet.AddAll(ICollection c) - { - bool changed = false; - foreach (T obj in c) - changed |= this.Add(obj); - return changed; - } - - bool ISet.Remove(object o) - { - if (o is T) - return this.Remove((T)o); - else - return false; - } - - bool ISet.RemoveAll(ICollection c) - { - ICollection col = new List(c.Count); - foreach (object o in c) - { - if (o is T) - col.Add((T)o); - } - return this.RemoveAll(col); - } - - bool ISet.RetainAll(ICollection c) - { - ICollection col = new List(c.Count); - foreach (object o in c) - { - if (o is T) - col.Add((T)o); - } - return this.RetainAll(col); - } - - #endregion ISet implementation + return resultSet; } + + /// + /// Performs a "union" of two sets, where all the elements + /// in both are present. That is, the element is included if it is in either a or b. + /// The return value is a Clone() of one of the sets (a if it is not ) with elements of the other set + /// added in. Neither of the input sets is modified by the operation. + /// + /// A set of elements. + /// A set of elements. + /// A set containing the union of the input sets. if both sets are . + public static ISet Union(ISet a, ISet b) + { + if (a == null && b == null) + return null; + else if (a == null) + return (ISet) b.Clone(); + else if (b == null) + return (ISet) a.Clone(); + else + return a.Union(b); + } + + /// + /// Performs a "union" of two sets, where all the elements + /// in both are present. That is, the element is included if it is in either a or b. + /// The return value is a Clone() of one of the sets (a if it is not ) with elements of the other set + /// added in. Neither of the input sets is modified by the operation. + /// + /// A set of elements. + /// A set of elements. + /// A set containing the union of the input sets. if both sets are . + public static Set operator |(Set a, Set b) + { + return (Set) Union(a, b); + } + + /// + /// Performs an "intersection" of the two sets, where only the elements + /// that are present in both sets remain. That is, the element is included if it exists in + /// both sets. The Intersect() operation does not modify the input sets. It returns + /// a Clone() of this set with the appropriate elements removed. + /// + /// A set of elements. + /// The intersection of this set with a. + public virtual ISet Intersect(ISet a) + { + ISet resultSet = (ISet) this.Clone(); + if (a != null) + resultSet.RetainAll(a); + else + resultSet.Clear(); + return resultSet; + } + + /// + /// Performs an "intersection" of the two sets, where only the elements + /// that are present in both sets remain. That is, the element is included only if it exists in + /// both a and b. Neither input object is modified by the operation. + /// The result object is a Clone() of one of the input objects (a if it is not ) containing the + /// elements from the intersect operation. + /// + /// A set of elements. + /// A set of elements. + /// The intersection of the two input sets. if both sets are . + public static ISet Intersect(ISet a, ISet b) + { + if (a == null && b == null) + return null; + else if (a == null) + { + return b.Intersect(a); + } + else + return a.Intersect(b); + } + + /// + /// Performs an "intersection" of the two sets, where only the elements + /// that are present in both sets remain. That is, the element is included only if it exists in + /// both a and b. Neither input object is modified by the operation. + /// The result object is a Clone() of one of the input objects (a if it is not ) containing the + /// elements from the intersect operation. + /// + /// A set of elements. + /// A set of elements. + /// The intersection of the two input sets. if both sets are . + public static Set operator &(Set a, Set b) + { + return (Set) Intersect(a, b); + } + + /// + /// Performs a "minus" of set b from set a. This returns a set of all + /// the elements in set a, removing the elements that are also in set b. + /// The original sets are not modified during this operation. The result set is a Clone() + /// of this Set containing the elements from the operation. + /// + /// A set of elements. + /// A set containing the elements from this set with the elements in a removed. + public virtual ISet Minus(ISet a) + { + ISet resultSet = (ISet) this.Clone(); + if (a != null) + resultSet.RemoveAll(a); + return resultSet; + } + + /// + /// Performs a "minus" of set b from set a. This returns a set of all + /// the elements in set a, removing the elements that are also in set b. + /// The original sets are not modified during this operation. The result set is a Clone() + /// of set a containing the elements from the operation. + /// + /// A set of elements. + /// A set of elements. + /// A set containing A - B elements. if a is . + public static ISet Minus(ISet a, ISet b) + { + if (a == null) + return null; + else + return a.Minus(b); + } + + /// + /// Performs a "minus" of set b from set a. This returns a set of all + /// the elements in set a, removing the elements that are also in set b. + /// The original sets are not modified during this operation. The result set is a Clone() + /// of set a containing the elements from the operation. + /// + /// A set of elements. + /// A set of elements. + /// A set containing A - B elements. if a is . + public static Set operator -(Set a, Set b) + { + return (Set) Minus(a, b); + } + + /// + /// Performs an "exclusive-or" of the two sets, keeping only the elements that + /// are in one of the sets, but not in both. The original sets are not modified + /// during this operation. The result set is a Clone() of this set containing + /// the elements from the exclusive-or operation. + /// + /// A set of elements. + /// A set containing the result of a ^ b. + public virtual ISet ExclusiveOr(ISet a) + { + ISet resultSet = (ISet) this.Clone(); + foreach (T element in a) + { + if (resultSet.Contains(element)) + resultSet.Remove(element); + else + resultSet.Add(element); + } + + return resultSet; + } + + /// + /// Performs an "exclusive-or" of the two sets, keeping only the elements that + /// are in one of the sets, but not in both. The original sets are not modified + /// during this operation. The result set is a Clone() of one of the sets + /// (a if it is not ) containing + /// the elements from the exclusive-or operation. + /// + /// A set of elements. + /// A set of elements. + /// A set containing the result of a ^ b. if both sets are . + public static ISet ExclusiveOr(ISet a, ISet b) + { + if (a == null && b == null) + return null; + else if (a == null) + return (ISet) b.Clone(); + else if (b == null) + return (ISet) a.Clone(); + else + return a.ExclusiveOr(b); + } + + /// + /// Performs an "exclusive-or" of the two sets, keeping only the elements that + /// are in one of the sets, but not in both. The original sets are not modified + /// during this operation. The result set is a Clone() of one of the sets + /// (a if it is not ) containing + /// the elements from the exclusive-or operation. + /// + /// A set of elements. + /// A set of elements. + /// A set containing the result of a ^ b. if both sets are . + public static Set operator ^(Set a, Set b) + { + return (Set) ExclusiveOr(a, b); + } + + /// + /// Adds the specified element to this set if it is not already present. + /// + /// The object to add to the set. + /// is the object was added, if it was already present. + public abstract bool Add(T o); + + /// + /// Adds all the elements in the specified collection to the set if they are not already present. + /// + /// A collection of objects to add to the set. + /// is the set changed as a result of this operation, if not. + public abstract bool AddAll(ICollection c); + + /// + /// Removes all objects from the set. + /// + public abstract void Clear(); + + /// + /// Returns if this set contains the specified element. + /// + /// The element to look for. + /// if this set contains the specified element, otherwise. + public abstract bool Contains(T o); + + /// + /// Returns if the set contains all the elements in the specified collection. + /// + /// A collection of objects. + /// if the set contains all the elements in the specified collection, otherwise. + public abstract bool ContainsAll(ICollection c); + + /// + /// Returns if this set contains no elements. + /// + public abstract bool IsEmpty { get; } + + /// + /// Removes the specified element from the set. + /// + /// The element to be removed. + /// if the set contained the specified element, otherwise. + public abstract bool Remove(T o); + + /// + /// Remove all the specified elements from this set, if they exist in this set. + /// + /// A collection of elements to remove. + /// if the set was modified as a result of this operation. + public abstract bool RemoveAll(ICollection c); + + /// + /// Retains only the elements in this set that are contained in the specified collection. + /// + /// Collection that defines the set of elements to be retained. + /// if this set changed as a result of this operation. + public abstract bool RetainAll(ICollection c); + + /// + /// Returns a clone of the Set instance. This will work for derived Set + /// classes if the derived class implements a constructor that takes no arguments. + /// + /// A clone of this object. + public virtual object Clone() + { + Set newSet = (Set) Activator.CreateInstance(this.GetType()); + newSet.AddAll(this); + return newSet; + } + + /// + /// Copies the elements in the Set to an array. The type of array needs + /// to be compatible with the objects in the Set, obviously. + /// + /// An array that will be the target of the copy operation. + /// The zero-based index where copying will start. + public abstract void CopyTo(T[] array, int index); + + /// + /// The number of elements currently contained in this collection. + /// + public abstract int Count { get; } + + /// + /// Returns if the Set is synchronized across threads. Note that + /// enumeration is inherently not thread-safe. Use the SyncRoot to lock the + /// object during enumeration. + /// + public abstract bool IsSynchronized { get; } + + /// + /// An object that can be used to synchronize this collection to make it thread-safe. + /// When implementing this, if your object uses a base object, like an IDictionary, + /// or anything that has a SyncRoot, return that object instead of "this". + /// + public abstract object SyncRoot { get; } + + /// + /// Gets an enumerator for the elements in the Set. + /// + /// An IEnumerator over the elements in the Set. + public abstract IEnumerator GetEnumerator(); + + /// + /// Indicates whether the given instance is read-only or not + /// + /// + /// if the ISet is read-only; otherwise, . + /// In the default implementation of Set, this property always returns false. + /// + public virtual bool IsReadOnly + { + get { return false; } + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + void ICollection.Add(T item) + { + this.Add(item); + } + + #region Protected helpers + + /// + /// Performs CopyTo when called trhough non-generic ISet (ICollection) interface + /// + /// + /// + protected abstract void NonGenericCopyTo(Array array, int index); + + /// + /// Performs Union when called trhough non-generic ISet interface + /// + /// + /// + protected virtual ISet NonGenericUnion(ISet a) + { + ISet resultSet = (ISet) this.Clone(); + if (a != null) + resultSet.AddAll(a); + return resultSet; + } + + /// + /// Performs Minus when called trhough non-generic ISet interface + /// + /// + /// + protected virtual ISet NonGenericMinus(ISet a) + { + ISet resultSet = (ISet) this.Clone(); + if (a != null) + resultSet.RemoveAll(a); + return resultSet; + } + + /// + /// Performs Intersect when called trhough non-generic ISet interface + /// + /// + /// + protected virtual ISet NonGenericIntersect(ISet a) + { + ISet resultSet = (ISet) this.Clone(); + if (a != null) + resultSet.RetainAll(a); + else + resultSet.Clear(); + return resultSet; + } + + /// + /// Performs ExclusiveOr when called trhough non-generic ISet interface + /// + /// + /// + protected virtual ISet NonGenericExclusiveOr(ISet a) + { + ISet resultSet = (ISet) this.Clone(); + foreach (object element in a) + { + if (resultSet.Contains(element)) + resultSet.Remove(element); + else + resultSet.Add(element); + } + + return resultSet; + } + + #endregion Protected helpers + + #region ISet implementation + + void ICollection.CopyTo(Array array, int index) + { + this.NonGenericCopyTo(array, index); + } + + ISet ISet.Union(ISet a) + { + return this.NonGenericUnion(a); + } + + ISet ISet.Intersect(ISet a) + { + return NonGenericIntersect(a); + } + + ISet ISet.Minus(ISet a) + { + return NonGenericMinus(a); + } + + ISet ISet.ExclusiveOr(ISet a) + { + return NonGenericExclusiveOr(a); + } + + bool ISet.Contains(object o) + { + if (o is T) + return this.Contains((T) o); + else + return false; + } + + bool ISet.ContainsAll(ICollection c) + { + ICollection col = new List(c.Count); + foreach (object o in c) + { + if (o is T) + col.Add((T) o); + else + return false; + } + + return this.ContainsAll(col); + } + + bool ISet.Add(object o) + { + return this.Add((T) o); + } + + bool ISet.AddAll(ICollection c) + { + bool changed = false; + foreach (T obj in c) + changed |= this.Add(obj); + return changed; + } + + bool ISet.Remove(object o) + { + if (o is T) + return this.Remove((T) o); + else + return false; + } + + bool ISet.RemoveAll(ICollection c) + { + ICollection col = new List(c.Count); + foreach (object o in c) + { + if (o is T) + col.Add((T) o); + } + + return this.RemoveAll(col); + } + + bool ISet.RetainAll(ICollection c) + { + ICollection col = new List(c.Count); + foreach (object o in c) + { + if (o is T) + col.Add((T) o); + } + + return this.RetainAll(col); + } + + #endregion ISet implementation } diff --git a/src/Spring/Spring.Core/Collections/Generic/SortedSet.cs b/src/Spring/Spring.Core/Collections/Generic/SortedSet.cs index b7bfaafd..0204f32f 100644 --- a/src/Spring/Spring.Core/Collections/Generic/SortedSet.cs +++ b/src/Spring/Spring.Core/Collections/Generic/SortedSet.cs @@ -2,67 +2,65 @@ using System.Collections; -namespace Spring.Collections.Generic +namespace Spring.Collections.Generic; + +/// +/// Implements a Set based on a sorted tree. This gives good performance for operations on very +/// large data-sets, though not as good - asymptotically - as a HashedSet. However, iteration +/// occurs in order. Elements that you put into this type of collection must implement IComparable, +/// and they must actually be comparable. You can't mix string and int values, for example. +/// +[Serializable] +public class SortedSet : DictionarySet { /// - /// Implements a Set based on a sorted tree. This gives good performance for operations on very - /// large data-sets, though not as good - asymptotically - as a HashedSet. However, iteration - /// occurs in order. Elements that you put into this type of collection must implement IComparable, - /// and they must actually be comparable. You can't mix string and int values, for example. + /// Creates a new set instance based on a sorted tree. /// - [Serializable] - public class SortedSet : DictionarySet + public SortedSet() { - /// - /// Creates a new set instance based on a sorted tree. - /// - public SortedSet() - { - InternalDictionary = new SortedDictionary(); - } + InternalDictionary = new SortedDictionary(); + } - /// - /// Creates a new set instance based on a sorted tree. - /// - /// The to use for sorting. - public SortedSet(IComparer comparer) - { - InternalDictionary = new SortedList(comparer); - } + /// + /// Creates a new set instance based on a sorted tree. + /// + /// The to use for sorting. + public SortedSet(IComparer comparer) + { + InternalDictionary = new SortedList(comparer); + } - /// - /// Creates a new set instance based on a sorted tree and - /// initializes it based on a collection of elements. - /// - /// A collection of elements that defines the initial set contents. - public SortedSet(ICollection initialValues) - : this() - { - this.AddAll(initialValues); - } + /// + /// Creates a new set instance based on a sorted tree and + /// initializes it based on a collection of elements. + /// + /// A collection of elements that defines the initial set contents. + public SortedSet(ICollection initialValues) + : this() + { + this.AddAll(initialValues); + } + /// + /// Creates a new set instance based on a sorted tree and + /// initializes it based on a collection of elements. + /// + /// A collection of elements that defines the initial set contents. + public SortedSet(ICollection initialValues) + : this() + { + ((ISet) this).AddAll(initialValues); + } - /// - /// Creates a new set instance based on a sorted tree and - /// initializes it based on a collection of elements. - /// - /// A collection of elements that defines the initial set contents. - public SortedSet(ICollection initialValues) - : this() - { - ((ISet)this).AddAll(initialValues); - } - - /// - /// Creates a new set instance based on a sorted tree and - /// initializes it based on a collection of elements. - /// - /// A collection of elements that defines the initial set contents. - /// The to use for sorting. - public SortedSet(ICollection initialValues, IComparer comparer) - : this(comparer) - { - this.AddAll(initialValues); - } + /// + /// Creates a new set instance based on a sorted tree and + /// initializes it based on a collection of elements. + /// + /// A collection of elements that defines the initial set contents. + /// The to use for sorting. + public SortedSet(ICollection initialValues, IComparer comparer) + : this(comparer) + { + this.AddAll(initialValues); } } diff --git a/src/Spring/Spring.Core/Collections/Generic/SynchronizedSet.cs b/src/Spring/Spring.Core/Collections/Generic/SynchronizedSet.cs index 13a97224..bd9ff86f 100644 --- a/src/Spring/Spring.Core/Collections/Generic/SynchronizedSet.cs +++ b/src/Spring/Spring.Core/Collections/Generic/SynchronizedSet.cs @@ -2,260 +2,261 @@ using System.Collections; -namespace Spring.Collections.Generic +namespace Spring.Collections.Generic; + +/// +///

Implements a thread-safe Set wrapper. The implementation is extremely conservative, +/// serializing critical sections to prevent possible deadlocks, and locking on everything. +/// The one exception is for enumeration, which is inherently not thread-safe. For this, you +/// have to lock the SyncRoot object for the duration of the enumeration.

+///
+[Serializable] +public sealed class SynchronizedSet : Set { + private ISet mBasisSet; + private object mSyncRoot; + /// - ///

Implements a thread-safe Set wrapper. The implementation is extremely conservative, - /// serializing critical sections to prevent possible deadlocks, and locking on everything. - /// The one exception is for enumeration, which is inherently not thread-safe. For this, you - /// have to lock the SyncRoot object for the duration of the enumeration.

+ /// Constructs a thread-safe Set wrapper. ///
- [Serializable] - public sealed class SynchronizedSet : Set + /// The Set object that this object will wrap. + public SynchronizedSet(ISet basisSet) { - private ISet mBasisSet; - private object mSyncRoot; + mBasisSet = basisSet; + mSyncRoot = ((ICollection) basisSet).SyncRoot; + if (mSyncRoot == null) + throw new NullReferenceException("The Set you specified returned a null SyncRoot."); + } - /// - /// Constructs a thread-safe Set wrapper. - /// - /// The Set object that this object will wrap. - public SynchronizedSet(ISet basisSet) + /// + /// Adds the specified element to this set if it is not already present. + /// + /// The object to add to the set. + /// is the object was added, if it was already present. + public override sealed bool Add(T o) + { + lock (mSyncRoot) { - mBasisSet = basisSet; - mSyncRoot = ((ICollection)basisSet).SyncRoot; - if (mSyncRoot == null) - throw new NullReferenceException("The Set you specified returned a null SyncRoot."); + return mBasisSet.Add(o); + } + } + + /// + /// Adds all the elements in the specified collection to the set if they are not already present. + /// + /// A collection of objects to add to the set. + /// is the set changed as a result of this operation, if not. + public override sealed bool AddAll(ICollection c) + { + Set temp; + lock (((ICollection) c).SyncRoot) + { + temp = new HashedSet(c); } - /// - /// Adds the specified element to this set if it is not already present. - /// - /// The object to add to the set. - /// is the object was added, if it was already present. - public override sealed bool Add(T o) + lock (mSyncRoot) + { + return mBasisSet.AddAll(temp); + } + } + + /// + /// Removes all objects from the set. + /// + public override sealed void Clear() + { + lock (mSyncRoot) + { + mBasisSet.Clear(); + } + } + + /// + /// Returns if this set contains the specified element. + /// + /// The element to look for. + /// if this set contains the specified element, otherwise. + public override sealed bool Contains(T o) + { + lock (mSyncRoot) + { + return mBasisSet.Contains(o); + } + } + + /// + /// Returns if the set contains all the elements in the specified collection. + /// + /// A collection of objects. + /// if the set contains all the elements in the specified collection, otherwise. + public override sealed bool ContainsAll(ICollection c) + { + Set temp; + lock (((ICollection) c).SyncRoot) + { + temp = new HashedSet(c); + } + + lock (mSyncRoot) + { + return mBasisSet.ContainsAll(temp); + } + } + + /// + /// Returns if this set contains no elements. + /// + public override sealed bool IsEmpty + { + get { lock (mSyncRoot) { - return mBasisSet.Add(o); - } - } - - /// - /// Adds all the elements in the specified collection to the set if they are not already present. - /// - /// A collection of objects to add to the set. - /// is the set changed as a result of this operation, if not. - public override sealed bool AddAll(ICollection c) - { - Set temp; - lock (((ICollection)c).SyncRoot) - { - temp = new HashedSet(c); - } - - lock (mSyncRoot) - { - return mBasisSet.AddAll(temp); - } - } - - /// - /// Removes all objects from the set. - /// - public override sealed void Clear() - { - lock (mSyncRoot) - { - mBasisSet.Clear(); - } - } - - /// - /// Returns if this set contains the specified element. - /// - /// The element to look for. - /// if this set contains the specified element, otherwise. - public override sealed bool Contains(T o) - { - lock (mSyncRoot) - { - return mBasisSet.Contains(o); - } - } - - /// - /// Returns if the set contains all the elements in the specified collection. - /// - /// A collection of objects. - /// if the set contains all the elements in the specified collection, otherwise. - public override sealed bool ContainsAll(ICollection c) - { - Set temp; - lock (((ICollection)c).SyncRoot) - { - temp = new HashedSet(c); - } - lock (mSyncRoot) - { - return mBasisSet.ContainsAll(temp); - } - } - - /// - /// Returns if this set contains no elements. - /// - public override sealed bool IsEmpty - { - get - { - lock (mSyncRoot) - { - return mBasisSet.IsEmpty; - } - } - } - - - /// - /// Removes the specified element from the set. - /// - /// The element to be removed. - /// if the set contained the specified element, otherwise. - public override sealed bool Remove(T o) - { - lock (mSyncRoot) - { - return mBasisSet.Remove(o); - } - } - - /// - /// Remove all the specified elements from this set, if they exist in this set. - /// - /// A collection of elements to remove. - /// if the set was modified as a result of this operation. - public override sealed bool RemoveAll(ICollection c) - { - Set temp; - lock (((ICollection)c).SyncRoot) - { - temp = new HashedSet(c); - } - lock (mSyncRoot) - { - return mBasisSet.RemoveAll(temp); - } - } - - /// - /// Retains only the elements in this set that are contained in the specified collection. - /// - /// Collection that defines the set of elements to be retained. - /// if this set changed as a result of this operation. - public override sealed bool RetainAll(ICollection c) - { - Set temp; - lock (((ICollection)c).SyncRoot) - { - temp = new HashedSet(c); - } - lock (mSyncRoot) - { - return mBasisSet.RetainAll(temp); - } - } - - /// - /// Copies the elements in the Set to an array. The type of array needs - /// to be compatible with the objects in the Set, obviously. - /// - /// An array that will be the target of the copy operation. - /// The zero-based index where copying will start. - public override sealed void CopyTo(T[] array, int index) - { - lock (mSyncRoot) - { - mBasisSet.CopyTo(array, index); - } - } - - /// - /// The number of elements contained in this collection. - /// - public override sealed int Count - { - get - { - lock (mSyncRoot) - { - return mBasisSet.Count; - } - } - } - - /// - /// Returns , indicating that this object is thread-safe. The exception to this - /// is enumeration, which is inherently not thread-safe. Use the SyncRoot object to - /// lock this object for the entire duration of the enumeration. - /// - public override sealed bool IsSynchronized - { - get { return true; } - } - - /// - /// Returns an object that can be used to synchronize the Set between threads. - /// - public override sealed object SyncRoot - { - get { return mSyncRoot; } - } - - /// - /// Enumeration is, by definition, not thread-safe. Use a lock on the SyncRoot - /// to synchronize the entire enumeration process. - /// - /// - public override sealed IEnumerator GetEnumerator() - { - return mBasisSet.GetEnumerator(); - } - - /// - /// Returns a clone of the Set instance. - /// - /// A clone of this object. - public override object Clone() - { - return new SynchronizedSet((ISet)mBasisSet.Clone()); - } - - /// - /// Indicates whether given instace is read-only or not - /// - public override bool IsReadOnly - { - get - { - lock (mSyncRoot) - { - return mBasisSet.IsReadOnly; - } - } - } - - /// - /// Performs CopyTo when called trhough non-generic ISet (ICollection) interface - /// - /// - /// - protected override void NonGenericCopyTo(Array array, int index) - { - lock (mSyncRoot) - { - ((ICollection)this.mBasisSet).CopyTo(array, index); + return mBasisSet.IsEmpty; } } } + + /// + /// Removes the specified element from the set. + /// + /// The element to be removed. + /// if the set contained the specified element, otherwise. + public override sealed bool Remove(T o) + { + lock (mSyncRoot) + { + return mBasisSet.Remove(o); + } + } + + /// + /// Remove all the specified elements from this set, if they exist in this set. + /// + /// A collection of elements to remove. + /// if the set was modified as a result of this operation. + public override sealed bool RemoveAll(ICollection c) + { + Set temp; + lock (((ICollection) c).SyncRoot) + { + temp = new HashedSet(c); + } + + lock (mSyncRoot) + { + return mBasisSet.RemoveAll(temp); + } + } + + /// + /// Retains only the elements in this set that are contained in the specified collection. + /// + /// Collection that defines the set of elements to be retained. + /// if this set changed as a result of this operation. + public override sealed bool RetainAll(ICollection c) + { + Set temp; + lock (((ICollection) c).SyncRoot) + { + temp = new HashedSet(c); + } + + lock (mSyncRoot) + { + return mBasisSet.RetainAll(temp); + } + } + + /// + /// Copies the elements in the Set to an array. The type of array needs + /// to be compatible with the objects in the Set, obviously. + /// + /// An array that will be the target of the copy operation. + /// The zero-based index where copying will start. + public override sealed void CopyTo(T[] array, int index) + { + lock (mSyncRoot) + { + mBasisSet.CopyTo(array, index); + } + } + + /// + /// The number of elements contained in this collection. + /// + public override sealed int Count + { + get + { + lock (mSyncRoot) + { + return mBasisSet.Count; + } + } + } + + /// + /// Returns , indicating that this object is thread-safe. The exception to this + /// is enumeration, which is inherently not thread-safe. Use the SyncRoot object to + /// lock this object for the entire duration of the enumeration. + /// + public override sealed bool IsSynchronized + { + get { return true; } + } + + /// + /// Returns an object that can be used to synchronize the Set between threads. + /// + public override sealed object SyncRoot + { + get { return mSyncRoot; } + } + + /// + /// Enumeration is, by definition, not thread-safe. Use a lock on the SyncRoot + /// to synchronize the entire enumeration process. + /// + /// + public override sealed IEnumerator GetEnumerator() + { + return mBasisSet.GetEnumerator(); + } + + /// + /// Returns a clone of the Set instance. + /// + /// A clone of this object. + public override object Clone() + { + return new SynchronizedSet((ISet) mBasisSet.Clone()); + } + + /// + /// Indicates whether given instace is read-only or not + /// + public override bool IsReadOnly + { + get + { + lock (mSyncRoot) + { + return mBasisSet.IsReadOnly; + } + } + } + + /// + /// Performs CopyTo when called trhough non-generic ISet (ICollection) interface + /// + /// + /// + protected override void NonGenericCopyTo(Array array, int index) + { + lock (mSyncRoot) + { + ((ICollection) this.mBasisSet).CopyTo(array, index); + } + } } diff --git a/src/Spring/Spring.Core/Collections/HashedSet.cs b/src/Spring/Spring.Core/Collections/HashedSet.cs index 31d7f67b..66435aa1 100644 --- a/src/Spring/Spring.Core/Collections/HashedSet.cs +++ b/src/Spring/Spring.Core/Collections/HashedSet.cs @@ -22,40 +22,39 @@ using System.Collections; -namespace Spring.Collections -{ - /// - /// Implements an based on a - /// hash table. - /// - /// - ///

- /// This will give the best lookup, add, and remove performance for very - /// large data-sets, but iteration will occur in no particular order. - ///

- ///
- /// - [Serializable] - public class HashedSet : DictionarySet - { - /// - /// Creates a new instance of the class. - /// - public HashedSet() - { - InternalDictionary = new Hashtable(); - } +namespace Spring.Collections; - /// - /// Creates a new instance of the class, and - /// initializes it based on a collection of elements. - /// - /// - /// A collection of elements that defines the initial set contents. - /// - public HashedSet(ICollection initialValues) : this() - { - this.AddAll(initialValues); - } - } +/// +/// Implements an based on a +/// hash table. +/// +/// +///

+/// This will give the best lookup, add, and remove performance for very +/// large data-sets, but iteration will occur in no particular order. +///

+///
+/// +[Serializable] +public class HashedSet : DictionarySet +{ + /// + /// Creates a new instance of the class. + /// + public HashedSet() + { + InternalDictionary = new Hashtable(); + } + + /// + /// Creates a new instance of the class, and + /// initializes it based on a collection of elements. + /// + /// + /// A collection of elements that defines the initial set contents. + /// + public HashedSet(ICollection initialValues) : this() + { + this.AddAll(initialValues); + } } diff --git a/src/Spring/Spring.Core/Collections/HybridSet.cs b/src/Spring/Spring.Core/Collections/HybridSet.cs index a87dcde3..76efa404 100644 --- a/src/Spring/Spring.Core/Collections/HybridSet.cs +++ b/src/Spring/Spring.Core/Collections/HybridSet.cs @@ -23,57 +23,56 @@ using System.Collections; using System.Collections.Specialized; -namespace Spring.Collections +namespace Spring.Collections; + +/// +/// Implements an that automatically +/// changes from a list based implementation to a hashtable based +/// implementation when the size reaches a certain threshold. +/// +/// +///

+/// This is good if you are unsure about whether you data-set will be tiny +/// or huge. +///

+/// +/// Because this uses a dual implementation, iteration order is not +/// guaranteed! +/// +///
+/// +[Serializable] +public class HybridSet : DictionarySet { - /// - /// Implements an that automatically - /// changes from a list based implementation to a hashtable based - /// implementation when the size reaches a certain threshold. - /// - /// - ///

- /// This is good if you are unsure about whether you data-set will be tiny - /// or huge. - ///

- /// - /// Because this uses a dual implementation, iteration order is not - /// guaranteed! - /// - ///
- /// - [Serializable] - public class HybridSet : DictionarySet - { - /// - /// Creates a new set instance based on either a list or a hash table, - /// depending on which will be more efficient based on the data-set - /// size. - /// - public HybridSet() - { - InternalDictionary = new HybridDictionary(); - } + /// + /// Creates a new set instance based on either a list or a hash table, + /// depending on which will be more efficient based on the data-set + /// size. + /// + public HybridSet() + { + InternalDictionary = new HybridDictionary(); + } - /// - /// Initializes a new instance of the class with a given capacity - /// - /// The size. - public HybridSet(int size) - { - InternalDictionary = new HybridDictionary(size); - } + /// + /// Initializes a new instance of the class with a given capacity + /// + /// The size. + public HybridSet(int size) + { + InternalDictionary = new HybridDictionary(size); + } - /// - /// Creates a new set instance based on either a list or a hash table, - /// depending on which will be more efficient based on the data-set - /// size, and initializes it based on a collection of elements. - /// - /// - /// A collection of elements that defines the initial set contents. - /// - public HybridSet(ICollection initialValues) : this() - { - this.AddAll(initialValues); - } - } -} + /// + /// Creates a new set instance based on either a list or a hash table, + /// depending on which will be more efficient based on the data-set + /// size, and initializes it based on a collection of elements. + /// + /// + /// A collection of elements that defines the initial set contents. + /// + public HybridSet(ICollection initialValues) : this() + { + this.AddAll(initialValues); + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Collections/IQueue.cs b/src/Spring/Spring.Core/Collections/IQueue.cs index d01c6a1b..a96feccb 100644 --- a/src/Spring/Spring.Core/Collections/IQueue.cs +++ b/src/Spring/Spring.Core/Collections/IQueue.cs @@ -20,208 +20,207 @@ using System.Collections; -namespace Spring.Collections +namespace Spring.Collections; + +/// +/// A collection designed for holding elements prior to processing. +/// +/// +///

+/// Besides basic operations, +/// queues provide additional insertion, extraction, and inspection +/// operations. +///

+///

+/// Each of these methods exists in two forms: one throws +/// an exception if the operation fails, the other returns a special +/// value (either or , depending on the +/// operation). The latter form of the insert operation is designed +/// specifically for use with capacity-restricted +/// implementations; in most implementations, insert operations cannot +/// fail. +///

+///

+/// Queues typically, but do not necessarily, order elements in a +/// FIFO (first-in-first-out) manner. Among the exceptions are +/// priority queues, which order elements according to a supplied +/// comparator, or the elements' natural ordering, and LIFO queues (or +/// stacks) which order the elements LIFO (last-in-first-out). +/// Whatever the ordering used, the head of the queue is that +/// element which would be removed by a call to +/// or +/// . In a FIFO queue, all new +/// elements are inserted at the tail of the queue. Other kinds of queues may +/// use different placement rules. Every implementation +/// must specify its ordering properties. +///

+///

+/// The method inserts an +/// element if possible, otherwise returning . This differs from the +/// method, which can fail to +/// add an element only by throwing an exception. The +/// method is designed for +/// use when failure is a normal, rather than exceptional occurrence, for example, +/// in fixed-capacity (or "bounded" queues. +///

+///

+/// The +/// methods remove and +/// return the head of the queue. Exactly which element is removed from the +/// queue is a function of the queue's ordering policy, which differs from +/// implementation to implementation. The +/// and +/// methods differ only in their +/// behavior when the queue is empty: the +/// method throws an exception, +/// while the method returns +/// . +///

+///

+/// The and +/// methods return, but do +/// not remove, the head of the queue. +///

+///

+/// The interface does not define the blocking queue +/// methods, which are common in concurrent programming. +///

+///

+/// implementations generally do not allow insertion +/// of elements, although some implementations, such as +/// a linked list, do not prohibit the insertion of . +/// Even in the implementations that permit it, should +/// not be inserted into a , as is also +/// used as a special return value by the +/// method to +/// indicate that the queue contains no elements. +///

+///

+/// implementations generally do not define +/// element-based versions of methods +/// and , but instead inherit the +/// identity based versions from the class object, because element-based equality +/// is not always well-defined for queues with the same elements but different +/// ordering properties. +///

+///

+/// Based on the back port of JCP JSR-166. +///

+///
+/// Doug Lea +/// Griffin Caprio (.NET) +public interface IQueue : ICollection { - /// - /// A collection designed for holding elements prior to processing. - /// - /// - ///

- /// Besides basic operations, - /// queues provide additional insertion, extraction, and inspection - /// operations. - ///

- ///

- /// Each of these methods exists in two forms: one throws - /// an exception if the operation fails, the other returns a special - /// value (either or , depending on the - /// operation). The latter form of the insert operation is designed - /// specifically for use with capacity-restricted - /// implementations; in most implementations, insert operations cannot - /// fail. - ///

- ///

- /// Queues typically, but do not necessarily, order elements in a - /// FIFO (first-in-first-out) manner. Among the exceptions are - /// priority queues, which order elements according to a supplied - /// comparator, or the elements' natural ordering, and LIFO queues (or - /// stacks) which order the elements LIFO (last-in-first-out). - /// Whatever the ordering used, the head of the queue is that - /// element which would be removed by a call to - /// or - /// . In a FIFO queue, all new - /// elements are inserted at the tail of the queue. Other kinds of queues may - /// use different placement rules. Every implementation - /// must specify its ordering properties. - ///

- ///

- /// The method inserts an - /// element if possible, otherwise returning . This differs from the - /// method, which can fail to - /// add an element only by throwing an exception. The - /// method is designed for - /// use when failure is a normal, rather than exceptional occurrence, for example, - /// in fixed-capacity (or "bounded" queues. - ///

- ///

- /// The - /// methods remove and - /// return the head of the queue. Exactly which element is removed from the - /// queue is a function of the queue's ordering policy, which differs from - /// implementation to implementation. The - /// and - /// methods differ only in their - /// behavior when the queue is empty: the - /// method throws an exception, - /// while the method returns - /// . - ///

- ///

- /// The and - /// methods return, but do - /// not remove, the head of the queue. - ///

- ///

- /// The interface does not define the blocking queue - /// methods, which are common in concurrent programming. - ///

- ///

- /// implementations generally do not allow insertion - /// of elements, although some implementations, such as - /// a linked list, do not prohibit the insertion of . - /// Even in the implementations that permit it, should - /// not be inserted into a , as is also - /// used as a special return value by the - /// method to - /// indicate that the queue contains no elements. - ///

- ///

- /// implementations generally do not define - /// element-based versions of methods - /// and , but instead inherit the - /// identity based versions from the class object, because element-based equality - /// is not always well-defined for queues with the same elements but different - /// ordering properties. - ///

- ///

- /// Based on the back port of JCP JSR-166. - ///

- ///
- /// Doug Lea - /// Griffin Caprio (.NET) - public interface IQueue : ICollection - { - /// - /// Inserts the specified element into this queue if it is possible to do so - /// immediately without violating capacity restrictions, returning - /// upon success and throwing an - /// if no space is - /// currently available. - /// - /// - /// The element to add. - /// - /// - /// if successful. - /// - /// - /// If the element cannot be added at this time due to capacity restrictions. - /// - /// - /// If the class of the supplied prevents it - /// from being added to this queue. - /// - /// - /// If the specified element is and this queue does not - /// permit elements. - /// - /// - /// If some property of the supplied prevents - /// it from being added to this queue. - /// - bool Add(object objectToAdd); + /// + /// Inserts the specified element into this queue if it is possible to do so + /// immediately without violating capacity restrictions, returning + /// upon success and throwing an + /// if no space is + /// currently available. + /// + /// + /// The element to add. + /// + /// + /// if successful. + /// + /// + /// If the element cannot be added at this time due to capacity restrictions. + /// + /// + /// If the class of the supplied prevents it + /// from being added to this queue. + /// + /// + /// If the specified element is and this queue does not + /// permit elements. + /// + /// + /// If some property of the supplied prevents + /// it from being added to this queue. + /// + bool Add(object objectToAdd); - /// - /// Inserts the specified element into this queue if it is possible to do - /// so immediately without violating capacity restrictions. - /// - /// - ///

- /// When using a capacity-restricted queue, this method is generally - /// preferable to , - /// which can fail to insert an element only by throwing an exception. - ///

- ///
- /// - /// The element to add. - /// - /// - /// if the element was added to this queue. - /// - /// - /// If the element cannot be added at this time due to capacity restrictions. - /// - /// - /// If the supplied is - /// . - /// - /// - /// If some property of the supplied prevents - /// it from being added to this queue. - /// - bool Offer(object objectToAdd); + /// + /// Inserts the specified element into this queue if it is possible to do + /// so immediately without violating capacity restrictions. + /// + /// + ///

+ /// When using a capacity-restricted queue, this method is generally + /// preferable to , + /// which can fail to insert an element only by throwing an exception. + ///

+ ///
+ /// + /// The element to add. + /// + /// + /// if the element was added to this queue. + /// + /// + /// If the element cannot be added at this time due to capacity restrictions. + /// + /// + /// If the supplied is + /// . + /// + /// + /// If some property of the supplied prevents + /// it from being added to this queue. + /// + bool Offer(object objectToAdd); - /// - /// Retrieves and removes the head of this queue. - /// - /// - ///

- /// This method differs from - /// only in that it throws an exception if this queue is empty. - ///

- ///
- /// - /// The head of this queue - /// - /// if this queue is empty - object Remove(); + /// + /// Retrieves and removes the head of this queue. + /// + /// + ///

+ /// This method differs from + /// only in that it throws an exception if this queue is empty. + ///

+ ///
+ /// + /// The head of this queue + /// + /// if this queue is empty + object Remove(); - /// - /// Retrieves and removes the head of this queue, - /// or returns if this queue is empty. - /// - /// - /// The head of this queue, or if this queue is empty. - /// - object Poll(); + /// + /// Retrieves and removes the head of this queue, + /// or returns if this queue is empty. + /// + /// + /// The head of this queue, or if this queue is empty. + /// + object Poll(); - /// - /// Retrieves, but does not remove, the head of this queue. - /// - /// - ///

- /// This method differs from - /// only in that it throws an exception if this queue is empty. - ///

- ///
- /// - /// The head of this queue. - /// - /// If this queue is empty. - object Element(); + /// + /// Retrieves, but does not remove, the head of this queue. + /// + /// + ///

+ /// This method differs from + /// only in that it throws an exception if this queue is empty. + ///

+ ///
+ /// + /// The head of this queue. + /// + /// If this queue is empty. + object Element(); - /// - /// Retrieves, but does not remove, the head of this queue, - /// or returns if this queue is empty. - /// - /// - /// The head of this queue, or if this queue is empty. - /// - object Peek(); + /// + /// Retrieves, but does not remove, the head of this queue, + /// or returns if this queue is empty. + /// + /// + /// The head of this queue, or if this queue is empty. + /// + object Peek(); - /// - /// Returns if there are no elements in the , otherwise. - /// - bool IsEmpty { get; } - } + /// + /// Returns if there are no elements in the , otherwise. + /// + bool IsEmpty { get; } } diff --git a/src/Spring/Spring.Core/Collections/ISet.cs b/src/Spring/Spring.Core/Collections/ISet.cs index 438cc622..cacc6c7f 100644 --- a/src/Spring/Spring.Core/Collections/ISet.cs +++ b/src/Spring/Spring.Core/Collections/ISet.cs @@ -22,248 +22,247 @@ using System.Collections; -namespace Spring.Collections +namespace Spring.Collections; + +/// +/// A collection that contains no duplicate elements. +/// +/// +///

+/// This interface models the mathematical +/// abstraction. The order of +/// elements in a set is dependant on (a)the data-structure implementation, and +/// (b)the implementation of the various +/// methods, and thus is not +/// guaranteed. +///

+///

+/// overrides the +/// method to test for "equivalency": +/// whether the two sets contain the same elements. The "==" and "!=" +/// operators are not overridden by design, since it is often desirable to +/// compare object references for equality. +///

+///

+/// Also, the method is not +/// implemented on any of the set implementations, since none of them are +/// truly immutable. This is by design, and it is the way almost all +/// collections in the .NET framework function. So as a general rule, don't +/// store collection objects inside +/// instances. You would typically want to use a keyed +/// instead. +///

+///

+/// None of the implementations in +/// this library are guaranteed to be thread-safe in any way unless wrapped +/// in a . +///

+///

+/// The following table summarizes the binary operators that are supported +/// by the class. +///

+/// +/// +/// Operation +/// Description +/// Method +/// +/// +/// Union (OR) +/// +/// Element included in result if it exists in either A OR +/// B. +/// +/// Union() +/// +/// +/// Intersection (AND) +/// +/// Element included in result if it exists in both A AND +/// B. +/// +/// InterSect() +/// +/// +/// Exclusive Or (XOR) +/// +/// Element included in result if it exists in one, but not both, +/// of A and B. +/// +/// ExclusiveOr() +/// +/// +/// Minus (n/a) +/// +/// Take all the elements in A. Now, if any of them exist in +/// B, remove them. Note that unlike the other operators, +/// A - B is not the same as B - A. +/// +/// Minus() +/// +/// +///
+public interface ISet : ICollection, ICloneable { - /// - /// A collection that contains no duplicate elements. - /// - /// - ///

- /// This interface models the mathematical - /// abstraction. The order of - /// elements in a set is dependant on (a)the data-structure implementation, and - /// (b)the implementation of the various - /// methods, and thus is not - /// guaranteed. - ///

- ///

- /// overrides the - /// method to test for "equivalency": - /// whether the two sets contain the same elements. The "==" and "!=" - /// operators are not overridden by design, since it is often desirable to - /// compare object references for equality. - ///

- ///

- /// Also, the method is not - /// implemented on any of the set implementations, since none of them are - /// truly immutable. This is by design, and it is the way almost all - /// collections in the .NET framework function. So as a general rule, don't - /// store collection objects inside - /// instances. You would typically want to use a keyed - /// instead. - ///

- ///

- /// None of the implementations in - /// this library are guaranteed to be thread-safe in any way unless wrapped - /// in a . - ///

- ///

- /// The following table summarizes the binary operators that are supported - /// by the class. - ///

- /// - /// - /// Operation - /// Description - /// Method - /// - /// - /// Union (OR) - /// - /// Element included in result if it exists in either A OR - /// B. - /// - /// Union() - /// - /// - /// Intersection (AND) - /// - /// Element included in result if it exists in both A AND - /// B. - /// - /// InterSect() - /// - /// - /// Exclusive Or (XOR) - /// - /// Element included in result if it exists in one, but not both, - /// of A and B. - /// - /// ExclusiveOr() - /// - /// - /// Minus (n/a) - /// - /// Take all the elements in A. Now, if any of them exist in - /// B, remove them. Note that unlike the other operators, - /// A - B is not the same as B - A. - /// - /// Minus() - /// - /// - ///
- public interface ISet : ICollection, ICloneable - { - /// - /// Performs a "union" of the two sets, where all the elements - /// in both sets are present. - /// - /// - ///

- /// That is, the element is included if it is in either - /// or this set. Neither this set nor the input - /// set are modified during the operation. The return value is a - /// clone of this set with the extra elements added in. - ///

- ///
- /// A collection of elements. - /// - /// A new containing the union of - /// this with the specified - /// collection. Neither of the input objects is modified by the union. - /// - ISet Union(ISet setOne); + /// + /// Performs a "union" of the two sets, where all the elements + /// in both sets are present. + /// + /// + ///

+ /// That is, the element is included if it is in either + /// or this set. Neither this set nor the input + /// set are modified during the operation. The return value is a + /// clone of this set with the extra elements added in. + ///

+ ///
+ /// A collection of elements. + /// + /// A new containing the union of + /// this with the specified + /// collection. Neither of the input objects is modified by the union. + /// + ISet Union(ISet setOne); - /// - /// Performs an "intersection" of the two sets, where only the elements - /// that are present in both sets remain. - /// - /// - ///

- /// That is, the element is included if it exists in both sets. The - /// Intersect() operation does not modify the input sets. It - /// returns a clone of this set with the appropriate elements - /// removed. - ///

- ///
- /// A set of elements. - /// - /// The intersection of this set with . - /// - ISet Intersect(ISet setOne); + /// + /// Performs an "intersection" of the two sets, where only the elements + /// that are present in both sets remain. + /// + /// + ///

+ /// That is, the element is included if it exists in both sets. The + /// Intersect() operation does not modify the input sets. It + /// returns a clone of this set with the appropriate elements + /// removed. + ///

+ ///
+ /// A set of elements. + /// + /// The intersection of this set with . + /// + ISet Intersect(ISet setOne); - /// - /// Performs a "minus" of this set from the - /// set. - /// - /// - ///

- /// This returns a set of all the elements in set - /// , removing the elements that are also in - /// this set. The original sets are not modified during this operation. - /// The result set is a clone of this - /// containing the elements from - /// the operation. - ///

- ///
- /// A set of elements. - /// - /// A set containing the elements from this set with the elements in - /// removed. - /// - ISet Minus(ISet setOne); + /// + /// Performs a "minus" of this set from the + /// set. + /// + /// + ///

+ /// This returns a set of all the elements in set + /// , removing the elements that are also in + /// this set. The original sets are not modified during this operation. + /// The result set is a clone of this + /// containing the elements from + /// the operation. + ///

+ ///
+ /// A set of elements. + /// + /// A set containing the elements from this set with the elements in + /// removed. + /// + ISet Minus(ISet setOne); - /// - /// Performs an "exclusive-or" of the two sets, keeping only those - /// elements that are in one of the sets, but not in both. - /// - /// - ///

- /// The original sets are not modified during this operation. The - /// result set is a clone of this set containing the elements - /// from the exclusive-or operation. - ///

- ///
- /// A set of elements. - /// - /// A set containing the result of - /// ^ this. - /// - ISet ExclusiveOr(ISet setOne); + /// + /// Performs an "exclusive-or" of the two sets, keeping only those + /// elements that are in one of the sets, but not in both. + /// + /// + ///

+ /// The original sets are not modified during this operation. The + /// result set is a clone of this set containing the elements + /// from the exclusive-or operation. + ///

+ ///
+ /// A set of elements. + /// + /// A set containing the result of + /// ^ this. + /// + ISet ExclusiveOr(ISet setOne); - /// - /// Returns if this set contains the specified - /// element. - /// - /// The element to look for. - /// - /// if this set contains the specified element. - /// - bool Contains(object element); + /// + /// Returns if this set contains the specified + /// element. + /// + /// The element to look for. + /// + /// if this set contains the specified element. + /// + bool Contains(object element); - /// - /// Returns if the set contains all the - /// elements in the specified collection. - /// - /// A collection of objects. - /// - /// if the set contains all the elements in the - /// specified collection. - /// - bool ContainsAll(ICollection collection); + /// + /// Returns if the set contains all the + /// elements in the specified collection. + /// + /// A collection of objects. + /// + /// if the set contains all the elements in the + /// specified collection. + /// + bool ContainsAll(ICollection collection); - /// - /// Returns if this set contains no elements. - /// - bool IsEmpty { get; } + /// + /// Returns if this set contains no elements. + /// + bool IsEmpty { get; } - /// - /// Adds the specified element to this set if it is not already present. - /// - /// The object to add to the set. - /// - /// is the object was added, - /// if the object was already present. - /// - bool Add(object element); + /// + /// Adds the specified element to this set if it is not already present. + /// + /// The object to add to the set. + /// + /// is the object was added, + /// if the object was already present. + /// + bool Add(object element); - /// - /// Adds all the elements in the specified collection to the set if - /// they are not already present. - /// - /// A collection of objects to add to the set. - /// - /// is the set changed as a result of this - /// operation. - /// - bool AddAll(ICollection collection); + /// + /// Adds all the elements in the specified collection to the set if + /// they are not already present. + /// + /// A collection of objects to add to the set. + /// + /// is the set changed as a result of this + /// operation. + /// + bool AddAll(ICollection collection); - /// - /// Removes the specified element from the set. - /// - /// The element to be removed. - /// - /// if the set contained the specified element. - /// - bool Remove(object element); + /// + /// Removes the specified element from the set. + /// + /// The element to be removed. + /// + /// if the set contained the specified element. + /// + bool Remove(object element); - /// - /// Remove all the specified elements from this set, if they exist in - /// this set. - /// - /// A collection of elements to remove. - /// - /// if the set was modified as a result of this - /// operation. - /// - bool RemoveAll(ICollection collection); + /// + /// Remove all the specified elements from this set, if they exist in + /// this set. + /// + /// A collection of elements to remove. + /// + /// if the set was modified as a result of this + /// operation. + /// + bool RemoveAll(ICollection collection); - /// - /// Retains only the elements in this set that are contained in the - /// specified collection. - /// - /// - /// The collection that defines the set of elements to be retained. - /// - /// - /// if this set changed as a result of this - /// operation. - /// - bool RetainAll(ICollection collection); + /// + /// Retains only the elements in this set that are contained in the + /// specified collection. + /// + /// + /// The collection that defines the set of elements to be retained. + /// + /// + /// if this set changed as a result of this + /// operation. + /// + bool RetainAll(ICollection collection); - /// - /// Removes all objects from this set. - /// - void Clear(); - } + /// + /// Removes all objects from this set. + /// + void Clear(); } diff --git a/src/Spring/Spring.Core/Collections/ImmutableSet.cs b/src/Spring/Spring.Core/Collections/ImmutableSet.cs index 5aa9a34f..1b6a9c7e 100644 --- a/src/Spring/Spring.Core/Collections/ImmutableSet.cs +++ b/src/Spring/Spring.Core/Collections/ImmutableSet.cs @@ -22,330 +22,333 @@ using System.Collections; -namespace Spring.Collections +namespace Spring.Collections; + +/// +/// Implements an immutable (read-only) +/// wrapper. +/// +/// +///

+/// Although this class is advertised as immutable, it really isn't. +/// Anyone with access to the wrapped +/// can still change the data. So +/// is not implemented for this , as +/// is the case for all +/// implementations in this library. This design decision was based on the +/// efficiency of not having to clone the wrapped +/// every time you wrap a mutable +/// . +///

+///
+[Serializable] +public sealed class ImmutableSet : Set { - /// - /// Implements an immutable (read-only) - /// wrapper. - /// - /// - ///

- /// Although this class is advertised as immutable, it really isn't. - /// Anyone with access to the wrapped - /// can still change the data. So - /// is not implemented for this , as - /// is the case for all - /// implementations in this library. This design decision was based on the - /// efficiency of not having to clone the wrapped - /// every time you wrap a mutable - /// . - ///

- ///
- [Serializable] - public sealed class ImmutableSet : Set - { - private const string ErrorMessage = "Object is immutable."; - private ISet _mBasisSet; + private const string ErrorMessage = "Object is immutable."; + private ISet _mBasisSet; - internal ISet BasisSet - { - get { return _mBasisSet; } - } + internal ISet BasisSet + { + get { return _mBasisSet; } + } - /// - /// Constructs an immutable (read-only) - /// wrapper. - /// - /// - /// The that is to be wrapped. - /// - public ImmutableSet(ISet basisSet) - { - _mBasisSet = basisSet; - } + /// + /// Constructs an immutable (read-only) + /// wrapper. + /// + /// + /// The that is to be wrapped. + /// + public ImmutableSet(ISet basisSet) + { + _mBasisSet = basisSet; + } - /// - /// Adds the specified element to this set if it is not already present. - /// - /// The object to add to the set. - /// - /// is the object was added, - /// if the object was already present. - /// - /// - public override sealed bool Add(object element) - { - throw CreateNotSupportedException(); - } + /// + /// Adds the specified element to this set if it is not already present. + /// + /// The object to add to the set. + /// + /// is the object was added, + /// if the object was already present. + /// + /// + public override sealed bool Add(object element) + { + throw CreateNotSupportedException(); + } - /// - /// Adds all the elements in the specified collection to the set if - /// they are not already present. - /// - /// A collection of objects to add to the set. - /// - /// is the set changed as a result of this - /// operation. - /// - /// - public override sealed bool AddAll(ICollection collection) - { - throw CreateNotSupportedException(); - } + /// + /// Adds all the elements in the specified collection to the set if + /// they are not already present. + /// + /// A collection of objects to add to the set. + /// + /// is the set changed as a result of this + /// operation. + /// + /// + public override sealed bool AddAll(ICollection collection) + { + throw CreateNotSupportedException(); + } - /// - /// Removes all objects from this set. - /// - /// - public override sealed void Clear() - { - throw CreateNotSupportedException(); - } + /// + /// Removes all objects from this set. + /// + /// + public override sealed void Clear() + { + throw CreateNotSupportedException(); + } - /// - /// Returns if this set contains the specified - /// element. - /// - /// The element to look for. - /// - /// if this set contains the specified element. - /// - public override sealed bool Contains(object element) - { - return _mBasisSet.Contains(element); - } + /// + /// Returns if this set contains the specified + /// element. + /// + /// The element to look for. + /// + /// if this set contains the specified element. + /// + public override sealed bool Contains(object element) + { + return _mBasisSet.Contains(element); + } - /// - /// Returns if the set contains all the - /// elements in the specified collection. - /// - /// A collection of objects. - /// - /// if the set contains all the elements in the - /// specified collection. - /// - public override sealed bool ContainsAll(ICollection collection) - { - return _mBasisSet.ContainsAll(collection); - } + /// + /// Returns if the set contains all the + /// elements in the specified collection. + /// + /// A collection of objects. + /// + /// if the set contains all the elements in the + /// specified collection. + /// + public override sealed bool ContainsAll(ICollection collection) + { + return _mBasisSet.ContainsAll(collection); + } - /// - /// Returns if this set contains no elements. - /// - public override sealed bool IsEmpty - { - get { return _mBasisSet.IsEmpty; } - } + /// + /// Returns if this set contains no elements. + /// + public override sealed bool IsEmpty + { + get { return _mBasisSet.IsEmpty; } + } - /// - /// Removes the specified element from the set. - /// - /// The element to be removed. - /// - /// if the set contained the specified element. - /// - /// - public override sealed bool Remove(object element) - { - throw CreateNotSupportedException(); - } + /// + /// Removes the specified element from the set. + /// + /// The element to be removed. + /// + /// if the set contained the specified element. + /// + /// + public override sealed bool Remove(object element) + { + throw CreateNotSupportedException(); + } - /// - /// Remove all the specified elements from this set, if they exist in - /// this set. - /// - /// A collection of elements to remove. - /// - /// if the set was modified as a result of this - /// operation. - /// - /// - public override sealed bool RemoveAll(ICollection collection) - { - throw CreateNotSupportedException(); - } + /// + /// Remove all the specified elements from this set, if they exist in + /// this set. + /// + /// A collection of elements to remove. + /// + /// if the set was modified as a result of this + /// operation. + /// + /// + public override sealed bool RemoveAll(ICollection collection) + { + throw CreateNotSupportedException(); + } - /// - /// Retains only the elements in this set that are contained in the - /// specified collection. - /// - /// - /// The collection that defines the set of elements to be retained. - /// - /// - /// if this set changed as a result of this - /// operation. - /// - /// - public override sealed bool RetainAll(ICollection collection) - { - throw CreateNotSupportedException(); - } + /// + /// Retains only the elements in this set that are contained in the + /// specified collection. + /// + /// + /// The collection that defines the set of elements to be retained. + /// + /// + /// if this set changed as a result of this + /// operation. + /// + /// + public override sealed bool RetainAll(ICollection collection) + { + throw CreateNotSupportedException(); + } - private static NotSupportedException CreateNotSupportedException() - { - return new NotSupportedException(ImmutableSet.ErrorMessage); - } + private static NotSupportedException CreateNotSupportedException() + { + return new NotSupportedException(ImmutableSet.ErrorMessage); + } - /// - /// Copies the elements in the to - /// an array. - /// - /// - ///

- /// The type of array needs to be compatible with the objects in the - /// , obviously. - ///

- ///
- /// - /// An array that will be the target of the copy operation. - /// - /// - /// The zero-based index where copying will start. - /// - public override sealed void CopyTo(Array array, int index) - { - _mBasisSet.CopyTo(array, index); - } + /// + /// Copies the elements in the to + /// an array. + /// + /// + ///

+ /// The type of array needs to be compatible with the objects in the + /// , obviously. + ///

+ ///
+ /// + /// An array that will be the target of the copy operation. + /// + /// + /// The zero-based index where copying will start. + /// + public override sealed void CopyTo(Array array, int index) + { + _mBasisSet.CopyTo(array, index); + } - /// - /// The number of elements currently contained in this collection. - /// - public override sealed int Count - { - get { return _mBasisSet.Count; } - } + /// + /// The number of elements currently contained in this collection. + /// + public override sealed int Count + { + get { return _mBasisSet.Count; } + } - /// - /// Returns if the - /// is synchronized across - /// threads. - /// - /// - ///

- /// Note that enumeration is inherently not thread-safe. Use the - /// to lock the object during enumeration. - ///

- ///
- public override sealed bool IsSynchronized - { - get { return _mBasisSet.IsSynchronized; } - } + /// + /// Returns if the + /// is synchronized across + /// threads. + /// + /// + ///

+ /// Note that enumeration is inherently not thread-safe. Use the + /// to lock the object during enumeration. + ///

+ ///
+ public override sealed bool IsSynchronized + { + get { return _mBasisSet.IsSynchronized; } + } - /// - /// An object that can be used to synchronize this collection to make - /// it thread-safe. - /// - /// - /// An object that can be used to synchronize this collection to make - /// it thread-safe. - /// - public override sealed object SyncRoot - { - get { return _mBasisSet.SyncRoot; } - } + /// + /// An object that can be used to synchronize this collection to make + /// it thread-safe. + /// + /// + /// An object that can be used to synchronize this collection to make + /// it thread-safe. + /// + public override sealed object SyncRoot + { + get { return _mBasisSet.SyncRoot; } + } - /// - /// Gets an enumerator for the elements in the - /// . - /// - /// - /// An over the elements - /// in the . - /// - public override sealed IEnumerator GetEnumerator() - { - return _mBasisSet.GetEnumerator(); - } + /// + /// Gets an enumerator for the elements in the + /// . + /// + /// + /// An over the elements + /// in the . + /// + public override sealed IEnumerator GetEnumerator() + { + return _mBasisSet.GetEnumerator(); + } - /// - /// Returns a clone of the - /// instance. - /// - /// A clone of this object. - public override sealed object Clone() - { - return new ImmutableSet(_mBasisSet); - } + /// + /// Returns a clone of the + /// instance. + /// + /// A clone of this object. + public override sealed object Clone() + { + return new ImmutableSet(_mBasisSet); + } - /// - /// Performs a "union" of the two sets, where all the elements - /// in both sets are present. - /// - /// A collection of elements. - /// - /// A new containing the union of - /// this with the specified - /// collection. Neither of the input objects is modified by the union. - /// - /// - public override sealed ISet Union(ISet setOne) - { - ISet m = this; - while (m is ImmutableSet) - { - m = ((ImmutableSet) m).BasisSet; - } - return new ImmutableSet(m.Union(setOne)); - } + /// + /// Performs a "union" of the two sets, where all the elements + /// in both sets are present. + /// + /// A collection of elements. + /// + /// A new containing the union of + /// this with the specified + /// collection. Neither of the input objects is modified by the union. + /// + /// + public override sealed ISet Union(ISet setOne) + { + ISet m = this; + while (m is ImmutableSet) + { + m = ((ImmutableSet) m).BasisSet; + } - /// - /// Performs an "intersection" of the two sets, where only the elements - /// that are present in both sets remain. - /// - /// A set of elements. - /// - /// The intersection of this set with . - /// - /// - public override sealed ISet Intersect(ISet setOne) - { - ISet m = this; - while (m is ImmutableSet) - { - m = ((ImmutableSet) m).BasisSet; - } - return new ImmutableSet(m.Intersect(setOne)); - } + return new ImmutableSet(m.Union(setOne)); + } - /// - /// Performs a "minus" of this set from the - /// set. - /// - /// A set of elements. - /// - /// A set containing the elements from this set with the elements in - /// removed. - /// - /// - public override sealed ISet Minus(ISet setOne) - { - ISet m = this; - while (m is ImmutableSet) - { - m = ((ImmutableSet) m).BasisSet; - } - return new ImmutableSet(m.Minus(setOne)); - } + /// + /// Performs an "intersection" of the two sets, where only the elements + /// that are present in both sets remain. + /// + /// A set of elements. + /// + /// The intersection of this set with . + /// + /// + public override sealed ISet Intersect(ISet setOne) + { + ISet m = this; + while (m is ImmutableSet) + { + m = ((ImmutableSet) m).BasisSet; + } - /// - /// Performs an "exclusive-or" of the two sets, keeping only those - /// elements that are in one of the sets, but not in both. - /// - /// A set of elements. - /// - /// A set containing the result of - /// ^ this. - /// - /// - public override sealed ISet ExclusiveOr(ISet setOne) - { - ISet m = this; - while (m is ImmutableSet) - { - m = ((ImmutableSet) m).BasisSet; - } - return new ImmutableSet(m.ExclusiveOr(setOne)); - } - } + return new ImmutableSet(m.Intersect(setOne)); + } + + /// + /// Performs a "minus" of this set from the + /// set. + /// + /// A set of elements. + /// + /// A set containing the elements from this set with the elements in + /// removed. + /// + /// + public override sealed ISet Minus(ISet setOne) + { + ISet m = this; + while (m is ImmutableSet) + { + m = ((ImmutableSet) m).BasisSet; + } + + return new ImmutableSet(m.Minus(setOne)); + } + + /// + /// Performs an "exclusive-or" of the two sets, keeping only those + /// elements that are in one of the sets, but not in both. + /// + /// A set of elements. + /// + /// A set containing the result of + /// ^ this. + /// + /// + public override sealed ISet ExclusiveOr(ISet setOne) + { + ISet m = this; + while (m is ImmutableSet) + { + m = ((ImmutableSet) m).BasisSet; + } + + return new ImmutableSet(m.ExclusiveOr(setOne)); + } } diff --git a/src/Spring/Spring.Core/Collections/LinkedList.cs b/src/Spring/Spring.Core/Collections/LinkedList.cs index 0d7e0a8a..f1a039a0 100644 --- a/src/Spring/Spring.Core/Collections/LinkedList.cs +++ b/src/Spring/Spring.Core/Collections/LinkedList.cs @@ -20,520 +20,525 @@ using System.Collections; -namespace Spring.Collections +namespace Spring.Collections; + +/// +/// Simple linked list implementation. +/// +/// Simon White +[Serializable] +public class LinkedList : IList { - /// - /// Simple linked list implementation. - /// - /// Simon White + private int _nodeIndex; + private Node _rootNode; + private int _modId; + + #region Constructors + + /// + /// Creates a new instance of the + /// class. + /// + public LinkedList() + { + _rootNode = new Node(null, null, null); + _rootNode.PreviousNode = _rootNode; + _rootNode.NextNode = _rootNode; + } + + /// + /// Creates a new instance of the + /// class that contains all + /// elements of the specified list. + /// + /// + /// A list of elements that defines the initial contents. + /// + public LinkedList(IList list) : this() + { + AddAll(list); + } + + #endregion + + #region IList Members + + /// + /// Is list read only? + /// + /// + /// if the list is read only. + /// + public bool IsReadOnly + { + get { return false; } + } + + /// + /// Returns the node at the specified index. + /// + /// + ///

+ /// This is the indexer for the + /// class. + ///

+ ///
+ /// + public object this[int index] + { + get { return GetNode(index).Value; } + set { GetNode(index).Value = value; } + } + + /// + /// Removes the object at the specified index. + /// + /// The lookup index. + /// + /// If the specified is greater than the + /// number of objects within the list. + /// + public void RemoveAt(int index) + { + CheckUpdateState(); + RemoveNode(GetNode(index)); + } + + /// + /// Inserts an object at the specified index. + /// + /// The lookup index. + /// The object to be inserted. + /// + /// If the specified is greater than the + /// number of objects within the list. + /// + public void Insert(int index, object value) + { + CheckUpdateState(); + + Node node = null; + if (index == _nodeIndex) + { + node = new Node(value, _rootNode.PreviousNode, _rootNode); + } + else + { + Node insert = GetNode(index); + node = new Node(value, insert.PreviousNode, insert); + } + + node.PreviousNode.NextNode = node; + node.NextNode.PreviousNode = node; + _nodeIndex++; + _modId++; + } + + /// + /// Removes the first instance of the specified object found. + /// + /// The object to remove + public void Remove(object value) + { + CheckUpdateState(); + NodeHolder nh = GetNode(value); + RemoveNode(nh.Node); + } + + /// + /// Returns if this list contains the specified + /// element. + /// + /// The element to look for. + /// + /// if this list contains the specified element. + /// + public bool Contains(object value) + { + return GetNode(value) != null; + } + + /// + /// Removes all objects from the list. + /// + public void Clear() + { + _rootNode = new Node(null, null, null); + _nodeIndex = 0; + _modId++; + } + + /// + /// Returns the index of the first instance of the specified + /// found. + /// + /// The object to search for + /// + /// The index of the first instance found, or -1 if the element was not + /// found. + /// + public int IndexOf(object value) + { + NodeHolder nh = GetNode(value); + if (nh == null) + { + return -1; + } + + return nh.Index; + } + + /// + /// Adds the specified object to the end of the list. + /// + /// The object to add + /// The index that the object was added at. + public int Add(object value) + { + Insert(_nodeIndex, value); + return _nodeIndex - 1; + } + + /// + /// Adds all of the elements of the supplied + /// list to the end of this list. + /// + /// The list of objects to add. + public void AddAll(IList elements) + { + foreach (object obj in elements) + { + Add(obj); + } + } + + /// + /// Is the list a fixed size? + /// + /// + /// if the list is a fixed size list. + /// + public bool IsFixedSize + { + get { return false; } + } + + #endregion + + #region Private Methods + + /// + /// Checks whether the list can be modified. + /// + /// + /// If the list cannot be modified. + /// + private void CheckUpdateState() + { + if (IsReadOnly || IsFixedSize) + { + throw new NotSupportedException("LinkedList cannot be modified."); + } + } + + /// + /// Validates the specified index. + /// + /// The lookup index. + /// + /// If the index is invalid. + /// + private void ValidateIndex(int index) + { + if (index < 0 || index >= _nodeIndex) + { + throw new ArgumentOutOfRangeException("index"); + } + } + + /// + /// Returns the node at the specified index. + /// + /// The lookup index. + /// The node at the specified index. + /// + /// If the specified is greater than the + /// number of objects within the list. + /// + private Node GetNode(int index) + { + ValidateIndex(index); + Node node = _rootNode; + for (int i = 0; i <= index; i++) + { + node = node.NextNode; + } + + return node; + } + + /// + /// Returns the node (and index) of the first node that contains + /// the specified value. + /// + /// The value to search for. + /// + /// The node, or if not found. + /// + private NodeHolder GetNode(object value) + { + int i = 0; + if (value == null) + { + for (Node n = _rootNode.NextNode; n != _rootNode; n = n.NextNode) + { + if (n.Value == null) + { + return new NodeHolder(n, i); + } + + i++; + } + } + else + { + for (Node n = _rootNode.NextNode; n != _rootNode; n = n.NextNode) + { + if (value.Equals(n.Value)) + { + return new NodeHolder(n, i); + } + + i++; + } + } + + return null; + } + + /// + /// Removes the specified node. + /// + /// The node to be removed. + private void RemoveNode(Node node) + { + Node previousNode = node.PreviousNode; + previousNode.NextNode = node.NextNode; + node.NextNode.PreviousNode = previousNode; + node.PreviousNode = null; + node.NextNode = null; + _nodeIndex--; + _modId++; + } + + #endregion + + #region ICollection Members + + /// + /// Returns if the list is synchronized across + /// threads. + /// + /// + /// + /// This implementation always returns . + /// + ///

+ /// Note that enumeration is inherently not thread-safe. Use the + /// to lock the object during enumeration. + ///

+ ///
+ public bool IsSynchronized + { + get { return false; } + } + + /// + /// The number of objects within the list. + /// + public int Count + { + get { return _nodeIndex; } + } + + /// + /// Copies the elements in this list to an array. + /// + /// + ///

+ /// The type of array needs to be compatible with the objects in this + /// list, obviously. + ///

+ ///
+ /// + /// An array that will be the target of the copy operation. + /// + /// + /// The zero-based index where copying will start. + /// + /// + /// If the supplied is . + /// + /// + /// If the supplied is less than zero + /// or is greater than the length of . + /// + /// + /// If the supplied is of insufficient size. + /// + public void CopyTo(Array array, int index) + { + if (array == null) + { + throw new ArgumentNullException("array"); + } + + if ((index < 0) || (index > array.Length)) + { + throw new ArgumentOutOfRangeException("index", String.Format("Index {0} is out of range.", index)); + } + + if ((array.Length - index) < this._nodeIndex) + { + throw new ArgumentException("Array is of insufficient size."); + } + + Node node = this._rootNode; + for (int i = 0, pos = index; i < this._nodeIndex; i++, pos++) + { + node = node.NextNode; + array.SetValue(node.Value, pos); + } + } + + /// + /// An object that can be used to synchronize this + /// to make it thread-safe. + /// + /// + /// An object that can be used to synchronize this + /// to make it thread-safe. + /// + public object SyncRoot + { + get { return this; } + } + + #endregion + + #region IEnumerable Members + + /// + /// Gets an enumerator for the elements in the + /// . + /// + /// + ///

+ /// Enumerators are fail fast. + ///

+ ///
+ /// + /// An over the elements + /// in the . + /// + public IEnumerator GetEnumerator() + { + return new LinkedListEnumerator(this); + } + + #endregion + + #region Inner Classes + [Serializable] - public class LinkedList : IList - { - private int _nodeIndex; - private Node _rootNode; - private int _modId; + private class Node + { + private object _value; + private Node _next; + private Node _previous; - #region Constructors + public object Value + { + get { return _value; } + set { _value = value; } + } - /// - /// Creates a new instance of the - /// class. - /// - public LinkedList() - { - _rootNode = new Node(null, null, null); - _rootNode.PreviousNode = _rootNode; - _rootNode.NextNode = _rootNode; - } + public Node NextNode + { + get { return _next; } + set { this._next = value; } + } - /// - /// Creates a new instance of the - /// class that contains all - /// elements of the specified list. - /// - /// - /// A list of elements that defines the initial contents. - /// - public LinkedList(IList list) : this() - { - AddAll(list); - } + public Node PreviousNode + { + get { return _previous; } + set { this._previous = value; } + } - #endregion + public Node(object val, Node previous, Node next) + { + this._value = val; + this._next = next; + this._previous = previous; + } + } - #region IList Members + private class NodeHolder + { + private int _index; + private Node _node; - /// - /// Is list read only? - /// - /// - /// if the list is read only. - /// - public bool IsReadOnly - { - get { return false; } - } + public int Index + { + get { return _index; } + } - /// - /// Returns the node at the specified index. - /// - /// - ///

- /// This is the indexer for the - /// class. - ///

- ///
- /// - public object this[int index] - { - get { return GetNode(index).Value; } - set { GetNode(index).Value = value; } - } + public Node Node + { + get { return _node; } + } - /// - /// Removes the object at the specified index. - /// - /// The lookup index. - /// - /// If the specified is greater than the - /// number of objects within the list. - /// - public void RemoveAt(int index) - { - CheckUpdateState(); - RemoveNode(GetNode(index)); - } + public NodeHolder(Node node, int index) + { + this._node = node; + this._index = index; + } + } - /// - /// Inserts an object at the specified index. - /// - /// The lookup index. - /// The object to be inserted. - /// - /// If the specified is greater than the - /// number of objects within the list. - /// - public void Insert(int index, object value) - { - CheckUpdateState(); + private class LinkedListEnumerator : IEnumerator + { + private LinkedList _ll; + private Node _current; + private int _modId; - Node node = null; - if (index == _nodeIndex) - { - node = new Node(value, _rootNode.PreviousNode, _rootNode); - } - else - { - Node insert = GetNode(index); - node = new Node(value, insert.PreviousNode, insert); - } - node.PreviousNode.NextNode = node; - node.NextNode.PreviousNode = node; - _nodeIndex++; - _modId++; - } + public object Current + { + get { return _current.Value; } + } - /// - /// Removes the first instance of the specified object found. - /// - /// The object to remove - public void Remove(object value) - { - CheckUpdateState(); - NodeHolder nh = GetNode(value); - RemoveNode(nh.Node); - } + public LinkedListEnumerator(LinkedList ll) + { + this._ll = ll; + this._modId = ll._modId; + this._current = _ll._rootNode; + } - /// - /// Returns if this list contains the specified - /// element. - /// - /// The element to look for. - /// - /// if this list contains the specified element. - /// - public bool Contains(object value) - { - return GetNode(value) != null; - } - - /// - /// Removes all objects from the list. - /// - public void Clear() - { - _rootNode = new Node(null, null, null); - _nodeIndex = 0; - _modId++; - } - - /// - /// Returns the index of the first instance of the specified - /// found. - /// - /// The object to search for - /// - /// The index of the first instance found, or -1 if the element was not - /// found. - /// - public int IndexOf(object value) - { - NodeHolder nh = GetNode(value); - if (nh == null) - { - return -1; - } - return nh.Index; - } - - /// - /// Adds the specified object to the end of the list. - /// - /// The object to add - /// The index that the object was added at. - public int Add(object value) - { - Insert(_nodeIndex, value); - return _nodeIndex - 1; - } - - /// - /// Adds all of the elements of the supplied - /// list to the end of this list. - /// - /// The list of objects to add. - public void AddAll(IList elements) - { - foreach (object obj in elements) - { - Add(obj); - } - } - - /// - /// Is the list a fixed size? - /// - /// - /// if the list is a fixed size list. - /// - public bool IsFixedSize - { - get { return false; } - } - - #endregion - - #region Private Methods - - /// - /// Checks whether the list can be modified. - /// - /// - /// If the list cannot be modified. - /// - private void CheckUpdateState() - { - if (IsReadOnly || IsFixedSize) - { - throw new NotSupportedException("LinkedList cannot be modified."); - } - } - - /// - /// Validates the specified index. - /// - /// The lookup index. - /// - /// If the index is invalid. - /// - private void ValidateIndex(int index) - { - if (index < 0 || index >= _nodeIndex) - { - throw new ArgumentOutOfRangeException("index"); - } - } - - /// - /// Returns the node at the specified index. - /// - /// The lookup index. - /// The node at the specified index. - /// - /// If the specified is greater than the - /// number of objects within the list. - /// - private Node GetNode(int index) - { - ValidateIndex(index); - Node node = _rootNode; - for (int i = 0; i <= index; i++) - { - node = node.NextNode; - } - return node; - } - - /// - /// Returns the node (and index) of the first node that contains - /// the specified value. - /// - /// The value to search for. - /// - /// The node, or if not found. - /// - private NodeHolder GetNode(object value) - { - int i = 0; - if (value == null) + public bool MoveNext() + { + if (this._modId != this._ll._modId) { - - for (Node n = _rootNode.NextNode; n != _rootNode; n = n.NextNode) - { - if (n.Value == null) - { - return new NodeHolder(n, i); - } - i++; - } + throw new InvalidOperationException("LinkedList has been modified."); } - else - { - for (Node n = _rootNode.NextNode; n != _rootNode; n = n.NextNode) - { - if (value.Equals(n.Value)) - { - return new NodeHolder(n, i); - } - i++; - } - } - return null; - } + _current = _current.NextNode; + return (_current == _ll._rootNode ? false : true); + } - /// - /// Removes the specified node. - /// - /// The node to be removed. - private void RemoveNode(Node node) - { - Node previousNode = node.PreviousNode; - previousNode.NextNode = node.NextNode; - node.NextNode.PreviousNode = previousNode; - node.PreviousNode = null; - node.NextNode = null; - _nodeIndex--; - _modId++; - } + public void Reset() + { + _current = _ll._rootNode; + } + } - #endregion - - #region ICollection Members - - /// - /// Returns if the list is synchronized across - /// threads. - /// - /// - /// - /// This implementation always returns . - /// - ///

- /// Note that enumeration is inherently not thread-safe. Use the - /// to lock the object during enumeration. - ///

- ///
- public bool IsSynchronized - { - get { return false; } - } - - /// - /// The number of objects within the list. - /// - public int Count - { - get { return _nodeIndex; } - } - - /// - /// Copies the elements in this list to an array. - /// - /// - ///

- /// The type of array needs to be compatible with the objects in this - /// list, obviously. - ///

- ///
- /// - /// An array that will be the target of the copy operation. - /// - /// - /// The zero-based index where copying will start. - /// - /// - /// If the supplied is . - /// - /// - /// If the supplied is less than zero - /// or is greater than the length of . - /// - /// - /// If the supplied is of insufficient size. - /// - public void CopyTo(Array array, int index) - { - if (array == null) - { - throw new ArgumentNullException("array"); - } - if ((index < 0) || (index > array.Length)) - { - throw new ArgumentOutOfRangeException("index", String.Format("Index {0} is out of range.", index)); - } - if ((array.Length - index) < this._nodeIndex) - { - throw new ArgumentException("Array is of insufficient size."); - } - - Node node = this._rootNode; - for (int i = 0, pos = index; i < this._nodeIndex; i++, pos++) - { - node = node.NextNode; - array.SetValue(node.Value, pos); - } - } - - /// - /// An object that can be used to synchronize this - /// to make it thread-safe. - /// - /// - /// An object that can be used to synchronize this - /// to make it thread-safe. - /// - public object SyncRoot - { - get { return this; } - } - - #endregion - - #region IEnumerable Members - - /// - /// Gets an enumerator for the elements in the - /// . - /// - /// - ///

- /// Enumerators are fail fast. - ///

- ///
- /// - /// An over the elements - /// in the . - /// - public IEnumerator GetEnumerator() - { - return new LinkedListEnumerator(this); - } - - #endregion - - #region Inner Classes - - [Serializable] - private class Node - { - private object _value; - private Node _next; - private Node _previous; - - public object Value - { - get { return _value; } - set { _value = value; } - } - - public Node NextNode - { - get { return _next; } - set { this._next = value; } - } - - public Node PreviousNode - { - get { return _previous; } - set { this._previous = value; } - } - - public Node(object val, Node previous, Node next) - { - this._value = val; - this._next = next; - this._previous = previous; - } - } - - private class NodeHolder - { - private int _index; - private Node _node; - - public int Index - { - get { return _index; } - } - - public Node Node - { - get { return _node; } - } - - public NodeHolder(Node node, int index) - { - this._node = node; - this._index = index; - } - } - - private class LinkedListEnumerator : IEnumerator - { - private LinkedList _ll; - private Node _current; - private int _modId; - - public object Current - { - get { return _current.Value; } - } - - public LinkedListEnumerator(LinkedList ll) - { - this._ll = ll; - this._modId = ll._modId; - this._current = _ll._rootNode; - } - - public bool MoveNext() - { - if (this._modId != this._ll._modId) - { - throw new InvalidOperationException("LinkedList has been modified."); - } - - _current = _current.NextNode; - return (_current == _ll._rootNode ? false : true); - } - - public void Reset() - { - _current = _ll._rootNode; - } - } - - #endregion - } + #endregion } diff --git a/src/Spring/Spring.Core/Collections/ListSet.cs b/src/Spring/Spring.Core/Collections/ListSet.cs index 760a0d91..e695e9cf 100644 --- a/src/Spring/Spring.Core/Collections/ListSet.cs +++ b/src/Spring/Spring.Core/Collections/ListSet.cs @@ -23,43 +23,42 @@ using System.Collections; using System.Collections.Specialized; -namespace Spring.Collections -{ - /// - /// Implements a based on a list. - /// - /// - ///

- /// Performance is much better for very small lists than either - /// or . - /// However, performance degrades rapidly as the data-set gets bigger. Use a - /// instead if you are not sure your data-set - /// will always remain very small. Iteration produces elements in the order they were added. - /// However, element order is not guaranteed to be maintained by the various - /// mathematical operators. - ///

- ///
- [Serializable] - public class ListSet : DictionarySet - { - /// - /// Creates a new set instance based on a list. - /// - public ListSet() - { - InternalDictionary = new ListDictionary(); - } +namespace Spring.Collections; - /// - /// Creates a new set instance based on a list and initializes it based on a - /// collection of elements. - /// - /// - /// A collection of elements that defines the initial set contents. - /// - public ListSet(ICollection initialValues) : this() - { - this.AddAll(initialValues); - } - } -} +/// +/// Implements a based on a list. +/// +/// +///

+/// Performance is much better for very small lists than either +/// or . +/// However, performance degrades rapidly as the data-set gets bigger. Use a +/// instead if you are not sure your data-set +/// will always remain very small. Iteration produces elements in the order they were added. +/// However, element order is not guaranteed to be maintained by the various +/// mathematical operators. +///

+///
+[Serializable] +public class ListSet : DictionarySet +{ + /// + /// Creates a new set instance based on a list. + /// + public ListSet() + { + InternalDictionary = new ListDictionary(); + } + + /// + /// Creates a new set instance based on a list and initializes it based on a + /// collection of elements. + /// + /// + /// A collection of elements that defines the initial set contents. + /// + public ListSet(ICollection initialValues) : this() + { + this.AddAll(initialValues); + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Collections/NoElementsException.cs b/src/Spring/Spring.Core/Collections/NoElementsException.cs index 27a2890c..383b1633 100644 --- a/src/Spring/Spring.Core/Collections/NoElementsException.cs +++ b/src/Spring/Spring.Core/Collections/NoElementsException.cs @@ -20,66 +20,65 @@ using System.Runtime.Serialization; -namespace Spring.Collections +namespace Spring.Collections; + +/// +/// Thrown when an element is requested from an empty . +/// +/// Griffin Caprio +[Serializable] +public class NoElementsException : ApplicationException { - /// - /// Thrown when an element is requested from an empty . - /// - /// Griffin Caprio - [Serializable] - public class NoElementsException : ApplicationException - { - /// - /// Creates a new instance of the - /// class. - /// - public NoElementsException() - { - } + /// + /// Creates a new instance of the + /// class. + /// + public NoElementsException() + { + } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The - /// that holds the serialized object data about the exception being thrown. - /// - /// - /// The - /// that contains contextual information about the source or destination. - /// - protected NoElementsException(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } + /// + /// Creates a new instance of the + /// class. + /// + /// + /// The + /// that holds the serialized object data about the exception being thrown. + /// + /// + /// The + /// that contains contextual information about the source or destination. + /// + protected NoElementsException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } - /// - /// Creates a new instance of the - /// class with the - /// specified message. - /// - /// - /// A message about the exception. - /// - public NoElementsException(string message) : base(message) - { - } + /// + /// Creates a new instance of the + /// class with the + /// specified message. + /// + /// + /// A message about the exception. + /// + public NoElementsException(string message) : base(message) + { + } - /// - /// Creates a new instance of the - /// class with the - /// specified message. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception that is being wrapped. - /// - public NoElementsException(string message, Exception rootCause) - : base(message, rootCause) - { - } - } + /// + /// Creates a new instance of the + /// class with the + /// specified message. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception that is being wrapped. + /// + public NoElementsException(string message, Exception rootCause) + : base(message, rootCause) + { + } } diff --git a/src/Spring/Spring.Core/Collections/PriorityQueue.cs b/src/Spring/Spring.Core/Collections/PriorityQueue.cs index e3218c25..7dd869fa 100644 --- a/src/Spring/Spring.Core/Collections/PriorityQueue.cs +++ b/src/Spring/Spring.Core/Collections/PriorityQueue.cs @@ -23,810 +23,820 @@ using System.Diagnostics; using System.Reflection; using System.Runtime.Serialization; -namespace Spring.Collections +namespace Spring.Collections; + +/// +/// An unbounded priority based on a priority +/// heap. This queue orders elements according to an order specified +/// at construction time, which is specified either according to their +/// natural order (see , or according to a +/// , depending on which constructor is +/// used. A priority queue does not permit elements. +/// A priority queue relying on natural ordering also does not +/// permit insertion of non-comparable objects (doing so will result +/// . +/// +///

+/// The head of this queue is the lowest element +/// with respect to the specified ordering. If multiple elements are +/// tied for lowest value, the head is one of those elements -- ties are +/// broken arbitrarily. +/// +///

+/// A priority queue is unbounded, but has an internal +/// capacity governing the size of an array used to store the +/// elements on the queue. It is always at least as large as the queue +/// size. As elements are added to a priority queue, its capacity +/// grows automatically. The details of the growth policy are not +/// specified. +/// +///

+/// This class and its enumerator implement all of the +/// optional methods of the and +/// interfaces. +/// The enumerator provided in method +/// is not guaranteed to traverse the elements of the PriorityQueue in any +/// particular order. +/// +///

+/// Note that this implementation is NOT synchronized. +/// Multiple threads should not access a +/// instance concurrently if any of the threads modifies the list +/// structurally. Instead, use the thread-safe PriorityBlockingQueue. +///

+/// Josh Bloch +/// Griffin Caprio (.NET) +[Serializable] +public class PriorityQueue : AbstractQueue, ISerializable { - /// - /// An unbounded priority based on a priority - /// heap. This queue orders elements according to an order specified - /// at construction time, which is specified either according to their - /// natural order (see , or according to a - /// , depending on which constructor is - /// used. A priority queue does not permit elements. - /// A priority queue relying on natural ordering also does not - /// permit insertion of non-comparable objects (doing so will result - /// . - /// - ///

- /// The head of this queue is the lowest element - /// with respect to the specified ordering. If multiple elements are - /// tied for lowest value, the head is one of those elements -- ties are - /// broken arbitrarily. - /// - ///

- /// A priority queue is unbounded, but has an internal - /// capacity governing the size of an array used to store the - /// elements on the queue. It is always at least as large as the queue - /// size. As elements are added to a priority queue, its capacity - /// grows automatically. The details of the growth policy are not - /// specified. - /// - ///

- /// This class and its enumerator implement all of the - /// optional methods of the and - /// interfaces. - /// The enumerator provided in method - /// is not guaranteed to traverse the elements of the PriorityQueue in any - /// particular order. - /// - ///

- /// Note that this implementation is NOT synchronized. - /// Multiple threads should not access a - /// instance concurrently if any of the threads modifies the list - /// structurally. Instead, use the thread-safe PriorityBlockingQueue. - ///

- /// Josh Bloch - /// Griffin Caprio (.NET) - [Serializable] - public class PriorityQueue : AbstractQueue, ISerializable - { - private class PriorityQueueEnumerator : IEnumerator - { - private PriorityQueue _enclosingInstance; - - public PriorityQueueEnumerator(PriorityQueue enclosingInstance) - { - _enclosingInstance = enclosingInstance; - } - - public Object Current - { - get - { - Object result = null; - if (_cursorIndex <= _enclosingInstance._priorityQueueSize) - { - result = _enclosingInstance._queue[_cursorIndex]; - } - return result; - } - - } - - /// - /// Index (into queue array) of element to be returned by subsequent call to next. - /// - private int _cursorIndex = 0; - - public bool MoveNext() - { - if ( _cursorIndex < _enclosingInstance._priorityQueueSize ) - { - _cursorIndex++; - return true; - } - return false; - } - - public void Reset() - { - _cursorIndex = 0; - } - } - - - #region Private Fields - - private const int DEFAULT_INITIAL_CAPACITY = 11; - - /// - /// Priority queue represented as a balanced binary heap: the two children - /// of queue[n] are queue[2*n] and queue[2*n + 1]. The priority queue is - /// ordered by comparator, or by the elements' natural ordering, if - /// comparator is null: For each node n in the heap and each descendant d - /// of n, n <= d. - /// - /// The element with the lowest value is in queue[1], assuming the queue is - /// nonempty. (A one-based array is used in preference to the traditional - /// zero-based array to simplify parent and child calculations.) - /// - /// queue.length must be >= 2, even if size == 0. - /// - [NonSerialized] private object[] _queue; - - /// The number of elements in the priority queue. - private int _priorityQueueSize = 0; - - /// - /// The comparator, or null if priority queue uses elements' - /// natural ordering. - /// - private IComparer _comparator; - - /// - /// The number of times this priority queue has been - /// structurally modified. - /// - [NonSerialized] private int _queueModificationCount = 0; - - #endregion - - #region Constructors - - /// - /// Creates a with the default initial capacity - /// (11) that orders its elements according to their natural - /// ordering (using ). - /// - public PriorityQueue() : this(DEFAULT_INITIAL_CAPACITY, null) - { - } - - /// - /// Creates a with the specified initial capacity - /// that orders its elements according to their natural ordering - /// (using ). - /// - /// the initial capacity for this priority queue. - /// - /// if is less than 1. - public PriorityQueue(int initialCapacity) : this(initialCapacity, null) - { - } - - /// - /// Creates a with the specified initial capacity - /// that orders its elements according to the specified comparator. - /// - /// the initial capacity for this priority queue. - /// the comparator used to order this priority queue. - /// If then the order depends on the elements' natural ordering. - /// - /// if is less than 1. - public PriorityQueue(int initialCapacity, IComparer comparator) - { - if (initialCapacity < 1) - throw new ArgumentException("initialCapacity"); - _queue = new object[initialCapacity + 1]; - _comparator = comparator; - } - - /// - /// Creates a containing the elements in the - /// specified collection. The priority queue has an initial - /// capacity of 110% of the size of the specified collection or 1 - /// if the collection is empty. If the specified collection is an - /// instance of a , the priority queue will be sorted - /// according to the same comparator, or according to its elements' - /// natural order if the collection is sorted according to its - /// elements' natural order. Otherwise, the priority queue is - /// ordered according to its elements' natural order. - /// - /// the collection whose elements are to be placed into this priority queue. - /// if elements of cannot be - /// compared to one another according to the priority queue's ordering - /// if or any element with it is - /// - /// - public PriorityQueue(ICollection collection) - { - if ( null == collection ) - throw new ArgumentNullException("collection"); - initializeArray(collection); - if (collection is PriorityQueue) - { - PriorityQueue s = (PriorityQueue) collection; - _comparator = s.Comparator(); - fillFromSorted(s); - } - else - { - _comparator = null; - fillFromUnsorted(collection); - } - } - - #endregion - - #region Private Helper Methods - - /// - /// Common code to initialize underlying queue array across - /// constructors below. - /// - private void initializeArray(ICollection c) - { - int size = c.Count; - int initialCapacity = getQueueSizeBasedOnPercentage(size, 110); - if (initialCapacity < 1) - initialCapacity = 1; - - _queue = new Object[initialCapacity + 1]; - } - - /// - /// Performs an unsigned bitwise right shift with the specified number - /// - /// Number to operate on - /// Amount of bits to shift - /// The resulting number from the shift operation - private int urShift(int number, int bits) - { - if (number >= 0) - return number >> bits; - else - return (number >> bits) + (2 << ~bits); - } - - /// - /// Establishes the heap invariant assuming the heap - /// satisfies the invariant except possibly for the leaf-node indexed by k - /// (which may have a nextExecutionTime less than its parent's). - /// - /// - /// This method functions by "promoting" queue[k] up the hierarchy - /// (by swapping it with its parent) repeatedly until queue[k] - /// is greater than or equal to its parent. - /// - private void fixUp(int k) - { - if (_comparator == null) - { - while (k > 1) - { - int j = k >> 1; - if (((IComparable) _queue[j]).CompareTo(_queue[k]) <= 0) - break; - Object tmp = _queue[j]; - _queue[j] = _queue[k]; - _queue[k] = tmp; - k = j; - } - } - else - { - while (k > 1) - { - int j = urShift(k, 1); - if (_comparator.Compare(_queue[j], _queue[k]) <= 0) - break; - Object tmp = _queue[j]; - _queue[j] = _queue[k]; - _queue[k] = tmp; - k = j; - } - } - } - - /// - /// Establishes the heap invariant (described above) in the subtree - /// rooted at k, which is assumed to satisfy the heap invariant except - /// possibly for node k itself (which may be greater than its children). - /// - /// - /// This method functions by "demoting" queue[k] down the hierarchy - /// (by swapping it with its smaller child) repeatedly until queue[k] - /// is less than or equal to its children. - /// - private void fixDown(int k) - { - int j; - if (_comparator == null) - { - while ((j = k << 1) <= _priorityQueueSize && (j > 0)) - { - if (j < _priorityQueueSize && ((IComparable) _queue[j]).CompareTo(_queue[j + 1]) > 0) - j++; // j indexes smallest kid - - if (((IComparable) _queue[k]).CompareTo(_queue[j]) <= 0) - break; - Object tmp = _queue[j]; - _queue[j] = _queue[k]; - _queue[k] = tmp; - k = j; - } - } - else - { - while ((j = k << 1) <= _priorityQueueSize && (j > 0)) - { - if (j < _priorityQueueSize && _comparator.Compare(_queue[j], _queue[j + 1]) > 0) - j++; // j indexes smallest kid - if (_comparator.Compare(_queue[k], _queue[j]) <= 0) - break; - Object tmp = _queue[j]; - _queue[j] = _queue[k]; - _queue[k] = tmp; - k = j; - } - } - } - - /// - /// Establishes the heap invariant in the entire tree, - /// assuming nothing about the order of the elements prior to the call. - /// - private void heapify() - { - for (int i = _priorityQueueSize/2; i >= 1; i--) - fixDown(i); - } - - /// - /// Returns the of or - 1, - /// whichever is smaller. - /// - /// base size - /// percentage to return - /// of - private int getQueueSizeBasedOnPercentage(int size, long percentage) - { - return (int) Math.Min((size*percentage)/100, Int32.MaxValue - 1); - } - - /// - /// Initially fill elements of the queue array under the - /// knowledge that it is sorted or is another , in which - /// case we can just place the elements in the order presented. - /// - private void fillFromSorted(ICollection collection) - { - fillArray(collection, true); - } - - private void fillArray(ICollection collection, bool sorted) - { - foreach (object currentObject in collection) - { - if (null == currentObject ) - throw new ArgumentNullException("collection", "Cannot add null elements to queue."); - _queue[++_priorityQueueSize] = currentObject; - } - if (! sorted) - { - heapify(); - } - } - - /// - /// Initially fill elements of the queue array that is not to our knowledge - /// sorted, so we must rearrange the elements to guarantee the heap - /// invariant. - /// - private void fillFromUnsorted(ICollection collection) - { - fillArray(collection, false); - } - - /// - /// Removes and returns element located at from queue. (Recall that the queue - /// is one-based, so 1 <= i <= size.) - /// - /// - /// Normally this method leaves the elements at positions from 1 up to i-1, - /// inclusive, untouched. Under these circumstances, it returns . - /// Occasionally, in order to maintain the heap invariant, it must move - /// the last element of the list to some index in the range [2, i-1], - /// and move the element previously at position (i/2) to position i. - /// Under these circumstances, this method returns the element that was - /// previously at the end of the list and is now at some position between - /// 2 and i-1 inclusive. - /// - private Object removeAt(int index) - { - Debug.Assert(index > 0 && index <= _priorityQueueSize); - _queueModificationCount++; - - Object moved = _queue[_priorityQueueSize]; - _queue[index] = moved; - _queue[_priorityQueueSize--] = null; - if (index <= _priorityQueueSize) - { - fixDown(index); - if (_queue[index] == moved) - { - fixUp(index); - if (_queue[index] != moved) - return moved; - } - } - return null; - } - - /// Resize array, if necessary, to be able to hold given index - private void grow(int index) - { - int newLength = _queue.Length; - if (index < newLength) - return; - if (index == Int32.MaxValue) - throw new InvalidOperationException("Cannot grow queue to accomdate index " + index + ". Doing so would result in a memory overflow."); - while (newLength <= index) - { - if (newLength >= Int32.MaxValue/2) - { - newLength = Int32.MaxValue; - } - else - { - newLength <<= 2; - } - } - Object[] newQueue = new Object[newLength]; - Array.Copy(_queue, 0, newQueue, 0, _queue.Length); - _queue = newQueue; - } - - #endregion - - #region Public Methods - /// - /// Gets the Capacity of this queue. Will equal - /// - public override int Capacity - { - get - { - return _queue.Length; - } - } - - /// - /// Returns the queue count. - /// - public override int Count - { - get { return _priorityQueueSize; } - } - - /// - /// Inserts the specified element into this queue if it is possible to do - /// so immediately without violating capacity restrictions. - /// - /// - ///

- /// When using a capacity-restricted queue, this method is generally - /// preferable to , - /// which can fail to insert an element only by throwing an exception. - ///

- ///
- /// - /// The element to add. - /// - /// - /// if the element was added to this queue. - /// - /// - /// if the specified element cannot be compared - /// with elements currently in the priority queue according - /// to the priority queue's ordering. - /// - /// - /// If the element cannot be added at this time due to capacity restrictions. - /// - /// - /// If the supplied is - /// and this queue does not permit - /// elements. - /// - /// - /// If some property of the supplied prevents - /// it from being added to this queue. - /// - public override bool Offer(Object objectToAdd) - { - if (objectToAdd == null) - throw new ArgumentNullException("objectToAdd"); - _queueModificationCount++; - ++_priorityQueueSize; - - if (_priorityQueueSize >= _queue.Length) - { - grow(_priorityQueueSize); - } - _queue[_priorityQueueSize] = objectToAdd; - fixUp(_priorityQueueSize); - return true; - } - - /// - /// Retrieves, but does not remove, the head of this queue, - /// or returns if this queue is empty. - /// - /// - /// The head of this queue, or if this queue is empty. - /// - public override Object Peek() - { - if (_priorityQueueSize == 0) - return null; - return _queue[1]; - } - - // Collection Methods - the first two override to update docs - /// - /// Inserts the specified element into this queue if it is possible to do so - /// immediately without violating capacity restrictions, returning - /// upon success and throwing an - /// if no space is - /// currently available. - /// - /// - /// The element to add. - /// - /// - /// if successful. - /// - /// - /// If the element cannot be added at this time due to capacity restrictions. - /// - /// - /// If the specified element is and this queue does not - /// permit elements. - /// - /// - /// If some property of the supplied prevents - /// it from being added to this queue. - /// - /// - /// if the specified element cannot be compared - /// with elements currently in the priority queue according - /// to the priority queue's ordering. - /// - public override bool Add(Object objectToAdd) - { - return Offer(objectToAdd); - } - - /// - /// Removes a single instance of the specified element from this - /// queue, if it is present. - /// - public virtual bool Remove(Object objectToRemove) - { - if (objectToRemove == null) - { - return false; - } - - if (_comparator == null) - { - for (int i = 1; i <= _priorityQueueSize; i++) - { - if (((IComparable) _queue[i]).CompareTo(objectToRemove) == 0) - { - removeAt(i); - return true; - } - } - } - else - { - for (int i = 1; i <= _priorityQueueSize; i++) - { - if (_comparator.Compare(_queue[i], objectToRemove) == 0) - { - removeAt(i); - return true; - } - } - } - return false; - } - - /// - /// Returns an over the elements in this queue. - /// The enumerator does not return the elements in any particular order. - /// - /// an enumerator over the elements in this queue. - public override IEnumerator GetEnumerator() - { - return new PriorityQueueEnumerator(this); - } - - - /// - /// Removes all elements from the priority queue. - /// The queue will be empty after this call returns. - /// - public override void Clear() - { - _queueModificationCount++; - - for (int i = 1; i <= _priorityQueueSize; i++) - _queue[i] = null; - - _priorityQueueSize = 0; - } - - /// - /// Retrieves and removes the head of this queue, - /// or returns if this queue is empty. - /// - /// - /// The head of this queue, or if this queue is empty. - /// - public override Object Poll() - { - if (_priorityQueueSize == 0) - return null; - _queueModificationCount++; - - Object result = _queue[1]; - _queue[1] = _queue[_priorityQueueSize]; - _queue[_priorityQueueSize--] = null; - if (_priorityQueueSize > 1) - fixDown(1); - return result; - } - /// - /// Queries the queue to see if it contains the specified - /// - /// element to look for. - /// if the queue contains the , - /// otherwise. - public bool Contains( object element ) - { - if (element == null) - { - for (int num1 = 0; num1 < Capacity; num1++) - { - if (_queue[num1] == null) - { - return true; - } - } - return false; - } - for (int num2 = 0; num2 < Capacity; num2++) - { - if (element.Equals(_queue[num2])) - { - return true; - } - } - return false; - } - - - /// Returns the comparator used to order this collection, or - /// if this collection is sorted according to its elements natural ordering - /// (using ). - /// - /// - /// the comparator used to order this collection, or - /// if this collection is sorted according to its elements natural ordering. - /// - public virtual IComparer Comparator() - { - return _comparator; - } - #endregion - - #region ISerializable Implementation - /// - /// Save the state of the instance to a stream (that - /// is, serialize it). - /// - /// The length of the array backing the instance is - /// emitted (int), followed by all of its elements (each an - /// ) in the proper order. - /// - /// the stream - /// the context - public virtual void GetObjectData(SerializationInfo serializationInfo, StreamingContext context) - { - Type thisType = this.GetType(); - MemberInfo[] mi = FormatterServices.GetSerializableMembers(thisType, context); - for (int i = 0; i < mi.Length; i++) - { - serializationInfo.AddValue(mi[i].Name, ((FieldInfo) mi[i]).GetValue(this)); - } - - // Write out array length - serializationInfo.AddValue("Spring.Collections.PriorityQueuedata1", _queue.Length); - - // Write out all elements in the proper order. - for (int i = 1; i <= _priorityQueueSize; i++) - { - serializationInfo.AddValue("Spring.Collections.PriorityQueueData" + i, _queue[i]); - } - } - - /// - /// Reconstitute the instance from a stream (that is, - /// deserialize it). - /// - /// the stream - /// the context - protected PriorityQueue(SerializationInfo serializationInfo, StreamingContext context) - { - Type thisType = this.GetType(); - MemberInfo[] mi = FormatterServices.GetSerializableMembers(thisType, context); - for (int i = 0; i < mi.Length; i++) - { - FieldInfo fi = (FieldInfo) mi[i]; - fi.SetValue(this, serializationInfo.GetValue(fi.Name, fi.FieldType)); - } - int arrayLength = serializationInfo.GetInt32("Spring.Collections.PriorityQueuedata1"); - _queue = new Object[arrayLength]; - - for (int i = 1; i <= _priorityQueueSize; i++) - { - _queue[i] = serializationInfo.GetValue("Spring.Collections.PriorityQueueData" + i, typeof (Object)); - } - } - #endregion - - #region ICollection Implementation - - /// - ///Copies the elements of the to an , starting at a particular index. - /// - ///The one-dimensional that is the destination of the elements copied from . The must have zero-based indexing. - ///The zero-based index in array at which copying begins. - ///array is null. - ///index is less than zero. - ///array is multidimensional.-or- index is equal to or greater than the length of array.-or- The number of elements in the source is greater than the available space from index to the end of the destination array. - ///The type of the source cannot be cast automatically to the type of the destination array. 2 - public override void CopyTo(Array array,Int32 index) - { - if ( _priorityQueueSize > array.Length ) throw new ArgumentException("Destination array too small.", "array"); - if ( index > array.Length - 1 ) throw new ArgumentException("Starting index outside bounds of target array.", "index"); - if ( index + _priorityQueueSize > array.Length ) throw new IndexOutOfRangeException("Destination array not long enough to begin copying at index " + index + "."); - - for ( int queueElementCount = 1; queueElementCount <= _priorityQueueSize; queueElementCount++) - { - array.SetValue(_queue[queueElementCount], index ); - index++; - } - Array.Sort(array); - } - - /// - ///Copies the elements of the to an , starting at index 0. - /// - ///The one-dimensional that is the destination of the elements copied from . The must have zero-based indexing. - ///array is null. - ///index is less than zero. - ///array is multidimensional.-or- index is equal to or greater than the length of array.-or- The number of elements in the source is greater than the available space from index to the end of the destination array. - ///The type of the source cannot be cast automatically to the type of the destination array. 2 - public void CopyTo(Array array) - { - CopyTo(array, 0); - } - - /// - ///Gets an object that can be used to synchronize access to the . - /// - /// - ///An object that can be used to synchronize access to the . - /// - public override Object SyncRoot - { - get { return null; } - - } - - /// - ///Gets a value indicating whether access to the is synchronized (thread safe). - /// - /// - ///true if access to the is synchronized (thread safe); otherwise, false. - /// - public override Boolean IsSynchronized - { - get { return false; } - - } - - /// - /// Returns if there are no elements in the , otherwise. - /// - public override bool IsEmpty - { - get { return _priorityQueueSize == 0; } - } - - #endregion - } + private class PriorityQueueEnumerator : IEnumerator + { + private PriorityQueue _enclosingInstance; + + public PriorityQueueEnumerator(PriorityQueue enclosingInstance) + { + _enclosingInstance = enclosingInstance; + } + + public Object Current + { + get + { + Object result = null; + if (_cursorIndex <= _enclosingInstance._priorityQueueSize) + { + result = _enclosingInstance._queue[_cursorIndex]; + } + + return result; + } + } + + /// + /// Index (into queue array) of element to be returned by subsequent call to next. + /// + private int _cursorIndex = 0; + + public bool MoveNext() + { + if (_cursorIndex < _enclosingInstance._priorityQueueSize) + { + _cursorIndex++; + return true; + } + + return false; + } + + public void Reset() + { + _cursorIndex = 0; + } + } + + #region Private Fields + + private const int DEFAULT_INITIAL_CAPACITY = 11; + + /// + /// Priority queue represented as a balanced binary heap: the two children + /// of queue[n] are queue[2*n] and queue[2*n + 1]. The priority queue is + /// ordered by comparator, or by the elements' natural ordering, if + /// comparator is null: For each node n in the heap and each descendant d + /// of n, n <= d. + /// + /// The element with the lowest value is in queue[1], assuming the queue is + /// nonempty. (A one-based array is used in preference to the traditional + /// zero-based array to simplify parent and child calculations.) + /// + /// queue.length must be >= 2, even if size == 0. + /// + [NonSerialized] private object[] _queue; + + /// The number of elements in the priority queue. + private int _priorityQueueSize = 0; + + /// + /// The comparator, or null if priority queue uses elements' + /// natural ordering. + /// + private IComparer _comparator; + + /// + /// The number of times this priority queue has been + /// structurally modified. + /// + [NonSerialized] private int _queueModificationCount = 0; + + #endregion + + #region Constructors + + /// + /// Creates a with the default initial capacity + /// (11) that orders its elements according to their natural + /// ordering (using ). + /// + public PriorityQueue() : this(DEFAULT_INITIAL_CAPACITY, null) + { + } + + /// + /// Creates a with the specified initial capacity + /// that orders its elements according to their natural ordering + /// (using ). + /// + /// the initial capacity for this priority queue. + /// + /// if is less than 1. + public PriorityQueue(int initialCapacity) : this(initialCapacity, null) + { + } + + /// + /// Creates a with the specified initial capacity + /// that orders its elements according to the specified comparator. + /// + /// the initial capacity for this priority queue. + /// the comparator used to order this priority queue. + /// If then the order depends on the elements' natural ordering. + /// + /// if is less than 1. + public PriorityQueue(int initialCapacity, IComparer comparator) + { + if (initialCapacity < 1) + throw new ArgumentException("initialCapacity"); + _queue = new object[initialCapacity + 1]; + _comparator = comparator; + } + + /// + /// Creates a containing the elements in the + /// specified collection. The priority queue has an initial + /// capacity of 110% of the size of the specified collection or 1 + /// if the collection is empty. If the specified collection is an + /// instance of a , the priority queue will be sorted + /// according to the same comparator, or according to its elements' + /// natural order if the collection is sorted according to its + /// elements' natural order. Otherwise, the priority queue is + /// ordered according to its elements' natural order. + /// + /// the collection whose elements are to be placed into this priority queue. + /// if elements of cannot be + /// compared to one another according to the priority queue's ordering + /// if or any element with it is + /// + /// + public PriorityQueue(ICollection collection) + { + if (null == collection) + throw new ArgumentNullException("collection"); + initializeArray(collection); + if (collection is PriorityQueue) + { + PriorityQueue s = (PriorityQueue) collection; + _comparator = s.Comparator(); + fillFromSorted(s); + } + else + { + _comparator = null; + fillFromUnsorted(collection); + } + } + + #endregion + + #region Private Helper Methods + + /// + /// Common code to initialize underlying queue array across + /// constructors below. + /// + private void initializeArray(ICollection c) + { + int size = c.Count; + int initialCapacity = getQueueSizeBasedOnPercentage(size, 110); + if (initialCapacity < 1) + initialCapacity = 1; + + _queue = new Object[initialCapacity + 1]; + } + + /// + /// Performs an unsigned bitwise right shift with the specified number + /// + /// Number to operate on + /// Amount of bits to shift + /// The resulting number from the shift operation + private int urShift(int number, int bits) + { + if (number >= 0) + return number >> bits; + else + return (number >> bits) + (2 << ~bits); + } + + /// + /// Establishes the heap invariant assuming the heap + /// satisfies the invariant except possibly for the leaf-node indexed by k + /// (which may have a nextExecutionTime less than its parent's). + /// + /// + /// This method functions by "promoting" queue[k] up the hierarchy + /// (by swapping it with its parent) repeatedly until queue[k] + /// is greater than or equal to its parent. + /// + private void fixUp(int k) + { + if (_comparator == null) + { + while (k > 1) + { + int j = k >> 1; + if (((IComparable) _queue[j]).CompareTo(_queue[k]) <= 0) + break; + Object tmp = _queue[j]; + _queue[j] = _queue[k]; + _queue[k] = tmp; + k = j; + } + } + else + { + while (k > 1) + { + int j = urShift(k, 1); + if (_comparator.Compare(_queue[j], _queue[k]) <= 0) + break; + Object tmp = _queue[j]; + _queue[j] = _queue[k]; + _queue[k] = tmp; + k = j; + } + } + } + + /// + /// Establishes the heap invariant (described above) in the subtree + /// rooted at k, which is assumed to satisfy the heap invariant except + /// possibly for node k itself (which may be greater than its children). + /// + /// + /// This method functions by "demoting" queue[k] down the hierarchy + /// (by swapping it with its smaller child) repeatedly until queue[k] + /// is less than or equal to its children. + /// + private void fixDown(int k) + { + int j; + if (_comparator == null) + { + while ((j = k << 1) <= _priorityQueueSize && (j > 0)) + { + if (j < _priorityQueueSize && ((IComparable) _queue[j]).CompareTo(_queue[j + 1]) > 0) + j++; // j indexes smallest kid + + if (((IComparable) _queue[k]).CompareTo(_queue[j]) <= 0) + break; + Object tmp = _queue[j]; + _queue[j] = _queue[k]; + _queue[k] = tmp; + k = j; + } + } + else + { + while ((j = k << 1) <= _priorityQueueSize && (j > 0)) + { + if (j < _priorityQueueSize && _comparator.Compare(_queue[j], _queue[j + 1]) > 0) + j++; // j indexes smallest kid + if (_comparator.Compare(_queue[k], _queue[j]) <= 0) + break; + Object tmp = _queue[j]; + _queue[j] = _queue[k]; + _queue[k] = tmp; + k = j; + } + } + } + + /// + /// Establishes the heap invariant in the entire tree, + /// assuming nothing about the order of the elements prior to the call. + /// + private void heapify() + { + for (int i = _priorityQueueSize / 2; i >= 1; i--) + fixDown(i); + } + + /// + /// Returns the of or - 1, + /// whichever is smaller. + /// + /// base size + /// percentage to return + /// of + private int getQueueSizeBasedOnPercentage(int size, long percentage) + { + return (int) Math.Min((size * percentage) / 100, Int32.MaxValue - 1); + } + + /// + /// Initially fill elements of the queue array under the + /// knowledge that it is sorted or is another , in which + /// case we can just place the elements in the order presented. + /// + private void fillFromSorted(ICollection collection) + { + fillArray(collection, true); + } + + private void fillArray(ICollection collection, bool sorted) + { + foreach (object currentObject in collection) + { + if (null == currentObject) + throw new ArgumentNullException("collection", "Cannot add null elements to queue."); + _queue[++_priorityQueueSize] = currentObject; + } + + if (!sorted) + { + heapify(); + } + } + + /// + /// Initially fill elements of the queue array that is not to our knowledge + /// sorted, so we must rearrange the elements to guarantee the heap + /// invariant. + /// + private void fillFromUnsorted(ICollection collection) + { + fillArray(collection, false); + } + + /// + /// Removes and returns element located at from queue. (Recall that the queue + /// is one-based, so 1 <= i <= size.) + /// + /// + /// Normally this method leaves the elements at positions from 1 up to i-1, + /// inclusive, untouched. Under these circumstances, it returns . + /// Occasionally, in order to maintain the heap invariant, it must move + /// the last element of the list to some index in the range [2, i-1], + /// and move the element previously at position (i/2) to position i. + /// Under these circumstances, this method returns the element that was + /// previously at the end of the list and is now at some position between + /// 2 and i-1 inclusive. + /// + private Object removeAt(int index) + { + Debug.Assert(index > 0 && index <= _priorityQueueSize); + _queueModificationCount++; + + Object moved = _queue[_priorityQueueSize]; + _queue[index] = moved; + _queue[_priorityQueueSize--] = null; + if (index <= _priorityQueueSize) + { + fixDown(index); + if (_queue[index] == moved) + { + fixUp(index); + if (_queue[index] != moved) + return moved; + } + } + + return null; + } + + /// Resize array, if necessary, to be able to hold given index + private void grow(int index) + { + int newLength = _queue.Length; + if (index < newLength) + return; + if (index == Int32.MaxValue) + throw new InvalidOperationException("Cannot grow queue to accomdate index " + index + ". Doing so would result in a memory overflow."); + while (newLength <= index) + { + if (newLength >= Int32.MaxValue / 2) + { + newLength = Int32.MaxValue; + } + else + { + newLength <<= 2; + } + } + + Object[] newQueue = new Object[newLength]; + Array.Copy(_queue, 0, newQueue, 0, _queue.Length); + _queue = newQueue; + } + + #endregion + + #region Public Methods + + /// + /// Gets the Capacity of this queue. Will equal + /// + public override int Capacity + { + get + { + return _queue.Length; + } + } + + /// + /// Returns the queue count. + /// + public override int Count + { + get { return _priorityQueueSize; } + } + + /// + /// Inserts the specified element into this queue if it is possible to do + /// so immediately without violating capacity restrictions. + /// + /// + ///

+ /// When using a capacity-restricted queue, this method is generally + /// preferable to , + /// which can fail to insert an element only by throwing an exception. + ///

+ ///
+ /// + /// The element to add. + /// + /// + /// if the element was added to this queue. + /// + /// + /// if the specified element cannot be compared + /// with elements currently in the priority queue according + /// to the priority queue's ordering. + /// + /// + /// If the element cannot be added at this time due to capacity restrictions. + /// + /// + /// If the supplied is + /// and this queue does not permit + /// elements. + /// + /// + /// If some property of the supplied prevents + /// it from being added to this queue. + /// + public override bool Offer(Object objectToAdd) + { + if (objectToAdd == null) + throw new ArgumentNullException("objectToAdd"); + _queueModificationCount++; + ++_priorityQueueSize; + + if (_priorityQueueSize >= _queue.Length) + { + grow(_priorityQueueSize); + } + + _queue[_priorityQueueSize] = objectToAdd; + fixUp(_priorityQueueSize); + return true; + } + + /// + /// Retrieves, but does not remove, the head of this queue, + /// or returns if this queue is empty. + /// + /// + /// The head of this queue, or if this queue is empty. + /// + public override Object Peek() + { + if (_priorityQueueSize == 0) + return null; + return _queue[1]; + } + + // Collection Methods - the first two override to update docs + /// + /// Inserts the specified element into this queue if it is possible to do so + /// immediately without violating capacity restrictions, returning + /// upon success and throwing an + /// if no space is + /// currently available. + /// + /// + /// The element to add. + /// + /// + /// if successful. + /// + /// + /// If the element cannot be added at this time due to capacity restrictions. + /// + /// + /// If the specified element is and this queue does not + /// permit elements. + /// + /// + /// If some property of the supplied prevents + /// it from being added to this queue. + /// + /// + /// if the specified element cannot be compared + /// with elements currently in the priority queue according + /// to the priority queue's ordering. + /// + public override bool Add(Object objectToAdd) + { + return Offer(objectToAdd); + } + + /// + /// Removes a single instance of the specified element from this + /// queue, if it is present. + /// + public virtual bool Remove(Object objectToRemove) + { + if (objectToRemove == null) + { + return false; + } + + if (_comparator == null) + { + for (int i = 1; i <= _priorityQueueSize; i++) + { + if (((IComparable) _queue[i]).CompareTo(objectToRemove) == 0) + { + removeAt(i); + return true; + } + } + } + else + { + for (int i = 1; i <= _priorityQueueSize; i++) + { + if (_comparator.Compare(_queue[i], objectToRemove) == 0) + { + removeAt(i); + return true; + } + } + } + + return false; + } + + /// + /// Returns an over the elements in this queue. + /// The enumerator does not return the elements in any particular order. + /// + /// an enumerator over the elements in this queue. + public override IEnumerator GetEnumerator() + { + return new PriorityQueueEnumerator(this); + } + + /// + /// Removes all elements from the priority queue. + /// The queue will be empty after this call returns. + /// + public override void Clear() + { + _queueModificationCount++; + + for (int i = 1; i <= _priorityQueueSize; i++) + _queue[i] = null; + + _priorityQueueSize = 0; + } + + /// + /// Retrieves and removes the head of this queue, + /// or returns if this queue is empty. + /// + /// + /// The head of this queue, or if this queue is empty. + /// + public override Object Poll() + { + if (_priorityQueueSize == 0) + return null; + _queueModificationCount++; + + Object result = _queue[1]; + _queue[1] = _queue[_priorityQueueSize]; + _queue[_priorityQueueSize--] = null; + if (_priorityQueueSize > 1) + fixDown(1); + return result; + } + + /// + /// Queries the queue to see if it contains the specified + /// + /// element to look for. + /// if the queue contains the , + /// otherwise. + public bool Contains(object element) + { + if (element == null) + { + for (int num1 = 0; num1 < Capacity; num1++) + { + if (_queue[num1] == null) + { + return true; + } + } + + return false; + } + + for (int num2 = 0; num2 < Capacity; num2++) + { + if (element.Equals(_queue[num2])) + { + return true; + } + } + + return false; + } + + /// Returns the comparator used to order this collection, or + /// if this collection is sorted according to its elements natural ordering + /// (using ). + /// + /// + /// the comparator used to order this collection, or + /// if this collection is sorted according to its elements natural ordering. + /// + public virtual IComparer Comparator() + { + return _comparator; + } + + #endregion + + #region ISerializable Implementation + + /// + /// Save the state of the instance to a stream (that + /// is, serialize it). + /// + /// The length of the array backing the instance is + /// emitted (int), followed by all of its elements (each an + /// ) in the proper order. + /// + /// the stream + /// the context + public virtual void GetObjectData(SerializationInfo serializationInfo, StreamingContext context) + { + Type thisType = this.GetType(); + MemberInfo[] mi = FormatterServices.GetSerializableMembers(thisType, context); + for (int i = 0; i < mi.Length; i++) + { + serializationInfo.AddValue(mi[i].Name, ((FieldInfo) mi[i]).GetValue(this)); + } + + // Write out array length + serializationInfo.AddValue("Spring.Collections.PriorityQueuedata1", _queue.Length); + + // Write out all elements in the proper order. + for (int i = 1; i <= _priorityQueueSize; i++) + { + serializationInfo.AddValue("Spring.Collections.PriorityQueueData" + i, _queue[i]); + } + } + + /// + /// Reconstitute the instance from a stream (that is, + /// deserialize it). + /// + /// the stream + /// the context + protected PriorityQueue(SerializationInfo serializationInfo, StreamingContext context) + { + Type thisType = this.GetType(); + MemberInfo[] mi = FormatterServices.GetSerializableMembers(thisType, context); + for (int i = 0; i < mi.Length; i++) + { + FieldInfo fi = (FieldInfo) mi[i]; + fi.SetValue(this, serializationInfo.GetValue(fi.Name, fi.FieldType)); + } + + int arrayLength = serializationInfo.GetInt32("Spring.Collections.PriorityQueuedata1"); + _queue = new Object[arrayLength]; + + for (int i = 1; i <= _priorityQueueSize; i++) + { + _queue[i] = serializationInfo.GetValue("Spring.Collections.PriorityQueueData" + i, typeof(Object)); + } + } + + #endregion + + #region ICollection Implementation + + /// + ///Copies the elements of the to an , starting at a particular index. + /// + ///The one-dimensional that is the destination of the elements copied from . The must have zero-based indexing. + ///The zero-based index in array at which copying begins. + ///array is null. + ///index is less than zero. + ///array is multidimensional.-or- index is equal to or greater than the length of array.-or- The number of elements in the source is greater than the available space from index to the end of the destination array. + ///The type of the source cannot be cast automatically to the type of the destination array. 2 + public override void CopyTo(Array array, Int32 index) + { + if (_priorityQueueSize > array.Length) throw new ArgumentException("Destination array too small.", "array"); + if (index > array.Length - 1) throw new ArgumentException("Starting index outside bounds of target array.", "index"); + if (index + _priorityQueueSize > array.Length) throw new IndexOutOfRangeException("Destination array not long enough to begin copying at index " + index + "."); + + for (int queueElementCount = 1; queueElementCount <= _priorityQueueSize; queueElementCount++) + { + array.SetValue(_queue[queueElementCount], index); + index++; + } + + Array.Sort(array); + } + + /// + ///Copies the elements of the to an , starting at index 0. + /// + ///The one-dimensional that is the destination of the elements copied from . The must have zero-based indexing. + ///array is null. + ///index is less than zero. + ///array is multidimensional.-or- index is equal to or greater than the length of array.-or- The number of elements in the source is greater than the available space from index to the end of the destination array. + ///The type of the source cannot be cast automatically to the type of the destination array. 2 + public void CopyTo(Array array) + { + CopyTo(array, 0); + } + + /// + ///Gets an object that can be used to synchronize access to the . + /// + /// + ///An object that can be used to synchronize access to the . + /// + public override Object SyncRoot + { + get { return null; } + } + + /// + ///Gets a value indicating whether access to the is synchronized (thread safe). + /// + /// + ///true if access to the is synchronized (thread safe); otherwise, false. + /// + public override Boolean IsSynchronized + { + get { return false; } + } + + /// + /// Returns if there are no elements in the , otherwise. + /// + public override bool IsEmpty + { + get { return _priorityQueueSize == 0; } + } + + #endregion } diff --git a/src/Spring/Spring.Core/Collections/Set.cs b/src/Spring/Spring.Core/Collections/Set.cs index 60555932..d5b33649 100644 --- a/src/Spring/Spring.Core/Collections/Set.cs +++ b/src/Spring/Spring.Core/Collections/Set.cs @@ -22,541 +22,545 @@ using System.Collections; -namespace Spring.Collections +namespace Spring.Collections; + +/// +/// A collection that contains no duplicate elements. +/// +/// +[Serializable] +public abstract class Set : ISet { - /// - /// A collection that contains no duplicate elements. - /// - /// - [Serializable] - public abstract class Set : ISet - { - /// - /// Performs a "union" of the two sets, where all the elements - /// in both sets are present. - /// - /// A collection of elements. - /// - /// A new containing the union of - /// this with the specified - /// collection. Neither of the input objects is modified by the union. - /// - /// - public virtual ISet Union(ISet setOne) - { - ISet resultSet = (ISet) this.Clone(); - if (setOne != null) - { - resultSet.AddAll(setOne); - } - return resultSet; - } + /// + /// Performs a "union" of the two sets, where all the elements + /// in both sets are present. + /// + /// A collection of elements. + /// + /// A new containing the union of + /// this with the specified + /// collection. Neither of the input objects is modified by the union. + /// + /// + public virtual ISet Union(ISet setOne) + { + ISet resultSet = (ISet) this.Clone(); + if (setOne != null) + { + resultSet.AddAll(setOne); + } - /// - /// Performs a "union" of two sets, where all the elements in both are - /// present. - /// - /// - ///

- /// That is, the element is included if it is in either - /// or . The return - /// value is a clone of one of the sets ( - /// if it is not ) with elements of the other set - /// added in. Neither of the input sets is modified by the operation. - ///

- ///
- /// A set of elements. - /// A set of elements. - /// - /// A set containing the union of the input sets; - /// if both sets are . - /// - public static ISet Union(ISet setOne, ISet anotherSet) - { - if (setOne == null && anotherSet == null) - { - return null; - } - else if (setOne == null) - { - return (ISet) anotherSet.Clone(); - } - else if (anotherSet == null) - { - return (ISet) setOne.Clone(); - } - else - { - return setOne.Union(anotherSet); - } - } + return resultSet; + } - /// - /// Performs a "union" of two sets, where all the elements in both are - /// present. - /// - /// A set of elements. - /// A set of elements. - /// - /// A set containing the union of the input sets; - /// if both sets are . - /// - /// - public static Set operator |(Set setOne, Set anotherSet) - { - return (Set) Union(setOne, anotherSet); - } + /// + /// Performs a "union" of two sets, where all the elements in both are + /// present. + /// + /// + ///

+ /// That is, the element is included if it is in either + /// or . The return + /// value is a clone of one of the sets ( + /// if it is not ) with elements of the other set + /// added in. Neither of the input sets is modified by the operation. + ///

+ ///
+ /// A set of elements. + /// A set of elements. + /// + /// A set containing the union of the input sets; + /// if both sets are . + /// + public static ISet Union(ISet setOne, ISet anotherSet) + { + if (setOne == null && anotherSet == null) + { + return null; + } + else if (setOne == null) + { + return (ISet) anotherSet.Clone(); + } + else if (anotherSet == null) + { + return (ISet) setOne.Clone(); + } + else + { + return setOne.Union(anotherSet); + } + } - /// - /// Performs an "intersection" of the two sets, where only the elements - /// that are present in both sets remain. - /// - /// A set of elements. - /// - /// The intersection of this set with . - /// - /// - public virtual ISet Intersect(ISet setOne) - { - ISet resultSet = (ISet) this.Clone(); - if (setOne != null) - { - resultSet.RetainAll(setOne); - } - else - { - resultSet.Clear(); - } - return resultSet; - } + /// + /// Performs a "union" of two sets, where all the elements in both are + /// present. + /// + /// A set of elements. + /// A set of elements. + /// + /// A set containing the union of the input sets; + /// if both sets are . + /// + /// + public static Set operator |(Set setOne, Set anotherSet) + { + return (Set) Union(setOne, anotherSet); + } - /// - /// Performs an "intersection" of the two sets, where only the elements - /// that are present in both sets remain. - /// - /// - ///

- /// That is, the element is included only if it exists in both - /// and . Neither input - /// object is modified by the operation. The result object is a - /// clone of one of the input objects ( - /// if it is not ) containing the elements from - /// the intersect operation. - ///

- ///
- /// A set of elements. - /// A set of elements. - /// - /// The intersection of the two input sets; if - /// both sets are . - /// - public static ISet Intersect(ISet setOne, ISet anotherSet) - { - if (setOne == null && anotherSet == null) - { - return null; - } - else if (setOne == null) - { - return anotherSet.Intersect(setOne); - } - else - { - return setOne.Intersect(anotherSet); - } - } + /// + /// Performs an "intersection" of the two sets, where only the elements + /// that are present in both sets remain. + /// + /// A set of elements. + /// + /// The intersection of this set with . + /// + /// + public virtual ISet Intersect(ISet setOne) + { + ISet resultSet = (ISet) this.Clone(); + if (setOne != null) + { + resultSet.RetainAll(setOne); + } + else + { + resultSet.Clear(); + } - /// - /// Performs an "intersection" of the two sets, where only the elements - /// that are present in both sets remain. - /// - /// A set of elements. - /// A set of elements. - /// - /// The intersection of the two input sets; if - /// both sets are . - /// - /// - public static Set operator &(Set setOne, Set anotherSet) - { - return (Set) Intersect(setOne, anotherSet); - } + return resultSet; + } - /// - /// Performs a "minus" of this set from the - /// set. - /// - /// A set of elements. - /// - /// A set containing the elements from this set with the elements in - /// removed. - /// - /// - public virtual ISet Minus(ISet setOne) - { - ISet resultSet = (ISet) this.Clone(); - if (setOne != null) - { - resultSet.RemoveAll(setOne); - } - return resultSet; - } + /// + /// Performs an "intersection" of the two sets, where only the elements + /// that are present in both sets remain. + /// + /// + ///

+ /// That is, the element is included only if it exists in both + /// and . Neither input + /// object is modified by the operation. The result object is a + /// clone of one of the input objects ( + /// if it is not ) containing the elements from + /// the intersect operation. + ///

+ ///
+ /// A set of elements. + /// A set of elements. + /// + /// The intersection of the two input sets; if + /// both sets are . + /// + public static ISet Intersect(ISet setOne, ISet anotherSet) + { + if (setOne == null && anotherSet == null) + { + return null; + } + else if (setOne == null) + { + return anotherSet.Intersect(setOne); + } + else + { + return setOne.Intersect(anotherSet); + } + } - /// - /// Performs a "minus" of set from set - /// . - /// - /// - ///

- /// This returns a set of all the elements in set - /// , removing the elements that are also in - /// set . The original sets are not modified - /// during this operation. The result set is a clone of set - /// containing the elements from the operation. - ///

- ///
- /// A set of elements. - /// A set of elements. - /// - /// A set containing - /// - elements. - /// if is - /// . - /// - public static ISet Minus(ISet setOne, ISet anotherSet) - { - if (setOne == null) - { - return null; - } - else - { - return setOne.Minus(anotherSet); - } - } + /// + /// Performs an "intersection" of the two sets, where only the elements + /// that are present in both sets remain. + /// + /// A set of elements. + /// A set of elements. + /// + /// The intersection of the two input sets; if + /// both sets are . + /// + /// + public static Set operator &(Set setOne, Set anotherSet) + { + return (Set) Intersect(setOne, anotherSet); + } - /// - /// Performs a "minus" of set from set - /// . - /// - /// A set of elements. - /// A set of elements. - /// - /// A set containing - /// - elements. - /// if is - /// . - /// - /// - public static Set operator -(Set setOne, Set anotherSet) - { - return (Set) Minus(setOne, anotherSet); - } + /// + /// Performs a "minus" of this set from the + /// set. + /// + /// A set of elements. + /// + /// A set containing the elements from this set with the elements in + /// removed. + /// + /// + public virtual ISet Minus(ISet setOne) + { + ISet resultSet = (ISet) this.Clone(); + if (setOne != null) + { + resultSet.RemoveAll(setOne); + } + return resultSet; + } - /// - /// Performs an "exclusive-or" of the two sets, keeping only those - /// elements that are in one of the sets, but not in both. - /// - /// A set of elements. - /// - /// A set containing the result of - /// ^ this. - /// - /// - public virtual ISet ExclusiveOr(ISet setOne) - { - ISet resultSet = (ISet) this.Clone(); - foreach (object element in setOne) - { - if (resultSet.Contains(element)) - { - resultSet.Remove(element); - } - else - { - resultSet.Add(element); - } - } - return resultSet; - } + /// + /// Performs a "minus" of set from set + /// . + /// + /// + ///

+ /// This returns a set of all the elements in set + /// , removing the elements that are also in + /// set . The original sets are not modified + /// during this operation. The result set is a clone of set + /// containing the elements from the operation. + ///

+ ///
+ /// A set of elements. + /// A set of elements. + /// + /// A set containing + /// - elements. + /// if is + /// . + /// + public static ISet Minus(ISet setOne, ISet anotherSet) + { + if (setOne == null) + { + return null; + } + else + { + return setOne.Minus(anotherSet); + } + } - /// - /// Performs an "exclusive-or" of the two sets, keeping only those - /// elements that are in one of the sets, but not in both. - /// - /// - ///

- /// The original sets are not modified during this operation. The - /// result set is a clone of one of the sets ( - /// if it is not ) - /// containing the elements from the exclusive-or operation. - ///

- ///
- /// A set of elements. - /// A set of elements. - /// - /// A set containing the result of - /// ^ . - /// if both sets are . - /// - public static ISet ExclusiveOr(ISet setOne, ISet anotherSet) - { - if (setOne == null && anotherSet == null) - { - return null; - } - else if (setOne == null) - { - return (Set) anotherSet.Clone(); - } - else if (anotherSet == null) - { - return (Set) setOne.Clone(); - } - else - { - return setOne.ExclusiveOr(anotherSet); - } - } + /// + /// Performs a "minus" of set from set + /// . + /// + /// A set of elements. + /// A set of elements. + /// + /// A set containing + /// - elements. + /// if is + /// . + /// + /// + public static Set operator -(Set setOne, Set anotherSet) + { + return (Set) Minus(setOne, anotherSet); + } - /// - /// Performs an "exclusive-or" of the two sets, keeping only those - /// elements that are in one of the sets, but not in both. - /// - /// A set of elements. - /// A set of elements. - /// - /// A set containing the result of - /// ^ . - /// if both sets are . - /// - /// - public static Set operator ^(Set setOne, Set anotherSet) - { - return (Set) ExclusiveOr(setOne, anotherSet); - } - - /// - /// Adds the specified element to this set if it is not already present. - /// - /// The object to add to the set. - /// - /// is the object was added, - /// if the object was already present. - /// - public abstract bool Add(object element); - - /// - /// Adds all the elements in the specified collection to the set if - /// they are not already present. - /// - /// A collection of objects to add to the set. - /// - /// is the set changed as a result of this - /// operation. - /// - public abstract bool AddAll(ICollection collection); - - /// - /// Removes all objects from this set. - /// - public abstract void Clear(); - - /// - /// Returns if this set contains the specified - /// element. - /// - /// The element to look for. - /// - /// if this set contains the specified element. - /// - public abstract bool Contains(object element); - - /// - /// Returns if the set contains all the - /// elements in the specified collection. - /// - /// A collection of objects. - /// - /// if the set contains all the elements in the - /// specified collection. - /// - public abstract bool ContainsAll(ICollection collection); - - /// - /// Returns if this set contains no elements. - /// - public abstract bool IsEmpty { get; } - - /// - /// Removes the specified element from the set. - /// - /// The element to be removed. - /// - /// if the set contained the specified element. - /// - public abstract bool Remove(object element); - - /// - /// Remove all the specified elements from this set, if they exist in - /// this set. - /// - /// A collection of elements to remove. - /// - /// if the set was modified as a result of this - /// operation. - /// - public abstract bool RemoveAll(ICollection collection); - - /// - /// Retains only the elements in this set that are contained in the - /// specified collection. - /// - /// - /// The collection that defines the set of elements to be retained. - /// - /// - /// if this set changed as a result of this - /// operation. - /// - public abstract bool RetainAll(ICollection collection); - - /// - /// Returns a clone of the - /// instance. - /// - /// - ///

- /// This will work for derived - /// classes if the derived class implements a constructor that takes no - /// arguments. - ///

- ///
- /// A clone of this object. - public virtual object Clone() - { - Set newSet = (Set) Activator.CreateInstance(this.GetType()); - newSet.AddAll(this); - return newSet; - } - - /// - /// Copies the elements in the to - /// an array. - /// - /// - ///

- /// The type of array needs to be compatible with the objects in the - /// , obviously. - ///

- ///
- /// - /// An array that will be the target of the copy operation. - /// - /// - /// The zero-based index where copying will start. - /// - public abstract void CopyTo(Array array, int index); - - /// - /// The number of elements currently contained in this collection. - /// - public abstract int Count { get; } - - /// - /// Returns if the - /// is synchronized across - /// threads. - /// - /// - ///

- /// Note that enumeration is inherently not thread-safe. Use the - /// to lock the object during enumeration. - ///

- ///
- public abstract bool IsSynchronized { get; } - - /// - /// An object that can be used to synchronize this collection to make - /// it thread-safe. - /// - /// - ///

- /// When implementing this, if your object uses a base object, like an - /// , or anything that has - /// a SyncRoot, return that object instead of "this". - ///

- ///
- /// - /// An object that can be used to synchronize this collection to make - /// it thread-safe. - /// - public abstract object SyncRoot { get; } - - /// - /// Gets an enumerator for the elements in the - /// . - /// - /// - /// An over the elements - /// in the . - /// - public abstract IEnumerator GetEnumerator(); - - /// - /// This method will test the - /// against another for - /// "equality". - /// - /// - ///

- /// In this case, "equality" means that the two sets contain the same - /// elements. The "==" and "!=" operators are not overridden by design. - /// If you wish to check for "equivalent" - /// instances, use - /// Equals(). If you wish to check to see if two references are - /// actually the same object, use "==" and "!=". - ///

- ///
- /// - /// A object to compare to. - /// - /// - /// if the two sets contain the same elements. - /// - public override bool Equals(object obj) - { - Set theOtherSet = obj as Set; - if (theOtherSet == null || theOtherSet.Count != Count) - { - return false; - } - else - { - foreach (object element in theOtherSet) - { - if (!this.Contains(element)) - { - return false; - } - } - return true; - } - } - - /// - /// Gets the hashcode for the object. - /// - public override int GetHashCode() - { - int hashCode = 0, count = 0; - foreach (object element in this) + /// + /// Performs an "exclusive-or" of the two sets, keeping only those + /// elements that are in one of the sets, but not in both. + /// + /// A set of elements. + /// + /// A set containing the result of + /// ^ this. + /// + /// + public virtual ISet ExclusiveOr(ISet setOne) + { + ISet resultSet = (ISet) this.Clone(); + foreach (object element in setOne) + { + if (resultSet.Contains(element)) { - hashCode += element.GetHashCode(); - count++; + resultSet.Remove(element); } - return count + hashCode; - } - } + else + { + resultSet.Add(element); + } + } + + return resultSet; + } + + /// + /// Performs an "exclusive-or" of the two sets, keeping only those + /// elements that are in one of the sets, but not in both. + /// + /// + ///

+ /// The original sets are not modified during this operation. The + /// result set is a clone of one of the sets ( + /// if it is not ) + /// containing the elements from the exclusive-or operation. + ///

+ ///
+ /// A set of elements. + /// A set of elements. + /// + /// A set containing the result of + /// ^ . + /// if both sets are . + /// + public static ISet ExclusiveOr(ISet setOne, ISet anotherSet) + { + if (setOne == null && anotherSet == null) + { + return null; + } + else if (setOne == null) + { + return (Set) anotherSet.Clone(); + } + else if (anotherSet == null) + { + return (Set) setOne.Clone(); + } + else + { + return setOne.ExclusiveOr(anotherSet); + } + } + + /// + /// Performs an "exclusive-or" of the two sets, keeping only those + /// elements that are in one of the sets, but not in both. + /// + /// A set of elements. + /// A set of elements. + /// + /// A set containing the result of + /// ^ . + /// if both sets are . + /// + /// + public static Set operator ^(Set setOne, Set anotherSet) + { + return (Set) ExclusiveOr(setOne, anotherSet); + } + + /// + /// Adds the specified element to this set if it is not already present. + /// + /// The object to add to the set. + /// + /// is the object was added, + /// if the object was already present. + /// + public abstract bool Add(object element); + + /// + /// Adds all the elements in the specified collection to the set if + /// they are not already present. + /// + /// A collection of objects to add to the set. + /// + /// is the set changed as a result of this + /// operation. + /// + public abstract bool AddAll(ICollection collection); + + /// + /// Removes all objects from this set. + /// + public abstract void Clear(); + + /// + /// Returns if this set contains the specified + /// element. + /// + /// The element to look for. + /// + /// if this set contains the specified element. + /// + public abstract bool Contains(object element); + + /// + /// Returns if the set contains all the + /// elements in the specified collection. + /// + /// A collection of objects. + /// + /// if the set contains all the elements in the + /// specified collection. + /// + public abstract bool ContainsAll(ICollection collection); + + /// + /// Returns if this set contains no elements. + /// + public abstract bool IsEmpty { get; } + + /// + /// Removes the specified element from the set. + /// + /// The element to be removed. + /// + /// if the set contained the specified element. + /// + public abstract bool Remove(object element); + + /// + /// Remove all the specified elements from this set, if they exist in + /// this set. + /// + /// A collection of elements to remove. + /// + /// if the set was modified as a result of this + /// operation. + /// + public abstract bool RemoveAll(ICollection collection); + + /// + /// Retains only the elements in this set that are contained in the + /// specified collection. + /// + /// + /// The collection that defines the set of elements to be retained. + /// + /// + /// if this set changed as a result of this + /// operation. + /// + public abstract bool RetainAll(ICollection collection); + + /// + /// Returns a clone of the + /// instance. + /// + /// + ///

+ /// This will work for derived + /// classes if the derived class implements a constructor that takes no + /// arguments. + ///

+ ///
+ /// A clone of this object. + public virtual object Clone() + { + Set newSet = (Set) Activator.CreateInstance(this.GetType()); + newSet.AddAll(this); + return newSet; + } + + /// + /// Copies the elements in the to + /// an array. + /// + /// + ///

+ /// The type of array needs to be compatible with the objects in the + /// , obviously. + ///

+ ///
+ /// + /// An array that will be the target of the copy operation. + /// + /// + /// The zero-based index where copying will start. + /// + public abstract void CopyTo(Array array, int index); + + /// + /// The number of elements currently contained in this collection. + /// + public abstract int Count { get; } + + /// + /// Returns if the + /// is synchronized across + /// threads. + /// + /// + ///

+ /// Note that enumeration is inherently not thread-safe. Use the + /// to lock the object during enumeration. + ///

+ ///
+ public abstract bool IsSynchronized { get; } + + /// + /// An object that can be used to synchronize this collection to make + /// it thread-safe. + /// + /// + ///

+ /// When implementing this, if your object uses a base object, like an + /// , or anything that has + /// a SyncRoot, return that object instead of "this". + ///

+ ///
+ /// + /// An object that can be used to synchronize this collection to make + /// it thread-safe. + /// + public abstract object SyncRoot { get; } + + /// + /// Gets an enumerator for the elements in the + /// . + /// + /// + /// An over the elements + /// in the . + /// + public abstract IEnumerator GetEnumerator(); + + /// + /// This method will test the + /// against another for + /// "equality". + /// + /// + ///

+ /// In this case, "equality" means that the two sets contain the same + /// elements. The "==" and "!=" operators are not overridden by design. + /// If you wish to check for "equivalent" + /// instances, use + /// Equals(). If you wish to check to see if two references are + /// actually the same object, use "==" and "!=". + ///

+ ///
+ /// + /// A object to compare to. + /// + /// + /// if the two sets contain the same elements. + /// + public override bool Equals(object obj) + { + Set theOtherSet = obj as Set; + if (theOtherSet == null || theOtherSet.Count != Count) + { + return false; + } + else + { + foreach (object element in theOtherSet) + { + if (!this.Contains(element)) + { + return false; + } + } + + return true; + } + } + + /// + /// Gets the hashcode for the object. + /// + public override int GetHashCode() + { + int hashCode = 0, count = 0; + foreach (object element in this) + { + hashCode += element.GetHashCode(); + count++; + } + + return count + hashCode; + } } diff --git a/src/Spring/Spring.Core/Collections/SortedSet.cs b/src/Spring/Spring.Core/Collections/SortedSet.cs index 8dbbe375..2c91411b 100644 --- a/src/Spring/Spring.Core/Collections/SortedSet.cs +++ b/src/Spring/Spring.Core/Collections/SortedSet.cs @@ -23,61 +23,60 @@ using System.Collections; using Spring.Util; -namespace Spring.Collections +namespace Spring.Collections; + +/// +/// Implements an based on a sorted +/// tree. +/// +/// +///

+/// This gives good performance for operations on very large data-sets, +/// though not as good - asymptotically - as a +/// . However, iteration occurs +/// in order. +///

+///

+/// Elements that you put into this type of collection must implement +/// , and they must actually be comparable. +/// You can't mix and +/// values, for example. +///

+///

+/// This implementation does +/// not support elements that are . +///

+///
+/// +[Serializable] +public class SortedSet : DictionarySet { - /// - /// Implements an based on a sorted - /// tree. - /// - /// - ///

- /// This gives good performance for operations on very large data-sets, - /// though not as good - asymptotically - as a - /// . However, iteration occurs - /// in order. - ///

- ///

- /// Elements that you put into this type of collection must implement - /// , and they must actually be comparable. - /// You can't mix and - /// values, for example. - ///

- ///

- /// This implementation does - /// not support elements that are . - ///

- ///
- /// - [Serializable] - public class SortedSet : DictionarySet - { - /// - /// Creates a new set instance based on a sorted tree. - /// - public SortedSet() - { - InternalDictionary = new SortedList(); - } + /// + /// Creates a new set instance based on a sorted tree. + /// + public SortedSet() + { + InternalDictionary = new SortedList(); + } - /// - /// Creates a new set instance based on a sorted tree using for ordering. - /// - public SortedSet(IComparer comparer) - { - AssertUtils.ArgumentNotNull(comparer, "comparer"); - InternalDictionary = new SortedList(comparer); - } + /// + /// Creates a new set instance based on a sorted tree using for ordering. + /// + public SortedSet(IComparer comparer) + { + AssertUtils.ArgumentNotNull(comparer, "comparer"); + InternalDictionary = new SortedList(comparer); + } - /// - /// Creates a new set instance based on a sorted tree and initializes - /// it based on a collection of elements. - /// - /// - /// A collection of elements that defines the initial set contents. - /// - public SortedSet(ICollection initialValues) : this() - { - this.AddAll(initialValues); - } - } + /// + /// Creates a new set instance based on a sorted tree and initializes + /// it based on a collection of elements. + /// + /// + /// A collection of elements that defines the initial set contents. + /// + public SortedSet(ICollection initialValues) : this() + { + this.AddAll(initialValues); + } } diff --git a/src/Spring/Spring.Core/Collections/SynchronizedDictionaryEnumerator.cs b/src/Spring/Spring.Core/Collections/SynchronizedDictionaryEnumerator.cs index 754d4363..3d2fa407 100644 --- a/src/Spring/Spring.Core/Collections/SynchronizedDictionaryEnumerator.cs +++ b/src/Spring/Spring.Core/Collections/SynchronizedDictionaryEnumerator.cs @@ -20,56 +20,55 @@ using System.Collections; -namespace Spring.Collections +namespace Spring.Collections; + +/// +/// Synchronized that should be returned by synchronized +/// dictionary implementations in order to ensure that the enumeration is thread safe. +/// +/// Aleksandar Seovic +internal class SynchronizedDictionaryEnumerator : SynchronizedEnumerator, IDictionaryEnumerator { - /// - /// Synchronized that should be returned by synchronized - /// dictionary implementations in order to ensure that the enumeration is thread safe. - /// - /// Aleksandar Seovic - internal class SynchronizedDictionaryEnumerator : SynchronizedEnumerator, IDictionaryEnumerator + public SynchronizedDictionaryEnumerator(object syncRoot, IDictionaryEnumerator enumerator) + : base(syncRoot, enumerator) { - public SynchronizedDictionaryEnumerator(object syncRoot, IDictionaryEnumerator enumerator) - : base(syncRoot, enumerator) - { - } + } - protected IDictionaryEnumerator Enumerator - { - get { return (IDictionaryEnumerator) enumerator; } - } + protected IDictionaryEnumerator Enumerator + { + get { return (IDictionaryEnumerator) enumerator; } + } - public object Key + public object Key + { + get { - get + lock (syncRoot) { - lock (syncRoot) - { - return Enumerator.Key; - } - } - } - - public object Value - { - get - { - lock (syncRoot) - { - return Enumerator.Value; - } - } - } - - public DictionaryEntry Entry - { - get - { - lock (syncRoot) - { - return Enumerator.Entry; - } + return Enumerator.Key; } } } -} \ No newline at end of file + + public object Value + { + get + { + lock (syncRoot) + { + return Enumerator.Value; + } + } + } + + public DictionaryEntry Entry + { + get + { + lock (syncRoot) + { + return Enumerator.Entry; + } + } + } +} diff --git a/src/Spring/Spring.Core/Collections/SynchronizedEnumerator.cs b/src/Spring/Spring.Core/Collections/SynchronizedEnumerator.cs index d47a782d..ed8b37a4 100644 --- a/src/Spring/Spring.Core/Collections/SynchronizedEnumerator.cs +++ b/src/Spring/Spring.Core/Collections/SynchronizedEnumerator.cs @@ -20,49 +20,48 @@ using System.Collections; -namespace Spring.Collections +namespace Spring.Collections; + +/// +/// Synchronized that should be returned by synchronized +/// collections in order to ensure that the enumeration is thread safe. +/// +/// Aleksandar Seovic +internal class SynchronizedEnumerator : IEnumerator { - /// - /// Synchronized that should be returned by synchronized - /// collections in order to ensure that the enumeration is thread safe. - /// - /// Aleksandar Seovic - internal class SynchronizedEnumerator : IEnumerator + protected object syncRoot; + protected IEnumerator enumerator; + + public SynchronizedEnumerator(object syncRoot, IEnumerator enumerator) { - protected object syncRoot; - protected IEnumerator enumerator; + this.syncRoot = syncRoot; + this.enumerator = enumerator; + } - public SynchronizedEnumerator(object syncRoot, IEnumerator enumerator) + public bool MoveNext() + { + lock (syncRoot) { - this.syncRoot = syncRoot; - this.enumerator = enumerator; + return enumerator.MoveNext(); } + } - public bool MoveNext() + public void Reset() + { + lock (syncRoot) + { + enumerator.Reset(); + } + } + + public object Current + { + get { lock (syncRoot) { - return enumerator.MoveNext(); - } - } - - public void Reset() - { - lock (syncRoot) - { - enumerator.Reset(); - } - } - - public object Current - { - get - { - lock (syncRoot) - { - return enumerator.Current; - } + return enumerator.Current; } } } -} \ No newline at end of file +} diff --git a/src/Spring/Spring.Core/Collections/SynchronizedHashtable.cs b/src/Spring/Spring.Core/Collections/SynchronizedHashtable.cs index 8e7fcd1b..383dd950 100644 --- a/src/Spring/Spring.Core/Collections/SynchronizedHashtable.cs +++ b/src/Spring/Spring.Core/Collections/SynchronizedHashtable.cs @@ -18,354 +18,355 @@ using System.Collections; using System.Collections.Specialized; using Spring.Util; -namespace Spring.Collections +namespace Spring.Collections; + +/// +/// Synchronized that, unlike hashtable created +/// using method, synchronizes +/// reads from the underlying hashtable in addition to writes. +/// +/// +///

+/// In addition to synchronizing reads, this implementation also fixes +/// IEnumerator/ICollection issue described at +/// http://msdn.microsoft.com/en-us/netframework/aa570326.aspx +/// (search for SynchronizedHashtable for issue description), by implementing +/// interface explicitly, and returns thread safe enumerator +/// implementations as well. +///

+///

+/// This class should be used whenever a truly synchronized +/// is needed. +///

+///
+/// Aleksandar Seovic +[Serializable] +public class SynchronizedHashtable : IDictionary, ICollection, IEnumerable, ICloneable { + private readonly bool _ignoreCase; + private readonly Hashtable _table; + /// - /// Synchronized that, unlike hashtable created - /// using method, synchronizes - /// reads from the underlying hashtable in addition to writes. + /// Initializes a new instance of /// - /// - ///

- /// In addition to synchronizing reads, this implementation also fixes - /// IEnumerator/ICollection issue described at - /// http://msdn.microsoft.com/en-us/netframework/aa570326.aspx - /// (search for SynchronizedHashtable for issue description), by implementing - /// interface explicitly, and returns thread safe enumerator - /// implementations as well. - ///

- ///

- /// This class should be used whenever a truly synchronized - /// is needed. - ///

- ///
- /// Aleksandar Seovic - [Serializable] - public class SynchronizedHashtable : IDictionary, ICollection, IEnumerable, ICloneable + public SynchronizedHashtable() + : this(new Hashtable(), false) { - private readonly bool _ignoreCase; - private readonly Hashtable _table; + } - /// - /// Initializes a new instance of - /// - public SynchronizedHashtable() - : this(new Hashtable(), false) - { } + /// + /// Initializes a new instance of + /// + public SynchronizedHashtable(bool ignoreCase) + : this(new Hashtable(), ignoreCase) + { + } - /// - /// Initializes a new instance of - /// - public SynchronizedHashtable(bool ignoreCase) - : this(new Hashtable(), ignoreCase) - { } + /// + /// Initializes a new instance of , copying initial entries from + /// handling keys depending on . + /// + public SynchronizedHashtable(IDictionary dictionary, bool ignoreCase) + { + AssertUtils.ArgumentNotNull(dictionary, "dictionary"); + this._table = (ignoreCase) ? CollectionsUtil.CreateCaseInsensitiveHashtable(dictionary) : new Hashtable(dictionary); + this._ignoreCase = ignoreCase; + } - /// - /// Initializes a new instance of , copying initial entries from - /// handling keys depending on . - /// - public SynchronizedHashtable(IDictionary dictionary, bool ignoreCase) - { - AssertUtils.ArgumentNotNull(dictionary, "dictionary"); - this._table = (ignoreCase) ? CollectionsUtil.CreateCaseInsensitiveHashtable(dictionary) : new Hashtable(dictionary); - this._ignoreCase = ignoreCase; - } + /// + /// Creates a instance that + /// synchronizes access to the underlying . + /// + /// the hashtable to be synchronized + protected SynchronizedHashtable(Hashtable other) + { + AssertUtils.ArgumentNotNull(other, "other"); + this._table = other; + } - /// - /// Creates a instance that - /// synchronizes access to the underlying . - /// - /// the hashtable to be synchronized - protected SynchronizedHashtable(Hashtable other) - { - AssertUtils.ArgumentNotNull(other, "other"); - this._table = other; - } + /// + /// Creates a wrapper that synchronizes + /// access to the passed . + /// + /// the hashtable to be synchronized + public static SynchronizedHashtable Wrap(Hashtable other) + { + return new SynchronizedHashtable(other); + } - /// - /// Creates a wrapper that synchronizes - /// access to the passed . - /// - /// the hashtable to be synchronized - public static SynchronizedHashtable Wrap(Hashtable other) - { - return new SynchronizedHashtable(other); - } - - /// - ///Gets a value indicating whether the object is read-only. - /// - /// - ///true if the object is read-only; otherwise, false. - /// - public bool IsReadOnly - { - get - { - lock (SyncRoot) - { - return _table.IsReadOnly; - } - } - } - - /// - ///Gets a value indicating whether the object has a fixed size. - /// - /// - ///true if the object has a fixed size; otherwise, false. - /// - public bool IsFixedSize - { - get - { - lock (SyncRoot) - { - return _table.IsFixedSize; - } - } - } - - /// - ///Gets a value indicating whether access to the is synchronized (thread safe). - /// - /// - ///true if access to the is synchronized (thread safe); otherwise, false. - /// - public bool IsSynchronized - { - get { return true; } - } - - /// - ///Gets an object containing the keys of the object. - /// - /// - ///An object containing the keys of the object. - /// - public ICollection Keys - { - get - { - lock (SyncRoot) - { - return _table.Keys; - } - } - } - - /// - ///Gets an object containing the values in the object. - /// - /// - ///An object containing the values in the object. - /// - public ICollection Values - { - get - { - lock (SyncRoot) - { - return _table.Values; - } - } - } - - /// - ///Gets an object that can be used to synchronize access to the . - /// - /// - ///An object that can be used to synchronize access to the . - /// - public object SyncRoot - { - get { return _table.SyncRoot; } - } - - /// - ///Gets the number of elements contained in the . - /// - /// - ///The number of elements contained in the . - /// - public int Count - { - get - { - lock (SyncRoot) - { - return _table.Count; - } - } - } - - /// - ///Adds an element with the provided key and value to the object. - /// - ///The to use as the value of the element to add. - ///The to use as the key of the element to add. - ///An element with the same key already exists in the object. - ///key is null. - ///The is read-only.-or- The has a fixed size. 2 - public void Add(object key, object value) + /// + ///Gets a value indicating whether the object is read-only. + /// + /// + ///true if the object is read-only; otherwise, false. + /// + public bool IsReadOnly + { + get { lock (SyncRoot) { - _table.Add(key, value); + return _table.IsReadOnly; } } + } - /// - ///Removes all elements from the object. - /// - ///The object is read-only. 2 - public void Clear() + /// + ///Gets a value indicating whether the object has a fixed size. + /// + /// + ///true if the object has a fixed size; otherwise, false. + /// + public bool IsFixedSize + { + get { lock (SyncRoot) { - _table.Clear(); + return _table.IsFixedSize; } } + } - /// - ///Creates a new object that is a copy of the current instance. - /// - /// - ///A new object that is a copy of this instance. - /// - public object Clone() + /// + ///Gets a value indicating whether access to the is synchronized (thread safe). + /// + /// + ///true if access to the is synchronized (thread safe); otherwise, false. + /// + public bool IsSynchronized + { + get { return true; } + } + + /// + ///Gets an object containing the keys of the object. + /// + /// + ///An object containing the keys of the object. + /// + public ICollection Keys + { + get { lock (SyncRoot) { - return new SynchronizedHashtable(this, _ignoreCase); + return _table.Keys; } } + } - /// - ///Determines whether the object contains an element with the specified key. - /// - /// - ///true if the contains an element with the key; otherwise, false. - /// - ///The key to locate in the object. - ///key is null. 2 - public bool Contains(object key) + /// + ///Gets an object containing the values in the object. + /// + /// + ///An object containing the values in the object. + /// + public ICollection Values + { + get { lock (SyncRoot) { - return _table.Contains(key); + return _table.Values; } } + } - /// - /// Returns, whether this contains an entry with the specified . - /// - ///The key to look for - ///, if this contains an entry with this - public bool ContainsKey(object key) + /// + ///Gets an object that can be used to synchronize access to the . + /// + /// + ///An object that can be used to synchronize access to the . + /// + public object SyncRoot + { + get { return _table.SyncRoot; } + } + + /// + ///Gets the number of elements contained in the . + /// + /// + ///The number of elements contained in the . + /// + public int Count + { + get { lock (SyncRoot) { - return _table.ContainsKey(key); + return _table.Count; } } + } - /// - /// Returns, whether this contains an entry with the specified . - /// - ///The value to look for - ///, if this contains an entry with this - public bool ContainsValue(object value) + /// + ///Adds an element with the provided key and value to the object. + /// + ///The to use as the value of the element to add. + ///The to use as the key of the element to add. + ///An element with the same key already exists in the object. + ///key is null. + ///The is read-only.-or- The has a fixed size. 2 + public void Add(object key, object value) + { + lock (SyncRoot) + { + _table.Add(key, value); + } + } + + /// + ///Removes all elements from the object. + /// + ///The object is read-only. 2 + public void Clear() + { + lock (SyncRoot) + { + _table.Clear(); + } + } + + /// + ///Creates a new object that is a copy of the current instance. + /// + /// + ///A new object that is a copy of this instance. + /// + public object Clone() + { + lock (SyncRoot) + { + return new SynchronizedHashtable(this, _ignoreCase); + } + } + + /// + ///Determines whether the object contains an element with the specified key. + /// + /// + ///true if the contains an element with the key; otherwise, false. + /// + ///The key to locate in the object. + ///key is null. 2 + public bool Contains(object key) + { + lock (SyncRoot) + { + return _table.Contains(key); + } + } + + /// + /// Returns, whether this contains an entry with the specified . + /// + ///The key to look for + ///, if this contains an entry with this + public bool ContainsKey(object key) + { + lock (SyncRoot) + { + return _table.ContainsKey(key); + } + } + + /// + /// Returns, whether this contains an entry with the specified . + /// + ///The value to look for + ///, if this contains an entry with this + public bool ContainsValue(object value) + { + lock (SyncRoot) + { + return _table.ContainsValue(value); + } + } + + /// + ///Copies the elements of the to an , starting at a particular index. + /// + ///The one-dimensional that is the destination of the elements copied from . The must have zero-based indexing. + ///The zero-based index in array at which copying begins. + ///array is null. + ///The type of the source cannot be cast automatically to the type of the destination array. + ///index is less than zero. + ///array is multidimensional.-or- index is equal to or greater than the length of array.-or- The number of elements in the source is greater than the available space from index to the end of the destination array. 2 + public void CopyTo(Array array, int index) + { + lock (SyncRoot) + { + _table.CopyTo(array, index); + } + } + + /// + ///Returns an object for the object. + /// + /// + ///An object for the object. + /// + public IDictionaryEnumerator GetEnumerator() + { + lock (SyncRoot) + { + return new SynchronizedDictionaryEnumerator(SyncRoot, _table.GetEnumerator()); + } + } + + /// + ///Removes the element with the specified key from the object. + /// + ///The key of the element to remove. + ///The object is read-only.-or- The has a fixed size. + ///key is null. 2 + public void Remove(object key) + { + lock (SyncRoot) + { + _table.Remove(key); + } + } + + /// + ///Returns an enumerator that iterates through a collection. + /// + /// + ///An object that can be used to iterate through the collection. + /// + IEnumerator IEnumerable.GetEnumerator() + { + lock (SyncRoot) + { + return new SynchronizedEnumerator(SyncRoot, ((IEnumerable) _table).GetEnumerator()); + } + } + + /// + ///Gets or sets the element with the specified key. + /// + /// + ///The element with the specified key. + /// + ///The key of the element to get or set. + ///The property is set and the object is read-only.-or- The property is set, key does not exist in the collection, and the has a fixed size. + ///key is null. 2 + public object this[object key] + { + get { lock (SyncRoot) { - return _table.ContainsValue(value); + return _table[key]; } } - - /// - ///Copies the elements of the to an , starting at a particular index. - /// - ///The one-dimensional that is the destination of the elements copied from . The must have zero-based indexing. - ///The zero-based index in array at which copying begins. - ///array is null. - ///The type of the source cannot be cast automatically to the type of the destination array. - ///index is less than zero. - ///array is multidimensional.-or- index is equal to or greater than the length of array.-or- The number of elements in the source is greater than the available space from index to the end of the destination array. 2 - public void CopyTo(Array array, int index) + set { lock (SyncRoot) { - _table.CopyTo(array, index); - } - } - - /// - ///Returns an object for the object. - /// - /// - ///An object for the object. - /// - public IDictionaryEnumerator GetEnumerator() - { - lock (SyncRoot) - { - return new SynchronizedDictionaryEnumerator(SyncRoot, _table.GetEnumerator()); - } - } - - /// - ///Removes the element with the specified key from the object. - /// - ///The key of the element to remove. - ///The object is read-only.-or- The has a fixed size. - ///key is null. 2 - public void Remove(object key) - { - lock (SyncRoot) - { - _table.Remove(key); - } - } - - /// - ///Returns an enumerator that iterates through a collection. - /// - /// - ///An object that can be used to iterate through the collection. - /// - IEnumerator IEnumerable.GetEnumerator() - { - lock (SyncRoot) - { - return new SynchronizedEnumerator(SyncRoot, ((IEnumerable)_table).GetEnumerator()); - } - } - - /// - ///Gets or sets the element with the specified key. - /// - /// - ///The element with the specified key. - /// - ///The key of the element to get or set. - ///The property is set and the object is read-only.-or- The property is set, key does not exist in the collection, and the has a fixed size. - ///key is null. 2 - public object this[object key] - { - get - { - lock (SyncRoot) - { - return _table[key]; - } - } - set - { - lock (SyncRoot) - { - _table[key] = value; - } + _table[key] = value; } } } diff --git a/src/Spring/Spring.Core/Collections/SynchronizedSet.cs b/src/Spring/Spring.Core/Collections/SynchronizedSet.cs index bbc2c5d6..efd2190f 100644 --- a/src/Spring/Spring.Core/Collections/SynchronizedSet.cs +++ b/src/Spring/Spring.Core/Collections/SynchronizedSet.cs @@ -22,304 +22,309 @@ using System.Collections; -namespace Spring.Collections +namespace Spring.Collections; + +/// +/// Implements a thread-safe wrapper. +/// +/// +///

+/// The implementation is extremely conservative, serializing critical +/// sections to prevent possible deadlocks, and locking on everything. The +/// one exception is for enumeration, which is inherently not thread-safe. +/// For this, you have to lock the SyncRoot object for the +/// duration of the enumeration. +///

+///
+/// +[Serializable] +public sealed class SynchronizedSet : Set { - /// - /// Implements a thread-safe wrapper. - /// - /// - ///

- /// The implementation is extremely conservative, serializing critical - /// sections to prevent possible deadlocks, and locking on everything. The - /// one exception is for enumeration, which is inherently not thread-safe. - /// For this, you have to lock the SyncRoot object for the - /// duration of the enumeration. - ///

- ///
- /// - [Serializable] - public sealed class SynchronizedSet : Set - { - private ISet _mBasisSet; - private object _mSyncRoot; + private ISet _mBasisSet; + private object _mSyncRoot; - /// - /// Constructs a thread-safe - /// wrapper. - /// - /// - /// The object that this object - /// will wrap. - /// - /// - /// If the supplied ecposes a - /// SyncRoot value. - /// - public SynchronizedSet(ISet basisSet) - { - _mBasisSet = basisSet; - _mSyncRoot = basisSet.SyncRoot; - if (_mSyncRoot == null) - { - throw new NullReferenceException( - "The Set you specified returned a null SyncRoot."); - } - } + /// + /// Constructs a thread-safe + /// wrapper. + /// + /// + /// The object that this object + /// will wrap. + /// + /// + /// If the supplied ecposes a + /// SyncRoot value. + /// + public SynchronizedSet(ISet basisSet) + { + _mBasisSet = basisSet; + _mSyncRoot = basisSet.SyncRoot; + if (_mSyncRoot == null) + { + throw new NullReferenceException( + "The Set you specified returned a null SyncRoot."); + } + } - /// - /// Adds the specified element to this set if it is not already present. - /// - /// The object to add to the set. - /// - /// is the object was added, - /// if the object was already present. - /// - public override sealed bool Add(object element) - { - lock (_mSyncRoot) - { - return _mBasisSet.Add(element); - } - } + /// + /// Adds the specified element to this set if it is not already present. + /// + /// The object to add to the set. + /// + /// is the object was added, + /// if the object was already present. + /// + public override sealed bool Add(object element) + { + lock (_mSyncRoot) + { + return _mBasisSet.Add(element); + } + } - /// - /// Adds all the elements in the specified collection to the set if - /// they are not already present. - /// - /// A collection of objects to add to the set. - /// - /// is the set changed as a result of this - /// operation. - /// - public override sealed bool AddAll(ICollection collection) - { - if(collection == null) - { - return false; - } - Set temp; - lock (collection.SyncRoot) - { - temp = new HybridSet(collection); - } - lock (_mSyncRoot) - { - return _mBasisSet.AddAll(temp); - } - } + /// + /// Adds all the elements in the specified collection to the set if + /// they are not already present. + /// + /// A collection of objects to add to the set. + /// + /// is the set changed as a result of this + /// operation. + /// + public override sealed bool AddAll(ICollection collection) + { + if (collection == null) + { + return false; + } - /// - /// Removes all objects from this set. - /// - public override sealed void Clear() - { - lock (_mSyncRoot) - { - _mBasisSet.Clear(); - } - } + Set temp; + lock (collection.SyncRoot) + { + temp = new HybridSet(collection); + } - /// - /// Returns if this set contains the specified - /// element. - /// - /// The element to look for. - /// - /// if this set contains the specified element. - /// - public override sealed bool Contains(object element) - { - lock (_mSyncRoot) - { - return _mBasisSet.Contains(element); - } - } + lock (_mSyncRoot) + { + return _mBasisSet.AddAll(temp); + } + } - /// - /// Returns if the set contains all the - /// elements in the specified collection. - /// - /// A collection of objects. - /// - /// if the set contains all the elements in the - /// specified collection; also if the - /// supplied is . - /// - public override sealed bool ContainsAll(ICollection collection) - { - if(collection == null) - { - return false; - } - Set temp; - lock (collection.SyncRoot) - { - temp = new HybridSet(collection); - } - lock (_mSyncRoot) - { - return _mBasisSet.ContainsAll(temp); - } - } + /// + /// Removes all objects from this set. + /// + public override sealed void Clear() + { + lock (_mSyncRoot) + { + _mBasisSet.Clear(); + } + } - /// - /// Returns if this set contains no elements. - /// - public override sealed bool IsEmpty - { - get - { - lock (_mSyncRoot) - { - return _mBasisSet.IsEmpty; - } - } - } + /// + /// Returns if this set contains the specified + /// element. + /// + /// The element to look for. + /// + /// if this set contains the specified element. + /// + public override sealed bool Contains(object element) + { + lock (_mSyncRoot) + { + return _mBasisSet.Contains(element); + } + } - /// - /// Removes the specified element from the set. - /// - /// The element to be removed. - /// - /// if the set contained the specified element. - /// - public override sealed bool Remove(object element) - { - lock (_mSyncRoot) - { - return _mBasisSet.Remove(element); - } - } + /// + /// Returns if the set contains all the + /// elements in the specified collection. + /// + /// A collection of objects. + /// + /// if the set contains all the elements in the + /// specified collection; also if the + /// supplied is . + /// + public override sealed bool ContainsAll(ICollection collection) + { + if (collection == null) + { + return false; + } - /// - /// Remove all the specified elements from this set, if they exist in - /// this set. - /// - /// A collection of elements to remove. - /// - /// if the set was modified as a result of this - /// operation. - /// - public override sealed bool RemoveAll(ICollection collection) - { - Set temp; - lock (collection.SyncRoot) - { - temp = new HybridSet(collection); - } - lock (_mSyncRoot) - { - return _mBasisSet.RemoveAll(temp); - } - } + Set temp; + lock (collection.SyncRoot) + { + temp = new HybridSet(collection); + } - /// - /// Retains only the elements in this set that are contained in the - /// specified collection. - /// - /// - /// The collection that defines the set of elements to be retained. - /// - /// - /// if this set changed as a result of this - /// operation. - /// - public override sealed bool RetainAll(ICollection c) - { - Set temp; - lock (c.SyncRoot) - { - temp = new HybridSet(c); - } - lock (_mSyncRoot) - { - return _mBasisSet.RetainAll(temp); - } - } + lock (_mSyncRoot) + { + return _mBasisSet.ContainsAll(temp); + } + } - /// - /// Copies the elements in the to - /// an array. - /// - /// - ///

- /// The type of array needs to be compatible with the objects in the - /// , obviously. - ///

- ///
- /// - /// An array that will be the target of the copy operation. - /// - /// - /// The zero-based index where copying will start. - /// - public override sealed void CopyTo(Array array, int index) - { - lock (_mSyncRoot) - { - _mBasisSet.CopyTo(array, index); - } - } + /// + /// Returns if this set contains no elements. + /// + public override sealed bool IsEmpty + { + get + { + lock (_mSyncRoot) + { + return _mBasisSet.IsEmpty; + } + } + } - /// - /// The number of elements currently contained in this collection. - /// - public override sealed int Count - { - get - { - lock (_mSyncRoot) - { - return _mBasisSet.Count; - } - } - } + /// + /// Removes the specified element from the set. + /// + /// The element to be removed. + /// + /// if the set contained the specified element. + /// + public override sealed bool Remove(object element) + { + lock (_mSyncRoot) + { + return _mBasisSet.Remove(element); + } + } - /// - /// Returns if the - /// is synchronized across - /// threads. - /// - /// - public override sealed bool IsSynchronized - { - get { return true; } - } + /// + /// Remove all the specified elements from this set, if they exist in + /// this set. + /// + /// A collection of elements to remove. + /// + /// if the set was modified as a result of this + /// operation. + /// + public override sealed bool RemoveAll(ICollection collection) + { + Set temp; + lock (collection.SyncRoot) + { + temp = new HybridSet(collection); + } - /// - /// An object that can be used to synchronize this collection to make - /// it thread-safe. - /// - /// - /// An object that can be used to synchronize this collection to make - /// it thread-safe. - /// - /// - public override sealed object SyncRoot - { - get { return _mSyncRoot; } - } + lock (_mSyncRoot) + { + return _mBasisSet.RemoveAll(temp); + } + } - /// - /// Gets an enumerator for the elements in the - /// . - /// - /// - /// An over the elements - /// in the . - /// - public override sealed IEnumerator GetEnumerator() - { - return _mBasisSet.GetEnumerator(); - } + /// + /// Retains only the elements in this set that are contained in the + /// specified collection. + /// + /// + /// The collection that defines the set of elements to be retained. + /// + /// + /// if this set changed as a result of this + /// operation. + /// + public override sealed bool RetainAll(ICollection c) + { + Set temp; + lock (c.SyncRoot) + { + temp = new HybridSet(c); + } - /// - /// Returns a clone of the instance. - /// - /// A clone of this object. - public override object Clone() - { - return new SynchronizedSet((ISet) _mBasisSet.Clone()); - } - } + lock (_mSyncRoot) + { + return _mBasisSet.RetainAll(temp); + } + } + + /// + /// Copies the elements in the to + /// an array. + /// + /// + ///

+ /// The type of array needs to be compatible with the objects in the + /// , obviously. + ///

+ ///
+ /// + /// An array that will be the target of the copy operation. + /// + /// + /// The zero-based index where copying will start. + /// + public override sealed void CopyTo(Array array, int index) + { + lock (_mSyncRoot) + { + _mBasisSet.CopyTo(array, index); + } + } + + /// + /// The number of elements currently contained in this collection. + /// + public override sealed int Count + { + get + { + lock (_mSyncRoot) + { + return _mBasisSet.Count; + } + } + } + + /// + /// Returns if the + /// is synchronized across + /// threads. + /// + /// + public override sealed bool IsSynchronized + { + get { return true; } + } + + /// + /// An object that can be used to synchronize this collection to make + /// it thread-safe. + /// + /// + /// An object that can be used to synchronize this collection to make + /// it thread-safe. + /// + /// + public override sealed object SyncRoot + { + get { return _mSyncRoot; } + } + + /// + /// Gets an enumerator for the elements in the + /// . + /// + /// + /// An over the elements + /// in the . + /// + public override sealed IEnumerator GetEnumerator() + { + return _mBasisSet.GetEnumerator(); + } + + /// + /// Returns a clone of the instance. + /// + /// A clone of this object. + public override object Clone() + { + return new SynchronizedSet((ISet) _mBasisSet.Clone()); + } } diff --git a/src/Spring/Spring.Core/Context/ApplicationContextException.cs b/src/Spring/Spring.Core/Context/ApplicationContextException.cs index 3f3b45e8..0672cef2 100644 --- a/src/Spring/Spring.Core/Context/ApplicationContextException.cs +++ b/src/Spring/Spring.Core/Context/ApplicationContextException.cs @@ -25,61 +25,62 @@ using Spring.Objects; #endregion -namespace Spring.Context +namespace Spring.Context; + +/// Exception thrown during application context initialization. +/// Rod Johnson +/// Mark Pollack (.NET) +[Serializable] +public class ApplicationContextException : FatalObjectException { - /// Exception thrown during application context initialization. - /// Rod Johnson - /// Mark Pollack (.NET) - [Serializable] - public class ApplicationContextException : FatalObjectException + /// + /// Creates a new instance of the + /// class. + /// + public ApplicationContextException() { } + + /// + /// Creates a new instance of the + /// class. + /// + /// + /// The + /// that holds the serialized object data about the exception being thrown. + /// + /// + /// The + /// that contains contextual information about the source or destination. + /// + protected ApplicationContextException(SerializationInfo info, StreamingContext context) + : base(info, context) { - /// - /// Creates a new instance of the - /// class. - /// - public ApplicationContextException() {} + } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The - /// that holds the serialized object data about the exception being thrown. - /// - /// - /// The - /// that contains contextual information about the source or destination. - /// - protected ApplicationContextException( SerializationInfo info, StreamingContext context ) - : base( info, context ) {} + /// + /// Creates a new instance of the + /// class with the + /// specified message. + /// + /// + /// A message about the exception. + /// + public ApplicationContextException(string message) : base(message) + { + } - /// - /// Creates a new instance of the - /// class with the - /// specified message. - /// - /// - /// A message about the exception. - /// - public ApplicationContextException(string message) : base(message) - { - } - - /// - /// Creates a new instance of the - /// class with the - /// specified message. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception that is being wrapped. - /// - public ApplicationContextException(string message, Exception rootCause) - : base(message, rootCause) - { - } + /// + /// Creates a new instance of the + /// class with the + /// specified message. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception that is being wrapped. + /// + public ApplicationContextException(string message, Exception rootCause) + : base(message, rootCause) + { } } diff --git a/src/Spring/Spring.Core/Context/ApplicationEventArgs.cs b/src/Spring/Spring.Core/Context/ApplicationEventArgs.cs index b517d217..0325d6cf 100644 --- a/src/Spring/Spring.Core/Context/ApplicationEventArgs.cs +++ b/src/Spring/Spring.Core/Context/ApplicationEventArgs.cs @@ -18,51 +18,50 @@ #endregion -namespace Spring.Context +namespace Spring.Context; + +/// +/// Encapsulates the data associated with an event raised by an +/// . +/// +/// Rod Johnson +/// Mark Pollack (.NET) +/// Griffin Caprio (.NET) +/// +[Serializable] +public class ApplicationEventArgs : EventArgs { - /// - /// Encapsulates the data associated with an event raised by an - /// . - /// - /// Rod Johnson - /// Mark Pollack (.NET) - /// Griffin Caprio (.NET) - /// - [Serializable] - public class ApplicationEventArgs : EventArgs - { - private const long TicksAtEpoch = 621355968000000000; - private DateTime _timestamp; + private const long TicksAtEpoch = 621355968000000000; + private DateTime _timestamp; - /// - /// Creates a new instance of the - /// class. - /// - public ApplicationEventArgs() - { - _timestamp = DateTime.Now; - } + /// + /// Creates a new instance of the + /// class. + /// + public ApplicationEventArgs() + { + _timestamp = DateTime.Now; + } - /// - /// The date and time when the event occured. - /// - /// - /// The date and time when the event occured. - /// - public DateTime TimeStamp - { - get { return _timestamp; } - } + /// + /// The date and time when the event occured. + /// + /// + /// The date and time when the event occured. + /// + public DateTime TimeStamp + { + get { return _timestamp; } + } - /// - /// The system time in milliseconds when the event happened. - /// - /// - /// The system time in milliseconds when the event happened. - /// - public long EventTimeMilliseconds - { - get { return ( _timestamp.Ticks - TicksAtEpoch ) / 10000; } - } - } + /// + /// The system time in milliseconds when the event happened. + /// + /// + /// The system time in milliseconds when the event happened. + /// + public long EventTimeMilliseconds + { + get { return (_timestamp.Ticks - TicksAtEpoch) / 10000; } + } } diff --git a/src/Spring/Spring.Core/Context/Attributes/AssemblyObjectDefinitionScanner.cs b/src/Spring/Spring.Core/Context/Attributes/AssemblyObjectDefinitionScanner.cs index 1c835890..5fb73947 100644 --- a/src/Spring/Spring.Core/Context/Attributes/AssemblyObjectDefinitionScanner.cs +++ b/src/Spring/Spring.Core/Context/Attributes/AssemblyObjectDefinitionScanner.cs @@ -24,225 +24,223 @@ using Spring.Objects.Factory.Support; using Spring.Stereotype; using Spring.Util; -namespace Spring.Context.Attributes +namespace Spring.Context.Attributes; + +/// +/// AssemblyTypeScanner that only accepts types that also meet the requirements of being ObjectDefintions. +/// +[Serializable] +public class AssemblyObjectDefinitionScanner : RequiredConstraintAssemblyTypeScanner { - /// - /// AssemblyTypeScanner that only accepts types that also meet the requirements of being ObjectDefintions. - /// - [Serializable] - public class AssemblyObjectDefinitionScanner : RequiredConstraintAssemblyTypeScanner + private readonly List> _assemblyExclusionPredicates = new List>(); + + private readonly List _springAssemblyExcludePrefixes = new List { - private readonly List> _assemblyExclusionPredicates = new List>(); + "Antlr3.Runtime", + "Spring.", + "NHibernate.", + "Common.Logging", + "log4net", + "Mono.Cecil", + "NUnit", + "Quartz", + "NVelocity", + "FakeItEasy", + "Apache.NMS" + }; - private readonly List _springAssemblyExcludePrefixes = new List + private IObjectNameGenerator _objectNameGenerator = new AttributeObjectNameGenerator(); + + /// + /// Provides the name generator for all scanned objects. + /// Default is + /// + public IObjectNameGenerator ObjectNameGenerator + { + get { return _objectNameGenerator; } + set { _objectNameGenerator = value; } + } + + /// + /// Registers the defintions for types. + /// + /// The registry. + /// The types to register. + private void RegisterDefinitionsForTypes(IObjectDefinitionRegistry registry, IEnumerable typesToRegister) + { + foreach (Type type in typesToRegister) { - "Antlr3.Runtime", - "Spring.", - "NHibernate.", - "Common.Logging", - "log4net", - "Mono.Cecil", - "NUnit", - "Quartz", - "NVelocity", - "FakeItEasy", - "Apache.NMS" - }; + var definition = new ScannedGenericObjectDefinition(type, Defaults); + string objectName = ObjectNameGenerator.GenerateObjectName(definition, registry); + string fullname = type.FullName; - private IObjectNameGenerator _objectNameGenerator = new AttributeObjectNameGenerator(); - - /// - /// Provides the name generator for all scanned objects. - /// Default is - /// - public IObjectNameGenerator ObjectNameGenerator - { - get { return _objectNameGenerator; } - set { _objectNameGenerator = value; } - } - - /// - /// Registers the defintions for types. - /// - /// The registry. - /// The types to register. - private void RegisterDefinitionsForTypes(IObjectDefinitionRegistry registry, IEnumerable typesToRegister) - { - foreach (Type type in typesToRegister) - { - var definition = new ScannedGenericObjectDefinition(type, Defaults); - string objectName = ObjectNameGenerator.GenerateObjectName(definition, registry); - string fullname = type.FullName; - - Logger.LogDebug("Register Type: {FullName} with object name {ObjectName}", fullname, objectName); - registry.RegisterObjectDefinition(objectName, definition); - } - } - - - /// - /// Applies the assembly filters to the assembly candidates. - /// - /// The assembly candidates. - /// - protected override IEnumerable ApplyAssemblyFiltersTo(IEnumerable assemblyCandidates) - { - foreach (Assembly candidate in assemblyCandidates) - { - if (IsIncludedAssembly(candidate) && !IsExcludedAssembly(candidate)) - { - yield return candidate; - } - } - } - - /// - /// Determines whether the specified candidate is and excluded assembly. - /// - /// The candidate. - /// - /// true if the specified candidate is an excluded assembly ; otherwise, false. - /// - protected virtual bool IsExcludedAssembly(Assembly candidate) - { - return _assemblyExclusionPredicates.Any(exclude => exclude(candidate)); - } - - /// - /// Determines whether the required constraint is satisfied by the specified type. - /// - /// The type. - /// - /// true if the required constraint is satisfied by the specified type; otherwise, false. - /// - protected override bool IsRequiredConstraintSatisfiedBy(Type type) - { - if (!type.Assembly.ReflectionOnly) - { - try - { - return Attribute.GetCustomAttribute(type, typeof(ComponentAttribute), true) != null && - !type.IsAbstract; - } - catch (AmbiguousMatchException) - { - Logger.LogError("Type {Type} has more than one ComponentAttributes assigned to it.", type.FullName); - return false; - } - } - - bool satisfied = false; - - foreach (CustomAttributeData customAttributeData in CustomAttributeData.GetCustomAttributes(type)) - { - if (customAttributeData.Constructor.DeclaringType != null && - (customAttributeData.Constructor.DeclaringType.FullName == typeof(ComponentAttribute).FullName && - !type.IsAbstract)) - { - satisfied = true; - break; - } - } - - return satisfied; - } - - /// - /// Sets the default filters. - /// - protected override void SetDefaultFilters() - { - //set the built-in defaults - base.SetDefaultFilters(); - - //add the desired assembly exclusions to the list - _assemblyExclusionPredicates.Add(assembly => - { - var assemblyName = assembly.GetName().Name; - if ("Spring.Core.Tests".Equals(assemblyName, StringComparison.OrdinalIgnoreCase)) - { - return false; - } - - for (var i = 0; i < _springAssemblyExcludePrefixes.Count; i++) - { - var name = _springAssemblyExcludePrefixes[i]; - if (assemblyName.StartsWith(name, StringComparison.OrdinalIgnoreCase)) - { - return true; - } - } - - return false; - }); - _assemblyExclusionPredicates.Add(assembly => assembly.GetName().Name.StartsWith("System.")); - _assemblyExclusionPredicates.Add(assembly => assembly.GetName().Name.StartsWith("Microsoft.")); - _assemblyExclusionPredicates.Add(assembly => assembly.GetName().Name == "mscorlib"); - _assemblyExclusionPredicates.Add(assembly => assembly.GetName().Name == "System"); - } - - /// - /// Scans the and register types. - /// - /// The registry within which to register the types. - public virtual void ScanAndRegisterTypes(IObjectDefinitionRegistry registry) - { - IEnumerable configTypes = Scan(); - RegisterDefinitionsForTypes(registry, configTypes); - } - - /// - /// Initializes a new instance of the class. - /// - public AssemblyObjectDefinitionScanner() - { - AssemblyLoadExclusionPredicates.Add(candidate => - { - if ("Spring.Core.Tests".Equals(candidate, StringComparison.OrdinalIgnoreCase)) - { - return false; - } - foreach (var prefix in _springAssemblyExcludePrefixes) - { - if (candidate.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)) - { - return true; - } - } - - return false; - }); - AssemblyLoadExclusionPredicates.Add(name => name.StartsWith("System.")); - AssemblyLoadExclusionPredicates.Add(name => name.StartsWith("Microsoft.")); - AssemblyLoadExclusionPredicates.Add(name => name == "mscorlib"); - AssemblyLoadExclusionPredicates.Add(name => name == "System"); - } - - - /// - /// Initializes a new instance of the class. - /// - /// The assemblies to include predicates. - public AssemblyObjectDefinitionScanner(params Func[] assembliesToIncludePredicates) - { - //force exclude for ALL assemblies - AssemblyLoadExclusionPredicates.Add(name => true); - - //since all assemblies are EXCLUDED above, these will be the ONLY assemblies to be loaded - foreach (var predicate in assembliesToIncludePredicates) - { - AssemblyLoadInclusionPredicates.Add(predicate); - } - } - - /// - /// Initializes a new instance of the class. - /// - /// The names of assemblies to include. - public AssemblyObjectDefinitionScanner(params string[] assembliesToInclude) - : this(name => assembliesToInclude.Any(candidate => candidate == name)) - { - AssertUtils.ArgumentNotNull(assembliesToInclude, "assembliesToInclude"); + Logger.LogDebug("Register Type: {FullName} with object name {ObjectName}", fullname, objectName); + registry.RegisterObjectDefinition(objectName, definition); } } + + /// + /// Applies the assembly filters to the assembly candidates. + /// + /// The assembly candidates. + /// + protected override IEnumerable ApplyAssemblyFiltersTo(IEnumerable assemblyCandidates) + { + foreach (Assembly candidate in assemblyCandidates) + { + if (IsIncludedAssembly(candidate) && !IsExcludedAssembly(candidate)) + { + yield return candidate; + } + } + } + + /// + /// Determines whether the specified candidate is and excluded assembly. + /// + /// The candidate. + /// + /// true if the specified candidate is an excluded assembly ; otherwise, false. + /// + protected virtual bool IsExcludedAssembly(Assembly candidate) + { + return _assemblyExclusionPredicates.Any(exclude => exclude(candidate)); + } + + /// + /// Determines whether the required constraint is satisfied by the specified type. + /// + /// The type. + /// + /// true if the required constraint is satisfied by the specified type; otherwise, false. + /// + protected override bool IsRequiredConstraintSatisfiedBy(Type type) + { + if (!type.Assembly.ReflectionOnly) + { + try + { + return Attribute.GetCustomAttribute(type, typeof(ComponentAttribute), true) != null && + !type.IsAbstract; + } + catch (AmbiguousMatchException) + { + Logger.LogError("Type {Type} has more than one ComponentAttributes assigned to it.", type.FullName); + return false; + } + } + + bool satisfied = false; + + foreach (CustomAttributeData customAttributeData in CustomAttributeData.GetCustomAttributes(type)) + { + if (customAttributeData.Constructor.DeclaringType != null && + (customAttributeData.Constructor.DeclaringType.FullName == typeof(ComponentAttribute).FullName && + !type.IsAbstract)) + { + satisfied = true; + break; + } + } + + return satisfied; + } + + /// + /// Sets the default filters. + /// + protected override void SetDefaultFilters() + { + //set the built-in defaults + base.SetDefaultFilters(); + + //add the desired assembly exclusions to the list + _assemblyExclusionPredicates.Add(assembly => + { + var assemblyName = assembly.GetName().Name; + if ("Spring.Core.Tests".Equals(assemblyName, StringComparison.OrdinalIgnoreCase)) + { + return false; + } + + for (var i = 0; i < _springAssemblyExcludePrefixes.Count; i++) + { + var name = _springAssemblyExcludePrefixes[i]; + if (assemblyName.StartsWith(name, StringComparison.OrdinalIgnoreCase)) + { + return true; + } + } + + return false; + }); + _assemblyExclusionPredicates.Add(assembly => assembly.GetName().Name.StartsWith("System.")); + _assemblyExclusionPredicates.Add(assembly => assembly.GetName().Name.StartsWith("Microsoft.")); + _assemblyExclusionPredicates.Add(assembly => assembly.GetName().Name == "mscorlib"); + _assemblyExclusionPredicates.Add(assembly => assembly.GetName().Name == "System"); + } + + /// + /// Scans the and register types. + /// + /// The registry within which to register the types. + public virtual void ScanAndRegisterTypes(IObjectDefinitionRegistry registry) + { + IEnumerable configTypes = Scan(); + RegisterDefinitionsForTypes(registry, configTypes); + } + + /// + /// Initializes a new instance of the class. + /// + public AssemblyObjectDefinitionScanner() + { + AssemblyLoadExclusionPredicates.Add(candidate => + { + if ("Spring.Core.Tests".Equals(candidate, StringComparison.OrdinalIgnoreCase)) + { + return false; + } + + foreach (var prefix in _springAssemblyExcludePrefixes) + { + if (candidate.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)) + { + return true; + } + } + + return false; + }); + AssemblyLoadExclusionPredicates.Add(name => name.StartsWith("System.")); + AssemblyLoadExclusionPredicates.Add(name => name.StartsWith("Microsoft.")); + AssemblyLoadExclusionPredicates.Add(name => name == "mscorlib"); + AssemblyLoadExclusionPredicates.Add(name => name == "System"); + } + + /// + /// Initializes a new instance of the class. + /// + /// The assemblies to include predicates. + public AssemblyObjectDefinitionScanner(params Func[] assembliesToIncludePredicates) + { + //force exclude for ALL assemblies + AssemblyLoadExclusionPredicates.Add(name => true); + + //since all assemblies are EXCLUDED above, these will be the ONLY assemblies to be loaded + foreach (var predicate in assembliesToIncludePredicates) + { + AssemblyLoadInclusionPredicates.Add(predicate); + } + } + + /// + /// Initializes a new instance of the class. + /// + /// The names of assemblies to include. + public AssemblyObjectDefinitionScanner(params string[] assembliesToInclude) + : this(name => assembliesToInclude.Any(candidate => candidate == name)) + { + AssertUtils.ArgumentNotNull(assembliesToInclude, "assembliesToInclude"); + } } diff --git a/src/Spring/Spring.Core/Context/Attributes/AssemblyTypeScanner.cs b/src/Spring/Spring.Core/Context/Attributes/AssemblyTypeScanner.cs index 5030de35..5d89d52f 100644 --- a/src/Spring/Spring.Core/Context/Attributes/AssemblyTypeScanner.cs +++ b/src/Spring/Spring.Core/Context/Attributes/AssemblyTypeScanner.cs @@ -24,431 +24,431 @@ using Spring.Context.Attributes.TypeFilters; using Spring.Util; using Spring.Objects.Factory.Xml; -namespace Spring.Context.Attributes +namespace Spring.Context.Attributes; + +/// +/// Scans Assebmlies for Types that satisfy a given set of constraints. +/// +[Serializable] +public abstract class AssemblyTypeScanner : IAssemblyTypeScanner { /// - /// Scans Assebmlies for Types that satisfy a given set of constraints. + /// Logger Instance. /// - [Serializable] - public abstract class AssemblyTypeScanner : IAssemblyTypeScanner + protected static readonly ILogger Logger = LogManager.GetLogger(); + + /// + /// Names of Assemblies to exclude from being loaded for scanning. + /// + protected IList> AssemblyLoadExclusionPredicates = new List>(); + + /// + /// Names of Assemblies to include for scanning. + /// + protected IList> AssemblyLoadInclusionPredicates = new List>(); + + /// + /// Assembly Inclusion Predicates. + /// + protected readonly List> AssemblyInclusionPredicates = new List>(); + + /// + /// Type Exclusion Predicates. + /// + protected readonly List> TypeExclusionPredicates = new List>(); + + /// + /// Type Exclusion Predicates. + /// + protected readonly List TypeExclusionTypeFilters = new List(); + + /// + /// Type Inclusion Predicates. + /// + protected readonly List> TypeInclusionPredicates = new List>(); + + /// + /// Type Inclusion TypeFilters. + /// + protected readonly List TypeInclusionTypeFilter = new List(); + + /// + /// Assemblies to scan. + /// + protected readonly List> TypeSources = new List>(); + + /// + /// Stores the object default definitons defined in the XML configuration documnet + /// + private DocumentDefaultsDefinition _defaults; + + private string _scanStartFolderPath; + + /// + /// Stores the object default definitons defined in the XML configuration documnet + /// + public DocumentDefaultsDefinition Defaults { - /// - /// Logger Instance. - /// - protected static readonly ILogger Logger = LogManager.GetLogger(); + get { return _defaults; } + set { _defaults = value; } + } - /// - /// Names of Assemblies to exclude from being loaded for scanning. - /// - protected IList> AssemblyLoadExclusionPredicates = new List>(); - - /// - /// Names of Assemblies to include for scanning. - /// - protected IList> AssemblyLoadInclusionPredicates = new List>(); - - /// - /// Assembly Inclusion Predicates. - /// - protected readonly List> AssemblyInclusionPredicates = new List>(); - - /// - /// Type Exclusion Predicates. - /// - protected readonly List> TypeExclusionPredicates = new List>(); - - /// - /// Type Exclusion Predicates. - /// - protected readonly List TypeExclusionTypeFilters = new List(); - - /// - /// Type Inclusion Predicates. - /// - protected readonly List> TypeInclusionPredicates = new List>(); - - /// - /// Type Inclusion TypeFilters. - /// - protected readonly List TypeInclusionTypeFilter = new List(); - - /// - /// Assemblies to scan. - /// - protected readonly List> TypeSources = new List>(); - - /// - /// Stores the object default definitons defined in the XML configuration documnet - /// - private DocumentDefaultsDefinition _defaults; - - private string _scanStartFolderPath; - - - /// - /// Stores the object default definitons defined in the XML configuration documnet - /// - public DocumentDefaultsDefinition Defaults + public string ScanStartFolderPath + { + get { - get { return _defaults; } - set { _defaults = value; } - } - - public string ScanStartFolderPath - { - get + //if we have no value, set it to the current bin dir + if (string.IsNullOrEmpty(_scanStartFolderPath)) { - //if we have no value, set it to the current bin dir - if (string.IsNullOrEmpty(_scanStartFolderPath)) - { - _scanStartFolderPath = GetCurrentBinDirectoryPath(); - } - return _scanStartFolderPath; - } - set { _scanStartFolderPath = value; } - } - - #region IAssemblyTypeScanner Members - - /// - /// Assemblies the type of the having. - /// - /// - /// - public IAssemblyTypeScanner AssemblyHavingType() - { - TypeSources.Add(new AssemblyTypeSource((typeof(T).Assembly))); - return this; - } - - /// - /// Excludes the type. - /// - /// - /// - public IAssemblyTypeScanner ExcludeType() - { - TypeExclusionPredicates.Add(t => t.FullName == typeof(T).FullName); - return this; - } - - /// - /// Includes the type. - /// - /// - /// - public IAssemblyTypeScanner IncludeType() - { - TypeInclusionPredicates.Add(t => t.FullName == typeof(T).FullName); - return this; - } - - /// - /// Includes the types. - /// - /// The type source. - /// - public IAssemblyTypeScanner IncludeTypes(IEnumerable typeSource) - { - AssertUtils.ArgumentNotNull(typeSource, "typeSource"); - TypeSources.Add(typeSource); - TypeInclusionPredicates.Add( - t => typeSource.Any(t1 => t1.FullName == t.FullName)); - return this; - } - - /// - /// Performs the Scan, respecting all filter settings. - /// - /// - public virtual IEnumerable Scan() - { - SetDefaultFilters(); - - IList types = new List(); - - foreach (Assembly assembly in GetAllMatchingAssemblies(ScanStartFolderPath)) - { - TypeSources.Add(new AssemblyTypeSource(assembly)); + _scanStartFolderPath = GetCurrentBinDirectoryPath(); } - foreach (var typeSource in TypeSources) + return _scanStartFolderPath; + } + set { _scanStartFolderPath = value; } + } + + #region IAssemblyTypeScanner Members + + /// + /// Assemblies the type of the having. + /// + /// + /// + public IAssemblyTypeScanner AssemblyHavingType() + { + TypeSources.Add(new AssemblyTypeSource((typeof(T).Assembly))); + return this; + } + + /// + /// Excludes the type. + /// + /// + /// + public IAssemblyTypeScanner ExcludeType() + { + TypeExclusionPredicates.Add(t => t.FullName == typeof(T).FullName); + return this; + } + + /// + /// Includes the type. + /// + /// + /// + public IAssemblyTypeScanner IncludeType() + { + TypeInclusionPredicates.Add(t => t.FullName == typeof(T).FullName); + return this; + } + + /// + /// Includes the types. + /// + /// The type source. + /// + public IAssemblyTypeScanner IncludeTypes(IEnumerable typeSource) + { + AssertUtils.ArgumentNotNull(typeSource, "typeSource"); + TypeSources.Add(typeSource); + TypeInclusionPredicates.Add(t => typeSource.Any(t1 => t1.FullName == t.FullName)); + return this; + } + + /// + /// Performs the Scan, respecting all filter settings. + /// + /// + public virtual IEnumerable Scan() + { + SetDefaultFilters(); + + IList types = new List(); + + foreach (Assembly assembly in GetAllMatchingAssemblies(ScanStartFolderPath)) + { + TypeSources.Add(new AssemblyTypeSource(assembly)); + } + + foreach (var typeSource in TypeSources) + { + foreach (Type type in typeSource) { - foreach (Type type in typeSource) - { - if (IsCompoundPredicateSatisfiedBy(type)) - { - if (Logger.IsEnabled(LogLevel.Debug)) - { - Logger.LogDebug("Satisfied Type: {FullName}", type.FullName); - } - types.Add(type); - } - } - } - - return types; - } - - /// - /// Adds the assembly filter. - /// - /// The assembly predicate. - /// - public IAssemblyTypeScanner WithAssemblyFilter(Func assemblyPredicate) - { - AssemblyInclusionPredicates.Add(assemblyPredicate); - return this; - } - - /// - /// Adds the exclude filter. - /// - /// The predicate. - /// - public IAssemblyTypeScanner WithExcludeFilter(Func predicate) - { - TypeExclusionPredicates.Add(predicate); - return this; - } - - /// - /// Adds the exclude filter. - /// - /// The type filter. - /// - public IAssemblyTypeScanner WithExcludeFilter(ITypeFilter filter) - { - if (filter != null) - TypeExclusionTypeFilters.Add(filter); - - return this; - } - - /// - /// Adds the include filter. - /// - /// The predicate. - /// - public IAssemblyTypeScanner WithIncludeFilter(Func predicate) - { - TypeInclusionPredicates.Add(predicate); - return this; - } - - /// - /// Adds the include filter. - /// - /// The filter type. - /// - public IAssemblyTypeScanner WithIncludeFilter(ITypeFilter filter) - { - if (filter != null) - TypeInclusionTypeFilter.Add(filter); - - return this; - } - - #endregion - - private List GetAllAssembliesInPath(string folderPath) - { - var assemblies = new List(); - assemblies.AddRange(DiscoverAssemblies(folderPath, "*.dll")); - assemblies.AddRange(DiscoverAssemblies(folderPath, "*.exe")); - - if (Logger.IsEnabled(LogLevel.Debug)) - { - Logger.LogDebug("Assemblies to be scanned: {AssemblyNames}", StringUtils.ArrayToCommaDelimitedString(assemblies.ToArray())); - } - - return assemblies; - } - - private IEnumerable GetAllMatchingAssemblies(string folderPath) - { - IEnumerable assemblyCandidates = GetAllAssembliesInPath(folderPath); - - IList assemblies = new List(); - - foreach (string assembly in assemblyCandidates) - { - if (!string.IsNullOrEmpty(assembly)) - { - Assembly loadedAssembly = TryLoadAssemblyFromPath(assembly); - - if (null != loadedAssembly) - { - string fullname = loadedAssembly.FullName; - Logger.LogDebug("Add Assembly: {FullName}", fullname); - - assemblies.Add(loadedAssembly); - } - } - } - - return ApplyAssemblyFiltersTo(assemblies); - } - - private Assembly TryLoadAssemblyFromPath(string filename) - { - Assembly assembly = null; - - try - { - assembly = Assembly.LoadFrom(filename); - } - catch (Exception ex) - { - //log and swallow everything that might go wrong here... - Logger.LogDebug(ex, "Failed to load assembly {FileName} to inspect for [Configuration] types!", filename); - } - - return assembly; - } - - private string GetCurrentBinDirectoryPath() - { - return string.IsNullOrEmpty(AppDomain.CurrentDomain.DynamicDirectory) - ? AppDomain.CurrentDomain.BaseDirectory - : AppDomain.CurrentDomain.DynamicDirectory; - } - - /// - /// Applies the assembly filters to the assembly candidates. - /// - /// The assembly candidates. - /// - protected virtual IEnumerable ApplyAssemblyFiltersTo(IEnumerable assemblyCandidates) - { - var filteredAssemblies = assemblyCandidates.Where(IsIncludedAssembly).ToList(); - - if (Logger.IsEnabled(LogLevel.Debug)) - { - Logger.LogDebug("Filtered Assemblies: {0}", StringUtils.ArrayToCommaDelimitedString(filteredAssemblies)); - } - - return filteredAssemblies; - } - - /// - /// Determines whether the compound predicate is satisfied by the specified type. - /// - /// The type. - /// - /// true if the compound predicate is satisfied by the specified type; otherwise, false. - /// - protected abstract bool IsCompoundPredicateSatisfiedBy(Type type); - - /// - /// Determines whether [is excluded type] [the specified type]. - /// - /// The type. - /// - /// true if [is excluded type] [the specified type]; otherwise, false. - /// - protected virtual bool IsExcludedType(Type type) - { - if (TypeExclusionPredicates.Count > 0 && TypeExclusionPredicates.Any(exclude => exclude(type))) - return true; - - return Enumerable.Any(TypeExclusionTypeFilters, filter => filter.Match(type)); - } - - /// - /// Determines whether [is included assembly] [the specified assembly]. - /// - /// The assembly. - /// - /// true if [is included assembly] [the specified assembly]; otherwise, false. - /// - protected virtual bool IsIncludedAssembly(Assembly assembly) - { - foreach (var include in AssemblyInclusionPredicates) - { - if (include(assembly)) + if (IsCompoundPredicateSatisfiedBy(type)) { if (Logger.IsEnabled(LogLevel.Debug)) { - Logger.LogDebug("Include Assembly: {FullName}", assembly.FullName); + Logger.LogDebug("Satisfied Type: {FullName}", type.FullName); } - return true; + + types.Add(type); } } - return false; } - /// - /// Determines whether [is included type] [the specified type]. - /// - /// The type. - /// - /// true if [is included type] [the specified type]; otherwise, false. - /// - protected virtual bool IsIncludedType(Type type) - { - for (var i = 0; i < TypeInclusionPredicates.Count; i++) - { - var include = TypeInclusionPredicates[i]; - if (include(type)) - { - return true; - } - } - - for (var i = 0; i < TypeInclusionTypeFilter.Count; i++) - { - var filter = TypeInclusionTypeFilter[i]; - if (filter.Match(type)) - { - return true; - } - } - - return false; - } - - /// - /// Sets the default filters. - /// - protected virtual void SetDefaultFilters() - { - if (TypeInclusionPredicates.Count == 0 && TypeInclusionTypeFilter.Count == 0) - TypeInclusionPredicates.Add(obj => true); - - if (TypeExclusionPredicates.Count == 0 && TypeExclusionTypeFilters.Count == 0) - TypeExclusionPredicates.Add(obj => false); - - if (AssemblyInclusionPredicates.Count == 0) - AssemblyInclusionPredicates.Add(obj => true); - } - - /// - /// Loads the assemblies found. - /// - /// The folder path. - /// The extension. - private IList DiscoverAssemblies(string folderPath, string extension) - { - IList assemblies = new List(); - - string[] files = Directory.GetFiles(folderPath, extension, SearchOption.AllDirectories); - - foreach (string file in files) - { - string name = Path.GetFileNameWithoutExtension(file); - - bool isNotExcluded = !AssemblyLoadExclusionPredicates.Any(exclude => exclude(name)); - bool isIncluded = AssemblyLoadInclusionPredicates.Any(include => include(name)); - - if (isNotExcluded || isIncluded) - { - assemblies.Add(file); - } - - } - - return assemblies; - } + return types; } -} + + /// + /// Adds the assembly filter. + /// + /// The assembly predicate. + /// + public IAssemblyTypeScanner WithAssemblyFilter(Func assemblyPredicate) + { + AssemblyInclusionPredicates.Add(assemblyPredicate); + return this; + } + + /// + /// Adds the exclude filter. + /// + /// The predicate. + /// + public IAssemblyTypeScanner WithExcludeFilter(Func predicate) + { + TypeExclusionPredicates.Add(predicate); + return this; + } + + /// + /// Adds the exclude filter. + /// + /// The type filter. + /// + public IAssemblyTypeScanner WithExcludeFilter(ITypeFilter filter) + { + if (filter != null) + TypeExclusionTypeFilters.Add(filter); + + return this; + } + + /// + /// Adds the include filter. + /// + /// The predicate. + /// + public IAssemblyTypeScanner WithIncludeFilter(Func predicate) + { + TypeInclusionPredicates.Add(predicate); + return this; + } + + /// + /// Adds the include filter. + /// + /// The filter type. + /// + public IAssemblyTypeScanner WithIncludeFilter(ITypeFilter filter) + { + if (filter != null) + TypeInclusionTypeFilter.Add(filter); + + return this; + } + + #endregion + + private List GetAllAssembliesInPath(string folderPath) + { + var assemblies = new List(); + assemblies.AddRange(DiscoverAssemblies(folderPath, "*.dll")); + assemblies.AddRange(DiscoverAssemblies(folderPath, "*.exe")); + + if (Logger.IsEnabled(LogLevel.Debug)) + { + Logger.LogDebug("Assemblies to be scanned: {AssemblyNames}", StringUtils.ArrayToCommaDelimitedString(assemblies.ToArray())); + } + + return assemblies; + } + + private IEnumerable GetAllMatchingAssemblies(string folderPath) + { + IEnumerable assemblyCandidates = GetAllAssembliesInPath(folderPath); + + IList assemblies = new List(); + + foreach (string assembly in assemblyCandidates) + { + if (!string.IsNullOrEmpty(assembly)) + { + Assembly loadedAssembly = TryLoadAssemblyFromPath(assembly); + + if (null != loadedAssembly) + { + string fullname = loadedAssembly.FullName; + Logger.LogDebug("Add Assembly: {FullName}", fullname); + + assemblies.Add(loadedAssembly); + } + } + } + + return ApplyAssemblyFiltersTo(assemblies); + } + + private Assembly TryLoadAssemblyFromPath(string filename) + { + Assembly assembly = null; + + try + { + assembly = Assembly.LoadFrom(filename); + } + catch (Exception ex) + { + //log and swallow everything that might go wrong here... + Logger.LogDebug(ex, "Failed to load assembly {FileName} to inspect for [Configuration] types!", filename); + } + + return assembly; + } + + private string GetCurrentBinDirectoryPath() + { + return string.IsNullOrEmpty(AppDomain.CurrentDomain.DynamicDirectory) + ? AppDomain.CurrentDomain.BaseDirectory + : AppDomain.CurrentDomain.DynamicDirectory; + } + + /// + /// Applies the assembly filters to the assembly candidates. + /// + /// The assembly candidates. + /// + protected virtual IEnumerable ApplyAssemblyFiltersTo(IEnumerable assemblyCandidates) + { + var filteredAssemblies = assemblyCandidates.Where(IsIncludedAssembly).ToList(); + + if (Logger.IsEnabled(LogLevel.Debug)) + { + Logger.LogDebug("Filtered Assemblies: {0}", StringUtils.ArrayToCommaDelimitedString(filteredAssemblies)); + } + + return filteredAssemblies; + } + + /// + /// Determines whether the compound predicate is satisfied by the specified type. + /// + /// The type. + /// + /// true if the compound predicate is satisfied by the specified type; otherwise, false. + /// + protected abstract bool IsCompoundPredicateSatisfiedBy(Type type); + + /// + /// Determines whether [is excluded type] [the specified type]. + /// + /// The type. + /// + /// true if [is excluded type] [the specified type]; otherwise, false. + /// + protected virtual bool IsExcludedType(Type type) + { + if (TypeExclusionPredicates.Count > 0 && TypeExclusionPredicates.Any(exclude => exclude(type))) + return true; + + return Enumerable.Any(TypeExclusionTypeFilters, filter => filter.Match(type)); + } + + /// + /// Determines whether [is included assembly] [the specified assembly]. + /// + /// The assembly. + /// + /// true if [is included assembly] [the specified assembly]; otherwise, false. + /// + protected virtual bool IsIncludedAssembly(Assembly assembly) + { + foreach (var include in AssemblyInclusionPredicates) + { + if (include(assembly)) + { + if (Logger.IsEnabled(LogLevel.Debug)) + { + Logger.LogDebug("Include Assembly: {FullName}", assembly.FullName); + } + + return true; + } + } + + return false; + } + + /// + /// Determines whether [is included type] [the specified type]. + /// + /// The type. + /// + /// true if [is included type] [the specified type]; otherwise, false. + /// + protected virtual bool IsIncludedType(Type type) + { + for (var i = 0; i < TypeInclusionPredicates.Count; i++) + { + var include = TypeInclusionPredicates[i]; + if (include(type)) + { + return true; + } + } + + for (var i = 0; i < TypeInclusionTypeFilter.Count; i++) + { + var filter = TypeInclusionTypeFilter[i]; + if (filter.Match(type)) + { + return true; + } + } + + return false; + } + + /// + /// Sets the default filters. + /// + protected virtual void SetDefaultFilters() + { + if (TypeInclusionPredicates.Count == 0 && TypeInclusionTypeFilter.Count == 0) + TypeInclusionPredicates.Add(obj => true); + + if (TypeExclusionPredicates.Count == 0 && TypeExclusionTypeFilters.Count == 0) + TypeExclusionPredicates.Add(obj => false); + + if (AssemblyInclusionPredicates.Count == 0) + AssemblyInclusionPredicates.Add(obj => true); + } + + /// + /// Loads the assemblies found. + /// + /// The folder path. + /// The extension. + private IList DiscoverAssemblies(string folderPath, string extension) + { + IList assemblies = new List(); + + string[] files = Directory.GetFiles(folderPath, extension, SearchOption.AllDirectories); + + foreach (string file in files) + { + string name = Path.GetFileNameWithoutExtension(file); + + bool isNotExcluded = !AssemblyLoadExclusionPredicates.Any(exclude => exclude(name)); + bool isIncluded = AssemblyLoadInclusionPredicates.Any(include => include(name)); + + if (isNotExcluded || isIncluded) + { + assemblies.Add(file); + } + } + + return assemblies; + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Context/Attributes/AssemblyTypeSource.cs b/src/Spring/Spring.Core/Context/Attributes/AssemblyTypeSource.cs index ac6ee235..bb886aba 100644 --- a/src/Spring/Spring.Core/Context/Attributes/AssemblyTypeSource.cs +++ b/src/Spring/Spring.Core/Context/Attributes/AssemblyTypeSource.cs @@ -23,65 +23,63 @@ using System.Reflection; using Microsoft.Extensions.Logging; using Spring.Util; -namespace Spring.Context.Attributes +namespace Spring.Context.Attributes; + +/// +/// Represents a collection of Types. +/// +[Serializable] +public class AssemblyTypeSource : IEnumerable { /// - /// Represents a collection of Types. + /// Logger Instance. /// - [Serializable] - public class AssemblyTypeSource : IEnumerable + protected static readonly ILogger Logger = LogManager.GetLogger(); + + private readonly Assembly _assembly; + + /// + /// Initializes a new instance of the class. + /// + /// The assembly. + public AssemblyTypeSource(Assembly assembly) { - /// - /// Logger Instance. - /// - protected static readonly ILogger Logger = LogManager.GetLogger(); - - private readonly Assembly _assembly; - - /// - /// Initializes a new instance of the class. - /// - /// The assembly. - public AssemblyTypeSource(Assembly assembly) - { - AssertUtils.ArgumentNotNull(assembly, "assembly"); - _assembly = assembly; - } - - #region IEnumerable Members - - /// - /// Gets the enumerator. - /// - /// - public IEnumerator GetEnumerator() - { - Type[] types = new Type[]{}; - try - { - types = _assembly.GetTypes(); - } - catch (ReflectionTypeLoadException ex) - { - //log and swallow everything that might go wrong here... - Logger.LogDebug(ex, "Failed to get types {LoaderExceptions}", ex.LoaderExceptions); - } - catch (Exception ex) - { - //log and swallow everything that might go wrong here... - Logger.LogDebug(ex, "Failed to get types"); - } - - - foreach (Type type in types) - yield return type; - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - #endregion + AssertUtils.ArgumentNotNull(assembly, "assembly"); + _assembly = assembly; } -} + + #region IEnumerable Members + + /// + /// Gets the enumerator. + /// + /// + public IEnumerator GetEnumerator() + { + Type[] types = new Type[] { }; + try + { + types = _assembly.GetTypes(); + } + catch (ReflectionTypeLoadException ex) + { + //log and swallow everything that might go wrong here... + Logger.LogDebug(ex, "Failed to get types {LoaderExceptions}", ex.LoaderExceptions); + } + catch (Exception ex) + { + //log and swallow everything that might go wrong here... + Logger.LogDebug(ex, "Failed to get types"); + } + + foreach (Type type in types) + yield return type; + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + #endregion +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Context/Attributes/AttributeConfigUtils.cs b/src/Spring/Spring.Core/Context/Attributes/AttributeConfigUtils.cs index 365c69ac..2e120a2b 100644 --- a/src/Spring/Spring.Core/Context/Attributes/AttributeConfigUtils.cs +++ b/src/Spring/Spring.Core/Context/Attributes/AttributeConfigUtils.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2010-2011 the original author or authors. + * Copyright � 2010-2011 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. @@ -22,83 +22,79 @@ using Spring.Objects.Factory.Attributes; using Spring.Objects.Factory.Config; using Spring.Objects.Factory.Support; -namespace Spring.Context.Attributes +namespace Spring.Context.Attributes; + +/// +/// Utility class that allows for convenient registration of common +/// and definitions for attribute based configuration +/// +/// +/// +/// +/// Mark Pollack (.NET) +/// Mark Fisher +/// Juergen Hoeller +/// Chris Beams +public class AttributeConfigUtils { /// - /// Utility class that allows for convenient registration of common - /// and definitions for attribute based configuration + /// The object name of the internally managed Configuration attribute processor. /// - /// - /// - /// - /// Mark Pollack (.NET) - /// Mark Fisher - /// Juergen Hoeller - /// Chris Beams - public class AttributeConfigUtils + public static readonly string CONFIGURATION_ATTRIBUTE_PROCESSOR_OBJECT_NAME = + "Spring.Context.Attributes.InternalConfigurationClassPostProcessor"; + + /// + /// The object name of the internally managed Autowire attribute processor + /// + public static readonly string AUTOWIRED_ATTRIBUTE_PROCESSOR_OBJECT_NAME = + "Spring.Context.Attributes.InternalAutowiredClassPostProcessor"; + + /// + ///The object name of the internally managed Required attribute processor. + /// + public static readonly string REQUIRED_ATTRIBUTE_PROCESSOR_OBJECT_NAME = + "Spring.Context.Attributes.InternalRequiredClassPostProcessor"; + + /// + ///The object name of the internally managed InitDestroy attribute processor. + /// + public static readonly string INITDESTROY_ATTRIBUTE_PROCESSOR_OBJECT_NAME = + "Spring.Context.Attributes.InternalInitDestroyClassPostProcessor"; + + /// + /// Registers the attribute config processors. + /// + /// The registry. + public static void RegisterAttributeConfigProcessors(IObjectDefinitionRegistry registry) { - - /// - /// The object name of the internally managed Configuration attribute processor. - /// - public static readonly string CONFIGURATION_ATTRIBUTE_PROCESSOR_OBJECT_NAME = - "Spring.Context.Attributes.InternalConfigurationClassPostProcessor"; - - /// - /// The object name of the internally managed Autowire attribute processor - /// - public static readonly string AUTOWIRED_ATTRIBUTE_PROCESSOR_OBJECT_NAME = - "Spring.Context.Attributes.InternalAutowiredClassPostProcessor"; - - /// - ///The object name of the internally managed Required attribute processor. - /// - public static readonly string REQUIRED_ATTRIBUTE_PROCESSOR_OBJECT_NAME = - "Spring.Context.Attributes.InternalRequiredClassPostProcessor"; - - /// - ///The object name of the internally managed InitDestroy attribute processor. - /// - public static readonly string INITDESTROY_ATTRIBUTE_PROCESSOR_OBJECT_NAME = - "Spring.Context.Attributes.InternalInitDestroyClassPostProcessor"; - - - /// - /// Registers the attribute config processors. - /// - /// The registry. - public static void RegisterAttributeConfigProcessors(IObjectDefinitionRegistry registry) + if (!registry.ContainsObjectDefinition(CONFIGURATION_ATTRIBUTE_PROCESSOR_OBJECT_NAME)) { - if (!registry.ContainsObjectDefinition(CONFIGURATION_ATTRIBUTE_PROCESSOR_OBJECT_NAME)) - { - RootObjectDefinition objectDefinition = new RootObjectDefinition(typeof(ConfigurationClassPostProcessor)); - RegisterPostProcessor(registry, objectDefinition, CONFIGURATION_ATTRIBUTE_PROCESSOR_OBJECT_NAME); - } - - if (!registry.ContainsObjectDefinition(AUTOWIRED_ATTRIBUTE_PROCESSOR_OBJECT_NAME)) - { - RootObjectDefinition objectDefinition = new RootObjectDefinition(typeof(AutowiredAttributeObjectPostProcessor)); - RegisterPostProcessor(registry, objectDefinition, AUTOWIRED_ATTRIBUTE_PROCESSOR_OBJECT_NAME); - } - - if (!registry.ContainsObjectDefinition(REQUIRED_ATTRIBUTE_PROCESSOR_OBJECT_NAME)) - { - RootObjectDefinition objectDefinition = new RootObjectDefinition(typeof(RequiredAttributeObjectPostProcessor)); - RegisterPostProcessor(registry, objectDefinition, REQUIRED_ATTRIBUTE_PROCESSOR_OBJECT_NAME); - } - - if (!registry.ContainsObjectDefinition(INITDESTROY_ATTRIBUTE_PROCESSOR_OBJECT_NAME)) - { - RootObjectDefinition objectDefinition = new RootObjectDefinition(typeof(InitDestroyAttributeObjectPostProcessor)); - RegisterPostProcessor(registry, objectDefinition, INITDESTROY_ATTRIBUTE_PROCESSOR_OBJECT_NAME); - } + RootObjectDefinition objectDefinition = new RootObjectDefinition(typeof(ConfigurationClassPostProcessor)); + RegisterPostProcessor(registry, objectDefinition, CONFIGURATION_ATTRIBUTE_PROCESSOR_OBJECT_NAME); } - private static void RegisterPostProcessor(IObjectDefinitionRegistry registry, IConfigurableObjectDefinition objectDefinition, string objectName) + if (!registry.ContainsObjectDefinition(AUTOWIRED_ATTRIBUTE_PROCESSOR_OBJECT_NAME)) { - objectDefinition.Role = ObjectRole.ROLE_INFRASTRUCTURE; - registry.RegisterObjectDefinition(objectName, objectDefinition); + RootObjectDefinition objectDefinition = new RootObjectDefinition(typeof(AutowiredAttributeObjectPostProcessor)); + RegisterPostProcessor(registry, objectDefinition, AUTOWIRED_ATTRIBUTE_PROCESSOR_OBJECT_NAME); + } + + if (!registry.ContainsObjectDefinition(REQUIRED_ATTRIBUTE_PROCESSOR_OBJECT_NAME)) + { + RootObjectDefinition objectDefinition = new RootObjectDefinition(typeof(RequiredAttributeObjectPostProcessor)); + RegisterPostProcessor(registry, objectDefinition, REQUIRED_ATTRIBUTE_PROCESSOR_OBJECT_NAME); + } + + if (!registry.ContainsObjectDefinition(INITDESTROY_ATTRIBUTE_PROCESSOR_OBJECT_NAME)) + { + RootObjectDefinition objectDefinition = new RootObjectDefinition(typeof(InitDestroyAttributeObjectPostProcessor)); + RegisterPostProcessor(registry, objectDefinition, INITDESTROY_ATTRIBUTE_PROCESSOR_OBJECT_NAME); } } + private static void RegisterPostProcessor(IObjectDefinitionRegistry registry, IConfigurableObjectDefinition objectDefinition, string objectName) + { + objectDefinition.Role = ObjectRole.ROLE_INFRASTRUCTURE; + registry.RegisterObjectDefinition(objectName, objectDefinition); + } } \ No newline at end of file diff --git a/src/Spring/Spring.Core/Context/Attributes/AttributeObjectNameGenerator.cs b/src/Spring/Spring.Core/Context/Attributes/AttributeObjectNameGenerator.cs index f98c1da2..59e6c930 100644 --- a/src/Spring/Spring.Core/Context/Attributes/AttributeObjectNameGenerator.cs +++ b/src/Spring/Spring.Core/Context/Attributes/AttributeObjectNameGenerator.cs @@ -21,39 +21,39 @@ using Spring.Objects.Factory.Config; using Spring.Objects.Factory.Support; -namespace Spring.Context.Attributes +namespace Spring.Context.Attributes; + +/// +/// Default Name Generator for attribute driven component scan. +/// +/// First choice is the provided name of the Component attribute. +/// Fallback is the short type name. +/// +public class AttributeObjectNameGenerator : IObjectNameGenerator { /// - /// Default Name Generator for attribute driven component scan. - /// - /// First choice is the provided name of the Component attribute. - /// Fallback is the short type name. + /// Generates an object name for the given object definition. /// - public class AttributeObjectNameGenerator : IObjectNameGenerator + /// The object definition to generate a name for. + /// The object definitions registry that the given definition is + /// supposed to be registerd with + /// + /// the generated object name + /// + public string GenerateObjectName(IObjectDefinition definition, IObjectDefinitionRegistry registry) { - /// - /// Generates an object name for the given object definition. - /// - /// The object definition to generate a name for. - /// The object definitions registry that the given definition is - /// supposed to be registerd with - /// - /// the generated object name - /// - public string GenerateObjectName(IObjectDefinition definition, IObjectDefinitionRegistry registry) + if (definition is ScannedGenericObjectDefinition) { - if (definition is ScannedGenericObjectDefinition) - { - string objectName = ((ScannedGenericObjectDefinition) definition).ComponentName; - if (!string.IsNullOrEmpty(objectName)) - return objectName; - } - return BuildDefaultObjectName(definition); + string objectName = ((ScannedGenericObjectDefinition) definition).ComponentName; + if (!string.IsNullOrEmpty(objectName)) + return objectName; } - private string BuildDefaultObjectName(IObjectDefinition definition) - { - return definition.ObjectType.FullName; - } + return BuildDefaultObjectName(definition); + } + + private string BuildDefaultObjectName(IObjectDefinition definition) + { + return definition.ObjectType.FullName; } } diff --git a/src/Spring/Spring.Core/Context/Attributes/ConfigurationAttribute.cs b/src/Spring/Spring.Core/Context/Attributes/ConfigurationAttribute.cs index c18d0443..b77f2215 100644 --- a/src/Spring/Spring.Core/Context/Attributes/ConfigurationAttribute.cs +++ b/src/Spring/Spring.Core/Context/Attributes/ConfigurationAttribute.cs @@ -20,45 +20,41 @@ using Spring.Stereotype; -namespace Spring.Context.Attributes +namespace Spring.Context.Attributes; + +/// +/// Indicates that a class declares one or more methods and may be processed +/// by the Spring container to generate object definitions and service requests for those objects +/// at runtime. +/// +/// Configuration is meta-annotated as a , therefore Configuration +/// classes are candidates for component-scanning. +/// +/// May be used in conjunction with the attribute to indicate that all object +/// methods declared within this class are by default lazily initialized. +/// +///

Constraints

+///
    +///
  • Configuration classes must be non-sealed
  • +///
  • Configuration classes must have a default/no-arg constructor
  • +///
+///
+[AttributeUsage(AttributeTargets.Class)] +public class ConfigurationAttribute : ComponentAttribute { /// - /// Indicates that a class declares one or more methods and may be processed - /// by the Spring container to generate object definitions and service requests for those objects - /// at runtime. - /// - /// Configuration is meta-annotated as a , therefore Configuration - /// classes are candidates for component-scanning. - /// - /// May be used in conjunction with the attribute to indicate that all object - /// methods declared within this class are by default lazily initialized. - /// - ///

Constraints

- ///
    - ///
  • Configuration classes must be non-sealed
  • - ///
  • Configuration classes must have a default/no-arg constructor
  • - ///
+ /// Initializes a new instance of the ConfigurationAttribute class. ///
- [AttributeUsage(AttributeTargets.Class)] - public class ConfigurationAttribute : ComponentAttribute + public ConfigurationAttribute() { + } - /// - /// Initializes a new instance of the ConfigurationAttribute class. - /// - public ConfigurationAttribute() - { - - } - - /// - /// Initializes a new instance of the Configuration class. - /// - /// - public ConfigurationAttribute(string name) - { - Name = name; - } - + /// + /// Initializes a new instance of the Configuration class. + /// + /// + public ConfigurationAttribute(string name) + { + Name = name; } } diff --git a/src/Spring/Spring.Core/Context/Attributes/ConfigurationClass.cs b/src/Spring/Spring.Core/Context/Attributes/ConfigurationClass.cs index 5c7e6e8d..7dd9a89e 100644 --- a/src/Spring/Spring.Core/Context/Attributes/ConfigurationClass.cs +++ b/src/Spring/Spring.Core/Context/Attributes/ConfigurationClass.cs @@ -24,227 +24,222 @@ using Spring.Core.IO; using Spring.Collections.Generic; using Spring.Objects.Factory.Parsing; -namespace Spring.Context.Attributes +namespace Spring.Context.Attributes; + +/// +/// Represents an instance of the metadata that has been parsed from a class with the applied to it. +/// +public class ConfigurationClass { + private Type _configurationClassType; + + private readonly IDictionary _importedResources = new Dictionary(); + + private readonly Collections.Generic.ISet _methods = new HashedSet(); + + private string _objectName; + + private readonly IResource _resource; + /// - /// Represents an instance of the metadata that has been parsed from a class with the applied to it. + /// Initializes a new instance of the ConfigurationClass class. /// - public class ConfigurationClass + /// + /// + public ConfigurationClass(string objectName, Type type) { - private Type _configurationClassType; + _objectName = objectName; + _configurationClassType = type; + _resource = new ConfigurationClassAssemblyResource(type); + } - private readonly IDictionary _importedResources = new Dictionary(); - - private readonly Collections.Generic.ISet _methods = new HashedSet(); - - private string _objectName; - - private readonly IResource _resource; - - /// - /// Initializes a new instance of the ConfigurationClass class. - /// - /// - /// - public ConfigurationClass(string objectName, Type type) + /// + /// Gets the type of the configuration class. + /// + /// The type of the configuration class. + public Type ConfigurationClassType + { + get { - _objectName = objectName; - _configurationClassType = type; - _resource = new ConfigurationClassAssemblyResource(type); - + return _configurationClassType; } + } - /// - /// Gets the type of the configuration class. - /// - /// The type of the configuration class. - public Type ConfigurationClassType + /// + /// Gets the imported resources. + /// + /// The imported resources. + public IDictionary ImportedResources + { + get { - get + return _importedResources; + } + } + + /// + /// Gets the methods. + /// + /// The methods. + public Collections.Generic.ISet Methods + { + get + { + return _methods; + } + } + + /// + /// Gets or sets the name of the object. + /// + /// The name of the object. + public string ObjectName + { + get + { + return _objectName; + } + set + { + _objectName = value; + } + } + + /// + /// Gets the resource. + /// + /// The resource. + public IResource Resource + { + get + { + return _resource; + } + } + + /// + /// Gets the SimpleName of the object. + /// + /// The simple name. + public string SimpleName + { + get { return ConfigurationClassType.Name; } + } + + /// + /// Adds the imported resource. + /// + /// The imported resource. + /// The reader class capable of interpreting the imported resource. + public void AddImportedResource(string importedResource, Type readerClass) + { + _importedResources.Add(importedResource, readerClass); + } + + /// + /// Determines whether the specified is equal to this instance. + /// + /// The to compare with this instance. + /// + /// true if the specified is equal to this instance; otherwise, false. + /// + public override bool Equals(object other) + { + return this == other || (other is ConfigurationClass && ConfigurationClassType == ((ConfigurationClass) other).ConfigurationClassType); + } + + /// + /// Returns a hash code for this instance. + /// + /// + /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. + /// + public override int GetHashCode() + { + return ConfigurationClassType.GetHashCode() * 14; + } + + /// + /// Validates the specified and reports all discovered violations to the provided problem reporter for appropriate action. + /// + /// The problem reporter. + public void Validate(IProblemReporter problemReporter) + { + // A [ObjectDef] method may only be overloaded through inheritance. No single + // [Configuration] class may declare two [ObjectDef] methods with the same name. + const char hashDelim = '#'; + Dictionary methodNameCounts = new Dictionary(); + foreach (ConfigurationClassMethod method in _methods) + { + String dClassName = method.MethodMetadata.DeclaringType.FullName; + String methodName = method.MethodMetadata.Name; + + string paramTypes = ParamTypesToString(method.MethodMetadata); + + String fqMethodName = dClassName + hashDelim + methodName + paramTypes; + if (!methodNameCounts.ContainsKey(fqMethodName)) { - return _configurationClassType; + methodNameCounts.Add(fqMethodName, 1); + } + else + { + int currentCount = methodNameCounts[fqMethodName]; + methodNameCounts.Add(fqMethodName, currentCount++); } } - /// - /// Gets the imported resources. - /// - /// The imported resources. - public IDictionary ImportedResources + foreach (String methodName in methodNameCounts.Keys) { - get + int count = methodNameCounts[methodName]; + if (count > 1) { - return _importedResources; + String shortMethodName = methodName.Substring(methodName.IndexOf(hashDelim) + 1); + problemReporter.Error(new ObjectMethodOverloadingProblem(shortMethodName, count, Resource, ConfigurationClassType)); } } - /// - /// Gets the methods. - /// - /// The methods. - public Collections.Generic.ISet Methods + if (Attribute.GetCustomAttribute(_configurationClassType, typeof(ConfigurationAttribute)) != null) { - get + if (ConfigurationClassType.IsSealed) { - return _methods; + problemReporter.Error(new SealedConfigurationProblem(SimpleName, Resource, ConfigurationClassType)); } - } - /// - /// Gets or sets the name of the object. - /// - /// The name of the object. - public string ObjectName - { - get - { - return _objectName; - } - set - { - _objectName = value; - } - } - - /// - /// Gets the resource. - /// - /// The resource. - public IResource Resource - { - get - { - return _resource; - } - } - - /// - /// Gets the SimpleName of the object. - /// - /// The simple name. - public string SimpleName - { - get { return ConfigurationClassType.Name; } - } - - /// - /// Adds the imported resource. - /// - /// The imported resource. - /// The reader class capable of interpreting the imported resource. - public void AddImportedResource(string importedResource, Type readerClass) - { - _importedResources.Add(importedResource, readerClass); - } - - /// - /// Determines whether the specified is equal to this instance. - /// - /// The to compare with this instance. - /// - /// true if the specified is equal to this instance; otherwise, false. - /// - public override bool Equals(object other) - { - return this == other || (other is ConfigurationClass && ConfigurationClassType == ((ConfigurationClass)other).ConfigurationClassType); - } - - /// - /// Returns a hash code for this instance. - /// - /// - /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. - /// - public override int GetHashCode() - { - return ConfigurationClassType.GetHashCode() * 14; - } - - /// - /// Validates the specified and reports all discovered violations to the provided problem reporter for appropriate action. - /// - /// The problem reporter. - public void Validate(IProblemReporter problemReporter) - { - // A [ObjectDef] method may only be overloaded through inheritance. No single - // [Configuration] class may declare two [ObjectDef] methods with the same name. - const char hashDelim = '#'; - Dictionary methodNameCounts = new Dictionary(); foreach (ConfigurationClassMethod method in _methods) { - String dClassName = method.MethodMetadata.DeclaringType.FullName; - String methodName = method.MethodMetadata.Name; - - string paramTypes = ParamTypesToString(method.MethodMetadata); - - String fqMethodName = dClassName + hashDelim + methodName + paramTypes; - if (!methodNameCounts.ContainsKey(fqMethodName)) - { - methodNameCounts.Add(fqMethodName, 1); - } - else - { - int currentCount = methodNameCounts[fqMethodName]; - methodNameCounts.Add(fqMethodName, currentCount++); - } - } - - foreach (String methodName in methodNameCounts.Keys) - { - int count = methodNameCounts[methodName]; - if (count > 1) - { - String shortMethodName = methodName.Substring(methodName.IndexOf(hashDelim) + 1); - problemReporter.Error(new ObjectMethodOverloadingProblem(shortMethodName, count, Resource, ConfigurationClassType)); - } - } - - if (Attribute.GetCustomAttribute(_configurationClassType, typeof(ConfigurationAttribute)) != null) - { - - if (ConfigurationClassType.IsSealed) - { - problemReporter.Error(new SealedConfigurationProblem(SimpleName, Resource, ConfigurationClassType)); - - } - - foreach (ConfigurationClassMethod method in _methods) - { - method.Validate(problemReporter); - } + method.Validate(problemReporter); } } + } - private string ParamTypesToString(MethodInfo methodMetadata) + private string ParamTypesToString(MethodInfo methodMetadata) + { + var result = new StringBuilder(); + + foreach (var parameter in methodMetadata.GetParameters()) { - var result = new StringBuilder(); - - foreach (var parameter in methodMetadata.GetParameters()) - { - result.Append(parameter.ParameterType.ToString()); - } - - return result.ToString(); + result.Append(parameter.ParameterType.ToString()); } - private class SealedConfigurationProblem : Problem + return result.ToString(); + } + + private class SealedConfigurationProblem : Problem + { + public SealedConfigurationProblem(string name, IResource resource, Type configurationClassType) + : base(String.Format("[Configuration] class '{0}' may not be sealed. Remove the sealed modifier to continue.", name), new Location(resource, configurationClassType)) { - public SealedConfigurationProblem(string name, IResource resource, Type configurationClassType) - : base(String.Format("[Configuration] class '{0}' may not be sealed. Remove the sealed modifier to continue.", name), new Location(resource, configurationClassType)) - { } - } + } - //This class is for future use when parameterized [ObjectDef] methods are supported in the future. - //Until then, the test for only permitting zero-param [ObjectDef] methods would fail first, previnting this error from ever being reported - private class ObjectMethodOverloadingProblem : Problem + //This class is for future use when parameterized [ObjectDef] methods are supported in the future. + //Until then, the test for only permitting zero-param [ObjectDef] methods would fail first, previnting this error from ever being reported + private class ObjectMethodOverloadingProblem : Problem + { + public ObjectMethodOverloadingProblem(string methodName, int count, IResource resource, Type configurationClassType) + : base(String.Format("[Configuration] class '{0}' has {1} overloaded [Definiton] methods named '{2}'. " + + "Only one [ObjectDef] method of a given name is allowed within each [Configuration] class.", configurationClassType.Name, count, methodName), new Location(resource, configurationClassType)) { - public ObjectMethodOverloadingProblem(string methodName, int count, IResource resource, Type configurationClassType) - : base(String.Format("[Configuration] class '{0}' has {1} overloaded [Definiton] methods named '{2}'. " + - "Only one [ObjectDef] method of a given name is allowed within each [Configuration] class.", configurationClassType.Name, count, methodName), new Location(resource, configurationClassType)) - { } - } - } } diff --git a/src/Spring/Spring.Core/Context/Attributes/ConfigurationClassAssemblyResource.cs b/src/Spring/Spring.Core/Context/Attributes/ConfigurationClassAssemblyResource.cs index 4fcd0063..0d3882f0 100644 --- a/src/Spring/Spring.Core/Context/Attributes/ConfigurationClassAssemblyResource.cs +++ b/src/Spring/Spring.Core/Context/Attributes/ConfigurationClassAssemblyResource.cs @@ -21,181 +21,180 @@ using System.Reflection; using Spring.Core.IO; -namespace Spring.Context.Attributes +namespace Spring.Context.Attributes; + +/// +/// Implementation of the IResource that represents an assembly containing one or more resources. +/// +public class ConfigurationClassAssemblyResource : IResource { + private readonly string _containingAssemblyFileName; + private readonly Type _type; + /// - /// Implementation of the IResource that represents an assembly containing one or more resources. + /// Initializes a new instance of the class. /// - public class ConfigurationClassAssemblyResource : IResource + /// The type. + public ConfigurationClassAssemblyResource(Type type) { - private readonly string _containingAssemblyFileName; - private readonly Type _type; - - /// - /// Initializes a new instance of the class. - /// - /// The type. - public ConfigurationClassAssemblyResource(Type type) - { - _type = type; - _containingAssemblyFileName = Assembly.GetAssembly(_type.GetType()).Location; - } - - #region IResource Members - - /// - /// Creates a resource relative to this resource. - /// - /// The path (always resolved as relative to this resource). - /// The relative resource. - /// - /// If the relative resource could not be created from the supplied - /// path. - /// - /// - /// If the resource does not support the notion of a relative path. - /// - public IResource CreateRelative(string relativePath) - { - throw new InvalidOperationException(); - } - - /// - /// Does this resource represent a handle with an open stream? - /// - /// - /// if this resource represents a handle with an - /// open stream. - /// - /// - ///

- /// If , the - /// cannot be read multiple times, and must be read and then closed to - /// avoid resource leaks. - ///

- ///

- /// Will be for all usual resource descriptors. - ///

- ///
- /// - public bool IsOpen - { - get { return false; } - } - - /// - /// Returns the handle for this resource. - /// - /// The handle for this resource. - /// - ///

- /// For safety, always check the value of the - /// property prior to - /// accessing this property; resources that cannot be exposed as - /// a will typically return - /// from a call to the - /// property. - ///

- ///
- /// - /// If the resource is not available or cannot be exposed as a - /// . - /// - /// - /// - public Uri Uri - { - get { return new Uri(_containingAssemblyFileName); } - } - - /// - /// Returns a handle for this resource. - /// - /// - /// The handle for this resource. - /// - /// - ///

- /// For safety, always check the value of the - /// property prior to - /// accessing this property; resources that cannot be exposed as - /// a will typically return - /// from a call to the - /// property. - ///

- ///
- /// - /// If the resource is not available on a filesystem, or cannot be - /// exposed as a handle. - /// - /// - /// - public FileInfo File - { - get { return new FileInfo(_containingAssemblyFileName); } - } - - /// - /// Returns a description for this resource. - /// - /// A description for this resource. - /// - ///

- /// The description is typically used for diagnostics and other such - /// logging when working with the resource. - ///

- ///

- /// Implementations are also encouraged to return this value from their - /// method. - ///

- ///
- public string Description - { - get { return _type.FullName; } - } - - /// - /// Does this resource actually exist in physical form? - /// - /// - /// if this resource actually exists in physical - /// form (for example on a filesystem). - /// - /// - ///

- /// An example of a resource that physically exists would be a - /// file on a local filesystem. An example of a resource that does not - /// physically exist would be an in-memory stream. - ///

- ///
- /// - /// - public bool Exists - { - get { return System.IO.File.Exists(_containingAssemblyFileName); } - } - - /// - /// Return an for this resource. - /// - /// An . - /// - /// - /// Clients of this interface must be aware that every access of this - /// property will create a fresh - /// ; - /// it is the responsibility of the calling code to close any such - /// . - /// - /// - /// - /// If the stream could not be opened. - /// - public Stream InputStream - { - get { throw new InvalidOperationException(); } - } - - #endregion + _type = type; + _containingAssemblyFileName = Assembly.GetAssembly(_type.GetType()).Location; } + + #region IResource Members + + /// + /// Creates a resource relative to this resource. + /// + /// The path (always resolved as relative to this resource). + /// The relative resource. + /// + /// If the relative resource could not be created from the supplied + /// path. + /// + /// + /// If the resource does not support the notion of a relative path. + /// + public IResource CreateRelative(string relativePath) + { + throw new InvalidOperationException(); + } + + /// + /// Does this resource represent a handle with an open stream? + /// + /// + /// if this resource represents a handle with an + /// open stream. + /// + /// + ///

+ /// If , the + /// cannot be read multiple times, and must be read and then closed to + /// avoid resource leaks. + ///

+ ///

+ /// Will be for all usual resource descriptors. + ///

+ ///
+ /// + public bool IsOpen + { + get { return false; } + } + + /// + /// Returns the handle for this resource. + /// + /// The handle for this resource. + /// + ///

+ /// For safety, always check the value of the + /// property prior to + /// accessing this property; resources that cannot be exposed as + /// a will typically return + /// from a call to the + /// property. + ///

+ ///
+ /// + /// If the resource is not available or cannot be exposed as a + /// . + /// + /// + /// + public Uri Uri + { + get { return new Uri(_containingAssemblyFileName); } + } + + /// + /// Returns a handle for this resource. + /// + /// + /// The handle for this resource. + /// + /// + ///

+ /// For safety, always check the value of the + /// property prior to + /// accessing this property; resources that cannot be exposed as + /// a will typically return + /// from a call to the + /// property. + ///

+ ///
+ /// + /// If the resource is not available on a filesystem, or cannot be + /// exposed as a handle. + /// + /// + /// + public FileInfo File + { + get { return new FileInfo(_containingAssemblyFileName); } + } + + /// + /// Returns a description for this resource. + /// + /// A description for this resource. + /// + ///

+ /// The description is typically used for diagnostics and other such + /// logging when working with the resource. + ///

+ ///

+ /// Implementations are also encouraged to return this value from their + /// method. + ///

+ ///
+ public string Description + { + get { return _type.FullName; } + } + + /// + /// Does this resource actually exist in physical form? + /// + /// + /// if this resource actually exists in physical + /// form (for example on a filesystem). + /// + /// + ///

+ /// An example of a resource that physically exists would be a + /// file on a local filesystem. An example of a resource that does not + /// physically exist would be an in-memory stream. + ///

+ ///
+ /// + /// + public bool Exists + { + get { return System.IO.File.Exists(_containingAssemblyFileName); } + } + + /// + /// Return an for this resource. + /// + /// An . + /// + /// + /// Clients of this interface must be aware that every access of this + /// property will create a fresh + /// ; + /// it is the responsibility of the calling code to close any such + /// . + /// + /// + /// + /// If the stream could not be opened. + /// + public Stream InputStream + { + get { throw new InvalidOperationException(); } + } + + #endregion } diff --git a/src/Spring/Spring.Core/Context/Attributes/ConfigurationClassEnhancer.cs b/src/Spring/Spring.Core/Context/Attributes/ConfigurationClassEnhancer.cs index 7a4b2348..04e6b414 100644 --- a/src/Spring/Spring.Core/Context/Attributes/ConfigurationClassEnhancer.cs +++ b/src/Spring/Spring.Core/Context/Attributes/ConfigurationClassEnhancer.cs @@ -26,257 +26,257 @@ using Spring.Objects.Factory.Config; using Spring.Util; using Spring.Proxy; -namespace Spring.Context.Attributes +namespace Spring.Context.Attributes; + +/// +/// Enhances Configuration classes by generating a dynamic proxy capable of +/// interacting with the Spring container to respect object semantics. +/// +/// Chris Beams +/// Juergen Hoeller +/// Bruno Baia (.NET) +/// +public class ConfigurationClassEnhancer { + private IConfigurationClassInterceptor interceptor; + /// - /// Enhances Configuration classes by generating a dynamic proxy capable of - /// interacting with the Spring container to respect object semantics. + /// Creates a new instance of the class. /// - /// Chris Beams - /// Juergen Hoeller - /// Bruno Baia (.NET) - /// - public class ConfigurationClassEnhancer + /// + /// The supplied ObjectFactory to check for the existence of object definitions. + /// + public ConfigurationClassEnhancer(IConfigurableListableObjectFactory objectFactory) { + AssertUtils.ArgumentNotNull(objectFactory, "objectFactory"); + + this.interceptor = new ConfigurationClassInterceptor(objectFactory); + } + + /// + /// Generates a dynamic subclass of the specified Configuration class with a + /// container-aware interceptor capable of respecting scoping and other bean semantics. + /// + /// The Configuration class. + /// The enhanced subclass. + public Type Enhance(Type configClass) + { + ConfigurationClassProxyTypeBuilder proxyTypeBuilder = new ConfigurationClassProxyTypeBuilder(configClass, this.interceptor); + return proxyTypeBuilder.BuildProxyType(); + } + + /// + /// Intercepts the invocation of any -decorated methods in order + /// to ensure proper handling of object semantics such as scoping and AOP proxying. + /// + public interface IConfigurationClassInterceptor + { + /// + /// Process the -decorated method to check + /// for the existence of this object. + /// + /// The method providing the object definition. + /// When this method returns true, contains the object definition. + /// true if the object exists; otherwise, false. + bool ProcessDefinition(MethodInfo method, out object instance); + } + + private sealed class ConfigurationClassInterceptor : IConfigurationClassInterceptor + { + #region Logging + + private static readonly ILogger Logger = LogManager.GetLogger(); + + #endregion + + private readonly IConfigurableListableObjectFactory _configurableListableObjectFactory; + + public ConfigurationClassInterceptor(IConfigurableListableObjectFactory configurableListableObjectFactory) + { + this._configurableListableObjectFactory = configurableListableObjectFactory; + } + + public bool ProcessDefinition(MethodInfo method, out object instance) + { + instance = null; + + string objectName = method.Name; + + if (objectName.StartsWith("set_") || objectName.StartsWith("get_")) + { + return false; + } + + object[] attribs = method.GetCustomAttributes(typeof(ObjectDefAttribute), true); + if (attribs.Length == 0) + { + return false; + } + + if (this._configurableListableObjectFactory.IsCurrentlyInCreation(objectName)) + { + Logger.LogDebug("Object '{ObjectName}' currently in creation, created one", objectName); + + return false; + } + + Logger.LogDebug("Object '{ObjectName}' not in creation, asked the application context for one", objectName); + + instance = this._configurableListableObjectFactory.GetObject(objectName); + return true; + } + } + + #region Proxy builder classes definition + + private sealed class ConfigurationClassProxyTypeBuilder : InheritanceProxyTypeBuilder + { + private FieldBuilder interceptorField; private IConfigurationClassInterceptor interceptor; - /// - /// Creates a new instance of the class. - /// - /// - /// The supplied ObjectFactory to check for the existence of object definitions. - /// - public ConfigurationClassEnhancer(IConfigurableListableObjectFactory objectFactory) + public ConfigurationClassProxyTypeBuilder(Type configurationClassType, IConfigurationClassInterceptor interceptor) { - AssertUtils.ArgumentNotNull(objectFactory, "objectFactory"); + if (configurationClassType.IsSealed) + { + throw new ArgumentException(String.Format( + "[Configuration] classes '{0}' cannot be sealed [{0}].", configurationClassType.FullName)); + } - this.interceptor = new ConfigurationClassInterceptor(objectFactory); - } + this.Name = "ConfigurationClassProxy"; + this.DeclaredMembersOnly = false; + this.BaseType = configurationClassType; + this.TargetType = configurationClassType; - /// - /// Generates a dynamic subclass of the specified Configuration class with a - /// container-aware interceptor capable of respecting scoping and other bean semantics. - /// - /// The Configuration class. - /// The enhanced subclass. - public Type Enhance(Type configClass) - { - ConfigurationClassProxyTypeBuilder proxyTypeBuilder = new ConfigurationClassProxyTypeBuilder(configClass, this.interceptor); - return proxyTypeBuilder.BuildProxyType(); + this.interceptor = interceptor; } - /// - /// Intercepts the invocation of any -decorated methods in order - /// to ensure proper handling of object semantics such as scoping and AOP proxying. - /// - public interface IConfigurationClassInterceptor + public override Type BuildProxyType() { - /// - /// Process the -decorated method to check - /// for the existence of this object. - /// - /// The method providing the object definition. - /// When this method returns true, contains the object definition. - /// true if the object exists; otherwise, false. - bool ProcessDefinition(MethodInfo method, out object instance); + IDictionary targetMethods = new Hashtable(); + + TypeBuilder typeBuilder = CreateTypeBuilder(Name, BaseType); + + // apply custom attributes to the proxy type. + //ApplyTypeAttributes(typeBuilder, BaseType); + + // declare interceptor field + interceptorField = typeBuilder.DefineField("__Interceptor", typeof(IConfigurationClassInterceptor), + FieldAttributes.Private | FieldAttributes.Static); + + // create constructors + ImplementConstructors(typeBuilder); + + // proxy base virtual methods + InheritType(typeBuilder, + new ConfigurationClassProxyMethodBuilder(typeBuilder, this, false, targetMethods), + BaseType, this.DeclaredMembersOnly); + + Type proxyType = typeBuilder.CreateTypeInfo(); + + // set target method references + foreach (DictionaryEntry entry in targetMethods) + { + FieldInfo targetMethodFieldInfo = proxyType.GetField((string) entry.Key, BindingFlags.NonPublic | BindingFlags.Static); + targetMethodFieldInfo.SetValue(proxyType, entry.Value); + } + + // set interceptor + FieldInfo interceptorFieldInfo = proxyType.GetField("__Interceptor", BindingFlags.NonPublic | BindingFlags.Static); + interceptorFieldInfo.SetValue(proxyType, this.interceptor); + + return proxyType; } - private sealed class ConfigurationClassInterceptor : IConfigurationClassInterceptor + public void PushInterceptor(ILGenerator il) { - #region Logging + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldfld, interceptorField); + } + } - private static readonly ILogger Logger = LogManager.GetLogger(); - - #endregion + private sealed class ConfigurationClassProxyMethodBuilder : AbstractProxyMethodBuilder + { + public static readonly MethodInfo ProcessDefinitionMethod = + typeof(IConfigurationClassInterceptor).GetMethod("ProcessDefinition", BindingFlags.Instance | BindingFlags.Public); - private readonly IConfigurableListableObjectFactory _configurableListableObjectFactory; + private ConfigurationClassProxyTypeBuilder customProxyGenerator; - public ConfigurationClassInterceptor(IConfigurableListableObjectFactory configurableListableObjectFactory) - { - this._configurableListableObjectFactory = configurableListableObjectFactory; - } + private IDictionary targetMethods; - public bool ProcessDefinition(MethodInfo method, out object instance) - { - instance = null; - - string objectName = method.Name; - - if (objectName.StartsWith("set_") || objectName.StartsWith("get_")) - { - return false; - } - - object[] attribs = method.GetCustomAttributes(typeof(ObjectDefAttribute), true); - if (attribs.Length == 0) - { - return false; - } - - if (this._configurableListableObjectFactory.IsCurrentlyInCreation(objectName)) - { - Logger.LogDebug("Object '{ObjectName}' currently in creation, created one", objectName); - - return false; - } - - Logger.LogDebug("Object '{ObjectName}' not in creation, asked the application context for one", objectName); - - instance = this._configurableListableObjectFactory.GetObject(objectName); - return true; - } + public ConfigurationClassProxyMethodBuilder( + TypeBuilder typeBuilder, ConfigurationClassProxyTypeBuilder proxyGenerator, + bool explicitImplementation, IDictionary targetMethods) + : base(typeBuilder, proxyGenerator, explicitImplementation) + { + this.customProxyGenerator = proxyGenerator; + this.targetMethods = targetMethods; } - #region Proxy builder classes definition - - private sealed class ConfigurationClassProxyTypeBuilder : InheritanceProxyTypeBuilder + protected override void GenerateMethod( + ILGenerator il, MethodInfo method, MethodInfo interfaceMethod) { - private FieldBuilder interceptorField; - private IConfigurationClassInterceptor interceptor; - - public ConfigurationClassProxyTypeBuilder(Type configurationClassType, IConfigurationClassInterceptor interceptor) - { - if (configurationClassType.IsSealed) - { - throw new ArgumentException(String.Format( - "[Configuration] classes '{0}' cannot be sealed [{0}].", configurationClassType.FullName)); - } - - this.Name = "ConfigurationClassProxy"; - this.DeclaredMembersOnly = false; - this.BaseType = configurationClassType; - this.TargetType = configurationClassType; - - this.interceptor = interceptor; - } - - public override Type BuildProxyType() - { - IDictionary targetMethods = new Hashtable(); - - TypeBuilder typeBuilder = CreateTypeBuilder(Name, BaseType); - - // apply custom attributes to the proxy type. - //ApplyTypeAttributes(typeBuilder, BaseType); - - // declare interceptor field - interceptorField = typeBuilder.DefineField("__Interceptor", typeof(IConfigurationClassInterceptor), - FieldAttributes.Private | FieldAttributes.Static); - - // create constructors - ImplementConstructors(typeBuilder); - - // proxy base virtual methods - InheritType(typeBuilder, - new ConfigurationClassProxyMethodBuilder(typeBuilder, this, false, targetMethods), - BaseType, this.DeclaredMembersOnly); - - Type proxyType = typeBuilder.CreateTypeInfo(); - - // set target method references - foreach (DictionaryEntry entry in targetMethods) - { - FieldInfo targetMethodFieldInfo = proxyType.GetField((string)entry.Key, BindingFlags.NonPublic | BindingFlags.Static); - targetMethodFieldInfo.SetValue(proxyType, entry.Value); - } - - // set interceptor - FieldInfo interceptorFieldInfo = proxyType.GetField("__Interceptor", BindingFlags.NonPublic | BindingFlags.Static); - interceptorFieldInfo.SetValue(proxyType, this.interceptor); - - return proxyType; - } - - public void PushInterceptor(ILGenerator il) - { - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Ldfld, interceptorField); - } - } - - private sealed class ConfigurationClassProxyMethodBuilder : AbstractProxyMethodBuilder - { - public static readonly MethodInfo ProcessDefinitionMethod = - typeof(IConfigurationClassInterceptor).GetMethod("ProcessDefinition", BindingFlags.Instance | BindingFlags.Public); - - private ConfigurationClassProxyTypeBuilder customProxyGenerator; - - private IDictionary targetMethods; - - public ConfigurationClassProxyMethodBuilder( - TypeBuilder typeBuilder, ConfigurationClassProxyTypeBuilder proxyGenerator, - bool explicitImplementation, IDictionary targetMethods) - : base(typeBuilder, proxyGenerator, explicitImplementation) - { - this.customProxyGenerator = proxyGenerator; - this.targetMethods = targetMethods; - } - - protected override void GenerateMethod( - ILGenerator il, MethodInfo method, MethodInfo interfaceMethod) - { - // Declare local variables - LocalBuilder interceptedReturnValue = il.DeclareLocal(typeof(Object)); + // Declare local variables + LocalBuilder interceptedReturnValue = il.DeclareLocal(typeof(Object)); //#if DEBUG // interceptedReturnValue.SetLocalSymInfo("interceptedReturnValue"); //#endif - LocalBuilder returnValue = null; - if (method.ReturnType != typeof(void)) - { - returnValue = il.DeclareLocal(method.ReturnType); + LocalBuilder returnValue = null; + if (method.ReturnType != typeof(void)) + { + returnValue = il.DeclareLocal(method.ReturnType); //#if DEBUG // returnValue.SetLocalSymInfo("returnValue"); //#endif - } + } - // Declare static field that will cache base method - string methodId = "_m" + Guid.NewGuid().ToString("N"); - targetMethods.Add(methodId, method); - FieldBuilder targetMethodCacheField = typeBuilder.DefineField(methodId, typeof(MethodInfo), - FieldAttributes.Private | FieldAttributes.Static); + // Declare static field that will cache base method + string methodId = "_m" + Guid.NewGuid().ToString("N"); + targetMethods.Add(methodId, method); + FieldBuilder targetMethodCacheField = typeBuilder.DefineField(methodId, typeof(MethodInfo), + FieldAttributes.Private | FieldAttributes.Static); - // Call IConfigurationClassInterceptor.TryGetObject method - il.Emit(OpCodes.Ldnull); - il.Emit(OpCodes.Stloc, interceptedReturnValue); - customProxyGenerator.PushInterceptor(il); - il.Emit(OpCodes.Ldsfld, targetMethodCacheField); - il.Emit(OpCodes.Ldloca_S, interceptedReturnValue); - il.EmitCall(OpCodes.Callvirt, ProcessDefinitionMethod, null); - Label jmpBaseCall = il.DefineLabel(); - Label jmpEndIf = il.DefineLabel(); - il.Emit(OpCodes.Brfalse_S, jmpBaseCall); + // Call IConfigurationClassInterceptor.TryGetObject method + il.Emit(OpCodes.Ldnull); + il.Emit(OpCodes.Stloc, interceptedReturnValue); + customProxyGenerator.PushInterceptor(il); + il.Emit(OpCodes.Ldsfld, targetMethodCacheField); + il.Emit(OpCodes.Ldloca_S, interceptedReturnValue); + il.EmitCall(OpCodes.Callvirt, ProcessDefinitionMethod, null); + Label jmpBaseCall = il.DefineLabel(); + Label jmpEndIf = il.DefineLabel(); + il.Emit(OpCodes.Brfalse_S, jmpBaseCall); - // if true - if (returnValue != null) + // if true + if (returnValue != null) + { + il.Emit(OpCodes.Ldloc, interceptedReturnValue); + if (method.ReturnType.IsValueType || method.ReturnType.IsGenericParameter) { - il.Emit(OpCodes.Ldloc, interceptedReturnValue); - if (method.ReturnType.IsValueType || method.ReturnType.IsGenericParameter) - { - il.Emit(OpCodes.Unbox_Any, method.ReturnType); - } - il.Emit(OpCodes.Stloc, returnValue); - il.Emit(OpCodes.Br, jmpEndIf); + il.Emit(OpCodes.Unbox_Any, method.ReturnType); } - // if false - il.MarkLabel(jmpBaseCall); - CallDirectBaseMethod(il, method); - if (returnValue != null) - { - il.Emit(OpCodes.Stloc, returnValue); - } + il.Emit(OpCodes.Stloc, returnValue); + il.Emit(OpCodes.Br, jmpEndIf); + } - // end if - il.MarkLabel(jmpEndIf); + // if false + il.MarkLabel(jmpBaseCall); + CallDirectBaseMethod(il, method); + if (returnValue != null) + { + il.Emit(OpCodes.Stloc, returnValue); + } - // return value - if (returnValue != null) - { - il.Emit(OpCodes.Ldloc, returnValue); - } + // end if + il.MarkLabel(jmpEndIf); + + // return value + if (returnValue != null) + { + il.Emit(OpCodes.Ldloc, returnValue); } } - - #endregion } + + #endregion } diff --git a/src/Spring/Spring.Core/Context/Attributes/ConfigurationClassMethod.cs b/src/Spring/Spring.Core/Context/Attributes/ConfigurationClassMethod.cs index ba44c5b5..cf4a9187 100644 --- a/src/Spring/Spring.Core/Context/Attributes/ConfigurationClassMethod.cs +++ b/src/Spring/Spring.Core/Context/Attributes/ConfigurationClassMethod.cs @@ -21,124 +21,122 @@ using System.Reflection; using Spring.Objects.Factory.Parsing; -namespace Spring.Context.Attributes +namespace Spring.Context.Attributes; + +/// +/// Represents a class method marked with the . +/// +public class ConfigurationClassMethod { + private readonly ConfigurationClass _configurationClass; + + private readonly MethodInfo _methodInfo; + /// - /// Represents a class method marked with the . + /// Initializes a new instance of the ConfigurationClassMethod class. /// - public class ConfigurationClassMethod + /// + /// + public ConfigurationClassMethod(MethodInfo methodInfo, ConfigurationClass configurationClass) { - private readonly ConfigurationClass _configurationClass; + _methodInfo = methodInfo; + _configurationClass = configurationClass; + } - private readonly MethodInfo _methodInfo; + /// + /// Gets the configuration class. + /// + /// The configuration class. + public ConfigurationClass ConfigurationClass + { + get { return _configurationClass; } + } - /// - /// Initializes a new instance of the ConfigurationClassMethod class. - /// - /// - /// - public ConfigurationClassMethod(MethodInfo methodInfo, ConfigurationClass configurationClass) + /// + /// Gets the method metadata. + /// + /// The method metadata. + public MethodInfo MethodMetadata + { + get { return _methodInfo; } + } + + /// + /// Gets the resource location. + /// + /// The resource location. + public Location ResourceLocation + { + get { return new Location(_configurationClass.Resource, _methodInfo); } + } + + /// + /// Returns a that represents this instance. + /// + /// + /// A that represents this instance. + /// + public override string ToString() + { + return string.Format("{0}:name={1},declaringClass={2}", GetType().Name, _methodInfo.Name, + _methodInfo.DeclaringType.FullName); + } + + /// + /// Validates the specified problem reporter. + /// + /// The problem reporter. + public void Validate(IProblemReporter problemReporter) + { + //TODO: investigate whether this should be "if method has ObjectDef attribute" instead of "if class has Configuration attribute" + if ( + Attribute.GetCustomAttribute(ConfigurationClass.ConfigurationClassType, typeof(ConfigurationAttribute)) != + null) { - _methodInfo = methodInfo; - _configurationClass = configurationClass; - } - - /// - /// Gets the configuration class. - /// - /// The configuration class. - public ConfigurationClass ConfigurationClass - { - get { return _configurationClass; } - } - - /// - /// Gets the method metadata. - /// - /// The method metadata. - public MethodInfo MethodMetadata - { - get { return _methodInfo; } - } - - /// - /// Gets the resource location. - /// - /// The resource location. - public Location ResourceLocation - { - get { return new Location(_configurationClass.Resource, _methodInfo); } - } - - /// - /// Returns a that represents this instance. - /// - /// - /// A that represents this instance. - /// - public override string ToString() - { - return string.Format("{0}:name={1},declaringClass={2}", GetType().Name, _methodInfo.Name, - _methodInfo.DeclaringType.FullName); - } - - /// - /// Validates the specified problem reporter. - /// - /// The problem reporter. - public void Validate(IProblemReporter problemReporter) - { - //TODO: investigate whether this should be "if method has ObjectDef attribute" instead of "if class has Configuration attribute" - if ( - Attribute.GetCustomAttribute(ConfigurationClass.ConfigurationClassType, typeof (ConfigurationAttribute)) != - null) + if (MethodMetadata.IsStatic) { - - if (MethodMetadata.IsStatic) - { - problemReporter.Error(new StaticMethodError(MethodMetadata.Name, ResourceLocation)); - } - - if (!MethodMetadata.IsVirtual) - { - problemReporter.Error(new NonVirtualMethodError(MethodMetadata.Name, ResourceLocation)); - } - - if (MethodMetadata.GetParameters().Length != 0) - { - problemReporter.Error(new MethodWithParametersError(MethodMetadata.Name, ResourceLocation)); - } + problemReporter.Error(new StaticMethodError(MethodMetadata.Name, ResourceLocation)); } - } - private class MethodWithParametersError : Problem - { - public MethodWithParametersError(string methodName, Location location) - : base( - String.Format( - "Method '{0}' must not accept parameters; remove the method's parameters to continue.", - methodName), location) + if (!MethodMetadata.IsVirtual) { + problemReporter.Error(new NonVirtualMethodError(MethodMetadata.Name, ResourceLocation)); } - } - private class NonVirtualMethodError : Problem - { - public NonVirtualMethodError(string methodName, Location location) - : base(String.Format("Method '{0}' must be public virtual; change the method's modifiers to continue.", - methodName), location) - { - } - } - - private class StaticMethodError : Problem - { - public StaticMethodError(string methodName, Location location) - : base( - String.Format("Method '{0}' must not be static; remove the method's static modifier to continue.", - methodName), location) + if (MethodMetadata.GetParameters().Length != 0) { + problemReporter.Error(new MethodWithParametersError(MethodMetadata.Name, ResourceLocation)); } } } + + private class MethodWithParametersError : Problem + { + public MethodWithParametersError(string methodName, Location location) + : base( + String.Format( + "Method '{0}' must not accept parameters; remove the method's parameters to continue.", + methodName), location) + { + } + } + + private class NonVirtualMethodError : Problem + { + public NonVirtualMethodError(string methodName, Location location) + : base(String.Format("Method '{0}' must be public virtual; change the method's modifiers to continue.", + methodName), location) + { + } + } + + private class StaticMethodError : Problem + { + public StaticMethodError(string methodName, Location location) + : base( + String.Format("Method '{0}' must not be static; remove the method's static modifier to continue.", + methodName), location) + { + } + } } diff --git a/src/Spring/Spring.Core/Context/Attributes/ConfigurationClassObjectDefinitionReader.cs b/src/Spring/Spring.Core/Context/Attributes/ConfigurationClassObjectDefinitionReader.cs index bdc33cd9..39a0413e 100644 --- a/src/Spring/Spring.Core/Context/Attributes/ConfigurationClassObjectDefinitionReader.cs +++ b/src/Spring/Spring.Core/Context/Attributes/ConfigurationClassObjectDefinitionReader.cs @@ -30,271 +30,272 @@ using Spring.Stereotype; #endregion -namespace Spring.Context.Attributes +namespace Spring.Context.Attributes; + +/// +/// Reads the class with the applied and converts it into an instance. +/// +public class ConfigurationClassObjectDefinitionReader { + private static readonly ILogger Logger = LogManager.GetLogger(); + + private IProblemReporter _problemReporter; + + private IObjectDefinitionRegistry _registry; + /// - /// Reads the class with the applied and converts it into an instance. + /// Initializes a new instance of the ConfigurationClassObjectDefinitionReader class. /// - public class ConfigurationClassObjectDefinitionReader + /// + /// + public ConfigurationClassObjectDefinitionReader(IObjectDefinitionRegistry registry, + IProblemReporter problemReporter) { - private static readonly ILogger Logger = LogManager.GetLogger(); + _registry = registry; + _problemReporter = problemReporter; + } - private IProblemReporter _problemReporter; - - private IObjectDefinitionRegistry _registry; - - /// - /// Initializes a new instance of the ConfigurationClassObjectDefinitionReader class. - /// - /// - /// - public ConfigurationClassObjectDefinitionReader(IObjectDefinitionRegistry registry, - IProblemReporter problemReporter) + private static bool HasAttributeOnMethods(Type objectType, Type attributeType) + { + Collections.Generic.ISet methods = ConfigurationClassParser.GetAllMethodsWithCustomAttributeForClass(objectType, + attributeType); + foreach (MethodInfo method in methods) { - _registry = registry; - _problemReporter = problemReporter; + if (Attribute.GetCustomAttribute(method, attributeType) != null) + { + return true; + } } - private static bool HasAttributeOnMethods(Type objectType, Type attributeType) + return false; + } + + /// + /// Loads the object definitions. + /// + /// The configuration model. + public void LoadObjectDefinitions(Collections.Generic.ISet configurationModel) + { + foreach (ConfigurationClass configClass in configurationModel) { - Collections.Generic.ISet methods = ConfigurationClassParser.GetAllMethodsWithCustomAttributeForClass(objectType, - attributeType); - foreach (MethodInfo method in methods) + LoadObjectDefinitionsForConfigurationClass(configClass); + } + } + + private void LoadObjectDefinitionForConfigurationClassIfNecessary(ConfigurationClass configClass) + { + if (configClass.ObjectName != null) + { + // a Object definition already exists for this configuration class -> nothing to do + return; + } + + // no Object definition exists yet -> this must be an imported configuration class ([Import]). + GenericObjectDefinition configObjectDef = new GenericObjectDefinition(); + String className = configClass.ConfigurationClassType.Name; + configObjectDef.ObjectTypeName = className; + configObjectDef.ObjectType = configClass.ConfigurationClassType; + if (CheckConfigurationClassCandidate(configClass.ConfigurationClassType)) + { + String configObjectName = ObjectDefinitionReaderUtils.RegisterWithGeneratedName(configObjectDef, + _registry); + configClass.ObjectName = configObjectName; + Logger.LogDebug("Registered object definition for imported [Configuration] class {ObjectName}", configObjectName); + } + } + + /// + /// Checks the class to see if it is a candidate to be a source. + /// + /// The object definition. + /// + public static bool CheckConfigurationClassCandidate(IObjectDefinition objectDefinition) + { + Type objectType = null; + if (objectDefinition is AbstractObjectDefinition) + { + AbstractObjectDefinition definition = (AbstractObjectDefinition) objectDefinition; + if (definition.HasObjectType) { - if (Attribute.GetCustomAttribute(method, attributeType) != null) + objectType = definition.ObjectType; + } + else + { + if (definition.ObjectTypeName != null && !definition.IsAbstract) + { + objectType = TypeResolutionUtils.ResolveType(definition.ObjectTypeName); + } + } + + if (objectType != null) + { + if (Attribute.GetCustomAttribute(objectType, typeof(ConfigurationAttribute)) != null) + { + return true; + } + + if (Attribute.GetCustomAttribute(objectType, typeof(ComponentAttribute)) != null || + HasAttributeOnMethods(objectType, typeof(ObjectDefAttribute))) { return true; } } - return false; } - /// - /// Loads the object definitions. - /// - /// The configuration model. - public void LoadObjectDefinitions(Collections.Generic.ISet configurationModel) + return false; + } + + private bool CheckConfigurationClassCandidate(Type type) + { + if (type != null) { - foreach (ConfigurationClass configClass in configurationModel) + return (Attribute.GetCustomAttribute(type, typeof(ConfigurationAttribute)) != null); + } + + return false; + } + + private void LoadObjectDefinitionsForConfigurationClass(ConfigurationClass configClass) + { + LoadObjectDefinitionForConfigurationClassIfNecessary(configClass); + + foreach (ConfigurationClassMethod method in configClass.Methods) + { + LoadObjectDefinitionsForModelMethod(method); + } + + LoadObjectDefinitionsFromImportedResources(configClass.ImportedResources); + } + + private void LoadObjectDefinitionsForModelMethod(ConfigurationClassMethod method) + { + ConfigurationClass configClass = method.ConfigurationClass; + MethodInfo metadata = method.MethodMetadata; + + RootObjectDefinition objDef = new ConfigurationClassObjectDefinition(); + + objDef.FactoryObjectName = configClass.ObjectName; + objDef.FactoryMethodName = metadata.Name; + objDef.AutowireMode = Objects.Factory.Config.AutoWiringMode.Constructor; + + // consider name and any aliases + //Dictionary ObjectAttributes = metadata.getAnnotationAttributes(Object.class.getName()); + object[] objectAttributes = metadata.GetCustomAttributes(typeof(ObjectDefAttribute), true); + List names = new List(); + foreach (object t in objectAttributes) + { + string[] namesAndAliases = ((ObjectDefAttribute) t).NamesToArray; + + if (namesAndAliases != null) { - LoadObjectDefinitionsForConfigurationClass(configClass); + names.Add(metadata.Name); } + else + { + namesAndAliases = new[] { metadata.Name }; + } + + names.AddRange(namesAndAliases); } - private void LoadObjectDefinitionForConfigurationClassIfNecessary(ConfigurationClass configClass) + string objectName = (names.Count > 0 ? names[0] : method.MethodMetadata.Name); + for (int i = 1; i < names.Count; i++) { - if (configClass.ObjectName != null) + _registry.RegisterAlias(objectName, names[i]); + } + + // has this already been overridden (e.g. via XML)? + if (_registry.ContainsObjectDefinition(objectName)) + { + IObjectDefinition existingObjectDef = _registry.GetObjectDefinition(objectName); + // is the existing Object definition one that was created from a configuration class? + if (!(existingObjectDef is ConfigurationClassObjectDefinition)) { - // a Object definition already exists for this configuration class -> nothing to do + // no -> then it's an external override, probably XML + // overriding is legal, return immediately + Logger.LogDebug("Skipping loading Object definition for {Method}: a definition for object {ObjectName} already exists. This is likely due to an override in XML.", method, objectName); return; } - - // no Object definition exists yet -> this must be an imported configuration class ([Import]). - GenericObjectDefinition configObjectDef = new GenericObjectDefinition(); - String className = configClass.ConfigurationClassType.Name; - configObjectDef.ObjectTypeName = className; - configObjectDef.ObjectType = configClass.ConfigurationClassType; - if (CheckConfigurationClassCandidate(configClass.ConfigurationClassType)) - { - String configObjectName = ObjectDefinitionReaderUtils.RegisterWithGeneratedName(configObjectDef, - _registry); - configClass.ObjectName = configObjectName; - Logger.LogDebug("Registered object definition for imported [Configuration] class {ObjectName}", configObjectName); - } } - /// - /// Checks the class to see if it is a candidate to be a source. - /// - /// The object definition. - /// - public static bool CheckConfigurationClassCandidate(IObjectDefinition objectDefinition) + //TODO: container does not presently support the concept of Primary object definition for type resolution + //if (Attribute.GetCustomAttribute(metadata, typeof(PrimaryAttribute)) != null) + //{ + // ObjectDef.isPrimary = true; + //} + + // is this Object to be instantiated lazily? + if (Attribute.GetCustomAttribute(metadata, typeof(LazyAttribute)) != null) { - Type objectType = null; - if (objectDefinition is AbstractObjectDefinition) - { - AbstractObjectDefinition definition = (AbstractObjectDefinition)objectDefinition; - if (definition.HasObjectType) - { - objectType = definition.ObjectType; - } - else - { - if (definition.ObjectTypeName != null && !definition.IsAbstract) - { - objectType = TypeResolutionUtils.ResolveType(definition.ObjectTypeName); - } - } - if (objectType != null) - { - if (Attribute.GetCustomAttribute(objectType, typeof(ConfigurationAttribute)) != null) - { - return true; - } - if (Attribute.GetCustomAttribute(objectType, typeof(ComponentAttribute)) != null || - HasAttributeOnMethods(objectType, typeof(ObjectDefAttribute))) - { - return true; - } - } - } - return false; + objDef.IsLazyInit = + (Attribute.GetCustomAttribute(metadata, typeof(LazyAttribute)) as LazyAttribute).LazyInitialize; } - private bool CheckConfigurationClassCandidate(Type type) + if (Attribute.GetCustomAttribute(metadata, typeof(DependsOnAttribute)) != null) { - if (type != null) - { - return (Attribute.GetCustomAttribute(type, typeof(ConfigurationAttribute)) != null); - } - - return false; + objDef.DependsOn = + (Attribute.GetCustomAttribute(metadata, typeof(DependsOnAttribute)) as DependsOnAttribute).Name; } - private void LoadObjectDefinitionsForConfigurationClass(ConfigurationClass configClass) + //TODO: container does not presently support autowiring to the degree needed to support this feature as of yet + //Autowire autowire = (Autowire) ObjectAttributes.get("autowire"); + //if (autowire.isAutowire()) { + // ObjectDef.setAutowireMode(autowire.value()); + //} + + if (Attribute.GetCustomAttribute(metadata, typeof(ObjectDefAttribute)) != null) { - LoadObjectDefinitionForConfigurationClassIfNecessary(configClass); - - foreach (ConfigurationClassMethod method in configClass.Methods) - { - LoadObjectDefinitionsForModelMethod(method); - } - - LoadObjectDefinitionsFromImportedResources(configClass.ImportedResources); + objDef.InitMethodName = + (Attribute.GetCustomAttribute(metadata, typeof(ObjectDefAttribute)) as ObjectDefAttribute).InitMethod; + objDef.DestroyMethodName = + (Attribute.GetCustomAttribute(metadata, typeof(ObjectDefAttribute)) as ObjectDefAttribute).DestroyMethod; } - private void LoadObjectDefinitionsForModelMethod(ConfigurationClassMethod method) + // consider scoping + if (Attribute.GetCustomAttribute(metadata, typeof(ScopeAttribute)) != null) { - ConfigurationClass configClass = method.ConfigurationClass; - MethodInfo metadata = method.MethodMetadata; + objDef.Scope = + (Attribute.GetCustomAttribute(metadata, typeof(ScopeAttribute)) as ScopeAttribute).ObjectScope.ToString(); + } - RootObjectDefinition objDef = new ConfigurationClassObjectDefinition(); + Logger.LogDebug("Registering Object definition for [ObjectDef] method {TypeName}.{ObjectName}()", configClass.ConfigurationClassType.Name, objectName); - objDef.FactoryObjectName = configClass.ObjectName; - objDef.FactoryMethodName = metadata.Name; - objDef.AutowireMode = Objects.Factory.Config.AutoWiringMode.Constructor; + _registry.RegisterObjectDefinition(objectName, objDef); + } - // consider name and any aliases - //Dictionary ObjectAttributes = metadata.getAnnotationAttributes(Object.class.getName()); - object[] objectAttributes = metadata.GetCustomAttributes(typeof(ObjectDefAttribute), true); - List names = new List(); - foreach (object t in objectAttributes) + private void LoadObjectDefinitionsFromImportedResources(IEnumerable> importedResources) + { + IDictionary readerInstanceCache = + new Dictionary(); + foreach (KeyValuePair entry in importedResources) + { + String resource = entry.Key; + Type readerClass = entry.Value; + + if (!readerInstanceCache.ContainsKey(readerClass)) { - string[] namesAndAliases = ((ObjectDefAttribute)t).NamesToArray; - - if (namesAndAliases != null) + try { - names.Add(metadata.Name); + IObjectDefinitionReader readerInstance = + (IObjectDefinitionReader) Activator.CreateInstance(readerClass, _registry); + + readerInstanceCache.Add(readerClass, readerInstance); } - else + catch (Exception) { - namesAndAliases = new[] { metadata.Name }; - } - - names.AddRange(namesAndAliases); - } - - string objectName = (names.Count > 0 ? names[0] : method.MethodMetadata.Name); - for (int i = 1; i < names.Count; i++) - { - _registry.RegisterAlias(objectName, names[i]); - } - - // has this already been overridden (e.g. via XML)? - if (_registry.ContainsObjectDefinition(objectName)) - { - IObjectDefinition existingObjectDef = _registry.GetObjectDefinition(objectName); - // is the existing Object definition one that was created from a configuration class? - if (!(existingObjectDef is ConfigurationClassObjectDefinition)) - { - // no -> then it's an external override, probably XML - // overriding is legal, return immediately - Logger.LogDebug("Skipping loading Object definition for {Method}: a definition for object {ObjectName} already exists. This is likely due to an override in XML.", method, objectName); - return; + throw new InvalidOperationException( + String.Format("Could not instantiate IObjectDefinitionReader class {0}", + readerClass.FullName)); } } - //TODO: container does not presently support the concept of Primary object definition for type resolution - //if (Attribute.GetCustomAttribute(metadata, typeof(PrimaryAttribute)) != null) - //{ - // ObjectDef.isPrimary = true; - //} + IObjectDefinitionReader reader = readerInstanceCache[readerClass]; - // is this Object to be instantiated lazily? - if (Attribute.GetCustomAttribute(metadata, typeof(LazyAttribute)) != null) - { - objDef.IsLazyInit = - (Attribute.GetCustomAttribute(metadata, typeof(LazyAttribute)) as LazyAttribute).LazyInitialize; - } - - if (Attribute.GetCustomAttribute(metadata, typeof(DependsOnAttribute)) != null) - { - objDef.DependsOn = - (Attribute.GetCustomAttribute(metadata, typeof(DependsOnAttribute)) as DependsOnAttribute).Name; - } - - //TODO: container does not presently support autowiring to the degree needed to support this feature as of yet - //Autowire autowire = (Autowire) ObjectAttributes.get("autowire"); - //if (autowire.isAutowire()) { - // ObjectDef.setAutowireMode(autowire.value()); - //} - - if (Attribute.GetCustomAttribute(metadata, typeof(ObjectDefAttribute)) != null) - { - objDef.InitMethodName = - (Attribute.GetCustomAttribute(metadata, typeof(ObjectDefAttribute)) as ObjectDefAttribute). - InitMethod; - objDef.DestroyMethodName = - (Attribute.GetCustomAttribute(metadata, typeof(ObjectDefAttribute)) as ObjectDefAttribute). - DestroyMethod; - } - - // consider scoping - if (Attribute.GetCustomAttribute(metadata, typeof(ScopeAttribute)) != null) - { - objDef.Scope = - (Attribute.GetCustomAttribute(metadata, typeof(ScopeAttribute)) as ScopeAttribute).ObjectScope.ToString(); - } - - Logger.LogDebug("Registering Object definition for [ObjectDef] method {TypeName}.{ObjectName}()", configClass.ConfigurationClassType.Name, objectName); - - _registry.RegisterObjectDefinition(objectName, objDef); - } - - private void LoadObjectDefinitionsFromImportedResources(IEnumerable> importedResources) - { - IDictionary readerInstanceCache = - new Dictionary(); - foreach (KeyValuePair entry in importedResources) - { - String resource = entry.Key; - Type readerClass = entry.Value; - - if (!readerInstanceCache.ContainsKey(readerClass)) - { - try - { - IObjectDefinitionReader readerInstance = - (IObjectDefinitionReader)Activator.CreateInstance(readerClass, _registry); - - readerInstanceCache.Add(readerClass, readerInstance); - } - catch (Exception) - { - throw new InvalidOperationException( - String.Format("Could not instantiate IObjectDefinitionReader class {0}", - readerClass.FullName)); - } - } - - IObjectDefinitionReader reader = readerInstanceCache[readerClass]; - - reader.LoadObjectDefinitions(resource); - } - } - - private class ConfigurationClassObjectDefinition : RootObjectDefinition - { + reader.LoadObjectDefinitions(resource); } } + + private class ConfigurationClassObjectDefinition : RootObjectDefinition + { + } } diff --git a/src/Spring/Spring.Core/Context/Attributes/ConfigurationClassParser.cs b/src/Spring/Spring.Core/Context/Attributes/ConfigurationClassParser.cs index 814d07eb..25314828 100644 --- a/src/Spring/Spring.Core/Context/Attributes/ConfigurationClassParser.cs +++ b/src/Spring/Spring.Core/Context/Attributes/ConfigurationClassParser.cs @@ -22,171 +22,168 @@ using Spring.Objects.Factory.Parsing; using Spring.Collections.Generic; using System.Reflection; -namespace Spring.Context.Attributes +namespace Spring.Context.Attributes; + +/// +/// Parses classes with the applied to them. +/// +public class ConfigurationClassParser { + private Collections.Generic.ISet _configurationClasses = new HashedSet(); + + private Stack _importStack = new Stack(); + + private IProblemReporter _problemReporter; /// - /// Parses classes with the applied to them. + /// Initializes a new instance of the ConfigurationClassParser class. /// - public class ConfigurationClassParser + /// + public ConfigurationClassParser(IProblemReporter problemReporter) { - private Collections.Generic.ISet _configurationClasses = new HashedSet(); + _problemReporter = problemReporter; + } - private Stack _importStack = new Stack(); + /// + /// Gets the configuration classes. + /// + /// The configuration classes. + public Collections.Generic.ISet ConfigurationClasses + { + get { return _configurationClasses; } + } - private IProblemReporter _problemReporter; + /// + /// Parses the specified type. + /// + /// The type. + /// Name of the object. + public void Parse(Type type, string objectName) + { + ProcessConfigurationClass(new ConfigurationClass(objectName, type)); + } - /// - /// Initializes a new instance of the ConfigurationClassParser class. - /// - /// - public ConfigurationClassParser(IProblemReporter problemReporter) + /// + /// Validates this instance. + /// + public void Validate() + { + foreach (ConfigurationClass configClass in ConfigurationClasses) { - _problemReporter = problemReporter; + configClass.Validate(_problemReporter); + } + } + + /// + /// Processes the configuration class. + /// + /// The configuration class. + protected void ProcessConfigurationClass(ConfigurationClass configurationClass) + { + DoProcessConfigurationClass(configurationClass); + + if (ConfigurationClasses.Contains(configurationClass) && configurationClass.ObjectName != null) + { + // Explicit object definition found, probably replacing an import. + // Let's remove the old one and go with the new one. + ConfigurationClasses.Remove(configurationClass); } - /// - /// Gets the configuration classes. - /// - /// The configuration classes. - public Collections.Generic.ISet ConfigurationClasses - { - get { return _configurationClasses; } - } + ConfigurationClasses.Add(configurationClass); + } - /// - /// Parses the specified type. - /// - /// The type. - /// Name of the object. - public void Parse(Type type, string objectName) - { - ProcessConfigurationClass(new ConfigurationClass(objectName, type)); - } + private void DoProcessConfigurationClass(ConfigurationClass configurationClass) + { + Attribute[] importAttributes = Attribute.GetCustomAttributes(configurationClass.ConfigurationClassType, typeof(ImportAttribute)); - /// - /// Validates this instance. - /// - public void Validate() + if (importAttributes.Length > 0) { - foreach (ConfigurationClass configClass in ConfigurationClasses) + foreach (Attribute importAttribute in importAttributes) { - configClass.Validate(_problemReporter); - } - } + ImportAttribute attrib = importAttribute as ImportAttribute; - /// - /// Processes the configuration class. - /// - /// The configuration class. - protected void ProcessConfigurationClass(ConfigurationClass configurationClass) - { - DoProcessConfigurationClass(configurationClass); - - if (ConfigurationClasses.Contains(configurationClass) && configurationClass.ObjectName != null) - { - // Explicit object definition found, probably replacing an import. - // Let's remove the old one and go with the new one. - ConfigurationClasses.Remove(configurationClass); - } - ConfigurationClasses.Add(configurationClass); - } - - private void DoProcessConfigurationClass(ConfigurationClass configurationClass) - { - - Attribute[] importAttributes = Attribute.GetCustomAttributes(configurationClass.ConfigurationClassType, typeof(ImportAttribute)); - - if (importAttributes.Length > 0) - { - foreach (Attribute importAttribute in importAttributes) + if (null != attrib) { - ImportAttribute attrib = importAttribute as ImportAttribute; + ProcessImport(configurationClass, attrib.Types); + } + } + } - if (null != attrib) + Attribute[] importResourceAttributes = Attribute.GetCustomAttributes(configurationClass.ConfigurationClassType, typeof(ImportResourceAttribute)); + + if (importResourceAttributes.Length > 0) + { + foreach (Attribute importResourceAttribute in importResourceAttributes) + { + ImportResourceAttribute attrib = importResourceAttribute as ImportResourceAttribute; + + if (null != attrib) + { + foreach (string resource in attrib.Resources) { - ProcessImport(configurationClass, attrib.Types); + configurationClass.AddImportedResource(resource, attrib.DefinitionReader); } } } - - Attribute[] importResourceAttributes = Attribute.GetCustomAttributes(configurationClass.ConfigurationClassType, typeof(ImportResourceAttribute)); - - if (importResourceAttributes.Length > 0) - { - foreach (Attribute importResourceAttribute in importResourceAttributes) - { - ImportResourceAttribute attrib = importResourceAttribute as ImportResourceAttribute; - - if (null != attrib) - { - foreach (string resource in attrib.Resources) - { - configurationClass.AddImportedResource(resource, attrib.DefinitionReader); - } - } - } - } - - Collections.Generic.ISet definitionMethods = GetAllMethodsWithCustomAttributeForClass(configurationClass.ConfigurationClassType, typeof(ObjectDefAttribute)); - foreach (MethodInfo definitionMethod in definitionMethods) - { - configurationClass.Methods.Add(new ConfigurationClassMethod(definitionMethod, configurationClass)); - - } } - /// - /// Gets all methods with custom attribute for class. - /// - /// The class. - /// The custom attribute. - /// - public static Collections.Generic.ISet GetAllMethodsWithCustomAttributeForClass(Type theClass, Type customAttribute) + Collections.Generic.ISet definitionMethods = GetAllMethodsWithCustomAttributeForClass(configurationClass.ConfigurationClassType, typeof(ObjectDefAttribute)); + foreach (MethodInfo definitionMethod in definitionMethods) { - Collections.Generic.ISet methods = new HashedSet(); - - foreach (MethodInfo method in theClass.GetMethods()) - { - if (Attribute.GetCustomAttribute(method, customAttribute) != null) - { - methods.Add(method); - } - } - - return methods; + configurationClass.Methods.Add(new ConfigurationClassMethod(definitionMethod, configurationClass)); } + } - private void ProcessImport(ConfigurationClass configClass, IEnumerable classesToImport) + /// + /// Gets all methods with custom attribute for class. + /// + /// The class. + /// The custom attribute. + /// + public static Collections.Generic.ISet GetAllMethodsWithCustomAttributeForClass(Type theClass, Type customAttribute) + { + Collections.Generic.ISet methods = new HashedSet(); + + foreach (MethodInfo method in theClass.GetMethods()) { - if (_importStack.Contains(configClass)) + if (Attribute.GetCustomAttribute(method, customAttribute) != null) { - _problemReporter.Error(new CircularImportProblem(configClass, _importStack, configClass.ConfigurationClassType)); - } - else - { - _importStack.Push(configClass); - foreach (Type classToImport in classesToImport) - { - ProcessConfigurationClass(new ConfigurationClass(null, classToImport)); - } - _importStack.Pop(); + methods.Add(method); } } - private class CircularImportProblem : Problem + return methods; + } + + private void ProcessImport(ConfigurationClass configClass, IEnumerable classesToImport) + { + if (_importStack.Contains(configClass)) { - public CircularImportProblem(ConfigurationClass configClass, Stack importStack, Type configurationClassType) - : base(String.Format("A circular [Import] has been detected: " + - "Illegal attempt by [Configuration] class '{0}' to import class '{1}' as '{2}' is " + - "already present in the current import stack [{3}]", - importStack.Peek().SimpleName, configClass.SimpleName, - configClass.SimpleName, importStack), - new Location(importStack.Peek().Resource, configurationClassType) - ) - { } - + _problemReporter.Error(new CircularImportProblem(configClass, _importStack, configClass.ConfigurationClassType)); } + else + { + _importStack.Push(configClass); + foreach (Type classToImport in classesToImport) + { + ProcessConfigurationClass(new ConfigurationClass(null, classToImport)); + } + _importStack.Pop(); + } + } + + private class CircularImportProblem : Problem + { + public CircularImportProblem(ConfigurationClass configClass, Stack importStack, Type configurationClassType) + : base(String.Format("A circular [Import] has been detected: " + + "Illegal attempt by [Configuration] class '{0}' to import class '{1}' as '{2}' is " + + "already present in the current import stack [{3}]", + importStack.Peek().SimpleName, configClass.SimpleName, + configClass.SimpleName, importStack), + new Location(importStack.Peek().Resource, configurationClassType) + ) + { + } } } diff --git a/src/Spring/Spring.Core/Context/Attributes/ConfigurationClassPostProcessor.cs b/src/Spring/Spring.Core/Context/Attributes/ConfigurationClassPostProcessor.cs index 166f8fcc..a9469c41 100644 --- a/src/Spring/Spring.Core/Context/Attributes/ConfigurationClassPostProcessor.cs +++ b/src/Spring/Spring.Core/Context/Attributes/ConfigurationClassPostProcessor.cs @@ -26,156 +26,159 @@ using Spring.Objects.Factory.Support; using Spring.Objects.Factory.Config; using Spring.Collections.Generic; -namespace Spring.Context.Attributes +namespace Spring.Context.Attributes; + +/// +/// Postprocesses the applied types registered with the . +/// +public class ConfigurationClassPostProcessor : IObjectDefinitionRegistryPostProcessor, IOrdered { + private static readonly ILogger Logger = LogManager.GetLogger(); + + private bool _postProcessObjectDefinitionRegistryCalled; + + private bool _postProcessObjectFactoryCalled; + + private IProblemReporter _problemReporter = new FailFastProblemReporter(); + /// - /// Postprocesses the applied types registered with the . + /// Return the order value of this object, where a higher value means greater in + /// terms of sorting. /// - public class ConfigurationClassPostProcessor : IObjectDefinitionRegistryPostProcessor, IOrdered + /// + /// + ///

+ /// Normally starting with 0 or 1, with indicating + /// greatest. Same order values will result in arbitrary positions for the affected + /// objects. + ///

+ ///

+ /// Higher value can be interpreted as lower priority, consequently the first object + /// has highest priority. + ///

+ ///
+ /// The order value. + public int Order => int.MinValue; + + /// + /// Sets the problem reporter. + /// + /// The problem reporter. + public IProblemReporter ProblemReporter { - private static readonly ILogger Logger = LogManager.GetLogger(); + set { _problemReporter = (value ?? new FailFastProblemReporter()); } + } - private bool _postProcessObjectDefinitionRegistryCalled; - - private bool _postProcessObjectFactoryCalled; - - private IProblemReporter _problemReporter = new FailFastProblemReporter(); - - /// - /// Return the order value of this object, where a higher value means greater in - /// terms of sorting. - /// - /// - /// - ///

- /// Normally starting with 0 or 1, with indicating - /// greatest. Same order values will result in arbitrary positions for the affected - /// objects. - ///

- ///

- /// Higher value can be interpreted as lower priority, consequently the first object - /// has highest priority. - ///

- ///
- /// The order value. - public int Order => int.MinValue; - - /// - /// Sets the problem reporter. - /// - /// The problem reporter. - public IProblemReporter ProblemReporter + /// + /// Postsprocesses the object definition registry. + /// + /// The registry. + public void PostProcessObjectDefinitionRegistry(IObjectDefinitionRegistry registry) + { + if (_postProcessObjectDefinitionRegistryCalled) { - set { _problemReporter = (value ?? new FailFastProblemReporter()); } + throw new InvalidOperationException("PostProcessObjectDefinitionRegistry already called for this post-processor"); } - /// - /// Postsprocesses the object definition registry. - /// - /// The registry. - public void PostProcessObjectDefinitionRegistry(IObjectDefinitionRegistry registry) + if (_postProcessObjectFactoryCalled) { - if (_postProcessObjectDefinitionRegistryCalled) - { - throw new InvalidOperationException("PostProcessObjectDefinitionRegistry already called for this post-processor"); - } - if (_postProcessObjectFactoryCalled) - { - throw new InvalidOperationException("PostProcessObjectFactory already called for this post-processor"); - } - _postProcessObjectDefinitionRegistryCalled = true; - ProcessConfigObjectDefinitions(registry); + throw new InvalidOperationException("PostProcessObjectFactory already called for this post-processor"); } - /// - /// Postprocesses the object factory. - /// - /// The object factory. - public void PostProcessObjectFactory(IConfigurableListableObjectFactory objectFactory) - { - if (_postProcessObjectFactoryCalled) - { - throw new InvalidOperationException( - "PostProcessObjectFactory already called for this post-processor"); - } - _postProcessObjectFactoryCalled = true; - if (!_postProcessObjectDefinitionRegistryCalled) - { - // ObjectDefinitionRegistryPostProcessor hook apparently not supported... - // Simply call processConfigObjectDefinitions lazily at this point then. - ProcessConfigObjectDefinitions((IObjectDefinitionRegistry)objectFactory); - } + _postProcessObjectDefinitionRegistryCalled = true; + ProcessConfigObjectDefinitions(registry); + } - EnhanceConfigurationClasses(objectFactory); + /// + /// Postprocesses the object factory. + /// + /// The object factory. + public void PostProcessObjectFactory(IConfigurableListableObjectFactory objectFactory) + { + if (_postProcessObjectFactoryCalled) + { + throw new InvalidOperationException( + "PostProcessObjectFactory already called for this post-processor"); } - private void EnhanceConfigurationClasses(IConfigurableListableObjectFactory objectFactory) + _postProcessObjectFactoryCalled = true; + if (!_postProcessObjectDefinitionRegistryCalled) { - ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer(objectFactory); - - var objectNames = objectFactory.GetObjectDefinitionNames(); - - foreach (string name in objectNames) - { - IObjectDefinition objDef = objectFactory.GetObjectDefinition(name); - - if (((AbstractObjectDefinition)objDef).HasObjectType) - { - if (Attribute.GetCustomAttribute(objDef.ObjectType, typeof(ConfigurationAttribute)) != null) - { - //TODO check type of object isn't infrastructure type. - - Type configClass = objDef.ObjectType; - Type enhancedClass = enhancer.Enhance(configClass); - - Logger.LogDebug("Replacing object definition '{Name}' existing class '{FullName}' with enhanced class", name, configClass.FullName); - - ((IConfigurableObjectDefinition)objDef).ObjectType = enhancedClass; - } - } - } + // ObjectDefinitionRegistryPostProcessor hook apparently not supported... + // Simply call processConfigObjectDefinitions lazily at this point then. + ProcessConfigObjectDefinitions((IObjectDefinitionRegistry) objectFactory); } - private void ProcessConfigObjectDefinitions(IObjectDefinitionRegistry registry) + EnhanceConfigurationClasses(objectFactory); + } + + private void EnhanceConfigurationClasses(IConfigurableListableObjectFactory objectFactory) + { + ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer(objectFactory); + + var objectNames = objectFactory.GetObjectDefinitionNames(); + + foreach (string name in objectNames) { - Collections.Generic.ISet configCandidates = new HashedSet(); - foreach (string objectName in registry.GetObjectDefinitionNames()) + IObjectDefinition objDef = objectFactory.GetObjectDefinition(name); + + if (((AbstractObjectDefinition) objDef).HasObjectType) { - IObjectDefinition objectDef = registry.GetObjectDefinition(objectName); - if (ConfigurationClassObjectDefinitionReader.CheckConfigurationClassCandidate(objectDef)) + if (Attribute.GetCustomAttribute(objDef.ObjectType, typeof(ConfigurationAttribute)) != null) { - configCandidates.Add(new ObjectDefinitionHolder(objectDef, objectName)); + //TODO check type of object isn't infrastructure type. + + Type configClass = objDef.ObjectType; + Type enhancedClass = enhancer.Enhance(configClass); + + Logger.LogDebug("Replacing object definition '{Name}' existing class '{FullName}' with enhanced class", name, configClass.FullName); + + ((IConfigurableObjectDefinition) objDef).ObjectType = enhancedClass; } } - - //if nothing to process, bail out - if (configCandidates.Count == 0) { return; } - - ConfigurationClassParser parser = new ConfigurationClassParser(_problemReporter); - foreach (ObjectDefinitionHolder holder in configCandidates) - { - IObjectDefinition bd = holder.ObjectDefinition; - try - { - if (bd is AbstractObjectDefinition && ((AbstractObjectDefinition)bd).HasObjectType) - { - parser.Parse(((AbstractObjectDefinition)bd).ObjectType, holder.ObjectName); - } - else - { - //parser.Parse(bd.ObjectTypeName, holder.ObjectName); - } - } - catch (ObjectDefinitionParsingException ex) - { - throw new ObjectDefinitionStoreException("Failed to load object class: " + bd.ObjectTypeName, ex); - } - } - parser.Validate(); - - // Read the model and create Object definitions based on its content - ConfigurationClassObjectDefinitionReader reader = new ConfigurationClassObjectDefinitionReader(registry, _problemReporter); - reader.LoadObjectDefinitions(parser.ConfigurationClasses); } } + + private void ProcessConfigObjectDefinitions(IObjectDefinitionRegistry registry) + { + Collections.Generic.ISet configCandidates = new HashedSet(); + foreach (string objectName in registry.GetObjectDefinitionNames()) + { + IObjectDefinition objectDef = registry.GetObjectDefinition(objectName); + if (ConfigurationClassObjectDefinitionReader.CheckConfigurationClassCandidate(objectDef)) + { + configCandidates.Add(new ObjectDefinitionHolder(objectDef, objectName)); + } + } + + //if nothing to process, bail out + if (configCandidates.Count == 0) { return; } + + ConfigurationClassParser parser = new ConfigurationClassParser(_problemReporter); + foreach (ObjectDefinitionHolder holder in configCandidates) + { + IObjectDefinition bd = holder.ObjectDefinition; + try + { + if (bd is AbstractObjectDefinition && ((AbstractObjectDefinition) bd).HasObjectType) + { + parser.Parse(((AbstractObjectDefinition) bd).ObjectType, holder.ObjectName); + } + else + { + //parser.Parse(bd.ObjectTypeName, holder.ObjectName); + } + } + catch (ObjectDefinitionParsingException ex) + { + throw new ObjectDefinitionStoreException("Failed to load object class: " + bd.ObjectTypeName, ex); + } + } + + parser.Validate(); + + // Read the model and create Object definitions based on its content + ConfigurationClassObjectDefinitionReader reader = new ConfigurationClassObjectDefinitionReader(registry, _problemReporter); + reader.LoadObjectDefinitions(parser.ConfigurationClasses); + } } diff --git a/src/Spring/Spring.Core/Context/Attributes/DependsOnAttribute.cs b/src/Spring/Spring.Core/Context/Attributes/DependsOnAttribute.cs index fd0c24e2..540908d0 100644 --- a/src/Spring/Spring.Core/Context/Attributes/DependsOnAttribute.cs +++ b/src/Spring/Spring.Core/Context/Attributes/DependsOnAttribute.cs @@ -18,55 +18,53 @@ #endregion -namespace Spring.Context.Attributes +namespace Spring.Context.Attributes; + +/// +/// objects on which the current object depends. Any objects specified are guaranteed to be +/// created by the container before this object. Used infrequently in cases where a object +/// does not explicitly depend on another through properties or constructor arguments, +/// but rather depends on the side effects of another object's initialization. +/// Note: This attribute will not be inherited by child object definitions, +/// hence it needs to be specified per concrete object definition. +/// +/// Using at the class level has no effect unless component-scanning +/// is being used. If a -attributed class is declared via XML, +/// attribute metadata is ignored, and +/// <object depends-on="..."/> is respected instead. +/// +/// +[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)] +public class DependsOnAttribute : Attribute { + private string[] _name; + /// - /// objects on which the current object depends. Any objects specified are guaranteed to be - /// created by the container before this object. Used infrequently in cases where a object - /// does not explicitly depend on another through properties or constructor arguments, - /// but rather depends on the side effects of another object's initialization. - /// Note: This attribute will not be inherited by child object definitions, - /// hence it needs to be specified per concrete object definition. - /// - /// Using at the class level has no effect unless component-scanning - /// is being used. If a -attributed class is declared via XML, - /// attribute metadata is ignored, and - /// <object depends-on="..."/> is respected instead. - /// + /// Initializes a new instance of the DependsOn class. /// - [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)] - public class DependsOnAttribute : Attribute + public DependsOnAttribute(string name) + : this(new[] { name }) { - private string[] _name; + } - /// - /// Initializes a new instance of the DependsOn class. - /// - public DependsOnAttribute(string name) - : this(new[] { name }) + /// + /// Initializes a new instance of the DependsOn class. + /// + public DependsOnAttribute(params string[] name) + { + _name = name; + } + + /// + /// Gets or sets the name. + /// + /// The name. + public string[] Name + { + get { return _name; } + set { + _name = value; } - - /// - /// Initializes a new instance of the DependsOn class. - /// - public DependsOnAttribute(params string[] name) - { - _name = name; - } - - /// - /// Gets or sets the name. - /// - /// The name. - public string[] Name - { - get { return _name; } - set - { - _name = value; - } - } - } } diff --git a/src/Spring/Spring.Core/Context/Attributes/IAssemblyTypeScanner.cs b/src/Spring/Spring.Core/Context/Attributes/IAssemblyTypeScanner.cs index b941f0b5..eb2b3dc0 100644 --- a/src/Spring/Spring.Core/Context/Attributes/IAssemblyTypeScanner.cs +++ b/src/Spring/Spring.Core/Context/Attributes/IAssemblyTypeScanner.cs @@ -20,68 +20,65 @@ using System.Reflection; -namespace Spring.Context.Attributes +namespace Spring.Context.Attributes; + +/// +/// Scanner that can filter types from assemblies based on constraints. +/// +public interface IAssemblyTypeScanner { + /// + /// Add the Assembly containing the specified . + /// + /// + /// + IAssemblyTypeScanner AssemblyHavingType(); /// - /// Scanner that can filter types from assemblies based on constraints. + /// Adds the predicate to the assembly filter constraints. /// - public interface IAssemblyTypeScanner - { - /// - /// Add the Assembly containing the specified . - /// - /// - /// - IAssemblyTypeScanner AssemblyHavingType(); - - /// - /// Adds the predicate to the assembly filter constraints. - /// - /// The assembly predicate. - /// - IAssemblyTypeScanner WithAssemblyFilter(Func assemblyPredicate); + /// The assembly predicate. + /// + IAssemblyTypeScanner WithAssemblyFilter(Func assemblyPredicate); - /// - /// Adds the predicte to the include filter for . - /// - /// The predicate. - /// - IAssemblyTypeScanner WithIncludeFilter(Func predicate); + /// + /// Adds the predicte to the include filter for . + /// + /// The predicate. + /// + IAssemblyTypeScanner WithIncludeFilter(Func predicate); - /// - /// Adds the predicte to the exclude filter for . - /// - /// The predicate. - /// - IAssemblyTypeScanner WithExcludeFilter(Func predicate); + /// + /// Adds the predicte to the exclude filter for . + /// + /// The predicate. + /// + IAssemblyTypeScanner WithExcludeFilter(Func predicate); - /// - /// Includes the specific types. - /// - /// The types. - /// - IAssemblyTypeScanner IncludeTypes(IEnumerable typeSource); + /// + /// Includes the specific types. + /// + /// The types. + /// + IAssemblyTypeScanner IncludeTypes(IEnumerable typeSource); + /// + /// Includes the type. + /// + /// The to include. + /// + IAssemblyTypeScanner IncludeType(); - /// - /// Includes the type. - /// - /// The to include. - /// - IAssemblyTypeScanner IncludeType(); + /// + /// Excludes the type. + /// + /// The to exclude. + /// + IAssemblyTypeScanner ExcludeType(); - /// - /// Excludes the type. - /// - /// The to exclude. - /// - IAssemblyTypeScanner ExcludeType(); - - /// - /// Perform the Scan, applying all provided - /// - /// - IEnumerable Scan(); - } + /// + /// Perform the Scan, applying all provided + /// + /// + IEnumerable Scan(); } diff --git a/src/Spring/Spring.Core/Context/Attributes/ImportAttribute.cs b/src/Spring/Spring.Core/Context/Attributes/ImportAttribute.cs index 9376e443..8efdeb1e 100644 --- a/src/Spring/Spring.Core/Context/Attributes/ImportAttribute.cs +++ b/src/Spring/Spring.Core/Context/Attributes/ImportAttribute.cs @@ -18,52 +18,50 @@ #endregion -namespace Spring.Context.Attributes +namespace Spring.Context.Attributes; + +/// +/// Indicates one or more classes to import. +/// +/// Provides functionality equivalent to the <import/> element in Spring XML. +/// Only supported for actual -attributed classes. +/// +/// +/// If XML or other non- object definition resources need to be +/// imported, use +/// +/// +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] +public class ImportAttribute : Attribute { + private Type[] _types; + /// - /// Indicates one or more classes to import. - /// - /// Provides functionality equivalent to the <import/> element in Spring XML. - /// Only supported for actual -attributed classes. - /// - /// - /// If XML or other non- object definition resources need to be - /// imported, use - /// + /// Initializes a new instance of the Import class. /// - [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] - public class ImportAttribute : Attribute + public ImportAttribute(Type type) : this(new[] { type }) { - private Type[] _types; - - /// - /// Initializes a new instance of the Import class. - /// - public ImportAttribute(Type type) : this(new []{ type }) - { - } + } - /// - /// Initializes a new instance of the Import class. - /// - /// - public ImportAttribute(params Type[] types) - { - _types = types; - } + /// + /// Initializes a new instance of the Import class. + /// + /// + public ImportAttribute(params Type[] types) + { + _types = types; + } - /// - /// The class or classes to import. - /// - /// The type. - public Type[] Types + /// + /// The class or classes to import. + /// + /// The type. + public Type[] Types + { + get { return _types; } + set { - get { return _types; } - set - { - _types = value; - } + _types = value; } - } } diff --git a/src/Spring/Spring.Core/Context/Attributes/ImportResourceAttribute.cs b/src/Spring/Spring.Core/Context/Attributes/ImportResourceAttribute.cs index b78d829f..0f54e1c8 100644 --- a/src/Spring/Spring.Core/Context/Attributes/ImportResourceAttribute.cs +++ b/src/Spring/Spring.Core/Context/Attributes/ImportResourceAttribute.cs @@ -23,76 +23,73 @@ using Spring.Objects.Factory.Support; using Spring.Objects.Factory.Xml; using Spring.Util; -namespace Spring.Context.Attributes +namespace Spring.Context.Attributes; + +/// +/// Supports providing one or more implementations to import when creating s. +/// +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] +public class ImportResourceAttribute : Attribute { + private Type _objectDefinitionReader = typeof(XmlObjectDefinitionReader); + + private string[] _resources; + /// - /// Supports providing one or more implementations to import when creating s. + /// Initializes a new instance of the ImportResourceAttribute class. /// - [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] - public class ImportResourceAttribute : Attribute + /// + public ImportResourceAttribute(string[] resources) { - private Type _objectDefinitionReader = typeof(XmlObjectDefinitionReader); + if (resources == null || resources.Length == 0) + throw new ArgumentException("resources cannot be null or empty!"); - private string[] _resources; + _resources = resources; + } - /// - /// Initializes a new instance of the ImportResourceAttribute class. - /// - /// - public ImportResourceAttribute(string[] resources) + /// + /// Initializes a new instance of the ImportResourceAttribute class. + /// + /// + public ImportResourceAttribute(string resource) + { + if (StringUtils.IsNullOrEmpty(resource)) + throw new ArgumentException("resource cannot be null or empty!"); + + _resources = new[] { resource }; + } + + /// + /// implementation to use when processing resources specified + /// by the attribute. + /// + /// The . + public Type DefinitionReader + { + get { - if (resources ==null || resources.Length ==0) - throw new ArgumentException("resources cannot be null or empty!"); - - _resources = resources; + return _objectDefinitionReader; } - - - /// - /// Initializes a new instance of the ImportResourceAttribute class. - /// - /// - public ImportResourceAttribute(string resource) + set { - if (StringUtils.IsNullOrEmpty(resource)) - throw new ArgumentException("resource cannot be null or empty!"); - - _resources = new[] { resource }; - } + if (!((typeof(IObjectDefinitionReader).IsAssignableFrom(value)))) + throw new ArgumentException(string.Format("DefinitionReader must be of type IObjectDefinitionReader but was of type {0}", value.Name)); - /// - /// implementation to use when processing resources specified - /// by the attribute. - /// - /// The . - public Type DefinitionReader + _objectDefinitionReader = value; + } + } + + /// + /// Resource paths to import. Resource-loading prefixes such as assembly:// and + /// file://, etc may be used. + /// + /// The resources. + public string[] Resources + { + get { return _resources; } + set { - get - { - return _objectDefinitionReader; - } - set - { - if (!((typeof(IObjectDefinitionReader).IsAssignableFrom(value)))) - throw new ArgumentException(string.Format("DefinitionReader must be of type IObjectDefinitionReader but was of type {0}", value.Name)); - - _objectDefinitionReader = value; - } + _resources = value; } - - /// - /// Resource paths to import. Resource-loading prefixes such as assembly:// and - /// file://, etc may be used. - /// - /// The resources. - public string[] Resources - { - get { return _resources; } - set - { - _resources = value; - } - } - } } diff --git a/src/Spring/Spring.Core/Context/Attributes/LazyAttribute.cs b/src/Spring/Spring.Core/Context/Attributes/LazyAttribute.cs index e6dc094f..32c2f157 100644 --- a/src/Spring/Spring.Core/Context/Attributes/LazyAttribute.cs +++ b/src/Spring/Spring.Core/Context/Attributes/LazyAttribute.cs @@ -18,60 +18,57 @@ #endregion -namespace Spring.Context.Attributes +namespace Spring.Context.Attributes; + +/// +/// Indicates whether a object is to be lazily initialized. +/// +/// If this attribute is not present on a Component or object definition, eager +/// initialization will occur. If present and set to true, the +/// object/Component will not be initialized until referenced by another object or +/// explicitly retrieved from the enclosing . +/// If present and set to false, the object will be instantiated on startup by object factories +/// that perform eager initialization of singletons. +/// +/// +/// If Lazy is present on a class, this indicates that all +/// methods within that should be lazily +/// initialized. If Lazy is present and false on a object method within a +/// Lazy-annotated Configuration class, this indicates overriding the 'default +/// lazy' behavior and that the object should be eagerly initialized. +/// +/// +[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)] +public class LazyAttribute : Attribute { + private bool _lazyInitialize = true; + /// - /// Indicates whether a object is to be lazily initialized. - /// - /// If this attribute is not present on a Component or object definition, eager - /// initialization will occur. If present and set to true, the - /// object/Component will not be initialized until referenced by another object or - /// explicitly retrieved from the enclosing . - /// If present and set to false, the object will be instantiated on startup by object factories - /// that perform eager initialization of singletons. - /// - /// - /// If Lazy is present on a class, this indicates that all - /// methods within that should be lazily - /// initialized. If Lazy is present and false on a object method within a - /// Lazy-annotated Configuration class, this indicates overriding the 'default - /// lazy' behavior and that the object should be eagerly initialized. - /// + /// Initializes a new instance of the LazyAttribute class. /// - [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)] - public class LazyAttribute : Attribute + /// + public LazyAttribute(bool lazyInitialize) { - private bool _lazyInitialize = true; + _lazyInitialize = lazyInitialize; + } - /// - /// Initializes a new instance of the LazyAttribute class. - /// - /// - public LazyAttribute(bool lazyInitialize) + /// + /// Initializes a new instance of the LazyAttribute class. + /// + public LazyAttribute() + { + } + + /// + /// Whether lazy initialization should occur. + /// + /// true if [lazy initialize]; otherwise, false. + public bool LazyInitialize + { + get { return _lazyInitialize; } + set { - _lazyInitialize = lazyInitialize; + _lazyInitialize = value; } - - /// - /// Initializes a new instance of the LazyAttribute class. - /// - public LazyAttribute() - { - - } - - /// - /// Whether lazy initialization should occur. - /// - /// true if [lazy initialize]; otherwise, false. - public bool LazyInitialize - { - get { return _lazyInitialize; } - set - { - _lazyInitialize = value; - } - } - } } diff --git a/src/Spring/Spring.Core/Context/Attributes/ObjectDefAttribute.cs b/src/Spring/Spring.Core/Context/Attributes/ObjectDefAttribute.cs index 370e804e..18f426c1 100644 --- a/src/Spring/Spring.Core/Context/Attributes/ObjectDefAttribute.cs +++ b/src/Spring/Spring.Core/Context/Attributes/ObjectDefAttribute.cs @@ -20,101 +20,99 @@ using Spring.Util; -namespace Spring.Context.Attributes +namespace Spring.Context.Attributes; + +/// +/// Identifies the Method as providing and Object Definition. +/// +[AttributeUsage(AttributeTargets.Method)] +public class ObjectDefAttribute : Attribute { + //private AutoWiringMode _autoWire = AutoWiringMode.No; + + private string _destroyMethod; + + private string _initMethod; + + private string _names; + + //TODO: constructor injection via factory methods is not presently supported by the container + ///// + ///// Are dependencies to be injected via autowiring? + ///// + ///// The auto wire. + //public AutoWiringMode AutoWire + //{ + // get { return _autoWire; } + // set + // { + // _autoWire = value; + // } + //} + /// - /// Identifies the Method as providing and Object Definition. + /// The optional name of a method to call on the Object instance upon closing the + /// application context, for example a Close() method on a DataSource. + /// The method must have no arguments but may throw any exception. + /// + /// Note: Only invoked on objects whose lifecycle is under the full control of the + /// factory, which is always the case for singletons but not guaranteed + /// for any other scope. + /// + /// /// - [AttributeUsage(AttributeTargets.Method)] - public class ObjectDefAttribute : Attribute + /// The destroy method. + public string DestroyMethod { - //private AutoWiringMode _autoWire = AutoWiringMode.No; - - private string _destroyMethod; - - private string _initMethod; - - private string _names; - - //TODO: constructor injection via factory methods is not presently supported by the container - ///// - ///// Are dependencies to be injected via autowiring? - ///// - ///// The auto wire. - //public AutoWiringMode AutoWire - //{ - // get { return _autoWire; } - // set - // { - // _autoWire = value; - // } - //} - - /// - /// The optional name of a method to call on the Object instance upon closing the - /// application context, for example a Close() method on a DataSource. - /// The method must have no arguments but may throw any exception. - /// - /// Note: Only invoked on objects whose lifecycle is under the full control of the - /// factory, which is always the case for singletons but not guaranteed - /// for any other scope. - /// - /// - /// - /// The destroy method. - public string DestroyMethod + get { return _destroyMethod; } + set { - get { return _destroyMethod; } - set - { - _destroyMethod = value; - } + _destroyMethod = value; } + } - /// - /// The optional name of a method to call on the object instance during initialization. - /// Not commonly used, given that the method may be called programmatically directly - /// within the body of a Object-annotated method. - /// - /// The init method. - public string InitMethod + /// + /// The optional name of a method to call on the object instance during initialization. + /// Not commonly used, given that the method may be called programmatically directly + /// within the body of a Object-annotated method. + /// + /// The init method. + public string InitMethod + { + get { return _initMethod; } + set { - get { return _initMethod; } - set - { - _initMethod = value; - } + _initMethod = value; } + } - /// - /// The name of this object, or if multiple, aliases for this object. If left unspecified - /// the name of the object is the name of the attributed method. If specified, the method - /// name is ignored. - /// - /// The name. - public string Names + /// + /// The name of this object, or if multiple, aliases for this object. If left unspecified + /// the name of the object is the name of the attributed method. If specified, the method + /// name is ignored. + /// + /// The name. + public string Names + { + get { - get - { - return _names; - } - set - { - _names = value; - } + return _names; } - - /// - /// Gets the comma-delimited list of names/aliases as an array. - /// - /// The array of names. - public string[] NamesToArray + set { - get - { - return StringUtils.DelimitedListToStringArray(_names, ","); - } + _names = value; } + } + /// + /// Gets the comma-delimited list of names/aliases as an array. + /// + /// The array of names. + public string[] NamesToArray + { + get + { + return StringUtils.DelimitedListToStringArray(_names, ","); + } } } diff --git a/src/Spring/Spring.Core/Context/Attributes/RequiredConstraintAssemblyTypeScanner.cs b/src/Spring/Spring.Core/Context/Attributes/RequiredConstraintAssemblyTypeScanner.cs index 5cb2f8fb..4fb46edd 100644 --- a/src/Spring/Spring.Core/Context/Attributes/RequiredConstraintAssemblyTypeScanner.cs +++ b/src/Spring/Spring.Core/Context/Attributes/RequiredConstraintAssemblyTypeScanner.cs @@ -18,35 +18,33 @@ #endregion -namespace Spring.Context.Attributes +namespace Spring.Context.Attributes; + +/// +/// AssemblyTypeScanner that provides for applying a final hard-coded Required Constraint to all types found in the the scanned assemblies +/// in addition to respecting the constraints passed to it during its configuration. +/// +[Serializable] +public abstract class RequiredConstraintAssemblyTypeScanner : AssemblyTypeScanner { /// - /// AssemblyTypeScanner that provides for applying a final hard-coded Required Constraint to all types found in the the scanned assemblies - /// in addition to respecting the constraints passed to it during its configuration. + /// Determines whether the compound predicate is satisfied by the specified type. /// - [Serializable] - public abstract class RequiredConstraintAssemblyTypeScanner : AssemblyTypeScanner + /// The type. + /// + /// true if the compound predicate is satisfied by the specified type; otherwise, false. + /// + protected override bool IsCompoundPredicateSatisfiedBy(Type type) { - - /// - /// Determines whether the compound predicate is satisfied by the specified type. - /// - /// The type. - /// - /// true if the compound predicate is satisfied by the specified type; otherwise, false. - /// - protected override bool IsCompoundPredicateSatisfiedBy(Type type) - { - return IsRequiredConstraintSatisfiedBy(type) && IsIncludedType(type) && !IsExcludedType(type); - } - - /// - /// Determines whether the required constraint is satisfied by the specified type. - /// - /// The type. - /// - /// true if the required constraint is satisfied by the specified type; otherwise, false. - /// - protected abstract bool IsRequiredConstraintSatisfiedBy(Type type); + return IsRequiredConstraintSatisfiedBy(type) && IsIncludedType(type) && !IsExcludedType(type); } + + /// + /// Determines whether the required constraint is satisfied by the specified type. + /// + /// The type. + /// + /// true if the required constraint is satisfied by the specified type; otherwise, false. + /// + protected abstract bool IsRequiredConstraintSatisfiedBy(Type type); } diff --git a/src/Spring/Spring.Core/Context/Attributes/ScannedGenericObjectDefinition.cs b/src/Spring/Spring.Core/Context/Attributes/ScannedGenericObjectDefinition.cs index cdfe2fa0..af1bc453 100644 --- a/src/Spring/Spring.Core/Context/Attributes/ScannedGenericObjectDefinition.cs +++ b/src/Spring/Spring.Core/Context/Attributes/ScannedGenericObjectDefinition.cs @@ -26,137 +26,135 @@ using Spring.Objects.Factory.Xml; using Spring.Stereotype; using Spring.Objects.Factory.Attributes; -namespace Spring.Context.Attributes +namespace Spring.Context.Attributes; + +/// +/// A GenericObjectDefinition that provides attribute driven propulation +/// of properties like LazyInit, Scope or Qualifier +/// +public class ScannedGenericObjectDefinition : GenericObjectDefinition { + private static readonly ILogger Log = LogManager.GetLogger(); + /// - /// A GenericObjectDefinition that provides attribute driven propulation - /// of properties like LazyInit, Scope or Qualifier + /// Name provided by the Component Attribute /// - public class ScannedGenericObjectDefinition : GenericObjectDefinition + private string _componentName; + + /// + /// Creates a GenericObjectDefinition that applies the default values provided + /// in the XML Spring config document. Additionally parses the specific class + /// attributesthat allows the definition of LazyInit, Scope or Qualifier + /// + /// Type of scanned component + /// Defualts provided in Spring Config document + public ScannedGenericObjectDefinition(Type typeOfObject, DocumentDefaultsDefinition defaults) { - private static readonly ILogger Log = LogManager.GetLogger(); + ObjectType = typeOfObject; - /// - /// Name provided by the Component Attribute - /// - private string _componentName; + ParseName(); + ApplyDefaults(defaults); + ParseLazyAttribute(); + ParseScopeAttribute(); + ParseQualifierAttribute(); - /// - /// Creates a GenericObjectDefinition that applies the default values provided - /// in the XML Spring config document. Additionally parses the specific class - /// attributesthat allows the definition of LazyInit, Scope or Qualifier - /// - /// Type of scanned component - /// Defualts provided in Spring Config document - public ScannedGenericObjectDefinition(Type typeOfObject, DocumentDefaultsDefinition defaults) + if (Log.IsEnabled(LogLevel.Debug)) { - ObjectType = typeOfObject; + Log.LogDebug("ComponentName: {ComponentNAme}; {Name}", _componentName, ToString()); + } + } - ParseName(); - ApplyDefaults(defaults); - ParseLazyAttribute(); - ParseScopeAttribute(); - ParseQualifierAttribute(); + private void ParseName() + { + var attr = Attribute.GetCustomAttribute(ObjectType, typeof(ComponentAttribute), true) as ComponentAttribute; + if (attr != null && !string.IsNullOrEmpty(attr.Name)) + _componentName = attr.Name; + } - if (Log.IsEnabled(LogLevel.Debug)) + private void ApplyDefaults(DocumentDefaultsDefinition defaults) + { + if (defaults == null) + return; + + bool lazyInit = false; + bool.TryParse(defaults.LazyInit, out lazyInit); + IsLazyInit = lazyInit; + + if (!String.IsNullOrEmpty(defaults.Autowire)) + { + AutowireMode = GetAutowireMode(defaults.Autowire); + } + } + + private AutoWiringMode GetAutowireMode(string value) + { + AutoWiringMode autoWiringMode; + autoWiringMode = (AutoWiringMode) Enum.Parse(typeof(AutoWiringMode), value, true); + return autoWiringMode; + } + + private void ParseScopeAttribute() + { + var attr = Attribute.GetCustomAttribute(ObjectType, typeof(ScopeAttribute), true) as ScopeAttribute; + if (attr != null) + { + Scope = attr.ObjectScope.ToString().ToLower(); + + if (attr.ObjectScope == ObjectScope.Request || attr.ObjectScope == ObjectScope.Session) { - Log.LogDebug("ComponentName: {ComponentNAme}; {Name}", _componentName, ToString()); - } - } - - private void ParseName() - { - var attr = Attribute.GetCustomAttribute(ObjectType, typeof (ComponentAttribute), true) as ComponentAttribute; - if (attr != null && !string.IsNullOrEmpty(attr.Name)) - _componentName = attr.Name; - } - - private void ApplyDefaults(DocumentDefaultsDefinition defaults) - { - if (defaults == null) - return; - - bool lazyInit = false; - bool.TryParse(defaults.LazyInit, out lazyInit); - IsLazyInit = lazyInit; - - if (!String.IsNullOrEmpty(defaults.Autowire)) - { - AutowireMode = GetAutowireMode(defaults.Autowire); - } - } - - private AutoWiringMode GetAutowireMode(string value) - { - AutoWiringMode autoWiringMode; - autoWiringMode = (AutoWiringMode)Enum.Parse(typeof(AutoWiringMode), value, true); - return autoWiringMode; - } - - - private void ParseScopeAttribute() - { - var attr = Attribute.GetCustomAttribute(ObjectType, typeof(ScopeAttribute), true) as ScopeAttribute; - if (attr != null) - { - Scope = attr.ObjectScope.ToString().ToLower(); - - if (attr.ObjectScope == ObjectScope.Request || attr.ObjectScope == ObjectScope.Session) - { - IsLazyInit = true; - } - } - } - - private void ParseLazyAttribute() - { - var attr = Attribute.GetCustomAttribute(ObjectType, typeof(LazyAttribute), true) as LazyAttribute; - if (attr != null) - IsLazyInit = attr.LazyInitialize; - } - - private void ParseQualifierAttribute() - { - var attr = Attribute.GetCustomAttribute(ObjectType, typeof(QualifierAttribute), true) as QualifierAttribute; - if (attr != null) - { - var qualifier = new AutowireCandidateQualifier(attr.GetType()); - - if (!string.IsNullOrEmpty(attr.Value)) - qualifier.SetAttribute(AutowireCandidateQualifier.VALUE_KEY, attr.Value); - - ParseQualifierProperties(attr, qualifier); - - AddQualifier(qualifier); - } - } - - private void ParseQualifierProperties(QualifierAttribute attr, AutowireCandidateQualifier qualifier) - { - foreach (var property in attr.GetType().GetProperties()) - { - if (!property.Name.Equals("TypeId") && !property.Name.Equals("Value")) - { - object value = property.GetValue(attr, null); - if (value != null) - { - var attribute = new ObjectMetadataAttribute(property.Name, value); - qualifier.AddMetadataAttribute(attribute); - } - } - } - } - - /// - /// Provides the name of the object scanned - /// - /// return the provided attribute name of the full object type name - public string ComponentName - { - get - { - return _componentName; + IsLazyInit = true; } } } + + private void ParseLazyAttribute() + { + var attr = Attribute.GetCustomAttribute(ObjectType, typeof(LazyAttribute), true) as LazyAttribute; + if (attr != null) + IsLazyInit = attr.LazyInitialize; + } + + private void ParseQualifierAttribute() + { + var attr = Attribute.GetCustomAttribute(ObjectType, typeof(QualifierAttribute), true) as QualifierAttribute; + if (attr != null) + { + var qualifier = new AutowireCandidateQualifier(attr.GetType()); + + if (!string.IsNullOrEmpty(attr.Value)) + qualifier.SetAttribute(AutowireCandidateQualifier.VALUE_KEY, attr.Value); + + ParseQualifierProperties(attr, qualifier); + + AddQualifier(qualifier); + } + } + + private void ParseQualifierProperties(QualifierAttribute attr, AutowireCandidateQualifier qualifier) + { + foreach (var property in attr.GetType().GetProperties()) + { + if (!property.Name.Equals("TypeId") && !property.Name.Equals("Value")) + { + object value = property.GetValue(attr, null); + if (value != null) + { + var attribute = new ObjectMetadataAttribute(property.Name, value); + qualifier.AddMetadataAttribute(attribute); + } + } + } + } + + /// + /// Provides the name of the object scanned + /// + /// return the provided attribute name of the full object type name + public string ComponentName + { + get + { + return _componentName; + } + } } diff --git a/src/Spring/Spring.Core/Context/Attributes/ScopeAttribute.cs b/src/Spring/Spring.Core/Context/Attributes/ScopeAttribute.cs index f3dc87d1..0c414a04 100644 --- a/src/Spring/Spring.Core/Context/Attributes/ScopeAttribute.cs +++ b/src/Spring/Spring.Core/Context/Attributes/ScopeAttribute.cs @@ -20,46 +20,44 @@ using Spring.Objects.Factory.Support; -namespace Spring.Context.Attributes +namespace Spring.Context.Attributes; + +/// +/// When used as a type-level attribute, indicates the name of a scope to use +/// for instances of the attributed type. +/// +/// When used as a method-level attribute in conjunction with the +/// attribute, indicates the name of a scope to use for +/// the instance returned from the method. +/// +/// In this context, scope means the lifecycle of an instance, such as +/// singleton, prototype, and so forth. +/// +/// +[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] +public class ScopeAttribute : Attribute { + private ObjectScope _scope = ObjectScope.Singleton; + /// - /// When used as a type-level attribute, indicates the name of a scope to use - /// for instances of the attributed type. - /// - /// When used as a method-level attribute in conjunction with the - /// attribute, indicates the name of a scope to use for - /// the instance returned from the method. - /// - /// In this context, scope means the lifecycle of an instance, such as - /// singleton, prototype, and so forth. - /// + /// Initializes a new instance of the Scope class. /// - [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] - public class ScopeAttribute : Attribute + /// + public ScopeAttribute(ObjectScope scope) { - private ObjectScope _scope = ObjectScope.Singleton; + _scope = scope; + } - /// - /// Initializes a new instance of the Scope class. - /// - /// - public ScopeAttribute(ObjectScope scope) + /// + /// Specifies the scope to use for the annotated object. + /// + /// The scope. + public ObjectScope ObjectScope + { + get { return _scope; } + set { - _scope = scope; + _scope = value; } - - /// - /// Specifies the scope to use for the annotated object. - /// - /// The scope. - public ObjectScope ObjectScope - { - get { return _scope; } - set - { - _scope = value; - } - } - } } diff --git a/src/Spring/Spring.Core/Context/Attributes/TypeFilters/AbstractLoadTypeFilter.cs b/src/Spring/Spring.Core/Context/Attributes/TypeFilters/AbstractLoadTypeFilter.cs index b5088774..93a81419 100644 --- a/src/Spring/Spring.Core/Context/Attributes/TypeFilters/AbstractLoadTypeFilter.cs +++ b/src/Spring/Spring.Core/Context/Attributes/TypeFilters/AbstractLoadTypeFilter.cs @@ -21,47 +21,40 @@ using Microsoft.Extensions.Logging; using Spring.Core.TypeResolution; -namespace Spring.Context.Attributes.TypeFilters +namespace Spring.Context.Attributes.TypeFilters; + +/// +/// Abstract Type Filter that provides methods to load a required type from assembly. +/// +public abstract class AbstractLoadTypeFilter : ITypeFilter { + private static readonly ILogger Logger = LogManager.GetLogger(); + /// - /// Abstract Type Filter that provides methods to load a required type from assembly. + /// Required Type to compare against provided Type /// - public abstract class AbstractLoadTypeFilter : ITypeFilter + protected Type RequiredType; + + /// + /// Determine a match based on the given type object. + /// + /// + /// true if there is a match; false is there is no match + public abstract bool Match(Type type); + + /// + /// Is loading a Type from a string passed to method in the form [Type.FullName], [Assembly.Name] + /// + protected void GetRequiredType(string typeToLoad) { - private static readonly ILogger Logger = LogManager.GetLogger(); - - - /// - /// Required Type to compare against provided Type - /// - protected Type RequiredType; - - - /// - /// Determine a match based on the given type object. - /// - /// - /// true if there is a match; false is there is no match - public abstract bool Match(Type type); - - - /// - /// Is loading a Type from a string passed to method in the form [Type.FullName], [Assembly.Name] - /// - protected void GetRequiredType(string typeToLoad) + try { - try - { - RequiredType = !string.IsNullOrEmpty(typeToLoad) ? - TypeResolutionUtils.ResolveType(typeToLoad) : - null; - } - catch (Exception) - { - RequiredType = null; - Logger.LogError("Can't load type defined in expression:" + typeToLoad); - } + RequiredType = !string.IsNullOrEmpty(typeToLoad) ? TypeResolutionUtils.ResolveType(typeToLoad) : null; + } + catch (Exception) + { + RequiredType = null; + Logger.LogError("Can't load type defined in expression:" + typeToLoad); } - } -} +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Context/Attributes/TypeFilters/AssignableTypeFilter.cs b/src/Spring/Spring.Core/Context/Attributes/TypeFilters/AssignableTypeFilter.cs index 4c3e5d46..228c4597 100644 --- a/src/Spring/Spring.Core/Context/Attributes/TypeFilters/AssignableTypeFilter.cs +++ b/src/Spring/Spring.Core/Context/Attributes/TypeFilters/AssignableTypeFilter.cs @@ -18,62 +18,59 @@ #endregion -namespace Spring.Context.Attributes.TypeFilters +namespace Spring.Context.Attributes.TypeFilters; + +/// +/// A simple filter which matches classes that are assignable to a given type. +/// +public class AssignableTypeFilter : AbstractLoadTypeFilter { + /// + /// Create a Type Filter with required type + /// + /// type name including assembly name + public AssignableTypeFilter(string expression) + { + GetRequiredType(expression); + } /// - /// A simple filter which matches classes that are assignable to a given type. + /// Determine a match based on the given type object. /// - public class AssignableTypeFilter : AbstractLoadTypeFilter + /// Type to compare against + /// true if there is a match; false is there is no match + public override bool Match(Type type) { - - /// - /// Create a Type Filter with required type - /// - /// type name including assembly name - public AssignableTypeFilter(string expression) + if (RequiredType == null) { - GetRequiredType(expression); - } - - /// - /// Determine a match based on the given type object. - /// - /// Type to compare against - /// true if there is a match; false is there is no match - public override bool Match(Type type) - { - if (RequiredType == null) - { - return false; - } - - if (RequiredType == type.BaseType) - { - return true; - } - - foreach (var i in type.GetInterfaces()) - { - if (i == RequiredType) - { - return true; - } - } - return false; } - /// - /// Returns a string that represents the current object. - /// - /// - /// A string that represents the current object. - /// - /// 2 - public override string ToString() + if (RequiredType == type.BaseType) { - return string.Format("Required Type: {0}", RequiredType != null ? RequiredType.FullName : ""); + return true; } + + foreach (var i in type.GetInterfaces()) + { + if (i == RequiredType) + { + return true; + } + } + + return false; + } + + /// + /// Returns a string that represents the current object. + /// + /// + /// A string that represents the current object. + /// + /// 2 + public override string ToString() + { + return string.Format("Required Type: {0}", RequiredType != null ? RequiredType.FullName : ""); } } diff --git a/src/Spring/Spring.Core/Context/Attributes/TypeFilters/AttributeTypeFilter.cs b/src/Spring/Spring.Core/Context/Attributes/TypeFilters/AttributeTypeFilter.cs index 21cfd518..56430e4e 100644 --- a/src/Spring/Spring.Core/Context/Attributes/TypeFilters/AttributeTypeFilter.cs +++ b/src/Spring/Spring.Core/Context/Attributes/TypeFilters/AttributeTypeFilter.cs @@ -18,49 +18,45 @@ #endregion -namespace Spring.Context.Attributes.TypeFilters +namespace Spring.Context.Attributes.TypeFilters; + +/// +/// A simple filter which matches classes with a given attribute, +/// checking inherited annotations as well. +/// +public class AttributeTypeFilter : AbstractLoadTypeFilter { + /// + /// Creates a Type Filter with required type attribute + /// + /// + public AttributeTypeFilter(string expression) + { + GetRequiredType(expression); + } /// - /// A simple filter which matches classes with a given attribute, - /// checking inherited annotations as well. + /// Determine a match based on the given type object. /// - public class AttributeTypeFilter : AbstractLoadTypeFilter + /// Type to compare against + /// true if there is a match; false is there is no match + public override bool Match(Type type) { + if (RequiredType == null) + return false; - /// - /// Creates a Type Filter with required type attribute - /// - /// - public AttributeTypeFilter(string expression) - { - GetRequiredType(expression); - } - - /// - /// Determine a match based on the given type object. - /// - /// Type to compare against - /// true if there is a match; false is there is no match - public override bool Match(Type type) - { - if (RequiredType == null) - return false; - - return (Attribute.GetCustomAttribute(type, RequiredType) != null); - } - - /// - /// Returns a string that represents the current object. - /// - /// - /// A string that represents the current object. - /// - /// 2 - public override string ToString() - { - return string.Format("Required Type: {0}", RequiredType != null ? RequiredType.FullName : ""); - } + return (Attribute.GetCustomAttribute(type, RequiredType) != null); + } + /// + /// Returns a string that represents the current object. + /// + /// + /// A string that represents the current object. + /// + /// 2 + public override string ToString() + { + return string.Format("Required Type: {0}", RequiredType != null ? RequiredType.FullName : ""); } } diff --git a/src/Spring/Spring.Core/Context/Attributes/TypeFilters/CustomTypeFactory.cs b/src/Spring/Spring.Core/Context/Attributes/TypeFilters/CustomTypeFactory.cs index 5d2ccf2f..6be453ce 100644 --- a/src/Spring/Spring.Core/Context/Attributes/TypeFilters/CustomTypeFactory.cs +++ b/src/Spring/Spring.Core/Context/Attributes/TypeFilters/CustomTypeFactory.cs @@ -23,68 +23,65 @@ using Spring.Core.TypeResolution; using Spring.Util; using Spring.Objects.Factory.Support; -namespace Spring.Context.Attributes.TypeFilters +namespace Spring.Context.Attributes.TypeFilters; + +/// +/// Creates a new instance of a given type string +/// +public static class CustomTypeFactory { + private static readonly ILogger Logger = LogManager.GetLogger(typeof(CustomTypeFactory).FullName); + /// - /// Creates a new instance of a given type string + /// Creates a new instance of given type filter type string /// - public static class CustomTypeFactory + /// Custom type filter to create + /// An instance of ITypeFilter or NULL if no instance can be created + public static ITypeFilter GetTypeFilter(string expression) { - private static readonly ILogger Logger = LogManager.GetLogger(typeof(CustomTypeFactory).FullName); + return GetCustomType(expression) as ITypeFilter; + } - /// - /// Creates a new instance of given type filter type string - /// - /// Custom type filter to create - /// An instance of ITypeFilter or NULL if no instance can be created - public static ITypeFilter GetTypeFilter(string expression) - { - return GetCustomType(expression) as ITypeFilter; - } - - - /// - /// Creates a new instance of given name generator type string - /// - /// Custom type name generator string to create - /// An instance of IObjectNameGenerator or NULL if no instance can be created - public static IObjectNameGenerator GetNameGenerator(string expression) - { - return GetCustomType(expression) as IObjectNameGenerator; - } - - private static object GetCustomType(string expression) - { - var customTypeFilterType = LoadType(expression); - if (customTypeFilterType == null) - return null; - - try - { - var instance = ObjectUtils.InstantiateType(customTypeFilterType); - return instance; - } - catch - { - Logger.LogError(string.Format("Can't instatiate {0}. Type needs to have a non arg constructor.", expression)); - } - - return null; - } - - - private static Type LoadType(string typeToLoad) - { - try - { - return TypeResolutionUtils.ResolveType(typeToLoad); - } - catch (Exception) - { - Logger.LogError("Can't load type defined in exoression:" + typeToLoad); - } + /// + /// Creates a new instance of given name generator type string + /// + /// Custom type name generator string to create + /// An instance of IObjectNameGenerator or NULL if no instance can be created + public static IObjectNameGenerator GetNameGenerator(string expression) + { + return GetCustomType(expression) as IObjectNameGenerator; + } + private static object GetCustomType(string expression) + { + var customTypeFilterType = LoadType(expression); + if (customTypeFilterType == null) return null; + + try + { + var instance = ObjectUtils.InstantiateType(customTypeFilterType); + return instance; } + catch + { + Logger.LogError(string.Format("Can't instatiate {0}. Type needs to have a non arg constructor.", expression)); + } + + return null; + } + + private static Type LoadType(string typeToLoad) + { + try + { + return TypeResolutionUtils.ResolveType(typeToLoad); + } + catch (Exception) + { + Logger.LogError("Can't load type defined in exoression:" + typeToLoad); + } + + return null; } } diff --git a/src/Spring/Spring.Core/Context/Attributes/TypeFilters/ITypeFilter.cs b/src/Spring/Spring.Core/Context/Attributes/TypeFilters/ITypeFilter.cs index eca8a730..ac7171b3 100644 --- a/src/Spring/Spring.Core/Context/Attributes/TypeFilters/ITypeFilter.cs +++ b/src/Spring/Spring.Core/Context/Attributes/TypeFilters/ITypeFilter.cs @@ -18,18 +18,17 @@ #endregion -namespace Spring.Context.Attributes.TypeFilters +namespace Spring.Context.Attributes.TypeFilters; + +/// +/// Represents the base interface for all component-scan type filters +/// +public interface ITypeFilter { /// - /// Represents the base interface for all component-scan type filters + /// Determine a match based on the given type object. /// - public interface ITypeFilter - { - /// - /// Determine a match based on the given type object. - /// - /// - /// true if there is a match; false is there is no match - bool Match(Type type); - } + /// + /// true if there is a match; false is there is no match + bool Match(Type type); } diff --git a/src/Spring/Spring.Core/Context/Attributes/TypeFilters/RegexPatternTypeFilter.cs b/src/Spring/Spring.Core/Context/Attributes/TypeFilters/RegexPatternTypeFilter.cs index 549da9b7..a037d443 100644 --- a/src/Spring/Spring.Core/Context/Attributes/TypeFilters/RegexPatternTypeFilter.cs +++ b/src/Spring/Spring.Core/Context/Attributes/TypeFilters/RegexPatternTypeFilter.cs @@ -20,45 +20,43 @@ using System.Text.RegularExpressions; -namespace Spring.Context.Attributes.TypeFilters +namespace Spring.Context.Attributes.TypeFilters; + +/// +/// A simple filter for matching a fully-qualified class name with a regex +/// +public class RegexPatternTypeFilter : ITypeFilter { + private string _pattern; + /// - /// A simple filter for matching a fully-qualified class name with a regex + /// Creates a type filter with provided pattern /// - public class RegexPatternTypeFilter : ITypeFilter + /// Regex pattern + public RegexPatternTypeFilter(string pattern) { - private string _pattern; - - - /// - /// Creates a type filter with provided pattern - /// - /// Regex pattern - public RegexPatternTypeFilter(string pattern) - { - _pattern = pattern; - } - - /// - /// Determine a match based on the given type object. - /// - /// Type to compare against - /// true if there is a match; false is there is no match - public bool Match(Type type) - { - return Regex.IsMatch(type.FullName, _pattern); - } - - /// - /// Returns a string that represents the current object. - /// - /// - /// A string that represents the current object. - /// - /// 2 - public override string ToString() - { - return string.Format("Pattern: {0}", _pattern); - } + _pattern = pattern; } -} + + /// + /// Determine a match based on the given type object. + /// + /// Type to compare against + /// true if there is a match; false is there is no match + public bool Match(Type type) + { + return Regex.IsMatch(type.FullName, _pattern); + } + + /// + /// Returns a string that represents the current object. + /// + /// + /// A string that represents the current object. + /// + /// 2 + public override string ToString() + { + return string.Format("Pattern: {0}", _pattern); + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Context/Config/AttributeConfigObjectDefinitionParser.cs b/src/Spring/Spring.Core/Context/Config/AttributeConfigObjectDefinitionParser.cs index d9e4714b..c4f2a7f2 100644 --- a/src/Spring/Spring.Core/Context/Config/AttributeConfigObjectDefinitionParser.cs +++ b/src/Spring/Spring.Core/Context/Config/AttributeConfigObjectDefinitionParser.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2010-2011 the original author or authors. + * Copyright � 2010-2011 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. @@ -25,36 +25,35 @@ using Spring.Objects.Factory.Support; using Spring.Objects.Factory.Xml; using Spring.Util; -namespace Spring.Context.Config +namespace Spring.Context.Config; + +/// +/// Object Defintion Parser for interpreting classes when primary configuration is peformed via XML. +/// +public class AttributeConfigObjectDefinitionParser : IObjectDefinitionParser { /// - /// Object Defintion Parser for interpreting classes when primary configuration is peformed via XML. + /// Parse the specified XmlElement and register the resulting + /// ObjectDefinitions with the IObjectDefinitionRegistry + /// embedded in the supplied /// - public class AttributeConfigObjectDefinitionParser : IObjectDefinitionParser + /// The element to be parsed. + /// The object encapsulating the current state of the parsing process. + /// Provides access to a IObjectDefinitionRegistry + /// The primary object definition. + /// + ///

+ /// This method is never invoked if the parser is namespace aware + /// and was called to process the root node. + ///

+ ///
+ public IObjectDefinition ParseElement(XmlElement element, ParserContext parserContext) { - /// - /// Parse the specified XmlElement and register the resulting - /// ObjectDefinitions with the IObjectDefinitionRegistry - /// embedded in the supplied - /// - /// The element to be parsed. - /// The object encapsulating the current state of the parsing process. - /// Provides access to a IObjectDefinitionRegistry - /// The primary object definition. - /// - ///

- /// This method is never invoked if the parser is namespace aware - /// and was called to process the root node. - ///

- ///
- public IObjectDefinition ParseElement(XmlElement element, ParserContext parserContext) - { - IObjectDefinitionRegistry registry = parserContext.ReaderContext.Registry; - AssertUtils.ArgumentNotNull(registry, "registry"); + IObjectDefinitionRegistry registry = parserContext.ReaderContext.Registry; + AssertUtils.ArgumentNotNull(registry, "registry"); - AttributeConfigUtils.RegisterAttributeConfigProcessors(registry); + AttributeConfigUtils.RegisterAttributeConfigProcessors(registry); - return null; - } + return null; } -} \ No newline at end of file +} diff --git a/src/Spring/Spring.Core/Context/Config/ComponentScanObjectDefinitionParser.cs b/src/Spring/Spring.Core/Context/Config/ComponentScanObjectDefinitionParser.cs index f733e373..4b99be58 100644 --- a/src/Spring/Spring.Core/Context/Config/ComponentScanObjectDefinitionParser.cs +++ b/src/Spring/Spring.Core/Context/Config/ComponentScanObjectDefinitionParser.cs @@ -27,146 +27,144 @@ using Spring.Objects.Factory.Config; using Spring.Objects.Factory.Support; using Spring.Objects.Factory.Xml; -namespace Spring.Context.Config +namespace Spring.Context.Config; + +/// +/// Parses ObjectDefinitions from classes identified by an . +/// +public class ComponentScanObjectDefinitionParser : IObjectDefinitionParser { + private static readonly ILogger Logger = LogManager.GetLogger(); + + private const string ATTRIBUTE_CONFIG_ATTRIBUTE = "attribute-config"; + + private const string NAME_GENERATOR_ATTRIBUTE = "name-generator"; + + private const string BASE_ASSEMBLIES_ATTRIBUTE = "base-assemblies"; + + private const string EXCLUDE_FILTER_ELEMENT = "exclude-filter"; + + private const string INCLUDE_FILTER_ELEMENT = "include-filter"; + /// - /// Parses ObjectDefinitions from classes identified by an . + /// Parse the specified XmlElement and register the resulting + /// ObjectDefinitions with the IObjectDefinitionRegistry + /// embedded in the supplied /// - public class ComponentScanObjectDefinitionParser : IObjectDefinitionParser + /// The element to be parsed. + /// The object encapsulating the current state of the parsing process. + /// Provides access to a IObjectDefinitionRegistry + /// The primary object definition. + /// + ///

+ /// This method is never invoked if the parser is namespace aware + /// and was called to process the root node. + ///

+ ///
+ public IObjectDefinition ParseElement(XmlElement element, ParserContext parserContext) { - private static readonly ILogger Logger = LogManager.GetLogger(); + AssemblyObjectDefinitionScanner scanner = ConfigureScanner(parserContext, element); + IObjectDefinitionRegistry registry = parserContext.Registry; - private const string ATTRIBUTE_CONFIG_ATTRIBUTE = "attribute-config"; + // Actually scan for objects definitions and register them. + scanner.ScanAndRegisterTypes(registry); + RegisterComponents(element, registry); - private const string NAME_GENERATOR_ATTRIBUTE = "name-generator"; + return null; + } - private const string BASE_ASSEMBLIES_ATTRIBUTE = "base-assemblies"; + /// + /// Configures the scanner. + /// + /// The parser context. + /// The element. + /// + protected virtual AssemblyObjectDefinitionScanner ConfigureScanner(ParserContext parserContext, XmlElement element) + { + var scanner = new AssemblyObjectDefinitionScanner(); - private const string EXCLUDE_FILTER_ELEMENT = "exclude-filter"; + ParseBaseAssembliesAttribute(scanner, element); + ParseNameGeneratorAttribute(scanner, element); + ParseTypeFilters(scanner, element); - private const string INCLUDE_FILTER_ELEMENT = "include-filter"; + scanner.Defaults = parserContext.ParserHelper.Defaults; + return scanner; + } - /// - /// Parse the specified XmlElement and register the resulting - /// ObjectDefinitions with the IObjectDefinitionRegistry - /// embedded in the supplied - /// - /// The element to be parsed. - /// The object encapsulating the current state of the parsing process. - /// Provides access to a IObjectDefinitionRegistry - /// The primary object definition. - /// - ///

- /// This method is never invoked if the parser is namespace aware - /// and was called to process the root node. - ///

- ///
- public IObjectDefinition ParseElement(XmlElement element, ParserContext parserContext) - { - AssemblyObjectDefinitionScanner scanner = ConfigureScanner(parserContext, element); - IObjectDefinitionRegistry registry = parserContext.Registry; - - // Actually scan for objects definitions and register them. - scanner.ScanAndRegisterTypes(registry); - RegisterComponents(element, registry); + private void ParseBaseAssembliesAttribute(AssemblyObjectDefinitionScanner scanner, XmlElement element) + { + var baseAssemblies = element.GetAttribute(BASE_ASSEMBLIES_ATTRIBUTE); - return null; - } + if (string.IsNullOrEmpty(baseAssemblies)) + return; - /// - /// Configures the scanner. - /// - /// The parser context. - /// The element. - /// - protected virtual AssemblyObjectDefinitionScanner ConfigureScanner(ParserContext parserContext, XmlElement element) - { - var scanner = new AssemblyObjectDefinitionScanner(); - - ParseBaseAssembliesAttribute(scanner, element); - ParseNameGeneratorAttribute(scanner, element); - ParseTypeFilters(scanner, element); - - scanner.Defaults = parserContext.ParserHelper.Defaults; - - return scanner; - } - - private void ParseBaseAssembliesAttribute(AssemblyObjectDefinitionScanner scanner, XmlElement element) + foreach (var baseAssembly in baseAssemblies.Split(',')) { - var baseAssemblies = element.GetAttribute(BASE_ASSEMBLIES_ATTRIBUTE); + if (Logger.IsEnabled(LogLevel.Debug)) + Logger.LogDebug("Start With Assembly Filter: " + baseAssembly); - if (string.IsNullOrEmpty(baseAssemblies)) - return; + scanner.WithAssemblyFilter(assy => assy.FullName.StartsWith(baseAssembly)); + } + } - foreach (var baseAssembly in baseAssemblies.Split(',')) + private void ParseNameGeneratorAttribute(AssemblyObjectDefinitionScanner scanner, XmlElement element) + { + var nameGeneratorString = element.GetAttribute(NAME_GENERATOR_ATTRIBUTE); + var nameGenerator = CustomTypeFactory.GetNameGenerator(nameGeneratorString); + if (nameGenerator != null) + { + Logger.LogDebug("Use NameTable Generator: {NameGenerator}", nameGeneratorString); + scanner.ObjectNameGenerator = nameGenerator; + } + } + + private void ParseTypeFilters(AssemblyObjectDefinitionScanner scanner, XmlElement element) + { + foreach (XmlNode node in element.ChildNodes) + { + if (node.Name.Contains(INCLUDE_FILTER_ELEMENT)) { - if (Logger.IsEnabled(LogLevel.Debug)) - Logger.LogDebug("Start With Assembly Filter: " + baseAssembly); - - scanner.WithAssemblyFilter(assy => assy.FullName.StartsWith(baseAssembly)); + var filter = CreateTypeFilter(node); + Logger.LogDebug("Include Filter: {Filter}", filter); + scanner.WithIncludeFilter(filter); } - } - - private void ParseNameGeneratorAttribute(AssemblyObjectDefinitionScanner scanner, XmlElement element) - { - var nameGeneratorString = element.GetAttribute(NAME_GENERATOR_ATTRIBUTE); - var nameGenerator = CustomTypeFactory.GetNameGenerator(nameGeneratorString); - if (nameGenerator != null) + else if (node.Name.Contains(EXCLUDE_FILTER_ELEMENT)) { - Logger.LogDebug("Use NameTable Generator: {NameGenerator}", nameGeneratorString); - scanner.ObjectNameGenerator = nameGenerator; - } - } - - private void ParseTypeFilters(AssemblyObjectDefinitionScanner scanner, XmlElement element) - { - foreach (XmlNode node in element.ChildNodes) - { - if (node.Name.Contains(INCLUDE_FILTER_ELEMENT)) - { - var filter = CreateTypeFilter(node); - Logger.LogDebug("Include Filter: {Filter}", filter); - scanner.WithIncludeFilter(filter); - } - else if (node.Name.Contains(EXCLUDE_FILTER_ELEMENT)) - { - var filter = CreateTypeFilter(node); - Logger.LogDebug("Exclude Filter: {Filter}", filter); - scanner.WithExcludeFilter(filter); - } - } - } - - private void RegisterComponents(XmlElement element, IObjectDefinitionRegistry registry) - { - bool attributeConfig = true; - var attr = element.GetAttribute(ATTRIBUTE_CONFIG_ATTRIBUTE); - if (attr != null) - bool.TryParse(attr, out attributeConfig); - if (attributeConfig) - AttributeConfigUtils.RegisterAttributeConfigProcessors(registry); - } - - private ITypeFilter CreateTypeFilter(XmlNode node) - { - var type = node.Attributes["type"].Value; - var expression = node.Attributes["expression"].Value; - - switch (type) - { - case "regex": - return new RegexPatternTypeFilter(expression); - case "attribute": - return new AttributeTypeFilter(expression); - case "assignable": - return new AssignableTypeFilter(expression); - case "custom": - return CustomTypeFactory.GetTypeFilter(expression); - default: - throw new InvalidEnumArgumentException(string.Format("Filter type {0} is not defined", type)); + var filter = CreateTypeFilter(node); + Logger.LogDebug("Exclude Filter: {Filter}", filter); + scanner.WithExcludeFilter(filter); } } } + + private void RegisterComponents(XmlElement element, IObjectDefinitionRegistry registry) + { + bool attributeConfig = true; + var attr = element.GetAttribute(ATTRIBUTE_CONFIG_ATTRIBUTE); + if (attr != null) + bool.TryParse(attr, out attributeConfig); + if (attributeConfig) + AttributeConfigUtils.RegisterAttributeConfigProcessors(registry); + } + + private ITypeFilter CreateTypeFilter(XmlNode node) + { + var type = node.Attributes["type"].Value; + var expression = node.Attributes["expression"].Value; + + switch (type) + { + case "regex": + return new RegexPatternTypeFilter(expression); + case "attribute": + return new AttributeTypeFilter(expression); + case "assignable": + return new AssignableTypeFilter(expression); + case "custom": + return CustomTypeFactory.GetTypeFilter(expression); + default: + throw new InvalidEnumArgumentException(string.Format("Filter type {0} is not defined", type)); + } + } } diff --git a/src/Spring/Spring.Core/Context/Config/ContextNamespaceParser.cs b/src/Spring/Spring.Core/Context/Config/ContextNamespaceParser.cs index 37fd3592..91938447 100644 --- a/src/Spring/Spring.Core/Context/Config/ContextNamespaceParser.cs +++ b/src/Spring/Spring.Core/Context/Config/ContextNamespaceParser.cs @@ -20,36 +20,35 @@ using Spring.Objects.Factory.Xml; -namespace Spring.Context.Config +namespace Spring.Context.Config; + +/// +/// NamespaceParser allowing for the configuration of +/// declarative transaction management using either XML or using attributes. +/// This namespace handler is the central piece of functionality in the +/// Spring transaction management facilities and offers two appraoches +/// to declaratively manage transactions. +/// One approach uses transaction semantics defined in XML using the +/// <tx:advice> elements, the other uses attributes +/// in combination with the <tx:annotation-driven> element. +/// Both approached are detailed in the Spring reference manual. +/// +[ + NamespaceParser( + Namespace = "http://www.springframework.net/context", + SchemaLocationAssemblyHint = typeof(ContextNamespaceParser), + SchemaLocation = "/Spring.Context.Config/spring-context-2.0.xsd" + ) +] +public class ContextNamespaceParser : NamespaceParserSupport { /// - /// NamespaceParser allowing for the configuration of - /// declarative transaction management using either XML or using attributes. - /// This namespace handler is the central piece of functionality in the - /// Spring transaction management facilities and offers two appraoches - /// to declaratively manage transactions. - /// One approach uses transaction semantics defined in XML using the - /// <tx:advice> elements, the other uses attributes - /// in combination with the <tx:annotation-driven> element. - /// Both approached are detailed in the Spring reference manual. + /// Register the for the 'advice' and + /// 'attribute-driven' tags. /// - [ - NamespaceParser( - Namespace = "http://www.springframework.net/context", - SchemaLocationAssemblyHint = typeof(ContextNamespaceParser), - SchemaLocation = "/Spring.Context.Config/spring-context-2.0.xsd" - ) - ] - public class ContextNamespaceParser : NamespaceParserSupport + public override void Init() { - /// - /// Register the for the 'advice' and - /// 'attribute-driven' tags. - /// - public override void Init() - { - RegisterObjectDefinitionParser("attribute-config", new AttributeConfigObjectDefinitionParser()); - RegisterObjectDefinitionParser("component-scan", new ComponentScanObjectDefinitionParser()); - } + RegisterObjectDefinitionParser("attribute-config", new AttributeConfigObjectDefinitionParser()); + RegisterObjectDefinitionParser("component-scan", new ComponentScanObjectDefinitionParser()); } } diff --git a/src/Spring/Spring.Core/Context/Config/spring-context-1.3.xsd b/src/Spring/Spring.Core/Context/Config/spring-context-1.3.xsd index a74947a8..9f622510 100644 --- a/src/Spring/Spring.Core/Context/Config/spring-context-1.3.xsd +++ b/src/Spring/Spring.Core/Context/Config/spring-context-1.3.xsd @@ -1,43 +1,43 @@ + xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:objects="http://www.springframework.net" + xmlns:tool="http://www.springframework.net/tool" + targetNamespace="http://www.springframework.net/context" + elementFormDefault="qualified" + attributeFormDefault="unqualified"> - - + + - - + - + - - - + + - - - + + + \ No newline at end of file diff --git a/src/Spring/Spring.Core/Context/Config/spring-context-2.0.xsd b/src/Spring/Spring.Core/Context/Config/spring-context-2.0.xsd index 1b9aab42..9009258e 100644 --- a/src/Spring/Spring.Core/Context/Config/spring-context-2.0.xsd +++ b/src/Spring/Spring.Core/Context/Config/spring-context-2.0.xsd @@ -1,28 +1,28 @@ + xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:objects="http://www.springframework.net" + xmlns:tool="http://www.springframework.net/tool" + targetNamespace="http://www.springframework.net/context" + elementFormDefault="qualified" + attributeFormDefault="unqualified"> - - + + - - + - + - - - - + + + tag for that purpose. ]]> - - - + + + - - - - + + + - - - - - - - - + + + + + + + - - - - - - - + + + + + + - - - - - - - - + + + + + + + - - - - - - - + + + + + + - - - - - - - + + + + + + - - - - - + + + + + - - - - - + + + + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - + + + + diff --git a/src/Spring/Spring.Core/Context/EventListenerAttribute.cs b/src/Spring/Spring.Core/Context/EventListenerAttribute.cs index 455d2274..4c91810f 100644 --- a/src/Spring/Spring.Core/Context/EventListenerAttribute.cs +++ b/src/Spring/Spring.Core/Context/EventListenerAttribute.cs @@ -22,20 +22,19 @@ #endregion -namespace Spring.Context +namespace Spring.Context; + +/// +/// Marks an interface as being an application event listener. +/// +/// Griffin Caprio +/// +[AttributeUsage(AttributeTargets.Interface)] +public sealed class EventListenerAttribute : Attribute { - /// - /// Marks an interface as being an application event listener. - /// - /// Griffin Caprio - /// - [AttributeUsage(AttributeTargets.Interface)] - public sealed class EventListenerAttribute : Attribute - { - /// - /// Creates a new instance of the - /// class. - /// - public EventListenerAttribute() {} - } -} + /// + /// Creates a new instance of the + /// class. + /// + public EventListenerAttribute() { } +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Context/Events/ConsoleListener.cs b/src/Spring/Spring.Core/Context/Events/ConsoleListener.cs index 96d6c431..59fd898f 100644 --- a/src/Spring/Spring.Core/Context/Events/ConsoleListener.cs +++ b/src/Spring/Spring.Core/Context/Events/ConsoleListener.cs @@ -18,42 +18,41 @@ #endregion -namespace Spring.Context.Events -{ - /// - /// Simple listener that logs application events to the console. - /// - /// - ///

- /// Intended for use during debugging only. - ///

- ///
- /// Rod Johnson - /// Griffin Caprio (.NET) - /// - public sealed class ConsoleListener : IApplicationEventListener - { - /// - /// Creates a new instance of the - /// class. - /// - public ConsoleListener() - { - } +namespace Spring.Context.Events; - /// - /// Handle an application event. - /// - /// - /// The source of the event. - /// - /// - /// The event that is to be handled. - /// - public void HandleApplicationEvent(object sender, ApplicationEventArgs e) - { - Console.WriteLine("Source : " + sender); - Console.WriteLine("Event fired : " + e.TimeStamp); - } - } +/// +/// Simple listener that logs application events to the console. +/// +/// +///

+/// Intended for use during debugging only. +///

+///
+/// Rod Johnson +/// Griffin Caprio (.NET) +/// +public sealed class ConsoleListener : IApplicationEventListener +{ + /// + /// Creates a new instance of the + /// class. + /// + public ConsoleListener() + { + } + + /// + /// Handle an application event. + /// + /// + /// The source of the event. + /// + /// + /// The event that is to be handled. + /// + public void HandleApplicationEvent(object sender, ApplicationEventArgs e) + { + Console.WriteLine("Source : " + sender); + Console.WriteLine("Event fired : " + e.TimeStamp); + } } diff --git a/src/Spring/Spring.Core/Context/Events/ContextEventArgs.cs b/src/Spring/Spring.Core/Context/Events/ContextEventArgs.cs index c4ed3e84..d4a9be17 100644 --- a/src/Spring/Spring.Core/Context/Events/ContextEventArgs.cs +++ b/src/Spring/Spring.Core/Context/Events/ContextEventArgs.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -20,88 +20,87 @@ using System.Globalization; -namespace Spring.Context.Events +namespace Spring.Context.Events; + +/// +/// Event object sent to listeners registered with an +/// to inform them of +/// context lifecycle events. +/// +/// Griffin Caprio (.NET) +/// +/// +/// +public class ContextEventArgs : ApplicationEventArgs { - /// - /// Event object sent to listeners registered with an - /// to inform them of - /// context lifecycle events. - /// - /// Griffin Caprio (.NET) - /// - /// - /// - public class ContextEventArgs : ApplicationEventArgs - { - /// - /// The various context event types. - /// - public enum ContextEvent - { - /// - /// The event type when the context is refreshed or created. - /// - Refreshed, + /// + /// The various context event types. + /// + public enum ContextEvent + { + /// + /// The event type when the context is refreshed or created. + /// + Refreshed, - /// - /// The event type when the context is closed. - /// - Closed - } ; + /// + /// The event type when the context is closed. + /// + Closed + }; - private readonly ContextEvent _contextEvent; - - /// - /// Creates a new instance of the ContextEventArgs class to represent the - /// supplied context event. - /// - /// The type of context event. - public ContextEventArgs(ContextEvent e) - { - _contextEvent = e; - } - - /// - /// The event type. - /// - public ContextEvent Event - { - get { return _contextEvent; } - } - - /// - /// Returns a string representation of this object. - /// - /// A string representation of this object. - public override string ToString() - { - return string.Format( - CultureInfo.InvariantCulture, - "{0} [{1}]", GetType().Name, Event); - } - } + private readonly ContextEvent _contextEvent; /// - /// Event object sent to listeners registered with an - /// to inform them of - /// context lifecycle event. + /// Creates a new instance of the ContextEventArgs class to represent the + /// supplied context event. /// - public class ContextRefreshedEventArgs : ContextEventArgs + /// The type of context event. + public ContextEventArgs(ContextEvent e) { - public ContextRefreshedEventArgs() : base(ContextEvent.Refreshed) - { - } + _contextEvent = e; } /// - /// Event object sent to listeners registered with an - /// to inform them of - /// context lifecycle event. + /// The event type. /// - public class ContextClosedEventArgs : ContextEventArgs + public ContextEvent Event { - public ContextClosedEventArgs() : base(ContextEvent.Closed) - { - } + get { return _contextEvent; } } -} \ No newline at end of file + + /// + /// Returns a string representation of this object. + /// + /// A string representation of this object. + public override string ToString() + { + return string.Format( + CultureInfo.InvariantCulture, + "{0} [{1}]", GetType().Name, Event); + } +} + +/// +/// Event object sent to listeners registered with an +/// to inform them of +/// context lifecycle event. +/// +public class ContextRefreshedEventArgs : ContextEventArgs +{ + public ContextRefreshedEventArgs() : base(ContextEvent.Refreshed) + { + } +} + +/// +/// Event object sent to listeners registered with an +/// to inform them of +/// context lifecycle event. +/// +public class ContextClosedEventArgs : ContextEventArgs +{ + public ContextClosedEventArgs() : base(ContextEvent.Closed) + { + } +} diff --git a/src/Spring/Spring.Core/Context/Extension/GenericApplicationContextExtensions.cs b/src/Spring/Spring.Core/Context/Extension/GenericApplicationContextExtensions.cs index 93324276..d7f5cc2c 100644 --- a/src/Spring/Spring.Core/Context/Extension/GenericApplicationContextExtensions.cs +++ b/src/Spring/Spring.Core/Context/Extension/GenericApplicationContextExtensions.cs @@ -23,104 +23,99 @@ using Spring.Context.Attributes; using Spring.Objects.Factory.Support; using Spring.Util; -namespace Spring.Context.Support +namespace Spring.Context.Support; + +/// +/// Extensions to enable scanning on any AbstractApplicationContext-derived type. +/// +public static class GenericApplicationContextExtensions { /// - /// Extensions to enable scanning on any AbstractApplicationContext-derived type. + /// Scans for types using the provided scanner. /// - public static class GenericApplicationContextExtensions + /// The context. + /// The scanner. + public static void Scan(this GenericApplicationContext context, AssemblyObjectDefinitionScanner scanner) { - /// - /// Scans for types using the provided scanner. - /// - /// The context. - /// The scanner. - public static void Scan(this GenericApplicationContext context, AssemblyObjectDefinitionScanner scanner) - { - var registry = context.ObjectFactory as IObjectDefinitionRegistry; - scanner.ScanAndRegisterTypes(registry); + var registry = context.ObjectFactory as IObjectDefinitionRegistry; + scanner.ScanAndRegisterTypes(registry); - AttributeConfigUtils.RegisterAttributeConfigProcessors(registry); - } + AttributeConfigUtils.RegisterAttributeConfigProcessors(registry); + } - /// - /// Scans for types that satisfy specified predicates located in the specified scan path. - /// - /// The context. - /// The assembly scan path. - /// The assembly predicate. - /// The type predicate. - public static void Scan(this GenericApplicationContext context, string assemblyScanPath, Func assemblyPredicate, - Func typePredicate) - { - Scan(context, assemblyScanPath, assemblyPredicate, typePredicate, new string[0]); - } + /// + /// Scans for types that satisfy specified predicates located in the specified scan path. + /// + /// The context. + /// The assembly scan path. + /// The assembly predicate. + /// The type predicate. + public static void Scan(this GenericApplicationContext context, string assemblyScanPath, Func assemblyPredicate, + Func typePredicate) + { + Scan(context, assemblyScanPath, assemblyPredicate, typePredicate, new string[0]); + } + /// + /// Scans the specified context. + /// + /// The context. + /// The assembly scan path. + /// The assembly predicate. + /// The type predicate. + /// The assemblies to scan. + public static void Scan(this GenericApplicationContext context, string assemblyScanPath, Func assemblyPredicate, Func typePredicate, params string[] assembliesToScan) + { + AssemblyObjectDefinitionScanner scanner = ArrayUtils.HasElements(assembliesToScan) + ? new AssemblyObjectDefinitionScanner(assembliesToScan) + : new AssemblyObjectDefinitionScanner(); - /// - /// Scans the specified context. - /// - /// The context. - /// The assembly scan path. - /// The assembly predicate. - /// The type predicate. - /// The assemblies to scan. - public static void Scan(this GenericApplicationContext context, string assemblyScanPath, Func assemblyPredicate, Func typePredicate, params string[] assembliesToScan) - { - AssemblyObjectDefinitionScanner scanner = ArrayUtils.HasElements(assembliesToScan) - ? new AssemblyObjectDefinitionScanner(assembliesToScan) - : new AssemblyObjectDefinitionScanner(); - - scanner.ScanStartFolderPath = assemblyScanPath; - - //configure the scanner per the provided constraints - scanner.WithAssemblyFilter(assemblyPredicate).WithIncludeFilter(typePredicate); + scanner.ScanStartFolderPath = assemblyScanPath; - //pass the scanner to primary Scan method to actually do the work - Scan(context, scanner); - } + //configure the scanner per the provided constraints + scanner.WithAssemblyFilter(assemblyPredicate).WithIncludeFilter(typePredicate); - /// - /// Scans for types that satisfy specified predicates. - /// - /// The context. - /// The assembly predicate. - /// The type predicate. - public static void Scan(this GenericApplicationContext context, Func assemblyPredicate, Func typePredicate) - { - Scan(context, null, assemblyPredicate, typePredicate); - } + //pass the scanner to primary Scan method to actually do the work + Scan(context, scanner); + } - /// - /// Scans for types using the default scanner. - /// - /// The context. - public static void ScanAllAssemblies(this GenericApplicationContext context) - { - Scan(context, new AssemblyObjectDefinitionScanner()); - } + /// + /// Scans for types that satisfy specified predicates. + /// + /// The context. + /// The assembly predicate. + /// The type predicate. + public static void Scan(this GenericApplicationContext context, Func assemblyPredicate, Func typePredicate) + { + Scan(context, null, assemblyPredicate, typePredicate); + } + /// + /// Scans for types using the default scanner. + /// + /// The context. + public static void ScanAllAssemblies(this GenericApplicationContext context) + { + Scan(context, new AssemblyObjectDefinitionScanner()); + } - /// - /// Scans the with assembly filter. - /// - /// The context. - /// The assembly predicate. - public static void ScanWithAssemblyFilter(this GenericApplicationContext context, Func assemblyPredicate) - { - Scan(context, null, assemblyPredicate, obj => true); - } - - /// - /// Scans the with type filter. - /// - /// The context. - /// The type predicate. - public static void ScanWithTypeFilter(this GenericApplicationContext context, Func typePredicate) - { - Scan(context, null, obj => true, typePredicate); - } - + /// + /// Scans the with assembly filter. + /// + /// The context. + /// The assembly predicate. + public static void ScanWithAssemblyFilter(this GenericApplicationContext context, Func assemblyPredicate) + { + Scan(context, null, assemblyPredicate, obj => true); + } + /// + /// Scans the with type filter. + /// + /// The context. + /// The type predicate. + public static void ScanWithTypeFilter(this GenericApplicationContext context, Func typePredicate) + { + Scan(context, null, obj => true, typePredicate); } } diff --git a/src/Spring/Spring.Core/Context/IApplicationContext.cs b/src/Spring/Spring.Core/Context/IApplicationContext.cs index 3e686fd6..4323311f 100644 --- a/src/Spring/Spring.Core/Context/IApplicationContext.cs +++ b/src/Spring/Spring.Core/Context/IApplicationContext.cs @@ -26,135 +26,133 @@ using Spring.Objects.Factory; #endregion -namespace Spring.Context +namespace Spring.Context; + +/// +/// The central interface to Spring.NET's IoC container. +/// +/// +///

+/// implementations +/// provide: +/// +/// +/// +/// Object factory functionality inherited from the +/// +/// and +/// interfaces. +/// +/// +/// +/// +/// The ability to resolve messages, supporting internationalization. +/// Inherited from the +/// interface. +/// +/// +/// +/// +/// The ability to load file resources in a generic fashion. +/// Inherited from the +/// interface. +/// +/// +/// +/// +/// Acts an an event registry for supporting loosely coupled eventing +/// between objecs. Inherited from the +/// interface. +/// +/// +/// +/// +/// The ability to raise events related to the context lifecycle. Inherited +/// from the +/// interface. +/// +/// +/// +/// +/// Inheritance from a parent context. Definitions in a descendant context +/// will always take priority. +/// +/// +/// +///

+///

+/// In addition to standard object factory lifecycle capabilities, +/// implementations need +/// to detect +/// , +/// , and +/// objects and supply +/// their attendant dependencies accordingly. +///

+///

+/// This interface is the central client interface in Spring.NET's IoC +/// container implementation. As such it does inherit a quite sizeable +/// number of interfaces; implementations are strongly encouraged to use +/// composition to satisfy each of the inherited interfaces (where +/// appropriate of course). +///

+///
+/// Rod Johnson +/// Juergen Hoeller +/// Mark Pollack (.NET) +/// +/// +/// +/// +public interface IApplicationContext + : IListableObjectFactory, IHierarchicalObjectFactory, IMessageSource, + IApplicationEventPublisher, IResourceLoader, IEventRegistry, IDisposable { - /// - /// The central interface to Spring.NET's IoC container. - /// - /// - ///

- /// implementations - /// provide: - /// - /// - /// - /// Object factory functionality inherited from the - /// - /// and - /// interfaces. - /// - /// - /// - /// - /// The ability to resolve messages, supporting internationalization. - /// Inherited from the - /// interface. - /// - /// - /// - /// - /// The ability to load file resources in a generic fashion. - /// Inherited from the - /// interface. - /// - /// - /// - /// - /// Acts an an event registry for supporting loosely coupled eventing - /// between objecs. Inherited from the - /// interface. - /// - /// - /// - /// - /// The ability to raise events related to the context lifecycle. Inherited - /// from the - /// interface. - /// - /// - /// - /// - /// Inheritance from a parent context. Definitions in a descendant context - /// will always take priority. - /// - /// - /// - ///

- ///

- /// In addition to standard object factory lifecycle capabilities, - /// implementations need - /// to detect - /// , - /// , and - /// objects and supply - /// their attendant dependencies accordingly. - ///

- ///

- /// This interface is the central client interface in Spring.NET's IoC - /// container implementation. As such it does inherit a quite sizeable - /// number of interfaces; implementations are strongly encouraged to use - /// composition to satisfy each of the inherited interfaces (where - /// appropriate of course). - ///

- ///
- /// Rod Johnson - /// Juergen Hoeller - /// Mark Pollack (.NET) - /// - /// - /// - /// - public interface IApplicationContext - : IListableObjectFactory, IHierarchicalObjectFactory, IMessageSource, - IApplicationEventPublisher, IResourceLoader, IEventRegistry, IDisposable - { - /// - /// Raised in response to an application context event. - /// - event ApplicationEventHandler ContextEvent; + /// + /// Raised in response to an application context event. + /// + event ApplicationEventHandler ContextEvent; - /// - /// Returns the date and time this context was loaded. - /// - /// - ///

- /// This is to be set immediately after an - /// has been - /// instantiated and its configuration has been loaded. Implementations - /// are permitted to update this value if the context is reset or - /// refreshed in some way. - ///

- ///
- /// - /// The representing when this context - /// was loaded. - /// - /// - DateTime StartupDate { get; } + /// + /// Returns the date and time this context was loaded. + /// + /// + ///

+ /// This is to be set immediately after an + /// has been + /// instantiated and its configuration has been loaded. Implementations + /// are permitted to update this value if the context is reset or + /// refreshed in some way. + ///

+ ///
+ /// + /// The representing when this context + /// was loaded. + /// + /// + DateTime StartupDate { get; } - /// - /// Gets the parent context, or if there is no - /// parent context. - /// - /// - ///

- /// If the parent context is , then this context - /// is the root of any context hierarchy. - ///

- ///
- /// - /// The parent context, or if there is no - /// parent. - /// - IApplicationContext ParentContext { get; } + /// + /// Gets the parent context, or if there is no + /// parent context. + /// + /// + ///

+ /// If the parent context is , then this context + /// is the root of any context hierarchy. + ///

+ ///
+ /// + /// The parent context, or if there is no + /// parent. + /// + IApplicationContext ParentContext { get; } - /// - /// Gets and sets a name for this context. - /// - /// - /// A name for this context. - /// - string Name { get; set; } - - } -} + /// + /// Gets and sets a name for this context. + /// + /// + /// A name for this context. + /// + string Name { get; set; } +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Context/IApplicationContextAware.cs b/src/Spring/Spring.Core/Context/IApplicationContextAware.cs index a0f46c77..401ab2e2 100644 --- a/src/Spring/Spring.Core/Context/IApplicationContextAware.cs +++ b/src/Spring/Spring.Core/Context/IApplicationContextAware.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -18,80 +18,79 @@ #endregion -namespace Spring.Context +namespace Spring.Context; + +/// +/// To be implemented by any object that wishes to be notified +/// of the that it runs in. +/// +/// +///

+/// Implementing this interface makes sense when an object requires access +/// to a set of collaborating objects. Note that configuration via object +/// references is preferable to implementing this interface just for object +/// lookup purposes. +///

+///

+/// This interface can also be implemented if an object needs access to +/// file resources, i.e. wants to call +/// , or access to +/// the . However, it is +/// preferable to implement the more specific +/// +/// interface to receive a reference to the +/// object in that scenario. +///

+///

+/// Note that dependencies can also +/// be exposed as object properties of the +/// type, populated via strings with +/// automatic type conversion performed by an object factory. This obviates +/// the need for implementing any callback interface just for the purpose +/// of accessing a specific file resource. +///

+///

+/// +/// is a convenience implementation of this interface for your +/// application objects. +///

+///

+/// For a list of all object lifecycle methods, see the overview for the +/// interface. +///

+///
+/// Rod Johnson +/// Mark Pollack (.NET) +/// +/// +/// +public interface IApplicationContextAware { /// - /// To be implemented by any object that wishes to be notified - /// of the that it runs in. + /// Sets the that this + /// object runs in. /// /// ///

- /// Implementing this interface makes sense when an object requires access - /// to a set of collaborating objects. Note that configuration via object - /// references is preferable to implementing this interface just for object - /// lookup purposes. + /// Normally this call will be used to initialize the object. ///

///

- /// This interface can also be implemented if an object needs access to - /// file resources, i.e. wants to call - /// , or access to - /// the . However, it is - /// preferable to implement the more specific - /// - /// interface to receive a reference to the - /// object in that scenario. - ///

- ///

- /// Note that dependencies can also - /// be exposed as object properties of the - /// type, populated via strings with - /// automatic type conversion performed by an object factory. This obviates - /// the need for implementing any callback interface just for the purpose - /// of accessing a specific file resource. - ///

- ///

- /// - /// is a convenience implementation of this interface for your - /// application objects. - ///

- ///

- /// For a list of all object lifecycle methods, see the overview for the - /// interface. + /// Invoked after population of normal object properties but before an + /// init callback such as + /// 's + /// + /// or a custom init-method. Invoked after the setting of any + /// 's + /// + /// property. ///

///
- /// Rod Johnson - /// Mark Pollack (.NET) - /// - /// - /// - public interface IApplicationContextAware - { - /// - /// Sets the that this - /// object runs in. - /// - /// - ///

- /// Normally this call will be used to initialize the object. - ///

- ///

- /// Invoked after population of normal object properties but before an - /// init callback such as - /// 's - /// - /// or a custom init-method. Invoked after the setting of any - /// 's - /// - /// property. - ///

- ///
- /// - /// In the case of application context initialization errors. - /// - /// - /// If thrown by any application context methods. - /// - /// - IApplicationContext ApplicationContext { set; } - } + /// + /// In the case of application context initialization errors. + /// + /// + /// If thrown by any application context methods. + /// + /// + IApplicationContext ApplicationContext { set; } } diff --git a/src/Spring/Spring.Core/Context/IApplicationEventListener.cs b/src/Spring/Spring.Core/Context/IApplicationEventListener.cs index 9f20ee3b..12a8953b 100644 --- a/src/Spring/Spring.Core/Context/IApplicationEventListener.cs +++ b/src/Spring/Spring.Core/Context/IApplicationEventListener.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -18,30 +18,29 @@ #endregion -namespace Spring.Context -{ - /// - /// The callback for application events. - /// - public delegate void ApplicationEventHandler(object sender, ApplicationEventArgs e); +namespace Spring.Context; - /// - /// A listener for application events. - /// - /// Rod Johnson - /// Griffin Caprio (.NET) - [EventListener] - public interface IApplicationEventListener - { - /// - /// Handle an application event. - /// - /// - /// The source of the event. - /// - /// - /// The event that is to be handled. - /// - void HandleApplicationEvent(object sender, ApplicationEventArgs e); - } -} \ No newline at end of file +/// +/// The callback for application events. +/// +public delegate void ApplicationEventHandler(object sender, ApplicationEventArgs e); + +/// +/// A listener for application events. +/// +/// Rod Johnson +/// Griffin Caprio (.NET) +[EventListener] +public interface IApplicationEventListener +{ + /// + /// Handle an application event. + /// + /// + /// The source of the event. + /// + /// + /// The event that is to be handled. + /// + void HandleApplicationEvent(object sender, ApplicationEventArgs e); +} diff --git a/src/Spring/Spring.Core/Context/IApplicationEventPublisher.cs b/src/Spring/Spring.Core/Context/IApplicationEventPublisher.cs index 8278b382..d004ad7a 100644 --- a/src/Spring/Spring.Core/Context/IApplicationEventPublisher.cs +++ b/src/Spring/Spring.Core/Context/IApplicationEventPublisher.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -18,30 +18,29 @@ #endregion -namespace Spring.Context { +namespace Spring.Context; - /// - /// Encapsulates event publication functionality. - /// - /// - ///

- /// Serves as a super-interface for the - /// interface. - ///

- ///
- /// Juergen Hoeller - /// Rick Evans (.NET) - public interface IApplicationEventPublisher - { - /// - /// Publishes an application context event. - /// - /// - /// The source of the event. May be . - /// - /// - /// The event that is to be raised. - /// - void PublishEvent(object sender, ApplicationEventArgs e); - } +/// +/// Encapsulates event publication functionality. +/// +/// +///

+/// Serves as a super-interface for the +/// interface. +///

+///
+/// Juergen Hoeller +/// Rick Evans (.NET) +public interface IApplicationEventPublisher +{ + /// + /// Publishes an application context event. + /// + /// + /// The source of the event. May be . + /// + /// + /// The event that is to be raised. + /// + void PublishEvent(object sender, ApplicationEventArgs e); } diff --git a/src/Spring/Spring.Core/Context/IConfigurableApplicationContext.cs b/src/Spring/Spring.Core/Context/IConfigurableApplicationContext.cs index 0f17cd60..239d595f 100644 --- a/src/Spring/Spring.Core/Context/IConfigurableApplicationContext.cs +++ b/src/Spring/Spring.Core/Context/IConfigurableApplicationContext.cs @@ -20,108 +20,107 @@ using Spring.Objects.Factory.Config; -namespace Spring.Context +namespace Spring.Context; + +/// +/// Provides the means to configure an application context in addition to +/// the methods exposed on the +/// interface. +/// +/// +///

+/// This interface is to be implemented by most (if not all) +/// implementations. +///

+///

+/// Configuration and lifecycle methods are encapsulated here to avoid +/// making them obvious to +/// client code. +///

+///

+/// Calling will close this +/// application context, releasing all resources and locks that the +/// implementation might hold. This includes disposing all cached +/// singleton objects. +///

+/// +/// does not invoke the +/// attendant on any parent +/// context. +/// +///
+/// Juergen Hoeller +/// Mark Pollack (.NET) +/// +/// +public interface IConfigurableApplicationContext : IApplicationContext, ILifecycle { /// - /// Provides the means to configure an application context in addition to - /// the methods exposed on the - /// interface. + /// Return the internal object factory of this application context. /// /// ///

- /// This interface is to be implemented by most (if not all) - /// implementations. - ///

- ///

- /// Configuration and lifecycle methods are encapsulated here to avoid - /// making them obvious to - /// client code. - ///

- ///

- /// Calling will close this - /// application context, releasing all resources and locks that the - /// implementation might hold. This includes disposing all cached - /// singleton objects. + /// Can be used to access specific functionality of the factory. ///

/// - /// does not invoke the - /// attendant on any parent - /// context. + /// This is just guaranteed to return an instance that is not + /// after the context has been refreshed + /// at least once. + /// + /// + /// Do not use this to post-process the object factory; singletons + /// will already have been instantiated. Use an + /// + /// to intercept the object factory setup process before objects even + /// get touched. /// ///
- /// Juergen Hoeller - /// Mark Pollack (.NET) - /// - /// - public interface IConfigurableApplicationContext : IApplicationContext, ILifecycle - { - /// - /// Return the internal object factory of this application context. - /// - /// - ///

- /// Can be used to access specific functionality of the factory. - ///

- /// - /// This is just guaranteed to return an instance that is not - /// after the context has been refreshed - /// at least once. - /// - /// - /// Do not use this to post-process the object factory; singletons - /// will already have been instantiated. Use an - /// - /// to intercept the object factory setup process before objects even - /// get touched. - /// - ///
- /// - IConfigurableListableObjectFactory ObjectFactory { get; } + /// + IConfigurableListableObjectFactory ObjectFactory { get; } - /// - /// Add an - /// - /// that will get applied to the internal object factory of this - /// application context on refresh, before any of the object - /// definitions are evaluated. - /// - /// - ///

- /// To be invoked during context configuration. - ///

- ///
- /// - /// The factory processor to register. - /// - /// - void AddObjectFactoryPostProcessor( - IObjectFactoryPostProcessor objectFactoryPostProcessor); + /// + /// Add an + /// + /// that will get applied to the internal object factory of this + /// application context on refresh, before any of the object + /// definitions are evaluated. + /// + /// + ///

+ /// To be invoked during context configuration. + ///

+ ///
+ /// + /// The factory processor to register. + /// + /// + void AddObjectFactoryPostProcessor( + IObjectFactoryPostProcessor objectFactoryPostProcessor); - /// - /// Load or refresh the persistent representation of the configuration, - /// which might an XML file, properties file, or relational database schema. - /// - /// - /// If the configuration cannot be loaded. - /// - /// - /// If the object factory could not be initialized. - /// - void Refresh(); + /// + /// Load or refresh the persistent representation of the configuration, + /// which might an XML file, properties file, or relational database schema. + /// + /// + /// If the configuration cannot be loaded. + /// + /// + /// If the object factory could not be initialized. + /// + void Refresh(); - /// - /// Sets the parent of this application context. - /// - /// - /// - /// The parent should not be changed: it should only be set - /// outside a constructor if it isn't available when an instance of - /// this class is created. - /// - /// - /// - /// The parent context. - /// - new IApplicationContext ParentContext { get; set; } - } + /// + /// Sets the parent of this application context. + /// + /// + /// + /// The parent should not be changed: it should only be set + /// outside a constructor if it isn't available when an instance of + /// this class is created. + /// + /// + /// + /// The parent context. + /// + new IApplicationContext ParentContext { get; set; } } diff --git a/src/Spring/Spring.Core/Context/IHierarchicalMessageSource.cs b/src/Spring/Spring.Core/Context/IHierarchicalMessageSource.cs index e76b9f7e..2a1e399d 100644 --- a/src/Spring/Spring.Core/Context/IHierarchicalMessageSource.cs +++ b/src/Spring/Spring.Core/Context/IHierarchicalMessageSource.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -18,28 +18,27 @@ #endregion -namespace Spring.Context +namespace Spring.Context; + +/// +/// Sub-interface of to be +/// implemented by objects that can resolve messages hierarchically. +/// +/// Rod Johnson +/// Juergen Hoeller +/// Mark Pollack (.NET) +/// +public interface IHierarchicalMessageSource : IMessageSource { - /// - /// Sub-interface of to be - /// implemented by objects that can resolve messages hierarchically. - /// - /// Rod Johnson - /// Juergen Hoeller - /// Mark Pollack (.NET) - /// - public interface IHierarchicalMessageSource : IMessageSource - { - /// - /// The parent message source used to try and resolve messages that - /// this object can't resolve. - /// - /// - ///

- /// If the value of this property is then no - /// further resolution is possible. - ///

- ///
- IMessageSource ParentMessageSource { get; set; } - } + /// + /// The parent message source used to try and resolve messages that + /// this object can't resolve. + /// + /// + ///

+ /// If the value of this property is then no + /// further resolution is possible. + ///

+ ///
+ IMessageSource ParentMessageSource { get; set; } } \ No newline at end of file diff --git a/src/Spring/Spring.Core/Context/ILifecycle.cs b/src/Spring/Spring.Core/Context/ILifecycle.cs index 132ecffc..5a1cfce3 100644 --- a/src/Spring/Spring.Core/Context/ILifecycle.cs +++ b/src/Spring/Spring.Core/Context/ILifecycle.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -18,56 +18,55 @@ #endregion -namespace Spring.Context +namespace Spring.Context; + +/// +/// Interface defining methods for start/stop lifecycle control. +/// The typical use case for this is to control asynchronous processing. +/// +/// +/// +/// Can be implemented by both components (typically a Spring object defined in +/// a spring and containers +/// (typically a spring . Containers will +/// propagate start/stop signals to all components that apply. +/// +/// +/// Juergen Hoeller +/// Mark Pollack (.NET) +public interface ILifecycle { /// - /// Interface defining methods for start/stop lifecycle control. - /// The typical use case for this is to control asynchronous processing. + /// Starts this component. + /// + /// Should not throw an exception if the component is already running. + /// In the case of a container, this will propagate the start signal + /// to all components that apply. + /// + void Start(); + + /// + /// Stops this component. /// /// - /// - /// Can be implemented by both components (typically a Spring object defined in - /// a spring and containers - /// (typically a spring . Containers will - /// propagate start/stop signals to all components that apply. - /// + /// Should not throw an exception if the component isn't started yet. + /// In the case of a container, this will propagate the stop signal + /// to all components that apply. /// - /// Juergen Hoeller - /// Mark Pollack (.NET) - public interface ILifecycle + void Stop(); + + /// + /// Gets a value indicating whether this component is currently running. + /// + /// + /// In the case of a container, this will return true + /// only if all components that apply are currently running. + /// + /// + /// true if this component is running; otherwise, false. + /// + bool IsRunning { - /// - /// Starts this component. - /// - /// Should not throw an exception if the component is already running. - /// In the case of a container, this will propagate the start signal - /// to all components that apply. - /// - void Start(); - - /// - /// Stops this component. - /// - /// - /// Should not throw an exception if the component isn't started yet. - /// In the case of a container, this will propagate the stop signal - /// to all components that apply. - /// - void Stop(); - - /// - /// Gets a value indicating whether this component is currently running. - /// - /// - /// In the case of a container, this will return true - /// only if all components that apply are currently running. - /// - /// - /// true if this component is running; otherwise, false. - /// - bool IsRunning - { - get; - } + get; } } diff --git a/src/Spring/Spring.Core/Context/IMessageSource.cs b/src/Spring/Spring.Core/Context/IMessageSource.cs index f9dc7b1b..9bbffc20 100644 --- a/src/Spring/Spring.Core/Context/IMessageSource.cs +++ b/src/Spring/Spring.Core/Context/IMessageSource.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -20,288 +20,289 @@ using System.Globalization; -namespace Spring.Context { +namespace Spring.Context; + +/// +/// Describes an object that can resolve messages. +/// +/// +///

+/// This enables the parameterization and internationalization of messages. +///

+///

+/// Spring.NET provides one out-of-the-box implementation for production +/// use: +///

    +///
  • .
  • +///
+///

+///
+/// Rod Johnson +/// Juergen Hoeller +/// Mark Pollack (.NET) +/// Aleksandar Seovic (.NET) +/// +public interface IMessageSource +{ /// - /// Describes an object that can resolve messages. + /// Resolve the message identified by the supplied + /// . /// /// - ///

- /// This enables the parameterization and internationalization of messages. + ///

+ /// If the lookup is not successful, implementations are permitted to + /// take one of two actions. + ///

+ /// + /// + /// Throw an exception. + /// + /// + /// + /// Return the supplied as is. + /// + /// + /// + ///
+ /// The name of the message to resolve. + /// + /// The resolved message if the lookup was successful (see above for + /// the return value in the case of an unsuccessful lookup). + /// + string GetMessage(string name); + + /// + /// Resolve the message identified by the supplied + /// . + /// + /// + ///

+ /// If the lookup is not successful, implementations are permitted to + /// take one of two actions. + ///

+ /// + /// + /// Throw an exception. + /// + /// + /// + /// Return the supplied as is. + /// + /// + /// + ///
+ /// The name of the message to resolve. + /// + /// The array of arguments that will be filled in for parameters within + /// the message, or if there are no parameters + /// within the message. Parameters within a message should be + /// referenced using the same syntax as the format string for the + /// method. + /// + /// + /// The resolved message if the lookup was successful (see above for + /// the return value in the case of an unsuccessful lookup). + /// + string GetMessage(string name, params object[] arguments); + + /// + /// Resolve the message identified by the supplied + /// . + /// + /// + /// Note that the fallback behavior based on CultureInfo seem to + /// have a bug that is fixed by installed .NET 1.1 Service Pack 1. + ///

+ /// If the lookup is not successful, implementations are permitted to + /// take one of two actions. + ///

+ /// + /// + /// Throw an exception. + /// + /// + /// + /// Return the supplied as is. + /// + /// + /// + ///
+ /// The name of the message to resolve. + /// + /// The that represents + /// the culture for which the resource is localized. + /// + /// + /// The resolved message if the lookup was successful (see above for + /// the return value in the case of an unsuccessful lookup). + /// + string GetMessage(string name, CultureInfo culture); + + /// + /// Resolve the message identified by the supplied + /// . + /// + /// + /// Note that the fallback behavior based on CultureInfo seem to + /// have a bug that is fixed by installed .NET 1.1 Service Pack 1. + ///

+ /// If the lookup is not successful, implementations are permitted to + /// take one of two actions. + ///

+ /// + /// + /// Throw an exception. + /// + /// + /// + /// Return the supplied as is. + /// + /// + /// + ///
+ /// The name of the message to resolve. + /// + /// The that represents + /// the culture for which the resource is localized. + /// + /// + /// The array of arguments that will be filled in for parameters within + /// the message, or if there are no parameters + /// within the message. Parameters within a message should be + /// referenced using the same syntax as the format string for the + /// method. + /// + /// + /// The resolved message if the lookup was successful (see above for + /// the return value in the case of an unsuccessful lookup). + /// + string GetMessage(string name, CultureInfo culture, params object[] arguments); + + /// + /// Resolve the message identified by the supplied + /// . + /// + /// + /// Note that the fallback behavior based on CultureInfo seem to + /// have a bug that is fixed by installed .NET 1.1 Service Pack 1. + ///

+ /// If the lookup is not successful, implementations are permitted to + /// take one of two actions. + ///

+ /// + /// + /// Throw an exception. + /// + /// + /// + /// Return the supplied as is. + /// + /// + /// + ///
+ /// The name of the message to resolve. + /// The default message if name is not found. + /// + /// The that represents + /// the culture for which the resource is localized. + /// + /// + /// The array of arguments that will be filled in for parameters within + /// the message, or if there are no parameters + /// within the message. Parameters within a message should be + /// referenced using the same syntax as the format string for the + /// method. + /// + /// + /// The resolved message if the lookup was successful (see above for + /// the return value in the case of an unsuccessful lookup). + /// + string GetMessage(string name, string defaultMessage, CultureInfo culture, params object[] arguments); + + /// + /// Resolve the message using all of the attributes contained within + /// the supplied + /// argument. + /// + /// + /// The value object storing those attributes that are required to + /// properly resolve a message. + /// + /// + /// The that represents + /// the culture for which the resource is localized. + /// + /// + /// The resolved message if the lookup was successful (see above for + /// the return value in the case of an unsuccessful lookup). + /// + /// + /// If the message could not be resolved. + /// + string GetMessage(IMessageSourceResolvable resolvable, CultureInfo culture); + + /// + /// Gets a localized resource object identified by the supplied + /// . + /// + /// + ///

+ /// This method must use the + /// + /// value to obtain a resource. ///

///

- /// Spring.NET provides one out-of-the-box implementation for production - /// use: - ///

    - ///
  • .
  • - ///
+ /// Examples of resources that may be resolved by this method include + /// (but are not limited to) objects such as icons and bitmaps. ///

///
- /// Rod Johnson - /// Juergen Hoeller - /// Mark Pollack (.NET) - /// Aleksandar Seovic (.NET) - /// - public interface IMessageSource { - /// - /// Resolve the message identified by the supplied - /// . - /// - /// - ///

- /// If the lookup is not successful, implementations are permitted to - /// take one of two actions. - ///

- /// - /// - /// Throw an exception. - /// - /// - /// - /// Return the supplied as is. - /// - /// - /// - ///
- /// The name of the message to resolve. - /// - /// The resolved message if the lookup was successful (see above for - /// the return value in the case of an unsuccessful lookup). - /// - string GetMessage(string name); + /// + /// The name of the resource object to resolve. + /// + /// + /// The resolved object, or if not found. + /// + object GetResourceObject(string name); - /// - /// Resolve the message identified by the supplied - /// . - /// - /// - ///

- /// If the lookup is not successful, implementations are permitted to - /// take one of two actions. - ///

- /// - /// - /// Throw an exception. - /// - /// - /// - /// Return the supplied as is. - /// - /// - /// - ///
- /// The name of the message to resolve. - /// - /// The array of arguments that will be filled in for parameters within - /// the message, or if there are no parameters - /// within the message. Parameters within a message should be - /// referenced using the same syntax as the format string for the - /// method. - /// - /// - /// The resolved message if the lookup was successful (see above for - /// the return value in the case of an unsuccessful lookup). - /// - string GetMessage(string name, params object[] arguments); + /// + /// Gets a localized resource object identified by the supplied + /// . + /// + /// + ///

+ /// Examples of resources that may be resolved by this method include + /// (but are not limited to) objects such as icons and bitmaps. + ///

+ ///
+ /// + /// The name of the resource object to resolve. + /// + /// + /// The with which the + /// resource is associated. + /// + /// + /// The resolved object, or if not found. + /// + object GetResourceObject(string name, CultureInfo culture); - /// - /// Resolve the message identified by the supplied - /// . - /// - /// - /// Note that the fallback behavior based on CultureInfo seem to - /// have a bug that is fixed by installed .NET 1.1 Service Pack 1. - ///

- /// If the lookup is not successful, implementations are permitted to - /// take one of two actions. - ///

- /// - /// - /// Throw an exception. - /// - /// - /// - /// Return the supplied as is. - /// - /// - /// - ///
- /// The name of the message to resolve. - /// - /// The that represents - /// the culture for which the resource is localized. - /// - /// - /// The resolved message if the lookup was successful (see above for - /// the return value in the case of an unsuccessful lookup). - /// - string GetMessage(string name, CultureInfo culture); - - /// - /// Resolve the message identified by the supplied - /// . - /// - /// - /// Note that the fallback behavior based on CultureInfo seem to - /// have a bug that is fixed by installed .NET 1.1 Service Pack 1. - ///

- /// If the lookup is not successful, implementations are permitted to - /// take one of two actions. - ///

- /// - /// - /// Throw an exception. - /// - /// - /// - /// Return the supplied as is. - /// - /// - /// - ///
- /// The name of the message to resolve. - /// - /// The that represents - /// the culture for which the resource is localized. - /// - /// - /// The array of arguments that will be filled in for parameters within - /// the message, or if there are no parameters - /// within the message. Parameters within a message should be - /// referenced using the same syntax as the format string for the - /// method. - /// - /// - /// The resolved message if the lookup was successful (see above for - /// the return value in the case of an unsuccessful lookup). - /// - string GetMessage(string name, CultureInfo culture, params object[] arguments); - - /// - /// Resolve the message identified by the supplied - /// . - /// - /// - /// Note that the fallback behavior based on CultureInfo seem to - /// have a bug that is fixed by installed .NET 1.1 Service Pack 1. - ///

- /// If the lookup is not successful, implementations are permitted to - /// take one of two actions. - ///

- /// - /// - /// Throw an exception. - /// - /// - /// - /// Return the supplied as is. - /// - /// - /// - ///
- /// The name of the message to resolve. - /// The default message if name is not found. - /// - /// The that represents - /// the culture for which the resource is localized. - /// - /// - /// The array of arguments that will be filled in for parameters within - /// the message, or if there are no parameters - /// within the message. Parameters within a message should be - /// referenced using the same syntax as the format string for the - /// method. - /// - /// - /// The resolved message if the lookup was successful (see above for - /// the return value in the case of an unsuccessful lookup). - /// - string GetMessage(string name, string defaultMessage, CultureInfo culture, params object[] arguments); - - /// - /// Resolve the message using all of the attributes contained within - /// the supplied - /// argument. - /// - /// - /// The value object storing those attributes that are required to - /// properly resolve a message. - /// - /// - /// The that represents - /// the culture for which the resource is localized. - /// - /// - /// The resolved message if the lookup was successful (see above for - /// the return value in the case of an unsuccessful lookup). - /// - /// - /// If the message could not be resolved. - /// - string GetMessage(IMessageSourceResolvable resolvable, CultureInfo culture); - - /// - /// Gets a localized resource object identified by the supplied - /// . - /// - /// - ///

- /// This method must use the - /// - /// value to obtain a resource. - ///

- ///

- /// Examples of resources that may be resolved by this method include - /// (but are not limited to) objects such as icons and bitmaps. - ///

- ///
- /// - /// The name of the resource object to resolve. - /// - /// - /// The resolved object, or if not found. - /// - object GetResourceObject(string name); - - /// - /// Gets a localized resource object identified by the supplied - /// . - /// - /// - ///

- /// Examples of resources that may be resolved by this method include - /// (but are not limited to) objects such as icons and bitmaps. - ///

- ///
- /// - /// The name of the resource object to resolve. - /// - /// - /// The with which the - /// resource is associated. - /// - /// - /// The resolved object, or if not found. - /// - object GetResourceObject(string name, CultureInfo culture); - - /// - /// Applies resources to object properties. - /// - /// - ///

- /// Resource key names are of the form objectName.propertyName. - ///

- ///
- /// - /// An object that contains the property values to be applied. - /// - /// - /// The base name of the object to use for key lookup. - /// - /// - /// The with which the - /// resource is associated. - /// - void ApplyResources(object value, string objectName, CultureInfo culture); - } -} \ No newline at end of file + /// + /// Applies resources to object properties. + /// + /// + ///

+ /// Resource key names are of the form objectName.propertyName. + ///

+ ///
+ /// + /// An object that contains the property values to be applied. + /// + /// + /// The base name of the object to use for key lookup. + /// + /// + /// The with which the + /// resource is associated. + /// + void ApplyResources(object value, string objectName, CultureInfo culture); +} diff --git a/src/Spring/Spring.Core/Context/IMessageSourceAware.cs b/src/Spring/Spring.Core/Context/IMessageSourceAware.cs index 130eca0d..7df7e1e6 100644 --- a/src/Spring/Spring.Core/Context/IMessageSourceAware.cs +++ b/src/Spring/Spring.Core/Context/IMessageSourceAware.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -18,61 +18,60 @@ #endregion -namespace Spring.Context { +namespace Spring.Context; - /// - /// To be implemented by any object that wishes to be notified - /// of the associated with it. - /// - /// - ///

- /// In the current implementation, the - /// will typically be the - /// associated that - /// spawned the implementing object. - ///

- ///

- /// The can usually also be - /// passed on as an object reference to arbitrary object properties or - /// constructor arguments, because a - /// is typically defined as an - /// object with the well known name "messageSource" in the - /// associated application context. - ///

- ///
- /// Juergen Hoeller - /// Rick Evans (.NET) - /// - public interface IMessageSourceAware +/// +/// To be implemented by any object that wishes to be notified +/// of the associated with it. +/// +/// +///

+/// In the current implementation, the +/// will typically be the +/// associated that +/// spawned the implementing object. +///

+///

+/// The can usually also be +/// passed on as an object reference to arbitrary object properties or +/// constructor arguments, because a +/// is typically defined as an +/// object with the well known name "messageSource" in the +/// associated application context. +///

+///
+/// Juergen Hoeller +/// Rick Evans (.NET) +/// +public interface IMessageSourceAware +{ + /// + /// Sets the associated + /// with this object. + /// + /// + ///

+ /// Invoked after population of normal object properties but + /// before an initializing callback such as the + /// + /// method of the + /// interface + /// or a custom init-method. + ///

+ ///

+ /// It is also invoked before the + /// + /// property of any + /// + /// implementation. + ///

+ ///
+ /// + /// The associated + /// with this object. + /// + IMessageSource MessageSource { - /// - /// Sets the associated - /// with this object. - /// - /// - ///

- /// Invoked after population of normal object properties but - /// before an initializing callback such as the - /// - /// method of the - /// interface - /// or a custom init-method. - ///

- ///

- /// It is also invoked before the - /// - /// property of any - /// - /// implementation. - ///

- ///
- /// - /// The associated - /// with this object. - /// - IMessageSource MessageSource - { - set; - } - } + set; + } } diff --git a/src/Spring/Spring.Core/Context/IMessageSourceResolvable.cs b/src/Spring/Spring.Core/Context/IMessageSourceResolvable.cs index a33e08b7..6e3ecc8d 100644 --- a/src/Spring/Spring.Core/Context/IMessageSourceResolvable.cs +++ b/src/Spring/Spring.Core/Context/IMessageSourceResolvable.cs @@ -20,54 +20,53 @@ using System.Globalization; -namespace Spring.Context +namespace Spring.Context; + +/// +/// Describes objects that are suitable for message resolution in a +/// . +/// +/// +///

+/// Spring.NET's own validation error classes implement this interface. +///

+///
+/// Juergen Hoeller +/// Mark Pollack (.NET) +/// +/// +public interface IMessageSourceResolvable { /// - /// Describes objects that are suitable for message resolution in a - /// . + /// Return the codes to be used to resolve this message, in the order + /// that they are to be tried. /// /// ///

- /// Spring.NET's own validation error classes implement this interface. + /// The last code will therefore be the default one. ///

///
- /// Juergen Hoeller - /// Mark Pollack (.NET) - /// - /// - public interface IMessageSourceResolvable - { - /// - /// Return the codes to be used to resolve this message, in the order - /// that they are to be tried. - /// - /// - ///

- /// The last code will therefore be the default one. - ///

- ///
- /// - /// A array of codes which are associated - /// with this message. - /// - IList GetCodes(); + /// + /// A array of codes which are associated + /// with this message. + /// + IList GetCodes(); - /// - /// Return the array of arguments to be used to resolve this message. - /// - /// - /// An array of objects to be used as parameters to replace - /// placeholders within the message text. - /// - object[] GetArguments(); + /// + /// Return the array of arguments to be used to resolve this message. + /// + /// + /// An array of objects to be used as parameters to replace + /// placeholders within the message text. + /// + object[] GetArguments(); - /// - /// Return the default message to be used to resolve this message. - /// - /// - /// The default message, or if there is no - /// default. - /// - string DefaultMessage { get; } - } -} + /// + /// Return the default message to be used to resolve this message. + /// + /// + /// The default message, or if there is no + /// default. + /// + string DefaultMessage { get; } +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Context/IResourceLoaderAware.cs b/src/Spring/Spring.Core/Context/IResourceLoaderAware.cs index 7851e0ee..31203af4 100644 --- a/src/Spring/Spring.Core/Context/IResourceLoaderAware.cs +++ b/src/Spring/Spring.Core/Context/IResourceLoaderAware.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -24,58 +24,57 @@ using Spring.Core.IO; #endregion -namespace Spring.Context +namespace Spring.Context; + +/// +/// Interface to be implemented by any object that wishes to be notified +/// of the (typically the +/// ) that it runs in. +/// +/// +///

+/// Note that dependencies can also +/// be exposed as object properties of type +/// , populated via strings with +/// automatic type conversion by the object factory. This obviates the +/// need for implementing any callback interface just for the purpose of +/// accessing a specific resource. +///

+///

+/// You typically need an +/// when your application object has to access a variety of file resources +/// whose names are calculated. A good strategy is to make the object use +/// a default resource loader but still implement the +/// interface to allow +/// for overriding when running in an +/// . +///

+///
+/// Juergen Hoeller +/// Mark Pollack (.NET) +/// +/// +/// +public interface IResourceLoaderAware { /// - /// Interface to be implemented by any object that wishes to be notified - /// of the (typically the - /// ) that it runs in. + /// Sets the + /// that this object runs in. /// /// ///

- /// Note that dependencies can also - /// be exposed as object properties of type - /// , populated via strings with - /// automatic type conversion by the object factory. This obviates the - /// need for implementing any callback interface just for the purpose of - /// accessing a specific resource. - ///

- ///

- /// You typically need an - /// when your application object has to access a variety of file resources - /// whose names are calculated. A good strategy is to make the object use - /// a default resource loader but still implement the - /// interface to allow - /// for overriding when running in an - /// . + /// Invoked after population of normal objects properties but + /// before an init callback such as + /// 's + /// + /// or a custom init-method. Invoked before setting + /// 's + /// + /// property. ///

///
- /// Juergen Hoeller - /// Mark Pollack (.NET) - /// - /// - /// - public interface IResourceLoaderAware + IResourceLoader ResourceLoader { - /// - /// Sets the - /// that this object runs in. - /// - /// - ///

- /// Invoked after population of normal objects properties but - /// before an init callback such as - /// 's - /// - /// or a custom init-method. Invoked before setting - /// 's - /// - /// property. - ///

- ///
- IResourceLoader ResourceLoader - { - set; - } + set; } } diff --git a/src/Spring/Spring.Core/Context/NoSuchMessageException.cs b/src/Spring/Spring.Core/Context/NoSuchMessageException.cs index 47a66f31..adefc0de 100644 --- a/src/Spring/Spring.Core/Context/NoSuchMessageException.cs +++ b/src/Spring/Spring.Core/Context/NoSuchMessageException.cs @@ -25,89 +25,88 @@ using System.Runtime.Serialization; #endregion -namespace Spring.Context +namespace Spring.Context; + +/// +/// Thrown when a message cannot be resolved. +/// +/// Rod Johnson +/// Mark Pollack (.NET) +/// +/// +[Serializable] +public class NoSuchMessageException : ApplicationException { - /// - /// Thrown when a message cannot be resolved. - /// - /// Rod Johnson - /// Mark Pollack (.NET) - /// - /// - [Serializable] - public class NoSuchMessageException : ApplicationException - { - /// - /// Creates a new instance of the - /// class. - /// - public NoSuchMessageException() - { - } + /// + /// Creates a new instance of the + /// class. + /// + public NoSuchMessageException() + { + } - /// - /// Creates a new instance of the - /// class with the - /// specified message. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception that is being wrapped. - /// - public NoSuchMessageException(string message, Exception rootCause) - : base(message, rootCause) - { - } + /// + /// Creates a new instance of the + /// class with the + /// specified message. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception that is being wrapped. + /// + public NoSuchMessageException(string message, Exception rootCause) + : base(message, rootCause) + { + } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The - /// that holds the serialized object data about the exception being - /// thrown. - /// - /// - /// The - /// that contains contextual information about the source or - /// destination. - /// - protected NoSuchMessageException( - SerializationInfo info, StreamingContext context) - : base(info, context) - { - } + /// + /// Creates a new instance of the + /// class. + /// + /// + /// The + /// that holds the serialized object data about the exception being + /// thrown. + /// + /// + /// The + /// that contains contextual information about the source or + /// destination. + /// + protected NoSuchMessageException( + SerializationInfo info, StreamingContext context) + : base(info, context) + { + } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The code that could not be resolved for given culture. - /// - /// - /// The that was used - /// to search for the code. - /// - public NoSuchMessageException(string code, CultureInfo culture) - : base(string.Format("No message found under code '{0}' for locale '{1}'.", - code, culture)) - { - } + /// + /// Creates a new instance of the + /// class. + /// + /// + /// The code that could not be resolved for given culture. + /// + /// + /// The that was used + /// to search for the code. + /// + public NoSuchMessageException(string code, CultureInfo culture) + : base(string.Format("No message found under code '{0}' for locale '{1}'.", + code, culture)) + { + } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The code that could not be resolved for the current UI culture. - /// - public NoSuchMessageException(string code) - : this(code, CultureInfo.CurrentUICulture) - { - } - } + /// + /// Creates a new instance of the + /// class. + /// + /// + /// The code that could not be resolved for the current UI culture. + /// + public NoSuchMessageException(string code) + : this(code, CultureInfo.CurrentUICulture) + { + } } diff --git a/src/Spring/Spring.Core/Context/Support/AbstractApplicationContext.cs b/src/Spring/Spring.Core/Context/Support/AbstractApplicationContext.cs index c4fe85a0..4c72f640 100644 --- a/src/Spring/Spring.Core/Context/Support/AbstractApplicationContext.cs +++ b/src/Spring/Spring.Core/Context/Support/AbstractApplicationContext.cs @@ -29,2359 +29,2364 @@ using Spring.Objects.Factory.Support; using Spring.Objects.Support; using Spring.Util; -namespace Spring.Context.Support +namespace Spring.Context.Support; + +/// +/// Partial implementation of the +/// interface. +/// +/// +///

+/// Does not mandate the type of storage used for configuration, but does +/// implement common functionality. Uses the Template Method design +/// pattern, requiring concrete subclasses to implement +/// methods. +///

+///

+/// In contrast to a plain vanilla +/// , an +/// is supposed +/// to detect special objects defined in its object factory: therefore, +/// this class automatically registers +/// s, +/// s +/// and s that are +/// defined as objects in the context. +///

+///

+/// An may be also supplied as +/// an object in the context, with the special, well-known-name of +/// "messageSource". Else, message resolution is delegated to the +/// parent context. +///

+///
+/// Rod Johnson +/// Juergan Hoeller +/// Griffin Caprio (.NET) +/// +/// +public abstract class AbstractApplicationContext + : ConfigurableResourceLoader, IConfigurableApplicationContext, IObjectDefinitionRegistry { /// - /// Partial implementation of the - /// interface. + /// Name of the .Net config section that contains Spring.Net context definition. + /// + public const string ContextSectionName = "spring/context"; + + /// + /// Default name of the root context. + /// + public const string DefaultRootContextName = "spring.root"; + + private const long TicksAtEpoch = 621355968000000000; + + /// + /// The special, well-known-name of the default + /// in the context. /// /// ///

- /// Does not mandate the type of storage used for configuration, but does - /// implement common functionality. Uses the Template Method design - /// pattern, requiring concrete subclasses to implement - /// methods. - ///

- ///

- /// In contrast to a plain vanilla - /// , an - /// is supposed - /// to detect special objects defined in its object factory: therefore, - /// this class automatically registers - /// s, - /// s - /// and s that are - /// defined as objects in the context. - ///

- ///

- /// An may be also supplied as - /// an object in the context, with the special, well-known-name of - /// "messageSource". Else, message resolution is delegated to the - /// parent context. + /// If no can be found + /// in the context using this lookup key, then message resolution + /// will be delegated to the parent context (if any). ///

///
- /// Rod Johnson - /// Juergan Hoeller - /// Griffin Caprio (.NET) - /// - /// - public abstract class AbstractApplicationContext - : ConfigurableResourceLoader, IConfigurableApplicationContext, IObjectDefinitionRegistry + public static readonly string MessageSourceObjectName = "messageSource"; + + /// + /// The special, well-known-name of the default + /// in the context. + /// + /// + ///

+ /// If no can be found + /// in the context using this lookup key, then a default + /// will be used. + ///

+ ///
+ public static readonly string EventRegistryObjectName = "eventRegistry"; + + /// + /// The instance for this class. + /// + protected readonly ILogger log; + + /// + /// The instance we delegate + /// our implementation of said interface to. + /// + private IMessageSource _messageSource; + + /// + /// The instance we + /// delegate our implementation of said interface to. + /// + private IEventRegistry _eventRegistry; + + private IApplicationContext _parentApplicationContext; + private readonly List _objectFactoryPostProcessors; + private readonly List _defaultObjectPostProcessors; + private string _name; + private DateTime _startupDate; + private readonly bool _isCaseSensitive; + private EventRaiser _eventRaiser; + private bool _isInDispose; + private bool _isInStart; + private bool _isInStop; + + /// + /// Protects access to the internal object factory used by the ApplicationContext if attempted to be accessed when in improper state. + /// + /// The internal ObjectFactory used by the ApplicationContext + /// Cannot Access ApplicationContext in this state! + private IConfigurableListableObjectFactory SafeGetObjectFactory() { - /// - /// Name of the .Net config section that contains Spring.Net context definition. - /// - public const string ContextSectionName = "spring/context"; - - /// - /// Default name of the root context. - /// - public const string DefaultRootContextName = "spring.root"; - - private const long TicksAtEpoch = 621355968000000000; - - /// - /// The special, well-known-name of the default - /// in the context. - /// - /// - ///

- /// If no can be found - /// in the context using this lookup key, then message resolution - /// will be delegated to the parent context (if any). - ///

- ///
- public static readonly string MessageSourceObjectName = "messageSource"; - - /// - /// The special, well-known-name of the default - /// in the context. - /// - /// - ///

- /// If no can be found - /// in the context using this lookup key, then a default - /// will be used. - ///

- ///
- public static readonly string EventRegistryObjectName = "eventRegistry"; - - /// - /// The instance for this class. - /// - protected readonly ILogger log; - - /// - /// The instance we delegate - /// our implementation of said interface to. - /// - private IMessageSource _messageSource; - - /// - /// The instance we - /// delegate our implementation of said interface to. - /// - private IEventRegistry _eventRegistry; - - private IApplicationContext _parentApplicationContext; - private readonly List _objectFactoryPostProcessors; - private readonly List _defaultObjectPostProcessors; - private string _name; - private DateTime _startupDate; - private readonly bool _isCaseSensitive; - private EventRaiser _eventRaiser; - private bool _isInDispose; - private bool _isInStart; - private bool _isInStop; - - /// - /// Protects access to the internal object factory used by the ApplicationContext if attempted to be accessed when in improper state. - /// - /// The internal ObjectFactory used by the ApplicationContext - /// Cannot Access ApplicationContext in this state! - private IConfigurableListableObjectFactory SafeGetObjectFactory() + if (_isInStart || _isInStop || _isInDispose) { - if (_isInStart || _isInStop || _isInDispose) + ThrowInvalidApplicationContextState(); + } + + return ObjectFactory; + } + + private static void ThrowInvalidApplicationContextState() + { + throw new InvalidOperationException("Cannot Access ApplicationContext in this state!"); + } + + /// + /// Creates a new instance of the + /// with no parent context. + /// + /// + ///

+ /// This is an class, and as such exposes + /// no public constructors. + ///

+ ///
+ protected AbstractApplicationContext() + : this(null, true, null) + { + } + + /// + /// Creates a new instance of the + /// with no parent context. + /// + /// + ///

+ /// This is an class, and as such exposes + /// no public constructors. + ///

+ ///
+ /// Flag specifying whether to make this context case sensitive or not. + protected AbstractApplicationContext(bool caseSensitive) + : this(null, caseSensitive, null) + { + } + + /// + /// Creates a new instance of the + /// with the supplied parent context. + /// + /// + ///

+ /// This is an class, and as such exposes + /// no public constructors. + ///

+ ///
+ /// The application context name. + /// Flag specifying whether to make this context case sensitive or not. + /// The parent application context. + protected AbstractApplicationContext(string name, bool caseSensitive, + IApplicationContext parentApplicationContext) + { + log = LogManager.GetLogger(GetType()); + + _name = (StringUtils.IsNullOrEmpty(name)) ? DefaultRootContextName : name; + _isCaseSensitive = caseSensitive; + _parentApplicationContext = parentApplicationContext; + EventRaiser = CreateEventRaiser(); + _objectFactoryPostProcessors = new List(); + _defaultObjectPostProcessors = new List(); + AddDefaultObjectPostProcessor(new ObjectPostProcessorChecker()); + AddDefaultObjectPostProcessor(new ApplicationContextAwareProcessor(this)); + AddDefaultObjectPostProcessor(new SharedStateAwareProcessor(new ISharedStateFactory[] { new ByTypeSharedStateFactory() }, Int32.MaxValue)); + } + + /// + /// Adds the given to the list of standard + /// processors being added to the underlying + /// + /// + /// Each time is called on this context, the context ensures, that + /// all default s are registered with the underlying . + /// + /// The instance. + protected void AddDefaultObjectPostProcessor(IObjectPostProcessor defaultObjectPostProcessor) + { + _defaultObjectPostProcessors.Add(defaultObjectPostProcessor); + } + + /// + /// Closes this context and disposes of any resources (such as + /// singleton objects in the wrapped + /// ). + /// + public virtual void Dispose() + { + _isInDispose = true; + + GC.SuppressFinalize(this); + + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug(string.Format( + CultureInfo.InvariantCulture, + "Closing application context [{0}].", + Name)); + } + + // Closed event is raised before destroying objectfactory to enable registered IApplicationEventListeners + // to handle the event before they get disposed. + PublishEvent(this, new ContextClosedEventArgs()); + + ObjectFactory.Dispose(); + + _isInDispose = false; + } + + /// + /// Subclasses must implement this method to perform the actual + /// configuration loading. + /// + /// + ///

+ /// This method is invoked by + /// , + /// before any other initialization occurs. + ///

+ ///
+ /// + /// In the case of errors encountered while refreshing the object factory. + /// + protected abstract void RefreshObjectFactory(); + + /// + /// An object that can be used to synchronize access to the + /// + public object SyncRoot => this; + + /// + /// Set the to be used by this context. + /// + public EventRaiser EventRaiser + { + set + { + AssertUtils.ArgumentNotNull(value, "EventRaiser"); + _eventRaiser = value; + } + } + + /// + /// The timestamp when this context was first loaded. + /// + /// + /// The timestamp (milliseconds) when this context was first loaded. + /// + public long StartupDateMilliseconds => (StartupDate.Ticks - TicksAtEpoch) / 10000; + + /// + /// Gets a flag indicating whether context should be case sensitive. + /// + /// true if object lookups are case sensitive; otherwise, false. + public bool IsCaseSensitive => _isCaseSensitive; + + /// + /// The for this context. + /// + /// + /// If the context has not been initialized yet. + /// + public IMessageSource MessageSource + { + get + { + if (_messageSource == null) { - ThrowInvalidApplicationContextState(); + throw new InvalidOperationException( + "MessageSource not initialized - call 'Refresh()' " + + "before accessing messages via the context: " + this); } - return ObjectFactory; + return _messageSource; } + } - private static void ThrowInvalidApplicationContextState() + /// + /// The for this context. + /// + /// + /// If the context has not been initialized yet. + /// + public IEventRegistry EventRegistry + { + get { - throw new InvalidOperationException("Cannot Access ApplicationContext in this state!"); - } - - /// - /// Creates a new instance of the - /// with no parent context. - /// - /// - ///

- /// This is an class, and as such exposes - /// no public constructors. - ///

- ///
- protected AbstractApplicationContext() - : this(null, true, null) - { - } - - /// - /// Creates a new instance of the - /// with no parent context. - /// - /// - ///

- /// This is an class, and as such exposes - /// no public constructors. - ///

- ///
- /// Flag specifying whether to make this context case sensitive or not. - protected AbstractApplicationContext(bool caseSensitive) - : this(null, caseSensitive, null) - { - } - - /// - /// Creates a new instance of the - /// with the supplied parent context. - /// - /// - ///

- /// This is an class, and as such exposes - /// no public constructors. - ///

- ///
- /// The application context name. - /// Flag specifying whether to make this context case sensitive or not. - /// The parent application context. - protected AbstractApplicationContext(string name, bool caseSensitive, - IApplicationContext parentApplicationContext) - { - log = LogManager.GetLogger(GetType()); - - _name = (StringUtils.IsNullOrEmpty(name)) ? DefaultRootContextName : name; - _isCaseSensitive = caseSensitive; - _parentApplicationContext = parentApplicationContext; - EventRaiser = CreateEventRaiser(); - _objectFactoryPostProcessors = new List(); - _defaultObjectPostProcessors = new List(); - AddDefaultObjectPostProcessor(new ObjectPostProcessorChecker()); - AddDefaultObjectPostProcessor(new ApplicationContextAwareProcessor(this)); - AddDefaultObjectPostProcessor(new SharedStateAwareProcessor(new ISharedStateFactory[] { new ByTypeSharedStateFactory() }, Int32.MaxValue)); - } - - /// - /// Adds the given to the list of standard - /// processors being added to the underlying - /// - /// - /// Each time is called on this context, the context ensures, that - /// all default s are registered with the underlying . - /// - /// The instance. - protected void AddDefaultObjectPostProcessor(IObjectPostProcessor defaultObjectPostProcessor) - { - _defaultObjectPostProcessors.Add(defaultObjectPostProcessor); - } - - /// - /// Closes this context and disposes of any resources (such as - /// singleton objects in the wrapped - /// ). - /// - public virtual void Dispose() - { - _isInDispose = true; - - GC.SuppressFinalize(this); - - if (log.IsEnabled(LogLevel.Debug)) + if (_eventRegistry == null) { - log.LogDebug(string.Format( - CultureInfo.InvariantCulture, - "Closing application context [{0}].", - Name)); + throw new InvalidOperationException( + "EventRegistry not initialized - call 'Refresh()' " + + "before accessing the event registry via the context: " + this); } - // Closed event is raised before destroying objectfactory to enable registered IApplicationEventListeners - // to handle the event before they get disposed. - PublishEvent(this, new ContextClosedEventArgs()); + return _eventRegistry; + } + } - ObjectFactory.Dispose(); - - _isInDispose = false; + /// + /// Returns the internal object factory of the parent context if it implements + /// ; else, + /// returns the parent context itself. + /// + /// + /// The parent context's object factory, or the parent itself. + /// + protected IObjectFactory GetInternalParentObjectFactory() + { + if (_parentApplicationContext is IConfigurableApplicationContext configContext) + { + return configContext.ObjectFactory; } - /// - /// Subclasses must implement this method to perform the actual - /// configuration loading. - /// - /// - ///

- /// This method is invoked by - /// , - /// before any other initialization occurs. - ///

- ///
- /// - /// In the case of errors encountered while refreshing the object factory. - /// - protected abstract void RefreshObjectFactory(); + return _parentApplicationContext; + } - /// - /// An object that can be used to synchronize access to the - /// - public object SyncRoot => this; + /// + /// Raises an application context event. + /// + /// + /// Any arguments to the event. May be . + /// + protected virtual void OnContextEvent(ApplicationEventArgs e) + { + OnContextEvent(this, e); + } - /// - /// Set the to be used by this context. - /// - public EventRaiser EventRaiser + /// + /// Raises an application context event. + /// + /// + /// The source of the event. + /// + /// + /// Any arguments to the event. May be . + /// + protected virtual void OnContextEvent(object source, ApplicationEventArgs e) + { + IEventExceptionsCollector exceptions = _eventRaiser.Raise(ContextEvent, source, e); + if (exceptions.HasExceptions) { - set - { - AssertUtils.ArgumentNotNull(value, "EventRaiser"); - _eventRaiser = value; - } + Delegate target = ContextEvent.GetInvocationList()[0]; + Exception exception = exceptions[target]; + throw new ApplicationContextException(string.Format("An unhandled exception occured during processing application event {0} in handler {1}", e.GetType(), target.Method), exception); } + } - /// - /// The timestamp when this context was first loaded. - /// - /// - /// The timestamp (milliseconds) when this context was first loaded. - /// - public long StartupDateMilliseconds => (StartupDate.Ticks - TicksAtEpoch) / 10000; + /// + /// Create the strategy to be used + /// + protected virtual EventRaiser CreateEventRaiser() + { + return new DefensiveEventRaiser(); + } - /// - /// Gets a flag indicating whether context should be case sensitive. - /// - /// true if object lookups are case sensitive; otherwise, false. - public bool IsCaseSensitive => _isCaseSensitive; + /// + /// Modify the application context's internal object factory after its standard + /// initialization. + /// + /// + ///

+ /// All object definitions will have been loaded, but no objects + /// will have been instantiated yet. This allows for the registration + /// of special + /// s + /// in certain + /// implementations. + ///

+ ///
+ /// + /// The object factory used by the application context. + /// + /// + /// In the case of errors. + /// . + protected virtual void PostProcessObjectFactory( + IConfigurableListableObjectFactory objectFactory) + { + } - /// - /// The for this context. - /// - /// - /// If the context has not been initialized yet. - /// - public IMessageSource MessageSource + /// + /// Template method which can be overridden to add context-specific + /// work before the underlying object factory gets refreshed. + /// + protected virtual void OnPreRefresh() + { + } + + /// + /// Template method which can be overridden to add context-specific + /// refresh work. + /// + /// + ///

+ /// Called on initialization of special objects, before instantiation + /// of singletons. + ///

+ ///
+ protected virtual void OnRefresh() + { + } + + /// + /// Template method which can be overridden to add context-specific + /// work after the context was refreshed but before the + /// event gets raised. + /// + protected virtual void OnPostRefresh() + { + PublishEvent(this, new ContextRefreshedEventArgs()); + } + + /// + /// Instantiate and invoke all registered + /// + /// objects, respecting any explicit ordering. + /// + /// + /// + /// Must be called before singleton instantiation. + /// + /// + /// In the case of errors. + private void InvokeObjectFactoryPostProcessors(IConfigurableListableObjectFactory objectFactory) + { + // Invoke BeanDefinitionRegistryPostProcessors first, if any. + var processedObjects = new HashSet(); + + if (objectFactory is IObjectDefinitionRegistry registry) { - get + List regularPostProcessors = null; + List registryPostProcessors = null; + + for (var i = 0; i < _objectFactoryPostProcessors.Count; i++) { - if (_messageSource == null) + IObjectFactoryPostProcessor factoryProcessor = _objectFactoryPostProcessors[i]; + if (factoryProcessor is IObjectDefinitionRegistryPostProcessor registryPostProcessor) { - throw new InvalidOperationException( - "MessageSource not initialized - call 'Refresh()' " + - "before accessing messages via the context: " + this); + registryPostProcessor.PostProcessObjectDefinitionRegistry(registry); + registryPostProcessors = registryPostProcessors ?? new List(); + registryPostProcessors.Add(registryPostProcessor); } - return _messageSource; + else + { + regularPostProcessors = regularPostProcessors ?? new List(); + regularPostProcessors.Add(factoryProcessor); + } + } + + var objectMap = objectFactory.GetObjects(true, false); + + List registryPostProcessorObjects = null; + if (objectMap.Count > 0) + { + registryPostProcessorObjects = new List(objectMap.Values); + registryPostProcessorObjects.Sort(OrderComparator.Instance); + foreach (var processor in registryPostProcessorObjects) + { + processor.PostProcessObjectDefinitionRegistry(registry); + } + } + + InvokeObjectFactoryPostProcessors(registryPostProcessors, objectFactory); + InvokeObjectFactoryPostProcessors(registryPostProcessorObjects, objectFactory); + InvokeObjectFactoryPostProcessors(regularPostProcessors, objectFactory); + + // processedObjects.Add(objectMap.Keys); + + foreach (KeyValuePair entry in objectMap) + { + processedObjects.Add(entry.Key); + } + } + else + { + for (var i = 0; i < _objectFactoryPostProcessors.Count; i++) + { + IObjectFactoryPostProcessor factoryProcessor = _objectFactoryPostProcessors[i]; + // Invoke factory processors registered with the context instance. + factoryProcessor.PostProcessObjectFactory(objectFactory); } } - /// - /// The for this context. - /// - /// - /// If the context has not been initialized yet. - /// - public IEventRegistry EventRegistry + // Do not initialize FactoryBeans here: We need to leave all regular beans + // uninitialized to let the bean factory post-processors apply to them! + var factoryProcessorNames = GetObjectNamesForType(typeof(IObjectFactoryPostProcessor), true, false); + + // Separate between ObjectFactoryPostProcessors that implement PriorityOrdered, + // Ordered, and the rest. + var priorityOrderedFactoryProcessors = new List(); + var orderedFactoryProcessorsNames = new List(); + var nonOrderedFactoryProcessorNames = new List(); + + for (int i = 0; i < factoryProcessorNames.Count; ++i) { - get + string processorName = factoryProcessorNames[i]; + if (processedObjects.Contains(processorName)) { - if (_eventRegistry == null) - { - throw new InvalidOperationException( - "EventRegistry not initialized - call 'Refresh()' " + - "before accessing the event registry via the context: " + this); - } - return _eventRegistry; + //skip -- already processed in first phase above + Debug.WriteLine(""); } - } - - /// - /// Returns the internal object factory of the parent context if it implements - /// ; else, - /// returns the parent context itself. - /// - /// - /// The parent context's object factory, or the parent itself. - /// - protected IObjectFactory GetInternalParentObjectFactory() - { - if (_parentApplicationContext is IConfigurableApplicationContext configContext) + else if (IsTypeMatch(processorName, typeof(IPriorityOrdered))) { - return configContext.ObjectFactory; + priorityOrderedFactoryProcessors.Add(SafeGetObjectFactory().GetObject(processorName)); } - - return _parentApplicationContext; - } - - /// - /// Raises an application context event. - /// - /// - /// Any arguments to the event. May be . - /// - protected virtual void OnContextEvent(ApplicationEventArgs e) - { - OnContextEvent(this, e); - } - - /// - /// Raises an application context event. - /// - /// - /// The source of the event. - /// - /// - /// Any arguments to the event. May be . - /// - protected virtual void OnContextEvent(object source, ApplicationEventArgs e) - { - IEventExceptionsCollector exceptions = _eventRaiser.Raise(ContextEvent, source, e); - if (exceptions.HasExceptions) + else if (IsTypeMatch(processorName, typeof(IOrdered))) { - Delegate target = ContextEvent.GetInvocationList()[0]; - Exception exception = exceptions[target]; - throw new ApplicationContextException(string.Format("An unhandled exception occured during processing application event {0} in handler {1}", e.GetType(), target.Method), exception); - } - } - - /// - /// Create the strategy to be used - /// - protected virtual EventRaiser CreateEventRaiser() - { - return new DefensiveEventRaiser(); - } - - /// - /// Modify the application context's internal object factory after its standard - /// initialization. - /// - /// - ///

- /// All object definitions will have been loaded, but no objects - /// will have been instantiated yet. This allows for the registration - /// of special - /// s - /// in certain - /// implementations. - ///

- ///
- /// - /// The object factory used by the application context. - /// - /// - /// In the case of errors. - /// . - protected virtual void PostProcessObjectFactory( - IConfigurableListableObjectFactory objectFactory) - { - } - - /// - /// Template method which can be overridden to add context-specific - /// work before the underlying object factory gets refreshed. - /// - protected virtual void OnPreRefresh() - { - } - - /// - /// Template method which can be overridden to add context-specific - /// refresh work. - /// - /// - ///

- /// Called on initialization of special objects, before instantiation - /// of singletons. - ///

- ///
- protected virtual void OnRefresh() - { - } - - /// - /// Template method which can be overridden to add context-specific - /// work after the context was refreshed but before the - /// event gets raised. - /// - protected virtual void OnPostRefresh() - { - PublishEvent(this, new ContextRefreshedEventArgs()); - } - - /// - /// Instantiate and invoke all registered - /// - /// objects, respecting any explicit ordering. - /// - /// - /// - /// Must be called before singleton instantiation. - /// - /// - /// In the case of errors. - private void InvokeObjectFactoryPostProcessors(IConfigurableListableObjectFactory objectFactory) - { - // Invoke BeanDefinitionRegistryPostProcessors first, if any. - var processedObjects = new HashSet(); - - if (objectFactory is IObjectDefinitionRegistry registry) - { - List regularPostProcessors = null; - List registryPostProcessors = null; - - for (var i = 0; i < _objectFactoryPostProcessors.Count; i++) - { - IObjectFactoryPostProcessor factoryProcessor = _objectFactoryPostProcessors[i]; - if (factoryProcessor is IObjectDefinitionRegistryPostProcessor registryPostProcessor) - { - registryPostProcessor.PostProcessObjectDefinitionRegistry(registry); - registryPostProcessors = registryPostProcessors ?? new List(); - registryPostProcessors.Add(registryPostProcessor); - } - else - { - regularPostProcessors = regularPostProcessors ?? new List(); - regularPostProcessors.Add(factoryProcessor); - } - } - - var objectMap = objectFactory.GetObjects(true, false); - - List registryPostProcessorObjects = null; - if (objectMap.Count > 0) - { - registryPostProcessorObjects = new List(objectMap.Values); - registryPostProcessorObjects.Sort(OrderComparator.Instance); - foreach (var processor in registryPostProcessorObjects) - { - processor.PostProcessObjectDefinitionRegistry(registry); - } - } - - - InvokeObjectFactoryPostProcessors(registryPostProcessors, objectFactory); - InvokeObjectFactoryPostProcessors(registryPostProcessorObjects, objectFactory); - InvokeObjectFactoryPostProcessors(regularPostProcessors, objectFactory); - - // processedObjects.Add(objectMap.Keys); - - foreach (KeyValuePair entry in objectMap) - { - processedObjects.Add(entry.Key); - } - + orderedFactoryProcessorsNames.Add(processorName); } else { - for (var i = 0; i < _objectFactoryPostProcessors.Count; i++) - { - IObjectFactoryPostProcessor factoryProcessor = _objectFactoryPostProcessors[i]; - // Invoke factory processors registered with the context instance. - factoryProcessor.PostProcessObjectFactory(objectFactory); - } - } - - // Do not initialize FactoryBeans here: We need to leave all regular beans - // uninitialized to let the bean factory post-processors apply to them! - var factoryProcessorNames = GetObjectNamesForType(typeof(IObjectFactoryPostProcessor), true, false); - - // Separate between ObjectFactoryPostProcessors that implement PriorityOrdered, - // Ordered, and the rest. - var priorityOrderedFactoryProcessors = new List(); - var orderedFactoryProcessorsNames = new List(); - var nonOrderedFactoryProcessorNames = new List(); - - for (int i = 0; i < factoryProcessorNames.Count; ++i) - { - string processorName = factoryProcessorNames[i]; - if (processedObjects.Contains(processorName)) - { - //skip -- already processed in first phase above - Debug.WriteLine(""); - } - else if (IsTypeMatch(processorName, typeof(IPriorityOrdered))) - { - priorityOrderedFactoryProcessors.Add(SafeGetObjectFactory().GetObject(processorName)); - } - else if (IsTypeMatch(processorName, typeof(IOrdered))) - { - orderedFactoryProcessorsNames.Add(processorName); - } - else - { - nonOrderedFactoryProcessorNames.Add(processorName); - } - } - // First, invoke the IObjectFactoryPostProcessors that implement IPriorityOrdered. - InvokePriorityOrderedObjectFactoryPostProcessors(factoryProcessorNames, priorityOrderedFactoryProcessors); - - // Second, invoke those IObjectFactoryPostProcessors that implement IOrdered... - var orderedFactoryProcessors = new List(); - foreach (string orderedFactoryProcessorsName in orderedFactoryProcessorsNames) - { - orderedFactoryProcessors.Add(SafeGetObjectFactory().GetObject(orderedFactoryProcessorsName)); - } - orderedFactoryProcessors.Sort(OrderComparator.Instance); - InvokeObjectFactoryPostProcessors(orderedFactoryProcessors, SafeGetObjectFactory()); - - // and then the unordered ones... - if (nonOrderedFactoryProcessorNames.Count > 0) - { - var nonOrderedPostProcessors = new List(); - for (var i = 0; i < nonOrderedFactoryProcessorNames.Count; i++) - { - string nonOrderedFactoryProcessorName = nonOrderedFactoryProcessorNames[i]; - nonOrderedPostProcessors.Add(SafeGetObjectFactory().GetObject(nonOrderedFactoryProcessorName)); - } - InvokeObjectFactoryPostProcessors(nonOrderedPostProcessors, SafeGetObjectFactory()); - } - - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug($"processed {factoryProcessorNames.Count} IFactoryObjectPostProcessors defined in application context [{Name}]."); + nonOrderedFactoryProcessorNames.Add(processorName); } } - protected virtual void InvokePriorityOrderedObjectFactoryPostProcessors( - IReadOnlyList factoryProcessorNames, - List priorityOrderedFactoryProcessors) + // First, invoke the IObjectFactoryPostProcessors that implement IPriorityOrdered. + InvokePriorityOrderedObjectFactoryPostProcessors(factoryProcessorNames, priorityOrderedFactoryProcessors); + + // Second, invoke those IObjectFactoryPostProcessors that implement IOrdered... + var orderedFactoryProcessors = new List(); + foreach (string orderedFactoryProcessorsName in orderedFactoryProcessorsNames) { - priorityOrderedFactoryProcessors.Sort(OrderComparator.Instance); - InvokeObjectFactoryPostProcessors(priorityOrderedFactoryProcessors, SafeGetObjectFactory()); + orderedFactoryProcessors.Add(SafeGetObjectFactory().GetObject(orderedFactoryProcessorsName)); + } - var processorNames = factoryProcessorNames.Count > 0 ? new HashSet(factoryProcessorNames) : null; + orderedFactoryProcessors.Sort(OrderComparator.Instance); + InvokeObjectFactoryPostProcessors(orderedFactoryProcessors, SafeGetObjectFactory()); - // Now will find any additional IObjectFactoryPostProcessors that implement IPriorityOrdered that may have been - // resolved due to using TypeAlias - var factoryProcessorNamesAfterTypeAlias = GetObjectNamesForType(typeof(IObjectFactoryPostProcessor), true, false); - priorityOrderedFactoryProcessors.Clear(); - foreach (string factoryProcessorName in factoryProcessorNamesAfterTypeAlias) + // and then the unordered ones... + if (nonOrderedFactoryProcessorNames.Count > 0) + { + var nonOrderedPostProcessors = new List(); + for (var i = 0; i < nonOrderedFactoryProcessorNames.Count; i++) { - if (processorNames == null || !processorNames.Contains(factoryProcessorName)) + string nonOrderedFactoryProcessorName = nonOrderedFactoryProcessorNames[i]; + nonOrderedPostProcessors.Add(SafeGetObjectFactory().GetObject(nonOrderedFactoryProcessorName)); + } + + InvokeObjectFactoryPostProcessors(nonOrderedPostProcessors, SafeGetObjectFactory()); + } + + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug($"processed {factoryProcessorNames.Count} IFactoryObjectPostProcessors defined in application context [{Name}]."); + } + } + + protected virtual void InvokePriorityOrderedObjectFactoryPostProcessors( + IReadOnlyList factoryProcessorNames, + List priorityOrderedFactoryProcessors) + { + priorityOrderedFactoryProcessors.Sort(OrderComparator.Instance); + InvokeObjectFactoryPostProcessors(priorityOrderedFactoryProcessors, SafeGetObjectFactory()); + + var processorNames = factoryProcessorNames.Count > 0 ? new HashSet(factoryProcessorNames) : null; + + // Now will find any additional IObjectFactoryPostProcessors that implement IPriorityOrdered that may have been + // resolved due to using TypeAlias + var factoryProcessorNamesAfterTypeAlias = GetObjectNamesForType(typeof(IObjectFactoryPostProcessor), true, false); + priorityOrderedFactoryProcessors.Clear(); + foreach (string factoryProcessorName in factoryProcessorNamesAfterTypeAlias) + { + if (processorNames == null || !processorNames.Contains(factoryProcessorName)) + { + if (IsTypeMatch(factoryProcessorName, typeof(IPriorityOrdered))) { - if (IsTypeMatch(factoryProcessorName, typeof(IPriorityOrdered))) - { - priorityOrderedFactoryProcessors.Add(SafeGetObjectFactory().GetObject(factoryProcessorName)); - } + priorityOrderedFactoryProcessors.Add(SafeGetObjectFactory().GetObject(factoryProcessorName)); } } - // Second, invoke newly discovered IObjectFactoryPostProcessors that implement IPriorityOrdered. - priorityOrderedFactoryProcessors.Sort(OrderComparator.Instance); - InvokeObjectFactoryPostProcessors(priorityOrderedFactoryProcessors, SafeGetObjectFactory()); } - private void InvokeObjectFactoryPostProcessors( - List objectFactoryPostProcessors, - IConfigurableListableObjectFactory objectFactory) where T : IObjectFactoryPostProcessor + // Second, invoke newly discovered IObjectFactoryPostProcessors that implement IPriorityOrdered. + priorityOrderedFactoryProcessors.Sort(OrderComparator.Instance); + InvokeObjectFactoryPostProcessors(priorityOrderedFactoryProcessors, SafeGetObjectFactory()); + } + + private void InvokeObjectFactoryPostProcessors( + List objectFactoryPostProcessors, + IConfigurableListableObjectFactory objectFactory) where T : IObjectFactoryPostProcessor + { + if (objectFactoryPostProcessors == null) { - if (objectFactoryPostProcessors == null) - { - return; - } - for (var i = 0; i < objectFactoryPostProcessors.Count; i++) - { - objectFactoryPostProcessors[i].PostProcessObjectFactory(objectFactory); - } + return; } - private void RegisterObjectPostProcessors(IConfigurableListableObjectFactory objectFactory) + for (var i = 0; i < objectFactoryPostProcessors.Count; i++) { - RefreshObjectPostProcessorChecker(objectFactory); - var dict = GetObjects(true, false); - List objectProcessors = new List(dict.Values); + objectFactoryPostProcessors[i].PostProcessObjectFactory(objectFactory); + } + } - // objectProcessors.Sort(new OrderComparator()); - for (var i = 0; i < objectProcessors.Count; i++) - { - IObjectPostProcessor objectPostProcessor = objectProcessors[i]; - SafeGetObjectFactory().AddObjectPostProcessor(objectPostProcessor); - } + private void RegisterObjectPostProcessors(IConfigurableListableObjectFactory objectFactory) + { + RefreshObjectPostProcessorChecker(objectFactory); + var dict = GetObjects(true, false); + List objectProcessors = new List(dict.Values); - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug($"processed {objectProcessors.Count} IObjectPostProcessors defined in application context [{Name}]."); - } + // objectProcessors.Sort(new OrderComparator()); + for (var i = 0; i < objectProcessors.Count; i++) + { + IObjectPostProcessor objectPostProcessor = objectProcessors[i]; + SafeGetObjectFactory().AddObjectPostProcessor(objectPostProcessor); } - /// - /// Resets the well-known ObjectPostProcessorChecker that logs an info - /// message when an object is created during IObjectPostProcessor - /// instantiation, i.e. when an object is not eligible for being - /// processed by all IObjectPostProcessors. - /// - private void RefreshObjectPostProcessorChecker(IConfigurableListableObjectFactory objectFactory) + if (log.IsEnabled(LogLevel.Debug)) { - int registeredObjectPostProcessorCount = GetObjectNamesForType(typeof(IObjectPostProcessor), true, false).Count; - int objectPostProcessorCount = SafeGetObjectFactory().ObjectPostProcessorCount + 1 - + registeredObjectPostProcessorCount; - ((ObjectPostProcessorChecker)_defaultObjectPostProcessors[0]).Reset(objectFactory, objectPostProcessorCount); + log.LogDebug($"processed {objectProcessors.Count} IObjectPostProcessors defined in application context [{Name}]."); } + } - /// - /// Initializes the default event registry for this context. - /// - private void InitEventRegistry() + /// + /// Resets the well-known ObjectPostProcessorChecker that logs an info + /// message when an object is created during IObjectPostProcessor + /// instantiation, i.e. when an object is not eligible for being + /// processed by all IObjectPostProcessors. + /// + private void RefreshObjectPostProcessorChecker(IConfigurableListableObjectFactory objectFactory) + { + int registeredObjectPostProcessorCount = GetObjectNamesForType(typeof(IObjectPostProcessor), true, false).Count; + int objectPostProcessorCount = SafeGetObjectFactory().ObjectPostProcessorCount + 1 + + registeredObjectPostProcessorCount; + ((ObjectPostProcessorChecker) _defaultObjectPostProcessors[0]).Reset(objectFactory, objectPostProcessorCount); + } + + /// + /// Initializes the default event registry for this context. + /// + private void InitEventRegistry() + { + if (ContainsLocalObject(EventRegistryObjectName)) { - if (ContainsLocalObject(EventRegistryObjectName)) + object candidateRegistry = GetObject(EventRegistryObjectName); + if (candidateRegistry is IEventRegistry) { - object candidateRegistry = GetObject(EventRegistryObjectName); - if (candidateRegistry is IEventRegistry) - { - _eventRegistry = (IEventRegistry)candidateRegistry; + _eventRegistry = (IEventRegistry) candidateRegistry; - log.LogDebug(StringUtils.Surround( - "Using IEventRegistry [", EventRegistry, "]")); - } - else - { - _eventRegistry = new EventRegistry(); - - if (log.IsEnabled(LogLevel.Warning)) - { - log.LogWarning(string.Format( - "Found object in context named '{0}' : this name " + - "is typically reserved for IEventRegistry objects. " + - "Falling back to default '{1}'.", - EventRegistryObjectName, EventRegistry)); - } - } + log.LogDebug(StringUtils.Surround( + "Using IEventRegistry [", EventRegistry, "]")); } else { _eventRegistry = new EventRegistry(); - if (log.IsEnabled(LogLevel.Debug)) + if (log.IsEnabled(LogLevel.Warning)) { - log.LogDebug($"No IEventRegistry found with name '{EventRegistryObjectName}' : using default '{EventRegistry}'."); + log.LogWarning(string.Format( + "Found object in context named '{0}' : this name " + + "is typically reserved for IEventRegistry objects. " + + "Falling back to default '{1}'.", + EventRegistryObjectName, EventRegistry)); } } - var interestedParties = GetObjects(true, false).Values; - foreach (IEventRegistryAware party in interestedParties) + } + else + { + _eventRegistry = new EventRegistry(); + + if (log.IsEnabled(LogLevel.Debug)) { - party.EventRegistry = EventRegistry; + log.LogDebug($"No IEventRegistry found with name '{EventRegistryObjectName}' : using default '{EventRegistry}'."); } - EventRegistry.PublishEvents(this); } - /// - /// Returns the internal message source of the parent context if said - /// parent context is an , else - /// simply the parent context itself. - /// - /// - /// The internal message source of the parent context if said - /// parent context is an , else - /// simply the parent context itself. - /// - protected virtual IMessageSource GetInternalParentMessageSource() + var interestedParties = GetObjects(true, false).Values; + foreach (IEventRegistryAware party in interestedParties) { - AbstractApplicationContext parent - = ParentContext as AbstractApplicationContext; - return parent == null ? ParentContext : parent._messageSource; + party.EventRegistry = EventRegistry; } - /// - /// Initializes the default message source for this context. - /// - /// - ///

- /// Uses any parent context's message source if one is not available - /// in this context. - ///

- ///
- private void InitMessageSource() + EventRegistry.PublishEvents(this); + } + + /// + /// Returns the internal message source of the parent context if said + /// parent context is an , else + /// simply the parent context itself. + /// + /// + /// The internal message source of the parent context if said + /// parent context is an , else + /// simply the parent context itself. + /// + protected virtual IMessageSource GetInternalParentMessageSource() + { + AbstractApplicationContext parent + = ParentContext as AbstractApplicationContext; + return parent == null ? ParentContext : parent._messageSource; + } + + /// + /// Initializes the default message source for this context. + /// + /// + ///

+ /// Uses any parent context's message source if one is not available + /// in this context. + ///

+ ///
+ private void InitMessageSource() + { + if (ContainsLocalObject(MessageSourceObjectName)) { - if (ContainsLocalObject(MessageSourceObjectName)) + object candidateSource = GetObject(MessageSourceObjectName); + if (candidateSource is IMessageSource) { - object candidateSource = GetObject(MessageSourceObjectName); - if (candidateSource is IMessageSource) + _messageSource + = (IMessageSource) GetObject(MessageSourceObjectName); + + // make IMessageSource aware of any parent IMessageSource... + if (ParentContext != null) { - _messageSource - = (IMessageSource)GetObject(MessageSourceObjectName); - - // make IMessageSource aware of any parent IMessageSource... - if (ParentContext != null) + IHierarchicalMessageSource hierSource + = MessageSource as IHierarchicalMessageSource; + if (hierSource != null) { - IHierarchicalMessageSource hierSource - = MessageSource as IHierarchicalMessageSource; - if (hierSource != null) - { - IMessageSource parentMessageSource - = GetInternalParentMessageSource(); - hierSource.ParentMessageSource = parentMessageSource; - } - } - - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug(StringUtils.Surround( - "Using MessageSource [", MessageSource, "]")); + IMessageSource parentMessageSource + = GetInternalParentMessageSource(); + hierSource.ParentMessageSource = parentMessageSource; } } - else - { - _messageSource = new DelegatingMessageSource( - GetInternalParentMessageSource()); - - if (log.IsEnabled(LogLevel.Warning)) - { - log.LogWarning(string.Format( - "Found object in context named '{0}' : this name " + - "is typically reserved for IMessageSource objects. " + - "Falling back to default '{1}'.", - MessageSourceObjectName, MessageSource)); - } - } - } - else if (ParentContext != null) - { - _messageSource = new DelegatingMessageSource( - GetInternalParentMessageSource()); - SafeGetObjectFactory().RegisterSingleton(MessageSourceObjectName, _messageSource); if (log.IsEnabled(LogLevel.Debug)) { - log.LogDebug(string.Format( - "No message source found in the current context: using parent context's message source '{0}'.", - MessageSource)); + log.LogDebug(StringUtils.Surround( + "Using MessageSource [", MessageSource, "]")); } } else { - _messageSource = new StaticMessageSource(); - SafeGetObjectFactory().RegisterSingleton(MessageSourceObjectName, _messageSource); + _messageSource = new DelegatingMessageSource( + GetInternalParentMessageSource()); - if (log.IsEnabled(LogLevel.Debug)) + if (log.IsEnabled(LogLevel.Warning)) { - log.LogDebug(string.Format( - "No IMessageSource found with name '{0}' : using default '{1}'.", + log.LogWarning(string.Format( + "Found object in context named '{0}' : this name " + + "is typically reserved for IMessageSource objects. " + + "Falling back to default '{1}'.", MessageSourceObjectName, MessageSource)); } } } - - private void RefreshApplicationEventListeners() + else if (ParentContext != null) { - var listeners = GetObjects(true, false).Values; - foreach (IApplicationEventListener applicationListener in listeners) + _messageSource = new DelegatingMessageSource( + GetInternalParentMessageSource()); + SafeGetObjectFactory().RegisterSingleton(MessageSourceObjectName, _messageSource); + + if (log.IsEnabled(LogLevel.Debug)) { - EventRegistry.Subscribe(applicationListener); + log.LogDebug(string.Format( + "No message source found in the current context: using parent context's message source '{0}'.", + MessageSource)); } } - - /// - /// Return the internal object factory of this application context. - /// - public abstract IConfigurableListableObjectFactory ObjectFactory { get; } - - /// - /// Add a new - /// that will get applied to the internal object factory of this application context - /// on refresh, before any of the object definitions are evaluated. - /// - /// - /// The factory processor to register. - /// - public void AddObjectFactoryPostProcessor( - IObjectFactoryPostProcessor objectFactoryPostProcessor) + else { - _objectFactoryPostProcessors.Add(objectFactoryPostProcessor); - } + _messageSource = new StaticMessageSource(); + SafeGetObjectFactory().RegisterSingleton(MessageSourceObjectName, _messageSource); - /// - /// Load or refresh the persistent representation of the configuration, - /// which might an XML file, properties file, or relational database schema. - /// - /// - /// If the configuration cannot be loaded. - /// - /// - /// If the object factory could not be initialized. - /// - public void Refresh() - { - lock (SyncRoot) + if (log.IsEnabled(LogLevel.Debug)) { - _startupDate = DateTime.Now; + log.LogDebug(string.Format( + "No IMessageSource found with name '{0}' : using default '{1}'.", + MessageSourceObjectName, MessageSource)); + } + } + } - OnPreRefresh(); + private void RefreshApplicationEventListeners() + { + var listeners = GetObjects(true, false).Values; + foreach (IApplicationEventListener applicationListener in listeners) + { + EventRegistry.Subscribe(applicationListener); + } + } - if (log.IsEnabled(LogLevel.Debug)) + /// + /// Return the internal object factory of this application context. + /// + public abstract IConfigurableListableObjectFactory ObjectFactory { get; } + + /// + /// Add a new + /// that will get applied to the internal object factory of this application context + /// on refresh, before any of the object definitions are evaluated. + /// + /// + /// The factory processor to register. + /// + public void AddObjectFactoryPostProcessor( + IObjectFactoryPostProcessor objectFactoryPostProcessor) + { + _objectFactoryPostProcessors.Add(objectFactoryPostProcessor); + } + + /// + /// Load or refresh the persistent representation of the configuration, + /// which might an XML file, properties file, or relational database schema. + /// + /// + /// If the configuration cannot be loaded. + /// + /// + /// If the object factory could not be initialized. + /// + public void Refresh() + { + lock (SyncRoot) + { + _startupDate = DateTime.Now; + + OnPreRefresh(); + + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug(string.Format("ApplicationContext Refresh: Refreshing object factory ")); + } + + RefreshObjectFactory(); + + IConfigurableListableObjectFactory objectFactory = ObjectFactory; + + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug(string.Format("ApplicationContext Refresh: Registering well-known processors and objects")); + } + + PrepareObjectFactory(objectFactory); + + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug(string.Format("ApplicationContext Refresh: Custom post processing object factory")); + } + + PostProcessObjectFactory(objectFactory); + + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug(string.Format("ApplicationContext Refresh: Post processing object factory using pre-registered processors")); + } + + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug(string.Format( + CultureInfo.InvariantCulture, + "{0} objects defined in application context [{1}].", + ObjectDefinitionCount == 0 ? "No" : ObjectDefinitionCount.ToString(), + Name)); + } + + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug(string.Format("ApplicationContext Refresh: Post processing object factory using defined processors")); + } + + InvokeObjectFactoryPostProcessors(objectFactory); + + RegisterObjectPostProcessors(objectFactory); + InitEventRegistry(); + InitMessageSource(); + + RefreshApplicationEventListeners(); + + OnRefresh(); + + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug(string.Format("ApplicationContext Refresh: Preinstantiating singletons")); + } + + objectFactory.PreInstantiateSingletons(); + + OnPostRefresh(); + + if (log.IsEnabled(LogLevel.Information)) + { + log.LogInformation(string.Format("ApplicationContext Refresh: Completed")); + } + } + } + + /// + /// Registers well-known s and + /// preregisters well-known dependencies using + /// + /// the raw object factory as returned from + private void PrepareObjectFactory(IConfigurableListableObjectFactory objectFactory) + { + EnsureKnownObjectPostProcessors(objectFactory); + objectFactory.IgnoreDependencyType(typeof(IResourceLoader)); + objectFactory.IgnoreDependencyType(typeof(IApplicationContext)); + + objectFactory.RegisterResolvableDependency(typeof(IObjectFactory), objectFactory); + objectFactory.RegisterResolvableDependency(typeof(IResourceLoader), this); + objectFactory.RegisterResolvableDependency(typeof(IApplicationEventPublisher), this); + objectFactory.RegisterResolvableDependency(typeof(IApplicationContext), this); + objectFactory.RegisterResolvableDependency(typeof(IEventRegistry), this); + } + + /// + /// Ensures, that predefined ObjectPostProcessors are registered with this ObjectFactory + /// + /// + protected void EnsureKnownObjectPostProcessors(IConfigurableListableObjectFactory objectFactory) + { + // index 0 contains the ObjectPostProcessorChecker that is handled separately! + for (int i = 1; i < _defaultObjectPostProcessors.Count; i++) + { + objectFactory.AddObjectPostProcessor(_defaultObjectPostProcessors[i]); + } + } + + /// + /// Gets the parent context, or if there is no + /// parent context. + /// + /// + /// The parent context, or if there is no + /// parent. + /// + /// + public virtual IApplicationContext ParentContext + { + get => _parentApplicationContext; + set => _parentApplicationContext = value; + } + + /// + /// Starts this component. + /// + /// Should not throw an exception if the component is already running. + /// In the case of a container, this will propagate the start signal + /// to all components that apply. + /// + public void Start() + { + _isInStart = true; + + IDictionary lifecycleObjects = LifeCycleObjects; + foreach (KeyValuePair dictionaryEntry in lifecycleObjects) + { + //TODO start dependencies of the lifecycle objects + ILifecycle obj = dictionaryEntry.Value; + if (obj != null) + { + if (!obj.IsRunning) { - log.LogDebug(string.Format("ApplicationContext Refresh: Refreshing object factory ")); - } - - RefreshObjectFactory(); - - IConfigurableListableObjectFactory objectFactory = ObjectFactory; - - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug(string.Format("ApplicationContext Refresh: Registering well-known processors and objects")); - } - - PrepareObjectFactory(objectFactory); - - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug(string.Format("ApplicationContext Refresh: Custom post processing object factory")); - } - - PostProcessObjectFactory(objectFactory); - - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug(string.Format("ApplicationContext Refresh: Post processing object factory using pre-registered processors")); - } - - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug(string.Format( - CultureInfo.InvariantCulture, - "{0} objects defined in application context [{1}].", - ObjectDefinitionCount == 0 ? "No" : ObjectDefinitionCount.ToString(), - Name)); - } - - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug(string.Format("ApplicationContext Refresh: Post processing object factory using defined processors")); - } - - InvokeObjectFactoryPostProcessors(objectFactory); - - RegisterObjectPostProcessors(objectFactory); - InitEventRegistry(); - InitMessageSource(); - - RefreshApplicationEventListeners(); - - OnRefresh(); - - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug(string.Format("ApplicationContext Refresh: Preinstantiating singletons")); - } - - objectFactory.PreInstantiateSingletons(); - - OnPostRefresh(); - - if (log.IsEnabled(LogLevel.Information)) - { - log.LogInformation(string.Format("ApplicationContext Refresh: Completed")); + obj.Start(); } } } - /// - /// Registers well-known s and - /// preregisters well-known dependencies using - /// - /// the raw object factory as returned from - private void PrepareObjectFactory(IConfigurableListableObjectFactory objectFactory) - { - EnsureKnownObjectPostProcessors(objectFactory); - objectFactory.IgnoreDependencyType(typeof(IResourceLoader)); - objectFactory.IgnoreDependencyType(typeof(IApplicationContext)); + _isInStart = false; + } - objectFactory.RegisterResolvableDependency(typeof(IObjectFactory), objectFactory); - objectFactory.RegisterResolvableDependency(typeof(IResourceLoader), this); - objectFactory.RegisterResolvableDependency(typeof(IApplicationEventPublisher), this); - objectFactory.RegisterResolvableDependency(typeof(IApplicationContext), this); - objectFactory.RegisterResolvableDependency(typeof(IEventRegistry), this); - } + /// + /// Stops this component. + /// + /// + /// Should not throw an exception if the component isn't started yet. + /// In the case of a container, this will propagate the stop signal + /// to all components that apply. + /// + public void Stop() + { + _isInStop = true; - /// - /// Ensures, that predefined ObjectPostProcessors are registered with this ObjectFactory - /// - /// - protected void EnsureKnownObjectPostProcessors(IConfigurableListableObjectFactory objectFactory) + IDictionary lifecycleObjects = LifeCycleObjects; + foreach (KeyValuePair dictionaryEntry in lifecycleObjects) { - // index 0 contains the ObjectPostProcessorChecker that is handled separately! - for (int i = 1; i < _defaultObjectPostProcessors.Count; i++) + //TODO stop dependencies of the lifecycle objects + ILifecycle obj = dictionaryEntry.Value; + if (obj != null) { - objectFactory.AddObjectPostProcessor(_defaultObjectPostProcessors[i]); + if (obj.IsRunning) + { + obj.Stop(); + } } } - /// - /// Gets the parent context, or if there is no - /// parent context. - /// - /// - /// The parent context, or if there is no - /// parent. - /// - /// - public virtual IApplicationContext ParentContext - { - get => _parentApplicationContext; - set => _parentApplicationContext = value; - } + _isInStop = false; + } - /// - /// Starts this component. - /// - /// Should not throw an exception if the component is already running. - /// In the case of a container, this will propagate the start signal - /// to all components that apply. - /// - public void Start() + /// + /// Gets a value indicating whether this component is currently running. + /// + /// + /// true if this component is running; otherwise, false. + /// + /// + /// In the case of a container, this will return true + /// only if all components that apply are currently running. + /// + public bool IsRunning + { + get { - _isInStart = true; - IDictionary lifecycleObjects = LifeCycleObjects; foreach (KeyValuePair dictionaryEntry in lifecycleObjects) { - //TODO start dependencies of the lifecycle objects ILifecycle obj = dictionaryEntry.Value; if (obj != null) { if (!obj.IsRunning) { - obj.Start(); + return false; } } } - _isInStart = false; - } - - /// - /// Stops this component. - /// - /// - /// Should not throw an exception if the component isn't started yet. - /// In the case of a container, this will propagate the stop signal - /// to all components that apply. - /// - public void Stop() - { - _isInStop = true; - - IDictionary lifecycleObjects = LifeCycleObjects; - foreach (KeyValuePair dictionaryEntry in lifecycleObjects) - { - //TODO stop dependencies of the lifecycle objects - ILifecycle obj = dictionaryEntry.Value; - if (obj != null) - { - if (obj.IsRunning) - { - obj.Stop(); - } - } - } - - _isInStop = false; - } - - /// - /// Gets a value indicating whether this component is currently running. - /// - /// - /// true if this component is running; otherwise, false. - /// - /// - /// In the case of a container, this will return true - /// only if all components that apply are currently running. - /// - public bool IsRunning - { - get - { - IDictionary lifecycleObjects = LifeCycleObjects; - foreach (KeyValuePair dictionaryEntry in lifecycleObjects) - { - ILifecycle obj = dictionaryEntry.Value; - if (obj != null) - { - if (!obj.IsRunning) - { - return false; - } - } - } - return true; - } - } - - /// - /// Gets a dictionary of all singleton beans that implement the - /// ILifecycle interface in this context. - /// - /// A dictionary of ILifecycle objects with object name as key. - private IDictionary LifeCycleObjects - { - get - { - IConfigurableListableObjectFactory objectFactory = ObjectFactory; - IList objectNames = objectFactory.SingletonNames; - IDictionary lifeCycleObjects = new Dictionary(); - foreach (string objectName in objectNames) - { - object obj = objectFactory.GetSingleton(objectName); - if (obj is ILifecycle) - { - lifeCycleObjects[objectName] = (ILifecycle) obj; - } - } - return lifeCycleObjects; - } - } - - /// - /// Raised in response to an implementation-dependant application - /// context event. - /// - public event ApplicationEventHandler ContextEvent; - - /// - /// The date and time this context was first loaded. - /// - /// - /// The representing when this context - /// was first loaded. - /// - public DateTime StartupDate => _startupDate; - - /// - /// A name for this context. - /// - /// - /// A name for this context. - /// - public string Name - { - get => _name; - set => _name = value; - } - - /// - /// Return the names of objects matching the given - /// (including subclasses), judging from the object definitions. - /// - /// - /// The (class or interface) to match, or - /// for all object names. - /// - /// - /// The names of all objects defined in this factory, or an empty array if none - /// are defined. - /// - /// - public IReadOnlyList GetObjectNamesForType(Type type) - { - return SafeGetObjectFactory().GetObjectNamesForType(type); - } - - /// - /// Return the names of objects matching the given - /// (including subclasses), judging from the object definitions. - /// - /// - ///

- /// Does consider objects created by s, - /// or rather it considers the type of objects created by - /// (which means that - /// s will be instantiated). - ///

- ///

- /// Does not consider any hierarchy this factory may participate in. - ///

- ///
- /// - /// The (class or interface) to match, or - /// for all object names. - /// - /// - /// The names of all objects defined in this factory, or an empty array if none - /// are defined. - /// - public IReadOnlyList GetObjectNames() - { - return GetObjectNamesForType(typeof(T)); - } - - /// - /// Return the names of objects matching the given - /// (including subclasses), judging from the object definitions. - /// - /// - /// The (class or interface) to match, or - /// for all object names. - /// - /// - /// Whether to include prototype objects too or just singletons (also applies to - /// s). - /// - /// - /// Whether to include s too - /// or just normal objects. - /// - /// - /// The names of all objects defined in this factory, or an empty array if none - /// are defined. - /// - /// - public IReadOnlyList GetObjectNamesForType(Type type, bool includePrototypes, bool includeFactoryObjects) - { - return SafeGetObjectFactory().GetObjectNamesForType(type, includePrototypes, includeFactoryObjects); - } - - /// - /// Return the names of objects matching the given - /// (including subclasses), judging from the object definitions. - /// - /// - ///

- /// Does consider objects created by s, - /// or rather it considers the type of objects created by - /// (which means that - /// s will be instantiated). - ///

- ///

- /// Does not consider any hierarchy this factory may participate in. - /// Use - /// to include beans in ancestor factories too. - /// <p>Note: Does <i>not</i> ignore singleton objects that have been registered - /// by other means than bean definitions. - ///

- ///
- /// - /// The (class or interface) to match, or - /// for all object names. - /// - /// - /// Whether to include prototype objects too or just singletons (also applies to - /// s). - /// - /// - /// Whether to include s too - /// or just normal objects. - /// - /// - /// The names of all objects defined in this factory, or an empty array if none - /// are defined. - /// - public IReadOnlyList GetObjectNames(bool includePrototypes, bool includeFactoryObjects) - { - return GetObjectNamesForType(typeof(T), includePrototypes, includeFactoryObjects); - } - - /// - /// Return the names of all objects defined in this factory. - /// - /// - /// The names of all objects defined in this factory, or an empty array if none - /// are defined. - /// - /// - public IReadOnlyList GetObjectDefinitionNames() - { - return GetObjectDefinitionNames(false); - } - - /// - /// Return the names of all objects defined in this factory, if includeAncestorsis true - /// includes all parent factories. - /// - /// to include parent factories into result - /// - /// The names of all objects defined in this factory, if includeAncestors is true includes all - /// objects defined in parent factories, or an empty array if none are defined. - /// - public IReadOnlyList GetObjectDefinitionNames(bool includeAncestors) - { - return SafeGetObjectFactory().GetObjectDefinitionNames(includeAncestors); - } - - /// - /// Return the registered - /// for the - /// given object, allowing access to its property values and constructor - /// argument values. - /// - /// The name of the object. - /// - /// The registered - /// . - /// - /// - /// If there is no object with the given name. - /// - /// - /// In the case of errors. - /// - public virtual IObjectDefinition GetObjectDefinition(string name) - { - return SafeGetObjectFactory().GetObjectDefinition(name); - } - - - /// - /// Return the registered - /// for the - /// given object, allowing access to its property values and constructor - /// argument values. - /// - /// The name of the object. - /// Whether to search parent object factories. - /// - /// The registered - /// . - /// - /// - /// If there is no object with the given name. - /// - /// - /// In the case of errors. - /// - public IObjectDefinition GetObjectDefinition(string name, bool includeAncestors) - { - return SafeGetObjectFactory().GetObjectDefinition(name, includeAncestors); - } - - /// - /// Return the object instances that match the given object - /// (including subclasses), judging from either object - /// definitions or the value of - /// in the case of - /// s. - /// - /// - /// The (class or interface) to match. - /// - /// - /// A of the matching objects, - /// containing the object names as keys and the corresponding object instances - /// as values. - /// - /// - /// If the objects could not be created. - /// - /// - public IReadOnlyDictionary GetObjectsOfType(Type type) - { - return GetObjectsOfType(type, true, true); - } - - /// - /// Return the object instances that match the given object - /// (including subclasses), judging from either object - /// definitions or the value of - /// in the case of - /// s. - /// - /// - ///

- /// This version of the - /// method matches all kinds of object definitions, be they singletons, prototypes, or - /// s. Typically, the results - /// of this method call will be the same as a call to - /// IListableObjectFactory.GetObjectsOfType(type,true,true) . - ///

- ///
- /// - /// The (class or interface) to match. - /// - /// - /// A of the matching objects, - /// containing the object names as keys and the corresponding object instances - /// as values. - /// - /// - /// If the objects could not be created. - /// - public IReadOnlyDictionary GetObjects() - { - return SafeGetObjectFactory().GetObjects(true, true); - } - - /// - /// Return the object instances that match the given object - /// (including subclasses), judging from either object - /// definitions or the value of - /// in the case of - /// s. - /// - /// - /// The (class or interface) to match. - /// - /// - /// Whether to include prototype objects too or just singletons (also applies to - /// s). - /// - /// - /// Whether to include s too - /// or just normal objects. - /// - /// - /// A of the matching objects, - /// containing the object names as keys and the corresponding object instances - /// as values. - /// - /// - /// If the objects could not be created. - /// - /// - public IReadOnlyDictionary GetObjectsOfType( - Type type, bool includePrototypes, bool includeFactoryObjects) - { - return SafeGetObjectFactory().GetObjectsOfType(type, includePrototypes, includeFactoryObjects); - } - - /// - /// Return the object instances that match the given object - /// (including subclasses), judging from either object - /// definitions or the value of - /// in the case of - /// s. - /// - /// - /// The (class or interface) to match. - /// - /// - /// Whether to include prototype objects too or just singletons (also applies to - /// s). - /// - /// - /// Whether to include s too - /// or just normal objects. - /// - /// - /// A of the matching objects, - /// containing the object names as keys and the corresponding object instances - /// as values. - /// - /// - /// If the objects could not be created. - /// - public IReadOnlyDictionary GetObjects(bool includePrototypes, bool includeFactoryObjects) - { - return SafeGetObjectFactory().GetObjects(includePrototypes, includeFactoryObjects); - } - - /// - /// Return an instance (possibly shared or independent) of the given object name. - /// - /// - /// - /// This method allows an object factory to be used as a replacement for the - /// Singleton or Prototype design pattern. - /// - /// - /// Note that callers should retain references to returned objects. There is no - /// guarantee that this method will be implemented to be efficient. For example, - /// it may be synchronized, or may need to run an RDBMS query. - /// - /// - /// Will ask the parent factory if the object cannot be found in this factory - /// instance. - /// - /// - /// The type of the object to return. - /// The instance of the object. - /// - /// If there's no such object definition. - /// - /// - /// If there is more than a single object of the requested type defined in the factory. - /// - /// - /// If the object could not be created. - /// - public T GetObject() - { - var objectNamesForType = GetObjectNamesForType(typeof(T)); - if ((objectNamesForType == null) || (objectNamesForType.Count == 0)) - { - throw new NoSuchObjectDefinitionException(typeof(T).FullName, "Requested Type not Defined in the Context."); - } - - if (objectNamesForType.Count > 1) - { - throw new ObjectDefinitionStoreException( - $"More than one definition for {typeof(T).FullName} found in the Context."); - } - - return (T)GetObject(objectNamesForType[0]); - } - - /// - /// Return the number of objects defined in the factory. - /// - /// - /// The number of objects defined in the factory. - /// - /// - public int ObjectDefinitionCount => SafeGetObjectFactory().ObjectDefinitionCount; - - /// - /// Check if this object factory contains an object definition with the given name. - /// - /// The name of the object to look for. - /// - /// True if this object factory contains an object definition with the given name. - /// - /// - public bool ContainsObjectDefinition(string name) - { - return SafeGetObjectFactory().ContainsObjectDefinition(name); - } - - /// - /// Return an instance (possibly shared or independent) of the given object name. - /// - /// The name of the object to return. - /// The instance of the object. - /// - /// If there's no such object definition. - /// - /// - /// If the object could not be created. - /// - /// - public object this[string name] => SafeGetObjectFactory().GetObject(name); - - /// - /// Does this object factory contain an object with the given name? - /// - /// The name of the object to query. - /// - /// if an object with the given name is defined. - /// - /// - public bool ContainsObject(string name) - { - return SafeGetObjectFactory().ContainsObject(name); - } - - /// - /// Return the aliases for the given object name, if defined. - /// - /// The object name to check for aliases. - /// The aliases, or an empty array if none. - /// - /// If there's no such object definition. - /// - /// - public IReadOnlyList GetAliases(string name) - { - return SafeGetObjectFactory().GetAliases(name); - } - - - /// - /// Determines whether the object with the given name matches the specified type. - /// - /// More specifically, check whether a GetObject call for the given name - /// would return an object that is assignable to the specified target type. - /// Translates aliases back to the corresponding canonical bean name. - /// Will ask the parent factory if the bean cannot be found in this factory instance. - /// - /// The name of the object to query. - /// Type of the target to match against. - /// - /// true if the object type matches; otherwise, false - /// if it doesn't match or cannot be determined yet. - /// - /// Ff there is no object with the given name - /// - public bool IsTypeMatch(string name) - { - return IsTypeMatch(name, typeof(T)); - } - - /// - /// Return an unconfigured(!) instance (possibly shared or independent) of the given object name. - /// - /// The name of the object to return. - /// - /// The the object may match. Can be an interface or - /// superclass of the actual class. For example, if the value is the - /// class, this method will succeed whatever the - /// class of the returned instance. - /// - /// - /// The arguments to use if creating a prototype using explicit arguments to - /// a factory method. If there is no factory method and the - /// supplied array is not , then - /// match the argument values by type and call the object's constructor. - /// - /// The unconfigured(!) instance of the object. - /// - /// If there's no such object definition. - /// - /// - /// If the object could not be created. - /// - /// - /// If the object is not of the required type. - /// - /// - /// If the supplied is . - /// - /// - /// - /// This method will only instantiate the requested object. It does NOT inject any dependencies! - /// - public object CreateObject(string name, Type requiredType, object[] arguments) - { - return SafeGetObjectFactory().CreateObject(name, requiredType, arguments); - } - - /// - /// Return an unconfigured(!) instance (possibly shared or independent) of the given object name. - /// - /// The name of the object to return. - /// - /// The the object may match. Can be an interface or - /// superclass of the actual class. For example, if the value is the - /// class, this method will succeed whatever the - /// class of the returned instance. - /// - /// - /// The arguments to use if creating a prototype using explicit arguments to - /// a factory method. If there is no factory method and the - /// supplied array is not , then - /// match the argument values by type and call the object's constructor. - /// - /// The unconfigured(!) instance of the object. - /// - /// If there's no such object definition. - /// - /// - /// If the object could not be created. - /// - /// - /// If the object is not of the required type. - /// - /// - /// If the supplied is . - /// - /// - /// - /// This method will only instantiate the requested object. It does NOT inject any dependencies! - /// - public T CreateObject(string name, object[] arguments) - { - return (T)CreateObject(name, typeof(T), arguments); - } - - /// - /// Return an instance (possibly shared or independent) of the given object name. - /// - /// The name of the object to return. - /// - /// the object may match. Can be an interface or - /// superclass of the actual class. For example, if the value is the - /// class, this method will succeed whatever the - /// class of the returned instance. - /// - /// The instance of the object. - /// - /// If there's no such object definition. - /// - /// - /// If the object could not be created. - /// - /// - /// If the object is not of the required type. - /// - /// - public object GetObject(string name, Type requiredType) - { - return SafeGetObjectFactory().GetObject(name, requiredType); - } - - /// - /// Return an instance (possibly shared or independent) of the given object name. - /// - /// The name of the object to return. - /// The instance of the object. - /// - /// If there's no such object definition. - /// - /// - /// If the object could not be created. - /// - /// - public object GetObject(string name) - { - return SafeGetObjectFactory().GetObject(name); - } - - /// - /// Return an instance (possibly shared or independent) of the given object name. - /// - /// - /// - /// This method allows an object factory to be used as a replacement for the - /// Singleton or Prototype design pattern. - /// - /// - /// Note that callers should retain references to returned objects. There is no - /// guarantee that this method will be implemented to be efficient. For example, - /// it may be synchronized, or may need to run an RDBMS query. - /// - /// - /// Will ask the parent factory if the object cannot be found in this factory - /// instance. - /// - /// - /// The type of the object to return. - /// The name of the object to return. - /// The instance of the object. - /// - /// If there's no such object definition. - /// - /// - /// If the object is not of the required type. - /// - /// - /// If the object could not be created. - /// - public T GetObject(string name) - { - return (T)GetObject(name, typeof(T)); - } - - /// - /// Return an instance (possibly shared or independent) of the given object name. - /// - /// - ///

- /// This method allows an object factory to be used as a replacement for the - /// Singleton or Prototype design pattern. - ///

- ///

- /// Note that callers should retain references to returned objects. There is no - /// guarantee that this method will be implemented to be efficient. For example, - /// it may be synchronized, or may need to run an RDBMS query. - ///

- ///

- /// Will ask the parent factory if the object cannot be found in this factory - /// instance. - ///

- ///
- /// The name of the object to return. - /// - /// The arguments to use if creating a prototype using explicit arguments to - /// a static factory method. If there is no factory method and the - /// arguments are not null, then match the argument values by type and - /// call the object's constructor. - /// - /// The instance of the object. - /// - /// If there's no such object definition. - /// - /// - /// If the object could not be created. - /// - /// - /// If the supplied is . - /// - public object GetObject(string name, object[] arguments) - { - return SafeGetObjectFactory().GetObject(name, arguments); - } - - /// - /// Return an instance (possibly shared or independent) of the given object name. - /// - /// - /// - /// This method allows an object factory to be used as a replacement for the - /// Singleton or Prototype design pattern. - /// - /// - /// Note that callers should retain references to returned objects. There is no - /// guarantee that this method will be implemented to be efficient. For example, - /// it may be synchronized, or may need to run an RDBMS query. - /// - /// - /// Will ask the parent factory if the object cannot be found in this factory - /// instance. - /// - /// - /// The name of the object to return. - /// - /// The arguments to use if creating a prototype using explicit arguments to - /// a static factory method. If there is no factory method and the - /// arguments are not null, then match the argument values by type and - /// call the object's constructor. - /// - /// The instance of the object. - /// - /// If there's no such object definition. - /// - /// - /// If the object could not be created. - /// - /// - /// If the object is not of the required type. - /// - /// - /// If the supplied is . - /// - public T GetObject(string name, object[] arguments) - { - return (T)GetObject(name, typeof(T), arguments); - } - - /// - /// Return an instance (possibly shared or independent) of the given object name. - /// - /// The name of the object to return. - /// - /// The the object may match. Can be an interface or - /// superclass of the actual class. For example, if the value is the - /// class, this method will succeed whatever the - /// class of the returned instance. - /// - /// - /// The arguments to use if creating a prototype using explicit arguments to - /// a factory method. If there is no factory method and the - /// supplied array is not , then - /// match the argument values by type and call the object's constructor. - /// - /// The instance of the object. - /// - /// If there's no such object definition. - /// - /// - /// If the object could not be created. - /// - /// - /// If the object is not of the required type. - /// - /// - /// If the supplied is . - /// - /// - public object GetObject(string name, Type requiredType, object[] arguments) - { - return SafeGetObjectFactory().GetObject(name, requiredType, arguments); - } - - /// - /// Is this object a singleton? - /// - /// The name of the object to query. - /// True if the named object is a singleton. - /// - /// If there's no such object definition. - /// - /// - public bool IsSingleton(string name) - { - return SafeGetObjectFactory().IsSingleton(name); - } - - /// - /// Determines whether the specified object name is prototype. That is, will GetObject - /// always return independent instances? - /// - /// The name of the object to query - /// - /// true if the specified object name will always deliver independent instances; otherwise, false. - /// - /// This method returning false does not clearly indicate a singleton object. - /// It indicated non-independent instances, which may correspond to a scoped object as - /// well. use the IsSingleton property to explicitly check for a shared - /// singleton instance. - /// Translates aliases back to the corresponding canonical object name. Will ask the - /// parent factory if the object can not be found in this factory instance. - /// - /// - /// if there is no object with the given name. - public bool IsPrototype(string name) - { - return SafeGetObjectFactory().IsPrototype(name); - } - - - /// - /// Determines whether the object with the given name matches the specified type. - /// - /// More specifically, check whether a GetObject call for the given name - /// would return an object that is assignable to the specified target type. - /// Translates aliases back to the corresponding canonical bean name. - /// Will ask the parent factory if the bean cannot be found in this factory instance. - /// - /// The name of the object to query. - /// Type of the target to match against. - /// - /// true if the object type matches; otherwise, false - /// if it doesn't match or cannot be determined yet. - /// - /// Ff there is no object with the given name - /// - public bool IsTypeMatch(string name, Type targetType) - { - return SafeGetObjectFactory().IsTypeMatch(name, targetType); - } - - /// - /// Determine the of the object with the - /// given name. - /// - /// The name of the object to query. - /// - /// The of the object, or - /// if not determinable. - /// - /// - public Type GetType(string name) - { - return SafeGetObjectFactory().GetType(name); - } - - /// - /// Injects dependencies into the supplied instance - /// using the named object definition. - /// - /// - /// The object instance that is to be so configured. - /// - /// - /// The name of the object definition expressing the dependencies that are to - /// be injected into the supplied instance. - /// - /// - public object ConfigureObject(object target, string name) - { - return SafeGetObjectFactory().ConfigureObject(target, name); - } - - /// - /// Injects dependencies into the supplied instance - /// using the supplied . - /// - /// - /// The object instance that is to be so configured. - /// - /// - /// The name of the object definition expressing the dependencies that are to - /// be injected into the supplied instance. - /// - /// - /// An object definition that should be used to configure object. - /// - /// - public object ConfigureObject(object target, string name, IObjectDefinition definition) - { - return SafeGetObjectFactory().ConfigureObject(target, name, definition); - } - - /// - /// Return the parent object factory, or if there is none. - /// - /// - /// The parent object factory, or if there is none. - /// - /// - public IObjectFactory ParentObjectFactory => _parentApplicationContext; - - /// - /// Determines whether the local object factory contains a bean of the given name, - /// ignoring object defined in ancestor contexts. - /// This is an alternative to ContainsObject, ignoring an object - /// of the given name from an ancestor object factory. - /// - /// - /// - /// - /// The name of the object to query. - /// - /// true if objects with the specified name is defined in the local factory; otherwise, false. - /// - public bool ContainsLocalObject(string name) - { - return SafeGetObjectFactory().ContainsLocalObject(name); - } - - /// - /// Determine whether the given object name is already in use within this context, - /// i.e. whether there is a local object. May be override by subclasses, the default - /// implementation simply returns - /// - public virtual bool IsObjectNameInUse(string objectName) - { - return ContainsLocalObject(objectName); - } - - /// - /// Register a new object definition with this registry. - /// Must support - /// - /// and . - /// - /// The name of the object instance to register. - /// The definition of the object instance to register. - /// - ///

- /// Must support - /// and - /// . - ///

- ///
- /// - /// If the object definition is invalid. - /// - public virtual void RegisterObjectDefinition(string name, IObjectDefinition definition) - { - SafeGetObjectFactory().RegisterObjectDefinition(name, definition); - } - - /// - /// Given a object name, create an alias. We typically use this method to - /// support names that are illegal within XML ids (used for object names). - /// - /// The name of the object. - /// The alias that will behave the same as the object name. - /// - /// If there is no object with the given name. - /// - /// - /// If the alias is already in use. - /// - public virtual void RegisterAlias(string name, string theAlias) - { - SafeGetObjectFactory().RegisterAlias(name, theAlias); - } - - /// - /// Resolve the message identified by the supplied - /// . - /// - /// The name of the message to resolve. - /// - /// The that represents - /// the culture for which the resource is localized. - /// - /// - /// The array of arguments that will be filled in for parameters within - /// the message, or if there are no parameters - /// within the message. Parameters within a message should be - /// referenced using the same syntax as the format string for the - /// method. - /// - /// - /// The resolved message if the lookup was successful (see above for - /// the return value in the case of an unsuccessful lookup). - /// - /// - /// If no message could be resolved. - /// - /// - /// If the supplied is . - /// - /// - public string GetMessage( - string name, CultureInfo culture, params object[] arguments) - { - return MessageSource.GetMessage(name, culture, arguments); - } - - /// - /// Resolve the message identified by the supplied - /// . - /// - /// The name of the message to resolve. - /// The default message. - /// - /// The that represents - /// the culture for which the resource is localized. - /// - /// - /// The array of arguments that will be filled in for parameters within - /// the message, or if there are no parameters - /// within the message. Parameters within a message should be - /// referenced using the same syntax as the format string for the - /// method. - /// - /// - /// The resolved message if the lookup was successful (see above for - /// the return value in the case of an unsuccessful lookup). - /// - /// - /// If no message could be resolved. - /// - /// - /// If the supplied is . - /// - /// - public string GetMessage(string name, string defaultMessage, CultureInfo culture, params object[] arguments) - { - return MessageSource.GetMessage(name, defaultMessage, culture, arguments); - } - - /// - /// Resolve the message identified by the supplied - /// . - /// - /// The name of the message to resolve. - /// - /// The resolved message if the lookup was successful. - /// - /// - /// If no message could be resolved. - /// - /// - public string GetMessage(string name) - { - return MessageSource.GetMessage(name); - } - - /// - /// Resolve the message identified by the supplied - /// . - /// - /// The name of the message to resolve. - /// - /// The array of arguments that will be filled in for parameters within - /// the message, or if there are no parameters - /// within the message. Parameters within a message should be - /// referenced using the same syntax as the format string for the - /// method. - /// - /// - /// The resolved message if the lookup was successful. - /// - /// - /// If no message could be resolved. - /// - /// - /// If the supplied is . - /// - /// - public string GetMessage(string name, params object[] arguments) - { - return MessageSource.GetMessage(name, arguments); - } - - /// - /// Resolve the message identified by the supplied - /// . - /// - /// The name of the message to resolve. - /// - /// The that represents - /// the culture for which the resource is localized. - /// - /// - /// The resolved message if the lookup was successful (see above for - /// the return value in the case of an unsuccessful lookup). - /// - /// - /// If no message could be resolved. - /// - /// - /// If the supplied is . - /// - /// - public string GetMessage(string name, CultureInfo culture) - { - return MessageSource.GetMessage(name, culture); - } - - /// - /// Resolve the message using all of the attributes contained within - /// the supplied - /// argument. - /// - /// - /// The value object storing those attributes that are required to - /// properly resolve a message. - /// - /// - /// The that represents - /// the culture for which the resource is localized. - /// - /// - /// The resolved message if the lookup was successful (see above for - /// the return value in the case of an unsuccessful lookup). - /// - /// - /// If the message could not be resolved. - /// - /// - public string GetMessage(IMessageSourceResolvable resolvable, CultureInfo culture) - { - return MessageSource.GetMessage(resolvable, culture); - } - - /// - /// Gets a localized resource object identified by the supplied - /// . - /// - /// - /// The name of the resource object to resolve. - /// - /// - /// The with which the - /// resource is associated. - /// - /// - /// The resolved object, or if not found. - /// - /// - object IMessageSource.GetResourceObject(string name, CultureInfo culture) - { - return GetResourceObject(name, culture); - } - - /// - /// Gets a localized resource object identified by the supplied - /// . - /// - /// - /// The name of the resource object to resolve. - /// - /// - /// The resolved object, or if not found. - /// - /// - object IMessageSource.GetResourceObject(string name) - { - return GetResourceObject(name); - } - - /// - /// Gets a localized resource object identified by the supplied - /// . - /// - /// - /// The name of the resource object to resolve. - /// - /// - /// The with which the - /// resource is associated. - /// - /// - /// The resolved object, or if not found. - /// - /// - public object GetResourceObject(string name, CultureInfo culture) - { - return MessageSource.GetResourceObject(name, culture); - } - - /// - /// Gets a localized resource object identified by the supplied - /// . - /// - /// - /// The name of the resource object to resolve. - /// - /// - /// The resolved object, or if not found. - /// - /// - public object GetResourceObject(string name) - { - return MessageSource.GetResourceObject(name); - } - - /// - /// Applies resources to object properties. - /// - /// - /// An object that contains the property values to be applied. - /// - /// - /// The base name of the object to use for key lookup. - /// - /// - /// The with which the - /// resource is associated. - /// - /// - public void ApplyResources(object value, string objectName, CultureInfo culture) - { - MessageSource.ApplyResources(value, objectName, culture); - } - - /// - /// Publishes all events of the source object. - /// - /// - /// The source object containing events to publish. - /// - /// - public void PublishEvents(object sourceObject) - { - _eventRegistry.PublishEvents(sourceObject); - } - - /// - /// Subscribes to all events published, if the subscriber - /// implements compatible handler methods. - /// - /// The subscriber to use. - /// - public void Subscribe(object subscriber) - { - _eventRegistry.Subscribe(subscriber); - } - - /// - /// Subscribes to published events of a all objects of a given - /// , if the subscriber implements - /// compatible handler methods. - /// - /// The subscriber to use. - /// - /// The target to subscribe to. - /// - /// - public void Subscribe(object subscriber, Type targetSourceType) - { - _eventRegistry.Subscribe(subscriber, targetSourceType); - } - - - /// - /// Unsubscribes to all events published, if the subscriber - /// implmenets compatible handler methods. - /// - /// The subscriber to use - public void Unsubscribe(object subscriber) - { - _eventRegistry.Unsubscribe(subscriber); - } - - /// - /// Unsubscribes to the published events of all objects of a given - /// , if the subscriber implements - /// compatible handler methods. - /// - /// The subscriber to use. - /// - /// The target to unsubscribe from - /// - public void Unsubscribe(object subscriber, Type targetSourceType) - { - _eventRegistry.Unsubscribe(subscriber, targetSourceType); - } - - /// - /// Publishes an application context event. - /// - /// - ///

- /// - ///

- ///
- /// - /// The source of the event. May be . - /// - /// - /// The event that is to be raised. - /// - /// - public void PublishEvent(object sender, ApplicationEventArgs e) - { - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug(string.Format( - CultureInfo.InvariantCulture, - "Publishing event in context [{0}] : {1}", - Name, e)); - } - - OnContextEvent(sender, e); - - if (ParentContext != null) - { - ParentContext.PublishEvent(sender, e); - } - } - - private sealed class ObjectPostProcessorChecker : IObjectPostProcessor, IOrdered - { - private static readonly ILogger log = LogManager.GetLogger(); - private int _objectPostProcessorTargetCount; - private IConfigurableListableObjectFactory _objectFactory; - - public void Reset(IConfigurableListableObjectFactory objectFactory, int objectPostProcessorTargetCount) - { - _objectFactory = objectFactory; - _objectPostProcessorTargetCount = objectPostProcessorTargetCount; - } - - public object PostProcessBeforeInitialization(object obj, string name) - { - return obj; - } - - public object PostProcessAfterInitialization(object obj, string objectName) - { - if (_objectFactory.ObjectPostProcessorCount < _objectPostProcessorTargetCount) - { - if (log.IsEnabled(LogLevel.Information)) - { - log.LogInformation(string.Format( - "Object '{0}' is not eligible for being processed by all " + - "IObjectPostProcessors (for example: not eligible for auto-proxying).", objectName)); - } - } - return obj; - } - - public int Order => Int32.MinValue; + return true; } } -} + + /// + /// Gets a dictionary of all singleton beans that implement the + /// ILifecycle interface in this context. + /// + /// A dictionary of ILifecycle objects with object name as key. + private IDictionary LifeCycleObjects + { + get + { + IConfigurableListableObjectFactory objectFactory = ObjectFactory; + IList objectNames = objectFactory.SingletonNames; + IDictionary lifeCycleObjects = new Dictionary(); + foreach (string objectName in objectNames) + { + object obj = objectFactory.GetSingleton(objectName); + if (obj is ILifecycle) + { + lifeCycleObjects[objectName] = (ILifecycle) obj; + } + } + + return lifeCycleObjects; + } + } + + /// + /// Raised in response to an implementation-dependant application + /// context event. + /// + public event ApplicationEventHandler ContextEvent; + + /// + /// The date and time this context was first loaded. + /// + /// + /// The representing when this context + /// was first loaded. + /// + public DateTime StartupDate => _startupDate; + + /// + /// A name for this context. + /// + /// + /// A name for this context. + /// + public string Name + { + get => _name; + set => _name = value; + } + + /// + /// Return the names of objects matching the given + /// (including subclasses), judging from the object definitions. + /// + /// + /// The (class or interface) to match, or + /// for all object names. + /// + /// + /// The names of all objects defined in this factory, or an empty array if none + /// are defined. + /// + /// + public IReadOnlyList GetObjectNamesForType(Type type) + { + return SafeGetObjectFactory().GetObjectNamesForType(type); + } + + /// + /// Return the names of objects matching the given + /// (including subclasses), judging from the object definitions. + /// + /// + ///

+ /// Does consider objects created by s, + /// or rather it considers the type of objects created by + /// (which means that + /// s will be instantiated). + ///

+ ///

+ /// Does not consider any hierarchy this factory may participate in. + ///

+ ///
+ /// + /// The (class or interface) to match, or + /// for all object names. + /// + /// + /// The names of all objects defined in this factory, or an empty array if none + /// are defined. + /// + public IReadOnlyList GetObjectNames() + { + return GetObjectNamesForType(typeof(T)); + } + + /// + /// Return the names of objects matching the given + /// (including subclasses), judging from the object definitions. + /// + /// + /// The (class or interface) to match, or + /// for all object names. + /// + /// + /// Whether to include prototype objects too or just singletons (also applies to + /// s). + /// + /// + /// Whether to include s too + /// or just normal objects. + /// + /// + /// The names of all objects defined in this factory, or an empty array if none + /// are defined. + /// + /// + public IReadOnlyList GetObjectNamesForType(Type type, bool includePrototypes, bool includeFactoryObjects) + { + return SafeGetObjectFactory().GetObjectNamesForType(type, includePrototypes, includeFactoryObjects); + } + + /// + /// Return the names of objects matching the given + /// (including subclasses), judging from the object definitions. + /// + /// + ///

+ /// Does consider objects created by s, + /// or rather it considers the type of objects created by + /// (which means that + /// s will be instantiated). + ///

+ ///

+ /// Does not consider any hierarchy this factory may participate in. + /// Use + /// to include beans in ancestor factories too. + /// <p>Note: Does <i>not</i> ignore singleton objects that have been registered + /// by other means than bean definitions. + ///

+ ///
+ /// + /// The (class or interface) to match, or + /// for all object names. + /// + /// + /// Whether to include prototype objects too or just singletons (also applies to + /// s). + /// + /// + /// Whether to include s too + /// or just normal objects. + /// + /// + /// The names of all objects defined in this factory, or an empty array if none + /// are defined. + /// + public IReadOnlyList GetObjectNames(bool includePrototypes, bool includeFactoryObjects) + { + return GetObjectNamesForType(typeof(T), includePrototypes, includeFactoryObjects); + } + + /// + /// Return the names of all objects defined in this factory. + /// + /// + /// The names of all objects defined in this factory, or an empty array if none + /// are defined. + /// + /// + public IReadOnlyList GetObjectDefinitionNames() + { + return GetObjectDefinitionNames(false); + } + + /// + /// Return the names of all objects defined in this factory, if includeAncestorsis true + /// includes all parent factories. + /// + /// to include parent factories into result + /// + /// The names of all objects defined in this factory, if includeAncestors is true includes all + /// objects defined in parent factories, or an empty array if none are defined. + /// + public IReadOnlyList GetObjectDefinitionNames(bool includeAncestors) + { + return SafeGetObjectFactory().GetObjectDefinitionNames(includeAncestors); + } + + /// + /// Return the registered + /// for the + /// given object, allowing access to its property values and constructor + /// argument values. + /// + /// The name of the object. + /// + /// The registered + /// . + /// + /// + /// If there is no object with the given name. + /// + /// + /// In the case of errors. + /// + public virtual IObjectDefinition GetObjectDefinition(string name) + { + return SafeGetObjectFactory().GetObjectDefinition(name); + } + + /// + /// Return the registered + /// for the + /// given object, allowing access to its property values and constructor + /// argument values. + /// + /// The name of the object. + /// Whether to search parent object factories. + /// + /// The registered + /// . + /// + /// + /// If there is no object with the given name. + /// + /// + /// In the case of errors. + /// + public IObjectDefinition GetObjectDefinition(string name, bool includeAncestors) + { + return SafeGetObjectFactory().GetObjectDefinition(name, includeAncestors); + } + + /// + /// Return the object instances that match the given object + /// (including subclasses), judging from either object + /// definitions or the value of + /// in the case of + /// s. + /// + /// + /// The (class or interface) to match. + /// + /// + /// A of the matching objects, + /// containing the object names as keys and the corresponding object instances + /// as values. + /// + /// + /// If the objects could not be created. + /// + /// + public IReadOnlyDictionary GetObjectsOfType(Type type) + { + return GetObjectsOfType(type, true, true); + } + + /// + /// Return the object instances that match the given object + /// (including subclasses), judging from either object + /// definitions or the value of + /// in the case of + /// s. + /// + /// + ///

+ /// This version of the + /// method matches all kinds of object definitions, be they singletons, prototypes, or + /// s. Typically, the results + /// of this method call will be the same as a call to + /// IListableObjectFactory.GetObjectsOfType(type,true,true) . + ///

+ ///
+ /// + /// The (class or interface) to match. + /// + /// + /// A of the matching objects, + /// containing the object names as keys and the corresponding object instances + /// as values. + /// + /// + /// If the objects could not be created. + /// + public IReadOnlyDictionary GetObjects() + { + return SafeGetObjectFactory().GetObjects(true, true); + } + + /// + /// Return the object instances that match the given object + /// (including subclasses), judging from either object + /// definitions or the value of + /// in the case of + /// s. + /// + /// + /// The (class or interface) to match. + /// + /// + /// Whether to include prototype objects too or just singletons (also applies to + /// s). + /// + /// + /// Whether to include s too + /// or just normal objects. + /// + /// + /// A of the matching objects, + /// containing the object names as keys and the corresponding object instances + /// as values. + /// + /// + /// If the objects could not be created. + /// + /// + public IReadOnlyDictionary GetObjectsOfType( + Type type, bool includePrototypes, bool includeFactoryObjects) + { + return SafeGetObjectFactory().GetObjectsOfType(type, includePrototypes, includeFactoryObjects); + } + + /// + /// Return the object instances that match the given object + /// (including subclasses), judging from either object + /// definitions or the value of + /// in the case of + /// s. + /// + /// + /// The (class or interface) to match. + /// + /// + /// Whether to include prototype objects too or just singletons (also applies to + /// s). + /// + /// + /// Whether to include s too + /// or just normal objects. + /// + /// + /// A of the matching objects, + /// containing the object names as keys and the corresponding object instances + /// as values. + /// + /// + /// If the objects could not be created. + /// + public IReadOnlyDictionary GetObjects(bool includePrototypes, bool includeFactoryObjects) + { + return SafeGetObjectFactory().GetObjects(includePrototypes, includeFactoryObjects); + } + + /// + /// Return an instance (possibly shared or independent) of the given object name. + /// + /// + /// + /// This method allows an object factory to be used as a replacement for the + /// Singleton or Prototype design pattern. + /// + /// + /// Note that callers should retain references to returned objects. There is no + /// guarantee that this method will be implemented to be efficient. For example, + /// it may be synchronized, or may need to run an RDBMS query. + /// + /// + /// Will ask the parent factory if the object cannot be found in this factory + /// instance. + /// + /// + /// The type of the object to return. + /// The instance of the object. + /// + /// If there's no such object definition. + /// + /// + /// If there is more than a single object of the requested type defined in the factory. + /// + /// + /// If the object could not be created. + /// + public T GetObject() + { + var objectNamesForType = GetObjectNamesForType(typeof(T)); + if ((objectNamesForType == null) || (objectNamesForType.Count == 0)) + { + throw new NoSuchObjectDefinitionException(typeof(T).FullName, "Requested Type not Defined in the Context."); + } + + if (objectNamesForType.Count > 1) + { + throw new ObjectDefinitionStoreException( + $"More than one definition for {typeof(T).FullName} found in the Context."); + } + + return (T) GetObject(objectNamesForType[0]); + } + + /// + /// Return the number of objects defined in the factory. + /// + /// + /// The number of objects defined in the factory. + /// + /// + public int ObjectDefinitionCount => SafeGetObjectFactory().ObjectDefinitionCount; + + /// + /// Check if this object factory contains an object definition with the given name. + /// + /// The name of the object to look for. + /// + /// True if this object factory contains an object definition with the given name. + /// + /// + public bool ContainsObjectDefinition(string name) + { + return SafeGetObjectFactory().ContainsObjectDefinition(name); + } + + /// + /// Return an instance (possibly shared or independent) of the given object name. + /// + /// The name of the object to return. + /// The instance of the object. + /// + /// If there's no such object definition. + /// + /// + /// If the object could not be created. + /// + /// + public object this[string name] => SafeGetObjectFactory().GetObject(name); + + /// + /// Does this object factory contain an object with the given name? + /// + /// The name of the object to query. + /// + /// if an object with the given name is defined. + /// + /// + public bool ContainsObject(string name) + { + return SafeGetObjectFactory().ContainsObject(name); + } + + /// + /// Return the aliases for the given object name, if defined. + /// + /// The object name to check for aliases. + /// The aliases, or an empty array if none. + /// + /// If there's no such object definition. + /// + /// + public IReadOnlyList GetAliases(string name) + { + return SafeGetObjectFactory().GetAliases(name); + } + + /// + /// Determines whether the object with the given name matches the specified type. + /// + /// More specifically, check whether a GetObject call for the given name + /// would return an object that is assignable to the specified target type. + /// Translates aliases back to the corresponding canonical bean name. + /// Will ask the parent factory if the bean cannot be found in this factory instance. + /// + /// The name of the object to query. + /// Type of the target to match against. + /// + /// true if the object type matches; otherwise, false + /// if it doesn't match or cannot be determined yet. + /// + /// Ff there is no object with the given name + /// + public bool IsTypeMatch(string name) + { + return IsTypeMatch(name, typeof(T)); + } + + /// + /// Return an unconfigured(!) instance (possibly shared or independent) of the given object name. + /// + /// The name of the object to return. + /// + /// The the object may match. Can be an interface or + /// superclass of the actual class. For example, if the value is the + /// class, this method will succeed whatever the + /// class of the returned instance. + /// + /// + /// The arguments to use if creating a prototype using explicit arguments to + /// a factory method. If there is no factory method and the + /// supplied array is not , then + /// match the argument values by type and call the object's constructor. + /// + /// The unconfigured(!) instance of the object. + /// + /// If there's no such object definition. + /// + /// + /// If the object could not be created. + /// + /// + /// If the object is not of the required type. + /// + /// + /// If the supplied is . + /// + /// + /// + /// This method will only instantiate the requested object. It does NOT inject any dependencies! + /// + public object CreateObject(string name, Type requiredType, object[] arguments) + { + return SafeGetObjectFactory().CreateObject(name, requiredType, arguments); + } + + /// + /// Return an unconfigured(!) instance (possibly shared or independent) of the given object name. + /// + /// The name of the object to return. + /// + /// The the object may match. Can be an interface or + /// superclass of the actual class. For example, if the value is the + /// class, this method will succeed whatever the + /// class of the returned instance. + /// + /// + /// The arguments to use if creating a prototype using explicit arguments to + /// a factory method. If there is no factory method and the + /// supplied array is not , then + /// match the argument values by type and call the object's constructor. + /// + /// The unconfigured(!) instance of the object. + /// + /// If there's no such object definition. + /// + /// + /// If the object could not be created. + /// + /// + /// If the object is not of the required type. + /// + /// + /// If the supplied is . + /// + /// + /// + /// This method will only instantiate the requested object. It does NOT inject any dependencies! + /// + public T CreateObject(string name, object[] arguments) + { + return (T) CreateObject(name, typeof(T), arguments); + } + + /// + /// Return an instance (possibly shared or independent) of the given object name. + /// + /// The name of the object to return. + /// + /// the object may match. Can be an interface or + /// superclass of the actual class. For example, if the value is the + /// class, this method will succeed whatever the + /// class of the returned instance. + /// + /// The instance of the object. + /// + /// If there's no such object definition. + /// + /// + /// If the object could not be created. + /// + /// + /// If the object is not of the required type. + /// + /// + public object GetObject(string name, Type requiredType) + { + return SafeGetObjectFactory().GetObject(name, requiredType); + } + + /// + /// Return an instance (possibly shared or independent) of the given object name. + /// + /// The name of the object to return. + /// The instance of the object. + /// + /// If there's no such object definition. + /// + /// + /// If the object could not be created. + /// + /// + public object GetObject(string name) + { + return SafeGetObjectFactory().GetObject(name); + } + + /// + /// Return an instance (possibly shared or independent) of the given object name. + /// + /// + /// + /// This method allows an object factory to be used as a replacement for the + /// Singleton or Prototype design pattern. + /// + /// + /// Note that callers should retain references to returned objects. There is no + /// guarantee that this method will be implemented to be efficient. For example, + /// it may be synchronized, or may need to run an RDBMS query. + /// + /// + /// Will ask the parent factory if the object cannot be found in this factory + /// instance. + /// + /// + /// The type of the object to return. + /// The name of the object to return. + /// The instance of the object. + /// + /// If there's no such object definition. + /// + /// + /// If the object is not of the required type. + /// + /// + /// If the object could not be created. + /// + public T GetObject(string name) + { + return (T) GetObject(name, typeof(T)); + } + + /// + /// Return an instance (possibly shared or independent) of the given object name. + /// + /// + ///

+ /// This method allows an object factory to be used as a replacement for the + /// Singleton or Prototype design pattern. + ///

+ ///

+ /// Note that callers should retain references to returned objects. There is no + /// guarantee that this method will be implemented to be efficient. For example, + /// it may be synchronized, or may need to run an RDBMS query. + ///

+ ///

+ /// Will ask the parent factory if the object cannot be found in this factory + /// instance. + ///

+ ///
+ /// The name of the object to return. + /// + /// The arguments to use if creating a prototype using explicit arguments to + /// a static factory method. If there is no factory method and the + /// arguments are not null, then match the argument values by type and + /// call the object's constructor. + /// + /// The instance of the object. + /// + /// If there's no such object definition. + /// + /// + /// If the object could not be created. + /// + /// + /// If the supplied is . + /// + public object GetObject(string name, object[] arguments) + { + return SafeGetObjectFactory().GetObject(name, arguments); + } + + /// + /// Return an instance (possibly shared or independent) of the given object name. + /// + /// + /// + /// This method allows an object factory to be used as a replacement for the + /// Singleton or Prototype design pattern. + /// + /// + /// Note that callers should retain references to returned objects. There is no + /// guarantee that this method will be implemented to be efficient. For example, + /// it may be synchronized, or may need to run an RDBMS query. + /// + /// + /// Will ask the parent factory if the object cannot be found in this factory + /// instance. + /// + /// + /// The name of the object to return. + /// + /// The arguments to use if creating a prototype using explicit arguments to + /// a static factory method. If there is no factory method and the + /// arguments are not null, then match the argument values by type and + /// call the object's constructor. + /// + /// The instance of the object. + /// + /// If there's no such object definition. + /// + /// + /// If the object could not be created. + /// + /// + /// If the object is not of the required type. + /// + /// + /// If the supplied is . + /// + public T GetObject(string name, object[] arguments) + { + return (T) GetObject(name, typeof(T), arguments); + } + + /// + /// Return an instance (possibly shared or independent) of the given object name. + /// + /// The name of the object to return. + /// + /// The the object may match. Can be an interface or + /// superclass of the actual class. For example, if the value is the + /// class, this method will succeed whatever the + /// class of the returned instance. + /// + /// + /// The arguments to use if creating a prototype using explicit arguments to + /// a factory method. If there is no factory method and the + /// supplied array is not , then + /// match the argument values by type and call the object's constructor. + /// + /// The instance of the object. + /// + /// If there's no such object definition. + /// + /// + /// If the object could not be created. + /// + /// + /// If the object is not of the required type. + /// + /// + /// If the supplied is . + /// + /// + public object GetObject(string name, Type requiredType, object[] arguments) + { + return SafeGetObjectFactory().GetObject(name, requiredType, arguments); + } + + /// + /// Is this object a singleton? + /// + /// The name of the object to query. + /// True if the named object is a singleton. + /// + /// If there's no such object definition. + /// + /// + public bool IsSingleton(string name) + { + return SafeGetObjectFactory().IsSingleton(name); + } + + /// + /// Determines whether the specified object name is prototype. That is, will GetObject + /// always return independent instances? + /// + /// The name of the object to query + /// + /// true if the specified object name will always deliver independent instances; otherwise, false. + /// + /// This method returning false does not clearly indicate a singleton object. + /// It indicated non-independent instances, which may correspond to a scoped object as + /// well. use the IsSingleton property to explicitly check for a shared + /// singleton instance. + /// Translates aliases back to the corresponding canonical object name. Will ask the + /// parent factory if the object can not be found in this factory instance. + /// + /// + /// if there is no object with the given name. + public bool IsPrototype(string name) + { + return SafeGetObjectFactory().IsPrototype(name); + } + + /// + /// Determines whether the object with the given name matches the specified type. + /// + /// More specifically, check whether a GetObject call for the given name + /// would return an object that is assignable to the specified target type. + /// Translates aliases back to the corresponding canonical bean name. + /// Will ask the parent factory if the bean cannot be found in this factory instance. + /// + /// The name of the object to query. + /// Type of the target to match against. + /// + /// true if the object type matches; otherwise, false + /// if it doesn't match or cannot be determined yet. + /// + /// Ff there is no object with the given name + /// + public bool IsTypeMatch(string name, Type targetType) + { + return SafeGetObjectFactory().IsTypeMatch(name, targetType); + } + + /// + /// Determine the of the object with the + /// given name. + /// + /// The name of the object to query. + /// + /// The of the object, or + /// if not determinable. + /// + /// + public Type GetType(string name) + { + return SafeGetObjectFactory().GetType(name); + } + + /// + /// Injects dependencies into the supplied instance + /// using the named object definition. + /// + /// + /// The object instance that is to be so configured. + /// + /// + /// The name of the object definition expressing the dependencies that are to + /// be injected into the supplied instance. + /// + /// + public object ConfigureObject(object target, string name) + { + return SafeGetObjectFactory().ConfigureObject(target, name); + } + + /// + /// Injects dependencies into the supplied instance + /// using the supplied . + /// + /// + /// The object instance that is to be so configured. + /// + /// + /// The name of the object definition expressing the dependencies that are to + /// be injected into the supplied instance. + /// + /// + /// An object definition that should be used to configure object. + /// + /// + public object ConfigureObject(object target, string name, IObjectDefinition definition) + { + return SafeGetObjectFactory().ConfigureObject(target, name, definition); + } + + /// + /// Return the parent object factory, or if there is none. + /// + /// + /// The parent object factory, or if there is none. + /// + /// + public IObjectFactory ParentObjectFactory => _parentApplicationContext; + + /// + /// Determines whether the local object factory contains a bean of the given name, + /// ignoring object defined in ancestor contexts. + /// This is an alternative to ContainsObject, ignoring an object + /// of the given name from an ancestor object factory. + /// + /// + /// + /// + /// The name of the object to query. + /// + /// true if objects with the specified name is defined in the local factory; otherwise, false. + /// + public bool ContainsLocalObject(string name) + { + return SafeGetObjectFactory().ContainsLocalObject(name); + } + + /// + /// Determine whether the given object name is already in use within this context, + /// i.e. whether there is a local object. May be override by subclasses, the default + /// implementation simply returns + /// + public virtual bool IsObjectNameInUse(string objectName) + { + return ContainsLocalObject(objectName); + } + + /// + /// Register a new object definition with this registry. + /// Must support + /// + /// and . + /// + /// The name of the object instance to register. + /// The definition of the object instance to register. + /// + ///

+ /// Must support + /// and + /// . + ///

+ ///
+ /// + /// If the object definition is invalid. + /// + public virtual void RegisterObjectDefinition(string name, IObjectDefinition definition) + { + SafeGetObjectFactory().RegisterObjectDefinition(name, definition); + } + + /// + /// Given a object name, create an alias. We typically use this method to + /// support names that are illegal within XML ids (used for object names). + /// + /// The name of the object. + /// The alias that will behave the same as the object name. + /// + /// If there is no object with the given name. + /// + /// + /// If the alias is already in use. + /// + public virtual void RegisterAlias(string name, string theAlias) + { + SafeGetObjectFactory().RegisterAlias(name, theAlias); + } + + /// + /// Resolve the message identified by the supplied + /// . + /// + /// The name of the message to resolve. + /// + /// The that represents + /// the culture for which the resource is localized. + /// + /// + /// The array of arguments that will be filled in for parameters within + /// the message, or if there are no parameters + /// within the message. Parameters within a message should be + /// referenced using the same syntax as the format string for the + /// method. + /// + /// + /// The resolved message if the lookup was successful (see above for + /// the return value in the case of an unsuccessful lookup). + /// + /// + /// If no message could be resolved. + /// + /// + /// If the supplied is . + /// + /// + public string GetMessage( + string name, CultureInfo culture, params object[] arguments) + { + return MessageSource.GetMessage(name, culture, arguments); + } + + /// + /// Resolve the message identified by the supplied + /// . + /// + /// The name of the message to resolve. + /// The default message. + /// + /// The that represents + /// the culture for which the resource is localized. + /// + /// + /// The array of arguments that will be filled in for parameters within + /// the message, or if there are no parameters + /// within the message. Parameters within a message should be + /// referenced using the same syntax as the format string for the + /// method. + /// + /// + /// The resolved message if the lookup was successful (see above for + /// the return value in the case of an unsuccessful lookup). + /// + /// + /// If no message could be resolved. + /// + /// + /// If the supplied is . + /// + /// + public string GetMessage(string name, string defaultMessage, CultureInfo culture, params object[] arguments) + { + return MessageSource.GetMessage(name, defaultMessage, culture, arguments); + } + + /// + /// Resolve the message identified by the supplied + /// . + /// + /// The name of the message to resolve. + /// + /// The resolved message if the lookup was successful. + /// + /// + /// If no message could be resolved. + /// + /// + public string GetMessage(string name) + { + return MessageSource.GetMessage(name); + } + + /// + /// Resolve the message identified by the supplied + /// . + /// + /// The name of the message to resolve. + /// + /// The array of arguments that will be filled in for parameters within + /// the message, or if there are no parameters + /// within the message. Parameters within a message should be + /// referenced using the same syntax as the format string for the + /// method. + /// + /// + /// The resolved message if the lookup was successful. + /// + /// + /// If no message could be resolved. + /// + /// + /// If the supplied is . + /// + /// + public string GetMessage(string name, params object[] arguments) + { + return MessageSource.GetMessage(name, arguments); + } + + /// + /// Resolve the message identified by the supplied + /// . + /// + /// The name of the message to resolve. + /// + /// The that represents + /// the culture for which the resource is localized. + /// + /// + /// The resolved message if the lookup was successful (see above for + /// the return value in the case of an unsuccessful lookup). + /// + /// + /// If no message could be resolved. + /// + /// + /// If the supplied is . + /// + /// + public string GetMessage(string name, CultureInfo culture) + { + return MessageSource.GetMessage(name, culture); + } + + /// + /// Resolve the message using all of the attributes contained within + /// the supplied + /// argument. + /// + /// + /// The value object storing those attributes that are required to + /// properly resolve a message. + /// + /// + /// The that represents + /// the culture for which the resource is localized. + /// + /// + /// The resolved message if the lookup was successful (see above for + /// the return value in the case of an unsuccessful lookup). + /// + /// + /// If the message could not be resolved. + /// + /// + public string GetMessage(IMessageSourceResolvable resolvable, CultureInfo culture) + { + return MessageSource.GetMessage(resolvable, culture); + } + + /// + /// Gets a localized resource object identified by the supplied + /// . + /// + /// + /// The name of the resource object to resolve. + /// + /// + /// The with which the + /// resource is associated. + /// + /// + /// The resolved object, or if not found. + /// + /// + object IMessageSource.GetResourceObject(string name, CultureInfo culture) + { + return GetResourceObject(name, culture); + } + + /// + /// Gets a localized resource object identified by the supplied + /// . + /// + /// + /// The name of the resource object to resolve. + /// + /// + /// The resolved object, or if not found. + /// + /// + object IMessageSource.GetResourceObject(string name) + { + return GetResourceObject(name); + } + + /// + /// Gets a localized resource object identified by the supplied + /// . + /// + /// + /// The name of the resource object to resolve. + /// + /// + /// The with which the + /// resource is associated. + /// + /// + /// The resolved object, or if not found. + /// + /// + public object GetResourceObject(string name, CultureInfo culture) + { + return MessageSource.GetResourceObject(name, culture); + } + + /// + /// Gets a localized resource object identified by the supplied + /// . + /// + /// + /// The name of the resource object to resolve. + /// + /// + /// The resolved object, or if not found. + /// + /// + public object GetResourceObject(string name) + { + return MessageSource.GetResourceObject(name); + } + + /// + /// Applies resources to object properties. + /// + /// + /// An object that contains the property values to be applied. + /// + /// + /// The base name of the object to use for key lookup. + /// + /// + /// The with which the + /// resource is associated. + /// + /// + public void ApplyResources(object value, string objectName, CultureInfo culture) + { + MessageSource.ApplyResources(value, objectName, culture); + } + + /// + /// Publishes all events of the source object. + /// + /// + /// The source object containing events to publish. + /// + /// + public void PublishEvents(object sourceObject) + { + _eventRegistry.PublishEvents(sourceObject); + } + + /// + /// Subscribes to all events published, if the subscriber + /// implements compatible handler methods. + /// + /// The subscriber to use. + /// + public void Subscribe(object subscriber) + { + _eventRegistry.Subscribe(subscriber); + } + + /// + /// Subscribes to published events of a all objects of a given + /// , if the subscriber implements + /// compatible handler methods. + /// + /// The subscriber to use. + /// + /// The target to subscribe to. + /// + /// + public void Subscribe(object subscriber, Type targetSourceType) + { + _eventRegistry.Subscribe(subscriber, targetSourceType); + } + + /// + /// Unsubscribes to all events published, if the subscriber + /// implmenets compatible handler methods. + /// + /// The subscriber to use + public void Unsubscribe(object subscriber) + { + _eventRegistry.Unsubscribe(subscriber); + } + + /// + /// Unsubscribes to the published events of all objects of a given + /// , if the subscriber implements + /// compatible handler methods. + /// + /// The subscriber to use. + /// + /// The target to unsubscribe from + /// + public void Unsubscribe(object subscriber, Type targetSourceType) + { + _eventRegistry.Unsubscribe(subscriber, targetSourceType); + } + + /// + /// Publishes an application context event. + /// + /// + ///

+ /// + ///

+ ///
+ /// + /// The source of the event. May be . + /// + /// + /// The event that is to be raised. + /// + /// + public void PublishEvent(object sender, ApplicationEventArgs e) + { + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug(string.Format( + CultureInfo.InvariantCulture, + "Publishing event in context [{0}] : {1}", + Name, e)); + } + + OnContextEvent(sender, e); + + if (ParentContext != null) + { + ParentContext.PublishEvent(sender, e); + } + } + + private sealed class ObjectPostProcessorChecker : IObjectPostProcessor, IOrdered + { + private static readonly ILogger log = LogManager.GetLogger(); + private int _objectPostProcessorTargetCount; + private IConfigurableListableObjectFactory _objectFactory; + + public void Reset(IConfigurableListableObjectFactory objectFactory, int objectPostProcessorTargetCount) + { + _objectFactory = objectFactory; + _objectPostProcessorTargetCount = objectPostProcessorTargetCount; + } + + public object PostProcessBeforeInitialization(object obj, string name) + { + return obj; + } + + public object PostProcessAfterInitialization(object obj, string objectName) + { + if (_objectFactory.ObjectPostProcessorCount < _objectPostProcessorTargetCount) + { + if (log.IsEnabled(LogLevel.Information)) + { + log.LogInformation(string.Format( + "Object '{0}' is not eligible for being processed by all " + + "IObjectPostProcessors (for example: not eligible for auto-proxying).", objectName)); + } + } + + return obj; + } + + public int Order => Int32.MinValue; + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Context/Support/AbstractMessageSource.cs b/src/Spring/Spring.Core/Context/Support/AbstractMessageSource.cs index 1148f04c..6fca2def 100644 --- a/src/Spring/Spring.Core/Context/Support/AbstractMessageSource.cs +++ b/src/Spring/Spring.Core/Context/Support/AbstractMessageSource.cs @@ -21,595 +21,590 @@ using System.Globalization; using Microsoft.Extensions.Logging; -namespace Spring.Context.Support +namespace Spring.Context.Support; + +/// +/// Abstract implementation of the interface, +/// implementing common handling of message variants, making it easy +/// to implement a specific strategy for a concrete . +/// +/// +///

Subclasses must implement the abstract ResolveObject +/// method.

+///

Note: By default, message texts are only parsed through +/// String.Format if arguments have been passed in for the message. In case +/// of no arguments, message texts will be returned as-is. As a consequence, +/// you should only use String.Format escaping for messages with actual +/// arguments, and keep all other messages unescaped. +///

+///

Supports not only IMessageSourceResolvables as primary messages +/// but also resolution of message arguments that are in turn +/// IMessageSourceResolvables themselves. +///

+///

This class does not implement caching of messages per code, thus +/// subclasses can dynamically change messages over time. Subclasses are +/// encouraged to cache their messages in a modification-aware fashion, +/// allowing for hot deployment of updated messages. +///

+///
+/// Rod Johnson +/// Juergen Hoeller +/// Griffin Caprio (.NET) +/// Harald Radi (.NET) +/// +/// +/// +public abstract class AbstractMessageSource : IHierarchicalMessageSource { + #region Fields + /// - /// Abstract implementation of the interface, - /// implementing common handling of message variants, making it easy - /// to implement a specific strategy for a concrete . + /// holds the logger instance shared with subclasses. + /// + protected readonly ILogger log; + + private IMessageSource parentMessageSource; + private bool useCodeAsDefaultMessage = false; + + #endregion + + #region Constructor + + /// + /// Initializes this instance. + /// + protected AbstractMessageSource() + { + log = LogManager.GetLogger(GetType()); + } + + #endregion + + #region Properties + + /// Gets or Sets a value indicating whether to use the message code as + /// default message instead of throwing a NoSuchMessageException. + /// Useful for development and debugging. Default is "false". /// /// - ///

Subclasses must implement the abstract ResolveObject - /// method.

- ///

Note: By default, message texts are only parsed through - /// String.Format if arguments have been passed in for the message. In case - /// of no arguments, message texts will be returned as-is. As a consequence, - /// you should only use String.Format escaping for messages with actual - /// arguments, and keep all other messages unescaped. - ///

- ///

Supports not only IMessageSourceResolvables as primary messages - /// but also resolution of message arguments that are in turn - /// IMessageSourceResolvables themselves. - ///

- ///

This class does not implement caching of messages per code, thus - /// subclasses can dynamically change messages over time. Subclasses are - /// encouraged to cache their messages in a modification-aware fashion, - /// allowing for hot deployment of updated messages. + ///

Note: In case of a IMessageSourceResolvable with multiple codes + /// (like a FieldError) and a MessageSource that has a parent MessageSource, + /// do not activate "UseCodeAsDefaultMessage" in the parent: + /// Else, you'll get the first code returned as message by the parent, + /// without attempts to check further codes.

+ ///

To be able to work with "UseCodeAsDefaultMessage" turned on in the parent, + /// AbstractMessageSource contains special checks + /// to delegate to the internal GetMessageInternal method if available. + /// In general, it is recommended to just use "UseCodeAsDefaultMessage" during + /// development and not rely on it in production in the first place, though.

+ ///

Alternatively, consider overriding the GetDefaultMessage + /// method to return a custom fallback message for an unresolvable code.

+ ///
+ /// + /// true if use the message code as default message instead of + /// throwing a NoSuchMessageException; otherwise, false. + /// + public bool UseCodeAsDefaultMessage + { + get { return useCodeAsDefaultMessage; } + set { useCodeAsDefaultMessage = value; } + } + + #endregion + + #region IHierarchicalMessageSource Members + + /// + /// The parent message source used to try and resolve messages that + /// this object can't resolve. + /// + /// + /// + ///

+ /// If the value of this property is then no + /// further resolution is possible. ///

///
- /// Rod Johnson - /// Juergen Hoeller - /// Griffin Caprio (.NET) - /// Harald Radi (.NET) - /// - /// - /// - public abstract class AbstractMessageSource : IHierarchicalMessageSource + public IMessageSource ParentMessageSource { - #region Fields + get { return parentMessageSource; } + set { parentMessageSource = value; } + } - /// - /// holds the logger instance shared with subclasses. - /// - protected readonly ILogger log; + /// + /// Resolve the message identified by the supplied + /// . + /// + /// The name of the message to resolve. + /// + /// The resolved message if the lookup was successful (see above for + /// the return value in the case of an unsuccessful lookup). + /// + /// + /// If the lookup is not successful throw NoSuchMessageException + /// + public string GetMessage(string name) + { + return GetMessage(name, CultureInfo.CurrentUICulture, null); + } - private IMessageSource parentMessageSource; - private bool useCodeAsDefaultMessage = false; + /// + /// Resolve the message identified by the supplied + /// . + /// + /// The name of the message to resolve. + /// The that represents + /// the culture for which the resource is localized. + /// + /// The resolved message if the lookup was successful (see above for + /// the return value in the case of an unsuccessful lookup). + /// + /// + /// Note that the fallback behavior based on CultureInfo seem to + /// have a bug that is fixed by installed .NET 1.1 Service Pack 1. + ///

+ /// If the lookup is not successful, implementations are permitted to + /// take one of two actions. + ///

+ /// If the lookup is not successful throw NoSuchMessageException + ///
+ public string GetMessage(string name, CultureInfo culture) + { + return GetMessage(name, culture, null); + } - #endregion + /// + /// Resolve the message identified by the supplied + /// . + /// + /// The name of the message to resolve. + /// The array of arguments that will be filled in for parameters within + /// the message, or if there are no parameters + /// within the message. Parameters within a message should be + /// referenced using the same syntax as the format string for the + /// method. + /// + /// The resolved message if the lookup was successful (see above for + /// the return value in the case of an unsuccessful lookup). + /// + /// + /// If the lookup is not successful throw NoSuchMessageException + /// + public string GetMessage(string name, params object[] arguments) + { + return GetMessage(name, CultureInfo.CurrentUICulture, arguments); + } - #region Constructor + /// + /// Resolve the message identified by the supplied + /// . + /// + /// The name of the message to resolve. + /// The that represents + /// the culture for which the resource is localized. + /// The array of arguments that will be filled in for parameters within + /// the message, or if there are no parameters + /// within the message. Parameters within a message should be + /// referenced using the same syntax as the format string for the + /// method. + /// + /// The resolved message if the lookup was successful (see above for + /// the return value in the case of an unsuccessful lookup). + /// + /// + /// Note that the fallback behavior based on CultureInfo seem to + /// have a bug that is fixed by installed .NET 1.1 Service Pack 1. + ///

+ /// If the lookup is not successful throw NoSuchMessageException. + ///

+ ///
+ public string GetMessage(string name, CultureInfo culture, params object[] arguments) + { + string msg = GetMessageInternal(name, arguments, culture); + if (msg != null) return msg; + string fallback = GetDefaultMessage(name); + if (fallback != null) return fallback; + throw new NoSuchMessageException(name, culture); + } - /// - /// Initializes this instance. - /// - protected AbstractMessageSource() + /// + /// Resolve the message identified by the supplied + /// . + /// + /// The name of the message to resolve. + /// The default message if name is not found. + /// The that represents + /// the culture for which the resource is localized. + /// The array of arguments that will be filled in for parameters within + /// the message, or if there are no parameters + /// within the message. Parameters within a message should be + /// referenced using the same syntax as the format string for the + /// method. + /// + /// The resolved message if the lookup was successful (see above for + /// the return value in the case of an unsuccessful lookup). + /// + /// + /// Note that the fallback behavior based on CultureInfo seem to + /// have a bug that is fixed by installed .NET 1.1 Service Pack 1. + ///

+ /// If the lookup is not successful throw NoSuchMessageException + ///

+ ///
+ public string GetMessage(string name, string defaultMessage, CultureInfo culture, params object[] arguments) + { + string msg = GetMessageInternal(name, arguments, culture); + if (msg != null) return msg; + if (defaultMessage == null) { - log = LogManager.GetLogger(GetType()); - } - - #endregion - - #region Properties - - - /// Gets or Sets a value indicating whether to use the message code as - /// default message instead of throwing a NoSuchMessageException. - /// Useful for development and debugging. Default is "false". - /// - /// - ///

Note: In case of a IMessageSourceResolvable with multiple codes - /// (like a FieldError) and a MessageSource that has a parent MessageSource, - /// do not activate "UseCodeAsDefaultMessage" in the parent: - /// Else, you'll get the first code returned as message by the parent, - /// without attempts to check further codes.

- ///

To be able to work with "UseCodeAsDefaultMessage" turned on in the parent, - /// AbstractMessageSource contains special checks - /// to delegate to the internal GetMessageInternal method if available. - /// In general, it is recommended to just use "UseCodeAsDefaultMessage" during - /// development and not rely on it in production in the first place, though.

- ///

Alternatively, consider overriding the GetDefaultMessage - /// method to return a custom fallback message for an unresolvable code.

- ///
- /// - /// true if use the message code as default message instead of - /// throwing a NoSuchMessageException; otherwise, false. - /// - public bool UseCodeAsDefaultMessage - { - get { return useCodeAsDefaultMessage; } - set { useCodeAsDefaultMessage = value; } - } - - #endregion - - #region IHierarchicalMessageSource Members - - /// - /// The parent message source used to try and resolve messages that - /// this object can't resolve. - /// - /// - /// - ///

- /// If the value of this property is then no - /// further resolution is possible. - ///

- ///
- public IMessageSource ParentMessageSource - { - get { return parentMessageSource; } - set { parentMessageSource = value; } - } - - /// - /// Resolve the message identified by the supplied - /// . - /// - /// The name of the message to resolve. - /// - /// The resolved message if the lookup was successful (see above for - /// the return value in the case of an unsuccessful lookup). - /// - /// - /// If the lookup is not successful throw NoSuchMessageException - /// - public string GetMessage(string name) - { - return GetMessage(name, CultureInfo.CurrentUICulture, null); - } - - /// - /// Resolve the message identified by the supplied - /// . - /// - /// The name of the message to resolve. - /// The that represents - /// the culture for which the resource is localized. - /// - /// The resolved message if the lookup was successful (see above for - /// the return value in the case of an unsuccessful lookup). - /// - /// - /// Note that the fallback behavior based on CultureInfo seem to - /// have a bug that is fixed by installed .NET 1.1 Service Pack 1. - ///

- /// If the lookup is not successful, implementations are permitted to - /// take one of two actions. - ///

- /// If the lookup is not successful throw NoSuchMessageException - ///
- public string GetMessage(string name, CultureInfo culture) - { - return GetMessage(name, culture, null); - } - - /// - /// Resolve the message identified by the supplied - /// . - /// - /// The name of the message to resolve. - /// The array of arguments that will be filled in for parameters within - /// the message, or if there are no parameters - /// within the message. Parameters within a message should be - /// referenced using the same syntax as the format string for the - /// method. - /// - /// The resolved message if the lookup was successful (see above for - /// the return value in the case of an unsuccessful lookup). - /// - /// - /// If the lookup is not successful throw NoSuchMessageException - /// - public string GetMessage(string name, params object[] arguments) - { - return GetMessage(name, CultureInfo.CurrentUICulture, arguments); - } - - /// - /// Resolve the message identified by the supplied - /// . - /// - /// The name of the message to resolve. - /// The that represents - /// the culture for which the resource is localized. - /// The array of arguments that will be filled in for parameters within - /// the message, or if there are no parameters - /// within the message. Parameters within a message should be - /// referenced using the same syntax as the format string for the - /// method. - /// - /// The resolved message if the lookup was successful (see above for - /// the return value in the case of an unsuccessful lookup). - /// - /// - /// Note that the fallback behavior based on CultureInfo seem to - /// have a bug that is fixed by installed .NET 1.1 Service Pack 1. - ///

- /// If the lookup is not successful throw NoSuchMessageException. - ///

- ///
- public string GetMessage(string name, CultureInfo culture, params object[] arguments) - { - string msg = GetMessageInternal(name, arguments, culture); - if (msg != null) return msg; string fallback = GetDefaultMessage(name); if (fallback != null) return fallback; - throw new NoSuchMessageException(name, culture); } - /// - /// Resolve the message identified by the supplied - /// . - /// - /// The name of the message to resolve. - /// The default message if name is not found. - /// The that represents - /// the culture for which the resource is localized. - /// The array of arguments that will be filled in for parameters within - /// the message, or if there are no parameters - /// within the message. Parameters within a message should be - /// referenced using the same syntax as the format string for the - /// method. - /// - /// The resolved message if the lookup was successful (see above for - /// the return value in the case of an unsuccessful lookup). - /// - /// - /// Note that the fallback behavior based on CultureInfo seem to - /// have a bug that is fixed by installed .NET 1.1 Service Pack 1. - ///

- /// If the lookup is not successful throw NoSuchMessageException - ///

- ///
- public string GetMessage(string name, string defaultMessage, CultureInfo culture, params object[] arguments) - { - string msg = GetMessageInternal(name, arguments, culture); - if (msg != null) return msg; - if (defaultMessage == null) - { - string fallback = GetDefaultMessage(name); - if (fallback != null) return fallback; - } - return RenderDefaultMessage(defaultMessage, arguments, culture); - } - - /// - /// Resolve the message using all of the attributes contained within - /// the supplied - /// argument. - /// - /// The value object storing those attributes that are required to - /// properly resolve a message. - /// The that represents - /// the culture for which the resource is localized. - /// - /// The resolved message if the lookup was successful. - /// - /// - /// If the message could not be resolved. - /// - public string GetMessage(IMessageSourceResolvable resolvable, CultureInfo culture) - { - IList codes = resolvable.GetCodes(); - if (codes == null) codes = new string[0]; - for (int i = 0; i < codes.Count; i++) - { - string msg = GetMessageInternal(codes[i], resolvable.GetArguments(), culture); - if (msg != null) return msg; - } - if (resolvable.DefaultMessage != null) - return RenderDefaultMessage(resolvable.DefaultMessage, resolvable.GetArguments(), culture); - if (codes.Count > 0) - { - string fallback = GetDefaultMessage(codes[0]); - if (fallback != null) return fallback; - } - throw new NoSuchMessageException(codes.Count > 0 ? codes[codes.Count - 1] : null, culture); - } - - /// - /// Gets a localized resource object identified by the supplied - /// . - /// - /// - /// The name of the resource object to resolve. - /// - /// - /// The resolved object, or if not found. - /// - /// - public object GetResourceObject(string name) - { - object resource = GetResourceInternal(name, CultureInfo.CurrentUICulture); - if (resource != null) return resource; - if (ParentMessageSource != null) - return ParentMessageSource.GetResourceObject(name, CultureInfo.CurrentUICulture); - return null; - } - - /// - /// Gets a localized resource object identified by the supplied - /// . - /// - /// - /// Note that the fallback behavior based on CultureInfo seem to - /// have a bug that is fixed by installed .NET 1.1 Service Pack 1. - /// - /// - /// The name of the resource object to resolve. - /// - /// - /// The with which the - /// resource is associated. - /// - /// - /// The resolved object, or if not found. If - /// the resource name resolves to null, then in .NET 1.1 the return - /// value will be String.Empty whereas in .NET 2.0 it will return - /// null. - /// - /// - public object GetResourceObject(string name, CultureInfo culture) - { - object resource = GetResourceInternal(name, culture); - if (resource != null) return resource; - if (ParentMessageSource != null) return ParentMessageSource.GetResourceObject(name, culture); - return null; - } - - /// - /// Applies resources to object properties. - /// - /// - /// An object that contains the property values to be applied. - /// - /// - /// The base name of the object to use for key lookup. - /// - /// - /// The with which the - /// resource is associated. - /// - /// - public void ApplyResources( - object value, string objectName, CultureInfo culture) - { - ApplyResourcesInternal(value, objectName, culture); - if (ParentMessageSource != null) ParentMessageSource.ApplyResources(value, objectName, culture); - } - - #endregion - - #region Protected Methods - - /// Resolve the given code and arguments as message in the given culture, - /// returning null if not found. Does not fall back to the code - /// as default message. Invoked by GetMessage methods. - /// - /// The code to lookup up, such as 'calculator.noRateSet'. - /// array of arguments that will be filled in for params - /// within the message. - /// The with which the - /// resource is associated. - /// - /// The resolved message if the lookup was successful. - /// - protected string GetMessageInternal(string code, object[] args, CultureInfo culture) - { - if (code == null) return null; - if (culture == null) culture = CultureInfo.CurrentUICulture; - - if ((args != null && args.Length > 0)) - { - // Resolve arguments eagerly, for the case where the message - // is defined in a parent MessageSource but resolvable arguments - // are defined in the child MessageSource. - args = ResolveArguments(args, culture); - } - - string message = ResolveMessage(code, culture); - - if (message != null) return FormatMessage(message, args, culture); - - // Not found -> check parent, if any. - return GetMessageFromParent(code, args, culture); - } - - - /// - /// Try to retrieve the given message from the parent MessageSource, if any. - /// - /// The code to lookup up, such as 'calculator.noRateSet'. - /// array of arguments that will be filled in for params - /// within the message. - /// The with which the - /// resource is associated. - /// - /// The resolved message if the lookup was successful. - /// - protected string GetMessageFromParent(string code, object[] args, CultureInfo culture) - { - if (ParentMessageSource != null) - { - AbstractMessageSource parent = ParentMessageSource as AbstractMessageSource; - if (parent != null) - { - // Call internal method to avoid getting the default code back - // in case of "useCodeAsDefaultMessage" being activated. - return parent.GetMessageInternal(code, args, culture); - } - else - { - // Check parent MessageSource, returning null if not found there. - return ParentMessageSource.GetMessage(code, null, culture, args); - } - } - // Not found in parent either. - return null; - } - - - /// - /// Return a fallback default message for the given code, if any. - /// - /// - /// Default is to return the code itself if "UseCodeAsDefaultMessage" - /// is activated, or return no fallback else. In case of no fallback, - /// the caller will usually receive a NoSuchMessageException from GetMessage - /// - /// The code to lookup up, such as 'calculator.noRateSet'. - /// The default message to use, or null if none. - protected virtual string GetDefaultMessage(string code) - { - if (UseCodeAsDefaultMessage) return code; - return null; - } - - - - /// - /// Renders the default message string. The default message is passed in as specified by the - /// caller and can be rendered into a fully formatted default message shown to the user. - /// - /// Default implementation passed he String for String.Format resolving any - /// argument placeholders found in them. Subclasses may override this method to plug - /// in custom processing of default messages. - /// - /// The default message. - /// The array of agruments that will be filled in for parameter - /// placeholders within the message, or null if none. - /// The with which the - /// resource is associated. - /// The rendered default message (with resolved arguments) - protected virtual string RenderDefaultMessage(string defaultMessage, object[] args, CultureInfo culture) - { - return FormatMessage(defaultMessage, args, culture); - } - - /// - /// Format the given default message String resolving any - /// agrument placeholders found in them. - /// - /// The message to format. - /// The array of agruments that will be filled in for parameter - /// placeholders within the message, or null if none. - /// The with which the - /// resource is associated. - /// The formatted message (with resolved arguments) - protected virtual string FormatMessage(string msg, object[] args, CultureInfo culture) - { - if (msg == null || ((args == null || args.Length == 0))) return msg; - return String.Format(culture, msg, args); - } - - - /// - /// Search through the given array of objects, find any - /// MessageSourceResolvable objects and resolve them. - /// - /// - /// Allows for messages to have MessageSourceResolvables as arguments. - /// - /// - /// The array of arguments for a message. - /// The with which the - /// resource is associated. - /// An array of arguments with any IMessageSourceResolvables resolved - protected virtual object[] ResolveArguments(object[] args, CultureInfo culture) - { - if (args == null) return new object[0]; - object[] resolvedArgs = new object[args.Length]; - - for (int i = 0; i < args.Length; i++) - { - IMessageSourceResolvable resolvable = args[i] as IMessageSourceResolvable; - if (resolvable != null) resolvedArgs[i] = GetMessage(resolvable, culture); - else resolvedArgs[i] = args[i]; - } - - return resolvedArgs; - } - - /// - /// Gets the specified resource (e.g. Icon or Bitmap). - /// - /// The name of the resource to resolve. - /// - /// The to resolve the - /// code for. - /// - /// The resource if found. otherwise. - protected object GetResourceInternal(string name, CultureInfo cultureInfo) - { - if (cultureInfo == null) cultureInfo = CultureInfo.CurrentUICulture; - if (name == null) return null; - return ResolveObject(name, cultureInfo); - } - - /// - /// Applies resources from the given name on the specified object. - /// - /// - /// An object that contains the property values to be applied. - /// - /// - /// The base name of the object to use for key lookup. - /// - /// - /// The with which the - /// resource is associated. - /// - protected void ApplyResourcesInternal(object value, string objectName, CultureInfo cultureInfo) - { - if (cultureInfo == null) cultureInfo = CultureInfo.CurrentUICulture; - ApplyResourcesToObject(value, objectName, cultureInfo); - } - - #endregion - - #region Protected Abstract Methods - - /// - /// Subclasses must implement this method to resolve a message. - /// - /// The code to lookup up, such as 'calculator.noRateSet'. - /// The with which the - /// resource is associated. - /// The resolved message from the backing store of message data. - protected abstract string ResolveMessage(string code, CultureInfo cultureInfo); - - /// - /// Resolves an object (typically an icon or bitmap). - /// - /// - ///

- /// Subclasses must implement this method to resolve an object. - ///

- ///
- /// The code of the object to resolve. - /// - /// The to resolve the - /// code for. - /// - /// - /// The resolved object or if not found. - /// - protected abstract object ResolveObject(string code, CultureInfo cultureInfo); - - /// - /// Applies resources to object properties. - /// - /// - ///

- /// Subclasses must implement this method to apply resources - /// to an arbitrary object. - ///

- ///
- /// - /// An object that contains the property values to be applied. - /// - /// - /// The base name of the object to use for key lookup. - /// - /// - /// The with which the - /// resource is associated. - /// - protected abstract void ApplyResourcesToObject(object value, string objectName, CultureInfo cultureInfo); - - - #endregion - + return RenderDefaultMessage(defaultMessage, arguments, culture); } -} + + /// + /// Resolve the message using all of the attributes contained within + /// the supplied + /// argument. + /// + /// The value object storing those attributes that are required to + /// properly resolve a message. + /// The that represents + /// the culture for which the resource is localized. + /// + /// The resolved message if the lookup was successful. + /// + /// + /// If the message could not be resolved. + /// + public string GetMessage(IMessageSourceResolvable resolvable, CultureInfo culture) + { + IList codes = resolvable.GetCodes(); + if (codes == null) codes = new string[0]; + for (int i = 0; i < codes.Count; i++) + { + string msg = GetMessageInternal(codes[i], resolvable.GetArguments(), culture); + if (msg != null) return msg; + } + + if (resolvable.DefaultMessage != null) + return RenderDefaultMessage(resolvable.DefaultMessage, resolvable.GetArguments(), culture); + if (codes.Count > 0) + { + string fallback = GetDefaultMessage(codes[0]); + if (fallback != null) return fallback; + } + + throw new NoSuchMessageException(codes.Count > 0 ? codes[codes.Count - 1] : null, culture); + } + + /// + /// Gets a localized resource object identified by the supplied + /// . + /// + /// + /// The name of the resource object to resolve. + /// + /// + /// The resolved object, or if not found. + /// + /// + public object GetResourceObject(string name) + { + object resource = GetResourceInternal(name, CultureInfo.CurrentUICulture); + if (resource != null) return resource; + if (ParentMessageSource != null) + return ParentMessageSource.GetResourceObject(name, CultureInfo.CurrentUICulture); + return null; + } + + /// + /// Gets a localized resource object identified by the supplied + /// . + /// + /// + /// Note that the fallback behavior based on CultureInfo seem to + /// have a bug that is fixed by installed .NET 1.1 Service Pack 1. + /// + /// + /// The name of the resource object to resolve. + /// + /// + /// The with which the + /// resource is associated. + /// + /// + /// The resolved object, or if not found. If + /// the resource name resolves to null, then in .NET 1.1 the return + /// value will be String.Empty whereas in .NET 2.0 it will return + /// null. + /// + /// + public object GetResourceObject(string name, CultureInfo culture) + { + object resource = GetResourceInternal(name, culture); + if (resource != null) return resource; + if (ParentMessageSource != null) return ParentMessageSource.GetResourceObject(name, culture); + return null; + } + + /// + /// Applies resources to object properties. + /// + /// + /// An object that contains the property values to be applied. + /// + /// + /// The base name of the object to use for key lookup. + /// + /// + /// The with which the + /// resource is associated. + /// + /// + public void ApplyResources( + object value, string objectName, CultureInfo culture) + { + ApplyResourcesInternal(value, objectName, culture); + if (ParentMessageSource != null) ParentMessageSource.ApplyResources(value, objectName, culture); + } + + #endregion + + #region Protected Methods + + /// Resolve the given code and arguments as message in the given culture, + /// returning null if not found. Does not fall back to the code + /// as default message. Invoked by GetMessage methods. + /// + /// The code to lookup up, such as 'calculator.noRateSet'. + /// array of arguments that will be filled in for params + /// within the message. + /// The with which the + /// resource is associated. + /// + /// The resolved message if the lookup was successful. + /// + protected string GetMessageInternal(string code, object[] args, CultureInfo culture) + { + if (code == null) return null; + if (culture == null) culture = CultureInfo.CurrentUICulture; + + if ((args != null && args.Length > 0)) + { + // Resolve arguments eagerly, for the case where the message + // is defined in a parent MessageSource but resolvable arguments + // are defined in the child MessageSource. + args = ResolveArguments(args, culture); + } + + string message = ResolveMessage(code, culture); + + if (message != null) return FormatMessage(message, args, culture); + + // Not found -> check parent, if any. + return GetMessageFromParent(code, args, culture); + } + + /// + /// Try to retrieve the given message from the parent MessageSource, if any. + /// + /// The code to lookup up, such as 'calculator.noRateSet'. + /// array of arguments that will be filled in for params + /// within the message. + /// The with which the + /// resource is associated. + /// + /// The resolved message if the lookup was successful. + /// + protected string GetMessageFromParent(string code, object[] args, CultureInfo culture) + { + if (ParentMessageSource != null) + { + AbstractMessageSource parent = ParentMessageSource as AbstractMessageSource; + if (parent != null) + { + // Call internal method to avoid getting the default code back + // in case of "useCodeAsDefaultMessage" being activated. + return parent.GetMessageInternal(code, args, culture); + } + else + { + // Check parent MessageSource, returning null if not found there. + return ParentMessageSource.GetMessage(code, null, culture, args); + } + } + + // Not found in parent either. + return null; + } + + /// + /// Return a fallback default message for the given code, if any. + /// + /// + /// Default is to return the code itself if "UseCodeAsDefaultMessage" + /// is activated, or return no fallback else. In case of no fallback, + /// the caller will usually receive a NoSuchMessageException from GetMessage + /// + /// The code to lookup up, such as 'calculator.noRateSet'. + /// The default message to use, or null if none. + protected virtual string GetDefaultMessage(string code) + { + if (UseCodeAsDefaultMessage) return code; + return null; + } + + /// + /// Renders the default message string. The default message is passed in as specified by the + /// caller and can be rendered into a fully formatted default message shown to the user. + /// + /// Default implementation passed he String for String.Format resolving any + /// argument placeholders found in them. Subclasses may override this method to plug + /// in custom processing of default messages. + /// + /// The default message. + /// The array of agruments that will be filled in for parameter + /// placeholders within the message, or null if none. + /// The with which the + /// resource is associated. + /// The rendered default message (with resolved arguments) + protected virtual string RenderDefaultMessage(string defaultMessage, object[] args, CultureInfo culture) + { + return FormatMessage(defaultMessage, args, culture); + } + + /// + /// Format the given default message String resolving any + /// agrument placeholders found in them. + /// + /// The message to format. + /// The array of agruments that will be filled in for parameter + /// placeholders within the message, or null if none. + /// The with which the + /// resource is associated. + /// The formatted message (with resolved arguments) + protected virtual string FormatMessage(string msg, object[] args, CultureInfo culture) + { + if (msg == null || ((args == null || args.Length == 0))) return msg; + return String.Format(culture, msg, args); + } + + /// + /// Search through the given array of objects, find any + /// MessageSourceResolvable objects and resolve them. + /// + /// + /// Allows for messages to have MessageSourceResolvables as arguments. + /// + /// + /// The array of arguments for a message. + /// The with which the + /// resource is associated. + /// An array of arguments with any IMessageSourceResolvables resolved + protected virtual object[] ResolveArguments(object[] args, CultureInfo culture) + { + if (args == null) return new object[0]; + object[] resolvedArgs = new object[args.Length]; + + for (int i = 0; i < args.Length; i++) + { + IMessageSourceResolvable resolvable = args[i] as IMessageSourceResolvable; + if (resolvable != null) resolvedArgs[i] = GetMessage(resolvable, culture); + else resolvedArgs[i] = args[i]; + } + + return resolvedArgs; + } + + /// + /// Gets the specified resource (e.g. Icon or Bitmap). + /// + /// The name of the resource to resolve. + /// + /// The to resolve the + /// code for. + /// + /// The resource if found. otherwise. + protected object GetResourceInternal(string name, CultureInfo cultureInfo) + { + if (cultureInfo == null) cultureInfo = CultureInfo.CurrentUICulture; + if (name == null) return null; + return ResolveObject(name, cultureInfo); + } + + /// + /// Applies resources from the given name on the specified object. + /// + /// + /// An object that contains the property values to be applied. + /// + /// + /// The base name of the object to use for key lookup. + /// + /// + /// The with which the + /// resource is associated. + /// + protected void ApplyResourcesInternal(object value, string objectName, CultureInfo cultureInfo) + { + if (cultureInfo == null) cultureInfo = CultureInfo.CurrentUICulture; + ApplyResourcesToObject(value, objectName, cultureInfo); + } + + #endregion + + #region Protected Abstract Methods + + /// + /// Subclasses must implement this method to resolve a message. + /// + /// The code to lookup up, such as 'calculator.noRateSet'. + /// The with which the + /// resource is associated. + /// The resolved message from the backing store of message data. + protected abstract string ResolveMessage(string code, CultureInfo cultureInfo); + + /// + /// Resolves an object (typically an icon or bitmap). + /// + /// + ///

+ /// Subclasses must implement this method to resolve an object. + ///

+ ///
+ /// The code of the object to resolve. + /// + /// The to resolve the + /// code for. + /// + /// + /// The resolved object or if not found. + /// + protected abstract object ResolveObject(string code, CultureInfo cultureInfo); + + /// + /// Applies resources to object properties. + /// + /// + ///

+ /// Subclasses must implement this method to apply resources + /// to an arbitrary object. + ///

+ ///
+ /// + /// An object that contains the property values to be applied. + /// + /// + /// The base name of the object to use for key lookup. + /// + /// + /// The with which the + /// resource is associated. + /// + protected abstract void ApplyResourcesToObject(object value, string objectName, CultureInfo cultureInfo); + + #endregion +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Context/Support/AbstractXmlApplicationContext.cs b/src/Spring/Spring.Core/Context/Support/AbstractXmlApplicationContext.cs index 9d60396e..2ba24b6c 100644 --- a/src/Spring/Spring.Core/Context/Support/AbstractXmlApplicationContext.cs +++ b/src/Spring/Spring.Core/Context/Support/AbstractXmlApplicationContext.cs @@ -26,296 +26,293 @@ using Spring.Objects.Factory.Xml; using Spring.Util; using Spring.Core.IO; -namespace Spring.Context.Support +namespace Spring.Context.Support; + +/// +/// Convenient abstract superclass for +/// implementations that +/// draw their configuration from XML documents containing object +/// definitions as understood by an +/// . +/// +/// Rod Johnson +/// Juergen Hoeller +/// Griffin Caprio (.NET) +public abstract class AbstractXmlApplicationContext : AbstractApplicationContext { + private DefaultListableObjectFactory _objectFactory; + /// - /// Convenient abstract superclass for - /// implementations that - /// draw their configuration from XML documents containing object - /// definitions as understood by an - /// . + /// Creates a new instance of the + /// + /// class. /// - /// Rod Johnson - /// Juergen Hoeller - /// Griffin Caprio (.NET) - public abstract class AbstractXmlApplicationContext : AbstractApplicationContext + /// + ///

+ /// This is an class, and as such exposes + /// no public constructors. + ///

+ ///
+ protected AbstractXmlApplicationContext() + : this(null, true, null) { - private DefaultListableObjectFactory _objectFactory; + } - /// - /// Creates a new instance of the - /// - /// class. - /// - /// - ///

- /// This is an class, and as such exposes - /// no public constructors. - ///

- ///
- protected AbstractXmlApplicationContext() - : this(null, true, null) - { } + /// + /// Creates a new instance of the + /// class + /// with the given parent context. + /// + /// + ///

+ /// This is an class, and as such exposes + /// no public constructors. + ///

+ ///
+ /// The application context name. + /// Flag specifying whether to make this context case sensitive or not. + /// The parent context. + protected AbstractXmlApplicationContext(string name, bool caseSensitive, + IApplicationContext parentContext) + : base(name, caseSensitive, parentContext) + { + } - /// - /// Creates a new instance of the - /// class - /// with the given parent context. - /// - /// - ///

- /// This is an class, and as such exposes - /// no public constructors. - ///

- ///
- /// The application context name. - /// Flag specifying whether to make this context case sensitive or not. - /// The parent context. - protected AbstractXmlApplicationContext(string name, bool caseSensitive, - IApplicationContext parentContext) - : base(name, caseSensitive, parentContext) - { } + /// + /// An array of resource locations, referring to the XML object + /// definition files that this context is to be built with. + /// + /// + ///

+ /// Examples of the format of the various strings that would be + /// returned by accessing this property can be found in the overview + /// documentation of with the + /// class. + ///

+ ///
+ /// + /// An array of resource locations, or if none. + /// + protected abstract string[] ConfigurationLocations { get; } - /// - /// An array of resource locations, referring to the XML object - /// definition files that this context is to be built with. - /// - /// - ///

- /// Examples of the format of the various strings that would be - /// returned by accessing this property can be found in the overview - /// documentation of with the - /// class. - ///

- ///
- /// - /// An array of resource locations, or if none. - /// - protected abstract string[] ConfigurationLocations { get; } + /// + /// An array of resources that this context is to be built with. + /// + /// + ///

+ /// Examples of the format of the various strings that would be + /// returned by accessing this property can be found in the overview + /// documentation of with the + /// class. + ///

+ ///
+ /// + /// An array of s, or if none. + /// + protected abstract IResource[] ConfigurationResources { get; } + /// + /// Instantiates and populates the underlying + /// with the object + /// definitions yielded up by the + /// method. + /// + /// + /// In the case of errors encountered while refreshing the object factory. + /// + /// + /// In the case of errors encountered reading any of the resources + /// yielded by the method. + /// + /// + protected override void RefreshObjectFactory() + { + // Shut down previous object factory, if any. + DefaultListableObjectFactory oldObjectFactory = _objectFactory; + _objectFactory = null; - /// - /// An array of resources that this context is to be built with. - /// - /// - ///

- /// Examples of the format of the various strings that would be - /// returned by accessing this property can be found in the overview - /// documentation of with the - /// class. - ///

- ///
- /// - /// An array of s, or if none. - /// - protected abstract IResource[] ConfigurationResources { get; } - - - /// - /// Instantiates and populates the underlying - /// with the object - /// definitions yielded up by the - /// method. - /// - /// - /// In the case of errors encountered while refreshing the object factory. - /// - /// - /// In the case of errors encountered reading any of the resources - /// yielded by the method. - /// - /// - protected override void RefreshObjectFactory() + if (oldObjectFactory != null) { - // Shut down previous object factory, if any. - DefaultListableObjectFactory oldObjectFactory = _objectFactory; - _objectFactory = null; + oldObjectFactory.Dispose(); + } - if (oldObjectFactory != null) + try + { + DefaultListableObjectFactory objectFactory = CreateObjectFactory(); + CustomizeObjectFactory(objectFactory); + LoadObjectDefinitions(objectFactory); + + _objectFactory = objectFactory; + + #region Instrumentation + + if (log.IsEnabled(LogLevel.Debug)) { - oldObjectFactory.Dispose(); + log.LogDebug(string.Format( + "Refreshed ObjectFactory for application context '{0}'.", + Name)); } - try - { - DefaultListableObjectFactory objectFactory = CreateObjectFactory(); - CustomizeObjectFactory(objectFactory); - LoadObjectDefinitions(objectFactory); - - _objectFactory = objectFactory; - - #region Instrumentation - - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug(string.Format( - "Refreshed ObjectFactory for application context '{0}'.", - Name)); - } - - #endregion - } - catch (IOException ex) - { - throw new ApplicationContextException( - string.Format( - "I/O error parsing XML resource for application context '{0}'.", - Name), ex); - } - catch (UriFormatException ex) - { - throw new ApplicationContextException( - string.Format( - "Error parsing resource locations [{0}] for application context '{1}'.", - StringUtils.ArrayToCommaDelimitedString(ConfigurationLocations), - Name), ex); - } + #endregion } - - - /// - /// Initialize the object definition reader used for loading the object - /// definitions of this context. - /// - /// - ///

- /// The default implementation of this method is a no-op; i.e. it does - /// nothing. Can be overridden in subclasses to provide custom - /// initialization of the supplied - /// ; for example, a derived - /// class may want to turn off XML validation. - ///

- ///
- /// - /// The object definition reader used by this context. - /// - protected virtual void InitObjectDefinitionReader( - XmlObjectDefinitionReader objectDefinitionReader) - { } - - /// - /// Load the object definitions with the given - /// . - /// - /// - ///

- /// The lifecycle of the object factory is handled by - /// ; - /// therefore this method is just supposed to load and / or register - /// object definitions. - ///

- ///
- /// - /// The reader containing object definitions. - /// - /// In case of object registration errors. - /// - /// - /// In the case of errors encountered reading any of the resources - /// yielded by either the or - /// the methods. - /// - protected virtual void LoadObjectDefinitions(XmlObjectDefinitionReader objectDefinitionReader) + catch (IOException ex) { - string[] locations = ConfigurationLocations; - if (locations != null) - { - objectDefinitionReader.LoadObjectDefinitions(locations); - } - - IResource[] resources = ConfigurationResources; - if (resources != null) - { - objectDefinitionReader.LoadObjectDefinitions(resources); - } - + throw new ApplicationContextException( + string.Format( + "I/O error parsing XML resource for application context '{0}'.", + Name), ex); } - - - /// - /// Loads the object definitions into the given object factory, typically through - /// delegating to one or more object definition readers. - /// - /// The object factory to lead object definitions into - /// - /// - protected virtual void LoadObjectDefinitions(DefaultListableObjectFactory objectFactory) + catch (UriFormatException ex) { - //Create a new XmlObjectDefinitionReader for the given ObjectFactory - XmlObjectDefinitionReader objectDefinitionReader = CreateXmlObjectDefinitionReader(objectFactory); - - // Configure the bean definition reader with this context's - // resource loading environment. - objectDefinitionReader.ResourceLoader = this; - - // Allow a subclass to provide custom initialization of the reader, - // then proceed with actually loading the object definitions. - InitObjectDefinitionReader(objectDefinitionReader); - LoadObjectDefinitions(objectDefinitionReader); - } - - /// - /// Create a new reader instance for importing object definitions into the specified . - /// - /// the to be associated with the reader - /// a new instance. - protected virtual XmlObjectDefinitionReader CreateXmlObjectDefinitionReader(DefaultListableObjectFactory objectFactory) - { - return new XmlObjectDefinitionReader(objectFactory); - } - - /// - /// Customizes the internal object factory used by this context. - /// - /// Called for each attempt. - ///

- /// The default implementation is empty. Can be overriden in subclassses to customize - /// DefaultListableBeanFatory's standard settings. - ///

- /// The newly created object factory for this context - protected virtual void CustomizeObjectFactory(DefaultListableObjectFactory objectFactory) - { - // noop - } - - /// - /// Create an internal object factory for this context. - /// - /// - ///

- /// Called for each attempt. - /// This default implementation creates a - /// - /// with the internal object factory of this context's parent serving - /// as the parent object factory. Can be overridden in subclasse,s - /// for example to customize DefaultListableBeanFactory's settings. - ///

- ///
- /// The object factory for this context. - protected virtual DefaultListableObjectFactory CreateObjectFactory() - { - return new DefaultListableObjectFactory(IsCaseSensitive, GetInternalParentObjectFactory()); - } - - /// - /// Subclasses must return their internal object factory here. - /// - /// - /// The internal object factory for the application context. - /// - /// - public override IConfigurableListableObjectFactory ObjectFactory - { - get { return _objectFactory; } - } - - /// - /// Determine whether the given object name is already in use within this context's object factory, - /// i.e. whether there is a local object or alias registered under this name. - /// - public override bool IsObjectNameInUse(string objectName) - { - return _objectFactory.IsObjectNameInUse(objectName); + throw new ApplicationContextException( + string.Format( + "Error parsing resource locations [{0}] for application context '{1}'.", + StringUtils.ArrayToCommaDelimitedString(ConfigurationLocations), + Name), ex); } } + + /// + /// Initialize the object definition reader used for loading the object + /// definitions of this context. + /// + /// + ///

+ /// The default implementation of this method is a no-op; i.e. it does + /// nothing. Can be overridden in subclasses to provide custom + /// initialization of the supplied + /// ; for example, a derived + /// class may want to turn off XML validation. + ///

+ ///
+ /// + /// The object definition reader used by this context. + /// + protected virtual void InitObjectDefinitionReader( + XmlObjectDefinitionReader objectDefinitionReader) + { + } + + /// + /// Load the object definitions with the given + /// . + /// + /// + ///

+ /// The lifecycle of the object factory is handled by + /// ; + /// therefore this method is just supposed to load and / or register + /// object definitions. + ///

+ ///
+ /// + /// The reader containing object definitions. + /// + /// In case of object registration errors. + /// + /// + /// In the case of errors encountered reading any of the resources + /// yielded by either the or + /// the methods. + /// + protected virtual void LoadObjectDefinitions(XmlObjectDefinitionReader objectDefinitionReader) + { + string[] locations = ConfigurationLocations; + if (locations != null) + { + objectDefinitionReader.LoadObjectDefinitions(locations); + } + + IResource[] resources = ConfigurationResources; + if (resources != null) + { + objectDefinitionReader.LoadObjectDefinitions(resources); + } + } + + /// + /// Loads the object definitions into the given object factory, typically through + /// delegating to one or more object definition readers. + /// + /// The object factory to lead object definitions into + /// + /// + protected virtual void LoadObjectDefinitions(DefaultListableObjectFactory objectFactory) + { + //Create a new XmlObjectDefinitionReader for the given ObjectFactory + XmlObjectDefinitionReader objectDefinitionReader = CreateXmlObjectDefinitionReader(objectFactory); + + // Configure the bean definition reader with this context's + // resource loading environment. + objectDefinitionReader.ResourceLoader = this; + + // Allow a subclass to provide custom initialization of the reader, + // then proceed with actually loading the object definitions. + InitObjectDefinitionReader(objectDefinitionReader); + LoadObjectDefinitions(objectDefinitionReader); + } + + /// + /// Create a new reader instance for importing object definitions into the specified . + /// + /// the to be associated with the reader + /// a new instance. + protected virtual XmlObjectDefinitionReader CreateXmlObjectDefinitionReader(DefaultListableObjectFactory objectFactory) + { + return new XmlObjectDefinitionReader(objectFactory); + } + + /// + /// Customizes the internal object factory used by this context. + /// + /// Called for each attempt. + ///

+ /// The default implementation is empty. Can be overriden in subclassses to customize + /// DefaultListableBeanFatory's standard settings. + ///

+ /// The newly created object factory for this context + protected virtual void CustomizeObjectFactory(DefaultListableObjectFactory objectFactory) + { + // noop + } + + /// + /// Create an internal object factory for this context. + /// + /// + ///

+ /// Called for each attempt. + /// This default implementation creates a + /// + /// with the internal object factory of this context's parent serving + /// as the parent object factory. Can be overridden in subclasse,s + /// for example to customize DefaultListableBeanFactory's settings. + ///

+ ///
+ /// The object factory for this context. + protected virtual DefaultListableObjectFactory CreateObjectFactory() + { + return new DefaultListableObjectFactory(IsCaseSensitive, GetInternalParentObjectFactory()); + } + + /// + /// Subclasses must return their internal object factory here. + /// + /// + /// The internal object factory for the application context. + /// + /// + public override IConfigurableListableObjectFactory ObjectFactory + { + get { return _objectFactory; } + } + + /// + /// Determine whether the given object name is already in use within this context's object factory, + /// i.e. whether there is a local object or alias registered under this name. + /// + public override bool IsObjectNameInUse(string objectName) + { + return _objectFactory.IsObjectNameInUse(objectName); + } } diff --git a/src/Spring/Spring.Core/Context/Support/AbstractXmlApplicationContextArgs.cs b/src/Spring/Spring.Core/Context/Support/AbstractXmlApplicationContextArgs.cs index 68e9ec8e..9b8c0752 100644 --- a/src/Spring/Spring.Core/Context/Support/AbstractXmlApplicationContextArgs.cs +++ b/src/Spring/Spring.Core/Context/Support/AbstractXmlApplicationContextArgs.cs @@ -20,99 +20,97 @@ using Spring.Core.IO; -namespace Spring.Context.Support +namespace Spring.Context.Support; + +public abstract class AbstractXmlApplicationContextArgs { - public abstract class AbstractXmlApplicationContextArgs + private bool _caseSensitive; + + private string[] _configurationLocations; + + private IResource[] _configurationResources; + + private string _name; + + private IApplicationContext _parentContext; + + private bool _refresh; + + public virtual bool CaseSensitive { - private bool _caseSensitive; - - private string[] _configurationLocations; - - private IResource[] _configurationResources; - - private string _name; - - private IApplicationContext _parentContext; - - private bool _refresh; - - public virtual bool CaseSensitive + get { - get - { - return _caseSensitive; - } - set - { - _caseSensitive = value; - } + return _caseSensitive; } - - public virtual string[] ConfigurationLocations + set { - get - { - if (_configurationLocations == null) - _configurationLocations = new string[0]; - - return _configurationLocations; - } - set - { - _configurationLocations = value; - } + _caseSensitive = value; } + } - public virtual IResource[] ConfigurationResources + public virtual string[] ConfigurationLocations + { + get { - get - { - if (_configurationResources == null) - _configurationResources = new IResource[0]; + if (_configurationLocations == null) + _configurationLocations = new string[0]; - return _configurationResources; - } - set - { - _configurationResources = value; - } + return _configurationLocations; } - - public virtual string Name + set { - get - { - return _name; - } - set - { - _name = value; - } + _configurationLocations = value; } + } - public virtual IApplicationContext ParentContext + public virtual IResource[] ConfigurationResources + { + get { - get - { - return _parentContext; - } - set - { - _parentContext = value; - } - } + if (_configurationResources == null) + _configurationResources = new IResource[0]; - public virtual bool Refresh + return _configurationResources; + } + set { - get - { - return _refresh; - } - set - { - _refresh = value; - } + _configurationResources = value; } + } + public virtual string Name + { + get + { + return _name; + } + set + { + _name = value; + } + } + + public virtual IApplicationContext ParentContext + { + get + { + return _parentContext; + } + set + { + _parentContext = value; + } + } + + public virtual bool Refresh + { + get + { + return _refresh; + } + set + { + _refresh = value; + } } } diff --git a/src/Spring/Spring.Core/Context/Support/ApplicationContextAwareProcessor.cs b/src/Spring/Spring.Core/Context/Support/ApplicationContextAwareProcessor.cs index 2e7b5cd0..ffaebb0c 100644 --- a/src/Spring/Spring.Core/Context/Support/ApplicationContextAwareProcessor.cs +++ b/src/Spring/Spring.Core/Context/Support/ApplicationContextAwareProcessor.cs @@ -21,120 +21,122 @@ using System.Runtime.Remoting; using Spring.Objects.Factory.Config; -namespace Spring.Context.Support +namespace Spring.Context.Support; + +/// +/// +/// implementation that passes the application context to object that +/// implement the +/// , +/// , and +/// interfaces. +/// +/// +///

+/// If an object's class implements more than one of the +/// , +/// , and +/// interfaces, then the +/// order in which the interfaces are satisfied is as follows... +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +///

+///

+/// Application contexts will automatically register this with their +/// underlying object factory. Applications should thus never need to use +/// this class directly. +///

+///
+/// Juergen Hoeller +/// Griffin Caprio (.NET) +public class ApplicationContextAwareProcessor : IObjectPostProcessor { - /// - /// - /// implementation that passes the application context to object that - /// implement the - /// , - /// , and - /// interfaces. - /// - /// - ///

- /// If an object's class implements more than one of the - /// , - /// , and - /// interfaces, then the - /// order in which the interfaces are satisfied is as follows... - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - ///

- ///

- /// Application contexts will automatically register this with their - /// underlying object factory. Applications should thus never need to use - /// this class directly. - ///

- ///
- /// Juergen Hoeller - /// Griffin Caprio (.NET) - public class ApplicationContextAwareProcessor : IObjectPostProcessor - { - private readonly IApplicationContext _applicationContext; + private readonly IApplicationContext _applicationContext; - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The that this - /// instance will work with. - /// - public ApplicationContextAwareProcessor( - IApplicationContext applicationContext) - { - _applicationContext = applicationContext; - } + /// + /// Creates a new instance of the + /// class. + /// + /// + /// The that this + /// instance will work with. + /// + public ApplicationContextAwareProcessor( + IApplicationContext applicationContext) + { + _applicationContext = applicationContext; + } - /// - /// Apply this - /// to the given new object instance before any object - /// initialization callbacks. - /// - /// - /// The new object instance. - /// - /// - /// The name of the object. - /// - /// - /// The the object instance to use, either the original or a wrapped one. - /// - /// - /// In case of errors. - /// - /// - public object PostProcessAfterInitialization(object obj, string objectName) - { - return obj; - } + /// + /// Apply this + /// to the given new object instance before any object + /// initialization callbacks. + /// + /// + /// The new object instance. + /// + /// + /// The name of the object. + /// + /// + /// The the object instance to use, either the original or a wrapped one. + /// + /// + /// In case of errors. + /// + /// + public object PostProcessAfterInitialization(object obj, string objectName) + { + return obj; + } - /// - /// Apply this to the - /// given new object instance after any object initialization - /// callbacks. - /// - /// - /// The new object instance. - /// - /// - /// The name of the object. - /// - /// - /// The object instance to use, either the original or a wrapped one. - /// - /// - /// In case of errors. - /// - /// - public object PostProcessBeforeInitialization(object obj, string name) - { - if(!RemotingServices.IsTransparentProxy(obj)) - { - if (obj is IResourceLoaderAware resourceLoaderAware) - { - resourceLoaderAware.ResourceLoader = _applicationContext; - } - if (obj is IMessageSourceAware messageSourceAware) - { - messageSourceAware.MessageSource = _applicationContext; - } - if (obj is IApplicationContextAware applicationContextAware) - { - applicationContextAware.ApplicationContext = _applicationContext; - } - } - return obj; - } - } -} \ No newline at end of file + /// + /// Apply this to the + /// given new object instance after any object initialization + /// callbacks. + /// + /// + /// The new object instance. + /// + /// + /// The name of the object. + /// + /// + /// The object instance to use, either the original or a wrapped one. + /// + /// + /// In case of errors. + /// + /// + public object PostProcessBeforeInitialization(object obj, string name) + { + if (!RemotingServices.IsTransparentProxy(obj)) + { + if (obj is IResourceLoaderAware resourceLoaderAware) + { + resourceLoaderAware.ResourceLoader = _applicationContext; + } + + if (obj is IMessageSourceAware messageSourceAware) + { + messageSourceAware.MessageSource = _applicationContext; + } + + if (obj is IApplicationContextAware applicationContextAware) + { + applicationContextAware.ApplicationContext = _applicationContext; + } + } + + return obj; + } +} diff --git a/src/Spring/Spring.Core/Context/Support/ApplicationObjectSupport.cs b/src/Spring/Spring.Core/Context/Support/ApplicationObjectSupport.cs index 60ab4ddc..f446a787 100644 --- a/src/Spring/Spring.Core/Context/Support/ApplicationObjectSupport.cs +++ b/src/Spring/Spring.Core/Context/Support/ApplicationObjectSupport.cs @@ -20,184 +20,186 @@ using Spring.Objects; -namespace Spring.Context.Support +namespace Spring.Context.Support; + +/// +/// Convenient superclass for application objects that want to be aware of +/// the application context, e.g. for custom lookup of collaborating object +/// or for context-specific resource access. +/// +/// +///

+/// It saves the application context reference and provides an +/// initialization callback method. Furthermore, it offers numerous +/// convenience methods for message lookup. +///

+///

+/// There is no requirement to subclass this class: it just makes things +/// a little easier if you need access to the context, e.g. for access to +/// file resources or to the message source. Note that many application +/// objects do not need to be aware of the application context at all, +/// as they can receive collaborating objects via object references. +///

+///
+/// Rod Johnson +/// Juergen Hoeller +/// Griffin Caprio (.NET) +public abstract class ApplicationObjectSupport : IApplicationContextAware { - /// - /// Convenient superclass for application objects that want to be aware of - /// the application context, e.g. for custom lookup of collaborating object - /// or for context-specific resource access. - /// - /// - ///

- /// It saves the application context reference and provides an - /// initialization callback method. Furthermore, it offers numerous - /// convenience methods for message lookup. - ///

- ///

- /// There is no requirement to subclass this class: it just makes things - /// a little easier if you need access to the context, e.g. for access to - /// file resources or to the message source. Note that many application - /// objects do not need to be aware of the application context at all, - /// as they can receive collaborating objects via object references. - ///

- ///
- /// Rod Johnson - /// Juergen Hoeller - /// Griffin Caprio (.NET) - public abstract class ApplicationObjectSupport : IApplicationContextAware - { - private IApplicationContext _applicationContext; - private MessageSourceAccessor _messageSourceAccessor; + private IApplicationContext _applicationContext; + private MessageSourceAccessor _messageSourceAccessor; - /// - /// Creates a new instance of the - /// class. - /// - /// - ///

- /// This is an class, and as such exposes no - /// public constructors. - ///

- ///
- protected ApplicationObjectSupport() - { - } + /// + /// Creates a new instance of the + /// class. + /// + /// + ///

+ /// This is an class, and as such exposes no + /// public constructors. + ///

+ ///
+ protected ApplicationObjectSupport() + { + } - /// - /// Creates a new instance of the - /// class. - /// - /// - ///

- /// This is an class, and as such exposes no - /// public constructors. - ///

- ///
- /// - /// The that this - /// object runs in. - /// - protected ApplicationObjectSupport( - IApplicationContext applicationContext) - { - _applicationContext = applicationContext; - } + /// + /// Creates a new instance of the + /// class. + /// + /// + ///

+ /// This is an class, and as such exposes no + /// public constructors. + ///

+ ///
+ /// + /// The that this + /// object runs in. + /// + protected ApplicationObjectSupport( + IApplicationContext applicationContext) + { + _applicationContext = applicationContext; + } - /// - /// The context class that any context passed to the - /// - /// must be an instance of. - /// - /// - /// The - /// . - /// - protected virtual Type RequiredType - { - get { return typeof (IApplicationContext); } - } + /// + /// The context class that any context passed to the + /// + /// must be an instance of. + /// + /// + /// The + /// . + /// + protected virtual Type RequiredType + { + get { return typeof(IApplicationContext); } + } - /// - /// Intializes the wrapped - /// . - /// - /// - ///

- /// This is a template method that subclasses can override for custom - /// initialization behavior. - ///

- ///

- /// Gets called by the - /// - /// instance directly after setting the context instance. - ///

- /// - /// Does not get called on reinitialization of the context. - /// - ///
- /// - /// In the case of any initialization errors. - /// - /// - /// If thrown by application context methods. - /// - protected virtual void InitApplicationContext() - { - } + /// + /// Intializes the wrapped + /// . + /// + /// + ///

+ /// This is a template method that subclasses can override for custom + /// initialization behavior. + ///

+ ///

+ /// Gets called by the + /// + /// instance directly after setting the context instance. + ///

+ /// + /// Does not get called on reinitialization of the context. + /// + ///
+ /// + /// In the case of any initialization errors. + /// + /// + /// If thrown by application context methods. + /// + protected virtual void InitApplicationContext() + { + } - /// - /// Return a for the - /// application context used by this object, for easy message access. - /// - public MessageSourceAccessor MessageSourceAccessor - { - get { return _messageSourceAccessor; } - } + /// + /// Return a for the + /// application context used by this object, for easy message access. + /// + public MessageSourceAccessor MessageSourceAccessor + { + get { return _messageSourceAccessor; } + } - #region IApplicationContextAware Members + #region IApplicationContextAware Members - /// - /// Gets or sets the that this - /// object runs in. - /// - /// - /// When passed an unexpected - /// implementation - /// instance that is not compatible with the - /// defined by the value of the - /// . - /// property. Also, thrown when trying to re-initialize with a - /// different than was - /// originally used. - /// - /// - /// If thrown by any application context methods. - /// - /// - /// - public IApplicationContext ApplicationContext - { - get { return _applicationContext; } - set - { - if (_applicationContext == null) - { - if (! isValueOfRequiredType(value)) - { - throw new ApplicationContextException( - "Invalid application context: needs to by of type '" + RequiredType.DeclaringType + "'"); - } - _applicationContext = value; - _messageSourceAccessor = new MessageSourceAccessor(value); - InitApplicationContext(); - } - else - { - if (_applicationContext != value) - { - throw new ApplicationContextException("Cannot reinitialize with different application context"); - } - } - } - } + /// + /// Gets or sets the that this + /// object runs in. + /// + /// + /// When passed an unexpected + /// implementation + /// instance that is not compatible with the + /// defined by the value of the + /// . + /// property. Also, thrown when trying to re-initialize with a + /// different than was + /// originally used. + /// + /// + /// If thrown by any application context methods. + /// + /// + /// + public IApplicationContext ApplicationContext + { + get { return _applicationContext; } + set + { + if (_applicationContext == null) + { + if (!isValueOfRequiredType(value)) + { + throw new ApplicationContextException( + "Invalid application context: needs to by of type '" + RequiredType.DeclaringType + "'"); + } - private bool isValueOfRequiredType(IApplicationContext value) - { - if (value.GetType() == RequiredType) - { - return true; - } - Type[] implementedTypes = value.GetType().GetInterfaces(); - for (int i = 0; i < implementedTypes.Length; i++) - { - if (implementedTypes[i] == RequiredType) - { - return true; - } - } - return false; - } + _applicationContext = value; + _messageSourceAccessor = new MessageSourceAccessor(value); + InitApplicationContext(); + } + else + { + if (_applicationContext != value) + { + throw new ApplicationContextException("Cannot reinitialize with different application context"); + } + } + } + } - #endregion - } + private bool isValueOfRequiredType(IApplicationContext value) + { + if (value.GetType() == RequiredType) + { + return true; + } + + Type[] implementedTypes = value.GetType().GetInterfaces(); + for (int i = 0; i < implementedTypes.Length; i++) + { + if (implementedTypes[i] == RequiredType) + { + return true; + } + } + + return false; + } + + #endregion } diff --git a/src/Spring/Spring.Core/Context/Support/CodeConfigApplicationContext.cs b/src/Spring/Spring.Core/Context/Support/CodeConfigApplicationContext.cs index 633909bf..3d4c75ef 100644 --- a/src/Spring/Spring.Core/Context/Support/CodeConfigApplicationContext.cs +++ b/src/Spring/Spring.Core/Context/Support/CodeConfigApplicationContext.cs @@ -20,73 +20,72 @@ using Spring.Objects.Factory.Support; -namespace Spring.Context.Support +namespace Spring.Context.Support; + +/// +/// ApplicationContext that can scan to identify object definitions +/// +public class CodeConfigApplicationContext : GenericApplicationContext { /// - /// ApplicationContext that can scan to identify object definitions + /// Initializes a new instance of the class. /// - public class CodeConfigApplicationContext : GenericApplicationContext + public CodeConfigApplicationContext() { - /// - /// Initializes a new instance of the class. - /// - public CodeConfigApplicationContext() - { - } - - /// - /// Initializes a new instance of the class. - /// - /// if set to true names in the context are case sensitive. - public CodeConfigApplicationContext(bool caseSensitive) - : base(caseSensitive) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The object factory instance to use for this context. - public CodeConfigApplicationContext(DefaultListableObjectFactory objectFactory) - : base(objectFactory) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The parent application context. - public CodeConfigApplicationContext(IApplicationContext parent) - : base(parent) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The name of the application context.if set to true names in the context are case sensitive.The parent application context. - public CodeConfigApplicationContext(string name, bool caseSensitive, IApplicationContext parent) - : base(name, caseSensitive, parent) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The object factory to use for this contextThe parent applicaiton context. - public CodeConfigApplicationContext(DefaultListableObjectFactory objectFactory, IApplicationContext parent) - : base(objectFactory, parent) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The name of the application context.if set to true names in the context are case sensitive.The parent application context.The object factory to use for this context - public CodeConfigApplicationContext(string name, bool caseSensitive, IApplicationContext parent, - DefaultListableObjectFactory objectFactory) - : base(name, caseSensitive, parent, objectFactory) - { - } } -} \ No newline at end of file + + /// + /// Initializes a new instance of the class. + /// + /// if set to true names in the context are case sensitive. + public CodeConfigApplicationContext(bool caseSensitive) + : base(caseSensitive) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The object factory instance to use for this context. + public CodeConfigApplicationContext(DefaultListableObjectFactory objectFactory) + : base(objectFactory) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The parent application context. + public CodeConfigApplicationContext(IApplicationContext parent) + : base(parent) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The name of the application context.if set to true names in the context are case sensitive.The parent application context. + public CodeConfigApplicationContext(string name, bool caseSensitive, IApplicationContext parent) + : base(name, caseSensitive, parent) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The object factory to use for this contextThe parent applicaiton context. + public CodeConfigApplicationContext(DefaultListableObjectFactory objectFactory, IApplicationContext parent) + : base(objectFactory, parent) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The name of the application context.if set to true names in the context are case sensitive.The parent application context.The object factory to use for this context + public CodeConfigApplicationContext(string name, bool caseSensitive, IApplicationContext parent, + DefaultListableObjectFactory objectFactory) + : base(name, caseSensitive, parent, objectFactory) + { + } +} diff --git a/src/Spring/Spring.Core/Context/Support/ContextHandler.cs b/src/Spring/Spring.Core/Context/Support/ContextHandler.cs index f8be41c8..2facc8bd 100644 --- a/src/Spring/Spring.Core/Context/Support/ContextHandler.cs +++ b/src/Spring/Spring.Core/Context/Support/ContextHandler.cs @@ -31,619 +31,628 @@ using Spring.Util; #endregion -namespace Spring.Context.Support +namespace Spring.Context.Support; + +/// +/// Creates an instance +/// using context definitions supplied in a custom configuration and +/// configures the with that instance. +/// +/// +/// Implementations of the +/// interface must provide the following two constructors: +/// +/// +/// +/// A constructor that takes a string array of resource locations. +/// +/// +/// +/// +/// A constructor that takes a reference to a parent application context +/// and a string array of resource locations (and in that order). +/// +/// +/// +///

+/// Note that if the type attribute is not present in the declaration +/// of a particular context, then a default +/// +/// is assumed. This default +/// +/// is currently the +/// ; please note the exact +/// of this default is an +/// implementation detail, that, while unlikely, may do so in the future. +/// to +///

+///
+/// +///

+/// This is an example of specifying a context that reads its resources from +/// an embedded Spring.NET XML object configuration file... +///

+/// +/// +/// +/// +///
+/// +/// +/// +/// +/// +/// +/// +/// +/// +///

+/// This is an example of specifying a context that reads its resources from +/// a custom configuration section within the same application / web +/// configuration file and uses case insensitive object lookups. +///

+///

+/// Please note that you must adhere to the naming +/// of the various sections (i.e. '<sectionGroup name="spring">' and +/// '<section name="context">'. +///

+/// +/// +/// +/// +///
+///
+/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +///

+/// And this is an example of specifying a hierarchy of contexts. The +/// hierarchy in this case is only a simple parent->child hierarchy, but +/// hopefully it illustrates the nesting of context configurations. This +/// nesting of contexts can be arbitrarily deep, and is one way... child +/// contexts know about their parent contexts, but parent contexts do not +/// know how many child contexts they have (if any), or have references +/// to any such child contexts. +///

+/// +/// +/// +/// +///
+///
+/// +///
+/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// Mark Pollack +/// Aleksandar Seovic +/// Rick Evans +/// +public class ContextHandler : IConfigurationSectionHandler { - /// - /// Creates an instance - /// using context definitions supplied in a custom configuration and - /// configures the with that instance. - /// - /// - /// Implementations of the - /// interface must provide the following two constructors: - /// - /// - /// - /// A constructor that takes a string array of resource locations. - /// - /// - /// - /// - /// A constructor that takes a reference to a parent application context - /// and a string array of resource locations (and in that order). - /// - /// - /// - ///

- /// Note that if the type attribute is not present in the declaration - /// of a particular context, then a default - /// - /// is assumed. This default - /// - /// is currently the - /// ; please note the exact - /// of this default is an - /// implementation detail, that, while unlikely, may do so in the future. - /// to - ///

- ///
- /// - ///

- /// This is an example of specifying a context that reads its resources from - /// an embedded Spring.NET XML object configuration file... - ///

- /// - /// - /// - /// - ///
- /// - /// - /// - /// - /// - /// - /// - /// - /// - ///

- /// This is an example of specifying a context that reads its resources from - /// a custom configuration section within the same application / web - /// configuration file and uses case insensitive object lookups. - ///

- ///

- /// Please note that you must adhere to the naming - /// of the various sections (i.e. '<sectionGroup name="spring">' and - /// '<section name="context">'. - ///

- /// - /// - /// - /// - ///
- ///
- /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - ///

- /// And this is an example of specifying a hierarchy of contexts. The - /// hierarchy in this case is only a simple parent->child hierarchy, but - /// hopefully it illustrates the nesting of context configurations. This - /// nesting of contexts can be arbitrarily deep, and is one way... child - /// contexts know about their parent contexts, but parent contexts do not - /// know how many child contexts they have (if any), or have references - /// to any such child contexts. - ///

- /// - /// - /// - /// - ///
- ///
- /// - ///
- /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// Mark Pollack - /// Aleksandar Seovic - /// Rick Evans - /// - public class ContextHandler : IConfigurationSectionHandler - { - private static readonly ILogger Log = LogManager.GetLogger(); - - /// - /// The of - /// created if no type attribute is specified on a context element. - /// - /// - protected virtual Type DefaultApplicationContextType - { - get { return typeof (XmlApplicationContext); } - } + private static readonly ILogger Log = LogManager.GetLogger(); - /// - /// Get the context's case-sensitivity to use if none is specified - /// - /// - ///

- /// Derived handlers may override this property to change their default case-sensitivity. - ///

- ///

- /// Defaults to 'true'. - ///

- ///
- protected virtual bool DefaultCaseSensitivity - { - get { return true; } - } - - /// - /// Specifies, whether the instantiated context will be automatically registered in the - /// global . - /// - protected virtual bool AutoRegisterWithContextRegistry - { - get { return true; } - } + /// + /// The of + /// created if no type attribute is specified on a context element. + /// + /// + protected virtual Type DefaultApplicationContextType + { + get { return typeof(XmlApplicationContext); } + } - /// - /// Creates an instance - /// using the context definitions supplied in a custom - /// configuration section. - /// - /// - ///

- /// This instance is - /// also used to configure the . - ///

- ///
- /// - /// The configuration settings in a corresponding parent - /// configuration section. - /// - /// - /// The configuration context when called from the ASP.NET - /// configuration system. Otherwise, this parameter is reserved and - /// is . - /// - /// - /// The for the section. - /// - /// - /// An instance - /// populated with the object definitions supplied in the configuration - /// section. - /// - public object Create(object parent, object configContext, XmlNode section) - { - XmlElement contextElement = section as XmlElement; + /// + /// Get the context's case-sensitivity to use if none is specified + /// + /// + ///

+ /// Derived handlers may override this property to change their default case-sensitivity. + ///

+ ///

+ /// Defaults to 'true'. + ///

+ ///
+ protected virtual bool DefaultCaseSensitivity + { + get { return true; } + } - #region Sanity Checks + /// + /// Specifies, whether the instantiated context will be automatically registered in the + /// global . + /// + protected virtual bool AutoRegisterWithContextRegistry + { + get { return true; } + } - if (contextElement == null) - { - throw ConfigurationUtils.CreateConfigurationException( - "Context configuration section must be an XmlElement."); - } + /// + /// Creates an instance + /// using the context definitions supplied in a custom + /// configuration section. + /// + /// + ///

+ /// This instance is + /// also used to configure the . + ///

+ ///
+ /// + /// The configuration settings in a corresponding parent + /// configuration section. + /// + /// + /// The configuration context when called from the ASP.NET + /// configuration system. Otherwise, this parameter is reserved and + /// is . + /// + /// + /// The for the section. + /// + /// + /// An instance + /// populated with the object definitions supplied in the configuration + /// section. + /// + public object Create(object parent, object configContext, XmlNode section) + { + XmlElement contextElement = section as XmlElement; - // sanity check on parent - if ( (parent != null) && !(parent is IApplicationContext) ) - { - throw ConfigurationUtils.CreateConfigurationException( - String.Format("Parent context must be of type IApplicationContext, but was '{0}'", parent.GetType().FullName)); - } + #region Sanity Checks - #endregion - - // determine name of context to be created - string contextName = GetContextName(configContext, contextElement); - if (!StringUtils.HasLength(contextName)) - { - contextName = AbstractApplicationContext.DefaultRootContextName; - } - - #region Instrumentation - if (Log.IsEnabled(LogLevel.Debug)) Log.LogDebug(string.Format("creating context '{0}'", contextName )); - #endregion - - IApplicationContext context = null; - try - { - IApplicationContext parentContext = parent as IApplicationContext; - - // determine context type - Type contextType = GetContextType(contextElement, parentContext); + if (contextElement == null) + { + throw ConfigurationUtils.CreateConfigurationException( + "Context configuration section must be an XmlElement."); + } - // determine case-sensitivity - bool caseSensitive = GetCaseSensitivity(contextElement); + // sanity check on parent + if ((parent != null) && !(parent is IApplicationContext)) + { + throw ConfigurationUtils.CreateConfigurationException( + String.Format("Parent context must be of type IApplicationContext, but was '{0}'", parent.GetType().FullName)); + } - // get resource-list - IList resources = GetResources(contextElement); - - // finally create the context instance - context = InstantiateContext(parentContext, configContext, contextName, contextType, caseSensitive, resources); - // and register with global context registry - if (AutoRegisterWithContextRegistry && !ContextRegistry.IsContextRegistered(context.Name)) - { - ContextRegistry.RegisterContext(context); - } + #endregion - // get and create child context definitions - IList childContexts = GetChildContexts(contextElement); - CreateChildContexts(context, configContext, childContexts); + // determine name of context to be created + string contextName = GetContextName(configContext, contextElement); + if (!StringUtils.HasLength(contextName)) + { + contextName = AbstractApplicationContext.DefaultRootContextName; + } - if (Log.IsEnabled(LogLevel.Debug)) Log.LogDebug(string.Format("context '{0}' created for name '{1}'", context, contextName)); - } - catch (Exception ex) - { - if (!ConfigurationUtils.IsConfigurationException(ex)) - { - throw ConfigurationUtils.CreateConfigurationException( - String.Format("Error creating context '{0}': {1}", - contextName, ReflectionUtils.GetExplicitBaseException(ex).Message), ex); - } - throw; - } - return context; - } + #region Instrumentation - /// - /// Create all child-contexts in the given for the given context. - /// - /// The parent context to use - /// The current configContext - /// The list of child context elements - protected virtual void CreateChildContexts(IApplicationContext parentContext, object configContext, IList childContexts) - { - // create child contexts for 'the most recently created context'... - foreach (XmlNode childContext in childContexts) - { - this.Create(parentContext, configContext, childContext); - } - } + if (Log.IsEnabled(LogLevel.Debug)) Log.LogDebug(string.Format("creating context '{0}'", contextName)); - /// - /// Instantiates a new context. - /// - protected virtual IApplicationContext InstantiateContext(IApplicationContext parentContext, object configContext, string contextName, Type contextType, bool caseSensitive, IList resources) - { - IApplicationContext context; - ContextInstantiator instantiator; - - if (parentContext == null) - { - instantiator = new RootContextInstantiator(contextType, contextName, caseSensitive, new List(resources).ToArray()); - } - else - { - instantiator = new DescendantContextInstantiator(parentContext, contextType, contextName, caseSensitive, new List(resources).ToArray()); - } - - if (IsLazy) - { - // TODO - } - context = instantiator.InstantiateContext(); - return context; - } + #endregion - /// - /// Gets the context's name specified in the name attribute of the context element. - /// - /// The current configContext - /// The context element - protected virtual string GetContextName(object configContext, XmlElement contextElement) - { - string contextName; - contextName = contextElement.GetAttribute(ContextSchema.NameAttribute); - return contextName; - } - - /// - /// Extracts the context-type from the context element. - /// If none is specified, returns the parent's type. - /// - private Type GetContextType(XmlElement contextElement, IApplicationContext parentContext) - { - Type contextType; - if (parentContext != null) - { - // set default context type to parent's type (allows for type inheritance) - contextType = GetConfiguredContextType(contextElement, parentContext.GetType()); - } - else - { - contextType = GetConfiguredContextType(contextElement, this.DefaultApplicationContextType); - } - return contextType; - } + IApplicationContext context = null; + try + { + IApplicationContext parentContext = parent as IApplicationContext; - /// - /// Extracts the case-sensitivity attribute from the context element - /// - private bool GetCaseSensitivity(XmlElement contextElement) - { - bool caseSensitive = DefaultCaseSensitivity; - - string caseSensitiveAttr = contextElement.GetAttribute(ContextSchema.CaseSensitiveAttribute); - if (StringUtils.HasText(caseSensitiveAttr)) - { - caseSensitive = Boolean.Parse(caseSensitiveAttr); - } - return caseSensitive; - } + // determine context type + Type contextType = GetContextType(contextElement, parentContext); - /// - /// Gets the context specified in the type - /// attribute of the context element. - /// - /// - ///

- /// If this attribute is not defined it defaults to the - /// type. - ///

- ///
- /// - /// If the context type does not implement the - /// interface. - /// - private Type GetConfiguredContextType(XmlElement contextElement, Type defaultContextType) - { - string typeName = contextElement.GetAttribute(ContextSchema.TypeAttribute); - - if (StringUtils.IsNullOrEmpty(typeName)) + // determine case-sensitivity + bool caseSensitive = GetCaseSensitivity(contextElement); + + // get resource-list + IList resources = GetResources(contextElement); + + // finally create the context instance + context = InstantiateContext(parentContext, configContext, contextName, contextType, caseSensitive, resources); + // and register with global context registry + if (AutoRegisterWithContextRegistry && !ContextRegistry.IsContextRegistered(context.Name)) { - return defaultContextType; + ContextRegistry.RegisterContext(context); + } + + // get and create child context definitions + IList childContexts = GetChildContexts(contextElement); + CreateChildContexts(context, configContext, childContexts); + + if (Log.IsEnabled(LogLevel.Debug)) Log.LogDebug(string.Format("context '{0}' created for name '{1}'", context, contextName)); + } + catch (Exception ex) + { + if (!ConfigurationUtils.IsConfigurationException(ex)) + { + throw ConfigurationUtils.CreateConfigurationException( + String.Format("Error creating context '{0}': {1}", + contextName, ReflectionUtils.GetExplicitBaseException(ex).Message), ex); + } + + throw; + } + + return context; + } + + /// + /// Create all child-contexts in the given for the given context. + /// + /// The parent context to use + /// The current configContext + /// The list of child context elements + protected virtual void CreateChildContexts(IApplicationContext parentContext, object configContext, IList childContexts) + { + // create child contexts for 'the most recently created context'... + foreach (XmlNode childContext in childContexts) + { + this.Create(parentContext, configContext, childContext); + } + } + + /// + /// Instantiates a new context. + /// + protected virtual IApplicationContext InstantiateContext(IApplicationContext parentContext, object configContext, string contextName, Type contextType, bool caseSensitive, IList resources) + { + IApplicationContext context; + ContextInstantiator instantiator; + + if (parentContext == null) + { + instantiator = new RootContextInstantiator(contextType, contextName, caseSensitive, new List(resources).ToArray()); + } + else + { + instantiator = new DescendantContextInstantiator(parentContext, contextType, contextName, caseSensitive, new List(resources).ToArray()); + } + + if (IsLazy) + { + // TODO + } + + context = instantiator.InstantiateContext(); + return context; + } + + /// + /// Gets the context's name specified in the name attribute of the context element. + /// + /// The current configContext + /// The context element + protected virtual string GetContextName(object configContext, XmlElement contextElement) + { + string contextName; + contextName = contextElement.GetAttribute(ContextSchema.NameAttribute); + return contextName; + } + + /// + /// Extracts the context-type from the context element. + /// If none is specified, returns the parent's type. + /// + private Type GetContextType(XmlElement contextElement, IApplicationContext parentContext) + { + Type contextType; + if (parentContext != null) + { + // set default context type to parent's type (allows for type inheritance) + contextType = GetConfiguredContextType(contextElement, parentContext.GetType()); + } + else + { + contextType = GetConfiguredContextType(contextElement, this.DefaultApplicationContextType); + } + + return contextType; + } + + /// + /// Extracts the case-sensitivity attribute from the context element + /// + private bool GetCaseSensitivity(XmlElement contextElement) + { + bool caseSensitive = DefaultCaseSensitivity; + + string caseSensitiveAttr = contextElement.GetAttribute(ContextSchema.CaseSensitiveAttribute); + if (StringUtils.HasText(caseSensitiveAttr)) + { + caseSensitive = Boolean.Parse(caseSensitiveAttr); + } + + return caseSensitive; + } + + /// + /// Gets the context specified in the type + /// attribute of the context element. + /// + /// + ///

+ /// If this attribute is not defined it defaults to the + /// type. + ///

+ ///
+ /// + /// If the context type does not implement the + /// interface. + /// + private Type GetConfiguredContextType(XmlElement contextElement, Type defaultContextType) + { + string typeName = contextElement.GetAttribute(ContextSchema.TypeAttribute); + + if (StringUtils.IsNullOrEmpty(typeName)) + { + return defaultContextType; + } + else + { + Type type = TypeResolutionUtils.ResolveType(typeName); + if (typeof(IApplicationContext).IsAssignableFrom(type)) + { + return type; } else { - Type type = TypeResolutionUtils.ResolveType(typeName); - if (typeof(IApplicationContext).IsAssignableFrom(type)) - { - return type; - } - else - { - throw new TypeMismatchException( type.Name + " does not implement IApplicationContext."); - } + throw new TypeMismatchException(type.Name + " does not implement IApplicationContext."); } - } + } + } - /// - /// Returns if the context should be lazily - /// initialized. - /// - private bool IsLazy - { - get { return false; } - } + /// + /// Returns if the context should be lazily + /// initialized. + /// + private bool IsLazy + { + get { return false; } + } - /// - /// Returns the array of resources containing object definitions for - /// this context. - /// - private IList GetResources( XmlElement contextElement ) - { - List resourceNodes = new List(contextElement.ChildNodes.Count); - foreach (XmlNode possibleResourceNode in contextElement.ChildNodes) - { - XmlElement possibleResourceElement = possibleResourceNode as XmlElement; - if(possibleResourceElement != null && - possibleResourceElement.LocalName == ContextSchema.ResourceElement) - { - string resourceName = possibleResourceElement.GetAttribute(ContextSchema.URIAttribute); - if(StringUtils.HasText(resourceName)) - { - resourceNodes.Add(resourceName); - } - } - } - return resourceNodes; - } - - /// - /// Returns the array of child contexts for this context. - /// - private IList GetChildContexts(XmlElement contextElement) + /// + /// Returns the array of resources containing object definitions for + /// this context. + /// + private IList GetResources(XmlElement contextElement) + { + List resourceNodes = new List(contextElement.ChildNodes.Count); + foreach (XmlNode possibleResourceNode in contextElement.ChildNodes) { - List contextNodes = new List(contextElement.ChildNodes.Count); - foreach (XmlNode possibleContextNode in contextElement.ChildNodes) + XmlElement possibleResourceElement = possibleResourceNode as XmlElement; + if (possibleResourceElement != null && + possibleResourceElement.LocalName == ContextSchema.ResourceElement) { - XmlElement possibleContextElement = possibleContextNode as XmlElement; - if (possibleContextElement != null && - possibleContextElement.LocalName == ContextSchema.ContextElement) + string resourceName = possibleResourceElement.GetAttribute(ContextSchema.URIAttribute); + if (StringUtils.HasText(resourceName)) { - contextNodes.Add(possibleContextElement); + resourceNodes.Add(resourceName); } } - return contextNodes; } - #region Inner Class : ContextInstantiator + return resourceNodes; + } - private abstract class ContextInstantiator - { - protected ContextInstantiator( - Type contextType, string contextName, bool caseSensitive, string[] resources) - { - _contextType = contextType; - _contextName = contextName; - _caseSensitive = caseSensitive; - _resources = resources; - } - - public IApplicationContext InstantiateContext() + /// + /// Returns the array of child contexts for this context. + /// + private IList GetChildContexts(XmlElement contextElement) + { + List contextNodes = new List(contextElement.ChildNodes.Count); + foreach (XmlNode possibleContextNode in contextElement.ChildNodes) + { + XmlElement possibleContextElement = possibleContextNode as XmlElement; + if (possibleContextElement != null && + possibleContextElement.LocalName == ContextSchema.ContextElement) { - ConstructorInfo ctor = GetContextConstructor(); - if (ctor == null) - { - string errorMessage = "No constructor with string[] argument found for context type [" + ContextType.Name + "]"; - throw ConfigurationUtils.CreateConfigurationException(errorMessage); - } - IApplicationContext context = InvokeContextConstructor(ctor); - return context; + contextNodes.Add(possibleContextElement); + } + } + + return contextNodes; + } + + #region Inner Class : ContextInstantiator + + private abstract class ContextInstantiator + { + protected ContextInstantiator( + Type contextType, string contextName, bool caseSensitive, string[] resources) + { + _contextType = contextType; + _contextName = contextName; + _caseSensitive = caseSensitive; + _resources = resources; + } + + public IApplicationContext InstantiateContext() + { + ConstructorInfo ctor = GetContextConstructor(); + if (ctor == null) + { + string errorMessage = "No constructor with string[] argument found for context type [" + ContextType.Name + "]"; + throw ConfigurationUtils.CreateConfigurationException(errorMessage); } - protected abstract ConstructorInfo GetContextConstructor(); + IApplicationContext context = InvokeContextConstructor(ctor); + return context; + } - protected abstract IApplicationContext InvokeContextConstructor( - ConstructorInfo ctor); + protected abstract ConstructorInfo GetContextConstructor(); - protected Type ContextType - { - get { return _contextType; } - } + protected abstract IApplicationContext InvokeContextConstructor( + ConstructorInfo ctor); - protected string ContextName - { - get { return _contextName; } - } + protected Type ContextType + { + get { return _contextType; } + } - protected bool CaseSensitive - { - get { return _caseSensitive; } - } + protected string ContextName + { + get { return _contextName; } + } - protected IList Resources - { - get { return _resources; } - } + protected bool CaseSensitive + { + get { return _caseSensitive; } + } - private Type _contextType; - private string _contextName; - private bool _caseSensitive; - private IList _resources; - } + protected IList Resources + { + get { return _resources; } + } - #endregion + private Type _contextType; + private string _contextName; + private bool _caseSensitive; + private IList _resources; + } - #region Inner Class : RootContextInstantiator + #endregion - private sealed class RootContextInstantiator : ContextInstantiator - { - public RootContextInstantiator( - Type contextType, string contextName, bool caseSensitive, string[] resources) - : base(contextType, contextName, caseSensitive, resources) - { - } + #region Inner Class : RootContextInstantiator - protected override ConstructorInfo GetContextConstructor() - { - return ContextType.GetConstructor(new Type[] {typeof(string), typeof(bool), typeof(string[])}); - } + private sealed class RootContextInstantiator : ContextInstantiator + { + public RootContextInstantiator( + Type contextType, string contextName, bool caseSensitive, string[] resources) + : base(contextType, contextName, caseSensitive, resources) + { + } - protected override IApplicationContext InvokeContextConstructor( - ConstructorInfo ctor) - { - return (IApplicationContext)(new SafeConstructor(ctor).Invoke(new object[] {ContextName, CaseSensitive, Resources})); - } - } + protected override ConstructorInfo GetContextConstructor() + { + return ContextType.GetConstructor(new Type[] { typeof(string), typeof(bool), typeof(string[]) }); + } - #endregion + protected override IApplicationContext InvokeContextConstructor( + ConstructorInfo ctor) + { + return (IApplicationContext) (new SafeConstructor(ctor).Invoke(new object[] { ContextName, CaseSensitive, Resources })); + } + } - #region Inner Class : DescendantContextInstantiator + #endregion - private sealed class DescendantContextInstantiator : ContextInstantiator - { - public DescendantContextInstantiator( - IApplicationContext parentContext, Type contextType, - string contextName, bool caseSensitive, string[] resources) - : base(contextType, contextName, caseSensitive, resources) - { - this.parentContext = parentContext; - } + #region Inner Class : DescendantContextInstantiator - protected override ConstructorInfo GetContextConstructor() - { - return ContextType.GetConstructor( - new Type[] {typeof(string), typeof(bool), typeof(IApplicationContext), typeof(string[])}); - } + private sealed class DescendantContextInstantiator : ContextInstantiator + { + public DescendantContextInstantiator( + IApplicationContext parentContext, Type contextType, + string contextName, bool caseSensitive, string[] resources) + : base(contextType, contextName, caseSensitive, resources) + { + this.parentContext = parentContext; + } - protected override IApplicationContext InvokeContextConstructor( - ConstructorInfo ctor) - { - return (IApplicationContext)(new SafeConstructor(ctor).Invoke(new object[] {ContextName, CaseSensitive, this.parentContext, Resources})); - } + protected override ConstructorInfo GetContextConstructor() + { + return ContextType.GetConstructor( + new Type[] { typeof(string), typeof(bool), typeof(IApplicationContext), typeof(string[]) }); + } - private IApplicationContext parentContext; - } + protected override IApplicationContext InvokeContextConstructor( + ConstructorInfo ctor) + { + return (IApplicationContext) (new SafeConstructor(ctor).Invoke(new object[] { ContextName, CaseSensitive, this.parentContext, Resources })); + } - #endregion + private IApplicationContext parentContext; + } - #region Context Schema Constants + #endregion - /// - /// Constants defining the structure and values associated with the - /// schema for laying out Spring.NET contexts in XML. - /// - private sealed class ContextSchema - { - /// - /// Defines a single - /// . - /// - public const string ContextElement = "context"; + #region Context Schema Constants - /// - /// Specifies a context name. - /// - public const string NameAttribute = "name"; + /// + /// Constants defining the structure and values associated with the + /// schema for laying out Spring.NET contexts in XML. + /// + private sealed class ContextSchema + { + /// + /// Defines a single + /// . + /// + public const string ContextElement = "context"; - /// - /// Specifies if context should be case sensitive or not. Default is true. - /// - public const string CaseSensitiveAttribute = "caseSensitive"; + /// + /// Specifies a context name. + /// + public const string NameAttribute = "name"; - /// - /// Specifies a . - /// - /// - ///

- /// Does not have to be fully assembly qualified, but its generally regarded - /// as better form if the names of one's objects - /// are specified explicitly. - ///

- ///
- public const string TypeAttribute = "type"; + /// + /// Specifies if context should be case sensitive or not. Default is true. + /// + public const string CaseSensitiveAttribute = "caseSensitive"; - /// - /// Specifies whether context should be lazy initialized. - /// - public const string LazyAttribute = "lazy"; + /// + /// Specifies a . + /// + /// + ///

+ /// Does not have to be fully assembly qualified, but its generally regarded + /// as better form if the names of one's objects + /// are specified explicitly. + ///

+ ///
+ public const string TypeAttribute = "type"; - /// - /// Defines an - /// - public const string ResourceElement = "resource"; + /// + /// Specifies whether context should be lazy initialized. + /// + public const string LazyAttribute = "lazy"; - /// - /// Specifies the URI for an - /// . - /// - public const string URIAttribute = "uri"; - } + /// + /// Defines an + /// + public const string ResourceElement = "resource"; - #endregion - } + /// + /// Specifies the URI for an + /// . + /// + public const string URIAttribute = "uri"; + } + + #endregion } diff --git a/src/Spring/Spring.Core/Context/Support/ContextRegistry.cs b/src/Spring/Spring.Core/Context/Support/ContextRegistry.cs index 46478f90..b82e679d 100644 --- a/src/Spring/Spring.Core/Context/Support/ContextRegistry.cs +++ b/src/Spring/Spring.Core/Context/Support/ContextRegistry.cs @@ -22,370 +22,366 @@ using Microsoft.Extensions.Logging; using Spring.Context.Events; using Spring.Util; -namespace Spring.Context.Support +namespace Spring.Context.Support; + +/// +/// Provides access to a central registry of +/// s. +/// +/// +///

+/// A singleton implementation to access one or more application contexts. Application +/// context instances are cached. +///

+///

Note that the use of this class or similar is unnecessary except (sometimes) for +/// a small amount of glue code. Excessive usage will lead to code that is more tightly +/// coupled, and harder to modify or test. Consider refactoring your code to use standard +/// Dependency Injection techniques or implement the interface IApplicationContextAware to +/// obtain a reference to an application context.

+///
+/// Mark Pollack +/// Aleksandar Seovic +/// +public sealed class ContextRegistry { /// - /// Provides access to a central registry of - /// s. + /// The shared instance for this class (and derived classes). + /// + private static readonly ILogger log = LogManager.GetLogger(); + + private static readonly object syncRoot = new Object(); + private static readonly ContextRegistry instance = new ContextRegistry(); + private static string rootContextName = null; + + private IDictionary contextMap = new Dictionary(StringComparer.OrdinalIgnoreCase); + + #region Constructor (s) / Destructor + + // CLOVER:OFF + + /// + /// Creates a new instance of the ContextRegistry class. /// /// ///

- /// A singleton implementation to access one or more application contexts. Application - /// context instances are cached. + /// Explicit static constructor to tell C# compiler + /// not to mark type as beforefieldinit. ///

- ///

Note that the use of this class or similar is unnecessary except (sometimes) for - /// a small amount of glue code. Excessive usage will lead to code that is more tightly - /// coupled, and harder to modify or test. Consider refactoring your code to use standard - /// Dependency Injection techniques or implement the interface IApplicationContextAware to - /// obtain a reference to an application context.

///
- /// Mark Pollack - /// Aleksandar Seovic - /// - public sealed class ContextRegistry + static ContextRegistry() { - /// - /// The shared instance for this class (and derived classes). - /// - private static readonly ILogger log = LogManager.GetLogger(); + } - private static readonly object syncRoot = new Object(); - private static readonly ContextRegistry instance = new ContextRegistry(); - private static string rootContextName = null; + // CLOVER:ON - private IDictionary contextMap = new Dictionary(StringComparer.OrdinalIgnoreCase); + #endregion - #region Constructor (s) / Destructor + /// + /// This event is fired, if ContextRegistry.Clear() is called.
+ /// Clients may register to get informed + ///
+ /// + /// This event is fired while still holding a lock on the Registry.
+ /// 'sender' parameter is sent as typeof(ContextRegistry), EventArgs are not used + ///
+ public static event EventHandler Cleared; - // CLOVER:OFF + /// + /// Gets an object that should be used to synchronize access to ContextRegistry + /// from the calling code. + /// + public static object SyncRoot + { + get { return syncRoot; } + } - /// - /// Creates a new instance of the ContextRegistry class. - /// - /// - ///

- /// Explicit static constructor to tell C# compiler - /// not to mark type as beforefieldinit. - ///

- ///
- static ContextRegistry() - { } + private static void ConstructNestedDefaultContextName(IApplicationContext context) + { + IApplicationContext parent = context.ParentContext; - // CLOVER:ON + Dictionary contexts = new Dictionary(); - #endregion + int contextIndex = 0; - /// - /// This event is fired, if ContextRegistry.Clear() is called.
- /// Clients may register to get informed - ///
- /// - /// This event is fired while still holding a lock on the Registry.
- /// 'sender' parameter is sent as typeof(ContextRegistry), EventArgs are not used - ///
- public static event EventHandler Cleared; + contexts.Add(contextIndex, context); - /// - /// Gets an object that should be used to synchronize access to ContextRegistry - /// from the calling code. - /// - public static object SyncRoot + while (parent != null) { - get { return syncRoot; } + contextIndex++; + contexts.Add(contextIndex, parent); + parent = parent.ParentContext; } - private static void ConstructNestedDefaultContextName(IApplicationContext context) + string prefix = string.Empty; + + for (int i = contextIndex; i > 0; i--) { - IApplicationContext parent = context.ParentContext; + IApplicationContext contextToUpdate = contexts[i]; - Dictionary contexts = new Dictionary(); + if (prefix != string.Empty) + prefix = string.Format("{0}/{1}", prefix, contextToUpdate.Name); + else + prefix = contextToUpdate.Name; + } - int contextIndex = 0; + context.Name = string.Format("{0}/{1}", prefix, context.Name); + } - contexts.Add(contextIndex, context); + private static void EnsureHierarchicalNameIfDefault(IApplicationContext context) + { + //if there is no parent context there is no change needed + if (context.ParentContext == null) + return; - while (parent != null) + if (context.Name == AbstractApplicationContext.DefaultRootContextName) + ConstructNestedDefaultContextName(context); + } + + /// + /// Registers an instance of an + /// . + /// + /// + ///

+ /// This is usually called via a + /// inside a .NET + /// application configuration file. + ///

+ ///
+ /// The application context to be registered. + /// + /// If a context has previously been registered using the same name + /// + public static void RegisterContext(IApplicationContext context) + { + EnsureHierarchicalNameIfDefault(context); + + lock (syncRoot) + { + IApplicationContext ctx; + if (instance.contextMap.TryGetValue(context.Name, out ctx)) { - contextIndex++; - contexts.Add(contextIndex, parent); - parent = parent.ParentContext; + throw new ApplicationContextException(string.Format("Existing context '{0}' already registered under name '{1}'.", ctx, context.Name)); } - string prefix = string.Empty; + instance.contextMap[context.Name] = context; + context.ContextEvent += OnContextEvent; - for (int i = contextIndex; i > 0; i--) + #region Instrumentation + + if (log.IsEnabled(LogLevel.Debug)) { - IApplicationContext contextToUpdate = contexts[i]; - - if (prefix != string.Empty) - prefix = string.Format("{0}/{1}", prefix, contextToUpdate.Name); - else - prefix = contextToUpdate.Name; - + log.LogDebug(String.Format("Registering context '{0}' under name '{1}'.", context, context.Name)); } - context.Name = string.Format("{0}/{1}", prefix, context.Name); + #endregion + + if (rootContextName == null) + { + rootContextName = context.Name; + } } + } - private static void EnsureHierarchicalNameIfDefault(IApplicationContext context) + /// + /// Handles events raised by an application context. + /// + /// + /// + private static void OnContextEvent(object sender, ApplicationEventArgs e) + { + ContextEventArgs cea = e as ContextEventArgs; + if (cea != null + && cea.Event == ContextEventArgs.ContextEvent.Closed + && sender is IApplicationContext) { - //if there is no parent context there is no change needed - if (context.ParentContext == null) - return; - - if (context.Name == AbstractApplicationContext.DefaultRootContextName) - ConstructNestedDefaultContextName(context); - + // we know the context is registered! + UnregisterContext((IApplicationContext) sender); } + } - - /// - /// Registers an instance of an - /// . - /// - /// - ///

- /// This is usually called via a - /// inside a .NET - /// application configuration file. - ///

- ///
- /// The application context to be registered. - /// - /// If a context has previously been registered using the same name - /// - public static void RegisterContext(IApplicationContext context) + /// + /// Removes the context from the registry + /// + /// + /// Has no effect if the context wasn't registered + /// + /// The context to remove from the registry + private static void UnregisterContext(IApplicationContext context) + { + AssertUtils.ArgumentNotNull(context, "context"); + lock (syncRoot) { + if (IsContextRegistered(context.Name)) + { + instance.contextMap.Remove(context.Name); + if (rootContextName == context.Name) + { + rootContextName = null; + } + } + } + } - EnsureHierarchicalNameIfDefault(context); + /// + /// Returns the root application context. + /// + /// + ///

+ /// The first call to GetContext will create the context + /// as specified in the .NET application configuration file + /// under the location spring/context. + ///

+ ///
+ /// The root application context. + public static IApplicationContext GetContext() + { + lock (syncRoot) + { + InitializeContextIfNeeded(); + if (rootContextName == null) + { + throw new ApplicationContextException( + "No context registered. Use the 'RegisterContext' method or the 'spring/context' section from your configuration file."); + } + return GetContext(rootContextName); + } + } + + /// + /// Returns context based on specified name. + /// + /// + ///

+ /// The first call to GetContext will create the context + /// as specified in the .NET application configuration file + /// under the location spring/context. + ///

+ ///
+ /// The context name. + /// The specified context, or null, if context with that name doesn't exists. + /// + /// If the context name is null or empty + /// + public static IApplicationContext GetContext(string name) + { + if (StringUtils.IsNullOrEmpty(name)) + { + throw new ArgumentException( + "The context name passed to the GetContext method cannot be null or empty."); + } + else + { lock (syncRoot) { + InitializeContextIfNeeded(); IApplicationContext ctx; - if (instance.contextMap.TryGetValue(context.Name, out ctx)) + if (!instance.contextMap.TryGetValue(name, out ctx)) { - throw new ApplicationContextException(string.Format("Existing context '{0}' already registered under name '{1}'.", ctx, context.Name)); + throw new ApplicationContextException(String.Format( + "No context registered under name '{0}'. Use the 'RegisterContext' method or the 'spring/context' section from your configuration file.", + name)); } - instance.contextMap[context.Name] = context; - context.ContextEvent += OnContextEvent; - #region Instrumentation if (log.IsEnabled(LogLevel.Debug)) { - log.LogDebug(String.Format("Registering context '{0}' under name '{1}'.", context, context.Name)); + log.LogDebug(String.Format( + "Returning context '{0}' registered under name '{1}'.", ctx, name)); } #endregion - if (rootContextName == null) - { - rootContextName = context.Name; - } - } - } - - /// - /// Handles events raised by an application context. - /// - /// - /// - private static void OnContextEvent(object sender, ApplicationEventArgs e) - { - ContextEventArgs cea = e as ContextEventArgs; - if (cea != null - && cea.Event == ContextEventArgs.ContextEvent.Closed - && sender is IApplicationContext) - { - // we know the context is registered! - UnregisterContext((IApplicationContext)sender); - } - } - - /// - /// Removes the context from the registry - /// - /// - /// Has no effect if the context wasn't registered - /// - /// The context to remove from the registry - private static void UnregisterContext(IApplicationContext context) - { - AssertUtils.ArgumentNotNull(context, "context"); - lock (syncRoot) - { - if (IsContextRegistered(context.Name)) - { - instance.contextMap.Remove(context.Name); - if (rootContextName == context.Name) - { - rootContextName = null; - } - } - } - } - - /// - /// Returns the root application context. - /// - /// - ///

- /// The first call to GetContext will create the context - /// as specified in the .NET application configuration file - /// under the location spring/context. - ///

- ///
- /// The root application context. - public static IApplicationContext GetContext() - { - lock (syncRoot) - { - InitializeContextIfNeeded(); - if (rootContextName == null) - { - throw new ApplicationContextException( - "No context registered. Use the 'RegisterContext' method or the 'spring/context' section from your configuration file."); - } - return GetContext(rootContextName); - } - } - - /// - /// Returns context based on specified name. - /// - /// - ///

- /// The first call to GetContext will create the context - /// as specified in the .NET application configuration file - /// under the location spring/context. - ///

- ///
- /// The context name. - /// The specified context, or null, if context with that name doesn't exists. - /// - /// If the context name is null or empty - /// - public static IApplicationContext GetContext(string name) - { - if (StringUtils.IsNullOrEmpty(name)) - { - throw new ArgumentException( - "The context name passed to the GetContext method cannot be null or empty."); - } - else - { - lock (syncRoot) - { - InitializeContextIfNeeded(); - IApplicationContext ctx; - if (!instance.contextMap.TryGetValue(name, out ctx)) - { - throw new ApplicationContextException(String.Format( - "No context registered under name '{0}'. Use the 'RegisterContext' method or the 'spring/context' section from your configuration file.", - name)); - } - - #region Instrumentation - - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug(String.Format( - "Returning context '{0}' registered under name '{1}'.", ctx, name)); - } - - #endregion - - return ctx; - } - } - } - - /// - /// Removes all registered - /// s from this - /// registry. - /// - /// - /// Raises the event while still holding a lock on - /// - public static void Clear() - { - lock (syncRoot) - { - ICollection contexts = new List(instance.contextMap.Values); - foreach (IApplicationContext ctx in contexts) - { - ctx.Dispose(); - } - - // contexts will be removed from contextMap during OnContextEvent handler - // but someone might choose to override AbstractApplicationContext.Dispose() without - // calling base.Dispose() ... - if (log.IsEnabled(LogLevel.Warning)) - { - if (instance.contextMap.Count > 0) - { - log.LogWarning(String.Format( - "Not all contexts were removed from registry during cleanup - did you forget to call base.Dispose() when overriding AbstractApplicationContext.Dispose()?")); - } - } - - instance.contextMap.Clear(); - ConfigurationUtils.ClearCache(); - rootContextName = null; - // mark section dirty - force re-read from disk next time - ConfigurationUtils.RefreshSection(AbstractApplicationContext.ContextSectionName); - DynamicCodeManager.Clear(); - Cleared?.Invoke(typeof(ContextRegistry), EventArgs.Empty); - } - } - - /// - /// Allows to check, if a context is already registered - /// - /// The context name. - /// true, if the context is already registered. false otherwise - public static bool IsContextRegistered(string name) - { - lock (instance) - { - IApplicationContext temp; - instance.contextMap.TryGetValue(name, out temp); - return temp != null; - } - } - - private static bool rootContextCurrentlyInCreation; - - private static void InitializeContextIfNeeded() - { - if (rootContextName != null) - { - return; - } - - DoInitializeRootContext(); - } - - private static void DoInitializeRootContext() - { - if (rootContextCurrentlyInCreation) - { - throw new InvalidOperationException( - "root context is currently in creation. You must not call ContextRegistry.GetContext() from e.g. constructors of your singleton objects"); - } - - rootContextCurrentlyInCreation = true; - try - { - ConfigurationUtils.GetSection(AbstractApplicationContext.ContextSectionName); - } - finally - { - rootContextCurrentlyInCreation = false; + return ctx; } } } -} + /// + /// Removes all registered + /// s from this + /// registry. + /// + /// + /// Raises the event while still holding a lock on + /// + public static void Clear() + { + lock (syncRoot) + { + ICollection contexts = new List(instance.contextMap.Values); + foreach (IApplicationContext ctx in contexts) + { + ctx.Dispose(); + } + + // contexts will be removed from contextMap during OnContextEvent handler + // but someone might choose to override AbstractApplicationContext.Dispose() without + // calling base.Dispose() ... + if (log.IsEnabled(LogLevel.Warning)) + { + if (instance.contextMap.Count > 0) + { + log.LogWarning(String.Format( + "Not all contexts were removed from registry during cleanup - did you forget to call base.Dispose() when overriding AbstractApplicationContext.Dispose()?")); + } + } + + instance.contextMap.Clear(); + ConfigurationUtils.ClearCache(); + rootContextName = null; + // mark section dirty - force re-read from disk next time + ConfigurationUtils.RefreshSection(AbstractApplicationContext.ContextSectionName); + DynamicCodeManager.Clear(); + Cleared?.Invoke(typeof(ContextRegistry), EventArgs.Empty); + } + } + + /// + /// Allows to check, if a context is already registered + /// + /// The context name. + /// true, if the context is already registered. false otherwise + public static bool IsContextRegistered(string name) + { + lock (instance) + { + IApplicationContext temp; + instance.contextMap.TryGetValue(name, out temp); + return temp != null; + } + } + + private static bool rootContextCurrentlyInCreation; + + private static void InitializeContextIfNeeded() + { + if (rootContextName != null) + { + return; + } + + DoInitializeRootContext(); + } + + private static void DoInitializeRootContext() + { + if (rootContextCurrentlyInCreation) + { + throw new InvalidOperationException( + "root context is currently in creation. You must not call ContextRegistry.GetContext() from e.g. constructors of your singleton objects"); + } + + rootContextCurrentlyInCreation = true; + try + { + ConfigurationUtils.GetSection(AbstractApplicationContext.ContextSectionName); + } + finally + { + rootContextCurrentlyInCreation = false; + } + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Context/Support/DefaultMessageSourceResolvable.cs b/src/Spring/Spring.Core/Context/Support/DefaultMessageSourceResolvable.cs index b7626c6a..f8a7cd1c 100644 --- a/src/Spring/Spring.Core/Context/Support/DefaultMessageSourceResolvable.cs +++ b/src/Spring/Spring.Core/Context/Support/DefaultMessageSourceResolvable.cs @@ -21,201 +21,200 @@ using System.Globalization; using Spring.Util; -namespace Spring.Context.Support +namespace Spring.Context.Support; + +/// +/// Default implementation of the +/// interface. +/// +/// +///

+/// Provides easy ways to store all the necessary values needed to resolve +/// messages from an . +///

+///
+/// Juergen Hoeller +/// Griffin Caprio (.NET) +/// +[Serializable] +public class DefaultMessageSourceResolvable : IMessageSourceResolvable { - /// - /// Default implementation of the - /// interface. - /// - /// - ///

- /// Provides easy ways to store all the necessary values needed to resolve - /// messages from an . - ///

- ///
- /// Juergen Hoeller - /// Griffin Caprio (.NET) - /// - [Serializable] - public class DefaultMessageSourceResolvable : IMessageSourceResolvable - { - private IList codes; - private object[] arguments; - private string defaultMessage; + private IList codes; + private object[] arguments; + private string defaultMessage; - #region Constructor (s) / Destructor + #region Constructor (s) / Destructor - /// - /// Creates a new instance of the - /// class - /// using a single code. - /// - /// The message code to be resolved. - public DefaultMessageSourceResolvable(string code) - : this(new string[] {code}, StringUtils.EmptyStrings, string.Empty) - { - } + /// + /// Creates a new instance of the + /// class + /// using a single code. + /// + /// The message code to be resolved. + public DefaultMessageSourceResolvable(string code) + : this(new string[] { code }, StringUtils.EmptyStrings, string.Empty) + { + } - /// - /// Initializes a new instance of the class. - /// - /// The codes to be used to resolve this message - public DefaultMessageSourceResolvable(string[] codes) - : this(codes, StringUtils.EmptyStrings, string.Empty) + /// + /// Initializes a new instance of the class. + /// + /// The codes to be used to resolve this message + public DefaultMessageSourceResolvable(string[] codes) + : this(codes, StringUtils.EmptyStrings, string.Empty) + { + } + + /// + /// Creates a new instance of the + /// class + /// using multiple codes. + /// + /// The message codes to be resolved. + /// + /// The arguments used to resolve the supplied . + /// + public DefaultMessageSourceResolvable(string[] codes, object[] arguments) + : this(codes, arguments, string.Empty) + { + } + + /// + /// Creates a new instance of the + /// class + /// using multiple codes and a default message. + /// + /// The message codes to be resolved. + /// + /// The arguments used to resolve the supplied . + /// + /// + /// The default message used if no code could be resolved. + /// + public DefaultMessageSourceResolvable( + IList codes, object[] arguments, string defaultMessage) + { + this.codes = codes; + this.arguments = arguments; + this.defaultMessage = defaultMessage; + } + + /// + /// Creates a new instance of the + /// class + /// from another resolvable. + /// + /// + ///

+ /// This is the copy constructor for the + /// class. + ///

+ ///
+ /// + /// The to be copied. + /// + /// + /// If the supplied is . + /// + public DefaultMessageSourceResolvable(IMessageSourceResolvable resolvable) + : this(resolvable.GetCodes(), resolvable.GetArguments(), resolvable.DefaultMessage) + { + } + + #endregion + + /// + /// Return the default code for this resolvable. + /// + /// + /// The default code of this resolvable; this will be the last code in + /// the codes array, or if this instance has no + /// codes. + /// + /// + public string LastCode + { + get { + if (codes != null && codes.Count > 0) + { + return codes[codes.Count - 1]; + } + else + { + return null; + } } + } - /// - /// Creates a new instance of the - /// class - /// using multiple codes. - /// - /// The message codes to be resolved. - /// - /// The arguments used to resolve the supplied . - /// - public DefaultMessageSourceResolvable(string[] codes, object[] arguments) - : this(codes, arguments, string.Empty) - { - } + /// + /// Returns a representation of this + /// . + /// + /// + /// A representation of this + /// . + /// + public override string ToString() + { + return Accept(new MessageSourceResolvableVisitor()); + } - /// - /// Creates a new instance of the - /// class - /// using multiple codes and a default message. - /// - /// The message codes to be resolved. - /// - /// The arguments used to resolve the supplied . - /// - /// - /// The default message used if no code could be resolved. - /// - public DefaultMessageSourceResolvable( - IList codes, object[] arguments, string defaultMessage) - { - this.codes = codes; - this.arguments = arguments; - this.defaultMessage = defaultMessage; - } + /// + /// Calls the visit method on the supplied + /// to output a version of this class. + /// + /// The visitor to use. + /// + /// A representation of this + /// . + /// + public string Accept(MessageSourceResolvableVisitor visitor) + { + return visitor.VisitMessageSourceResolvableString(this); + } - /// - /// Creates a new instance of the - /// class - /// from another resolvable. - /// - /// - ///

- /// This is the copy constructor for the - /// class. - ///

- ///
- /// - /// The to be copied. - /// - /// - /// If the supplied is . - /// - public DefaultMessageSourceResolvable(IMessageSourceResolvable resolvable) - : this(resolvable.GetCodes(), resolvable.GetArguments(), resolvable.DefaultMessage) - { - } + #region IMessageSourceResolvable Members - #endregion + /// + /// Return the codes to be used to resolve this message, in the order + /// that they are to be tried. + /// + /// + /// A array of codes which are associated + /// with this message. + /// + /// + public IList GetCodes() + { + return codes; + } - /// - /// Return the default code for this resolvable. - /// - /// - /// The default code of this resolvable; this will be the last code in - /// the codes array, or if this instance has no - /// codes. - /// - /// - public string LastCode - { - get - { - if (codes != null && codes.Count > 0) - { - return codes[codes.Count - 1]; - } - else - { - return null; - } - } - } + /// + /// Return the array of arguments to be used to resolve this message. + /// + /// + /// An array of objects to be used as parameters to replace + /// placeholders within the message text. + /// + /// + public object[] GetArguments() + { + return arguments; + } - /// - /// Returns a representation of this - /// . - /// - /// - /// A representation of this - /// . - /// - public override string ToString() - { - return Accept(new MessageSourceResolvableVisitor()); - } + /// + /// Return the default message to be used to resolve this message. + /// + /// + /// The default message, or if there is no + /// default. + /// + /// + public string DefaultMessage + { + get { return defaultMessage; } + } - /// - /// Calls the visit method on the supplied - /// to output a version of this class. - /// - /// The visitor to use. - /// - /// A representation of this - /// . - /// - public string Accept(MessageSourceResolvableVisitor visitor) - { - return visitor.VisitMessageSourceResolvableString(this); - } - - #region IMessageSourceResolvable Members - - /// - /// Return the codes to be used to resolve this message, in the order - /// that they are to be tried. - /// - /// - /// A array of codes which are associated - /// with this message. - /// - /// - public IList GetCodes() - { - return codes; - } - - /// - /// Return the array of arguments to be used to resolve this message. - /// - /// - /// An array of objects to be used as parameters to replace - /// placeholders within the message text. - /// - /// - public object[] GetArguments() - { - return arguments; - } - - /// - /// Return the default message to be used to resolve this message. - /// - /// - /// The default message, or if there is no - /// default. - /// - /// - public string DefaultMessage - { - get { return defaultMessage; } - } - - #endregion - } + #endregion } diff --git a/src/Spring/Spring.Core/Context/Support/DefaultSectionHandler.cs b/src/Spring/Spring.Core/Context/Support/DefaultSectionHandler.cs index 6b157ec2..b6e8b77d 100644 --- a/src/Spring/Spring.Core/Context/Support/DefaultSectionHandler.cs +++ b/src/Spring/Spring.Core/Context/Support/DefaultSectionHandler.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -25,40 +25,41 @@ using System.Xml; #endregion -namespace Spring.Context.Support +namespace Spring.Context.Support; + +/// +/// Default section handler that can handle any configuration section. +/// +/// +///

+/// Simply returns the configuration section as an . +///

+///
+/// Aleksandar Seovic +public class DefaultSectionHandler : IConfigurationSectionHandler { + #region Methods + /// - /// Default section handler that can handle any configuration section. + /// Returns the configuration section as an /// - /// - ///

- /// Simply returns the configuration section as an . - ///

- ///
- /// Aleksandar Seovic - public class DefaultSectionHandler : IConfigurationSectionHandler + /// + /// The configuration settings in a corresponding parent + /// configuration section. + /// + /// + /// The configuration context when called from the ASP.NET + /// configuration system. Otherwise, this parameter is reserved and + /// is a null reference. + /// + /// + /// The for the section. + /// + /// Config section as XmlElement. + public object Create(object parent, object configContext, XmlNode section) { - #region Methods - /// - /// Returns the configuration section as an - /// - /// - /// The configuration settings in a corresponding parent - /// configuration section. - /// - /// - /// The configuration context when called from the ASP.NET - /// configuration system. Otherwise, this parameter is reserved and - /// is a null reference. - /// - /// - /// The for the section. - /// - /// Config section as XmlElement. - public object Create(object parent, object configContext, XmlNode section) - { - return section as XmlElement; - } - #endregion + return section as XmlElement; } -} \ No newline at end of file + + #endregion +} diff --git a/src/Spring/Spring.Core/Context/Support/DelegatingMessageSource.cs b/src/Spring/Spring.Core/Context/Support/DelegatingMessageSource.cs index 7798f81b..2c5c9638 100644 --- a/src/Spring/Spring.Core/Context/Support/DelegatingMessageSource.cs +++ b/src/Spring/Spring.Core/Context/Support/DelegatingMessageSource.cs @@ -21,366 +21,366 @@ #region Imports using System.Globalization; - using Spring.Util; #endregion -namespace Spring.Context.Support +namespace Spring.Context.Support; + +/// +/// Empty implementation that +/// simply delegates all method calls to it's parent +/// . +/// +/// +///

+/// If no parent is available, +/// no messages will be resolved (and a +/// will be thrown). +///

+///

+/// Used as placeholder by the +/// class, +/// if the context definition doesn't define its own +/// . Not intended for direct use +/// in applications. +///

+///
+/// Juergan Hoeller +/// Rick Evans (.NET) +/// +public class DelegatingMessageSource : IHierarchicalMessageSource { + #region Fields + + private IMessageSource _parentMessageSource; + + #endregion + + #region Constructor (s) / Destructor + /// - /// Empty implementation that - /// simply delegates all method calls to it's parent - /// . + /// Creates a new instance of the + /// class. /// - /// - ///

- /// If no parent is available, - /// no messages will be resolved (and a - /// will be thrown). - ///

- ///

- /// Used as placeholder by the - /// class, - /// if the context definition doesn't define its own - /// . Not intended for direct use - /// in applications. - ///

- ///
- /// Juergan Hoeller - /// Rick Evans (.NET) - /// - public class DelegatingMessageSource : IHierarchicalMessageSource + public DelegatingMessageSource() { - #region Fields + } - private IMessageSource _parentMessageSource; + /// + /// Creates a new instance of the + /// class. + /// + /// + /// The parent message source used to try and resolve messages that + /// this object can't resolve. + /// + public DelegatingMessageSource(IMessageSource parentMessageSource) + { + ParentMessageSource = parentMessageSource; + } - #endregion + #endregion - #region Constructor (s) / Destructor + #region Properties - /// - /// Creates a new instance of the - /// class. - /// - public DelegatingMessageSource() - {} - - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The parent message source used to try and resolve messages that - /// this object can't resolve. - /// - public DelegatingMessageSource(IMessageSource parentMessageSource) + /// + /// The parent message source used to try and resolve messages that + /// this object can't resolve. + /// + /// + public IMessageSource ParentMessageSource + { + get { - ParentMessageSource = parentMessageSource; - } - - #endregion - - #region Properties - - /// - /// The parent message source used to try and resolve messages that - /// this object can't resolve. - /// - /// - public IMessageSource ParentMessageSource - { - get + if (_parentMessageSource == null) { - if (_parentMessageSource == null) - { - _parentMessageSource = new SpecialCaseNullMessageSource(); - } - return _parentMessageSource; + _parentMessageSource = new SpecialCaseNullMessageSource(); } - set { _parentMessageSource = value; } + + return _parentMessageSource; } + set { _parentMessageSource = value; } + } - #endregion + #endregion - #region Methods + #region Methods - /// - /// Resolve the message identified by the supplied - /// . - /// - /// The name of the message to resolve. - /// - /// The resolved message if the lookup was successful (see above for - /// the return value in the case of an unsuccessful lookup). - /// - /// - /// If the message could not be resolved. - /// - /// + /// + /// Resolve the message identified by the supplied + /// . + /// + /// The name of the message to resolve. + /// + /// The resolved message if the lookup was successful (see above for + /// the return value in the case of an unsuccessful lookup). + /// + /// + /// If the message could not be resolved. + /// + /// + public string GetMessage(string name) + { + return ParentMessageSource.GetMessage(name); + } + + /// + /// Resolve the message identified by the supplied + /// . + /// + /// The name of the message to resolve. + /// + /// The array of arguments that will be filled in for parameters within + /// the message, or if there are no parameters + /// within the message. Parameters within a message should be + /// referenced using the same syntax as the format string for the + /// method. + /// + /// + /// The resolved message if the lookup was successful (see above for + /// the return value in the case of an unsuccessful lookup). + /// + /// + /// If the message could not be resolved. + /// + /// + public string GetMessage(string name, params object[] arguments) + { + return ParentMessageSource.GetMessage(name, arguments); + } + + /// + /// Resolve the message identified by the supplied + /// . + /// + /// The name of the message to resolve. + /// + /// The that represents + /// the culture for which the resource is localized. + /// + /// + /// The resolved message if the lookup was successful (see above for + /// the return value in the case of an unsuccessful lookup). + /// + /// + /// If the message could not be resolved. + /// + /// + public string GetMessage(string name, CultureInfo culture) + { + return ParentMessageSource.GetMessage(name, culture); + } + + /// + /// Resolve the message identified by the supplied + /// . + /// + /// The name of the message to resolve. + /// + /// The that represents + /// the culture for which the resource is localized. + /// + /// + /// The array of arguments that will be filled in for parameters within + /// the message, or if there are no parameters + /// within the message. Parameters within a message should be + /// referenced using the same syntax as the format string for the + /// method. + /// + /// + /// The resolved message if the lookup was successful (see above for + /// the return value in the case of an unsuccessful lookup). + /// + /// + /// If the message could not be resolved. + /// + /// + public string GetMessage(string name, CultureInfo culture, params object[] arguments) + { + return ParentMessageSource.GetMessage(name, culture, arguments); + } + + /// + /// Resolve the message identified by the supplied + /// . + /// + /// The name of the message to resolve. + /// The default message. + /// + /// The that represents + /// the culture for which the resource is localized. + /// + /// + /// The array of arguments that will be filled in for parameters within + /// the message, or if there are no parameters + /// within the message. Parameters within a message should be + /// referenced using the same syntax as the format string for the + /// method. + /// + /// + /// The resolved message if the lookup was successful (see above for + /// the return value in the case of an unsuccessful lookup). + /// + /// + /// If the message could not be resolved. + /// + /// + public string GetMessage(string name, string defaultMessage, CultureInfo culture, params object[] arguments) + { + return ParentMessageSource.GetMessage(name, defaultMessage, culture, arguments); + } + + /// + /// Resolve the message using all of the attributes contained within + /// the supplied + /// argument. + /// + /// + /// The value object storing those attributes that are required to + /// properly resolve a message. + /// + /// + /// The that represents + /// the culture for which the resource is localized. + /// + /// + /// The resolved message if the lookup was successful (see above for + /// the return value in the case of an unsuccessful lookup). + /// + /// + /// If the message could not be resolved. + /// + /// + /// If the message could not be resolved. + /// + /// + public string GetMessage(IMessageSourceResolvable resolvable, CultureInfo culture) + { + return ParentMessageSource.GetMessage(resolvable, culture); + } + + /// + /// Gets a localized resource object identified by the supplied + /// . + /// + /// + /// The name of the resource object to resolve. + /// + /// + /// The resolved object, or if not found. + /// + /// + public object GetResourceObject(string name) + { + return ParentMessageSource.GetResourceObject(name); + } + + /// + /// Gets a localized resource object identified by the supplied + /// . + /// + /// + /// The name of the resource object to resolve. + /// + /// + /// The with which the + /// resource is associated. + /// + /// + /// The resolved object, or if not found. + /// + /// + public object GetResourceObject(string name, CultureInfo culture) + { + return ParentMessageSource.GetResourceObject(name, culture); + } + + /// + /// Applies resources to object properties. + /// + /// + /// An object that contains the property values to be applied. + /// + /// + /// The base name of the object to use for key lookup. + /// + /// + /// The with which the + /// resource is associated. + /// + /// + public void ApplyResources(object value, string objectName, CultureInfo culture) + { + ParentMessageSource.ApplyResources(value, objectName, culture); + } + + #endregion + + #region Inner Class : SpecialCaseNullMessageSource + + private sealed class SpecialCaseNullMessageSource : IMessageSource + { public string GetMessage(string name) { - return ParentMessageSource.GetMessage(name); + return GetMessage(name, (object[]) null); } - /// - /// Resolve the message identified by the supplied - /// . - /// - /// The name of the message to resolve. - /// - /// The array of arguments that will be filled in for parameters within - /// the message, or if there are no parameters - /// within the message. Parameters within a message should be - /// referenced using the same syntax as the format string for the - /// method. - /// - /// - /// The resolved message if the lookup was successful (see above for - /// the return value in the case of an unsuccessful lookup). - /// - /// - /// If the message could not be resolved. - /// - /// public string GetMessage(string name, params object[] arguments) { - return ParentMessageSource.GetMessage(name, arguments); + return GetMessage(name, CultureInfo.CurrentUICulture, null); } - /// - /// Resolve the message identified by the supplied - /// . - /// - /// The name of the message to resolve. - /// - /// The that represents - /// the culture for which the resource is localized. - /// - /// - /// The resolved message if the lookup was successful (see above for - /// the return value in the case of an unsuccessful lookup). - /// - /// - /// If the message could not be resolved. - /// - /// public string GetMessage(string name, CultureInfo culture) { - return ParentMessageSource.GetMessage(name, culture); + return GetMessage(name, culture, null); } - /// - /// Resolve the message identified by the supplied - /// . - /// - /// The name of the message to resolve. - /// - /// The that represents - /// the culture for which the resource is localized. - /// - /// - /// The array of arguments that will be filled in for parameters within - /// the message, or if there are no parameters - /// within the message. Parameters within a message should be - /// referenced using the same syntax as the format string for the - /// method. - /// - /// - /// The resolved message if the lookup was successful (see above for - /// the return value in the case of an unsuccessful lookup). - /// - /// - /// If the message could not be resolved. - /// - /// public string GetMessage(string name, CultureInfo culture, params object[] arguments) { - return ParentMessageSource.GetMessage(name, culture, arguments); + throw new NoSuchMessageException(name, culture); } - /// - /// Resolve the message identified by the supplied - /// . - /// - /// The name of the message to resolve. - /// The default message. - /// - /// The that represents - /// the culture for which the resource is localized. - /// - /// - /// The array of arguments that will be filled in for parameters within - /// the message, or if there are no parameters - /// within the message. Parameters within a message should be - /// referenced using the same syntax as the format string for the - /// method. - /// - /// - /// The resolved message if the lookup was successful (see above for - /// the return value in the case of an unsuccessful lookup). - /// - /// - /// If the message could not be resolved. - /// - /// public string GetMessage(string name, string defaultMessage, CultureInfo culture, params object[] arguments) { - return ParentMessageSource.GetMessage(name, defaultMessage, culture, arguments); + throw new NoSuchMessageException(name, culture); } - /// - /// Resolve the message using all of the attributes contained within - /// the supplied - /// argument. - /// - /// - /// The value object storing those attributes that are required to - /// properly resolve a message. - /// - /// - /// The that represents - /// the culture for which the resource is localized. - /// - /// - /// The resolved message if the lookup was successful (see above for - /// the return value in the case of an unsuccessful lookup). - /// - /// - /// If the message could not be resolved. - /// - /// - /// If the message could not be resolved. - /// - /// public string GetMessage(IMessageSourceResolvable resolvable, CultureInfo culture) { - return ParentMessageSource.GetMessage(resolvable, culture); + if (StringUtils.HasText(resolvable.DefaultMessage)) + { + return resolvable.DefaultMessage; + } + + IList codes = resolvable.GetCodes(); + string code = (codes != null && codes.Count > 0 ? codes[0] : string.Empty); + throw new NoSuchMessageException(code, culture); } - /// - /// Gets a localized resource object identified by the supplied - /// . - /// - /// - /// The name of the resource object to resolve. - /// - /// - /// The resolved object, or if not found. - /// - /// public object GetResourceObject(string name) { - return ParentMessageSource.GetResourceObject(name); + return GetResourceObject(name, CultureInfo.CurrentUICulture); } - /// - /// Gets a localized resource object identified by the supplied - /// . - /// - /// - /// The name of the resource object to resolve. - /// - /// - /// The with which the - /// resource is associated. - /// - /// - /// The resolved object, or if not found. - /// - /// public object GetResourceObject(string name, CultureInfo culture) { - return ParentMessageSource.GetResourceObject(name, culture); + throw new ApplicationContextException( + string.Format( + "Cannot lookup the named resource '{0}' for locale '{1}' " + + ": no IMessageSource in context.", + name, culture)); } - /// - /// Applies resources to object properties. - /// - /// - /// An object that contains the property values to be applied. - /// - /// - /// The base name of the object to use for key lookup. - /// - /// - /// The with which the - /// resource is associated. - /// - /// public void ApplyResources(object value, string objectName, CultureInfo culture) { - ParentMessageSource.ApplyResources(value, objectName, culture); + throw new ApplicationContextException( + string.Format( + "Cannot apply [{0}] resource to object '{1}' for locale '{2}' " + + ": no IMessageSource in context.", + value, objectName, culture)); } - - #endregion - - #region Inner Class : SpecialCaseNullMessageSource - - private sealed class SpecialCaseNullMessageSource : IMessageSource - { - public string GetMessage(string name) - { - return GetMessage(name, (object[]) null); - } - - public string GetMessage(string name, params object[] arguments) - { - return GetMessage(name, CultureInfo.CurrentUICulture, null); - } - - public string GetMessage(string name, CultureInfo culture) - { - return GetMessage(name, culture, null); - } - - public string GetMessage(string name, CultureInfo culture, params object[] arguments) - { - throw new NoSuchMessageException(name, culture); - } - - public string GetMessage(string name, string defaultMessage, CultureInfo culture, params object[] arguments) - { - throw new NoSuchMessageException(name, culture); - } - - - public string GetMessage(IMessageSourceResolvable resolvable, CultureInfo culture) - { - if (StringUtils.HasText(resolvable.DefaultMessage)) - { - return resolvable.DefaultMessage; - } - IList codes = resolvable.GetCodes(); - string code = (codes != null && codes.Count > 0 ? codes[0] : string.Empty); - throw new NoSuchMessageException(code, culture); - } - - public object GetResourceObject(string name) - { - return GetResourceObject(name, CultureInfo.CurrentUICulture); - } - - public object GetResourceObject(string name, CultureInfo culture) - { - throw new ApplicationContextException( - string.Format( - "Cannot lookup the named resource '{0}' for locale '{1}' " + - ": no IMessageSource in context.", - name, culture)); - } - - public void ApplyResources(object value, string objectName, CultureInfo culture) - { - throw new ApplicationContextException( - string.Format( - "Cannot apply [{0}] resource to object '{1}' for locale '{2}' " + - ": no IMessageSource in context.", - value, objectName, culture)); - } - } - - #endregion } + + #endregion } diff --git a/src/Spring/Spring.Core/Context/Support/GenericApplicationContext.cs b/src/Spring/Spring.Core/Context/Support/GenericApplicationContext.cs index de5436ee..c177b0c6 100644 --- a/src/Spring/Spring.Core/Context/Support/GenericApplicationContext.cs +++ b/src/Spring/Spring.Core/Context/Support/GenericApplicationContext.cs @@ -22,167 +22,165 @@ using Spring.Objects.Factory.Config; using Spring.Objects.Factory.Support; using Spring.Util; -namespace Spring.Context.Support +namespace Spring.Context.Support; + +/// +/// Generic ApplicationContext implementation that holds a single internal +/// instance and does not +/// assume a specific object definition format. +/// +/// +/// Implements the interface in order +/// to allow for aplying any object definition readers to it. +/// Typical usage is to register a variety of object definitions via the +/// interface and then call +/// to initialize those +/// objects with application context semantics (handling +/// , auto-detecting +/// ObjectFactoryPostProcessors, etc). +/// +/// In contrast to other IApplicationContext implementations that create a new internal +/// IObjectFactory instance for each refresh, the internal IObjectFactory of this context +/// is available right from the start, to be able to register object definitions on it. +/// may only be called once +/// Usage examples +/// +/// GenericApplicationContext ctx = new GenericApplicationContext(); +/// // register your objects and object definitions +/// ctx.RegisterObjectDefinition(...) +/// ctx.Refresh(); +/// +/// +/// Mark Pollack +public class GenericApplicationContext : AbstractApplicationContext { + private readonly DefaultListableObjectFactory objectFactory; + private bool refreshed = false; + /// - /// Generic ApplicationContext implementation that holds a single internal - /// instance and does not - /// assume a specific object definition format. + /// Initializes a new instance of the class. /// - /// - /// Implements the interface in order - /// to allow for aplying any object definition readers to it. - /// Typical usage is to register a variety of object definitions via the - /// interface and then call - /// to initialize those - /// objects with application context semantics (handling - /// , auto-detecting - /// ObjectFactoryPostProcessors, etc). - /// - /// In contrast to other IApplicationContext implementations that create a new internal - /// IObjectFactory instance for each refresh, the internal IObjectFactory of this context - /// is available right from the start, to be able to register object definitions on it. - /// may only be called once - /// Usage examples - /// - /// GenericApplicationContext ctx = new GenericApplicationContext(); - /// // register your objects and object definitions - /// ctx.RegisterObjectDefinition(...) - /// ctx.Refresh(); - /// - /// - /// Mark Pollack - public class GenericApplicationContext : AbstractApplicationContext + public GenericApplicationContext() + : this(null, true, null, new DefaultListableObjectFactory()) { - private readonly DefaultListableObjectFactory objectFactory; - private bool refreshed = false; + // noop + } + /// + /// Initializes a new instance of the class. + /// + /// if set to true names in the context are case sensitive. + public GenericApplicationContext(bool caseSensitive) + : this(null, caseSensitive, null, new DefaultListableObjectFactory()) + { + // noop + } - /// - /// Initializes a new instance of the class. - /// - public GenericApplicationContext() - : this(null, true, null, new DefaultListableObjectFactory()) + /// + /// Initializes a new instance of the class. + /// + /// The object factory instance to use for this context. + public GenericApplicationContext(DefaultListableObjectFactory objectFactory) + : this(null, true, null, objectFactory) + { + // noop + } + + /// + /// Initializes a new instance of the class. + /// + /// The parent application context. + public GenericApplicationContext(IApplicationContext parent) + : this(null, true, parent, new DefaultListableObjectFactory()) + { + // noop + } + + /// + /// Initializes a new instance of the class. + /// + /// The name of the application context. + /// if set to true names in the context are case sensitive. + /// The parent application context. + public GenericApplicationContext(string name, bool caseSensitive, IApplicationContext parent) + : this(name, caseSensitive, parent, new DefaultListableObjectFactory()) + { + // noop + } + + /// + /// Initializes a new instance of the class. + /// + /// The object factory to use for this context + /// The parent applicaiton context. + public GenericApplicationContext(DefaultListableObjectFactory objectFactory, IApplicationContext parent) + : this(null, true, parent, objectFactory) + { + // noop + } + + /// + /// Initializes a new instance of the class. + /// + /// The name of the application context. + /// if set to true names in the context are case sensitive. + /// The parent application context. + /// The object factory to use for this context + public GenericApplicationContext(string name, bool caseSensitive, IApplicationContext parent, DefaultListableObjectFactory objectFactory) + : base(name, caseSensitive, parent) + { + AssertUtils.ArgumentNotNull(objectFactory, "objectFactory", "ObjectFactory must not be null"); + this.objectFactory = objectFactory; + this.objectFactory.ParentObjectFactory = base.GetInternalParentObjectFactory(); + } + + /// + /// Do nothing operation. We hold a single internal ObjectFactory and rely on callers + /// to register objects throug our public methods (or the ObjectFactory's). + /// + /// + /// In the case of errors encountered while refreshing the object factory. + /// + protected override void RefreshObjectFactory() + { + if (refreshed) { - // noop + throw new InvalidOperationException( + "GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once"); } - /// - /// Initializes a new instance of the class. - /// - /// if set to true names in the context are case sensitive. - public GenericApplicationContext(bool caseSensitive) - : this(null, caseSensitive, null, new DefaultListableObjectFactory()) - { - // noop - } + refreshed = true; + } - /// - /// Initializes a new instance of the class. - /// - /// The object factory instance to use for this context. - public GenericApplicationContext(DefaultListableObjectFactory objectFactory) - : this(null, true, null, objectFactory) - { - // noop - } + /// + /// Return the internal object factory of this application context. + /// + /// + public override IConfigurableListableObjectFactory ObjectFactory + { + get { return objectFactory; } + } - /// - /// Initializes a new instance of the class. - /// - /// The parent application context. - public GenericApplicationContext(IApplicationContext parent) - : this(null, true, parent, new DefaultListableObjectFactory()) - { - // noop - } + /// + /// Gets the underlying object factory of this context, available for + /// registering object definitions. + /// + /// You need to call Refresh to initialize the + /// objects factory and its contained objects with application context + /// semantics (autodecting IObjectFactoryPostProcessors, etc). + /// The internal object factory (as DefaultListableObjectFactory). + public DefaultListableObjectFactory DefaultListableObjectFactory + { + get { return objectFactory; } + } - /// - /// Initializes a new instance of the class. - /// - /// The name of the application context. - /// if set to true names in the context are case sensitive. - /// The parent application context. - public GenericApplicationContext(string name, bool caseSensitive, IApplicationContext parent) - : this(name, caseSensitive, parent, new DefaultListableObjectFactory()) - { - // noop - } - - /// - /// Initializes a new instance of the class. - /// - /// The object factory to use for this context - /// The parent applicaiton context. - public GenericApplicationContext(DefaultListableObjectFactory objectFactory, IApplicationContext parent) - : this(null, true, parent, objectFactory) - { - // noop - } - - /// - /// Initializes a new instance of the class. - /// - /// The name of the application context. - /// if set to true names in the context are case sensitive. - /// The parent application context. - /// The object factory to use for this context - public GenericApplicationContext(string name, bool caseSensitive, IApplicationContext parent, DefaultListableObjectFactory objectFactory) - : base(name, caseSensitive, parent) - { - AssertUtils.ArgumentNotNull(objectFactory, "objectFactory", "ObjectFactory must not be null"); - this.objectFactory = objectFactory; - this.objectFactory.ParentObjectFactory = base.GetInternalParentObjectFactory(); - } - - /// - /// Do nothing operation. We hold a single internal ObjectFactory and rely on callers - /// to register objects throug our public methods (or the ObjectFactory's). - /// - /// - /// In the case of errors encountered while refreshing the object factory. - /// - protected override void RefreshObjectFactory() - { - if (refreshed) - { - throw new InvalidOperationException( - "GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once"); - } - - refreshed = true; - } - - /// - /// Return the internal object factory of this application context. - /// - /// - public override IConfigurableListableObjectFactory ObjectFactory - { - get { return objectFactory; } - } - - /// - /// Gets the underlying object factory of this context, available for - /// registering object definitions. - /// - /// You need to call Refresh to initialize the - /// objects factory and its contained objects with application context - /// semantics (autodecting IObjectFactoryPostProcessors, etc). - /// The internal object factory (as DefaultListableObjectFactory). - public DefaultListableObjectFactory DefaultListableObjectFactory - { - get { return objectFactory; } - } - - /// - /// Determines whether the given object name is already in use within this factory, - /// i.e. whether there is a local object or alias registered under this name or - /// an inner object created with this name. - /// - public override bool IsObjectNameInUse(string objectName) - { - return objectFactory.IsObjectNameInUse(objectName); - } + /// + /// Determines whether the given object name is already in use within this factory, + /// i.e. whether there is a local object or alias registered under this name or + /// an inner object created with this name. + /// + public override bool IsObjectNameInUse(string objectName) + { + return objectFactory.IsObjectNameInUse(objectName); } } diff --git a/src/Spring/Spring.Core/Context/Support/MessageSourceAccessor.cs b/src/Spring/Spring.Core/Context/Support/MessageSourceAccessor.cs index acae5d81..d650b4c9 100644 --- a/src/Spring/Spring.Core/Context/Support/MessageSourceAccessor.cs +++ b/src/Spring/Spring.Core/Context/Support/MessageSourceAccessor.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -24,163 +24,162 @@ using System.Globalization; #endregion -namespace Spring.Context.Support +namespace Spring.Context.Support; + +/// +/// Helper class for easy access to messages from an +/// , providing various +/// overloaded GetMessage methods. +/// +/// +///

+/// Available from +/// , but also +/// reusable as a standalone helper to delegate to in application objects. +///

+///
+/// Juergen Hoeller +/// Griffin Caprio (.NET) +/// +/// +public class MessageSourceAccessor { - /// - /// Helper class for easy access to messages from an - /// , providing various - /// overloaded GetMessage methods. - /// - /// - ///

- /// Available from - /// , but also - /// reusable as a standalone helper to delegate to in application objects. - ///

- ///
- /// Juergen Hoeller - /// Griffin Caprio (.NET) - /// - /// - public class MessageSourceAccessor - { - private IMessageSource _messageSource; - private CultureInfo _defaultCultureInfo; + private IMessageSource _messageSource; + private CultureInfo _defaultCultureInfo; - /// - /// Creates a new instance of the - /// class - /// that uses the current - /// for all locale specific lookups. - /// - /// - /// The to use to locate messages. - /// - public MessageSourceAccessor(IMessageSource messageSource) - : this(messageSource, CultureInfo.CurrentUICulture) - { - } + /// + /// Creates a new instance of the + /// class + /// that uses the current + /// for all locale specific lookups. + /// + /// + /// The to use to locate messages. + /// + public MessageSourceAccessor(IMessageSource messageSource) + : this(messageSource, CultureInfo.CurrentUICulture) + { + } - /// - /// Creates a new instance of the - /// class - /// - /// - /// The to use to locate - /// messages. - /// - /// - /// The to use for - /// locale specific messages. - /// - public MessageSourceAccessor( - IMessageSource messageSource, CultureInfo cultureInfo) - { - _messageSource = messageSource; - _defaultCultureInfo = cultureInfo; - } + /// + /// Creates a new instance of the + /// class + /// + /// + /// The to use to locate + /// messages. + /// + /// + /// The to use for + /// locale specific messages. + /// + public MessageSourceAccessor( + IMessageSource messageSource, CultureInfo cultureInfo) + { + _messageSource = messageSource; + _defaultCultureInfo = cultureInfo; + } - /// - /// Retrieve the message for the given code and the default - /// . - /// - /// The code of the message. - /// The message. - public string GetMessage(string code) - { - return _messageSource.GetMessage(code, _defaultCultureInfo); - } + /// + /// Retrieve the message for the given code and the default + /// . + /// + /// The code of the message. + /// The message. + public string GetMessage(string code) + { + return _messageSource.GetMessage(code, _defaultCultureInfo); + } - /// - /// Retrieve the message for the given code and the given - /// . - /// - /// The code of the message. - /// - /// The to use for - /// lookups. - /// - /// The message. - public string GetMessage(string code, CultureInfo cultureInfo) - { - return _messageSource.GetMessage(code, cultureInfo); - } + /// + /// Retrieve the message for the given code and the given + /// . + /// + /// The code of the message. + /// + /// The to use for + /// lookups. + /// + /// The message. + public string GetMessage(string code, CultureInfo cultureInfo) + { + return _messageSource.GetMessage(code, cultureInfo); + } - /// - /// Retrieve the message for the given code and the default - /// . - /// - /// The code of the message. - /// - /// The arguments for the message, or if none. - /// - /// The message. - /// - /// If the message could not be found. - /// - public string GetMessage(string code, params object[] args) - { - return _messageSource.GetMessage(code, _defaultCultureInfo, args); - } + /// + /// Retrieve the message for the given code and the default + /// . + /// + /// The code of the message. + /// + /// The arguments for the message, or if none. + /// + /// The message. + /// + /// If the message could not be found. + /// + public string GetMessage(string code, params object[] args) + { + return _messageSource.GetMessage(code, _defaultCultureInfo, args); + } - /// - /// Retrieve the message for the given code and the given - /// . - /// - /// The code of the message. - /// - /// The to use for - /// lookups. - /// - /// - /// The arguments for the message, or if none. - /// - /// The message. - /// - /// If the message could not be found. - /// - public string GetMessage( - string code, CultureInfo cultureInfo, params object[] args) - { - return _messageSource.GetMessage(code, cultureInfo, args); - } + /// + /// Retrieve the message for the given code and the given + /// . + /// + /// The code of the message. + /// + /// The to use for + /// lookups. + /// + /// + /// The arguments for the message, or if none. + /// + /// The message. + /// + /// If the message could not be found. + /// + public string GetMessage( + string code, CultureInfo cultureInfo, params object[] args) + { + return _messageSource.GetMessage(code, cultureInfo, args); + } - /// - /// Retrieve a mesage using the given - /// . - /// - /// - /// The . - /// - /// The message. - /// - /// If the message could not be found. - /// - public string GetMessage(IMessageSourceResolvable resolvable) - { - return GetMessage(resolvable, _defaultCultureInfo); - } + /// + /// Retrieve a mesage using the given + /// . + /// + /// + /// The . + /// + /// The message. + /// + /// If the message could not be found. + /// + public string GetMessage(IMessageSourceResolvable resolvable) + { + return GetMessage(resolvable, _defaultCultureInfo); + } - /// - /// Retrieve a mesage using the given - /// in the given - /// . - /// - /// - /// The . - /// - /// - /// The to use for - /// lookups. - /// - /// The message - /// - /// If the message could not be found. - /// - public string GetMessage( - IMessageSourceResolvable resolvable, CultureInfo cultureInfo) - { - return _messageSource.GetMessage(resolvable, cultureInfo); - } - } -} \ No newline at end of file + /// + /// Retrieve a mesage using the given + /// in the given + /// . + /// + /// + /// The . + /// + /// + /// The to use for + /// lookups. + /// + /// The message + /// + /// If the message could not be found. + /// + public string GetMessage( + IMessageSourceResolvable resolvable, CultureInfo cultureInfo) + { + return _messageSource.GetMessage(resolvable, cultureInfo); + } +} diff --git a/src/Spring/Spring.Core/Context/Support/MessageSourceResolvableVisitor.cs b/src/Spring/Spring.Core/Context/Support/MessageSourceResolvableVisitor.cs index d079d819..0b6c2e73 100644 --- a/src/Spring/Spring.Core/Context/Support/MessageSourceResolvableVisitor.cs +++ b/src/Spring/Spring.Core/Context/Support/MessageSourceResolvableVisitor.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -25,71 +25,71 @@ using Spring.Util; #endregion -namespace Spring.Context.Support -{ - /// - /// Visitor class to represent - /// instances. - /// - /// - ///

- /// Used in the first instance to supply stringified versions of - /// instances. - ///

- ///

- /// Other methods can be added here to return different representations, - /// including XML, CSV, etc.. - ///

- ///
- /// Griffin Caprio (.NET) - public class MessageSourceResolvableVisitor - { - /// - /// Creates a new instance of the - /// class. - /// - public MessageSourceResolvableVisitor() - { - } +namespace Spring.Context.Support; - /// - /// Outputs the supplied - /// as a nicely formatted . - /// - /// - /// The to output. - /// - public string VisitMessageSourceResolvableString( - IMessageSourceResolvable resolvable) - { - StringBuilder builder = new StringBuilder(); - builder.Append("codes=["); - builder.Append(StringUtils.ArrayToDelimitedString(resolvable.GetCodes(), ",")); - builder.Append("]; arguments=["); - if (resolvable.GetArguments() == null) - { - builder.Append("null"); - } - else - { - object[] arguments = resolvable.GetArguments(); - for (int i = 0; i < arguments.Length; i++) - { - builder.Append("("); - builder.Append(arguments[i].GetType().Name); - builder.Append(")["); - builder.Append(arguments[i]); - builder.Append("]"); - if (i < arguments.Length - 1) - { - builder.Append(", "); - } - } - } - builder.Append("]; defaultMessage=["); - builder.Append(resolvable.DefaultMessage); - builder.Append("]"); - return builder.ToString(); - } - } -} \ No newline at end of file +/// +/// Visitor class to represent +/// instances. +/// +/// +///

+/// Used in the first instance to supply stringified versions of +/// instances. +///

+///

+/// Other methods can be added here to return different representations, +/// including XML, CSV, etc.. +///

+///
+/// Griffin Caprio (.NET) +public class MessageSourceResolvableVisitor +{ + /// + /// Creates a new instance of the + /// class. + /// + public MessageSourceResolvableVisitor() + { + } + + /// + /// Outputs the supplied + /// as a nicely formatted . + /// + /// + /// The to output. + /// + public string VisitMessageSourceResolvableString( + IMessageSourceResolvable resolvable) + { + StringBuilder builder = new StringBuilder(); + builder.Append("codes=["); + builder.Append(StringUtils.ArrayToDelimitedString(resolvable.GetCodes(), ",")); + builder.Append("]; arguments=["); + if (resolvable.GetArguments() == null) + { + builder.Append("null"); + } + else + { + object[] arguments = resolvable.GetArguments(); + for (int i = 0; i < arguments.Length; i++) + { + builder.Append("("); + builder.Append(arguments[i].GetType().Name); + builder.Append(")["); + builder.Append(arguments[i]); + builder.Append("]"); + if (i < arguments.Length - 1) + { + builder.Append(", "); + } + } + } + + builder.Append("]; defaultMessage=["); + builder.Append(resolvable.DefaultMessage); + builder.Append("]"); + return builder.ToString(); + } +} diff --git a/src/Spring/Spring.Core/Context/Support/NamespaceParsersSectionHandler.cs b/src/Spring/Spring.Core/Context/Support/NamespaceParsersSectionHandler.cs index 5949cb43..2253b843 100644 --- a/src/Spring/Spring.Core/Context/Support/NamespaceParsersSectionHandler.cs +++ b/src/Spring/Spring.Core/Context/Support/NamespaceParsersSectionHandler.cs @@ -23,113 +23,113 @@ using System.Configuration; using System.Globalization; using System.Xml; - using Spring.Core.TypeResolution; using Spring.Objects.Factory.Xml; using Spring.Util; #endregion -namespace Spring.Context.Support +namespace Spring.Context.Support; + +/// +/// Configuration section handler for the (recommended, Spring.NET standard) parsers +/// config section. +/// +/// +///

+/// Spring.NET allows the registration of custom configuration parsers that +/// can be used to create simplified configuration schemas that better +/// describe object definitions. +///

+///

+/// For example, Spring.NET uses this facility internally in order to +/// define simplified schemas for various AOP, Data and Services definitions. +///

+///
+/// +///

+/// The following example shows how to configure both this section handler +/// and how to define custom configuration parsers within a Spring.NET +/// config section. +///

+/// +/// +/// +/// +///
+/// +/// +/// +/// +/// +/// +/// ... +/// +/// ... +/// +/// +/// +/// +/// Aleksandar Seovic +/// +public class NamespaceParsersSectionHandler : IConfigurationSectionHandler { - /// - /// Configuration section handler for the (recommended, Spring.NET standard) parsers - /// config section. - /// - /// - ///

- /// Spring.NET allows the registration of custom configuration parsers that - /// can be used to create simplified configuration schemas that better - /// describe object definitions. - ///

- ///

- /// For example, Spring.NET uses this facility internally in order to - /// define simplified schemas for various AOP, Data and Services definitions. - ///

- ///
- /// - ///

- /// The following example shows how to configure both this section handler - /// and how to define custom configuration parsers within a Spring.NET - /// config section. - ///

- /// - /// - /// - /// - ///
- /// - /// - /// - /// - /// - /// - /// ... - /// - /// ... - /// - /// - /// - /// - /// Aleksandar Seovic - /// - public class NamespaceParsersSectionHandler : IConfigurationSectionHandler - { - private const string ParserElementName = "parser"; - private const string TypeAttributeName = "type"; - private const string NamespaceAttributeName = "namespace"; - private const string SchemaLocationAttributeName = "schemaLocation"; + private const string ParserElementName = "parser"; + private const string TypeAttributeName = "type"; + private const string NamespaceAttributeName = "namespace"; + private const string SchemaLocationAttributeName = "schemaLocation"; - /// - /// Registers parsers specified in the (recommended, Spring.NET standard) - /// parsers config section with the . - /// - /// - /// The configuration settings in a corresponding parent - /// configuration section. - /// - /// - /// The configuration context when called from the ASP.NET - /// configuration system. Otherwise, this parameter is reserved and - /// is . - /// - /// - /// The for the section. - /// - /// - /// This method always returns , because parsers - /// are registered as a side-effect of this object's execution and there - /// is thus no need to return anything. - /// - public object Create(object parent, object configContext, XmlNode section) - { - if (section != null) + /// + /// Registers parsers specified in the (recommended, Spring.NET standard) + /// parsers config section with the . + /// + /// + /// The configuration settings in a corresponding parent + /// configuration section. + /// + /// + /// The configuration context when called from the ASP.NET + /// configuration system. Otherwise, this parameter is reserved and + /// is . + /// + /// + /// The for the section. + /// + /// + /// This method always returns , because parsers + /// are registered as a side-effect of this object's execution and there + /// is thus no need to return anything. + /// + public object Create(object parent, object configContext, XmlNode section) + { + if (section != null) + { + XmlNodeList parsers = ((XmlElement) section).GetElementsByTagName(ParserElementName); + foreach (XmlElement parserElement in parsers) { - XmlNodeList parsers = ((XmlElement)section).GetElementsByTagName(ParserElementName); - foreach (XmlElement parserElement in parsers) - { - string parserTypeName = GetRequiredAttributeValue(parserElement, TypeAttributeName, section); - string xmlNamespace = parserElement.GetAttribute(NamespaceAttributeName); - string schemaLocation = parserElement.GetAttribute(SchemaLocationAttributeName); + string parserTypeName = GetRequiredAttributeValue(parserElement, TypeAttributeName, section); + string xmlNamespace = parserElement.GetAttribute(NamespaceAttributeName); + string schemaLocation = parserElement.GetAttribute(SchemaLocationAttributeName); - Type parserType = TypeResolutionUtils.ResolveType(parserTypeName); - NamespaceParserRegistry.RegisterParser(parserType, xmlNamespace, schemaLocation); - } + Type parserType = TypeResolutionUtils.ResolveType(parserTypeName); + NamespaceParserRegistry.RegisterParser(parserType, xmlNamespace, schemaLocation); } - return null; - } + } - private static string GetRequiredAttributeValue( - XmlElement aliasElement, string requiredAttributeName, XmlNode section) - { - XmlAttribute attribute = aliasElement.GetAttributeNode(requiredAttributeName); - if (attribute == null) - { - string errorMessage = string.Format(CultureInfo.InvariantCulture, - "The '{0}' attribute is required for the element.", requiredAttributeName); - throw ConfigurationUtils.CreateConfigurationException(errorMessage, section); - } - return attribute.Value; - } - } + return null; + } + + private static string GetRequiredAttributeValue( + XmlElement aliasElement, string requiredAttributeName, XmlNode section) + { + XmlAttribute attribute = aliasElement.GetAttributeNode(requiredAttributeName); + if (attribute == null) + { + string errorMessage = string.Format(CultureInfo.InvariantCulture, + "The '{0}' attribute is required for the element.", requiredAttributeName); + throw ConfigurationUtils.CreateConfigurationException(errorMessage, section); + } + + return attribute.Value; + } } diff --git a/src/Spring/Spring.Core/Context/Support/NullMessageSource.cs b/src/Spring/Spring.Core/Context/Support/NullMessageSource.cs index 4a386396..1d4b375b 100644 --- a/src/Spring/Spring.Core/Context/Support/NullMessageSource.cs +++ b/src/Spring/Spring.Core/Context/Support/NullMessageSource.cs @@ -20,93 +20,94 @@ using System.Globalization; -namespace Spring.Context.Support +namespace Spring.Context.Support; + +/// +/// An that doesn't do a whole lot. +/// +/// +///

+/// is an implementation of +/// the NullObject pattern. It should be used in those situations where a +/// needs to be passed (say to a +/// method) but where the resolution of messages is not required. +///

+///

+/// There should not (typically) be a need to instantiate instances of this class; +/// does not maintan any state +/// and the instance is +/// thus safe to pass around. +///

+///
+/// Aleksandar Seovic +public sealed class NullMessageSource : AbstractMessageSource { /// - /// An that doesn't do a whole lot. + /// The canonical instance of the + /// class. + /// + public static readonly NullMessageSource Null = new NullMessageSource(); + + /// + /// Creates a new instance of the class. /// /// ///

- /// is an implementation of - /// the NullObject pattern. It should be used in those situations where a - /// needs to be passed (say to a - /// method) but where the resolution of messages is not required. - ///

- ///

- /// There should not (typically) be a need to instantiate instances of this class; - /// does not maintan any state - /// and the instance is - /// thus safe to pass around. + /// Consider using + /// instead. ///

///
- /// Aleksandar Seovic - public sealed class NullMessageSource : AbstractMessageSource + public NullMessageSource() { - /// - /// The canonical instance of the - /// class. - /// - public static readonly NullMessageSource Null = new NullMessageSource(); + } - /// - /// Creates a new instance of the class. - /// - /// - ///

- /// Consider using - /// instead. - ///

- ///
- public NullMessageSource() - {} + /// + /// Simply returns the supplied message as-is. + /// + /// The code of the message to resolve. + /// + /// The to resolve the + /// code for. + /// + /// + /// The supplied message as-is. + /// + protected override string ResolveMessage(string code, CultureInfo cultureInfo) + { + return code; + } - /// - /// Simply returns the supplied message as-is. - /// - /// The code of the message to resolve. - /// - /// The to resolve the - /// code for. - /// - /// - /// The supplied message as-is. - /// - protected override string ResolveMessage(string code, CultureInfo cultureInfo) - { - return code; - } + /// + /// Always returns . + /// + /// The code of the object to resolve. + /// + /// The to resolve the + /// code for. + /// + /// + /// (always). + /// + protected override object ResolveObject(string code, CultureInfo cultureInfo) + { + return null; + } - /// - /// Always returns . - /// - /// The code of the object to resolve. - /// - /// The to resolve the - /// code for. - /// - /// - /// (always). - /// - protected override object ResolveObject(string code, CultureInfo cultureInfo) - { - return null; - } - - /// - /// Does nothing. - /// - /// - /// An object that contains the property values to be applied. - /// - /// - /// The base name of the object to use for key lookup. - /// - /// - /// The with which the - /// resource is associated. - /// - protected override void ApplyResourcesToObject( - object value, string objectName, CultureInfo cultureInfo) - {} + /// + /// Does nothing. + /// + /// + /// An object that contains the property values to be applied. + /// + /// + /// The base name of the object to use for key lookup. + /// + /// + /// The with which the + /// resource is associated. + /// + protected override void ApplyResourcesToObject( + object value, string objectName, CultureInfo cultureInfo) + { } } diff --git a/src/Spring/Spring.Core/Context/Support/ResourceHandlersSectionHandler.cs b/src/Spring/Spring.Core/Context/Support/ResourceHandlersSectionHandler.cs index 3bffbd2c..b589be08 100644 --- a/src/Spring/Spring.Core/Context/Support/ResourceHandlersSectionHandler.cs +++ b/src/Spring/Spring.Core/Context/Support/ResourceHandlersSectionHandler.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -23,112 +23,112 @@ using System.Configuration; using System.Globalization; using System.Xml; - using Spring.Core.IO; using Spring.Util; #endregion -namespace Spring.Context.Support +namespace Spring.Context.Support; + +/// +/// Handler for Spring.NET resourceHandlers config section. +/// +/// +///

+/// Spring allows registration of custom resource handlers that can be used to load +/// object definitions from. +///

+///

+/// For example, if you wanted to store your object definitions in a database instead +/// of in the config file, you could write a custom implementation +/// and register it with Spring using 'db' as a protocol name. +///

+///

+/// Afterwards, you would simply specify resource URI within the context config element +/// using your custom resource handler. +///

+///
+/// +///

+/// The following example shows how to configure both this section handler, +/// how to define custom resource within Spring config section, and how to load +/// object definitions using custom resource handler: +///

+/// +/// +/// +/// +///
+/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// Aleksandar Seovic +/// +public class ResourceHandlersSectionHandler : IConfigurationSectionHandler { + private const string HandlerElement = "handler"; + private const string ProtocolAttribute = "protocol"; + private const string TypeAttribute = "type"; + /// - /// Handler for Spring.NET resourceHandlers config section. + /// Registers resource handlers that are specified in + /// the resources config section with the . /// - /// - ///

- /// Spring allows registration of custom resource handlers that can be used to load - /// object definitions from. - ///

- ///

- /// For example, if you wanted to store your object definitions in a database instead - /// of in the config file, you could write a custom implementation - /// and register it with Spring using 'db' as a protocol name. - ///

- ///

- /// Afterwards, you would simply specify resource URI within the context config element - /// using your custom resource handler. - ///

- ///
- /// - ///

- /// The following example shows how to configure both this section handler, - /// how to define custom resource within Spring config section, and how to load - /// object definitions using custom resource handler: - ///

- /// - /// - /// - /// - ///
- /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// Aleksandar Seovic - /// - public class ResourceHandlersSectionHandler : IConfigurationSectionHandler + /// + /// The configuration settings in a corresponding parent + /// configuration section. Ignored. + /// + /// + /// The configuration context when called from the ASP.NET + /// configuration system. Otherwise, this parameter is reserved and + /// is . + /// + /// + /// The for the section. + /// + /// + /// This method always returns null, because resource handlers are registered + /// as a sideffect of its execution and there is no need to return anything. + /// + public object Create(object parent, object configContext, XmlNode section) { - private const string HandlerElement = "handler"; - private const string ProtocolAttribute = "protocol"; - private const string TypeAttribute = "type"; - - /// - /// Registers resource handlers that are specified in - /// the resources config section with the . - /// - /// - /// The configuration settings in a corresponding parent - /// configuration section. Ignored. - /// - /// - /// The configuration context when called from the ASP.NET - /// configuration system. Otherwise, this parameter is reserved and - /// is . - /// - /// - /// The for the section. - /// - /// - /// This method always returns null, because resource handlers are registered - /// as a sideffect of its execution and there is no need to return anything. - /// - public object Create(object parent, object configContext, XmlNode section) + if (section != null) { - if (section != null) + XmlNodeList resourceHandlers = ((XmlElement) section).GetElementsByTagName(HandlerElement); + + foreach (XmlElement handler in resourceHandlers) { - XmlNodeList resourceHandlers = ((XmlElement) section).GetElementsByTagName(HandlerElement); + string protocolName = GetRequiredAttributeValue(handler, ProtocolAttribute, section); + string typeName = GetRequiredAttributeValue(handler, TypeAttribute, section); - foreach (XmlElement handler in resourceHandlers) - { - string protocolName = GetRequiredAttributeValue(handler, ProtocolAttribute, section); - string typeName = GetRequiredAttributeValue(handler, TypeAttribute, section); - - ResourceHandlerRegistry.RegisterResourceHandler(protocolName, typeName); - } + ResourceHandlerRegistry.RegisterResourceHandler(protocolName, typeName); } - return null; } - private static string GetRequiredAttributeValue(XmlElement resourceElement, string requiredAttributeName, XmlNode section) + return null; + } + + private static string GetRequiredAttributeValue(XmlElement resourceElement, string requiredAttributeName, XmlNode section) + { + XmlAttribute attribute = resourceElement.GetAttributeNode(requiredAttributeName); + if (attribute == null) { - XmlAttribute attribute = resourceElement.GetAttributeNode(requiredAttributeName); - if (attribute == null) - { - string errorMessage = - string.Format(CultureInfo.InvariantCulture, "The '{0}' attribute is required for the resource handler definition.", - requiredAttributeName); - throw ConfigurationUtils.CreateConfigurationException(errorMessage, section); - } - return attribute.Value; + string errorMessage = + string.Format(CultureInfo.InvariantCulture, "The '{0}' attribute is required for the resource handler definition.", + requiredAttributeName); + throw ConfigurationUtils.CreateConfigurationException(errorMessage, section); } + + return attribute.Value; } } \ No newline at end of file diff --git a/src/Spring/Spring.Core/Context/Support/ResourceSetMessageSource.cs b/src/Spring/Spring.Core/Context/Support/ResourceSetMessageSource.cs index 617d399f..ac6aaa5c 100644 --- a/src/Spring/Spring.Core/Context/Support/ResourceSetMessageSource.cs +++ b/src/Spring/Spring.Core/Context/Support/ResourceSetMessageSource.cs @@ -24,208 +24,209 @@ using System.ComponentModel; using System.Globalization; using System.Resources; using System.Text; - using Spring.Objects.Factory; using Spring.Core.TypeConversion; #endregion -namespace Spring.Context.Support +namespace Spring.Context.Support; + +/// +/// An implementation that +/// accesses resources from .resx / .resource files. +/// +/// Note that for the method +/// GetResourceObject if the resource name resolves to null, then in +/// .NET 1.1 the return value will be String.Empty whereas +/// in .NET 2.0 it will return null. +/// Griffin Caprio (.NET) +/// Mark Pollack (.NET) +/// Aleksandar Seovic (.NET) +public class ResourceSetMessageSource : AbstractMessageSource, IInitializingObject { - /// - /// An implementation that - /// accesses resources from .resx / .resource files. - /// - /// Note that for the method - /// GetResourceObject if the resource name resolves to null, then in - /// .NET 1.1 the return value will be String.Empty whereas - /// in .NET 2.0 it will return null. - /// Griffin Caprio (.NET) - /// Mark Pollack (.NET) - /// Aleksandar Seovic (.NET) - public class ResourceSetMessageSource : AbstractMessageSource, IInitializingObject - { - #region Fields + #region Fields - private Dictionary _cachedResources; - private IList _resourceManagers; + private Dictionary _cachedResources; + private IList _resourceManagers; - #endregion + #endregion - /// - /// Creates a new instance of the - /// class. - /// - public ResourceSetMessageSource() - { - _cachedResources = new Dictionary(); - _resourceManagers = new List(); - } + /// + /// Creates a new instance of the + /// class. + /// + public ResourceSetMessageSource() + { + _cachedResources = new Dictionary(); + _resourceManagers = new List(); + } - /// - /// The collection of s - /// in this . - /// - public IList ResourceManagers - { - get { return _resourceManagers; } - set { _resourceManagers = value; } - } + /// + /// The collection of s + /// in this . + /// + public IList ResourceManagers + { + get { return _resourceManagers; } + set { _resourceManagers = value; } + } - /// - /// Resolves a given code by searching through each assembly name in - /// the base names array. - /// - /// The code to resolve. - /// - /// The to use for lookups. - /// - /// The message from the resource set. - protected override string ResolveMessage( - string code, CultureInfo cultureInfo) - { - string message = null; - for (int i = 0; message == null & i < _resourceManagers.Count; i++) - { - message = ResolveObject((ResourceManager) _resourceManagers[i], code, cultureInfo) as string; - } - return message; - } + /// + /// Resolves a given code by searching through each assembly name in + /// the base names array. + /// + /// The code to resolve. + /// + /// The to use for lookups. + /// + /// The message from the resource set. + protected override string ResolveMessage( + string code, CultureInfo cultureInfo) + { + string message = null; + for (int i = 0; message == null & i < _resourceManagers.Count; i++) + { + message = ResolveObject((ResourceManager) _resourceManagers[i], code, cultureInfo) as string; + } - /// - /// Resolves a given code by searching through each assembly name in the array. - /// - /// The code to resolve. - /// - /// The to use for lookups. - /// - /// The object from the resource set. - protected override object ResolveObject(string code, CultureInfo cultureInfo) - { - object obj = null; + return message; + } - for (int i = 0; obj == null & i < _resourceManagers.Count; i++) - { - obj = ResolveObject((ResourceManager) _resourceManagers[i], code, cultureInfo); - } - return obj; - } + /// + /// Resolves a given code by searching through each assembly name in the array. + /// + /// The code to resolve. + /// + /// The to use for lookups. + /// + /// The object from the resource set. + protected override object ResolveObject(string code, CultureInfo cultureInfo) + { + object obj = null; - // *** NOTE Don't use cref for ComponentResourceManager as it doesn't - // exist on 1.0 - // + for (int i = 0; obj == null & i < _resourceManagers.Count; i++) + { + obj = ResolveObject((ResourceManager) _resourceManagers[i], code, cultureInfo); + } - /// - /// Uses a System.ComponentModel.ComponentResourceManager - /// to apply resources to object properties. - /// Resource key names are of the form objectName.propertyName - /// - /// - /// This feature is not currently supported on version 1.0 of the .NET platform. - /// - /// - /// An object that contains the property values to be applied. - /// - /// - /// The base name of the object to use for the key lookup. - /// - /// - /// The to use for lookups. - /// If , uses the - /// value. - /// - /// - /// This feature is not currently supported on version 1.0 of the .NET platform. - /// - protected override void ApplyResourcesToObject(object value, string objectName, CultureInfo culture) - { - if(value != null) - { - ComponentResourceManager crm = new ComponentResourceManager(value.GetType()); - crm.ApplyResources(value, objectName, culture); - } - } + return obj; + } - /// - /// Resolves a code into an object given a base name. - /// - /// The to search. - /// The code to resolve. - /// - /// The to use for lookups. - /// - /// The object from the resource file. - protected object ResolveObject(ResourceManager resourceManager, string code, CultureInfo cultureInfo) - { - string cacheKey = code + "." + cultureInfo.Name; - object resource; + // *** NOTE Don't use cref for ComponentResourceManager as it doesn't + // exist on 1.0 + // - if (!_cachedResources.TryGetValue(cacheKey, out resource)) + /// + /// Uses a System.ComponentModel.ComponentResourceManager + /// to apply resources to object properties. + /// Resource key names are of the form objectName.propertyName + /// + /// + /// This feature is not currently supported on version 1.0 of the .NET platform. + /// + /// + /// An object that contains the property values to be applied. + /// + /// + /// The base name of the object to use for the key lookup. + /// + /// + /// The to use for lookups. + /// If , uses the + /// value. + /// + /// + /// This feature is not currently supported on version 1.0 of the .NET platform. + /// + protected override void ApplyResourcesToObject(object value, string objectName, CultureInfo culture) + { + if (value != null) + { + ComponentResourceManager crm = new ComponentResourceManager(value.GetType()); + crm.ApplyResources(value, objectName, culture); + } + } + + /// + /// Resolves a code into an object given a base name. + /// + /// The to search. + /// The code to resolve. + /// + /// The to use for lookups. + /// + /// The object from the resource file. + protected object ResolveObject(ResourceManager resourceManager, string code, CultureInfo cultureInfo) + { + string cacheKey = code + "." + cultureInfo.Name; + object resource; + + if (!_cachedResources.TryGetValue(cacheKey, out resource)) + { + resource = resourceManager.GetObject(code, cultureInfo); + if (resource != null) { - resource = resourceManager.GetObject(code, cultureInfo); - if (resource != null) + lock (_cachedResources) { - lock (_cachedResources) - { - _cachedResources[cacheKey] = resource; - } + _cachedResources[cacheKey] = resource; } } + } - return resource; - } + return resource; + } - /// - /// Returns a representation of the - /// . - /// - /// A representation of the - /// . - public override string ToString() - { - StringBuilder sb = new StringBuilder(); - sb.Append(GetType().Name); - sb.Append(" with ResourceManagers of base names = ["); - foreach (ResourceManager rm in ResourceManagers) - { - sb.Append(rm.BaseName); - sb.Append(","); - } - string s = sb.ToString(); - return s.TrimEnd(new char[] {','}) + "]"; - } + /// + /// Returns a representation of the + /// . + /// + /// A representation of the + /// . + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + sb.Append(GetType().Name); + sb.Append(" with ResourceManagers of base names = ["); + foreach (ResourceManager rm in ResourceManagers) + { + sb.Append(rm.BaseName); + sb.Append(","); + } - /// - /// Invoked by an - /// after it has set all object properties supplied. - /// - /// - ///

- /// The list may contain objects of type or - /// . types - /// are converted to instances using the notation - /// resourcename, assembly partial name. - ///

- ///
- /// - /// If the conversion from a to a - /// can't be performed. - /// - public void AfterPropertiesSet() - { - ResourceManagerConverter cvt = new ResourceManagerConverter(); - for (int i = 0; i < _resourceManagers.Count; i++) - { - object o = _resourceManagers[i]; - if (o is String) - { - _resourceManagers[i] = cvt.ConvertFrom((string) o); - } - else if (!(o is ResourceManager)) - { - throw new ArgumentException("Only Types of string and ResourceManager are allowed. Type " + o.GetType() + " was set instead."); - } - } - } - } + string s = sb.ToString(); + return s.TrimEnd(new char[] { ',' }) + "]"; + } + + /// + /// Invoked by an + /// after it has set all object properties supplied. + /// + /// + ///

+ /// The list may contain objects of type or + /// . types + /// are converted to instances using the notation + /// resourcename, assembly partial name. + ///

+ ///
+ /// + /// If the conversion from a to a + /// can't be performed. + /// + public void AfterPropertiesSet() + { + ResourceManagerConverter cvt = new ResourceManagerConverter(); + for (int i = 0; i < _resourceManagers.Count; i++) + { + object o = _resourceManagers[i]; + if (o is String) + { + _resourceManagers[i] = cvt.ConvertFrom((string) o); + } + else if (!(o is ResourceManager)) + { + throw new ArgumentException("Only Types of string and ResourceManager are allowed. Type " + o.GetType() + " was set instead."); + } + } + } } diff --git a/src/Spring/Spring.Core/Context/Support/StaticApplicationContext.cs b/src/Spring/Spring.Core/Context/Support/StaticApplicationContext.cs index e95efd01..10f2a75c 100644 --- a/src/Spring/Spring.Core/Context/Support/StaticApplicationContext.cs +++ b/src/Spring/Spring.Core/Context/Support/StaticApplicationContext.cs @@ -26,86 +26,85 @@ using Spring.Objects.Factory.Support; #endregion -namespace Spring.Context.Support +namespace Spring.Context.Support; + +/// +/// that allows concrete registration of +/// objects and messages in code, rather than from external configuration sources. +/// +/// +///

+/// Mainly useful for testing. +///

+///
+/// Rod Johnson +/// Griffin Caprio (.NET) +public class StaticApplicationContext : GenericApplicationContext { - /// - /// that allows concrete registration of - /// objects and messages in code, rather than from external configuration sources. - /// - /// - ///

- /// Mainly useful for testing. - ///

- ///
- /// Rod Johnson - /// Griffin Caprio (.NET) - public class StaticApplicationContext : GenericApplicationContext - { - /// - /// Creates a new instance of the StaticApplicationContext class. - /// - public StaticApplicationContext() : this( null ) {} + /// + /// Creates a new instance of the StaticApplicationContext class. + /// + public StaticApplicationContext() : this(null) { } - /// - /// Creates a new instance of the StaticApplicationContext class. - /// - /// The parent application context. - public StaticApplicationContext( IApplicationContext parentContext ) - : base( null, true, parentContext ) - { - RegisterSingleton( MessageSourceObjectName, typeof( StaticMessageSource ), null ); - } + /// + /// Creates a new instance of the StaticApplicationContext class. + /// + /// The parent application context. + public StaticApplicationContext(IApplicationContext parentContext) + : base(null, true, parentContext) + { + RegisterSingleton(MessageSourceObjectName, typeof(StaticMessageSource), null); + } - /// - /// Creates a new, named instance of the StaticApplicationContext class. - /// - /// the context name - /// The parent application context. - public StaticApplicationContext( string name, IApplicationContext parentContext ) - : base( name, true, parentContext ) - { - RegisterSingleton( MessageSourceObjectName, typeof( StaticMessageSource ), null ); - } + /// + /// Creates a new, named instance of the StaticApplicationContext class. + /// + /// the context name + /// The parent application context. + public StaticApplicationContext(string name, IApplicationContext parentContext) + : base(name, true, parentContext) + { + RegisterSingleton(MessageSourceObjectName, typeof(StaticMessageSource), null); + } - /// - /// Do nothing: we rely on callers to update our public methods. - /// - protected override void RefreshObjectFactory() {} + /// + /// Do nothing: we rely on callers to update our public methods. + /// + protected override void RefreshObjectFactory() { } - /// - /// Register a singleton object with the default object factory. - /// - /// The name of the object. - /// The of the object. - /// The property values for the singleton instance. - public void RegisterSingleton( string name, Type classType, MutablePropertyValues propertyValues ) - { - DefaultListableObjectFactory.RegisterObjectDefinition( name, new RootObjectDefinition( classType, propertyValues ) ); - } + /// + /// Register a singleton object with the default object factory. + /// + /// The name of the object. + /// The of the object. + /// The property values for the singleton instance. + public void RegisterSingleton(string name, Type classType, MutablePropertyValues propertyValues) + { + DefaultListableObjectFactory.RegisterObjectDefinition(name, new RootObjectDefinition(classType, propertyValues)); + } - /// - /// Registers a prototype object with the default object factory. - /// - /// The name of the prototype object. - /// The of the prototype object. - /// The property values for the prototype instance. - public void RegisterPrototype( string name, Type classType, MutablePropertyValues propertyValues ) - { - DefaultListableObjectFactory.RegisterObjectDefinition(name, new RootObjectDefinition(classType, propertyValues, false)); - } + /// + /// Registers a prototype object with the default object factory. + /// + /// The name of the prototype object. + /// The of the prototype object. + /// The property values for the prototype instance. + public void RegisterPrototype(string name, Type classType, MutablePropertyValues propertyValues) + { + DefaultListableObjectFactory.RegisterObjectDefinition(name, new RootObjectDefinition(classType, propertyValues, false)); + } - /// - /// Associate the given message with the given code. - /// - /// The lookup code. - /// - /// The that the message should be found within. - /// - /// The message associated with the lookup code. - public void AddMessage( string code, CultureInfo cultureInfo, string defaultMessage ) - { - StaticMessageSource messageSource = (StaticMessageSource) GetObject( MessageSourceObjectName ); - messageSource.AddMessage( code, cultureInfo, defaultMessage ); - } - } + /// + /// Associate the given message with the given code. + /// + /// The lookup code. + /// + /// The that the message should be found within. + /// + /// The message associated with the lookup code. + public void AddMessage(string code, CultureInfo cultureInfo, string defaultMessage) + { + StaticMessageSource messageSource = (StaticMessageSource) GetObject(MessageSourceObjectName); + messageSource.AddMessage(code, cultureInfo, defaultMessage); + } } diff --git a/src/Spring/Spring.Core/Context/Support/StaticMessageSource.cs b/src/Spring/Spring.Core/Context/Support/StaticMessageSource.cs index 1d63d947..b7b88f6c 100644 --- a/src/Spring/Spring.Core/Context/Support/StaticMessageSource.cs +++ b/src/Spring/Spring.Core/Context/Support/StaticMessageSource.cs @@ -22,177 +22,176 @@ using System.ComponentModel; using System.Globalization; using System.Text; -namespace Spring.Context.Support +namespace Spring.Context.Support; + +/// +/// Simple implementation of +/// that allows messages to be held in an object and added programmatically. +/// +/// +///

+/// Mainly useful for testing. +///

+///

+/// This supports internationalization. +///

+///
+/// Rod Johnson +/// Juergen Hoeller +/// Griffin Caprio (.NET) +/// +public class StaticMessageSource : AbstractMessageSource { + private Dictionary _messages; + private Dictionary _objects; + /// - /// Simple implementation of - /// that allows messages to be held in an object and added programmatically. - /// - /// - ///

- /// Mainly useful for testing. - ///

- ///

- /// This supports internationalization. - ///

- ///
- /// Rod Johnson - /// Juergen Hoeller - /// Griffin Caprio (.NET) - /// - public class StaticMessageSource : AbstractMessageSource + /// Creates a new instance of the + /// class. + /// + public StaticMessageSource() { - private Dictionary _messages; - private Dictionary _objects; + _messages = new Dictionary(); + _objects = new Dictionary(); + } - /// - /// Creates a new instance of the - /// class. - /// - public StaticMessageSource() + /// + /// Returns a format string. + /// + /// The code of the message to resolve. + /// + /// The to resolve the + /// code for. + /// + /// + /// A format string or if not found. + /// + /// + protected override string ResolveMessage(string code, CultureInfo cultureInfo) + { + string key = GetLookupKey(code, cultureInfo); + string message; + _messages.TryGetValue(key, out message); + return message; + } + + /// + /// Resolves an object (typically an icon or bitmap). + /// + /// The code of the object to resolve. + /// + /// The to resolve the + /// code for. + /// + /// + /// The resolved object or if not found. + /// + /// + protected override object ResolveObject(string code, CultureInfo cultureInfo) + { + string key = GetLookupKey(code, cultureInfo); + object obj; + _objects.TryGetValue(key, out obj); + return obj; + } + + // *** NOTE Don't use cref for ComponentResourceManager as it doesn't + // exist on 1.0 + // + + /// + /// Applies resources to object properties. + /// + /// + ///

+ /// Uses a System.ComponentModel.ComponentResourceManager + /// internally to apply resources to object properties. Resource key + /// names are of the form objectName.propertyName. + ///

+ ///

+ /// This feature is not currently supported on version 1.0 of the .NET platform. + ///

+ ///
+ /// + /// An object that contains the property values to be applied. + /// + /// + /// The base name of the object to use for key lookup. + /// + /// + /// The with which the + /// resource is associated. + /// + /// + /// This feature is not currently supported on version 1.0 of the .NET platform. + /// + /// + protected override void ApplyResourcesToObject(object value, string objectName, CultureInfo cultureInfo) + { + if (value != null) { - _messages = new Dictionary(); - _objects = new Dictionary(); - } - - /// - /// Returns a format string. - /// - /// The code of the message to resolve. - /// - /// The to resolve the - /// code for. - /// - /// - /// A format string or if not found. - /// - /// - protected override string ResolveMessage(string code, CultureInfo cultureInfo) - { - string key = GetLookupKey(code, cultureInfo); - string message; - _messages.TryGetValue(key, out message); - return message; - } - - /// - /// Resolves an object (typically an icon or bitmap). - /// - /// The code of the object to resolve. - /// - /// The to resolve the - /// code for. - /// - /// - /// The resolved object or if not found. - /// - /// - protected override object ResolveObject(string code, CultureInfo cultureInfo) - { - string key = GetLookupKey(code, cultureInfo); - object obj; - _objects.TryGetValue(key, out obj); - return obj; - } - - - // *** NOTE Don't use cref for ComponentResourceManager as it doesn't - // exist on 1.0 - // - - /// - /// Applies resources to object properties. - /// - /// - ///

- /// Uses a System.ComponentModel.ComponentResourceManager - /// internally to apply resources to object properties. Resource key - /// names are of the form objectName.propertyName. - ///

- ///

- /// This feature is not currently supported on version 1.0 of the .NET platform. - ///

- ///
- /// - /// An object that contains the property values to be applied. - /// - /// - /// The base name of the object to use for key lookup. - /// - /// - /// The with which the - /// resource is associated. - /// - /// - /// This feature is not currently supported on version 1.0 of the .NET platform. - /// - /// - protected override void ApplyResourcesToObject(object value, string objectName, CultureInfo cultureInfo) - { - if(value != null) - { - new ComponentResourceManager(value.GetType()).ApplyResources(value, objectName, cultureInfo); - } - } - - /// - /// Associate the supplied with the - /// supplied . - /// - /// The lookup code. - /// - /// The to resolve the - /// code for. - /// - /// - /// The message format associated with this lookup code. - /// - public void AddMessage( - string code, CultureInfo culture, string messageFormat) - { - _messages.Add(GetLookupKey(code, culture), messageFormat); - } - - /// - /// Associate the supplied with the - /// supplied . - /// - /// The lookup code. - /// - /// The to resolve the - /// code for. - /// - /// - /// The object associated with this lookup code. - /// - public void AddObject(string code, CultureInfo cultureInfo, object value) - { - _objects.Add(GetLookupKey(code, cultureInfo), value); - } - - /// - /// Returns a representation of this - /// message source. - /// - /// - /// A containing all of this message - /// source's messages. - /// - public override string ToString() - { - StringBuilder output = new StringBuilder(); - output.Append(GetType().Name); - output.Append(" : "); - foreach (string code in _messages.Keys) - { - output.AppendFormat("['{0}' : '{1}']", code, _messages[code]); - } - return output.ToString(); - } - - private static string GetLookupKey(string code, CultureInfo culture) - { - return new StringBuilder(code).Append("_").Append(culture).ToString(); + new ComponentResourceManager(value.GetType()).ApplyResources(value, objectName, cultureInfo); } } + + /// + /// Associate the supplied with the + /// supplied . + /// + /// The lookup code. + /// + /// The to resolve the + /// code for. + /// + /// + /// The message format associated with this lookup code. + /// + public void AddMessage( + string code, CultureInfo culture, string messageFormat) + { + _messages.Add(GetLookupKey(code, culture), messageFormat); + } + + /// + /// Associate the supplied with the + /// supplied . + /// + /// The lookup code. + /// + /// The to resolve the + /// code for. + /// + /// + /// The object associated with this lookup code. + /// + public void AddObject(string code, CultureInfo cultureInfo, object value) + { + _objects.Add(GetLookupKey(code, cultureInfo), value); + } + + /// + /// Returns a representation of this + /// message source. + /// + /// + /// A containing all of this message + /// source's messages. + /// + public override string ToString() + { + StringBuilder output = new StringBuilder(); + output.Append(GetType().Name); + output.Append(" : "); + foreach (string code in _messages.Keys) + { + output.AppendFormat("['{0}' : '{1}']", code, _messages[code]); + } + + return output.ToString(); + } + + private static string GetLookupKey(string code, CultureInfo culture) + { + return new StringBuilder(code).Append("_").Append(culture).ToString(); + } } diff --git a/src/Spring/Spring.Core/Context/Support/TypeAliasesSectionHandler.cs b/src/Spring/Spring.Core/Context/Support/TypeAliasesSectionHandler.cs index df111615..22e035e9 100644 --- a/src/Spring/Spring.Core/Context/Support/TypeAliasesSectionHandler.cs +++ b/src/Spring/Spring.Core/Context/Support/TypeAliasesSectionHandler.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -23,107 +23,107 @@ using System.Configuration; using System.Globalization; using System.Xml; - using Spring.Core.TypeResolution; using Spring.Util; #endregion -namespace Spring.Context.Support +namespace Spring.Context.Support; + +/// +/// Configuration section handler for the Spring.NET typeAliases +/// config section. +/// +/// +///

+/// Type aliases can be used instead of fully qualified type names anywhere +/// a type name is expected in a Spring.NET configuration file. +///

+///

+/// This includes type names specified within an object definition, as well +/// as values of the properties or constructor arguments that expect +/// instances. +///

+///
+/// +///

+/// The following example shows how to configure both this section handler and +/// how to define type aliases within a Spring.NET config section: +///

+/// +/// +/// +/// +///
+/// +/// +/// +/// +/// +/// +/// ... +/// +/// ... +/// +/// +/// +/// +/// Aleksandar Seovic +/// +public class TypeAliasesSectionHandler : IConfigurationSectionHandler { + private const string AliasElementName = "alias"; + private const string NameAttributeName = "name"; + private const string TypeAttributeName = "type"; + /// - /// Configuration section handler for the Spring.NET typeAliases - /// config section. + /// Populates using values specified in + /// the typeAliases config section. /// - /// - ///

- /// Type aliases can be used instead of fully qualified type names anywhere - /// a type name is expected in a Spring.NET configuration file. - ///

- ///

- /// This includes type names specified within an object definition, as well - /// as values of the properties or constructor arguments that expect - /// instances. - ///

- ///
- /// - ///

- /// The following example shows how to configure both this section handler and - /// how to define type aliases within a Spring.NET config section: - ///

- /// - /// - /// - /// - ///
- /// - /// - /// - /// - /// - /// - /// ... - /// - /// ... - /// - /// - /// - /// - /// Aleksandar Seovic - /// - public class TypeAliasesSectionHandler : IConfigurationSectionHandler + /// + /// The configuration settings in a corresponding parent + /// configuration section. + /// + /// + /// The configuration context when called from the ASP.NET + /// configuration system. Otherwise, this parameter is reserved and + /// is . + /// + /// + /// The for the section. + /// + /// + /// This method always returns , because the + /// is populated as a side-effect of this + /// object's execution and thus there is no need to return anything. + /// + public object Create(object parent, object configContext, XmlNode section) { - private const string AliasElementName = "alias"; - private const string NameAttributeName = "name"; - private const string TypeAttributeName = "type"; - - /// - /// Populates using values specified in - /// the typeAliases config section. - /// - /// - /// The configuration settings in a corresponding parent - /// configuration section. - /// - /// - /// The configuration context when called from the ASP.NET - /// configuration system. Otherwise, this parameter is reserved and - /// is . - /// - /// - /// The for the section. - /// - /// - /// This method always returns , because the - /// is populated as a side-effect of this - /// object's execution and thus there is no need to return anything. - /// - public object Create(object parent, object configContext, XmlNode section) + if (section != null) { - if (section != null) + XmlNodeList aliases = ((XmlElement) section).GetElementsByTagName(AliasElementName); + foreach (XmlElement aliasElement in aliases) { - XmlNodeList aliases = ((XmlElement) section).GetElementsByTagName(AliasElementName); - foreach (XmlElement aliasElement in aliases) - { - string alias = GetRequiredAttributeValue(aliasElement, NameAttributeName, section); - string typeName = GetRequiredAttributeValue(aliasElement, TypeAttributeName, section); - TypeRegistry.RegisterType(alias, typeName); - } + string alias = GetRequiredAttributeValue(aliasElement, NameAttributeName, section); + string typeName = GetRequiredAttributeValue(aliasElement, TypeAttributeName, section); + TypeRegistry.RegisterType(alias, typeName); } - return null; } - private static string GetRequiredAttributeValue( - XmlElement aliasElement, string requiredAttributeName, XmlNode section) - { - XmlAttribute attribute = aliasElement.GetAttributeNode(requiredAttributeName); - if (attribute == null) - { - string errorMessage = string.Format(CultureInfo.InvariantCulture, - "The '{0}' attribute is required for the (type) element.", requiredAttributeName); - throw ConfigurationUtils.CreateConfigurationException(errorMessage, section); - } - return attribute.Value; - } + return null; } -} \ No newline at end of file + + private static string GetRequiredAttributeValue( + XmlElement aliasElement, string requiredAttributeName, XmlNode section) + { + XmlAttribute attribute = aliasElement.GetAttributeNode(requiredAttributeName); + if (attribute == null) + { + string errorMessage = string.Format(CultureInfo.InvariantCulture, + "The '{0}' attribute is required for the (type) element.", requiredAttributeName); + throw ConfigurationUtils.CreateConfigurationException(errorMessage, section); + } + + return attribute.Value; + } +} diff --git a/src/Spring/Spring.Core/Context/Support/TypeConvertersSectionHandler.cs b/src/Spring/Spring.Core/Context/Support/TypeConvertersSectionHandler.cs index da9c1697..3d2f979b 100644 --- a/src/Spring/Spring.Core/Context/Support/TypeConvertersSectionHandler.cs +++ b/src/Spring/Spring.Core/Context/Support/TypeConvertersSectionHandler.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -24,124 +24,124 @@ using System.ComponentModel; using System.Configuration; using System.Globalization; using System.Xml; - using Spring.Core.TypeConversion; using Spring.Util; #endregion -namespace Spring.Context.Support +namespace Spring.Context.Support; + +/// +/// Configuration section handler for the Spring.NET typeConverters +/// config section. +/// +/// +///

+/// Type converters are used to convert objects from one type into another +/// when injecting property values, evaluating expressions, performing data +/// binding, etc. +///

+///

+/// They are a very powerful mechanism as they allow Spring.NET to automatically +/// convert string-based property values from the configuration file into the appropriate +/// type based on the target property's type or to convert string values submitted +/// via a web form into a type that is used by your data model when Spring.NET data +/// binding is used. Because they offer such tremendous help, you should always provide +/// a type converter implementation for your custom types that you want to be able to use +/// for injected properties or for data binding. +///

+///

+/// The standard .NET mechanism for specifying type converter for a particular type is +/// to decorate the type with a , passing the type +/// of the -derived class as a parameter. +///

+///

+/// This mechanism will still work and is a preferred way of defining type converters if +/// you control the source code for the type that you want to define a converter for. However, +/// this configuration section allows you to specify converters for the types that you don't +/// control and it also allows you to override some of the standard type converters, such as +/// the ones that are defined for some of the types in the .NET Base Class Library. +///

+///
+/// +///

+/// The following example shows how to configure both this section handler and +/// how to define type converters within a Spring.NET config section: +///

+/// +/// +/// +/// +///
+/// +/// +/// +/// +/// +/// +/// ... +/// +/// ... +/// +/// +/// +/// +/// Aleksandar Seovic +/// +public class TypeConvertersSectionHandler : IConfigurationSectionHandler { + private const string ConverterElementName = "converter"; + private const string ForAttributeName = "for"; + private const string TypeAttributeName = "type"; + /// - /// Configuration section handler for the Spring.NET typeConverters - /// config section. + /// Populates using values specified in + /// the typeConverters config section. /// - /// - ///

- /// Type converters are used to convert objects from one type into another - /// when injecting property values, evaluating expressions, performing data - /// binding, etc. - ///

- ///

- /// They are a very powerful mechanism as they allow Spring.NET to automatically - /// convert string-based property values from the configuration file into the appropriate - /// type based on the target property's type or to convert string values submitted - /// via a web form into a type that is used by your data model when Spring.NET data - /// binding is used. Because they offer such tremendous help, you should always provide - /// a type converter implementation for your custom types that you want to be able to use - /// for injected properties or for data binding. - ///

- ///

- /// The standard .NET mechanism for specifying type converter for a particular type is - /// to decorate the type with a , passing the type - /// of the -derived class as a parameter. - ///

- ///

- /// This mechanism will still work and is a preferred way of defining type converters if - /// you control the source code for the type that you want to define a converter for. However, - /// this configuration section allows you to specify converters for the types that you don't - /// control and it also allows you to override some of the standard type converters, such as - /// the ones that are defined for some of the types in the .NET Base Class Library. - ///

- ///
- /// - ///

- /// The following example shows how to configure both this section handler and - /// how to define type converters within a Spring.NET config section: - ///

- /// - /// - /// - /// - ///
- /// - /// - /// - /// - /// - /// - /// ... - /// - /// ... - /// - /// - /// - /// - /// Aleksandar Seovic - /// - public class TypeConvertersSectionHandler : IConfigurationSectionHandler + /// + /// The configuration settings in a corresponding parent + /// configuration section. + /// + /// + /// The configuration context when called from the ASP.NET + /// configuration system. Otherwise, this parameter is reserved and + /// is . + /// + /// + /// The for the section. + /// + /// + /// This method always returns , because the + /// is populated as a side-effect of + /// its execution and thus there is no need to return anything. + /// + public object Create(object parent, object configContext, XmlNode section) { - private const string ConverterElementName = "converter"; - private const string ForAttributeName = "for"; - private const string TypeAttributeName = "type"; - - /// - /// Populates using values specified in - /// the typeConverters config section. - /// - /// - /// The configuration settings in a corresponding parent - /// configuration section. - /// - /// - /// The configuration context when called from the ASP.NET - /// configuration system. Otherwise, this parameter is reserved and - /// is . - /// - /// - /// The for the section. - /// - /// - /// This method always returns , because the - /// is populated as a side-effect of - /// its execution and thus there is no need to return anything. - /// - public object Create(object parent, object configContext, XmlNode section) + if (section != null) { - if (section != null) + XmlNodeList converters = ((XmlElement) section).GetElementsByTagName(ConverterElementName); + foreach (XmlElement aliasElement in converters) { - XmlNodeList converters = ((XmlElement) section).GetElementsByTagName(ConverterElementName); - foreach (XmlElement aliasElement in converters) - { - string forType = GetRequiredAttributeValue(aliasElement, ForAttributeName, section); - string converterType = GetRequiredAttributeValue(aliasElement, TypeAttributeName, section); - TypeConverterRegistry.RegisterConverter(forType, converterType); - } + string forType = GetRequiredAttributeValue(aliasElement, ForAttributeName, section); + string converterType = GetRequiredAttributeValue(aliasElement, TypeAttributeName, section); + TypeConverterRegistry.RegisterConverter(forType, converterType); } - return null; } - private static string GetRequiredAttributeValue( - XmlElement aliasElement, string requiredAttributeName, XmlNode section) - { - XmlAttribute attribute = aliasElement.GetAttributeNode(requiredAttributeName); - if (attribute == null) - { - string errorMessage = string.Format(CultureInfo.InvariantCulture, - "The '{0}' attribute is required for the element.", requiredAttributeName); - throw ConfigurationUtils.CreateConfigurationException(errorMessage, section); - } - return attribute.Value; - } + return null; } -} \ No newline at end of file + + private static string GetRequiredAttributeValue( + XmlElement aliasElement, string requiredAttributeName, XmlNode section) + { + XmlAttribute attribute = aliasElement.GetAttributeNode(requiredAttributeName); + if (attribute == null) + { + string errorMessage = string.Format(CultureInfo.InvariantCulture, + "The '{0}' attribute is required for the element.", requiredAttributeName); + throw ConfigurationUtils.CreateConfigurationException(errorMessage, section); + } + + return attribute.Value; + } +} diff --git a/src/Spring/Spring.Core/Context/Support/XmlApplicationContext.cs b/src/Spring/Spring.Core/Context/Support/XmlApplicationContext.cs index b0f6a63a..1b906d4d 100644 --- a/src/Spring/Spring.Core/Context/Support/XmlApplicationContext.cs +++ b/src/Spring/Spring.Core/Context/Support/XmlApplicationContext.cs @@ -20,265 +20,265 @@ using Spring.Core.IO; -namespace Spring.Context.Support +namespace Spring.Context.Support; + +/// +/// An implementation that +/// reads context definitions from XML based resources. +/// +/// +///

+/// Currently, the resources that are supported are the file, +/// http, ftp, config and assembly resource +/// types. +///

+///

+/// You can provide custom implementations of the +/// interface and and register them +/// with any that inherits +/// from the +/// +/// interface. +///

+/// +/// In case of multiple config locations, later object definitions will +/// override ones defined in previously loaded resources. This can be +/// leveraged to deliberately override certain object definitions via an +/// extra XML file. +/// +///
+/// +///

+/// Find below some examples of instantiating an +/// using a +/// variety of different XML resources. +///

+/// +/// // an XmlApplicationContext that reads its object definitions from an +/// // XML file that has been embedded in an assembly... +/// IApplicationContext context = new XmlApplicationContext +/// ( +/// "assembly://AssemblyName/NameSpace/ResourceName" +/// ); +/// +/// // an XmlApplicationContext that reads its object definitions from a +/// // number of disparate XML resources... +/// IApplicationContext context = new XmlApplicationContext +/// ( +/// // from an XML file that has been embedded in an assembly... +/// "assembly://AssemblyName/NameSpace/ResourceName", +/// // and from a (relative) filesystem-based resource... +/// "file://Objects/services.xml", +/// // and from an App.config / Web.config resource... +/// "config://spring/objects" +/// ); +/// +///
+/// Rod Johnson +/// Juergen Hoeller +/// Griffin Caprio (.NET) +/// +/// +/// +public class XmlApplicationContext : AbstractXmlApplicationContext { + private readonly string[] _configurationLocations; + private readonly IResource[] _configurationResources; + /// - /// An implementation that - /// reads context definitions from XML based resources. + /// Initializes a new instance of the XmlApplicationContext class. /// - /// - ///

- /// Currently, the resources that are supported are the file, - /// http, ftp, config and assembly resource - /// types. - ///

- ///

- /// You can provide custom implementations of the - /// interface and and register them - /// with any that inherits - /// from the - /// - /// interface. - ///

- /// - /// In case of multiple config locations, later object definitions will - /// override ones defined in previously loaded resources. This can be - /// leveraged to deliberately override certain object definitions via an - /// extra XML file. - /// - ///
- /// - ///

- /// Find below some examples of instantiating an - /// using a - /// variety of different XML resources. - ///

- /// - /// // an XmlApplicationContext that reads its object definitions from an - /// // XML file that has been embedded in an assembly... - /// IApplicationContext context = new XmlApplicationContext - /// ( - /// "assembly://AssemblyName/NameSpace/ResourceName" - /// ); - /// - /// // an XmlApplicationContext that reads its object definitions from a - /// // number of disparate XML resources... - /// IApplicationContext context = new XmlApplicationContext - /// ( - /// // from an XML file that has been embedded in an assembly... - /// "assembly://AssemblyName/NameSpace/ResourceName", - /// // and from a (relative) filesystem-based resource... - /// "file://Objects/services.xml", - /// // and from an App.config / Web.config resource... - /// "config://spring/objects" - /// ); - /// - ///
- /// Rod Johnson - /// Juergen Hoeller - /// Griffin Caprio (.NET) - /// - /// - /// - public class XmlApplicationContext : AbstractXmlApplicationContext + public XmlApplicationContext(XmlApplicationContextArgs args) + : base(args.Name, args.CaseSensitive, args.ParentContext) { - private readonly string[] _configurationLocations; - private readonly IResource[] _configurationResources; + _configurationLocations = args.ConfigurationLocations; + _configurationResources = args.ConfigurationResources; - - - /// - /// Initializes a new instance of the XmlApplicationContext class. - /// - public XmlApplicationContext(XmlApplicationContextArgs args) - : base(args.Name, args.CaseSensitive, args.ParentContext) + if (args.Refresh) { - _configurationLocations = args.ConfigurationLocations; - _configurationResources = args.ConfigurationResources; + bool hasLocations = args.ConfigurationLocations.Length > 0; + bool hasResources = args.ConfigurationResources.Length > 0; - if (args.Refresh) + if (!hasLocations && !hasResources) + throw new ArgumentException("You must provide either or both Configuration Locations and/or Configuration Resources!"); + + if (hasLocations || hasResources) { - bool hasLocations = args.ConfigurationLocations.Length > 0; - bool hasResources = args.ConfigurationResources.Length > 0; - - if (!hasLocations && !hasResources) - throw new ArgumentException("You must provide either or both Configuration Locations and/or Configuration Resources!"); - - if (hasLocations || hasResources) - { - Refresh(); - } + Refresh(); } - - } - - - - /// - /// Creates a new instance of the - /// class, - /// loading the definitions from the supplied XML resource locations. - /// - /// The created context will be case sensitive. - /// - /// Any number of XML based object definition resource locations. - /// - public XmlApplicationContext(params string[] configurationLocations) - : this(new XmlApplicationContextArgs(string.Empty, null, configurationLocations, null, true, true)) - { } - - /// - /// Creates a new instance of the - /// class, - /// loading the definitions from the supplied XML resource locations. - /// - /// Flag specifying whether to make this context case sensitive or not. - /// - /// Any number of XML based object definition resource locations. - /// - public XmlApplicationContext(bool caseSensitive, - params string[] configurationLocations) - : this(new XmlApplicationContextArgs(string.Empty, null, configurationLocations, null, caseSensitive, true)) - { } - - /// - /// Creates a new instance of the - /// class, - /// loading the definitions from the supplied XML resource locations. - /// - /// The application context name. - /// Flag specifying whether to make this context case sensitive or not. - /// - /// Any number of XML based object definition resource locations. - /// - public XmlApplicationContext(string name, bool caseSensitive, - params string[] configurationLocations) - : this(new XmlApplicationContextArgs(name, null, configurationLocations, null, caseSensitive, true)) - { } - - /// - /// Creates a new instance of the - /// class, - /// loading the definitions from the supplied XML resource locations, - /// with the given . - /// - /// - /// The parent context (may be ). - /// - /// - /// Any number of XML based object definition resource locations. - /// - public XmlApplicationContext( - IApplicationContext parentContext, - params string[] configurationLocations) - : this(new XmlApplicationContextArgs(string.Empty, parentContext, configurationLocations, null, true, true)) - { } - - /// - /// Creates a new instance of the - /// class, - /// loading the definitions from the supplied XML resource locations, - /// with the given . - /// - /// Flag specifying whether to make this context case sensitive or not. - /// - /// The parent context (may be ). - /// - /// - /// Any number of XML based object definition resource locations. - /// - public XmlApplicationContext( - bool caseSensitive, - IApplicationContext parentContext, - params string[] configurationLocations) - : this(new XmlApplicationContextArgs(string.Empty, parentContext, configurationLocations, null, caseSensitive, true)) - { } - - /// - /// Creates a new instance of the - /// class, - /// loading the definitions from the supplied XML resource locations, - /// with the given . - /// - /// The application context name. - /// Flag specifying whether to make this context case sensitive or not. - /// - /// The parent context (may be ). - /// - /// - /// Any number of XML based object definition resource locations. - /// - public XmlApplicationContext( - string name, - bool caseSensitive, - IApplicationContext parentContext, - params string[] configurationLocations) - : this(new XmlApplicationContextArgs(name, parentContext, configurationLocations, null, caseSensitive, true)) - { } - - /// - /// Creates a new instance of the - /// class, - /// loading the definitions from the supplied XML resource locations, - /// with the given . - /// - /// - /// This constructor is meant to be used by derived classes. By passing =false, it is - /// the responsibility of the deriving class to call to initialize the context instance. - /// - /// if true, is called automatically. - /// The application context name. - /// Flag specifying whether to make this context case sensitive or not. - /// - /// The parent context (may be ). - /// - /// - /// Any number of XML based object definition resource locations. - /// - public XmlApplicationContext( - bool refresh, - string name, - bool caseSensitive, - IApplicationContext parentContext, - params string[] configurationLocations) - : this(new XmlApplicationContextArgs(name, parentContext, configurationLocations, null, true, refresh)) - { } - - - public XmlApplicationContext( - bool refresh, - string name, - bool caseSensitive, - IApplicationContext parentContext, - string[] configurationLocations, - IResource[] configurationResources) - : this(new XmlApplicationContextArgs(name, parentContext, configurationLocations, configurationResources, caseSensitive, refresh)) - { } - - - /// - /// An array of resource locations, referring to the XML object - /// definition files with which this context is to be built. - /// - /// - /// An array of resource locations, or if none. - /// - /// - protected override string[] ConfigurationLocations - { - get { return _configurationLocations; } - } - - /// - /// An array of resources instances with which this context is to be built. - /// - /// - /// An array of s, or if none. - /// - /// - protected override IResource[] ConfigurationResources - { - get { return _configurationResources; } } } + + /// + /// Creates a new instance of the + /// class, + /// loading the definitions from the supplied XML resource locations. + /// + /// The created context will be case sensitive. + /// + /// Any number of XML based object definition resource locations. + /// + public XmlApplicationContext(params string[] configurationLocations) + : this(new XmlApplicationContextArgs(string.Empty, null, configurationLocations, null, true, true)) + { + } + + /// + /// Creates a new instance of the + /// class, + /// loading the definitions from the supplied XML resource locations. + /// + /// Flag specifying whether to make this context case sensitive or not. + /// + /// Any number of XML based object definition resource locations. + /// + public XmlApplicationContext(bool caseSensitive, + params string[] configurationLocations) + : this(new XmlApplicationContextArgs(string.Empty, null, configurationLocations, null, caseSensitive, true)) + { + } + + /// + /// Creates a new instance of the + /// class, + /// loading the definitions from the supplied XML resource locations. + /// + /// The application context name. + /// Flag specifying whether to make this context case sensitive or not. + /// + /// Any number of XML based object definition resource locations. + /// + public XmlApplicationContext(string name, bool caseSensitive, + params string[] configurationLocations) + : this(new XmlApplicationContextArgs(name, null, configurationLocations, null, caseSensitive, true)) + { + } + + /// + /// Creates a new instance of the + /// class, + /// loading the definitions from the supplied XML resource locations, + /// with the given . + /// + /// + /// The parent context (may be ). + /// + /// + /// Any number of XML based object definition resource locations. + /// + public XmlApplicationContext( + IApplicationContext parentContext, + params string[] configurationLocations) + : this(new XmlApplicationContextArgs(string.Empty, parentContext, configurationLocations, null, true, true)) + { + } + + /// + /// Creates a new instance of the + /// class, + /// loading the definitions from the supplied XML resource locations, + /// with the given . + /// + /// Flag specifying whether to make this context case sensitive or not. + /// + /// The parent context (may be ). + /// + /// + /// Any number of XML based object definition resource locations. + /// + public XmlApplicationContext( + bool caseSensitive, + IApplicationContext parentContext, + params string[] configurationLocations) + : this(new XmlApplicationContextArgs(string.Empty, parentContext, configurationLocations, null, caseSensitive, true)) + { + } + + /// + /// Creates a new instance of the + /// class, + /// loading the definitions from the supplied XML resource locations, + /// with the given . + /// + /// The application context name. + /// Flag specifying whether to make this context case sensitive or not. + /// + /// The parent context (may be ). + /// + /// + /// Any number of XML based object definition resource locations. + /// + public XmlApplicationContext( + string name, + bool caseSensitive, + IApplicationContext parentContext, + params string[] configurationLocations) + : this(new XmlApplicationContextArgs(name, parentContext, configurationLocations, null, caseSensitive, true)) + { + } + + /// + /// Creates a new instance of the + /// class, + /// loading the definitions from the supplied XML resource locations, + /// with the given . + /// + /// + /// This constructor is meant to be used by derived classes. By passing =false, it is + /// the responsibility of the deriving class to call to initialize the context instance. + /// + /// if true, is called automatically. + /// The application context name. + /// Flag specifying whether to make this context case sensitive or not. + /// + /// The parent context (may be ). + /// + /// + /// Any number of XML based object definition resource locations. + /// + public XmlApplicationContext( + bool refresh, + string name, + bool caseSensitive, + IApplicationContext parentContext, + params string[] configurationLocations) + : this(new XmlApplicationContextArgs(name, parentContext, configurationLocations, null, true, refresh)) + { + } + + public XmlApplicationContext( + bool refresh, + string name, + bool caseSensitive, + IApplicationContext parentContext, + string[] configurationLocations, + IResource[] configurationResources) + : this(new XmlApplicationContextArgs(name, parentContext, configurationLocations, configurationResources, caseSensitive, refresh)) + { + } + + /// + /// An array of resource locations, referring to the XML object + /// definition files with which this context is to be built. + /// + /// + /// An array of resource locations, or if none. + /// + /// + protected override string[] ConfigurationLocations + { + get { return _configurationLocations; } + } + + /// + /// An array of resources instances with which this context is to be built. + /// + /// + /// An array of s, or if none. + /// + /// + protected override IResource[] ConfigurationResources + { + get { return _configurationResources; } + } } diff --git a/src/Spring/Spring.Core/Context/Support/XmlApplicationContextArgs.cs b/src/Spring/Spring.Core/Context/Support/XmlApplicationContextArgs.cs index bdc3365e..fd2e5e55 100644 --- a/src/Spring/Spring.Core/Context/Support/XmlApplicationContextArgs.cs +++ b/src/Spring/Spring.Core/Context/Support/XmlApplicationContextArgs.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -20,54 +20,52 @@ using Spring.Core.IO; -namespace Spring.Context.Support +namespace Spring.Context.Support; + +/// +/// Encapsulates arguments to the class. +/// +public class XmlApplicationContextArgs : AbstractXmlApplicationContextArgs { + private const bool DEFAULT_REFRESH = true; + private const bool DEFAULT_CASESENSITIVE = true; + /// - /// Encapsulates arguments to the class. + /// Initializes a new instance of the class. /// - public class XmlApplicationContextArgs : AbstractXmlApplicationContextArgs + public XmlApplicationContextArgs() + : this(string.Empty, null, null, null, DEFAULT_CASESENSITIVE, DEFAULT_REFRESH) { + } - private const bool DEFAULT_REFRESH = true; - private const bool DEFAULT_CASESENSITIVE = true; + /// + /// Initializes a new instance of the class. + /// + /// The name. + /// The parent context. + /// The configuration locations. + /// The configuration resources. + public XmlApplicationContextArgs(string name, IApplicationContext parentContext, string[] configurationLocations, IResource[] configurationResources) + : this(name, parentContext, configurationLocations, configurationResources, DEFAULT_CASESENSITIVE, DEFAULT_REFRESH) + { + } - - /// - /// Initializes a new instance of the class. - /// - public XmlApplicationContextArgs() - : this(string.Empty, null, null, null, DEFAULT_CASESENSITIVE, DEFAULT_REFRESH) - { } - - - /// - /// Initializes a new instance of the class. - /// - /// The name. - /// The parent context. - /// The configuration locations. - /// The configuration resources. - public XmlApplicationContextArgs(string name, IApplicationContext parentContext, string[] configurationLocations, IResource[] configurationResources) - : this(name, parentContext, configurationLocations, configurationResources, DEFAULT_CASESENSITIVE, DEFAULT_REFRESH) - { } - - /// - /// Initializes a new instance of the XmlApplicationContextArgs class. - /// - /// The name. - /// The parent context. - /// The configuration locations. - /// The configuration resources. - /// if set to true [case sensitive]. - /// if set to true [refresh]. - public XmlApplicationContextArgs(string name, IApplicationContext parentContext, string[] configurationLocations, IResource[] configurationResources, bool caseSensitive, bool refresh) - { - Name = name; - ParentContext = parentContext; - ConfigurationLocations = configurationLocations; - ConfigurationResources = configurationResources; - CaseSensitive = caseSensitive; - Refresh = refresh; - } + /// + /// Initializes a new instance of the XmlApplicationContextArgs class. + /// + /// The name. + /// The parent context. + /// The configuration locations. + /// The configuration resources. + /// if set to true [case sensitive]. + /// if set to true [refresh]. + public XmlApplicationContextArgs(string name, IApplicationContext parentContext, string[] configurationLocations, IResource[] configurationResources, bool caseSensitive, bool refresh) + { + Name = name; + ParentContext = parentContext; + ConfigurationLocations = configurationLocations; + ConfigurationResources = configurationResources; + CaseSensitive = caseSensitive; + Refresh = refresh; } } diff --git a/src/Spring/Spring.Core/Core/AttributeAccessorSupport.cs b/src/Spring/Spring.Core/Core/AttributeAccessorSupport.cs index 0455ccef..41990d62 100644 --- a/src/Spring/Spring.Core/Core/AttributeAccessorSupport.cs +++ b/src/Spring/Spring.Core/Core/AttributeAccessorSupport.cs @@ -20,88 +20,93 @@ using System.Diagnostics; -namespace Spring.Core +namespace Spring.Core; + +/// +/// Support class for , providing +/// a base implementation of all methods. To be extended by subclasses. +/// +[Serializable] +public abstract class AttributeAccessorSupport : IAttributeAccessor { - /// - /// Support class for , providing - /// a base implementation of all methods. To be extended by subclasses. - /// - [Serializable] - public abstract class AttributeAccessorSupport : IAttributeAccessor + /** Map with String keys and Object values */ + private readonly IDictionary _attributes = new Dictionary(); + + public virtual void SetAttribute(string name, object value) { - /** Map with String keys and Object values */ - private readonly IDictionary _attributes = new Dictionary(); - - - public virtual void SetAttribute(string name, object value) + Trace.Assert(name != null, "Name must not be null"); + if (value != null) { - Trace.Assert(name != null, "Name must not be null"); - if (value != null) { - _attributes.Add(name, value); - } - else { - RemoveAttribute(name); - } - } - - public virtual object GetAttribute(string name) + _attributes.Add(name, value); + } + else { - Trace.Assert(name != null, "Name must not be null"); - if (_attributes.ContainsKey(name)) - return _attributes[name]; - return null; + RemoveAttribute(name); + } + } + + public virtual object GetAttribute(string name) + { + Trace.Assert(name != null, "Name must not be null"); + if (_attributes.ContainsKey(name)) + return _attributes[name]; + return null; + } + + public virtual object RemoveAttribute(string name) + { + Trace.Assert(name != null, "Name must not be null"); + if (_attributes.ContainsKey(name)) + return _attributes.Remove(name); + return false; + } + + public bool HasAttribute(string name) + { + Trace.Assert(name != null, "Name must not be null"); + return _attributes.ContainsKey(name); + } + + public String[] AttributeNames + { + get + { + return _attributes.Keys.ToArray(); + } + } + + /** + * Copy the attributes from the supplied AttributeAccessor to this accessor. + * @param source the AttributeAccessor to copy from + */ + protected void CopyAttributesFrom(IAttributeAccessor source) + { + Trace.Assert(source != null, "Source must not be null"); + string[] attributeNames = source.AttributeNames; + foreach (string attributeName in attributeNames) + { + SetAttribute(attributeName, source.GetAttribute(attributeName)); + } + } + + public override bool Equals(object other) + { + if (this == other) + { + return true; } - public virtual object RemoveAttribute(string name) { - Trace.Assert(name != null, "Name must not be null"); - if (_attributes.ContainsKey(name)) - return _attributes.Remove(name); - return false; - } - - public bool HasAttribute(string name) + if (!(other is AttributeAccessorSupport)) { - Trace.Assert(name != null, "Name must not be null"); - return _attributes.ContainsKey(name); - } - - public String[] AttributeNames - { - get - { - return _attributes.Keys.ToArray(); - } + return false; } + var that = (AttributeAccessorSupport) other; + return _attributes.Equals(that._attributes); + } - /** - * Copy the attributes from the supplied AttributeAccessor to this accessor. - * @param source the AttributeAccessor to copy from - */ - protected void CopyAttributesFrom(IAttributeAccessor source) { - Trace.Assert(source != null, "Source must not be null"); - string[] attributeNames = source.AttributeNames; - foreach(string attributeName in attributeNames) - { - SetAttribute(attributeName, source.GetAttribute(attributeName)); - } - } - - - public override bool Equals(object other) { - if (this == other) { - return true; - } - if (!(other is AttributeAccessorSupport)) { - return false; - } - var that = (AttributeAccessorSupport) other; - return _attributes.Equals(that._attributes); - } - - public override int GetHashCode() - { - return _attributes.GetHashCode(); - } + public override int GetHashCode() + { + return _attributes.GetHashCode(); } } diff --git a/src/Spring/Spring.Core/Core/CannotLoadObjectTypeException.cs b/src/Spring/Spring.Core/Core/CannotLoadObjectTypeException.cs index 4eeab991..0a9e4b91 100644 --- a/src/Spring/Spring.Core/Core/CannotLoadObjectTypeException.cs +++ b/src/Spring/Spring.Core/Core/CannotLoadObjectTypeException.cs @@ -26,153 +26,149 @@ using Spring.Util; #endregion -namespace Spring.Core +namespace Spring.Core; + +/// +/// Exception thrown when the ObjectFactory cannot load the specified type of a given object. +/// +/// Mark Pollack +[Serializable] +public class CannotLoadObjectTypeException : FatalReflectionException { + #region Constructor (s) / Destructor + /// - /// Exception thrown when the ObjectFactory cannot load the specified type of a given object. + /// Initializes a new instance of the class. /// - /// Mark Pollack - [Serializable] - public class CannotLoadObjectTypeException : FatalReflectionException + public CannotLoadObjectTypeException() { - #region Constructor (s) / Destructor - - /// - /// Initializes a new instance of the class. - /// - public CannotLoadObjectTypeException() - { - } - - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - public CannotLoadObjectTypeException(string message) - : base(message) - { - } - - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception that is being wrapped. - /// - public CannotLoadObjectTypeException(string message, Exception rootCause) - : base(message, rootCause) - { - } - - - /// - /// Initializes a new instance of the class. - /// - /// The resource description that the object definition came from. - /// Name of the object requested - /// Name of the object type. - /// The root cause. - public CannotLoadObjectTypeException(string resourceDescription, string objectName, string objectTypeName, Exception rootCause ) - : base("Cannot resolve type [" + objectTypeName + "] for object with name '" + objectName + "' defined in " + resourceDescription, rootCause) - { - this.resourceDescription = resourceDescription; - this.objectName = objectName; - this.objectTypeName = objectTypeName; - } - - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The - /// that holds the serialized object data about the exception being thrown. - /// - /// - /// The - /// that contains contextual information about the source or destination. - /// - protected CannotLoadObjectTypeException(SerializationInfo info, StreamingContext context) - : base(info, context) - { - - resourceDescription = info.GetString("ResourceDescription"); - objectName = info.GetString("ObjectName"); - objectTypeName = info.GetString("ObjectTypeName"); - } - - - #endregion - - #region Properties - - /// - /// Gets he name of the object we are trying to load. - /// - /// The name of the object. - public string ObjectName - { - get { return objectName; } - } - - /// - /// Gets the name of the object type we are trying to load. - /// - /// The name of the object type. - public string ObjectTypeName - { - get { return objectTypeName; } - } - - /// - /// Gets the resource description that the object definition came from - /// - /// The resource description. - public string ResourceDescription - { - get { return resourceDescription; } - } - - #endregion - - #region Methods - - /// - /// Populates a with - /// the data needed to serialize the target object. - /// - /// - /// The to populate - /// with data. - /// - /// - /// The destination (see ) - /// for this serialization. - /// - [SecurityPermission(SecurityAction.Demand, SerializationFormatter=true)] - public override void GetObjectData(SerializationInfo info, StreamingContext context) - { - base.GetObjectData(info, context); - info.AddValue("ResourceDescription", ResourceDescription); - info.AddValue("ObjectName", ObjectName); - info.AddValue("ObjectTypeName", ObjectTypeName); - } - - #endregion - - #region Fields - - private string resourceDescription; - private string objectName; - private string objectTypeName; - - #endregion } + + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + public CannotLoadObjectTypeException(string message) + : base(message) + { + } + + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception that is being wrapped. + /// + public CannotLoadObjectTypeException(string message, Exception rootCause) + : base(message, rootCause) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The resource description that the object definition came from. + /// Name of the object requested + /// Name of the object type. + /// The root cause. + public CannotLoadObjectTypeException(string resourceDescription, string objectName, string objectTypeName, Exception rootCause) + : base("Cannot resolve type [" + objectTypeName + "] for object with name '" + objectName + "' defined in " + resourceDescription, rootCause) + { + this.resourceDescription = resourceDescription; + this.objectName = objectName; + this.objectTypeName = objectTypeName; + } + + /// + /// Creates a new instance of the + /// class. + /// + /// + /// The + /// that holds the serialized object data about the exception being thrown. + /// + /// + /// The + /// that contains contextual information about the source or destination. + /// + protected CannotLoadObjectTypeException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + resourceDescription = info.GetString("ResourceDescription"); + objectName = info.GetString("ObjectName"); + objectTypeName = info.GetString("ObjectTypeName"); + } + + #endregion + + #region Properties + + /// + /// Gets he name of the object we are trying to load. + /// + /// The name of the object. + public string ObjectName + { + get { return objectName; } + } + + /// + /// Gets the name of the object type we are trying to load. + /// + /// The name of the object type. + public string ObjectTypeName + { + get { return objectTypeName; } + } + + /// + /// Gets the resource description that the object definition came from + /// + /// The resource description. + public string ResourceDescription + { + get { return resourceDescription; } + } + + #endregion + + #region Methods + + /// + /// Populates a with + /// the data needed to serialize the target object. + /// + /// + /// The to populate + /// with data. + /// + /// + /// The destination (see ) + /// for this serialization. + /// + [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)] + public override void GetObjectData(SerializationInfo info, StreamingContext context) + { + base.GetObjectData(info, context); + info.AddValue("ResourceDescription", ResourceDescription); + info.AddValue("ObjectName", ObjectName); + info.AddValue("ObjectTypeName", ObjectTypeName); + } + + #endregion + + #region Fields + + private string resourceDescription; + private string objectName; + private string objectTypeName; + + #endregion } diff --git a/src/Spring/Spring.Core/Core/ComposedCriteria.cs b/src/Spring/Spring.Core/Core/ComposedCriteria.cs index 85672893..057e61de 100644 --- a/src/Spring/Spring.Core/Core/ComposedCriteria.cs +++ b/src/Spring/Spring.Core/Core/ComposedCriteria.cs @@ -22,92 +22,92 @@ #endregion -namespace Spring.Core +namespace Spring.Core; + +/// +/// A implementation that represents +/// a composed collection of instances. +/// +public class ComposedCriteria : ICriteria { + #region Constructor (s) / Destructor + /// - /// A implementation that represents - /// a composed collection of instances. + /// Creates a new instance of the + /// class. /// - public class ComposedCriteria : ICriteria + public ComposedCriteria() : this(null) { - #region Constructor (s) / Destructor - - /// - /// Creates a new instance of the - /// class. - /// - public ComposedCriteria() : this(null) - { - } - - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A user-defined (child) criteria that will be composed into this instance. - /// - public ComposedCriteria(ICriteria criteria) - { - _criteria = new List(); - Add(criteria); - } - - #endregion - - #region Methods - - /// - /// Does the supplied satisfy the criteria encapsulated by - /// this instance? - /// - /// The data to be checked by this criteria instance. - /// - /// True if the supplied satisfies the criteria encapsulated - /// by this instance; false if not or the supplied is null. - /// - public virtual bool IsSatisfied(object datum) - { - foreach (ICriteria criteria in _criteria) - { - if (!criteria.IsSatisfied(datum)) - { - return false; - } - } - return true; - } - - /// - /// Adds the supplied into the criteria - /// composed within this instance. - /// - /// - /// The to be added. - /// - public void Add(ICriteria criteria) - { - if (criteria != null) - { - _criteria.Add(criteria); - } - } - - #endregion - - /// - /// The list of composing this - /// instance. - /// - protected IList Criteria - { - get { return _criteria; } - } - - #region Fields - - private IList _criteria; - - #endregion } -} + + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A user-defined (child) criteria that will be composed into this instance. + /// + public ComposedCriteria(ICriteria criteria) + { + _criteria = new List(); + Add(criteria); + } + + #endregion + + #region Methods + + /// + /// Does the supplied satisfy the criteria encapsulated by + /// this instance? + /// + /// The data to be checked by this criteria instance. + /// + /// True if the supplied satisfies the criteria encapsulated + /// by this instance; false if not or the supplied is null. + /// + public virtual bool IsSatisfied(object datum) + { + foreach (ICriteria criteria in _criteria) + { + if (!criteria.IsSatisfied(datum)) + { + return false; + } + } + + return true; + } + + /// + /// Adds the supplied into the criteria + /// composed within this instance. + /// + /// + /// The to be added. + /// + public void Add(ICriteria criteria) + { + if (criteria != null) + { + _criteria.Add(criteria); + } + } + + #endregion + + /// + /// The list of composing this + /// instance. + /// + protected IList Criteria + { + get { return _criteria; } + } + + #region Fields + + private IList _criteria; + + #endregion +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Core/ControlFlowFactory.cs b/src/Spring/Spring.Core/Core/ControlFlowFactory.cs index 8c9b037f..ad842b0d 100644 --- a/src/Spring/Spring.Core/Core/ControlFlowFactory.cs +++ b/src/Spring/Spring.Core/Core/ControlFlowFactory.cs @@ -25,125 +25,126 @@ using System.Reflection; #endregion -namespace Spring.Core +namespace Spring.Core; + +/// +/// Factory class to conceal any default implementation. +/// +/// Rod Johnson +/// Simon White (.NET) +public abstract class ControlFlowFactory { - /// - /// Factory class to conceal any default implementation. - /// - /// Rod Johnson - /// Simon White (.NET) - public abstract class ControlFlowFactory - { - /// - /// Creates a new instance of the - /// implementation provided by this factory. - /// - /// - /// A new instance of the - /// implementation provided by this factory. - /// - public static IControlFlow CreateControlFlow() - { - return new DefaultControlFlow(); - } + /// + /// Creates a new instance of the + /// implementation provided by this factory. + /// + /// + /// A new instance of the + /// implementation provided by this factory. + /// + public static IControlFlow CreateControlFlow() + { + return new DefaultControlFlow(); + } - private class DefaultControlFlow : IControlFlow - { - private StackTrace _stackTrace; + private class DefaultControlFlow : IControlFlow + { + private StackTrace _stackTrace; - #region Constructor (s) / Destructor + #region Constructor (s) / Destructor - /// - /// Creates a new instance of the - /// class. - /// - public DefaultControlFlow() - { - _stackTrace = new StackTrace(); - } + /// + /// Creates a new instance of the + /// class. + /// + public DefaultControlFlow() + { + _stackTrace = new StackTrace(); + } - #endregion + #endregion - #region IControlFlow Members + #region IControlFlow Members - /// - /// Detects whether the caller is under the supplied , - /// according to the current stacktrace. - /// - /// - bool IControlFlow.Under(Type type) - { - return IsMatch(new MethodsDeclaredTypeCriteria(type)); - } + /// + /// Detects whether the caller is under the supplied , + /// according to the current stacktrace. + /// + /// + bool IControlFlow.Under(Type type) + { + return IsMatch(new MethodsDeclaredTypeCriteria(type)); + } - /// - /// Detects whether the caller is under the supplied - /// and , according to the current stacktrace. - /// - /// - ///

- /// Matches the whole method name. - ///

- ///
- /// - bool IControlFlow.Under(Type type, string methodName) - { - ComposedCriteria criteria = new ComposedCriteria(); - criteria.Add(new MethodsDeclaredTypeCriteria(type)); - criteria.Add(new RegularExpressionMethodNameCriteria(methodName)); - return IsMatch(criteria); - } + /// + /// Detects whether the caller is under the supplied + /// and , according to the current stacktrace. + /// + /// + ///

+ /// Matches the whole method name. + ///

+ ///
+ /// + bool IControlFlow.Under(Type type, string methodName) + { + ComposedCriteria criteria = new ComposedCriteria(); + criteria.Add(new MethodsDeclaredTypeCriteria(type)); + criteria.Add(new RegularExpressionMethodNameCriteria(methodName)); + return IsMatch(criteria); + } - /// - /// Does the current stack trace contain the supplied ? - /// - /// - ///

- /// This leaves it up to the caller to decide what matches, but is obviously less of - /// an abstraction because the caller must know the exact format of the underlying - /// stack trace. - ///

- ///
- /// - bool IControlFlow.UnderToken(string token) - { - return _stackTrace.ToString().IndexOf(token) != -1; - } + /// + /// Does the current stack trace contain the supplied ? + /// + /// + ///

+ /// This leaves it up to the caller to decide what matches, but is obviously less of + /// an abstraction because the caller must know the exact format of the underlying + /// stack trace. + ///

+ ///
+ /// + bool IControlFlow.UnderToken(string token) + { + return _stackTrace.ToString().IndexOf(token) != -1; + } - private bool IsMatch(ICriteria criteria) - { - for (int i = 0; i < _stackTrace.FrameCount; i++) - { - MethodBase method = _stackTrace.GetFrame(i).GetMethod(); - if(criteria.IsSatisfied(method)) - { - return true; - } - } - return false; - } + private bool IsMatch(ICriteria criteria) + { + for (int i = 0; i < _stackTrace.FrameCount; i++) + { + MethodBase method = _stackTrace.GetFrame(i).GetMethod(); + if (criteria.IsSatisfied(method)) + { + return true; + } + } - private sealed class MethodsDeclaredTypeCriteria : ICriteria - { - public MethodsDeclaredTypeCriteria(Type typeToMatch) - { - _typeToMatch = typeToMatch; - } + return false; + } - public bool IsSatisfied(object datum) - { - MethodBase method = datum as MethodBase; - if(method != null && method.DeclaringType != null) - { - return method.DeclaringType.Equals(_typeToMatch); - } - return false; - } + private sealed class MethodsDeclaredTypeCriteria : ICriteria + { + public MethodsDeclaredTypeCriteria(Type typeToMatch) + { + _typeToMatch = typeToMatch; + } - private Type _typeToMatch; - } + public bool IsSatisfied(object datum) + { + MethodBase method = datum as MethodBase; + if (method != null && method.DeclaringType != null) + { + return method.DeclaringType.Equals(_typeToMatch); + } - #endregion - } - } + return false; + } + + private Type _typeToMatch; + } + + #endregion + } } diff --git a/src/Spring/Spring.Core/Core/Conventions.cs b/src/Spring/Spring.Core/Core/Conventions.cs index db8a3b80..35b836fc 100644 --- a/src/Spring/Spring.Core/Core/Conventions.cs +++ b/src/Spring/Spring.Core/Core/Conventions.cs @@ -20,50 +20,51 @@ using Spring.Util; -namespace Spring.Core +namespace Spring.Core; + +/// +/// Provides methods to support various naming and other conventions used throughout the framework. +/// Mainly for internal use within the framework. +/// +/// Rob Harrop +/// Juergen Hoeller +/// Mark Pollack (.NET) +public sealed class Conventions { - /// - /// Provides methods to support various naming and other conventions used throughout the framework. - /// Mainly for internal use within the framework. + /// Convert Strings in attribute name format (lowercase, hyphens separating words) + /// into property name format (camel-cased). For example, transaction-manager is + /// converted into transactionManager. /// - /// Rob Harrop - /// Juergen Hoeller - /// Mark Pollack (.NET) - public sealed class Conventions + public static string AttributeNameToPropertyName(string attributeName) { - /// Convert Strings in attribute name format (lowercase, hyphens separating words) - /// into property name format (camel-cased). For example, transaction-manager is - /// converted into transactionManager. - /// - public static string AttributeNameToPropertyName(string attributeName) + AssertUtils.ArgumentNotNull(attributeName, "attributeName"); + if (attributeName.IndexOf("-") == -1) { - AssertUtils.ArgumentNotNull(attributeName, "attributeName"); - if (attributeName.IndexOf("-") == -1) - { - return attributeName; - } - char[] chars = attributeName.ToCharArray(); - char[] result = new char[chars.Length - 1]; // not completely accurate but good guess - int currPos = 0; - bool upperCaseNext = false; - for (int i = 0; i < chars.Length; i++) - { - char c = chars[i]; - if (c == '-') - { - upperCaseNext = true; - } - else if (upperCaseNext) - { - result[currPos++] = Char.ToUpper(c); - upperCaseNext = false; - } - else - { - result[currPos++] = c; - } - } - return new String(result, 0, currPos); + return attributeName; } + + char[] chars = attributeName.ToCharArray(); + char[] result = new char[chars.Length - 1]; // not completely accurate but good guess + int currPos = 0; + bool upperCaseNext = false; + for (int i = 0; i < chars.Length; i++) + { + char c = chars[i]; + if (c == '-') + { + upperCaseNext = true; + } + else if (upperCaseNext) + { + result[currPos++] = Char.ToUpper(c); + upperCaseNext = false; + } + else + { + result[currPos++] = c; + } + } + + return new String(result, 0, currPos); } } diff --git a/src/Spring/Spring.Core/Core/CriteriaMemberFilter.cs b/src/Spring/Spring.Core/Core/CriteriaMemberFilter.cs index 122fcd47..c168431e 100644 --- a/src/Spring/Spring.Core/Core/CriteriaMemberFilter.cs +++ b/src/Spring/Spring.Core/Core/CriteriaMemberFilter.cs @@ -16,53 +16,52 @@ using System.Reflection; -namespace Spring.Core +namespace Spring.Core; + +/// +/// Convenience class that exposes a signature that matches the +/// delegate. +/// +/// +///

+/// Useful when filtering members via the +/// mechanism. +///

+///
+/// Rick Evans +public class CriteriaMemberFilter { /// - /// Convenience class that exposes a signature that matches the - /// delegate. + /// Creates a new instance of the + /// class. /// - /// - ///

- /// Useful when filtering members via the - /// mechanism. - ///

- ///
- /// Rick Evans - public class CriteriaMemberFilter + public CriteriaMemberFilter() { - /// - /// Creates a new instance of the - /// class. - /// - public CriteriaMemberFilter () - { - } - - /// - /// Returns true if the supplied instance - /// satisfies the supplied (which must be an - /// implementation). - /// - /// - /// The instance that will be checked to see if - /// it matches the supplied . - /// - /// - /// The criteria against which to filter the supplied - /// instance. - /// - /// - /// True if the supplied instance - /// satisfies the supplied (which must be an - /// implementation); false if not or the - /// supplied is not an - /// implementation or is null. - /// - public virtual bool FilterMemberByCriteria (MemberInfo member, object filterCriteria) - { - ICriteria criteria = filterCriteria as ICriteria; - return criteria.IsSatisfied (member); - } } -} \ No newline at end of file + + /// + /// Returns true if the supplied instance + /// satisfies the supplied (which must be an + /// implementation). + /// + /// + /// The instance that will be checked to see if + /// it matches the supplied . + /// + /// + /// The criteria against which to filter the supplied + /// instance. + /// + /// + /// True if the supplied instance + /// satisfies the supplied (which must be an + /// implementation); false if not or the + /// supplied is not an + /// implementation or is null. + /// + public virtual bool FilterMemberByCriteria(MemberInfo member, object filterCriteria) + { + ICriteria criteria = filterCriteria as ICriteria; + return criteria.IsSatisfied(member); + } +} diff --git a/src/Spring/Spring.Core/Core/IAttributeAccessor.cs b/src/Spring/Spring.Core/Core/IAttributeAccessor.cs index f7c16824..0246b1b9 100644 --- a/src/Spring/Spring.Core/Core/IAttributeAccessor.cs +++ b/src/Spring/Spring.Core/Core/IAttributeAccessor.cs @@ -18,54 +18,52 @@ #endregion -namespace Spring.Core +namespace Spring.Core; + +/// +/// Interface defining a generic contract for attaching and accessing metadata +/// to/from arbitrary objects. +/// +public interface IAttributeAccessor { /// - /// Interface defining a generic contract for attaching and accessing metadata - /// to/from arbitrary objects. + /// Set the attribute defined by name to the supplied value. + /// In general, users should take care to prevent overlaps with other + /// metadata attributes by using fully-qualified names, perhaps using + /// class or package names as prefix. /// - public interface IAttributeAccessor - { - /// - /// Set the attribute defined by name to the supplied value. - /// In general, users should take care to prevent overlaps with other - /// metadata attributes by using fully-qualified names, perhaps using - /// class or package names as prefix. - /// - /// the unique attribute key - /// the attribute value to be attached - void SetAttribute(string name, object value); + /// the unique attribute key + /// the attribute value to be attached + void SetAttribute(string name, object value); - /// - /// Get the value of the attribute identified by name. - /// Return null if the attribute doesn't exist. - /// - /// the unique attribute key - /// the current value of the attribute, if any - object GetAttribute(string name); + /// + /// Get the value of the attribute identified by name. + /// Return null if the attribute doesn't exist. + /// + /// the unique attribute key + /// the current value of the attribute, if any + object GetAttribute(string name); - /// - /// Remove the attribute identified by name and return its value. - /// Return null if no attribute under name is found. - /// - /// the unique attribute key - /// The last value of the attribute, if any - object RemoveAttribute(string name); + /// + /// Remove the attribute identified by name and return its value. + /// Return null if no attribute under name is found. + /// + /// the unique attribute key + /// The last value of the attribute, if any + object RemoveAttribute(string name); - /// - /// Checks weather a specific attributes exists - /// - /// The unique attribute key - /// - /// true if the attribute identified by name exists. - /// Otherwise return false - /// - bool HasAttribute(string name); + /// + /// Checks weather a specific attributes exists + /// + /// The unique attribute key + /// + /// true if the attribute identified by name exists. + /// Otherwise return false + /// + bool HasAttribute(string name); - /// - /// Return the names of all attributes. - /// - String[] AttributeNames { get; } - - } + /// + /// Return the names of all attributes. + /// + String[] AttributeNames { get; } } diff --git a/src/Spring/Spring.Core/Core/IControlFlow.cs b/src/Spring/Spring.Core/Core/IControlFlow.cs index 3524a690..b9b90ac4 100644 --- a/src/Spring/Spring.Core/Core/IControlFlow.cs +++ b/src/Spring/Spring.Core/Core/IControlFlow.cs @@ -22,55 +22,54 @@ #endregion -namespace Spring.Core +namespace Spring.Core; + +/// +/// Interface to be implemented by objects that can return information about +/// the current call stack. +/// +/// +///

+/// Useful in AOP (as an expression of the AspectJ cflow concept) but not AOP-specific. +///

+///
+/// Rod Johnson +/// Aleksandar Seovic (.Net) +public interface IControlFlow { - /// - /// Interface to be implemented by objects that can return information about - /// the current call stack. - /// - /// - ///

- /// Useful in AOP (as an expression of the AspectJ cflow concept) but not AOP-specific. - ///

- ///
- /// Rod Johnson - /// Aleksandar Seovic (.Net) - public interface IControlFlow - { - /// - /// Detects whether the caller is under the supplied , - /// according to the current stacktrace. - /// - /// - /// The to look for. - /// - /// - /// if the caller is under the supplied . - /// - bool Under(Type type); + /// + /// Detects whether the caller is under the supplied , + /// according to the current stacktrace. + /// + /// + /// The to look for. + /// + /// + /// if the caller is under the supplied . + /// + bool Under(Type type); - /// - /// Detects whether the caller is under the supplied - /// and , according to the current stacktrace. - /// - /// - /// The to look for. - /// - /// The name of the method to look for. - /// - /// if the caller is under the supplied - /// and . - /// - bool Under(Type type, string methodName); + /// + /// Detects whether the caller is under the supplied + /// and , according to the current stacktrace. + /// + /// + /// The to look for. + /// + /// The name of the method to look for. + /// + /// if the caller is under the supplied + /// and . + /// + bool Under(Type type, string methodName); - /// - /// Does the current stack trace contain the supplied ? - /// - /// The token to match against. - /// - /// if the current stack trace contains the supplied - /// . - /// - bool UnderToken(string token); - } -} + /// + /// Does the current stack trace contain the supplied ? + /// + /// The token to match against. + /// + /// if the current stack trace contains the supplied + /// . + /// + bool UnderToken(string token); +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Core/ICriteria.cs b/src/Spring/Spring.Core/Core/ICriteria.cs index 72691cab..482d6bec 100644 --- a/src/Spring/Spring.Core/Core/ICriteria.cs +++ b/src/Spring/Spring.Core/Core/ICriteria.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -20,31 +20,28 @@ #region Imports - - #endregion -namespace Spring.Core +namespace Spring.Core; + +/// +/// The criteria for an arbitrary filter. +/// +/// Rick Evans +public interface ICriteria { /// - /// The criteria for an arbitrary filter. + /// Does the supplied satisfy the criteria + /// encapsulated by this instance? /// - /// Rick Evans - public interface ICriteria - { - /// - /// Does the supplied satisfy the criteria - /// encapsulated by this instance? - /// - /// - /// The datum to be checked by this criteria instance. - /// - /// - /// if the supplied - /// satisfies the criteria encapsulated by this instance; - /// if not, or the supplied - /// is . - /// - bool IsSatisfied (object datum); - } + /// + /// The datum to be checked by this criteria instance. + /// + /// + /// if the supplied + /// satisfies the criteria encapsulated by this instance; + /// if not, or the supplied + /// is . + /// + bool IsSatisfied(object datum); } diff --git a/src/Spring/Spring.Core/Core/IErrorCoded.cs b/src/Spring/Spring.Core/Core/IErrorCoded.cs index 57b654d7..e509fceb 100644 --- a/src/Spring/Spring.Core/Core/IErrorCoded.cs +++ b/src/Spring/Spring.Core/Core/IErrorCoded.cs @@ -1,14 +1,14 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. - * + * Copyright � 2002-2011 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. @@ -20,40 +20,37 @@ #region Imports - - #endregion -namespace Spring.Core +namespace Spring.Core; + +/// +/// Interface that can be implemented by exceptions etc that are error coded. +/// +/// +///

+/// The error code is a , rather than a number, so it can +/// be given user-readable values, such as "object.failureDescription". +///

+///
+/// Rod Johnson +/// Aleksandar Seovic (.Net) +public interface IErrorCoded { - /// - /// Interface that can be implemented by exceptions etc that are error coded. - /// - /// - ///

- /// The error code is a , rather than a number, so it can - /// be given user-readable values, such as "object.failureDescription". - ///

- ///
- /// Rod Johnson - /// Aleksandar Seovic (.Net) - public interface IErrorCoded - { - /// - /// Return the error code associated with this failure. - /// - /// - ///

- /// The GUI can render this anyway it pleases, allowing for I18n etc. - ///

- ///
- /// - /// The error code associated with this failure, - /// or the empty string instance if not error-coded. - /// - string ErrorCode - { - get; - } - } -} \ No newline at end of file + /// + /// Return the error code associated with this failure. + /// + /// + ///

+ /// The GUI can render this anyway it pleases, allowing for I18n etc. + ///

+ ///
+ /// + /// The error code associated with this failure, + /// or the empty string instance if not error-coded. + /// + string ErrorCode + { + get; + } +} diff --git a/src/Spring/Spring.Core/Core/IO/AbstractResource.cs b/src/Spring/Spring.Core/Core/IO/AbstractResource.cs index aebe339e..ffa5cc95 100644 --- a/src/Spring/Spring.Core/Core/IO/AbstractResource.cs +++ b/src/Spring/Spring.Core/Core/IO/AbstractResource.cs @@ -25,724 +25,732 @@ using Spring.Util; #endregion -namespace Spring.Core.IO +namespace Spring.Core.IO; + +/// +/// Convenience base class for +/// implementations, pre-implementing typical behavior. +/// +/// +///

+/// The method will +/// check whether a or +/// can be opened; +/// will always return +/// ; +/// and +/// throw an exception; +/// and will +/// return the value of the +/// property. +///

+///
+/// Juergen Hoeller +/// Rick Evans (.NET) +/// Aleksandar Seovic (.NET) +/// +public abstract class AbstractResource : IResource { /// - /// Convenience base class for - /// implementations, pre-implementing typical behavior. + /// The default special character that denotes the base (home, or root) + /// path. /// /// ///

- /// The method will - /// check whether a or - /// can be opened; - /// will always return - /// ; - /// and - /// throw an exception; - /// and will - /// return the value of the - /// property. + /// Will be resolved (by those + /// implementations that support it) to the home (or root) path for + /// the specific implementation. + ///

+ ///

+ /// For example, in the case of a web application this will (probably) + /// resolve to the virtual directory of said web application. ///

///
- /// Juergen Hoeller - /// Rick Evans (.NET) - /// Aleksandar Seovic (.NET) - /// - public abstract class AbstractResource : IResource + protected const string DefaultBasePathPlaceHolder = "~"; + + private string protocol; + private string resourceName; + private string basePathPlaceHolder = DefaultBasePathPlaceHolder; + + #region Constructor (s) / Destructor + + /// + /// Creates a new instance of the + /// class. + /// + /// + ///

+ /// This is an class, and as such exposes no + /// public constructors. + ///

+ ///
+ protected AbstractResource() { - /// - /// The default special character that denotes the base (home, or root) - /// path. - /// - /// - ///

- /// Will be resolved (by those - /// implementations that support it) to the home (or root) path for - /// the specific implementation. - ///

- ///

- /// For example, in the case of a web application this will (probably) - /// resolve to the virtual directory of said web application. - ///

- ///
- protected const string DefaultBasePathPlaceHolder = "~"; + } - private string protocol; - private string resourceName; - private string basePathPlaceHolder = DefaultBasePathPlaceHolder; + /// + /// Creates a new instance of the + /// class. + /// + /// + ///

+ /// This is an class, and as such exposes no + /// public constructors. + ///

+ ///
+ /// + /// A string representation of the resource. + /// + /// + /// If the supplied is + /// or contains only whitespace character(s). + /// + protected AbstractResource(string resourceName) + { + AssertUtils.ArgumentHasText(resourceName, "resourceName"); + this.protocol = ConfigurableResourceLoader.GetProtocol(resourceName); + this.resourceName = resourceName; + } - #region Constructor (s) / Destructor + #endregion - /// - /// Creates a new instance of the - /// class. - /// - /// - ///

- /// This is an class, and as such exposes no - /// public constructors. - ///

- ///
- protected AbstractResource() + #region Properties + + /// + /// The special character that denotes the base (home, or root) + /// path. + /// + /// + ///

+ /// Will be resolved (by those + /// implementations that support it) to the home (or root) path for + /// the specific implementation. + ///

+ ///

+ /// For example, in the case of a web application this will (probably) + /// resolve to the virtual directory of said web application. + ///

+ ///
+ /// + public string BasePathPlaceHolder + { + get { return basePathPlaceHolder; } + set { basePathPlaceHolder = value; } + } + + /// + /// Return an for this resource. + /// + /// + /// An . + /// + /// + /// If the stream could not be opened. + /// + /// + public abstract Stream InputStream { get; } + + /// + /// Returns a description for this resource. + /// + /// + /// A description for this resource. + /// + /// + public abstract string Description { get; } + + /// + /// Returns the protocol associated with this resource (if any). + /// + /// + ///

+ /// The value of this property may be if no + /// protocol is associated with the resource type (for example if the + /// resource is a memory stream). + ///

+ ///
+ /// + /// The protocol associated with this resource (if any). + /// + public string Protocol + { + get { return protocol; } + } + + /// + /// Does this resource represent a handle with an open stream? + /// + /// + ///

+ /// This, the default implementation, always returns + /// . + ///

+ ///
+ /// + /// if this resource represents a handle with an + /// open stream. + /// + /// + public virtual bool IsOpen + { + get { return false; } + } + + /// + /// Returns the handle for this resource. + /// + /// + public virtual Uri Uri + { + get { + return new Uri(resourceName); } + } - /// - /// Creates a new instance of the - /// class. - /// - /// - ///

- /// This is an class, and as such exposes no - /// public constructors. - ///

- ///
- /// - /// A string representation of the resource. - /// - /// - /// If the supplied is - /// or contains only whitespace character(s). - /// - protected AbstractResource(string resourceName) + /// + /// Returns a handle for this resource. + /// + /// + ///

+ /// This, the default implementation, always throws a + /// , assuming that the + /// resource cannot be resolved to an absolute file path. + ///

+ ///
+ /// + /// The handle for this resource. + /// + /// + /// This implementation always throws a + /// . + /// + /// + /// + public virtual FileInfo File + { + get { - AssertUtils.ArgumentHasText(resourceName, "resourceName"); - this.protocol = ConfigurableResourceLoader.GetProtocol(resourceName); - this.resourceName = resourceName; + throw new FileNotFoundException( + Description + " cannot be resolved to an absolute file path."); } + } - #endregion - - #region Properties - - /// - /// The special character that denotes the base (home, or root) - /// path. - /// - /// - ///

- /// Will be resolved (by those - /// implementations that support it) to the home (or root) path for - /// the specific implementation. - ///

- ///

- /// For example, in the case of a web application this will (probably) - /// resolve to the virtual directory of said web application. - ///

- ///
- /// - public string BasePathPlaceHolder + /// + /// Does this resource actually exist in physical form? + /// + /// + ///

+ /// This implementation checks whether a + /// can be opened, falling back to whether a + /// can be opened. + ///

+ ///

+ /// This will cover both directories and content resources. + ///

+ ///

+ /// This implementation will also return if + /// permission to the (file's) path is denied. + ///

+ ///
+ /// + /// if this resource actually exists in physical + /// form (for example on a filesystem). + /// + /// + /// + public virtual bool Exists + { + get { - get { return basePathPlaceHolder; } - set { basePathPlaceHolder = value; } - } - - /// - /// Return an for this resource. - /// - /// - /// An . - /// - /// - /// If the stream could not be opened. - /// - /// - public abstract Stream InputStream { get; } - - /// - /// Returns a description for this resource. - /// - /// - /// A description for this resource. - /// - /// - public abstract string Description { get; } - - /// - /// Returns the protocol associated with this resource (if any). - /// - /// - ///

- /// The value of this property may be if no - /// protocol is associated with the resource type (for example if the - /// resource is a memory stream). - ///

- ///
- /// - /// The protocol associated with this resource (if any). - /// - public string Protocol - { - get { return protocol; } - } - - /// - /// Does this resource represent a handle with an open stream? - /// - /// - ///

- /// This, the default implementation, always returns - /// . - ///

- ///
- /// - /// if this resource represents a handle with an - /// open stream. - /// - /// - public virtual bool IsOpen - { - get { return false; } - } - - /// - /// Returns the handle for this resource. - /// - /// - public virtual Uri Uri - { - get + try { - return new Uri(resourceName); + return File.Exists; } - } - - /// - /// Returns a handle for this resource. - /// - /// - ///

- /// This, the default implementation, always throws a - /// , assuming that the - /// resource cannot be resolved to an absolute file path. - ///

- ///
- /// - /// The handle for this resource. - /// - /// - /// This implementation always throws a - /// . - /// - /// - /// - public virtual FileInfo File - { - get - { - throw new FileNotFoundException( - Description + " cannot be resolved to an absolute file path."); - } - } - - /// - /// Does this resource actually exist in physical form? - /// - /// - ///

- /// This implementation checks whether a - /// can be opened, falling back to whether a - /// can be opened. - ///

- ///

- /// This will cover both directories and content resources. - ///

- ///

- /// This implementation will also return if - /// permission to the (file's) path is denied. - ///

- ///
- /// - /// if this resource actually exists in physical - /// form (for example on a filesystem). - /// - /// - /// - public virtual bool Exists - { - get + catch (IOException) { try { - return File.Exists; + Stream inputStream = InputStream; + inputStream.Close(); + return true; } - catch (IOException) + catch (Exception) { - try - { - Stream inputStream = InputStream; - inputStream.Close(); - return true; - } catch (Exception) - { - return false; - } + return false; } } } + } - #endregion + #endregion - #region Methods + #region Methods - /// - /// Strips any protocol name from the supplied - /// . - /// - /// - ///

- /// If the supplied does not - /// have any protocol associated with it, then the supplied - /// will be returned as-is. - ///

- ///
- /// - /// - /// GetResourceNameWithoutProtocol("http://www.mycompany.com/resource.txt"); - /// // returns www.mycompany.com/resource.txt - /// - /// - /// - /// The name of the resource. - /// - /// - /// The name of the resource without the protocol name. - /// - protected static string GetResourceNameWithoutProtocol(string resourceName) - { - int pos = resourceName.IndexOf( - ConfigurableResourceLoader.ProtocolSeparator); - if (pos == -1) - { - return resourceName; - } - else - { - return resourceName.Substring(pos + ConfigurableResourceLoader.ProtocolSeparator.Length); - } - } - - /// - /// Resolves the supplied to its value - /// sans any leading protocol. - /// - /// - /// The name of the resource. - /// - /// - /// The name of the resource without the protocol name. - /// - /// - protected virtual string ResolveResourceNameWithoutProtocol(string resourceName) - { - return ResolveBasePathPlaceHolder( - GetResourceNameWithoutProtocol(resourceName), BasePathPlaceHolder); - } - - /// - /// Resolves the presence of the - /// value - /// in the supplied into a path. - /// - /// - ///

- /// The default implementation simply returns the supplied - /// as is. - ///

- ///
- /// - /// The name of the resource. - /// - /// - /// The string that is a placeholder for a base path. - /// - /// - /// The name of the resource with any - /// value having been resolved into an actual path. - /// - protected virtual string ResolveBasePathPlaceHolder( - string resourceName, string basePathPlaceHolder) + /// + /// Strips any protocol name from the supplied + /// . + /// + /// + ///

+ /// If the supplied does not + /// have any protocol associated with it, then the supplied + /// will be returned as-is. + ///

+ ///
+ /// + /// + /// GetResourceNameWithoutProtocol("http://www.mycompany.com/resource.txt"); + /// // returns www.mycompany.com/resource.txt + /// + /// + /// + /// The name of the resource. + /// + /// + /// The name of the resource without the protocol name. + /// + protected static string GetResourceNameWithoutProtocol(string resourceName) + { + int pos = resourceName.IndexOf( + ConfigurableResourceLoader.ProtocolSeparator); + if (pos == -1) { return resourceName; } - - /// - /// This implementation returns the - /// of this resource. - /// - /// - public override string ToString() + else { - return Description; + return resourceName.Substring(pos + ConfigurableResourceLoader.ProtocolSeparator.Length); } + } - /// - /// Determines whether the specified is - /// equal to the current . - /// - /// - ///

- /// This implementation compares values. - ///

- ///
- /// - public override bool Equals(object obj) + /// + /// Resolves the supplied to its value + /// sans any leading protocol. + /// + /// + /// The name of the resource. + /// + /// + /// The name of the resource without the protocol name. + /// + /// + protected virtual string ResolveResourceNameWithoutProtocol(string resourceName) + { + return ResolveBasePathPlaceHolder( + GetResourceNameWithoutProtocol(resourceName), BasePathPlaceHolder); + } + + /// + /// Resolves the presence of the + /// value + /// in the supplied into a path. + /// + /// + ///

+ /// The default implementation simply returns the supplied + /// as is. + ///

+ ///
+ /// + /// The name of the resource. + /// + /// + /// The string that is a placeholder for a base path. + /// + /// + /// The name of the resource with any + /// value having been resolved into an actual path. + /// + protected virtual string ResolveBasePathPlaceHolder( + string resourceName, string basePathPlaceHolder) + { + return resourceName; + } + + /// + /// This implementation returns the + /// of this resource. + /// + /// + public override string ToString() + { + return Description; + } + + /// + /// Determines whether the specified is + /// equal to the current . + /// + /// + ///

+ /// This implementation compares values. + ///

+ ///
+ /// + public override bool Equals(object obj) + { + return obj is IResource + && ((IResource) obj).Description.Equals(Description); + } + + /// + /// Serves as a hash function for a particular type, suitable for use + /// in hashing algorithms and data structures like a hash table. + /// + /// + ///

+ /// This implementation returns the hashcode of the + /// property. + ///

+ ///
+ /// + public override int GetHashCode() + { + return Description.GetHashCode(); + } + + #endregion + + #region Relative Resource Support + + /// + /// Factory Method. Create a new instance of the current resource type using the given resourceName + /// + protected virtual IResource CreateResourceInstance(string resourceName) + { + return null; + } + + /// + /// The ResourceLoader to be used for resolving relative resources + /// + protected virtual IResourceLoader GetResourceLoader() + { + return new ConfigurableResourceLoader(); + } + + /// + /// Does this support relative + /// resource retrieval? + /// + /// + ///

+ /// This property is generally to be consulted prior to attempting + /// to attempting to access a resource that is relative to this + /// resource (via a call to + /// ). + ///

+ ///

+ /// This, the default implementation, always returns + /// . + ///

+ ///
+ /// + /// if this + /// supports relative resource + /// retrieval. + /// + protected virtual bool SupportsRelativeResources + { + get { return false; } + } + + /// + /// Gets the root location of the resource. + /// + /// + ///

+ /// Where root resource can be taken to mean that part of the resource + /// descriptor that doesn't change when a relative resource is looked + /// up. Examples of such a root location would include a drive letter, + /// a web server name, an assembly name, etc. + ///

+ ///
+ /// + /// The root location of the resource. + /// + /// + /// This, the default implementation, always throws a + /// . + /// + protected virtual string RootLocation + { + get { throw new NotSupportedException(); } + } + + /// + /// Gets the current path of the resource. + /// + /// + ///

+ /// An example value of this property would be the name of the + /// directory containing a filesystem based resource. + ///

+ ///
+ /// + /// The current path of the resource. + /// + /// + /// This, the default implementation, always throws a + /// . + /// + protected virtual string ResourcePath + { + get { throw new NotSupportedException(); } + } + + /// + /// Gets those characters that are valid path separators for the + /// resource type. + /// + /// + ///

+ /// An example value of this property would be the + /// and + /// values for a + /// filesystem based resource. + ///

+ ///

+ /// Any derived classes that override this method are expected to + /// return a new array for each access of this property. + ///

+ ///
+ /// + /// Those characters that are valid path separators for the resource + /// type. + /// + /// + /// This, the default implementation, always throws a + /// . + /// + protected virtual char[] PathSeparatorChars + { + get { throw new NotSupportedException(); } + } + + /// + /// Does the supplied relative ? + /// + /// + /// The name of the resource to test. + /// + /// + /// if resource name is relative; + /// otherwise . + /// + protected virtual bool IsRelativeResource(string resourceName) + { + return false; + } + + /// + /// Creates a new resource that is relative to this resource based on the + /// supplied . + /// + /// + ///

+ /// This method can accept either a fully qualified resource name or a + /// relative resource name as it's parameter. + ///

+ ///

+ /// A fully qualified resource is one that has a protocol prefix and + /// all elements of the resource name. All other resources are treated + /// as relative to this resource, and the following rules are used to + /// locate a relative resource: + ///

+ /// + /// + /// If the starts with '..', + /// the current resource path is navigated backwards before the + /// is concatenated to the current + /// of + /// this resource. + /// + /// + /// If the starts with '/', the + /// current resource path is ignored and a new resource name is + /// appended to the + /// of + /// this resource. + /// + /// + /// If the starts with '.' or a + /// letter, a new path is appended to the current + /// of + /// this resource. + /// + /// + ///
+ /// + /// The name of the resource to create. + /// + /// The relative resource. + /// + /// If the process of resolving the relative resource yielded an + /// invalid URI. + /// + /// + /// If this resource does not support the resolution of relative + /// resources (as determined by the value of the + /// + /// property). + /// + /// + public virtual IResource CreateRelative(string resourceName) + { + AssertUtils.ArgumentNotNull(resourceName, "relativePath"); + + // try to create fully qualified resource... + IResourceLoader loader = GetResourceLoader(); + + if (ConfigurableResourceLoader.HasProtocol(resourceName)) { - return obj is IResource - && ((IResource)obj).Description.Equals(Description); - } - - /// - /// Serves as a hash function for a particular type, suitable for use - /// in hashing algorithms and data structures like a hash table. - /// - /// - ///

- /// This implementation returns the hashcode of the - /// property. - ///

- ///
- /// - public override int GetHashCode() - { - return Description.GetHashCode(); - } - - #endregion - - #region Relative Resource Support - - /// - /// Factory Method. Create a new instance of the current resource type using the given resourceName - /// - protected virtual IResource CreateResourceInstance( string resourceName ) - { - return null; - } - - /// - /// The ResourceLoader to be used for resolving relative resources - /// - protected virtual IResourceLoader GetResourceLoader() - { - return new ConfigurableResourceLoader(); - } - - /// - /// Does this support relative - /// resource retrieval? - /// - /// - ///

- /// This property is generally to be consulted prior to attempting - /// to attempting to access a resource that is relative to this - /// resource (via a call to - /// ). - ///

- ///

- /// This, the default implementation, always returns - /// . - ///

- ///
- /// - /// if this - /// supports relative resource - /// retrieval. - /// - protected virtual bool SupportsRelativeResources - { - get { return false; } - } - - /// - /// Gets the root location of the resource. - /// - /// - ///

- /// Where root resource can be taken to mean that part of the resource - /// descriptor that doesn't change when a relative resource is looked - /// up. Examples of such a root location would include a drive letter, - /// a web server name, an assembly name, etc. - ///

- ///
- /// - /// The root location of the resource. - /// - /// - /// This, the default implementation, always throws a - /// . - /// - protected virtual string RootLocation - { - get { throw new NotSupportedException(); } - } - - /// - /// Gets the current path of the resource. - /// - /// - ///

- /// An example value of this property would be the name of the - /// directory containing a filesystem based resource. - ///

- ///
- /// - /// The current path of the resource. - /// - /// - /// This, the default implementation, always throws a - /// . - /// - protected virtual string ResourcePath - { - get { throw new NotSupportedException(); } - } - - /// - /// Gets those characters that are valid path separators for the - /// resource type. - /// - /// - ///

- /// An example value of this property would be the - /// and - /// values for a - /// filesystem based resource. - ///

- ///

- /// Any derived classes that override this method are expected to - /// return a new array for each access of this property. - ///

- ///
- /// - /// Those characters that are valid path separators for the resource - /// type. - /// - /// - /// This, the default implementation, always throws a - /// . - /// - protected virtual char[] PathSeparatorChars - { - get { throw new NotSupportedException(); } - } - - /// - /// Does the supplied relative ? - /// - /// - /// The name of the resource to test. - /// - /// - /// if resource name is relative; - /// otherwise . - /// - protected virtual bool IsRelativeResource(string resourceName) - { - return false; - } - - /// - /// Creates a new resource that is relative to this resource based on the - /// supplied . - /// - /// - ///

- /// This method can accept either a fully qualified resource name or a - /// relative resource name as it's parameter. - ///

- ///

- /// A fully qualified resource is one that has a protocol prefix and - /// all elements of the resource name. All other resources are treated - /// as relative to this resource, and the following rules are used to - /// locate a relative resource: - ///

- /// - /// - /// If the starts with '..', - /// the current resource path is navigated backwards before the - /// is concatenated to the current - /// of - /// this resource. - /// - /// - /// If the starts with '/', the - /// current resource path is ignored and a new resource name is - /// appended to the - /// of - /// this resource. - /// - /// - /// If the starts with '.' or a - /// letter, a new path is appended to the current - /// of - /// this resource. - /// - /// - ///
- /// - /// The name of the resource to create. - /// - /// The relative resource. - /// - /// If the process of resolving the relative resource yielded an - /// invalid URI. - /// - /// - /// If this resource does not support the resolution of relative - /// resources (as determined by the value of the - /// - /// property). - /// - /// - public virtual IResource CreateRelative(string resourceName) - { - AssertUtils.ArgumentNotNull(resourceName, "relativePath"); - - // try to create fully qualified resource... - IResourceLoader loader = GetResourceLoader(); - - if (ConfigurableResourceLoader.HasProtocol(resourceName)) + IResource resource = loader.GetResource(resourceName); + if (resource != null) { - IResource resource = loader.GetResource(resourceName); - if (resource != null) - { - return resource; - } + return resource; } - if (!SupportsRelativeResources) + } + + if (!SupportsRelativeResources) + { + throw new NotSupportedException(GetType().Name + + " does not support relative resources. Please use fully qualified resource name."); + } + + StringBuilder fullResourceName = new StringBuilder(256); + if (Protocol != null && Protocol != String.Empty) + { + fullResourceName.Append(Protocol).Append(ConfigurableResourceLoader.ProtocolSeparator); + } + + if (!IsRelativeResource(resourceName)) + { + fullResourceName.Append(resourceName); + } + else + { + string targetResource; + string resourcePath; + int n = resourceName.LastIndexOfAny(new char[] { '/', '\\' }); + if (n >= 0) { - throw new NotSupportedException(GetType().Name + - " does not support relative resources. Please use fully qualified resource name."); + targetResource = resourceName.Substring(n + 1); + resourcePath = CalculateResourcePath(resourceName.Substring(0, n + 1)); + } + else // only resource name is specified, so current path should be used + { + targetResource = resourceName; + resourcePath = ResourcePath; } - StringBuilder fullResourceName = new StringBuilder(256); - if (Protocol != null && Protocol != String.Empty) + fullResourceName.Append(RootLocation.TrimEnd('\\', '/')); + if (resourcePath != null && resourcePath != String.Empty) { - fullResourceName.Append(Protocol).Append(ConfigurableResourceLoader.ProtocolSeparator); + fullResourceName.Append('/').Append(resourcePath); } - - if (!IsRelativeResource(resourceName)) + + fullResourceName.Append('/').Append(targetResource); + } + + string resultResourceName = fullResourceName.ToString(); + + if (!ConfigurableResourceLoader.HasProtocol(resultResourceName)) + { + // give derived resource classes a chance to create an instance on their own + IResource resultResource = CreateResourceInstance(resultResourceName); + if (resultResource != null) return resultResource; + } + + // create resource instance using default loader + return loader.GetResource(resultResourceName); + } + + /// + /// Calculates a new resource path based on the supplied + /// . + /// + /// + /// The relative path to evaluate. + /// + /// The newly calculated resource path. + private string CalculateResourcePath(string relativePath) + { + StringBuilder path = new StringBuilder(256); + if (relativePath.StartsWith("..")) // back level navigation + { + string[] pathElements = ResourcePath.Split(PathSeparatorChars); + int upWalks = UpWalks(relativePath); + if (upWalks > pathElements.Length) { - fullResourceName.Append(resourceName); + throw new UriFormatException("Too many back levels."); + } + + char separator = PathSeparatorChars[0]; + for (int i = 0; i < pathElements.Length - upWalks; i++) + { + path.Append(pathElements[i]).Append(separator); + } + + string[] relativeParts = relativePath.Split('/', '\\'); + for (int i = upWalks; i < relativeParts.Length - 1; i++) + { + path.Append(relativeParts[i]).Append(separator); + } + + if (path.Length > 0) + { + path.Length -= 1; + } + + return path.ToString(); + } + else if (relativePath.StartsWith("/")) // relative to root + { + if (relativePath.Length > 1) + { + return relativePath.Substring(1, relativePath.Length - 2); } else { - string targetResource; - string resourcePath; - int n = resourceName.LastIndexOfAny(new char[] { '/', '\\' }); - if (n >= 0) - { - targetResource = resourceName.Substring(n + 1); - resourcePath = CalculateResourcePath(resourceName.Substring(0, n + 1)); - } - else // only resource name is specified, so current path should be used - { - targetResource = resourceName; - resourcePath = ResourcePath; - } - - fullResourceName.Append(RootLocation.TrimEnd('\\','/')); - if (resourcePath != null && resourcePath != String.Empty) - { - fullResourceName.Append('/').Append(resourcePath); - } - fullResourceName.Append('/').Append(targetResource); + return null; } - - string resultResourceName = fullResourceName.ToString(); - - if (!ConfigurableResourceLoader.HasProtocol( resultResourceName )) - { - // give derived resource classes a chance to create an instance on their own - IResource resultResource = CreateResourceInstance( resultResourceName ); - if (resultResource != null) return resultResource; - } - - // create resource instance using default loader - return loader.GetResource(resultResourceName); } - - /// - /// Calculates a new resource path based on the supplied - /// . - /// - /// - /// The relative path to evaluate. - /// - /// The newly calculated resource path. - private string CalculateResourcePath(string relativePath ) + else // relative to current namespace... { - StringBuilder path = new StringBuilder(256); - if (relativePath.StartsWith("..")) // back level navigation + if (ResourcePath != null && ResourcePath != String.Empty) { - string[] pathElements = ResourcePath.Split(PathSeparatorChars); - int upWalks = UpWalks(relativePath); - if (upWalks > pathElements.Length) - { - throw new UriFormatException("Too many back levels."); - } - char separator = PathSeparatorChars[0]; - for (int i = 0; i < pathElements.Length - upWalks; i++) - { - path.Append(pathElements[i]).Append(separator); - } - string[] relativeParts = relativePath.Split('/', '\\'); - for (int i = upWalks; i < relativeParts.Length - 1; i++) - { - path.Append(relativeParts[i]).Append(separator); - } - if (path.Length > 0) - { - path.Length -= 1; - } - return path.ToString(); + path.Append(ResourcePath.TrimEnd(PathSeparatorChars)).Append(PathSeparatorChars[0]); } - else if (relativePath.StartsWith("/")) // relative to root - { - if (relativePath.Length > 1) - { - return relativePath.Substring(1, relativePath.Length - 2); - } - else - { - return null; - } - } - else // relative to current namespace... - { - if (ResourcePath != null && ResourcePath != String.Empty) - { - path.Append(ResourcePath.TrimEnd(PathSeparatorChars)).Append(PathSeparatorChars[0]); - } - if (relativePath.StartsWith("./")) - { - if (relativePath.Length > 2) - { - path.Append(relativePath.Substring(2, relativePath.Length - 3)); - } - } - else - { - path.Append(relativePath.Substring(0, relativePath.Length - 1)); - } - return path.ToString(); + if (relativePath.StartsWith("./")) + { + if (relativePath.Length > 2) + { + path.Append(relativePath.Substring(2, relativePath.Length - 3)); + } } + else + { + path.Append(relativePath.Substring(0, relativePath.Length - 1)); + } + + return path.ToString(); } - - private int UpWalks(string path) - { - string[] parts = path.Split('/', '\\'); - int count = 0; - for (; count < parts.Length && parts[count].Equals(".."); count++) - { - ; - } - return count; - } - - #endregion } + + private int UpWalks(string path) + { + string[] parts = path.Split('/', '\\'); + int count = 0; + for (; count < parts.Length && parts[count].Equals(".."); count++) + { + ; + } + + return count; + } + + #endregion } diff --git a/src/Spring/Spring.Core/Core/IO/AssemblyResource.cs b/src/Spring/Spring.Core/Core/IO/AssemblyResource.cs index f6115363..ac11dc36 100644 --- a/src/Spring/Spring.Core/Core/IO/AssemblyResource.cs +++ b/src/Spring/Spring.Core/Core/IO/AssemblyResource.cs @@ -26,251 +26,254 @@ using Microsoft.Extensions.Logging; #endregion -namespace Spring.Core.IO +namespace Spring.Core.IO; + +/// +/// An implementation for +/// resources stored within assemblies. +/// +/// +///

+/// This implementation expects any resource name passed to the +/// constructor to adhere to the following format: +///

+///

+/// assembly://assemblyName/namespace/resourceName +///

+///
+/// Aleksandar Seovic (.NET) +/// Federico Spinazzi (.NET) +public class AssemblyResource : AbstractResource { + #region Fields + + private Assembly _assembly; + private string[] _resources; + private string _resourceName; + private string _fullResourceName; + private string _resourceNamespace; + private string _resourceAssemblyName; + private static readonly ILogger log = LogManager.GetLogger(); + + #endregion + + #region Constructors + /// - /// An implementation for - /// resources stored within assemblies. + /// Creates a new instance of the + /// class. + /// + /// + /// The name of the assembly resource. + /// + /// + /// If the supplied did not conform + /// to the expected format. + /// + /// + /// If the assembly specified in the supplied + /// was loaded twice with two + /// different evidences. + /// + /// + /// If the assembly specified in the supplied + /// could not be found. + /// + /// + /// If the caller does not have the required permission to load + /// the assembly specified in the supplied + /// . + /// + /// + public AssemblyResource(string resourceName) + : base(resourceName) + { + string[] info = GetResourceNameWithoutProtocol(resourceName).Split('/'); + if (info.Length != 3) + { + throw new UriFormatException(string.Format("Invalid resource name. Name has to be in 'assembly://' format:{0}", resourceName)); + } + + this._assembly = Assembly.Load(info[0]); + if (this._assembly == null) + { + throw new FileNotFoundException("Unable to load assembly [" + info[0] + "]"); + } + + this._fullResourceName = resourceName; + this._resourceAssemblyName = info[0]; + this._resourceNamespace = info[1]; + this._resourceName = String.Format("{0}.{1}", info[1], info[2]); + } + + #endregion + + #region Properties + + /// + /// Return an for this resource. + /// + /// + /// An . + /// + /// + /// If the stream could not be opened. + /// + /// + /// If the caller does not have the required permission to load + /// the underlying assembly's manifest. + /// + /// + /// + public override Stream InputStream + { + get + { + Stream stream = _assembly.GetManifestResourceStream(_resourceName); + if (stream == null) + { + log.LogError("Could not load resource with name = [" + _resourceName + + "] from assembly + " + _assembly); + log.LogError("URI specified = [" + this._fullResourceName + "] Spring.NET URI syntax is 'assembly://assemblyName/namespace/resourceName'."); + log.LogError("Resource name often has the default namespace prefixed, e.g. 'assembly://MyAssembly/MyNamespace/MyNamespace.MyResource.txt'."); + } + + return stream; + } + } + + /// + /// Does the embedded resource specified in the value passed to the + /// constructor exist? + /// + /// + /// if this resource actually exists in physical + /// form (for example on a filesystem). + /// + /// + /// + /// + public override bool Exists + { + get + { + if (_resources == null) + { + _resources = _assembly.GetManifestResourceNames(); + Array.Sort(_resources); + } + + return (Array.BinarySearch(_resources, _resourceName) >= 0); + } + } + + /// + /// Does this support relative + /// resource retrieval? /// /// ///

- /// This implementation expects any resource name passed to the - /// constructor to adhere to the following format: - ///

- ///

- /// assembly://assemblyName/namespace/resourceName + /// This implementation does support relative resource retrieval, and + /// so will always return . ///

///
- /// Aleksandar Seovic (.NET) - /// Federico Spinazzi (.NET) - public class AssemblyResource : AbstractResource + /// + /// if this + /// supports relative resource + /// retrieval. + /// + /// + protected override bool SupportsRelativeResources { - #region Fields + get { return true; } + } - private Assembly _assembly; - private string[] _resources; - private string _resourceName; - private string _fullResourceName; - private string _resourceNamespace; - private string _resourceAssemblyName; - private static readonly ILogger log = LogManager.GetLogger(); + /// + /// Gets the root location of the resource (the assembly name in this + /// case). + /// + /// + /// The root location of the resource. + /// + /// + protected override string RootLocation + { + get { return _resourceAssemblyName; } + } - #endregion + /// + /// Gets the current path of the resource (the namespace in which the + /// target resource was embedded in this case). + /// + /// + /// The current path of the resource. + /// + /// + protected override string ResourcePath + { + get { return _resourceNamespace; } + } - #region Constructors + /// + /// Gets those characters that are valid path separators for the + /// resource type. + /// + /// + /// Those characters that are valid path separators for the resource + /// type. + /// + /// + protected override char[] PathSeparatorChars + { + get { return new char[] { '.' }; } + } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The name of the assembly resource. - /// - /// - /// If the supplied did not conform - /// to the expected format. - /// - /// - /// If the assembly specified in the supplied - /// was loaded twice with two - /// different evidences. - /// - /// - /// If the assembly specified in the supplied - /// could not be found. - /// - /// - /// If the caller does not have the required permission to load - /// the assembly specified in the supplied - /// . - /// - /// - public AssemblyResource(string resourceName) - : base(resourceName) + /// + /// Returns a description for this resource. + /// + /// + /// A description for this resource. + /// + /// + public override string Description + { + get { - string[] info = GetResourceNameWithoutProtocol(resourceName).Split('/'); - if (info.Length != 3) - { - throw new UriFormatException(string.Format("Invalid resource name. Name has to be in 'assembly://' format:{0}", resourceName)); - } - this._assembly = Assembly.Load(info[0]); - if (this._assembly == null) - { - throw new FileNotFoundException("Unable to load assembly [" + info[0] + "]"); - } - this._fullResourceName = resourceName; - this._resourceAssemblyName = info[0]; - this._resourceNamespace = info[1]; - this._resourceName = String.Format("{0}.{1}", info[1], info[2]); + return string.Format( + CultureInfo.InvariantCulture, + "assembly [{0}], resource [{1}]", _assembly.FullName, _resourceName); } + } - #endregion - - #region Properties - - /// - /// Return an for this resource. - /// - /// - /// An . - /// - /// - /// If the stream could not be opened. - /// - /// - /// If the caller does not have the required permission to load - /// the underlying assembly's manifest. - /// - /// - /// - public override Stream InputStream + /// + /// Returns the handle for this resource. + /// + /// + public override Uri Uri + { + get { - get - { - Stream stream = _assembly.GetManifestResourceStream(_resourceName); - if (stream == null) - { - log.LogError("Could not load resource with name = [" + _resourceName + - "] from assembly + " + _assembly); - log.LogError("URI specified = [" + this._fullResourceName + "] Spring.NET URI syntax is 'assembly://assemblyName/namespace/resourceName'."); - log.LogError("Resource name often has the default namespace prefixed, e.g. 'assembly://MyAssembly/MyNamespace/MyNamespace.MyResource.txt'."); - } - return stream; - } + return new Uri(_fullResourceName); } + } - /// - /// Does the embedded resource specified in the value passed to the - /// constructor exist? - /// - /// - /// if this resource actually exists in physical - /// form (for example on a filesystem). - /// - /// - /// - /// - public override bool Exists - { - get - { - if (_resources == null) - { - _resources = _assembly.GetManifestResourceNames(); - Array.Sort(_resources); - } - return (Array.BinarySearch(_resources, _resourceName) >= 0); - } - } + #endregion - /// - /// Does this support relative - /// resource retrieval? - /// - /// - ///

- /// This implementation does support relative resource retrieval, and - /// so will always return . - ///

- ///
- /// - /// if this - /// supports relative resource - /// retrieval. - /// - /// - protected override bool SupportsRelativeResources - { - get { return true; } - } - - /// - /// Gets the root location of the resource (the assembly name in this - /// case). - /// - /// - /// The root location of the resource. - /// - /// - protected override string RootLocation - { - get { return _resourceAssemblyName; } - } - - /// - /// Gets the current path of the resource (the namespace in which the - /// target resource was embedded in this case). - /// - /// - /// The current path of the resource. - /// - /// - protected override string ResourcePath - { - get { return _resourceNamespace; } - } - - /// - /// Gets those characters that are valid path separators for the - /// resource type. - /// - /// - /// Those characters that are valid path separators for the resource - /// type. - /// - /// - protected override char[] PathSeparatorChars - { - get { return new char[] { '.' }; } - } - - /// - /// Returns a description for this resource. - /// - /// - /// A description for this resource. - /// - /// - public override string Description - { - get - { - return string.Format( - CultureInfo.InvariantCulture, - "assembly [{0}], resource [{1}]", _assembly.FullName, _resourceName); - } - } - - /// - /// Returns the handle for this resource. - /// - /// - public override Uri Uri - { - get - { - return new Uri(_fullResourceName); - } - } - - #endregion - - /// - /// Does the supplied relative ? - /// - /// - /// The name of the resource to test. - /// - /// - /// if resource name is relative; - /// otherwise . - /// - protected override bool IsRelativeResource(string resourceName) - { - return (resourceName.StartsWith("./") || + /// + /// Does the supplied relative ? + /// + /// + /// The name of the resource to test. + /// + /// + /// if resource name is relative; + /// otherwise . + /// + protected override bool IsRelativeResource(string resourceName) + { + return (resourceName.StartsWith("./") || resourceName.StartsWith("/") || resourceName.StartsWith("../") || resourceName.Split('/').Length != 3); - } } } diff --git a/src/Spring/Spring.Core/Core/IO/ConfigSectionResource.cs b/src/Spring/Spring.Core/Core/IO/ConfigSectionResource.cs index a701dce1..16b21a5c 100644 --- a/src/Spring/Spring.Core/Core/IO/ConfigSectionResource.cs +++ b/src/Spring/Spring.Core/Core/IO/ConfigSectionResource.cs @@ -22,187 +22,186 @@ using System.Text; using System.Xml; - using Spring.Util; #endregion -namespace Spring.Core.IO +namespace Spring.Core.IO; + +/// +/// Used when retrieving information from the standard .NET configuration +/// files (App.config / Web.config). +/// +/// +///

+/// If created with the name of a configuration section, then all methods +/// aside from the description return , +/// , or throw an exception. If created with an +/// , then the +/// property +/// will return a corresponding to parse. +///

+///
+/// Mark Pollack +/// Rick Evans +public class ConfigSectionResource : AbstractResource { + private XmlElement configElement; + private string sectionName; + + #region Constructor (s) / Destructor + /// - /// Used when retrieving information from the standard .NET configuration - /// files (App.config / Web.config). + /// Creates new instance of the + /// class. + /// + /// + /// The actual XML configuration section. + /// + /// + /// If the supplied is . + /// + public ConfigSectionResource(XmlElement configSection) + { + AssertUtils.ArgumentNotNull(configSection, "configSection"); + sectionName = configSection.Name; + configElement = configSection; + } + + /// + /// Creates new instance of the + /// class. + /// + /// + /// The name of the configuration section. + /// + /// + /// If the supplied is + /// or contains only whitespace character(s). + /// + public ConfigSectionResource(string resourceName) : base(resourceName) + { + AssertUtils.ArgumentHasText(resourceName, "resourceName"); + sectionName = GetResourceNameWithoutProtocol(resourceName); + configElement = (XmlElement) ConfigurationUtils.GetSection(sectionName); + } + + #endregion + + #region IResource Members + + /// + /// Returns the handle for this resource. /// /// ///

- /// If created with the name of a configuration section, then all methods - /// aside from the description return , - /// , or throw an exception. If created with an - /// , then the - /// property - /// will return a corresponding to parse. + /// This implementation always returns . ///

///
- /// Mark Pollack - /// Rick Evans - public class ConfigSectionResource : AbstractResource + /// + /// . + /// + /// + public override Uri Uri { - private XmlElement configElement; - private string sectionName; - - #region Constructor (s) / Destructor - - /// - /// Creates new instance of the - /// class. - /// - /// - /// The actual XML configuration section. - /// - /// - /// If the supplied is . - /// - public ConfigSectionResource(XmlElement configSection) - { - AssertUtils.ArgumentNotNull(configSection, "configSection"); - sectionName = configSection.Name; - configElement = configSection; - } - - /// - /// Creates new instance of the - /// class. - /// - /// - /// The name of the configuration section. - /// - /// - /// If the supplied is - /// or contains only whitespace character(s). - /// - public ConfigSectionResource(string resourceName) : base(resourceName) - { - AssertUtils.ArgumentHasText(resourceName, "resourceName"); - sectionName = GetResourceNameWithoutProtocol(resourceName); - configElement = (XmlElement) ConfigurationUtils.GetSection(sectionName); - } - - #endregion - - #region IResource Members - - /// - /// Returns the handle for this resource. - /// - /// - ///

- /// This implementation always returns . - ///

- ///
- /// - /// . - /// - /// - public override Uri Uri - { - get { return null; } - } - - /// - /// Returns a handle for this resource. - /// - /// - ///

- /// This implementation always returns . - ///

- ///
- /// - /// . - /// - /// - public override FileInfo File - { - get { return null; } - } - - /// - /// Returns a description for this resource (the name of the - /// configuration section in this case). - /// - /// - /// A description for this resource. - /// - /// - public override string Description - { - get - { - return string.Format("config [{0}#{1}]", ConfigurationUtils.GetFileName(configElement), sectionName); - } - } - - /// - /// Does this resource actually exist in physical form? - /// - /// - ///

- /// This implementation always returns . - ///

- ///
- /// - /// - /// - /// - /// - public override bool Exists - { - get { return false; } - } - - #endregion - - #region IInputStreamSource Members - - /// - /// Return an for this resource. - /// - /// - /// An . - /// - /// - /// If the stream could not be opened. - /// - /// - public override Stream InputStream - { - get - { - if (configElement == null) - { - throw new FileNotFoundException(string.Format("Configuration Section '{0}' does not exist", this.sectionName), this.sectionName); - } - return new MemoryStream(Encoding.UTF8.GetBytes(configElement.OuterXml)); - } - } - - #endregion - - #region Properties - - /// - /// Exposes the actual for the - /// configuration section. - /// - /// - ///

- /// Introduced to accomodate line info tracking during parsing. - ///

- ///
- internal XmlElement ConfigElement - { - get { return configElement; } - } - - #endregion + get { return null; } } + + /// + /// Returns a handle for this resource. + /// + /// + ///

+ /// This implementation always returns . + ///

+ ///
+ /// + /// . + /// + /// + public override FileInfo File + { + get { return null; } + } + + /// + /// Returns a description for this resource (the name of the + /// configuration section in this case). + /// + /// + /// A description for this resource. + /// + /// + public override string Description + { + get + { + return string.Format("config [{0}#{1}]", ConfigurationUtils.GetFileName(configElement), sectionName); + } + } + + /// + /// Does this resource actually exist in physical form? + /// + /// + ///

+ /// This implementation always returns . + ///

+ ///
+ /// + /// + /// + /// + /// + public override bool Exists + { + get { return false; } + } + + #endregion + + #region IInputStreamSource Members + + /// + /// Return an for this resource. + /// + /// + /// An . + /// + /// + /// If the stream could not be opened. + /// + /// + public override Stream InputStream + { + get + { + if (configElement == null) + { + throw new FileNotFoundException(string.Format("Configuration Section '{0}' does not exist", this.sectionName), this.sectionName); + } + + return new MemoryStream(Encoding.UTF8.GetBytes(configElement.OuterXml)); + } + } + + #endregion + + #region Properties + + /// + /// Exposes the actual for the + /// configuration section. + /// + /// + ///

+ /// Introduced to accomodate line info tracking during parsing. + ///

+ ///
+ internal XmlElement ConfigElement + { + get { return configElement; } + } + + #endregion } diff --git a/src/Spring/Spring.Core/Core/IO/ConfigurableResourceLoader.cs b/src/Spring/Spring.Core/Core/IO/ConfigurableResourceLoader.cs index e6025d93..d2aaa37d 100644 --- a/src/Spring/Spring.Core/Core/IO/ConfigurableResourceLoader.cs +++ b/src/Spring/Spring.Core/Core/IO/ConfigurableResourceLoader.cs @@ -25,171 +25,172 @@ using Spring.Reflection.Dynamic; #endregion -namespace Spring.Core.IO +namespace Spring.Core.IO; + +/// +/// Configurable implementation of the +/// interface. +/// +/// +///

+/// This implementation +/// supports the configuration of resource access protocols and the +/// corresponding .NET types that know how to handle those protocols. +///

+///

+/// Basic protocol-to-resource type mappings are also defined by this class, +/// while others can be added either internally, by application contexts +/// extending this class, or externally, by the end user configuring the +/// context. +///

+///

+/// Only one resource type can be defined for each protocol, but multiple +/// protocols can map to the same resource type (for example, the +/// "http" and "ftp" protocols both map to the +/// type. The protocols that are +/// mapped by default can be found in the following list. +///

+///

+/// +/// +/// assembly +/// +/// +/// config +/// +/// +/// file +/// +/// +/// http +/// +/// +/// https +/// +/// +///

+///
+/// Aleksandar Seovic +/// +/// +/// +public class ConfigurableResourceLoader : IResourceLoader { /// - /// Configurable implementation of the - /// interface. + /// The separator between the protocol name and the resource name. + /// + public const string ProtocolSeparator = "://"; + + /// + /// Creates a new instance of the + /// class. + /// + public ConfigurableResourceLoader() + { + } + + /// + /// Creates a new instance of the + /// class using the specified default protocol for unqualified resources. + /// + public ConfigurableResourceLoader(string defaultProtocol) + { + AssertUtils.ArgumentNotNull(defaultProtocol, "defaultProtocol"); + this.defaultProtocol = defaultProtocol; + } + + /// + /// The default protocol to use for unqualified resources. /// /// ///

- /// This implementation - /// supports the configuration of resource access protocols and the - /// corresponding .NET types that know how to handle those protocols. - ///

- ///

- /// Basic protocol-to-resource type mappings are also defined by this class, - /// while others can be added either internally, by application contexts - /// extending this class, or externally, by the end user configuring the - /// context. - ///

- ///

- /// Only one resource type can be defined for each protocol, but multiple - /// protocols can map to the same resource type (for example, the - /// "http" and "ftp" protocols both map to the - /// type. The protocols that are - /// mapped by default can be found in the following list. - ///

- ///

- /// - /// - /// assembly - /// - /// - /// config - /// - /// - /// file - /// - /// - /// http - /// - /// - /// https - /// - /// + /// The initial value is "file". ///

///
- /// Aleksandar Seovic - /// - /// - /// - public class ConfigurableResourceLoader : IResourceLoader + public string DefaultResourceProtocol { - /// - /// The separator between the protocol name and the resource name. - /// - public const string ProtocolSeparator = "://"; - - /// - /// Creates a new instance of the - /// class. - /// - public ConfigurableResourceLoader() - { } - - /// - /// Creates a new instance of the - /// class using the specified default protocol for unqualified resources. - /// - public ConfigurableResourceLoader(string defaultProtocol) - { - AssertUtils.ArgumentNotNull(defaultProtocol, "defaultProtocol"); - this.defaultProtocol = defaultProtocol; - } - - /// - /// The default protocol to use for unqualified resources. - /// - /// - ///

- /// The initial value is "file". - ///

- ///
- public string DefaultResourceProtocol - { - get { return defaultProtocol; } - set { defaultProtocol = value; } - } - - /// - /// Returns a that has been - /// mapped to the protocol of the supplied . - /// - /// The name of the resource. - /// - /// A new instance for the - /// supplied . - /// - /// - /// If a - /// mapping does not exist for the supplied . - /// - /// - /// In the case of any errors arising from the instantiation of the - /// returned instance. - /// - /// - public IResource GetResource(string resourceName) - { - string protocol = GetProtocol(resourceName); - if (protocol == null) - { - protocol = DefaultResourceProtocol; - resourceName = protocol + ProtocolSeparator + resourceName; - } - - IDynamicConstructor handler = ResourceHandlerRegistry.GetResourceHandler(protocol); - if (handler == null) - { - throw new UriFormatException("Resource handler for the '" + protocol + "' protocol is not defined."); - } - - return (IResource) handler.Invoke(new object[] { resourceName }); - } - - /// - /// Checks that the supplied starts - /// with one of the protocol names currently mapped by this - /// instance. - /// - /// The name of the resource. - /// - /// if the supplied - /// starts with one of the known - /// protocols; if not, or if the supplied - /// is itself . - /// - public static bool HasProtocol(string resourceName) - { - string protocol = GetProtocol(resourceName); - return protocol != null && ResourceHandlerRegistry.IsHandlerRegistered(protocol); - } - - /// - /// Extracts the protocol name from the supplied - /// . - /// - /// The name of the resource. - /// - /// The extracted protocol name or if the - /// supplied is unqualified (or - /// is itself ). - /// - internal static string GetProtocol(string resourceName) - { - if (resourceName == null) - { - return null; - } - int pos = resourceName.IndexOf(ProtocolSeparator); - return pos == -1 ? null : resourceName.Substring(0, pos); - } - - #region Fields - - private string defaultProtocol = "file"; - - #endregion + get { return defaultProtocol; } + set { defaultProtocol = value; } } + + /// + /// Returns a that has been + /// mapped to the protocol of the supplied . + /// + /// The name of the resource. + /// + /// A new instance for the + /// supplied . + /// + /// + /// If a + /// mapping does not exist for the supplied . + /// + /// + /// In the case of any errors arising from the instantiation of the + /// returned instance. + /// + /// + public IResource GetResource(string resourceName) + { + string protocol = GetProtocol(resourceName); + if (protocol == null) + { + protocol = DefaultResourceProtocol; + resourceName = protocol + ProtocolSeparator + resourceName; + } + + IDynamicConstructor handler = ResourceHandlerRegistry.GetResourceHandler(protocol); + if (handler == null) + { + throw new UriFormatException("Resource handler for the '" + protocol + "' protocol is not defined."); + } + + return (IResource) handler.Invoke(new object[] { resourceName }); + } + + /// + /// Checks that the supplied starts + /// with one of the protocol names currently mapped by this + /// instance. + /// + /// The name of the resource. + /// + /// if the supplied + /// starts with one of the known + /// protocols; if not, or if the supplied + /// is itself . + /// + public static bool HasProtocol(string resourceName) + { + string protocol = GetProtocol(resourceName); + return protocol != null && ResourceHandlerRegistry.IsHandlerRegistered(protocol); + } + + /// + /// Extracts the protocol name from the supplied + /// . + /// + /// The name of the resource. + /// + /// The extracted protocol name or if the + /// supplied is unqualified (or + /// is itself ). + /// + internal static string GetProtocol(string resourceName) + { + if (resourceName == null) + { + return null; + } + + int pos = resourceName.IndexOf(ProtocolSeparator); + return pos == -1 ? null : resourceName.Substring(0, pos); + } + + #region Fields + + private string defaultProtocol = "file"; + + #endregion } diff --git a/src/Spring/Spring.Core/Core/IO/EncodedResource.cs b/src/Spring/Spring.Core/Core/IO/EncodedResource.cs index a6d4a07b..0b827dbe 100644 --- a/src/Spring/Spring.Core/Core/IO/EncodedResource.cs +++ b/src/Spring/Spring.Core/Core/IO/EncodedResource.cs @@ -21,124 +21,124 @@ using System.Text; using Spring.Util; -namespace Spring.Core.IO +namespace Spring.Core.IO; + +/// +/// Holder that combines with a specific encoding to be used for reading +/// from the resource +/// +/// Juergen Hoeller +/// Erich Eichinger (.NET) +public class EncodedResource { + private readonly IResource resource; + private readonly Encoding encoding; + private readonly bool autoDetectEncoding; + /// - /// Holder that combines with a specific encoding to be used for reading - /// from the resource + /// Create an encoded resource, autodetecting the encoding from the resource stream. /// - /// Juergen Hoeller - /// Erich Eichinger (.NET) - public class EncodedResource + /// + public EncodedResource(IResource resource) + : this(resource, null, true) { - private readonly IResource resource; - private readonly Encoding encoding; - private readonly bool autoDetectEncoding; + // noop + } - /// - /// Create an encoded resource, autodetecting the encoding from the resource stream. - /// - /// - public EncodedResource(IResource resource) - :this(resource, null, true) + /// + /// Create an encoded resource, autodetecting the encoding from the resource stream. + /// + /// the resource to read from. Must not be null + /// whether to autoDetect encoding from byte-order marks () + public EncodedResource(IResource resource, bool autoDetectEncoding) + : this(resource, null, autoDetectEncoding) + { + // noop + } + + /// + /// Create an encoded resource using the specified encoding. + /// + /// the resource to read from. Must not be null + /// the encoding to use. If null, encoding will be autodetected. + /// whether to autoDetect encoding from byte-order marks () + public EncodedResource(IResource resource, Encoding encoding, bool autoDetectEncoding) + { + AssertUtils.ArgumentNotNull(resource, "resource"); + this.resource = resource; + this.encoding = encoding; + this.autoDetectEncoding = autoDetectEncoding; + } + + /// + /// Get the underlying resource + /// + public IResource Resource + { + get { return resource; } + } + + /// + /// Get the encoding to use for reading, if any. May be null + /// + public Encoding Encoding + { + get { return encoding; } + } + + /// + /// whether to autoDetect encoding from byte-order marks () + /// + public bool AutoDetectEncoding + { + get { return autoDetectEncoding; } + } + + /// + /// + /// + /// + public TextReader OpenReader() + { + if (this.encoding != null) { - // noop + return new StreamReader(this.resource.InputStream, this.encoding, autoDetectEncoding); } - /// - /// Create an encoded resource, autodetecting the encoding from the resource stream. - /// - /// the resource to read from. Must not be null - /// whether to autoDetect encoding from byte-order marks () - public EncodedResource(IResource resource, bool autoDetectEncoding) - :this(resource, null, autoDetectEncoding) - { - // noop - } + return new StreamReader(this.resource.InputStream, autoDetectEncoding); + } - /// - /// Create an encoded resource using the specified encoding. - /// - /// the resource to read from. Must not be null - /// the encoding to use. If null, encoding will be autodetected. - /// whether to autoDetect encoding from byte-order marks () - public EncodedResource(IResource resource, Encoding encoding, bool autoDetectEncoding) - { - AssertUtils.ArgumentNotNull(resource, "resource"); - this.resource = resource; - this.encoding = encoding; - this.autoDetectEncoding = autoDetectEncoding; - } + /// + /// Determine whether equals this instance. + /// + /// + /// true if obj is an and both + /// , and are equal. + /// + public override bool Equals(object obj) + { + if (obj == this) return true; + if (!(obj is EncodedResource)) return false; - /// - /// Get the underlying resource - /// - public IResource Resource - { - get { return resource; } - } + EncodedResource other = (EncodedResource) obj; + return object.Equals(this.resource, other.resource) + && object.Equals(this.encoding, other.encoding); + } - /// - /// Get the encoding to use for reading, if any. May be null - /// - public Encoding Encoding - { - get { return encoding; } - } + /// + /// Calculate the unique hash code for this instance. + /// + /// + public override int GetHashCode() + { + return this.resource.GetHashCode(); + } - /// - /// whether to autoDetect encoding from byte-order marks () - /// - public bool AutoDetectEncoding - { - get { return autoDetectEncoding; } - } - - /// - /// - /// - /// - public TextReader OpenReader() - { - if (this.encoding != null) - { - return new StreamReader(this.resource.InputStream, this.encoding, autoDetectEncoding); - } - return new StreamReader(this.resource.InputStream, autoDetectEncoding); - } - - /// - /// Determine whether equals this instance. - /// - /// - /// true if obj is an and both - /// , and are equal. - /// - public override bool Equals(object obj) - { - if (obj == this) return true; - if (!(obj is EncodedResource)) return false; - - EncodedResource other = (EncodedResource) obj; - return object.Equals(this.resource, other.resource) - && object.Equals(this.encoding, other.encoding); - } - - /// - /// Calculate the unique hash code for this instance. - /// - /// - public override int GetHashCode() - { - return this.resource.GetHashCode(); - } - - /// - /// Get a textual description of the resource. - /// - public override string ToString() - { - return this.resource.ToString(); - } + /// + /// Get a textual description of the resource. + /// + public override string ToString() + { + return this.resource.ToString(); } } diff --git a/src/Spring/Spring.Core/Core/IO/FileSystemResource.cs b/src/Spring/Spring.Core/Core/IO/FileSystemResource.cs index f75c6f59..19584dad 100644 --- a/src/Spring/Spring.Core/Core/IO/FileSystemResource.cs +++ b/src/Spring/Spring.Core/Core/IO/FileSystemResource.cs @@ -25,367 +25,368 @@ using Spring.Util; #endregion -namespace Spring.Core.IO +namespace Spring.Core.IO; + +/// +/// A backed resource. +/// +/// +///

+/// Supports resolution as both a and a +/// . +///

+///

+/// Also supports the use of the ~ character. If the ~ character +/// is the first character in a resource path (sans protocol), the ~ +/// character will be replaced with the value of the +/// System.AppDomain.CurrentDomain.BaseDirectory property (an example of +/// this can be seen in the examples below). +///

+///
+/// +///

+/// Consider the example of an application that is running (has been launched +/// from) the C:\App\ directory. The following resource paths will map +/// to the following resources on the filesystem... +///

+/// +/// strings.txt C:\App\strings.txt +/// ~/strings.txt C:\App\strings.txt +/// file://~/strings.txt C:\App\strings.txt +/// file://~/../strings.txt C:\strings.txt +/// ../strings.txt C:\strings.txt +/// ~/../strings.txt C:\strings.txt +/// +/// // note that only a leading ~ character is resolved to the executing directory... +/// stri~ngs.txt C:\App\stri~ngs.txt +/// +///
+/// Juergen Hoeller +/// Leonardo Susatyo (.NET) +/// Aleksandar Seovic (.NET) +public class FileSystemResource : AbstractResource { + private FileInfo fileHandle; + private string rootLocation; + private string resourcePath; + + #region Constructors + /// - /// A backed resource. + /// Creates a new instance of the + /// class. + /// + protected FileSystemResource() + { + } + + /// + /// Creates a new instance of the + /// class. + /// + /// + /// The name of the file system resource. + /// + /// + /// If the supplied is + /// or contains only whitespace character(s). + /// + public FileSystemResource(string resourceName) + : this(resourceName, false) + { + } + + /// + /// Creates a new instance of the + /// class. + /// + /// + /// The name of the file system resource. + /// + /// + /// Supresses initialization of this instance. Used from derived classes. + /// + /// + /// If the supplied is + /// or contains only whitespace character(s). + /// + protected FileSystemResource(string resourceName, bool suppressInitialize) + : base(resourceName) + { + if (!suppressInitialize) + { + Initialize(resourceName); + } + } + + #endregion + + #region Properties + + /// + /// Returns the underlying handle for + /// this resource. + /// + /// + /// The handle for this resource. + /// + /// + public override FileInfo File + { + get { return fileHandle; } + } + + /// + /// Does this support relative + /// resource retrieval? /// /// ///

- /// Supports resolution as both a and a - /// . - ///

- ///

- /// Also supports the use of the ~ character. If the ~ character - /// is the first character in a resource path (sans protocol), the ~ - /// character will be replaced with the value of the - /// System.AppDomain.CurrentDomain.BaseDirectory property (an example of - /// this can be seen in the examples below). + /// This implementation does support relative resource retrieval, and + /// so will always return . ///

///
- /// - ///

- /// Consider the example of an application that is running (has been launched - /// from) the C:\App\ directory. The following resource paths will map - /// to the following resources on the filesystem... - ///

- /// - /// strings.txt C:\App\strings.txt - /// ~/strings.txt C:\App\strings.txt - /// file://~/strings.txt C:\App\strings.txt - /// file://~/../strings.txt C:\strings.txt - /// ../strings.txt C:\strings.txt - /// ~/../strings.txt C:\strings.txt - /// - /// // note that only a leading ~ character is resolved to the executing directory... - /// stri~ngs.txt C:\App\stri~ngs.txt - /// - ///
- /// Juergen Hoeller - /// Leonardo Susatyo (.NET) - /// Aleksandar Seovic (.NET) - public class FileSystemResource : AbstractResource + /// + /// if this + /// supports relative resource + /// retrieval. + /// + /// + protected override bool SupportsRelativeResources { - private FileInfo fileHandle; - private string rootLocation; - private string resourcePath; + get { return true; } + } - #region Constructors + /// + /// Gets the root location of the resource (a drive or UNC file share + /// name in this case). + /// + /// + /// The root location of the resource. + /// + /// + protected override string RootLocation + { + get { return this.rootLocation; } + } - /// - /// Creates a new instance of the - /// class. - /// - protected FileSystemResource() + /// + /// Gets the current path of the resource. + /// + /// + /// The current path of the resource. + /// + /// + protected override string ResourcePath + { + get { return this.resourcePath; } + } + + /// + /// Gets those characters that are valid path separators for the + /// resource type. + /// + /// + /// Those characters that are valid path separators for the resource + /// type. + /// + /// + /// + protected override char[] PathSeparatorChars + { + get { return new char[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar }; } + } + + /// + /// Return an for this resource. + /// + /// + /// An . + /// + /// + /// If the stream could not be opened. + /// + /// + /// If the underlying file could not be found. + /// + /// + public override Stream InputStream + { + get { - } - - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The name of the file system resource. - /// - /// - /// If the supplied is - /// or contains only whitespace character(s). - /// - public FileSystemResource(string resourceName) - : this(resourceName, false) - { - } - - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The name of the file system resource. - /// - /// - /// Supresses initialization of this instance. Used from derived classes. - /// - /// - /// If the supplied is - /// or contains only whitespace character(s). - /// - protected FileSystemResource(string resourceName, bool suppressInitialize) - : base(resourceName) - { - if (!suppressInitialize) + if (Uri.IsFile) { - Initialize( resourceName ); - } - } - - #endregion - - #region Properties - - /// - /// Returns the underlying handle for - /// this resource. - /// - /// - /// The handle for this resource. - /// - /// - public override FileInfo File - { - get { return fileHandle; } - } - - /// - /// Does this support relative - /// resource retrieval? - /// - /// - ///

- /// This implementation does support relative resource retrieval, and - /// so will always return . - ///

- ///
- /// - /// if this - /// supports relative resource - /// retrieval. - /// - /// - protected override bool SupportsRelativeResources - { - get { return true; } - } - - /// - /// Gets the root location of the resource (a drive or UNC file share - /// name in this case). - /// - /// - /// The root location of the resource. - /// - /// - protected override string RootLocation - { - get { return this.rootLocation; } - } - - /// - /// Gets the current path of the resource. - /// - /// - /// The current path of the resource. - /// - /// - protected override string ResourcePath - { - get { return this.resourcePath; } - } - - /// - /// Gets those characters that are valid path separators for the - /// resource type. - /// - /// - /// Those characters that are valid path separators for the resource - /// type. - /// - /// - /// - protected override char[] PathSeparatorChars - { - get { return new char[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar }; } - } - - /// - /// Return an for this resource. - /// - /// - /// An . - /// - /// - /// If the stream could not be opened. - /// - /// - /// If the underlying file could not be found. - /// - /// - public override Stream InputStream - { - get - { - if (Uri.IsFile) + try { - try - { - return new FileStream(Uri.LocalPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); - } - catch(DirectoryNotFoundException) - { - // ignore difference between File & Directory exception in this case - } + return new FileStream(Uri.LocalPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); + } + catch (DirectoryNotFoundException) + { + // ignore difference between File & Directory exception in this case } - throw new FileNotFoundException(Description - + " cannot be resolved to local file path" - + " - resource does not use 'file:' protocol."); - } - } - - /// - /// Returns a description for this resource. - /// - /// - /// A description for this resource. - /// - /// - public override string Description - { - get - { - return string.Format( - CultureInfo.InvariantCulture, - "file [{0}]", fileHandle.FullName); - } - } - - /// - /// Returns the handle for this resource. - /// - /// - /// The handle for this resource. - /// - /// - /// If the resource is not available or cannot be exposed as a - /// . - /// - /// - public override Uri Uri - { - get { return new UriBuilder("file", null, 0, fileHandle.FullName).Uri; } - } - - #endregion - - /// - /// Initializes this instance. - /// - /// - protected void Initialize( string resourceName ) - { - this.fileHandle = ResolveFileHandle(resourceName); - this.rootLocation = ResolveRootLocation(resourceName); - this.resourcePath = ResolveResourcePath(resourceName); - } - - /// - /// Resolves the handle - /// for the supplied . - /// - /// - /// The name of the file system resource. - /// - /// - /// The handle for this resource. - /// - protected virtual FileInfo ResolveFileHandle(string resourceName) - { - return new FileInfo(ResolveResourceNameWithoutProtocol(resourceName)); - } - - /// - /// Resolves the root location for the supplied . - /// - /// - /// The name of the file system resource. - /// - /// - /// The root location of the resource. - /// - protected virtual string ResolveRootLocation(string resourceName) - { - string root = this.fileHandle.Directory.Root.ToString(); - if (root.Length > 0 && - (root.EndsWith(Path.DirectorySeparatorChar.ToString()) || - root.EndsWith(Path.AltDirectorySeparatorChar.ToString()))) - { - root = root.Substring(0, root.Length - 1); } - return root; - } - - /// - /// Resolves the path for the supplied . - /// - /// - /// The name of the file system resource. - /// - /// - /// The current path of the resource. - /// - protected virtual string ResolveResourcePath(string resourceName) - { - string path = this.fileHandle.DirectoryName; - if (path.Equals(this.fileHandle.Directory.Root.ToString())) - { - path = null; - } - else - { - path = path.Substring(this.rootLocation.Length + 1); - } - - return path; - } - - /// - /// Resolves the presence of the - /// value - /// in the supplied into a path. - /// - /// - /// The name of the resource. - /// - /// - /// The string that is a placeholder for a base path. - /// - /// - /// The name of the resource with any - /// value having been resolved into an actual path. - /// - protected override string ResolveBasePathPlaceHolder( - string resourceName, string basePathPlaceHolder) - { - // Remove extra slashes used to indicate that resource is local (handle the case "/C:/path1/...") - if (resourceName[0] == '/' && resourceName[2] == ':') - { - resourceName = resourceName.Substring(1); - } - - if (StringUtils.HasText(resourceName) - && resourceName.TrimStart().StartsWith(basePathPlaceHolder)) - { - return resourceName.Replace(basePathPlaceHolder, AppDomain.CurrentDomain.BaseDirectory).TrimStart(); - } - return resourceName; - } - - /// - /// Does the supplied relative ? - /// - /// - /// The name of the resource to test. - /// - /// - /// if resource name is relative; - /// otherwise . - /// - protected override bool IsRelativeResource(string resourceName) - { - return (! - (resourceName.StartsWith(@"\\") || // UNC file share - resourceName.IndexOf(':') >= 0 || // drive - resourceName.StartsWith(BasePathPlaceHolder))); + throw new FileNotFoundException(Description + + " cannot be resolved to local file path" + + " - resource does not use 'file:' protocol."); } } + + /// + /// Returns a description for this resource. + /// + /// + /// A description for this resource. + /// + /// + public override string Description + { + get + { + return string.Format( + CultureInfo.InvariantCulture, + "file [{0}]", fileHandle.FullName); + } + } + + /// + /// Returns the handle for this resource. + /// + /// + /// The handle for this resource. + /// + /// + /// If the resource is not available or cannot be exposed as a + /// . + /// + /// + public override Uri Uri + { + get { return new UriBuilder("file", null, 0, fileHandle.FullName).Uri; } + } + + #endregion + + /// + /// Initializes this instance. + /// + /// + protected void Initialize(string resourceName) + { + this.fileHandle = ResolveFileHandle(resourceName); + this.rootLocation = ResolveRootLocation(resourceName); + this.resourcePath = ResolveResourcePath(resourceName); + } + + /// + /// Resolves the handle + /// for the supplied . + /// + /// + /// The name of the file system resource. + /// + /// + /// The handle for this resource. + /// + protected virtual FileInfo ResolveFileHandle(string resourceName) + { + return new FileInfo(ResolveResourceNameWithoutProtocol(resourceName)); + } + + /// + /// Resolves the root location for the supplied . + /// + /// + /// The name of the file system resource. + /// + /// + /// The root location of the resource. + /// + protected virtual string ResolveRootLocation(string resourceName) + { + string root = this.fileHandle.Directory.Root.ToString(); + if (root.Length > 0 && + (root.EndsWith(Path.DirectorySeparatorChar.ToString()) || + root.EndsWith(Path.AltDirectorySeparatorChar.ToString()))) + { + root = root.Substring(0, root.Length - 1); + } + + return root; + } + + /// + /// Resolves the path for the supplied . + /// + /// + /// The name of the file system resource. + /// + /// + /// The current path of the resource. + /// + protected virtual string ResolveResourcePath(string resourceName) + { + string path = this.fileHandle.DirectoryName; + if (path.Equals(this.fileHandle.Directory.Root.ToString())) + { + path = null; + } + else + { + path = path.Substring(this.rootLocation.Length + 1); + } + + return path; + } + + /// + /// Resolves the presence of the + /// value + /// in the supplied into a path. + /// + /// + /// The name of the resource. + /// + /// + /// The string that is a placeholder for a base path. + /// + /// + /// The name of the resource with any + /// value having been resolved into an actual path. + /// + protected override string ResolveBasePathPlaceHolder( + string resourceName, string basePathPlaceHolder) + { + // Remove extra slashes used to indicate that resource is local (handle the case "/C:/path1/...") + if (resourceName[0] == '/' && resourceName[2] == ':') + { + resourceName = resourceName.Substring(1); + } + + if (StringUtils.HasText(resourceName) + && resourceName.TrimStart().StartsWith(basePathPlaceHolder)) + { + return resourceName.Replace(basePathPlaceHolder, AppDomain.CurrentDomain.BaseDirectory).TrimStart(); + } + + return resourceName; + } + + /// + /// Does the supplied relative ? + /// + /// + /// The name of the resource to test. + /// + /// + /// if resource name is relative; + /// otherwise . + /// + protected override bool IsRelativeResource(string resourceName) + { + return (! + (resourceName.StartsWith(@"\\") || // UNC file share + resourceName.IndexOf(':') >= 0 || // drive + resourceName.StartsWith(BasePathPlaceHolder))); + } } diff --git a/src/Spring/Spring.Core/Core/IO/IInputStreamSource.cs b/src/Spring/Spring.Core/Core/IO/IInputStreamSource.cs index ad856e2a..2a397a33 100644 --- a/src/Spring/Spring.Core/Core/IO/IInputStreamSource.cs +++ b/src/Spring/Spring.Core/Core/IO/IInputStreamSource.cs @@ -22,43 +22,42 @@ #endregion -namespace Spring.Core.IO +namespace Spring.Core.IO; + +/// +/// Simple interface for objects that are sources for +/// s. +/// +/// +///

+/// This is the base interface for the abstraction encapsulated by +/// Spring.NET's interface. +///

+///
+/// Juergen Hoeller +/// Rick Evans (.NET) +/// +public interface IInputStreamSource { - /// - /// Simple interface for objects that are sources for - /// s. - /// - /// - ///

- /// This is the base interface for the abstraction encapsulated by - /// Spring.NET's interface. - ///

+ /// + /// Return an for this resource. + /// + /// + /// + /// Clients of this interface must be aware that every access of this + /// property will create a fresh ; + /// it is the responsibility of the calling code to close any such + /// . + /// /// - /// Juergen Hoeller - /// Rick Evans (.NET) - /// - public interface IInputStreamSource + /// + /// An . + /// + /// + /// If the stream could not be opened. + /// + Stream InputStream { - /// - /// Return an for this resource. - /// - /// - /// - /// Clients of this interface must be aware that every access of this - /// property will create a fresh ; - /// it is the responsibility of the calling code to close any such - /// . - /// - /// - /// - /// An . - /// - /// - /// If the stream could not be opened. - /// - Stream InputStream - { - get; - } - } + get; + } } diff --git a/src/Spring/Spring.Core/Core/IO/IResource.cs b/src/Spring/Spring.Core/Core/IO/IResource.cs index 412c144f..2e84410a 100644 --- a/src/Spring/Spring.Core/Core/IO/IResource.cs +++ b/src/Spring/Spring.Core/Core/IO/IResource.cs @@ -24,169 +24,168 @@ using System.ComponentModel; #endregion -namespace Spring.Core.IO +namespace Spring.Core.IO; + +/// +/// The central abstraction for Spring.NET's access to resources such as +/// s. +/// +/// +///

+/// This interface encapsulates a resource descriptor that abstracts away +/// from the underlying type of resource; possible resource types include +/// files, memory streams, and databases (this list is not exhaustive). +///

+///

+/// A can definitely be opened and accessed +/// for every such resource; if the resource exists in a physical form (for +/// example, the resource is not an in-memory stream or one that has been +/// extracted from an assembly or ZIP file), a or +/// can also be accessed. The actual +/// behavior is implementation-specific. +///

+///

+/// This interface, when used in tandem with the +/// interface, forms the backbone of +/// Spring.NET's resource handling. Third party extensions or libraries +/// that want to integrate external resources with Spring.NET's IoC +/// container are encouraged expose such resources via this abstraction. +///

+///

+/// Interfaces cannot obviously mandate implementation, but derived classes +/// are strongly encouraged to expose a constructor that takes a +/// single as it's sole argument (see example). +/// Exposing such a constructor will make your custom +/// implementation integrate nicely +/// with the class. +///

+///
+/// Juergen Hoeller +/// Rick Evans (.NET) +/// +/// +[TypeConverter(typeof(ResourceConverter))] +public interface IResource : IInputStreamSource { - /// - /// The central abstraction for Spring.NET's access to resources such as - /// s. - /// - /// - ///

- /// This interface encapsulates a resource descriptor that abstracts away - /// from the underlying type of resource; possible resource types include - /// files, memory streams, and databases (this list is not exhaustive). - ///

- ///

- /// A can definitely be opened and accessed - /// for every such resource; if the resource exists in a physical form (for - /// example, the resource is not an in-memory stream or one that has been - /// extracted from an assembly or ZIP file), a or - /// can also be accessed. The actual - /// behavior is implementation-specific. - ///

- ///

- /// This interface, when used in tandem with the - /// interface, forms the backbone of - /// Spring.NET's resource handling. Third party extensions or libraries - /// that want to integrate external resources with Spring.NET's IoC - /// container are encouraged expose such resources via this abstraction. - ///

- ///

- /// Interfaces cannot obviously mandate implementation, but derived classes - /// are strongly encouraged to expose a constructor that takes a - /// single as it's sole argument (see example). - /// Exposing such a constructor will make your custom - /// implementation integrate nicely - /// with the class. - ///

- ///
- /// Juergen Hoeller - /// Rick Evans (.NET) - /// - /// - [TypeConverter(typeof(ResourceConverter))] - public interface IResource : IInputStreamSource - { - /// - /// Does this resource represent a handle with an open stream? - /// - /// - ///

- /// If , the - /// cannot be read multiple times, and must be read and then closed to - /// avoid resource leaks. - ///

- ///

- /// Will be for all usual resource descriptors. - ///

- ///
- /// - /// if this resource represents a handle with an - /// open stream. - /// - /// - bool IsOpen { get; } + /// + /// Does this resource represent a handle with an open stream? + /// + /// + ///

+ /// If , the + /// cannot be read multiple times, and must be read and then closed to + /// avoid resource leaks. + ///

+ ///

+ /// Will be for all usual resource descriptors. + ///

+ ///
+ /// + /// if this resource represents a handle with an + /// open stream. + /// + /// + bool IsOpen { get; } - /// - /// Returns the handle for this resource. - /// - /// - ///

- /// For safety, always check the value of the - /// property prior to - /// accessing this property; resources that cannot be exposed as - /// a will typically return - /// from a call to the - /// property. - ///

- ///
- /// - /// The handle for this resource. - /// - /// - /// If the resource is not available or cannot be exposed as a - /// . - /// - /// - /// - Uri Uri { get; } + /// + /// Returns the handle for this resource. + /// + /// + ///

+ /// For safety, always check the value of the + /// property prior to + /// accessing this property; resources that cannot be exposed as + /// a will typically return + /// from a call to the + /// property. + ///

+ ///
+ /// + /// The handle for this resource. + /// + /// + /// If the resource is not available or cannot be exposed as a + /// . + /// + /// + /// + Uri Uri { get; } - /// - /// Returns a handle for this resource. - /// - /// - ///

- /// For safety, always check the value of the - /// property prior to - /// accessing this property; resources that cannot be exposed as - /// a will typically return - /// from a call to the - /// property. - ///

- ///
- /// - /// The handle for this resource. - /// - /// - /// If the resource is not available on a filesystem, or cannot be - /// exposed as a handle. - /// - /// - /// - FileInfo File { get; } + /// + /// Returns a handle for this resource. + /// + /// + ///

+ /// For safety, always check the value of the + /// property prior to + /// accessing this property; resources that cannot be exposed as + /// a will typically return + /// from a call to the + /// property. + ///

+ ///
+ /// + /// The handle for this resource. + /// + /// + /// If the resource is not available on a filesystem, or cannot be + /// exposed as a handle. + /// + /// + /// + FileInfo File { get; } - /// - /// Returns a description for this resource. - /// - /// - ///

- /// The description is typically used for diagnostics and other such - /// logging when working with the resource. - ///

- ///

- /// Implementations are also encouraged to return this value from their - /// method. - ///

- ///
- /// - /// A description for this resource. - /// - string Description { get; } + /// + /// Returns a description for this resource. + /// + /// + ///

+ /// The description is typically used for diagnostics and other such + /// logging when working with the resource. + ///

+ ///

+ /// Implementations are also encouraged to return this value from their + /// method. + ///

+ ///
+ /// + /// A description for this resource. + /// + string Description { get; } - /// - /// Does this resource actually exist in physical form? - /// - /// - ///

- /// An example of a resource that physically exists would be a - /// file on a local filesystem. An example of a resource that does not - /// physically exist would be an in-memory stream. - ///

- ///
- /// - /// if this resource actually exists in physical - /// form (for example on a filesystem). - /// - /// - /// - bool Exists { get; } + /// + /// Does this resource actually exist in physical form? + /// + /// + ///

+ /// An example of a resource that physically exists would be a + /// file on a local filesystem. An example of a resource that does not + /// physically exist would be an in-memory stream. + ///

+ ///
+ /// + /// if this resource actually exists in physical + /// form (for example on a filesystem). + /// + /// + /// + bool Exists { get; } - /// - /// Creates a resource relative to this resource. - /// - /// - /// The path (always resolved as relative to this resource). - /// - /// - /// The relative resource. - /// - /// - /// If the relative resource could not be created from the supplied - /// path. - /// - /// - /// If the resource does not support the notion of a relative path. - /// - IResource CreateRelative(string relativePath); - } -} + /// + /// Creates a resource relative to this resource. + /// + /// + /// The path (always resolved as relative to this resource). + /// + /// + /// The relative resource. + /// + /// + /// If the relative resource could not be created from the supplied + /// path. + /// + /// + /// If the resource does not support the notion of a relative path. + /// + IResource CreateRelative(string relativePath); +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Core/IO/IResourceLoader.cs b/src/Spring/Spring.Core/Core/IO/IResourceLoader.cs index 7dd977a7..ed9e058a 100644 --- a/src/Spring/Spring.Core/Core/IO/IResourceLoader.cs +++ b/src/Spring/Spring.Core/Core/IO/IResourceLoader.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -20,74 +20,71 @@ #region Imports - - #endregion -namespace Spring.Core.IO +namespace Spring.Core.IO; + +/// +/// Describes an object that can load +/// s. +/// +/// +///

+/// An implementation is +/// generally required to support the functionality described by this +/// interface. +///

+///

+/// The class is a +/// standalone implementation that is usable outside an +/// ; the aforementioned +/// class is also used by the +/// class. +///

+///
+/// Juergen Hoeller +/// Mark Pollack (.NET) +/// +/// +/// +public interface IResourceLoader { /// - /// Describes an object that can load - /// s. + /// Return an handle for the + /// specified resource. /// /// ///

- /// An implementation is - /// generally required to support the functionality described by this - /// interface. + /// The handle should always be a reusable resource descriptor; this + /// allows one to make repeated calls to the underlying + /// . ///

///

- /// The class is a - /// standalone implementation that is usable outside an - /// ; the aforementioned - /// class is also used by the - /// class. + ///

    + ///
  • + /// Must support fully qualified URLs, e.g. "file:C:/test.dat". + ///
  • + ///
  • + /// Should support relative file paths, e.g. "test.dat" (this will be + /// implementation-specific, typically provided by an + /// implementation). + ///
  • + ///
///

+ /// + /// An handle does not imply an + /// existing resource; you need to check the value of an + /// 's + /// property to determine + /// conclusively whether or not the resource actually exists. + /// ///
- /// Juergen Hoeller - /// Mark Pollack (.NET) + /// The resource location. + /// + /// An appropriate handle. + /// /// - /// - /// - public interface IResourceLoader - { - /// - /// Return an handle for the - /// specified resource. - /// - /// - ///

- /// The handle should always be a reusable resource descriptor; this - /// allows one to make repeated calls to the underlying - /// . - ///

- ///

- ///

    - ///
  • - /// Must support fully qualified URLs, e.g. "file:C:/test.dat". - ///
  • - ///
  • - /// Should support relative file paths, e.g. "test.dat" (this will be - /// implementation-specific, typically provided by an - /// implementation). - ///
  • - ///
- ///

- /// - /// An handle does not imply an - /// existing resource; you need to check the value of an - /// 's - /// property to determine - /// conclusively whether or not the resource actually exists. - /// - ///
- /// The resource location. - /// - /// An appropriate handle. - /// - /// - /// - /// - IResource GetResource(string location); - } + /// + /// + IResource GetResource(string location); } diff --git a/src/Spring/Spring.Core/Core/IO/InputStreamResource.cs b/src/Spring/Spring.Core/Core/IO/InputStreamResource.cs index 67f46a0a..63cf9ad9 100644 --- a/src/Spring/Spring.Core/Core/IO/InputStreamResource.cs +++ b/src/Spring/Spring.Core/Core/IO/InputStreamResource.cs @@ -24,119 +24,117 @@ using Spring.Util; #endregion -namespace Spring.Core.IO +namespace Spring.Core.IO; + +/// +/// adapter implementation for a +/// . +/// +/// +///

+/// Should only be used if no other +/// implementation is applicable. +///

+///

+/// In contrast to other +/// implementations, this is an adapter for an already opened +/// resource - the +/// therefore always returns . Do not use this class +/// if you need to keep the resource descriptor somewhere, or if you need +/// to read a stream multiple times. +///

+///
+/// Juergen Hoeller +/// Rick Evans (.NET) +public class InputStreamResource : AbstractResource { - /// - /// adapter implementation for a - /// . - /// - /// - ///

- /// Should only be used if no other - /// implementation is applicable. - ///

- ///

- /// In contrast to other - /// implementations, this is an adapter for an already opened - /// resource - the - /// therefore always returns . Do not use this class - /// if you need to keep the resource descriptor somewhere, or if you need - /// to read a stream multiple times. - ///

- ///
- /// Juergen Hoeller - /// Rick Evans (.NET) - public class InputStreamResource : AbstractResource - { - #region Constructor (s) / Destructor + #region Constructor (s) / Destructor - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The input to use. - /// - /// - /// Where the input comes from. - /// - /// - /// If the supplied is - /// . - /// - public InputStreamResource(Stream inputStream, string description) - { - AssertUtils.ArgumentNotNull(inputStream, "inputStream"); + /// + /// Creates a new instance of the + /// class. + /// + /// + /// The input to use. + /// + /// + /// Where the input comes from. + /// + /// + /// If the supplied is + /// . + /// + public InputStreamResource(Stream inputStream, string description) + { + AssertUtils.ArgumentNotNull(inputStream, "inputStream"); - _inputStream = inputStream; - _description = description == null ? string.Empty : description; - } + _inputStream = inputStream; + _description = description == null ? string.Empty : description; + } - #endregion + #endregion - #region Properties + #region Properties - /// - /// The input to use. - /// - /// - /// If the underlying has already - /// been read. - /// - public override Stream InputStream - { - get - { - if (_inputStream == null) - { - throw new InvalidOperationException( - "InputStream has already been read - " + - "do not use InputStreamResource if a stream " + - "needs to be read multiple times"); - } - Stream result = _inputStream; - _inputStream = null; - return result; - } - } + /// + /// The input to use. + /// + /// + /// If the underlying has already + /// been read. + /// + public override Stream InputStream + { + get + { + if (_inputStream == null) + { + throw new InvalidOperationException( + "InputStream has already been read - " + + "do not use InputStreamResource if a stream " + + "needs to be read multiple times"); + } - /// - /// Returns a description for this resource. - /// - /// - /// A description for this resource. - /// - /// - public override string Description - { - get { return _description; } - } + Stream result = _inputStream; + _inputStream = null; + return result; + } + } - /// - /// This implementation always returns true - /// - public override bool IsOpen - { - get { return true; } - } + /// + /// Returns a description for this resource. + /// + /// + /// A description for this resource. + /// + /// + public override string Description + { + get { return _description; } + } + /// + /// This implementation always returns true + /// + public override bool IsOpen + { + get { return true; } + } + /// + /// This implemementation always returns true + /// + public override bool Exists + { + get { return true; } + } - /// - /// This implemementation always returns true - /// - public override bool Exists - { - get { return true; } - } + #endregion - #endregion + #region Fields - #region Fields + private Stream _inputStream; + private string _description; - private Stream _inputStream; - private string _description; - - #endregion - } + #endregion } diff --git a/src/Spring/Spring.Core/Core/IO/ResourceConverter.cs b/src/Spring/Spring.Core/Core/IO/ResourceConverter.cs index c7c86990..4669daea 100644 --- a/src/Spring/Spring.Core/Core/IO/ResourceConverter.cs +++ b/src/Spring/Spring.Core/Core/IO/ResourceConverter.cs @@ -27,186 +27,189 @@ using Spring.Util; #endregion -namespace Spring.Core.IO +namespace Spring.Core.IO; + +/// +/// Custom type converter for instances. +/// +/// +///

+/// A resource path may contain placeholder variables of the form ${...} +/// that will be expended to environment variables. +///

+///

+/// Currently only supports conversion from a +/// instance. +///

+///
+/// +///

+/// On Win9x boxes, this resource path, ${userprofile}\objects.xml will +/// be expanded at runtime with the value of the 'userprofile' environment +/// variable substituted for the '${userprofile}' portion of the path. +///

+/// +/// // assuming a user called Rick, running on a plain vanilla Windows XP setup... +/// // this resource path... +/// +/// ${userprofile}\objects.xml +/// +/// // will become (after expansion)... +/// +/// C:\Documents and Settings\Rick\objects.xml +/// +///
+/// Mark Pollack +/// +/// +public class ResourceConverter : TypeConverter { - /// - /// Custom type converter for instances. - /// - /// - ///

- /// A resource path may contain placeholder variables of the form ${...} - /// that will be expended to environment variables. - ///

- ///

- /// Currently only supports conversion from a - /// instance. - ///

- ///
- /// - ///

- /// On Win9x boxes, this resource path, ${userprofile}\objects.xml will - /// be expanded at runtime with the value of the 'userprofile' environment - /// variable substituted for the '${userprofile}' portion of the path. - ///

- /// - /// // assuming a user called Rick, running on a plain vanilla Windows XP setup... - /// // this resource path... - /// - /// ${userprofile}\objects.xml - /// - /// // will become (after expansion)... - /// - /// C:\Documents and Settings\Rick\objects.xml - /// - ///
- /// Mark Pollack - /// - /// - public class ResourceConverter : TypeConverter - { - private static readonly ILogger _log = LogManager.GetLogger(); - private IResourceLoader _resourceLoader; - - #region Constructor (s) / Destructor + private static readonly ILogger _log = LogManager.GetLogger(); + private IResourceLoader _resourceLoader; - /// - /// Creates a new instance of the - /// class. - /// - public ResourceConverter() - { - _resourceLoader = new ConfigurableResourceLoader(); - } + #region Constructor (s) / Destructor - /// - /// Creates a new instance of the - /// class using the specified resourceLoader. - /// - /// the underlying IResourceLoader to be used to resolve resources - public ResourceConverter( IResourceLoader resourceLoader ) - { - AssertUtils.ArgumentNotNull( resourceLoader, "resourceLoader" ); - _resourceLoader = resourceLoader; - } - #endregion + /// + /// Creates a new instance of the + /// class. + /// + public ResourceConverter() + { + _resourceLoader = new ConfigurableResourceLoader(); + } - /// - /// Returns whether this converter can convert an object of one - /// to a - /// - /// - /// A - /// that provides a format context. - /// - /// - /// A that represents the - /// you want to convert from. - /// - /// - /// if the conversion is possible. - /// - public override bool CanConvertFrom( - ITypeDescriptorContext context, - Type sourceType) - { - if (sourceType == typeof (string)) - { - return true; - } - return base.CanConvertFrom(context, sourceType); - } + /// + /// Creates a new instance of the + /// class using the specified resourceLoader. + /// + /// the underlying IResourceLoader to be used to resolve resources + public ResourceConverter(IResourceLoader resourceLoader) + { + AssertUtils.ArgumentNotNull(resourceLoader, "resourceLoader"); + _resourceLoader = resourceLoader; + } - /// - /// Convert from a string value to a - /// instance. - /// - /// - /// A - /// that provides a format context. - /// - /// - /// The to use - /// as the current culture. - /// - /// - /// The value that is to be converted. - /// - /// - /// An if successful. - /// - /// - /// If the resource name objectained form the supplied - /// is malformed. - /// - /// - /// In the case of any errors arising from the instantiation of the - /// returned instance. - /// - public override object ConvertFrom( - ITypeDescriptorContext context, - CultureInfo culture, object value) - { - string resource = value as string; - if (resource != null) - { - return GetResourceLoader().GetResource(ResolvePath(resource)); - } - return base.ConvertFrom(context, culture, value); - } + #endregion - /// - /// Resolve the given path, replacing placeholder values with - /// corresponding property values if necessary. - /// - /// - ///

- /// This implementation resolves environment variables only. - ///

- ///
- /// The original resource path. - /// The resolved resource path. - protected virtual string ResolvePath(string path) - { - // quite inefficient, but cost is only ever paid once at startup... - IList expressions = StringUtils.GetAntExpressions(path); - foreach (string expression in expressions) - { - string environmentValue - = Environment.GetEnvironmentVariable(expression); - if (environmentValue != null) - { - path = StringUtils.SetAntExpression( - path, expression, environmentValue); - } - else - { - #region Instrumentation + /// + /// Returns whether this converter can convert an object of one + /// to a + /// + /// + /// A + /// that provides a format context. + /// + /// + /// A that represents the + /// you want to convert from. + /// + /// + /// if the conversion is possible. + /// + public override bool CanConvertFrom( + ITypeDescriptorContext context, + Type sourceType) + { + if (sourceType == typeof(string)) + { + return true; + } - if (_log.IsEnabled(LogLevel.Warning)) - { - _log.LogWarning(string.Format( - CultureInfo.InvariantCulture, - "Could not resolve placeholder '{0}' in resource path " + - "'{1}' as an environment variable.", expression, path)); - } + return base.CanConvertFrom(context, sourceType); + } - #endregion - } - } - return path; - } + /// + /// Convert from a string value to a + /// instance. + /// + /// + /// A + /// that provides a format context. + /// + /// + /// The to use + /// as the current culture. + /// + /// + /// The value that is to be converted. + /// + /// + /// An if successful. + /// + /// + /// If the resource name objectained form the supplied + /// is malformed. + /// + /// + /// In the case of any errors arising from the instantiation of the + /// returned instance. + /// + public override object ConvertFrom( + ITypeDescriptorContext context, + CultureInfo culture, object value) + { + string resource = value as string; + if (resource != null) + { + return GetResourceLoader().GetResource(ResolvePath(resource)); + } - /// - /// Return the used to - /// resolve the string. - /// - /// - /// The used to resolve - /// the string. - /// - protected internal virtual IResourceLoader GetResourceLoader() - { - return _resourceLoader; - } - } + return base.ConvertFrom(context, culture, value); + } + + /// + /// Resolve the given path, replacing placeholder values with + /// corresponding property values if necessary. + /// + /// + ///

+ /// This implementation resolves environment variables only. + ///

+ ///
+ /// The original resource path. + /// The resolved resource path. + protected virtual string ResolvePath(string path) + { + // quite inefficient, but cost is only ever paid once at startup... + IList expressions = StringUtils.GetAntExpressions(path); + foreach (string expression in expressions) + { + string environmentValue + = Environment.GetEnvironmentVariable(expression); + if (environmentValue != null) + { + path = StringUtils.SetAntExpression( + path, expression, environmentValue); + } + else + { + #region Instrumentation + + if (_log.IsEnabled(LogLevel.Warning)) + { + _log.LogWarning(string.Format( + CultureInfo.InvariantCulture, + "Could not resolve placeholder '{0}' in resource path " + + "'{1}' as an environment variable.", expression, path)); + } + + #endregion + } + } + + return path; + } + + /// + /// Return the used to + /// resolve the string. + /// + /// + /// The used to resolve + /// the string. + /// + protected internal virtual IResourceLoader GetResourceLoader() + { + return _resourceLoader; + } } diff --git a/src/Spring/Spring.Core/Core/IO/ResourceHandlerRegistry.cs b/src/Spring/Spring.Core/Core/IO/ResourceHandlerRegistry.cs index 88963791..e5e5b372 100644 --- a/src/Spring/Spring.Core/Core/IO/ResourceHandlerRegistry.cs +++ b/src/Spring/Spring.Core/Core/IO/ResourceHandlerRegistry.cs @@ -19,271 +19,271 @@ #endregion using System.Reflection; - using Spring.Context.Support; using Spring.Core.TypeResolution; using Spring.Util; using Spring.Reflection.Dynamic; -namespace Spring.Core.IO +namespace Spring.Core.IO; + +/// +/// Registry class that allows users to register and retrieve protocol handlers. +/// +/// +/// +/// Resource handler is an implementation of interface +/// that should be used to process resources with the specified protocol. +/// +/// +/// They are used throughout the framework to access resources from various +/// sources. For example, application context loads object definitions from the resources +/// that are processed using one of the registered resource handlers. +/// +/// Following resource handlers are registered by default: +/// +/// +/// Protocol +/// Handler Type +/// Description +/// +/// +/// config +/// +/// Resolves the resources by loading specified configuration section from the standard .NET config file. +/// +/// +/// file +/// +/// Resolves filesystem resources. +/// +/// +/// http +/// +/// Resolves remote web resources. +/// +/// +/// https +/// +/// Resolves remote web resources via HTTPS. +/// +/// +/// ftp +/// +/// Resolves ftp resources. +/// +/// +/// assembly +/// +/// Resolves resources that are embedded into an assembly. +/// +/// +/// web +/// Spring.Core.IO.WebResource, Spring.Web* +/// Resolves resources relative to the web application's virtual directory. +/// +/// +/// * only available in web applications. +/// +/// Users can create and register their own protocol handlers by implementing interface +/// and mapping custom protocol name to that implementation. See for details +/// on how to register custom protocol handler. +/// +/// +/// Aleksandar Seovic +public class ResourceHandlerRegistry { /// - /// Registry class that allows users to register and retrieve protocol handlers. + /// Name of the .Net config section that contains definitions + /// for custom resource handlers. + /// + private const string ResourcesSectionName = "spring/resourceHandlers"; + + private static object syncRoot = new object(); + private static IDictionary resourceHandlers = new Dictionary(); + + /// + /// Registers standard and user-configured resource handlers. + /// + static ResourceHandlerRegistry() + { + lock (syncRoot) + { + RegisterResourceHandler("config", typeof(ConfigSectionResource)); + RegisterResourceHandler("file", typeof(FileSystemResource)); + RegisterResourceHandler("http", typeof(UrlResource)); + RegisterResourceHandler("https", typeof(UrlResource)); + RegisterResourceHandler("ftp", typeof(UrlResource)); + RegisterResourceHandler("assembly", typeof(AssemblyResource)); + + // register custom resource handlers + ConfigurationUtils.GetSection(ResourcesSectionName); + } + } + + /// + /// Returns resource handler for the specified protocol name. /// /// /// - /// Resource handler is an implementation of interface - /// that should be used to process resources with the specified protocol. - /// - /// - /// They are used throughout the framework to access resources from various - /// sources. For example, application context loads object definitions from the resources - /// that are processed using one of the registered resource handlers. - /// - /// Following resource handlers are registered by default: - /// - /// - /// Protocol - /// Handler Type - /// Description - /// - /// - /// config - /// - /// Resolves the resources by loading specified configuration section from the standard .NET config file. - /// - /// - /// file - /// - /// Resolves filesystem resources. - /// - /// - /// http - /// - /// Resolves remote web resources. - /// - /// - /// https - /// - /// Resolves remote web resources via HTTPS. - /// - /// - /// ftp - /// - /// Resolves ftp resources. - /// - /// - /// assembly - /// - /// Resolves resources that are embedded into an assembly. - /// - /// - /// web - /// Spring.Core.IO.WebResource, Spring.Web* - /// Resolves resources relative to the web application's virtual directory. - /// - /// - /// * only available in web applications. - /// - /// Users can create and register their own protocol handlers by implementing interface - /// and mapping custom protocol name to that implementation. See for details - /// on how to register custom protocol handler. + /// This method returns object that should be used + /// to create an instance of the -derived type by passing + /// resource location as a parameter. /// /// - /// Aleksandar Seovic - public class ResourceHandlerRegistry + /// Name of the protocol to get the handler for. + /// Resource handler constructor for the specified protocol name. + /// If is null. + public static IDynamicConstructor GetResourceHandler(string protocolName) { - /// - /// Name of the .Net config section that contains definitions - /// for custom resource handlers. - /// - private const string ResourcesSectionName = "spring/resourceHandlers"; + AssertUtils.ArgumentNotNull(protocolName, "protocolName"); + IDynamicConstructor constructor; + resourceHandlers.TryGetValue(protocolName, out constructor); + return constructor; + } - private static object syncRoot = new object(); - private static IDictionary resourceHandlers = new Dictionary(); + /// + /// Returns true if a handler is registered for the specified protocol, + /// false otherwise. + /// + /// Name of the protocol. + /// + /// true if a handler is registered for the specified protocol, false otherwise. + /// + /// If is null. + public static bool IsHandlerRegistered(string protocolName) + { + return resourceHandlers.ContainsKey(protocolName); + } - /// - /// Registers standard and user-configured resource handlers. - /// - static ResourceHandlerRegistry() + /// + /// Registers resource handler and maps it to the specified protocol name. + /// + /// + ///

+ /// If the mapping already exists, the existing mapping will be + /// silently overwritten with the new mapping. + ///

+ ///
+ /// + /// The protocol to add (or override). + /// + /// + /// The type name of the concrete implementation of the + /// interface that will handle + /// the specified protocol. + /// + /// + /// If the supplied is + /// or contains only whitespace character(s); or + /// if the supplied is + /// . + /// + /// + /// If the supplied is not a + /// that derives from the + /// interface; or (having passed + /// this first check), the supplied + /// does not expose a constructor that takes a single + /// parameter. + /// + public static void RegisterResourceHandler(string protocolName, string handlerTypeName) + { + AssertUtils.ArgumentHasText(protocolName, "protocolName"); + AssertUtils.ArgumentHasText(handlerTypeName, "handlerTypeName"); + + Type handlerType = TypeResolutionUtils.ResolveType(handlerTypeName); + RegisterResourceHandler(protocolName, handlerType); + } + + /// + /// Registers resource handler and maps it to the specified protocol name. + /// + /// + ///

+ /// If the mapping already exists, the existing mapping will be + /// silently overwritten with the new mapping. + ///

+ ///
+ /// + /// The protocol to add (or override). + /// + /// + /// The concrete implementation of the + /// interface that will handle + /// the specified protocol. + /// + /// + /// If the supplied is + /// or contains only whitespace character(s); or + /// if the supplied is + /// . + /// + /// + /// If the supplied is not a + /// that derives from the + /// interface; or (having passed + /// this first check), the supplied + /// does not expose a constructor that takes a single + /// parameter. + /// + public static void RegisterResourceHandler(string protocolName, Type handlerType) + { + #region Sanity Checks + + AssertUtils.ArgumentHasText(protocolName, "protocolName"); + AssertUtils.ArgumentNotNull(handlerType, "handlerType"); + if (!typeof(IResource).IsAssignableFrom(handlerType)) { - lock (syncRoot) + throw new ArgumentException( + string.Format("[{0}] does not implement [{1}] interface (it must).", handlerType.FullName, typeof(IResource).FullName)); + } + + #endregion + + lock (syncRoot) + { + Action callback = () => { - RegisterResourceHandler("config", typeof(ConfigSectionResource)); - RegisterResourceHandler("file", typeof(FileSystemResource)); - RegisterResourceHandler("http", typeof(UrlResource)); - RegisterResourceHandler("https", typeof(UrlResource)); - RegisterResourceHandler("ftp", typeof(UrlResource)); - RegisterResourceHandler("assembly", typeof(AssemblyResource)); - - // register custom resource handlers - ConfigurationUtils.GetSection(ResourcesSectionName); - } - } - - /// - /// Returns resource handler for the specified protocol name. - /// - /// - /// - /// This method returns object that should be used - /// to create an instance of the -derived type by passing - /// resource location as a parameter. - /// - /// - /// Name of the protocol to get the handler for. - /// Resource handler constructor for the specified protocol name. - /// If is null. - public static IDynamicConstructor GetResourceHandler(string protocolName) - { - AssertUtils.ArgumentNotNull(protocolName, "protocolName"); - IDynamicConstructor constructor; - resourceHandlers.TryGetValue(protocolName, out constructor); - return constructor; - } - - /// - /// Returns true if a handler is registered for the specified protocol, - /// false otherwise. - /// - /// Name of the protocol. - /// - /// true if a handler is registered for the specified protocol, false otherwise. - /// - /// If is null. - public static bool IsHandlerRegistered(string protocolName) - { - return resourceHandlers.ContainsKey(protocolName); - } - - /// - /// Registers resource handler and maps it to the specified protocol name. - /// - /// - ///

- /// If the mapping already exists, the existing mapping will be - /// silently overwritten with the new mapping. - ///

- ///
- /// - /// The protocol to add (or override). - /// - /// - /// The type name of the concrete implementation of the - /// interface that will handle - /// the specified protocol. - /// - /// - /// If the supplied is - /// or contains only whitespace character(s); or - /// if the supplied is - /// . - /// - /// - /// If the supplied is not a - /// that derives from the - /// interface; or (having passed - /// this first check), the supplied - /// does not expose a constructor that takes a single - /// parameter. - /// - public static void RegisterResourceHandler(string protocolName, string handlerTypeName) - { - AssertUtils.ArgumentHasText(protocolName, "protocolName"); - AssertUtils.ArgumentHasText(handlerTypeName, "handlerTypeName"); - - Type handlerType = TypeResolutionUtils.ResolveType(handlerTypeName); - RegisterResourceHandler(protocolName, handlerType); - } - - /// - /// Registers resource handler and maps it to the specified protocol name. - /// - /// - ///

- /// If the mapping already exists, the existing mapping will be - /// silently overwritten with the new mapping. - ///

- ///
- /// - /// The protocol to add (or override). - /// - /// - /// The concrete implementation of the - /// interface that will handle - /// the specified protocol. - /// - /// - /// If the supplied is - /// or contains only whitespace character(s); or - /// if the supplied is - /// . - /// - /// - /// If the supplied is not a - /// that derives from the - /// interface; or (having passed - /// this first check), the supplied - /// does not expose a constructor that takes a single - /// parameter. - /// - public static void RegisterResourceHandler(string protocolName, Type handlerType) - { - #region Sanity Checks - - AssertUtils.ArgumentHasText(protocolName, "protocolName"); - AssertUtils.ArgumentNotNull(handlerType, "handlerType"); - if (!typeof(IResource).IsAssignableFrom(handlerType)) - { - throw new ArgumentException( - string.Format("[{0}] does not implement [{1}] interface (it must).", handlerType.FullName, typeof(IResource).FullName)); - } - - #endregion - - lock (syncRoot) - { - Action callback = () => + // register generic uri parser for this scheme + if (!UriParser.IsKnownScheme(protocolName)) { - // register generic uri parser for this scheme - if (!UriParser.IsKnownScheme(protocolName)) - { - UriParser.Register(new TolerantUriParser(), protocolName, 0); - } - }; + UriParser.Register(new TolerantUriParser(), protocolName, 0); + } + }; #if NETSTANDARD callback(); #else - SecurityCritical.ExecutePrivileged(new System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityPermissionFlag.Infrastructure), callback); + SecurityCritical.ExecutePrivileged(new System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityPermissionFlag.Infrastructure), callback); #endif - IDynamicConstructor ctor = GetResourceConstructor(handlerType); - resourceHandlers[protocolName] = ctor; - } - } - - /// - /// Allows to create any arbitrary Url format - /// - private class TolerantUriParser : GenericUriParser - { - private const GenericUriParserOptions DefaultOptions = GenericUriParserOptions.Default - | GenericUriParserOptions.GenericAuthority - | GenericUriParserOptions.AllowEmptyAuthority; - - public TolerantUriParser() - : base(DefaultOptions) - { } - } - - private static IDynamicConstructor GetResourceConstructor(Type handlerType) - { - ConstructorInfo ctor = handlerType.GetConstructor(new Type[] { typeof(string) }); - if (ctor == null) - { - throw new ArgumentException( - string.Format("[{0}] does not have a constructor that takes a single string as an argument (it must).", handlerType.FullName)); - } - return new SafeConstructor(ctor); + IDynamicConstructor ctor = GetResourceConstructor(handlerType); + resourceHandlers[protocolName] = ctor; } } -} + + /// + /// Allows to create any arbitrary Url format + /// + private class TolerantUriParser : GenericUriParser + { + private const GenericUriParserOptions DefaultOptions = GenericUriParserOptions.Default + | GenericUriParserOptions.GenericAuthority + | GenericUriParserOptions.AllowEmptyAuthority; + + public TolerantUriParser() + : base(DefaultOptions) + { + } + } + + private static IDynamicConstructor GetResourceConstructor(Type handlerType) + { + ConstructorInfo ctor = handlerType.GetConstructor(new Type[] { typeof(string) }); + if (ctor == null) + { + throw new ArgumentException( + string.Format("[{0}] does not have a constructor that takes a single string as an argument (it must).", handlerType.FullName)); + } + + return new SafeConstructor(ctor); + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Core/IO/StringResource.cs b/src/Spring/Spring.Core/Core/IO/StringResource.cs index 14472963..1d075122 100644 --- a/src/Spring/Spring.Core/Core/IO/StringResource.cs +++ b/src/Spring/Spring.Core/Core/IO/StringResource.cs @@ -21,109 +21,107 @@ #region Imports using System.Text; - using Spring.Util; #endregion -namespace Spring.Core.IO +namespace Spring.Core.IO; + +/// +/// A adapter implementation encapsulating a simple string. +/// +/// Erich Eichinger +public class StringResource : AbstractResource { + #region Fields + + private readonly string _description; + private readonly string _content; + private readonly Encoding _encoding; + + #endregion + /// - /// A adapter implementation encapsulating a simple string. + /// Creates a new instance of the class. /// - /// Erich Eichinger - public class StringResource : AbstractResource + public StringResource(string content) + : this(content, Encoding.Default, null) { - #region Fields + } - private readonly string _description; - private readonly string _content; - private readonly Encoding _encoding; + /// + /// Creates a new instance of the class. + /// + public StringResource(string content, Encoding encoding) + : this(content, encoding, null) + { + } - #endregion + /// + /// Creates a new instance of the class. + /// + public StringResource(string content, Encoding encoding, string description) + { + AssertUtils.ArgumentNotNull(encoding, "encoding"); - /// - /// Creates a new instance of the class. - /// - public StringResource(string content) - : this(content, Encoding.Default, null) - { - } + _content = content == null ? string.Empty : content; + _encoding = encoding; + _description = description == null ? string.Empty : description; + } - /// - /// Creates a new instance of the class. - /// - public StringResource(string content, Encoding encoding) - : this(content, encoding, null) + /// + /// Get the to + /// for accessing this resource. + /// + public override Stream InputStream + { + get { - } - - /// - /// Creates a new instance of the class. - /// - public StringResource(string content, Encoding encoding, string description) - { - AssertUtils.ArgumentNotNull(encoding, "encoding"); - - _content = content==null ? string.Empty : content; - _encoding = encoding; - _description = description == null ? string.Empty : description; - } - - /// - /// Get the to - /// for accessing this resource. - /// - public override Stream InputStream - { - get - { - return new MemoryStream(_encoding.GetBytes(_content), false); - } - } - - /// - /// Returns a description for this resource. - /// - /// - /// A description for this resource. - /// - /// - public override string Description - { - get { return _description; } - } - - /// - /// This implementation always returns true - /// - public override bool IsOpen - { - get { return true; } - } - - /// - /// This implemementation always returns true - /// - public override bool Exists - { - get { return true; } - } - - /// - /// Gets the encoding used to create a byte stream of the string. - /// - public Encoding Encoding - { - get { return _encoding; } - } - - /// - /// Gets the content encapsulated by this . - /// - public string Content - { - get { return _content; } + return new MemoryStream(_encoding.GetBytes(_content), false); } } + + /// + /// Returns a description for this resource. + /// + /// + /// A description for this resource. + /// + /// + public override string Description + { + get { return _description; } + } + + /// + /// This implementation always returns true + /// + public override bool IsOpen + { + get { return true; } + } + + /// + /// This implemementation always returns true + /// + public override bool Exists + { + get { return true; } + } + + /// + /// Gets the encoding used to create a byte stream of the string. + /// + public Encoding Encoding + { + get { return _encoding; } + } + + /// + /// Gets the content encapsulated by this . + /// + public string Content + { + get { return _content; } + } } diff --git a/src/Spring/Spring.Core/Core/IO/UrlResource.cs b/src/Spring/Spring.Core/Core/IO/UrlResource.cs index 93e22fd3..b02b284a 100644 --- a/src/Spring/Spring.Core/Core/IO/UrlResource.cs +++ b/src/Spring/Spring.Core/Core/IO/UrlResource.cs @@ -25,247 +25,249 @@ using Spring.Util; #endregion -namespace Spring.Core.IO -{ - /// - /// A backed resource - /// on top of - /// - /// - ///

- /// Obviously supports resolution as a , and also - /// as a in the case of the "file:" - /// protocol. - ///

- ///
- /// - ///

- /// Some examples of the strings that can be used to initialize a new - /// instance of the class - /// include... - /// - /// - /// file:///Config/objects.xml - /// - /// - /// http://www.mycompany.com/services.txt - /// - /// - ///

- ///
- /// Juergen Hoeller - /// Leonardo Susatyo (.NET) - /// Aleksandar Seovic (.NET) - /// - /// - /// - public class UrlResource : AbstractResource - { - private Uri _uri; - private WebRequest _webRequest; - private string _rootLocation; - private string _resourcePath; +namespace Spring.Core.IO; - /// - /// Creates a new instance of the - /// class. - /// - /// - ///

- /// Some examples of the values that the - /// can typically be expected to hold include... - /// - /// - /// file:///Config/objects.xml - /// - /// - /// http://www.mycompany.com/services.txt - /// - /// - ///

- ///
- /// - /// A string representation of the resource. - /// - public UrlResource(string resourceName) : base(resourceName) - { - if (resourceName.StartsWith("file:///")) +/// +/// A backed resource +/// on top of +/// +/// +///

+/// Obviously supports resolution as a , and also +/// as a in the case of the "file:" +/// protocol. +///

+///
+/// +///

+/// Some examples of the strings that can be used to initialize a new +/// instance of the class +/// include... +/// +/// +/// file:///Config/objects.xml +/// +/// +/// http://www.mycompany.com/services.txt +/// +/// +///

+///
+/// Juergen Hoeller +/// Leonardo Susatyo (.NET) +/// Aleksandar Seovic (.NET) +/// +/// +/// +public class UrlResource : AbstractResource +{ + private Uri _uri; + private WebRequest _webRequest; + private string _rootLocation; + private string _resourcePath; + + /// + /// Creates a new instance of the + /// class. + /// + /// + ///

+ /// Some examples of the values that the + /// can typically be expected to hold include... + /// + /// + /// file:///Config/objects.xml + /// + /// + /// http://www.mycompany.com/services.txt + /// + /// + ///

+ ///
+ /// + /// A string representation of the resource. + /// + public UrlResource(string resourceName) : base(resourceName) + { + if (resourceName.StartsWith("file:///")) + { + resourceName = resourceName.Substring("file:///".Length); + } + + this._uri = new Uri(resourceName); + _rootLocation = _uri.Host; + if (!_uri.IsDefaultPort) + { + _rootLocation += ":" + _uri.Port; + } + + _resourcePath = _uri.AbsolutePath; + int n = _resourcePath.LastIndexOf('/'); + if (n > 0) + { + _resourcePath = _resourcePath.Substring(1, n - 1); + } + else + { + _resourcePath = null; + } + + _webRequest = WebRequest.Create(_uri); + } + + /// + /// Returns the instance + /// used for the resource resolution. + /// + /// + /// A instance. + /// + /// + /// + public WebRequest WebRequest + { + get { return _webRequest; } + } + + /// + /// Return an for this resource. + /// + /// + /// An . + /// + /// + /// If the stream could not be opened. + /// + /// + public override Stream InputStream + { + get { return _webRequest.GetResponse().GetResponseStream(); } + } + + /// + /// Returns the handle for this resource. + /// + /// + /// The handle for this resource. + /// + /// + /// If the resource is not available or cannot be exposed as a + /// . + /// + /// + public override Uri Uri + { + get { return _uri; } + } + + /// + /// Returns a handle for this resource. + /// + /// + /// The handle for this resource. + /// + /// + /// If the resource is not available on a filesystem. + /// + /// + public override FileInfo File + { + get + { + if (_uri.IsFile) { - resourceName = resourceName.Substring("file:///".Length); + return new FileInfo(_uri.AbsolutePath); } - this._uri = new Uri(resourceName); - _rootLocation = _uri.Host; - if (!_uri.IsDefaultPort) - { - _rootLocation += ":" + _uri.Port; - } - _resourcePath = _uri.AbsolutePath; - int n = _resourcePath.LastIndexOf('/'); - if (n > 0) - { - _resourcePath = _resourcePath.Substring(1, n - 1); - } - else - { - _resourcePath = null; - } - _webRequest = WebRequest.Create(_uri); - } - - /// - /// Returns the instance - /// used for the resource resolution. - /// - /// - /// A instance. - /// - /// - /// - public WebRequest WebRequest - { - get { return _webRequest; } + throw new FileNotFoundException(Description + + " cannot be resolved to absolute file path - " + + "resource does not use 'file:' protocol."); } + } - /// - /// Return an for this resource. - /// - /// - /// An . - /// - /// - /// If the stream could not be opened. - /// - /// - public override Stream InputStream - { - get { return _webRequest.GetResponse().GetResponseStream(); } - } + /// + /// Does this support relative + /// resource retrieval? + /// + /// + ///

+ /// This implementation does support relative resource retrieval, and + /// so will always return . + ///

+ ///
+ /// + /// if this + /// supports relative resource + /// retrieval. + /// + /// + protected override bool SupportsRelativeResources + { + get { return true; } + } - /// - /// Returns the handle for this resource. - /// - /// - /// The handle for this resource. - /// - /// - /// If the resource is not available or cannot be exposed as a - /// . - /// - /// - public override Uri Uri - { - get { return _uri; } - } + /// + /// Gets the root location of the resource. + /// + /// + /// The root location of the resource. + /// + /// + protected override string RootLocation + { + get { return _rootLocation; } + } - /// - /// Returns a handle for this resource. - /// - /// - /// The handle for this resource. - /// - /// - /// If the resource is not available on a filesystem. - /// - /// - public override FileInfo File - { - get - { - if (_uri.IsFile) - { - return new FileInfo(_uri.AbsolutePath); - } - throw new FileNotFoundException(Description + - " cannot be resolved to absolute file path - " + - "resource does not use 'file:' protocol." ); - } - } + /// + /// Gets the current path of the resource. + /// + /// + /// The current path of the resource. + /// + /// + protected override string ResourcePath + { + get { return _resourcePath; } + } - /// - /// Does this support relative - /// resource retrieval? - /// - /// - ///

- /// This implementation does support relative resource retrieval, and - /// so will always return . - ///

- ///
- /// - /// if this - /// supports relative resource - /// retrieval. - /// - /// - protected override bool SupportsRelativeResources - { - get { return true; } - } + /// + /// Gets those characters that are valid path separators for the + /// resource type. + /// + /// + /// Those characters that are valid path separators for the resource + /// type. + /// + /// + protected override char[] PathSeparatorChars + { + get { return new char[] { '/' }; } + } - /// - /// Gets the root location of the resource. - /// - /// - /// The root location of the resource. - /// - /// - protected override string RootLocation - { - get { return _rootLocation; } - } + /// + /// Returns a description for this resource. + /// + /// + /// A description for this resource. + /// + /// + public override string Description + { + get { return StringUtils.Surround("URL [", Uri, "]"); } + } - /// - /// Gets the current path of the resource. - /// - /// - /// The current path of the resource. - /// - /// - protected override string ResourcePath - { - get { return _resourcePath; } - } - - /// - /// Gets those characters that are valid path separators for the - /// resource type. - /// - /// - /// Those characters that are valid path separators for the resource - /// type. - /// - /// - protected override char[] PathSeparatorChars - { - get { return new char[] {'/'}; } - } - - /// - /// Returns a description for this resource. - /// - /// - /// A description for this resource. - /// - /// - public override string Description - { - get { return StringUtils.Surround("URL [", Uri, "]"); } - } - - /// - /// Does the supplied relative ? - /// - /// - /// The name of the resource to test. - /// - /// - /// if resource name is relative; - /// otherwise . - /// - protected override bool IsRelativeResource(string resourceName) - { - return true; - } - } + /// + /// Does the supplied relative ? + /// + /// + /// The name of the resource to test. + /// + /// + /// if resource name is relative; + /// otherwise . + /// + protected override bool IsRelativeResource(string resourceName) + { + return true; + } } diff --git a/src/Spring/Spring.Core/Core/IOrdered.cs b/src/Spring/Spring.Core/Core/IOrdered.cs index a16bb463..8466b3aa 100644 --- a/src/Spring/Spring.Core/Core/IOrdered.cs +++ b/src/Spring/Spring.Core/Core/IOrdered.cs @@ -1,14 +1,14 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. - * + * Copyright � 2002-2011 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. @@ -20,46 +20,42 @@ #region Imports - - #endregion -namespace Spring.Core -{ - /// - /// Interface that can be implemented by objects that should be orderable, e.g. in an - /// . - /// - /// - ///

- /// The actual order can be interpreted as prioritization, the first object (with the - /// lowest order value) having the highest priority. - ///

- ///
- /// Juergen Hoeller - /// Aleksandar Seovic (.Net) - public interface IOrdered - { +namespace Spring.Core; - /// - /// Return the order value of this object, where a higher value means greater in - /// terms of sorting. - /// - /// - ///

- /// Normally starting with 0 or 1, with indicating - /// greatest. Same order values will result in arbitrary positions for the affected - /// objects. - ///

- ///

- /// Higher value can be interpreted as lower priority, consequently the first object - /// has highest priority. - ///

- ///
- /// The order value. - int Order - { - get; - } - } -} \ No newline at end of file +/// +/// Interface that can be implemented by objects that should be orderable, e.g. in an +/// . +/// +/// +///

+/// The actual order can be interpreted as prioritization, the first object (with the +/// lowest order value) having the highest priority. +///

+///
+/// Juergen Hoeller +/// Aleksandar Seovic (.Net) +public interface IOrdered +{ + /// + /// Return the order value of this object, where a higher value means greater in + /// terms of sorting. + /// + /// + ///

+ /// Normally starting with 0 or 1, with indicating + /// greatest. Same order values will result in arbitrary positions for the affected + /// objects. + ///

+ ///

+ /// Higher value can be interpreted as lower priority, consequently the first object + /// has highest priority. + ///

+ ///
+ /// The order value. + int Order + { + get; + } +} diff --git a/src/Spring/Spring.Core/Core/IPriorityOrdered.cs b/src/Spring/Spring.Core/Core/IPriorityOrdered.cs index 851ee04d..06d29313 100644 --- a/src/Spring/Spring.Core/Core/IPriorityOrdered.cs +++ b/src/Spring/Spring.Core/Core/IPriorityOrdered.cs @@ -21,29 +21,28 @@ using Spring.Context; using Spring.Objects.Factory.Config; -namespace Spring.Core +namespace Spring.Core; + +/// +/// Extension of the interface, expressing a 'priority' +/// ordering: Order values expressed by IPriorityOrdered objects always +/// apply before order values of 'plain' Ordered values. +/// +/// +/// This is primarily a special-purpose interface, used for objects +/// where it is particularly important to determine 'prioritized' +/// objects first, without even obtaining the remaining objects. +/// A typical example: Prioritized post-processors in a Spring +/// +/// +/// IPriorityOrdered post-processor objects are initialized in +/// a special phase, ahead of other post-processor objects. +/// +/// Juergen Hoeller +/// Mark Pollack (.NET) +/// +/// +/// +public interface IPriorityOrdered : IOrdered { - /// - /// Extension of the interface, expressing a 'priority' - /// ordering: Order values expressed by IPriorityOrdered objects always - /// apply before order values of 'plain' Ordered values. - /// - /// - /// This is primarily a special-purpose interface, used for objects - /// where it is particularly important to determine 'prioritized' - /// objects first, without even obtaining the remaining objects. - /// A typical example: Prioritized post-processors in a Spring - /// - /// - /// IPriorityOrdered post-processor objects are initialized in - /// a special phase, ahead of other post-processor objects. - /// - /// Juergen Hoeller - /// Mark Pollack (.NET) - /// - /// - /// - public interface IPriorityOrdered : IOrdered - { - } -} \ No newline at end of file +} diff --git a/src/Spring/Spring.Core/Core/InvalidPropertyException.cs b/src/Spring/Spring.Core/Core/InvalidPropertyException.cs index a919e4bf..91f36a67 100644 --- a/src/Spring/Spring.Core/Core/InvalidPropertyException.cs +++ b/src/Spring/Spring.Core/Core/InvalidPropertyException.cs @@ -19,171 +19,170 @@ using System.Runtime.Serialization; using System.Security.Permissions; using Spring.Util; -namespace Spring.Core +namespace Spring.Core; + +/// +/// Thrown in response to referring to an invalid property (most often via reflection). +/// +/// Rick Evans +[Serializable] +public class InvalidPropertyException : FatalReflectionException { /// - /// Thrown in response to referring to an invalid property (most often via reflection). + /// Creates a new instance of the + /// class. /// - /// Rick Evans - [Serializable] - public class InvalidPropertyException : FatalReflectionException + public InvalidPropertyException() { - /// - /// Creates a new instance of the - /// class. - /// - public InvalidPropertyException() - { - } - - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - public InvalidPropertyException(string message) : base(message) - { - } - - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The that is (or rather was) the source of the - /// offending property. - /// - /// - /// The name of the offending property. - /// - public InvalidPropertyException(Type type, string propertyName) - : this(type, propertyName, string.Format( - CultureInfo.InvariantCulture, - "Invalid property '{0}' in class [{1}].", propertyName, type.FullName)) - { - } - - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The that is (or rather was) the source of the - /// offending property. - /// - /// - /// The name of the offending property. - /// - /// - /// A message about the exception. - /// - public InvalidPropertyException(Type type, string propertyName, string message) - : base(message) - { - offendingObjectType = type; - offendingPropertyName = propertyName; - } - - /// - /// Creates a new instance of the InvalidPropertyException class. - /// - /// - /// The that is (or rather was) the source of the - /// offending property. - /// - /// - /// The name of the offending property. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception that is being wrapped. - /// - public InvalidPropertyException ( - Type offendingType, string offendingProperty, string message, Exception rootCause) - : base (message, rootCause) - { - offendingObjectType = offendingType; - offendingPropertyName = offendingProperty; - } - - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception that is being wrapped. - /// - public InvalidPropertyException(string message, Exception rootCause) - : base(message, rootCause) - { - } - - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The - /// that holds the serialized object data about the exception being thrown. - /// - /// - /// The - /// that contains contextual information about the source or destination. - /// - protected InvalidPropertyException(SerializationInfo info, StreamingContext context) - : base(info, context) - { - var typeName = info.GetString("ObjectTypeName"); - offendingObjectType = typeName != null ? Type.GetType(typeName) : null; - offendingPropertyName = info.GetString("OffendingPropertyName"); - } - - /// - /// The that is (or rather was) the source of the - /// offending property. - /// - public Type ObjectType - { - get { return offendingObjectType; } - } - - /// - /// The name of the offending property. - /// - public string OffendingPropertyName - { - get { return offendingPropertyName; } - } - - /// - /// Populates a with - /// the data needed to serialize the target object. - /// - /// - /// The to populate - /// with data. - /// - /// - /// The destination (see ) - /// for this serialization. - /// - [SecurityPermission(SecurityAction.Demand, SerializationFormatter=true)] - public override void GetObjectData( - SerializationInfo info, StreamingContext context) - { - base.GetObjectData(info, context); - info.AddValue("ObjectTypeName", ObjectType?.AssemblyQualifiedNameWithoutVersion()); - info.AddValue("OffendingPropertyName", OffendingPropertyName); - } - - private Type offendingObjectType; - private string offendingPropertyName; } + + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + public InvalidPropertyException(string message) : base(message) + { + } + + /// + /// Creates a new instance of the + /// class. + /// + /// + /// The that is (or rather was) the source of the + /// offending property. + /// + /// + /// The name of the offending property. + /// + public InvalidPropertyException(Type type, string propertyName) + : this(type, propertyName, string.Format( + CultureInfo.InvariantCulture, + "Invalid property '{0}' in class [{1}].", propertyName, type.FullName)) + { + } + + /// + /// Creates a new instance of the + /// class. + /// + /// + /// The that is (or rather was) the source of the + /// offending property. + /// + /// + /// The name of the offending property. + /// + /// + /// A message about the exception. + /// + public InvalidPropertyException(Type type, string propertyName, string message) + : base(message) + { + offendingObjectType = type; + offendingPropertyName = propertyName; + } + + /// + /// Creates a new instance of the InvalidPropertyException class. + /// + /// + /// The that is (or rather was) the source of the + /// offending property. + /// + /// + /// The name of the offending property. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception that is being wrapped. + /// + public InvalidPropertyException( + Type offendingType, string offendingProperty, string message, Exception rootCause) + : base(message, rootCause) + { + offendingObjectType = offendingType; + offendingPropertyName = offendingProperty; + } + + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception that is being wrapped. + /// + public InvalidPropertyException(string message, Exception rootCause) + : base(message, rootCause) + { + } + + /// + /// Creates a new instance of the + /// class. + /// + /// + /// The + /// that holds the serialized object data about the exception being thrown. + /// + /// + /// The + /// that contains contextual information about the source or destination. + /// + protected InvalidPropertyException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + var typeName = info.GetString("ObjectTypeName"); + offendingObjectType = typeName != null ? Type.GetType(typeName) : null; + offendingPropertyName = info.GetString("OffendingPropertyName"); + } + + /// + /// The that is (or rather was) the source of the + /// offending property. + /// + public Type ObjectType + { + get { return offendingObjectType; } + } + + /// + /// The name of the offending property. + /// + public string OffendingPropertyName + { + get { return offendingPropertyName; } + } + + /// + /// Populates a with + /// the data needed to serialize the target object. + /// + /// + /// The to populate + /// with data. + /// + /// + /// The destination (see ) + /// for this serialization. + /// + [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)] + public override void GetObjectData( + SerializationInfo info, StreamingContext context) + { + base.GetObjectData(info, context); + info.AddValue("ObjectTypeName", ObjectType?.AssemblyQualifiedNameWithoutVersion()); + info.AddValue("OffendingPropertyName", OffendingPropertyName); + } + + private Type offendingObjectType; + private string offendingPropertyName; } diff --git a/src/Spring/Spring.Core/Core/MethodArgumentsCriteria.cs b/src/Spring/Spring.Core/Core/MethodArgumentsCriteria.cs index 5d82af6b..ad99c64f 100644 --- a/src/Spring/Spring.Core/Core/MethodArgumentsCriteria.cs +++ b/src/Spring/Spring.Core/Core/MethodArgumentsCriteria.cs @@ -21,142 +21,118 @@ #region Imports using System.Reflection; - using Spring.Util; #endregion -namespace Spring.Core +namespace Spring.Core; + +/// +/// Criteria that is satisfied if the of each of the +/// arguments matches each of the parameter s of a given +/// . +/// +/// +///

+/// If no array is passed to the overloaded constructor, +/// any method that has no parameters will satisfy an instance of this +/// class. The same effect could be achieved by passing the +/// array to the overloaded constructor. +///

+///
+/// Rick Evans +/// Bruno Baia +public class MethodArgumentsCriteria : ICriteria { + #region Constructor (s) / Destructor + /// - /// Criteria that is satisfied if the of each of the - /// arguments matches each of the parameter s of a given - /// . + /// Creates a new instance of the + /// class. + /// + public MethodArgumentsCriteria() : this(ObjectUtils.EmptyObjects) + { + } + + /// + /// Creates a new instance of the + /// class. /// /// ///

- /// If no array is passed to the overloaded constructor, - /// any method that has no parameters will satisfy an instance of this - /// class. The same effect could be achieved by passing the - /// array to the overloaded constructor. + /// If the supplied array is null, then this + /// constructor uses the array. ///

///
- /// Rick Evans - /// Bruno Baia - public class MethodArgumentsCriteria : ICriteria + /// + /// The array that this criteria will use to + /// check parameter s. + /// + public MethodArgumentsCriteria(object[] arguments) { - #region Constructor (s) / Destructor + _parameters = ReflectionUtils.GetTypes(arguments); + } - /// - /// Creates a new instance of the - /// class. - /// - public MethodArgumentsCriteria() : this(ObjectUtils.EmptyObjects) + #endregion + + #region Methods + + /// + /// Does the supplied satisfy the criteria encapsulated by + /// this instance? + /// + /// + ///

+ /// This implementation respects the inheritance chain of any parameter + /// s... i.e. methods that have a base type (or + /// interface) that is assignable to the in the + /// same corresponding index of the parameter types will satisfy this + /// criteria instance. + ///

+ ///
+ /// The datum to be checked by this criteria instance. + /// + /// True if the supplied satisfies the criteria encapsulated + /// by this instance; false if not or the supplied is null. + /// + public bool IsSatisfied(object datum) + { + bool satisfied = false; + MethodInfo method = datum as MethodInfo; + if (method != null) { - } - - /// - /// Creates a new instance of the - /// class. - /// - /// - ///

- /// If the supplied array is null, then this - /// constructor uses the array. - ///

- ///
- /// - /// The array that this criteria will use to - /// check parameter s. - /// - public MethodArgumentsCriteria(object[] arguments) - { - _parameters = ReflectionUtils.GetTypes(arguments); - } - - #endregion - - #region Methods - - /// - /// Does the supplied satisfy the criteria encapsulated by - /// this instance? - /// - /// - ///

- /// This implementation respects the inheritance chain of any parameter - /// s... i.e. methods that have a base type (or - /// interface) that is assignable to the in the - /// same corresponding index of the parameter types will satisfy this - /// criteria instance. - ///

- ///
- /// The datum to be checked by this criteria instance. - /// - /// True if the supplied satisfies the criteria encapsulated - /// by this instance; false if not or the supplied is null. - /// - public bool IsSatisfied(object datum) - { - bool satisfied = false; - MethodInfo method = datum as MethodInfo; - if (method != null) + bool isParamArray = false; + Type paramArrayType = null; + ParameterInfo[] parametersBeingChecked = method.GetParameters(); + if (parametersBeingChecked.Length > 0) { - bool isParamArray = false; - Type paramArrayType = null; - ParameterInfo[] parametersBeingChecked = method.GetParameters(); - if (parametersBeingChecked.Length > 0) + ParameterInfo lastParameter = parametersBeingChecked[parametersBeingChecked.Length - 1]; + isParamArray = lastParameter.GetCustomAttributes(typeof(ParamArrayAttribute), false).Length > 0; + if (isParamArray) { - ParameterInfo lastParameter = parametersBeingChecked[parametersBeingChecked.Length - 1]; - isParamArray = lastParameter.GetCustomAttributes(typeof(ParamArrayAttribute), false).Length > 0; - if (isParamArray) - { - paramArrayType = lastParameter.ParameterType.GetElementType(); - } + paramArrayType = lastParameter.ParameterType.GetElementType(); } - if (parametersBeingChecked != null - && parametersBeingChecked.Length == _parameters.Length) + } + + if (parametersBeingChecked != null + && parametersBeingChecked.Length == _parameters.Length) + { + satisfied = true; + for (int i = 0; i < _parameters.Length; ++i) { - satisfied = true; - for (int i = 0; i < _parameters.Length; ++i) + Type sourceType = _parameters[i]; + Type typeBeingChecked = parametersBeingChecked[i].ParameterType; + if (!typeBeingChecked.IsAssignableFrom(sourceType)) { - Type sourceType = _parameters[i]; - Type typeBeingChecked = parametersBeingChecked[i].ParameterType; - if (!typeBeingChecked.IsAssignableFrom(sourceType)) + if (isParamArray && i == _parameters.Length - 1) { - if (isParamArray && i == _parameters.Length - 1) - { - if (!paramArrayType.IsAssignableFrom(sourceType)) - { - satisfied = false; - break; - } - } - else + if (!paramArrayType.IsAssignableFrom(sourceType)) { satisfied = false; break; } } - } - } - else if (isParamArray && (_parameters.Length >= parametersBeingChecked.Length - 1)) - { - satisfied = true; - for (int i = 0; i < parametersBeingChecked.Length - 1; ++i) - { - Type sourceType = _parameters[i]; - Type typeBeingChecked = parametersBeingChecked[i].ParameterType; - if (!typeBeingChecked.IsAssignableFrom(sourceType)) - { - satisfied = false; - break; - } - } - for (int i = parametersBeingChecked.Length - 1; i < _parameters.Length; ++i) - { - Type sourceType = _parameters[i]; - if (!paramArrayType.IsAssignableFrom(sourceType)) + else { satisfied = false; break; @@ -164,15 +140,40 @@ namespace Spring.Core } } } - return satisfied; + else if (isParamArray && (_parameters.Length >= parametersBeingChecked.Length - 1)) + { + satisfied = true; + for (int i = 0; i < parametersBeingChecked.Length - 1; ++i) + { + Type sourceType = _parameters[i]; + Type typeBeingChecked = parametersBeingChecked[i].ParameterType; + if (!typeBeingChecked.IsAssignableFrom(sourceType)) + { + satisfied = false; + break; + } + } + + for (int i = parametersBeingChecked.Length - 1; i < _parameters.Length; ++i) + { + Type sourceType = _parameters[i]; + if (!paramArrayType.IsAssignableFrom(sourceType)) + { + satisfied = false; + break; + } + } + } } - #endregion - - #region Fields - - private readonly Type[] _parameters; - - #endregion + return satisfied; } + + #endregion + + #region Fields + + private readonly Type[] _parameters; + + #endregion } diff --git a/src/Spring/Spring.Core/Core/MethodGenericArgumentsCountCriteria.cs b/src/Spring/Spring.Core/Core/MethodGenericArgumentsCountCriteria.cs index fee66065..ce548667 100644 --- a/src/Spring/Spring.Core/Core/MethodGenericArgumentsCountCriteria.cs +++ b/src/Spring/Spring.Core/Core/MethodGenericArgumentsCountCriteria.cs @@ -24,110 +24,111 @@ using System.Reflection; #endregion -namespace Spring.Core +namespace Spring.Core; + +/// +/// Criteria that is satisfied if the number of generic arguments to a given +/// matches an arbitrary number. +/// +/// +///

+/// This class supports checking the generic arguments count of both +/// generic methods and constructors. +///

+///
+/// Bruno Baia +public class MethodGenericArgumentsCountCriteria : ICriteria { + #region Constructor (s) / Destructor + /// - /// Criteria that is satisfied if the number of generic arguments to a given - /// matches an arbitrary number. + /// Creates a new instance of the + /// class. /// /// ///

- /// This class supports checking the generic arguments count of both - /// generic methods and constructors. + /// This constructor sets the + /// + /// property to zero (0). ///

///
- /// Bruno Baia - public class MethodGenericArgumentsCountCriteria : ICriteria + public MethodGenericArgumentsCountCriteria() : this(0) { - #region Constructor (s) / Destructor - - /// - /// Creates a new instance of the - /// class. - /// - /// - ///

- /// This constructor sets the - /// - /// property to zero (0). - ///

- ///
- public MethodGenericArgumentsCountCriteria() : this(0) - { - } - - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The number of generic arguments that a - /// must have to satisfy this criteria. - /// - /// - /// If the supplied is less - /// than zero. - /// - public MethodGenericArgumentsCountCriteria(int expectedGenericArgumentCount) - { - ExpectedGenericArgumentCount = expectedGenericArgumentCount; - } - - #endregion - - #region Properties - - /// - /// The number of generic arguments that a - /// must have to satisfy this criteria. - /// - /// - /// If the supplied value is less than zero. - /// - public int ExpectedGenericArgumentCount - { - get { return _count; } - set - { - if (value < 0) - { - throw new ArgumentOutOfRangeException( - "value", value, "Cannot specify a generic argument count of less than zero."); - } - _count = value; - } - } - - #endregion - - #region Methods - - /// - /// Does the supplied satisfy the criteria encapsulated by - /// this instance? - /// - /// The datum to be checked by this criteria instance. - /// - /// True if the supplied satisfies the criteria encapsulated - /// by this instance; false if not or the supplied is null. - /// - public bool IsSatisfied(object datum) - { - bool satisfied = false; - MethodBase method = datum as MethodBase; - if (method != null) - { - satisfied = method.GetGenericArguments().Length == ExpectedGenericArgumentCount; - } - return satisfied; - } - - #endregion - - #region Fields - - private int _count; - - #endregion } -} + + /// + /// Creates a new instance of the + /// class. + /// + /// + /// The number of generic arguments that a + /// must have to satisfy this criteria. + /// + /// + /// If the supplied is less + /// than zero. + /// + public MethodGenericArgumentsCountCriteria(int expectedGenericArgumentCount) + { + ExpectedGenericArgumentCount = expectedGenericArgumentCount; + } + + #endregion + + #region Properties + + /// + /// The number of generic arguments that a + /// must have to satisfy this criteria. + /// + /// + /// If the supplied value is less than zero. + /// + public int ExpectedGenericArgumentCount + { + get { return _count; } + set + { + if (value < 0) + { + throw new ArgumentOutOfRangeException( + "value", value, "Cannot specify a generic argument count of less than zero."); + } + + _count = value; + } + } + + #endregion + + #region Methods + + /// + /// Does the supplied satisfy the criteria encapsulated by + /// this instance? + /// + /// The datum to be checked by this criteria instance. + /// + /// True if the supplied satisfies the criteria encapsulated + /// by this instance; false if not or the supplied is null. + /// + public bool IsSatisfied(object datum) + { + bool satisfied = false; + MethodBase method = datum as MethodBase; + if (method != null) + { + satisfied = method.GetGenericArguments().Length == ExpectedGenericArgumentCount; + } + + return satisfied; + } + + #endregion + + #region Fields + + private int _count; + + #endregion +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Core/MethodInvocationException.cs b/src/Spring/Spring.Core/Core/MethodInvocationException.cs index 3f682561..59ce0bfc 100644 --- a/src/Spring/Spring.Core/Core/MethodInvocationException.cs +++ b/src/Spring/Spring.Core/Core/MethodInvocationException.cs @@ -24,93 +24,94 @@ using System.Runtime.Serialization; #endregion -namespace Spring.Core +namespace Spring.Core; + +/// +/// Thrown when a method (typically a property getter or setter invoked via reflection) +/// throws an exception, analogous to a . +/// +/// Rod Johnson +/// Mark Pollack (.NET) +[Serializable] +public class MethodInvocationException : PropertyAccessException { /// - /// Thrown when a method (typically a property getter or setter invoked via reflection) - /// throws an exception, analogous to a . + /// The error code string for this exception. /// - /// Rod Johnson - /// Mark Pollack (.NET) - [Serializable] - public class MethodInvocationException : PropertyAccessException + override public string ErrorCode { - /// - /// The error code string for this exception. - /// - override public string ErrorCode + get { - get - { - return "methodInvocation"; - } + return "methodInvocation"; } - - #region Constructor (s) / Destructor - /// - /// Creates a new instance of the MethodInvocationException class. - /// - public MethodInvocationException () - { - } - - /// - /// Creates a new instance of the MethodInvocationException class. - /// - /// - /// A message about the exception. - /// - public MethodInvocationException (string message) - : base (message) - { - } - - /// - /// Creates a new instance of the MethodInvocationException class. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception that is being wrapped. - /// - public MethodInvocationException (string message, Exception rootCause) - : base (message, rootCause) - { - } - - /// - /// Constructor to use when an exception results from a - /// . - /// - /// - /// The raised by the invoked property. - /// - /// - /// The that - /// resulted in an exception. - /// - public MethodInvocationException (Exception ex, PropertyChangeEventArgs argument) : - base ("Property '" + argument.PropertyName + "' threw exception.", argument, ex) - { - } - - /// - /// Creates a new instance of the MethodInvocationException class. - /// - /// - /// The - /// that holds the serialized object data about the exception being thrown. - /// - /// - /// The - /// that contains contextual information about the source or destination. - /// - protected MethodInvocationException ( - SerializationInfo info, StreamingContext context) - : base (info, context) - { - } - #endregion } + + #region Constructor (s) / Destructor + + /// + /// Creates a new instance of the MethodInvocationException class. + /// + public MethodInvocationException() + { + } + + /// + /// Creates a new instance of the MethodInvocationException class. + /// + /// + /// A message about the exception. + /// + public MethodInvocationException(string message) + : base(message) + { + } + + /// + /// Creates a new instance of the MethodInvocationException class. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception that is being wrapped. + /// + public MethodInvocationException(string message, Exception rootCause) + : base(message, rootCause) + { + } + + /// + /// Constructor to use when an exception results from a + /// . + /// + /// + /// The raised by the invoked property. + /// + /// + /// The that + /// resulted in an exception. + /// + public MethodInvocationException(Exception ex, PropertyChangeEventArgs argument) : + base("Property '" + argument.PropertyName + "' threw exception.", argument, ex) + { + } + + /// + /// Creates a new instance of the MethodInvocationException class. + /// + /// + /// The + /// that holds the serialized object data about the exception being thrown. + /// + /// + /// The + /// that contains contextual information about the source or destination. + /// + protected MethodInvocationException( + SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + + #endregion } diff --git a/src/Spring/Spring.Core/Core/MethodNameMatchCriteria.cs b/src/Spring/Spring.Core/Core/MethodNameMatchCriteria.cs index 730b51a6..db1f87c8 100644 --- a/src/Spring/Spring.Core/Core/MethodNameMatchCriteria.cs +++ b/src/Spring/Spring.Core/Core/MethodNameMatchCriteria.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -21,109 +21,108 @@ #region Imports using System.Reflection; - using Spring.Util; #endregion -namespace Spring.Core +namespace Spring.Core; + +/// +/// Criteria that is satisfied if the method Name of an +/// instance matches a +/// supplied string pattern. +/// +/// +/// +/// Supports the following simple pattern styles: +/// "xxx*", "*xxx" and "*xxx*" matches, as well as direct equality. +/// +/// +/// Bruno Baia +public class MethodNameMatchCriteria : ICriteria { - /// - /// Criteria that is satisfied if the method Name of an - /// instance matches a - /// supplied string pattern. + #region Constructor (s) / Destructor + + /// + /// Creates a new instance of the + /// class. /// /// - /// - /// Supports the following simple pattern styles: - /// "xxx*", "*xxx" and "*xxx*" matches, as well as direct equality. - /// + ///

+ /// This constructor sets the + /// + /// property to * (any method name). + ///

///
- /// Bruno Baia - public class MethodNameMatchCriteria : ICriteria + public MethodNameMatchCriteria() : this("*") { - #region Constructor (s) / Destructor - - /// - /// Creates a new instance of the - /// class. - /// - /// - ///

- /// This constructor sets the - /// - /// property to * (any method name). - ///

- ///
- public MethodNameMatchCriteria() : this("*") - { - } - - /// - /// Creates a new instance of the - /// class. - /// - /// The pattern that names - /// must match against in order to satisfy this criteria. - /// - /// If the supplied is null or resolve to an empty string. - /// - public MethodNameMatchCriteria(string pattern) - { - Pattern = pattern; - } - - #endregion - - #region Properties - - /// - /// The number of parameters that a - /// must have to satisfy this criteria. - /// - /// - /// If the supplied value is null or resolve to an empty string. - /// - public string Pattern - { - get { return pattern; } - set - { - AssertUtils.ArgumentHasText(value, "value"); - pattern = value; - } - } - - #endregion - - #region Methods - - /// - /// Does the supplied satisfy the criteria encapsulated by - /// this instance? - /// - /// The datum to be checked by this criteria instance. - /// - /// True if the supplied satisfies the criteria encapsulated - /// by this instance; false if not or the supplied is null. - /// - public bool IsSatisfied(object datum) - { - bool satisfied = false; - MethodBase method = datum as MethodBase; - if (method != null) - { - satisfied = PatternMatchUtils.SimpleMatch(pattern.ToLower(), method.Name.ToLower()); - } - return satisfied; - } - - #endregion - - #region Fields - - private string pattern; - - #endregion } -} \ No newline at end of file + + /// + /// Creates a new instance of the + /// class. + /// + /// The pattern that names + /// must match against in order to satisfy this criteria. + /// + /// If the supplied is null or resolve to an empty string. + /// + public MethodNameMatchCriteria(string pattern) + { + Pattern = pattern; + } + + #endregion + + #region Properties + + /// + /// The number of parameters that a + /// must have to satisfy this criteria. + /// + /// + /// If the supplied value is null or resolve to an empty string. + /// + public string Pattern + { + get { return pattern; } + set + { + AssertUtils.ArgumentHasText(value, "value"); + pattern = value; + } + } + + #endregion + + #region Methods + + /// + /// Does the supplied satisfy the criteria encapsulated by + /// this instance? + /// + /// The datum to be checked by this criteria instance. + /// + /// True if the supplied satisfies the criteria encapsulated + /// by this instance; false if not or the supplied is null. + /// + public bool IsSatisfied(object datum) + { + bool satisfied = false; + MethodBase method = datum as MethodBase; + if (method != null) + { + satisfied = PatternMatchUtils.SimpleMatch(pattern.ToLower(), method.Name.ToLower()); + } + + return satisfied; + } + + #endregion + + #region Fields + + private string pattern; + + #endregion +} diff --git a/src/Spring/Spring.Core/Core/MethodParameter.cs b/src/Spring/Spring.Core/Core/MethodParameter.cs index 8fecfaeb..3f1d9505 100644 --- a/src/Spring/Spring.Core/Core/MethodParameter.cs +++ b/src/Spring/Spring.Core/Core/MethodParameter.cs @@ -21,149 +21,151 @@ using System.Reflection; using Spring.Util; -namespace Spring.Core +namespace Spring.Core; + +/// +/// Helper class that encapsulates the specification of a method parameter, i.e. +/// a MethodInfo or ConstructorInfo plus a parameter index. +/// Useful as a specification object to pass along. +/// +/// Juergen Hoeller +/// Rob Harrop +/// Mark Pollack (.NET) +public class MethodParameter { + private MethodInfo methodInfo; + + private ConstructorInfo constructorInfo; + + private readonly int parameterIndex; + + private Type parameterType; + /// - /// Helper class that encapsulates the specification of a method parameter, i.e. - /// a MethodInfo or ConstructorInfo plus a parameter index. - /// Useful as a specification object to pass along. + /// Initializes a new instance of the class for the given + /// MethodInfo. /// - /// Juergen Hoeller - /// Rob Harrop - /// Mark Pollack (.NET) - public class MethodParameter + /// The MethodInfo to specify a parameter for. + /// Index of the parameter. + public MethodParameter(MethodInfo methodInfo, int parameterIndex) { - private MethodInfo methodInfo; + this.methodInfo = methodInfo; + this.parameterIndex = parameterIndex; + } - private ConstructorInfo constructorInfo; + /// + /// Initializes a new instance of the class. + /// + /// The ConstructorInfo to specify a parameter for. + /// Index of the parameter. + public MethodParameter(ConstructorInfo constructorInfo, int parameterIndex) + { + this.constructorInfo = constructorInfo; + this.parameterIndex = parameterIndex; + } - private readonly int parameterIndex; - - private Type parameterType; - - /// - /// Initializes a new instance of the class for the given - /// MethodInfo. - /// - /// The MethodInfo to specify a parameter for. - /// Index of the parameter. - public MethodParameter(MethodInfo methodInfo, int parameterIndex) + /// + /// Gets the type of the method/constructor parameter. + /// + /// The type of the parameter. (never null) + public Type ParameterType + { + get { - this.methodInfo = methodInfo; - this.parameterIndex = parameterIndex; - } - - /// - /// Initializes a new instance of the class. - /// - /// The ConstructorInfo to specify a parameter for. - /// Index of the parameter. - public MethodParameter(ConstructorInfo constructorInfo, int parameterIndex) - { - this.constructorInfo = constructorInfo; - this.parameterIndex = parameterIndex; - } - - /// - /// Gets the type of the method/constructor parameter. - /// - /// The type of the parameter. (never null) - public Type ParameterType - { - get + if (this.parameterType == null) { - if (this.parameterType == null) - { - this.parameterType = (this.methodInfo != null - ? ReflectionUtils.GetParameterTypes(this.methodInfo.GetParameters())[parameterIndex] - : ReflectionUtils.GetParameterTypes(this.constructorInfo.GetParameters())[parameterIndex]); - } - return this.parameterType; + this.parameterType = (this.methodInfo != null + ? ReflectionUtils.GetParameterTypes(this.methodInfo.GetParameters())[parameterIndex] + : ReflectionUtils.GetParameterTypes(this.constructorInfo.GetParameters())[parameterIndex]); } - } - /// - /// Create a new MethodParameter for the given method or donstructor. - /// This is a convenience constructor for scenarios where a - /// Method or Constructor reference is treated in a generic fashion. - /// - /// The method or constructor to specify a parameter for. - /// Index of the parameter. - /// the corresponding MethodParameter instance - public static MethodParameter ForMethodOrConstructor(object methodOrConstructorInfo, int parameterIndex) + return this.parameterType; + } + } + + /// + /// Create a new MethodParameter for the given method or donstructor. + /// This is a convenience constructor for scenarios where a + /// Method or Constructor reference is treated in a generic fashion. + /// + /// The method or constructor to specify a parameter for. + /// Index of the parameter. + /// the corresponding MethodParameter instance + public static MethodParameter ForMethodOrConstructor(object methodOrConstructorInfo, int parameterIndex) + { + if (methodOrConstructorInfo is MethodInfo) { - if (methodOrConstructorInfo is MethodInfo) - { - return new MethodParameter((MethodInfo) methodOrConstructorInfo, parameterIndex); - } else if (methodOrConstructorInfo is ConstructorInfo) - { - return new MethodParameter((ConstructorInfo) methodOrConstructorInfo, parameterIndex); - } else - { - throw new ArgumentException("Given object [" + methodOrConstructorInfo + "] is nieth a MethodInfo nor a ConstructorInfo"); - } + return new MethodParameter((MethodInfo) methodOrConstructorInfo, parameterIndex); } + else if (methodOrConstructorInfo is ConstructorInfo) + { + return new MethodParameter((ConstructorInfo) methodOrConstructorInfo, parameterIndex); + } + else + { + throw new ArgumentException("Given object [" + methodOrConstructorInfo + "] is nieth a MethodInfo nor a ConstructorInfo"); + } + } - /// - /// Parameters the name of the method/constructor parameter. - /// - /// the parameter name. - public string ParameterName() + /// + /// Parameters the name of the method/constructor parameter. + /// + /// the parameter name. + public string ParameterName() + { + if (methodInfo != null) + { + return methodInfo.GetParameters()[parameterIndex].Name; + } + else + { + return constructorInfo.GetParameters()[parameterIndex].Name; + } + } + + /// + /// Gets the wrapped MethodInfo, if any. Note Either MethodInfo or ConstructorInfo is available. + /// + /// The MethodInfo, or null if none. + public MethodInfo MethodInfo + { + get { return methodInfo; } + } + + /// + /// Gets wrapped ConstructorInfo, if any. Note Either MethodInfo or ConstructorInfo is available. + /// + /// The ConstructorInfo, or null if none + public ConstructorInfo ConstructorInfo + { + get { return constructorInfo; } + } + + /// + /// Return the annotations associated with the specific method/constructor parameter. + /// + public Attribute[] ParameterAttributes + { + get { if (methodInfo != null) - { - return methodInfo.GetParameters()[parameterIndex].Name; - } else - { - return constructorInfo.GetParameters()[parameterIndex].Name; - } + return Attribute.GetCustomAttributes(methodInfo.GetParameters()[parameterIndex]); + else + return Attribute.GetCustomAttributes(constructorInfo.GetParameters()[parameterIndex]); } + } - /// - /// Gets the wrapped MethodInfo, if any. Note Either MethodInfo or ConstructorInfo is available. - /// - /// The MethodInfo, or null if none. - public MethodInfo MethodInfo + /// + /// Return the annotations associated with the target method/constructor itself. + /// + public Attribute[] MethodAttributes + { + get { - get { return methodInfo; } + if (methodInfo != null) + return Attribute.GetCustomAttributes(methodInfo); + else + return Attribute.GetCustomAttributes(constructorInfo); } - - /// - /// Gets wrapped ConstructorInfo, if any. Note Either MethodInfo or ConstructorInfo is available. - /// - /// The ConstructorInfo, or null if none - public ConstructorInfo ConstructorInfo - { - get { return constructorInfo; } - } - - /// - /// Return the annotations associated with the specific method/constructor parameter. - /// - public Attribute[] ParameterAttributes - { - get - { - if (methodInfo != null) - return Attribute.GetCustomAttributes(methodInfo.GetParameters()[parameterIndex]); - else - return Attribute.GetCustomAttributes(constructorInfo.GetParameters()[parameterIndex]); - } - } - - /// - /// Return the annotations associated with the target method/constructor itself. - /// - public Attribute[] MethodAttributes - { - get - { - if (methodInfo != null) - return Attribute.GetCustomAttributes(methodInfo); - else - return Attribute.GetCustomAttributes(constructorInfo); - } - } - } } diff --git a/src/Spring/Spring.Core/Core/MethodParametersCountCriteria.cs b/src/Spring/Spring.Core/Core/MethodParametersCountCriteria.cs index be456df1..f6640442 100644 --- a/src/Spring/Spring.Core/Core/MethodParametersCountCriteria.cs +++ b/src/Spring/Spring.Core/Core/MethodParametersCountCriteria.cs @@ -24,122 +24,123 @@ using System.Reflection; #endregion -namespace Spring.Core +namespace Spring.Core; + +/// +/// Criteria that is satisfied if the number of parameters to a given +/// matches an arbitrary number. +/// +/// +///

+/// This class supports checking the parameter count of both methods and +/// constructors. +///

+///

+/// Default parameters, etc need to taken into account. +///

+///
+/// Rick Evans +public class MethodParametersCountCriteria : ICriteria { + #region Constructor (s) / Destructor + /// - /// Criteria that is satisfied if the number of parameters to a given - /// matches an arbitrary number. + /// Creates a new instance of the + /// class. /// /// ///

- /// This class supports checking the parameter count of both methods and - /// constructors. - ///

- ///

- /// Default parameters, etc need to taken into account. + /// This constructor sets the + /// + /// property to zero (0). ///

///
- /// Rick Evans - public class MethodParametersCountCriteria : ICriteria + public MethodParametersCountCriteria() : this(0) { - #region Constructor (s) / Destructor - - /// - /// Creates a new instance of the - /// class. - /// - /// - ///

- /// This constructor sets the - /// - /// property to zero (0). - ///

- ///
- public MethodParametersCountCriteria() : this(0) - { - } - - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The number of parameters that a - /// must have to satisfy this criteria. - /// - /// - /// If the supplied is less - /// than zero. - /// - public MethodParametersCountCriteria(int expectedParameterCount) - { - ExpectedParameterCount = expectedParameterCount; - } - - #endregion - - #region Properties - - /// - /// The number of parameters that a - /// must have to satisfy this criteria. - /// - /// - /// If the supplied value is less than zero. - /// - public int ExpectedParameterCount - { - get { return _count; } - set - { - if (value < 0) - { - throw new ArgumentOutOfRangeException( - "value", value, "Cannot specify a parameter count of less than zero."); - } - _count = value; - } - } - - #endregion - - #region Methods - - /// - /// Does the supplied satisfy the criteria encapsulated by - /// this instance? - /// - /// The datum to be checked by this criteria instance. - /// - /// True if the supplied satisfies the criteria encapsulated - /// by this instance; false if not or the supplied is null. - /// - public bool IsSatisfied(object datum) - { - bool satisfied = false; - MethodBase method = datum as MethodBase; - if (method != null) - { - ParameterInfo[] parameters = method.GetParameters(); - if (parameters.Length == ExpectedParameterCount) - { - satisfied = true; - } - else if ((parameters.Length > 0) && (ExpectedParameterCount >= parameters.Length-1)) - { - ParameterInfo lastParameter = parameters[parameters.Length - 1]; - satisfied = lastParameter.GetCustomAttributes(typeof(ParamArrayAttribute), false).Length > 0; - } - } - return satisfied; - } - - #endregion - - #region Fields - - private int _count; - - #endregion } + + /// + /// Creates a new instance of the + /// class. + /// + /// + /// The number of parameters that a + /// must have to satisfy this criteria. + /// + /// + /// If the supplied is less + /// than zero. + /// + public MethodParametersCountCriteria(int expectedParameterCount) + { + ExpectedParameterCount = expectedParameterCount; + } + + #endregion + + #region Properties + + /// + /// The number of parameters that a + /// must have to satisfy this criteria. + /// + /// + /// If the supplied value is less than zero. + /// + public int ExpectedParameterCount + { + get { return _count; } + set + { + if (value < 0) + { + throw new ArgumentOutOfRangeException( + "value", value, "Cannot specify a parameter count of less than zero."); + } + + _count = value; + } + } + + #endregion + + #region Methods + + /// + /// Does the supplied satisfy the criteria encapsulated by + /// this instance? + /// + /// The datum to be checked by this criteria instance. + /// + /// True if the supplied satisfies the criteria encapsulated + /// by this instance; false if not or the supplied is null. + /// + public bool IsSatisfied(object datum) + { + bool satisfied = false; + MethodBase method = datum as MethodBase; + if (method != null) + { + ParameterInfo[] parameters = method.GetParameters(); + if (parameters.Length == ExpectedParameterCount) + { + satisfied = true; + } + else if ((parameters.Length > 0) && (ExpectedParameterCount >= parameters.Length - 1)) + { + ParameterInfo lastParameter = parameters[parameters.Length - 1]; + satisfied = lastParameter.GetCustomAttributes(typeof(ParamArrayAttribute), false).Length > 0; + } + } + + return satisfied; + } + + #endregion + + #region Fields + + private int _count; + + #endregion } diff --git a/src/Spring/Spring.Core/Core/MethodParametersCriteria.cs b/src/Spring/Spring.Core/Core/MethodParametersCriteria.cs index b1cc4cf3..f5e18ba6 100644 --- a/src/Spring/Spring.Core/Core/MethodParametersCriteria.cs +++ b/src/Spring/Spring.Core/Core/MethodParametersCriteria.cs @@ -24,102 +24,102 @@ using System.Reflection; #endregion -namespace Spring.Core +namespace Spring.Core; + +/// +/// Criteria that is satisfied if the of each of the +/// parameters of a given matches each +/// of the parameter s of a given +/// . +/// +/// +///

+/// If no array is passed to the overloaded constructor, +/// any method that has no parameters will satisfy an instance of this +/// class. The same effect could be achieved by passing the +/// array to the overloaded constructor. +///

+///
+/// Rick Evans +/// Bruno Baia +public class MethodParametersCriteria : ICriteria { + #region Constructor (s) / Destructor + /// - /// Criteria that is satisfied if the of each of the - /// parameters of a given matches each - /// of the parameter s of a given - /// . + /// Creates a new instance of the + /// class. + /// + public MethodParametersCriteria() : this(Type.EmptyTypes) + { + } + + /// + /// Creates a new instance of the + /// class. /// /// ///

- /// If no array is passed to the overloaded constructor, - /// any method that has no parameters will satisfy an instance of this - /// class. The same effect could be achieved by passing the - /// array to the overloaded constructor. + /// If the supplied array is null, then this + /// constructor uses the array. ///

///
- /// Rick Evans - /// Bruno Baia - public class MethodParametersCriteria : ICriteria + /// + /// The array that this criteria will use to + /// check parameter s. + /// + public MethodParametersCriteria(Type[] parameters) { - #region Constructor (s) / Destructor + _parameters = parameters; + } - /// - /// Creates a new instance of the - /// class. - /// - public MethodParametersCriteria() : this(Type.EmptyTypes) + #endregion + + #region Methods + + /// + /// Does the supplied satisfy the criteria encapsulated by + /// this instance? + /// + /// The datum to be checked by this criteria instance. + /// + /// True if the supplied satisfies the criteria encapsulated + /// by this instance; false if not or the supplied is null. + /// + public bool IsSatisfied(object datum) + { + bool satisfied = false; + MethodInfo method = datum as MethodInfo; + if (method != null) { - } - - /// - /// Creates a new instance of the - /// class. - /// - /// - ///

- /// If the supplied array is null, then this - /// constructor uses the array. - ///

- ///
- /// - /// The array that this criteria will use to - /// check parameter s. - /// - public MethodParametersCriteria(Type[] parameters) - { - _parameters = parameters; - } - - #endregion - - #region Methods - - /// - /// Does the supplied satisfy the criteria encapsulated by - /// this instance? - /// - /// The datum to be checked by this criteria instance. - /// - /// True if the supplied satisfies the criteria encapsulated - /// by this instance; false if not or the supplied is null. - /// - public bool IsSatisfied(object datum) - { - bool satisfied = false; - MethodInfo method = datum as MethodInfo; - if (method != null) + ParameterInfo[] parameterInfosBeingChecked = method.GetParameters(); + if (parameterInfosBeingChecked != null + && parameterInfosBeingChecked.Length == _parameters.Length) { - ParameterInfo[] parameterInfosBeingChecked = method.GetParameters(); - if (parameterInfosBeingChecked != null - && parameterInfosBeingChecked.Length == _parameters.Length) + satisfied = true; + for (int i = 0; i < _parameters.Length; ++i) { - satisfied = true; - for (int i = 0; i < _parameters.Length; ++i) + if (parameterInfosBeingChecked[i].ParameterType == _parameters[i]) { - if (parameterInfosBeingChecked[i].ParameterType == _parameters[i]) - { - satisfied = true; - } - else - { - satisfied = false; - break; - } + satisfied = true; + } + else + { + satisfied = false; + break; } } } - return satisfied; } - #endregion - - #region Fields - - private readonly Type[] _parameters; - - #endregion + return satisfied; } + + #endregion + + #region Fields + + private readonly Type[] _parameters; + + #endregion } diff --git a/src/Spring/Spring.Core/Core/MethodReturnTypeCriteria.cs b/src/Spring/Spring.Core/Core/MethodReturnTypeCriteria.cs index 07269b7b..7d96f389 100644 --- a/src/Spring/Spring.Core/Core/MethodReturnTypeCriteria.cs +++ b/src/Spring/Spring.Core/Core/MethodReturnTypeCriteria.cs @@ -24,95 +24,95 @@ using System.Reflection; #endregion -namespace Spring.Core +namespace Spring.Core; + +/// +/// Criteria that is satisfied if the return of a given +/// matches a given . +/// +/// Rick Evans +public class MethodReturnTypeCriteria : ICriteria { + #region Constants + /// - /// Criteria that is satisfied if the return of a given - /// matches a given . + /// The return to match against if no + /// is provided explictly. /// - /// Rick Evans - public class MethodReturnTypeCriteria : ICriteria + private static readonly Type DefaultType = typeof(void); + + #endregion + + #region Constructor (s) / Destructor + + /// + /// Creates a new instance of the + /// class. + /// + public MethodReturnTypeCriteria() + : this(DefaultType) { - #region Constants - - /// - /// The return to match against if no - /// is provided explictly. - /// - private static readonly Type DefaultType = typeof (void); - - #endregion - - #region Constructor (s) / Destructor - - /// - /// Creates a new instance of the - /// class. - /// - public MethodReturnTypeCriteria() - : this(DefaultType) - { - } - - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The that the return type of a given - /// must match in order to satisfy - /// this criteria. - /// - public MethodReturnTypeCriteria(Type type) - { - ReturnType = type; - } - - #endregion - - #region Properties - - /// - /// The that the return type of a given - /// must match in order to satisfy - /// this criteria. - /// - public Type ReturnType - { - get { return _type; } - set { _type = value == null ? DefaultType : value; } - } - - #endregion - - #region Methods - - /// - /// Does the supplied satisfy the criteria encapsulated by - /// this instance? - /// - /// The datum to be checked by this criteria instance. - /// - /// True if the supplied satisfies the criteria encapsulated - /// by this instance; false if not or the supplied is null. - /// - public bool IsSatisfied(object datum) - { - bool satisfied = false; - MethodInfo method = datum as MethodInfo; - if (method != null) - { - satisfied = method.ReturnType.Equals(ReturnType); - } - return satisfied; - } - - #endregion - - #region Fields - - private Type _type; - - #endregion } + + /// + /// Creates a new instance of the + /// class. + /// + /// + /// The that the return type of a given + /// must match in order to satisfy + /// this criteria. + /// + public MethodReturnTypeCriteria(Type type) + { + ReturnType = type; + } + + #endregion + + #region Properties + + /// + /// The that the return type of a given + /// must match in order to satisfy + /// this criteria. + /// + public Type ReturnType + { + get { return _type; } + set { _type = value == null ? DefaultType : value; } + } + + #endregion + + #region Methods + + /// + /// Does the supplied satisfy the criteria encapsulated by + /// this instance? + /// + /// The datum to be checked by this criteria instance. + /// + /// True if the supplied satisfies the criteria encapsulated + /// by this instance; false if not or the supplied is null. + /// + public bool IsSatisfied(object datum) + { + bool satisfied = false; + MethodInfo method = datum as MethodInfo; + if (method != null) + { + satisfied = method.ReturnType.Equals(ReturnType); + } + + return satisfied; + } + + #endregion + + #region Fields + + private Type _type; + + #endregion } diff --git a/src/Spring/Spring.Core/Core/NotReadablePropertyException.cs b/src/Spring/Spring.Core/Core/NotReadablePropertyException.cs index ef0fae38..001b6366 100644 --- a/src/Spring/Spring.Core/Core/NotReadablePropertyException.cs +++ b/src/Spring/Spring.Core/Core/NotReadablePropertyException.cs @@ -25,90 +25,89 @@ using System.Runtime.Serialization; #endregion -namespace Spring.Core +namespace Spring.Core; + +/// +/// Thrown in response to a failed attempt to read a property. +/// +/// +///

+/// Typically thrown when attempting to read the value of a write-only +/// property via reflection. +///

+///
+/// Juergen Hoeller +/// Rick Evans (.NET) +[Serializable] +public class NotReadablePropertyException : InvalidPropertyException { /// - /// Thrown in response to a failed attempt to read a property. + /// Creates a new instance of the + /// class. /// - /// - ///

- /// Typically thrown when attempting to read the value of a write-only - /// property via reflection. - ///

- ///
- /// Juergen Hoeller - /// Rick Evans (.NET) - [Serializable] - public class NotReadablePropertyException : InvalidPropertyException + public NotReadablePropertyException() { - /// - /// Creates a new instance of the - /// class. - /// - public NotReadablePropertyException() - { - } + } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - public NotReadablePropertyException(string message) : base(message) - { - } + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + public NotReadablePropertyException(string message) : base(message) + { + } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The that is (or rather was) the source of the - /// offending property. - /// - /// - /// The name of the offending property. - /// - public NotReadablePropertyException(Type type, string propertyName) - : base(type, propertyName, string.Format( - CultureInfo.InvariantCulture, - "Cannot read the value of the '{0}' property " + - "declared on the [{1}] class : property is read-only.", propertyName, type.FullName)) - { - } + /// + /// Creates a new instance of the + /// class. + /// + /// + /// The that is (or rather was) the source of the + /// offending property. + /// + /// + /// The name of the offending property. + /// + public NotReadablePropertyException(Type type, string propertyName) + : base(type, propertyName, string.Format( + CultureInfo.InvariantCulture, + "Cannot read the value of the '{0}' property " + + "declared on the [{1}] class : property is read-only.", propertyName, type.FullName)) + { + } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception that is being wrapped. - /// - public NotReadablePropertyException(string message, Exception rootCause) - : base(message, rootCause) - { - } + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception that is being wrapped. + /// + public NotReadablePropertyException(string message, Exception rootCause) + : base(message, rootCause) + { + } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The - /// that holds the serialized object data about the exception being thrown. - /// - /// - /// The - /// that contains contextual information about the source or destination. - /// - protected NotReadablePropertyException(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } + /// + /// Creates a new instance of the + /// class. + /// + /// + /// The + /// that holds the serialized object data about the exception being thrown. + /// + /// + /// The + /// that contains contextual information about the source or destination. + /// + protected NotReadablePropertyException(SerializationInfo info, StreamingContext context) + : base(info, context) + { } } diff --git a/src/Spring/Spring.Core/Core/NotWritablePropertyException.cs b/src/Spring/Spring.Core/Core/NotWritablePropertyException.cs index 1541fa2e..7900c7c3 100644 --- a/src/Spring/Spring.Core/Core/NotWritablePropertyException.cs +++ b/src/Spring/Spring.Core/Core/NotWritablePropertyException.cs @@ -25,122 +25,121 @@ using System.Runtime.Serialization; #endregion -namespace Spring.Core +namespace Spring.Core; + +/// +/// Thrown in response to a failed attempt to write a property. +/// +/// Mark Pollack (.NET) +[Serializable] +public class NotWritablePropertyException : InvalidPropertyException { /// - /// Thrown in response to a failed attempt to write a property. + /// Creates a new instance of the NotWritablePropertyException class. /// - /// Mark Pollack (.NET) - [Serializable] - public class NotWritablePropertyException : InvalidPropertyException + public NotWritablePropertyException() { - /// - /// Creates a new instance of the NotWritablePropertyException class. - /// - public NotWritablePropertyException() - { - } + } - /// - /// Creates a new instance of the NotWritablePropertyException class. - /// - /// - /// A message about the exception. - /// - public NotWritablePropertyException(string message) : base(message) - { - } + /// + /// Creates a new instance of the NotWritablePropertyException class. + /// + /// + /// A message about the exception. + /// + public NotWritablePropertyException(string message) : base(message) + { + } - /// - /// Creates a new instance of the NotWritablePropertyException class. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception that is being wrapped. - /// - public NotWritablePropertyException(string message, Exception rootCause) - : base(message, rootCause) - { - } + /// + /// Creates a new instance of the NotWritablePropertyException class. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception that is being wrapped. + /// + public NotWritablePropertyException(string message, Exception rootCause) + : base(message, rootCause) + { + } - /// - /// Creates a new instance of the NotWritablePropertyException class. - /// - /// - /// The that is (or rather was) the source of the - /// offending property. - /// - /// - /// The name of the offending property. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception that is being wrapped. - /// - public NotWritablePropertyException( - Type offendingType, string offendingProperty, string message, Exception rootCause) - : base(offendingType, offendingProperty, message, rootCause) - { - } + /// + /// Creates a new instance of the NotWritablePropertyException class. + /// + /// + /// The that is (or rather was) the source of the + /// offending property. + /// + /// + /// The name of the offending property. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception that is being wrapped. + /// + public NotWritablePropertyException( + Type offendingType, string offendingProperty, string message, Exception rootCause) + : base(offendingType, offendingProperty, message, rootCause) + { + } - /// - /// Creates a new instance of the NotWritablePropertyException class - /// summarizing what property was not writable. - /// - /// - /// The name of the property that is not writable. - /// - /// - /// The in which the property is not writable. - /// - public NotWritablePropertyException(string offendingProperty, Type offendingType) - : base(offendingType, offendingProperty, - string.Format(CultureInfo.InvariantCulture, - "Property '{0}' is not writable in class [{1}].", - offendingProperty, offendingType.FullName)) - { - } + /// + /// Creates a new instance of the NotWritablePropertyException class + /// summarizing what property was not writable. + /// + /// + /// The name of the property that is not writable. + /// + /// + /// The in which the property is not writable. + /// + public NotWritablePropertyException(string offendingProperty, Type offendingType) + : base(offendingType, offendingProperty, + string.Format(CultureInfo.InvariantCulture, + "Property '{0}' is not writable in class [{1}].", + offendingProperty, offendingType.FullName)) + { + } - /// - /// Creates new NotWritablePropertyException with a root cause. - /// - /// - /// The name of the property that is not writable. - /// - /// - /// The in which the property is not writable. - /// - /// - /// The root cause indicating why the property was not writable. - /// - public NotWritablePropertyException(string offendingProperty, Type offendingType, Exception rootCause) - : base(offendingType, offendingProperty, - string.Format(CultureInfo.InvariantCulture, - "Property '{0}' is not writable in class [{1}].", - offendingProperty, - offendingType != null ? offendingType.FullName : "null"), - rootCause) - { - } + /// + /// Creates new NotWritablePropertyException with a root cause. + /// + /// + /// The name of the property that is not writable. + /// + /// + /// The in which the property is not writable. + /// + /// + /// The root cause indicating why the property was not writable. + /// + public NotWritablePropertyException(string offendingProperty, Type offendingType, Exception rootCause) + : base(offendingType, offendingProperty, + string.Format(CultureInfo.InvariantCulture, + "Property '{0}' is not writable in class [{1}].", + offendingProperty, + offendingType != null ? offendingType.FullName : "null"), + rootCause) + { + } - /// - /// Creates a new instance of the NotWritablePropertyException class. - /// - /// - /// The - /// that holds the serialized object data about the exception being thrown. - /// - /// - /// The - /// that contains contextual information about the source or destination. - /// - protected NotWritablePropertyException(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } + /// + /// Creates a new instance of the NotWritablePropertyException class. + /// + /// + /// The + /// that holds the serialized object data about the exception being thrown. + /// + /// + /// The + /// that contains contextual information about the source or destination. + /// + protected NotWritablePropertyException(SerializationInfo info, StreamingContext context) + : base(info, context) + { } } diff --git a/src/Spring/Spring.Core/Core/NullValueInNestedPathException.cs b/src/Spring/Spring.Core/Core/NullValueInNestedPathException.cs index 53acaf3a..5a7afda5 100644 --- a/src/Spring/Spring.Core/Core/NullValueInNestedPathException.cs +++ b/src/Spring/Spring.Core/Core/NullValueInNestedPathException.cs @@ -27,144 +27,143 @@ using Spring.Util; #endregion -namespace Spring.Core +namespace Spring.Core; + +/// +/// Thrown in response to encountering a value +/// when traversing a nested path expression. +/// +[Serializable] +public class NullValueInNestedPathException : FatalReflectionException { + private string property; + private Type type; + /// - /// Thrown in response to encountering a value - /// when traversing a nested path expression. + /// The name of the offending property. /// - [Serializable] - public class NullValueInNestedPathException : FatalReflectionException + public string PropertyName { - private string property; - private Type type; - - /// - /// The name of the offending property. - /// - public string PropertyName - { - get { return property; } - } - - /// - /// The of the class where the property was last looked for. - /// - public Type ObjectType - { - get { return type; } - } - - #region Constructor (s) / Destructor - - /// - /// Creates a new instance of the - /// class. - /// - public NullValueInNestedPathException() - { - } - - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - public NullValueInNestedPathException(string message) : base(message) - { - } - - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception that is being wrapped. - /// - public NullValueInNestedPathException(string message, Exception rootCause) - : base(message, rootCause) - { - } - - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The of the object where the property was not found. - /// - /// The name of the property not found. - public NullValueInNestedPathException(Type type, string theProperty) - : this(type, theProperty, string.Format(CultureInfo.InvariantCulture, - "Value of nested property '{0}' is null in Type [{1}].", theProperty, type)) - { - } - - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The of the object where the property was not found. - /// - /// The name of the property not found. - /// A message about the exception. - public NullValueInNestedPathException(Type type, string theProperty, string message) - : base(message) - { - property = theProperty; - this.type = type; - } - - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The - /// that holds the serialized object data about the exception being thrown. - /// - /// - /// The - /// that contains contextual information about the source or destination. - /// - protected NullValueInNestedPathException(SerializationInfo info, StreamingContext context) - : base(info, context) - { - type = info.GetValue("ObjectType", typeof (Type)) as Type; - property = info.GetString("PropertyName"); - } - - #endregion - - #region Methods - - /// - /// Populates a with - /// the data needed to serialize the target object. - /// - /// - /// The to populate - /// with data. - /// - /// - /// The destination (see ) - /// for this serialization. - /// - [SecurityPermission(SecurityAction.Demand, SerializationFormatter=true)] - public override void GetObjectData( - SerializationInfo info, StreamingContext context) - { - base.GetObjectData(info, context); - info.AddValue("ObjectType", ObjectType); - info.AddValue("PropertyName", PropertyName); - } - - #endregion + get { return property; } } + + /// + /// The of the class where the property was last looked for. + /// + public Type ObjectType + { + get { return type; } + } + + #region Constructor (s) / Destructor + + /// + /// Creates a new instance of the + /// class. + /// + public NullValueInNestedPathException() + { + } + + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + public NullValueInNestedPathException(string message) : base(message) + { + } + + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception that is being wrapped. + /// + public NullValueInNestedPathException(string message, Exception rootCause) + : base(message, rootCause) + { + } + + /// + /// Creates a new instance of the + /// class. + /// + /// + /// The of the object where the property was not found. + /// + /// The name of the property not found. + public NullValueInNestedPathException(Type type, string theProperty) + : this(type, theProperty, string.Format(CultureInfo.InvariantCulture, + "Value of nested property '{0}' is null in Type [{1}].", theProperty, type)) + { + } + + /// + /// Creates a new instance of the + /// class. + /// + /// + /// The of the object where the property was not found. + /// + /// The name of the property not found. + /// A message about the exception. + public NullValueInNestedPathException(Type type, string theProperty, string message) + : base(message) + { + property = theProperty; + this.type = type; + } + + /// + /// Creates a new instance of the + /// class. + /// + /// + /// The + /// that holds the serialized object data about the exception being thrown. + /// + /// + /// The + /// that contains contextual information about the source or destination. + /// + protected NullValueInNestedPathException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + type = info.GetValue("ObjectType", typeof(Type)) as Type; + property = info.GetString("PropertyName"); + } + + #endregion + + #region Methods + + /// + /// Populates a with + /// the data needed to serialize the target object. + /// + /// + /// The to populate + /// with data. + /// + /// + /// The destination (see ) + /// for this serialization. + /// + [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)] + public override void GetObjectData( + SerializationInfo info, StreamingContext context) + { + base.GetObjectData(info, context); + info.AddValue("ObjectType", ObjectType); + info.AddValue("PropertyName", PropertyName); + } + + #endregion } diff --git a/src/Spring/Spring.Core/Core/OrderComparator.cs b/src/Spring/Spring.Core/Core/OrderComparator.cs index 4fa7976c..03044297 100644 --- a/src/Spring/Spring.Core/Core/OrderComparator.cs +++ b/src/Spring/Spring.Core/Core/OrderComparator.cs @@ -24,90 +24,89 @@ using System.Collections; #endregion -namespace Spring.Core +namespace Spring.Core; + +/// +/// Comparator implementation for objects, sorting by +/// order value ascending (resp. by priority descending). +/// +/// +///

+/// Non- objects are treated as greatest order values, +/// thus ending up at the end of a list, in arbitrary order (just like same order values of +/// objects). +///

+///
+/// Juergen Hoeller +/// Aleksandar Seovic (.Net) +[Serializable] +public class OrderComparator : OrderComparator, IComparer { +} + +/// +/// Comparator implementation for objects, sorting by +/// order value ascending (resp. by priority descending). +/// +/// +///

+/// Non- objects are treated as greatest order values, +/// thus ending up at the end of a list, in arbitrary order (just like same order values of +/// objects). +///

+///
+/// Juergen Hoeller +/// Aleksandar Seovic (.Net) +[Serializable] +public class OrderComparator : IComparer +{ + public static readonly IComparer Instance = new OrderComparator(); + /// - /// Comparator implementation for objects, sorting by - /// order value ascending (resp. by priority descending). + /// Compares two objects and returns a value indicating whether one is less than, + /// equal to or greater than the other. /// /// ///

- /// Non- objects are treated as greatest order values, - /// thus ending up at the end of a list, in arbitrary order (just like same order values of - /// objects). + /// Uses direct evaluation instead of + /// to avoid unnecessary boxing. ///

///
- /// Juergen Hoeller - /// Aleksandar Seovic (.Net) - [Serializable] - public class OrderComparator : OrderComparator, IComparer + /// The first object to compare. + /// The second object to compare. + /// + /// -1 if first object is less then second, 1 if it is greater, or 0 if they are equal. + /// + public virtual int Compare(T o1, T o2) { + IOrdered o1lhs = o1 as IOrdered; + IOrdered o2rhs = o2 as IOrdered; + int lhs = o1lhs?.Order ?? int.MaxValue; + int rhs = o2rhs?.Order ?? int.MaxValue; + if (lhs < rhs) + { + return -1; + } + + if (lhs > rhs) + { + return 1; + } + + return CompareEqualOrder(o1, o2); } /// - /// Comparator implementation for objects, sorting by - /// order value ascending (resp. by priority descending). + /// Handle the case when both objects have equal sort order priority. By default returns 0, + /// but may be overriden for handling special cases. /// - /// - ///

- /// Non- objects are treated as greatest order values, - /// thus ending up at the end of a list, in arbitrary order (just like same order values of - /// objects). - ///

- ///
- /// Juergen Hoeller - /// Aleksandar Seovic (.Net) - [Serializable] - public class OrderComparator : IComparer + /// The first object to compare. + /// The second object to compare. + /// + /// -1 if first object is less then second, 1 if it is greater, or 0 if they are equal. + /// + protected virtual int CompareEqualOrder(T o1, T o2) { - public static readonly IComparer Instance = new OrderComparator(); - - /// - /// Compares two objects and returns a value indicating whether one is less than, - /// equal to or greater than the other. - /// - /// - ///

- /// Uses direct evaluation instead of - /// to avoid unnecessary boxing. - ///

- ///
- /// The first object to compare. - /// The second object to compare. - /// - /// -1 if first object is less then second, 1 if it is greater, or 0 if they are equal. - /// - public virtual int Compare(T o1, T o2) - { - IOrdered o1lhs = o1 as IOrdered; - IOrdered o2rhs = o2 as IOrdered; - int lhs = o1lhs?.Order ?? int.MaxValue; - int rhs = o2rhs?.Order ?? int.MaxValue; - if (lhs < rhs) - { - return - 1; - } - - if (lhs > rhs) - { - return 1; - } - - return CompareEqualOrder(o1, o2); - } - - /// - /// Handle the case when both objects have equal sort order priority. By default returns 0, - /// but may be overriden for handling special cases. - /// - /// The first object to compare. - /// The second object to compare. - /// - /// -1 if first object is less then second, 1 if it is greater, or 0 if they are equal. - /// - protected virtual int CompareEqualOrder(T o1, T o2) - { - return 0; - } + return 0; } } diff --git a/src/Spring/Spring.Core/Core/PropertyAccessException.cs b/src/Spring/Spring.Core/Core/PropertyAccessException.cs index 272c94f9..6c9b2035 100644 --- a/src/Spring/Spring.Core/Core/PropertyAccessException.cs +++ b/src/Spring/Spring.Core/Core/PropertyAccessException.cs @@ -22,136 +22,134 @@ using System.Runtime.Serialization; using System.Security.Permissions; - using Spring.Util; #endregion -namespace Spring.Core +namespace Spring.Core; + +/// +/// Superclass for exceptions related to a property access, such as a +/// mismatch or a target invocation exception. +/// +/// Rod Johnson +/// Mark Pollack (.NET) +[Serializable] +public abstract class PropertyAccessException : ReflectionException, IErrorCoded { /// - /// Superclass for exceptions related to a property access, such as a - /// mismatch or a target invocation exception. + /// Returns the PropertyChangeEventArgs that resulted in the problem. /// - /// Rod Johnson - /// Mark Pollack (.NET) - [Serializable] - public abstract class PropertyAccessException : ReflectionException, IErrorCoded + public PropertyChangeEventArgs PropertyChangeArgs { - /// - /// Returns the PropertyChangeEventArgs that resulted in the problem. - /// - public PropertyChangeEventArgs PropertyChangeArgs - { - get { return _propertyChangeEventArgs; } - } + get { return _propertyChangeEventArgs; } + } - /// - /// The string error code used to classify the error. - /// - public abstract string ErrorCode { get; } + /// + /// The string error code used to classify the error. + /// + public abstract string ErrorCode { get; } - private PropertyChangeEventArgs _propertyChangeEventArgs; + private PropertyChangeEventArgs _propertyChangeEventArgs; - #region Methods + #region Methods - /// - /// Populates a with - /// the data needed to serialize the target object. - /// - /// - /// The to populate - /// with data. - /// - /// - /// The destination (see ) - /// for this serialization. - /// - [SecurityPermission(SecurityAction.Demand, SerializationFormatter=true)] - public override void GetObjectData( - SerializationInfo info, StreamingContext context) - { - base.GetObjectData(info, context); - info.AddValue("PropertyChangeArgs", PropertyChangeArgs); - } + /// + /// Populates a with + /// the data needed to serialize the target object. + /// + /// + /// The to populate + /// with data. + /// + /// + /// The destination (see ) + /// for this serialization. + /// + [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)] + public override void GetObjectData( + SerializationInfo info, StreamingContext context) + { + base.GetObjectData(info, context); + info.AddValue("PropertyChangeArgs", PropertyChangeArgs); + } - #endregion + #endregion - /// - /// Create a new instance of the PropertyAccessException class. - /// - /// - /// A message about the exception. - /// - /// Describes the change attempted on the property. - protected PropertyAccessException(string message, PropertyChangeEventArgs propertyChangeEvent) : base(message) - { - _propertyChangeEventArgs = propertyChangeEvent; - } + /// + /// Create a new instance of the PropertyAccessException class. + /// + /// + /// A message about the exception. + /// + /// Describes the change attempted on the property. + protected PropertyAccessException(string message, PropertyChangeEventArgs propertyChangeEvent) : base(message) + { + _propertyChangeEventArgs = propertyChangeEvent; + } - /// - /// Create a new instance of the PropertyAccessException class. - /// - /// - /// A message about the exception. - /// - /// Describes the change attempted on the property. - /// - /// The root exception that is being wrapped. - /// - protected PropertyAccessException(string message, PropertyChangeEventArgs propertyChangeEvent, Exception rootCause) - : base(message, rootCause) - { - _propertyChangeEventArgs = propertyChangeEvent; - } + /// + /// Create a new instance of the PropertyAccessException class. + /// + /// + /// A message about the exception. + /// + /// Describes the change attempted on the property. + /// + /// The root exception that is being wrapped. + /// + protected PropertyAccessException(string message, PropertyChangeEventArgs propertyChangeEvent, Exception rootCause) + : base(message, rootCause) + { + _propertyChangeEventArgs = propertyChangeEvent; + } - /// - /// Creates a new instance of the PropertyAccessException class. - /// - protected PropertyAccessException() - { - } + /// + /// Creates a new instance of the PropertyAccessException class. + /// + protected PropertyAccessException() + { + } - /// - /// Creates a new instance of the PropertyAccessException class. - /// - /// - /// A message about the exception. - /// - protected PropertyAccessException(string message) : base(message) - { - } + /// + /// Creates a new instance of the PropertyAccessException class. + /// + /// + /// A message about the exception. + /// + protected PropertyAccessException(string message) : base(message) + { + } - /// - /// Creates a new instance of the PropertyAccessExceptionsException class. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception that is being wrapped. - /// - protected PropertyAccessException(string message, Exception rootCause) - : base(message, rootCause) - { - } + /// + /// Creates a new instance of the PropertyAccessExceptionsException class. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception that is being wrapped. + /// + protected PropertyAccessException(string message, Exception rootCause) + : base(message, rootCause) + { + } - /// - /// Creates a new instance of the PropertyAccessExceptionsException class. - /// - /// - /// The - /// that holds the serialized object data about the exception being thrown. - /// - /// - /// The - /// that contains contextual information about the source or destination. - /// - protected PropertyAccessException( - SerializationInfo info, StreamingContext context) - : base(info, context) - { - _propertyChangeEventArgs = info.GetValue("PropertyChangeArgs", typeof (object)) as PropertyChangeEventArgs; - } + /// + /// Creates a new instance of the PropertyAccessExceptionsException class. + /// + /// + /// The + /// that holds the serialized object data about the exception being thrown. + /// + /// + /// The + /// that contains contextual information about the source or destination. + /// + protected PropertyAccessException( + SerializationInfo info, StreamingContext context) + : base(info, context) + { + _propertyChangeEventArgs = info.GetValue("PropertyChangeArgs", typeof(object)) as PropertyChangeEventArgs; } } diff --git a/src/Spring/Spring.Core/Core/PropertyChangeEventArgs.cs b/src/Spring/Spring.Core/Core/PropertyChangeEventArgs.cs index 7b005d41..d0109605 100644 --- a/src/Spring/Spring.Core/Core/PropertyChangeEventArgs.cs +++ b/src/Spring/Spring.Core/Core/PropertyChangeEventArgs.cs @@ -24,59 +24,58 @@ using System.ComponentModel; #endregion -namespace Spring.Core +namespace Spring.Core; + +/// +/// Provides additional data for the PropertyChanged event. +/// +/// +///

+/// Provides some additional properties over and above the name of the +/// property that has changed (which is inherited from the +/// base class). +/// This allows calling code to determine whether or not a property has +/// actually changed (i.e. a PropertyChanged event may have been +/// raised, but the value itself may be equivalent). +///

+///
+/// +[Serializable] +public class PropertyChangeEventArgs : PropertyChangedEventArgs { + private object oldValue; + private object newValue; + /// - /// Provides additional data for the PropertyChanged event. + /// Create a new instance of the + /// class. /// - /// - ///

- /// Provides some additional properties over and above the name of the - /// property that has changed (which is inherited from the - /// base class). - /// This allows calling code to determine whether or not a property has - /// actually changed (i.e. a PropertyChanged event may have been - /// raised, but the value itself may be equivalent). - ///

- ///
- /// - [Serializable] - public class PropertyChangeEventArgs : PropertyChangedEventArgs + /// + /// The name of the property that was changed. + /// The old value of the property. + /// the new value of the property. + public PropertyChangeEventArgs( + string propertyName, object oldValue, object newValue) : base(propertyName) { - private object oldValue; - private object newValue; + this.oldValue = oldValue; + this.newValue = newValue; + } - /// - /// Create a new instance of the - /// class. - /// - /// - /// The name of the property that was changed. - /// The old value of the property. - /// the new value of the property. - public PropertyChangeEventArgs( - string propertyName, object oldValue, object newValue) : base(propertyName) - { - this.oldValue = oldValue; - this.newValue = newValue; - } + /// + /// Get the old value for the property. + /// + /// + public object OldValue + { + get { return oldValue; } + } - /// - /// Get the old value for the property. - /// - /// - public object OldValue - { - get { return oldValue; } - } - - /// - /// Get the new value of the property. - /// - /// - public object NewValue - { - get { return newValue; } - } + /// + /// Get the new value of the property. + /// + /// + public object NewValue + { + get { return newValue; } } } diff --git a/src/Spring/Spring.Core/Core/RegularExpressionCriteria.cs b/src/Spring/Spring.Core/Core/RegularExpressionCriteria.cs index 5fe44f4b..057ca347 100644 --- a/src/Spring/Spring.Core/Core/RegularExpressionCriteria.cs +++ b/src/Spring/Spring.Core/Core/RegularExpressionCriteria.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -21,122 +21,119 @@ #region Imports using System.Text.RegularExpressions; - using Spring.Util; #endregion -namespace Spring.Core +namespace Spring.Core; + +/// +/// A base class for all +/// implementations that are regular expression based. +/// +/// Rick Evans +public abstract class RegularExpressionCriteria : ICriteria { + #region Constants + /// - /// A base class for all - /// implementations that are regular expression based. + /// The default pattern... matches absolutely anything. /// - /// Rick Evans - public abstract class RegularExpressionCriteria : ICriteria + protected const string MatchAnyThingPattern = ".*"; + + #endregion + + #region Constructor (s) / Destructor + + /// + /// Creates a new instance of the + /// class. + /// + protected RegularExpressionCriteria() : this(RegularExpressionCriteria.MatchAnyThingPattern) { - #region Constants - - /// - /// The default pattern... matches absolutely anything. - /// - protected const string MatchAnyThingPattern = ".*"; - - #endregion - - #region Constructor (s) / Destructor - - /// - /// Creates a new instance of the - /// class. - /// - protected RegularExpressionCriteria() : this(RegularExpressionCriteria.MatchAnyThingPattern) - { - } - - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The regular expression pattern to be applied. - /// - protected RegularExpressionCriteria(string pattern) - { - Pattern = pattern; - } - - #endregion - - #region Properties - - /// - /// The regular expression pattern to be applied. - /// - public string Pattern - { - get { return _pattern; } - set - { - _pattern = StringUtils.HasText(value) ? - value : RegularExpressionCriteria.MatchAnyThingPattern; - Expression = new Regex(Pattern, Options); - } - } - - /// - /// The regular expression options to be applied. - /// - public RegexOptions Options - { - get { return _options; } - set { _options = value; } - } - - /// - /// The regular expression to be applied. - /// - public Regex Expression - { - get { return _expression; } - set { _expression = value; } - } - - #endregion - - #region Methods - - /// - /// Does the supplied satisfy the criteria encapsulated by - /// this instance? - /// - /// The datum to be checked by this criteria instance. - /// - /// True if the supplied satisfies the criteria encapsulated - /// by this instance; false if not or the supplied is null. - /// - public abstract bool IsSatisfied(object datum); - - /// - /// Convenience method that calls the - /// - /// on the supplied . - /// - /// The input to match against. - /// True if the matches. - protected bool IsMatch(string input) - { - return Expression.IsMatch(input); - } - - #endregion - - #region Fields - - private string _pattern; - private RegexOptions _options; - private Regex _expression; - - #endregion } -} \ No newline at end of file + + /// + /// Creates a new instance of the + /// class. + /// + /// + /// The regular expression pattern to be applied. + /// + protected RegularExpressionCriteria(string pattern) + { + Pattern = pattern; + } + + #endregion + + #region Properties + + /// + /// The regular expression pattern to be applied. + /// + public string Pattern + { + get { return _pattern; } + set + { + _pattern = StringUtils.HasText(value) ? value : RegularExpressionCriteria.MatchAnyThingPattern; + Expression = new Regex(Pattern, Options); + } + } + + /// + /// The regular expression options to be applied. + /// + public RegexOptions Options + { + get { return _options; } + set { _options = value; } + } + + /// + /// The regular expression to be applied. + /// + public Regex Expression + { + get { return _expression; } + set { _expression = value; } + } + + #endregion + + #region Methods + + /// + /// Does the supplied satisfy the criteria encapsulated by + /// this instance? + /// + /// The datum to be checked by this criteria instance. + /// + /// True if the supplied satisfies the criteria encapsulated + /// by this instance; false if not or the supplied is null. + /// + public abstract bool IsSatisfied(object datum); + + /// + /// Convenience method that calls the + /// + /// on the supplied . + /// + /// The input to match against. + /// True if the matches. + protected bool IsMatch(string input) + { + return Expression.IsMatch(input); + } + + #endregion + + #region Fields + + private string _pattern; + private RegexOptions _options; + private Regex _expression; + + #endregion +} diff --git a/src/Spring/Spring.Core/Core/RegularExpressionEventNameCriteria.cs b/src/Spring/Spring.Core/Core/RegularExpressionEventNameCriteria.cs index 191269b4..f3fd37bc 100644 --- a/src/Spring/Spring.Core/Core/RegularExpressionEventNameCriteria.cs +++ b/src/Spring/Spring.Core/Core/RegularExpressionEventNameCriteria.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -22,81 +22,79 @@ using System.Reflection; using System.Text.RegularExpressions; - using Spring.Util; #endregion -namespace Spring.Core +namespace Spring.Core; + +/// +/// Criteria that is satisfied if the Name property of an +/// instance matches a +/// supplied regular expression pattern. +/// +/// Rick Evans +public class RegularExpressionEventNameCriteria : RegularExpressionCriteria { + #region Constants + /// - /// Criteria that is satisfied if the Name property of an - /// instance matches a - /// supplied regular expression pattern. + /// The default event name pattern... matches pretty much any event name. /// - /// Rick Evans - public class RegularExpressionEventNameCriteria : RegularExpressionCriteria + private const string MatchAnyEventNamePattern = ".+"; + + #endregion + + #region Constructor (s) / Destructor + + /// + /// Creates a new instance of the + /// class. + /// + public RegularExpressionEventNameCriteria() + : this(RegularExpressionEventNameCriteria.MatchAnyEventNamePattern) { - #region Constants - - /// - /// The default event name pattern... matches pretty much any event name. - /// - private const string MatchAnyEventNamePattern = ".+"; - - #endregion - - #region Constructor (s) / Destructor - - /// - /// Creates a new instance of the - /// class. - /// - public RegularExpressionEventNameCriteria() - : this(RegularExpressionEventNameCriteria.MatchAnyEventNamePattern) - { - Options = RegexOptions.IgnoreCase; - } - - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The pattern that names - /// must match against in order to satisfy this criteria. - /// - public RegularExpressionEventNameCriteria(string eventNamePattern) - { - Options = RegexOptions.IgnoreCase; - Pattern = StringUtils.HasText(eventNamePattern) ? - eventNamePattern : RegularExpressionEventNameCriteria.MatchAnyEventNamePattern; - } - - #endregion - - #region Methods - - /// - /// Does the supplied satisfy the criteria encapsulated by - /// this instance? - /// - /// The datum to be checked by this criteria instance. - /// - /// True if the supplied satisfies the criteria encapsulated - /// by this instance; false if not or the supplied is null. - /// - public override bool IsSatisfied(object datum) - { - bool satisfied = false; - EventInfo evt = datum as EventInfo; - if (evt != null) - { - satisfied = IsMatch(evt.Name); - } - return satisfied; - } - - #endregion + Options = RegexOptions.IgnoreCase; } + + /// + /// Creates a new instance of the + /// class. + /// + /// + /// The pattern that names + /// must match against in order to satisfy this criteria. + /// + public RegularExpressionEventNameCriteria(string eventNamePattern) + { + Options = RegexOptions.IgnoreCase; + Pattern = StringUtils.HasText(eventNamePattern) ? eventNamePattern : RegularExpressionEventNameCriteria.MatchAnyEventNamePattern; + } + + #endregion + + #region Methods + + /// + /// Does the supplied satisfy the criteria encapsulated by + /// this instance? + /// + /// The datum to be checked by this criteria instance. + /// + /// True if the supplied satisfies the criteria encapsulated + /// by this instance; false if not or the supplied is null. + /// + public override bool IsSatisfied(object datum) + { + bool satisfied = false; + EventInfo evt = datum as EventInfo; + if (evt != null) + { + satisfied = IsMatch(evt.Name); + } + + return satisfied; + } + + #endregion } \ No newline at end of file diff --git a/src/Spring/Spring.Core/Core/RegularExpressionMethodNameCriteria.cs b/src/Spring/Spring.Core/Core/RegularExpressionMethodNameCriteria.cs index a72a5a8d..294279da 100644 --- a/src/Spring/Spring.Core/Core/RegularExpressionMethodNameCriteria.cs +++ b/src/Spring/Spring.Core/Core/RegularExpressionMethodNameCriteria.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -22,81 +22,79 @@ using System.Reflection; using System.Text.RegularExpressions; - using Spring.Util; #endregion -namespace Spring.Core +namespace Spring.Core; + +/// +/// Criteria that is satisfied if the Name property of an +/// instance matches a +/// supplied regular expression pattern. +/// +/// Rick Evans +public class RegularExpressionMethodNameCriteria : RegularExpressionCriteria { + #region Constants + /// - /// Criteria that is satisfied if the Name property of an - /// instance matches a - /// supplied regular expression pattern. + /// The default method name pattern... matches pretty much any method name. /// - /// Rick Evans - public class RegularExpressionMethodNameCriteria : RegularExpressionCriteria + private const string MatchAnyMethodNamePattern = ".+"; + + #endregion + + #region Constructor (s) / Destructor + + /// + /// Creates a new instance of the + /// class. + /// + public RegularExpressionMethodNameCriteria() + : this(RegularExpressionMethodNameCriteria.MatchAnyMethodNamePattern) { - #region Constants - - /// - /// The default method name pattern... matches pretty much any method name. - /// - private const string MatchAnyMethodNamePattern = ".+"; - - #endregion - - #region Constructor (s) / Destructor - - /// - /// Creates a new instance of the - /// class. - /// - public RegularExpressionMethodNameCriteria() - : this(RegularExpressionMethodNameCriteria.MatchAnyMethodNamePattern) - { - Options = RegexOptions.IgnoreCase; - } - - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The pattern that names - /// must match against in order to satisfy this criteria. - /// - public RegularExpressionMethodNameCriteria(string methodNamePattern) - { - Options = RegexOptions.IgnoreCase; - Pattern = StringUtils.HasText(methodNamePattern) ? - methodNamePattern : RegularExpressionMethodNameCriteria.MatchAnyMethodNamePattern; - } - - #endregion - - #region Methods - - /// - /// Does the supplied satisfy the criteria encapsulated by - /// this instance? - /// - /// The datum to be checked by this criteria instance. - /// - /// True if the supplied satisfies the criteria encapsulated - /// by this instance; false if not or the supplied is null. - /// - public override bool IsSatisfied(object datum) - { - bool satisfied = false; - MethodInfo method = datum as MethodInfo; - if (method != null) - { - satisfied = IsMatch(method.Name); - } - return satisfied; - } - - #endregion + Options = RegexOptions.IgnoreCase; } -} \ No newline at end of file + + /// + /// Creates a new instance of the + /// class. + /// + /// + /// The pattern that names + /// must match against in order to satisfy this criteria. + /// + public RegularExpressionMethodNameCriteria(string methodNamePattern) + { + Options = RegexOptions.IgnoreCase; + Pattern = StringUtils.HasText(methodNamePattern) ? methodNamePattern : RegularExpressionMethodNameCriteria.MatchAnyMethodNamePattern; + } + + #endregion + + #region Methods + + /// + /// Does the supplied satisfy the criteria encapsulated by + /// this instance? + /// + /// The datum to be checked by this criteria instance. + /// + /// True if the supplied satisfies the criteria encapsulated + /// by this instance; false if not or the supplied is null. + /// + public override bool IsSatisfied(object datum) + { + bool satisfied = false; + MethodInfo method = datum as MethodInfo; + if (method != null) + { + satisfied = IsMatch(method.Name); + } + + return satisfied; + } + + #endregion +} diff --git a/src/Spring/Spring.Core/Core/TypeConversion/CredentialConverter.cs b/src/Spring/Spring.Core/Core/TypeConversion/CredentialConverter.cs index 627d4f9b..07b28a3e 100644 --- a/src/Spring/Spring.Core/Core/TypeConversion/CredentialConverter.cs +++ b/src/Spring/Spring.Core/Core/TypeConversion/CredentialConverter.cs @@ -27,97 +27,97 @@ using System.Text.RegularExpressions; #endregion -namespace Spring.Core.TypeConversion +namespace Spring.Core.TypeConversion; + +/// +/// Converts string representation of a credential for Web client authentication +/// into an instance of . +/// +/// +///

+/// Find below some examples of the XML formatted strings that this +/// converter will sucessfully convert. +///

+/// +/// +/// +/// +/// +/// +///
+/// Bruno Baia +public class CredentialConverter : TypeConverter { + private readonly static Regex credentialRegex = new Regex( + @"(((?[\w_.]+)\\)?)(?([\w_.]+))((:(?([\w_.]+)))?)", + RegexOptions.Compiled); + /// - /// Converts string representation of a credential for Web client authentication - /// into an instance of . + /// Can we convert from the sourcetype + /// to a instance ? /// - /// + /// ///

- /// Find below some examples of the XML formatted strings that this - /// converter will sucessfully convert. + /// Currently only supports conversion from a instance. ///

- /// - /// - /// - /// - /// - /// - ///
- /// Bruno Baia - public class CredentialConverter : TypeConverter + /// + /// + /// A + /// that provides a format context. + /// + /// + /// A that represents the + /// you want to convert from. + /// + /// if the conversion is possible. + public override bool CanConvertFrom( + ITypeDescriptorContext context, Type sourceType) { - private readonly static Regex credentialRegex = new Regex( - @"(((?[\w_.]+)\\)?)(?([\w_.]+))((:(?([\w_.]+)))?)", - RegexOptions.Compiled); + return (sourceType == typeof(string)); + } - /// - /// Can we convert from the sourcetype - /// to a instance ? - /// - /// - ///

- /// Currently only supports conversion from a instance. - ///

- ///
- /// - /// A - /// that provides a format context. - /// - /// - /// A that represents the - /// you want to convert from. - /// - /// if the conversion is possible. - public override bool CanConvertFrom( - ITypeDescriptorContext context, Type sourceType) + /// + /// Convert from a value to an + /// instance. + /// + /// + /// A + /// that provides a format context. + /// + /// + /// The to use + /// as the current culture. + /// + /// + /// The value that is to be converted. + /// + /// + /// A instance if successful. + /// + public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) + { + if (value is string) { - return (sourceType == typeof(string)); - } + string credentials = (string) value; + Match m = credentialRegex.Match(credentials); - /// - /// Convert from a value to an - /// instance. - /// - /// - /// A - /// that provides a format context. - /// - /// - /// The to use - /// as the current culture. - /// - /// - /// The value that is to be converted. - /// - /// - /// A instance if successful. - /// - public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) - { - if (value is string) + if (!m.Success || m.Value != credentials) { - string credentials = (string)value; - Match m = credentialRegex.Match(credentials); - - if (!m.Success || m.Value != credentials) - { - throw new ArgumentException(String.Format("The credential '{0}' is not well-formed.", value)); - } - - // Get domain - string domain = m.Groups["domain"].Value; - - // Get user name - string userName = m.Groups["userName"].Value; - - // Get password - string password = m.Groups["password"].Value; - - return new NetworkCredential(userName, password, domain); + throw new ArgumentException(String.Format("The credential '{0}' is not well-formed.", value)); } - return base.ConvertFrom(context, culture, value); + + // Get domain + string domain = m.Groups["domain"].Value; + + // Get user name + string userName = m.Groups["userName"].Value; + + // Get password + string password = m.Groups["password"].Value; + + return new NetworkCredential(userName, password, domain); } + + return base.ConvertFrom(context, culture, value); } } diff --git a/src/Spring/Spring.Core/Core/TypeConversion/CustomNumberConverter.cs b/src/Spring/Spring.Core/Core/TypeConversion/CustomNumberConverter.cs index 16641ad2..6ae02b57 100644 --- a/src/Spring/Spring.Core/Core/TypeConversion/CustomNumberConverter.cs +++ b/src/Spring/Spring.Core/Core/TypeConversion/CustomNumberConverter.cs @@ -2,13 +2,13 @@ /* * Copyright � 2002-2011 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. @@ -22,164 +22,166 @@ using System.ComponentModel; using System.Globalization; - using Spring.Util; #endregion -namespace Spring.Core.TypeConversion +namespace Spring.Core.TypeConversion; + +/// +/// A custom for any +/// primitive numeric type such as , +/// , , etc. +/// +/// +///

+/// Can use a given for +/// (locale-specific) parsing and rendering. +///

+///

+/// This is not meant to be used as a system +/// but rather as a +/// locale-specific number converter within custom controller code, to +/// parse user-entered number strings into number properties of objects, +/// and render them in a UI form. +///

+///
+/// Juergen Hoeller +/// Simon White (.NET) +public class CustomNumberConverter : TypeConverter { - /// - /// A custom for any - /// primitive numeric type such as , - /// , , etc. - /// - /// - ///

- /// Can use a given for - /// (locale-specific) parsing and rendering. - ///

- ///

- /// This is not meant to be used as a system - /// but rather as a - /// locale-specific number converter within custom controller code, to - /// parse user-entered number strings into number properties of objects, - /// and render them in a UI form. - ///

- ///
- /// Juergen Hoeller - /// Simon White (.NET) - public class CustomNumberConverter : TypeConverter - { - private Type _type; - private NumberFormatInfo _nfi; - private bool _allowEmpty; + private Type _type; + private NumberFormatInfo _nfi; + private bool _allowEmpty; - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The primitive numeric to convert to. - /// - /// - /// The to use for - /// (locale-specific) parsing and rendering - /// - /// - /// Is an empty string allowed to be converted? If - /// , an empty string value will be converted to - /// numeric 0. - /// - /// Id the supplied is not a primitive - /// . - /// - /// - public CustomNumberConverter( - Type type, NumberFormatInfo format, bool allowEmpty) - { - if (!type.IsPrimitive) - { - throw new ArgumentException( - "Property type must be a primitive type."); - } - this._type = type; - this._nfi = format; - this._allowEmpty = allowEmpty; - } + /// + /// Creates a new instance of the + /// class. + /// + /// + /// The primitive numeric to convert to. + /// + /// + /// The to use for + /// (locale-specific) parsing and rendering + /// + /// + /// Is an empty string allowed to be converted? If + /// , an empty string value will be converted to + /// numeric 0. + /// + /// Id the supplied is not a primitive + /// . + /// + /// + public CustomNumberConverter( + Type type, NumberFormatInfo format, bool allowEmpty) + { + if (!type.IsPrimitive) + { + throw new ArgumentException( + "Property type must be a primitive type."); + } - /// - /// Returns whether this converter can convert an object of one - /// to a - /// - /// - ///

- /// Currently only supports conversion from a - /// instance. - ///

- ///
- /// - /// A - /// that provides a format context. - /// - /// - /// A that represents the - /// you want to convert from. - /// - /// - /// if the conversion is possible. - /// - public override bool CanConvertFrom( - ITypeDescriptorContext context, Type sourceType) - { - if (sourceType == typeof (string)) - { - return true; - } - return base.CanConvertFrom(context, sourceType); - } + this._type = type; + this._nfi = format; + this._allowEmpty = allowEmpty; + } - /// - /// Converts the specified object (a string) to the required primitive - /// type. - /// - /// - /// A - /// that provides a format context. - /// - /// - /// The to use - /// as the current culture. - /// - /// - /// The value that is to be converted. - /// - /// A primitive representation of the string value. - public override object ConvertFrom( - ITypeDescriptorContext context, CultureInfo culture, object val) - { - if (val is string) - { - string value = val as string; - if (!StringUtils.HasText(value) - && _allowEmpty) - { - value = "0"; - } - if (_type.Equals(typeof (Int16))) - { - return Convert.ToInt16(value, _nfi); - } - else if (_type.Equals(typeof (UInt16))) - { - return Convert.ToUInt16(value, _nfi); - } - else if (_type.Equals(typeof (Int32))) - { - return Convert.ToInt32(value, _nfi); - } - else if (_type.Equals(typeof (UInt32))) - { - return Convert.ToUInt32(value, _nfi); - } - else if (_type.Equals(typeof (Int64))) - { - return Convert.ToInt64(value, _nfi); - } - else if (_type.Equals(typeof (UInt64))) - { - return Convert.ToUInt64(value, _nfi); - } - else if (_type.Equals(typeof (Single))) - { - return Convert.ToSingle(value, _nfi); - } - else if (_type.Equals(typeof (Double))) - { - return Convert.ToDouble(value, _nfi); - } - } - return base.ConvertFrom(context, culture, val); - } - } + /// + /// Returns whether this converter can convert an object of one + /// to a + /// + /// + ///

+ /// Currently only supports conversion from a + /// instance. + ///

+ ///
+ /// + /// A + /// that provides a format context. + /// + /// + /// A that represents the + /// you want to convert from. + /// + /// + /// if the conversion is possible. + /// + public override bool CanConvertFrom( + ITypeDescriptorContext context, Type sourceType) + { + if (sourceType == typeof(string)) + { + return true; + } + + return base.CanConvertFrom(context, sourceType); + } + + /// + /// Converts the specified object (a string) to the required primitive + /// type. + /// + /// + /// A + /// that provides a format context. + /// + /// + /// The to use + /// as the current culture. + /// + /// + /// The value that is to be converted. + /// + /// A primitive representation of the string value. + public override object ConvertFrom( + ITypeDescriptorContext context, CultureInfo culture, object val) + { + if (val is string) + { + string value = val as string; + if (!StringUtils.HasText(value) + && _allowEmpty) + { + value = "0"; + } + + if (_type.Equals(typeof(Int16))) + { + return Convert.ToInt16(value, _nfi); + } + else if (_type.Equals(typeof(UInt16))) + { + return Convert.ToUInt16(value, _nfi); + } + else if (_type.Equals(typeof(Int32))) + { + return Convert.ToInt32(value, _nfi); + } + else if (_type.Equals(typeof(UInt32))) + { + return Convert.ToUInt32(value, _nfi); + } + else if (_type.Equals(typeof(Int64))) + { + return Convert.ToInt64(value, _nfi); + } + else if (_type.Equals(typeof(UInt64))) + { + return Convert.ToUInt64(value, _nfi); + } + else if (_type.Equals(typeof(Single))) + { + return Convert.ToSingle(value, _nfi); + } + else if (_type.Equals(typeof(Double))) + { + return Convert.ToDouble(value, _nfi); + } + } + + return base.ConvertFrom(context, culture, val); + } } diff --git a/src/Spring/Spring.Core/Core/TypeConversion/FileInfoConverter.cs b/src/Spring/Spring.Core/Core/TypeConversion/FileInfoConverter.cs index 0d0b2cda..aa351af0 100644 --- a/src/Spring/Spring.Core/Core/TypeConversion/FileInfoConverter.cs +++ b/src/Spring/Spring.Core/Core/TypeConversion/FileInfoConverter.cs @@ -25,83 +25,86 @@ using System.Globalization; #endregion -namespace Spring.Core.TypeConversion +namespace Spring.Core.TypeConversion; + +/// +/// Converter for instances. +/// +/// Juergen Hoeller +/// Mark Pollack (.NET) +public class FileInfoConverter : TypeConverter { + #region Constructor (s) / Destructor + /// - /// Converter for instances. + /// Creates a new instance of the + /// class. /// - /// Juergen Hoeller - /// Mark Pollack (.NET) - public class FileInfoConverter : TypeConverter + public FileInfoConverter() { } + + #endregion + + #region Methods + + /// + /// Returns whether this converter can convert an object of one + /// to a + /// + /// + ///

+ /// Currently only supports conversion from a + /// instance. + ///

+ ///
+ /// + /// A + /// that provides a format context. + /// + /// + /// A that represents the + /// you want to convert from. + /// + /// True if the conversion is possible. + public override bool CanConvertFrom( + ITypeDescriptorContext context, + Type sourceType) { - #region Constructor (s) / Destructor - /// - /// Creates a new instance of the - /// class. - /// - public FileInfoConverter () {} - #endregion - - #region Methods - /// - /// Returns whether this converter can convert an object of one - /// to a - /// - /// - ///

- /// Currently only supports conversion from a - /// instance. - ///

- ///
- /// - /// A - /// that provides a format context. - /// - /// - /// A that represents the - /// you want to convert from. - /// - /// True if the conversion is possible. - public override bool CanConvertFrom ( - ITypeDescriptorContext context, - Type sourceType) + if (sourceType == typeof(string)) { - if (sourceType == typeof (string)) - { - return true; - } - return base.CanConvertFrom (context, sourceType); + return true; } - /// - /// Convert from a string value to a instance. - /// - /// - /// A - /// that provides a format context. - /// - /// - /// The to use - /// as the current culture. - /// - /// - /// The value that is to be converted. - /// - /// - /// A if successful. - /// - public override object ConvertFrom ( - ITypeDescriptorContext context, - CultureInfo culture, object value) - { - if (value is string) - { - return new FileInfo(value as string); - } - return base.ConvertFrom (context, culture, value); - } - #endregion - + return base.CanConvertFrom(context, sourceType); } + /// + /// Convert from a string value to a instance. + /// + /// + /// A + /// that provides a format context. + /// + /// + /// The to use + /// as the current culture. + /// + /// + /// The value that is to be converted. + /// + /// + /// A if successful. + /// + public override object ConvertFrom( + ITypeDescriptorContext context, + CultureInfo culture, object value) + { + if (value is string) + { + return new FileInfo(value as string); + } + + return base.ConvertFrom(context, culture, value); + } + + #endregion } diff --git a/src/Spring/Spring.Core/Core/TypeConversion/NameValueConverter.cs b/src/Spring/Spring.Core/Core/TypeConversion/NameValueConverter.cs index 0284dcfd..db6ce18d 100644 --- a/src/Spring/Spring.Core/Core/TypeConversion/NameValueConverter.cs +++ b/src/Spring/Spring.Core/Core/TypeConversion/NameValueConverter.cs @@ -27,131 +27,132 @@ using System.Xml; #endregion -namespace Spring.Core.TypeConversion +namespace Spring.Core.TypeConversion; + +/// +/// Custom implementation for +/// objects. +/// +/// +///

+/// Handles conversion from an XML formatted string to a +/// object +/// (see below for an example of the expected XML format). +///

+///

+/// This converter must be registered before it will be available. Standard +/// converters in this namespace are automatically registered by the +/// class. +///

+///
+/// +///

+/// Find below some examples of the XML formatted strings that this +/// converter will sucessfully convert. Note that the name of the top level +/// (document) element is quite arbitrary... it is only the content that +/// matters (and which must be in the format +/// <add key="..." value="..."/>. For your continued sanity +/// though, you may wish to standardize on the top level name of +/// 'dictionary' (although you are of course free to not do so). +///

+/// +/// +/// +/// +/// +/// +///

+/// The following example uses a different top level (document) element +/// name, but is equivalent to the first example. +///

+/// +/// +/// +/// +/// +/// +///
+/// Rod Johnson +/// Juergen Hoeller +/// Simon White (.NET) +public class NameValueConverter : TypeConverter { - /// - /// Custom implementation for - /// objects. - /// - /// - ///

- /// Handles conversion from an XML formatted string to a - /// object - /// (see below for an example of the expected XML format). - ///

- ///

- /// This converter must be registered before it will be available. Standard - /// converters in this namespace are automatically registered by the - /// class. - ///

- ///
- /// - ///

- /// Find below some examples of the XML formatted strings that this - /// converter will sucessfully convert. Note that the name of the top level - /// (document) element is quite arbitrary... it is only the content that - /// matters (and which must be in the format - /// <add key="..." value="..."/>. For your continued sanity - /// though, you may wish to standardize on the top level name of - /// 'dictionary' (although you are of course free to not do so). - ///

- /// - /// - /// - /// - /// - /// - ///

- /// The following example uses a different top level (document) element - /// name, but is equivalent to the first example. - ///

- /// - /// - /// - /// - /// - /// - ///
- /// Rod Johnson - /// Juergen Hoeller - /// Simon White (.NET) - public class NameValueConverter : TypeConverter - { - #region Constructor (s) / Destructor + #region Constructor (s) / Destructor - /// - /// Creates a new instance of the - /// class. - /// - public NameValueConverter() - { - } + /// + /// Creates a new instance of the + /// class. + /// + public NameValueConverter() + { + } - #endregion + #endregion - /// - /// Returns whether this converter can convert an object of one - /// to a - /// - /// - /// - ///

- /// Currently only supports conversion from an - /// XML formatted instance. - ///

- ///
- /// - /// A - /// that provides a format context. - /// - /// - /// A that represents the - /// you want to convert from. - /// - /// True if the conversion is possible. - public override bool CanConvertFrom( - ITypeDescriptorContext context, - Type sourceType) - { - if (sourceType == typeof (string)) - { - return true; - } - return base.CanConvertFrom(context, sourceType); - } + /// + /// Returns whether this converter can convert an object of one + /// to a + /// + /// + /// + ///

+ /// Currently only supports conversion from an + /// XML formatted instance. + ///

+ ///
+ /// + /// A + /// that provides a format context. + /// + /// + /// A that represents the + /// you want to convert from. + /// + /// True if the conversion is possible. + public override bool CanConvertFrom( + ITypeDescriptorContext context, + Type sourceType) + { + if (sourceType == typeof(string)) + { + return true; + } - /// - /// Convert from a string value to a - /// instance. - /// - /// - /// A - /// that provides a format context. - /// - /// - /// The to use - /// as the current culture. - /// - /// - /// The value that is to be converted. - /// - /// - /// A - /// if successful. - /// - public override object ConvertFrom( - ITypeDescriptorContext context, - CultureInfo culture, object value) - { - string text = value as string; - if (text != null) - { - XmlDocument doc = new XmlDocument(); - doc.LoadXml(text); - return new NameValueSectionHandler() - .Create(null, null, doc.DocumentElement); - } - return base.ConvertFrom(context, culture, value); - } - } + return base.CanConvertFrom(context, sourceType); + } + + /// + /// Convert from a string value to a + /// instance. + /// + /// + /// A + /// that provides a format context. + /// + /// + /// The to use + /// as the current culture. + /// + /// + /// The value that is to be converted. + /// + /// + /// A + /// if successful. + /// + public override object ConvertFrom( + ITypeDescriptorContext context, + CultureInfo culture, object value) + { + string text = value as string; + if (text != null) + { + XmlDocument doc = new XmlDocument(); + doc.LoadXml(text); + return new NameValueSectionHandler() + .Create(null, null, doc.DocumentElement); + } + + return base.ConvertFrom(context, culture, value); + } } diff --git a/src/Spring/Spring.Core/Core/TypeConversion/RGBColorConverter.cs b/src/Spring/Spring.Core/Core/TypeConversion/RGBColorConverter.cs index 0effa890..6b9e4d72 100644 --- a/src/Spring/Spring.Core/Core/TypeConversion/RGBColorConverter.cs +++ b/src/Spring/Spring.Core/Core/TypeConversion/RGBColorConverter.cs @@ -2,13 +2,13 @@ /* * Copyright � 2002-2011 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. @@ -23,129 +23,131 @@ using System.ComponentModel; using System.Drawing; using System.Globalization; - using Spring.Util; #endregion -namespace Spring.Core.TypeConversion +namespace Spring.Core.TypeConversion; + +/// +/// Converter for from a comma separated +/// list of RBG values. +/// +/// +///

+/// Please note that this class does not implement converting +/// to a comma separated list of RBG values from a +/// . +///

+///
+/// Federico Spinazzi +public sealed class RGBColorConverter : TypeConverter { + private const char ArgbSeparator = ','; + + private const string DefaultAlpha = "255"; + /// - /// Converter for from a comma separated - /// list of RBG values. + /// Returns whether this converter can convert an object of one + /// to a + /// . /// /// ///

- /// Please note that this class does not implement converting - /// to a comma separated list of RBG values from a - /// . + /// Currently only supports conversion from a + /// instance. ///

///
- /// Federico Spinazzi - public sealed class RGBColorConverter : TypeConverter + /// + /// A + /// that provides a format context. + /// + /// + /// A that represents the + /// you want to convert from. + /// + /// if the conversion is possible. + public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) { - private const char ArgbSeparator = ','; - - private const string DefaultAlpha = "255"; - - /// - /// Returns whether this converter can convert an object of one - /// to a - /// . - /// - /// - ///

- /// Currently only supports conversion from a - /// instance. - ///

- ///
- /// - /// A - /// that provides a format context. - /// - /// - /// A that represents the - /// you want to convert from. - /// - /// if the conversion is possible. - public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) + if (sourceType == typeof(string)) { - if (sourceType == typeof (string)) - { - return true; - } - return base.CanConvertFrom(context, sourceType); + return true; } - /// - /// Converts the specified object (a string) a - /// instance. - /// - /// - /// A - /// that provides a format context. - /// - /// - /// The to use - /// as the current culture: currently ignored. - /// - /// - /// The value that is to be converted, in "R,G,B", "A,R,G,B", or - /// symbolic color name (System.Drawing.KnownColor if on .NET Full Framework). - /// - /// - /// A representation of the string value. - /// - /// - /// If the input string is not in a supported format, or is not one of the - /// predefined system colors (System.Drawing.KnownColor if on .NET Full Framework). - /// - public override object ConvertFrom( - ITypeDescriptorContext context, CultureInfo culture, object value) + return base.CanConvertFrom(context, sourceType); + } + + /// + /// Converts the specified object (a string) a + /// instance. + /// + /// + /// A + /// that provides a format context. + /// + /// + /// The to use + /// as the current culture: currently ignored. + /// + /// + /// The value that is to be converted, in "R,G,B", "A,R,G,B", or + /// symbolic color name (System.Drawing.KnownColor if on .NET Full Framework). + /// + /// + /// A representation of the string value. + /// + /// + /// If the input string is not in a supported format, or is not one of the + /// predefined system colors (System.Drawing.KnownColor if on .NET Full Framework). + /// + public override object ConvertFrom( + ITypeDescriptorContext context, CultureInfo culture, object value) + { + string input = value as string; + if (StringUtils.HasText(input)) { - string input = value as string; - if (StringUtils.HasText(input)) + if (input.IndexOf(ArgbSeparator) > -1) { - if (input.IndexOf(ArgbSeparator) > -1) + string[] colorSplit = input.Split(ArgbSeparator); + if (colorSplit.Length == 3) { - string[] colorSplit = input.Split(ArgbSeparator); - if (colorSplit.Length == 3) - { - return FromRgb(colorSplit); - } - else if (colorSplit.Length == 4) - { - return FromArgb(colorSplit); - } - else - { - throw new FormatException( - "Input string is not in the correct format : '" + input + "'."); - } + return FromRgb(colorSplit); + } + else if (colorSplit.Length == 4) + { + return FromArgb(colorSplit); + } + else + { + throw new FormatException( + "Input string is not in the correct format : '" + input + "'."); } - return FromName(input); } - return base.ConvertFrom(context, culture, value); + + return FromName(input); } - private static object FromRgb(string[] rgb) - { - return GetColorFrom(DefaultAlpha, rgb[0], rgb[1], rgb[2]); - } + return base.ConvertFrom(context, culture, value); + } - private static object FromArgb(string[] argb) - { - return GetColorFrom(argb[0], argb[1], argb[2], argb[3]); - } + private static object FromRgb(string[] rgb) + { + return GetColorFrom(DefaultAlpha, rgb[0], rgb[1], rgb[2]); + } - private static Color FromName(string name) - { + private static object FromArgb(string[] argb) + { + return GetColorFrom(argb[0], argb[1], argb[2], argb[3]); + } + + private static Color FromName(string name) + { #if NETSTANDARD - throw new NotSupportedException("FromName is not supported under .NET Core"); + throw new NotSupportedException("FromName is not supported under .NET Core"); #else try { - KnownColor color = (KnownColor) Enum.Parse(typeof (KnownColor), name); + KnownColor color = (KnownColor) Enum.Parse(typeof(KnownColor), name); return Color.FromKnownColor(color); } catch (Exception ex) @@ -154,19 +156,18 @@ namespace Spring.Core.TypeConversion "Input string is not a known system color : '" + name + "'.", ex); } #endif - } + } - private static Color GetColorFrom(string alpha, string red, string green, string blue) + private static Color GetColorFrom(string alpha, string red, string green, string blue) + { + try { - try - { - return Color.FromArgb(Int32.Parse(alpha), Int32.Parse(red), Int32.Parse(green), Int32.Parse(blue)); - } - catch (Exception ex) - { - throw new FormatException( - "Bad color format.", ex); - } + return Color.FromArgb(Int32.Parse(alpha), Int32.Parse(red), Int32.Parse(green), Int32.Parse(blue)); + } + catch (Exception ex) + { + throw new FormatException( + "Bad color format.", ex); } } } diff --git a/src/Spring/Spring.Core/Core/TypeConversion/RegexConverter.cs b/src/Spring/Spring.Core/Core/TypeConversion/RegexConverter.cs index 8d1517c9..df45e4ce 100644 --- a/src/Spring/Spring.Core/Core/TypeConversion/RegexConverter.cs +++ b/src/Spring/Spring.Core/Core/TypeConversion/RegexConverter.cs @@ -26,65 +26,64 @@ using System.Text.RegularExpressions; #endregion -namespace Spring.Core.TypeConversion +namespace Spring.Core.TypeConversion; + +/// +/// Converts string representation of a regular expression into an instance of . +/// +/// Aleksandar Seovic +public class RegexConverter : TypeConverter { /// - /// Converts string representation of a regular expression into an instance of . + /// Can we convert from the sourcetype to a ? /// - /// Aleksandar Seovic - public class RegexConverter : TypeConverter + /// + ///

+ /// Currently only supports conversion from a instance. + ///

+ ///
+ /// + /// A + /// that provides a format context. + /// + /// + /// A that represents the + /// you want to convert from. + /// + /// if the conversion is possible. + public override bool CanConvertFrom( + ITypeDescriptorContext context, Type sourceType) { - /// - /// Can we convert from the sourcetype to a ? - /// - /// - ///

- /// Currently only supports conversion from a instance. - ///

- ///
- /// - /// A - /// that provides a format context. - /// - /// - /// A that represents the - /// you want to convert from. - /// - /// if the conversion is possible. - public override bool CanConvertFrom( - ITypeDescriptorContext context, Type sourceType) - { - return (sourceType == typeof(string)); - } + return (sourceType == typeof(string)); + } - /// - /// Convert from a value to an - /// instance. - /// - /// - /// A - /// that provides a format context. - /// - /// - /// The to use - /// as the current culture. - /// - /// - /// The value that is to be converted. - /// - /// - /// A if successful. - /// - public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) + /// + /// Convert from a value to an + /// instance. + /// + /// + /// A + /// that provides a format context. + /// + /// + /// The to use + /// as the current culture. + /// + /// + /// The value that is to be converted. + /// + /// + /// A if successful. + /// + public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) + { + if (value is string) { - if (value is string) - { - return new Regex(value as string); - } - else - { - return base.ConvertFrom(context, culture, value); - } + return new Regex(value as string); + } + else + { + return base.ConvertFrom(context, culture, value); } } -} +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Core/TypeConversion/RegistryKeyConverter.cs b/src/Spring/Spring.Core/Core/TypeConversion/RegistryKeyConverter.cs index 2d7f6bf2..ee6fa9b9 100644 --- a/src/Spring/Spring.Core/Core/TypeConversion/RegistryKeyConverter.cs +++ b/src/Spring/Spring.Core/Core/TypeConversion/RegistryKeyConverter.cs @@ -23,138 +23,138 @@ using System.ComponentModel; using System.Globalization; using Microsoft.Win32; - using Spring.Util; #endregion -namespace Spring.Core.TypeConversion +namespace Spring.Core.TypeConversion; + +/// +/// Converts string representation of the registry key +/// into instance. +/// +/// Aleksandar Seovic +public class RegistryKeyConverter : TypeConverter { /// - /// Converts string representation of the registry key - /// into instance. + /// Can we convert from a the sourcetype to a ? /// - /// Aleksandar Seovic - public class RegistryKeyConverter : TypeConverter + /// + ///

+ /// Currently only supports conversion from a instance. + ///

+ ///
+ /// + /// A + /// that provides a format context. + /// + /// + /// A that represents the + /// you want to convert from. + /// + /// if the conversion is possible. + public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) { - /// - /// Can we convert from a the sourcetype to a ? - /// - /// - ///

- /// Currently only supports conversion from a instance. - ///

- ///
- /// - /// A - /// that provides a format context. - /// - /// - /// A that represents the - /// you want to convert from. - /// - /// if the conversion is possible. - public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) - { - return (sourceType == typeof(string)); - } + return (sourceType == typeof(string)); + } - /// - /// Convert from a value to an - /// instance. - /// - /// - /// A - /// that provides a format context. - /// - /// - /// The to use - /// as the current culture. - /// - /// - /// The value that is to be converted. - /// - /// - /// A array if successful. - /// - public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) - { - AssertUtils.ArgumentNotNull(value, "value"); + /// + /// Convert from a value to an + /// instance. + /// + /// + /// A + /// that provides a format context. + /// + /// + /// The to use + /// as the current culture. + /// + /// + /// The value that is to be converted. + /// + /// + /// A array if successful. + /// + public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) + { + AssertUtils.ArgumentNotNull(value, "value"); - if (value is string) + if (value is string) + { + string keyName = (string) value; + AssertUtils.ArgumentHasText(keyName, "value"); + + string[] keys = StringUtils.Split(keyName, "\\", false, true); + RegistryKey key = GetRootKey(keys[0]); + for (int i = 1; i < keys.Length; i++) { - string keyName = (string) value; - AssertUtils.ArgumentHasText(keyName, "value"); - - string[] keys = StringUtils.Split(keyName, "\\", false, true); - RegistryKey key = GetRootKey(keys[0]); - for (int i = 1; i < keys.Length; i++) + // open all sub-keys but the last one as read-only + key = key.OpenSubKey(keys[i], (i == keys.Length - 1)); + if (key == null) { - // open all sub-keys but the last one as read-only - key = key.OpenSubKey(keys[i], (i == keys.Length - 1)); - if (key == null) - { - throw new ArgumentException("Registry key [" + GetPartialKeyName(keys, i) + "] does not exist."); - } + throw new ArgumentException("Registry key [" + GetPartialKeyName(keys, i) + "] does not exist."); } - - return key; } - return base.ConvertFrom(context, culture, value); + + return key; } - /// - /// Generates partial registry key name. - /// - /// - /// Key elements. - /// - /// - /// Index of the last element to use. - /// - /// - /// Friendly key name containing key element from - /// 0 to , inclusive. - /// - private static string GetPartialKeyName(string[] keys, int index) + return base.ConvertFrom(context, culture, value); + } + + /// + /// Generates partial registry key name. + /// + /// + /// Key elements. + /// + /// + /// Index of the last element to use. + /// + /// + /// Friendly key name containing key element from + /// 0 to , inclusive. + /// + private static string GetPartialKeyName(string[] keys, int index) + { + string keyName = ""; + for (int i = 0; i <= index; i++) { - string keyName = ""; - for (int i = 0; i <= index; i++) - { - keyName += (keys[i] + (i < index ? "\\" : "")); - } - return keyName; + keyName += (keys[i] + (i < index ? "\\" : "")); } - /// - /// Returns for the specified - /// root hive name. - /// - /// - /// Root hive name. - /// - /// - /// Registry key for the specified name. - /// - private static RegistryKey GetRootKey(string name) + return keyName; + } + + /// + /// Returns for the specified + /// root hive name. + /// + /// + /// Root hive name. + /// + /// + /// Registry key for the specified name. + /// + private static RegistryKey GetRootKey(string name) + { + switch (name) { - switch (name) - { - case "HKEY_CURRENT_USER": - return Registry.CurrentUser; - case "HKEY_LOCAL_MACHINE": - return Registry.LocalMachine; - case "HKEY_CLASSES_ROOT": - return Registry.ClassesRoot; - case "HKEY_USERS": - return Registry.Users; - case "HKEY_PERFORMANCE_DATA": - return Registry.PerformanceData; - case "HKEY_CURRENT_CONFIG": - return Registry.CurrentConfig; - default: - throw new ArgumentException("Invalid root hive name [" + name + "]."); - } + case "HKEY_CURRENT_USER": + return Registry.CurrentUser; + case "HKEY_LOCAL_MACHINE": + return Registry.LocalMachine; + case "HKEY_CLASSES_ROOT": + return Registry.ClassesRoot; + case "HKEY_USERS": + return Registry.Users; + case "HKEY_PERFORMANCE_DATA": + return Registry.PerformanceData; + case "HKEY_CURRENT_CONFIG": + return Registry.CurrentConfig; + default: + throw new ArgumentException("Invalid root hive name [" + name + "]."); } } } diff --git a/src/Spring/Spring.Core/Core/TypeConversion/ResourceManagerConverter.cs b/src/Spring/Spring.Core/Core/TypeConversion/ResourceManagerConverter.cs index 95495397..46de20f7 100644 --- a/src/Spring/Spring.Core/Core/TypeConversion/ResourceManagerConverter.cs +++ b/src/Spring/Spring.Core/Core/TypeConversion/ResourceManagerConverter.cs @@ -15,6 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + #endregion #region Imports @@ -28,126 +29,136 @@ using Spring.Util; #endregion -namespace Spring.Core.TypeConversion +namespace Spring.Core.TypeConversion; + +/// +/// Converts a two part string, (resource name, assembly name) +/// to a ResourceManager instance. +/// +public class ResourceManagerConverter : TypeConverter { - /// - /// Converts a two part string, (resource name, assembly name) - /// to a ResourceManager instance. - /// - public class ResourceManagerConverter : TypeConverter - { - /// - /// This constant represents the name of the folder/assembly containing global resources. - /// - public static readonly string APP_GLOBALRESOURCES_ASSEMBLYNAME = "App_GlobalResources"; + /// + /// This constant represents the name of the folder/assembly containing global resources. + /// + public static readonly string APP_GLOBALRESOURCES_ASSEMBLYNAME = "App_GlobalResources"; - #region Constructor (s) / Destructor - /// - /// Creates a new instance of the - /// class. - /// - public ResourceManagerConverter() + #region Constructor (s) / Destructor + + /// + /// Creates a new instance of the + /// class. + /// + public ResourceManagerConverter() + { + } + + #endregion + + #region Methods + + /// + /// Returns whether this converter can convert an object of one + /// to a + /// + /// + /// + ///

+ /// Currently only supports conversion from a + /// instance. + ///

+ ///
+ /// + /// A + /// that provides a format context. + /// + /// + /// A that represents the + /// you want to convert from. + /// + /// True if the conversion is possible. + public override bool CanConvertFrom( + ITypeDescriptorContext context, + Type sourceType) + { + if (sourceType == typeof(string)) { + return true; } - #endregion - #region Methods - /// - /// Returns whether this converter can convert an object of one - /// to a - /// - /// - /// - ///

- /// Currently only supports conversion from a - /// instance. - ///

- ///
- /// - /// A - /// that provides a format context. - /// - /// - /// A that represents the - /// you want to convert from. - /// - /// True if the conversion is possible. - public override bool CanConvertFrom ( - ITypeDescriptorContext context, - Type sourceType) + return base.CanConvertFrom(context, sourceType); + } + + /// + /// Convert from a string value to a + /// instance. + /// + /// + /// A + /// that provides a format context. + /// + /// + /// The to use + /// as the current culture. + /// + /// + /// The value that is to be converted. + /// + /// + /// A + /// if successful. + /// + /// If the specified does not denote a valid resource + public override object ConvertFrom( + ITypeDescriptorContext context, + CultureInfo culture, object value) + { + if (value is string) { - if (sourceType == typeof(string)) + // convert incoming string into ResourceManager... + string[] resourceManagerDescription = StringUtils.DelimitedListToStringArray((string) value, ","); + if (resourceManagerDescription.Length != 2) { - return true; + throw new ArgumentException("The string to specify a ResourceManager must be a comma delimited list of length two. i.e. resourcename, assembly parial name."); } - return base.CanConvertFrom(context, sourceType); + + string resourceName = resourceManagerDescription[0].Trim(); + if (resourceName != null && resourceName.Length == 0) + { + throw new ArgumentException("Empty value set for the resource name in ResourceManager string."); + } + + string assemblyName = resourceManagerDescription[1].Trim(); + if (assemblyName != null && assemblyName.Length == 0) + { + throw new ArgumentException("Empty value set for the assembly name in ResourceManager string."); + } + + if (assemblyName == APP_GLOBALRESOURCES_ASSEMBLYNAME) + { + try + { + Type globalResourcesType = TypeResolutionUtils.ResolveType(resourceName); + // look both, NonPublic and Public properties (SPRNET-861) + PropertyInfo resourceManagerProperty = globalResourcesType.GetProperty("ResourceManager", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static); + return (ResourceManager) resourceManagerProperty.GetValue(globalResourcesType, null); + } + catch (TypeLoadException ex) + { + throw new ArgumentException("Could not load resources '{0}'", resourceName, ex); + } + } + + Assembly ass = Assembly.LoadWithPartialName(assemblyName); + if (ass == null) + { + throw new ArgumentException("Could not find assembly with name = '" + assemblyName + "'."); + } + + return new ResourceManager(resourceName, ass); } - /// - /// Convert from a string value to a - /// instance. - /// - /// - /// A - /// that provides a format context. - /// - /// - /// The to use - /// as the current culture. - /// - /// - /// The value that is to be converted. - /// - /// - /// A - /// if successful. - /// - /// If the specified does not denote a valid resource - public override object ConvertFrom ( - ITypeDescriptorContext context, - CultureInfo culture, object value) - { - if (value is string) - { - // convert incoming string into ResourceManager... - string[] resourceManagerDescription = StringUtils.DelimitedListToStringArray((string)value, ","); - if (resourceManagerDescription.Length != 2) - { - throw new ArgumentException ("The string to specify a ResourceManager must be a comma delimited list of length two. i.e. resourcename, assembly parial name."); - } - string resourceName = resourceManagerDescription[0].Trim(); - if (resourceName != null && resourceName.Length == 0) - { - throw new ArgumentException("Empty value set for the resource name in ResourceManager string."); - } - string assemblyName = resourceManagerDescription[1].Trim(); - if (assemblyName != null && assemblyName.Length == 0) - { - throw new ArgumentException("Empty value set for the assembly name in ResourceManager string."); - } - if (assemblyName == APP_GLOBALRESOURCES_ASSEMBLYNAME) - { - try - { - Type globalResourcesType = TypeResolutionUtils.ResolveType(resourceName); - // look both, NonPublic and Public properties (SPRNET-861) - PropertyInfo resourceManagerProperty = globalResourcesType.GetProperty("ResourceManager", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static); - return (ResourceManager) resourceManagerProperty.GetValue(globalResourcesType, null); - } - catch (TypeLoadException ex) - { - throw new ArgumentException("Could not load resources '{0}'", resourceName, ex); - } - } - Assembly ass = Assembly.LoadWithPartialName(assemblyName); - if (ass == null) - { - throw new ArgumentException("Could not find assembly with name = '" + assemblyName + "'."); - } - return new ResourceManager(resourceName, ass); - } - return base.ConvertFrom (context, culture, value); - } - #endregion - } -} + return base.ConvertFrom(context, culture, value); + } + + #endregion +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Core/TypeConversion/RuntimeTypeConverter.cs b/src/Spring/Spring.Core/Core/TypeConversion/RuntimeTypeConverter.cs index f331aa29..2d1134c0 100644 --- a/src/Spring/Spring.Core/Core/TypeConversion/RuntimeTypeConverter.cs +++ b/src/Spring/Spring.Core/Core/TypeConversion/RuntimeTypeConverter.cs @@ -22,151 +22,156 @@ using System.ComponentModel; using System.Globalization; - using Spring.Core.TypeResolution; #endregion -namespace Spring.Core.TypeConversion -{ +namespace Spring.Core.TypeConversion; - /// - /// A custom for - /// runtime type references. +/// +/// A custom for +/// runtime type references. +/// +/// +///

+/// Currently only supports conversion to and from a +/// . +///

+///
+/// Rick Evans (.NET) +public class RuntimeTypeConverter : TypeConverter +{ + #region Constructor (s) / Destructor + + /// + /// Creates a new instance of the + /// class. + /// + public RuntimeTypeConverter() { } + + #endregion + + #region Methods + + /// + /// Returns whether this converter can convert an object of one + /// to the + /// of this converter. /// /// ///

- /// Currently only supports conversion to and from a - /// . + /// Currently only supports conversion from a + /// instance. ///

///
- /// Rick Evans (.NET) - public class RuntimeTypeConverter : TypeConverter + /// + /// A + /// that provides a format context. + /// + /// + /// A that represents the + /// you want to convert from. + /// + /// True if the conversion is possible. + public override bool CanConvertFrom( + ITypeDescriptorContext context, + Type sourceType) { - #region Constructor (s) / Destructor - /// - /// Creates a new instance of the - /// class. - /// - public RuntimeTypeConverter () {} - #endregion - - #region Methods - /// - /// Returns whether this converter can convert an object of one - /// to the - /// of this converter. - /// - /// - ///

- /// Currently only supports conversion from a - /// instance. - ///

- ///
- /// - /// A - /// that provides a format context. - /// - /// - /// A that represents the - /// you want to convert from. - /// - /// True if the conversion is possible. - public override bool CanConvertFrom ( - ITypeDescriptorContext context, - Type sourceType) + if (sourceType == typeof(string)) { - if (sourceType == typeof (string)) - { - return true; - } - return base.CanConvertFrom (context, sourceType); + return true; } - /// - /// Returns whether this converter can convert the object to the specified - /// . - /// - /// - /// A - /// that provides a format context. - /// - /// - /// A that represents the - /// you want to convert to. - /// - /// True if the conversion is possible. - public override bool CanConvertTo ( - ITypeDescriptorContext context, Type destinationType) + return base.CanConvertFrom(context, sourceType); + } + + /// + /// Returns whether this converter can convert the object to the specified + /// . + /// + /// + /// A + /// that provides a format context. + /// + /// + /// A that represents the + /// you want to convert to. + /// + /// True if the conversion is possible. + public override bool CanConvertTo( + ITypeDescriptorContext context, Type destinationType) + { + if (destinationType == typeof(Type)) { - if (destinationType == typeof (Type)) - { - return true; - } - return base.CanConvertTo (context, destinationType); + return true; } - /// - /// Converts the given value to the type of this converter. - /// - /// - /// A - /// that provides a format context. - /// - /// - /// The to use - /// as the current culture. - /// - /// - /// The value that is to be converted. - /// - /// - /// An that represents the converted value. - /// - public override object ConvertFrom ( - ITypeDescriptorContext context, - CultureInfo culture, object value) + return base.CanConvertTo(context, destinationType); + } + + /// + /// Converts the given value to the type of this converter. + /// + /// + /// A + /// that provides a format context. + /// + /// + /// The to use + /// as the current culture. + /// + /// + /// The value that is to be converted. + /// + /// + /// An that represents the converted value. + /// + public override object ConvertFrom( + ITypeDescriptorContext context, + CultureInfo culture, object value) + { + if (value is string) { - if (value is string) - { - return TypeResolutionUtils.ResolveType(value as string); - } - return base.ConvertFrom(context, culture, value); + return TypeResolutionUtils.ResolveType(value as string); } - /// - /// Converts the given value object to the specified type, - /// using the specified context and culture information. - /// - /// - /// A - /// that provides a format context. - /// - /// - /// The to use - /// as the current culture. - /// - /// - /// The value that is to be converted. - /// - /// - /// The to convert the - /// parameter to. - /// - /// - /// An that represents the converted value. - /// - public override object ConvertTo ( - ITypeDescriptorContext context, - CultureInfo culture, object value, Type destinationType) - { - if (value is Type - && destinationType == typeof (string)) - { - return ((Type) value).AssemblyQualifiedName; - } - return base.ConvertTo (context, culture, value, destinationType); + return base.ConvertFrom(context, culture, value); + } + + /// + /// Converts the given value object to the specified type, + /// using the specified context and culture information. + /// + /// + /// A + /// that provides a format context. + /// + /// + /// The to use + /// as the current culture. + /// + /// + /// The value that is to be converted. + /// + /// + /// The to convert the + /// parameter to. + /// + /// + /// An that represents the converted value. + /// + public override object ConvertTo( + ITypeDescriptorContext context, + CultureInfo culture, object value, Type destinationType) + { + if (value is Type + && destinationType == typeof(string)) + { + return ((Type) value).AssemblyQualifiedName; } - #endregion - } + + return base.ConvertTo(context, culture, value, destinationType); + } + + #endregion } diff --git a/src/Spring/Spring.Core/Core/TypeConversion/StreamConverter.cs b/src/Spring/Spring.Core/Core/TypeConversion/StreamConverter.cs index 420b0565..37948e65 100644 --- a/src/Spring/Spring.Core/Core/TypeConversion/StreamConverter.cs +++ b/src/Spring/Spring.Core/Core/TypeConversion/StreamConverter.cs @@ -22,104 +22,109 @@ using System.ComponentModel; using System.Globalization; - using Spring.Core.IO; #endregion -namespace Spring.Core.TypeConversion +namespace Spring.Core.TypeConversion; + +/// +/// Converter for to directly set a +/// property. +/// +/// Jurgen Hoeller +/// Mark Pollack (.NET) +public class StreamConverter : TypeConverter { - /// - /// Converter for to directly set a - /// property. - /// - /// Jurgen Hoeller - /// Mark Pollack (.NET) - public class StreamConverter : TypeConverter - { - private ResourceConverter resourceConverter; + private ResourceConverter resourceConverter; - #region Constructors - /// - /// Create a new StreamConverter using the default - /// . - /// - public StreamConverter() : this (new ResourceConverter()) - { - } + #region Constructors - /// - /// Create a new StreamConverter using the given - /// . - /// - /// - /// The to use. - public StreamConverter(ResourceConverter resourceConverter) + /// + /// Create a new StreamConverter using the default + /// . + /// + public StreamConverter() : this(new ResourceConverter()) + { + } + + /// + /// Create a new StreamConverter using the given + /// . + /// + /// + /// The to use. + public StreamConverter(ResourceConverter resourceConverter) + { + this.resourceConverter = resourceConverter == null + ? new ResourceConverter() + : resourceConverter; + } + + #endregion + + #region Methods + + /// + /// Returns whether this converter can convert an object of one + /// to a + /// + /// + ///

+ /// Currently only supports conversion from a + /// instance. + ///

+ ///
+ /// + /// A + /// that provides a format context. + /// + /// + /// A that represents the + /// you want to convert from. + /// + /// True if the conversion is possible. + public override bool CanConvertFrom( + ITypeDescriptorContext context, + Type sourceType) + { + if (sourceType == typeof(string)) { - this.resourceConverter = resourceConverter == null - ? new ResourceConverter() : resourceConverter; - } - #endregion - - #region Methods - /// - /// Returns whether this converter can convert an object of one - /// to a - /// - /// - ///

- /// Currently only supports conversion from a - /// instance. - ///

- ///
- /// - /// A - /// that provides a format context. - /// - /// - /// A that represents the - /// you want to convert from. - /// - /// True if the conversion is possible. - public override bool CanConvertFrom ( - ITypeDescriptorContext context, - Type sourceType) - { - if (sourceType == typeof (string)) - { - return true; - } - return base.CanConvertFrom (context, sourceType); + return true; } - /// - /// Convert from a string value to a instance. - /// - /// - /// A - /// that provides a format context. - /// - /// - /// The to use - /// as the current culture. - /// - /// - /// The value that is to be converted. - /// - /// - /// A if successful. - /// - public override object ConvertFrom ( - ITypeDescriptorContext context, - CultureInfo culture, object val) + return base.CanConvertFrom(context, sourceType); + } + + /// + /// Convert from a string value to a instance. + /// + /// + /// A + /// that provides a format context. + /// + /// + /// The to use + /// as the current culture. + /// + /// + /// The value that is to be converted. + /// + /// + /// A if successful. + /// + public override object ConvertFrom( + ITypeDescriptorContext context, + CultureInfo culture, object val) + { + if (val is string) { - if (val is string) - { - IResource resource = (IResource) resourceConverter.ConvertFrom(context, culture, val); - return resource.InputStream; - } - return base.ConvertFrom (context, culture, val); + IResource resource = (IResource) resourceConverter.ConvertFrom(context, culture, val); + return resource.InputStream; } - #endregion - } -} + + return base.ConvertFrom(context, culture, val); + } + + #endregion +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Core/TypeConversion/StringArrayConverter.cs b/src/Spring/Spring.Core/Core/TypeConversion/StringArrayConverter.cs index b406fae3..139e1225 100644 --- a/src/Spring/Spring.Core/Core/TypeConversion/StringArrayConverter.cs +++ b/src/Spring/Spring.Core/Core/TypeConversion/StringArrayConverter.cs @@ -22,160 +22,161 @@ using System.ComponentModel; using System.Globalization; - using Spring.Util; #endregion -namespace Spring.Core.TypeConversion +namespace Spring.Core.TypeConversion; + +/// +/// Converts a separated to a +/// array. +/// +/// +///

+/// Defaults to using the , (comma) as the list separator. Note that the value +/// of the current is +/// not used. +///

+///

+/// If you want to provide your own list separator, you can set the value of the +/// +/// property to the value that you want. Please note that this value will be used +/// for all future conversions in preference to the default list separator. +///

+///

+/// Please note that the individual elements of a string will be passed +/// through as is (i.e. no conversion or trimming of surrounding +/// whitespace will be performed). +///

+///

+/// This should be +/// automatically registered with any +/// implementations. +///

+///
+/// +/// +/// public class StringArrayConverterExample +/// { +/// public static void Main() +/// { +/// StringArrayConverter converter = new StringArrayConverter(); +/// +/// string csvWords = "This,Is,It"; +/// string[] frankBoothWords = converter.ConvertFrom(csvWords); +/// +/// // the 'frankBoothWords' array will have 3 elements, namely +/// // "This", "Is", "It". +/// +/// // please note that extraneous whitespace is NOT trimmed off +/// // in the current implementation... +/// string csv = " Cogito ,ergo ,sum "; +/// string[] descartesWords = converter.ConvertFrom(csv); +/// +/// // the 'descartesWords' array will have 3 elements, namely +/// // " Cogito ", "ergo ", "sum ". +/// // notice how the whitespace has NOT been trimmed. +/// } +/// } +/// +/// +/// +public class StringArrayConverter : TypeConverter { - /// - /// Converts a separated to a - /// array. - /// - /// - ///

- /// Defaults to using the , (comma) as the list separator. Note that the value - /// of the current is - /// not used. - ///

- ///

- /// If you want to provide your own list separator, you can set the value of the - /// - /// property to the value that you want. Please note that this value will be used - /// for all future conversions in preference to the default list separator. - ///

- ///

- /// Please note that the individual elements of a string will be passed - /// through as is (i.e. no conversion or trimming of surrounding - /// whitespace will be performed). - ///

- ///

- /// This should be - /// automatically registered with any - /// implementations. - ///

- ///
- /// - /// - /// public class StringArrayConverterExample - /// { - /// public static void Main() - /// { - /// StringArrayConverter converter = new StringArrayConverter(); - /// - /// string csvWords = "This,Is,It"; - /// string[] frankBoothWords = converter.ConvertFrom(csvWords); - /// - /// // the 'frankBoothWords' array will have 3 elements, namely - /// // "This", "Is", "It". - /// - /// // please note that extraneous whitespace is NOT trimmed off - /// // in the current implementation... - /// string csv = " Cogito ,ergo ,sum "; - /// string[] descartesWords = converter.ConvertFrom(csv); - /// - /// // the 'descartesWords' array will have 3 elements, namely - /// // " Cogito ", "ergo ", "sum ". - /// // notice how the whitespace has NOT been trimmed. - /// } - /// } - /// - /// - /// - public class StringArrayConverter : TypeConverter - { - private const string DefaultListSeparator = ","; + private const string DefaultListSeparator = ","; - private string listSeparator = DefaultListSeparator; + private string listSeparator = DefaultListSeparator; - /// - /// The value that will be used as the list separator when performing - /// conversions. - /// - /// - /// A 'single' string character that will be used as the list separator - /// when performing conversions. - /// - /// - /// If the supplied value is not and is an empty - /// string, or has more than one character. - /// - public string ListSeparator - { - get { return this.listSeparator; } - set - { - if (value != null) - { - if (value.Length != 1) - { - throw new ArgumentException( - "The 'ListSeparator' must be exactly one character in length."); - } - listSeparator = value; - } - else - { - listSeparator = DefaultListSeparator; - } - } - } + /// + /// The value that will be used as the list separator when performing + /// conversions. + /// + /// + /// A 'single' string character that will be used as the list separator + /// when performing conversions. + /// + /// + /// If the supplied value is not and is an empty + /// string, or has more than one character. + /// + public string ListSeparator + { + get { return this.listSeparator; } + set + { + if (value != null) + { + if (value.Length != 1) + { + throw new ArgumentException( + "The 'ListSeparator' must be exactly one character in length."); + } - /// - /// Can we convert from a the sourcetype to a array? - /// - /// - ///

- /// Currently only supports conversion from a instance. - ///

- ///
- /// - /// A - /// that provides a format context. - /// - /// - /// A that represents the - /// you want to convert from. - /// - /// if the conversion is possible. - public override bool CanConvertFrom( - ITypeDescriptorContext context, Type sourceType) - { - if (sourceType == typeof (string)) - { - return true; - } - return base.CanConvertFrom(context, sourceType); - } + listSeparator = value; + } + else + { + listSeparator = DefaultListSeparator; + } + } + } - /// - /// Convert from a value to a - /// array. - /// - /// - /// A - /// that provides a format context. - /// - /// - /// The to use - /// as the current culture. - /// - /// - /// The value that is to be converted. - /// - /// - /// A array if successful. - /// - public override object ConvertFrom( - ITypeDescriptorContext context, CultureInfo culture, object value) - { - string values = value as string; - if (values != null) - { - return StringUtils.DelimitedListToStringArray(values, this.ListSeparator); - } - return base.ConvertFrom(context, culture, value); - } - } + /// + /// Can we convert from a the sourcetype to a array? + /// + /// + ///

+ /// Currently only supports conversion from a instance. + ///

+ ///
+ /// + /// A + /// that provides a format context. + /// + /// + /// A that represents the + /// you want to convert from. + /// + /// if the conversion is possible. + public override bool CanConvertFrom( + ITypeDescriptorContext context, Type sourceType) + { + if (sourceType == typeof(string)) + { + return true; + } + + return base.CanConvertFrom(context, sourceType); + } + + /// + /// Convert from a value to a + /// array. + /// + /// + /// A + /// that provides a format context. + /// + /// + /// The to use + /// as the current culture. + /// + /// + /// The value that is to be converted. + /// + /// + /// A array if successful. + /// + public override object ConvertFrom( + ITypeDescriptorContext context, CultureInfo culture, object value) + { + string values = value as string; + if (values != null) + { + return StringUtils.DelimitedListToStringArray(values, this.ListSeparator); + } + + return base.ConvertFrom(context, culture, value); + } } diff --git a/src/Spring/Spring.Core/Core/TypeConversion/TimeSpanConverter.cs b/src/Spring/Spring.Core/Core/TypeConversion/TimeSpanConverter.cs index 1f8b8120..a7ea842f 100644 --- a/src/Spring/Spring.Core/Core/TypeConversion/TimeSpanConverter.cs +++ b/src/Spring/Spring.Core/Core/TypeConversion/TimeSpanConverter.cs @@ -26,240 +26,233 @@ using System.Text.RegularExpressions; #endregion -namespace Spring.Core.TypeConversion +namespace Spring.Core.TypeConversion; + +#region Specifier parsers + +using TimeSpanNullable = Nullable; + +/// +/// Base parser for custom specifiers. +/// +abstract class SpecifierParser { - #region Specifier parsers - - using TimeSpanNullable = Nullable; + const RegexOptions ParsingOptions = RegexOptions.IgnorePatternWhitespace | RegexOptions.Singleline | RegexOptions.IgnoreCase; /// - /// Base parser for custom specifiers. + /// Specifier /// - abstract class SpecifierParser + public abstract string Specifier { get; } + + /// + /// Convert int value to a Timespan based on the specifier + /// + /// + /// + public abstract TimeSpan Parse(int value); + + /// + /// Check if the string contains the specifier and + /// + /// + /// + public TimeSpanNullable Match(string value) { - const RegexOptions ParsingOptions = RegexOptions.IgnorePatternWhitespace | RegexOptions.Singleline | RegexOptions.IgnoreCase; + string regex = @"^(\d+)" + Specifier + "$"; + Match match = Regex.Match(value, regex, ParsingOptions); - /// - /// Specifier - /// - public abstract string Specifier { get; } + if (!match.Success) return new TimeSpanNullable(); - /// - /// Convert int value to a Timespan based on the specifier - /// - /// - /// - public abstract TimeSpan Parse(int value); - - /// - /// Check if the string contains the specifier and - /// - /// - /// - public TimeSpanNullable Match(string value) - { - string regex = @"^(\d+)" + Specifier + "$"; - Match match = Regex.Match(value, regex, ParsingOptions); - - if (!match.Success) return new TimeSpanNullable(); - - return new TimeSpanNullable(Parse(int.Parse(match.Groups[1].Value))); - } + return new TimeSpanNullable(Parse(int.Parse(match.Groups[1].Value))); + } +} +/// +/// Recognize 10d as ten days +/// +class DaySpecifier : SpecifierParser +{ + /// + /// Day specifier: d + /// + public override string Specifier + { + get { return "d"; } } /// - /// Recognize 10d as ten days + /// Parse value as days /// - class DaySpecifier: SpecifierParser + /// Timespan in days + /// + public override TimeSpan Parse(int value) { - /// - /// Day specifier: d - /// - public override string Specifier - { - get { return "d"; } - } + return TimeSpan.FromDays(value); + } +} - /// - /// Parse value as days - /// - /// Timespan in days - /// - public override TimeSpan Parse(int value) - { - return TimeSpan.FromDays(value); - } +/// +/// Recognize 10h as ten hours +/// +class HourSpecifier : SpecifierParser +{ + /// + /// Hour specifier: h + /// + public override string Specifier + { + get { return "h"; } } /// - /// Recognize 10h as ten hours + /// Parse value as hours /// - class HourSpecifier : SpecifierParser + /// Timespan in hours + /// + public override TimeSpan Parse(int value) { - /// - /// Hour specifier: h - /// - public override string Specifier - { - get { return "h"; } - } + return TimeSpan.FromHours(value); + } +} - /// - /// Parse value as hours - /// - /// Timespan in hours - /// - public override TimeSpan Parse(int value) - { - return TimeSpan.FromHours(value); - } +/// +/// Recognize 10m as ten minutes +/// +class MinuteSpecifier : SpecifierParser +{ + /// + /// Minute specifier: m + /// + public override string Specifier + { + get { return "m"; } } /// - /// Recognize 10m as ten minutes + /// Parse value as minutes /// - class MinuteSpecifier : SpecifierParser + /// Timespan in minutes + /// + public override TimeSpan Parse(int value) { - /// - /// Minute specifier: m - /// - public override string Specifier - { - get { return "m"; } - } + return TimeSpan.FromMinutes(value); + } +} - /// - /// Parse value as minutes - /// - /// Timespan in minutes - /// - public override TimeSpan Parse(int value) - { - return TimeSpan.FromMinutes(value); - } +/// +/// Recognize 10s as ten seconds +/// +class SecondSpecifier : SpecifierParser +{ + /// + /// Second specifier: s + /// + public override string Specifier + { + get { return "s"; } } /// - /// Recognize 10s as ten seconds + /// Parse value as seconds /// - class SecondSpecifier : SpecifierParser + /// Timespan in seconds + /// + public override TimeSpan Parse(int value) { - /// - /// Second specifier: s - /// - public override string Specifier - { - get { return "s"; } - } + return TimeSpan.FromSeconds(value); + } +} - /// - /// Parse value as seconds - /// - /// Timespan in seconds - /// - public override TimeSpan Parse(int value) - { - return TimeSpan.FromSeconds(value); - } +/// +/// Recognize 10ms as ten milliseconds +/// +class MillisecondSpecifier : SpecifierParser +{ + /// + /// Millisecond specifier: ms + /// + public override string Specifier + { + get { return "ms"; } } /// - /// Recognize 10ms as ten milliseconds + /// Parse value as milliseconds /// - class MillisecondSpecifier : SpecifierParser + /// Timespan in milliseconds + /// + public override TimeSpan Parse(int value) { - /// - /// Millisecond specifier: ms - /// - public override string Specifier - { - get { return "ms"; } - } - - /// - /// Parse value as milliseconds - /// - /// Timespan in milliseconds - /// - public override TimeSpan Parse(int value) - { - return TimeSpan.FromMilliseconds(value); - } + return TimeSpan.FromMilliseconds(value); } +} + +#endregion + +/// +/// Converter for instances. +/// +/// Bruno Baia +/// Roberto Paterlini +public class TimeSpanConverter : System.ComponentModel.TimeSpanConverter +{ + #region Constants + + static readonly SpecifierParser[] Specifiers = { new DaySpecifier(), new HourSpecifier(), new MinuteSpecifier(), new SecondSpecifier(), new MillisecondSpecifier() }; #endregion + #region Constructor (s) / Destructor + /// - /// Converter for instances. + /// Creates a new instance of the + /// class. /// - /// Bruno Baia - /// Roberto Paterlini - public class TimeSpanConverter : System.ComponentModel.TimeSpanConverter + public TimeSpanConverter() { } + + #endregion + + #region Methods + + /// + /// Convert from a string value to a instance. + /// + /// + /// A + /// that provides a format context. + /// + /// + /// The to use + /// as the current culture. + /// + /// + /// The value that is to be converted. + /// + /// + /// A if successful. + /// + public override object ConvertFrom( + ITypeDescriptorContext context, + CultureInfo culture, object value) { - #region Constants - - static readonly SpecifierParser[] Specifiers = { - new DaySpecifier(), - new HourSpecifier(), - new MinuteSpecifier(), - new SecondSpecifier(), - new MillisecondSpecifier() - }; - - #endregion - - #region Constructor (s) / Destructor - - /// - /// Creates a new instance of the - /// class. - /// - public TimeSpanConverter() { } - - #endregion - - #region Methods - - /// - /// Convert from a string value to a instance. - /// - /// - /// A - /// that provides a format context. - /// - /// - /// The to use - /// as the current culture. - /// - /// - /// The value that is to be converted. - /// - /// - /// A if successful. - /// - public override object ConvertFrom( - ITypeDescriptorContext context, - CultureInfo culture, object value) + string stringValue = value as string; + if (stringValue != null) { - string stringValue = value as string; - if (stringValue!=null) + try { - try - { - stringValue = stringValue.Trim(); + stringValue = stringValue.Trim(); - foreach (SpecifierParser specifierParser in Specifiers) - { - TimeSpanNullable res = specifierParser.Match(stringValue); - if (res.HasValue) return res.Value; - } + foreach (SpecifierParser specifierParser in Specifiers) + { + TimeSpanNullable res = specifierParser.Match(stringValue); + if (res.HasValue) return res.Value; } - catch { } } - return base.ConvertFrom(context, culture, value); + catch { } } - #endregion + return base.ConvertFrom(context, culture, value); } + + #endregion } diff --git a/src/Spring/Spring.Core/Core/TypeConversion/TypeConversionUtils.cs b/src/Spring/Spring.Core/Core/TypeConversion/TypeConversionUtils.cs index 0da3486e..d8b0bfe1 100644 --- a/src/Spring/Spring.Core/Core/TypeConversion/TypeConversionUtils.cs +++ b/src/Spring/Spring.Core/Core/TypeConversion/TypeConversionUtils.cs @@ -27,181 +27,172 @@ using System.Reflection; #endregion -namespace Spring.Core.TypeConversion +namespace Spring.Core.TypeConversion; + +/// +/// Utility methods that are used to convert objects from one type into another. +/// +/// Aleksandar Seovic +public class TypeConversionUtils { /// - /// Utility methods that are used to convert objects from one type into another. + /// Convert the value to the required (if necessary from a string). /// - /// Aleksandar Seovic - public class TypeConversionUtils + /// The proposed change value. + /// + /// The we must convert to. + /// + /// Property name, used for error reporting purposes... + /// + /// If there is an internal error. + /// + /// The new value, possibly the result of type conversion. + public static object ConvertValueIfNecessary(Type requiredType, object newValue, string propertyName) { - /// - /// Convert the value to the required (if necessary from a string). - /// - /// The proposed change value. - /// - /// The we must convert to. - /// - /// Property name, used for error reporting purposes... - /// - /// If there is an internal error. - /// - /// The new value, possibly the result of type conversion. - public static object ConvertValueIfNecessary(Type requiredType, object newValue, string propertyName) + if (newValue != null) { - if (newValue != null) + // if it is assignable, return the value right away + if (IsAssignableFrom(newValue, requiredType)) { - // if it is assignable, return the value right away - if (IsAssignableFrom(newValue, requiredType)) - { - return newValue; - } + return newValue; + } - // if required type is an array, convert all the elements - if (requiredType != null && requiredType.IsArray) + // if required type is an array, convert all the elements + if (requiredType != null && requiredType.IsArray) + { + // convert individual elements to array elements + Type componentType = requiredType.GetElementType(); + if (newValue is ICollection) { - // convert individual elements to array elements - Type componentType = requiredType.GetElementType(); - if (newValue is ICollection) - { - ICollection elements = (ICollection)newValue; - return ToArrayWithTypeConversion(componentType, elements, propertyName); - } - else if (newValue is string) - { - if (requiredType.Equals(typeof(char[]))) - { - return ((string)newValue).ToCharArray(); - } - else - { - string[] elements = StringUtils.CommaDelimitedListToStringArray((string)newValue); - return ToArrayWithTypeConversion(componentType, elements, propertyName); - } - } - else if (!newValue.GetType().IsArray) - { - // A plain value: convert it to an array with a single component. - Array result = Array.CreateInstance(componentType, 1); - object val = ConvertValueIfNecessary(componentType, newValue, propertyName); - result.SetValue(val, 0); - return result; - } + ICollection elements = (ICollection) newValue; + return ToArrayWithTypeConversion(componentType, elements, propertyName); } - // if required type is some ISet, convert all the elements - if (requiredType != null && requiredType.IsGenericType && TypeImplementsGenericInterface(requiredType, typeof(Spring.Collections.Generic.ISet<>))) + else if (newValue is string) { - // convert individual elements to array elements - Type componentType = requiredType.GetGenericArguments()[0]; - if (newValue is ICollection) + if (requiredType.Equals(typeof(char[]))) { - ICollection elements = (ICollection)newValue; - return ToTypedCollectionWithTypeConversion(typeof(Spring.Collections.Generic.HashedSet<>), componentType, elements, propertyName); - } - } - - // if required type is some IList, convert all the elements - if (requiredType != null && requiredType.IsGenericType && TypeImplementsGenericInterface(requiredType, typeof(IList<>))) - { - // convert individual elements to array elements - Type componentType = requiredType.GetGenericArguments()[0]; - if (newValue is ICollection) - { - ICollection elements = (ICollection)newValue; - return ToTypedCollectionWithTypeConversion(typeof(List<>), componentType, elements, propertyName); - } - } - - // if required type is some IDictionary, convert all the elements - if (requiredType != null && requiredType.IsGenericType && TypeImplementsGenericInterface(requiredType, typeof(IDictionary<,>))) - { - Type[] typeParameters = requiredType.GetGenericArguments(); - Type keyType = typeParameters[0]; - Type valueType = typeParameters[1]; - if (newValue is IDictionary) - { - IDictionary elements = (IDictionary)newValue; - Type targetCollectionType = typeof(Dictionary<,>); - Type collectionType = targetCollectionType.MakeGenericType(new Type[] { keyType, valueType }); - object typedCollection = Activator.CreateInstance(collectionType); - - MethodInfo addMethod = collectionType.GetMethod("Add", new Type[] { keyType, valueType }); - int i = 0; - foreach (DictionaryEntry entry in elements) - { - string propertyExpr = BuildIndexedPropertyName(propertyName, i); - object key = ConvertValueIfNecessary(keyType, entry.Key, propertyExpr + ".Key"); - object value = ConvertValueIfNecessary(valueType, entry.Value, propertyExpr + ".Value"); - addMethod.Invoke(typedCollection, new object[] { key, value }); - i++; - } - return typedCollection; - } - } - - // if required type is some IEnumerable, convert all the elements - if (requiredType != null && requiredType.IsGenericType && TypeImplementsGenericInterface(requiredType, typeof(IEnumerable<>))) - { - // convert individual elements to array elements - Type componentType = requiredType.GetGenericArguments()[0]; - if (newValue is ICollection) - { - ICollection elements = (ICollection)newValue; - return ToTypedCollectionWithTypeConversion(typeof(List<>), componentType, elements, propertyName); - } - } - - // try to convert using type converter - try - { - TypeConverter typeConverter = TypeConverterRegistry.GetConverter(requiredType); - if (typeConverter != null && typeConverter.CanConvertFrom(newValue.GetType())) - { - try - { - newValue = typeConverter.ConvertFrom(newValue); - } - catch - { - if (newValue is string) - { - newValue = typeConverter.ConvertFromInvariantString((string)newValue); - } - } + return ((string) newValue).ToCharArray(); } else { - typeConverter = TypeConverterRegistry.GetConverter(newValue.GetType()); - if (typeConverter != null && typeConverter.CanConvertTo(requiredType)) - { - newValue = typeConverter.ConvertTo(newValue, requiredType); - } - else - { - // look if it's an enum - if (requiredType != null - && requiredType.IsEnum - && (!(newValue is float) - && (!(newValue is double)))) - { - // convert numeric value into enum's underlying type - Type numericType = Enum.GetUnderlyingType(requiredType); - newValue = Convert.ChangeType(newValue, numericType); + string[] elements = StringUtils.CommaDelimitedListToStringArray((string) newValue); + return ToArrayWithTypeConversion(componentType, elements, propertyName); + } + } + else if (!newValue.GetType().IsArray) + { + // A plain value: convert it to an array with a single component. + Array result = Array.CreateInstance(componentType, 1); + object val = ConvertValueIfNecessary(componentType, newValue, propertyName); + result.SetValue(val, 0); + return result; + } + } - if (Enum.IsDefined(requiredType, newValue)) - { - newValue = Enum.ToObject(requiredType, newValue); - } - else - { - throw new TypeMismatchException( - CreatePropertyChangeEventArgs(propertyName, null, newValue), requiredType); - } - } - else if (newValue is IConvertible) + // if required type is some ISet, convert all the elements + if (requiredType != null && requiredType.IsGenericType && TypeImplementsGenericInterface(requiredType, typeof(Spring.Collections.Generic.ISet<>))) + { + // convert individual elements to array elements + Type componentType = requiredType.GetGenericArguments()[0]; + if (newValue is ICollection) + { + ICollection elements = (ICollection) newValue; + return ToTypedCollectionWithTypeConversion(typeof(Spring.Collections.Generic.HashedSet<>), componentType, elements, propertyName); + } + } + + // if required type is some IList, convert all the elements + if (requiredType != null && requiredType.IsGenericType && TypeImplementsGenericInterface(requiredType, typeof(IList<>))) + { + // convert individual elements to array elements + Type componentType = requiredType.GetGenericArguments()[0]; + if (newValue is ICollection) + { + ICollection elements = (ICollection) newValue; + return ToTypedCollectionWithTypeConversion(typeof(List<>), componentType, elements, propertyName); + } + } + + // if required type is some IDictionary, convert all the elements + if (requiredType != null && requiredType.IsGenericType && TypeImplementsGenericInterface(requiredType, typeof(IDictionary<,>))) + { + Type[] typeParameters = requiredType.GetGenericArguments(); + Type keyType = typeParameters[0]; + Type valueType = typeParameters[1]; + if (newValue is IDictionary) + { + IDictionary elements = (IDictionary) newValue; + Type targetCollectionType = typeof(Dictionary<,>); + Type collectionType = targetCollectionType.MakeGenericType(new Type[] { keyType, valueType }); + object typedCollection = Activator.CreateInstance(collectionType); + + MethodInfo addMethod = collectionType.GetMethod("Add", new Type[] { keyType, valueType }); + int i = 0; + foreach (DictionaryEntry entry in elements) + { + string propertyExpr = BuildIndexedPropertyName(propertyName, i); + object key = ConvertValueIfNecessary(keyType, entry.Key, propertyExpr + ".Key"); + object value = ConvertValueIfNecessary(valueType, entry.Value, propertyExpr + ".Value"); + addMethod.Invoke(typedCollection, new object[] { key, value }); + i++; + } + + return typedCollection; + } + } + + // if required type is some IEnumerable, convert all the elements + if (requiredType != null && requiredType.IsGenericType && TypeImplementsGenericInterface(requiredType, typeof(IEnumerable<>))) + { + // convert individual elements to array elements + Type componentType = requiredType.GetGenericArguments()[0]; + if (newValue is ICollection) + { + ICollection elements = (ICollection) newValue; + return ToTypedCollectionWithTypeConversion(typeof(List<>), componentType, elements, propertyName); + } + } + + // try to convert using type converter + try + { + TypeConverter typeConverter = TypeConverterRegistry.GetConverter(requiredType); + if (typeConverter != null && typeConverter.CanConvertFrom(newValue.GetType())) + { + try + { + newValue = typeConverter.ConvertFrom(newValue); + } + catch + { + if (newValue is string) + { + newValue = typeConverter.ConvertFromInvariantString((string) newValue); + } + } + } + else + { + typeConverter = TypeConverterRegistry.GetConverter(newValue.GetType()); + if (typeConverter != null && typeConverter.CanConvertTo(requiredType)) + { + newValue = typeConverter.ConvertTo(newValue, requiredType); + } + else + { + // look if it's an enum + if (requiredType != null + && requiredType.IsEnum + && (!(newValue is float) + && (!(newValue is double)))) + { + // convert numeric value into enum's underlying type + Type numericType = Enum.GetUnderlyingType(requiredType); + newValue = Convert.ChangeType(newValue, numericType); + + if (Enum.IsDefined(requiredType, newValue)) { - // last resort - try ChangeType - newValue = Convert.ChangeType(newValue, requiredType); + newValue = Enum.ToObject(requiredType, newValue); } else { @@ -209,131 +200,144 @@ namespace Spring.Core.TypeConversion CreatePropertyChangeEventArgs(propertyName, null, newValue), requiredType); } } + else if (newValue is IConvertible) + { + // last resort - try ChangeType + newValue = Convert.ChangeType(newValue, requiredType); + } + else + { + throw new TypeMismatchException( + CreatePropertyChangeEventArgs(propertyName, null, newValue), requiredType); + } } } - catch (Exception ex) - { - throw new TypeMismatchException( - CreatePropertyChangeEventArgs(propertyName, null, newValue), requiredType, ex); - } - if (newValue == null && (requiredType == null || !Type.GetType("System.Nullable`1").Equals(requiredType.GetGenericTypeDefinition()))) - { - throw new TypeMismatchException( - CreatePropertyChangeEventArgs(propertyName, null, newValue), requiredType); - } } - return newValue; + catch (Exception ex) + { + throw new TypeMismatchException( + CreatePropertyChangeEventArgs(propertyName, null, newValue), requiredType, ex); + } + + if (newValue == null && (requiredType == null || !Type.GetType("System.Nullable`1").Equals(requiredType.GetGenericTypeDefinition()))) + { + throw new TypeMismatchException( + CreatePropertyChangeEventArgs(propertyName, null, newValue), requiredType); + } } - private static object ToArrayWithTypeConversion(Type componentType, ICollection elements, string propertyName) + return newValue; + } + + private static object ToArrayWithTypeConversion(Type componentType, ICollection elements, string propertyName) + { + Array destination = Array.CreateInstance(componentType, elements.Count); + int i = 0; + foreach (object element in elements) { - Array destination = Array.CreateInstance(componentType, elements.Count); - int i = 0; - foreach (object element in elements) - { - object value = ConvertValueIfNecessary(componentType, element, BuildIndexedPropertyName(propertyName, i)); - destination.SetValue(value, i); - i++; - } - return destination; + object value = ConvertValueIfNecessary(componentType, element, BuildIndexedPropertyName(propertyName, i)); + destination.SetValue(value, i); + i++; } - private static object ToTypedCollectionWithTypeConversion(Type targetCollectionType, Type componentType, ICollection elements, string propertyName) + return destination; + } + + private static object ToTypedCollectionWithTypeConversion(Type targetCollectionType, Type componentType, ICollection elements, string propertyName) + { + if (!TypeImplementsGenericInterface(targetCollectionType, typeof(ICollection<>))) { - if (!TypeImplementsGenericInterface(targetCollectionType, typeof(ICollection<>))) - { - throw new ArgumentException("argument must be a type that derives from ICollection", "targetCollectionType"); - } - - - Type collectionType = targetCollectionType.MakeGenericType(new Type[] { componentType }); - - object typedCollection = Activator.CreateInstance(collectionType); - - int i = 0; - foreach (object element in elements) - { - object value = ConvertValueIfNecessary(componentType, element, BuildIndexedPropertyName(propertyName, i)); - collectionType.GetMethod("Add").Invoke(typedCollection, new object[] { value }); - i++; - } - return typedCollection; + throw new ArgumentException("argument must be a type that derives from ICollection", "targetCollectionType"); } - private static string BuildIndexedPropertyName(string propertyName, int index) + Type collectionType = targetCollectionType.MakeGenericType(new Type[] { componentType }); + + object typedCollection = Activator.CreateInstance(collectionType); + + int i = 0; + foreach (object element in elements) { - return (propertyName != null ? - propertyName + "[" + index + "]" : - null); + object value = ConvertValueIfNecessary(componentType, element, BuildIndexedPropertyName(propertyName, i)); + collectionType.GetMethod("Add").Invoke(typedCollection, new object[] { value }); + i++; } - private static bool IsAssignableFrom(object newValue, Type requiredType) + return typedCollection; + } + + private static string BuildIndexedPropertyName(string propertyName, int index) + { + return (propertyName != null ? propertyName + "[" + index + "]" : null); + } + + private static bool IsAssignableFrom(object newValue, Type requiredType) + { + if (newValue is MarshalByRefObject) { - if (newValue is MarshalByRefObject) - { - //TODO see what type of type checking can be done. May need to - //preserve information when proxy was created by SaoServiceExporter. - return true; - } - if (requiredType == null) - { - return false; - } - return requiredType.IsAssignableFrom(newValue.GetType()); + //TODO see what type of type checking can be done. May need to + //preserve information when proxy was created by SaoServiceExporter. + return true; } - /// - /// Utility method to create a property change event. - /// - /// - /// The full name of the property that has changed. - /// - /// The property old value - /// The property new value - /// - /// A new . - /// - private static PropertyChangeEventArgs CreatePropertyChangeEventArgs(string fullPropertyName, object oldValue, - object newValue) + if (requiredType == null) { - return new PropertyChangeEventArgs(fullPropertyName, oldValue, newValue); + return false; } - /// - /// Determines if a Type implements a specific generic interface. - /// - /// Candidate to evaluate. - /// The to test for in the Candidate . - /// if a match, else - private static bool TypeImplementsGenericInterface(Type candidateType, Type matchingInterface) + return requiredType.IsAssignableFrom(newValue.GetType()); + } + + /// + /// Utility method to create a property change event. + /// + /// + /// The full name of the property that has changed. + /// + /// The property old value + /// The property new value + /// + /// A new . + /// + private static PropertyChangeEventArgs CreatePropertyChangeEventArgs(string fullPropertyName, object oldValue, + object newValue) + { + return new PropertyChangeEventArgs(fullPropertyName, oldValue, newValue); + } + + /// + /// Determines if a Type implements a specific generic interface. + /// + /// Candidate to evaluate. + /// The to test for in the Candidate . + /// if a match, else + private static bool TypeImplementsGenericInterface(Type candidateType, Type matchingInterface) + { + if (!matchingInterface.IsInterface) { - if (!matchingInterface.IsInterface) - { - throw new ArgumentException("matchingInterface Type must be an Interface Type", "matchingInterface"); - } - - if (candidateType.IsInterface && IsMatchingGenericInterface(candidateType, matchingInterface)) - { - return true; - } - - bool match = false; - Type[] implementedInterfaces = candidateType.GetInterfaces(); - foreach (Type interfaceType in implementedInterfaces) - { - if (IsMatchingGenericInterface(interfaceType, matchingInterface)) - { - match = true; - break; - } - } - - return match; + throw new ArgumentException("matchingInterface Type must be an Interface Type", "matchingInterface"); } - private static bool IsMatchingGenericInterface(Type candidateInterfaceType, Type matchingGenericInterface) + if (candidateType.IsInterface && IsMatchingGenericInterface(candidateType, matchingInterface)) { - return candidateInterfaceType.IsGenericType && candidateInterfaceType.GetGenericTypeDefinition() == matchingGenericInterface; + return true; } + + bool match = false; + Type[] implementedInterfaces = candidateType.GetInterfaces(); + foreach (Type interfaceType in implementedInterfaces) + { + if (IsMatchingGenericInterface(interfaceType, matchingInterface)) + { + match = true; + break; + } + } + + return match; + } + + private static bool IsMatchingGenericInterface(Type candidateInterfaceType, Type matchingGenericInterface) + { + return candidateInterfaceType.IsGenericType && candidateInterfaceType.GetGenericTypeDefinition() == matchingGenericInterface; } } diff --git a/src/Spring/Spring.Core/Core/TypeConversion/TypeConverterRegistry.cs b/src/Spring/Spring.Core/Core/TypeConversion/TypeConverterRegistry.cs index 437815a9..7df3d0c0 100644 --- a/src/Spring/Spring.Core/Core/TypeConversion/TypeConverterRegistry.cs +++ b/src/Spring/Spring.Core/Core/TypeConversion/TypeConverterRegistry.cs @@ -26,139 +26,136 @@ using System.Drawing; using System.Net; using System.Resources; using System.Text.RegularExpressions; - using Microsoft.Win32; - using Spring.Core.TypeResolution; using Spring.Util; #endregion -namespace Spring.Core.TypeConversion +namespace Spring.Core.TypeConversion; + +/// +/// Registry class that allows users to register and retrieve type converters. +/// +/// Aleksandar Seovic +public class TypeConverterRegistry { /// - /// Registry class that allows users to register and retrieve type converters. + /// Name of the .Net config section that contains Spring.Net type aliases. /// - /// Aleksandar Seovic - public class TypeConverterRegistry + private const string TypeConvertersSectionName = "spring/typeConverters"; + + private static readonly object syncRoot = new object(); + private static IDictionary converters = new Dictionary(); + + /// + /// Registers standard and configured type converters. + /// + static TypeConverterRegistry() { - /// - /// Name of the .Net config section that contains Spring.Net type aliases. - /// - private const string TypeConvertersSectionName = "spring/typeConverters"; - - private static readonly object syncRoot = new object(); - private static IDictionary converters = new Dictionary(); - - /// - /// Registers standard and configured type converters. - /// - static TypeConverterRegistry() + lock (syncRoot) { - lock (syncRoot) - { - converters[typeof(string[])] = new StringArrayConverter(); - converters[typeof(Type)] = new RuntimeTypeConverter(); - converters[typeof(Color)] = new RGBColorConverter(); - converters[typeof(Uri)] = new UriConverter(); - converters[typeof(FileInfo)] = new FileInfoConverter(); - converters[typeof(Stream)] = new StreamConverter(); - converters[typeof(NameValueCollection)] = new NameValueConverter(); - converters[typeof(ResourceManager)] = new ResourceManagerConverter(); - converters[typeof(Regex)] = new RegexConverter(); - converters[typeof(TimeSpan)] = new TimeSpanConverter(); - converters[typeof(ICredentials)] = new CredentialConverter(); - converters[typeof(NetworkCredential)] = new CredentialConverter(); - converters[typeof(RegistryKey)] = new RegistryKeyConverter(); + converters[typeof(string[])] = new StringArrayConverter(); + converters[typeof(Type)] = new RuntimeTypeConverter(); + converters[typeof(Color)] = new RGBColorConverter(); + converters[typeof(Uri)] = new UriConverter(); + converters[typeof(FileInfo)] = new FileInfoConverter(); + converters[typeof(Stream)] = new StreamConverter(); + converters[typeof(NameValueCollection)] = new NameValueConverter(); + converters[typeof(ResourceManager)] = new ResourceManagerConverter(); + converters[typeof(Regex)] = new RegexConverter(); + converters[typeof(TimeSpan)] = new TimeSpanConverter(); + converters[typeof(ICredentials)] = new CredentialConverter(); + converters[typeof(NetworkCredential)] = new CredentialConverter(); + converters[typeof(RegistryKey)] = new RegistryKeyConverter(); - // register user-defined type converters - ConfigurationUtils.GetSection(TypeConvertersSectionName); + // register user-defined type converters + ConfigurationUtils.GetSection(TypeConvertersSectionName); + } + } + + /// + /// Returns for the specified type. + /// + /// Type to get the converter for. + /// a type converter for the specified type. + /// If is null. + public static TypeConverter GetConverter(Type type) + { + AssertUtils.ArgumentNotNull(type, "type"); + + TypeConverter converter; + if (!converters.TryGetValue(type, out converter)) + { + if (type.IsEnum) + { + converter = new EnumConverter(type); + } + else + { + converter = TypeDescriptor.GetConverter(type); } } - /// - /// Returns for the specified type. - /// - /// Type to get the converter for. - /// a type converter for the specified type. - /// If is null. - public static TypeConverter GetConverter(Type type) + return converter; + } + + /// + /// Registers for the specified type. + /// + /// Type to register the converter for. + /// Type converter to register. + /// If either of arguments is null. + public static void RegisterConverter(Type type, TypeConverter converter) + { + AssertUtils.ArgumentNotNull(type, "type"); + AssertUtils.ArgumentNotNull(converter, "converter"); + + lock (syncRoot) { - AssertUtils.ArgumentNotNull(type, "type"); - - TypeConverter converter; - if (!converters.TryGetValue(type, out converter)) - { - if (type.IsEnum) - { - converter = new EnumConverter(type); - } - else - { - converter = TypeDescriptor.GetConverter(type); - } - } - - return converter; + converters[type] = converter; } + } - /// - /// Registers for the specified type. - /// - /// Type to register the converter for. - /// Type converter to register. - /// If either of arguments is null. - public static void RegisterConverter(Type type, TypeConverter converter) + /// + /// Registers for the specified type. + /// + /// + /// This is a convinience method that accepts the names of both + /// type to register converter for and the converter itself, + /// resolves them using , creates an + /// instance of type converter and calls overloaded + /// method. + /// + /// Type name of the type to register the converter for (can be a type alias). + /// Type name of the type converter to register (can be a type alias). + /// If either of arguments is null or empty string. + /// + /// If either of arguments fails to resolve to a valid . + /// + /// + /// If type converter does not derive from or if it cannot be instantiated. + /// + public static void RegisterConverter(string typeName, string converterTypeName) + { + AssertUtils.ArgumentHasText(typeName, "typeName"); + AssertUtils.ArgumentHasText(converterTypeName, "converterTypeName"); + + try { - AssertUtils.ArgumentNotNull(type, "type"); - AssertUtils.ArgumentNotNull(converter, "converter"); - - lock (syncRoot) + Type type = TypeResolutionUtils.ResolveType(typeName); + Type converterType = TypeResolutionUtils.ResolveType(converterTypeName); + if (!typeof(TypeConverter).IsAssignableFrom(converterType)) { - converters[type] = converter; + throw new ArgumentException( + "Type specified as a 'converterTypeName' does not inherit from System.ComponentModel.TypeConverter"); } - } - /// - /// Registers for the specified type. - /// - /// - /// This is a convinience method that accepts the names of both - /// type to register converter for and the converter itself, - /// resolves them using , creates an - /// instance of type converter and calls overloaded - /// method. - /// - /// Type name of the type to register the converter for (can be a type alias). - /// Type name of the type converter to register (can be a type alias). - /// If either of arguments is null or empty string. - /// - /// If either of arguments fails to resolve to a valid . - /// - /// - /// If type converter does not derive from or if it cannot be instantiated. - /// - public static void RegisterConverter(string typeName, string converterTypeName) + RegisterConverter(type, (TypeConverter) ObjectUtils.InstantiateType(converterType)); + } + catch (FatalReflectionException e) { - AssertUtils.ArgumentHasText(typeName, "typeName"); - AssertUtils.ArgumentHasText(converterTypeName, "converterTypeName"); - - try - { - Type type = TypeResolutionUtils.ResolveType(typeName); - Type converterType = TypeResolutionUtils.ResolveType(converterTypeName); - if (!typeof(TypeConverter).IsAssignableFrom(converterType)) - { - throw new ArgumentException( - "Type specified as a 'converterTypeName' does not inherit from System.ComponentModel.TypeConverter"); - } - RegisterConverter(type,(TypeConverter) ObjectUtils.InstantiateType(converterType)); - } - catch (FatalReflectionException e) - { - throw new ArgumentException("Failed to create an instance of the specified type converter.", e); - } + throw new ArgumentException("Failed to create an instance of the specified type converter.", e); } - } } diff --git a/src/Spring/Spring.Core/Core/TypeConversion/UniqueKeyConverter.cs b/src/Spring/Spring.Core/Core/TypeConversion/UniqueKeyConverter.cs index 8c7b04b5..10804eb0 100644 --- a/src/Spring/Spring.Core/Core/TypeConversion/UniqueKeyConverter.cs +++ b/src/Spring/Spring.Core/Core/TypeConversion/UniqueKeyConverter.cs @@ -26,135 +26,134 @@ using Spring.Util; #endregion -namespace Spring.Core.TypeConversion +namespace Spring.Core.TypeConversion; + +/// +/// Converts between instances of and their string representations. +/// +/// Erich Eichinger +public class UniqueKeyConverter : TypeConverter { /// - /// Converts between instances of and their string representations. + /// Can we convert from the sourcetype to a ? /// - /// Erich Eichinger - public class UniqueKeyConverter : TypeConverter + /// + ///

+ /// Currently only supports conversion from a instance. + ///

+ ///
+ /// + /// A that provides a format context. + /// + /// + /// A that represents the you want to convert from. + /// + /// if the conversion is possible. + public override bool CanConvertFrom( + ITypeDescriptorContext context, Type sourceType) { - /// - /// Can we convert from the sourcetype to a ? - /// - /// - ///

- /// Currently only supports conversion from a instance. - ///

- ///
- /// - /// A that provides a format context. - /// - /// - /// A that represents the you want to convert from. - /// - /// if the conversion is possible. - public override bool CanConvertFrom( - ITypeDescriptorContext context, Type sourceType) + return (typeof(string) == sourceType || typeof(UniqueKey) == sourceType); + } + + /// + /// Convert from a value to an instance. + /// + /// + /// A + /// that provides a format context. + /// + /// + /// The to use + /// as the current culture. + /// + /// + /// The value that is to be converted. + /// + /// + /// A if successful, otherwise. + /// + ///The conversion cannot be performed. + public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) + { + if (value == null) return null; + + if (!CanConvertFrom(context, value.GetType())) { - return (typeof(string)==sourceType || typeof(UniqueKey)==sourceType); + throw new NotSupportedException(string.Format("Conversion from value of type '{0}' is not supported", value.GetType().FullName)); } - /// - /// Convert from a value to an instance. - /// - /// - /// A - /// that provides a format context. - /// - /// - /// The to use - /// as the current culture. - /// - /// - /// The value that is to be converted. - /// - /// - /// A if successful, otherwise. - /// - ///The conversion cannot be performed. - public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) + if (value is string) { - if (value == null) return null; - - if (!CanConvertFrom(context, value.GetType())) - { - throw new NotSupportedException(string.Format("Conversion from value of type '{0}' is not supported", value.GetType().FullName)); - } - - if (value is string) - { - return new UniqueKey(value as string); - } - else if (value is UniqueKey) - { - return value; - } - - throw new NotSupportedException(string.Format("Cannot convert from value of type '{0}' to '{1}'", value.GetType().FullName, typeof(UniqueKey).FullName)); + return new UniqueKey(value as string); + } + else if (value is UniqueKey) + { + return value; } - /// - ///Returns whether this converter can convert the object to the specified type, using the specified context. - /// - ///An that provides a format context. - ///A that represents the type you want to convert to. - /// - ///true if this converter can perform the conversion; otherwise, false. - /// - /// - /// At the moment only conversion to string is supported. - /// - public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) + throw new NotSupportedException(string.Format("Cannot convert from value of type '{0}' to '{1}'", value.GetType().FullName, typeof(UniqueKey).FullName)); + } + + /// + ///Returns whether this converter can convert the object to the specified type, using the specified context. + /// + ///An that provides a format context. + ///A that represents the type you want to convert to. + /// + ///true if this converter can perform the conversion; otherwise, false. + /// + /// + /// At the moment only conversion to string is supported. + /// + public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) + { + return (typeof(string) == destinationType || typeof(UniqueKey) == destinationType); + } + + /// + ///Converts the given value object to the specified type, using the specified context and culture information. + /// + /// + /// + ///An that represents the converted value. + /// + /// + ///A . If null is passed, the current culture is assumed. + ///An that provides a format context. + ///The to convert the value parameter to. + ///The to convert. + ///The conversion cannot be performed. + ///The destinationType parameter is null. + public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) + { + // check destinationType + if (destinationType == null) { - return (typeof(string)==destinationType || typeof(UniqueKey)==destinationType); + throw new ArgumentNullException("destinationType", "destinationType must not be null"); } - /// - ///Converts the given value object to the specified type, using the specified context and culture information. - /// - /// - /// - ///An that represents the converted value. - /// - /// - ///A . If null is passed, the current culture is assumed. - ///An that provides a format context. - ///The to convert the value parameter to. - ///The to convert. - ///The conversion cannot be performed. - ///The destinationType parameter is null. - public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) + if (!CanConvertTo(context, destinationType)) { - // check destinationType - if (destinationType == null) - { - throw new ArgumentNullException("destinationType", "destinationType must not be null"); - } - if (!CanConvertTo(context, destinationType)) - { - throw new NotSupportedException(string.Format("conversion to destinationType '{0}' is not supported.", destinationType.FullName)); - } - - // value must either be null or a UniqueKey - if ( (value != null) && (typeof(UniqueKey) != value.GetType()) ) - { - throw new NotSupportedException(string.Format("value is not of type '{0}'", typeof(UniqueKey).FullName)); - } - - if (value == null) return null; - - if (typeof(string)==destinationType) - { - return (value).ToString(); - } - else if (typeof(UniqueKey)==destinationType) - { - return value; - } - - throw new NotSupportedException(string.Format("destinationType must be '{0}' but was '{1}'", typeof(string).FullName, destinationType)); + throw new NotSupportedException(string.Format("conversion to destinationType '{0}' is not supported.", destinationType.FullName)); } + // value must either be null or a UniqueKey + if ((value != null) && (typeof(UniqueKey) != value.GetType())) + { + throw new NotSupportedException(string.Format("value is not of type '{0}'", typeof(UniqueKey).FullName)); + } + + if (value == null) return null; + + if (typeof(string) == destinationType) + { + return (value).ToString(); + } + else if (typeof(UniqueKey) == destinationType) + { + return value; + } + + throw new NotSupportedException(string.Format("destinationType must be '{0}' but was '{1}'", typeof(string).FullName, destinationType)); } } diff --git a/src/Spring/Spring.Core/Core/TypeConversion/UriConverter.cs b/src/Spring/Spring.Core/Core/TypeConversion/UriConverter.cs index 268356a7..24c27a85 100644 --- a/src/Spring/Spring.Core/Core/TypeConversion/UriConverter.cs +++ b/src/Spring/Spring.Core/Core/TypeConversion/UriConverter.cs @@ -25,88 +25,93 @@ using System.Globalization; #endregion -namespace Spring.Core.TypeConversion +namespace Spring.Core.TypeConversion; + +/// +/// Converter for instances. +/// +/// Juergen Hoeller +/// Mark Pollack (.NET) +public class UriConverter : TypeConverter { - /// - /// Converter for instances. - /// - /// Juergen Hoeller - /// Mark Pollack (.NET) - public class UriConverter : TypeConverter - { - #region Constructor (s) / Destructor - /// - /// Creates a new instance of the - /// class. - /// - public UriConverter () {} - #endregion + #region Constructor (s) / Destructor - #region Methods - /// - /// Returns whether this converter can convert an object of one - /// to a - /// - /// - ///

- /// Currently only supports conversion from a - /// instance. - ///

- ///
- /// - /// A - /// that provides a format context. - /// - /// - /// A that represents the - /// you want to convert from. - /// - /// True if the conversion is possible. - public override bool CanConvertFrom ( - ITypeDescriptorContext context, - Type sourceType) + /// + /// Creates a new instance of the + /// class. + /// + public UriConverter() { } + + #endregion + + #region Methods + + /// + /// Returns whether this converter can convert an object of one + /// to a + /// + /// + ///

+ /// Currently only supports conversion from a + /// instance. + ///

+ ///
+ /// + /// A + /// that provides a format context. + /// + /// + /// A that represents the + /// you want to convert from. + /// + /// True if the conversion is possible. + public override bool CanConvertFrom( + ITypeDescriptorContext context, + Type sourceType) + { + if (sourceType == typeof(string)) { - if (sourceType == typeof (string)) - { - return true; - } - return base.CanConvertFrom (context, sourceType); + return true; } - /// - /// Convert from a string value to a instance. - /// - /// - /// A - /// that provides a format context. - /// - /// - /// The to use - /// as the current culture. - /// - /// - /// The value that is to be converted. - /// - /// - /// A if successful. - /// - public override object ConvertFrom ( - ITypeDescriptorContext context, - CultureInfo culture, object value) + return base.CanConvertFrom(context, sourceType); + } + + /// + /// Convert from a string value to a instance. + /// + /// + /// A + /// that provides a format context. + /// + /// + /// The to use + /// as the current culture. + /// + /// + /// The value that is to be converted. + /// + /// + /// A if successful. + /// + public override object ConvertFrom( + ITypeDescriptorContext context, + CultureInfo culture, object value) + { + if (value is string) { - if (value is string) + try { - try - { - return new Uri(value as string); - } - catch (UriFormatException ex) - { - throw new ArgumentException("Malformed URL: ", ex); - } + return new Uri(value as string); + } + catch (UriFormatException ex) + { + throw new ArgumentException("Malformed URL: ", ex); } - return base.ConvertFrom (context, culture, value); } - #endregion - } + + return base.ConvertFrom(context, culture, value); + } + + #endregion } diff --git a/src/Spring/Spring.Core/Core/TypeMismatchException.cs b/src/Spring/Spring.Core/Core/TypeMismatchException.cs index ed5ba6f4..76eed9d4 100644 --- a/src/Spring/Spring.Core/Core/TypeMismatchException.cs +++ b/src/Spring/Spring.Core/Core/TypeMismatchException.cs @@ -25,131 +25,133 @@ using System.Text; #endregion -namespace Spring.Core +namespace Spring.Core; + +/// +/// Exception thrown on a mismatch when trying to set a property +/// or resolve an argument to a method invocation. +/// +/// Rod Johnson +/// Juergen Hoeller +/// Mark Pollack (.NET) +[Serializable] +public class TypeMismatchException : PropertyAccessException { /// - /// Exception thrown on a mismatch when trying to set a property - /// or resolve an argument to a method invocation. + /// The string error code used to classify the exception. /// - /// Rod Johnson - /// Juergen Hoeller - /// Mark Pollack (.NET) - [Serializable] - public class TypeMismatchException : PropertyAccessException + public override string ErrorCode { - /// - /// The string error code used to classify the exception. - /// - public override string ErrorCode + get { return "typeMismatch"; } + } + + /// + /// Creates a new instance of the TypeMismatchException class. + /// + public TypeMismatchException() + { + } + + /// + /// Creates a new instance of the TypeMismatchException class. + /// + /// + /// A message about the exception. + /// + public TypeMismatchException(string message) : base(message) + { + } + + /// + /// Creates a new instance of the TypeMismatchException class. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception that is being wrapped. + /// + public TypeMismatchException(string message, Exception rootCause) + : base(message, rootCause) + { + } + + /// + /// Creates a new instance of the TypeMismatchException class describing the + /// property and required type that could not used to set a property on the target object. + /// + /// + /// The description of the property that was to be changed. + /// + /// The target conversion type. + public TypeMismatchException( + PropertyChangeEventArgs propertyChangeEventArgs, Type requiredType) : + base(BuildMessage(propertyChangeEventArgs, requiredType), propertyChangeEventArgs) + { + } + + /// + /// Creates a new instance of the TypeMismatchException class describing the + /// property, required type, and underlying exception that could not be used + /// to set a property on the target object. + /// + /// + /// The description of the property that was to be changed. + /// + /// The target conversion type. + /// The underlying exception. + public TypeMismatchException( + PropertyChangeEventArgs propertyChangeEventArgs, Type requiredType, Exception rootCause) : + base(BuildMessage(propertyChangeEventArgs, requiredType), propertyChangeEventArgs, rootCause) + { + } + + /// + /// Creates a new instance of the TypeMismatchException class. + /// + /// + /// The + /// that holds the serialized object data about the exception being thrown. + /// + /// + /// The + /// that contains contextual information about the source or destination. + /// + protected TypeMismatchException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + + private static string BuildMessage(PropertyChangeEventArgs propertyChangeEventArgs, Type requiredType) + { + StringBuilder message = new StringBuilder(); + message.Append("Cannot convert property value of type ["); + if (propertyChangeEventArgs != null && propertyChangeEventArgs.NewValue != null) { - get { return "typeMismatch"; } + message.Append(propertyChangeEventArgs.NewValue.GetType().FullName); + } + else + { + message.Append("null"); } - /// - /// Creates a new instance of the TypeMismatchException class. - /// - public TypeMismatchException() + message.Append("] to required type ["); + if (requiredType != null) { + message.Append(requiredType.FullName); + } + else + { + message.Append("null"); } - /// - /// Creates a new instance of the TypeMismatchException class. - /// - /// - /// A message about the exception. - /// - public TypeMismatchException(string message) : base(message) + message.Append("] for property '"); + if (propertyChangeEventArgs != null && propertyChangeEventArgs.PropertyName != null) { + message.Append(propertyChangeEventArgs.PropertyName); } - /// - /// Creates a new instance of the TypeMismatchException class. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception that is being wrapped. - /// - public TypeMismatchException(string message, Exception rootCause) - : base(message, rootCause) - { - } - - /// - /// Creates a new instance of the TypeMismatchException class describing the - /// property and required type that could not used to set a property on the target object. - /// - /// - /// The description of the property that was to be changed. - /// - /// The target conversion type. - public TypeMismatchException( - PropertyChangeEventArgs propertyChangeEventArgs, Type requiredType) : - base(BuildMessage(propertyChangeEventArgs, requiredType), propertyChangeEventArgs) - { - } - - /// - /// Creates a new instance of the TypeMismatchException class describing the - /// property, required type, and underlying exception that could not be used - /// to set a property on the target object. - /// - /// - /// The description of the property that was to be changed. - /// - /// The target conversion type. - /// The underlying exception. - public TypeMismatchException( - PropertyChangeEventArgs propertyChangeEventArgs, Type requiredType, Exception rootCause) : - base(BuildMessage(propertyChangeEventArgs, requiredType), propertyChangeEventArgs, rootCause) - { - } - - /// - /// Creates a new instance of the TypeMismatchException class. - /// - /// - /// The - /// that holds the serialized object data about the exception being thrown. - /// - /// - /// The - /// that contains contextual information about the source or destination. - /// - protected TypeMismatchException(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } - - private static string BuildMessage(PropertyChangeEventArgs propertyChangeEventArgs, Type requiredType) - { - StringBuilder message = new StringBuilder(); - message.Append("Cannot convert property value of type ["); - if (propertyChangeEventArgs != null && propertyChangeEventArgs.NewValue != null) - { - message.Append(propertyChangeEventArgs.NewValue.GetType().FullName); - } - else - { - message.Append("null"); - } - message.Append("] to required type ["); - if (requiredType != null) - { - message.Append(requiredType.FullName); - } - else - { - message.Append("null"); - } - message.Append("] for property '"); - if (propertyChangeEventArgs != null && propertyChangeEventArgs.PropertyName != null) - { - message.Append(propertyChangeEventArgs.PropertyName); - } - message.Append("'."); - return message.ToString(); - } + message.Append("'."); + return message.ToString(); } } diff --git a/src/Spring/Spring.Core/Core/TypeResolution/CachedTypeResolver.cs b/src/Spring/Spring.Core/Core/TypeResolution/CachedTypeResolver.cs index 40ee8878..377a16f7 100644 --- a/src/Spring/Spring.Core/Core/TypeResolution/CachedTypeResolver.cs +++ b/src/Spring/Spring.Core/Core/TypeResolution/CachedTypeResolver.cs @@ -22,102 +22,103 @@ using System.Collections; using System.Collections.Specialized; - using Spring.Util; #endregion -namespace Spring.Core.TypeResolution +namespace Spring.Core.TypeResolution; + +/// +/// Resolves (instantiates) a by it's (possibly +/// assembly qualified) name, and caches the +/// instance against the type name. +/// +/// Rick Evans +/// Bruno Baia +/// Erich Eichinger +public class CachedTypeResolver : ITypeResolver { - /// - /// Resolves (instantiates) a by it's (possibly - /// assembly qualified) name, and caches the - /// instance against the type name. - /// - /// Rick Evans - /// Bruno Baia - /// Erich Eichinger - public class CachedTypeResolver : ITypeResolver - { - /// - /// The cache, mapping type names ( instances) against - /// instances. - /// - private IDictionary typeCache = new HybridDictionary(); + /// + /// The cache, mapping type names ( instances) against + /// instances. + /// + private IDictionary typeCache = new HybridDictionary(); - private ITypeResolver typeResolver; + private ITypeResolver typeResolver; - /// - /// Creates a new instance of the class. - /// - /// - /// The that this instance will delegate - /// actual resolution to if a - /// cannot be found in this instance's cache. - /// - /// - /// If the supplied is . - /// - public CachedTypeResolver(ITypeResolver typeResolver) - { - AssertUtils.ArgumentNotNull(typeResolver, "typeResolver"); - this.typeResolver = typeResolver; - } + /// + /// Creates a new instance of the class. + /// + /// + /// The that this instance will delegate + /// actual resolution to if a + /// cannot be found in this instance's cache. + /// + /// + /// If the supplied is . + /// + public CachedTypeResolver(ITypeResolver typeResolver) + { + AssertUtils.ArgumentNotNull(typeResolver, "typeResolver"); + this.typeResolver = typeResolver; + } - /// - /// Resolves the supplied to a - /// - /// instance. - /// - /// - /// The (possibly partially assembly qualified) name of a - /// . - /// - /// - /// A resolved instance. - /// - /// - /// If the supplied could not be resolved - /// to a . - /// - public Type Resolve(string typeName) - { - if (StringUtils.IsNullOrEmpty(typeName)) - { - throw BuildTypeLoadException(typeName); - } - Type type = null; - try - { - lock (this.typeCache.SyncRoot) - { - type = this.typeCache[typeName] as Type; - if (type == null) - { - type = this.typeResolver.Resolve(typeName); - this.typeCache[typeName] = type; - } - } - } - catch (Exception ex) - { - if (ex is TypeLoadException) - { - throw; - } - throw BuildTypeLoadException(typeName, ex); - } - return type; - } - - private static TypeLoadException BuildTypeLoadException(string typeName) - { - return new TypeLoadException("Could not load type from string value '" + typeName + "'."); - } - - private static TypeLoadException BuildTypeLoadException(string typeName, Exception ex) + /// + /// Resolves the supplied to a + /// + /// instance. + /// + /// + /// The (possibly partially assembly qualified) name of a + /// . + /// + /// + /// A resolved instance. + /// + /// + /// If the supplied could not be resolved + /// to a . + /// + public Type Resolve(string typeName) + { + if (StringUtils.IsNullOrEmpty(typeName)) { - return new TypeLoadException("Could not load type from string value '" + typeName + "'.", ex); + throw BuildTypeLoadException(typeName); } - } + + Type type = null; + try + { + lock (this.typeCache.SyncRoot) + { + type = this.typeCache[typeName] as Type; + if (type == null) + { + type = this.typeResolver.Resolve(typeName); + this.typeCache[typeName] = type; + } + } + } + catch (Exception ex) + { + if (ex is TypeLoadException) + { + throw; + } + + throw BuildTypeLoadException(typeName, ex); + } + + return type; + } + + private static TypeLoadException BuildTypeLoadException(string typeName) + { + return new TypeLoadException("Could not load type from string value '" + typeName + "'."); + } + + private static TypeLoadException BuildTypeLoadException(string typeName, Exception ex) + { + return new TypeLoadException("Could not load type from string value '" + typeName + "'.", ex); + } } diff --git a/src/Spring/Spring.Core/Core/TypeResolution/GenericArgumentsHolder.cs b/src/Spring/Spring.Core/Core/TypeResolution/GenericArgumentsHolder.cs index cacf1d97..67c9f73f 100644 --- a/src/Spring/Spring.Core/Core/TypeResolution/GenericArgumentsHolder.cs +++ b/src/Spring/Spring.Core/Core/TypeResolution/GenericArgumentsHolder.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -25,289 +25,289 @@ using Spring.Util; #endregion -namespace Spring.Core.TypeResolution +namespace Spring.Core.TypeResolution; + +/// +/// Holder for the generic arguments when using type parameters. +/// +/// +///

+/// Type parameters can be applied to classes, interfaces, +/// structures, methods, delegates, etc... +///

+///
+public class GenericArgumentsHolder { + #region Constants + + private static readonly Regex ClrPattern = new Regex( + "^" + + @"(?'name'\w[\w\d\.]+)" + + @"`\d+\s*\[" + + @"(?'args'(?>[^\[\]]+|\[(?)|\](?<-DEPTH>))*(?(DEPTH)(?!)))" + + @"\]" + + @"(?'remainder'.*)" + + @"$" + , RegexOptions.CultureInvariant | RegexOptions.Compiled + ); + + private static readonly Regex CSharpPattern = new Regex( + "^" + + @"(?'name'\w[\w\d\.]+)" + + @"<" + + @"(?'args'.*)" + + @">" + + @"(?'remainder'.*)" + + @"$" + , RegexOptions.CultureInvariant | RegexOptions.Compiled + ); + + private static Regex GenericArgumentListPattern = new Regex( + @",(" + + @"(\[(?>[^\[\]]+|\[(?)|\](?<-DEPTH>))*(?(DEPTH)(?!))\])" // capture anything between matching brackets + + @"|" + + @"([^,\[\]]*)" // alternatively capture any string that doesn't contain brackets and commas + + @")+" + ); + /// - /// Holder for the generic arguments when using type parameters. + /// The generic arguments prefix. + /// + public const char GenericArgumentsQuotePrefix = '['; + + /// + /// The generic arguments suffix. + /// + public const char GenericArgumentsQuoteSuffix = ']'; + + /// + /// The generic arguments prefix. + /// + public const char GenericArgumentsPrefix = '<'; + + /// + /// The generic arguments suffix. + /// + public const char GenericArgumentsSuffix = '>'; + + /// + /// The character that separates a list of generic arguments. + /// + public const char GenericArgumentsSeparator = ','; + + #endregion + + #region Fields + + private string unresolvedGenericTypeName; + private string unresolvedGenericMethodName; + private string[] unresolvedGenericArguments; + private string arrayDeclaration; + + #endregion + + #region Constructor (s) / Destructor + + /// + /// Creates a new instance of the GenericArgumentsHolder class. + /// + /// + /// The string value to parse looking for a generic definition + /// and retrieving its generic arguments. + /// + public GenericArgumentsHolder(string value) + { + ParseGenericTypeDeclaration(value); + } + + #endregion + + #region Properties + + /// + /// The (unresolved) generic type name portion + /// of the original value when parsing a generic type. + /// + public string GenericTypeName + { + get { return unresolvedGenericTypeName; } + } + + /// + /// The (unresolved) generic method name portion + /// of the original value when parsing a generic method. + /// + public string GenericMethodName + { + get { return unresolvedGenericMethodName; } + } + + /// + /// Is the string value contains generic arguments ? /// /// ///

- /// Type parameters can be applied to classes, interfaces, - /// structures, methods, delegates, etc... + /// A generic argument can be a type parameter or a type argument. ///

///
- public class GenericArgumentsHolder + public bool ContainsGenericArguments { - #region Constants - - private static readonly Regex ClrPattern = new Regex( - "^" - + @"(?'name'\w[\w\d\.]+)" - + @"`\d+\s*\[" - + @"(?'args'(?>[^\[\]]+|\[(?)|\](?<-DEPTH>))*(?(DEPTH)(?!)))" - + @"\]" - + @"(?'remainder'.*)" - + @"$" - , RegexOptions.CultureInvariant | RegexOptions.Compiled - ); - - private static readonly Regex CSharpPattern = new Regex( - "^" - + @"(?'name'\w[\w\d\.]+)" - + @"<" - + @"(?'args'.*)" - + @">" - + @"(?'remainder'.*)" - + @"$" - , RegexOptions.CultureInvariant | RegexOptions.Compiled - ); - - private static Regex GenericArgumentListPattern = new Regex( - @",(" - + @"(\[(?>[^\[\]]+|\[(?)|\](?<-DEPTH>))*(?(DEPTH)(?!))\])" // capture anything between matching brackets - + @"|" - + @"([^,\[\]]*)" // alternatively capture any string that doesn't contain brackets and commas - + @")+" - ); - - /// - /// The generic arguments prefix. - /// - public const char GenericArgumentsQuotePrefix = '['; - - /// - /// The generic arguments suffix. - /// - public const char GenericArgumentsQuoteSuffix = ']'; - - /// - /// The generic arguments prefix. - /// - public const char GenericArgumentsPrefix = '<'; - - /// - /// The generic arguments suffix. - /// - public const char GenericArgumentsSuffix = '>'; - - /// - /// The character that separates a list of generic arguments. - /// - public const char GenericArgumentsSeparator = ','; - - #endregion - - #region Fields - - private string unresolvedGenericTypeName; - private string unresolvedGenericMethodName; - private string[] unresolvedGenericArguments; - private string arrayDeclaration; - - #endregion - - #region Constructor (s) / Destructor - - /// - /// Creates a new instance of the GenericArgumentsHolder class. - /// - /// - /// The string value to parse looking for a generic definition - /// and retrieving its generic arguments. - /// - public GenericArgumentsHolder(string value) + get { - ParseGenericTypeDeclaration(value); - } - - #endregion - - #region Properties - - /// - /// The (unresolved) generic type name portion - /// of the original value when parsing a generic type. - /// - public string GenericTypeName - { - get { return unresolvedGenericTypeName; } - } - - /// - /// The (unresolved) generic method name portion - /// of the original value when parsing a generic method. - /// - public string GenericMethodName - { - get { return unresolvedGenericMethodName; } - } - - /// - /// Is the string value contains generic arguments ? - /// - /// - ///

- /// A generic argument can be a type parameter or a type argument. - ///

- ///
- public bool ContainsGenericArguments - { - get - { - return (unresolvedGenericArguments != null && + return (unresolvedGenericArguments != null && unresolvedGenericArguments.Length > 0); - } } + } - /// - /// Is generic arguments only contains type parameters ? - /// - public bool IsGenericDefinition - { - get - { - if (unresolvedGenericArguments == null) - return false; - - foreach (string arg in unresolvedGenericArguments) - { - if (arg.Length > 0) - return false; - } - return true; - } - } - - /// - /// Returns the array declaration portion of the definition, e.g. "[,]" - /// - /// - public string GetArrayDeclaration() - { - return arrayDeclaration; - } - - /// - /// Is this an array type definition? - /// - public bool IsArrayDeclaration - { - get { return arrayDeclaration != null; } - } - - #endregion - - #region Methods - - /// - /// Returns an array of unresolved generic arguments types. - /// - /// - ///

- /// A empty string represents a type parameter that - /// did not have been substituted by a specific type. - ///

- ///
- /// - /// An array of strings that represents the unresolved generic - /// arguments types or an empty array if not generic. - /// - public string[] GetGenericArguments() + /// + /// Is generic arguments only contains type parameters ? + /// + public bool IsGenericDefinition + { + get { if (unresolvedGenericArguments == null) - return StringUtils.EmptyStrings; + return false; - return unresolvedGenericArguments; + foreach (string arg in unresolvedGenericArguments) + { + if (arg.Length > 0) + return false; + } + + return true; + } + } + + /// + /// Returns the array declaration portion of the definition, e.g. "[,]" + /// + /// + public string GetArrayDeclaration() + { + return arrayDeclaration; + } + + /// + /// Is this an array type definition? + /// + public bool IsArrayDeclaration + { + get { return arrayDeclaration != null; } + } + + #endregion + + #region Methods + + /// + /// Returns an array of unresolved generic arguments types. + /// + /// + ///

+ /// A empty string represents a type parameter that + /// did not have been substituted by a specific type. + ///

+ ///
+ /// + /// An array of strings that represents the unresolved generic + /// arguments types or an empty array if not generic. + /// + public string[] GetGenericArguments() + { + if (unresolvedGenericArguments == null) + return StringUtils.EmptyStrings; + + return unresolvedGenericArguments; + } + + private void ParseGenericTypeDeclaration(string originalString) + { + if (originalString.IndexOf('[') == -1 && originalString.IndexOf('<') == -1) + { + // nothing to do + unresolvedGenericTypeName = originalString; + unresolvedGenericMethodName = originalString; + return; } - private void ParseGenericTypeDeclaration(string originalString) + originalString = originalString.Trim(); + + bool isClrStyleNotation = originalString.IndexOf('`') > -1; + + Match m = (isClrStyleNotation) + ? ClrPattern.Match(originalString) + : CSharpPattern.Match(originalString); + + if (m == null || !m.Success) { - if (originalString.IndexOf('[') == -1 && originalString.IndexOf('<') == -1) - { - // nothing to do - unresolvedGenericTypeName = originalString; - unresolvedGenericMethodName = originalString; - return; - } - - originalString = originalString.Trim(); - - bool isClrStyleNotation = originalString.IndexOf('`') > -1; - - Match m = (isClrStyleNotation) - ? ClrPattern.Match(originalString) - : CSharpPattern.Match(originalString); - - if (m == null || !m.Success) - { - unresolvedGenericTypeName = originalString; - unresolvedGenericMethodName = originalString; - return; - } - - Group g = m.Groups["args"]; - unresolvedGenericArguments = ParseGenericArgumentList(g.Value); - - string name = m.Groups["name"].Value; - string remainder = m.Groups["remainder"].Value.Trim(); - - // check, if we're dealing with an array type declaration - if (remainder.Length > 0 && remainder.IndexOf('[') > -1) - { - string[] remainderParts = StringUtils.Split(remainder, ",", false, false, "[]"); - string arrayPart = remainderParts[0].Trim(); - if (arrayPart[0] == '[' && arrayPart[arrayPart.Length-1] == ']') - { - arrayDeclaration = arrayPart; - remainder = ", " + string.Join(",", remainderParts, 1, remainderParts.Length - 1); - } - } - - unresolvedGenericMethodName = name + remainder; - unresolvedGenericTypeName = name + "`" + unresolvedGenericArguments.Length + remainder; - - - - // char lBoundary = isClrStyleNotation ? '[' : GenericArgumentsPrefix; - // char rBoundary = isClrStyleNotation ? ']' : GenericArgumentsSuffix; - // - // int argsStartIndex = originalString.IndexOf(lBoundary); - // if (argsStartIndex < 0) - // { - // unresolvedGenericTypeName = originalString; - // unresolvedGenericMethodName = originalString; - // } - // else - // { - // int argsEndIndex = originalString.LastIndexOf(rBoundary); - // if (argsEndIndex != -1) - // { - // unresolvedGenericMethodName = originalString.Remove( - // argsStartIndex, argsEndIndex - argsStartIndex + 1); - // - // unresolvedGenericArguments = ParseGenericArgumentList(originalString.Substring( - // argsStartIndex + 1, argsEndIndex - argsStartIndex - 1)); - // - // unresolvedGenericTypeName = originalString.Replace( - // originalString.Substring(argsStartIndex, argsEndIndex - argsStartIndex + 1), - // "`" + unresolvedGenericArguments.Length); - // } - // } + unresolvedGenericTypeName = originalString; + unresolvedGenericMethodName = originalString; + return; } - private static string[] ParseGenericArgumentList(string originalArgs) + Group g = m.Groups["args"]; + unresolvedGenericArguments = ParseGenericArgumentList(g.Value); + + string name = m.Groups["name"].Value; + string remainder = m.Groups["remainder"].Value.Trim(); + + // check, if we're dealing with an array type declaration + if (remainder.Length > 0 && remainder.IndexOf('[') > -1) { - string[] args = StringUtils.Split(originalArgs, ",", true, false, "[]<>" ); - // remove quotes if necessary - for(int i=0;i 1 && arg[0] == '[') - { - args[i] = arg.Substring(1, arg.Length - 2); - } + arrayDeclaration = arrayPart; + remainder = ", " + string.Join(",", remainderParts, 1, remainderParts.Length - 1); } - return args; + } + + unresolvedGenericMethodName = name + remainder; + unresolvedGenericTypeName = name + "`" + unresolvedGenericArguments.Length + remainder; + + // char lBoundary = isClrStyleNotation ? '[' : GenericArgumentsPrefix; + // char rBoundary = isClrStyleNotation ? ']' : GenericArgumentsSuffix; + // + // int argsStartIndex = originalString.IndexOf(lBoundary); + // if (argsStartIndex < 0) + // { + // unresolvedGenericTypeName = originalString; + // unresolvedGenericMethodName = originalString; + // } + // else + // { + // int argsEndIndex = originalString.LastIndexOf(rBoundary); + // if (argsEndIndex != -1) + // { + // unresolvedGenericMethodName = originalString.Remove( + // argsStartIndex, argsEndIndex - argsStartIndex + 1); + // + // unresolvedGenericArguments = ParseGenericArgumentList(originalString.Substring( + // argsStartIndex + 1, argsEndIndex - argsStartIndex - 1)); + // + // unresolvedGenericTypeName = originalString.Replace( + // originalString.Substring(argsStartIndex, argsEndIndex - argsStartIndex + 1), + // "`" + unresolvedGenericArguments.Length); + // } + // } + } + + private static string[] ParseGenericArgumentList(string originalArgs) + { + string[] args = StringUtils.Split(originalArgs, ",", true, false, "[]<>"); + // remove quotes if necessary + for (int i = 0; i < args.Length; i++) + { + string arg = args[i]; + if (arg.Length > 1 && arg[0] == '[') + { + args[i] = arg.Substring(1, arg.Length - 2); + } + } + + return args; // ArrayList args = new ArrayList(); // originalArgs = originalArgs.Trim(); // if (originalArgs.Length == 0) @@ -329,33 +329,33 @@ namespace Spring.Core.TypeResolution // args.Add(arg); // } - // Match m = GenericArgumentListPattern.Match(originalArgs); - // if (m != null && m.Success) - // { - // Group g = m.Groups[0]; - // foreach (Capture capture in g.Captures) - // { - // string arg = capture.Value.Trim(' ', '\t', '[', ']'); - // args.Add(arg); - // } - // } - // int index = 0; - // int cursor = originalArgs.IndexOf(GenericArgumentsSeparator, index); - // while (cursor != -1) - // { - // string arg = originalArgs.Substring(index, cursor - index); - // if (arg.Split(GenericArgumentsPrefix).Length == - // arg.Split(GenericArgumentsSuffix).Length) - // { - // args.Add(arg.Trim()); - // index = cursor + 1; - // } - // cursor = originalArgs.IndexOf(GenericArgumentsSeparator, cursor + 1); - // } - // args.Add(originalArgs.Substring(index, originalArgs.Length - index).Trim()); + // Match m = GenericArgumentListPattern.Match(originalArgs); + // if (m != null && m.Success) + // { + // Group g = m.Groups[0]; + // foreach (Capture capture in g.Captures) + // { + // string arg = capture.Value.Trim(' ', '\t', '[', ']'); + // args.Add(arg); + // } + // } + // int index = 0; + // int cursor = originalArgs.IndexOf(GenericArgumentsSeparator, index); + // while (cursor != -1) + // { + // string arg = originalArgs.Substring(index, cursor - index); + // if (arg.Split(GenericArgumentsPrefix).Length == + // arg.Split(GenericArgumentsSuffix).Length) + // { + // args.Add(arg.Trim()); + // index = cursor + 1; + // } + // cursor = originalArgs.IndexOf(GenericArgumentsSeparator, cursor + 1); + // } + // args.Add(originalArgs.Substring(index, originalArgs.Length - index).Trim()); // return (string[])args.ToArray(typeof(string)); - } - #endregion } + + #endregion } diff --git a/src/Spring/Spring.Core/Core/TypeResolution/GenericTypeResolver.cs b/src/Spring/Spring.Core/Core/TypeResolution/GenericTypeResolver.cs index ac6437ae..5ddc6166 100644 --- a/src/Spring/Spring.Core/Core/TypeResolution/GenericTypeResolver.cs +++ b/src/Spring/Spring.Core/Core/TypeResolution/GenericTypeResolver.cs @@ -24,73 +24,76 @@ using Spring.Util; #endregion -namespace Spring.Core.TypeResolution +namespace Spring.Core.TypeResolution; + +/// +/// Resolves a generic by name. +/// +/// Bruno Baia +public class GenericTypeResolver : TypeResolver { /// - /// Resolves a generic by name. + /// Resolves the supplied generic to a + /// instance. /// - /// Bruno Baia - public class GenericTypeResolver : TypeResolver + /// + /// The unresolved (possibly generic) name of a . + /// + /// + /// A resolved instance. + /// + /// + /// If the supplied could not be resolved + /// to a . + /// + public override Type Resolve(string typeName) { - /// - /// Resolves the supplied generic to a - /// instance. - /// - /// - /// The unresolved (possibly generic) name of a . - /// - /// - /// A resolved instance. - /// - /// - /// If the supplied could not be resolved - /// to a . - /// - public override Type Resolve(string typeName) + if (StringUtils.IsNullOrEmpty(typeName)) { - if (StringUtils.IsNullOrEmpty(typeName)) - { - throw BuildTypeLoadException(typeName); - } - GenericArgumentsHolder genericInfo = new GenericArgumentsHolder(typeName); - Type type = null; - try - { - if (genericInfo.ContainsGenericArguments) - { - type = TypeResolutionUtils.ResolveType(genericInfo.GenericTypeName); - if (!genericInfo.IsGenericDefinition) - { - string[] unresolvedGenericArgs = genericInfo.GetGenericArguments(); - Type[] genericArgs = new Type[unresolvedGenericArgs.Length]; - for (int i = 0; i < unresolvedGenericArgs.Length; i++) - { - genericArgs[i] = TypeResolutionUtils.ResolveType(unresolvedGenericArgs[i]); - } - type = type.MakeGenericType(genericArgs); - } - if (genericInfo.IsArrayDeclaration) - { - typeName = string.Format("{0}{1},{2}", type.FullName, genericInfo.GetArrayDeclaration(), type.Assembly.FullName); - type = null; - } - } - } - catch (Exception ex) - { - if (ex is TypeLoadException) - { - throw; - } - throw BuildTypeLoadException(typeName, ex); - } - - if (type == null) - { - type = base.Resolve(typeName); - } - - return type; + throw BuildTypeLoadException(typeName); } + + GenericArgumentsHolder genericInfo = new GenericArgumentsHolder(typeName); + Type type = null; + try + { + if (genericInfo.ContainsGenericArguments) + { + type = TypeResolutionUtils.ResolveType(genericInfo.GenericTypeName); + if (!genericInfo.IsGenericDefinition) + { + string[] unresolvedGenericArgs = genericInfo.GetGenericArguments(); + Type[] genericArgs = new Type[unresolvedGenericArgs.Length]; + for (int i = 0; i < unresolvedGenericArgs.Length; i++) + { + genericArgs[i] = TypeResolutionUtils.ResolveType(unresolvedGenericArgs[i]); + } + + type = type.MakeGenericType(genericArgs); + } + + if (genericInfo.IsArrayDeclaration) + { + typeName = string.Format("{0}{1},{2}", type.FullName, genericInfo.GetArrayDeclaration(), type.Assembly.FullName); + type = null; + } + } + } + catch (Exception ex) + { + if (ex is TypeLoadException) + { + throw; + } + + throw BuildTypeLoadException(typeName, ex); + } + + if (type == null) + { + type = base.Resolve(typeName); + } + + return type; } -} +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Core/TypeResolution/ITypeResolver.cs b/src/Spring/Spring.Core/Core/TypeResolution/ITypeResolver.cs index ab6bc8c8..972176f5 100644 --- a/src/Spring/Spring.Core/Core/TypeResolution/ITypeResolver.cs +++ b/src/Spring/Spring.Core/Core/TypeResolution/ITypeResolver.cs @@ -22,38 +22,37 @@ #endregion -namespace Spring.Core.TypeResolution +namespace Spring.Core.TypeResolution; + +/// +/// Resolves a by name. +/// +/// +///

+/// The rationale behind the creation of this interface is to centralise +/// the resolution of type names to instances +/// beyond that offered by the plain vanilla +/// method call. +///

+///
+/// Rick Evans +public interface ITypeResolver { - /// - /// Resolves a by name. - /// - /// - ///

- /// The rationale behind the creation of this interface is to centralise - /// the resolution of type names to instances - /// beyond that offered by the plain vanilla - /// method call. - ///

- ///
- /// Rick Evans - public interface ITypeResolver - { - /// - /// Resolves the supplied to a - /// - /// instance. - /// - /// - /// The (possibly partially assembly qualified) name of a - /// . - /// - /// - /// A resolved instance. - /// - /// - /// If the supplied could not be resolved - /// to a . - /// - Type Resolve(string typeName); - } + /// + /// Resolves the supplied to a + /// + /// instance. + /// + /// + /// The (possibly partially assembly qualified) name of a + /// . + /// + /// + /// A resolved instance. + /// + /// + /// If the supplied could not be resolved + /// to a . + /// + Type Resolve(string typeName); } diff --git a/src/Spring/Spring.Core/Core/TypeResolution/TypeAssemblyHolder.cs b/src/Spring/Spring.Core/Core/TypeResolution/TypeAssemblyHolder.cs index 018d8bd5..a4388faa 100644 --- a/src/Spring/Spring.Core/Core/TypeResolution/TypeAssemblyHolder.cs +++ b/src/Spring/Spring.Core/Core/TypeResolution/TypeAssemblyHolder.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -24,98 +24,97 @@ using Spring.Util; #endregion -namespace Spring.Core.TypeResolution +namespace Spring.Core.TypeResolution; + +/// +/// Holds data about a and it's +/// attendant . +/// +public class TypeAssemblyHolder { + #region Constants + /// - /// Holds data about a and it's - /// attendant . + /// The string that separates a name + /// from the name of it's attendant + /// in an assembly qualified type name. /// - public class TypeAssemblyHolder + public const string TypeAssemblySeparator = ","; + + #endregion + + #region Fields + + private string unresolvedAssemblyName; + private string unresolvedTypeName; + + #endregion + + #region Constructor (s) / Destructor + + /// + /// Creates a new instance of the TypeAssemblyHolder class. + /// + /// + /// The unresolved name of a . + /// + public TypeAssemblyHolder(string unresolvedTypeName) { - #region Constants - - /// - /// The string that separates a name - /// from the name of it's attendant - /// in an assembly qualified type name. - /// - public const string TypeAssemblySeparator = ","; - - #endregion - - #region Fields - - private string unresolvedAssemblyName; - private string unresolvedTypeName; - - #endregion - - #region Constructor (s) / Destructor - - /// - /// Creates a new instance of the TypeAssemblyHolder class. - /// - /// - /// The unresolved name of a . - /// - public TypeAssemblyHolder(string unresolvedTypeName) - { - SplitTypeAndAssemblyNames(unresolvedTypeName); - } - - #endregion - - #region Properties - - /// - /// The (unresolved) type name portion of the original type name. - /// - public string TypeName - { - get { return unresolvedTypeName; } - } - - /// - /// The (unresolved, possibly partial) name of the attandant assembly. - /// - public string AssemblyName - { - get { return unresolvedAssemblyName; } - } - - /// - /// Is the type name being resolved assembly qualified? - /// - public bool IsAssemblyQualified - { - get { return StringUtils.HasText(AssemblyName); } - } - - #endregion - - #region Methods - - private void SplitTypeAndAssemblyNames(string originalTypeName) - { - // generic types may look like: - // Spring.Objects.TestGenericObject`2[[System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]][] , Spring.Core.Tests, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null - // - // start searching for assembly separator after the last bracket if any - int typeAssemblyIndex = originalTypeName.LastIndexOf(']'); - typeAssemblyIndex = originalTypeName.IndexOf(TypeAssemblySeparator, typeAssemblyIndex+1); - if (typeAssemblyIndex < 0) - { - unresolvedTypeName = originalTypeName; - } - else - { - unresolvedTypeName = originalTypeName.Substring( - 0, typeAssemblyIndex).Trim(); - unresolvedAssemblyName = originalTypeName.Substring( - typeAssemblyIndex + 1).Trim(); - } - } - - #endregion + SplitTypeAndAssemblyNames(unresolvedTypeName); } + + #endregion + + #region Properties + + /// + /// The (unresolved) type name portion of the original type name. + /// + public string TypeName + { + get { return unresolvedTypeName; } + } + + /// + /// The (unresolved, possibly partial) name of the attandant assembly. + /// + public string AssemblyName + { + get { return unresolvedAssemblyName; } + } + + /// + /// Is the type name being resolved assembly qualified? + /// + public bool IsAssemblyQualified + { + get { return StringUtils.HasText(AssemblyName); } + } + + #endregion + + #region Methods + + private void SplitTypeAndAssemblyNames(string originalTypeName) + { + // generic types may look like: + // Spring.Objects.TestGenericObject`2[[System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]][] , Spring.Core.Tests, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + // + // start searching for assembly separator after the last bracket if any + int typeAssemblyIndex = originalTypeName.LastIndexOf(']'); + typeAssemblyIndex = originalTypeName.IndexOf(TypeAssemblySeparator, typeAssemblyIndex + 1); + if (typeAssemblyIndex < 0) + { + unresolvedTypeName = originalTypeName; + } + else + { + unresolvedTypeName = originalTypeName.Substring( + 0, typeAssemblyIndex).Trim(); + unresolvedAssemblyName = originalTypeName.Substring( + typeAssemblyIndex + 1).Trim(); + } + } + + #endregion } diff --git a/src/Spring/Spring.Core/Core/TypeResolution/TypeRegistry.cs b/src/Spring/Spring.Core/Core/TypeResolution/TypeRegistry.cs index eb424ab2..eda6454b 100644 --- a/src/Spring/Spring.Core/Core/TypeResolution/TypeRegistry.cs +++ b/src/Spring/Spring.Core/Core/TypeResolution/TypeRegistry.cs @@ -24,656 +24,655 @@ using Spring.Util; #endregion -namespace Spring.Core.TypeResolution +namespace Spring.Core.TypeResolution; + +/// +/// Provides access to a central registry of aliased s. +/// +/// +///

+/// Simplifies configuration by allowing aliases to be used instead of +/// fully qualified type names. +///

+///

+/// Comes 'pre-loaded' with a number of convenience alias' for the more +/// common types; an example would be the 'int' (or 'Integer' +/// for Visual Basic.NET developers) alias for the +/// type. +///

+///
+/// Aleksandar Seovic +/// +public sealed class TypeRegistry { + #region Constants + /// - /// Provides access to a central registry of aliased s. + /// Name of the .Net config section that contains Spring.Net type aliases. + /// + private const string TypeAliasesSectionName = "spring/typeAliases"; + + /// + /// The alias around the 'int' type. + /// + public const string Int32Alias = "int"; + + /// + /// The alias around the 'Integer' type (Visual Basic.NET style). + /// + public const string Int32AliasVB = "Integer"; + + /// + /// The alias around the 'int[]' array type. + /// + public const string Int32ArrayAlias = "int[]"; + + /// + /// The alias around the 'Integer()' array type (Visual Basic.NET style). + /// + public const string Int32ArrayAliasVB = "Integer()"; + + /// + /// The alias around the 'decimal' type. + /// + public const string DecimalAlias = "decimal"; + + /// + /// The alias around the 'Decimal' type (Visual Basic.NET style). + /// + public const string DecimalAliasVB = "Decimal"; + + /// + /// The alias around the 'decimal[]' array type. + /// + public const string DecimalArrayAlias = "decimal[]"; + + /// + /// The alias around the 'Decimal()' array type (Visual Basic.NET style). + /// + public const string DecimalArrayAliasVB = "Decimal()"; + + /// + /// The alias around the 'char' type. + /// + public const string CharAlias = "char"; + + /// + /// The alias around the 'Char' type (Visual Basic.NET style). + /// + public const string CharAliasVB = "Char"; + + /// + /// The alias around the 'char[]' array type. + /// + public const string CharArrayAlias = "char[]"; + + /// + /// The alias around the 'Char()' array type (Visual Basic.NET style). + /// + public const string CharArrayAliasVB = "Char()"; + + /// + /// The alias around the 'long' type. + /// + public const string Int64Alias = "long"; + + /// + /// The alias around the 'Long' type (Visual Basic.NET style). + /// + public const string Int64AliasVB = "Long"; + + /// + /// The alias around the 'long[]' array type. + /// + public const string Int64ArrayAlias = "long[]"; + + /// + /// The alias around the 'Long()' array type (Visual Basic.NET style). + /// + public const string Int64ArrayAliasVB = "Long()"; + + /// + /// The alias around the 'short' type. + /// + public const string Int16Alias = "short"; + + /// + /// The alias around the 'Short' type (Visual Basic.NET style). + /// + public const string Int16AliasVB = "Short"; + + /// + /// The alias around the 'short[]' array type. + /// + public const string Int16ArrayAlias = "short[]"; + + /// + /// The alias around the 'Short()' array type (Visual Basic.NET style). + /// + public const string Int16ArrayAliasVB = "Short()"; + + /// + /// The alias around the 'unsigned int' type. + /// + public const string UInt32Alias = "uint"; + + /// + /// The alias around the 'unsigned long' type. + /// + public const string UInt64Alias = "ulong"; + + /// + /// The alias around the 'ulong[]' array type. + /// + public const string UInt64ArrayAlias = "ulong[]"; + + /// + /// The alias around the 'uint[]' array type. + /// + public const string UInt32ArrayAlias = "uint[]"; + + /// + /// The alias around the 'unsigned short' type. + /// + public const string UInt16Alias = "ushort"; + + /// + /// The alias around the 'ushort[]' array type. + /// + public const string UInt16ArrayAlias = "ushort[]"; + + /// + /// The alias around the 'double' type. + /// + public const string DoubleAlias = "double"; + + /// + /// The alias around the 'Double' type (Visual Basic.NET style). + /// + public const string DoubleAliasVB = "Double"; + + /// + /// The alias around the 'double[]' array type. + /// + public const string DoubleArrayAlias = "double[]"; + + /// + /// The alias around the 'Double()' array type (Visual Basic.NET style). + /// + public const string DoubleArrayAliasVB = "Double()"; + + /// + /// The alias around the 'float' type. + /// + public const string FloatAlias = "float"; + + /// + /// The alias around the 'Single' type (Visual Basic.NET style). + /// + public const string SingleAlias = "Single"; + + /// + /// The alias around the 'float[]' array type. + /// + public const string FloatArrayAlias = "float[]"; + + /// + /// The alias around the 'Single()' array type (Visual Basic.NET style). + /// + public const string SingleArrayAliasVB = "Single()"; + + /// + /// The alias around the 'DateTime' type. + /// + public const string DateTimeAlias = "DateTime"; + + /// + /// The alias around the 'DateTime' type (C# style). + /// + public const string DateAlias = "date"; + + /// + /// The alias around the 'DateTime' type (Visual Basic.NET style). + /// + public const string DateAliasVB = "Date"; + + /// + /// The alias around the 'DateTime[]' array type. + /// + public const string DateTimeArrayAlias = "DateTime[]"; + + /// + /// The alias around the 'DateTime[]' array type. + /// + public const string DateTimeArrayAliasCSharp = "date[]"; + + /// + /// The alias around the 'DateTime()' array type (Visual Basic.NET style). + /// + public const string DateTimeArrayAliasVB = "DateTime()"; + + /// + /// The alias around the 'bool' type. + /// + public const string BoolAlias = "bool"; + + /// + /// The alias around the 'Boolean' type (Visual Basic.NET style). + /// + public const string BoolAliasVB = "Boolean"; + + /// + /// The alias around the 'bool[]' array type. + /// + public const string BoolArrayAlias = "bool[]"; + + /// + /// The alias around the 'Boolean()' array type (Visual Basic.NET style). + /// + public const string BoolArrayAliasVB = "Boolean()"; + + /// + /// The alias around the 'string' type. + /// + public const string StringAlias = "string"; + + /// + /// The alias around the 'string' type (Visual Basic.NET style). + /// + public const string StringAliasVB = "String"; + + /// + /// The alias around the 'string[]' array type. + /// + public const string StringArrayAlias = "string[]"; + + /// + /// The alias around the 'string[]' array type (Visual Basic.NET style). + /// + public const string StringArrayAliasVB = "String()"; + + /// + /// The alias around the 'object' type. + /// + public const string ObjectAlias = "object"; + + /// + /// The alias around the 'object' type (Visual Basic.NET style). + /// + public const string ObjectAliasVB = "Object"; + + /// + /// The alias around the 'object[]' array type. + /// + public const string ObjectArrayAlias = "object[]"; + + /// + /// The alias around the 'object[]' array type (Visual Basic.NET style). + /// + public const string ObjectArrayAliasVB = "Object()"; + + /// + /// The alias around the 'int?' type. + /// + public const string NullableInt32Alias = "int?"; + + /// + /// The alias around the 'int?[]' array type. + /// + public const string NullableInt32ArrayAlias = "int?[]"; + + /// + /// The alias around the 'decimal?' type. + /// + public const string NullableDecimalAlias = "decimal?"; + + /// + /// The alias around the 'decimal?[]' array type. + /// + public const string NullableDecimalArrayAlias = "decimal?[]"; + + /// + /// The alias around the 'char?' type. + /// + public const string NullableCharAlias = "char?"; + + /// + /// The alias around the 'char?[]' array type. + /// + public const string NullableCharArrayAlias = "char?[]"; + + /// + /// The alias around the 'long?' type. + /// + public const string NullableInt64Alias = "long?"; + + /// + /// The alias around the 'long?[]' array type. + /// + public const string NullableInt64ArrayAlias = "long?[]"; + + /// + /// The alias around the 'short?' type. + /// + public const string NullableInt16Alias = "short?"; + + /// + /// The alias around the 'short?[]' array type. + /// + public const string NullableInt16ArrayAlias = "short?[]"; + + /// + /// The alias around the 'unsigned int?' type. + /// + public const string NullableUInt32Alias = "uint?"; + + /// + /// The alias around the 'unsigned long?' type. + /// + public const string NullableUInt64Alias = "ulong?"; + + /// + /// The alias around the 'ulong?[]' array type. + /// + public const string NullableUInt64ArrayAlias = "ulong?[]"; + + /// + /// The alias around the 'uint?[]' array type. + /// + public const string NullableUInt32ArrayAlias = "uint?[]"; + + /// + /// The alias around the 'unsigned short?' type. + /// + public const string NullableUInt16Alias = "ushort?"; + + /// + /// The alias around the 'ushort?[]' array type. + /// + public const string NullableUInt16ArrayAlias = "ushort?[]"; + + /// + /// The alias around the 'double?' type. + /// + public const string NullableDoubleAlias = "double?"; + + /// + /// The alias around the 'double?[]' array type. + /// + public const string NullableDoubleArrayAlias = "double?[]"; + + /// + /// The alias around the 'float?' type. + /// + public const string NullableFloatAlias = "float?"; + + /// + /// The alias around the 'float?[]' array type. + /// + public const string NullableFloatArrayAlias = "float?[]"; + + /// + /// The alias around the 'bool?' type. + /// + public const string NullableBoolAlias = "bool?"; + + /// + /// The alias around the 'bool?[]' array type. + /// + public const string NullableBoolArrayAlias = "bool?[]"; + + #endregion + + #region Fields + + private static readonly object syncRoot = new object(); + private static IDictionary types = new Dictionary(); + + #endregion + + #region Constructor (s) / Destructor + + /// + /// Registers standard and user-configured type aliases. + /// + static TypeRegistry() + { + lock (syncRoot) + { + types["Int32"] = typeof(Int32); + types[Int32Alias] = typeof(Int32); + types[Int32AliasVB] = typeof(Int32); + types[Int32ArrayAlias] = typeof(Int32[]); + types[Int32ArrayAliasVB] = typeof(Int32[]); + + types["UInt32"] = typeof(UInt32); + types[UInt32Alias] = typeof(UInt32); + types[UInt32ArrayAlias] = typeof(UInt32[]); + + types["Int16"] = typeof(Int16); + types[Int16Alias] = typeof(Int16); + types[Int16AliasVB] = typeof(Int16); + types[Int16ArrayAlias] = typeof(Int16[]); + types[Int16ArrayAliasVB] = typeof(Int16[]); + + types["UInt16"] = typeof(UInt16); + types[UInt16Alias] = typeof(UInt16); + types[UInt16ArrayAlias] = typeof(UInt16[]); + + types["Int64"] = typeof(Int64); + types[Int64Alias] = typeof(Int64); + types[Int64AliasVB] = typeof(Int64); + types[Int64ArrayAlias] = typeof(Int64[]); + types[Int64ArrayAliasVB] = typeof(Int64[]); + + types["UInt64"] = typeof(UInt64); + types[UInt64Alias] = typeof(UInt64); + types[UInt64ArrayAlias] = typeof(UInt64[]); + + types[DoubleAlias] = typeof(double); + types[DoubleAliasVB] = typeof(double); + types[DoubleArrayAlias] = typeof(double[]); + types[DoubleArrayAliasVB] = typeof(double[]); + + types[FloatAlias] = typeof(float); + types[SingleAlias] = typeof(float); + types[FloatArrayAlias] = typeof(float[]); + types[SingleArrayAliasVB] = typeof(float[]); + + types[DateTimeAlias] = typeof(DateTime); + types[DateAlias] = typeof(DateTime); + types[DateAliasVB] = typeof(DateTime); + types[DateTimeArrayAlias] = typeof(DateTime[]); + types[DateTimeArrayAliasCSharp] = typeof(DateTime[]); + types[DateTimeArrayAliasVB] = typeof(DateTime[]); + + types[BoolAlias] = typeof(bool); + types[BoolAliasVB] = typeof(bool); + types[BoolArrayAlias] = typeof(bool[]); + types[BoolArrayAliasVB] = typeof(bool[]); + + types[DecimalAlias] = typeof(decimal); + types[DecimalAliasVB] = typeof(decimal); + types[DecimalArrayAlias] = typeof(decimal[]); + types[DecimalArrayAliasVB] = typeof(decimal[]); + + types[CharAlias] = typeof(char); + types[CharAliasVB] = typeof(char); + types[CharArrayAlias] = typeof(char[]); + types[CharArrayAliasVB] = typeof(char[]); + + types[StringAlias] = typeof(string); + types[StringAliasVB] = typeof(string); + types[StringArrayAlias] = typeof(string[]); + types[StringArrayAliasVB] = typeof(string[]); + + types[ObjectAlias] = typeof(object); + types[ObjectAliasVB] = typeof(object); + types[ObjectArrayAlias] = typeof(object[]); + types[ObjectArrayAliasVB] = typeof(object[]); + + types[NullableInt32Alias] = typeof(int?); + types[NullableInt32ArrayAlias] = typeof(int?[]); + + types[NullableDecimalAlias] = typeof(decimal?); + types[NullableDecimalArrayAlias] = typeof(decimal?[]); + + types[NullableCharAlias] = typeof(char?); + types[NullableCharArrayAlias] = typeof(char?[]); + + types[NullableInt64Alias] = typeof(long?); + types[NullableInt64ArrayAlias] = typeof(long?[]); + + types[NullableInt16Alias] = typeof(short?); + types[NullableInt16ArrayAlias] = typeof(short?[]); + + types[NullableUInt32Alias] = typeof(uint?); + types[NullableUInt32ArrayAlias] = typeof(uint?[]); + + types[NullableUInt64Alias] = typeof(ulong?); + types[NullableUInt64ArrayAlias] = typeof(ulong?[]); + + types[NullableUInt16Alias] = typeof(ushort?); + types[NullableUInt16ArrayAlias] = typeof(ushort?[]); + + types[NullableDoubleAlias] = typeof(double?); + types[NullableDoubleArrayAlias] = typeof(double?[]); + + types[NullableFloatAlias] = typeof(float?); + types[NullableFloatArrayAlias] = typeof(float?[]); + + types[NullableBoolAlias] = typeof(bool?); + types[NullableBoolArrayAlias] = typeof(bool?[]); + + // register user-configured type aliases + ConfigurationUtils.GetSection(TypeAliasesSectionName); + } + } + + #endregion + + /// + /// Registers an alias for the specified . /// /// ///

- /// Simplifies configuration by allowing aliases to be used instead of - /// fully qualified type names. - ///

- ///

- /// Comes 'pre-loaded' with a number of convenience alias' for the more - /// common types; an example would be the 'int' (or 'Integer' - /// for Visual Basic.NET developers) alias for the - /// type. + /// This overload does eager resolution of the + /// referred to by the parameter. It will throw a + /// if the referred + /// to by the parameter cannot be resolved. ///

///
- /// Aleksandar Seovic - /// - public sealed class TypeRegistry + /// + /// A string that will be used as an alias for the specified + /// . + /// + /// + /// The (possibly partially assembly qualified) name of the + /// to register the alias for. + /// + /// + /// If either of the supplied parameters is or + /// contains only whitespace character(s). + /// + /// + /// If the referred to by the supplied + /// cannot be loaded. + /// + public static void RegisterType(string alias, string typeName) { - #region Constants - - /// - /// Name of the .Net config section that contains Spring.Net type aliases. - /// - private const string TypeAliasesSectionName = "spring/typeAliases"; - - /// - /// The alias around the 'int' type. - /// - public const string Int32Alias = "int"; - - /// - /// The alias around the 'Integer' type (Visual Basic.NET style). - /// - public const string Int32AliasVB = "Integer"; - - /// - /// The alias around the 'int[]' array type. - /// - public const string Int32ArrayAlias = "int[]"; - - /// - /// The alias around the 'Integer()' array type (Visual Basic.NET style). - /// - public const string Int32ArrayAliasVB = "Integer()"; - - /// - /// The alias around the 'decimal' type. - /// - public const string DecimalAlias = "decimal"; - - /// - /// The alias around the 'Decimal' type (Visual Basic.NET style). - /// - public const string DecimalAliasVB = "Decimal"; - - /// - /// The alias around the 'decimal[]' array type. - /// - public const string DecimalArrayAlias = "decimal[]"; - - /// - /// The alias around the 'Decimal()' array type (Visual Basic.NET style). - /// - public const string DecimalArrayAliasVB = "Decimal()"; - - /// - /// The alias around the 'char' type. - /// - public const string CharAlias = "char"; - - /// - /// The alias around the 'Char' type (Visual Basic.NET style). - /// - public const string CharAliasVB = "Char"; - - /// - /// The alias around the 'char[]' array type. - /// - public const string CharArrayAlias = "char[]"; - - /// - /// The alias around the 'Char()' array type (Visual Basic.NET style). - /// - public const string CharArrayAliasVB = "Char()"; - - /// - /// The alias around the 'long' type. - /// - public const string Int64Alias = "long"; - - /// - /// The alias around the 'Long' type (Visual Basic.NET style). - /// - public const string Int64AliasVB = "Long"; - - /// - /// The alias around the 'long[]' array type. - /// - public const string Int64ArrayAlias = "long[]"; - - /// - /// The alias around the 'Long()' array type (Visual Basic.NET style). - /// - public const string Int64ArrayAliasVB = "Long()"; - - /// - /// The alias around the 'short' type. - /// - public const string Int16Alias = "short"; - - /// - /// The alias around the 'Short' type (Visual Basic.NET style). - /// - public const string Int16AliasVB = "Short"; - - /// - /// The alias around the 'short[]' array type. - /// - public const string Int16ArrayAlias = "short[]"; - - /// - /// The alias around the 'Short()' array type (Visual Basic.NET style). - /// - public const string Int16ArrayAliasVB = "Short()"; - - /// - /// The alias around the 'unsigned int' type. - /// - public const string UInt32Alias = "uint"; - - /// - /// The alias around the 'unsigned long' type. - /// - public const string UInt64Alias = "ulong"; - - /// - /// The alias around the 'ulong[]' array type. - /// - public const string UInt64ArrayAlias = "ulong[]"; - - /// - /// The alias around the 'uint[]' array type. - /// - public const string UInt32ArrayAlias = "uint[]"; - - /// - /// The alias around the 'unsigned short' type. - /// - public const string UInt16Alias = "ushort"; - - /// - /// The alias around the 'ushort[]' array type. - /// - public const string UInt16ArrayAlias = "ushort[]"; - - /// - /// The alias around the 'double' type. - /// - public const string DoubleAlias = "double"; - - /// - /// The alias around the 'Double' type (Visual Basic.NET style). - /// - public const string DoubleAliasVB = "Double"; - - /// - /// The alias around the 'double[]' array type. - /// - public const string DoubleArrayAlias = "double[]"; - - /// - /// The alias around the 'Double()' array type (Visual Basic.NET style). - /// - public const string DoubleArrayAliasVB = "Double()"; - - /// - /// The alias around the 'float' type. - /// - public const string FloatAlias = "float"; - - /// - /// The alias around the 'Single' type (Visual Basic.NET style). - /// - public const string SingleAlias = "Single"; - - /// - /// The alias around the 'float[]' array type. - /// - public const string FloatArrayAlias = "float[]"; - - /// - /// The alias around the 'Single()' array type (Visual Basic.NET style). - /// - public const string SingleArrayAliasVB = "Single()"; - - /// - /// The alias around the 'DateTime' type. - /// - public const string DateTimeAlias = "DateTime"; - - /// - /// The alias around the 'DateTime' type (C# style). - /// - public const string DateAlias = "date"; - - /// - /// The alias around the 'DateTime' type (Visual Basic.NET style). - /// - public const string DateAliasVB = "Date"; - - /// - /// The alias around the 'DateTime[]' array type. - /// - public const string DateTimeArrayAlias = "DateTime[]"; - - /// - /// The alias around the 'DateTime[]' array type. - /// - public const string DateTimeArrayAliasCSharp = "date[]"; - - /// - /// The alias around the 'DateTime()' array type (Visual Basic.NET style). - /// - public const string DateTimeArrayAliasVB = "DateTime()"; - - /// - /// The alias around the 'bool' type. - /// - public const string BoolAlias = "bool"; - - /// - /// The alias around the 'Boolean' type (Visual Basic.NET style). - /// - public const string BoolAliasVB = "Boolean"; - - /// - /// The alias around the 'bool[]' array type. - /// - public const string BoolArrayAlias = "bool[]"; - - /// - /// The alias around the 'Boolean()' array type (Visual Basic.NET style). - /// - public const string BoolArrayAliasVB = "Boolean()"; - - /// - /// The alias around the 'string' type. - /// - public const string StringAlias = "string"; - - /// - /// The alias around the 'string' type (Visual Basic.NET style). - /// - public const string StringAliasVB = "String"; - - /// - /// The alias around the 'string[]' array type. - /// - public const string StringArrayAlias = "string[]"; - - /// - /// The alias around the 'string[]' array type (Visual Basic.NET style). - /// - public const string StringArrayAliasVB = "String()"; - - /// - /// The alias around the 'object' type. - /// - public const string ObjectAlias = "object"; - - /// - /// The alias around the 'object' type (Visual Basic.NET style). - /// - public const string ObjectAliasVB = "Object"; - - /// - /// The alias around the 'object[]' array type. - /// - public const string ObjectArrayAlias = "object[]"; - - /// - /// The alias around the 'object[]' array type (Visual Basic.NET style). - /// - public const string ObjectArrayAliasVB = "Object()"; - - /// - /// The alias around the 'int?' type. - /// - public const string NullableInt32Alias = "int?"; - - /// - /// The alias around the 'int?[]' array type. - /// - public const string NullableInt32ArrayAlias = "int?[]"; - - /// - /// The alias around the 'decimal?' type. - /// - public const string NullableDecimalAlias = "decimal?"; - - /// - /// The alias around the 'decimal?[]' array type. - /// - public const string NullableDecimalArrayAlias = "decimal?[]"; - - /// - /// The alias around the 'char?' type. - /// - public const string NullableCharAlias = "char?"; - - /// - /// The alias around the 'char?[]' array type. - /// - public const string NullableCharArrayAlias = "char?[]"; - - /// - /// The alias around the 'long?' type. - /// - public const string NullableInt64Alias = "long?"; - - /// - /// The alias around the 'long?[]' array type. - /// - public const string NullableInt64ArrayAlias = "long?[]"; - - /// - /// The alias around the 'short?' type. - /// - public const string NullableInt16Alias = "short?"; - - /// - /// The alias around the 'short?[]' array type. - /// - public const string NullableInt16ArrayAlias = "short?[]"; - - /// - /// The alias around the 'unsigned int?' type. - /// - public const string NullableUInt32Alias = "uint?"; - - /// - /// The alias around the 'unsigned long?' type. - /// - public const string NullableUInt64Alias = "ulong?"; - - /// - /// The alias around the 'ulong?[]' array type. - /// - public const string NullableUInt64ArrayAlias = "ulong?[]"; - - /// - /// The alias around the 'uint?[]' array type. - /// - public const string NullableUInt32ArrayAlias = "uint?[]"; - - /// - /// The alias around the 'unsigned short?' type. - /// - public const string NullableUInt16Alias = "ushort?"; - - /// - /// The alias around the 'ushort?[]' array type. - /// - public const string NullableUInt16ArrayAlias = "ushort?[]"; - - /// - /// The alias around the 'double?' type. - /// - public const string NullableDoubleAlias = "double?"; - - /// - /// The alias around the 'double?[]' array type. - /// - public const string NullableDoubleArrayAlias = "double?[]"; - - /// - /// The alias around the 'float?' type. - /// - public const string NullableFloatAlias = "float?"; - - /// - /// The alias around the 'float?[]' array type. - /// - public const string NullableFloatArrayAlias = "float?[]"; - - /// - /// The alias around the 'bool?' type. - /// - public const string NullableBoolAlias = "bool?"; - - /// - /// The alias around the 'bool?[]' array type. - /// - public const string NullableBoolArrayAlias = "bool?[]"; - - #endregion - - #region Fields - - private static readonly object syncRoot = new object(); - private static IDictionary types = new Dictionary(); - - #endregion - - #region Constructor (s) / Destructor - - /// - /// Registers standard and user-configured type aliases. - /// - static TypeRegistry() + AssertUtils.ArgumentHasText(alias, "alias"); + AssertUtils.ArgumentHasText(typeName, "typeName"); + + Type type = TypeResolutionUtils.ResolveType(typeName); + + if (type.IsGenericTypeDefinition) + alias += ("`" + type.GetGenericArguments().Length); + + RegisterType(alias, type); + } + + /// + /// Registers short type name as an alias for + /// the supplied . + /// + /// + /// The to register. + /// + /// + /// If the supplied is . + /// + public static void RegisterType(Type type) + { + AssertUtils.ArgumentNotNull(type, "type"); + + lock (syncRoot) { - lock (syncRoot) - { - types["Int32"] = typeof(Int32); - types[Int32Alias] = typeof(Int32); - types[Int32AliasVB] = typeof(Int32); - types[Int32ArrayAlias] = typeof(Int32[]); - types[Int32ArrayAliasVB] = typeof(Int32[]); - - types["UInt32"] = typeof(UInt32); - types[UInt32Alias] = typeof(UInt32); - types[UInt32ArrayAlias] = typeof(UInt32[]); - - types["Int16"] = typeof(Int16); - types[Int16Alias] = typeof(Int16); - types[Int16AliasVB] = typeof(Int16); - types[Int16ArrayAlias] = typeof(Int16[]); - types[Int16ArrayAliasVB] = typeof(Int16[]); - - types["UInt16"] = typeof(UInt16); - types[UInt16Alias] = typeof(UInt16); - types[UInt16ArrayAlias] = typeof(UInt16[]); - - types["Int64"] = typeof(Int64); - types[Int64Alias] = typeof(Int64); - types[Int64AliasVB] = typeof(Int64); - types[Int64ArrayAlias] = typeof(Int64[]); - types[Int64ArrayAliasVB] = typeof(Int64[]); - - types["UInt64"] = typeof(UInt64); - types[UInt64Alias] = typeof(UInt64); - types[UInt64ArrayAlias] = typeof(UInt64[]); - - types[DoubleAlias] = typeof(double); - types[DoubleAliasVB] = typeof(double); - types[DoubleArrayAlias] = typeof(double[]); - types[DoubleArrayAliasVB] = typeof(double[]); - - types[FloatAlias] = typeof(float); - types[SingleAlias] = typeof(float); - types[FloatArrayAlias] = typeof(float[]); - types[SingleArrayAliasVB] = typeof(float[]); - - types[DateTimeAlias] = typeof(DateTime); - types[DateAlias] = typeof(DateTime); - types[DateAliasVB] = typeof(DateTime); - types[DateTimeArrayAlias] = typeof(DateTime[]); - types[DateTimeArrayAliasCSharp] = typeof(DateTime[]); - types[DateTimeArrayAliasVB] = typeof(DateTime[]); - - types[BoolAlias] = typeof(bool); - types[BoolAliasVB] = typeof(bool); - types[BoolArrayAlias] = typeof(bool[]); - types[BoolArrayAliasVB] = typeof(bool[]); - - types[DecimalAlias] = typeof(decimal); - types[DecimalAliasVB] = typeof(decimal); - types[DecimalArrayAlias] = typeof(decimal[]); - types[DecimalArrayAliasVB] = typeof(decimal[]); - - types[CharAlias] = typeof(char); - types[CharAliasVB] = typeof(char); - types[CharArrayAlias] = typeof(char[]); - types[CharArrayAliasVB] = typeof(char[]); - - types[StringAlias] = typeof(string); - types[StringAliasVB] = typeof(string); - types[StringArrayAlias] = typeof(string[]); - types[StringArrayAliasVB] = typeof(string[]); - - types[ObjectAlias] = typeof(object); - types[ObjectAliasVB] = typeof(object); - types[ObjectArrayAlias] = typeof(object[]); - types[ObjectArrayAliasVB] = typeof(object[]); - - types[NullableInt32Alias] = typeof(int?); - types[NullableInt32ArrayAlias] = typeof(int?[]); - - types[NullableDecimalAlias] = typeof(decimal?); - types[NullableDecimalArrayAlias] = typeof(decimal?[]); - - types[NullableCharAlias] = typeof(char?); - types[NullableCharArrayAlias] = typeof(char?[]); - - types[NullableInt64Alias] = typeof(long?); - types[NullableInt64ArrayAlias] = typeof(long?[]); - - types[NullableInt16Alias] = typeof(short?); - types[NullableInt16ArrayAlias] = typeof(short?[]); - - types[NullableUInt32Alias] = typeof(uint?); - types[NullableUInt32ArrayAlias] = typeof(uint?[]); - - types[NullableUInt64Alias] = typeof(ulong?); - types[NullableUInt64ArrayAlias] = typeof(ulong?[]); - - types[NullableUInt16Alias] = typeof(ushort?); - types[NullableUInt16ArrayAlias] = typeof(ushort?[]); - - types[NullableDoubleAlias] = typeof(double?); - types[NullableDoubleArrayAlias] = typeof(double?[]); - - types[NullableFloatAlias] = typeof(float?); - types[NullableFloatArrayAlias] = typeof(float?[]); - - types[NullableBoolAlias] = typeof(bool?); - types[NullableBoolArrayAlias] = typeof(bool?[]); - - // register user-configured type aliases - ConfigurationUtils.GetSection(TypeAliasesSectionName); - } - } - - #endregion - - /// - /// Registers an alias for the specified . - /// - /// - ///

- /// This overload does eager resolution of the - /// referred to by the parameter. It will throw a - /// if the referred - /// to by the parameter cannot be resolved. - ///

- ///
- /// - /// A string that will be used as an alias for the specified - /// . - /// - /// - /// The (possibly partially assembly qualified) name of the - /// to register the alias for. - /// - /// - /// If either of the supplied parameters is or - /// contains only whitespace character(s). - /// - /// - /// If the referred to by the supplied - /// cannot be loaded. - /// - public static void RegisterType(string alias, string typeName) - { - AssertUtils.ArgumentHasText(alias, "alias"); - AssertUtils.ArgumentHasText(typeName, "typeName"); - - Type type = TypeResolutionUtils.ResolveType(typeName); - - if (type.IsGenericTypeDefinition) - alias += ("`" + type.GetGenericArguments().Length); - - RegisterType(alias, type); - } - - /// - /// Registers short type name as an alias for - /// the supplied . - /// - /// - /// The to register. - /// - /// - /// If the supplied is . - /// - public static void RegisterType(Type type) - { - AssertUtils.ArgumentNotNull(type, "type"); - - lock (syncRoot) - { - types[type.Name] = type; - } - } - - /// - /// Registers an alias for the supplied . - /// - /// - /// The alias for the supplied . - /// - /// - /// The to register the supplied under. - /// - /// - /// If the supplied is ; or if - /// the supplied is or - /// contains only whitespace character(s). - /// - public static void RegisterType(string alias, Type type) - { - AssertUtils.ArgumentHasText(alias, "alias"); - AssertUtils.ArgumentNotNull(type, "type"); - - lock (syncRoot) - { - types[alias] = type; - } - } - - /// - /// Resolves the supplied to a . - /// - /// - /// The alias to resolve. - /// - /// - /// The the supplied was - /// associated with, or if no - /// was previously registered for the supplied . - /// - /// - /// If the supplied is or - /// contains only whitespace character(s). - /// - public static Type ResolveType(string alias) - { - AssertUtils.ArgumentHasText(alias, "alias"); - Type type; - types.TryGetValue(alias, out type); - return type; - } - - /// - /// Returns a flag specifying whether TypeRegistry contains - /// specified alias or not. - /// - /// - /// Alias to check. - /// - /// - /// true if the specified type alias is registered, - /// false otherwise. - /// - public static bool ContainsAlias(string alias) - { - return types.ContainsKey(alias); + types[type.Name] = type; } } + + /// + /// Registers an alias for the supplied . + /// + /// + /// The alias for the supplied . + /// + /// + /// The to register the supplied under. + /// + /// + /// If the supplied is ; or if + /// the supplied is or + /// contains only whitespace character(s). + /// + public static void RegisterType(string alias, Type type) + { + AssertUtils.ArgumentHasText(alias, "alias"); + AssertUtils.ArgumentNotNull(type, "type"); + + lock (syncRoot) + { + types[alias] = type; + } + } + + /// + /// Resolves the supplied to a . + /// + /// + /// The alias to resolve. + /// + /// + /// The the supplied was + /// associated with, or if no + /// was previously registered for the supplied . + /// + /// + /// If the supplied is or + /// contains only whitespace character(s). + /// + public static Type ResolveType(string alias) + { + AssertUtils.ArgumentHasText(alias, "alias"); + Type type; + types.TryGetValue(alias, out type); + return type; + } + + /// + /// Returns a flag specifying whether TypeRegistry contains + /// specified alias or not. + /// + /// + /// Alias to check. + /// + /// + /// true if the specified type alias is registered, + /// false otherwise. + /// + public static bool ContainsAlias(string alias) + { + return types.ContainsKey(alias); + } } diff --git a/src/Spring/Spring.Core/Core/TypeResolution/TypeResolutionUtils.cs b/src/Spring/Spring.Core/Core/TypeResolution/TypeResolutionUtils.cs index 82696f17..fdac82bf 100644 --- a/src/Spring/Spring.Core/Core/TypeResolution/TypeResolutionUtils.cs +++ b/src/Spring/Spring.Core/Core/TypeResolution/TypeResolutionUtils.cs @@ -23,185 +23,186 @@ using System.Globalization; using System.Text.RegularExpressions; using System.Reflection; - using Spring.Util; #endregion -namespace Spring.Core.TypeResolution +namespace Spring.Core.TypeResolution; + +/// +/// Helper methods with regard to type resolution. +/// +/// +///

+/// Not intended to be used directly by applications. +///

+///
+/// Bruno Baia +public sealed class TypeResolutionUtils { + #region Fields + + private static readonly ITypeResolver internalTypeResolver + = new CachedTypeResolver(new GenericTypeResolver()); + + #endregion + + #region Constructor (s) / Destructor + + // CLOVER:OFF + /// - /// Helper methods with regard to type resolution. + /// Creates a new instance of the class. /// /// ///

- /// Not intended to be used directly by applications. + /// This is a utility class, and as such exposes no public constructors. ///

///
- /// Bruno Baia - public sealed class TypeResolutionUtils + private TypeResolutionUtils() { - #region Fields + } - private static readonly ITypeResolver internalTypeResolver - = new CachedTypeResolver(new GenericTypeResolver()); + // CLOVER:ON - #endregion + #endregion - #region Constructor (s) / Destructor + #region Methods - // CLOVER:OFF - - /// - /// Creates a new instance of the class. - /// - /// - ///

- /// This is a utility class, and as such exposes no public constructors. - ///

- ///
- private TypeResolutionUtils() + /// + /// Resolves the supplied type name into a + /// instance. + /// + /// + ///

+ /// If you require special resolution, do + /// not use this method, but rather instantiate + /// your own . + ///

+ ///
+ /// + /// The (possibly partially assembly qualified) name of a + /// . + /// + /// + /// A resolved instance. + /// + /// + /// If the type cannot be resolved. + /// + public static Type ResolveType(string typeName) + { + Type type = TypeRegistry.ResolveType(typeName); + if (type == null) { + type = internalTypeResolver.Resolve(typeName); } - // CLOVER:ON + return type; + } - #endregion + /// + /// Resolves a string array of interface names to + /// a array. + /// + /// + /// An array of valid interface names. Each name must include the full + /// interface and assembly name. + /// + /// An array of interface s. + /// + /// If any of the interfaces can't be loaded. + /// + /// + /// If any of the s specified is not an interface. + /// + /// + /// If (or any of its elements ) is + /// . + /// + public static IList ResolveInterfaceArray(string[] interfaceNames) + { + AssertUtils.ArgumentNotNull(interfaceNames, "interfaceNames"); - #region Methods - - /// - /// Resolves the supplied type name into a - /// instance. - /// - /// - ///

- /// If you require special resolution, do - /// not use this method, but rather instantiate - /// your own . - ///

- ///
- /// - /// The (possibly partially assembly qualified) name of a - /// . - /// - /// - /// A resolved instance. - /// - /// - /// If the type cannot be resolved. - /// - public static Type ResolveType(string typeName) + List interfaces = new List(); + for (int i = 0; i < interfaceNames.Length; i++) { - Type type = TypeRegistry.ResolveType(typeName); - if (type == null) + string interfaceName = interfaceNames[i]; + AssertUtils.ArgumentNotNull(interfaceName, + string.Format(CultureInfo.InvariantCulture, "interfaceNames[{0}]", i)); + Type resolvedInterface = ResolveType(interfaceName); + if (!resolvedInterface.IsInterface) { - type = internalTypeResolver.Resolve(typeName); + throw new ArgumentException( + string.Format(CultureInfo.InvariantCulture, + "[{0}] is a class.", + resolvedInterface.FullName)); } - return type; + + interfaces.Add(resolvedInterface); + interfaces.AddRange(resolvedInterface.GetInterfaces()); } - /// - /// Resolves a string array of interface names to - /// a array. - /// - /// - /// An array of valid interface names. Each name must include the full - /// interface and assembly name. - /// - /// An array of interface s. - /// - /// If any of the interfaces can't be loaded. - /// - /// - /// If any of the s specified is not an interface. - /// - /// - /// If (or any of its elements ) is - /// . - /// - public static IList ResolveInterfaceArray(string[] interfaceNames) + return interfaces; + } + + #region MethodMatch + + // TODO : Use the future Pointcut expression language instead + + private readonly static Regex methodMatchRegex = new Regex( + @"(?([\w]+\.)*[\w\*]+)(?(\((?[\w\.]+(,[\w\.]+)*)*\))?)", + RegexOptions.Compiled | RegexOptions.ExplicitCapture); + + /// + /// Match a method against the given pattern. + /// + /// the pattern to match against. + /// the method to match. + /// + /// if the method matches the given pattern; otherwise . + /// + /// + /// If the supplied is invalid. + /// + public static bool MethodMatch(string pattern, MethodInfo method) + { + Match m = methodMatchRegex.Match(pattern); + + if (!m.Success) + throw new ArgumentException(String.Format("The pattern [{0}] is not well-formed.", pattern)); + + // Check method name + string methodNamePattern = m.Groups["methodName"].Value; + if (!PatternMatchUtils.SimpleMatch(methodNamePattern, method.Name)) + return false; + + if (m.Groups["parameters"].Value.Length > 0) { - AssertUtils.ArgumentNotNull(interfaceNames, "interfaceNames"); - - List interfaces = new List(); - for (int i = 0; i < interfaceNames.Length; i++) - { - string interfaceName = interfaceNames[i]; - AssertUtils.ArgumentNotNull(interfaceName, - string.Format(CultureInfo.InvariantCulture, "interfaceNames[{0}]", i)); - Type resolvedInterface = ResolveType(interfaceName); - if (!resolvedInterface.IsInterface) - { - throw new ArgumentException( - string.Format(CultureInfo.InvariantCulture, - "[{0}] is a class.", - resolvedInterface.FullName)); - } - interfaces.Add(resolvedInterface); - interfaces.AddRange(resolvedInterface.GetInterfaces()); - } - return interfaces; - } - - #region MethodMatch - - // TODO : Use the future Pointcut expression language instead - - private readonly static Regex methodMatchRegex = new Regex( - @"(?([\w]+\.)*[\w\*]+)(?(\((?[\w\.]+(,[\w\.]+)*)*\))?)", - RegexOptions.Compiled | RegexOptions.ExplicitCapture); - - /// - /// Match a method against the given pattern. - /// - /// the pattern to match against. - /// the method to match. - /// - /// if the method matches the given pattern; otherwise . - /// - /// - /// If the supplied is invalid. - /// - public static bool MethodMatch(string pattern, MethodInfo method) - { - Match m = methodMatchRegex.Match(pattern); - - if (!m.Success) - throw new ArgumentException(String.Format("The pattern [{0}] is not well-formed.", pattern)); - - // Check method name - string methodNamePattern = m.Groups["methodName"].Value; - if (!PatternMatchUtils.SimpleMatch(methodNamePattern, method.Name)) - return false; - - if (m.Groups["parameters"].Value.Length > 0) - { - // Check parameter types - string parameters = m.Groups["parameterTypes"].Value; - string[] paramTypes = - (parameters.Length == 0) + // Check parameter types + string parameters = m.Groups["parameterTypes"].Value; + string[] paramTypes = + (parameters.Length == 0) ? new string[0] : StringUtils.DelimitedListToStringArray(parameters, ","); - ParameterInfo[] paramInfos = method.GetParameters(); + ParameterInfo[] paramInfos = method.GetParameters(); - // Verify parameter count - if (paramTypes.Length != paramInfos.Length) + // Verify parameter count + if (paramTypes.Length != paramInfos.Length) + return false; + + // Match parameter types + for (int i = 0; i < paramInfos.Length; i++) + { + if (paramInfos[i].ParameterType != TypeResolutionUtils.ResolveType(paramTypes[i])) return false; - - // Match parameter types - for (int i = 0; i < paramInfos.Length; i++) - { - if (paramInfos[i].ParameterType != TypeResolutionUtils.ResolveType(paramTypes[i])) - return false; - } } - - return true; } - #endregion - - #endregion + return true; } + + #endregion + + #endregion } diff --git a/src/Spring/Spring.Core/Core/TypeResolution/TypeResolver.cs b/src/Spring/Spring.Core/Core/TypeResolution/TypeResolver.cs index 89b37e0e..86da84b1 100644 --- a/src/Spring/Spring.Core/Core/TypeResolution/TypeResolver.cs +++ b/src/Spring/Spring.Core/Core/TypeResolution/TypeResolver.cs @@ -21,149 +21,151 @@ #region Imports using System.Reflection; - using Spring.Util; #endregion -namespace Spring.Core.TypeResolution +namespace Spring.Core.TypeResolution; + +/// +/// Resolves a by name. +/// +/// Rick Evans +/// Aleksandar Seovic +/// Bruno Baia +public class TypeResolver : ITypeResolver { /// - /// Resolves a by name. + /// Resolves the supplied to a + /// instance. /// - /// Rick Evans - /// Aleksandar Seovic - /// Bruno Baia - public class TypeResolver : ITypeResolver + /// + /// The unresolved (possibly partially assembly qualified) name + /// of a . + /// + /// + /// A resolved instance. + /// + /// + /// If the supplied could not be resolved + /// to a . + /// + public virtual Type Resolve(string typeName) { - /// - /// Resolves the supplied to a - /// instance. - /// - /// - /// The unresolved (possibly partially assembly qualified) name - /// of a . - /// - /// - /// A resolved instance. - /// - /// - /// If the supplied could not be resolved - /// to a . - /// - public virtual Type Resolve(string typeName) + if (StringUtils.IsNullOrEmpty(typeName)) { - if (StringUtils.IsNullOrEmpty(typeName)) - { - throw BuildTypeLoadException(typeName); - } - TypeAssemblyHolder typeInfo = new TypeAssemblyHolder(typeName); - Type type = null; - try - { - type = (typeInfo.IsAssemblyQualified) ? - LoadTypeDirectlyFromAssembly(typeInfo) : - LoadTypeByIteratingOverAllLoadedAssemblies(typeInfo); - } - catch (Exception ex) - { - if (ex is TypeLoadException) - { - throw; - } - throw BuildTypeLoadException(typeName, ex); - } - if (type == null) - { - throw BuildTypeLoadException(typeName); - } - return type; + throw BuildTypeLoadException(typeName); } - /// - /// Uses - /// to load an and then the attendant - /// referred to by the - /// parameter. - /// - /// - ///

- /// is - /// deprecated in .NET 2.0, but is still used here (even when this class is - /// compiled for .NET 2.0); - /// will - /// still resolve (non-.NET Framework) local assemblies when given only the - /// display name of an assembly (the behaviour for .NET Framework assemblies - /// and strongly named assemblies is documented in the docs for the - /// method). - ///

- ///
- /// - /// The assembly and type to be loaded. - /// - /// - /// A , or . - /// - /// - /// - /// - private static Type LoadTypeDirectlyFromAssembly(TypeAssemblyHolder typeInfo) + TypeAssemblyHolder typeInfo = new TypeAssemblyHolder(typeName); + Type type = null; + try { - Type type = null; + type = (typeInfo.IsAssemblyQualified) ? LoadTypeDirectlyFromAssembly(typeInfo) : LoadTypeByIteratingOverAllLoadedAssemblies(typeInfo); + } + catch (Exception ex) + { + if (ex is TypeLoadException) + { + throw; + } + + throw BuildTypeLoadException(typeName, ex); + } + + if (type == null) + { + throw BuildTypeLoadException(typeName); + } + + return type; + } + + /// + /// Uses + /// to load an and then the attendant + /// referred to by the + /// parameter. + /// + /// + ///

+ /// is + /// deprecated in .NET 2.0, but is still used here (even when this class is + /// compiled for .NET 2.0); + /// will + /// still resolve (non-.NET Framework) local assemblies when given only the + /// display name of an assembly (the behaviour for .NET Framework assemblies + /// and strongly named assemblies is documented in the docs for the + /// method). + ///

+ ///
+ /// + /// The assembly and type to be loaded. + /// + /// + /// A , or . + /// + /// + /// + /// + private static Type LoadTypeDirectlyFromAssembly(TypeAssemblyHolder typeInfo) + { + Type type = null; #if MONO_2_0 Assembly assembly = Assembly.Load(typeInfo.AssemblyName); #else - Assembly assembly = Assembly.LoadWithPartialName(typeInfo.AssemblyName); + Assembly assembly = Assembly.LoadWithPartialName(typeInfo.AssemblyName); #endif - if (assembly != null) + if (assembly != null) + { + type = assembly.GetType(typeInfo.TypeName, true, true); + } + + return type; + } + + /// + /// Uses + /// to load the attendant referred to by + /// the parameter. + /// + /// + /// The type to be loaded. + /// + /// + /// A , or . + /// + private static Type LoadTypeByIteratingOverAllLoadedAssemblies(TypeAssemblyHolder typeInfo) + { + Type type = null; + Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); + foreach (Assembly assembly in assemblies) + { + type = assembly.GetType(typeInfo.TypeName, false, false); + if (type != null) { - type = assembly.GetType(typeInfo.TypeName, true, true); + break; } - return type; } - /// - /// Uses - /// to load the attendant referred to by - /// the parameter. - /// - /// - /// The type to be loaded. - /// - /// - /// A , or . - /// - private static Type LoadTypeByIteratingOverAllLoadedAssemblies(TypeAssemblyHolder typeInfo) - { - Type type = null; - Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); - foreach (Assembly assembly in assemblies) - { - type = assembly.GetType(typeInfo.TypeName, false, false); - if (type != null) - { - break; - } - } - return type; - } + return type; + } - /// - /// Creates a new instance - /// from the given - /// - protected static TypeLoadException BuildTypeLoadException(string typeName) - { - return new TypeLoadException("Could not load type from string value '" + typeName + "'."); - } + /// + /// Creates a new instance + /// from the given + /// + protected static TypeLoadException BuildTypeLoadException(string typeName) + { + return new TypeLoadException("Could not load type from string value '" + typeName + "'."); + } - /// - /// Creates a new instance - /// from the given with the given inner - /// - protected static TypeLoadException BuildTypeLoadException(string typeName, Exception ex) - { - return new TypeLoadException("Could not load type from string value '" + typeName + "'.", ex); - } + /// + /// Creates a new instance + /// from the given with the given inner + /// + protected static TypeLoadException BuildTypeLoadException(string typeName, Exception ex) + { + return new TypeLoadException("Could not load type from string value '" + typeName + "'.", ex); } } diff --git a/src/Spring/Spring.Core/DataBinding/AbstractBinding.cs b/src/Spring/Spring.Core/DataBinding/AbstractBinding.cs index 278d1a52..8269b2d7 100644 --- a/src/Spring/Spring.Core/DataBinding/AbstractBinding.cs +++ b/src/Spring/Spring.Core/DataBinding/AbstractBinding.cs @@ -2,233 +2,234 @@ using Spring.Collections; using Spring.Util; using Spring.Validation; -namespace Spring.DataBinding +namespace Spring.DataBinding; + +/// +/// Abstract base class for implementations. +/// +/// Aleksandar Seovic +public abstract class AbstractBinding : IBinding { + #region Fields + /// - /// Abstract base class for implementations. + /// The name of the always filled error provider /// - /// Aleksandar Seovic - public abstract class AbstractBinding : IBinding + public static readonly string ALL_BINDINGERRORS_PROVIDER = "__all_bindingerrors"; + + // each Binding instance needs its own ID + private readonly string BINDING_ID = Guid.NewGuid().ToString("N"); + + private BindingDirection direction = BindingDirection.Bidirectional; + private BindingErrorMessage errorMessage; + private string[] errorProviders; + + #endregion + + #region Properties + + /// + /// Gets or sets a flag specifying whether this binding is valid. + /// + /// + /// true if this binding evaluated without errors; + /// false otherwise. + /// + public bool IsValid(IValidationErrors errors) { - #region Fields + if (errors == null) return true; - /// - /// The name of the always filled error provider - /// - public static readonly string ALL_BINDINGERRORS_PROVIDER = "__all_bindingerrors"; + IList errorList = errors.GetErrors(ALL_BINDINGERRORS_PROVIDER); + return (errorList == null) || (!errorList.Contains(this.ErrorMessage)); + } - // each Binding instance needs its own ID - private readonly string BINDING_ID = Guid.NewGuid().ToString("N"); - - private BindingDirection direction = BindingDirection.Bidirectional; - private BindingErrorMessage errorMessage; - private string[] errorProviders; - - #endregion - - #region Properties - - /// - /// Gets or sets a flag specifying whether this binding is valid. - /// - /// - /// true if this binding evaluated without errors; - /// false otherwise. - /// - public bool IsValid(IValidationErrors errors) + /// + /// Marks this binding's state as invalid for this validationErrors collection. + /// Returns false if is null. + /// + /// + /// false, if validationErrors is null + protected bool SetInvalid(IValidationErrors validationErrors) + { + if (validationErrors != null) { - if (errors == null) return true; - - IList errorList = errors.GetErrors(ALL_BINDINGERRORS_PROVIDER); - return (errorList == null) || (!errorList.Contains(this.ErrorMessage)); - } - - /// - /// Marks this binding's state as invalid for this validationErrors collection. - /// Returns false if is null. - /// - /// - /// false, if validationErrors is null - protected bool SetInvalid(IValidationErrors validationErrors) - { - if (validationErrors != null) + foreach (string provider in this.ErrorProviders) { - foreach (string provider in this.ErrorProviders) - { - validationErrors.AddError(provider, this.ErrorMessage); - } - return true; - } - return false; - } - - /// - /// Gets the unique ID of this binding instance. - /// - public string Id - { - get { return BINDING_ID; } - } - - /// - /// Gets or sets the . - /// - /// The binding direction. - public BindingDirection Direction - { - get { return direction; } - set { direction = value; } - } - - /// - /// Gets the error message. - /// - /// The error message. - public BindingErrorMessage ErrorMessage - { - get { return errorMessage; } - } - - /// - /// Gets the error providers. - /// - public string[] ErrorProviders - { - get { return errorProviders; } - } - - #endregion - - /// - /// Initializes a new instance of the class. - /// - protected AbstractBinding() - { - this.errorMessage = new BindingErrorMessage( this.Id, "Binding-Error"); - this.errorProviders = new string[] { ALL_BINDINGERRORS_PROVIDER }; - } - - #region IBinding Implementation - - /// - /// Binds source object to target object. - /// - /// - /// The source object. - /// - /// - /// The target object. - /// - /// - /// Validation errors collection that type conversion errors should be added to. - /// - public virtual void BindSourceToTarget(object source, object target, IValidationErrors validationErrors) - { - BindSourceToTarget(source, target, validationErrors, null); - } - - /// - /// Binds target object to source object. - /// - /// - /// The source object. - /// - /// - /// The target object. - /// - /// - /// Validation errors collection that type conversion errors should be added to. - /// - public virtual void BindTargetToSource(object source, object target, IValidationErrors validationErrors) - { - BindTargetToSource(source, target, validationErrors, null); - } - - /// - /// Binds source object to target object. - /// - /// - /// The source object. - /// - /// - /// The target object. - /// - /// - /// Validation errors collection that type conversion errors should be added to. - /// - /// - /// Variables that should be used during expression evaluation. - /// - public abstract void BindSourceToTarget(object source, object target, IValidationErrors validationErrors, IDictionary variables); - - /// - /// Binds target object to source object. - /// - /// - /// The source object. - /// - /// - /// The target object. - /// - /// - /// Validation errors collection that type conversion errors should be added to. - /// - /// - /// Variables that should be used during expression evaluation. - /// - public abstract void BindTargetToSource(object source, object target, IValidationErrors validationErrors, IDictionary variables); - - /// - /// Sets error message that should be displayed in the case - /// of a non-fatal binding error. - /// - /// - /// Resource ID of the error message. - /// - /// - /// List of error providers message should be added to. - /// - public void SetErrorMessage(string messageId, params string[] errorProviders) - { - AssertUtils.ArgumentHasText(messageId, "messageId"); - if (errorProviders == null || errorProviders.Length == 0) - { - throw new ArgumentException("At least one error provider has to be specified.", "providers"); + validationErrors.AddError(provider, this.ErrorMessage); } - this.errorMessage = new BindingErrorMessage(this.BINDING_ID, messageId, null); - Set providers = new HashedSet(); - providers.Add(ALL_BINDINGERRORS_PROVIDER); - providers.AddAll(errorProviders); - errorProviders = new string[providers.Count]; - providers.CopyTo(errorProviders, 0); - this.errorProviders = errorProviders; + return true; } - #endregion + return false; + } - /// - ///Determines whether the specified is equal to the current . - /// - /// - ///true if the specified is equal to the current ; otherwise, false. - /// - ///The to compare with the current . 2 - public override bool Equals(object obj) + /// + /// Gets the unique ID of this binding instance. + /// + public string Id + { + get { return BINDING_ID; } + } + + /// + /// Gets or sets the . + /// + /// The binding direction. + public BindingDirection Direction + { + get { return direction; } + set { direction = value; } + } + + /// + /// Gets the error message. + /// + /// The error message. + public BindingErrorMessage ErrorMessage + { + get { return errorMessage; } + } + + /// + /// Gets the error providers. + /// + public string[] ErrorProviders + { + get { return errorProviders; } + } + + #endregion + + /// + /// Initializes a new instance of the class. + /// + protected AbstractBinding() + { + this.errorMessage = new BindingErrorMessage(this.Id, "Binding-Error"); + this.errorProviders = new string[] { ALL_BINDINGERRORS_PROVIDER }; + } + + #region IBinding Implementation + + /// + /// Binds source object to target object. + /// + /// + /// The source object. + /// + /// + /// The target object. + /// + /// + /// Validation errors collection that type conversion errors should be added to. + /// + public virtual void BindSourceToTarget(object source, object target, IValidationErrors validationErrors) + { + BindSourceToTarget(source, target, validationErrors, null); + } + + /// + /// Binds target object to source object. + /// + /// + /// The source object. + /// + /// + /// The target object. + /// + /// + /// Validation errors collection that type conversion errors should be added to. + /// + public virtual void BindTargetToSource(object source, object target, IValidationErrors validationErrors) + { + BindTargetToSource(source, target, validationErrors, null); + } + + /// + /// Binds source object to target object. + /// + /// + /// The source object. + /// + /// + /// The target object. + /// + /// + /// Validation errors collection that type conversion errors should be added to. + /// + /// + /// Variables that should be used during expression evaluation. + /// + public abstract void BindSourceToTarget(object source, object target, IValidationErrors validationErrors, IDictionary variables); + + /// + /// Binds target object to source object. + /// + /// + /// The source object. + /// + /// + /// The target object. + /// + /// + /// Validation errors collection that type conversion errors should be added to. + /// + /// + /// Variables that should be used during expression evaluation. + /// + public abstract void BindTargetToSource(object source, object target, IValidationErrors validationErrors, IDictionary variables); + + /// + /// Sets error message that should be displayed in the case + /// of a non-fatal binding error. + /// + /// + /// Resource ID of the error message. + /// + /// + /// List of error providers message should be added to. + /// + public void SetErrorMessage(string messageId, params string[] errorProviders) + { + AssertUtils.ArgumentHasText(messageId, "messageId"); + if (errorProviders == null || errorProviders.Length == 0) { - AbstractBinding other = obj as AbstractBinding; - return (other != null) && (this.Id == other.Id); + throw new ArgumentException("At least one error provider has to be specified.", "providers"); } - /// - ///Serves as a hash function for a particular type. is suitable for use in hashing algorithms and data structures like a hash table. - /// - /// - ///A hash code for the current . - /// - public override int GetHashCode() - { - return this.Id.GetHashCode(); - } + this.errorMessage = new BindingErrorMessage(this.BINDING_ID, messageId, null); + Set providers = new HashedSet(); + providers.Add(ALL_BINDINGERRORS_PROVIDER); + providers.AddAll(errorProviders); + errorProviders = new string[providers.Count]; + providers.CopyTo(errorProviders, 0); + this.errorProviders = errorProviders; + } + + #endregion + + /// + ///Determines whether the specified is equal to the current . + /// + /// + ///true if the specified is equal to the current ; otherwise, false. + /// + ///The to compare with the current . 2 + public override bool Equals(object obj) + { + AbstractBinding other = obj as AbstractBinding; + return (other != null) && (this.Id == other.Id); + } + + /// + ///Serves as a hash function for a particular type. is suitable for use in hashing algorithms and data structures like a hash table. + /// + /// + ///A hash code for the current . + /// + public override int GetHashCode() + { + return this.Id.GetHashCode(); } } diff --git a/src/Spring/Spring.Core/DataBinding/AbstractSimpleBinding.cs b/src/Spring/Spring.Core/DataBinding/AbstractSimpleBinding.cs index fd85c2df..7e2f088e 100644 --- a/src/Spring/Spring.Core/DataBinding/AbstractSimpleBinding.cs +++ b/src/Spring/Spring.Core/DataBinding/AbstractSimpleBinding.cs @@ -3,224 +3,225 @@ using Microsoft.Extensions.Logging; using Spring.Globalization; using Spring.Validation; -namespace Spring.DataBinding +namespace Spring.DataBinding; + +/// +/// Abstract base class for simple, one-to-one implementations. +/// +/// Aleksandar Seovic +public abstract class AbstractSimpleBinding : AbstractBinding { + #region Fields + + private readonly ILogger log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private IFormatter formatter; + + #endregion + + #region Constructor(s) + /// - /// Abstract base class for simple, one-to-one implementations. + /// Initialize a new instance of without any /// - /// Aleksandar Seovic - public abstract class AbstractSimpleBinding : AbstractBinding + protected AbstractSimpleBinding() { - #region Fields - - private readonly ILogger log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - private IFormatter formatter; - - #endregion - - #region Constructor(s) - - /// - /// Initialize a new instance of without any - /// - protected AbstractSimpleBinding() - { - } - - /// - /// Initialize a new instance of with the - /// specified . - /// - protected AbstractSimpleBinding(IFormatter formatter) - { - this.formatter = formatter; - } - - #endregion - - #region Properties - - /// - /// Gets or sets the to use. - /// - /// The formatter to use. - public IFormatter Formatter - { - get { return formatter; } - set { formatter = value; } - } - - #endregion - - #region IBinding Implementation - - /// - /// Binds source object to target object. - /// - /// - /// The source object. - /// - /// - /// The target object. - /// - /// - /// Validation errors collection that type conversion errors should be added to. - /// - /// - /// Variables that should be used during expression evaluation. - /// - public override void BindSourceToTarget(object source, object target, IValidationErrors validationErrors, IDictionary variables) - { - if (this.IsValid(validationErrors) - && (this.Direction == BindingDirection.Bidirectional || this.Direction == BindingDirection.SourceToTarget)) - { - try - { - DoBindSourceToTarget(source, target, variables); - } - catch (Exception) - { - if (!SetInvalid(validationErrors)) throw; - } - } - } - - /// - /// Concrete implementation if source to target binding. - /// - /// - /// The source object. - /// - /// - /// The target object. - /// - /// - /// Variables that should be used during expression evaluation. - /// - protected virtual void DoBindSourceToTarget(object source, object target, IDictionary variables) - { - object value = this.GetSourceValue(source, variables); - if (this.Formatter != null && value is string) - { - value = this.Formatter.Parse((string)value); - } - this.SetTargetValue(target, value, variables); - } - - /// - /// Binds target object to source object. - /// - /// - /// The source object. - /// - /// - /// The target object. - /// - /// - /// Validation errors collection that type conversion errors should be added to. - /// - /// - /// Variables that should be used during expression evaluation. - /// - public override void BindTargetToSource(object source, object target, IValidationErrors validationErrors, IDictionary variables) - { - if (this.IsValid(validationErrors) - && (this.Direction == BindingDirection.Bidirectional || this.Direction == BindingDirection.TargetToSource)) - { - try - { - DoBindTargetToSource(source, target, variables); - } - catch (Exception ex) - { - log.LogWarning(string.Format("Failed binding[{0}]:{1}", this.Id, ex)); - if (!SetInvalid(validationErrors)) throw; - } - } - } - - /// - /// Concrete implementation of target to source binding. - /// - /// - /// The source object. - /// - /// - /// The target object. - /// - /// - /// Variables that should be used during expression evaluation. - /// - protected virtual void DoBindTargetToSource(object source, object target, IDictionary variables) - { - object value = this.GetTargetValue(target, variables); - if (this.Formatter != null) - { - value = this.Formatter.Format(value); - } - this.SetSourceValue(source, value, variables); - } - - #endregion - - #region Abstract Methods - - /// - /// Gets the source value for the binding. - /// - /// - /// Source object to extract value from. - /// - /// - /// Variables for expression evaluation. - /// - /// - /// The source value for the binding. - /// - protected abstract object GetSourceValue(object source, IDictionary variables); - - /// - /// Sets the source value for the binding. - /// - /// - /// The source object to set the value on. - /// - /// - /// The value to set. - /// - /// - /// Variables for expression evaluation. - /// - protected abstract void SetSourceValue(object source, object value, IDictionary variables); - - /// - /// Gets the target value for the binding. - /// - /// - /// Source object to extract value from. - /// - /// - /// Variables for expression evaluation. - /// - /// - /// The target value for the binding. - /// - protected abstract object GetTargetValue(object target, IDictionary variables); - - /// - /// Sets the target value for the binding. - /// - /// - /// The target object to set the value on. - /// - /// - /// The value to set. - /// - /// - /// Variables for expression evaluation. - /// - protected abstract void SetTargetValue(object target, object value, IDictionary variables); - - #endregion } + + /// + /// Initialize a new instance of with the + /// specified . + /// + protected AbstractSimpleBinding(IFormatter formatter) + { + this.formatter = formatter; + } + + #endregion + + #region Properties + + /// + /// Gets or sets the to use. + /// + /// The formatter to use. + public IFormatter Formatter + { + get { return formatter; } + set { formatter = value; } + } + + #endregion + + #region IBinding Implementation + + /// + /// Binds source object to target object. + /// + /// + /// The source object. + /// + /// + /// The target object. + /// + /// + /// Validation errors collection that type conversion errors should be added to. + /// + /// + /// Variables that should be used during expression evaluation. + /// + public override void BindSourceToTarget(object source, object target, IValidationErrors validationErrors, IDictionary variables) + { + if (this.IsValid(validationErrors) + && (this.Direction == BindingDirection.Bidirectional || this.Direction == BindingDirection.SourceToTarget)) + { + try + { + DoBindSourceToTarget(source, target, variables); + } + catch (Exception) + { + if (!SetInvalid(validationErrors)) throw; + } + } + } + + /// + /// Concrete implementation if source to target binding. + /// + /// + /// The source object. + /// + /// + /// The target object. + /// + /// + /// Variables that should be used during expression evaluation. + /// + protected virtual void DoBindSourceToTarget(object source, object target, IDictionary variables) + { + object value = this.GetSourceValue(source, variables); + if (this.Formatter != null && value is string) + { + value = this.Formatter.Parse((string) value); + } + + this.SetTargetValue(target, value, variables); + } + + /// + /// Binds target object to source object. + /// + /// + /// The source object. + /// + /// + /// The target object. + /// + /// + /// Validation errors collection that type conversion errors should be added to. + /// + /// + /// Variables that should be used during expression evaluation. + /// + public override void BindTargetToSource(object source, object target, IValidationErrors validationErrors, IDictionary variables) + { + if (this.IsValid(validationErrors) + && (this.Direction == BindingDirection.Bidirectional || this.Direction == BindingDirection.TargetToSource)) + { + try + { + DoBindTargetToSource(source, target, variables); + } + catch (Exception ex) + { + log.LogWarning(string.Format("Failed binding[{0}]:{1}", this.Id, ex)); + if (!SetInvalid(validationErrors)) throw; + } + } + } + + /// + /// Concrete implementation of target to source binding. + /// + /// + /// The source object. + /// + /// + /// The target object. + /// + /// + /// Variables that should be used during expression evaluation. + /// + protected virtual void DoBindTargetToSource(object source, object target, IDictionary variables) + { + object value = this.GetTargetValue(target, variables); + if (this.Formatter != null) + { + value = this.Formatter.Format(value); + } + + this.SetSourceValue(source, value, variables); + } + + #endregion + + #region Abstract Methods + + /// + /// Gets the source value for the binding. + /// + /// + /// Source object to extract value from. + /// + /// + /// Variables for expression evaluation. + /// + /// + /// The source value for the binding. + /// + protected abstract object GetSourceValue(object source, IDictionary variables); + + /// + /// Sets the source value for the binding. + /// + /// + /// The source object to set the value on. + /// + /// + /// The value to set. + /// + /// + /// Variables for expression evaluation. + /// + protected abstract void SetSourceValue(object source, object value, IDictionary variables); + + /// + /// Gets the target value for the binding. + /// + /// + /// Source object to extract value from. + /// + /// + /// Variables for expression evaluation. + /// + /// + /// The target value for the binding. + /// + protected abstract object GetTargetValue(object target, IDictionary variables); + + /// + /// Sets the target value for the binding. + /// + /// + /// The target object to set the value on. + /// + /// + /// The value to set. + /// + /// + /// Variables for expression evaluation. + /// + protected abstract void SetTargetValue(object target, object value, IDictionary variables); + + #endregion } diff --git a/src/Spring/Spring.Core/DataBinding/BaseBindingContainer.cs b/src/Spring/Spring.Core/DataBinding/BaseBindingContainer.cs index 0b8b318e..ff564873 100644 --- a/src/Spring/Spring.Core/DataBinding/BaseBindingContainer.cs +++ b/src/Spring/Spring.Core/DataBinding/BaseBindingContainer.cs @@ -1,258 +1,259 @@ using Spring.Globalization; using Spring.Validation; -namespace Spring.DataBinding +namespace Spring.DataBinding; + +/// +/// Base implementation of the . +/// +/// Aleksandar Seovic +public class BaseBindingContainer : IBindingContainer { + #region Fields + + private IList bindings = new List(); + + #endregion + + #region Constructor(s) + /// - /// Base implementation of the . + /// Creates a new instance of . /// - /// Aleksandar Seovic - public class BaseBindingContainer : IBindingContainer + public BaseBindingContainer() { - #region Fields - - private IList bindings = new List(); - - #endregion - - #region Constructor(s) - - /// - /// Creates a new instance of . - /// - public BaseBindingContainer() - { } - - #endregion - - #region Properties - - /// - /// Gets a list of bindings for this container. - /// - /// - /// A list of bindings for this container. - /// - protected IList Bindings - { - get { return bindings; } - } - - #endregion - - #region IBindingContainer Implementation - - /// - /// Gets a value indicating whether this instance has bindings. - /// - /// - /// true if this instance has bindings; otherwise, false. - /// - public bool HasBindings - { - get { return bindings.Count > 0; } - } - - /// - /// Adds the binding. - /// - /// - /// Binding definition to add. - /// - /// - /// Added instance. - /// - public IBinding AddBinding(IBinding binding) - { - bindings.Add(binding); - return binding; - } - - /// - /// Adds the binding with a default - /// binding direction of . - /// - /// - /// The source expression. - /// - /// - /// The target expression. - /// - /// - /// Added instance. - /// - public IBinding AddBinding(string sourceExpression, string targetExpression) - { - return AddBinding(sourceExpression, targetExpression, BindingDirection.Bidirectional, null); - } - - /// - /// Adds the binding. - /// - /// - /// The source expression. - /// - /// - /// The target expression. - /// - /// - /// Binding direction. - /// - /// - /// Added instance. - /// - public IBinding AddBinding(string sourceExpression, string targetExpression, BindingDirection direction) - { - return AddBinding(sourceExpression, targetExpression, direction, null); - } - - /// - /// Adds the binding with a default - /// binding direction of . - /// - /// - /// The source expression. - /// - /// - /// The target expression. - /// - /// - /// to use for value formatting and parsing. - /// - /// - /// Added instance. - /// - public IBinding AddBinding(string sourceExpression, string targetExpression, IFormatter formatter) - { - return AddBinding(sourceExpression, targetExpression, BindingDirection.Bidirectional, formatter); - } - - /// - /// Adds the binding. - /// - /// - /// The source expression. - /// - /// - /// The target expression. - /// - /// - /// Binding direction. - /// - /// - /// to use for value formatting and parsing. - /// - /// - /// Added instance. - /// - public virtual IBinding AddBinding(string sourceExpression, string targetExpression, - BindingDirection direction, IFormatter formatter) - { - SimpleExpressionBinding binding = new SimpleExpressionBinding(sourceExpression, targetExpression); - binding.Direction = direction; - binding.Formatter = formatter; - bindings.Add(binding); - - return binding; - } - - #endregion - - #region IBinding Implementation - - /// - /// Binds source object to target object. - /// - /// - /// The source object. - /// - /// - /// The target object. - /// - /// - /// Validation errors collection that type conversion errors should be added to. - /// - public virtual void BindSourceToTarget(object source, object target, IValidationErrors validationErrors) - { - BindSourceToTarget(source, target, validationErrors, null); - } - - /// - /// Binds source object to target object. - /// - /// - /// The source object. - /// - /// - /// The target object. - /// - /// - /// Validation errors collection that type conversion errors should be added to. - /// - /// - /// Variables that should be used during expression evaluation. - /// - public virtual void BindSourceToTarget(object source, object target, IValidationErrors validationErrors, IDictionary variables) - { - foreach (IBinding binding in bindings) - { - binding.BindSourceToTarget(source, target, validationErrors, variables); - } - } - - /// - /// Binds target object to source object. - /// - /// - /// The source object. - /// - /// - /// The target object. - /// - /// - /// Validation errors collection that type conversion errors should be added to. - /// - public virtual void BindTargetToSource(object source, object target, IValidationErrors validationErrors) - { - BindTargetToSource(source, target, validationErrors, null); - } - - /// - /// Binds target object to source object. - /// - /// - /// The source object. - /// - /// - /// The target object. - /// - /// - /// Validation errors collection that type conversion errors should be added to. - /// - /// - /// Variables that should be used during expression evaluation. - /// - public virtual void BindTargetToSource(object source, object target, IValidationErrors validationErrors, IDictionary variables) - { - foreach (IBinding binding in bindings) - { - binding.BindTargetToSource(source, target, validationErrors, variables); - } - } - - /// - /// Implemented as a NOOP for containers. - /// of a non-fatal binding error. - /// - /// - /// Resource ID of the error message. - /// - /// - /// List of error providers message should be added to. - /// - public virtual void SetErrorMessage(string messageId, params string[] errorProviders) - { } - - #endregion } + + #endregion + + #region Properties + + /// + /// Gets a list of bindings for this container. + /// + /// + /// A list of bindings for this container. + /// + protected IList Bindings + { + get { return bindings; } + } + + #endregion + + #region IBindingContainer Implementation + + /// + /// Gets a value indicating whether this instance has bindings. + /// + /// + /// true if this instance has bindings; otherwise, false. + /// + public bool HasBindings + { + get { return bindings.Count > 0; } + } + + /// + /// Adds the binding. + /// + /// + /// Binding definition to add. + /// + /// + /// Added instance. + /// + public IBinding AddBinding(IBinding binding) + { + bindings.Add(binding); + return binding; + } + + /// + /// Adds the binding with a default + /// binding direction of . + /// + /// + /// The source expression. + /// + /// + /// The target expression. + /// + /// + /// Added instance. + /// + public IBinding AddBinding(string sourceExpression, string targetExpression) + { + return AddBinding(sourceExpression, targetExpression, BindingDirection.Bidirectional, null); + } + + /// + /// Adds the binding. + /// + /// + /// The source expression. + /// + /// + /// The target expression. + /// + /// + /// Binding direction. + /// + /// + /// Added instance. + /// + public IBinding AddBinding(string sourceExpression, string targetExpression, BindingDirection direction) + { + return AddBinding(sourceExpression, targetExpression, direction, null); + } + + /// + /// Adds the binding with a default + /// binding direction of . + /// + /// + /// The source expression. + /// + /// + /// The target expression. + /// + /// + /// to use for value formatting and parsing. + /// + /// + /// Added instance. + /// + public IBinding AddBinding(string sourceExpression, string targetExpression, IFormatter formatter) + { + return AddBinding(sourceExpression, targetExpression, BindingDirection.Bidirectional, formatter); + } + + /// + /// Adds the binding. + /// + /// + /// The source expression. + /// + /// + /// The target expression. + /// + /// + /// Binding direction. + /// + /// + /// to use for value formatting and parsing. + /// + /// + /// Added instance. + /// + public virtual IBinding AddBinding(string sourceExpression, string targetExpression, + BindingDirection direction, IFormatter formatter) + { + SimpleExpressionBinding binding = new SimpleExpressionBinding(sourceExpression, targetExpression); + binding.Direction = direction; + binding.Formatter = formatter; + bindings.Add(binding); + + return binding; + } + + #endregion + + #region IBinding Implementation + + /// + /// Binds source object to target object. + /// + /// + /// The source object. + /// + /// + /// The target object. + /// + /// + /// Validation errors collection that type conversion errors should be added to. + /// + public virtual void BindSourceToTarget(object source, object target, IValidationErrors validationErrors) + { + BindSourceToTarget(source, target, validationErrors, null); + } + + /// + /// Binds source object to target object. + /// + /// + /// The source object. + /// + /// + /// The target object. + /// + /// + /// Validation errors collection that type conversion errors should be added to. + /// + /// + /// Variables that should be used during expression evaluation. + /// + public virtual void BindSourceToTarget(object source, object target, IValidationErrors validationErrors, IDictionary variables) + { + foreach (IBinding binding in bindings) + { + binding.BindSourceToTarget(source, target, validationErrors, variables); + } + } + + /// + /// Binds target object to source object. + /// + /// + /// The source object. + /// + /// + /// The target object. + /// + /// + /// Validation errors collection that type conversion errors should be added to. + /// + public virtual void BindTargetToSource(object source, object target, IValidationErrors validationErrors) + { + BindTargetToSource(source, target, validationErrors, null); + } + + /// + /// Binds target object to source object. + /// + /// + /// The source object. + /// + /// + /// The target object. + /// + /// + /// Validation errors collection that type conversion errors should be added to. + /// + /// + /// Variables that should be used during expression evaluation. + /// + public virtual void BindTargetToSource(object source, object target, IValidationErrors validationErrors, IDictionary variables) + { + foreach (IBinding binding in bindings) + { + binding.BindTargetToSource(source, target, validationErrors, variables); + } + } + + /// + /// Implemented as a NOOP for containers. + /// of a non-fatal binding error. + /// + /// + /// Resource ID of the error message. + /// + /// + /// List of error providers message should be added to. + /// + public virtual void SetErrorMessage(string messageId, params string[] errorProviders) + { + } + + #endregion } diff --git a/src/Spring/Spring.Core/DataBinding/BaseBindingManager.cs b/src/Spring/Spring.Core/DataBinding/BaseBindingManager.cs index 146f54b1..e558d44a 100644 --- a/src/Spring/Spring.Core/DataBinding/BaseBindingManager.cs +++ b/src/Spring/Spring.Core/DataBinding/BaseBindingManager.cs @@ -18,23 +18,23 @@ #endregion -namespace Spring.DataBinding +namespace Spring.DataBinding; + +/// +/// BaseBindingManager keeps track of all registered bindings and +/// represents an entry point for the binding and unbinding process. +/// +/// Aleksandar Seovic +public class BaseBindingManager : BaseBindingContainer { + #region Constructor(s) + /// - /// BaseBindingManager keeps track of all registered bindings and - /// represents an entry point for the binding and unbinding process. + /// Initializes a new instance of the class. /// - /// Aleksandar Seovic - public class BaseBindingManager : BaseBindingContainer + public BaseBindingManager() { - #region Constructor(s) - - /// - /// Initializes a new instance of the class. - /// - public BaseBindingManager() - {} - - #endregion } -} \ No newline at end of file + + #endregion +} diff --git a/src/Spring/Spring.Core/DataBinding/BindingDirection.cs b/src/Spring/Spring.Core/DataBinding/BindingDirection.cs index 306fd198..cc6b1542 100644 --- a/src/Spring/Spring.Core/DataBinding/BindingDirection.cs +++ b/src/Spring/Spring.Core/DataBinding/BindingDirection.cs @@ -18,28 +18,27 @@ #endregion -namespace Spring.DataBinding +namespace Spring.DataBinding; + +/// +/// Enumeration that defines possible values for data binding direction. +/// +/// Aleksandar Seovic +[Flags] +public enum BindingDirection { - /// - /// Enumeration that defines possible values for data binding direction. - /// - /// Aleksandar Seovic - [Flags] - public enum BindingDirection - { - /// - /// Specifies that value from the control property should be bound to a data model. - /// - SourceToTarget = 0x0001, + /// + /// Specifies that value from the control property should be bound to a data model. + /// + SourceToTarget = 0x0001, - /// - /// Specifies that value from the data model should be bound to control property. - /// - TargetToSource = 0x0002, + /// + /// Specifies that value from the data model should be bound to control property. + /// + TargetToSource = 0x0002, - /// - /// Specifies that binding is bidirectional. - /// - Bidirectional = SourceToTarget | TargetToSource - } + /// + /// Specifies that binding is bidirectional. + /// + Bidirectional = SourceToTarget | TargetToSource } diff --git a/src/Spring/Spring.Core/DataBinding/BindingErrorMessage.cs b/src/Spring/Spring.Core/DataBinding/BindingErrorMessage.cs index 5728789b..a8ee7f52 100644 --- a/src/Spring/Spring.Core/DataBinding/BindingErrorMessage.cs +++ b/src/Spring/Spring.Core/DataBinding/BindingErrorMessage.cs @@ -21,87 +21,86 @@ using Spring.Util; using Spring.Validation; -namespace Spring.DataBinding +namespace Spring.DataBinding; + +/// +/// Represents an ErrorMessage specific to a binding instance. +/// +/// Erich Eichinger +[Serializable] +public class BindingErrorMessage : ErrorMessage { + private string _bindingId; + /// - /// Represents an ErrorMessage specific to a binding instance. + /// Initializes a new instance of the class. /// - /// Erich Eichinger - [Serializable] - public class BindingErrorMessage : ErrorMessage + /// the id of the binding this error message is associated with + /// the message id + /// optional parameters to this message + public BindingErrorMessage(string bindingId, string id, params object[] parameters) : base(id, parameters) { - private string _bindingId; + AssertUtils.ArgumentNotNull(bindingId, "bindingId"); + _bindingId = bindingId; + } - /// - /// Initializes a new instance of the class. - /// - /// the id of the binding this error message is associated with - /// the message id - /// optional parameters to this message - public BindingErrorMessage(string bindingId, string id, params object[] parameters) : base(id, parameters) - { - AssertUtils.ArgumentNotNull(bindingId, "bindingId"); - _bindingId = bindingId; - } + /// + /// Get the ID of the binding this message instance relates to. + /// + public string BindingId + { + get { return _bindingId; } + } - /// - /// Get the ID of the binding this message instance relates to. - /// - public string BindingId - { - get { return _bindingId; } - } + /// + /// Generates an object from its XML representation. + /// + /// + /// The stream + /// from which the object is deserialized. + /// + public override void ReadXml(System.Xml.XmlReader reader) + { + base.ReadXml(reader); + _bindingId = reader.GetAttribute("bindingId"); + } - /// - /// Generates an object from its XML representation. - /// - /// - /// The stream - /// from which the object is deserialized. - /// - public override void ReadXml(System.Xml.XmlReader reader) - { - base.ReadXml(reader); - _bindingId = reader.GetAttribute("bindingId"); - } + /// + /// Converts an object into its XML representation. + /// + /// + /// The stream + /// to which the object is serialized. + /// + public override void WriteXml(System.Xml.XmlWriter writer) + { + base.WriteXml(writer); + writer.WriteAttributeString("bindingId", _bindingId); + } - /// - /// Converts an object into its XML representation. - /// - /// - /// The stream - /// to which the object is serialized. - /// - public override void WriteXml(System.Xml.XmlWriter writer) - { - base.WriteXml(writer); - writer.WriteAttributeString("bindingId", _bindingId); - } + /// + ///Determines whether the specified is equal to the current . + /// + /// + ///true if the specified is equal to the current ; otherwise, false. + /// + ///The to compare with the current . 2 + public override bool Equals(object obj) + { + BindingErrorMessage other = obj as BindingErrorMessage; + return (other != null) + && (this.BindingId == other.BindingId) + && (base.Equals(obj)); + } - /// - ///Determines whether the specified is equal to the current . - /// - /// - ///true if the specified is equal to the current ; otherwise, false. - /// - ///The to compare with the current . 2 - public override bool Equals(object obj) - { - BindingErrorMessage other = obj as BindingErrorMessage; - return (other != null) - && (this.BindingId == other.BindingId) - && (base.Equals(obj)); - } - - /// - ///Serves as a hash function for a particular type. is suitable for use in hashing algorithms and data structures like a hash table. - /// - /// - ///A hash code for the current . - /// - public override int GetHashCode() - { - return base.GetHashCode() + 31*this.BindingId.GetHashCode(); - } + /// + ///Serves as a hash function for a particular type. is suitable for use in hashing algorithms and data structures like a hash table. + /// + /// + ///A hash code for the current . + /// + public override int GetHashCode() + { + return base.GetHashCode() + 31 * this.BindingId.GetHashCode(); } } diff --git a/src/Spring/Spring.Core/DataBinding/IBinding.cs b/src/Spring/Spring.Core/DataBinding/IBinding.cs index f6aeb63a..ba582810 100644 --- a/src/Spring/Spring.Core/DataBinding/IBinding.cs +++ b/src/Spring/Spring.Core/DataBinding/IBinding.cs @@ -1,86 +1,84 @@ using Spring.Validation; -namespace Spring.DataBinding +namespace Spring.DataBinding; + +/// +/// An interface that defines the methods that have to be implemented by all data bindings. +/// +/// Aleksandar Seovic +public interface IBinding { /// - /// An interface that defines the methods that have to be implemented by all data bindings. + /// Binds source object to target object. /// - /// Aleksandar Seovic - public interface IBinding - { - /// - /// Binds source object to target object. - /// - /// - /// The source object. - /// - /// - /// The target object. - /// - /// - /// Validation errors collection that type conversion errors should be added to. - /// - void BindSourceToTarget(object source, object target, IValidationErrors validationErrors); + /// + /// The source object. + /// + /// + /// The target object. + /// + /// + /// Validation errors collection that type conversion errors should be added to. + /// + void BindSourceToTarget(object source, object target, IValidationErrors validationErrors); - /// - /// Binds source object to target object. - /// - /// - /// The source object. - /// - /// - /// The target object. - /// - /// - /// Validation errors collection that type conversion errors should be added to. - /// - /// - /// Variables that should be used during expression evaluation. - /// - void BindSourceToTarget(object source, object target, IValidationErrors validationErrors, IDictionary variables); + /// + /// Binds source object to target object. + /// + /// + /// The source object. + /// + /// + /// The target object. + /// + /// + /// Validation errors collection that type conversion errors should be added to. + /// + /// + /// Variables that should be used during expression evaluation. + /// + void BindSourceToTarget(object source, object target, IValidationErrors validationErrors, IDictionary variables); - /// - /// Binds target object to source object. - /// - /// - /// The source object. - /// - /// - /// The target object. - /// - /// - /// Validation errors collection that type conversion errors should be added to. - /// - void BindTargetToSource(object source, object target, IValidationErrors validationErrors); + /// + /// Binds target object to source object. + /// + /// + /// The source object. + /// + /// + /// The target object. + /// + /// + /// Validation errors collection that type conversion errors should be added to. + /// + void BindTargetToSource(object source, object target, IValidationErrors validationErrors); - /// - /// Binds target object to source object. - /// - /// - /// The source object. - /// - /// - /// The target object. - /// - /// - /// Validation errors collection that type conversion errors should be added to. - /// - /// - /// Variables that should be used during expression evaluation. - /// - void BindTargetToSource(object source, object target, IValidationErrors validationErrors, IDictionary variables); + /// + /// Binds target object to source object. + /// + /// + /// The source object. + /// + /// + /// The target object. + /// + /// + /// Validation errors collection that type conversion errors should be added to. + /// + /// + /// Variables that should be used during expression evaluation. + /// + void BindTargetToSource(object source, object target, IValidationErrors validationErrors, IDictionary variables); - /// - /// Sets error message that should be displayed in the case - /// of a non-fatal binding error. - /// - /// - /// Resource ID of the error message. - /// - /// - /// List of error providers message should be added to. - /// - void SetErrorMessage(string messageId, params string[] errorProviders); - - } + /// + /// Sets error message that should be displayed in the case + /// of a non-fatal binding error. + /// + /// + /// Resource ID of the error message. + /// + /// + /// List of error providers message should be added to. + /// + void SetErrorMessage(string messageId, params string[] errorProviders); } diff --git a/src/Spring/Spring.Core/DataBinding/IBindingContainer.cs b/src/Spring/Spring.Core/DataBinding/IBindingContainer.cs index a2baaa5d..bef95a53 100644 --- a/src/Spring/Spring.Core/DataBinding/IBindingContainer.cs +++ b/src/Spring/Spring.Core/DataBinding/IBindingContainer.cs @@ -1,119 +1,118 @@ using Spring.Globalization; -namespace Spring.DataBinding +namespace Spring.DataBinding; + +/// +/// An interface that has to be implemented by all data binding containers. +/// +/// Aleksandar Seovic +public interface IBindingContainer : IBinding { /// - /// An interface that has to be implemented by all data binding containers. + /// Gets a value indicating whether this data binding container + /// has bindings. /// - /// Aleksandar Seovic - public interface IBindingContainer : IBinding - { - /// - /// Gets a value indicating whether this data binding container - /// has bindings. - /// - /// - /// true if this data binding container has bindings; - /// false otherwise. - /// - bool HasBindings { get; } + /// + /// true if this data binding container has bindings; + /// false otherwise. + /// + bool HasBindings { get; } - /// - /// Adds the binding. - /// - /// - /// Binding definition to add. - /// - /// - /// Added instance. - /// - IBinding AddBinding(IBinding binding); + /// + /// Adds the binding. + /// + /// + /// Binding definition to add. + /// + /// + /// Added instance. + /// + IBinding AddBinding(IBinding binding); - /// - /// Adds the binding with a default - /// binding direction of . - /// - /// - /// This is a convinience method for adding SimpleExpressionBinding, - /// one of the most often used binding types, to the bindings list. - /// - /// - /// The source expression. - /// - /// - /// The target expression. - /// - /// - /// Added instance. - /// - IBinding AddBinding(string sourceExpression, string targetExpression); + /// + /// Adds the binding with a default + /// binding direction of . + /// + /// + /// This is a convinience method for adding SimpleExpressionBinding, + /// one of the most often used binding types, to the bindings list. + /// + /// + /// The source expression. + /// + /// + /// The target expression. + /// + /// + /// Added instance. + /// + IBinding AddBinding(string sourceExpression, string targetExpression); - /// - /// Adds the binding. - /// - /// - /// This is a convinience method for adding SimpleExpressionBinding, - /// one of the most often used binding types, to the bindings list. - /// - /// - /// The source expression. - /// - /// - /// The target expression. - /// - /// - /// Binding direction. - /// - /// - /// Added instance. - /// - IBinding AddBinding(string sourceExpression, string targetExpression, BindingDirection direction); + /// + /// Adds the binding. + /// + /// + /// This is a convinience method for adding SimpleExpressionBinding, + /// one of the most often used binding types, to the bindings list. + /// + /// + /// The source expression. + /// + /// + /// The target expression. + /// + /// + /// Binding direction. + /// + /// + /// Added instance. + /// + IBinding AddBinding(string sourceExpression, string targetExpression, BindingDirection direction); - /// - /// Adds the binding with a default - /// binding direction of . - /// - /// - /// This is a convinience method for adding SimpleExpressionBinding, - /// one of the most often used binding types, to the bindings list. - /// - /// - /// The source expression. - /// - /// - /// The target expression. - /// - /// - /// to use for value formatting and parsing. - /// - /// - /// Added instance. - /// - IBinding AddBinding(string sourceExpression, string targetExpression, IFormatter formatter); + /// + /// Adds the binding with a default + /// binding direction of . + /// + /// + /// This is a convinience method for adding SimpleExpressionBinding, + /// one of the most often used binding types, to the bindings list. + /// + /// + /// The source expression. + /// + /// + /// The target expression. + /// + /// + /// to use for value formatting and parsing. + /// + /// + /// Added instance. + /// + IBinding AddBinding(string sourceExpression, string targetExpression, IFormatter formatter); - /// - /// Adds the binding. - /// - /// - /// This is a convinience method for adding SimpleExpressionBinding, - /// one of the most often used binding types, to the bindings list. - /// - /// - /// The source expression. - /// - /// - /// The target expression. - /// - /// - /// Binding direction. - /// - /// - /// to use for value formatting and parsing. - /// - /// - /// Added instance. - /// - IBinding AddBinding(string sourceExpression, string targetExpression, BindingDirection direction, - IFormatter formatter); - } + /// + /// Adds the binding. + /// + /// + /// This is a convinience method for adding SimpleExpressionBinding, + /// one of the most often used binding types, to the bindings list. + /// + /// + /// The source expression. + /// + /// + /// The target expression. + /// + /// + /// Binding direction. + /// + /// + /// to use for value formatting and parsing. + /// + /// + /// Added instance. + /// + IBinding AddBinding(string sourceExpression, string targetExpression, BindingDirection direction, + IFormatter formatter); } \ No newline at end of file diff --git a/src/Spring/Spring.Core/DataBinding/IDataBound.cs b/src/Spring/Spring.Core/DataBinding/IDataBound.cs index c56939ab..846c8735 100644 --- a/src/Spring/Spring.Core/DataBinding/IDataBound.cs +++ b/src/Spring/Spring.Core/DataBinding/IDataBound.cs @@ -18,19 +18,18 @@ #endregion -namespace Spring.DataBinding +namespace Spring.DataBinding; + +/// +/// Interface that should be implemented by data bound objects, such as +/// web pages, user controls, windows forms, etc. +/// +/// Aleksandar Seovic +public interface IDataBound { /// - /// Interface that should be implemented by data bound objects, such as - /// web pages, user controls, windows forms, etc. + /// Gets the binding manager. /// - /// Aleksandar Seovic - public interface IDataBound - { - /// - /// Gets the binding manager. - /// - /// The binding manager. - IBindingContainer BindingManager { get; } - } -} \ No newline at end of file + /// The binding manager. + IBindingContainer BindingManager { get; } +} diff --git a/src/Spring/Spring.Core/DataBinding/ListBinding.cs b/src/Spring/Spring.Core/DataBinding/ListBinding.cs index 69e52a24..a6da03ca 100644 --- a/src/Spring/Spring.Core/DataBinding/ListBinding.cs +++ b/src/Spring/Spring.Core/DataBinding/ListBinding.cs @@ -2,71 +2,72 @@ using System.Collections; using Spring.Expressions; using Spring.Validation; -namespace Spring.DataBinding +namespace Spring.DataBinding; + +/// +/// implementation that allows +/// data binding between collections that implement +/// interface. +/// +/// Aleksandar Seovic +public class ListBinding : AbstractBinding { + private IExpression sourceExpression = Expression.Parse("#source = #target"); + private IExpression targetExpression = Expression.Parse("#target = #source"); + /// - /// implementation that allows - /// data binding between collections that implement - /// interface. + /// Binds source object to target object. /// - /// Aleksandar Seovic - public class ListBinding : AbstractBinding + /// + /// The source object. + /// + /// + /// The target object. + /// + /// + /// Validation errors collection that type conversion errors should be added to. + /// + /// + /// Variables that should be used during expression evaluation. + /// + public override void BindSourceToTarget(object source, object target, IValidationErrors validationErrors, IDictionary variables) { - private IExpression sourceExpression = Expression.Parse("#source = #target"); - private IExpression targetExpression = Expression.Parse("#target = #source"); - - /// - /// Binds source object to target object. - /// - /// - /// The source object. - /// - /// - /// The target object. - /// - /// - /// Validation errors collection that type conversion errors should be added to. - /// - /// - /// Variables that should be used during expression evaluation. - /// - public override void BindSourceToTarget(object source, object target, IValidationErrors validationErrors, IDictionary variables) + if (variables == null) { - if (variables == null) - { - variables = new Dictionary(); - } - variables["source"] = source; - variables["target"] = target; - - targetExpression.GetValue(null, variables); + variables = new Dictionary(); } - /// - /// Binds target object to source object. - /// - /// - /// The source object. - /// - /// - /// The target object. - /// - /// - /// Validation errors collection that type conversion errors should be added to. - /// - /// - /// Variables that should be used during expression evaluation. - /// - public override void BindTargetToSource(object source, object target, IValidationErrors validationErrors, IDictionary variables) - { - if (variables == null) - { - variables = new Dictionary(); - } - variables["source"] = source; - variables["target"] = target; + variables["source"] = source; + variables["target"] = target; - sourceExpression.GetValue(null, variables); + targetExpression.GetValue(null, variables); + } + + /// + /// Binds target object to source object. + /// + /// + /// The source object. + /// + /// + /// The target object. + /// + /// + /// Validation errors collection that type conversion errors should be added to. + /// + /// + /// Variables that should be used during expression evaluation. + /// + public override void BindTargetToSource(object source, object target, IValidationErrors validationErrors, IDictionary variables) + { + if (variables == null) + { + variables = new Dictionary(); } + + variables["source"] = source; + variables["target"] = target; + + sourceExpression.GetValue(null, variables); } } diff --git a/src/Spring/Spring.Core/DataBinding/SimpleExpressionBinding.cs b/src/Spring/Spring.Core/DataBinding/SimpleExpressionBinding.cs index 7cb35968..5810e6c3 100644 --- a/src/Spring/Spring.Core/DataBinding/SimpleExpressionBinding.cs +++ b/src/Spring/Spring.Core/DataBinding/SimpleExpressionBinding.cs @@ -21,153 +21,151 @@ using Spring.Expressions; using Spring.Globalization; -namespace Spring.DataBinding +namespace Spring.DataBinding; + +/// +/// Simple, expression-based implementation of that +/// binds source to target one-to-one. +/// +/// Aleksandar Seovic +public class SimpleExpressionBinding : AbstractSimpleBinding { + #region Fields + + private IExpression sourceExpression; + private IExpression targetExpression; + + #endregion + + #region Constructor(s) + /// - /// Simple, expression-based implementation of that - /// binds source to target one-to-one. + /// Initializes a new instance of the class. /// - /// Aleksandar Seovic - public class SimpleExpressionBinding : AbstractSimpleBinding + /// + /// The source expression. + /// + /// + /// The target expression. + /// + public SimpleExpressionBinding(string sourceExpression, string targetExpression) { - #region Fields - - private IExpression sourceExpression; - private IExpression targetExpression; - - #endregion - - #region Constructor(s) - - /// - /// Initializes a new instance of the class. - /// - /// - /// The source expression. - /// - /// - /// The target expression. - /// - public SimpleExpressionBinding(string sourceExpression, string targetExpression) - { - this.sourceExpression = Expression.Parse(sourceExpression); - this.targetExpression = Expression.Parse(targetExpression); - } - - /// - /// Initializes a new instance of the class. - /// - /// - /// The source expression. - /// - /// - /// The target expression. - /// - /// - /// The formatter to use. - /// - public SimpleExpressionBinding(string sourceExpression, string targetExpression, IFormatter formatter) - :base(formatter) - { - this.sourceExpression = Expression.Parse(sourceExpression); - this.targetExpression = Expression.Parse(targetExpression); - } - - #endregion - - #region Properties - - /// - /// Gets the source expression. - /// - /// The source expression. - public IExpression SourceExpression - { - get { return sourceExpression; } - } - - /// - /// Gets the target expression. - /// - /// The target expression. - public IExpression TargetExpression - { - get { return targetExpression; } - } - - #endregion - - #region Abstract Methods Implementation - - /// - /// Gets the source value for the binding. - /// - /// - /// Source object to extract value from. - /// - /// - /// Variables for expression evaluation. - /// - /// - /// The source value for the binding. - /// - protected override object GetSourceValue(object source, IDictionary variables) - { - return this.SourceExpression.GetValue(source, variables); - } - - /// - /// Sets the source value for the binding. - /// - /// - /// The source object to set the value on. - /// - /// - /// The value to set. - /// - /// - /// Variables for expression evaluation. - /// - protected override void SetSourceValue(object source, object value, IDictionary variables) - { - this.SourceExpression.SetValue(source, variables, value); - } - - /// - /// Gets the target value for the binding. - /// - /// - /// Source object to extract value from. - /// - /// - /// Variables for expression evaluation. - /// - /// - /// The target value for the binding. - /// - protected override object GetTargetValue(object target, IDictionary variables) - { - return this.TargetExpression.GetValue(target, variables); - } - - /// - /// Sets the target value for the binding. - /// - /// - /// The target object to set the value on. - /// - /// - /// The value to set. - /// - /// - /// Variables for expression evaluation. - /// - protected override void SetTargetValue(object target, object value, IDictionary variables) - { - this.TargetExpression.SetValue(target, variables, value); - } - - #endregion - + this.sourceExpression = Expression.Parse(sourceExpression); + this.targetExpression = Expression.Parse(targetExpression); } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The source expression. + /// + /// + /// The target expression. + /// + /// + /// The formatter to use. + /// + public SimpleExpressionBinding(string sourceExpression, string targetExpression, IFormatter formatter) + : base(formatter) + { + this.sourceExpression = Expression.Parse(sourceExpression); + this.targetExpression = Expression.Parse(targetExpression); + } + + #endregion + + #region Properties + + /// + /// Gets the source expression. + /// + /// The source expression. + public IExpression SourceExpression + { + get { return sourceExpression; } + } + + /// + /// Gets the target expression. + /// + /// The target expression. + public IExpression TargetExpression + { + get { return targetExpression; } + } + + #endregion + + #region Abstract Methods Implementation + + /// + /// Gets the source value for the binding. + /// + /// + /// Source object to extract value from. + /// + /// + /// Variables for expression evaluation. + /// + /// + /// The source value for the binding. + /// + protected override object GetSourceValue(object source, IDictionary variables) + { + return this.SourceExpression.GetValue(source, variables); + } + + /// + /// Sets the source value for the binding. + /// + /// + /// The source object to set the value on. + /// + /// + /// The value to set. + /// + /// + /// Variables for expression evaluation. + /// + protected override void SetSourceValue(object source, object value, IDictionary variables) + { + this.SourceExpression.SetValue(source, variables, value); + } + + /// + /// Gets the target value for the binding. + /// + /// + /// Source object to extract value from. + /// + /// + /// Variables for expression evaluation. + /// + /// + /// The target value for the binding. + /// + protected override object GetTargetValue(object target, IDictionary variables) + { + return this.TargetExpression.GetValue(target, variables); + } + + /// + /// Sets the target value for the binding. + /// + /// + /// The target object to set the value on. + /// + /// + /// The value to set. + /// + /// + /// Variables for expression evaluation. + /// + protected override void SetTargetValue(object target, object value, IDictionary variables) + { + this.TargetExpression.SetValue(target, variables, value); + } + + #endregion } diff --git a/src/Spring/Spring.Core/Expressions/ArrayConstructorNode.cs b/src/Spring/Spring.Core/Expressions/ArrayConstructorNode.cs index d62cdc98..6b385519 100644 --- a/src/Spring/Spring.Core/Expressions/ArrayConstructorNode.cs +++ b/src/Spring/Spring.Core/Expressions/ArrayConstructorNode.cs @@ -23,75 +23,75 @@ using System.Runtime.Serialization; using Spring.Core.TypeResolution; using Spring.Expressions.Parser.antlr.collections; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// Represents parsed method node in the navigation expression. +/// +/// Aleksandar Seovic +[Serializable] +public class ArrayConstructorNode : NodeWithArguments { + private Type arrayType; + /// - /// Represents parsed method node in the navigation expression. + /// Create a new instance /// - /// Aleksandar Seovic - [Serializable] - public class ArrayConstructorNode : NodeWithArguments + public ArrayConstructorNode() { - private Type arrayType; + } - /// - /// Create a new instance - /// - public ArrayConstructorNode() - { - } + /// + /// Create a new instance from SerializationInfo + /// + protected ArrayConstructorNode(SerializationInfo info, StreamingContext context) : base(info, context) + { + } - /// - /// Create a new instance from SerializationInfo - /// - protected ArrayConstructorNode(SerializationInfo info, StreamingContext context) : base(info, context) + /// + /// Creates new instance of the type defined by this node. + /// + /// Context to evaluate expressions against. + /// Current expression evaluation context. + /// Node's value. + protected override object Get(object context, EvaluationContext evalContext) + { + if (arrayType == null) { - } - - /// - /// Creates new instance of the type defined by this node. - /// - /// Context to evaluate expressions against. - /// Current expression evaluation context. - /// Node's value. - protected override object Get(object context, EvaluationContext evalContext) - { - if (arrayType == null) + lock (this) { - lock (this) + if (arrayType == null) { - if (arrayType == null) - { - arrayType = TypeResolutionUtils.ResolveType(getText()); - } + arrayType = TypeResolutionUtils.ResolveType(getText()); } } - - AST rankRoot = getFirstChild(); - int dimensions = rankRoot.getNumberOfChildren(); - int[] ranks = new int[dimensions]; - if (dimensions > 0) - { - int i = 0; - AST rankNode = rankRoot.getFirstChild(); - while (rankNode != null) - { - ranks[i++] = (int)GetValue((BaseNode)rankNode, context, evalContext); - rankNode = rankNode.getNextSibling(); - } - return Array.CreateInstance(arrayType, ranks); - } - else - { - AST valuesRoot = getFirstChild().getNextSibling(); - if (valuesRoot != null) - { - ArrayList values = (ArrayList)GetValue(((BaseNode)valuesRoot), context, evalContext); - return values.ToArray(arrayType); - } - } - - throw new ArgumentException("You have to specify either rank or initializer for an array."); } + + AST rankRoot = getFirstChild(); + int dimensions = rankRoot.getNumberOfChildren(); + int[] ranks = new int[dimensions]; + if (dimensions > 0) + { + int i = 0; + AST rankNode = rankRoot.getFirstChild(); + while (rankNode != null) + { + ranks[i++] = (int) GetValue((BaseNode) rankNode, context, evalContext); + rankNode = rankNode.getNextSibling(); + } + + return Array.CreateInstance(arrayType, ranks); + } + else + { + AST valuesRoot = getFirstChild().getNextSibling(); + if (valuesRoot != null) + { + ArrayList values = (ArrayList) GetValue(((BaseNode) valuesRoot), context, evalContext); + return values.ToArray(arrayType); + } + } + + throw new ArgumentException("You have to specify either rank or initializer for an array."); } } diff --git a/src/Spring/Spring.Core/Expressions/AssignNode.cs b/src/Spring/Spring.Core/Expressions/AssignNode.cs index 853c354c..e86d5ea4 100644 --- a/src/Spring/Spring.Core/Expressions/AssignNode.cs +++ b/src/Spring/Spring.Core/Expressions/AssignNode.cs @@ -21,59 +21,59 @@ using System.Runtime.Serialization; using Spring.Expressions.Parser.antlr.collections; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// Represents parsed assignment node in the navigation expression. +/// +/// Aleksandar Seovic +[Serializable] +public class AssignNode : BaseNode { /// - /// Represents parsed assignment node in the navigation expression. + /// Create a new instance /// - /// Aleksandar Seovic - [Serializable] - public class AssignNode : BaseNode + public AssignNode() { - /// - /// Create a new instance - /// - public AssignNode() + } + + /// + /// Create a new instance from SerializationInfo + /// + protected AssignNode(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + + /// + /// Assigns value of the right operand to the left one. + /// + /// Context to evaluate expressions against. + /// Current expression evaluation context. + /// Node's value. + protected override object Get(object context, EvaluationContext evalContext) + { + AST left = getFirstChild(); + AST right = left.getNextSibling(); + + object result; + + if (right.getFirstChild() is LambdaExpressionNode) { - } - - /// - /// Create a new instance from SerializationInfo - /// - protected AssignNode(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } - - /// - /// Assigns value of the right operand to the left one. - /// - /// Context to evaluate expressions against. - /// Current expression evaluation context. - /// Node's value. - protected override object Get(object context, EvaluationContext evalContext) - { - AST left = getFirstChild(); - AST right = left.getNextSibling(); - - object result; - - if (right.getFirstChild() is LambdaExpressionNode) + if (!(left.getFirstChild() is VariableNode)) { - if (!(left.getFirstChild() is VariableNode)) - { - throw new ArgumentException("Lambda expression can only be assigned to a global variable."); - } - result = right.getFirstChild(); - } - else - { - result = GetValue(((BaseNode)right), context, evalContext); + throw new ArgumentException("Lambda expression can only be assigned to a global variable."); } - SetValue(((BaseNode)left), context, evalContext, result ); - - return result; + result = right.getFirstChild(); } + else + { + result = GetValue(((BaseNode) right), context, evalContext); + } + + SetValue(((BaseNode) left), context, evalContext, result); + + return result; } } diff --git a/src/Spring/Spring.Core/Expressions/AttributeNode.cs b/src/Spring/Spring.Core/Expressions/AttributeNode.cs index 0e6eb438..5e86dd37 100644 --- a/src/Spring/Spring.Core/Expressions/AttributeNode.cs +++ b/src/Spring/Spring.Core/Expressions/AttributeNode.cs @@ -19,64 +19,63 @@ #endregion using System.Runtime.Serialization; - using Spring.Core.TypeResolution; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// Represents parsed attribute node in the navigation expression. +/// +/// Aleksandar Seovic +[Serializable] +public class AttributeNode : ConstructorNode { /// - /// Represents parsed attribute node in the navigation expression. + /// Create a new instance /// - /// Aleksandar Seovic - [Serializable] - public class AttributeNode : ConstructorNode + public AttributeNode() { - /// - /// Create a new instance - /// - public AttributeNode() + } + + /// + /// Create a new instance from SerializationInfo + /// + protected AttributeNode(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + + /// + /// Tries to determine attribute type based on the specified + /// attribute type name. + /// + /// + /// Attribute type name to resolve. + /// + /// + /// Resolved attribute type. + /// + /// + /// If type cannot be resolved. + /// + protected override Type GetObjectType(string typeName) + { + Type type; + + try { + type = base.GetObjectType(typeName); } - - /// - /// Create a new instance from SerializationInfo - /// - protected AttributeNode(SerializationInfo info, StreamingContext context) - : base(info, context) + catch (TypeLoadException) { - } - - /// - /// Tries to determine attribute type based on the specified - /// attribute type name. - /// - /// - /// Attribute type name to resolve. - /// - /// - /// Resolved attribute type. - /// - /// - /// If type cannot be resolved. - /// - protected override Type GetObjectType(string typeName) - { - Type type; - - try + if (typeName.EndsWith("Attribute")) { - type = base.GetObjectType(typeName); - } - catch (TypeLoadException) - { - if (typeName.EndsWith("Attribute")) - { - throw; - } - type = TypeResolutionUtils.ResolveType(typeName + "Attribute"); + throw; } - return type; + type = TypeResolutionUtils.ResolveType(typeName + "Attribute"); } + + return type; } } diff --git a/src/Spring/Spring.Core/Expressions/BaseNode.cs b/src/Spring/Spring.Core/Expressions/BaseNode.cs index 0abd550c..855884b5 100644 --- a/src/Spring/Spring.Core/Expressions/BaseNode.cs +++ b/src/Spring/Spring.Core/Expressions/BaseNode.cs @@ -21,243 +21,248 @@ using System.Collections; using System.Runtime.Serialization; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// Base type for all expression nodes. +/// +/// Aleksandar Seovic +//[Serializable] +public abstract class BaseNode : SpringAST, IExpression { - /// - /// Base type for all expression nodes. - /// - /// Aleksandar Seovic - //[Serializable] - public abstract class BaseNode : SpringAST, IExpression + protected class ArgumentMismatchException : Exception { - protected class ArgumentMismatchException : Exception + public ArgumentMismatchException(string message) + : base(message) { - public ArgumentMismatchException(string message) - : base(message) - { } + } + } + + #region EvaluationContext class + + /// + /// Holds the state during evaluating an expression. + /// + protected class EvaluationContext + { + #region Holder classes + + private class ThisContextHolder : IDisposable + { + private readonly EvaluationContext owner; + private readonly object savedThisContext; + + public ThisContextHolder(EvaluationContext owner) + { + this.owner = owner; + this.savedThisContext = owner.ThisContext; + } + + public void Dispose() + { + owner.ThisContext = savedThisContext; + } } - #region EvaluationContext class - - /// - /// Holds the state during evaluating an expression. - /// - protected class EvaluationContext + private class LocalVariablesHolder : IDisposable { - #region Holder classes + private readonly EvaluationContext owner; + private readonly IDictionary savedLocalVariables; - private class ThisContextHolder : IDisposable + public LocalVariablesHolder(EvaluationContext owner, IDictionary newLocalVariables) { - private readonly EvaluationContext owner; - private readonly object savedThisContext; - - public ThisContextHolder(EvaluationContext owner) - { - this.owner = owner; - this.savedThisContext = owner.ThisContext; - } - - public void Dispose() - { - owner.ThisContext = savedThisContext; - } + this.owner = owner; + this.savedLocalVariables = owner.LocalVariables; + owner.LocalVariables = newLocalVariables; } - private class LocalVariablesHolder : IDisposable + public void Dispose() { - private readonly EvaluationContext owner; - private readonly IDictionary savedLocalVariables; - - public LocalVariablesHolder(EvaluationContext owner, IDictionary newLocalVariables) - { - this.owner = owner; - this.savedLocalVariables = owner.LocalVariables; - owner.LocalVariables = newLocalVariables; - } - - public void Dispose() - { - owner.LocalVariables = savedLocalVariables; - } - } - - #endregion - - /// - /// Gets/Sets the root context of the current evaluation - /// - public object RootContext; - /// - /// Gets the type of the - /// - public Type RootContextType { get { return (RootContext == null) ? null : RootContext.GetType(); } } - /// - /// Gets/Sets the current context of the current evaluation - /// - public object ThisContext; - /// - /// Gets/Sets global variables of the current evaluation - /// - public IDictionary Variables; - /// - /// Gets/Sets local variables of the current evaluation - /// - public IDictionary LocalVariables; - - /// - /// Initializes a new EvaluationContext instance. - /// - /// The root context for this evaluation - /// dictionary of global variables used during this evaluation - public EvaluationContext(object rootContext, IDictionary globalVariables) - { - this.RootContext = rootContext; - this.ThisContext = rootContext; - this.Variables = globalVariables; - } - - /// - /// Switches current ThisContext. - /// - public IDisposable SwitchThisContext() - { - return new ThisContextHolder(this); - } - - /// - /// Switches current LocalVariables. - /// - public IDisposable SwitchLocalVariables(IDictionary newLocalVariables) - { - return new LocalVariablesHolder(this, newLocalVariables); + owner.LocalVariables = savedLocalVariables; } } #endregion /// - /// Create a new instance + /// Gets/Sets the root context of the current evaluation /// - public BaseNode() - { } + public object RootContext; /// - /// Create a new instance from SerializationInfo + /// Gets the type of the /// - protected BaseNode(SerializationInfo info, StreamingContext context) - : base(info, context) + public Type RootContextType { get { return (RootContext == null) ? null : RootContext.GetType(); } } + + /// + /// Gets/Sets the current context of the current evaluation + /// + public object ThisContext; + + /// + /// Gets/Sets global variables of the current evaluation + /// + public IDictionary Variables; + + /// + /// Gets/Sets local variables of the current evaluation + /// + public IDictionary LocalVariables; + + /// + /// Initializes a new EvaluationContext instance. + /// + /// The root context for this evaluation + /// dictionary of global variables used during this evaluation + public EvaluationContext(object rootContext, IDictionary globalVariables) { + this.RootContext = rootContext; + this.ThisContext = rootContext; + this.Variables = globalVariables; } /// - /// Returns node's value. + /// Switches current ThisContext. /// - /// Node's value. - public object GetValue() + public IDisposable SwitchThisContext() { - return GetValue(null, null); + return new ThisContextHolder(this); } /// - /// Returns node's value for the given context. + /// Switches current LocalVariables. /// - /// Object to evaluate node against. - /// Node's value. - public object GetValue(object context) + public IDisposable SwitchLocalVariables(IDictionary newLocalVariables) { - return GetValue(context, null); - } - - /// - /// Returns node's value for the given context. - /// - /// Object to evaluate node against. - /// Expression variables map. - /// Node's value. - public object GetValue(object context, IDictionary variables) - { - EvaluationContext evalContext = new EvaluationContext(context, variables); - return Get(context, evalContext); - } - - /// - /// Returns node's value for the given context. - /// - /// Node's value. - protected abstract object Get(object context, EvaluationContext evalContext); - - /// - /// Evaluates this node for the given context, switching local variables map to the ones specified in . - /// - protected virtual object Get(object context, EvaluationContext evalContext, object[] arguments) - { - throw new NotSupportedException("Node " + this.GetType() + " does not support evaluation with arguments"); - } - - /// - /// Sets node's value for the given context. - /// - /// Object to evaluate node against. - /// New value for this node. - public void SetValue(object context, object newValue) - { - SetValue(context, null, newValue); - } - - /// - /// Sets node's value for the given context. - /// - /// Object to evaluate node against. - /// Expression variables map. - /// New value for this node. - public void SetValue(object context, IDictionary variables, object newValue) - { - EvaluationContext evalContext = new EvaluationContext(context, variables); - Set(context, evalContext, newValue); - } - - /// - /// Sets node's value for the given context. - /// - /// - ///

- /// This is a default implementation of Set method, which - /// simply throws . - ///

- ///

- /// This was done in order to avoid redundant Set method implementations, - /// because most of the node types do not support value setting. - ///

- ///
- protected virtual void Set(object context, EvaluationContext evalContext, object newValue) - { - throw new NotSupportedException("You cannot set the value for the node of this type: [" + this.GetType().Name + "]."); - } - - /// - /// Returns a string representation of this node instance. - /// - public override string ToString() - { - return string.Format("{0}[{1}]", this.GetType().Name, base.GetHashCode()); - } - - /// - /// Evaluates this node, switching local variables map to the ones specified in . - /// - protected object GetValueWithArguments(BaseNode node, object context, EvaluationContext evalContext, object[] arguments) - { - return node.Get(context, evalContext, arguments); - } - - protected object GetValue(BaseNode node, object context, EvaluationContext evalContext) - { - return node.Get(context, evalContext); - } - - protected void SetValue(BaseNode node, object context, EvaluationContext evalContext, object newValue) - { - node.Set(context, evalContext, newValue); + return new LocalVariablesHolder(this, newLocalVariables); } } + + #endregion + + /// + /// Create a new instance + /// + public BaseNode() + { + } + + /// + /// Create a new instance from SerializationInfo + /// + protected BaseNode(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + + /// + /// Returns node's value. + /// + /// Node's value. + public object GetValue() + { + return GetValue(null, null); + } + + /// + /// Returns node's value for the given context. + /// + /// Object to evaluate node against. + /// Node's value. + public object GetValue(object context) + { + return GetValue(context, null); + } + + /// + /// Returns node's value for the given context. + /// + /// Object to evaluate node against. + /// Expression variables map. + /// Node's value. + public object GetValue(object context, IDictionary variables) + { + EvaluationContext evalContext = new EvaluationContext(context, variables); + return Get(context, evalContext); + } + + /// + /// Returns node's value for the given context. + /// + /// Node's value. + protected abstract object Get(object context, EvaluationContext evalContext); + + /// + /// Evaluates this node for the given context, switching local variables map to the ones specified in . + /// + protected virtual object Get(object context, EvaluationContext evalContext, object[] arguments) + { + throw new NotSupportedException("Node " + this.GetType() + " does not support evaluation with arguments"); + } + + /// + /// Sets node's value for the given context. + /// + /// Object to evaluate node against. + /// New value for this node. + public void SetValue(object context, object newValue) + { + SetValue(context, null, newValue); + } + + /// + /// Sets node's value for the given context. + /// + /// Object to evaluate node against. + /// Expression variables map. + /// New value for this node. + public void SetValue(object context, IDictionary variables, object newValue) + { + EvaluationContext evalContext = new EvaluationContext(context, variables); + Set(context, evalContext, newValue); + } + + /// + /// Sets node's value for the given context. + /// + /// + ///

+ /// This is a default implementation of Set method, which + /// simply throws . + ///

+ ///

+ /// This was done in order to avoid redundant Set method implementations, + /// because most of the node types do not support value setting. + ///

+ ///
+ protected virtual void Set(object context, EvaluationContext evalContext, object newValue) + { + throw new NotSupportedException("You cannot set the value for the node of this type: [" + this.GetType().Name + "]."); + } + + /// + /// Returns a string representation of this node instance. + /// + public override string ToString() + { + return string.Format("{0}[{1}]", this.GetType().Name, base.GetHashCode()); + } + + /// + /// Evaluates this node, switching local variables map to the ones specified in . + /// + protected object GetValueWithArguments(BaseNode node, object context, EvaluationContext evalContext, object[] arguments) + { + return node.Get(context, evalContext, arguments); + } + + protected object GetValue(BaseNode node, object context, EvaluationContext evalContext) + { + return node.Get(context, evalContext); + } + + protected void SetValue(BaseNode node, object context, EvaluationContext evalContext, object newValue) + { + node.Set(context, evalContext, newValue); + } } diff --git a/src/Spring/Spring.Core/Expressions/BinaryOperator.cs b/src/Spring/Spring.Core/Expressions/BinaryOperator.cs index f8e9bee7..4044540b 100644 --- a/src/Spring/Spring.Core/Expressions/BinaryOperator.cs +++ b/src/Spring/Spring.Core/Expressions/BinaryOperator.cs @@ -20,70 +20,72 @@ using System.Runtime.Serialization; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// Base class for binary operators. +/// +/// Aleksandar Seovic +[Serializable] +public abstract class BinaryOperator : BaseNode { /// - /// Base class for binary operators. + /// Create a new instance /// - /// Aleksandar Seovic - [Serializable] - public abstract class BinaryOperator : BaseNode + protected BinaryOperator() { - /// - /// Create a new instance - /// - protected BinaryOperator() - {} + } - /// - /// Create a new instance with the supplied operands - /// - /// - /// - protected BinaryOperator(BaseNode left, BaseNode right) - { - base.addChild(left); - base.addChild(right); - } + /// + /// Create a new instance with the supplied operands + /// + /// + /// + protected BinaryOperator(BaseNode left, BaseNode right) + { + base.addChild(left); + base.addChild(right); + } - /// - /// Create a new instance from SerializationInfo - /// - protected BinaryOperator(SerializationInfo info, StreamingContext context) - : base(info, context) - {} + /// + /// Create a new instance from SerializationInfo + /// + protected BinaryOperator(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } - /// - /// Gets the left operand. - /// - /// The left operand. - public BaseNode Left - { - get { return (BaseNode) this.getFirstChild(); } - } + /// + /// Gets the left operand. + /// + /// The left operand. + public BaseNode Left + { + get { return (BaseNode) this.getFirstChild(); } + } - /// - /// Evaluate the left operand - /// - protected object GetLeftValue(object context, EvaluationContext evalContext) - { - return GetValue(Left, context, evalContext); - } - /// - /// Gets the right operand. - /// - /// The right operand. - public BaseNode Right - { - get { return (BaseNode) this.getFirstChild().getNextSibling(); } - } + /// + /// Evaluate the left operand + /// + protected object GetLeftValue(object context, EvaluationContext evalContext) + { + return GetValue(Left, context, evalContext); + } - /// - /// Evaluate the left operand - /// - protected object GetRightValue(object context, EvaluationContext evalContext) - { - return GetValue(Right, context, evalContext); - } + /// + /// Gets the right operand. + /// + /// The right operand. + public BaseNode Right + { + get { return (BaseNode) this.getFirstChild().getNextSibling(); } + } + + /// + /// Evaluate the left operand + /// + protected object GetRightValue(object context, EvaluationContext evalContext) + { + return GetValue(Right, context, evalContext); } } diff --git a/src/Spring/Spring.Core/Expressions/BooleanLiteralNode.cs b/src/Spring/Spring.Core/Expressions/BooleanLiteralNode.cs index 64a28451..0ac098d5 100644 --- a/src/Spring/Spring.Core/Expressions/BooleanLiteralNode.cs +++ b/src/Spring/Spring.Core/Expressions/BooleanLiteralNode.cs @@ -20,61 +20,60 @@ using System.Runtime.Serialization; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// Represents parsed boolean literal node. +/// +/// Aleksandar Seovic +[Serializable] +public class BooleanLiteralNode : BaseNode { + private object nodeValue; + /// - /// Represents parsed boolean literal node. + /// Create a new instance /// - /// Aleksandar Seovic - [Serializable] - public class BooleanLiteralNode : BaseNode + public BooleanLiteralNode() { - private object nodeValue; + } - /// - /// Create a new instance - /// - public BooleanLiteralNode() - { - } + /// + /// Create a new instance + /// + public BooleanLiteralNode(string text) + { + this.Text = text; + } - /// - /// Create a new instance - /// - public BooleanLiteralNode(string text) - { - this.Text = text; - } + /// + /// Create a new instance from SerializationInfo + /// + protected BooleanLiteralNode(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } - /// - /// Create a new instance from SerializationInfo - /// - protected BooleanLiteralNode(SerializationInfo info, StreamingContext context) - : base(info, context) + /// + /// Returns a value for the boolean literal node. + /// + /// + /// This is the entrypoint into evaluating this expression. + /// + /// Node's value. + protected override object Get(object context, EvaluationContext evalContext) + { + if (nodeValue == null) { - } - - /// - /// Returns a value for the boolean literal node. - /// - /// - /// This is the entrypoint into evaluating this expression. - /// - /// Node's value. - protected override object Get(object context, EvaluationContext evalContext) - { - if (nodeValue == null) + lock (this) { - lock(this) + if (nodeValue == null) { - if (nodeValue == null) - { - nodeValue = Boolean.Parse(this.getText()); - } + nodeValue = Boolean.Parse(this.getText()); } } - - return nodeValue; } + + return nodeValue; } } diff --git a/src/Spring/Spring.Core/Expressions/ConstructorNode.cs b/src/Spring/Spring.Core/Expressions/ConstructorNode.cs index 30ad962a..8cd31608 100644 --- a/src/Spring/Spring.Core/Expressions/ConstructorNode.cs +++ b/src/Spring/Spring.Core/Expressions/ConstructorNode.cs @@ -21,194 +21,193 @@ using System.Collections; using System.Reflection; using System.Runtime.Serialization; - using Spring.Core.TypeResolution; using Spring.Util; using Spring.Reflection.Dynamic; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// Represents parsed method node in the navigation expression. +/// +/// Aleksandar Seovic +[Serializable] +public class ConstructorNode : NodeWithArguments { + private SafeConstructor constructor; + private IDictionary namedArgs; + private bool isParamArray = false; + private Type paramArrayType; + private int argumentCount; + /// - /// Represents parsed method node in the navigation expression. + /// Create a new instance /// - /// Aleksandar Seovic - [Serializable] - public class ConstructorNode : NodeWithArguments + public ConstructorNode() { - private SafeConstructor constructor; - private IDictionary namedArgs; - private bool isParamArray = false; - private Type paramArrayType; - private int argumentCount; + } - /// - /// Create a new instance - /// - public ConstructorNode() + /// + /// Create a new instance + /// + public ConstructorNode(Type type) + : base(type.FullName) + { + } + + /// + /// Create a new instance from SerializationInfo + /// + protected ConstructorNode(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + + /// + /// Creates new instance of the type defined by this node. + /// + /// Context to evaluate expressions against. + /// Current expression evaluation context. + /// Node's value. + protected override object Get(object context, EvaluationContext evalContext) + { + object[] argValues = ResolveArguments(evalContext); + IDictionary namedArgValues = ResolveNamedArguments(evalContext); + + if (constructor == null) { - } - - /// - /// Create a new instance - /// - public ConstructorNode(Type type) - :base(type.FullName) - { - } - - /// - /// Create a new instance from SerializationInfo - /// - protected ConstructorNode(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } - - /// - /// Creates new instance of the type defined by this node. - /// - /// Context to evaluate expressions against. - /// Current expression evaluation context. - /// Node's value. - protected override object Get(object context, EvaluationContext evalContext) - { - object[] argValues = ResolveArguments(evalContext); - IDictionary namedArgValues = ResolveNamedArguments(evalContext); - - if (constructor == null) + lock (this) { - lock(this) + if (constructor == null) { - if (constructor == null) - { - constructor = InitializeNode(argValues, namedArgValues); - } + constructor = InitializeNode(argValues, namedArgValues); + } + } + } + + object[] paramValues = (isParamArray ? ReflectionUtils.PackageParamArray(argValues, argumentCount, paramArrayType) : argValues); + object instance = constructor.Invoke(paramValues); + if (namedArgValues != null) + { + SetNamedArguments(instance, namedArgValues); + } + + return instance; + } + + /// + /// Determines the type of object that should be instantiated. + /// + /// + /// The type name to resolve. + /// + /// + /// The type of object that should be instantiated. + /// + /// + /// If the type cannot be resolved. + /// + protected virtual Type GetObjectType(string typeName) + { + return TypeResolutionUtils.ResolveType(typeName); + } + + /// + /// Initializes this node by caching necessary constructor and property info. + /// + /// + /// + private SafeConstructor InitializeNode(object[] argValues, IDictionary namedArgValues) + { + SafeConstructor ctor = null; + Type objectType = GetObjectType(this.getText().Trim()); + + // cache constructor info + ConstructorInfo ci = GetBestConstructor(objectType, argValues); + if (ci == null) + { + throw new ArgumentException( + String.Format("Constructor for the type [{0}] with a specified " + + "number and types of arguments does not exist.", + objectType.FullName)); + } + else + { + ParameterInfo[] parameters = ci.GetParameters(); + if (parameters.Length > 0) + { + ParameterInfo lastParameter = parameters[parameters.Length - 1]; + isParamArray = lastParameter.GetCustomAttributes(typeof(ParamArrayAttribute), false).Length > 0; + if (isParamArray) + { + paramArrayType = lastParameter.ParameterType.GetElementType(); + argumentCount = parameters.Length; } } - object[] paramValues = (isParamArray ? ReflectionUtils.PackageParamArray(argValues, argumentCount, paramArrayType) : argValues); - object instance = constructor.Invoke(paramValues); - if (namedArgValues != null) - { - SetNamedArguments(instance, namedArgValues); - } - - return instance; + ctor = new SafeConstructor(ci); } - /// - /// Determines the type of object that should be instantiated. - /// - /// - /// The type name to resolve. - /// - /// - /// The type of object that should be instantiated. - /// - /// - /// If the type cannot be resolved. - /// - protected virtual Type GetObjectType(string typeName) - { - return TypeResolutionUtils.ResolveType(typeName); - } - - /// - /// Initializes this node by caching necessary constructor and property info. - /// - /// - /// - private SafeConstructor InitializeNode(object[] argValues, IDictionary namedArgValues) - { - SafeConstructor ctor = null; - Type objectType = GetObjectType(this.getText().Trim()); - - // cache constructor info - ConstructorInfo ci = GetBestConstructor(objectType, argValues); - if (ci == null) - { - throw new ArgumentException( - String.Format("Constructor for the type [{0}] with a specified " + - "number and types of arguments does not exist.", - objectType.FullName)); - } - else - { - ParameterInfo[] parameters = ci.GetParameters(); - if (parameters.Length > 0) - { - ParameterInfo lastParameter = parameters[parameters.Length - 1]; - isParamArray = lastParameter.GetCustomAttributes(typeof(ParamArrayAttribute), false).Length > 0; - if (isParamArray) - { - paramArrayType = lastParameter.ParameterType.GetElementType(); - argumentCount = parameters.Length; - } - } - ctor = new SafeConstructor(ci); - } - - // cache named args info - if (namedArgValues != null) - { - namedArgs = new Hashtable(namedArgValues.Count); - foreach (string name in namedArgValues.Keys) - { - this.namedArgs[name] = Expression.ParseProperty(name); - } - } - - return ctor; - } - - /// - /// Sets the named arguments (properties). - /// - /// Instance to set property values on. - /// Argument (property) name to value mappings. - private void SetNamedArguments(object instance, IDictionary namedArgValues) + // cache named args info + if (namedArgValues != null) { + namedArgs = new Hashtable(namedArgValues.Count); foreach (string name in namedArgValues.Keys) { - IExpression property = (IExpression) namedArgs[name]; - property.SetValue(instance, namedArgValues[name]); + this.namedArgs[name] = Expression.ParseProperty(name); } } - private static ConstructorInfo GetBestConstructor(Type type, object[] argValues) + return ctor; + } + + /// + /// Sets the named arguments (properties). + /// + /// Instance to set property values on. + /// Argument (property) name to value mappings. + private void SetNamedArguments(object instance, IDictionary namedArgValues) + { + foreach (string name in namedArgValues.Keys) { - IList candidates = GetCandidateConstructors(type, argValues.Length); - if (candidates.Count > 0) - { - return ReflectionUtils.GetConstructorByArgumentValues(candidates, argValues); - } - return null; + IExpression property = (IExpression) namedArgs[name]; + property.SetValue(instance, namedArgValues[name]); + } + } + + private static ConstructorInfo GetBestConstructor(Type type, object[] argValues) + { + IList candidates = GetCandidateConstructors(type, argValues.Length); + if (candidates.Count > 0) + { + return ReflectionUtils.GetConstructorByArgumentValues(candidates, argValues); } - private static IList GetCandidateConstructors(Type type, int argCount) - { - ConstructorInfo[] ctors = type.GetConstructors(BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic); - List matches = new List(); + return null; + } - foreach (ConstructorInfo ctor in ctors) + private static IList GetCandidateConstructors(Type type, int argCount) + { + ConstructorInfo[] ctors = type.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + List matches = new List(); + + foreach (ConstructorInfo ctor in ctors) + { + ParameterInfo[] parameters = ctor.GetParameters(); + if (parameters.Length == argCount) { - ParameterInfo[] parameters = ctor.GetParameters(); - if (parameters.Length == argCount) + matches.Add(ctor); + } + else if (parameters.Length > 0) + { + ParameterInfo lastParameter = parameters[parameters.Length - 1]; + if (lastParameter.GetCustomAttributes(typeof(ParamArrayAttribute), false).Length > 0) { matches.Add(ctor); } - else if (parameters.Length > 0) - { - ParameterInfo lastParameter = parameters[parameters.Length - 1]; - if (lastParameter.GetCustomAttributes(typeof(ParamArrayAttribute), false).Length > 0) - { - matches.Add(ctor); - } - } } - - return matches; } + return matches; } } diff --git a/src/Spring/Spring.Core/Expressions/DefaultNode.cs b/src/Spring/Spring.Core/Expressions/DefaultNode.cs index 9652a054..a3800000 100644 --- a/src/Spring/Spring.Core/Expressions/DefaultNode.cs +++ b/src/Spring/Spring.Core/Expressions/DefaultNode.cs @@ -20,42 +20,41 @@ using System.Runtime.Serialization; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// Represents parsed default node in the navigation expression. +/// +/// Aleksandar Seovic +[Serializable] +public class DefaultNode : BinaryOperator { /// - /// Represents parsed default node in the navigation expression. + /// Create a new instance /// - /// Aleksandar Seovic - [Serializable] - public class DefaultNode : BinaryOperator + public DefaultNode() { - /// - /// Create a new instance - /// - public DefaultNode() - { - } + } - /// - /// Create a new instance from SerializationInfo - /// - protected DefaultNode(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } + /// + /// Create a new instance from SerializationInfo + /// + protected DefaultNode(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } - /// - /// Returns left operand if it is not null, or the right operand if it is. - /// - /// Context to evaluate expressions against. - /// Current expression evaluation context. - /// Node's value. - protected override object Get(object context, EvaluationContext evalContext) - { - object leftVal = GetValue(Left, context, evalContext); - object rightVal = GetValue(Right, context, evalContext); + /// + /// Returns left operand if it is not null, or the right operand if it is. + /// + /// Context to evaluate expressions against. + /// Current expression evaluation context. + /// Node's value. + protected override object Get(object context, EvaluationContext evalContext) + { + object leftVal = GetValue(Left, context, evalContext); + object rightVal = GetValue(Right, context, evalContext); - return (leftVal != null ? leftVal : rightVal); - } + return (leftVal != null ? leftVal : rightVal); } } diff --git a/src/Spring/Spring.Core/Expressions/Expression.cs b/src/Spring/Spring.Core/Expressions/Expression.cs index 8e4cc5da..d44e6e70 100644 --- a/src/Spring/Spring.Core/Expressions/Expression.cs +++ b/src/Spring/Spring.Core/Expressions/Expression.cs @@ -29,327 +29,334 @@ using Spring.Reflection.Dynamic; using Spring.Util; using StringUtils = Spring.Util.StringUtils; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// Container object for the parsed expression. +/// +/// +///

+/// Preparing this object once and reusing it many times for expression +/// evaluation can result in significant performance improvements, as +/// expression parsing and reflection lookups are only performed once. +///

+///
+/// Aleksandar Seovic +[Serializable] +public class Expression : BaseNode { /// - /// Container object for the parsed expression. + /// Contains a list of reserved variable names. + /// You must not use any variable names with the reserved prefix! /// - /// - ///

- /// Preparing this object once and reusing it many times for expression - /// evaluation can result in significant performance improvements, as - /// expression parsing and reflection lookups are only performed once. - ///

- ///
- /// Aleksandar Seovic - [Serializable] - public class Expression : BaseNode + public class ReservedVariableNames { /// - /// Contains a list of reserved variable names. - /// You must not use any variable names with the reserved prefix! + /// Variable Names using this prefix are reserved for internal framework use /// - public class ReservedVariableNames - { - /// - /// Variable Names using this prefix are reserved for internal framework use - /// - public static readonly string RESERVEDPREFIX = "____spring_"; + public static readonly string RESERVEDPREFIX = "____spring_"; - /// - /// variable name of the currently processed object factory, if any - /// - internal static readonly string CurrentObjectFactory = RESERVEDPREFIX + "CurrentObjectFactory"; + /// + /// variable name of the currently processed object factory, if any + /// + internal static readonly string CurrentObjectFactory = RESERVEDPREFIX + "CurrentObjectFactory"; + } + + private class ASTNodeCreator : Parser.antlr.ASTNodeCreator + { + private readonly SafeConstructor ctor; + private readonly string name; + + public ASTNodeCreator(ConstructorInfo ctor) + { + this.ctor = new SafeConstructor(ctor); + this.name = ctor.DeclaringType.FullName; } - private class ASTNodeCreator : Parser.antlr.ASTNodeCreator + public override AST Create() { - private readonly SafeConstructor ctor; - private readonly string name; - - public ASTNodeCreator(ConstructorInfo ctor) - { - this.ctor = new SafeConstructor(ctor); - this.name = ctor.DeclaringType.FullName; - } - - public override AST Create() - { - return (AST) ctor.Invoke(new object[0]); - } - - public override string ASTNodeTypeName - { - get { return name; } - } + return (AST) ctor.Invoke(new object[0]); } - private class SpringASTFactory : ASTFactory + public override string ASTNodeTypeName { - private static readonly Type BASENODE_TYPE; - private static readonly Hashtable Typename2Creator; + get { return name; } + } + } - static SpringASTFactory() + private class SpringASTFactory : ASTFactory + { + private static readonly Type BASENODE_TYPE; + private static readonly Hashtable Typename2Creator; + + static SpringASTFactory() + { + BASENODE_TYPE = typeof(SpringAST); + + Typename2Creator = new Hashtable(); + foreach (Type type in typeof(SpringASTFactory).Assembly.GetTypes()) { - BASENODE_TYPE = typeof (SpringAST); - - Typename2Creator = new Hashtable(); - foreach (Type type in typeof(SpringASTFactory).Assembly.GetTypes()) + if (BASENODE_TYPE.IsAssignableFrom(type) && !type.IsAbstract) { - if (BASENODE_TYPE.IsAssignableFrom(type) && !type.IsAbstract) + ConstructorInfo ctor = type.GetConstructor(System.Type.EmptyTypes); + if (ctor != null) { - ConstructorInfo ctor = type.GetConstructor(System.Type.EmptyTypes); - if (ctor != null) - { - ASTNodeCreator creator = new ASTNodeCreator(ctor); - Typename2Creator[creator.ASTNodeTypeName] = creator; - } + ASTNodeCreator creator = new ASTNodeCreator(ctor); + Typename2Creator[creator.ASTNodeTypeName] = creator; } } - Typename2Creator[BASENODE_TYPE.FullName] = SpringAST.Creator; } - public SpringASTFactory() : base(BASENODE_TYPE) - { - base.defaultASTNodeTypeObject_ = BASENODE_TYPE; - base.typename2creator_ = Typename2Creator; - } + Typename2Creator[BASENODE_TYPE.FullName] = SpringAST.Creator; } - private class SpringExpressionParser : ExpressionParser + public SpringASTFactory() : base(BASENODE_TYPE) { - public SpringExpressionParser( TokenStream lexer ) - : base( lexer ) - { - base.astFactory = new SpringASTFactory(); - base.initialize(); - } + base.defaultASTNodeTypeObject_ = BASENODE_TYPE; + base.typename2creator_ = Typename2Creator; } + } - static Expression() + private class SpringExpressionParser : ExpressionParser + { + public SpringExpressionParser(TokenStream lexer) + : base(lexer) { - // Ensure antlr is loaded (fixes GAC issues)! - Assembly antlrAss = typeof( Parser.antlr.LLkParser ).Assembly; + base.astFactory = new SpringASTFactory(); + base.initialize(); } + } - /// - /// Initializes a new instance of the class - /// by parsing specified expression string. - /// - /// Expression to parse. - public static IExpression Parse( string expression ) + static Expression() + { + // Ensure antlr is loaded (fixes GAC issues)! + Assembly antlrAss = typeof(Parser.antlr.LLkParser).Assembly; + } + + /// + /// Initializes a new instance of the class + /// by parsing specified expression string. + /// + /// Expression to parse. + public static IExpression Parse(string expression) + { + if (StringUtils.HasText(expression)) { - if (StringUtils.HasText( expression )) - { - ExpressionLexer lexer = new ExpressionLexer( new StringReader( expression ) ); - ExpressionParser parser = new SpringExpressionParser( lexer ); - - try - { - parser.expr(); - } - catch (TokenStreamRecognitionException ex) - { - throw new SyntaxErrorException( ex.recog.Message, ex.recog.getLine(), ex.recog.getColumn(), expression ); - } - return (IExpression)parser.getAST(); - } - else - { - return new Expression(); - } - } - - /// - /// Registers lambda expression under the specified . - /// - /// Function name to register expression as. - /// Lambda expression to register. - /// Variables dictionary that the function will be registered in. - public static void RegisterFunction( string functionName, string lambdaExpression, IDictionary variables ) - { - AssertUtils.ArgumentHasText( functionName, "functionName" ); - AssertUtils.ArgumentHasText( lambdaExpression, "lambdaExpression" ); - - ExpressionLexer lexer = new ExpressionLexer( new StringReader( lambdaExpression ) ); - ExpressionParser parser = new SpringExpressionParser( lexer ); + ExpressionLexer lexer = new ExpressionLexer(new StringReader(expression)); + ExpressionParser parser = new SpringExpressionParser(lexer); try { - parser.lambda(); + parser.expr(); } catch (TokenStreamRecognitionException ex) { - throw new SyntaxErrorException( ex.recog.Message, ex.recog.getLine(), ex.recog.getColumn(), lambdaExpression ); + throw new SyntaxErrorException(ex.recog.Message, ex.recog.getLine(), ex.recog.getColumn(), expression); } - variables[functionName] = parser.getAST(); + + return (IExpression) parser.getAST(); } - - /// - /// Initializes a new instance of the class - /// by parsing specified primary expression string. - /// - /// Primary expression to parse. - internal static IExpression ParsePrimary( string expression ) + else { - if (StringUtils.HasText( expression )) - { - ExpressionLexer lexer = new ExpressionLexer( new StringReader( expression ) ); - ExpressionParser parser = new SpringExpressionParser( lexer ); - - try - { - parser.primaryExpression(); - } - catch (TokenStreamRecognitionException ex) - { - throw new SyntaxErrorException( ex.recog.Message, ex.recog.getLine(), ex.recog.getColumn(), expression ); - } - return (IExpression)parser.getAST(); - } - else - { - return new Expression(); - } - } - - /// - /// Initializes a new instance of the class - /// by parsing specified property expression string. - /// - /// Property expression to parse. - internal static IExpression ParseProperty( string expression ) - { - if (StringUtils.HasText( expression )) - { - ExpressionLexer lexer = new ExpressionLexer( new StringReader( expression ) ); - ExpressionParser parser = new SpringExpressionParser( lexer ); - - try - { - parser.property(); - } - catch (TokenStreamRecognitionException ex) - { - throw new SyntaxErrorException( ex.recog.Message, ex.recog.getLine(), ex.recog.getColumn(), expression ); - } - return (IExpression)parser.getAST(); - } - else - { - return new Expression(); - } - } - - /// - /// Initializes a new instance of the class. - /// - public Expression() - { } - - /// - /// Create a new instance from SerializationInfo - /// - protected Expression( SerializationInfo info, StreamingContext context ) - : base( info, context ) - { } - - /// - /// Evaluates this expression for the specified root object and returns - /// value of the last node. - /// - /// Context to evaluate expressions against. - /// Current expression evaluation context. - /// Value of the last node. - protected override object Get(object context, EvaluationContext evalContext) - { - object result = context; - - if (this.getNumberOfChildren() > 0) - { - AST node = this.getFirstChild(); - while (node != null) - { - result = GetValue(((BaseNode)node), result, evalContext ); - - node = node.getNextSibling(); - } - } - - return result; - } - - /// - /// Evaluates this expression for the specified root object and sets - /// value of the last node. - /// - /// Context to evaluate expressions against. - /// Current expression evaluation context. - /// Value to set last node to. - /// If navigation expression is empty. - protected override void Set( object context, EvaluationContext evalContext, object newValue ) - { - object target = context; - - if (this.getNumberOfChildren() > 0) - { - AST node = this.getFirstChild(); - - for (int i = 0; i < this.getNumberOfChildren() - 1; i++) - { - try - { - target = GetValue(((BaseNode)node), target, evalContext); - node = node.getNextSibling(); - } - catch (NotReadablePropertyException e) - { - throw new NotWritablePropertyException( "Cannot read the value of '" + node.getText() + "' property in the expression.", e ); - } - } - SetValue(((BaseNode)node), target, evalContext, newValue); - } - else - { - throw new NotSupportedException( "You cannot set the value for an empty expression." ); - } - } - - /// - /// Evaluates this expression for the specified root object and returns - /// of the last node, if possible. - /// - /// Context to evaluate expression against. - /// Expression variables map. - /// Value of the last node. - internal PropertyInfo GetPropertyInfo( object context, IDictionary variables ) - { - if (this.getNumberOfChildren() > 0) - { - object target = context; - AST node = this.getFirstChild(); - - for (int i = 0; i < this.getNumberOfChildren() - 1; i++) - { - target = ((IExpression)node).GetValue( target, variables ); - node = node.getNextSibling(); - } - - if (node is PropertyOrFieldNode) - { - return (PropertyInfo)((PropertyOrFieldNode)node).GetMemberInfo( target ); - } - else if (node is IndexerNode) - { - return ((IndexerNode)node).GetPropertyInfo( target, variables ); - } - else - { - throw new FatalReflectionException( "Cannot obtain PropertyInfo from an expression that does not resolve to a property or an indexer." ); - } - } - - throw new FatalReflectionException( "Cannot obtain PropertyInfo for empty property name." ); + return new Expression(); } } + + /// + /// Registers lambda expression under the specified . + /// + /// Function name to register expression as. + /// Lambda expression to register. + /// Variables dictionary that the function will be registered in. + public static void RegisterFunction(string functionName, string lambdaExpression, IDictionary variables) + { + AssertUtils.ArgumentHasText(functionName, "functionName"); + AssertUtils.ArgumentHasText(lambdaExpression, "lambdaExpression"); + + ExpressionLexer lexer = new ExpressionLexer(new StringReader(lambdaExpression)); + ExpressionParser parser = new SpringExpressionParser(lexer); + + try + { + parser.lambda(); + } + catch (TokenStreamRecognitionException ex) + { + throw new SyntaxErrorException(ex.recog.Message, ex.recog.getLine(), ex.recog.getColumn(), lambdaExpression); + } + + variables[functionName] = parser.getAST(); + } + + /// + /// Initializes a new instance of the class + /// by parsing specified primary expression string. + /// + /// Primary expression to parse. + internal static IExpression ParsePrimary(string expression) + { + if (StringUtils.HasText(expression)) + { + ExpressionLexer lexer = new ExpressionLexer(new StringReader(expression)); + ExpressionParser parser = new SpringExpressionParser(lexer); + + try + { + parser.primaryExpression(); + } + catch (TokenStreamRecognitionException ex) + { + throw new SyntaxErrorException(ex.recog.Message, ex.recog.getLine(), ex.recog.getColumn(), expression); + } + + return (IExpression) parser.getAST(); + } + else + { + return new Expression(); + } + } + + /// + /// Initializes a new instance of the class + /// by parsing specified property expression string. + /// + /// Property expression to parse. + internal static IExpression ParseProperty(string expression) + { + if (StringUtils.HasText(expression)) + { + ExpressionLexer lexer = new ExpressionLexer(new StringReader(expression)); + ExpressionParser parser = new SpringExpressionParser(lexer); + + try + { + parser.property(); + } + catch (TokenStreamRecognitionException ex) + { + throw new SyntaxErrorException(ex.recog.Message, ex.recog.getLine(), ex.recog.getColumn(), expression); + } + + return (IExpression) parser.getAST(); + } + else + { + return new Expression(); + } + } + + /// + /// Initializes a new instance of the class. + /// + public Expression() + { + } + + /// + /// Create a new instance from SerializationInfo + /// + protected Expression(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + + /// + /// Evaluates this expression for the specified root object and returns + /// value of the last node. + /// + /// Context to evaluate expressions against. + /// Current expression evaluation context. + /// Value of the last node. + protected override object Get(object context, EvaluationContext evalContext) + { + object result = context; + + if (this.getNumberOfChildren() > 0) + { + AST node = this.getFirstChild(); + while (node != null) + { + result = GetValue(((BaseNode) node), result, evalContext); + + node = node.getNextSibling(); + } + } + + return result; + } + + /// + /// Evaluates this expression for the specified root object and sets + /// value of the last node. + /// + /// Context to evaluate expressions against. + /// Current expression evaluation context. + /// Value to set last node to. + /// If navigation expression is empty. + protected override void Set(object context, EvaluationContext evalContext, object newValue) + { + object target = context; + + if (this.getNumberOfChildren() > 0) + { + AST node = this.getFirstChild(); + + for (int i = 0; i < this.getNumberOfChildren() - 1; i++) + { + try + { + target = GetValue(((BaseNode) node), target, evalContext); + node = node.getNextSibling(); + } + catch (NotReadablePropertyException e) + { + throw new NotWritablePropertyException("Cannot read the value of '" + node.getText() + "' property in the expression.", e); + } + } + + SetValue(((BaseNode) node), target, evalContext, newValue); + } + else + { + throw new NotSupportedException("You cannot set the value for an empty expression."); + } + } + + /// + /// Evaluates this expression for the specified root object and returns + /// of the last node, if possible. + /// + /// Context to evaluate expression against. + /// Expression variables map. + /// Value of the last node. + internal PropertyInfo GetPropertyInfo(object context, IDictionary variables) + { + if (this.getNumberOfChildren() > 0) + { + object target = context; + AST node = this.getFirstChild(); + + for (int i = 0; i < this.getNumberOfChildren() - 1; i++) + { + target = ((IExpression) node).GetValue(target, variables); + node = node.getNextSibling(); + } + + if (node is PropertyOrFieldNode) + { + return (PropertyInfo) ((PropertyOrFieldNode) node).GetMemberInfo(target); + } + else if (node is IndexerNode) + { + return ((IndexerNode) node).GetPropertyInfo(target, variables); + } + else + { + throw new FatalReflectionException("Cannot obtain PropertyInfo from an expression that does not resolve to a property or an indexer."); + } + } + + throw new FatalReflectionException("Cannot obtain PropertyInfo for empty property name."); + } } diff --git a/src/Spring/Spring.Core/Expressions/ExpressionConverter.cs b/src/Spring/Spring.Core/Expressions/ExpressionConverter.cs index 96c8bf20..12034c2b 100644 --- a/src/Spring/Spring.Core/Expressions/ExpressionConverter.cs +++ b/src/Spring/Spring.Core/Expressions/ExpressionConverter.cs @@ -21,59 +21,58 @@ using System.ComponentModel; using System.Globalization; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// Converts string representation of expression into an instance of . +/// +/// Aleksandar Seovic +public class ExpressionConverter : TypeConverter { /// - /// Converts string representation of expression into an instance of . + /// Can we convert from a the sourcetype to a ? /// - /// Aleksandar Seovic - public class ExpressionConverter : TypeConverter + /// + ///

+ /// Currently only supports conversion from a instance. + ///

+ ///
+ /// + /// A + /// that provides a format context. + /// + /// + /// A that represents the + /// you want to convert from. + /// + /// if the conversion is possible. + public override bool CanConvertFrom( + ITypeDescriptorContext context, Type sourceType) { - /// - /// Can we convert from a the sourcetype to a ? - /// - /// - ///

- /// Currently only supports conversion from a instance. - ///

- ///
- /// - /// A - /// that provides a format context. - /// - /// - /// A that represents the - /// you want to convert from. - /// - /// if the conversion is possible. - public override bool CanConvertFrom( - ITypeDescriptorContext context, Type sourceType) - { - return (sourceType == typeof(string)); - } + return (sourceType == typeof(string)); + } - /// - /// Convert from a value to an - /// instance. - /// - /// - /// A - /// that provides a format context. - /// - /// - /// The to use - /// as the current culture. - /// - /// - /// The value that is to be converted. - /// - /// - /// A array if successful. - /// - public override object ConvertFrom( - ITypeDescriptorContext context, CultureInfo culture, object value) - { - return Expression.Parse(value as string); - } + /// + /// Convert from a value to an + /// instance. + /// + /// + /// A + /// that provides a format context. + /// + /// + /// The to use + /// as the current culture. + /// + /// + /// The value that is to be converted. + /// + /// + /// A array if successful. + /// + public override object ConvertFrom( + ITypeDescriptorContext context, CultureInfo culture, object value) + { + return Expression.Parse(value as string); } } diff --git a/src/Spring/Spring.Core/Expressions/ExpressionEvaluator.cs b/src/Spring/Spring.Core/Expressions/ExpressionEvaluator.cs index 92768c1b..0df2e90b 100644 --- a/src/Spring/Spring.Core/Expressions/ExpressionEvaluator.cs +++ b/src/Spring/Spring.Core/Expressions/ExpressionEvaluator.cs @@ -18,82 +18,81 @@ #endregion -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// Utility class that enables easy expression evaluation. +/// +/// +///

+/// This class allows users to get or set properties, execute methods, and evaluate +/// logical and arithmetic expressions. +///

+///

+/// Methods in this class parse expression on every invocation. +/// If you plan to reuse the same expression many times, you should prepare +/// the expression once using the static method, +/// and then call to evaluate it. +///

+///

+/// This can result in significant performance improvements as it avoids expression +/// parsing and node resolution every time it is called. +///

+///

+///

+///
+/// Aleksandar Seovic +public class ExpressionEvaluator { /// - /// Utility class that enables easy expression evaluation. + /// Parses and evaluates specified expression. /// - /// - ///

- /// This class allows users to get or set properties, execute methods, and evaluate - /// logical and arithmetic expressions. - ///

- ///

- /// Methods in this class parse expression on every invocation. - /// If you plan to reuse the same expression many times, you should prepare - /// the expression once using the static method, - /// and then call to evaluate it. - ///

- ///

- /// This can result in significant performance improvements as it avoids expression - /// parsing and node resolution every time it is called. - ///

- ///

- ///

- ///
- /// Aleksandar Seovic - public class ExpressionEvaluator + /// Root object. + /// Expression to evaluate. + /// Value of the last node in the expression. + public static object GetValue(object root, string expression) { - /// - /// Parses and evaluates specified expression. - /// - /// Root object. - /// Expression to evaluate. - /// Value of the last node in the expression. - public static object GetValue(object root, string expression) - { - IExpression exp = Expression.Parse(expression); - return exp.GetValue(root, null); - } + IExpression exp = Expression.Parse(expression); + return exp.GetValue(root, null); + } - /// - /// Parses and evaluates specified expression. - /// - /// Root object. - /// Expression to evaluate. - /// Expression variables map. - /// Value of the last node in the expression. - public static object GetValue(object root, string expression, IDictionary variables) - { - IExpression exp = Expression.Parse(expression); - return exp.GetValue(root, variables); - } + /// + /// Parses and evaluates specified expression. + /// + /// Root object. + /// Expression to evaluate. + /// Expression variables map. + /// Value of the last node in the expression. + public static object GetValue(object root, string expression, IDictionary variables) + { + IExpression exp = Expression.Parse(expression); + return exp.GetValue(root, variables); + } - /// - /// Parses and specified expression and sets the value of the - /// last node to the value of the newValue parameter. - /// - /// Root object. - /// Expression to evaluate. - /// Value to set last node to. - public static void SetValue(object root, string expression, object newValue) - { - IExpression exp = Expression.Parse(expression); - exp.SetValue(root, null, newValue); - } + /// + /// Parses and specified expression and sets the value of the + /// last node to the value of the newValue parameter. + /// + /// Root object. + /// Expression to evaluate. + /// Value to set last node to. + public static void SetValue(object root, string expression, object newValue) + { + IExpression exp = Expression.Parse(expression); + exp.SetValue(root, null, newValue); + } - /// - /// Parses and specified expression and sets the value of the - /// last node to the value of the newValue parameter. - /// - /// Root object. - /// Expression to evaluate. - /// Expression variables map. - /// Value to set last node to. - public static void SetValue(object root, string expression, IDictionary variables, object newValue) - { - IExpression exp = Expression.Parse(expression); - exp.SetValue(root, variables, newValue); - } + /// + /// Parses and specified expression and sets the value of the + /// last node to the value of the newValue parameter. + /// + /// Root object. + /// Expression to evaluate. + /// Expression variables map. + /// Value to set last node to. + public static void SetValue(object root, string expression, IDictionary variables, object newValue) + { + IExpression exp = Expression.Parse(expression); + exp.SetValue(root, variables, newValue); } } diff --git a/src/Spring/Spring.Core/Expressions/ExpressionListNode.cs b/src/Spring/Spring.Core/Expressions/ExpressionListNode.cs index cb69aa86..1a2d0d7f 100644 --- a/src/Spring/Spring.Core/Expressions/ExpressionListNode.cs +++ b/src/Spring/Spring.Core/Expressions/ExpressionListNode.cs @@ -21,47 +21,47 @@ using System.Runtime.Serialization; using Spring.Expressions.Parser.antlr.collections; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// Represents parsed expression list node in the navigation expression. +/// +/// Aleksandar Seovic +[Serializable] +public class ExpressionListNode : BaseNode { /// - /// Represents parsed expression list node in the navigation expression. + /// Create a new instance /// - /// Aleksandar Seovic - [Serializable] - public class ExpressionListNode : BaseNode + public ExpressionListNode() { - /// - /// Create a new instance - /// - public ExpressionListNode() + } + + /// + /// Create a new instance from SerializationInfo + /// + protected ExpressionListNode(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + + /// + /// Returns a result of the last expression in a list. + /// + /// Context to evaluate expressions against. + /// Current expression evaluation context. + /// Result of the last expression in a list + protected override object Get(object context, EvaluationContext evalContext) + { + object result = context; + + AST node = this.getFirstChild(); + while (node != null) { + result = GetValue(((BaseNode) node), context, evalContext); + node = node.getNextSibling(); } - /// - /// Create a new instance from SerializationInfo - /// - protected ExpressionListNode(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } - - /// - /// Returns a result of the last expression in a list. - /// - /// Context to evaluate expressions against. - /// Current expression evaluation context. - /// Result of the last expression in a list - protected override object Get(object context, EvaluationContext evalContext) - { - object result = context; - - AST node = this.getFirstChild(); - while (node != null) - { - result = GetValue(((BaseNode) node), context, evalContext); - node = node.getNextSibling(); - } - return result; - } + return result; } } diff --git a/src/Spring/Spring.Core/Expressions/FunctionNode.cs b/src/Spring/Spring.Core/Expressions/FunctionNode.cs index 65d7e15a..9876dc8c 100644 --- a/src/Spring/Spring.Core/Expressions/FunctionNode.cs +++ b/src/Spring/Spring.Core/Expressions/FunctionNode.cs @@ -21,75 +21,75 @@ using System.Runtime.Serialization; using Spring.Reflection.Dynamic; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// Represents parsed function node. +/// +/// Aleksandar Seovic +[Serializable] +public class FunctionNode : NodeWithArguments { /// - /// Represents parsed function node. + /// Create a new instance /// - /// Aleksandar Seovic - [Serializable] - public class FunctionNode : NodeWithArguments + public FunctionNode() { - /// - /// Create a new instance - /// - public FunctionNode() + } + + /// + /// Create a new instance from SerializationInfo + /// + protected FunctionNode(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + + /// + /// Evaluates function represented by this node. + /// + /// Context to evaluate expressions against. + /// Current expression evaluation context. + /// Result of the function evaluation. + protected override object Get(object context, EvaluationContext evalContext) + { + string name = this.getText(); + + object[] argValues = ResolveArguments(evalContext); + + object function = evalContext.Variables[name]; + + // delegate? + Delegate callback = function as Delegate; + if (callback != null) { + return InvokeDelegate(callback, argValues); } - /// - /// Create a new instance from SerializationInfo - /// - protected FunctionNode(SerializationInfo info, StreamingContext context) - : base(info, context) + // lambda? + LambdaExpressionNode lambda = function as LambdaExpressionNode; + if (lambda != null) { - } - - /// - /// Evaluates function represented by this node. - /// - /// Context to evaluate expressions against. - /// Current expression evaluation context. - /// Result of the function evaluation. - protected override object Get(object context, EvaluationContext evalContext) - { - string name = this.getText(); - - object[] argValues = ResolveArguments(evalContext); - - object function = evalContext.Variables[name]; - - // delegate? - Delegate callback = function as Delegate; - if (callback != null) + try { - return InvokeDelegate(callback, argValues); + return GetValueWithArguments(lambda, context, evalContext, argValues); } - - // lambda? - LambdaExpressionNode lambda = function as LambdaExpressionNode; - if (lambda != null) + catch (ArgumentMismatchException ame) { - try - { - return GetValueWithArguments(lambda, context, evalContext, argValues); - } - catch (ArgumentMismatchException ame) - { - throw new InvalidOperationException( "Failed executing function " + name + ": " + ame.Message ); - } + throw new InvalidOperationException("Failed executing function " + name + ": " + ame.Message); } - - if (function == null) - { - throw new InvalidOperationException("Function '" + name + "' is not defined."); - } - throw new InvalidOperationException("Function '" + name + "' is defined but of unknown type."); } - private object InvokeDelegate(Delegate callback, object[] arguments) + if (function == null) { - return new SafeMethod(callback.Method).Invoke(callback.Target, arguments); + throw new InvalidOperationException("Function '" + name + "' is not defined."); } + + throw new InvalidOperationException("Function '" + name + "' is defined but of unknown type."); + } + + private object InvokeDelegate(Delegate callback, object[] arguments) + { + return new SafeMethod(callback.Method).Invoke(callback.Target, arguments); } } diff --git a/src/Spring/Spring.Core/Expressions/HexLiteralNode.cs b/src/Spring/Spring.Core/Expressions/HexLiteralNode.cs index d98db485..43e91a39 100644 --- a/src/Spring/Spring.Core/Expressions/HexLiteralNode.cs +++ b/src/Spring/Spring.Core/Expressions/HexLiteralNode.cs @@ -21,60 +21,59 @@ using System.Globalization; using System.Runtime.Serialization; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// Represents parsed hexadecimal integer literal node. +/// +/// Aleksandar Seovic +[Serializable] +public class HexLiteralNode : BaseNode { + private object nodeValue; + /// - /// Represents parsed hexadecimal integer literal node. + /// Create a new instance /// - /// Aleksandar Seovic - [Serializable] - public class HexLiteralNode : BaseNode + public HexLiteralNode() { - private object nodeValue; + } - /// - /// Create a new instance - /// - public HexLiteralNode() - { - } + /// + /// Create a new instance from SerializationInfo + /// + protected HexLiteralNode(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } - /// - /// Create a new instance from SerializationInfo - /// - protected HexLiteralNode(SerializationInfo info, StreamingContext context) - : base(info, context) + /// + /// Returns a value for the hexadecimal integer literal node. + /// + /// Context to evaluate expressions against. + /// Current expression evaluation context. + /// Node's value. + protected override object Get(object context, EvaluationContext evalContext) + { + if (nodeValue == null) { - } - - /// - /// Returns a value for the hexadecimal integer literal node. - /// - /// Context to evaluate expressions against. - /// Current expression evaluation context. - /// Node's value. - protected override object Get(object context, EvaluationContext evalContext) - { - if (nodeValue == null) + lock (this) { - lock (this) + if (nodeValue == null) { - if (nodeValue == null) + string n = this.getText(); + try { - string n = this.getText(); - try - { - nodeValue = Int32.Parse(n.Substring(2), NumberStyles.HexNumber); - } - catch (OverflowException) - { - nodeValue = Int64.Parse(n.Substring(2), NumberStyles.HexNumber); - } + nodeValue = Int32.Parse(n.Substring(2), NumberStyles.HexNumber); + } + catch (OverflowException) + { + nodeValue = Int64.Parse(n.Substring(2), NumberStyles.HexNumber); } } } - - return nodeValue; } + + return nodeValue; } } diff --git a/src/Spring/Spring.Core/Expressions/IExpression.cs b/src/Spring/Spring.Core/Expressions/IExpression.cs index b97ab1a4..5c8bee0b 100644 --- a/src/Spring/Spring.Core/Expressions/IExpression.cs +++ b/src/Spring/Spring.Core/Expressions/IExpression.cs @@ -20,49 +20,48 @@ using System.ComponentModel; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// Interface that all navigation expression nodes have to implement. +/// +/// Aleksandar Seovic +[TypeConverter(typeof(ExpressionConverter))] +public interface IExpression { /// - /// Interface that all navigation expression nodes have to implement. + /// Returns expression value. /// - /// Aleksandar Seovic - [TypeConverter(typeof(ExpressionConverter))] - public interface IExpression - { - /// - /// Returns expression value. - /// - /// Value of the expression. - object GetValue(); + /// Value of the expression. + object GetValue(); - /// - /// Returns expression value. - /// - /// Object to evaluate expression against. - /// Value of the expression. - object GetValue(object context); + /// + /// Returns expression value. + /// + /// Object to evaluate expression against. + /// Value of the expression. + object GetValue(object context); - /// - /// Returns expression value. - /// - /// Object to evaluate expression against. - /// Expression variables map. - /// Value of the expression. - object GetValue(object context, IDictionary variables); + /// + /// Returns expression value. + /// + /// Object to evaluate expression against. + /// Expression variables map. + /// Value of the expression. + object GetValue(object context, IDictionary variables); - /// - /// Sets expression value. - /// - /// Object to evaluate expression against. - /// New value for the last node of the expression. - void SetValue(object context, object newValue); + /// + /// Sets expression value. + /// + /// Object to evaluate expression against. + /// New value for the last node of the expression. + void SetValue(object context, object newValue); - /// - /// Sets expression value. - /// - /// Object to evaluate expression against. - /// Expression variables map. - /// New value for the last node of the expression. - void SetValue(object context, IDictionary variables, object newValue); - } + /// + /// Sets expression value. + /// + /// Object to evaluate expression against. + /// Expression variables map. + /// New value for the last node of the expression. + void SetValue(object context, IDictionary variables, object newValue); } diff --git a/src/Spring/Spring.Core/Expressions/IndexerNode.cs b/src/Spring/Spring.Core/Expressions/IndexerNode.cs index 36c5a79e..88669d82 100644 --- a/src/Spring/Spring.Core/Expressions/IndexerNode.cs +++ b/src/Spring/Spring.Core/Expressions/IndexerNode.cs @@ -25,273 +25,274 @@ using Spring.Core; using Spring.Util; using Spring.Reflection.Dynamic; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// Represents parsed indexer node in the navigation expression. +/// +/// Aleksandar Seovic +[Serializable] +public class IndexerNode : NodeWithArguments { + private const BindingFlags BINDING_FLAGS + = BindingFlags.Public | BindingFlags.NonPublic + | BindingFlags.Instance | BindingFlags.Static + | BindingFlags.IgnoreCase; + + private SafeProperty indexer; + /// - /// Represents parsed indexer node in the navigation expression. + /// Create a new instance /// - /// Aleksandar Seovic - [Serializable] - public class IndexerNode : NodeWithArguments + public IndexerNode() { - private const BindingFlags BINDING_FLAGS - = BindingFlags.Public | BindingFlags.NonPublic - | BindingFlags.Instance | BindingFlags.Static - | BindingFlags.IgnoreCase; + } - private SafeProperty indexer; + /// + /// Create a new instance from SerializationInfo + /// + protected IndexerNode(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } - /// - /// Create a new instance - /// - public IndexerNode() + /// + /// Returns node's value for the given context. + /// + /// Context to evaluate expressions against. + /// Current expression evaluation context. + /// Node's value. + protected override object Get(object context, EvaluationContext evalContext) + { + if (context == null) { + throw new NullValueInNestedPathException("Cannot retrieve the value of the indexer because the context for its resolution is null."); } - /// - /// Create a new instance from SerializationInfo - /// - protected IndexerNode(SerializationInfo info, StreamingContext context) - : base(info, context) + try { - } - - /// - /// Returns node's value for the given context. - /// - /// Context to evaluate expressions against. - /// Current expression evaluation context. - /// Node's value. - protected override object Get(object context, EvaluationContext evalContext) - { - if (context == null) + if (context is Array) { - throw new NullValueInNestedPathException("Cannot retrieve the value of the indexer because the context for its resolution is null."); + return GetArrayValue((Array) context, evalContext); } - - try + else if (context is IList) { - if (context is Array) - { - return GetArrayValue( (Array) context, evalContext ); - } - else if (context is IList) - { - return GetListValue( (IList) context, evalContext ); - } - else if (context is IDictionary) - { - return GetDictionaryValue( (IDictionary) context, evalContext ); - } - else if (context is string) - { - return GetCharacter( (string) context, evalContext ); - } - else - { - return GetGenericIndexer( context, evalContext ); - } + return GetListValue((IList) context, evalContext); } - catch (TargetInvocationException e) + else if (context is IDictionary) { - throw new InvalidPropertyException(evalContext.RootContextType, this.ToString(), "Getter for indexer threw an exception.", e); + return GetDictionaryValue((IDictionary) context, evalContext); } - catch (UnauthorizedAccessException e) + else if (context is string) { - throw new InvalidPropertyException( evalContext.RootContextType,this.ToString(),"Illegal attempt to get value for the indexer.",e ); + return GetCharacter((string) context, evalContext); } - catch (IndexOutOfRangeException e) + else { - throw new InvalidPropertyException( evalContext.RootContextType,this.ToString(),"Index out of range.",e ); - } - catch (ArgumentOutOfRangeException e) - { - throw new InvalidPropertyException( evalContext.RootContextType,this.ToString(),"Argument out of range.",e ); - } - catch (InvalidCastException e) - { - throw new InvalidPropertyException( evalContext.RootContextType,this.ToString(),"Invalid index type.",e ); - } - catch (ArgumentException e) - { - throw new InvalidPropertyException( evalContext.RootContextType,this.ToString(),"Invalid argument.",e ); + return GetGenericIndexer(context, evalContext); } } - - /// - /// Sets node's value for the given context. - /// - /// Context to evaluate expressions against. - /// Current expression evaluation context. - /// New value for this node. - protected override void Set(object context, EvaluationContext evalContext, object newValue) + catch (TargetInvocationException e) { - if (context == null) - { - throw new NullValueInNestedPathException("Cannot set the value of the indexer because the context for its resolution is null."); - } - - try - { - if (context is Array) - { - SetArrayValue( (Array) context, evalContext,newValue ); - } - else if (context is IList) - { - SetListValue( (IList) context, evalContext,newValue ); - } - else if (context is IDictionary) - { - SetDictionaryValue( (IDictionary) context, evalContext,newValue ); - } - else - { - SetGenericIndexer( context, evalContext,newValue ); - } - } - catch (TargetInvocationException e) - { - throw new InvalidPropertyException( evalContext.RootContextType,this.ToString(),"Setter for indexer threw an exception.",e ); - } - catch (UnauthorizedAccessException e) - { - throw new InvalidPropertyException( evalContext.RootContextType,this.ToString(),"Illegal attempt to set value for the indexer.",e ); - } - catch (IndexOutOfRangeException e) - { - throw new InvalidPropertyException( evalContext.RootContextType,this.ToString(),"Index out of range.",e ); - } - catch (ArgumentOutOfRangeException e) - { - throw new InvalidPropertyException( evalContext.RootContextType,this.ToString(),"Argument out of range.",e ); - } - catch (InvalidCastException e) - { - throw new InvalidPropertyException( evalContext.RootContextType,this.ToString(),"Invalid index type.",e ); - } - catch (ArgumentException e) - { - throw new InvalidPropertyException( evalContext.RootContextType,this.ToString(),"Invalid argument.",e ); - } + throw new InvalidPropertyException(evalContext.RootContextType, this.ToString(), "Getter for indexer threw an exception.", e); + } + catch (UnauthorizedAccessException e) + { + throw new InvalidPropertyException(evalContext.RootContextType, this.ToString(), "Illegal attempt to get value for the indexer.", e); + } + catch (IndexOutOfRangeException e) + { + throw new InvalidPropertyException(evalContext.RootContextType, this.ToString(), "Index out of range.", e); + } + catch (ArgumentOutOfRangeException e) + { + throw new InvalidPropertyException(evalContext.RootContextType, this.ToString(), "Argument out of range.", e); + } + catch (InvalidCastException e) + { + throw new InvalidPropertyException(evalContext.RootContextType, this.ToString(), "Invalid index type.", e); + } + catch (ArgumentException e) + { + throw new InvalidPropertyException(evalContext.RootContextType, this.ToString(), "Invalid argument.", e); + } + } + /// + /// Sets node's value for the given context. + /// + /// Context to evaluate expressions against. + /// Current expression evaluation context. + /// New value for this node. + protected override void Set(object context, EvaluationContext evalContext, object newValue) + { + if (context == null) + { + throw new NullValueInNestedPathException("Cannot set the value of the indexer because the context for its resolution is null."); } - /// - /// Utility method that is needed by ObjectWrapper and AbstractAutowireCapableObjectFactory. - /// - /// Context to resolve property against. - /// Expression variables map. - /// PropertyInfo for this node. - internal PropertyInfo GetPropertyInfo(object context, IDictionary variables) + try + { + if (context is Array) + { + SetArrayValue((Array) context, evalContext, newValue); + } + else if (context is IList) + { + SetListValue((IList) context, evalContext, newValue); + } + else if (context is IDictionary) + { + SetDictionaryValue((IDictionary) context, evalContext, newValue); + } + else + { + SetGenericIndexer(context, evalContext, newValue); + } + } + catch (TargetInvocationException e) + { + throw new InvalidPropertyException(evalContext.RootContextType, this.ToString(), "Setter for indexer threw an exception.", e); + } + catch (UnauthorizedAccessException e) + { + throw new InvalidPropertyException(evalContext.RootContextType, this.ToString(), "Illegal attempt to set value for the indexer.", e); + } + catch (IndexOutOfRangeException e) + { + throw new InvalidPropertyException(evalContext.RootContextType, this.ToString(), "Index out of range.", e); + } + catch (ArgumentOutOfRangeException e) + { + throw new InvalidPropertyException(evalContext.RootContextType, this.ToString(), "Argument out of range.", e); + } + catch (InvalidCastException e) + { + throw new InvalidPropertyException(evalContext.RootContextType, this.ToString(), "Invalid index type.", e); + } + catch (ArgumentException e) + { + throw new InvalidPropertyException(evalContext.RootContextType, this.ToString(), "Invalid argument.", e); + } + } + + /// + /// Utility method that is needed by ObjectWrapper and AbstractAutowireCapableObjectFactory. + /// + /// Context to resolve property against. + /// Expression variables map. + /// PropertyInfo for this node. + internal PropertyInfo GetPropertyInfo(object context, IDictionary variables) + { + lock (this) + { + EvaluationContext evalContext = new EvaluationContext(context, variables); + InitializeIndexerProperty(context, evalContext); + + return indexer.PropertyInfo; + } + } + + private object GetArrayValue(Array array, EvaluationContext evalContext) + { + int argCount = array.Rank; + AssertArgumentCount(argCount); + + Int32[] indices = new Int32[argCount]; + for (int i = 0; i < argCount; i++) + { + indices[i] = (Int32) ResolveArgument(i, evalContext); + } + + return array.GetValue(indices); + } + + private object GetListValue(IList list, EvaluationContext evalContext) + { + AssertArgumentCount(1); + return list[(int) ResolveArgument(0, evalContext)]; + } + + private object GetDictionaryValue(IDictionary dictionary, EvaluationContext evalContext) + { + AssertArgumentCount(1); + return dictionary[ResolveArgument(0, evalContext)]; + } + + private object GetCharacter(string character, EvaluationContext evalContext) + { + AssertArgumentCount(1); + return character[(int) ResolveArgument(0, evalContext)]; + } + + private object GetGenericIndexer(object context, EvaluationContext evalContext) + { + object[] indices = InitializeIndexerProperty(context, evalContext); + return indexer.GetValue(context, indices); + } + + private void SetArrayValue(Array array, EvaluationContext evalContext, object newValue) + { + int argCount = array.Rank; + AssertArgumentCount(argCount); + + Int32[] indices = new Int32[argCount]; + for (int i = 0; i < argCount; i++) + { + indices[i] = (Int32) ResolveArgument(i, evalContext); + } + + array.SetValue(newValue, indices); + } + + private void SetListValue(IList list, EvaluationContext evalContext, object newValue) + { + AssertArgumentCount(1); + list[(int) ResolveArgument(0, evalContext)] = newValue; + } + + private void SetDictionaryValue(IDictionary dictionary, EvaluationContext evalContext, object newValue) + { + AssertArgumentCount(1); + dictionary[ResolveArgument(0, evalContext)] = newValue; + } + + private void SetGenericIndexer(object context, EvaluationContext evalContext, object newValue) + { + object[] indices = InitializeIndexerProperty(context, evalContext); + indexer.SetValue(context, newValue, indices); + } + + private object[] InitializeIndexerProperty(object context, EvaluationContext evalContext) + { + object[] indices = ResolveArguments(evalContext); + + if (indexer == null) { lock (this) { - EvaluationContext evalContext = new EvaluationContext(context, variables); - InitializeIndexerProperty(context, evalContext); - - return indexer.PropertyInfo; - } - } - - private object GetArrayValue(Array array, EvaluationContext evalContext) - { - int argCount = array.Rank; - AssertArgumentCount(argCount); - - Int32[] indices = new Int32[argCount]; - for (int i = 0; i < argCount; i++) - { - indices[i] = (Int32) ResolveArgument(i, evalContext); - } - return array.GetValue(indices); - } - - private object GetListValue(IList list, EvaluationContext evalContext) - { - AssertArgumentCount(1); - return list[(int) ResolveArgument(0, evalContext)]; - } - - private object GetDictionaryValue(IDictionary dictionary, EvaluationContext evalContext) - { - AssertArgumentCount(1); - return dictionary[ResolveArgument( 0,evalContext )]; - } - - private object GetCharacter(string character, EvaluationContext evalContext) - { - AssertArgumentCount(1); - return character[(int)ResolveArgument( 0,evalContext )]; - } - - private object GetGenericIndexer(object context, EvaluationContext evalContext) - { - object[] indices = InitializeIndexerProperty( context, evalContext ); - return indexer.GetValue(context, indices); - } - - private void SetArrayValue(Array array, EvaluationContext evalContext,object newValue) - { - int argCount = array.Rank; - AssertArgumentCount(argCount); - - Int32[] indices = new Int32[argCount]; - for (int i = 0; i < argCount; i++) - { - indices[i] = (Int32) ResolveArgument(i, evalContext); - } - array.SetValue(newValue, indices); - } - - private void SetListValue(IList list, EvaluationContext evalContext,object newValue) - { - AssertArgumentCount(1); - list[(int) ResolveArgument(0, evalContext)] = newValue; - } - - private void SetDictionaryValue(IDictionary dictionary, EvaluationContext evalContext,object newValue) - { - AssertArgumentCount(1); - dictionary[ResolveArgument( 0,evalContext )] = newValue; - } - - private void SetGenericIndexer(object context, EvaluationContext evalContext,object newValue) - { - object[] indices = InitializeIndexerProperty( context, evalContext ); - indexer.SetValue( context, newValue, indices ); - } - - private object[] InitializeIndexerProperty(object context, EvaluationContext evalContext) - { - object[] indices = ResolveArguments( evalContext ); - - if (indexer == null) - { - lock (this) + if (indexer == null) { - if (indexer == null) + Type contextType = context.GetType(); + Type[] argTypes = ReflectionUtils.GetTypes(indices); + string defaultMember = "Item"; + object[] atts = contextType.GetCustomAttributes(typeof(DefaultMemberAttribute), true); + if (atts != null && atts.Length > 0) { - Type contextType = context.GetType(); - Type[] argTypes = ReflectionUtils.GetTypes(indices); - string defaultMember = "Item"; - object[] atts = contextType.GetCustomAttributes(typeof(DefaultMemberAttribute), true); - if (atts != null && atts.Length > 0) - { - defaultMember = ((DefaultMemberAttribute) atts[0]).MemberName; - } - PropertyInfo indexerProperty = contextType.GetProperty(defaultMember, BINDING_FLAGS, null, null, argTypes, null); - if (indexerProperty == null) - { - throw new ArgumentException("Indexer property with specified number and types of arguments does not exist."); - } - - indexer = new SafeProperty(indexerProperty); + defaultMember = ((DefaultMemberAttribute) atts[0]).MemberName; } + + PropertyInfo indexerProperty = contextType.GetProperty(defaultMember, BINDING_FLAGS, null, null, argTypes, null); + if (indexerProperty == null) + { + throw new ArgumentException("Indexer property with specified number and types of arguments does not exist."); + } + + indexer = new SafeProperty(indexerProperty); } } - - return indices; } + + return indices; } } diff --git a/src/Spring/Spring.Core/Expressions/IntLiteralNode.cs b/src/Spring/Spring.Core/Expressions/IntLiteralNode.cs index 8a65f4c9..eec37b82 100644 --- a/src/Spring/Spring.Core/Expressions/IntLiteralNode.cs +++ b/src/Spring/Spring.Core/Expressions/IntLiteralNode.cs @@ -20,68 +20,67 @@ using System.Runtime.Serialization; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// Represents parsed integer literal node. +/// +/// Aleksandar Seovic +[Serializable] +public class IntLiteralNode : BaseNode { + private object nodeValue; + /// - /// Represents parsed integer literal node. + /// Create a new instance /// - /// Aleksandar Seovic - [Serializable] - public class IntLiteralNode : BaseNode + public IntLiteralNode() { - private object nodeValue; + } - /// - /// Create a new instance - /// - public IntLiteralNode() - { - } + /// + /// Create a new instance + /// + public IntLiteralNode(string text) + { + this.Text = text; + } - /// - /// Create a new instance - /// - public IntLiteralNode(string text) - { - this.Text = text; - } + /// + /// Create a new instance from SerializationInfo + /// + protected IntLiteralNode(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } - /// - /// Create a new instance from SerializationInfo - /// - protected IntLiteralNode(SerializationInfo info, StreamingContext context) - : base(info, context) + /// + /// Returns a value for the integer literal node. + /// + /// Context to evaluate expressions against. + /// Current expression evaluation context. + /// Node's value. + protected override object Get(object context, EvaluationContext evalContext) + { + if (nodeValue == null) { - } - - /// - /// Returns a value for the integer literal node. - /// - /// Context to evaluate expressions against. - /// Current expression evaluation context. - /// Node's value. - protected override object Get(object context, EvaluationContext evalContext) - { - if (nodeValue == null) + lock (this) { - lock (this) + if (nodeValue == null) { - if (nodeValue == null) + string n = this.getText(); + try { - string n = this.getText(); - try - { - nodeValue = Int32.Parse(n); - } - catch (OverflowException) - { - nodeValue = Int64.Parse(n); - } + nodeValue = Int32.Parse(n); + } + catch (OverflowException) + { + nodeValue = Int64.Parse(n); } } } - - return nodeValue; } + + return nodeValue; } } diff --git a/src/Spring/Spring.Core/Expressions/LambdaExpressionNode.cs b/src/Spring/Spring.Core/Expressions/LambdaExpressionNode.cs index 3e1656af..cc8e28e3 100644 --- a/src/Spring/Spring.Core/Expressions/LambdaExpressionNode.cs +++ b/src/Spring/Spring.Core/Expressions/LambdaExpressionNode.cs @@ -22,125 +22,125 @@ using System.Collections; using System.Runtime.Serialization; using Spring.Expressions.Parser.antlr.collections; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// Represents lambda expression. +/// +/// Aleksandar Seovic +[Serializable] +public class LambdaExpressionNode : BaseNode { /// - /// Represents lambda expression. + /// caches argumentNames of this instance /// - /// Aleksandar Seovic - [Serializable] - public class LambdaExpressionNode : BaseNode + private string[] argumentNames; + + /// + /// caches body expression of this lambda function + /// + private BaseNode bodyExpression; + + /// + /// Create a new instance + /// + public LambdaExpressionNode() { - /// - /// caches argumentNames of this instance - /// - private string[] argumentNames; + } - /// - /// caches body expression of this lambda function - /// - private BaseNode bodyExpression; + /// + /// Create a new instance from SerializationInfo + /// + protected LambdaExpressionNode(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } - /// - /// Create a new instance - /// - public LambdaExpressionNode() + /// + /// Gets argument names for this lambda expression. + /// + public string[] ArgumentNames + { + get { - } - - /// - /// Create a new instance from SerializationInfo - /// - protected LambdaExpressionNode(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } - - /// - /// Gets argument names for this lambda expression. - /// - public string[] ArgumentNames - { - get - { - if(bodyExpression == null) - { - InitializeLambda(); - } - return argumentNames; - } - } - - /// - /// Assigns value of the right operand to the left one. - /// - /// Context to evaluate expressions against. - /// Current expression evaluation context. - /// Node's value. - protected override object Get(object context, EvaluationContext evalContext) - { - if(bodyExpression == null) + if (bodyExpression == null) { InitializeLambda(); } - object result = GetValue(bodyExpression, context, evalContext); + return argumentNames; + } + } + + /// + /// Assigns value of the right operand to the left one. + /// + /// Context to evaluate expressions against. + /// Current expression evaluation context. + /// Node's value. + protected override object Get(object context, EvaluationContext evalContext) + { + if (bodyExpression == null) + { + InitializeLambda(); + } + + object result = GetValue(bodyExpression, context, evalContext); + return result; + } + + /// + /// Evaluates this node, switching local variables map to the ones specified in . + /// + protected override object Get(object context, EvaluationContext evalContext, object[] argValues) + { + string[] argNames = this.ArgumentNames; + + if (argValues.Length != argNames.Length) + { + throw new ArgumentMismatchException(string.Format("Invalid number of arguments - expected {0} arguments, but was called with {1}", argNames.Length, argValues.Length)); + } + + IDictionary arguments = new Hashtable(); + for (int i = 0; i < argValues.Length; i++) + { + arguments[argNames[i]] = argValues[i]; + } + + EvaluationContext ec = evalContext; + using (ec.SwitchLocalVariables(arguments)) + { + object result = Get(context, ec); return result; } + } - /// - /// Evaluates this node, switching local variables map to the ones specified in . - /// - protected override object Get(object context, EvaluationContext evalContext, object[] argValues) + private void InitializeLambda() + { + lock (this) { - string[] argNames = this.ArgumentNames; - - if (argValues.Length != argNames.Length) + if (bodyExpression == null) { - throw new ArgumentMismatchException(string.Format("Invalid number of arguments - expected {0} arguments, but was called with {1}", argNames.Length, argValues.Length)); - } - - IDictionary arguments = new Hashtable(); - for (int i = 0; i < argValues.Length; i++) - { - arguments[argNames[i]] = argValues[i]; - } - - EvaluationContext ec = evalContext; - using (ec.SwitchLocalVariables(arguments)) - { - object result = Get(context, ec); - return result; - } - } - - private void InitializeLambda() - { - lock (this) - { - if (bodyExpression == null) + if (this.getNumberOfChildren() == 1) { - if (this.getNumberOfChildren() == 1) + argumentNames = new string[0]; + bodyExpression = (BaseNode) this.getFirstChild(); + } + else + { + AST argsNode = this.getFirstChild(); + argumentNames = new string[argsNode.getNumberOfChildren()]; + AST argNode = argsNode.getFirstChild(); + int i = 0; + while (argNode != null) { - argumentNames = new string[0]; - bodyExpression = (BaseNode)this.getFirstChild(); + argumentNames[i++] = argNode.getText(); + argNode = argNode.getNextSibling(); } - else - { - AST argsNode = this.getFirstChild(); - argumentNames = new string[argsNode.getNumberOfChildren()]; - AST argNode = argsNode.getFirstChild(); - int i = 0; - while (argNode != null) - { - argumentNames[i++] = argNode.getText(); - argNode = argNode.getNextSibling(); - } - bodyExpression = (BaseNode)argsNode.getNextSibling(); - } + bodyExpression = (BaseNode) argsNode.getNextSibling(); } } } } -} +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Expressions/ListInitializerNode.cs b/src/Spring/Spring.Core/Expressions/ListInitializerNode.cs index 194123d2..d87b0837 100644 --- a/src/Spring/Spring.Core/Expressions/ListInitializerNode.cs +++ b/src/Spring/Spring.Core/Expressions/ListInitializerNode.cs @@ -21,40 +21,39 @@ using System.Collections; using System.Runtime.Serialization; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// Represents parsed list initializer node in the navigation expression. +/// +/// Aleksandar Seovic +[Serializable] +public class ListInitializerNode : NodeWithArguments { - /// - /// Represents parsed list initializer node in the navigation expression. - /// - /// Aleksandar Seovic - [Serializable] - public class ListInitializerNode : NodeWithArguments - { - /// - /// Create a new instance - /// - public ListInitializerNode() - { - } + /// + /// Create a new instance + /// + public ListInitializerNode() + { + } - /// - /// Create a new instance from SerializationInfo - /// - protected ListInitializerNode(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } + /// + /// Create a new instance from SerializationInfo + /// + protected ListInitializerNode(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } - /// - /// Creates new instance of the list defined by this node. - /// - /// Context to evaluate expressions against. - /// Current expression evaluation context. - /// Node's value. - protected override object Get(object context, EvaluationContext evalContext) - { - object[] values = ResolveArguments(evalContext); - return new ArrayList(values); - } + /// + /// Creates new instance of the list defined by this node. + /// + /// Context to evaluate expressions against. + /// Current expression evaluation context. + /// Node's value. + protected override object Get(object context, EvaluationContext evalContext) + { + object[] values = ResolveArguments(evalContext); + return new ArrayList(values); } } diff --git a/src/Spring/Spring.Core/Expressions/LocalFunctionNode.cs b/src/Spring/Spring.Core/Expressions/LocalFunctionNode.cs index 5af091c3..83208d26 100644 --- a/src/Spring/Spring.Core/Expressions/LocalFunctionNode.cs +++ b/src/Spring/Spring.Core/Expressions/LocalFunctionNode.cs @@ -21,57 +21,56 @@ using System.Collections; using System.Runtime.Serialization; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// Represents local function node. +/// +/// Aleksandar Seovic +[Serializable] +public class LocalFunctionNode : NodeWithArguments { /// - /// Represents local function node. + /// Create a new instance /// - /// Aleksandar Seovic - [Serializable] - public class LocalFunctionNode : NodeWithArguments + public LocalFunctionNode() { - /// - /// Create a new instance - /// - public LocalFunctionNode() + } + + /// + /// Create a new instance from SerializationInfo + /// + protected LocalFunctionNode(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + + /// + /// Evaluates function represented by this node. + /// + /// Context to evaluate expressions against. + /// Current expression evaluation context. + /// Result of the function evaluation. + protected override object Get(object context, EvaluationContext evalContext) + { + string name = this.getText(); + IDictionary locals = evalContext.LocalVariables; + LambdaExpressionNode lambda = locals[name] as LambdaExpressionNode; + + if (lambda == null) { + throw new InvalidOperationException("Function '" + name + "' is not defined."); } - /// - /// Create a new instance from SerializationInfo - /// - protected LocalFunctionNode(SerializationInfo info, StreamingContext context) - : base(info, context) + object[] argValues = ResolveArguments(evalContext); + + try { + return GetValueWithArguments(lambda, context, evalContext, argValues); } - - /// - /// Evaluates function represented by this node. - /// - /// Context to evaluate expressions against. - /// Current expression evaluation context. - /// Result of the function evaluation. - protected override object Get(object context, EvaluationContext evalContext) + catch (ArgumentMismatchException ame) { - string name = this.getText(); - IDictionary locals = evalContext.LocalVariables; - LambdaExpressionNode lambda = locals[name] as LambdaExpressionNode; - - if (lambda == null) - { - throw new InvalidOperationException("Function '" + name + "' is not defined."); - } - - object[] argValues = ResolveArguments(evalContext); - - try - { - return GetValueWithArguments(lambda, context, evalContext, argValues); - } - catch (ArgumentMismatchException ame) - { - throw new InvalidOperationException("Failed executing function '" + name + "': " + ame.Message); - } + throw new InvalidOperationException("Failed executing function '" + name + "': " + ame.Message); } } } diff --git a/src/Spring/Spring.Core/Expressions/LocalVariableNode.cs b/src/Spring/Spring.Core/Expressions/LocalVariableNode.cs index 0ba7a8d0..f356debb 100644 --- a/src/Spring/Spring.Core/Expressions/LocalVariableNode.cs +++ b/src/Spring/Spring.Core/Expressions/LocalVariableNode.cs @@ -21,65 +21,66 @@ using System.Collections; using System.Runtime.Serialization; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// Represents parsed variable node. +/// +/// Aleksandar Seovic +[Serializable] +public class LocalVariableNode : BaseNode { + //internal const string LOCAL_VARIABLES = "__locals"; + /// - /// Represents parsed variable node. + /// Create a new instance /// - /// Aleksandar Seovic - [Serializable] - public class LocalVariableNode : BaseNode + public LocalVariableNode() { - //internal const string LOCAL_VARIABLES = "__locals"; + } - /// - /// Create a new instance - /// - public LocalVariableNode() + /// + /// Create a new instance from SerializationInfo + /// + protected LocalVariableNode(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + + /// + /// Returns value of the local variable represented by this node. + /// + /// Context to evaluate expressions against. + /// Current expression evaluation context. + /// Node's value. + protected override object Get(object context, EvaluationContext evalContext) + { + string varName = this.getText(); + IDictionary locals = evalContext.LocalVariables; + if (locals != null) { + return locals[varName]; } - /// - /// Create a new instance from SerializationInfo - /// - protected LocalVariableNode(SerializationInfo info, StreamingContext context) - : base(info, context) + return null; + } + + /// + /// Sets value of the local variable represented by this node. + /// + /// Context to evaluate expressions against. + /// Current expression evaluation context. + /// New value for this node. + protected override void Set(object context, EvaluationContext evalContext, object newValue) + { + string varName = this.getText(); + IDictionary locals = evalContext.LocalVariables; + if (locals == null) { + locals = new Hashtable(); + evalContext.LocalVariables = locals; } - /// - /// Returns value of the local variable represented by this node. - /// - /// Context to evaluate expressions against. - /// Current expression evaluation context. - /// Node's value. - protected override object Get(object context, EvaluationContext evalContext) - { - string varName = this.getText(); - IDictionary locals = evalContext.LocalVariables; - if (locals != null) - { - return locals[varName]; - } - return null; - } - - /// - /// Sets value of the local variable represented by this node. - /// - /// Context to evaluate expressions against. - /// Current expression evaluation context. - /// New value for this node. - protected override void Set(object context, EvaluationContext evalContext, object newValue) - { - string varName = this.getText(); - IDictionary locals = evalContext.LocalVariables; - if (locals == null) - { - locals = new Hashtable(); - evalContext.LocalVariables = locals; - } - locals[varName] = newValue; - } + locals[varName] = newValue; } } diff --git a/src/Spring/Spring.Core/Expressions/MapEntryNode.cs b/src/Spring/Spring.Core/Expressions/MapEntryNode.cs index 8ade206e..efc5b0b0 100644 --- a/src/Spring/Spring.Core/Expressions/MapEntryNode.cs +++ b/src/Spring/Spring.Core/Expressions/MapEntryNode.cs @@ -21,42 +21,42 @@ using System.Collections; using System.Runtime.Serialization; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// Represents parsed map entry node. +/// +/// Aleksandar Seovic +[Serializable] +public class MapEntryNode : BaseNode { /// - /// Represents parsed map entry node. + /// Creates a new instance of . /// - /// Aleksandar Seovic - [Serializable] - public class MapEntryNode : BaseNode + public MapEntryNode() { - /// - /// Creates a new instance of . - /// - public MapEntryNode() - {} + } - /// - /// Create a new instance from SerializationInfo - /// - protected MapEntryNode(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } + /// + /// Create a new instance from SerializationInfo + /// + protected MapEntryNode(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } - /// - /// Creates new instance of the map entry defined by this node. - /// - /// Context to evaluate expressions against. - /// Current expression evaluation context. - /// Node's value. - protected override object Get(object context, EvaluationContext evalContext) - { - BaseNode firstChild = (BaseNode)this.getFirstChild(); - object key = GetValue(firstChild, context, evalContext); - object value = GetValue((BaseNode) firstChild.getNextSibling(), context, evalContext); + /// + /// Creates new instance of the map entry defined by this node. + /// + /// Context to evaluate expressions against. + /// Current expression evaluation context. + /// Node's value. + protected override object Get(object context, EvaluationContext evalContext) + { + BaseNode firstChild = (BaseNode) this.getFirstChild(); + object key = GetValue(firstChild, context, evalContext); + object value = GetValue((BaseNode) firstChild.getNextSibling(), context, evalContext); - return new DictionaryEntry(key, value); - } + return new DictionaryEntry(key, value); } } diff --git a/src/Spring/Spring.Core/Expressions/MapInitializerNode.cs b/src/Spring/Spring.Core/Expressions/MapInitializerNode.cs index 3449c182..b54ae198 100644 --- a/src/Spring/Spring.Core/Expressions/MapInitializerNode.cs +++ b/src/Spring/Spring.Core/Expressions/MapInitializerNode.cs @@ -22,47 +22,47 @@ using System.Collections; using System.Runtime.Serialization; using Spring.Expressions.Parser.antlr.collections; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// Represents parsed map initializer node in the navigation expression. +/// +/// Aleksandar Seovic +[Serializable] +public class MapInitializerNode : BaseNode { /// - /// Represents parsed map initializer node in the navigation expression. + /// Creates a new instance of . /// - /// Aleksandar Seovic - [Serializable] - public class MapInitializerNode : BaseNode + public MapInitializerNode() { - /// - /// Creates a new instance of . - /// - public MapInitializerNode() - {} + } - /// - /// Create a new instance from SerializationInfo - /// - protected MapInitializerNode(SerializationInfo info, StreamingContext context) - : base(info, context) + /// + /// Create a new instance from SerializationInfo + /// + protected MapInitializerNode(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + + /// + /// Creates new instance of the map defined by this node. + /// + /// Context to evaluate expressions against. + /// Current expression evaluation context. + /// Node's value. + protected override object Get(object context, EvaluationContext evalContext) + { + IDictionary entries = new Hashtable(); + AST entryNode = this.getFirstChild(); + while (entryNode != null) { + DictionaryEntry entry = (DictionaryEntry) GetValue(((MapEntryNode) entryNode), evalContext.RootContext, evalContext); + entries[entry.Key] = entry.Value; + entryNode = entryNode.getNextSibling(); } - /// - /// Creates new instance of the map defined by this node. - /// - /// Context to evaluate expressions against. - /// Current expression evaluation context. - /// Node's value. - protected override object Get(object context, EvaluationContext evalContext) - { - IDictionary entries = new Hashtable(); - AST entryNode = this.getFirstChild(); - while (entryNode != null) - { - DictionaryEntry entry = (DictionaryEntry) GetValue(((MapEntryNode)entryNode), evalContext.RootContext, evalContext ); - entries[entry.Key] = entry.Value; - entryNode = entryNode.getNextSibling(); - } - - return entries; - } + return entries; } } diff --git a/src/Spring/Spring.Core/Expressions/MethodNode.cs b/src/Spring/Spring.Core/Expressions/MethodNode.cs index a4d49e43..01803d35 100644 --- a/src/Spring/Spring.Core/Expressions/MethodNode.cs +++ b/src/Spring/Spring.Core/Expressions/MethodNode.cs @@ -25,255 +25,252 @@ using Spring.Expressions.Processors; using Spring.Util; using Spring.Reflection.Dynamic; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// Represents parsed method node in the navigation expression. +/// +/// Aleksandar Seovic +[Serializable] +public class MethodNode : NodeWithArguments { + private const BindingFlags BINDING_FLAGS + = BindingFlags.Public | BindingFlags.NonPublic + | BindingFlags.Instance | BindingFlags.Static + | BindingFlags.IgnoreCase; + + private static readonly IDictionary collectionProcessorMap = new Hashtable(); + private static readonly IDictionary extensionMethodProcessorMap = new Hashtable(); + + private bool initialized = false; + private bool cachedIsParamArray = false; + private Type paramArrayType; + private int argumentCount; + private SafeMethod cachedInstanceMethod; + private int cachedInstanceMethodHash; + /// - /// Represents parsed method node in the navigation expression. + /// Static constructor. Initializes a map of special collection processor methods. /// - /// Aleksandar Seovic - [Serializable] - public class MethodNode : NodeWithArguments + static MethodNode() { - private const BindingFlags BINDING_FLAGS - = BindingFlags.Public | BindingFlags.NonPublic - | BindingFlags.Instance | BindingFlags.Static - | BindingFlags.IgnoreCase; + collectionProcessorMap.Add("count", new CountAggregator()); + collectionProcessorMap.Add("sum", new SumAggregator()); + collectionProcessorMap.Add("max", new MaxAggregator()); + collectionProcessorMap.Add("min", new MinAggregator()); + collectionProcessorMap.Add("average", new AverageAggregator()); + collectionProcessorMap.Add("sort", new SortProcessor()); + collectionProcessorMap.Add("orderBy", new OrderByProcessor()); + collectionProcessorMap.Add("distinct", new DistinctProcessor()); + collectionProcessorMap.Add("nonNull", new NonNullProcessor()); + collectionProcessorMap.Add("reverse", new ReverseProcessor()); + collectionProcessorMap.Add("convert", new ConversionProcessor()); - private static readonly IDictionary collectionProcessorMap = new Hashtable(); - private static readonly IDictionary extensionMethodProcessorMap = new Hashtable(); + extensionMethodProcessorMap.Add("date", new DateConversionProcessor()); + } - private bool initialized = false; - private bool cachedIsParamArray = false; - private Type paramArrayType; - private int argumentCount; - private SafeMethod cachedInstanceMethod; - private int cachedInstanceMethodHash; + /// + /// Create a new instance + /// + public MethodNode() + { + } - /// - /// Static constructor. Initializes a map of special collection processor methods. - /// - static MethodNode() + /// + /// Create a new instance from SerializationInfo + /// + protected MethodNode(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + + /// + /// Returns node's value for the given context. + /// + /// Context to evaluate expressions against. + /// Current expression evaluation context. + /// Node's value. + protected override object Get(object context, EvaluationContext evalContext) + { + string methodName = this.getText(); + object[] argValues = ResolveArguments(evalContext); + ICollectionProcessor localCollectionProcessor = null; + IMethodCallProcessor methodCallProcessor = null; + + // resolve method, if necessary + lock (this) { - collectionProcessorMap.Add("count", new CountAggregator()); - collectionProcessorMap.Add("sum", new SumAggregator()); - collectionProcessorMap.Add("max", new MaxAggregator()); - collectionProcessorMap.Add("min", new MinAggregator()); - collectionProcessorMap.Add("average", new AverageAggregator()); - collectionProcessorMap.Add("sort", new SortProcessor()); - collectionProcessorMap.Add("orderBy", new OrderByProcessor()); - collectionProcessorMap.Add("distinct", new DistinctProcessor()); - collectionProcessorMap.Add("nonNull", new NonNullProcessor()); - collectionProcessorMap.Add("reverse", new ReverseProcessor()); - collectionProcessorMap.Add("convert", new ConversionProcessor()); - - extensionMethodProcessorMap.Add("date", new DateConversionProcessor()); - } - - /// - /// Create a new instance - /// - public MethodNode() - { - } - - /// - /// Create a new instance from SerializationInfo - /// - protected MethodNode(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } - - /// - /// Returns node's value for the given context. - /// - /// Context to evaluate expressions against. - /// Current expression evaluation context. - /// Node's value. - protected override object Get(object context, EvaluationContext evalContext) - { - string methodName = this.getText(); - object[] argValues = ResolveArguments(evalContext); - ICollectionProcessor localCollectionProcessor = null; - IMethodCallProcessor methodCallProcessor = null; - - // resolve method, if necessary - lock (this) + // check if it is a collection and the methodname denotes a collection processor + if ((context == null || context is ICollection)) { - // check if it is a collection and the methodname denotes a collection processor - if ((context == null || context is ICollection)) + // predefined collection processor? + localCollectionProcessor = (ICollectionProcessor) collectionProcessorMap[methodName]; + + // user-defined collection processor? + if (localCollectionProcessor == null && evalContext.Variables != null) { - // predefined collection processor? - localCollectionProcessor = (ICollectionProcessor)collectionProcessorMap[methodName]; - - // user-defined collection processor? - if (localCollectionProcessor == null && evalContext.Variables != null) - { - object temp; - evalContext.Variables.TryGetValue(methodName, out temp); - localCollectionProcessor = temp as ICollectionProcessor; - } - } - - // try extension methods - methodCallProcessor = (IMethodCallProcessor)extensionMethodProcessorMap[methodName]; - { - // user-defined extension method processor? - if (methodCallProcessor == null && evalContext.Variables != null) - { - object temp; - evalContext.Variables.TryGetValue(methodName, out temp); - methodCallProcessor = temp as IMethodCallProcessor; - } - } - - // try instance method - if (context != null) - { - // calculate checksum, if the cached method matches the current context - if (initialized) - { - int calculatedHash = CalculateMethodHash(context.GetType(), argValues); - initialized = (calculatedHash == cachedInstanceMethodHash); - } - - if (!initialized) - { - Initialize(methodName, argValues, context); - initialized = true; - } + object temp; + evalContext.Variables.TryGetValue(methodName, out temp); + localCollectionProcessor = temp as ICollectionProcessor; } } - if (localCollectionProcessor != null) + // try extension methods + methodCallProcessor = (IMethodCallProcessor) extensionMethodProcessorMap[methodName]; { - return localCollectionProcessor.Process((ICollection)context, argValues); - } - else if (methodCallProcessor != null) - { - return methodCallProcessor.Process(context, argValues); - } - else if (cachedInstanceMethod != null) - { - object[] paramValues = (cachedIsParamArray) - ? ReflectionUtils.PackageParamArray(argValues, argumentCount, paramArrayType) - : argValues; - return cachedInstanceMethod.Invoke(context, paramValues); - } - else - { - throw new ArgumentException(string.Format("Method '{0}' with the specified number and types of arguments does not exist.", methodName)); - } - } - - private int CalculateMethodHash(Type contextType, object[] argValues) - { - HashCode hash = new HashCode(); - hash.Add(contextType.GetHashCode()); - - for (int i = 0; i < argValues.Length; i++) - { - object arg = argValues[i]; - if (arg != null) + // user-defined extension method processor? + if (methodCallProcessor == null && evalContext.Variables != null) { - hash.Add(arg.GetType().GetHashCode()); + object temp; + evalContext.Variables.TryGetValue(methodName, out temp); + methodCallProcessor = temp as IMethodCallProcessor; } } - return hash.ToHashCode(); + // try instance method + if (context != null) + { + // calculate checksum, if the cached method matches the current context + if (initialized) + { + int calculatedHash = CalculateMethodHash(context.GetType(), argValues); + initialized = (calculatedHash == cachedInstanceMethodHash); + } + + if (!initialized) + { + Initialize(methodName, argValues, context); + initialized = true; + } + } } - private void Initialize(string methodName, object[] argValues, object context) + if (localCollectionProcessor != null) { - Type contextType = (context is Type ? context as Type : context.GetType()); + return localCollectionProcessor.Process((ICollection) context, argValues); + } + else if (methodCallProcessor != null) + { + return methodCallProcessor.Process(context, argValues); + } + else if (cachedInstanceMethod != null) + { + object[] paramValues = (cachedIsParamArray) + ? ReflectionUtils.PackageParamArray(argValues, argumentCount, paramArrayType) + : argValues; + return cachedInstanceMethod.Invoke(context, paramValues); + } + else + { + throw new ArgumentException(string.Format("Method '{0}' with the specified number and types of arguments does not exist.", methodName)); + } + } - // check the context type first - MethodInfo mi = GetBestMethod(contextType, methodName, BINDING_FLAGS, argValues); + private int CalculateMethodHash(Type contextType, object[] argValues) + { + HashCode hash = new HashCode(); + hash.Add(contextType.GetHashCode()); - // if not found, probe the Type's type - if (mi == null) + for (int i = 0; i < argValues.Length; i++) + { + object arg = argValues[i]; + if (arg != null) { - mi = GetBestMethod(typeof(Type), methodName, BINDING_FLAGS, argValues); + hash.Add(arg.GetType().GetHashCode()); + } + } + + return hash.ToHashCode(); + } + + private void Initialize(string methodName, object[] argValues, object context) + { + Type contextType = (context is Type ? context as Type : context.GetType()); + + // check the context type first + MethodInfo mi = GetBestMethod(contextType, methodName, BINDING_FLAGS, argValues); + + // if not found, probe the Type's type + if (mi == null) + { + mi = GetBestMethod(typeof(Type), methodName, BINDING_FLAGS, argValues); + } + + if (mi == null) + { + return; + } + else + { + ParameterInfo[] parameters = mi.GetParameters(); + if (parameters.Length > 0) + { + ParameterInfo lastParameter = parameters[parameters.Length - 1]; + cachedIsParamArray = lastParameter.GetCustomAttributes(typeof(ParamArrayAttribute), false).Length > 0; + if (cachedIsParamArray) + { + paramArrayType = lastParameter.ParameterType.GetElementType(); + argumentCount = parameters.Length; + } } - if (mi == null) + cachedInstanceMethod = new SafeMethod(mi); + cachedInstanceMethodHash = CalculateMethodHash(contextType, argValues); + } + } + + /// + /// Gets the best method given the name, argument values, for a given type. + /// + /// The type on which to search for the method. + /// Name of the method. + /// The binding flags. + /// The arg values. + /// Best matching method or null if none found. + public static MethodInfo GetBestMethod(Type type, string methodName, BindingFlags bindingFlags, object[] argValues) + { + MethodInfo mi = null; + try + { + mi = type.GetMethod(methodName, bindingFlags | BindingFlags.FlattenHierarchy); + } + catch (AmbiguousMatchException) + { + IList overloads = GetCandidateMethods(type, methodName, bindingFlags, argValues.Length); + if (overloads.Count > 0) { - return; + mi = ReflectionUtils.GetMethodByArgumentValues(overloads, argValues); } - else + } + + return mi; + } + + private static IList GetCandidateMethods(Type type, string methodName, BindingFlags bindingFlags, int argCount) + { + MethodInfo[] methods = type.GetMethods(bindingFlags | BindingFlags.FlattenHierarchy); + List matches = new List(); + + foreach (MethodInfo method in methods) + { + if (method.Name == methodName) { - ParameterInfo[] parameters = mi.GetParameters(); - if (parameters.Length > 0) + ParameterInfo[] parameters = method.GetParameters(); + if (parameters.Length == argCount) + { + matches.Add(method); + } + else if (parameters.Length > 0) { ParameterInfo lastParameter = parameters[parameters.Length - 1]; - cachedIsParamArray = lastParameter.GetCustomAttributes(typeof(ParamArrayAttribute), false).Length > 0; - if (cachedIsParamArray) - { - paramArrayType = lastParameter.ParameterType.GetElementType(); - argumentCount = parameters.Length; - } - } - - cachedInstanceMethod = new SafeMethod(mi); - cachedInstanceMethodHash = CalculateMethodHash(contextType, argValues); - } - } - - /// - /// Gets the best method given the name, argument values, for a given type. - /// - /// The type on which to search for the method. - /// Name of the method. - /// The binding flags. - /// The arg values. - /// Best matching method or null if none found. - public static MethodInfo GetBestMethod(Type type, string methodName, BindingFlags bindingFlags, object[] argValues) - { - MethodInfo mi = null; - try - { - mi = type.GetMethod(methodName, bindingFlags | BindingFlags.FlattenHierarchy); - } - catch (AmbiguousMatchException) - { - - IList overloads = GetCandidateMethods(type, methodName, bindingFlags, argValues.Length); - if (overloads.Count > 0) - { - mi = ReflectionUtils.GetMethodByArgumentValues(overloads, argValues); - } - } - return mi; - } - - - - private static IList GetCandidateMethods(Type type, string methodName, BindingFlags bindingFlags, int argCount) - { - MethodInfo[] methods = type.GetMethods(bindingFlags | BindingFlags.FlattenHierarchy); - List matches = new List(); - - foreach (MethodInfo method in methods) - { - if (method.Name == methodName) - { - ParameterInfo[] parameters = method.GetParameters(); - if (parameters.Length == argCount) + if (lastParameter.GetCustomAttributes(typeof(ParamArrayAttribute), false).Length > 0) { matches.Add(method); } - else if (parameters.Length > 0) - { - ParameterInfo lastParameter = parameters[parameters.Length - 1]; - if (lastParameter.GetCustomAttributes(typeof(ParamArrayAttribute), false).Length > 0) - { - matches.Add(method); - } - } } } - - return matches; } + + return matches; } -} +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Expressions/NamedArgumentNode.cs b/src/Spring/Spring.Core/Expressions/NamedArgumentNode.cs index ee0a5e68..6cd0b5d4 100644 --- a/src/Spring/Spring.Core/Expressions/NamedArgumentNode.cs +++ b/src/Spring/Spring.Core/Expressions/NamedArgumentNode.cs @@ -20,39 +20,38 @@ using System.Runtime.Serialization; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// Represents parsed named argument node in the expression. +/// +/// Aleksandar Seovic +[Serializable] +public class NamedArgumentNode : BaseNode { /// - /// Represents parsed named argument node in the expression. + /// Create a new instance /// - /// Aleksandar Seovic - [Serializable] - public class NamedArgumentNode : BaseNode + public NamedArgumentNode() { - /// - /// Create a new instance - /// - public NamedArgumentNode() - { - } - - /// - /// Create a new instance from SerializationInfo - /// - protected NamedArgumentNode(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } - - /// - /// Returns the value of the named argument defined by this node. - /// - /// Context to evaluate expressions against. - /// Current expression evaluation context. - /// Node's value. - protected override object Get(object context, EvaluationContext evalContext) - { - return GetValue(((BaseNode) this.getFirstChild()), evalContext.RootContext, evalContext); - } } -} + + /// + /// Create a new instance from SerializationInfo + /// + protected NamedArgumentNode(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + + /// + /// Returns the value of the named argument defined by this node. + /// + /// Context to evaluate expressions against. + /// Current expression evaluation context. + /// Node's value. + protected override object Get(object context, EvaluationContext evalContext) + { + return GetValue(((BaseNode) this.getFirstChild()), evalContext.RootContext, evalContext); + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Expressions/NodeWithArguments.cs b/src/Spring/Spring.Core/Expressions/NodeWithArguments.cs index c8946f39..bdec7aa3 100644 --- a/src/Spring/Spring.Core/Expressions/NodeWithArguments.cs +++ b/src/Spring/Spring.Core/Expressions/NodeWithArguments.cs @@ -22,188 +22,191 @@ using System.Collections; using System.Runtime.Serialization; using Spring.Expressions.Parser.antlr.collections; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// Base type for nodes that accept arguments. +/// +/// Aleksandar Seovic +[Serializable] +public abstract class NodeWithArguments : BaseNode { + private BaseNode[] args; + private IDictionary namedArgs; + /// - /// Base type for nodes that accept arguments. + /// Create a new instance /// - /// Aleksandar Seovic - [Serializable] - public abstract class NodeWithArguments : BaseNode + public NodeWithArguments() { - private BaseNode[] args; - private IDictionary namedArgs; + } - /// - /// Create a new instance - /// - public NodeWithArguments() - { - } + /// + /// Create a new instance + /// + public NodeWithArguments(string text) + { + this.setText(text); + } - /// - /// Create a new instance - /// - public NodeWithArguments(string text) - { - this.setText(text); - } + /// + /// Append an argument node to the list of child nodes + /// + /// + public void AddArgument(BaseNode argumentNode) + { + base.addChild(argumentNode); + } - /// - /// Append an argument node to the list of child nodes - /// - /// - public void AddArgument(BaseNode argumentNode) - { - base.addChild(argumentNode); - } + /// + /// Create a new instance from SerializationInfo + /// + protected NodeWithArguments(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } - /// - /// Create a new instance from SerializationInfo - /// - protected NodeWithArguments(SerializationInfo info, StreamingContext context) - : base(info, context) + /// + /// Initializes the node. + /// + private void InitializeNode() + { + lock (this) { - } - - /// - /// Initializes the node. - /// - private void InitializeNode() - { - lock (this) + if (args == null) { - if (args == null) + List argList = new List(); + namedArgs = new Hashtable(); + + AST node = this.getFirstChild(); + + while (node != null) { - List argList = new List(); - namedArgs = new Hashtable(); - - AST node = this.getFirstChild(); - - while (node != null) + if (node.getFirstChild() is LambdaExpressionNode) { - if (node.getFirstChild() is LambdaExpressionNode) - { - argList.Add((BaseNode) node.getFirstChild()); - } - else if (node is NamedArgumentNode) - { - namedArgs.Add(node.getText(), node); - } - else - { - argList.Add((BaseNode) node); - } - node = node.getNextSibling(); + argList.Add((BaseNode) node.getFirstChild()); + } + else if (node is NamedArgumentNode) + { + namedArgs.Add(node.getText(), node); + } + else + { + argList.Add((BaseNode) node); } - args = argList.ToArray(); + node = node.getNextSibling(); } + + args = argList.ToArray(); } } + } - /// - /// Asserts the argument count. - /// - /// The required count. - protected void AssertArgumentCount(int requiredCount) + /// + /// Asserts the argument count. + /// + /// The required count. + protected void AssertArgumentCount(int requiredCount) + { + InitializeNode(); + if (requiredCount != args.Length) + { + throw new ArgumentException("This expression node requires exactly " + + requiredCount + " argument(s) and " + + args.Length + " were specified."); + } + } + + /// + /// Resolves the arguments. + /// + /// Current expression evaluation context. + /// An array of argument values + protected object[] ResolveArguments(EvaluationContext evalContext) + { + if (args == null) { InitializeNode(); - if (requiredCount != args.Length) - { - throw new ArgumentException("This expression node requires exactly " + - requiredCount + " argument(s) and " + - args.Length + " were specified."); - } } - /// - /// Resolves the arguments. - /// - /// Current expression evaluation context. - /// An array of argument values - protected object[] ResolveArguments(EvaluationContext evalContext) + int length = args.Length; + object[] values = new object[length]; + for (int i = 0; i < length; i++) { - if (args == null) - { - InitializeNode(); - } - - int length = args.Length; - object[] values = new object[length]; - for (int i = 0; i < length; i++) - { - values[i] = ResolveArgumentInternal(i, evalContext); - } - return values; - } - - /// - /// Resolves the named arguments. - /// - /// Current expression evaluation context. - /// A dictionary of argument name to value mappings. - protected IDictionary ResolveNamedArguments(EvaluationContext evalContext) - { - if (args == null) - { - InitializeNode(); - } - - if (namedArgs.Count == 0) - { - return null; - } - - IDictionary namesAndValues = new Hashtable(namedArgs.Count); - foreach (string name in namedArgs.Keys) - { - namesAndValues[name] = ResolveNamedArgument(name, evalContext); - } - return namesAndValues; - } - - /// - /// Resolves the argument. - /// - /// Argument position. - /// Current expression evaluation context. - /// Resolved argument value. - protected object ResolveArgument(int position, EvaluationContext evalContext) - { - if (args == null) - { - InitializeNode(); - } - return ResolveArgumentInternal(position, evalContext); - } - - /// - /// Resolves the argument without ensuring was called. - /// - /// Argument position. - /// Current expression evaluation context. - /// Resolved argument value. - private object ResolveArgumentInternal(int position, EvaluationContext evalContext) - { - BaseNode arg = args[position]; - if (arg is LambdaExpressionNode) - { - return arg; - } - return GetValue(arg, evalContext.ThisContext, evalContext); - } - - /// - /// Resolves the named argument. - /// - /// Argument name. - /// Current expression evaluation context. - /// Resolved named argument value. - private object ResolveNamedArgument(string name, EvaluationContext evalContext) - { - return GetValue(((BaseNode)namedArgs[name]), evalContext.ThisContext, evalContext); + values[i] = ResolveArgumentInternal(i, evalContext); } + return values; } -} + + /// + /// Resolves the named arguments. + /// + /// Current expression evaluation context. + /// A dictionary of argument name to value mappings. + protected IDictionary ResolveNamedArguments(EvaluationContext evalContext) + { + if (args == null) + { + InitializeNode(); + } + + if (namedArgs.Count == 0) + { + return null; + } + + IDictionary namesAndValues = new Hashtable(namedArgs.Count); + foreach (string name in namedArgs.Keys) + { + namesAndValues[name] = ResolveNamedArgument(name, evalContext); + } + + return namesAndValues; + } + + /// + /// Resolves the argument. + /// + /// Argument position. + /// Current expression evaluation context. + /// Resolved argument value. + protected object ResolveArgument(int position, EvaluationContext evalContext) + { + if (args == null) + { + InitializeNode(); + } + + return ResolveArgumentInternal(position, evalContext); + } + + /// + /// Resolves the argument without ensuring was called. + /// + /// Argument position. + /// Current expression evaluation context. + /// Resolved argument value. + private object ResolveArgumentInternal(int position, EvaluationContext evalContext) + { + BaseNode arg = args[position]; + if (arg is LambdaExpressionNode) + { + return arg; + } + + return GetValue(arg, evalContext.ThisContext, evalContext); + } + + /// + /// Resolves the named argument. + /// + /// Argument name. + /// Current expression evaluation context. + /// Resolved named argument value. + private object ResolveNamedArgument(string name, EvaluationContext evalContext) + { + return GetValue(((BaseNode) namedArgs[name]), evalContext.ThisContext, evalContext); + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Expressions/NullLiteralNode.cs b/src/Spring/Spring.Core/Expressions/NullLiteralNode.cs index 4aefa12f..0575bc4f 100644 --- a/src/Spring/Spring.Core/Expressions/NullLiteralNode.cs +++ b/src/Spring/Spring.Core/Expressions/NullLiteralNode.cs @@ -20,39 +20,38 @@ using System.Runtime.Serialization; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// Represents parsed null literal node. +/// +/// Aleksandar Seovic +[Serializable] +public class NullLiteralNode : BaseNode { /// - /// Represents parsed null literal node. + /// Create a new instance /// - /// Aleksandar Seovic - [Serializable] - public class NullLiteralNode : BaseNode + public NullLiteralNode() { - /// - /// Create a new instance - /// - public NullLiteralNode() - { - } + } - /// - /// Create a new instance from SerializationInfo - /// - protected NullLiteralNode(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } + /// + /// Create a new instance from SerializationInfo + /// + protected NullLiteralNode(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } - /// - /// Returns a value for the null literal node. - /// - /// Context to evaluate expressions against. - /// Current expression evaluation context. - /// Node's value. - protected override object Get(object context, EvaluationContext evalContext) - { - return null; - } + /// + /// Returns a value for the null literal node. + /// + /// Context to evaluate expressions against. + /// Current expression evaluation context. + /// Node's value. + protected override object Get(object context, EvaluationContext evalContext) + { + return null; } } diff --git a/src/Spring/Spring.Core/Expressions/OpADD.cs b/src/Spring/Spring.Core/Expressions/OpADD.cs index 81f8bad0..addf2bc4 100644 --- a/src/Spring/Spring.Core/Expressions/OpADD.cs +++ b/src/Spring/Spring.Core/Expressions/OpADD.cs @@ -23,96 +23,96 @@ using System.Runtime.Serialization; using Spring.Collections; using Spring.Util; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// Represents arithmetic addition operator. +/// +/// Aleksandar Seovic +[Serializable] +public class OpADD : BinaryOperator { /// - /// Represents arithmetic addition operator. + /// Create a new instance /// - /// Aleksandar Seovic - [Serializable] - public class OpADD : BinaryOperator + public OpADD() { - /// - /// Create a new instance - /// - public OpADD() + } + + /// + /// Create a new instance from SerializationInfo + /// + protected OpADD(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + + /// + /// Returns a value for the arithmetic addition operator node. + /// + /// Context to evaluate expressions against. + /// Current expression evaluation context. + /// Node's value. + protected override object Get(object context, EvaluationContext evalContext) + { + object left = GetLeftValue(context, evalContext); + object right = GetRightValue(context, evalContext); + + if (NumberUtils.IsNumber(left) && NumberUtils.IsNumber(right)) { + return NumberUtils.Add(left, right); } - - /// - /// Create a new instance from SerializationInfo - /// - protected OpADD(SerializationInfo info, StreamingContext context) - : base(info, context) + else if (left is DateTime && (right is TimeSpan || right is string || NumberUtils.IsNumber(right))) { + if (NumberUtils.IsNumber(right)) + { + right = TimeSpan.FromDays(Convert.ToDouble(right)); + } + else if (right is string) + { + right = TimeSpan.Parse((string) right); + } + + return (DateTime) left + (TimeSpan) right; } - - /// - /// Returns a value for the arithmetic addition operator node. - /// - /// Context to evaluate expressions against. - /// Current expression evaluation context. - /// Node's value. - protected override object Get(object context, EvaluationContext evalContext) + else if (left is String || right is String) { - object left = GetLeftValue(context, evalContext); - object right = GetRightValue(context, evalContext); + return string.Concat(left, right); + } + else if ((left is IList || left is ISet) && (right is IList || right is ISet)) + { + ISet leftset = new HybridSet(left as ICollection); + ISet rightset = new HybridSet(right as ICollection); + return leftset.Union(rightset); + } + else if (left is IDictionary && right is IDictionary) + { + ISet leftset = new HybridSet(((IDictionary) left).Keys); + ISet rightset = new HybridSet(((IDictionary) right).Keys); + ISet unionset = leftset.Union(rightset); - if (NumberUtils.IsNumber(left) && NumberUtils.IsNumber(right)) + IDictionary result = new Hashtable(unionset.Count); + foreach (object key in unionset) { - return NumberUtils.Add(left, right); + if (leftset.Contains(key)) + { + result.Add(key, ((IDictionary) left)[key]); + } + else + { + result.Add(key, ((IDictionary) right)[key]); + } } - else if (left is DateTime && (right is TimeSpan || right is string || NumberUtils.IsNumber(right))) - { - if (NumberUtils.IsNumber(right)) - { - right = TimeSpan.FromDays(Convert.ToDouble(right)); - } - else if (right is string) - { - right = TimeSpan.Parse((string) right); - } - return (DateTime) left + (TimeSpan) right; - } - else if (left is String || right is String) - { - return string.Concat(left, right); - } - else if ((left is IList || left is ISet) && (right is IList || right is ISet)) - { - ISet leftset = new HybridSet(left as ICollection); - ISet rightset = new HybridSet(right as ICollection); - return leftset.Union(rightset); - } - else if (left is IDictionary && right is IDictionary) - { - ISet leftset = new HybridSet(((IDictionary) left).Keys); - ISet rightset = new HybridSet(((IDictionary) right).Keys); - ISet unionset = leftset.Union(rightset); - - IDictionary result = new Hashtable(unionset.Count); - foreach(object key in unionset) - { - if(leftset.Contains(key)) - { - result.Add(key, ((IDictionary)left)[key]); - } - else - { - result.Add(key, ((IDictionary)right)[key]); - } - } - return result; - } - else - { - throw new ArgumentException("Cannot add instances of '" - + left.GetType().FullName - + "' and '" - + right.GetType().FullName - + "'."); - } + return result; + } + else + { + throw new ArgumentException("Cannot add instances of '" + + left.GetType().FullName + + "' and '" + + right.GetType().FullName + + "'."); } } } diff --git a/src/Spring/Spring.Core/Expressions/OpAND.cs b/src/Spring/Spring.Core/Expressions/OpAND.cs index 15be919a..ddb968c3 100644 --- a/src/Spring/Spring.Core/Expressions/OpAND.cs +++ b/src/Spring/Spring.Core/Expressions/OpAND.cs @@ -21,72 +21,71 @@ using System.Runtime.Serialization; using Spring.Util; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// Represents AND operator (both, bitwise and logical). +/// +/// Aleksandar Seovic +[Serializable] +public class OpAND : BinaryOperator { /// - /// Represents AND operator (both, bitwise and logical). + /// Create a new instance /// - /// Aleksandar Seovic - [Serializable] - public class OpAND : BinaryOperator + public OpAND() { - /// - /// Create a new instance - /// - public OpAND() - { - } + } - /// - /// Create a new instance - /// - public OpAND(BaseNode left, BaseNode right) - :base(left, right) - { - } + /// + /// Create a new instance + /// + public OpAND(BaseNode left, BaseNode right) + : base(left, right) + { + } - /// - /// Create a new instance from SerializationInfo - /// - protected OpAND(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } - - /// - /// Returns a value for the logical AND operator node. - /// - /// Context to evaluate expressions against. - /// Current expression evaluation context. - /// Node's value. - protected override object Get(object context, EvaluationContext evalContext) - { - object l = GetLeftValue(context, evalContext); + /// + /// Create a new instance from SerializationInfo + /// + protected OpAND(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } - if (NumberUtils.IsInteger(l)) + /// + /// Returns a value for the logical AND operator node. + /// + /// Context to evaluate expressions against. + /// Current expression evaluation context. + /// Node's value. + protected override object Get(object context, EvaluationContext evalContext) + { + object l = GetLeftValue(context, evalContext); + + if (NumberUtils.IsInteger(l)) + { + object r = GetRightValue(context, evalContext); + if (NumberUtils.IsInteger(r)) { - object r = GetRightValue(context, evalContext); - if (NumberUtils.IsInteger(r)) - { - return NumberUtils.BitwiseAnd(l, r); - } + return NumberUtils.BitwiseAnd(l, r); } - else if (l is Enum) - { - object r = GetRightValue(context, evalContext); - if (l.GetType() == r.GetType()) - { - Type enumType = l.GetType(); - Type integralType = Enum.GetUnderlyingType(enumType); - l = Convert.ChangeType(l, integralType); - r = Convert.ChangeType(r, integralType); - object result = NumberUtils.BitwiseAnd(l, r); - return Enum.ToObject(enumType, result); - } - } - - return Convert.ToBoolean(l) && - Convert.ToBoolean(GetRightValue(context, evalContext)); } + else if (l is Enum) + { + object r = GetRightValue(context, evalContext); + if (l.GetType() == r.GetType()) + { + Type enumType = l.GetType(); + Type integralType = Enum.GetUnderlyingType(enumType); + l = Convert.ChangeType(l, integralType); + r = Convert.ChangeType(r, integralType); + object result = NumberUtils.BitwiseAnd(l, r); + return Enum.ToObject(enumType, result); + } + } + + return Convert.ToBoolean(l) && + Convert.ToBoolean(GetRightValue(context, evalContext)); } } diff --git a/src/Spring/Spring.Core/Expressions/OpBetween.cs b/src/Spring/Spring.Core/Expressions/OpBetween.cs index 13f66c09..a8c8a9b3 100644 --- a/src/Spring/Spring.Core/Expressions/OpBetween.cs +++ b/src/Spring/Spring.Core/Expressions/OpBetween.cs @@ -22,52 +22,51 @@ using System.Collections; using System.Runtime.Serialization; using Spring.Util; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// Represents logical BETWEEN operator. +/// +/// Aleksandar Seovic +[Serializable] +public class OpBetween : BinaryOperator { /// - /// Represents logical BETWEEN operator. + /// Create a new instance /// - /// Aleksandar Seovic - [Serializable] - public class OpBetween : BinaryOperator + public OpBetween() { - /// - /// Create a new instance - /// - public OpBetween() + } + + /// + /// Create a new instance from SerializationInfo + /// + protected OpBetween(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + + /// + /// Returns a value for the logical IN operator node. + /// + /// Context to evaluate expressions against. + /// Current expression evaluation context. + /// + /// true if the left operand is contained within the right operand, false otherwise. + /// + protected override object Get(object context, EvaluationContext evalContext) + { + object value = GetLeftValue(context, evalContext); + IList range = GetRightValue(context, evalContext) as IList; + + if (range == null || range.Count != 2) { + throw new ArgumentException("Right operand for the 'between' operator has to be a two-element list."); } - /// - /// Create a new instance from SerializationInfo - /// - protected OpBetween(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } - - /// - /// Returns a value for the logical IN operator node. - /// - /// Context to evaluate expressions against. - /// Current expression evaluation context. - /// - /// true if the left operand is contained within the right operand, false otherwise. - /// - protected override object Get(object context, EvaluationContext evalContext) - { - object value = GetLeftValue(context, evalContext); - IList range = GetRightValue(context, evalContext) as IList; + object low = range[0]; + object high = range[1]; - if (range == null || range.Count != 2) - { - throw new ArgumentException("Right operand for the 'between' operator has to be a two-element list."); - } - - object low = range[0]; - object high = range[1]; - - return (CompareUtils.Compare(value, low) >= 0 && CompareUtils.Compare(value, high) <= 0); - } + return (CompareUtils.Compare(value, low) >= 0 && CompareUtils.Compare(value, high) <= 0); } } diff --git a/src/Spring/Spring.Core/Expressions/OpDIVIDE.cs b/src/Spring/Spring.Core/Expressions/OpDIVIDE.cs index ff6eca6c..1b20a1dc 100644 --- a/src/Spring/Spring.Core/Expressions/OpDIVIDE.cs +++ b/src/Spring/Spring.Core/Expressions/OpDIVIDE.cs @@ -21,53 +21,52 @@ using System.Runtime.Serialization; using Spring.Util; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// Represents arithmetic division operator. +/// +/// Aleksandar Seovic +[Serializable] +public class OpDIVIDE : BinaryOperator { /// - /// Represents arithmetic division operator. + /// Create a new instance /// - /// Aleksandar Seovic - [Serializable] - public class OpDIVIDE : BinaryOperator + public OpDIVIDE() { - /// - /// Create a new instance - /// - public OpDIVIDE() + } + + /// + /// Create a new instance from SerializationInfo + /// + protected OpDIVIDE(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + + /// + /// Returns a value for the arithmetic division operator node. + /// + /// Context to evaluate expressions against. + /// Current expression evaluation context. + /// Node's value. + protected override object Get(object context, EvaluationContext evalContext) + { + object left = GetLeftValue(context, evalContext); + object right = GetRightValue(context, evalContext); + + if (NumberUtils.IsNumber(left) && NumberUtils.IsNumber(right)) { + return NumberUtils.Divide(left, right); } - - /// - /// Create a new instance from SerializationInfo - /// - protected OpDIVIDE(SerializationInfo info, StreamingContext context) - : base(info, context) + else { - } - - /// - /// Returns a value for the arithmetic division operator node. - /// - /// Context to evaluate expressions against. - /// Current expression evaluation context. - /// Node's value. - protected override object Get(object context, EvaluationContext evalContext) - { - object left = GetLeftValue(context, evalContext); - object right = GetRightValue(context, evalContext); - - if (NumberUtils.IsNumber(left) && NumberUtils.IsNumber(right)) - { - return NumberUtils.Divide(left, right); - } - else - { - throw new ArgumentException("Cannot divide instances of '" - + left.GetType().FullName - + "' and '" - + right.GetType().FullName - + "'."); - } + throw new ArgumentException("Cannot divide instances of '" + + left.GetType().FullName + + "' and '" + + right.GetType().FullName + + "'."); } } } diff --git a/src/Spring/Spring.Core/Expressions/OpEqual.cs b/src/Spring/Spring.Core/Expressions/OpEqual.cs index c1d28038..d9fed1ce 100644 --- a/src/Spring/Spring.Core/Expressions/OpEqual.cs +++ b/src/Spring/Spring.Core/Expressions/OpEqual.cs @@ -21,72 +21,71 @@ using System.Runtime.Serialization; using Spring.Util; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// Represents logical equality operator. +/// +/// Aleksandar Seovic +[Serializable] +public class OpEqual : BinaryOperator { /// - /// Represents logical equality operator. + /// Create a new instance /// - /// Aleksandar Seovic - [Serializable] - public class OpEqual : BinaryOperator + public OpEqual() { - /// - /// Create a new instance - /// - public OpEqual() + } + + /// + /// Create a new instance from SerializationInfo + /// + protected OpEqual(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + + /// + /// Returns a value for the logical equality operator node. + /// + /// Context to evaluate expressions against. + /// Current expression evaluation context. + /// Node's value. + protected override object Get(object context, EvaluationContext evalContext) + { + object left = GetLeftValue(context, evalContext); + object right = GetRightValue(context, evalContext); + + if (left == null) { + return (right == null); } - - /// - /// Create a new instance from SerializationInfo - /// - protected OpEqual(SerializationInfo info, StreamingContext context) - : base(info, context) + else if (right == null) { + return false; } - - /// - /// Returns a value for the logical equality operator node. - /// - /// Context to evaluate expressions against. - /// Current expression evaluation context. - /// Node's value. - protected override object Get(object context, EvaluationContext evalContext) + else if (left.GetType() == right.GetType()) { - object left = GetLeftValue(context, evalContext); - object right = GetRightValue(context, evalContext); - - if (left == null) + if (left is Array) { - return (right == null); - } - else if (right == null) - { - return false; - } - else if (left.GetType() == right.GetType()) - { - if (left is Array) - { - return ArrayUtils.AreEqual(left as Array, right as Array); - } - else - { - return left.Equals(right); - } - } - else if (left.GetType().IsEnum && right is string) - { - return left.Equals(Enum.Parse(left.GetType(), (string)right)); - } - else if (right.GetType().IsEnum && left is string) - { - return right.Equals(Enum.Parse(right.GetType(), (string)left)); + return ArrayUtils.AreEqual(left as Array, right as Array); } else { - return CompareUtils.Compare(left, right) == 0; + return left.Equals(right); } } + else if (left.GetType().IsEnum && right is string) + { + return left.Equals(Enum.Parse(left.GetType(), (string) right)); + } + else if (right.GetType().IsEnum && left is string) + { + return right.Equals(Enum.Parse(right.GetType(), (string) left)); + } + else + { + return CompareUtils.Compare(left, right) == 0; + } } } diff --git a/src/Spring/Spring.Core/Expressions/OpGreater.cs b/src/Spring/Spring.Core/Expressions/OpGreater.cs index a42707fc..657f2c37 100644 --- a/src/Spring/Spring.Core/Expressions/OpGreater.cs +++ b/src/Spring/Spring.Core/Expressions/OpGreater.cs @@ -21,42 +21,41 @@ using System.Runtime.Serialization; using Spring.Util; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// Represents logical "greater than" operator. +/// +/// Aleksandar Seovic +[Serializable] +public class OpGreater : BinaryOperator { /// - /// Represents logical "greater than" operator. + /// Create a new instance /// - /// Aleksandar Seovic - [Serializable] - public class OpGreater : BinaryOperator + public OpGreater() : base() { - /// - /// Create a new instance - /// - public OpGreater():base() - { - } + } - /// - /// Create a new instance from SerializationInfo - /// - protected OpGreater(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } + /// + /// Create a new instance from SerializationInfo + /// + protected OpGreater(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } - /// - /// Returns a value for the logical "greater than" operator node. - /// - /// Context to evaluate expressions against. - /// Current expression evaluation context. - /// Node's value. - protected override object Get(object context, EvaluationContext evalContext) - { - object left = GetLeftValue(context, evalContext); - object right = GetRightValue(context, evalContext); + /// + /// Returns a value for the logical "greater than" operator node. + /// + /// Context to evaluate expressions against. + /// Current expression evaluation context. + /// Node's value. + protected override object Get(object context, EvaluationContext evalContext) + { + object left = GetLeftValue(context, evalContext); + object right = GetRightValue(context, evalContext); - return CompareUtils.Compare(left, right) > 0; - } + return CompareUtils.Compare(left, right) > 0; } } diff --git a/src/Spring/Spring.Core/Expressions/OpGreaterOrEqual.cs b/src/Spring/Spring.Core/Expressions/OpGreaterOrEqual.cs index b4686a71..8a6bcd28 100644 --- a/src/Spring/Spring.Core/Expressions/OpGreaterOrEqual.cs +++ b/src/Spring/Spring.Core/Expressions/OpGreaterOrEqual.cs @@ -21,42 +21,41 @@ using System.Runtime.Serialization; using Spring.Util; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// Represents logical "greater than or equal" operator. +/// +/// Aleksandar Seovic +[Serializable] +public class OpGreaterOrEqual : BinaryOperator { /// - /// Represents logical "greater than or equal" operator. + /// Create a new instance /// - /// Aleksandar Seovic - [Serializable] - public class OpGreaterOrEqual : BinaryOperator + public OpGreaterOrEqual() : base() { - /// - /// Create a new instance - /// - public OpGreaterOrEqual():base() - { - } + } - /// - /// Create a new instance from SerializationInfo - /// - protected OpGreaterOrEqual(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } + /// + /// Create a new instance from SerializationInfo + /// + protected OpGreaterOrEqual(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } - /// - /// Returns a value for the logical "greater than or equal" operator node. - /// - /// Context to evaluate expressions against. - /// Current expression evaluation context. - /// Node's value. - protected override object Get(object context, EvaluationContext evalContext) - { - object left = GetLeftValue( context, evalContext ); - object right = GetRightValue( context, evalContext ); + /// + /// Returns a value for the logical "greater than or equal" operator node. + /// + /// Context to evaluate expressions against. + /// Current expression evaluation context. + /// Node's value. + protected override object Get(object context, EvaluationContext evalContext) + { + object left = GetLeftValue(context, evalContext); + object right = GetRightValue(context, evalContext); - return CompareUtils.Compare(left, right) >= 0; - } + return CompareUtils.Compare(left, right) >= 0; } } diff --git a/src/Spring/Spring.Core/Expressions/OpIn.cs b/src/Spring/Spring.Core/Expressions/OpIn.cs index 630455c7..126fc097 100644 --- a/src/Spring/Spring.Core/Expressions/OpIn.cs +++ b/src/Spring/Spring.Core/Expressions/OpIn.cs @@ -21,60 +21,59 @@ using System.Collections; using System.Runtime.Serialization; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// Represents logical IN operator. +/// +/// Aleksandar Seovic +[Serializable] +public class OpIn : BinaryOperator { /// - /// Represents logical IN operator. + /// Create a new instance /// - /// Aleksandar Seovic - [Serializable] - public class OpIn : BinaryOperator + public OpIn() : base() { - /// - /// Create a new instance - /// - public OpIn():base() + } + + /// + /// Create a new instance from SerializationInfo + /// + protected OpIn(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + + /// + /// Returns a value for the logical IN operator node. + /// + /// Context to evaluate expressions against. + /// Current expression evaluation context. + /// + /// true if the left operand is contained within the right operand, false otherwise. + /// + protected override object Get(object context, EvaluationContext evalContext) + { + object left = GetLeftValue(context, evalContext); + object right = GetRightValue(context, evalContext); + + if (right == null) { + return false; } - - /// - /// Create a new instance from SerializationInfo - /// - protected OpIn(SerializationInfo info, StreamingContext context) - : base(info, context) + else if (right is IList) { + return ((IList) right).Contains(left); } - - /// - /// Returns a value for the logical IN operator node. - /// - /// Context to evaluate expressions against. - /// Current expression evaluation context. - /// - /// true if the left operand is contained within the right operand, false otherwise. - /// - protected override object Get(object context, EvaluationContext evalContext) + else if (right is IDictionary) { - object left = GetLeftValue( context, evalContext ); - object right = GetRightValue( context, evalContext ); - - if (right == null) - { - return false; - } - else if (right is IList) - { - return ((IList) right).Contains(left); - } - else if (right is IDictionary) - { - return ((IDictionary) right).Contains(left); - } - else - { - throw new ArgumentException( - "Right hand parameter for 'in' operator has to be an instance of IList or IDictionary."); - } + return ((IDictionary) right).Contains(left); + } + else + { + throw new ArgumentException( + "Right hand parameter for 'in' operator has to be an instance of IList or IDictionary."); } } } diff --git a/src/Spring/Spring.Core/Expressions/OpIs.cs b/src/Spring/Spring.Core/Expressions/OpIs.cs index 3435e16c..0a1822d8 100644 --- a/src/Spring/Spring.Core/Expressions/OpIs.cs +++ b/src/Spring/Spring.Core/Expressions/OpIs.cs @@ -20,48 +20,48 @@ using System.Runtime.Serialization; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// Represents logical IS operator. +/// +/// Aleksandar Seovic +[Serializable] +public class OpIs : BinaryOperator { /// - /// Represents logical IS operator. + /// Create a new instance /// - /// Aleksandar Seovic - [Serializable] - public class OpIs : BinaryOperator + public OpIs() : base() { - /// - /// Create a new instance - /// - public OpIs():base() - { - } - - /// - /// Create a new instance from SerializationInfo - /// - protected OpIs(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } - - /// - /// Returns a value for the logical IS operator node. - /// - /// Context to evaluate expressions against. - /// Current expression evaluation context. - /// - /// true if the left operand is contained within the right operand, false otherwise. - /// - protected override object Get(object context, EvaluationContext evalContext) - { - object instance = GetLeftValue( context, evalContext ); - Type type = GetRightValue( context, evalContext ) as Type; - - if (instance == null || type == null) - { - return false; - } - return type.IsAssignableFrom(instance.GetType()); - } } -} + + /// + /// Create a new instance from SerializationInfo + /// + protected OpIs(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + + /// + /// Returns a value for the logical IS operator node. + /// + /// Context to evaluate expressions against. + /// Current expression evaluation context. + /// + /// true if the left operand is contained within the right operand, false otherwise. + /// + protected override object Get(object context, EvaluationContext evalContext) + { + object instance = GetLeftValue(context, evalContext); + Type type = GetRightValue(context, evalContext) as Type; + + if (instance == null || type == null) + { + return false; + } + + return type.IsAssignableFrom(instance.GetType()); + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Expressions/OpLess.cs b/src/Spring/Spring.Core/Expressions/OpLess.cs index 999133a0..94401072 100644 --- a/src/Spring/Spring.Core/Expressions/OpLess.cs +++ b/src/Spring/Spring.Core/Expressions/OpLess.cs @@ -21,42 +21,41 @@ using System.Runtime.Serialization; using Spring.Util; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// Represents logical "less than" operator. +/// +/// Aleksandar Seovic +[Serializable] +public class OpLess : BinaryOperator { /// - /// Represents logical "less than" operator. + /// Create a new instance /// - /// Aleksandar Seovic - [Serializable] - public class OpLess : BinaryOperator + public OpLess() : base() { - /// - /// Create a new instance - /// - public OpLess():base() - { - } + } - /// - /// Create a new instance from SerializationInfo - /// - protected OpLess(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } + /// + /// Create a new instance from SerializationInfo + /// + protected OpLess(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } - /// - /// Returns a value for the logical "less than" operator node. - /// - /// Context to evaluate expressions against. - /// Current expression evaluation context. - /// Node's value. - protected override object Get(object context, EvaluationContext evalContext) - { - object left = GetLeftValue( context, evalContext ); - object right = GetRightValue( context, evalContext ); + /// + /// Returns a value for the logical "less than" operator node. + /// + /// Context to evaluate expressions against. + /// Current expression evaluation context. + /// Node's value. + protected override object Get(object context, EvaluationContext evalContext) + { + object left = GetLeftValue(context, evalContext); + object right = GetRightValue(context, evalContext); - return CompareUtils.Compare(left, right) < 0; - } + return CompareUtils.Compare(left, right) < 0; } } diff --git a/src/Spring/Spring.Core/Expressions/OpLessOrEqual.cs b/src/Spring/Spring.Core/Expressions/OpLessOrEqual.cs index f22f66a0..dd5a7923 100644 --- a/src/Spring/Spring.Core/Expressions/OpLessOrEqual.cs +++ b/src/Spring/Spring.Core/Expressions/OpLessOrEqual.cs @@ -21,42 +21,41 @@ using System.Runtime.Serialization; using Spring.Util; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// Represents logical "less than or equal" operator. +/// +/// Aleksandar Seovic +[Serializable] +public class OpLessOrEqual : BinaryOperator { /// - /// Represents logical "less than or equal" operator. + /// Create a new instance /// - /// Aleksandar Seovic - [Serializable] - public class OpLessOrEqual : BinaryOperator + public OpLessOrEqual() : base() { - /// - /// Create a new instance - /// - public OpLessOrEqual():base() - { - } + } - /// - /// Create a new instance from SerializationInfo - /// - protected OpLessOrEqual(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } + /// + /// Create a new instance from SerializationInfo + /// + protected OpLessOrEqual(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } - /// - /// Returns a value for the logical "less than or equal" operator node. - /// - /// Context to evaluate expressions against. - /// Current expression evaluation context. - /// Node's value. - protected override object Get(object context, EvaluationContext evalContext) - { - object left = GetLeftValue( context, evalContext ); - object right = GetRightValue( context, evalContext ); + /// + /// Returns a value for the logical "less than or equal" operator node. + /// + /// Context to evaluate expressions against. + /// Current expression evaluation context. + /// Node's value. + protected override object Get(object context, EvaluationContext evalContext) + { + object left = GetLeftValue(context, evalContext); + object right = GetRightValue(context, evalContext); - return CompareUtils.Compare(left, right) <= 0; - } + return CompareUtils.Compare(left, right) <= 0; } } diff --git a/src/Spring/Spring.Core/Expressions/OpLike.cs b/src/Spring/Spring.Core/Expressions/OpLike.cs index 7767e64b..fcab9330 100644 --- a/src/Spring/Spring.Core/Expressions/OpLike.cs +++ b/src/Spring/Spring.Core/Expressions/OpLike.cs @@ -22,134 +22,137 @@ using System.Runtime.Serialization; using System.Text; using System.Text.RegularExpressions; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// Represents VB-style logical LIKE operator. +/// +/// Aleksandar Seovic +[Serializable] +public class OpLike : BinaryOperator { /// - /// Represents VB-style logical LIKE operator. + /// Create a new instance /// - /// Aleksandar Seovic - [Serializable] - public class OpLike : BinaryOperator + public OpLike() { - /// - /// Create a new instance - /// - public OpLike() + } + + /// + /// Create a new instance from SerializationInfo + /// + protected OpLike(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + + /// + /// Returns a value for the logical LIKE operator node. + /// + /// Context to evaluate expressions against. + /// Current expression evaluation context. + /// + /// true if the left operand matches the right operand, false otherwise. + /// + protected override object Get(object context, EvaluationContext evalContext) + { + string text = GetLeftValue(context, evalContext) as string; + string pattern = GetRightValue(context, evalContext) as string; + + return LikeString(text, pattern); + } + + private static bool LikeString(string Source, string Pattern) + { + if (string.IsNullOrEmpty(Source) && string.IsNullOrEmpty(Pattern)) { + return true; + // LAMESPEC : MSDN states "if either string or pattern is an empty string, the result is False." + // but "" Like "[]" returns True } - /// - /// Create a new instance from SerializationInfo - /// - protected OpLike(SerializationInfo info, StreamingContext context) - : base(info, context) + if ((string.IsNullOrEmpty(Source) || string.IsNullOrEmpty(Pattern)) && string.Compare(Pattern, "[]") != 0) { + return false; } - /// - /// Returns a value for the logical LIKE operator node. - /// - /// Context to evaluate expressions against. - /// Current expression evaluation context. - /// - /// true if the left operand matches the right operand, false otherwise. - /// - protected override object Get(object context, EvaluationContext evalContext) - { - string text = GetLeftValue(context, evalContext) as string; - string pattern = GetRightValue(context, evalContext) as string; + RegexOptions options = RegexOptions.Singleline | RegexOptions.CultureInvariant | RegexOptions.IgnoreCase; - return LikeString(text, pattern); - } + string regexString = ConvertLikeExpression(Pattern); + Regex regexpr = new Regex(regexString, options); - private static bool LikeString(string Source, string Pattern) + //Console.WriteLine("{0} --> {1}", Pattern, regexString) + + return regexpr.IsMatch(Source); + } + + private static string ConvertLikeExpression(string expression) + { + StringBuilder sb = new StringBuilder(); + + sb.Append("^"); + + for (int pos = 0; pos <= expression.Length - 1; pos++) { - if (string.IsNullOrEmpty(Source) && string.IsNullOrEmpty(Pattern)) + switch (expression[pos]) { - return true; - // LAMESPEC : MSDN states "if either string or pattern is an empty string, the result is False." - // but "" Like "[]" returns True + case '?': + sb.Append('.'); + break; + case '*': + sb.Append('.').Append('*'); + break; + case '#': + sb.Append("\\d{1}"); + break; + case '[': + StringBuilder gsb = ConvertGroupSubexpression(expression, ref pos); + // skip groups of form [], i.e. empty strings + if (gsb.Length > 2) + { + sb.Append(gsb); + } + + break; + default: + sb.Append(Regex.Escape(expression[pos].ToString())); + break; + } + } + + sb.Append("$"); + + return sb.ToString(); + } + + private static StringBuilder ConvertGroupSubexpression(string carr, ref int pos) + { + StringBuilder sb = new StringBuilder(); + bool negate = false; + + while (carr[pos] != ']') + { + if (negate) + { + sb.Append('^'); + negate = false; } - if ((string.IsNullOrEmpty(Source) || string.IsNullOrEmpty(Pattern)) && string.Compare(Pattern, "[]") != 0) + if (carr[pos] == '!') { - return false; + sb.Remove(1, sb.Length - 1); + negate = true; + } + else + { + sb.Append(carr[pos]); } - RegexOptions options = RegexOptions.Singleline | RegexOptions.CultureInvariant | RegexOptions.IgnoreCase; - - string regexString = ConvertLikeExpression(Pattern); - Regex regexpr = new Regex(regexString, options); - - //Console.WriteLine("{0} --> {1}", Pattern, regexString) - - return regexpr.IsMatch(Source); + pos = pos + 1; } - private static string ConvertLikeExpression(string expression) - { - StringBuilder sb = new StringBuilder(); + sb.Append(']'); - sb.Append("^"); - - for (int pos = 0; pos <= expression.Length - 1; pos++) - { - switch (expression[pos]) - { - case '?': - sb.Append('.'); - break; - case '*': - sb.Append('.').Append('*'); - break; - case '#': - sb.Append("\\d{1}"); - break; - case '[': - StringBuilder gsb = ConvertGroupSubexpression(expression, ref pos); - // skip groups of form [], i.e. empty strings - if (gsb.Length > 2) - { - sb.Append(gsb); - } - break; - default: - sb.Append(Regex.Escape(expression[pos].ToString())); - break; - } - } - - sb.Append("$"); - - return sb.ToString(); - } - - private static StringBuilder ConvertGroupSubexpression(string carr, ref int pos) - { - StringBuilder sb = new StringBuilder(); - bool negate = false; - - while (carr[pos] != ']') - { - if (negate) - { - sb.Append('^'); - negate = false; - } - if (carr[pos] == '!') - { - sb.Remove(1, sb.Length - 1); - negate = true; - } - else - { - sb.Append(carr[pos]); - } - pos = pos + 1; - } - sb.Append(']'); - - return sb; - } + return sb; } } diff --git a/src/Spring/Spring.Core/Expressions/OpMODULUS.cs b/src/Spring/Spring.Core/Expressions/OpMODULUS.cs index 02040bb4..7b497a60 100644 --- a/src/Spring/Spring.Core/Expressions/OpMODULUS.cs +++ b/src/Spring/Spring.Core/Expressions/OpMODULUS.cs @@ -21,53 +21,52 @@ using System.Runtime.Serialization; using Spring.Util; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// Represents arithmetic modulus operator. +/// +/// Aleksandar Seovic +[Serializable] +public class OpMODULUS : BinaryOperator { /// - /// Represents arithmetic modulus operator. + /// Create a new instance /// - /// Aleksandar Seovic - [Serializable] - public class OpMODULUS : BinaryOperator + public OpMODULUS() : base() { - /// - /// Create a new instance - /// - public OpMODULUS():base() + } + + /// + /// Create a new instance from SerializationInfo + /// + protected OpMODULUS(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + + /// + /// Returns a value for the arithmetic modulus operator node. + /// + /// Context to evaluate expressions against. + /// Current expression evaluation context. + /// Node's value. + protected override object Get(object context, EvaluationContext evalContext) + { + object leftVal = GetLeftValue(context, evalContext); + object rightVal = GetRightValue(context, evalContext); + + if (NumberUtils.IsNumber(leftVal) && NumberUtils.IsNumber(rightVal)) { + return NumberUtils.Modulus(leftVal, rightVal); } - - /// - /// Create a new instance from SerializationInfo - /// - protected OpMODULUS(SerializationInfo info, StreamingContext context) - : base(info, context) + else { - } - - /// - /// Returns a value for the arithmetic modulus operator node. - /// - /// Context to evaluate expressions against. - /// Current expression evaluation context. - /// Node's value. - protected override object Get(object context, EvaluationContext evalContext) - { - object leftVal = GetLeftValue(context, evalContext ); - object rightVal = GetRightValue(context, evalContext ); - - if (NumberUtils.IsNumber(leftVal) && NumberUtils.IsNumber(rightVal)) - { - return NumberUtils.Modulus(leftVal, rightVal); - } - else - { - throw new ArgumentException("Cannot calculate modulus for instances of '" - + leftVal.GetType().FullName - + "' and '" - + rightVal.GetType().FullName - + "'."); - } + throw new ArgumentException("Cannot calculate modulus for instances of '" + + leftVal.GetType().FullName + + "' and '" + + rightVal.GetType().FullName + + "'."); } } } diff --git a/src/Spring/Spring.Core/Expressions/OpMULTIPLY.cs b/src/Spring/Spring.Core/Expressions/OpMULTIPLY.cs index 59d2d74c..6fad20ad 100644 --- a/src/Spring/Spring.Core/Expressions/OpMULTIPLY.cs +++ b/src/Spring/Spring.Core/Expressions/OpMULTIPLY.cs @@ -23,102 +23,104 @@ using System.Runtime.Serialization; using Spring.Collections; using Spring.Util; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// Represents arithmetic multiplication operator. +/// +/// Aleksandar Seovic +[Serializable] +public class OpMULTIPLY : BinaryOperator { /// - /// Represents arithmetic multiplication operator. + /// Create a new instance /// - /// Aleksandar Seovic - [Serializable] - public class OpMULTIPLY : BinaryOperator + public OpMULTIPLY() : base() { - /// - /// Create a new instance - /// - public OpMULTIPLY():base() - { - } + } - /// - /// Create a new instance from SerializationInfo - /// - protected OpMULTIPLY(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } - - /// - /// Returns a value for the arithmetic multiplication operator node. - /// - /// Context to evaluate expressions against. - /// Current expression evaluation context. - /// Node's value. - protected override object Get(object context, EvaluationContext evalContext) - { - object left = GetLeftValue( context, evalContext ); - object right = GetRightValue( context, evalContext ); + /// + /// Create a new instance from SerializationInfo + /// + protected OpMULTIPLY(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } - if (NumberUtils.IsNumber(left) && NumberUtils.IsNumber(right)) + /// + /// Returns a value for the arithmetic multiplication operator node. + /// + /// Context to evaluate expressions against. + /// Current expression evaluation context. + /// Node's value. + protected override object Get(object context, EvaluationContext evalContext) + { + object left = GetLeftValue(context, evalContext); + object right = GetRightValue(context, evalContext); + + if (NumberUtils.IsNumber(left) && NumberUtils.IsNumber(right)) + { + return NumberUtils.Multiply(left, right); + } + else if (left is IList || left is ISet) + { + ISet leftset = new HybridSet(left as ICollection); + ISet rightset; + if (right is IList || right is ISet) { - return NumberUtils.Multiply(left, right); + rightset = new HybridSet(right as ICollection); } - else if (left is IList || left is ISet) + else if (right is IDictionary) { - ISet leftset = new HybridSet(left as ICollection); - ISet rightset; - if (right is IList || right is ISet) - { - rightset = new HybridSet(right as ICollection); - } - else if (right is IDictionary) - { - rightset = new HybridSet(((IDictionary)right).Keys); - } - else - { - throw new ArgumentException("Cannot subtract instances of '" - + left.GetType().FullName - + "' and '" - + right.GetType().FullName - + "'."); - } - return leftset.Intersect(rightset); - } - else if (left is IDictionary) - { - ISet leftset = new HybridSet(((IDictionary)left).Keys); - ISet rightset; - if (right is IList || right is ISet) - { - rightset = new HybridSet(right as ICollection); - } - else if (right is IDictionary) - { - rightset = new HybridSet(((IDictionary)right).Keys); - } - else - { - throw new ArgumentException("Cannot subtract instances of '" - + left.GetType().FullName - + "' and '" - + right.GetType().FullName - + "'."); - } - IDictionary result = new Hashtable(rightset.Count); - foreach (object key in leftset.Intersect(rightset)) - { - result.Add(key, ((IDictionary)left)[key]); - } - return result; + rightset = new HybridSet(((IDictionary) right).Keys); } else { - throw new ArgumentException("Cannot multiply instances of '" + throw new ArgumentException("Cannot subtract instances of '" + left.GetType().FullName + "' and '" + right.GetType().FullName + "'."); } + + return leftset.Intersect(rightset); + } + else if (left is IDictionary) + { + ISet leftset = new HybridSet(((IDictionary) left).Keys); + ISet rightset; + if (right is IList || right is ISet) + { + rightset = new HybridSet(right as ICollection); + } + else if (right is IDictionary) + { + rightset = new HybridSet(((IDictionary) right).Keys); + } + else + { + throw new ArgumentException("Cannot subtract instances of '" + + left.GetType().FullName + + "' and '" + + right.GetType().FullName + + "'."); + } + + IDictionary result = new Hashtable(rightset.Count); + foreach (object key in leftset.Intersect(rightset)) + { + result.Add(key, ((IDictionary) left)[key]); + } + + return result; + } + else + { + throw new ArgumentException("Cannot multiply instances of '" + + left.GetType().FullName + + "' and '" + + right.GetType().FullName + + "'."); } } } diff --git a/src/Spring/Spring.Core/Expressions/OpMatches.cs b/src/Spring/Spring.Core/Expressions/OpMatches.cs index 2463012d..ed0ca429 100644 --- a/src/Spring/Spring.Core/Expressions/OpMatches.cs +++ b/src/Spring/Spring.Core/Expressions/OpMatches.cs @@ -21,56 +21,55 @@ using System.Runtime.Serialization; using System.Text.RegularExpressions; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// Represents logical MATCHES operator. +/// +/// Aleksandar Seovic +[Serializable] +public class OpMatches : BinaryOperator { + private Regex regex; + /// - /// Represents logical MATCHES operator. + /// Create a new instance /// - /// Aleksandar Seovic - [Serializable] - public class OpMatches : BinaryOperator + public OpMatches() : base() { - private Regex regex; + } - /// - /// Create a new instance - /// - public OpMatches():base() - { - } + /// + /// Create a new instance from SerializationInfo + /// + protected OpMatches(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } - /// - /// Create a new instance from SerializationInfo - /// - protected OpMatches(SerializationInfo info, StreamingContext context) - : base(info, context) + /// + /// Returns a value for the logical MATCHES operator node. + /// + /// Context to evaluate expressions against. + /// Current expression evaluation context. + /// + /// true if the left operand matches the right operand, false otherwise. + /// + protected override object Get(object context, EvaluationContext evalContext) + { + if (regex == null) { - } - - /// - /// Returns a value for the logical MATCHES operator node. - /// - /// Context to evaluate expressions against. - /// Current expression evaluation context. - /// - /// true if the left operand matches the right operand, false otherwise. - /// - protected override object Get(object context, EvaluationContext evalContext) - { - if (regex == null) + lock (this) { - lock (this) + if (regex == null) { - if (regex == null) - { - string pattern = GetRightValue( context, evalContext ) as string; - regex = new Regex(pattern, RegexOptions.Compiled); - } + string pattern = GetRightValue(context, evalContext) as string; + regex = new Regex(pattern, RegexOptions.Compiled); } } - - string text = GetLeftValue( context, evalContext ) as string; - return regex.IsMatch(text); } + + string text = GetLeftValue(context, evalContext) as string; + return regex.IsMatch(text); } } diff --git a/src/Spring/Spring.Core/Expressions/OpNOT.cs b/src/Spring/Spring.Core/Expressions/OpNOT.cs index 987a1f56..5cd83403 100644 --- a/src/Spring/Spring.Core/Expressions/OpNOT.cs +++ b/src/Spring/Spring.Core/Expressions/OpNOT.cs @@ -21,61 +21,60 @@ using System.Runtime.Serialization; using Spring.Util; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// Represents NOT operator (both, bitwise and logical). +/// +/// Aleksandar Seovic +[Serializable] +public class OpNOT : UnaryOperator { /// - /// Represents NOT operator (both, bitwise and logical). + /// Create a new instance /// - /// Aleksandar Seovic - [Serializable] - public class OpNOT : UnaryOperator + public OpNOT() : base() { - /// - /// Create a new instance - /// - public OpNOT():base() - { - } + } - /// - /// Create a new instance - /// - public OpNOT(BaseNode operand) - :base(operand) - { - } + /// + /// Create a new instance + /// + public OpNOT(BaseNode operand) + : base(operand) + { + } - /// - /// Create a new instance from SerializationInfo - /// - protected OpNOT(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } + /// + /// Create a new instance from SerializationInfo + /// + protected OpNOT(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } - /// - /// Returns a value for the logical NOT operator node. - /// - /// Context to evaluate expressions against. - /// Current expression evaluation context. - /// Node's value. - protected override object Get(object context, EvaluationContext evalContext) + /// + /// Returns a value for the logical NOT operator node. + /// + /// Context to evaluate expressions against. + /// Current expression evaluation context. + /// Node's value. + protected override object Get(object context, EvaluationContext evalContext) + { + object operand = GetValue(Operand, context, evalContext); + if (NumberUtils.IsInteger(operand)) { - object operand = GetValue(Operand, context, evalContext); - if (NumberUtils.IsInteger(operand)) - { - return NumberUtils.BitwiseNot(operand); - } - else if (operand is Enum) - { - Type enumType = operand.GetType(); - Type integralType = Enum.GetUnderlyingType(enumType); - operand = Convert.ChangeType(operand, integralType); - object result = NumberUtils.BitwiseNot(operand); - return Enum.ToObject(enumType, result); - } - else - return !Convert.ToBoolean(operand); + return NumberUtils.BitwiseNot(operand); } + else if (operand is Enum) + { + Type enumType = operand.GetType(); + Type integralType = Enum.GetUnderlyingType(enumType); + operand = Convert.ChangeType(operand, integralType); + object result = NumberUtils.BitwiseNot(operand); + return Enum.ToObject(enumType, result); + } + else + return !Convert.ToBoolean(operand); } } diff --git a/src/Spring/Spring.Core/Expressions/OpNotEqual.cs b/src/Spring/Spring.Core/Expressions/OpNotEqual.cs index 0011e808..27e41354 100644 --- a/src/Spring/Spring.Core/Expressions/OpNotEqual.cs +++ b/src/Spring/Spring.Core/Expressions/OpNotEqual.cs @@ -21,64 +21,63 @@ using System.Runtime.Serialization; using Spring.Util; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// Represents logical inequality operator. +/// +/// Aleksandar Seovic +[Serializable] +public class OpNotEqual : BinaryOperator { /// - /// Represents logical inequality operator. + /// Create a new instance /// - /// Aleksandar Seovic - [Serializable] - public class OpNotEqual : BinaryOperator + public OpNotEqual() : base() { - /// - /// Create a new instance - /// - public OpNotEqual():base() + } + + /// + /// Create a new instance from SerializationInfo + /// + protected OpNotEqual(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + + /// + /// Returns a value for the logical inequality operator node. + /// + /// Context to evaluate expressions against. + /// Current expression evaluation context. + /// Node's value. + protected override object Get(object context, EvaluationContext evalContext) + { + object leftVal = GetLeftValue(context, evalContext); + object rightVal = GetRightValue(context, evalContext); + + if (leftVal == null) { + return (rightVal != null); } - - /// - /// Create a new instance from SerializationInfo - /// - protected OpNotEqual(SerializationInfo info, StreamingContext context) - : base(info, context) + else if (rightVal == null) { + return true; } - - /// - /// Returns a value for the logical inequality operator node. - /// - /// Context to evaluate expressions against. - /// Current expression evaluation context. - /// Node's value. - protected override object Get(object context, EvaluationContext evalContext) + else if (leftVal.GetType() == rightVal.GetType()) { - object leftVal = GetLeftValue( context, evalContext ); - object rightVal = GetRightValue( context, evalContext ); - - if (leftVal == null) + if (leftVal is Array) { - return (rightVal != null); - } - else if (rightVal == null) - { - return true; - } - else if (leftVal.GetType() == rightVal.GetType()) - { - if (leftVal is Array) - { - return !ArrayUtils.AreEqual(leftVal as Array, rightVal as Array); - } - else - { - return !leftVal.Equals(rightVal); - } + return !ArrayUtils.AreEqual(leftVal as Array, rightVal as Array); } else { - return CompareUtils.Compare(leftVal, rightVal) != 0; + return !leftVal.Equals(rightVal); } } + else + { + return CompareUtils.Compare(leftVal, rightVal) != 0; + } } -} +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Expressions/OpOR.cs b/src/Spring/Spring.Core/Expressions/OpOR.cs index fb52c4cf..a80a73d8 100644 --- a/src/Spring/Spring.Core/Expressions/OpOR.cs +++ b/src/Spring/Spring.Core/Expressions/OpOR.cs @@ -21,72 +21,71 @@ using System.Runtime.Serialization; using Spring.Util; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// Represents OR operator (both, bitwise and logical). +/// +/// Aleksandar Seovic +[Serializable] +public class OpOR : BinaryOperator { /// - /// Represents OR operator (both, bitwise and logical). + /// Create a new instance /// - /// Aleksandar Seovic - [Serializable] - public class OpOR : BinaryOperator + public OpOR() : base() { - /// - /// Create a new instance - /// - public OpOR():base() - { - } + } - /// - /// Create a new instance - /// - public OpOR(BaseNode left, BaseNode right) - :base(left, right) - { - } + /// + /// Create a new instance + /// + public OpOR(BaseNode left, BaseNode right) + : base(left, right) + { + } - /// - /// Create a new instance from SerializationInfo - /// - protected OpOR(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } + /// + /// Create a new instance from SerializationInfo + /// + protected OpOR(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } - /// - /// Returns a value for the logical OR operator node. - /// - /// Context to evaluate expressions against. - /// Current expression evaluation context. - /// Node's value. - protected override object Get(object context, EvaluationContext evalContext) - { - object l = GetLeftValue(context, evalContext); + /// + /// Returns a value for the logical OR operator node. + /// + /// Context to evaluate expressions against. + /// Current expression evaluation context. + /// Node's value. + protected override object Get(object context, EvaluationContext evalContext) + { + object l = GetLeftValue(context, evalContext); - if (NumberUtils.IsInteger(l)) + if (NumberUtils.IsInteger(l)) + { + object r = GetRightValue(context, evalContext); + if (NumberUtils.IsInteger(r)) { - object r = GetRightValue(context, evalContext); - if (NumberUtils.IsInteger(r)) - { - return NumberUtils.BitwiseOr(l, r); - } + return NumberUtils.BitwiseOr(l, r); } - else if (l is Enum) - { - object r = GetRightValue(context, evalContext); - if (l.GetType() == r.GetType()) - { - Type enumType = l.GetType(); - Type integralType = Enum.GetUnderlyingType(enumType); - l = Convert.ChangeType(l, integralType); - r = Convert.ChangeType(r, integralType); - object result = NumberUtils.BitwiseOr(l, r); - return Enum.ToObject(enumType, result); - } - } - - return Convert.ToBoolean(l) || - Convert.ToBoolean(GetRightValue(context, evalContext)); } + else if (l is Enum) + { + object r = GetRightValue(context, evalContext); + if (l.GetType() == r.GetType()) + { + Type enumType = l.GetType(); + Type integralType = Enum.GetUnderlyingType(enumType); + l = Convert.ChangeType(l, integralType); + r = Convert.ChangeType(r, integralType); + object result = NumberUtils.BitwiseOr(l, r); + return Enum.ToObject(enumType, result); + } + } + + return Convert.ToBoolean(l) || + Convert.ToBoolean(GetRightValue(context, evalContext)); } } diff --git a/src/Spring/Spring.Core/Expressions/OpPOWER.cs b/src/Spring/Spring.Core/Expressions/OpPOWER.cs index e1734ab9..ba98d2ec 100644 --- a/src/Spring/Spring.Core/Expressions/OpPOWER.cs +++ b/src/Spring/Spring.Core/Expressions/OpPOWER.cs @@ -21,53 +21,52 @@ using System.Runtime.Serialization; using Spring.Util; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// Represents arithmetic exponent operator. +/// +/// Aleksandar Seovic +[Serializable] +public class OpPOWER : BinaryOperator { /// - /// Represents arithmetic exponent operator. + /// Create a new instance /// - /// Aleksandar Seovic - [Serializable] - public class OpPOWER : BinaryOperator + public OpPOWER() : base() { - /// - /// Create a new instance - /// - public OpPOWER():base() - { - } + } - /// - /// Create a new instance from SerializationInfo - /// - protected OpPOWER(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } - - /// - /// Returns a value for the arithmetic exponent operator node. - /// - /// Context to evaluate expressions against. - /// Current expression evaluation context. - /// Node's value. - protected override object Get(object context, EvaluationContext evalContext) - { - object left = GetLeftValue( context, evalContext ); - object right = GetRightValue( context, evalContext ); + /// + /// Create a new instance from SerializationInfo + /// + protected OpPOWER(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } - if (NumberUtils.IsNumber(left) && NumberUtils.IsNumber(right)) - { - return NumberUtils.Power(left, right); - } - else - { - throw new ArgumentException("Cannot calculate exponent for the instances of '" - + left.GetType().FullName - + "' and '" - + right.GetType().FullName - + "'."); - } + /// + /// Returns a value for the arithmetic exponent operator node. + /// + /// Context to evaluate expressions against. + /// Current expression evaluation context. + /// Node's value. + protected override object Get(object context, EvaluationContext evalContext) + { + object left = GetLeftValue(context, evalContext); + object right = GetRightValue(context, evalContext); + + if (NumberUtils.IsNumber(left) && NumberUtils.IsNumber(right)) + { + return NumberUtils.Power(left, right); + } + else + { + throw new ArgumentException("Cannot calculate exponent for the instances of '" + + left.GetType().FullName + + "' and '" + + right.GetType().FullName + + "'."); } } } diff --git a/src/Spring/Spring.Core/Expressions/OpSUBTRACT.cs b/src/Spring/Spring.Core/Expressions/OpSUBTRACT.cs index 5d79f1fa..419daea5 100644 --- a/src/Spring/Spring.Core/Expressions/OpSUBTRACT.cs +++ b/src/Spring/Spring.Core/Expressions/OpSUBTRACT.cs @@ -23,118 +23,121 @@ using System.Runtime.Serialization; using Spring.Collections; using Spring.Util; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// Represents arithmetic subtraction operator. +/// +/// Aleksandar Seovic +[Serializable] +public class OpSUBTRACT : BinaryOperator { /// - /// Represents arithmetic subtraction operator. + /// Create a new instance /// - /// Aleksandar Seovic - [Serializable] - public class OpSUBTRACT : BinaryOperator + public OpSUBTRACT() : base() { - /// - /// Create a new instance - /// - public OpSUBTRACT():base() + } + + /// + /// Create a new instance from SerializationInfo + /// + protected OpSUBTRACT(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + + /// + /// Returns a value for the arithmetic subtraction operator node. + /// + /// Context to evaluate expressions against. + /// Current expression evaluation context. + /// Node's value. + protected override object Get(object context, EvaluationContext evalContext) + { + object left = GetLeftValue(context, evalContext); + object right = GetRightValue(context, evalContext); + + if (NumberUtils.IsNumber(left) && NumberUtils.IsNumber(right)) { + return NumberUtils.Subtract(left, right); } - - /// - /// Create a new instance from SerializationInfo - /// - protected OpSUBTRACT(SerializationInfo info, StreamingContext context) - : base(info, context) + else if (left is DateTime && (right is TimeSpan || right is string || NumberUtils.IsNumber(right))) { + if (NumberUtils.IsNumber(right)) + { + right = TimeSpan.FromDays(Convert.ToDouble(right)); + } + else if (right is string) + { + right = TimeSpan.Parse((string) right); + } + + return (DateTime) left - (TimeSpan) right; } - - /// - /// Returns a value for the arithmetic subtraction operator node. - /// - /// Context to evaluate expressions against. - /// Current expression evaluation context. - /// Node's value. - protected override object Get(object context, EvaluationContext evalContext) + else if (left is DateTime && right is DateTime) { - object left = GetLeftValue( context, evalContext ); - object right = GetRightValue( context, evalContext ); - - if (NumberUtils.IsNumber(left) && NumberUtils.IsNumber(right)) + return (DateTime) left - (DateTime) right; + } + else if (left is IList || left is ISet) + { + ISet leftset = new HybridSet(left as ICollection); + ISet rightset; + if (right is IList || right is ISet) { - return NumberUtils.Subtract(left, right); + rightset = new HybridSet(right as ICollection); } - else if (left is DateTime && (right is TimeSpan || right is string || NumberUtils.IsNumber(right))) + else if (right is IDictionary) { - if (NumberUtils.IsNumber(right)) - { - right = TimeSpan.FromDays(Convert.ToDouble(right)); - } - else if (right is string) - { - right = TimeSpan.Parse((string) right); - } - return (DateTime) left - (TimeSpan) right; - } - else if (left is DateTime && right is DateTime) - { - return (DateTime) left - (DateTime) right; - } - else if (left is IList || left is ISet) - { - ISet leftset = new HybridSet(left as ICollection); - ISet rightset; - if(right is IList || right is ISet) - { - rightset = new HybridSet(right as ICollection); - } - else if (right is IDictionary) - { - rightset = new HybridSet(((IDictionary) right).Keys); - } - else - { - throw new ArgumentException("Cannot subtract instances of '" - + left.GetType().FullName - + "' and '" - + right.GetType().FullName - + "'."); - } - return leftset.Minus(rightset); - } - else if (left is IDictionary) - { - ISet leftset = new HybridSet(((IDictionary) left).Keys); - ISet rightset; - if (right is IList || right is ISet) - { - rightset = new HybridSet(right as ICollection); - } - else if (right is IDictionary) - { - rightset = new HybridSet(((IDictionary) right).Keys); - } - else - { - throw new ArgumentException("Cannot subtract instances of '" - + left.GetType().FullName - + "' and '" - + right.GetType().FullName - + "'."); - } - IDictionary result = new Hashtable(rightset.Count); - foreach(object key in leftset.Minus(rightset)) - { - result.Add(key, ((IDictionary)left)[key]); - } - return result; + rightset = new HybridSet(((IDictionary) right).Keys); } else { throw new ArgumentException("Cannot subtract instances of '" - + left.GetType().FullName - + "' and '" - + right.GetType().FullName - + "'."); + + left.GetType().FullName + + "' and '" + + right.GetType().FullName + + "'."); } + + return leftset.Minus(rightset); + } + else if (left is IDictionary) + { + ISet leftset = new HybridSet(((IDictionary) left).Keys); + ISet rightset; + if (right is IList || right is ISet) + { + rightset = new HybridSet(right as ICollection); + } + else if (right is IDictionary) + { + rightset = new HybridSet(((IDictionary) right).Keys); + } + else + { + throw new ArgumentException("Cannot subtract instances of '" + + left.GetType().FullName + + "' and '" + + right.GetType().FullName + + "'."); + } + + IDictionary result = new Hashtable(rightset.Count); + foreach (object key in leftset.Minus(rightset)) + { + result.Add(key, ((IDictionary) left)[key]); + } + + return result; + } + else + { + throw new ArgumentException("Cannot subtract instances of '" + + left.GetType().FullName + + "' and '" + + right.GetType().FullName + + "'."); } } } diff --git a/src/Spring/Spring.Core/Expressions/OpUnaryMinus.cs b/src/Spring/Spring.Core/Expressions/OpUnaryMinus.cs index f0b4d912..580062b9 100644 --- a/src/Spring/Spring.Core/Expressions/OpUnaryMinus.cs +++ b/src/Spring/Spring.Core/Expressions/OpUnaryMinus.cs @@ -21,46 +21,46 @@ using System.Runtime.Serialization; using Spring.Util; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// Represents unary minus operator. +/// +/// Aleksandar Seovic +[Serializable] +public class OpUnaryMinus : UnaryOperator { /// - /// Represents unary minus operator. + /// Create a new instance /// - /// Aleksandar Seovic - [Serializable] - public class OpUnaryMinus : UnaryOperator + public OpUnaryMinus() : base() { - /// - /// Create a new instance - /// - public OpUnaryMinus():base() + } + + /// + /// Create a new instance from SerializationInfo + /// + protected OpUnaryMinus(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + + /// + /// Returns a value for the unary plus operator node. + /// + /// Context to evaluate expressions against. + /// Current expression evaluation context. + /// Node's value. + protected override object Get(object context, EvaluationContext evalContext) + { + object n = GetValue(Operand, context, evalContext); + + if (!NumberUtils.IsNumber(n)) { + throw new ArgumentException( + "Specified operand is not a number. Only numbers support unary minus operator."); } - /// - /// Create a new instance from SerializationInfo - /// - protected OpUnaryMinus(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } - - /// - /// Returns a value for the unary plus operator node. - /// - /// Context to evaluate expressions against. - /// Current expression evaluation context. - /// Node's value. - protected override object Get(object context, EvaluationContext evalContext) - { - object n = GetValue(Operand, context, evalContext ); - - if (!NumberUtils.IsNumber(n)) - { - throw new ArgumentException( - "Specified operand is not a number. Only numbers support unary minus operator."); - } - return NumberUtils.Negate(n); - } + return NumberUtils.Negate(n); } } diff --git a/src/Spring/Spring.Core/Expressions/OpUnaryPlus.cs b/src/Spring/Spring.Core/Expressions/OpUnaryPlus.cs index 5f4ffee0..e592ac6c 100644 --- a/src/Spring/Spring.Core/Expressions/OpUnaryPlus.cs +++ b/src/Spring/Spring.Core/Expressions/OpUnaryPlus.cs @@ -21,46 +21,46 @@ using System.Runtime.Serialization; using Spring.Util; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// Represents unary plus operator. +/// +/// Aleksandar Seovic +[Serializable] +public class OpUnaryPlus : UnaryOperator { /// - /// Represents unary plus operator. + /// Create a new instance /// - /// Aleksandar Seovic - [Serializable] - public class OpUnaryPlus : UnaryOperator + public OpUnaryPlus() : base() { - /// - /// Create a new instance - /// - public OpUnaryPlus():base() + } + + /// + /// Create a new instance from SerializationInfo + /// + protected OpUnaryPlus(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + + /// + /// Returns a value for the unary plus operator node. + /// + /// Context to evaluate expressions against. + /// Current expression evaluation context. + /// Node's value. + protected override object Get(object context, EvaluationContext evalContext) + { + object n = GetValue(Operand, context, evalContext); + + if (!NumberUtils.IsNumber(n)) { + throw new ArgumentException( + "Specified operand is not a number. Only numbers support unary plus operator."); } - /// - /// Create a new instance from SerializationInfo - /// - protected OpUnaryPlus(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } - - /// - /// Returns a value for the unary plus operator node. - /// - /// Context to evaluate expressions against. - /// Current expression evaluation context. - /// Node's value. - protected override object Get(object context, EvaluationContext evalContext) - { - object n = GetValue(Operand, context, evalContext); - - if (!NumberUtils.IsNumber(n)) - { - throw new ArgumentException( - "Specified operand is not a number. Only numbers support unary plus operator."); - } - return n; - } + return n; } } diff --git a/src/Spring/Spring.Core/Expressions/OpXOR.cs b/src/Spring/Spring.Core/Expressions/OpXOR.cs index fa7dce01..af45dff7 100644 --- a/src/Spring/Spring.Core/Expressions/OpXOR.cs +++ b/src/Spring/Spring.Core/Expressions/OpXOR.cs @@ -21,61 +21,62 @@ using System.Runtime.Serialization; using Spring.Util; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// +/// Erich Eichinger +[Serializable] +public class OpXOR : BinaryOperator { /// + /// Create a new instance /// - /// Erich Eichinger - [Serializable] - public class OpXOR : BinaryOperator + public OpXOR() { - /// - /// Create a new instance - /// - public OpXOR() - { } + } - /// - /// Create a new instance - /// - public OpXOR(BaseNode left, BaseNode right) - :base(left, right) + /// + /// Create a new instance + /// + public OpXOR(BaseNode left, BaseNode right) + : base(left, right) + { + } + + /// + /// Create a new instance from SerializationInfo + /// + protected OpXOR(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + + /// + /// Returns a value for the logical AND operator node. + /// + /// Context to evaluate expressions against. + /// Current expression evaluation context. + /// Node's value. + protected override object Get(object context, EvaluationContext evalContext) + { + object l = GetLeftValue(context, evalContext); + object r = GetRightValue(context, evalContext); + + if (NumberUtils.IsInteger(l) && NumberUtils.IsInteger(r)) { + return NumberUtils.BitwiseXor(l, r); + } + else if (l is Enum && l.GetType() == r.GetType()) + { + Type enumType = l.GetType(); + Type integralType = Enum.GetUnderlyingType(enumType); + l = Convert.ChangeType(l, integralType); + r = Convert.ChangeType(r, integralType); + object result = NumberUtils.BitwiseXor(l, r); + return Enum.ToObject(enumType, result); } - /// - /// Create a new instance from SerializationInfo - /// - protected OpXOR(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } - - /// - /// Returns a value for the logical AND operator node. - /// - /// Context to evaluate expressions against. - /// Current expression evaluation context. - /// Node's value. - protected override object Get(object context, EvaluationContext evalContext) - { - object l = GetLeftValue(context, evalContext); - object r = GetRightValue(context, evalContext); - - if (NumberUtils.IsInteger(l) && NumberUtils.IsInteger(r)) - { - return NumberUtils.BitwiseXor(l, r); - } - else if (l is Enum && l.GetType() == r.GetType()) - { - Type enumType = l.GetType(); - Type integralType = Enum.GetUnderlyingType(enumType); - l = Convert.ChangeType(l, integralType); - r = Convert.ChangeType(r, integralType); - object result = NumberUtils.BitwiseXor(l, r); - return Enum.ToObject(enumType, result); - } - return Convert.ToBoolean(l) ^ Convert.ToBoolean(r); - } + return Convert.ToBoolean(l) ^ Convert.ToBoolean(r); } } diff --git a/src/Spring/Spring.Core/Expressions/Parser/ExpressionLexer.cs b/src/Spring/Spring.Core/Expressions/Parser/ExpressionLexer.cs index 0760f6a1..916fad73 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/ExpressionLexer.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/ExpressionLexer.cs @@ -1,1982 +1,2402 @@ // $ANTLR 2.7.6 (2005-12-22): "Expression.g" -> "ExpressionLexer.cs"$ -namespace Spring.Expressions.Parser +namespace Spring.Expressions.Parser; + +// Generate header specific to lexer CSharp file +using Stream = System.IO.Stream; +using TextReader = System.IO.TextReader; +using Hashtable = System.Collections.Hashtable; +using Comparer = System.Collections.Comparer; +using TokenStreamException = antlr.TokenStreamException; +using TokenStreamIOException = antlr.TokenStreamIOException; +using TokenStreamRecognitionException = antlr.TokenStreamRecognitionException; +using CharStreamException = antlr.CharStreamException; +using CharStreamIOException = antlr.CharStreamIOException; +using InputBuffer = antlr.InputBuffer; +using ByteBuffer = antlr.ByteBuffer; +using CharBuffer = antlr.CharBuffer; +using Token = antlr.Token; +using IToken = antlr.IToken; +using RecognitionException = antlr.RecognitionException; +using NoViableAltForCharException = antlr.NoViableAltForCharException; +using TokenStream = antlr.TokenStream; +using LexerSharedInputState = antlr.LexerSharedInputState; +using BitSet = antlr.collections.impl.BitSet; + +internal class ExpressionLexer : antlr.CharScanner, TokenStream { - // Generate header specific to lexer CSharp file - using Stream = System.IO.Stream; - using TextReader = System.IO.TextReader; - using Hashtable = System.Collections.Hashtable; - using Comparer = System.Collections.Comparer; - - using TokenStreamException = antlr.TokenStreamException; - using TokenStreamIOException = antlr.TokenStreamIOException; - using TokenStreamRecognitionException = antlr.TokenStreamRecognitionException; - using CharStreamException = antlr.CharStreamException; - using CharStreamIOException = antlr.CharStreamIOException; - using InputBuffer = antlr.InputBuffer; - using ByteBuffer = antlr.ByteBuffer; - using CharBuffer = antlr.CharBuffer; - using Token = antlr.Token; - using IToken = antlr.IToken; - using RecognitionException = antlr.RecognitionException; - using NoViableAltForCharException = antlr.NoViableAltForCharException; - using TokenStream = antlr.TokenStream; - using LexerSharedInputState = antlr.LexerSharedInputState; - using BitSet = antlr.collections.impl.BitSet; - - internal class ExpressionLexer : antlr.CharScanner , TokenStream - { - public const int EOF = 1; - public const int NULL_TREE_LOOKAHEAD = 3; - public const int EXPR = 4; - public const int OPERAND = 5; - public const int FALSE = 6; - public const int TRUE = 7; - public const int AND = 8; - public const int OR = 9; - public const int XOR = 10; - public const int IN = 11; - public const int IS = 12; - public const int BETWEEN = 13; - public const int LIKE = 14; - public const int MATCHES = 15; - public const int NULL_LITERAL = 16; - public const int LPAREN = 17; - public const int SEMI = 18; - public const int RPAREN = 19; - public const int ASSIGN = 20; - public const int DEFAULT = 21; - public const int QMARK = 22; - public const int COLON = 23; - public const int PLUS = 24; - public const int MINUS = 25; - public const int STAR = 26; - public const int DIV = 27; - public const int MOD = 28; - public const int POWER = 29; - public const int BANG = 30; - public const int DOT = 31; - public const int POUND = 32; - public const int ID = 33; - public const int DOLLAR = 34; - public const int COMMA = 35; - public const int AT = 36; - public const int LBRACKET = 37; - public const int RBRACKET = 38; - public const int PROJECT = 39; - public const int RCURLY = 40; - public const int SELECT = 41; - public const int SELECT_FIRST = 42; - public const int SELECT_LAST = 43; - public const int TYPE = 44; - public const int QUOTE = 45; - public const int STRING_LITERAL = 46; - public const int LAMBDA = 47; - public const int PIPE = 48; - public const int LITERAL_new = 49; - public const int LCURLY = 50; - public const int INTEGER_LITERAL = 51; - public const int HEXADECIMAL_INTEGER_LITERAL = 52; - public const int REAL_LITERAL = 53; - public const int EQUAL = 54; - public const int NOT_EQUAL = 55; - public const int LESS_THAN = 56; - public const int LESS_THAN_OR_EQUAL = 57; - public const int GREATER_THAN = 58; - public const int GREATER_THAN_OR_EQUAL = 59; - public const int WS = 60; - public const int BACKTICK = 61; - public const int BACKSLASH = 62; - public const int DOT_ESCAPED = 63; - public const int APOS = 64; - public const int NUMERIC_LITERAL = 65; - public const int DECIMAL_DIGIT = 66; - public const int INTEGER_TYPE_SUFFIX = 67; - public const int HEX_DIGIT = 68; - public const int EXPONENT_PART = 69; - public const int SIGN = 70; - public const int REAL_TYPE_SUFFIX = 71; - - + public const int EOF = 1; + public const int NULL_TREE_LOOKAHEAD = 3; + public const int EXPR = 4; + public const int OPERAND = 5; + public const int FALSE = 6; + public const int TRUE = 7; + public const int AND = 8; + public const int OR = 9; + public const int XOR = 10; + public const int IN = 11; + public const int IS = 12; + public const int BETWEEN = 13; + public const int LIKE = 14; + public const int MATCHES = 15; + public const int NULL_LITERAL = 16; + public const int LPAREN = 17; + public const int SEMI = 18; + public const int RPAREN = 19; + public const int ASSIGN = 20; + public const int DEFAULT = 21; + public const int QMARK = 22; + public const int COLON = 23; + public const int PLUS = 24; + public const int MINUS = 25; + public const int STAR = 26; + public const int DIV = 27; + public const int MOD = 28; + public const int POWER = 29; + public const int BANG = 30; + public const int DOT = 31; + public const int POUND = 32; + public const int ID = 33; + public const int DOLLAR = 34; + public const int COMMA = 35; + public const int AT = 36; + public const int LBRACKET = 37; + public const int RBRACKET = 38; + public const int PROJECT = 39; + public const int RCURLY = 40; + public const int SELECT = 41; + public const int SELECT_FIRST = 42; + public const int SELECT_LAST = 43; + public const int TYPE = 44; + public const int QUOTE = 45; + public const int STRING_LITERAL = 46; + public const int LAMBDA = 47; + public const int PIPE = 48; + public const int LITERAL_new = 49; + public const int LCURLY = 50; + public const int INTEGER_LITERAL = 51; + public const int HEXADECIMAL_INTEGER_LITERAL = 52; + public const int REAL_LITERAL = 53; + public const int EQUAL = 54; + public const int NOT_EQUAL = 55; + public const int LESS_THAN = 56; + public const int LESS_THAN_OR_EQUAL = 57; + public const int GREATER_THAN = 58; + public const int GREATER_THAN_OR_EQUAL = 59; + public const int WS = 60; + public const int BACKTICK = 61; + public const int BACKSLASH = 62; + public const int DOT_ESCAPED = 63; + public const int APOS = 64; + public const int NUMERIC_LITERAL = 65; + public const int DECIMAL_DIGIT = 66; + public const int INTEGER_TYPE_SUFFIX = 67; + public const int HEX_DIGIT = 68; + public const int EXPONENT_PART = 69; + public const int SIGN = 70; + public const int REAL_TYPE_SUFFIX = 71; + // CLOVER:OFF - public ExpressionLexer(Stream ins) : this(new ByteBuffer(ins)) - { - } - - public ExpressionLexer(TextReader r) : this(new CharBuffer(r)) - { - } - - public ExpressionLexer(InputBuffer ib) : this(new LexerSharedInputState(ib)) - { - } - - public ExpressionLexer(LexerSharedInputState state) : base(state) - { - initialize(); - } - private void initialize() - { - caseSensitiveLiterals = true; - setCaseSensitive(true); - literals = new Hashtable(100, (float) 0.4, null, Comparer.Default); - literals.Add("true", 7); - literals.Add("and", 8); - literals.Add("matches", 15); - literals.Add("in", 11); - literals.Add("xor", 10); - literals.Add("null", 16); - literals.Add("between", 13); - literals.Add("or", 9); - literals.Add("is", 12); - literals.Add("like", 14); - literals.Add("new", 49); - literals.Add("false", 6); - } - - override public IToken nextToken() //throws TokenStreamException - { - IToken theRetToken = null; -tryAgain: - for (;;) - { - IToken _token = null; - int _ttype = Token.INVALID_TYPE; - resetText(); - try // for char stream error handling - { - try // for lexical error handling - { - switch ( cached_LA1 ) - { - case '\t': case '\n': case '\r': case ' ': - { - mWS(true); - theRetToken = returnToken_; - break; - } - case '@': - { - mAT(true); - theRetToken = returnToken_; - break; - } - case '`': - { - mBACKTICK(true); - theRetToken = returnToken_; - break; - } - case '|': - { - mPIPE(true); - theRetToken = returnToken_; - break; - } - case '#': - { - mPOUND(true); - theRetToken = returnToken_; - break; - } - case '(': - { - mLPAREN(true); - theRetToken = returnToken_; - break; - } - case ')': - { - mRPAREN(true); - theRetToken = returnToken_; - break; - } - case '[': - { - mLBRACKET(true); - theRetToken = returnToken_; - break; - } - case ']': - { - mRBRACKET(true); - theRetToken = returnToken_; - break; - } - case '}': - { - mRCURLY(true); - theRetToken = returnToken_; - break; - } - case ',': - { - mCOMMA(true); - theRetToken = returnToken_; - break; - } - case ';': - { - mSEMI(true); - theRetToken = returnToken_; - break; - } - case ':': - { - mCOLON(true); - theRetToken = returnToken_; - break; - } - case '+': - { - mPLUS(true); - theRetToken = returnToken_; - break; - } - case '-': - { - mMINUS(true); - theRetToken = returnToken_; - break; - } - case '/': - { - mDIV(true); - theRetToken = returnToken_; - break; - } - case '*': - { - mSTAR(true); - theRetToken = returnToken_; - break; - } - case '%': - { - mMOD(true); - theRetToken = returnToken_; - break; - } - default: - if ((cached_LA1=='?') && (cached_LA2=='?')) - { - mDEFAULT(true); - theRetToken = returnToken_; - } - else if ((cached_LA1=='=') && (cached_LA2=='=')) { - mEQUAL(true); - theRetToken = returnToken_; - } - else if ((cached_LA1=='!') && (cached_LA2=='=')) { - mNOT_EQUAL(true); - theRetToken = returnToken_; - } - else if ((cached_LA1=='<') && (cached_LA2=='=')) { - mLESS_THAN_OR_EQUAL(true); - theRetToken = returnToken_; - } - else if ((cached_LA1=='>') && (cached_LA2=='=')) { - mGREATER_THAN_OR_EQUAL(true); - theRetToken = returnToken_; - } - else if ((cached_LA1=='!') && (cached_LA2=='{')) { - mPROJECT(true); - theRetToken = returnToken_; - } - else if ((cached_LA1=='?') && (cached_LA2=='{')) { - mSELECT(true); - theRetToken = returnToken_; - } - else if ((cached_LA1=='^') && (cached_LA2=='{')) { - mSELECT_FIRST(true); - theRetToken = returnToken_; - } - else if ((cached_LA1=='$') && (cached_LA2=='{')) { - mSELECT_LAST(true); - theRetToken = returnToken_; - } - else if ((cached_LA1=='T') && (cached_LA2=='(')) { - mTYPE(true); - theRetToken = returnToken_; - } - else if ((cached_LA1=='{') && (cached_LA2=='|')) { - mLAMBDA(true); - theRetToken = returnToken_; - } - else if ((cached_LA1=='\\') && (cached_LA2=='.')) { - mDOT_ESCAPED(true); - theRetToken = returnToken_; - } - else if ((cached_LA1=='\'') && ((cached_LA2 >= '\u0000' && cached_LA2 <= '\ufffe'))) { - mSTRING_LITERAL(true); - theRetToken = returnToken_; - } - else if ((cached_LA1=='0') && (cached_LA2=='x')) { - mHEXADECIMAL_INTEGER_LITERAL(true); - theRetToken = returnToken_; - } - else if ((cached_LA1=='\\') && (true)) { - mBACKSLASH(true); - theRetToken = returnToken_; - } - else if ((cached_LA1=='!') && (true)) { - mBANG(true); - theRetToken = returnToken_; - } - else if ((cached_LA1=='?') && (true)) { - mQMARK(true); - theRetToken = returnToken_; - } - else if ((cached_LA1=='$') && (true)) { - mDOLLAR(true); - theRetToken = returnToken_; - } - else if ((cached_LA1=='{') && (true)) { - mLCURLY(true); - theRetToken = returnToken_; - } - else if ((cached_LA1=='=') && (true)) { - mASSIGN(true); - theRetToken = returnToken_; - } - else if ((cached_LA1=='^') && (true)) { - mPOWER(true); - theRetToken = returnToken_; - } - else if ((cached_LA1=='<') && (true)) { - mLESS_THAN(true); - theRetToken = returnToken_; - } - else if ((cached_LA1=='>') && (true)) { - mGREATER_THAN(true); - theRetToken = returnToken_; - } - else if ((cached_LA1=='\'') && (true)) { - mQUOTE(true); - theRetToken = returnToken_; - } - else if ((tokenSet_0_.member(cached_LA1)) && (true)) { - mID(true); - theRetToken = returnToken_; - } - else if ((tokenSet_1_.member(cached_LA1)) && (true)) { - mNUMERIC_LITERAL(true); - theRetToken = returnToken_; - } - else - { - if (cached_LA1==EOF_CHAR) { uponEOF(); returnToken_ = makeToken(Token.EOF_TYPE); } - else {throw new NoViableAltForCharException(cached_LA1, getFilename(), getLine(), getColumn());} - } - break; } - if ( null==returnToken_ ) goto tryAgain; // found SKIP token - _ttype = returnToken_.Type; - returnToken_.Type = _ttype; - return returnToken_; - } - catch (RecognitionException e) { - throw new TokenStreamRecognitionException(e); - } - } - catch (CharStreamException cse) { - if ( cse is CharStreamIOException ) { - throw new TokenStreamIOException(((CharStreamIOException)cse).io); - } - else { - throw new TokenStreamException(cse.Message); - } - } - } - } - - public void mWS(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException -{ - int _ttype; IToken _token=null; int _begin=text.Length; - _ttype = WS; - - { - switch ( cached_LA1 ) - { - case ' ': - { - match(' '); - break; - } - case '\t': - { - match('\t'); - break; - } - case '\n': - { - match('\n'); - break; - } - case '\r': - { - match('\r'); - break; - } - default: - { - throw new NoViableAltForCharException(cached_LA1, getFilename(), getLine(), getColumn()); - } - } - } - if (0==inputState.guessing) - { - _ttype = Token.SKIP; - } - if (_createToken && (null == _token) && (_ttype != Token.SKIP)) - { - _token = makeToken(_ttype); - _token.setText(text.ToString(_begin, text.Length-_begin)); - } - returnToken_ = _token; - } - - public void mAT(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException -{ - int _ttype; IToken _token=null; int _begin=text.Length; - _ttype = AT; - - match('@'); - if (_createToken && (null == _token) && (_ttype != Token.SKIP)) - { - _token = makeToken(_ttype); - _token.setText(text.ToString(_begin, text.Length-_begin)); - } - returnToken_ = _token; - } - - public void mBACKTICK(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException -{ - int _ttype; IToken _token=null; int _begin=text.Length; - _ttype = BACKTICK; - - match('`'); - if (_createToken && (null == _token) && (_ttype != Token.SKIP)) - { - _token = makeToken(_ttype); - _token.setText(text.ToString(_begin, text.Length-_begin)); - } - returnToken_ = _token; - } - - public void mBACKSLASH(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException -{ - int _ttype; IToken _token=null; int _begin=text.Length; - _ttype = BACKSLASH; - - match('\\'); - if (_createToken && (null == _token) && (_ttype != Token.SKIP)) - { - _token = makeToken(_ttype); - _token.setText(text.ToString(_begin, text.Length-_begin)); - } - returnToken_ = _token; - } - - public void mPIPE(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException -{ - int _ttype; IToken _token=null; int _begin=text.Length; - _ttype = PIPE; - - match('|'); - if (_createToken && (null == _token) && (_ttype != Token.SKIP)) - { - _token = makeToken(_ttype); - _token.setText(text.ToString(_begin, text.Length-_begin)); - } - returnToken_ = _token; - } - - public void mBANG(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException -{ - int _ttype; IToken _token=null; int _begin=text.Length; - _ttype = BANG; - - match('!'); - if (_createToken && (null == _token) && (_ttype != Token.SKIP)) - { - _token = makeToken(_ttype); - _token.setText(text.ToString(_begin, text.Length-_begin)); - } - returnToken_ = _token; - } - - public void mQMARK(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException -{ - int _ttype; IToken _token=null; int _begin=text.Length; - _ttype = QMARK; - - match('?'); - if (_createToken && (null == _token) && (_ttype != Token.SKIP)) - { - _token = makeToken(_ttype); - _token.setText(text.ToString(_begin, text.Length-_begin)); - } - returnToken_ = _token; - } - - public void mDOLLAR(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException -{ - int _ttype; IToken _token=null; int _begin=text.Length; - _ttype = DOLLAR; - - match('$'); - if (_createToken && (null == _token) && (_ttype != Token.SKIP)) - { - _token = makeToken(_ttype); - _token.setText(text.ToString(_begin, text.Length-_begin)); - } - returnToken_ = _token; - } - - public void mPOUND(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException -{ - int _ttype; IToken _token=null; int _begin=text.Length; - _ttype = POUND; - - match('#'); - if (_createToken && (null == _token) && (_ttype != Token.SKIP)) - { - _token = makeToken(_ttype); - _token.setText(text.ToString(_begin, text.Length-_begin)); - } - returnToken_ = _token; - } - - public void mLPAREN(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException -{ - int _ttype; IToken _token=null; int _begin=text.Length; - _ttype = LPAREN; - - match('('); - if (_createToken && (null == _token) && (_ttype != Token.SKIP)) - { - _token = makeToken(_ttype); - _token.setText(text.ToString(_begin, text.Length-_begin)); - } - returnToken_ = _token; - } - - public void mRPAREN(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException -{ - int _ttype; IToken _token=null; int _begin=text.Length; - _ttype = RPAREN; - - match(')'); - if (_createToken && (null == _token) && (_ttype != Token.SKIP)) - { - _token = makeToken(_ttype); - _token.setText(text.ToString(_begin, text.Length-_begin)); - } - returnToken_ = _token; - } - - public void mLBRACKET(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException -{ - int _ttype; IToken _token=null; int _begin=text.Length; - _ttype = LBRACKET; - - match('['); - if (_createToken && (null == _token) && (_ttype != Token.SKIP)) - { - _token = makeToken(_ttype); - _token.setText(text.ToString(_begin, text.Length-_begin)); - } - returnToken_ = _token; - } - - public void mRBRACKET(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException -{ - int _ttype; IToken _token=null; int _begin=text.Length; - _ttype = RBRACKET; - - match(']'); - if (_createToken && (null == _token) && (_ttype != Token.SKIP)) - { - _token = makeToken(_ttype); - _token.setText(text.ToString(_begin, text.Length-_begin)); - } - returnToken_ = _token; - } - - public void mLCURLY(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException -{ - int _ttype; IToken _token=null; int _begin=text.Length; - _ttype = LCURLY; - - match('{'); - if (_createToken && (null == _token) && (_ttype != Token.SKIP)) - { - _token = makeToken(_ttype); - _token.setText(text.ToString(_begin, text.Length-_begin)); - } - returnToken_ = _token; - } - - public void mRCURLY(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException -{ - int _ttype; IToken _token=null; int _begin=text.Length; - _ttype = RCURLY; - - match('}'); - if (_createToken && (null == _token) && (_ttype != Token.SKIP)) - { - _token = makeToken(_ttype); - _token.setText(text.ToString(_begin, text.Length-_begin)); - } - returnToken_ = _token; - } - - public void mCOMMA(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException -{ - int _ttype; IToken _token=null; int _begin=text.Length; - _ttype = COMMA; - - match(','); - if (_createToken && (null == _token) && (_ttype != Token.SKIP)) - { - _token = makeToken(_ttype); - _token.setText(text.ToString(_begin, text.Length-_begin)); - } - returnToken_ = _token; - } - - public void mSEMI(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException -{ - int _ttype; IToken _token=null; int _begin=text.Length; - _ttype = SEMI; - - match(';'); - if (_createToken && (null == _token) && (_ttype != Token.SKIP)) - { - _token = makeToken(_ttype); - _token.setText(text.ToString(_begin, text.Length-_begin)); - } - returnToken_ = _token; - } - - public void mCOLON(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException -{ - int _ttype; IToken _token=null; int _begin=text.Length; - _ttype = COLON; - - match(':'); - if (_createToken && (null == _token) && (_ttype != Token.SKIP)) - { - _token = makeToken(_ttype); - _token.setText(text.ToString(_begin, text.Length-_begin)); - } - returnToken_ = _token; - } - - public void mASSIGN(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException -{ - int _ttype; IToken _token=null; int _begin=text.Length; - _ttype = ASSIGN; - - match('='); - if (_createToken && (null == _token) && (_ttype != Token.SKIP)) - { - _token = makeToken(_ttype); - _token.setText(text.ToString(_begin, text.Length-_begin)); - } - returnToken_ = _token; - } - - public void mDEFAULT(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException -{ - int _ttype; IToken _token=null; int _begin=text.Length; - _ttype = DEFAULT; - - match("??"); - if (_createToken && (null == _token) && (_ttype != Token.SKIP)) - { - _token = makeToken(_ttype); - _token.setText(text.ToString(_begin, text.Length-_begin)); - } - returnToken_ = _token; - } - - public void mPLUS(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException -{ - int _ttype; IToken _token=null; int _begin=text.Length; - _ttype = PLUS; - - match('+'); - if (_createToken && (null == _token) && (_ttype != Token.SKIP)) - { - _token = makeToken(_ttype); - _token.setText(text.ToString(_begin, text.Length-_begin)); - } - returnToken_ = _token; - } - - public void mMINUS(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException -{ - int _ttype; IToken _token=null; int _begin=text.Length; - _ttype = MINUS; - - match('-'); - if (_createToken && (null == _token) && (_ttype != Token.SKIP)) - { - _token = makeToken(_ttype); - _token.setText(text.ToString(_begin, text.Length-_begin)); - } - returnToken_ = _token; - } - - public void mDIV(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException -{ - int _ttype; IToken _token=null; int _begin=text.Length; - _ttype = DIV; - - match('/'); - if (_createToken && (null == _token) && (_ttype != Token.SKIP)) - { - _token = makeToken(_ttype); - _token.setText(text.ToString(_begin, text.Length-_begin)); - } - returnToken_ = _token; - } - - public void mSTAR(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException -{ - int _ttype; IToken _token=null; int _begin=text.Length; - _ttype = STAR; - - match('*'); - if (_createToken && (null == _token) && (_ttype != Token.SKIP)) - { - _token = makeToken(_ttype); - _token.setText(text.ToString(_begin, text.Length-_begin)); - } - returnToken_ = _token; - } - - public void mMOD(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException -{ - int _ttype; IToken _token=null; int _begin=text.Length; - _ttype = MOD; - - match('%'); - if (_createToken && (null == _token) && (_ttype != Token.SKIP)) - { - _token = makeToken(_ttype); - _token.setText(text.ToString(_begin, text.Length-_begin)); - } - returnToken_ = _token; - } - - public void mPOWER(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException -{ - int _ttype; IToken _token=null; int _begin=text.Length; - _ttype = POWER; - - match('^'); - if (_createToken && (null == _token) && (_ttype != Token.SKIP)) - { - _token = makeToken(_ttype); - _token.setText(text.ToString(_begin, text.Length-_begin)); - } - returnToken_ = _token; - } - - public void mEQUAL(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException -{ - int _ttype; IToken _token=null; int _begin=text.Length; - _ttype = EQUAL; - - match("=="); - if (_createToken && (null == _token) && (_ttype != Token.SKIP)) - { - _token = makeToken(_ttype); - _token.setText(text.ToString(_begin, text.Length-_begin)); - } - returnToken_ = _token; - } - - public void mNOT_EQUAL(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException -{ - int _ttype; IToken _token=null; int _begin=text.Length; - _ttype = NOT_EQUAL; - - match("!="); - if (_createToken && (null == _token) && (_ttype != Token.SKIP)) - { - _token = makeToken(_ttype); - _token.setText(text.ToString(_begin, text.Length-_begin)); - } - returnToken_ = _token; - } - - public void mLESS_THAN(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException -{ - int _ttype; IToken _token=null; int _begin=text.Length; - _ttype = LESS_THAN; - - match('<'); - if (_createToken && (null == _token) && (_ttype != Token.SKIP)) - { - _token = makeToken(_ttype); - _token.setText(text.ToString(_begin, text.Length-_begin)); - } - returnToken_ = _token; - } - - public void mLESS_THAN_OR_EQUAL(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException -{ - int _ttype; IToken _token=null; int _begin=text.Length; - _ttype = LESS_THAN_OR_EQUAL; - - match("<="); - if (_createToken && (null == _token) && (_ttype != Token.SKIP)) - { - _token = makeToken(_ttype); - _token.setText(text.ToString(_begin, text.Length-_begin)); - } - returnToken_ = _token; - } - - public void mGREATER_THAN(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException -{ - int _ttype; IToken _token=null; int _begin=text.Length; - _ttype = GREATER_THAN; - - match('>'); - if (_createToken && (null == _token) && (_ttype != Token.SKIP)) - { - _token = makeToken(_ttype); - _token.setText(text.ToString(_begin, text.Length-_begin)); - } - returnToken_ = _token; - } - - public void mGREATER_THAN_OR_EQUAL(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException -{ - int _ttype; IToken _token=null; int _begin=text.Length; - _ttype = GREATER_THAN_OR_EQUAL; - - match(">="); - if (_createToken && (null == _token) && (_ttype != Token.SKIP)) - { - _token = makeToken(_ttype); - _token.setText(text.ToString(_begin, text.Length-_begin)); - } - returnToken_ = _token; - } - - public void mPROJECT(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException -{ - int _ttype; IToken _token=null; int _begin=text.Length; - _ttype = PROJECT; - - match("!{"); - if (_createToken && (null == _token) && (_ttype != Token.SKIP)) - { - _token = makeToken(_ttype); - _token.setText(text.ToString(_begin, text.Length-_begin)); - } - returnToken_ = _token; - } - - public void mSELECT(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException -{ - int _ttype; IToken _token=null; int _begin=text.Length; - _ttype = SELECT; - - match("?{"); - if (_createToken && (null == _token) && (_ttype != Token.SKIP)) - { - _token = makeToken(_ttype); - _token.setText(text.ToString(_begin, text.Length-_begin)); - } - returnToken_ = _token; - } - - public void mSELECT_FIRST(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException -{ - int _ttype; IToken _token=null; int _begin=text.Length; - _ttype = SELECT_FIRST; - - match("^{"); - if (_createToken && (null == _token) && (_ttype != Token.SKIP)) - { - _token = makeToken(_ttype); - _token.setText(text.ToString(_begin, text.Length-_begin)); - } - returnToken_ = _token; - } - - public void mSELECT_LAST(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException -{ - int _ttype; IToken _token=null; int _begin=text.Length; - _ttype = SELECT_LAST; - - match("${"); - if (_createToken && (null == _token) && (_ttype != Token.SKIP)) - { - _token = makeToken(_ttype); - _token.setText(text.ToString(_begin, text.Length-_begin)); - } - returnToken_ = _token; - } - - public void mTYPE(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException -{ - int _ttype; IToken _token=null; int _begin=text.Length; - _ttype = TYPE; - - match("T("); - if (_createToken && (null == _token) && (_ttype != Token.SKIP)) - { - _token = makeToken(_ttype); - _token.setText(text.ToString(_begin, text.Length-_begin)); - } - returnToken_ = _token; - } - - public void mLAMBDA(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException -{ - int _ttype; IToken _token=null; int _begin=text.Length; - _ttype = LAMBDA; - - match("{|"); - if (_createToken && (null == _token) && (_ttype != Token.SKIP)) - { - _token = makeToken(_ttype); - _token.setText(text.ToString(_begin, text.Length-_begin)); - } - returnToken_ = _token; - } - - public void mDOT_ESCAPED(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException -{ - int _ttype; IToken _token=null; int _begin=text.Length; - _ttype = DOT_ESCAPED; - - match("\\."); - if (_createToken && (null == _token) && (_ttype != Token.SKIP)) - { - _token = makeToken(_ttype); - _token.setText(text.ToString(_begin, text.Length-_begin)); - } - returnToken_ = _token; - } - - public void mQUOTE(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException -{ - int _ttype; IToken _token=null; int _begin=text.Length; - _ttype = QUOTE; - - match('\''); - if (_createToken && (null == _token) && (_ttype != Token.SKIP)) - { - _token = makeToken(_ttype); - _token.setText(text.ToString(_begin, text.Length-_begin)); - } - returnToken_ = _token; - } - - public void mSTRING_LITERAL(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException -{ - int _ttype; IToken _token=null; int _begin=text.Length; - _ttype = STRING_LITERAL; - - int _saveIndex = 0; - _saveIndex = text.Length; - mQUOTE(false); - text.Length = _saveIndex; - { // ( ... )* - for (;;) - { - if ((cached_LA1=='\'') && (cached_LA2=='\'')) - { - mAPOS(false); - } - else if ((tokenSet_2_.member(cached_LA1))) { - matchNot('\''); - } - else - { - goto _loop161_breakloop; - } - - } -_loop161_breakloop: ; - } // ( ... )* - _saveIndex = text.Length; - mQUOTE(false); - text.Length = _saveIndex; - if (_createToken && (null == _token) && (_ttype != Token.SKIP)) - { - _token = makeToken(_ttype); - _token.setText(text.ToString(_begin, text.Length-_begin)); - } - returnToken_ = _token; - } - - protected void mAPOS(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException -{ - int _ttype; IToken _token=null; int _begin=text.Length; - _ttype = APOS; - - int _saveIndex = 0; - _saveIndex = text.Length; - mQUOTE(false); - text.Length = _saveIndex; - mQUOTE(false); - if (_createToken && (null == _token) && (_ttype != Token.SKIP)) - { - _token = makeToken(_ttype); - _token.setText(text.ToString(_begin, text.Length-_begin)); - } - returnToken_ = _token; - } - - public void mID(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException -{ - int _ttype; IToken _token=null; int _begin=text.Length; - _ttype = ID; - - { - switch ( cached_LA1 ) - { - case 'a': case 'b': case 'c': case 'd': - case 'e': case 'f': case 'g': case 'h': - case 'i': case 'j': case 'k': case 'l': - case 'm': case 'n': case 'o': case 'p': - case 'q': case 'r': case 's': case 't': - case 'u': case 'v': case 'w': case 'x': - case 'y': case 'z': - { - matchRange('a','z'); - break; - } - case 'A': case 'B': case 'C': case 'D': - case 'E': case 'F': case 'G': case 'H': - case 'I': case 'J': case 'K': case 'L': - case 'M': case 'N': case 'O': case 'P': - case 'Q': case 'R': case 'S': case 'T': - case 'U': case 'V': case 'W': case 'X': - case 'Y': case 'Z': - { - matchRange('A','Z'); - break; - } - case '_': - { - match('_'); - break; - } - default: - { - throw new NoViableAltForCharException(cached_LA1, getFilename(), getLine(), getColumn()); - } - } - } - { // ( ... )* - for (;;) - { - switch ( cached_LA1 ) - { - case 'a': case 'b': case 'c': case 'd': - case 'e': case 'f': case 'g': case 'h': - case 'i': case 'j': case 'k': case 'l': - case 'm': case 'n': case 'o': case 'p': - case 'q': case 'r': case 's': case 't': - case 'u': case 'v': case 'w': case 'x': - case 'y': case 'z': - { - matchRange('a','z'); - break; - } - case 'A': case 'B': case 'C': case 'D': - case 'E': case 'F': case 'G': case 'H': - case 'I': case 'J': case 'K': case 'L': - case 'M': case 'N': case 'O': case 'P': - case 'Q': case 'R': case 'S': case 'T': - case 'U': case 'V': case 'W': case 'X': - case 'Y': case 'Z': - { - matchRange('A','Z'); - break; - } - case '_': - { - match('_'); - break; - } - case '0': case '1': case '2': case '3': - case '4': case '5': case '6': case '7': - case '8': case '9': - { - matchRange('0','9'); - break; - } - default: - { - goto _loop166_breakloop; - } - } - } -_loop166_breakloop: ; - } // ( ... )* - _ttype = testLiteralsTable(_ttype); - if (_createToken && (null == _token) && (_ttype != Token.SKIP)) - { - _token = makeToken(_ttype); - _token.setText(text.ToString(_begin, text.Length-_begin)); - } - returnToken_ = _token; - } - - public void mNUMERIC_LITERAL(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException -{ - int _ttype; IToken _token=null; int _begin=text.Length; - _ttype = NUMERIC_LITERAL; - - bool synPredMatched169 = false; - if (((cached_LA1=='.') && ((cached_LA2 >= '0' && cached_LA2 <= '9')))) - { - int _m169 = mark(); - synPredMatched169 = true; - inputState.guessing++; - try { - { - match('.'); - mDECIMAL_DIGIT(false); - } - } - catch (RecognitionException) - { - synPredMatched169 = false; - } - rewind(_m169); - inputState.guessing--; - } - if ( synPredMatched169 ) - { - match('.'); - { // ( ... )+ - int _cnt171=0; - for (;;) - { - if (((cached_LA1 >= '0' && cached_LA1 <= '9'))) - { - mDECIMAL_DIGIT(false); - } - else - { - if (_cnt171 >= 1) { goto _loop171_breakloop; } else { throw new NoViableAltForCharException(cached_LA1, getFilename(), getLine(), getColumn());; } - } - - _cnt171++; - } -_loop171_breakloop: ; - } // ( ... )+ - { - if ((cached_LA1=='E'||cached_LA1=='e')) - { - mEXPONENT_PART(false); - } - else { - } - - } - { - if ((tokenSet_3_.member(cached_LA1))) - { - mREAL_TYPE_SUFFIX(false); - } - else { - } - - } - if (0==inputState.guessing) - { - _ttype = REAL_LITERAL; - } - } - else { - bool synPredMatched177 = false; - if ((((cached_LA1 >= '0' && cached_LA1 <= '9')) && (tokenSet_1_.member(cached_LA2)))) - { - int _m177 = mark(); - synPredMatched177 = true; - inputState.guessing++; - try { - { - { // ( ... )+ - int _cnt176=0; - for (;;) - { - if (((cached_LA1 >= '0' && cached_LA1 <= '9'))) - { - mDECIMAL_DIGIT(false); - } - else - { - if (_cnt176 >= 1) { goto _loop176_breakloop; } else { throw new NoViableAltForCharException(cached_LA1, getFilename(), getLine(), getColumn());; } - } - - _cnt176++; - } -_loop176_breakloop: ; - } // ( ... )+ - match('.'); - mDECIMAL_DIGIT(false); - } - } - catch (RecognitionException) - { - synPredMatched177 = false; - } - rewind(_m177); - inputState.guessing--; - } - if ( synPredMatched177 ) - { - { // ( ... )+ - int _cnt179=0; - for (;;) - { - if (((cached_LA1 >= '0' && cached_LA1 <= '9'))) - { - mDECIMAL_DIGIT(false); - } - else - { - if (_cnt179 >= 1) { goto _loop179_breakloop; } else { throw new NoViableAltForCharException(cached_LA1, getFilename(), getLine(), getColumn());; } - } - - _cnt179++; - } -_loop179_breakloop: ; - } // ( ... )+ - match('.'); - { // ( ... )+ - int _cnt181=0; - for (;;) - { - if (((cached_LA1 >= '0' && cached_LA1 <= '9'))) - { - mDECIMAL_DIGIT(false); - } - else - { - if (_cnt181 >= 1) { goto _loop181_breakloop; } else { throw new NoViableAltForCharException(cached_LA1, getFilename(), getLine(), getColumn());; } - } - - _cnt181++; - } -_loop181_breakloop: ; - } // ( ... )+ - { - if ((cached_LA1=='E'||cached_LA1=='e')) - { - mEXPONENT_PART(false); - } - else { - } - - } - { - if ((tokenSet_3_.member(cached_LA1))) - { - mREAL_TYPE_SUFFIX(false); - } - else { - } - - } - if (0==inputState.guessing) - { - _ttype = REAL_LITERAL; - } - } - else { - bool synPredMatched188 = false; - if ((((cached_LA1 >= '0' && cached_LA1 <= '9')) && (tokenSet_4_.member(cached_LA2)))) - { - int _m188 = mark(); - synPredMatched188 = true; - inputState.guessing++; - try { - { - { // ( ... )+ - int _cnt186=0; - for (;;) - { - if (((cached_LA1 >= '0' && cached_LA1 <= '9'))) - { - mDECIMAL_DIGIT(false); - } - else - { - if (_cnt186 >= 1) { goto _loop186_breakloop; } else { throw new NoViableAltForCharException(cached_LA1, getFilename(), getLine(), getColumn());; } - } - - _cnt186++; - } -_loop186_breakloop: ; - } // ( ... )+ - { - mEXPONENT_PART(false); - } - } - } - catch (RecognitionException) - { - synPredMatched188 = false; - } - rewind(_m188); - inputState.guessing--; - } - if ( synPredMatched188 ) - { - { // ( ... )+ - int _cnt190=0; - for (;;) - { - if (((cached_LA1 >= '0' && cached_LA1 <= '9'))) - { - mDECIMAL_DIGIT(false); - } - else - { - if (_cnt190 >= 1) { goto _loop190_breakloop; } else { throw new NoViableAltForCharException(cached_LA1, getFilename(), getLine(), getColumn());; } - } - - _cnt190++; - } -_loop190_breakloop: ; - } // ( ... )+ - { - mEXPONENT_PART(false); - } - { - if ((tokenSet_3_.member(cached_LA1))) - { - mREAL_TYPE_SUFFIX(false); - } - else { - } - - } - if (0==inputState.guessing) - { - _ttype = REAL_LITERAL; - } - } - else { - bool synPredMatched197 = false; - if ((((cached_LA1 >= '0' && cached_LA1 <= '9')) && (tokenSet_5_.member(cached_LA2)))) - { - int _m197 = mark(); - synPredMatched197 = true; - inputState.guessing++; - try { - { - { // ( ... )+ - int _cnt195=0; - for (;;) - { - if (((cached_LA1 >= '0' && cached_LA1 <= '9'))) - { - mDECIMAL_DIGIT(false); - } - else - { - if (_cnt195 >= 1) { goto _loop195_breakloop; } else { throw new NoViableAltForCharException(cached_LA1, getFilename(), getLine(), getColumn());; } - } - - _cnt195++; - } -_loop195_breakloop: ; - } // ( ... )+ - { - mREAL_TYPE_SUFFIX(false); - } - } - } - catch (RecognitionException) - { - synPredMatched197 = false; - } - rewind(_m197); - inputState.guessing--; - } - if ( synPredMatched197 ) - { - { // ( ... )+ - int _cnt199=0; - for (;;) - { - if (((cached_LA1 >= '0' && cached_LA1 <= '9'))) - { - mDECIMAL_DIGIT(false); - } - else - { - if (_cnt199 >= 1) { goto _loop199_breakloop; } else { throw new NoViableAltForCharException(cached_LA1, getFilename(), getLine(), getColumn());; } - } - - _cnt199++; - } -_loop199_breakloop: ; - } // ( ... )+ - { - mREAL_TYPE_SUFFIX(false); - } - if (0==inputState.guessing) - { - _ttype = REAL_LITERAL; - } - } - else if (((cached_LA1 >= '0' && cached_LA1 <= '9')) && (true)) { - { // ( ... )+ - int _cnt202=0; - for (;;) - { - if (((cached_LA1 >= '0' && cached_LA1 <= '9'))) - { - mDECIMAL_DIGIT(false); - } - else - { - if (_cnt202 >= 1) { goto _loop202_breakloop; } else { throw new NoViableAltForCharException(cached_LA1, getFilename(), getLine(), getColumn());; } - } - - _cnt202++; - } -_loop202_breakloop: ; - } // ( ... )+ - { - if ((tokenSet_6_.member(cached_LA1))) - { - mINTEGER_TYPE_SUFFIX(false); - } - else { - } - - } - if (0==inputState.guessing) - { - _ttype = INTEGER_LITERAL; - } - } - else if ((cached_LA1=='.') && (true)) { - match('.'); - if (0==inputState.guessing) - { - _ttype = DOT; - } - } - else - { - throw new NoViableAltForCharException(cached_LA1, getFilename(), getLine(), getColumn()); - } - }}} - if (_createToken && (null == _token) && (_ttype != Token.SKIP)) - { - _token = makeToken(_ttype); - _token.setText(text.ToString(_begin, text.Length-_begin)); - } - returnToken_ = _token; - } - - protected void mDECIMAL_DIGIT(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException -{ - int _ttype; IToken _token=null; int _begin=text.Length; - _ttype = DECIMAL_DIGIT; - - matchRange('0','9'); - if (_createToken && (null == _token) && (_ttype != Token.SKIP)) - { - _token = makeToken(_ttype); - _token.setText(text.ToString(_begin, text.Length-_begin)); - } - returnToken_ = _token; - } - - protected void mEXPONENT_PART(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException -{ - int _ttype; IToken _token=null; int _begin=text.Length; - _ttype = EXPONENT_PART; - - switch ( cached_LA1 ) - { - case 'e': - { - match("e"); - { // ( ... )* - for (;;) - { - if ((cached_LA1=='+'||cached_LA1=='-')) - { - mSIGN(false); - } - else - { - goto _loop214_breakloop; - } - - } -_loop214_breakloop: ; - } // ( ... )* - { // ( ... )+ - int _cnt216=0; - for (;;) - { - if (((cached_LA1 >= '0' && cached_LA1 <= '9'))) - { - mDECIMAL_DIGIT(false); - } - else - { - if (_cnt216 >= 1) { goto _loop216_breakloop; } else { throw new NoViableAltForCharException(cached_LA1, getFilename(), getLine(), getColumn());; } - } - - _cnt216++; - } -_loop216_breakloop: ; - } // ( ... )+ - break; - } - case 'E': - { - match("E"); - { // ( ... )* - for (;;) - { - if ((cached_LA1=='+'||cached_LA1=='-')) - { - mSIGN(false); - } - else - { - goto _loop218_breakloop; - } - - } -_loop218_breakloop: ; - } // ( ... )* - { // ( ... )+ - int _cnt220=0; - for (;;) - { - if (((cached_LA1 >= '0' && cached_LA1 <= '9'))) - { - mDECIMAL_DIGIT(false); - } - else - { - if (_cnt220 >= 1) { goto _loop220_breakloop; } else { throw new NoViableAltForCharException(cached_LA1, getFilename(), getLine(), getColumn());; } - } - - _cnt220++; - } -_loop220_breakloop: ; - } // ( ... )+ - break; - } - default: - { - throw new NoViableAltForCharException(cached_LA1, getFilename(), getLine(), getColumn()); - } - } - if (_createToken && (null == _token) && (_ttype != Token.SKIP)) - { - _token = makeToken(_ttype); - _token.setText(text.ToString(_begin, text.Length-_begin)); - } - returnToken_ = _token; - } - - protected void mREAL_TYPE_SUFFIX(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException -{ - int _ttype; IToken _token=null; int _begin=text.Length; - _ttype = REAL_TYPE_SUFFIX; - - switch ( cached_LA1 ) - { - case 'F': - { - match('F'); - break; - } - case 'f': - { - match('f'); - break; - } - case 'D': - { - match('D'); - break; - } - case 'd': - { - match('d'); - break; - } - case 'M': - { - match('M'); - break; - } - case 'm': - { - match('m'); - break; - } - default: - { - throw new NoViableAltForCharException(cached_LA1, getFilename(), getLine(), getColumn()); - } - } - if (_createToken && (null == _token) && (_ttype != Token.SKIP)) - { - _token = makeToken(_ttype); - _token.setText(text.ToString(_begin, text.Length-_begin)); - } - returnToken_ = _token; - } - - protected void mINTEGER_TYPE_SUFFIX(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException -{ - int _ttype; IToken _token=null; int _begin=text.Length; - _ttype = INTEGER_TYPE_SUFFIX; - - { - if ((cached_LA1=='U') && (cached_LA2=='L')) - { - match("UL"); - } - else if ((cached_LA1=='L') && (cached_LA2=='U')) { - match("LU"); - } - else if ((cached_LA1=='u') && (cached_LA2=='l')) { - match("ul"); - } - else if ((cached_LA1=='l') && (cached_LA2=='u')) { - match("lu"); - } - else if ((cached_LA1=='U') && (cached_LA2=='L')) { - match("UL"); - } - else if ((cached_LA1=='L') && (cached_LA2=='U')) { - match("LU"); - } - else if ((cached_LA1=='u') && (cached_LA2=='L')) { - match("uL"); - } - else if ((cached_LA1=='l') && (cached_LA2=='U')) { - match("lU"); - } - else if ((cached_LA1=='U') && (true)) { - match("U"); - } - else if ((cached_LA1=='L') && (true)) { - match("L"); - } - else if ((cached_LA1=='u') && (true)) { - match("u"); - } - else if ((cached_LA1=='l') && (true)) { - match("l"); - } - else - { - throw new NoViableAltForCharException(cached_LA1, getFilename(), getLine(), getColumn()); - } - - } - if (_createToken && (null == _token) && (_ttype != Token.SKIP)) - { - _token = makeToken(_ttype); - _token.setText(text.ToString(_begin, text.Length-_begin)); - } - returnToken_ = _token; - } - - public void mHEXADECIMAL_INTEGER_LITERAL(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException -{ - int _ttype; IToken _token=null; int _begin=text.Length; - _ttype = HEXADECIMAL_INTEGER_LITERAL; - - match("0x"); - { // ( ... )+ - int _cnt206=0; - for (;;) - { - if ((tokenSet_7_.member(cached_LA1))) - { - mHEX_DIGIT(false); - } - else - { - if (_cnt206 >= 1) { goto _loop206_breakloop; } else { throw new NoViableAltForCharException(cached_LA1, getFilename(), getLine(), getColumn());; } - } - - _cnt206++; - } -_loop206_breakloop: ; - } // ( ... )+ - { - if ((tokenSet_6_.member(cached_LA1))) - { - mINTEGER_TYPE_SUFFIX(false); - } - else { - } - - } - if (_createToken && (null == _token) && (_ttype != Token.SKIP)) - { - _token = makeToken(_ttype); - _token.setText(text.ToString(_begin, text.Length-_begin)); - } - returnToken_ = _token; - } - - protected void mHEX_DIGIT(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException -{ - int _ttype; IToken _token=null; int _begin=text.Length; - _ttype = HEX_DIGIT; - - switch ( cached_LA1 ) - { - case '0': - { - match('0'); - break; - } - case '1': - { - match('1'); - break; - } - case '2': - { - match('2'); - break; - } - case '3': - { - match('3'); - break; - } - case '4': - { - match('4'); - break; - } - case '5': - { - match('5'); - break; - } - case '6': - { - match('6'); - break; - } - case '7': - { - match('7'); - break; - } - case '8': - { - match('8'); - break; - } - case '9': - { - match('9'); - break; - } - case 'A': - { - match('A'); - break; - } - case 'B': - { - match('B'); - break; - } - case 'C': - { - match('C'); - break; - } - case 'D': - { - match('D'); - break; - } - case 'E': - { - match('E'); - break; - } - case 'F': - { - match('F'); - break; - } - case 'a': - { - match('a'); - break; - } - case 'b': - { - match('b'); - break; - } - case 'c': - { - match('c'); - break; - } - case 'd': - { - match('d'); - break; - } - case 'e': - { - match('e'); - break; - } - case 'f': - { - match('f'); - break; - } - default: - { - throw new NoViableAltForCharException(cached_LA1, getFilename(), getLine(), getColumn()); - } - } - if (_createToken && (null == _token) && (_ttype != Token.SKIP)) - { - _token = makeToken(_ttype); - _token.setText(text.ToString(_begin, text.Length-_begin)); - } - returnToken_ = _token; - } - - protected void mSIGN(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException -{ - int _ttype; IToken _token=null; int _begin=text.Length; - _ttype = SIGN; - - switch ( cached_LA1 ) - { - case '+': - { - match('+'); - break; - } - case '-': - { - match('-'); - break; - } - default: - { - throw new NoViableAltForCharException(cached_LA1, getFilename(), getLine(), getColumn()); - } - } - if (_createToken && (null == _token) && (_ttype != Token.SKIP)) - { - _token = makeToken(_ttype); - _token.setText(text.ToString(_begin, text.Length-_begin)); - } - returnToken_ = _token; - } - - - private static long[] mk_tokenSet_0_() - { - long[] data = new long[1025]; - data[0]=0L; - data[1]=576460745995190270L; - for (int i = 2; i<=1024; i++) { data[i]=0L; } - return data; - } - public static readonly BitSet tokenSet_0_ = new BitSet(mk_tokenSet_0_()); - private static long[] mk_tokenSet_1_() - { - long[] data = new long[1025]; - data[0]=288019269919178752L; - for (int i = 1; i<=1024; i++) { data[i]=0L; } - return data; - } - public static readonly BitSet tokenSet_1_ = new BitSet(mk_tokenSet_1_()); - private static long[] mk_tokenSet_2_() - { - long[] data = new long[2048]; - data[0]=-549755813889L; - for (int i = 1; i<=1022; i++) { data[i]=-1L; } - data[1023]=9223372036854775807L; - for (int i = 1024; i<=2047; i++) { data[i]=0L; } - return data; - } - public static readonly BitSet tokenSet_2_ = new BitSet(mk_tokenSet_2_()); - private static long[] mk_tokenSet_3_() - { - long[] data = new long[1025]; - data[0]=0L; - data[1]=35527969480784L; - for (int i = 2; i<=1024; i++) { data[i]=0L; } - return data; - } - public static readonly BitSet tokenSet_3_ = new BitSet(mk_tokenSet_3_()); - private static long[] mk_tokenSet_4_() - { - long[] data = new long[1025]; - data[0]=287948901175001088L; - data[1]=137438953504L; - for (int i = 2; i<=1024; i++) { data[i]=0L; } - return data; - } - public static readonly BitSet tokenSet_4_ = new BitSet(mk_tokenSet_4_()); - private static long[] mk_tokenSet_5_() - { - long[] data = new long[1025]; - data[0]=287948901175001088L; - data[1]=35527969480784L; - for (int i = 2; i<=1024; i++) { data[i]=0L; } - return data; - } - public static readonly BitSet tokenSet_5_ = new BitSet(mk_tokenSet_5_()); - private static long[] mk_tokenSet_6_() - { - long[] data = new long[1025]; - data[0]=0L; - data[1]=9024791442886656L; - for (int i = 2; i<=1024; i++) { data[i]=0L; } - return data; - } - public static readonly BitSet tokenSet_6_ = new BitSet(mk_tokenSet_6_()); - private static long[] mk_tokenSet_7_() - { - long[] data = new long[1025]; - data[0]=287948901175001088L; - data[1]=541165879422L; - for (int i = 2; i<=1024; i++) { data[i]=0L; } - return data; - } - public static readonly BitSet tokenSet_7_ = new BitSet(mk_tokenSet_7_()); - -} + public ExpressionLexer(Stream ins) : this(new ByteBuffer(ins)) + { + } + + public ExpressionLexer(TextReader r) : this(new CharBuffer(r)) + { + } + + public ExpressionLexer(InputBuffer ib) : this(new LexerSharedInputState(ib)) + { + } + + public ExpressionLexer(LexerSharedInputState state) : base(state) + { + initialize(); + } + + private void initialize() + { + caseSensitiveLiterals = true; + setCaseSensitive(true); + literals = new Hashtable(100, (float) 0.4, null, Comparer.Default); + literals.Add("true", 7); + literals.Add("and", 8); + literals.Add("matches", 15); + literals.Add("in", 11); + literals.Add("xor", 10); + literals.Add("null", 16); + literals.Add("between", 13); + literals.Add("or", 9); + literals.Add("is", 12); + literals.Add("like", 14); + literals.Add("new", 49); + literals.Add("false", 6); + } + + override public IToken nextToken() //throws TokenStreamException + { + IToken theRetToken = null; + tryAgain: + for (;;) + { + IToken _token = null; + int _ttype = Token.INVALID_TYPE; + resetText(); + try // for char stream error handling + { + try // for lexical error handling + { + switch (cached_LA1) + { + case '\t': + case '\n': + case '\r': + case ' ': + { + mWS(true); + theRetToken = returnToken_; + break; + } + case '@': + { + mAT(true); + theRetToken = returnToken_; + break; + } + case '`': + { + mBACKTICK(true); + theRetToken = returnToken_; + break; + } + case '|': + { + mPIPE(true); + theRetToken = returnToken_; + break; + } + case '#': + { + mPOUND(true); + theRetToken = returnToken_; + break; + } + case '(': + { + mLPAREN(true); + theRetToken = returnToken_; + break; + } + case ')': + { + mRPAREN(true); + theRetToken = returnToken_; + break; + } + case '[': + { + mLBRACKET(true); + theRetToken = returnToken_; + break; + } + case ']': + { + mRBRACKET(true); + theRetToken = returnToken_; + break; + } + case '}': + { + mRCURLY(true); + theRetToken = returnToken_; + break; + } + case ',': + { + mCOMMA(true); + theRetToken = returnToken_; + break; + } + case ';': + { + mSEMI(true); + theRetToken = returnToken_; + break; + } + case ':': + { + mCOLON(true); + theRetToken = returnToken_; + break; + } + case '+': + { + mPLUS(true); + theRetToken = returnToken_; + break; + } + case '-': + { + mMINUS(true); + theRetToken = returnToken_; + break; + } + case '/': + { + mDIV(true); + theRetToken = returnToken_; + break; + } + case '*': + { + mSTAR(true); + theRetToken = returnToken_; + break; + } + case '%': + { + mMOD(true); + theRetToken = returnToken_; + break; + } + default: + if ((cached_LA1 == '?') && (cached_LA2 == '?')) + { + mDEFAULT(true); + theRetToken = returnToken_; + } + else if ((cached_LA1 == '=') && (cached_LA2 == '=')) + { + mEQUAL(true); + theRetToken = returnToken_; + } + else if ((cached_LA1 == '!') && (cached_LA2 == '=')) + { + mNOT_EQUAL(true); + theRetToken = returnToken_; + } + else if ((cached_LA1 == '<') && (cached_LA2 == '=')) + { + mLESS_THAN_OR_EQUAL(true); + theRetToken = returnToken_; + } + else if ((cached_LA1 == '>') && (cached_LA2 == '=')) + { + mGREATER_THAN_OR_EQUAL(true); + theRetToken = returnToken_; + } + else if ((cached_LA1 == '!') && (cached_LA2 == '{')) + { + mPROJECT(true); + theRetToken = returnToken_; + } + else if ((cached_LA1 == '?') && (cached_LA2 == '{')) + { + mSELECT(true); + theRetToken = returnToken_; + } + else if ((cached_LA1 == '^') && (cached_LA2 == '{')) + { + mSELECT_FIRST(true); + theRetToken = returnToken_; + } + else if ((cached_LA1 == '$') && (cached_LA2 == '{')) + { + mSELECT_LAST(true); + theRetToken = returnToken_; + } + else if ((cached_LA1 == 'T') && (cached_LA2 == '(')) + { + mTYPE(true); + theRetToken = returnToken_; + } + else if ((cached_LA1 == '{') && (cached_LA2 == '|')) + { + mLAMBDA(true); + theRetToken = returnToken_; + } + else if ((cached_LA1 == '\\') && (cached_LA2 == '.')) + { + mDOT_ESCAPED(true); + theRetToken = returnToken_; + } + else if ((cached_LA1 == '\'') && ((cached_LA2 >= '\u0000' && cached_LA2 <= '\ufffe'))) + { + mSTRING_LITERAL(true); + theRetToken = returnToken_; + } + else if ((cached_LA1 == '0') && (cached_LA2 == 'x')) + { + mHEXADECIMAL_INTEGER_LITERAL(true); + theRetToken = returnToken_; + } + else if ((cached_LA1 == '\\') && (true)) + { + mBACKSLASH(true); + theRetToken = returnToken_; + } + else if ((cached_LA1 == '!') && (true)) + { + mBANG(true); + theRetToken = returnToken_; + } + else if ((cached_LA1 == '?') && (true)) + { + mQMARK(true); + theRetToken = returnToken_; + } + else if ((cached_LA1 == '$') && (true)) + { + mDOLLAR(true); + theRetToken = returnToken_; + } + else if ((cached_LA1 == '{') && (true)) + { + mLCURLY(true); + theRetToken = returnToken_; + } + else if ((cached_LA1 == '=') && (true)) + { + mASSIGN(true); + theRetToken = returnToken_; + } + else if ((cached_LA1 == '^') && (true)) + { + mPOWER(true); + theRetToken = returnToken_; + } + else if ((cached_LA1 == '<') && (true)) + { + mLESS_THAN(true); + theRetToken = returnToken_; + } + else if ((cached_LA1 == '>') && (true)) + { + mGREATER_THAN(true); + theRetToken = returnToken_; + } + else if ((cached_LA1 == '\'') && (true)) + { + mQUOTE(true); + theRetToken = returnToken_; + } + else if ((tokenSet_0_.member(cached_LA1)) && (true)) + { + mID(true); + theRetToken = returnToken_; + } + else if ((tokenSet_1_.member(cached_LA1)) && (true)) + { + mNUMERIC_LITERAL(true); + theRetToken = returnToken_; + } + else + { + if (cached_LA1 == EOF_CHAR) + { + uponEOF(); + returnToken_ = makeToken(Token.EOF_TYPE); + } + else { throw new NoViableAltForCharException(cached_LA1, getFilename(), getLine(), getColumn()); } + } + + break; + } + + if (null == returnToken_) goto tryAgain; // found SKIP token + _ttype = returnToken_.Type; + returnToken_.Type = _ttype; + return returnToken_; + } + catch (RecognitionException e) + { + throw new TokenStreamRecognitionException(e); + } + } + catch (CharStreamException cse) + { + if (cse is CharStreamIOException) + { + throw new TokenStreamIOException(((CharStreamIOException) cse).io); + } + else + { + throw new TokenStreamException(cse.Message); + } + } + } + } + + public void mWS(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException + { + int _ttype; + IToken _token = null; + int _begin = text.Length; + _ttype = WS; + + { + switch (cached_LA1) + { + case ' ': + { + match(' '); + break; + } + case '\t': + { + match('\t'); + break; + } + case '\n': + { + match('\n'); + break; + } + case '\r': + { + match('\r'); + break; + } + default: + { + throw new NoViableAltForCharException(cached_LA1, getFilename(), getLine(), getColumn()); + } + } + } + if (0 == inputState.guessing) + { + _ttype = Token.SKIP; + } + + if (_createToken && (null == _token) && (_ttype != Token.SKIP)) + { + _token = makeToken(_ttype); + _token.setText(text.ToString(_begin, text.Length - _begin)); + } + + returnToken_ = _token; + } + + public void mAT(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException + { + int _ttype; + IToken _token = null; + int _begin = text.Length; + _ttype = AT; + + match('@'); + if (_createToken && (null == _token) && (_ttype != Token.SKIP)) + { + _token = makeToken(_ttype); + _token.setText(text.ToString(_begin, text.Length - _begin)); + } + + returnToken_ = _token; + } + + public void mBACKTICK(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException + { + int _ttype; + IToken _token = null; + int _begin = text.Length; + _ttype = BACKTICK; + + match('`'); + if (_createToken && (null == _token) && (_ttype != Token.SKIP)) + { + _token = makeToken(_ttype); + _token.setText(text.ToString(_begin, text.Length - _begin)); + } + + returnToken_ = _token; + } + + public void mBACKSLASH(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException + { + int _ttype; + IToken _token = null; + int _begin = text.Length; + _ttype = BACKSLASH; + + match('\\'); + if (_createToken && (null == _token) && (_ttype != Token.SKIP)) + { + _token = makeToken(_ttype); + _token.setText(text.ToString(_begin, text.Length - _begin)); + } + + returnToken_ = _token; + } + + public void mPIPE(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException + { + int _ttype; + IToken _token = null; + int _begin = text.Length; + _ttype = PIPE; + + match('|'); + if (_createToken && (null == _token) && (_ttype != Token.SKIP)) + { + _token = makeToken(_ttype); + _token.setText(text.ToString(_begin, text.Length - _begin)); + } + + returnToken_ = _token; + } + + public void mBANG(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException + { + int _ttype; + IToken _token = null; + int _begin = text.Length; + _ttype = BANG; + + match('!'); + if (_createToken && (null == _token) && (_ttype != Token.SKIP)) + { + _token = makeToken(_ttype); + _token.setText(text.ToString(_begin, text.Length - _begin)); + } + + returnToken_ = _token; + } + + public void mQMARK(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException + { + int _ttype; + IToken _token = null; + int _begin = text.Length; + _ttype = QMARK; + + match('?'); + if (_createToken && (null == _token) && (_ttype != Token.SKIP)) + { + _token = makeToken(_ttype); + _token.setText(text.ToString(_begin, text.Length - _begin)); + } + + returnToken_ = _token; + } + + public void mDOLLAR(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException + { + int _ttype; + IToken _token = null; + int _begin = text.Length; + _ttype = DOLLAR; + + match('$'); + if (_createToken && (null == _token) && (_ttype != Token.SKIP)) + { + _token = makeToken(_ttype); + _token.setText(text.ToString(_begin, text.Length - _begin)); + } + + returnToken_ = _token; + } + + public void mPOUND(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException + { + int _ttype; + IToken _token = null; + int _begin = text.Length; + _ttype = POUND; + + match('#'); + if (_createToken && (null == _token) && (_ttype != Token.SKIP)) + { + _token = makeToken(_ttype); + _token.setText(text.ToString(_begin, text.Length - _begin)); + } + + returnToken_ = _token; + } + + public void mLPAREN(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException + { + int _ttype; + IToken _token = null; + int _begin = text.Length; + _ttype = LPAREN; + + match('('); + if (_createToken && (null == _token) && (_ttype != Token.SKIP)) + { + _token = makeToken(_ttype); + _token.setText(text.ToString(_begin, text.Length - _begin)); + } + + returnToken_ = _token; + } + + public void mRPAREN(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException + { + int _ttype; + IToken _token = null; + int _begin = text.Length; + _ttype = RPAREN; + + match(')'); + if (_createToken && (null == _token) && (_ttype != Token.SKIP)) + { + _token = makeToken(_ttype); + _token.setText(text.ToString(_begin, text.Length - _begin)); + } + + returnToken_ = _token; + } + + public void mLBRACKET(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException + { + int _ttype; + IToken _token = null; + int _begin = text.Length; + _ttype = LBRACKET; + + match('['); + if (_createToken && (null == _token) && (_ttype != Token.SKIP)) + { + _token = makeToken(_ttype); + _token.setText(text.ToString(_begin, text.Length - _begin)); + } + + returnToken_ = _token; + } + + public void mRBRACKET(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException + { + int _ttype; + IToken _token = null; + int _begin = text.Length; + _ttype = RBRACKET; + + match(']'); + if (_createToken && (null == _token) && (_ttype != Token.SKIP)) + { + _token = makeToken(_ttype); + _token.setText(text.ToString(_begin, text.Length - _begin)); + } + + returnToken_ = _token; + } + + public void mLCURLY(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException + { + int _ttype; + IToken _token = null; + int _begin = text.Length; + _ttype = LCURLY; + + match('{'); + if (_createToken && (null == _token) && (_ttype != Token.SKIP)) + { + _token = makeToken(_ttype); + _token.setText(text.ToString(_begin, text.Length - _begin)); + } + + returnToken_ = _token; + } + + public void mRCURLY(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException + { + int _ttype; + IToken _token = null; + int _begin = text.Length; + _ttype = RCURLY; + + match('}'); + if (_createToken && (null == _token) && (_ttype != Token.SKIP)) + { + _token = makeToken(_ttype); + _token.setText(text.ToString(_begin, text.Length - _begin)); + } + + returnToken_ = _token; + } + + public void mCOMMA(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException + { + int _ttype; + IToken _token = null; + int _begin = text.Length; + _ttype = COMMA; + + match(','); + if (_createToken && (null == _token) && (_ttype != Token.SKIP)) + { + _token = makeToken(_ttype); + _token.setText(text.ToString(_begin, text.Length - _begin)); + } + + returnToken_ = _token; + } + + public void mSEMI(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException + { + int _ttype; + IToken _token = null; + int _begin = text.Length; + _ttype = SEMI; + + match(';'); + if (_createToken && (null == _token) && (_ttype != Token.SKIP)) + { + _token = makeToken(_ttype); + _token.setText(text.ToString(_begin, text.Length - _begin)); + } + + returnToken_ = _token; + } + + public void mCOLON(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException + { + int _ttype; + IToken _token = null; + int _begin = text.Length; + _ttype = COLON; + + match(':'); + if (_createToken && (null == _token) && (_ttype != Token.SKIP)) + { + _token = makeToken(_ttype); + _token.setText(text.ToString(_begin, text.Length - _begin)); + } + + returnToken_ = _token; + } + + public void mASSIGN(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException + { + int _ttype; + IToken _token = null; + int _begin = text.Length; + _ttype = ASSIGN; + + match('='); + if (_createToken && (null == _token) && (_ttype != Token.SKIP)) + { + _token = makeToken(_ttype); + _token.setText(text.ToString(_begin, text.Length - _begin)); + } + + returnToken_ = _token; + } + + public void mDEFAULT(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException + { + int _ttype; + IToken _token = null; + int _begin = text.Length; + _ttype = DEFAULT; + + match("??"); + if (_createToken && (null == _token) && (_ttype != Token.SKIP)) + { + _token = makeToken(_ttype); + _token.setText(text.ToString(_begin, text.Length - _begin)); + } + + returnToken_ = _token; + } + + public void mPLUS(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException + { + int _ttype; + IToken _token = null; + int _begin = text.Length; + _ttype = PLUS; + + match('+'); + if (_createToken && (null == _token) && (_ttype != Token.SKIP)) + { + _token = makeToken(_ttype); + _token.setText(text.ToString(_begin, text.Length - _begin)); + } + + returnToken_ = _token; + } + + public void mMINUS(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException + { + int _ttype; + IToken _token = null; + int _begin = text.Length; + _ttype = MINUS; + + match('-'); + if (_createToken && (null == _token) && (_ttype != Token.SKIP)) + { + _token = makeToken(_ttype); + _token.setText(text.ToString(_begin, text.Length - _begin)); + } + + returnToken_ = _token; + } + + public void mDIV(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException + { + int _ttype; + IToken _token = null; + int _begin = text.Length; + _ttype = DIV; + + match('/'); + if (_createToken && (null == _token) && (_ttype != Token.SKIP)) + { + _token = makeToken(_ttype); + _token.setText(text.ToString(_begin, text.Length - _begin)); + } + + returnToken_ = _token; + } + + public void mSTAR(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException + { + int _ttype; + IToken _token = null; + int _begin = text.Length; + _ttype = STAR; + + match('*'); + if (_createToken && (null == _token) && (_ttype != Token.SKIP)) + { + _token = makeToken(_ttype); + _token.setText(text.ToString(_begin, text.Length - _begin)); + } + + returnToken_ = _token; + } + + public void mMOD(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException + { + int _ttype; + IToken _token = null; + int _begin = text.Length; + _ttype = MOD; + + match('%'); + if (_createToken && (null == _token) && (_ttype != Token.SKIP)) + { + _token = makeToken(_ttype); + _token.setText(text.ToString(_begin, text.Length - _begin)); + } + + returnToken_ = _token; + } + + public void mPOWER(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException + { + int _ttype; + IToken _token = null; + int _begin = text.Length; + _ttype = POWER; + + match('^'); + if (_createToken && (null == _token) && (_ttype != Token.SKIP)) + { + _token = makeToken(_ttype); + _token.setText(text.ToString(_begin, text.Length - _begin)); + } + + returnToken_ = _token; + } + + public void mEQUAL(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException + { + int _ttype; + IToken _token = null; + int _begin = text.Length; + _ttype = EQUAL; + + match("=="); + if (_createToken && (null == _token) && (_ttype != Token.SKIP)) + { + _token = makeToken(_ttype); + _token.setText(text.ToString(_begin, text.Length - _begin)); + } + + returnToken_ = _token; + } + + public void mNOT_EQUAL(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException + { + int _ttype; + IToken _token = null; + int _begin = text.Length; + _ttype = NOT_EQUAL; + + match("!="); + if (_createToken && (null == _token) && (_ttype != Token.SKIP)) + { + _token = makeToken(_ttype); + _token.setText(text.ToString(_begin, text.Length - _begin)); + } + + returnToken_ = _token; + } + + public void mLESS_THAN(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException + { + int _ttype; + IToken _token = null; + int _begin = text.Length; + _ttype = LESS_THAN; + + match('<'); + if (_createToken && (null == _token) && (_ttype != Token.SKIP)) + { + _token = makeToken(_ttype); + _token.setText(text.ToString(_begin, text.Length - _begin)); + } + + returnToken_ = _token; + } + + public void mLESS_THAN_OR_EQUAL(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException + { + int _ttype; + IToken _token = null; + int _begin = text.Length; + _ttype = LESS_THAN_OR_EQUAL; + + match("<="); + if (_createToken && (null == _token) && (_ttype != Token.SKIP)) + { + _token = makeToken(_ttype); + _token.setText(text.ToString(_begin, text.Length - _begin)); + } + + returnToken_ = _token; + } + + public void mGREATER_THAN(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException + { + int _ttype; + IToken _token = null; + int _begin = text.Length; + _ttype = GREATER_THAN; + + match('>'); + if (_createToken && (null == _token) && (_ttype != Token.SKIP)) + { + _token = makeToken(_ttype); + _token.setText(text.ToString(_begin, text.Length - _begin)); + } + + returnToken_ = _token; + } + + public void mGREATER_THAN_OR_EQUAL(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException + { + int _ttype; + IToken _token = null; + int _begin = text.Length; + _ttype = GREATER_THAN_OR_EQUAL; + + match(">="); + if (_createToken && (null == _token) && (_ttype != Token.SKIP)) + { + _token = makeToken(_ttype); + _token.setText(text.ToString(_begin, text.Length - _begin)); + } + + returnToken_ = _token; + } + + public void mPROJECT(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException + { + int _ttype; + IToken _token = null; + int _begin = text.Length; + _ttype = PROJECT; + + match("!{"); + if (_createToken && (null == _token) && (_ttype != Token.SKIP)) + { + _token = makeToken(_ttype); + _token.setText(text.ToString(_begin, text.Length - _begin)); + } + + returnToken_ = _token; + } + + public void mSELECT(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException + { + int _ttype; + IToken _token = null; + int _begin = text.Length; + _ttype = SELECT; + + match("?{"); + if (_createToken && (null == _token) && (_ttype != Token.SKIP)) + { + _token = makeToken(_ttype); + _token.setText(text.ToString(_begin, text.Length - _begin)); + } + + returnToken_ = _token; + } + + public void mSELECT_FIRST(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException + { + int _ttype; + IToken _token = null; + int _begin = text.Length; + _ttype = SELECT_FIRST; + + match("^{"); + if (_createToken && (null == _token) && (_ttype != Token.SKIP)) + { + _token = makeToken(_ttype); + _token.setText(text.ToString(_begin, text.Length - _begin)); + } + + returnToken_ = _token; + } + + public void mSELECT_LAST(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException + { + int _ttype; + IToken _token = null; + int _begin = text.Length; + _ttype = SELECT_LAST; + + match("${"); + if (_createToken && (null == _token) && (_ttype != Token.SKIP)) + { + _token = makeToken(_ttype); + _token.setText(text.ToString(_begin, text.Length - _begin)); + } + + returnToken_ = _token; + } + + public void mTYPE(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException + { + int _ttype; + IToken _token = null; + int _begin = text.Length; + _ttype = TYPE; + + match("T("); + if (_createToken && (null == _token) && (_ttype != Token.SKIP)) + { + _token = makeToken(_ttype); + _token.setText(text.ToString(_begin, text.Length - _begin)); + } + + returnToken_ = _token; + } + + public void mLAMBDA(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException + { + int _ttype; + IToken _token = null; + int _begin = text.Length; + _ttype = LAMBDA; + + match("{|"); + if (_createToken && (null == _token) && (_ttype != Token.SKIP)) + { + _token = makeToken(_ttype); + _token.setText(text.ToString(_begin, text.Length - _begin)); + } + + returnToken_ = _token; + } + + public void mDOT_ESCAPED(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException + { + int _ttype; + IToken _token = null; + int _begin = text.Length; + _ttype = DOT_ESCAPED; + + match("\\."); + if (_createToken && (null == _token) && (_ttype != Token.SKIP)) + { + _token = makeToken(_ttype); + _token.setText(text.ToString(_begin, text.Length - _begin)); + } + + returnToken_ = _token; + } + + public void mQUOTE(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException + { + int _ttype; + IToken _token = null; + int _begin = text.Length; + _ttype = QUOTE; + + match('\''); + if (_createToken && (null == _token) && (_ttype != Token.SKIP)) + { + _token = makeToken(_ttype); + _token.setText(text.ToString(_begin, text.Length - _begin)); + } + + returnToken_ = _token; + } + + public void mSTRING_LITERAL(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException + { + int _ttype; + IToken _token = null; + int _begin = text.Length; + _ttype = STRING_LITERAL; + + int _saveIndex = 0; + _saveIndex = text.Length; + mQUOTE(false); + text.Length = _saveIndex; + { + // ( ... )* + for (;;) + { + if ((cached_LA1 == '\'') && (cached_LA2 == '\'')) + { + mAPOS(false); + } + else if ((tokenSet_2_.member(cached_LA1))) + { + matchNot('\''); + } + else + { + goto _loop161_breakloop; + } + } + + _loop161_breakloop: ; + } // ( ... )* + _saveIndex = text.Length; + mQUOTE(false); + text.Length = _saveIndex; + if (_createToken && (null == _token) && (_ttype != Token.SKIP)) + { + _token = makeToken(_ttype); + _token.setText(text.ToString(_begin, text.Length - _begin)); + } + + returnToken_ = _token; + } + + protected void mAPOS(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException + { + int _ttype; + IToken _token = null; + int _begin = text.Length; + _ttype = APOS; + + int _saveIndex = 0; + _saveIndex = text.Length; + mQUOTE(false); + text.Length = _saveIndex; + mQUOTE(false); + if (_createToken && (null == _token) && (_ttype != Token.SKIP)) + { + _token = makeToken(_ttype); + _token.setText(text.ToString(_begin, text.Length - _begin)); + } + + returnToken_ = _token; + } + + public void mID(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException + { + int _ttype; + IToken _token = null; + int _begin = text.Length; + _ttype = ID; + + { + switch (cached_LA1) + { + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + case 'g': + case 'h': + case 'i': + case 'j': + case 'k': + case 'l': + case 'm': + case 'n': + case 'o': + case 'p': + case 'q': + case 'r': + case 's': + case 't': + case 'u': + case 'v': + case 'w': + case 'x': + case 'y': + case 'z': + { + matchRange('a', 'z'); + break; + } + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + case 'G': + case 'H': + case 'I': + case 'J': + case 'K': + case 'L': + case 'M': + case 'N': + case 'O': + case 'P': + case 'Q': + case 'R': + case 'S': + case 'T': + case 'U': + case 'V': + case 'W': + case 'X': + case 'Y': + case 'Z': + { + matchRange('A', 'Z'); + break; + } + case '_': + { + match('_'); + break; + } + default: + { + throw new NoViableAltForCharException(cached_LA1, getFilename(), getLine(), getColumn()); + } + } + } + { + // ( ... )* + for (;;) + { + switch (cached_LA1) + { + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + case 'g': + case 'h': + case 'i': + case 'j': + case 'k': + case 'l': + case 'm': + case 'n': + case 'o': + case 'p': + case 'q': + case 'r': + case 's': + case 't': + case 'u': + case 'v': + case 'w': + case 'x': + case 'y': + case 'z': + { + matchRange('a', 'z'); + break; + } + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + case 'G': + case 'H': + case 'I': + case 'J': + case 'K': + case 'L': + case 'M': + case 'N': + case 'O': + case 'P': + case 'Q': + case 'R': + case 'S': + case 'T': + case 'U': + case 'V': + case 'W': + case 'X': + case 'Y': + case 'Z': + { + matchRange('A', 'Z'); + break; + } + case '_': + { + match('_'); + break; + } + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + matchRange('0', '9'); + break; + } + default: + { + goto _loop166_breakloop; + } + } + } + + _loop166_breakloop: ; + } // ( ... )* + _ttype = testLiteralsTable(_ttype); + if (_createToken && (null == _token) && (_ttype != Token.SKIP)) + { + _token = makeToken(_ttype); + _token.setText(text.ToString(_begin, text.Length - _begin)); + } + + returnToken_ = _token; + } + + public void mNUMERIC_LITERAL(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException + { + int _ttype; + IToken _token = null; + int _begin = text.Length; + _ttype = NUMERIC_LITERAL; + + bool synPredMatched169 = false; + if (((cached_LA1 == '.') && ((cached_LA2 >= '0' && cached_LA2 <= '9')))) + { + int _m169 = mark(); + synPredMatched169 = true; + inputState.guessing++; + try + { + { + match('.'); + mDECIMAL_DIGIT(false); + } + } + catch (RecognitionException) + { + synPredMatched169 = false; + } + + rewind(_m169); + inputState.guessing--; + } + + if (synPredMatched169) + { + match('.'); + { + // ( ... )+ + int _cnt171 = 0; + for (;;) + { + if (((cached_LA1 >= '0' && cached_LA1 <= '9'))) + { + mDECIMAL_DIGIT(false); + } + else + { + if (_cnt171 >= 1) { goto _loop171_breakloop; } + else + { + throw new NoViableAltForCharException(cached_LA1, getFilename(), getLine(), getColumn()); + ; + } + } + + _cnt171++; + } + + _loop171_breakloop: ; + } // ( ... )+ + { + if ((cached_LA1 == 'E' || cached_LA1 == 'e')) + { + mEXPONENT_PART(false); + } + else + { + } + } + { + if ((tokenSet_3_.member(cached_LA1))) + { + mREAL_TYPE_SUFFIX(false); + } + else + { + } + } + if (0 == inputState.guessing) + { + _ttype = REAL_LITERAL; + } + } + else + { + bool synPredMatched177 = false; + if ((((cached_LA1 >= '0' && cached_LA1 <= '9')) && (tokenSet_1_.member(cached_LA2)))) + { + int _m177 = mark(); + synPredMatched177 = true; + inputState.guessing++; + try + { + { + { + // ( ... )+ + int _cnt176 = 0; + for (;;) + { + if (((cached_LA1 >= '0' && cached_LA1 <= '9'))) + { + mDECIMAL_DIGIT(false); + } + else + { + if (_cnt176 >= 1) { goto _loop176_breakloop; } + else + { + throw new NoViableAltForCharException(cached_LA1, getFilename(), getLine(), getColumn()); + ; + } + } + + _cnt176++; + } + + _loop176_breakloop: ; + } // ( ... )+ + match('.'); + mDECIMAL_DIGIT(false); + } + } + catch (RecognitionException) + { + synPredMatched177 = false; + } + + rewind(_m177); + inputState.guessing--; + } + + if (synPredMatched177) + { + { + // ( ... )+ + int _cnt179 = 0; + for (;;) + { + if (((cached_LA1 >= '0' && cached_LA1 <= '9'))) + { + mDECIMAL_DIGIT(false); + } + else + { + if (_cnt179 >= 1) { goto _loop179_breakloop; } + else + { + throw new NoViableAltForCharException(cached_LA1, getFilename(), getLine(), getColumn()); + ; + } + } + + _cnt179++; + } + + _loop179_breakloop: ; + } // ( ... )+ + match('.'); + { + // ( ... )+ + int _cnt181 = 0; + for (;;) + { + if (((cached_LA1 >= '0' && cached_LA1 <= '9'))) + { + mDECIMAL_DIGIT(false); + } + else + { + if (_cnt181 >= 1) { goto _loop181_breakloop; } + else + { + throw new NoViableAltForCharException(cached_LA1, getFilename(), getLine(), getColumn()); + ; + } + } + + _cnt181++; + } + + _loop181_breakloop: ; + } // ( ... )+ + { + if ((cached_LA1 == 'E' || cached_LA1 == 'e')) + { + mEXPONENT_PART(false); + } + else + { + } + } + { + if ((tokenSet_3_.member(cached_LA1))) + { + mREAL_TYPE_SUFFIX(false); + } + else + { + } + } + if (0 == inputState.guessing) + { + _ttype = REAL_LITERAL; + } + } + else + { + bool synPredMatched188 = false; + if ((((cached_LA1 >= '0' && cached_LA1 <= '9')) && (tokenSet_4_.member(cached_LA2)))) + { + int _m188 = mark(); + synPredMatched188 = true; + inputState.guessing++; + try + { + { + { + // ( ... )+ + int _cnt186 = 0; + for (;;) + { + if (((cached_LA1 >= '0' && cached_LA1 <= '9'))) + { + mDECIMAL_DIGIT(false); + } + else + { + if (_cnt186 >= 1) { goto _loop186_breakloop; } + else + { + throw new NoViableAltForCharException(cached_LA1, getFilename(), getLine(), getColumn()); + ; + } + } + + _cnt186++; + } + + _loop186_breakloop: ; + } // ( ... )+ + { + mEXPONENT_PART(false); + } + } + } + catch (RecognitionException) + { + synPredMatched188 = false; + } + + rewind(_m188); + inputState.guessing--; + } + + if (synPredMatched188) + { + { + // ( ... )+ + int _cnt190 = 0; + for (;;) + { + if (((cached_LA1 >= '0' && cached_LA1 <= '9'))) + { + mDECIMAL_DIGIT(false); + } + else + { + if (_cnt190 >= 1) { goto _loop190_breakloop; } + else + { + throw new NoViableAltForCharException(cached_LA1, getFilename(), getLine(), getColumn()); + ; + } + } + + _cnt190++; + } + + _loop190_breakloop: ; + } // ( ... )+ + { + mEXPONENT_PART(false); + } + { + if ((tokenSet_3_.member(cached_LA1))) + { + mREAL_TYPE_SUFFIX(false); + } + else + { + } + } + if (0 == inputState.guessing) + { + _ttype = REAL_LITERAL; + } + } + else + { + bool synPredMatched197 = false; + if ((((cached_LA1 >= '0' && cached_LA1 <= '9')) && (tokenSet_5_.member(cached_LA2)))) + { + int _m197 = mark(); + synPredMatched197 = true; + inputState.guessing++; + try + { + { + { + // ( ... )+ + int _cnt195 = 0; + for (;;) + { + if (((cached_LA1 >= '0' && cached_LA1 <= '9'))) + { + mDECIMAL_DIGIT(false); + } + else + { + if (_cnt195 >= 1) { goto _loop195_breakloop; } + else + { + throw new NoViableAltForCharException(cached_LA1, getFilename(), getLine(), getColumn()); + ; + } + } + + _cnt195++; + } + + _loop195_breakloop: ; + } // ( ... )+ + { + mREAL_TYPE_SUFFIX(false); + } + } + } + catch (RecognitionException) + { + synPredMatched197 = false; + } + + rewind(_m197); + inputState.guessing--; + } + + if (synPredMatched197) + { + { + // ( ... )+ + int _cnt199 = 0; + for (;;) + { + if (((cached_LA1 >= '0' && cached_LA1 <= '9'))) + { + mDECIMAL_DIGIT(false); + } + else + { + if (_cnt199 >= 1) { goto _loop199_breakloop; } + else + { + throw new NoViableAltForCharException(cached_LA1, getFilename(), getLine(), getColumn()); + ; + } + } + + _cnt199++; + } + + _loop199_breakloop: ; + } // ( ... )+ + { + mREAL_TYPE_SUFFIX(false); + } + if (0 == inputState.guessing) + { + _ttype = REAL_LITERAL; + } + } + else if (((cached_LA1 >= '0' && cached_LA1 <= '9')) && (true)) + { + { + // ( ... )+ + int _cnt202 = 0; + for (;;) + { + if (((cached_LA1 >= '0' && cached_LA1 <= '9'))) + { + mDECIMAL_DIGIT(false); + } + else + { + if (_cnt202 >= 1) { goto _loop202_breakloop; } + else + { + throw new NoViableAltForCharException(cached_LA1, getFilename(), getLine(), getColumn()); + ; + } + } + + _cnt202++; + } + + _loop202_breakloop: ; + } // ( ... )+ + { + if ((tokenSet_6_.member(cached_LA1))) + { + mINTEGER_TYPE_SUFFIX(false); + } + else + { + } + } + if (0 == inputState.guessing) + { + _ttype = INTEGER_LITERAL; + } + } + else if ((cached_LA1 == '.') && (true)) + { + match('.'); + if (0 == inputState.guessing) + { + _ttype = DOT; + } + } + else + { + throw new NoViableAltForCharException(cached_LA1, getFilename(), getLine(), getColumn()); + } + } + } + } + + if (_createToken && (null == _token) && (_ttype != Token.SKIP)) + { + _token = makeToken(_ttype); + _token.setText(text.ToString(_begin, text.Length - _begin)); + } + + returnToken_ = _token; + } + + protected void mDECIMAL_DIGIT(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException + { + int _ttype; + IToken _token = null; + int _begin = text.Length; + _ttype = DECIMAL_DIGIT; + + matchRange('0', '9'); + if (_createToken && (null == _token) && (_ttype != Token.SKIP)) + { + _token = makeToken(_ttype); + _token.setText(text.ToString(_begin, text.Length - _begin)); + } + + returnToken_ = _token; + } + + protected void mEXPONENT_PART(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException + { + int _ttype; + IToken _token = null; + int _begin = text.Length; + _ttype = EXPONENT_PART; + + switch (cached_LA1) + { + case 'e': + { + match("e"); + { + // ( ... )* + for (;;) + { + if ((cached_LA1 == '+' || cached_LA1 == '-')) + { + mSIGN(false); + } + else + { + goto _loop214_breakloop; + } + } + + _loop214_breakloop: ; + } // ( ... )* + { + // ( ... )+ + int _cnt216 = 0; + for (;;) + { + if (((cached_LA1 >= '0' && cached_LA1 <= '9'))) + { + mDECIMAL_DIGIT(false); + } + else + { + if (_cnt216 >= 1) { goto _loop216_breakloop; } + else + { + throw new NoViableAltForCharException(cached_LA1, getFilename(), getLine(), getColumn()); + ; + } + } + + _cnt216++; + } + + _loop216_breakloop: ; + } // ( ... )+ + break; + } + case 'E': + { + match("E"); + { + // ( ... )* + for (;;) + { + if ((cached_LA1 == '+' || cached_LA1 == '-')) + { + mSIGN(false); + } + else + { + goto _loop218_breakloop; + } + } + + _loop218_breakloop: ; + } // ( ... )* + { + // ( ... )+ + int _cnt220 = 0; + for (;;) + { + if (((cached_LA1 >= '0' && cached_LA1 <= '9'))) + { + mDECIMAL_DIGIT(false); + } + else + { + if (_cnt220 >= 1) { goto _loop220_breakloop; } + else + { + throw new NoViableAltForCharException(cached_LA1, getFilename(), getLine(), getColumn()); + ; + } + } + + _cnt220++; + } + + _loop220_breakloop: ; + } // ( ... )+ + break; + } + default: + { + throw new NoViableAltForCharException(cached_LA1, getFilename(), getLine(), getColumn()); + } + } + + if (_createToken && (null == _token) && (_ttype != Token.SKIP)) + { + _token = makeToken(_ttype); + _token.setText(text.ToString(_begin, text.Length - _begin)); + } + + returnToken_ = _token; + } + + protected void mREAL_TYPE_SUFFIX(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException + { + int _ttype; + IToken _token = null; + int _begin = text.Length; + _ttype = REAL_TYPE_SUFFIX; + + switch (cached_LA1) + { + case 'F': + { + match('F'); + break; + } + case 'f': + { + match('f'); + break; + } + case 'D': + { + match('D'); + break; + } + case 'd': + { + match('d'); + break; + } + case 'M': + { + match('M'); + break; + } + case 'm': + { + match('m'); + break; + } + default: + { + throw new NoViableAltForCharException(cached_LA1, getFilename(), getLine(), getColumn()); + } + } + + if (_createToken && (null == _token) && (_ttype != Token.SKIP)) + { + _token = makeToken(_ttype); + _token.setText(text.ToString(_begin, text.Length - _begin)); + } + + returnToken_ = _token; + } + + protected void mINTEGER_TYPE_SUFFIX(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException + { + int _ttype; + IToken _token = null; + int _begin = text.Length; + _ttype = INTEGER_TYPE_SUFFIX; + + { + if ((cached_LA1 == 'U') && (cached_LA2 == 'L')) + { + match("UL"); + } + else if ((cached_LA1 == 'L') && (cached_LA2 == 'U')) + { + match("LU"); + } + else if ((cached_LA1 == 'u') && (cached_LA2 == 'l')) + { + match("ul"); + } + else if ((cached_LA1 == 'l') && (cached_LA2 == 'u')) + { + match("lu"); + } + else if ((cached_LA1 == 'U') && (cached_LA2 == 'L')) + { + match("UL"); + } + else if ((cached_LA1 == 'L') && (cached_LA2 == 'U')) + { + match("LU"); + } + else if ((cached_LA1 == 'u') && (cached_LA2 == 'L')) + { + match("uL"); + } + else if ((cached_LA1 == 'l') && (cached_LA2 == 'U')) + { + match("lU"); + } + else if ((cached_LA1 == 'U') && (true)) + { + match("U"); + } + else if ((cached_LA1 == 'L') && (true)) + { + match("L"); + } + else if ((cached_LA1 == 'u') && (true)) + { + match("u"); + } + else if ((cached_LA1 == 'l') && (true)) + { + match("l"); + } + else + { + throw new NoViableAltForCharException(cached_LA1, getFilename(), getLine(), getColumn()); + } + } + if (_createToken && (null == _token) && (_ttype != Token.SKIP)) + { + _token = makeToken(_ttype); + _token.setText(text.ToString(_begin, text.Length - _begin)); + } + + returnToken_ = _token; + } + + public void mHEXADECIMAL_INTEGER_LITERAL(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException + { + int _ttype; + IToken _token = null; + int _begin = text.Length; + _ttype = HEXADECIMAL_INTEGER_LITERAL; + + match("0x"); + { + // ( ... )+ + int _cnt206 = 0; + for (;;) + { + if ((tokenSet_7_.member(cached_LA1))) + { + mHEX_DIGIT(false); + } + else + { + if (_cnt206 >= 1) { goto _loop206_breakloop; } + else + { + throw new NoViableAltForCharException(cached_LA1, getFilename(), getLine(), getColumn()); + ; + } + } + + _cnt206++; + } + + _loop206_breakloop: ; + } // ( ... )+ + { + if ((tokenSet_6_.member(cached_LA1))) + { + mINTEGER_TYPE_SUFFIX(false); + } + else + { + } + } + if (_createToken && (null == _token) && (_ttype != Token.SKIP)) + { + _token = makeToken(_ttype); + _token.setText(text.ToString(_begin, text.Length - _begin)); + } + + returnToken_ = _token; + } + + protected void mHEX_DIGIT(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException + { + int _ttype; + IToken _token = null; + int _begin = text.Length; + _ttype = HEX_DIGIT; + + switch (cached_LA1) + { + case '0': + { + match('0'); + break; + } + case '1': + { + match('1'); + break; + } + case '2': + { + match('2'); + break; + } + case '3': + { + match('3'); + break; + } + case '4': + { + match('4'); + break; + } + case '5': + { + match('5'); + break; + } + case '6': + { + match('6'); + break; + } + case '7': + { + match('7'); + break; + } + case '8': + { + match('8'); + break; + } + case '9': + { + match('9'); + break; + } + case 'A': + { + match('A'); + break; + } + case 'B': + { + match('B'); + break; + } + case 'C': + { + match('C'); + break; + } + case 'D': + { + match('D'); + break; + } + case 'E': + { + match('E'); + break; + } + case 'F': + { + match('F'); + break; + } + case 'a': + { + match('a'); + break; + } + case 'b': + { + match('b'); + break; + } + case 'c': + { + match('c'); + break; + } + case 'd': + { + match('d'); + break; + } + case 'e': + { + match('e'); + break; + } + case 'f': + { + match('f'); + break; + } + default: + { + throw new NoViableAltForCharException(cached_LA1, getFilename(), getLine(), getColumn()); + } + } + + if (_createToken && (null == _token) && (_ttype != Token.SKIP)) + { + _token = makeToken(_ttype); + _token.setText(text.ToString(_begin, text.Length - _begin)); + } + + returnToken_ = _token; + } + + protected void mSIGN(bool _createToken) //throws RecognitionException, CharStreamException, TokenStreamException + { + int _ttype; + IToken _token = null; + int _begin = text.Length; + _ttype = SIGN; + + switch (cached_LA1) + { + case '+': + { + match('+'); + break; + } + case '-': + { + match('-'); + break; + } + default: + { + throw new NoViableAltForCharException(cached_LA1, getFilename(), getLine(), getColumn()); + } + } + + if (_createToken && (null == _token) && (_ttype != Token.SKIP)) + { + _token = makeToken(_ttype); + _token.setText(text.ToString(_begin, text.Length - _begin)); + } + + returnToken_ = _token; + } + + private static long[] mk_tokenSet_0_() + { + long[] data = new long[1025]; + data[0] = 0L; + data[1] = 576460745995190270L; + for (int i = 2; i <= 1024; i++) { data[i] = 0L; } + + return data; + } + + public static readonly BitSet tokenSet_0_ = new BitSet(mk_tokenSet_0_()); + + private static long[] mk_tokenSet_1_() + { + long[] data = new long[1025]; + data[0] = 288019269919178752L; + for (int i = 1; i <= 1024; i++) { data[i] = 0L; } + + return data; + } + + public static readonly BitSet tokenSet_1_ = new BitSet(mk_tokenSet_1_()); + + private static long[] mk_tokenSet_2_() + { + long[] data = new long[2048]; + data[0] = -549755813889L; + for (int i = 1; i <= 1022; i++) { data[i] = -1L; } + + data[1023] = 9223372036854775807L; + for (int i = 1024; i <= 2047; i++) { data[i] = 0L; } + + return data; + } + + public static readonly BitSet tokenSet_2_ = new BitSet(mk_tokenSet_2_()); + + private static long[] mk_tokenSet_3_() + { + long[] data = new long[1025]; + data[0] = 0L; + data[1] = 35527969480784L; + for (int i = 2; i <= 1024; i++) { data[i] = 0L; } + + return data; + } + + public static readonly BitSet tokenSet_3_ = new BitSet(mk_tokenSet_3_()); + + private static long[] mk_tokenSet_4_() + { + long[] data = new long[1025]; + data[0] = 287948901175001088L; + data[1] = 137438953504L; + for (int i = 2; i <= 1024; i++) { data[i] = 0L; } + + return data; + } + + public static readonly BitSet tokenSet_4_ = new BitSet(mk_tokenSet_4_()); + + private static long[] mk_tokenSet_5_() + { + long[] data = new long[1025]; + data[0] = 287948901175001088L; + data[1] = 35527969480784L; + for (int i = 2; i <= 1024; i++) { data[i] = 0L; } + + return data; + } + + public static readonly BitSet tokenSet_5_ = new BitSet(mk_tokenSet_5_()); + + private static long[] mk_tokenSet_6_() + { + long[] data = new long[1025]; + data[0] = 0L; + data[1] = 9024791442886656L; + for (int i = 2; i <= 1024; i++) { data[i] = 0L; } + + return data; + } + + public static readonly BitSet tokenSet_6_ = new BitSet(mk_tokenSet_6_()); + + private static long[] mk_tokenSet_7_() + { + long[] data = new long[1025]; + data[0] = 287948901175001088L; + data[1] = 541165879422L; + for (int i = 2; i <= 1024; i++) { data[i] = 0L; } + + return data; + } + + public static readonly BitSet tokenSet_7_ = new BitSet(mk_tokenSet_7_()); } diff --git a/src/Spring/Spring.Core/Expressions/Parser/ExpressionParser.cs b/src/Spring/Spring.Core/Expressions/Parser/ExpressionParser.cs index 1124ebb5..ba692cfd 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/ExpressionParser.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/ExpressionParser.cs @@ -1,106 +1,104 @@ // $ANTLR 2.7.6 (2005-12-22): "Expression.g" -> "ExpressionParser.cs"$ -namespace Spring.Expressions.Parser +namespace Spring.Expressions.Parser; + +// Generate the header common to all output files. +using System; +using TokenBuffer = antlr.TokenBuffer; +using Token = antlr.Token; +using TokenStream = antlr.TokenStream; +using RecognitionException = antlr.RecognitionException; +using NoViableAltException = antlr.NoViableAltException; +using ParserSharedInputState = antlr.ParserSharedInputState; +using BitSet = antlr.collections.impl.BitSet; +using AST = antlr.collections.AST; +using ASTPair = antlr.ASTPair; +using ASTFactory = antlr.ASTFactory; + +internal class ExpressionParser : antlr.LLkParser { - // Generate the header common to all output files. - using System; - - using TokenBuffer = antlr.TokenBuffer; - using Token = antlr.Token; - using TokenStream = antlr.TokenStream; - using RecognitionException = antlr.RecognitionException; - using NoViableAltException = antlr.NoViableAltException; - using ParserSharedInputState = antlr.ParserSharedInputState; - using BitSet = antlr.collections.impl.BitSet; - using AST = antlr.collections.AST; - using ASTPair = antlr.ASTPair; - using ASTFactory = antlr.ASTFactory; - - internal class ExpressionParser : antlr.LLkParser - { - public const int EOF = 1; - public const int NULL_TREE_LOOKAHEAD = 3; - public const int EXPR = 4; - public const int OPERAND = 5; - public const int FALSE = 6; - public const int TRUE = 7; - public const int AND = 8; - public const int OR = 9; - public const int XOR = 10; - public const int IN = 11; - public const int IS = 12; - public const int BETWEEN = 13; - public const int LIKE = 14; - public const int MATCHES = 15; - public const int NULL_LITERAL = 16; - public const int LPAREN = 17; - public const int SEMI = 18; - public const int RPAREN = 19; - public const int ASSIGN = 20; - public const int DEFAULT = 21; - public const int QMARK = 22; - public const int COLON = 23; - public const int PLUS = 24; - public const int MINUS = 25; - public const int STAR = 26; - public const int DIV = 27; - public const int MOD = 28; - public const int POWER = 29; - public const int BANG = 30; - public const int DOT = 31; - public const int POUND = 32; - public const int ID = 33; - public const int DOLLAR = 34; - public const int COMMA = 35; - public const int AT = 36; - public const int LBRACKET = 37; - public const int RBRACKET = 38; - public const int PROJECT = 39; - public const int RCURLY = 40; - public const int SELECT = 41; - public const int SELECT_FIRST = 42; - public const int SELECT_LAST = 43; - public const int TYPE = 44; - public const int QUOTE = 45; - public const int STRING_LITERAL = 46; - public const int LAMBDA = 47; - public const int PIPE = 48; - public const int LITERAL_new = 49; - public const int LCURLY = 50; - public const int INTEGER_LITERAL = 51; - public const int HEXADECIMAL_INTEGER_LITERAL = 52; - public const int REAL_LITERAL = 53; - public const int EQUAL = 54; - public const int NOT_EQUAL = 55; - public const int LESS_THAN = 56; - public const int LESS_THAN_OR_EQUAL = 57; - public const int GREATER_THAN = 58; - public const int GREATER_THAN_OR_EQUAL = 59; - public const int WS = 60; - public const int BACKTICK = 61; - public const int BACKSLASH = 62; - public const int DOT_ESCAPED = 63; - public const int APOS = 64; - public const int NUMERIC_LITERAL = 65; - public const int DECIMAL_DIGIT = 66; - public const int INTEGER_TYPE_SUFFIX = 67; - public const int HEX_DIGIT = 68; - public const int EXPONENT_PART = 69; - public const int SIGN = 70; - public const int REAL_TYPE_SUFFIX = 71; - + public const int EOF = 1; + public const int NULL_TREE_LOOKAHEAD = 3; + public const int EXPR = 4; + public const int OPERAND = 5; + public const int FALSE = 6; + public const int TRUE = 7; + public const int AND = 8; + public const int OR = 9; + public const int XOR = 10; + public const int IN = 11; + public const int IS = 12; + public const int BETWEEN = 13; + public const int LIKE = 14; + public const int MATCHES = 15; + public const int NULL_LITERAL = 16; + public const int LPAREN = 17; + public const int SEMI = 18; + public const int RPAREN = 19; + public const int ASSIGN = 20; + public const int DEFAULT = 21; + public const int QMARK = 22; + public const int COLON = 23; + public const int PLUS = 24; + public const int MINUS = 25; + public const int STAR = 26; + public const int DIV = 27; + public const int MOD = 28; + public const int POWER = 29; + public const int BANG = 30; + public const int DOT = 31; + public const int POUND = 32; + public const int ID = 33; + public const int DOLLAR = 34; + public const int COMMA = 35; + public const int AT = 36; + public const int LBRACKET = 37; + public const int RBRACKET = 38; + public const int PROJECT = 39; + public const int RCURLY = 40; + public const int SELECT = 41; + public const int SELECT_FIRST = 42; + public const int SELECT_LAST = 43; + public const int TYPE = 44; + public const int QUOTE = 45; + public const int STRING_LITERAL = 46; + public const int LAMBDA = 47; + public const int PIPE = 48; + public const int LITERAL_new = 49; + public const int LCURLY = 50; + public const int INTEGER_LITERAL = 51; + public const int HEXADECIMAL_INTEGER_LITERAL = 52; + public const int REAL_LITERAL = 53; + public const int EQUAL = 54; + public const int NOT_EQUAL = 55; + public const int LESS_THAN = 56; + public const int LESS_THAN_OR_EQUAL = 57; + public const int GREATER_THAN = 58; + public const int GREATER_THAN_OR_EQUAL = 59; + public const int WS = 60; + public const int BACKTICK = 61; + public const int BACKSLASH = 62; + public const int DOT_ESCAPED = 63; + public const int APOS = 64; + public const int NUMERIC_LITERAL = 65; + public const int DECIMAL_DIGIT = 66; + public const int INTEGER_TYPE_SUFFIX = 67; + public const int HEX_DIGIT = 68; + public const int EXPONENT_PART = 69; + public const int SIGN = 70; + public const int REAL_TYPE_SUFFIX = 71; // CLOVER:OFF public override void reportError(RecognitionException ex) { - //base.reportError(ex); + //base.reportError(ex); throw new antlr.TokenStreamRecognitionException(ex); } public override void reportError(string error) { - //base.reportError(error); + //base.reportError(error); throw new RecognitionException(error); } @@ -108,3376 +106,3591 @@ namespace Spring.Expressions.Parser { switch (op) { - case "==" : return "Spring.Expressions.OpEqual"; - case "!=" : return "Spring.Expressions.OpNotEqual"; - case "<" : return "Spring.Expressions.OpLess"; - case "<=" : return "Spring.Expressions.OpLessOrEqual"; - case ">" : return "Spring.Expressions.OpGreater"; - case ">=" : return "Spring.Expressions.OpGreaterOrEqual"; - case "in" : return "Spring.Expressions.OpIn"; - case "is" : return "Spring.Expressions.OpIs"; - case "between" : return "Spring.Expressions.OpBetween"; - case "like" : return "Spring.Expressions.OpLike"; - case "matches" : return "Spring.Expressions.OpMatches"; - default : + case "==": return "Spring.Expressions.OpEqual"; + case "!=": return "Spring.Expressions.OpNotEqual"; + case "<": return "Spring.Expressions.OpLess"; + case "<=": return "Spring.Expressions.OpLessOrEqual"; + case ">": return "Spring.Expressions.OpGreater"; + case ">=": return "Spring.Expressions.OpGreaterOrEqual"; + case "in": return "Spring.Expressions.OpIn"; + case "is": return "Spring.Expressions.OpIs"; + case "between": return "Spring.Expressions.OpBetween"; + case "like": return "Spring.Expressions.OpLike"; + case "matches": return "Spring.Expressions.OpMatches"; + default: throw new ArgumentException("Node type for operator '" + op + "' is not defined."); } } - protected void initialize() - { - tokenNames = tokenNames_; - initializeFactory(); - } - - - protected ExpressionParser(TokenBuffer tokenBuf, int k) : base(tokenBuf, k) - { - initialize(); - } - - public ExpressionParser(TokenBuffer tokenBuf) : this(tokenBuf,2) - { - } - - protected ExpressionParser(TokenStream lexer, int k) : base(lexer,k) - { - initialize(); - } - - public ExpressionParser(TokenStream lexer) : this(lexer,2) - { - } - - public ExpressionParser(ParserSharedInputState state) : base(state,2) - { - initialize(); - } - - public void expr() //throws RecognitionException, TokenStreamException -{ - - returnAST = null; - ASTPair currentAST = new ASTPair(); - Spring.Expressions.SpringAST expr_AST = null; - - try { // for error handling - expression(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - match(Token.EOF_TYPE); - expr_AST = (Spring.Expressions.SpringAST)currentAST.root; - } - catch (RecognitionException ex) - { - if (0 == inputState.guessing) - { - reportError(ex); - recover(ex,tokenSet_0_); - } - else - { - throw ex; - } - } - returnAST = expr_AST; - } - - public void expression() //throws RecognitionException, TokenStreamException -{ - - returnAST = null; - ASTPair currentAST = new ASTPair(); - Spring.Expressions.SpringAST expression_AST = null; - - try { // for error handling - logicalOrExpression(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - { - switch ( LA(1) ) - { - case ASSIGN: - { - { - Spring.Expressions.AssignNode tmp2_AST = null; - tmp2_AST = (Spring.Expressions.AssignNode) astFactory.create(LT(1), "Spring.Expressions.AssignNode"); - astFactory.makeASTRoot(ref currentAST, (AST)tmp2_AST); - match(ASSIGN); - logicalOrExpression(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - } - break; - } - case DEFAULT: - { - { - Spring.Expressions.DefaultNode tmp3_AST = null; - tmp3_AST = (Spring.Expressions.DefaultNode) astFactory.create(LT(1), "Spring.Expressions.DefaultNode"); - astFactory.makeASTRoot(ref currentAST, (AST)tmp3_AST); - match(DEFAULT); - logicalOrExpression(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - } - break; - } - case QMARK: - { - { - Spring.Expressions.TernaryNode tmp4_AST = null; - tmp4_AST = (Spring.Expressions.TernaryNode) astFactory.create(LT(1), "Spring.Expressions.TernaryNode"); - astFactory.makeASTRoot(ref currentAST, (AST)tmp4_AST); - match(QMARK); - expression(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - match(COLON); - expression(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - } - break; - } - case EOF: - case SEMI: - case RPAREN: - case COLON: - case COMMA: - case RBRACKET: - case RCURLY: - { - break; - } - default: - { - throw new NoViableAltException(LT(1), getFilename()); - } - } - } - expression_AST = (Spring.Expressions.SpringAST)currentAST.root; - } - catch (RecognitionException ex) - { - if (0 == inputState.guessing) - { - reportError(ex); - recover(ex,tokenSet_1_); - } - else - { - throw ex; - } - } - returnAST = expression_AST; - } - - public void exprList() //throws RecognitionException, TokenStreamException -{ - - returnAST = null; - ASTPair currentAST = new ASTPair(); - Spring.Expressions.SpringAST exprList_AST = null; - - try { // for error handling - match(LPAREN); - expression(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - { // ( ... )+ - int _cnt4=0; - for (;;) - { - if ((LA(1)==SEMI)) - { - match(SEMI); - expression(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - } - else - { - if (_cnt4 >= 1) { goto _loop4_breakloop; } else { throw new NoViableAltException(LT(1), getFilename());; } - } - - _cnt4++; - } -_loop4_breakloop: ; - } // ( ... )+ - match(RPAREN); - if (0==inputState.guessing) - { - exprList_AST = (Spring.Expressions.SpringAST)currentAST.root; - exprList_AST = (Spring.Expressions.SpringAST) astFactory.make((AST)(Spring.Expressions.SpringAST) astFactory.create(EXPR,"expressionList","Spring.Expressions.ExpressionListNode"), (AST)exprList_AST); - currentAST.root = exprList_AST; - if ( (null != exprList_AST) && (null != exprList_AST.getFirstChild()) ) - currentAST.child = exprList_AST.getFirstChild(); - else - currentAST.child = exprList_AST; - currentAST.advanceChildToEnd(); - } - exprList_AST = (Spring.Expressions.SpringAST)currentAST.root; - } - catch (RecognitionException ex) - { - if (0 == inputState.guessing) - { - reportError(ex); - recover(ex,tokenSet_2_); - } - else - { - throw ex; - } - } - returnAST = exprList_AST; - } - - public void logicalOrExpression() //throws RecognitionException, TokenStreamException -{ - - returnAST = null; - ASTPair currentAST = new ASTPair(); - Spring.Expressions.SpringAST logicalOrExpression_AST = null; - - try { // for error handling - logicalXorExpression(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - { // ( ... )* - for (;;) - { - if ((LA(1)==OR)) - { - Spring.Expressions.OpOR tmp9_AST = null; - tmp9_AST = (Spring.Expressions.OpOR) astFactory.create(LT(1), "Spring.Expressions.OpOR"); - astFactory.makeASTRoot(ref currentAST, (AST)tmp9_AST); - match(OR); - logicalXorExpression(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - } - else - { - goto _loop13_breakloop; - } - - } -_loop13_breakloop: ; - } // ( ... )* - logicalOrExpression_AST = (Spring.Expressions.SpringAST)currentAST.root; - } - catch (RecognitionException ex) - { - if (0 == inputState.guessing) - { - reportError(ex); - recover(ex,tokenSet_3_); - } - else - { - throw ex; - } - } - returnAST = logicalOrExpression_AST; - } - - public void parenExpr() //throws RecognitionException, TokenStreamException -{ - - returnAST = null; - ASTPair currentAST = new ASTPair(); - Spring.Expressions.SpringAST parenExpr_AST = null; - - try { // for error handling - match(LPAREN); - expression(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - match(RPAREN); - parenExpr_AST = (Spring.Expressions.SpringAST)currentAST.root; - } - catch (RecognitionException ex) - { - if (0 == inputState.guessing) - { - reportError(ex); - recover(ex,tokenSet_2_); - } - else - { - throw ex; - } - } - returnAST = parenExpr_AST; - } - - public void logicalXorExpression() //throws RecognitionException, TokenStreamException -{ - - returnAST = null; - ASTPair currentAST = new ASTPair(); - Spring.Expressions.SpringAST logicalXorExpression_AST = null; - - try { // for error handling - logicalAndExpression(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - { // ( ... )* - for (;;) - { - if ((LA(1)==XOR)) - { - Spring.Expressions.OpXOR tmp12_AST = null; - tmp12_AST = (Spring.Expressions.OpXOR) astFactory.create(LT(1), "Spring.Expressions.OpXOR"); - astFactory.makeASTRoot(ref currentAST, (AST)tmp12_AST); - match(XOR); - logicalAndExpression(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - } - else - { - goto _loop16_breakloop; - } - - } -_loop16_breakloop: ; - } // ( ... )* - logicalXorExpression_AST = (Spring.Expressions.SpringAST)currentAST.root; - } - catch (RecognitionException ex) - { - if (0 == inputState.guessing) - { - reportError(ex); - recover(ex,tokenSet_4_); - } - else - { - throw ex; - } - } - returnAST = logicalXorExpression_AST; - } - - public void logicalAndExpression() //throws RecognitionException, TokenStreamException -{ - - returnAST = null; - ASTPair currentAST = new ASTPair(); - Spring.Expressions.SpringAST logicalAndExpression_AST = null; - - try { // for error handling - relationalExpression(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - { // ( ... )* - for (;;) - { - if ((LA(1)==AND)) - { - Spring.Expressions.OpAND tmp13_AST = null; - tmp13_AST = (Spring.Expressions.OpAND) astFactory.create(LT(1), "Spring.Expressions.OpAND"); - astFactory.makeASTRoot(ref currentAST, (AST)tmp13_AST); - match(AND); - relationalExpression(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - } - else - { - goto _loop19_breakloop; - } - - } -_loop19_breakloop: ; - } // ( ... )* - logicalAndExpression_AST = (Spring.Expressions.SpringAST)currentAST.root; - } - catch (RecognitionException ex) - { - if (0 == inputState.guessing) - { - reportError(ex); - recover(ex,tokenSet_5_); - } - else - { - throw ex; - } - } - returnAST = logicalAndExpression_AST; - } - - public void relationalExpression() //throws RecognitionException, TokenStreamException -{ - - returnAST = null; - ASTPair currentAST = new ASTPair(); - Spring.Expressions.SpringAST relationalExpression_AST = null; - Spring.Expressions.SpringAST e1_AST = null; - Spring.Expressions.SpringAST op_AST = null; - Spring.Expressions.SpringAST e2_AST = null; - - try { // for error handling - sumExpr(); - if (0 == inputState.guessing) - { - e1_AST = (Spring.Expressions.SpringAST)returnAST; - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - { - if ((tokenSet_6_.member(LA(1)))) - { - relationalOperator(); - if (0 == inputState.guessing) - { - op_AST = (Spring.Expressions.SpringAST)returnAST; - } - sumExpr(); - if (0 == inputState.guessing) - { - e2_AST = (Spring.Expressions.SpringAST)returnAST; - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - if (0==inputState.guessing) - { - relationalExpression_AST = (Spring.Expressions.SpringAST)currentAST.root; - relationalExpression_AST = (Spring.Expressions.SpringAST) astFactory.make((AST)(Spring.Expressions.SpringAST) astFactory.create(EXPR,op_AST.getText(),GetRelationalOperatorNodeType(op_AST.getText())), (AST)relationalExpression_AST); - currentAST.root = relationalExpression_AST; - if ( (null != relationalExpression_AST) && (null != relationalExpression_AST.getFirstChild()) ) - currentAST.child = relationalExpression_AST.getFirstChild(); - else - currentAST.child = relationalExpression_AST; - currentAST.advanceChildToEnd(); - } - } - else if ((tokenSet_7_.member(LA(1)))) { - } - else - { - throw new NoViableAltException(LT(1), getFilename()); - } - - } - relationalExpression_AST = (Spring.Expressions.SpringAST)currentAST.root; - } - catch (RecognitionException ex) - { - if (0 == inputState.guessing) - { - reportError(ex); - recover(ex,tokenSet_7_); - } - else - { - throw ex; - } - } - returnAST = relationalExpression_AST; - } - - public void sumExpr() //throws RecognitionException, TokenStreamException -{ - - returnAST = null; - ASTPair currentAST = new ASTPair(); - Spring.Expressions.SpringAST sumExpr_AST = null; - - try { // for error handling - prodExpr(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - { // ( ... )* - for (;;) - { - if ((LA(1)==PLUS||LA(1)==MINUS)) - { - { - if ((LA(1)==PLUS)) - { - Spring.Expressions.OpADD tmp14_AST = null; - tmp14_AST = (Spring.Expressions.OpADD) astFactory.create(LT(1), "Spring.Expressions.OpADD"); - astFactory.makeASTRoot(ref currentAST, (AST)tmp14_AST); - match(PLUS); - } - else if ((LA(1)==MINUS)) { - Spring.Expressions.OpSUBTRACT tmp15_AST = null; - tmp15_AST = (Spring.Expressions.OpSUBTRACT) astFactory.create(LT(1), "Spring.Expressions.OpSUBTRACT"); - astFactory.makeASTRoot(ref currentAST, (AST)tmp15_AST); - match(MINUS); - } - else - { - throw new NoViableAltException(LT(1), getFilename()); - } - - } - prodExpr(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - } - else - { - goto _loop25_breakloop; - } - - } -_loop25_breakloop: ; - } // ( ... )* - sumExpr_AST = (Spring.Expressions.SpringAST)currentAST.root; - } - catch (RecognitionException ex) - { - if (0 == inputState.guessing) - { - reportError(ex); - recover(ex,tokenSet_8_); - } - else - { - throw ex; - } - } - returnAST = sumExpr_AST; - } - - public void relationalOperator() //throws RecognitionException, TokenStreamException -{ - - returnAST = null; - ASTPair currentAST = new ASTPair(); - Spring.Expressions.SpringAST relationalOperator_AST = null; - - try { // for error handling - switch ( LA(1) ) - { - case EQUAL: - { - Spring.Expressions.SpringAST tmp16_AST = null; - tmp16_AST = (Spring.Expressions.SpringAST) astFactory.create(LT(1)); - astFactory.addASTChild(ref currentAST, (AST)tmp16_AST); - match(EQUAL); - relationalOperator_AST = (Spring.Expressions.SpringAST)currentAST.root; - break; - } - case NOT_EQUAL: - { - Spring.Expressions.SpringAST tmp17_AST = null; - tmp17_AST = (Spring.Expressions.SpringAST) astFactory.create(LT(1)); - astFactory.addASTChild(ref currentAST, (AST)tmp17_AST); - match(NOT_EQUAL); - relationalOperator_AST = (Spring.Expressions.SpringAST)currentAST.root; - break; - } - case LESS_THAN: - { - Spring.Expressions.SpringAST tmp18_AST = null; - tmp18_AST = (Spring.Expressions.SpringAST) astFactory.create(LT(1)); - astFactory.addASTChild(ref currentAST, (AST)tmp18_AST); - match(LESS_THAN); - relationalOperator_AST = (Spring.Expressions.SpringAST)currentAST.root; - break; - } - case LESS_THAN_OR_EQUAL: - { - Spring.Expressions.SpringAST tmp19_AST = null; - tmp19_AST = (Spring.Expressions.SpringAST) astFactory.create(LT(1)); - astFactory.addASTChild(ref currentAST, (AST)tmp19_AST); - match(LESS_THAN_OR_EQUAL); - relationalOperator_AST = (Spring.Expressions.SpringAST)currentAST.root; - break; - } - case GREATER_THAN: - { - Spring.Expressions.SpringAST tmp20_AST = null; - tmp20_AST = (Spring.Expressions.SpringAST) astFactory.create(LT(1)); - astFactory.addASTChild(ref currentAST, (AST)tmp20_AST); - match(GREATER_THAN); - relationalOperator_AST = (Spring.Expressions.SpringAST)currentAST.root; - break; - } - case GREATER_THAN_OR_EQUAL: - { - Spring.Expressions.SpringAST tmp21_AST = null; - tmp21_AST = (Spring.Expressions.SpringAST) astFactory.create(LT(1)); - astFactory.addASTChild(ref currentAST, (AST)tmp21_AST); - match(GREATER_THAN_OR_EQUAL); - relationalOperator_AST = (Spring.Expressions.SpringAST)currentAST.root; - break; - } - case IN: - { - Spring.Expressions.SpringAST tmp22_AST = null; - tmp22_AST = (Spring.Expressions.SpringAST) astFactory.create(LT(1)); - astFactory.addASTChild(ref currentAST, (AST)tmp22_AST); - match(IN); - relationalOperator_AST = (Spring.Expressions.SpringAST)currentAST.root; - break; - } - case IS: - { - Spring.Expressions.SpringAST tmp23_AST = null; - tmp23_AST = (Spring.Expressions.SpringAST) astFactory.create(LT(1)); - astFactory.addASTChild(ref currentAST, (AST)tmp23_AST); - match(IS); - relationalOperator_AST = (Spring.Expressions.SpringAST)currentAST.root; - break; - } - case BETWEEN: - { - Spring.Expressions.SpringAST tmp24_AST = null; - tmp24_AST = (Spring.Expressions.SpringAST) astFactory.create(LT(1)); - astFactory.addASTChild(ref currentAST, (AST)tmp24_AST); - match(BETWEEN); - relationalOperator_AST = (Spring.Expressions.SpringAST)currentAST.root; - break; - } - case LIKE: - { - Spring.Expressions.SpringAST tmp25_AST = null; - tmp25_AST = (Spring.Expressions.SpringAST) astFactory.create(LT(1)); - astFactory.addASTChild(ref currentAST, (AST)tmp25_AST); - match(LIKE); - relationalOperator_AST = (Spring.Expressions.SpringAST)currentAST.root; - break; - } - case MATCHES: - { - Spring.Expressions.SpringAST tmp26_AST = null; - tmp26_AST = (Spring.Expressions.SpringAST) astFactory.create(LT(1)); - astFactory.addASTChild(ref currentAST, (AST)tmp26_AST); - match(MATCHES); - relationalOperator_AST = (Spring.Expressions.SpringAST)currentAST.root; - break; - } - default: - { - throw new NoViableAltException(LT(1), getFilename()); - } - } - } - catch (RecognitionException ex) - { - if (0 == inputState.guessing) - { - reportError(ex); - recover(ex,tokenSet_9_); - } - else - { - throw ex; - } - } - returnAST = relationalOperator_AST; - } - - public void prodExpr() //throws RecognitionException, TokenStreamException -{ - - returnAST = null; - ASTPair currentAST = new ASTPair(); - Spring.Expressions.SpringAST prodExpr_AST = null; - - try { // for error handling - powExpr(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - { // ( ... )* - for (;;) - { - if (((LA(1) >= STAR && LA(1) <= MOD))) - { - { - switch ( LA(1) ) - { - case STAR: - { - Spring.Expressions.OpMULTIPLY tmp27_AST = null; - tmp27_AST = (Spring.Expressions.OpMULTIPLY) astFactory.create(LT(1), "Spring.Expressions.OpMULTIPLY"); - astFactory.makeASTRoot(ref currentAST, (AST)tmp27_AST); - match(STAR); - break; - } - case DIV: - { - Spring.Expressions.OpDIVIDE tmp28_AST = null; - tmp28_AST = (Spring.Expressions.OpDIVIDE) astFactory.create(LT(1), "Spring.Expressions.OpDIVIDE"); - astFactory.makeASTRoot(ref currentAST, (AST)tmp28_AST); - match(DIV); - break; - } - case MOD: - { - Spring.Expressions.OpMODULUS tmp29_AST = null; - tmp29_AST = (Spring.Expressions.OpMODULUS) astFactory.create(LT(1), "Spring.Expressions.OpMODULUS"); - astFactory.makeASTRoot(ref currentAST, (AST)tmp29_AST); - match(MOD); - break; - } - default: - { - throw new NoViableAltException(LT(1), getFilename()); - } - } - } - powExpr(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - } - else - { - goto _loop29_breakloop; - } - - } -_loop29_breakloop: ; - } // ( ... )* - prodExpr_AST = (Spring.Expressions.SpringAST)currentAST.root; - } - catch (RecognitionException ex) - { - if (0 == inputState.guessing) - { - reportError(ex); - recover(ex,tokenSet_10_); - } - else - { - throw ex; - } - } - returnAST = prodExpr_AST; - } - - public void powExpr() //throws RecognitionException, TokenStreamException -{ - - returnAST = null; - ASTPair currentAST = new ASTPair(); - Spring.Expressions.SpringAST powExpr_AST = null; - - try { // for error handling - unaryExpression(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - { - if ((LA(1)==POWER)) - { - Spring.Expressions.OpPOWER tmp30_AST = null; - tmp30_AST = (Spring.Expressions.OpPOWER) astFactory.create(LT(1), "Spring.Expressions.OpPOWER"); - astFactory.makeASTRoot(ref currentAST, (AST)tmp30_AST); - match(POWER); - unaryExpression(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - } - else if ((tokenSet_11_.member(LA(1)))) { - } - else - { - throw new NoViableAltException(LT(1), getFilename()); - } - - } - powExpr_AST = (Spring.Expressions.SpringAST)currentAST.root; - } - catch (RecognitionException ex) - { - if (0 == inputState.guessing) - { - reportError(ex); - recover(ex,tokenSet_11_); - } - else - { - throw ex; - } - } - returnAST = powExpr_AST; - } - - public void unaryExpression() //throws RecognitionException, TokenStreamException -{ - - returnAST = null; - ASTPair currentAST = new ASTPair(); - Spring.Expressions.SpringAST unaryExpression_AST = null; - - try { // for error handling - if ((LA(1)==PLUS||LA(1)==MINUS||LA(1)==BANG)) - { - { - switch ( LA(1) ) - { - case PLUS: - { - Spring.Expressions.OpUnaryPlus tmp31_AST = null; - tmp31_AST = (Spring.Expressions.OpUnaryPlus) astFactory.create(LT(1), "Spring.Expressions.OpUnaryPlus"); - astFactory.makeASTRoot(ref currentAST, (AST)tmp31_AST); - match(PLUS); - break; - } - case MINUS: - { - Spring.Expressions.OpUnaryMinus tmp32_AST = null; - tmp32_AST = (Spring.Expressions.OpUnaryMinus) astFactory.create(LT(1), "Spring.Expressions.OpUnaryMinus"); - astFactory.makeASTRoot(ref currentAST, (AST)tmp32_AST); - match(MINUS); - break; - } - case BANG: - { - Spring.Expressions.OpNOT tmp33_AST = null; - tmp33_AST = (Spring.Expressions.OpNOT) astFactory.create(LT(1), "Spring.Expressions.OpNOT"); - astFactory.makeASTRoot(ref currentAST, (AST)tmp33_AST); - match(BANG); - break; - } - default: - { - throw new NoViableAltException(LT(1), getFilename()); - } - } - } - unaryExpression(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - unaryExpression_AST = (Spring.Expressions.SpringAST)currentAST.root; - } - else if ((tokenSet_12_.member(LA(1)))) { - primaryExpression(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - unaryExpression_AST = (Spring.Expressions.SpringAST)currentAST.root; - } - else - { - throw new NoViableAltException(LT(1), getFilename()); - } - - } - catch (RecognitionException ex) - { - if (0 == inputState.guessing) - { - reportError(ex); - recover(ex,tokenSet_13_); - } - else - { - throw ex; - } - } - returnAST = unaryExpression_AST; - } - - public void primaryExpression() //throws RecognitionException, TokenStreamException -{ - - returnAST = null; - ASTPair currentAST = new ASTPair(); - Spring.Expressions.SpringAST primaryExpression_AST = null; - - try { // for error handling - startNode(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - { - if ((tokenSet_14_.member(LA(1)))) - { - node(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - } - else if ((tokenSet_13_.member(LA(1)))) { - } - else - { - throw new NoViableAltException(LT(1), getFilename()); - } - - } - if (0==inputState.guessing) - { - primaryExpression_AST = (Spring.Expressions.SpringAST)currentAST.root; - primaryExpression_AST = (Spring.Expressions.SpringAST) astFactory.make((AST)(Spring.Expressions.SpringAST) astFactory.create(EXPR,"expression","Spring.Expressions.Expression"), (AST)primaryExpression_AST); - currentAST.root = primaryExpression_AST; - if ( (null != primaryExpression_AST) && (null != primaryExpression_AST.getFirstChild()) ) - currentAST.child = primaryExpression_AST.getFirstChild(); - else - currentAST.child = primaryExpression_AST; - currentAST.advanceChildToEnd(); - } - primaryExpression_AST = (Spring.Expressions.SpringAST)currentAST.root; - } - catch (RecognitionException ex) - { - if (0 == inputState.guessing) - { - reportError(ex); - recover(ex,tokenSet_13_); - } - else - { - throw ex; - } - } - returnAST = primaryExpression_AST; - } - - public void unaryOperator() //throws RecognitionException, TokenStreamException -{ - - returnAST = null; - ASTPair currentAST = new ASTPair(); - Spring.Expressions.SpringAST unaryOperator_AST = null; - - try { // for error handling - switch ( LA(1) ) - { - case PLUS: - { - Spring.Expressions.SpringAST tmp34_AST = null; - tmp34_AST = (Spring.Expressions.SpringAST) astFactory.create(LT(1)); - astFactory.addASTChild(ref currentAST, (AST)tmp34_AST); - match(PLUS); - unaryOperator_AST = (Spring.Expressions.SpringAST)currentAST.root; - break; - } - case MINUS: - { - Spring.Expressions.SpringAST tmp35_AST = null; - tmp35_AST = (Spring.Expressions.SpringAST) astFactory.create(LT(1)); - astFactory.addASTChild(ref currentAST, (AST)tmp35_AST); - match(MINUS); - unaryOperator_AST = (Spring.Expressions.SpringAST)currentAST.root; - break; - } - case BANG: - { - Spring.Expressions.SpringAST tmp36_AST = null; - tmp36_AST = (Spring.Expressions.SpringAST) astFactory.create(LT(1)); - astFactory.addASTChild(ref currentAST, (AST)tmp36_AST); - match(BANG); - unaryOperator_AST = (Spring.Expressions.SpringAST)currentAST.root; - break; - } - default: - { - throw new NoViableAltException(LT(1), getFilename()); - } - } - } - catch (RecognitionException ex) - { - if (0 == inputState.guessing) - { - reportError(ex); - recover(ex,tokenSet_0_); - } - else - { - throw ex; - } - } - returnAST = unaryOperator_AST; - } - - public void startNode() //throws RecognitionException, TokenStreamException -{ - - returnAST = null; - ASTPair currentAST = new ASTPair(); - Spring.Expressions.SpringAST startNode_AST = null; - - try { // for error handling - { - switch ( LA(1) ) - { - case ID: - { - methodOrProperty(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - break; - } - case DOLLAR: - { - localFunctionOrVar(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - break; - } - case LBRACKET: - { - indexer(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - break; - } - case FALSE: - case TRUE: - case NULL_LITERAL: - case STRING_LITERAL: - case INTEGER_LITERAL: - case HEXADECIMAL_INTEGER_LITERAL: - case REAL_LITERAL: - { - literal(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - break; - } - case TYPE: - { - type(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - break; - } - case LITERAL_new: - { - constructor(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - break; - } - case PROJECT: - { - projection(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - break; - } - case SELECT: - { - selection(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - break; - } - case SELECT_FIRST: - { - firstSelection(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - break; - } - case SELECT_LAST: - { - lastSelection(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - break; - } - case LCURLY: - { - listInitializer(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - break; - } - case LAMBDA: - { - lambda(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - break; - } - default: - bool synPredMatched40 = false; - if (((LA(1)==LPAREN) && (tokenSet_9_.member(LA(2))))) - { - int _m40 = mark(); - synPredMatched40 = true; - inputState.guessing++; - try { - { - match(LPAREN); - expression(); - match(SEMI); - } - } - catch (RecognitionException) - { - synPredMatched40 = false; - } - rewind(_m40); - inputState.guessing--; - } - if ( synPredMatched40 ) - { - exprList(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - } - else if ((LA(1)==LPAREN) && (tokenSet_9_.member(LA(2)))) { - parenExpr(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - } - else if ((LA(1)==POUND) && (LA(2)==ID)) { - functionOrVar(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - } - else if ((LA(1)==AT) && (LA(2)==LPAREN)) { - reference(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - } - else if ((LA(1)==POUND) && (LA(2)==LCURLY)) { - mapInitializer(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - } - else if ((LA(1)==AT) && (LA(2)==LBRACKET)) { - attribute(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - } - else - { - throw new NoViableAltException(LT(1), getFilename()); - } - break; } - } - startNode_AST = (Spring.Expressions.SpringAST)currentAST.root; - } - catch (RecognitionException ex) - { - if (0 == inputState.guessing) - { - reportError(ex); - recover(ex,tokenSet_2_); - } - else - { - throw ex; - } - } - returnAST = startNode_AST; - } - - public void node() //throws RecognitionException, TokenStreamException -{ - - returnAST = null; - ASTPair currentAST = new ASTPair(); - Spring.Expressions.SpringAST node_AST = null; - - try { // for error handling - { // ( ... )+ - int _cnt43=0; - for (;;) - { - switch ( LA(1) ) - { - case ID: - { - methodOrProperty(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - break; - } - case LBRACKET: - { - indexer(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - break; - } - case PROJECT: - { - projection(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - break; - } - case SELECT: - { - selection(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - break; - } - case SELECT_FIRST: - { - firstSelection(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - break; - } - case SELECT_LAST: - { - lastSelection(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - break; - } - case LPAREN: - { - exprList(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - break; - } - case DOT: - { - match(DOT); - break; - } - default: - { - if (_cnt43 >= 1) { goto _loop43_breakloop; } else { throw new NoViableAltException(LT(1), getFilename());; } - } - break; } - _cnt43++; - } -_loop43_breakloop: ; - } // ( ... )+ - node_AST = (Spring.Expressions.SpringAST)currentAST.root; - } - catch (RecognitionException ex) - { - if (0 == inputState.guessing) - { - reportError(ex); - recover(ex,tokenSet_13_); - } - else - { - throw ex; - } - } - returnAST = node_AST; - } - - public void methodOrProperty() //throws RecognitionException, TokenStreamException -{ - - returnAST = null; - ASTPair currentAST = new ASTPair(); - Spring.Expressions.SpringAST methodOrProperty_AST = null; - - try { // for error handling - bool synPredMatched56 = false; - if (((LA(1)==ID) && (LA(2)==LPAREN))) - { - int _m56 = mark(); - synPredMatched56 = true; - inputState.guessing++; - try { - { - match(ID); - match(LPAREN); - } - } - catch (RecognitionException) - { - synPredMatched56 = false; - } - rewind(_m56); - inputState.guessing--; - } - if ( synPredMatched56 ) - { - Spring.Expressions.MethodNode tmp38_AST = null; - tmp38_AST = (Spring.Expressions.MethodNode) astFactory.create(LT(1), "Spring.Expressions.MethodNode"); - astFactory.makeASTRoot(ref currentAST, (AST)tmp38_AST); - match(ID); - methodArgs(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - methodOrProperty_AST = (Spring.Expressions.SpringAST)currentAST.root; - } - else if ((LA(1)==ID) && (tokenSet_2_.member(LA(2)))) { - property(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - methodOrProperty_AST = (Spring.Expressions.SpringAST)currentAST.root; - } - else - { - throw new NoViableAltException(LT(1), getFilename()); - } - - } - catch (RecognitionException ex) - { - if (0 == inputState.guessing) - { - reportError(ex); - recover(ex,tokenSet_2_); - } - else - { - throw ex; - } - } - returnAST = methodOrProperty_AST; - } - - public void functionOrVar() //throws RecognitionException, TokenStreamException -{ - - returnAST = null; - ASTPair currentAST = new ASTPair(); - Spring.Expressions.SpringAST functionOrVar_AST = null; - - try { // for error handling - bool synPredMatched46 = false; - if (((LA(1)==POUND) && (LA(2)==ID))) - { - int _m46 = mark(); - synPredMatched46 = true; - inputState.guessing++; - try { - { - match(POUND); - match(ID); - match(LPAREN); - } - } - catch (RecognitionException) - { - synPredMatched46 = false; - } - rewind(_m46); - inputState.guessing--; - } - if ( synPredMatched46 ) - { - function(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - functionOrVar_AST = (Spring.Expressions.SpringAST)currentAST.root; - } - else if ((LA(1)==POUND) && (LA(2)==ID)) { - var(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - functionOrVar_AST = (Spring.Expressions.SpringAST)currentAST.root; - } - else - { - throw new NoViableAltException(LT(1), getFilename()); - } - - } - catch (RecognitionException ex) - { - if (0 == inputState.guessing) - { - reportError(ex); - recover(ex,tokenSet_2_); - } - else - { - throw ex; - } - } - returnAST = functionOrVar_AST; - } - - public void localFunctionOrVar() //throws RecognitionException, TokenStreamException -{ - - returnAST = null; - ASTPair currentAST = new ASTPair(); - Spring.Expressions.SpringAST localFunctionOrVar_AST = null; - - try { // for error handling - bool synPredMatched51 = false; - if (((LA(1)==DOLLAR) && (LA(2)==ID))) - { - int _m51 = mark(); - synPredMatched51 = true; - inputState.guessing++; - try { - { - match(DOLLAR); - match(ID); - match(LPAREN); - } - } - catch (RecognitionException) - { - synPredMatched51 = false; - } - rewind(_m51); - inputState.guessing--; - } - if ( synPredMatched51 ) - { - localFunction(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - localFunctionOrVar_AST = (Spring.Expressions.SpringAST)currentAST.root; - } - else if ((LA(1)==DOLLAR) && (LA(2)==ID)) { - localVar(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - localFunctionOrVar_AST = (Spring.Expressions.SpringAST)currentAST.root; - } - else - { - throw new NoViableAltException(LT(1), getFilename()); - } - - } - catch (RecognitionException ex) - { - if (0 == inputState.guessing) - { - reportError(ex); - recover(ex,tokenSet_2_); - } - else - { - throw ex; - } - } - returnAST = localFunctionOrVar_AST; - } - - public void reference() //throws RecognitionException, TokenStreamException -{ - - returnAST = null; - ASTPair currentAST = new ASTPair(); - Spring.Expressions.SpringAST reference_AST = null; - Spring.Expressions.SpringAST cn_AST = null; - Spring.Expressions.SpringAST id_AST = null; - Spring.Expressions.SpringAST localid_AST = null; - - try { // for error handling - bool synPredMatched64 = false; - if (((LA(1)==AT) && (LA(2)==LPAREN))) - { - int _m64 = mark(); - synPredMatched64 = true; - inputState.guessing++; - try { - { - match(AT); - match(LPAREN); - quotableName(); - match(COLON); - } - } - catch (RecognitionException) - { - synPredMatched64 = false; - } - rewind(_m64); - inputState.guessing--; - } - if ( synPredMatched64 ) - { - match(AT); - match(LPAREN); - quotableName(); - if (0 == inputState.guessing) - { - cn_AST = (Spring.Expressions.SpringAST)returnAST; - } - match(COLON); - quotableName(); - if (0 == inputState.guessing) - { - id_AST = (Spring.Expressions.SpringAST)returnAST; - } - match(RPAREN); - if (0==inputState.guessing) - { - reference_AST = (Spring.Expressions.SpringAST)currentAST.root; - reference_AST = (Spring.Expressions.SpringAST) astFactory.make((AST)(Spring.Expressions.SpringAST) astFactory.create(EXPR,"ref","Spring.Context.Support.ReferenceNode"), (AST)cn_AST, (AST)id_AST); - currentAST.root = reference_AST; - if ( (null != reference_AST) && (null != reference_AST.getFirstChild()) ) - currentAST.child = reference_AST.getFirstChild(); - else - currentAST.child = reference_AST; - currentAST.advanceChildToEnd(); - } - reference_AST = (Spring.Expressions.SpringAST)currentAST.root; - } - else if ((LA(1)==AT) && (LA(2)==LPAREN)) { - match(AT); - match(LPAREN); - quotableName(); - if (0 == inputState.guessing) - { - localid_AST = (Spring.Expressions.SpringAST)returnAST; - } - match(RPAREN); - if (0==inputState.guessing) - { - reference_AST = (Spring.Expressions.SpringAST)currentAST.root; - reference_AST = (Spring.Expressions.SpringAST) astFactory.make((AST)(Spring.Expressions.SpringAST) astFactory.create(EXPR,"ref","Spring.Context.Support.ReferenceNode"), (AST)null, (AST)localid_AST); - currentAST.root = reference_AST; - if ( (null != reference_AST) && (null != reference_AST.getFirstChild()) ) - currentAST.child = reference_AST.getFirstChild(); - else - currentAST.child = reference_AST; - currentAST.advanceChildToEnd(); - } - reference_AST = (Spring.Expressions.SpringAST)currentAST.root; - } - else - { - throw new NoViableAltException(LT(1), getFilename()); - } - - } - catch (RecognitionException ex) - { - if (0 == inputState.guessing) - { - reportError(ex); - recover(ex,tokenSet_2_); - } - else - { - throw ex; - } - } - returnAST = reference_AST; - } - - public void indexer() //throws RecognitionException, TokenStreamException -{ - - returnAST = null; - ASTPair currentAST = new ASTPair(); - Spring.Expressions.SpringAST indexer_AST = null; - - try { // for error handling - Spring.Expressions.IndexerNode tmp46_AST = null; - tmp46_AST = (Spring.Expressions.IndexerNode) astFactory.create(LT(1), "Spring.Expressions.IndexerNode"); - astFactory.makeASTRoot(ref currentAST, (AST)tmp46_AST); - match(LBRACKET); - argument(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - { // ( ... )* - for (;;) - { - if ((LA(1)==COMMA)) - { - match(COMMA); - argument(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - } - else - { - goto _loop67_breakloop; - } - - } -_loop67_breakloop: ; - } // ( ... )* - match(RBRACKET); - indexer_AST = (Spring.Expressions.SpringAST)currentAST.root; - } - catch (RecognitionException ex) - { - if (0 == inputState.guessing) - { - reportError(ex); - recover(ex,tokenSet_2_); - } - else - { - throw ex; - } - } - returnAST = indexer_AST; - } - - public void literal() //throws RecognitionException, TokenStreamException -{ - - returnAST = null; - ASTPair currentAST = new ASTPair(); - Spring.Expressions.SpringAST literal_AST = null; - - try { // for error handling - switch ( LA(1) ) - { - case NULL_LITERAL: - { - Spring.Expressions.NullLiteralNode tmp49_AST = null; - tmp49_AST = (Spring.Expressions.NullLiteralNode) astFactory.create(LT(1), "Spring.Expressions.NullLiteralNode"); - astFactory.addASTChild(ref currentAST, (AST)tmp49_AST); - match(NULL_LITERAL); - literal_AST = (Spring.Expressions.SpringAST)currentAST.root; - break; - } - case INTEGER_LITERAL: - { - Spring.Expressions.IntLiteralNode tmp50_AST = null; - tmp50_AST = (Spring.Expressions.IntLiteralNode) astFactory.create(LT(1), "Spring.Expressions.IntLiteralNode"); - astFactory.addASTChild(ref currentAST, (AST)tmp50_AST); - match(INTEGER_LITERAL); - literal_AST = (Spring.Expressions.SpringAST)currentAST.root; - break; - } - case HEXADECIMAL_INTEGER_LITERAL: - { - Spring.Expressions.HexLiteralNode tmp51_AST = null; - tmp51_AST = (Spring.Expressions.HexLiteralNode) astFactory.create(LT(1), "Spring.Expressions.HexLiteralNode"); - astFactory.addASTChild(ref currentAST, (AST)tmp51_AST); - match(HEXADECIMAL_INTEGER_LITERAL); - literal_AST = (Spring.Expressions.SpringAST)currentAST.root; - break; - } - case REAL_LITERAL: - { - Spring.Expressions.RealLiteralNode tmp52_AST = null; - tmp52_AST = (Spring.Expressions.RealLiteralNode) astFactory.create(LT(1), "Spring.Expressions.RealLiteralNode"); - astFactory.addASTChild(ref currentAST, (AST)tmp52_AST); - match(REAL_LITERAL); - literal_AST = (Spring.Expressions.SpringAST)currentAST.root; - break; - } - case STRING_LITERAL: - { - Spring.Expressions.StringLiteralNode tmp53_AST = null; - tmp53_AST = (Spring.Expressions.StringLiteralNode) astFactory.create(LT(1), "Spring.Expressions.StringLiteralNode"); - astFactory.addASTChild(ref currentAST, (AST)tmp53_AST); - match(STRING_LITERAL); - literal_AST = (Spring.Expressions.SpringAST)currentAST.root; - break; - } - case FALSE: - case TRUE: - { - boolLiteral(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - literal_AST = (Spring.Expressions.SpringAST)currentAST.root; - break; - } - default: - { - throw new NoViableAltException(LT(1), getFilename()); - } - } - } - catch (RecognitionException ex) - { - if (0 == inputState.guessing) - { - reportError(ex); - recover(ex,tokenSet_2_); - } - else - { - throw ex; - } - } - returnAST = literal_AST; - } - - public void type() //throws RecognitionException, TokenStreamException -{ - - returnAST = null; - ASTPair currentAST = new ASTPair(); - Spring.Expressions.SpringAST type_AST = null; - Spring.Expressions.SpringAST tn_AST = null; - - try { // for error handling - match(TYPE); - name(); - if (0 == inputState.guessing) - { - tn_AST = (Spring.Expressions.SpringAST)returnAST; - } - match(RPAREN); - if (0==inputState.guessing) - { - type_AST = (Spring.Expressions.SpringAST)currentAST.root; - type_AST = (Spring.Expressions.SpringAST) astFactory.make((AST)(Spring.Expressions.SpringAST) astFactory.create(EXPR,tn_AST.getText(),"Spring.Expressions.TypeNode"), (AST)type_AST); - currentAST.root = type_AST; - if ( (null != type_AST) && (null != type_AST.getFirstChild()) ) - currentAST.child = type_AST.getFirstChild(); - else - currentAST.child = type_AST; - currentAST.advanceChildToEnd(); - } - type_AST = (Spring.Expressions.SpringAST)currentAST.root; - } - catch (RecognitionException ex) - { - if (0 == inputState.guessing) - { - reportError(ex); - recover(ex,tokenSet_2_); - } - else - { - throw ex; - } - } - returnAST = type_AST; - } - - public void constructor() //throws RecognitionException, TokenStreamException -{ - - returnAST = null; - ASTPair currentAST = new ASTPair(); - Spring.Expressions.SpringAST constructor_AST = null; - Spring.Expressions.SpringAST type_AST = null; - - try { // for error handling - bool synPredMatched90 = false; - if (((LA(1)==LITERAL_new) && (LA(2)==ID))) - { - int _m90 = mark(); - synPredMatched90 = true; - inputState.guessing++; - try { - { - match(LITERAL_new); - qualifiedId(); - match(LPAREN); - } - } - catch (RecognitionException) - { - synPredMatched90 = false; - } - rewind(_m90); - inputState.guessing--; - } - if ( synPredMatched90 ) - { - match(LITERAL_new); - qualifiedId(); - if (0 == inputState.guessing) - { - type_AST = (Spring.Expressions.SpringAST)returnAST; - } - ctorArgs(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - if (0==inputState.guessing) - { - constructor_AST = (Spring.Expressions.SpringAST)currentAST.root; - constructor_AST = (Spring.Expressions.SpringAST) astFactory.make((AST)(Spring.Expressions.SpringAST) astFactory.create(EXPR,type_AST.getText(),"Spring.Expressions.ConstructorNode"), (AST)constructor_AST); - currentAST.root = constructor_AST; - if ( (null != constructor_AST) && (null != constructor_AST.getFirstChild()) ) - currentAST.child = constructor_AST.getFirstChild(); - else - currentAST.child = constructor_AST; - currentAST.advanceChildToEnd(); - } - constructor_AST = (Spring.Expressions.SpringAST)currentAST.root; - } - else if ((LA(1)==LITERAL_new) && (LA(2)==ID)) { - arrayConstructor(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - constructor_AST = (Spring.Expressions.SpringAST)currentAST.root; - } - else - { - throw new NoViableAltException(LT(1), getFilename()); - } - - } - catch (RecognitionException ex) - { - if (0 == inputState.guessing) - { - reportError(ex); - recover(ex,tokenSet_2_); - } - else - { - throw ex; - } - } - returnAST = constructor_AST; - } - - public void projection() //throws RecognitionException, TokenStreamException -{ - - returnAST = null; - ASTPair currentAST = new ASTPair(); - Spring.Expressions.SpringAST projection_AST = null; - - try { // for error handling - Spring.Expressions.ProjectionNode tmp57_AST = null; - tmp57_AST = (Spring.Expressions.ProjectionNode) astFactory.create(LT(1), "Spring.Expressions.ProjectionNode"); - astFactory.makeASTRoot(ref currentAST, (AST)tmp57_AST); - match(PROJECT); - expression(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - match(RCURLY); - projection_AST = (Spring.Expressions.SpringAST)currentAST.root; - } - catch (RecognitionException ex) - { - if (0 == inputState.guessing) - { - reportError(ex); - recover(ex,tokenSet_2_); - } - else - { - throw ex; - } - } - returnAST = projection_AST; - } - - public void selection() //throws RecognitionException, TokenStreamException -{ - - returnAST = null; - ASTPair currentAST = new ASTPair(); - Spring.Expressions.SpringAST selection_AST = null; - - try { // for error handling - Spring.Expressions.SelectionNode tmp59_AST = null; - tmp59_AST = (Spring.Expressions.SelectionNode) astFactory.create(LT(1), "Spring.Expressions.SelectionNode"); - astFactory.makeASTRoot(ref currentAST, (AST)tmp59_AST); - match(SELECT); - expression(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - { // ( ... )* - for (;;) - { - if ((LA(1)==COMMA)) - { - match(COMMA); - expression(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - } - else - { - goto _loop71_breakloop; - } - - } -_loop71_breakloop: ; - } // ( ... )* - match(RCURLY); - selection_AST = (Spring.Expressions.SpringAST)currentAST.root; - } - catch (RecognitionException ex) - { - if (0 == inputState.guessing) - { - reportError(ex); - recover(ex,tokenSet_2_); - } - else - { - throw ex; - } - } - returnAST = selection_AST; - } - - public void firstSelection() //throws RecognitionException, TokenStreamException -{ - - returnAST = null; - ASTPair currentAST = new ASTPair(); - Spring.Expressions.SpringAST firstSelection_AST = null; - - try { // for error handling - Spring.Expressions.SelectionFirstNode tmp62_AST = null; - tmp62_AST = (Spring.Expressions.SelectionFirstNode) astFactory.create(LT(1), "Spring.Expressions.SelectionFirstNode"); - astFactory.makeASTRoot(ref currentAST, (AST)tmp62_AST); - match(SELECT_FIRST); - expression(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - match(RCURLY); - firstSelection_AST = (Spring.Expressions.SpringAST)currentAST.root; - } - catch (RecognitionException ex) - { - if (0 == inputState.guessing) - { - reportError(ex); - recover(ex,tokenSet_2_); - } - else - { - throw ex; - } - } - returnAST = firstSelection_AST; - } - - public void lastSelection() //throws RecognitionException, TokenStreamException -{ - - returnAST = null; - ASTPair currentAST = new ASTPair(); - Spring.Expressions.SpringAST lastSelection_AST = null; - - try { // for error handling - Spring.Expressions.SelectionLastNode tmp64_AST = null; - tmp64_AST = (Spring.Expressions.SelectionLastNode) astFactory.create(LT(1), "Spring.Expressions.SelectionLastNode"); - astFactory.makeASTRoot(ref currentAST, (AST)tmp64_AST); - match(SELECT_LAST); - expression(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - match(RCURLY); - lastSelection_AST = (Spring.Expressions.SpringAST)currentAST.root; - } - catch (RecognitionException ex) - { - if (0 == inputState.guessing) - { - reportError(ex); - recover(ex,tokenSet_2_); - } - else - { - throw ex; - } - } - returnAST = lastSelection_AST; - } - - public void listInitializer() //throws RecognitionException, TokenStreamException -{ - - returnAST = null; - ASTPair currentAST = new ASTPair(); - Spring.Expressions.SpringAST listInitializer_AST = null; - - try { // for error handling - Spring.Expressions.ListInitializerNode tmp66_AST = null; - tmp66_AST = (Spring.Expressions.ListInitializerNode) astFactory.create(LT(1), "Spring.Expressions.ListInitializerNode"); - astFactory.makeASTRoot(ref currentAST, (AST)tmp66_AST); - match(LCURLY); - expression(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - { // ( ... )* - for (;;) - { - if ((LA(1)==COMMA)) - { - match(COMMA); - expression(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - } - else - { - goto _loop99_breakloop; - } - - } -_loop99_breakloop: ; - } // ( ... )* - match(RCURLY); - listInitializer_AST = (Spring.Expressions.SpringAST)currentAST.root; - } - catch (RecognitionException ex) - { - if (0 == inputState.guessing) - { - reportError(ex); - recover(ex,tokenSet_2_); - } - else - { - throw ex; - } - } - returnAST = listInitializer_AST; - } - - public void mapInitializer() //throws RecognitionException, TokenStreamException -{ - - returnAST = null; - ASTPair currentAST = new ASTPair(); - Spring.Expressions.SpringAST mapInitializer_AST = null; - - try { // for error handling - match(POUND); - Spring.Expressions.MapInitializerNode tmp70_AST = null; - tmp70_AST = (Spring.Expressions.MapInitializerNode) astFactory.create(LT(1), "Spring.Expressions.MapInitializerNode"); - astFactory.makeASTRoot(ref currentAST, (AST)tmp70_AST); - match(LCURLY); - mapEntry(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - { // ( ... )* - for (;;) - { - if ((LA(1)==COMMA)) - { - match(COMMA); - mapEntry(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - } - else - { - goto _loop102_breakloop; - } - - } -_loop102_breakloop: ; - } // ( ... )* - match(RCURLY); - mapInitializer_AST = (Spring.Expressions.SpringAST)currentAST.root; - } - catch (RecognitionException ex) - { - if (0 == inputState.guessing) - { - reportError(ex); - recover(ex,tokenSet_2_); - } - else - { - throw ex; - } - } - returnAST = mapInitializer_AST; - } - - public void lambda() //throws RecognitionException, TokenStreamException -{ - - returnAST = null; - ASTPair currentAST = new ASTPair(); - Spring.Expressions.SpringAST lambda_AST = null; - - try { // for error handling - match(LAMBDA); - { - if ((LA(1)==ID)) - { - argList(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - } - else if ((LA(1)==PIPE)) { - } - else - { - throw new NoViableAltException(LT(1), getFilename()); - } - - } - match(PIPE); - expression(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - match(RCURLY); - if (0==inputState.guessing) - { - lambda_AST = (Spring.Expressions.SpringAST)currentAST.root; - lambda_AST = (Spring.Expressions.SpringAST) astFactory.make((AST)(Spring.Expressions.SpringAST) astFactory.create(EXPR,"lambda","Spring.Expressions.LambdaExpressionNode"), (AST)lambda_AST); - currentAST.root = lambda_AST; - if ( (null != lambda_AST) && (null != lambda_AST.getFirstChild()) ) - currentAST.child = lambda_AST.getFirstChild(); - else - currentAST.child = lambda_AST; - currentAST.advanceChildToEnd(); - } - lambda_AST = (Spring.Expressions.SpringAST)currentAST.root; - } - catch (RecognitionException ex) - { - if (0 == inputState.guessing) - { - reportError(ex); - recover(ex,tokenSet_2_); - } - else - { - throw ex; - } - } - returnAST = lambda_AST; - } - - public void attribute() //throws RecognitionException, TokenStreamException -{ - - returnAST = null; - ASTPair currentAST = new ASTPair(); - Spring.Expressions.SpringAST attribute_AST = null; - Spring.Expressions.SpringAST tn_AST = null; - - try { // for error handling - match(AT); - match(LBRACKET); - qualifiedId(); - if (0 == inputState.guessing) - { - tn_AST = (Spring.Expressions.SpringAST)returnAST; - } - { - if ((LA(1)==LPAREN)) - { - ctorArgs(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - } - else if ((LA(1)==RBRACKET)) { - } - else - { - throw new NoViableAltException(LT(1), getFilename()); - } - - } - match(RBRACKET); - if (0==inputState.guessing) - { - attribute_AST = (Spring.Expressions.SpringAST)currentAST.root; - attribute_AST = (Spring.Expressions.SpringAST) astFactory.make((AST)(Spring.Expressions.SpringAST) astFactory.create(EXPR,tn_AST.getText(),"Spring.Expressions.AttributeNode"), (AST)attribute_AST); - currentAST.root = attribute_AST; - if ( (null != attribute_AST) && (null != attribute_AST.getFirstChild()) ) - currentAST.child = attribute_AST.getFirstChild(); - else - currentAST.child = attribute_AST; - currentAST.advanceChildToEnd(); - } - attribute_AST = (Spring.Expressions.SpringAST)currentAST.root; - } - catch (RecognitionException ex) - { - if (0 == inputState.guessing) - { - reportError(ex); - recover(ex,tokenSet_2_); - } - else - { - throw ex; - } - } - returnAST = attribute_AST; - } - - public void function() //throws RecognitionException, TokenStreamException -{ - - returnAST = null; - ASTPair currentAST = new ASTPair(); - Spring.Expressions.SpringAST function_AST = null; - - try { // for error handling - match(POUND); - Spring.Expressions.FunctionNode tmp80_AST = null; - tmp80_AST = (Spring.Expressions.FunctionNode) astFactory.create(LT(1), "Spring.Expressions.FunctionNode"); - astFactory.makeASTRoot(ref currentAST, (AST)tmp80_AST); - match(ID); - methodArgs(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - function_AST = (Spring.Expressions.SpringAST)currentAST.root; - } - catch (RecognitionException ex) - { - if (0 == inputState.guessing) - { - reportError(ex); - recover(ex,tokenSet_2_); - } - else - { - throw ex; - } - } - returnAST = function_AST; - } - - public void var() //throws RecognitionException, TokenStreamException -{ - - returnAST = null; - ASTPair currentAST = new ASTPair(); - Spring.Expressions.SpringAST var_AST = null; - - try { // for error handling - match(POUND); - Spring.Expressions.VariableNode tmp82_AST = null; - tmp82_AST = (Spring.Expressions.VariableNode) astFactory.create(LT(1), "Spring.Expressions.VariableNode"); - astFactory.makeASTRoot(ref currentAST, (AST)tmp82_AST); - match(ID); - var_AST = (Spring.Expressions.SpringAST)currentAST.root; - } - catch (RecognitionException ex) - { - if (0 == inputState.guessing) - { - reportError(ex); - recover(ex,tokenSet_2_); - } - else - { - throw ex; - } - } - returnAST = var_AST; - } - - public void methodArgs() //throws RecognitionException, TokenStreamException -{ - - returnAST = null; - ASTPair currentAST = new ASTPair(); - Spring.Expressions.SpringAST methodArgs_AST = null; - - try { // for error handling - match(LPAREN); - { - if ((tokenSet_9_.member(LA(1)))) - { - argument(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - { // ( ... )* - for (;;) - { - if ((LA(1)==COMMA)) - { - match(COMMA); - argument(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - } - else - { - goto _loop60_breakloop; - } - - } -_loop60_breakloop: ; - } // ( ... )* - } - else if ((LA(1)==RPAREN)) { - } - else - { - throw new NoViableAltException(LT(1), getFilename()); - } - - } - match(RPAREN); - methodArgs_AST = (Spring.Expressions.SpringAST)currentAST.root; - } - catch (RecognitionException ex) - { - if (0 == inputState.guessing) - { - reportError(ex); - recover(ex,tokenSet_2_); - } - else - { - throw ex; - } - } - returnAST = methodArgs_AST; - } - - public void localFunction() //throws RecognitionException, TokenStreamException -{ - - returnAST = null; - ASTPair currentAST = new ASTPair(); - Spring.Expressions.SpringAST localFunction_AST = null; - - try { // for error handling - match(DOLLAR); - Spring.Expressions.LocalFunctionNode tmp87_AST = null; - tmp87_AST = (Spring.Expressions.LocalFunctionNode) astFactory.create(LT(1), "Spring.Expressions.LocalFunctionNode"); - astFactory.makeASTRoot(ref currentAST, (AST)tmp87_AST); - match(ID); - methodArgs(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - localFunction_AST = (Spring.Expressions.SpringAST)currentAST.root; - } - catch (RecognitionException ex) - { - if (0 == inputState.guessing) - { - reportError(ex); - recover(ex,tokenSet_2_); - } - else - { - throw ex; - } - } - returnAST = localFunction_AST; - } - - public void localVar() //throws RecognitionException, TokenStreamException -{ - - returnAST = null; - ASTPair currentAST = new ASTPair(); - Spring.Expressions.SpringAST localVar_AST = null; - - try { // for error handling - match(DOLLAR); - Spring.Expressions.LocalVariableNode tmp89_AST = null; - tmp89_AST = (Spring.Expressions.LocalVariableNode) astFactory.create(LT(1), "Spring.Expressions.LocalVariableNode"); - astFactory.makeASTRoot(ref currentAST, (AST)tmp89_AST); - match(ID); - localVar_AST = (Spring.Expressions.SpringAST)currentAST.root; - } - catch (RecognitionException ex) - { - if (0 == inputState.guessing) - { - reportError(ex); - recover(ex,tokenSet_2_); - } - else - { - throw ex; - } - } - returnAST = localVar_AST; - } - - public void property() //throws RecognitionException, TokenStreamException -{ - - returnAST = null; - ASTPair currentAST = new ASTPair(); - Spring.Expressions.SpringAST property_AST = null; - - try { // for error handling - Spring.Expressions.PropertyOrFieldNode tmp90_AST = null; - tmp90_AST = (Spring.Expressions.PropertyOrFieldNode) astFactory.create(LT(1), "Spring.Expressions.PropertyOrFieldNode"); - astFactory.addASTChild(ref currentAST, (AST)tmp90_AST); - match(ID); - property_AST = (Spring.Expressions.SpringAST)currentAST.root; - } - catch (RecognitionException ex) - { - if (0 == inputState.guessing) - { - reportError(ex); - recover(ex,tokenSet_2_); - } - else - { - throw ex; - } - } - returnAST = property_AST; - } - - public void argument() //throws RecognitionException, TokenStreamException -{ - - returnAST = null; - ASTPair currentAST = new ASTPair(); - Spring.Expressions.SpringAST argument_AST = null; - - try { // for error handling - expression(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - argument_AST = (Spring.Expressions.SpringAST)currentAST.root; - } - catch (RecognitionException ex) - { - if (0 == inputState.guessing) - { - reportError(ex); - recover(ex,tokenSet_15_); - } - else - { - throw ex; - } - } - returnAST = argument_AST; - } - - public void quotableName() //throws RecognitionException, TokenStreamException -{ - - returnAST = null; - ASTPair currentAST = new ASTPair(); - Spring.Expressions.SpringAST quotableName_AST = null; - - try { // for error handling - if ((LA(1)==STRING_LITERAL)) - { - Spring.Expressions.QualifiedIdentifier tmp91_AST = null; - tmp91_AST = (Spring.Expressions.QualifiedIdentifier) astFactory.create(LT(1), "Spring.Expressions.QualifiedIdentifier"); - astFactory.makeASTRoot(ref currentAST, (AST)tmp91_AST); - match(STRING_LITERAL); - quotableName_AST = (Spring.Expressions.SpringAST)currentAST.root; - } - else if ((LA(1)==ID)) { - name(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - quotableName_AST = (Spring.Expressions.SpringAST)currentAST.root; - } - else - { - throw new NoViableAltException(LT(1), getFilename()); - } - - } - catch (RecognitionException ex) - { - if (0 == inputState.guessing) - { - reportError(ex); - recover(ex,tokenSet_16_); - } - else - { - throw ex; - } - } - returnAST = quotableName_AST; - } - - public void name() //throws RecognitionException, TokenStreamException -{ - - returnAST = null; - ASTPair currentAST = new ASTPair(); - Spring.Expressions.SpringAST name_AST = null; - - try { // for error handling - Spring.Expressions.QualifiedIdentifier tmp92_AST = null; - tmp92_AST = (Spring.Expressions.QualifiedIdentifier) astFactory.create(LT(1), "Spring.Expressions.QualifiedIdentifier"); - astFactory.makeASTRoot(ref currentAST, (AST)tmp92_AST); - match(ID); - { // ( ... )* - for (;;) - { - if ((tokenSet_17_.member(LA(1)))) - { - { - Spring.Expressions.SpringAST tmp93_AST = null; - tmp93_AST = (Spring.Expressions.SpringAST) astFactory.create(LT(1)); - astFactory.addASTChild(ref currentAST, (AST)tmp93_AST); - match(tokenSet_17_); - } - } - else - { - goto _loop78_breakloop; - } - - } -_loop78_breakloop: ; - } // ( ... )* - name_AST = (Spring.Expressions.SpringAST)currentAST.root; - } - catch (RecognitionException ex) - { - if (0 == inputState.guessing) - { - reportError(ex); - recover(ex,tokenSet_16_); - } - else - { - throw ex; - } - } - returnAST = name_AST; - } - - public void qualifiedId() //throws RecognitionException, TokenStreamException -{ - - returnAST = null; - ASTPair currentAST = new ASTPair(); - Spring.Expressions.SpringAST qualifiedId_AST = null; - - try { // for error handling - Spring.Expressions.QualifiedIdentifier tmp94_AST = null; - tmp94_AST = (Spring.Expressions.QualifiedIdentifier) astFactory.create(LT(1), "Spring.Expressions.QualifiedIdentifier"); - astFactory.makeASTRoot(ref currentAST, (AST)tmp94_AST); - match(ID); - { // ( ... )* - for (;;) - { - if ((LA(1)==DOT)) - { - Spring.Expressions.SpringAST tmp95_AST = null; - tmp95_AST = (Spring.Expressions.SpringAST) astFactory.create(LT(1)); - astFactory.addASTChild(ref currentAST, (AST)tmp95_AST); - match(DOT); - Spring.Expressions.SpringAST tmp96_AST = null; - tmp96_AST = (Spring.Expressions.SpringAST) astFactory.create(LT(1)); - astFactory.addASTChild(ref currentAST, (AST)tmp96_AST); - match(ID); - } - else - { - goto _loop114_breakloop; - } - - } -_loop114_breakloop: ; - } // ( ... )* - qualifiedId_AST = (Spring.Expressions.SpringAST)currentAST.root; - } - catch (RecognitionException ex) - { - if (0 == inputState.guessing) - { - reportError(ex); - recover(ex,tokenSet_18_); - } - else - { - throw ex; - } - } - returnAST = qualifiedId_AST; - } - - public void ctorArgs() //throws RecognitionException, TokenStreamException -{ - - returnAST = null; - ASTPair currentAST = new ASTPair(); - Spring.Expressions.SpringAST ctorArgs_AST = null; - - try { // for error handling - match(LPAREN); - { - if ((tokenSet_9_.member(LA(1)))) - { - namedArgument(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - { // ( ... )* - for (;;) - { - if ((LA(1)==COMMA)) - { - match(COMMA); - namedArgument(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - } - else - { - goto _loop107_breakloop; - } - - } -_loop107_breakloop: ; - } // ( ... )* - } - else if ((LA(1)==RPAREN)) { - } - else - { - throw new NoViableAltException(LT(1), getFilename()); - } - - } - match(RPAREN); - ctorArgs_AST = (Spring.Expressions.SpringAST)currentAST.root; - } - catch (RecognitionException ex) - { - if (0 == inputState.guessing) - { - reportError(ex); - recover(ex,tokenSet_2_); - } - else - { - throw ex; - } - } - returnAST = ctorArgs_AST; - } - - public void argList() //throws RecognitionException, TokenStreamException -{ - - returnAST = null; - ASTPair currentAST = new ASTPair(); - Spring.Expressions.SpringAST argList_AST = null; - - try { // for error handling - { - Spring.Expressions.SpringAST tmp100_AST = null; - tmp100_AST = (Spring.Expressions.SpringAST) astFactory.create(LT(1)); - astFactory.addASTChild(ref currentAST, (AST)tmp100_AST); - match(ID); - { // ( ... )* - for (;;) - { - if ((LA(1)==COMMA)) - { - match(COMMA); - Spring.Expressions.SpringAST tmp102_AST = null; - tmp102_AST = (Spring.Expressions.SpringAST) astFactory.create(LT(1)); - astFactory.addASTChild(ref currentAST, (AST)tmp102_AST); - match(ID); - } - else - { - goto _loop87_breakloop; - } - - } -_loop87_breakloop: ; - } // ( ... )* - } - if (0==inputState.guessing) - { - argList_AST = (Spring.Expressions.SpringAST)currentAST.root; - argList_AST = (Spring.Expressions.SpringAST) astFactory.make((AST)(Spring.Expressions.SpringAST) astFactory.create(EXPR,"args"), (AST)argList_AST); - currentAST.root = argList_AST; - if ( (null != argList_AST) && (null != argList_AST.getFirstChild()) ) - currentAST.child = argList_AST.getFirstChild(); - else - currentAST.child = argList_AST; - currentAST.advanceChildToEnd(); - } - argList_AST = (Spring.Expressions.SpringAST)currentAST.root; - } - catch (RecognitionException ex) - { - if (0 == inputState.guessing) - { - reportError(ex); - recover(ex,tokenSet_19_); - } - else - { - throw ex; - } - } - returnAST = argList_AST; - } - - public void arrayConstructor() //throws RecognitionException, TokenStreamException -{ - - returnAST = null; - ASTPair currentAST = new ASTPair(); - Spring.Expressions.SpringAST arrayConstructor_AST = null; - Spring.Expressions.SpringAST type_AST = null; - - try { // for error handling - match(LITERAL_new); - qualifiedId(); - if (0 == inputState.guessing) - { - type_AST = (Spring.Expressions.SpringAST)returnAST; - } - arrayRank(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - { - if ((LA(1)==LCURLY)) - { - listInitializer(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - } - else if ((tokenSet_2_.member(LA(1)))) { - } - else - { - throw new NoViableAltException(LT(1), getFilename()); - } - - } - if (0==inputState.guessing) - { - arrayConstructor_AST = (Spring.Expressions.SpringAST)currentAST.root; - arrayConstructor_AST = (Spring.Expressions.SpringAST) astFactory.make((AST)(Spring.Expressions.SpringAST) astFactory.create(EXPR,type_AST.getText(),"Spring.Expressions.ArrayConstructorNode"), (AST)arrayConstructor_AST); - currentAST.root = arrayConstructor_AST; - if ( (null != arrayConstructor_AST) && (null != arrayConstructor_AST.getFirstChild()) ) - currentAST.child = arrayConstructor_AST.getFirstChild(); - else - currentAST.child = arrayConstructor_AST; - currentAST.advanceChildToEnd(); - } - arrayConstructor_AST = (Spring.Expressions.SpringAST)currentAST.root; - } - catch (RecognitionException ex) - { - if (0 == inputState.guessing) - { - reportError(ex); - recover(ex,tokenSet_2_); - } - else - { - throw ex; - } - } - returnAST = arrayConstructor_AST; - } - - public void arrayRank() //throws RecognitionException, TokenStreamException -{ - - returnAST = null; - ASTPair currentAST = new ASTPair(); - Spring.Expressions.SpringAST arrayRank_AST = null; - - try { // for error handling - Spring.Expressions.SpringAST tmp104_AST = null; - tmp104_AST = (Spring.Expressions.SpringAST) astFactory.create(LT(1)); - astFactory.makeASTRoot(ref currentAST, (AST)tmp104_AST); - match(LBRACKET); - { - if ((tokenSet_9_.member(LA(1)))) - { - expression(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - { // ( ... )* - for (;;) - { - if ((LA(1)==COMMA)) - { - match(COMMA); - expression(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - } - else - { - goto _loop96_breakloop; - } - - } -_loop96_breakloop: ; - } // ( ... )* - } - else if ((LA(1)==RBRACKET)) { - } - else - { - throw new NoViableAltException(LT(1), getFilename()); - } - - } - match(RBRACKET); - arrayRank_AST = (Spring.Expressions.SpringAST)currentAST.root; - } - catch (RecognitionException ex) - { - if (0 == inputState.guessing) - { - reportError(ex); - recover(ex,tokenSet_20_); - } - else - { - throw ex; - } - } - returnAST = arrayRank_AST; - } - - public void mapEntry() //throws RecognitionException, TokenStreamException -{ - - returnAST = null; - ASTPair currentAST = new ASTPair(); - Spring.Expressions.SpringAST mapEntry_AST = null; - - try { // for error handling - expression(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - match(COLON); - expression(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - if (0==inputState.guessing) - { - mapEntry_AST = (Spring.Expressions.SpringAST)currentAST.root; - mapEntry_AST = (Spring.Expressions.SpringAST) astFactory.make((AST)(Spring.Expressions.SpringAST) astFactory.create(EXPR,"entry","Spring.Expressions.MapEntryNode"), (AST)mapEntry_AST); - currentAST.root = mapEntry_AST; - if ( (null != mapEntry_AST) && (null != mapEntry_AST.getFirstChild()) ) - currentAST.child = mapEntry_AST.getFirstChild(); - else - currentAST.child = mapEntry_AST; - currentAST.advanceChildToEnd(); - } - mapEntry_AST = (Spring.Expressions.SpringAST)currentAST.root; - } - catch (RecognitionException ex) - { - if (0 == inputState.guessing) - { - reportError(ex); - recover(ex,tokenSet_21_); - } - else - { - throw ex; - } - } - returnAST = mapEntry_AST; - } - - public void namedArgument() //throws RecognitionException, TokenStreamException -{ - - returnAST = null; - ASTPair currentAST = new ASTPair(); - Spring.Expressions.SpringAST namedArgument_AST = null; - - try { // for error handling - bool synPredMatched111 = false; - if (((LA(1)==ID) && (LA(2)==ASSIGN))) - { - int _m111 = mark(); - synPredMatched111 = true; - inputState.guessing++; - try { - { - match(ID); - match(ASSIGN); - } - } - catch (RecognitionException) - { - synPredMatched111 = false; - } - rewind(_m111); - inputState.guessing--; - } - if ( synPredMatched111 ) - { - Spring.Expressions.NamedArgumentNode tmp108_AST = null; - tmp108_AST = (Spring.Expressions.NamedArgumentNode) astFactory.create(LT(1), "Spring.Expressions.NamedArgumentNode"); - astFactory.makeASTRoot(ref currentAST, (AST)tmp108_AST); - match(ID); - match(ASSIGN); - expression(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - namedArgument_AST = (Spring.Expressions.SpringAST)currentAST.root; - } - else if ((tokenSet_9_.member(LA(1))) && (tokenSet_22_.member(LA(2)))) { - argument(); - if (0 == inputState.guessing) - { - astFactory.addASTChild(ref currentAST, (AST)returnAST); - } - namedArgument_AST = (Spring.Expressions.SpringAST)currentAST.root; - } - else - { - throw new NoViableAltException(LT(1), getFilename()); - } - - } - catch (RecognitionException ex) - { - if (0 == inputState.guessing) - { - reportError(ex); - recover(ex,tokenSet_23_); - } - else - { - throw ex; - } - } - returnAST = namedArgument_AST; - } - - public void boolLiteral() //throws RecognitionException, TokenStreamException -{ - - returnAST = null; - ASTPair currentAST = new ASTPair(); - Spring.Expressions.SpringAST boolLiteral_AST = null; - - try { // for error handling - if ((LA(1)==TRUE)) - { - Spring.Expressions.BooleanLiteralNode tmp110_AST = null; - tmp110_AST = (Spring.Expressions.BooleanLiteralNode) astFactory.create(LT(1), "Spring.Expressions.BooleanLiteralNode"); - astFactory.addASTChild(ref currentAST, (AST)tmp110_AST); - match(TRUE); - boolLiteral_AST = (Spring.Expressions.SpringAST)currentAST.root; - } - else if ((LA(1)==FALSE)) { - Spring.Expressions.BooleanLiteralNode tmp111_AST = null; - tmp111_AST = (Spring.Expressions.BooleanLiteralNode) astFactory.create(LT(1), "Spring.Expressions.BooleanLiteralNode"); - astFactory.addASTChild(ref currentAST, (AST)tmp111_AST); - match(FALSE); - boolLiteral_AST = (Spring.Expressions.SpringAST)currentAST.root; - } - else - { - throw new NoViableAltException(LT(1), getFilename()); - } - - } - catch (RecognitionException ex) - { - if (0 == inputState.guessing) - { - reportError(ex); - recover(ex,tokenSet_2_); - } - else - { - throw ex; - } - } - returnAST = boolLiteral_AST; - } - - public new Spring.Expressions.SpringAST getAST() - { - return (Spring.Expressions.SpringAST) returnAST; - } - - private void initializeFactory() - { - if (astFactory == null) - { - astFactory = new ASTFactory("Spring.Expressions.SpringAST"); - } - initializeASTFactory( astFactory ); - } - static public void initializeASTFactory( ASTFactory factory ) - { - factory.setMaxNodeType(71); - } - - public static readonly string[] tokenNames_ = new string[] { - @"""<0>""", - @"""EOF""", - @"""<2>""", - @"""NULL_TREE_LOOKAHEAD""", - @"""EXPR""", - @"""OPERAND""", - @"""false""", - @"""true""", - @"""and""", - @"""or""", - @"""xor""", - @"""in""", - @"""is""", - @"""between""", - @"""like""", - @"""matches""", - @"""null""", - @"""LPAREN""", - @"""SEMI""", - @"""RPAREN""", - @"""ASSIGN""", - @"""DEFAULT""", - @"""QMARK""", - @"""COLON""", - @"""PLUS""", - @"""MINUS""", - @"""STAR""", - @"""DIV""", - @"""MOD""", - @"""POWER""", - @"""BANG""", - @"""DOT""", - @"""POUND""", - @"""ID""", - @"""DOLLAR""", - @"""COMMA""", - @"""AT""", - @"""LBRACKET""", - @"""RBRACKET""", - @"""PROJECT""", - @"""RCURLY""", - @"""SELECT""", - @"""SELECT_FIRST""", - @"""SELECT_LAST""", - @"""TYPE""", - @"""QUOTE""", - @"""STRING_LITERAL""", - @"""LAMBDA""", - @"""PIPE""", - @"""new""", - @"""LCURLY""", - @"""INTEGER_LITERAL""", - @"""HEXADECIMAL_INTEGER_LITERAL""", - @"""REAL_LITERAL""", - @"""EQUAL""", - @"""NOT_EQUAL""", - @"""LESS_THAN""", - @"""LESS_THAN_OR_EQUAL""", - @"""GREATER_THAN""", - @"""GREATER_THAN_OR_EQUAL""", - @"""WS""", - @"""BACKTICK""", - @"""BACKSLASH""", - @"""DOT_ESCAPED""", - @"""APOS""", - @"""NUMERIC_LITERAL""", - @"""DECIMAL_DIGIT""", - @"""INTEGER_TYPE_SUFFIX""", - @"""HEX_DIGIT""", - @"""EXPONENT_PART""", - @"""SIGN""", - @"""REAL_TYPE_SUFFIX""" - }; - - private static long[] mk_tokenSet_0_() - { - long[] data = { 2L, 0L}; - return data; - } - public static readonly BitSet tokenSet_0_ = new BitSet(mk_tokenSet_0_()); - private static long[] mk_tokenSet_1_() - { - long[] data = { 1408758448130L, 0L}; - return data; - } - public static readonly BitSet tokenSet_1_ = new BitSet(mk_tokenSet_1_()); - private static long[] mk_tokenSet_2_() - { - long[] data = { 1134924607015288578L, 0L}; - return data; - } - public static readonly BitSet tokenSet_2_ = new BitSet(mk_tokenSet_2_()); - private static long[] mk_tokenSet_3_() - { - long[] data = { 1408765788162L, 0L}; - return data; - } - public static readonly BitSet tokenSet_3_ = new BitSet(mk_tokenSet_3_()); - private static long[] mk_tokenSet_4_() - { - long[] data = { 1408765788674L, 0L}; - return data; - } - public static readonly BitSet tokenSet_4_ = new BitSet(mk_tokenSet_4_()); - private static long[] mk_tokenSet_5_() - { - long[] data = { 1408765789698L, 0L}; - return data; - } - public static readonly BitSet tokenSet_5_ = new BitSet(mk_tokenSet_5_()); - private static long[] mk_tokenSet_6_() - { - long[] data = { 1134907106097428480L, 0L}; - return data; - } - public static readonly BitSet tokenSet_6_ = new BitSet(mk_tokenSet_6_()); - private static long[] mk_tokenSet_7_() - { - long[] data = { 1408765789954L, 0L}; - return data; - } - public static readonly BitSet tokenSet_7_ = new BitSet(mk_tokenSet_7_()); - private static long[] mk_tokenSet_8_() - { - long[] data = { 1134908514863218434L, 0L}; - return data; - } - public static readonly BitSet tokenSet_8_ = new BitSet(mk_tokenSet_8_()); - private static long[] mk_tokenSet_9_() - { - long[] data = { 17696327240712384L, 0L}; - return data; - } - public static readonly BitSet tokenSet_9_ = new BitSet(mk_tokenSet_9_()); - private static long[] mk_tokenSet_10_() - { - long[] data = { 1134908514913550082L, 0L}; - return data; - } - public static readonly BitSet tokenSet_10_ = new BitSet(mk_tokenSet_10_()); - private static long[] mk_tokenSet_11_() - { - long[] data = { 1134908515383312130L, 0L}; - return data; - } - public static readonly BitSet tokenSet_11_ = new BitSet(mk_tokenSet_11_()); - private static long[] mk_tokenSet_12_() - { - long[] data = { 17696326116638912L, 0L}; - return data; - } - public static readonly BitSet tokenSet_12_ = new BitSet(mk_tokenSet_12_()); - private static long[] mk_tokenSet_13_() - { - long[] data = { 1134908515920183042L, 0L}; - return data; - } - public static readonly BitSet tokenSet_13_ = new BitSet(mk_tokenSet_13_()); - private static long[] mk_tokenSet_14_() - { - long[] data = { 16091095105536L, 0L}; - return data; - } - public static readonly BitSet tokenSet_14_ = new BitSet(mk_tokenSet_14_()); - private static long[] mk_tokenSet_15_() - { - long[] data = { 309238169600L, 0L}; - return data; - } - public static readonly BitSet tokenSet_15_ = new BitSet(mk_tokenSet_15_()); - private static long[] mk_tokenSet_16_() - { - long[] data = { 8912896L, 0L}; - return data; - } - public static readonly BitSet tokenSet_16_ = new BitSet(mk_tokenSet_16_()); - private static long[] mk_tokenSet_17_() - { - long[] data = { -35184381001744L, 255L, 0L, 0L}; - return data; - } - public static readonly BitSet tokenSet_17_ = new BitSet(mk_tokenSet_17_()); - private static long[] mk_tokenSet_18_() - { - long[] data = { 412316991488L, 0L}; - return data; - } - public static readonly BitSet tokenSet_18_ = new BitSet(mk_tokenSet_18_()); - private static long[] mk_tokenSet_19_() - { - long[] data = { 281474976710656L, 0L}; - return data; - } - public static readonly BitSet tokenSet_19_ = new BitSet(mk_tokenSet_19_()); - private static long[] mk_tokenSet_20_() - { - long[] data = { 1136050506922131202L, 0L}; - return data; - } - public static readonly BitSet tokenSet_20_ = new BitSet(mk_tokenSet_20_()); - private static long[] mk_tokenSet_21_() - { - long[] data = { 1133871366144L, 0L}; - return data; - } - public static readonly BitSet tokenSet_21_ = new BitSet(mk_tokenSet_21_()); - private static long[] mk_tokenSet_22_() - { - long[] data = { 1152884945836572608L, 0L}; - return data; - } - public static readonly BitSet tokenSet_22_ = new BitSet(mk_tokenSet_22_()); - private static long[] mk_tokenSet_23_() - { - long[] data = { 34360262656L, 0L}; - return data; - } - public static readonly BitSet tokenSet_23_ = new BitSet(mk_tokenSet_23_()); + protected void initialize() + { + tokenNames = tokenNames_; + initializeFactory(); + } + + protected ExpressionParser(TokenBuffer tokenBuf, int k) : base(tokenBuf, k) + { + initialize(); + } + + public ExpressionParser(TokenBuffer tokenBuf) : this(tokenBuf, 2) + { + } + + protected ExpressionParser(TokenStream lexer, int k) : base(lexer, k) + { + initialize(); + } + + public ExpressionParser(TokenStream lexer) : this(lexer, 2) + { + } + + public ExpressionParser(ParserSharedInputState state) : base(state, 2) + { + initialize(); + } + + public void expr() //throws RecognitionException, TokenStreamException + { + returnAST = null; + ASTPair currentAST = new ASTPair(); + Spring.Expressions.SpringAST expr_AST = null; + + try + { + // for error handling + expression(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + + match(Token.EOF_TYPE); + expr_AST = (Spring.Expressions.SpringAST) currentAST.root; + } + catch (RecognitionException ex) + { + if (0 == inputState.guessing) + { + reportError(ex); + recover(ex, tokenSet_0_); + } + else + { + throw ex; + } + } + + returnAST = expr_AST; + } + + public void expression() //throws RecognitionException, TokenStreamException + { + returnAST = null; + ASTPair currentAST = new ASTPair(); + Spring.Expressions.SpringAST expression_AST = null; + + try + { + // for error handling + logicalOrExpression(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + + { + switch (LA(1)) + { + case ASSIGN: + { + { + Spring.Expressions.AssignNode tmp2_AST = null; + tmp2_AST = (Spring.Expressions.AssignNode) astFactory.create(LT(1), "Spring.Expressions.AssignNode"); + astFactory.makeASTRoot(ref currentAST, (AST) tmp2_AST); + match(ASSIGN); + logicalOrExpression(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + } + break; + } + case DEFAULT: + { + { + Spring.Expressions.DefaultNode tmp3_AST = null; + tmp3_AST = (Spring.Expressions.DefaultNode) astFactory.create(LT(1), "Spring.Expressions.DefaultNode"); + astFactory.makeASTRoot(ref currentAST, (AST) tmp3_AST); + match(DEFAULT); + logicalOrExpression(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + } + break; + } + case QMARK: + { + { + Spring.Expressions.TernaryNode tmp4_AST = null; + tmp4_AST = (Spring.Expressions.TernaryNode) astFactory.create(LT(1), "Spring.Expressions.TernaryNode"); + astFactory.makeASTRoot(ref currentAST, (AST) tmp4_AST); + match(QMARK); + expression(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + + match(COLON); + expression(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + } + break; + } + case EOF: + case SEMI: + case RPAREN: + case COLON: + case COMMA: + case RBRACKET: + case RCURLY: + { + break; + } + default: + { + throw new NoViableAltException(LT(1), getFilename()); + } + } + } + expression_AST = (Spring.Expressions.SpringAST) currentAST.root; + } + catch (RecognitionException ex) + { + if (0 == inputState.guessing) + { + reportError(ex); + recover(ex, tokenSet_1_); + } + else + { + throw ex; + } + } + + returnAST = expression_AST; + } + + public void exprList() //throws RecognitionException, TokenStreamException + { + returnAST = null; + ASTPair currentAST = new ASTPair(); + Spring.Expressions.SpringAST exprList_AST = null; + + try + { + // for error handling + match(LPAREN); + expression(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + + { + // ( ... )+ + int _cnt4 = 0; + for (;;) + { + if ((LA(1) == SEMI)) + { + match(SEMI); + expression(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + } + else + { + if (_cnt4 >= 1) { goto _loop4_breakloop; } + else + { + throw new NoViableAltException(LT(1), getFilename()); + ; + } + } + + _cnt4++; + } + + _loop4_breakloop: ; + } // ( ... )+ + match(RPAREN); + if (0 == inputState.guessing) + { + exprList_AST = (Spring.Expressions.SpringAST) currentAST.root; + exprList_AST = (Spring.Expressions.SpringAST) astFactory.make((AST) (Spring.Expressions.SpringAST) astFactory.create(EXPR, "expressionList", "Spring.Expressions.ExpressionListNode"), (AST) exprList_AST); + currentAST.root = exprList_AST; + if ((null != exprList_AST) && (null != exprList_AST.getFirstChild())) + currentAST.child = exprList_AST.getFirstChild(); + else + currentAST.child = exprList_AST; + currentAST.advanceChildToEnd(); + } + + exprList_AST = (Spring.Expressions.SpringAST) currentAST.root; + } + catch (RecognitionException ex) + { + if (0 == inputState.guessing) + { + reportError(ex); + recover(ex, tokenSet_2_); + } + else + { + throw ex; + } + } + + returnAST = exprList_AST; + } + + public void logicalOrExpression() //throws RecognitionException, TokenStreamException + { + returnAST = null; + ASTPair currentAST = new ASTPair(); + Spring.Expressions.SpringAST logicalOrExpression_AST = null; + + try + { + // for error handling + logicalXorExpression(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + + { + // ( ... )* + for (;;) + { + if ((LA(1) == OR)) + { + Spring.Expressions.OpOR tmp9_AST = null; + tmp9_AST = (Spring.Expressions.OpOR) astFactory.create(LT(1), "Spring.Expressions.OpOR"); + astFactory.makeASTRoot(ref currentAST, (AST) tmp9_AST); + match(OR); + logicalXorExpression(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + } + else + { + goto _loop13_breakloop; + } + } + + _loop13_breakloop: ; + } // ( ... )* + logicalOrExpression_AST = (Spring.Expressions.SpringAST) currentAST.root; + } + catch (RecognitionException ex) + { + if (0 == inputState.guessing) + { + reportError(ex); + recover(ex, tokenSet_3_); + } + else + { + throw ex; + } + } + + returnAST = logicalOrExpression_AST; + } + + public void parenExpr() //throws RecognitionException, TokenStreamException + { + returnAST = null; + ASTPair currentAST = new ASTPair(); + Spring.Expressions.SpringAST parenExpr_AST = null; + + try + { + // for error handling + match(LPAREN); + expression(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + + match(RPAREN); + parenExpr_AST = (Spring.Expressions.SpringAST) currentAST.root; + } + catch (RecognitionException ex) + { + if (0 == inputState.guessing) + { + reportError(ex); + recover(ex, tokenSet_2_); + } + else + { + throw ex; + } + } + + returnAST = parenExpr_AST; + } + + public void logicalXorExpression() //throws RecognitionException, TokenStreamException + { + returnAST = null; + ASTPair currentAST = new ASTPair(); + Spring.Expressions.SpringAST logicalXorExpression_AST = null; + + try + { + // for error handling + logicalAndExpression(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + + { + // ( ... )* + for (;;) + { + if ((LA(1) == XOR)) + { + Spring.Expressions.OpXOR tmp12_AST = null; + tmp12_AST = (Spring.Expressions.OpXOR) astFactory.create(LT(1), "Spring.Expressions.OpXOR"); + astFactory.makeASTRoot(ref currentAST, (AST) tmp12_AST); + match(XOR); + logicalAndExpression(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + } + else + { + goto _loop16_breakloop; + } + } + + _loop16_breakloop: ; + } // ( ... )* + logicalXorExpression_AST = (Spring.Expressions.SpringAST) currentAST.root; + } + catch (RecognitionException ex) + { + if (0 == inputState.guessing) + { + reportError(ex); + recover(ex, tokenSet_4_); + } + else + { + throw ex; + } + } + + returnAST = logicalXorExpression_AST; + } + + public void logicalAndExpression() //throws RecognitionException, TokenStreamException + { + returnAST = null; + ASTPair currentAST = new ASTPair(); + Spring.Expressions.SpringAST logicalAndExpression_AST = null; + + try + { + // for error handling + relationalExpression(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + + { + // ( ... )* + for (;;) + { + if ((LA(1) == AND)) + { + Spring.Expressions.OpAND tmp13_AST = null; + tmp13_AST = (Spring.Expressions.OpAND) astFactory.create(LT(1), "Spring.Expressions.OpAND"); + astFactory.makeASTRoot(ref currentAST, (AST) tmp13_AST); + match(AND); + relationalExpression(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + } + else + { + goto _loop19_breakloop; + } + } + + _loop19_breakloop: ; + } // ( ... )* + logicalAndExpression_AST = (Spring.Expressions.SpringAST) currentAST.root; + } + catch (RecognitionException ex) + { + if (0 == inputState.guessing) + { + reportError(ex); + recover(ex, tokenSet_5_); + } + else + { + throw ex; + } + } + + returnAST = logicalAndExpression_AST; + } + + public void relationalExpression() //throws RecognitionException, TokenStreamException + { + returnAST = null; + ASTPair currentAST = new ASTPair(); + Spring.Expressions.SpringAST relationalExpression_AST = null; + Spring.Expressions.SpringAST e1_AST = null; + Spring.Expressions.SpringAST op_AST = null; + Spring.Expressions.SpringAST e2_AST = null; + + try + { + // for error handling + sumExpr(); + if (0 == inputState.guessing) + { + e1_AST = (Spring.Expressions.SpringAST) returnAST; + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + + { + if ((tokenSet_6_.member(LA(1)))) + { + relationalOperator(); + if (0 == inputState.guessing) + { + op_AST = (Spring.Expressions.SpringAST) returnAST; + } + + sumExpr(); + if (0 == inputState.guessing) + { + e2_AST = (Spring.Expressions.SpringAST) returnAST; + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + + if (0 == inputState.guessing) + { + relationalExpression_AST = (Spring.Expressions.SpringAST) currentAST.root; + relationalExpression_AST = (Spring.Expressions.SpringAST) astFactory.make((AST) (Spring.Expressions.SpringAST) astFactory.create(EXPR, op_AST.getText(), GetRelationalOperatorNodeType(op_AST.getText())), (AST) relationalExpression_AST); + currentAST.root = relationalExpression_AST; + if ((null != relationalExpression_AST) && (null != relationalExpression_AST.getFirstChild())) + currentAST.child = relationalExpression_AST.getFirstChild(); + else + currentAST.child = relationalExpression_AST; + currentAST.advanceChildToEnd(); + } + } + else if ((tokenSet_7_.member(LA(1)))) + { + } + else + { + throw new NoViableAltException(LT(1), getFilename()); + } + } + relationalExpression_AST = (Spring.Expressions.SpringAST) currentAST.root; + } + catch (RecognitionException ex) + { + if (0 == inputState.guessing) + { + reportError(ex); + recover(ex, tokenSet_7_); + } + else + { + throw ex; + } + } + + returnAST = relationalExpression_AST; + } + + public void sumExpr() //throws RecognitionException, TokenStreamException + { + returnAST = null; + ASTPair currentAST = new ASTPair(); + Spring.Expressions.SpringAST sumExpr_AST = null; + + try + { + // for error handling + prodExpr(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + + { + // ( ... )* + for (;;) + { + if ((LA(1) == PLUS || LA(1) == MINUS)) + { + { + if ((LA(1) == PLUS)) + { + Spring.Expressions.OpADD tmp14_AST = null; + tmp14_AST = (Spring.Expressions.OpADD) astFactory.create(LT(1), "Spring.Expressions.OpADD"); + astFactory.makeASTRoot(ref currentAST, (AST) tmp14_AST); + match(PLUS); + } + else if ((LA(1) == MINUS)) + { + Spring.Expressions.OpSUBTRACT tmp15_AST = null; + tmp15_AST = (Spring.Expressions.OpSUBTRACT) astFactory.create(LT(1), "Spring.Expressions.OpSUBTRACT"); + astFactory.makeASTRoot(ref currentAST, (AST) tmp15_AST); + match(MINUS); + } + else + { + throw new NoViableAltException(LT(1), getFilename()); + } + } + prodExpr(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + } + else + { + goto _loop25_breakloop; + } + } + + _loop25_breakloop: ; + } // ( ... )* + sumExpr_AST = (Spring.Expressions.SpringAST) currentAST.root; + } + catch (RecognitionException ex) + { + if (0 == inputState.guessing) + { + reportError(ex); + recover(ex, tokenSet_8_); + } + else + { + throw ex; + } + } + + returnAST = sumExpr_AST; + } + + public void relationalOperator() //throws RecognitionException, TokenStreamException + { + returnAST = null; + ASTPair currentAST = new ASTPair(); + Spring.Expressions.SpringAST relationalOperator_AST = null; + + try + { + // for error handling + switch (LA(1)) + { + case EQUAL: + { + Spring.Expressions.SpringAST tmp16_AST = null; + tmp16_AST = (Spring.Expressions.SpringAST) astFactory.create(LT(1)); + astFactory.addASTChild(ref currentAST, (AST) tmp16_AST); + match(EQUAL); + relationalOperator_AST = (Spring.Expressions.SpringAST) currentAST.root; + break; + } + case NOT_EQUAL: + { + Spring.Expressions.SpringAST tmp17_AST = null; + tmp17_AST = (Spring.Expressions.SpringAST) astFactory.create(LT(1)); + astFactory.addASTChild(ref currentAST, (AST) tmp17_AST); + match(NOT_EQUAL); + relationalOperator_AST = (Spring.Expressions.SpringAST) currentAST.root; + break; + } + case LESS_THAN: + { + Spring.Expressions.SpringAST tmp18_AST = null; + tmp18_AST = (Spring.Expressions.SpringAST) astFactory.create(LT(1)); + astFactory.addASTChild(ref currentAST, (AST) tmp18_AST); + match(LESS_THAN); + relationalOperator_AST = (Spring.Expressions.SpringAST) currentAST.root; + break; + } + case LESS_THAN_OR_EQUAL: + { + Spring.Expressions.SpringAST tmp19_AST = null; + tmp19_AST = (Spring.Expressions.SpringAST) astFactory.create(LT(1)); + astFactory.addASTChild(ref currentAST, (AST) tmp19_AST); + match(LESS_THAN_OR_EQUAL); + relationalOperator_AST = (Spring.Expressions.SpringAST) currentAST.root; + break; + } + case GREATER_THAN: + { + Spring.Expressions.SpringAST tmp20_AST = null; + tmp20_AST = (Spring.Expressions.SpringAST) astFactory.create(LT(1)); + astFactory.addASTChild(ref currentAST, (AST) tmp20_AST); + match(GREATER_THAN); + relationalOperator_AST = (Spring.Expressions.SpringAST) currentAST.root; + break; + } + case GREATER_THAN_OR_EQUAL: + { + Spring.Expressions.SpringAST tmp21_AST = null; + tmp21_AST = (Spring.Expressions.SpringAST) astFactory.create(LT(1)); + astFactory.addASTChild(ref currentAST, (AST) tmp21_AST); + match(GREATER_THAN_OR_EQUAL); + relationalOperator_AST = (Spring.Expressions.SpringAST) currentAST.root; + break; + } + case IN: + { + Spring.Expressions.SpringAST tmp22_AST = null; + tmp22_AST = (Spring.Expressions.SpringAST) astFactory.create(LT(1)); + astFactory.addASTChild(ref currentAST, (AST) tmp22_AST); + match(IN); + relationalOperator_AST = (Spring.Expressions.SpringAST) currentAST.root; + break; + } + case IS: + { + Spring.Expressions.SpringAST tmp23_AST = null; + tmp23_AST = (Spring.Expressions.SpringAST) astFactory.create(LT(1)); + astFactory.addASTChild(ref currentAST, (AST) tmp23_AST); + match(IS); + relationalOperator_AST = (Spring.Expressions.SpringAST) currentAST.root; + break; + } + case BETWEEN: + { + Spring.Expressions.SpringAST tmp24_AST = null; + tmp24_AST = (Spring.Expressions.SpringAST) astFactory.create(LT(1)); + astFactory.addASTChild(ref currentAST, (AST) tmp24_AST); + match(BETWEEN); + relationalOperator_AST = (Spring.Expressions.SpringAST) currentAST.root; + break; + } + case LIKE: + { + Spring.Expressions.SpringAST tmp25_AST = null; + tmp25_AST = (Spring.Expressions.SpringAST) astFactory.create(LT(1)); + astFactory.addASTChild(ref currentAST, (AST) tmp25_AST); + match(LIKE); + relationalOperator_AST = (Spring.Expressions.SpringAST) currentAST.root; + break; + } + case MATCHES: + { + Spring.Expressions.SpringAST tmp26_AST = null; + tmp26_AST = (Spring.Expressions.SpringAST) astFactory.create(LT(1)); + astFactory.addASTChild(ref currentAST, (AST) tmp26_AST); + match(MATCHES); + relationalOperator_AST = (Spring.Expressions.SpringAST) currentAST.root; + break; + } + default: + { + throw new NoViableAltException(LT(1), getFilename()); + } + } + } + catch (RecognitionException ex) + { + if (0 == inputState.guessing) + { + reportError(ex); + recover(ex, tokenSet_9_); + } + else + { + throw ex; + } + } + + returnAST = relationalOperator_AST; + } + + public void prodExpr() //throws RecognitionException, TokenStreamException + { + returnAST = null; + ASTPair currentAST = new ASTPair(); + Spring.Expressions.SpringAST prodExpr_AST = null; + + try + { + // for error handling + powExpr(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + + { + // ( ... )* + for (;;) + { + if (((LA(1) >= STAR && LA(1) <= MOD))) + { + { + switch (LA(1)) + { + case STAR: + { + Spring.Expressions.OpMULTIPLY tmp27_AST = null; + tmp27_AST = (Spring.Expressions.OpMULTIPLY) astFactory.create(LT(1), "Spring.Expressions.OpMULTIPLY"); + astFactory.makeASTRoot(ref currentAST, (AST) tmp27_AST); + match(STAR); + break; + } + case DIV: + { + Spring.Expressions.OpDIVIDE tmp28_AST = null; + tmp28_AST = (Spring.Expressions.OpDIVIDE) astFactory.create(LT(1), "Spring.Expressions.OpDIVIDE"); + astFactory.makeASTRoot(ref currentAST, (AST) tmp28_AST); + match(DIV); + break; + } + case MOD: + { + Spring.Expressions.OpMODULUS tmp29_AST = null; + tmp29_AST = (Spring.Expressions.OpMODULUS) astFactory.create(LT(1), "Spring.Expressions.OpMODULUS"); + astFactory.makeASTRoot(ref currentAST, (AST) tmp29_AST); + match(MOD); + break; + } + default: + { + throw new NoViableAltException(LT(1), getFilename()); + } + } + } + powExpr(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + } + else + { + goto _loop29_breakloop; + } + } + + _loop29_breakloop: ; + } // ( ... )* + prodExpr_AST = (Spring.Expressions.SpringAST) currentAST.root; + } + catch (RecognitionException ex) + { + if (0 == inputState.guessing) + { + reportError(ex); + recover(ex, tokenSet_10_); + } + else + { + throw ex; + } + } + + returnAST = prodExpr_AST; + } + + public void powExpr() //throws RecognitionException, TokenStreamException + { + returnAST = null; + ASTPair currentAST = new ASTPair(); + Spring.Expressions.SpringAST powExpr_AST = null; + + try + { + // for error handling + unaryExpression(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + + { + if ((LA(1) == POWER)) + { + Spring.Expressions.OpPOWER tmp30_AST = null; + tmp30_AST = (Spring.Expressions.OpPOWER) astFactory.create(LT(1), "Spring.Expressions.OpPOWER"); + astFactory.makeASTRoot(ref currentAST, (AST) tmp30_AST); + match(POWER); + unaryExpression(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + } + else if ((tokenSet_11_.member(LA(1)))) + { + } + else + { + throw new NoViableAltException(LT(1), getFilename()); + } + } + powExpr_AST = (Spring.Expressions.SpringAST) currentAST.root; + } + catch (RecognitionException ex) + { + if (0 == inputState.guessing) + { + reportError(ex); + recover(ex, tokenSet_11_); + } + else + { + throw ex; + } + } + + returnAST = powExpr_AST; + } + + public void unaryExpression() //throws RecognitionException, TokenStreamException + { + returnAST = null; + ASTPair currentAST = new ASTPair(); + Spring.Expressions.SpringAST unaryExpression_AST = null; + + try + { + // for error handling + if ((LA(1) == PLUS || LA(1) == MINUS || LA(1) == BANG)) + { + { + switch (LA(1)) + { + case PLUS: + { + Spring.Expressions.OpUnaryPlus tmp31_AST = null; + tmp31_AST = (Spring.Expressions.OpUnaryPlus) astFactory.create(LT(1), "Spring.Expressions.OpUnaryPlus"); + astFactory.makeASTRoot(ref currentAST, (AST) tmp31_AST); + match(PLUS); + break; + } + case MINUS: + { + Spring.Expressions.OpUnaryMinus tmp32_AST = null; + tmp32_AST = (Spring.Expressions.OpUnaryMinus) astFactory.create(LT(1), "Spring.Expressions.OpUnaryMinus"); + astFactory.makeASTRoot(ref currentAST, (AST) tmp32_AST); + match(MINUS); + break; + } + case BANG: + { + Spring.Expressions.OpNOT tmp33_AST = null; + tmp33_AST = (Spring.Expressions.OpNOT) astFactory.create(LT(1), "Spring.Expressions.OpNOT"); + astFactory.makeASTRoot(ref currentAST, (AST) tmp33_AST); + match(BANG); + break; + } + default: + { + throw new NoViableAltException(LT(1), getFilename()); + } + } + } + unaryExpression(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + + unaryExpression_AST = (Spring.Expressions.SpringAST) currentAST.root; + } + else if ((tokenSet_12_.member(LA(1)))) + { + primaryExpression(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + + unaryExpression_AST = (Spring.Expressions.SpringAST) currentAST.root; + } + else + { + throw new NoViableAltException(LT(1), getFilename()); + } + } + catch (RecognitionException ex) + { + if (0 == inputState.guessing) + { + reportError(ex); + recover(ex, tokenSet_13_); + } + else + { + throw ex; + } + } + + returnAST = unaryExpression_AST; + } + + public void primaryExpression() //throws RecognitionException, TokenStreamException + { + returnAST = null; + ASTPair currentAST = new ASTPair(); + Spring.Expressions.SpringAST primaryExpression_AST = null; + + try + { + // for error handling + startNode(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + + { + if ((tokenSet_14_.member(LA(1)))) + { + node(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + } + else if ((tokenSet_13_.member(LA(1)))) + { + } + else + { + throw new NoViableAltException(LT(1), getFilename()); + } + } + if (0 == inputState.guessing) + { + primaryExpression_AST = (Spring.Expressions.SpringAST) currentAST.root; + primaryExpression_AST = (Spring.Expressions.SpringAST) astFactory.make((AST) (Spring.Expressions.SpringAST) astFactory.create(EXPR, "expression", "Spring.Expressions.Expression"), (AST) primaryExpression_AST); + currentAST.root = primaryExpression_AST; + if ((null != primaryExpression_AST) && (null != primaryExpression_AST.getFirstChild())) + currentAST.child = primaryExpression_AST.getFirstChild(); + else + currentAST.child = primaryExpression_AST; + currentAST.advanceChildToEnd(); + } + + primaryExpression_AST = (Spring.Expressions.SpringAST) currentAST.root; + } + catch (RecognitionException ex) + { + if (0 == inputState.guessing) + { + reportError(ex); + recover(ex, tokenSet_13_); + } + else + { + throw ex; + } + } + + returnAST = primaryExpression_AST; + } + + public void unaryOperator() //throws RecognitionException, TokenStreamException + { + returnAST = null; + ASTPair currentAST = new ASTPair(); + Spring.Expressions.SpringAST unaryOperator_AST = null; + + try + { + // for error handling + switch (LA(1)) + { + case PLUS: + { + Spring.Expressions.SpringAST tmp34_AST = null; + tmp34_AST = (Spring.Expressions.SpringAST) astFactory.create(LT(1)); + astFactory.addASTChild(ref currentAST, (AST) tmp34_AST); + match(PLUS); + unaryOperator_AST = (Spring.Expressions.SpringAST) currentAST.root; + break; + } + case MINUS: + { + Spring.Expressions.SpringAST tmp35_AST = null; + tmp35_AST = (Spring.Expressions.SpringAST) astFactory.create(LT(1)); + astFactory.addASTChild(ref currentAST, (AST) tmp35_AST); + match(MINUS); + unaryOperator_AST = (Spring.Expressions.SpringAST) currentAST.root; + break; + } + case BANG: + { + Spring.Expressions.SpringAST tmp36_AST = null; + tmp36_AST = (Spring.Expressions.SpringAST) astFactory.create(LT(1)); + astFactory.addASTChild(ref currentAST, (AST) tmp36_AST); + match(BANG); + unaryOperator_AST = (Spring.Expressions.SpringAST) currentAST.root; + break; + } + default: + { + throw new NoViableAltException(LT(1), getFilename()); + } + } + } + catch (RecognitionException ex) + { + if (0 == inputState.guessing) + { + reportError(ex); + recover(ex, tokenSet_0_); + } + else + { + throw ex; + } + } + + returnAST = unaryOperator_AST; + } + + public void startNode() //throws RecognitionException, TokenStreamException + { + returnAST = null; + ASTPair currentAST = new ASTPair(); + Spring.Expressions.SpringAST startNode_AST = null; + + try + { + // for error handling + { + switch (LA(1)) + { + case ID: + { + methodOrProperty(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + + break; + } + case DOLLAR: + { + localFunctionOrVar(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + + break; + } + case LBRACKET: + { + indexer(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + + break; + } + case FALSE: + case TRUE: + case NULL_LITERAL: + case STRING_LITERAL: + case INTEGER_LITERAL: + case HEXADECIMAL_INTEGER_LITERAL: + case REAL_LITERAL: + { + literal(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + + break; + } + case TYPE: + { + type(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + + break; + } + case LITERAL_new: + { + constructor(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + + break; + } + case PROJECT: + { + projection(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + + break; + } + case SELECT: + { + selection(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + + break; + } + case SELECT_FIRST: + { + firstSelection(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + + break; + } + case SELECT_LAST: + { + lastSelection(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + + break; + } + case LCURLY: + { + listInitializer(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + + break; + } + case LAMBDA: + { + lambda(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + + break; + } + default: + bool synPredMatched40 = false; + if (((LA(1) == LPAREN) && (tokenSet_9_.member(LA(2))))) + { + int _m40 = mark(); + synPredMatched40 = true; + inputState.guessing++; + try + { + { + match(LPAREN); + expression(); + match(SEMI); + } + } + catch (RecognitionException) + { + synPredMatched40 = false; + } + + rewind(_m40); + inputState.guessing--; + } + + if (synPredMatched40) + { + exprList(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + } + else if ((LA(1) == LPAREN) && (tokenSet_9_.member(LA(2)))) + { + parenExpr(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + } + else if ((LA(1) == POUND) && (LA(2) == ID)) + { + functionOrVar(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + } + else if ((LA(1) == AT) && (LA(2) == LPAREN)) + { + reference(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + } + else if ((LA(1) == POUND) && (LA(2) == LCURLY)) + { + mapInitializer(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + } + else if ((LA(1) == AT) && (LA(2) == LBRACKET)) + { + attribute(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + } + else + { + throw new NoViableAltException(LT(1), getFilename()); + } + + break; + } + } + startNode_AST = (Spring.Expressions.SpringAST) currentAST.root; + } + catch (RecognitionException ex) + { + if (0 == inputState.guessing) + { + reportError(ex); + recover(ex, tokenSet_2_); + } + else + { + throw ex; + } + } + + returnAST = startNode_AST; + } + + public void node() //throws RecognitionException, TokenStreamException + { + returnAST = null; + ASTPair currentAST = new ASTPair(); + Spring.Expressions.SpringAST node_AST = null; + + try + { + // for error handling + { + // ( ... )+ + int _cnt43 = 0; + for (;;) + { + switch (LA(1)) + { + case ID: + { + methodOrProperty(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + + break; + } + case LBRACKET: + { + indexer(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + + break; + } + case PROJECT: + { + projection(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + + break; + } + case SELECT: + { + selection(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + + break; + } + case SELECT_FIRST: + { + firstSelection(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + + break; + } + case SELECT_LAST: + { + lastSelection(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + + break; + } + case LPAREN: + { + exprList(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + + break; + } + case DOT: + { + match(DOT); + break; + } + default: + { + if (_cnt43 >= 1) { goto _loop43_breakloop; } + else + { + throw new NoViableAltException(LT(1), getFilename()); + ; + } + } + break; + } + + _cnt43++; + } + + _loop43_breakloop: ; + } // ( ... )+ + node_AST = (Spring.Expressions.SpringAST) currentAST.root; + } + catch (RecognitionException ex) + { + if (0 == inputState.guessing) + { + reportError(ex); + recover(ex, tokenSet_13_); + } + else + { + throw ex; + } + } + + returnAST = node_AST; + } + + public void methodOrProperty() //throws RecognitionException, TokenStreamException + { + returnAST = null; + ASTPair currentAST = new ASTPair(); + Spring.Expressions.SpringAST methodOrProperty_AST = null; + + try + { + // for error handling + bool synPredMatched56 = false; + if (((LA(1) == ID) && (LA(2) == LPAREN))) + { + int _m56 = mark(); + synPredMatched56 = true; + inputState.guessing++; + try + { + { + match(ID); + match(LPAREN); + } + } + catch (RecognitionException) + { + synPredMatched56 = false; + } + + rewind(_m56); + inputState.guessing--; + } + + if (synPredMatched56) + { + Spring.Expressions.MethodNode tmp38_AST = null; + tmp38_AST = (Spring.Expressions.MethodNode) astFactory.create(LT(1), "Spring.Expressions.MethodNode"); + astFactory.makeASTRoot(ref currentAST, (AST) tmp38_AST); + match(ID); + methodArgs(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + + methodOrProperty_AST = (Spring.Expressions.SpringAST) currentAST.root; + } + else if ((LA(1) == ID) && (tokenSet_2_.member(LA(2)))) + { + property(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + + methodOrProperty_AST = (Spring.Expressions.SpringAST) currentAST.root; + } + else + { + throw new NoViableAltException(LT(1), getFilename()); + } + } + catch (RecognitionException ex) + { + if (0 == inputState.guessing) + { + reportError(ex); + recover(ex, tokenSet_2_); + } + else + { + throw ex; + } + } + + returnAST = methodOrProperty_AST; + } + + public void functionOrVar() //throws RecognitionException, TokenStreamException + { + returnAST = null; + ASTPair currentAST = new ASTPair(); + Spring.Expressions.SpringAST functionOrVar_AST = null; + + try + { + // for error handling + bool synPredMatched46 = false; + if (((LA(1) == POUND) && (LA(2) == ID))) + { + int _m46 = mark(); + synPredMatched46 = true; + inputState.guessing++; + try + { + { + match(POUND); + match(ID); + match(LPAREN); + } + } + catch (RecognitionException) + { + synPredMatched46 = false; + } + + rewind(_m46); + inputState.guessing--; + } + + if (synPredMatched46) + { + function(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + + functionOrVar_AST = (Spring.Expressions.SpringAST) currentAST.root; + } + else if ((LA(1) == POUND) && (LA(2) == ID)) + { + var(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + + functionOrVar_AST = (Spring.Expressions.SpringAST) currentAST.root; + } + else + { + throw new NoViableAltException(LT(1), getFilename()); + } + } + catch (RecognitionException ex) + { + if (0 == inputState.guessing) + { + reportError(ex); + recover(ex, tokenSet_2_); + } + else + { + throw ex; + } + } + + returnAST = functionOrVar_AST; + } + + public void localFunctionOrVar() //throws RecognitionException, TokenStreamException + { + returnAST = null; + ASTPair currentAST = new ASTPair(); + Spring.Expressions.SpringAST localFunctionOrVar_AST = null; + + try + { + // for error handling + bool synPredMatched51 = false; + if (((LA(1) == DOLLAR) && (LA(2) == ID))) + { + int _m51 = mark(); + synPredMatched51 = true; + inputState.guessing++; + try + { + { + match(DOLLAR); + match(ID); + match(LPAREN); + } + } + catch (RecognitionException) + { + synPredMatched51 = false; + } + + rewind(_m51); + inputState.guessing--; + } + + if (synPredMatched51) + { + localFunction(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + + localFunctionOrVar_AST = (Spring.Expressions.SpringAST) currentAST.root; + } + else if ((LA(1) == DOLLAR) && (LA(2) == ID)) + { + localVar(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + + localFunctionOrVar_AST = (Spring.Expressions.SpringAST) currentAST.root; + } + else + { + throw new NoViableAltException(LT(1), getFilename()); + } + } + catch (RecognitionException ex) + { + if (0 == inputState.guessing) + { + reportError(ex); + recover(ex, tokenSet_2_); + } + else + { + throw ex; + } + } + + returnAST = localFunctionOrVar_AST; + } + + public void reference() //throws RecognitionException, TokenStreamException + { + returnAST = null; + ASTPair currentAST = new ASTPair(); + Spring.Expressions.SpringAST reference_AST = null; + Spring.Expressions.SpringAST cn_AST = null; + Spring.Expressions.SpringAST id_AST = null; + Spring.Expressions.SpringAST localid_AST = null; + + try + { + // for error handling + bool synPredMatched64 = false; + if (((LA(1) == AT) && (LA(2) == LPAREN))) + { + int _m64 = mark(); + synPredMatched64 = true; + inputState.guessing++; + try + { + { + match(AT); + match(LPAREN); + quotableName(); + match(COLON); + } + } + catch (RecognitionException) + { + synPredMatched64 = false; + } + + rewind(_m64); + inputState.guessing--; + } + + if (synPredMatched64) + { + match(AT); + match(LPAREN); + quotableName(); + if (0 == inputState.guessing) + { + cn_AST = (Spring.Expressions.SpringAST) returnAST; + } + + match(COLON); + quotableName(); + if (0 == inputState.guessing) + { + id_AST = (Spring.Expressions.SpringAST) returnAST; + } + + match(RPAREN); + if (0 == inputState.guessing) + { + reference_AST = (Spring.Expressions.SpringAST) currentAST.root; + reference_AST = (Spring.Expressions.SpringAST) astFactory.make((AST) (Spring.Expressions.SpringAST) astFactory.create(EXPR, "ref", "Spring.Context.Support.ReferenceNode"), (AST) cn_AST, (AST) id_AST); + currentAST.root = reference_AST; + if ((null != reference_AST) && (null != reference_AST.getFirstChild())) + currentAST.child = reference_AST.getFirstChild(); + else + currentAST.child = reference_AST; + currentAST.advanceChildToEnd(); + } + + reference_AST = (Spring.Expressions.SpringAST) currentAST.root; + } + else if ((LA(1) == AT) && (LA(2) == LPAREN)) + { + match(AT); + match(LPAREN); + quotableName(); + if (0 == inputState.guessing) + { + localid_AST = (Spring.Expressions.SpringAST) returnAST; + } + + match(RPAREN); + if (0 == inputState.guessing) + { + reference_AST = (Spring.Expressions.SpringAST) currentAST.root; + reference_AST = (Spring.Expressions.SpringAST) astFactory.make((AST) (Spring.Expressions.SpringAST) astFactory.create(EXPR, "ref", "Spring.Context.Support.ReferenceNode"), (AST) null, (AST) localid_AST); + currentAST.root = reference_AST; + if ((null != reference_AST) && (null != reference_AST.getFirstChild())) + currentAST.child = reference_AST.getFirstChild(); + else + currentAST.child = reference_AST; + currentAST.advanceChildToEnd(); + } + + reference_AST = (Spring.Expressions.SpringAST) currentAST.root; + } + else + { + throw new NoViableAltException(LT(1), getFilename()); + } + } + catch (RecognitionException ex) + { + if (0 == inputState.guessing) + { + reportError(ex); + recover(ex, tokenSet_2_); + } + else + { + throw ex; + } + } + + returnAST = reference_AST; + } + + public void indexer() //throws RecognitionException, TokenStreamException + { + returnAST = null; + ASTPair currentAST = new ASTPair(); + Spring.Expressions.SpringAST indexer_AST = null; + + try + { + // for error handling + Spring.Expressions.IndexerNode tmp46_AST = null; + tmp46_AST = (Spring.Expressions.IndexerNode) astFactory.create(LT(1), "Spring.Expressions.IndexerNode"); + astFactory.makeASTRoot(ref currentAST, (AST) tmp46_AST); + match(LBRACKET); + argument(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + + { + // ( ... )* + for (;;) + { + if ((LA(1) == COMMA)) + { + match(COMMA); + argument(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + } + else + { + goto _loop67_breakloop; + } + } + + _loop67_breakloop: ; + } // ( ... )* + match(RBRACKET); + indexer_AST = (Spring.Expressions.SpringAST) currentAST.root; + } + catch (RecognitionException ex) + { + if (0 == inputState.guessing) + { + reportError(ex); + recover(ex, tokenSet_2_); + } + else + { + throw ex; + } + } + + returnAST = indexer_AST; + } + + public void literal() //throws RecognitionException, TokenStreamException + { + returnAST = null; + ASTPair currentAST = new ASTPair(); + Spring.Expressions.SpringAST literal_AST = null; + + try + { + // for error handling + switch (LA(1)) + { + case NULL_LITERAL: + { + Spring.Expressions.NullLiteralNode tmp49_AST = null; + tmp49_AST = (Spring.Expressions.NullLiteralNode) astFactory.create(LT(1), "Spring.Expressions.NullLiteralNode"); + astFactory.addASTChild(ref currentAST, (AST) tmp49_AST); + match(NULL_LITERAL); + literal_AST = (Spring.Expressions.SpringAST) currentAST.root; + break; + } + case INTEGER_LITERAL: + { + Spring.Expressions.IntLiteralNode tmp50_AST = null; + tmp50_AST = (Spring.Expressions.IntLiteralNode) astFactory.create(LT(1), "Spring.Expressions.IntLiteralNode"); + astFactory.addASTChild(ref currentAST, (AST) tmp50_AST); + match(INTEGER_LITERAL); + literal_AST = (Spring.Expressions.SpringAST) currentAST.root; + break; + } + case HEXADECIMAL_INTEGER_LITERAL: + { + Spring.Expressions.HexLiteralNode tmp51_AST = null; + tmp51_AST = (Spring.Expressions.HexLiteralNode) astFactory.create(LT(1), "Spring.Expressions.HexLiteralNode"); + astFactory.addASTChild(ref currentAST, (AST) tmp51_AST); + match(HEXADECIMAL_INTEGER_LITERAL); + literal_AST = (Spring.Expressions.SpringAST) currentAST.root; + break; + } + case REAL_LITERAL: + { + Spring.Expressions.RealLiteralNode tmp52_AST = null; + tmp52_AST = (Spring.Expressions.RealLiteralNode) astFactory.create(LT(1), "Spring.Expressions.RealLiteralNode"); + astFactory.addASTChild(ref currentAST, (AST) tmp52_AST); + match(REAL_LITERAL); + literal_AST = (Spring.Expressions.SpringAST) currentAST.root; + break; + } + case STRING_LITERAL: + { + Spring.Expressions.StringLiteralNode tmp53_AST = null; + tmp53_AST = (Spring.Expressions.StringLiteralNode) astFactory.create(LT(1), "Spring.Expressions.StringLiteralNode"); + astFactory.addASTChild(ref currentAST, (AST) tmp53_AST); + match(STRING_LITERAL); + literal_AST = (Spring.Expressions.SpringAST) currentAST.root; + break; + } + case FALSE: + case TRUE: + { + boolLiteral(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + + literal_AST = (Spring.Expressions.SpringAST) currentAST.root; + break; + } + default: + { + throw new NoViableAltException(LT(1), getFilename()); + } + } + } + catch (RecognitionException ex) + { + if (0 == inputState.guessing) + { + reportError(ex); + recover(ex, tokenSet_2_); + } + else + { + throw ex; + } + } + + returnAST = literal_AST; + } + + public void type() //throws RecognitionException, TokenStreamException + { + returnAST = null; + ASTPair currentAST = new ASTPair(); + Spring.Expressions.SpringAST type_AST = null; + Spring.Expressions.SpringAST tn_AST = null; + + try + { + // for error handling + match(TYPE); + name(); + if (0 == inputState.guessing) + { + tn_AST = (Spring.Expressions.SpringAST) returnAST; + } + + match(RPAREN); + if (0 == inputState.guessing) + { + type_AST = (Spring.Expressions.SpringAST) currentAST.root; + type_AST = (Spring.Expressions.SpringAST) astFactory.make((AST) (Spring.Expressions.SpringAST) astFactory.create(EXPR, tn_AST.getText(), "Spring.Expressions.TypeNode"), (AST) type_AST); + currentAST.root = type_AST; + if ((null != type_AST) && (null != type_AST.getFirstChild())) + currentAST.child = type_AST.getFirstChild(); + else + currentAST.child = type_AST; + currentAST.advanceChildToEnd(); + } + + type_AST = (Spring.Expressions.SpringAST) currentAST.root; + } + catch (RecognitionException ex) + { + if (0 == inputState.guessing) + { + reportError(ex); + recover(ex, tokenSet_2_); + } + else + { + throw ex; + } + } + + returnAST = type_AST; + } + + public void constructor() //throws RecognitionException, TokenStreamException + { + returnAST = null; + ASTPair currentAST = new ASTPair(); + Spring.Expressions.SpringAST constructor_AST = null; + Spring.Expressions.SpringAST type_AST = null; + + try + { + // for error handling + bool synPredMatched90 = false; + if (((LA(1) == LITERAL_new) && (LA(2) == ID))) + { + int _m90 = mark(); + synPredMatched90 = true; + inputState.guessing++; + try + { + { + match(LITERAL_new); + qualifiedId(); + match(LPAREN); + } + } + catch (RecognitionException) + { + synPredMatched90 = false; + } + + rewind(_m90); + inputState.guessing--; + } + + if (synPredMatched90) + { + match(LITERAL_new); + qualifiedId(); + if (0 == inputState.guessing) + { + type_AST = (Spring.Expressions.SpringAST) returnAST; + } + + ctorArgs(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + + if (0 == inputState.guessing) + { + constructor_AST = (Spring.Expressions.SpringAST) currentAST.root; + constructor_AST = (Spring.Expressions.SpringAST) astFactory.make((AST) (Spring.Expressions.SpringAST) astFactory.create(EXPR, type_AST.getText(), "Spring.Expressions.ConstructorNode"), (AST) constructor_AST); + currentAST.root = constructor_AST; + if ((null != constructor_AST) && (null != constructor_AST.getFirstChild())) + currentAST.child = constructor_AST.getFirstChild(); + else + currentAST.child = constructor_AST; + currentAST.advanceChildToEnd(); + } + + constructor_AST = (Spring.Expressions.SpringAST) currentAST.root; + } + else if ((LA(1) == LITERAL_new) && (LA(2) == ID)) + { + arrayConstructor(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + + constructor_AST = (Spring.Expressions.SpringAST) currentAST.root; + } + else + { + throw new NoViableAltException(LT(1), getFilename()); + } + } + catch (RecognitionException ex) + { + if (0 == inputState.guessing) + { + reportError(ex); + recover(ex, tokenSet_2_); + } + else + { + throw ex; + } + } + + returnAST = constructor_AST; + } + + public void projection() //throws RecognitionException, TokenStreamException + { + returnAST = null; + ASTPair currentAST = new ASTPair(); + Spring.Expressions.SpringAST projection_AST = null; + + try + { + // for error handling + Spring.Expressions.ProjectionNode tmp57_AST = null; + tmp57_AST = (Spring.Expressions.ProjectionNode) astFactory.create(LT(1), "Spring.Expressions.ProjectionNode"); + astFactory.makeASTRoot(ref currentAST, (AST) tmp57_AST); + match(PROJECT); + expression(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + + match(RCURLY); + projection_AST = (Spring.Expressions.SpringAST) currentAST.root; + } + catch (RecognitionException ex) + { + if (0 == inputState.guessing) + { + reportError(ex); + recover(ex, tokenSet_2_); + } + else + { + throw ex; + } + } + + returnAST = projection_AST; + } + + public void selection() //throws RecognitionException, TokenStreamException + { + returnAST = null; + ASTPair currentAST = new ASTPair(); + Spring.Expressions.SpringAST selection_AST = null; + + try + { + // for error handling + Spring.Expressions.SelectionNode tmp59_AST = null; + tmp59_AST = (Spring.Expressions.SelectionNode) astFactory.create(LT(1), "Spring.Expressions.SelectionNode"); + astFactory.makeASTRoot(ref currentAST, (AST) tmp59_AST); + match(SELECT); + expression(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + + { + // ( ... )* + for (;;) + { + if ((LA(1) == COMMA)) + { + match(COMMA); + expression(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + } + else + { + goto _loop71_breakloop; + } + } + + _loop71_breakloop: ; + } // ( ... )* + match(RCURLY); + selection_AST = (Spring.Expressions.SpringAST) currentAST.root; + } + catch (RecognitionException ex) + { + if (0 == inputState.guessing) + { + reportError(ex); + recover(ex, tokenSet_2_); + } + else + { + throw ex; + } + } + + returnAST = selection_AST; + } + + public void firstSelection() //throws RecognitionException, TokenStreamException + { + returnAST = null; + ASTPair currentAST = new ASTPair(); + Spring.Expressions.SpringAST firstSelection_AST = null; + + try + { + // for error handling + Spring.Expressions.SelectionFirstNode tmp62_AST = null; + tmp62_AST = (Spring.Expressions.SelectionFirstNode) astFactory.create(LT(1), "Spring.Expressions.SelectionFirstNode"); + astFactory.makeASTRoot(ref currentAST, (AST) tmp62_AST); + match(SELECT_FIRST); + expression(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + + match(RCURLY); + firstSelection_AST = (Spring.Expressions.SpringAST) currentAST.root; + } + catch (RecognitionException ex) + { + if (0 == inputState.guessing) + { + reportError(ex); + recover(ex, tokenSet_2_); + } + else + { + throw ex; + } + } + + returnAST = firstSelection_AST; + } + + public void lastSelection() //throws RecognitionException, TokenStreamException + { + returnAST = null; + ASTPair currentAST = new ASTPair(); + Spring.Expressions.SpringAST lastSelection_AST = null; + + try + { + // for error handling + Spring.Expressions.SelectionLastNode tmp64_AST = null; + tmp64_AST = (Spring.Expressions.SelectionLastNode) astFactory.create(LT(1), "Spring.Expressions.SelectionLastNode"); + astFactory.makeASTRoot(ref currentAST, (AST) tmp64_AST); + match(SELECT_LAST); + expression(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + + match(RCURLY); + lastSelection_AST = (Spring.Expressions.SpringAST) currentAST.root; + } + catch (RecognitionException ex) + { + if (0 == inputState.guessing) + { + reportError(ex); + recover(ex, tokenSet_2_); + } + else + { + throw ex; + } + } + + returnAST = lastSelection_AST; + } + + public void listInitializer() //throws RecognitionException, TokenStreamException + { + returnAST = null; + ASTPair currentAST = new ASTPair(); + Spring.Expressions.SpringAST listInitializer_AST = null; + + try + { + // for error handling + Spring.Expressions.ListInitializerNode tmp66_AST = null; + tmp66_AST = (Spring.Expressions.ListInitializerNode) astFactory.create(LT(1), "Spring.Expressions.ListInitializerNode"); + astFactory.makeASTRoot(ref currentAST, (AST) tmp66_AST); + match(LCURLY); + expression(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + + { + // ( ... )* + for (;;) + { + if ((LA(1) == COMMA)) + { + match(COMMA); + expression(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + } + else + { + goto _loop99_breakloop; + } + } + + _loop99_breakloop: ; + } // ( ... )* + match(RCURLY); + listInitializer_AST = (Spring.Expressions.SpringAST) currentAST.root; + } + catch (RecognitionException ex) + { + if (0 == inputState.guessing) + { + reportError(ex); + recover(ex, tokenSet_2_); + } + else + { + throw ex; + } + } + + returnAST = listInitializer_AST; + } + + public void mapInitializer() //throws RecognitionException, TokenStreamException + { + returnAST = null; + ASTPair currentAST = new ASTPair(); + Spring.Expressions.SpringAST mapInitializer_AST = null; + + try + { + // for error handling + match(POUND); + Spring.Expressions.MapInitializerNode tmp70_AST = null; + tmp70_AST = (Spring.Expressions.MapInitializerNode) astFactory.create(LT(1), "Spring.Expressions.MapInitializerNode"); + astFactory.makeASTRoot(ref currentAST, (AST) tmp70_AST); + match(LCURLY); + mapEntry(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + + { + // ( ... )* + for (;;) + { + if ((LA(1) == COMMA)) + { + match(COMMA); + mapEntry(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + } + else + { + goto _loop102_breakloop; + } + } + + _loop102_breakloop: ; + } // ( ... )* + match(RCURLY); + mapInitializer_AST = (Spring.Expressions.SpringAST) currentAST.root; + } + catch (RecognitionException ex) + { + if (0 == inputState.guessing) + { + reportError(ex); + recover(ex, tokenSet_2_); + } + else + { + throw ex; + } + } + + returnAST = mapInitializer_AST; + } + + public void lambda() //throws RecognitionException, TokenStreamException + { + returnAST = null; + ASTPair currentAST = new ASTPair(); + Spring.Expressions.SpringAST lambda_AST = null; + + try + { + // for error handling + match(LAMBDA); + { + if ((LA(1) == ID)) + { + argList(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + } + else if ((LA(1) == PIPE)) + { + } + else + { + throw new NoViableAltException(LT(1), getFilename()); + } + } + match(PIPE); + expression(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + + match(RCURLY); + if (0 == inputState.guessing) + { + lambda_AST = (Spring.Expressions.SpringAST) currentAST.root; + lambda_AST = (Spring.Expressions.SpringAST) astFactory.make((AST) (Spring.Expressions.SpringAST) astFactory.create(EXPR, "lambda", "Spring.Expressions.LambdaExpressionNode"), (AST) lambda_AST); + currentAST.root = lambda_AST; + if ((null != lambda_AST) && (null != lambda_AST.getFirstChild())) + currentAST.child = lambda_AST.getFirstChild(); + else + currentAST.child = lambda_AST; + currentAST.advanceChildToEnd(); + } + + lambda_AST = (Spring.Expressions.SpringAST) currentAST.root; + } + catch (RecognitionException ex) + { + if (0 == inputState.guessing) + { + reportError(ex); + recover(ex, tokenSet_2_); + } + else + { + throw ex; + } + } + + returnAST = lambda_AST; + } + + public void attribute() //throws RecognitionException, TokenStreamException + { + returnAST = null; + ASTPair currentAST = new ASTPair(); + Spring.Expressions.SpringAST attribute_AST = null; + Spring.Expressions.SpringAST tn_AST = null; + + try + { + // for error handling + match(AT); + match(LBRACKET); + qualifiedId(); + if (0 == inputState.guessing) + { + tn_AST = (Spring.Expressions.SpringAST) returnAST; + } + + { + if ((LA(1) == LPAREN)) + { + ctorArgs(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + } + else if ((LA(1) == RBRACKET)) + { + } + else + { + throw new NoViableAltException(LT(1), getFilename()); + } + } + match(RBRACKET); + if (0 == inputState.guessing) + { + attribute_AST = (Spring.Expressions.SpringAST) currentAST.root; + attribute_AST = (Spring.Expressions.SpringAST) astFactory.make((AST) (Spring.Expressions.SpringAST) astFactory.create(EXPR, tn_AST.getText(), "Spring.Expressions.AttributeNode"), (AST) attribute_AST); + currentAST.root = attribute_AST; + if ((null != attribute_AST) && (null != attribute_AST.getFirstChild())) + currentAST.child = attribute_AST.getFirstChild(); + else + currentAST.child = attribute_AST; + currentAST.advanceChildToEnd(); + } + + attribute_AST = (Spring.Expressions.SpringAST) currentAST.root; + } + catch (RecognitionException ex) + { + if (0 == inputState.guessing) + { + reportError(ex); + recover(ex, tokenSet_2_); + } + else + { + throw ex; + } + } + + returnAST = attribute_AST; + } + + public void function() //throws RecognitionException, TokenStreamException + { + returnAST = null; + ASTPair currentAST = new ASTPair(); + Spring.Expressions.SpringAST function_AST = null; + + try + { + // for error handling + match(POUND); + Spring.Expressions.FunctionNode tmp80_AST = null; + tmp80_AST = (Spring.Expressions.FunctionNode) astFactory.create(LT(1), "Spring.Expressions.FunctionNode"); + astFactory.makeASTRoot(ref currentAST, (AST) tmp80_AST); + match(ID); + methodArgs(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + + function_AST = (Spring.Expressions.SpringAST) currentAST.root; + } + catch (RecognitionException ex) + { + if (0 == inputState.guessing) + { + reportError(ex); + recover(ex, tokenSet_2_); + } + else + { + throw ex; + } + } + + returnAST = function_AST; + } + + public void var() //throws RecognitionException, TokenStreamException + { + returnAST = null; + ASTPair currentAST = new ASTPair(); + Spring.Expressions.SpringAST var_AST = null; + + try + { + // for error handling + match(POUND); + Spring.Expressions.VariableNode tmp82_AST = null; + tmp82_AST = (Spring.Expressions.VariableNode) astFactory.create(LT(1), "Spring.Expressions.VariableNode"); + astFactory.makeASTRoot(ref currentAST, (AST) tmp82_AST); + match(ID); + var_AST = (Spring.Expressions.SpringAST) currentAST.root; + } + catch (RecognitionException ex) + { + if (0 == inputState.guessing) + { + reportError(ex); + recover(ex, tokenSet_2_); + } + else + { + throw ex; + } + } + + returnAST = var_AST; + } + + public void methodArgs() //throws RecognitionException, TokenStreamException + { + returnAST = null; + ASTPair currentAST = new ASTPair(); + Spring.Expressions.SpringAST methodArgs_AST = null; + + try + { + // for error handling + match(LPAREN); + { + if ((tokenSet_9_.member(LA(1)))) + { + argument(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + + { + // ( ... )* + for (;;) + { + if ((LA(1) == COMMA)) + { + match(COMMA); + argument(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + } + else + { + goto _loop60_breakloop; + } + } + + _loop60_breakloop: ; + } // ( ... )* + } + else if ((LA(1) == RPAREN)) + { + } + else + { + throw new NoViableAltException(LT(1), getFilename()); + } + } + match(RPAREN); + methodArgs_AST = (Spring.Expressions.SpringAST) currentAST.root; + } + catch (RecognitionException ex) + { + if (0 == inputState.guessing) + { + reportError(ex); + recover(ex, tokenSet_2_); + } + else + { + throw ex; + } + } + + returnAST = methodArgs_AST; + } + + public void localFunction() //throws RecognitionException, TokenStreamException + { + returnAST = null; + ASTPair currentAST = new ASTPair(); + Spring.Expressions.SpringAST localFunction_AST = null; + + try + { + // for error handling + match(DOLLAR); + Spring.Expressions.LocalFunctionNode tmp87_AST = null; + tmp87_AST = (Spring.Expressions.LocalFunctionNode) astFactory.create(LT(1), "Spring.Expressions.LocalFunctionNode"); + astFactory.makeASTRoot(ref currentAST, (AST) tmp87_AST); + match(ID); + methodArgs(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + + localFunction_AST = (Spring.Expressions.SpringAST) currentAST.root; + } + catch (RecognitionException ex) + { + if (0 == inputState.guessing) + { + reportError(ex); + recover(ex, tokenSet_2_); + } + else + { + throw ex; + } + } + + returnAST = localFunction_AST; + } + + public void localVar() //throws RecognitionException, TokenStreamException + { + returnAST = null; + ASTPair currentAST = new ASTPair(); + Spring.Expressions.SpringAST localVar_AST = null; + + try + { + // for error handling + match(DOLLAR); + Spring.Expressions.LocalVariableNode tmp89_AST = null; + tmp89_AST = (Spring.Expressions.LocalVariableNode) astFactory.create(LT(1), "Spring.Expressions.LocalVariableNode"); + astFactory.makeASTRoot(ref currentAST, (AST) tmp89_AST); + match(ID); + localVar_AST = (Spring.Expressions.SpringAST) currentAST.root; + } + catch (RecognitionException ex) + { + if (0 == inputState.guessing) + { + reportError(ex); + recover(ex, tokenSet_2_); + } + else + { + throw ex; + } + } + + returnAST = localVar_AST; + } + + public void property() //throws RecognitionException, TokenStreamException + { + returnAST = null; + ASTPair currentAST = new ASTPair(); + Spring.Expressions.SpringAST property_AST = null; + + try + { + // for error handling + Spring.Expressions.PropertyOrFieldNode tmp90_AST = null; + tmp90_AST = (Spring.Expressions.PropertyOrFieldNode) astFactory.create(LT(1), "Spring.Expressions.PropertyOrFieldNode"); + astFactory.addASTChild(ref currentAST, (AST) tmp90_AST); + match(ID); + property_AST = (Spring.Expressions.SpringAST) currentAST.root; + } + catch (RecognitionException ex) + { + if (0 == inputState.guessing) + { + reportError(ex); + recover(ex, tokenSet_2_); + } + else + { + throw ex; + } + } + + returnAST = property_AST; + } + + public void argument() //throws RecognitionException, TokenStreamException + { + returnAST = null; + ASTPair currentAST = new ASTPair(); + Spring.Expressions.SpringAST argument_AST = null; + + try + { + // for error handling + expression(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + + argument_AST = (Spring.Expressions.SpringAST) currentAST.root; + } + catch (RecognitionException ex) + { + if (0 == inputState.guessing) + { + reportError(ex); + recover(ex, tokenSet_15_); + } + else + { + throw ex; + } + } + + returnAST = argument_AST; + } + + public void quotableName() //throws RecognitionException, TokenStreamException + { + returnAST = null; + ASTPair currentAST = new ASTPair(); + Spring.Expressions.SpringAST quotableName_AST = null; + + try + { + // for error handling + if ((LA(1) == STRING_LITERAL)) + { + Spring.Expressions.QualifiedIdentifier tmp91_AST = null; + tmp91_AST = (Spring.Expressions.QualifiedIdentifier) astFactory.create(LT(1), "Spring.Expressions.QualifiedIdentifier"); + astFactory.makeASTRoot(ref currentAST, (AST) tmp91_AST); + match(STRING_LITERAL); + quotableName_AST = (Spring.Expressions.SpringAST) currentAST.root; + } + else if ((LA(1) == ID)) + { + name(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + + quotableName_AST = (Spring.Expressions.SpringAST) currentAST.root; + } + else + { + throw new NoViableAltException(LT(1), getFilename()); + } + } + catch (RecognitionException ex) + { + if (0 == inputState.guessing) + { + reportError(ex); + recover(ex, tokenSet_16_); + } + else + { + throw ex; + } + } + + returnAST = quotableName_AST; + } + + public void name() //throws RecognitionException, TokenStreamException + { + returnAST = null; + ASTPair currentAST = new ASTPair(); + Spring.Expressions.SpringAST name_AST = null; + + try + { + // for error handling + Spring.Expressions.QualifiedIdentifier tmp92_AST = null; + tmp92_AST = (Spring.Expressions.QualifiedIdentifier) astFactory.create(LT(1), "Spring.Expressions.QualifiedIdentifier"); + astFactory.makeASTRoot(ref currentAST, (AST) tmp92_AST); + match(ID); + { + // ( ... )* + for (;;) + { + if ((tokenSet_17_.member(LA(1)))) + { + { + Spring.Expressions.SpringAST tmp93_AST = null; + tmp93_AST = (Spring.Expressions.SpringAST) astFactory.create(LT(1)); + astFactory.addASTChild(ref currentAST, (AST) tmp93_AST); + match(tokenSet_17_); + } + } + else + { + goto _loop78_breakloop; + } + } + + _loop78_breakloop: ; + } // ( ... )* + name_AST = (Spring.Expressions.SpringAST) currentAST.root; + } + catch (RecognitionException ex) + { + if (0 == inputState.guessing) + { + reportError(ex); + recover(ex, tokenSet_16_); + } + else + { + throw ex; + } + } + + returnAST = name_AST; + } + + public void qualifiedId() //throws RecognitionException, TokenStreamException + { + returnAST = null; + ASTPair currentAST = new ASTPair(); + Spring.Expressions.SpringAST qualifiedId_AST = null; + + try + { + // for error handling + Spring.Expressions.QualifiedIdentifier tmp94_AST = null; + tmp94_AST = (Spring.Expressions.QualifiedIdentifier) astFactory.create(LT(1), "Spring.Expressions.QualifiedIdentifier"); + astFactory.makeASTRoot(ref currentAST, (AST) tmp94_AST); + match(ID); + { + // ( ... )* + for (;;) + { + if ((LA(1) == DOT)) + { + Spring.Expressions.SpringAST tmp95_AST = null; + tmp95_AST = (Spring.Expressions.SpringAST) astFactory.create(LT(1)); + astFactory.addASTChild(ref currentAST, (AST) tmp95_AST); + match(DOT); + Spring.Expressions.SpringAST tmp96_AST = null; + tmp96_AST = (Spring.Expressions.SpringAST) astFactory.create(LT(1)); + astFactory.addASTChild(ref currentAST, (AST) tmp96_AST); + match(ID); + } + else + { + goto _loop114_breakloop; + } + } + + _loop114_breakloop: ; + } // ( ... )* + qualifiedId_AST = (Spring.Expressions.SpringAST) currentAST.root; + } + catch (RecognitionException ex) + { + if (0 == inputState.guessing) + { + reportError(ex); + recover(ex, tokenSet_18_); + } + else + { + throw ex; + } + } + + returnAST = qualifiedId_AST; + } + + public void ctorArgs() //throws RecognitionException, TokenStreamException + { + returnAST = null; + ASTPair currentAST = new ASTPair(); + Spring.Expressions.SpringAST ctorArgs_AST = null; + + try + { + // for error handling + match(LPAREN); + { + if ((tokenSet_9_.member(LA(1)))) + { + namedArgument(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + + { + // ( ... )* + for (;;) + { + if ((LA(1) == COMMA)) + { + match(COMMA); + namedArgument(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + } + else + { + goto _loop107_breakloop; + } + } + + _loop107_breakloop: ; + } // ( ... )* + } + else if ((LA(1) == RPAREN)) + { + } + else + { + throw new NoViableAltException(LT(1), getFilename()); + } + } + match(RPAREN); + ctorArgs_AST = (Spring.Expressions.SpringAST) currentAST.root; + } + catch (RecognitionException ex) + { + if (0 == inputState.guessing) + { + reportError(ex); + recover(ex, tokenSet_2_); + } + else + { + throw ex; + } + } + + returnAST = ctorArgs_AST; + } + + public void argList() //throws RecognitionException, TokenStreamException + { + returnAST = null; + ASTPair currentAST = new ASTPair(); + Spring.Expressions.SpringAST argList_AST = null; + + try + { + // for error handling + { + Spring.Expressions.SpringAST tmp100_AST = null; + tmp100_AST = (Spring.Expressions.SpringAST) astFactory.create(LT(1)); + astFactory.addASTChild(ref currentAST, (AST) tmp100_AST); + match(ID); + { + // ( ... )* + for (;;) + { + if ((LA(1) == COMMA)) + { + match(COMMA); + Spring.Expressions.SpringAST tmp102_AST = null; + tmp102_AST = (Spring.Expressions.SpringAST) astFactory.create(LT(1)); + astFactory.addASTChild(ref currentAST, (AST) tmp102_AST); + match(ID); + } + else + { + goto _loop87_breakloop; + } + } + + _loop87_breakloop: ; + } // ( ... )* + } + if (0 == inputState.guessing) + { + argList_AST = (Spring.Expressions.SpringAST) currentAST.root; + argList_AST = (Spring.Expressions.SpringAST) astFactory.make((AST) (Spring.Expressions.SpringAST) astFactory.create(EXPR, "args"), (AST) argList_AST); + currentAST.root = argList_AST; + if ((null != argList_AST) && (null != argList_AST.getFirstChild())) + currentAST.child = argList_AST.getFirstChild(); + else + currentAST.child = argList_AST; + currentAST.advanceChildToEnd(); + } + + argList_AST = (Spring.Expressions.SpringAST) currentAST.root; + } + catch (RecognitionException ex) + { + if (0 == inputState.guessing) + { + reportError(ex); + recover(ex, tokenSet_19_); + } + else + { + throw ex; + } + } + + returnAST = argList_AST; + } + + public void arrayConstructor() //throws RecognitionException, TokenStreamException + { + returnAST = null; + ASTPair currentAST = new ASTPair(); + Spring.Expressions.SpringAST arrayConstructor_AST = null; + Spring.Expressions.SpringAST type_AST = null; + + try + { + // for error handling + match(LITERAL_new); + qualifiedId(); + if (0 == inputState.guessing) + { + type_AST = (Spring.Expressions.SpringAST) returnAST; + } + + arrayRank(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + + { + if ((LA(1) == LCURLY)) + { + listInitializer(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + } + else if ((tokenSet_2_.member(LA(1)))) + { + } + else + { + throw new NoViableAltException(LT(1), getFilename()); + } + } + if (0 == inputState.guessing) + { + arrayConstructor_AST = (Spring.Expressions.SpringAST) currentAST.root; + arrayConstructor_AST = (Spring.Expressions.SpringAST) astFactory.make((AST) (Spring.Expressions.SpringAST) astFactory.create(EXPR, type_AST.getText(), "Spring.Expressions.ArrayConstructorNode"), (AST) arrayConstructor_AST); + currentAST.root = arrayConstructor_AST; + if ((null != arrayConstructor_AST) && (null != arrayConstructor_AST.getFirstChild())) + currentAST.child = arrayConstructor_AST.getFirstChild(); + else + currentAST.child = arrayConstructor_AST; + currentAST.advanceChildToEnd(); + } + + arrayConstructor_AST = (Spring.Expressions.SpringAST) currentAST.root; + } + catch (RecognitionException ex) + { + if (0 == inputState.guessing) + { + reportError(ex); + recover(ex, tokenSet_2_); + } + else + { + throw ex; + } + } + + returnAST = arrayConstructor_AST; + } + + public void arrayRank() //throws RecognitionException, TokenStreamException + { + returnAST = null; + ASTPair currentAST = new ASTPair(); + Spring.Expressions.SpringAST arrayRank_AST = null; + + try + { + // for error handling + Spring.Expressions.SpringAST tmp104_AST = null; + tmp104_AST = (Spring.Expressions.SpringAST) astFactory.create(LT(1)); + astFactory.makeASTRoot(ref currentAST, (AST) tmp104_AST); + match(LBRACKET); + { + if ((tokenSet_9_.member(LA(1)))) + { + expression(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + + { + // ( ... )* + for (;;) + { + if ((LA(1) == COMMA)) + { + match(COMMA); + expression(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + } + else + { + goto _loop96_breakloop; + } + } + + _loop96_breakloop: ; + } // ( ... )* + } + else if ((LA(1) == RBRACKET)) + { + } + else + { + throw new NoViableAltException(LT(1), getFilename()); + } + } + match(RBRACKET); + arrayRank_AST = (Spring.Expressions.SpringAST) currentAST.root; + } + catch (RecognitionException ex) + { + if (0 == inputState.guessing) + { + reportError(ex); + recover(ex, tokenSet_20_); + } + else + { + throw ex; + } + } + + returnAST = arrayRank_AST; + } + + public void mapEntry() //throws RecognitionException, TokenStreamException + { + returnAST = null; + ASTPair currentAST = new ASTPair(); + Spring.Expressions.SpringAST mapEntry_AST = null; + + try + { + // for error handling + expression(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + + match(COLON); + expression(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + + if (0 == inputState.guessing) + { + mapEntry_AST = (Spring.Expressions.SpringAST) currentAST.root; + mapEntry_AST = (Spring.Expressions.SpringAST) astFactory.make((AST) (Spring.Expressions.SpringAST) astFactory.create(EXPR, "entry", "Spring.Expressions.MapEntryNode"), (AST) mapEntry_AST); + currentAST.root = mapEntry_AST; + if ((null != mapEntry_AST) && (null != mapEntry_AST.getFirstChild())) + currentAST.child = mapEntry_AST.getFirstChild(); + else + currentAST.child = mapEntry_AST; + currentAST.advanceChildToEnd(); + } + + mapEntry_AST = (Spring.Expressions.SpringAST) currentAST.root; + } + catch (RecognitionException ex) + { + if (0 == inputState.guessing) + { + reportError(ex); + recover(ex, tokenSet_21_); + } + else + { + throw ex; + } + } + + returnAST = mapEntry_AST; + } + + public void namedArgument() //throws RecognitionException, TokenStreamException + { + returnAST = null; + ASTPair currentAST = new ASTPair(); + Spring.Expressions.SpringAST namedArgument_AST = null; + + try + { + // for error handling + bool synPredMatched111 = false; + if (((LA(1) == ID) && (LA(2) == ASSIGN))) + { + int _m111 = mark(); + synPredMatched111 = true; + inputState.guessing++; + try + { + { + match(ID); + match(ASSIGN); + } + } + catch (RecognitionException) + { + synPredMatched111 = false; + } + + rewind(_m111); + inputState.guessing--; + } + + if (synPredMatched111) + { + Spring.Expressions.NamedArgumentNode tmp108_AST = null; + tmp108_AST = (Spring.Expressions.NamedArgumentNode) astFactory.create(LT(1), "Spring.Expressions.NamedArgumentNode"); + astFactory.makeASTRoot(ref currentAST, (AST) tmp108_AST); + match(ID); + match(ASSIGN); + expression(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + + namedArgument_AST = (Spring.Expressions.SpringAST) currentAST.root; + } + else if ((tokenSet_9_.member(LA(1))) && (tokenSet_22_.member(LA(2)))) + { + argument(); + if (0 == inputState.guessing) + { + astFactory.addASTChild(ref currentAST, (AST) returnAST); + } + + namedArgument_AST = (Spring.Expressions.SpringAST) currentAST.root; + } + else + { + throw new NoViableAltException(LT(1), getFilename()); + } + } + catch (RecognitionException ex) + { + if (0 == inputState.guessing) + { + reportError(ex); + recover(ex, tokenSet_23_); + } + else + { + throw ex; + } + } + + returnAST = namedArgument_AST; + } + + public void boolLiteral() //throws RecognitionException, TokenStreamException + { + returnAST = null; + ASTPair currentAST = new ASTPair(); + Spring.Expressions.SpringAST boolLiteral_AST = null; + + try + { + // for error handling + if ((LA(1) == TRUE)) + { + Spring.Expressions.BooleanLiteralNode tmp110_AST = null; + tmp110_AST = (Spring.Expressions.BooleanLiteralNode) astFactory.create(LT(1), "Spring.Expressions.BooleanLiteralNode"); + astFactory.addASTChild(ref currentAST, (AST) tmp110_AST); + match(TRUE); + boolLiteral_AST = (Spring.Expressions.SpringAST) currentAST.root; + } + else if ((LA(1) == FALSE)) + { + Spring.Expressions.BooleanLiteralNode tmp111_AST = null; + tmp111_AST = (Spring.Expressions.BooleanLiteralNode) astFactory.create(LT(1), "Spring.Expressions.BooleanLiteralNode"); + astFactory.addASTChild(ref currentAST, (AST) tmp111_AST); + match(FALSE); + boolLiteral_AST = (Spring.Expressions.SpringAST) currentAST.root; + } + else + { + throw new NoViableAltException(LT(1), getFilename()); + } + } + catch (RecognitionException ex) + { + if (0 == inputState.guessing) + { + reportError(ex); + recover(ex, tokenSet_2_); + } + else + { + throw ex; + } + } + + returnAST = boolLiteral_AST; + } + + public new Spring.Expressions.SpringAST getAST() + { + return (Spring.Expressions.SpringAST) returnAST; + } + + private void initializeFactory() + { + if (astFactory == null) + { + astFactory = new ASTFactory("Spring.Expressions.SpringAST"); + } + + initializeASTFactory(astFactory); + } + + static public void initializeASTFactory(ASTFactory factory) + { + factory.setMaxNodeType(71); + } + + public static readonly string[] tokenNames_ = new string[] { @"""<0>""", @"""EOF""", @"""<2>""", @"""NULL_TREE_LOOKAHEAD""", @"""EXPR""", @"""OPERAND""", @"""false""", @"""true""", @"""and""", @"""or""", @"""xor""", @"""in""", @"""is""", @"""between""", @"""like""", @"""matches""", @"""null""", @"""LPAREN""", @"""SEMI""", @"""RPAREN""", @"""ASSIGN""", @"""DEFAULT""", @"""QMARK""", @"""COLON""", @"""PLUS""", @"""MINUS""", @"""STAR""", @"""DIV""", @"""MOD""", @"""POWER""", @"""BANG""", @"""DOT""", @"""POUND""", @"""ID""", @"""DOLLAR""", @"""COMMA""", @"""AT""", @"""LBRACKET""", @"""RBRACKET""", @"""PROJECT""", @"""RCURLY""", @"""SELECT""", @"""SELECT_FIRST""", @"""SELECT_LAST""", @"""TYPE""", @"""QUOTE""", @"""STRING_LITERAL""", @"""LAMBDA""", @"""PIPE""", @"""new""", @"""LCURLY""", @"""INTEGER_LITERAL""", @"""HEXADECIMAL_INTEGER_LITERAL""", @"""REAL_LITERAL""", @"""EQUAL""", @"""NOT_EQUAL""", @"""LESS_THAN""", @"""LESS_THAN_OR_EQUAL""", @"""GREATER_THAN""", @"""GREATER_THAN_OR_EQUAL""", @"""WS""", @"""BACKTICK""", @"""BACKSLASH""", @"""DOT_ESCAPED""", @"""APOS""", @"""NUMERIC_LITERAL""", @"""DECIMAL_DIGIT""", @"""INTEGER_TYPE_SUFFIX""", @"""HEX_DIGIT""", @"""EXPONENT_PART""", @"""SIGN""", @"""REAL_TYPE_SUFFIX""" }; + + private static long[] mk_tokenSet_0_() + { + long[] data = { 2L, 0L }; + return data; + } + + public static readonly BitSet tokenSet_0_ = new BitSet(mk_tokenSet_0_()); + + private static long[] mk_tokenSet_1_() + { + long[] data = { 1408758448130L, 0L }; + return data; + } + + public static readonly BitSet tokenSet_1_ = new BitSet(mk_tokenSet_1_()); + + private static long[] mk_tokenSet_2_() + { + long[] data = { 1134924607015288578L, 0L }; + return data; + } + + public static readonly BitSet tokenSet_2_ = new BitSet(mk_tokenSet_2_()); + + private static long[] mk_tokenSet_3_() + { + long[] data = { 1408765788162L, 0L }; + return data; + } + + public static readonly BitSet tokenSet_3_ = new BitSet(mk_tokenSet_3_()); + + private static long[] mk_tokenSet_4_() + { + long[] data = { 1408765788674L, 0L }; + return data; + } + + public static readonly BitSet tokenSet_4_ = new BitSet(mk_tokenSet_4_()); + + private static long[] mk_tokenSet_5_() + { + long[] data = { 1408765789698L, 0L }; + return data; + } + + public static readonly BitSet tokenSet_5_ = new BitSet(mk_tokenSet_5_()); + + private static long[] mk_tokenSet_6_() + { + long[] data = { 1134907106097428480L, 0L }; + return data; + } + + public static readonly BitSet tokenSet_6_ = new BitSet(mk_tokenSet_6_()); + + private static long[] mk_tokenSet_7_() + { + long[] data = { 1408765789954L, 0L }; + return data; + } + + public static readonly BitSet tokenSet_7_ = new BitSet(mk_tokenSet_7_()); + + private static long[] mk_tokenSet_8_() + { + long[] data = { 1134908514863218434L, 0L }; + return data; + } + + public static readonly BitSet tokenSet_8_ = new BitSet(mk_tokenSet_8_()); + + private static long[] mk_tokenSet_9_() + { + long[] data = { 17696327240712384L, 0L }; + return data; + } -} + public static readonly BitSet tokenSet_9_ = new BitSet(mk_tokenSet_9_()); + + private static long[] mk_tokenSet_10_() + { + long[] data = { 1134908514913550082L, 0L }; + return data; + } + + public static readonly BitSet tokenSet_10_ = new BitSet(mk_tokenSet_10_()); + + private static long[] mk_tokenSet_11_() + { + long[] data = { 1134908515383312130L, 0L }; + return data; + } + + public static readonly BitSet tokenSet_11_ = new BitSet(mk_tokenSet_11_()); + + private static long[] mk_tokenSet_12_() + { + long[] data = { 17696326116638912L, 0L }; + return data; + } + + public static readonly BitSet tokenSet_12_ = new BitSet(mk_tokenSet_12_()); + + private static long[] mk_tokenSet_13_() + { + long[] data = { 1134908515920183042L, 0L }; + return data; + } + + public static readonly BitSet tokenSet_13_ = new BitSet(mk_tokenSet_13_()); + + private static long[] mk_tokenSet_14_() + { + long[] data = { 16091095105536L, 0L }; + return data; + } + + public static readonly BitSet tokenSet_14_ = new BitSet(mk_tokenSet_14_()); + + private static long[] mk_tokenSet_15_() + { + long[] data = { 309238169600L, 0L }; + return data; + } + + public static readonly BitSet tokenSet_15_ = new BitSet(mk_tokenSet_15_()); + + private static long[] mk_tokenSet_16_() + { + long[] data = { 8912896L, 0L }; + return data; + } + + public static readonly BitSet tokenSet_16_ = new BitSet(mk_tokenSet_16_()); + + private static long[] mk_tokenSet_17_() + { + long[] data = { -35184381001744L, 255L, 0L, 0L }; + return data; + } + + public static readonly BitSet tokenSet_17_ = new BitSet(mk_tokenSet_17_()); + + private static long[] mk_tokenSet_18_() + { + long[] data = { 412316991488L, 0L }; + return data; + } + + public static readonly BitSet tokenSet_18_ = new BitSet(mk_tokenSet_18_()); + + private static long[] mk_tokenSet_19_() + { + long[] data = { 281474976710656L, 0L }; + return data; + } + + public static readonly BitSet tokenSet_19_ = new BitSet(mk_tokenSet_19_()); + + private static long[] mk_tokenSet_20_() + { + long[] data = { 1136050506922131202L, 0L }; + return data; + } + + public static readonly BitSet tokenSet_20_ = new BitSet(mk_tokenSet_20_()); + + private static long[] mk_tokenSet_21_() + { + long[] data = { 1133871366144L, 0L }; + return data; + } + + public static readonly BitSet tokenSet_21_ = new BitSet(mk_tokenSet_21_()); + + private static long[] mk_tokenSet_22_() + { + long[] data = { 1152884945836572608L, 0L }; + return data; + } + + public static readonly BitSet tokenSet_22_ = new BitSet(mk_tokenSet_22_()); + + private static long[] mk_tokenSet_23_() + { + long[] data = { 34360262656L, 0L }; + return data; + } + + public static readonly BitSet tokenSet_23_ = new BitSet(mk_tokenSet_23_()); } diff --git a/src/Spring/Spring.Core/Expressions/Parser/ExpressionParserTokenTypes.cs b/src/Spring/Spring.Core/Expressions/Parser/ExpressionParserTokenTypes.cs index 7d3fb74d..4a7f760d 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/ExpressionParserTokenTypes.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/ExpressionParserTokenTypes.cs @@ -1,79 +1,77 @@ // $ANTLR 2.7.6 (2005-12-22): "Expression.g" -> "ExpressionLexer.cs"$ -namespace Spring.Expressions.Parser +namespace Spring.Expressions.Parser; + +public class ExpressionParserTokenTypes { - public class ExpressionParserTokenTypes - { - public const int EOF = 1; - public const int NULL_TREE_LOOKAHEAD = 3; - public const int EXPR = 4; - public const int OPERAND = 5; - public const int FALSE = 6; - public const int TRUE = 7; - public const int AND = 8; - public const int OR = 9; - public const int XOR = 10; - public const int IN = 11; - public const int IS = 12; - public const int BETWEEN = 13; - public const int LIKE = 14; - public const int MATCHES = 15; - public const int NULL_LITERAL = 16; - public const int LPAREN = 17; - public const int SEMI = 18; - public const int RPAREN = 19; - public const int ASSIGN = 20; - public const int DEFAULT = 21; - public const int QMARK = 22; - public const int COLON = 23; - public const int PLUS = 24; - public const int MINUS = 25; - public const int STAR = 26; - public const int DIV = 27; - public const int MOD = 28; - public const int POWER = 29; - public const int BANG = 30; - public const int DOT = 31; - public const int POUND = 32; - public const int ID = 33; - public const int DOLLAR = 34; - public const int COMMA = 35; - public const int AT = 36; - public const int LBRACKET = 37; - public const int RBRACKET = 38; - public const int PROJECT = 39; - public const int RCURLY = 40; - public const int SELECT = 41; - public const int SELECT_FIRST = 42; - public const int SELECT_LAST = 43; - public const int TYPE = 44; - public const int QUOTE = 45; - public const int STRING_LITERAL = 46; - public const int LAMBDA = 47; - public const int PIPE = 48; - public const int LITERAL_new = 49; - public const int LCURLY = 50; - public const int INTEGER_LITERAL = 51; - public const int HEXADECIMAL_INTEGER_LITERAL = 52; - public const int REAL_LITERAL = 53; - public const int EQUAL = 54; - public const int NOT_EQUAL = 55; - public const int LESS_THAN = 56; - public const int LESS_THAN_OR_EQUAL = 57; - public const int GREATER_THAN = 58; - public const int GREATER_THAN_OR_EQUAL = 59; - public const int WS = 60; - public const int BACKTICK = 61; - public const int BACKSLASH = 62; - public const int DOT_ESCAPED = 63; - public const int APOS = 64; - public const int NUMERIC_LITERAL = 65; - public const int DECIMAL_DIGIT = 66; - public const int INTEGER_TYPE_SUFFIX = 67; - public const int HEX_DIGIT = 68; - public const int EXPONENT_PART = 69; - public const int SIGN = 70; - public const int REAL_TYPE_SUFFIX = 71; - - } + public const int EOF = 1; + public const int NULL_TREE_LOOKAHEAD = 3; + public const int EXPR = 4; + public const int OPERAND = 5; + public const int FALSE = 6; + public const int TRUE = 7; + public const int AND = 8; + public const int OR = 9; + public const int XOR = 10; + public const int IN = 11; + public const int IS = 12; + public const int BETWEEN = 13; + public const int LIKE = 14; + public const int MATCHES = 15; + public const int NULL_LITERAL = 16; + public const int LPAREN = 17; + public const int SEMI = 18; + public const int RPAREN = 19; + public const int ASSIGN = 20; + public const int DEFAULT = 21; + public const int QMARK = 22; + public const int COLON = 23; + public const int PLUS = 24; + public const int MINUS = 25; + public const int STAR = 26; + public const int DIV = 27; + public const int MOD = 28; + public const int POWER = 29; + public const int BANG = 30; + public const int DOT = 31; + public const int POUND = 32; + public const int ID = 33; + public const int DOLLAR = 34; + public const int COMMA = 35; + public const int AT = 36; + public const int LBRACKET = 37; + public const int RBRACKET = 38; + public const int PROJECT = 39; + public const int RCURLY = 40; + public const int SELECT = 41; + public const int SELECT_FIRST = 42; + public const int SELECT_LAST = 43; + public const int TYPE = 44; + public const int QUOTE = 45; + public const int STRING_LITERAL = 46; + public const int LAMBDA = 47; + public const int PIPE = 48; + public const int LITERAL_new = 49; + public const int LCURLY = 50; + public const int INTEGER_LITERAL = 51; + public const int HEXADECIMAL_INTEGER_LITERAL = 52; + public const int REAL_LITERAL = 53; + public const int EQUAL = 54; + public const int NOT_EQUAL = 55; + public const int LESS_THAN = 56; + public const int LESS_THAN_OR_EQUAL = 57; + public const int GREATER_THAN = 58; + public const int GREATER_THAN_OR_EQUAL = 59; + public const int WS = 60; + public const int BACKTICK = 61; + public const int BACKSLASH = 62; + public const int DOT_ESCAPED = 63; + public const int APOS = 64; + public const int NUMERIC_LITERAL = 65; + public const int DECIMAL_DIGIT = 66; + public const int INTEGER_TYPE_SUFFIX = 67; + public const int HEX_DIGIT = 68; + public const int EXPONENT_PART = 69; + public const int SIGN = 70; + public const int REAL_TYPE_SUFFIX = 71; } diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/ANTLRException.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/ANTLRException.cs index 36bfc0b8..f1c084da 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/ANTLRException.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/ANTLRException.cs @@ -1,35 +1,33 @@ -namespace Spring.Expressions.Parser.antlr +namespace Spring.Expressions.Parser.antlr; + +/*ANTLR Translator Generator + * Project led by Terence Parr at http://www.jGuru.com + * Software rights: http://www.antlr.org/license.html + * + * $Id:$ + */ + +// +// ANTLR C# Code Generator by Micheal Jordan +// Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com +// Anthony Oguntimehin +// +// With many thanks to Eric V. Smith from the ANTLR list. +// +using System; + +[Serializable] +public class ANTLRException : Exception { - /*ANTLR Translator Generator - * Project led by Terence Parr at http://www.jGuru.com - * Software rights: http://www.antlr.org/license.html - * - * $Id:$ - */ + public ANTLRException() : base() + { + } - // - // ANTLR C# Code Generator by Micheal Jordan - // Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com - // Anthony Oguntimehin - // - // With many thanks to Eric V. Smith from the ANTLR list. - // - - using System; - - [Serializable] - public class ANTLRException : Exception - { - public ANTLRException() : base() - { - } + public ANTLRException(string s) : base(s) + { + } - public ANTLRException(string s) : base(s) - { - } - - public ANTLRException(string s, Exception inner) : base(s, inner) - { - } - } + public ANTLRException(string s, Exception inner) : base(s, inner) + { + } } diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/ANTLRPanicException.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/ANTLRPanicException.cs index e88c020a..09a8082b 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/ANTLRPanicException.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/ANTLRPanicException.cs @@ -1,35 +1,33 @@ -namespace Spring.Expressions.Parser.antlr +namespace Spring.Expressions.Parser.antlr; + +/*ANTLR Translator Generator + * Project led by Terence Parr at http://www.jGuru.com + * Software rights: http://www.antlr.org/license.html + * + * $Id:$ + */ + +// +// ANTLR C# Code Generator by Micheal Jordan +// Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com +// Anthony Oguntimehin +// +// With many thanks to Eric V. Smith from the ANTLR list. +// +using System; + +[Serializable] +public class ANTLRPanicException : ANTLRException { - /*ANTLR Translator Generator - * Project led by Terence Parr at http://www.jGuru.com - * Software rights: http://www.antlr.org/license.html - * - * $Id:$ - */ + public ANTLRPanicException() : base() + { + } - // - // ANTLR C# Code Generator by Micheal Jordan - // Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com - // Anthony Oguntimehin - // - // With many thanks to Eric V. Smith from the ANTLR list. - // - - using System; - - [Serializable] - public class ANTLRPanicException : ANTLRException - { - public ANTLRPanicException() : base() - { - } + public ANTLRPanicException(string s) : base(s) + { + } - public ANTLRPanicException(string s) : base(s) - { - } - - public ANTLRPanicException(string s, Exception inner) : base(s, inner) - { - } - } + public ANTLRPanicException(string s, Exception inner) : base(s, inner) + { + } } diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/ASTFactory.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/ASTFactory.cs index 20d6944f..4986e612 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/ASTFactory.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/ASTFactory.cs @@ -1,706 +1,717 @@ using System.Collections; +using Assembly = System.Reflection.Assembly; +using Debug = System.Diagnostics.Debug; +using AST = Spring.Expressions.Parser.antlr.collections.AST; +using ASTArray = Spring.Expressions.Parser.antlr.collections.impl.ASTArray; -using Assembly = System.Reflection.Assembly; -using Debug = System.Diagnostics.Debug; -using AST = Spring.Expressions.Parser.antlr.collections.AST; -using ASTArray = Spring.Expressions.Parser.antlr.collections.impl.ASTArray; +namespace Spring.Expressions.Parser.antlr; +/*ANTLR Translator Generator + * Project led by Terence Parr at http://www.jGuru.com + * Software rights: http://www.antlr.org/license.html + * + * $Id:$ + */ -namespace Spring.Expressions.Parser.antlr +// +// ANTLR C# Code Generator by Micheal Jordan +// Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com +// Anthony Oguntimehin +// +// With many thanks to Eric V. Smith from the ANTLR list. +// + +// HISTORY: +// +// 19-Aug-2002 kunle Augmented the basic flexibility of the default ASTFactory with a map +// of TokenID-to-NodeTypeName. It's now a proper GoF-style Factory ;-) +// + +/// +/// AST Support code shared by TreeParser and Parser. +/// +/// +/// +/// We use delegation to share code (and have only one +/// bit of code to maintain) rather than subclassing +/// or superclassing (forces AST support code to be +/// loaded even when you don't want to do AST stuff). +/// +/// +/// Typically, is used to specify the +/// homogeneous type of node to create, but you can override +/// to make heterogeneous nodes etc... +/// +/// +public class ASTFactory { - /*ANTLR Translator Generator - * Project led by Terence Parr at http://www.jGuru.com - * Software rights: http://www.antlr.org/license.html - * - * $Id:$ - */ + //--------------------------------------------------------------------- + // CONSTRUCTORS + //--------------------------------------------------------------------- - // - // ANTLR C# Code Generator by Micheal Jordan - // Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com - // Anthony Oguntimehin - // - // With many thanks to Eric V. Smith from the ANTLR list. - // + /// + /// Constructs an ASTFactory with the default AST node type of + /// . + /// + public ASTFactory() : this(typeof(antlr.CommonAST)) + { + } + /// + /// Constructs an ASTFactory and use the specified AST node type + /// as the default. + /// + /// + /// Name of default AST node type for this factory. + /// + public ASTFactory(string nodeTypeName) + : this(loadNodeTypeObject(nodeTypeName)) + { + } - // HISTORY: - // - // 19-Aug-2002 kunle Augmented the basic flexibility of the default ASTFactory with a map - // of TokenID-to-NodeTypeName. It's now a proper GoF-style Factory ;-) - // + /// + /// Constructs an ASTFactory and use the specified AST node type + /// as the default. + /// + /// + /// MetaType of default AST node type for this factory. + /// + public ASTFactory(Type nodeType) + { + heteroList_ = new FactoryEntry[Token.MIN_USER_TYPE + 1]; + defaultASTNodeTypeObject_ = nodeType; + defaultCreator_ = null; + typename2creator_ = new Hashtable(32, (float) 0.3); + typename2creator_[typeof(antlr.CommonAST).FullName] = CommonAST.Creator; + typename2creator_[typeof(antlr.CommonASTWithHiddenTokens).FullName] = CommonASTWithHiddenTokens.Creator; + } - /// - /// AST Support code shared by TreeParser and Parser. - /// - /// - /// - /// We use delegation to share code (and have only one - /// bit of code to maintain) rather than subclassing - /// or superclassing (forces AST support code to be - /// loaded even when you don't want to do AST stuff). - /// - /// - /// Typically, is used to specify the - /// homogeneous type of node to create, but you can override - /// to make heterogeneous nodes etc... - /// - /// - public class ASTFactory - { - //--------------------------------------------------------------------- - // CONSTRUCTORS - //--------------------------------------------------------------------- + //--------------------------------------------------------------------- + // DATA MEMBERS + //--------------------------------------------------------------------- - /// - /// Constructs an ASTFactory with the default AST node type of - /// . - /// - public ASTFactory() : this(typeof(antlr.CommonAST)) - { - } + /// + /// Stores the Type of the default AST node class to be used during tree construction. + /// + protected Type defaultASTNodeTypeObject_; - /// - /// Constructs an ASTFactory and use the specified AST node type - /// as the default. - /// - /// - /// Name of default AST node type for this factory. - /// - public ASTFactory(string nodeTypeName) - : this( loadNodeTypeObject(nodeTypeName) ) - { - } + protected ASTNodeCreator defaultCreator_; - /// - /// Constructs an ASTFactory and use the specified AST node type - /// as the default. - /// - /// - /// MetaType of default AST node type for this factory. - /// - public ASTFactory(Type nodeType) - { - heteroList_ = new FactoryEntry[Token.MIN_USER_TYPE+1]; - defaultASTNodeTypeObject_ = nodeType; - defaultCreator_ = null; - typename2creator_ = new Hashtable(32, (float) 0.3); - typename2creator_[typeof(antlr.CommonAST).FullName] = CommonAST.Creator; - typename2creator_[typeof(antlr.CommonASTWithHiddenTokens).FullName] = CommonASTWithHiddenTokens.Creator; + /// + /// Stores the mapping between custom AST NodeTypes and their NodeTypeName/NodeTypeClass + /// and ASTNodeCreator. + /// + protected FactoryEntry[] heteroList_; - } + /// + /// Stores the mapping between AST node typenames and their token ID. + /// + protected Hashtable typename2creator_; - //--------------------------------------------------------------------- - // DATA MEMBERS - //--------------------------------------------------------------------- + //--------------------------------------------------------------------- + // FUNCTION MEMBERS + //--------------------------------------------------------------------- - /// - /// Stores the Type of the default AST node class to be used during tree construction. - /// - protected Type defaultASTNodeTypeObject_; - protected ASTNodeCreator defaultCreator_; + /// + /// Specify an "override" for the type created for + /// the specified Token type. + /// + /// + /// This method is useful for situations that ANTLR cannot oridinarily deal + /// with (i.e., when you create a token based upon a nonliteral token symbol + /// like #[LT(1)]. This is a runtime value and ANTLR cannot determine the token + /// type (and hence the AST) statically. + /// + /// Token type to override. + /// + /// Fully qualified AST typename (or null to specify + /// the factory's default AST type). + /// + public void setTokenTypeASTNodeType(int tokenType, string NodeTypeName) + { + // check validity of arguments... + if (tokenType < Token.MIN_USER_TYPE) + throw new ANTLRException("Internal parser error: Cannot change AST Node Type for Token ID '" + tokenType + "'"); - /// - /// Stores the mapping between custom AST NodeTypes and their NodeTypeName/NodeTypeClass - /// and ASTNodeCreator. - /// - protected FactoryEntry[] heteroList_; + // resize up to and including 'type' and initialize any gaps to default + // factory. + if (tokenType > (heteroList_.Length + 1)) + setMaxNodeType(tokenType); + // And add new thing.. + if (heteroList_[tokenType] == null) + heteroList_[tokenType] = new FactoryEntry(loadNodeTypeObject(NodeTypeName)); + else + heteroList_[tokenType].NodeTypeObject = loadNodeTypeObject(NodeTypeName); + } - /// - /// Stores the mapping between AST node typenames and their token ID. - /// - protected Hashtable typename2creator_; + /// + /// Register an AST Node Type for a given Token type ID. + /// + /// The Token type ID. + /// The AST Node Type to register. + [Obsolete("Replaced by setTokenTypeASTNodeType(int, string) since version 2.7.2.6", true)] + public void registerFactory(int NodeType, string NodeTypeName) + { + setTokenTypeASTNodeType(NodeType, NodeTypeName); + } - //--------------------------------------------------------------------- - // FUNCTION MEMBERS - //--------------------------------------------------------------------- + /// + /// Register an ASTNodeCreator for a given Token type ID. + /// + /// The Token type ID. + /// The creater to register. + public void setTokenTypeASTNodeCreator(int NodeType, ASTNodeCreator creator) + { + // check validity of arguments... + if (NodeType < Token.MIN_USER_TYPE) + throw new ANTLRException("Internal parser error: Cannot change AST Node Type for Token ID '" + NodeType + "'"); - /// - /// Specify an "override" for the type created for - /// the specified Token type. - /// - /// - /// This method is useful for situations that ANTLR cannot oridinarily deal - /// with (i.e., when you create a token based upon a nonliteral token symbol - /// like #[LT(1)]. This is a runtime value and ANTLR cannot determine the token - /// type (and hence the AST) statically. - /// - /// Token type to override. - /// - /// Fully qualified AST typename (or null to specify - /// the factory's default AST type). - /// - public void setTokenTypeASTNodeType(int tokenType, string NodeTypeName) - { - // check validity of arguments... - if( tokenType < Token.MIN_USER_TYPE ) - throw new ANTLRException("Internal parser error: Cannot change AST Node Type for Token ID '" + tokenType + "'"); + // resize up to and including 'type' and initialize any gaps to default + // factory. + if (NodeType > (heteroList_.Length + 1)) + setMaxNodeType(NodeType); + // And add new thing.. + if (heteroList_[NodeType] == null) + heteroList_[NodeType] = new FactoryEntry(creator); + else + heteroList_[NodeType].Creator = creator; - // resize up to and including 'type' and initialize any gaps to default - // factory. - if (tokenType > (heteroList_.Length+1)) - setMaxNodeType(tokenType); - // And add new thing.. - if (heteroList_[tokenType] == null) - heteroList_[tokenType] = new FactoryEntry(loadNodeTypeObject(NodeTypeName)); - else - heteroList_[tokenType].NodeTypeObject = loadNodeTypeObject(NodeTypeName); - } + //typename2creator_[NodeType.ToString()] = creator; + typename2creator_[creator.ASTNodeTypeName] = creator; + } - /// - /// Register an AST Node Type for a given Token type ID. - /// - /// The Token type ID. - /// The AST Node Type to register. - [Obsolete("Replaced by setTokenTypeASTNodeType(int, string) since version 2.7.2.6", true)] - public void registerFactory(int NodeType, string NodeTypeName) - { - setTokenTypeASTNodeType(NodeType, NodeTypeName); - } + /// + /// Register an ASTNodeCreator to be used for creating node by default. + /// + /// The ASTNodeCreator. + public void setASTNodeCreator(ASTNodeCreator creator) + { + defaultCreator_ = creator; + } - /// - /// Register an ASTNodeCreator for a given Token type ID. - /// - /// The Token type ID. - /// The creater to register. - public void setTokenTypeASTNodeCreator(int NodeType, ASTNodeCreator creator) - { - // check validity of arguments... - if( NodeType < Token.MIN_USER_TYPE ) - throw new ANTLRException("Internal parser error: Cannot change AST Node Type for Token ID '" + NodeType + "'"); + /// + /// Pre-expands the internal list of TokenTypeID-to-ASTNodeType mappings + /// to the specified size. + /// This is primarily a convenience method that can be used to prevent + /// unnecessary and costly re-org of the mappings list. + /// + /// Maximum Token Type ID. + public void setMaxNodeType(int NodeType) + { + //Debug.WriteLine(this, "NodeType = " + NodeType + " and NodeList.Length = " + nodeTypeList_.Length); + if (heteroList_ == null) + { + heteroList_ = new FactoryEntry[NodeType + 1]; + } + else + { + int length = heteroList_.Length; - // resize up to and including 'type' and initialize any gaps to default - // factory. - if (NodeType > (heteroList_.Length+1)) - setMaxNodeType(NodeType); - // And add new thing.. - if (heteroList_[NodeType] == null) - heteroList_[NodeType] = new FactoryEntry(creator); - else - heteroList_[NodeType].Creator = creator; + if (NodeType >= length) + { + FactoryEntry[] newList = new FactoryEntry[NodeType + 1]; + Array.Copy(heteroList_, 0, newList, 0, length); + heteroList_ = newList; + } + else if (NodeType < length) + { + FactoryEntry[] newList = new FactoryEntry[NodeType + 1]; + Array.Copy(heteroList_, 0, newList, 0, (NodeType + 1)); + heteroList_ = newList; + } + } + //Debug.WriteLine(this, "NodeType = " + NodeType + " and NodeList.Length = " + nodeTypeList_.Length); + } - //typename2creator_[NodeType.ToString()] = creator; - typename2creator_[creator.ASTNodeTypeName] = creator; - } + /// + /// Add a child to the current AST + /// + /// The AST to add a child to + /// The child AST to be added + public virtual void addASTChild(ref ASTPair currentAST, AST child) + { + if (child != null) + { + if (currentAST.root == null) + { + // Make new child the current root + currentAST.root = child; + } + else + { + if (currentAST.child == null) + { + // Add new child to current root + currentAST.root.setFirstChild(child); + } + else + { + currentAST.child.setNextSibling(child); + } + } - /// - /// Register an ASTNodeCreator to be used for creating node by default. - /// - /// The ASTNodeCreator. - public void setASTNodeCreator(ASTNodeCreator creator) - { - defaultCreator_ = creator; - } + // Make new child the current child + currentAST.child = child; + currentAST.advanceChildToEnd(); + } + } - /// - /// Pre-expands the internal list of TokenTypeID-to-ASTNodeType mappings - /// to the specified size. - /// This is primarily a convenience method that can be used to prevent - /// unnecessary and costly re-org of the mappings list. - /// - /// Maximum Token Type ID. - public void setMaxNodeType( int NodeType ) - { - //Debug.WriteLine(this, "NodeType = " + NodeType + " and NodeList.Length = " + nodeTypeList_.Length); - if (heteroList_ == null) - { - heteroList_ = new FactoryEntry[NodeType+1]; - } - else - { - int length = heteroList_.Length; + /// + /// Creates a new uninitialized AST node. Since a specific AST Node Type + /// wasn't indicated, the new AST node is created using the current default + /// AST Node type - + /// + /// An uninitialized AST node object. + public virtual AST create() + { + AST newNode; - if ( NodeType >= length ) - { - FactoryEntry[] newList = new FactoryEntry[NodeType+1]; - Array.Copy(heteroList_, 0, newList, 0, length); - heteroList_ = newList; - } - else if ( NodeType < length ) - { - FactoryEntry[] newList = new FactoryEntry[NodeType+1]; - Array.Copy(heteroList_, 0, newList, 0, (NodeType+1)); - heteroList_ = newList; - } - } - //Debug.WriteLine(this, "NodeType = " + NodeType + " and NodeList.Length = " + nodeTypeList_.Length); - } + if (defaultCreator_ == null) + newNode = createFromNodeTypeObject(defaultASTNodeTypeObject_); + else + newNode = defaultCreator_.Create(); - /// - /// Add a child to the current AST - /// - /// The AST to add a child to - /// The child AST to be added - public virtual void addASTChild(ref ASTPair currentAST, AST child) - { - if (child != null) - { - if (currentAST.root == null) - { - // Make new child the current root - currentAST.root = child; - } - else - { - if (currentAST.child == null) - { - // Add new child to current root - currentAST.root.setFirstChild(child); - } - else - { - currentAST.child.setNextSibling(child); - } - } - // Make new child the current child - currentAST.child = child; - currentAST.advanceChildToEnd(); - } - } + return newNode; + } - /// - /// Creates a new uninitialized AST node. Since a specific AST Node Type - /// wasn't indicated, the new AST node is created using the current default - /// AST Node type - - /// - /// An uninitialized AST node object. - public virtual AST create() - { - AST newNode; + /// + /// Creates and initializes a new AST node using the specified Token Type ID. + /// The used for creating this new AST node is + /// determined by the following: + /// + /// the current TokenTypeID-to-ASTNodeType mapping (if any) or, + /// the otherwise + /// + /// + /// Token type ID to be used to create new AST Node. + /// An initialized AST node object. + public virtual AST create(int type) + { + AST newNode = createFromNodeType(type); + newNode.initialize(type, ""); + return newNode; + } - if (defaultCreator_ == null) - newNode = createFromNodeTypeObject(defaultASTNodeTypeObject_); - else - newNode = defaultCreator_.Create(); + /// + /// Creates and initializes a new AST node using the specified Token Type ID. + /// The used for creating this new AST node is + /// determined by the following: + /// + /// the current TokenTypeID-to-ASTNodeType mapping (if any) or, + /// the otherwise + /// + /// + /// Token type ID to be used to create new AST Node. + /// Text for initializing the new AST Node. + /// An initialized AST node object. + public virtual AST create(int type, string txt) + { + AST newNode = createFromNodeType(type); + newNode.initialize(type, txt); + return newNode; + } - return newNode; - } + /// + /// Creates a new AST node using the specified AST Node Type name. Once created, + /// the new AST node is initialized with the specified Token type ID and string. + /// The used for creating this new AST node is + /// determined solely by ASTNodeTypeName. + /// The AST Node type must have a default/parameterless constructor. + /// + /// Token type ID to be used to create new AST Node. + /// Text for initializing the new AST Node. + /// Fully qualified name of the Type to be used for creating the new AST Node. + /// An initialized AST node object. + public virtual AST create(int type, string txt, string ASTNodeTypeName) + { + AST newNode = createFromNodeName(ASTNodeTypeName); + newNode.initialize(type, txt); + return newNode; + } - /// - /// Creates and initializes a new AST node using the specified Token Type ID. - /// The used for creating this new AST node is - /// determined by the following: - /// - /// the current TokenTypeID-to-ASTNodeType mapping (if any) or, - /// the otherwise - /// - /// - /// Token type ID to be used to create new AST Node. - /// An initialized AST node object. - public virtual AST create(int type) - { - AST newNode = createFromNodeType(type); - newNode.initialize(type, ""); - return newNode; - } + /// + /// Creates a new AST node using the specified AST Node Type name. + /// + /// Token instance to be used to initialize the new AST Node. + /// + /// Fully qualified name of the Type to be used for creating the new AST Node. + /// + /// A newly created and initialized AST node object. + /// + /// Once created, the new AST node is initialized with the specified Token + /// instance. The used for creating this new AST + /// node is determined solely by ASTNodeTypeName. + /// The AST Node type must have a default/parameterless constructor. + /// + public virtual AST create(IToken tok, string ASTNodeTypeName) + { + AST newNode = createFromNodeName(ASTNodeTypeName); + newNode.initialize(tok); + return newNode; + } - /// - /// Creates and initializes a new AST node using the specified Token Type ID. - /// The used for creating this new AST node is - /// determined by the following: - /// - /// the current TokenTypeID-to-ASTNodeType mapping (if any) or, - /// the otherwise - /// - /// - /// Token type ID to be used to create new AST Node. - /// Text for initializing the new AST Node. - /// An initialized AST node object. - public virtual AST create(int type, string txt) - { - AST newNode = createFromNodeType(type); - newNode.initialize(type, txt); - return newNode; - } + /// + /// Creates and initializes a new AST node using the specified AST Node instance. + /// the new AST node is initialized with the specified Token type ID and string. + /// The used for creating this new AST node is + /// determined solely by aNode. + /// The AST Node type must have a default/parameterless constructor. + /// + /// AST Node instance to be used for creating the new AST Node. + /// An initialized AST node object. + public virtual AST create(AST aNode) + { + AST newNode; - /// - /// Creates a new AST node using the specified AST Node Type name. Once created, - /// the new AST node is initialized with the specified Token type ID and string. - /// The used for creating this new AST node is - /// determined solely by ASTNodeTypeName. - /// The AST Node type must have a default/parameterless constructor. - /// - /// Token type ID to be used to create new AST Node. - /// Text for initializing the new AST Node. - /// Fully qualified name of the Type to be used for creating the new AST Node. - /// An initialized AST node object. - public virtual AST create(int type, string txt, string ASTNodeTypeName) - { - AST newNode = createFromNodeName(ASTNodeTypeName); - newNode.initialize(type, txt); - return newNode; - } + if (aNode == null) + newNode = null; + else + { + newNode = createFromAST(aNode); + newNode.initialize(aNode); + } - /// - /// Creates a new AST node using the specified AST Node Type name. - /// - /// Token instance to be used to initialize the new AST Node. - /// - /// Fully qualified name of the Type to be used for creating the new AST Node. - /// - /// A newly created and initialized AST node object. - /// - /// Once created, the new AST node is initialized with the specified Token - /// instance. The used for creating this new AST - /// node is determined solely by ASTNodeTypeName. - /// The AST Node type must have a default/parameterless constructor. - /// - public virtual AST create(IToken tok, string ASTNodeTypeName) - { - AST newNode = createFromNodeName(ASTNodeTypeName); - newNode.initialize(tok); - return newNode; - } + return newNode; + } - /// - /// Creates and initializes a new AST node using the specified AST Node instance. - /// the new AST node is initialized with the specified Token type ID and string. - /// The used for creating this new AST node is - /// determined solely by aNode. - /// The AST Node type must have a default/parameterless constructor. - /// - /// AST Node instance to be used for creating the new AST Node. - /// An initialized AST node object. - public virtual AST create(AST aNode) - { - AST newNode; + /// + /// Creates and initializes a new AST node using the specified Token instance. + /// The used for creating this new AST node is + /// determined by the following: + /// + /// the current TokenTypeID-to-ASTNodeType mapping (if any) or, + /// the otherwise + /// + /// + /// Token instance to be used to create new AST Node. + /// An initialized AST node object. + public virtual AST create(IToken tok) + { + AST newNode; - if (aNode == null) - newNode = null; - else - { - newNode = createFromAST(aNode); - newNode.initialize(aNode); - } - return newNode; - } + if (tok == null) + newNode = null; + else + { + newNode = createFromNodeType(tok.Type); + newNode.initialize(tok); + } - /// - /// Creates and initializes a new AST node using the specified Token instance. - /// The used for creating this new AST node is - /// determined by the following: - /// - /// the current TokenTypeID-to-ASTNodeType mapping (if any) or, - /// the otherwise - /// - /// - /// Token instance to be used to create new AST Node. - /// An initialized AST node object. - public virtual AST create(IToken tok) - { - AST newNode; + return newNode; + } - if (tok == null) - newNode = null; - else - { - newNode = createFromNodeType(tok.Type); - newNode.initialize(tok); - } - return newNode; - } + /// + /// Returns a copy of the specified AST Node instance. The copy is obtained by + /// using the method Clone(). + /// + /// AST Node to copy. + /// An AST Node (or null if t is null). + public virtual AST dup(AST t) + { + // The Java version is implemented using code like this: + if (t == null) + return null; - /// - /// Returns a copy of the specified AST Node instance. The copy is obtained by - /// using the method Clone(). - /// - /// AST Node to copy. - /// An AST Node (or null if t is null). - public virtual AST dup(AST t) - { - // The Java version is implemented using code like this: - if (t == null) - return null; + AST dup_edNode = createFromAST(t); + dup_edNode.initialize(t); + return dup_edNode; + } - AST dup_edNode = createFromAST(t); - dup_edNode.initialize(t); - return dup_edNode; - } + /// + /// Duplicate AST Node tree rooted at specified AST node and all of it's siblings. + /// + /// Root of AST Node tree. + /// Root node of new AST Node tree (or null if t is null). + public virtual AST dupList(AST t) + { + AST result = dupTree(t); // if t == null, then result==null + AST nt = result; + while (t != null) + { + // for each sibling of the root + t = t.getNextSibling(); + nt.setNextSibling(dupTree(t)); // dup each subtree, building new tree + nt = nt.getNextSibling(); + } - /// - /// Duplicate AST Node tree rooted at specified AST node and all of it's siblings. - /// - /// Root of AST Node tree. - /// Root node of new AST Node tree (or null if t is null). - public virtual AST dupList(AST t) - { - AST result = dupTree(t); // if t == null, then result==null - AST nt = result; - while (t != null) - { - // for each sibling of the root - t = t.getNextSibling(); - nt.setNextSibling(dupTree(t)); // dup each subtree, building new tree - nt = nt.getNextSibling(); - } - return result; - } + return result; + } - /// - /// Duplicate AST Node tree rooted at specified AST node. Ignore it's siblings. - /// - /// Root of AST Node tree. - /// Root node of new AST Node tree (or null if t is null). - public virtual AST dupTree(AST t) - { - AST result = dup(t); // make copy of root - // copy all children of root. - if (t != null) - { - result.setFirstChild(dupList(t.getFirstChild())); - } - return result; - } + /// + /// Duplicate AST Node tree rooted at specified AST node. Ignore it's siblings. + /// + /// Root of AST Node tree. + /// Root node of new AST Node tree (or null if t is null). + public virtual AST dupTree(AST t) + { + AST result = dup(t); // make copy of root + // copy all children of root. + if (t != null) + { + result.setFirstChild(dupList(t.getFirstChild())); + } - /// - /// Make a tree from a list of nodes. The first element in the - /// array is the root. If the root is null, then the tree is - /// a simple list not a tree. Handles null children nodes correctly. - /// For example, build(a, b, null, c) yields tree (a b c). build(null,a,b) - /// yields tree (nil a b). - /// - /// List of Nodes. - /// AST Node tree. - public virtual AST make(params AST[] nodes) - { - if (nodes == null || nodes.Length == 0) - return null; - AST root = nodes[0]; - AST tail = null; - if (root != null) - { - root.setFirstChild(null); // don't leave any old pointers set - } - // link in children; - for (int i = 1; i < nodes.Length; i++) - { - if (nodes[i] == null) - continue; - // ignore null nodes - if (root == null) - { - // Set the root and set it up for a flat list - root = (tail = nodes[i]); - } - else if (tail == null) - { - root.setFirstChild(nodes[i]); - tail = root.getFirstChild(); - } - else - { - tail.setNextSibling(nodes[i]); - tail = tail.getNextSibling(); - } - // Chase tail to last sibling - while (tail.getNextSibling() != null) - { - tail = tail.getNextSibling(); - } - } - return root; - } + return result; + } - /// - /// Make a tree from a list of nodes, where the nodes are contained - /// in an ASTArray object. - /// - /// List of Nodes. - /// AST Node tree. - public virtual AST make(ASTArray nodes) - { - return make(nodes.array); - } + /// + /// Make a tree from a list of nodes. The first element in the + /// array is the root. If the root is null, then the tree is + /// a simple list not a tree. Handles null children nodes correctly. + /// For example, build(a, b, null, c) yields tree (a b c). build(null,a,b) + /// yields tree (nil a b). + /// + /// List of Nodes. + /// AST Node tree. + public virtual AST make(params AST[] nodes) + { + if (nodes == null || nodes.Length == 0) + return null; + AST root = nodes[0]; + AST tail = null; + if (root != null) + { + root.setFirstChild(null); // don't leave any old pointers set + } - /// - /// Make an AST the root of current AST. - /// - /// - /// - public virtual void makeASTRoot(ref ASTPair currentAST, AST root) - { - if (root != null) - { - // Add the current root as a child of new root - root.addChild(currentAST.root); - // The new current child is the last sibling of the old root - currentAST.child = currentAST.root; - currentAST.advanceChildToEnd(); - // Set the new root - currentAST.root = root; - } - } + // link in children; + for (int i = 1; i < nodes.Length; i++) + { + if (nodes[i] == null) + continue; + // ignore null nodes + if (root == null) + { + // Set the root and set it up for a flat list + root = (tail = nodes[i]); + } + else if (tail == null) + { + root.setFirstChild(nodes[i]); + tail = root.getFirstChild(); + } + else + { + tail.setNextSibling(nodes[i]); + tail = tail.getNextSibling(); + } - /// - /// Sets the global default AST Node Type for this ASTFactory instance. - /// This method also attempts to load the instance - /// for the specified typename. - /// - /// Fully qualified AST Node Type name. - public virtual void setASTNodeType(string t) - { - if (defaultCreator_ != null) - { - if (t != defaultCreator_.ASTNodeTypeName) - { - defaultCreator_ = null; - } - } - defaultASTNodeTypeObject_ = loadNodeTypeObject(t); - } + // Chase tail to last sibling + while (tail.getNextSibling() != null) + { + tail = tail.getNextSibling(); + } + } - /// - /// To change where error messages go, can subclass/override this method - /// and then setASTFactory in Parser and TreeParser. This method removes - /// a prior dependency on class antlr.Tool. - /// - /// - public virtual void error(string e) - { - Console.Error.WriteLine(e); - } + return root; + } - //--------------------------------------------------------------------- - // PRIVATE FUNCTION MEMBERS - //--------------------------------------------------------------------- + /// + /// Make a tree from a list of nodes, where the nodes are contained + /// in an ASTArray object. + /// + /// List of Nodes. + /// AST Node tree. + public virtual AST make(ASTArray nodes) + { + return make(nodes.array); + } - private static Type loadNodeTypeObject(string nodeTypeName) - { - Type nodeTypeObject = null; - bool typeCreated = false; + /// + /// Make an AST the root of current AST. + /// + /// + /// + public virtual void makeASTRoot(ref ASTPair currentAST, AST root) + { + if (root != null) + { + // Add the current root as a child of new root + root.addChild(currentAST.root); + // The new current child is the last sibling of the old root + currentAST.child = currentAST.root; + currentAST.advanceChildToEnd(); + // Set the new root + currentAST.root = root; + } + } - if (nodeTypeName != null) - { - foreach (Assembly assem in AppDomain.CurrentDomain.GetAssemblies()) - { - try - { - nodeTypeObject = assem.GetType(nodeTypeName); - if (nodeTypeObject != null) - { - typeCreated = true; - break; - } - } - catch - { - typeCreated = false; - } - } - } - if (!typeCreated) - { - throw new TypeLoadException("Unable to load AST Node Type: '" + nodeTypeName + "'"); - } - return nodeTypeObject; - } + /// + /// Sets the global default AST Node Type for this ASTFactory instance. + /// This method also attempts to load the instance + /// for the specified typename. + /// + /// Fully qualified AST Node Type name. + public virtual void setASTNodeType(string t) + { + if (defaultCreator_ != null) + { + if (t != defaultCreator_.ASTNodeTypeName) + { + defaultCreator_ = null; + } + } - private AST createFromAST(AST node) - { - AST newNode = null; - Type nodeAsTypeObj = node.GetType(); + defaultASTNodeTypeObject_ = loadNodeTypeObject(t); + } - ASTNodeCreator creator = (ASTNodeCreator) typename2creator_[nodeAsTypeObj.FullName]; - if (creator != null) - { - newNode = creator.Create(); - if (newNode == null) - { - throw new ArgumentException("Unable to create AST Node Type: '" + nodeAsTypeObj.FullName + "'"); - } - } - else - { - newNode = createFromNodeTypeObject(nodeAsTypeObj); - } - return newNode; - } + /// + /// To change where error messages go, can subclass/override this method + /// and then setASTFactory in Parser and TreeParser. This method removes + /// a prior dependency on class antlr.Tool. + /// + /// + public virtual void error(string e) + { + Console.Error.WriteLine(e); + } - private AST createFromNodeName(string nodeTypeName) - { - AST newNode = null; + //--------------------------------------------------------------------- + // PRIVATE FUNCTION MEMBERS + //--------------------------------------------------------------------- - ASTNodeCreator creator = (ASTNodeCreator) typename2creator_[nodeTypeName]; - if (creator != null) - { - newNode = creator.Create(); - if (newNode == null) - { - throw new ArgumentException("Unable to create AST Node Type: '" + nodeTypeName + "'"); - } - } - else - { - newNode = createFromNodeTypeObject( loadNodeTypeObject(nodeTypeName) ); - } - return newNode; - } + private static Type loadNodeTypeObject(string nodeTypeName) + { + Type nodeTypeObject = null; + bool typeCreated = false; - private AST createFromNodeType(int nodeTypeIndex) - { - Debug.Assert((nodeTypeIndex >= 0) && (nodeTypeIndex <= heteroList_.Length), "Invalid AST node type!"); - AST newNode = null; + if (nodeTypeName != null) + { + foreach (Assembly assem in AppDomain.CurrentDomain.GetAssemblies()) + { + try + { + nodeTypeObject = assem.GetType(nodeTypeName); + if (nodeTypeObject != null) + { + typeCreated = true; + break; + } + } + catch + { + typeCreated = false; + } + } + } - FactoryEntry entry = heteroList_[nodeTypeIndex]; - if ((entry != null) && (entry.Creator != null)) - { - newNode = entry.Creator.Create(); - } - else - { - if ((entry == null) || (entry.NodeTypeObject == null)) - { - if (defaultCreator_ == null) - { - newNode = createFromNodeTypeObject(defaultASTNodeTypeObject_); - } - else - newNode = defaultCreator_.Create(); - } - else - newNode = createFromNodeTypeObject( entry.NodeTypeObject ); - } - return newNode; - } + if (!typeCreated) + { + throw new TypeLoadException("Unable to load AST Node Type: '" + nodeTypeName + "'"); + } - private AST createFromNodeTypeObject(Type nodeTypeObject) - { - AST newNode = null; + return nodeTypeObject; + } - try - { - newNode = (AST) Activator.CreateInstance(nodeTypeObject); - if (newNode == null) - { - throw new ArgumentException("Unable to create AST Node Type: '" + nodeTypeObject.FullName + "'"); - } - } - catch(Exception ex) - { - throw new ArgumentException("Unable to create AST Node Type: '" + nodeTypeObject.FullName + "'", ex); - } - return newNode; - } + private AST createFromAST(AST node) + { + AST newNode = null; + Type nodeAsTypeObj = node.GetType(); - protected class FactoryEntry - { - public FactoryEntry(Type typeObj, ASTNodeCreator creator) - { - NodeTypeObject = typeObj; - Creator = creator; - } + ASTNodeCreator creator = (ASTNodeCreator) typename2creator_[nodeAsTypeObj.FullName]; + if (creator != null) + { + newNode = creator.Create(); + if (newNode == null) + { + throw new ArgumentException("Unable to create AST Node Type: '" + nodeAsTypeObj.FullName + "'"); + } + } + else + { + newNode = createFromNodeTypeObject(nodeAsTypeObj); + } - public FactoryEntry(Type typeObj) - { - NodeTypeObject = typeObj; - } + return newNode; + } - public FactoryEntry(ASTNodeCreator creator) - { - Creator = creator; - } + private AST createFromNodeName(string nodeTypeName) + { + AST newNode = null; - public Type NodeTypeObject; - public ASTNodeCreator Creator; - } - } + ASTNodeCreator creator = (ASTNodeCreator) typename2creator_[nodeTypeName]; + if (creator != null) + { + newNode = creator.Create(); + if (newNode == null) + { + throw new ArgumentException("Unable to create AST Node Type: '" + nodeTypeName + "'"); + } + } + else + { + newNode = createFromNodeTypeObject(loadNodeTypeObject(nodeTypeName)); + } + + return newNode; + } + + private AST createFromNodeType(int nodeTypeIndex) + { + Debug.Assert((nodeTypeIndex >= 0) && (nodeTypeIndex <= heteroList_.Length), "Invalid AST node type!"); + AST newNode = null; + + FactoryEntry entry = heteroList_[nodeTypeIndex]; + if ((entry != null) && (entry.Creator != null)) + { + newNode = entry.Creator.Create(); + } + else + { + if ((entry == null) || (entry.NodeTypeObject == null)) + { + if (defaultCreator_ == null) + { + newNode = createFromNodeTypeObject(defaultASTNodeTypeObject_); + } + else + newNode = defaultCreator_.Create(); + } + else + newNode = createFromNodeTypeObject(entry.NodeTypeObject); + } + + return newNode; + } + + private AST createFromNodeTypeObject(Type nodeTypeObject) + { + AST newNode = null; + + try + { + newNode = (AST) Activator.CreateInstance(nodeTypeObject); + if (newNode == null) + { + throw new ArgumentException("Unable to create AST Node Type: '" + nodeTypeObject.FullName + "'"); + } + } + catch (Exception ex) + { + throw new ArgumentException("Unable to create AST Node Type: '" + nodeTypeObject.FullName + "'", ex); + } + + return newNode; + } + + protected class FactoryEntry + { + public FactoryEntry(Type typeObj, ASTNodeCreator creator) + { + NodeTypeObject = typeObj; + Creator = creator; + } + + public FactoryEntry(Type typeObj) + { + NodeTypeObject = typeObj; + } + + public FactoryEntry(ASTNodeCreator creator) + { + Creator = creator; + } + + public Type NodeTypeObject; + public ASTNodeCreator Creator; + } } diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/ASTNULLType.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/ASTNULLType.cs index 0dd800ca..2ddaf41e 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/ASTNULLType.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/ASTNULLType.cs @@ -1,121 +1,141 @@ -using IEnumerator = System.Collections.IEnumerator; +using IEnumerator = System.Collections.IEnumerator; +using AST = Spring.Expressions.Parser.antlr.collections.AST; -using AST = Spring.Expressions.Parser.antlr.collections.AST; +namespace Spring.Expressions.Parser.antlr; +/*ANTLR Translator Generator + * Project led by Terence Parr at http://www.jGuru.com + * Software rights: http://www.antlr.org/license.html + * + * $Id:$ + */ -namespace Spring.Expressions.Parser.antlr +// +// ANTLR C# Code Generator by Micheal Jordan +// Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com +// Anthony Oguntimehin +// +// With many thanks to Eric V. Smith from the ANTLR list. +// + +/*There is only one instance of this class **/ +public class ASTNULLType : AST { - /*ANTLR Translator Generator - * Project led by Terence Parr at http://www.jGuru.com - * Software rights: http://www.antlr.org/license.html - * - * $Id:$ - */ - - // - // ANTLR C# Code Generator by Micheal Jordan - // Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com - // Anthony Oguntimehin - // - // With many thanks to Eric V. Smith from the ANTLR list. - // + public virtual void addChild(AST c) { } - /*There is only one instance of this class **/ - public class ASTNULLType : AST - { - public virtual void addChild(AST c) {} + public virtual bool Equals(AST t) + { + return false; + } - public virtual bool Equals(AST t) - { - return false; - } - public virtual bool EqualsList(AST t) - { - return false; - } - public virtual bool EqualsListPartial(AST t) - { - return false; - } - public virtual bool EqualsTree(AST t) - { - return false; - } - public virtual bool EqualsTreePartial(AST t) - { - return false; - } - public virtual IEnumerator findAll(AST tree) - { - return null; - } - public virtual IEnumerator findAllPartial(AST subtree) - { - return null; - } - public virtual AST getFirstChild() - { - return this; - } - public virtual AST getNextSibling() - { - return this; - } - public virtual string getText() - { - return ""; - } - public virtual int Type - { - get { return Token.NULL_TREE_LOOKAHEAD; } - set { ; } - } - public int getNumberOfChildren() - { - return 0; - } - public virtual void initialize(int t, string txt) - { - } - public virtual void initialize(AST t) - { - } - public virtual void initialize(IToken t) - { - } - public virtual void setFirstChild(AST c) - { - ; - } - public virtual void setNextSibling(AST n) - { - ; - } - public virtual void setText(string text) - { - ; - } - public virtual void setType(int ttype) - { - this.Type = ttype; - } - override public string ToString() - { - return getText(); - } - public virtual string ToStringList() - { - return getText(); - } - public virtual string ToStringTree() - { - return getText(); - } + public virtual bool EqualsList(AST t) + { + return false; + } - #region Implementation of ICloneable - public object Clone() - { - return MemberwiseClone(); - } - #endregion - } -} \ No newline at end of file + public virtual bool EqualsListPartial(AST t) + { + return false; + } + + public virtual bool EqualsTree(AST t) + { + return false; + } + + public virtual bool EqualsTreePartial(AST t) + { + return false; + } + + public virtual IEnumerator findAll(AST tree) + { + return null; + } + + public virtual IEnumerator findAllPartial(AST subtree) + { + return null; + } + + public virtual AST getFirstChild() + { + return this; + } + + public virtual AST getNextSibling() + { + return this; + } + + public virtual string getText() + { + return ""; + } + + public virtual int Type + { + get { return Token.NULL_TREE_LOOKAHEAD; } + set { ; } + } + + public int getNumberOfChildren() + { + return 0; + } + + public virtual void initialize(int t, string txt) + { + } + + public virtual void initialize(AST t) + { + } + + public virtual void initialize(IToken t) + { + } + + public virtual void setFirstChild(AST c) + { + ; + } + + public virtual void setNextSibling(AST n) + { + ; + } + + public virtual void setText(string text) + { + ; + } + + public virtual void setType(int ttype) + { + this.Type = ttype; + } + + override public string ToString() + { + return getText(); + } + + public virtual string ToStringList() + { + return getText(); + } + + public virtual string ToStringTree() + { + return getText(); + } + + #region Implementation of ICloneable + + public object Clone() + { + return MemberwiseClone(); + } + + #endregion +} diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/ASTNodeCreator.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/ASTNodeCreator.cs index 56d1a3f8..11485318 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/ASTNodeCreator.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/ASTNodeCreator.cs @@ -1,51 +1,50 @@ -namespace Spring.Expressions.Parser.antlr +namespace Spring.Expressions.Parser.antlr; + +using AST = antlr.collections.AST; + +/*ANTLR Translator Generator + * Project led by Terence Parr at http://www.jGuru.com + * Software rights: http://www.antlr.org/license.html + * + * $Id:$ + */ + +// +// ANTLR C# Code Generator by Micheal Jordan +// Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com +// Anthony Oguntimehin +// + +/// +/// A creator of AST node instances. +/// +/// +/// +/// This class and it's sub-classes exists primarily as an optimization +/// of the reflection-based mechanism(s) previously used exclusively to +/// create instances of AST node objects. +/// +/// +/// Parsers and TreeParsers already use the ASTFactory class in ANTLR whenever +/// they need to create an AST node objeect. What this class does is to support +/// performant extensibility of the basic ASTFactory. The ASTFactory can now be +/// extnded as run-time to support more new AST node types without using needing +/// to use reflection. +/// +/// +public abstract class ASTNodeCreator { - using AST = antlr.collections.AST; + /// + /// Returns the fully qualified name of the AST type that this + /// class creates. + /// + public abstract string ASTNodeTypeName + { + get; + } - /*ANTLR Translator Generator - * Project led by Terence Parr at http://www.jGuru.com - * Software rights: http://www.antlr.org/license.html - * - * $Id:$ - */ - - // - // ANTLR C# Code Generator by Micheal Jordan - // Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com - // Anthony Oguntimehin - // - - /// - /// A creator of AST node instances. - /// - /// - /// - /// This class and it's sub-classes exists primarily as an optimization - /// of the reflection-based mechanism(s) previously used exclusively to - /// create instances of AST node objects. - /// - /// - /// Parsers and TreeParsers already use the ASTFactory class in ANTLR whenever - /// they need to create an AST node objeect. What this class does is to support - /// performant extensibility of the basic ASTFactory. The ASTFactory can now be - /// extnded as run-time to support more new AST node types without using needing - /// to use reflection. - /// - /// - public abstract class ASTNodeCreator - { - /// - /// Returns the fully qualified name of the AST type that this - /// class creates. - /// - public abstract string ASTNodeTypeName - { - get; - } - - /// - /// Constructs an instance. - /// - public abstract AST Create(); - } -} \ No newline at end of file + /// + /// Constructs an instance. + /// + public abstract AST Create(); +} diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/ASTPair.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/ASTPair.cs index 850fd508..262ac672 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/ASTPair.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/ASTPair.cs @@ -1,66 +1,64 @@ -namespace Spring.Expressions.Parser.antlr +namespace Spring.Expressions.Parser.antlr; + +using AST = antlr.collections.AST; + +/*ANTLR Translator Generator + * Project led by Terence Parr at http://www.jGuru.com + * Software rights: http://www.antlr.org/license.html + * + * $Id:$ + */ + +// +// ANTLR C# Code Generator by Micheal Jordan +// Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com +// Anthony Oguntimehin +// +// With many thanks to Eric V. Smith from the ANTLR list. +// + +/*ASTPair: utility class used for manipulating a pair of ASTs + * representing the current AST root and current AST sibling. + * This exists to compensate for the lack of pointers or 'var' + * arguments in Java. + */ + +public struct ASTPair { - using AST = antlr.collections.AST; + public AST root; // current root of tree + public AST child; // current child to which siblings are added - /*ANTLR Translator Generator - * Project led by Terence Parr at http://www.jGuru.com - * Software rights: http://www.antlr.org/license.html - * - * $Id:$ - */ + /*Make sure that child is the last sibling */ + public void advanceChildToEnd() + { + if (child != null) + { + while (child.getNextSibling() != null) + { + child = child.getNextSibling(); + } + } + } - // - // ANTLR C# Code Generator by Micheal Jordan - // Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com - // Anthony Oguntimehin - // - // With many thanks to Eric V. Smith from the ANTLR list. - // + /*Copy an ASTPair. Don't call it clone() because we want type-safety */ + public ASTPair copy() + { + ASTPair tmp = new ASTPair(); + tmp.root = root; + tmp.child = child; + return tmp; + } + private void reset() + { + root = null; + child = null; + } - /*ASTPair: utility class used for manipulating a pair of ASTs - * representing the current AST root and current AST sibling. - * This exists to compensate for the lack of pointers or 'var' - * arguments in Java. - */ - - public struct ASTPair - { - public AST root; // current root of tree - public AST child; // current child to which siblings are added - - /*Make sure that child is the last sibling */ - public void advanceChildToEnd() - { - if (child != null) - { - while (child.getNextSibling() != null) - { - child = child.getNextSibling(); - } - } - } - - /*Copy an ASTPair. Don't call it clone() because we want type-safety */ - public ASTPair copy() - { - ASTPair tmp = new ASTPair(); - tmp.root = root; - tmp.child = child; - return tmp; - } - - private void reset() - { - root = null; - child = null; - } - - override public string ToString() - { - string r = (root == null) ? "null" : root.getText(); - string c = (child == null) ? "null" : child.getText(); - return "[" + r + "," + c + "]"; - } - } -} \ No newline at end of file + override public string ToString() + { + string r = (root == null) ? "null" : root.getText(); + string c = (child == null) ? "null" : child.getText(); + return "[" + r + "," + c + "]"; + } +} diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/ASTVisitor.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/ASTVisitor.cs index a9fb32e2..b11220d5 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/ASTVisitor.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/ASTVisitor.cs @@ -1,27 +1,25 @@ -using AST = Spring.Expressions.Parser.antlr.collections.AST; +using AST = Spring.Expressions.Parser.antlr.collections.AST; -namespace Spring.Expressions.Parser.antlr +namespace Spring.Expressions.Parser.antlr; +/* ANTLR Translator Generator + * Project led by Terence Parr at http://www.jGuru.com + * Software rights: http://www.antlr.org/license.html + * + * $Id:$ + */ + +// +// ANTLR C# Code Generator by Micheal Jordan +// Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com +// Anthony Oguntimehin +// +// With many thanks to Eric V. Smith from the ANTLR list. +// + +/// +/// Summary description for ASTVisitor. +/// +public interface ASTVisitor { - /* ANTLR Translator Generator - * Project led by Terence Parr at http://www.jGuru.com - * Software rights: http://www.antlr.org/license.html - * - * $Id:$ - */ - - // - // ANTLR C# Code Generator by Micheal Jordan - // Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com - // Anthony Oguntimehin - // - // With many thanks to Eric V. Smith from the ANTLR list. - // - - /// - /// Summary description for ASTVisitor. - /// - public interface ASTVisitor - { - void visit(AST node); - } + void visit(AST node); } diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/BaseAST.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/BaseAST.cs index 49cc140d..2b210d52 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/BaseAST.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/BaseAST.cs @@ -1,614 +1,630 @@ -using StringBuilder = System.Text.StringBuilder; -using TextWriter = System.IO.TextWriter; -using ArrayList = System.Collections.ArrayList; -using IEnumerator = System.Collections.IEnumerator; +using StringBuilder = System.Text.StringBuilder; +using TextWriter = System.IO.TextWriter; +using ArrayList = System.Collections.ArrayList; +using IEnumerator = System.Collections.IEnumerator; +using AST = Spring.Expressions.Parser.antlr.collections.AST; -using AST = Spring.Expressions.Parser.antlr.collections.AST; +namespace Spring.Expressions.Parser.antlr; +/*ANTLR Translator Generator + * Project led by Terence Parr at http://www.jGuru.com + * Software rights: http://www.antlr.org/license.html + * + * $Id:$ + */ -namespace Spring.Expressions.Parser.antlr +// +// ANTLR C# Code Generator by Micheal Jordan +// Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com +// Anthony Oguntimehin +// +// With many thanks to Eric V. Smith from the ANTLR list. +// + +/* + * A Child-Sibling Tree. + * + * A tree with PLUS at the root and with two children 3 and 4 is + * structured as: + * + * PLUS + * | + * 3 -- 4 + * + * and can be specified easily in LISP notation as + * + * (PLUS 3 4) + * + * where every '(' starts a new subtree. + * + * These trees are particular useful for translators because of + * the flexibility of the children lists. They are also very easy + * to walk automatically, whereas trees with specific children + * reference fields can't easily be walked automatically. + * + * This class contains the basic support for an AST. + * Most people will create ASTs that are subclasses of + * BaseAST or of CommonAST. + */ +[Serializable()] +public abstract class BaseAST : AST { - /*ANTLR Translator Generator - * Project led by Terence Parr at http://www.jGuru.com - * Software rights: http://www.antlr.org/license.html - * - * $Id:$ - */ + protected internal BaseAST down; + protected internal BaseAST right; - // - // ANTLR C# Code Generator by Micheal Jordan - // Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com - // Anthony Oguntimehin - // - // With many thanks to Eric V. Smith from the ANTLR list. - // + private static bool verboseStringConversion = false; + private static string[] tokenNames = null; - /* - * A Child-Sibling Tree. - * - * A tree with PLUS at the root and with two children 3 and 4 is - * structured as: - * - * PLUS - * | - * 3 -- 4 - * - * and can be specified easily in LISP notation as - * - * (PLUS 3 4) - * - * where every '(' starts a new subtree. - * - * These trees are particular useful for translators because of - * the flexibility of the children lists. They are also very easy - * to walk automatically, whereas trees with specific children - * reference fields can't easily be walked automatically. - * - * This class contains the basic support for an AST. - * Most people will create ASTs that are subclasses of - * BaseAST or of CommonAST. - */ - [Serializable()] - public abstract class BaseAST : AST - { - protected internal BaseAST down; - protected internal BaseAST right; + /*Add a node to the end of the child list for this node */ + public virtual void addChild(AST node) + { + if (node == null) + return; + BaseAST t = this.down; + if (t != null) + { + while (t.right != null) + { + t = t.right; + } - private static bool verboseStringConversion = false; - private static string[] tokenNames = null; + t.right = (BaseAST) node; + } + else + { + this.down = (BaseAST) node; + } + } - /*Add a node to the end of the child list for this node */ - public virtual void addChild(AST node) - { - if (node == null) - return ; - BaseAST t = this.down; - if (t != null) - { - while (t.right != null) - { - t = t.right; - } - t.right = (BaseAST) node; - } - else - { - this.down = (BaseAST) node; - } - } + private void doWorkForFindAll(ArrayList v, AST target, bool partialMatch) + { + AST sibling; - private void doWorkForFindAll(ArrayList v, AST target, bool partialMatch) - { - AST sibling; - - // Start walking sibling lists, looking for matches. + // Start walking sibling lists, looking for matches. //siblingWalk: - for (sibling = this; sibling != null; sibling = sibling.getNextSibling()) - { - if ((partialMatch && sibling.EqualsTreePartial(target)) || (!partialMatch && sibling.EqualsTree(target))) - { - v.Add(sibling); - } - // regardless of match or not, check any children for matches - if (sibling.getFirstChild() != null) - { - ((BaseAST) sibling.getFirstChild()).doWorkForFindAll(v, target, partialMatch); - } - } - } + for (sibling = this; sibling != null; sibling = sibling.getNextSibling()) + { + if ((partialMatch && sibling.EqualsTreePartial(target)) || (!partialMatch && sibling.EqualsTree(target))) + { + v.Add(sibling); + } - public override bool Equals(object obj) - { - if (obj == null) - return false; - if (this.GetType() != obj.GetType()) - return false; - return Equals((AST)obj); - } + // regardless of match or not, check any children for matches + if (sibling.getFirstChild() != null) + { + ((BaseAST) sibling.getFirstChild()).doWorkForFindAll(v, target, partialMatch); + } + } + } - /*Is node t equal to this in terms of token type and text? */ - public virtual bool Equals(AST t) - { - if (t == null) - return false; + public override bool Equals(object obj) + { + if (obj == null) + return false; + if (this.GetType() != obj.GetType()) + return false; + return Equals((AST) obj); + } - return (Object.Equals(this.getText(), t.getText())) && - (this.Type == t.Type); - } + /*Is node t equal to this in terms of token type and text? */ + public virtual bool Equals(AST t) + { + if (t == null) + return false; - /*Is t an exact structural and equals() match of this tree. The - * 'this' reference is considered the start of a sibling list. - */ - public virtual bool EqualsList(AST t) - { - AST sibling; + return (Object.Equals(this.getText(), t.getText())) && + (this.Type == t.Type); + } - // the empty tree is not a match of any non-null tree. - if (t == null) - { - return false; - } + /*Is t an exact structural and equals() match of this tree. The + * 'this' reference is considered the start of a sibling list. + */ + public virtual bool EqualsList(AST t) + { + AST sibling; - // Otherwise, start walking sibling lists. First mismatch, return false. - for (sibling = this; sibling != null && t != null; sibling = sibling.getNextSibling(), t = t.getNextSibling()) - { - // as a quick optimization, check roots first. - if (!sibling.Equals(t)) - { - return false; - } - // if roots match, do full list match test on children. - if (sibling.getFirstChild() != null) - { - if (!sibling.getFirstChild().EqualsList(t.getFirstChild())) - { - return false; - } - } - else if (t.getFirstChild() != null) - { - return false; - } - } - if (sibling == null && t == null) - { - return true; - } - // one sibling list has more than the other - return false; - } + // the empty tree is not a match of any non-null tree. + if (t == null) + { + return false; + } - /*Is 'sub' a subtree of this list? - * The siblings of the root are NOT ignored. - */ - public virtual bool EqualsListPartial(AST sub) - { - AST sibling; + // Otherwise, start walking sibling lists. First mismatch, return false. + for (sibling = this; sibling != null && t != null; sibling = sibling.getNextSibling(), t = t.getNextSibling()) + { + // as a quick optimization, check roots first. + if (!sibling.Equals(t)) + { + return false; + } - // the empty tree is always a subset of any tree. - if (sub == null) - { - return true; - } + // if roots match, do full list match test on children. + if (sibling.getFirstChild() != null) + { + if (!sibling.getFirstChild().EqualsList(t.getFirstChild())) + { + return false; + } + } + else if (t.getFirstChild() != null) + { + return false; + } + } - // Otherwise, start walking sibling lists. First mismatch, return false. - for (sibling = this; sibling != null && sub != null; sibling = sibling.getNextSibling(), sub = sub.getNextSibling()) - { - // as a quick optimization, check roots first. - if (!sibling.Equals(sub)) - return false; - // if roots match, do partial list match test on children. - if (sibling.getFirstChild() != null) - { - if (!sibling.getFirstChild().EqualsListPartial(sub.getFirstChild())) - return false; - } - } - if (sibling == null && sub != null) - { - // nothing left to match in this tree, but subtree has more - return false; - } - // either both are null or sibling has more, but subtree doesn't - return true; - } + if (sibling == null && t == null) + { + return true; + } - /*Is tree rooted at 'this' equal to 't'? The siblings - * of 'this' are ignored. - */ - public virtual bool EqualsTree(AST t) - { - // check roots first. - if (!this.Equals(t)) - return false; - // if roots match, do full list match test on children. - if (this.getFirstChild() != null) - { - if (!this.getFirstChild().EqualsList(t.getFirstChild())) - return false; - } - else if (t.getFirstChild() != null) - { - return false; - } - return true; - } + // one sibling list has more than the other + return false; + } - /*Is 't' a subtree of the tree rooted at 'this'? The siblings - * of 'this' are ignored. - */ - public virtual bool EqualsTreePartial(AST sub) - { - // the empty tree is always a subset of any tree. - if (sub == null) - { - return true; - } + /*Is 'sub' a subtree of this list? + * The siblings of the root are NOT ignored. + */ + public virtual bool EqualsListPartial(AST sub) + { + AST sibling; - // check roots first. - if (!this.Equals(sub)) - return false; - // if roots match, do full list partial match test on children. - if (this.getFirstChild() != null) - { - if (!this.getFirstChild().EqualsListPartial(sub.getFirstChild())) - return false; - } - return true; - } + // the empty tree is always a subset of any tree. + if (sub == null) + { + return true; + } - /*Walk the tree looking for all exact subtree matches. Return - * an IEnumerator that lets the caller walk the list - * of subtree roots found herein. - */ - public virtual IEnumerator findAll(AST target) - { - ArrayList roots = new ArrayList(10); - //AST sibling; + // Otherwise, start walking sibling lists. First mismatch, return false. + for (sibling = this; sibling != null && sub != null; sibling = sibling.getNextSibling(), sub = sub.getNextSibling()) + { + // as a quick optimization, check roots first. + if (!sibling.Equals(sub)) + return false; + // if roots match, do partial list match test on children. + if (sibling.getFirstChild() != null) + { + if (!sibling.getFirstChild().EqualsListPartial(sub.getFirstChild())) + return false; + } + } - // the empty tree cannot result in an enumeration - if (target == null) - { - return null; - } + if (sibling == null && sub != null) + { + // nothing left to match in this tree, but subtree has more + return false; + } - doWorkForFindAll(roots, target, false); // find all matches recursively + // either both are null or sibling has more, but subtree doesn't + return true; + } - return roots.GetEnumerator(); - } + /*Is tree rooted at 'this' equal to 't'? The siblings + * of 'this' are ignored. + */ + public virtual bool EqualsTree(AST t) + { + // check roots first. + if (!this.Equals(t)) + return false; + // if roots match, do full list match test on children. + if (this.getFirstChild() != null) + { + if (!this.getFirstChild().EqualsList(t.getFirstChild())) + return false; + } + else if (t.getFirstChild() != null) + { + return false; + } - /*Walk the tree looking for all subtrees. Return - * an IEnumerator that lets the caller walk the list - * of subtree roots found herein. - */ - public virtual IEnumerator findAllPartial(AST sub) - { - ArrayList roots = new ArrayList(10); - //AST sibling; + return true; + } - // the empty tree cannot result in an enumeration - if (sub == null) - { - return null; - } + /*Is 't' a subtree of the tree rooted at 'this'? The siblings + * of 'this' are ignored. + */ + public virtual bool EqualsTreePartial(AST sub) + { + // the empty tree is always a subset of any tree. + if (sub == null) + { + return true; + } - doWorkForFindAll(roots, sub, true); // find all matches recursively + // check roots first. + if (!this.Equals(sub)) + return false; + // if roots match, do full list partial match test on children. + if (this.getFirstChild() != null) + { + if (!this.getFirstChild().EqualsListPartial(sub.getFirstChild())) + return false; + } - return roots.GetEnumerator(); - } + return true; + } - /*Get the first child of this node; null if not children */ - public virtual AST getFirstChild() - { - return down; - } + /*Walk the tree looking for all exact subtree matches. Return + * an IEnumerator that lets the caller walk the list + * of subtree roots found herein. + */ + public virtual IEnumerator findAll(AST target) + { + ArrayList roots = new ArrayList(10); + //AST sibling; - /*Get the next sibling in line after this one */ - public virtual AST getNextSibling() - { - return right; - } + // the empty tree cannot result in an enumeration + if (target == null) + { + return null; + } - /*Get the token text for this node */ - public virtual string getText() - { - return ""; - } + doWorkForFindAll(roots, target, false); // find all matches recursively - /*Get the token type for this node */ - public virtual int Type - { - get { return 0; } - set { ; } - } + return roots.GetEnumerator(); + } - /// - /// Get number of children of this node; if leaf, returns 0 - /// - /// Number of children - public int getNumberOfChildren() - { - BaseAST t = this.down; - int n = 0; - if (t != null) - { - n = 1; - while (t.right != null) - { - t = t.right; - n++; - } - } - return n; - } + /*Walk the tree looking for all subtrees. Return + * an IEnumerator that lets the caller walk the list + * of subtree roots found herein. + */ + public virtual IEnumerator findAllPartial(AST sub) + { + ArrayList roots = new ArrayList(10); + //AST sibling; - public abstract void initialize(int t, string txt); + // the empty tree cannot result in an enumeration + if (sub == null) + { + return null; + } - public abstract void initialize(AST t); + doWorkForFindAll(roots, sub, true); // find all matches recursively - public abstract void initialize(IToken t); + return roots.GetEnumerator(); + } - /*Remove all children */ - public virtual void removeChildren() - { - down = null; - } + /*Get the first child of this node; null if not children */ + public virtual AST getFirstChild() + { + return down; + } - public virtual void setFirstChild(AST c) - { - down = (BaseAST) c; - } + /*Get the next sibling in line after this one */ + public virtual AST getNextSibling() + { + return right; + } - public virtual void setNextSibling(AST n) - { - right = (BaseAST) n; - } + /*Get the token text for this node */ + public virtual string getText() + { + return ""; + } - /*Set the token text for this node */ - public virtual void setText(string text) - { - ; - } + /*Get the token type for this node */ + public virtual int Type + { + get { return 0; } + set { ; } + } - /*Set the token type for this node */ - public virtual void setType(int ttype) - { - this.Type = ttype; - } + /// + /// Get number of children of this node; if leaf, returns 0 + /// + /// Number of children + public int getNumberOfChildren() + { + BaseAST t = this.down; + int n = 0; + if (t != null) + { + n = 1; + while (t.right != null) + { + t = t.right; + n++; + } + } - public static void setVerboseStringConversion(bool verbose, string[] names) - { - verboseStringConversion = verbose; - tokenNames = names; - } + return n; + } - override public string ToString() - { - StringBuilder b = new StringBuilder(); - // if verbose and type name not same as text (keyword probably) - if (verboseStringConversion && - (0 != String.Compare(getText(), (tokenNames[Type]), true)) && - (0 != String.Compare(getText(), StringUtils.stripFrontBack(tokenNames[Type], @"""", @""""), true))) - { - b.Append('['); - b.Append(getText()); - b.Append(",<"); - b.Append(tokenNames[Type]); - b.Append(">]"); - return b.ToString(); - } - return getText(); - } + public abstract void initialize(int t, string txt); - /*Print out a child-sibling tree in LISP notation */ - public virtual string ToStringList() - { - AST t = this; - string ts = ""; - if (t.getFirstChild() != null) - ts += " ("; - ts += " " + this.ToString(); - if (t.getFirstChild() != null) - { - ts += ((BaseAST) t.getFirstChild()).ToStringList(); - } - if (t.getFirstChild() != null) - ts += " )"; - if (t.getNextSibling() != null) - { - ts += ((BaseAST) t.getNextSibling()).ToStringList(); - } - return ts; - } + public abstract void initialize(AST t); - public virtual string ToStringTree() - { - AST t = this; - string ts = ""; - if (t.getFirstChild() != null) - { - ts += " ("; - } - ts += " " + this.ToString(); - if (t.getFirstChild() != null) - { - ts += ((BaseAST) t.getFirstChild()).ToStringList(); - } - if (t.getFirstChild() != null) - { - ts += " )"; - } - return ts; - } + public abstract void initialize(IToken t); - public virtual string ToTree() - { - return ToTree(string.Empty); - } + /*Remove all children */ + public virtual void removeChildren() + { + down = null; + } - public virtual string ToTree(string prefix) - { - StringBuilder sb = new StringBuilder(prefix); + public virtual void setFirstChild(AST c) + { + down = (BaseAST) c; + } - // Replace vertical bar if there is no next sibling. - if ( (getNextSibling() == null) ) - sb.Append("+--"); - else - sb.Append("|--"); + public virtual void setNextSibling(AST n) + { + right = (BaseAST) n; + } - sb.Append( ToString() ); - sb.Append( Environment.NewLine ); + /*Set the token text for this node */ + public virtual void setText(string text) + { + ; + } - if ( getFirstChild() != null ) - { - // Replace vertical bar if there is no next sibling. - if ( getNextSibling() == null ) - sb.Append( ((BaseAST) getFirstChild()).ToTree(prefix + " ") ); - else - sb.Append( ((BaseAST) getFirstChild()).ToTree(prefix + "| ") ); - } + /*Set the token type for this node */ + public virtual void setType(int ttype) + { + this.Type = ttype; + } - if ( getNextSibling() != null ) - sb.Append( ((BaseAST) getNextSibling()).ToTree(prefix) ); + public static void setVerboseStringConversion(bool verbose, string[] names) + { + verboseStringConversion = verbose; + tokenNames = names; + } - return sb.ToString(); - } + override public string ToString() + { + StringBuilder b = new StringBuilder(); + // if verbose and type name not same as text (keyword probably) + if (verboseStringConversion && + (0 != String.Compare(getText(), (tokenNames[Type]), true)) && + (0 != String.Compare(getText(), StringUtils.stripFrontBack(tokenNames[Type], @"""", @""""), true))) + { + b.Append('['); + b.Append(getText()); + b.Append(",<"); + b.Append(tokenNames[Type]); + b.Append(">]"); + return b.ToString(); + } - public static string decode(string text) - { - char c, c1, c2, c3, c4, c5; - StringBuilder n = new StringBuilder(); - for (int i = 0; i < text.Length; i++) - { - c = text[i]; - if (c == '&') - { - c1 = text[i + 1]; - c2 = text[i + 2]; - c3 = text[i + 3]; - c4 = text[i + 4]; - c5 = text[i + 5]; + return getText(); + } - if (c1 == 'a' && c2 == 'm' && c3 == 'p' && c4 == ';') - { - n.Append("&"); - i += 5; - } - else if (c1 == 'l' && c2 == 't' && c3 == ';') - { - n.Append("<"); - i += 4; - } - else if (c1 == 'g' && c2 == 't' && c3 == ';') - { - n.Append(">"); - i += 4; - } - else if (c1 == 'q' && c2 == 'u' && c3 == 'o' && c4 == 't' && c5 == ';') - { - n.Append("\""); - i += 6; - } - else if (c1 == 'a' && c2 == 'p' && c3 == 'o' && c4 == 's' && c5 == ';') - { - n.Append("'"); - i += 6; - } - else - n.Append("&"); - } - else - n.Append(c); - } - return n.ToString(); - } + /*Print out a child-sibling tree in LISP notation */ + public virtual string ToStringList() + { + AST t = this; + string ts = ""; + if (t.getFirstChild() != null) + ts += " ("; + ts += " " + this.ToString(); + if (t.getFirstChild() != null) + { + ts += ((BaseAST) t.getFirstChild()).ToStringList(); + } - public static string encode(string text) - { - char c; - StringBuilder n = new StringBuilder(); - for (int i = 0; i < text.Length; i++) - { - c = text[i]; - switch (c) - { - case '&': - { - n.Append("&"); - break; - } + if (t.getFirstChild() != null) + ts += " )"; + if (t.getNextSibling() != null) + { + ts += ((BaseAST) t.getNextSibling()).ToStringList(); + } - case '<': - { - n.Append("<"); - break; - } + return ts; + } - case '>': - { - n.Append(">"); - break; - } + public virtual string ToStringTree() + { + AST t = this; + string ts = ""; + if (t.getFirstChild() != null) + { + ts += " ("; + } - case '"': - { - n.Append("""); - break; - } + ts += " " + this.ToString(); + if (t.getFirstChild() != null) + { + ts += ((BaseAST) t.getFirstChild()).ToStringList(); + } - case '\'': - { - n.Append("'"); - break; - } + if (t.getFirstChild() != null) + { + ts += " )"; + } - default: - { - n.Append(c); - break; - } + return ts; + } - } - } - return n.ToString(); - } + public virtual string ToTree() + { + return ToTree(string.Empty); + } - public virtual void xmlSerializeNode(TextWriter outWriter) - { - StringBuilder buf = new StringBuilder(100); - buf.Append("<"); - buf.Append(GetType().FullName + " "); - buf.Append("text=\"" + encode(getText()) + "\" type=\"" + Type + "\"/>"); - outWriter.Write(buf.ToString()); - } + public virtual string ToTree(string prefix) + { + StringBuilder sb = new StringBuilder(prefix); - public virtual void xmlSerializeRootOpen(TextWriter outWriter) - { - StringBuilder buf = new StringBuilder(100); - buf.Append("<"); - buf.Append(GetType().FullName + " "); - buf.Append("text=\"" + encode(getText()) + "\" type=\"" + Type + "\">\n"); - outWriter.Write(buf.ToString()); - } + // Replace vertical bar if there is no next sibling. + if ((getNextSibling() == null)) + sb.Append("+--"); + else + sb.Append("|--"); - public virtual void xmlSerializeRootClose(TextWriter outWriter) - { - outWriter.Write("\n"); - } + sb.Append(ToString()); + sb.Append(Environment.NewLine); - public virtual void xmlSerialize(TextWriter outWriter) - { - // print out this node and all siblings - for (AST node = this; node != null; node = node.getNextSibling()) - { - if (node.getFirstChild() == null) - { - // print guts (class name, attributes) - ((BaseAST) node).xmlSerializeNode(outWriter); - } - else - { - ((BaseAST) node).xmlSerializeRootOpen(outWriter); + if (getFirstChild() != null) + { + // Replace vertical bar if there is no next sibling. + if (getNextSibling() == null) + sb.Append(((BaseAST) getFirstChild()).ToTree(prefix + " ")); + else + sb.Append(((BaseAST) getFirstChild()).ToTree(prefix + "| ")); + } - // print children - ((BaseAST) node.getFirstChild()).xmlSerialize(outWriter); + if (getNextSibling() != null) + sb.Append(((BaseAST) getNextSibling()).ToTree(prefix)); - // print end tag - ((BaseAST) node).xmlSerializeRootClose(outWriter); - } - } - } + return sb.ToString(); + } - #region Implementation of ICloneable - [Obsolete("Deprecated since version 2.7.2. Use ASTFactory.dup() instead.", false)] - public virtual object Clone() - { - return MemberwiseClone(); - } - #endregion + public static string decode(string text) + { + char c, c1, c2, c3, c4, c5; + StringBuilder n = new StringBuilder(); + for (int i = 0; i < text.Length; i++) + { + c = text[i]; + if (c == '&') + { + c1 = text[i + 1]; + c2 = text[i + 2]; + c3 = text[i + 3]; + c4 = text[i + 4]; + c5 = text[i + 5]; - public override Int32 GetHashCode() - { - return base.GetHashCode(); - } - } + if (c1 == 'a' && c2 == 'm' && c3 == 'p' && c4 == ';') + { + n.Append("&"); + i += 5; + } + else if (c1 == 'l' && c2 == 't' && c3 == ';') + { + n.Append("<"); + i += 4; + } + else if (c1 == 'g' && c2 == 't' && c3 == ';') + { + n.Append(">"); + i += 4; + } + else if (c1 == 'q' && c2 == 'u' && c3 == 'o' && c4 == 't' && c5 == ';') + { + n.Append("\""); + i += 6; + } + else if (c1 == 'a' && c2 == 'p' && c3 == 'o' && c4 == 's' && c5 == ';') + { + n.Append("'"); + i += 6; + } + else + n.Append("&"); + } + else + n.Append(c); + } + + return n.ToString(); + } + + public static string encode(string text) + { + char c; + StringBuilder n = new StringBuilder(); + for (int i = 0; i < text.Length; i++) + { + c = text[i]; + switch (c) + { + case '&': + { + n.Append("&"); + break; + } + + case '<': + { + n.Append("<"); + break; + } + + case '>': + { + n.Append(">"); + break; + } + + case '"': + { + n.Append("""); + break; + } + + case '\'': + { + n.Append("'"); + break; + } + + default: + { + n.Append(c); + break; + } + } + } + + return n.ToString(); + } + + public virtual void xmlSerializeNode(TextWriter outWriter) + { + StringBuilder buf = new StringBuilder(100); + buf.Append("<"); + buf.Append(GetType().FullName + " "); + buf.Append("text=\"" + encode(getText()) + "\" type=\"" + Type + "\"/>"); + outWriter.Write(buf.ToString()); + } + + public virtual void xmlSerializeRootOpen(TextWriter outWriter) + { + StringBuilder buf = new StringBuilder(100); + buf.Append("<"); + buf.Append(GetType().FullName + " "); + buf.Append("text=\"" + encode(getText()) + "\" type=\"" + Type + "\">\n"); + outWriter.Write(buf.ToString()); + } + + public virtual void xmlSerializeRootClose(TextWriter outWriter) + { + outWriter.Write("\n"); + } + + public virtual void xmlSerialize(TextWriter outWriter) + { + // print out this node and all siblings + for (AST node = this; node != null; node = node.getNextSibling()) + { + if (node.getFirstChild() == null) + { + // print guts (class name, attributes) + ((BaseAST) node).xmlSerializeNode(outWriter); + } + else + { + ((BaseAST) node).xmlSerializeRootOpen(outWriter); + + // print children + ((BaseAST) node.getFirstChild()).xmlSerialize(outWriter); + + // print end tag + ((BaseAST) node).xmlSerializeRootClose(outWriter); + } + } + } + + #region Implementation of ICloneable + + [Obsolete("Deprecated since version 2.7.2. Use ASTFactory.dup() instead.", false)] + public virtual object Clone() + { + return MemberwiseClone(); + } + + #endregion + + public override Int32 GetHashCode() + { + return base.GetHashCode(); + } } diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/ByteBuffer.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/ByteBuffer.cs index 2f02547e..c86a94f1 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/ByteBuffer.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/ByteBuffer.cs @@ -1,89 +1,87 @@ -using Stream = System.IO.Stream; +using Stream = System.IO.Stream; -namespace Spring.Expressions.Parser.antlr +namespace Spring.Expressions.Parser.antlr; +/*ANTLR Translator Generator + * Project led by Terence Parr at http://www.jGuru.com + * Software rights: http://www.antlr.org/license.html + * + * $Id:$ + */ + +// +// ANTLR C# Code Generator by Micheal Jordan +// Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com +// Anthony Oguntimehin +// +// With many thanks to Eric V. Smith from the ANTLR list. +// +/*A Stream of characters fed to the lexer from a InputStream that can + * be rewound via mark()/rewind() methods. + *

+ * A dynamic array is used to buffer up all the input characters. Normally, + * "k" characters are stored in the buffer. More characters may be stored during + * guess mode (testing syntactic predicate), or when LT(i>k) is referenced. + * Consumption of characters is deferred. In other words, reading the next + * character is not done by conume(), but deferred until needed by LA or LT. + *

+ */ + +// SAS: added this class to handle Binary input w/ FileInputStream + +public class ByteBuffer : InputBuffer { - /*ANTLR Translator Generator - * Project led by Terence Parr at http://www.jGuru.com - * Software rights: http://www.antlr.org/license.html - * - * $Id:$ - */ + // char source + [NonSerialized()] internal Stream input; - // - // ANTLR C# Code Generator by Micheal Jordan - // Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com - // Anthony Oguntimehin - // - // With many thanks to Eric V. Smith from the ANTLR list. - // + private const int BUF_SIZE = 16; - /*A Stream of characters fed to the lexer from a InputStream that can - * be rewound via mark()/rewind() methods. - *

- * A dynamic array is used to buffer up all the input characters. Normally, - * "k" characters are stored in the buffer. More characters may be stored during - * guess mode (testing syntactic predicate), or when LT(i>k) is referenced. - * Consumption of characters is deferred. In other words, reading the next - * character is not done by conume(), but deferred until needed by LA or LT. - *

- */ + ///

+ /// Small buffer used to avoid reading individual chars + /// + private byte[] buf = new byte[BUF_SIZE]; - // SAS: added this class to handle Binary input w/ FileInputStream - - public class ByteBuffer:InputBuffer - { - - // char source - [NonSerialized()] - internal Stream input; - - private const int BUF_SIZE = 16; - /// - /// Small buffer used to avoid reading individual chars - /// - private byte[] buf = new byte[BUF_SIZE]; + /*Create a character buffer */ + public ByteBuffer(Stream input_) : base() + { + input = input_; + } - - /*Create a character buffer */ - public ByteBuffer(Stream input_) : base() - { - input = input_; - } - - /*Ensure that the character buffer is sufficiently full */ - override public void fill(int amount) - { + /*Ensure that the character buffer is sufficiently full */ + override public void fill(int amount) + { // try // { - syncConsume(); - // Fill the buffer sufficiently to hold needed characters - int bytesToRead = (amount + markerOffset) - queue.Count; - int c; + syncConsume(); + // Fill the buffer sufficiently to hold needed characters + int bytesToRead = (amount + markerOffset) - queue.Count; + int c; - while (bytesToRead > 0) - { - // Read a few characters - c = input.Read(buf, 0, BUF_SIZE); - for (int i = 0; i < c; i++) - { - // Append the next character - queue.Add(unchecked((char) buf[i])); - } - if (c < BUF_SIZE) - { - while ((bytesToRead-- > 0) && (queue.Count < BUF_SIZE)) - { - queue.Add(CharScanner.EOF_CHAR); - } - break; - } - bytesToRead -= c; - } - // } + while (bytesToRead > 0) + { + // Read a few characters + c = input.Read(buf, 0, BUF_SIZE); + for (int i = 0; i < c; i++) + { + // Append the next character + queue.Add(unchecked((char) buf[i])); + } + + if (c < BUF_SIZE) + { + while ((bytesToRead-- > 0) && (queue.Count < BUF_SIZE)) + { + queue.Add(CharScanner.EOF_CHAR); + } + + break; + } + + bytesToRead -= c; + } + // } // catch (IOException io) // { // throw new CharStreamIOException(io); // } - } - } + } } diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/CharBuffer.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/CharBuffer.cs index 85aba59f..5560c45b 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/CharBuffer.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/CharBuffer.cs @@ -1,90 +1,88 @@ -using TextReader = System.IO.TextReader; -using IOException = System.IO.IOException; +using TextReader = System.IO.TextReader; +using IOException = System.IO.IOException; +namespace Spring.Expressions.Parser.antlr; +/*ANTLR Translator Generator + * Project led by Terence Parr at http://www.jGuru.com + * Software rights: http://www.antlr.org/license.html + * + * $Id:$ + */ -namespace Spring.Expressions.Parser.antlr +// +// ANTLR C# Code Generator by Micheal Jordan +// Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com +// Anthony Oguntimehin +// +// With many thanks to Eric V. Smith from the ANTLR list. +// +/*A Stream of characters fed to the lexer from a InputStream that can + * be rewound via mark()/rewind() methods. + *

+ * A dynamic array is used to buffer up all the input characters. Normally, + * "k" characters are stored in the buffer. More characters may be stored during + * guess mode (testing syntactic predicate), or when LT(i>k) is referenced. + * Consumption of characters is deferred. In other words, reading the next + * character is not done by conume(), but deferred until needed by LA or LT. + *

+ */ + +// SAS: Move most functionality into InputBuffer -- just the file-specific +// stuff is in here +public class CharBuffer : InputBuffer { - /*ANTLR Translator Generator - * Project led by Terence Parr at http://www.jGuru.com - * Software rights: http://www.antlr.org/license.html - * - * $Id:$ - */ + // char source + [NonSerialized()] internal TextReader input; - // - // ANTLR C# Code Generator by Micheal Jordan - // Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com - // Anthony Oguntimehin - // - // With many thanks to Eric V. Smith from the ANTLR list. - // + private const int BUF_SIZE = 16; - /*A Stream of characters fed to the lexer from a InputStream that can - * be rewound via mark()/rewind() methods. - *

- * A dynamic array is used to buffer up all the input characters. Normally, - * "k" characters are stored in the buffer. More characters may be stored during - * guess mode (testing syntactic predicate), or when LT(i>k) is referenced. - * Consumption of characters is deferred. In other words, reading the next - * character is not done by conume(), but deferred until needed by LA or LT. - *

- */ + ///

+ /// Small buffer used to avoid reading individual chars + /// + private char[] buf = new char[BUF_SIZE]; - // SAS: Move most functionality into InputBuffer -- just the file-specific - // stuff is in here - public class CharBuffer : InputBuffer - { - // char source - [NonSerialized()] - internal TextReader input; + /*Create a character buffer */ + public CharBuffer(TextReader input_) : base() + { + input = input_; + } - private const int BUF_SIZE = 16; - /// - /// Small buffer used to avoid reading individual chars - /// - private char[] buf = new char[BUF_SIZE]; + /*Ensure that the character buffer is sufficiently full */ + override public void fill(int amount) + { + try + { + syncConsume(); + // Fill the buffer sufficiently to hold needed characters + int charsToRead = (amount + markerOffset) - queue.Count; + int c; + while (charsToRead > 0) + { + // Read a few characters + c = input.Read(buf, 0, BUF_SIZE); + for (int i = 0; i < c; i++) + { + // Append the next character + queue.Add(buf[i]); + } - /*Create a character buffer */ - public CharBuffer(TextReader input_) : base() - { - input = input_; - } + if (c < BUF_SIZE) + { + while ((charsToRead-- > 0) && (queue.Count < BUF_SIZE)) + { + queue.Add(CharScanner.EOF_CHAR); + } - /*Ensure that the character buffer is sufficiently full */ - override public void fill(int amount) - { - try - { - syncConsume(); - // Fill the buffer sufficiently to hold needed characters - int charsToRead = (amount + markerOffset) - queue.Count; - int c; + break; + } - while (charsToRead > 0) - { - // Read a few characters - c = input.Read(buf, 0, BUF_SIZE); - for (int i = 0; i < c; i++) - { - // Append the next character - queue.Add(buf[i]); - } - if (c < BUF_SIZE) - { - while ((charsToRead-- > 0) && (queue.Count < BUF_SIZE)) - { - queue.Add(CharScanner.EOF_CHAR); - } - break; - } - charsToRead -= c; - } - } - catch (IOException io) - { - throw new CharStreamIOException(io); - } - } - } + charsToRead -= c; + } + } + catch (IOException io) + { + throw new CharStreamIOException(io); + } + } } diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/CharQueue.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/CharQueue.cs index 15f58a32..1a59e335 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/CharQueue.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/CharQueue.cs @@ -1,118 +1,124 @@ -namespace Spring.Expressions.Parser.antlr +namespace Spring.Expressions.Parser.antlr; +/*ANTLR Translator Generator + * Project led by Terence Parr at http://www.jGuru.com + * Software rights: http://www.antlr.org/license.html + * + * $Id:$ + */ + +// +// ANTLR C# Code Generator by Micheal Jordan +// Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com +// Anthony Oguntimehin +// +// With many thanks to Eric V. Smith from the ANTLR list. +// + +/*A circular buffer object used by CharBuffer */ +public class CharQueue { - /*ANTLR Translator Generator - * Project led by Terence Parr at http://www.jGuru.com - * Software rights: http://www.antlr.org/license.html - * - * $Id:$ - */ + /*Physical circular buffer of tokens */ + protected internal char[] buffer; - // - // ANTLR C# Code Generator by Micheal Jordan - // Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com - // Anthony Oguntimehin - // - // With many thanks to Eric V. Smith from the ANTLR list. - // + /*buffer.length-1 for quick modulos */ + private int sizeLessOne; - /*A circular buffer object used by CharBuffer */ - public class CharQueue - { - /*Physical circular buffer of tokens */ - protected internal char[] buffer; - /*buffer.length-1 for quick modulos */ - private int sizeLessOne; - /*physical index of front token */ - private int offset; - /*number of tokens in the queue */ - protected internal int nbrEntries; + /*physical index of front token */ + private int offset; - public CharQueue(int minSize) - { - // Find first power of 2 >= to requested size - int size; - if (minSize < 0) - { - init(16); // pick some value for them - return ; - } - // check for overflow - if (minSize >= (Int32.MaxValue / 2)) - { - init(Int32.MaxValue); // wow that's big. - return ; - } - for (size = 2; size < minSize; size *= 2) - { - ; - } - init(size); - } + /*number of tokens in the queue */ + protected internal int nbrEntries; - /*Add token to end of the queue - * @param tok The token to add - */ - public void append(char tok) - { - if (nbrEntries == buffer.Length) - { - expand(); - } - buffer[(offset + nbrEntries) & sizeLessOne] = tok; - nbrEntries++; - } + public CharQueue(int minSize) + { + // Find first power of 2 >= to requested size + int size; + if (minSize < 0) + { + init(16); // pick some value for them + return; + } - /*Fetch a token from the queue by index - * @param idx The index of the token to fetch, where zero is the token at the front of the queue - */ - public char elementAt(int idx) - { - return buffer[(offset + idx) & sizeLessOne]; - } + // check for overflow + if (minSize >= (Int32.MaxValue / 2)) + { + init(Int32.MaxValue); // wow that's big. + return; + } - /*Expand the token buffer by doubling its capacity */ - private void expand() - { - char[] newBuffer = new char[buffer.Length * 2]; - // Copy the contents to the new buffer - // Note that this will store the first logical item in the - // first physical array element. - for (int i = 0; i < buffer.Length; i++) - { - newBuffer[i] = elementAt(i); - } - // Re-initialize with new contents, keep old nbrEntries - buffer = newBuffer; - sizeLessOne = buffer.Length - 1; - offset = 0; - } + for (size = 2; size < minSize; size *= 2) + { + ; + } - /*Initialize the queue. - * @param size The initial size of the queue - */ - public virtual void init(int size) - { - // Allocate buffer - buffer = new char[size]; - // Other initialization - sizeLessOne = size - 1; - offset = 0; - nbrEntries = 0; - } + init(size); + } - /*Clear the queue. Leaving the previous buffer alone. - */ - public void reset() - { - offset = 0; - nbrEntries = 0; - } + /*Add token to end of the queue + * @param tok The token to add + */ + public void append(char tok) + { + if (nbrEntries == buffer.Length) + { + expand(); + } - /*Remove char from front of queue */ - public void removeFirst() - { - offset = (offset + 1) & sizeLessOne; - nbrEntries--; - } - } + buffer[(offset + nbrEntries) & sizeLessOne] = tok; + nbrEntries++; + } + + /*Fetch a token from the queue by index + * @param idx The index of the token to fetch, where zero is the token at the front of the queue + */ + public char elementAt(int idx) + { + return buffer[(offset + idx) & sizeLessOne]; + } + + /*Expand the token buffer by doubling its capacity */ + private void expand() + { + char[] newBuffer = new char[buffer.Length * 2]; + // Copy the contents to the new buffer + // Note that this will store the first logical item in the + // first physical array element. + for (int i = 0; i < buffer.Length; i++) + { + newBuffer[i] = elementAt(i); + } + + // Re-initialize with new contents, keep old nbrEntries + buffer = newBuffer; + sizeLessOne = buffer.Length - 1; + offset = 0; + } + + /*Initialize the queue. + * @param size The initial size of the queue + */ + public virtual void init(int size) + { + // Allocate buffer + buffer = new char[size]; + // Other initialization + sizeLessOne = size - 1; + offset = 0; + nbrEntries = 0; + } + + /*Clear the queue. Leaving the previous buffer alone. + */ + public void reset() + { + offset = 0; + nbrEntries = 0; + } + + /*Remove char from front of queue */ + public void removeFirst() + { + offset = (offset + 1) & sizeLessOne; + nbrEntries--; + } } diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/CharScanner.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/CharScanner.cs index 59287b16..bc207c96 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/CharScanner.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/CharScanner.cs @@ -1,813 +1,822 @@ using Spring.Expressions.Parser.antlr.debug; -using Stream = System.IO.Stream; -using TextReader = System.IO.TextReader; -using StringBuilder = System.Text.StringBuilder; -using Hashtable = System.Collections.Hashtable; -using Assembly = System.Reflection.Assembly; -using EventHandlerList = System.ComponentModel.EventHandlerList; +using Stream = System.IO.Stream; +using TextReader = System.IO.TextReader; +using StringBuilder = System.Text.StringBuilder; +using Hashtable = System.Collections.Hashtable; +using Assembly = System.Reflection.Assembly; +using EventHandlerList = System.ComponentModel.EventHandlerList; +using BitSet = Spring.Expressions.Parser.antlr.collections.impl.BitSet; -using BitSet = Spring.Expressions.Parser.antlr.collections.impl.BitSet; +namespace Spring.Expressions.Parser.antlr; +/*ANTLR Translator Generator + * Project led by Terence Parr at http://www.jGuru.com + * Software rights: http://www.antlr.org/license.html + * + * $Id:$ + */ -namespace Spring.Expressions.Parser.antlr +// +// ANTLR C# Code Generator by Micheal Jordan +// Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com +// Anthony Oguntimehin +// +// With many thanks to Eric V. Smith from the ANTLR list. +// + +public abstract class CharScanner : TokenStream, ICharScannerDebugSubject { - /*ANTLR Translator Generator - * Project led by Terence Parr at http://www.jGuru.com - * Software rights: http://www.antlr.org/license.html - * - * $Id:$ - */ - - // - // ANTLR C# Code Generator by Micheal Jordan - // Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com - // Anthony Oguntimehin - // - // With many thanks to Eric V. Smith from the ANTLR list. - // - - public abstract class CharScanner : TokenStream, ICharScannerDebugSubject - { - internal const char NO_CHAR = (char) (0); - public static readonly char EOF_CHAR = Char.MaxValue; - - // Used to store event delegates - private EventHandlerList events_ = new EventHandlerList(); - - protected internal EventHandlerList Events - { - get { return events_; } - } - - // The unique keys for each event that CharScanner [objects] can generate - internal static readonly object EnterRuleEventKey = new object(); - internal static readonly object ExitRuleEventKey = new object(); - internal static readonly object DoneEventKey = new object(); - internal static readonly object ReportErrorEventKey = new object(); - internal static readonly object ReportWarningEventKey = new object(); - internal static readonly object NewLineEventKey = new object(); - internal static readonly object MatchEventKey = new object(); - internal static readonly object MatchNotEventKey = new object(); - internal static readonly object MisMatchEventKey = new object(); - internal static readonly object MisMatchNotEventKey = new object(); - internal static readonly object ConsumeEventKey = new object(); - internal static readonly object LAEventKey = new object(); - internal static readonly object SemPredEvaluatedEventKey = new object(); - internal static readonly object SynPredStartedEventKey = new object(); - internal static readonly object SynPredFailedEventKey = new object(); - internal static readonly object SynPredSucceededEventKey = new object(); - - protected internal StringBuilder text; // text of current token - - protected bool saveConsumedInput = true; // does consume() save characters? - - /// Used for creating Token instances. - protected TokenCreator tokenCreator; - - /// Used for caching lookahead characters. - protected char cached_LA1; - protected char cached_LA2; - - protected bool caseSensitive = true; - protected bool caseSensitiveLiterals = true; - protected Hashtable literals; // set by subclass - - /*Tab chars are handled by tab() according to this value; override - * method to do anything weird with tabs. - */ - protected internal int tabsize = 8; - - protected internal IToken returnToken_ = null; // used to return tokens w/o using return val. - - protected internal LexerSharedInputState inputState; - - /*Used during filter mode to indicate that path is desired. - * A subsequent scan error will report an error as usual if - * acceptPath=true; - */ - protected internal bool commitToPath = false; - - /*Used to keep track of indentdepth for traceIn/Out */ - protected internal int traceDepth = 0; - - public CharScanner() - { - text = new StringBuilder(); - setTokenCreator(new CommonToken.CommonTokenCreator()); - } - - public CharScanner(InputBuffer cb) : this() - { - inputState = new LexerSharedInputState(cb); - cached_LA2 = inputState.input.LA(2); - cached_LA1 = inputState.input.LA(1); - } - - public CharScanner(LexerSharedInputState sharedState) : this() - { - inputState = sharedState; - if (inputState != null) - { - cached_LA2 = inputState.input.LA(2); - cached_LA1 = inputState.input.LA(1); - } - } - - - public event TraceEventHandler EnterRule - { - add { Events.AddHandler(EnterRuleEventKey, value); } - remove { Events.RemoveHandler(EnterRuleEventKey, value); } - } - - public event TraceEventHandler ExitRule - { - add { Events.AddHandler(ExitRuleEventKey, value); } - remove { Events.RemoveHandler(ExitRuleEventKey, value); } - } - - public event TraceEventHandler Done - { - add { Events.AddHandler(DoneEventKey, value); } - remove { Events.RemoveHandler(DoneEventKey, value); } - } - - public event MessageEventHandler ErrorReported - { - add { Events.AddHandler(ReportErrorEventKey, value); } - remove { Events.RemoveHandler(ReportErrorEventKey, value); } - } - - public event MessageEventHandler WarningReported - { - add { Events.AddHandler(ReportWarningEventKey, value); } - remove { Events.RemoveHandler(ReportWarningEventKey, value); } - } - - public event NewLineEventHandler HitNewLine - { - add { Events.AddHandler(NewLineEventKey, value); } - remove { Events.RemoveHandler(NewLineEventKey, value); } - } - - public event MatchEventHandler MatchedChar - { - add { Events.AddHandler(MatchEventKey, value); } - remove { Events.RemoveHandler(MatchEventKey, value); } - } - - public event MatchEventHandler MatchedNotChar - { - add { Events.AddHandler(MatchNotEventKey, value); } - remove { Events.RemoveHandler(MatchNotEventKey, value); } - } - - public event MatchEventHandler MisMatchedChar - { - add { Events.AddHandler(MisMatchEventKey, value); } - remove { Events.RemoveHandler(MisMatchEventKey, value); } - } - - public event MatchEventHandler MisMatchedNotChar - { - add { Events.AddHandler(MisMatchNotEventKey, value); } - remove { Events.RemoveHandler(MisMatchNotEventKey, value); } - } - - public event TokenEventHandler ConsumedChar - { - add { Events.AddHandler(ConsumeEventKey, value); } - remove { Events.RemoveHandler(ConsumeEventKey, value); } - } - - public event TokenEventHandler CharLA - { - add { Events.AddHandler(LAEventKey, value); } - remove { Events.RemoveHandler(LAEventKey, value); } - } - - public event SemanticPredicateEventHandler SemPredEvaluated - { - add { Events.AddHandler(SemPredEvaluatedEventKey, value); } - remove { Events.RemoveHandler(SemPredEvaluatedEventKey, value); } - } - - public event SyntacticPredicateEventHandler SynPredStarted - { - add { Events.AddHandler(SynPredStartedEventKey, value); } - remove { Events.RemoveHandler(SynPredStartedEventKey, value); } - } - - public event SyntacticPredicateEventHandler SynPredFailed - { - add { Events.AddHandler(SynPredFailedEventKey, value); } - remove { Events.RemoveHandler(SynPredFailedEventKey, value); } - } - - public event SyntacticPredicateEventHandler SynPredSucceeded - { - add { Events.AddHandler(SynPredSucceededEventKey, value); } - remove { Events.RemoveHandler(SynPredSucceededEventKey, value); } - } - - // From interface TokenStream - public virtual IToken nextToken() { return null; } - - public virtual void append(char c) - { - if (saveConsumedInput) - { - text.Append(c); - } - } - - public virtual void append(string s) - { - if (saveConsumedInput) - { - text.Append(s); - } - } - - public virtual void commit() - { - inputState.input.commit(); - } - - public virtual void recover(RecognitionException ex, BitSet tokenSet) - { - consume(); - consumeUntil(tokenSet); - } - - public virtual void consume() - { - if (inputState.guessing == 0) - { - if (caseSensitive) - { - append(cached_LA1); - } - else - { - // use input.LA(), not LA(), to get original case - // CharScanner.LA() would toLower it. - append(inputState.input.LA(1)); - } - if (cached_LA1 == '\t') - { - tab(); - } - else - { - inputState.column++; - } - } - if (caseSensitive) - { - cached_LA1 = inputState.input.consume(); - cached_LA2 = inputState.input.LA(2); - } - else - { - cached_LA1 = toLower(inputState.input.consume()); - cached_LA2 = toLower(inputState.input.LA(2)); - } - } - - /*Consume chars until one matches the given char */ - public virtual void consumeUntil(int c) - { - while ((EOF_CHAR != cached_LA1) && (c != cached_LA1)) - { - consume(); - } - } - - /*Consume chars until one matches the given set */ - public virtual void consumeUntil(BitSet bset) - { - while (cached_LA1 != EOF_CHAR && !bset.member(cached_LA1)) - { - consume(); - } - } - - public virtual bool getCaseSensitive() - { - return caseSensitive; - } - - public bool getCaseSensitiveLiterals() - { - return caseSensitiveLiterals; - } - - public virtual int getColumn() - { - return inputState.column; - } - - public virtual void setColumn(int c) - { - inputState.column = c; - } - - public virtual bool getCommitToPath() - { - return commitToPath; - } - - public virtual string getFilename() - { - return inputState.filename; - } - - public virtual InputBuffer getInputBuffer() - { - return inputState.input; - } - - public virtual LexerSharedInputState getInputState() - { - return inputState; - } - - public virtual void setInputState(LexerSharedInputState state) - { - inputState = state; - } - - public virtual int getLine() - { - return inputState.line; - } - - /*return a copy of the current text buffer */ - public virtual string getText() - { - return text.ToString(); - } - - public virtual IToken getTokenObject() - { - return returnToken_; - } - - public virtual char LA(int i) - { - if (i == 1) - { - return cached_LA1; - } - if (i == 2) - { - return cached_LA2; - } - if (caseSensitive) - { - return inputState.input.LA(i); - } - else - { - return toLower(inputState.input.LA(i)); - } - } - - protected internal virtual IToken makeToken(int t) - { - IToken newToken = null; - bool typeCreated; - - try - { - newToken = tokenCreator.Create(); - if (newToken != null) - { - newToken.Type = t; - newToken.setColumn(inputState.tokenStartColumn); - newToken.setLine(inputState.tokenStartLine); - // tracking real start line now: newToken.setLine(inputState.line); - newToken.setFilename(inputState.filename); - } - typeCreated = true; - } - catch - { - typeCreated = false; - } - - if (!typeCreated) - { - panic("Can't create Token object '" + tokenCreator.TokenTypeName + "'"); - newToken = Token.badToken; - } - return newToken; - } - - public virtual int mark() - { - return inputState.input.mark(); - } - - public virtual void match(char c) - { - match((int) c); - } - - public virtual void match(int c) - { - if (cached_LA1 != c) - { - throw new MismatchedCharException(cached_LA1, Convert.ToChar(c), false, this); - } - consume(); - } - - public virtual void match(BitSet b) - { - if (!b.member(cached_LA1)) - { - throw new MismatchedCharException(cached_LA1, b, false, this); - } - consume(); - } - - public virtual void match(string s) - { - int len = s.Length; - for (int i = 0; i < len; i++) - { - if (cached_LA1 != s[i]) - { - throw new MismatchedCharException(cached_LA1, s[i], false, this); - } - consume(); - } - } - - public virtual void matchNot(char c) - { - matchNot((int) c); - } - - public virtual void matchNot(int c) - { - if (cached_LA1 == c) - { - throw new MismatchedCharException(cached_LA1, Convert.ToChar(c), true, this); - } - consume(); - } - - public virtual void matchRange(int c1, int c2) - { - if (cached_LA1 < c1 || cached_LA1 > c2) - { - throw new MismatchedCharException(cached_LA1, Convert.ToChar(c1), Convert.ToChar(c2), false, this); - } - consume(); - } - - public virtual void matchRange(char c1, char c2) - { - matchRange((int) c1, (int) c2); - } - - public virtual void newline() - { - inputState.line++; - inputState.column = 1; - } - - /*advance the current column number by an appropriate amount - * according to tab size. This method is called from consume(). - */ - public virtual void tab() - { - int c = getColumn(); - int nc = (((c - 1) / tabsize) + 1) * tabsize + 1; // calculate tab stop - setColumn(nc); - } - - public virtual void setTabSize(int size) - { - tabsize = size; - } - - public virtual int getTabSize() - { - return tabsize; - } - - public virtual void panic() - { - //Console.Error.WriteLine("CharScanner: panic"); - //Environment.Exit(1); - panic(""); - - } - - /// - /// This method is executed by ANTLR internally when it detected an illegal - /// state that cannot be recovered from. - /// The previous implementation of this method called - /// and writes directly to , which is usually not - /// appropriate when a translator is embedded into a larger application. - /// - /// Error message. - public virtual void panic(string s) - { - //Console.Error.WriteLine("CharScanner; panic: " + s); - //Environment.Exit(1); - throw new ANTLRPanicException("CharScanner::panic: " + s); - } - - /*Parser error-reporting function can be overridden in subclass */ - public virtual void reportError(RecognitionException ex) - { - Console.Error.WriteLine(ex); - } - - /*Parser error-reporting function can be overridden in subclass */ - public virtual void reportError(string s) - { - if (getFilename() == null) - { - Console.Error.WriteLine("error: " + s); - } - else - { - Console.Error.WriteLine(getFilename() + ": error: " + s); - } - } - - /*Parser warning-reporting function can be overridden in subclass */ - public virtual void reportWarning(string s) - { - if (getFilename() == null) - { - Console.Error.WriteLine("warning: " + s); - } - else - { - Console.Error.WriteLine(getFilename() + ": warning: " + s); - } - } - - public virtual void refresh() - { - if (caseSensitive) - { - cached_LA2 = inputState.input.LA(2); - cached_LA1 = inputState.input.LA(1); - } - else - { - cached_LA2 = toLower(inputState.input.LA(2)); - cached_LA1 = toLower(inputState.input.LA(1)); - } - } - - public virtual void resetState(InputBuffer ib) - { - text.Length = 0; - traceDepth = 0; - inputState.resetInput(ib); - refresh(); - } - - public void resetState(Stream s) - { - resetState(new ByteBuffer(s)); - } - - public void resetState(TextReader tr) - { - resetState(new CharBuffer(tr)); - } - - public virtual void resetText() - { - text.Length = 0; - inputState.tokenStartColumn = inputState.column; - inputState.tokenStartLine = inputState.line; - } - - public virtual void rewind(int pos) - { - inputState.input.rewind(pos); - //setColumn(inputState.tokenStartColumn); - if (caseSensitive) - { - cached_LA2 = inputState.input.LA(2); - cached_LA1 = inputState.input.LA(1); - } - else - { - cached_LA2 = toLower(inputState.input.LA(2)); - cached_LA1 = toLower(inputState.input.LA(1)); - } - } - - public virtual void setCaseSensitive(bool t) - { - caseSensitive = t; - if (caseSensitive) - { - cached_LA2 = inputState.input.LA(2); - cached_LA1 = inputState.input.LA(1); - } - else - { - cached_LA2 = toLower(inputState.input.LA(2)); - cached_LA1 = toLower(inputState.input.LA(1)); - } - } - - public virtual void setCommitToPath(bool commit) - { - commitToPath = commit; - } - - public virtual void setFilename(string f) - { - inputState.filename = f; - } - - public virtual void setLine(int line) - { - inputState.line = line; - } - - public virtual void setText(string s) - { - resetText(); - text.Append(s); - } - - public virtual void setTokenObjectClass(string cl) - { - this.tokenCreator = new ReflectionBasedTokenCreator(this, cl); - } - - public virtual void setTokenCreator(TokenCreator tokenCreator) - { - this.tokenCreator = tokenCreator; - } - - // Test the token text against the literals table - // Override this method to perform a different literals test - public virtual int testLiteralsTable(int ttype) - { - string tokenText = text.ToString(); - - if ( (tokenText == null) || (tokenText == string.Empty) ) - return ttype; - else - { - object typeAsObject = literals[tokenText]; - return (typeAsObject == null) ? ttype : ((int) typeAsObject); - } - } - - /*Test the text passed in against the literals table - * Override this method to perform a different literals test - * This is used primarily when you want to test a portion of - * a token. - */ - public virtual int testLiteralsTable(string someText, int ttype) - { - if ( (someText == null) || (someText == string.Empty) ) - return ttype; - else - { - object typeAsObject = literals[someText]; - return (typeAsObject == null) ? ttype : ((int) typeAsObject); - } - } - - // Override this method to get more specific case handling - public virtual char toLower(int c) - { - return Char.ToLower(Convert.ToChar(c), System.Globalization.CultureInfo.InvariantCulture); - } - - public virtual void traceIndent() - { - for (int i = 0; i < traceDepth; i++) - Console.Out.Write(" "); - } - - public virtual void traceIn(string rname) - { - traceDepth += 1; - traceIndent(); - Console.Out.WriteLine("> lexer " + rname + "; c==" + LA(1)); - } - - public virtual void traceOut(string rname) - { - traceIndent(); - Console.Out.WriteLine("< lexer " + rname + "; c==" + LA(1)); - traceDepth -= 1; - } - - /*This method is called by YourLexer.nextToken() when the lexer has - * hit EOF condition. EOF is NOT a character. - * This method is not called if EOF is reached during - * syntactic predicate evaluation or during evaluation - * of normal lexical rules, which presumably would be - * an IOException. This traps the "normal" EOF condition. - * - * uponEOF() is called after the complete evaluation of - * the previous token and only if your parser asks - * for another token beyond that last non-EOF token. - * - * You might want to throw token or char stream exceptions - * like: "Heh, premature eof" or a retry stream exception - * ("I found the end of this file, go back to referencing file"). - */ - public virtual void uponEOF() - { - } - - private class ReflectionBasedTokenCreator : TokenCreator - { - protected ReflectionBasedTokenCreator() {} - - public ReflectionBasedTokenCreator(CharScanner owner, string tokenTypeName) - { - this.owner = owner; - SetTokenType(tokenTypeName); - } - - private CharScanner owner; - - /// - /// The fully qualified name of the Token type to create. - /// - private string tokenTypeName; - - /// - /// Type object used as a template for creating tokens by reflection. - /// - private Type tokenTypeObject; - - /// - /// Returns the fully qualified name of the Token type that this - /// class creates. - /// - private void SetTokenType(string tokenTypeName) - { - this.tokenTypeName = tokenTypeName; - foreach (Assembly assem in AppDomain.CurrentDomain.GetAssemblies()) - { - try - { - tokenTypeObject = assem.GetType(tokenTypeName); - if (tokenTypeObject != null) - { - break; - } - } - catch - { - throw new TypeLoadException("Unable to load Type for Token class '" + tokenTypeName + "'"); - } - } - if (tokenTypeObject==null) - throw new TypeLoadException("Unable to load Type for Token class '" + tokenTypeName + "'"); - } - - /// - /// Returns the fully qualified name of the Token type that this - /// class creates. - /// - public override string TokenTypeName - { - get - { - return tokenTypeName; - } - } - - /// - /// Constructs a instance. - /// - public override IToken Create() - { - IToken newToken = null; - - try - { - newToken = (Token) Activator.CreateInstance(tokenTypeObject); - } - catch - { - // supress exception - } - return newToken; - } - } - } + internal const char NO_CHAR = (char) (0); + public static readonly char EOF_CHAR = Char.MaxValue; + + // Used to store event delegates + private EventHandlerList events_ = new EventHandlerList(); + + protected internal EventHandlerList Events + { + get { return events_; } + } + + // The unique keys for each event that CharScanner [objects] can generate + internal static readonly object EnterRuleEventKey = new object(); + internal static readonly object ExitRuleEventKey = new object(); + internal static readonly object DoneEventKey = new object(); + internal static readonly object ReportErrorEventKey = new object(); + internal static readonly object ReportWarningEventKey = new object(); + internal static readonly object NewLineEventKey = new object(); + internal static readonly object MatchEventKey = new object(); + internal static readonly object MatchNotEventKey = new object(); + internal static readonly object MisMatchEventKey = new object(); + internal static readonly object MisMatchNotEventKey = new object(); + internal static readonly object ConsumeEventKey = new object(); + internal static readonly object LAEventKey = new object(); + internal static readonly object SemPredEvaluatedEventKey = new object(); + internal static readonly object SynPredStartedEventKey = new object(); + internal static readonly object SynPredFailedEventKey = new object(); + internal static readonly object SynPredSucceededEventKey = new object(); + + protected internal StringBuilder text; // text of current token + + protected bool saveConsumedInput = true; // does consume() save characters? + + /// Used for creating Token instances. + protected TokenCreator tokenCreator; + + /// Used for caching lookahead characters. + protected char cached_LA1; + + protected char cached_LA2; + + protected bool caseSensitive = true; + protected bool caseSensitiveLiterals = true; + protected Hashtable literals; // set by subclass + + /*Tab chars are handled by tab() according to this value; override + * method to do anything weird with tabs. + */ + protected internal int tabsize = 8; + + protected internal IToken returnToken_ = null; // used to return tokens w/o using return val. + + protected internal LexerSharedInputState inputState; + + /*Used during filter mode to indicate that path is desired. + * A subsequent scan error will report an error as usual if + * acceptPath=true; + */ + protected internal bool commitToPath = false; + + /*Used to keep track of indentdepth for traceIn/Out */ + protected internal int traceDepth = 0; + + public CharScanner() + { + text = new StringBuilder(); + setTokenCreator(new CommonToken.CommonTokenCreator()); + } + + public CharScanner(InputBuffer cb) : this() + { + inputState = new LexerSharedInputState(cb); + cached_LA2 = inputState.input.LA(2); + cached_LA1 = inputState.input.LA(1); + } + + public CharScanner(LexerSharedInputState sharedState) : this() + { + inputState = sharedState; + if (inputState != null) + { + cached_LA2 = inputState.input.LA(2); + cached_LA1 = inputState.input.LA(1); + } + } + + public event TraceEventHandler EnterRule + { + add { Events.AddHandler(EnterRuleEventKey, value); } + remove { Events.RemoveHandler(EnterRuleEventKey, value); } + } + + public event TraceEventHandler ExitRule + { + add { Events.AddHandler(ExitRuleEventKey, value); } + remove { Events.RemoveHandler(ExitRuleEventKey, value); } + } + + public event TraceEventHandler Done + { + add { Events.AddHandler(DoneEventKey, value); } + remove { Events.RemoveHandler(DoneEventKey, value); } + } + + public event MessageEventHandler ErrorReported + { + add { Events.AddHandler(ReportErrorEventKey, value); } + remove { Events.RemoveHandler(ReportErrorEventKey, value); } + } + + public event MessageEventHandler WarningReported + { + add { Events.AddHandler(ReportWarningEventKey, value); } + remove { Events.RemoveHandler(ReportWarningEventKey, value); } + } + + public event NewLineEventHandler HitNewLine + { + add { Events.AddHandler(NewLineEventKey, value); } + remove { Events.RemoveHandler(NewLineEventKey, value); } + } + + public event MatchEventHandler MatchedChar + { + add { Events.AddHandler(MatchEventKey, value); } + remove { Events.RemoveHandler(MatchEventKey, value); } + } + + public event MatchEventHandler MatchedNotChar + { + add { Events.AddHandler(MatchNotEventKey, value); } + remove { Events.RemoveHandler(MatchNotEventKey, value); } + } + + public event MatchEventHandler MisMatchedChar + { + add { Events.AddHandler(MisMatchEventKey, value); } + remove { Events.RemoveHandler(MisMatchEventKey, value); } + } + + public event MatchEventHandler MisMatchedNotChar + { + add { Events.AddHandler(MisMatchNotEventKey, value); } + remove { Events.RemoveHandler(MisMatchNotEventKey, value); } + } + + public event TokenEventHandler ConsumedChar + { + add { Events.AddHandler(ConsumeEventKey, value); } + remove { Events.RemoveHandler(ConsumeEventKey, value); } + } + + public event TokenEventHandler CharLA + { + add { Events.AddHandler(LAEventKey, value); } + remove { Events.RemoveHandler(LAEventKey, value); } + } + + public event SemanticPredicateEventHandler SemPredEvaluated + { + add { Events.AddHandler(SemPredEvaluatedEventKey, value); } + remove { Events.RemoveHandler(SemPredEvaluatedEventKey, value); } + } + + public event SyntacticPredicateEventHandler SynPredStarted + { + add { Events.AddHandler(SynPredStartedEventKey, value); } + remove { Events.RemoveHandler(SynPredStartedEventKey, value); } + } + + public event SyntacticPredicateEventHandler SynPredFailed + { + add { Events.AddHandler(SynPredFailedEventKey, value); } + remove { Events.RemoveHandler(SynPredFailedEventKey, value); } + } + + public event SyntacticPredicateEventHandler SynPredSucceeded + { + add { Events.AddHandler(SynPredSucceededEventKey, value); } + remove { Events.RemoveHandler(SynPredSucceededEventKey, value); } + } + + // From interface TokenStream + public virtual IToken nextToken() { return null; } + + public virtual void append(char c) + { + if (saveConsumedInput) + { + text.Append(c); + } + } + + public virtual void append(string s) + { + if (saveConsumedInput) + { + text.Append(s); + } + } + + public virtual void commit() + { + inputState.input.commit(); + } + + public virtual void recover(RecognitionException ex, BitSet tokenSet) + { + consume(); + consumeUntil(tokenSet); + } + + public virtual void consume() + { + if (inputState.guessing == 0) + { + if (caseSensitive) + { + append(cached_LA1); + } + else + { + // use input.LA(), not LA(), to get original case + // CharScanner.LA() would toLower it. + append(inputState.input.LA(1)); + } + + if (cached_LA1 == '\t') + { + tab(); + } + else + { + inputState.column++; + } + } + + if (caseSensitive) + { + cached_LA1 = inputState.input.consume(); + cached_LA2 = inputState.input.LA(2); + } + else + { + cached_LA1 = toLower(inputState.input.consume()); + cached_LA2 = toLower(inputState.input.LA(2)); + } + } + + /*Consume chars until one matches the given char */ + public virtual void consumeUntil(int c) + { + while ((EOF_CHAR != cached_LA1) && (c != cached_LA1)) + { + consume(); + } + } + + /*Consume chars until one matches the given set */ + public virtual void consumeUntil(BitSet bset) + { + while (cached_LA1 != EOF_CHAR && !bset.member(cached_LA1)) + { + consume(); + } + } + + public virtual bool getCaseSensitive() + { + return caseSensitive; + } + + public bool getCaseSensitiveLiterals() + { + return caseSensitiveLiterals; + } + + public virtual int getColumn() + { + return inputState.column; + } + + public virtual void setColumn(int c) + { + inputState.column = c; + } + + public virtual bool getCommitToPath() + { + return commitToPath; + } + + public virtual string getFilename() + { + return inputState.filename; + } + + public virtual InputBuffer getInputBuffer() + { + return inputState.input; + } + + public virtual LexerSharedInputState getInputState() + { + return inputState; + } + + public virtual void setInputState(LexerSharedInputState state) + { + inputState = state; + } + + public virtual int getLine() + { + return inputState.line; + } + + /*return a copy of the current text buffer */ + public virtual string getText() + { + return text.ToString(); + } + + public virtual IToken getTokenObject() + { + return returnToken_; + } + + public virtual char LA(int i) + { + if (i == 1) + { + return cached_LA1; + } + + if (i == 2) + { + return cached_LA2; + } + + if (caseSensitive) + { + return inputState.input.LA(i); + } + else + { + return toLower(inputState.input.LA(i)); + } + } + + protected internal virtual IToken makeToken(int t) + { + IToken newToken = null; + bool typeCreated; + + try + { + newToken = tokenCreator.Create(); + if (newToken != null) + { + newToken.Type = t; + newToken.setColumn(inputState.tokenStartColumn); + newToken.setLine(inputState.tokenStartLine); + // tracking real start line now: newToken.setLine(inputState.line); + newToken.setFilename(inputState.filename); + } + + typeCreated = true; + } + catch + { + typeCreated = false; + } + + if (!typeCreated) + { + panic("Can't create Token object '" + tokenCreator.TokenTypeName + "'"); + newToken = Token.badToken; + } + + return newToken; + } + + public virtual int mark() + { + return inputState.input.mark(); + } + + public virtual void match(char c) + { + match((int) c); + } + + public virtual void match(int c) + { + if (cached_LA1 != c) + { + throw new MismatchedCharException(cached_LA1, Convert.ToChar(c), false, this); + } + + consume(); + } + + public virtual void match(BitSet b) + { + if (!b.member(cached_LA1)) + { + throw new MismatchedCharException(cached_LA1, b, false, this); + } + + consume(); + } + + public virtual void match(string s) + { + int len = s.Length; + for (int i = 0; i < len; i++) + { + if (cached_LA1 != s[i]) + { + throw new MismatchedCharException(cached_LA1, s[i], false, this); + } + + consume(); + } + } + + public virtual void matchNot(char c) + { + matchNot((int) c); + } + + public virtual void matchNot(int c) + { + if (cached_LA1 == c) + { + throw new MismatchedCharException(cached_LA1, Convert.ToChar(c), true, this); + } + + consume(); + } + + public virtual void matchRange(int c1, int c2) + { + if (cached_LA1 < c1 || cached_LA1 > c2) + { + throw new MismatchedCharException(cached_LA1, Convert.ToChar(c1), Convert.ToChar(c2), false, this); + } + + consume(); + } + + public virtual void matchRange(char c1, char c2) + { + matchRange((int) c1, (int) c2); + } + + public virtual void newline() + { + inputState.line++; + inputState.column = 1; + } + + /*advance the current column number by an appropriate amount + * according to tab size. This method is called from consume(). + */ + public virtual void tab() + { + int c = getColumn(); + int nc = (((c - 1) / tabsize) + 1) * tabsize + 1; // calculate tab stop + setColumn(nc); + } + + public virtual void setTabSize(int size) + { + tabsize = size; + } + + public virtual int getTabSize() + { + return tabsize; + } + + public virtual void panic() + { + //Console.Error.WriteLine("CharScanner: panic"); + //Environment.Exit(1); + panic(""); + } + + /// + /// This method is executed by ANTLR internally when it detected an illegal + /// state that cannot be recovered from. + /// The previous implementation of this method called + /// and writes directly to , which is usually not + /// appropriate when a translator is embedded into a larger application. + /// + /// Error message. + public virtual void panic(string s) + { + //Console.Error.WriteLine("CharScanner; panic: " + s); + //Environment.Exit(1); + throw new ANTLRPanicException("CharScanner::panic: " + s); + } + + /*Parser error-reporting function can be overridden in subclass */ + public virtual void reportError(RecognitionException ex) + { + Console.Error.WriteLine(ex); + } + + /*Parser error-reporting function can be overridden in subclass */ + public virtual void reportError(string s) + { + if (getFilename() == null) + { + Console.Error.WriteLine("error: " + s); + } + else + { + Console.Error.WriteLine(getFilename() + ": error: " + s); + } + } + + /*Parser warning-reporting function can be overridden in subclass */ + public virtual void reportWarning(string s) + { + if (getFilename() == null) + { + Console.Error.WriteLine("warning: " + s); + } + else + { + Console.Error.WriteLine(getFilename() + ": warning: " + s); + } + } + + public virtual void refresh() + { + if (caseSensitive) + { + cached_LA2 = inputState.input.LA(2); + cached_LA1 = inputState.input.LA(1); + } + else + { + cached_LA2 = toLower(inputState.input.LA(2)); + cached_LA1 = toLower(inputState.input.LA(1)); + } + } + + public virtual void resetState(InputBuffer ib) + { + text.Length = 0; + traceDepth = 0; + inputState.resetInput(ib); + refresh(); + } + + public void resetState(Stream s) + { + resetState(new ByteBuffer(s)); + } + + public void resetState(TextReader tr) + { + resetState(new CharBuffer(tr)); + } + + public virtual void resetText() + { + text.Length = 0; + inputState.tokenStartColumn = inputState.column; + inputState.tokenStartLine = inputState.line; + } + + public virtual void rewind(int pos) + { + inputState.input.rewind(pos); + //setColumn(inputState.tokenStartColumn); + if (caseSensitive) + { + cached_LA2 = inputState.input.LA(2); + cached_LA1 = inputState.input.LA(1); + } + else + { + cached_LA2 = toLower(inputState.input.LA(2)); + cached_LA1 = toLower(inputState.input.LA(1)); + } + } + + public virtual void setCaseSensitive(bool t) + { + caseSensitive = t; + if (caseSensitive) + { + cached_LA2 = inputState.input.LA(2); + cached_LA1 = inputState.input.LA(1); + } + else + { + cached_LA2 = toLower(inputState.input.LA(2)); + cached_LA1 = toLower(inputState.input.LA(1)); + } + } + + public virtual void setCommitToPath(bool commit) + { + commitToPath = commit; + } + + public virtual void setFilename(string f) + { + inputState.filename = f; + } + + public virtual void setLine(int line) + { + inputState.line = line; + } + + public virtual void setText(string s) + { + resetText(); + text.Append(s); + } + + public virtual void setTokenObjectClass(string cl) + { + this.tokenCreator = new ReflectionBasedTokenCreator(this, cl); + } + + public virtual void setTokenCreator(TokenCreator tokenCreator) + { + this.tokenCreator = tokenCreator; + } + + // Test the token text against the literals table + // Override this method to perform a different literals test + public virtual int testLiteralsTable(int ttype) + { + string tokenText = text.ToString(); + + if ((tokenText == null) || (tokenText == string.Empty)) + return ttype; + else + { + object typeAsObject = literals[tokenText]; + return (typeAsObject == null) ? ttype : ((int) typeAsObject); + } + } + + /*Test the text passed in against the literals table + * Override this method to perform a different literals test + * This is used primarily when you want to test a portion of + * a token. + */ + public virtual int testLiteralsTable(string someText, int ttype) + { + if ((someText == null) || (someText == string.Empty)) + return ttype; + else + { + object typeAsObject = literals[someText]; + return (typeAsObject == null) ? ttype : ((int) typeAsObject); + } + } + + // Override this method to get more specific case handling + public virtual char toLower(int c) + { + return Char.ToLower(Convert.ToChar(c), System.Globalization.CultureInfo.InvariantCulture); + } + + public virtual void traceIndent() + { + for (int i = 0; i < traceDepth; i++) + Console.Out.Write(" "); + } + + public virtual void traceIn(string rname) + { + traceDepth += 1; + traceIndent(); + Console.Out.WriteLine("> lexer " + rname + "; c==" + LA(1)); + } + + public virtual void traceOut(string rname) + { + traceIndent(); + Console.Out.WriteLine("< lexer " + rname + "; c==" + LA(1)); + traceDepth -= 1; + } + + /*This method is called by YourLexer.nextToken() when the lexer has + * hit EOF condition. EOF is NOT a character. + * This method is not called if EOF is reached during + * syntactic predicate evaluation or during evaluation + * of normal lexical rules, which presumably would be + * an IOException. This traps the "normal" EOF condition. + * + * uponEOF() is called after the complete evaluation of + * the previous token and only if your parser asks + * for another token beyond that last non-EOF token. + * + * You might want to throw token or char stream exceptions + * like: "Heh, premature eof" or a retry stream exception + * ("I found the end of this file, go back to referencing file"). + */ + public virtual void uponEOF() + { + } + + private class ReflectionBasedTokenCreator : TokenCreator + { + protected ReflectionBasedTokenCreator() { } + + public ReflectionBasedTokenCreator(CharScanner owner, string tokenTypeName) + { + this.owner = owner; + SetTokenType(tokenTypeName); + } + + private CharScanner owner; + + /// + /// The fully qualified name of the Token type to create. + /// + private string tokenTypeName; + + /// + /// Type object used as a template for creating tokens by reflection. + /// + private Type tokenTypeObject; + + /// + /// Returns the fully qualified name of the Token type that this + /// class creates. + /// + private void SetTokenType(string tokenTypeName) + { + this.tokenTypeName = tokenTypeName; + foreach (Assembly assem in AppDomain.CurrentDomain.GetAssemblies()) + { + try + { + tokenTypeObject = assem.GetType(tokenTypeName); + if (tokenTypeObject != null) + { + break; + } + } + catch + { + throw new TypeLoadException("Unable to load Type for Token class '" + tokenTypeName + "'"); + } + } + + if (tokenTypeObject == null) + throw new TypeLoadException("Unable to load Type for Token class '" + tokenTypeName + "'"); + } + + /// + /// Returns the fully qualified name of the Token type that this + /// class creates. + /// + public override string TokenTypeName + { + get + { + return tokenTypeName; + } + } + + /// + /// Constructs a instance. + /// + public override IToken Create() + { + IToken newToken = null; + + try + { + newToken = (Token) Activator.CreateInstance(tokenTypeObject); + } + catch + { + // supress exception + } + + return newToken; + } + } } diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/CharStreamException.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/CharStreamException.cs index d07ac17a..0404995b 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/CharStreamException.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/CharStreamException.cs @@ -1,32 +1,29 @@ -namespace Spring.Expressions.Parser.antlr +namespace Spring.Expressions.Parser.antlr; +/*ANTLR Translator Generator + * Project led by Terence Parr at http://www.jGuru.com + * Software rights: http://www.antlr.org/license.html + * + * $Id:$ + */ + +// +// ANTLR C# Code Generator by Micheal Jordan +// Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com +// Anthony Oguntimehin +// +// With many thanks to Eric V. Smith from the ANTLR list. +// +/* + * Anything that goes wrong while generating a stream of characters + */ + +[Serializable] +public class CharStreamException : ANTLRException { - /*ANTLR Translator Generator - * Project led by Terence Parr at http://www.jGuru.com - * Software rights: http://www.antlr.org/license.html - * - * $Id:$ - */ - - // - // ANTLR C# Code Generator by Micheal Jordan - // Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com - // Anthony Oguntimehin - // - // With many thanks to Eric V. Smith from the ANTLR list. - // - - /* - * Anything that goes wrong while generating a stream of characters - */ - - [Serializable] - public class CharStreamException : ANTLRException - { - /* - * CharStreamException constructor comment. - */ - public CharStreamException(string s) : base(s) - { - } - } + /* + * CharStreamException constructor comment. + */ + public CharStreamException(string s) : base(s) + { + } } diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/CharStreamIOException.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/CharStreamIOException.cs index 8b0a000d..6a4e8ebe 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/CharStreamIOException.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/CharStreamIOException.cs @@ -1,33 +1,31 @@ using IOException = System.IO.IOException; -namespace Spring.Expressions.Parser.antlr +namespace Spring.Expressions.Parser.antlr; +/*ANTLR Translator Generator + * Project led by Terence Parr at http://www.jGuru.com + * Software rights: http://www.antlr.org/license.html + * + * $Id:$ + */ + +// +// ANTLR C# Code Generator by Micheal Jordan +// Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com +// Anthony Oguntimehin +// +// With many thanks to Eric V. Smith from the ANTLR list. +// + +/* + * Wrap an IOException in a CharStreamException + */ +[Serializable] +public class CharStreamIOException : CharStreamException { - /*ANTLR Translator Generator - * Project led by Terence Parr at http://www.jGuru.com - * Software rights: http://www.antlr.org/license.html - * - * $Id:$ - */ + public IOException io; - // - // ANTLR C# Code Generator by Micheal Jordan - // Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com - // Anthony Oguntimehin - // - // With many thanks to Eric V. Smith from the ANTLR list. - // - - /* - * Wrap an IOException in a CharStreamException - */ - [Serializable] - public class CharStreamIOException : CharStreamException - { - public IOException io; - - public CharStreamIOException(IOException io) : base(io.Message) - { - this.io = io; - } - } + public CharStreamIOException(IOException io) : base(io.Message) + { + this.io = io; + } } diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/CommonAST.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/CommonAST.cs index 74ccd634..44788eb9 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/CommonAST.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/CommonAST.cs @@ -1,122 +1,124 @@ using AST = Spring.Expressions.Parser.antlr.collections.AST; -namespace Spring.Expressions.Parser.antlr +namespace Spring.Expressions.Parser.antlr; +/*ANTLR Translator Generator + * Project led by Terence Parr at http://www.jGuru.com + * Software rights: http://www.antlr.org/license.html + * + * $Id:$ + */ + +// +// ANTLR C# Code Generator by Micheal Jordan +// Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com +// Anthony Oguntimehin +// +// With many thanks to Eric V. Smith from the ANTLR list. +// + +/*Common AST node implementation */ +public class CommonAST : BaseAST { - /*ANTLR Translator Generator - * Project led by Terence Parr at http://www.jGuru.com - * Software rights: http://www.antlr.org/license.html - * - * $Id:$ - */ + public static readonly CommonAST.CommonASTCreator Creator = new CommonASTCreator(); - // - // ANTLR C# Code Generator by Micheal Jordan - // Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com - // Anthony Oguntimehin - // - // With many thanks to Eric V. Smith from the ANTLR list. - // + internal int ttype = Token.INVALID_TYPE; + internal string text; - /*Common AST node implementation */ - public class CommonAST : BaseAST - { - public static readonly CommonAST.CommonASTCreator Creator = new CommonASTCreator(); + [Obsolete("Deprecated since version 2.7.2. Use ASTFactory.dup() instead.", false)] + protected CommonAST(CommonAST another) + { + // don't include child/sibling pointers in Clone()/dup() + //down = another.down; + //right = another.right; + ttype = another.ttype; + text = (another.text == null) ? null : String.Copy(another.text); + } - internal int ttype = Token.INVALID_TYPE; - internal string text; + /*Get the token text for this node */ + override public string getText() + { + return text; + } + /*Get the token type for this node */ + override public int Type + { + get { return ttype; } + set { ttype = value; } + } - [Obsolete("Deprecated since version 2.7.2. Use ASTFactory.dup() instead.", false)] - protected CommonAST(CommonAST another) - { - // don't include child/sibling pointers in Clone()/dup() - //down = another.down; - //right = another.right; - ttype = another.ttype; - text = (another.text==null) ? null : String.Copy(another.text); - } + override public void initialize(int t, string txt) + { + Type = t; + setText(txt); + } - /*Get the token text for this node */ - override public string getText() - { - return text; - } + override public void initialize(collections.AST t) + { + setText(t.getText()); + Type = t.Type; + } - /*Get the token type for this node */ - override public int Type - { - get { return ttype; } - set { ttype = value; } - } + public CommonAST() + { + } - override public void initialize(int t, string txt) - { - Type = t; - setText(txt); - } + public CommonAST(IToken tok) + { + initialize(tok); + } - override public void initialize(collections.AST t) - { - setText(t.getText()); - Type = t.Type; - } + override public void initialize(IToken tok) + { + setText(tok.getText()); + Type = tok.Type; + } - public CommonAST() - { - } + /*Set the token text for this node */ + override public void setText(string text_) + { + text = text_; + } - public CommonAST(IToken tok) - { - initialize(tok); - } + /*Set the token type for this node */ + override public void setType(int ttype_) + { + this.Type = ttype_; + } - override public void initialize(IToken tok) - { - setText(tok.getText()); - Type = tok.Type; - } - /*Set the token text for this node */ - override public void setText(string text_) - { - text = text_; - } - /*Set the token type for this node */ - override public void setType(int ttype_) - { - this.Type = ttype_; - } + #region Implementation of ICloneable - #region Implementation of ICloneable - [Obsolete("Deprecated since version 2.7.2. Use ASTFactory.dup() instead.", false)] - override public object Clone() - { - return new CommonAST(this); - } - #endregion + [Obsolete("Deprecated since version 2.7.2. Use ASTFactory.dup() instead.", false)] + override public object Clone() + { + return new CommonAST(this); + } - public class CommonASTCreator : ASTNodeCreator - { - public CommonASTCreator() {} + #endregion - /// - /// Returns the fully qualified name of the AST type that this - /// class creates. - /// - public override string ASTNodeTypeName - { - get - { - return typeof(antlr.CommonAST).FullName;; - } - } + public class CommonASTCreator : ASTNodeCreator + { + public CommonASTCreator() { } - /// - /// Constructs a instance. - /// - public override AST Create() - { - return new CommonAST(); - } - } - } + /// + /// Returns the fully qualified name of the AST type that this + /// class creates. + /// + public override string ASTNodeTypeName + { + get + { + return typeof(antlr.CommonAST).FullName; + ; + } + } + + /// + /// Constructs a instance. + /// + public override AST Create() + { + return new CommonAST(); + } + } } diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/CommonASTWithHiddenTokens.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/CommonASTWithHiddenTokens.cs index 64f1135f..43123489 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/CommonASTWithHiddenTokens.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/CommonASTWithHiddenTokens.cs @@ -1,103 +1,103 @@ -using AST = Spring.Expressions.Parser.antlr.collections.AST; +using AST = Spring.Expressions.Parser.antlr.collections.AST; -namespace Spring.Expressions.Parser.antlr +namespace Spring.Expressions.Parser.antlr; +/*ANTLR Translator Generator + * Project led by Terence Parr at http://www.jGuru.com + * Software rights: http://www.antlr.org/license.html + * + * $Id:$ + */ + +// +// ANTLR C# Code Generator by Micheal Jordan +// Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com +// Anthony Oguntimehin +// +// With many thanks to Eric V. Smith from the ANTLR list. +// +/*A CommonAST whose initialization copies hidden token + * information from the Token used to create a node. + */ + +public class CommonASTWithHiddenTokens : CommonAST { - /*ANTLR Translator Generator - * Project led by Terence Parr at http://www.jGuru.com - * Software rights: http://www.antlr.org/license.html - * - * $Id:$ - */ + new public static readonly CommonASTWithHiddenTokens.CommonASTWithHiddenTokensCreator Creator = new CommonASTWithHiddenTokensCreator(); - // - // ANTLR C# Code Generator by Micheal Jordan - // Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com - // Anthony Oguntimehin - // - // With many thanks to Eric V. Smith from the ANTLR list. - // + protected internal IHiddenStreamToken hiddenBefore, hiddenAfter; // references to hidden tokens - /*A CommonAST whose initialization copies hidden token - * information from the Token used to create a node. - */ + public CommonASTWithHiddenTokens() : base() + { + } - public class CommonASTWithHiddenTokens : CommonAST - { - new public static readonly CommonASTWithHiddenTokens.CommonASTWithHiddenTokensCreator Creator = new CommonASTWithHiddenTokensCreator(); + public CommonASTWithHiddenTokens(IToken tok) : base(tok) + { + } - protected internal IHiddenStreamToken hiddenBefore, hiddenAfter; // references to hidden tokens + [Obsolete("Deprecated since version 2.7.2. Use ASTFactory.dup() instead.", false)] + protected CommonASTWithHiddenTokens(CommonASTWithHiddenTokens another) : base(another) + { + hiddenBefore = another.hiddenBefore; + hiddenAfter = another.hiddenAfter; + } - public CommonASTWithHiddenTokens() : base() - { - } + public virtual IHiddenStreamToken getHiddenAfter() + { + return hiddenAfter; + } - public CommonASTWithHiddenTokens(IToken tok) : base(tok) - { - } + public virtual IHiddenStreamToken getHiddenBefore() + { + return hiddenBefore; + } - [Obsolete("Deprecated since version 2.7.2. Use ASTFactory.dup() instead.", false)] - protected CommonASTWithHiddenTokens(CommonASTWithHiddenTokens another) : base(another) - { - hiddenBefore = another.hiddenBefore; - hiddenAfter = another.hiddenAfter; - } + override public void initialize(collections.AST t) + { + hiddenBefore = ((CommonASTWithHiddenTokens) t).getHiddenBefore(); + hiddenAfter = ((CommonASTWithHiddenTokens) t).getHiddenAfter(); + base.initialize(t); + } - public virtual IHiddenStreamToken getHiddenAfter() - { - return hiddenAfter; - } + override public void initialize(IToken tok) + { + IHiddenStreamToken t = (IHiddenStreamToken) tok; + base.initialize(t); + hiddenBefore = t.getHiddenBefore(); + hiddenAfter = t.getHiddenAfter(); + } - public virtual IHiddenStreamToken getHiddenBefore() - { - return hiddenBefore; - } + #region Implementation of ICloneable - override public void initialize(collections.AST t) - { - hiddenBefore = ((CommonASTWithHiddenTokens) t).getHiddenBefore(); - hiddenAfter = ((CommonASTWithHiddenTokens) t).getHiddenAfter(); - base.initialize(t); - } + [Obsolete("Deprecated since version 2.7.2. Use ASTFactory.dup() instead.", false)] + override public object Clone() + { + return new CommonASTWithHiddenTokens(this); + } - override public void initialize(IToken tok) - { - IHiddenStreamToken t = (IHiddenStreamToken) tok; - base.initialize(t); - hiddenBefore = t.getHiddenBefore(); - hiddenAfter = t.getHiddenAfter(); - } + #endregion - #region Implementation of ICloneable - [Obsolete("Deprecated since version 2.7.2. Use ASTFactory.dup() instead.", false)] - override public object Clone() - { - return new CommonASTWithHiddenTokens(this); - } - #endregion + public class CommonASTWithHiddenTokensCreator : ASTNodeCreator + { + public CommonASTWithHiddenTokensCreator() { } - public class CommonASTWithHiddenTokensCreator : ASTNodeCreator - { - public CommonASTWithHiddenTokensCreator() {} + /// + /// Returns the fully qualified name of the AST type that this + /// class creates. + /// + public override string ASTNodeTypeName + { + get + { + return typeof(antlr.CommonASTWithHiddenTokens).FullName; + ; + } + } - /// - /// Returns the fully qualified name of the AST type that this - /// class creates. - /// - public override string ASTNodeTypeName - { - get - { - return typeof(antlr.CommonASTWithHiddenTokens).FullName;; - } - } - - /// - /// Constructs a instance. - /// - public override AST Create() - { - return new CommonASTWithHiddenTokens(); - } - } - } + /// + /// Constructs a instance. + /// + public override AST Create() + { + return new CommonASTWithHiddenTokens(); + } + } } diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/CommonHiddenStreamToken.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/CommonHiddenStreamToken.cs index ba4760be..94e246e8 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/CommonHiddenStreamToken.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/CommonHiddenStreamToken.cs @@ -1,82 +1,81 @@ -namespace Spring.Expressions.Parser.antlr +namespace Spring.Expressions.Parser.antlr; +/*ANTLR Translator Generator + * Project led by Terence Parr at http://www.jGuru.com + * Software rights: http://www.antlr.org/license.html + * + * $Id:$ + */ + +// +// ANTLR C# Code Generator by Micheal Jordan +// Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com +// Anthony Oguntimehin +// +// With many thanks to Eric V. Smith from the ANTLR list. +// + +public class CommonHiddenStreamToken : CommonToken, IHiddenStreamToken { - /*ANTLR Translator Generator - * Project led by Terence Parr at http://www.jGuru.com - * Software rights: http://www.antlr.org/license.html - * - * $Id:$ - */ + new public static readonly CommonHiddenStreamToken.CommonHiddenStreamTokenCreator Creator = new CommonHiddenStreamTokenCreator(); - // - // ANTLR C# Code Generator by Micheal Jordan - // Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com - // Anthony Oguntimehin - // - // With many thanks to Eric V. Smith from the ANTLR list. - // - - public class CommonHiddenStreamToken : CommonToken, IHiddenStreamToken - { - new public static readonly CommonHiddenStreamToken.CommonHiddenStreamTokenCreator Creator = new CommonHiddenStreamTokenCreator(); + protected internal IHiddenStreamToken hiddenBefore; + protected internal IHiddenStreamToken hiddenAfter; - protected internal IHiddenStreamToken hiddenBefore; - protected internal IHiddenStreamToken hiddenAfter; - - public CommonHiddenStreamToken() : base() - { - } - - public CommonHiddenStreamToken(int t, string txt) : base(t, txt) - { - } - - public CommonHiddenStreamToken(string s) : base(s) - { - } - - public virtual IHiddenStreamToken getHiddenAfter() - { - return hiddenAfter; - } - - public virtual IHiddenStreamToken getHiddenBefore() - { - return hiddenBefore; - } - - public virtual void setHiddenAfter(IHiddenStreamToken t) - { - hiddenAfter = t; - } - - public virtual void setHiddenBefore(IHiddenStreamToken t) - { - hiddenBefore = t; - } + public CommonHiddenStreamToken() : base() + { + } - public class CommonHiddenStreamTokenCreator : TokenCreator - { - public CommonHiddenStreamTokenCreator() {} + public CommonHiddenStreamToken(int t, string txt) : base(t, txt) + { + } - /// - /// Returns the fully qualified name of the Token type that this - /// class creates. - /// - public override string TokenTypeName - { - get - { - return typeof(antlr.CommonHiddenStreamToken).FullName;; - } - } + public CommonHiddenStreamToken(string s) : base(s) + { + } - /// - /// Constructs a instance. - /// - public override IToken Create() - { - return new CommonHiddenStreamToken(); - } - } - } -} \ No newline at end of file + public virtual IHiddenStreamToken getHiddenAfter() + { + return hiddenAfter; + } + + public virtual IHiddenStreamToken getHiddenBefore() + { + return hiddenBefore; + } + + public virtual void setHiddenAfter(IHiddenStreamToken t) + { + hiddenAfter = t; + } + + public virtual void setHiddenBefore(IHiddenStreamToken t) + { + hiddenBefore = t; + } + + public class CommonHiddenStreamTokenCreator : TokenCreator + { + public CommonHiddenStreamTokenCreator() { } + + /// + /// Returns the fully qualified name of the Token type that this + /// class creates. + /// + public override string TokenTypeName + { + get + { + return typeof(antlr.CommonHiddenStreamToken).FullName; + ; + } + } + + /// + /// Constructs a instance. + /// + public override IToken Create() + { + return new CommonHiddenStreamToken(); + } + } +} diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/CommonToken.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/CommonToken.cs index c39492df..c5455d9e 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/CommonToken.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/CommonToken.cs @@ -1,103 +1,102 @@ -namespace Spring.Expressions.Parser.antlr +namespace Spring.Expressions.Parser.antlr; +/*ANTLR Translator Generator + * Project led by Terence Parr at http://www.jGuru.com + * Software rights: http://www.antlr.org/license.html + * + * $Id:$ + */ + +// +// ANTLR C# Code Generator by Micheal Jordan +// Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com +// Anthony Oguntimehin +// +// With many thanks to Eric V. Smith from the ANTLR list. +// + +public class CommonToken : Token { - /*ANTLR Translator Generator - * Project led by Terence Parr at http://www.jGuru.com - * Software rights: http://www.antlr.org/license.html - * - * $Id:$ - */ + public static readonly CommonToken.CommonTokenCreator Creator = new CommonTokenCreator(); - // - // ANTLR C# Code Generator by Micheal Jordan - // Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com - // Anthony Oguntimehin - // - // With many thanks to Eric V. Smith from the ANTLR list. - // + // most tokens will want line and text information + protected internal int line; + protected internal string text = null; + protected internal int col; - public class CommonToken : Token - { - public static readonly CommonToken.CommonTokenCreator Creator = new CommonTokenCreator(); + public CommonToken() + { + } - // most tokens will want line and text information - protected internal int line; - protected internal string text = null; - protected internal int col; - - public CommonToken() - { - } - - public CommonToken(int t, string txt) - { - type_ = t; - setText(txt); - } - - public CommonToken(string s) - { - text = s; - } - - override public int getLine() - { - return line; - } - - override public string getText() - { - return text; - } - - override public void setLine(int l) - { - line = l; - } - - override public void setText(string s) - { - text = s; - } - - override public string ToString() - { - return "[\"" + getText() + "\",<" + type_ + ">,line=" + line + ",col=" + col + "]"; - } - - /*Return token's start column */ - override public int getColumn() - { - return col; - } - - override public void setColumn(int c) - { - col = c; - } + public CommonToken(int t, string txt) + { + type_ = t; + setText(txt); + } - public class CommonTokenCreator : TokenCreator - { - public CommonTokenCreator() {} + public CommonToken(string s) + { + text = s; + } - /// - /// Returns the fully qualified name of the Token type that this - /// class creates. - /// - public override string TokenTypeName - { - get - { - return typeof(antlr.CommonToken).FullName;; - } - } + override public int getLine() + { + return line; + } - /// - /// Constructs a instance. - /// - public override IToken Create() - { - return new CommonToken(); - } - } - } -} \ No newline at end of file + override public string getText() + { + return text; + } + + override public void setLine(int l) + { + line = l; + } + + override public void setText(string s) + { + text = s; + } + + override public string ToString() + { + return "[\"" + getText() + "\",<" + type_ + ">,line=" + line + ",col=" + col + "]"; + } + + /*Return token's start column */ + override public int getColumn() + { + return col; + } + + override public void setColumn(int c) + { + col = c; + } + + public class CommonTokenCreator : TokenCreator + { + public CommonTokenCreator() { } + + /// + /// Returns the fully qualified name of the Token type that this + /// class creates. + /// + public override string TokenTypeName + { + get + { + return typeof(antlr.CommonToken).FullName; + ; + } + } + + /// + /// Constructs a instance. + /// + public override IToken Create() + { + return new CommonToken(); + } + } +} diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/DefaultFileLineFormatter.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/DefaultFileLineFormatter.cs index f4756ba3..c717a532 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/DefaultFileLineFormatter.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/DefaultFileLineFormatter.cs @@ -1,47 +1,45 @@ -using StringBuilder = System.Text.StringBuilder; +using StringBuilder = System.Text.StringBuilder; -namespace Spring.Expressions.Parser.antlr +namespace Spring.Expressions.Parser.antlr; +/*ANTLR Translator Generator + * Project led by Terence Parr at http://www.jGuru.com + * Software rights: http://www.antlr.org/license.html + * + * $Id:$ + */ + +// +// ANTLR C# Code Generator by Micheal Jordan +// Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com +// Anthony Oguntimehin +// +// With many thanks to Eric V. Smith from the ANTLR list. +// + +public class DefaultFileLineFormatter : FileLineFormatter { - /*ANTLR Translator Generator - * Project led by Terence Parr at http://www.jGuru.com - * Software rights: http://www.antlr.org/license.html - * - * $Id:$ - */ - - // - // ANTLR C# Code Generator by Micheal Jordan - // Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com - // Anthony Oguntimehin - // - // With many thanks to Eric V. Smith from the ANTLR list. - // + public override string getFormatString(string fileName, int line, int column) + { + StringBuilder buf = new StringBuilder(); - public class DefaultFileLineFormatter : FileLineFormatter - { - public override string getFormatString(string fileName, int line, int column) - { - StringBuilder buf = new StringBuilder(); - - if (fileName != null) - buf.Append(fileName + ":"); - - if (line != - 1) - { - if (fileName == null) - buf.Append("line "); - - buf.Append(line); - - if (column != - 1) - buf.Append(":" + column); - - buf.Append(":"); - } - - buf.Append(" "); - - return buf.ToString(); - } - } -} \ No newline at end of file + if (fileName != null) + buf.Append(fileName + ":"); + + if (line != -1) + { + if (fileName == null) + buf.Append("line "); + + buf.Append(line); + + if (column != -1) + buf.Append(":" + column); + + buf.Append(":"); + } + + buf.Append(" "); + + return buf.ToString(); + } +} diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/DumpASTVisitor.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/DumpASTVisitor.cs index 4cc196f7..e90fb111 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/DumpASTVisitor.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/DumpASTVisitor.cs @@ -1,93 +1,89 @@ -using AST = Spring.Expressions.Parser.antlr.collections.AST; +using AST = Spring.Expressions.Parser.antlr.collections.AST; -namespace Spring.Expressions.Parser.antlr +namespace Spring.Expressions.Parser.antlr; +/* ANTLR Translator Generator + * Project led by Terence Parr at http://www.jGuru.com + * Software rights: http://www.antlr.org/license.html + * + * $Id:$ + */ + +// +// ANTLR C# Code Generator by Micheal Jordan +// Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com +// Anthony Oguntimehin +// +// With many thanks to Eric V. Smith from the ANTLR list. +// + +/// +/// Summary description for DumpASTVisitor. +/// +/** Simple class to dump the contents of an AST to the output */ +public class DumpASTVisitor : ASTVisitor { - /* ANTLR Translator Generator - * Project led by Terence Parr at http://www.jGuru.com - * Software rights: http://www.antlr.org/license.html - * - * $Id:$ - */ + protected int level = 0; - // - // ANTLR C# Code Generator by Micheal Jordan - // Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com - // Anthony Oguntimehin - // - // With many thanks to Eric V. Smith from the ANTLR list. - // - - /// - /// Summary description for DumpASTVisitor. - /// - /** Simple class to dump the contents of an AST to the output */ - public class DumpASTVisitor : ASTVisitor - { - protected int level = 0; + private void tabs() + { + for (int i = 0; i < level; i++) + { + Console.Out.Write(" "); + } + } + public void visit(AST node) + { + // Flatten this level of the tree if it has no children + bool flatten = /*true*/ false; + AST node2; + for (node2 = node; node2 != null; node2 = node2.getNextSibling()) + { + if (node2.getFirstChild() != null) + { + flatten = false; + break; + } + } - private void tabs() - { - for (int i = 0; i < level; i++) - { - Console.Out.Write(" "); - } - } + for (node2 = node; node2 != null; node2 = node2.getNextSibling()) + { + if (!flatten || node2 == node) + { + tabs(); + } - public void visit(AST node) - { - // Flatten this level of the tree if it has no children - bool flatten = /*true*/ false; - AST node2; - for (node2 = node; node2 != null; node2 = node2.getNextSibling()) - { - if (node2.getFirstChild() != null) - { - flatten = false; - break; - } - } + if (node2.getText() == null) + { + Console.Out.Write("nil"); + } + else + { + Console.Out.Write(node2.getText()); + } - for (node2 = node; node2 != null; node2 = node2.getNextSibling()) - { - if (!flatten || node2 == node) - { - tabs(); - } - if (node2.getText() == null) - { - Console.Out.Write("nil"); - } - else - { - Console.Out.Write(node2.getText()); - } + Console.Out.Write(" [" + node2.Type + "] "); - Console.Out.Write(" [" + node2.Type + "] "); + if (flatten) + { + Console.Out.Write(" "); + } + else + { + Console.Out.WriteLine(""); + } - if (flatten) - { - Console.Out.Write(" "); - } - else - { - Console.Out.WriteLine(""); - } + if (node2.getFirstChild() != null) + { + level++; + visit(node2.getFirstChild()); + level--; + } + } - if (node2.getFirstChild() != null) - { - level++; - visit(node2.getFirstChild()); - level--; - } - } - - if (flatten) - { - Console.Out.WriteLine(""); - } - } - } + if (flatten) + { + Console.Out.WriteLine(""); + } + } } - - diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/FileLineFormatter.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/FileLineFormatter.cs index 194e75cb..eeafb033 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/FileLineFormatter.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/FileLineFormatter.cs @@ -1,39 +1,36 @@ -namespace Spring.Expressions.Parser.antlr -{ - /*ANTLR Translator Generator - * Project led by Terence Parr at http://www.jGuru.com - * Software rights: http://www.antlr.org/license.html - * - * $Id:$ - */ - - // - // ANTLR C# Code Generator by Micheal Jordan - // Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com - // Anthony Oguntimehin - // - // With many thanks to Eric V. Smith from the ANTLR list. - // +namespace Spring.Expressions.Parser.antlr; +/*ANTLR Translator Generator + * Project led by Terence Parr at http://www.jGuru.com + * Software rights: http://www.antlr.org/license.html + * + * $Id:$ + */ - public abstract class FileLineFormatter - { - - private static FileLineFormatter formatter = new DefaultFileLineFormatter(); - - public static FileLineFormatter getFormatter() - { - return formatter; - } - - public static void setFormatter(FileLineFormatter f) - { - formatter = f; - } - - /*@param fileName the file that should appear in the prefix. (or null) - * @param line the line (or -1) - * @param column the column (or -1) - */ - public abstract string getFormatString(string fileName, int line, int column); - } -} \ No newline at end of file +// +// ANTLR C# Code Generator by Micheal Jordan +// Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com +// Anthony Oguntimehin +// +// With many thanks to Eric V. Smith from the ANTLR list. +// + +public abstract class FileLineFormatter +{ + private static FileLineFormatter formatter = new DefaultFileLineFormatter(); + + public static FileLineFormatter getFormatter() + { + return formatter; + } + + public static void setFormatter(FileLineFormatter f) + { + formatter = f; + } + + /*@param fileName the file that should appear in the prefix. (or null) + * @param line the line (or -1) + * @param column the column (or -1) + */ + public abstract string getFormatString(string fileName, int line, int column); +} diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/IHiddenStreamToken.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/IHiddenStreamToken.cs index 8fa435d4..5e6afde4 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/IHiddenStreamToken.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/IHiddenStreamToken.cs @@ -1,26 +1,24 @@ -namespace Spring.Expressions.Parser.antlr +namespace Spring.Expressions.Parser.antlr; +/*ANTLR Translator Generator + * Project led by Terence Parr at http://www.jGuru.com + * Software rights: http://www.antlr.org/license.html + * + * $Id:$ + */ + +// +// ANTLR C# Code Generator by Micheal Jordan +// Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com +// Anthony Oguntimehin +// +// With many thanks to Eric V. Smith from the ANTLR list. +// + +public interface IHiddenStreamToken : IToken { - /*ANTLR Translator Generator - * Project led by Terence Parr at http://www.jGuru.com - * Software rights: http://www.antlr.org/license.html - * - * $Id:$ - */ + IHiddenStreamToken getHiddenAfter(); + void setHiddenAfter(IHiddenStreamToken t); - // - // ANTLR C# Code Generator by Micheal Jordan - // Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com - // Anthony Oguntimehin - // - // With many thanks to Eric V. Smith from the ANTLR list. - // - - public interface IHiddenStreamToken : IToken - { - IHiddenStreamToken getHiddenAfter(); - void setHiddenAfter(IHiddenStreamToken t); - - IHiddenStreamToken getHiddenBefore(); - void setHiddenBefore(IHiddenStreamToken t); - } -} \ No newline at end of file + IHiddenStreamToken getHiddenBefore(); + void setHiddenBefore(IHiddenStreamToken t); +} diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/IToken.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/IToken.cs index 06455610..6b5364d1 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/IToken.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/IToken.cs @@ -1,38 +1,36 @@ -namespace Spring.Expressions.Parser.antlr +namespace Spring.Expressions.Parser.antlr; +/*ANTLR Translator Generator + * Project led by Terence Parr at http://www.jGuru.com + * Software rights: http://www.antlr.org/license.html + * + * $Id:$ + */ + +// +// ANTLR C# Code Generator by Micheal Jordan +// Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com +// Anthony Oguntimehin +// +// With many thanks to Eric V. Smith from the ANTLR list. +// + +/// +/// A token is minimally a token type. Subclasses can add the text matched +/// for the token and line info. +/// +public interface IToken { - /*ANTLR Translator Generator - * Project led by Terence Parr at http://www.jGuru.com - * Software rights: http://www.antlr.org/license.html - * - * $Id:$ - */ + int getColumn(); + void setColumn(int c); - // - // ANTLR C# Code Generator by Micheal Jordan - // Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com - // Anthony Oguntimehin - // - // With many thanks to Eric V. Smith from the ANTLR list. - // + int getLine(); + void setLine(int l); - /// - /// A token is minimally a token type. Subclasses can add the text matched - /// for the token and line info. - /// - public interface IToken - { - int getColumn(); - void setColumn(int c); + string getFilename(); + void setFilename(string name); - int getLine(); - void setLine(int l); + string getText(); + void setText(string t); - string getFilename(); - void setFilename(string name); - - string getText(); - void setText(string t); - - int Type { get; set; } - } -} \ No newline at end of file + int Type { get; set; } +} diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/InputBuffer.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/InputBuffer.cs index b575cfb9..e738953c 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/InputBuffer.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/InputBuffer.cs @@ -1,168 +1,169 @@ -namespace Spring.Expressions.Parser.antlr +namespace Spring.Expressions.Parser.antlr; + +using ArrayList = System.Collections.ArrayList; +using StringBuilder = System.Text.StringBuilder; + +/*ANTLR Translator Generator + * Project led by Terence Parr at http://www.jGuru.com + * Software rights: http://www.antlr.org/license.html + */ + +// +// ANTLR C# Code Generator by Micheal Jordan +// Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com +// Anthony Oguntimehin +// +// With many thanks to Eric V. Smith from the ANTLR list. +// + +// SAS: Added this class to genericise the input buffers for scanners +// This allows a scanner to use a binary (FileInputStream) or +// text (FileReader) stream of data; the generated scanner +// subclass will define the input stream +// There are two subclasses to this: CharBuffer and ByteBuffer + +/// +/// Represents a stream of characters fed to the lexer from that can be rewound +/// via mark()/rewind() methods. +/// +/// +/// +/// A dynamic array is used to buffer up all the input characters. Normally, +/// "k" characters are stored in the buffer. More characters may be stored +/// during guess mode (testing syntactic predicate), or when LT(i>k) is referenced. +/// Consumption of characters is deferred. In other words, reading the next +/// character is not done by conume(), but deferred until needed by LA or LT. +/// +/// +public abstract class InputBuffer { - using ArrayList = System.Collections.ArrayList; - using StringBuilder = System.Text.StringBuilder; + // Number of active markers + protected internal int nMarkers = 0; - /*ANTLR Translator Generator - * Project led by Terence Parr at http://www.jGuru.com - * Software rights: http://www.antlr.org/license.html - */ + // Additional offset used when markers are active + protected internal int markerOffset = 0; - // - // ANTLR C# Code Generator by Micheal Jordan - // Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com - // Anthony Oguntimehin - // - // With many thanks to Eric V. Smith from the ANTLR list. - // + // Number of calls to consume() since last LA() or LT() call + protected internal int numToConsume = 0; - // SAS: Added this class to genericise the input buffers for scanners - // This allows a scanner to use a binary (FileInputStream) or - // text (FileReader) stream of data; the generated scanner - // subclass will define the input stream - // There are two subclasses to this: CharBuffer and ByteBuffer - - /// - /// Represents a stream of characters fed to the lexer from that can be rewound - /// via mark()/rewind() methods. - /// - /// - /// - /// A dynamic array is used to buffer up all the input characters. Normally, - /// "k" characters are stored in the buffer. More characters may be stored - /// during guess mode (testing syntactic predicate), or when LT(i>k) is referenced. - /// Consumption of characters is deferred. In other words, reading the next - /// character is not done by conume(), but deferred until needed by LA or LT. - /// - /// - public abstract class InputBuffer - { - // Number of active markers - protected internal int nMarkers = 0; - - // Additional offset used when markers are active - protected internal int markerOffset = 0; - - // Number of calls to consume() since last LA() or LT() call - protected internal int numToConsume = 0; - - // Circular queue - protected ArrayList queue; - - /*Create an input buffer */ - public InputBuffer() - { - queue = new ArrayList(); - } - - /*This method updates the state of the input buffer so that - * the text matched since the most recent mark() is no longer - * held by the buffer. So, you either do a mark/rewind for - * failed predicate or mark/commit to keep on parsing without - * rewinding the input. - */ - public virtual void commit() - { - nMarkers--; - } - - /*Mark another character for deferred consumption */ - public virtual char consume() - { - numToConsume++; - return LA(1); - } - - /*Ensure that the input buffer is sufficiently full */ - public abstract void fill(int amount); - - public virtual string getLAChars() - { - StringBuilder la = new StringBuilder(); + // Circular queue + protected ArrayList queue; - // copy buffer contents to array before looping thru contents (it's usually faster) - char[] fastBuf = new char[queue.Count-markerOffset]; - queue.CopyTo(fastBuf, markerOffset); + /*Create an input buffer */ + public InputBuffer() + { + queue = new ArrayList(); + } - la.Append(fastBuf); - return la.ToString(); - } - - public virtual string getMarkedChars() - { - StringBuilder marked = new StringBuilder(); + /*This method updates the state of the input buffer so that + * the text matched since the most recent mark() is no longer + * held by the buffer. So, you either do a mark/rewind for + * failed predicate or mark/commit to keep on parsing without + * rewinding the input. + */ + public virtual void commit() + { + nMarkers--; + } - // copy buffer contents to array before looping thru contents (it's usually faster) - char[] fastBuf = new char[queue.Count-markerOffset]; - queue.CopyTo(fastBuf, markerOffset); + /*Mark another character for deferred consumption */ + public virtual char consume() + { + numToConsume++; + return LA(1); + } - marked.Append(fastBuf); - return marked.ToString(); - } - - public virtual bool isMarked() - { - return (nMarkers != 0); - } - - /*Get a lookahead character */ - public virtual char LA(int i) - { - fill(i); - if ((this.markerOffset + i) <= this.queue.Count) - { - return (char)this.queue[(this.markerOffset + i) - 1]; - } - return CharScanner.EOF_CHAR; + /*Ensure that the input buffer is sufficiently full */ + public abstract void fill(int amount); + + public virtual string getLAChars() + { + StringBuilder la = new StringBuilder(); + + // copy buffer contents to array before looping thru contents (it's usually faster) + char[] fastBuf = new char[queue.Count - markerOffset]; + queue.CopyTo(fastBuf, markerOffset); + + la.Append(fastBuf); + return la.ToString(); + } + + public virtual string getMarkedChars() + { + StringBuilder marked = new StringBuilder(); + + // copy buffer contents to array before looping thru contents (it's usually faster) + char[] fastBuf = new char[queue.Count - markerOffset]; + queue.CopyTo(fastBuf, markerOffset); + + marked.Append(fastBuf); + return marked.ToString(); + } + + public virtual bool isMarked() + { + return (nMarkers != 0); + } + + /*Get a lookahead character */ + public virtual char LA(int i) + { + fill(i); + if ((this.markerOffset + i) <= this.queue.Count) + { + return (char) this.queue[(this.markerOffset + i) - 1]; } - - /*Return an integer marker that can be used to rewind the buffer to - * its current state. - */ - public virtual int mark() - { - syncConsume(); - nMarkers++; - return markerOffset; - } - - /*Rewind the character buffer to a marker. - * @param mark Marker returned previously from mark() - */ - public virtual void rewind(int mark) - { - syncConsume(); - markerOffset = mark; - nMarkers--; - } - - /*Reset the input buffer - */ - public virtual void reset() - { - nMarkers = 0; - markerOffset = 0; - numToConsume = 0; - queue.Clear(); - } - - /*Sync up deferred consumption */ - protected internal virtual void syncConsume() - { - if (numToConsume > 0) - { - if (nMarkers > 0) - { - // guess mode -- leave leading characters and bump offset. - markerOffset += numToConsume; - } - else - { - // normal mode -- remove "consumed" characters from buffer - queue.RemoveRange(0, numToConsume); - } - numToConsume = 0; - } - } - } -} \ No newline at end of file + + return CharScanner.EOF_CHAR; + } + + /*Return an integer marker that can be used to rewind the buffer to + * its current state. + */ + public virtual int mark() + { + syncConsume(); + nMarkers++; + return markerOffset; + } + + /*Rewind the character buffer to a marker. + * @param mark Marker returned previously from mark() + */ + public virtual void rewind(int mark) + { + syncConsume(); + markerOffset = mark; + nMarkers--; + } + + /*Reset the input buffer + */ + public virtual void reset() + { + nMarkers = 0; + markerOffset = 0; + numToConsume = 0; + queue.Clear(); + } + + /*Sync up deferred consumption */ + protected internal virtual void syncConsume() + { + if (numToConsume > 0) + { + if (nMarkers > 0) + { + // guess mode -- leave leading characters and bump offset. + markerOffset += numToConsume; + } + else + { + // normal mode -- remove "consumed" characters from buffer + queue.RemoveRange(0, numToConsume); + } + + numToConsume = 0; + } + } +} diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/LLkParser.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/LLkParser.cs index 650a9d2d..29add71a 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/LLkParser.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/LLkParser.cs @@ -1,98 +1,108 @@ -namespace Spring.Expressions.Parser.antlr +namespace Spring.Expressions.Parser.antlr; +/*ANTLR Translator Generator + * Project led by Terence Parr at http://www.jGuru.com + * Software rights: http://www.antlr.org/license.html + * + * $Id:$ + */ + +// +// ANTLR C# Code Generator by Micheal Jordan +// Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com +// Anthony Oguntimehin +// +// With many thanks to Eric V. Smith from the ANTLR list. +// + +/*An LL(k) parser. + * + * @see antlr.Token + * @see antlr.TokenBuffer + * @see antlr.LL1Parser + */ +public class LLkParser : Parser { - /*ANTLR Translator Generator - * Project led by Terence Parr at http://www.jGuru.com - * Software rights: http://www.antlr.org/license.html - * - * $Id:$ - */ + internal int k; - // - // ANTLR C# Code Generator by Micheal Jordan - // Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com - // Anthony Oguntimehin - // - // With many thanks to Eric V. Smith from the ANTLR list. - // + public LLkParser(int k_) + { + k = k_; + } - /*An LL(k) parser. - * - * @see antlr.Token - * @see antlr.TokenBuffer - * @see antlr.LL1Parser - */ - public class LLkParser : Parser - { - internal int k; + public LLkParser(ParserSharedInputState state, int k_) + { + k = k_; + inputState = state; + } - public LLkParser(int k_) - { - k = k_; - } - public LLkParser(ParserSharedInputState state, int k_) - { - k = k_; - inputState = state; - } - public LLkParser(TokenBuffer tokenBuf, int k_) - { - k = k_; - setTokenBuffer(tokenBuf); - } - public LLkParser(TokenStream lexer, int k_) - { - k = k_; - TokenBuffer tokenBuf = new TokenBuffer(lexer); - setTokenBuffer(tokenBuf); - } - /*Consume another token from the input stream. Can only write sequentially! - * If you need 3 tokens ahead, you must consume() 3 times. - *

- * Note that it is possible to overwrite tokens that have not been matched. - * For example, calling consume() 3 times when k=2, means that the first token - * consumed will be overwritten with the 3rd. - */ - override public void consume() - { - inputState.input.consume(); - } - override public int LA(int i) - { - return inputState.input.LA(i); - } - override public IToken LT(int i) - { - return inputState.input.LT(i); - } - private void trace(string ee, string rname) - { - traceIndent(); - Console.Out.Write(ee + rname + ((inputState.guessing > 0)?"; [guessing]":"; ")); - for (int i = 1; i <= k; i++) - { - if (i != 1) - { - Console.Out.Write(", "); - } - if ( LT(i)!=null ) { - Console.Out.Write("LA(" + i + ")==" + LT(i).getText()); - } - else - { - Console.Out.Write("LA(" + i + ")==ull"); - } - } - Console.Out.WriteLine(""); - } - override public void traceIn(string rname) - { - traceDepth += 1; - trace("> ", rname); - } - override public void traceOut(string rname) - { - trace("< ", rname); - traceDepth -= 1; - } - } + public LLkParser(TokenBuffer tokenBuf, int k_) + { + k = k_; + setTokenBuffer(tokenBuf); + } + + public LLkParser(TokenStream lexer, int k_) + { + k = k_; + TokenBuffer tokenBuf = new TokenBuffer(lexer); + setTokenBuffer(tokenBuf); + } + + /*Consume another token from the input stream. Can only write sequentially! + * If you need 3 tokens ahead, you must consume() 3 times. + *

+ * Note that it is possible to overwrite tokens that have not been matched. + * For example, calling consume() 3 times when k=2, means that the first token + * consumed will be overwritten with the 3rd. + */ + override public void consume() + { + inputState.input.consume(); + } + + override public int LA(int i) + { + return inputState.input.LA(i); + } + + override public IToken LT(int i) + { + return inputState.input.LT(i); + } + + private void trace(string ee, string rname) + { + traceIndent(); + Console.Out.Write(ee + rname + ((inputState.guessing > 0) ? "; [guessing]" : "; ")); + for (int i = 1; i <= k; i++) + { + if (i != 1) + { + Console.Out.Write(", "); + } + + if (LT(i) != null) + { + Console.Out.Write("LA(" + i + ")==" + LT(i).getText()); + } + else + { + Console.Out.Write("LA(" + i + ")==ull"); + } + } + + Console.Out.WriteLine(""); + } + + override public void traceIn(string rname) + { + traceDepth += 1; + trace("> ", rname); + } + + override public void traceOut(string rname) + { + trace("< ", rname); + traceDepth -= 1; + } } diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/LexerSharedInputState.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/LexerSharedInputState.cs index c09dc3a9..bd4d219d 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/LexerSharedInputState.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/LexerSharedInputState.cs @@ -1,87 +1,85 @@ -using Stream = System.IO.Stream; -using TextReader = System.IO.TextReader; +using Stream = System.IO.Stream; +using TextReader = System.IO.TextReader; -namespace Spring.Expressions.Parser.antlr +namespace Spring.Expressions.Parser.antlr; +/*ANTLR Translator Generator + * Project led by Terence Parr at http://www.jGuru.com + * Software rights: http://www.antlr.org/license.html + * + * $Id:$ + */ + +// +// ANTLR C# Code Generator by Micheal Jordan +// Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com +// Anthony Oguntimehin +// +// With many thanks to Eric V. Smith from the ANTLR list. +// + +/*This object contains the data associated with an + * input stream of characters. Multiple lexers + * share a single LexerSharedInputState to lex + * the same input stream. + */ +public class LexerSharedInputState { - /*ANTLR Translator Generator - * Project led by Terence Parr at http://www.jGuru.com - * Software rights: http://www.antlr.org/license.html - * - * $Id:$ - */ - - // - // ANTLR C# Code Generator by Micheal Jordan - // Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com - // Anthony Oguntimehin - // - // With many thanks to Eric V. Smith from the ANTLR list. - // + protected internal int column; + protected internal int line; + protected internal int tokenStartColumn; + protected internal int tokenStartLine; + protected internal InputBuffer input; - /*This object contains the data associated with an - * input stream of characters. Multiple lexers - * share a single LexerSharedInputState to lex - * the same input stream. - */ - public class LexerSharedInputState - { - protected internal int column; - protected internal int line; - protected internal int tokenStartColumn; - protected internal int tokenStartLine; - protected internal InputBuffer input; - - /*What file (if known) caused the problem? */ - protected internal string filename; - - public int guessing; - - public LexerSharedInputState(InputBuffer inbuf) - { - initialize(); - input = inbuf; - } - - public LexerSharedInputState(Stream inStream) : this(new ByteBuffer(inStream)) - { - } - - public LexerSharedInputState(TextReader inReader) : this(new CharBuffer(inReader)) - { - } - - private void initialize() - { - column = 1; - line = 1; - tokenStartColumn = 1; - tokenStartLine = 1; - guessing = 0; - filename = null; - } - - public virtual void reset() - { - initialize(); - input.reset(); - } + /*What file (if known) caused the problem? */ + protected internal string filename; - public virtual void resetInput(InputBuffer ib) - { - reset(); - input = ib; - } + public int guessing; - public virtual void resetInput(Stream s) - { - reset(); - input = new ByteBuffer(s); - } + public LexerSharedInputState(InputBuffer inbuf) + { + initialize(); + input = inbuf; + } - public virtual void resetInput(TextReader tr) - { - reset(); - input = new CharBuffer(tr); - } - } -} \ No newline at end of file + public LexerSharedInputState(Stream inStream) : this(new ByteBuffer(inStream)) + { + } + + public LexerSharedInputState(TextReader inReader) : this(new CharBuffer(inReader)) + { + } + + private void initialize() + { + column = 1; + line = 1; + tokenStartColumn = 1; + tokenStartLine = 1; + guessing = 0; + filename = null; + } + + public virtual void reset() + { + initialize(); + input.reset(); + } + + public virtual void resetInput(InputBuffer ib) + { + reset(); + input = ib; + } + + public virtual void resetInput(Stream s) + { + reset(); + input = new ByteBuffer(s); + } + + public virtual void resetInput(TextReader tr) + { + reset(); + input = new CharBuffer(tr); + } +} diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/MismatchedCharException.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/MismatchedCharException.cs index d9ca8757..43f38b49 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/MismatchedCharException.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/MismatchedCharException.cs @@ -1,178 +1,179 @@ -using StringBuilder = System.Text.StringBuilder; +using StringBuilder = System.Text.StringBuilder; +using BitSet = Spring.Expressions.Parser.antlr.collections.impl.BitSet; -using BitSet = Spring.Expressions.Parser.antlr.collections.impl.BitSet; +namespace Spring.Expressions.Parser.antlr; +/*ANTLR Translator Generator + * Project led by Terence Parr at http://www.jGuru.com + * Software rights: http://www.antlr.org/license.html + * + * $Id:$ + */ -namespace Spring.Expressions.Parser.antlr +// +// ANTLR C# Code Generator by Micheal Jordan +// Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com +// Anthony Oguntimehin +// +// With many thanks to Eric V. Smith from the ANTLR list. +// + +[Serializable] +public class MismatchedCharException : RecognitionException { - /*ANTLR Translator Generator - * Project led by Terence Parr at http://www.jGuru.com - * Software rights: http://www.antlr.org/license.html - * - * $Id:$ - */ + /* + * Returns a clean error message (no line number/column information) + */ + override public string Message + { + get + { + StringBuilder sb = new StringBuilder(); - // - // ANTLR C# Code Generator by Micheal Jordan - // Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com - // Anthony Oguntimehin - // - // With many thanks to Eric V. Smith from the ANTLR list. - // + switch (mismatchType) + { + case CharTypeEnum.CharType: + sb.Append("expecting "); + appendCharName(sb, expecting); + sb.Append(", found "); + appendCharName(sb, foundChar); + break; - [Serializable] - public class MismatchedCharException : RecognitionException - { - /* - * Returns a clean error message (no line number/column information) - */ - override public string Message - { - get - { - StringBuilder sb = new StringBuilder(); + case CharTypeEnum.NotCharType: + sb.Append("expecting anything but '"); + appendCharName(sb, expecting); + sb.Append("'; got it anyway"); + break; - switch (mismatchType) - { - case CharTypeEnum.CharType: - sb.Append("expecting "); appendCharName(sb, expecting); - sb.Append(", found "); appendCharName(sb, foundChar); - break; + case CharTypeEnum.RangeType: + case CharTypeEnum.NotRangeType: + sb.Append("expecting token "); + if (mismatchType == CharTypeEnum.NotRangeType) + sb.Append("NOT "); + sb.Append("in range: "); + appendCharName(sb, expecting); + sb.Append(".."); + appendCharName(sb, upper); + sb.Append(", found "); + appendCharName(sb, foundChar); + break; - case CharTypeEnum.NotCharType: - sb.Append("expecting anything but '"); - appendCharName(sb, expecting); - sb.Append("'; got it anyway"); - break; + case CharTypeEnum.SetType: + case CharTypeEnum.NotSetType: + sb.Append("expecting " + (mismatchType == CharTypeEnum.NotSetType ? "NOT " : "") + "one of ("); + int[] elems = bset.toArray(); + for (int i = 0; i < elems.Length; i++) + { + appendCharName(sb, elems[i]); + } - case CharTypeEnum.RangeType: - case CharTypeEnum.NotRangeType: - sb.Append("expecting token "); - if (mismatchType == CharTypeEnum.NotRangeType) - sb.Append("NOT "); - sb.Append("in range: "); - appendCharName(sb, expecting); - sb.Append(".."); - appendCharName(sb, upper); - sb.Append(", found "); - appendCharName(sb, foundChar); - break; + sb.Append("), found "); + appendCharName(sb, foundChar); + break; - case CharTypeEnum.SetType: - case CharTypeEnum.NotSetType: - sb.Append("expecting " + (mismatchType == CharTypeEnum.NotSetType ? "NOT " : "") + "one of ("); - int[] elems = bset.toArray(); - for (int i = 0; i < elems.Length; i++) - { - appendCharName(sb, elems[i]); - } - sb.Append("), found "); - appendCharName(sb, foundChar); - break; + default: + sb.Append(base.Message); + break; + } - default: - sb.Append(base.Message); - break; - } - return sb.ToString(); - } - } + return sb.ToString(); + } + } - // Types of chars + // Types of chars - public enum CharTypeEnum - { - CharType = 1, - NotCharType = 2, - RangeType = 3, - NotRangeType = 4, - SetType = 5, - NotSetType = 6 - } + public enum CharTypeEnum + { + CharType = 1, + NotCharType = 2, + RangeType = 3, + NotRangeType = 4, + SetType = 5, + NotSetType = 6 + } - // One of the above - public CharTypeEnum mismatchType; + // One of the above + public CharTypeEnum mismatchType; - // what was found on the input stream - public int foundChar; + // what was found on the input stream + public int foundChar; - // For CHAR/NOT_CHAR and RANGE/NOT_RANGE - public int expecting; + // For CHAR/NOT_CHAR and RANGE/NOT_RANGE + public int expecting; - // For RANGE/NOT_RANGE (expecting is lower bound of range) - public int upper; + // For RANGE/NOT_RANGE (expecting is lower bound of range) + public int upper; - // For SET/NOT_SET - public BitSet bset; + // For SET/NOT_SET + public BitSet bset; - // who knows...they may want to ask scanner questions - public CharScanner scanner; + // who knows...they may want to ask scanner questions + public CharScanner scanner; - /* - * MismatchedCharException constructor comment. - */ - public MismatchedCharException() : base("Mismatched char") - { - } + /* + * MismatchedCharException constructor comment. + */ + public MismatchedCharException() : base("Mismatched char") + { + } - // Expected range / not range - public MismatchedCharException(char c, char lower, char upper_, bool matchNot, CharScanner scanner_) : - base("Mismatched char", scanner_.getFilename(), scanner_.getLine(), scanner_.getColumn()) - { - mismatchType = matchNot ? CharTypeEnum.NotRangeType : CharTypeEnum.RangeType; - foundChar = c; - expecting = lower; - upper = upper_; - scanner = scanner_; - } + // Expected range / not range + public MismatchedCharException(char c, char lower, char upper_, bool matchNot, CharScanner scanner_) : + base("Mismatched char", scanner_.getFilename(), scanner_.getLine(), scanner_.getColumn()) + { + mismatchType = matchNot ? CharTypeEnum.NotRangeType : CharTypeEnum.RangeType; + foundChar = c; + expecting = lower; + upper = upper_; + scanner = scanner_; + } - // Expected token / not token - public MismatchedCharException(char c, char expecting_, bool matchNot, CharScanner scanner_) : - base("Mismatched char", scanner_.getFilename(), scanner_.getLine(), scanner_.getColumn()) - { - mismatchType = matchNot ? CharTypeEnum.NotCharType : CharTypeEnum.CharType; - foundChar = c; - expecting = expecting_; - scanner = scanner_; - } + // Expected token / not token + public MismatchedCharException(char c, char expecting_, bool matchNot, CharScanner scanner_) : + base("Mismatched char", scanner_.getFilename(), scanner_.getLine(), scanner_.getColumn()) + { + mismatchType = matchNot ? CharTypeEnum.NotCharType : CharTypeEnum.CharType; + foundChar = c; + expecting = expecting_; + scanner = scanner_; + } - // Expected BitSet / not BitSet - public MismatchedCharException(char c, BitSet set_, bool matchNot, CharScanner scanner_) : - base("Mismatched char", scanner_.getFilename(), scanner_.getLine(), scanner_.getColumn()) - { - mismatchType = matchNot ? CharTypeEnum.NotSetType : CharTypeEnum.SetType; - foundChar = c; - bset = set_; - scanner = scanner_; - } + // Expected BitSet / not BitSet + public MismatchedCharException(char c, BitSet set_, bool matchNot, CharScanner scanner_) : + base("Mismatched char", scanner_.getFilename(), scanner_.getLine(), scanner_.getColumn()) + { + mismatchType = matchNot ? CharTypeEnum.NotSetType : CharTypeEnum.SetType; + foundChar = c; + bset = set_; + scanner = scanner_; + } - ///

- /// Append a char to the msg buffer. If special, then show escaped version - /// - /// Message buffer - /// Char to append - private void appendCharName(StringBuilder sb, int c) - { - switch (c) - { - case 65535 : - // 65535 = (char) -1 = EOF - sb.Append("''"); - break; - case '\n' : - sb.Append(@"'\n'"); - break; - case '\r' : - sb.Append(@"'\r'"); - break; - case '\t' : - sb.Append(@"'\t'"); - break; - default : - sb.Append('\''); - sb.Append((char) c); - sb.Append('\''); - break; - } - } - } + /// + /// Append a char to the msg buffer. If special, then show escaped version + /// + /// Message buffer + /// Char to append + private void appendCharName(StringBuilder sb, int c) + { + switch (c) + { + case 65535: + // 65535 = (char) -1 = EOF + sb.Append("''"); + break; + case '\n': + sb.Append(@"'\n'"); + break; + case '\r': + sb.Append(@"'\r'"); + break; + case '\t': + sb.Append(@"'\t'"); + break; + default: + sb.Append('\''); + sb.Append((char) c); + sb.Append('\''); + break; + } + } } diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/MismatchedTokenException.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/MismatchedTokenException.cs index 29395285..37ada530 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/MismatchedTokenException.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/MismatchedTokenException.cs @@ -1,213 +1,219 @@ -using StringBuilder = System.Text.StringBuilder; +using StringBuilder = System.Text.StringBuilder; +using BitSet = Spring.Expressions.Parser.antlr.collections.impl.BitSet; +using AST = Spring.Expressions.Parser.antlr.collections.AST; -using BitSet = Spring.Expressions.Parser.antlr.collections.impl.BitSet; -using AST = Spring.Expressions.Parser.antlr.collections.AST; +namespace Spring.Expressions.Parser.antlr; +/*ANTLR Translator Generator + * Project led by Terence Parr at http://www.jGuru.com + * Software rights: http://www.antlr.org/license.html + * + * $Id:$ + */ -namespace Spring.Expressions.Parser.antlr +// +// ANTLR C# Code Generator by Micheal Jordan +// Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com +// Anthony Oguntimehin +// +// With many thanks to Eric V. Smith from the ANTLR list. +// + +[Serializable] +public class MismatchedTokenException : RecognitionException { - /*ANTLR Translator Generator - * Project led by Terence Parr at http://www.jGuru.com - * Software rights: http://www.antlr.org/license.html - * - * $Id:$ - */ + // Token names array for formatting + internal string[] tokenNames; - // - // ANTLR C# Code Generator by Micheal Jordan - // Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com - // Anthony Oguntimehin - // - // With many thanks to Eric V. Smith from the ANTLR list. - // + // The token that was encountered + public IToken token; - [Serializable] - public class MismatchedTokenException : RecognitionException - { - // Token names array for formatting - internal string[] tokenNames; - // The token that was encountered - public IToken token; - // The offending AST node if tree walking - public AST node; + // The offending AST node if tree walking + public AST node; - internal string tokenText = null; // taken from node or token object + internal string tokenText = null; // taken from node or token object - // Types of tokens - public enum TokenTypeEnum - { - TokenType = 1, - NotTokenType = 2, - RangeType = 3, - NotRangeType = 4, - SetType = 5, - NotSetType = 6 - } - // One of the above - public TokenTypeEnum mismatchType; + // Types of tokens + public enum TokenTypeEnum + { + TokenType = 1, + NotTokenType = 2, + RangeType = 3, + NotRangeType = 4, + SetType = 5, + NotSetType = 6 + } - // For TOKEN/NOT_TOKEN and RANGE/NOT_RANGE - public int expecting; + // One of the above + public TokenTypeEnum mismatchType; - // For RANGE/NOT_RANGE (expecting is lower bound of range) - public int upper; + // For TOKEN/NOT_TOKEN and RANGE/NOT_RANGE + public int expecting; - // For SET/NOT_SET - public BitSet bset; + // For RANGE/NOT_RANGE (expecting is lower bound of range) + public int upper; - /*Looking for AST wildcard, didn't find it */ - public MismatchedTokenException() : base("Mismatched Token: expecting any AST node", "", - 1, - 1) - { - } + // For SET/NOT_SET + public BitSet bset; - // Expected range / not range - public MismatchedTokenException(string[] tokenNames_, AST node_, int lower, int upper_, bool matchNot) : - base("Mismatched Token", "", - 1, - 1) - { - tokenNames = tokenNames_; - node = node_; - if (node_ == null) - { - tokenText = ""; - } - else - { - tokenText = node_.ToString(); - } - mismatchType = matchNot ? TokenTypeEnum.NotRangeType : TokenTypeEnum.RangeType; - expecting = lower; - upper = upper_; - } + /*Looking for AST wildcard, didn't find it */ + public MismatchedTokenException() : base("Mismatched Token: expecting any AST node", "", -1, -1) + { + } - // Expected token / not token - public MismatchedTokenException(string[] tokenNames_, AST node_, int expecting_, bool matchNot) : - base("Mismatched Token", "", - 1, - 1) - { - tokenNames = tokenNames_; - node = node_; - if (node_ == null) - { - tokenText = ""; - } - else - { - tokenText = node_.ToString(); - } - mismatchType = matchNot ? TokenTypeEnum.NotTokenType : TokenTypeEnum.TokenType; - expecting = expecting_; - } + // Expected range / not range + public MismatchedTokenException(string[] tokenNames_, AST node_, int lower, int upper_, bool matchNot) : + base("Mismatched Token", "", -1, -1) + { + tokenNames = tokenNames_; + node = node_; + if (node_ == null) + { + tokenText = ""; + } + else + { + tokenText = node_.ToString(); + } - // Expected BitSet / not BitSet - public MismatchedTokenException(string[] tokenNames_, AST node_, BitSet set_, bool matchNot) : - base("Mismatched Token", "", - 1, - 1) - { - tokenNames = tokenNames_; - node = node_; - if (node_ == null) - { - tokenText = ""; - } - else - { - tokenText = node_.ToString(); - } - mismatchType = matchNot ? TokenTypeEnum.NotSetType : TokenTypeEnum.SetType; - bset = set_; - } + mismatchType = matchNot ? TokenTypeEnum.NotRangeType : TokenTypeEnum.RangeType; + expecting = lower; + upper = upper_; + } - // Expected range / not range - public MismatchedTokenException(string[] tokenNames_, IToken token_, int lower, int upper_, bool matchNot, string fileName_) : - base("Mismatched Token", fileName_, token_.getLine(), token_.getColumn()) - { - tokenNames = tokenNames_; - token = token_; - tokenText = token_.getText(); - mismatchType = matchNot ? TokenTypeEnum.NotRangeType : TokenTypeEnum.RangeType; - expecting = lower; - upper = upper_; - } + // Expected token / not token + public MismatchedTokenException(string[] tokenNames_, AST node_, int expecting_, bool matchNot) : + base("Mismatched Token", "", -1, -1) + { + tokenNames = tokenNames_; + node = node_; + if (node_ == null) + { + tokenText = ""; + } + else + { + tokenText = node_.ToString(); + } - // Expected token / not token - public MismatchedTokenException(string[] tokenNames_, IToken token_, int expecting_, bool matchNot, string fileName_) : - base("Mismatched Token", fileName_, token_.getLine(), token_.getColumn()) - { - tokenNames = tokenNames_; - token = token_; - tokenText = token_.getText(); - mismatchType = matchNot ? TokenTypeEnum.NotTokenType : TokenTypeEnum.TokenType; - expecting = expecting_; - } + mismatchType = matchNot ? TokenTypeEnum.NotTokenType : TokenTypeEnum.TokenType; + expecting = expecting_; + } - // Expected BitSet / not BitSet - public MismatchedTokenException(string[] tokenNames_, IToken token_, BitSet set_, bool matchNot, string fileName_) : - base("Mismatched Token", fileName_, token_.getLine(), token_.getColumn()) - { - tokenNames = tokenNames_; - token = token_; - tokenText = token_.getText(); - mismatchType = matchNot ? TokenTypeEnum.NotSetType : TokenTypeEnum.SetType; - bset = set_; - } + // Expected BitSet / not BitSet + public MismatchedTokenException(string[] tokenNames_, AST node_, BitSet set_, bool matchNot) : + base("Mismatched Token", "", -1, -1) + { + tokenNames = tokenNames_; + node = node_; + if (node_ == null) + { + tokenText = ""; + } + else + { + tokenText = node_.ToString(); + } - /* - * Returns a clean error message (no line number/column information) - */ - override public string Message - { - get - { - StringBuilder sb = new StringBuilder(); + mismatchType = matchNot ? TokenTypeEnum.NotSetType : TokenTypeEnum.SetType; + bset = set_; + } - switch (mismatchType) - { - case TokenTypeEnum.TokenType: - sb.Append("expecting " + tokenName(expecting) + ", found '" + tokenText + "'"); - break; + // Expected range / not range + public MismatchedTokenException(string[] tokenNames_, IToken token_, int lower, int upper_, bool matchNot, string fileName_) : + base("Mismatched Token", fileName_, token_.getLine(), token_.getColumn()) + { + tokenNames = tokenNames_; + token = token_; + tokenText = token_.getText(); + mismatchType = matchNot ? TokenTypeEnum.NotRangeType : TokenTypeEnum.RangeType; + expecting = lower; + upper = upper_; + } - case TokenTypeEnum.NotTokenType: - sb.Append("expecting anything but " + tokenName(expecting) + "; got it anyway"); - break; + // Expected token / not token + public MismatchedTokenException(string[] tokenNames_, IToken token_, int expecting_, bool matchNot, string fileName_) : + base("Mismatched Token", fileName_, token_.getLine(), token_.getColumn()) + { + tokenNames = tokenNames_; + token = token_; + tokenText = token_.getText(); + mismatchType = matchNot ? TokenTypeEnum.NotTokenType : TokenTypeEnum.TokenType; + expecting = expecting_; + } - case TokenTypeEnum.RangeType: - sb.Append("expecting token in range: " + tokenName(expecting) + ".." + tokenName(upper) + ", found '" + tokenText + "'"); - break; + // Expected BitSet / not BitSet + public MismatchedTokenException(string[] tokenNames_, IToken token_, BitSet set_, bool matchNot, string fileName_) : + base("Mismatched Token", fileName_, token_.getLine(), token_.getColumn()) + { + tokenNames = tokenNames_; + token = token_; + tokenText = token_.getText(); + mismatchType = matchNot ? TokenTypeEnum.NotSetType : TokenTypeEnum.SetType; + bset = set_; + } - case TokenTypeEnum.NotRangeType: - sb.Append("expecting token NOT in range: " + tokenName(expecting) + ".." + tokenName(upper) + ", found '" + tokenText + "'"); - break; + /* + * Returns a clean error message (no line number/column information) + */ + override public string Message + { + get + { + StringBuilder sb = new StringBuilder(); - case TokenTypeEnum.SetType: case TokenTypeEnum.NotSetType: - sb.Append("expecting " + (mismatchType == TokenTypeEnum.NotSetType ? "NOT " : "") + "one of ("); - int[] elems = bset.toArray(); - for (int i = 0; i < elems.Length; i++) - { - sb.Append(" "); - sb.Append(tokenName(elems[i])); - } - sb.Append("), found '" + tokenText + "'"); - break; + switch (mismatchType) + { + case TokenTypeEnum.TokenType: + sb.Append("expecting " + tokenName(expecting) + ", found '" + tokenText + "'"); + break; - default: - sb.Append(base.Message); - break; - } - return sb.ToString(); - } - } + case TokenTypeEnum.NotTokenType: + sb.Append("expecting anything but " + tokenName(expecting) + "; got it anyway"); + break; - private string tokenName(int tokenType) - { - if (tokenType == Token.INVALID_TYPE) - { - return ""; - } - else if (tokenType < 0 || tokenType >= tokenNames.Length) - { - return "<" + tokenType.ToString() + ">"; - } - else - { - return tokenNames[tokenType]; - } - } - } + case TokenTypeEnum.RangeType: + sb.Append("expecting token in range: " + tokenName(expecting) + ".." + tokenName(upper) + ", found '" + tokenText + "'"); + break; + + case TokenTypeEnum.NotRangeType: + sb.Append("expecting token NOT in range: " + tokenName(expecting) + ".." + tokenName(upper) + ", found '" + tokenText + "'"); + break; + + case TokenTypeEnum.SetType: + case TokenTypeEnum.NotSetType: + sb.Append("expecting " + (mismatchType == TokenTypeEnum.NotSetType ? "NOT " : "") + "one of ("); + int[] elems = bset.toArray(); + for (int i = 0; i < elems.Length; i++) + { + sb.Append(" "); + sb.Append(tokenName(elems[i])); + } + + sb.Append("), found '" + tokenText + "'"); + break; + + default: + sb.Append(base.Message); + break; + } + + return sb.ToString(); + } + } + + private string tokenName(int tokenType) + { + if (tokenType == Token.INVALID_TYPE) + { + return ""; + } + else if (tokenType < 0 || tokenType >= tokenNames.Length) + { + return "<" + tokenType.ToString() + ">"; + } + else + { + return tokenNames[tokenType]; + } + } } diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/NoViableAltException.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/NoViableAltException.cs index c27b4365..594ae711 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/NoViableAltException.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/NoViableAltException.cs @@ -1,59 +1,58 @@ -using AST = Spring.Expressions.Parser.antlr.collections.AST; +using AST = Spring.Expressions.Parser.antlr.collections.AST; -namespace Spring.Expressions.Parser.antlr +namespace Spring.Expressions.Parser.antlr; +/*ANTLR Translator Generator + * Project led by Terence Parr at http://www.jGuru.com + * Software rights: http://www.antlr.org/license.html + * + * $Id:$ + */ + +// +// ANTLR C# Code Generator by Micheal Jordan +// Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com +// Anthony Oguntimehin +// +// With many thanks to Eric V. Smith from the ANTLR list. +// + +[Serializable] +public class NoViableAltException : RecognitionException { - /*ANTLR Translator Generator - * Project led by Terence Parr at http://www.jGuru.com - * Software rights: http://www.antlr.org/license.html - * - * $Id:$ - */ + public IToken token; + public AST node; // handles parsing and treeparsing - // - // ANTLR C# Code Generator by Micheal Jordan - // Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com - // Anthony Oguntimehin - // - // With many thanks to Eric V. Smith from the ANTLR list. - // + public NoViableAltException(AST t) : base("NoViableAlt", "", -1, -1) + { + node = t; + } - [Serializable] - public class NoViableAltException : RecognitionException - { - public IToken token; - public AST node; // handles parsing and treeparsing + public NoViableAltException(IToken t, string fileName_) : + base("NoViableAlt", fileName_, t.getLine(), t.getColumn()) + { + token = t; + } - public NoViableAltException(AST t) : base("NoViableAlt", "", - 1, - 1) - { - node = t; - } + /* + * Returns a clean error message (no line number/column information) + */ + override public string Message + { + get + { + if (token != null) + { + //return "unexpected token: " + token.getText(); + return "unexpected token: " + token.ToString(); + } - public NoViableAltException(IToken t, string fileName_) : - base("NoViableAlt", fileName_, t.getLine(), t.getColumn()) - { - token = t; - } + // must a tree parser error if token==null + if ((node == null) || (node == TreeParser.ASTNULL)) + { + return "unexpected end of subtree"; + } - /* - * Returns a clean error message (no line number/column information) - */ - override public string Message - { - get - { - if (token != null) - { - //return "unexpected token: " + token.getText(); - return "unexpected token: " + token.ToString(); - } - - // must a tree parser error if token==null - if ( (node==null) || (node==TreeParser.ASTNULL) ) - { - return "unexpected end of subtree"; - } - return "unexpected AST node: " + node.ToString(); - } - } - } + return "unexpected AST node: " + node.ToString(); + } + } } diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/NoViableAltForCharException.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/NoViableAltForCharException.cs index 7f453540..ae661cd0 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/NoViableAltForCharException.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/NoViableAltForCharException.cs @@ -1,65 +1,64 @@ -using StringBuilder = System.Text.StringBuilder; +using StringBuilder = System.Text.StringBuilder; -namespace Spring.Expressions.Parser.antlr +namespace Spring.Expressions.Parser.antlr; +/*ANTLR Translator Generator + * Project led by Terence Parr at http://www.jGuru.com + * Software rights: http://www.antlr.org/license.html + * + * $Id:$ + */ + +// +// ANTLR C# Code Generator by Micheal Jordan +// Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com +// Anthony Oguntimehin +// +// With many thanks to Eric V. Smith from the ANTLR list. +// + +[Serializable] +public class NoViableAltForCharException : RecognitionException { - /*ANTLR Translator Generator - * Project led by Terence Parr at http://www.jGuru.com - * Software rights: http://www.antlr.org/license.html - * - * $Id:$ - */ + public char foundChar; - // - // ANTLR C# Code Generator by Micheal Jordan - // Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com - // Anthony Oguntimehin - // - // With many thanks to Eric V. Smith from the ANTLR list. - // + public NoViableAltForCharException(char c, CharScanner scanner) : + base("NoViableAlt", scanner.getFilename(), scanner.getLine(), scanner.getColumn()) + { + foundChar = c; + } - [Serializable] - public class NoViableAltForCharException : RecognitionException - { - public char foundChar; + public NoViableAltForCharException(char c, string fileName, int line, int column) : + base("NoViableAlt", fileName, line, column) + { + foundChar = c; + } - public NoViableAltForCharException(char c, CharScanner scanner) : - base("NoViableAlt", scanner.getFilename(), scanner.getLine(), scanner.getColumn()) - { - foundChar = c; - } + /* + * Returns a clean error message (no line number/column information) + */ + override public string Message + { + get + { + StringBuilder mesg = new StringBuilder("unexpected char: "); - public NoViableAltForCharException(char c, string fileName, int line, int column) : - base("NoViableAlt", fileName, line, column) - { - foundChar = c; - } + // I'm trying to mirror a change in the C++ stuff. + // But java seems to lack something isprint-ish.. + // so we do it manually. This is probably too restrictive. - /* - * Returns a clean error message (no line number/column information) - */ - override public string Message - { - get - { - StringBuilder mesg = new StringBuilder("unexpected char: "); + if ((foundChar >= ' ') && (foundChar <= '~')) + { + mesg.Append('\''); + mesg.Append(foundChar); + mesg.Append('\''); + } + else + { + mesg.Append("0x"); + mesg.Append(((int) foundChar).ToString("X")); + } - // I'm trying to mirror a change in the C++ stuff. - // But java seems to lack something isprint-ish.. - // so we do it manually. This is probably too restrictive. - - if ((foundChar >= ' ') && (foundChar <= '~')) - { - mesg.Append('\''); - mesg.Append(foundChar); - mesg.Append('\''); - } - else - { - mesg.Append("0x"); - mesg.Append(((int)foundChar).ToString("X")); - } - return mesg.ToString(); - } - } - } + return mesg.ToString(); + } + } } diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/ParseTree.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/ParseTree.cs index c39f80c6..19d6133a 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/ParseTree.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/ParseTree.cs @@ -1,74 +1,74 @@ -namespace Spring.Expressions.Parser.antlr +namespace Spring.Expressions.Parser.antlr; + +/* ANTLR Translator Generator + * Project led by Terence Parr at http://www.jGuru.com + * Software rights: http://www.antlr.org/license.html + */ + +// +// ANTLR C# Code Generator by Micheal Jordan +// Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com +// Anthony Oguntimehin +// +using StringBuilder = System.Text.StringBuilder; +using AST = antlr.collections.AST; + +public abstract class ParseTree : BaseAST { - /* ANTLR Translator Generator - * Project led by Terence Parr at http://www.jGuru.com - * Software rights: http://www.antlr.org/license.html - */ + /// + /// Walk parse tree and return requested number of derivation steps. + /// If steps less-than 0, return node text. If steps equals 1, return derivation + /// string at step. + /// + /// derivation steps + /// + public string getLeftmostDerivationStep(int step) + { + if (step <= 0) + { + return ToString(); + } - // - // ANTLR C# Code Generator by Micheal Jordan - // Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com - // Anthony Oguntimehin - // + StringBuilder buf = new StringBuilder(2000); + getLeftmostDerivation(buf, step); + return buf.ToString(); + } - using StringBuilder = System.Text.StringBuilder; - using AST = antlr.collections.AST; + public string getLeftmostDerivation(int maxSteps) + { + StringBuilder buf = new StringBuilder(2000); + buf.Append(" " + this.ToString()); + buf.Append("\n"); + for (int d = 1; d < maxSteps; d++) + { + buf.Append(" =>"); + buf.Append(getLeftmostDerivationStep(d)); + buf.Append("\n"); + } - public abstract class ParseTree : BaseAST - { - /// - /// Walk parse tree and return requested number of derivation steps. - /// If steps less-than 0, return node text. If steps equals 1, return derivation - /// string at step. - /// - /// derivation steps - /// - public string getLeftmostDerivationStep(int step) - { - if ( step <= 0 ) - { - return ToString(); - } - StringBuilder buf = new StringBuilder (2000); - getLeftmostDerivation(buf, step); - return buf.ToString(); - } + return buf.ToString(); + } - public string getLeftmostDerivation(int maxSteps) - { - StringBuilder buf = new StringBuilder(2000); - buf.Append(" " + this.ToString()); - buf.Append("\n"); - for (int d=1; d < maxSteps; d++) - { - buf.Append(" =>"); - buf.Append(getLeftmostDerivationStep(d)); - buf.Append("\n"); - } - return buf.ToString(); - } + /// + /// Get derivation and return how many you did (less than requested for + /// subtree roots. + /// + /// string buffer + /// derivation steps + /// + protected internal abstract int getLeftmostDerivation(StringBuilder buf, int step); - /// - /// Get derivation and return how many you did (less than requested for - /// subtree roots. - /// - /// string buffer - /// derivation steps - /// - protected internal abstract int getLeftmostDerivation(StringBuilder buf, int step); + // just satisfy BaseAST interface; unused as we manually create nodes - // just satisfy BaseAST interface; unused as we manually create nodes + public override void initialize(int i, string s) + { + } - public override void initialize(int i, string s) - { - } - - public override void initialize(AST ast) - { - } - - public override void initialize(IToken token) - { - } - } + public override void initialize(AST ast) + { + } + + public override void initialize(IToken token) + { + } } diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/ParseTreeRule.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/ParseTreeRule.cs index 19d89192..43c8b5da 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/ParseTreeRule.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/ParseTreeRule.cs @@ -1,91 +1,91 @@ -namespace Spring.Expressions.Parser.antlr +namespace Spring.Expressions.Parser.antlr; + +/* ANTLR Translator Generator + * Project led by Terence Parr at http://www.jGuru.com + * Software rights: http://www.antlr.org/license.html + */ + +// +// ANTLR C# Code Generator by Micheal Jordan +// Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com +// Anthony Oguntimehin +// +using StringBuilder = System.Text.StringBuilder; +using AST = antlr.collections.AST; + +public class ParseTreeRule : ParseTree { + public const int INVALID_ALT = -1; - /* ANTLR Translator Generator - * Project led by Terence Parr at http://www.jGuru.com - * Software rights: http://www.antlr.org/license.html - */ + protected string ruleName; + protected int altNumber; // unused until I modify antlr to record this - // - // ANTLR C# Code Generator by Micheal Jordan - // Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com - // Anthony Oguntimehin - // + public ParseTreeRule(string ruleName) : this(ruleName, INVALID_ALT) + { + } - using StringBuilder = System.Text.StringBuilder; - using AST = antlr.collections.AST; + public ParseTreeRule(string ruleName, int altNumber) + { + this.ruleName = ruleName; + this.altNumber = altNumber; + } - public class ParseTreeRule : ParseTree - { - public const int INVALID_ALT = -1; + public string getRuleName() + { + return ruleName; + } - protected string ruleName; - protected int altNumber; // unused until I modify antlr to record this + /// + /// Do a step-first walk, building up a buffer of tokens until + /// you've reached a particular step and print out any rule subroots + /// insteads of descending. + /// + /// derivation buffer + /// derivation steps + /// + protected internal override int getLeftmostDerivation(StringBuilder buf, int step) + { + int numReplacements = 0; + if (step <= 0) + { + buf.Append(' '); + buf.Append(ToString()); + return numReplacements; + } - public ParseTreeRule(string ruleName) : this(ruleName, INVALID_ALT) - { - } + AST child = getFirstChild(); + numReplacements = 1; + // walk child printing them out, descending into at most one + while (child != null) + { + if ((numReplacements >= step) || (child is ParseTreeToken)) + { + buf.Append(' '); + buf.Append(child.ToString()); + } + else + { + // descend for at least one more derivation; update count + int remainingReplacements = step - numReplacements; + int n = ((ParseTree) child).getLeftmostDerivation(buf, remainingReplacements); + numReplacements += n; + } - public ParseTreeRule(string ruleName, int altNumber) - { - this.ruleName = ruleName; - this.altNumber = altNumber; - } + child = child.getNextSibling(); + } - public string getRuleName() - { - return ruleName; - } + return numReplacements; + } - /// - /// Do a step-first walk, building up a buffer of tokens until - /// you've reached a particular step and print out any rule subroots - /// insteads of descending. - /// - /// derivation buffer - /// derivation steps - /// - protected internal override int getLeftmostDerivation(StringBuilder buf, int step) - { - int numReplacements = 0; - if ( step <= 0 ) - { - buf.Append(' '); - buf.Append(ToString()); - return numReplacements; - } - AST child = getFirstChild(); - numReplacements = 1; - // walk child printing them out, descending into at most one - while ( child != null ) - { - if ( (numReplacements >= step) || (child is ParseTreeToken) ) - { - buf.Append(' '); - buf.Append(child.ToString()); - } - else - { - // descend for at least one more derivation; update count - int remainingReplacements = step - numReplacements; - int n = ((ParseTree) child).getLeftmostDerivation(buf, remainingReplacements); - numReplacements += n; - } - child = child.getNextSibling(); - } - return numReplacements; - } - - public override string ToString() - { - if ( altNumber == INVALID_ALT ) - { - return '<'+ruleName+'>'; - } - else - { - return '<'+ruleName+"["+altNumber+"]>"; - } - } - } + public override string ToString() + { + if (altNumber == INVALID_ALT) + { + return '<' + ruleName + '>'; + } + else + { + return '<' + ruleName + "[" + altNumber + "]>"; + } + } } diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/ParseTreeToken.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/ParseTreeToken.cs index 53d4e85b..6601d5a1 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/ParseTreeToken.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/ParseTreeToken.cs @@ -1,42 +1,40 @@ -namespace Spring.Expressions.Parser.antlr +namespace Spring.Expressions.Parser.antlr; + +/* ANTLR Translator Generator + * Project led by Terence Parr at http://www.jGuru.com + * Software rights: http://www.antlr.org/license.html + */ + +// +// ANTLR C# Code Generator by Micheal Jordan +// Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com +// Anthony Oguntimehin +// +using StringBuilder = System.Text.StringBuilder; + +public class ParseTreeToken : ParseTree { + protected IToken token; - /* ANTLR Translator Generator - * Project led by Terence Parr at http://www.jGuru.com - * Software rights: http://www.antlr.org/license.html - */ + public ParseTreeToken(IToken token) + { + this.token = token; + } - // - // ANTLR C# Code Generator by Micheal Jordan - // Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com - // Anthony Oguntimehin - // + protected override internal int getLeftmostDerivation(StringBuilder buf, int step) + { + buf.Append(' '); + buf.Append(ToString()); + return step; // did on replacements + } - using StringBuilder = System.Text.StringBuilder; + public override string ToString() + { + if (token != null) + { + return token.getText(); + } - public class ParseTreeToken : ParseTree - { - protected IToken token; - - public ParseTreeToken(IToken token) - { - this.token = token; - } - - protected override internal int getLeftmostDerivation(StringBuilder buf, int step) - { - buf.Append(' '); - buf.Append(ToString()); - return step; // did on replacements - } - - public override string ToString() - { - if ( token != null ) - { - return token.getText(); - } - return ""; - } - } + return ""; + } } diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/Parser.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/Parser.cs index d58f87a1..af308e47 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/Parser.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/Parser.cs @@ -1,504 +1,524 @@ using Spring.Expressions.Parser.antlr.debug; -using EventHandlerList = System.ComponentModel.EventHandlerList; - -using BitSet = Spring.Expressions.Parser.antlr.collections.impl.BitSet; -using AST = Spring.Expressions.Parser.antlr.collections.AST; -using MessageListener = Spring.Expressions.Parser.antlr.debug.MessageListener; -using ParserListener = Spring.Expressions.Parser.antlr.debug.ParserListener; -using ParserMatchListener = Spring.Expressions.Parser.antlr.debug.ParserMatchListener; -using ParserTokenListener = Spring.Expressions.Parser.antlr.debug.ParserTokenListener; -using SemanticPredicateListener = Spring.Expressions.Parser.antlr.debug.SemanticPredicateListener; -using SyntacticPredicateListener = Spring.Expressions.Parser.antlr.debug.SyntacticPredicateListener; -using TraceListener = Spring.Expressions.Parser.antlr.debug.TraceListener; +using EventHandlerList = System.ComponentModel.EventHandlerList; +using BitSet = Spring.Expressions.Parser.antlr.collections.impl.BitSet; +using AST = Spring.Expressions.Parser.antlr.collections.AST; +using MessageListener = Spring.Expressions.Parser.antlr.debug.MessageListener; +using ParserListener = Spring.Expressions.Parser.antlr.debug.ParserListener; +using ParserMatchListener = Spring.Expressions.Parser.antlr.debug.ParserMatchListener; +using ParserTokenListener = Spring.Expressions.Parser.antlr.debug.ParserTokenListener; +using SemanticPredicateListener = Spring.Expressions.Parser.antlr.debug.SemanticPredicateListener; +using SyntacticPredicateListener = Spring.Expressions.Parser.antlr.debug.SyntacticPredicateListener; +using TraceListener = Spring.Expressions.Parser.antlr.debug.TraceListener; /* - private Vector messageListeners; - private Vector newLineListeners; - private Vector matchListeners; - private Vector tokenListeners; - private Vector semPredListeners; - private Vector synPredListeners; - private Vector traceListeners; + private Vector messageListeners; + private Vector newLineListeners; + private Vector matchListeners; + private Vector tokenListeners; + private Vector semPredListeners; + private Vector synPredListeners; + private Vector traceListeners; */ -namespace Spring.Expressions.Parser.antlr +namespace Spring.Expressions.Parser.antlr; +/*ANTLR Translator Generator + * Project led by Terence Parr at http://www.jGuru.com + * Software rights: http://www.antlr.org/license.html + * + * $Id:$ + */ + +// +// ANTLR C# Code Generator by Micheal Jordan +// Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com +// Anthony Oguntimehin +// +// With many thanks to Eric V. Smith from the ANTLR list. +// + +public abstract class Parser : IParserDebugSubject { - /*ANTLR Translator Generator - * Project led by Terence Parr at http://www.jGuru.com - * Software rights: http://www.antlr.org/license.html - * - * $Id:$ - */ + // Used to store event delegates + private EventHandlerList events_ = new EventHandlerList(); - // - // ANTLR C# Code Generator by Micheal Jordan - // Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com - // Anthony Oguntimehin - // - // With many thanks to Eric V. Smith from the ANTLR list. - // + protected internal EventHandlerList Events + { + get { return events_; } + } - public abstract class Parser : IParserDebugSubject - { - // Used to store event delegates - private EventHandlerList events_ = new EventHandlerList(); + // The unique keys for each event that Parser [objects] can generate + internal static readonly object EnterRuleEventKey = new object(); + internal static readonly object ExitRuleEventKey = new object(); + internal static readonly object DoneEventKey = new object(); + internal static readonly object ReportErrorEventKey = new object(); + internal static readonly object ReportWarningEventKey = new object(); + internal static readonly object NewLineEventKey = new object(); + internal static readonly object MatchEventKey = new object(); + internal static readonly object MatchNotEventKey = new object(); + internal static readonly object MisMatchEventKey = new object(); + internal static readonly object MisMatchNotEventKey = new object(); + internal static readonly object ConsumeEventKey = new object(); + internal static readonly object LAEventKey = new object(); + internal static readonly object SemPredEvaluatedEventKey = new object(); + internal static readonly object SynPredStartedEventKey = new object(); + internal static readonly object SynPredFailedEventKey = new object(); + internal static readonly object SynPredSucceededEventKey = new object(); - protected internal EventHandlerList Events - { - get { return events_; } - } + protected internal ParserSharedInputState inputState; - // The unique keys for each event that Parser [objects] can generate - internal static readonly object EnterRuleEventKey = new object(); - internal static readonly object ExitRuleEventKey = new object(); - internal static readonly object DoneEventKey = new object(); - internal static readonly object ReportErrorEventKey = new object(); - internal static readonly object ReportWarningEventKey = new object(); - internal static readonly object NewLineEventKey = new object(); - internal static readonly object MatchEventKey = new object(); - internal static readonly object MatchNotEventKey = new object(); - internal static readonly object MisMatchEventKey = new object(); - internal static readonly object MisMatchNotEventKey = new object(); - internal static readonly object ConsumeEventKey = new object(); - internal static readonly object LAEventKey = new object(); - internal static readonly object SemPredEvaluatedEventKey = new object(); - internal static readonly object SynPredStartedEventKey = new object(); - internal static readonly object SynPredFailedEventKey = new object(); - internal static readonly object SynPredSucceededEventKey = new object(); + /*Nesting level of registered handlers */ + // protected int exceptionLevel = 0; - protected internal ParserSharedInputState inputState; + /*Table of token type to token names */ + protected internal string[] tokenNames; - /*Nesting level of registered handlers */ - // protected int exceptionLevel = 0; + /*AST return value for a rule is squirreled away here */ + protected internal AST returnAST; - /*Table of token type to token names */ - protected internal string[] tokenNames; + /*AST support code; parser and treeparser delegate to this object */ + protected internal ASTFactory astFactory = new ASTFactory(); - /*AST return value for a rule is squirreled away here */ - protected internal AST returnAST; + private bool ignoreInvalidDebugCalls = false; - /*AST support code; parser and treeparser delegate to this object */ - protected internal ASTFactory astFactory = new ASTFactory(); + /*Used to keep track of indentdepth for traceIn/Out */ + protected internal int traceDepth = 0; - private bool ignoreInvalidDebugCalls = false; + public Parser() + { + inputState = new ParserSharedInputState(); + } - /*Used to keep track of indentdepth for traceIn/Out */ - protected internal int traceDepth = 0; + public Parser(ParserSharedInputState state) + { + inputState = state; + } - public Parser() - { - inputState = new ParserSharedInputState(); - } + /// + /// + /// + public event TraceEventHandler EnterRule + { + add { Events.AddHandler(EnterRuleEventKey, value); } + remove { Events.RemoveHandler(EnterRuleEventKey, value); } + } - public Parser(ParserSharedInputState state) - { - inputState = state; - } + public event TraceEventHandler ExitRule + { + add { Events.AddHandler(ExitRuleEventKey, value); } + remove { Events.RemoveHandler(ExitRuleEventKey, value); } + } - /// - /// - /// + public event TraceEventHandler Done + { + add { Events.AddHandler(DoneEventKey, value); } + remove { Events.RemoveHandler(DoneEventKey, value); } + } - public event TraceEventHandler EnterRule - { - add { Events.AddHandler(EnterRuleEventKey, value); } - remove { Events.RemoveHandler(EnterRuleEventKey, value); } - } + public event MessageEventHandler ErrorReported + { + add { Events.AddHandler(ReportErrorEventKey, value); } + remove { Events.RemoveHandler(ReportErrorEventKey, value); } + } - public event TraceEventHandler ExitRule - { - add { Events.AddHandler(ExitRuleEventKey, value); } - remove { Events.RemoveHandler(ExitRuleEventKey, value); } - } + public event MessageEventHandler WarningReported + { + add { Events.AddHandler(ReportWarningEventKey, value); } + remove { Events.RemoveHandler(ReportWarningEventKey, value); } + } - public event TraceEventHandler Done - { - add { Events.AddHandler(DoneEventKey, value); } - remove { Events.RemoveHandler(DoneEventKey, value); } - } + public event MatchEventHandler MatchedToken + { + add { Events.AddHandler(MatchEventKey, value); } + remove { Events.RemoveHandler(MatchEventKey, value); } + } - public event MessageEventHandler ErrorReported - { - add { Events.AddHandler(ReportErrorEventKey, value); } - remove { Events.RemoveHandler(ReportErrorEventKey, value); } - } + public event MatchEventHandler MatchedNotToken + { + add { Events.AddHandler(MatchNotEventKey, value); } + remove { Events.RemoveHandler(MatchNotEventKey, value); } + } - public event MessageEventHandler WarningReported - { - add { Events.AddHandler(ReportWarningEventKey, value); } - remove { Events.RemoveHandler(ReportWarningEventKey, value); } - } + public event MatchEventHandler MisMatchedToken + { + add { Events.AddHandler(MisMatchEventKey, value); } + remove { Events.RemoveHandler(MisMatchEventKey, value); } + } - public event MatchEventHandler MatchedToken - { - add { Events.AddHandler(MatchEventKey, value); } - remove { Events.RemoveHandler(MatchEventKey, value); } - } + public event MatchEventHandler MisMatchedNotToken + { + add { Events.AddHandler(MisMatchNotEventKey, value); } + remove { Events.RemoveHandler(MisMatchNotEventKey, value); } + } - public event MatchEventHandler MatchedNotToken - { - add { Events.AddHandler(MatchNotEventKey, value); } - remove { Events.RemoveHandler(MatchNotEventKey, value); } - } + public event TokenEventHandler ConsumedToken + { + add { Events.AddHandler(ConsumeEventKey, value); } + remove { Events.RemoveHandler(ConsumeEventKey, value); } + } - public event MatchEventHandler MisMatchedToken - { - add { Events.AddHandler(MisMatchEventKey, value); } - remove { Events.RemoveHandler(MisMatchEventKey, value); } - } + public event TokenEventHandler TokenLA + { + add { Events.AddHandler(LAEventKey, value); } + remove { Events.RemoveHandler(LAEventKey, value); } + } - public event MatchEventHandler MisMatchedNotToken - { - add { Events.AddHandler(MisMatchNotEventKey, value); } - remove { Events.RemoveHandler(MisMatchNotEventKey, value); } - } + public event SemanticPredicateEventHandler SemPredEvaluated + { + add { Events.AddHandler(SemPredEvaluatedEventKey, value); } + remove { Events.RemoveHandler(SemPredEvaluatedEventKey, value); } + } - public event TokenEventHandler ConsumedToken - { - add { Events.AddHandler(ConsumeEventKey, value); } - remove { Events.RemoveHandler(ConsumeEventKey, value); } - } + public event SyntacticPredicateEventHandler SynPredStarted + { + add { Events.AddHandler(SynPredStartedEventKey, value); } + remove { Events.RemoveHandler(SynPredStartedEventKey, value); } + } - public event TokenEventHandler TokenLA - { - add { Events.AddHandler(LAEventKey, value); } - remove { Events.RemoveHandler(LAEventKey, value); } - } + public event SyntacticPredicateEventHandler SynPredFailed + { + add { Events.AddHandler(SynPredFailedEventKey, value); } + remove { Events.RemoveHandler(SynPredFailedEventKey, value); } + } - public event SemanticPredicateEventHandler SemPredEvaluated - { - add { Events.AddHandler(SemPredEvaluatedEventKey, value); } - remove { Events.RemoveHandler(SemPredEvaluatedEventKey, value); } - } + public event SyntacticPredicateEventHandler SynPredSucceeded + { + add { Events.AddHandler(SynPredSucceededEventKey, value); } + remove { Events.RemoveHandler(SynPredSucceededEventKey, value); } + } - public event SyntacticPredicateEventHandler SynPredStarted - { - add { Events.AddHandler(SynPredStartedEventKey, value); } - remove { Events.RemoveHandler(SynPredStartedEventKey, value); } - } + public virtual void addMessageListener(MessageListener l) + { + if (!ignoreInvalidDebugCalls) + throw new System.ArgumentException("addMessageListener() is only valid if parser built for debugging"); + } - public event SyntacticPredicateEventHandler SynPredFailed - { - add { Events.AddHandler(SynPredFailedEventKey, value); } - remove { Events.RemoveHandler(SynPredFailedEventKey, value); } - } + public virtual void addParserListener(ParserListener l) + { + if (!ignoreInvalidDebugCalls) + throw new System.ArgumentException("addParserListener() is only valid if parser built for debugging"); + } - public event SyntacticPredicateEventHandler SynPredSucceeded - { - add { Events.AddHandler(SynPredSucceededEventKey, value); } - remove { Events.RemoveHandler(SynPredSucceededEventKey, value); } - } + public virtual void addParserMatchListener(ParserMatchListener l) + { + if (!ignoreInvalidDebugCalls) + throw new System.ArgumentException("addParserMatchListener() is only valid if parser built for debugging"); + } + public virtual void addParserTokenListener(ParserTokenListener l) + { + if (!ignoreInvalidDebugCalls) + throw new System.ArgumentException("addParserTokenListener() is only valid if parser built for debugging"); + } - public virtual void addMessageListener(MessageListener l) - { - if (!ignoreInvalidDebugCalls) - throw new System.ArgumentException("addMessageListener() is only valid if parser built for debugging"); - } + public virtual void addSemanticPredicateListener(SemanticPredicateListener l) + { + if (!ignoreInvalidDebugCalls) + throw new System.ArgumentException("addSemanticPredicateListener() is only valid if parser built for debugging"); + } - public virtual void addParserListener(ParserListener l) - { - if (!ignoreInvalidDebugCalls) - throw new System.ArgumentException("addParserListener() is only valid if parser built for debugging"); - } + public virtual void addSyntacticPredicateListener(SyntacticPredicateListener l) + { + if (!ignoreInvalidDebugCalls) + throw new System.ArgumentException("addSyntacticPredicateListener() is only valid if parser built for debugging"); + } - public virtual void addParserMatchListener(ParserMatchListener l) - { - if (!ignoreInvalidDebugCalls) - throw new System.ArgumentException("addParserMatchListener() is only valid if parser built for debugging"); - } + public virtual void addTraceListener(TraceListener l) + { + if (!ignoreInvalidDebugCalls) + throw new System.ArgumentException("addTraceListener() is only valid if parser built for debugging"); + } - public virtual void addParserTokenListener(ParserTokenListener l) - { - if (!ignoreInvalidDebugCalls) - throw new System.ArgumentException("addParserTokenListener() is only valid if parser built for debugging"); - } + /*Get another token object from the token stream */ + public abstract void consume(); - public virtual void addSemanticPredicateListener(SemanticPredicateListener l) - { - if (!ignoreInvalidDebugCalls) - throw new System.ArgumentException("addSemanticPredicateListener() is only valid if parser built for debugging"); - } + /*Consume tokens until one matches the given token */ + public virtual void consumeUntil(int tokenType) + { + while (LA(1) != Token.EOF_TYPE && LA(1) != tokenType) + { + consume(); + } + } - public virtual void addSyntacticPredicateListener(SyntacticPredicateListener l) - { - if (!ignoreInvalidDebugCalls) - throw new System.ArgumentException("addSyntacticPredicateListener() is only valid if parser built for debugging"); - } + /*Consume tokens until one matches the given token set */ + public virtual void consumeUntil(BitSet bset) + { + while (LA(1) != Token.EOF_TYPE && !bset.member(LA(1))) + { + consume(); + } + } - public virtual void addTraceListener(TraceListener l) - { - if (!ignoreInvalidDebugCalls) - throw new System.ArgumentException("addTraceListener() is only valid if parser built for debugging"); - } + protected internal virtual void defaultDebuggingSetup(TokenStream lexer, TokenBuffer tokBuf) + { + // by default, do nothing -- we're not debugging + } - /*Get another token object from the token stream */ - public abstract void consume(); - /*Consume tokens until one matches the given token */ - public virtual void consumeUntil(int tokenType) - { - while (LA(1) != Token.EOF_TYPE && LA(1) != tokenType) - { - consume(); - } - } - /*Consume tokens until one matches the given token set */ - public virtual void consumeUntil(BitSet bset) - { - while (LA(1) != Token.EOF_TYPE && !bset.member(LA(1))) - { - consume(); - } - } - protected internal virtual void defaultDebuggingSetup(TokenStream lexer, TokenBuffer tokBuf) - { - // by default, do nothing -- we're not debugging - } - /*Get the AST return value squirreled away in the parser */ - public virtual AST getAST() - { - return returnAST; - } - public virtual ASTFactory getASTFactory() - { - return astFactory; - } - public virtual string getFilename() - { - return inputState.filename; - } + /*Get the AST return value squirreled away in the parser */ + public virtual AST getAST() + { + return returnAST; + } - public virtual ParserSharedInputState getInputState() - { - return inputState; - } + public virtual ASTFactory getASTFactory() + { + return astFactory; + } - public virtual void setInputState(ParserSharedInputState state) - { - inputState = state; - } + public virtual string getFilename() + { + return inputState.filename; + } - public virtual void resetState() - { - traceDepth = 0; - inputState.reset(); - } + public virtual ParserSharedInputState getInputState() + { + return inputState; + } - public virtual string getTokenName(int num) - { - return tokenNames[num]; - } - public virtual string[] getTokenNames() - { - return tokenNames; - } - public virtual bool isDebugMode() - { - return false; - } - /*Return the token type of the ith token of lookahead where i=1 - * is the current token being examined by the parser (i.e., it - * has not been matched yet). - */ - public abstract int LA(int i); - /*Return the ith token of lookahead */ - public abstract IToken LT(int i); - // Forwarded to TokenBuffer - public virtual int mark() - { - return inputState.input.mark(); - } - /*Make sure current lookahead symbol matches token type t. - * Throw an exception upon mismatch, which is catch by either the - * error handler or by the syntactic predicate. - */ - public virtual void match(int t) - { - if (LA(1) != t) - throw new MismatchedTokenException(tokenNames, LT(1), t, false, getFilename()); - else - consume(); - } - /*Make sure current lookahead symbol matches the given set - * Throw an exception upon mismatch, which is catch by either the - * error handler or by the syntactic predicate. - */ - public virtual void match(BitSet b) - { - if (!b.member(LA(1))) - throw new MismatchedTokenException(tokenNames, LT(1), b, false, getFilename()); - else - consume(); - } - public virtual void matchNot(int t) - { - if (LA(1) == t) - throw new MismatchedTokenException(tokenNames, LT(1), t, true, getFilename()); - else - consume(); - } + public virtual void setInputState(ParserSharedInputState state) + { + inputState = state; + } - /// - /// @deprecated as of 2.7.2. This method calls System.exit() and writes - /// directly to stderr, which is usually not appropriate when - /// a parser is embedded into a larger application. Since the method is - /// static, it cannot be overridden to avoid these problems. - /// ANTLR no longer uses this method internally or in generated code. - /// - /// - [Obsolete("De-activated since version 2.7.2.6 as it cannot be overidden.", true)] - public static void panic() - { - System.Console.Error.WriteLine("Parser: panic"); - System.Environment.Exit(1); - } + public virtual void resetState() + { + traceDepth = 0; + inputState.reset(); + } - public virtual void removeMessageListener(MessageListener l) - { - if (!ignoreInvalidDebugCalls) - throw new System.SystemException("removeMessageListener() is only valid if parser built for debugging"); - } - public virtual void removeParserListener(ParserListener l) - { - if (!ignoreInvalidDebugCalls) - throw new System.SystemException("removeParserListener() is only valid if parser built for debugging"); - } - public virtual void removeParserMatchListener(ParserMatchListener l) - { - if (!ignoreInvalidDebugCalls) - throw new System.SystemException("removeParserMatchListener() is only valid if parser built for debugging"); - } - public virtual void removeParserTokenListener(ParserTokenListener l) - { - if (!ignoreInvalidDebugCalls) - throw new System.SystemException("removeParserTokenListener() is only valid if parser built for debugging"); - } - public virtual void removeSemanticPredicateListener(SemanticPredicateListener l) - { - if (!ignoreInvalidDebugCalls) - throw new System.ArgumentException("removeSemanticPredicateListener() is only valid if parser built for debugging"); - } - public virtual void removeSyntacticPredicateListener(SyntacticPredicateListener l) - { - if (!ignoreInvalidDebugCalls) - throw new System.ArgumentException("removeSyntacticPredicateListener() is only valid if parser built for debugging"); - } - public virtual void removeTraceListener(TraceListener l) - { - if (!ignoreInvalidDebugCalls) - throw new System.SystemException("removeTraceListener() is only valid if parser built for debugging"); - } + public virtual string getTokenName(int num) + { + return tokenNames[num]; + } - /*Parser error-reporting function can be overridden in subclass */ - public virtual void reportError(RecognitionException ex) - { - Console.Error.WriteLine(ex); - } + public virtual string[] getTokenNames() + { + return tokenNames; + } - /*Parser error-reporting function can be overridden in subclass */ - public virtual void reportError(string s) - { - if (getFilename() == null) - { - Console.Error.WriteLine("error: " + s); - } - else - { - Console.Error.WriteLine(getFilename() + ": error: " + s); - } - } + public virtual bool isDebugMode() + { + return false; + } - /*Parser warning-reporting function can be overridden in subclass */ - public virtual void reportWarning(string s) - { - if (getFilename() == null) - { - Console.Error.WriteLine("warning: " + s); - } - else - { - Console.Error.WriteLine(getFilename() + ": warning: " + s); - } - } + /*Return the token type of the ith token of lookahead where i=1 + * is the current token being examined by the parser (i.e., it + * has not been matched yet). + */ + public abstract int LA(int i); - public virtual void recover(RecognitionException ex, BitSet tokenSet) - { - consume(); - consumeUntil(tokenSet); - } + /*Return the ith token of lookahead */ + public abstract IToken LT(int i); - public virtual void rewind(int pos) - { - inputState.input.rewind(pos); - } + // Forwarded to TokenBuffer + public virtual int mark() + { + return inputState.input.mark(); + } - /// - /// Specify an object with support code (shared by Parser and TreeParser. - /// Normally, the programmer does not play with this, using - /// instead. - /// - /// - public virtual void setASTFactory(ASTFactory f) - { - astFactory = f; - } + /*Make sure current lookahead symbol matches token type t. + * Throw an exception upon mismatch, which is catch by either the + * error handler or by the syntactic predicate. + */ + public virtual void match(int t) + { + if (LA(1) != t) + throw new MismatchedTokenException(tokenNames, LT(1), t, false, getFilename()); + else + consume(); + } - /// - /// Specify the type of node to create during tree building. - /// - /// Fully qualified AST Node type name. - public virtual void setASTNodeClass(string cl) - { - astFactory.setASTNodeType(cl); - } + /*Make sure current lookahead symbol matches the given set + * Throw an exception upon mismatch, which is catch by either the + * error handler or by the syntactic predicate. + */ + public virtual void match(BitSet b) + { + if (!b.member(LA(1))) + throw new MismatchedTokenException(tokenNames, LT(1), b, false, getFilename()); + else + consume(); + } - /// - /// Specify the type of node to create during tree building. - /// use now to be consistent with - /// Token Object Type accessor. - /// - /// Fully qualified AST Node type name. - [Obsolete("Replaced by setASTNodeClass(string) since version 2.7.1", true)] - public virtual void setASTNodeType(string nodeType) - { - setASTNodeClass(nodeType); - } + public virtual void matchNot(int t) + { + if (LA(1) == t) + throw new MismatchedTokenException(tokenNames, LT(1), t, true, getFilename()); + else + consume(); + } - public virtual void setDebugMode(bool debugMode) - { - if (!ignoreInvalidDebugCalls) - throw new System.SystemException("setDebugMode() only valid if parser built for debugging"); - } - public virtual void setFilename(string f) - { - inputState.filename = f; - } - public virtual void setIgnoreInvalidDebugCalls(bool Value) - { - ignoreInvalidDebugCalls = Value; - } - /*Set or change the input token buffer */ - public virtual void setTokenBuffer(TokenBuffer t) - { - inputState.input = t; - } + /// + /// @deprecated as of 2.7.2. This method calls System.exit() and writes + /// directly to stderr, which is usually not appropriate when + /// a parser is embedded into a larger application. Since the method is + /// static, it cannot be overridden to avoid these problems. + /// ANTLR no longer uses this method internally or in generated code. + /// + /// + [Obsolete("De-activated since version 2.7.2.6 as it cannot be overidden.", true)] + public static void panic() + { + System.Console.Error.WriteLine("Parser: panic"); + System.Environment.Exit(1); + } - public virtual void traceIndent() - { - for (int i = 0; i < traceDepth; i++) - Console.Out.Write(" "); - } - public virtual void traceIn(string rname) - { - traceDepth += 1; - traceIndent(); - Console.Out.WriteLine("> " + rname + "; LA(1)==" + LT(1).getText() + ((inputState.guessing > 0)?" [guessing]":"")); - } - public virtual void traceOut(string rname) - { - traceIndent(); - Console.Out.WriteLine("< " + rname + "; LA(1)==" + LT(1).getText() + ((inputState.guessing > 0)?" [guessing]":"")); - traceDepth -= 1; - } - } + public virtual void removeMessageListener(MessageListener l) + { + if (!ignoreInvalidDebugCalls) + throw new System.SystemException("removeMessageListener() is only valid if parser built for debugging"); + } + + public virtual void removeParserListener(ParserListener l) + { + if (!ignoreInvalidDebugCalls) + throw new System.SystemException("removeParserListener() is only valid if parser built for debugging"); + } + + public virtual void removeParserMatchListener(ParserMatchListener l) + { + if (!ignoreInvalidDebugCalls) + throw new System.SystemException("removeParserMatchListener() is only valid if parser built for debugging"); + } + + public virtual void removeParserTokenListener(ParserTokenListener l) + { + if (!ignoreInvalidDebugCalls) + throw new System.SystemException("removeParserTokenListener() is only valid if parser built for debugging"); + } + + public virtual void removeSemanticPredicateListener(SemanticPredicateListener l) + { + if (!ignoreInvalidDebugCalls) + throw new System.ArgumentException("removeSemanticPredicateListener() is only valid if parser built for debugging"); + } + + public virtual void removeSyntacticPredicateListener(SyntacticPredicateListener l) + { + if (!ignoreInvalidDebugCalls) + throw new System.ArgumentException("removeSyntacticPredicateListener() is only valid if parser built for debugging"); + } + + public virtual void removeTraceListener(TraceListener l) + { + if (!ignoreInvalidDebugCalls) + throw new System.SystemException("removeTraceListener() is only valid if parser built for debugging"); + } + + /*Parser error-reporting function can be overridden in subclass */ + public virtual void reportError(RecognitionException ex) + { + Console.Error.WriteLine(ex); + } + + /*Parser error-reporting function can be overridden in subclass */ + public virtual void reportError(string s) + { + if (getFilename() == null) + { + Console.Error.WriteLine("error: " + s); + } + else + { + Console.Error.WriteLine(getFilename() + ": error: " + s); + } + } + + /*Parser warning-reporting function can be overridden in subclass */ + public virtual void reportWarning(string s) + { + if (getFilename() == null) + { + Console.Error.WriteLine("warning: " + s); + } + else + { + Console.Error.WriteLine(getFilename() + ": warning: " + s); + } + } + + public virtual void recover(RecognitionException ex, BitSet tokenSet) + { + consume(); + consumeUntil(tokenSet); + } + + public virtual void rewind(int pos) + { + inputState.input.rewind(pos); + } + + /// + /// Specify an object with support code (shared by Parser and TreeParser. + /// Normally, the programmer does not play with this, using + /// instead. + /// + /// + public virtual void setASTFactory(ASTFactory f) + { + astFactory = f; + } + + /// + /// Specify the type of node to create during tree building. + /// + /// Fully qualified AST Node type name. + public virtual void setASTNodeClass(string cl) + { + astFactory.setASTNodeType(cl); + } + + /// + /// Specify the type of node to create during tree building. + /// use now to be consistent with + /// Token Object Type accessor. + /// + /// Fully qualified AST Node type name. + [Obsolete("Replaced by setASTNodeClass(string) since version 2.7.1", true)] + public virtual void setASTNodeType(string nodeType) + { + setASTNodeClass(nodeType); + } + + public virtual void setDebugMode(bool debugMode) + { + if (!ignoreInvalidDebugCalls) + throw new System.SystemException("setDebugMode() only valid if parser built for debugging"); + } + + public virtual void setFilename(string f) + { + inputState.filename = f; + } + + public virtual void setIgnoreInvalidDebugCalls(bool Value) + { + ignoreInvalidDebugCalls = Value; + } + + /*Set or change the input token buffer */ + public virtual void setTokenBuffer(TokenBuffer t) + { + inputState.input = t; + } + + public virtual void traceIndent() + { + for (int i = 0; i < traceDepth; i++) + Console.Out.Write(" "); + } + + public virtual void traceIn(string rname) + { + traceDepth += 1; + traceIndent(); + Console.Out.WriteLine("> " + rname + "; LA(1)==" + LT(1).getText() + ((inputState.guessing > 0) ? " [guessing]" : "")); + } + + public virtual void traceOut(string rname) + { + traceIndent(); + Console.Out.WriteLine("< " + rname + "; LA(1)==" + LT(1).getText() + ((inputState.guessing > 0) ? " [guessing]" : "")); + traceDepth -= 1; + } } diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/ParserSharedInputState.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/ParserSharedInputState.cs index 0ee542ed..db00dae4 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/ParserSharedInputState.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/ParserSharedInputState.cs @@ -1,42 +1,39 @@ -namespace Spring.Expressions.Parser.antlr +namespace Spring.Expressions.Parser.antlr; +/*ANTLR Translator Generator + * Project led by Terence Parr at http://www.jGuru.com + * Software rights: http://www.antlr.org/license.html + * + * $Id:$ + */ + +// +// ANTLR C# Code Generator by Micheal Jordan +// Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com +// Anthony Oguntimehin +// +// With many thanks to Eric V. Smith from the ANTLR list. +// +/*This object contains the data associated with an + * input stream of tokens. Multiple parsers + * share a single ParserSharedInputState to parse + * the same stream of tokens. + */ + +public class ParserSharedInputState { - /*ANTLR Translator Generator - * Project led by Terence Parr at http://www.jGuru.com - * Software rights: http://www.antlr.org/license.html - * - * $Id:$ - */ + /*Where to get token objects */ + protected internal TokenBuffer input; - // - // ANTLR C# Code Generator by Micheal Jordan - // Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com - // Anthony Oguntimehin - // - // With many thanks to Eric V. Smith from the ANTLR list. - // - - /*This object contains the data associated with an - * input stream of tokens. Multiple parsers - * share a single ParserSharedInputState to parse - * the same stream of tokens. - */ + /*Are we guessing (guessing>0)? */ + public int guessing = 0; - public class ParserSharedInputState - { - /*Where to get token objects */ - protected internal TokenBuffer input; - - /*Are we guessing (guessing>0)? */ - public int guessing = 0; - - /*What file (if known) caused the problem? */ - protected internal string filename; - - public virtual void reset() - { - guessing = 0; - filename = null; - input.reset(); - } - } + /*What file (if known) caused the problem? */ + protected internal string filename; + + public virtual void reset() + { + guessing = 0; + filename = null; + input.reset(); + } } \ No newline at end of file diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/RecognitionException.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/RecognitionException.cs index ae978b12..91447bb0 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/RecognitionException.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/RecognitionException.cs @@ -1,80 +1,78 @@ -namespace Spring.Expressions.Parser.antlr +namespace Spring.Expressions.Parser.antlr; +/*ANTLR Translator Generator + * Project led by Terence Parr at http://www.jGuru.com + * Software rights: http://www.antlr.org/license.html + * + * $Id:$ + */ + +// +// ANTLR C# Code Generator by Micheal Jordan +// Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com +// Anthony Oguntimehin +// +// With many thanks to Eric V. Smith from the ANTLR list. +// + +[Serializable] +public class RecognitionException : ANTLRException { - /*ANTLR Translator Generator - * Project led by Terence Parr at http://www.jGuru.com - * Software rights: http://www.antlr.org/license.html - * - * $Id:$ - */ + public string fileName; // not used by treeparsers + public int line; // not used by treeparsers + public int column; // not used by treeparsers - // - // ANTLR C# Code Generator by Micheal Jordan - // Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com - // Anthony Oguntimehin - // - // With many thanks to Eric V. Smith from the ANTLR list. - // + public RecognitionException() : base("parsing error") + { + fileName = null; + line = -1; + column = -1; + } - [Serializable] - public class RecognitionException : ANTLRException - { - public string fileName; // not used by treeparsers - public int line; // not used by treeparsers - public int column; // not used by treeparsers + /* + * RecognitionException constructor comment. + * @param s java.lang.String + */ + public RecognitionException(string s) : base(s) + { + fileName = null; + line = -1; + column = -1; + } - public RecognitionException() : base("parsing error") - { - fileName = null; - line = - 1; - column = - 1; - } + /* + * RecognitionException constructor comment. + * @param s java.lang.String + */ + public RecognitionException(string s, string fileName_, int line_, int column_) : base(s) + { + fileName = fileName_; + line = line_; + column = column_; + } - /* - * RecognitionException constructor comment. - * @param s java.lang.String - */ - public RecognitionException(string s) : base(s) - { - fileName = null; - line = - 1; - column = - 1; - } + public virtual string getFilename() + { + return fileName; + } - /* - * RecognitionException constructor comment. - * @param s java.lang.String - */ - public RecognitionException(string s, string fileName_, int line_, int column_) : base(s) - { - fileName = fileName_; - line = line_; - column = column_; - } + public virtual int getLine() + { + return line; + } - public virtual string getFilename() - { - return fileName; - } + public virtual int getColumn() + { + return column; + } - public virtual int getLine() - { - return line; - } + [Obsolete("Replaced by Message property since version 2.7.0", true)] + public virtual string getErrorMessage() + { + return Message; + } - public virtual int getColumn() - { - return column; - } - - [Obsolete("Replaced by Message property since version 2.7.0", true)] - public virtual string getErrorMessage() - { - return Message; - } - - override public string ToString() - { - return FileLineFormatter.getFormatter().getFormatString(fileName, line, column) + Message; - } - } + override public string ToString() + { + return FileLineFormatter.getFormatter().getFormatString(fileName, line, column) + Message; + } } diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/SemanticException.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/SemanticException.cs index 0a44aa0f..65e5b6bf 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/SemanticException.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/SemanticException.cs @@ -1,37 +1,34 @@ -namespace Spring.Expressions.Parser.antlr +namespace Spring.Expressions.Parser.antlr; +/*ANTLR Translator Generator + * Project led by Terence Parr at http://www.jGuru.com + * Software rights: http://www.antlr.org/license.html + * + * $Id:$ + */ + +// +// ANTLR C# Code Generator by Micheal Jordan +// Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com +// Anthony Oguntimehin +// +// With many thanks to Eric V. Smith from the ANTLR list. +// + +[Serializable] +public class SemanticException : RecognitionException { - /*ANTLR Translator Generator - * Project led by Terence Parr at http://www.jGuru.com - * Software rights: http://www.antlr.org/license.html - * - * $Id:$ - */ + public SemanticException(string s) : base(s) + { + } - // - // ANTLR C# Code Generator by Micheal Jordan - // Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com - // Anthony Oguntimehin - // - // With many thanks to Eric V. Smith from the ANTLR list. - // + [Obsolete("Replaced by SemanticException(string, string, int, int) since version 2.7.2.6", false)] + public SemanticException(String s, String fileName, int line) : + this(s, fileName, line, -1) + { + } - [Serializable] - public class SemanticException : RecognitionException - { - public SemanticException(string s) : base(s) - { - } - - [Obsolete("Replaced by SemanticException(string, string, int, int) since version 2.7.2.6", false)] - public SemanticException(String s, String fileName, int line) : - this(s, fileName, line, -1) - { - - } - - public SemanticException(string s, string fileName, int line, int column) : - base(s, fileName, line, column) - { - } - } + public SemanticException(string s, string fileName, int line, int column) : + base(s, fileName, line, column) + { + } } diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/StringUtils.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/StringUtils.cs index 788393cc..4a376c0a 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/StringUtils.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/StringUtils.cs @@ -1,117 +1,117 @@ -namespace Spring.Expressions.Parser.antlr +namespace Spring.Expressions.Parser.antlr; +/* ANTLR Translator Generator + * Project led by Terence Parr at http://www.jGuru.com + * Software rights: http://www.antlr.org/license.html + * + * $Id:$ + */ +// +// ANTLR C# Code Generator by Micheal Jordan +// Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com +// Anthony Oguntimehin +// +// With many thanks to Eric V. Smith from the ANTLR list. +// + +public class StringUtils { - /* ANTLR Translator Generator - * Project led by Terence Parr at http://www.jGuru.com - * Software rights: http://www.antlr.org/license.html - * - * $Id:$ - */ - // - // ANTLR C# Code Generator by Micheal Jordan - // Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com - // Anthony Oguntimehin - // - // With many thanks to Eric V. Smith from the ANTLR list. - // - - public class StringUtils - { - /*General-purpose utility function for removing - * characters from back of string - * @param s The string to process - * @param c The character to remove - * @return The resulting string - */ - static public string stripBack(string s, char c) - { - while (s.Length > 0 && s[s.Length - 1] == c) - { - s = s.Substring(0, (s.Length - 1) - (0)); - } - return s; - } - - /*General-purpose utility function for removing - * characters from back of string - * @param s The string to process - * @param remove A string containing the set of characters to remove - * @return The resulting string - */ - static public string stripBack(string s, string remove) - { - bool changed; - do - { - changed = false; - for (int i = 0; i < remove.Length; i++) - { - char c = remove[i]; - while (s.Length > 0 && s[s.Length - 1] == c) - { - changed = true; - s = s.Substring(0, (s.Length - 1) - (0)); - } - } - } - while (changed); - return s; - } - - /*General-purpose utility function for removing - * characters from front of string - * @param s The string to process - * @param c The character to remove - * @return The resulting string - */ - static public string stripFront(string s, char c) - { - while (s.Length > 0 && s[0] == c) - { - s = s.Substring(1); - } - return s; - } - - /*General-purpose utility function for removing - * characters from front of string - * @param s The string to process - * @param remove A string containing the set of characters to remove - * @return The resulting string - */ - static public string stripFront(string s, string remove) - { - bool changed; - do - { - changed = false; - for (int i = 0; i < remove.Length; i++) - { - char c = remove[i]; - while (s.Length > 0 && s[0] == c) - { - changed = true; - s = s.Substring(1); - } - } - } - while (changed); - return s; - } - - /*General-purpose utility function for removing - * characters from the front and back of string - * @param s The string to process - * @param head exact string to strip from head - * @param tail exact string to strip from tail - * @return The resulting string - */ - public static string stripFrontBack(string src, string head, string tail) - { - int h = src.IndexOf(head); - int t = src.LastIndexOf(tail); - if (h == - 1 || t == - 1) - return src; - return src.Substring(h + 1, (t) - (h + 1)); - } - } -} \ No newline at end of file + /*General-purpose utility function for removing + * characters from back of string + * @param s The string to process + * @param c The character to remove + * @return The resulting string + */ + static public string stripBack(string s, char c) + { + while (s.Length > 0 && s[s.Length - 1] == c) + { + s = s.Substring(0, (s.Length - 1) - (0)); + } + + return s; + } + + /*General-purpose utility function for removing + * characters from back of string + * @param s The string to process + * @param remove A string containing the set of characters to remove + * @return The resulting string + */ + static public string stripBack(string s, string remove) + { + bool changed; + do + { + changed = false; + for (int i = 0; i < remove.Length; i++) + { + char c = remove[i]; + while (s.Length > 0 && s[s.Length - 1] == c) + { + changed = true; + s = s.Substring(0, (s.Length - 1) - (0)); + } + } + } while (changed); + + return s; + } + + /*General-purpose utility function for removing + * characters from front of string + * @param s The string to process + * @param c The character to remove + * @return The resulting string + */ + static public string stripFront(string s, char c) + { + while (s.Length > 0 && s[0] == c) + { + s = s.Substring(1); + } + + return s; + } + + /*General-purpose utility function for removing + * characters from front of string + * @param s The string to process + * @param remove A string containing the set of characters to remove + * @return The resulting string + */ + static public string stripFront(string s, string remove) + { + bool changed; + do + { + changed = false; + for (int i = 0; i < remove.Length; i++) + { + char c = remove[i]; + while (s.Length > 0 && s[0] == c) + { + changed = true; + s = s.Substring(1); + } + } + } while (changed); + + return s; + } + + /*General-purpose utility function for removing + * characters from the front and back of string + * @param s The string to process + * @param head exact string to strip from head + * @param tail exact string to strip from tail + * @return The resulting string + */ + public static string stripFrontBack(string src, string head, string tail) + { + int h = src.IndexOf(head); + int t = src.LastIndexOf(tail); + if (h == -1 || t == -1) + return src; + return src.Substring(h + 1, (t) - (h + 1)); + } +} diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/SupportClass.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/SupportClass.cs index 0a82a4da..ab9df1c3 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/SupportClass.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/SupportClass.cs @@ -1,31 +1,30 @@ -namespace Spring.Expressions.Parser.antlr +namespace Spring.Expressions.Parser.antlr; + +internal class SupportClass { - internal class SupportClass + public static int URShift(int number, int bits) { - public static int URShift(int number, int bits) - { - if (number >= 0) - return number >> bits; - else - return (number >> bits) + (2 << ~bits); - } + if (number >= 0) + return number >> bits; + else + return (number >> bits) + (2 << ~bits); + } - public static int URShift(int number, long bits) - { - return URShift(number, (int)bits); - } + public static int URShift(int number, long bits) + { + return URShift(number, (int) bits); + } - public static long URShift(long number, int bits) - { - if (number >= 0) - return number >> bits; - else - return (number >> bits) + (2L << ~bits); - } + public static long URShift(long number, int bits) + { + if (number >= 0) + return number >> bits; + else + return (number >> bits) + (2L << ~bits); + } - public static long URShift(long number, long bits) - { - return URShift(number, (int)bits); - } + public static long URShift(long number, long bits) + { + return URShift(number, (int) bits); } } diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/Token.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/Token.cs index 75b1bd95..d004d894 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/Token.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/Token.cs @@ -1,97 +1,102 @@ -namespace Spring.Expressions.Parser.antlr +namespace Spring.Expressions.Parser.antlr; +/*ANTLR Translator Generator + * Project led by Terence Parr at http://www.jGuru.com + * Software rights: http://www.antlr.org/license.html + * + * $Id:$ + */ + +// +// ANTLR C# Code Generator by Micheal Jordan +// Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com +// Anthony Oguntimehin +// +// With many thanks to Eric V. Smith from the ANTLR list. +// +/*A token is minimally a token type. Subclasses can add the text matched + * for the token and line info. + */ + +public class Token : IToken //, ICloneable { - /*ANTLR Translator Generator - * Project led by Terence Parr at http://www.jGuru.com - * Software rights: http://www.antlr.org/license.html - * - * $Id:$ - */ + // constants + public const int MIN_USER_TYPE = 4; + public const int NULL_TREE_LOOKAHEAD = 3; + public const int INVALID_TYPE = 0; + public const int EOF_TYPE = 1; + public static readonly int SKIP = -1; - // - // ANTLR C# Code Generator by Micheal Jordan - // Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com - // Anthony Oguntimehin - // - // With many thanks to Eric V. Smith from the ANTLR list. - // + // each Token has at least a token type + protected int type_; - /*A token is minimally a token type. Subclasses can add the text matched - * for the token and line info. - */ + // the illegal token object + public static Token badToken = new Token(INVALID_TYPE, ""); - public class Token : IToken //, ICloneable - { - // constants - public const int MIN_USER_TYPE = 4; - public const int NULL_TREE_LOOKAHEAD = 3; - public const int INVALID_TYPE = 0; - public const int EOF_TYPE = 1; - public static readonly int SKIP = - 1; - - // each Token has at least a token type - protected int type_; - - // the illegal token object - public static Token badToken = new Token(INVALID_TYPE, ""); - - public Token() - { - type_ = INVALID_TYPE; - } - public Token(int t) - { - type_ = t; - } - public Token(int t, string txt) - { - type_ = t; - setText(txt); - } - public virtual int getColumn() - { - return 0; - } - public virtual int getLine() - { - return 0; - } - public virtual string getFilename() - { - return null; - } + public Token() + { + type_ = INVALID_TYPE; + } - public virtual void setFilename(string name) - { - } + public Token(int t) + { + type_ = t; + } - public virtual string getText() - { - return ""; - } + public Token(int t, string txt) + { + type_ = t; + setText(txt); + } - public int Type - { - get { return type_; } - set { type_ = value; } - } + public virtual int getColumn() + { + return 0; + } - public virtual void setType(int newType) { this.Type = newType; } + public virtual int getLine() + { + return 0; + } - public virtual void setColumn(int c) - { - ; - } - public virtual void setLine(int l) - { - ; - } - public virtual void setText(string t) - { - ; - } - override public string ToString() - { - return "[\"" + getText() + "\",<" + type_ + ">]"; - } - } -} \ No newline at end of file + public virtual string getFilename() + { + return null; + } + + public virtual void setFilename(string name) + { + } + + public virtual string getText() + { + return ""; + } + + public int Type + { + get { return type_; } + set { type_ = value; } + } + + public virtual void setType(int newType) { this.Type = newType; } + + public virtual void setColumn(int c) + { + ; + } + + public virtual void setLine(int l) + { + ; + } + + public virtual void setText(string t) + { + ; + } + + override public string ToString() + { + return "[\"" + getText() + "\",<" + type_ + ">]"; + } +} diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/TokenBuffer.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/TokenBuffer.cs index d40d56f6..4c3d543e 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/TokenBuffer.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/TokenBuffer.cs @@ -1,144 +1,141 @@ -namespace Spring.Expressions.Parser.antlr +namespace Spring.Expressions.Parser.antlr; +/*ANTLR Translator Generator + * Project led by Terence Parr at http://www.jGuru.com + * Software rights: http://www.antlr.org/license.html + * + * $Id:$ + */ + +// +// ANTLR C# Code Generator by Micheal Jordan +// Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com +// Anthony Oguntimehin +// +// With many thanks to Eric V. Smith from the ANTLR list. +// +/*A Stream of Token objects fed to the parser from a Tokenizer that can + * be rewound via mark()/rewind() methods. + *

+ * A dynamic array is used to buffer up all the input tokens. Normally, + * "k" tokens are stored in the buffer. More tokens may be stored during + * guess mode (testing syntactic predicate), or when LT(i>k) is referenced. + * Consumption of tokens is deferred. In other words, reading the next + * token is not done by conume(), but deferred until needed by LA or LT. + *

+ * + * @see antlr.Token + * @see antlr.Tokenizer + * @see antlr.TokenQueue + */ + +public class TokenBuffer { - /*ANTLR Translator Generator - * Project led by Terence Parr at http://www.jGuru.com - * Software rights: http://www.antlr.org/license.html - * - * $Id:$ - */ - - // - // ANTLR C# Code Generator by Micheal Jordan - // Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com - // Anthony Oguntimehin - // - // With many thanks to Eric V. Smith from the ANTLR list. - // - - /*A Stream of Token objects fed to the parser from a Tokenizer that can - * be rewound via mark()/rewind() methods. - *

- * A dynamic array is used to buffer up all the input tokens. Normally, - * "k" tokens are stored in the buffer. More tokens may be stored during - * guess mode (testing syntactic predicate), or when LT(i>k) is referenced. - * Consumption of tokens is deferred. In other words, reading the next - * token is not done by conume(), but deferred until needed by LA or LT. - *

- * - * @see antlr.Token - * @see antlr.Tokenizer - * @see antlr.TokenQueue - */ - - public class TokenBuffer - { - - // Token source - protected internal TokenStream input; - - // Number of active markers - protected internal int nMarkers = 0; - - // Additional offset used when markers are active - protected internal int markerOffset = 0; - - // Number of calls to consume() since last LA() or LT() call - protected internal int numToConsume = 0; - - // Circular queue - internal TokenQueue queue; - - /*Create a token buffer */ - public TokenBuffer(TokenStream input_) - { - input = input_; - queue = new TokenQueue(1); - } - - /*Reset the input buffer to empty state */ - public virtual void reset() - { - nMarkers = 0; - markerOffset = 0; - numToConsume = 0; - queue.reset(); - } - - /*Mark another token for deferred consumption */ - public virtual void consume() - { - numToConsume++; - } - - /*Ensure that the token buffer is sufficiently full */ - protected virtual void fill(int amount) - { - syncConsume(); - // Fill the buffer sufficiently to hold needed tokens - while (queue.nbrEntries < (amount + markerOffset)) - { - // Append the next token - queue.append(input.nextToken()); - } - } - - /*return the Tokenizer (needed by ParseView) */ - public virtual TokenStream getInput() - { - return input; - } - - /*Get a lookahead token value */ - public virtual int LA(int i) - { - fill(i); - return queue.elementAt(markerOffset + i - 1).Type; - } - - /*Get a lookahead token */ - public virtual IToken LT(int i) - { - fill(i); - return queue.elementAt(markerOffset + i - 1); - } - - /*Return an integer marker that can be used to rewind the buffer to - * its current state. - */ - public virtual int mark() - { - syncConsume(); - nMarkers++; - return markerOffset; - } - - /*Rewind the token buffer to a marker. - * @param mark Marker returned previously from mark() - */ - public virtual void rewind(int mark) - { - syncConsume(); - markerOffset = mark; - nMarkers--; - } - - /*Sync up deferred consumption */ - protected virtual void syncConsume() - { - while (numToConsume > 0) - { - if (nMarkers > 0) - { - // guess mode -- leave leading tokens and bump offset. - markerOffset++; - } - else - { - // normal mode -- remove first token - queue.removeFirst(); - } - numToConsume--; - } - } - } -} \ No newline at end of file + // Token source + protected internal TokenStream input; + + // Number of active markers + protected internal int nMarkers = 0; + + // Additional offset used when markers are active + protected internal int markerOffset = 0; + + // Number of calls to consume() since last LA() or LT() call + protected internal int numToConsume = 0; + + // Circular queue + internal TokenQueue queue; + + /*Create a token buffer */ + public TokenBuffer(TokenStream input_) + { + input = input_; + queue = new TokenQueue(1); + } + + /*Reset the input buffer to empty state */ + public virtual void reset() + { + nMarkers = 0; + markerOffset = 0; + numToConsume = 0; + queue.reset(); + } + + /*Mark another token for deferred consumption */ + public virtual void consume() + { + numToConsume++; + } + + /*Ensure that the token buffer is sufficiently full */ + protected virtual void fill(int amount) + { + syncConsume(); + // Fill the buffer sufficiently to hold needed tokens + while (queue.nbrEntries < (amount + markerOffset)) + { + // Append the next token + queue.append(input.nextToken()); + } + } + + /*return the Tokenizer (needed by ParseView) */ + public virtual TokenStream getInput() + { + return input; + } + + /*Get a lookahead token value */ + public virtual int LA(int i) + { + fill(i); + return queue.elementAt(markerOffset + i - 1).Type; + } + + /*Get a lookahead token */ + public virtual IToken LT(int i) + { + fill(i); + return queue.elementAt(markerOffset + i - 1); + } + + /*Return an integer marker that can be used to rewind the buffer to + * its current state. + */ + public virtual int mark() + { + syncConsume(); + nMarkers++; + return markerOffset; + } + + /*Rewind the token buffer to a marker. + * @param mark Marker returned previously from mark() + */ + public virtual void rewind(int mark) + { + syncConsume(); + markerOffset = mark; + nMarkers--; + } + + /*Sync up deferred consumption */ + protected virtual void syncConsume() + { + while (numToConsume > 0) + { + if (nMarkers > 0) + { + // guess mode -- leave leading tokens and bump offset. + markerOffset++; + } + else + { + // normal mode -- remove first token + queue.removeFirst(); + } + + numToConsume--; + } + } +} diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/TokenCreator.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/TokenCreator.cs index 22059a64..9de83db4 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/TokenCreator.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/TokenCreator.cs @@ -1,46 +1,44 @@ -namespace Spring.Expressions.Parser.antlr +namespace Spring.Expressions.Parser.antlr; +/*ANTLR Translator Generator + * Project led by Terence Parr at http://www.jGuru.com + * Software rights: http://www.antlr.org/license.html + * + * $Id:$ + */ + +// +// ANTLR C# Code Generator by Micheal Jordan +// Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com +// Anthony Oguntimehin +// + +///

+/// A creator of Token object instances. +/// +/// +/// +/// This class and it's sub-classes exists primarily as an optimization +/// of the reflection-based mechanism(s) previously used exclusively to +/// create instances of Token objects. +/// +/// +/// Since Lexers in ANTLR use a single Token type, each TokenCreator can +/// create one class of Token objects (that's why it's not called TokenFactory). +/// +/// +public abstract class TokenCreator { - /*ANTLR Translator Generator - * Project led by Terence Parr at http://www.jGuru.com - * Software rights: http://www.antlr.org/license.html - * - * $Id:$ - */ - - // - // ANTLR C# Code Generator by Micheal Jordan - // Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com - // Anthony Oguntimehin - // + /// + /// Returns the fully qualified name of the Token type that this + /// class creates. + /// + public abstract string TokenTypeName + { + get; + } - /// - /// A creator of Token object instances. - /// - /// - /// - /// This class and it's sub-classes exists primarily as an optimization - /// of the reflection-based mechanism(s) previously used exclusively to - /// create instances of Token objects. - /// - /// - /// Since Lexers in ANTLR use a single Token type, each TokenCreator can - /// create one class of Token objects (that's why it's not called TokenFactory). - /// - /// - public abstract class TokenCreator - { - /// - /// Returns the fully qualified name of the Token type that this - /// class creates. - /// - public abstract string TokenTypeName - { - get; - } - - /// - /// Constructs a instance. - /// - public abstract IToken Create(); - } -} \ No newline at end of file + /// + /// Constructs a instance. + /// + public abstract IToken Create(); +} diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/TokenQueue.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/TokenQueue.cs index 18154896..eb1156d0 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/TokenQueue.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/TokenQueue.cs @@ -1,119 +1,124 @@ -namespace Spring.Expressions.Parser.antlr +namespace Spring.Expressions.Parser.antlr; +/*ANTLR Translator Generator + * Project led by Terence Parr at http://www.jGuru.com + * Software rights: http://www.antlr.org/license.html + * + * $Id:$ + */ + +// +// ANTLR C# Code Generator by Micheal Jordan +// Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com +// Anthony Oguntimehin +// +// With many thanks to Eric V. Smith from the ANTLR list. +// +/*A private circular buffer object used by the token buffer */ + +class TokenQueue { - /*ANTLR Translator Generator - * Project led by Terence Parr at http://www.jGuru.com - * Software rights: http://www.antlr.org/license.html - * - * $Id:$ - */ + /*Physical circular buffer of tokens */ + private IToken[] buffer; - // - // ANTLR C# Code Generator by Micheal Jordan - // Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com - // Anthony Oguntimehin - // - // With many thanks to Eric V. Smith from the ANTLR list. - // - - /*A private circular buffer object used by the token buffer */ + /*buffer.length-1 for quick modulos */ + private int sizeLessOne; - class TokenQueue - { - /*Physical circular buffer of tokens */ - private IToken[] buffer; - /*buffer.length-1 for quick modulos */ - private int sizeLessOne; - /*physical index of front token */ - private int offset; - /*number of tokens in the queue */ - protected internal int nbrEntries; - - public TokenQueue(int minSize) - { - // Find first power of 2 >= to requested size - int size; - if (minSize < 0) - { - init(16); // pick some value for them - return ; - } - // check for overflow - if (minSize >= (int.MaxValue / 2)) - { - init(int.MaxValue); // wow that's big. - return ; - } - for (size = 2; size < minSize; size *= 2) - { - ; - } - init(size); - } - - /*Add token to end of the queue - * @param tok The token to add - */ - public void append(IToken tok) - { - if (nbrEntries == buffer.Length) - { - expand(); - } - buffer[(offset + nbrEntries) & sizeLessOne] = tok; - nbrEntries++; - } - - /*Fetch a token from the queue by index - * @param idx The index of the token to fetch, where zero is the token at the front of the queue - */ - public IToken elementAt(int idx) - { - return buffer[(offset + idx) & sizeLessOne]; - } - - /*Expand the token buffer by doubling its capacity */ - private void expand() - { - IToken[] newBuffer = new IToken[buffer.Length * 2]; - // Copy the contents to the new buffer - // Note that this will store the first logical item in the - // first physical array element. - for (int i = 0; i < buffer.Length; i++) - { - newBuffer[i] = elementAt(i); - } - // Re-initialize with new contents, keep old nbrEntries - buffer = newBuffer; - sizeLessOne = buffer.Length - 1; - offset = 0; - } - - /*Initialize the queue. - * @param size The initial size of the queue - */ - private void init(int size) - { - // Allocate buffer - buffer = new IToken[size]; - // Other initialization - sizeLessOne = size - 1; - offset = 0; - nbrEntries = 0; - } - - /*Clear the queue. Leaving the previous buffer alone. - */ - public void reset() - { - offset = 0; - nbrEntries = 0; - } - - /*Remove token from front of queue */ - public void removeFirst() - { - offset = (offset + 1) & sizeLessOne; - nbrEntries--; - } - } -} \ No newline at end of file + /*physical index of front token */ + private int offset; + + /*number of tokens in the queue */ + protected internal int nbrEntries; + + public TokenQueue(int minSize) + { + // Find first power of 2 >= to requested size + int size; + if (minSize < 0) + { + init(16); // pick some value for them + return; + } + + // check for overflow + if (minSize >= (int.MaxValue / 2)) + { + init(int.MaxValue); // wow that's big. + return; + } + + for (size = 2; size < minSize; size *= 2) + { + ; + } + + init(size); + } + + /*Add token to end of the queue + * @param tok The token to add + */ + public void append(IToken tok) + { + if (nbrEntries == buffer.Length) + { + expand(); + } + + buffer[(offset + nbrEntries) & sizeLessOne] = tok; + nbrEntries++; + } + + /*Fetch a token from the queue by index + * @param idx The index of the token to fetch, where zero is the token at the front of the queue + */ + public IToken elementAt(int idx) + { + return buffer[(offset + idx) & sizeLessOne]; + } + + /*Expand the token buffer by doubling its capacity */ + private void expand() + { + IToken[] newBuffer = new IToken[buffer.Length * 2]; + // Copy the contents to the new buffer + // Note that this will store the first logical item in the + // first physical array element. + for (int i = 0; i < buffer.Length; i++) + { + newBuffer[i] = elementAt(i); + } + + // Re-initialize with new contents, keep old nbrEntries + buffer = newBuffer; + sizeLessOne = buffer.Length - 1; + offset = 0; + } + + /*Initialize the queue. + * @param size The initial size of the queue + */ + private void init(int size) + { + // Allocate buffer + buffer = new IToken[size]; + // Other initialization + sizeLessOne = size - 1; + offset = 0; + nbrEntries = 0; + } + + /*Clear the queue. Leaving the previous buffer alone. + */ + public void reset() + { + offset = 0; + nbrEntries = 0; + } + + /*Remove token from front of queue */ + public void removeFirst() + { + offset = (offset + 1) & sizeLessOne; + nbrEntries--; + } +} diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/TokenStream.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/TokenStream.cs index 748ea326..b4bb7899 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/TokenStream.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/TokenStream.cs @@ -1,24 +1,20 @@ -namespace Spring.Expressions.Parser.antlr -{ - /*ANTLR Translator Generator - * Project led by Terence Parr at http://www.jGuru.com - * Software rights: http://www.antlr.org/license.html - * - * $Id:$ - */ +namespace Spring.Expressions.Parser.antlr; +/*ANTLR Translator Generator + * Project led by Terence Parr at http://www.jGuru.com + * Software rights: http://www.antlr.org/license.html + * + * $Id:$ + */ - - // - // ANTLR C# Code Generator by Micheal Jordan - // Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com - // Anthony Oguntimehin - // - // With many thanks to Eric V. Smith from the ANTLR list. - // - - public interface TokenStream - { - IToken nextToken(); - } - -} \ No newline at end of file +// +// ANTLR C# Code Generator by Micheal Jordan +// Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com +// Anthony Oguntimehin +// +// With many thanks to Eric V. Smith from the ANTLR list. +// + +public interface TokenStream +{ + IToken nextToken(); +} diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/TokenStreamBasicFilter.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/TokenStreamBasicFilter.cs index 664463ae..daa1a536 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/TokenStreamBasicFilter.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/TokenStreamBasicFilter.cs @@ -1,55 +1,57 @@ using BitSet = Spring.Expressions.Parser.antlr.collections.impl.BitSet; - -namespace Spring.Expressions.Parser.antlr + +namespace Spring.Expressions.Parser.antlr; +/*ANTLR Translator Generator + * Project led by Terence Parr at http://www.jGuru.com + * Software rights: http://www.antlr.org/license.html + * + * $Id:$ + */ + +// +// ANTLR C# Code Generator by Micheal Jordan +// Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com +// Anthony Oguntimehin +// +// With many thanks to Eric V. Smith from the ANTLR list. +// + +/*This object is a TokenStream that passes through all + * tokens except for those that you tell it to discard. + * There is no buffering of the tokens. + */ +public class TokenStreamBasicFilter : TokenStream { - /*ANTLR Translator Generator - * Project led by Terence Parr at http://www.jGuru.com - * Software rights: http://www.antlr.org/license.html - * - * $Id:$ - */ + /*The set of token types to discard */ + protected internal BitSet discardMask; - // - // ANTLR C# Code Generator by Micheal Jordan - // Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com - // Anthony Oguntimehin - // - // With many thanks to Eric V. Smith from the ANTLR list. - // + /*The input stream */ + protected internal TokenStream input; - /*This object is a TokenStream that passes through all - * tokens except for those that you tell it to discard. - * There is no buffering of the tokens. - */ - public class TokenStreamBasicFilter : TokenStream - { - /*The set of token types to discard */ - protected internal BitSet discardMask; - - /*The input stream */ - protected internal TokenStream input; - - public TokenStreamBasicFilter(TokenStream input) - { - this.input = input; - discardMask = new BitSet(); - } - public virtual void discard(int ttype) - { - discardMask.add(ttype); - } - public virtual void discard(BitSet mask) - { - discardMask = mask; - } - public virtual IToken nextToken() - { - IToken tok = input.nextToken(); - while (tok != null && discardMask.member(tok.Type)) - { - tok = input.nextToken(); - } - return tok; - } - } -} \ No newline at end of file + public TokenStreamBasicFilter(TokenStream input) + { + this.input = input; + discardMask = new BitSet(); + } + + public virtual void discard(int ttype) + { + discardMask.add(ttype); + } + + public virtual void discard(BitSet mask) + { + discardMask = mask; + } + + public virtual IToken nextToken() + { + IToken tok = input.nextToken(); + while (tok != null && discardMask.member(tok.Type)) + { + tok = input.nextToken(); + } + + return tok; + } +} diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/TokenStreamException.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/TokenStreamException.cs index 814ef4b9..c5c1403f 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/TokenStreamException.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/TokenStreamException.cs @@ -1,32 +1,30 @@ -namespace Spring.Expressions.Parser.antlr +namespace Spring.Expressions.Parser.antlr; +/*ANTLR Translator Generator + * Project led by Terence Parr at http://www.jGuru.com + * Software rights: http://www.antlr.org/license.html + * + * $Id:$ + */ + +// +// ANTLR C# Code Generator by Micheal Jordan +// Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com +// Anthony Oguntimehin +// +// With many thanks to Eric V. Smith from the ANTLR list. +// +/* + * Anything that goes wrong while generating a stream of tokens. + */ + +[Serializable] +public class TokenStreamException : ANTLRException { - /*ANTLR Translator Generator - * Project led by Terence Parr at http://www.jGuru.com - * Software rights: http://www.antlr.org/license.html - * - * $Id:$ - */ + public TokenStreamException() + { + } - // - // ANTLR C# Code Generator by Micheal Jordan - // Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com - // Anthony Oguntimehin - // - // With many thanks to Eric V. Smith from the ANTLR list. - // - - /* - * Anything that goes wrong while generating a stream of tokens. - */ - - [Serializable] - public class TokenStreamException : ANTLRException - { - public TokenStreamException() - { - } - public TokenStreamException(string s) : base(s) - { - } - } + public TokenStreamException(string s) : base(s) + { + } } diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/TokenStreamHiddenTokenFilter.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/TokenStreamHiddenTokenFilter.cs index 03f7f0cf..a5d66a29 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/TokenStreamHiddenTokenFilter.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/TokenStreamHiddenTokenFilter.cs @@ -1,178 +1,193 @@ using BitSet = Spring.Expressions.Parser.antlr.collections.impl.BitSet; - -namespace Spring.Expressions.Parser.antlr + +namespace Spring.Expressions.Parser.antlr; +/*ANTLR Translator Generator + * Project led by Terence Parr at http://www.jGuru.com + * Software rights: http://www.antlr.org/license.html + * + * $Id:$ + */ + +// +// ANTLR C# Code Generator by Micheal Jordan +// Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com +// Anthony Oguntimehin +// +// With many thanks to Eric V. Smith from the ANTLR list. +// + +/*This object filters a token stream coming from a lexer + * or another TokenStream so that only certain token channels + * get transmitted to the parser. + * + * Any of the channels can be filtered off as "hidden" channels whose + * tokens can be accessed from the parser. + */ +public class TokenStreamHiddenTokenFilter : TokenStreamBasicFilter, TokenStream { - /*ANTLR Translator Generator - * Project led by Terence Parr at http://www.jGuru.com - * Software rights: http://www.antlr.org/license.html - * - * $Id:$ - */ + // protected BitSet discardMask; + protected internal BitSet hideMask; - // - // ANTLR C# Code Generator by Micheal Jordan - // Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com - // Anthony Oguntimehin - // - // With many thanks to Eric V. Smith from the ANTLR list. - // + private IHiddenStreamToken nextMonitoredToken; - /*This object filters a token stream coming from a lexer - * or another TokenStream so that only certain token channels - * get transmitted to the parser. - * - * Any of the channels can be filtered off as "hidden" channels whose - * tokens can be accessed from the parser. - */ - public class TokenStreamHiddenTokenFilter : TokenStreamBasicFilter, TokenStream - { - // protected BitSet discardMask; - protected internal BitSet hideMask; - - private IHiddenStreamToken nextMonitoredToken; - - /*track tail of hidden list emanating from previous - * monitored token - */ - protected internal IHiddenStreamToken lastHiddenToken; - - protected internal IHiddenStreamToken firstHidden = null; - - public TokenStreamHiddenTokenFilter(TokenStream input) : base(input) - { - hideMask = new BitSet(); - } - protected internal virtual void consume() - { - nextMonitoredToken = (IHiddenStreamToken) input.nextToken(); - } - private void consumeFirst() - { - consume(); // get first token of input stream - - // Handle situation where hidden or discarded tokens - // appear first in input stream - IHiddenStreamToken p = null; - // while hidden or discarded scarf tokens - while (hideMask.member(LA(1).Type) || discardMask.member(LA(1).Type)) - { - if (hideMask.member(LA(1).Type)) - { - if (p == null) - { - p = LA(1); - } - else - { - p.setHiddenAfter(LA(1)); - LA(1).setHiddenBefore(p); // double-link - p = LA(1); - } - lastHiddenToken = p; - if (firstHidden == null) - { - firstHidden = p; // record hidden token if first - } - } - consume(); - } - } - public virtual BitSet getDiscardMask() - { - return discardMask; - } - /*Return a ptr to the hidden token appearing immediately after - * token t in the input stream. - */ - public virtual IHiddenStreamToken getHiddenAfter(IHiddenStreamToken t) - { - return t.getHiddenAfter(); - } - /*Return a ptr to the hidden token appearing immediately before - * token t in the input stream. - */ - public virtual IHiddenStreamToken getHiddenBefore(IHiddenStreamToken t) - { - return t.getHiddenBefore(); - } - public virtual BitSet getHideMask() - { - return hideMask; - } - /*Return the first hidden token if one appears - * before any monitored token. - */ - public virtual IHiddenStreamToken getInitialHiddenToken() - { - return firstHidden; - } - public virtual void hide(int m) - { - hideMask.add(m); - } - public virtual void hide(BitSet mask) - { - hideMask = mask; - } - protected internal virtual IHiddenStreamToken LA(int i) - { - return nextMonitoredToken; - } - /*Return the next monitored token. - * Test the token following the monitored token. - * If following is another monitored token, save it - * for the next invocation of nextToken (like a single - * lookahead token) and return it then. - * If following is unmonitored, nondiscarded (hidden) - * channel token, add it to the monitored token. - * - * Note: EOF must be a monitored Token. - */ - override public IToken nextToken() - { - // handle an initial condition; don't want to get lookahead - // token of this splitter until first call to nextToken - if (LA(1) == null) - { - consumeFirst(); - } - - // we always consume hidden tokens after monitored, thus, - // upon entry LA(1) is a monitored token. - IHiddenStreamToken monitored = LA(1); - // point to hidden tokens found during last invocation - monitored.setHiddenBefore(lastHiddenToken); - lastHiddenToken = null; - - // Look for hidden tokens, hook them into list emanating - // from the monitored tokens. - consume(); - IHiddenStreamToken p = monitored; - // while hidden or discarded scarf tokens - while (hideMask.member(LA(1).Type) || discardMask.member(LA(1).Type)) - { - if (hideMask.member(LA(1).Type)) - { - // attach the hidden token to the monitored in a chain - // link forwards - p.setHiddenAfter(LA(1)); - // link backwards - if (p != monitored) - { - //hidden cannot point to monitored tokens - LA(1).setHiddenBefore(p); - } - p = (lastHiddenToken = LA(1)); - } - consume(); - } - return monitored; - } - public virtual void resetState() - { - firstHidden = null; - lastHiddenToken = null; - nextMonitoredToken = null; - } - } + /*track tail of hidden list emanating from previous + * monitored token + */ + protected internal IHiddenStreamToken lastHiddenToken; + + protected internal IHiddenStreamToken firstHidden = null; + + public TokenStreamHiddenTokenFilter(TokenStream input) : base(input) + { + hideMask = new BitSet(); + } + + protected internal virtual void consume() + { + nextMonitoredToken = (IHiddenStreamToken) input.nextToken(); + } + + private void consumeFirst() + { + consume(); // get first token of input stream + + // Handle situation where hidden or discarded tokens + // appear first in input stream + IHiddenStreamToken p = null; + // while hidden or discarded scarf tokens + while (hideMask.member(LA(1).Type) || discardMask.member(LA(1).Type)) + { + if (hideMask.member(LA(1).Type)) + { + if (p == null) + { + p = LA(1); + } + else + { + p.setHiddenAfter(LA(1)); + LA(1).setHiddenBefore(p); // double-link + p = LA(1); + } + + lastHiddenToken = p; + if (firstHidden == null) + { + firstHidden = p; // record hidden token if first + } + } + + consume(); + } + } + + public virtual BitSet getDiscardMask() + { + return discardMask; + } + + /*Return a ptr to the hidden token appearing immediately after + * token t in the input stream. + */ + public virtual IHiddenStreamToken getHiddenAfter(IHiddenStreamToken t) + { + return t.getHiddenAfter(); + } + + /*Return a ptr to the hidden token appearing immediately before + * token t in the input stream. + */ + public virtual IHiddenStreamToken getHiddenBefore(IHiddenStreamToken t) + { + return t.getHiddenBefore(); + } + + public virtual BitSet getHideMask() + { + return hideMask; + } + + /*Return the first hidden token if one appears + * before any monitored token. + */ + public virtual IHiddenStreamToken getInitialHiddenToken() + { + return firstHidden; + } + + public virtual void hide(int m) + { + hideMask.add(m); + } + + public virtual void hide(BitSet mask) + { + hideMask = mask; + } + + protected internal virtual IHiddenStreamToken LA(int i) + { + return nextMonitoredToken; + } + + /*Return the next monitored token. + * Test the token following the monitored token. + * If following is another monitored token, save it + * for the next invocation of nextToken (like a single + * lookahead token) and return it then. + * If following is unmonitored, nondiscarded (hidden) + * channel token, add it to the monitored token. + * + * Note: EOF must be a monitored Token. + */ + override public IToken nextToken() + { + // handle an initial condition; don't want to get lookahead + // token of this splitter until first call to nextToken + if (LA(1) == null) + { + consumeFirst(); + } + + // we always consume hidden tokens after monitored, thus, + // upon entry LA(1) is a monitored token. + IHiddenStreamToken monitored = LA(1); + // point to hidden tokens found during last invocation + monitored.setHiddenBefore(lastHiddenToken); + lastHiddenToken = null; + + // Look for hidden tokens, hook them into list emanating + // from the monitored tokens. + consume(); + IHiddenStreamToken p = monitored; + // while hidden or discarded scarf tokens + while (hideMask.member(LA(1).Type) || discardMask.member(LA(1).Type)) + { + if (hideMask.member(LA(1).Type)) + { + // attach the hidden token to the monitored in a chain + // link forwards + p.setHiddenAfter(LA(1)); + // link backwards + if (p != monitored) + { + //hidden cannot point to monitored tokens + LA(1).setHiddenBefore(p); + } + + p = (lastHiddenToken = LA(1)); + } + + consume(); + } + + return monitored; + } + + public virtual void resetState() + { + firstHidden = null; + lastHiddenToken = null; + nextMonitoredToken = null; + } } \ No newline at end of file diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/TokenStreamIOException.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/TokenStreamIOException.cs index 9dd9245b..5e42b7eb 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/TokenStreamIOException.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/TokenStreamIOException.cs @@ -1,36 +1,35 @@ using IOException = System.IO.IOException; -namespace Spring.Expressions.Parser.antlr +namespace Spring.Expressions.Parser.antlr; +/*ANTLR Translator Generator + * Project led by Terence Parr at http://www.jGuru.com + * Software rights: http://www.antlr.org/license.html + * + * $Id:$ + */ + +// +// ANTLR C# Code Generator by Micheal Jordan +// Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com +// Anthony Oguntimehin +// +// With many thanks to Eric V. Smith from the ANTLR list. +// + +/* + * Wraps an IOException in a TokenStreamException + */ +[Serializable] +public class TokenStreamIOException : TokenStreamException { - /*ANTLR Translator Generator - * Project led by Terence Parr at http://www.jGuru.com - * Software rights: http://www.antlr.org/license.html - * - * $Id:$ - */ + public IOException io; - // - // ANTLR C# Code Generator by Micheal Jordan - // Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com - // Anthony Oguntimehin - // - // With many thanks to Eric V. Smith from the ANTLR list. - // - - /* - * Wraps an IOException in a TokenStreamException - */ - [Serializable] - public class TokenStreamIOException : TokenStreamException - { - public IOException io; - /* - * TokenStreamIOException constructor comment. - * @param s java.lang.String - */ - public TokenStreamIOException(IOException io) : base(io.Message) - { - this.io = io; - } - } -} + /* + * TokenStreamIOException constructor comment. + * @param s java.lang.String + */ + public TokenStreamIOException(IOException io) : base(io.Message) + { + this.io = io; + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/TokenStreamRecognitionException.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/TokenStreamRecognitionException.cs index 0290f4e9..4af2233e 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/TokenStreamRecognitionException.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/TokenStreamRecognitionException.cs @@ -1,39 +1,36 @@ -namespace Spring.Expressions.Parser.antlr +namespace Spring.Expressions.Parser.antlr; +/*ANTLR Translator Generator + * Project led by Terence Parr at http://www.jGuru.com + * Software rights: http://www.antlr.org/license.html + * + * $Id:$ + */ + +// +// ANTLR C# Code Generator by Micheal Jordan +// Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com +// Anthony Oguntimehin +// +// With many thanks to Eric V. Smith from the ANTLR list. +// +/* + * Wraps a RecognitionException in a TokenStreamException so you + * can pass it along. + */ + +[Serializable] +public class TokenStreamRecognitionException : TokenStreamException { - /*ANTLR Translator Generator - * Project led by Terence Parr at http://www.jGuru.com - * Software rights: http://www.antlr.org/license.html - * - * $Id:$ - */ + public RecognitionException recog; - // - // ANTLR C# Code Generator by Micheal Jordan - // Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com - // Anthony Oguntimehin - // - // With many thanks to Eric V. Smith from the ANTLR list. - // + public TokenStreamRecognitionException(RecognitionException re) : + base(re.Message) + { + this.recog = re; + } - /* - * Wraps a RecognitionException in a TokenStreamException so you - * can pass it along. - */ - - [Serializable] - public class TokenStreamRecognitionException : TokenStreamException - { - public RecognitionException recog; - - public TokenStreamRecognitionException(RecognitionException re) : - base(re.Message) - { - this.recog = re; - } - - override public string ToString() - { - return recog.ToString(); - } - } + override public string ToString() + { + return recog.ToString(); + } } diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/TokenStreamRetryException.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/TokenStreamRetryException.cs index 6a8f6b2a..9796d759 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/TokenStreamRetryException.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/TokenStreamRetryException.cs @@ -1,29 +1,26 @@ -namespace Spring.Expressions.Parser.antlr +namespace Spring.Expressions.Parser.antlr; +/*ANTLR Translator Generator + * Project led by Terence Parr at http://www.jGuru.com + * Software rights: http://www.antlr.org/license.html + * + * $Id:$ + */ + +// +// ANTLR C# Code Generator by Micheal Jordan +// Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com +// Anthony Oguntimehin +// +// With many thanks to Eric V. Smith from the ANTLR list. +// +/* + * Aborted recognition of current token. Try to get one again. + * Used by TokenStreamSelector.retry() to force nextToken() + * of stream to re-enter and retry. + */ + +[Serializable] +public class TokenStreamRetryException : TokenStreamException { - /*ANTLR Translator Generator - * Project led by Terence Parr at http://www.jGuru.com - * Software rights: http://www.antlr.org/license.html - * - * $Id:$ - */ - - // - // ANTLR C# Code Generator by Micheal Jordan - // Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com - // Anthony Oguntimehin - // - // With many thanks to Eric V. Smith from the ANTLR list. - // - - /* - * Aborted recognition of current token. Try to get one again. - * Used by TokenStreamSelector.retry() to force nextToken() - * of stream to re-enter and retry. - */ - - [Serializable] - public class TokenStreamRetryException : TokenStreamException - { - public TokenStreamRetryException() {} - } + public TokenStreamRetryException() { } } diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/TokenStreamRewriteEngine.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/TokenStreamRewriteEngine.cs index 2518cc28..cee7551b 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/TokenStreamRewriteEngine.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/TokenStreamRewriteEngine.cs @@ -1,551 +1,559 @@ -namespace Spring.Expressions.Parser.antlr +namespace Spring.Expressions.Parser.antlr; + +/* ANTLR Translator Generator + * Project led by Terence Parr at http://www.jGuru.com + * Software rights: http://www.antlr.org/license.html + */ + +// +// ANTLR C# Code Generator by Micheal Jordan +// Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com +// Anthony Oguntimehin +// +using IList = System.Collections.IList; +using IDictionary = System.Collections.IDictionary; +using ArrayList = System.Collections.ArrayList; +using Hashtable = System.Collections.Hashtable; +using IComparer = System.Collections.IComparer; +using StringBuilder = System.Text.StringBuilder; +using BitSet = antlr.collections.impl.BitSet; + +/// +/// This token stream tracks the *entire* token stream coming from +/// a lexer, but does not pass on the whitespace (or whatever else +/// you want to discard) to the parser. +/// +/// +/// +/// This class can then be asked for the ith token in the input stream. +/// Useful for dumping out the input stream exactly after doing some +/// augmentation or other manipulations. Tokens are index from 0..n-1 +/// +/// +/// You can insert stuff, replace, and delete chunks. Note that the +/// operations are done lazily--only if you convert the buffer to a +/// string. This is very efficient because you are not moving data around +/// all the time. As the buffer of tokens is converted to strings, the +/// toString() method(s) check to see if there is an operation at the +/// current index. If so, the operation is done and then normal string +/// rendering continues on the buffer. This is like having multiple Turing +/// machine instruction streams (programs) operating on a single input tape. :) +/// +/// +/// Since the operations are done lazily at toString-time, operations do not +/// screw up the token index values. That is, an insert operation at token +/// index i does not change the index values for tokens i+1..n-1. +/// +/// +/// Because operations never actually alter the buffer, you may always get +/// the original token stream back without undoing anything. Since +/// the instructions are queued up, you can easily simulate transactions and +/// roll back any changes if there is an error just by removing instructions. +/// For example, +/// +/// For example: +/// +/// TokenStreamRewriteEngine rewriteEngine = new TokenStreamRewriteEngine(lexer); +/// JavaRecognizer parser = new JavaRecognizer(rewriteEngine); +/// ... +/// rewriteEngine.insertAfter("pass1", t, "foobar");} +/// rewriteEngine.insertAfter("pass2", u, "start");} +/// System.Console.Out.WriteLine(rewriteEngine.ToString("pass1")); +/// System.Console.Out.WriteLine(rewriteEngine.ToString("pass2")); +/// +/// +/// +/// You can also have multiple "instruction streams" and get multiple +/// rewrites from a single pass over the input. Just name the instruction +/// streams and use that name again when printing the buffer. This could be +/// useful for generating a C file and also its header file--all from the +/// same buffer. +/// +/// +/// If you don't use named rewrite streams, a "default" stream is used. +/// +/// +/// Terence Parr, parrt@cs.usfca.edu +/// University of San Francisco +/// February 2004 +/// +/// +public class TokenStreamRewriteEngine : TokenStream { - /* ANTLR Translator Generator - * Project led by Terence Parr at http://www.jGuru.com - * Software rights: http://www.antlr.org/license.html - */ - - // - // ANTLR C# Code Generator by Micheal Jordan - // Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com - // Anthony Oguntimehin - // - - using IList = System.Collections.IList; - using IDictionary = System.Collections.IDictionary; - using ArrayList = System.Collections.ArrayList; - using Hashtable = System.Collections.Hashtable; - using IComparer = System.Collections.IComparer; - using StringBuilder = System.Text.StringBuilder; - using BitSet = antlr.collections.impl.BitSet; - - /// - /// This token stream tracks the *entire* token stream coming from - /// a lexer, but does not pass on the whitespace (or whatever else - /// you want to discard) to the parser. - /// - /// - /// - /// This class can then be asked for the ith token in the input stream. - /// Useful for dumping out the input stream exactly after doing some - /// augmentation or other manipulations. Tokens are index from 0..n-1 - /// - /// - /// You can insert stuff, replace, and delete chunks. Note that the - /// operations are done lazily--only if you convert the buffer to a - /// string. This is very efficient because you are not moving data around - /// all the time. As the buffer of tokens is converted to strings, the - /// toString() method(s) check to see if there is an operation at the - /// current index. If so, the operation is done and then normal string - /// rendering continues on the buffer. This is like having multiple Turing - /// machine instruction streams (programs) operating on a single input tape. :) - /// - /// - /// Since the operations are done lazily at toString-time, operations do not - /// screw up the token index values. That is, an insert operation at token - /// index i does not change the index values for tokens i+1..n-1. - /// - /// - /// Because operations never actually alter the buffer, you may always get - /// the original token stream back without undoing anything. Since - /// the instructions are queued up, you can easily simulate transactions and - /// roll back any changes if there is an error just by removing instructions. - /// For example, - /// - /// For example: - /// - /// TokenStreamRewriteEngine rewriteEngine = new TokenStreamRewriteEngine(lexer); - /// JavaRecognizer parser = new JavaRecognizer(rewriteEngine); - /// ... - /// rewriteEngine.insertAfter("pass1", t, "foobar");} - /// rewriteEngine.insertAfter("pass2", u, "start");} - /// System.Console.Out.WriteLine(rewriteEngine.ToString("pass1")); - /// System.Console.Out.WriteLine(rewriteEngine.ToString("pass2")); - /// - /// - /// - /// You can also have multiple "instruction streams" and get multiple - /// rewrites from a single pass over the input. Just name the instruction - /// streams and use that name again when printing the buffer. This could be - /// useful for generating a C file and also its header file--all from the - /// same buffer. - /// - /// - /// If you don't use named rewrite streams, a "default" stream is used. - /// - /// - /// Terence Parr, parrt@cs.usfca.edu - /// University of San Francisco - /// February 2004 - /// - /// - public class TokenStreamRewriteEngine : TokenStream - { - public const int MIN_TOKEN_INDEX = 0; - - protected class RewriteOperation - { - protected internal int index; - protected internal string text; - - protected RewriteOperation(int index, string text) - { - this.index = index; - this.text = text; - } - - /// - /// Execute the rewrite operation by possibly adding to the buffer. - /// - /// rewrite buffer - /// The index of the next token to operate on. - public virtual int execute(StringBuilder buf) - { - return index; - } - } - - protected class InsertBeforeOp : RewriteOperation - { - public InsertBeforeOp(int index, string text) : base(index, text) - { - } - - public override int execute(StringBuilder buf) - { - buf.Append(text); - return index; - } - } - - protected class ReplaceOp : RewriteOperation - { - protected int lastIndex; - - public ReplaceOp(int from, int to, string text) : base(from, text) - { - lastIndex = to; - } - - public override int execute(StringBuilder buf) - { - if ( text != null ) - { - buf.Append(text); - } - return lastIndex+1; - } - } - - protected class DeleteOp : ReplaceOp - { - public DeleteOp(int from, int to) : base(from, to, null) - { - } - } - - public const string DEFAULT_PROGRAM_NAME = "default"; - public const int PROGRAM_INIT_SIZE = 100; - - /// - /// Track the incoming list of tokens - /// - protected IList tokens; - - /// - /// You may have multiple, named streams of rewrite operations. - /// I'm calling these things "programs." - /// Maps string (name) -> rewrite (List) - /// - protected IDictionary programs = null; - - /// - /// Map string (program name) -> Integer index - /// - protected IDictionary lastRewriteTokenIndexes = null; - - /// - /// track index of tokens - /// - protected int index = MIN_TOKEN_INDEX; - - /// - /// Who do we suck tokens from? - /// - protected TokenStream stream; - - /// - /// Which (whitespace) token(s) to throw out - /// - protected BitSet discardMask = new BitSet(); - - public TokenStreamRewriteEngine(TokenStream upstream) : this(upstream, 1000) - { - } - - public TokenStreamRewriteEngine(TokenStream upstream, int initialSize) - { - stream = upstream; - tokens = new ArrayList(initialSize); - programs = new Hashtable(); - programs[DEFAULT_PROGRAM_NAME] = new ArrayList(PROGRAM_INIT_SIZE); - lastRewriteTokenIndexes = new Hashtable(); - } - - public IToken nextToken() // throws TokenStreamException - { - TokenWithIndex t; - - // suck tokens until end of stream or we find a non-discarded token - do - { - t = (TokenWithIndex) stream.nextToken(); - if ( t != null ) - { - t.setIndex(index); // what is t's index in list? - if ( t.Type != Token.EOF_TYPE ) - { - tokens.Add(t); // track all tokens except EOF - } - index++; // move to next position - } - } while ( (t != null) && (discardMask.member(t.Type)) ); - - return t; - } - - public void rollback(int instructionIndex) - { - rollback(DEFAULT_PROGRAM_NAME, instructionIndex); - } - - /// - /// Rollback the instruction stream for a program so that - /// the indicated instruction (via instructionIndex) is no - /// longer in the stream. - /// - /// - /// UNTESTED! - /// - /// - /// - public void rollback(string programName, int instructionIndex) - { - ArrayList il = (ArrayList) programs[programName]; - if ( il != null ) - { - programs[programName] = il.GetRange(MIN_TOKEN_INDEX, (instructionIndex - MIN_TOKEN_INDEX)); - } - } - - public void deleteProgram() - { - deleteProgram(DEFAULT_PROGRAM_NAME); - } - - /// - /// Reset the program so that no instructions exist - /// - /// - public void deleteProgram(string programName) - { - rollback(programName, MIN_TOKEN_INDEX); - } - - /// - /// If op.index > lastRewriteTokenIndexes, just add to the end. - /// Otherwise, do linear - /// - /// - protected void addToSortedRewriteList(RewriteOperation op) - { - addToSortedRewriteList(DEFAULT_PROGRAM_NAME, op); - } - - protected void addToSortedRewriteList(string programName, RewriteOperation op) - { - ArrayList rewrites = (ArrayList) getProgram(programName); - // if at or beyond last op's index, just append - if ( op.index >= getLastRewriteTokenIndex(programName) ) - { - rewrites.Add(op); // append to list of operations - // record the index of this operation for next time through - setLastRewriteTokenIndex(programName, op.index); - return; - } - // not after the last one, so must insert to ordered list - int pos = rewrites.BinarySearch(op, RewriteOperationComparer.Default); - if (pos < 0) - { - rewrites.Insert(-pos-1, op); - } - } - - public void insertAfter(IToken t, string text) - { - insertAfter(DEFAULT_PROGRAM_NAME, t, text); - } - - public void insertAfter(int index, string text) - { - insertAfter(DEFAULT_PROGRAM_NAME, index, text); - } - - public void insertAfter(string programName, IToken t, string text) - { - insertAfter(programName,((TokenWithIndex) t).getIndex(), text); - } - - public void insertAfter(string programName, int index, string text) - { - // to insert after, just insert before next index (even if past end) - insertBefore(programName, index+1, text); - } - - public void insertBefore(IToken t, string text) - { - insertBefore(DEFAULT_PROGRAM_NAME, t, text); - } - - public void insertBefore(int index, string text) - { - insertBefore(DEFAULT_PROGRAM_NAME, index, text); - } - - public void insertBefore(string programName, IToken t, string text) - { - insertBefore(programName, ((TokenWithIndex) t).getIndex(), text); - } - - public void insertBefore(string programName, int index, string text) - { - addToSortedRewriteList(programName, new InsertBeforeOp(index, text)); - } - - public void replace(int index, string text) - { - replace(DEFAULT_PROGRAM_NAME, index, index, text); - } - - public void replace(int from, int to, string text) - { - replace(DEFAULT_PROGRAM_NAME, from, to, text); - } - - public void replace(IToken indexT, string text) - { - replace(DEFAULT_PROGRAM_NAME, indexT, indexT, text); - } - - public void replace(IToken from, IToken to, string text) - { - replace(DEFAULT_PROGRAM_NAME, from, to, text); - } - - public void replace(string programName, int from, int to, string text) - { - addToSortedRewriteList(new ReplaceOp(from, to, text)); - } - - public void replace(string programName, IToken from, IToken to, string text) - { - replace(programName, - ((TokenWithIndex) from).getIndex(), - ((TokenWithIndex) to).getIndex(), - text); - } - - public void delete(int index) - { - delete(DEFAULT_PROGRAM_NAME, index, index); - } - - public void delete(int from, int to) - { - delete(DEFAULT_PROGRAM_NAME, from, to); - } - - public void delete(IToken indexT) - { - delete(DEFAULT_PROGRAM_NAME, indexT, indexT); - } - - public void delete(IToken from, IToken to) - { - delete(DEFAULT_PROGRAM_NAME, from, to); - } - - public void delete(string programName, int from, int to) - { - replace(programName, from, to, null); - } - - public void delete(string programName, IToken from, IToken to) - { - replace(programName, from, to, null); - } - - public void discard(int ttype) - { - discardMask.add(ttype); - } - - public TokenWithIndex getToken(int i) - { - return (TokenWithIndex) tokens[i]; - } - - public int getTokenStreamSize() - { - return tokens.Count; - } - - public string ToOriginalString() - { - return ToOriginalString(MIN_TOKEN_INDEX, getTokenStreamSize()-1); - } - - public string ToOriginalString(int start, int end) - { - StringBuilder buf = new StringBuilder(); - for (int i = start; (i >= MIN_TOKEN_INDEX) && (i <= end) && (i < tokens.Count); i++) - { - buf.Append(getToken(i).getText()); - } - return buf.ToString(); - } - - public override string ToString() - { - return ToString(MIN_TOKEN_INDEX, getTokenStreamSize()); - } - - public string ToString(string programName) - { - return ToString(programName, MIN_TOKEN_INDEX, getTokenStreamSize()); - } - - public string ToString(int start, int end) - { - return ToString(DEFAULT_PROGRAM_NAME, start, end); - } - - public string ToString(string programName, int start, int end) - { - IList rewrites = (IList) programs[programName]; - if (rewrites == null) - { - return null; // invalid program - } - StringBuilder buf = new StringBuilder(); - - // Index of first rewrite we have not done - int rewriteOpIndex = 0; - - int tokenCursor = start; - while ( (tokenCursor >= MIN_TOKEN_INDEX) && - (tokenCursor <= end) && - (tokenCursor < tokens.Count) ) - { - if (rewriteOpIndex < rewrites.Count) - { - RewriteOperation op = (RewriteOperation) rewrites[rewriteOpIndex]; - while ( (tokenCursor == op.index) && (rewriteOpIndex < rewrites.Count) ) - { - /* - Console.Out.WriteLine("execute op "+rewriteOpIndex+ - " (type "+op.GetType().FullName+")" - +" at index "+op.index); - */ - tokenCursor = op.execute(buf); - rewriteOpIndex++; - if (rewriteOpIndex < rewrites.Count) - { - op = (RewriteOperation) rewrites[rewriteOpIndex]; - } - } - } - if ( tokenCursor < end ) - { - buf.Append(getToken(tokenCursor).getText()); - tokenCursor++; - } - } - // now see if there are operations (append) beyond last token index - for (int opi = rewriteOpIndex; opi < rewrites.Count; opi++) - { - RewriteOperation op = (RewriteOperation) rewrites[opi]; - op.execute(buf); // must be insertions if after last token - } - - return buf.ToString(); - } - - public string ToDebugString() - { - return ToDebugString(MIN_TOKEN_INDEX, getTokenStreamSize()); - } - - public string ToDebugString(int start, int end) - { - StringBuilder buf = new StringBuilder(); - for (int i = start; (i >= MIN_TOKEN_INDEX) && (i <= end) && (i < tokens.Count); i++) - { - buf.Append(getToken(i)); - } - return buf.ToString(); - } - - public int getLastRewriteTokenIndex() - { - return getLastRewriteTokenIndex(DEFAULT_PROGRAM_NAME); - } - - protected int getLastRewriteTokenIndex(string programName) - { - object i = lastRewriteTokenIndexes[programName]; - if (i == null) - { - return -1; - } - return (int) i; - } - - protected void setLastRewriteTokenIndex(string programName, int i) - { - lastRewriteTokenIndexes[programName] = (object) i; - } - - protected IList getProgram(string name) - { - IList il = (IList) programs[name]; - if ( il == null ) - { - il = initializeProgram(name); - } - return il; - } - - private IList initializeProgram(string name) - { - IList il = new ArrayList(PROGRAM_INIT_SIZE); - programs[name] = il; - return il; - } - - public class RewriteOperationComparer : IComparer - { - public static readonly RewriteOperationComparer Default = new RewriteOperationComparer(); - - public virtual int Compare(object o1, object o2) - { - RewriteOperation rop1 = (RewriteOperation) o1; - RewriteOperation rop2 = (RewriteOperation) o2; - - if (rop1.index < rop2.index) return -1; - if (rop1.index > rop2.index) return 1; - return 0; - } - } - } + public const int MIN_TOKEN_INDEX = 0; + + protected class RewriteOperation + { + protected internal int index; + protected internal string text; + + protected RewriteOperation(int index, string text) + { + this.index = index; + this.text = text; + } + + /// + /// Execute the rewrite operation by possibly adding to the buffer. + /// + /// rewrite buffer + /// The index of the next token to operate on. + public virtual int execute(StringBuilder buf) + { + return index; + } + } + + protected class InsertBeforeOp : RewriteOperation + { + public InsertBeforeOp(int index, string text) : base(index, text) + { + } + + public override int execute(StringBuilder buf) + { + buf.Append(text); + return index; + } + } + + protected class ReplaceOp : RewriteOperation + { + protected int lastIndex; + + public ReplaceOp(int from, int to, string text) : base(from, text) + { + lastIndex = to; + } + + public override int execute(StringBuilder buf) + { + if (text != null) + { + buf.Append(text); + } + + return lastIndex + 1; + } + } + + protected class DeleteOp : ReplaceOp + { + public DeleteOp(int from, int to) : base(from, to, null) + { + } + } + + public const string DEFAULT_PROGRAM_NAME = "default"; + public const int PROGRAM_INIT_SIZE = 100; + + /// + /// Track the incoming list of tokens + /// + protected IList tokens; + + /// + /// You may have multiple, named streams of rewrite operations. + /// I'm calling these things "programs." + /// Maps string (name) -> rewrite (List) + /// + protected IDictionary programs = null; + + /// + /// Map string (program name) -> Integer index + /// + protected IDictionary lastRewriteTokenIndexes = null; + + /// + /// track index of tokens + /// + protected int index = MIN_TOKEN_INDEX; + + /// + /// Who do we suck tokens from? + /// + protected TokenStream stream; + + /// + /// Which (whitespace) token(s) to throw out + /// + protected BitSet discardMask = new BitSet(); + + public TokenStreamRewriteEngine(TokenStream upstream) : this(upstream, 1000) + { + } + + public TokenStreamRewriteEngine(TokenStream upstream, int initialSize) + { + stream = upstream; + tokens = new ArrayList(initialSize); + programs = new Hashtable(); + programs[DEFAULT_PROGRAM_NAME] = new ArrayList(PROGRAM_INIT_SIZE); + lastRewriteTokenIndexes = new Hashtable(); + } + + public IToken nextToken() // throws TokenStreamException + { + TokenWithIndex t; + + // suck tokens until end of stream or we find a non-discarded token + do + { + t = (TokenWithIndex) stream.nextToken(); + if (t != null) + { + t.setIndex(index); // what is t's index in list? + if (t.Type != Token.EOF_TYPE) + { + tokens.Add(t); // track all tokens except EOF + } + + index++; // move to next position + } + } while ((t != null) && (discardMask.member(t.Type))); + + return t; + } + + public void rollback(int instructionIndex) + { + rollback(DEFAULT_PROGRAM_NAME, instructionIndex); + } + + /// + /// Rollback the instruction stream for a program so that + /// the indicated instruction (via instructionIndex) is no + /// longer in the stream. + /// + /// + /// UNTESTED! + /// + /// + /// + public void rollback(string programName, int instructionIndex) + { + ArrayList il = (ArrayList) programs[programName]; + if (il != null) + { + programs[programName] = il.GetRange(MIN_TOKEN_INDEX, (instructionIndex - MIN_TOKEN_INDEX)); + } + } + + public void deleteProgram() + { + deleteProgram(DEFAULT_PROGRAM_NAME); + } + + /// + /// Reset the program so that no instructions exist + /// + /// + public void deleteProgram(string programName) + { + rollback(programName, MIN_TOKEN_INDEX); + } + + /// + /// If op.index > lastRewriteTokenIndexes, just add to the end. + /// Otherwise, do linear + /// + /// + protected void addToSortedRewriteList(RewriteOperation op) + { + addToSortedRewriteList(DEFAULT_PROGRAM_NAME, op); + } + + protected void addToSortedRewriteList(string programName, RewriteOperation op) + { + ArrayList rewrites = (ArrayList) getProgram(programName); + // if at or beyond last op's index, just append + if (op.index >= getLastRewriteTokenIndex(programName)) + { + rewrites.Add(op); // append to list of operations + // record the index of this operation for next time through + setLastRewriteTokenIndex(programName, op.index); + return; + } + + // not after the last one, so must insert to ordered list + int pos = rewrites.BinarySearch(op, RewriteOperationComparer.Default); + if (pos < 0) + { + rewrites.Insert(-pos - 1, op); + } + } + + public void insertAfter(IToken t, string text) + { + insertAfter(DEFAULT_PROGRAM_NAME, t, text); + } + + public void insertAfter(int index, string text) + { + insertAfter(DEFAULT_PROGRAM_NAME, index, text); + } + + public void insertAfter(string programName, IToken t, string text) + { + insertAfter(programName, ((TokenWithIndex) t).getIndex(), text); + } + + public void insertAfter(string programName, int index, string text) + { + // to insert after, just insert before next index (even if past end) + insertBefore(programName, index + 1, text); + } + + public void insertBefore(IToken t, string text) + { + insertBefore(DEFAULT_PROGRAM_NAME, t, text); + } + + public void insertBefore(int index, string text) + { + insertBefore(DEFAULT_PROGRAM_NAME, index, text); + } + + public void insertBefore(string programName, IToken t, string text) + { + insertBefore(programName, ((TokenWithIndex) t).getIndex(), text); + } + + public void insertBefore(string programName, int index, string text) + { + addToSortedRewriteList(programName, new InsertBeforeOp(index, text)); + } + + public void replace(int index, string text) + { + replace(DEFAULT_PROGRAM_NAME, index, index, text); + } + + public void replace(int from, int to, string text) + { + replace(DEFAULT_PROGRAM_NAME, from, to, text); + } + + public void replace(IToken indexT, string text) + { + replace(DEFAULT_PROGRAM_NAME, indexT, indexT, text); + } + + public void replace(IToken from, IToken to, string text) + { + replace(DEFAULT_PROGRAM_NAME, from, to, text); + } + + public void replace(string programName, int from, int to, string text) + { + addToSortedRewriteList(new ReplaceOp(from, to, text)); + } + + public void replace(string programName, IToken from, IToken to, string text) + { + replace(programName, + ((TokenWithIndex) from).getIndex(), + ((TokenWithIndex) to).getIndex(), + text); + } + + public void delete(int index) + { + delete(DEFAULT_PROGRAM_NAME, index, index); + } + + public void delete(int from, int to) + { + delete(DEFAULT_PROGRAM_NAME, from, to); + } + + public void delete(IToken indexT) + { + delete(DEFAULT_PROGRAM_NAME, indexT, indexT); + } + + public void delete(IToken from, IToken to) + { + delete(DEFAULT_PROGRAM_NAME, from, to); + } + + public void delete(string programName, int from, int to) + { + replace(programName, from, to, null); + } + + public void delete(string programName, IToken from, IToken to) + { + replace(programName, from, to, null); + } + + public void discard(int ttype) + { + discardMask.add(ttype); + } + + public TokenWithIndex getToken(int i) + { + return (TokenWithIndex) tokens[i]; + } + + public int getTokenStreamSize() + { + return tokens.Count; + } + + public string ToOriginalString() + { + return ToOriginalString(MIN_TOKEN_INDEX, getTokenStreamSize() - 1); + } + + public string ToOriginalString(int start, int end) + { + StringBuilder buf = new StringBuilder(); + for (int i = start; (i >= MIN_TOKEN_INDEX) && (i <= end) && (i < tokens.Count); i++) + { + buf.Append(getToken(i).getText()); + } + + return buf.ToString(); + } + + public override string ToString() + { + return ToString(MIN_TOKEN_INDEX, getTokenStreamSize()); + } + + public string ToString(string programName) + { + return ToString(programName, MIN_TOKEN_INDEX, getTokenStreamSize()); + } + + public string ToString(int start, int end) + { + return ToString(DEFAULT_PROGRAM_NAME, start, end); + } + + public string ToString(string programName, int start, int end) + { + IList rewrites = (IList) programs[programName]; + if (rewrites == null) + { + return null; // invalid program + } + + StringBuilder buf = new StringBuilder(); + + // Index of first rewrite we have not done + int rewriteOpIndex = 0; + + int tokenCursor = start; + while ((tokenCursor >= MIN_TOKEN_INDEX) && + (tokenCursor <= end) && + (tokenCursor < tokens.Count)) + { + if (rewriteOpIndex < rewrites.Count) + { + RewriteOperation op = (RewriteOperation) rewrites[rewriteOpIndex]; + while ((tokenCursor == op.index) && (rewriteOpIndex < rewrites.Count)) + { + /* + Console.Out.WriteLine("execute op "+rewriteOpIndex+ + " (type "+op.GetType().FullName+")" + +" at index "+op.index); + */ + tokenCursor = op.execute(buf); + rewriteOpIndex++; + if (rewriteOpIndex < rewrites.Count) + { + op = (RewriteOperation) rewrites[rewriteOpIndex]; + } + } + } + + if (tokenCursor < end) + { + buf.Append(getToken(tokenCursor).getText()); + tokenCursor++; + } + } + + // now see if there are operations (append) beyond last token index + for (int opi = rewriteOpIndex; opi < rewrites.Count; opi++) + { + RewriteOperation op = (RewriteOperation) rewrites[opi]; + op.execute(buf); // must be insertions if after last token + } + + return buf.ToString(); + } + + public string ToDebugString() + { + return ToDebugString(MIN_TOKEN_INDEX, getTokenStreamSize()); + } + + public string ToDebugString(int start, int end) + { + StringBuilder buf = new StringBuilder(); + for (int i = start; (i >= MIN_TOKEN_INDEX) && (i <= end) && (i < tokens.Count); i++) + { + buf.Append(getToken(i)); + } + + return buf.ToString(); + } + + public int getLastRewriteTokenIndex() + { + return getLastRewriteTokenIndex(DEFAULT_PROGRAM_NAME); + } + + protected int getLastRewriteTokenIndex(string programName) + { + object i = lastRewriteTokenIndexes[programName]; + if (i == null) + { + return -1; + } + + return (int) i; + } + + protected void setLastRewriteTokenIndex(string programName, int i) + { + lastRewriteTokenIndexes[programName] = (object) i; + } + + protected IList getProgram(string name) + { + IList il = (IList) programs[name]; + if (il == null) + { + il = initializeProgram(name); + } + + return il; + } + + private IList initializeProgram(string name) + { + IList il = new ArrayList(PROGRAM_INIT_SIZE); + programs[name] = il; + return il; + } + + public class RewriteOperationComparer : IComparer + { + public static readonly RewriteOperationComparer Default = new RewriteOperationComparer(); + + public virtual int Compare(object o1, object o2) + { + RewriteOperation rop1 = (RewriteOperation) o1; + RewriteOperation rop2 = (RewriteOperation) o2; + + if (rop1.index < rop2.index) return -1; + if (rop1.index > rop2.index) return 1; + return 0; + } + } } diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/TokenStreamSelector.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/TokenStreamSelector.cs index c09e9bf8..808cb77f 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/TokenStreamSelector.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/TokenStreamSelector.cs @@ -1,125 +1,134 @@ -using Hashtable = System.Collections.Hashtable; -using Stack = System.Collections.Stack; - -namespace Spring.Expressions.Parser.antlr +using Hashtable = System.Collections.Hashtable; +using Stack = System.Collections.Stack; + +namespace Spring.Expressions.Parser.antlr; +/*ANTLR Translator Generator + * Project led by Terence Parr at http://www.jGuru.com + * Software rights: http://www.antlr.org/license.html + * + * $Id:$ + */ + +// +// ANTLR C# Code Generator by Micheal Jordan +// Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com +// Anthony Oguntimehin +// +// With many thanks to Eric V. Smith from the ANTLR list. +// + +/*A token stream MUX (multiplexor) knows about n token streams + * and can multiplex them onto the same channel for use by token + * stream consumer like a parser. This is a way to have multiple + * lexers break up the same input stream for a single parser. + * Or, you can have multiple instances of the same lexer handle + * multiple input streams; this works great for includes. + */ +public class TokenStreamSelector : TokenStream { - /*ANTLR Translator Generator - * Project led by Terence Parr at http://www.jGuru.com - * Software rights: http://www.antlr.org/license.html - * - * $Id:$ - */ + /*The set of inputs to the MUX */ + protected internal Hashtable inputStreamNames; - // - // ANTLR C# Code Generator by Micheal Jordan - // Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com - // Anthony Oguntimehin - // - // With many thanks to Eric V. Smith from the ANTLR list. - // + /*The currently-selected token stream input */ + protected internal TokenStream input; - /*A token stream MUX (multiplexor) knows about n token streams - * and can multiplex them onto the same channel for use by token - * stream consumer like a parser. This is a way to have multiple - * lexers break up the same input stream for a single parser. - * Or, you can have multiple instances of the same lexer handle - * multiple input streams; this works great for includes. - */ - public class TokenStreamSelector : TokenStream - { - /*The set of inputs to the MUX */ - protected internal Hashtable inputStreamNames; - - /*The currently-selected token stream input */ - protected internal TokenStream input; - - /*Used to track stack of input streams */ - protected internal Stack streamStack = new Stack(); - - public TokenStreamSelector() : base() - { - inputStreamNames = new Hashtable(); - } - public virtual void addInputStream(TokenStream stream, string key) - { - inputStreamNames[key] = stream; - } - /*Return the stream from tokens are being pulled at - * the moment. - */ - public virtual TokenStream getCurrentStream() - { - return input; - } - public virtual TokenStream getStream(string sname) - { - TokenStream stream = (TokenStream) inputStreamNames[sname]; - if (stream == null) - { - throw new System.ArgumentException("TokenStream " + sname + " not found"); - } - return stream; - } - public virtual IToken nextToken() - { - // return input.nextToken(); - // keep looking for a token until you don't - // get a retry exception. - for (; ; ) - { - try - { - return input.nextToken(); - } - catch (TokenStreamRetryException) - { - // just retry "forever" - } - } - } - public virtual TokenStream pop() - { - TokenStream stream = (TokenStream) streamStack.Pop(); - select(stream); - return stream; - } - public virtual void push(TokenStream stream) - { - streamStack.Push(input); // save current stream - select(stream); - } - public virtual void push(string sname) - { - streamStack.Push(input); - select(sname); - } - /*Abort recognition of current Token and try again. - * A stream can push a new stream (for include files - * for example, and then retry(), which will cause - * the current stream to abort back to this.nextToken(). - * this.nextToken() then asks for a token from the - * current stream, which is the new "substream." - */ - public virtual void retry() - { - throw new TokenStreamRetryException(); - } - /*Set the stream without pushing old stream */ - public virtual void select(TokenStream stream) - { - input = stream; - if (input is CharScanner) - { - ((CharScanner) input).refresh(); - } - } - public virtual void select(string sname) - { - input = getStream(sname); - if (input is CharScanner) - { - ((CharScanner) input).refresh(); - } - } - } -} \ No newline at end of file + /*Used to track stack of input streams */ + protected internal Stack streamStack = new Stack(); + + public TokenStreamSelector() : base() + { + inputStreamNames = new Hashtable(); + } + + public virtual void addInputStream(TokenStream stream, string key) + { + inputStreamNames[key] = stream; + } + + /*Return the stream from tokens are being pulled at + * the moment. + */ + public virtual TokenStream getCurrentStream() + { + return input; + } + + public virtual TokenStream getStream(string sname) + { + TokenStream stream = (TokenStream) inputStreamNames[sname]; + if (stream == null) + { + throw new System.ArgumentException("TokenStream " + sname + " not found"); + } + + return stream; + } + + public virtual IToken nextToken() + { + // return input.nextToken(); + // keep looking for a token until you don't + // get a retry exception. + for (;;) + { + try + { + return input.nextToken(); + } + catch (TokenStreamRetryException) + { + // just retry "forever" + } + } + } + + public virtual TokenStream pop() + { + TokenStream stream = (TokenStream) streamStack.Pop(); + select(stream); + return stream; + } + + public virtual void push(TokenStream stream) + { + streamStack.Push(input); // save current stream + select(stream); + } + + public virtual void push(string sname) + { + streamStack.Push(input); + select(sname); + } + + /*Abort recognition of current Token and try again. + * A stream can push a new stream (for include files + * for example, and then retry(), which will cause + * the current stream to abort back to this.nextToken(). + * this.nextToken() then asks for a token from the + * current stream, which is the new "substream." + */ + public virtual void retry() + { + throw new TokenStreamRetryException(); + } + + /*Set the stream without pushing old stream */ + public virtual void select(TokenStream stream) + { + input = stream; + if (input is CharScanner) + { + ((CharScanner) input).refresh(); + } + } + + public virtual void select(string sname) + { + input = getStream(sname); + if (input is CharScanner) + { + ((CharScanner) input).refresh(); + } + } +} diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/TokenWithIndex.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/TokenWithIndex.cs index 4989dcc2..5a209448 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/TokenWithIndex.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/TokenWithIndex.cs @@ -1,49 +1,47 @@ -namespace Spring.Expressions.Parser.antlr +namespace Spring.Expressions.Parser.antlr; +/* ANTLR Translator Generator + * Project led by Terence Parr at http://www.jGuru.com + * Software rights: http://www.antlr.org/license.html + */ + +// +// ANTLR C# Code Generator by Micheal Jordan +// Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com +// Anthony Oguntimehin +// + +/// +/// This token tracks it's own index 0..n-1 relative to the beginning +/// of the stream. It is designed to work with +/// in TokenStreamRewriteEngine.cs +/// +public class TokenWithIndex : CommonToken { - /* ANTLR Translator Generator - * Project led by Terence Parr at http://www.jGuru.com - * Software rights: http://www.antlr.org/license.html - */ - - // - // ANTLR C# Code Generator by Micheal Jordan - // Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com - // Anthony Oguntimehin - // - /// - /// This token tracks it's own index 0..n-1 relative to the beginning - /// of the stream. It is designed to work with - /// in TokenStreamRewriteEngine.cs - /// - public class TokenWithIndex : CommonToken - { - /// - /// Index into token array indicating position in input stream - /// - int index; + /// Index into token array indicating position in input stream + ///
+ int index; - public TokenWithIndex() : base() - { - } + public TokenWithIndex() : base() + { + } - public TokenWithIndex(int i, string t) : base(i, t) - { - } + public TokenWithIndex(int i, string t) : base(i, t) + { + } - public void setIndex(int i) - { - index = i; - } + public void setIndex(int i) + { + index = i; + } - public int getIndex() - { - return index; - } + public int getIndex() + { + return index; + } - public override string ToString() - { - return "["+index+":\"" + getText() + "\",<" + Type + ">,line=" + line + ",col=" + col + "]\n"; - } - } -} \ No newline at end of file + public override string ToString() + { + return "[" + index + ":\"" + getText() + "\",<" + Type + ">,line=" + line + ",col=" + col + "]\n"; + } +} diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/TreeParser.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/TreeParser.cs index 2f111ebe..9d2b991f 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/TreeParser.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/TreeParser.cs @@ -1,177 +1,189 @@ using AST = Spring.Expressions.Parser.antlr.collections.AST; using BitSet = Spring.Expressions.Parser.antlr.collections.impl.BitSet; - -namespace Spring.Expressions.Parser.antlr + +namespace Spring.Expressions.Parser.antlr; +/*ANTLR Translator Generator + * Project led by Terence Parr at http://www.jGuru.com + * Software rights: http://www.antlr.org/license.html + * + * $Id:$ + */ + +// +// ANTLR C# Code Generator by Micheal Jordan +// Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com +// Anthony Oguntimehin +// +// With many thanks to Eric V. Smith from the ANTLR list. +// + +public class TreeParser { - /*ANTLR Translator Generator - * Project led by Terence Parr at http://www.jGuru.com - * Software rights: http://www.antlr.org/license.html - * - * $Id:$ - */ + /*The AST Null object; the parsing cursor is set to this when + * it is found to be null. This way, we can test the + * token type of a node without having to have tests for null + * everywhere. + */ + public static ASTNULLType ASTNULL = new ASTNULLType(); - // - // ANTLR C# Code Generator by Micheal Jordan - // Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com - // Anthony Oguntimehin - // - // With many thanks to Eric V. Smith from the ANTLR list. - // + /*Where did this rule leave off parsing; avoids a return parameter */ + protected internal AST retTree_; - public class TreeParser - { - /*The AST Null object; the parsing cursor is set to this when - * it is found to be null. This way, we can test the - * token type of a node without having to have tests for null - * everywhere. - */ - public static ASTNULLType ASTNULL = new ASTNULLType(); - - /*Where did this rule leave off parsing; avoids a return parameter */ - protected internal AST retTree_; - - /*guessing nesting level; guessing==0 implies not guessing */ - // protected int guessing = 0; - - /*Nesting level of registered handlers */ - // protected int exceptionLevel = 0; - - protected internal TreeParserSharedInputState inputState; - - /*Table of token type to token names */ - protected internal string[] tokenNames; - - /*AST return value for a rule is squirreled away here */ - protected internal AST returnAST; - - /*AST support code; parser and treeparser delegate to this object */ - protected internal ASTFactory astFactory = new ASTFactory(); - - /*Used to keep track of indentdepth for traceIn/Out */ - protected internal int traceDepth = 0; - - public TreeParser() - { - inputState = new TreeParserSharedInputState(); - } - /*Get the AST return value squirreled away in the parser */ - public virtual AST getAST() - { - return returnAST; - } - public virtual ASTFactory getASTFactory() - { - return astFactory; - } - public virtual void resetState() - { - traceDepth = 0; - returnAST = null; - retTree_ = null; - inputState.reset(); - } - public virtual string getTokenName(int num) - { - return tokenNames[num]; - } - public virtual string[] getTokenNames() - { - return tokenNames; - } - protected internal virtual void match(AST t, int ttype) - { - //System.out.println("match("+ttype+"); cursor is "+t); - if (t == null || t == ASTNULL || t.Type != ttype) - { - throw new MismatchedTokenException(getTokenNames(), t, ttype, false); - } - } - /*Make sure current lookahead symbol matches the given set - * Throw an exception upon mismatch, which is catch by either the - * error handler or by the syntactic predicate. - */ - public virtual void match(AST t, BitSet b) - { - if (t == null || t == ASTNULL || !b.member(t.Type)) - { - throw new MismatchedTokenException(getTokenNames(), t, b, false); - } - } - protected internal virtual void matchNot(AST t, int ttype) - { - //System.out.println("match("+ttype+"); cursor is "+t); - if (t == null || t == ASTNULL || t.Type == ttype) - { - throw new MismatchedTokenException(getTokenNames(), t, ttype, true); - } - } + /*guessing nesting level; guessing==0 implies not guessing */ + // protected int guessing = 0; - /// - /// @deprecated as of 2.7.2. This method calls System.exit() and writes - /// directly to stderr, which is usually not appropriate when - /// a parser is embedded into a larger application. Since the method is - /// static, it cannot be overridden to avoid these problems. - /// ANTLR no longer uses this method internally or in generated code. - /// - /// - [Obsolete("De-activated since version 2.7.2.6 as it cannot be overidden.", true)] - public static void panic() - { - Console.Error.WriteLine("TreeWalker: panic"); - System.Environment.Exit(1); - } - /*Parser error-reporting function can be overridden in subclass */ - public virtual void reportError(RecognitionException ex) - { - Console.Error.WriteLine(ex.ToString()); - } - /*Parser error-reporting function can be overridden in subclass */ - public virtual void reportError(string s) - { - Console.Error.WriteLine("error: " + s); - } - /*Parser warning-reporting function can be overridden in subclass */ - public virtual void reportWarning(string s) - { - Console.Error.WriteLine("warning: " + s); - } - /*Specify an object with support code (shared by - * Parser and TreeParser. Normally, the programmer - * does not play with this, using setASTNodeType instead. - */ - public virtual void setASTFactory(ASTFactory f) - { - astFactory = f; - } - - /*Specify the type of node to create during tree building */ - public virtual void setASTNodeType(string nodeType) - { - setASTNodeClass(nodeType); - } - - /*Specify the type of node to create during tree building */ - public virtual void setASTNodeClass(string nodeType) - { - astFactory.setASTNodeType(nodeType); - } - - public virtual void traceIndent() - { - for (int i = 0; i < traceDepth; i++) - Console.Out.Write(" "); - } - public virtual void traceIn(string rname, AST t) - { - traceDepth += 1; - traceIndent(); - Console.Out.WriteLine("> " + rname + "(" + ((t != null) ? t.ToString() : "null") + ")" + ((inputState.guessing > 0) ? " [guessing]" : "")); - } - public virtual void traceOut(string rname, AST t) - { - traceIndent(); - Console.Out.WriteLine("< " + rname + "(" + ((t != null) ? t.ToString() : "null") + ")" + ((inputState.guessing > 0) ? " [guessing]" : "")); - traceDepth--; - } - } + /*Nesting level of registered handlers */ + // protected int exceptionLevel = 0; + + protected internal TreeParserSharedInputState inputState; + + /*Table of token type to token names */ + protected internal string[] tokenNames; + + /*AST return value for a rule is squirreled away here */ + protected internal AST returnAST; + + /*AST support code; parser and treeparser delegate to this object */ + protected internal ASTFactory astFactory = new ASTFactory(); + + /*Used to keep track of indentdepth for traceIn/Out */ + protected internal int traceDepth = 0; + + public TreeParser() + { + inputState = new TreeParserSharedInputState(); + } + + /*Get the AST return value squirreled away in the parser */ + public virtual AST getAST() + { + return returnAST; + } + + public virtual ASTFactory getASTFactory() + { + return astFactory; + } + + public virtual void resetState() + { + traceDepth = 0; + returnAST = null; + retTree_ = null; + inputState.reset(); + } + + public virtual string getTokenName(int num) + { + return tokenNames[num]; + } + + public virtual string[] getTokenNames() + { + return tokenNames; + } + + protected internal virtual void match(AST t, int ttype) + { + //System.out.println("match("+ttype+"); cursor is "+t); + if (t == null || t == ASTNULL || t.Type != ttype) + { + throw new MismatchedTokenException(getTokenNames(), t, ttype, false); + } + } + + /*Make sure current lookahead symbol matches the given set + * Throw an exception upon mismatch, which is catch by either the + * error handler or by the syntactic predicate. + */ + public virtual void match(AST t, BitSet b) + { + if (t == null || t == ASTNULL || !b.member(t.Type)) + { + throw new MismatchedTokenException(getTokenNames(), t, b, false); + } + } + + protected internal virtual void matchNot(AST t, int ttype) + { + //System.out.println("match("+ttype+"); cursor is "+t); + if (t == null || t == ASTNULL || t.Type == ttype) + { + throw new MismatchedTokenException(getTokenNames(), t, ttype, true); + } + } + + /// + /// @deprecated as of 2.7.2. This method calls System.exit() and writes + /// directly to stderr, which is usually not appropriate when + /// a parser is embedded into a larger application. Since the method is + /// static, it cannot be overridden to avoid these problems. + /// ANTLR no longer uses this method internally or in generated code. + /// + /// + [Obsolete("De-activated since version 2.7.2.6 as it cannot be overidden.", true)] + public static void panic() + { + Console.Error.WriteLine("TreeWalker: panic"); + System.Environment.Exit(1); + } + + /*Parser error-reporting function can be overridden in subclass */ + public virtual void reportError(RecognitionException ex) + { + Console.Error.WriteLine(ex.ToString()); + } + + /*Parser error-reporting function can be overridden in subclass */ + public virtual void reportError(string s) + { + Console.Error.WriteLine("error: " + s); + } + + /*Parser warning-reporting function can be overridden in subclass */ + public virtual void reportWarning(string s) + { + Console.Error.WriteLine("warning: " + s); + } + + /*Specify an object with support code (shared by + * Parser and TreeParser. Normally, the programmer + * does not play with this, using setASTNodeType instead. + */ + public virtual void setASTFactory(ASTFactory f) + { + astFactory = f; + } + + /*Specify the type of node to create during tree building */ + public virtual void setASTNodeType(string nodeType) + { + setASTNodeClass(nodeType); + } + + /*Specify the type of node to create during tree building */ + public virtual void setASTNodeClass(string nodeType) + { + astFactory.setASTNodeType(nodeType); + } + + public virtual void traceIndent() + { + for (int i = 0; i < traceDepth; i++) + Console.Out.Write(" "); + } + + public virtual void traceIn(string rname, AST t) + { + traceDepth += 1; + traceIndent(); + Console.Out.WriteLine("> " + rname + "(" + ((t != null) ? t.ToString() : "null") + ")" + ((inputState.guessing > 0) ? " [guessing]" : "")); + } + + public virtual void traceOut(string rname, AST t) + { + traceIndent(); + Console.Out.WriteLine("< " + rname + "(" + ((t != null) ? t.ToString() : "null") + ")" + ((inputState.guessing > 0) ? " [guessing]" : "")); + traceDepth--; + } } diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/TreeParserSharedInputState.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/TreeParserSharedInputState.cs index 13e93509..32287d41 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/TreeParserSharedInputState.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/TreeParserSharedInputState.cs @@ -1,35 +1,32 @@ -namespace Spring.Expressions.Parser.antlr +namespace Spring.Expressions.Parser.antlr; +/*ANTLR Translator Generator + * Project led by Terence Parr at http://www.jGuru.com + * Software rights: http://www.antlr.org/license.html + * + * $Id:$ + */ + +// +// ANTLR C# Code Generator by Micheal Jordan +// Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com +// Anthony Oguntimehin +// +// With many thanks to Eric V. Smith from the ANTLR list. +// +/*This object contains the data associated with an + * input AST. Multiple parsers + * share a single TreeParserSharedInputState to parse + * the same tree or to have the parser walk multiple + * trees. + */ + +public class TreeParserSharedInputState { - /*ANTLR Translator Generator - * Project led by Terence Parr at http://www.jGuru.com - * Software rights: http://www.antlr.org/license.html - * - * $Id:$ - */ + /*Are we guessing (guessing>0)? */ + public int guessing = 0; - // - // ANTLR C# Code Generator by Micheal Jordan - // Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com - // Anthony Oguntimehin - // - // With many thanks to Eric V. Smith from the ANTLR list. - // - - /*This object contains the data associated with an - * input AST. Multiple parsers - * share a single TreeParserSharedInputState to parse - * the same tree or to have the parser walk multiple - * trees. - */ - - public class TreeParserSharedInputState - { - /*Are we guessing (guessing>0)? */ - public int guessing = 0; - - public virtual void reset() - { - guessing = 0; - } - } -} \ No newline at end of file + public virtual void reset() + { + guessing = 0; + } +} diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/collections/AST.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/collections/AST.cs index 9c4cc9d6..87bb4f4c 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/collections/AST.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/collections/AST.cs @@ -1,86 +1,96 @@ using IEnumerator = System.Collections.IEnumerator; -namespace Spring.Expressions.Parser.antlr.collections +namespace Spring.Expressions.Parser.antlr.collections; +/*ANTLR Translator Generator + * Project led by Terence Parr at http://www.jGuru.com + * Software rights: http://www.antlr.org/license.html + * + * $Id:$ + */ + +// +// ANTLR C# Code Generator by Micheal Jordan +// Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com +// Anthony Oguntimehin +// +// With many thanks to Eric V. Smith from the ANTLR list. +// + +/// +/// Minimal AST node interface used by ANTLR AST generation and tree-walker. +/// +public interface AST : ICloneable { - /*ANTLR Translator Generator - * Project led by Terence Parr at http://www.jGuru.com - * Software rights: http://www.antlr.org/license.html - * - * $Id:$ - */ + /// + /// Add a (rightmost) child to this node + /// + /// + void addChild(AST c); - // - // ANTLR C# Code Generator by Micheal Jordan - // Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com - // Anthony Oguntimehin - // - // With many thanks to Eric V. Smith from the ANTLR list. - // + bool Equals(AST t); + bool EqualsList(AST t); + bool EqualsListPartial(AST t); + bool EqualsTree(AST t); + bool EqualsTreePartial(AST t); + IEnumerator findAll(AST tree); + IEnumerator findAllPartial(AST subtree); - /// - /// Minimal AST node interface used by ANTLR AST generation and tree-walker. - /// - public interface AST : ICloneable - { - /// - /// Add a (rightmost) child to this node - /// - /// - void addChild(AST c); - bool Equals(AST t); - bool EqualsList(AST t); - bool EqualsListPartial(AST t); - bool EqualsTree(AST t); - bool EqualsTreePartial(AST t); - IEnumerator findAll(AST tree); - IEnumerator findAllPartial(AST subtree); - /// - /// Get the first child of this node; null if no children - /// - AST getFirstChild(); - /// - /// Get the next sibling in line after this one - /// - AST getNextSibling(); - /// - /// Get the token text for this node - /// - /// - string getText(); - /// - /// Get the token type for this node - /// - int Type { get; set;} - /// - /// Get number of children of this node; if leaf, returns 0 - /// - /// Number of children - int getNumberOfChildren(); - void initialize(int t, string txt); - void initialize(AST t); - void initialize(IToken t); - /// - /// Set the first child of a node. - /// - /// - void setFirstChild(AST c); - /// - /// Set the next sibling after this one. - /// - /// - void setNextSibling(AST n); - /// - /// Set the token text for this node - /// - /// - void setText(string text); - /// - /// Set the token type for this node - /// - /// - void setType(int ttype); - string ToString(); - string ToStringList(); - string ToStringTree(); - } + /// + /// Get the first child of this node; null if no children + /// + AST getFirstChild(); + + /// + /// Get the next sibling in line after this one + /// + AST getNextSibling(); + + /// + /// Get the token text for this node + /// + /// + string getText(); + + /// + /// Get the token type for this node + /// + int Type { get; set; } + + /// + /// Get number of children of this node; if leaf, returns 0 + /// + /// Number of children + int getNumberOfChildren(); + + void initialize(int t, string txt); + void initialize(AST t); + void initialize(IToken t); + + /// + /// Set the first child of a node. + /// + /// + void setFirstChild(AST c); + + /// + /// Set the next sibling after this one. + /// + /// + void setNextSibling(AST n); + + /// + /// Set the token text for this node + /// + /// + void setText(string text); + + /// + /// Set the token type for this node + /// + /// + void setType(int ttype); + + string ToString(); + string ToStringList(); + string ToStringTree(); } diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/collections/impl/ASTArray.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/collections/impl/ASTArray.cs index 675ce60a..c6a06295 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/collections/impl/ASTArray.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/collections/impl/ASTArray.cs @@ -1,39 +1,37 @@ -namespace Spring.Expressions.Parser.antlr.collections.impl +namespace Spring.Expressions.Parser.antlr.collections.impl; +/*ANTLR Translator Generator + * Project led by Terence Parr at http://www.jGuru.com + * Software rights: http://www.antlr.org/license.html + * + * $Id:$ + */ + +// +// ANTLR C# Code Generator by Micheal Jordan +// Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com +// Anthony Oguntimehin +// +// With many thanks to Eric V. Smith from the ANTLR list. +// + +/*ASTArray is a class that allows ANTLR to + * generate code that can create and initialize an array + * in one expression, like: + * (new ASTArray(3)).add(x).add(y).add(z) + */ +public class ASTArray { - /*ANTLR Translator Generator - * Project led by Terence Parr at http://www.jGuru.com - * Software rights: http://www.antlr.org/license.html - * - * $Id:$ - */ + public int size = 0; + public AST[] array; - // - // ANTLR C# Code Generator by Micheal Jordan - // Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com - // Anthony Oguntimehin - // - // With many thanks to Eric V. Smith from the ANTLR list. - // + public ASTArray(int capacity) + { + array = new AST[capacity]; + } - /*ASTArray is a class that allows ANTLR to - * generate code that can create and initialize an array - * in one expression, like: - * (new ASTArray(3)).add(x).add(y).add(z) - */ - public class ASTArray - { - public int size = 0; - public AST[] array; - - - public ASTArray(int capacity) - { - array = new AST[capacity]; - } - public virtual ASTArray add(AST node) - { - array[size++] = node; - return this; - } - } -} \ No newline at end of file + public virtual ASTArray add(AST node) + { + array[size++] = node; + return this; + } +} diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/collections/impl/BitSet.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/collections/impl/BitSet.cs index 6fcc4ce8..3b7cba9d 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/collections/impl/BitSet.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/collections/impl/BitSet.cs @@ -1,538 +1,554 @@ -using ArrayList = System.Collections.ArrayList; +using ArrayList = System.Collections.ArrayList; //using CharFormatter = antlr.CharFormatter; -namespace Spring.Expressions.Parser.antlr.collections.impl +namespace Spring.Expressions.Parser.antlr.collections.impl; +/*ANTLR Translator Generator + * Project led by Terence Parr at http://www.jGuru.com + * Software rights: http://www.antlr.org/license.html + * + * $Id:$ + */ + +// +// ANTLR C# Code Generator by Micheal Jordan +// Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com +// Anthony Oguntimehin +// +// With many thanks to Eric V. Smith from the ANTLR list. +// +/*A BitSet to replace java.util.BitSet. + * Primary differences are that most set operators return new sets + * as opposed to oring and anding "in place". Further, a number of + * operations were added. I cannot contain a BitSet because there + * is no way to access the internal bits (which I need for speed) + * and, because it is final, I cannot subclass to add functionality. + * Consider defining set degree. Without access to the bits, I must + * call a method n times to test the ith bit...ack! + * + * Also seems like or() from util is wrong when size of incoming set is bigger + * than this.bits.length. + * + * @author Terence Parr + * @author
Pete Wells + */ + +public class BitSet : ICloneable { - /*ANTLR Translator Generator - * Project led by Terence Parr at http://www.jGuru.com - * Software rights: http://www.antlr.org/license.html - * - * $Id:$ - */ + protected internal const int BITS = 64; // number of bits / long + protected internal const int NIBBLE = 4; + protected internal const int LOG_BITS = 6; // 2^6 == 64 - // - // ANTLR C# Code Generator by Micheal Jordan - // Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com - // Anthony Oguntimehin - // - // With many thanks to Eric V. Smith from the ANTLR list. - // + /*We will often need to do a mod operator (i mod nbits). Its + * turns out that, for powers of two, this mod operation is + * same as (i & (nbits-1)). Since mod is slow, we use a + * precomputed mod mask to do the mod instead. + */ + protected internal static readonly int MOD_MASK = BITS - 1; - /*A BitSet to replace java.util.BitSet. - * Primary differences are that most set operators return new sets - * as opposed to oring and anding "in place". Further, a number of - * operations were added. I cannot contain a BitSet because there - * is no way to access the internal bits (which I need for speed) - * and, because it is final, I cannot subclass to add functionality. - * Consider defining set degree. Without access to the bits, I must - * call a method n times to test the ith bit...ack! - * - * Also seems like or() from util is wrong when size of incoming set is bigger - * than this.bits.length. - * - * @author Terence Parr - * @author
Pete Wells - */ + /*The actual data bits */ + protected internal long[] dataBits; - public class BitSet : ICloneable - { - protected internal const int BITS = 64; // number of bits / long - protected internal const int NIBBLE = 4; - protected internal const int LOG_BITS = 6; // 2^6 == 64 + /*Construct a bitset of size one word (64 bits) */ + public BitSet() : this(BITS) + { + } - /*We will often need to do a mod operator (i mod nbits). Its - * turns out that, for powers of two, this mod operation is - * same as (i & (nbits-1)). Since mod is slow, we use a - * precomputed mod mask to do the mod instead. - */ - protected internal static readonly int MOD_MASK = BITS - 1; + /*Construction from a static array of longs */ + public BitSet(long[] bits_) + { + dataBits = bits_; + } - /*The actual data bits */ - protected internal long[] dataBits; + /*Construct a bitset given the size + * @param nbits The size of the bitset in bits + */ + public BitSet(int nbits) + { + dataBits = new long[((nbits - 1) >> LOG_BITS) + 1]; + } - /*Construct a bitset of size one word (64 bits) */ - public BitSet() : this(BITS) - { - } + /*or this element into this set (grow as necessary to accommodate) */ + public virtual void add(int el) + { + int n = wordNumber(el); + if (n >= dataBits.Length) + { + growToInclude(el); + } - /*Construction from a static array of longs */ - public BitSet(long[] bits_) - { - dataBits = bits_; - } + dataBits[n] |= bitMask(el); + } - /*Construct a bitset given the size - * @param nbits The size of the bitset in bits - */ - public BitSet(int nbits) - { - dataBits = new long[((nbits - 1) >> LOG_BITS) + 1]; - } + public virtual BitSet and(BitSet a) + { + BitSet s = (BitSet) this.Clone(); + s.andInPlace(a); + return s; + } - /*or this element into this set (grow as necessary to accommodate) */ - public virtual void add(int el) - { - int n = wordNumber(el); - if (n >= dataBits.Length) - { - growToInclude(el); - } - dataBits[n] |= bitMask(el); - } + public virtual void andInPlace(BitSet a) + { + int min = (int) (Math.Min(dataBits.Length, a.dataBits.Length)); + for (int i = min - 1; i >= 0; i--) + { + dataBits[i] &= a.dataBits[i]; + } - public virtual BitSet and(BitSet a) - { - BitSet s = (BitSet) this.Clone(); - s.andInPlace(a); - return s; - } + // clear all bits in this not present in a (if this bigger than a). + for (int i = min; i < dataBits.Length; i++) + { + dataBits[i] = 0; + } + } - public virtual void andInPlace(BitSet a) - { - int min = (int) (Math.Min(dataBits.Length, a.dataBits.Length)); - for (int i = min - 1; i >= 0; i--) - { - dataBits[i] &= a.dataBits[i]; - } - // clear all bits in this not present in a (if this bigger than a). - for (int i = min; i < dataBits.Length; i++) - { - dataBits[i] = 0; - } - } + private static long bitMask(int bitNumber) + { + int bitPosition = bitNumber & MOD_MASK; // bitNumber mod BITS + return 1L << bitPosition; + } - private static long bitMask(int bitNumber) - { - int bitPosition = bitNumber & MOD_MASK; // bitNumber mod BITS - return 1L << bitPosition; - } + public virtual void clear() + { + for (int i = dataBits.Length - 1; i >= 0; i--) + { + dataBits[i] = 0; + } + } - public virtual void clear() - { - for (int i = dataBits.Length - 1; i >= 0; i--) - { - dataBits[i] = 0; - } - } + public virtual void clear(int el) + { + int n = wordNumber(el); + if (n >= dataBits.Length) + { + // grow as necessary to accommodate + growToInclude(el); + } - public virtual void clear(int el) - { - int n = wordNumber(el); - if (n >= dataBits.Length) - { - // grow as necessary to accommodate - growToInclude(el); - } - dataBits[n] &= ~ bitMask(el); - } + dataBits[n] &= ~ bitMask(el); + } - public virtual object Clone() - { - BitSet s; - try - { - s = new BitSet(); - s.dataBits = new long[dataBits.Length]; - Array.Copy(dataBits, 0, s.dataBits, 0, dataBits.Length); - } - catch //(System.Exception e) - { - throw new System.ApplicationException(); - } - return s; - } + public virtual object Clone() + { + BitSet s; + try + { + s = new BitSet(); + s.dataBits = new long[dataBits.Length]; + Array.Copy(dataBits, 0, s.dataBits, 0, dataBits.Length); + } + catch //(System.Exception e) + { + throw new System.ApplicationException(); + } - public virtual int degree() - { - int deg = 0; - for (int i = dataBits.Length - 1; i >= 0; i--) - { - long word = dataBits[i]; - if (word != 0L) - { - for (int bit = BITS - 1; bit >= 0; bit--) - { - if ((word & (1L << bit)) != 0) - { - deg++; - } - } - } - } - return deg; - } + return s; + } - override public int GetHashCode() - { - return dataBits.GetHashCode(); - } + public virtual int degree() + { + int deg = 0; + for (int i = dataBits.Length - 1; i >= 0; i--) + { + long word = dataBits[i]; + if (word != 0L) + { + for (int bit = BITS - 1; bit >= 0; bit--) + { + if ((word & (1L << bit)) != 0) + { + deg++; + } + } + } + } - /*code "inherited" from java.util.BitSet */ - override public bool Equals(object obj) - { - if ((obj != null) && (obj is BitSet)) - { - BitSet bset = (BitSet) obj; + return deg; + } - int n = (int) (System.Math.Min(dataBits.Length, bset.dataBits.Length)); - for (int i = n; i-- > 0; ) - { - if (dataBits[i] != bset.dataBits[i]) - { - return false; - } - } - if (dataBits.Length > n) - { - for (int i = (int) (dataBits.Length); i-- > n; ) - { - if (dataBits[i] != 0) - { - return false; - } - } - } - else if (bset.dataBits.Length > n) - { - for (int i = (int) (bset.dataBits.Length); i-- > n; ) - { - if (bset.dataBits[i] != 0) - { - return false; - } - } - } - return true; - } - return false; - } + override public int GetHashCode() + { + return dataBits.GetHashCode(); + } - /* - * Grows the set to a larger number of bits. - * @param bit element that must fit in set - */ - public virtual void growToInclude(int bit) - { - int newSize = (int) (System.Math.Max(dataBits.Length << 1, numWordsToHold(bit))); - long[] newbits = new long[newSize]; - Array.Copy(dataBits, 0, newbits, 0, dataBits.Length); - dataBits = newbits; - } + /*code "inherited" from java.util.BitSet */ + override public bool Equals(object obj) + { + if ((obj != null) && (obj is BitSet)) + { + BitSet bset = (BitSet) obj; - public virtual bool member(int el) - { - int n = wordNumber(el); - if (n >= dataBits.Length) - return false; - return (dataBits[n] & bitMask(el)) != 0; - } + int n = (int) (System.Math.Min(dataBits.Length, bset.dataBits.Length)); + for (int i = n; i-- > 0;) + { + if (dataBits[i] != bset.dataBits[i]) + { + return false; + } + } - public virtual bool nil() - { - for (int i = dataBits.Length - 1; i >= 0; i--) - { - if (dataBits[i] != 0) - return false; - } - return true; - } + if (dataBits.Length > n) + { + for (int i = (int) (dataBits.Length); i-- > n;) + { + if (dataBits[i] != 0) + { + return false; + } + } + } + else if (bset.dataBits.Length > n) + { + for (int i = (int) (bset.dataBits.Length); i-- > n;) + { + if (bset.dataBits[i] != 0) + { + return false; + } + } + } - public virtual BitSet not() - { - BitSet s = (BitSet) this.Clone(); - s.notInPlace(); - return s; - } + return true; + } - public virtual void notInPlace() - { - for (int i = dataBits.Length - 1; i >= 0; i--) - { - dataBits[i] = ~ dataBits[i]; - } - } + return false; + } - /*complement bits in the range 0..maxBit. */ - public virtual void notInPlace(int maxBit) - { - notInPlace(0, maxBit); - } + /* + * Grows the set to a larger number of bits. + * @param bit element that must fit in set + */ + public virtual void growToInclude(int bit) + { + int newSize = (int) (System.Math.Max(dataBits.Length << 1, numWordsToHold(bit))); + long[] newbits = new long[newSize]; + Array.Copy(dataBits, 0, newbits, 0, dataBits.Length); + dataBits = newbits; + } - /*complement bits in the range minBit..maxBit.*/ - public virtual void notInPlace(int minBit, int maxBit) - { - // make sure that we have room for maxBit - growToInclude(maxBit); - for (int i = minBit; i <= maxBit; i++) - { - int n = wordNumber(i); - dataBits[n] ^= bitMask(i); - } - } + public virtual bool member(int el) + { + int n = wordNumber(el); + if (n >= dataBits.Length) + return false; + return (dataBits[n] & bitMask(el)) != 0; + } - private int numWordsToHold(int el) - { - return (el >> LOG_BITS) + 1; - } + public virtual bool nil() + { + for (int i = dataBits.Length - 1; i >= 0; i--) + { + if (dataBits[i] != 0) + return false; + } - public static BitSet of(int el) - { - BitSet s = new BitSet(el + 1); - s.add(el); - return s; - } + return true; + } - /*return this | a in a new set */ - public virtual BitSet or(BitSet a) - { - BitSet s = (BitSet) this.Clone(); - s.orInPlace(a); - return s; - } + public virtual BitSet not() + { + BitSet s = (BitSet) this.Clone(); + s.notInPlace(); + return s; + } - public virtual void orInPlace(BitSet a) - { - // If this is smaller than a, grow this first - if (a.dataBits.Length > dataBits.Length) - { - setSize((int) (a.dataBits.Length)); - } - int min = (int) (System.Math.Min(dataBits.Length, a.dataBits.Length)); - for (int i = min - 1; i >= 0; i--) - { - dataBits[i] |= a.dataBits[i]; - } - } + public virtual void notInPlace() + { + for (int i = dataBits.Length - 1; i >= 0; i--) + { + dataBits[i] = ~ dataBits[i]; + } + } - // remove this element from this set - public virtual void remove(int el) - { - int n = wordNumber(el); - if (n >= dataBits.Length) - { - growToInclude(el); - } - dataBits[n] &= ~ bitMask(el); - } + /*complement bits in the range 0..maxBit. */ + public virtual void notInPlace(int maxBit) + { + notInPlace(0, maxBit); + } - /* - * Sets the size of a set. - * @param nwords how many words the new set should be - */ - private void setSize(int nwords) - { - long[] newbits = new long[nwords]; - int n = (int) (System.Math.Min(nwords, dataBits.Length)); - Array.Copy(dataBits, 0, newbits, 0, n); - dataBits = newbits; - } + /*complement bits in the range minBit..maxBit.*/ + public virtual void notInPlace(int minBit, int maxBit) + { + // make sure that we have room for maxBit + growToInclude(maxBit); + for (int i = minBit; i <= maxBit; i++) + { + int n = wordNumber(i); + dataBits[n] ^= bitMask(i); + } + } - public virtual int size() - { - return dataBits.Length << LOG_BITS; // num words * bits per word - } + private int numWordsToHold(int el) + { + return (el >> LOG_BITS) + 1; + } - /*return how much space is being used by the dataBits array not - * how many actually have member bits on. - */ - public virtual int lengthInLongWords() - { - return dataBits.Length; - } + public static BitSet of(int el) + { + BitSet s = new BitSet(el + 1); + s.add(el); + return s; + } - /*Is this contained within a? */ - public virtual bool subset(BitSet a) - { - if (a == null) //(a == null || !(a is BitSet)) - return false; - return this.and(a).Equals(this); - } + /*return this | a in a new set */ + public virtual BitSet or(BitSet a) + { + BitSet s = (BitSet) this.Clone(); + s.orInPlace(a); + return s; + } - /*Subtract the elements of 'a' from 'this' in-place. - * Basically, just turn off all bits of 'this' that are in 'a'. - */ - public virtual void subtractInPlace(BitSet a) - { - if (a == null) - return ; - // for all words of 'a', turn off corresponding bits of 'this' - for (int i = 0; i < dataBits.Length && i < a.dataBits.Length; i++) - { - dataBits[i] &= ~ a.dataBits[i]; - } - } + public virtual void orInPlace(BitSet a) + { + // If this is smaller than a, grow this first + if (a.dataBits.Length > dataBits.Length) + { + setSize((int) (a.dataBits.Length)); + } - public virtual int[] toArray() - { - int[] elems = new int[degree()]; - int en = 0; - for (int i = 0; i < (dataBits.Length << LOG_BITS); i++) - { - if (member(i)) - { - elems[en++] = i; - } - } - return elems; - } + int min = (int) (System.Math.Min(dataBits.Length, a.dataBits.Length)); + for (int i = min - 1; i >= 0; i--) + { + dataBits[i] |= a.dataBits[i]; + } + } - public virtual long[] toPackedArray() - { - return dataBits; - } + // remove this element from this set + public virtual void remove(int el) + { + int n = wordNumber(el); + if (n >= dataBits.Length) + { + growToInclude(el); + } - override public string ToString() - { - return ToString(","); - } + dataBits[n] &= ~ bitMask(el); + } - /*Transform a bit set into a string by formatting each element as an integer - * @separator The string to put in between elements - * @return A commma-separated list of values - */ - public virtual string ToString(string separator) - { - string str = ""; - for (int i = 0; i < (dataBits.Length << LOG_BITS); i++) - { - if (member(i)) - { - if (str.Length > 0) - { - str += separator; - } - str = str + i; - } - } - return str; - } + /* + * Sets the size of a set. + * @param nwords how many words the new set should be + */ + private void setSize(int nwords) + { + long[] newbits = new long[nwords]; + int n = (int) (System.Math.Min(nwords, dataBits.Length)); + Array.Copy(dataBits, 0, newbits, 0, n); + dataBits = newbits; + } - /*Create a string representation where instead of integer elements, the - * ith element of vocabulary is displayed instead. Vocabulary is a Vector - * of Strings. - * @separator The string to put in between elements - * @return A commma-separated list of character constants. - */ - public virtual string ToString(string separator, ArrayList vocabulary) - { - if (vocabulary == null) - { - return ToString(separator); - } - string str = ""; - for (int i = 0; i < (dataBits.Length << LOG_BITS); i++) - { - if (member(i)) - { - if (str.Length > 0) - { - str += separator; - } - if (i >= vocabulary.Count) - { - str += ""; - } - else if (vocabulary[i] == null) - { - str += "<" + i + ">"; - } - else - { - str += (string) vocabulary[i]; - } - } - } - return str; - } + public virtual int size() + { + return dataBits.Length << LOG_BITS; // num words * bits per word + } - /* - * Dump a comma-separated list of the words making up the bit set. - * Split each 64 bit number into two more manageable 32 bit numbers. - * This generates a comma-separated list of C++-like unsigned long constants. - */ - public virtual string toStringOfHalfWords() - { - string s = new string("".ToCharArray()); - for (int i = 0; i < dataBits.Length; i++) - { - if (i != 0) - s += ", "; - long tmp = dataBits[i]; - tmp &= 0xFFFFFFFFL; - s += (tmp + "UL"); - s += ", "; - tmp = SupportClass.URShift(dataBits[i], 32); - tmp &= 0xFFFFFFFFL; - s += (tmp + "UL"); - } - return s; - } + /*return how much space is being used by the dataBits array not + * how many actually have member bits on. + */ + public virtual int lengthInLongWords() + { + return dataBits.Length; + } - /* - * Dump a comma-separated list of the words making up the bit set. - * This generates a comma-separated list of Java-like long int constants. - */ - public virtual string toStringOfWords() - { - string s = new string("".ToCharArray()); - for (int i = 0; i < dataBits.Length; i++) - { - if (i != 0) - s += ", "; - s += (dataBits[i] + "L"); - } - return s; - } + /*Is this contained within a? */ + public virtual bool subset(BitSet a) + { + if (a == null) //(a == null || !(a is BitSet)) + return false; + return this.and(a).Equals(this); + } - /*Print out the bit set but collapse char ranges. */ + /*Subtract the elements of 'a' from 'this' in-place. + * Basically, just turn off all bits of 'this' that are in 'a'. + */ + public virtual void subtractInPlace(BitSet a) + { + if (a == null) + return; + // for all words of 'a', turn off corresponding bits of 'this' + for (int i = 0; i < dataBits.Length && i < a.dataBits.Length; i++) + { + dataBits[i] &= ~ a.dataBits[i]; + } + } + + public virtual int[] toArray() + { + int[] elems = new int[degree()]; + int en = 0; + for (int i = 0; i < (dataBits.Length << LOG_BITS); i++) + { + if (member(i)) + { + elems[en++] = i; + } + } + + return elems; + } + + public virtual long[] toPackedArray() + { + return dataBits; + } + + override public string ToString() + { + return ToString(","); + } + + /*Transform a bit set into a string by formatting each element as an integer + * @separator The string to put in between elements + * @return A commma-separated list of values + */ + public virtual string ToString(string separator) + { + string str = ""; + for (int i = 0; i < (dataBits.Length << LOG_BITS); i++) + { + if (member(i)) + { + if (str.Length > 0) + { + str += separator; + } + + str = str + i; + } + } + + return str; + } + + /*Create a string representation where instead of integer elements, the + * ith element of vocabulary is displayed instead. Vocabulary is a Vector + * of Strings. + * @separator The string to put in between elements + * @return A commma-separated list of character constants. + */ + public virtual string ToString(string separator, ArrayList vocabulary) + { + if (vocabulary == null) + { + return ToString(separator); + } + + string str = ""; + for (int i = 0; i < (dataBits.Length << LOG_BITS); i++) + { + if (member(i)) + { + if (str.Length > 0) + { + str += separator; + } + + if (i >= vocabulary.Count) + { + str += ""; + } + else if (vocabulary[i] == null) + { + str += "<" + i + ">"; + } + else + { + str += (string) vocabulary[i]; + } + } + } + + return str; + } + + /* + * Dump a comma-separated list of the words making up the bit set. + * Split each 64 bit number into two more manageable 32 bit numbers. + * This generates a comma-separated list of C++-like unsigned long constants. + */ + public virtual string toStringOfHalfWords() + { + string s = new string("".ToCharArray()); + for (int i = 0; i < dataBits.Length; i++) + { + if (i != 0) + s += ", "; + long tmp = dataBits[i]; + tmp &= 0xFFFFFFFFL; + s += (tmp + "UL"); + s += ", "; + tmp = SupportClass.URShift(dataBits[i], 32); + tmp &= 0xFFFFFFFFL; + s += (tmp + "UL"); + } + + return s; + } + + /* + * Dump a comma-separated list of the words making up the bit set. + * This generates a comma-separated list of Java-like long int constants. + */ + public virtual string toStringOfWords() + { + string s = new string("".ToCharArray()); + for (int i = 0; i < dataBits.Length; i++) + { + if (i != 0) + s += ", "; + s += (dataBits[i] + "L"); + } + + return s; + } + + /*Print out the bit set but collapse char ranges. */ /* public virtual string toStringWithRanges(string separator, CharFormatter formatter) - { - string str = ""; - int[] elems = this.toArray(); - if (elems.Length == 0) - { - return ""; - } - // look for ranges - int i = 0; - while (i < elems.Length) - { - int lastInRange; - lastInRange = 0; - for (int j = i + 1; j < elems.Length; j++) - { - if (elems[j] != elems[j - 1] + 1) - { - break; - } - lastInRange = j; - } - // found a range - if (str.Length > 0) - { - str += separator; - } - if (lastInRange - i >= 2) - { - str += formatter.literalChar(elems[i]); - str += ".."; - str += formatter.literalChar(elems[lastInRange]); - i = lastInRange; // skip past end of range for next range - } - else - { - // no range, just print current char and move on - str += formatter.literalChar(elems[i]); - } - i++; - } - return str; - } + { + string str = ""; + int[] elems = this.toArray(); + if (elems.Length == 0) + { + return ""; + } + // look for ranges + int i = 0; + while (i < elems.Length) + { + int lastInRange; + lastInRange = 0; + for (int j = i + 1; j < elems.Length; j++) + { + if (elems[j] != elems[j - 1] + 1) + { + break; + } + lastInRange = j; + } + // found a range + if (str.Length > 0) + { + str += separator; + } + if (lastInRange - i >= 2) + { + str += formatter.literalChar(elems[i]); + str += ".."; + str += formatter.literalChar(elems[lastInRange]); + i = lastInRange; // skip past end of range for next range + } + else + { + // no range, just print current char and move on + str += formatter.literalChar(elems[i]); + } + i++; + } + return str; + } */ - private static int wordNumber(int bit) - { - return bit >> LOG_BITS; // bit / BITS - } - } -} + private static int wordNumber(int bit) + { + return bit >> LOG_BITS; // bit / BITS + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/ANTLREventArgs.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/ANTLREventArgs.cs index 50128545..1f322e69 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/ANTLREventArgs.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/ANTLREventArgs.cs @@ -1,37 +1,37 @@ -namespace Spring.Expressions.Parser.antlr.debug +namespace Spring.Expressions.Parser.antlr.debug; + +using System; + +public abstract class ANTLREventArgs : EventArgs { - using System; - - public abstract class ANTLREventArgs : EventArgs - { - public ANTLREventArgs() - { - } - public ANTLREventArgs(int type) - { - this.Type = type; - } - - public virtual int Type - { - get - { - return this.type_; - } - set - { - this.type_ = value; - } - } + public ANTLREventArgs() + { + } - internal void setValues(int type) - { - this.Type = type; - } + public ANTLREventArgs(int type) + { + this.Type = type; + } - /// - /// Event type. - /// - private int type_; - } -} \ No newline at end of file + public virtual int Type + { + get + { + return this.type_; + } + set + { + this.type_ = value; + } + } + + internal void setValues(int type) + { + this.Type = type; + } + + /// + /// Event type. + /// + private int type_; +} diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/DebuggingCharScanner.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/DebuggingCharScanner.cs index 66666645..7595a081 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/DebuggingCharScanner.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/DebuggingCharScanner.cs @@ -1,322 +1,358 @@ -namespace Spring.Expressions.Parser.antlr.debug +namespace Spring.Expressions.Parser.antlr.debug; + +using System; +using System.Threading; +using antlr; +using BitSet = antlr.collections.impl.BitSet; + +public abstract class DebuggingCharScanner : CharScanner, DebuggingParser { - using System; - using System.Threading; - using antlr; + private void InitBlock() + { + eventSupport = new ScannerEventSupport(this); + } - using BitSet = antlr.collections.impl.BitSet; - - public abstract class DebuggingCharScanner : CharScanner, DebuggingParser - { - private void InitBlock() - { - eventSupport = new ScannerEventSupport(this); - } - public virtual void setDebugMode(bool mode) - { - _notDebugMode = !mode; - } + public virtual void setDebugMode(bool mode) + { + _notDebugMode = !mode; + } - private ScannerEventSupport eventSupport; - private bool _notDebugMode = false; - protected internal string[] ruleNames; - protected internal string[] semPredNames; - - - public DebuggingCharScanner(InputBuffer cb) : base(cb) - { - InitBlock(); - } - public DebuggingCharScanner(LexerSharedInputState state) : base(state) - { - InitBlock(); - } - public virtual void addMessageListener(MessageListener l) - { - eventSupport.addMessageListener(l); - } - public virtual void addNewLineListener(NewLineListener l) - { - eventSupport.addNewLineListener(l); - } - public virtual void addParserListener(ParserListener l) - { - eventSupport.addParserListener(l); - } - public virtual void addParserMatchListener(ParserMatchListener l) - { - eventSupport.addParserMatchListener(l); - } - public virtual void addParserTokenListener(ParserTokenListener l) - { - eventSupport.addParserTokenListener(l); - } - public virtual void addSemanticPredicateListener(SemanticPredicateListener l) - { - eventSupport.addSemanticPredicateListener(l); - } - public virtual void addSyntacticPredicateListener(SyntacticPredicateListener l) - { - eventSupport.addSyntacticPredicateListener(l); - } - public virtual void addTraceListener(TraceListener l) - { - eventSupport.addTraceListener(l); - } - public override void consume() - { - int la_1 = - 99; - try - { - la_1 = LA(1); - } - catch (CharStreamException) - { - } - base.consume(); - eventSupport.fireConsume(la_1); - } - protected internal virtual void fireEnterRule(int num, int data) - { - if (isDebugMode()) - eventSupport.fireEnterRule(num, inputState.guessing, data); - } - protected internal virtual void fireExitRule(int num, int ttype) - { - if (isDebugMode()) - eventSupport.fireExitRule(num, inputState.guessing, ttype); - } - protected internal virtual bool fireSemanticPredicateEvaluated(int type, int num, bool condition) - { - if (isDebugMode()) - return eventSupport.fireSemanticPredicateEvaluated(type, num, condition, inputState.guessing); - else - return condition; - } - protected internal virtual void fireSyntacticPredicateFailed() - { - if (isDebugMode()) - eventSupport.fireSyntacticPredicateFailed(inputState.guessing); - } - protected internal virtual void fireSyntacticPredicateStarted() - { - if (isDebugMode()) - eventSupport.fireSyntacticPredicateStarted(inputState.guessing); - } - protected internal virtual void fireSyntacticPredicateSucceeded() - { - if (isDebugMode()) - eventSupport.fireSyntacticPredicateSucceeded(inputState.guessing); - } - public virtual string getRuleName(int num) - { - return ruleNames[num]; - } - public virtual string getSemPredName(int num) - { - return semPredNames[num]; - } - public virtual void goToSleep() - { - lock(this) - { - try - { - Monitor.Wait(this); - } - catch (System.Threading.ThreadInterruptedException) - { - } - } - } - public virtual bool isDebugMode() - { - return !_notDebugMode; - } - public override char LA(int i) - { - char la = base.LA(i); - eventSupport.fireLA(i, la); - return la; - } - protected internal override IToken makeToken(int t) - { - // do something with char buffer??? - // try { - // IToken tok = (Token)tokenObjectClass.newInstance(); - // tok.setType(t); - // // tok.setText(getText()); done in generated lexer now - // tok.setLine(line); - // return tok; - // } - // catch (InstantiationException ie) { - // panic("can't instantiate a Token"); - // } - // catch (IllegalAccessException iae) { - // panic("Token class is not accessible"); - // } - return base.makeToken(t); - } - public override void match(int c) - { - char la_1 = LA(1); - try - { - base.match(c); - eventSupport.fireMatch(Convert.ToChar(c), inputState.guessing); - } - catch (MismatchedCharException e) - { - if (inputState.guessing == 0) - eventSupport.fireMismatch(la_1, Convert.ToChar(c), inputState.guessing); - throw e; - } - } - public override void match(BitSet b) - { - string text = this.text.ToString(); - char la_1 = LA(1); - try - { - base.match(b); - eventSupport.fireMatch(la_1, b, text, inputState.guessing); - } - catch (MismatchedCharException e) - { - if (inputState.guessing == 0) - eventSupport.fireMismatch(la_1, b, text, inputState.guessing); - throw e; - } - } - public override void match(string s) - { - System.Text.StringBuilder la_s = new System.Text.StringBuilder(""); - int len = s.Length; - // peek at the next len worth of characters - try - { - for (int i = 1; i <= len; i++) - { - la_s.Append(base.LA(i)); - } - } - catch (System.Exception) - { - } - - try - { - base.match(s); - eventSupport.fireMatch(s, inputState.guessing); - } - catch (MismatchedCharException e) - { - if (inputState.guessing == 0) - eventSupport.fireMismatch(la_s.ToString(), s, inputState.guessing); - throw e; - } - - } - public override void matchNot(int c) - { - char la_1 = LA(1); - try - { - base.matchNot(c); - eventSupport.fireMatchNot(la_1, Convert.ToChar(c), inputState.guessing); - } - catch (MismatchedCharException e) - { - if (inputState.guessing == 0) - eventSupport.fireMismatchNot(la_1, Convert.ToChar(c), inputState.guessing); - throw e; - } - - } - public override void matchRange(int c1, int c2) - { - char la_1 = LA(1); - try - { - base.matchRange(c1, c2); - eventSupport.fireMatch(la_1, "" + c1 + c2, inputState.guessing); - } - catch (MismatchedCharException e) - { - if (inputState.guessing == 0) - eventSupport.fireMismatch(la_1, "" + c1 + c2, inputState.guessing); - throw e; - } - - } - public override void newline() - { - base.newline(); - eventSupport.fireNewLine(getLine()); - } - public virtual void removeMessageListener(MessageListener l) - { - eventSupport.removeMessageListener(l); - } - public virtual void removeNewLineListener(NewLineListener l) - { - eventSupport.removeNewLineListener(l); - } - public virtual void removeParserListener(ParserListener l) - { - eventSupport.removeParserListener(l); - } - public virtual void removeParserMatchListener(ParserMatchListener l) - { - eventSupport.removeParserMatchListener(l); - } - public virtual void removeParserTokenListener(ParserTokenListener l) - { - eventSupport.removeParserTokenListener(l); - } - public virtual void removeSemanticPredicateListener(SemanticPredicateListener l) - { - eventSupport.removeSemanticPredicateListener(l); - } - public virtual void removeSyntacticPredicateListener(SyntacticPredicateListener l) - { - eventSupport.removeSyntacticPredicateListener(l); - } - public virtual void removeTraceListener(TraceListener l) - { - eventSupport.removeTraceListener(l); - } - /// Report exception errors caught in nextToken() - /// - public virtual void reportError(MismatchedCharException e) - { - eventSupport.fireReportError(e); - base.reportError(e); - } - /// Parser error-reporting function can be overridden in subclass - /// - public override void reportError(string s) - { - eventSupport.fireReportError(s); - base.reportError(s); - } - /// Parser warning-reporting function can be overridden in subclass - /// - public override void reportWarning(string s) - { - eventSupport.fireReportWarning(s); - base.reportWarning(s); - } - public virtual void setupDebugging() - { - } + private ScannerEventSupport eventSupport; + private bool _notDebugMode = false; + protected internal string[] ruleNames; + protected internal string[] semPredNames; - public virtual void wakeUp() - { - lock(this) - { - Monitor.Pulse(this); - } - } - } -} \ No newline at end of file + public DebuggingCharScanner(InputBuffer cb) : base(cb) + { + InitBlock(); + } + + public DebuggingCharScanner(LexerSharedInputState state) : base(state) + { + InitBlock(); + } + + public virtual void addMessageListener(MessageListener l) + { + eventSupport.addMessageListener(l); + } + + public virtual void addNewLineListener(NewLineListener l) + { + eventSupport.addNewLineListener(l); + } + + public virtual void addParserListener(ParserListener l) + { + eventSupport.addParserListener(l); + } + + public virtual void addParserMatchListener(ParserMatchListener l) + { + eventSupport.addParserMatchListener(l); + } + + public virtual void addParserTokenListener(ParserTokenListener l) + { + eventSupport.addParserTokenListener(l); + } + + public virtual void addSemanticPredicateListener(SemanticPredicateListener l) + { + eventSupport.addSemanticPredicateListener(l); + } + + public virtual void addSyntacticPredicateListener(SyntacticPredicateListener l) + { + eventSupport.addSyntacticPredicateListener(l); + } + + public virtual void addTraceListener(TraceListener l) + { + eventSupport.addTraceListener(l); + } + + public override void consume() + { + int la_1 = -99; + try + { + la_1 = LA(1); + } + catch (CharStreamException) + { + } + + base.consume(); + eventSupport.fireConsume(la_1); + } + + protected internal virtual void fireEnterRule(int num, int data) + { + if (isDebugMode()) + eventSupport.fireEnterRule(num, inputState.guessing, data); + } + + protected internal virtual void fireExitRule(int num, int ttype) + { + if (isDebugMode()) + eventSupport.fireExitRule(num, inputState.guessing, ttype); + } + + protected internal virtual bool fireSemanticPredicateEvaluated(int type, int num, bool condition) + { + if (isDebugMode()) + return eventSupport.fireSemanticPredicateEvaluated(type, num, condition, inputState.guessing); + else + return condition; + } + + protected internal virtual void fireSyntacticPredicateFailed() + { + if (isDebugMode()) + eventSupport.fireSyntacticPredicateFailed(inputState.guessing); + } + + protected internal virtual void fireSyntacticPredicateStarted() + { + if (isDebugMode()) + eventSupport.fireSyntacticPredicateStarted(inputState.guessing); + } + + protected internal virtual void fireSyntacticPredicateSucceeded() + { + if (isDebugMode()) + eventSupport.fireSyntacticPredicateSucceeded(inputState.guessing); + } + + public virtual string getRuleName(int num) + { + return ruleNames[num]; + } + + public virtual string getSemPredName(int num) + { + return semPredNames[num]; + } + + public virtual void goToSleep() + { + lock (this) + { + try + { + Monitor.Wait(this); + } + catch (System.Threading.ThreadInterruptedException) + { + } + } + } + + public virtual bool isDebugMode() + { + return !_notDebugMode; + } + + public override char LA(int i) + { + char la = base.LA(i); + eventSupport.fireLA(i, la); + return la; + } + + protected internal override IToken makeToken(int t) + { + // do something with char buffer??? + // try { + // IToken tok = (Token)tokenObjectClass.newInstance(); + // tok.setType(t); + // // tok.setText(getText()); done in generated lexer now + // tok.setLine(line); + // return tok; + // } + // catch (InstantiationException ie) { + // panic("can't instantiate a Token"); + // } + // catch (IllegalAccessException iae) { + // panic("Token class is not accessible"); + // } + return base.makeToken(t); + } + + public override void match(int c) + { + char la_1 = LA(1); + try + { + base.match(c); + eventSupport.fireMatch(Convert.ToChar(c), inputState.guessing); + } + catch (MismatchedCharException e) + { + if (inputState.guessing == 0) + eventSupport.fireMismatch(la_1, Convert.ToChar(c), inputState.guessing); + throw e; + } + } + + public override void match(BitSet b) + { + string text = this.text.ToString(); + char la_1 = LA(1); + try + { + base.match(b); + eventSupport.fireMatch(la_1, b, text, inputState.guessing); + } + catch (MismatchedCharException e) + { + if (inputState.guessing == 0) + eventSupport.fireMismatch(la_1, b, text, inputState.guessing); + throw e; + } + } + + public override void match(string s) + { + System.Text.StringBuilder la_s = new System.Text.StringBuilder(""); + int len = s.Length; + // peek at the next len worth of characters + try + { + for (int i = 1; i <= len; i++) + { + la_s.Append(base.LA(i)); + } + } + catch (System.Exception) + { + } + + try + { + base.match(s); + eventSupport.fireMatch(s, inputState.guessing); + } + catch (MismatchedCharException e) + { + if (inputState.guessing == 0) + eventSupport.fireMismatch(la_s.ToString(), s, inputState.guessing); + throw e; + } + } + + public override void matchNot(int c) + { + char la_1 = LA(1); + try + { + base.matchNot(c); + eventSupport.fireMatchNot(la_1, Convert.ToChar(c), inputState.guessing); + } + catch (MismatchedCharException e) + { + if (inputState.guessing == 0) + eventSupport.fireMismatchNot(la_1, Convert.ToChar(c), inputState.guessing); + throw e; + } + } + + public override void matchRange(int c1, int c2) + { + char la_1 = LA(1); + try + { + base.matchRange(c1, c2); + eventSupport.fireMatch(la_1, "" + c1 + c2, inputState.guessing); + } + catch (MismatchedCharException e) + { + if (inputState.guessing == 0) + eventSupport.fireMismatch(la_1, "" + c1 + c2, inputState.guessing); + throw e; + } + } + + public override void newline() + { + base.newline(); + eventSupport.fireNewLine(getLine()); + } + + public virtual void removeMessageListener(MessageListener l) + { + eventSupport.removeMessageListener(l); + } + + public virtual void removeNewLineListener(NewLineListener l) + { + eventSupport.removeNewLineListener(l); + } + + public virtual void removeParserListener(ParserListener l) + { + eventSupport.removeParserListener(l); + } + + public virtual void removeParserMatchListener(ParserMatchListener l) + { + eventSupport.removeParserMatchListener(l); + } + + public virtual void removeParserTokenListener(ParserTokenListener l) + { + eventSupport.removeParserTokenListener(l); + } + + public virtual void removeSemanticPredicateListener(SemanticPredicateListener l) + { + eventSupport.removeSemanticPredicateListener(l); + } + + public virtual void removeSyntacticPredicateListener(SyntacticPredicateListener l) + { + eventSupport.removeSyntacticPredicateListener(l); + } + + public virtual void removeTraceListener(TraceListener l) + { + eventSupport.removeTraceListener(l); + } + + /// Report exception errors caught in nextToken() + /// + public virtual void reportError(MismatchedCharException e) + { + eventSupport.fireReportError(e); + base.reportError(e); + } + + /// Parser error-reporting function can be overridden in subclass + /// + public override void reportError(string s) + { + eventSupport.fireReportError(s); + base.reportError(s); + } + + /// Parser warning-reporting function can be overridden in subclass + /// + public override void reportWarning(string s) + { + eventSupport.fireReportWarning(s); + base.reportWarning(s); + } + + public virtual void setupDebugging() + { + } + + public virtual void wakeUp() + { + lock (this) + { + Monitor.Pulse(this); + } + } +} diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/DebuggingInputBuffer.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/DebuggingInputBuffer.cs index 39b1babc..ccef8268 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/DebuggingInputBuffer.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/DebuggingInputBuffer.cs @@ -1,81 +1,90 @@ -namespace Spring.Expressions.Parser.antlr.debug -{ - using ArrayList = System.Collections.ArrayList; - - public class DebuggingInputBuffer : InputBuffer - { - public virtual ArrayList InputBufferListeners - { - get { return inputBufferEventSupport.InputBufferListeners; } - } - public virtual bool DebugMode - { - set { debugMode = value; } - } +namespace Spring.Expressions.Parser.antlr.debug; - private InputBuffer buffer; - private InputBufferEventSupport inputBufferEventSupport; - private bool debugMode = true; - - - public DebuggingInputBuffer(InputBuffer buffer) - { - this.buffer = buffer; - inputBufferEventSupport = new InputBufferEventSupport(this); - } - public virtual void addInputBufferListener(InputBufferListener l) - { - inputBufferEventSupport.addInputBufferListener(l); - } - public override char consume() - { - char la = ' '; - try - { - la = buffer.LA(1); - } - catch (CharStreamException) - { - } // vaporize it... - buffer.consume(); - if (debugMode) - inputBufferEventSupport.fireConsume(la); - return la; - } - public override void fill(int a) - { - buffer.fill(a); - } - public virtual bool isDebugMode() - { - return debugMode; - } - public override bool isMarked() - { - return buffer.isMarked(); - } - public override char LA(int i) - { - char la = buffer.LA(i); - if (debugMode) - inputBufferEventSupport.fireLA(la, i); - return la; - } - public override int mark() - { - int m = buffer.mark(); - inputBufferEventSupport.fireMark(m); - return m; - } - public virtual void removeInputBufferListener(InputBufferListener l) - { - if (inputBufferEventSupport != null) - inputBufferEventSupport.removeInputBufferListener(l); - } - public override void rewind(int mark) - { - buffer.rewind(mark); - inputBufferEventSupport.fireRewind(mark); - } - } -} \ No newline at end of file +using ArrayList = System.Collections.ArrayList; + +public class DebuggingInputBuffer : InputBuffer +{ + public virtual ArrayList InputBufferListeners + { + get { return inputBufferEventSupport.InputBufferListeners; } + } + + public virtual bool DebugMode + { + set { debugMode = value; } + } + + private InputBuffer buffer; + private InputBufferEventSupport inputBufferEventSupport; + private bool debugMode = true; + + public DebuggingInputBuffer(InputBuffer buffer) + { + this.buffer = buffer; + inputBufferEventSupport = new InputBufferEventSupport(this); + } + + public virtual void addInputBufferListener(InputBufferListener l) + { + inputBufferEventSupport.addInputBufferListener(l); + } + + public override char consume() + { + char la = ' '; + try + { + la = buffer.LA(1); + } + catch (CharStreamException) + { + } // vaporize it... + + buffer.consume(); + if (debugMode) + inputBufferEventSupport.fireConsume(la); + return la; + } + + public override void fill(int a) + { + buffer.fill(a); + } + + public virtual bool isDebugMode() + { + return debugMode; + } + + public override bool isMarked() + { + return buffer.isMarked(); + } + + public override char LA(int i) + { + char la = buffer.LA(i); + if (debugMode) + inputBufferEventSupport.fireLA(la, i); + return la; + } + + public override int mark() + { + int m = buffer.mark(); + inputBufferEventSupport.fireMark(m); + return m; + } + + public virtual void removeInputBufferListener(InputBufferListener l) + { + if (inputBufferEventSupport != null) + inputBufferEventSupport.removeInputBufferListener(l); + } + + public override void rewind(int mark) + { + buffer.rewind(mark); + inputBufferEventSupport.fireRewind(mark); + } +} diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/DebuggingParser.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/DebuggingParser.cs index f14ee0d2..57aeb456 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/DebuggingParser.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/DebuggingParser.cs @@ -1,10 +1,9 @@ -namespace Spring.Expressions.Parser.antlr.debug +namespace Spring.Expressions.Parser.antlr.debug; + +/// This type was created in VisualAge. +/// +public interface DebuggingParser { - /// This type was created in VisualAge. - /// - public interface DebuggingParser - { - string getRuleName(int n); - string getSemPredName(int n); - } -} \ No newline at end of file + string getRuleName(int n); + string getSemPredName(int n); +} diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/GuessingEventArgs.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/GuessingEventArgs.cs index 90b33113..5c661412 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/GuessingEventArgs.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/GuessingEventArgs.cs @@ -1,29 +1,28 @@ -namespace Spring.Expressions.Parser.antlr.debug +namespace Spring.Expressions.Parser.antlr.debug; + +public abstract class GuessingEventArgs : ANTLREventArgs { - public abstract class GuessingEventArgs : ANTLREventArgs - { - public GuessingEventArgs() - { - } - public GuessingEventArgs(int type) : base(type) - { - } + public GuessingEventArgs() + { + } - public virtual int Guessing - { - get { return guessing_; } - set { this.guessing_ = value; } - } + public GuessingEventArgs(int type) : base(type) + { + } - private int guessing_; - - - /// This should NOT be called from anyone other than ParserEventSupport! - /// - public virtual void setValues(int type, int guessing) - { - setValues(type); - this.Guessing = guessing; - } - } -} \ No newline at end of file + public virtual int Guessing + { + get { return guessing_; } + set { this.guessing_ = value; } + } + + private int guessing_; + + /// This should NOT be called from anyone other than ParserEventSupport! + /// + public virtual void setValues(int type, int guessing) + { + setValues(type); + this.Guessing = guessing; + } +} diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/ICharScannerDebugSubject.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/ICharScannerDebugSubject.cs index c57887fd..69dc95bd 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/ICharScannerDebugSubject.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/ICharScannerDebugSubject.cs @@ -1,13 +1,12 @@ -namespace Spring.Expressions.Parser.antlr.debug +namespace Spring.Expressions.Parser.antlr.debug; + +public interface ICharScannerDebugSubject : IDebugSubject { - public interface ICharScannerDebugSubject : IDebugSubject - { - event NewLineEventHandler HitNewLine; - event MatchEventHandler MatchedChar; - event MatchEventHandler MatchedNotChar; - event MatchEventHandler MisMatchedChar; - event MatchEventHandler MisMatchedNotChar; - event TokenEventHandler ConsumedChar; - event TokenEventHandler CharLA; - } + event NewLineEventHandler HitNewLine; + event MatchEventHandler MatchedChar; + event MatchEventHandler MatchedNotChar; + event MatchEventHandler MisMatchedChar; + event MatchEventHandler MisMatchedNotChar; + event TokenEventHandler ConsumedChar; + event TokenEventHandler CharLA; } diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/IDebugSubject.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/IDebugSubject.cs index 5435314c..ee4f9986 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/IDebugSubject.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/IDebugSubject.cs @@ -1,22 +1,20 @@ -namespace Spring.Expressions.Parser.antlr.debug +namespace Spring.Expressions.Parser.antlr.debug; +//using EventHandlerList = System.ComponentModel.EventHandlerList; + +public interface IDebugSubject { - //using EventHandlerList = System.ComponentModel.EventHandlerList; - - public interface IDebugSubject - { - /* EventHandlerList Events - { - get; - } + /* EventHandlerList Events + { + get; + } */ - event TraceEventHandler EnterRule; - event TraceEventHandler ExitRule; - event TraceEventHandler Done; - event MessageEventHandler ErrorReported; - event MessageEventHandler WarningReported; - event SemanticPredicateEventHandler SemPredEvaluated; - event SyntacticPredicateEventHandler SynPredStarted; - event SyntacticPredicateEventHandler SynPredFailed; - event SyntacticPredicateEventHandler SynPredSucceeded; - } + event TraceEventHandler EnterRule; + event TraceEventHandler ExitRule; + event TraceEventHandler Done; + event MessageEventHandler ErrorReported; + event MessageEventHandler WarningReported; + event SemanticPredicateEventHandler SemPredEvaluated; + event SyntacticPredicateEventHandler SynPredStarted; + event SyntacticPredicateEventHandler SynPredFailed; + event SyntacticPredicateEventHandler SynPredSucceeded; } diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/IParserDebugSubject.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/IParserDebugSubject.cs index e8b35ba0..5ccd49b2 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/IParserDebugSubject.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/IParserDebugSubject.cs @@ -1,12 +1,11 @@ -namespace Spring.Expressions.Parser.antlr.debug +namespace Spring.Expressions.Parser.antlr.debug; + +public interface IParserDebugSubject : IDebugSubject { - public interface IParserDebugSubject : IDebugSubject - { - event MatchEventHandler MatchedToken; - event MatchEventHandler MatchedNotToken; - event MatchEventHandler MisMatchedToken; - event MatchEventHandler MisMatchedNotToken; - event TokenEventHandler ConsumedToken; - event TokenEventHandler TokenLA; - } + event MatchEventHandler MatchedToken; + event MatchEventHandler MatchedNotToken; + event MatchEventHandler MisMatchedToken; + event MatchEventHandler MisMatchedNotToken; + event TokenEventHandler ConsumedToken; + event TokenEventHandler TokenLA; } diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/InputBufferEventArgs.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/InputBufferEventArgs.cs index 98a8c3b6..59d04c9c 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/InputBufferEventArgs.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/InputBufferEventArgs.cs @@ -1,48 +1,47 @@ -namespace Spring.Expressions.Parser.antlr.debug +namespace Spring.Expressions.Parser.antlr.debug; + +public class InputBufferEventArgs : ANTLREventArgs { - public class InputBufferEventArgs : ANTLREventArgs - { - public InputBufferEventArgs() - { - } + public InputBufferEventArgs() + { + } - public InputBufferEventArgs(int type, char c, int lookaheadAmount) - { - setValues(type, c, lookaheadAmount); - } - - public virtual char Char - { - get { return this.c_; } - set { this.c_ = value; } - } - public virtual int LookaheadAmount - { - get { return this.lookaheadAmount_; } - set { this.lookaheadAmount_ = value; } - } + public InputBufferEventArgs(int type, char c, int lookaheadAmount) + { + setValues(type, c, lookaheadAmount); + } - internal char c_; - internal int lookaheadAmount_; // amount of lookahead + public virtual char Char + { + get { return this.c_; } + set { this.c_ = value; } + } - public const int CONSUME = 0; - public const int LA = 1; - public const int MARK = 2; - public const int REWIND = 3; - - - /// This should NOT be called from anyone other than ParserEventSupport! - /// - internal void setValues(int type, char c, int la) - { - setValues(type); - this.Char = c; - this.LookaheadAmount = la; - } + public virtual int LookaheadAmount + { + get { return this.lookaheadAmount_; } + set { this.lookaheadAmount_ = value; } + } - public override string ToString() - { - return "CharBufferEvent [" + (Type == CONSUME?"CONSUME, ":"LA, ") + Char + "," + LookaheadAmount + "]"; - } - } -} \ No newline at end of file + internal char c_; + internal int lookaheadAmount_; // amount of lookahead + + public const int CONSUME = 0; + public const int LA = 1; + public const int MARK = 2; + public const int REWIND = 3; + + /// This should NOT be called from anyone other than ParserEventSupport! + /// + internal void setValues(int type, char c, int la) + { + setValues(type); + this.Char = c; + this.LookaheadAmount = la; + } + + public override string ToString() + { + return "CharBufferEvent [" + (Type == CONSUME ? "CONSUME, " : "LA, ") + Char + "," + LookaheadAmount + "]"; + } +} diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/InputBufferEventSupport.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/InputBufferEventSupport.cs index d0991389..a8470904 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/InputBufferEventSupport.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/InputBufferEventSupport.cs @@ -1,123 +1,131 @@ -namespace Spring.Expressions.Parser.antlr.debug -{ - using ArrayList = System.Collections.ArrayList; +namespace Spring.Expressions.Parser.antlr.debug; - public class InputBufferEventSupport - { - public virtual ArrayList InputBufferListeners - { - get - { - return inputBufferListeners; - } - - } - private object source; - private ArrayList inputBufferListeners; - private InputBufferEventArgs inputBufferEvent; - protected internal const int CONSUME = 0; - protected internal const int LA = 1; - protected internal const int MARK = 2; - protected internal const int REWIND = 3; - - - public InputBufferEventSupport(object source) - { - inputBufferEvent = new InputBufferEventArgs(); - this.source = source; - } - public virtual void addInputBufferListener(InputBufferListener l) - { - if (inputBufferListeners == null) - inputBufferListeners = new ArrayList(); - inputBufferListeners.Add(l); - } - public virtual void fireConsume(char c) - { - inputBufferEvent.setValues(InputBufferEventArgs.CONSUME, c, 0); - fireEvents(CONSUME, inputBufferListeners); - } - public virtual void fireEvent(int type, Listener l) - { - switch (type) - { - case CONSUME: - ((InputBufferListener) l).inputBufferConsume(source, inputBufferEvent); break; - - case LA: - ((InputBufferListener) l).inputBufferLA(source, inputBufferEvent); break; - - case MARK: - ((InputBufferListener) l).inputBufferMark(source, inputBufferEvent); break; - - case REWIND: - ((InputBufferListener) l).inputBufferRewind(source, inputBufferEvent); break; - - default: - throw new System.ArgumentException("bad type " + type + " for fireEvent()"); - - } - } - public virtual void fireEvents(int type, ArrayList listeners) - { - ArrayList targets = null; - Listener l = null; - - lock(this) - { - if (listeners == null) - return ; - targets = (ArrayList) listeners.Clone(); - } - - if (targets != null) - for (int i = 0; i < targets.Count; i++) - { - l = (Listener) targets[i]; - fireEvent(type, l); - } - } - public virtual void fireLA(char c, int la) - { - inputBufferEvent.setValues(InputBufferEventArgs.LA, c, la); - fireEvents(LA, inputBufferListeners); - } - public virtual void fireMark(int pos) - { - inputBufferEvent.setValues(InputBufferEventArgs.MARK, ' ', pos); - fireEvents(MARK, inputBufferListeners); - } - public virtual void fireRewind(int pos) - { - inputBufferEvent.setValues(InputBufferEventArgs.REWIND, ' ', pos); - fireEvents(REWIND, inputBufferListeners); - } - protected internal virtual void refresh(ArrayList listeners) - { - ArrayList v; - lock(listeners) - { - v = (ArrayList) listeners.Clone(); - } - if (v != null) - for (int i = 0; i < v.Count; i++) - ((Listener) v[i]).refresh(); - } - public virtual void refreshListeners() - { - refresh(inputBufferListeners); - } - public virtual void removeInputBufferListener(InputBufferListener l) - { - if (inputBufferListeners != null) - { - ArrayList temp_arraylist; - object temp_object; - temp_arraylist = inputBufferListeners; - temp_object = l; - temp_arraylist.Contains(temp_object); - temp_arraylist.Remove(temp_object); - } - } - } -} \ No newline at end of file +using ArrayList = System.Collections.ArrayList; + +public class InputBufferEventSupport +{ + public virtual ArrayList InputBufferListeners + { + get + { + return inputBufferListeners; + } + } + + private object source; + private ArrayList inputBufferListeners; + private InputBufferEventArgs inputBufferEvent; + protected internal const int CONSUME = 0; + protected internal const int LA = 1; + protected internal const int MARK = 2; + protected internal const int REWIND = 3; + + public InputBufferEventSupport(object source) + { + inputBufferEvent = new InputBufferEventArgs(); + this.source = source; + } + + public virtual void addInputBufferListener(InputBufferListener l) + { + if (inputBufferListeners == null) + inputBufferListeners = new ArrayList(); + inputBufferListeners.Add(l); + } + + public virtual void fireConsume(char c) + { + inputBufferEvent.setValues(InputBufferEventArgs.CONSUME, c, 0); + fireEvents(CONSUME, inputBufferListeners); + } + + public virtual void fireEvent(int type, Listener l) + { + switch (type) + { + case CONSUME: + ((InputBufferListener) l).inputBufferConsume(source, inputBufferEvent); break; + + case LA: + ((InputBufferListener) l).inputBufferLA(source, inputBufferEvent); break; + + case MARK: + ((InputBufferListener) l).inputBufferMark(source, inputBufferEvent); break; + + case REWIND: + ((InputBufferListener) l).inputBufferRewind(source, inputBufferEvent); break; + + default: + throw new System.ArgumentException("bad type " + type + " for fireEvent()"); + } + } + + public virtual void fireEvents(int type, ArrayList listeners) + { + ArrayList targets = null; + Listener l = null; + + lock (this) + { + if (listeners == null) + return; + targets = (ArrayList) listeners.Clone(); + } + + if (targets != null) + for (int i = 0; i < targets.Count; i++) + { + l = (Listener) targets[i]; + fireEvent(type, l); + } + } + + public virtual void fireLA(char c, int la) + { + inputBufferEvent.setValues(InputBufferEventArgs.LA, c, la); + fireEvents(LA, inputBufferListeners); + } + + public virtual void fireMark(int pos) + { + inputBufferEvent.setValues(InputBufferEventArgs.MARK, ' ', pos); + fireEvents(MARK, inputBufferListeners); + } + + public virtual void fireRewind(int pos) + { + inputBufferEvent.setValues(InputBufferEventArgs.REWIND, ' ', pos); + fireEvents(REWIND, inputBufferListeners); + } + + protected internal virtual void refresh(ArrayList listeners) + { + ArrayList v; + lock (listeners) + { + v = (ArrayList) listeners.Clone(); + } + + if (v != null) + for (int i = 0; i < v.Count; i++) + ((Listener) v[i]).refresh(); + } + + public virtual void refreshListeners() + { + refresh(inputBufferListeners); + } + + public virtual void removeInputBufferListener(InputBufferListener l) + { + if (inputBufferListeners != null) + { + ArrayList temp_arraylist; + object temp_object; + temp_arraylist = inputBufferListeners; + temp_object = l; + temp_arraylist.Contains(temp_object); + temp_arraylist.Remove(temp_object); + } + } +} diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/InputBufferListener.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/InputBufferListener.cs index a08d1791..6f7268f2 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/InputBufferListener.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/InputBufferListener.cs @@ -1,10 +1,9 @@ -namespace Spring.Expressions.Parser.antlr.debug +namespace Spring.Expressions.Parser.antlr.debug; + +public interface InputBufferListener : Listener { - public interface InputBufferListener : Listener - { - void inputBufferConsume (object source, InputBufferEventArgs e); - void inputBufferLA (object source, InputBufferEventArgs e); - void inputBufferMark (object source, InputBufferEventArgs e); - void inputBufferRewind (object source, InputBufferEventArgs e); - } -} \ No newline at end of file + void inputBufferConsume(object source, InputBufferEventArgs e); + void inputBufferLA(object source, InputBufferEventArgs e); + void inputBufferMark(object source, InputBufferEventArgs e); + void inputBufferRewind(object source, InputBufferEventArgs e); +} diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/InputBufferListenerBase.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/InputBufferListenerBase.cs index e63dc2f3..18c7079b 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/InputBufferListenerBase.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/InputBufferListenerBase.cs @@ -1,63 +1,62 @@ -namespace Spring.Expressions.Parser.antlr.debug +namespace Spring.Expressions.Parser.antlr.debug; + +/// +/// Provides an abstract base for implementing subclasses. +/// +/// +/// +/// This abstract class is provided to make it easier to create s. +/// You should extend this base class rather than creating your own. +/// +/// +public abstract class InputBufferListenerBase : InputBufferListener { /// - /// Provides an abstract base for implementing subclasses. - /// - /// - /// - /// This abstract class is provided to make it easier to create s. - /// You should extend this base class rather than creating your own. - /// - /// - public abstract class InputBufferListenerBase : InputBufferListener - { - /// - /// Handle the "Done" event. - /// - /// Event source object - /// Event data object - public virtual void doneParsing(object source, TraceEventArgs e) - { - } + /// Handle the "Done" event. + /// + /// Event source object + /// Event data object + public virtual void doneParsing(object source, TraceEventArgs e) + { + } - /// - /// Handle the "CharConsumed" event. - /// - /// Event source object - /// Event data object - public virtual void inputBufferConsume(object source, InputBufferEventArgs e) - { - } + /// + /// Handle the "CharConsumed" event. + /// + /// Event source object + /// Event data object + public virtual void inputBufferConsume(object source, InputBufferEventArgs e) + { + } - /// - /// Handle the "CharLA" event. - /// - /// Event source object - /// Event data object - public virtual void inputBufferLA(object source, InputBufferEventArgs e) - { - } + /// + /// Handle the "CharLA" event. + /// + /// Event source object + /// Event data object + public virtual void inputBufferLA(object source, InputBufferEventArgs e) + { + } - /// - /// Handle the "Mark" event. - /// - /// Event source object - /// Event data object - public virtual void inputBufferMark(object source, InputBufferEventArgs e) - { - } + /// + /// Handle the "Mark" event. + /// + /// Event source object + /// Event data object + public virtual void inputBufferMark(object source, InputBufferEventArgs e) + { + } - /// - /// Handle the "Rewind" event. - /// - /// Event source object - /// Event data object - public virtual void inputBufferRewind(object source, InputBufferEventArgs e) - { - } + /// + /// Handle the "Rewind" event. + /// + /// Event source object + /// Event data object + public virtual void inputBufferRewind(object source, InputBufferEventArgs e) + { + } - public virtual void refresh() - { - } - } -} \ No newline at end of file + public virtual void refresh() + { + } +} diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/InputBufferReporter.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/InputBufferReporter.cs index f2dc6d33..a3f66bd2 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/InputBufferReporter.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/InputBufferReporter.cs @@ -1,34 +1,33 @@ -namespace Spring.Expressions.Parser.antlr.debug +namespace Spring.Expressions.Parser.antlr.debug; + +public class InputBufferReporter : InputBufferListenerBase, InputBufferListener { - public class InputBufferReporter : InputBufferListenerBase, InputBufferListener - { - public virtual void inputBufferChanged(object source, InputBufferEventArgs e) - { - System.Console.Out.WriteLine(e); - } + public virtual void inputBufferChanged(object source, InputBufferEventArgs e) + { + System.Console.Out.WriteLine(e); + } - /// charBufferConsume method comment. - /// - public override void inputBufferConsume(object source, InputBufferEventArgs e) - { - System.Console.Out.WriteLine(e); - } + /// charBufferConsume method comment. + /// + public override void inputBufferConsume(object source, InputBufferEventArgs e) + { + System.Console.Out.WriteLine(e); + } - /// charBufferLA method comment. - /// - public override void inputBufferLA(object source, InputBufferEventArgs e) - { - System.Console.Out.WriteLine(e); - } + /// charBufferLA method comment. + /// + public override void inputBufferLA(object source, InputBufferEventArgs e) + { + System.Console.Out.WriteLine(e); + } - public override void inputBufferMark(object source, InputBufferEventArgs e) - { - System.Console.Out.WriteLine(e); - } + public override void inputBufferMark(object source, InputBufferEventArgs e) + { + System.Console.Out.WriteLine(e); + } - public override void inputBufferRewind(object source, InputBufferEventArgs e) - { - System.Console.Out.WriteLine(e); - } - } + public override void inputBufferRewind(object source, InputBufferEventArgs e) + { + System.Console.Out.WriteLine(e); + } } \ No newline at end of file diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/LLkDebuggingParser.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/LLkDebuggingParser.cs index 04a59dfe..6eb4be2a 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/LLkDebuggingParser.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/LLkDebuggingParser.cs @@ -1,271 +1,310 @@ -namespace Spring.Expressions.Parser.antlr.debug -{ - using System.Threading; - using antlr.collections.impl; - - public class LLkDebuggingParser : LLkParser, DebuggingParser - { - private void InitBlock() - { - parserEventSupport = new ParserEventSupport(this); - } - public override void setDebugMode(bool mode) - { - _notDebugMode = !mode; - } - protected internal ParserEventSupport parserEventSupport; - - private bool _notDebugMode = false; - protected internal string[] ruleNames; - protected internal string[] semPredNames; - - - public LLkDebuggingParser(int k_):base(k_) - { - InitBlock(); - } - public LLkDebuggingParser(ParserSharedInputState state, int k_):base(state, k_) - { - InitBlock(); - } - public LLkDebuggingParser(TokenBuffer tokenBuf, int k_):base(tokenBuf, k_) - { - InitBlock(); - } - public LLkDebuggingParser(TokenStream lexer, int k_):base(lexer, k_) - { - InitBlock(); - } - public override void addMessageListener(MessageListener l) - { - parserEventSupport.addMessageListener(l); - } - public override void addParserListener(ParserListener l) - { - parserEventSupport.addParserListener(l); - } - public override void addParserMatchListener(ParserMatchListener l) - { - parserEventSupport.addParserMatchListener(l); - } - public override void addParserTokenListener(ParserTokenListener l) - { - parserEventSupport.addParserTokenListener(l); - } - public override void addSemanticPredicateListener(SemanticPredicateListener l) - { - parserEventSupport.addSemanticPredicateListener(l); - } - public override void addSyntacticPredicateListener(SyntacticPredicateListener l) - { - parserEventSupport.addSyntacticPredicateListener(l); - } - public override void addTraceListener(TraceListener l) - { - parserEventSupport.addTraceListener(l); - } - /// Get another token object from the token stream - /// - public override void consume() - { - int la_1 = - 99; - la_1 = LA(1); - base.consume(); - parserEventSupport.fireConsume(la_1); - } - protected internal virtual void fireEnterRule(int num, int data) - { - if (isDebugMode()) - parserEventSupport.fireEnterRule(num, inputState.guessing, data); - } - protected internal virtual void fireExitRule(int num, int data) - { - if (isDebugMode()) - parserEventSupport.fireExitRule(num, inputState.guessing, data); - } - protected internal virtual bool fireSemanticPredicateEvaluated(int type, int num, bool condition) - { - if (isDebugMode()) - return parserEventSupport.fireSemanticPredicateEvaluated(type, num, condition, inputState.guessing); - else - return condition; - } - protected internal virtual void fireSyntacticPredicateFailed() - { - if (isDebugMode()) - parserEventSupport.fireSyntacticPredicateFailed(inputState.guessing); - } - protected internal virtual void fireSyntacticPredicateStarted() - { - if (isDebugMode()) - parserEventSupport.fireSyntacticPredicateStarted(inputState.guessing); - } - protected internal virtual void fireSyntacticPredicateSucceeded() - { - if (isDebugMode()) - parserEventSupport.fireSyntacticPredicateSucceeded(inputState.guessing); - } - public virtual string getRuleName(int num) - { - return ruleNames[num]; - } - public virtual string getSemPredName(int num) - { - return semPredNames[num]; - } +namespace Spring.Expressions.Parser.antlr.debug; - public virtual void goToSleep() - { - lock(this) - { - try - { - Monitor.Wait(this); - } - catch (System.Threading.ThreadInterruptedException) - { - } - } - } - public override bool isDebugMode() - { - return !_notDebugMode; - } - public virtual bool isGuessing() - { - return inputState.guessing > 0; - } - /// Return the token type of the ith token of lookahead where i=1 - /// is the current token being examined by the parser (i.e., it - /// has not been matched yet). - /// - public override int LA(int i) - { - int la = base.LA(i); - parserEventSupport.fireLA(i, la); - return la; - } - /// Make sure current lookahead symbol matches token type t. - /// Throw an exception upon mismatch, which is catch by either the - /// error handler or by the syntactic predicate. - /// - public override void match(int t) - { - string text = LT(1).getText(); - int la_1 = LA(1); - try - { - base.match(t); - parserEventSupport.fireMatch(t, text, inputState.guessing); - } - catch (MismatchedTokenException e) - { - if (inputState.guessing == 0) - parserEventSupport.fireMismatch(la_1, t, text, inputState.guessing); - throw e; - } - } - /// Make sure current lookahead symbol matches the given set - /// Throw an exception upon mismatch, which is catch by either the - /// error handler or by the syntactic predicate. - /// - public override void match(BitSet b) - { - string text = LT(1).getText(); - int la_1 = LA(1); - try - { - base.match(b); - parserEventSupport.fireMatch(la_1, b, text, inputState.guessing); - } - catch (MismatchedTokenException e) - { - if (inputState.guessing == 0) - parserEventSupport.fireMismatch(la_1, b, text, inputState.guessing); - throw e; - } - } - public override void matchNot(int t) - { - string text = LT(1).getText(); - int la_1 = LA(1); - try - { - base.matchNot(t); - parserEventSupport.fireMatchNot(la_1, t, text, inputState.guessing); - } - catch (MismatchedTokenException e) - { - if (inputState.guessing == 0) - parserEventSupport.fireMismatchNot(la_1, t, text, inputState.guessing); - throw e; - } - } - public override void removeMessageListener(MessageListener l) - { - parserEventSupport.removeMessageListener(l); - } - public override void removeParserListener(ParserListener l) - { - parserEventSupport.removeParserListener(l); - } - public override void removeParserMatchListener(ParserMatchListener l) - { - parserEventSupport.removeParserMatchListener(l); - } - public override void removeParserTokenListener(ParserTokenListener l) - { - parserEventSupport.removeParserTokenListener(l); - } - public override void removeSemanticPredicateListener(SemanticPredicateListener l) - { - parserEventSupport.removeSemanticPredicateListener(l); - } - public override void removeSyntacticPredicateListener(SyntacticPredicateListener l) - { - parserEventSupport.removeSyntacticPredicateListener(l); - } - public override void removeTraceListener(TraceListener l) - { - parserEventSupport.removeTraceListener(l); - } - /// Parser error-reporting function can be overridden in subclass - /// - public override void reportError(RecognitionException ex) - { - parserEventSupport.fireReportError(ex); - base.reportError(ex); - } - /// Parser error-reporting function can be overridden in subclass - /// - public override void reportError(string s) - { - parserEventSupport.fireReportError(s); - base.reportError(s); - } - /// Parser warning-reporting function can be overridden in subclass - /// - public override void reportWarning(string s) - { - parserEventSupport.fireReportWarning(s); - base.reportWarning(s); - } - public virtual void setupDebugging(TokenBuffer tokenBuf) - { - setupDebugging(null, tokenBuf); - } - public virtual void setupDebugging(TokenStream lexer) - { - setupDebugging(lexer, null); - } - /// User can override to do their own debugging - /// - protected internal virtual void setupDebugging(TokenStream lexer, TokenBuffer tokenBuf) - { - setDebugMode(true); - // default parser debug setup is ParseView - try - { +using System.Threading; +using antlr.collections.impl; + +public class LLkDebuggingParser : LLkParser, DebuggingParser +{ + private void InitBlock() + { + parserEventSupport = new ParserEventSupport(this); + } + + public override void setDebugMode(bool mode) + { + _notDebugMode = !mode; + } + + protected internal ParserEventSupport parserEventSupport; + + private bool _notDebugMode = false; + protected internal string[] ruleNames; + protected internal string[] semPredNames; + + public LLkDebuggingParser(int k_) : base(k_) + { + InitBlock(); + } + + public LLkDebuggingParser(ParserSharedInputState state, int k_) : base(state, k_) + { + InitBlock(); + } + + public LLkDebuggingParser(TokenBuffer tokenBuf, int k_) : base(tokenBuf, k_) + { + InitBlock(); + } + + public LLkDebuggingParser(TokenStream lexer, int k_) : base(lexer, k_) + { + InitBlock(); + } + + public override void addMessageListener(MessageListener l) + { + parserEventSupport.addMessageListener(l); + } + + public override void addParserListener(ParserListener l) + { + parserEventSupport.addParserListener(l); + } + + public override void addParserMatchListener(ParserMatchListener l) + { + parserEventSupport.addParserMatchListener(l); + } + + public override void addParserTokenListener(ParserTokenListener l) + { + parserEventSupport.addParserTokenListener(l); + } + + public override void addSemanticPredicateListener(SemanticPredicateListener l) + { + parserEventSupport.addSemanticPredicateListener(l); + } + + public override void addSyntacticPredicateListener(SyntacticPredicateListener l) + { + parserEventSupport.addSyntacticPredicateListener(l); + } + + public override void addTraceListener(TraceListener l) + { + parserEventSupport.addTraceListener(l); + } + + /// Get another token object from the token stream + /// + public override void consume() + { + int la_1 = -99; + la_1 = LA(1); + base.consume(); + parserEventSupport.fireConsume(la_1); + } + + protected internal virtual void fireEnterRule(int num, int data) + { + if (isDebugMode()) + parserEventSupport.fireEnterRule(num, inputState.guessing, data); + } + + protected internal virtual void fireExitRule(int num, int data) + { + if (isDebugMode()) + parserEventSupport.fireExitRule(num, inputState.guessing, data); + } + + protected internal virtual bool fireSemanticPredicateEvaluated(int type, int num, bool condition) + { + if (isDebugMode()) + return parserEventSupport.fireSemanticPredicateEvaluated(type, num, condition, inputState.guessing); + else + return condition; + } + + protected internal virtual void fireSyntacticPredicateFailed() + { + if (isDebugMode()) + parserEventSupport.fireSyntacticPredicateFailed(inputState.guessing); + } + + protected internal virtual void fireSyntacticPredicateStarted() + { + if (isDebugMode()) + parserEventSupport.fireSyntacticPredicateStarted(inputState.guessing); + } + + protected internal virtual void fireSyntacticPredicateSucceeded() + { + if (isDebugMode()) + parserEventSupport.fireSyntacticPredicateSucceeded(inputState.guessing); + } + + public virtual string getRuleName(int num) + { + return ruleNames[num]; + } + + public virtual string getSemPredName(int num) + { + return semPredNames[num]; + } + + public virtual void goToSleep() + { + lock (this) + { + try + { + Monitor.Wait(this); + } + catch (System.Threading.ThreadInterruptedException) + { + } + } + } + + public override bool isDebugMode() + { + return !_notDebugMode; + } + + public virtual bool isGuessing() + { + return inputState.guessing > 0; + } + + /// Return the token type of the ith token of lookahead where i=1 + /// is the current token being examined by the parser (i.e., it + /// has not been matched yet). + /// + public override int LA(int i) + { + int la = base.LA(i); + parserEventSupport.fireLA(i, la); + return la; + } + + /// Make sure current lookahead symbol matches token type t. + /// Throw an exception upon mismatch, which is catch by either the + /// error handler or by the syntactic predicate. + /// + public override void match(int t) + { + string text = LT(1).getText(); + int la_1 = LA(1); + try + { + base.match(t); + parserEventSupport.fireMatch(t, text, inputState.guessing); + } + catch (MismatchedTokenException e) + { + if (inputState.guessing == 0) + parserEventSupport.fireMismatch(la_1, t, text, inputState.guessing); + throw e; + } + } + + /// Make sure current lookahead symbol matches the given set + /// Throw an exception upon mismatch, which is catch by either the + /// error handler or by the syntactic predicate. + /// + public override void match(BitSet b) + { + string text = LT(1).getText(); + int la_1 = LA(1); + try + { + base.match(b); + parserEventSupport.fireMatch(la_1, b, text, inputState.guessing); + } + catch (MismatchedTokenException e) + { + if (inputState.guessing == 0) + parserEventSupport.fireMismatch(la_1, b, text, inputState.guessing); + throw e; + } + } + + public override void matchNot(int t) + { + string text = LT(1).getText(); + int la_1 = LA(1); + try + { + base.matchNot(t); + parserEventSupport.fireMatchNot(la_1, t, text, inputState.guessing); + } + catch (MismatchedTokenException e) + { + if (inputState.guessing == 0) + parserEventSupport.fireMismatchNot(la_1, t, text, inputState.guessing); + throw e; + } + } + + public override void removeMessageListener(MessageListener l) + { + parserEventSupport.removeMessageListener(l); + } + + public override void removeParserListener(ParserListener l) + { + parserEventSupport.removeParserListener(l); + } + + public override void removeParserMatchListener(ParserMatchListener l) + { + parserEventSupport.removeParserMatchListener(l); + } + + public override void removeParserTokenListener(ParserTokenListener l) + { + parserEventSupport.removeParserTokenListener(l); + } + + public override void removeSemanticPredicateListener(SemanticPredicateListener l) + { + parserEventSupport.removeSemanticPredicateListener(l); + } + + public override void removeSyntacticPredicateListener(SyntacticPredicateListener l) + { + parserEventSupport.removeSyntacticPredicateListener(l); + } + + public override void removeTraceListener(TraceListener l) + { + parserEventSupport.removeTraceListener(l); + } + + /// Parser error-reporting function can be overridden in subclass + /// + public override void reportError(RecognitionException ex) + { + parserEventSupport.fireReportError(ex); + base.reportError(ex); + } + + /// Parser error-reporting function can be overridden in subclass + /// + public override void reportError(string s) + { + parserEventSupport.fireReportError(s); + base.reportError(s); + } + + /// Parser warning-reporting function can be overridden in subclass + /// + public override void reportWarning(string s) + { + parserEventSupport.fireReportWarning(s); + base.reportWarning(s); + } + + public virtual void setupDebugging(TokenBuffer tokenBuf) + { + setupDebugging(null, tokenBuf); + } + + public virtual void setupDebugging(TokenStream lexer) + { + setupDebugging(lexer, null); + } + + /// User can override to do their own debugging + /// + protected internal virtual void setupDebugging(TokenStream lexer, TokenBuffer tokenBuf) + { + setDebugMode(true); + // default parser debug setup is ParseView + try + { // try // { // System.Type.GetType("javax.swing.JButton"); @@ -275,24 +314,23 @@ namespace Spring.Expressions.Parser.antlr.debug // System.Console.Error.WriteLine("Swing is required to use ParseView, but is not present in your CLASSPATH"); // System.Environment.Exit(1); // } - System.Type c = System.Type.GetType("antlr.parseview.ParseView"); - System.Reflection.ConstructorInfo constructor = c.GetConstructor(new System.Type[]{typeof(LLkDebuggingParser), typeof(TokenStream), typeof(TokenBuffer)}); - constructor.Invoke(new object[]{this, lexer, tokenBuf}); - } - catch (System.Exception e) - { - System.Console.Error.WriteLine("Error initializing ParseView: " + e); - System.Console.Error.WriteLine("Please report this to Scott Stanchfield, thetick@magelang.com"); - System.Environment.Exit(1); - } - } + System.Type c = System.Type.GetType("antlr.parseview.ParseView"); + System.Reflection.ConstructorInfo constructor = c.GetConstructor(new System.Type[] { typeof(LLkDebuggingParser), typeof(TokenStream), typeof(TokenBuffer) }); + constructor.Invoke(new object[] { this, lexer, tokenBuf }); + } + catch (System.Exception e) + { + System.Console.Error.WriteLine("Error initializing ParseView: " + e); + System.Console.Error.WriteLine("Please report this to Scott Stanchfield, thetick@magelang.com"); + System.Environment.Exit(1); + } + } - public virtual void wakeUp() - { - lock(this) - { - Monitor.Pulse(this); - } - } - } -} \ No newline at end of file + public virtual void wakeUp() + { + lock (this) + { + Monitor.Pulse(this); + } + } +} diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/Listener.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/Listener.cs index 77dfb8fe..14e02e9c 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/Listener.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/Listener.cs @@ -1,8 +1,7 @@ -namespace Spring.Expressions.Parser.antlr.debug +namespace Spring.Expressions.Parser.antlr.debug; + +public interface Listener { - public interface Listener - { - void doneParsing (object source, TraceEventArgs e); - void refresh (); - } -} \ No newline at end of file + void doneParsing(object source, TraceEventArgs e); + void refresh(); +} diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/MessageEventArgs.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/MessageEventArgs.cs index 114141e6..a4a1993c 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/MessageEventArgs.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/MessageEventArgs.cs @@ -1,39 +1,37 @@ -namespace Spring.Expressions.Parser.antlr.debug +namespace Spring.Expressions.Parser.antlr.debug; + +public class MessageEventArgs : ANTLREventArgs { - public class MessageEventArgs : ANTLREventArgs - { - public MessageEventArgs() - { - } - public MessageEventArgs(int type, string text) - { - setValues(type, text); - } + public MessageEventArgs() + { + } - public virtual string Text - { - get { return text_; } - set { this.text_ = value; } - - } + public MessageEventArgs(int type, string text) + { + setValues(type, text); + } - private string text_; + public virtual string Text + { + get { return text_; } + set { this.text_ = value; } + } - public static int WARNING = 0; - public static int ERROR = 1; - - - /// This should NOT be called from anyone other than ParserEventSupport! - /// - internal void setValues(int type, string text) - { - setValues(type); - this.Text = text; - } + private string text_; - public override string ToString() - { - return "ParserMessageEvent [" + (Type == WARNING?"warning,":"error,") + Text + "]"; - } - } -} \ No newline at end of file + public static int WARNING = 0; + public static int ERROR = 1; + + /// This should NOT be called from anyone other than ParserEventSupport! + /// + internal void setValues(int type, string text) + { + setValues(type); + this.Text = text; + } + + public override string ToString() + { + return "ParserMessageEvent [" + (Type == WARNING ? "warning," : "error,") + Text + "]"; + } +} diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/MessageListener.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/MessageListener.cs index 59d86d68..b5f7e3ab 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/MessageListener.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/MessageListener.cs @@ -1,8 +1,7 @@ -namespace Spring.Expressions.Parser.antlr.debug +namespace Spring.Expressions.Parser.antlr.debug; + +public interface MessageListener : Listener { - public interface MessageListener : Listener - { - void reportError (object source, MessageEventArgs e); - void reportWarning (object source, MessageEventArgs e); - } -} \ No newline at end of file + void reportError(object source, MessageEventArgs e); + void reportWarning(object source, MessageEventArgs e); +} diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/MessageListenerBase.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/MessageListenerBase.cs index 84136adf..e107cd85 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/MessageListenerBase.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/MessageListenerBase.cs @@ -1,45 +1,44 @@ -namespace Spring.Expressions.Parser.antlr.debug +namespace Spring.Expressions.Parser.antlr.debug; + +/// +/// Provides an abstract base for implementing subclasses. +/// +/// +/// +/// This abstract class is provided to make it easier to create s. +/// You should extend this base class rather than creating your own. +/// +/// +public class MessageListenerBase : MessageListener { /// - /// Provides an abstract base for implementing subclasses. - /// - /// - /// - /// This abstract class is provided to make it easier to create s. - /// You should extend this base class rather than creating your own. - /// - /// - public class MessageListenerBase : MessageListener - { - /// - /// Handle the "Done" event. - /// - /// Event source object - /// Event data object - public virtual void doneParsing(object source, TraceEventArgs e) - { - } + /// Handle the "Done" event. + /// + /// Event source object + /// Event data object + public virtual void doneParsing(object source, TraceEventArgs e) + { + } - public virtual void refresh() - { - } - - /// - /// Handle the "ReportError" event. - /// - /// Event source object - /// Event data object - public virtual void reportError(object source, MessageEventArgs e) - { - } - - /// - /// Handle the "ReportWarning" event. - /// - /// Event source object - /// Event data object - public virtual void reportWarning(object source, MessageEventArgs e) - { - } - } -} \ No newline at end of file + public virtual void refresh() + { + } + + /// + /// Handle the "ReportError" event. + /// + /// Event source object + /// Event data object + public virtual void reportError(object source, MessageEventArgs e) + { + } + + /// + /// Handle the "ReportWarning" event. + /// + /// Event source object + /// Event data object + public virtual void reportWarning(object source, MessageEventArgs e) + { + } +} diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/NewLineEventArgs.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/NewLineEventArgs.cs index e9776f6b..f35d844f 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/NewLineEventArgs.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/NewLineEventArgs.cs @@ -1,29 +1,28 @@ -namespace Spring.Expressions.Parser.antlr.debug +namespace Spring.Expressions.Parser.antlr.debug; + +public class NewLineEventArgs : ANTLREventArgs { - public class NewLineEventArgs : ANTLREventArgs - { - public NewLineEventArgs() - { - } - public NewLineEventArgs(int line) - { - Line = line; - } + public NewLineEventArgs() + { + } - public virtual int Line - { - get { return this.line_; } - set { this.line_ = value; } - } + public NewLineEventArgs(int line) + { + Line = line; + } - private int line_; - - - /// This should NOT be called from anyone other than ParserEventSupport! - /// - public override string ToString() - { - return "NewLineEvent [" + line_ + "]"; - } - } -} \ No newline at end of file + public virtual int Line + { + get { return this.line_; } + set { this.line_ = value; } + } + + private int line_; + + /// This should NOT be called from anyone other than ParserEventSupport! + /// + public override string ToString() + { + return "NewLineEvent [" + line_ + "]"; + } +} diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/NewLineListener.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/NewLineListener.cs index 87a2612e..912ee701 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/NewLineListener.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/NewLineListener.cs @@ -1,7 +1,6 @@ -namespace Spring.Expressions.Parser.antlr.debug +namespace Spring.Expressions.Parser.antlr.debug; + +public interface NewLineListener : Listener { - public interface NewLineListener : Listener - { - void hitNewLine(object source, NewLineEventArgs e); - } -} \ No newline at end of file + void hitNewLine(object source, NewLineEventArgs e); +} diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/ParseTreeDebugParser.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/ParseTreeDebugParser.cs index 412c8ff4..29598fc4 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/ParseTreeDebugParser.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/ParseTreeDebugParser.cs @@ -1,161 +1,163 @@ -namespace Spring.Expressions.Parser.antlr.debug +namespace Spring.Expressions.Parser.antlr.debug; + +/* ANTLR Translator Generator + * Project led by Terence Parr at http://www.jGuru.com + * Software rights: http://www.antlr.org/license.html + */ + +// +// ANTLR C# Code Generator by Micheal Jordan +// Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com +// Anthony Oguntimehin +// +using Stack = System.Collections.Stack; +using antlr; +using BitSet = antlr.collections.impl.BitSet; + +/// +/// Specifies the behaviour required (i.e. parser modifications) +/// specifically to support parse tree debugging and derivation. +/// +/// +/// +/// Override the standard matching and rule entry/exit routines +/// to build parse trees. This class is useful for 2.7.3 where +/// you can specify a superclass like +/// +/// +/// class TinyCParser extends Parser(ParseTreeDebugParser); +/// +/// +public class ParseTreeDebugParser : LLkParser { + /// + /// Each new rule invocation must have it's own subtree. Tokens are + /// added to the current root so we must have a stack of subtree roots. + /// + protected Stack currentParseTreeRoot = new Stack(); - /* ANTLR Translator Generator - * Project led by Terence Parr at http://www.jGuru.com - * Software rights: http://www.antlr.org/license.html - */ + /// + /// Track most recently created parse subtree so that when parsing + /// is finished, we can get to the root. + /// + protected ParseTreeRule mostRecentParseTreeRoot = null; - // - // ANTLR C# Code Generator by Micheal Jordan - // Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com - // Anthony Oguntimehin - // + /// + /// For every rule replacement with a production, we bump up count. + /// + protected int numberOfDerivationSteps = 1; // n replacements plus step 0 - using Stack = System.Collections.Stack; - using antlr; - using BitSet = antlr.collections.impl.BitSet; + public ParseTreeDebugParser(int k_) : base(k_) + { + } - /// - /// Specifies the behaviour required (i.e. parser modifications) - /// specifically to support parse tree debugging and derivation. - /// - /// - /// - /// Override the standard matching and rule entry/exit routines - /// to build parse trees. This class is useful for 2.7.3 where - /// you can specify a superclass like - /// - /// - /// class TinyCParser extends Parser(ParseTreeDebugParser); - /// - /// - public class ParseTreeDebugParser : LLkParser - { - /// - /// Each new rule invocation must have it's own subtree. Tokens are - /// added to the current root so we must have a stack of subtree roots. - /// - protected Stack currentParseTreeRoot = new Stack(); + public ParseTreeDebugParser(ParserSharedInputState state, int k_) : base(state, k_) + { + } - /// - /// Track most recently created parse subtree so that when parsing - /// is finished, we can get to the root. - /// - protected ParseTreeRule mostRecentParseTreeRoot = null; + public ParseTreeDebugParser(TokenBuffer tokenBuf, int k_) : base(tokenBuf, k_) + { + } - /// - /// For every rule replacement with a production, we bump up count. - /// - protected int numberOfDerivationSteps = 1; // n replacements plus step 0 + public ParseTreeDebugParser(TokenStream lexer, int k_) : base(lexer, k_) + { + } - public ParseTreeDebugParser(int k_) : base(k_) - { - } + public ParseTree getParseTree() + { + return mostRecentParseTreeRoot; + } - public ParseTreeDebugParser(ParserSharedInputState state, int k_) : base(state, k_) - { - } + public int getNumberOfDerivationSteps() + { + return numberOfDerivationSteps; + } - public ParseTreeDebugParser(TokenBuffer tokenBuf, int k_) : base(tokenBuf, k_) - { - } + public override void match(int i) // throws MismatchedTokenException, TokenStreamException + { + addCurrentTokenToParseTree(); + base.match(i); + } - public ParseTreeDebugParser(TokenStream lexer, int k_) : base(lexer,k_) - { - } + public override void match(BitSet bitSet) // throws MismatchedTokenException, TokenStreamException + { + addCurrentTokenToParseTree(); + base.match(bitSet); + } - public ParseTree getParseTree() - { - return mostRecentParseTreeRoot; - } + public override void matchNot(int i) // throws MismatchedTokenException, TokenStreamException + { + addCurrentTokenToParseTree(); + base.matchNot(i); + } - public int getNumberOfDerivationSteps() - { - return numberOfDerivationSteps; - } + /// + /// Adds LT(1) to the current parse subtree. + /// + /// + /// + /// Note that the match() routines add the node before checking for + /// correct match. This means that, upon mismatched token, there + /// will a token node in the tree corresponding to where that token + /// was expected. For no viable alternative errors, no node will + /// be in the tree as nothing was matched() (the lookahead failed + /// to predict an alternative). + /// + /// + protected void addCurrentTokenToParseTree() // throws TokenStreamException + { + if (inputState.guessing > 0) + { + return; + } - public override void match(int i) // throws MismatchedTokenException, TokenStreamException - { - addCurrentTokenToParseTree(); - base.match(i); - } + ParseTreeRule root = (ParseTreeRule) currentParseTreeRoot.Peek(); + ParseTreeToken tokenNode = null; + if (LA(1) == Token.EOF_TYPE) + { + tokenNode = new ParseTreeToken(new antlr.CommonToken("EOF")); + } + else + { + tokenNode = new ParseTreeToken(LT(1)); + } - public override void match(BitSet bitSet) // throws MismatchedTokenException, TokenStreamException - { - addCurrentTokenToParseTree(); - base.match(bitSet); - } + root.addChild(tokenNode); + } - public override void matchNot(int i) // throws MismatchedTokenException, TokenStreamException - { - addCurrentTokenToParseTree(); - base.matchNot(i); - } + /// + /// Create a rule node, add to current tree, and make it current root + /// + /// + public override void traceIn(string s) // throws TokenStreamException + { + if (inputState.guessing > 0) + { + return; + } - /// - /// Adds LT(1) to the current parse subtree. - /// - /// - /// - /// Note that the match() routines add the node before checking for - /// correct match. This means that, upon mismatched token, there - /// will a token node in the tree corresponding to where that token - /// was expected. For no viable alternative errors, no node will - /// be in the tree as nothing was matched() (the lookahead failed - /// to predict an alternative). - /// - /// - protected void addCurrentTokenToParseTree() // throws TokenStreamException - { - if (inputState.guessing > 0) - { - return; - } - ParseTreeRule root = (ParseTreeRule) currentParseTreeRoot.Peek(); - ParseTreeToken tokenNode = null; - if ( LA(1) == Token.EOF_TYPE ) - { - tokenNode = new ParseTreeToken(new antlr.CommonToken("EOF")); - } - else - { - tokenNode = new ParseTreeToken(LT(1)); - } - root.addChild(tokenNode); - } + ParseTreeRule subRoot = new ParseTreeRule(s); + if (currentParseTreeRoot.Count > 0) + { + ParseTreeRule oldRoot = (ParseTreeRule) currentParseTreeRoot.Peek(); + oldRoot.addChild(subRoot); + } - /// - /// Create a rule node, add to current tree, and make it current root - /// - /// - public override void traceIn(string s) // throws TokenStreamException - { - if (inputState.guessing > 0) - { - return; - } - ParseTreeRule subRoot = new ParseTreeRule(s); - if ( currentParseTreeRoot.Count > 0 ) - { - ParseTreeRule oldRoot = (ParseTreeRule) currentParseTreeRoot.Peek(); - oldRoot.addChild(subRoot); - } - currentParseTreeRoot.Push(subRoot); - numberOfDerivationSteps++; - } + currentParseTreeRoot.Push(subRoot); + numberOfDerivationSteps++; + } - /// - /// Pop current root; back to adding to old root - /// - /// - public override void traceOut(string s) // throws TokenStreamException - { - if (inputState.guessing > 0) - { - return; - } - mostRecentParseTreeRoot = (ParseTreeRule) currentParseTreeRoot.Pop(); - } - } + /// + /// Pop current root; back to adding to old root + /// + /// + public override void traceOut(string s) // throws TokenStreamException + { + if (inputState.guessing > 0) + { + return; + } + + mostRecentParseTreeRoot = (ParseTreeRule) currentParseTreeRoot.Pop(); + } } diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/ParserController.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/ParserController.cs index 77808fd5..f0ba1a73 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/ParserController.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/ParserController.cs @@ -1,12 +1,11 @@ -namespace Spring.Expressions.Parser.antlr.debug -{ - public interface ParserController : ParserListener - { - ParserEventSupport ParserEventSupport - { - set; - } +namespace Spring.Expressions.Parser.antlr.debug; - void checkBreak(); - } -} \ No newline at end of file +public interface ParserController : ParserListener +{ + ParserEventSupport ParserEventSupport + { + set; + } + + void checkBreak(); +} diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/ParserEventSupport.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/ParserEventSupport.cs index d5baf1c2..726c4f29 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/ParserEventSupport.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/ParserEventSupport.cs @@ -1,487 +1,562 @@ -namespace Spring.Expressions.Parser.antlr.debug +namespace Spring.Expressions.Parser.antlr.debug; + +using Hashtable = System.Collections.Hashtable; +using DictionaryEntry = System.Collections.DictionaryEntry; +using antlr.collections.impl; + +public delegate void MessageEventHandler(object sender, MessageEventArgs e); + +public delegate void NewLineEventHandler(object sender, NewLineEventArgs e); + +public delegate void MatchEventHandler(object sender, MatchEventArgs e); + +public delegate void TokenEventHandler(object sender, TokenEventArgs e); + +public delegate void SemanticPredicateEventHandler(object sender, SemanticPredicateEventArgs e); + +public delegate void SyntacticPredicateEventHandler(object sender, SyntacticPredicateEventArgs e); + +public delegate void TraceEventHandler(object sender, TraceEventArgs e); + +/// A class to assist in firing parser events +/// NOTE: I intentionally _did_not_ synchronize the event firing and +/// add/remove listener methods. This is because the add/remove should +/// _only_ be called by the parser at its start/end, and the _same_thread_ +/// should be performing the parsing. This should help performance a tad... +/// +public class ParserEventSupport { - using Hashtable = System.Collections.Hashtable; - using DictionaryEntry = System.Collections.DictionaryEntry; + private object source; + private Hashtable listeners; - using antlr.collections.impl; - - - public delegate void MessageEventHandler(object sender, MessageEventArgs e); - public delegate void NewLineEventHandler(object sender, NewLineEventArgs e); - public delegate void MatchEventHandler(object sender, MatchEventArgs e); - public delegate void TokenEventHandler(object sender, TokenEventArgs e); - public delegate void SemanticPredicateEventHandler(object sender, SemanticPredicateEventArgs e); - public delegate void SyntacticPredicateEventHandler(object sender, SyntacticPredicateEventArgs e); - public delegate void TraceEventHandler(object sender, TraceEventArgs e); + private MatchEventArgs matchEvent; + private MessageEventArgs messageEvent; + private TokenEventArgs tokenEvent; + private SemanticPredicateEventArgs semPredEvent; + private SyntacticPredicateEventArgs synPredEvent; + private TraceEventArgs traceEvent; + private NewLineEventArgs newLineEvent; - /// A class to assist in firing parser events - /// NOTE: I intentionally _did_not_ synchronize the event firing and - /// add/remove listener methods. This is because the add/remove should - /// _only_ be called by the parser at its start/end, and the _same_thread_ - /// should be performing the parsing. This should help performance a tad... - /// - public class ParserEventSupport - { - private object source; - private Hashtable listeners; + private ParserController controller; - private MatchEventArgs matchEvent; - private MessageEventArgs messageEvent; - private TokenEventArgs tokenEvent; - private SemanticPredicateEventArgs semPredEvent; - private SyntacticPredicateEventArgs synPredEvent; - private TraceEventArgs traceEvent; - private NewLineEventArgs newLineEvent; + private int ruleDepth = 0; - private ParserController controller; + public ParserEventSupport(object source) + { + matchEvent = new MatchEventArgs(); + messageEvent = new MessageEventArgs(); + tokenEvent = new TokenEventArgs(); + traceEvent = new TraceEventArgs(); + semPredEvent = new SemanticPredicateEventArgs(); + synPredEvent = new SyntacticPredicateEventArgs(); + newLineEvent = new NewLineEventArgs(); + listeners = new Hashtable(); + this.source = source; + } - private int ruleDepth = 0; - - - public ParserEventSupport(object source) - { - matchEvent = new MatchEventArgs(); - messageEvent = new MessageEventArgs(); - tokenEvent = new TokenEventArgs(); - traceEvent = new TraceEventArgs(); - semPredEvent = new SemanticPredicateEventArgs(); - synPredEvent = new SyntacticPredicateEventArgs(); - newLineEvent = new NewLineEventArgs(); - listeners = new Hashtable(); - this.source = source; - } + public virtual void checkController() + { + if (controller != null) + controller.checkBreak(); + } - public virtual void checkController() - { - if (controller != null) - controller.checkBreak(); - } + public virtual void addDoneListener(Listener l) + { + ((Parser) source).Done += new TraceEventHandler(l.doneParsing); + listeners[l] = l; + } - public virtual void addDoneListener(Listener l) - { - ((Parser)source).Done += new TraceEventHandler(l.doneParsing); - listeners[l] = l; - } - public virtual void addMessageListener(MessageListener l) - { - ((Parser)source).ErrorReported += new MessageEventHandler(l.reportError); - ((Parser)source).WarningReported += new MessageEventHandler(l.reportWarning); - //messageListeners.Add(l); - addDoneListener(l); - } - public virtual void addParserListener(ParserListener l) - { - if (l is ParserController) - { - ((ParserController) l).ParserEventSupport = this; - controller = (ParserController) l; - } - addParserMatchListener(l); - addParserTokenListener(l); - - addMessageListener(l); - addTraceListener(l); - addSemanticPredicateListener(l); - addSyntacticPredicateListener(l); - } - public virtual void addParserMatchListener(ParserMatchListener l) - { - ((Parser)source).MatchedToken += new MatchEventHandler(l.parserMatch); - ((Parser)source).MatchedNotToken += new MatchEventHandler(l.parserMatchNot); - ((Parser)source).MisMatchedToken += new MatchEventHandler(l.parserMismatch); - ((Parser)source).MisMatchedNotToken += new MatchEventHandler(l.parserMismatchNot); - //matchListeners.Add(l); - addDoneListener(l); - } - public virtual void addParserTokenListener(ParserTokenListener l) - { - ((Parser)source).ConsumedToken += new TokenEventHandler(l.parserConsume); - ((Parser)source).TokenLA += new TokenEventHandler(l.parserLA); - //tokenListeners.Add(l); - addDoneListener(l); - } - public virtual void addSemanticPredicateListener(SemanticPredicateListener l) - { - ((Parser)source).SemPredEvaluated += new SemanticPredicateEventHandler(l.semanticPredicateEvaluated); - //semPredListeners.Add(l); - addDoneListener(l); - } - public virtual void addSyntacticPredicateListener(SyntacticPredicateListener l) - { - ((Parser)source).SynPredStarted += new SyntacticPredicateEventHandler(l.syntacticPredicateStarted); - ((Parser)source).SynPredFailed += new SyntacticPredicateEventHandler(l.syntacticPredicateFailed); - ((Parser)source).SynPredSucceeded += new SyntacticPredicateEventHandler(l.syntacticPredicateSucceeded); - //synPredListeners.Add(l); - addDoneListener(l); - } - public virtual void addTraceListener(TraceListener l) - { - ((Parser)source).EnterRule += new TraceEventHandler(l.enterRule); - ((Parser)source).ExitRule += new TraceEventHandler(l.exitRule); - //traceListeners.Add(l); - addDoneListener(l); - } - public virtual void fireConsume(int c) - { - TokenEventHandler eventDelegate = (TokenEventHandler)((Parser)source).Events[Parser.LAEventKey]; - if (eventDelegate != null) - { - tokenEvent.setValues(TokenEventArgs.CONSUME, 1, c); - eventDelegate(source, tokenEvent); - } - checkController(); - } - public virtual void fireDoneParsing() - { - TraceEventHandler eventDelegate = (TraceEventHandler)((Parser)source).Events[Parser.DoneEventKey]; - if (eventDelegate != null) - { - traceEvent.setValues(TraceEventArgs.DONE_PARSING, 0, 0, 0); - eventDelegate(source, traceEvent); - } - checkController(); - } - public virtual void fireEnterRule(int ruleNum, int guessing, int data) - { - ruleDepth++; - TraceEventHandler eventDelegate = (TraceEventHandler)((Parser)source).Events[Parser.EnterRuleEventKey]; - if (eventDelegate != null) - { - traceEvent.setValues(TraceEventArgs.ENTER, ruleNum, guessing, data); - eventDelegate(source, traceEvent); - } - checkController(); - } - public virtual void fireExitRule(int ruleNum, int guessing, int data) - { - TraceEventHandler eventDelegate = (TraceEventHandler)((Parser)source).Events[Parser.ExitRuleEventKey]; - if (eventDelegate != null) - { - traceEvent.setValues(TraceEventArgs.EXIT, ruleNum, guessing, data); - eventDelegate(source, traceEvent); - } - checkController(); + public virtual void addMessageListener(MessageListener l) + { + ((Parser) source).ErrorReported += new MessageEventHandler(l.reportError); + ((Parser) source).WarningReported += new MessageEventHandler(l.reportWarning); + //messageListeners.Add(l); + addDoneListener(l); + } - ruleDepth--; - if (ruleDepth == 0) - fireDoneParsing(); + public virtual void addParserListener(ParserListener l) + { + if (l is ParserController) + { + ((ParserController) l).ParserEventSupport = this; + controller = (ParserController) l; + } - } - public virtual void fireLA(int k, int la) - { - TokenEventHandler eventDelegate = (TokenEventHandler)((Parser)source).Events[Parser.LAEventKey]; - if (eventDelegate != null) - { - tokenEvent.setValues(TokenEventArgs.LA, k, la); - eventDelegate(source, tokenEvent); - } - checkController(); - } - public virtual void fireMatch(char c, int guessing) - { - MatchEventHandler eventDelegate = (MatchEventHandler)((Parser)source).Events[Parser.MatchEventKey]; - if (eventDelegate != null) - { - matchEvent.setValues(MatchEventArgs.CHAR, c, c, null, guessing, false, true); - eventDelegate(source, matchEvent); - } - checkController(); - } - public virtual void fireMatch(char c, BitSet b, int guessing) - { - MatchEventHandler eventDelegate = (MatchEventHandler)((Parser)source).Events[Parser.MatchEventKey]; - if (eventDelegate != null) - { - matchEvent.setValues(MatchEventArgs.CHAR_BITSET, c, b, null, guessing, false, true); - eventDelegate(source, matchEvent); - } - checkController(); - } - public virtual void fireMatch(char c, string target, int guessing) - { - MatchEventHandler eventDelegate = (MatchEventHandler)((Parser)source).Events[Parser.MatchEventKey]; - if (eventDelegate != null) - { - matchEvent.setValues(MatchEventArgs.CHAR_RANGE, c, target, null, guessing, false, true); - eventDelegate(source, matchEvent); - } - checkController(); - } - public virtual void fireMatch(int c, BitSet b, string text, int guessing) - { - MatchEventHandler eventDelegate = (MatchEventHandler)((Parser)source).Events[Parser.MatchEventKey]; - if (eventDelegate != null) - { - matchEvent.setValues(MatchEventArgs.BITSET, c, b, text, guessing, false, true); - eventDelegate(source, matchEvent); - } - checkController(); - } - public virtual void fireMatch(int n, string text, int guessing) - { - MatchEventHandler eventDelegate = (MatchEventHandler)((Parser)source).Events[Parser.MatchEventKey]; - if (eventDelegate != null) - { - matchEvent.setValues(MatchEventArgs.TOKEN, n, n, text, guessing, false, true); - eventDelegate(source, matchEvent); - } - checkController(); - } - public virtual void fireMatch(string s, int guessing) - { - MatchEventHandler eventDelegate = (MatchEventHandler)((Parser)source).Events[Parser.MatchEventKey]; - if (eventDelegate != null) - { - matchEvent.setValues(MatchEventArgs.STRING, 0, s, null, guessing, false, true); - eventDelegate(source, matchEvent); - } - checkController(); - } - public virtual void fireMatchNot(char c, char n, int guessing) - { - MatchEventHandler eventDelegate = (MatchEventHandler)((Parser)source).Events[Parser.MatchNotEventKey]; - if (eventDelegate != null) - { - matchEvent.setValues(MatchEventArgs.CHAR, c, n, null, guessing, true, true); - eventDelegate(source, matchEvent); - } - checkController(); - } - public virtual void fireMatchNot(int c, int n, string text, int guessing) - { - MatchEventHandler eventDelegate = (MatchEventHandler)((Parser)source).Events[Parser.MatchNotEventKey]; - if (eventDelegate != null) - { - matchEvent.setValues(MatchEventArgs.TOKEN, c, n, text, guessing, true, true); - eventDelegate(source, matchEvent); - } - checkController(); - } - public virtual void fireMismatch(char c, char n, int guessing) - { - MatchEventHandler eventDelegate = (MatchEventHandler)((Parser)source).Events[Parser.MisMatchEventKey]; - if (eventDelegate != null) - { - matchEvent.setValues(MatchEventArgs.CHAR, c, n, null, guessing, false, false); - eventDelegate(source, matchEvent); - } - checkController(); - } - public virtual void fireMismatch(char c, BitSet b, int guessing) - { - MatchEventHandler eventDelegate = (MatchEventHandler)((Parser)source).Events[Parser.MisMatchEventKey]; - if (eventDelegate != null) - { - matchEvent.setValues(MatchEventArgs.CHAR_BITSET, c, b, null, guessing, false, true); - eventDelegate(source, matchEvent); - } - checkController(); - } - public virtual void fireMismatch(char c, string target, int guessing) - { - MatchEventHandler eventDelegate = (MatchEventHandler)((Parser)source).Events[Parser.MisMatchEventKey]; - if (eventDelegate != null) - { - matchEvent.setValues(MatchEventArgs.CHAR_RANGE, c, target, null, guessing, false, true); - eventDelegate(source, matchEvent); - } - checkController(); - } - public virtual void fireMismatch(int i, int n, string text, int guessing) - { - MatchEventHandler eventDelegate = (MatchEventHandler)((Parser)source).Events[Parser.MisMatchEventKey]; - if (eventDelegate != null) - { - matchEvent.setValues(MatchEventArgs.TOKEN, i, n, text, guessing, false, false); - eventDelegate(source, matchEvent); - } - checkController(); - } - public virtual void fireMismatch(int i, BitSet b, string text, int guessing) - { - MatchEventHandler eventDelegate = (MatchEventHandler)((Parser)source).Events[Parser.MisMatchEventKey]; - if (eventDelegate != null) - { - matchEvent.setValues(MatchEventArgs.BITSET, i, b, text, guessing, false, true); - eventDelegate(source, matchEvent); - } - checkController(); - } - public virtual void fireMismatch(string s, string text, int guessing) - { - MatchEventHandler eventDelegate = (MatchEventHandler)((Parser)source).Events[Parser.MisMatchEventKey]; - if (eventDelegate != null) - { - matchEvent.setValues(MatchEventArgs.STRING, 0, text, s, guessing, false, true); - eventDelegate(source, matchEvent); - } - checkController(); - } - public virtual void fireMismatchNot(char v, char c, int guessing) - { - MatchEventHandler eventDelegate = (MatchEventHandler)((Parser)source).Events[Parser.MisMatchNotEventKey]; - if (eventDelegate != null) - { - matchEvent.setValues(MatchEventArgs.CHAR, v, c, null, guessing, true, true); - eventDelegate(source, matchEvent); - } - checkController(); - } - public virtual void fireMismatchNot(int i, int n, string text, int guessing) - { - MatchEventHandler eventDelegate = (MatchEventHandler)((Parser)source).Events[Parser.MisMatchNotEventKey]; - if (eventDelegate != null) - { - matchEvent.setValues(MatchEventArgs.TOKEN, i, n, text, guessing, true, true); - eventDelegate(source, matchEvent); - } - checkController(); - } - public virtual void fireReportError(System.Exception e) - { - MessageEventHandler eventDelegate = (MessageEventHandler)((Parser)source).Events[Parser.ReportErrorEventKey]; - if (eventDelegate != null) - { - messageEvent.setValues(MessageEventArgs.ERROR, e.ToString()); - eventDelegate(source, messageEvent); - } - checkController(); - } - public virtual void fireReportError(string s) - { - MessageEventHandler eventDelegate = (MessageEventHandler)((Parser)source).Events[Parser.ReportErrorEventKey]; - if (eventDelegate != null) - { - messageEvent.setValues(MessageEventArgs.ERROR, s); - eventDelegate(source, messageEvent); - } - checkController(); - } - public virtual void fireReportWarning(string s) - { - MessageEventHandler eventDelegate = (MessageEventHandler)((Parser)source).Events[Parser.ReportWarningEventKey]; - if (eventDelegate != null) - { - messageEvent.setValues(MessageEventArgs.WARNING, s); - eventDelegate(source, messageEvent); - } - checkController(); - } - public virtual bool fireSemanticPredicateEvaluated(int type, int condition, bool result, int guessing) - { - SemanticPredicateEventHandler eventDelegate = (SemanticPredicateEventHandler)((Parser)source).Events[Parser.SemPredEvaluatedEventKey]; - if (eventDelegate != null) - { - semPredEvent.setValues(type, condition, result, guessing); - eventDelegate(source, semPredEvent); - } - checkController(); + addParserMatchListener(l); + addParserTokenListener(l); - return result; - } - public virtual void fireSyntacticPredicateFailed(int guessing) - { - SyntacticPredicateEventHandler eventDelegate = (SyntacticPredicateEventHandler)((Parser)source).Events[Parser.SynPredFailedEventKey]; - if (eventDelegate != null) - { - synPredEvent.setValues(0, guessing); - eventDelegate(source, synPredEvent); - } - checkController(); - } - public virtual void fireSyntacticPredicateStarted(int guessing) - { - SyntacticPredicateEventHandler eventDelegate = (SyntacticPredicateEventHandler)((Parser)source).Events[Parser.SynPredStartedEventKey]; - if (eventDelegate != null) - { - synPredEvent.setValues(0, guessing); - eventDelegate(source, synPredEvent); - } - checkController(); - } - public virtual void fireSyntacticPredicateSucceeded(int guessing) - { - SyntacticPredicateEventHandler eventDelegate = (SyntacticPredicateEventHandler)((Parser)source).Events[Parser.SynPredSucceededEventKey]; - if (eventDelegate != null) - { - synPredEvent.setValues(0, guessing); - eventDelegate(source, synPredEvent); - } - checkController(); - } - public virtual void refreshListeners() - { - Hashtable clonedTable; + addMessageListener(l); + addTraceListener(l); + addSemanticPredicateListener(l); + addSyntacticPredicateListener(l); + } - lock(listeners.SyncRoot) - { - clonedTable = (Hashtable)listeners.Clone(); - } - foreach (DictionaryEntry entry in clonedTable) - { - if (entry.Value != null) - { - ((Listener) entry.Value).refresh(); - } - } - } - public virtual void removeDoneListener(Listener l) - { - ((Parser)source).Done -= new TraceEventHandler(l.doneParsing); - listeners.Remove(l); - } - public virtual void removeMessageListener(MessageListener l) - { - ((Parser)source).ErrorReported -= new MessageEventHandler(l.reportError); - ((Parser)source).WarningReported -= new MessageEventHandler(l.reportWarning); - //messageListeners.Remove(l); - removeDoneListener(l); - } - public virtual void removeParserListener(ParserListener l) - { - removeParserMatchListener(l); - removeMessageListener(l); - removeParserTokenListener(l); - removeTraceListener(l); - removeSemanticPredicateListener(l); - removeSyntacticPredicateListener(l); - } - public virtual void removeParserMatchListener(ParserMatchListener l) - { - ((Parser)source).MatchedToken -= new MatchEventHandler(l.parserMatch); - ((Parser)source).MatchedNotToken -= new MatchEventHandler(l.parserMatchNot); - ((Parser)source).MisMatchedToken -= new MatchEventHandler(l.parserMismatch); - ((Parser)source).MisMatchedNotToken -= new MatchEventHandler(l.parserMismatchNot); - //matchListeners.Remove(l); - removeDoneListener(l); - } - public virtual void removeParserTokenListener(ParserTokenListener l) - { - ((Parser)source).ConsumedToken -= new TokenEventHandler(l.parserConsume); - ((Parser)source).TokenLA -= new TokenEventHandler(l.parserLA); - //tokenListeners.Remove(l); - removeDoneListener(l); - } - public virtual void removeSemanticPredicateListener(SemanticPredicateListener l) - { - ((Parser)source).SemPredEvaluated -= new SemanticPredicateEventHandler(l.semanticPredicateEvaluated); - //semPredListeners.Remove(l); - removeDoneListener(l); - } - public virtual void removeSyntacticPredicateListener(SyntacticPredicateListener l) - { - ((Parser)source).SynPredStarted -= new SyntacticPredicateEventHandler(l.syntacticPredicateStarted); - ((Parser)source).SynPredFailed -= new SyntacticPredicateEventHandler(l.syntacticPredicateFailed); - ((Parser)source).SynPredSucceeded -= new SyntacticPredicateEventHandler(l.syntacticPredicateSucceeded); - //synPredListeners.Remove(l); - removeDoneListener(l); - } - public virtual void removeTraceListener(TraceListener l) - { - ((Parser)source).EnterRule -= new TraceEventHandler(l.enterRule); - ((Parser)source).ExitRule -= new TraceEventHandler(l.exitRule); - //traceListeners.Remove(l); - removeDoneListener(l); - } - } -} \ No newline at end of file + public virtual void addParserMatchListener(ParserMatchListener l) + { + ((Parser) source).MatchedToken += new MatchEventHandler(l.parserMatch); + ((Parser) source).MatchedNotToken += new MatchEventHandler(l.parserMatchNot); + ((Parser) source).MisMatchedToken += new MatchEventHandler(l.parserMismatch); + ((Parser) source).MisMatchedNotToken += new MatchEventHandler(l.parserMismatchNot); + //matchListeners.Add(l); + addDoneListener(l); + } + + public virtual void addParserTokenListener(ParserTokenListener l) + { + ((Parser) source).ConsumedToken += new TokenEventHandler(l.parserConsume); + ((Parser) source).TokenLA += new TokenEventHandler(l.parserLA); + //tokenListeners.Add(l); + addDoneListener(l); + } + + public virtual void addSemanticPredicateListener(SemanticPredicateListener l) + { + ((Parser) source).SemPredEvaluated += new SemanticPredicateEventHandler(l.semanticPredicateEvaluated); + //semPredListeners.Add(l); + addDoneListener(l); + } + + public virtual void addSyntacticPredicateListener(SyntacticPredicateListener l) + { + ((Parser) source).SynPredStarted += new SyntacticPredicateEventHandler(l.syntacticPredicateStarted); + ((Parser) source).SynPredFailed += new SyntacticPredicateEventHandler(l.syntacticPredicateFailed); + ((Parser) source).SynPredSucceeded += new SyntacticPredicateEventHandler(l.syntacticPredicateSucceeded); + //synPredListeners.Add(l); + addDoneListener(l); + } + + public virtual void addTraceListener(TraceListener l) + { + ((Parser) source).EnterRule += new TraceEventHandler(l.enterRule); + ((Parser) source).ExitRule += new TraceEventHandler(l.exitRule); + //traceListeners.Add(l); + addDoneListener(l); + } + + public virtual void fireConsume(int c) + { + TokenEventHandler eventDelegate = (TokenEventHandler) ((Parser) source).Events[Parser.LAEventKey]; + if (eventDelegate != null) + { + tokenEvent.setValues(TokenEventArgs.CONSUME, 1, c); + eventDelegate(source, tokenEvent); + } + + checkController(); + } + + public virtual void fireDoneParsing() + { + TraceEventHandler eventDelegate = (TraceEventHandler) ((Parser) source).Events[Parser.DoneEventKey]; + if (eventDelegate != null) + { + traceEvent.setValues(TraceEventArgs.DONE_PARSING, 0, 0, 0); + eventDelegate(source, traceEvent); + } + + checkController(); + } + + public virtual void fireEnterRule(int ruleNum, int guessing, int data) + { + ruleDepth++; + TraceEventHandler eventDelegate = (TraceEventHandler) ((Parser) source).Events[Parser.EnterRuleEventKey]; + if (eventDelegate != null) + { + traceEvent.setValues(TraceEventArgs.ENTER, ruleNum, guessing, data); + eventDelegate(source, traceEvent); + } + + checkController(); + } + + public virtual void fireExitRule(int ruleNum, int guessing, int data) + { + TraceEventHandler eventDelegate = (TraceEventHandler) ((Parser) source).Events[Parser.ExitRuleEventKey]; + if (eventDelegate != null) + { + traceEvent.setValues(TraceEventArgs.EXIT, ruleNum, guessing, data); + eventDelegate(source, traceEvent); + } + + checkController(); + + ruleDepth--; + if (ruleDepth == 0) + fireDoneParsing(); + } + + public virtual void fireLA(int k, int la) + { + TokenEventHandler eventDelegate = (TokenEventHandler) ((Parser) source).Events[Parser.LAEventKey]; + if (eventDelegate != null) + { + tokenEvent.setValues(TokenEventArgs.LA, k, la); + eventDelegate(source, tokenEvent); + } + + checkController(); + } + + public virtual void fireMatch(char c, int guessing) + { + MatchEventHandler eventDelegate = (MatchEventHandler) ((Parser) source).Events[Parser.MatchEventKey]; + if (eventDelegate != null) + { + matchEvent.setValues(MatchEventArgs.CHAR, c, c, null, guessing, false, true); + eventDelegate(source, matchEvent); + } + + checkController(); + } + + public virtual void fireMatch(char c, BitSet b, int guessing) + { + MatchEventHandler eventDelegate = (MatchEventHandler) ((Parser) source).Events[Parser.MatchEventKey]; + if (eventDelegate != null) + { + matchEvent.setValues(MatchEventArgs.CHAR_BITSET, c, b, null, guessing, false, true); + eventDelegate(source, matchEvent); + } + + checkController(); + } + + public virtual void fireMatch(char c, string target, int guessing) + { + MatchEventHandler eventDelegate = (MatchEventHandler) ((Parser) source).Events[Parser.MatchEventKey]; + if (eventDelegate != null) + { + matchEvent.setValues(MatchEventArgs.CHAR_RANGE, c, target, null, guessing, false, true); + eventDelegate(source, matchEvent); + } + + checkController(); + } + + public virtual void fireMatch(int c, BitSet b, string text, int guessing) + { + MatchEventHandler eventDelegate = (MatchEventHandler) ((Parser) source).Events[Parser.MatchEventKey]; + if (eventDelegate != null) + { + matchEvent.setValues(MatchEventArgs.BITSET, c, b, text, guessing, false, true); + eventDelegate(source, matchEvent); + } + + checkController(); + } + + public virtual void fireMatch(int n, string text, int guessing) + { + MatchEventHandler eventDelegate = (MatchEventHandler) ((Parser) source).Events[Parser.MatchEventKey]; + if (eventDelegate != null) + { + matchEvent.setValues(MatchEventArgs.TOKEN, n, n, text, guessing, false, true); + eventDelegate(source, matchEvent); + } + + checkController(); + } + + public virtual void fireMatch(string s, int guessing) + { + MatchEventHandler eventDelegate = (MatchEventHandler) ((Parser) source).Events[Parser.MatchEventKey]; + if (eventDelegate != null) + { + matchEvent.setValues(MatchEventArgs.STRING, 0, s, null, guessing, false, true); + eventDelegate(source, matchEvent); + } + + checkController(); + } + + public virtual void fireMatchNot(char c, char n, int guessing) + { + MatchEventHandler eventDelegate = (MatchEventHandler) ((Parser) source).Events[Parser.MatchNotEventKey]; + if (eventDelegate != null) + { + matchEvent.setValues(MatchEventArgs.CHAR, c, n, null, guessing, true, true); + eventDelegate(source, matchEvent); + } + + checkController(); + } + + public virtual void fireMatchNot(int c, int n, string text, int guessing) + { + MatchEventHandler eventDelegate = (MatchEventHandler) ((Parser) source).Events[Parser.MatchNotEventKey]; + if (eventDelegate != null) + { + matchEvent.setValues(MatchEventArgs.TOKEN, c, n, text, guessing, true, true); + eventDelegate(source, matchEvent); + } + + checkController(); + } + + public virtual void fireMismatch(char c, char n, int guessing) + { + MatchEventHandler eventDelegate = (MatchEventHandler) ((Parser) source).Events[Parser.MisMatchEventKey]; + if (eventDelegate != null) + { + matchEvent.setValues(MatchEventArgs.CHAR, c, n, null, guessing, false, false); + eventDelegate(source, matchEvent); + } + + checkController(); + } + + public virtual void fireMismatch(char c, BitSet b, int guessing) + { + MatchEventHandler eventDelegate = (MatchEventHandler) ((Parser) source).Events[Parser.MisMatchEventKey]; + if (eventDelegate != null) + { + matchEvent.setValues(MatchEventArgs.CHAR_BITSET, c, b, null, guessing, false, true); + eventDelegate(source, matchEvent); + } + + checkController(); + } + + public virtual void fireMismatch(char c, string target, int guessing) + { + MatchEventHandler eventDelegate = (MatchEventHandler) ((Parser) source).Events[Parser.MisMatchEventKey]; + if (eventDelegate != null) + { + matchEvent.setValues(MatchEventArgs.CHAR_RANGE, c, target, null, guessing, false, true); + eventDelegate(source, matchEvent); + } + + checkController(); + } + + public virtual void fireMismatch(int i, int n, string text, int guessing) + { + MatchEventHandler eventDelegate = (MatchEventHandler) ((Parser) source).Events[Parser.MisMatchEventKey]; + if (eventDelegate != null) + { + matchEvent.setValues(MatchEventArgs.TOKEN, i, n, text, guessing, false, false); + eventDelegate(source, matchEvent); + } + + checkController(); + } + + public virtual void fireMismatch(int i, BitSet b, string text, int guessing) + { + MatchEventHandler eventDelegate = (MatchEventHandler) ((Parser) source).Events[Parser.MisMatchEventKey]; + if (eventDelegate != null) + { + matchEvent.setValues(MatchEventArgs.BITSET, i, b, text, guessing, false, true); + eventDelegate(source, matchEvent); + } + + checkController(); + } + + public virtual void fireMismatch(string s, string text, int guessing) + { + MatchEventHandler eventDelegate = (MatchEventHandler) ((Parser) source).Events[Parser.MisMatchEventKey]; + if (eventDelegate != null) + { + matchEvent.setValues(MatchEventArgs.STRING, 0, text, s, guessing, false, true); + eventDelegate(source, matchEvent); + } + + checkController(); + } + + public virtual void fireMismatchNot(char v, char c, int guessing) + { + MatchEventHandler eventDelegate = (MatchEventHandler) ((Parser) source).Events[Parser.MisMatchNotEventKey]; + if (eventDelegate != null) + { + matchEvent.setValues(MatchEventArgs.CHAR, v, c, null, guessing, true, true); + eventDelegate(source, matchEvent); + } + + checkController(); + } + + public virtual void fireMismatchNot(int i, int n, string text, int guessing) + { + MatchEventHandler eventDelegate = (MatchEventHandler) ((Parser) source).Events[Parser.MisMatchNotEventKey]; + if (eventDelegate != null) + { + matchEvent.setValues(MatchEventArgs.TOKEN, i, n, text, guessing, true, true); + eventDelegate(source, matchEvent); + } + + checkController(); + } + + public virtual void fireReportError(System.Exception e) + { + MessageEventHandler eventDelegate = (MessageEventHandler) ((Parser) source).Events[Parser.ReportErrorEventKey]; + if (eventDelegate != null) + { + messageEvent.setValues(MessageEventArgs.ERROR, e.ToString()); + eventDelegate(source, messageEvent); + } + + checkController(); + } + + public virtual void fireReportError(string s) + { + MessageEventHandler eventDelegate = (MessageEventHandler) ((Parser) source).Events[Parser.ReportErrorEventKey]; + if (eventDelegate != null) + { + messageEvent.setValues(MessageEventArgs.ERROR, s); + eventDelegate(source, messageEvent); + } + + checkController(); + } + + public virtual void fireReportWarning(string s) + { + MessageEventHandler eventDelegate = (MessageEventHandler) ((Parser) source).Events[Parser.ReportWarningEventKey]; + if (eventDelegate != null) + { + messageEvent.setValues(MessageEventArgs.WARNING, s); + eventDelegate(source, messageEvent); + } + + checkController(); + } + + public virtual bool fireSemanticPredicateEvaluated(int type, int condition, bool result, int guessing) + { + SemanticPredicateEventHandler eventDelegate = (SemanticPredicateEventHandler) ((Parser) source).Events[Parser.SemPredEvaluatedEventKey]; + if (eventDelegate != null) + { + semPredEvent.setValues(type, condition, result, guessing); + eventDelegate(source, semPredEvent); + } + + checkController(); + + return result; + } + + public virtual void fireSyntacticPredicateFailed(int guessing) + { + SyntacticPredicateEventHandler eventDelegate = (SyntacticPredicateEventHandler) ((Parser) source).Events[Parser.SynPredFailedEventKey]; + if (eventDelegate != null) + { + synPredEvent.setValues(0, guessing); + eventDelegate(source, synPredEvent); + } + + checkController(); + } + + public virtual void fireSyntacticPredicateStarted(int guessing) + { + SyntacticPredicateEventHandler eventDelegate = (SyntacticPredicateEventHandler) ((Parser) source).Events[Parser.SynPredStartedEventKey]; + if (eventDelegate != null) + { + synPredEvent.setValues(0, guessing); + eventDelegate(source, synPredEvent); + } + + checkController(); + } + + public virtual void fireSyntacticPredicateSucceeded(int guessing) + { + SyntacticPredicateEventHandler eventDelegate = (SyntacticPredicateEventHandler) ((Parser) source).Events[Parser.SynPredSucceededEventKey]; + if (eventDelegate != null) + { + synPredEvent.setValues(0, guessing); + eventDelegate(source, synPredEvent); + } + + checkController(); + } + + public virtual void refreshListeners() + { + Hashtable clonedTable; + + lock (listeners.SyncRoot) + { + clonedTable = (Hashtable) listeners.Clone(); + } + + foreach (DictionaryEntry entry in clonedTable) + { + if (entry.Value != null) + { + ((Listener) entry.Value).refresh(); + } + } + } + + public virtual void removeDoneListener(Listener l) + { + ((Parser) source).Done -= new TraceEventHandler(l.doneParsing); + listeners.Remove(l); + } + + public virtual void removeMessageListener(MessageListener l) + { + ((Parser) source).ErrorReported -= new MessageEventHandler(l.reportError); + ((Parser) source).WarningReported -= new MessageEventHandler(l.reportWarning); + //messageListeners.Remove(l); + removeDoneListener(l); + } + + public virtual void removeParserListener(ParserListener l) + { + removeParserMatchListener(l); + removeMessageListener(l); + removeParserTokenListener(l); + removeTraceListener(l); + removeSemanticPredicateListener(l); + removeSyntacticPredicateListener(l); + } + + public virtual void removeParserMatchListener(ParserMatchListener l) + { + ((Parser) source).MatchedToken -= new MatchEventHandler(l.parserMatch); + ((Parser) source).MatchedNotToken -= new MatchEventHandler(l.parserMatchNot); + ((Parser) source).MisMatchedToken -= new MatchEventHandler(l.parserMismatch); + ((Parser) source).MisMatchedNotToken -= new MatchEventHandler(l.parserMismatchNot); + //matchListeners.Remove(l); + removeDoneListener(l); + } + + public virtual void removeParserTokenListener(ParserTokenListener l) + { + ((Parser) source).ConsumedToken -= new TokenEventHandler(l.parserConsume); + ((Parser) source).TokenLA -= new TokenEventHandler(l.parserLA); + //tokenListeners.Remove(l); + removeDoneListener(l); + } + + public virtual void removeSemanticPredicateListener(SemanticPredicateListener l) + { + ((Parser) source).SemPredEvaluated -= new SemanticPredicateEventHandler(l.semanticPredicateEvaluated); + //semPredListeners.Remove(l); + removeDoneListener(l); + } + + public virtual void removeSyntacticPredicateListener(SyntacticPredicateListener l) + { + ((Parser) source).SynPredStarted -= new SyntacticPredicateEventHandler(l.syntacticPredicateStarted); + ((Parser) source).SynPredFailed -= new SyntacticPredicateEventHandler(l.syntacticPredicateFailed); + ((Parser) source).SynPredSucceeded -= new SyntacticPredicateEventHandler(l.syntacticPredicateSucceeded); + //synPredListeners.Remove(l); + removeDoneListener(l); + } + + public virtual void removeTraceListener(TraceListener l) + { + ((Parser) source).EnterRule -= new TraceEventHandler(l.enterRule); + ((Parser) source).ExitRule -= new TraceEventHandler(l.exitRule); + //traceListeners.Remove(l); + removeDoneListener(l); + } +} diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/ParserListener.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/ParserListener.cs index b383cba3..aaa5b07b 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/ParserListener.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/ParserListener.cs @@ -1,6 +1,5 @@ -namespace Spring.Expressions.Parser.antlr.debug +namespace Spring.Expressions.Parser.antlr.debug; + +public interface ParserListener : SemanticPredicateListener, ParserMatchListener, MessageListener, ParserTokenListener, TraceListener, SyntacticPredicateListener { - public interface ParserListener : SemanticPredicateListener, ParserMatchListener, MessageListener, ParserTokenListener, TraceListener, SyntacticPredicateListener - { - } -} \ No newline at end of file +} diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/ParserListenerBase.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/ParserListenerBase.cs index 4d7f1394..67a9368c 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/ParserListenerBase.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/ParserListenerBase.cs @@ -1,153 +1,152 @@ -namespace Spring.Expressions.Parser.antlr.debug +namespace Spring.Expressions.Parser.antlr.debug; + +/// +/// Provides an abstract base for implementing subclasses. +/// +/// +/// +/// This abstract class is provided to make it easier to create s. +/// You should extend this base class rather than creating your own. +/// +/// +public class ParserListenerBase : ParserListener { /// - /// Provides an abstract base for implementing subclasses. - /// - /// - /// - /// This abstract class is provided to make it easier to create s. - /// You should extend this base class rather than creating your own. - /// - /// - public class ParserListenerBase : ParserListener - { - /// - /// Handle the "Done" event. - /// - /// Event source object - /// Event data object - public virtual void doneParsing(object source, TraceEventArgs e) - { - } + /// Handle the "Done" event. + /// + /// Event source object + /// Event data object + public virtual void doneParsing(object source, TraceEventArgs e) + { + } - /// - /// Handle the "EnterRule" event - /// - /// Event source object - /// Event data object - public virtual void enterRule(object source, TraceEventArgs e) - { - } + /// + /// Handle the "EnterRule" event + /// + /// Event source object + /// Event data object + public virtual void enterRule(object source, TraceEventArgs e) + { + } - /// - /// Handle the "ExitRule" event - /// - /// Event source object - /// Event data object - public virtual void exitRule(object source, TraceEventArgs e) - { - } + /// + /// Handle the "ExitRule" event + /// + /// Event source object + /// Event data object + public virtual void exitRule(object source, TraceEventArgs e) + { + } - /// - /// Handle the "Consume" event. - /// - /// Event source object - /// Event data object - public virtual void parserConsume(object source, TokenEventArgs e) - { - } + /// + /// Handle the "Consume" event. + /// + /// Event source object + /// Event data object + public virtual void parserConsume(object source, TokenEventArgs e) + { + } - /// - /// Handle the "ParserLA" event. - /// - /// Event source object - /// Event data object - public virtual void parserLA(object source, TokenEventArgs e) - { - } + /// + /// Handle the "ParserLA" event. + /// + /// Event source object + /// Event data object + public virtual void parserLA(object source, TokenEventArgs e) + { + } - /// - /// Handle the "Match" event. - /// - /// Event source object - /// Event data object - public virtual void parserMatch(object source, MatchEventArgs e) - { - } + /// + /// Handle the "Match" event. + /// + /// Event source object + /// Event data object + public virtual void parserMatch(object source, MatchEventArgs e) + { + } - /// - /// Handle the "MatchNot" event. - /// - /// Event source object - /// Event data object - public virtual void parserMatchNot(object source, MatchEventArgs e) - { - } - - /// - /// Handle the "MisMatch" event. - /// - /// Event source object - /// Event data object - public virtual void parserMismatch(object source, MatchEventArgs e) - { - } - - /// - /// Handle the "MisMatchNot" event. - /// - /// Event source object - /// Event data object - public virtual void parserMismatchNot(object source, MatchEventArgs e) - { - } + /// + /// Handle the "MatchNot" event. + /// + /// Event source object + /// Event data object + public virtual void parserMatchNot(object source, MatchEventArgs e) + { + } - /// - /// Handle the "ReportError" event. - /// - /// Event source object - /// Event data object - public virtual void reportError(object source, MessageEventArgs e) - { - } - - /// - /// Handle the "ReportWarning" event. - /// - /// Event source object - /// Event data object - public virtual void reportWarning(object source, MessageEventArgs e) - { - } - - /// - /// Handle the "SemPreEvaluated" event. - /// - /// Event source object - /// Event data object - public virtual void semanticPredicateEvaluated(object source, SemanticPredicateEventArgs e) - { - } + /// + /// Handle the "MisMatch" event. + /// + /// Event source object + /// Event data object + public virtual void parserMismatch(object source, MatchEventArgs e) + { + } - /// - /// Handle the "SynPredFailed" event. - /// - /// Event source object - /// Event data object - public virtual void syntacticPredicateFailed(object source, SyntacticPredicateEventArgs e) - { - } + /// + /// Handle the "MisMatchNot" event. + /// + /// Event source object + /// Event data object + public virtual void parserMismatchNot(object source, MatchEventArgs e) + { + } - /// - /// Handle the "SynPredStarted" event. - /// - /// Event source object - /// Event data object - public virtual void syntacticPredicateStarted(object source, SyntacticPredicateEventArgs e) - { - } - - /// - /// Handle the "SynPredSucceeded" event. - /// - /// Event source object - /// Event data object - public virtual void syntacticPredicateSucceeded(object source, SyntacticPredicateEventArgs e) - { - } + /// + /// Handle the "ReportError" event. + /// + /// Event source object + /// Event data object + public virtual void reportError(object source, MessageEventArgs e) + { + } - public virtual void refresh() - { - } - } -} \ No newline at end of file + /// + /// Handle the "ReportWarning" event. + /// + /// Event source object + /// Event data object + public virtual void reportWarning(object source, MessageEventArgs e) + { + } + + /// + /// Handle the "SemPreEvaluated" event. + /// + /// Event source object + /// Event data object + public virtual void semanticPredicateEvaluated(object source, SemanticPredicateEventArgs e) + { + } + + /// + /// Handle the "SynPredFailed" event. + /// + /// Event source object + /// Event data object + public virtual void syntacticPredicateFailed(object source, SyntacticPredicateEventArgs e) + { + } + + /// + /// Handle the "SynPredStarted" event. + /// + /// Event source object + /// Event data object + public virtual void syntacticPredicateStarted(object source, SyntacticPredicateEventArgs e) + { + } + + /// + /// Handle the "SynPredSucceeded" event. + /// + /// Event source object + /// Event data object + public virtual void syntacticPredicateSucceeded(object source, SyntacticPredicateEventArgs e) + { + } + + public virtual void refresh() + { + } +} diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/ParserMatchEventArgs.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/ParserMatchEventArgs.cs index 98be7693..c7cc46d3 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/ParserMatchEventArgs.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/ParserMatchEventArgs.cs @@ -1,91 +1,93 @@ -namespace Spring.Expressions.Parser.antlr.debug +namespace Spring.Expressions.Parser.antlr.debug; + +public class MatchEventArgs : GuessingEventArgs { - public class MatchEventArgs : GuessingEventArgs - { - public MatchEventArgs() - { - } - public MatchEventArgs(int type, int val, object target, string text, int guessing, bool inverse, bool matched) - { - setValues(type, val, target, text, guessing, inverse, matched); - } + public MatchEventArgs() + { + } - public virtual object Target - { - get { return this.target_; } - set { this.target_ = value; } - } + public MatchEventArgs(int type, int val, object target, string text, int guessing, bool inverse, bool matched) + { + setValues(type, val, target, text, guessing, inverse, matched); + } - public virtual string Text - { - get { return this.text_; } - set { this.text_ = value; } - } + public virtual object Target + { + get { return this.target_; } + set { this.target_ = value; } + } - public virtual int Value - { - get { return this.val_; } - set { this.val_ = value; } - } + public virtual string Text + { + get { return this.text_; } + set { this.text_ = value; } + } - internal bool Inverse - { - set { this.inverse_ = value; } - } + public virtual int Value + { + get { return this.val_; } + set { this.val_ = value; } + } - internal bool Matched - { - set { this.matched_ = value; } - } + internal bool Inverse + { + set { this.inverse_ = value; } + } - // NOTE: for a mismatch on type STRING, the "text" is used as the lookahead - // value. Normally "value" is this - public enum ParserMatchEnums - { - TOKEN = 0, - BITSET = 1, - CHAR = 2, - CHAR_BITSET = 3, - STRING = 4, - CHAR_RANGE = 5, - } - public static int TOKEN = 0; - public static int BITSET = 1; - public static int CHAR = 2; - public static int CHAR_BITSET = 3; - public static int STRING = 4; - public static int CHAR_RANGE = 5; + internal bool Matched + { + set { this.matched_ = value; } + } - private bool inverse_; - private bool matched_; - private object target_; - private int val_; - private string text_; - - - public virtual bool isInverse() - { - return inverse_; - } - public virtual bool isMatched() - { - return matched_; - } - /// This should NOT be called from anyone other than ParserEventSupport! - /// - internal void setValues(int type, int val, object target, string text, int guessing, bool inverse, bool matched) - { - base.setValues(type, guessing); - this.Value = val; - this.Target = target; - this.Inverse = inverse; - this.Matched = matched; - this.Text = text; - } - - public override string ToString() - { - return "ParserMatchEvent [" + (isMatched()?"ok,":"bad,") + (isInverse()?"NOT ":"") + (Type == TOKEN?"token,":"bitset,") + Value + "," + Target + "," + Guessing + "]"; - } - } -} \ No newline at end of file + // NOTE: for a mismatch on type STRING, the "text" is used as the lookahead + // value. Normally "value" is this + public enum ParserMatchEnums + { + TOKEN = 0, + BITSET = 1, + CHAR = 2, + CHAR_BITSET = 3, + STRING = 4, + CHAR_RANGE = 5, + } + + public static int TOKEN = 0; + public static int BITSET = 1; + public static int CHAR = 2; + public static int CHAR_BITSET = 3; + public static int STRING = 4; + public static int CHAR_RANGE = 5; + + private bool inverse_; + private bool matched_; + private object target_; + private int val_; + private string text_; + + public virtual bool isInverse() + { + return inverse_; + } + + public virtual bool isMatched() + { + return matched_; + } + + /// This should NOT be called from anyone other than ParserEventSupport! + /// + internal void setValues(int type, int val, object target, string text, int guessing, bool inverse, bool matched) + { + base.setValues(type, guessing); + this.Value = val; + this.Target = target; + this.Inverse = inverse; + this.Matched = matched; + this.Text = text; + } + + public override string ToString() + { + return "ParserMatchEvent [" + (isMatched() ? "ok," : "bad,") + (isInverse() ? "NOT " : "") + (Type == TOKEN ? "token," : "bitset,") + Value + "," + Target + "," + Guessing + "]"; + } +} diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/ParserMatchListener.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/ParserMatchListener.cs index b2eb584d..ebfcf6e5 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/ParserMatchListener.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/ParserMatchListener.cs @@ -1,10 +1,9 @@ -namespace Spring.Expressions.Parser.antlr.debug +namespace Spring.Expressions.Parser.antlr.debug; + +public interface ParserMatchListener : Listener { - public interface ParserMatchListener : Listener - { - void parserMatch (object source, MatchEventArgs e); - void parserMatchNot (object source, MatchEventArgs e); - void parserMismatch (object source, MatchEventArgs e); - void parserMismatchNot (object source, MatchEventArgs e); - } -} \ No newline at end of file + void parserMatch(object source, MatchEventArgs e); + void parserMatchNot(object source, MatchEventArgs e); + void parserMismatch(object source, MatchEventArgs e); + void parserMismatchNot(object source, MatchEventArgs e); +} diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/ParserMatchListenerBase.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/ParserMatchListenerBase.cs index 4fe44f7e..5569e5c3 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/ParserMatchListenerBase.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/ParserMatchListenerBase.cs @@ -1,63 +1,62 @@ -namespace Spring.Expressions.Parser.antlr.debug +namespace Spring.Expressions.Parser.antlr.debug; + +/// +/// Provides an abstract base for implementing subclasses. +/// +/// +/// +/// This abstract class is provided to make it easier to create s. +/// You should extend this base class rather than creating your own. +/// +/// +public abstract class ParserMatchListenerBase : ParserMatchListener { /// - /// Provides an abstract base for implementing subclasses. - /// - /// - /// - /// This abstract class is provided to make it easier to create s. - /// You should extend this base class rather than creating your own. - /// - /// - public abstract class ParserMatchListenerBase : ParserMatchListener - { - /// - /// Handle the "Done" event. - /// - /// Event source object - /// Event data object - public virtual void doneParsing(object source, TraceEventArgs e) - { - } + /// Handle the "Done" event. + /// + /// Event source object + /// Event data object + public virtual void doneParsing(object source, TraceEventArgs e) + { + } - /// - /// Handle the "Match" event. - /// - /// Event source object - /// Event data object - public virtual void parserMatch(object source, MatchEventArgs e) - { - } + /// + /// Handle the "Match" event. + /// + /// Event source object + /// Event data object + public virtual void parserMatch(object source, MatchEventArgs e) + { + } - /// - /// Handle the "MatchNot" event. - /// - /// Event source object - /// Event data object - public virtual void parserMatchNot(object source, MatchEventArgs e) - { - } - - /// - /// Handle the "MisMatch" event. - /// - /// Event source object - /// Event data object - public virtual void parserMismatch(object source, MatchEventArgs e) - { - } - - /// - /// Handle the "MisMatchNot" event. - /// - /// Event source object - /// Event data object - public virtual void parserMismatchNot(object source, MatchEventArgs e) - { - } + /// + /// Handle the "MatchNot" event. + /// + /// Event source object + /// Event data object + public virtual void parserMatchNot(object source, MatchEventArgs e) + { + } - public virtual void refresh() - { - } - } -} \ No newline at end of file + /// + /// Handle the "MisMatch" event. + /// + /// Event source object + /// Event data object + public virtual void parserMismatch(object source, MatchEventArgs e) + { + } + + /// + /// Handle the "MisMatchNot" event. + /// + /// Event source object + /// Event data object + public virtual void parserMismatchNot(object source, MatchEventArgs e) + { + } + + public virtual void refresh() + { + } +} diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/ParserReporter.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/ParserReporter.cs index 3ded8d03..1296f8c6 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/ParserReporter.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/ParserReporter.cs @@ -1,54 +1,64 @@ -namespace Spring.Expressions.Parser.antlr.debug +namespace Spring.Expressions.Parser.antlr.debug; + +public class ParserReporter : Tracer, ParserListener { - public class ParserReporter : Tracer, ParserListener - { - public virtual void parserConsume(object source, TokenEventArgs e) - { - System.Console.Out.WriteLine(indentString + e); - } - public virtual void parserLA(object source, TokenEventArgs e) - { - System.Console.Out.WriteLine(indentString + e); - } - public virtual void parserMatch(object source, MatchEventArgs e) - { - System.Console.Out.WriteLine(indentString + e); - } - public virtual void parserMatchNot(object source, MatchEventArgs e) - { - System.Console.Out.WriteLine(indentString + e); - } - public virtual void parserMismatch(object source, MatchEventArgs e) - { - System.Console.Out.WriteLine(indentString + e); - } - public virtual void parserMismatchNot(object source, MatchEventArgs e) - { - System.Console.Out.WriteLine(indentString + e); - } - public virtual void reportError(object source, MessageEventArgs e) - { - System.Console.Out.WriteLine(indentString + e); - } - public virtual void reportWarning(object source, MessageEventArgs e) - { - System.Console.Out.WriteLine(indentString + e); - } - public virtual void semanticPredicateEvaluated(object source, SemanticPredicateEventArgs e) - { - System.Console.Out.WriteLine(indentString + e); - } - public virtual void syntacticPredicateFailed(object source, SyntacticPredicateEventArgs e) - { - System.Console.Out.WriteLine(indentString + e); - } - public virtual void syntacticPredicateStarted(object source, SyntacticPredicateEventArgs e) - { - System.Console.Out.WriteLine(indentString + e); - } - public virtual void syntacticPredicateSucceeded(object source, SyntacticPredicateEventArgs e) - { - System.Console.Out.WriteLine(indentString + e); - } - } -} \ No newline at end of file + public virtual void parserConsume(object source, TokenEventArgs e) + { + System.Console.Out.WriteLine(indentString + e); + } + + public virtual void parserLA(object source, TokenEventArgs e) + { + System.Console.Out.WriteLine(indentString + e); + } + + public virtual void parserMatch(object source, MatchEventArgs e) + { + System.Console.Out.WriteLine(indentString + e); + } + + public virtual void parserMatchNot(object source, MatchEventArgs e) + { + System.Console.Out.WriteLine(indentString + e); + } + + public virtual void parserMismatch(object source, MatchEventArgs e) + { + System.Console.Out.WriteLine(indentString + e); + } + + public virtual void parserMismatchNot(object source, MatchEventArgs e) + { + System.Console.Out.WriteLine(indentString + e); + } + + public virtual void reportError(object source, MessageEventArgs e) + { + System.Console.Out.WriteLine(indentString + e); + } + + public virtual void reportWarning(object source, MessageEventArgs e) + { + System.Console.Out.WriteLine(indentString + e); + } + + public virtual void semanticPredicateEvaluated(object source, SemanticPredicateEventArgs e) + { + System.Console.Out.WriteLine(indentString + e); + } + + public virtual void syntacticPredicateFailed(object source, SyntacticPredicateEventArgs e) + { + System.Console.Out.WriteLine(indentString + e); + } + + public virtual void syntacticPredicateStarted(object source, SyntacticPredicateEventArgs e) + { + System.Console.Out.WriteLine(indentString + e); + } + + public virtual void syntacticPredicateSucceeded(object source, SyntacticPredicateEventArgs e) + { + System.Console.Out.WriteLine(indentString + e); + } +} diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/ParserTokenEventArgs.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/ParserTokenEventArgs.cs index 178ddeda..64dbe7ec 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/ParserTokenEventArgs.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/ParserTokenEventArgs.cs @@ -1,49 +1,48 @@ -namespace Spring.Expressions.Parser.antlr.debug +namespace Spring.Expressions.Parser.antlr.debug; + +public class TokenEventArgs : ANTLREventArgs { - public class TokenEventArgs : ANTLREventArgs - { - public TokenEventArgs() - { - } - public TokenEventArgs(int type, int amount, int val) - { - setValues(type, amount, val); - } + public TokenEventArgs() + { + } - public virtual int Amount - { - get { return amount; } - set { this.amount = value; } - } + public TokenEventArgs(int type, int amount, int val) + { + setValues(type, amount, val); + } - public virtual int Value - { - get { return this.value_; } - set { this.value_ = value; } - } + public virtual int Amount + { + get { return amount; } + set { this.amount = value; } + } - private int value_; - private int amount; + public virtual int Value + { + get { return this.value_; } + set { this.value_ = value; } + } - public static int LA = 0; - public static int CONSUME = 1; - - - /// This should NOT be called from anyone other than ParserEventSupport! - /// - internal void setValues(int type, int amount, int val) - { - base.setValues(type); - this.Amount = amount; - this.Value = val; - } + private int value_; + private int amount; - public override string ToString() - { - if (Type == LA) - return "ParserTokenEvent [LA," + Amount + "," + Value + "]"; - else - return "ParserTokenEvent [consume,1," + Value + "]"; - } - } -} \ No newline at end of file + public static int LA = 0; + public static int CONSUME = 1; + + /// This should NOT be called from anyone other than ParserEventSupport! + /// + internal void setValues(int type, int amount, int val) + { + base.setValues(type); + this.Amount = amount; + this.Value = val; + } + + public override string ToString() + { + if (Type == LA) + return "ParserTokenEvent [LA," + Amount + "," + Value + "]"; + else + return "ParserTokenEvent [consume,1," + Value + "]"; + } +} diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/ParserTokenListener.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/ParserTokenListener.cs index 9c0bcd18..70e42403 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/ParserTokenListener.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/ParserTokenListener.cs @@ -1,8 +1,7 @@ -namespace Spring.Expressions.Parser.antlr.debug +namespace Spring.Expressions.Parser.antlr.debug; + +public interface ParserTokenListener : Listener { - public interface ParserTokenListener : Listener - { - void parserConsume (object source, TokenEventArgs e); - void parserLA (object source, TokenEventArgs e); - } -} \ No newline at end of file + void parserConsume(object source, TokenEventArgs e); + void parserLA(object source, TokenEventArgs e); +} diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/ParserTokenListenerBase.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/ParserTokenListenerBase.cs index bedc4e58..3eb8f511 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/ParserTokenListenerBase.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/ParserTokenListenerBase.cs @@ -1,45 +1,44 @@ -namespace Spring.Expressions.Parser.antlr.debug +namespace Spring.Expressions.Parser.antlr.debug; + +/// +/// Provides an abstract base for implementing subclasses. +/// +/// +/// +/// This abstract class is provided to make it easier to create s. +/// You should extend this base class rather than creating your own. +/// +/// +public abstract class ParserTokenListenerBase : ParserTokenListener { /// - /// Provides an abstract base for implementing subclasses. - /// - /// - /// - /// This abstract class is provided to make it easier to create s. - /// You should extend this base class rather than creating your own. - /// - /// - public abstract class ParserTokenListenerBase : ParserTokenListener - { - /// - /// Handle the "Done" event. - /// - /// Event source object - /// Event data object - public virtual void doneParsing(object source, TraceEventArgs e) - { - } + /// Handle the "Done" event. + /// + /// Event source object + /// Event data object + public virtual void doneParsing(object source, TraceEventArgs e) + { + } - public virtual void refresh() - { - } + public virtual void refresh() + { + } - /// - /// Handle the "Consume" event. - /// - /// Event source object - /// Event data object - public virtual void parserConsume(object source, TokenEventArgs e) - { - } + /// + /// Handle the "Consume" event. + /// + /// Event source object + /// Event data object + public virtual void parserConsume(object source, TokenEventArgs e) + { + } - /// - /// Handle the "ParserLA" event. - /// - /// Event source object - /// Event data object - public virtual void parserLA(object source, TokenEventArgs e) - { - } - } -} \ No newline at end of file + /// + /// Handle the "ParserLA" event. + /// + /// Event source object + /// Event data object + public virtual void parserLA(object source, TokenEventArgs e) + { + } +} diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/ScannerEventSupport.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/ScannerEventSupport.cs index da8cc0a2..3d647607 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/ScannerEventSupport.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/ScannerEventSupport.cs @@ -1,481 +1,554 @@ -namespace Spring.Expressions.Parser.antlr.debug +namespace Spring.Expressions.Parser.antlr.debug; + +using Hashtable = System.Collections.Hashtable; +using antlr.collections.impl; + +/// A class to assist in firing parser events +/// NOTE: I intentionally _did_not_ synchronize the event firing and +/// add/remove listener methods. This is because the add/remove should +/// _only_ be called by the parser at its start/end, and the _same_thread_ +/// should be performing the parsing. This should help performance a tad... +/// +public class ScannerEventSupport { - using Hashtable = System.Collections.Hashtable; + private object source; + private Hashtable listeners; + private MatchEventArgs matchEvent; + private MessageEventArgs messageEvent; + private TokenEventArgs tokenEvent; + private SemanticPredicateEventArgs semPredEvent; + private SyntacticPredicateEventArgs synPredEvent; + private TraceEventArgs traceEvent; + private NewLineEventArgs newLineEvent; + //private ParserController controller; - using antlr.collections.impl; - - - /// A class to assist in firing parser events - /// NOTE: I intentionally _did_not_ synchronize the event firing and - /// add/remove listener methods. This is because the add/remove should - /// _only_ be called by the parser at its start/end, and the _same_thread_ - /// should be performing the parsing. This should help performance a tad... - /// - public class ScannerEventSupport - { - private object source; - private Hashtable listeners; - private MatchEventArgs matchEvent; - private MessageEventArgs messageEvent; - private TokenEventArgs tokenEvent; - private SemanticPredicateEventArgs semPredEvent; - private SyntacticPredicateEventArgs synPredEvent; - private TraceEventArgs traceEvent; - private NewLineEventArgs newLineEvent; - //private ParserController controller; + private int ruleDepth = 0; - private int ruleDepth = 0; - - - public ScannerEventSupport(object source) - { - matchEvent = new MatchEventArgs(); - messageEvent = new MessageEventArgs(); - tokenEvent = new TokenEventArgs(); - traceEvent = new TraceEventArgs(); - semPredEvent = new SemanticPredicateEventArgs(); - synPredEvent = new SyntacticPredicateEventArgs(); - newLineEvent = new NewLineEventArgs(); - listeners = new Hashtable(); - this.source = source; - } + public ScannerEventSupport(object source) + { + matchEvent = new MatchEventArgs(); + messageEvent = new MessageEventArgs(); + tokenEvent = new TokenEventArgs(); + traceEvent = new TraceEventArgs(); + semPredEvent = new SemanticPredicateEventArgs(); + synPredEvent = new SyntacticPredicateEventArgs(); + newLineEvent = new NewLineEventArgs(); + listeners = new Hashtable(); + this.source = source; + } - public virtual void checkController() - { - //if (controller != null) - // controller.checkBreak(); - } + public virtual void checkController() + { + //if (controller != null) + // controller.checkBreak(); + } - public virtual void addDoneListener(Listener l) - { - ((CharScanner)source).Done += new TraceEventHandler(l.doneParsing); - listeners[l] = l; - } - public virtual void addMessageListener(MessageListener l) - { - ((CharScanner)source).ErrorReported += new MessageEventHandler(l.reportError); - ((CharScanner)source).WarningReported += new MessageEventHandler(l.reportWarning); - addDoneListener(l); - } - public virtual void addNewLineListener(NewLineListener l) - { - ((CharScanner)source).HitNewLine += new NewLineEventHandler(l.hitNewLine); - addDoneListener(l); - } - public virtual void addParserListener(ParserListener l) - { - if (l is ParserController) - { - //((ParserController) l).ParserEventSupport = this; - //controller = (ParserController) l; - } - addParserMatchListener(l); - addParserTokenListener(l); - - addMessageListener(l); - addTraceListener(l); - addSemanticPredicateListener(l); - addSyntacticPredicateListener(l); - } - public virtual void addParserMatchListener(ParserMatchListener l) - { - ((CharScanner)source).MatchedChar += new MatchEventHandler(l.parserMatch); - ((CharScanner)source).MatchedNotChar += new MatchEventHandler(l.parserMatchNot); - ((CharScanner)source).MisMatchedChar += new MatchEventHandler(l.parserMismatch); - ((CharScanner)source).MisMatchedNotChar += new MatchEventHandler(l.parserMismatchNot); - addDoneListener(l); - } - public virtual void addParserTokenListener(ParserTokenListener l) - { - ((CharScanner)source).ConsumedChar += new TokenEventHandler(l.parserConsume); - ((CharScanner)source).CharLA += new TokenEventHandler(l.parserLA); - addDoneListener(l); - } - public virtual void addSemanticPredicateListener(SemanticPredicateListener l) - { - ((CharScanner)source).SemPredEvaluated += new SemanticPredicateEventHandler(l.semanticPredicateEvaluated); - addDoneListener(l); - } - public virtual void addSyntacticPredicateListener(SyntacticPredicateListener l) - { - ((CharScanner)source).SynPredStarted += new SyntacticPredicateEventHandler(l.syntacticPredicateStarted); - ((CharScanner)source).SynPredFailed += new SyntacticPredicateEventHandler(l.syntacticPredicateFailed); - ((CharScanner)source).SynPredSucceeded += new SyntacticPredicateEventHandler(l.syntacticPredicateSucceeded); - addDoneListener(l); - } - public virtual void addTraceListener(TraceListener l) - { - ((CharScanner)source).EnterRule += new TraceEventHandler(l.enterRule); - ((CharScanner)source).ExitRule += new TraceEventHandler(l.exitRule); - addDoneListener(l); - } - public virtual void fireConsume(int c) - { - TokenEventHandler eventDelegate = (TokenEventHandler)((CharScanner)source).Events[Parser.LAEventKey]; - if (eventDelegate != null) - { - tokenEvent.setValues(TokenEventArgs.CONSUME, 1, c); - eventDelegate(source, tokenEvent); - } - checkController(); - } - public virtual void fireDoneParsing() - { - TraceEventHandler eventDelegate = (TraceEventHandler)((CharScanner)source).Events[Parser.DoneEventKey]; - if (eventDelegate != null) - { - traceEvent.setValues(TraceEventArgs.DONE_PARSING, 0, 0, 0); - eventDelegate(source, traceEvent); - } - checkController(); - } - public virtual void fireEnterRule(int ruleNum, int guessing, int data) - { - ruleDepth++; - TraceEventHandler eventDelegate = (TraceEventHandler)((CharScanner)source).Events[Parser.EnterRuleEventKey]; - if (eventDelegate != null) - { - traceEvent.setValues(TraceEventArgs.ENTER, ruleNum, guessing, data); - eventDelegate(source, traceEvent); - } - checkController(); - } - public virtual void fireExitRule(int ruleNum, int guessing, int data) - { - TraceEventHandler eventDelegate = (TraceEventHandler)((CharScanner)source).Events[Parser.ExitRuleEventKey]; - if (eventDelegate != null) - { - traceEvent.setValues(TraceEventArgs.EXIT, ruleNum, guessing, data); - eventDelegate(source, traceEvent); - } - checkController(); + public virtual void addDoneListener(Listener l) + { + ((CharScanner) source).Done += new TraceEventHandler(l.doneParsing); + listeners[l] = l; + } - ruleDepth--; - if (ruleDepth == 0) - fireDoneParsing(); + public virtual void addMessageListener(MessageListener l) + { + ((CharScanner) source).ErrorReported += new MessageEventHandler(l.reportError); + ((CharScanner) source).WarningReported += new MessageEventHandler(l.reportWarning); + addDoneListener(l); + } - } - public virtual void fireLA(int k, int la) - { - TokenEventHandler eventDelegate = (TokenEventHandler)((CharScanner)source).Events[Parser.LAEventKey]; - if (eventDelegate != null) - { - tokenEvent.setValues(TokenEventArgs.LA, k, la); - eventDelegate(source, tokenEvent); - } - checkController(); - } - public virtual void fireMatch(char c, int guessing) - { - MatchEventHandler eventDelegate = (MatchEventHandler)((CharScanner)source).Events[Parser.MatchEventKey]; - if (eventDelegate != null) - { - matchEvent.setValues(MatchEventArgs.CHAR, c, c, null, guessing, false, true); - eventDelegate(source, matchEvent); - } - checkController(); - } - public virtual void fireMatch(char c, BitSet b, int guessing) - { - MatchEventHandler eventDelegate = (MatchEventHandler)((CharScanner)source).Events[Parser.MatchEventKey]; - if (eventDelegate != null) - { - matchEvent.setValues(MatchEventArgs.CHAR_BITSET, c, b, null, guessing, false, true); - eventDelegate(source, matchEvent); - } - checkController(); - } - public virtual void fireMatch(char c, string target, int guessing) - { - MatchEventHandler eventDelegate = (MatchEventHandler)((CharScanner)source).Events[Parser.MatchEventKey]; - if (eventDelegate != null) - { - matchEvent.setValues(MatchEventArgs.CHAR_RANGE, c, target, null, guessing, false, true); - eventDelegate(source, matchEvent); - } - checkController(); - } - public virtual void fireMatch(int c, BitSet b, string text, int guessing) - { - MatchEventHandler eventDelegate = (MatchEventHandler)((CharScanner)source).Events[Parser.MatchEventKey]; - if (eventDelegate != null) - { - matchEvent.setValues(MatchEventArgs.BITSET, c, b, text, guessing, false, true); - eventDelegate(source, matchEvent); - } - checkController(); - } - public virtual void fireMatch(int n, string text, int guessing) - { - MatchEventHandler eventDelegate = (MatchEventHandler)((CharScanner)source).Events[Parser.MatchEventKey]; - if (eventDelegate != null) - { - matchEvent.setValues(MatchEventArgs.TOKEN, n, n, text, guessing, false, true); - eventDelegate(source, matchEvent); - } - checkController(); - } - public virtual void fireMatch(string s, int guessing) - { - MatchEventHandler eventDelegate = (MatchEventHandler)((CharScanner)source).Events[Parser.MatchEventKey]; - if (eventDelegate != null) - { - matchEvent.setValues(MatchEventArgs.STRING, 0, s, null, guessing, false, true); - eventDelegate(source, matchEvent); - } - checkController(); - } - public virtual void fireMatchNot(char c, char n, int guessing) - { - MatchEventHandler eventDelegate = (MatchEventHandler)((CharScanner)source).Events[Parser.MatchNotEventKey]; - if (eventDelegate != null) - { - matchEvent.setValues(MatchEventArgs.CHAR, c, n, null, guessing, true, true); - eventDelegate(source, matchEvent); - } - checkController(); - } - public virtual void fireMatchNot(int c, int n, string text, int guessing) - { - MatchEventHandler eventDelegate = (MatchEventHandler)((CharScanner)source).Events[Parser.MatchNotEventKey]; - if (eventDelegate != null) - { - matchEvent.setValues(MatchEventArgs.TOKEN, c, n, text, guessing, true, true); - eventDelegate(source, matchEvent); - } - checkController(); - } - public virtual void fireMismatch(char c, char n, int guessing) - { - MatchEventHandler eventDelegate = (MatchEventHandler)((CharScanner)source).Events[Parser.MisMatchEventKey]; - if (eventDelegate != null) - { - matchEvent.setValues(MatchEventArgs.CHAR, c, n, null, guessing, false, false); - eventDelegate(source, matchEvent); - } - checkController(); - } - public virtual void fireMismatch(char c, BitSet b, int guessing) - { - MatchEventHandler eventDelegate = (MatchEventHandler)((CharScanner)source).Events[Parser.MisMatchEventKey]; - if (eventDelegate != null) - { - matchEvent.setValues(MatchEventArgs.CHAR_BITSET, c, b, null, guessing, false, true); - eventDelegate(source, matchEvent); - } - checkController(); - } - public virtual void fireMismatch(char c, string target, int guessing) - { - MatchEventHandler eventDelegate = (MatchEventHandler)((CharScanner)source).Events[Parser.MisMatchEventKey]; - if (eventDelegate != null) - { - matchEvent.setValues(MatchEventArgs.CHAR_RANGE, c, target, null, guessing, false, true); - eventDelegate(source, matchEvent); - } - checkController(); - } - public virtual void fireMismatch(int i, int n, string text, int guessing) - { - MatchEventHandler eventDelegate = (MatchEventHandler)((CharScanner)source).Events[Parser.MisMatchEventKey]; - if (eventDelegate != null) - { - matchEvent.setValues(MatchEventArgs.TOKEN, i, n, text, guessing, false, false); - eventDelegate(source, matchEvent); - } - checkController(); - } - public virtual void fireMismatch(int i, BitSet b, string text, int guessing) - { - MatchEventHandler eventDelegate = (MatchEventHandler)((CharScanner)source).Events[Parser.MisMatchEventKey]; - if (eventDelegate != null) - { - matchEvent.setValues(MatchEventArgs.BITSET, i, b, text, guessing, false, true); - eventDelegate(source, matchEvent); - } - checkController(); - } - public virtual void fireMismatch(string s, string text, int guessing) - { - MatchEventHandler eventDelegate = (MatchEventHandler)((CharScanner)source).Events[Parser.MisMatchEventKey]; - if (eventDelegate != null) - { - matchEvent.setValues(MatchEventArgs.STRING, 0, text, s, guessing, false, true); - eventDelegate(source, matchEvent); - } - checkController(); - } - public virtual void fireMismatchNot(char v, char c, int guessing) - { - MatchEventHandler eventDelegate = (MatchEventHandler)((CharScanner)source).Events[Parser.MisMatchNotEventKey]; - if (eventDelegate != null) - { - matchEvent.setValues(MatchEventArgs.CHAR, v, c, null, guessing, true, true); - eventDelegate(source, matchEvent); - } - checkController(); - } - public virtual void fireMismatchNot(int i, int n, string text, int guessing) - { - MatchEventHandler eventDelegate = (MatchEventHandler)((CharScanner)source).Events[Parser.MisMatchNotEventKey]; - if (eventDelegate != null) - { - matchEvent.setValues(MatchEventArgs.TOKEN, i, n, text, guessing, true, true); - eventDelegate(source, matchEvent); - } - checkController(); - } - public virtual void fireNewLine(int line) - { - NewLineEventHandler eventDelegate = (NewLineEventHandler)((CharScanner)source).Events[Parser.NewLineEventKey]; - if (eventDelegate != null) - { - newLineEvent.Line = line; - eventDelegate(source, newLineEvent); - } - checkController(); - } - public virtual void fireReportError(System.Exception e) - { - MessageEventHandler eventDelegate = (MessageEventHandler)((CharScanner)source).Events[Parser.ReportErrorEventKey]; - if (eventDelegate != null) - { - messageEvent.setValues(MessageEventArgs.ERROR, e.ToString()); - eventDelegate(source, messageEvent); - } - checkController(); - } - public virtual void fireReportError(string s) - { - MessageEventHandler eventDelegate = (MessageEventHandler)((CharScanner)source).Events[Parser.ReportErrorEventKey]; - if (eventDelegate != null) - { - messageEvent.setValues(MessageEventArgs.ERROR, s); - eventDelegate(source, messageEvent); - } - checkController(); - } - public virtual void fireReportWarning(string s) - { - MessageEventHandler eventDelegate = (MessageEventHandler)((CharScanner)source).Events[Parser.ReportWarningEventKey]; - if (eventDelegate != null) - { - messageEvent.setValues(MessageEventArgs.WARNING, s); - eventDelegate(source, messageEvent); - } - checkController(); - } - public virtual bool fireSemanticPredicateEvaluated(int type, int condition, bool result, int guessing) - { - SemanticPredicateEventHandler eventDelegate = (SemanticPredicateEventHandler)((CharScanner)source).Events[Parser.SemPredEvaluatedEventKey]; - if (eventDelegate != null) - { - semPredEvent.setValues(type, condition, result, guessing); - eventDelegate(source, semPredEvent); - } - checkController(); + public virtual void addNewLineListener(NewLineListener l) + { + ((CharScanner) source).HitNewLine += new NewLineEventHandler(l.hitNewLine); + addDoneListener(l); + } - return result; - } - public virtual void fireSyntacticPredicateFailed(int guessing) - { - SyntacticPredicateEventHandler eventDelegate = (SyntacticPredicateEventHandler)((CharScanner)source).Events[Parser.SynPredFailedEventKey]; - if (eventDelegate != null) - { - synPredEvent.setValues(0, guessing); - eventDelegate(source, synPredEvent); - } - checkController(); - } - public virtual void fireSyntacticPredicateStarted(int guessing) - { - SyntacticPredicateEventHandler eventDelegate = (SyntacticPredicateEventHandler)((CharScanner)source).Events[Parser.SynPredStartedEventKey]; - if (eventDelegate != null) - { - synPredEvent.setValues(0, guessing); - eventDelegate(source, synPredEvent); - } - checkController(); - } - public virtual void fireSyntacticPredicateSucceeded(int guessing) - { - SyntacticPredicateEventHandler eventDelegate = (SyntacticPredicateEventHandler)((CharScanner)source).Events[Parser.SynPredSucceededEventKey]; - if (eventDelegate != null) - { - synPredEvent.setValues(0, guessing); - eventDelegate(source, synPredEvent); - } - checkController(); - } - public virtual void refreshListeners() - { - Hashtable clonedTable; + public virtual void addParserListener(ParserListener l) + { + if (l is ParserController) + { + //((ParserController) l).ParserEventSupport = this; + //controller = (ParserController) l; + } - lock(listeners.SyncRoot) - { - clonedTable = (Hashtable)listeners.Clone(); - } - foreach (Listener l in clonedTable) - { - l.refresh(); - } - } - public virtual void removeDoneListener(Listener l) - { - ((CharScanner)source).Done -= new TraceEventHandler(l.doneParsing); - listeners.Remove(l); - } - public virtual void removeMessageListener(MessageListener l) - { - ((CharScanner)source).ErrorReported -= new MessageEventHandler(l.reportError); - ((CharScanner)source).WarningReported -= new MessageEventHandler(l.reportWarning); - removeDoneListener(l); - } - public virtual void removeNewLineListener(NewLineListener l) - { - ((CharScanner)source).HitNewLine -= new NewLineEventHandler(l.hitNewLine); - removeDoneListener(l); - } - public virtual void removeParserListener(ParserListener l) - { - removeParserMatchListener(l); - removeMessageListener(l); - removeParserTokenListener(l); - removeTraceListener(l); - removeSemanticPredicateListener(l); - removeSyntacticPredicateListener(l); - } - public virtual void removeParserMatchListener(ParserMatchListener l) - { - ((CharScanner)source).MatchedChar -= new MatchEventHandler(l.parserMatch); - ((CharScanner)source).MatchedNotChar -= new MatchEventHandler(l.parserMatchNot); - ((CharScanner)source).MisMatchedChar -= new MatchEventHandler(l.parserMismatch); - ((CharScanner)source).MisMatchedNotChar -= new MatchEventHandler(l.parserMismatchNot); - removeDoneListener(l); - } - public virtual void removeParserTokenListener(ParserTokenListener l) - { - ((CharScanner)source).ConsumedChar -= new TokenEventHandler(l.parserConsume); - ((CharScanner)source).CharLA -= new TokenEventHandler(l.parserLA); - removeDoneListener(l); - } - public virtual void removeSemanticPredicateListener(SemanticPredicateListener l) - { - ((CharScanner)source).SemPredEvaluated -= new SemanticPredicateEventHandler(l.semanticPredicateEvaluated); - removeDoneListener(l); - } - public virtual void removeSyntacticPredicateListener(SyntacticPredicateListener l) - { - ((CharScanner)source).SynPredStarted -= new SyntacticPredicateEventHandler(l.syntacticPredicateStarted); - ((CharScanner)source).SynPredFailed -= new SyntacticPredicateEventHandler(l.syntacticPredicateFailed); - ((CharScanner)source).SynPredSucceeded -= new SyntacticPredicateEventHandler(l.syntacticPredicateSucceeded); - removeDoneListener(l); - } - public virtual void removeTraceListener(TraceListener l) - { - ((CharScanner)source).EnterRule -= new TraceEventHandler(l.enterRule); - ((CharScanner)source).ExitRule -= new TraceEventHandler(l.exitRule); - removeDoneListener(l); - } - } + addParserMatchListener(l); + addParserTokenListener(l); + + addMessageListener(l); + addTraceListener(l); + addSemanticPredicateListener(l); + addSyntacticPredicateListener(l); + } + + public virtual void addParserMatchListener(ParserMatchListener l) + { + ((CharScanner) source).MatchedChar += new MatchEventHandler(l.parserMatch); + ((CharScanner) source).MatchedNotChar += new MatchEventHandler(l.parserMatchNot); + ((CharScanner) source).MisMatchedChar += new MatchEventHandler(l.parserMismatch); + ((CharScanner) source).MisMatchedNotChar += new MatchEventHandler(l.parserMismatchNot); + addDoneListener(l); + } + + public virtual void addParserTokenListener(ParserTokenListener l) + { + ((CharScanner) source).ConsumedChar += new TokenEventHandler(l.parserConsume); + ((CharScanner) source).CharLA += new TokenEventHandler(l.parserLA); + addDoneListener(l); + } + + public virtual void addSemanticPredicateListener(SemanticPredicateListener l) + { + ((CharScanner) source).SemPredEvaluated += new SemanticPredicateEventHandler(l.semanticPredicateEvaluated); + addDoneListener(l); + } + + public virtual void addSyntacticPredicateListener(SyntacticPredicateListener l) + { + ((CharScanner) source).SynPredStarted += new SyntacticPredicateEventHandler(l.syntacticPredicateStarted); + ((CharScanner) source).SynPredFailed += new SyntacticPredicateEventHandler(l.syntacticPredicateFailed); + ((CharScanner) source).SynPredSucceeded += new SyntacticPredicateEventHandler(l.syntacticPredicateSucceeded); + addDoneListener(l); + } + + public virtual void addTraceListener(TraceListener l) + { + ((CharScanner) source).EnterRule += new TraceEventHandler(l.enterRule); + ((CharScanner) source).ExitRule += new TraceEventHandler(l.exitRule); + addDoneListener(l); + } + + public virtual void fireConsume(int c) + { + TokenEventHandler eventDelegate = (TokenEventHandler) ((CharScanner) source).Events[Parser.LAEventKey]; + if (eventDelegate != null) + { + tokenEvent.setValues(TokenEventArgs.CONSUME, 1, c); + eventDelegate(source, tokenEvent); + } + + checkController(); + } + + public virtual void fireDoneParsing() + { + TraceEventHandler eventDelegate = (TraceEventHandler) ((CharScanner) source).Events[Parser.DoneEventKey]; + if (eventDelegate != null) + { + traceEvent.setValues(TraceEventArgs.DONE_PARSING, 0, 0, 0); + eventDelegate(source, traceEvent); + } + + checkController(); + } + + public virtual void fireEnterRule(int ruleNum, int guessing, int data) + { + ruleDepth++; + TraceEventHandler eventDelegate = (TraceEventHandler) ((CharScanner) source).Events[Parser.EnterRuleEventKey]; + if (eventDelegate != null) + { + traceEvent.setValues(TraceEventArgs.ENTER, ruleNum, guessing, data); + eventDelegate(source, traceEvent); + } + + checkController(); + } + + public virtual void fireExitRule(int ruleNum, int guessing, int data) + { + TraceEventHandler eventDelegate = (TraceEventHandler) ((CharScanner) source).Events[Parser.ExitRuleEventKey]; + if (eventDelegate != null) + { + traceEvent.setValues(TraceEventArgs.EXIT, ruleNum, guessing, data); + eventDelegate(source, traceEvent); + } + + checkController(); + + ruleDepth--; + if (ruleDepth == 0) + fireDoneParsing(); + } + + public virtual void fireLA(int k, int la) + { + TokenEventHandler eventDelegate = (TokenEventHandler) ((CharScanner) source).Events[Parser.LAEventKey]; + if (eventDelegate != null) + { + tokenEvent.setValues(TokenEventArgs.LA, k, la); + eventDelegate(source, tokenEvent); + } + + checkController(); + } + + public virtual void fireMatch(char c, int guessing) + { + MatchEventHandler eventDelegate = (MatchEventHandler) ((CharScanner) source).Events[Parser.MatchEventKey]; + if (eventDelegate != null) + { + matchEvent.setValues(MatchEventArgs.CHAR, c, c, null, guessing, false, true); + eventDelegate(source, matchEvent); + } + + checkController(); + } + + public virtual void fireMatch(char c, BitSet b, int guessing) + { + MatchEventHandler eventDelegate = (MatchEventHandler) ((CharScanner) source).Events[Parser.MatchEventKey]; + if (eventDelegate != null) + { + matchEvent.setValues(MatchEventArgs.CHAR_BITSET, c, b, null, guessing, false, true); + eventDelegate(source, matchEvent); + } + + checkController(); + } + + public virtual void fireMatch(char c, string target, int guessing) + { + MatchEventHandler eventDelegate = (MatchEventHandler) ((CharScanner) source).Events[Parser.MatchEventKey]; + if (eventDelegate != null) + { + matchEvent.setValues(MatchEventArgs.CHAR_RANGE, c, target, null, guessing, false, true); + eventDelegate(source, matchEvent); + } + + checkController(); + } + + public virtual void fireMatch(int c, BitSet b, string text, int guessing) + { + MatchEventHandler eventDelegate = (MatchEventHandler) ((CharScanner) source).Events[Parser.MatchEventKey]; + if (eventDelegate != null) + { + matchEvent.setValues(MatchEventArgs.BITSET, c, b, text, guessing, false, true); + eventDelegate(source, matchEvent); + } + + checkController(); + } + + public virtual void fireMatch(int n, string text, int guessing) + { + MatchEventHandler eventDelegate = (MatchEventHandler) ((CharScanner) source).Events[Parser.MatchEventKey]; + if (eventDelegate != null) + { + matchEvent.setValues(MatchEventArgs.TOKEN, n, n, text, guessing, false, true); + eventDelegate(source, matchEvent); + } + + checkController(); + } + + public virtual void fireMatch(string s, int guessing) + { + MatchEventHandler eventDelegate = (MatchEventHandler) ((CharScanner) source).Events[Parser.MatchEventKey]; + if (eventDelegate != null) + { + matchEvent.setValues(MatchEventArgs.STRING, 0, s, null, guessing, false, true); + eventDelegate(source, matchEvent); + } + + checkController(); + } + + public virtual void fireMatchNot(char c, char n, int guessing) + { + MatchEventHandler eventDelegate = (MatchEventHandler) ((CharScanner) source).Events[Parser.MatchNotEventKey]; + if (eventDelegate != null) + { + matchEvent.setValues(MatchEventArgs.CHAR, c, n, null, guessing, true, true); + eventDelegate(source, matchEvent); + } + + checkController(); + } + + public virtual void fireMatchNot(int c, int n, string text, int guessing) + { + MatchEventHandler eventDelegate = (MatchEventHandler) ((CharScanner) source).Events[Parser.MatchNotEventKey]; + if (eventDelegate != null) + { + matchEvent.setValues(MatchEventArgs.TOKEN, c, n, text, guessing, true, true); + eventDelegate(source, matchEvent); + } + + checkController(); + } + + public virtual void fireMismatch(char c, char n, int guessing) + { + MatchEventHandler eventDelegate = (MatchEventHandler) ((CharScanner) source).Events[Parser.MisMatchEventKey]; + if (eventDelegate != null) + { + matchEvent.setValues(MatchEventArgs.CHAR, c, n, null, guessing, false, false); + eventDelegate(source, matchEvent); + } + + checkController(); + } + + public virtual void fireMismatch(char c, BitSet b, int guessing) + { + MatchEventHandler eventDelegate = (MatchEventHandler) ((CharScanner) source).Events[Parser.MisMatchEventKey]; + if (eventDelegate != null) + { + matchEvent.setValues(MatchEventArgs.CHAR_BITSET, c, b, null, guessing, false, true); + eventDelegate(source, matchEvent); + } + + checkController(); + } + + public virtual void fireMismatch(char c, string target, int guessing) + { + MatchEventHandler eventDelegate = (MatchEventHandler) ((CharScanner) source).Events[Parser.MisMatchEventKey]; + if (eventDelegate != null) + { + matchEvent.setValues(MatchEventArgs.CHAR_RANGE, c, target, null, guessing, false, true); + eventDelegate(source, matchEvent); + } + + checkController(); + } + + public virtual void fireMismatch(int i, int n, string text, int guessing) + { + MatchEventHandler eventDelegate = (MatchEventHandler) ((CharScanner) source).Events[Parser.MisMatchEventKey]; + if (eventDelegate != null) + { + matchEvent.setValues(MatchEventArgs.TOKEN, i, n, text, guessing, false, false); + eventDelegate(source, matchEvent); + } + + checkController(); + } + + public virtual void fireMismatch(int i, BitSet b, string text, int guessing) + { + MatchEventHandler eventDelegate = (MatchEventHandler) ((CharScanner) source).Events[Parser.MisMatchEventKey]; + if (eventDelegate != null) + { + matchEvent.setValues(MatchEventArgs.BITSET, i, b, text, guessing, false, true); + eventDelegate(source, matchEvent); + } + + checkController(); + } + + public virtual void fireMismatch(string s, string text, int guessing) + { + MatchEventHandler eventDelegate = (MatchEventHandler) ((CharScanner) source).Events[Parser.MisMatchEventKey]; + if (eventDelegate != null) + { + matchEvent.setValues(MatchEventArgs.STRING, 0, text, s, guessing, false, true); + eventDelegate(source, matchEvent); + } + + checkController(); + } + + public virtual void fireMismatchNot(char v, char c, int guessing) + { + MatchEventHandler eventDelegate = (MatchEventHandler) ((CharScanner) source).Events[Parser.MisMatchNotEventKey]; + if (eventDelegate != null) + { + matchEvent.setValues(MatchEventArgs.CHAR, v, c, null, guessing, true, true); + eventDelegate(source, matchEvent); + } + + checkController(); + } + + public virtual void fireMismatchNot(int i, int n, string text, int guessing) + { + MatchEventHandler eventDelegate = (MatchEventHandler) ((CharScanner) source).Events[Parser.MisMatchNotEventKey]; + if (eventDelegate != null) + { + matchEvent.setValues(MatchEventArgs.TOKEN, i, n, text, guessing, true, true); + eventDelegate(source, matchEvent); + } + + checkController(); + } + + public virtual void fireNewLine(int line) + { + NewLineEventHandler eventDelegate = (NewLineEventHandler) ((CharScanner) source).Events[Parser.NewLineEventKey]; + if (eventDelegate != null) + { + newLineEvent.Line = line; + eventDelegate(source, newLineEvent); + } + + checkController(); + } + + public virtual void fireReportError(System.Exception e) + { + MessageEventHandler eventDelegate = (MessageEventHandler) ((CharScanner) source).Events[Parser.ReportErrorEventKey]; + if (eventDelegate != null) + { + messageEvent.setValues(MessageEventArgs.ERROR, e.ToString()); + eventDelegate(source, messageEvent); + } + + checkController(); + } + + public virtual void fireReportError(string s) + { + MessageEventHandler eventDelegate = (MessageEventHandler) ((CharScanner) source).Events[Parser.ReportErrorEventKey]; + if (eventDelegate != null) + { + messageEvent.setValues(MessageEventArgs.ERROR, s); + eventDelegate(source, messageEvent); + } + + checkController(); + } + + public virtual void fireReportWarning(string s) + { + MessageEventHandler eventDelegate = (MessageEventHandler) ((CharScanner) source).Events[Parser.ReportWarningEventKey]; + if (eventDelegate != null) + { + messageEvent.setValues(MessageEventArgs.WARNING, s); + eventDelegate(source, messageEvent); + } + + checkController(); + } + + public virtual bool fireSemanticPredicateEvaluated(int type, int condition, bool result, int guessing) + { + SemanticPredicateEventHandler eventDelegate = (SemanticPredicateEventHandler) ((CharScanner) source).Events[Parser.SemPredEvaluatedEventKey]; + if (eventDelegate != null) + { + semPredEvent.setValues(type, condition, result, guessing); + eventDelegate(source, semPredEvent); + } + + checkController(); + + return result; + } + + public virtual void fireSyntacticPredicateFailed(int guessing) + { + SyntacticPredicateEventHandler eventDelegate = (SyntacticPredicateEventHandler) ((CharScanner) source).Events[Parser.SynPredFailedEventKey]; + if (eventDelegate != null) + { + synPredEvent.setValues(0, guessing); + eventDelegate(source, synPredEvent); + } + + checkController(); + } + + public virtual void fireSyntacticPredicateStarted(int guessing) + { + SyntacticPredicateEventHandler eventDelegate = (SyntacticPredicateEventHandler) ((CharScanner) source).Events[Parser.SynPredStartedEventKey]; + if (eventDelegate != null) + { + synPredEvent.setValues(0, guessing); + eventDelegate(source, synPredEvent); + } + + checkController(); + } + + public virtual void fireSyntacticPredicateSucceeded(int guessing) + { + SyntacticPredicateEventHandler eventDelegate = (SyntacticPredicateEventHandler) ((CharScanner) source).Events[Parser.SynPredSucceededEventKey]; + if (eventDelegate != null) + { + synPredEvent.setValues(0, guessing); + eventDelegate(source, synPredEvent); + } + + checkController(); + } + + public virtual void refreshListeners() + { + Hashtable clonedTable; + + lock (listeners.SyncRoot) + { + clonedTable = (Hashtable) listeners.Clone(); + } + + foreach (Listener l in clonedTable) + { + l.refresh(); + } + } + + public virtual void removeDoneListener(Listener l) + { + ((CharScanner) source).Done -= new TraceEventHandler(l.doneParsing); + listeners.Remove(l); + } + + public virtual void removeMessageListener(MessageListener l) + { + ((CharScanner) source).ErrorReported -= new MessageEventHandler(l.reportError); + ((CharScanner) source).WarningReported -= new MessageEventHandler(l.reportWarning); + removeDoneListener(l); + } + + public virtual void removeNewLineListener(NewLineListener l) + { + ((CharScanner) source).HitNewLine -= new NewLineEventHandler(l.hitNewLine); + removeDoneListener(l); + } + + public virtual void removeParserListener(ParserListener l) + { + removeParserMatchListener(l); + removeMessageListener(l); + removeParserTokenListener(l); + removeTraceListener(l); + removeSemanticPredicateListener(l); + removeSyntacticPredicateListener(l); + } + + public virtual void removeParserMatchListener(ParserMatchListener l) + { + ((CharScanner) source).MatchedChar -= new MatchEventHandler(l.parserMatch); + ((CharScanner) source).MatchedNotChar -= new MatchEventHandler(l.parserMatchNot); + ((CharScanner) source).MisMatchedChar -= new MatchEventHandler(l.parserMismatch); + ((CharScanner) source).MisMatchedNotChar -= new MatchEventHandler(l.parserMismatchNot); + removeDoneListener(l); + } + + public virtual void removeParserTokenListener(ParserTokenListener l) + { + ((CharScanner) source).ConsumedChar -= new TokenEventHandler(l.parserConsume); + ((CharScanner) source).CharLA -= new TokenEventHandler(l.parserLA); + removeDoneListener(l); + } + + public virtual void removeSemanticPredicateListener(SemanticPredicateListener l) + { + ((CharScanner) source).SemPredEvaluated -= new SemanticPredicateEventHandler(l.semanticPredicateEvaluated); + removeDoneListener(l); + } + + public virtual void removeSyntacticPredicateListener(SyntacticPredicateListener l) + { + ((CharScanner) source).SynPredStarted -= new SyntacticPredicateEventHandler(l.syntacticPredicateStarted); + ((CharScanner) source).SynPredFailed -= new SyntacticPredicateEventHandler(l.syntacticPredicateFailed); + ((CharScanner) source).SynPredSucceeded -= new SyntacticPredicateEventHandler(l.syntacticPredicateSucceeded); + removeDoneListener(l); + } + + public virtual void removeTraceListener(TraceListener l) + { + ((CharScanner) source).EnterRule -= new TraceEventHandler(l.enterRule); + ((CharScanner) source).ExitRule -= new TraceEventHandler(l.exitRule); + removeDoneListener(l); + } } \ No newline at end of file diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/SemanticPredicateEventArgs.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/SemanticPredicateEventArgs.cs index bdc838e1..2ce8fc54 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/SemanticPredicateEventArgs.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/SemanticPredicateEventArgs.cs @@ -1,45 +1,44 @@ -namespace Spring.Expressions.Parser.antlr.debug +namespace Spring.Expressions.Parser.antlr.debug; + +public class SemanticPredicateEventArgs : GuessingEventArgs { - public class SemanticPredicateEventArgs : GuessingEventArgs - { - public SemanticPredicateEventArgs() - { - } - public SemanticPredicateEventArgs(int type) : base(type) - { - } + public SemanticPredicateEventArgs() + { + } - public virtual int Condition - { - get { return this.condition_; } - set { this.condition_ = value; } - } + public SemanticPredicateEventArgs(int type) : base(type) + { + } - public virtual bool Result - { - get { return this.result_; } - set { this.result_ = value; } - } + public virtual int Condition + { + get { return this.condition_; } + set { this.condition_ = value; } + } - public const int VALIDATING = 0; - public const int PREDICTING = 1; + public virtual bool Result + { + get { return this.result_; } + set { this.result_ = value; } + } - private int condition_; - private bool result_; - - - /// This should NOT be called from anyone other than ParserEventSupport! - /// - internal void setValues(int type, int condition, bool result, int guessing) - { - base.setValues(type, guessing); - this.Condition = condition; - this.Result = result; - } + public const int VALIDATING = 0; + public const int PREDICTING = 1; - public override string ToString() - { - return "SemanticPredicateEvent [" + Condition + "," + Result + "," + Guessing + "]"; - } - } -} \ No newline at end of file + private int condition_; + private bool result_; + + /// This should NOT be called from anyone other than ParserEventSupport! + /// + internal void setValues(int type, int condition, bool result, int guessing) + { + base.setValues(type, guessing); + this.Condition = condition; + this.Result = result; + } + + public override string ToString() + { + return "SemanticPredicateEvent [" + Condition + "," + Result + "," + Guessing + "]"; + } +} diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/SemanticPredicateListener.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/SemanticPredicateListener.cs index 2d399ed3..30f38551 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/SemanticPredicateListener.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/SemanticPredicateListener.cs @@ -1,7 +1,6 @@ -namespace Spring.Expressions.Parser.antlr.debug +namespace Spring.Expressions.Parser.antlr.debug; + +public interface SemanticPredicateListener : Listener { - public interface SemanticPredicateListener : Listener - { - void semanticPredicateEvaluated(object source, SemanticPredicateEventArgs e); - } -} \ No newline at end of file + void semanticPredicateEvaluated(object source, SemanticPredicateEventArgs e); +} diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/SemanticPredicateListenerBase.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/SemanticPredicateListenerBase.cs index 573cd07a..9a724828 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/SemanticPredicateListenerBase.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/SemanticPredicateListenerBase.cs @@ -1,36 +1,35 @@ -namespace Spring.Expressions.Parser.antlr.debug +namespace Spring.Expressions.Parser.antlr.debug; + +/// +/// Provides an abstract base for implementing subclasses. +/// +/// +/// +/// This abstract class is provided to make it easier to create s. +/// You should extend this base class rather than creating your own. +/// +/// +public class SemanticPredicateListenerBase : SemanticPredicateListener { /// - /// Provides an abstract base for implementing subclasses. - /// - /// - /// - /// This abstract class is provided to make it easier to create s. - /// You should extend this base class rather than creating your own. - /// - /// - public class SemanticPredicateListenerBase : SemanticPredicateListener - { - /// - /// Handle the "Done" event. - /// - /// Event source object - /// Event data object - public virtual void doneParsing(object source, TraceEventArgs e) - { - } + /// Handle the "Done" event. + /// + /// Event source object + /// Event data object + public virtual void doneParsing(object source, TraceEventArgs e) + { + } - public virtual void refresh() - { - } + public virtual void refresh() + { + } - /// - /// Handle the "SemPreEvaluated" event. - /// - /// Event source object - /// Event data object - public virtual void semanticPredicateEvaluated(object source, SemanticPredicateEventArgs e) - { - } - } + /// + /// Handle the "SemPreEvaluated" event. + /// + /// Event source object + /// Event data object + public virtual void semanticPredicateEvaluated(object source, SemanticPredicateEventArgs e) + { + } } \ No newline at end of file diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/SyntacticPredicateEventArgs.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/SyntacticPredicateEventArgs.cs index 979b1b52..b3e8f09a 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/SyntacticPredicateEventArgs.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/SyntacticPredicateEventArgs.cs @@ -1,19 +1,17 @@ -namespace Spring.Expressions.Parser.antlr.debug -{ - public class SyntacticPredicateEventArgs : GuessingEventArgs - { - - - public SyntacticPredicateEventArgs() - { - } - public SyntacticPredicateEventArgs(int type) : base(type) - { - } +namespace Spring.Expressions.Parser.antlr.debug; - public override string ToString() - { - return "SyntacticPredicateEvent [" + Guessing + "]"; - } - } -} \ No newline at end of file +public class SyntacticPredicateEventArgs : GuessingEventArgs +{ + public SyntacticPredicateEventArgs() + { + } + + public SyntacticPredicateEventArgs(int type) : base(type) + { + } + + public override string ToString() + { + return "SyntacticPredicateEvent [" + Guessing + "]"; + } +} diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/SyntacticPredicateListener.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/SyntacticPredicateListener.cs index 60865b87..89d77070 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/SyntacticPredicateListener.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/SyntacticPredicateListener.cs @@ -1,9 +1,8 @@ -namespace Spring.Expressions.Parser.antlr.debug +namespace Spring.Expressions.Parser.antlr.debug; + +public interface SyntacticPredicateListener : Listener { - public interface SyntacticPredicateListener : Listener - { - void syntacticPredicateFailed (object source, SyntacticPredicateEventArgs e); - void syntacticPredicateStarted (object source, SyntacticPredicateEventArgs e); - void syntacticPredicateSucceeded (object source, SyntacticPredicateEventArgs e); - } -} \ No newline at end of file + void syntacticPredicateFailed(object source, SyntacticPredicateEventArgs e); + void syntacticPredicateStarted(object source, SyntacticPredicateEventArgs e); + void syntacticPredicateSucceeded(object source, SyntacticPredicateEventArgs e); +} diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/SyntacticPredicateListenerBase.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/SyntacticPredicateListenerBase.cs index b93f17f4..2e7bc7ba 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/SyntacticPredicateListenerBase.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/SyntacticPredicateListenerBase.cs @@ -1,54 +1,53 @@ -namespace Spring.Expressions.Parser.antlr.debug +namespace Spring.Expressions.Parser.antlr.debug; + +/// +/// Provides an abstract base for implementing subclasses. +/// +/// +/// +/// This abstract class is provided to make it easier to create s. +/// You should extend this base class rather than creating your own. +/// +/// +public abstract class SyntacticPredicateListenerBase : SyntacticPredicateListener { /// - /// Provides an abstract base for implementing subclasses. - /// - /// - /// - /// This abstract class is provided to make it easier to create s. - /// You should extend this base class rather than creating your own. - /// - /// - public abstract class SyntacticPredicateListenerBase : SyntacticPredicateListener - { - /// - /// Handle the "Done" event. - /// - /// Event source object - /// Event data object - public virtual void doneParsing(object source, TraceEventArgs e) - { - } + /// Handle the "Done" event. + /// + /// Event source object + /// Event data object + public virtual void doneParsing(object source, TraceEventArgs e) + { + } - public virtual void refresh() - { - } + public virtual void refresh() + { + } - /// - /// Handle the "SynPredFailed" event. - /// - /// Event source object - /// Event data object - public virtual void syntacticPredicateFailed(object source, SyntacticPredicateEventArgs e) - { - } + /// + /// Handle the "SynPredFailed" event. + /// + /// Event source object + /// Event data object + public virtual void syntacticPredicateFailed(object source, SyntacticPredicateEventArgs e) + { + } - /// - /// Handle the "SynPredStarted" event. - /// - /// Event source object - /// Event data object - public virtual void syntacticPredicateStarted(object source, SyntacticPredicateEventArgs e) - { - } - - /// - /// Handle the "SynPredSucceeded" event. - /// - /// Event source object - /// Event data object - public virtual void syntacticPredicateSucceeded(object source, SyntacticPredicateEventArgs e) - { - } - } -} \ No newline at end of file + /// + /// Handle the "SynPredStarted" event. + /// + /// Event source object + /// Event data object + public virtual void syntacticPredicateStarted(object source, SyntacticPredicateEventArgs e) + { + } + + /// + /// Handle the "SynPredSucceeded" event. + /// + /// Event source object + /// Event data object + public virtual void syntacticPredicateSucceeded(object source, SyntacticPredicateEventArgs e) + { + } +} diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/TraceEventArgs.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/TraceEventArgs.cs index 11a30dda..a94aa54b 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/TraceEventArgs.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/TraceEventArgs.cs @@ -1,47 +1,46 @@ -namespace Spring.Expressions.Parser.antlr.debug +namespace Spring.Expressions.Parser.antlr.debug; + +public class TraceEventArgs : GuessingEventArgs { - public class TraceEventArgs : GuessingEventArgs - { - public TraceEventArgs() - { - } - public TraceEventArgs(int type, int ruleNum, int guessing, int data) - { - setValues(type, ruleNum, guessing, data); - } + public TraceEventArgs() + { + } - public virtual int Data - { - get { return this.data_; } - set { this.data_ = value; } - } + public TraceEventArgs(int type, int ruleNum, int guessing, int data) + { + setValues(type, ruleNum, guessing, data); + } - public virtual int RuleNum - { - get { return this.ruleNum_; } - set { this.ruleNum_ = value; } - } + public virtual int Data + { + get { return this.data_; } + set { this.data_ = value; } + } - private int ruleNum_; - private int data_; + public virtual int RuleNum + { + get { return this.ruleNum_; } + set { this.ruleNum_ = value; } + } - public static int ENTER = 0; - public static int EXIT = 1; - public static int DONE_PARSING = 2; - - - /// This should NOT be called from anyone other than ParserEventSupport! - /// - internal void setValues(int type, int ruleNum, int guessing, int data) - { - base.setValues(type, guessing); - RuleNum = ruleNum; - Data = data; - } + private int ruleNum_; + private int data_; - public override string ToString() - { - return "ParserTraceEvent [" + (Type == ENTER?"enter,":"exit,") + RuleNum + "," + Guessing + "]"; - } - } -} \ No newline at end of file + public static int ENTER = 0; + public static int EXIT = 1; + public static int DONE_PARSING = 2; + + /// This should NOT be called from anyone other than ParserEventSupport! + /// + internal void setValues(int type, int ruleNum, int guessing, int data) + { + base.setValues(type, guessing); + RuleNum = ruleNum; + Data = data; + } + + public override string ToString() + { + return "ParserTraceEvent [" + (Type == ENTER ? "enter," : "exit,") + RuleNum + "," + Guessing + "]"; + } +} diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/TraceListener.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/TraceListener.cs index ec22023b..82844508 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/TraceListener.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/TraceListener.cs @@ -1,8 +1,7 @@ -namespace Spring.Expressions.Parser.antlr.debug +namespace Spring.Expressions.Parser.antlr.debug; + +public interface TraceListener : Listener { - public interface TraceListener : Listener - { - void enterRule (object source, TraceEventArgs e); - void exitRule (object source, TraceEventArgs e); - } -} \ No newline at end of file + void enterRule(object source, TraceEventArgs e); + void exitRule(object source, TraceEventArgs e); +} diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/TraceListenerBase.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/TraceListenerBase.cs index 81ac7edf..b1c6048a 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/TraceListenerBase.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/TraceListenerBase.cs @@ -1,45 +1,44 @@ -namespace Spring.Expressions.Parser.antlr.debug +namespace Spring.Expressions.Parser.antlr.debug; + +/// +/// Provides an abstract base for implementing subclasses. +/// +/// +/// +/// This abstract class is provided to make it easier to create s. +/// You should extend this base class rather than creating your own. +/// +/// +public abstract class TraceListenerBase : TraceListener { /// - /// Provides an abstract base for implementing subclasses. - /// - /// - /// - /// This abstract class is provided to make it easier to create s. - /// You should extend this base class rather than creating your own. - /// - /// - public abstract class TraceListenerBase : TraceListener - { - /// - /// Handle the "Done" event. - /// - /// Event source object - /// Event data object - public virtual void doneParsing(object source, TraceEventArgs e) - { - } + /// Handle the "Done" event. + /// + /// Event source object + /// Event data object + public virtual void doneParsing(object source, TraceEventArgs e) + { + } - /// - /// Handle the "EnterRule" event - /// - /// Event source object - /// Event data object - public virtual void enterRule(object source, TraceEventArgs e) - { - } + /// + /// Handle the "EnterRule" event + /// + /// Event source object + /// Event data object + public virtual void enterRule(object source, TraceEventArgs e) + { + } - /// - /// Handle the "ExitRule" event - /// - /// Event source object - /// Event data object - public virtual void exitRule(object source, TraceEventArgs e) - { - } + /// + /// Handle the "ExitRule" event + /// + /// Event source object + /// Event data object + public virtual void exitRule(object source, TraceEventArgs e) + { + } - public virtual void refresh() - { - } - } -} \ No newline at end of file + public virtual void refresh() + { + } +} diff --git a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/Tracer.cs b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/Tracer.cs index c889512d..671d7ba8 100644 --- a/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/Tracer.cs +++ b/src/Spring/Spring.Core/Expressions/Parser/antlr/debug/Tracer.cs @@ -1,31 +1,32 @@ -namespace Spring.Expressions.Parser.antlr.debug +namespace Spring.Expressions.Parser.antlr.debug; + +public class Tracer : TraceListenerBase, TraceListener { - public class Tracer : TraceListenerBase, TraceListener - { - protected string indentString = ""; - // TBD: should be StringBuffer - - - protected internal virtual void dedent() - { - if (indentString.Length < 2) - indentString = ""; - else - indentString = indentString.Substring(2); - } - public override void enterRule(object source, TraceEventArgs e) - { - System.Console.Out.WriteLine(indentString + e); - indent(); - } - public override void exitRule(object source, TraceEventArgs e) - { - dedent(); - System.Console.Out.WriteLine(indentString + e); - } - protected internal virtual void indent() - { - indentString += " "; - } - } -} \ No newline at end of file + protected string indentString = ""; + // TBD: should be StringBuffer + + protected internal virtual void dedent() + { + if (indentString.Length < 2) + indentString = ""; + else + indentString = indentString.Substring(2); + } + + public override void enterRule(object source, TraceEventArgs e) + { + System.Console.Out.WriteLine(indentString + e); + indent(); + } + + public override void exitRule(object source, TraceEventArgs e) + { + dedent(); + System.Console.Out.WriteLine(indentString + e); + } + + protected internal virtual void indent() + { + indentString += " "; + } +} diff --git a/src/Spring/Spring.Core/Expressions/Processors/AverageAggregator.cs b/src/Spring/Spring.Core/Expressions/Processors/AverageAggregator.cs index 95691b10..bdd74f77 100644 --- a/src/Spring/Spring.Core/Expressions/Processors/AverageAggregator.cs +++ b/src/Spring/Spring.Core/Expressions/Processors/AverageAggregator.cs @@ -21,47 +21,46 @@ using System.Collections; using Spring.Util; -namespace Spring.Expressions.Processors +namespace Spring.Expressions.Processors; + +/// +/// Implementation of the average aggregator. +/// +/// Aleksandar Seovic +public class AverageAggregator : ICollectionProcessor { /// - /// Implementation of the average aggregator. + /// Returns the average of the numeric values in the source collection. /// - /// Aleksandar Seovic - public class AverageAggregator : ICollectionProcessor + /// + /// The source collection to process. + /// + /// + /// Ignored. + /// + /// + /// The average of the numeric values in the source collection. + /// + public object Process(ICollection source, object[] args) { - /// - /// Returns the average of the numeric values in the source collection. - /// - /// - /// The source collection to process. - /// - /// - /// Ignored. - /// - /// - /// The average of the numeric values in the source collection. - /// - public object Process(ICollection source, object[] args) + int n = 0; + object total = 0d; + foreach (object item in source) { - int n = 0; - object total = 0d; - foreach (object item in source) + if (item != null) { - if (item != null) + if (NumberUtils.IsNumber(item)) { - if (NumberUtils.IsNumber(item)) - { - total = NumberUtils.Add(total, item); - n++; - } - else - { - throw new ArgumentException("Average can only be calculated for a collection of numeric values."); - } + total = NumberUtils.Add(total, item); + n++; + } + else + { + throw new ArgumentException("Average can only be calculated for a collection of numeric values."); } } - - return NumberUtils.Divide(total, n); } + + return NumberUtils.Divide(total, n); } } diff --git a/src/Spring/Spring.Core/Expressions/Processors/ConversionProcessor.cs b/src/Spring/Spring.Core/Expressions/Processors/ConversionProcessor.cs index 5e840db7..6e0b63a2 100644 --- a/src/Spring/Spring.Core/Expressions/Processors/ConversionProcessor.cs +++ b/src/Spring/Spring.Core/Expressions/Processors/ConversionProcessor.cs @@ -21,63 +21,62 @@ using System.Collections; using Spring.Core.TypeConversion; -namespace Spring.Expressions.Processors +namespace Spring.Expressions.Processors; + +/// +/// Converts all elements in the input list to a given target type. +/// +/// Erich Eichinger +public class ConversionProcessor : ICollectionProcessor { /// - /// Converts all elements in the input list to a given target type. + /// Processes a list of source items and returns a result. /// - /// Erich Eichinger - public class ConversionProcessor : ICollectionProcessor + /// + /// The source list to process. + /// + /// + /// An optional processor arguments array. + /// + /// + /// The processing result. + /// + public object Process(ICollection source, object[] args) { - /// - /// Processes a list of source items and returns a result. - /// - /// - /// The source list to process. - /// - /// - /// An optional processor arguments array. - /// - /// - /// The processing result. - /// - public object Process(ICollection source, object[] args) + if (source == null + || source.Count == 0) { - if (source == null - || source.Count == 0) - { - return source; - } - - Type targetType = typeof(double); - if (args == null || args.Length == 0) - { - throw new ArgumentNullException("args", "convert() processor requires a Type value argument."); - } - else if (args.Length == 1) - { - if (args[0] is Type) - { - targetType = (Type)args[0]; - } - else - { - throw new ArgumentException("convert() processor argument must be a Type value."); - } - } - else if (args.Length > 1) - { - throw new ArgumentException("Only a single argument can be specified for a convert() processor."); - } - - ArrayList result = new ArrayList(); - foreach(object val in source) - { - object newVal = TypeConversionUtils.ConvertValueIfNecessary(targetType, val, null); - result.Add(newVal); - } - - return result.ToArray(targetType); + return source; } + + Type targetType = typeof(double); + if (args == null || args.Length == 0) + { + throw new ArgumentNullException("args", "convert() processor requires a Type value argument."); + } + else if (args.Length == 1) + { + if (args[0] is Type) + { + targetType = (Type) args[0]; + } + else + { + throw new ArgumentException("convert() processor argument must be a Type value."); + } + } + else if (args.Length > 1) + { + throw new ArgumentException("Only a single argument can be specified for a convert() processor."); + } + + ArrayList result = new ArrayList(); + foreach (object val in source) + { + object newVal = TypeConversionUtils.ConvertValueIfNecessary(targetType, val, null); + result.Add(newVal); + } + + return result.ToArray(targetType); } } diff --git a/src/Spring/Spring.Core/Expressions/Processors/CountAggregator.cs b/src/Spring/Spring.Core/Expressions/Processors/CountAggregator.cs index 44fdb55e..766125ec 100644 --- a/src/Spring/Spring.Core/Expressions/Processors/CountAggregator.cs +++ b/src/Spring/Spring.Core/Expressions/Processors/CountAggregator.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -20,34 +20,34 @@ using System.Collections; -namespace Spring.Expressions.Processors +namespace Spring.Expressions.Processors; + +/// +/// Implementation of the count aggregator. +/// +/// Aleksandar Seovic +public class CountAggregator : ICollectionProcessor { /// - /// Implementation of the count aggregator. + /// Returns the number of items in the source collection. /// - /// Aleksandar Seovic - public class CountAggregator : ICollectionProcessor + /// + /// The source collection to process. + /// + /// + /// Ignored. + /// + /// + /// The number of items in the source collection, + /// or zero if the collection is empty or null. + /// + public object Process(ICollection source, object[] args) { - /// - /// Returns the number of items in the source collection. - /// - /// - /// The source collection to process. - /// - /// - /// Ignored. - /// - /// - /// The number of items in the source collection, - /// or zero if the collection is empty or null. - /// - public object Process(ICollection source, object[] args) + if (source == null) { - if (source == null) - { - return 0; - } - return source.Count; + return 0; } + + return source.Count; } } diff --git a/src/Spring/Spring.Core/Expressions/Processors/DateConversionProcessor.cs b/src/Spring/Spring.Core/Expressions/Processors/DateConversionProcessor.cs index 86c2c0b6..65450745 100644 --- a/src/Spring/Spring.Core/Expressions/Processors/DateConversionProcessor.cs +++ b/src/Spring/Spring.Core/Expressions/Processors/DateConversionProcessor.cs @@ -20,26 +20,25 @@ using System.Globalization; -namespace Spring.Expressions.Processors +namespace Spring.Expressions.Processors; + +/// +/// Converts a string literal to a instance. +/// +/// Erich Eichinger +public class DateConversionProcessor : IMethodCallProcessor { - /// - /// Converts a string literal to a instance. - /// - /// Erich Eichinger - public class DateConversionProcessor : IMethodCallProcessor + public object Process(object context, object[] args) { - public object Process(object context, object[] args) + int argc = args != null ? args.Length : 0; + switch (argc) { - int argc = args != null ? args.Length : 0; - switch (argc) - { - case 1: - return DateTime.Parse((string)args[0]); - case 2: - return DateTime.ParseExact((string)args[0], (string)args[1], CultureInfo.InvariantCulture); - default: - throw new ArgumentException("date( [,]) expects 1 or 2 arguments"); - } + case 1: + return DateTime.Parse((string) args[0]); + case 2: + return DateTime.ParseExact((string) args[0], (string) args[1], CultureInfo.InvariantCulture); + default: + throw new ArgumentException("date( [,]) expects 1 or 2 arguments"); } } } diff --git a/src/Spring/Spring.Core/Expressions/Processors/DistinctProcessor.cs b/src/Spring/Spring.Core/Expressions/Processors/DistinctProcessor.cs index 23496e1d..441ab0e6 100644 --- a/src/Spring/Spring.Core/Expressions/Processors/DistinctProcessor.cs +++ b/src/Spring/Spring.Core/Expressions/Processors/DistinctProcessor.cs @@ -21,62 +21,62 @@ using System.Collections; using Spring.Collections; -namespace Spring.Expressions.Processors +namespace Spring.Expressions.Processors; + +/// +/// Implementation of the distinct processor. +/// +/// Aleksandar Seovic +public class DistinctProcessor : ICollectionProcessor { /// - /// Implementation of the distinct processor. + /// Returns distinct items from the collection. /// - /// Aleksandar Seovic - public class DistinctProcessor : ICollectionProcessor + /// + /// The source collection to process. + /// + /// + /// 0: boolean flag specifying whether to include null + /// in the results or not. Default is false, which means that + /// null values will not be included in the results. + /// + /// + /// A collection containing distinct source collection elements. + /// + /// + /// If there is more than one argument, or if the single optional argument + /// is not Boolean. + /// + public object Process(ICollection source, object[] args) { - /// - /// Returns distinct items from the collection. - /// - /// - /// The source collection to process. - /// - /// - /// 0: boolean flag specifying whether to include null - /// in the results or not. Default is false, which means that - /// null values will not be included in the results. - /// - /// - /// A collection containing distinct source collection elements. - /// - /// - /// If there is more than one argument, or if the single optional argument - /// is not Boolean. - /// - public object Process(ICollection source, object[] args) + if (source == null) { - if (source == null) - { - return null; - } - - bool includeNulls = false; - if (args.Length == 1) - { - if (args[0] is bool) - { - includeNulls = (bool) args[0]; - } - else - { - throw new ArgumentException("distinct() processor argument must be a boolean value."); - } - } - else if (args.Length > 1) - { - throw new ArgumentException("Only a single argument can be specified for a distinct() processor."); - } - - HybridSet set = new HybridSet(source); - if (!includeNulls) - { - set.Remove(null); - } - return set; + return null; } + + bool includeNulls = false; + if (args.Length == 1) + { + if (args[0] is bool) + { + includeNulls = (bool) args[0]; + } + else + { + throw new ArgumentException("distinct() processor argument must be a boolean value."); + } + } + else if (args.Length > 1) + { + throw new ArgumentException("Only a single argument can be specified for a distinct() processor."); + } + + HybridSet set = new HybridSet(source); + if (!includeNulls) + { + set.Remove(null); + } + + return set; } } diff --git a/src/Spring/Spring.Core/Expressions/Processors/ICollectionProcessor.cs b/src/Spring/Spring.Core/Expressions/Processors/ICollectionProcessor.cs index 3b62d1e8..0b6c0590 100644 --- a/src/Spring/Spring.Core/Expressions/Processors/ICollectionProcessor.cs +++ b/src/Spring/Spring.Core/Expressions/Processors/ICollectionProcessor.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -20,26 +20,25 @@ using System.Collections; -namespace Spring.Expressions.Processors +namespace Spring.Expressions.Processors; + +/// +/// Defines an interface that should be implemented +/// by all collection processors and aggregators. +/// +public interface ICollectionProcessor { /// - /// Defines an interface that should be implemented - /// by all collection processors and aggregators. + /// Processes a list of source items and returns a result. /// - public interface ICollectionProcessor - { - /// - /// Processes a list of source items and returns a result. - /// - /// - /// The source list to process. - /// - /// - /// An optional processor arguments array. - /// - /// - /// The processing result. - /// - object Process(ICollection source, object[] args); - } + /// + /// The source list to process. + /// + /// + /// An optional processor arguments array. + /// + /// + /// The processing result. + /// + object Process(ICollection source, object[] args); } diff --git a/src/Spring/Spring.Core/Expressions/Processors/IMethodCallProcessor.cs b/src/Spring/Spring.Core/Expressions/Processors/IMethodCallProcessor.cs index f615921a..66ab6be2 100644 --- a/src/Spring/Spring.Core/Expressions/Processors/IMethodCallProcessor.cs +++ b/src/Spring/Spring.Core/Expressions/Processors/IMethodCallProcessor.cs @@ -1,30 +1,29 @@ #region License -/* - * Copyright 2002-2010 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. +/* + * Copyright 2002-2010 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 -namespace Spring.Expressions.Processors +namespace Spring.Expressions.Processors; + +/// +/// +/// Erich Eichinger +public interface IMethodCallProcessor { - /// - /// - /// Erich Eichinger - public interface IMethodCallProcessor - { - object Process(object context, object[] args); - } -} \ No newline at end of file + object Process(object context, object[] args); +} diff --git a/src/Spring/Spring.Core/Expressions/Processors/MaxAggregator.cs b/src/Spring/Spring.Core/Expressions/Processors/MaxAggregator.cs index cc2651b8..488db3a7 100644 --- a/src/Spring/Spring.Core/Expressions/Processors/MaxAggregator.cs +++ b/src/Spring/Spring.Core/Expressions/Processors/MaxAggregator.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -21,37 +21,37 @@ using System.Collections; using Spring.Util; -namespace Spring.Expressions.Processors +namespace Spring.Expressions.Processors; + +/// +/// Implementation of the maximum aggregator. +/// +/// Aleksandar Seovic +public class MaxAggregator : ICollectionProcessor { /// - /// Implementation of the maximum aggregator. + /// Returns the largest item in the source collection. /// - /// Aleksandar Seovic - public class MaxAggregator : ICollectionProcessor + /// + /// The source collection to process. + /// + /// + /// Ignored. + /// + /// + /// The largest item in the source collection. + /// + public object Process(ICollection source, object[] args) { - /// - /// Returns the largest item in the source collection. - /// - /// - /// The source collection to process. - /// - /// - /// Ignored. - /// - /// - /// The largest item in the source collection. - /// - public object Process(ICollection source, object[] args) + object maxItem = null; + foreach (object item in source) { - object maxItem = null; - foreach (object item in source) + if (CompareUtils.Compare(maxItem, item) < 0) { - if (CompareUtils.Compare(maxItem, item) < 0) - { - maxItem = item; - } + maxItem = item; } - return maxItem; } + + return maxItem; } } diff --git a/src/Spring/Spring.Core/Expressions/Processors/MinAggregator.cs b/src/Spring/Spring.Core/Expressions/Processors/MinAggregator.cs index 36cb8d18..9c426482 100644 --- a/src/Spring/Spring.Core/Expressions/Processors/MinAggregator.cs +++ b/src/Spring/Spring.Core/Expressions/Processors/MinAggregator.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -21,37 +21,37 @@ using System.Collections; using Spring.Util; -namespace Spring.Expressions.Processors +namespace Spring.Expressions.Processors; + +/// +/// Implementation of the minimum aggregator. +/// +/// Aleksandar Seovic +public class MinAggregator : ICollectionProcessor { /// - /// Implementation of the minimum aggregator. + /// Returns the smallest item in the source collection. /// - /// Aleksandar Seovic - public class MinAggregator : ICollectionProcessor + /// + /// The source collection to process. + /// + /// + /// Ignored. + /// + /// + /// The smallest item in the source collection. + /// + public object Process(ICollection source, object[] args) { - /// - /// Returns the smallest item in the source collection. - /// - /// - /// The source collection to process. - /// - /// - /// Ignored. - /// - /// - /// The smallest item in the source collection. - /// - public object Process(ICollection source, object[] args) + object minItem = null; + foreach (object item in source) { - object minItem = null; - foreach (object item in source) + if ((minItem == null && item != null) || (CompareUtils.Compare(minItem, item) > 0)) { - if ((minItem == null && item != null) || (CompareUtils.Compare(minItem, item) > 0)) - { - minItem = item; - } + minItem = item; } - return minItem; } + + return minItem; } -} +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Expressions/Processors/NonNullProcessor.cs b/src/Spring/Spring.Core/Expressions/Processors/NonNullProcessor.cs index e522e06d..b03fc718 100644 --- a/src/Spring/Spring.Core/Expressions/Processors/NonNullProcessor.cs +++ b/src/Spring/Spring.Core/Expressions/Processors/NonNullProcessor.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -20,42 +20,42 @@ using System.Collections; -namespace Spring.Expressions.Processors +namespace Spring.Expressions.Processors; + +/// +/// Implementation of the non-null processor. +/// +/// Aleksandar Seovic +public class NonNullProcessor : ICollectionProcessor { /// - /// Implementation of the non-null processor. + /// Returns non-null items from the collection. /// - /// Aleksandar Seovic - public class NonNullProcessor : ICollectionProcessor + /// + /// The source collection to process. + /// + /// + /// Ignored. + /// + /// + /// A collection containing non-null source collection elements. + /// + public object Process(ICollection source, object[] args) { - /// - /// Returns non-null items from the collection. - /// - /// - /// The source collection to process. - /// - /// - /// Ignored. - /// - /// - /// A collection containing non-null source collection elements. - /// - public object Process(ICollection source, object[] args) + if (source == null) { - if (source == null) - { - return null; - } - - ArrayList list = new ArrayList(); - foreach (object item in source) - { - if (item != null) - { - list.Add(item); - } - } - return list.ToArray(); + return null; } + + ArrayList list = new ArrayList(); + foreach (object item in source) + { + if (item != null) + { + list.Add(item); + } + } + + return list.ToArray(); } -} \ No newline at end of file +} diff --git a/src/Spring/Spring.Core/Expressions/Processors/OrderByProcessor.cs b/src/Spring/Spring.Core/Expressions/Processors/OrderByProcessor.cs index be17756a..c473175f 100644 --- a/src/Spring/Spring.Core/Expressions/Processors/OrderByProcessor.cs +++ b/src/Spring/Spring.Core/Expressions/Processors/OrderByProcessor.cs @@ -21,144 +21,144 @@ using System.Collections; using Spring.Util; -namespace Spring.Expressions.Processors +namespace Spring.Expressions.Processors; + +/// +/// Implementation of the 'order by' processor. +/// +/// Aleksandar Seovic +/// Erich Eichinger +public class OrderByProcessor : ICollectionProcessor { - /// - /// Implementation of the 'order by' processor. - /// - /// Aleksandar Seovic - /// Erich Eichinger - public class OrderByProcessor : ICollectionProcessor + #region Comparer Helper Implementations + + private class SimpleExpressionComparer : IComparer { - #region Comparer Helper Implementations + private readonly IExpression _expression; - private class SimpleExpressionComparer : IComparer + public SimpleExpressionComparer(IExpression expression) { - private readonly IExpression _expression; - - public SimpleExpressionComparer(IExpression expression) - { - _expression = expression; - } - - public int Compare(object x, object y) - { - x = _expression.GetValue(x); - y = _expression.GetValue(y); - - if (x==y) return 0; - - if (x != null) return ((IComparable) x).CompareTo(y); - - return ((IComparable)y).CompareTo(x)*-1; - } + _expression = expression; } - private class LambdaComparer : IComparer + public int Compare(object x, object y) { - private readonly Dictionary _variables; - private readonly IExpression _fn; + x = _expression.GetValue(x); + y = _expression.GetValue(y); - public LambdaComparer(LambdaExpressionNode lambdaExpression) - { - FunctionNode functionNode = new FunctionNode(); - functionNode.Text = "compare"; - VariableNode x = new VariableNode(); - x.Text = "x"; - VariableNode y = new VariableNode(); - y.Text = "y"; + if (x == y) return 0; - functionNode.addChild(x); - functionNode.addChild(y); + if (x != null) return ((IComparable) x).CompareTo(y); - _fn = functionNode; - _variables = new Dictionary(); - _variables.Add( "compare", lambdaExpression ); - } - - public int Compare(object x, object y) - { - _variables["x"] = x; - _variables["y"] = y; - return (int) _fn.GetValue(null, _variables); - } - } - - private class DelegateComparer : IComparer - { - private readonly Delegate _fnCompare; - - public DelegateComparer(Delegate fnCompare) - { - _fnCompare = fnCompare; - } - - public int Compare(object x, object y) - { - return (int)_fnCompare.DynamicInvoke(new object[] { x, y }); - } - } - - #endregion - - /// - /// Sorts the source collection using custom sort criteria. - /// - /// - /// Please note that your compare function needs to take care about - /// proper conversion of types to be comparable! - /// - /// - /// The source collection to sort. - /// - /// - /// Sort criteria to use. - /// - /// - /// A sorted array containing collection elements. - /// - public object Process(ICollection source, object[] args) - { - if (source == null || source.Count == 0) - { - return source; - } - - if (args == null || args.Length != 1) - { - throw new ArgumentException("compare expression is a required argument for orderBy"); - } - - object arg = args[0]; - IComparer comparer = null; - if (arg is string) - { - IExpression expCompare = Expression.Parse((string) arg); - comparer = new SimpleExpressionComparer(expCompare); - } - else if (arg is IComparer) - { - comparer = (IComparer) arg; - } - else if (arg is LambdaExpressionNode) - { - LambdaExpressionNode fnCompare = (LambdaExpressionNode)arg; - if (fnCompare.ArgumentNames.Length != 2) - { - throw new ArgumentException("compare function must accept 2 arguments"); - } - comparer = new LambdaComparer(fnCompare); - } - else if (arg is Delegate) - { - comparer = new DelegateComparer((Delegate) arg); - } - - AssertUtils.ArgumentNotNull(comparer, "comparer", "orderBy(comparer) argument 'comparer' does not evaluate to a supported type"); - - ArrayList list = new ArrayList(source); - list.Sort(comparer); - return list; + return ((IComparable) y).CompareTo(x) * -1; } } -} + + private class LambdaComparer : IComparer + { + private readonly Dictionary _variables; + private readonly IExpression _fn; + + public LambdaComparer(LambdaExpressionNode lambdaExpression) + { + FunctionNode functionNode = new FunctionNode(); + functionNode.Text = "compare"; + VariableNode x = new VariableNode(); + x.Text = "x"; + VariableNode y = new VariableNode(); + y.Text = "y"; + + functionNode.addChild(x); + functionNode.addChild(y); + + _fn = functionNode; + _variables = new Dictionary(); + _variables.Add("compare", lambdaExpression); + } + + public int Compare(object x, object y) + { + _variables["x"] = x; + _variables["y"] = y; + return (int) _fn.GetValue(null, _variables); + } + } + + private class DelegateComparer : IComparer + { + private readonly Delegate _fnCompare; + + public DelegateComparer(Delegate fnCompare) + { + _fnCompare = fnCompare; + } + + public int Compare(object x, object y) + { + return (int) _fnCompare.DynamicInvoke(new object[] { x, y }); + } + } + + #endregion + + /// + /// Sorts the source collection using custom sort criteria. + /// + /// + /// Please note that your compare function needs to take care about + /// proper conversion of types to be comparable! + /// + /// + /// The source collection to sort. + /// + /// + /// Sort criteria to use. + /// + /// + /// A sorted array containing collection elements. + /// + public object Process(ICollection source, object[] args) + { + if (source == null || source.Count == 0) + { + return source; + } + + if (args == null || args.Length != 1) + { + throw new ArgumentException("compare expression is a required argument for orderBy"); + } + + object arg = args[0]; + IComparer comparer = null; + if (arg is string) + { + IExpression expCompare = Expression.Parse((string) arg); + comparer = new SimpleExpressionComparer(expCompare); + } + else if (arg is IComparer) + { + comparer = (IComparer) arg; + } + else if (arg is LambdaExpressionNode) + { + LambdaExpressionNode fnCompare = (LambdaExpressionNode) arg; + if (fnCompare.ArgumentNames.Length != 2) + { + throw new ArgumentException("compare function must accept 2 arguments"); + } + + comparer = new LambdaComparer(fnCompare); + } + else if (arg is Delegate) + { + comparer = new DelegateComparer((Delegate) arg); + } + + AssertUtils.ArgumentNotNull(comparer, "comparer", "orderBy(comparer) argument 'comparer' does not evaluate to a supported type"); + + ArrayList list = new ArrayList(source); + list.Sort(comparer); + return list; + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Expressions/Processors/ReverseProcessor.cs b/src/Spring/Spring.Core/Expressions/Processors/ReverseProcessor.cs index 1189d8ec..1d90feab 100644 --- a/src/Spring/Spring.Core/Expressions/Processors/ReverseProcessor.cs +++ b/src/Spring/Spring.Core/Expressions/Processors/ReverseProcessor.cs @@ -20,37 +20,36 @@ using System.Collections; -namespace Spring.Expressions.Processors +namespace Spring.Expressions.Processors; + +/// +/// Reverts order of elements in the list +/// +/// Erich Eichinger +public class ReverseProcessor : ICollectionProcessor { /// - /// Reverts order of elements in the list + /// Processes a list of source items and returns a result. /// - /// Erich Eichinger - public class ReverseProcessor : ICollectionProcessor + /// + /// The source list to process. + /// + /// + /// An optional processor arguments array. + /// + /// + /// The processing result. + /// + public object Process(ICollection source, object[] args) { - /// - /// Processes a list of source items and returns a result. - /// - /// - /// The source list to process. - /// - /// - /// An optional processor arguments array. - /// - /// - /// The processing result. - /// - public object Process(ICollection source, object[] args) + if (source == null || source.Count == 0) { - if (source == null || source.Count == 0) - { - return source; - } - - ArrayList list = new ArrayList(source); - list.Reverse(); - - return list; + return source; } + + ArrayList list = new ArrayList(source); + list.Reverse(); + + return list; } } diff --git a/src/Spring/Spring.Core/Expressions/Processors/SortProcessor.cs b/src/Spring/Spring.Core/Expressions/Processors/SortProcessor.cs index b6602360..6ccffee6 100644 --- a/src/Spring/Spring.Core/Expressions/Processors/SortProcessor.cs +++ b/src/Spring/Spring.Core/Expressions/Processors/SortProcessor.cs @@ -21,70 +21,70 @@ using System.Collections; using Spring.Collections; -namespace Spring.Expressions.Processors +namespace Spring.Expressions.Processors; + +/// +/// Implementation of the sort processor. +/// +/// Aleksandar Seovic +public class SortProcessor : ICollectionProcessor { /// - /// Implementation of the sort processor. + /// Sorts the source collection. /// - /// Aleksandar Seovic - public class SortProcessor : ICollectionProcessor + /// + /// Please not that this processor requires that collection elements + /// are of a uniform type and that they implement + /// interface. + ///

+ /// If you want to perform custom sorting based on element properties + /// you should consider using instead. + /// + /// + /// The source collection to sort. + /// + /// + /// Ignored. + /// + /// + /// An array containing sorted collection elements. + /// + /// + /// If collection is not empty and it is + /// neither nor . + /// + public object Process(ICollection source, object[] args) { - ///

- /// Sorts the source collection. - /// - /// - /// Please not that this processor requires that collection elements - /// are of a uniform type and that they implement - /// interface. - ///

- /// If you want to perform custom sorting based on element properties - /// you should consider using instead. - /// - /// - /// The source collection to sort. - /// - /// - /// Ignored. - /// - /// - /// An array containing sorted collection elements. - /// - /// - /// If collection is not empty and it is - /// neither nor . - /// - public object Process(ICollection source, object[] args) + if (source == null || source.Count == 0) { - if (source == null || source.Count == 0) - { - return source; - } - - bool sortAscending = true; - if (args != null && args.Length == 1 && args[0] is bool) - { - sortAscending = (bool) args[0]; - } - - ArrayList list = new ArrayList(source); - list.Sort(); - if (!sortAscending) - { - list.Reverse(); - } - - Type elementType = DetermineElementType(list); - return list.ToArray(elementType); + return source; } - private Type DetermineElementType(IList list) + bool sortAscending = true; + if (args != null && args.Length == 1 && args[0] is bool) { - for(int i=0;i +/// Implementation of the sum aggregator. +/// +/// Aleksandar Seovic +public class SumAggregator : ICollectionProcessor { ///

- /// Implementation of the sum aggregator. + /// Returns the sum of the numeric values in the source collection. /// - /// Aleksandar Seovic - public class SumAggregator : ICollectionProcessor + /// + /// The source collection to process. + /// + /// + /// Ignored. + /// + /// + /// The sum of the numeric values in the source collection. + /// + public object Process(ICollection source, object[] args) { - /// - /// Returns the sum of the numeric values in the source collection. - /// - /// - /// The source collection to process. - /// - /// - /// Ignored. - /// - /// - /// The sum of the numeric values in the source collection. - /// - public object Process(ICollection source, object[] args) + object total = 0d; + foreach (object item in source) { - object total = 0d; - foreach (object item in source) + if (item != null) { - if (item != null) + if (NumberUtils.IsNumber(item)) { - if (NumberUtils.IsNumber(item)) - { - total = NumberUtils.Add(total, item); - } - else - { - throw new ArgumentException("Sum can only be calculated for a collection of numeric values."); - } + total = NumberUtils.Add(total, item); + } + else + { + throw new ArgumentException("Sum can only be calculated for a collection of numeric values."); } } - - return total; } + + return total; } } diff --git a/src/Spring/Spring.Core/Expressions/ProjectionNode.cs b/src/Spring/Spring.Core/Expressions/ProjectionNode.cs index 9c5a9378..d3b29508 100644 --- a/src/Spring/Spring.Core/Expressions/ProjectionNode.cs +++ b/src/Spring/Spring.Core/Expressions/ProjectionNode.cs @@ -21,57 +21,57 @@ using System.Collections; using System.Runtime.Serialization; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// Represents parsed projection node in the navigation expression. +/// +/// Aleksandar Seovic +[Serializable] +public class ProjectionNode : BaseNode { /// - /// Represents parsed projection node in the navigation expression. + /// Create a new instance /// - /// Aleksandar Seovic - [Serializable] - public class ProjectionNode : BaseNode + public ProjectionNode() : base() { - /// - /// Create a new instance - /// - public ProjectionNode():base() + } + + /// + /// Create a new instance from SerializationInfo + /// + protected ProjectionNode(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + + /// + /// Returns a containing results of evaluation + /// of projection expression against each node in the context. + /// + /// Context to evaluate expressions against. + /// Current expression evaluation context. + /// Node's value. + protected override object Get(object context, EvaluationContext evalContext) + { + IEnumerable enumerable = context as IEnumerable; + if (enumerable == null) { + throw new ArgumentException( + "Projection can only be used on an instance of the type that implements IEnumerable."); } - /// - /// Create a new instance from SerializationInfo - /// - protected ProjectionNode(SerializationInfo info, StreamingContext context) - : base(info, context) + BaseNode expression = (BaseNode) this.getFirstChild(); + IList projectedList = new ArrayList(); + using (evalContext.SwitchThisContext()) { - } - - /// - /// Returns a containing results of evaluation - /// of projection expression against each node in the context. - /// - /// Context to evaluate expressions against. - /// Current expression evaluation context. - /// Node's value. - protected override object Get(object context, EvaluationContext evalContext) - { - IEnumerable enumerable = context as IEnumerable; - if(enumerable == null) + foreach (object o in enumerable) { - throw new ArgumentException( - "Projection can only be used on an instance of the type that implements IEnumerable."); + evalContext.ThisContext = o; + projectedList.Add(GetValue(expression, o, evalContext)); } - - BaseNode expression = (BaseNode) this.getFirstChild(); - IList projectedList = new ArrayList(); - using (evalContext.SwitchThisContext()) - { - foreach(object o in enumerable) - { - evalContext.ThisContext = o; - projectedList.Add(GetValue(expression, o, evalContext)); - } - } - return projectedList; } + + return projectedList; } } diff --git a/src/Spring/Spring.Core/Expressions/PropertyOrFieldNode.cs b/src/Spring/Spring.Core/Expressions/PropertyOrFieldNode.cs index 6143a3d2..fe031e0c 100644 --- a/src/Spring/Spring.Core/Expressions/PropertyOrFieldNode.cs +++ b/src/Spring/Spring.Core/Expressions/PropertyOrFieldNode.cs @@ -23,7 +23,6 @@ using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Remoting; using System.Runtime.Serialization; - using Spring.Collections; using Spring.Core; using Spring.Core.TypeConversion; @@ -31,148 +30,169 @@ using Spring.Core.TypeResolution; using Spring.Util; using Spring.Reflection.Dynamic; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// Represents node that navigates to object's property or public field. +/// +/// Aleksandar Seovic +[Serializable] +public class PropertyOrFieldNode : BaseNode { + private const BindingFlags BINDING_FLAGS = + BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | + BindingFlags.IgnoreCase; + + private string memberName; + private IValueAccessor accessor; + /// - /// Represents node that navigates to object's property or public field. + /// Create a new instance /// - /// Aleksandar Seovic - [Serializable] - public class PropertyOrFieldNode : BaseNode + public PropertyOrFieldNode() { - private const BindingFlags BINDING_FLAGS = - BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | - BindingFlags.IgnoreCase; + } - private string memberName; - private IValueAccessor accessor; + /// + /// Create a new instance from SerializationInfo + /// + protected PropertyOrFieldNode(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } - /// - /// Create a new instance - /// - public PropertyOrFieldNode() + /// + /// Initializes the node. + /// + /// The parent. + private void InitializeNode(object context) + { + Type contextType = (context == null || context is Type ? context as Type : context.GetType()); + + if (accessor == null || accessor.RequiresRefresh(contextType)) { - } + memberName = this.getText(); - /// - /// Create a new instance from SerializationInfo - /// - protected PropertyOrFieldNode(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } - - /// - /// Initializes the node. - /// - /// The parent. - private void InitializeNode(object context) - { - Type contextType = (context == null || context is Type ? context as Type : context.GetType()); - - if (accessor == null || accessor.RequiresRefresh(contextType)) + // clear cached member info if context type has changed (for example, when ASP.NET page is recompiled) + if (accessor != null && accessor.RequiresRefresh(contextType)) { - memberName = this.getText(); + accessor = null; + } - // clear cached member info if context type has changed (for example, when ASP.NET page is recompiled) - if (accessor != null && accessor.RequiresRefresh(contextType)) + // initialize this node if necessary + if (contextType != null && accessor == null) + { + // try to initialize node as ExpandoObject value + if (contextType == typeof(System.Dynamic.ExpandoObject)) { - accessor = null; + accessor = new ExpandoObjectValueAccessor(memberName); } - - // initialize this node if necessary - if (contextType != null && accessor == null) + // try to initialize node as DynamicObject value + else if (contextType.IsSubclassOf(typeof(System.Dynamic.DynamicObject))) { - // try to initialize node as ExpandoObject value - if (contextType == typeof(System.Dynamic.ExpandoObject)) - { - accessor = new ExpandoObjectValueAccessor(memberName); - } - // try to initialize node as DynamicObject value - else if (contextType.IsSubclassOf(typeof(System.Dynamic.DynamicObject))) - { - accessor = new DynamicObjectValueAccessor(memberName); - } - // try to initialize node as enum value first - else if (contextType.IsEnum) - { - try - { - accessor = new EnumValueAccessor(Enum.Parse(contextType, memberName, true)); - } - catch (ArgumentException) - { - // ArgumentException will be thrown if specified member name is not a valid - // enum value for the context type. We should just ignore it and continue processing, - // because the specified member could be a property of a Type class (i.e. EnumType.FullName) - } - } - - // then try to initialize node as property or field value - if (accessor == null) - { - // check the context type first - accessor = GetPropertyOrFieldAccessor(contextType, memberName, BINDING_FLAGS); - - // if not found, probe the Type type - if (accessor == null && context is Type) - { - accessor = GetPropertyOrFieldAccessor(typeof(Type), memberName, BINDING_FLAGS); - } - } + accessor = new DynamicObjectValueAccessor(memberName); } - - // if there is still no match, try to initialize node as type accessor - if (accessor == null) + // try to initialize node as enum value first + else if (contextType.IsEnum) { try { - accessor = new TypeValueAccessor(TypeResolutionUtils.ResolveType(memberName)); + accessor = new EnumValueAccessor(Enum.Parse(contextType, memberName, true)); } - catch (TypeLoadException) + catch (ArgumentException) { - if (context == null) - { - throw new NullValueInNestedPathException("Cannot initialize property or field node '" + - memberName + - "' because the specified context is null."); - } - else - { - throw new InvalidPropertyException(contextType, memberName, - "'" + memberName + - "' node cannot be resolved for the specified context [" + - context + "]."); - } + // ArgumentException will be thrown if specified member name is not a valid + // enum value for the context type. We should just ignore it and continue processing, + // because the specified member could be a property of a Type class (i.e. EnumType.FullName) + } + } + + // then try to initialize node as property or field value + if (accessor == null) + { + // check the context type first + accessor = GetPropertyOrFieldAccessor(contextType, memberName, BINDING_FLAGS); + + // if not found, probe the Type type + if (accessor == null && context is Type) + { + accessor = GetPropertyOrFieldAccessor(typeof(Type), memberName, BINDING_FLAGS); + } + } + } + + // if there is still no match, try to initialize node as type accessor + if (accessor == null) + { + try + { + accessor = new TypeValueAccessor(TypeResolutionUtils.ResolveType(memberName)); + } + catch (TypeLoadException) + { + if (context == null) + { + throw new NullValueInNestedPathException("Cannot initialize property or field node '" + + memberName + + "' because the specified context is null."); + } + else + { + throw new InvalidPropertyException(contextType, memberName, + "'" + memberName + + "' node cannot be resolved for the specified context [" + + context + "]."); } } } } + } - /// - /// Attempts to resolve property or field. - /// - /// - /// Type to search for a property or a field. - /// - /// - /// Property or field name. - /// - /// - /// Binding flags to use. - /// - /// - /// Resolved property or field accessor, or null - /// if specified cannot be resolved. - /// - private static IValueAccessor GetPropertyOrFieldAccessor(Type contextType, string memberName, BindingFlags bindingFlags) + /// + /// Attempts to resolve property or field. + /// + /// + /// Type to search for a property or a field. + /// + /// + /// Property or field name. + /// + /// + /// Binding flags to use. + /// + /// + /// Resolved property or field accessor, or null + /// if specified cannot be resolved. + /// + private static IValueAccessor GetPropertyOrFieldAccessor(Type contextType, string memberName, BindingFlags bindingFlags) + { + try { - try + PropertyInfo pi = contextType.GetProperty(memberName, bindingFlags); + if (pi == null) { - PropertyInfo pi = contextType.GetProperty(memberName, bindingFlags); + FieldInfo fi = contextType.GetField(memberName, bindingFlags); + if (fi != null) + { + return new FieldValueAccessor(fi); + } + } + else + { + return new PropertyValueAccessor(pi); + } + } + catch (AmbiguousMatchException) + { + PropertyInfo pi = null; + + // search type hierarchy + while (contextType != typeof(object)) + { + pi = contextType.GetProperty(memberName, bindingFlags | BindingFlags.DeclaredOnly); if (pi == null) { - FieldInfo fi = contextType.GetField(memberName, bindingFlags); + FieldInfo fi = contextType.GetField(memberName, bindingFlags | BindingFlags.DeclaredOnly); if (fi != null) { return new FieldValueAccessor(fi); @@ -182,629 +202,613 @@ namespace Spring.Expressions { return new PropertyValueAccessor(pi); } + + contextType = contextType.BaseType; } - catch (AmbiguousMatchException) + } + + return null; + } + + /// + /// Returns node's value for the given context. + /// + /// Context to evaluate expressions against. + /// Current expression evaluation context. + /// Node's value. + protected override object Get(object context, EvaluationContext evalContext) + { + lock (this) + { + InitializeNode(context); + + if (context == null && accessor.RequiresContext) { - PropertyInfo pi = null; - - // search type hierarchy - while (contextType != typeof(object)) - { - pi = contextType.GetProperty(memberName, bindingFlags | BindingFlags.DeclaredOnly); - if (pi == null) - { - FieldInfo fi = contextType.GetField(memberName, bindingFlags | BindingFlags.DeclaredOnly); - if (fi != null) - { - return new FieldValueAccessor(fi); - } - } - else - { - return new PropertyValueAccessor(pi); - } - contextType = contextType.BaseType; - } + throw new NullValueInNestedPathException( + "Cannot retrieve the value of a field or property '" + this.memberName + + "', because context for its resolution is null."); } - return null; - } - - /// - /// Returns node's value for the given context. - /// - /// Context to evaluate expressions against. - /// Current expression evaluation context. - /// Node's value. - protected override object Get(object context, EvaluationContext evalContext) - { - lock (this) + if (IsProperty || IsField) { - InitializeNode(context); - - if (context == null && accessor.RequiresContext) - { - throw new NullValueInNestedPathException( - "Cannot retrieve the value of a field or property '" + this.memberName - + "', because context for its resolution is null."); - } - if (IsProperty || IsField) - { - return GetPropertyOrFieldValue(context, evalContext); - } - else - { - return accessor.Get(context); - } + return GetPropertyOrFieldValue(context, evalContext); } - } - - /// - /// Sets node's value for the given context. - /// - /// Context to evaluate expressions against. - /// Current expression evaluation context. - /// New value for this node. - protected override void Set(object context, EvaluationContext evalContext, object newValue) - { - lock (this) - { - InitializeNode(context); - - if (context == null && accessor.RequiresContext) - { - throw new NullValueInNestedPathException( - "Cannot set the value of a field or property '" + this.memberName - + "', because context for its resolution is null."); - } - if (IsProperty || IsField) - { - SetPropertyOrFieldValue(context, evalContext, newValue); - } - else - { - accessor.Set(context, newValue); - } - } - } - - /// - /// Gets a value indicating whether this node represents a property. - /// - /// - /// true if this node is a property; otherwise, false. - /// - private bool IsProperty - { - get { return accessor is PropertyValueAccessor; } - } - - /// - /// Gets a value indicating whether this node represents a field. - /// - /// - /// true if this node is a field; otherwise, false. - /// - private bool IsField - { - get { return accessor is FieldValueAccessor; } - } - - /// - /// Retrieves property or field value. - /// - /// Context to evaluate expressions against. - /// Current expression evaluation context. - /// Property or field value. - private object GetPropertyOrFieldValue(object context, EvaluationContext evalContext) - { - try + else { return accessor.Get(context); } - catch (InvalidOperationException) + } + } + + /// + /// Sets node's value for the given context. + /// + /// Context to evaluate expressions against. + /// Current expression evaluation context. + /// New value for this node. + protected override void Set(object context, EvaluationContext evalContext, object newValue) + { + lock (this) + { + InitializeNode(context); + + if (context == null && accessor.RequiresContext) { - throw new NotReadablePropertyException(evalContext.RootContextType, this.memberName); + throw new NullValueInNestedPathException( + "Cannot set the value of a field or property '" + this.memberName + + "', because context for its resolution is null."); } - catch (TargetInvocationException e) + + if (IsProperty || IsField) { - throw new InvalidPropertyException(evalContext.RootContextType, this.memberName, - "Getter for property '" + this.memberName + "' threw an exception.", - e); + SetPropertyOrFieldValue(context, evalContext, newValue); } - catch (UnauthorizedAccessException e) + else { - throw new InvalidPropertyException(evalContext.RootContextType, this.memberName, - "Illegal attempt to get value for the property '" + this.memberName + - "'.", e); + accessor.Set(context, newValue); } } + } - /// - /// Sets property value, doing any type conversions that are necessary along the way. - /// - /// Context to evaluate expressions against. - /// Current expression evaluation context. - /// New value for this node. - private void SetPropertyOrFieldValue(object context, EvaluationContext evalContext, object newValue) + /// + /// Gets a value indicating whether this node represents a property. + /// + /// + /// true if this node is a property; otherwise, false. + /// + private bool IsProperty + { + get { return accessor is PropertyValueAccessor; } + } + + /// + /// Gets a value indicating whether this node represents a field. + /// + /// + /// true if this node is a field; otherwise, false. + /// + private bool IsField + { + get { return accessor is FieldValueAccessor; } + } + + /// + /// Retrieves property or field value. + /// + /// Context to evaluate expressions against. + /// Current expression evaluation context. + /// Property or field value. + private object GetPropertyOrFieldValue(object context, EvaluationContext evalContext) + { + try { - bool isWriteable = accessor.IsWriteable; - Type targetType = accessor.TargetType; + return accessor.Get(context); + } + catch (InvalidOperationException) + { + throw new NotReadablePropertyException(evalContext.RootContextType, this.memberName); + } + catch (TargetInvocationException e) + { + throw new InvalidPropertyException(evalContext.RootContextType, this.memberName, + "Getter for property '" + this.memberName + "' threw an exception.", + e); + } + catch (UnauthorizedAccessException e) + { + throw new InvalidPropertyException(evalContext.RootContextType, this.memberName, + "Illegal attempt to get value for the property '" + this.memberName + + "'.", e); + } + } - try + /// + /// Sets property value, doing any type conversions that are necessary along the way. + /// + /// Context to evaluate expressions against. + /// Current expression evaluation context. + /// New value for this node. + private void SetPropertyOrFieldValue(object context, EvaluationContext evalContext, object newValue) + { + bool isWriteable = accessor.IsWriteable; + Type targetType = accessor.TargetType; + + try + { + if (!isWriteable) { - if (!isWriteable) + if (!AddToCollections(context, evalContext, newValue)) { - if (!AddToCollections(context, evalContext, newValue)) - { - throw new NotWritablePropertyException( - "Can't change the value of the read-only property or field '" + this.memberName + "'."); - } + throw new NotWritablePropertyException( + "Can't change the value of the read-only property or field '" + this.memberName + "'."); } - else if (targetType.IsPrimitive && (newValue == null || String.Empty.Equals(newValue))) + } + else if (targetType.IsPrimitive && (newValue == null || String.Empty.Equals(newValue))) + { + throw new ArgumentException("Invalid value [" + newValue + "] for property or field '" + + this.memberName + "' of primitive type [" + + targetType + "]"); + } + else if (newValue == null || ObjectUtils.IsAssignable(targetType, newValue)) // targetType.IsAssignableFrom(newValue.GetType()) + { + SetPropertyOrFieldValueInternal(context, newValue); + } + else if (!RemotingServices.IsTransparentProxy(newValue) && + (newValue is IList || newValue is IDictionary || newValue is ISet)) + { + if (!AddToCollections(context, evalContext, newValue)) { - throw new ArgumentException("Invalid value [" + newValue + "] for property or field '" + - this.memberName + "' of primitive type [" - + targetType + "]"); - } - else if (newValue == null || ObjectUtils.IsAssignable(targetType, newValue)) // targetType.IsAssignableFrom(newValue.GetType()) - { - SetPropertyOrFieldValueInternal(context, newValue); - } - else if (!RemotingServices.IsTransparentProxy(newValue) && - (newValue is IList || newValue is IDictionary || newValue is ISet)) - { - if (!AddToCollections(context, evalContext, newValue)) - { - object tmpValue = - TypeConversionUtils.ConvertValueIfNecessary(targetType, newValue, this.memberName); - SetPropertyOrFieldValueInternal(context, tmpValue); - } - } - else - { - object tmpValue = TypeConversionUtils.ConvertValueIfNecessary(targetType, newValue, this.memberName); + object tmpValue = + TypeConversionUtils.ConvertValueIfNecessary(targetType, newValue, this.memberName); SetPropertyOrFieldValueInternal(context, tmpValue); } } - catch (TargetInvocationException ex) + else { - PropertyChangeEventArgs propertyChangeEvent = - new PropertyChangeEventArgs(this.memberName, null, newValue); - if (ex.GetBaseException() is InvalidCastException) - { - throw new TypeMismatchException(propertyChangeEvent, targetType, ex.GetBaseException()); - } - else - { - throw new MethodInvocationException(ex.GetBaseException(), propertyChangeEvent); - } - } - catch (UnauthorizedAccessException ex) - { - throw new FatalReflectionException("Illegal attempt to set property '" + this.memberName + "'", ex); - } - catch (NotWritablePropertyException) - { - throw; - } - catch (NotReadablePropertyException) - { - throw; - } - catch (ArgumentException ex) - { - PropertyChangeEventArgs propertyChangeEvent = - new PropertyChangeEventArgs(this.memberName, null, newValue); - throw new TypeMismatchException(propertyChangeEvent, targetType, ex); + object tmpValue = TypeConversionUtils.ConvertValueIfNecessary(targetType, newValue, this.memberName); + SetPropertyOrFieldValueInternal(context, tmpValue); } } - - /// - /// Sets property or field value using either dynamic or standard reflection. - /// - /// Object to evaluate node against. - /// New value for this node, converted to appropriate type. - private void SetPropertyOrFieldValueInternal(object context, object newValue) + catch (TargetInvocationException ex) { - accessor.Set(context, newValue); + PropertyChangeEventArgs propertyChangeEvent = + new PropertyChangeEventArgs(this.memberName, null, newValue); + if (ex.GetBaseException() is InvalidCastException) + { + throw new TypeMismatchException(propertyChangeEvent, targetType, ex.GetBaseException()); + } + else + { + throw new MethodInvocationException(ex.GetBaseException(), propertyChangeEvent); + } } - - /// - /// In the case of read only collections or custom collections that are not assignable from - /// IList, try to add to the collection. - /// - /// Context to evaluate expressions against. - /// Current expression evaluation context. - /// New value for this node. - /// true if was able add to IList, IDictionary, or ISet - private bool AddToCollections(object context, EvaluationContext evalContext, object newValue) + catch (UnauthorizedAccessException ex) { - // short-circuit if accessor is not readable or if we have an array - if (!this.accessor.IsReadable || this.accessor.TargetType.IsArray) - { - return false; - } - - bool added = false; - - // try adding values if property is a list... - if (newValue is IList && !RemotingServices.IsTransparentProxy(newValue)) - { - IList currentValue = (IList)Get(context, evalContext); - if (currentValue != null && !currentValue.IsFixedSize && !currentValue.IsReadOnly) - { - foreach (object el in (IList)newValue) - { - currentValue.Add(el); - } - added = true; - } - } - // try adding values if property is a dictionary... - else if (newValue is IDictionary && !RemotingServices.IsTransparentProxy(newValue)) - { - IDictionary currentValue = (IDictionary)Get(context, evalContext); - if (currentValue != null && !currentValue.IsFixedSize && !currentValue.IsReadOnly) - { - foreach (DictionaryEntry entry in (IDictionary)newValue) - { - currentValue[entry.Key] = entry.Value; - } - added = true; - } - } - // try adding values if property is a set... - else if (newValue is ISet && !RemotingServices.IsTransparentProxy(newValue)) - { - ISet currentValue = (ISet)Get(context, evalContext); - if (currentValue != null) - { - currentValue.AddAll((ICollection)newValue); - added = true; - } - } - return added; + throw new FatalReflectionException("Illegal attempt to set property '" + this.memberName + "'", ex); } - - /// - /// Utility method that is needed by ObjectWrapper and AbstractAutowireCapableObjectFactory. - /// We try as hard as we can, but there are instances when we won't be able to obtain PropertyInfo... - /// - /// Context to resolve property against. - /// PropertyInfo for this node. - internal MemberInfo GetMemberInfo(object context) + catch (NotWritablePropertyException) { - lock (this) - { - InitializeNode(context); - } - return accessor.MemberInfo; - - //if (IsProperty) - //{ - // return (((PropertyValueAccessor) accessor).MemberInfo); - //} - //else - //{ - // throw new FatalObjectException( - // "Cannot obtain PropertyInfo from an expression that does not resolve to a property."); - //} + throw; } - - #region IValueAccessor interface - - private interface IValueAccessor + catch (NotReadablePropertyException) { - object Get(object context); - void Set(object context, object value); - - bool IsReadable { get; } - bool IsWriteable { get; } - bool RequiresContext { get; } - Type TargetType { get; } - MemberInfo MemberInfo { get; } - bool RequiresRefresh(Type contextType); + throw; } - - #endregion - - #region BaseValueAccessor implementation - - private abstract class BaseValueAccessor : IValueAccessor + catch (ArgumentException ex) { - public abstract object Get(object context); - - public abstract void Set(object context, object value); - - public virtual bool IsReadable - { - get { return true; } - } - - public virtual bool IsWriteable - { - get { return false; } - } - - public virtual bool RequiresContext - { - get { return false; } - } - - public virtual Type TargetType - { - get { throw new NotSupportedException(); } - } - - public virtual MemberInfo MemberInfo - { - get { throw new NotSupportedException(); } - } - - public virtual bool RequiresRefresh(Type contextType) - { - return false; - } + PropertyChangeEventArgs propertyChangeEvent = + new PropertyChangeEventArgs(this.memberName, null, newValue); + throw new TypeMismatchException(propertyChangeEvent, targetType, ex); } - - #endregion - - #region PropertyValueAccessor implementation - - private class PropertyValueAccessor : BaseValueAccessor - { - private SafeProperty property; - private string name; - private bool isReadable; - private bool isWriteable; - private Type targetType; - private Type contextType; - - public PropertyValueAccessor(PropertyInfo propertyInfo) - { - this.name = propertyInfo.Name; - this.isReadable = propertyInfo.CanRead; - this.isWriteable = propertyInfo.CanWrite; - this.targetType = propertyInfo.PropertyType; - this.contextType = propertyInfo.DeclaringType; - this.property = new SafeProperty(propertyInfo); - } - - public override object Get(object context) - { - if (!isReadable) - { - throw new NotReadablePropertyException("Cannot get a non-readable property [" + name + "]"); - } - return property.GetValue(context); - } - - public override void Set(object context, object value) - { - if (!isWriteable) - { - throw new NotWritablePropertyException("Cannot set a read-only property [" + name + "]"); - } - property.SetValue(context, value); - } - - public override bool IsReadable - { - get { return isReadable; } - } - - public override bool IsWriteable - { - get { return isWriteable; } - } - - public override bool RequiresContext - { - get { return true; } - } - - public override Type TargetType - { - get { return targetType; } - } - - public override MemberInfo MemberInfo - { - get { return property.PropertyInfo; } - } - - public override bool RequiresRefresh(Type contextType) - { - return this.contextType != contextType; - } - } - - #endregion - - #region FieldValueAccessor implementation - - private class FieldValueAccessor : BaseValueAccessor - { - private SafeField field; - private bool isWriteable; - private Type targetType; - private Type contextType; - - public FieldValueAccessor(FieldInfo fieldInfo) - { - this.field = new SafeField(fieldInfo); - this.isWriteable = !(fieldInfo.IsInitOnly || fieldInfo.IsLiteral); - this.targetType = fieldInfo.FieldType; - this.contextType = fieldInfo.DeclaringType; - } - - public override object Get(object context) - { - return field.GetValue(context); - } - - public override void Set(object context, object value) - { - field.SetValue(context, value); - } - - public override bool IsWriteable - { - get { return isWriteable; } - } - - public override bool RequiresContext - { - get { return true; } - } - - public override Type TargetType - { - get { return targetType; } - } - - public override MemberInfo MemberInfo - { - get { return field.FieldInfo; } - } - - public override bool RequiresRefresh(Type contextType) - { - return this.contextType != contextType; - } - } - - #endregion - - #region EnumValueAccessor implementation - - private class EnumValueAccessor : BaseValueAccessor - { - private object enumValue; - - public EnumValueAccessor(object enumValue) - { - this.enumValue = enumValue; - } - - public override object Get(object context) - { - return enumValue; - } - - public override void Set(object context, object value) - { - throw new NotSupportedException("Cannot set the value of an enum."); - } - } - - #endregion - - #region ExpandoObjectValueAccessor implementation - - private class ExpandoObjectValueAccessor : BaseValueAccessor - { - private string memberName; - - public ExpandoObjectValueAccessor(string memberName) - { - this.memberName = memberName; - } - - public override object Get(object context) - { - var dictionary = context as IDictionary; - - object value; - if (dictionary.TryGetValue(memberName, out value)) - return value; - throw new InvalidPropertyException(typeof(System.Dynamic.ExpandoObject), memberName, - "'" + memberName + - "' node cannot be resolved for the specified context [" + - context + "]."); - } - - public override void Set(object context, object value) - { - throw new NotSupportedException("Cannot set the value of an expando object."); - } - } - - #endregion - - #region DynamicObjectValueAccessor implementation - - private class DynamicObjectValueAccessor : BaseValueAccessor - { - private string memberName; - - public DynamicObjectValueAccessor(string memberName) - { - this.memberName = memberName; - } - - public override object Get(object context) - { - var dynamicObject = context as System.Dynamic.DynamicObject; - - try - { - var binder = Microsoft.CSharp.RuntimeBinder.Binder.GetMember( - Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags.None, - memberName, - dynamicObject.GetType(), - new List - { - Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create(Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags.None, null) - } - ); - - var callsite = CallSite>.Create(binder); - - return callsite.Target(callsite, dynamicObject); - } - catch (Microsoft.CSharp.RuntimeBinder.RuntimeBinderException runtimeBinderException) - { - throw new InvalidPropertyException( - typeof(System.Dynamic.DynamicObject), - memberName, - "'" + memberName + "' node cannot be resolved for the specified context [" + context + "].", - runtimeBinderException - ); - } - } - - public override void Set(object context, object value) - { - throw new NotSupportedException("Cannot set the value of an dynamic object."); - } - } - - #endregion - - #region TypeValueAccessor implementation - - private class TypeValueAccessor : BaseValueAccessor - { - private Type type; - - public TypeValueAccessor(Type type) - { - this.type = type; - } - - public override object Get(object context) - { - return type; - } - - public override void Set(object context, object value) - { - throw new NotSupportedException("Cannot set the value of a type."); - } - } - - #endregion } + + /// + /// Sets property or field value using either dynamic or standard reflection. + /// + /// Object to evaluate node against. + /// New value for this node, converted to appropriate type. + private void SetPropertyOrFieldValueInternal(object context, object newValue) + { + accessor.Set(context, newValue); + } + + /// + /// In the case of read only collections or custom collections that are not assignable from + /// IList, try to add to the collection. + /// + /// Context to evaluate expressions against. + /// Current expression evaluation context. + /// New value for this node. + /// true if was able add to IList, IDictionary, or ISet + private bool AddToCollections(object context, EvaluationContext evalContext, object newValue) + { + // short-circuit if accessor is not readable or if we have an array + if (!this.accessor.IsReadable || this.accessor.TargetType.IsArray) + { + return false; + } + + bool added = false; + + // try adding values if property is a list... + if (newValue is IList && !RemotingServices.IsTransparentProxy(newValue)) + { + IList currentValue = (IList) Get(context, evalContext); + if (currentValue != null && !currentValue.IsFixedSize && !currentValue.IsReadOnly) + { + foreach (object el in (IList) newValue) + { + currentValue.Add(el); + } + + added = true; + } + } + // try adding values if property is a dictionary... + else if (newValue is IDictionary && !RemotingServices.IsTransparentProxy(newValue)) + { + IDictionary currentValue = (IDictionary) Get(context, evalContext); + if (currentValue != null && !currentValue.IsFixedSize && !currentValue.IsReadOnly) + { + foreach (DictionaryEntry entry in (IDictionary) newValue) + { + currentValue[entry.Key] = entry.Value; + } + + added = true; + } + } + // try adding values if property is a set... + else if (newValue is ISet && !RemotingServices.IsTransparentProxy(newValue)) + { + ISet currentValue = (ISet) Get(context, evalContext); + if (currentValue != null) + { + currentValue.AddAll((ICollection) newValue); + added = true; + } + } + + return added; + } + + /// + /// Utility method that is needed by ObjectWrapper and AbstractAutowireCapableObjectFactory. + /// We try as hard as we can, but there are instances when we won't be able to obtain PropertyInfo... + /// + /// Context to resolve property against. + /// PropertyInfo for this node. + internal MemberInfo GetMemberInfo(object context) + { + lock (this) + { + InitializeNode(context); + } + + return accessor.MemberInfo; + + //if (IsProperty) + //{ + // return (((PropertyValueAccessor) accessor).MemberInfo); + //} + //else + //{ + // throw new FatalObjectException( + // "Cannot obtain PropertyInfo from an expression that does not resolve to a property."); + //} + } + + #region IValueAccessor interface + + private interface IValueAccessor + { + object Get(object context); + void Set(object context, object value); + + bool IsReadable { get; } + bool IsWriteable { get; } + bool RequiresContext { get; } + Type TargetType { get; } + MemberInfo MemberInfo { get; } + bool RequiresRefresh(Type contextType); + } + + #endregion + + #region BaseValueAccessor implementation + + private abstract class BaseValueAccessor : IValueAccessor + { + public abstract object Get(object context); + + public abstract void Set(object context, object value); + + public virtual bool IsReadable + { + get { return true; } + } + + public virtual bool IsWriteable + { + get { return false; } + } + + public virtual bool RequiresContext + { + get { return false; } + } + + public virtual Type TargetType + { + get { throw new NotSupportedException(); } + } + + public virtual MemberInfo MemberInfo + { + get { throw new NotSupportedException(); } + } + + public virtual bool RequiresRefresh(Type contextType) + { + return false; + } + } + + #endregion + + #region PropertyValueAccessor implementation + + private class PropertyValueAccessor : BaseValueAccessor + { + private SafeProperty property; + private string name; + private bool isReadable; + private bool isWriteable; + private Type targetType; + private Type contextType; + + public PropertyValueAccessor(PropertyInfo propertyInfo) + { + this.name = propertyInfo.Name; + this.isReadable = propertyInfo.CanRead; + this.isWriteable = propertyInfo.CanWrite; + this.targetType = propertyInfo.PropertyType; + this.contextType = propertyInfo.DeclaringType; + this.property = new SafeProperty(propertyInfo); + } + + public override object Get(object context) + { + if (!isReadable) + { + throw new NotReadablePropertyException("Cannot get a non-readable property [" + name + "]"); + } + + return property.GetValue(context); + } + + public override void Set(object context, object value) + { + if (!isWriteable) + { + throw new NotWritablePropertyException("Cannot set a read-only property [" + name + "]"); + } + + property.SetValue(context, value); + } + + public override bool IsReadable + { + get { return isReadable; } + } + + public override bool IsWriteable + { + get { return isWriteable; } + } + + public override bool RequiresContext + { + get { return true; } + } + + public override Type TargetType + { + get { return targetType; } + } + + public override MemberInfo MemberInfo + { + get { return property.PropertyInfo; } + } + + public override bool RequiresRefresh(Type contextType) + { + return this.contextType != contextType; + } + } + + #endregion + + #region FieldValueAccessor implementation + + private class FieldValueAccessor : BaseValueAccessor + { + private SafeField field; + private bool isWriteable; + private Type targetType; + private Type contextType; + + public FieldValueAccessor(FieldInfo fieldInfo) + { + this.field = new SafeField(fieldInfo); + this.isWriteable = !(fieldInfo.IsInitOnly || fieldInfo.IsLiteral); + this.targetType = fieldInfo.FieldType; + this.contextType = fieldInfo.DeclaringType; + } + + public override object Get(object context) + { + return field.GetValue(context); + } + + public override void Set(object context, object value) + { + field.SetValue(context, value); + } + + public override bool IsWriteable + { + get { return isWriteable; } + } + + public override bool RequiresContext + { + get { return true; } + } + + public override Type TargetType + { + get { return targetType; } + } + + public override MemberInfo MemberInfo + { + get { return field.FieldInfo; } + } + + public override bool RequiresRefresh(Type contextType) + { + return this.contextType != contextType; + } + } + + #endregion + + #region EnumValueAccessor implementation + + private class EnumValueAccessor : BaseValueAccessor + { + private object enumValue; + + public EnumValueAccessor(object enumValue) + { + this.enumValue = enumValue; + } + + public override object Get(object context) + { + return enumValue; + } + + public override void Set(object context, object value) + { + throw new NotSupportedException("Cannot set the value of an enum."); + } + } + + #endregion + + #region ExpandoObjectValueAccessor implementation + + private class ExpandoObjectValueAccessor : BaseValueAccessor + { + private string memberName; + + public ExpandoObjectValueAccessor(string memberName) + { + this.memberName = memberName; + } + + public override object Get(object context) + { + var dictionary = context as IDictionary; + + object value; + if (dictionary.TryGetValue(memberName, out value)) + return value; + throw new InvalidPropertyException(typeof(System.Dynamic.ExpandoObject), memberName, + "'" + memberName + + "' node cannot be resolved for the specified context [" + + context + "]."); + } + + public override void Set(object context, object value) + { + throw new NotSupportedException("Cannot set the value of an expando object."); + } + } + + #endregion + + #region DynamicObjectValueAccessor implementation + + private class DynamicObjectValueAccessor : BaseValueAccessor + { + private string memberName; + + public DynamicObjectValueAccessor(string memberName) + { + this.memberName = memberName; + } + + public override object Get(object context) + { + var dynamicObject = context as System.Dynamic.DynamicObject; + + try + { + var binder = Microsoft.CSharp.RuntimeBinder.Binder.GetMember( + Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags.None, + memberName, + dynamicObject.GetType(), + new List { Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create(Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags.None, null) } + ); + + var callsite = CallSite>.Create(binder); + + return callsite.Target(callsite, dynamicObject); + } + catch (Microsoft.CSharp.RuntimeBinder.RuntimeBinderException runtimeBinderException) + { + throw new InvalidPropertyException( + typeof(System.Dynamic.DynamicObject), + memberName, + "'" + memberName + "' node cannot be resolved for the specified context [" + context + "].", + runtimeBinderException + ); + } + } + + public override void Set(object context, object value) + { + throw new NotSupportedException("Cannot set the value of an dynamic object."); + } + } + + #endregion + + #region TypeValueAccessor implementation + + private class TypeValueAccessor : BaseValueAccessor + { + private Type type; + + public TypeValueAccessor(Type type) + { + this.type = type; + } + + public override object Get(object context) + { + return type; + } + + public override void Set(object context, object value) + { + throw new NotSupportedException("Cannot set the value of a type."); + } + } + + #endregion } diff --git a/src/Spring/Spring.Core/Expressions/QualifiedIdentifier.cs b/src/Spring/Spring.Core/Expressions/QualifiedIdentifier.cs index e5592f14..65bbf1e3 100644 --- a/src/Spring/Spring.Core/Expressions/QualifiedIdentifier.cs +++ b/src/Spring/Spring.Core/Expressions/QualifiedIdentifier.cs @@ -21,76 +21,76 @@ using System.Runtime.Serialization; using Spring.Expressions.Parser.antlr.collections; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// Represents parsed named argument node in the expression. +/// +/// Aleksandar Seovic +[Serializable] +public class QualifiedIdentifier : BaseNode { + private string identifier; + /// - /// Represents parsed named argument node in the expression. + /// Create a new instance /// - /// Aleksandar Seovic - [Serializable] - public class QualifiedIdentifier : BaseNode + public QualifiedIdentifier() + : base() { - private string identifier; + } - /// - /// Create a new instance - /// - public QualifiedIdentifier() - : base() - { - } + /// + /// Create a new instance from SerializationInfo + /// + protected QualifiedIdentifier(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } - /// - /// Create a new instance from SerializationInfo - /// - protected QualifiedIdentifier(SerializationInfo info, StreamingContext context) - : base(info, context) + /// + /// Returns the value of the named argument defined by this node. + /// + /// Context to evaluate expressions against. + /// Current expression evaluation context. + /// Node's value. + protected override object Get(object context, EvaluationContext evalContext) + { + if (identifier == null) { - } - - /// - /// Returns the value of the named argument defined by this node. - /// - /// Context to evaluate expressions against. - /// Current expression evaluation context. - /// Node's value. - protected override object Get(object context, EvaluationContext evalContext) - { - if (identifier == null) + lock (this) { - lock (this) + if (identifier == null) { - if (identifier == null) - { - identifier = this.getText(); - } + identifier = this.getText(); } } - - return identifier; } - /// - /// Overrides getText to allow easy way to get fully - /// qualified identifier. - /// - /// - /// Fully qualified identifier as a string. - /// - public override string getText() - { - string tmp = base.getText(); + return identifier; + } + + /// + /// Overrides getText to allow easy way to get fully + /// qualified identifier. + /// + /// + /// Fully qualified identifier as a string. + /// + public override string getText() + { + string tmp = base.getText(); // if (tmp != null) // { // tmp = tmp.Replace(ESCAPE_CHAR, ""); // remove all occurrences of escape char // } - AST node = this.getFirstChild(); - while (node != null) - { - tmp = string.Concat(tmp, node.getText()); - node = node.getNextSibling(); - } - return tmp; + AST node = this.getFirstChild(); + while (node != null) + { + tmp = string.Concat(tmp, node.getText()); + node = node.getNextSibling(); } + + return tmp; } -} +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Expressions/RealLiteralNode.cs b/src/Spring/Spring.Core/Expressions/RealLiteralNode.cs index 2a9835a7..79aabd2b 100644 --- a/src/Spring/Spring.Core/Expressions/RealLiteralNode.cs +++ b/src/Spring/Spring.Core/Expressions/RealLiteralNode.cs @@ -21,73 +21,72 @@ using System.Globalization; using System.Runtime.Serialization; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// Represents parsed real literal node. +/// +/// Aleksandar Seovic +[Serializable] +public class RealLiteralNode : BaseNode { + private object nodeValue; + /// - /// Represents parsed real literal node. + /// Create a new instance /// - /// Aleksandar Seovic - [Serializable] - public class RealLiteralNode : BaseNode + public RealLiteralNode() : base() { - private object nodeValue; + } - /// - /// Create a new instance - /// - public RealLiteralNode():base() - { - } + /// + /// Create a new instance from SerializationInfo + /// + protected RealLiteralNode(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } - /// - /// Create a new instance from SerializationInfo - /// - protected RealLiteralNode(SerializationInfo info, StreamingContext context) - : base(info, context) + /// + /// Returns a value for the real literal node. + /// + /// Context to evaluate expressions against. + /// Current expression evaluation context. + /// Node's value. + protected override object Get(object context, EvaluationContext evalContext) + { + if (nodeValue == null) { - } - - /// - /// Returns a value for the real literal node. - /// - /// Context to evaluate expressions against. - /// Current expression evaluation context. - /// Node's value. - protected override object Get(object context, EvaluationContext evalContext) - { - if (nodeValue == null) + lock (this) { - lock (this) + if (nodeValue == null) { - if (nodeValue == null) + string n = this.getText(); + char lastChar = n.ToLower()[n.Length - 1]; + if (Char.IsDigit(lastChar)) { - string n = this.getText(); - char lastChar = n.ToLower()[n.Length - 1]; - if (Char.IsDigit(lastChar)) + nodeValue = Double.Parse(n, NumberFormatInfo.InvariantInfo); + } + else + { + n = n.Substring(0, n.Length - 1); + if (lastChar == 'm') { - nodeValue = Double.Parse(n, NumberFormatInfo.InvariantInfo); + nodeValue = Decimal.Parse(n, NumberFormatInfo.InvariantInfo); + } + else if (lastChar == 'f') + { + nodeValue = Single.Parse(n, NumberFormatInfo.InvariantInfo); } else { - n = n.Substring(0, n.Length - 1); - if (lastChar == 'm') - { - nodeValue = Decimal.Parse(n, NumberFormatInfo.InvariantInfo); - } - else if (lastChar == 'f') - { - nodeValue = Single.Parse(n, NumberFormatInfo.InvariantInfo); - } - else - { - nodeValue = Double.Parse(n, NumberFormatInfo.InvariantInfo); - } + nodeValue = Double.Parse(n, NumberFormatInfo.InvariantInfo); } } } } - - return nodeValue; } + + return nodeValue; } } diff --git a/src/Spring/Spring.Core/Expressions/ReferenceNode.cs b/src/Spring/Spring.Core/Expressions/ReferenceNode.cs index b28369eb..830e947c 100644 --- a/src/Spring/Spring.Core/Expressions/ReferenceNode.cs +++ b/src/Spring/Spring.Core/Expressions/ReferenceNode.cs @@ -22,77 +22,76 @@ using Spring.Expressions; using Spring.Objects.Factory; using System.Runtime.Serialization; -namespace Spring.Context.Support +namespace Spring.Context.Support; + +/// +/// Represents a reference to a Spring-managed object. +/// +/// Aleksandar Seovic +[Serializable] +public class ReferenceNode : BaseNode { /// - /// Represents a reference to a Spring-managed object. + /// Create a new instance /// - /// Aleksandar Seovic - [Serializable] - public class ReferenceNode : BaseNode + public ReferenceNode() { } + + /// + /// Create a new instance from SerializationInfo + /// + protected ReferenceNode(SerializationInfo info, StreamingContext context) + : base(info, context) { - /// - /// Create a new instance - /// - public ReferenceNode() { } + } - /// - /// Create a new instance from SerializationInfo - /// - protected ReferenceNode(SerializationInfo info, StreamingContext context) - : base(info, context) + /// + /// + /// Returns a value for the integer literal node. + /// + /// Context to evaluate expressions against. + /// Current expression evaluation context. + /// Node's value. + protected override object Get(object context, EvaluationContext evalContext) + { + var objectName = ResolveNames(out var contextName); + + var sourceContext = SelectSourceContext(evalContext, contextName); + + return sourceContext.GetObject(objectName); + } + + private string ResolveNames(out string contextName) + { + var hasContextDefined = getNumberOfChildren() == 2; + + if (hasContextDefined) { + contextName = getFirstChild().getText(); + return getFirstChild().getNextSibling().getText(); } - /// - /// - /// Returns a value for the integer literal node. - /// - /// Context to evaluate expressions against. - /// Current expression evaluation context. - /// Node's value. - protected override object Get(object context, EvaluationContext evalContext) - { - var objectName = ResolveNames(out var contextName); + contextName = null; + return getFirstChild().getText(); + } - var sourceContext = SelectSourceContext(evalContext, contextName); + private static IObjectFactory SelectSourceContext(EvaluationContext evalContext, string contextName) + { + if (contextName != null) + return ContextRegistry.GetContext(contextName) ?? throw new ArgumentException($"Context '{contextName}' is not registered."); - return sourceContext.GetObject(objectName); - } + if (TryGetFromCurrentContext(evalContext, out var currentObjectFactory)) + return (IObjectFactory) currentObjectFactory; - private string ResolveNames(out string contextName) - { - var hasContextDefined = getNumberOfChildren() == 2; + return ContextRegistry.GetContext() ?? throw new ArgumentException("No context registered."); + } - if (hasContextDefined) - { - contextName = getFirstChild().getText(); - return getFirstChild().getNextSibling().getText(); - } + private static bool TryGetFromCurrentContext(EvaluationContext evalContext, out object currentObjectFactory) + { + currentObjectFactory = null; - contextName = null; - return getFirstChild().getText(); - } + if (evalContext.Variables is null) + return false; - private static IObjectFactory SelectSourceContext(EvaluationContext evalContext, string contextName) - { - if (contextName != null) - return ContextRegistry.GetContext(contextName) ?? throw new ArgumentException($"Context '{contextName}' is not registered."); - - if (TryGetFromCurrentContext(evalContext, out var currentObjectFactory)) - return (IObjectFactory) currentObjectFactory; - - return ContextRegistry.GetContext() ?? throw new ArgumentException("No context registered."); - } - - private static bool TryGetFromCurrentContext(EvaluationContext evalContext, out object currentObjectFactory) - { - currentObjectFactory = null; - - if (evalContext.Variables is null) - return false; - - return evalContext.Variables.TryGetValue(Expression.ReservedVariableNames.CurrentObjectFactory, out currentObjectFactory); - } + return evalContext.Variables.TryGetValue(Expression.ReservedVariableNames.CurrentObjectFactory, out currentObjectFactory); } } diff --git a/src/Spring/Spring.Core/Expressions/SelectionFirstNode.cs b/src/Spring/Spring.Core/Expressions/SelectionFirstNode.cs index eb73ca6d..5fceeaff 100644 --- a/src/Spring/Spring.Core/Expressions/SelectionFirstNode.cs +++ b/src/Spring/Spring.Core/Expressions/SelectionFirstNode.cs @@ -21,59 +21,59 @@ using System.Collections; using System.Runtime.Serialization; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// Represents parsed selection node in the navigation expression. +/// +/// Aleksandar Seovic +[Serializable] +public class SelectionFirstNode : BaseNode { /// - /// Represents parsed selection node in the navigation expression. + /// Create a new instance /// - /// Aleksandar Seovic - [Serializable] - public class SelectionFirstNode : BaseNode + public SelectionFirstNode() : base() { - /// - /// Create a new instance - /// - public SelectionFirstNode():base() + } + + /// + /// Create a new instance from SerializationInfo + /// + protected SelectionFirstNode(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + + /// + /// Returns the first context item that matches selection expression. + /// + /// Context to evaluate expressions against. + /// Current expression evaluation context. + /// Node's value. + protected override object Get(object context, EvaluationContext evalContext) + { + IEnumerable enumerable = context as IEnumerable; + if (enumerable == null) { + throw new ArgumentException( + "Selection can only be used on an instance of the type that implements IEnumerable."); } - /// - /// Create a new instance from SerializationInfo - /// - protected SelectionFirstNode(SerializationInfo info, StreamingContext context) - : base(info, context) + BaseNode expression = (BaseNode) this.getFirstChild(); + using (evalContext.SwitchThisContext()) { - } - - /// - /// Returns the first context item that matches selection expression. - /// - /// Context to evaluate expressions against. - /// Current expression evaluation context. - /// Node's value. - protected override object Get(object context, EvaluationContext evalContext) - { - IEnumerable enumerable = context as IEnumerable; - if (enumerable == null) + foreach (object o in enumerable) { - throw new ArgumentException( - "Selection can only be used on an instance of the type that implements IEnumerable."); - } - - BaseNode expression = (BaseNode) this.getFirstChild(); - using (evalContext.SwitchThisContext()) - { - foreach (object o in enumerable) + evalContext.ThisContext = o; + bool isMatch = (bool) GetValue(expression, o, evalContext); + if (isMatch) { - evalContext.ThisContext = o; - bool isMatch = (bool)GetValue(expression, o, evalContext); - if (isMatch) - { - return o; - } + return o; } } - return null; } + + return null; } } diff --git a/src/Spring/Spring.Core/Expressions/SelectionLastNode.cs b/src/Spring/Spring.Core/Expressions/SelectionLastNode.cs index d1439059..fa42075c 100644 --- a/src/Spring/Spring.Core/Expressions/SelectionLastNode.cs +++ b/src/Spring/Spring.Core/Expressions/SelectionLastNode.cs @@ -21,61 +21,61 @@ using System.Collections; using System.Runtime.Serialization; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// Represents parsed selection node in the navigation expression. +/// +/// Aleksandar Seovic +[Serializable] +public class SelectionLastNode : BaseNode { /// - /// Represents parsed selection node in the navigation expression. + /// Create a new instance /// - /// Aleksandar Seovic - [Serializable] - public class SelectionLastNode : BaseNode + public SelectionLastNode() : base() { - /// - /// Create a new instance - /// - public SelectionLastNode():base() + } + + /// + /// Create a new instance from SerializationInfo + /// + protected SelectionLastNode(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + + /// + /// Returns the last context item that matches selection expression. + /// + /// Context to evaluate expressions against. + /// Current expression evaluation context. + /// Node's value. + protected override object Get(object context, EvaluationContext evalContext) + { + IList list = context as IList; + + if (list == null) { + throw new ArgumentException( + "Selection can only be used on an instance of the type that implements IList."); } - /// - /// Create a new instance from SerializationInfo - /// - protected SelectionLastNode(SerializationInfo info, StreamingContext context) - : base(info, context) + using (evalContext.SwitchThisContext()) { - } - - /// - /// Returns the last context item that matches selection expression. - /// - /// Context to evaluate expressions against. - /// Current expression evaluation context. - /// Node's value. - protected override object Get(object context, EvaluationContext evalContext) - { - IList list = context as IList; - - if (list == null) + BaseNode expression = (BaseNode) this.getFirstChild(); + for (int i = list.Count - 1; i >= 0; i--) { - throw new ArgumentException( - "Selection can only be used on an instance of the type that implements IList."); - } - - using (evalContext.SwitchThisContext()) - { - BaseNode expression = (BaseNode) this.getFirstChild(); - for (int i = list.Count - 1; i >= 0; i--) + object listItem = list[i]; + evalContext.ThisContext = listItem; + bool isMatch = (bool) GetValue(expression, listItem, evalContext); + if (isMatch) { - object listItem = list[i]; - evalContext.ThisContext = listItem; - bool isMatch = (bool)GetValue(expression, listItem, evalContext ); - if (isMatch) - { - return listItem; - } + return listItem; } } - return null; } + + return null; } } diff --git a/src/Spring/Spring.Core/Expressions/SelectionNode.cs b/src/Spring/Spring.Core/Expressions/SelectionNode.cs index ad447ada..88679965 100644 --- a/src/Spring/Spring.Core/Expressions/SelectionNode.cs +++ b/src/Spring/Spring.Core/Expressions/SelectionNode.cs @@ -21,83 +21,84 @@ using System.Collections; using System.Runtime.Serialization; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// Represents parsed selection node in the navigation expression. +/// +/// Aleksandar Seovic +[Serializable] +public class SelectionNode : BaseNode { /// - /// Represents parsed selection node in the navigation expression. + /// Create a new instance /// - /// Aleksandar Seovic - [Serializable] - public class SelectionNode : BaseNode + public SelectionNode() + : base() { - /// - /// Create a new instance - /// - public SelectionNode() - : base() + } + + /// + /// Create a new instance from SerializationInfo + /// + protected SelectionNode(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + + /// + /// Returns a containing results of evaluation + /// of selection expression against each node in the context. + /// + /// Context to evaluate expressions against. + /// Current expression evaluation context. + /// Node's value. + protected override object Get(object context, EvaluationContext evalContext) + { + IEnumerable enumerable = context as IEnumerable; + if (enumerable == null) { + throw new ArgumentException( + "Selection can only be used on an instance of the type that implements IEnumerable."); } - /// - /// Create a new instance from SerializationInfo - /// - protected SelectionNode(SerializationInfo info, StreamingContext context) - : base(info, context) + BaseNode expression = (BaseNode) this.getFirstChild(); + BaseNode minIndexExpression = (BaseNode) expression.getNextSibling(); + BaseNode maxIndexExpression = (minIndexExpression == null) ? null : (BaseNode) minIndexExpression.getNextSibling(); + + int minIndex = (int) ((minIndexExpression == null) + ? Int32.MinValue + : GetValue(minIndexExpression, context, evalContext)); + int maxIndex = (int) ((maxIndexExpression == null) + ? Int32.MaxValue + : GetValue(maxIndexExpression, context, evalContext)); + + IList selectionList = new ArrayList(); + + using (evalContext.SwitchThisContext()) { - } - - /// - /// Returns a containing results of evaluation - /// of selection expression against each node in the context. - /// - /// Context to evaluate expressions against. - /// Current expression evaluation context. - /// Node's value. - protected override object Get(object context, EvaluationContext evalContext) - { - IEnumerable enumerable = context as IEnumerable; - if (enumerable == null) + int found = 0; + foreach (object o in enumerable) { - throw new ArgumentException( - "Selection can only be used on an instance of the type that implements IEnumerable."); - } - - BaseNode expression = (BaseNode)this.getFirstChild(); - BaseNode minIndexExpression = (BaseNode)expression.getNextSibling(); - BaseNode maxIndexExpression = (minIndexExpression == null) ? null : (BaseNode)minIndexExpression.getNextSibling(); - - int minIndex = (int)((minIndexExpression == null) - ? Int32.MinValue - : GetValue(minIndexExpression, context, evalContext)); - int maxIndex = (int)((maxIndexExpression == null) - ? Int32.MaxValue - : GetValue(maxIndexExpression, context, evalContext)); - - IList selectionList = new ArrayList(); - - using (evalContext.SwitchThisContext()) - { - int found = 0; - foreach (object o in enumerable) + evalContext.ThisContext = o; + bool isMatch = (bool) GetValue(expression, o, evalContext); + if (isMatch) { - evalContext.ThisContext = o; - bool isMatch = (bool)GetValue(expression, o, evalContext); - if (isMatch) + if (minIndex <= found && found <= maxIndex) { - if (minIndex <= found && found <= maxIndex) - { - selectionList.Add(o); - } - found++; + selectionList.Add(o); + } - if (found>maxIndex) - { - break; // don't look any further - } + found++; + + if (found > maxIndex) + { + break; // don't look any further } } } - return selectionList; } + + return selectionList; } } diff --git a/src/Spring/Spring.Core/Expressions/SpringAST.cs b/src/Spring/Spring.Core/Expressions/SpringAST.cs index 07886b15..cac1dc2b 100644 --- a/src/Spring/Spring.Core/Expressions/SpringAST.cs +++ b/src/Spring/Spring.Core/Expressions/SpringAST.cs @@ -2,150 +2,150 @@ using System.Runtime.Serialization; using Spring.Expressions.Parser.antlr; using Spring.Expressions.Parser.antlr.collections; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// For internal purposes only. Use for expression node implementations. +/// +/// +/// This class is only required to enable serialization of parsed Spring expressions since antlr.CommonAST +/// unfortunately is not marked as [Serializable].
+///
+/// Note:Since SpringAST implements , deriving classes +/// have to explicitely override if they need to persist additional +/// data during serialization. +///
+[Serializable] +public class SpringAST : Parser.antlr.BaseAST, ISerializable { - /// - /// For internal purposes only. Use for expression node implementations. - /// - /// - /// This class is only required to enable serialization of parsed Spring expressions since antlr.CommonAST - /// unfortunately is not marked as [Serializable].
- ///
- /// Note:Since SpringAST implements , deriving classes - /// have to explicitely override if they need to persist additional - /// data during serialization. - ///
- [Serializable] - public class SpringAST : Parser.antlr.BaseAST, ISerializable + #region Global SpringAST Factory + + internal class SpringASTCreator : Parser.antlr.ASTNodeCreator { - #region Global SpringAST Factory - - internal class SpringASTCreator : Parser.antlr.ASTNodeCreator + public override Parser.antlr.collections.AST Create() { - public override Parser.antlr.collections.AST Create() - { - return new SpringAST(); - } - - public override string ASTNodeTypeName - { - get { return typeof(SpringAST).FullName; } - } + return new SpringAST(); } - /// - /// The global SpringAST node factory - /// - internal static readonly SpringASTCreator Creator = new SpringASTCreator(); - - #endregion - - #region Members - - private string text; - private int ttype; - - #endregion - - /// - /// Create an instance - /// - public SpringAST() - {} - - /// - /// Create an instance from a token - /// - public SpringAST(IToken token) + public override string ASTNodeTypeName { - initialize(token); + get { return typeof(SpringAST).FullName; } } - - /// - /// initialize this instance from an AST - /// - public override void initialize(AST t) - { - this.setText(t.getText()); - this.Type = t.Type; - } - - /// - /// initialize this instance from an IToken - /// - public override void initialize(IToken tok) - { - this.setText(tok.getText()); - this.Type = tok.Type; - } - - /// - /// initialize this instance from a token type number and a text - /// - public override void initialize(int t, string txt) - { - this.Type = t; - this.setText(txt); - } - - /// - /// gets or sets the token type of this node - /// - public override int Type - { - get { return this.ttype; } - set { this.ttype = value; } - } - - /// - /// gets or sets the text of this node - /// - public string Text - { - get { return this.getText(); } - set { this.setText(value); } - } - - /// - /// sets the text of this node - /// - public override void setText(string txt) - { - this.text = txt; - } - - /// - /// gets the text of this node - /// - public override string getText() - { - return this.text; - } - - #region ISerializable Implementation - - /// - /// Create a new instance from SerializationInfo - /// - protected SpringAST(SerializationInfo info, StreamingContext context) - { - base.down = (BaseAST)info.GetValue("down", typeof(BaseAST)); - base.right = (BaseAST)info.GetValue("right", typeof(BaseAST)); - this.ttype = info.GetInt32("ttype"); - this.text = info.GetString("text"); - } - - /// - /// populate SerializationInfo from this instance - /// - public virtual void GetObjectData(SerializationInfo info, StreamingContext context) - { - info.AddValue("down", base.down, typeof(SpringAST)); - info.AddValue("right", base.right, typeof(SpringAST)); - info.AddValue("ttype", this.Type, typeof(int)); - info.AddValue("text", this.Text, typeof(string)); - } - - #endregion } + + /// + /// The global SpringAST node factory + /// + internal static readonly SpringASTCreator Creator = new SpringASTCreator(); + + #endregion + + #region Members + + private string text; + private int ttype; + + #endregion + + /// + /// Create an instance + /// + public SpringAST() + { + } + + /// + /// Create an instance from a token + /// + public SpringAST(IToken token) + { + initialize(token); + } + + /// + /// initialize this instance from an AST + /// + public override void initialize(AST t) + { + this.setText(t.getText()); + this.Type = t.Type; + } + + /// + /// initialize this instance from an IToken + /// + public override void initialize(IToken tok) + { + this.setText(tok.getText()); + this.Type = tok.Type; + } + + /// + /// initialize this instance from a token type number and a text + /// + public override void initialize(int t, string txt) + { + this.Type = t; + this.setText(txt); + } + + /// + /// gets or sets the token type of this node + /// + public override int Type + { + get { return this.ttype; } + set { this.ttype = value; } + } + + /// + /// gets or sets the text of this node + /// + public string Text + { + get { return this.getText(); } + set { this.setText(value); } + } + + /// + /// sets the text of this node + /// + public override void setText(string txt) + { + this.text = txt; + } + + /// + /// gets the text of this node + /// + public override string getText() + { + return this.text; + } + + #region ISerializable Implementation + + /// + /// Create a new instance from SerializationInfo + /// + protected SpringAST(SerializationInfo info, StreamingContext context) + { + base.down = (BaseAST) info.GetValue("down", typeof(BaseAST)); + base.right = (BaseAST) info.GetValue("right", typeof(BaseAST)); + this.ttype = info.GetInt32("ttype"); + this.text = info.GetString("text"); + } + + /// + /// populate SerializationInfo from this instance + /// + public virtual void GetObjectData(SerializationInfo info, StreamingContext context) + { + info.AddValue("down", base.down, typeof(SpringAST)); + info.AddValue("right", base.right, typeof(SpringAST)); + info.AddValue("ttype", this.Type, typeof(int)); + info.AddValue("text", this.Text, typeof(string)); + } + + #endregion } diff --git a/src/Spring/Spring.Core/Expressions/StringLiteralNode.cs b/src/Spring/Spring.Core/Expressions/StringLiteralNode.cs index b4d4405f..6ebdcabb 100644 --- a/src/Spring/Spring.Core/Expressions/StringLiteralNode.cs +++ b/src/Spring/Spring.Core/Expressions/StringLiteralNode.cs @@ -20,47 +20,46 @@ using System.Runtime.Serialization; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// Represents parsed string literal node. +/// +/// Aleksandar Seovic +[Serializable] +public class StringLiteralNode : BaseNode { /// - /// Represents parsed string literal node. + /// Create a new instance /// - /// Aleksandar Seovic - [Serializable] - public class StringLiteralNode : BaseNode + public StringLiteralNode() : base() { - /// - /// Create a new instance - /// - public StringLiteralNode():base() - { - } + } - /// - /// Create a new instance - /// - public StringLiteralNode(string text):base() - { - this.Text = text; - } + /// + /// Create a new instance + /// + public StringLiteralNode(string text) : base() + { + this.Text = text; + } - /// - /// Create a new instance from SerializationInfo - /// - protected StringLiteralNode(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } - - /// - /// Returns a value for the string literal node. - /// - /// Context to evaluate expressions against. - /// Current expression evaluation context. - /// Node's value. - protected override object Get(object context, EvaluationContext evalContext) - { - return this.getText(); - } + /// + /// Create a new instance from SerializationInfo + /// + protected StringLiteralNode(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + + /// + /// Returns a value for the string literal node. + /// + /// Context to evaluate expressions against. + /// Current expression evaluation context. + /// Node's value. + protected override object Get(object context, EvaluationContext evalContext) + { + return this.getText(); } } diff --git a/src/Spring/Spring.Core/Expressions/SyntaxErrorException.cs b/src/Spring/Spring.Core/Expressions/SyntaxErrorException.cs index d0940121..1689d0bf 100644 --- a/src/Spring/Spring.Core/Expressions/SyntaxErrorException.cs +++ b/src/Spring/Spring.Core/Expressions/SyntaxErrorException.cs @@ -21,91 +21,90 @@ using System.Runtime.Serialization; using Spring.Expressions.Parser.antlr; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// Exception thrown when detecting invalid SpEL syntax +/// +/// Erich Eichinger +[Serializable] +internal class SyntaxErrorException : RecognitionException, ISerializable { - /// - /// Exception thrown when detecting invalid SpEL syntax - /// - /// Erich Eichinger - [Serializable] - internal class SyntaxErrorException : RecognitionException, ISerializable - { - private readonly string _expression; + private readonly string _expression; - /// - /// - public int Line - { - get { return line; } - } + /// + /// + public int Line + { + get { return line; } + } - /// - /// - public int Column - { - get { return column; } - } + /// + /// + public int Column + { + get { return column; } + } - /// - ///Gets a message that provides details on the syntax error. - /// - public override string Message + /// + ///Gets a message that provides details on the syntax error. + /// + public override string Message + { + get { - get - { - return string.Format("Syntax Error on line {0}, column {1}: {2} in expression{3}'{4}'", Line, Column, base.Message, Environment.NewLine, _expression ); - } + return string.Format("Syntax Error on line {0}, column {1}: {2} in expression{3}'{4}'", Line, Column, base.Message, Environment.NewLine, _expression); } + } - /// - /// The expression that caused the error - /// - public string Expression - { - get { return _expression; } - } + /// + /// The expression that caused the error + /// + public string Expression + { + get { return _expression; } + } - #region Public Instance Constructors + #region Public Instance Constructors - /// - /// TODO - /// - public SyntaxErrorException(string message, int line, int column, string expression) - : base(message, null, line, column) - { - _expression = expression; - } + /// + /// TODO + /// + public SyntaxErrorException(string message, int line, int column, string expression) + : base(message, null, line, column) + { + _expression = expression; + } - #endregion Public Instance Constructors + #endregion Public Instance Constructors - #region Protected Instance Constructors + #region Protected Instance Constructors - /// - /// TODO - /// - protected SyntaxErrorException(SerializationInfo info, StreamingContext context) : base(info.GetString("Message")) - { - base.line = info.GetInt32("Line"); - base.column = info.GetInt32("Column"); - this._expression = info.GetString("Expression"); - } + /// + /// TODO + /// + protected SyntaxErrorException(SerializationInfo info, StreamingContext context) : base(info.GetString("Message")) + { + base.line = info.GetInt32("Line"); + base.column = info.GetInt32("Column"); + this._expression = info.GetString("Expression"); + } - /// - /// - /// - /// - /// - public override void GetObjectData( SerializationInfo info, StreamingContext context ) - { - // since RecognitionException does not implement .ctor(SerializationInfo info, StreamingContext context) - // we need to do the serialization on our own... #�$% - //base.GetObjectData( info, context ); - info.AddValue("Line", base.line); - info.AddValue("Column", base.column); - info.AddValue("Message", base.Message); - info.AddValue("Expression", this._expression); - } + /// + /// + /// + /// + /// + public override void GetObjectData(SerializationInfo info, StreamingContext context) + { + // since RecognitionException does not implement .ctor(SerializationInfo info, StreamingContext context) + // we need to do the serialization on our own... #�$% + //base.GetObjectData( info, context ); + info.AddValue("Line", base.line); + info.AddValue("Column", base.column); + info.AddValue("Message", base.Message); + info.AddValue("Expression", this._expression); + } - #endregion Protected Instance Constructors - } + #endregion Protected Instance Constructors } diff --git a/src/Spring/Spring.Core/Expressions/TernaryNode.cs b/src/Spring/Spring.Core/Expressions/TernaryNode.cs index 1aee663f..5a63c5d6 100644 --- a/src/Spring/Spring.Core/Expressions/TernaryNode.cs +++ b/src/Spring/Spring.Core/Expressions/TernaryNode.cs @@ -21,69 +21,68 @@ using System.Runtime.Serialization; using Spring.Expressions.Parser.antlr.collections; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// Represents ternary expression node. +/// +/// Aleksandar Seovic +[Serializable] +public class TernaryNode : BaseNode { + private bool initialized = false; + private BaseNode condition; + private BaseNode trueExp; + private BaseNode falseExp; + /// - /// Represents ternary expression node. + /// Create a new instance /// - /// Aleksandar Seovic - [Serializable] - public class TernaryNode : BaseNode + public TernaryNode() : base() { - private bool initialized = false; - private BaseNode condition; - private BaseNode trueExp; - private BaseNode falseExp; + } - /// - /// Create a new instance - /// - public TernaryNode():base() - { - } + /// + /// Create a new instance from SerializationInfo + /// + protected TernaryNode(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } - /// - /// Create a new instance from SerializationInfo - /// - protected TernaryNode(SerializationInfo info, StreamingContext context) - : base(info, context) + /// + /// Returns a value for the string literal node. + /// + /// Context to evaluate expressions against. + /// Current expression evaluation context. + /// Node's value. + protected override object Get(object context, EvaluationContext evalContext) + { + if (!initialized) { - } - - /// - /// Returns a value for the string literal node. - /// - /// Context to evaluate expressions against. - /// Current expression evaluation context. - /// Node's value. - protected override object Get(object context, EvaluationContext evalContext) - { - if (!initialized) + lock (this) { - lock (this) + if (!initialized) { - if (!initialized) - { - AST node = this.getFirstChild(); - condition = (BaseNode) node; - node = node.getNextSibling(); - trueExp = (BaseNode) node; - node = node.getNextSibling(); - falseExp = (BaseNode) node; + AST node = this.getFirstChild(); + condition = (BaseNode) node; + node = node.getNextSibling(); + trueExp = (BaseNode) node; + node = node.getNextSibling(); + falseExp = (BaseNode) node; - initialized = true; - } + initialized = true; } } + } - if (Convert.ToBoolean(GetValue(condition, context, evalContext))) - { - return GetValue(trueExp, context, evalContext); - } - else - { - return GetValue(falseExp, context, evalContext); - } + if (Convert.ToBoolean(GetValue(condition, context, evalContext))) + { + return GetValue(trueExp, context, evalContext); + } + else + { + return GetValue(falseExp, context, evalContext); } } } diff --git a/src/Spring/Spring.Core/Expressions/TypeNode.cs b/src/Spring/Spring.Core/Expressions/TypeNode.cs index 4be566d5..4a1b4d60 100644 --- a/src/Spring/Spring.Core/Expressions/TypeNode.cs +++ b/src/Spring/Spring.Core/Expressions/TypeNode.cs @@ -22,62 +22,62 @@ using System.Runtime.Serialization; using Spring.Core.TypeResolution; using Spring.Expressions.Parser.antlr.collections; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// Represents parsed type node in the navigation expression. +/// +/// Aleksandar Seovic +[Serializable] +public class TypeNode : BaseNode { + private Type type; + /// - /// Represents parsed type node in the navigation expression. + /// Create a new instance /// - /// Aleksandar Seovic - [Serializable] - public class TypeNode : BaseNode + public TypeNode() + : base() { - private Type type; + } - /// - /// Create a new instance - /// - public TypeNode() - : base() - { - } + /// + /// Create a new instance from SerializationInfo + /// + protected TypeNode(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } - /// - /// Create a new instance from SerializationInfo - /// - protected TypeNode(SerializationInfo info, StreamingContext context) - : base(info, context) + /// + /// Returns node's value for the given context. + /// + /// Context to evaluate expressions against. + /// Current expression evaluation context. + /// Node's value. + protected override object Get(object context, EvaluationContext evalContext) + { + if (type == null) { - } - - /// - /// Returns node's value for the given context. - /// - /// Context to evaluate expressions against. - /// Current expression evaluation context. - /// Node's value. - protected override object Get(object context, EvaluationContext evalContext) - { - if (type == null) + lock (this) { - lock(this) - { - type = TypeResolutionUtils.ResolveType(getText()); - } + type = TypeResolutionUtils.ResolveType(getText()); } - - return type; } - /// - /// Overrides getText to allow easy way to get fully - /// qualified typename. - /// - /// - /// Fully qualified typename as a string. - /// - public override string getText() - { - string tmp = base.getText(); + return type; + } + + /// + /// Overrides getText to allow easy way to get fully + /// qualified typename. + /// + /// + /// Fully qualified typename as a string. + /// + public override string getText() + { + string tmp = base.getText(); // if (tmp != null && TypeRegistry.ContainsAlias(tmp)) // { // Type type = TypeRegistry.ResolveType(tmp); @@ -86,13 +86,13 @@ namespace Spring.Expressions // tmp = type.AssemblyQualifiedName; // } // } - AST node = this.getFirstChild(); - while (node != null) - { - tmp += node.getText(); - node = node.getNextSibling(); - } - return tmp; + AST node = this.getFirstChild(); + while (node != null) + { + tmp += node.getText(); + node = node.getNextSibling(); } + + return tmp; } } diff --git a/src/Spring/Spring.Core/Expressions/UnaryOperator.cs b/src/Spring/Spring.Core/Expressions/UnaryOperator.cs index 8034fa5d..2cc090d0 100644 --- a/src/Spring/Spring.Core/Expressions/UnaryOperator.cs +++ b/src/Spring/Spring.Core/Expressions/UnaryOperator.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -20,45 +20,44 @@ using System.Runtime.Serialization; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// Base class for unary operators. +/// +/// Aleksandar Seovic +//[Serializable] +public abstract class UnaryOperator : BaseNode { /// - /// Base class for unary operators. + /// Create a new instance /// - /// Aleksandar Seovic - //[Serializable] - public abstract class UnaryOperator : BaseNode + public UnaryOperator() : base() { - /// - /// Create a new instance - /// - public UnaryOperator():base() - { - } + } - /// - /// Create a new instance - /// - public UnaryOperator(BaseNode operand) - { - this.addChild(operand); - } + /// + /// Create a new instance + /// + public UnaryOperator(BaseNode operand) + { + this.addChild(operand); + } - /// - /// Create a new instance from SerializationInfo - /// - protected UnaryOperator(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } - - /// - /// Gets the operand. - /// - /// The operand. - public BaseNode Operand - { - get { return (BaseNode) this.getFirstChild(); } - } + /// + /// Create a new instance from SerializationInfo + /// + protected UnaryOperator(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + + /// + /// Gets the operand. + /// + /// The operand. + public BaseNode Operand + { + get { return (BaseNode) this.getFirstChild(); } } } \ No newline at end of file diff --git a/src/Spring/Spring.Core/Expressions/VariableNode.cs b/src/Spring/Spring.Core/Expressions/VariableNode.cs index 8583aaba..c391919f 100644 --- a/src/Spring/Spring.Core/Expressions/VariableNode.cs +++ b/src/Spring/Spring.Core/Expressions/VariableNode.cs @@ -20,69 +20,71 @@ using System.Runtime.Serialization; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// Represents parsed variable node. +/// +/// Aleksandar Seovic +[Serializable] +public class VariableNode : BaseNode { /// - /// Represents parsed variable node. + /// Create a new instance /// - /// Aleksandar Seovic - [Serializable] - public class VariableNode : BaseNode + public VariableNode() : base() { - /// - /// Create a new instance - /// - public VariableNode():base() + } + + /// + /// Create a new instance from SerializationInfo + /// + protected VariableNode(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + + /// + /// Returns value of the variable represented by this node. + /// + /// Context to evaluate expressions against. + /// Current expression evaluation context. + /// Node's value. + protected override object Get(object context, EvaluationContext evalContext) + { + string varName = this.getText(); + if (varName == "this") { + return evalContext.ThisContext; + } + else if (varName == "root") + { + return evalContext.RootContext; } - /// - /// Create a new instance from SerializationInfo - /// - protected VariableNode(SerializationInfo info, StreamingContext context) - : base(info, context) + return evalContext.Variables[varName]; + } + + /// + /// Sets value of the variable represented by this node. + /// + /// Context to evaluate expressions against. + /// Current expression evaluation context. + /// New value for this node. + protected override void Set(object context, EvaluationContext evalContext, object newValue) + { + string varName = this.getText(); + if (varName == "this" || varName == "root") { + throw new ArgumentException("You cannot assign a value to intrinsic variable '" + varName + "'."); } - /// - /// Returns value of the variable represented by this node. - /// - /// Context to evaluate expressions against. - /// Current expression evaluation context. - /// Node's value. - protected override object Get(object context, EvaluationContext evalContext) + if (evalContext.Variables == null) { - string varName = this.getText(); - if (varName == "this") - { - return evalContext.ThisContext; - } - else if (varName == "root") - { - return evalContext.RootContext; - } - return evalContext.Variables[varName]; + throw new InvalidOperationException( + "You need to provide variables dictionary to expression evaluation engine in order to be able to set variable values."); } - /// - /// Sets value of the variable represented by this node. - /// - /// Context to evaluate expressions against. - /// Current expression evaluation context. - /// New value for this node. - protected override void Set(object context, EvaluationContext evalContext, object newValue) - { - string varName = this.getText(); - if (varName == "this" || varName == "root") - { - throw new ArgumentException("You cannot assign a value to intrinsic variable '" + varName + "'."); - } - if (evalContext.Variables == null) - { - throw new InvalidOperationException( - "You need to provide variables dictionary to expression evaluation engine in order to be able to set variable values."); - } - evalContext.Variables[varName] = newValue; - } + evalContext.Variables[varName] = newValue; } } diff --git a/src/Spring/Spring.Core/Globalization/AbstractLocalizer.cs b/src/Spring/Spring.Core/Globalization/AbstractLocalizer.cs index f1caa7b7..dd31b454 100644 --- a/src/Spring/Spring.Core/Globalization/AbstractLocalizer.cs +++ b/src/Spring/Spring.Core/Globalization/AbstractLocalizer.cs @@ -20,103 +20,100 @@ using System.Globalization; using System.Threading; - using Spring.Context; using Spring.Util; -namespace Spring.Globalization +namespace Spring.Globalization; + +/// +/// Abstract base class that all localizers should extend +/// +/// +///

+/// This class contains the bulk of the localizer logic, including implementation +/// of the ApplyResources methods that are defined in +/// interface. +///

+///

+/// All specific localizers need to do is inherit this class and implement +/// GetResources method that will return a list of +/// objects that should be applied to a specified target. +///

+///

+/// Custom implementations can use whatever type of resource storage they want, +/// such as standard .NET resource sets, custom XML files, database, etc. +///

+///
+/// Aleksandar Seovic +public abstract class AbstractLocalizer : ILocalizer { + private IResourceCache resourceCache = new NullResourceCache(); + /// - /// Abstract base class that all localizers should extend + /// Gets or sets the resource cache instance. /// - /// - ///

- /// This class contains the bulk of the localizer logic, including implementation - /// of the ApplyResources methods that are defined in - /// interface. - ///

- ///

- /// All specific localizers need to do is inherit this class and implement - /// GetResources method that will return a list of - /// objects that should be applied to a specified target. - ///

- ///

- /// Custom implementations can use whatever type of resource storage they want, - /// such as standard .NET resource sets, custom XML files, database, etc. - ///

- ///
- /// Aleksandar Seovic - public abstract class AbstractLocalizer : ILocalizer + /// The resource cache instance. + public IResourceCache ResourceCache { - private IResourceCache resourceCache = new NullResourceCache(); - - /// - /// Gets or sets the resource cache instance. - /// - /// The resource cache instance. - public IResourceCache ResourceCache - { - get { return resourceCache; } - set { resourceCache = value; } - } - - /// - /// Applies resources of the specified culture to the specified target object. - /// - /// Target object to apply resources to. - /// instance to retrieve resources from. - /// Resource culture to use for resource lookup. - public void ApplyResources(object target, IMessageSource messageSource, CultureInfo culture) - { - AssertUtils.ArgumentNotNull(target, "target"); - AssertUtils.ArgumentNotNull(culture, "culture"); - - IList resources = GetResources(target, messageSource, culture); - foreach (Resource resource in resources) - { - resource.Target.SetValue(target, null, resource.Value); - } - } - - /// - /// Applies resources to the specified target object, using current thread's uiCulture to resolve resources. - /// - /// Target object to apply resources to. - /// instance to retrieve resources from. - public void ApplyResources(object target, IMessageSource messageSource) - { - AssertUtils.ArgumentNotNull(target, "target"); - ApplyResources(target, messageSource, Thread.CurrentThread.CurrentUICulture); - } - - /// - /// Returns a list of instances that should be applied to the target. - /// - /// Target to get a list of resources for. - /// instance to retrieve resources from. - /// Resource locale. - /// A list of resources to apply. - private IList GetResources(object target, IMessageSource messageSource, CultureInfo culture) - { - IList resources = resourceCache.GetResources(target, culture); - - if (resources == null) - { - resources = LoadResources(target, messageSource, culture); - resourceCache.PutResources(target, culture, resources); - } - - return resources; - } - - /// - /// Loads resources from the storage and creates a list of instances that should be applied to the target. - /// - /// Target to get a list of resources for. - /// instance to retrieve resources from. - /// Resource locale. - /// A list of resources to apply. - protected abstract IList LoadResources(object target, IMessageSource messageSource, CultureInfo culture); - + get { return resourceCache; } + set { resourceCache = value; } } -} + + /// + /// Applies resources of the specified culture to the specified target object. + /// + /// Target object to apply resources to. + /// instance to retrieve resources from. + /// Resource culture to use for resource lookup. + public void ApplyResources(object target, IMessageSource messageSource, CultureInfo culture) + { + AssertUtils.ArgumentNotNull(target, "target"); + AssertUtils.ArgumentNotNull(culture, "culture"); + + IList resources = GetResources(target, messageSource, culture); + foreach (Resource resource in resources) + { + resource.Target.SetValue(target, null, resource.Value); + } + } + + /// + /// Applies resources to the specified target object, using current thread's uiCulture to resolve resources. + /// + /// Target object to apply resources to. + /// instance to retrieve resources from. + public void ApplyResources(object target, IMessageSource messageSource) + { + AssertUtils.ArgumentNotNull(target, "target"); + ApplyResources(target, messageSource, Thread.CurrentThread.CurrentUICulture); + } + + /// + /// Returns a list of instances that should be applied to the target. + /// + /// Target to get a list of resources for. + /// instance to retrieve resources from. + /// Resource locale. + /// A list of resources to apply. + private IList GetResources(object target, IMessageSource messageSource, CultureInfo culture) + { + IList resources = resourceCache.GetResources(target, culture); + + if (resources == null) + { + resources = LoadResources(target, messageSource, culture); + resourceCache.PutResources(target, culture, resources); + } + + return resources; + } + + /// + /// Loads resources from the storage and creates a list of instances that should be applied to the target. + /// + /// Target to get a list of resources for. + /// instance to retrieve resources from. + /// Resource locale. + /// A list of resources to apply. + protected abstract IList LoadResources(object target, IMessageSource messageSource, CultureInfo culture); +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Globalization/AbstractResourceCache.cs b/src/Spring/Spring.Core/Globalization/AbstractResourceCache.cs index b6ee250e..843488b8 100644 --- a/src/Spring/Spring.Core/Globalization/AbstractResourceCache.cs +++ b/src/Spring/Spring.Core/Globalization/AbstractResourceCache.cs @@ -20,61 +20,59 @@ using System.Globalization; -namespace Spring.Globalization +namespace Spring.Globalization; + +/// +/// Abstract base class that all resource cache implementations should extend. +/// +/// Aleksandar Seovic +public abstract class AbstractResourceCache : IResourceCache { /// - /// Abstract base class that all resource cache implementations should extend. + /// Gets the list of resources from the cache. /// - /// Aleksandar Seovic - public abstract class AbstractResourceCache : IResourceCache + /// Target to get a list of resources for. + /// Resource culture. + /// A list of cached resources for the specified target object and culture. + public IList GetResources(object target, CultureInfo culture) { - /// - /// Gets the list of resources from the cache. - /// - /// Target to get a list of resources for. - /// Resource culture. - /// A list of cached resources for the specified target object and culture. - public IList GetResources(object target, CultureInfo culture) - { - return GetResources(CreateCacheKey(target, culture)); - } - - /// - /// Puts the list of resources in the cache. - /// - /// Target to cache a list of resources for. - /// Resource culture. - /// A list of resources to cache. - /// A list of cached resources for the specified target object and culture. - public void PutResources(object target, CultureInfo culture, IList resources) - { - PutResources(CreateCacheKey(target, culture), resources); - } - - /// - /// Crates resource cache key for the specified target object and culture. - /// - /// Target object to apply resources to. - /// Resource culture to use for resource lookup. - protected virtual string CreateCacheKey(object target, CultureInfo culture) - { - return target.GetType().FullName + "." + culture.Name + ".resources"; - } - - /// - /// Gets the list of resources from cache. - /// - /// Cache key to use for lookup. - /// A list of cached resources for the specified target object and culture. - protected abstract IList GetResources(string cacheKey); - - /// - /// Puts the list of resources in the cache. - /// - /// Cache key to use for the specified resources. - /// A list of resources to cache. - /// A list of cached resources for the specified target object and culture. - protected abstract void PutResources(string cacheKey, IList resources); - + return GetResources(CreateCacheKey(target, culture)); } + + /// + /// Puts the list of resources in the cache. + /// + /// Target to cache a list of resources for. + /// Resource culture. + /// A list of resources to cache. + /// A list of cached resources for the specified target object and culture. + public void PutResources(object target, CultureInfo culture, IList resources) + { + PutResources(CreateCacheKey(target, culture), resources); + } + + /// + /// Crates resource cache key for the specified target object and culture. + /// + /// Target object to apply resources to. + /// Resource culture to use for resource lookup. + protected virtual string CreateCacheKey(object target, CultureInfo culture) + { + return target.GetType().FullName + "." + culture.Name + ".resources"; + } + + /// + /// Gets the list of resources from cache. + /// + /// Cache key to use for lookup. + /// A list of cached resources for the specified target object and culture. + protected abstract IList GetResources(string cacheKey); + + /// + /// Puts the list of resources in the cache. + /// + /// Cache key to use for the specified resources. + /// A list of resources to cache. + /// A list of cached resources for the specified target object and culture. + protected abstract void PutResources(string cacheKey, IList resources); } diff --git a/src/Spring/Spring.Core/Globalization/Formatters/BooleanFormatter.cs b/src/Spring/Spring.Core/Globalization/Formatters/BooleanFormatter.cs index 3a0f70b5..df2257a8 100644 --- a/src/Spring/Spring.Core/Globalization/Formatters/BooleanFormatter.cs +++ b/src/Spring/Spring.Core/Globalization/Formatters/BooleanFormatter.cs @@ -20,123 +20,124 @@ using Spring.Util; -namespace Spring.Globalization.Formatters +namespace Spring.Globalization.Formatters; + +/// +/// Implementation of that can be used to +/// format and parse boolean values. +/// +/// Erich Eichinger +public class BooleanFormatter : IFormatter { + private string trueString; + private string falseString; + private bool ignoreCase; + + #region Constructors + /// - /// Implementation of that can be used to - /// format and parse boolean values. + /// Initializes a new instance of the class + /// using default values /// - /// Erich Eichinger - public class BooleanFormatter:IFormatter + public BooleanFormatter() + : this(true, bool.TrueString, bool.FalseString) { - private string trueString; - private string falseString; - private bool ignoreCase; + } - #region Constructors + /// + /// Initializes a new instance of the class + /// + public BooleanFormatter(bool ignoreCase, string trueString, string falseString) + { + this.trueString = trueString; + this.falseString = falseString; + this.ignoreCase = ignoreCase; + } - /// - /// Initializes a new instance of the class - /// using default values - /// - public BooleanFormatter() - : this(true,bool.TrueString,bool.FalseString) - { } + #endregion - /// - /// Initializes a new instance of the class - /// - public BooleanFormatter(bool ignoreCase,string trueString,string falseString) + #region Properties + + /// + /// Set/Get value to control casesensitivity of + /// + /// + /// Defaults to true + /// + public bool IgnoreCase + { + get { return this.ignoreCase; } + set { this.ignoreCase = value; } + } + + /// + /// Set/Get value to recognize as boolean "true" value + /// + /// + /// Defaults to + /// + public string TrueString + { + get { return this.trueString; } + set { this.trueString = value; } + } + + /// + /// Set/Get value to recognize as boolean "false" value + /// + /// + /// Defaults to + /// + public string FalseString + { + get { return this.falseString; } + set { this.falseString = value; } + } + + #endregion + + /// + /// Formats the specified boolean value. + /// + /// The value to format. + /// Formatted boolean value. + /// If is null. + /// If is not of type . + public string Format(object value) + { + AssertUtils.ArgumentNotNull(value, "value"); + if (!(value is bool)) { - this.trueString = trueString; - this.falseString = falseString; - this.ignoreCase = ignoreCase; + throw new ArgumentException("BooleanFormatter can only be used to format instances of [System.Boolean]"); } - #endregion + return ((bool) value) ? this.trueString : this.falseString; + } - #region Properties - - /// - /// Set/Get value to control casesensitivity of - /// - /// - /// Defaults to true - /// - public bool IgnoreCase + /// + /// Parses the specified boolean value according to settings of and + /// + /// The boolean value to parse. + /// Parsed boolean value as a . + /// If does not match or . + public object Parse(string value) + { + if (!StringUtils.HasText(value)) { - get { return this.ignoreCase; } - set { this.ignoreCase = value; } + return false; } - /// - /// Set/Get value to recognize as boolean "true" value - /// - /// - /// Defaults to - /// - public string TrueString + if (0 == string.Compare(value, this.trueString, this.ignoreCase)) { - get { return this.trueString; } - set { this.trueString = value; } + return true; } - - /// - /// Set/Get value to recognize as boolean "false" value - /// - /// - /// Defaults to - /// - public string FalseString + else if (0 == string.Compare(value, this.falseString, this.ignoreCase)) { - get { return this.falseString; } - set { this.falseString = value; } + return false; } - - #endregion - - /// - /// Formats the specified boolean value. - /// - /// The value to format. - /// Formatted boolean value. - /// If is null. - /// If is not of type . - public string Format(object value) + else { - AssertUtils.ArgumentNotNull( value,"value" ); - if(!(value is bool)) - { - throw new ArgumentException( "BooleanFormatter can only be used to format instances of [System.Boolean]" ); - } - return ((bool) value) ? this.trueString : this.falseString; - } - - /// - /// Parses the specified boolean value according to settings of and - /// - /// The boolean value to parse. - /// Parsed boolean value as a . - /// If does not match or . - public object Parse(string value) - { - if(!StringUtils.HasText( value )) - { - return false; - } - - if ( 0 == string.Compare( value, this.trueString, this.ignoreCase )) - { - return true; - } - else if(0 == string.Compare( value,this.falseString,this.ignoreCase )) - { - return false; - } - else - { - throw new ArgumentException( string.Format("input value '{0}' is not recognized as a boolean", value) ); - } + throw new ArgumentException(string.Format("input value '{0}' is not recognized as a boolean", value)); } } } diff --git a/src/Spring/Spring.Core/Globalization/Formatters/CurrencyFormatter.cs b/src/Spring/Spring.Core/Globalization/Formatters/CurrencyFormatter.cs index 891a59bf..3347544c 100644 --- a/src/Spring/Spring.Core/Globalization/Formatters/CurrencyFormatter.cs +++ b/src/Spring/Spring.Core/Globalization/Formatters/CurrencyFormatter.cs @@ -19,189 +19,189 @@ #endregion using System.Globalization; - using Spring.Util; -namespace Spring.Globalization.Formatters +namespace Spring.Globalization.Formatters; + +/// +/// Implementation of that can be used to +/// format and parse currency values. +/// +/// +/// +/// CurrencyFormatter uses currency related properties of the +/// to format and parse currency values. +/// +/// +/// If you use one of the constructors that accept culture as a parameter +/// to create an instance of CurrencyFormatter, default NumberFormatInfo +/// for the specified culture will be used. +/// +/// +/// You can also use properties exposed by the CurrencyFormatter in order +/// to override some of the default currency formatting parameters. +/// +/// +/// Aleksandar Seovic +public class CurrencyFormatter : IFormatter { - /// - /// Implementation of that can be used to - /// format and parse currency values. - /// - /// - /// - /// CurrencyFormatter uses currency related properties of the - /// to format and parse currency values. - /// - /// - /// If you use one of the constructors that accept culture as a parameter - /// to create an instance of CurrencyFormatter, default NumberFormatInfo - /// for the specified culture will be used. - /// - /// - /// You can also use properties exposed by the CurrencyFormatter in order - /// to override some of the default currency formatting parameters. - /// - /// - /// Aleksandar Seovic - public class CurrencyFormatter : IFormatter - { - private NumberFormatInfo formatInfo; + private NumberFormatInfo formatInfo; - #region Constructors + #region Constructors - /// - /// Initializes a new instance of the class - /// using default for the current thread's culture. - /// - public CurrencyFormatter() : this(CultureInfo.CurrentCulture) - {} + /// + /// Initializes a new instance of the class + /// using default for the current thread's culture. + /// + public CurrencyFormatter() : this(CultureInfo.CurrentCulture) + { + } - /// - /// Initializes a new instance of the class - /// using default for the specified culture. - /// - /// The culture name. - public CurrencyFormatter(string cultureName) : this(CultureInfo.CreateSpecificCulture(cultureName)) - {} + /// + /// Initializes a new instance of the class + /// using default for the specified culture. + /// + /// The culture name. + public CurrencyFormatter(string cultureName) : this(CultureInfo.CreateSpecificCulture(cultureName)) + { + } - /// - /// Initializes a new instance of the class - /// using default for the specified culture. - /// - /// The culture. - public CurrencyFormatter(CultureInfo culture) - { - formatInfo = culture.NumberFormat; - } + /// + /// Initializes a new instance of the class + /// using default for the specified culture. + /// + /// The culture. + public CurrencyFormatter(CultureInfo culture) + { + formatInfo = culture.NumberFormat; + } - /// - /// Initializes a new instance of the class - /// using specified . - /// - /// - /// The instance that defines how - /// currency values are formatted. - /// - public CurrencyFormatter(NumberFormatInfo formatInfo) + /// + /// Initializes a new instance of the class + /// using specified . + /// + /// + /// The instance that defines how + /// currency values are formatted. + /// + public CurrencyFormatter(NumberFormatInfo formatInfo) + { + this.formatInfo = formatInfo; + } + + #endregion + + #region Properties + + /// + /// Gets or sets the currency decimal digits. + /// + /// The currency decimal digits. + /// + public int DecimalDigits + { + get { return formatInfo.CurrencyDecimalDigits; } + set { formatInfo.CurrencyDecimalDigits = value; } + } + + /// + /// Gets or sets the currency decimal separator. + /// + /// The currency decimal separator. + /// + public string DecimalSeparator + { + get { return formatInfo.CurrencyDecimalSeparator; } + set { formatInfo.CurrencyDecimalSeparator = value; } + } + + /// + /// Gets or sets the currency group sizes. + /// + /// The currency group sizes. + /// + public int[] GroupSizes + { + get { return formatInfo.CurrencyGroupSizes; } + set { formatInfo.CurrencyGroupSizes = value; } + } + + /// + /// Gets or sets the currency group separator. + /// + /// The currency group separator. + /// + public string GroupSeparator + { + get { return formatInfo.CurrencyGroupSeparator; } + set { formatInfo.CurrencyGroupSeparator = value; } + } + + /// + /// Gets or sets the currency symbol. + /// + /// The currency symbol. + /// + public string CurrencySymbol + { + get { return formatInfo.CurrencySymbol; } + set { formatInfo.CurrencySymbol = value; } + } + + /// + /// Gets or sets the currency negative pattern. + /// + /// The currency negative pattern. + /// + public int NegativePattern + { + get { return formatInfo.CurrencyNegativePattern; } + set { formatInfo.CurrencyNegativePattern = value; } + } + + /// + /// Gets or sets the currency positive pattern. + /// + /// The currency positive pattern. + /// + public int PositivePattern + { + get { return formatInfo.CurrencyPositivePattern; } + set { formatInfo.CurrencyPositivePattern = value; } + } + + #endregion + + /// + /// Formats the specified currency value. + /// + /// The value to format. + /// Formatted currency . + /// If is null. + /// If is not a number. + public string Format(object value) + { + AssertUtils.ArgumentNotNull(value, "value"); + if (!NumberUtils.IsNumber(value)) { - this.formatInfo = formatInfo; + throw new ArgumentException("CurrencyFormatter can only be used to format numbers."); } - #endregion + return String.Format(formatInfo, "{0:C}", value); + } - #region Properties + /// + /// Parses the specified currency value. + /// + /// The currency value to parse. + /// Parsed currency value as a . + public object Parse(string value) + { + if (!StringUtils.HasText(value)) + { + return 0d; + } - /// - /// Gets or sets the currency decimal digits. - /// - /// The currency decimal digits. - /// - public int DecimalDigits - { - get { return formatInfo.CurrencyDecimalDigits; } - set { formatInfo.CurrencyDecimalDigits = value; } - } - - /// - /// Gets or sets the currency decimal separator. - /// - /// The currency decimal separator. - /// - public string DecimalSeparator - { - get { return formatInfo.CurrencyDecimalSeparator; } - set { formatInfo.CurrencyDecimalSeparator = value; } - } - - /// - /// Gets or sets the currency group sizes. - /// - /// The currency group sizes. - /// - public int[] GroupSizes - { - get { return formatInfo.CurrencyGroupSizes; } - set { formatInfo.CurrencyGroupSizes = value; } - } - - /// - /// Gets or sets the currency group separator. - /// - /// The currency group separator. - /// - public string GroupSeparator - { - get { return formatInfo.CurrencyGroupSeparator; } - set { formatInfo.CurrencyGroupSeparator = value; } - } - - /// - /// Gets or sets the currency symbol. - /// - /// The currency symbol. - /// - public string CurrencySymbol - { - get { return formatInfo.CurrencySymbol; } - set { formatInfo.CurrencySymbol = value; } - } - - /// - /// Gets or sets the currency negative pattern. - /// - /// The currency negative pattern. - /// - public int NegativePattern - { - get { return formatInfo.CurrencyNegativePattern; } - set { formatInfo.CurrencyNegativePattern = value; } - } - - /// - /// Gets or sets the currency positive pattern. - /// - /// The currency positive pattern. - /// - public int PositivePattern - { - get { return formatInfo.CurrencyPositivePattern; } - set { formatInfo.CurrencyPositivePattern = value; } - } - - #endregion - - /// - /// Formats the specified currency value. - /// - /// The value to format. - /// Formatted currency . - /// If is null. - /// If is not a number. - public string Format(object value) - { - AssertUtils.ArgumentNotNull(value, "value"); - if (!NumberUtils.IsNumber(value)) - { - throw new ArgumentException("CurrencyFormatter can only be used to format numbers."); - } - - return String.Format(formatInfo, "{0:C}", value); - } - - /// - /// Parses the specified currency value. - /// - /// The currency value to parse. - /// Parsed currency value as a . - public object Parse(string value) - { - if (!StringUtils.HasText(value)) - { - return 0d; - } - - return Double.Parse(value, NumberStyles.Currency, formatInfo); - } - } + return Double.Parse(value, NumberStyles.Currency, formatInfo); + } } diff --git a/src/Spring/Spring.Core/Globalization/Formatters/DateTimeFormatter.cs b/src/Spring/Spring.Core/Globalization/Formatters/DateTimeFormatter.cs index f2c1a6bc..41ef56a1 100644 --- a/src/Spring/Spring.Core/Globalization/Formatters/DateTimeFormatter.cs +++ b/src/Spring/Spring.Core/Globalization/Formatters/DateTimeFormatter.cs @@ -19,100 +19,100 @@ #endregion using System.Globalization; - using Spring.Util; -namespace Spring.Globalization.Formatters +namespace Spring.Globalization.Formatters; + +/// +/// Implementation of that can be used to +/// format and parse values. +/// +/// +/// +/// DateTimeFormatter uses properties of the +/// to format and parse values. +/// +/// +/// If you use one of the constructors that accept culture as a parameter +/// to create an instance of DateTimeFormatter, default DateTimeFormatInfo +/// for the specified culture will be used. +/// +/// +/// You can also use properties exposed by the DateTimeFormatter in order +/// to override some of the default formatting parameters. +/// +/// +/// Aleksandar Seovic +public class DateTimeFormatter : IFormatter { - /// - /// Implementation of that can be used to - /// format and parse values. - /// - /// - /// - /// DateTimeFormatter uses properties of the - /// to format and parse values. - /// - /// - /// If you use one of the constructors that accept culture as a parameter - /// to create an instance of DateTimeFormatter, default DateTimeFormatInfo - /// for the specified culture will be used. - /// - /// - /// You can also use properties exposed by the DateTimeFormatter in order - /// to override some of the default formatting parameters. - /// - /// - /// Aleksandar Seovic - public class DateTimeFormatter : IFormatter - { - private DateTimeFormatInfo formatInfo; - private string format; + private DateTimeFormatInfo formatInfo; + private string format; - #region Constructors + #region Constructors - /// - /// Initializes a new instance of the class - /// using default for the current thread's culture. - /// - /// Date/time format string. - public DateTimeFormatter(string format) : this(format, CultureInfo.CurrentCulture) - {} + /// + /// Initializes a new instance of the class + /// using default for the current thread's culture. + /// + /// Date/time format string. + public DateTimeFormatter(string format) : this(format, CultureInfo.CurrentCulture) + { + } - /// - /// Initializes a new instance of the class - /// using default for the specified culture. - /// - /// Date/time format string. - /// The culture name. - public DateTimeFormatter(string format, string cultureName) : this(format, CultureInfo.CreateSpecificCulture(cultureName)) - {} + /// + /// Initializes a new instance of the class + /// using default for the specified culture. + /// + /// Date/time format string. + /// The culture name. + public DateTimeFormatter(string format, string cultureName) : this(format, CultureInfo.CreateSpecificCulture(cultureName)) + { + } - /// - /// Initializes a new instance of the class - /// using default for the specified culture. - /// - /// Date/time format string. - /// The culture. - public DateTimeFormatter(string format, CultureInfo culture) - { - this.format = format; - this.formatInfo = culture.DateTimeFormat; - } + /// + /// Initializes a new instance of the class + /// using default for the specified culture. + /// + /// Date/time format string. + /// The culture. + public DateTimeFormatter(string format, CultureInfo culture) + { + this.format = format; + this.formatInfo = culture.DateTimeFormat; + } - #endregion + #endregion - /// - /// Formats the specified value. - /// - /// The value to format. - /// Formatted value. - /// If is null. - /// If is not an instance of . - public string Format(object value) - { - AssertUtils.ArgumentNotNull(value, "value"); - if (!(value is DateTime)) - { - throw new ArgumentException("DateTimeFormatter can only be used to format instances of [System.DateTime]."); - } + /// + /// Formats the specified value. + /// + /// The value to format. + /// Formatted value. + /// If is null. + /// If is not an instance of . + public string Format(object value) + { + AssertUtils.ArgumentNotNull(value, "value"); + if (!(value is DateTime)) + { + throw new ArgumentException("DateTimeFormatter can only be used to format instances of [System.DateTime]."); + } - return ((DateTime) value).ToString(format, formatInfo); - } + return ((DateTime) value).ToString(format, formatInfo); + } - /// - /// Parses the specified value. - /// - /// The string to parse. - /// Parsed value. - public object Parse(string value) - { - if (!StringUtils.HasText(value)) - { - return DateTime.MinValue; - } + /// + /// Parses the specified value. + /// + /// The string to parse. + /// Parsed value. + public object Parse(string value) + { + if (!StringUtils.HasText(value)) + { + return DateTime.MinValue; + } - return DateTime.ParseExact(value, format, formatInfo, DateTimeStyles.AllowWhiteSpaces); - } - } + return DateTime.ParseExact(value, format, formatInfo, DateTimeStyles.AllowWhiteSpaces); + } } diff --git a/src/Spring/Spring.Core/Globalization/Formatters/FilteringFormatter.cs b/src/Spring/Spring.Core/Globalization/Formatters/FilteringFormatter.cs index bd7aca08..10bdde8d 100644 --- a/src/Spring/Spring.Core/Globalization/Formatters/FilteringFormatter.cs +++ b/src/Spring/Spring.Core/Globalization/Formatters/FilteringFormatter.cs @@ -18,77 +18,76 @@ #endregion -namespace Spring.Globalization.Formatters +namespace Spring.Globalization.Formatters; + +/// +/// Provides base functionality for filtering values before they actually get parsed/formatted. +/// +/// Erich Eichinger +public abstract class FilteringFormatter : IFormatter { - /// - /// Provides base functionality for filtering values before they actually get parsed/formatted. - /// - /// Erich Eichinger - public abstract class FilteringFormatter : IFormatter + private readonly IFormatter _underlyingFormatter; + + /// + /// Creates a new instance of this FilteringFormatter. + /// + ///an optional underlying formatter + /// + /// If no underlying formatter is specified, the values + /// get passed through "as-is" after being filtered + /// + public FilteringFormatter(IFormatter underlyingFormatter) { - private readonly IFormatter _underlyingFormatter; + _underlyingFormatter = underlyingFormatter; + } - /// - /// Creates a new instance of this FilteringFormatter. - /// - ///an optional underlying formatter - /// - /// If no underlying formatter is specified, the values - /// get passed through "as-is" after being filtered - /// - public FilteringFormatter(IFormatter underlyingFormatter) + /// + /// Parses the specified value. + /// + /// The value to parse. + /// Parsed . + public object Parse(string value) + { + value = FilterValueToParse(value); + + if (_underlyingFormatter != null) { - _underlyingFormatter = underlyingFormatter; + return _underlyingFormatter.Parse(value); } - /// - /// Parses the specified value. - /// - /// The value to parse. - /// Parsed . - public object Parse(string value) + return value; + } + + /// + /// Formats the specified value. + /// + /// The value to format. + /// Formatted . + public string Format(object value) + { + value = FilterValueToFormat(value); + + if (_underlyingFormatter != null) { - value = FilterValueToParse(value); - - if (_underlyingFormatter != null) - { - return _underlyingFormatter.Parse(value); - } - - return value; + return _underlyingFormatter.Format(value); } - /// - /// Formats the specified value. - /// - /// The value to format. - /// Formatted . - public string Format(object value) - { - value = FilterValueToFormat(value); + return (value != null) ? value.ToString() : null; + } - if (_underlyingFormatter != null) - { - return _underlyingFormatter.Format(value); - } + /// + /// Allows to rewrite a value before it gets parsed by the underlying formatter + /// + protected virtual string FilterValueToParse(string value) + { + return value; + } - return (value != null) ? value.ToString() : null; - } - - /// - /// Allows to rewrite a value before it gets parsed by the underlying formatter - /// - protected virtual string FilterValueToParse(string value) - { - return value; - } - - /// - /// Allows to change a value before it gets formatted by the underlying formatter - /// - protected virtual object FilterValueToFormat(object value) - { - return value; - } + /// + /// Allows to change a value before it gets formatted by the underlying formatter + /// + protected virtual object FilterValueToFormat(object value) + { + return value; } } diff --git a/src/Spring/Spring.Core/Globalization/Formatters/FloatFormatter.cs b/src/Spring/Spring.Core/Globalization/Formatters/FloatFormatter.cs index b9d20d8d..30e38220 100644 --- a/src/Spring/Spring.Core/Globalization/Formatters/FloatFormatter.cs +++ b/src/Spring/Spring.Core/Globalization/Formatters/FloatFormatter.cs @@ -19,111 +19,114 @@ #endregion using System.Globalization; - using Spring.Util; -namespace Spring.Globalization.Formatters +namespace Spring.Globalization.Formatters; + +/// +/// Implementation of that can be used to +/// format and parse floating point numbers. +/// +/// +/// +/// This formatter allows you to format and parse numbers that conform +/// to number style (leading and trailing +/// white space, leading sign, decimal point, exponent). +/// +/// +/// Aleksandar Seovic +public class FloatFormatter : IFormatter { - /// - /// Implementation of that can be used to - /// format and parse floating point numbers. - /// - /// - /// - /// This formatter allows you to format and parse numbers that conform - /// to number style (leading and trailing - /// white space, leading sign, decimal point, exponent). - /// - /// - /// Aleksandar Seovic - public class FloatFormatter : IFormatter - { - /// - /// Default format string. - /// - public const string DefaultFormat = "{0:F}"; + /// + /// Default format string. + /// + public const string DefaultFormat = "{0:F}"; - private string format; - private NumberFormatInfo numberInfo; + private string format; + private NumberFormatInfo numberInfo; - #region Constructors + #region Constructors - /// - /// Initializes a new instance of the class, - /// using default format string of '{0:F}' and current thread's culture. - /// - public FloatFormatter() : this(DefaultFormat, CultureInfo.CurrentCulture) - {} + /// + /// Initializes a new instance of the class, + /// using default format string of '{0:F}' and current thread's culture. + /// + public FloatFormatter() : this(DefaultFormat, CultureInfo.CurrentCulture) + { + } - /// - /// Initializes a new instance of the class, - /// using specified format string and current thread's culture. - /// - /// The format string. - public FloatFormatter(string format) : this(format, CultureInfo.CurrentCulture) - {} + /// + /// Initializes a new instance of the class, + /// using specified format string and current thread's culture. + /// + /// The format string. + public FloatFormatter(string format) : this(format, CultureInfo.CurrentCulture) + { + } - /// - /// Initializes a new instance of the class, - /// using default format string of '{0:F}' and specified culture. - /// - /// The culture. - public FloatFormatter(CultureInfo culture) : this(DefaultFormat, culture) - {} + /// + /// Initializes a new instance of the class, + /// using default format string of '{0:F}' and specified culture. + /// + /// The culture. + public FloatFormatter(CultureInfo culture) : this(DefaultFormat, culture) + { + } - /// - /// Initializes a new instance of the class, - /// using specified format string and current thread's culture. - /// - /// The format string. - /// The culture name. - public FloatFormatter(string format, string cultureName) : this(format, CultureInfo.CreateSpecificCulture(cultureName)) - {} + /// + /// Initializes a new instance of the class, + /// using specified format string and current thread's culture. + /// + /// The format string. + /// The culture name. + public FloatFormatter(string format, string cultureName) : this(format, CultureInfo.CreateSpecificCulture(cultureName)) + { + } - /// - /// Initializes a new instance of the class, - /// using specified format string and culture. - /// - /// The format string. - /// The culture. - public FloatFormatter(string format, CultureInfo culture) + /// + /// Initializes a new instance of the class, + /// using specified format string and culture. + /// + /// The format string. + /// The culture. + public FloatFormatter(string format, CultureInfo culture) + { + this.format = format; + this.numberInfo = culture.NumberFormat; + } + + #endregion + + /// + /// Formats the specified float value. + /// + /// The value to format. + /// Formatted floating point number. + /// If is null. + /// If is not a number. + public string Format(object value) + { + AssertUtils.ArgumentNotNull(value, "value"); + if (!NumberUtils.IsNumber(value)) { - this.format = format; - this.numberInfo = culture.NumberFormat; + throw new ArgumentException("FloatFormatter can only be used to format numbers."); } - #endregion + return String.Format(numberInfo, format, value); + } - /// - /// Formats the specified float value. - /// - /// The value to format. - /// Formatted floating point number. - /// If is null. - /// If is not a number. - public string Format(object value) - { - AssertUtils.ArgumentNotNull(value, "value"); - if (!NumberUtils.IsNumber(value)) - { - throw new ArgumentException("FloatFormatter can only be used to format numbers."); - } + /// + /// Parses the specified float value. + /// + /// The float value to parse. + /// Parsed float value as a . + public object Parse(string value) + { + if (!StringUtils.HasText(value)) + { + return 0d; + } - return String.Format(numberInfo, format, value); - } - - /// - /// Parses the specified float value. - /// - /// The float value to parse. - /// Parsed float value as a . - public object Parse(string value) - { - if (!StringUtils.HasText(value)) - { - return 0d; - } - return Double.Parse(value, NumberStyles.Float, numberInfo); - } - } + return Double.Parse(value, NumberStyles.Float, numberInfo); + } } diff --git a/src/Spring/Spring.Core/Globalization/Formatters/HasTextFilteringFormatter.cs b/src/Spring/Spring.Core/Globalization/Formatters/HasTextFilteringFormatter.cs index 8334af24..24d82daa 100644 --- a/src/Spring/Spring.Core/Globalization/Formatters/HasTextFilteringFormatter.cs +++ b/src/Spring/Spring.Core/Globalization/Formatters/HasTextFilteringFormatter.cs @@ -20,55 +20,55 @@ using Spring.Util; -namespace Spring.Globalization.Formatters +namespace Spring.Globalization.Formatters; + +/// +/// Replaces input strings with a given default value, +/// if they are null or contain whitespaces only, +/// +/// Erich Eichinger +public class HasTextFilteringFormatter : FilteringFormatter { - /// - /// Replaces input strings with a given default value, - /// if they are null or contain whitespaces only, - /// - /// Erich Eichinger - public class HasTextFilteringFormatter : FilteringFormatter + private readonly string _defaultValue; + + /// + /// Creates a new instance of this HasTextFilteringFormatter using null as default value. + /// + ///an optional underlying formatter + /// + /// If no underlying formatter is specified, the values + /// get passed through "as-is" after being filtered + /// + public HasTextFilteringFormatter(IFormatter underlyingFormatter) + : this(null, underlyingFormatter) { - private readonly string _defaultValue; - - /// - /// Creates a new instance of this HasTextFilteringFormatter using null as default value. - /// - ///an optional underlying formatter - /// - /// If no underlying formatter is specified, the values - /// get passed through "as-is" after being filtered - /// - public HasTextFilteringFormatter(IFormatter underlyingFormatter) - : this(null, underlyingFormatter) - { - } - - /// - /// Creates a new instance of this HasTextFilteringFormatter. - /// - /// the default value to be returned, if input text doesn't contain text - ///an optional underlying formatter - /// - /// If no underlying formatter is specified, the values - /// get passed through "as-is" after being filtered - /// - public HasTextFilteringFormatter(string defaultValue, IFormatter underlyingFormatter) - : base(underlyingFormatter) - { - _defaultValue = defaultValue; - } - - /// - /// If value contains no text, it will be replaced by a defaultValue. - /// - protected override string FilterValueToParse(string value) - { - if (!StringUtils.HasText(value)) - { - value = _defaultValue; - } - return value; - } } -} + + /// + /// Creates a new instance of this HasTextFilteringFormatter. + /// + /// the default value to be returned, if input text doesn't contain text + ///an optional underlying formatter + /// + /// If no underlying formatter is specified, the values + /// get passed through "as-is" after being filtered + /// + public HasTextFilteringFormatter(string defaultValue, IFormatter underlyingFormatter) + : base(underlyingFormatter) + { + _defaultValue = defaultValue; + } + + /// + /// If value contains no text, it will be replaced by a defaultValue. + /// + protected override string FilterValueToParse(string value) + { + if (!StringUtils.HasText(value)) + { + value = _defaultValue; + } + + return value; + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Globalization/Formatters/IntegerFormatter.cs b/src/Spring/Spring.Core/Globalization/Formatters/IntegerFormatter.cs index f04fdac7..628a6a07 100644 --- a/src/Spring/Spring.Core/Globalization/Formatters/IntegerFormatter.cs +++ b/src/Spring/Spring.Core/Globalization/Formatters/IntegerFormatter.cs @@ -19,77 +19,77 @@ #endregion using System.Globalization; - using Spring.Util; -namespace Spring.Globalization.Formatters +namespace Spring.Globalization.Formatters; + +/// +/// Implementation of that can be used to +/// format and parse integer numbers. +/// +/// +/// +/// This formatter allows you to format and parse numbers that conform +/// to number style (leading and trailing +/// white space, leading sign). +/// +/// +/// Aleksandar Seovic +public class IntegerFormatter : IFormatter { - /// - /// Implementation of that can be used to - /// format and parse integer numbers. - /// - /// - /// - /// This formatter allows you to format and parse numbers that conform - /// to number style (leading and trailing - /// white space, leading sign). - /// - /// - /// Aleksandar Seovic - public class IntegerFormatter : IFormatter - { - private string format = "{0:D}"; + private string format = "{0:D}"; - #region Constructors + #region Constructors - /// - /// Initializes a new instance of the class, - /// using default format string of '{0:D}'. - /// - public IntegerFormatter() - {} + /// + /// Initializes a new instance of the class, + /// using default format string of '{0:D}'. + /// + public IntegerFormatter() + { + } - /// - /// Initializes a new instance of the class, - /// using specified format string. - /// - public IntegerFormatter(string format) + /// + /// Initializes a new instance of the class, + /// using specified format string. + /// + public IntegerFormatter(string format) + { + this.format = format; + } + + #endregion + + /// + /// Formats the specified integer value. + /// + /// The value to format. + /// Formatted integer number. + /// If is null. + /// If is not an integer number. + public string Format(object value) + { + AssertUtils.ArgumentNotNull(value, "value"); + if (!NumberUtils.IsInteger(value)) { - this.format = format; + throw new ArgumentException("IntegerFormatter can only be used to format integer numbers."); } - #endregion + return String.Format(format, value); + } - /// - /// Formats the specified integer value. - /// - /// The value to format. - /// Formatted integer number. - /// If is null. - /// If is not an integer number. - public string Format(object value) - { - AssertUtils.ArgumentNotNull(value, "value"); - if (!NumberUtils.IsInteger(value)) - { - throw new ArgumentException("IntegerFormatter can only be used to format integer numbers."); - } + /// + /// Parses the specified integer value. + /// + /// The integer value to parse. + /// Parsed number value as a . + public object Parse(string value) + { + if (!StringUtils.HasText(value)) + { + return 0; + } - return String.Format(format, value); - } - - /// - /// Parses the specified integer value. - /// - /// The integer value to parse. - /// Parsed number value as a . - public object Parse(string value) - { - if (!StringUtils.HasText(value)) - { - return 0; - } - return Int32.Parse(value, NumberStyles.Integer); - } - } + return Int32.Parse(value, NumberStyles.Integer); + } } diff --git a/src/Spring/Spring.Core/Globalization/Formatters/NullFormatter.cs b/src/Spring/Spring.Core/Globalization/Formatters/NullFormatter.cs index dfc7a627..7f5c1793 100644 --- a/src/Spring/Spring.Core/Globalization/Formatters/NullFormatter.cs +++ b/src/Spring/Spring.Core/Globalization/Formatters/NullFormatter.cs @@ -18,46 +18,45 @@ #endregion -namespace Spring.Globalization.Formatters +namespace Spring.Globalization.Formatters; + +/// +/// Implementation of that simply calls . +/// +/// +/// This formatter is a no-operation implementation. +/// +/// Erich Eichinger +public class NullFormatter : IFormatter { + #region Constructors + /// - /// Implementation of that simply calls . + /// Initializes a new instance of the class. /// - /// - /// This formatter is a no-operation implementation. - /// - /// Erich Eichinger - public class NullFormatter : IFormatter + public NullFormatter() { - #region Constructors + } - /// - /// Initializes a new instance of the class. - /// - public NullFormatter() - { - } + #endregion - #endregion + /// + /// Converts the passed value to a string by calling . + /// + /// The value to convert. + /// to string converted value. + public string Format(object value) + { + return value != null ? value.ToString() : null; + } - /// - /// Converts the passed value to a string by calling . - /// - /// The value to convert. - /// to string converted value. - public string Format(object value) - { - return value != null ? value.ToString() : null; - } - - /// - /// Returns the passed string "as is". - /// - /// The value to return. - /// The value passed into this method. - public object Parse(string value) - { - return value; - } + /// + /// Returns the passed string "as is". + /// + /// The value to return. + /// The value passed into this method. + public object Parse(string value) + { + return value; } } diff --git a/src/Spring/Spring.Core/Globalization/Formatters/NumberFormatter.cs b/src/Spring/Spring.Core/Globalization/Formatters/NumberFormatter.cs index 41db6b78..107ff215 100644 --- a/src/Spring/Spring.Core/Globalization/Formatters/NumberFormatter.cs +++ b/src/Spring/Spring.Core/Globalization/Formatters/NumberFormatter.cs @@ -19,179 +19,179 @@ #endregion using System.Globalization; - using Spring.Util; -namespace Spring.Globalization.Formatters +namespace Spring.Globalization.Formatters; + +/// +/// Implementation of that can be used to +/// format and parse numbers. +/// +/// +/// +/// NumberFormatter uses number-related properties of the +/// to format and parse numbers. +/// +/// +/// This formatter works with both integer and decimal numbers and allows +/// you to format and parse numbers that conform to +/// number style (leading and trailing white space and/or sign, thousands separator, +/// decimal point) +/// +/// +/// If you use one of the constructors that accept culture as a parameter +/// to create an instance of NumberFormatter, default NumberFormatInfo +/// for the specified culture will be used. +/// +/// +/// You can also use properties exposed by the NumberFormatter in order +/// to override some of the default number formatting parameters. +/// +/// +/// Aleksandar Seovic +public class NumberFormatter : IFormatter { - /// - /// Implementation of that can be used to - /// format and parse numbers. - /// - /// - /// - /// NumberFormatter uses number-related properties of the - /// to format and parse numbers. - /// - /// - /// This formatter works with both integer and decimal numbers and allows - /// you to format and parse numbers that conform to - /// number style (leading and trailing white space and/or sign, thousands separator, - /// decimal point) - /// - /// - /// If you use one of the constructors that accept culture as a parameter - /// to create an instance of NumberFormatter, default NumberFormatInfo - /// for the specified culture will be used. - /// - /// - /// You can also use properties exposed by the NumberFormatter in order - /// to override some of the default number formatting parameters. - /// - /// - /// Aleksandar Seovic - public class NumberFormatter : IFormatter - { - private NumberFormatInfo formatInfo; + private NumberFormatInfo formatInfo; - #region Constructors + #region Constructors - /// - /// Initializes a new instance of the class - /// using default for the current thread's culture. - /// - public NumberFormatter() : this(CultureInfo.CurrentCulture) - {} + /// + /// Initializes a new instance of the class + /// using default for the current thread's culture. + /// + public NumberFormatter() : this(CultureInfo.CurrentCulture) + { + } - /// - /// Initializes a new instance of the class - /// using default for the specified culture. - /// - /// The culture name. - public NumberFormatter(string cultureName) : this(CultureInfo.CreateSpecificCulture(cultureName)) - {} + /// + /// Initializes a new instance of the class + /// using default for the specified culture. + /// + /// The culture name. + public NumberFormatter(string cultureName) : this(CultureInfo.CreateSpecificCulture(cultureName)) + { + } - /// - /// Initializes a new instance of the class - /// using default for the specified culture. - /// - /// The culture. - public NumberFormatter(CultureInfo culture) - { - formatInfo = culture.NumberFormat; - } + /// + /// Initializes a new instance of the class + /// using default for the specified culture. + /// + /// The culture. + public NumberFormatter(CultureInfo culture) + { + formatInfo = culture.NumberFormat; + } - /// - /// Initializes a new instance of the class - /// using specified . - /// - /// - /// The instance that defines how - /// numbers are formatted and parsed. - /// - public NumberFormatter(NumberFormatInfo formatInfo) + /// + /// Initializes a new instance of the class + /// using specified . + /// + /// + /// The instance that defines how + /// numbers are formatted and parsed. + /// + public NumberFormatter(NumberFormatInfo formatInfo) + { + this.formatInfo = formatInfo; + } + + #endregion + + #region Properties + + /// + /// Gets or sets the number of decimal digits. + /// + /// The number of decimal digits. + /// + public int DecimalDigits + { + get { return formatInfo.NumberDecimalDigits; } + set { formatInfo.NumberDecimalDigits = value; } + } + + /// + /// Gets or sets the decimal separator. + /// + /// The decimal separator. + /// + public string DecimalSeparator + { + get { return formatInfo.NumberDecimalSeparator; } + set { formatInfo.NumberDecimalSeparator = value; } + } + + /// + /// Gets or sets the number group sizes. + /// + /// The number group sizes. + /// + public int[] GroupSizes + { + get { return formatInfo.NumberGroupSizes; } + set { formatInfo.NumberGroupSizes = value; } + } + + /// + /// Gets or sets the number group separator. + /// + /// The number group separator. + /// + public string GroupSeparator + { + get { return formatInfo.NumberGroupSeparator; } + set { formatInfo.NumberGroupSeparator = value; } + } + + /// + /// Gets or sets the negative pattern. + /// + /// The number negative pattern. + /// + public int NegativePattern + { + get { return formatInfo.NumberNegativePattern; } + set { formatInfo.NumberNegativePattern = value; } + } + + #endregion + + /// + /// Formats the specified number value. + /// + /// The value to format. + /// Formatted number . + /// If is null. + /// If is not a number. + public string Format(object value) + { + AssertUtils.ArgumentNotNull(value, "value"); + if (!NumberUtils.IsNumber(value)) { - this.formatInfo = formatInfo; + throw new ArgumentException("NumberFormatter can only be used to format numbers."); } - #endregion + return String.Format(formatInfo, "{0:N}", value); + } - #region Properties + /// + /// Parses the specified number value. + /// + /// The number value to parse. + /// Parsed number value as a . + public object Parse(string value) + { + if (!StringUtils.HasText(value)) + { + return 0d; + } - /// - /// Gets or sets the number of decimal digits. - /// - /// The number of decimal digits. - /// - public int DecimalDigits - { - get { return formatInfo.NumberDecimalDigits; } - set { formatInfo.NumberDecimalDigits = value; } - } + NumberStyles numberStyle = NumberStyles.Number; + if (formatInfo.NumberNegativePattern == 0) + { + numberStyle |= NumberStyles.AllowParentheses; + } - /// - /// Gets or sets the decimal separator. - /// - /// The decimal separator. - /// - public string DecimalSeparator - { - get { return formatInfo.NumberDecimalSeparator; } - set { formatInfo.NumberDecimalSeparator = value; } - } - - /// - /// Gets or sets the number group sizes. - /// - /// The number group sizes. - /// - public int[] GroupSizes - { - get { return formatInfo.NumberGroupSizes; } - set { formatInfo.NumberGroupSizes = value; } - } - - /// - /// Gets or sets the number group separator. - /// - /// The number group separator. - /// - public string GroupSeparator - { - get { return formatInfo.NumberGroupSeparator; } - set { formatInfo.NumberGroupSeparator = value; } - } - - /// - /// Gets or sets the negative pattern. - /// - /// The number negative pattern. - /// - public int NegativePattern - { - get { return formatInfo.NumberNegativePattern; } - set { formatInfo.NumberNegativePattern = value; } - } - - #endregion - - /// - /// Formats the specified number value. - /// - /// The value to format. - /// Formatted number . - /// If is null. - /// If is not a number. - public string Format(object value) - { - AssertUtils.ArgumentNotNull(value, "value"); - if (!NumberUtils.IsNumber(value)) - { - throw new ArgumentException("NumberFormatter can only be used to format numbers."); - } - - return String.Format(formatInfo, "{0:N}", value); - } - - /// - /// Parses the specified number value. - /// - /// The number value to parse. - /// Parsed number value as a . - public object Parse(string value) - { - if (!StringUtils.HasText(value)) - { - return 0d; - } - - NumberStyles numberStyle = NumberStyles.Number; - if (formatInfo.NumberNegativePattern == 0) - { - numberStyle |= NumberStyles.AllowParentheses; - } - - return Double.Parse(value, numberStyle, formatInfo); - } - } + return Double.Parse(value, numberStyle, formatInfo); + } } diff --git a/src/Spring/Spring.Core/Globalization/Formatters/PercentFormatter.cs b/src/Spring/Spring.Core/Globalization/Formatters/PercentFormatter.cs index 782d8174..1e93dd1d 100644 --- a/src/Spring/Spring.Core/Globalization/Formatters/PercentFormatter.cs +++ b/src/Spring/Spring.Core/Globalization/Formatters/PercentFormatter.cs @@ -19,213 +19,213 @@ #endregion using System.Globalization; - using Spring.Util; -namespace Spring.Globalization.Formatters +namespace Spring.Globalization.Formatters; + +/// +/// Implementation of that can be used to +/// format and parse numbers. +/// +/// +/// +/// PercentFormatter uses percent-related properties of the +/// to format and parse percentages. +/// +/// +/// If you use one of the constructors that accept culture as a parameter +/// to create an instance of PercentFormatter, default NumberFormatInfo +/// for the specified culture will be used. +/// +/// +/// You can also use properties exposed by the PercentFormatter in order +/// to override some of the default number formatting parameters. +/// +/// +/// Aleksandar Seovic +public class PercentFormatter : IFormatter { - /// - /// Implementation of that can be used to - /// format and parse numbers. - /// - /// - /// - /// PercentFormatter uses percent-related properties of the - /// to format and parse percentages. - /// - /// - /// If you use one of the constructors that accept culture as a parameter - /// to create an instance of PercentFormatter, default NumberFormatInfo - /// for the specified culture will be used. - /// - /// - /// You can also use properties exposed by the PercentFormatter in order - /// to override some of the default number formatting parameters. - /// - /// - /// Aleksandar Seovic - public class PercentFormatter : IFormatter - { - private static int[] positivePatterns = new int[] {3, 1, 0}; - private static int[] negativePatterns = new int[] {8, 5, 1}; + private static int[] positivePatterns = new int[] { 3, 1, 0 }; + private static int[] negativePatterns = new int[] { 8, 5, 1 }; - private NumberFormatInfo formatInfo; + private NumberFormatInfo formatInfo; - #region Constructors + #region Constructors - /// - /// Initializes a new instance of the class - /// using default for the current thread's culture. - /// - public PercentFormatter() : this(CultureInfo.CurrentCulture) - {} + /// + /// Initializes a new instance of the class + /// using default for the current thread's culture. + /// + public PercentFormatter() : this(CultureInfo.CurrentCulture) + { + } - /// - /// Initializes a new instance of the class - /// using default for the specified culture. - /// - /// The culture name. - public PercentFormatter(string cultureName) : this(CultureInfo.CreateSpecificCulture(cultureName)) - {} + /// + /// Initializes a new instance of the class + /// using default for the specified culture. + /// + /// The culture name. + public PercentFormatter(string cultureName) : this(CultureInfo.CreateSpecificCulture(cultureName)) + { + } - /// - /// Initializes a new instance of the class - /// using default for the specified culture. - /// - /// The culture. - public PercentFormatter(CultureInfo culture) - { - formatInfo = culture.NumberFormat; - } + /// + /// Initializes a new instance of the class + /// using default for the specified culture. + /// + /// The culture. + public PercentFormatter(CultureInfo culture) + { + formatInfo = culture.NumberFormat; + } - /// - /// Initializes a new instance of the class - /// using specified . - /// - /// - /// The instance that defines how - /// numbers are formatted and parsed. - /// - public PercentFormatter(NumberFormatInfo formatInfo) + /// + /// Initializes a new instance of the class + /// using specified . + /// + /// + /// The instance that defines how + /// numbers are formatted and parsed. + /// + public PercentFormatter(NumberFormatInfo formatInfo) + { + this.formatInfo = formatInfo; + } + + #endregion + + #region Properties + + /// + /// Gets or sets the number of decimal digits. + /// + /// The number of decimal digits. + /// + public int DecimalDigits + { + get { return formatInfo.PercentDecimalDigits; } + set { formatInfo.PercentDecimalDigits = value; } + } + + /// + /// Gets or sets the decimal separator. + /// + /// The decimal separator. + /// + public string DecimalSeparator + { + get { return formatInfo.PercentDecimalSeparator; } + set { formatInfo.PercentDecimalSeparator = value; } + } + + /// + /// Gets or sets the percent group sizes. + /// + /// The percent group sizes. + /// + public int[] GroupSizes + { + get { return formatInfo.PercentGroupSizes; } + set { formatInfo.PercentGroupSizes = value; } + } + + /// + /// Gets or sets the percent group separator. + /// + /// The percent group separator. + /// + public string GroupSeparator + { + get { return formatInfo.PercentGroupSeparator; } + set { formatInfo.PercentGroupSeparator = value; } + } + + /// + /// Gets or sets the negative pattern. + /// + /// The percent negative pattern. + /// + public int NegativePattern + { + get { return formatInfo.PercentNegativePattern; } + set { formatInfo.PercentNegativePattern = value; } + } + + /// + /// Gets or sets the positive pattern. + /// + /// The percent positive pattern. + /// + public int PositivePattern + { + get { return formatInfo.PercentPositivePattern; } + set { formatInfo.PercentPositivePattern = value; } + } + + /// + /// Gets or sets the percent symbol. + /// + /// The percent symbol. + /// + public string PercentSymbol + { + get { return formatInfo.PercentSymbol; } + set { formatInfo.PercentSymbol = value; } + } + + /// + /// Gets or sets the per mille symbol. + /// + /// The per mille symbol. + /// + public string PerMilleSymbol + { + get { return formatInfo.PerMilleSymbol; } + set { formatInfo.PerMilleSymbol = value; } + } + + #endregion + + /// + /// Formats the specified percentage value. + /// + /// The value to format. + /// Formatted percentage. + /// If is null. + /// If is not a number. + public string Format(object value) + { + AssertUtils.ArgumentNotNull(value, "value"); + if (!NumberUtils.IsNumber(value)) { - this.formatInfo = formatInfo; + throw new ArgumentException("PercentFormatter can only be used to format numbers."); } - #endregion + return String.Format(formatInfo, "{0:P}", value); + } - #region Properties - - /// - /// Gets or sets the number of decimal digits. - /// - /// The number of decimal digits. - /// - public int DecimalDigits - { - get { return formatInfo.PercentDecimalDigits; } - set { formatInfo.PercentDecimalDigits = value; } - } - - /// - /// Gets or sets the decimal separator. - /// - /// The decimal separator. - /// - public string DecimalSeparator - { - get { return formatInfo.PercentDecimalSeparator; } - set { formatInfo.PercentDecimalSeparator = value; } - } - - /// - /// Gets or sets the percent group sizes. - /// - /// The percent group sizes. - /// - public int[] GroupSizes - { - get { return formatInfo.PercentGroupSizes; } - set { formatInfo.PercentGroupSizes = value; } - } - - /// - /// Gets or sets the percent group separator. - /// - /// The percent group separator. - /// - public string GroupSeparator - { - get { return formatInfo.PercentGroupSeparator; } - set { formatInfo.PercentGroupSeparator = value; } - } - - /// - /// Gets or sets the negative pattern. - /// - /// The percent negative pattern. - /// - public int NegativePattern - { - get { return formatInfo.PercentNegativePattern; } - set { formatInfo.PercentNegativePattern = value; } - } - - /// - /// Gets or sets the positive pattern. - /// - /// The percent positive pattern. - /// - public int PositivePattern + /// + /// Parses the specified percentage value. + /// + /// The percentage value to parse. + /// Parsed percentage value as a . + public object Parse(string value) + { + if (!StringUtils.HasText(value)) { - get { return formatInfo.PercentPositivePattern; } - set { formatInfo.PercentPositivePattern = value; } + return 0d; } - /// - /// Gets or sets the percent symbol. - /// - /// The percent symbol. - /// - public string PercentSymbol - { - get { return formatInfo.PercentSymbol; } - set { formatInfo.PercentSymbol = value; } - } + // there is no percentage parser in .NET, so we use currency parser to achieve the goal + NumberFormatInfo fi = (NumberFormatInfo) formatInfo.Clone(); + fi.CurrencyDecimalDigits = formatInfo.PercentDecimalDigits; + fi.CurrencyDecimalSeparator = formatInfo.PercentDecimalSeparator; + fi.CurrencyGroupSeparator = formatInfo.PercentGroupSeparator; + fi.CurrencyGroupSizes = formatInfo.PercentGroupSizes; + fi.CurrencyNegativePattern = negativePatterns[formatInfo.PercentNegativePattern]; + fi.CurrencyPositivePattern = positivePatterns[formatInfo.PercentPositivePattern]; + fi.CurrencySymbol = formatInfo.PercentSymbol; - /// - /// Gets or sets the per mille symbol. - /// - /// The per mille symbol. - /// - public string PerMilleSymbol - { - get { return formatInfo.PerMilleSymbol; } - set { formatInfo.PerMilleSymbol = value; } - } - - #endregion - - /// - /// Formats the specified percentage value. - /// - /// The value to format. - /// Formatted percentage. - /// If is null. - /// If is not a number. - public string Format(object value) - { - AssertUtils.ArgumentNotNull(value, "value"); - if (!NumberUtils.IsNumber(value)) - { - throw new ArgumentException("PercentFormatter can only be used to format numbers."); - } - - return String.Format(formatInfo, "{0:P}", value); - } - - /// - /// Parses the specified percentage value. - /// - /// The percentage value to parse. - /// Parsed percentage value as a . - public object Parse(string value) - { - if (!StringUtils.HasText(value)) - { - return 0d; - } - - // there is no percentage parser in .NET, so we use currency parser to achieve the goal - NumberFormatInfo fi = (NumberFormatInfo) formatInfo.Clone(); - fi.CurrencyDecimalDigits = formatInfo.PercentDecimalDigits; - fi.CurrencyDecimalSeparator = formatInfo.PercentDecimalSeparator; - fi.CurrencyGroupSeparator = formatInfo.PercentGroupSeparator; - fi.CurrencyGroupSizes = formatInfo.PercentGroupSizes; - fi.CurrencyNegativePattern = negativePatterns[formatInfo.PercentNegativePattern]; - fi.CurrencyPositivePattern = positivePatterns[formatInfo.PercentPositivePattern]; - fi.CurrencySymbol = formatInfo.PercentSymbol; - - return Double.Parse(value, NumberStyles.Currency, fi) / 100; - } - } + return Double.Parse(value, NumberStyles.Currency, fi) / 100; + } } diff --git a/src/Spring/Spring.Core/Globalization/ICultureResolver.cs b/src/Spring/Spring.Core/Globalization/ICultureResolver.cs index 59de3dc8..11e807a7 100644 --- a/src/Spring/Spring.Core/Globalization/ICultureResolver.cs +++ b/src/Spring/Spring.Core/Globalization/ICultureResolver.cs @@ -20,47 +20,46 @@ using System.Globalization; -namespace Spring.Globalization +namespace Spring.Globalization; + +/// +/// Strategy interface for +/// resolution. +/// +/// Aleksandar Seovic +public interface ICultureResolver { /// - /// Strategy interface for - /// resolution. + /// Resolves the + /// from some context. /// - /// Aleksandar Seovic - public interface ICultureResolver - { - /// - /// Resolves the - /// from some context. - /// - /// - ///

- /// The 'context' is determined by the appropriate implementation class. - /// An example of such a context might be a thread local bound - /// , or a - /// sourced from an HTTP - /// session. - ///

- ///
- /// - /// The that should be used - /// by the caller. - /// - CultureInfo ResolveCulture(); + /// + ///

+ /// The 'context' is determined by the appropriate implementation class. + /// An example of such a context might be a thread local bound + /// , or a + /// sourced from an HTTP + /// session. + ///

+ ///
+ /// + /// The that should be used + /// by the caller. + /// + CultureInfo ResolveCulture(); - /// - /// Sets the . - /// - /// - ///

- /// This is an optional operation and does not need to be implemented - /// such that it actually does anything useful (i.e. it can be a no-op). - ///

- ///
- /// - /// The new or - /// to clear the current . - /// - void SetCulture(CultureInfo culture); - } + /// + /// Sets the . + /// + /// + ///

+ /// This is an optional operation and does not need to be implemented + /// such that it actually does anything useful (i.e. it can be a no-op). + ///

+ ///
+ /// + /// The new or + /// to clear the current . + /// + void SetCulture(CultureInfo culture); } diff --git a/src/Spring/Spring.Core/Globalization/IFormatter.cs b/src/Spring/Spring.Core/Globalization/IFormatter.cs index f95bcdce..6d05456f 100644 --- a/src/Spring/Spring.Core/Globalization/IFormatter.cs +++ b/src/Spring/Spring.Core/Globalization/IFormatter.cs @@ -18,33 +18,32 @@ #endregion -namespace Spring.Globalization +namespace Spring.Globalization; + +/// +/// Interface that should be implemented by all formatters. +/// +/// +/// +/// Formatters assume that source value is a string, and make no assumptions +/// about the target value's type, which means that Parse method can return +/// object of any type. +/// +/// +/// Aleksandar Seovic +public interface IFormatter { /// - /// Interface that should be implemented by all formatters. + /// Formats the specified value. /// - /// - /// - /// Formatters assume that source value is a string, and make no assumptions - /// about the target value's type, which means that Parse method can return - /// object of any type. - /// - /// - /// Aleksandar Seovic - public interface IFormatter - { - /// - /// Formats the specified value. - /// - /// The value to format. - /// Formatted . - string Format(object value); + /// The value to format. + /// Formatted . + string Format(object value); - /// - /// Parses the specified value. - /// - /// The value to parse. - /// Parsed . - object Parse(string value); - } -} \ No newline at end of file + /// + /// Parses the specified value. + /// + /// The value to parse. + /// Parsed . + object Parse(string value); +} diff --git a/src/Spring/Spring.Core/Globalization/ILocalizer.cs b/src/Spring/Spring.Core/Globalization/ILocalizer.cs index 4eec905f..64223690 100644 --- a/src/Spring/Spring.Core/Globalization/ILocalizer.cs +++ b/src/Spring/Spring.Core/Globalization/ILocalizer.cs @@ -19,42 +19,40 @@ #endregion using System.Globalization; - using Spring.Context; -namespace Spring.Globalization +namespace Spring.Globalization; + +/// +/// Defines an interface that localizers have to implement. +/// +/// +///

+/// Localizers are used to automatically apply resources to object's members +/// using reflection. +///

+///
+/// Aleksandar Seovic +public interface ILocalizer { /// - /// Defines an interface that localizers have to implement. + /// Gets or sets the resource cache instance. /// - /// - ///

- /// Localizers are used to automatically apply resources to object's members - /// using reflection. - ///

- ///
- /// Aleksandar Seovic - public interface ILocalizer - { - /// - /// Gets or sets the resource cache instance. - /// - /// The resource cache instance. - IResourceCache ResourceCache { get; set; } - - /// - /// Applies resources of the specified culture to the specified target object. - /// - /// Target object to apply resources to. - /// instance to retrieve resources from. - /// Resource culture to use for resource lookup. - void ApplyResources(object target, IMessageSource messageSource, CultureInfo culture); + /// The resource cache instance. + IResourceCache ResourceCache { get; set; } - /// - /// Applies resources to the specified target object, using current thread's culture to resolve resources. - /// - /// Target object to apply resources to. - /// instance to retrieve resources from. - void ApplyResources(object target, IMessageSource messageSource); - } -} \ No newline at end of file + /// + /// Applies resources of the specified culture to the specified target object. + /// + /// Target object to apply resources to. + /// instance to retrieve resources from. + /// Resource culture to use for resource lookup. + void ApplyResources(object target, IMessageSource messageSource, CultureInfo culture); + + /// + /// Applies resources to the specified target object, using current thread's culture to resolve resources. + /// + /// Target object to apply resources to. + /// instance to retrieve resources from. + void ApplyResources(object target, IMessageSource messageSource); +} diff --git a/src/Spring/Spring.Core/Globalization/IResourceCache.cs b/src/Spring/Spring.Core/Globalization/IResourceCache.cs index 80f36d32..460da2e0 100644 --- a/src/Spring/Spring.Core/Globalization/IResourceCache.cs +++ b/src/Spring/Spring.Core/Globalization/IResourceCache.cs @@ -20,29 +20,28 @@ using System.Globalization; -namespace Spring.Globalization +namespace Spring.Globalization; + +/// +/// Defines an interface that resource cache adapters have to implement. +/// +/// Aleksandar Seovic +public interface IResourceCache { /// - /// Defines an interface that resource cache adapters have to implement. + /// Gets the list of resources from cache. /// - /// Aleksandar Seovic - public interface IResourceCache - { - /// - /// Gets the list of resources from cache. - /// - /// Target to get a list of resources for. - /// Resource culture. - /// A list of cached resources for the specified target object and culture. - IList GetResources(object target, CultureInfo culture); + /// Target to get a list of resources for. + /// Resource culture. + /// A list of cached resources for the specified target object and culture. + IList GetResources(object target, CultureInfo culture); - /// - /// Puts the list of resources in the cache. - /// - /// Target to cache a list of resources for. - /// Resource culture. - /// A list of resources to cache. - /// A list of cached resources for the specified target object and culture. - void PutResources(object target, CultureInfo culture, IList resources); - } + /// + /// Puts the list of resources in the cache. + /// + /// Target to cache a list of resources for. + /// Resource culture. + /// A list of resources to cache. + /// A list of cached resources for the specified target object and culture. + void PutResources(object target, CultureInfo culture, IList resources); } diff --git a/src/Spring/Spring.Core/Globalization/Localizers/ResourceSetLocalizer.cs b/src/Spring/Spring.Core/Globalization/Localizers/ResourceSetLocalizer.cs index 48d6e25e..09b3d3d5 100644 --- a/src/Spring/Spring.Core/Globalization/Localizers/ResourceSetLocalizer.cs +++ b/src/Spring/Spring.Core/Globalization/Localizers/ResourceSetLocalizer.cs @@ -26,79 +26,80 @@ using Spring.Context; using Spring.Context.Support; using Spring.Expressions; -namespace Spring.Globalization.Localizers +namespace Spring.Globalization.Localizers; + +/// +/// Loads a list of resources that should be applied from the .NET . +/// +/// +///

+/// This implementation will iterate over all resource managers +/// within the message source and return a list of all the resources whose name starts with '$this'. +///

+///

+/// All other resources will be ignored, but you can retrieve them by calling one of +/// GetMessage methods on the message source directly. +///

+///
+/// Aleksandar Seovic +public class ResourceSetLocalizer : AbstractLocalizer { + private static readonly ILogger log = LogManager.GetLogger(); + + private static readonly IList ignoreList = + new string[] { "$this.DefaultModifiers", "$this.TrayAutoArrange", "$this.TrayLargeIcon" }; + /// - /// Loads a list of resources that should be applied from the .NET . + /// Loads resources from the storage and creates a list of instances that should be applied to the target. /// /// - ///

- /// This implementation will iterate over all resource managers - /// within the message source and return a list of all the resources whose name starts with '$this'. - ///

- ///

- /// All other resources will be ignored, but you can retrieve them by calling one of - /// GetMessage methods on the message source directly. - ///

+ /// This feature is not currently supported on version 1.0 of the .NET platform. ///
- /// Aleksandar Seovic - public class ResourceSetLocalizer : AbstractLocalizer + /// Target to get a list of resources for. + /// instance to retrieve resources from. + /// Resource locale. + /// A list of resources to apply. + protected override IList LoadResources(object target, IMessageSource messageSource, CultureInfo culture) { - private static readonly ILogger log = LogManager.GetLogger(); + IList resources = new List(); - private static readonly IList ignoreList = - new string[] {"$this.DefaultModifiers", "$this.TrayAutoArrange", "$this.TrayLargeIcon"}; - - /// - /// Loads resources from the storage and creates a list of instances that should be applied to the target. - /// - /// - /// This feature is not currently supported on version 1.0 of the .NET platform. - /// - /// Target to get a list of resources for. - /// instance to retrieve resources from. - /// Resource locale. - /// A list of resources to apply. - protected override IList LoadResources(object target, IMessageSource messageSource, CultureInfo culture) + if (messageSource is ResourceSetMessageSource) { - IList resources = new List(); - - if (messageSource is ResourceSetMessageSource) + for (int i = 0; i < ((ResourceSetMessageSource) messageSource).ResourceManagers.Count; i++) { - for (int i = 0; i < ((ResourceSetMessageSource) messageSource).ResourceManagers.Count; i++) + ResourceManager rm = ((ResourceSetMessageSource) messageSource).ResourceManagers[i] as ResourceManager; + ResourceSet invariantResources = null; + try { - ResourceManager rm = ((ResourceSetMessageSource) messageSource).ResourceManagers[i] as ResourceManager; - ResourceSet invariantResources = null; - try - { - invariantResources = rm.GetResourceSet(CultureInfo.InvariantCulture, true, true); - } - catch (MissingManifestResourceException mmrex) - { - // ignore but log missing ResourceSet - log.LogDebug(mmrex, "No ResourceSet available for invariant culture"); - } + invariantResources = rm.GetResourceSet(CultureInfo.InvariantCulture, true, true); + } + catch (MissingManifestResourceException mmrex) + { + // ignore but log missing ResourceSet + log.LogDebug(mmrex, "No ResourceSet available for invariant culture"); + } - if (invariantResources != null) + if (invariantResources != null) + { + foreach (DictionaryEntry resource in invariantResources) { - foreach (DictionaryEntry resource in invariantResources) + string resourceName = (string) resource.Key; + if (resourceName.StartsWith("$this") && !ignoreList.Contains(resourceName)) { - string resourceName = (string)resource.Key; - if (resourceName.StartsWith("$this") && !ignoreList.Contains(resourceName)) + // redirect resource resolution if necessary + object resourceValue = rm.GetObject(resourceName, culture); + if (resourceValue is String && ((String) resourceValue).StartsWith("$messageSource")) { - // redirect resource resolution if necessary - object resourceValue = rm.GetObject(resourceName, culture); - if (resourceValue is String && ((String)resourceValue).StartsWith("$messageSource")) - { - resourceValue = messageSource.GetResourceObject(((String)resourceValue).Substring(15), culture); - } - resources.Add(new Resource(Expression.ParsePrimary(resourceName.Substring(6)), resourceValue)); + resourceValue = messageSource.GetResourceObject(((String) resourceValue).Substring(15), culture); } + + resources.Add(new Resource(Expression.ParsePrimary(resourceName.Substring(6)), resourceValue)); } } } } - return resources; } + + return resources; } } diff --git a/src/Spring/Spring.Core/Globalization/NullResourceCache.cs b/src/Spring/Spring.Core/Globalization/NullResourceCache.cs index cd5fad4b..41cb15e9 100644 --- a/src/Spring/Spring.Core/Globalization/NullResourceCache.cs +++ b/src/Spring/Spring.Core/Globalization/NullResourceCache.cs @@ -18,30 +18,30 @@ #endregion -namespace Spring.Globalization +namespace Spring.Globalization; + +/// +/// Resource cache implementation that doesn't cache resources. +/// +/// Aleksandar Seovic +public class NullResourceCache : AbstractResourceCache { /// - /// Resource cache implementation that doesn't cache resources. + /// Gets the list of resources from cache. /// - /// Aleksandar Seovic - public class NullResourceCache : AbstractResourceCache + /// Cache key to use for lookup. + /// Always returns null. + protected override IList GetResources(string cacheKey) { - /// - /// Gets the list of resources from cache. - /// - /// Cache key to use for lookup. - /// Always returns null. - protected override IList GetResources(string cacheKey) - { - return null; - } + return null; + } - /// - /// Puts the list of resources in the cache. - /// - /// Cache key to use for the specified resources. - /// A list of resources to cache. - protected override void PutResources(string cacheKey, IList resources) - {} + /// + /// Puts the list of resources in the cache. + /// + /// Cache key to use for the specified resources. + /// A list of resources to cache. + protected override void PutResources(string cacheKey, IList resources) + { } } diff --git a/src/Spring/Spring.Core/Globalization/Resolvers/DefaultCultureResolver.cs b/src/Spring/Spring.Core/Globalization/Resolvers/DefaultCultureResolver.cs index ee4c73bc..1463e1cb 100644 --- a/src/Spring/Spring.Core/Globalization/Resolvers/DefaultCultureResolver.cs +++ b/src/Spring/Spring.Core/Globalization/Resolvers/DefaultCultureResolver.cs @@ -21,98 +21,97 @@ using System.Globalization; using System.Threading; -namespace Spring.Globalization.Resolvers +namespace Spring.Globalization.Resolvers; + +/// +/// implementation +/// that simply returns the +/// value of the +/// +/// property (if said property value is not ), or the +/// of the current thread if it is +/// . +/// +/// Aleksandar Seovic +public class DefaultCultureResolver : ICultureResolver { + private CultureInfo defaultCulture; + /// - /// implementation - /// that simply returns the - /// value of the + /// The default . + /// + /// + /// The default . + /// + public CultureInfo DefaultCulture + { + get { return defaultCulture; } + set { defaultCulture = value; } + } + + /// + /// Returns the default . + /// + /// + ///

+ /// It tries to get the + /// from the value of the + /// + /// property and falls back to the of the + /// current thread if the + /// + /// is . + ///

+ ///
+ /// + /// The default + /// + protected virtual CultureInfo GetDefaultLocale() + { + if (defaultCulture != null) + { + return defaultCulture; + } + else + { + return Thread.CurrentThread.CurrentUICulture; + } + } + + /// + /// Resolves the + /// from some context. + /// + /// + ///

+ /// The 'context' in this implementation is the + /// value of the /// /// property (if said property value is not ), or the /// of the current thread if it is /// . - /// - /// Aleksandar Seovic - public class DefaultCultureResolver : ICultureResolver + ///

+ ///
+ /// + /// The that should be used + /// by the caller. + /// + public virtual CultureInfo ResolveCulture() { - private CultureInfo defaultCulture; + return GetDefaultLocale(); + } - /// - /// The default . - /// - /// - /// The default . - /// - public CultureInfo DefaultCulture - { - get { return defaultCulture; } - set { defaultCulture = value; } - } - - /// - /// Returns the default . - /// - /// - ///

- /// It tries to get the - /// from the value of the - /// - /// property and falls back to the of the - /// current thread if the - /// - /// is . - ///

- ///
- /// - /// The default - /// - protected virtual CultureInfo GetDefaultLocale() - { - if (defaultCulture != null) - { - return defaultCulture; - } - else - { - return Thread.CurrentThread.CurrentUICulture; - } - } - - /// - /// Resolves the - /// from some context. - /// - /// - ///

- /// The 'context' in this implementation is the - /// value of the - /// - /// property (if said property value is not ), or the - /// of the current thread if it is - /// . - ///

- ///
- /// - /// The that should be used - /// by the caller. - /// - public virtual CultureInfo ResolveCulture() - { - return GetDefaultLocale(); - } - - /// - /// Sets the . - /// - /// - /// The new or - /// to clear the current . - /// - /// - /// - public virtual void SetCulture(CultureInfo culture) - { - defaultCulture = culture; - } + /// + /// Sets the . + /// + /// + /// The new or + /// to clear the current . + /// + /// + /// + public virtual void SetCulture(CultureInfo culture) + { + defaultCulture = culture; } } diff --git a/src/Spring/Spring.Core/Globalization/Resource.cs b/src/Spring/Spring.Core/Globalization/Resource.cs index 8990d5a4..f9fc09a4 100644 --- a/src/Spring/Spring.Core/Globalization/Resource.cs +++ b/src/Spring/Spring.Core/Globalization/Resource.cs @@ -20,45 +20,44 @@ using Spring.Expressions; -namespace Spring.Globalization +namespace Spring.Globalization; + +/// +/// Holds mapping between control property and it's value +/// as read from the resource file. +/// +/// Aleksandar Seovic +[Serializable] +public class Resource { - /// - /// Holds mapping between control property and it's value - /// as read from the resource file. - /// - /// Aleksandar Seovic - [Serializable] - public class Resource + private IExpression target; + private object resourceValue; + + /// + /// Creates instance of resource mapper. + /// + /// Target property. + /// Resource value. + public Resource(IExpression target, object resourceValue) { - private IExpression target; - private object resourceValue; + this.target = target; + this.resourceValue = resourceValue; + } - /// - /// Creates instance of resource mapper. - /// - /// Target property. - /// Resource value. - public Resource(IExpression target, object resourceValue) - { - this.target = target; - this.resourceValue = resourceValue; - } + /// + /// Gets parsed target property expression. See + /// for more information on object navigation expressions. + /// + public IExpression Target + { + get { return target; } + } - /// - /// Gets parsed target property expression. See - /// for more information on object navigation expressions. - /// - public IExpression Target - { - get { return target; } - } - - /// - /// Value of the resource that target property should be set to. - /// - public object Value - { - get { return resourceValue; } - } + /// + /// Value of the resource that target property should be set to. + /// + public object Value + { + get { return resourceValue; } } } diff --git a/src/Spring/Spring.Core/LogManager.cs b/src/Spring/Spring.Core/LogManager.cs index b3811c53..dce1f3cc 100644 --- a/src/Spring/Spring.Core/LogManager.cs +++ b/src/Spring/Spring.Core/LogManager.cs @@ -1,4 +1,5 @@ #region License + // /* // * Copyright 2018 the original author or authors. // * @@ -14,6 +15,7 @@ // * See the License for the specific language governing permissions and // * limitations under the License. // */ + #endregion using Microsoft.Extensions.Logging; diff --git a/src/Spring/Spring.Core/Objects/Events/IEventRegistry.cs b/src/Spring/Spring.Core/Objects/Events/IEventRegistry.cs index 2c280836..b560d1b0 100644 --- a/src/Spring/Spring.Core/Objects/Events/IEventRegistry.cs +++ b/src/Spring/Spring.Core/Objects/Events/IEventRegistry.cs @@ -18,57 +18,56 @@ #endregion -namespace Spring.Objects.Events +namespace Spring.Objects.Events; + +/// +/// A registry that manages subscriptions to and the +/// publishing of events. +/// +/// Griffin Caprio +public interface IEventRegistry { - /// - /// A registry that manages subscriptions to and the - /// publishing of events. - /// - /// Griffin Caprio - public interface IEventRegistry - { - /// - /// Publishes all events of the source object. - /// - /// - /// The source object containing events to publish. - /// - void PublishEvents(object sourceObject); + /// + /// Publishes all events of the source object. + /// + /// + /// The source object containing events to publish. + /// + void PublishEvents(object sourceObject); - /// - /// Subscribes to all events published, if the subscriber - /// implements compatible handler methods. - /// - /// The subscriber to use. - void Subscribe(object subscriber); + /// + /// Subscribes to all events published, if the subscriber + /// implements compatible handler methods. + /// + /// The subscriber to use. + void Subscribe(object subscriber); - /// - /// Subscribes to the published events of all objects of a given - /// , if the subscriber implements - /// compatible handler methods. - /// - /// The subscriber to use. - /// - /// The target to subscribe to. - /// - void Subscribe(object subscriber, Type targetSourceType); + /// + /// Subscribes to the published events of all objects of a given + /// , if the subscriber implements + /// compatible handler methods. + /// + /// The subscriber to use. + /// + /// The target to subscribe to. + /// + void Subscribe(object subscriber, Type targetSourceType); - /// - /// Unsubscribes to all events published, if the subscriber - /// implmenets compatible handler methods. - /// - /// The subscriber to use - void Unsubscribe(object subscriber); + /// + /// Unsubscribes to all events published, if the subscriber + /// implmenets compatible handler methods. + /// + /// The subscriber to use + void Unsubscribe(object subscriber); - /// - /// Unsubscribes to the published events of all objects of a given - /// , if the subscriber implements - /// compatible handler methods. - /// - /// The subscriber to use. - /// - /// The target to unsubscribe from - /// - void Unsubscribe(object subscriber, Type targetSourceType); - } + /// + /// Unsubscribes to the published events of all objects of a given + /// , if the subscriber implements + /// compatible handler methods. + /// + /// The subscriber to use. + /// + /// The target to unsubscribe from + /// + void Unsubscribe(object subscriber, Type targetSourceType); } diff --git a/src/Spring/Spring.Core/Objects/Events/IEventRegistryAware.cs b/src/Spring/Spring.Core/Objects/Events/IEventRegistryAware.cs index 77f59246..ab5f1aca 100644 --- a/src/Spring/Spring.Core/Objects/Events/IEventRegistryAware.cs +++ b/src/Spring/Spring.Core/Objects/Events/IEventRegistryAware.cs @@ -18,40 +18,39 @@ #endregion -namespace Spring.Objects.Events +namespace Spring.Objects.Events; + +/// +/// To be implemented by any object that wishes to receive a reference to +/// an . +/// +/// +///

+/// This interface only applies to objects that have been instantiated +/// within the context of an +/// . This interface does +/// not typically need to be implemented by application code, but is rather +/// used by classes internal to Spring.NET. +///

+///
+/// Mark Pollack +/// Rick Evans +public interface IEventRegistryAware { - /// - /// To be implemented by any object that wishes to receive a reference to - /// an . - /// - /// - ///

- /// This interface only applies to objects that have been instantiated - /// within the context of an - /// . This interface does - /// not typically need to be implemented by application code, but is rather - /// used by classes internal to Spring.NET. - ///

- ///
- /// Mark Pollack - /// Rick Evans - public interface IEventRegistryAware - { - /// - /// Set the - /// associated with the - /// that created this - /// object. - /// - /// - ///

- /// This property will be set by the relevant - /// after all of this - /// object's dependencies have been resolved. This object can use the - /// supplied - /// immediately to publish or subscribe to one or more events. - ///

- ///
- IEventRegistry EventRegistry { set; } - } + /// + /// Set the + /// associated with the + /// that created this + /// object. + /// + /// + ///

+ /// This property will be set by the relevant + /// after all of this + /// object's dependencies have been resolved. This object can use the + /// supplied + /// immediately to publish or subscribe to one or more events. + ///

+ ///
+ IEventRegistry EventRegistry { set; } } diff --git a/src/Spring/Spring.Core/Objects/Events/Support/EventManipulationUtils.cs b/src/Spring/Spring.Core/Objects/Events/Support/EventManipulationUtils.cs index 097ef6b0..b91ae0f5 100644 --- a/src/Spring/Spring.Core/Objects/Events/Support/EventManipulationUtils.cs +++ b/src/Spring/Spring.Core/Objects/Events/Support/EventManipulationUtils.cs @@ -22,94 +22,94 @@ using System.Reflection; using Spring.Core; using Spring.Util; -namespace Spring.Objects.Events.Support +namespace Spring.Objects.Events.Support; + +/// +/// Utility class to aid in the manipulation of events and delegates. +/// +/// Griffin Caprio +public sealed class EventManipulationUtils { - /// - /// Utility class to aid in the manipulation of events and delegates. - /// - /// Griffin Caprio - public sealed class EventManipulationUtils - { - /// - /// Returns a new instance of the requested . - /// - /// - ///

- /// Often used to wire subscribers to event publishers. - ///

- ///
- /// - /// The of delegate to create. - /// - /// - /// The target subscriber object that contains the delegate implementation. - /// - /// - /// referencing the delegate method on the subscriber. - /// - /// - /// A delegate handler that can be added to an events list of handlers, or called directly. - /// - public static Delegate GetHandlerDelegate( - Type delegateType, object targetSubscriber, MethodInfo targetSubscriberDelegateMethod) - { - return Delegate.CreateDelegate( - delegateType, targetSubscriber, targetSubscriberDelegateMethod.Name); - } + /// + /// Returns a new instance of the requested . + /// + /// + ///

+ /// Often used to wire subscribers to event publishers. + ///

+ ///
+ /// + /// The of delegate to create. + /// + /// + /// The target subscriber object that contains the delegate implementation. + /// + /// + /// referencing the delegate method on the subscriber. + /// + /// + /// A delegate handler that can be added to an events list of handlers, or called directly. + /// + public static Delegate GetHandlerDelegate( + Type delegateType, object targetSubscriber, MethodInfo targetSubscriberDelegateMethod) + { + return Delegate.CreateDelegate( + delegateType, targetSubscriber, targetSubscriberDelegateMethod.Name); + } - /// - /// Queries the input type for a signature matching the input - /// signature. - /// - /// - /// Typically used to query a potential subscriber to see if they implement an event handler. - /// - /// to match against - /// to query - /// - /// matching input - /// signature, or if there is no match. - /// - public static MethodInfo GetMethodInfoMatchingSignature( - MethodInfo invoke, Type subscriberType) - { - ParameterInfo[] parameters = invoke.GetParameters(); + /// + /// Queries the input type for a signature matching the input + /// signature. + /// + /// + /// Typically used to query a potential subscriber to see if they implement an event handler. + /// + /// to match against + /// to query + /// + /// matching input + /// signature, or if there is no match. + /// + public static MethodInfo GetMethodInfoMatchingSignature( + MethodInfo invoke, Type subscriberType) + { + ParameterInfo[] parameters = invoke.GetParameters(); - ComposedCriteria criteria = new ComposedCriteria(); - criteria.Add(new MethodReturnTypeCriteria(invoke.ReturnType)); - criteria.Add(new MethodParametersCountCriteria(parameters.Length)); - criteria.Add(new MethodParametersCriteria(ReflectionUtils.GetParameterTypes(parameters))); + ComposedCriteria criteria = new ComposedCriteria(); + criteria.Add(new MethodReturnTypeCriteria(invoke.ReturnType)); + criteria.Add(new MethodParametersCountCriteria(parameters.Length)); + criteria.Add(new MethodParametersCriteria(ReflectionUtils.GetParameterTypes(parameters))); - MemberInfo[] methods = subscriberType.FindMembers( - MemberTypes.Method, ReflectionUtils.AllMembersCaseInsensitiveFlags, - new MemberFilter(new CriteriaMemberFilter().FilterMemberByCriteria), - criteria); - if (methods != null - && methods.Length > 0) - { - return methods[0] as MethodInfo; - } - return null; - } + MemberInfo[] methods = subscriberType.FindMembers( + MemberTypes.Method, ReflectionUtils.AllMembersCaseInsensitiveFlags, + new MemberFilter(new CriteriaMemberFilter().FilterMemberByCriteria), + criteria); + if (methods != null + && methods.Length > 0) + { + return methods[0] as MethodInfo; + } - #region Constructor (s) / Destructor + return null; + } - // CLOVER:OFF + #region Constructor (s) / Destructor - /// - /// Creates a new instance of the EventManipulationUtilities class. - /// - /// - ///

- /// This is a utility class, and as such has no publicly visible constructors. - ///

- ///
- private EventManipulationUtils() - { - } + // CLOVER:OFF - // CLOVER:ON + /// + /// Creates a new instance of the EventManipulationUtilities class. + /// + /// + ///

+ /// This is a utility class, and as such has no publicly visible constructors. + ///

+ ///
+ private EventManipulationUtils() + { + } - #endregion - } + // CLOVER:ON + + #endregion } diff --git a/src/Spring/Spring.Core/Objects/Events/Support/EventRegistry.cs b/src/Spring/Spring.Core/Objects/Events/Support/EventRegistry.cs index 81df4067..d40da42a 100644 --- a/src/Spring/Spring.Core/Objects/Events/Support/EventRegistry.cs +++ b/src/Spring/Spring.Core/Objects/Events/Support/EventRegistry.cs @@ -20,140 +20,139 @@ using System.Reflection; -namespace Spring.Objects.Events.Support +namespace Spring.Objects.Events.Support; + +/// +/// Default implementation of the +/// interface. +/// +/// Griffin Caprio +public class EventRegistry : IEventRegistry { + private readonly IList _publishers; + /// - /// Default implementation of the - /// interface. + /// Creates a new instance of the EventRegistry class. /// - /// Griffin Caprio - public class EventRegistry : IEventRegistry + public EventRegistry() { - private readonly IList _publishers; + _publishers = new List(); + } - /// - /// Creates a new instance of the EventRegistry class. - /// - public EventRegistry() - { - _publishers = new List(); - } + /// + /// The list of event publishers. + /// + /// The list of event publishers. + protected IList Publishers + { + get { return _publishers; } + } - /// - /// The list of event publishers. - /// - /// The list of event publishers. - protected IList Publishers - { - get { return _publishers; } - } + /// + /// Adds the input object to the list of publishers. + /// + /// + /// This publishes all events of the source object to any object + /// wishing to subscribe + /// + /// The source object to publish. + public virtual void PublishEvents(object source) + { + Publishers.Add(source); + } - /// - /// Adds the input object to the list of publishers. - /// - /// - /// This publishes all events of the source object to any object - /// wishing to subscribe - /// - /// The source object to publish. - public virtual void PublishEvents(object source) - { - Publishers.Add(source); - } + /// + /// Subscribes to all events published, if the subscriber implements + /// compatible handler methods. + /// + /// The subscriber to use. + public virtual void Subscribe(object subscriber) + { + Subscribe(subscriber, null); + } - /// - /// Subscribes to all events published, if the subscriber implements - /// compatible handler methods. - /// - /// The subscriber to use. - public virtual void Subscribe(object subscriber) + /// + /// Subscribes to published events of all objects of a given type, if the + /// subscriber implements compatible handler methods. + /// + /// The subscriber to use. + /// + /// The target to subscribe to. + /// + public virtual void Subscribe(object subscriber, Type sourceType) + { + Type currentSubscriberType = subscriber.GetType(); + foreach (object currentPublisher in _publishers) { - Subscribe(subscriber, null); - } - - /// - /// Subscribes to published events of all objects of a given type, if the - /// subscriber implements compatible handler methods. - /// - /// The subscriber to use. - /// - /// The target to subscribe to. - /// - public virtual void Subscribe(object subscriber, Type sourceType) - { - Type currentSubscriberType = subscriber.GetType(); - foreach (object currentPublisher in _publishers) + if (null == sourceType + || sourceType.IsAssignableFrom(currentPublisher.GetType())) { - if (null == sourceType - || sourceType.IsAssignableFrom(currentPublisher.GetType())) - { - WireOrUnwireSubscriberToPublisher( - currentPublisher, currentSubscriberType, subscriber, true); - } + WireOrUnwireSubscriberToPublisher( + currentPublisher, currentSubscriberType, subscriber, true); } } + } - /// - /// Unsubscribes to all events published, if the subscriber - /// implmenets compatible handler methods. - /// - /// The subscriber to use - public virtual void Unsubscribe(object subscriber) - { - Unsubscribe(subscriber, null); - } + /// + /// Unsubscribes to all events published, if the subscriber + /// implmenets compatible handler methods. + /// + /// The subscriber to use + public virtual void Unsubscribe(object subscriber) + { + Unsubscribe(subscriber, null); + } - /// - /// Unsubscribes to the published events of all objects of a given - /// , if the subscriber implements - /// compatible handler methods. - /// - /// The subscriber to use. - /// The target to unsubscribe from - public virtual void Unsubscribe(object subscriber, Type sourceType) + /// + /// Unsubscribes to the published events of all objects of a given + /// , if the subscriber implements + /// compatible handler methods. + /// + /// The subscriber to use. + /// The target to unsubscribe from + public virtual void Unsubscribe(object subscriber, Type sourceType) + { + Type currentSubscriberType = subscriber.GetType(); + foreach (object currentPublisher in _publishers) { - Type currentSubscriberType = subscriber.GetType(); - foreach (object currentPublisher in _publishers) + if (null == sourceType + || sourceType.IsAssignableFrom(currentPublisher.GetType())) { - if (null == sourceType - || sourceType.IsAssignableFrom(currentPublisher.GetType())) - { - WireOrUnwireSubscriberToPublisher( - currentPublisher, currentSubscriberType, subscriber, false); - } + WireOrUnwireSubscriberToPublisher( + currentPublisher, currentSubscriberType, subscriber, false); } } + } - private static void WireOrUnwireSubscriberToPublisher( - object currentPublisher, Type currentSubscriberType, object subscriber, bool wire) + private static void WireOrUnwireSubscriberToPublisher( + object currentPublisher, Type currentSubscriberType, object subscriber, bool wire) + { + Type currentPublisherType = currentPublisher.GetType(); + EventInfo[] events = currentPublisherType.GetEvents(); + foreach (EventInfo currentEvent in events) { - Type currentPublisherType = currentPublisher.GetType(); - EventInfo[] events = currentPublisherType.GetEvents(); - foreach (EventInfo currentEvent in events) + Type eventHandlerType = currentEvent.EventHandlerType; + MethodInfo invoke = eventHandlerType.GetMethod("Invoke"); + MethodInfo eventHandler + = EventManipulationUtils.GetMethodInfoMatchingSignature( + invoke, currentSubscriberType); + if (eventHandler != null) { - Type eventHandlerType = currentEvent.EventHandlerType; - MethodInfo invoke = eventHandlerType.GetMethod("Invoke"); - MethodInfo eventHandler - = EventManipulationUtils.GetMethodInfoMatchingSignature( - invoke, currentSubscriberType); - if (eventHandler != null) + if (wire) { - if (wire) - { - currentEvent.AddEventHandler( - currentPublisher, - EventManipulationUtils.GetHandlerDelegate( - eventHandlerType, subscriber, eventHandler)); - } - else - { - currentEvent.RemoveEventHandler( - currentPublisher, - EventManipulationUtils.GetHandlerDelegate( - eventHandlerType, subscriber, eventHandler)); - } + currentEvent.AddEventHandler( + currentPublisher, + EventManipulationUtils.GetHandlerDelegate( + eventHandlerType, subscriber, eventHandler)); + } + else + { + currentEvent.RemoveEventHandler( + currentPublisher, + EventManipulationUtils.GetHandlerDelegate( + eventHandlerType, subscriber, eventHandler)); } } } } -} +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Objects/Factory/Attributes/AutowiredAttribute.cs b/src/Spring/Spring.Core/Objects/Factory/Attributes/AutowiredAttribute.cs index bd395fce..505393f3 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Attributes/AutowiredAttribute.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Attributes/AutowiredAttribute.cs @@ -18,55 +18,54 @@ #endregion -namespace Spring.Objects.Factory.Attributes -{ - /// - /// Marks a constructor, field, propery or config method as to be - /// autowired by Spring's dependency injection facilities. - /// - /// Only one constructor (at max) of any given bean class may carry this - /// annotation, indicating the constructor to autowire when used as a Spring - /// bean. Such a constructor does not have to be public. - /// - /// Fields are injected right after construction of a object, before any - /// config methods are invoked. Such a config field does not have to be public. - /// - /// Config methods may have an arbitrary name and any number of arguments; - /// each of those arguments will be autowired with a matching bean in the - /// Spring container. Object property setter methods are effectively just - /// a special case of such a general config method. Such config methods - /// do not have to be public. - /// - /// In the case of multiple argument methods, the 'required' parameter is - /// applicable for all arguments. - /// - /// In case of a {@link java.util.Collection} or {@link java.util.Map} - /// dependency type, the container will autowire all beans matching the - /// declared value type. In case of a Map, the keys must be declared as - /// type String and will be resolved to the corresponding bean names. - /// - /// Note that actual injection is performed through a - /// {@link org.springframework.beans.factory.config.BeanPostProcessor - /// BeanPostProcessor} which in turn means that you cannot - /// use {@code @Autowired} to inject references into - /// {@link org.springframework.beans.factory.config.BeanPostProcessor - /// BeanPostProcessor} or - /// {@link org.springframework.beans.factory.config.BeanFactoryPostProcessor BeanFactoryPostProcessor} - /// types. Please consult the javadoc for the {@link AutowiredAnnotationBeanPostProcessor} - /// class (which, by default, checks for the presence of this annotation). - /// - [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Method | AttributeTargets.Constructor)] - public class AutowiredAttribute : Attribute - { - private bool _required = true; +namespace Spring.Objects.Factory.Attributes; - /// - /// Defines it Autowired PostProcessor should fail if object is not set - /// - public bool Required - { - get { return _required; } - set { _required = value; } - } +/// +/// Marks a constructor, field, propery or config method as to be +/// autowired by Spring's dependency injection facilities. +/// +/// Only one constructor (at max) of any given bean class may carry this +/// annotation, indicating the constructor to autowire when used as a Spring +/// bean. Such a constructor does not have to be public. +/// +/// Fields are injected right after construction of a object, before any +/// config methods are invoked. Such a config field does not have to be public. +/// +/// Config methods may have an arbitrary name and any number of arguments; +/// each of those arguments will be autowired with a matching bean in the +/// Spring container. Object property setter methods are effectively just +/// a special case of such a general config method. Such config methods +/// do not have to be public. +/// +/// In the case of multiple argument methods, the 'required' parameter is +/// applicable for all arguments. +/// +/// In case of a {@link java.util.Collection} or {@link java.util.Map} +/// dependency type, the container will autowire all beans matching the +/// declared value type. In case of a Map, the keys must be declared as +/// type String and will be resolved to the corresponding bean names. +/// +/// Note that actual injection is performed through a +/// {@link org.springframework.beans.factory.config.BeanPostProcessor +/// BeanPostProcessor} which in turn means that you cannot +/// use {@code @Autowired} to inject references into +/// {@link org.springframework.beans.factory.config.BeanPostProcessor +/// BeanPostProcessor} or +/// {@link org.springframework.beans.factory.config.BeanFactoryPostProcessor BeanFactoryPostProcessor} +/// types. Please consult the javadoc for the {@link AutowiredAnnotationBeanPostProcessor} +/// class (which, by default, checks for the presence of this annotation). +/// +[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Method | AttributeTargets.Constructor)] +public class AutowiredAttribute : Attribute +{ + private bool _required = true; + + /// + /// Defines it Autowired PostProcessor should fail if object is not set + /// + public bool Required + { + get { return _required; } + set { _required = value; } } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Attributes/AutowiredAttributeObjectPostProcessor.cs b/src/Spring/Spring.Core/Objects/Factory/Attributes/AutowiredAttributeObjectPostProcessor.cs index 38c49ae3..39d00d6e 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Attributes/AutowiredAttributeObjectPostProcessor.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Attributes/AutowiredAttributeObjectPostProcessor.cs @@ -23,694 +23,712 @@ using Microsoft.Extensions.Logging; using Spring.Collections; using Spring.Core; using Spring.Objects.Factory.Config; - - using Spring.Objects.Factory.Support; using Spring.Util; -namespace Spring.Objects.Factory.Attributes +namespace Spring.Objects.Factory.Attributes; + +/// +/// implementation +/// that autowires annotated fields, properties and arbitrary config methods. +/// Such members to be injected are detected through an attribute: by default, +/// Spring's . +/// +/// Only one constructor (at max) of any given bean class may carry this +/// annotation with the 'required' parameter set to true, +/// indicating the constructor to autowire when used as a Spring bean. +/// If multiple non-required constructors carry the annotation, they +/// will be considered as candidates for autowiring. The constructor with +/// the greatest number of dependencies that can be satisfied by matching +/// beans in the Spring container will be chosen. If none of the candidates +/// can be satisfied, then a default constructor (if present) will be used. +/// An annotated constructor does not have to be public. +/// +/// Fields are injected right after construction of a bean, before any +/// config methods are invoked. Such a config field does not have to be public. +/// +/// Config methods may have an arbitrary name and any number of arguments; each of +/// those arguments will be autowired with a matching bean in the Spring container. +/// Bean property setter methods are effectively just a special case of such a +/// general config method. Config methods do not have to be public. +/// +/// Note: A default AutowiredAttributeObjectPostProcessor will be registered +/// by the "context:annotation-config" and "context:component-scan" XML tags. +/// Remove or turn off the default annotation configuration there if you intend +/// to specify a custom AutowiredAnnotationBeanPostProcessor bean definition. +/// NOTE: Annotation injection will be performed before XML injection; +/// thus the latter configuration will override the former for properties wired through +/// both approaches. +/// +public class AutowiredAttributeObjectPostProcessor + : InstantiationAwareObjectPostProcessorAdapter, IMergedObjectDefinitionPostProcessor, IObjectFactoryAware, IOrdered { + private static readonly ILogger logger = LogManager.GetLogger(); + + private IConfigurableListableObjectFactory objectFactory; + + private readonly HashSet lookupMethodsChecked = new HashSet(); + + private readonly SynchronizedHashtable candidateConstructorsCache = new SynchronizedHashtable(); + + private readonly Dictionary injectionMetadataCache = new Dictionary(); + + private readonly List autowiredPropertyTypes = new List(); + /// - /// implementation - /// that autowires annotated fields, properties and arbitrary config methods. - /// Such members to be injected are detected through an attribute: by default, - /// Spring's . - /// - /// Only one constructor (at max) of any given bean class may carry this - /// annotation with the 'required' parameter set to true, - /// indicating the constructor to autowire when used as a Spring bean. - /// If multiple non-required constructors carry the annotation, they - /// will be considered as candidates for autowiring. The constructor with - /// the greatest number of dependencies that can be satisfied by matching - /// beans in the Spring container will be chosen. If none of the candidates - /// can be satisfied, then a default constructor (if present) will be used. - /// An annotated constructor does not have to be public. - /// - /// Fields are injected right after construction of a bean, before any - /// config methods are invoked. Such a config field does not have to be public. - /// - /// Config methods may have an arbitrary name and any number of arguments; each of - /// those arguments will be autowired with a matching bean in the Spring container. - /// Bean property setter methods are effectively just a special case of such a - /// general config method. Config methods do not have to be public. - /// - /// Note: A default AutowiredAttributeObjectPostProcessor will be registered - /// by the "context:annotation-config" and "context:component-scan" XML tags. - /// Remove or turn off the default annotation configuration there if you intend - /// to specify a custom AutowiredAnnotationBeanPostProcessor bean definition. - /// NOTE: Annotation injection will be performed before XML injection; - /// thus the latter configuration will override the former for properties wired through - /// both approaches. + /// Return the order value of this object, where a higher value means greater in + /// terms of sorting. /// - public class AutowiredAttributeObjectPostProcessor - : InstantiationAwareObjectPostProcessorAdapter, IMergedObjectDefinitionPostProcessor, IObjectFactoryAware, IOrdered + /// + ///

Normally starting with 0 or 1, with indicating + /// greatest. Same order values will result in arbitrary positions for the affected + /// objects. + ///

Higher value can be interpreted as lower priority, consequently the first object + /// has highest priority. + ///

+ ///
+ /// + /// The order value. + /// + public int Order { get; private set; } = int.MaxValue - 2; + + /// + /// Callback that supplies the owning factory to an object instance. + /// + /// + /// Owning + /// (may not be ). The object can immediately + /// call methods on the factory. + /// + /// + ///

Invoked after population of normal object properties but before an init + /// callback like 's + /// + /// method or a custom init-method. + ///

+ ///
+ /// In case of initialization errors. + /// + public IObjectFactory ObjectFactory { - private static readonly ILogger logger = LogManager.GetLogger(); + set => objectFactory = (IConfigurableListableObjectFactory) value; + } - private IConfigurableListableObjectFactory objectFactory; + public void PostProcessMergedObjectDefinition(RootObjectDefinition objectDefinition, Type objectType, string objectName) + { + var metadata = FindAutowiringMetadata(objectName, objectType, null); + metadata.CheckConfigMembers(objectDefinition); + } - private readonly HashSet lookupMethodsChecked = new HashSet(); + public void ResetObjectDefinition(string beanName) + { + this.lookupMethodsChecked.Remove(beanName); + injectionMetadataCache.Remove(beanName); + } - private readonly SynchronizedHashtable candidateConstructorsCache = new SynchronizedHashtable(); - - private readonly Dictionary injectionMetadataCache = new Dictionary(); - - private readonly List autowiredPropertyTypes = new List(); - - /// - /// Return the order value of this object, where a higher value means greater in - /// terms of sorting. - /// - /// - ///

Normally starting with 0 or 1, with indicating - /// greatest. Same order values will result in arbitrary positions for the affected - /// objects. - ///

Higher value can be interpreted as lower priority, consequently the first object - /// has highest priority. - ///

- ///
- /// - /// The order value. - /// - public int Order { get; private set; } = int.MaxValue - 2; - - /// - /// Callback that supplies the owning factory to an object instance. - /// - /// - /// Owning - /// (may not be ). The object can immediately - /// call methods on the factory. - /// - /// - ///

Invoked after population of normal object properties but before an init - /// callback like 's - /// - /// method or a custom init-method. - ///

- ///
- /// In case of initialization errors. - /// - public IObjectFactory ObjectFactory + /// + /// Add a Autowired Attribute Type + /// + public void AddAutowiredType(Type attributeType) + { + if (!autowiredPropertyTypes.Contains(attributeType)) { - set => objectFactory = (IConfigurableListableObjectFactory) value; + autowiredPropertyTypes.Add(attributeType); + } + } + + /// + /// Create a new instance of an Autowire Post Processor + /// with standard attributes of + /// and + /// + public AutowiredAttributeObjectPostProcessor() + { + autowiredPropertyTypes.Add(typeof(AutowiredAttribute)); + autowiredPropertyTypes.Add(typeof(ValueAttribute)); + } + + /// + /// Determines the candidate constructors to use for the given object. + /// + /// The raw Type of the object. + /// Name of the object. + /// The candidate constructors, or null if none specified + /// in case of errors + public override ConstructorInfo[] DetermineCandidateConstructors(Type objectType, string objectName) + { + /* TODO implement Lookup + // Let's check for lookup methods here.. + if (!lookupMethodsChecked.Contains(objectName)) + { + try + { + foreach (var method in objectType.GetMethods()) + { + ValueAttribute lookup = method.GetCustomAttribute(true); + if (lookup != null) + { + AssertUtils.State(objectFactory != null, "No ObjectFactory available"); + var lookupMethodOverride = new LookupMethodOverride(method.Name, lookup.Expression); + try + { + var mbd = (RootObjectDefinition) objectFactory.GetMergedObjectDefinition(objectName); + mbd.MethodOverrides.Add(lookupMethodOverride); + } + catch (NoSuchObjectDefinitionException) + { + throw new ObjectCreationException(objectName, + "Cannot apply @Lookup to objects without corresponding object definition"); + } + } + }; + } + catch (Exception ex) + { + throw new ObjectCreationException(objectName, "Lookup method resolution failed", ex); + } + + lookupMethodsChecked.Add(objectName); + }*/ + + // Quick check on the concurrent map first, with minimal locking. + ConstructorInfo[] candidateConstructors = candidateConstructorsCache.ContainsKey(objectType) + ? (ConstructorInfo[]) candidateConstructorsCache[objectType] + : null; + if (candidateConstructors == null) + { + lock (candidateConstructorsCache) + { + candidateConstructors = candidateConstructorsCache.ContainsKey(objectType) + ? (ConstructorInfo[]) candidateConstructorsCache[objectType] + : null; + if (candidateConstructors == null) + { + ConstructorInfo[] rawCandidates = objectType.GetConstructors(); + IList candidates = new List(rawCandidates.Length); + ConstructorInfo requiredConstructor = null; + ConstructorInfo defaultConstructor = null; + foreach (var candidate in rawCandidates) + { + if (Attribute.GetCustomAttribute(candidate, typeof(AutowiredAttribute)) is AutowiredAttribute attr) + { + if (requiredConstructor != null) + { + throw new ObjectCreationException("Invalid autowire-marked constructor: " + candidate + + ". Found another constructor with 'required' Autowired annotation: " + + requiredConstructor); + } + + if (candidate.GetParameters().Length == 0) + { + throw new InvalidOperationException("Autowired annotation requires at least one argument: " + candidate); + } + + if (attr.Required) + { + if (candidates.Count > 0) + { + throw new ObjectCreationException( + "Invalid autowire-marked constructors: " + candidates + + ". Found another constructor with 'required' Autowired annotation: " + + requiredConstructor); + } + + requiredConstructor = candidate; + } + + candidates.Add(candidate); + } + else if (candidate.GetParameters().Length == 0) + { + defaultConstructor = candidate; + } + } + + if (candidates.Count > 0) + { + // Add default constructor to list of optional constructors, as fallback. + if (requiredConstructor == null && defaultConstructor != null) + { + candidates.Add(defaultConstructor); + } + + candidateConstructors = candidates.ToArray(); + } + else + { + candidateConstructors = new ConstructorInfo[0]; + } + + candidateConstructorsCache.Add(objectType, candidateConstructors); + } + } } - public void PostProcessMergedObjectDefinition(RootObjectDefinition objectDefinition, Type objectType, string objectName) + return (candidateConstructors.Length > 0 ? candidateConstructors : null); + } + + /// + /// Finds autowire candidates and verifies them + /// + /// + /// The of the target object that is to be + /// instantiated. + /// + /// + /// The name of the target object. + /// + /// + /// The object to expose instead of a default instance of the target + /// object. + /// + /// + /// In the case of any errors. + /// + /// + /// + public override object PostProcessBeforeInstantiation(Type objectType, string objectName) + { + var objectDefinition = objectFactory.GetObjectDefinition(objectName) as RootObjectDefinition; + if (objectType != null) { var metadata = FindAutowiringMetadata(objectName, objectType, null); metadata.CheckConfigMembers(objectDefinition); } - public void ResetObjectDefinition(string beanName) + return null; + } + + /// + /// Injects autoried annotated properties, fields, methods into objectInstance + /// + /// + /// + /// + /// Name of the object. + /// The actual property values to apply to the given object (can be the + /// passed-in PropertyValues instances0 or null to skip property population. + public override IPropertyValues PostProcessPropertyValues(IPropertyValues pvs, IList pis, + object objectInstance, string objectName) + { + var metadata = FindAutowiringMetadata(objectName, objectInstance.GetType(), pvs); + try { - this.lookupMethodsChecked.Remove(beanName); - injectionMetadataCache.Remove(beanName); + metadata.Inject(objectInstance, objectName, pvs); + } + catch (Exception ex) + { + throw new ObjectCreationException(objectName, "Injection of autowired dependencies failed", ex); } - /// - /// Add a Autowired Attribute Type - /// - public void AddAutowiredType(Type attributeType) + return pvs; + } + + private InjectionMetadata FindAutowiringMetadata(string objectName, Type objectType, IPropertyValues pvs) + { + // Fall back to class name as cache key, for backwards compatibility with custom callers. + var cacheKey = StringUtils.HasLength(objectName) ? objectName : objectType.Name; + injectionMetadataCache.TryGetValue(cacheKey, out var metadata); + + if (InjectionMetadata.NeedsRefresh(metadata, objectType)) { - if (!autowiredPropertyTypes.Contains(attributeType)) + lock (injectionMetadataCache) { - autowiredPropertyTypes.Add(attributeType); + if (!injectionMetadataCache.TryGetValue(cacheKey, out metadata) + || InjectionMetadata.NeedsRefresh(metadata, objectType)) + { + metadata = BuildAutowiringMetadata(objectType); + injectionMetadataCache[cacheKey] = metadata; + } } } - /// - /// Create a new instance of an Autowire Post Processor - /// with standard attributes of - /// and - /// - public AutowiredAttributeObjectPostProcessor() + return metadata; + } + + private InjectionMetadata BuildAutowiringMetadata(Type objectType) + { + var elements = new List(); + + do { - autowiredPropertyTypes.Add(typeof (AutowiredAttribute)); - autowiredPropertyTypes.Add(typeof (ValueAttribute)); - } - - /// - /// Determines the candidate constructors to use for the given object. - /// - /// The raw Type of the object. - /// Name of the object. - /// The candidate constructors, or null if none specified - /// in case of errors - public override ConstructorInfo[] DetermineCandidateConstructors(Type objectType, string objectName) - { - /* TODO implement Lookup - // Let's check for lookup methods here.. - if (!lookupMethodsChecked.Contains(objectName)) + for (var i = 0; i < autowiredPropertyTypes.Count; i++) { - try - { - foreach (var method in objectType.GetMethods()) - { - ValueAttribute lookup = method.GetCustomAttribute(true); - if (lookup != null) - { - AssertUtils.State(objectFactory != null, "No ObjectFactory available"); - var lookupMethodOverride = new LookupMethodOverride(method.Name, lookup.Expression); - try - { - var mbd = (RootObjectDefinition) objectFactory.GetMergedObjectDefinition(objectName); - mbd.MethodOverrides.Add(lookupMethodOverride); - } - catch (NoSuchObjectDefinitionException) - { - throw new ObjectCreationException(objectName, - "Cannot apply @Lookup to objects without corresponding object definition"); - } - } - }; - } - catch (Exception ex) - { - throw new ObjectCreationException(objectName, "Lookup method resolution failed", ex); - } + var autowiredType = autowiredPropertyTypes[i]; + var currElements = new List(); + var properties = + objectType.GetProperties(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); - lookupMethodsChecked.Add(objectName); - }*/ - - // Quick check on the concurrent map first, with minimal locking. - ConstructorInfo[] candidateConstructors = candidateConstructorsCache.ContainsKey(objectType) - ? (ConstructorInfo[]) candidateConstructorsCache[objectType] - : null; - if (candidateConstructors == null) - { - lock (candidateConstructorsCache) + foreach (var property in properties) { - candidateConstructors = candidateConstructorsCache.ContainsKey(objectType) - ? (ConstructorInfo[]) candidateConstructorsCache[objectType] - : null; - if (candidateConstructors == null) + var required = true; + var attr = Attribute.GetCustomAttribute(property, autowiredType); + if (attr is AutowiredAttribute autowiredAttribute) { - ConstructorInfo[] rawCandidates = objectType.GetConstructors(); - IList candidates = new List(rawCandidates.Length); - ConstructorInfo requiredConstructor = null; - ConstructorInfo defaultConstructor = null; - foreach (var candidate in rawCandidates) - { - if (Attribute.GetCustomAttribute(candidate, typeof (AutowiredAttribute)) is AutowiredAttribute attr) - { - if (requiredConstructor != null) - { - throw new ObjectCreationException("Invalid autowire-marked constructor: " + candidate + - ". Found another constructor with 'required' Autowired annotation: " + - requiredConstructor); - } - if (candidate.GetParameters().Length == 0) - { - throw new InvalidOperationException("Autowired annotation requires at least one argument: " + candidate); - } - if (attr.Required) - { - if (candidates.Count > 0) - { - throw new ObjectCreationException( - "Invalid autowire-marked constructors: " + candidates + - ". Found another constructor with 'required' Autowired annotation: " + - requiredConstructor); - } - requiredConstructor = candidate; - } - candidates.Add(candidate); - } - else if (candidate.GetParameters().Length == 0) - { - defaultConstructor = candidate; - } - } - if (candidates.Count > 0) - { - // Add default constructor to list of optional constructors, as fallback. - if (requiredConstructor == null && defaultConstructor != null) - { - candidates.Add(defaultConstructor); - } - candidateConstructors = candidates.ToArray(); - } - else - { - candidateConstructors = new ConstructorInfo[0]; - } - candidateConstructorsCache.Add(objectType, candidateConstructors); + required = autowiredAttribute.Required; + } + + if (attr != null && property.DeclaringType == objectType) + { + currElements.Add(new AutowiredPropertyElement(this, property, required)); } } + + var fields = objectType.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); + foreach (var field in fields) + { + var required = true; + var attr = Attribute.GetCustomAttribute(field, autowiredType); + if (attr is AutowiredAttribute autowiredAttribute) + { + required = autowiredAttribute.Required; + } + + if (attr != null && field.DeclaringType == objectType) + { + currElements.Add(new AutowiredFieldElement(this, field, required)); + } + } + + var methods = objectType.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); + foreach (var method in methods) + { + var required = true; + var attr = Attribute.GetCustomAttribute(method, autowiredType); + if (attr is AutowiredAttribute autowiredAttribute) + { + required = autowiredAttribute.Required; + } + + if (attr != null && method.DeclaringType == objectType) + { + if (method.IsStatic) + { + logger.LogWarning("Autowired annotation is not supported on static methods: {MethodName}", method.Name); + continue; + } + + if (method.IsGenericMethod) + { + logger.LogWarning("Autowired annotation is not supported on generic methods: {MethodName}", method.Name); + continue; + } + + currElements.Add(new AutowiredMethodElement(this, method, required)); + } + } + + elements.InsertRange(0, currElements); } - return (candidateConstructors.Length > 0 ? candidateConstructors : null); + + objectType = objectType.BaseType; + } while (objectType != null && objectType != typeof(object)); + + return new InjectionMetadata(objectType, elements); + } + + /// + /// Register the specified bean as dependent on the autowired beans. + /// + private void RegisterDependentObjects(string objectName, List autowiredObjectNames) + { + if (objectName == null) + { + return; } - /// - /// Finds autowire candidates and verifies them - /// - /// - /// The of the target object that is to be - /// instantiated. - /// - /// - /// The name of the target object. - /// - /// - /// The object to expose instead of a default instance of the target - /// object. - /// - /// - /// In the case of any errors. - /// - /// - /// - public override object PostProcessBeforeInstantiation(Type objectType, string objectName) + var objectDefinition = objectFactory.GetObjectDefinition(objectName) as RootObjectDefinition; + if (objectDefinition == null) { - var objectDefinition = objectFactory.GetObjectDefinition(objectName) as RootObjectDefinition; - if (objectType != null) + return; + } + + var dependsOn = new List(objectDefinition.DependsOn); + foreach (var name in autowiredObjectNames) + { + var autowiredObjectName = name; + if (!dependsOn.Contains(autowiredObjectName)) { - var metadata = FindAutowiringMetadata(objectName, objectType, null); - metadata.CheckConfigMembers(objectDefinition); + dependsOn.Add(autowiredObjectName); + logger.LogDebug("Autowiring by type from object name '{ObjectName}' to object named '{AutoWiredObjectName}'", objectName, autowiredObjectName); } - return null; } - /// - /// Injects autoried annotated properties, fields, methods into objectInstance - /// - /// - /// - /// - /// Name of the object. - /// The actual property values to apply to the given object (can be the - /// passed-in PropertyValues instances0 or null to skip property population. - public override IPropertyValues PostProcessPropertyValues(IPropertyValues pvs, IList pis, - object objectInstance, string objectName) + objectDefinition.DependsOn = dependsOn; + } + + private object ResolvedCachedArgument(string objectName, object cachedArgument) + { + if (cachedArgument is DependencyDescriptor descriptor) { - var metadata = FindAutowiringMetadata(objectName, objectInstance.GetType(), pvs); + return objectFactory.ResolveDependency(descriptor, objectName, null); + } + + if (cachedArgument is RuntimeObjectReference runtimeObjectReference) + { + return objectFactory.GetObject(runtimeObjectReference.ObjectName); + } + + return cachedArgument; + } + + /// + /// Class representing injection information about an annotated field. + /// + private class AutowiredPropertyElement : InjectionMetadata.InjectedElement + { + private readonly AutowiredAttributeObjectPostProcessor processor; + private readonly bool required; + private bool cached; + private object cachedFieldValue; + + public AutowiredPropertyElement(AutowiredAttributeObjectPostProcessor processor, PropertyInfo property, bool required) + : base(property) + { + this.processor = processor; + this.required = required; + } + + public override void Inject(object instance, string objectName, IPropertyValues pvs) + { + var property = (PropertyInfo) Member; try { - metadata.Inject(objectInstance, objectName, pvs); + object value; + if (cached) + { + value = processor.ResolvedCachedArgument(objectName, cachedFieldValue); + } + else + { + var descriptor = new DependencyDescriptor(property, required); + var autowiredObjectNames = new List(); + value = processor.objectFactory.ResolveDependency(descriptor, objectName, autowiredObjectNames); + lock (this) + { + if (!cached) + { + if (value != null || required) + { + cachedFieldValue = descriptor; + processor.RegisterDependentObjects(objectName, autowiredObjectNames); + if (autowiredObjectNames.Count == 1) + { + var autowiredBeanName = autowiredObjectNames[0]; + if (processor.objectFactory.ContainsObject(autowiredBeanName)) + { + if (processor.objectFactory.IsTypeMatch(autowiredBeanName, property.GetType())) + { + cachedFieldValue = new RuntimeObjectReference(autowiredBeanName); + } + } + } + } + else + { + cachedFieldValue = null; + } + + cached = true; + } + } + } + + if (value != null) + { + property.SetValue(instance, value, null); + } } catch (Exception ex) { - throw new ObjectCreationException(objectName, "Injection of autowired dependencies failed", ex); - } - return pvs; - } - - private InjectionMetadata FindAutowiringMetadata(string objectName, Type objectType, IPropertyValues pvs) - { - // Fall back to class name as cache key, for backwards compatibility with custom callers. - var cacheKey = StringUtils.HasLength(objectName) ? objectName : objectType.Name; - injectionMetadataCache.TryGetValue(cacheKey, out var metadata); - - if (InjectionMetadata.NeedsRefresh(metadata, objectType)) - { - lock (injectionMetadataCache) - { - if (!injectionMetadataCache.TryGetValue(cacheKey, out metadata) - || InjectionMetadata.NeedsRefresh(metadata, objectType)) - { - metadata = BuildAutowiringMetadata(objectType); - injectionMetadataCache[cacheKey] = metadata; - } - } - } - - return metadata; - } - - private InjectionMetadata BuildAutowiringMetadata(Type objectType) - { - var elements = new List(); - - do - { - for (var i = 0; i < autowiredPropertyTypes.Count; i++) - { - var autowiredType = autowiredPropertyTypes[i]; - var currElements = new List(); - var properties = - objectType.GetProperties(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); - - foreach (var property in properties) - { - var required = true; - var attr = Attribute.GetCustomAttribute(property, autowiredType); - if (attr is AutowiredAttribute autowiredAttribute) - { - required = autowiredAttribute.Required; - } - - if (attr != null && property.DeclaringType == objectType) - { - currElements.Add(new AutowiredPropertyElement(this, property, required)); - } - } - - var fields = objectType.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); - foreach (var field in fields) - { - var required = true; - var attr = Attribute.GetCustomAttribute(field, autowiredType); - if (attr is AutowiredAttribute autowiredAttribute) - { - required = autowiredAttribute.Required; - } - - if (attr != null && field.DeclaringType == objectType) - { - currElements.Add(new AutowiredFieldElement(this, field, required)); - } - } - - var methods = objectType.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); - foreach (var method in methods) - { - var required = true; - var attr = Attribute.GetCustomAttribute(method, autowiredType); - if (attr is AutowiredAttribute autowiredAttribute) - { - required = autowiredAttribute.Required; - } - - if (attr != null && method.DeclaringType == objectType) - { - if (method.IsStatic) - { - logger.LogWarning("Autowired annotation is not supported on static methods: {MethodName}", method.Name); - continue; - } - - if (method.IsGenericMethod) - { - logger.LogWarning("Autowired annotation is not supported on generic methods: {MethodName}", method.Name); - continue; - } - - currElements.Add(new AutowiredMethodElement(this, method, required)); - } - } - - elements.InsertRange(0, currElements); - } - - objectType = objectType.BaseType; - } while (objectType != null && objectType != typeof (object)); - - return new InjectionMetadata(objectType, elements); - } - - /// - /// Register the specified bean as dependent on the autowired beans. - /// - private void RegisterDependentObjects(string objectName, List autowiredObjectNames) - { - if (objectName == null) - { - return; - } - - var objectDefinition = objectFactory.GetObjectDefinition(objectName) as RootObjectDefinition; - if (objectDefinition == null) - { - return; - } - - var dependsOn = new List(objectDefinition.DependsOn); - foreach (var name in autowiredObjectNames) - { - var autowiredObjectName = name; - if (!dependsOn.Contains(autowiredObjectName)) - { - dependsOn.Add(autowiredObjectName); - logger.LogDebug("Autowiring by type from object name '{ObjectName}' to object named '{AutoWiredObjectName}'", objectName, autowiredObjectName); - } - } - objectDefinition.DependsOn = dependsOn; - } - - private object ResolvedCachedArgument(string objectName, object cachedArgument) - { - if (cachedArgument is DependencyDescriptor descriptor) - { - return objectFactory.ResolveDependency(descriptor, objectName, null); - } - - if (cachedArgument is RuntimeObjectReference runtimeObjectReference) - { - return objectFactory.GetObject(runtimeObjectReference.ObjectName); - } - - return cachedArgument; - } - - /// - /// Class representing injection information about an annotated field. - /// - private class AutowiredPropertyElement : InjectionMetadata.InjectedElement - { - private readonly AutowiredAttributeObjectPostProcessor processor; - private readonly bool required; - private bool cached; - private object cachedFieldValue; - - public AutowiredPropertyElement(AutowiredAttributeObjectPostProcessor processor, PropertyInfo property, bool required) - : base(property) - { - this.processor = processor; - this.required = required; - } - - public override void Inject(object instance, string objectName, IPropertyValues pvs) - { - var property = (PropertyInfo) Member; - try - { - object value; - if (cached) - { - value = processor.ResolvedCachedArgument(objectName, cachedFieldValue); - } - else - { - var descriptor = new DependencyDescriptor(property, required); - var autowiredObjectNames = new List(); - value = processor.objectFactory.ResolveDependency(descriptor, objectName, autowiredObjectNames); - lock (this) - { - if (!cached) - { - if (value != null || required) - { - cachedFieldValue = descriptor; - processor.RegisterDependentObjects(objectName, autowiredObjectNames); - if (autowiredObjectNames.Count == 1) - { - var autowiredBeanName = autowiredObjectNames[0]; - if (processor.objectFactory.ContainsObject(autowiredBeanName)) - { - if (processor.objectFactory.IsTypeMatch(autowiredBeanName, property.GetType())) - { - cachedFieldValue = new RuntimeObjectReference(autowiredBeanName); - } - } - } - } - else - { - cachedFieldValue = null; - } - cached = true; - } - } - } - if (value != null) - { - property.SetValue(instance, value, null); - } - } - catch (Exception ex) - { - throw new ObjectCreationException("Could not autowire property: " + property, ex); - } - } - } - - /// - /// Class representing injection information about an annotated field. - /// - private class AutowiredFieldElement : InjectionMetadata.InjectedElement - { - private readonly AutowiredAttributeObjectPostProcessor processor; - private readonly bool required; - private bool cached; - private object cachedFieldValue; - - public AutowiredFieldElement(AutowiredAttributeObjectPostProcessor processor, FieldInfo field, bool required) - : base(field) - { - this.processor = processor; - this.required = required; - } - - public override void Inject(object instance, string objectName, IPropertyValues pvs) - { - var field = (FieldInfo) Member; - try - { - object value; - if (cached) - { - value = processor.ResolvedCachedArgument(objectName, cachedFieldValue); - } - else - { - var descriptor = new DependencyDescriptor(field, required); - var autowiredObjectNames = new List(); - value = processor.objectFactory.ResolveDependency(descriptor, objectName, autowiredObjectNames); - lock (this) - { - if (!cached) - { - if (value != null || required) - { - cachedFieldValue = descriptor; - processor.RegisterDependentObjects(objectName, autowiredObjectNames); - if (autowiredObjectNames.Count == 1) - { - var autowiredBeanName = autowiredObjectNames[0] as string; - if (processor.objectFactory.ContainsObject(autowiredBeanName)) - { - if (processor.objectFactory.IsTypeMatch(autowiredBeanName, field.GetType())) - { - cachedFieldValue = new RuntimeObjectReference(autowiredBeanName); - } - } - } - } - else - { - cachedFieldValue = null; - } - cached = true; - } - } - } - if (value != null) - { - field.SetValue(instance, value); - } - } - catch (Exception ex) - { - throw new ObjectCreationException("Could not autowire field: " + field, ex); - } - } - } - - /// - /// Class representing injection information about an annotated method. - /// - private class AutowiredMethodElement : InjectionMetadata.InjectedElement - { - private readonly AutowiredAttributeObjectPostProcessor processor; - private readonly bool required; - private bool cached; - private volatile object[] cachedMethodArguments; - - public AutowiredMethodElement(AutowiredAttributeObjectPostProcessor processor, MethodInfo method, bool required) - : base(method) - { - this.processor = processor; - this.required = required; - } - - public override void Inject(object target, string objectName, IPropertyValues pvs) - { - MethodInfo method = Member as MethodInfo; - try - { - object[] arguments; - if (cached) - { - arguments = ResolveCachedArguments(objectName); - } - else - { - Type[] paramTypes = method.GetParameters().Select(p => p.ParameterType).ToArray(); - arguments = new object[paramTypes.Length]; - var descriptors = new DependencyDescriptor[paramTypes.Length]; - var autowiredBeanNames = new List(); - for (int i = 0; i < arguments.Length; i++) - { - MethodParameter methodParam = new MethodParameter(method, i); - descriptors[i] = new DependencyDescriptor(methodParam, required); - arguments[i] = processor.objectFactory.ResolveDependency(descriptors[i], objectName, autowiredBeanNames); - if (arguments[i] == null && !required) - { - arguments = null; - break; - } - } - lock (this) - { - if (!cached) - { - if (arguments != null) - { - cachedMethodArguments = new object[arguments.Length]; - for (int i = 0; i < arguments.Length; i++) - { - cachedMethodArguments[i] = descriptors[i]; - } - processor.RegisterDependentObjects(objectName, autowiredBeanNames); - if (autowiredBeanNames.Count == paramTypes.Length) - { - for (int i = 0; i < paramTypes.Length; i++) - { - string autowiredBeanName = autowiredBeanNames[i] as string; - if (processor.objectFactory.ContainsObject(autowiredBeanName)) - { - if (processor.objectFactory.IsTypeMatch(autowiredBeanName, paramTypes[i])) - { - cachedMethodArguments[i] = - new RuntimeObjectReference(autowiredBeanName); - } - } - } - } - } - else - { - cachedMethodArguments = null; - } - cached = true; - } - } - } - if (arguments != null) - { - method.Invoke(target, arguments); - } - } - catch (Exception ex) - { - throw new ObjectCreationException("Could not autowire method: " + method, ex); - } - } - - private object[] ResolveCachedArguments(string objectName) - { - if (cachedMethodArguments == null) - { - return null; - } - object[] arguments = new object[cachedMethodArguments.Length]; - for (int i = 0; i < arguments.Length; i++) - { - arguments[i] = processor.ResolvedCachedArgument(objectName, cachedMethodArguments[i]); - } - return arguments; + throw new ObjectCreationException("Could not autowire property: " + property, ex); } } } + + /// + /// Class representing injection information about an annotated field. + /// + private class AutowiredFieldElement : InjectionMetadata.InjectedElement + { + private readonly AutowiredAttributeObjectPostProcessor processor; + private readonly bool required; + private bool cached; + private object cachedFieldValue; + + public AutowiredFieldElement(AutowiredAttributeObjectPostProcessor processor, FieldInfo field, bool required) + : base(field) + { + this.processor = processor; + this.required = required; + } + + public override void Inject(object instance, string objectName, IPropertyValues pvs) + { + var field = (FieldInfo) Member; + try + { + object value; + if (cached) + { + value = processor.ResolvedCachedArgument(objectName, cachedFieldValue); + } + else + { + var descriptor = new DependencyDescriptor(field, required); + var autowiredObjectNames = new List(); + value = processor.objectFactory.ResolveDependency(descriptor, objectName, autowiredObjectNames); + lock (this) + { + if (!cached) + { + if (value != null || required) + { + cachedFieldValue = descriptor; + processor.RegisterDependentObjects(objectName, autowiredObjectNames); + if (autowiredObjectNames.Count == 1) + { + var autowiredBeanName = autowiredObjectNames[0] as string; + if (processor.objectFactory.ContainsObject(autowiredBeanName)) + { + if (processor.objectFactory.IsTypeMatch(autowiredBeanName, field.GetType())) + { + cachedFieldValue = new RuntimeObjectReference(autowiredBeanName); + } + } + } + } + else + { + cachedFieldValue = null; + } + + cached = true; + } + } + } + + if (value != null) + { + field.SetValue(instance, value); + } + } + catch (Exception ex) + { + throw new ObjectCreationException("Could not autowire field: " + field, ex); + } + } + } + + /// + /// Class representing injection information about an annotated method. + /// + private class AutowiredMethodElement : InjectionMetadata.InjectedElement + { + private readonly AutowiredAttributeObjectPostProcessor processor; + private readonly bool required; + private bool cached; + private volatile object[] cachedMethodArguments; + + public AutowiredMethodElement(AutowiredAttributeObjectPostProcessor processor, MethodInfo method, bool required) + : base(method) + { + this.processor = processor; + this.required = required; + } + + public override void Inject(object target, string objectName, IPropertyValues pvs) + { + MethodInfo method = Member as MethodInfo; + try + { + object[] arguments; + if (cached) + { + arguments = ResolveCachedArguments(objectName); + } + else + { + Type[] paramTypes = method.GetParameters().Select(p => p.ParameterType).ToArray(); + arguments = new object[paramTypes.Length]; + var descriptors = new DependencyDescriptor[paramTypes.Length]; + var autowiredBeanNames = new List(); + for (int i = 0; i < arguments.Length; i++) + { + MethodParameter methodParam = new MethodParameter(method, i); + descriptors[i] = new DependencyDescriptor(methodParam, required); + arguments[i] = processor.objectFactory.ResolveDependency(descriptors[i], objectName, autowiredBeanNames); + if (arguments[i] == null && !required) + { + arguments = null; + break; + } + } + + lock (this) + { + if (!cached) + { + if (arguments != null) + { + cachedMethodArguments = new object[arguments.Length]; + for (int i = 0; i < arguments.Length; i++) + { + cachedMethodArguments[i] = descriptors[i]; + } + + processor.RegisterDependentObjects(objectName, autowiredBeanNames); + if (autowiredBeanNames.Count == paramTypes.Length) + { + for (int i = 0; i < paramTypes.Length; i++) + { + string autowiredBeanName = autowiredBeanNames[i] as string; + if (processor.objectFactory.ContainsObject(autowiredBeanName)) + { + if (processor.objectFactory.IsTypeMatch(autowiredBeanName, paramTypes[i])) + { + cachedMethodArguments[i] = + new RuntimeObjectReference(autowiredBeanName); + } + } + } + } + } + else + { + cachedMethodArguments = null; + } + + cached = true; + } + } + } + + if (arguments != null) + { + method.Invoke(target, arguments); + } + } + catch (Exception ex) + { + throw new ObjectCreationException("Could not autowire method: " + method, ex); + } + } + + private object[] ResolveCachedArguments(string objectName) + { + if (cachedMethodArguments == null) + { + return null; + } + + object[] arguments = new object[cachedMethodArguments.Length]; + for (int i = 0; i < arguments.Length; i++) + { + arguments[i] = processor.ResolvedCachedArgument(objectName, cachedMethodArguments[i]); + } + + return arguments; + } + } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Attributes/InitDestroyAttributeObjectPostProcessor.cs b/src/Spring/Spring.Core/Objects/Factory/Attributes/InitDestroyAttributeObjectPostProcessor.cs index 16512278..5a3d9a66 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Attributes/InitDestroyAttributeObjectPostProcessor.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Attributes/InitDestroyAttributeObjectPostProcessor.cs @@ -23,288 +23,289 @@ using Microsoft.Extensions.Logging; using Spring.Objects.Factory.Config; using Spring.Core; -namespace Spring.Objects.Factory.Attributes +namespace Spring.Objects.Factory.Attributes; + +/// +/// implementation +/// that invokes attributed init and destroy methods. Allows for an attributation +/// alternative to Spring's and +/// callback interfaces. +/// +/// Invoke and destroy annotations may be applied to methods of any visibility: +/// public, protected, or private. Multiple such methods +/// may be annotated, but it is recommended to only annotate one single +/// init method and destroy method, respectively. +/// +public class InitDestroyAttributeObjectPostProcessor : IDestructionAwareObjectPostProcessor, IObjectFactoryAware, IOrdered { + private static readonly ILogger logger = LogManager.GetLogger(); + + private IConfigurableListableObjectFactory objectFactory; + private readonly IDictionary lifecycleMetadataCache; + + private int order = int.MaxValue; + private Type initAttributeType; + private Type destroyAttributeType; + /// - /// implementation - /// that invokes attributed init and destroy methods. Allows for an attributation - /// alternative to Spring's and - /// callback interfaces. - /// - /// Invoke and destroy annotations may be applied to methods of any visibility: - /// public, protected, or private. Multiple such methods - /// may be annotated, but it is recommended to only annotate one single - /// init method and destroy method, respectively. + /// Return the order value of this object, where a higher value means greater in + /// terms of sorting. /// - public class InitDestroyAttributeObjectPostProcessor : IDestructionAwareObjectPostProcessor, IObjectFactoryAware, IOrdered + /// + ///

Normally starting with 0 or 1, with indicating + /// greatest. Same order values will result in arbitrary positions for the affected + /// objects. + ///

Higher value can be interpreted as lower priority, consequently the first object + /// has highest priority. + ///

+ ///
+ /// + /// The order value. + /// + public int Order { - private static readonly ILogger logger = LogManager.GetLogger(); + get { return order; } + private set { order = value; } + } - private IConfigurableListableObjectFactory objectFactory; - private readonly IDictionary lifecycleMetadataCache; + /// + /// Specify the init attribute to check for, indicating initialization + /// methods to call after configuration of an object. + /// + public Type InitAttributeType + { + get { return initAttributeType; } + set { initAttributeType = value; } + } - private int order = int.MaxValue; - private Type initAttributeType; - private Type destroyAttributeType; + /// + /// Specify the destroy attribute to check for, indicating disposal + /// methods to call before object is destroyed + /// + public Type DestroyAttributeType + { + get { return destroyAttributeType; } + set { destroyAttributeType = value; } + } - /// - /// Return the order value of this object, where a higher value means greater in - /// terms of sorting. - /// - /// - ///

Normally starting with 0 or 1, with indicating - /// greatest. Same order values will result in arbitrary positions for the affected - /// objects. - ///

Higher value can be interpreted as lower priority, consequently the first object - /// has highest priority. - ///

- ///
- /// - /// The order value. - /// - public int Order + /// + /// + /// + public IObjectFactory ObjectFactory + { + set { objectFactory = value as IConfigurableListableObjectFactory; } + } + + /// + /// Creates InitDestroy Post Processor with default attribute types of + /// + /// + public InitDestroyAttributeObjectPostProcessor() + { + initAttributeType = typeof(PostConstructAttribute); + destroyAttributeType = typeof(PreDestroyAttribute); + + lifecycleMetadataCache = new Dictionary(); + } + + /// + /// Applies PostConstruct init method initialisation if instance is attributed + /// + /// The new object instance. + /// The name of the object. + /// + /// + /// The object instance to use, either the original or a wrapped one. + /// + /// In case of errors. + /// + public object PostProcessBeforeInitialization(object instance, string name) + { + try { - get { return order; } - private set { order = value; } + var metadata = FindLifecycleMetadata(instance.GetType(), name); + metadata.InvokeInitMethods(instance, name); + } + catch (Exception e) + { + throw new ObjectCreationException(name, "Couldn't invoke init method", e); } - /// - /// Specify the init attribute to check for, indicating initialization - /// methods to call after configuration of an object. - /// - public Type InitAttributeType + return instance; + } + + /// + /// No special post processing after initialization + /// + public object PostProcessAfterInitialization(object instance, string objectName) + { + return instance; + } + + /// + /// Executed PreDestroy methods in given order for provided instance + /// + /// The new object instance.The name of the object.In case of errors. + /// + public void PostProcessBeforeDestruction(object instance, string name) + { + try { - get { return initAttributeType; } - set { initAttributeType = value; } + var metadata = FindLifecycleMetadata(instance.GetType(), name); + metadata.InvokeDestroyMethods(instance, name); } - - /// - /// Specify the destroy attribute to check for, indicating disposal - /// methods to call before object is destroyed - /// - public Type DestroyAttributeType + catch (Exception e) { - get { return destroyAttributeType; } - set { destroyAttributeType = value; } + throw new ObjectsException("Couldn't invoke destroy method", e); } + } - /// - /// - /// - public IObjectFactory ObjectFactory + private LifecycleLifecycleMetadata FindLifecycleMetadata(Type instanceType, string name) + { + LifecycleLifecycleMetadata metadata; + if (lifecycleMetadataCache.TryGetValue(name, out metadata)) { - set { objectFactory = value as IConfigurableListableObjectFactory; } - } - - /// - /// Creates InitDestroy Post Processor with default attribute types of - /// - /// - public InitDestroyAttributeObjectPostProcessor() - { - initAttributeType = typeof (PostConstructAttribute); - destroyAttributeType = typeof (PreDestroyAttribute); - - lifecycleMetadataCache = new Dictionary(); - } - - /// - /// Applies PostConstruct init method initialisation if instance is attributed - /// - /// The new object instance. - /// The name of the object. - /// - /// - /// The object instance to use, either the original or a wrapped one. - /// - /// In case of errors. - /// - public object PostProcessBeforeInitialization(object instance, string name) - { - try - { - var metadata = FindLifecycleMetadata(instance.GetType(), name); - metadata.InvokeInitMethods(instance, name); - } - catch (Exception e) - { - throw new ObjectCreationException(name, "Couldn't invoke init method", e); - } - - return instance; - } - - /// - /// No special post processing after initialization - /// - public object PostProcessAfterInitialization(object instance, string objectName) - { - return instance; - } - - /// - /// Executed PreDestroy methods in given order for provided instance - /// - /// The new object instance.The name of the object.In case of errors. - /// - public void PostProcessBeforeDestruction(object instance, string name) - { - try - { - var metadata = FindLifecycleMetadata(instance.GetType(), name); - metadata.InvokeDestroyMethods(instance, name); - } - catch (Exception e) - { - throw new ObjectsException("Couldn't invoke destroy method", e); - } - } - - private LifecycleLifecycleMetadata FindLifecycleMetadata(Type instanceType, string name) - { - LifecycleLifecycleMetadata metadata; - if (lifecycleMetadataCache.TryGetValue(name, out metadata)) - { - return metadata; - } - - lock (lifecycleMetadataCache) - { - if (!lifecycleMetadataCache.TryGetValue(name, out metadata)) - { - metadata = BuildLifecycleMetadata(instanceType, name); - lifecycleMetadataCache.Add(name, metadata); - } - } return metadata; } - private LifecycleLifecycleMetadata BuildLifecycleMetadata(Type instanceType, string name) + lock (lifecycleMetadataCache) { - var initMethods = new List(); - var destroyMethods = new List(); - - do + if (!lifecycleMetadataCache.TryGetValue(name, out metadata)) { - var curInitMethods = new List(); - var curDestroyMethods = new List(); - var methods = - instanceType.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); - foreach (var methodInfo in methods) - { - var initAttribute = - Attribute.GetCustomAttribute(methodInfo, initAttributeType) as PostConstructAttribute; - if (initAttribute != null && methodInfo.DeclaringType == instanceType) - { - logger.LogDebug("Found init method on class [{InstanceType}]: {MethodName}", instanceType.Name, methodInfo.Name); - curInitMethods.Add(new LifecycleElement(methodInfo, initAttribute.Order)); - } - - var destroyAttribute = - Attribute.GetCustomAttribute(methodInfo, destroyAttributeType) as PreDestroyAttribute; - if (destroyAttribute != null && methodInfo.DeclaringType == instanceType) - { - logger.LogDebug("Found destroy method on class [{InstanceType}]: {MethodName}", instanceType.Name, methodInfo.Name); - curDestroyMethods.Add(new LifecycleElement(methodInfo, destroyAttribute.Order)); - } - } - - initMethods.InsertRange(0, curInitMethods.OrderBy(e => e.Order)); - destroyMethods.InsertRange(0, curDestroyMethods.OrderBy(e => e.Order)); - instanceType = instanceType.BaseType; - } while (instanceType != null && instanceType != typeof (Object)); - - var objectDef = objectFactory.GetObjectDefinition(name); - var metadata = new LifecycleLifecycleMetadata(initMethods, destroyMethods); - metadata.CheckConfigMembers(objectDef); - - return metadata; + metadata = BuildLifecycleMetadata(instanceType, name); + lifecycleMetadataCache.Add(name, metadata); + } } - private class LifecycleLifecycleMetadata + return metadata; + } + + private LifecycleLifecycleMetadata BuildLifecycleMetadata(Type instanceType, string name) + { + var initMethods = new List(); + var destroyMethods = new List(); + + do { - private readonly IList initMethods; - private readonly IList destroyMethods; - - public LifecycleLifecycleMetadata(IList initMethods, - IList destroyMethods) + var curInitMethods = new List(); + var curDestroyMethods = new List(); + var methods = + instanceType.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); + foreach (var methodInfo in methods) { - this.initMethods = initMethods; - this.destroyMethods = destroyMethods; + var initAttribute = + Attribute.GetCustomAttribute(methodInfo, initAttributeType) as PostConstructAttribute; + if (initAttribute != null && methodInfo.DeclaringType == instanceType) + { + logger.LogDebug("Found init method on class [{InstanceType}]: {MethodName}", instanceType.Name, methodInfo.Name); + curInitMethods.Add(new LifecycleElement(methodInfo, initAttribute.Order)); + } + + var destroyAttribute = + Attribute.GetCustomAttribute(methodInfo, destroyAttributeType) as PreDestroyAttribute; + if (destroyAttribute != null && methodInfo.DeclaringType == instanceType) + { + logger.LogDebug("Found destroy method on class [{InstanceType}]: {MethodName}", instanceType.Name, methodInfo.Name); + curDestroyMethods.Add(new LifecycleElement(methodInfo, destroyAttribute.Order)); + } } - public void CheckConfigMembers(IObjectDefinition objectDef) + initMethods.InsertRange(0, curInitMethods.OrderBy(e => e.Order)); + destroyMethods.InsertRange(0, curDestroyMethods.OrderBy(e => e.Order)); + instanceType = instanceType.BaseType; + } while (instanceType != null && instanceType != typeof(Object)); + + var objectDef = objectFactory.GetObjectDefinition(name); + var metadata = new LifecycleLifecycleMetadata(initMethods, destroyMethods); + metadata.CheckConfigMembers(objectDef); + + return metadata; + } + + private class LifecycleLifecycleMetadata + { + private readonly IList initMethods; + private readonly IList destroyMethods; + + public LifecycleLifecycleMetadata(IList initMethods, + IList destroyMethods) + { + this.initMethods = initMethods; + this.destroyMethods = destroyMethods; + } + + public void CheckConfigMembers(IObjectDefinition objectDef) + { + lock (initMethods) { - lock (initMethods) + for (int i = 0; i < initMethods.Count; i++) { - for (int i = 0; i < initMethods.Count; i++) + if (!initMethods[i].CheckConfig(objectDef)) { - if (!initMethods[i].CheckConfig(objectDef)) - { - initMethods.Remove(initMethods[i]); - } - } - } - lock (destroyMethods) - { - for (int i = 0; i < destroyMethods.Count; i++) - { - if (!destroyMethods[i].CheckConfig(objectDef)) - { - destroyMethods.Remove(destroyMethods[i]); - } + initMethods.Remove(initMethods[i]); } } } - public void InvokeInitMethods(object instance, string objectName) + lock (destroyMethods) { - foreach (var lifecycleElement in initMethods) + for (int i = 0; i < destroyMethods.Count; i++) { - lifecycleElement.Invoke(instance, objectName); - } - } - - public void InvokeDestroyMethods(object instance, string objectName) - { - foreach (var lifecycleElement in destroyMethods) - { - lifecycleElement.Invoke(instance, objectName); + if (!destroyMethods[i].CheckConfig(objectDef)) + { + destroyMethods.Remove(destroyMethods[i]); + } } } } - private class LifecycleElement + public void InvokeInitMethods(object instance, string objectName) { - private readonly MethodInfo method; - private readonly int order; - - public int Order + foreach (var lifecycleElement in initMethods) { - get { return order; } + lifecycleElement.Invoke(instance, objectName); } + } - public LifecycleElement(MethodInfo method, int order) + public void InvokeDestroyMethods(object instance, string objectName) + { + foreach (var lifecycleElement in destroyMethods) { - this.method = method; - this.order = order; - } - - public bool CheckConfig(IObjectDefinition objectDef) - { - if (method.Name == objectDef.InitMethodName || method.Name == objectDef.DestroyMethodName) - { - return false; - } - - return true; - } - - public void Invoke(object instance, string objectName) - { - logger.LogDebug("Invoking init method on object {ObjectName}: {MethodName}", objectName, method.Name); - method.Invoke(instance, new object[] {}); + lifecycleElement.Invoke(instance, objectName); } } } + + private class LifecycleElement + { + private readonly MethodInfo method; + private readonly int order; + + public int Order + { + get { return order; } + } + + public LifecycleElement(MethodInfo method, int order) + { + this.method = method; + this.order = order; + } + + public bool CheckConfig(IObjectDefinition objectDef) + { + if (method.Name == objectDef.InitMethodName || method.Name == objectDef.DestroyMethodName) + { + return false; + } + + return true; + } + + public void Invoke(object instance, string objectName) + { + logger.LogDebug("Invoking init method on object {ObjectName}: {MethodName}", objectName, method.Name); + method.Invoke(instance, new object[] { }); + } + } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Attributes/InjectionMetadata.cs b/src/Spring/Spring.Core/Objects/Factory/Attributes/InjectionMetadata.cs index 3692869d..48f0b0a3 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Attributes/InjectionMetadata.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Attributes/InjectionMetadata.cs @@ -22,91 +22,90 @@ using System.Reflection; using Microsoft.Extensions.Logging; using Spring.Objects.Factory.Support; -namespace Spring.Objects.Factory.Attributes +namespace Spring.Objects.Factory.Attributes; + +/// +/// Internal class for managing injection metadata. +/// Not intended for direct use in applications. +/// +public class InjectionMetadata { - /// - /// Internal class for managing injection metadata. - /// Not intended for direct use in applications. - /// - public class InjectionMetadata - { - private static readonly ILogger Logger = LogManager.GetLogger(); + private static readonly ILogger Logger = LogManager.GetLogger(); - private readonly Type targetType; - private readonly IList _injectedElements; + private readonly Type targetType; + private readonly IList _injectedElements; - /// - /// - /// - /// - public InjectionMetadata(Type targetType, IList elements) - { - this.targetType = targetType; - _injectedElements = new List(); - if (elements.Count > 0) - { - foreach (var element in elements) - { - Logger.LogDebug("Found injected element on class [{TargetType}]: {Element}", targetType.Name, element); - _injectedElements.Add(element); - } - } - } + /// + /// + /// + /// + public InjectionMetadata(Type targetType, IList elements) + { + this.targetType = targetType; + _injectedElements = new List(); + if (elements.Count > 0) + { + foreach (var element in elements) + { + Logger.LogDebug("Found injected element on class [{TargetType}]: {Element}", targetType.Name, element); + _injectedElements.Add(element); + } + } + } - /// - /// - /// - public void CheckConfigMembers(RootObjectDefinition objectDefinition) - { - } + /// + /// + /// + public void CheckConfigMembers(RootObjectDefinition objectDefinition) + { + } - /// - /// Inject values for members into object instance - /// - /// - /// - /// - public void Inject(object instance, string objectName, IPropertyValues pvs) - { - for (var i = 0; i < _injectedElements.Count; i++) - { - var element = _injectedElements[i]; - Logger.LogDebug("Processing injected method of bean '{ObjectName}': {Element}", objectName, element); - element.Inject(instance, objectName, pvs); - } - } + /// + /// Inject values for members into object instance + /// + /// + /// + /// + public void Inject(object instance, string objectName, IPropertyValues pvs) + { + for (var i = 0; i < _injectedElements.Count; i++) + { + var element = _injectedElements[i]; + Logger.LogDebug("Processing injected method of bean '{ObjectName}': {Element}", objectName, element); + element.Inject(instance, objectName, pvs); + } + } - /// - /// Represents an element that needs to be injected - /// - public abstract class InjectedElement - { - /// - /// Instantiates a new inject element - /// - /// - protected InjectedElement(MemberInfo member) - { - Member = member; - } + /// + /// Represents an element that needs to be injected + /// + public abstract class InjectedElement + { + /// + /// Instantiates a new inject element + /// + /// + protected InjectedElement(MemberInfo member) + { + Member = member; + } - /// - /// The Property, field, method or constructor info. - /// - public MemberInfo Member { get; } + /// + /// The Property, field, method or constructor info. + /// + public MemberInfo Member { get; } - /// - /// Ececuted to inject value to associated memeber info - /// - /// - /// - /// - public abstract void Inject(object target, string requestingObjectName, IPropertyValues pvs); - } + /// + /// Ececuted to inject value to associated memeber info + /// + /// + /// + /// + public abstract void Inject(object target, string requestingObjectName, IPropertyValues pvs); + } - public static bool NeedsRefresh(InjectionMetadata metadata, Type type) - { - return (metadata == null || metadata.targetType != type); - } - } + public static bool NeedsRefresh(InjectionMetadata metadata, Type type) + { + return (metadata == null || metadata.targetType != type); + } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Attributes/PostConstructAttribute.cs b/src/Spring/Spring.Core/Objects/Factory/Attributes/PostConstructAttribute.cs index 5d154bdb..6f8a1826 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Attributes/PostConstructAttribute.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Attributes/PostConstructAttribute.cs @@ -18,42 +18,39 @@ #endregion -namespace Spring.Objects.Factory.Attributes +namespace Spring.Objects.Factory.Attributes; + +/// +/// Defines a method that will be called during the intantiation of an instance +/// +[AttributeUsage(AttributeTargets.Method)] +public class PostConstructAttribute : Attribute { + private int _order; + /// - /// Defines a method that will be called during the intantiation of an instance + /// Initializes a new instance of the PostConstruct class with order = 1 /// - [AttributeUsage(AttributeTargets.Method)] - public class PostConstructAttribute : Attribute + public PostConstructAttribute() { - private int _order; + _order = int.MaxValue; + } + /// + /// Initializes a new instance of the PostConstruct class with defined order + /// + /// Order in which the PostContruct method is called + public PostConstructAttribute(int order) + { + _order = order; + } - /// - /// Initializes a new instance of the PostConstruct class with order = 1 - /// - public PostConstructAttribute() - { - _order = int.MaxValue; - } - - /// - /// Initializes a new instance of the PostConstruct class with defined order - /// - /// Order in which the PostContruct method is called - public PostConstructAttribute(int order) - { - _order = order; - } - - - /// - /// Defined the order in which the PostContruct methods are called - /// - public int Order - { - get { return _order; } - set { _order = value; } - } + /// + /// Defined the order in which the PostContruct methods are called + /// + public int Order + { + get { return _order; } + set { _order = value; } } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Attributes/PreDestroyAttribute.cs b/src/Spring/Spring.Core/Objects/Factory/Attributes/PreDestroyAttribute.cs index e10a15b2..7295bf60 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Attributes/PreDestroyAttribute.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Attributes/PreDestroyAttribute.cs @@ -18,42 +18,39 @@ #endregion -namespace Spring.Objects.Factory.Attributes +namespace Spring.Objects.Factory.Attributes; + +/// +/// Defines a method that will be called prior to the destruction of the object instance +/// +[AttributeUsage(AttributeTargets.Method)] +public class PreDestroyAttribute : Attribute { + private int _order; + /// - /// Defines a method that will be called prior to the destruction of the object instance + /// Initializes a new instance of the PreDestroy attribute with order = 1 /// - [AttributeUsage(AttributeTargets.Method)] - public class PreDestroyAttribute : Attribute + public PreDestroyAttribute() { - private int _order; + _order = int.MaxValue; + } + /// + /// Initializes a new instance of the PreDestroy attribute with defined order + /// + /// Order in which the PostContruct method is called + public PreDestroyAttribute(int order) + { + _order = order; + } - /// - /// Initializes a new instance of the PreDestroy attribute with order = 1 - /// - public PreDestroyAttribute() - { - _order = int.MaxValue; - } - - /// - /// Initializes a new instance of the PreDestroy attribute with defined order - /// - /// Order in which the PostContruct method is called - public PreDestroyAttribute(int order) - { - _order = order; - } - - - /// - /// Defined the order in which the PreDestroy methods are called - /// - public int Order - { - get { return _order; } - set { _order = value; } - } + /// + /// Defined the order in which the PreDestroy methods are called + /// + public int Order + { + get { return _order; } + set { _order = value; } } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Attributes/QualifierAnnotationAutowireCandidateResolver.cs b/src/Spring/Spring.Core/Objects/Factory/Attributes/QualifierAnnotationAutowireCandidateResolver.cs index 3bfe2196..33c185f5 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Attributes/QualifierAnnotationAutowireCandidateResolver.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Attributes/QualifierAnnotationAutowireCandidateResolver.cs @@ -19,341 +19,340 @@ #endregion using System.Runtime.Serialization; - using Spring.Core; using Spring.Core.TypeConversion; using Spring.Objects.Factory.Config; using Spring.Objects.Factory.Support; using Spring.Util; -namespace Spring.Objects.Factory.Attributes +namespace Spring.Objects.Factory.Attributes; + +/// +/// implementation that matches bean definition qualifier +/// against on the field or parameter to be autowired. +/// Also supports suggested expression values through a attribute. +/// +[Serializable] +public class QualifierAnnotationAutowireCandidateResolver : IAutowireCandidateResolver, IObjectFactoryAware, ISerializable { - /// - /// implementation that matches bean definition qualifier - /// against on the field or parameter to be autowired. - /// Also supports suggested expression values through a attribute. - /// - [Serializable] - public class QualifierAnnotationAutowireCandidateResolver : IAutowireCandidateResolver, IObjectFactoryAware, ISerializable + private IObjectFactory _objectFactory; + private readonly HashSet _qualifierTypes = new HashSet(); + + private Type _valueAttributeType = typeof(ValueAttribute); + + public IObjectFactory ObjectFactory { - private IObjectFactory _objectFactory; - private readonly HashSet _qualifierTypes = new HashSet(); + set { _objectFactory = value; } + } - private Type _valueAttributeType = typeof(ValueAttribute); + public Type ValueAttributeType + { + set { _valueAttributeType = value; } + } - public IObjectFactory ObjectFactory + /// + /// Create a new QualifierAnnotationAutowireCandidateResolver + /// for Spring's standard attribute. + /// + public QualifierAnnotationAutowireCandidateResolver() + { + _qualifierTypes.Add(typeof(QualifierAttribute)); + } + + /// + /// Create a new QualifierAnnotationAutowireCandidateResolver + /// for the given qualifier attribute type. + /// + /// the qualifier attribute to look for + public QualifierAnnotationAutowireCandidateResolver(Type qualifierType) + { + AssertUtils.ArgumentNotNull(qualifierType, "'qualifierType' must not be null"); + _qualifierTypes.Add(qualifierType); + } + + /// + /// Create a new QualifierAnnotationAutowireCandidateResolver + /// for the given qualifier attribute types. + /// + /// the qualifier annotations to look for + public QualifierAnnotationAutowireCandidateResolver(Collections.Generic.ISet qualifierTypes) + { + AssertUtils.ArgumentNotNull(qualifierTypes, "'qualifierTypes' must not be null"); + foreach (var type in qualifierTypes) { - set { _objectFactory = value; } + if (!_qualifierTypes.Contains(type)) + _qualifierTypes.Add(type); + } + } + + protected QualifierAnnotationAutowireCandidateResolver(SerializationInfo info, StreamingContext context) + { + _objectFactory = (IObjectFactory) info.GetValue("objectFactory", typeof(IObjectFactory)); + var type = info.GetString("valueAttributeType"); + _valueAttributeType = type != null ? Type.GetType(type) : null; + + _qualifierTypes = new HashSet(); + var typeNames = (List) info.GetValue("qualifierTypeNames", typeof(List)); + foreach (var typeName in typeNames) + { + _qualifierTypes.Add(Type.GetType(typeName)); + } + } + + public void GetObjectData(SerializationInfo info, StreamingContext context) + { + info.AddValue("objectFactory", _objectFactory); + info.AddValue("valueAttributeType", _valueAttributeType?.AssemblyQualifiedName); + + var qualifierTypeNames = new List(); + foreach (var qualifierType in _qualifierTypes) + { + qualifierTypeNames.Add(qualifierType?.AssemblyQualifiedName); } - public Type ValueAttributeType + info.AddValue("qualifierTypeNames", qualifierTypeNames); + } + + /// + /// Register the given type to be used as a qualifier when autowiring. + ///

This identifies qualifier annotations for direct use (on fields, + /// method parameters and constructor parameters) as well as meta + /// annotations that in turn identify actual qualifier annotations.

+ ///

This implementation only supports annotations as qualifier types. + /// The default is Spring's attribute which serves + /// as a qualifier for direct use and also as a meta attribute.

+ ///
+ /// the attribute type to register + public void AddQualifierType(Type qualifierType) + { + _qualifierTypes.Add(qualifierType); + } + + /// + /// Determine whether the provided object definition is an autowire candidate. + ///

To be considered a candidate the object's autowire-candidate + /// attribute must not have been set to 'false'. Also, if an attribute on + /// the field or parameter to be autowired is recognized by this bean factory + /// as a qualifier, the object must 'match' against the attribute as + /// well as any attributes it may contain. The bean definition must contain + /// the same qualifier or match by meta attributes. A "value" attribute will + /// fallback to match against the bean name or an alias if a qualifier or + /// attribute does not match.

+ ///
+ public bool IsAutowireCandidate(ObjectDefinitionHolder odHolder, DependencyDescriptor descriptor) + { + if (!odHolder.ObjectDefinition.IsAutowireCandidate) { - set { _valueAttributeType = value; } + // if explicitly false, do not proceed with qualifier check + return false; } - /// - /// Create a new QualifierAnnotationAutowireCandidateResolver - /// for Spring's standard attribute. - /// - public QualifierAnnotationAutowireCandidateResolver() + if (descriptor == null) { - _qualifierTypes.Add(typeof(QualifierAttribute)); - } - - /// - /// Create a new QualifierAnnotationAutowireCandidateResolver - /// for the given qualifier attribute type. - /// - /// the qualifier attribute to look for - public QualifierAnnotationAutowireCandidateResolver(Type qualifierType) - { - AssertUtils.ArgumentNotNull(qualifierType, "'qualifierType' must not be null"); - _qualifierTypes.Add(qualifierType); - } - - /// - /// Create a new QualifierAnnotationAutowireCandidateResolver - /// for the given qualifier attribute types. - /// - /// the qualifier annotations to look for - public QualifierAnnotationAutowireCandidateResolver(Collections.Generic.ISet qualifierTypes) - { - AssertUtils.ArgumentNotNull(qualifierTypes, "'qualifierTypes' must not be null"); - foreach (var type in qualifierTypes) - { - if (!_qualifierTypes.Contains(type)) - _qualifierTypes.Add(type); - } - } - - protected QualifierAnnotationAutowireCandidateResolver(SerializationInfo info, StreamingContext context) - { - _objectFactory = (IObjectFactory) info.GetValue("objectFactory", typeof(IObjectFactory)); - var type = info.GetString("valueAttributeType"); - _valueAttributeType = type != null ? Type.GetType(type) : null; - - _qualifierTypes = new HashSet(); - var typeNames = (List) info.GetValue("qualifierTypeNames", typeof(List)); - foreach (var typeName in typeNames) - { - _qualifierTypes.Add(Type.GetType(typeName)); - } - } - - public void GetObjectData(SerializationInfo info, StreamingContext context) - { - info.AddValue("objectFactory", _objectFactory); - info.AddValue("valueAttributeType", _valueAttributeType?.AssemblyQualifiedName); - - var qualifierTypeNames = new List(); - foreach (var qualifierType in _qualifierTypes) - { - qualifierTypeNames.Add(qualifierType?.AssemblyQualifiedName); - } - info.AddValue("qualifierTypeNames", qualifierTypeNames); - } - - /// - /// Register the given type to be used as a qualifier when autowiring. - ///

This identifies qualifier annotations for direct use (on fields, - /// method parameters and constructor parameters) as well as meta - /// annotations that in turn identify actual qualifier annotations.

- ///

This implementation only supports annotations as qualifier types. - /// The default is Spring's attribute which serves - /// as a qualifier for direct use and also as a meta attribute.

- ///
- /// the attribute type to register - public void AddQualifierType(Type qualifierType) - { - _qualifierTypes.Add(qualifierType); - } - - /// - /// Determine whether the provided object definition is an autowire candidate. - ///

To be considered a candidate the object's autowire-candidate - /// attribute must not have been set to 'false'. Also, if an attribute on - /// the field or parameter to be autowired is recognized by this bean factory - /// as a qualifier, the object must 'match' against the attribute as - /// well as any attributes it may contain. The bean definition must contain - /// the same qualifier or match by meta attributes. A "value" attribute will - /// fallback to match against the bean name or an alias if a qualifier or - /// attribute does not match.

- ///
- public bool IsAutowireCandidate(ObjectDefinitionHolder odHolder, DependencyDescriptor descriptor) - { - if (!odHolder.ObjectDefinition.IsAutowireCandidate) - { - // if explicitly false, do not proceed with qualifier check - return false; - } - - if (descriptor == null) - { - // no qualification necessaryodHolder - return true; - } - - bool match = CheckQualifiers(odHolder, descriptor.Attributes); - if (match) - { - MethodParameter methodParam = descriptor.MethodParameter; - if (methodParam != null) - { - var method = methodParam.MethodInfo; - if (method == null || method.ReturnType == typeof(void)) - { - match = CheckQualifiers(odHolder, methodParam.MethodAttributes); - } - } - } - - return match; - } - - /// - /// Match the given qualifier annotations against the candidate bean definition. - /// - protected bool CheckQualifiers(ObjectDefinitionHolder odHolder, Attribute[] annotationsToSearch) - { - if (annotationsToSearch == null || annotationsToSearch.Length == 0) - { - return true; - } - - foreach (var attribute in annotationsToSearch) - { - if (IsQualifier(attribute.GetType())) - { - if (!CheckQualifier(odHolder, attribute)) - { - return false; - } - } - } - + // no qualification necessaryodHolder return true; } - /// - /// Checks whether the given attribute type is a recognized qualifier type. - /// - protected bool IsQualifier(Type attributeType) + bool match = CheckQualifiers(odHolder, descriptor.Attributes); + if (match) { - foreach (Type qualifierType in _qualifierTypes) + MethodParameter methodParam = descriptor.MethodParameter; + if (methodParam != null) { - if (IsSubTypeOf(attributeType, qualifierType)) - return true; + var method = methodParam.MethodInfo; + if (method == null || method.ReturnType == typeof(void)) + { + match = CheckQualifiers(odHolder, methodParam.MethodAttributes); + } } - - return false; } - private bool IsSubTypeOf(Type actual, Type requested) + return match; + } + + /// + /// Match the given qualifier annotations against the candidate bean definition. + /// + protected bool CheckQualifiers(ObjectDefinitionHolder odHolder, Attribute[] annotationsToSearch) + { + if (annotationsToSearch == null || annotationsToSearch.Length == 0) { - do - { - if (actual == requested) - return true; - - actual = actual.BaseType; - } while (actual != typeof(Object)); - - return false; + return true; } - /// - /// Match the given qualifier attribute against the candidate bean definition. - /// - protected bool CheckQualifier(ObjectDefinitionHolder odHolder, Attribute attribute) + foreach (var attribute in annotationsToSearch) { - Type type = attribute.GetType(); - RootObjectDefinition od = (RootObjectDefinition) odHolder.ObjectDefinition; - AutowireCandidateQualifier qualifier = od.GetQualifier(type.FullName); - if (qualifier == null) + if (IsQualifier(attribute.GetType())) { - qualifier = od.GetQualifier(type.Name); - } - - if (qualifier == null) - { - Attribute targetAttribute = null; - // TODO: Get the resolved factory method - //if (od.GetResolvedFactoryMethod() != null) { - // targetAttribute = Attribute.GetCustomAttribute(od.GetResolvedFactoryMethod(), type); - //} - if (targetAttribute == null) - { - // look for matching attribute on the target class - if (_objectFactory != null) - { - Type objectType = od.ObjectType; - if (objectType != null) - { - targetAttribute = Attribute.GetCustomAttribute(objectType, type); - } - } - - if (targetAttribute == null && od.ObjectType != null) - { - targetAttribute = Attribute.GetCustomAttribute(od.ObjectType, type); - } - } - - if (targetAttribute != null && targetAttribute.Equals(attribute)) - { - return true; - } - } - - IDictionary attributes = AttributeUtils.GetAttributeProperties(attribute); - if (attributes.Count == 0 && qualifier == null) - { - // if no attributes, the qualifier must be present - return false; - } - - foreach (var entry in attributes) - { - string propertyName = entry.Key; - object expectedValue = entry.Value; - object actualValue = null; - // check qualifier first - if (qualifier != null) - { - actualValue = qualifier.GetAttribute(propertyName); - } - - if (actualValue == null) - { - // fall back on bean definition attribute - actualValue = od.GetAttribute(propertyName); - } - - if (actualValue == null && propertyName.Equals(AutowireCandidateQualifier.VALUE_KEY) && - expectedValue is string && odHolder.MatchesName((string) expectedValue)) - { - // fall back on bean name (or alias) match - continue; - } - - if (actualValue == null && qualifier != null) - { - // fall back on default, but only if the qualifier is present - actualValue = AttributeUtils.GetDefaultValue(attribute, propertyName); - } - - if (actualValue != null) - { - actualValue = TypeConversionUtils.ConvertValueIfNecessary(expectedValue.GetType(), actualValue, null); - } - - if (!expectedValue.Equals(actualValue)) + if (!CheckQualifier(odHolder, attribute)) { return false; } } - - return true; } - /// - /// Determine whether the given dependency carries a value attribute. - /// - public Object GetSuggestedValue(DependencyDescriptor descriptor) - { - Object value = FindValue(descriptor.Attributes); - if (value == null) - { - MethodParameter methodParam = descriptor.MethodParameter; - if (methodParam != null) - { - value = FindValue(methodParam.MethodAttributes); - } - } + return true; + } - return value; + /// + /// Checks whether the given attribute type is a recognized qualifier type. + /// + protected bool IsQualifier(Type attributeType) + { + foreach (Type qualifierType in _qualifierTypes) + { + if (IsSubTypeOf(attributeType, qualifierType)) + return true; } - /// - /// Determine a suggested value from any of the given candidate annotations. - /// - protected Object FindValue(Attribute[] annotationsToSearch) + return false; + } + + private bool IsSubTypeOf(Type actual, Type requested) + { + do { - foreach (var attribute in annotationsToSearch) + if (actual == requested) + return true; + + actual = actual.BaseType; + } while (actual != typeof(Object)); + + return false; + } + + /// + /// Match the given qualifier attribute against the candidate bean definition. + /// + protected bool CheckQualifier(ObjectDefinitionHolder odHolder, Attribute attribute) + { + Type type = attribute.GetType(); + RootObjectDefinition od = (RootObjectDefinition) odHolder.ObjectDefinition; + AutowireCandidateQualifier qualifier = od.GetQualifier(type.FullName); + if (qualifier == null) + { + qualifier = od.GetQualifier(type.Name); + } + + if (qualifier == null) + { + Attribute targetAttribute = null; + // TODO: Get the resolved factory method + //if (od.GetResolvedFactoryMethod() != null) { + // targetAttribute = Attribute.GetCustomAttribute(od.GetResolvedFactoryMethod(), type); + //} + if (targetAttribute == null) { - if (_valueAttributeType == attribute.GetType()) + // look for matching attribute on the target class + if (_objectFactory != null) { - Object value = ((ValueAttribute) attribute).Expression; - if (value == null) + Type objectType = od.ObjectType; + if (objectType != null) { - throw new InvalidOperationException("Value attribute must have a value attribute"); + targetAttribute = Attribute.GetCustomAttribute(objectType, type); } + } - return value; + if (targetAttribute == null && od.ObjectType != null) + { + targetAttribute = Attribute.GetCustomAttribute(od.ObjectType, type); } } - return null; + if (targetAttribute != null && targetAttribute.Equals(attribute)) + { + return true; + } } + + IDictionary attributes = AttributeUtils.GetAttributeProperties(attribute); + if (attributes.Count == 0 && qualifier == null) + { + // if no attributes, the qualifier must be present + return false; + } + + foreach (var entry in attributes) + { + string propertyName = entry.Key; + object expectedValue = entry.Value; + object actualValue = null; + // check qualifier first + if (qualifier != null) + { + actualValue = qualifier.GetAttribute(propertyName); + } + + if (actualValue == null) + { + // fall back on bean definition attribute + actualValue = od.GetAttribute(propertyName); + } + + if (actualValue == null && propertyName.Equals(AutowireCandidateQualifier.VALUE_KEY) && + expectedValue is string && odHolder.MatchesName((string) expectedValue)) + { + // fall back on bean name (or alias) match + continue; + } + + if (actualValue == null && qualifier != null) + { + // fall back on default, but only if the qualifier is present + actualValue = AttributeUtils.GetDefaultValue(attribute, propertyName); + } + + if (actualValue != null) + { + actualValue = TypeConversionUtils.ConvertValueIfNecessary(expectedValue.GetType(), actualValue, null); + } + + if (!expectedValue.Equals(actualValue)) + { + return false; + } + } + + return true; + } + + /// + /// Determine whether the given dependency carries a value attribute. + /// + public Object GetSuggestedValue(DependencyDescriptor descriptor) + { + Object value = FindValue(descriptor.Attributes); + if (value == null) + { + MethodParameter methodParam = descriptor.MethodParameter; + if (methodParam != null) + { + value = FindValue(methodParam.MethodAttributes); + } + } + + return value; + } + + /// + /// Determine a suggested value from any of the given candidate annotations. + /// + protected Object FindValue(Attribute[] annotationsToSearch) + { + foreach (var attribute in annotationsToSearch) + { + if (_valueAttributeType == attribute.GetType()) + { + Object value = ((ValueAttribute) attribute).Expression; + if (value == null) + { + throw new InvalidOperationException("Value attribute must have a value attribute"); + } + + return value; + } + } + + return null; } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Attributes/QualifierAttribute.cs b/src/Spring/Spring.Core/Objects/Factory/Attributes/QualifierAttribute.cs index 1fd35836..54d6187e 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Attributes/QualifierAttribute.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Attributes/QualifierAttribute.cs @@ -1,59 +1,57 @@ -namespace Spring.Objects.Factory.Attributes +namespace Spring.Objects.Factory.Attributes; + +/// +/// This annotation may be used on a field or parameter as a qualifier for +/// candidate beans when autowiring. It may also be used to annotate other +/// custom annotations that can then in turn be used as qualifiers. +/// +[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter)] +public class QualifierAttribute : Attribute { + private readonly string _value; + /// - /// This annotation may be used on a field or parameter as a qualifier for - /// candidate beans when autowiring. It may also be used to annotate other - /// custom annotations that can then in turn be used as qualifiers. + /// Instantiate a new qualifier with an empty name /// - [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter)] - public class QualifierAttribute : Attribute + public QualifierAttribute() { - private readonly string _value; + _value = ""; + } - /// - /// Instantiate a new qualifier with an empty name - /// - public QualifierAttribute() + /// + /// Instantiate a new qualifier with a givin name + /// + /// name to use as qualifier + public QualifierAttribute(string value) + { + _value = value; + } + + /// + /// Gets the name associated with this qualifier + /// + public string Value { get { return _value; } } + + /// + /// Checks weather the attribute is the same + /// + /// + /// + public override bool Equals(object obj) + { + if (obj == null || GetType() != obj.GetType()) { - _value = ""; + return false; } - /// - /// Instantiate a new qualifier with a givin name - /// - /// name to use as qualifier - public QualifierAttribute(string value) - { - _value = value; - } + var o1 = obj as QualifierAttribute; + if (_value != o1._value) return false; - /// - /// Gets the name associated with this qualifier - /// - public string Value { get { return _value; } } + return true; + } - - /// - /// Checks weather the attribute is the same - /// - /// - /// - public override bool Equals(object obj) - { - if (obj == null || GetType() != obj.GetType()) - { - return false; - } - - var o1 = obj as QualifierAttribute; - if (_value != o1._value) return false; - - return true; - } - - public override int GetHashCode() - { - return _value != null ? _value.GetHashCode() : 0; - } + public override int GetHashCode() + { + return _value != null ? _value.GetHashCode() : 0; } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Attributes/RequiredAttribute.cs b/src/Spring/Spring.Core/Objects/Factory/Attributes/RequiredAttribute.cs index 8d58f19a..21abe6b8 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Attributes/RequiredAttribute.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Attributes/RequiredAttribute.cs @@ -18,20 +18,18 @@ #endregion -namespace Spring.Objects.Factory.Attributes -{ - /// - /// Marks a property as being 'required': that is, the setter property - /// must be configured to be dependency-injected with a value. - /// - /// Consult the SDK documentation for , - /// which, by default, checks for the presence of this annotation. - /// - /// Rob Harrop - /// Mark Pollack - [AttributeUsage(AttributeTargets.Property, Inherited = true)] - public class RequiredAttribute : Attribute - { +namespace Spring.Objects.Factory.Attributes; - } +/// +/// Marks a property as being 'required': that is, the setter property +/// must be configured to be dependency-injected with a value. +/// +/// Consult the SDK documentation for , +/// which, by default, checks for the presence of this annotation. +/// +/// Rob Harrop +/// Mark Pollack +[AttributeUsage(AttributeTargets.Property, Inherited = true)] +public class RequiredAttribute : Attribute +{ } diff --git a/src/Spring/Spring.Core/Objects/Factory/Attributes/RequiredAttributeObjectPostProcessor.cs b/src/Spring/Spring.Core/Objects/Factory/Attributes/RequiredAttributeObjectPostProcessor.cs index a9fd15dc..e97142df 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Attributes/RequiredAttributeObjectPostProcessor.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Attributes/RequiredAttributeObjectPostProcessor.cs @@ -20,160 +20,162 @@ using System.Reflection; using System.Text; - using Spring.Collections; using Spring.Objects.Factory.Config; using Spring.Util; -namespace Spring.Objects.Factory.Attributes +namespace Spring.Objects.Factory.Attributes; + +/// +/// A implementation that enforces required properties to have been configured. +/// Required properties are detected through an attribute, by default, Spring's +/// attribute. +/// +/// +/// The motivation for the existence of this IObjectPostProcessor is to allow +/// developers to annotate the setter properties of their own classes with an +/// arbitrary attribute to indicate that the container must check +/// for the configuration of a dependency injected value. This neatly pushes +/// responsibility for such checking onto the container (where it arguably belongs), +/// and obviates the need (in part) for a developer to code a method that +/// simply checks that all required properties have actually been set. +/// +/// Please note that an 'init' method may still need to implemented (and may +/// still be desirable), because all that this class does is enforce that a +/// 'required' property has actually been configured with a value. It does +/// not check anything else... In particular, it does not check that a +/// configured value is not null. +/// +/// +/// Rob Harrop +/// Juergen Hoeller +/// Mark Pollack (.NET) +public class RequiredAttributeObjectPostProcessor : InstantiationAwareObjectPostProcessorAdapter { + private Type requiredAttributeType = typeof(RequiredAttribute); + /// - /// A implementation that enforces required properties to have been configured. - /// Required properties are detected through an attribute, by default, Spring's - /// attribute. + /// Cache for validated object names, skipping re-validation for the same object + /// + private ISet validatedObjectNames = new SynchronizedSet(new HashedSet()); + + /// + /// Sets the type of the required attribute, to be used on a property setter /// /// - /// The motivation for the existence of this IObjectPostProcessor is to allow - /// developers to annotate the setter properties of their own classes with an - /// arbitrary attribute to indicate that the container must check - /// for the configuration of a dependency injected value. This neatly pushes - /// responsibility for such checking onto the container (where it arguably belongs), - /// and obviates the need (in part) for a developer to code a method that - /// simply checks that all required properties have actually been set. - /// - /// Please note that an 'init' method may still need to implemented (and may - /// still be desirable), because all that this class does is enforce that a - /// 'required' property has actually been configured with a value. It does - /// not check anything else... In particular, it does not check that a - /// configured value is not null. - /// + /// The default required attribute type is the Spring-provided attribute. + /// This setter property exists so that developers can provide their own + /// (non-Spring-specific) annotation type to indicate that a property value is required. /// - /// Rob Harrop - /// Juergen Hoeller - /// Mark Pollack (.NET) - public class RequiredAttributeObjectPostProcessor : InstantiationAwareObjectPostProcessorAdapter + /// The type of the required attribute. + public Type RequiredAttributeType { - private Type requiredAttributeType = typeof (RequiredAttribute); - - /// - /// Cache for validated object names, skipping re-validation for the same object - /// - private ISet validatedObjectNames = new SynchronizedSet(new HashedSet()); - - /// - /// Sets the type of the required attribute, to be used on a property setter - /// - /// - /// The default required attribute type is the Spring-provided attribute. - /// This setter property exists so that developers can provide their own - /// (non-Spring-specific) annotation type to indicate that a property value is required. - /// - /// The type of the required attribute. - public Type RequiredAttributeType + set { - set + AssertUtils.ArgumentNotNull(value, "RequiredAttributeType", "RequiredAttributeType property must not be null"); + if (!typeof(Attribute).IsAssignableFrom(value)) { - AssertUtils.ArgumentNotNull(value, "RequiredAttributeType", "RequiredAttributeType property must not be null"); - if (!typeof(Attribute).IsAssignableFrom(value)) - { - throw new ArgumentException( - string.Format("[{0}] does not inherit from System.Attribute (it must).", value.FullName)); - } - requiredAttributeType = value; - } - get - { - return requiredAttributeType; + throw new ArgumentException( + string.Format("[{0}] does not inherit from System.Attribute (it must).", value.FullName)); } + + requiredAttributeType = value; } - - - /// - /// Post-process the given property values before the factory applies them - /// to the given object. Checks for the attribute specified by this PostProcessor's RequiredAttributeType. - /// - /// The property values that the factory is about to apply (never null). - /// The relevant property infos for the target object (with ignored - /// dependency types - which the factory handles specifically - already filtered out) - /// The object instance created, but whose properties have not yet - /// been set. - /// Name of the object. - /// - /// The actual property values to apply to the given object (can be the - /// passed-in PropertyValues instances or null to skip property population. - /// - /// If a required property value has not been specified - /// in the configuration metadata. - public override IPropertyValues PostProcessPropertyValues(IPropertyValues pvs, IList pis, object objectInstance, string objectName) + get { - if (!validatedObjectNames.Contains(objectName)) - { - List invalidProperties = new List(); - - foreach (PropertyInfo pi in pis) - { - if (IsRequiredProperty(pi) && !pvs.Contains(pi.Name)) - { - invalidProperties.Add(pi.Name); - } - } - if (invalidProperties.Count != 0) - { - throw new ObjectInitializationException( - BuildExceptionMessage(invalidProperties, objectName)); - } - validatedObjectNames.Add(objectName); - } - return pvs; - } - - /// - /// Determines whether the supplied property is required to have a value, that is to be dependency injected. - /// - /// - /// This implementation looks for the existence of a "required" attribute on the supplied PropertyInfo and that - /// the property has a setter method. - /// - /// The target PropertyInfo - /// - /// true if the supplied property has been marked as being required;; otherwise, false if - /// not or if the supplied property does not have a setter method - /// - protected virtual bool IsRequiredProperty(PropertyInfo pi) - { - return (pi.GetSetMethod() != null && pi.GetCustomAttributes(RequiredAttributeType, true).Length > 0); - } - - /// - /// Builds an exception message for the given list of invalid properties. - /// - /// The list of names of invalid properties. - /// Name of the object. - /// The exception message - private string BuildExceptionMessage(IList invalidProperties, ICloneable objectName) - { - int size = invalidProperties.Count; - StringBuilder sb = new StringBuilder(); - sb.Append(size == 1 ? "Property" : "Properties"); - for (int i=0; i < size; i++) - { - string propName = invalidProperties[i]; - if (i > 0) - { - if (i == (size -1 )) - { - sb.Append(" and"); - } - else - { - sb.Append(", "); - } - } - sb.Append(" '").Append(propName).Append("'"); - } - sb.Append(" required for object '").Append(objectName).Append("'"); - return sb.ToString(); - + return requiredAttributeType; } } -} + + /// + /// Post-process the given property values before the factory applies them + /// to the given object. Checks for the attribute specified by this PostProcessor's RequiredAttributeType. + /// + /// The property values that the factory is about to apply (never null). + /// The relevant property infos for the target object (with ignored + /// dependency types - which the factory handles specifically - already filtered out) + /// The object instance created, but whose properties have not yet + /// been set. + /// Name of the object. + /// + /// The actual property values to apply to the given object (can be the + /// passed-in PropertyValues instances or null to skip property population. + /// + /// If a required property value has not been specified + /// in the configuration metadata. + public override IPropertyValues PostProcessPropertyValues(IPropertyValues pvs, IList pis, object objectInstance, string objectName) + { + if (!validatedObjectNames.Contains(objectName)) + { + List invalidProperties = new List(); + + foreach (PropertyInfo pi in pis) + { + if (IsRequiredProperty(pi) && !pvs.Contains(pi.Name)) + { + invalidProperties.Add(pi.Name); + } + } + + if (invalidProperties.Count != 0) + { + throw new ObjectInitializationException( + BuildExceptionMessage(invalidProperties, objectName)); + } + + validatedObjectNames.Add(objectName); + } + + return pvs; + } + + /// + /// Determines whether the supplied property is required to have a value, that is to be dependency injected. + /// + /// + /// This implementation looks for the existence of a "required" attribute on the supplied PropertyInfo and that + /// the property has a setter method. + /// + /// The target PropertyInfo + /// + /// true if the supplied property has been marked as being required;; otherwise, false if + /// not or if the supplied property does not have a setter method + /// + protected virtual bool IsRequiredProperty(PropertyInfo pi) + { + return (pi.GetSetMethod() != null && pi.GetCustomAttributes(RequiredAttributeType, true).Length > 0); + } + + /// + /// Builds an exception message for the given list of invalid properties. + /// + /// The list of names of invalid properties. + /// Name of the object. + /// The exception message + private string BuildExceptionMessage(IList invalidProperties, ICloneable objectName) + { + int size = invalidProperties.Count; + StringBuilder sb = new StringBuilder(); + sb.Append(size == 1 ? "Property" : "Properties"); + for (int i = 0; i < size; i++) + { + string propName = invalidProperties[i]; + if (i > 0) + { + if (i == (size - 1)) + { + sb.Append(" and"); + } + else + { + sb.Append(", "); + } + } + + sb.Append(" '").Append(propName).Append("'"); + } + + sb.Append(" required for object '").Append(objectName).Append("'"); + return sb.ToString(); + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Objects/Factory/Attributes/ValueAttribute.cs b/src/Spring/Spring.Core/Objects/Factory/Attributes/ValueAttribute.cs index 5ca21b73..6ca009c3 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Attributes/ValueAttribute.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Attributes/ValueAttribute.cs @@ -18,18 +18,17 @@ #endregion -namespace Spring.Objects.Factory.Attributes +namespace Spring.Objects.Factory.Attributes; + +[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter)] +public class ValueAttribute : Attribute { - [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter)] - public class ValueAttribute : Attribute + private string _expression; + + public ValueAttribute(string expression) { - private string _expression; - - public ValueAttribute(string expression) - { - _expression = expression; - } - - public string Expression { get { return _expression; } } + _expression = expression; } + + public string Expression { get { return _expression; } } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/AbstractConfigurer.cs b/src/Spring/Spring.Core/Objects/Factory/Config/AbstractConfigurer.cs index b04239bf..311e8b53 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/AbstractConfigurer.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/AbstractConfigurer.cs @@ -21,100 +21,100 @@ using Spring.Core; using Spring.Core.TypeResolution; -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Base class that provides common functionality needed for several IObjectFactoryPostProcessor +/// implementations +/// +/// Mark Pollack +[Serializable] +public abstract class AbstractConfigurer : IPriorityOrdered, IObjectFactoryPostProcessor { + private int order = Int32.MaxValue; // default: same as non-Ordered + /// - /// Base class that provides common functionality needed for several IObjectFactoryPostProcessor - /// implementations + /// Return the order value of this object, with a higher value meaning + /// greater in terms of sorting. /// - /// Mark Pollack - [Serializable] - public abstract class AbstractConfigurer : IPriorityOrdered, IObjectFactoryPostProcessor + /// The order value. + /// + public int Order { - private int order = Int32.MaxValue; // default: same as non-Ordered + get { return order; } + set { order = value; } + } - /// - /// Return the order value of this object, with a higher value meaning - /// greater in terms of sorting. - /// - /// The order value. - /// - public int Order + /// + /// Modify the application context's internal object factory after its + /// standard initialization. + /// + /// The object factory used by the application context. + /// + ///

+ /// All object definitions will have been loaded, but no objects will have + /// been instantiated yet. This allows for overriding or adding properties + /// even to eager-initializing objects. + ///

+ ///
+ /// + /// In case of errors. + /// + public abstract void PostProcessObjectFactory( + IConfigurableListableObjectFactory factory); + + /// + /// Resolves the supplied into a + /// instance. + /// + /// The object that is to be resolved into a + /// instance. + /// The error context source. + /// The error context string. + /// A resolved . + /// + ///

+ /// This (default) implementation supports resolving + /// s and s. + /// Only override this method if you want to key your type alias + /// on something other than s + /// and s. + ///

+ ///
+ /// + /// If the supplied is , + /// or the supplied cannot be resolved. + /// + protected virtual Type ResolveRequiredType(object value, string errorContextSource, string errorContext) + { + Type requiredType = value as Type; + if (requiredType == null) { - get { return order; } - set { order = value; } - } - - /// - /// Modify the application context's internal object factory after its - /// standard initialization. - /// - /// The object factory used by the application context. - /// - ///

- /// All object definitions will have been loaded, but no objects will have - /// been instantiated yet. This allows for overriding or adding properties - /// even to eager-initializing objects. - ///

- ///
- /// - /// In case of errors. - /// - public abstract void PostProcessObjectFactory( - IConfigurableListableObjectFactory factory); - - /// - /// Resolves the supplied into a - /// instance. - /// - /// The object that is to be resolved into a - /// instance. - /// The error context source. - /// The error context string. - /// A resolved . - /// - ///

- /// This (default) implementation supports resolving - /// s and s. - /// Only override this method if you want to key your type alias - /// on something other than s - /// and s. - ///

- ///
- /// - /// If the supplied is , - /// or the supplied cannot be resolved. - /// - protected virtual Type ResolveRequiredType(object value, string errorContextSource, string errorContext) - { - Type requiredType = value as Type; - if (requiredType == null) + string typeName = value as string; + if (typeName != null) { - string typeName = value as string; - if (typeName != null) + try { - try - { - requiredType = TypeResolutionUtils.ResolveType(typeName); - } - catch (TypeLoadException ex) - { - throw new ObjectInitializationException( - string.Format( - "Could not load required type [{0}] for {1}.", - typeName, errorContext), ex); - } + requiredType = TypeResolutionUtils.ResolveType(typeName); } - else + catch (TypeLoadException ex) { throw new ObjectInitializationException( string.Format( - "Invalid value '{0}' for {1} - " + - "must be a System.String or System.Type.", - value, errorContext)); + "Could not load required type [{0}] for {1}.", + typeName, errorContext), ex); } } - return requiredType; + else + { + throw new ObjectInitializationException( + string.Format( + "Invalid value '{0}' for {1} - " + + "must be a System.String or System.Type.", + value, errorContext)); + } } + + return requiredType; } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/AbstractFactoryObject.cs b/src/Spring/Spring.Core/Objects/Factory/Config/AbstractFactoryObject.cs index d4b584ec..df456f0d 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/AbstractFactoryObject.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/AbstractFactoryObject.cs @@ -18,139 +18,138 @@ #endregion -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Simple template superclass for +/// implementations that allows for the creation of a singleton or a prototype +/// instance (depending on a flag). +/// +/// +/// If the value of the +/// +/// property is (this is the default), this class +/// will create a single instance of it's object upon initialization and +/// subsequently return the singleton instance; else, this class will +/// create a new instance each time (prototype mode). Subclasses must +/// implement the +/// +/// template method to actually create objects. +/// +/// Juergen Hoeller +/// Keith Donald +/// Simon White (.NET) +[Serializable] +public abstract class AbstractFactoryObject : IFactoryObject, IInitializingObject, IDisposable { - /// - /// Simple template superclass for - /// implementations that allows for the creation of a singleton or a prototype - /// instance (depending on a flag). - /// - /// - /// If the value of the - /// - /// property is (this is the default), this class - /// will create a single instance of it's object upon initialization and - /// subsequently return the singleton instance; else, this class will - /// create a new instance each time (prototype mode). Subclasses must - /// implement the - /// - /// template method to actually create objects. - /// - /// Juergen Hoeller - /// Keith Donald - /// Simon White (.NET) - [Serializable] - public abstract class AbstractFactoryObject : IFactoryObject, IInitializingObject, IDisposable - { - private bool isSingleton = true; - private object singletonInstance; + private bool isSingleton = true; + private object singletonInstance; - /// - /// Is the object managed by this factory a singleton or a prototype? - /// - /// - ///

- /// Please note that changing the value of this property after - /// this factory object instance has been created by an enclosing - /// Spring.NET IoC container really is a programming error. This - /// property should really only be set once, prior to the invocation - /// of the - /// - /// callback method. - ///

- ///
- /// - public bool IsSingleton - { - get { return this.isSingleton; } - set { this.isSingleton = value; } - } + /// + /// Is the object managed by this factory a singleton or a prototype? + /// + /// + ///

+ /// Please note that changing the value of this property after + /// this factory object instance has been created by an enclosing + /// Spring.NET IoC container really is a programming error. This + /// property should really only be set once, prior to the invocation + /// of the + /// + /// callback method. + ///

+ ///
+ /// + public bool IsSingleton + { + get { return this.isSingleton; } + set { this.isSingleton = value; } + } - /// - /// Return the of object that this - /// creates, or - /// if not known in advance. - /// - /// - public abstract Type ObjectType { get; } + /// + /// Return the of object that this + /// creates, or + /// if not known in advance. + /// + /// + public abstract Type ObjectType { get; } - /// - /// Invoked by an - /// after it has injected all of an object's dependencies. - /// - /// - /// In the event of misconfiguration (such as the failure to set a - /// required property) or if initialization fails. - /// - /// - public virtual void AfterPropertiesSet() - { - if (this.isSingleton && this.singletonInstance == null) - { - this.singletonInstance = CreateInstance(); - } - } + /// + /// Invoked by an + /// after it has injected all of an object's dependencies. + /// + /// + /// In the event of misconfiguration (such as the failure to set a + /// required property) or if initialization fails. + /// + /// + public virtual void AfterPropertiesSet() + { + if (this.isSingleton && this.singletonInstance == null) + { + this.singletonInstance = CreateInstance(); + } + } - /// - /// Return an instance (possibly shared or independent) of the object - /// managed by this factory. - /// - /// - /// An instance (possibly shared or independent) of the object managed by - /// this factory. - /// - /// - public object GetObject() - { - if (this.isSingleton) - { - return this.singletonInstance; - } - else - { - return CreateInstance(); - } - } + /// + /// Return an instance (possibly shared or independent) of the object + /// managed by this factory. + /// + /// + /// An instance (possibly shared or independent) of the object managed by + /// this factory. + /// + /// + public object GetObject() + { + if (this.isSingleton) + { + return this.singletonInstance; + } + else + { + return CreateInstance(); + } + } - /// - /// Template method that subclasses must override to construct - /// the object returned by this factory. - /// - /// - /// Invoked once immediately after the initialization of this - /// in the case of - /// a singleton; else, on each call to the - /// - /// method. - /// - /// - /// If an exception occured during object creation. - /// - /// - /// A distinct instance of the object created by this factory. - /// - protected abstract object CreateInstance(); + /// + /// Template method that subclasses must override to construct + /// the object returned by this factory. + /// + /// + /// Invoked once immediately after the initialization of this + /// in the case of + /// a singleton; else, on each call to the + /// + /// method. + /// + /// + /// If an exception occured during object creation. + /// + /// + /// A distinct instance of the object created by this factory. + /// + protected abstract object CreateInstance(); - /// - /// Performs cleanup on any cached singleton object. - /// - /// - ///

- /// Only makes sense in the context of a singleton object. - ///

- ///
- /// - /// - public virtual void Dispose() - { - if (this.isSingleton && this.singletonInstance != null) - { - IDisposable disposableSingletonInstance = this.singletonInstance as IDisposable; - if (disposableSingletonInstance != null) - { - disposableSingletonInstance.Dispose(); - } - } - } - } + /// + /// Performs cleanup on any cached singleton object. + /// + /// + ///

+ /// Only makes sense in the context of a singleton object. + ///

+ ///
+ /// + /// + public virtual void Dispose() + { + if (this.isSingleton && this.singletonInstance != null) + { + IDisposable disposableSingletonInstance = this.singletonInstance as IDisposable; + if (disposableSingletonInstance != null) + { + disposableSingletonInstance.Dispose(); + } + } + } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/AutoWiringMode.cs b/src/Spring/Spring.Core/Objects/Factory/Config/AutoWiringMode.cs index 6c6a561c..9f5c408d 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/AutoWiringMode.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/AutoWiringMode.cs @@ -18,40 +18,38 @@ #endregion -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// The various autowiring modes. +/// +/// Rick Evans +[Serializable] +public enum AutoWiringMode { - - /// - /// The various autowiring modes. + /// + /// Do not autowire. /// - /// Rick Evans - [Serializable] - public enum AutoWiringMode - { - /// - /// Do not autowire. - /// - No = 0, + No = 0, - /// - /// Autowire by name. - /// - ByName = 1, + /// + /// Autowire by name. + /// + ByName = 1, - /// - /// Autowire by . - /// - ByType = 2, + /// + /// Autowire by . + /// + ByType = 2, - /// - /// Autowiring by constructor. - /// - Constructor = 3, + /// + /// Autowiring by constructor. + /// + Constructor = 3, - /// - /// The autowiring strategy is to be determined by introspection - /// of the object's . - /// - AutoDetect = 4 - } + /// + /// The autowiring strategy is to be determined by introspection + /// of the object's . + /// + AutoDetect = 4 } diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/CommandLineArgsVariableSource.cs b/src/Spring/Spring.Core/Objects/Factory/Config/CommandLineArgsVariableSource.cs index 70f8d04e..97c2ba6b 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/CommandLineArgsVariableSource.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/CommandLineArgsVariableSource.cs @@ -18,130 +18,131 @@ #endregion -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Implementation of that +/// resolves variable name against command line arguments. +/// +/// Aleksandar Seovic +[Serializable] +public class CommandLineArgsVariableSource : IVariableSource { + private const string DEFAULT_ARG_PREFIX = "/"; + private const string DEFAULT_VALUE_SEPARATOR = ":"; + + private string argumentPrefix = DEFAULT_ARG_PREFIX; + private string valueSeparator = DEFAULT_VALUE_SEPARATOR; + + private string[] commandLineArgs; + protected IDictionary arguments; + + private object objectMonitor = new object(); + /// - /// Implementation of that - /// resolves variable name against command line arguments. + /// Default constructor. + /// Initializes command line arguments from the environment. /// - /// Aleksandar Seovic - [Serializable] - public class CommandLineArgsVariableSource : IVariableSource + public CommandLineArgsVariableSource() { - private const string DEFAULT_ARG_PREFIX = "/"; - private const string DEFAULT_VALUE_SEPARATOR = ":"; + this.commandLineArgs = Environment.GetCommandLineArgs(); + } - private string argumentPrefix = DEFAULT_ARG_PREFIX; - private string valueSeparator = DEFAULT_VALUE_SEPARATOR; + /// + /// Constructor that allows arguments to be passed externally. + /// Useful for testing. + /// + public CommandLineArgsVariableSource(string[] commandLineArgs) + { + this.commandLineArgs = commandLineArgs; + } - private string[] commandLineArgs; - protected IDictionary arguments; + /// + /// Gets or sets a prefix that should be used to + /// identify arguments to extract values from. + /// + /// + /// A prefix that should be used to identify arguments + /// to extract values from. Defaults to slash ("/"). + /// + public string ArgumentPrefix + { + get { return argumentPrefix; } + set { argumentPrefix = value; } + } - private object objectMonitor = new object(); + /// + /// Gets or sets a character that should be used to + /// separate argument name from its value. + /// + /// + /// A character that should be used to separate argument + /// name from its value. Defaults to colon (":"). + /// + public string ValueSeparator + { + get { return valueSeparator; } + set { valueSeparator = value; } + } - /// - /// Default constructor. - /// Initializes command line arguments from the environment. - /// - public CommandLineArgsVariableSource() + /// + /// Before requesting a variable resolution, a client should + /// ask, whether the source can resolve a particular variable name. + /// + /// the name of the variable to resolve + /// true if the variable can be resolved, false otherwise + public bool CanResolveVariable(string name) + { + lock (objectMonitor) { - this.commandLineArgs = Environment.GetCommandLineArgs(); - } - - /// - /// Constructor that allows arguments to be passed externally. - /// Useful for testing. - /// - public CommandLineArgsVariableSource(string[] commandLineArgs) - { - this.commandLineArgs = commandLineArgs; - } - - /// - /// Gets or sets a prefix that should be used to - /// identify arguments to extract values from. - /// - /// - /// A prefix that should be used to identify arguments - /// to extract values from. Defaults to slash ("/"). - /// - public string ArgumentPrefix - { - get { return argumentPrefix; } - set { argumentPrefix = value; } - } - - /// - /// Gets or sets a character that should be used to - /// separate argument name from its value. - /// - /// - /// A character that should be used to separate argument - /// name from its value. Defaults to colon (":"). - /// - public string ValueSeparator - { - get { return valueSeparator; } - set { valueSeparator = value; } - } - - /// - /// Before requesting a variable resolution, a client should - /// ask, whether the source can resolve a particular variable name. - /// - /// the name of the variable to resolve - /// true if the variable can be resolved, false otherwise - public bool CanResolveVariable(string name) - { - lock (objectMonitor) + if (arguments == null) { - if (arguments == null) - { - InitArguments(); - } - return arguments.ContainsKey(name); + InitArguments(); } - } - /// - /// Resolves variable value for the specified variable name. - /// - /// - /// The name of the variable to resolve. - /// - /// - /// The variable value if able to resolve, null otherwise. - /// - public string ResolveVariable(string name) + return arguments.ContainsKey(name); + } + } + + /// + /// Resolves variable value for the specified variable name. + /// + /// + /// The name of the variable to resolve. + /// + /// + /// The variable value if able to resolve, null otherwise. + /// + public string ResolveVariable(string name) + { + lock (objectMonitor) { - lock (objectMonitor) + if (arguments == null) { - if (arguments == null) - { - InitArguments(); - } - string retValue; - arguments.TryGetValue(name, out retValue); - return retValue; + InitArguments(); } + + string retValue; + arguments.TryGetValue(name, out retValue); + return retValue; } + } - /// - /// Initializes command line arguments dictionary. - /// - protected virtual void InitArguments() + /// + /// Initializes command line arguments dictionary. + /// + protected virtual void InitArguments() + { + this.arguments = new Dictionary(StringComparer.OrdinalIgnoreCase); + + foreach (string arg in commandLineArgs) { - this.arguments = new Dictionary(StringComparer.OrdinalIgnoreCase); - - foreach (string arg in commandLineArgs) + int separatorIndex = arg.IndexOf(valueSeparator); + if (arg.StartsWith(argumentPrefix) && separatorIndex > argumentPrefix.Length) { - int separatorIndex = arg.IndexOf(valueSeparator); - if (arg.StartsWith(argumentPrefix) && separatorIndex > argumentPrefix.Length) - { - string argName = arg.Substring(argumentPrefix.Length, separatorIndex - argumentPrefix.Length); - string argValue = arg.Substring(separatorIndex + valueSeparator.Length); - this.arguments[argName] = argValue; - } + string argName = arg.Substring(argumentPrefix.Length, separatorIndex - argumentPrefix.Length); + string argValue = arg.Substring(separatorIndex + valueSeparator.Length); + this.arguments[argName] = argValue; } } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/ConfigSectionVariableSource.cs b/src/Spring/Spring.Core/Objects/Factory/Config/ConfigSectionVariableSource.cs index 3c0e8a36..cc70d727 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/ConfigSectionVariableSource.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/ConfigSectionVariableSource.cs @@ -22,144 +22,145 @@ using System.Collections.Specialized; using System.Configuration; using Spring.Util; -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Implementation of that +/// resolves variable name against name-value sections in +/// the standard .NET configuration file. +/// +/// Aleksandar Seovic +[Serializable] +public class ConfigSectionVariableSource : IVariableSource { + private string[] sectionNames; + protected NameValueCollection variables; + private readonly object objectMonitor = new object(); + /// - /// Implementation of that - /// resolves variable name against name-value sections in - /// the standard .NET configuration file. + /// Initializes a new instance of /// - /// Aleksandar Seovic - [Serializable] - public class ConfigSectionVariableSource : IVariableSource + public ConfigSectionVariableSource() { - private string[] sectionNames; - protected NameValueCollection variables; - private readonly object objectMonitor = new object(); + } - /// - /// Initializes a new instance of - /// - public ConfigSectionVariableSource() - { - } + /// + /// Initializes a new instance of from the given + /// + public ConfigSectionVariableSource(string sectionName) + { + this.SectionName = sectionName; + } - /// - /// Initializes a new instance of from the given - /// - public ConfigSectionVariableSource(string sectionName) - { - this.SectionName = sectionName; - } + /// + /// Initializes a new instance of from the given + /// + public ConfigSectionVariableSource(string[] sectionNames) + { + this.SectionNames = sectionNames; + } - /// - /// Initializes a new instance of from the given - /// - public ConfigSectionVariableSource(string[] sectionNames) - { - this.SectionNames = sectionNames; - } + /// + /// Gets or sets a list of section names variables should be loaded from. + /// + /// + /// All sections specified need to be handled by the + /// in order to be processed successfully. + /// + /// + /// A list of section names variables should be loaded from. + /// + public string[] SectionNames + { + get { return sectionNames; } + set { sectionNames = value; } + } - /// - /// Gets or sets a list of section names variables should be loaded from. - /// - /// - /// All sections specified need to be handled by the - /// in order to be processed successfully. - /// - /// - /// A list of section names variables should be loaded from. - /// - public string[] SectionNames - { - get { return sectionNames; } - set { sectionNames = value; } - } + /// + /// Convinience property. Gets or sets a single section + /// to read properties from. + /// + /// + /// The section specified needs to be handled by the + /// in order to be processed successfully. + /// + /// + /// A section to read properties from. + /// + public string SectionName + { + set { sectionNames = new string[] { value }; } + } - /// - /// Convinience property. Gets or sets a single section - /// to read properties from. - /// - /// - /// The section specified needs to be handled by the - /// in order to be processed successfully. - /// - /// - /// A section to read properties from. - /// - public string SectionName + /// + /// Before requesting a variable resolution, a client should + /// ask, whether the source can resolve a particular variable name. + /// + /// the name of the variable to resolve + /// true if the variable can be resolved, false otherwise + public bool CanResolveVariable(string name) + { + lock (objectMonitor) { - set { sectionNames = new string[] { value }; } - } - - /// - /// Before requesting a variable resolution, a client should - /// ask, whether the source can resolve a particular variable name. - /// - /// the name of the variable to resolve - /// true if the variable can be resolved, false otherwise - public bool CanResolveVariable(string name) - { - lock (objectMonitor) + if (variables == null) { - if (variables == null) - { - variables = new NameValueCollection(); - InitVariables(); - } - return CollectionUtils.Contains(variables.AllKeys, name); + variables = new NameValueCollection(); + InitVariables(); } - } - /// - /// Resolves variable value for the specified variable name. - /// - /// - /// The name of the variable to resolve. - /// - /// - /// The variable value if able to resolve, null otherwise. - /// - public string ResolveVariable(string name) + return CollectionUtils.Contains(variables.AllKeys, name); + } + } + + /// + /// Resolves variable value for the specified variable name. + /// + /// + /// The name of the variable to resolve. + /// + /// + /// The variable value if able to resolve, null otherwise. + /// + public string ResolveVariable(string name) + { + lock (objectMonitor) { - lock (objectMonitor) + if (variables == null) { - if (variables == null) - { - variables = new NameValueCollection(); - InitVariables(); - } - return variables.Get(name); + variables = new NameValueCollection(); + InitVariables(); } - } - /// - /// Initializes properties based on the specified - /// property file locations. - /// - protected virtual void InitVariables() + return variables.Get(name); + } + } + + /// + /// Initializes properties based on the specified + /// property file locations. + /// + protected virtual void InitVariables() + { + foreach (string sectionName in sectionNames) { - foreach (string sectionName in sectionNames) + object section = ConfigurationUtils.GetSection(sectionName); + if (section is NameValueCollection) { - object section = ConfigurationUtils.GetSection(sectionName); - if (section is NameValueCollection) + variables.Add((NameValueCollection) section); + } + else if (section is ClientSettingsSection) + { + ClientSettingsSection clientSettingsSection = (ClientSettingsSection) section; + foreach (SettingElement setting in clientSettingsSection.Settings) { - variables.Add((NameValueCollection) section); - } - else if (section is ClientSettingsSection) - { - ClientSettingsSection clientSettingsSection = (ClientSettingsSection)section; - foreach (SettingElement setting in clientSettingsSection.Settings) - { - variables.Add(setting.Name, setting.Value.ValueXml.InnerText); - } - } - else - { - throw new ArgumentException("Section [" + sectionName + - "] is not handled by the NameValueSectionHandler."); + variables.Add(setting.Name, setting.Value.ValueXml.InnerText); } } + else + { + throw new ArgumentException("Section [" + sectionName + + "] is not handled by the NameValueSectionHandler."); + } } } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/ConfigurableVariableSource.cs b/src/Spring/Spring.Core/Objects/Factory/Config/ConfigurableVariableSource.cs index fdb4fcb6..79a7dd63 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/ConfigurableVariableSource.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/ConfigurableVariableSource.cs @@ -20,61 +20,60 @@ using System.Collections.Specialized; -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Implementation of that +/// resolves variable name against provided variables. +/// +/// +/// Variable name resolution is case insensitive. +/// +/// Bruno Baia +[Serializable] +public class ConfigurableVariableSource : IVariableSource { + private NameValueCollection _variables; + /// - /// Implementation of that - /// resolves variable name against provided variables. + /// Initializes a new instance of . /// - /// - /// Variable name resolution is case insensitive. - /// - /// Bruno Baia - [Serializable] - public class ConfigurableVariableSource : IVariableSource + public ConfigurableVariableSource() { - private NameValueCollection _variables; + this._variables = new NameValueCollection(); + } - /// - /// Initializes a new instance of . - /// - public ConfigurableVariableSource() - { - this._variables = new NameValueCollection(); - } + /// + /// Gets or sets variables. + /// + public NameValueCollection Variables + { + get { return _variables; } + set { _variables = value; } + } - /// - /// Gets or sets variables. - /// - public NameValueCollection Variables - { - get { return _variables; } - set { _variables = value; } - } + /// + /// Before requesting a variable resolution, a client should + /// ask, whether the source can resolve a particular variable name. + /// + /// the name of the variable to resolve + /// true if the variable can be resolved, false otherwise + public bool CanResolveVariable(string name) + { + return this._variables.Get(name) != null; + } - /// - /// Before requesting a variable resolution, a client should - /// ask, whether the source can resolve a particular variable name. - /// - /// the name of the variable to resolve - /// true if the variable can be resolved, false otherwise - public bool CanResolveVariable(string name) - { - return this._variables.Get(name) != null; - } - - /// - /// Resolves variable value for the specified variable name. - /// - /// - /// The name of the variable to resolve. - /// - /// - /// The variable value if able to resolve, null otherwise. - /// - public string ResolveVariable(string name) - { - return this._variables.Get(name); - } + /// + /// Resolves variable value for the specified variable name. + /// + /// + /// The name of the variable to resolve. + /// + /// + /// The variable value if able to resolve, null otherwise. + /// + public string ResolveVariable(string name) + { + return this._variables.Get(name); } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/ConfigurationReader.cs b/src/Spring/Spring.Core/Objects/Factory/Config/ConfigurationReader.cs index 273bca17..ba0e589b 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/ConfigurationReader.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/ConfigurationReader.cs @@ -29,460 +29,466 @@ using Spring.Core.TypeResolution; using Spring.Util; using ConfigXmlDocument = Spring.Util.ConfigXmlDocument; -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Various utility methods for .NET style .config files. +/// +/// +///

+/// Currently supports reading custom configuration sections and returning them as +/// objects. +///

+///
+/// Simon White +/// Mark Pollack +public sealed class ConfigurationReader { + private const string ConfigSectionTypeAttribute = "type"; + private const string ConfigurationElement = "configuration"; + private const string ConfigSectionsElement = "configSections"; + private const string ConfigSectionGroupElement = "sectionGroup"; + private const string ConfigSectionElement = "section"; + private const string ConfigSectionNameAttribute = "name"; + + private static readonly ILogger _log = LogManager.GetLogger(); + /// - /// Various utility methods for .NET style .config files. + /// Initializes the type members + /// + static ConfigurationReader() + { + } + + /// + /// Reads the specified configuration section into a + /// . + /// + /// The resource to read. + /// The section name. + /// + /// A newly populated + /// . + /// + /// + /// If any errors are encountered while attempting to open a stream + /// from the supplied . + /// + /// + /// If any errors are encountered while loading or reading (this only applies to + /// v1.1 and greater of the .NET Framework) the actual XML. + /// + /// + /// If any errors are encountered while loading or reading (this only applies to + /// v1.0 of the .NET Framework). + /// + /// + /// If the configuration section was otherwise invalid. + /// + public static NameValueCollection Read(IResource resource, string configSection) + { + return ConfigurationReader.Read(resource, configSection, new NameValueCollection()); + } + + /// + /// Reads the specified configuration section into the supplied + /// . + /// + /// The resource to read. + /// The section name. + /// + /// The collection that is to be populated. May be + /// . + /// + /// + /// A newly populated + /// . + /// + /// + /// If any errors are encountered while attempting to open a stream + /// from the supplied . + /// + /// + /// If any errors are encountered while loading or reading (this only applies to + /// v1.1 and greater of the .NET Framework) the actual XML. + /// + /// + /// If any errors are encountered while loading or reading (this only applies to + /// v1.0 of the .NET Framework). + /// + /// + /// If the configuration section was otherwise invalid. + /// + public static NameValueCollection Read( + IResource resource, string configSection, NameValueCollection properties) + { + return ConfigurationReader.Read(resource, configSection, properties, true); + } + + /// + /// Reads the specified configuration section into the supplied + /// . + /// + /// The resource to read. + /// The section name. + /// + /// The collection that is to be populated. May be + /// . + /// + /// + /// If a key already exists, is its value to be appended to the current + /// value or replaced? + /// + /// + /// The populated + /// . + /// + /// + /// If any errors are encountered while attempting to open a stream + /// from the supplied . + /// + /// + /// If any errors are encountered while loading or reading (this only applies to + /// v1.1 and greater of the .NET Framework) the actual XML. + /// + /// + /// If any errors are encountered while loading or reading (this only applies to + /// v1.0 of the .NET Framework). + /// + /// + /// If the configuration section was otherwise invalid. + /// + public static NameValueCollection Read( + IResource resource, string configSection, NameValueCollection properties, bool overrideValues) + { + if (properties == null) + { + properties = new NameValueCollection(); + } + + NameValueCollection newProperties = (NameValueCollection) GetSection(resource, configSection, typeof(NameValueFileSectionHandler)); + if (newProperties != null) + { + PopulateProperties(overrideValues, properties, newProperties); + } + + return properties; + } + + /// + /// Read from the specified configuration from the supplied XML + /// into a + /// . /// /// - ///

- /// Currently supports reading custom configuration sections and returning them as - /// objects. - ///

+ /// + /// Does not support section grouping. The supplied XML + /// must already be loaded. + /// ///
- /// Simon White - /// Mark Pollack - public sealed class ConfigurationReader + /// + /// The to read from. + /// + /// + /// The configuration section name to read. + /// + /// + /// A newly populated + /// . + /// + /// + /// If any errors are encountered while reading (this only applies to + /// v1.1 and greater of the .NET Framework). + /// + /// + /// If any errors are encountered while reading (this only applies to + /// v1.0 of the .NET Framework). + /// + /// + /// If the configuration section was otherwise invalid. + /// + public static NameValueCollection ReadFromXmlDocument(XmlDocument document, + string configSectionName) { - private const string ConfigSectionTypeAttribute = "type"; - private const string ConfigurationElement = "configuration"; - private const string ConfigSectionsElement = "configSections"; - private const string ConfigSectionGroupElement = "sectionGroup"; - private const string ConfigSectionElement = "section"; - private const string ConfigSectionNameAttribute = "name"; + // find the config section declaration (if one exists)... + return (NameValueCollection) GetSectionFromXmlDocument(document, configSectionName); + } - private static readonly ILogger _log = LogManager.GetLogger(); + /// + /// Returns the section from the specified resource with the given section name + /// + public static object GetSection(IResource resource, string configSectionName) + { + return GetSection(resource, configSectionName, null); + } - /// - /// Initializes the type members - /// - static ConfigurationReader() - {} - - /// - /// Reads the specified configuration section into a - /// . - /// - /// The resource to read. - /// The section name. - /// - /// A newly populated - /// . - /// - /// - /// If any errors are encountered while attempting to open a stream - /// from the supplied . - /// - /// - /// If any errors are encountered while loading or reading (this only applies to - /// v1.1 and greater of the .NET Framework) the actual XML. - /// - /// - /// If any errors are encountered while loading or reading (this only applies to - /// v1.0 of the .NET Framework). - /// - /// - /// If the configuration section was otherwise invalid. - /// - public static NameValueCollection Read(IResource resource, string configSection) + /// + /// Returns the section from the specified resource with the given section name. Use + /// in case no section handler is specified. + /// + public static object GetSection(IResource resource, string configSectionName, Type defaultConfigurationSectionHandlerType) + { + using (Stream istm = resource.InputStream) { - return ConfigurationReader.Read(resource, configSection, new NameValueCollection()); + ConfigXmlDocument doc = new ConfigXmlDocument(); + doc.Load(istm); + return GetSectionFromXmlDocument(doc, configSectionName, defaultConfigurationSectionHandlerType); + } + } + + /// + /// Returns the typed section from the specified resource with the given section name + /// + public static TResult GetSection(IResource resource, string configSectionName) + { + return GetSection(resource, configSectionName, null); + } + + /// + /// Returns the section from the specified resource with the given section name. Use + /// in case no section handler is specified. + /// + public static TResult GetSection(IResource resource, string configSectionName, Type defaultConfigurationSectionHandlerType) + { + object result = GetSection(resource, configSectionName, defaultConfigurationSectionHandlerType); + if (result != null && !(result is TResult)) + { + throw new ArgumentException(string.Format("evaluating configuration section {0} does not result in an instance of type {1}", configSectionName, typeof(TResult))); } - /// - /// Reads the specified configuration section into the supplied - /// . - /// - /// The resource to read. - /// The section name. - /// - /// The collection that is to be populated. May be - /// . - /// - /// - /// A newly populated - /// . - /// - /// - /// If any errors are encountered while attempting to open a stream - /// from the supplied . - /// - /// - /// If any errors are encountered while loading or reading (this only applies to - /// v1.1 and greater of the .NET Framework) the actual XML. - /// - /// - /// If any errors are encountered while loading or reading (this only applies to - /// v1.0 of the .NET Framework). - /// - /// - /// If the configuration section was otherwise invalid. - /// - public static NameValueCollection Read( - IResource resource, string configSection, NameValueCollection properties) + return (TResult) result; + } + + /// + /// Returns the typed result of evaluating the specified . + /// + /// if the result's type does not match the expected type + public static TResult GetSectionFromXmlDocument(XmlDocument configDocument, string configSectionName) + { + object result = GetSectionFromXmlDocument(configDocument, configSectionName); + if (result != null && !(result is TResult)) { - return ConfigurationReader.Read(resource, configSection, properties, true); + throw new ArgumentException(string.Format("evaluating configuration sectoin {0} does not result in an instance of type {1}", configSectionName, typeof(TResult))); } - /// - /// Reads the specified configuration section into the supplied - /// . - /// - /// The resource to read. - /// The section name. - /// - /// The collection that is to be populated. May be - /// . - /// - /// - /// If a key already exists, is its value to be appended to the current - /// value or replaced? - /// - /// - /// The populated - /// . - /// - /// - /// If any errors are encountered while attempting to open a stream - /// from the supplied . - /// - /// - /// If any errors are encountered while loading or reading (this only applies to - /// v1.1 and greater of the .NET Framework) the actual XML. - /// - /// - /// If any errors are encountered while loading or reading (this only applies to - /// v1.0 of the .NET Framework). - /// - /// - /// If the configuration section was otherwise invalid. - /// - public static NameValueCollection Read( - IResource resource, string configSection, NameValueCollection properties, bool overrideValues) + return (TResult) result; + } + + /// + /// Reads the specified configuration section from the given + /// + /// + /// + /// + public static object GetSectionFromXmlDocument(XmlDocument document, string configSectionName) + { + return GetSectionFromXmlDocument(document, configSectionName, null); + } + + /// + /// Reads the specified configuration section from the given + /// + /// + /// + /// + /// + public static object GetSectionFromXmlDocument(XmlDocument document, string configSectionName, Type defaultConfigurationSectionHandlerType) + { + Type handlerType = GetSectionHandlerType(document, configSectionName, defaultConfigurationSectionHandlerType); + + // obtain Xml node with section content + XmlNode sectionContent = document.SelectSingleNode(string.Format("//{0}/{1}", ConfigurationElement, configSectionName)); + if (sectionContent == null) { - if (properties == null) - { - properties = new NameValueCollection(); - } - - NameValueCollection newProperties = (NameValueCollection)GetSection(resource, configSection, typeof(NameValueFileSectionHandler)); - if (newProperties != null) - { - PopulateProperties(overrideValues, properties, newProperties); - } - - return properties; + // TODO: review if we shouldn't better simply return null here to match the ConfigurationManager's behaviour? + throw ConfigurationUtils.CreateConfigurationException("Cannot read config section '" + configSectionName + "' - section not found."); } - /// - /// Read from the specified configuration from the supplied XML - /// into a - /// . - /// - /// - /// - /// Does not support section grouping. The supplied XML - /// must already be loaded. - /// - /// - /// - /// The to read from. - /// - /// - /// The configuration section name to read. - /// - /// - /// A newly populated - /// . - /// - /// - /// If any errors are encountered while reading (this only applies to - /// v1.1 and greater of the .NET Framework). - /// - /// - /// If any errors are encountered while reading (this only applies to - /// v1.0 of the .NET Framework). - /// - /// - /// If the configuration section was otherwise invalid. - /// - public static NameValueCollection ReadFromXmlDocument(XmlDocument document, - string configSectionName) + // IConfigurationSectionHandler + if (typeof(IConfigurationSectionHandler).IsAssignableFrom(handlerType)) { - // find the config section declaration (if one exists)... - return (NameValueCollection)GetSectionFromXmlDocument(document, configSectionName); + IConfigurationSectionHandler handler = (IConfigurationSectionHandler) ObjectUtils.InstantiateType(handlerType); + return handler.Create(null, null, sectionContent); } - /// - /// Returns the section from the specified resource with the given section name - /// - public static object GetSection(IResource resource, string configSectionName) + // NET 2.0 ConfigurationSection + if (typeof(ConfigurationSection).IsAssignableFrom(handlerType)) { - return GetSection(resource, configSectionName, null); - } - - /// - /// Returns the section from the specified resource with the given section name. Use - /// in case no section handler is specified. - /// - public static object GetSection(IResource resource, string configSectionName, Type defaultConfigurationSectionHandlerType) - { - using (Stream istm = resource.InputStream) - { - ConfigXmlDocument doc = new ConfigXmlDocument(); - doc.Load(istm); - return GetSectionFromXmlDocument(doc, configSectionName, defaultConfigurationSectionHandlerType); - } - } - - /// - /// Returns the typed section from the specified resource with the given section name - /// - public static TResult GetSection(IResource resource, string configSectionName) - { - return GetSection(resource, configSectionName, null); - } - - /// - /// Returns the section from the specified resource with the given section name. Use - /// in case no section handler is specified. - /// - public static TResult GetSection(IResource resource, string configSectionName, Type defaultConfigurationSectionHandlerType) - { - object result = GetSection(resource, configSectionName, defaultConfigurationSectionHandlerType); - if (result != null && !(result is TResult)) - { - throw new ArgumentException(string.Format("evaluating configuration section {0} does not result in an instance of type {1}", configSectionName, typeof(TResult))); - } - return (TResult) result; - } - - /// - /// Returns the typed result of evaluating the specified . - /// - /// if the result's type does not match the expected type - public static TResult GetSectionFromXmlDocument(XmlDocument configDocument, string configSectionName) - { - object result = GetSectionFromXmlDocument(configDocument, configSectionName); - if (result != null && !(result is TResult)) - { - throw new ArgumentException(string.Format("evaluating configuration sectoin {0} does not result in an instance of type {1}", configSectionName, typeof(TResult))); - } - return (TResult)result; - } - - /// - /// Reads the specified configuration section from the given - /// - /// - /// - /// - public static object GetSectionFromXmlDocument(XmlDocument document, string configSectionName) - { - return GetSectionFromXmlDocument(document, configSectionName, null); - } - - /// - /// Reads the specified configuration section from the given - /// - /// - /// - /// - /// - public static object GetSectionFromXmlDocument(XmlDocument document, string configSectionName, Type defaultConfigurationSectionHandlerType) - { - Type handlerType = GetSectionHandlerType(document, configSectionName, defaultConfigurationSectionHandlerType); - - // obtain Xml node with section content - XmlNode sectionContent = document.SelectSingleNode(string.Format("//{0}/{1}", ConfigurationElement, configSectionName)); - if (sectionContent == null) - { - // TODO: review if we shouldn't better simply return null here to match the ConfigurationManager's behaviour? - throw ConfigurationUtils.CreateConfigurationException("Cannot read config section '" + configSectionName + "' - section not found."); - } - - // IConfigurationSectionHandler - if (typeof(IConfigurationSectionHandler).IsAssignableFrom(handlerType)) - { - IConfigurationSectionHandler handler = (IConfigurationSectionHandler)ObjectUtils.InstantiateType(handlerType); - return handler.Create(null, null, sectionContent); - } - - // NET 2.0 ConfigurationSection - if (typeof(ConfigurationSection).IsAssignableFrom(handlerType)) - { - ConfigurationSection section = CreateConfigurationSection(handlerType, new XmlNodeReader(sectionContent)); - return section; - } - - // Not supported - throw ConfigurationUtils.CreateConfigurationException("Configuration section '" + configSectionName + "' is neither of type IConfigurationSectionHandler nor ConfigurationSection."); - } - - /// - /// Determine the configuration section handler type - /// - private static Type GetSectionHandlerType(XmlDocument document, string configSectionName, Type defaultConfigurationSectionHandlerType) - { - string[] sectionNameParts = configSectionName.Split('/'); - string sectionHandlerPath = string.Format("//{0}/{1}", ConfigurationElement, ConfigSectionsElement); - - if (sectionNameParts.Length > 1) - { - // deal with sectionGroups - for (int i = 0; i < sectionNameParts.Length - 1; i++) - { - sectionHandlerPath = string.Format("{0}/{1}[@{2}='{3}']", sectionHandlerPath, ConfigSectionGroupElement, ConfigSectionNameAttribute, sectionNameParts[i]); - } - } - sectionHandlerPath = string.Format("{0}/{1}[@{2}='{3}']", sectionHandlerPath, ConfigSectionElement, ConfigSectionNameAttribute, sectionNameParts[sectionNameParts.Length - 1]); - - XmlNode xmlConfig = document.SelectSingleNode(sectionHandlerPath); - - // create appropriate configuration section handler... - Type handlerType = null; - if (xmlConfig == null) - { - // none specified, use machine inherited - try - { - XmlDocument machineConfig = new XmlDocument(); - machineConfig.Load(RuntimeEnvironment.SystemConfigurationFile); - xmlConfig = machineConfig.SelectSingleNode(sectionHandlerPath); - if (xmlConfig == null) - { - // TOOD: better throw a sensible exception in case of a missing handler configuration? - handlerType = defaultConfigurationSectionHandlerType; - } - } - catch (PlatformNotSupportedException) - { - if (configSectionName == "connectionStrings") - { - handlerType = typeof(ConnectionStringsSectionHandler); - } - else - { - handlerType = typeof(NameValueSectionHandler); - } - } - } - - if (xmlConfig != null) - { - XmlAttribute xmlConfigType = xmlConfig.Attributes[ConfigSectionTypeAttribute]; - handlerType = TypeResolutionUtils.ResolveType(xmlConfigType.Value); - } - - if (handlerType == null) - { - throw new ConfigurationException(string.Format("missing handler-'type' attribute on configuration section definition for section '{0}'", configSectionName)); - } - return handlerType; - } - - private class ConnectionStringsSectionHandler : IConfigurationSectionHandler - { - public object Create(object parent, object configContext, XmlNode section) - { - var data = new ConnectionStringsSection(); - foreach (XmlNode node in section.ChildNodes) - { - var settings = new ConnectionStringSettings( - node.Attributes["name"].Value, - node.Attributes["connectionString"]?.Value, - node.Attributes["providerName"]?.Value); - data.ConnectionStrings.Add(settings); - } - return data; - } - } - - - private delegate void DeserializeSectionMethod(ConfigurationSection section, XmlReader reader); - private static DeserializeSectionMethod deserialized = (DeserializeSectionMethod)Delegate.CreateDelegate(typeof(DeserializeSectionMethod), - typeof(ConfigurationSection).GetMethod("DeserializeSection", - BindingFlags.Instance | - BindingFlags.NonPublic)); - - private static ConfigurationSection CreateConfigurationSection(Type handlerType, XmlReader reader) - { - ConfigurationSection section = (ConfigurationSection)ObjectUtils.InstantiateType(handlerType); - deserialized(section, reader); + ConfigurationSection section = CreateConfigurationSection(handlerType, new XmlNodeReader(sectionContent)); return section; } - /// - /// Populates the supplied with values from - /// a .NET application configuration file. - /// - /// - /// The - /// to add any key-value pairs to. - /// - /// - /// The configuration section name in the a .NET application configuration - /// file. - /// - /// - /// If a key already exists, is its value to be appended to the current - /// value or replaced? - /// - /// - /// if the supplied - /// was found. - /// - public static bool PopulateFromAppConfig( - NameValueCollection properties, string configSectionName, bool overrideValues) + // Not supported + throw ConfigurationUtils.CreateConfigurationException("Configuration section '" + configSectionName + "' is neither of type IConfigurationSectionHandler nor ConfigurationSection."); + } + + /// + /// Determine the configuration section handler type + /// + private static Type GetSectionHandlerType(XmlDocument document, string configSectionName, Type defaultConfigurationSectionHandlerType) + { + string[] sectionNameParts = configSectionName.Split('/'); + string sectionHandlerPath = string.Format("//{0}/{1}", ConfigurationElement, ConfigSectionsElement); + + if (sectionNameParts.Length > 1) { - bool sectionFound = false; - - NameValueCollection newProperties - = ConfigurationUtils.GetSection(configSectionName) as NameValueCollection; - - if (newProperties != null) + // deal with sectionGroups + for (int i = 0; i < sectionNameParts.Length - 1; i++) { - sectionFound = true; - PopulateProperties(overrideValues, properties, newProperties); + sectionHandlerPath = string.Format("{0}/{1}[@{2}='{3}']", sectionHandlerPath, ConfigSectionGroupElement, ConfigSectionNameAttribute, sectionNameParts[i]); } - return sectionFound; } - private static void PopulateProperties( - bool overrideValues, NameValueCollection properties, NameValueCollection newProperties) + sectionHandlerPath = string.Format("{0}/{1}[@{2}='{3}']", sectionHandlerPath, ConfigSectionElement, ConfigSectionNameAttribute, sectionNameParts[sectionNameParts.Length - 1]); + + XmlNode xmlConfig = document.SelectSingleNode(sectionHandlerPath); + + // create appropriate configuration section handler... + Type handlerType = null; + if (xmlConfig == null) { - if (!overrideValues) + // none specified, use machine inherited + try { - properties.Add(newProperties); - } - else - { - foreach (string key in newProperties.AllKeys) + XmlDocument machineConfig = new XmlDocument(); + machineConfig.Load(RuntimeEnvironment.SystemConfigurationFile); + xmlConfig = machineConfig.SelectSingleNode(sectionHandlerPath); + if (xmlConfig == null) { - properties.Set(key, newProperties.Get(key)); + // TOOD: better throw a sensible exception in case of a missing handler configuration? + handlerType = defaultConfigurationSectionHandlerType; + } + } + catch (PlatformNotSupportedException) + { + if (configSectionName == "connectionStrings") + { + handlerType = typeof(ConnectionStringsSectionHandler); + } + else + { + handlerType = typeof(NameValueSectionHandler); } } } - #region Constructor (s) / Destructor - - // CLOVER:OFF - - /// - /// Creates a new instance of the ConfigurationReader class. - /// - /// - ///

- /// This is a utility class, and as such has no publicly visible - /// constructors. - ///

- ///
- private ConfigurationReader() + if (xmlConfig != null) { + XmlAttribute xmlConfigType = xmlConfig.Attributes[ConfigSectionTypeAttribute]; + handlerType = TypeResolutionUtils.ResolveType(xmlConfigType.Value); } - // CLOVER:ON + if (handlerType == null) + { + throw new ConfigurationException(string.Format("missing handler-'type' attribute on configuration section definition for section '{0}'", configSectionName)); + } - #endregion + return handlerType; } + + private class ConnectionStringsSectionHandler : IConfigurationSectionHandler + { + public object Create(object parent, object configContext, XmlNode section) + { + var data = new ConnectionStringsSection(); + foreach (XmlNode node in section.ChildNodes) + { + var settings = new ConnectionStringSettings( + node.Attributes["name"].Value, + node.Attributes["connectionString"]?.Value, + node.Attributes["providerName"]?.Value); + data.ConnectionStrings.Add(settings); + } + + return data; + } + } + + private delegate void DeserializeSectionMethod(ConfigurationSection section, XmlReader reader); + + private static DeserializeSectionMethod deserialized = (DeserializeSectionMethod) Delegate.CreateDelegate(typeof(DeserializeSectionMethod), + typeof(ConfigurationSection).GetMethod("DeserializeSection", + BindingFlags.Instance | + BindingFlags.NonPublic)); + + private static ConfigurationSection CreateConfigurationSection(Type handlerType, XmlReader reader) + { + ConfigurationSection section = (ConfigurationSection) ObjectUtils.InstantiateType(handlerType); + deserialized(section, reader); + return section; + } + + /// + /// Populates the supplied with values from + /// a .NET application configuration file. + /// + /// + /// The + /// to add any key-value pairs to. + /// + /// + /// The configuration section name in the a .NET application configuration + /// file. + /// + /// + /// If a key already exists, is its value to be appended to the current + /// value or replaced? + /// + /// + /// if the supplied + /// was found. + /// + public static bool PopulateFromAppConfig( + NameValueCollection properties, string configSectionName, bool overrideValues) + { + bool sectionFound = false; + + NameValueCollection newProperties + = ConfigurationUtils.GetSection(configSectionName) as NameValueCollection; + + if (newProperties != null) + { + sectionFound = true; + PopulateProperties(overrideValues, properties, newProperties); + } + + return sectionFound; + } + + private static void PopulateProperties( + bool overrideValues, NameValueCollection properties, NameValueCollection newProperties) + { + if (!overrideValues) + { + properties.Add(newProperties); + } + else + { + foreach (string key in newProperties.AllKeys) + { + properties.Set(key, newProperties.Get(key)); + } + } + } + + #region Constructor (s) / Destructor + + // CLOVER:OFF + + /// + /// Creates a new instance of the ConfigurationReader class. + /// + /// + ///

+ /// This is a utility class, and as such has no publicly visible + /// constructors. + ///

+ ///
+ private ConfigurationReader() + { + } + + // CLOVER:ON + + #endregion } diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/ConnectionStringsVariableSource.cs b/src/Spring/Spring.Core/Objects/Factory/Config/ConnectionStringsVariableSource.cs index 8d514f78..35d1171b 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/ConnectionStringsVariableSource.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/ConnectionStringsVariableSource.cs @@ -19,92 +19,91 @@ #endregion using System.Configuration; - using Spring.Util; -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Implementation of that +/// resolves variable name connection strings defined in +/// the standard .NET configuration file. +/// +/// +///

+/// When the <connectionStrings> configuration section is processed by this class, +/// two variables are defined for each connection string: one for connection string and +/// the second one for the provider name.

+///

+/// Variable names are generated by appending '.connectionString' and '.providerName' +/// literals to the value of the name attribute of the connection string element. +/// For example:

+///
+/// 
+///    
+/// 
+/// 
+///

+/// will result in two variables being created: myConn.connectionString and myConn.providerName. +/// You can reference these variables within your object definitions, just like any other variable.

+///
+/// Aleksandar Seovic +[Serializable] +public class ConnectionStringsVariableSource : IVariableSource { + private Dictionary variables; + /// - /// Implementation of that - /// resolves variable name connection strings defined in - /// the standard .NET configuration file. + /// Before requesting a variable resolution, a client should + /// ask, whether the source can resolve a particular variable name. /// - /// - ///

- /// When the <connectionStrings> configuration section is processed by this class, - /// two variables are defined for each connection string: one for connection string and - /// the second one for the provider name.

- ///

- /// Variable names are generated by appending '.connectionString' and '.providerName' - /// literals to the value of the name attribute of the connection string element. - /// For example:

- ///
-    /// 
-    ///    
-    /// 
-    /// 
- ///

- /// will result in two variables being created: myConn.connectionString and myConn.providerName. - /// You can reference these variables within your object definitions, just like any other variable.

- ///
- /// Aleksandar Seovic - [Serializable] - public class ConnectionStringsVariableSource : IVariableSource + /// the name of the variable to resolve + /// true if the variable can be resolved, false otherwise + public bool CanResolveVariable(string name) { - private Dictionary variables; - - - /// - /// Before requesting a variable resolution, a client should - /// ask, whether the source can resolve a particular variable name. - /// - /// the name of the variable to resolve - /// true if the variable can be resolved, false otherwise - public bool CanResolveVariable(string name) + if (variables == null) { - if (variables == null) - { - InitVariables(); - } - return variables.ContainsKey(name); + InitVariables(); } - /// - /// Resolves variable value for the specified variable name. - /// - /// - /// The name of the variable to resolve. - /// - /// - /// The variable value if able to resolve, null otherwise. - /// - public string ResolveVariable(string name) + return variables.ContainsKey(name); + } + + /// + /// Resolves variable value for the specified variable name. + /// + /// + /// The name of the variable to resolve. + /// + /// + /// The variable value if able to resolve, null otherwise. + /// + public string ResolveVariable(string name) + { + if (variables == null) { - if (variables == null) - { - InitVariables(); - } - string retValue; - variables.TryGetValue(name, out retValue); - return retValue; + InitVariables(); } - /// - /// Initializes properties based on the specified - /// property file locations. - /// - private void InitVariables() - { - variables = new Dictionary(StringComparer.OrdinalIgnoreCase); - ConnectionStringSettingsCollection settings = ConfigurationManager.ConnectionStrings; - foreach (ConnectionStringSettings setting in settings) - { - string providerName = setting.ProviderName; + string retValue; + variables.TryGetValue(name, out retValue); + return retValue; + } - variables.Add(setting.Name + ".connectionString", setting.ConnectionString); - variables.Add(setting.Name + ".providerName", - StringUtils.HasText(providerName) ? providerName : "System.Data.SqlClient"); - } + /// + /// Initializes properties based on the specified + /// property file locations. + /// + private void InitVariables() + { + variables = new Dictionary(StringComparer.OrdinalIgnoreCase); + ConnectionStringSettingsCollection settings = ConfigurationManager.ConnectionStrings; + foreach (ConnectionStringSettings setting in settings) + { + string providerName = setting.ProviderName; + + variables.Add(setting.Name + ".connectionString", setting.ConnectionString); + variables.Add(setting.Name + ".providerName", + StringUtils.HasText(providerName) ? providerName : "System.Data.SqlClient"); } } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/ConstructorArgumentValues.cs b/src/Spring/Spring.Core/Objects/Factory/Config/ConstructorArgumentValues.cs index 6daae6e9..34e858b4 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/ConstructorArgumentValues.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/ConstructorArgumentValues.cs @@ -19,675 +19,682 @@ using System.Globalization; using Spring.Collections; using Spring.Util; -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Holder for constructor argument values for an object. +/// +/// +///

+/// Supports values for a specific index or parameter name (case +/// insensitive) in the constructor argument list, and generic matches by +/// . +///

+///
+/// Juergen Hoeller +/// Rick Evans (.NET) +/// +[Serializable] +public class ConstructorArgumentValues { - /// - /// Holder for constructor argument values for an object. - /// - /// - ///

- /// Supports values for a specific index or parameter name (case - /// insensitive) in the constructor argument list, and generic matches by - /// . - ///

- ///
- /// Juergen Hoeller - /// Rick Evans (.NET) - /// - [Serializable] - public class ConstructorArgumentValues - { - private static readonly CultureInfo enUSCultureInfo = new CultureInfo("en-US", false); + private static readonly CultureInfo enUSCultureInfo = new CultureInfo("en-US", false); - private static readonly IReadOnlyDictionary _emptyIndexedArgumentValues = new Dictionary(); - internal Dictionary _indexedArgumentValues = null; + private static readonly IReadOnlyDictionary _emptyIndexedArgumentValues = new Dictionary(); + internal Dictionary _indexedArgumentValues = null; - private static readonly IReadOnlyList _emptyGenericArgumentValues = new List(); - internal List _genericArgumentValues = null; + private static readonly IReadOnlyList _emptyGenericArgumentValues = new List(); + internal List _genericArgumentValues = null; - private static readonly IReadOnlyDictionary _emptyNamedArgumentValues = new Dictionary(); - internal Dictionary _namedArgumentValues = null; + private static readonly IReadOnlyDictionary _emptyNamedArgumentValues = new Dictionary(); + internal Dictionary _namedArgumentValues = null; - /// - /// Can be used as an argument filler for the - /// - /// overload when one is not looking for an argument by index. - /// - public const int NoIndex = -1289; // yes, the number really is wholly arbitrary... + /// + /// Can be used as an argument filler for the + /// + /// overload when one is not looking for an argument by index. + /// + public const int NoIndex = -1289; // yes, the number really is wholly arbitrary... - /// - /// Creates a new instance of the - /// - /// class. - /// - public ConstructorArgumentValues() - { - } + /// + /// Creates a new instance of the + /// + /// class. + /// + public ConstructorArgumentValues() + { + } - /// - /// Creates a new instance of the - /// - /// class. - /// - /// - /// The - /// to be used to populate this instance. - /// - public ConstructorArgumentValues(ConstructorArgumentValues other) - { - AddAll(other); - } + /// + /// Creates a new instance of the + /// + /// class. + /// + /// + /// The + /// to be used to populate this instance. + /// + public ConstructorArgumentValues(ConstructorArgumentValues other) + { + AddAll(other); + } - /// - /// Return the map of indexed argument values. - /// - /// - /// An with - /// indices as keys and - /// s - /// as values. - /// - public IReadOnlyDictionary IndexedArgumentValues - => _indexedArgumentValues ?? _emptyIndexedArgumentValues; + /// + /// Return the map of indexed argument values. + /// + /// + /// An with + /// indices as keys and + /// s + /// as values. + /// + public IReadOnlyDictionary IndexedArgumentValues + => _indexedArgumentValues ?? _emptyIndexedArgumentValues; - /// - /// Return the map of named argument values. - /// - /// - /// An with - /// named arguments as keys and - /// s - /// as values. - /// - public IReadOnlyDictionary NamedArgumentValues => _namedArgumentValues ?? _emptyNamedArgumentValues; + /// + /// Return the map of named argument values. + /// + /// + /// An with + /// named arguments as keys and + /// s + /// as values. + /// + public IReadOnlyDictionary NamedArgumentValues => _namedArgumentValues ?? _emptyNamedArgumentValues; - /// - /// Return the set of generic argument values. - /// - /// - /// A of - /// s. - /// - public IReadOnlyList GenericArgumentValues => _genericArgumentValues ?? _emptyGenericArgumentValues; + /// + /// Return the set of generic argument values. + /// + /// + /// A of + /// s. + /// + public IReadOnlyList GenericArgumentValues => _genericArgumentValues ?? _emptyGenericArgumentValues; - /// - /// Return the number of arguments held in this instance. - /// - public int ArgumentCount - { - get - { - int count = 0; - if (_indexedArgumentValues != null) - { - count += _indexedArgumentValues.Count; - } - if (_genericArgumentValues != null) - { - count += _genericArgumentValues.Count; - } - if (_namedArgumentValues != null) - { - count += _namedArgumentValues.Count; - } - - return count; - } - } - - /// - /// Returns true if this holder does not contain any argument values, - /// neither indexed ones nor generic ones. - /// - public bool Empty - { - get - { - if (_indexedArgumentValues != null && _indexedArgumentValues.Count > 0) - { - return false; - } - if (_genericArgumentValues != null && _genericArgumentValues.Count > 0) - { - return false; - } - if (_namedArgumentValues != null && _namedArgumentValues.Count > 0) - { - return false; - } - - return true; - } - } - - /// - /// Copy all given argument values into this object. - /// - /// - /// The - /// to be used to populate this instance. - /// - public void AddAll(ConstructorArgumentValues other) - { - if (other != null) - { - if (other._genericArgumentValues != null && other._genericArgumentValues.Count > 0) - { - GetAndInitializeGenericArgumentValuesIfNeeded().AddRange(other._genericArgumentValues); - } - - if (other._indexedArgumentValues != null && other._indexedArgumentValues.Count > 0) - { - foreach (var entry in other._indexedArgumentValues) - { - ValueHolder vh = entry.Value; - if (vh != null) - { - AddOrMergeIndexedArgumentValues(entry.Key, vh.Copy()); - } - } - } - - if (other._namedArgumentValues != null && other._namedArgumentValues.Count > 0) - { - foreach (var entry in other._namedArgumentValues) - { - AddOrMergeNamedArgumentValues(entry.Key, entry.Value); - //NamedArgumentValues.Add(entry.Key, entry.Value); - } - } - } - } - - private void AddOrMergeNamedArgumentValues(string key, ValueHolder newValue) - { - var namedArgumentValues = GetAndInitializeNamedArgumentValuesIfNeeded(); - namedArgumentValues[key] = newValue; - } - - private void AddOrMergeIndexedArgumentValues(int key, ValueHolder newValue) - { - var dictionary = GetAndInitializeIndexedArgumentValuesIfNeeded(); - - if (newValue.Value is IMergable mergable - && dictionary.TryGetValue(key, out var currentValue)) + /// + /// Return the number of arguments held in this instance. + /// + public int ArgumentCount + { + get + { + int count = 0; + if (_indexedArgumentValues != null) { - if (mergable.MergeEnabled) + count += _indexedArgumentValues.Count; + } + + if (_genericArgumentValues != null) + { + count += _genericArgumentValues.Count; + } + + if (_namedArgumentValues != null) + { + count += _namedArgumentValues.Count; + } + + return count; + } + } + + /// + /// Returns true if this holder does not contain any argument values, + /// neither indexed ones nor generic ones. + /// + public bool Empty + { + get + { + if (_indexedArgumentValues != null && _indexedArgumentValues.Count > 0) + { + return false; + } + + if (_genericArgumentValues != null && _genericArgumentValues.Count > 0) + { + return false; + } + + if (_namedArgumentValues != null && _namedArgumentValues.Count > 0) + { + return false; + } + + return true; + } + } + + /// + /// Copy all given argument values into this object. + /// + /// + /// The + /// to be used to populate this instance. + /// + public void AddAll(ConstructorArgumentValues other) + { + if (other != null) + { + if (other._genericArgumentValues != null && other._genericArgumentValues.Count > 0) + { + GetAndInitializeGenericArgumentValuesIfNeeded().AddRange(other._genericArgumentValues); + } + + if (other._indexedArgumentValues != null && other._indexedArgumentValues.Count > 0) + { + foreach (var entry in other._indexedArgumentValues) { - newValue.Value = mergable.Merge(currentValue.Value); + ValueHolder vh = entry.Value; + if (vh != null) + { + AddOrMergeIndexedArgumentValues(entry.Key, vh.Copy()); + } } } - dictionary[key] = newValue; - } - /// - /// Add argument value for the given index in the constructor argument list. - /// - /// - /// The index in the constructor argument list. - /// - /// - /// The argument value. - /// - public void AddIndexedArgumentValue(int index, object value) - { - GetAndInitializeIndexedArgumentValuesIfNeeded()[index] = new ValueHolder(value); - } - - /// - /// Add argument value for the given index in the constructor argument list. - /// - /// The index in the constructor argument list. - /// The argument value. - /// - /// The of the argument - /// . - /// - public void AddIndexedArgumentValue(int index, object value, string type) - { - GetAndInitializeIndexedArgumentValuesIfNeeded()[index] = new ValueHolder(value, type); - } - - /// - /// Add argument value for the given name in the constructor argument list. - /// - /// The name in the constructor argument list. - /// The argument value. - /// - /// If the supplied is - /// or is composed wholly of whitespace. - /// - public void AddNamedArgumentValue(string name, object value) - { - AssertUtils.ArgumentHasText(name, "name"); - GetAndInitializeNamedArgumentValuesIfNeeded()[GetCanonicalNamedArgument(name)] = new ValueHolder(value); - } - - /// - /// Get argument value for the given index in the constructor argument list. - /// - /// The index in the constructor argument list. - /// - /// The required of the argument. - /// - /// - /// The - /// - /// for the argument, or if none set. - /// - public ValueHolder GetIndexedArgumentValue(int index, Type requiredType) - { - ValueHolder valueHolder; - if (IndexedArgumentValues.TryGetValue(index, out valueHolder)) - { - if (valueHolder.Type == null - || requiredType.FullName.Equals(valueHolder.Type) - || requiredType.AssemblyQualifiedName.Equals(valueHolder.Type)) - { - return valueHolder; - } - } - return null; - } - - /// - /// Get argument value for the given name in the constructor argument list. - /// - /// The name in the constructor argument list. - /// - /// The - /// - /// for the argument, or if none set. - /// - public ValueHolder GetNamedArgumentValue(string name) - { - ValueHolder valueHolder = null; - if (name != null && ContainsNamedArgument(name)) - { - valueHolder = GetAndInitializeNamedArgumentValuesIfNeeded()[GetCanonicalNamedArgument(name)]; - } - - return valueHolder; - } - - /// - /// Does this set of constructor arguments contain a named argument matching the - /// supplied name? - /// - /// - /// - /// The comparison is performed in a case-insensitive fashion. - /// - /// - /// The named argument to look up. - /// - /// if this set of constructor arguments - /// contains a named argument matching the supplied - /// name. - /// - public bool ContainsNamedArgument(string argument) - { - return _namedArgumentValues != null && _namedArgumentValues.ContainsKey(GetCanonicalNamedArgument(argument)); - } - - /// - /// Add generic argument value to be matched by type. - /// - /// - /// The argument value. - /// - public void AddGenericArgumentValue(object value) - { - GetAndInitializeGenericArgumentValuesIfNeeded().Add(new ValueHolder(value)); - } - - /// - /// Add generic argument value to be matched by type. - /// - /// The argument value. - /// - /// The of the argument - /// . - /// - public void AddGenericArgumentValue(object value, string type) - { - GetAndInitializeGenericArgumentValuesIfNeeded().Add(new ValueHolder(value, type)); - } - - /// - /// Look for a generic argument value that matches the given - /// . - /// - /// - /// The to match. - /// - /// - /// The - /// - /// for the argument, or if none set. - /// - public ValueHolder GetGenericArgumentValue(Type requiredType) - { - return GetGenericArgumentValue(requiredType, null); - } - - /// - /// Look for a generic argument value that matches the given - /// . - /// - /// - /// The to match. - /// - /// - /// A of - /// - /// objects that have already been used in the current resolution - /// process and should therefore not be returned again; this allows one - /// to return the next generic argument match in the case of multiple - /// generic argument values of the same type. - /// - /// - /// The - /// - /// for the argument, or if none set. - /// - public ValueHolder GetGenericArgumentValue( - Type requiredType, - ISet usedValues) - { - if (_genericArgumentValues == null) - { - return null; - } - - for (var i = 0; i < _genericArgumentValues.Count; i++) - { - ValueHolder valueHolder = _genericArgumentValues[i]; - if (usedValues == null || !usedValues.Contains(valueHolder)) - { - if (requiredType != null) - { - if (StringUtils.HasText(valueHolder.Type)) - { - if (valueHolder.Type.Equals(requiredType.FullName) - || valueHolder.Type.Equals(requiredType.AssemblyQualifiedName)) - { - return valueHolder; - } - } - else if (requiredType.IsInstanceOfType(valueHolder.Value) - || (requiredType.IsArray - && valueHolder.Value is IList)) - { - return valueHolder; - } - } - // if the value holder is (pretty much) untyped, that's ok to return... - else if (StringUtils.IsNullOrEmpty(valueHolder.Type)) - { - return valueHolder; - } - } - } - - return null; - } - - /// - /// Look for an argument value that either corresponds to the given index - /// in the constructor argument list or generically matches by - /// . - /// - /// - /// The index in the constructor argument list. - /// - /// - /// The to match. - /// - /// - /// The - /// - /// for the argument, or if none is set. - /// - public ValueHolder GetArgumentValue(int index, Type requiredType) - { - return GetArgumentValue(index, string.Empty, requiredType, null); - } - - /// - /// Look for an argument value that either corresponds to the given index - /// in the constructor argument list or generically matches by - /// . - /// - /// - /// The index in the constructor argument list. - /// - /// - /// The to match. - /// - /// - /// A of - /// - /// objects that have already been used in the current resolution - /// process and should therefore not be returned again; this allows one - /// to return the next generic argument match in the case of multiple - /// generic argument values of the same type. - /// - /// - /// The - /// - /// for the argument, or if none is set. - /// - public ValueHolder GetArgumentValue(int index, Type requiredType, ISet usedValues) - { - return GetArgumentValue(index, string.Empty, requiredType, usedValues); - } - - /// - /// Look for an argument value that either corresponds to the given index - /// in the constructor argument list or generically matches by - /// . - /// - /// - /// The name of the argument in the constructor argument list. May be - /// , in which case generic matching by - /// is assumed. - /// - /// - /// The to match. - /// - /// - /// The - /// - /// for the argument, or if none is set. - /// - public ValueHolder GetArgumentValue(string name, Type requiredType) - { - return GetArgumentValue(NoIndex, name, requiredType, null); - } - - /// - /// Look for an argument value that either corresponds to the given index - /// in the constructor argument list or generically matches by - /// . - /// - /// - /// The name of the argument in the constructor argument list. May be - /// , in which case generic matching by - /// is assumed. - /// - /// - /// The to match. - /// - /// - /// A of - /// - /// objects that have already been used in the current resolution - /// process and should therefore not be returned again; this allows one - /// to return the next generic argument match in the case of multiple - /// generic argument values of the same type. - /// - /// - /// The - /// - /// for the argument, or if none is set. - /// - public ValueHolder GetArgumentValue( - string name, Type requiredType, ISet usedValues) - { - return GetArgumentValue(NoIndex, name, requiredType, usedValues); - } - - /// - /// Look for an argument value that either corresponds to the given index - /// in the constructor argument list, or to the named argument, or - /// generically matches by . - /// - /// - /// The index of the argument in the constructor argument list. May be - /// negative, to denote the fact that we are not looking for an - /// argument by index (see - /// . - /// - /// - /// The name of the argument in the constructor argument list. May be - /// . - /// - /// - /// The to match. - /// - /// - /// A of - /// - /// objects that have already been used in the current resolution - /// process and should therefore not be returned again; this allows one - /// to return the next generic argument match in the case of multiple - /// generic argument values of the same type. - /// - /// - /// The - /// - /// for the argument, or if none is set. - /// - public ValueHolder GetArgumentValue( - int index, string name, Type requiredType, ISet usedValues) - { - ValueHolder valueHolder = null; - if(index != NoIndex) - { - valueHolder = GetIndexedArgumentValue(index, requiredType); - } - if (valueHolder == null) - { - valueHolder = GetNamedArgumentValue(name); - if (valueHolder == null) - { - valueHolder = GetGenericArgumentValue(requiredType, usedValues); - } - } - return valueHolder; - } - - private string GetCanonicalNamedArgument(string argument) - { - return argument != null ? argument.ToLower(enUSCultureInfo) : argument; - } - - private Dictionary GetAndInitializeIndexedArgumentValuesIfNeeded() - { - return _indexedArgumentValues = _indexedArgumentValues ?? new Dictionary(); - } - - private Dictionary GetAndInitializeNamedArgumentValuesIfNeeded() - { - return _namedArgumentValues = _namedArgumentValues ?? new Dictionary(); - } - - private List GetAndInitializeGenericArgumentValuesIfNeeded() - { - return _genericArgumentValues = _genericArgumentValues ?? new List(); - } - - /// - /// Holder for a constructor argument value, with an optional - /// attribute indicating the target - /// of the actual constructor argument. - /// - [Serializable] - public class ValueHolder - { - private object _ctorValue; - private readonly string typeName; - - /// - /// Creates a new instance of the ValueHolder class. - /// - /// - /// The value of the constructor argument. - /// - internal ValueHolder(object value) - { - Value = value; - } - - /// - /// Creates a new instance of the ValueHolder class. - /// - /// - /// The value of the constructor argument. - /// - /// - /// The of the argument - /// . Can also be one of the common - /// aliases (int, bool, - /// float, etc). - /// - internal ValueHolder(object value, string typeName) - { - Value = value; - this.typeName = typeName; - } - - public ValueHolder Copy() + if (other._namedArgumentValues != null && other._namedArgumentValues.Count > 0) { - ValueHolder copy = new ValueHolder(_ctorValue, typeName); - return copy; + foreach (var entry in other._namedArgumentValues) + { + AddOrMergeNamedArgumentValues(entry.Key, entry.Value); + //NamedArgumentValues.Add(entry.Key, entry.Value); + } } + } + } - /// - /// A that represents the current - /// . - /// - /// - /// A that represents the current - /// . - /// - public override string ToString() - { - return string.Format(CultureInfo.InvariantCulture, - "'{0}' [{1}]", Value, Type); - } + private void AddOrMergeNamedArgumentValues(string key, ValueHolder newValue) + { + var namedArgumentValues = GetAndInitializeNamedArgumentValuesIfNeeded(); + namedArgumentValues[key] = newValue; + } - /// - /// Gets and sets the value for the constructor argument. - /// - /// - ///

- /// Only necessary for manipulating a registered value, for example in - /// s. - ///

- ///
- public object Value - { - get => _ctorValue; - set => _ctorValue = value; - } + private void AddOrMergeIndexedArgumentValues(int key, ValueHolder newValue) + { + var dictionary = GetAndInitializeIndexedArgumentValuesIfNeeded(); - /// - /// Return the of the constructor - /// argument. - /// - public string Type => typeName; - } - } + if (newValue.Value is IMergable mergable + && dictionary.TryGetValue(key, out var currentValue)) + { + if (mergable.MergeEnabled) + { + newValue.Value = mergable.Merge(currentValue.Value); + } + } + + dictionary[key] = newValue; + } + + /// + /// Add argument value for the given index in the constructor argument list. + /// + /// + /// The index in the constructor argument list. + /// + /// + /// The argument value. + /// + public void AddIndexedArgumentValue(int index, object value) + { + GetAndInitializeIndexedArgumentValuesIfNeeded()[index] = new ValueHolder(value); + } + + /// + /// Add argument value for the given index in the constructor argument list. + /// + /// The index in the constructor argument list. + /// The argument value. + /// + /// The of the argument + /// . + /// + public void AddIndexedArgumentValue(int index, object value, string type) + { + GetAndInitializeIndexedArgumentValuesIfNeeded()[index] = new ValueHolder(value, type); + } + + /// + /// Add argument value for the given name in the constructor argument list. + /// + /// The name in the constructor argument list. + /// The argument value. + /// + /// If the supplied is + /// or is composed wholly of whitespace. + /// + public void AddNamedArgumentValue(string name, object value) + { + AssertUtils.ArgumentHasText(name, "name"); + GetAndInitializeNamedArgumentValuesIfNeeded()[GetCanonicalNamedArgument(name)] = new ValueHolder(value); + } + + /// + /// Get argument value for the given index in the constructor argument list. + /// + /// The index in the constructor argument list. + /// + /// The required of the argument. + /// + /// + /// The + /// + /// for the argument, or if none set. + /// + public ValueHolder GetIndexedArgumentValue(int index, Type requiredType) + { + ValueHolder valueHolder; + if (IndexedArgumentValues.TryGetValue(index, out valueHolder)) + { + if (valueHolder.Type == null + || requiredType.FullName.Equals(valueHolder.Type) + || requiredType.AssemblyQualifiedName.Equals(valueHolder.Type)) + { + return valueHolder; + } + } + + return null; + } + + /// + /// Get argument value for the given name in the constructor argument list. + /// + /// The name in the constructor argument list. + /// + /// The + /// + /// for the argument, or if none set. + /// + public ValueHolder GetNamedArgumentValue(string name) + { + ValueHolder valueHolder = null; + if (name != null && ContainsNamedArgument(name)) + { + valueHolder = GetAndInitializeNamedArgumentValuesIfNeeded()[GetCanonicalNamedArgument(name)]; + } + + return valueHolder; + } + + /// + /// Does this set of constructor arguments contain a named argument matching the + /// supplied name? + /// + /// + /// + /// The comparison is performed in a case-insensitive fashion. + /// + /// + /// The named argument to look up. + /// + /// if this set of constructor arguments + /// contains a named argument matching the supplied + /// name. + /// + public bool ContainsNamedArgument(string argument) + { + return _namedArgumentValues != null && _namedArgumentValues.ContainsKey(GetCanonicalNamedArgument(argument)); + } + + /// + /// Add generic argument value to be matched by type. + /// + /// + /// The argument value. + /// + public void AddGenericArgumentValue(object value) + { + GetAndInitializeGenericArgumentValuesIfNeeded().Add(new ValueHolder(value)); + } + + /// + /// Add generic argument value to be matched by type. + /// + /// The argument value. + /// + /// The of the argument + /// . + /// + public void AddGenericArgumentValue(object value, string type) + { + GetAndInitializeGenericArgumentValuesIfNeeded().Add(new ValueHolder(value, type)); + } + + /// + /// Look for a generic argument value that matches the given + /// . + /// + /// + /// The to match. + /// + /// + /// The + /// + /// for the argument, or if none set. + /// + public ValueHolder GetGenericArgumentValue(Type requiredType) + { + return GetGenericArgumentValue(requiredType, null); + } + + /// + /// Look for a generic argument value that matches the given + /// . + /// + /// + /// The to match. + /// + /// + /// A of + /// + /// objects that have already been used in the current resolution + /// process and should therefore not be returned again; this allows one + /// to return the next generic argument match in the case of multiple + /// generic argument values of the same type. + /// + /// + /// The + /// + /// for the argument, or if none set. + /// + public ValueHolder GetGenericArgumentValue( + Type requiredType, + ISet usedValues) + { + if (_genericArgumentValues == null) + { + return null; + } + + for (var i = 0; i < _genericArgumentValues.Count; i++) + { + ValueHolder valueHolder = _genericArgumentValues[i]; + if (usedValues == null || !usedValues.Contains(valueHolder)) + { + if (requiredType != null) + { + if (StringUtils.HasText(valueHolder.Type)) + { + if (valueHolder.Type.Equals(requiredType.FullName) + || valueHolder.Type.Equals(requiredType.AssemblyQualifiedName)) + { + return valueHolder; + } + } + else if (requiredType.IsInstanceOfType(valueHolder.Value) + || (requiredType.IsArray + && valueHolder.Value is IList)) + { + return valueHolder; + } + } + // if the value holder is (pretty much) untyped, that's ok to return... + else if (StringUtils.IsNullOrEmpty(valueHolder.Type)) + { + return valueHolder; + } + } + } + + return null; + } + + /// + /// Look for an argument value that either corresponds to the given index + /// in the constructor argument list or generically matches by + /// . + /// + /// + /// The index in the constructor argument list. + /// + /// + /// The to match. + /// + /// + /// The + /// + /// for the argument, or if none is set. + /// + public ValueHolder GetArgumentValue(int index, Type requiredType) + { + return GetArgumentValue(index, string.Empty, requiredType, null); + } + + /// + /// Look for an argument value that either corresponds to the given index + /// in the constructor argument list or generically matches by + /// . + /// + /// + /// The index in the constructor argument list. + /// + /// + /// The to match. + /// + /// + /// A of + /// + /// objects that have already been used in the current resolution + /// process and should therefore not be returned again; this allows one + /// to return the next generic argument match in the case of multiple + /// generic argument values of the same type. + /// + /// + /// The + /// + /// for the argument, or if none is set. + /// + public ValueHolder GetArgumentValue(int index, Type requiredType, ISet usedValues) + { + return GetArgumentValue(index, string.Empty, requiredType, usedValues); + } + + /// + /// Look for an argument value that either corresponds to the given index + /// in the constructor argument list or generically matches by + /// . + /// + /// + /// The name of the argument in the constructor argument list. May be + /// , in which case generic matching by + /// is assumed. + /// + /// + /// The to match. + /// + /// + /// The + /// + /// for the argument, or if none is set. + /// + public ValueHolder GetArgumentValue(string name, Type requiredType) + { + return GetArgumentValue(NoIndex, name, requiredType, null); + } + + /// + /// Look for an argument value that either corresponds to the given index + /// in the constructor argument list or generically matches by + /// . + /// + /// + /// The name of the argument in the constructor argument list. May be + /// , in which case generic matching by + /// is assumed. + /// + /// + /// The to match. + /// + /// + /// A of + /// + /// objects that have already been used in the current resolution + /// process and should therefore not be returned again; this allows one + /// to return the next generic argument match in the case of multiple + /// generic argument values of the same type. + /// + /// + /// The + /// + /// for the argument, or if none is set. + /// + public ValueHolder GetArgumentValue( + string name, Type requiredType, ISet usedValues) + { + return GetArgumentValue(NoIndex, name, requiredType, usedValues); + } + + /// + /// Look for an argument value that either corresponds to the given index + /// in the constructor argument list, or to the named argument, or + /// generically matches by . + /// + /// + /// The index of the argument in the constructor argument list. May be + /// negative, to denote the fact that we are not looking for an + /// argument by index (see + /// . + /// + /// + /// The name of the argument in the constructor argument list. May be + /// . + /// + /// + /// The to match. + /// + /// + /// A of + /// + /// objects that have already been used in the current resolution + /// process and should therefore not be returned again; this allows one + /// to return the next generic argument match in the case of multiple + /// generic argument values of the same type. + /// + /// + /// The + /// + /// for the argument, or if none is set. + /// + public ValueHolder GetArgumentValue( + int index, string name, Type requiredType, ISet usedValues) + { + ValueHolder valueHolder = null; + if (index != NoIndex) + { + valueHolder = GetIndexedArgumentValue(index, requiredType); + } + + if (valueHolder == null) + { + valueHolder = GetNamedArgumentValue(name); + if (valueHolder == null) + { + valueHolder = GetGenericArgumentValue(requiredType, usedValues); + } + } + + return valueHolder; + } + + private string GetCanonicalNamedArgument(string argument) + { + return argument != null ? argument.ToLower(enUSCultureInfo) : argument; + } + + private Dictionary GetAndInitializeIndexedArgumentValuesIfNeeded() + { + return _indexedArgumentValues = _indexedArgumentValues ?? new Dictionary(); + } + + private Dictionary GetAndInitializeNamedArgumentValuesIfNeeded() + { + return _namedArgumentValues = _namedArgumentValues ?? new Dictionary(); + } + + private List GetAndInitializeGenericArgumentValuesIfNeeded() + { + return _genericArgumentValues = _genericArgumentValues ?? new List(); + } + + /// + /// Holder for a constructor argument value, with an optional + /// attribute indicating the target + /// of the actual constructor argument. + /// + [Serializable] + public class ValueHolder + { + private object _ctorValue; + private readonly string typeName; + + /// + /// Creates a new instance of the ValueHolder class. + /// + /// + /// The value of the constructor argument. + /// + internal ValueHolder(object value) + { + Value = value; + } + + /// + /// Creates a new instance of the ValueHolder class. + /// + /// + /// The value of the constructor argument. + /// + /// + /// The of the argument + /// . Can also be one of the common + /// aliases (int, bool, + /// float, etc). + /// + internal ValueHolder(object value, string typeName) + { + Value = value; + this.typeName = typeName; + } + + public ValueHolder Copy() + { + ValueHolder copy = new ValueHolder(_ctorValue, typeName); + return copy; + } + + /// + /// A that represents the current + /// . + /// + /// + /// A that represents the current + /// . + /// + public override string ToString() + { + return string.Format(CultureInfo.InvariantCulture, + "'{0}' [{1}]", Value, Type); + } + + /// + /// Gets and sets the value for the constructor argument. + /// + /// + ///

+ /// Only necessary for manipulating a registered value, for example in + /// s. + ///

+ ///
+ public object Value + { + get => _ctorValue; + set => _ctorValue = value; + } + + /// + /// Return the of the constructor + /// argument. + /// + public string Type => typeName; + } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/CustomConverterConfigurer.cs b/src/Spring/Spring.Core/Objects/Factory/Config/CustomConverterConfigurer.cs index 997b188c..130103d5 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/CustomConverterConfigurer.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/CustomConverterConfigurer.cs @@ -21,276 +21,275 @@ using System.Collections; using System.ComponentModel; -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// +/// implementation that allows for convenient registration of custom +/// s. +/// +/// +/// +/// The use of this class is typically not required; the .NET +/// mechanism of associating a +/// with a +/// via the use of the +/// is the +/// recommended (and standard) way. This class primarily exists to cover +/// those cases where third party classes to which one does not have the +/// source need to be exposed to the type conversion mechanism. +/// +///

+/// Because the +/// +/// class implements the +/// +/// interface, instances of this class that have been exposed in the +/// scope of an +/// will +/// automatically be picked up by the application context and made +/// available to the IoC container whenever type conversion is required. If +/// one is using a +/// +/// object definition within the scope of an +/// , no such automatic +/// pickup of the +/// +/// is performed (custom converters will have to be added manually using the +/// +/// method). For most application scenarios, one will get better +/// mileage using the +/// abstraction. +///

+///
+/// +///

+/// The following examples all assume XML based configuration, and use +/// inner object definitions to define the custom +/// objects (nominally to +/// avoid polluting the object name space, but also because the +/// configuration simply reads better that way). +///

+/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +///

+/// The following example illustrates a complete (albeit naieve) use case +/// for this class, including a custom +/// implementation, said +/// converters domain class, and the XML configuration that hooks the +/// converter in place and makes it available to a Spring.NET container for +/// use during object resolution. +///

+///

+/// The domain class is a simple data-only object that contains the data +/// required to send an email message (such as the host and user account +/// name). A developer would prefer to use a string of the form +/// UserName=administrator,Password=r1l0k1l3y,Host=localhost to +/// configure the mail settings and just let the container take care of the +/// conversion. +///

+/// +/// namespace ExampleNamespace +/// { +/// public sealed class MailSettings +/// { +/// private string _userName; +/// private string _password; +/// private string _host; +/// +/// public string Host +/// { +/// get { return _host; } +/// set { _host = value; } +/// } +/// +/// public string UserName +/// { +/// get { return _userName; } +/// set { _userName = value; } +/// } +/// +/// public string Password +/// { +/// get { return _password; } +/// set { _password = value; } +/// } +/// } +/// +/// public sealed class MailSettingsConverter : TypeConverter +/// { +/// public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) +/// { +/// if (typeof (string) == sourceType) +/// { +/// return true; +/// } +/// return base.CanConvertFrom(context, sourceType); +/// } +/// +/// public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) +/// { +/// string text = value as string; +/// if(text != null) +/// { +/// MailSettings mailSettings = new MailSettings(); +/// string[] tokens = text.Split(','); +/// for (int i = 0; i < tokens.Length; ++i) +/// { +/// string token = tokens[i]; +/// string[] settings = token.Split('='); +/// typeof(MailSettings).GetProperty(settings[0]) +/// .SetValue(mailSettings, settings[1], null); +/// } +/// return mailSettings; +/// } +/// return base.ConvertFrom(context, culture, value); +/// } +/// } +/// +/// // a very naieve class that uses the MailSettings class... +/// public sealed class ExceptionLogger +/// { +/// private MailSettings _mailSettings; +/// +/// public MailSettings MailSettings { +/// { +/// set { _mailSettings = value; } +/// } +/// +/// public void Log(object value) +/// { +/// Exception ex = value as Exception; +/// if(ex != null) +/// { +/// // use _mailSettings instance... +/// } +/// } +/// } +/// } +/// +///

+/// The attendant XML configuration for the above classes would be... +///

+/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// Juergen Hoeller +/// Simon White (.NET) +/// +/// +/// +[Serializable] +public class CustomConverterConfigurer : AbstractConfigurer { - /// - /// - /// implementation that allows for convenient registration of custom - /// s. - /// - /// - /// - /// The use of this class is typically not required; the .NET - /// mechanism of associating a - /// with a - /// via the use of the - /// is the - /// recommended (and standard) way. This class primarily exists to cover - /// those cases where third party classes to which one does not have the - /// source need to be exposed to the type conversion mechanism. - /// - ///

- /// Because the - /// - /// class implements the - /// - /// interface, instances of this class that have been exposed in the - /// scope of an - /// will - /// automatically be picked up by the application context and made - /// available to the IoC container whenever type conversion is required. If - /// one is using a - /// - /// object definition within the scope of an - /// , no such automatic - /// pickup of the - /// - /// is performed (custom converters will have to be added manually using the - /// - /// method). For most application scenarios, one will get better - /// mileage using the - /// abstraction. - ///

- ///
- /// - ///

- /// The following examples all assume XML based configuration, and use - /// inner object definitions to define the custom - /// objects (nominally to - /// avoid polluting the object name space, but also because the - /// configuration simply reads better that way). - ///

- /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - ///

- /// The following example illustrates a complete (albeit naieve) use case - /// for this class, including a custom - /// implementation, said - /// converters domain class, and the XML configuration that hooks the - /// converter in place and makes it available to a Spring.NET container for - /// use during object resolution. - ///

- ///

- /// The domain class is a simple data-only object that contains the data - /// required to send an email message (such as the host and user account - /// name). A developer would prefer to use a string of the form - /// UserName=administrator,Password=r1l0k1l3y,Host=localhost to - /// configure the mail settings and just let the container take care of the - /// conversion. - ///

- /// - /// namespace ExampleNamespace - /// { - /// public sealed class MailSettings - /// { - /// private string _userName; - /// private string _password; - /// private string _host; - /// - /// public string Host - /// { - /// get { return _host; } - /// set { _host = value; } - /// } - /// - /// public string UserName - /// { - /// get { return _userName; } - /// set { _userName = value; } - /// } - /// - /// public string Password - /// { - /// get { return _password; } - /// set { _password = value; } - /// } - /// } - /// - /// public sealed class MailSettingsConverter : TypeConverter - /// { - /// public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) - /// { - /// if (typeof (string) == sourceType) - /// { - /// return true; - /// } - /// return base.CanConvertFrom(context, sourceType); - /// } - /// - /// public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) - /// { - /// string text = value as string; - /// if(text != null) - /// { - /// MailSettings mailSettings = new MailSettings(); - /// string[] tokens = text.Split(','); - /// for (int i = 0; i < tokens.Length; ++i) - /// { - /// string token = tokens[i]; - /// string[] settings = token.Split('='); - /// typeof(MailSettings).GetProperty(settings[0]) - /// .SetValue(mailSettings, settings[1], null); - /// } - /// return mailSettings; - /// } - /// return base.ConvertFrom(context, culture, value); - /// } - /// } - /// - /// // a very naieve class that uses the MailSettings class... - /// public sealed class ExceptionLogger - /// { - /// private MailSettings _mailSettings; - /// - /// public MailSettings MailSettings { - /// { - /// set { _mailSettings = value; } - /// } - /// - /// public void Log(object value) - /// { - /// Exception ex = value as Exception; - /// if(ex != null) - /// { - /// // use _mailSettings instance... - /// } - /// } - /// } - /// } - /// - ///

- /// The attendant XML configuration for the above classes would be... - ///

- /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// Juergen Hoeller - /// Simon White (.NET) - /// - /// - /// - [Serializable] - public class CustomConverterConfigurer : AbstractConfigurer - { - private IDictionary _customConverters; + private IDictionary _customConverters; - /// - /// The custom converters to register. - /// - /// - ///

- /// The uses the type name - /// of the class that requires conversion as the key, and an - /// instance of the - /// that will effect - /// the conversion. Alternatively, the actual - /// of the class that requires conversion - /// can be used as the key. - ///

- ///
- /// - ///

- /// - /// IDictionary converters = new Hashtable(); - /// converters.Add( "System.Date", new MyCustomDateConverter() ); - /// // a System.Type instance can also be used as the key... - /// converters.Add( typeof(Color), new MyCustomRBGColorConverter() ); - /// - ///

- ///
- public IDictionary CustomConverters - { - set { this._customConverters = value; } - } + /// + /// The custom converters to register. + /// + /// + ///

+ /// The uses the type name + /// of the class that requires conversion as the key, and an + /// instance of the + /// that will effect + /// the conversion. Alternatively, the actual + /// of the class that requires conversion + /// can be used as the key. + ///

+ ///
+ /// + ///

+ /// + /// IDictionary converters = new Hashtable(); + /// converters.Add( "System.Date", new MyCustomDateConverter() ); + /// // a System.Type instance can also be used as the key... + /// converters.Add( typeof(Color), new MyCustomRBGColorConverter() ); + /// + ///

+ ///
+ public IDictionary CustomConverters + { + set { this._customConverters = value; } + } - /// - /// Registers any custom converters with the supplied - /// . - /// - /// - /// The object factory to register the converters with. - /// - /// - /// In case of errors. - /// - public override void PostProcessObjectFactory( - IConfigurableListableObjectFactory factory) - { - if (_customConverters != null) - { - foreach (DictionaryEntry entry in _customConverters) - { - Type requiredType = ResolveRequiredType(entry.Key, "key", "custom type converter"); - TypeConverter converter = ResolveConverter(entry.Value); - factory.RegisterCustomConverter(requiredType, converter); - } - } - } + /// + /// Registers any custom converters with the supplied + /// . + /// + /// + /// The object factory to register the converters with. + /// + /// + /// In case of errors. + /// + public override void PostProcessObjectFactory( + IConfigurableListableObjectFactory factory) + { + if (_customConverters != null) + { + foreach (DictionaryEntry entry in _customConverters) + { + Type requiredType = ResolveRequiredType(entry.Key, "key", "custom type converter"); + TypeConverter converter = ResolveConverter(entry.Value); + factory.RegisterCustomConverter(requiredType, converter); + } + } + } - /// - /// Resolves the supplied into a - /// instance. - /// - /// - /// The object that is to be resolved into a - /// instance. - /// - /// - /// A resolved instance. - /// - /// - /// If the supplied is , - /// or the supplied cannot be resolved. - /// - protected virtual TypeConverter ResolveConverter(object value) - { - TypeConverter converter = value as TypeConverter; - if (converter == null) - { - throw new ObjectInitializationException( - "Mapped value for custom converter is not a " + - "[System.ComponentModel.TypeConverter] instance."); - } - return converter; - } + /// + /// Resolves the supplied into a + /// instance. + /// + /// + /// The object that is to be resolved into a + /// instance. + /// + /// + /// A resolved instance. + /// + /// + /// If the supplied is , + /// or the supplied cannot be resolved. + /// + protected virtual TypeConverter ResolveConverter(object value) + { + TypeConverter converter = value as TypeConverter; + if (converter == null) + { + throw new ObjectInitializationException( + "Mapped value for custom converter is not a " + + "[System.ComponentModel.TypeConverter] instance."); + } - } -} + return converter; + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/DelegateFactoryObject.cs b/src/Spring/Spring.Core/Objects/Factory/Config/DelegateFactoryObject.cs index b9f73780..17313e51 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/DelegateFactoryObject.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/DelegateFactoryObject.cs @@ -20,154 +20,159 @@ using Spring.Util; -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// implementation that +/// creates delegates. +/// +/// +///

+/// Supports the creation of s for both +/// instance and methods. +///

+///
+/// Rick Evans +[Serializable] +public class DelegateFactoryObject : AbstractFactoryObject { - /// - /// implementation that - /// creates delegates. - /// - /// - ///

- /// Supports the creation of s for both - /// instance and methods. - ///

- ///
- /// Rick Evans - [Serializable] - public class DelegateFactoryObject : AbstractFactoryObject - { - /// - /// Callback method called once all factory properties have been set. - /// - /// - /// In the event of misconfiguration (such as failure to set an essential - /// property) or if initialization fails. - /// - /// - public override void AfterPropertiesSet() - { - if (DelegateType == null) - { - throw new ArgumentException( - "The 'DelegateType' property is required."); - } - if (!typeof (Delegate).IsAssignableFrom(DelegateType)) - { - throw new ArgumentException( - "The 'DelegateType' property must (obviously) be a Type derived from [System.Delegate]."); - } - if (TargetType == null && TargetObject == null) - { - throw new ArgumentException( - "Exactly one of either the 'TargetType' or 'TargetObject' properties is required."); - } - if (TargetType != null && TargetObject != null) - { - throw new ArgumentException( - "Exactly one of either the 'TargetType' or 'TargetObject' properties is required (not both)."); - } - if (StringUtils.IsNullOrEmpty(MethodName)) - { - throw new ArgumentException( - "The 'MethodName' property is required."); - } - base.AfterPropertiesSet(); - } + /// + /// Callback method called once all factory properties have been set. + /// + /// + /// In the event of misconfiguration (such as failure to set an essential + /// property) or if initialization fails. + /// + /// + public override void AfterPropertiesSet() + { + if (DelegateType == null) + { + throw new ArgumentException( + "The 'DelegateType' property is required."); + } - /// - /// Creates the delegate. - /// - /// - /// If an exception occured during object creation. - /// - /// The object returned by this factory. - /// - protected override object CreateInstance() - { - Delegate instance = null; - if (TargetType != null) - { - instance = Delegate.CreateDelegate(DelegateType, TargetType, MethodName); - } - else - { - instance = Delegate.CreateDelegate(DelegateType, TargetObject, MethodName); - } - return instance; - } + if (!typeof(Delegate).IsAssignableFrom(DelegateType)) + { + throw new ArgumentException( + "The 'DelegateType' property must (obviously) be a Type derived from [System.Delegate]."); + } - #region Properties + if (TargetType == null && TargetObject == null) + { + throw new ArgumentException( + "Exactly one of either the 'TargetType' or 'TargetObject' properties is required."); + } - /// - /// The of - /// created by this factory. - /// - /// - ///

- /// Returns the - /// if accessed prior to the method - /// being called. - ///

- ///
- public override Type ObjectType - { - get - { - return (DelegateType != null) - ? DelegateType - : typeof (Delegate); - } - } + if (TargetType != null && TargetObject != null) + { + throw new ArgumentException( + "Exactly one of either the 'TargetType' or 'TargetObject' properties is required (not both)."); + } - /// - /// The of the - /// created by this factory. - /// - public Type DelegateType - { - get { return _delegateType; } - set { _delegateType = value; } - } + if (StringUtils.IsNullOrEmpty(MethodName)) + { + throw new ArgumentException( + "The 'MethodName' property is required."); + } - /// - /// The name of the method that is to be invoked by the created - /// delegate. - /// - public string MethodName - { - get { return _methodName; } - set { _methodName = value; } - } + base.AfterPropertiesSet(); + } - /// - /// The target if the - /// refers to a method. - /// - public Type TargetType - { - get { return _targetType; } - set { _targetType = value; } - } + /// + /// Creates the delegate. + /// + /// + /// If an exception occured during object creation. + /// + /// The object returned by this factory. + /// + protected override object CreateInstance() + { + Delegate instance = null; + if (TargetType != null) + { + instance = Delegate.CreateDelegate(DelegateType, TargetType, MethodName); + } + else + { + instance = Delegate.CreateDelegate(DelegateType, TargetObject, MethodName); + } - /// - /// The target object if the - /// refers to an instance method. - /// - public object TargetObject - { - get { return _targetObject; } - set { _targetObject = value; } - } + return instance; + } - #endregion + #region Properties - #region Fields + /// + /// The of + /// created by this factory. + /// + /// + ///

+ /// Returns the + /// if accessed prior to the method + /// being called. + ///

+ ///
+ public override Type ObjectType + { + get + { + return (DelegateType != null) + ? DelegateType + : typeof(Delegate); + } + } - private Type _delegateType; - private string _methodName; - private Type _targetType; - private object _targetObject; + /// + /// The of the + /// created by this factory. + /// + public Type DelegateType + { + get { return _delegateType; } + set { _delegateType = value; } + } - #endregion - } + /// + /// The name of the method that is to be invoked by the created + /// delegate. + /// + public string MethodName + { + get { return _methodName; } + set { _methodName = value; } + } + + /// + /// The target if the + /// refers to a method. + /// + public Type TargetType + { + get { return _targetType; } + set { _targetType = value; } + } + + /// + /// The target object if the + /// refers to an instance method. + /// + public object TargetObject + { + get { return _targetObject; } + set { _targetObject = value; } + } + + #endregion + + #region Fields + + private Type _delegateType; + private string _methodName; + private Type _targetType; + private object _targetObject; + + #endregion } diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/DelegateObjectFactoryConfigurer.cs b/src/Spring/Spring.Core/Objects/Factory/Config/DelegateObjectFactoryConfigurer.cs index 49367630..4762912f 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/DelegateObjectFactoryConfigurer.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/DelegateObjectFactoryConfigurer.cs @@ -1,72 +1,72 @@ #region License -/* - * Copyright 2002-2010 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. +/* + * Copyright 2002-2010 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 -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// A generic implementation of an , that delegates post processing to a passed delegate +/// +/// +/// This comes in handy when you want to perform specific tasks on an object factory, e.g. doing special initialization. +/// +/// +/// The example below is taken from a unit test. The snippet causes 'someObject' to be registered each time is called on +/// the context instance: +/// +/// IConfigurableApplicationContext ctx = new XmlApplicationContext(false, "name", false, null); +/// ctx.AddObjectFactoryPostProcessor(new DelegateObjectFactoryConfigurer( of => +/// { +/// of.RegisterSingleton("someObject", someObject); +/// })); +/// +/// +/// Erich Eichinger +public class DelegateObjectFactoryConfigurer : IObjectFactoryPostProcessor { + public delegate void ObjectFactoryConfigurationHandler(IConfigurableListableObjectFactory objectFactory); + + private ObjectFactoryConfigurationHandler _configurationHandler; + /// - /// A generic implementation of an , that delegates post processing to a passed delegate + /// Get or Set the handler to delegate configuration to /// - /// - /// This comes in handy when you want to perform specific tasks on an object factory, e.g. doing special initialization. - /// - /// - /// The example below is taken from a unit test. The snippet causes 'someObject' to be registered each time is called on - /// the context instance: - /// - /// IConfigurableApplicationContext ctx = new XmlApplicationContext(false, "name", false, null); - /// ctx.AddObjectFactoryPostProcessor(new DelegateObjectFactoryConfigurer( of => - /// { - /// of.RegisterSingleton("someObject", someObject); - /// })); - /// - /// - /// Erich Eichinger - public class DelegateObjectFactoryConfigurer : IObjectFactoryPostProcessor + public ObjectFactoryConfigurationHandler ConfigurationHandler { - public delegate void ObjectFactoryConfigurationHandler(IConfigurableListableObjectFactory objectFactory); + get { return _configurationHandler; } + set { _configurationHandler = value; } + } - private ObjectFactoryConfigurationHandler _configurationHandler; + public DelegateObjectFactoryConfigurer() + { + } - /// - /// Get or Set the handler to delegate configuration to - /// - public ObjectFactoryConfigurationHandler ConfigurationHandler + public DelegateObjectFactoryConfigurer(ObjectFactoryConfigurationHandler configurationHandler) + { + _configurationHandler = configurationHandler; + } + + public void PostProcessObjectFactory(IConfigurableListableObjectFactory factory) + { + if (_configurationHandler != null) { - get { return _configurationHandler; } - set { _configurationHandler = value; } - } - - public DelegateObjectFactoryConfigurer() - { } - - public DelegateObjectFactoryConfigurer(ObjectFactoryConfigurationHandler configurationHandler) - { - _configurationHandler = configurationHandler; - } - - public void PostProcessObjectFactory(IConfigurableListableObjectFactory factory) - { - if (_configurationHandler != null) - { - _configurationHandler(factory); - } + _configurationHandler(factory); } } -} \ No newline at end of file +} diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/DependencyDescriptor.cs b/src/Spring/Spring.Core/Objects/Factory/Config/DependencyDescriptor.cs index 401596eb..af0f7885 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/DependencyDescriptor.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/DependencyDescriptor.cs @@ -21,185 +21,182 @@ using Spring.Core; using System.Reflection; -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Descriptor for a specific dependency that is about to be injected. +/// Wraps a constructor parameter, a method parameter or a field, +/// allowing unified access to their metadata. +/// +/// Juergen Hoeller +/// Mark Pollack +public class DependencyDescriptor { + private MethodParameter methodParameter; + + private PropertyInfo property; + + private FieldInfo field; + + private readonly bool required; + + private readonly bool eager; + /// - /// Descriptor for a specific dependency that is about to be injected. - /// Wraps a constructor parameter, a method parameter or a field, - /// allowing unified access to their metadata. + /// Initializes a new instance of the class for a method or constructor parameter. + /// Considers the dependency as 'eager' /// - /// Juergen Hoeller - /// Mark Pollack - public class DependencyDescriptor + /// The MethodParameter to wrap. + /// if set to true if the dependency is required. + public DependencyDescriptor(MethodParameter methodParameter, bool required) + : this(methodParameter, required, true) { - private MethodParameter methodParameter; + } - private PropertyInfo property; + /// + /// Initializes a new instance of the class for a method or a constructor parameter. + /// + /// The MethodParameter to wrap. + /// if set to true the dependency is required. + /// if set to true the dependency is 'eager' in the sense of + /// eagerly resolving potential target objects for type matching. + public DependencyDescriptor(MethodParameter methodParameter, bool required, bool eager) + { + this.methodParameter = methodParameter; + this.required = required; + this.eager = eager; + } - private FieldInfo field; + /// + /// Create a new descriptor for a property. + /// Considers the dependency as 'eager'. + /// property to wrap + /// required whether the dependency is required + /// + public DependencyDescriptor(PropertyInfo property, bool required) + : this(property, required, true) + { + } - private readonly bool required; + /// + /// Create a new descriptor for a property. + /// property to wrap + /// whether the dependency is required + /// whether this dependency is 'eager' in the sense of + /// eagerly resolving potential target beans for type matching + /// + public DependencyDescriptor(PropertyInfo property, bool required, bool eager) + { + this.property = property; + this.required = required; + this.eager = eager; + } - private readonly bool eager; + /// + /// Create a new descriptor for a field. + /// Considers the dependency as 'eager'. + /// field to wrap + /// whether the dependency is required + /// + public DependencyDescriptor(FieldInfo field, bool required) + : this(field, required, true) + { + } + /// + /// Create a new descriptor for a field. + /// field to wrap + /// whether the dependency is required + /// whether this dependency is 'eager' in the sense of + /// eagerly resolving potential target beans for type matching + /// + public DependencyDescriptor(FieldInfo field, bool required, bool eager) + { + this.field = field; + this.required = required; + this.eager = eager; + } - /// - /// Initializes a new instance of the class for a method or constructor parameter. - /// Considers the dependency as 'eager' - /// - /// The MethodParameter to wrap. - /// if set to true if the dependency is required. - public DependencyDescriptor(MethodParameter methodParameter, bool required) - : this(methodParameter, required, true) + /// + /// Gets a value indicating whether this dependency is required. + /// + /// true if required; otherwise, false. + public bool Required + { + get { return required; } + } + + /// + /// Determine the declared (non-generic) type of the wrapped parameter/field. + /// + /// The type of the dependency (never null + public Type DependencyType + { + get { + if (methodParameter != null) + return methodParameter.ParameterType; + if (property != null) + return property.PropertyType; + if (field != null) + return field.FieldType; + + return null; } + } - /// - /// Initializes a new instance of the class for a method or a constructor parameter. - /// - /// The MethodParameter to wrap. - /// if set to true the dependency is required. - /// if set to true the dependency is 'eager' in the sense of - /// eagerly resolving potential target objects for type matching. - public DependencyDescriptor(MethodParameter methodParameter, bool required, bool eager) + /// + /// Gets a value indicating whether this is eager in the sense of + /// eagerly resolving potential target beans for type matching. + /// + /// true if eager; otherwise, false. + public bool Eager + { + get { return this.eager; } + } + + /// + /// Gets the wrapped MethodParameter, if any. + /// + /// The method parameter. + public MethodParameter MethodParameter + { + get { return methodParameter; } + } + + /// + /// Gets the Attributes assigned to Field, Property or Paramater + /// + public Attribute[] Attributes + { + get { - this.methodParameter = methodParameter; - this.required = required; - this.eager = eager; + if (methodParameter != null) + return methodParameter.ParameterAttributes; + if (property != null) + return Attribute.GetCustomAttributes(property); + if (field != null) + return Attribute.GetCustomAttributes(field); + + return new Attribute[0]; } + } - /// - /// Create a new descriptor for a property. - /// Considers the dependency as 'eager'. - /// property to wrap - /// required whether the dependency is required - /// - public DependencyDescriptor(PropertyInfo property, bool required) - : this(property, required, true) + /// + /// Gets the name of the member info + /// + public string DependencyName + { + get { - } + if (methodParameter != null) + return methodParameter.ParameterName(); + if (property != null) + return property.Name; + if (field != null) + return field.Name; - /// - /// Create a new descriptor for a property. - /// property to wrap - /// whether the dependency is required - /// whether this dependency is 'eager' in the sense of - /// eagerly resolving potential target beans for type matching - /// - public DependencyDescriptor(PropertyInfo property, bool required, bool eager) - { - this.property = property; - this.required = required; - this.eager = eager; - } - - /// - /// Create a new descriptor for a field. - /// Considers the dependency as 'eager'. - /// field to wrap - /// whether the dependency is required - /// - public DependencyDescriptor(FieldInfo field, bool required) - : this(field, required, true) - { - } - - /// - /// Create a new descriptor for a field. - /// field to wrap - /// whether the dependency is required - /// whether this dependency is 'eager' in the sense of - /// eagerly resolving potential target beans for type matching - /// - public DependencyDescriptor(FieldInfo field, bool required, bool eager) - { - this.field = field; - this.required = required; - this.eager = eager; - } - - /// - /// Gets a value indicating whether this dependency is required. - /// - /// true if required; otherwise, false. - public bool Required - { - get { return required; } - } - - /// - /// Determine the declared (non-generic) type of the wrapped parameter/field. - /// - /// The type of the dependency (never null - public Type DependencyType - { - get - { - if (methodParameter != null) - return methodParameter.ParameterType; - if (property != null) - return property.PropertyType; - if (field != null) - return field.FieldType; - - return null; - } - } - - /// - /// Gets a value indicating whether this is eager in the sense of - /// eagerly resolving potential target beans for type matching. - /// - /// true if eager; otherwise, false. - public bool Eager - { - get { return this.eager; } - } - - - /// - /// Gets the wrapped MethodParameter, if any. - /// - /// The method parameter. - public MethodParameter MethodParameter - { - get { return methodParameter; } - } - - /// - /// Gets the Attributes assigned to Field, Property or Paramater - /// - public Attribute[] Attributes - { - get - { - if (methodParameter != null) - return methodParameter.ParameterAttributes; - if (property != null) - return Attribute.GetCustomAttributes(property); - if (field != null) - return Attribute.GetCustomAttributes(field); - - return new Attribute[0]; - } - } - - /// - /// Gets the name of the member info - /// - public string DependencyName - { - get - { - if (methodParameter != null) - return methodParameter.ParameterName(); - if (property != null) - return property.Name; - if (field != null) - return field.Name; - - return ""; - } + return ""; } } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/DictionaryFactoryObject.cs b/src/Spring/Spring.Core/Objects/Factory/Config/DictionaryFactoryObject.cs index bd69d6e1..31987e00 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/DictionaryFactoryObject.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/DictionaryFactoryObject.cs @@ -20,111 +20,114 @@ using System.Collections; using System.Globalization; - using Spring.Util; -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Simple factory for shared instances. +/// +/// Juergen Hoeller +/// Simon White (.NET) +[Serializable] +public class DictionaryFactoryObject : AbstractFactoryObject { - /// - /// Simple factory for shared instances. - /// - /// Juergen Hoeller - /// Simon White (.NET) - [Serializable] - public class DictionaryFactoryObject : AbstractFactoryObject - { - private IDictionary _sourceDictionary; - private Type _targetDictionaryType = typeof (Hashtable); + private IDictionary _sourceDictionary; + private Type _targetDictionaryType = typeof(Hashtable); - /// - /// Set the source . - /// - /// - ///

- /// This value will be used to populate the - /// returned by this factory. - ///

- ///
- public IDictionary SourceDictionary - { - set { this._sourceDictionary = value; } - } + /// + /// Set the source . + /// + /// + ///

+ /// This value will be used to populate the + /// returned by this factory. + ///

+ ///
+ public IDictionary SourceDictionary + { + set { this._sourceDictionary = value; } + } - /// - /// Set the of the - /// implementation to use. - /// - /// - ///

- /// The default is the . - ///

- ///
- /// - /// If the value is . - /// - /// - /// If the value is an . - /// - /// - /// If the value is an interface. - /// - public Type TargetDictionaryType - { - set - { - AssertUtils.ArgumentNotNull(value, "value"); - if (!typeof (IDictionary).IsAssignableFrom(value)) - { - throw new ArgumentException( - string.Format(CultureInfo.InvariantCulture, - "The Type passed to the TargetDictionaryType property must implement the '{0}' interface.", - ObjectType.FullName)); - } - if (value.IsInterface) - { - throw new ArgumentException( - string.Format(CultureInfo.InvariantCulture, - "The Type passed to the TargetDictionaryType property cannot be an interface; it must be a concrete class that implements the '{0}' interface.", - ObjectType.FullName)); - } - if (value.IsAbstract) - { - throw new ArgumentException( - string.Format(CultureInfo.InvariantCulture, - "The Type passed to the TargetDictionaryType property cannot be abstract (MustInherit in VisualBasic.NET); it must be a concrete class that implements the '{0}' interface.", - ObjectType.FullName)); - } - this._targetDictionaryType = value; - } - } + /// + /// Set the of the + /// implementation to use. + /// + /// + ///

+ /// The default is the . + ///

+ ///
+ /// + /// If the value is . + /// + /// + /// If the value is an . + /// + /// + /// If the value is an interface. + /// + public Type TargetDictionaryType + { + set + { + AssertUtils.ArgumentNotNull(value, "value"); + if (!typeof(IDictionary).IsAssignableFrom(value)) + { + throw new ArgumentException( + string.Format(CultureInfo.InvariantCulture, + "The Type passed to the TargetDictionaryType property must implement the '{0}' interface.", + ObjectType.FullName)); + } - /// - /// The of objects created by this factory. - /// - /// - /// Always returns the . - /// - public override Type ObjectType - { - get { return typeof (IDictionary); } - } + if (value.IsInterface) + { + throw new ArgumentException( + string.Format(CultureInfo.InvariantCulture, + "The Type passed to the TargetDictionaryType property cannot be an interface; it must be a concrete class that implements the '{0}' interface.", + ObjectType.FullName)); + } - /// - /// Constructs a new instance of the target dictionary. - /// - /// The new instance. - protected override object CreateInstance() - { - if (this._sourceDictionary == null) - { - throw new ArgumentException("The 'SourceDictionary' property cannot be null (Nothing in Visual Basic.NET)."); - } - IDictionary result = (IDictionary) ObjectUtils.InstantiateType(this._targetDictionaryType); - foreach (DictionaryEntry de in _sourceDictionary) - { - result[de.Key] = de.Value; - } - return result; - } - } + if (value.IsAbstract) + { + throw new ArgumentException( + string.Format(CultureInfo.InvariantCulture, + "The Type passed to the TargetDictionaryType property cannot be abstract (MustInherit in VisualBasic.NET); it must be a concrete class that implements the '{0}' interface.", + ObjectType.FullName)); + } + + this._targetDictionaryType = value; + } + } + + /// + /// The of objects created by this factory. + /// + /// + /// Always returns the . + /// + public override Type ObjectType + { + get { return typeof(IDictionary); } + } + + /// + /// Constructs a new instance of the target dictionary. + /// + /// The new instance. + protected override object CreateInstance() + { + if (this._sourceDictionary == null) + { + throw new ArgumentException("The 'SourceDictionary' property cannot be null (Nothing in Visual Basic.NET)."); + } + + IDictionary result = (IDictionary) ObjectUtils.InstantiateType(this._targetDictionaryType); + foreach (DictionaryEntry de in _sourceDictionary) + { + result[de.Key] = de.Value; + } + + return result; + } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/DictionaryVariableSource.cs b/src/Spring/Spring.Core/Objects/Factory/Config/DictionaryVariableSource.cs index e72395b3..e817002c 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/DictionaryVariableSource.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/DictionaryVariableSource.cs @@ -20,140 +20,138 @@ using System.Collections; -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// A very simple, hashtable-based implementation of +/// +/// Erich Eichinger +public class DictionaryVariableSource : IVariableSource, IEnumerable> { + private readonly Dictionary variables; + /// - /// A very simple, hashtable-based implementation of + /// Creates a new, empty variable source /// - /// Erich Eichinger - public class DictionaryVariableSource : IVariableSource, IEnumerable> + public DictionaryVariableSource() + : this(null, true) { - private readonly Dictionary variables; + } - /// - /// Creates a new, empty variable source - /// - public DictionaryVariableSource() - : this(null, true) - { - } + /// + /// Creates a new, empty and case-insensitive variable source + /// + public DictionaryVariableSource(bool ignoreCase) + : this(null, ignoreCase) + { + } - /// - /// Creates a new, empty and case-insensitive variable source - /// - public DictionaryVariableSource(bool ignoreCase) - : this(null, ignoreCase) + /// + /// Create a new variable source from a list of paired string values. + /// + /// + /// + /// The example below shows, how the dictionary is filled with { 'key1', 'value1' }, { 'key2', 'value2' } pairs: + /// + /// new DictionaryVariableSource( new string[] { "key1", "value1", "key2", "value2" } ) + /// + /// + /// + /// the argument list containing pairs, or null + public DictionaryVariableSource(params string[] args) + : this(true) + { + if (args != null) { - } - - /// - /// Create a new variable source from a list of paired string values. - /// - /// - /// - /// The example below shows, how the dictionary is filled with { 'key1', 'value1' }, { 'key2', 'value2' } pairs: - /// - /// new DictionaryVariableSource( new string[] { "key1", "value1", "key2", "value2" } ) - /// - /// - /// - /// the argument list containing pairs, or null - public DictionaryVariableSource(params string[] args) - : this(true) - { - if (args != null) + if (args.Length % 2 != 0) { - if (args.Length % 2 != 0) - { - throw new ArgumentOutOfRangeException("Unbalanced Key-Value pairs of strings detected. Verify that args contains pairs of key strings and value strings."); - } - - for (int i = 0; i < args.Length; i += 2) - { - Add(args[i], args[i + 1]); - } - - } - } - - /// - /// Initializes a new instance of the DictionaryVariableSource class. - /// - public DictionaryVariableSource(IDictionary dictionary) - : this(dictionary, true) - { - } - - - /// - /// Creates a new variable source, reading values from another dictionary - /// and converting them to strings if necessary - /// - public DictionaryVariableSource(IDictionary dictionary, bool ignoreCase) - { - if (ignoreCase) - { - variables = new Dictionary(StringComparer.OrdinalIgnoreCase); - } - else - { - variables = new Dictionary(); + throw new ArgumentOutOfRangeException("Unbalanced Key-Value pairs of strings detected. Verify that args contains pairs of key strings and value strings."); } - if (dictionary != null) + for (int i = 0; i < args.Length; i += 2) { - foreach (DictionaryEntry entry in dictionary) - { - string key = "" + entry.Key; - string value = entry.Value != null ? "" + entry.Value : null; - - variables[key] = value; - } + Add(args[i], args[i + 1]); } } - - /// - /// Adds a key/value pair - /// - /// this dictionary. allows for fluent config - public DictionaryVariableSource Add(string key, string value) - { - variables.Add(key, value); - return this; - } - - /// - /// Before requesting a variable resolution, a client should - /// ask, whether the source can resolve a particular variable name. - /// - /// the name of the variable to resolve - /// true if the variable can be resolved, false otherwise - public bool CanResolveVariable(string name) - { - return variables.ContainsKey(name); - } - - /// - /// Performs a variable name lookup - /// - public string ResolveVariable(string name) - { - string value; - if (!variables.TryGetValue(name, out value)) - { - throw new ArgumentException(string.Format("variable '{0}' cannot be resolved", name)); - } - return value; - } - - IEnumerator> IEnumerable>.GetEnumerator() - { - return variables.GetEnumerator(); - } - - public IEnumerator GetEnumerator() - { - return variables.GetEnumerator(); - } + } + + /// + /// Initializes a new instance of the DictionaryVariableSource class. + /// + public DictionaryVariableSource(IDictionary dictionary) + : this(dictionary, true) + { + } + + /// + /// Creates a new variable source, reading values from another dictionary + /// and converting them to strings if necessary + /// + public DictionaryVariableSource(IDictionary dictionary, bool ignoreCase) + { + if (ignoreCase) + { + variables = new Dictionary(StringComparer.OrdinalIgnoreCase); + } + else + { + variables = new Dictionary(); + } + + if (dictionary != null) + { + foreach (DictionaryEntry entry in dictionary) + { + string key = "" + entry.Key; + string value = entry.Value != null ? "" + entry.Value : null; + + variables[key] = value; + } + } + } + + /// + /// Adds a key/value pair + /// + /// this dictionary. allows for fluent config + public DictionaryVariableSource Add(string key, string value) + { + variables.Add(key, value); + return this; + } + + /// + /// Before requesting a variable resolution, a client should + /// ask, whether the source can resolve a particular variable name. + /// + /// the name of the variable to resolve + /// true if the variable can be resolved, false otherwise + public bool CanResolveVariable(string name) + { + return variables.ContainsKey(name); + } + + /// + /// Performs a variable name lookup + /// + public string ResolveVariable(string name) + { + string value; + if (!variables.TryGetValue(name, out value)) + { + throw new ArgumentException(string.Format("variable '{0}' cannot be resolved", name)); + } + + return value; + } + + IEnumerator> IEnumerable>.GetEnumerator() + { + return variables.GetEnumerator(); + } + + public IEnumerator GetEnumerator() + { + return variables.GetEnumerator(); } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/EnvironmentVariableMode.cs b/src/Spring/Spring.Core/Objects/Factory/Config/EnvironmentVariableMode.cs index 273ed405..41ecc999 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/EnvironmentVariableMode.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/EnvironmentVariableMode.cs @@ -18,32 +18,31 @@ #endregion -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Specifies how instances of the +/// +/// class must apply environment variables when replacing values. +/// +/// Mark Pollack +[Serializable] +public enum EnvironmentVariableMode { - /// - /// Specifies how instances of the - /// - /// class must apply environment variables when replacing values. - /// - /// Mark Pollack - [Serializable] - public enum EnvironmentVariableMode - { - /// - /// Never replace environment variables. - /// - Never = 1, + /// + /// Never replace environment variables. + /// + Never = 1, - /// - /// If properties are not specified via a resource, - /// then resolve using environment variables. - /// - Fallback = 2, + /// + /// If properties are not specified via a resource, + /// then resolve using environment variables. + /// + Fallback = 2, - /// - /// Apply environment variables first before applying properties from a - /// resource. - /// - Override = 3 - } + /// + /// Apply environment variables first before applying properties from a + /// resource. + /// + Override = 3 } diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/EnvironmentVariableSource.cs b/src/Spring/Spring.Core/Objects/Factory/Config/EnvironmentVariableSource.cs index 6b353b52..c738ede2 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/EnvironmentVariableSource.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/EnvironmentVariableSource.cs @@ -18,39 +18,38 @@ #endregion -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Implementation of that +/// resolves variable name against environment variables. +/// +/// Aleksandar Seovic +[Serializable] +public class EnvironmentVariableSource : IVariableSource { /// - /// Implementation of that - /// resolves variable name against environment variables. + /// Before requesting a variable resolution, a client should + /// ask, whether the source can resolve a particular variable name. /// - /// Aleksandar Seovic - [Serializable] - public class EnvironmentVariableSource : IVariableSource + /// the name of the variable to resolve + /// true if the variable can be resolved, false otherwise + public bool CanResolveVariable(string name) { - /// - /// Before requesting a variable resolution, a client should - /// ask, whether the source can resolve a particular variable name. - /// - /// the name of the variable to resolve - /// true if the variable can be resolved, false otherwise - public bool CanResolveVariable(string name) - { - return (Environment.GetEnvironmentVariable(name) != null); - } + return (Environment.GetEnvironmentVariable(name) != null); + } - /// - /// Resolves variable value for the specified variable name. - /// - /// - /// The name of the variable to resolve. - /// - /// - /// The variable value if able to resolve, null otherwise. - /// - public string ResolveVariable(string name) - { - return Environment.GetEnvironmentVariable(name); - } + /// + /// Resolves variable value for the specified variable name. + /// + /// + /// The name of the variable to resolve. + /// + /// + /// The variable value if able to resolve, null otherwise. + /// + public string ResolveVariable(string name) + { + return Environment.GetEnvironmentVariable(name); } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/EventValues.cs b/src/Spring/Spring.Core/Objects/Factory/Config/EventValues.cs index baddc04d..d857ff94 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/EventValues.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/EventValues.cs @@ -14,106 +14,105 @@ * limitations under the License. */ -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Holder for event handler values for an object. +/// +/// Rick Evans (.NET) +[Serializable] +public class EventValues { /// - /// Holder for event handler values for an object. + /// The empty array of s. /// - /// Rick Evans (.NET) - [Serializable] - public class EventValues + private static readonly IEventHandlerValue[] EmptyHandlers = { }; + + private static readonly string[] EmptyKeys = { }; + + private Dictionary> _eventHandlers; + + /// + /// Creates a new instance of the + /// class. + /// + public EventValues() { - /// - /// The empty array of s. - /// - private static readonly IEventHandlerValue[] EmptyHandlers = { }; + } - private static readonly string[] EmptyKeys = { }; + /// + /// Creates a new instance of the + /// class. + /// + /// + /// The + /// to be used to populate this instance. + /// + public EventValues(EventValues other) + { + AddAll(other); + } - private Dictionary> _eventHandlers; + /// + /// Gets the of events + /// that have handlers associated with them. + /// + public ICollection Events => (ICollection) _eventHandlers?.Keys ?? EmptyKeys; - /// - /// Creates a new instance of the - /// class. - /// - public EventValues() + /// + /// Gets the of + /// s for the supplied + /// event name. + /// + public ICollection this[string eventName] + { + get { - } - - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The - /// to be used to populate this instance. - /// - public EventValues(EventValues other) - { - AddAll(other); - } - - /// - /// Gets the of events - /// that have handlers associated with them. - /// - public ICollection Events => (ICollection) _eventHandlers?.Keys ?? EmptyKeys; - - /// - /// Gets the of - /// s for the supplied - /// event name. - /// - public ICollection this[string eventName] - { - get + if (_eventHandlers == null || !_eventHandlers.TryGetValue(eventName, out var handlers)) { - if (_eventHandlers == null || !_eventHandlers.TryGetValue(eventName, out var handlers)) - { - return EmptyHandlers; - } - - return handlers; - } - } - - /// - /// Copy all given argument values into this object. - /// - /// - /// The - /// to be used to populate this instance. - /// - public void AddAll(EventValues other) - { - if (other?._eventHandlers != null) - { - foreach (var pair in other._eventHandlers) - { - var list = pair.Value; - for (var i = 0; i < list.Count; i++) - { - AddHandler(list[i]); - } - } - } - } - - /// - /// Adds the supplied handler to the collection of event handlers. - /// - /// The handler to be added. - public void AddHandler(IEventHandlerValue handler) - { - _eventHandlers = _eventHandlers ?? new Dictionary>(); - - if (!_eventHandlers.TryGetValue(handler.EventName, out var handlers)) - { - handlers = new List(); - _eventHandlers[handler.EventName] = handlers; + return EmptyHandlers; } - handlers.Add(handler); + return handlers; } } + + /// + /// Copy all given argument values into this object. + /// + /// + /// The + /// to be used to populate this instance. + /// + public void AddAll(EventValues other) + { + if (other?._eventHandlers != null) + { + foreach (var pair in other._eventHandlers) + { + var list = pair.Value; + for (var i = 0; i < list.Count; i++) + { + AddHandler(list[i]); + } + } + } + } + + /// + /// Adds the supplied handler to the collection of event handlers. + /// + /// The handler to be added. + public void AddHandler(IEventHandlerValue handler) + { + _eventHandlers = _eventHandlers ?? new Dictionary>(); + + if (!_eventHandlers.TryGetValue(handler.EventName, out var handlers)) + { + handlers = new List(); + _eventHandlers[handler.EventName] = handlers; + } + + handlers.Add(handler); + } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/ExpressionHolder.cs b/src/Spring/Spring.Core/Objects/Factory/Config/ExpressionHolder.cs index 0cd6c38b..265139ed 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/ExpressionHolder.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/ExpressionHolder.cs @@ -16,67 +16,66 @@ using Spring.Expressions; -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Immutable placeholder class used for the value of a +/// object when it's a reference +/// to a Spring that should be evaluated at runtime. +/// +/// Aleksandar Seovic +[Serializable] +public class ExpressionHolder { - /// - /// Immutable placeholder class used for the value of a - /// object when it's a reference - /// to a Spring that should be evaluated at runtime. - /// - /// Aleksandar Seovic - [Serializable] - public class ExpressionHolder - { - private IExpression expression; - private string expressionString; - private MutablePropertyValues properties; + private IExpression expression; + private string expressionString; + private MutablePropertyValues properties; - /// - /// Creates a new instance of the - /// - /// class. - /// - /// The expression to resolve. - public ExpressionHolder(string expression) - { - expressionString = expression; - this.expression = Spring.Expressions.Expression.Parse(expression); - } + /// + /// Creates a new instance of the + /// + /// class. + /// + /// The expression to resolve. + public ExpressionHolder(string expression) + { + expressionString = expression; + this.expression = Spring.Expressions.Expression.Parse(expression); + } - /// - /// Gets or sets the expression string. Setting the expression string will cause - /// the expression to be parsed. - /// - /// The expression string. - public string ExpressionString - { - get { return expressionString; } - } + /// + /// Gets or sets the expression string. Setting the expression string will cause + /// the expression to be parsed. + /// + /// The expression string. + public string ExpressionString + { + get { return expressionString; } + } - /// - /// Return the expression. - /// - public IExpression Expression - { - get { return expression; } - } + /// + /// Return the expression. + /// + public IExpression Expression + { + get { return expression; } + } - /// - /// Properties for this expression node. - /// - public MutablePropertyValues Properties - { - get { return properties; } - set { properties = value; } - } + /// + /// Properties for this expression node. + /// + public MutablePropertyValues Properties + { + get { return properties; } + set { properties = value; } + } - /// - /// Returns a string representation of this instance. - /// - /// A string representation of this instance. - public override string ToString() - { - return $"<{expressionString}>"; - } - } + /// + /// Returns a string representation of this instance. + /// + /// A string representation of this instance. + public override string ToString() + { + return $"<{expressionString}>"; + } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/FieldRetrievingFactoryObject.cs b/src/Spring/Spring.Core/Objects/Factory/Config/FieldRetrievingFactoryObject.cs index f437447c..3aefa831 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/FieldRetrievingFactoryObject.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/FieldRetrievingFactoryObject.cs @@ -21,284 +21,289 @@ using System.Globalization; using System.Reflection; using System.Text; - using Spring.Core.TypeResolution; using Spring.Util; -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// implementation that +/// retrieves a static or non-static public field value. +/// +/// +///

+/// Typically used for retrieving public constants. +///

+///
+/// +///

+/// The following example retrieves the field value... +///

+/// +/// +/// +/// +/// +/// +///

+/// The previous example could also have been written using the convenience +/// +/// property, like so... +///

+/// +/// +/// +/// +/// +///

+/// This class also implements the +/// interface +/// (). +/// If the id (or name) of one's +/// +/// object definition is set to the +/// of the field to be retrieved, then the id (or +/// name) of one's object definition will be used for the name of the +/// field lookup. See below for an example of this +/// concise style of definition. +///

+/// +/// +/// +/// +/// +/// +/// +///

+/// The usage for retrieving instance fields is similar. No example is shown +/// because public instance fields are generally bad practice; but if +/// you have some legacy code that exposes public instance fields, or if you +/// just really like coding public instance fields, then you can use this +/// implementation to +/// retrieve such field values. +///

+/// +/// Juergen Hoeller +/// Rick Evans (.NET) +[Serializable] +public class FieldRetrievingFactoryObject : IFactoryObject, IInitializingObject, IObjectNameAware { + private string targetField; + private object targetObject; + private Type targetType; + private FieldInfo field; + private string objectName; + private string staticField; + /// - /// implementation that - /// retrieves a static or non-static public field value. + /// The of the + /// field to be retrieved. + /// + public string StaticField + { + set { this.staticField = value; } + } + + /// + /// Set the name of the object in the object factory that created this object. + /// + /// + /// The name of the object in the factory. + /// + /// + ///

+ /// In the context of the + /// + /// class, the + /// + /// value will be interepreted as the value of the + /// + /// property if no value has been explicitly assigned to the + /// + /// property. This allows for concise object definitions with just an id or name; + /// see the class documentation for + /// + /// for an example of this style of usage. + ///

+ ///
+ public string ObjectName + { + set { this.objectName = value; } + } + + /// + /// The name of the field the value of which is to be retrieved. /// /// ///

- /// Typically used for retrieving public constants. + /// If the + /// + /// has been set (and is not ), then the value of this property + /// refers to an instance field name; it otherwise refers to a + /// field name. ///

///
- /// - ///

- /// The following example retrieves the field value... - ///

- /// - /// - /// - /// - /// - /// - ///

- /// The previous example could also have been written using the convenience - /// - /// property, like so... - ///

- /// - /// - /// - /// - /// - ///

- /// This class also implements the - /// interface - /// (). - /// If the id (or name) of one's - /// - /// object definition is set to the - /// of the field to be retrieved, then the id (or - /// name) of one's object definition will be used for the name of the - /// field lookup. See below for an example of this - /// concise style of definition. - ///

- /// - /// - /// - /// - /// - /// - /// - ///

- /// The usage for retrieving instance fields is similar. No example is shown - /// because public instance fields are generally bad practice; but if - /// you have some legacy code that exposes public instance fields, or if you - /// just really like coding public instance fields, then you can use this - /// implementation to - /// retrieve such field values. - ///

- /// - /// Juergen Hoeller - /// Rick Evans (.NET) - [Serializable] - public class FieldRetrievingFactoryObject : IFactoryObject, IInitializingObject, IObjectNameAware + public string TargetField { - private string targetField; - private object targetObject; - private Type targetType; - private FieldInfo field; - private string objectName; - private string staticField; + get { return targetField; } + set { targetField = value; } + } - /// - /// The of the - /// field to be retrieved. - /// - public string StaticField + /// + /// The object instance on which the field is defined. + /// + public object TargetObject + { + get { return targetObject; } + set { targetObject = value; } + } + + /// + /// The on which the field is defined. + /// + public Type TargetType + { + get { return targetType; } + set { targetType = value; } + } + + /// + /// The of object that this + /// creates, or + /// if not known in advance. + /// + public Type ObjectType + { + get { return (this.field == null) ? null : this.field.FieldType; } + } + + /// + /// Is the object managed by this factory a singleton or a prototype? + /// + public bool IsSingleton + { + get { return true; } + } + + /// + /// Invoked by an + /// after it has set all object properties supplied + /// (and satisfied + /// and ApplicationContextAware). + /// + /// + ///

+ /// This method allows the object instance to perform initialization only + /// possible when all object properties have been set and to throw an + /// exception in the event of misconfiguration. + ///

+ ///
+ /// + /// In the event of misconfiguration (such as failure to set an essential + /// property) or if initialization fails. + /// + public void AfterPropertiesSet() + { + if (TargetType != null && TargetObject != null) { - set { this.staticField = value; } + throw new ArgumentException( + "Only one of the TargetType or TargetObject properties can be set, not both."); } - /// - /// Set the name of the object in the object factory that created this object. - /// - /// - /// The name of the object in the factory. - /// - /// - ///

- /// In the context of the - /// - /// class, the - /// - /// value will be interepreted as the value of the - /// - /// property if no value has been explicitly assigned to the - /// - /// property. This allows for concise object definitions with just an id or name; - /// see the class documentation for - /// - /// for an example of this style of usage. - ///

- ///
- public string ObjectName + if (TargetType == null && TargetObject == null) { - set { this.objectName = value; } - } - - /// - /// The name of the field the value of which is to be retrieved. - /// - /// - ///

- /// If the - /// - /// has been set (and is not ), then the value of this property - /// refers to an instance field name; it otherwise refers to a - /// field name. - ///

- ///
- public string TargetField - { - get { return targetField; } - set { targetField = value; } - } - - /// - /// The object instance on which the field is defined. - /// - public object TargetObject - { - get { return targetObject; } - set { targetObject = value; } - } - - /// - /// The on which the field is defined. - /// - public Type TargetType - { - get { return targetType; } - set { targetType = value; } - } - - /// - /// The of object that this - /// creates, or - /// if not known in advance. - /// - public Type ObjectType - { - get { return (this.field == null) ? null : this.field.FieldType; } - } - - /// - /// Is the object managed by this factory a singleton or a prototype? - /// - public bool IsSingleton - { - get { return true; } - } - - /// - /// Invoked by an - /// after it has set all object properties supplied - /// (and satisfied - /// and ApplicationContextAware). - /// - /// - ///

- /// This method allows the object instance to perform initialization only - /// possible when all object properties have been set and to throw an - /// exception in the event of misconfiguration. - ///

- ///
- /// - /// In the event of misconfiguration (such as failure to set an essential - /// property) or if initialization fails. - /// - public void AfterPropertiesSet() - { - if (TargetType != null && TargetObject != null) + if (TargetField != null) { throw new ArgumentException( - "Only one of the TargetType or TargetObject properties can be set, not both."); + "Specify the TargetType or TargetObject property in combination with the TargetField property."); } - if (TargetType == null && TargetObject == null) - { - if (TargetField != null) - { - throw new ArgumentException( - "Specify the TargetType or TargetObject property in combination with the TargetField property."); - } - // if no other property specified, use the object name for the static field expression... - if (StringUtils.IsNullOrEmpty(this.staticField)) - { - this.staticField = this.objectName; - } - ParseAndSetFromStaticFieldValue(); - } - if (TargetField == null) + // if no other property specified, use the object name for the static field expression... + if (StringUtils.IsNullOrEmpty(this.staticField)) { - throw new ArgumentException("The TargetField property is required."); - } - BindingFlags fieldFlags = BindingFlags.Public | BindingFlags.IgnoreCase; - if (TargetObject == null) - { - // a static field... - fieldFlags |= BindingFlags.Static; - } - else - { - // an instance field... - fieldFlags |= BindingFlags.Instance; - TargetType = TargetObject.GetType(); - } - this.field = targetType.GetField(TargetField, fieldFlags); - if (this.field == null) - { - throw new ObjectDefinitionStoreException( - string.Format( - CultureInfo.InvariantCulture, - "No such field '{0}' on [{1}].", TargetField, - TargetObject == null ? TargetType : TargetObject)); + this.staticField = this.objectName; } + + ParseAndSetFromStaticFieldValue(); } - /// - /// Return an instance (possibly shared or independent) of the object - /// managed by this factory. - /// - /// - /// An instance (possibly shared or independent) of the object managed by - /// this factory. - /// - /// - public object GetObject() + if (TargetField == null) { - if (TargetObject != null) - { - return this.field.GetValue(TargetObject); - } - else - { - return this.field.GetValue(null); - } + throw new ArgumentException("The TargetField property is required."); } - private void ParseAndSetFromStaticFieldValue() + BindingFlags fieldFlags = BindingFlags.Public | BindingFlags.IgnoreCase; + if (TargetObject == null) { - TypeAssemblyHolder info = new TypeAssemblyHolder(this.staticField); - // the info.TypeName should now contains the Type name, followed by a - // period, followed by the name of the field - int lastDotIndex = info.TypeName.LastIndexOf('.'); - if (lastDotIndex == -1 - || lastDotIndex == info.TypeName.Length) - { - throw new ArgumentException( - "The value passed to the StaticField property must be a fully " + - "qualified Type plus field name: " + - "e.g. 'Example.MyExampleClass.MyField, MyAssembly'"); - } - string typeName = info.TypeName.Substring(0, lastDotIndex); - string fieldName = info.TypeName.Substring(lastDotIndex + 1); - StringBuilder buffer = new StringBuilder(typeName); - if (info.IsAssemblyQualified) - { - buffer.Append(TypeAssemblyHolder.TypeAssemblySeparator); - buffer.Append(info.AssemblyName); - } - TargetType = TypeResolutionUtils.ResolveType(buffer.ToString()); - TargetField = fieldName; + // a static field... + fieldFlags |= BindingFlags.Static; + } + else + { + // an instance field... + fieldFlags |= BindingFlags.Instance; + TargetType = TargetObject.GetType(); + } + + this.field = targetType.GetField(TargetField, fieldFlags); + if (this.field == null) + { + throw new ObjectDefinitionStoreException( + string.Format( + CultureInfo.InvariantCulture, + "No such field '{0}' on [{1}].", TargetField, + TargetObject == null ? TargetType : TargetObject)); } } + + /// + /// Return an instance (possibly shared or independent) of the object + /// managed by this factory. + /// + /// + /// An instance (possibly shared or independent) of the object managed by + /// this factory. + /// + /// + public object GetObject() + { + if (TargetObject != null) + { + return this.field.GetValue(TargetObject); + } + else + { + return this.field.GetValue(null); + } + } + + private void ParseAndSetFromStaticFieldValue() + { + TypeAssemblyHolder info = new TypeAssemblyHolder(this.staticField); + // the info.TypeName should now contains the Type name, followed by a + // period, followed by the name of the field + int lastDotIndex = info.TypeName.LastIndexOf('.'); + if (lastDotIndex == -1 + || lastDotIndex == info.TypeName.Length) + { + throw new ArgumentException( + "The value passed to the StaticField property must be a fully " + + "qualified Type plus field name: " + + "e.g. 'Example.MyExampleClass.MyField, MyAssembly'"); + } + + string typeName = info.TypeName.Substring(0, lastDotIndex); + string fieldName = info.TypeName.Substring(lastDotIndex + 1); + StringBuilder buffer = new StringBuilder(typeName); + if (info.IsAssemblyQualified) + { + buffer.Append(TypeAssemblyHolder.TypeAssemblySeparator); + buffer.Append(info.AssemblyName); + } + + TargetType = TypeResolutionUtils.ResolveType(buffer.ToString()); + TargetField = fieldName; + } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/IAutowireCapableObjectFactory.cs b/src/Spring/Spring.Core/Objects/Factory/Config/IAutowireCapableObjectFactory.cs index 740eff30..9af33310 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/IAutowireCapableObjectFactory.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/IAutowireCapableObjectFactory.cs @@ -18,123 +18,122 @@ #endregion -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Extension of the +/// interface to be implemented by object factories that are capable of +/// autowiring and expose this functionality for existing object instances. +/// +/// Juergen Hoeller +/// Rick Evans (.NET) +public interface IAutowireCapableObjectFactory : IObjectFactory { - /// - /// Extension of the - /// interface to be implemented by object factories that are capable of - /// autowiring and expose this functionality for existing object instances. - /// - /// Juergen Hoeller - /// Rick Evans (.NET) - public interface IAutowireCapableObjectFactory : IObjectFactory - { - /// - /// Create a new object instance of the given class with the specified - /// autowire strategy. - /// - /// - /// The of the object to instantiate. - /// - /// - /// The desired autowiring mode. - /// - /// - /// Whether to perform a dependency check for objects (not applicable to - /// autowiring a constructor, thus ignored there). - /// - /// The new object instance. - /// - /// If the wiring fails. - /// - /// - object Autowire(Type type, AutoWiringMode autowireMode, bool dependencyCheck); + /// + /// Create a new object instance of the given class with the specified + /// autowire strategy. + /// + /// + /// The of the object to instantiate. + /// + /// + /// The desired autowiring mode. + /// + /// + /// Whether to perform a dependency check for objects (not applicable to + /// autowiring a constructor, thus ignored there). + /// + /// The new object instance. + /// + /// If the wiring fails. + /// + /// + object Autowire(Type type, AutoWiringMode autowireMode, bool dependencyCheck); - /// - /// Autowire the object properties of the given object instance by name or - /// . - /// - /// - /// The existing object instance. - /// - /// - /// The desired autowiring mode. - /// - /// - /// Whether to perform a dependency check for the object. - /// - /// - /// If the wiring fails. - /// - /// - void AutowireObjectProperties(object instance, AutoWiringMode autowireMode, bool dependencyCheck); + /// + /// Autowire the object properties of the given object instance by name or + /// . + /// + /// + /// The existing object instance. + /// + /// + /// The desired autowiring mode. + /// + /// + /// Whether to perform a dependency check for the object. + /// + /// + /// If the wiring fails. + /// + /// + void AutowireObjectProperties(object instance, AutoWiringMode autowireMode, bool dependencyCheck); - /// - /// Apply s - /// to the given existing object instance, invoking their - /// - /// methods. - /// - /// - ///

- /// The returned object instance may be a wrapper around the original. - ///

- ///
- /// - /// The existing object instance. - /// - /// - /// The name of the object. - /// - /// - /// The object instance to use, either the original or a wrapped one. - /// - /// - /// If any post-processing failed. - /// - /// - object ApplyObjectPostProcessorsBeforeInitialization(object instance, string name); + /// + /// Apply s + /// to the given existing object instance, invoking their + /// + /// methods. + /// + /// + ///

+ /// The returned object instance may be a wrapper around the original. + ///

+ ///
+ /// + /// The existing object instance. + /// + /// + /// The name of the object. + /// + /// + /// The object instance to use, either the original or a wrapped one. + /// + /// + /// If any post-processing failed. + /// + /// + object ApplyObjectPostProcessorsBeforeInitialization(object instance, string name); - /// - /// Apply s - /// to the given existing object instance, invoking their - /// - /// methods. - /// - /// - ///

- /// The returned object instance may be a wrapper around the original. - ///

- ///
- /// - /// The existing object instance. - /// - /// - /// The name of the object. - /// - /// - /// The object instance to use, either the original or a wrapped one. - /// - /// - /// If any post-processing failed. - /// - /// - object ApplyObjectPostProcessorsAfterInitialization(object instance, string name); + /// + /// Apply s + /// to the given existing object instance, invoking their + /// + /// methods. + /// + /// + ///

+ /// The returned object instance may be a wrapper around the original. + ///

+ ///
+ /// + /// The existing object instance. + /// + /// + /// The name of the object. + /// + /// + /// The object instance to use, either the original or a wrapped one. + /// + /// + /// If any post-processing failed. + /// + /// + object ApplyObjectPostProcessorsAfterInitialization(object instance, string name); - /// - /// Resolve the specified dependency against the objects defined in this factory. - /// - /// The descriptor for the dependency. - /// Name of the object which declares the present dependency. - /// - /// A list that all names of autowired object (used for - /// resolving the present dependency) are supposed to be added to. - /// - /// the resolved object, or null if none found - /// if dependency resolution failed - object ResolveDependency( - DependencyDescriptor descriptor, - string objectName, - IList autowiredObjectNames); - } + /// + /// Resolve the specified dependency against the objects defined in this factory. + /// + /// The descriptor for the dependency. + /// Name of the object which declares the present dependency. + /// + /// A list that all names of autowired object (used for + /// resolving the present dependency) are supposed to be added to. + /// + /// the resolved object, or null if none found + /// if dependency resolution failed + object ResolveDependency( + DependencyDescriptor descriptor, + string objectName, + IList autowiredObjectNames); } diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/IConfigurableFactoryObject.cs b/src/Spring/Spring.Core/Objects/Factory/Config/IConfigurableFactoryObject.cs index e5e35f82..96124008 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/IConfigurableFactoryObject.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/IConfigurableFactoryObject.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -20,23 +20,20 @@ #region Imports - - #endregion -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Extension of the interface +/// that injects dependencies into the object managed by the factory. +/// +/// Bruno Baia +public interface IConfigurableFactoryObject : IFactoryObject { /// - /// Extension of the interface - /// that injects dependencies into the object managed by the factory. + /// Gets the template object definition that should be used + /// to configure the instance of the object managed by this factory. /// - /// Bruno Baia - public interface IConfigurableFactoryObject : IFactoryObject - { - /// - /// Gets the template object definition that should be used - /// to configure the instance of the object managed by this factory. - /// - IObjectDefinition ProductTemplate { get; } - } -} \ No newline at end of file + IObjectDefinition ProductTemplate { get; } +} diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/IConfigurableListableObjectFactory.cs b/src/Spring/Spring.Core/Objects/Factory/Config/IConfigurableListableObjectFactory.cs index f61cf0fd..f480bff3 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/IConfigurableListableObjectFactory.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/IConfigurableListableObjectFactory.cs @@ -18,186 +18,184 @@ #endregion -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// SPI interface to be implemented by most if not all listable object factories. +/// +/// +///

+/// Allows for framework-internal plug'n'play, e.g. in +/// . +///

+///
+/// Juergen Hoeller +/// Rick Evans (.NET) +public interface IConfigurableListableObjectFactory + : IListableObjectFactory, + IConfigurableObjectFactory, + IAutowireCapableObjectFactory { - /// - /// SPI interface to be implemented by most if not all listable object factories. + /// + /// Return the registered + /// for the + /// given object, allowing access to its property values and constructor + /// argument values. + /// + /// The name of the object. + /// + /// The registered + /// . + /// + /// + /// If there is no object with the given name. + /// + /// + /// In the case of errors. + /// + IObjectDefinition GetObjectDefinition(string name); + + /// + /// Return the registered + /// for the + /// given object, allowing access to its property values and constructor + /// argument values. + /// + /// The name of the object. + /// Whether to search parent object factories. + /// + /// The registered + /// . + /// + /// + /// If there is no object with the given name. + /// + /// + /// In the case of errors. + /// + IObjectDefinition GetObjectDefinition(string name, bool includeAncestors); + + /// + /// Register a new object definition with this registry. + /// Must support + /// + /// and . + /// + /// + /// The name of the object instance to register. + /// + /// + /// The definition of the object instance to register. + /// + /// + ///

+ /// Must support + /// and + /// . + ///

+ ///
+ /// + /// If the object definition is invalid. + /// + void RegisterObjectDefinition(string name, IObjectDefinition definition); + + /// + /// Injects dependencies into the supplied instance + /// using the supplied . + /// + /// + /// The object instance that is to be so configured. + /// + /// + /// The name of the object definition expressing the dependencies that are to + /// be injected into the supplied instance. + /// + /// + /// An object definition that should be used to configure object. + /// + /// + object ConfigureObject(object target, string name, IObjectDefinition definition); + + /// + /// Ensure that all non-lazy-init singletons are instantiated, also + /// considering s. /// /// ///

- /// Allows for framework-internal plug'n'play, e.g. in - /// . + /// Typically invoked at the end of factory setup, if desired. + ///

+ ///

+ /// As this is a startup method, it should destroy already created singletons if + /// it fails, to avoid dangling resources. In other words, after invocation + /// of that method, either all or no singletons at all should be + /// instantiated. ///

///
- /// Juergen Hoeller - /// Rick Evans (.NET) - public interface IConfigurableListableObjectFactory - : IListableObjectFactory, - IConfigurableObjectFactory, - IAutowireCapableObjectFactory - { - /// - /// Return the registered - /// for the - /// given object, allowing access to its property values and constructor - /// argument values. - /// - /// The name of the object. - /// - /// The registered - /// . - /// - /// - /// If there is no object with the given name. - /// - /// - /// In the case of errors. - /// - IObjectDefinition GetObjectDefinition(string name); + /// + /// If one of the singleton objects could not be created. + /// + void PreInstantiateSingletons(); - /// - /// Return the registered - /// for the - /// given object, allowing access to its property values and constructor - /// argument values. - /// - /// The name of the object. - /// Whether to search parent object factories. - /// - /// The registered - /// . - /// - /// - /// If there is no object with the given name. - /// - /// - /// In the case of errors. - /// - IObjectDefinition GetObjectDefinition(string name, bool includeAncestors); + /// + /// Register a special dependency type with corresponding autowired value. + /// + /// + /// This is intended for factory/context references that are supposed + /// to be autowirable but are not defined as objects in the factory: + /// e.g. a dependency of type ApplicationContext resolved to the + /// ApplicationContext instance that the object is living in. + /// + /// Note there are no such default types registered in a plain IObjectFactory, + /// not even for the IObjectFactory interface itself. + /// + /// + /// Type of the dependency to register. + /// This will typically be a base interface such as IObjectFactory, with extensions of it resolved + /// as well if declared as an autowiring dependency (e.g. IListableObjectFactory), + /// as long as the given value actually implements the extended interface. + /// + /// The autowired value. This may also be an + /// implementation o the interface, + /// which allows for lazy resolution of the actual target value. + void RegisterResolvableDependency(Type dependencyType, object autowiredValue); - /// - /// Register a new object definition with this registry. - /// Must support - /// - /// and . - /// - /// - /// The name of the object instance to register. - /// - /// - /// The definition of the object instance to register. - /// - /// - ///

- /// Must support - /// and - /// . - ///

- ///
- /// - /// If the object definition is invalid. - /// - void RegisterObjectDefinition(string name, IObjectDefinition definition); + /// + /// Determines whether the specified object qualifies as an autowire candidate, + /// to be injected into other objects which declare a dependency of matching type. + /// This method checks ancestor factories as well. + /// + /// Name of the object to check. + /// The descriptor of the dependency to resolve. + /// + /// true if the object should be considered as an autowire candidate; otherwise, false. + /// + /// if there is no object with the given name. + bool IsAutowireCandidate(string objectName, DependencyDescriptor descriptor); - /// - /// Injects dependencies into the supplied instance - /// using the supplied . - /// - /// - /// The object instance that is to be so configured. - /// - /// - /// The name of the object definition expressing the dependencies that are to - /// be injected into the supplied instance. - /// - /// - /// An object definition that should be used to configure object. - /// - /// - object ConfigureObject(object target, string name, IObjectDefinition definition); + /// + /// Clear the merged object definition cache, removing entries for objects + /// which are not considered eligible for full metadata caching yet. + /// + /// + /// Typically triggered after changes to the original object definitions, + /// e.g. after applying a . Note that metadata + /// for objects which have already been created at this point will be kept around. + /// + /// + void ClearMetadataCache(); - /// - /// Ensure that all non-lazy-init singletons are instantiated, also - /// considering s. - /// - /// - ///

- /// Typically invoked at the end of factory setup, if desired. - ///

- ///

- /// As this is a startup method, it should destroy already created singletons if - /// it fails, to avoid dangling resources. In other words, after invocation - /// of that method, either all or no singletons at all should be - /// instantiated. - ///

- ///
- /// - /// If one of the singleton objects could not be created. - /// - void PreInstantiateSingletons (); + /// + /// Freeze all object definitions, signalling that the registered object definitions + /// will not be modified or post-processed any further. + /// + /// + /// This allows the factory to aggressively cache object definition metadata. + /// + void FreezeConfiguration(); - /// - /// Register a special dependency type with corresponding autowired value. - /// - /// - /// This is intended for factory/context references that are supposed - /// to be autowirable but are not defined as objects in the factory: - /// e.g. a dependency of type ApplicationContext resolved to the - /// ApplicationContext instance that the object is living in. - /// - /// Note there are no such default types registered in a plain IObjectFactory, - /// not even for the IObjectFactory interface itself. - /// - /// - /// Type of the dependency to register. - /// This will typically be a base interface such as IObjectFactory, with extensions of it resolved - /// as well if declared as an autowiring dependency (e.g. IListableObjectFactory), - /// as long as the given value actually implements the extended interface. - /// - /// The autowired value. This may also be an - /// implementation o the interface, - /// which allows for lazy resolution of the actual target value. - void RegisterResolvableDependency(Type dependencyType, object autowiredValue); - - /// - /// Determines whether the specified object qualifies as an autowire candidate, - /// to be injected into other objects which declare a dependency of matching type. - /// This method checks ancestor factories as well. - /// - /// Name of the object to check. - /// The descriptor of the dependency to resolve. - /// - /// true if the object should be considered as an autowire candidate; otherwise, false. - /// - /// if there is no object with the given name. - bool IsAutowireCandidate(string objectName, DependencyDescriptor descriptor); - - - /// - /// Clear the merged object definition cache, removing entries for objects - /// which are not considered eligible for full metadata caching yet. - /// - /// - /// Typically triggered after changes to the original object definitions, - /// e.g. after applying a . Note that metadata - /// for objects which have already been created at this point will be kept around. - /// - /// - void ClearMetadataCache(); - - /// - /// Freeze all object definitions, signalling that the registered object definitions - /// will not be modified or post-processed any further. - /// - /// - /// This allows the factory to aggressively cache object definition metadata. - /// - void FreezeConfiguration(); - - /// - /// Return whether this factory's object definitions are frozen, - /// i.e. are not supposed to be modified or post-processed any further. - /// - bool ConfigurationFrozen { get; } - } + /// + /// Return whether this factory's object definitions are frozen, + /// i.e. are not supposed to be modified or post-processed any further. + /// + bool ConfigurationFrozen { get; } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/IConfigurableObjectFactory.cs b/src/Spring/Spring.Core/Objects/Factory/Config/IConfigurableObjectFactory.cs index fc785c7e..c6d1206f 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/IConfigurableObjectFactory.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/IConfigurableObjectFactory.cs @@ -21,155 +21,153 @@ using System.ComponentModel; using Spring.Util; -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Configuration interface to be implemented by most if not all object +/// factories. +/// +/// +///

+/// Provides the means to configure an object factory in addition to the +/// object factory client methods in the +/// interface. +///

+///

+/// Allows for framework-internal plug'n'play even when needing access to object +/// factory configuration methods. +///

+///

+/// When disposed, it will destroy all cached singletons in this factory. Call +/// when you want to shutdown +/// the factory. +///

+///
+/// Juergen Hoeller +/// Rick Evans (.NET) +public interface IConfigurableObjectFactory : IHierarchicalObjectFactory, ISingletonObjectRegistry { - /// - /// Configuration interface to be implemented by most if not all object - /// factories. - /// - /// - ///

- /// Provides the means to configure an object factory in addition to the - /// object factory client methods in the - /// interface. - ///

- ///

- /// Allows for framework-internal plug'n'play even when needing access to object - /// factory configuration methods. - ///

- ///

- /// When disposed, it will destroy all cached singletons in this factory. Call - /// when you want to shutdown - /// the factory. - ///

- ///
- /// Juergen Hoeller - /// Rick Evans (.NET) - public interface IConfigurableObjectFactory : IHierarchicalObjectFactory, ISingletonObjectRegistry - { - /// - /// Set the parent of this object factory. - /// - /// - ///

- /// Note that the parent shouldn't be changed: it should only be set outside - /// a constructor if it isn't available when an object of this class is - /// created. - ///

- ///
- new IObjectFactory ParentObjectFactory { set; } + /// + /// Set the parent of this object factory. + /// + /// + ///

+ /// Note that the parent shouldn't be changed: it should only be set outside + /// a constructor if it isn't available when an object of this class is + /// created. + ///

+ ///
+ new IObjectFactory ParentObjectFactory { set; } - /// - /// Ignore the given dependency type for autowiring. - /// - /// - ///

- /// To be invoked during factory configuration. - ///

- ///

- /// This will typically be used for dependencies that are resolved - /// in other ways, like - /// through . - ///

- ///
- /// - /// The to be ignored. - /// - void IgnoreDependencyType(Type type); + /// + /// Ignore the given dependency type for autowiring. + /// + /// + ///

+ /// To be invoked during factory configuration. + ///

+ ///

+ /// This will typically be used for dependencies that are resolved + /// in other ways, like + /// through . + ///

+ ///
+ /// + /// The to be ignored. + /// + void IgnoreDependencyType(Type type); + /// + /// Determines whether the specified object name is currently in creation.. + /// + /// Name of the object. + /// + /// true if the specified object name is currently in creation; otherwise, false. + /// + bool IsCurrentlyInCreation(string objectName); - /// - /// Determines whether the specified object name is currently in creation.. - /// - /// Name of the object. - /// - /// true if the specified object name is currently in creation; otherwise, false. - /// - bool IsCurrentlyInCreation(string objectName); + /// + /// Add a new + /// that will get applied to objects created by this factory. + /// + /// + ///

+ /// To be invoked during factory configuration. + ///

+ ///
+ /// + /// The + /// to register. + /// + void AddObjectPostProcessor(IObjectPostProcessor processor); - /// - /// Add a new - /// that will get applied to objects created by this factory. - /// - /// - ///

- /// To be invoked during factory configuration. - ///

- ///
- /// - /// The - /// to register. - /// - void AddObjectPostProcessor(IObjectPostProcessor processor); + /// + /// Returns the current number of registered + /// s. + /// + /// + /// The current number of registered + /// s. + /// + int ObjectPostProcessorCount + { + get; + } - /// - /// Returns the current number of registered - /// s. - /// - /// - /// The current number of registered - /// s. - /// - int ObjectPostProcessorCount - { - get; - } + /// + /// Given an object name, create an alias. + /// + /// + ///

+ /// This is typically used to support names that are illegal within + /// XML ids (which are used for object names). + ///

+ ///

+ /// Typically invoked during factory configuration, but can also be + /// used for runtime registration of aliases. Therefore, a factory + /// implementation should synchronize alias access. + ///

+ ///
+ /// The name of the object. + /// + /// + /// The alias that will behave the same as the object name. + /// + /// + /// If there is no object with the given name. + /// + /// + /// If the alias is already in use. + /// + void RegisterAlias(string name, string theAlias); - /// - /// Given an object name, create an alias. - /// - /// - ///

- /// This is typically used to support names that are illegal within - /// XML ids (which are used for object names). - ///

- ///

- /// Typically invoked during factory configuration, but can also be - /// used for runtime registration of aliases. Therefore, a factory - /// implementation should synchronize alias access. - ///

- ///
- /// The name of the object. - /// - /// - /// The alias that will behave the same as the object name. - /// - /// - /// If there is no object with the given name. - /// - /// - /// If the alias is already in use. - /// - void RegisterAlias(string name, string theAlias); + /// + /// Register the given custom + /// for all properties of the given . + /// + /// + ///

+ /// To be invoked during factory configuration. + ///

+ ///
+ /// + /// The required of the property. + /// + /// + /// The to register. + /// + void RegisterCustomConverter(Type requiredType, TypeConverter converter); - /// - /// Register the given custom - /// for all properties of the given . - /// - /// - ///

- /// To be invoked during factory configuration. - ///

- ///
- /// - /// The required of the property. - /// - /// - /// The to register. - /// - void RegisterCustomConverter(Type requiredType, TypeConverter converter); + /// + /// Add a String resolver for embedded values such as annotation attributes. + /// + /// the String resolver to apply to embedded values + void AddEmbeddedValueResolver(IStringValueResolver valueResolver); - /// - /// Add a String resolver for embedded values such as annotation attributes. - /// - /// the String resolver to apply to embedded values - void AddEmbeddedValueResolver(IStringValueResolver valueResolver); - - /// - /// Resolve the given embedded value, e.g. an annotation attribute. - /// - /// the value to resolve - /// the resolved value (may be the original value as-is) - string ResolveEmbeddedValue(string value); - } + /// + /// Resolve the given embedded value, e.g. an annotation attribute. + /// + /// the value to resolve + /// the resolved value (may be the original value as-is) + string ResolveEmbeddedValue(string value); } diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/ICustomValueReferenceHolder.cs b/src/Spring/Spring.Core/Objects/Factory/Config/ICustomValueReferenceHolder.cs index f113e444..57995261 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/ICustomValueReferenceHolder.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/ICustomValueReferenceHolder.cs @@ -1,49 +1,48 @@ #region License -/* - * Copyright 2002-2010 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. +/* + * Copyright 2002-2010 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 -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// May be used to store custom value references in object definition properties. +/// +/// +/// Erich Eichinger +public interface ICustomValueReferenceHolder { /// - /// May be used to store custom value references in object definition properties. /// - /// - /// Erich Eichinger - public interface ICustomValueReferenceHolder - { - /// - /// - /// - /// the object factory holding the given object definition - /// - /// - /// The name of the object that is having the value of one of its properties resolved. - /// - /// - /// The definition of the named object. - /// - /// - /// The name of the property the value of which is being resolved. - /// - /// - /// The value of the property that is being resolved. - /// - object Resolve(IObjectFactory objectFactory, string name, IObjectDefinition definition, string argumentName, object argumentValue); - } -} \ No newline at end of file + /// + /// the object factory holding the given object definition + /// + /// + /// The name of the object that is having the value of one of its properties resolved. + /// + /// + /// The definition of the named object. + /// + /// + /// The name of the property the value of which is being resolved. + /// + /// + /// The value of the property that is being resolved. + /// + object Resolve(IObjectFactory objectFactory, string name, IObjectDefinition definition, string argumentName, object argumentValue); +} diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/IDestructionAwareObjectPostProcessor.cs b/src/Spring/Spring.Core/Objects/Factory/Config/IDestructionAwareObjectPostProcessor.cs index eb872234..cdd490d1 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/IDestructionAwareObjectPostProcessor.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/IDestructionAwareObjectPostProcessor.cs @@ -18,32 +18,31 @@ #endregion -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Subinterface of +/// that adds +/// a before-destruction callback. +/// +/// +/// The typical usage will be to invoke custom destruction callbacks on +/// specific object types, matching corresponding initialization callbacks. +/// +/// Juergen Hoeller +/// Simon White (.NET) +public interface IDestructionAwareObjectPostProcessor : IObjectPostProcessor { - /// - /// Subinterface of - /// that adds - /// a before-destruction callback. - /// - /// - /// The typical usage will be to invoke custom destruction callbacks on - /// specific object types, matching corresponding initialization callbacks. - /// - /// Juergen Hoeller - /// Simon White (.NET) - public interface IDestructionAwareObjectPostProcessor : IObjectPostProcessor - { - /// - /// Apply this - /// to the - /// given new object instance before its destruction. Can invoke custom - /// destruction callbacks. - /// - /// The new object instance. - /// The name of the object. - /// - /// In case of errors. - /// - void PostProcessBeforeDestruction (object instance, string name); - } + /// + /// Apply this + /// to the + /// given new object instance before its destruction. Can invoke custom + /// destruction callbacks. + /// + /// The new object instance. + /// The name of the object. + /// + /// In case of errors. + /// + void PostProcessBeforeDestruction(object instance, string name); } diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/IInstantiationAwareObjectPostProcessor.cs b/src/Spring/Spring.Core/Objects/Factory/Config/IInstantiationAwareObjectPostProcessor.cs index ecd58295..893a249a 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/IInstantiationAwareObjectPostProcessor.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/IInstantiationAwareObjectPostProcessor.cs @@ -20,109 +20,107 @@ using System.Reflection; -namespace Spring.Objects.Factory.Config { +namespace Spring.Objects.Factory.Config; - /// - /// Subinterface of - /// - /// that adds a before-instantiation callback and a callback after instantiation but before - /// explicit properties are set or autowiring occurs. - /// - /// - /// - /// Typically used to suppress default instantiation for specific target objects, - /// for example to create proxies with special Spring.Aop.ITargetSources (pooling targets, - /// lazily initializing targets, etc), or to implement additional injection strategies such as field - /// injection. - /// - /// - /// This interface is a special purpose interface, mainly for internal use within the framework. - /// It is recommended to implement the plain interface as far as - /// possible, or to derive from in order to be shielded - /// from extension to this interface. - /// - /// - /// Juergen Hoeller - /// Rick Evans (.NET) - public interface IInstantiationAwareObjectPostProcessor : IObjectPostProcessor - { - /// - /// Apply this - /// - /// before the target object gets instantiated. - /// - /// - ///

- /// The returned object may be a proxy to use instead of the target - /// object, effectively suppressing the default instantiation of the - /// target object. - ///

- ///

- /// If the object is returned by this method is not - /// , the object creation process will be - /// short-circuited. The returned object will not be processed any - /// further; in particular, no further - /// - /// callbacks will be applied to it. This mechanism is mainly intended - /// for exposing a proxy instead of an actual target object. - ///

- ///

- /// This callback will only be applied to object definitions with an - /// object class. In particular, it will not be applied to - /// objects with a "factory-method" (i.e. objects that are to be - /// instantiated via a layer of indirection anyway). - ///

- ///
- /// - /// The of the target object that is to be - /// instantiated. - /// - /// - /// The name of the target object. - /// - /// - /// The object to expose instead of a default instance of the target - /// object. - /// - /// - /// In the case of any errors. - /// - /// - /// - object PostProcessBeforeInstantiation(Type objectType, string objectName); +/// +/// Subinterface of +/// +/// that adds a before-instantiation callback and a callback after instantiation but before +/// explicit properties are set or autowiring occurs. +/// +/// +/// +/// Typically used to suppress default instantiation for specific target objects, +/// for example to create proxies with special Spring.Aop.ITargetSources (pooling targets, +/// lazily initializing targets, etc), or to implement additional injection strategies such as field +/// injection. +/// +/// +/// This interface is a special purpose interface, mainly for internal use within the framework. +/// It is recommended to implement the plain interface as far as +/// possible, or to derive from in order to be shielded +/// from extension to this interface. +/// +/// +/// Juergen Hoeller +/// Rick Evans (.NET) +public interface IInstantiationAwareObjectPostProcessor : IObjectPostProcessor +{ + /// + /// Apply this + /// + /// before the target object gets instantiated. + /// + /// + ///

+ /// The returned object may be a proxy to use instead of the target + /// object, effectively suppressing the default instantiation of the + /// target object. + ///

+ ///

+ /// If the object is returned by this method is not + /// , the object creation process will be + /// short-circuited. The returned object will not be processed any + /// further; in particular, no further + /// + /// callbacks will be applied to it. This mechanism is mainly intended + /// for exposing a proxy instead of an actual target object. + ///

+ ///

+ /// This callback will only be applied to object definitions with an + /// object class. In particular, it will not be applied to + /// objects with a "factory-method" (i.e. objects that are to be + /// instantiated via a layer of indirection anyway). + ///

+ ///
+ /// + /// The of the target object that is to be + /// instantiated. + /// + /// + /// The name of the target object. + /// + /// + /// The object to expose instead of a default instance of the target + /// object. + /// + /// + /// In the case of any errors. + /// + /// + /// + object PostProcessBeforeInstantiation(Type objectType, string objectName); + /// + /// Perform operations after the object has been instantiated, via a constructor or factory method, + /// but before Spring property population (from explicit properties or autowiring) occurs. + /// + /// The object instance created, but whose properties have not yet been set + /// Name of the object. + /// true if properties should be set on the object; false if property population + /// should be skipped. Normal implementations should return true. Returning false will also + /// prevent any subsequent InstantiationAwareObjectPostProcessor instances from being + /// invoked on this object instance. + bool PostProcessAfterInstantiation(object objectInstance, string objectName); - /// - /// Perform operations after the object has been instantiated, via a constructor or factory method, - /// but before Spring property population (from explicit properties or autowiring) occurs. - /// - /// The object instance created, but whose properties have not yet been set - /// Name of the object. - /// true if properties should be set on the object; false if property population - /// should be skipped. Normal implementations should return true. Returning false will also - /// prevent any subsequent InstantiationAwareObjectPostProcessor instances from being - /// invoked on this object instance. - bool PostProcessAfterInstantiation(object objectInstance, string objectName); - - /// - /// Post-process the given property values before the factory applies them - /// to the given object. - /// - /// Allows for checking whether all dependencies have been - /// satisfied, for example based on a "Required" annotation on bean property setters. - /// Also allows for replacing the property values to apply, typically through - /// creating a new MutablePropertyValues instance based on the original PropertyValues, - /// adding or removing specific values. - /// - /// - /// The property values that the factory is about to apply (never null). - /// he relevant property infos for the target object (with ignored - /// dependency types - which the factory handles specifically - already filtered out) - /// The object instance created, but whose properties have not yet - /// been set. - /// Name of the object. - /// The actual property values to apply to the given object (can be the - /// passed-in PropertyValues instances0 or null to skip property population. - IPropertyValues PostProcessPropertyValues(IPropertyValues pvs, IList pis, object objectInstance, string objectName); - } + /// + /// Post-process the given property values before the factory applies them + /// to the given object. + /// + /// Allows for checking whether all dependencies have been + /// satisfied, for example based on a "Required" annotation on bean property setters. + /// Also allows for replacing the property values to apply, typically through + /// creating a new MutablePropertyValues instance based on the original PropertyValues, + /// adding or removing specific values. + /// + /// + /// The property values that the factory is about to apply (never null). + /// he relevant property infos for the target object (with ignored + /// dependency types - which the factory handles specifically - already filtered out) + /// The object instance created, but whose properties have not yet + /// been set. + /// Name of the object. + /// The actual property values to apply to the given object (can be the + /// passed-in PropertyValues instances0 or null to skip property population. + IPropertyValues PostProcessPropertyValues(IPropertyValues pvs, IList pis, object objectInstance, string objectName); } diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/IManagedCollection.cs b/src/Spring/Spring.Core/Objects/Factory/Config/IManagedCollection.cs index 7433600e..7193eb96 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/IManagedCollection.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/IManagedCollection.cs @@ -20,140 +20,139 @@ using System.Collections; -namespace Spring.Objects.Factory.Config -{ - /// - /// Denotes a special placeholder collection that may contain - /// s or - /// other placeholder objects that will need to be resolved. - /// - /// - ///

- /// 'A special placeholder collection' means that the elements of this - /// collection can be placeholders for objects that will be resolved later by - /// a Spring.NET IoC container, i.e. the elements themselves will be - /// resolved at runtime by the enclosing IoC container. - ///

- ///

- /// The core Spring.NET library already provides three implementations of this interface - /// straight out of the box; they are... - ///

- /// - /// - /// - /// . - /// - /// - /// - /// - /// . - /// - /// - /// - /// - /// . - /// - /// - /// - ///

- /// If you have a custom collection class (i.e. a class that either implements the - /// directly or derives from a class that does) - /// that you would like to expose as a special placeholder collection (i.e. one that can - /// have s as elements - /// that will be resolved at runtime by an appropriate Spring.NET IoC container, just - /// implement this interface. - ///

- ///
- /// - ///

- /// Lets say one has a Bag class (i.e. a collection that supports bag style semantics). - ///

- /// - /// using System; - /// - /// using Spring.Objects.Factory.Support; - /// - /// namespace MyNamespace - /// { - /// public sealed class Bag : ICollection - /// { - /// // ICollection implementation elided for clarity... - /// - /// public void Add(object o) - /// { - /// // implementation elided for clarity... - /// } - /// } - /// - /// public class ManagedBag : Bag, IManagedCollection - /// { - /// public ICollection Resolve( - /// string objectName, RootObjectDefinition definition, - /// string propertyName, ManagedCollectionElementResolver resolver) - /// { - /// Bag newBag = new Bag(); - /// string elementName = propertyName + "[bag-element]"; - /// foreach(object element in this) - /// { - /// object resolvedElement = resolver(objectName, definition, elementName, element); - /// newBag.Add(resolvedElement); - /// } - /// return newBag; - /// } - /// } - /// } - /// - ///
- /// Rick Evans - public interface IManagedCollection : ICollection - { - /// - /// Resolves this managed collection at runtime. - /// - /// - /// The name of the top level object that is having the value of one of it's - /// collection properties resolved. - /// - /// - /// The definition of the named top level object. - /// - /// - /// The name of the property the value of which is being resolved. - /// - /// - /// The callback that will actually do the donkey work of resolving - /// this managed collection. - /// - /// A fully resolved collection. - ICollection Resolve(string objectName, IObjectDefinition definition, - string propertyName, ManagedCollectionElementResolver resolver); - } +namespace Spring.Objects.Factory.Config; - /// - /// Resolves a single element value of a managed collection. - /// - /// - ///

- /// If the does not need to be resolved or - /// converted to an appropriate , the - /// will be returned as-is. - ///

- ///
- /// - /// The name of the top level object that is having the value of one of it's - /// collection properties resolved. - /// - /// - /// The definition of the named top level object. - /// - /// - /// The name of the property the value of which is being resolved. - /// - /// - /// That element of a managed collection that may need to be resolved - /// to a concrete value. - /// - /// A fully resolved element. - public delegate object ManagedCollectionElementResolver( - string name, IObjectDefinition definition, string argumentName, object element); +/// +/// Denotes a special placeholder collection that may contain +/// s or +/// other placeholder objects that will need to be resolved. +/// +/// +///

+/// 'A special placeholder collection' means that the elements of this +/// collection can be placeholders for objects that will be resolved later by +/// a Spring.NET IoC container, i.e. the elements themselves will be +/// resolved at runtime by the enclosing IoC container. +///

+///

+/// The core Spring.NET library already provides three implementations of this interface +/// straight out of the box; they are... +///

+/// +/// +/// +/// . +/// +/// +/// +/// +/// . +/// +/// +/// +/// +/// . +/// +/// +/// +///

+/// If you have a custom collection class (i.e. a class that either implements the +/// directly or derives from a class that does) +/// that you would like to expose as a special placeholder collection (i.e. one that can +/// have s as elements +/// that will be resolved at runtime by an appropriate Spring.NET IoC container, just +/// implement this interface. +///

+///
+/// +///

+/// Lets say one has a Bag class (i.e. a collection that supports bag style semantics). +///

+/// +/// using System; +/// +/// using Spring.Objects.Factory.Support; +/// +/// namespace MyNamespace +/// { +/// public sealed class Bag : ICollection +/// { +/// // ICollection implementation elided for clarity... +/// +/// public void Add(object o) +/// { +/// // implementation elided for clarity... +/// } +/// } +/// +/// public class ManagedBag : Bag, IManagedCollection +/// { +/// public ICollection Resolve( +/// string objectName, RootObjectDefinition definition, +/// string propertyName, ManagedCollectionElementResolver resolver) +/// { +/// Bag newBag = new Bag(); +/// string elementName = propertyName + "[bag-element]"; +/// foreach(object element in this) +/// { +/// object resolvedElement = resolver(objectName, definition, elementName, element); +/// newBag.Add(resolvedElement); +/// } +/// return newBag; +/// } +/// } +/// } +/// +///
+/// Rick Evans +public interface IManagedCollection : ICollection +{ + /// + /// Resolves this managed collection at runtime. + /// + /// + /// The name of the top level object that is having the value of one of it's + /// collection properties resolved. + /// + /// + /// The definition of the named top level object. + /// + /// + /// The name of the property the value of which is being resolved. + /// + /// + /// The callback that will actually do the donkey work of resolving + /// this managed collection. + /// + /// A fully resolved collection. + ICollection Resolve(string objectName, IObjectDefinition definition, + string propertyName, ManagedCollectionElementResolver resolver); } + +/// +/// Resolves a single element value of a managed collection. +/// +/// +///

+/// If the does not need to be resolved or +/// converted to an appropriate , the +/// will be returned as-is. +///

+///
+/// +/// The name of the top level object that is having the value of one of it's +/// collection properties resolved. +/// +/// +/// The definition of the named top level object. +/// +/// +/// The name of the property the value of which is being resolved. +/// +/// +/// That element of a managed collection that may need to be resolved +/// to a concrete value. +/// +/// A fully resolved element. +public delegate object ManagedCollectionElementResolver( + string name, IObjectDefinition definition, string argumentName, object element); diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/IObjectDefinition.cs b/src/Spring/Spring.Core/Objects/Factory/Config/IObjectDefinition.cs index 171e6ca8..bc74e562 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/IObjectDefinition.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/IObjectDefinition.cs @@ -18,213 +18,212 @@ #endregion -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Describes an object instance, which has property values, constructor +/// argument values, and further information supplied by concrete implementations. +/// +/// +///

+/// This is just a minimal interface: the main intention is to allow +/// +/// (like PropertyPlaceholderConfigurer) to access and modify property values. +///

+///
+/// Juergen Hoeller +/// Rick Evans (.NET) +public interface IObjectDefinition { - /// - /// Describes an object instance, which has property values, constructor - /// argument values, and further information supplied by concrete implementations. - /// - /// - ///

- /// This is just a minimal interface: the main intention is to allow - /// - /// (like PropertyPlaceholderConfigurer) to access and modify property values. - ///

- ///
- /// Juergen Hoeller - /// Rick Evans (.NET) - public interface IObjectDefinition - { - /// - /// Return the property values to be applied to a new instance of the object. - /// - MutablePropertyValues PropertyValues { get; } + /// + /// Return the property values to be applied to a new instance of the object. + /// + MutablePropertyValues PropertyValues { get; } - /// - /// Return the constructor argument values for this object. - /// - ConstructorArgumentValues ConstructorArgumentValues { get; } + /// + /// Return the constructor argument values for this object. + /// + ConstructorArgumentValues ConstructorArgumentValues { get; } - /// - /// Return the event handlers for any events exposed by this object. - /// - EventValues EventHandlerValues { get; } + /// + /// Return the event handlers for any events exposed by this object. + /// + EventValues EventHandlerValues { get; } - /// - /// Return a description of the resource that this object definition - /// came from (for the purpose of showing context in case of errors). - /// - string ResourceDescription { get; } + /// + /// Return a description of the resource that this object definition + /// came from (for the purpose of showing context in case of errors). + /// + string ResourceDescription { get; } - /// - /// Is this object definition a "template", i.e. not meant to be instantiated - /// itself but rather just serving as an object definition for configuration - /// templates used by . - /// - /// - /// if this object definition is a "template". - /// - bool IsTemplate { get; } + /// + /// Is this object definition a "template", i.e. not meant to be instantiated + /// itself but rather just serving as an object definition for configuration + /// templates used by . + /// + /// + /// if this object definition is a "template". + /// + bool IsTemplate { get; } - /// - /// Is this object definition "abstract", i.e. not meant to be instantiated - /// itself but rather just serving as parent for concrete child object - /// definitions. - /// - /// - /// if this object definition is "abstract". - /// - bool IsAbstract { get; } + /// + /// Is this object definition "abstract", i.e. not meant to be instantiated + /// itself but rather just serving as parent for concrete child object + /// definitions. + /// + /// + /// if this object definition is "abstract". + /// + bool IsAbstract { get; } - /// - /// Return whether this a Singleton, with a single, shared instance - /// returned on all calls. - /// - /// - ///

- /// If , an object factory will apply the Prototype - /// design pattern, with each caller requesting an instance getting an - /// independent instance. How this is defined will depend on the - /// object factory implementation. Singletons are the commoner type. - ///

- ///
- bool IsSingleton { get; } + /// + /// Return whether this a Singleton, with a single, shared instance + /// returned on all calls. + /// + /// + ///

+ /// If , an object factory will apply the Prototype + /// design pattern, with each caller requesting an instance getting an + /// independent instance. How this is defined will depend on the + /// object factory implementation. Singletons are the commoner type. + ///

+ ///
+ bool IsSingleton { get; } - /// - /// Is this object lazily initialized? - /// - ///

- /// Only applicable to a singleton object. - ///

- ///

- /// If , it will get instantiated on startup by object factories - /// that perform eager initialization of singletons. - ///

- ///
- bool IsLazyInit { get; } + /// + /// Is this object lazily initialized? + /// + ///

+ /// Only applicable to a singleton object. + ///

+ ///

+ /// If , it will get instantiated on startup by object factories + /// that perform eager initialization of singletons. + ///

+ ///
+ bool IsLazyInit { get; } - /// - /// The name of the parent definition of this object definition, if any. - /// - string ParentName { get; set; } + /// + /// The name of the parent definition of this object definition, if any. + /// + string ParentName { get; set; } - /// - /// The target scope for this object. - /// - string Scope { get; set; } + /// + /// The target scope for this object. + /// + string Scope { get; set; } - /// - /// Get the role hint for this object definition - /// - ObjectRole Role { get; } + /// + /// Get the role hint for this object definition + /// + ObjectRole Role { get; } - /// - /// Returns the of the object definition (if any). - /// - /// - /// A resolved object . - /// - /// - /// If the of the object definition is not a - /// resolved or . - /// - Type ObjectType { get; } + /// + /// Returns the of the object definition (if any). + /// + /// + /// A resolved object . + /// + /// + /// If the of the object definition is not a + /// resolved or . + /// + Type ObjectType { get; } - /// - /// Returns the of the - /// of the object definition. - /// - /// Note that this does not have to be the actual type name used at runtime, - /// in case of a child definition overrding/inheriting the the type name from its - /// parent. It can be modifed during object factory post-processing, typically - /// replacing the original class name with a parsed variant of it. - /// Hence, do not consider this to be the definitive bean type at runtime - /// but rather only use it for parsing purposes at the individual object - /// definition level. - /// - string ObjectTypeName { get; set;} + /// + /// Returns the of the + /// of the object definition. + /// + /// Note that this does not have to be the actual type name used at runtime, + /// in case of a child definition overrding/inheriting the the type name from its + /// parent. It can be modifed during object factory post-processing, typically + /// replacing the original class name with a parsed variant of it. + /// Hence, do not consider this to be the definitive bean type at runtime + /// but rather only use it for parsing purposes at the individual object + /// definition level. + /// + string ObjectTypeName { get; set; } - /// - /// The autowire mode as specified in the object definition. - /// - /// - ///

- /// This determines whether any automagical detection and setting of - /// object references will happen. Default is - /// , - /// which means there's no autowire. - ///

- ///
- AutoWiringMode AutowireMode { get; } + /// + /// The autowire mode as specified in the object definition. + /// + /// + ///

+ /// This determines whether any automagical detection and setting of + /// object references will happen. Default is + /// , + /// which means there's no autowire. + ///

+ ///
+ AutoWiringMode AutowireMode { get; } - /// - /// The object names that this object depends on. - /// - /// - ///

- /// The object factory will guarantee that these objects get initialized - /// before. - ///

- ///

- /// Note that dependencies are normally expressed through object properties - /// or constructor arguments. This property should just be necessary for - /// other kinds of dependencies like statics (*ugh*) or database - /// preparation on startup. - ///

- ///
- IReadOnlyList DependsOn { get; } + /// + /// The object names that this object depends on. + /// + /// + ///

+ /// The object factory will guarantee that these objects get initialized + /// before. + ///

+ ///

+ /// Note that dependencies are normally expressed through object properties + /// or constructor arguments. This property should just be necessary for + /// other kinds of dependencies like statics (*ugh*) or database + /// preparation on startup. + ///

+ ///
+ IReadOnlyList DependsOn { get; } - /// - /// The name of the initializer method. - /// - /// - ///

- /// The default is , in which case there is no initializer method. - ///

- ///
- string InitMethodName { get; } + /// + /// The name of the initializer method. + /// + /// + ///

+ /// The default is , in which case there is no initializer method. + ///

+ ///
+ string InitMethodName { get; } - /// - /// Return the name of the destroy method. - /// - /// - ///

- /// The default is , in which case there is no destroy method. - ///

- ///
- string DestroyMethodName { get; } + /// + /// Return the name of the destroy method. + /// + /// + ///

+ /// The default is , in which case there is no destroy method. + ///

+ ///
+ string DestroyMethodName { get; } - /// - /// The name of the factory method to use (if any). - /// - /// - ///

- /// This method will be invoked with constructor arguments, or with no - /// arguments if none are specified. The static method will be invoked on - /// the specified . - ///

- ///
- string FactoryMethodName { get; } + /// + /// The name of the factory method to use (if any). + /// + /// + ///

+ /// This method will be invoked with constructor arguments, or with no + /// arguments if none are specified. The static method will be invoked on + /// the specified . + ///

+ ///
+ string FactoryMethodName { get; } - /// - /// The name of the factory object to use (if any). - /// - string FactoryObjectName { get; } + /// + /// The name of the factory object to use (if any). + /// + string FactoryObjectName { get; } - /// - /// Gets a value indicating whether this instance a candidate for getting autowired into some other - /// object. - /// - /// - /// true if this instance is autowire candidate; otherwise, false. - /// - bool IsAutowireCandidate { get; } + /// + /// Gets a value indicating whether this instance a candidate for getting autowired into some other + /// object. + /// + /// + /// true if this instance is autowire candidate; otherwise, false. + /// + bool IsAutowireCandidate { get; } - /// - /// Return whether this bean is a primary autowire candidate. - /// If this value is true for exactly one bean among multiple - /// matching candidates, it will serve as a tie-breaker. - /// - bool IsPrimary { get; } - } + /// + /// Return whether this bean is a primary autowire candidate. + /// If this value is true for exactly one bean among multiple + /// matching candidates, it will serve as a tie-breaker. + /// + bool IsPrimary { get; } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/IObjectFactoryPostProcessor.cs b/src/Spring/Spring.Core/Objects/Factory/Config/IObjectFactoryPostProcessor.cs index 5f33bfa4..e364e5de 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/IObjectFactoryPostProcessor.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/IObjectFactoryPostProcessor.cs @@ -18,49 +18,48 @@ #endregion -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Allows for custom modification of an application context's object +/// definitions, adapting the object property values of the context's +/// underlying object factory. +/// +/// +///

+/// Application contexts can auto-detect +/// IObjectFactoryPostProcessor objects in their object definitions and +/// apply them before any other objects get created. +///

+///

+/// Useful for custom config files targeted at system administrators that +/// override object properties configured in the application context. +///

+///

+/// See PropertyResourceConfigurer and its concrete implementations for +/// out-of-the-box solutions that address such configuration needs. +///

+///
+/// Juergen Hoeller +/// Rick Evans (.Net) +public interface IObjectFactoryPostProcessor { - /// - /// Allows for custom modification of an application context's object - /// definitions, adapting the object property values of the context's - /// underlying object factory. + /// + /// Modify the application context's internal object factory after its + /// standard initialization. /// /// ///

- /// Application contexts can auto-detect - /// IObjectFactoryPostProcessor objects in their object definitions and - /// apply them before any other objects get created. - ///

- ///

- /// Useful for custom config files targeted at system administrators that - /// override object properties configured in the application context. - ///

- ///

- /// See PropertyResourceConfigurer and its concrete implementations for - /// out-of-the-box solutions that address such configuration needs. + /// All object definitions will have been loaded, but no objects will have + /// been instantiated yet. This allows for overriding or adding properties + /// even to eager-initializing objects. ///

///
- /// Juergen Hoeller - /// Rick Evans (.Net) - public interface IObjectFactoryPostProcessor - { - /// - /// Modify the application context's internal object factory after its - /// standard initialization. - /// - /// - ///

- /// All object definitions will have been loaded, but no objects will have - /// been instantiated yet. This allows for overriding or adding properties - /// even to eager-initializing objects. - ///

- ///
- /// - /// The object factory used by the application context. - /// - /// - /// In case of errors. - /// - void PostProcessObjectFactory (IConfigurableListableObjectFactory factory); - } + /// + /// The object factory used by the application context. + /// + /// + /// In case of errors. + /// + void PostProcessObjectFactory(IConfigurableListableObjectFactory factory); } diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/IObjectPostProcessor.cs b/src/Spring/Spring.Core/Objects/Factory/Config/IObjectPostProcessor.cs index bfbec461..712804ef 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/IObjectPostProcessor.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/IObjectPostProcessor.cs @@ -18,79 +18,78 @@ #endregion -namespace Spring.Objects.Factory.Config -{ - /// - /// Allows for custom modification of new object instances, e.g. - /// checking for marker interfaces or wrapping them with proxies. - /// - /// - ///

- /// Application contexts can auto-detect - /// - /// objects in their object definitions and apply them before any other - /// objects get created. Plain object factories allow for programmatic - /// registration of post-processors. - ///

- ///

- /// Typically, post-processors that populate objects via marker interfaces - /// or the like will implement - /// , - /// and post-processors that wrap objects with proxies will normally implement - /// . - ///

- ///
- /// Juergen Hoeller - /// Aleksandar Seovic (.NET) - /// - public interface IObjectPostProcessor - { - /// - /// Apply this - /// to the given new object instance before any object initialization callbacks. - /// - /// - ///

- /// The object will already be populated with property values. - /// The returned object instance may be a wrapper around the original. - ///

- ///
- /// - /// The new object instance. - /// - /// - /// The name of the object. - /// - /// - /// The object instance to use, either the original or a wrapped one. - /// - /// - /// In case of errors. - /// - object PostProcessBeforeInitialization(object instance, string name); +namespace Spring.Objects.Factory.Config; - /// - /// Apply this to the - /// given new object instance after any object initialization callbacks. - /// - /// - ///

- /// The object will already be populated with property values. The returned object - /// instance may be a wrapper around the original. - ///

- ///
- /// - /// The new object instance. - /// - /// - /// The name of the object. - /// - /// - /// The object instance to use, either the original or a wrapped one. - /// - /// - /// In case of errors. - /// - object PostProcessAfterInitialization(object instance, string objectName); - } -} \ No newline at end of file +/// +/// Allows for custom modification of new object instances, e.g. +/// checking for marker interfaces or wrapping them with proxies. +/// +/// +///

+/// Application contexts can auto-detect +/// +/// objects in their object definitions and apply them before any other +/// objects get created. Plain object factories allow for programmatic +/// registration of post-processors. +///

+///

+/// Typically, post-processors that populate objects via marker interfaces +/// or the like will implement +/// , +/// and post-processors that wrap objects with proxies will normally implement +/// . +///

+///
+/// Juergen Hoeller +/// Aleksandar Seovic (.NET) +/// +public interface IObjectPostProcessor +{ + /// + /// Apply this + /// to the given new object instance before any object initialization callbacks. + /// + /// + ///

+ /// The object will already be populated with property values. + /// The returned object instance may be a wrapper around the original. + ///

+ ///
+ /// + /// The new object instance. + /// + /// + /// The name of the object. + /// + /// + /// The object instance to use, either the original or a wrapped one. + /// + /// + /// In case of errors. + /// + object PostProcessBeforeInitialization(object instance, string name); + + /// + /// Apply this to the + /// given new object instance after any object initialization callbacks. + /// + /// + ///

+ /// The object will already be populated with property values. The returned object + /// instance may be a wrapper around the original. + ///

+ ///
+ /// + /// The new object instance. + /// + /// + /// The name of the object. + /// + /// + /// The object instance to use, either the original or a wrapped one. + /// + /// + /// In case of errors. + /// + object PostProcessAfterInitialization(object instance, string objectName); +} diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/ISingletonObjectRegistry.cs b/src/Spring/Spring.Core/Objects/Factory/Config/ISingletonObjectRegistry.cs index 670fd195..e89c143e 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/ISingletonObjectRegistry.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/ISingletonObjectRegistry.cs @@ -20,152 +20,149 @@ using Spring.Objects.Factory.Support; -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Interface that defines a registry for shared object instances. +/// +/// +/// Can be implemented by +/// implementations in order to expose their singleton management facility +/// in a uniform manner. +/// +/// The interface extends this interface. +/// +/// +/// Juergen Hoeller +/// Mark Pollack (.NET) +public interface ISingletonObjectRegistry { /// - /// Interface that defines a registry for shared object instances. + /// Registers the given existing object as singleton in the object registry, + /// under the given object name. /// /// - /// Can be implemented by - /// implementations in order to expose their singleton management facility - /// in a uniform manner. /// - /// The interface extends this interface. + /// The given instance is supposed to be fully initialized; the registry + /// will not perform any initialization callbacks (in particular, it won't + /// call IInitializingObject's AfterPropertiesSet method). + /// The given instance will not receive any destruction callbacks + /// (like IDisposable's Dispose method) either. + /// + /// + /// If running within a full IObjectFactory: Register an object definition + /// instead of an existing instance if your object is supposed to receive + /// initialization and/or destruction callbacks. + /// + /// + /// Typically invoked during registry configuration, but can also be used + /// for runtime registration of singletons. As a consequence, a registry + /// implementation should synchronize singleton access; it will have to do + /// this anyway if it supports a BeanFactory's lazy initialization of singletons. /// /// - /// Juergen Hoeller - /// Mark Pollack (.NET) - public interface ISingletonObjectRegistry + /// Name of the object. + /// The singleton object. + /// + /// + void RegisterSingleton(string objectName, object singletonObject); + + /// + /// Return the (raw) singleton object registered under the given name. + /// + /// + /// + /// Only checks already instantiated singletons; does not return an Object + /// for singleton object definitions which have not been instantiated yet. + /// + /// + /// The main purpose of this method is to access manually registered singletons + /// . Can also be used to access a singleton + /// defined by an object definition that already been created, in a raw fashion. + /// + /// + /// Name of the object to look for. + /// the registered singleton object, or null if none found + /// + object GetSingleton(string objectName); + + /// + /// Check if this registry contains a singleton instance with the given name. + /// + /// + /// + /// Only checks already instantiated singletons; does not return true + /// for singleton bean definitions which have not been instantiated yet. + /// + /// + /// The main purpose of this method is to check manually registered singletons + /// . Can also be used to check whether a + /// singleton defined by an object definition has already been created. + /// + /// + /// To check whether an object factory contains an object definition with a given name, + /// use ListableBeanFactory's ContainsObjectDefinition. Calling both + /// ContainsObjectDefinition and ContainsSingleton answers + /// whether a specific object factory contains an own object with the given name. + /// + /// + /// Use IObjectFactory's ContainsObject for general checks whether the + /// factory knows about an object with a given name (whether manually registered singleton + /// instance or created by bean definition), also checking ancestor factories. + /// + /// + /// Name of the object to look for. + /// + /// true if this bean factory contains a singleton instance with the given name; otherwise, false. + /// + /// + /// + /// + bool ContainsSingleton(string objectName); + + /// + /// Gets the names of singleton objects registered in this registry. + /// + /// + /// + /// Only checks already instantiated singletons; does not return names + /// for singleton bean definitions which have not been instantiated yet. + /// + /// + /// The main purpose of this method is to check manually registered singletons + /// . Can also be used to check which + /// singletons defined by an object definition have already been created. + /// + /// + /// The list of names as String array (never null). + /// + /// + /// + IList SingletonNames { - /// - /// Registers the given existing object as singleton in the object registry, - /// under the given object name. - /// - /// - /// - /// The given instance is supposed to be fully initialized; the registry - /// will not perform any initialization callbacks (in particular, it won't - /// call IInitializingObject's AfterPropertiesSet method). - /// The given instance will not receive any destruction callbacks - /// (like IDisposable's Dispose method) either. - /// - /// - /// If running within a full IObjectFactory: Register an object definition - /// instead of an existing instance if your object is supposed to receive - /// initialization and/or destruction callbacks. - /// - /// - /// Typically invoked during registry configuration, but can also be used - /// for runtime registration of singletons. As a consequence, a registry - /// implementation should synchronize singleton access; it will have to do - /// this anyway if it supports a BeanFactory's lazy initialization of singletons. - /// - /// - /// Name of the object. - /// The singleton object. - /// - /// - void RegisterSingleton(string objectName, object singletonObject); + get; + } - - /// - /// Return the (raw) singleton object registered under the given name. - /// - /// - /// - /// Only checks already instantiated singletons; does not return an Object - /// for singleton object definitions which have not been instantiated yet. - /// - /// - /// The main purpose of this method is to access manually registered singletons - /// . Can also be used to access a singleton - /// defined by an object definition that already been created, in a raw fashion. - /// - /// - /// Name of the object to look for. - /// the registered singleton object, or null if none found - /// - object GetSingleton(string objectName); - - - /// - /// Check if this registry contains a singleton instance with the given name. - /// - /// - /// - /// Only checks already instantiated singletons; does not return true - /// for singleton bean definitions which have not been instantiated yet. - /// - /// - /// The main purpose of this method is to check manually registered singletons - /// . Can also be used to check whether a - /// singleton defined by an object definition has already been created. - /// - /// - /// To check whether an object factory contains an object definition with a given name, - /// use ListableBeanFactory's ContainsObjectDefinition. Calling both - /// ContainsObjectDefinition and ContainsSingleton answers - /// whether a specific object factory contains an own object with the given name. - /// - /// - /// Use IObjectFactory's ContainsObject for general checks whether the - /// factory knows about an object with a given name (whether manually registered singleton - /// instance or created by bean definition), also checking ancestor factories. - /// - /// - /// Name of the object to look for. - /// - /// true if this bean factory contains a singleton instance with the given name; otherwise, false. - /// - /// - /// - /// - bool ContainsSingleton(string objectName); - - /// - /// Gets the names of singleton objects registered in this registry. - /// - /// - /// - /// Only checks already instantiated singletons; does not return names - /// for singleton bean definitions which have not been instantiated yet. - /// - /// - /// The main purpose of this method is to check manually registered singletons - /// . Can also be used to check which - /// singletons defined by an object definition have already been created. - /// - /// - /// The list of names as String array (never null). - /// - /// - /// - IList SingletonNames - { - get; - } - - /// - /// Gets the number of singleton beans registered in this registry. - /// - /// - /// - /// Only checks already instantiated singletons; does not count - /// singleton object definitions which have not been instantiated yet. - /// - /// - /// The main purpose of this method is to check manually registered singletons - /// . Can also be used to count the number of - /// singletons defined by an object definition that have already been created. - /// - /// - /// The number of singleton objects. - /// - /// - /// - int SingletonCount - { - get; - } + /// + /// Gets the number of singleton beans registered in this registry. + /// + /// + /// + /// Only checks already instantiated singletons; does not count + /// singleton object definitions which have not been instantiated yet. + /// + /// + /// The main purpose of this method is to check manually registered singletons + /// . Can also be used to count the number of + /// singletons defined by an object definition that have already been created. + /// + /// + /// The number of singleton objects. + /// + /// + /// + int SingletonCount + { + get; } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/IVariableSource.cs b/src/Spring/Spring.Core/Objects/Factory/Config/IVariableSource.cs index cb523f82..3f0d823e 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/IVariableSource.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/IVariableSource.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -18,50 +18,49 @@ #endregion -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Defines contract that different variable sources have to implement. +/// +/// +///

+/// The "variable sources" are objects containing name-value pairs +/// that allow a variable value to be retrieved for the given name.

+///

+/// Out of the box, Spring.NET supports a number of variable sources, +/// that allow users to obtain variable values from .NET config files, +/// Java-style property files, environment, registry, etc.

+///

+/// Users can always write their own variable sources implementations, +/// that will allow them to load variable values from the database or +/// other proprietary data source.

+///
+/// +/// +/// +/// +/// +/// +/// Aleksandar Seovic +public interface IVariableSource { /// - /// Defines contract that different variable sources have to implement. + /// Before requesting a variable resolution, a client should + /// ask, whether the source can resolve a particular variable name. /// - /// - ///

- /// The "variable sources" are objects containing name-value pairs - /// that allow a variable value to be retrieved for the given name.

- ///

- /// Out of the box, Spring.NET supports a number of variable sources, - /// that allow users to obtain variable values from .NET config files, - /// Java-style property files, environment, registry, etc.

- ///

- /// Users can always write their own variable sources implementations, - /// that will allow them to load variable values from the database or - /// other proprietary data source.

- ///
- /// - /// - /// - /// - /// - /// - /// Aleksandar Seovic - public interface IVariableSource - { - /// - /// Before requesting a variable resolution, a client should - /// ask, whether the source can resolve a particular variable name. - /// - /// the name of the variable to resolve - /// true if the variable can be resolved, false otherwise - bool CanResolveVariable(string name); + /// the name of the variable to resolve + /// true if the variable can be resolved, false otherwise + bool CanResolveVariable(string name); - /// - /// Resolves variable value for the specified variable name. - /// - /// - /// The name of the variable to resolve. - /// - /// - /// The variable value if able to resolve, null otherwise. - /// - string ResolveVariable(string name); - } -} \ No newline at end of file + /// + /// Resolves variable value for the specified variable name. + /// + /// + /// The name of the variable to resolve. + /// + /// + /// The variable value if able to resolve, null otherwise. + /// + string ResolveVariable(string name); +} diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/InstantiationAwareObjectPostProcessorAdapter.cs b/src/Spring/Spring.Core/Objects/Factory/Config/InstantiationAwareObjectPostProcessorAdapter.cs index 5ab6e545..c5361621 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/InstantiationAwareObjectPostProcessorAdapter.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/InstantiationAwareObjectPostProcessorAdapter.cs @@ -16,189 +16,188 @@ using System.Reflection; -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Adapter that implements all methods on +/// as no-ops, which will not change normal processing of each object instantiated +/// by the container. Subclasses may override merely those methods that they are +/// actually interested in. +/// +/// +/// Note that this base class is only recommendable if you actually require +/// functionality. If all you need +/// is plain functionality, prefer a straight +/// implementation of that (simpler) interface. +/// +/// Rod Johnson +/// Juergen Hoeller +/// Mark Pollack (.NET) +public abstract class InstantiationAwareObjectPostProcessorAdapter : SmartInstantiationAwareObjectPostProcessor { /// - /// Adapter that implements all methods on - /// as no-ops, which will not change normal processing of each object instantiated - /// by the container. Subclasses may override merely those methods that they are - /// actually interested in. + /// Predicts the type of the object to be eventually returned from this + /// processors PostProcessBeforeInstantiation callback. + /// + /// The raw Type of the object. + /// Name of the object. + /// The type of the object, or null if not predictable. + /// in case of errors + public virtual Type PredictObjectType(Type objectType, string objectName) + { + return null; + } + + /// + /// Determines the candidate constructors to use for the given object. + /// + /// The raw Type of the object. + /// Name of the object. + /// The candidate constructors, or null if none specified + /// in case of errors + public virtual ConstructorInfo[] DetermineCandidateConstructors(Type objectType, string objectName) + { + return null; + } + + /// + /// Apply this + /// + /// before the target object gets instantiated. /// /// - /// Note that this base class is only recommendable if you actually require - /// functionality. If all you need - /// is plain functionality, prefer a straight - /// implementation of that (simpler) interface. + ///

+ /// The returned object may be a proxy to use instead of the target + /// object, effectively suppressing the default instantiation of the + /// target object. + ///

+ ///

+ /// If the object is returned by this method is not + /// , the object creation process will be + /// short-circuited. The returned object will not be processed any + /// further; in particular, no further + /// + /// callbacks will be applied to it. This mechanism is mainly intended + /// for exposing a proxy instead of an actual target object. + ///

+ ///

+ /// This callback will only be applied to object definitions with an + /// object class. In particular, it will not be applied to + /// objects with a "factory-method" (i.e. objects that are to be + /// instantiated via a layer of indirection anyway). + ///

///
- /// Rod Johnson - /// Juergen Hoeller - /// Mark Pollack (.NET) - public abstract class InstantiationAwareObjectPostProcessorAdapter : SmartInstantiationAwareObjectPostProcessor + /// + /// The of the target object that is to be + /// instantiated. + /// + /// + /// The name of the target object. + /// + /// + /// The object to expose instead of a default instance of the target + /// object. + /// + /// + /// In the case of any errors. + /// + /// + /// + public virtual object PostProcessBeforeInstantiation(Type objectType, string objectName) { - /// - /// Predicts the type of the object to be eventually returned from this - /// processors PostProcessBeforeInstantiation callback. - /// - /// The raw Type of the object. - /// Name of the object. - /// The type of the object, or null if not predictable. - /// in case of errors - public virtual Type PredictObjectType(Type objectType, string objectName) - { - return null; - } + return null; + } - /// - /// Determines the candidate constructors to use for the given object. - /// - /// The raw Type of the object. - /// Name of the object. - /// The candidate constructors, or null if none specified - /// in case of errors - public virtual ConstructorInfo[] DetermineCandidateConstructors(Type objectType, string objectName) - { - return null; - } + /// + /// Perform operations after the object has been instantiated, via a constructor or factory method, + /// but before Spring property population (from explicit properties or autowiring) occurs. + /// + /// The object instance created, but whose properties have not yet been set + /// Name of the object. + /// true if properties should be set on the object; false if property population + /// should be skipped. Normal implementations should return true. Returning false will also + /// prevent any subsequent InstantiationAwareObjectPostProcessor instances from being + /// invoked on this object instance. + public virtual bool PostProcessAfterInstantiation(object objectInstance, string objectName) + { + return true; + } - /// - /// Apply this - /// - /// before the target object gets instantiated. - /// - /// - ///

- /// The returned object may be a proxy to use instead of the target - /// object, effectively suppressing the default instantiation of the - /// target object. - ///

- ///

- /// If the object is returned by this method is not - /// , the object creation process will be - /// short-circuited. The returned object will not be processed any - /// further; in particular, no further - /// - /// callbacks will be applied to it. This mechanism is mainly intended - /// for exposing a proxy instead of an actual target object. - ///

- ///

- /// This callback will only be applied to object definitions with an - /// object class. In particular, it will not be applied to - /// objects with a "factory-method" (i.e. objects that are to be - /// instantiated via a layer of indirection anyway). - ///

- ///
- /// - /// The of the target object that is to be - /// instantiated. - /// - /// - /// The name of the target object. - /// - /// - /// The object to expose instead of a default instance of the target - /// object. - /// - /// - /// In the case of any errors. - /// - /// - /// - public virtual object PostProcessBeforeInstantiation(Type objectType, string objectName) - { - return null; - } + /// + /// Post-process the given property values before the factory applies them + /// to the given object. + /// + /// Allows for checking whether all dependencies have been + /// satisfied, for example based on a "Required" annotation on bean property setters. + /// Also allows for replacing the property values to apply, typically through + /// creating a new MutablePropertyValues instance based on the original PropertyValues, + /// adding or removing specific values. + /// + /// + /// The property values that the factory is about to apply (never null). + /// he relevant property infos for the target object (with ignored + /// dependency types - which the factory handles specifically - already filtered out) + /// The object instance created, but whose properties have not yet + /// been set. + /// Name of the object. + /// The actual property values to apply to the given object (can be the + /// passed-in PropertyValues instances0 or null to skip property population. + public virtual IPropertyValues PostProcessPropertyValues(IPropertyValues pvs, IList pis, object objectInstance, string objectName) + { + return pvs; + } - /// - /// Perform operations after the object has been instantiated, via a constructor or factory method, - /// but before Spring property population (from explicit properties or autowiring) occurs. - /// - /// The object instance created, but whose properties have not yet been set - /// Name of the object. - /// true if properties should be set on the object; false if property population - /// should be skipped. Normal implementations should return true. Returning false will also - /// prevent any subsequent InstantiationAwareObjectPostProcessor instances from being - /// invoked on this object instance. - public virtual bool PostProcessAfterInstantiation(object objectInstance, string objectName) - { - return true; - } + /// + /// Apply this + /// to the given new object instance before any object initialization callbacks. + /// + /// + ///

+ /// The object will already be populated with property values. + /// The returned object instance may be a wrapper around the original. + ///

+ ///
+ /// + /// The new object instance. + /// + /// + /// The name of the object. + /// + /// + /// The object instance to use, either the original or a wrapped one. + /// + /// + /// In case of errors. + /// + public virtual object PostProcessBeforeInitialization(object instance, string name) + { + return instance; + } - /// - /// Post-process the given property values before the factory applies them - /// to the given object. - /// - /// Allows for checking whether all dependencies have been - /// satisfied, for example based on a "Required" annotation on bean property setters. - /// Also allows for replacing the property values to apply, typically through - /// creating a new MutablePropertyValues instance based on the original PropertyValues, - /// adding or removing specific values. - /// - /// - /// The property values that the factory is about to apply (never null). - /// he relevant property infos for the target object (with ignored - /// dependency types - which the factory handles specifically - already filtered out) - /// The object instance created, but whose properties have not yet - /// been set. - /// Name of the object. - /// The actual property values to apply to the given object (can be the - /// passed-in PropertyValues instances0 or null to skip property population. - public virtual IPropertyValues PostProcessPropertyValues(IPropertyValues pvs, IList pis, object objectInstance, string objectName) - { - return pvs; - } - - /// - /// Apply this - /// to the given new object instance before any object initialization callbacks. - /// - /// - ///

- /// The object will already be populated with property values. - /// The returned object instance may be a wrapper around the original. - ///

- ///
- /// - /// The new object instance. - /// - /// - /// The name of the object. - /// - /// - /// The object instance to use, either the original or a wrapped one. - /// - /// - /// In case of errors. - /// - public virtual object PostProcessBeforeInitialization(object instance, string name) - { - return instance; - } - - /// - /// Apply this to the - /// given new object instance after any object initialization callbacks. - /// - /// - ///

- /// The object will already be populated with property values. The returned object - /// instance may be a wrapper around the original. - ///

- ///
- /// - /// The new object instance. - /// - /// - /// The name of the object. - /// - /// - /// The object instance to use, either the original or a wrapped one. - /// - /// - /// In case of errors. - /// - public virtual object PostProcessAfterInitialization(object instance, string objectName) - { - return instance; - } + /// + /// Apply this to the + /// given new object instance after any object initialization callbacks. + /// + /// + ///

+ /// The object will already be populated with property values. The returned object + /// instance may be a wrapper around the original. + ///

+ ///
+ /// + /// The new object instance. + /// + /// + /// The name of the object. + /// + /// + /// The object instance to use, either the original or a wrapped one. + /// + /// + /// In case of errors. + /// + public virtual object PostProcessAfterInitialization(object instance, string objectName) + { + return instance; } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/ListFactoryObject.cs b/src/Spring/Spring.Core/Objects/Factory/Config/ListFactoryObject.cs index 8aa60bc4..8d908c8e 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/ListFactoryObject.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/ListFactoryObject.cs @@ -20,106 +20,109 @@ using System.Collections; using System.Globalization; - using Spring.Util; -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Simple factory for shared instances. +/// +/// Juergen Hoeller +/// Simon White (.NET) +[Serializable] +public class ListFactoryObject : AbstractFactoryObject { - /// - /// Simple factory for shared instances. - /// - /// Juergen Hoeller - /// Simon White (.NET) - [Serializable] - public class ListFactoryObject : AbstractFactoryObject - { - private IList _sourceList; - private Type _targetListType = typeof (ArrayList); + private IList _sourceList; + private Type _targetListType = typeof(ArrayList); - #region Properties + #region Properties - /// - /// Set the source . - /// - /// - ///

- /// This value will be used to populate the - /// returned by this factory. - ///

- ///
- public IList SourceList - { - set { this._sourceList = value; } - } + /// + /// Set the source . + /// + /// + ///

+ /// This value will be used to populate the + /// returned by this factory. + ///

+ ///
+ public IList SourceList + { + set { this._sourceList = value; } + } - /// - /// Set the of the - /// implementation to use. - /// - /// - ///

- /// The default is the . - ///

- ///
- public Type TargetListType - { - set - { - AssertUtils.ArgumentNotNull(value, "value"); - if (!typeof (IList).IsAssignableFrom(value)) - { - throw new ArgumentException( - string.Format(CultureInfo.InvariantCulture, - "The Type passed to the TargetListType property must implement the '{0}' interface.", - ObjectType.FullName)); - } - if (value.IsInterface) - { - throw new ArgumentException( - string.Format(CultureInfo.InvariantCulture, - "The Type passed to the TargetListType property cannot be an interface; it must be a concrete class that implements the '{0}' interface.", - ObjectType.FullName)); - } - if (value.IsAbstract) - { - throw new ArgumentException( - string.Format(CultureInfo.InvariantCulture, - "The Type passed to the TargetListType property cannot be abstract (MustInherit in VisualBasic.NET); it must be a concrete class that implements the '{0}' interface.", - ObjectType.FullName)); - } - this._targetListType = value; - } - } + /// + /// Set the of the + /// implementation to use. + /// + /// + ///

+ /// The default is the . + ///

+ ///
+ public Type TargetListType + { + set + { + AssertUtils.ArgumentNotNull(value, "value"); + if (!typeof(IList).IsAssignableFrom(value)) + { + throw new ArgumentException( + string.Format(CultureInfo.InvariantCulture, + "The Type passed to the TargetListType property must implement the '{0}' interface.", + ObjectType.FullName)); + } - /// - /// The of objects created by this factory. - /// - /// - /// Always returns the . - /// - public override Type ObjectType - { - get { return typeof (IList); } - } + if (value.IsInterface) + { + throw new ArgumentException( + string.Format(CultureInfo.InvariantCulture, + "The Type passed to the TargetListType property cannot be an interface; it must be a concrete class that implements the '{0}' interface.", + ObjectType.FullName)); + } - #endregion + if (value.IsAbstract) + { + throw new ArgumentException( + string.Format(CultureInfo.InvariantCulture, + "The Type passed to the TargetListType property cannot be abstract (MustInherit in VisualBasic.NET); it must be a concrete class that implements the '{0}' interface.", + ObjectType.FullName)); + } - /// - /// Constructs a new instance of the target dictionary. - /// - /// The new instance. - protected override object CreateInstance() - { - if (this._sourceList == null) - { - throw new ArgumentException("The 'SourceList' property cannot be null (Nothing in Visual Basic.NET)."); - } - IList result = (IList) ObjectUtils.InstantiateType(this._targetListType); - foreach (object obj in this._sourceList) - { - result.Add(obj); - } - return result; - } - } -} + this._targetListType = value; + } + } + + /// + /// The of objects created by this factory. + /// + /// + /// Always returns the . + /// + public override Type ObjectType + { + get { return typeof(IList); } + } + + #endregion + + /// + /// Constructs a new instance of the target dictionary. + /// + /// The new instance. + protected override object CreateInstance() + { + if (this._sourceList == null) + { + throw new ArgumentException("The 'SourceList' property cannot be null (Nothing in Visual Basic.NET)."); + } + + IList result = (IList) ObjectUtils.InstantiateType(this._targetListType); + foreach (object obj in this._sourceList) + { + result.Add(obj); + } + + return result; + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/LogFactoryObject.cs b/src/Spring/Spring.Core/Objects/Factory/Config/LogFactoryObject.cs index aec48ef1..431baf0f 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/LogFactoryObject.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/LogFactoryObject.cs @@ -21,145 +21,145 @@ using Microsoft.Extensions.Logging; using Spring.Util; -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// implementation that +/// creates instances of the class. +/// +/// +///

+/// Typically used for retrieving shared +/// instances for common topics (such as the 'DAL', 'BLL', etc). The +/// +/// property determines the name of the +/// Common.Logging logger. +///

+///
+/// Rick Evans +/// +[Serializable] +public class LogFactoryObject : IFactoryObject, IInitializingObject { - /// - /// implementation that - /// creates instances of the class. - /// - /// - ///

- /// Typically used for retrieving shared - /// instances for common topics (such as the 'DAL', 'BLL', etc). The - /// - /// property determines the name of the - /// Common.Logging logger. - ///

- ///
- /// Rick Evans - /// - [Serializable] - public class LogFactoryObject : IFactoryObject, IInitializingObject - { - #region Constructor (s) / Destructor + #region Constructor (s) / Destructor - /// - /// Creates a new instance of the - /// - /// class. - /// - public LogFactoryObject() - { - } + /// + /// Creates a new instance of the + /// + /// class. + /// + public LogFactoryObject() + { + } - /// - /// Creates a new instance of the - /// - /// class. - /// - /// - /// The name of the instance served up by - /// this factory. - /// - /// - /// If the supplied is - /// or contains only whitespace character(s). - /// - public LogFactoryObject(string logName) - { - LogName = logName; - } + /// + /// Creates a new instance of the + /// + /// class. + /// + /// + /// The name of the instance served up by + /// this factory. + /// + /// + /// If the supplied is + /// or contains only whitespace character(s). + /// + public LogFactoryObject(string logName) + { + LogName = logName; + } - #endregion + #endregion - /// - /// The name of the instance served up by - /// this factory. - /// - /// - /// The name of the instance served up by - /// this factory. - /// - /// - /// If the supplied to the setter is - /// or contains only whitespace character(s). - /// - public string LogName - { - get { return this.logName; } - set - { - AssertUtils.ArgumentHasText(value, "The 'LogName' property must have a value."); - this.logName = value.Trim(); - } - } + /// + /// The name of the instance served up by + /// this factory. + /// + /// + /// The name of the instance served up by + /// this factory. + /// + /// + /// If the supplied to the setter is + /// or contains only whitespace character(s). + /// + public string LogName + { + get { return this.logName; } + set + { + AssertUtils.ArgumentHasText(value, "The 'LogName' property must have a value."); + this.logName = value.Trim(); + } + } - /// - /// Return an instance (possibly shared or independent) of the object - /// managed by this factory. - /// - /// - /// An instance (possibly shared or independent) of the object - /// managed by this factory. - /// - /// - public object GetObject() - { - if (this.log == null) - { - ValidateProperties(); - this.log = LogManager.GetLogger(LogName); - } - return this.log; - } + /// + /// Return an instance (possibly shared or independent) of the object + /// managed by this factory. + /// + /// + /// An instance (possibly shared or independent) of the object + /// managed by this factory. + /// + /// + public object GetObject() + { + if (this.log == null) + { + ValidateProperties(); + this.log = LogManager.GetLogger(LogName); + } - /// - /// Return the type of object that this - /// creates, or - /// if not known in advance. - /// - /// - public Type ObjectType - { - get { return typeof(ILogger); } - } + return this.log; + } - /// - /// Is the object managed by this factory a singleton or a prototype? - /// - /// - public bool IsSingleton - { - get { return true; } - } + /// + /// Return the type of object that this + /// creates, or + /// if not known in advance. + /// + /// + public Type ObjectType + { + get { return typeof(ILogger); } + } - /// - /// Invoked by an - /// after it has set all object properties supplied - /// (and satisfied the - /// - /// and - /// interfaces). - /// - /// - /// In the event of misconfiguration (such as failure to set an essential - /// property) or if initialization fails. - /// - /// - public void AfterPropertiesSet() - { - ValidateProperties(); - } + /// + /// Is the object managed by this factory a singleton or a prototype? + /// + /// + public bool IsSingleton + { + get { return true; } + } - private void ValidateProperties() - { - if (StringUtils.IsNullOrEmpty(LogName)) - { - throw new ArgumentException("The 'LogName' property has not been set."); - } - } + /// + /// Invoked by an + /// after it has set all object properties supplied + /// (and satisfied the + /// + /// and + /// interfaces). + /// + /// + /// In the event of misconfiguration (such as failure to set an essential + /// property) or if initialization fails. + /// + /// + public void AfterPropertiesSet() + { + ValidateProperties(); + } - private ILogger log; - private string logName; - } + private void ValidateProperties() + { + if (StringUtils.IsNullOrEmpty(LogName)) + { + throw new ArgumentException("The 'LogName' property has not been set."); + } + } + + private ILogger log; + private string logName; } diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/ManagedDictionary.cs b/src/Spring/Spring.Core/Objects/Factory/Config/ManagedDictionary.cs index 98cf812e..2e3be288 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/ManagedDictionary.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/ManagedDictionary.cs @@ -17,6 +17,7 @@ */ #endregion + #region License /* @@ -40,213 +41,215 @@ using System.Collections; using System.Collections.Specialized; using System.Globalization; - using Spring.Core; using Spring.Core.TypeConversion; using Spring.Core.TypeResolution; using Spring.Util; -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Tag subclass used to hold a dictionary of managed elements. +/// +/// Juergen Hoeller +/// Rick Evans (.NET) +[Serializable] +public class ManagedDictionary : Hashtable, IManagedCollection, IMergable { - /// - /// Tag subclass used to hold a dictionary of managed elements. - /// - /// Juergen Hoeller - /// Rick Evans (.NET) - [Serializable] - public class ManagedDictionary : Hashtable, IManagedCollection, IMergable - { - private string keyTypeName; - private string valueTypeName; - private bool mergeEnabled; + private string keyTypeName; + private string valueTypeName; + private bool mergeEnabled; - /// - /// Initializes a new, empty instance of the class using the default initial capacity, load factor, hash code provider, and comparer. - /// - public ManagedDictionary() - { - } + /// + /// Initializes a new, empty instance of the class using the default initial capacity, load factor, hash code provider, and comparer. + /// + public ManagedDictionary() + { + } - /// - /// Initializes a new, empty instance of the class using the specified initial capacity, and the default load factor, hash code provider, and comparer. - /// - /// The approximate number of elements that the object can initially contain. is less than zero. - public ManagedDictionary(int capacity) : base(capacity) - { - } + /// + /// Initializes a new, empty instance of the class using the specified initial capacity, and the default load factor, hash code provider, and comparer. + /// + /// The approximate number of elements that the object can initially contain. is less than zero. + public ManagedDictionary(int capacity) : base(capacity) + { + } - /// - /// Gets or sets the unresolved name for the - /// of the keys of this managed dictionary. - /// - /// The unresolved name for the type of the keys of this managed dictionary. - public string KeyTypeName + /// + /// Gets or sets the unresolved name for the + /// of the keys of this managed dictionary. + /// + /// The unresolved name for the type of the keys of this managed dictionary. + public string KeyTypeName + { + get { return this.keyTypeName; } + set { this.keyTypeName = value; } + } + + /// + /// Gets or sets the unresolved name for the + /// of the values of this managed dictionary. + /// + /// The unresolved name for the type of the values of this managed dictionary. + public string ValueTypeName + { + get { return this.valueTypeName; } + set { this.valueTypeName = value; } + } + + /// + /// Resolves this managed collection at runtime. + /// + /// + /// The name of the top level object that is having the value of one of it's + /// collection properties resolved. + /// + /// + /// The definition of the named top level object. + /// + /// + /// The name of the property the value of which is being resolved. + /// + /// + /// The callback that will actually do the donkey work of resolving + /// this managed collection. + /// + /// A fully resolved collection. + public ICollection Resolve( + string objectName, IObjectDefinition definition, + string propertyName, ManagedCollectionElementResolver resolver) + { + IDictionary dictionary; + + Type keyType = null; + if (StringUtils.HasText(this.keyTypeName)) { - get { return this.keyTypeName; } - set { this.keyTypeName = value; } + keyType = TypeResolutionUtils.ResolveType(this.keyTypeName); } - /// - /// Gets or sets the unresolved name for the - /// of the values of this managed dictionary. - /// - /// The unresolved name for the type of the values of this managed dictionary. - public string ValueTypeName + Type valueType = null; + if (StringUtils.HasText(this.valueTypeName)) { - get { return this.valueTypeName; } - set { this.valueTypeName = value; } + valueType = TypeResolutionUtils.ResolveType(this.valueTypeName); } - /// - /// Resolves this managed collection at runtime. - /// - /// - /// The name of the top level object that is having the value of one of it's - /// collection properties resolved. - /// - /// - /// The definition of the named top level object. - /// - /// - /// The name of the property the value of which is being resolved. - /// - /// - /// The callback that will actually do the donkey work of resolving - /// this managed collection. - /// - /// A fully resolved collection. - public ICollection Resolve( - string objectName, IObjectDefinition definition, - string propertyName, ManagedCollectionElementResolver resolver) - { - IDictionary dictionary; + if ((keyType == null) && (valueType == null)) + { + dictionary = new HybridDictionary(); + } + else + { + Type type = typeof(Dictionary<,>); + Type[] genericArgs = new Type[2] { (keyType == null) ? typeof(object) : keyType, (valueType == null) ? typeof(object) : valueType }; + type = type.MakeGenericType(genericArgs); - Type keyType = null; - if (StringUtils.HasText(this.keyTypeName)) + dictionary = (IDictionary) ObjectUtils.InstantiateType(type); + } + + foreach (object key in this.Keys) + { + string elementName = string.Format(CultureInfo.InvariantCulture, "{0}[{1}]", propertyName, key); + object resolvedKey = resolver(objectName, definition, elementName, key); + object resolvedValue = resolver(objectName, definition, elementName, this[key]); + + if (keyType != null) { - keyType = TypeResolutionUtils.ResolveType(this.keyTypeName); - } - - Type valueType = null; - if (StringUtils.HasText(this.valueTypeName)) - { - valueType = TypeResolutionUtils.ResolveType(this.valueTypeName); - } - - if ((keyType == null) && (valueType == null)) - { - dictionary = new HybridDictionary(); - } - else - { - Type type = typeof(Dictionary<,>); - Type[] genericArgs = new Type[2] { - (keyType == null) ? typeof(object) : keyType, - (valueType == null) ? typeof(object) : valueType }; - type = type.MakeGenericType(genericArgs); - - dictionary = (IDictionary)ObjectUtils.InstantiateType(type); - } - - foreach (object key in this.Keys) - { - string elementName = string.Format(CultureInfo.InvariantCulture, "{0}[{1}]", propertyName, key); - object resolvedKey = resolver(objectName, definition, elementName, key); - object resolvedValue = resolver(objectName, definition, elementName, this[key]); - - if (keyType != null) + try { - try - { - resolvedKey = TypeConversionUtils.ConvertValueIfNecessary(keyType, resolvedKey, propertyName); - } - catch (TypeMismatchException) - { - throw new TypeMismatchException( - String.Format( - "Unable to convert managed dictionary key '{0}' from [{1}] into [{2}] during initialization" - + " of property '{3}' for object '{4}'. Do you have an appropriate type converter registered?", - resolvedKey, resolvedKey.GetType(), keyType, propertyName, objectName)); - } + resolvedKey = TypeConversionUtils.ConvertValueIfNecessary(keyType, resolvedKey, propertyName); } - - if (valueType != null) + catch (TypeMismatchException) { - try - { - resolvedValue = TypeConversionUtils.ConvertValueIfNecessary(valueType, resolvedValue, propertyName + "[" + resolvedKey + "]"); - } - catch (TypeMismatchException) - { - throw new TypeMismatchException( - String.Format( - "Unable to convert managed dictionary value '{0}' from [{1}] into [{2}] during initialization" - + " of property '{3}' for object '{4}'. Do you have an appropriate type converter registered?", - resolvedValue, resolvedValue.GetType(), valueType, propertyName, objectName)); - } + throw new TypeMismatchException( + String.Format( + "Unable to convert managed dictionary key '{0}' from [{1}] into [{2}] during initialization" + + " of property '{3}' for object '{4}'. Do you have an appropriate type converter registered?", + resolvedKey, resolvedKey.GetType(), keyType, propertyName, objectName)); } + } - dictionary.Add(resolvedKey, resolvedValue); - } + if (valueType != null) + { + try + { + resolvedValue = TypeConversionUtils.ConvertValueIfNecessary(valueType, resolvedValue, propertyName + "[" + resolvedKey + "]"); + } + catch (TypeMismatchException) + { + throw new TypeMismatchException( + String.Format( + "Unable to convert managed dictionary value '{0}' from [{1}] into [{2}] during initialization" + + " of property '{3}' for object '{4}'. Do you have an appropriate type converter registered?", + resolvedValue, resolvedValue.GetType(), valueType, propertyName, objectName)); + } + } - return dictionary; - } + dictionary.Add(resolvedKey, resolvedValue); + } - /// - /// Gets a value indicating whether this instance is merge enabled for this instance - /// - /// - /// true if this instance is merge enabled; otherwise, false. - /// - public bool MergeEnabled - { - get { return this.mergeEnabled; } - set { this.mergeEnabled = value; } - } + return dictionary; + } - /// - /// Merges the current value set with that of the supplied object. - /// - /// The supplied object is considered the parent, and values in the - /// callee's value set must override those of the supplied object. - /// - /// The parent object to merge with - /// The result of the merge operation - /// If the supplied parent is null - /// If merging is not enabled for this instance, - /// (i.e. MergeEnabled equals false. - public object Merge(object parent) - { - if (!this.mergeEnabled) - { - throw new InvalidOperationException( - "Not allowed to merge when the 'MergeEnabled' property is set to 'false'"); - } - if (parent == null) - { - return this; - } - var pDict = parent as IDictionary; - if (pDict == null) - { - throw new InvalidOperationException("Cannot merge with object of type [" + parent.GetType() + "]"); - } - var merged = new ManagedDictionary(); - var pManagedDict = pDict as ManagedDictionary; - if (pManagedDict != null) - { - merged.KeyTypeName = pManagedDict.keyTypeName; - merged.valueTypeName = pManagedDict.valueTypeName; - } - foreach (DictionaryEntry dictionaryEntry in pDict) - { - merged[dictionaryEntry.Key] = dictionaryEntry.Value; - } - foreach (DictionaryEntry entry in this) - { - merged[entry.Key] = entry.Value; - } - return merged; - } - } + /// + /// Gets a value indicating whether this instance is merge enabled for this instance + /// + /// + /// true if this instance is merge enabled; otherwise, false. + /// + public bool MergeEnabled + { + get { return this.mergeEnabled; } + set { this.mergeEnabled = value; } + } + + /// + /// Merges the current value set with that of the supplied object. + /// + /// The supplied object is considered the parent, and values in the + /// callee's value set must override those of the supplied object. + /// + /// The parent object to merge with + /// The result of the merge operation + /// If the supplied parent is null + /// If merging is not enabled for this instance, + /// (i.e. MergeEnabled equals false. + public object Merge(object parent) + { + if (!this.mergeEnabled) + { + throw new InvalidOperationException( + "Not allowed to merge when the 'MergeEnabled' property is set to 'false'"); + } + + if (parent == null) + { + return this; + } + + var pDict = parent as IDictionary; + if (pDict == null) + { + throw new InvalidOperationException("Cannot merge with object of type [" + parent.GetType() + "]"); + } + + var merged = new ManagedDictionary(); + var pManagedDict = pDict as ManagedDictionary; + if (pManagedDict != null) + { + merged.KeyTypeName = pManagedDict.keyTypeName; + merged.valueTypeName = pManagedDict.valueTypeName; + } + + foreach (DictionaryEntry dictionaryEntry in pDict) + { + merged[dictionaryEntry.Key] = dictionaryEntry.Value; + } + + foreach (DictionaryEntry entry in this) + { + merged[entry.Key] = entry.Value; + } + + return merged; + } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/ManagedList.cs b/src/Spring/Spring.Core/Objects/Factory/Config/ManagedList.cs index 91575c38..b93d91e0 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/ManagedList.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/ManagedList.cs @@ -20,173 +20,175 @@ using System.Collections; using System.Globalization; - using Spring.Core; using Spring.Core.TypeConversion; using Spring.Core.TypeResolution; using Spring.Util; -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Tag subclass used to hold a list of managed elements. +/// +/// Rod Johnson +/// Rick Evans (.NET) +[Serializable] +public class ManagedList : ArrayList, IManagedCollection, IMergable { + private string elementTypeName; + private bool mergeEnabled; + /// - /// Tag subclass used to hold a list of managed elements. + /// Initializes a new instance of the ManagedList class that is empty and has the default initial capacity. /// - /// Rod Johnson - /// Rick Evans (.NET) - [Serializable] - public class ManagedList : ArrayList, IManagedCollection, IMergable + public ManagedList() { - private string elementTypeName; - private bool mergeEnabled; + } - /// - /// Initializes a new instance of the ManagedList class that is empty and has the default initial capacity. - /// - public ManagedList() + /// + /// Initializes a new instance of the ManagedList class that is empty and has the specified initial capacity. + /// + /// The number of elements that the new list can initially store. is less than zero. + public ManagedList(int capacity) + : base(capacity) + { + } + + /// + /// Gets or sets the unresolved name for the + /// of the elements of this managed list. + /// + /// The unresolved name for the type of the elements of this managed list. + public string ElementTypeName + { + get { return this.elementTypeName; } + set { this.elementTypeName = value; } + } + + /// + /// Resolves this managed collection at runtime. + /// + /// + /// The name of the top level object that is having the value of one of it's + /// collection properties resolved. + /// + /// + /// The definition of the named top level object. + /// + /// + /// The name of the property the value of which is being resolved. + /// + /// + /// The callback that will actually do the donkey work of resolving + /// this managed collection. + /// + /// A fully resolved collection. + public ICollection Resolve(string objectName, IObjectDefinition definition, string propertyName, ManagedCollectionElementResolver resolver) + { + IList list; + + Type elementType = null; + if (StringUtils.HasText(this.elementTypeName)) { + elementType = TypeResolutionUtils.ResolveType(this.elementTypeName); } - /// - /// Initializes a new instance of the ManagedList class that is empty and has the specified initial capacity. - /// - /// The number of elements that the new list can initially store. is less than zero. - public ManagedList(int capacity) - : base(capacity) + if (elementType == null) { + list = new ArrayList(); + } + else + { + // CLOVER:ON + Type type = typeof(List<>); + Type[] genericArgs = new Type[1] { elementType }; + type = type.MakeGenericType(genericArgs); + + list = (IList) ObjectUtils.InstantiateType(type); + // CLOVER:OFF } - - /// - /// Gets or sets the unresolved name for the - /// of the elements of this managed list. - /// - /// The unresolved name for the type of the elements of this managed list. - public string ElementTypeName + for (int i = 0; i < Count; ++i) { - get { return this.elementTypeName; } - set { this.elementTypeName = value; } - } + object element = this[i]; + object resolvedElement = + resolver(objectName, definition, String.Format(CultureInfo.InvariantCulture, "{0}[{1}]", propertyName, i), element); - /// - /// Resolves this managed collection at runtime. - /// - /// - /// The name of the top level object that is having the value of one of it's - /// collection properties resolved. - /// - /// - /// The definition of the named top level object. - /// - /// - /// The name of the property the value of which is being resolved. - /// - /// - /// The callback that will actually do the donkey work of resolving - /// this managed collection. - /// - /// A fully resolved collection. - public ICollection Resolve(string objectName, IObjectDefinition definition, string propertyName, ManagedCollectionElementResolver resolver) - { - IList list; - - Type elementType = null; - if (StringUtils.HasText(this.elementTypeName)) + if (elementType != null) { - elementType = TypeResolutionUtils.ResolveType(this.elementTypeName); - } - - if (elementType == null) - { - list = new ArrayList(); - } - else - { - // CLOVER:ON - Type type = typeof(List<>); - Type[] genericArgs = new Type[1] { elementType }; - type = type.MakeGenericType(genericArgs); - - list = (IList)ObjectUtils.InstantiateType(type); - // CLOVER:OFF - } - - for (int i = 0; i < Count; ++i) - { - object element = this[i]; - object resolvedElement = - resolver(objectName, definition, String.Format(CultureInfo.InvariantCulture, "{0}[{1}]", propertyName, i), element); - - if (elementType != null) + try { - try - { - resolvedElement = TypeConversionUtils.ConvertValueIfNecessary(elementType, resolvedElement, propertyName + "[" + i + "]"); - } - catch (TypeMismatchException) - { - throw new TypeMismatchException( - String.Format( - "Unable to convert managed list element '{0}' from [{1}] into [{2}] during initialization" - + " of property '{3}' for object '{4}'. Do you have an appropriate type converter registered?", - resolvedElement, resolvedElement.GetType(), elementType, propertyName, objectName)); - } + resolvedElement = TypeConversionUtils.ConvertValueIfNecessary(elementType, resolvedElement, propertyName + "[" + i + "]"); + } + catch (TypeMismatchException) + { + throw new TypeMismatchException( + String.Format( + "Unable to convert managed list element '{0}' from [{1}] into [{2}] during initialization" + + " of property '{3}' for object '{4}'. Do you have an appropriate type converter registered?", + resolvedElement, resolvedElement.GetType(), elementType, propertyName, objectName)); } - - list.Add(resolvedElement); } - return list; + list.Add(resolvedElement); } - /// - /// Gets a value indicating whether this instance is merge enabled for this instance - /// - /// - /// true if this instance is merge enabled; otherwise, false. - /// - public bool MergeEnabled + return list; + } + + /// + /// Gets a value indicating whether this instance is merge enabled for this instance + /// + /// + /// true if this instance is merge enabled; otherwise, false. + /// + public bool MergeEnabled + { + get { return this.mergeEnabled; } + set { this.mergeEnabled = value; } + } + + /// + /// Merges the current value set with that of the supplied object. + /// + /// The supplied object is considered the parent, and values in the + /// callee's value set must override those of the supplied object. + /// + /// The parent object to merge with + /// The result of the merge operation + /// If the supplied parent is null + /// If merging is not enabled for this instance, + /// (i.e. MergeEnabled equals false. + public object Merge(object parent) + { + if (!this.mergeEnabled) { - get { return this.mergeEnabled; } - set { this.mergeEnabled = value; } + throw new InvalidOperationException( + "Not allowed to merge when the 'MergeEnabled' property is set to 'false'"); } - /// - /// Merges the current value set with that of the supplied object. - /// - /// The supplied object is considered the parent, and values in the - /// callee's value set must override those of the supplied object. - /// - /// The parent object to merge with - /// The result of the merge operation - /// If the supplied parent is null - /// If merging is not enabled for this instance, - /// (i.e. MergeEnabled equals false. - public object Merge(object parent) + if (parent == null) { - if (!this.mergeEnabled) - { - throw new InvalidOperationException( - "Not allowed to merge when the 'MergeEnabled' property is set to 'false'"); - } - if (parent == null) - { - return this; - } - IList plist = parent as IList; - if (plist == null) - { - throw new InvalidOperationException("Cannot merge with object of type [" + parent.GetType() + "]"); - } - IList merged = new ManagedList(); - foreach (object element in plist) - { - merged.Add(element); - } - foreach (object o in this) - { - merged.Add(o); - } - return merged; + return this; } + + IList plist = parent as IList; + if (plist == null) + { + throw new InvalidOperationException("Cannot merge with object of type [" + parent.GetType() + "]"); + } + + IList merged = new ManagedList(); + foreach (object element in plist) + { + merged.Add(element); + } + + foreach (object o in this) + { + merged.Add(o); + } + + return merged; } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/ManagedNameValueCollection.cs b/src/Spring/Spring.Core/Objects/Factory/Config/ManagedNameValueCollection.cs index c998881a..14e0dcc0 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/ManagedNameValueCollection.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/ManagedNameValueCollection.cs @@ -20,80 +20,84 @@ using System.Collections.Specialized; -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Tag class which represent a Spring-managed instance that +/// supports merging of parent/child definitions. +/// +public class ManagedNameValueCollection : NameValueCollection, IMergable { + private bool mergeEnabled; + /// - /// Tag class which represent a Spring-managed instance that - /// supports merging of parent/child definitions. + /// Initializes a new instance of the class that is empty, has the default initial capacity and uses the default case-insensitive hash code provider and the default case-insensitive comparer. /// - public class ManagedNameValueCollection: NameValueCollection, IMergable + public ManagedNameValueCollection() { - private bool mergeEnabled; + } - /// - /// Initializes a new instance of the class that is empty, has the default initial capacity and uses the default case-insensitive hash code provider and the default case-insensitive comparer. - /// - public ManagedNameValueCollection() + /// + /// Initializes a new instance of the class that is empty, has the specified initial capacity and uses the default case-insensitive hash code provider and the default case-insensitive comparer. + /// + /// The initial number of entries that the can contain. is less than zero. + public ManagedNameValueCollection(int capacity) : base(capacity) + { + } + + /// + /// Gets a value indicating whether this instance is merge enabled for this instance + /// + /// + /// true if this instance is merge enabled; otherwise, false. + /// + public bool MergeEnabled + { + get { return this.mergeEnabled; } + set { this.mergeEnabled = value; } + } + + /// + /// Merges the current value set with that of the supplied object. + /// + /// The supplied object is considered the parent, and values in the + /// callee's value set must override those of the supplied object. + /// + /// The parent object to merge with + /// The result of the merge operation + /// If the supplied parent is null + /// If merging is not enabled for this instance, + /// (i.e. MergeEnabled equals false. + public object Merge(object parent) + { + if (!this.mergeEnabled) { + throw new InvalidOperationException( + "Not allowed to merge when the 'MergeEnabled' property is set to 'false'"); } - /// - /// Initializes a new instance of the class that is empty, has the specified initial capacity and uses the default case-insensitive hash code provider and the default case-insensitive comparer. - /// - /// The initial number of entries that the can contain. is less than zero. - public ManagedNameValueCollection(int capacity) : base(capacity) + if (parent == null) { + return this; } - /// - /// Gets a value indicating whether this instance is merge enabled for this instance - /// - /// - /// true if this instance is merge enabled; otherwise, false. - /// - public bool MergeEnabled + NameValueCollection pDict = parent as NameValueCollection; + if (pDict == null) { - get { return this.mergeEnabled; } - set { this.mergeEnabled = value; } + throw new InvalidOperationException("Cannot merge with object of type [" + parent.GetType() + "]"); } - /// - /// Merges the current value set with that of the supplied object. - /// - /// The supplied object is considered the parent, and values in the - /// callee's value set must override those of the supplied object. - /// - /// The parent object to merge with - /// The result of the merge operation - /// If the supplied parent is null - /// If merging is not enabled for this instance, - /// (i.e. MergeEnabled equals false. - public object Merge(object parent) + NameValueCollection merged = new ManagedNameValueCollection(); + foreach (string s in pDict.AllKeys) { - if (!this.mergeEnabled) - { - throw new InvalidOperationException( - "Not allowed to merge when the 'MergeEnabled' property is set to 'false'"); - } - if (parent == null) - { - return this; - } - NameValueCollection pDict = parent as NameValueCollection; - if (pDict == null) - { - throw new InvalidOperationException("Cannot merge with object of type [" + parent.GetType() + "]"); - } - NameValueCollection merged = new ManagedNameValueCollection(); - foreach (string s in pDict.AllKeys) - { - merged[s] = pDict.Get(s); - } - foreach (string s in this.AllKeys) - { - merged[s] = this.Get(s); - } - return merged; + merged[s] = pDict.Get(s); } + + foreach (string s in this.AllKeys) + { + merged[s] = this.Get(s); + } + + return merged; } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/ManagedSet.cs b/src/Spring/Spring.Core/Objects/Factory/Config/ManagedSet.cs index a435f213..ec42a82f 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/ManagedSet.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/ManagedSet.cs @@ -19,160 +19,162 @@ #endregion using System.Collections; - using Spring.Collections; using Spring.Core; using Spring.Core.TypeConversion; using Spring.Core.TypeResolution; using Spring.Util; -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Tag subclass used to hold a set of managed elements. +/// +/// Juergen Hoeller +/// Rick Evans (.NET) +[Serializable] +public class ManagedSet : HybridSet, IManagedCollection, IMergable { + private string elementTypeName; + + private bool mergeEnabled; + /// - /// Tag subclass used to hold a set of managed elements. + /// Creates a new set instance based on either a list or a hash table, + /// depending on which will be more efficient based on the data-set + /// size. /// - /// Juergen Hoeller - /// Rick Evans (.NET) - [Serializable] - public class ManagedSet : HybridSet, IManagedCollection, IMergable + public ManagedSet() { - private string elementTypeName; + } - private bool mergeEnabled; + /// + /// Initializes a new instance of the class with a given capacity + /// + /// The size. + public ManagedSet(int size) : base(size) + { + } + /// + /// Gets or sets the unresolved name for the + /// of the elements of this managed set. + /// + /// The unresolved name for the type of the elements of this managed set. + public string ElementTypeName + { + get { return this.elementTypeName; } + set { this.elementTypeName = value; } + } - /// - /// Creates a new set instance based on either a list or a hash table, - /// depending on which will be more efficient based on the data-set - /// size. - /// - public ManagedSet() + /// + /// Resolves this managed collection at runtime. + /// + /// + /// The name of the top level object that is having the value of one of it's + /// collection properties resolved. + /// + /// + /// The definition of the named top level object. + /// + /// + /// The name of the property the value of which is being resolved. + /// + /// + /// The callback that will actually do the donkey work of resolving + /// this managed collection. + /// + /// A fully resolved collection. + public ICollection Resolve(string objectName, IObjectDefinition definition, string propertyName, ManagedCollectionElementResolver resolver) + { + ISet set = new HybridSet(); + + Type elementType = null; + if (StringUtils.HasText(this.elementTypeName)) { + elementType = TypeResolutionUtils.ResolveType(this.elementTypeName); } - /// - /// Initializes a new instance of the class with a given capacity - /// - /// The size. - public ManagedSet(int size) : base(size) + string elementName = propertyName + "[(set-element)]"; + foreach (object element in this) { - } + object resolvedElement = resolver(objectName, definition, elementName, element); - /// - /// Gets or sets the unresolved name for the - /// of the elements of this managed set. - /// - /// The unresolved name for the type of the elements of this managed set. - public string ElementTypeName - { - get { return this.elementTypeName; } - set { this.elementTypeName = value; } - } - - /// - /// Resolves this managed collection at runtime. - /// - /// - /// The name of the top level object that is having the value of one of it's - /// collection properties resolved. - /// - /// - /// The definition of the named top level object. - /// - /// - /// The name of the property the value of which is being resolved. - /// - /// - /// The callback that will actually do the donkey work of resolving - /// this managed collection. - /// - /// A fully resolved collection. - public ICollection Resolve(string objectName, IObjectDefinition definition, string propertyName, ManagedCollectionElementResolver resolver) - { - ISet set = new HybridSet(); - - Type elementType = null; - if (StringUtils.HasText(this.elementTypeName)) + if (elementType != null) { - elementType = TypeResolutionUtils.ResolveType(this.elementTypeName); - } - - string elementName = propertyName + "[(set-element)]"; - foreach (object element in this) - { - object resolvedElement = resolver(objectName, definition, elementName, element); - - if (elementType != null) + try { - try - { - resolvedElement = TypeConversionUtils.ConvertValueIfNecessary(elementType, resolvedElement, propertyName); - } - catch (TypeMismatchException) - { - throw new TypeMismatchException( - String.Format( - "Unable to convert managed set element '{0}' from [{1}] into [{2}] during initialization" - + " of property '{3}' for object '{4}'. Do you have an appropriate type converter registered?", - resolvedElement, resolvedElement.GetType(), elementType, propertyName, objectName)); - } + resolvedElement = TypeConversionUtils.ConvertValueIfNecessary(elementType, resolvedElement, propertyName); + } + catch (TypeMismatchException) + { + throw new TypeMismatchException( + String.Format( + "Unable to convert managed set element '{0}' from [{1}] into [{2}] during initialization" + + " of property '{3}' for object '{4}'. Do you have an appropriate type converter registered?", + resolvedElement, resolvedElement.GetType(), elementType, propertyName, objectName)); } - - set.Add(resolvedElement); } - return set; + set.Add(resolvedElement); } - /// - /// Gets a value indicating whether this instance is merge enabled for this instance - /// - /// - /// true if this instance is merge enabled; otherwise, false. - /// - public bool MergeEnabled + return set; + } + + /// + /// Gets a value indicating whether this instance is merge enabled for this instance + /// + /// + /// true if this instance is merge enabled; otherwise, false. + /// + public bool MergeEnabled + { + get { return this.mergeEnabled; } + set { this.mergeEnabled = value; } + } + + /// + /// Merges the current value set with that of the supplied object. + /// + /// The supplied object is considered the parent, and values in the + /// callee's value set must override those of the supplied object. + /// + /// The parent object to merge with + /// The result of the merge operation + /// If the supplied parent is null + /// If merging is not enabled for this instance, + /// (i.e. MergeEnabled equals false. + public object Merge(object parent) + { + if (!this.mergeEnabled) { - get { return this.mergeEnabled; } - set { this.mergeEnabled = value; } + throw new InvalidOperationException( + "Not allowed to merge when the 'MergeEnabled' property is set to 'false'"); } - /// - /// Merges the current value set with that of the supplied object. - /// - /// The supplied object is considered the parent, and values in the - /// callee's value set must override those of the supplied object. - /// - /// The parent object to merge with - /// The result of the merge operation - /// If the supplied parent is null - /// If merging is not enabled for this instance, - /// (i.e. MergeEnabled equals false. - public object Merge(object parent) + if (parent == null) { - if (!this.mergeEnabled) - { - throw new InvalidOperationException( - "Not allowed to merge when the 'MergeEnabled' property is set to 'false'"); - } - if (parent == null) - { - return this; - } - ISet pSet = parent as ISet; - if (pSet == null) - { - throw new InvalidOperationException("Cannot merge with object of type [" + parent.GetType() + "]"); - } - ISet merged = new ManagedSet(); - foreach (object element in pSet) - { - merged.Add(element); - } - foreach (object o in this) - { - merged.Add(o); - } - return merged; + return this; } + + ISet pSet = parent as ISet; + if (pSet == null) + { + throw new InvalidOperationException("Cannot merge with object of type [" + parent.GetType() + "]"); + } + + ISet merged = new ManagedSet(); + foreach (object element in pSet) + { + merged.Add(element); + } + + foreach (object o in this) + { + merged.Add(o); + } + + return merged; } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/MethodInvokingFactoryObject.cs b/src/Spring/Spring.Core/Objects/Factory/Config/MethodInvokingFactoryObject.cs index 3c4a5753..2357c13c 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/MethodInvokingFactoryObject.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/MethodInvokingFactoryObject.cs @@ -20,246 +20,248 @@ using Spring.Objects.Support; -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// An that returns a value +/// that is the result of a or instance method invocation. +/// +/// +///

+/// Note that this class generally is expected to be used for accessing factory methods, +/// and as such defaults to operating in singleton mode. The first request to +/// +/// by the owning object factory will cause a method invocation, the return +/// value of which will be cached for all subsequent requests. The +/// property may be set to +/// , to cause this factory to invoke the target method each +/// time it is asked for an object. +///

+///

+/// A target method may be specified by setting the +/// property to a string representing +/// the method name, with specifying +/// the that the method is defined on. +/// Alternatively, a target instance method may be specified, by setting the +/// property as the target object, and +/// the property as the name of the +/// method to call on that target object. Arguments for the method invocation may be +/// specified by setting the property. +///

+///

+/// Another (esoteric) use case for this factory object is when one needs to call a method +/// that doesn't return any value (for example, a class method to +/// force some sort of initialization to happen)... this use case is not supported by +/// factory-methods, since a return value is needed to become the object. +///

+///

+/// +/// This class depends on the +/// +/// method being called after all properties have been set, as per the +/// contract. If you are +/// using this class outside of a Spring.NET IoC container, you must call one of either +/// or +/// yourself to ready the object's internal +/// state, or you will get a nasty . +/// +///

+///
+/// +///

+/// The following example uses an instance of this class to call a +/// factory method... +///

+/// +/// +/// +/// +/// +/// +/// +/// 1st +/// 2nd +/// and 3rd arguments +/// +/// +/// +/// +///

+/// The following example is similar to the preceding example; the only pertinent difference is the fact that +/// a number of different objects are passed as arguments, demonstrating that not only simple value types +/// are valid as elements of the argument list... +///

+/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// 1st +/// +/// +/// +/// +/// +/// +/// http://www.springframework.net/ +/// +/// +/// +/// +/// +///

+/// Named parameters are also supported... this next example yields the same results as +/// the preceding example (that did not use named arguments). +///

+/// +/// +/// +/// +/// +/// +/// +/// +/// +/// 1st +/// and 3rd arguments +/// 2nd +/// +/// +/// +/// +///

+/// Similarly, the following example uses an instance of this class to call an instance method... +///

+/// +/// +/// +/// +/// +/// +/// +/// +/// +///

+/// The above example could also have been written using an anonymous inner object definition... if the +/// object on which the method is to be invoked is not going to be used outside of the factory object +/// definition, then this is the preferred idiom because it limits the scope of the object on which the +/// method is to be invoked to the surrounding factory object. +///

+/// +/// +/// +/// +/// +/// +/// +/// +/// +/// Colin Sampaleanu +/// Juergen Hoeller +/// Rick Evans (.NET) +/// Simon White (.NET) +/// +/// +[Serializable] +public class MethodInvokingFactoryObject : ArgumentConvertingMethodInvoker, IFactoryObject, IInitializingObject { - /// - /// An that returns a value - /// that is the result of a or instance method invocation. - /// - /// - ///

- /// Note that this class generally is expected to be used for accessing factory methods, - /// and as such defaults to operating in singleton mode. The first request to - /// - /// by the owning object factory will cause a method invocation, the return - /// value of which will be cached for all subsequent requests. The - /// property may be set to - /// , to cause this factory to invoke the target method each - /// time it is asked for an object. - ///

- ///

- /// A target method may be specified by setting the - /// property to a string representing - /// the method name, with specifying - /// the that the method is defined on. - /// Alternatively, a target instance method may be specified, by setting the - /// property as the target object, and - /// the property as the name of the - /// method to call on that target object. Arguments for the method invocation may be - /// specified by setting the property. - ///

- ///

- /// Another (esoteric) use case for this factory object is when one needs to call a method - /// that doesn't return any value (for example, a class method to - /// force some sort of initialization to happen)... this use case is not supported by - /// factory-methods, since a return value is needed to become the object. - ///

- ///

- /// - /// This class depends on the - /// - /// method being called after all properties have been set, as per the - /// contract. If you are - /// using this class outside of a Spring.NET IoC container, you must call one of either - /// or - /// yourself to ready the object's internal - /// state, or you will get a nasty . - /// - ///

- ///
- /// - ///

- /// The following example uses an instance of this class to call a - /// factory method... - ///

- /// - /// - /// - /// - /// - /// - /// - /// 1st - /// 2nd - /// and 3rd arguments - /// - /// - /// - /// - ///

- /// The following example is similar to the preceding example; the only pertinent difference is the fact that - /// a number of different objects are passed as arguments, demonstrating that not only simple value types - /// are valid as elements of the argument list... - ///

- /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// 1st - /// - /// - /// - /// - /// - /// - /// http://www.springframework.net/ - /// - /// - /// - /// - /// - ///

- /// Named parameters are also supported... this next example yields the same results as - /// the preceding example (that did not use named arguments). - ///

- /// - /// - /// - /// - /// - /// - /// - /// - /// - /// 1st - /// and 3rd arguments - /// 2nd - /// - /// - /// - /// - ///

- /// Similarly, the following example uses an instance of this class to call an instance method... - ///

- /// - /// - /// - /// - /// - /// - /// - /// - /// - ///

- /// The above example could also have been written using an anonymous inner object definition... if the - /// object on which the method is to be invoked is not going to be used outside of the factory object - /// definition, then this is the preferred idiom because it limits the scope of the object on which the - /// method is to be invoked to the surrounding factory object. - ///

- /// - /// - /// - /// - /// - /// - /// - /// - /// - /// Colin Sampaleanu - /// Juergen Hoeller - /// Rick Evans (.NET) - /// Simon White (.NET) - /// - /// - [Serializable] - public class MethodInvokingFactoryObject : ArgumentConvertingMethodInvoker, IFactoryObject, IInitializingObject - { - private bool singleton = true; - private object singletonObject; + private bool singleton = true; + private object singletonObject; - /// - /// If a singleton should be created, or a new object on each request. - /// Defaults to . - /// - public bool IsSingleton - { - get { return singleton; } - set { singleton = value; } - } + /// + /// If a singleton should be created, or a new object on each request. + /// Defaults to . + /// + public bool IsSingleton + { + get { return singleton; } + set { singleton = value; } + } - /// - /// Return the return value of the method - /// that this factory invokes, or if not - /// known in advance. - /// - /// - ///

- /// If the return value of the method that this factory is to invoke is - /// , then the - /// will be returned (in accordance with the - /// contract that - /// treats a value as a configuration error). - ///

- ///
- /// - public Type ObjectType - { - get - { - Type objectType = null; - if (GetPreparedMethod() != null) - { - objectType = GetPreparedMethod().ReturnType; - if (objectType.Equals(typeof (void))) - { - objectType = Void.GetType(); - } - } - return objectType; - } - } + /// + /// Return the return value of the method + /// that this factory invokes, or if not + /// known in advance. + /// + /// + ///

+ /// If the return value of the method that this factory is to invoke is + /// , then the + /// will be returned (in accordance with the + /// contract that + /// treats a value as a configuration error). + ///

+ ///
+ /// + public Type ObjectType + { + get + { + Type objectType = null; + if (GetPreparedMethod() != null) + { + objectType = GetPreparedMethod().ReturnType; + if (objectType.Equals(typeof(void))) + { + objectType = Void.GetType(); + } + } - /// - /// Return an instance (possibly shared or independent) of the object - /// managed by this factory. - /// - /// - ///

- /// Returns the return value of the method that is to be invoked. - ///

- ///

- /// Will return the same value each time if the - /// - /// property value is . - ///

- ///
- /// - /// An instance (possibly shared or independent) of the object managed by - /// this factory. - /// - /// - public object GetObject() - { - if (singleton) - { - if (singletonObject == null) - { - singletonObject = Invoke(); - } - return singletonObject; - } - return Invoke(); - } + return objectType; + } + } - /// - /// Prepares this method invoker. - /// - /// - /// If all required properties are not set. - /// - /// - /// If the specified method could not be found. - /// - /// - public void AfterPropertiesSet() - { - Prepare(); - } - } + /// + /// Return an instance (possibly shared or independent) of the object + /// managed by this factory. + /// + /// + ///

+ /// Returns the return value of the method that is to be invoked. + ///

+ ///

+ /// Will return the same value each time if the + /// + /// property value is . + ///

+ ///
+ /// + /// An instance (possibly shared or independent) of the object managed by + /// this factory. + /// + /// + public object GetObject() + { + if (singleton) + { + if (singletonObject == null) + { + singletonObject = Invoke(); + } + + return singletonObject; + } + + return Invoke(); + } + + /// + /// Prepares this method invoker. + /// + /// + /// If all required properties are not set. + /// + /// + /// If the specified method could not be found. + /// + /// + public void AfterPropertiesSet() + { + Prepare(); + } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/ObjectDefinitionHolder.cs b/src/Spring/Spring.Core/Objects/Factory/Config/ObjectDefinitionHolder.cs index fa6d2afe..2667ce90 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/ObjectDefinitionHolder.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/ObjectDefinitionHolder.cs @@ -17,108 +17,107 @@ using Spring.Objects.Factory.Xml; using Spring.Util; -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Holder for an with +/// name and aliases. +/// +/// +///

+/// Recognized by +/// +/// for inner object definitions. Registered by +/// , +/// which also uses it as general holder for a parsed object definition. +///

+///

+/// Can also be used for programmatic registration of inner object +/// definitions. If you don't care about the functionality offered by the +/// interface and the like, +/// registering +/// or is good enough. +///

+///
+/// Juergen Hoeller +/// Simon White (.NET) +[Serializable] +public class ObjectDefinitionHolder { + private readonly IObjectDefinition objectDefinition; + private readonly string objectName; + private readonly List aliases; + /// - /// Holder for an with - /// name and aliases. + /// Creates a new instance of the + /// class. + /// + /// + /// The object definition to be held by this instance. + /// + /// + /// The name of the object definition. + /// + public ObjectDefinitionHolder(IObjectDefinition definition, string name) + : this(definition, name, StringUtils.EmptyStrings) + { + } + + /// + /// Creates a new instance of the + /// class. + /// + /// + /// The object definition to be held by this instance. + /// + /// The name of the object. + /// + /// Any aliases for the supplied + /// + public ObjectDefinitionHolder( + IObjectDefinition definition, + string name, + IReadOnlyList aliases) + { + objectDefinition = definition; + objectName = name; + this.aliases = aliases != null && aliases.Count > 0 + ? new List(aliases) + : null; + } + + /// + /// The held by this + /// instance. + /// + public IObjectDefinition ObjectDefinition => objectDefinition; + + /// + /// The name of the object definition. + /// + public string ObjectName => objectName; + + /// + /// Any aliases for the object definition. /// /// ///

- /// Recognized by - /// - /// for inner object definitions. Registered by - /// , - /// which also uses it as general holder for a parsed object definition. - ///

- ///

- /// Can also be used for programmatic registration of inner object - /// definitions. If you don't care about the functionality offered by the - /// interface and the like, - /// registering - /// or is good enough. + /// Guaranteed to never return ; if the associated + /// + /// does not have any aliases associated with it, then an empty + /// array will be returned. ///

///
- /// Juergen Hoeller - /// Simon White (.NET) - [Serializable] - public class ObjectDefinitionHolder + public IReadOnlyList Aliases => aliases ?? StringUtils.EmptyStringsList; + + /// + /// Checks wether a givin candidate name has a defined object or alias + /// + /// name to check if exists + /// + public bool MatchesName(string candidateName) { - private readonly IObjectDefinition objectDefinition; - private readonly string objectName; - private readonly List aliases; - - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The object definition to be held by this instance. - /// - /// - /// The name of the object definition. - /// - public ObjectDefinitionHolder(IObjectDefinition definition, string name) - : this(definition, name, StringUtils.EmptyStrings) - { - } - - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The object definition to be held by this instance. - /// - /// The name of the object. - /// - /// Any aliases for the supplied - /// - public ObjectDefinitionHolder( - IObjectDefinition definition, - string name, - IReadOnlyList aliases) - { - objectDefinition = definition; - objectName = name; - this.aliases = aliases != null && aliases.Count > 0 - ? new List(aliases) - : null; - } - - /// - /// The held by this - /// instance. - /// - public IObjectDefinition ObjectDefinition => objectDefinition; - - /// - /// The name of the object definition. - /// - public string ObjectName => objectName; - - /// - /// Any aliases for the object definition. - /// - /// - ///

- /// Guaranteed to never return ; if the associated - /// - /// does not have any aliases associated with it, then an empty - /// array will be returned. - ///

- ///
- public IReadOnlyList Aliases => aliases ?? StringUtils.EmptyStringsList; - - /// - /// Checks wether a givin candidate name has a defined object or alias - /// - /// name to check if exists - /// - public bool MatchesName(string candidateName) - { - return !string.IsNullOrEmpty(candidateName) - && (candidateName == ObjectName || aliases?.Contains(candidateName) == true); - } + return !string.IsNullOrEmpty(candidateName) + && (candidateName == ObjectName || aliases?.Contains(candidateName) == true); } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/ObjectDefinitionVisitor.cs b/src/Spring/Spring.Core/Objects/Factory/Config/ObjectDefinitionVisitor.cs index 6fd7b85f..1ef1bc13 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/ObjectDefinitionVisitor.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/ObjectDefinitionVisitor.cs @@ -20,369 +20,367 @@ using System.Collections; using System.Collections.Specialized; - using Spring.Collections; using Spring.Util; -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Visitor class for traversing objects, in particular +/// the property values and constructor arguments contained in them resolving +/// object metadata values. +/// +/// +/// Used by and +/// to parse all string values contained in a ObjectDefinition, resolving any placeholders found. +/// +/// Mark Pollack +public class ObjectDefinitionVisitor { + public delegate string ResolveHandler(string rawStringValue); + + private readonly ResolveHandler resolveHandler; + /// - /// Visitor class for traversing objects, in particular - /// the property values and constructor arguments contained in them resolving - /// object metadata values. + /// Initializes a new instance of the class. /// - /// - /// Used by and - /// to parse all string values contained in a ObjectDefinition, resolving any placeholders found. - /// - /// Mark Pollack - public class ObjectDefinitionVisitor + /// The handler to be called for resolving variables contained in a string. + public ObjectDefinitionVisitor(ResolveHandler resolveHandler) { - public delegate string ResolveHandler(string rawStringValue); + AssertUtils.ArgumentNotNull(resolveHandler, "ResovleHandler"); + this.resolveHandler = resolveHandler; + } - private readonly ResolveHandler resolveHandler; + /// + /// Initializes a new instance of the class + /// for subclassing + /// + /// Subclasses should override the ResolveStringValue method + protected ObjectDefinitionVisitor() + { + } - /// - /// Initializes a new instance of the class. - /// - /// The handler to be called for resolving variables contained in a string. - public ObjectDefinitionVisitor(ResolveHandler resolveHandler) + /// + /// Traverse the given ObjectDefinition object and the MutablePropertyValues + /// and ConstructorArgumentValues contained in them. + /// + /// The object definition to traverse. + public virtual void VisitObjectDefinition(IObjectDefinition definition) + { + VisitObjectTypeName(definition); + VisitPropertyValues(definition); + + ConstructorArgumentValues cas = definition.ConstructorArgumentValues; + if (cas != null) { - AssertUtils.ArgumentNotNull(resolveHandler, "ResovleHandler"); - this.resolveHandler = resolveHandler; - } - - /// - /// Initializes a new instance of the class - /// for subclassing - /// - /// Subclasses should override the ResolveStringValue method - protected ObjectDefinitionVisitor() - { - } - - /// - /// Traverse the given ObjectDefinition object and the MutablePropertyValues - /// and ConstructorArgumentValues contained in them. - /// - /// The object definition to traverse. - public virtual void VisitObjectDefinition(IObjectDefinition definition) - { - VisitObjectTypeName(definition); - VisitPropertyValues(definition); - - ConstructorArgumentValues cas = definition.ConstructorArgumentValues; - if (cas != null) - { - VisitIndexedArgumentValues(cas.IndexedArgumentValues); - VisitNamedArgumentValues(cas.NamedArgumentValues); - VisitGenericArgumentValues(cas.GenericArgumentValues); - } - } - - /// - /// Visits the ObjectDefinition property ObjectTypeName, replacing string values using - /// the specified IVariableSource. - /// - /// The object definition. - protected virtual void VisitObjectTypeName(IObjectDefinition objectDefinition) - { - string objectTypeName = objectDefinition.ObjectTypeName; - if (objectTypeName != null) - { - string resolvedName = ResolveStringValue(objectTypeName); - if (!objectTypeName.Equals(resolvedName)) - { - objectDefinition.ObjectTypeName = resolvedName; - } - } - } - - - /// - /// Visits the property values of the ObjectDefinition, replacing string values - /// using the specified IVariableSource. - /// - /// The object definition. - protected virtual void VisitPropertyValues(IObjectDefinition objectDefinition) - { - MutablePropertyValues pvs = objectDefinition.PropertyValues; - if (pvs != null) - { - for (int j = 0; j < pvs.PropertyValues.Count; j++) - { - PropertyValue pv = pvs.PropertyValues[j]; - object newVal = ResolveValue(pv.Value); - if (!ObjectUtils.NullSafeEquals(newVal, pv.Value)) - { - pvs.Add(pv.Name, newVal); - } - } - } - } - - /// - /// Visits the indexed constructor argument values, replacing string values using the - /// specified IVariableSource. - /// - /// The indexed argument values. - protected virtual void VisitIndexedArgumentValues(IReadOnlyDictionary ias) - { - foreach (ConstructorArgumentValues.ValueHolder valueHolder in ias.Values) - { - ConfigureConstructorArgument(valueHolder); - } - } - - /// - /// Visits the named constructor argument values, replacing string values using the - /// specified IVariableSource. - /// - /// The named argument values. - protected virtual void VisitNamedArgumentValues(IReadOnlyDictionary nav) - { - foreach (ConstructorArgumentValues.ValueHolder valueHolder in nav.Values) - { - ConfigureConstructorArgument(valueHolder); - } - } - - /// - /// Visits the generic constructor argument values, replacing string values using - /// the specified IVariableSource. - /// - /// The genreic argument values. - protected virtual void VisitGenericArgumentValues(IReadOnlyList gav) - { - for (var i = 0; i < gav.Count; i++) - { - ConfigureConstructorArgument(gav[i]); - } - } - - /// - /// Configures the constructor argument ValueHolder. - /// - /// The vconstructor alue holder. - protected void ConfigureConstructorArgument(ConstructorArgumentValues.ValueHolder valueHolder) - { - object newVal = ResolveValue(valueHolder.Value); - if (!ObjectUtils.NullSafeEquals(newVal, valueHolder.Value)) - { - valueHolder.Value = newVal; - } - } - - /// - /// Resolves the given value taken from an object definition according to its type - /// - /// the value to resolve - /// the resolved value - protected virtual object ResolveValue(object value) - { - if (value is IObjectDefinition definition) - { - VisitObjectDefinition(definition); - } - else if (value is ObjectDefinitionHolder definitionHolder) - { - VisitObjectDefinition( definitionHolder.ObjectDefinition); - } - else if (value is RuntimeObjectReference ror) - { - //name has to be of string type. - string newObjectName = ResolveStringValue(ror.ObjectName); - if (!newObjectName.Equals(ror.ObjectName)) - { - return new RuntimeObjectReference(newObjectName); - } - } - else if (value is ManagedList list) - { - VisitManagedList(list); - } - else if (value is ManagedSet set) - { - VisitManagedSet(set); - } - else if (value is ManagedDictionary dictionary) - { - VisitManagedDictionary(dictionary); - } - else if (value is NameValueCollection collection) - { - VisitNameValueCollection(collection); - } - else if (value is TypedStringValue typedStringValue) - { - String stringValue = typedStringValue.Value; - if (stringValue != null) - { - String visitedString = ResolveStringValue(stringValue); - typedStringValue.Value = visitedString; - } - } - else if (value is string s) - { - return ResolveStringValue(s); - } - else if (value is ExpressionHolder holder) - { - string newExpressionString = ResolveStringValue(holder.ExpressionString); - return new ExpressionHolder(newExpressionString); - } - return value; - } - - /// - /// Visits the ManagedList property ElementTypeName and - /// calls for list element. - /// - protected virtual void VisitManagedList(ManagedList listVal) - { - string elementTypeName = listVal.ElementTypeName; - if (elementTypeName != null) - { - string resolvedName = ResolveStringValue(elementTypeName); - if (!elementTypeName.Equals(resolvedName)) - { - listVal.ElementTypeName = resolvedName; - } - } - - for (int i = 0; i < listVal.Count; ++i) - { - object oldValue = listVal[i]; - object newValue = ResolveValue(oldValue); - if (!ObjectUtils.NullSafeEquals(newValue, oldValue)) - { - listVal[i] = newValue; - } - } - } - - /// - /// Visits the ManagedSet property ElementTypeName and - /// calls for list element. - /// - protected virtual void VisitManagedSet(ManagedSet setVal) - { - string elementTypeName = setVal.ElementTypeName; - if (elementTypeName != null) - { - string resolvedName = ResolveStringValue(elementTypeName); - if (!elementTypeName.Equals(resolvedName)) - { - setVal.ElementTypeName = resolvedName; - } - } - - ISet clone = (ISet)setVal.Clone(); - foreach (object oldValue in clone) - { - object newValue = ResolveValue(oldValue); - if (!ObjectUtils.NullSafeEquals(newValue, oldValue)) - { - setVal.Remove(oldValue); - setVal.Add(newValue); - } - } - } - - /// - /// Visits the ManagedSet properties KeyTypeName and ValueTypeName and - /// calls for dictionary's value element. - /// - protected virtual void VisitManagedDictionary(ManagedDictionary dictVal) - { - string keyTypeName = dictVal.KeyTypeName; - if (keyTypeName != null) - { - string resolvedName = ResolveStringValue(keyTypeName); - if (!keyTypeName.Equals(resolvedName)) - { - dictVal.KeyTypeName = resolvedName; - } - } - - string valueTypeName = dictVal.ValueTypeName; - if (valueTypeName != null) - { - string resolvedName = ResolveStringValue(valueTypeName); - if (!valueTypeName.Equals(resolvedName)) - { - dictVal.ValueTypeName = resolvedName; - } - } - - Hashtable mods = new Hashtable(); - bool entriesModified = false; - foreach (DictionaryEntry entry in dictVal) - { - /* - - object oldValue = entry.Value; - object newValue = ResolveValue(oldValue); - if (!ObjectUtils.NullSafeEquals(newValue, oldValue)) - { - mods[entry.Key] = newValue; - }*/ - - object key = entry.Key; - object newKey = ResolveValue(key); - object oldValue = entry.Value; - object newValue = ResolveValue(oldValue); - - if (!ObjectUtils.NullSafeEquals(newValue, oldValue) || key != newKey) - { - entriesModified = true; - } - mods[newKey] = newValue; - - } - if (entriesModified) - { - dictVal.Clear(); - foreach (DictionaryEntry entry in mods) - { - dictVal[entry.Key] = entry.Value; - } - } - - } - - /// - /// Visits the elements of a NameValueCollection and calls - /// for value of each element. - /// - protected virtual void VisitNameValueCollection(NameValueCollection collection) - { - foreach (string key in collection.AllKeys) - { - string oldValue = collection[key]; - string newValue = ResolveValue(oldValue) as string; - if (!ObjectUtils.NullSafeEquals(newValue, oldValue)) - { - collection[key] = newValue; - } - } - } - - /// - /// calls the to resolve any variables contained in the raw string. - /// - /// the raw string value containing variable placeholders to be resolved - /// If no has been configured. - /// the resolved string, having variables being replaced, if any - protected virtual string ResolveStringValue(string rawStringValue) - { - if (resolveHandler == null) - { - throw new InvalidOperationException("No resolveHandler specified - pass an instance " + - "into the constructor or override the 'ResolveStringValue' method"); - } - - return resolveHandler(rawStringValue); + VisitIndexedArgumentValues(cas.IndexedArgumentValues); + VisitNamedArgumentValues(cas.NamedArgumentValues); + VisitGenericArgumentValues(cas.GenericArgumentValues); } } + + /// + /// Visits the ObjectDefinition property ObjectTypeName, replacing string values using + /// the specified IVariableSource. + /// + /// The object definition. + protected virtual void VisitObjectTypeName(IObjectDefinition objectDefinition) + { + string objectTypeName = objectDefinition.ObjectTypeName; + if (objectTypeName != null) + { + string resolvedName = ResolveStringValue(objectTypeName); + if (!objectTypeName.Equals(resolvedName)) + { + objectDefinition.ObjectTypeName = resolvedName; + } + } + } + + /// + /// Visits the property values of the ObjectDefinition, replacing string values + /// using the specified IVariableSource. + /// + /// The object definition. + protected virtual void VisitPropertyValues(IObjectDefinition objectDefinition) + { + MutablePropertyValues pvs = objectDefinition.PropertyValues; + if (pvs != null) + { + for (int j = 0; j < pvs.PropertyValues.Count; j++) + { + PropertyValue pv = pvs.PropertyValues[j]; + object newVal = ResolveValue(pv.Value); + if (!ObjectUtils.NullSafeEquals(newVal, pv.Value)) + { + pvs.Add(pv.Name, newVal); + } + } + } + } + + /// + /// Visits the indexed constructor argument values, replacing string values using the + /// specified IVariableSource. + /// + /// The indexed argument values. + protected virtual void VisitIndexedArgumentValues(IReadOnlyDictionary ias) + { + foreach (ConstructorArgumentValues.ValueHolder valueHolder in ias.Values) + { + ConfigureConstructorArgument(valueHolder); + } + } + + /// + /// Visits the named constructor argument values, replacing string values using the + /// specified IVariableSource. + /// + /// The named argument values. + protected virtual void VisitNamedArgumentValues(IReadOnlyDictionary nav) + { + foreach (ConstructorArgumentValues.ValueHolder valueHolder in nav.Values) + { + ConfigureConstructorArgument(valueHolder); + } + } + + /// + /// Visits the generic constructor argument values, replacing string values using + /// the specified IVariableSource. + /// + /// The genreic argument values. + protected virtual void VisitGenericArgumentValues(IReadOnlyList gav) + { + for (var i = 0; i < gav.Count; i++) + { + ConfigureConstructorArgument(gav[i]); + } + } + + /// + /// Configures the constructor argument ValueHolder. + /// + /// The vconstructor alue holder. + protected void ConfigureConstructorArgument(ConstructorArgumentValues.ValueHolder valueHolder) + { + object newVal = ResolveValue(valueHolder.Value); + if (!ObjectUtils.NullSafeEquals(newVal, valueHolder.Value)) + { + valueHolder.Value = newVal; + } + } + + /// + /// Resolves the given value taken from an object definition according to its type + /// + /// the value to resolve + /// the resolved value + protected virtual object ResolveValue(object value) + { + if (value is IObjectDefinition definition) + { + VisitObjectDefinition(definition); + } + else if (value is ObjectDefinitionHolder definitionHolder) + { + VisitObjectDefinition(definitionHolder.ObjectDefinition); + } + else if (value is RuntimeObjectReference ror) + { + //name has to be of string type. + string newObjectName = ResolveStringValue(ror.ObjectName); + if (!newObjectName.Equals(ror.ObjectName)) + { + return new RuntimeObjectReference(newObjectName); + } + } + else if (value is ManagedList list) + { + VisitManagedList(list); + } + else if (value is ManagedSet set) + { + VisitManagedSet(set); + } + else if (value is ManagedDictionary dictionary) + { + VisitManagedDictionary(dictionary); + } + else if (value is NameValueCollection collection) + { + VisitNameValueCollection(collection); + } + else if (value is TypedStringValue typedStringValue) + { + String stringValue = typedStringValue.Value; + if (stringValue != null) + { + String visitedString = ResolveStringValue(stringValue); + typedStringValue.Value = visitedString; + } + } + else if (value is string s) + { + return ResolveStringValue(s); + } + else if (value is ExpressionHolder holder) + { + string newExpressionString = ResolveStringValue(holder.ExpressionString); + return new ExpressionHolder(newExpressionString); + } + + return value; + } + + /// + /// Visits the ManagedList property ElementTypeName and + /// calls for list element. + /// + protected virtual void VisitManagedList(ManagedList listVal) + { + string elementTypeName = listVal.ElementTypeName; + if (elementTypeName != null) + { + string resolvedName = ResolveStringValue(elementTypeName); + if (!elementTypeName.Equals(resolvedName)) + { + listVal.ElementTypeName = resolvedName; + } + } + + for (int i = 0; i < listVal.Count; ++i) + { + object oldValue = listVal[i]; + object newValue = ResolveValue(oldValue); + if (!ObjectUtils.NullSafeEquals(newValue, oldValue)) + { + listVal[i] = newValue; + } + } + } + + /// + /// Visits the ManagedSet property ElementTypeName and + /// calls for list element. + /// + protected virtual void VisitManagedSet(ManagedSet setVal) + { + string elementTypeName = setVal.ElementTypeName; + if (elementTypeName != null) + { + string resolvedName = ResolveStringValue(elementTypeName); + if (!elementTypeName.Equals(resolvedName)) + { + setVal.ElementTypeName = resolvedName; + } + } + + ISet clone = (ISet) setVal.Clone(); + foreach (object oldValue in clone) + { + object newValue = ResolveValue(oldValue); + if (!ObjectUtils.NullSafeEquals(newValue, oldValue)) + { + setVal.Remove(oldValue); + setVal.Add(newValue); + } + } + } + + /// + /// Visits the ManagedSet properties KeyTypeName and ValueTypeName and + /// calls for dictionary's value element. + /// + protected virtual void VisitManagedDictionary(ManagedDictionary dictVal) + { + string keyTypeName = dictVal.KeyTypeName; + if (keyTypeName != null) + { + string resolvedName = ResolveStringValue(keyTypeName); + if (!keyTypeName.Equals(resolvedName)) + { + dictVal.KeyTypeName = resolvedName; + } + } + + string valueTypeName = dictVal.ValueTypeName; + if (valueTypeName != null) + { + string resolvedName = ResolveStringValue(valueTypeName); + if (!valueTypeName.Equals(resolvedName)) + { + dictVal.ValueTypeName = resolvedName; + } + } + + Hashtable mods = new Hashtable(); + bool entriesModified = false; + foreach (DictionaryEntry entry in dictVal) + { + /* + + object oldValue = entry.Value; + object newValue = ResolveValue(oldValue); + if (!ObjectUtils.NullSafeEquals(newValue, oldValue)) + { + mods[entry.Key] = newValue; + }*/ + + object key = entry.Key; + object newKey = ResolveValue(key); + object oldValue = entry.Value; + object newValue = ResolveValue(oldValue); + + if (!ObjectUtils.NullSafeEquals(newValue, oldValue) || key != newKey) + { + entriesModified = true; + } + + mods[newKey] = newValue; + } + + if (entriesModified) + { + dictVal.Clear(); + foreach (DictionaryEntry entry in mods) + { + dictVal[entry.Key] = entry.Value; + } + } + } + + /// + /// Visits the elements of a NameValueCollection and calls + /// for value of each element. + /// + protected virtual void VisitNameValueCollection(NameValueCollection collection) + { + foreach (string key in collection.AllKeys) + { + string oldValue = collection[key]; + string newValue = ResolveValue(oldValue) as string; + if (!ObjectUtils.NullSafeEquals(newValue, oldValue)) + { + collection[key] = newValue; + } + } + } + + /// + /// calls the to resolve any variables contained in the raw string. + /// + /// the raw string value containing variable placeholders to be resolved + /// If no has been configured. + /// the resolved string, having variables being replaced, if any + protected virtual string ResolveStringValue(string rawStringValue) + { + if (resolveHandler == null) + { + throw new InvalidOperationException("No resolveHandler specified - pass an instance " + + "into the constructor or override the 'ResolveStringValue' method"); + } + + return resolveHandler(rawStringValue); + } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/ObjectFactoryCreatingFactoryObject.cs b/src/Spring/Spring.Core/Objects/Factory/Config/ObjectFactoryCreatingFactoryObject.cs index 9098ecd4..5609b019 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/ObjectFactoryCreatingFactoryObject.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/ObjectFactoryCreatingFactoryObject.cs @@ -20,153 +20,153 @@ using Spring.Util; -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Returns a value that is an +/// that +/// returns an object from an +/// . +/// +/// +///

+/// The primary motivation of this class is to avoid having a client object +/// directly calling the +/// +/// method to get a prototype object out of an +/// , which would be a +/// violation of the inversion of control principle. With the use of this +/// class, the client object can be fed an +/// as a property +/// that directly returns one target prototype object. +///

+///

+/// The object referred to by the value of the +/// +/// property does not have to be a prototype object, but there is little +/// to no point in using this class in conjunction with a singleton object. +///

+///
+/// +///

+/// The following XML configuration snippet illustrates the use of this +/// class... +///

+/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// Colin Sampaleanu +/// Simon White (.NET) +[Serializable] +public class ObjectFactoryCreatingFactoryObject + : AbstractFactoryObject, IObjectFactoryAware { - /// - /// Returns a value that is an - /// that - /// returns an object from an - /// . - /// - /// - ///

- /// The primary motivation of this class is to avoid having a client object - /// directly calling the - /// - /// method to get a prototype object out of an - /// , which would be a - /// violation of the inversion of control principle. With the use of this - /// class, the client object can be fed an - /// as a property - /// that directly returns one target prototype object. - ///

- ///

- /// The object referred to by the value of the - /// - /// property does not have to be a prototype object, but there is little - /// to no point in using this class in conjunction with a singleton object. - ///

- ///
- /// - ///

- /// The following XML configuration snippet illustrates the use of this - /// class... - ///

- /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// Colin Sampaleanu - /// Simon White (.NET) - [Serializable] - public class ObjectFactoryCreatingFactoryObject - : AbstractFactoryObject, IObjectFactoryAware - { - private string _targetObjectName; - private IObjectFactory _objectFactory; + private string _targetObjectName; + private IObjectFactory _objectFactory; - #region Properties + #region Properties - /// - /// Sets the name of the target object. - /// - public string TargetObjectName - { - set { _targetObjectName = value; } - } + /// + /// Sets the name of the target object. + /// + public string TargetObjectName + { + set { _targetObjectName = value; } + } - /// - /// The target factory that will be used to perform the lookup - /// of the object referred to by the - /// property. - /// - /// - /// The owning - /// (will never be ). - /// - /// - /// In case of initialization errors. - /// - /// - public IObjectFactory ObjectFactory - { - set { this._objectFactory = value; } - } + /// + /// The target factory that will be used to perform the lookup + /// of the object referred to by the + /// property. + /// + /// + /// The owning + /// (will never be ). + /// + /// + /// In case of initialization errors. + /// + /// + public IObjectFactory ObjectFactory + { + set { this._objectFactory = value; } + } - /// - /// The of object created by this factory. - /// - public override Type ObjectType - { - get { return typeof (IGenericObjectFactory); } - } + /// + /// The of object created by this factory. + /// + public override Type ObjectType + { + get { return typeof(IGenericObjectFactory); } + } - #endregion + #endregion - /// - /// Returns an instance of the object factory. - /// - /// The object factory. - protected override object CreateInstance() - { - return new GenericObjectFactory(this); - } + /// + /// Returns an instance of the object factory. + /// + /// The object factory. + protected override object CreateInstance() + { + return new GenericObjectFactory(this); + } - /// - /// Invoked by an - /// after it has set all supplied object properties. - /// - /// - /// In the event of misconfiguration (such as failure to set an essential - /// property) or if initialization fails. - /// - /// - public override void AfterPropertiesSet() - { - if(StringUtils.IsNullOrEmpty(_targetObjectName)) - { - throw new ArgumentException("The 'TargetObjectName' property must have a value."); - } - base.AfterPropertiesSet (); - } + /// + /// Invoked by an + /// after it has set all supplied object properties. + /// + /// + /// In the event of misconfiguration (such as failure to set an essential + /// property) or if initialization fails. + /// + /// + public override void AfterPropertiesSet() + { + if (StringUtils.IsNullOrEmpty(_targetObjectName)) + { + throw new ArgumentException("The 'TargetObjectName' property must have a value."); + } - private sealed class GenericObjectFactory : IGenericObjectFactory - { - private ObjectFactoryCreatingFactoryObject _enclosing; + base.AfterPropertiesSet(); + } - /// - /// Creates a new instance of the GenericObjectFactory class. - /// - /// - /// The enclosing - /// . - /// - public GenericObjectFactory( - ObjectFactoryCreatingFactoryObject enclosing) - { - _enclosing = enclosing; - } + private sealed class GenericObjectFactory : IGenericObjectFactory + { + private ObjectFactoryCreatingFactoryObject _enclosing; - /// - /// Returns the object created by the enclosed object factory. - /// - /// The created object. - public object GetObject() - { - return _enclosing._objectFactory.GetObject(_enclosing._targetObjectName); - } - } - } + /// + /// Creates a new instance of the GenericObjectFactory class. + /// + /// + /// The enclosing + /// . + /// + public GenericObjectFactory( + ObjectFactoryCreatingFactoryObject enclosing) + { + _enclosing = enclosing; + } + + /// + /// Returns the object created by the enclosed object factory. + /// + /// The created object. + public object GetObject() + { + return _enclosing._objectFactory.GetObject(_enclosing._targetObjectName); + } + } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/ObjectReferenceFactoryObject.cs b/src/Spring/Spring.Core/Objects/Factory/Config/ObjectReferenceFactoryObject.cs index 8d83bfe6..fdee018c 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/ObjectReferenceFactoryObject.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/ObjectReferenceFactoryObject.cs @@ -20,130 +20,131 @@ using Spring.Util; -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// An implementation +/// that exposes an arbitrary target object under a different name. +/// +/// +///

+/// Usually, the target object will reside in a different object +/// definition file, using this +/// to link it in +/// and expose it under a different name. Effectively, this corresponds +/// to an alias for the target object. +///

+/// +/// For XML based object definition files, a <alias> +/// tag is available that effectively achieves the same. +/// +///
+/// Juergen Hoeller +/// Rick Evans (.NET) +/// +[Serializable] +public sealed class ObjectReferenceFactoryObject + : IFactoryObject, IObjectFactoryAware { - /// - /// An implementation - /// that exposes an arbitrary target object under a different name. - /// - /// - ///

- /// Usually, the target object will reside in a different object - /// definition file, using this - /// to link it in - /// and expose it under a different name. Effectively, this corresponds - /// to an alias for the target object. - ///

- /// - /// For XML based object definition files, a <alias> - /// tag is available that effectively achieves the same. - /// - ///
- /// Juergen Hoeller - /// Rick Evans (.NET) - /// - [Serializable] - public sealed class ObjectReferenceFactoryObject - : IFactoryObject, IObjectFactoryAware - { - private string _targetObjectName; - private IObjectFactory _objectFactory; + private string _targetObjectName; + private IObjectFactory _objectFactory; - /// - /// Initialize a new default instance - /// - public ObjectReferenceFactoryObject() - { - } - /// - /// Initialize this instance with the predefined and . - /// - /// - /// - public ObjectReferenceFactoryObject(string targetObjectName, IObjectFactory objectFactory) - { - this.TargetObjectName = targetObjectName; - this.ObjectFactory = objectFactory; - } + /// + /// Initialize a new default instance + /// + public ObjectReferenceFactoryObject() + { + } - /// - /// The name of the target object. - /// - /// - ///

- /// The target object may potentially be defined in a different object - /// definition file. - ///

- ///
- /// The name of the target object. - public string TargetObjectName - { - set { _targetObjectName = value; } - } + /// + /// Initialize this instance with the predefined and . + /// + /// + /// + public ObjectReferenceFactoryObject(string targetObjectName, IObjectFactory objectFactory) + { + this.TargetObjectName = targetObjectName; + this.ObjectFactory = objectFactory; + } - /// - /// Return an instance (possibly shared or independent) of the object - /// managed by this factory. - /// - /// - /// An instance (possibly shared or independent) of the object managed by - /// this factory. - /// - /// - public object GetObject() - { - return _objectFactory.GetObject(_targetObjectName); - } + /// + /// The name of the target object. + /// + /// + ///

+ /// The target object may potentially be defined in a different object + /// definition file. + ///

+ ///
+ /// The name of the target object. + public string TargetObjectName + { + set { _targetObjectName = value; } + } - /// - /// Return the type of object that this - /// creates, or - /// if not known in advance. - /// - /// - public Type ObjectType - { - get { return _objectFactory.GetType(_targetObjectName); } - } + /// + /// Return an instance (possibly shared or independent) of the object + /// managed by this factory. + /// + /// + /// An instance (possibly shared or independent) of the object managed by + /// this factory. + /// + /// + public object GetObject() + { + return _objectFactory.GetObject(_targetObjectName); + } - /// - /// Is the object managed by this factory a singleton or a prototype? - /// - /// - public bool IsSingleton - { - get { return _objectFactory.IsSingleton(_targetObjectName); } - } + /// + /// Return the type of object that this + /// creates, or + /// if not known in advance. + /// + /// + public Type ObjectType + { + get { return _objectFactory.GetType(_targetObjectName); } + } - /// - /// Callback that supplies the owning factory to an object instance. - /// - /// - /// The owning - /// (may not be ). The object can immediately - /// call methods on the factory. - /// - /// - /// In case of initialization errors. - /// - /// - public IObjectFactory ObjectFactory - { - set - { - // the call to set this property occurs 'after' all properties have been set... - _objectFactory = value; - if (StringUtils.IsNullOrEmpty(_targetObjectName)) - { - throw new ArgumentException( - "The 'TargetObjectName' property is required."); - } - if (!_objectFactory.ContainsObject(_targetObjectName)) - { - throw new NoSuchObjectDefinitionException( - _targetObjectName, _objectFactory.ToString()); - } - } - } - } + /// + /// Is the object managed by this factory a singleton or a prototype? + /// + /// + public bool IsSingleton + { + get { return _objectFactory.IsSingleton(_targetObjectName); } + } + + /// + /// Callback that supplies the owning factory to an object instance. + /// + /// + /// The owning + /// (may not be ). The object can immediately + /// call methods on the factory. + /// + /// + /// In case of initialization errors. + /// + /// + public IObjectFactory ObjectFactory + { + set + { + // the call to set this property occurs 'after' all properties have been set... + _objectFactory = value; + if (StringUtils.IsNullOrEmpty(_targetObjectName)) + { + throw new ArgumentException( + "The 'TargetObjectName' property is required."); + } + + if (!_objectFactory.ContainsObject(_targetObjectName)) + { + throw new NoSuchObjectDefinitionException( + _targetObjectName, _objectFactory.ToString()); + } + } + } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/ObjectRole.cs b/src/Spring/Spring.Core/Objects/Factory/Config/ObjectRole.cs index e86f7bf4..714d9aed 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/ObjectRole.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/ObjectRole.cs @@ -1,52 +1,51 @@ #region License -/* - * Copyright 2002-2010 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. +/* + * Copyright 2002-2010 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 -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// +/// Erich Eichinger +public enum ObjectRole { + // TODO (EE): ComponentDefinitions are part of Spring/J 2.5 + /// + /// Role hint indicating that a is a major part of the application. Typically corresponds to a user-defined object. /// - /// Erich Eichinger - public enum ObjectRole - { - // TODO (EE): ComponentDefinitions are part of Spring/J 2.5 + ROLE_APPLICATION = 0, - /// - /// Role hint indicating that a is a major part of the application. Typically corresponds to a user-defined object. - /// - ROLE_APPLICATION = 0, + /// + /// Role hint indicating that a is a supporting + /// part of some larger configuration, typically an outer ComponentDefinition + /// SUPPORT objects are considered important enough to be aware + /// of when looking more closely at a particular ComponentDefinition, + /// but not when looking at the overall configuration of an application. + /// + ROLE_SUPPORT = 1, - /// - /// Role hint indicating that a is a supporting - /// part of some larger configuration, typically an outer ComponentDefinition - /// SUPPORT objects are considered important enough to be aware - /// of when looking more closely at a particular ComponentDefinition, - /// but not when looking at the overall configuration of an application. - /// - ROLE_SUPPORT = 1, - - /// - /// Role hint indicating that a is providing an - /// entirely background role and has no relevance to the end-user. This hint is - /// used when registering objects that are completely part of the internal workings - /// of a ComponentDefinition. - /// - ROLE_INFRASTRUCTURE = 2 - } + /// + /// Role hint indicating that a is providing an + /// entirely background role and has no relevance to the end-user. This hint is + /// used when registering objects that are completely part of the internal workings + /// of a ComponentDefinition. + /// + ROLE_INFRASTRUCTURE = 2 } \ No newline at end of file diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/PropertyFileVariableSource.cs b/src/Spring/Spring.Core/Objects/Factory/Config/PropertyFileVariableSource.cs index 9c7ab2b6..2e2b4477 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/PropertyFileVariableSource.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/PropertyFileVariableSource.cs @@ -21,118 +21,120 @@ using Spring.Core.IO; using Spring.Util; -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Implementation of that +/// resolves variable name against Java-style property file. +/// +/// +/// Aleksandar Seovic +[Serializable] +public class PropertyFileVariableSource : IVariableSource { + private IResource[] locations; + protected Properties properties; + private readonly object objectMonitor = new object(); + private bool ignoreMissingResources; + /// - /// Implementation of that - /// resolves variable name against Java-style property file. + /// Gets or sets the locations of the property files + /// to read properties from. /// - /// - /// Aleksandar Seovic - [Serializable] - public class PropertyFileVariableSource : IVariableSource + /// + /// The locations of the property files + /// to read properties from. + /// + public IResource[] Locations { - private IResource[] locations; - protected Properties properties; - private readonly object objectMonitor = new object(); - private bool ignoreMissingResources; + get { return locations; } + set { locations = value; } + } - /// - /// Gets or sets the locations of the property files - /// to read properties from. - /// - /// - /// The locations of the property files - /// to read properties from. - /// - public IResource[] Locations - { - get { return locations; } - set { locations = value; } - } + /// + /// Convinience property. Gets or sets a single location + /// to read properties from. + /// + /// + /// A location to read properties from. + /// + public IResource Location + { + set { locations = new IResource[] { value }; } + } - /// - /// Convinience property. Gets or sets a single location - /// to read properties from. - /// - /// - /// A location to read properties from. - /// - public IResource Location - { - set { locations = new IResource[] { value} ;} - } + /// + /// Sets a value indicating whether to ignore resource locations that do not exist. This will call + /// the Exists property. + /// + /// + /// true if one should ignore missing resources; otherwise, false. + /// + public bool IgnoreMissingResources + { + set { ignoreMissingResources = value; } + } - /// - /// Sets a value indicating whether to ignore resource locations that do not exist. This will call - /// the Exists property. - /// - /// - /// true if one should ignore missing resources; otherwise, false. - /// - public bool IgnoreMissingResources + /// + /// Before requesting a variable resolution, a client should + /// ask, whether the source can resolve a particular variable name. + /// + /// the name of the variable to resolve + /// true if the variable can be resolved, false otherwise + public bool CanResolveVariable(string name) + { + lock (objectMonitor) { - set { ignoreMissingResources = value; } - } - - /// - /// Before requesting a variable resolution, a client should - /// ask, whether the source can resolve a particular variable name. - /// - /// the name of the variable to resolve - /// true if the variable can be resolved, false otherwise - public bool CanResolveVariable(string name) - { - lock (objectMonitor) + if (properties == null) { - if (properties == null) - { - properties = new Properties(); - InitProperties(); - } - return properties.Contains(name); + properties = new Properties(); + InitProperties(); } - } - /// - /// Resolves variable value for the specified variable name. - /// - /// - /// The name of the variable to resolve. - /// - /// - /// The variable value if able to resolve, null otherwise. - /// - public string ResolveVariable(string name) + return properties.Contains(name); + } + } + + /// + /// Resolves variable value for the specified variable name. + /// + /// + /// The name of the variable to resolve. + /// + /// + /// The variable value if able to resolve, null otherwise. + /// + public string ResolveVariable(string name) + { + lock (objectMonitor) { - lock (objectMonitor) + if (properties == null) { - if (properties == null) - { - properties = new Properties(); - InitProperties(); - } - return properties.GetProperty(name); + properties = new Properties(); + InitProperties(); } - } - /// - /// Initializes properties based on the specified - /// property file locations. - /// - protected virtual void InitProperties() + return properties.GetProperty(name); + } + } + + /// + /// Initializes properties based on the specified + /// property file locations. + /// + protected virtual void InitProperties() + { + foreach (IResource location in locations) { - foreach (IResource location in locations) + bool exists = location.Exists; + if (!exists && ignoreMissingResources) { - bool exists = location.Exists; - if (!exists && ignoreMissingResources) - { - continue; - } - using (Stream input = location.InputStream) - { - properties.Load(input); - } + continue; + } + + using (Stream input = location.InputStream) + { + properties.Load(input); } } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/PropertyOverrideConfigurer.cs b/src/Spring/Spring.Core/Objects/Factory/Config/PropertyOverrideConfigurer.cs index 619cf77d..35bf1fbb 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/PropertyOverrideConfigurer.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/PropertyOverrideConfigurer.cs @@ -22,176 +22,176 @@ using System.Collections.Specialized; using System.Globalization; using Microsoft.Extensions.Logging; -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Overrides default values in one or more object definitions. +/// +/// +///

+/// Instances of this class override already existing values, and is +/// thus best suited to replacing defaults. If you need to replace +/// placeholder values, consider using the +/// +/// class instead. +///

+///

+/// In contrast to the +/// +/// class, the original object definition can have default +/// values or no values at all for such object properties. If an overriding +/// configuration file does not have an entry for a certain object property, +/// the default object value is left as is. Also note that it is not +/// immediately obvious to discern which object definitions will be mutated by +/// one or more +/// s +/// simply by looking at the object configuration. +///

+///

+/// Each line in a referenced configuration file is expected to take the +/// following form... +///

+/// +/// +/// +///

+/// The name.property key refers to the object name and the +/// property that is to be overridden; and the value is the overridding +/// value that will be inserted into the appropriate object definition's +/// named property. +///

+///

+/// Please note that in the case of multiple +/// s +/// that define different values for the same object definition value, the +/// last overridden value will win (due to the fact that the values +/// supplied by previous +/// s +/// will be overridden). +///

+///
+/// +///

+/// The following XML context definition defines an object that has a number +/// of properties, all of which have default values... +///

+/// +/// +/// +/// +/// +/// +/// +/// +///

+/// What follows is a .NET config file snippet for the above example (assuming +/// the need to override one of the default values)... +///

+/// +/// +/// +/// +/// +/// +///
+/// Juergen Hoeller +/// Simon White (.NET) +/// +/// +/// +[Serializable] +public class PropertyOverrideConfigurer : PropertyResourceConfigurer { - /// - /// Overrides default values in one or more object definitions. - /// - /// - ///

- /// Instances of this class override already existing values, and is - /// thus best suited to replacing defaults. If you need to replace - /// placeholder values, consider using the - /// - /// class instead. - ///

- ///

- /// In contrast to the - /// - /// class, the original object definition can have default - /// values or no values at all for such object properties. If an overriding - /// configuration file does not have an entry for a certain object property, - /// the default object value is left as is. Also note that it is not - /// immediately obvious to discern which object definitions will be mutated by - /// one or more - /// s - /// simply by looking at the object configuration. - ///

- ///

- /// Each line in a referenced configuration file is expected to take the - /// following form... - ///

- /// - /// - /// - ///

- /// The name.property key refers to the object name and the - /// property that is to be overridden; and the value is the overridding - /// value that will be inserted into the appropriate object definition's - /// named property. - ///

- ///

- /// Please note that in the case of multiple - /// s - /// that define different values for the same object definition value, the - /// last overridden value will win (due to the fact that the values - /// supplied by previous - /// s - /// will be overridden). - ///

- ///
- /// - ///

- /// The following XML context definition defines an object that has a number - /// of properties, all of which have default values... - ///

- /// - /// - /// - /// - /// - /// - /// - /// - ///

- /// What follows is a .NET config file snippet for the above example (assuming - /// the need to override one of the default values)... - ///

- /// - /// - /// - /// - /// - /// - ///
- /// Juergen Hoeller - /// Simon White (.NET) - /// - /// - /// - [Serializable] - public class PropertyOverrideConfigurer : PropertyResourceConfigurer - { - private static readonly ILogger _logger = LogManager.GetLogger(); + private static readonly ILogger _logger = LogManager.GetLogger(); - /// - /// Apply the given properties to the supplied - /// . - /// - /// - /// The - /// used by the application context. - /// - /// The properties to apply. - /// - /// If an error occured. - /// - protected override void ProcessProperties( - IConfigurableListableObjectFactory factory, NameValueCollection props) - { - foreach (string key in props.AllKeys) - { - ProcessKey(factory, key, props[key]); - } - } + /// + /// Apply the given properties to the supplied + /// . + /// + /// + /// The + /// used by the application context. + /// + /// The properties to apply. + /// + /// If an error occured. + /// + protected override void ProcessProperties( + IConfigurableListableObjectFactory factory, NameValueCollection props) + { + foreach (string key in props.AllKeys) + { + ProcessKey(factory, key, props[key]); + } + } - /// - /// Process the given key as 'name.property' entry. - /// - /// - /// The object factory containing the object definitions that are to be - /// processed. - /// - /// The key. - /// The value. - /// - /// If an error occurs. - /// - /// - /// If the property was not well formed (i.e. not in the format "name.property"). - /// - protected virtual void ProcessKey( - IConfigurableListableObjectFactory factory, string key, string value) - { - int dotIndex = key.IndexOf('.'); - if (dotIndex == -1) - { - throw new FatalObjectException( - string.Format(CultureInfo.InvariantCulture, - "Invalid key '{0}': expected 'objectName.property' form.", key)); - } - string name = key.Substring(0, dotIndex); - string objectProperty = key.Substring(dotIndex + 1); - IObjectDefinition definition = factory.GetObjectDefinition(name); - if(definition != null) - { - PropertyValue pv = definition.PropertyValues.GetPropertyValue(objectProperty); - if (pv != null && pv.Value is RuntimeObjectReference) - { - definition.PropertyValues.Add(objectProperty, new RuntimeObjectReference(value)); - } - else if (pv != null && pv.Value is ExpressionHolder) - { - definition.PropertyValues.Add(objectProperty, new ExpressionHolder(value)); - } - else - { - definition.PropertyValues.Add(objectProperty, value); - } - } - else - { - #region Instrumentation + /// + /// Process the given key as 'name.property' entry. + /// + /// + /// The object factory containing the object definitions that are to be + /// processed. + /// + /// The key. + /// The value. + /// + /// If an error occurs. + /// + /// + /// If the property was not well formed (i.e. not in the format "name.property"). + /// + protected virtual void ProcessKey( + IConfigurableListableObjectFactory factory, string key, string value) + { + int dotIndex = key.IndexOf('.'); + if (dotIndex == -1) + { + throw new FatalObjectException( + string.Format(CultureInfo.InvariantCulture, + "Invalid key '{0}': expected 'objectName.property' form.", key)); + } - if (_logger.IsEnabled(LogLevel.Warning)) - { - _logger.LogWarning(string.Format(CultureInfo.InvariantCulture, - "Cannot find object '{0}' when overriding properties; check configuration.", name)); - } + string name = key.Substring(0, dotIndex); + string objectProperty = key.Substring(dotIndex + 1); + IObjectDefinition definition = factory.GetObjectDefinition(name); + if (definition != null) + { + PropertyValue pv = definition.PropertyValues.GetPropertyValue(objectProperty); + if (pv != null && pv.Value is RuntimeObjectReference) + { + definition.PropertyValues.Add(objectProperty, new RuntimeObjectReference(value)); + } + else if (pv != null && pv.Value is ExpressionHolder) + { + definition.PropertyValues.Add(objectProperty, new ExpressionHolder(value)); + } + else + { + definition.PropertyValues.Add(objectProperty, value); + } + } + else + { + #region Instrumentation - #endregion - } + if (_logger.IsEnabled(LogLevel.Warning)) + { + _logger.LogWarning(string.Format(CultureInfo.InvariantCulture, + "Cannot find object '{0}' when overriding properties; check configuration.", name)); + } - #region Instrumentation + #endregion + } - if (_logger.IsEnabled(LogLevel.Debug)) - { - _logger.LogDebug(string.Format(CultureInfo.InvariantCulture, - "Property '{0}' set to '{1}'.", key, value)); - } + #region Instrumentation - #endregion - } - } + if (_logger.IsEnabled(LogLevel.Debug)) + { + _logger.LogDebug(string.Format(CultureInfo.InvariantCulture, + "Property '{0}' set to '{1}'.", key, value)); + } + + #endregion + } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/PropertyPathFactoryObject.cs b/src/Spring/Spring.Core/Objects/Factory/Config/PropertyPathFactoryObject.cs index a280f26e..43a63e90 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/PropertyPathFactoryObject.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/PropertyPathFactoryObject.cs @@ -18,317 +18,324 @@ #endregion -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// implementation that +/// evaluates a property path on a given target object. +/// +/// +///

+/// The target object can be specified directly or via an object name (see +/// example below). +///

+///

+/// Please note that the +/// is an implementation, and as such has +/// to comply with the contract of the +/// interface; more specifically, this means that the end result of the property lookup path +/// evaluation cannot be ( +/// implementations are not permitted to return ). If the resut of a +/// property lookup path evaluates to , an exception will be thrown. +///

+///
+/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// Juergen Hoeller +/// Rick Evans (.NET) +[Serializable] +public class PropertyPathFactoryObject : IFactoryObject, IObjectNameAware, IObjectFactoryAware { - /// - /// implementation that - /// evaluates a property path on a given target object. - /// - /// - ///

- /// The target object can be specified directly or via an object name (see - /// example below). - ///

- ///

- /// Please note that the - /// is an implementation, and as such has - /// to comply with the contract of the - /// interface; more specifically, this means that the end result of the property lookup path - /// evaluation cannot be ( - /// implementations are not permitted to return ). If the resut of a - /// property lookup path evaluates to , an exception will be thrown. - ///

- ///
- /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// Juergen Hoeller - /// Rick Evans (.NET) - [Serializable] - public class PropertyPathFactoryObject : IFactoryObject, IObjectNameAware, IObjectFactoryAware - { - private IObjectWrapper targetObjectWrapper; - private string targetObjectName; - private string propertyPath; - private Type resultType; - private string objectName; - private IObjectFactory objectFactory; + private IObjectWrapper targetObjectWrapper; + private string targetObjectName; + private string propertyPath; + private Type resultType; + private string objectName; + private IObjectFactory objectFactory; - /// - /// The target object that the property path lookup is to be applied to. - /// - /// - ///

- /// This would most likely be an inner object, but can of course be - /// any object reference. - ///

- ///
- /// - /// The target object that the property path lookup is to be applied to. - /// - /// - public object TargetObject - { - set { this.targetObjectWrapper = new ObjectWrapper(value); } - } + /// + /// The target object that the property path lookup is to be applied to. + /// + /// + ///

+ /// This would most likely be an inner object, but can of course be + /// any object reference. + ///

+ ///
+ /// + /// The target object that the property path lookup is to be applied to. + /// + /// + public object TargetObject + { + set { this.targetObjectWrapper = new ObjectWrapper(value); } + } - /// - /// The (object) name of the target object that the property path lookup - /// is to be applied to. - /// - /// - ///

- /// Please note that any leading or trailing whitespace will be - /// trimmed from this name prior to resolution. The implication of this is that - /// one cannot use the - /// class in conjunction with object names that start or end with whitespace. - ///

- ///
- /// - /// The (object) name of the target object that the property path lookup - /// is to be applied to. - /// - /// - public string TargetObjectName - { - set - { - if (value != null) - { - value = value.Trim(); - } - this.targetObjectName = value; - } - } + /// + /// The (object) name of the target object that the property path lookup + /// is to be applied to. + /// + /// + ///

+ /// Please note that any leading or trailing whitespace will be + /// trimmed from this name prior to resolution. The implication of this is that + /// one cannot use the + /// class in conjunction with object names that start or end with whitespace. + ///

+ ///
+ /// + /// The (object) name of the target object that the property path lookup + /// is to be applied to. + /// + /// + public string TargetObjectName + { + set + { + if (value != null) + { + value = value.Trim(); + } - /// - /// The property (lookup) path to be applied to the target object. - /// - /// - ///

- /// Please note that any leading or trailing whitespace will be - /// trimmed from this path prior to resolution. Whitespace is not a valid - /// identifier for property names (in part or whole) in CLS-based languages, - /// so this is a not unreasonable action. Please also note that whitespace - /// that is embedded within the property path will be left as-is (which may - /// or may not result in an error being thrown, depending on the context of - /// the whitespace). - ///

- ///
- /// - ///

- /// Examples of such property lookup paths can be seen below; note that - /// property lookup paths can be nested to an arbitrary level. - ///

- /// - /// name.length - /// accountManager.account['the key'].name - /// accounts[0].name - /// - ///
- /// - /// The property (lookup) path to be applied to the target object. - /// - public string PropertyPath - { - set - { - if (value != null) - { - value = value.Trim(); - } - this.propertyPath = value; - } - } + this.targetObjectName = value; + } + } - /// - /// The 'expected' of the result from evaluating the - /// property path. - /// - /// - ///

- /// This is not necessary for directly specified target objects, or - /// singleton target objects, where the can - /// be determined via reflection. Just specify this in case of a - /// prototype target, provided that you need matching by type (for - /// example, for autowiring). - ///

- ///

- /// It is permissable to set the value of this property to - /// (which in any case is the default value). - ///

- ///
- /// - /// The 'expected' of the result from evaluating the - /// property path. - /// - public Type ResultType - { - set { this.resultType = value; } - } + /// + /// The property (lookup) path to be applied to the target object. + /// + /// + ///

+ /// Please note that any leading or trailing whitespace will be + /// trimmed from this path prior to resolution. Whitespace is not a valid + /// identifier for property names (in part or whole) in CLS-based languages, + /// so this is a not unreasonable action. Please also note that whitespace + /// that is embedded within the property path will be left as-is (which may + /// or may not result in an error being thrown, depending on the context of + /// the whitespace). + ///

+ ///
+ /// + ///

+ /// Examples of such property lookup paths can be seen below; note that + /// property lookup paths can be nested to an arbitrary level. + ///

+ /// + /// name.length + /// accountManager.account['the key'].name + /// accounts[0].name + /// + ///
+ /// + /// The property (lookup) path to be applied to the target object. + /// + public string PropertyPath + { + set + { + if (value != null) + { + value = value.Trim(); + } - /// - /// Return an instance (possibly shared or independent) of the object - /// managed by this factory. - /// - /// - /// An instance (possibly shared or independent) of the object managed by - /// this factory. - /// - /// - public object GetObject() - { - IObjectWrapper target = this.targetObjectWrapper; - if (target == null) - { - // fetch the prototype object object... - target = new ObjectWrapper(this.objectFactory[this.targetObjectName]); - } - object value = target.GetPropertyValue(this.propertyPath); - if (value == null) - { - throw new FatalObjectException("PropertyPathFactoryObject is not allowed to return null, " + - "but property value for path '" + this.propertyPath + "' is null."); - } - return value; - } + this.propertyPath = value; + } + } - /// - /// Return the of object that this - /// creates, or - /// if not known in advance. - /// - /// - public Type ObjectType - { - get { return this.resultType; } - } + /// + /// The 'expected' of the result from evaluating the + /// property path. + /// + /// + ///

+ /// This is not necessary for directly specified target objects, or + /// singleton target objects, where the can + /// be determined via reflection. Just specify this in case of a + /// prototype target, provided that you need matching by type (for + /// example, for autowiring). + ///

+ ///

+ /// It is permissable to set the value of this property to + /// (which in any case is the default value). + ///

+ ///
+ /// + /// The 'expected' of the result from evaluating the + /// property path. + /// + public Type ResultType + { + set { this.resultType = value; } + } - /// - /// Is the object managed by this factory a singleton or a prototype? - /// - /// - public bool IsSingleton - { - get { return false; } - } + /// + /// Return an instance (possibly shared or independent) of the object + /// managed by this factory. + /// + /// + /// An instance (possibly shared or independent) of the object managed by + /// this factory. + /// + /// + public object GetObject() + { + IObjectWrapper target = this.targetObjectWrapper; + if (target == null) + { + // fetch the prototype object object... + target = new ObjectWrapper(this.objectFactory[this.targetObjectName]); + } - /// - /// Set the name of the object in the object factory that created this object. - /// - /// - ///

- /// The object name of this - /// - /// will be interpreted as "objectName.property" pattern, if neither the - /// - /// - /// have been supplied (set). - ///

- ///

- /// This allows for concise object definitions with just an id or name. - ///

- ///
- /// - /// The name of the object in the factory. - /// - public string ObjectName - { - set { this.objectName = value; } - } + object value = target.GetPropertyValue(this.propertyPath); + if (value == null) + { + throw new FatalObjectException("PropertyPathFactoryObject is not allowed to return null, " + + "but property value for path '" + this.propertyPath + "' is null."); + } - /// - /// Callback that supplies the owning factory to an object instance. - /// - /// - /// Owning - /// (may not be ). The object can immediately - /// call methods on the factory. - /// - /// - /// In case of initialization errors. - /// - public IObjectFactory ObjectFactory - { - set - { - this.objectFactory = value; - if (this.targetObjectWrapper != null && this.targetObjectName != null) - { - throw new ArgumentException("Only one of the TargetObjectName or TargetObject properties can be set, not both."); - } - if (this.targetObjectWrapper == null && this.targetObjectName == null) - { - if (this.propertyPath != null) - { - throw new ArgumentException( - "Specify TargetObject or TargetObjectName property in combination with PropertyPath."); - } - // no other properties specified: check object name... - string strippedObjectname = this.objectName.Trim(); - int dotIndex = strippedObjectname.IndexOf('.'); - if (dotIndex <= 0) - { - throw new ArgumentException( - "Neither TargetObject nor TargetObjectName specified, and PropertyPathFactoryObject " + - "object name '" + this.objectName + "' does not follow 'objectName.property' syntax."); - } - this.targetObjectName = strippedObjectname.Substring(0, dotIndex); - this.propertyPath = strippedObjectname.Substring(dotIndex + 1); - } - else if (this.propertyPath == null) - { - throw new ArgumentException("The 'PropertyPath' property has not been set."); - } - if (this.targetObjectWrapper == null - && this.objectFactory.IsSingleton(this.targetObjectName)) - { - // eagerly fetch singleton target object, and determine result type... - this.targetObjectWrapper - = new ObjectWrapper(this.objectFactory.GetObject(this.targetObjectName)); - this.resultType = this.targetObjectWrapper.GetPropertyType(this.propertyPath); - } - } - } - } + return value; + } + + /// + /// Return the of object that this + /// creates, or + /// if not known in advance. + /// + /// + public Type ObjectType + { + get { return this.resultType; } + } + + /// + /// Is the object managed by this factory a singleton or a prototype? + /// + /// + public bool IsSingleton + { + get { return false; } + } + + /// + /// Set the name of the object in the object factory that created this object. + /// + /// + ///

+ /// The object name of this + /// + /// will be interpreted as "objectName.property" pattern, if neither the + /// + /// + /// have been supplied (set). + ///

+ ///

+ /// This allows for concise object definitions with just an id or name. + ///

+ ///
+ /// + /// The name of the object in the factory. + /// + public string ObjectName + { + set { this.objectName = value; } + } + + /// + /// Callback that supplies the owning factory to an object instance. + /// + /// + /// Owning + /// (may not be ). The object can immediately + /// call methods on the factory. + /// + /// + /// In case of initialization errors. + /// + public IObjectFactory ObjectFactory + { + set + { + this.objectFactory = value; + if (this.targetObjectWrapper != null && this.targetObjectName != null) + { + throw new ArgumentException("Only one of the TargetObjectName or TargetObject properties can be set, not both."); + } + + if (this.targetObjectWrapper == null && this.targetObjectName == null) + { + if (this.propertyPath != null) + { + throw new ArgumentException( + "Specify TargetObject or TargetObjectName property in combination with PropertyPath."); + } + + // no other properties specified: check object name... + string strippedObjectname = this.objectName.Trim(); + int dotIndex = strippedObjectname.IndexOf('.'); + if (dotIndex <= 0) + { + throw new ArgumentException( + "Neither TargetObject nor TargetObjectName specified, and PropertyPathFactoryObject " + + "object name '" + this.objectName + "' does not follow 'objectName.property' syntax."); + } + + this.targetObjectName = strippedObjectname.Substring(0, dotIndex); + this.propertyPath = strippedObjectname.Substring(dotIndex + 1); + } + else if (this.propertyPath == null) + { + throw new ArgumentException("The 'PropertyPath' property has not been set."); + } + + if (this.targetObjectWrapper == null + && this.objectFactory.IsSingleton(this.targetObjectName)) + { + // eagerly fetch singleton target object, and determine result type... + this.targetObjectWrapper + = new ObjectWrapper(this.objectFactory.GetObject(this.targetObjectName)); + this.resultType = this.targetObjectWrapper.GetPropertyType(this.propertyPath); + } + } + } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/PropertyPlaceholderConfigurer.cs b/src/Spring/Spring.Core/Objects/Factory/Config/PropertyPlaceholderConfigurer.cs index f37ecc5b..92d409f9 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/PropertyPlaceholderConfigurer.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/PropertyPlaceholderConfigurer.cs @@ -24,404 +24,407 @@ using Microsoft.Extensions.Logging; using Spring.Collections; using Spring.Util; -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Resolves placeholder values in one or more object definitions. +/// +/// +///

+/// The default placeholder syntax follows the NAnt style: ${...}. +/// Instances of this class can be configured in the same way as any other +/// object in a Spring.NET container, and so custom placeholder prefix +/// and suffix values can be set via the +/// and properties. +///

+/// +///

+/// The following example XML context definition defines an object that has +/// a number of placeholders. The placeholders can easily be distinguished +/// by the presence of the ${} characters. +///

+/// +/// +/// +/// +/// +/// +/// +/// +///

+/// The associated XML configuration file for the above example containing the +/// values for the placeholders would contain a snippet such as .. +///

+/// +/// +/// +/// +/// +/// +/// +/// +///

+/// The preceding XML snippet listing the various property keys and their +/// associated values needs to be inserted into the .NET config file of +/// your application (or Web.config file for your ASP.NET web application, +/// as the case may be), like so... +///

+/// +/// +/// +/// +/// +/// +/// +/// +///
+///

+/// +/// checks simple property values, lists, dictionaries, sets, constructor +/// values, object type name, and object names in +/// runtime object references ( +/// ). +/// Furthermore, placeholder values can also cross-reference other +/// placeholders, in the manner of the following example where the +/// rootPath property is cross-referenced by the subPath +/// property. +///

+/// +/// +/// +/// +/// +/// +/// +/// +///

+/// In contrast to the +/// +/// class, this configurer only permits the replacement of explicit +/// placeholders in object definitions. Therefore, the original definition +/// cannot specify any default values for its object properties, and the +/// placeholder configuration file is expected to contain an entry for each +/// defined placeholder. That is, if an object definition contains a +/// placeholder ${foo}, there should be an associated +/// <add key="foo" value="..."/> entry in the +/// referenced placeholder configuration file. Default property values +/// can be defined via the inherited +/// +/// collection to overcome any perceived limitation of this feature. +///

+///

+/// If a configurer cannot resolve a placeholder, and the value of the +/// +/// property is currently set to , an +/// +/// will be thrown. If you want to resolve properties from multiple configuration +/// resources, simply specify multiple resources via the +/// +/// property. Finally, please note that you can also define multiple +/// +/// instances, each with their own custom placeholder syntax. +///

+///
+/// Juergen Hoeller +/// Simon White (.NET) +/// +/// +/// +[Serializable] +public class PropertyPlaceholderConfigurer : PropertyResourceConfigurer { - /// - /// Resolves placeholder values in one or more object definitions. - /// - /// - ///

- /// The default placeholder syntax follows the NAnt style: ${...}. - /// Instances of this class can be configured in the same way as any other - /// object in a Spring.NET container, and so custom placeholder prefix - /// and suffix values can be set via the - /// and properties. - ///

- /// - ///

- /// The following example XML context definition defines an object that has - /// a number of placeholders. The placeholders can easily be distinguished - /// by the presence of the ${} characters. - ///

- /// - /// - /// - /// - /// - /// - /// - /// - ///

- /// The associated XML configuration file for the above example containing the - /// values for the placeholders would contain a snippet such as .. - ///

- /// - /// - /// - /// - /// - /// - /// - /// - ///

- /// The preceding XML snippet listing the various property keys and their - /// associated values needs to be inserted into the .NET config file of - /// your application (or Web.config file for your ASP.NET web application, - /// as the case may be), like so... - ///

- /// - /// - /// - /// - /// - /// - /// - /// - ///
- ///

- /// - /// checks simple property values, lists, dictionaries, sets, constructor - /// values, object type name, and object names in - /// runtime object references ( - /// ). - /// Furthermore, placeholder values can also cross-reference other - /// placeholders, in the manner of the following example where the - /// rootPath property is cross-referenced by the subPath - /// property. - ///

- /// - /// - /// - /// - /// - /// - /// - /// - ///

- /// In contrast to the - /// - /// class, this configurer only permits the replacement of explicit - /// placeholders in object definitions. Therefore, the original definition - /// cannot specify any default values for its object properties, and the - /// placeholder configuration file is expected to contain an entry for each - /// defined placeholder. That is, if an object definition contains a - /// placeholder ${foo}, there should be an associated - /// <add key="foo" value="..."/> entry in the - /// referenced placeholder configuration file. Default property values - /// can be defined via the inherited - /// - /// collection to overcome any perceived limitation of this feature. - ///

- ///

- /// If a configurer cannot resolve a placeholder, and the value of the - /// - /// property is currently set to , an - /// - /// will be thrown. If you want to resolve properties from multiple configuration - /// resources, simply specify multiple resources via the - /// - /// property. Finally, please note that you can also define multiple - /// - /// instances, each with their own custom placeholder syntax. - ///

- ///
- /// Juergen Hoeller - /// Simon White (.NET) - /// - /// - /// - [Serializable] - public class PropertyPlaceholderConfigurer : PropertyResourceConfigurer - { - /// - /// The default placeholder prefix. - /// - public static readonly string DefaultPlaceholderPrefix = "${"; + /// + /// The default placeholder prefix. + /// + public static readonly string DefaultPlaceholderPrefix = "${"; - /// - /// The default placeholder suffix. - /// - public static readonly string DefaultPlaceholderSuffix = "}"; + /// + /// The default placeholder suffix. + /// + public static readonly string DefaultPlaceholderSuffix = "}"; + private readonly ILogger logger; - private readonly ILogger logger; + private bool ignoreUnresolvablePlaceholders = false; + private string placeholderPrefix = DefaultPlaceholderPrefix; + private string placeholderSuffix = DefaultPlaceholderSuffix; + private EnvironmentVariableMode environmentVariableMode = EnvironmentVariableMode.Fallback; + private bool includeAncestors; - - private bool ignoreUnresolvablePlaceholders = false; - private string placeholderPrefix = DefaultPlaceholderPrefix; - private string placeholderSuffix = DefaultPlaceholderSuffix; - private EnvironmentVariableMode environmentVariableMode = EnvironmentVariableMode.Fallback; - private bool includeAncestors; - - /// - /// Initializes the new instance - /// - public PropertyPlaceholderConfigurer() - { - logger = LogManager.GetLogger(this.GetType()); - } - - #region Properties - - /// - /// The placeholder prefix (the default is ${). - /// - /// - public string PlaceholderPrefix - { - set { placeholderPrefix = value; } - } - - /// - /// The placeholder suffix (the default is }) - /// - /// - public string PlaceholderSuffix - { - set { placeholderSuffix = value; } - } - - /// - /// Indicates whether unresolved placeholders should be ignored. - /// - public bool IgnoreUnresolvablePlaceholders - { - get { return ignoreUnresolvablePlaceholders; } - set { ignoreUnresolvablePlaceholders = value; } - } - - /// - /// Controls how environment variables will be used to - /// replace property placeholders. - /// - /// - ///

- /// See the overview of the - /// - /// enumeration for the available options. - ///

- ///
- public EnvironmentVariableMode EnvironmentVariableMode - { - set { environmentVariableMode = value; } - } - - public bool IncludeAncestors - { - set { includeAncestors = value; } - } - - #endregion - - /// - /// Apply the given properties to the supplied - /// . - /// - /// - /// The - /// used by the application context. - /// - /// The properties to apply. - /// - /// If an error occured. - /// - protected override void ProcessProperties(IConfigurableListableObjectFactory factory, NameValueCollection props) - { - PlaceholderResolveHandlerAdapter resolveAdapter = new PlaceholderResolveHandlerAdapter(this, props); - ObjectDefinitionVisitor visitor = new ObjectDefinitionVisitor(resolveAdapter.ParseAndResolveVariables); - - var objectDefinitionNames = factory.GetObjectDefinitionNames(includeAncestors); - for (int i = 0; i < objectDefinitionNames.Count; ++i) - { - string name = objectDefinitionNames[i]; - IObjectDefinition definition = factory.GetObjectDefinition(name, includeAncestors); - - if (definition == null) - { - logger.LogError("{Name} can't be found in factorys' {Factory} object definition (includeAncestor {IncludeAncestor})", name, factory, includeAncestors); - continue; - } - - try - { - visitor.VisitObjectDefinition(definition); - } - catch (ObjectDefinitionStoreException ex) - { - throw new ObjectDefinitionStoreException( - definition.ResourceDescription, name, ex.Message); - } - } - - factory.AddEmbeddedValueResolver(resolveAdapter); - } - - /// - /// Parse values recursively to be able to resolve cross-references between - /// placeholder values. - /// - /// - /// The map of constructor arguments / property values. - /// - /// The string to be resolved. - /// The placeholders that have already been visited - /// during the current resolution attempt (used to detect circular references - /// between placeholders). Only non-null if we're parsing a nested placeholder. - /// - /// If an error occurs. - /// - /// The resolved string. - public virtual string ParseString( - NameValueCollection properties, string strVal, ISet visitedPlaceholders) - { - int startIndex = strVal.IndexOf(placeholderPrefix); - while (startIndex != -1) - { - int endIndex = strVal.IndexOf( - placeholderSuffix, startIndex + placeholderPrefix.Length); - if (endIndex != -1) - { - int pos = startIndex + placeholderPrefix.Length; - string placeholder = strVal.Substring(pos, endIndex - pos); - if (visitedPlaceholders.Contains(placeholder)) - { - throw new ObjectDefinitionStoreException( - string.Format( - CultureInfo.InvariantCulture, - "Circular placeholder reference '{0}' detected " + - "in property definitions [{1}].", - placeholder, properties)); - } - visitedPlaceholders.Add(placeholder); - string resolvedValue = ResolvePlaceholder(placeholder, properties, environmentVariableMode); - if (resolvedValue != null) - { - resolvedValue = ParseString(properties, resolvedValue, visitedPlaceholders); - - #region Instrumentation - - if (logger.IsEnabled(LogLevel.Debug)) - { - logger.LogDebug(string.Format( - CultureInfo.InvariantCulture, - "Resolving placeholder '{0}' to '{1}'.", placeholder, resolvedValue)); - } - - #endregion - - strVal = strVal.Substring(0, startIndex) + resolvedValue + strVal.Substring(endIndex + 1); - startIndex = strVal.IndexOf(placeholderPrefix, startIndex + resolvedValue.Length); - } - else if (ignoreUnresolvablePlaceholders) - { - // simply return the unprocessed value... - return strVal; - } - else - { - throw new ObjectDefinitionStoreException(string.Format( - CultureInfo.InvariantCulture, - "Could not resolve placeholder '{0}'.", placeholder)); - } - visitedPlaceholders.Remove(placeholder); - } - else - { - startIndex = -1; - } - } - return strVal; - } - - /// - /// Resolve the given placeholder using the given name value collection, - /// performing an environment variables check according to the given mode. - /// - /// - ///

- /// The default implementation delegates to - /// - /// before/afer the environment variable check. Subclasses can override - /// this for custom resolution strategies, including customized points - /// for the environment properties check. - ///

- ///
- /// The placeholder to resolve - /// - /// The merged name value collection of this configurer. - /// - /// The environment variable mode. - /// - /// The resolved value or if none. - /// - /// - protected virtual string ResolvePlaceholder(string placeholder, - NameValueCollection props, - EnvironmentVariableMode mode) - { - string propertyValue = null; - if (mode == Spring.Objects.Factory.Config.EnvironmentVariableMode.Override) - { - propertyValue = Environment.GetEnvironmentVariable(placeholder); - } - if (propertyValue == null) - { - propertyValue = ResolvePlaceholder(placeholder, props); - } - if (propertyValue == null - && mode == Spring.Objects.Factory.Config.EnvironmentVariableMode.Fallback) - { - propertyValue = Environment.GetEnvironmentVariable(placeholder); - } - return propertyValue; - } - - /// - /// Resolve the given placeholder using the given name value collection. - /// - /// - ///

- /// This (the default) implementation simply looks up the value of the - /// supplied key. - ///

- ///

- /// Subclasses can override this for customized placeholder-to-key - /// mappings or custom resolution strategies, possibly just using the - /// given name value collection as fallback. - ///

- ///
- /// The placeholder to resolve. - /// - /// The merged name value collection of this configurer. - /// - /// The resolved value. - protected virtual string ResolvePlaceholder( - string placeholder, NameValueCollection props) - { - return props[placeholder]; - } - - #region Helper class - - private class PlaceholderResolveHandlerAdapter : IStringValueResolver - { - private readonly PropertyPlaceholderConfigurer ppc; - private readonly NameValueCollection props; - - public PlaceholderResolveHandlerAdapter(PropertyPlaceholderConfigurer outerPPC, NameValueCollection props) - { - ppc = outerPPC; - this.props = props; - } - - public string ParseAndResolveVariables(string name) - { - return ppc.ParseString(props, name, new HashedSet()); - } - } - - #endregion + /// + /// Initializes the new instance + /// + public PropertyPlaceholderConfigurer() + { + logger = LogManager.GetLogger(this.GetType()); } + + #region Properties + + /// + /// The placeholder prefix (the default is ${). + /// + /// + public string PlaceholderPrefix + { + set { placeholderPrefix = value; } + } + + /// + /// The placeholder suffix (the default is }) + /// + /// + public string PlaceholderSuffix + { + set { placeholderSuffix = value; } + } + + /// + /// Indicates whether unresolved placeholders should be ignored. + /// + public bool IgnoreUnresolvablePlaceholders + { + get { return ignoreUnresolvablePlaceholders; } + set { ignoreUnresolvablePlaceholders = value; } + } + + /// + /// Controls how environment variables will be used to + /// replace property placeholders. + /// + /// + ///

+ /// See the overview of the + /// + /// enumeration for the available options. + ///

+ ///
+ public EnvironmentVariableMode EnvironmentVariableMode + { + set { environmentVariableMode = value; } + } + + public bool IncludeAncestors + { + set { includeAncestors = value; } + } + + #endregion + + /// + /// Apply the given properties to the supplied + /// . + /// + /// + /// The + /// used by the application context. + /// + /// The properties to apply. + /// + /// If an error occured. + /// + protected override void ProcessProperties(IConfigurableListableObjectFactory factory, NameValueCollection props) + { + PlaceholderResolveHandlerAdapter resolveAdapter = new PlaceholderResolveHandlerAdapter(this, props); + ObjectDefinitionVisitor visitor = new ObjectDefinitionVisitor(resolveAdapter.ParseAndResolveVariables); + + var objectDefinitionNames = factory.GetObjectDefinitionNames(includeAncestors); + for (int i = 0; i < objectDefinitionNames.Count; ++i) + { + string name = objectDefinitionNames[i]; + IObjectDefinition definition = factory.GetObjectDefinition(name, includeAncestors); + + if (definition == null) + { + logger.LogError("{Name} can't be found in factorys' {Factory} object definition (includeAncestor {IncludeAncestor})", name, factory, includeAncestors); + continue; + } + + try + { + visitor.VisitObjectDefinition(definition); + } + catch (ObjectDefinitionStoreException ex) + { + throw new ObjectDefinitionStoreException( + definition.ResourceDescription, name, ex.Message); + } + } + + factory.AddEmbeddedValueResolver(resolveAdapter); + } + + /// + /// Parse values recursively to be able to resolve cross-references between + /// placeholder values. + /// + /// + /// The map of constructor arguments / property values. + /// + /// The string to be resolved. + /// The placeholders that have already been visited + /// during the current resolution attempt (used to detect circular references + /// between placeholders). Only non-null if we're parsing a nested placeholder. + /// + /// If an error occurs. + /// + /// The resolved string. + public virtual string ParseString( + NameValueCollection properties, string strVal, ISet visitedPlaceholders) + { + int startIndex = strVal.IndexOf(placeholderPrefix); + while (startIndex != -1) + { + int endIndex = strVal.IndexOf( + placeholderSuffix, startIndex + placeholderPrefix.Length); + if (endIndex != -1) + { + int pos = startIndex + placeholderPrefix.Length; + string placeholder = strVal.Substring(pos, endIndex - pos); + if (visitedPlaceholders.Contains(placeholder)) + { + throw new ObjectDefinitionStoreException( + string.Format( + CultureInfo.InvariantCulture, + "Circular placeholder reference '{0}' detected " + + "in property definitions [{1}].", + placeholder, properties)); + } + + visitedPlaceholders.Add(placeholder); + string resolvedValue = ResolvePlaceholder(placeholder, properties, environmentVariableMode); + if (resolvedValue != null) + { + resolvedValue = ParseString(properties, resolvedValue, visitedPlaceholders); + + #region Instrumentation + + if (logger.IsEnabled(LogLevel.Debug)) + { + logger.LogDebug(string.Format( + CultureInfo.InvariantCulture, + "Resolving placeholder '{0}' to '{1}'.", placeholder, resolvedValue)); + } + + #endregion + + strVal = strVal.Substring(0, startIndex) + resolvedValue + strVal.Substring(endIndex + 1); + startIndex = strVal.IndexOf(placeholderPrefix, startIndex + resolvedValue.Length); + } + else if (ignoreUnresolvablePlaceholders) + { + // simply return the unprocessed value... + return strVal; + } + else + { + throw new ObjectDefinitionStoreException(string.Format( + CultureInfo.InvariantCulture, + "Could not resolve placeholder '{0}'.", placeholder)); + } + + visitedPlaceholders.Remove(placeholder); + } + else + { + startIndex = -1; + } + } + + return strVal; + } + + /// + /// Resolve the given placeholder using the given name value collection, + /// performing an environment variables check according to the given mode. + /// + /// + ///

+ /// The default implementation delegates to + /// + /// before/afer the environment variable check. Subclasses can override + /// this for custom resolution strategies, including customized points + /// for the environment properties check. + ///

+ ///
+ /// The placeholder to resolve + /// + /// The merged name value collection of this configurer. + /// + /// The environment variable mode. + /// + /// The resolved value or if none. + /// + /// + protected virtual string ResolvePlaceholder(string placeholder, + NameValueCollection props, + EnvironmentVariableMode mode) + { + string propertyValue = null; + if (mode == Spring.Objects.Factory.Config.EnvironmentVariableMode.Override) + { + propertyValue = Environment.GetEnvironmentVariable(placeholder); + } + + if (propertyValue == null) + { + propertyValue = ResolvePlaceholder(placeholder, props); + } + + if (propertyValue == null + && mode == Spring.Objects.Factory.Config.EnvironmentVariableMode.Fallback) + { + propertyValue = Environment.GetEnvironmentVariable(placeholder); + } + + return propertyValue; + } + + /// + /// Resolve the given placeholder using the given name value collection. + /// + /// + ///

+ /// This (the default) implementation simply looks up the value of the + /// supplied key. + ///

+ ///

+ /// Subclasses can override this for customized placeholder-to-key + /// mappings or custom resolution strategies, possibly just using the + /// given name value collection as fallback. + ///

+ ///
+ /// The placeholder to resolve. + /// + /// The merged name value collection of this configurer. + /// + /// The resolved value. + protected virtual string ResolvePlaceholder( + string placeholder, NameValueCollection props) + { + return props[placeholder]; + } + + #region Helper class + + private class PlaceholderResolveHandlerAdapter : IStringValueResolver + { + private readonly PropertyPlaceholderConfigurer ppc; + private readonly NameValueCollection props; + + public PlaceholderResolveHandlerAdapter(PropertyPlaceholderConfigurer outerPPC, NameValueCollection props) + { + ppc = outerPPC; + this.props = props; + } + + public string ParseAndResolveVariables(string name) + { + return ppc.ParseString(props, name, new HashedSet()); + } + } + + #endregion } diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/PropertyResourceConfigurer.cs b/src/Spring/Spring.Core/Objects/Factory/Config/PropertyResourceConfigurer.cs index 590fba5f..2d8b787e 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/PropertyResourceConfigurer.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/PropertyResourceConfigurer.cs @@ -24,365 +24,366 @@ using Microsoft.Extensions.Logging; using Spring.Core; using Spring.Core.IO; -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Allows for the configuration of individual object property values from +/// a .NET .config file. +/// +/// +///

+/// Useful for custom .NET .config files targetted at system administrators +/// that override object properties configured in the application context. +///

+///

+/// Two concrete implementations are provided in the Spring.NET core library: +/// +/// +/// +/// +/// for <add key="placeholderKey" value="..."/> style +/// overriding (pushing values from a .NET .config file into object +/// definitions). +/// +/// +/// +/// +/// +/// for replacing "${...}" placeholders (pulling values from a .NET .config +/// file into object definitions). +/// +/// +/// +///

+///

+/// Please refer to the API documentation for the concrete implementations +/// listed above for example usage. +///

+///
+/// Juergen Hoeller +/// Simon White (.NET) +/// +/// +[Serializable] +public abstract class PropertyResourceConfigurer + : IObjectFactoryPostProcessor, IOrdered { /// - /// Allows for the configuration of individual object property values from - /// a .NET .config file. + /// The default configuration section name to use if none is explictly supplied. + /// + /// + public static readonly string DefaultConfigSectionName = "spring-config"; + + #region Fields + + private readonly ILogger _log; + + private int _order = Int32.MaxValue; // default: same as non-Ordered + private NameValueCollection _defaultProperties; + private IResource[] _locations; + private string[] _configSections; + private bool _ignoreResourceNotFound = false; + private bool _lastLocationOverrides = true; + + #endregion + + #region Constructor (s) / Destructor + + /// + /// Creates a new instance of the + /// + /// class. /// /// ///

- /// Useful for custom .NET .config files targetted at system administrators - /// that override object properties configured in the application context. - ///

- ///

- /// Two concrete implementations are provided in the Spring.NET core library: - /// - /// - /// - /// - /// for <add key="placeholderKey" value="..."/> style - /// overriding (pushing values from a .NET .config file into object - /// definitions). - /// - /// - /// - /// - /// - /// for replacing "${...}" placeholders (pulling values from a .NET .config - /// file into object definitions). - /// - /// - /// - ///

- ///

- /// Please refer to the API documentation for the concrete implementations - /// listed above for example usage. + /// This is an class, and as such exposes no + /// public constructors. ///

///
- /// Juergen Hoeller - /// Simon White (.NET) - /// - /// - [Serializable] - public abstract class PropertyResourceConfigurer - : IObjectFactoryPostProcessor, IOrdered + protected PropertyResourceConfigurer() { - /// - /// The default configuration section name to use if none is explictly supplied. - /// - /// - public static readonly string DefaultConfigSectionName = "spring-config"; + _log = LogManager.GetLogger(this.GetType()); + } - #region Fields + #endregion - private readonly ILogger _log; + #region Properties - private int _order = Int32.MaxValue; // default: same as non-Ordered - private NameValueCollection _defaultProperties; - private IResource[] _locations; - private string[] _configSections; - private bool _ignoreResourceNotFound = false; - private bool _lastLocationOverrides = true; + /// + /// The policy for resolving conflicting property overrides from + /// several resources. + /// + /// + ///

+ /// When merging conflicting property overrides from several resources, + /// should append an override with the same key be appended to the + /// current value, or should the property override from the last resource + /// processed override previous values? + ///

+ ///

+ /// The default value is ; i.e. a property + /// override from the last resource to be processed overrides previous + /// values. + ///

+ ///
+ /// + /// if the property override from the last resource + /// processed overrides previous values. + /// + public bool LastLocationOverrides + { + set { _lastLocationOverrides = value; } + } - #endregion + /// + /// Return the order value of this object, where a higher value means greater in + /// terms of sorting. + /// + /// The order value. + /// + public int Order + { + get { return _order; } + set { _order = value; } + } - #region Constructor (s) / Destructor + /// + /// The default properties to be applied. + /// + /// + ///

+ /// These are to be considered defaults, to be overridden by values + /// loaded from other resources. + ///

+ ///
+ public NameValueCollection Properties + { + get { return _defaultProperties; } + set { _defaultProperties = value; } + } - /// - /// Creates a new instance of the - /// - /// class. - /// - /// - ///

- /// This is an class, and as such exposes no - /// public constructors. - ///

- ///
- protected PropertyResourceConfigurer() + /// + /// The location of the .NET .config file that contains the property + /// overrides that are to be applied. + /// + public IResource Location + { + set { _locations = new IResource[] { value }; } + } + + /// + /// The locations of the .NET .config files containing the property + /// overrides that are to be applied. + /// + public IResource[] Locations + { + set { _locations = value; } + } + + /// + /// The configuration sections to look for within the .config files. + /// + /// + /// + public string[] ConfigSections + { + get { - _log = LogManager.GetLogger(this.GetType()); - } - - #endregion - - #region Properties - - /// - /// The policy for resolving conflicting property overrides from - /// several resources. - /// - /// - ///

- /// When merging conflicting property overrides from several resources, - /// should append an override with the same key be appended to the - /// current value, or should the property override from the last resource - /// processed override previous values? - ///

- ///

- /// The default value is ; i.e. a property - /// override from the last resource to be processed overrides previous - /// values. - ///

- ///
- /// - /// if the property override from the last resource - /// processed overrides previous values. - /// - public bool LastLocationOverrides - { - set { _lastLocationOverrides = value; } - } - - /// - /// Return the order value of this object, where a higher value means greater in - /// terms of sorting. - /// - /// The order value. - /// - public int Order - { - get { return _order; } - set { _order = value; } - } - - /// - /// The default properties to be applied. - /// - /// - ///

- /// These are to be considered defaults, to be overridden by values - /// loaded from other resources. - ///

- ///
- public NameValueCollection Properties - { - get { return _defaultProperties; } - set { _defaultProperties = value; } - } - - /// - /// The location of the .NET .config file that contains the property - /// overrides that are to be applied. - /// - public IResource Location - { - set { _locations = new IResource[] {value}; } - } - - /// - /// The locations of the .NET .config files containing the property - /// overrides that are to be applied. - /// - public IResource[] Locations - { - set { _locations = value; } - } - - /// - /// The configuration sections to look for within the .config files. - /// - /// - /// - public string[] ConfigSections - { - get + if (_configSections == null + || _configSections.Length == 0) { - if (_configSections == null - || _configSections.Length == 0) - { - _configSections = new string[] {DefaultConfigSectionName}; - } - return _configSections; + _configSections = new string[] { DefaultConfigSectionName }; } - set { _configSections = value; } + + return _configSections; } + set { _configSections = value; } + } - /// - /// Should a failure to find a .config file be ignored? - /// - /// - ///

- /// is only appropriate if the .config file is - /// completely optional. The default is . - ///

- ///
- /// - /// if a failure to find a .config file is to be - /// ignored. - /// - public bool IgnoreResourceNotFound + /// + /// Should a failure to find a .config file be ignored? + /// + /// + ///

+ /// is only appropriate if the .config file is + /// completely optional. The default is . + ///

+ ///
+ /// + /// if a failure to find a .config file is to be + /// ignored. + /// + public bool IgnoreResourceNotFound + { + set { _ignoreResourceNotFound = value; } + } + + #endregion + + /// + /// Modify the application context's internal object factory after its + /// standard initialization. + /// + /// + /// The object factory used by the application context. + /// + /// + /// In case of errors. + /// + /// + public void PostProcessObjectFactory(IConfigurableListableObjectFactory factory) + { + try { - set { _ignoreResourceNotFound = value; } + NameValueCollection properties = new NameValueCollection(); + InitializeWithDefaultProperties(properties); + LoadProperties(properties); + ProcessProperties(factory, properties); } - - #endregion - - /// - /// Modify the application context's internal object factory after its - /// standard initialization. - /// - /// - /// The object factory used by the application context. - /// - /// - /// In case of errors. - /// - /// - public void PostProcessObjectFactory(IConfigurableListableObjectFactory factory) + catch (Exception ex) { - try + if (typeof(ObjectsException).IsInstanceOfType(ex)) { - NameValueCollection properties = new NameValueCollection(); - InitializeWithDefaultProperties(properties); - LoadProperties(properties); - ProcessProperties(factory, properties); - } - catch (Exception ex) - { - if (typeof(ObjectsException).IsInstanceOfType(ex)) - { - throw; - } - else - { - throw new ObjectsException( - "Errored while postprocessing an object factory.", ex); - } - } - } - - /// - /// Loads properties from the configuration sections - /// specified in into . - /// - /// The instance to be filled with properties. - protected virtual void LoadProperties(NameValueCollection properties) - { - string[] configSections = ConfigSections; - if (_locations != null) - { - ValidateConfigSections(configSections); - bool usingMultipleConfigSections = configSections.Length > 1; - int sectionNameIndex = 0; - foreach (IResource resource in _locations) - { - #region Instrumentation - - if (_log.IsEnabled(LogLevel.Debug)) - { - _log.LogDebug(string.Format( - CultureInfo.InvariantCulture, - "Loading configuration from '{0}'.", resource)); - } - - #endregion - - string sectionName = configSections[sectionNameIndex]; - if (resource is ConfigSectionResource) - { - ConfigurationReader.PopulateFromAppConfig( - properties, sectionName, _lastLocationOverrides); - } - else - { - if (resource.Exists) - { - ConfigurationReader.Read( - resource, sectionName, properties, _lastLocationOverrides); - } - else - { - string errorMessage = "Could not load configuration from " + resource; - if (_ignoreResourceNotFound) - { - #region Instrumentation - - if (_log.IsEnabled(LogLevel.Warning)) - { - _log.LogWarning(errorMessage); - } - - #endregion - } - else - { - throw new ObjectInitializationException(errorMessage); - } - } - } - if (usingMultipleConfigSections) - { - ++sectionNameIndex; - } - } + throw; } else { - foreach (string sectionName in configSections) + throw new ObjectsException( + "Errored while postprocessing an object factory.", ex); + } + } + } + + /// + /// Loads properties from the configuration sections + /// specified in into . + /// + /// The instance to be filled with properties. + protected virtual void LoadProperties(NameValueCollection properties) + { + string[] configSections = ConfigSections; + if (_locations != null) + { + ValidateConfigSections(configSections); + bool usingMultipleConfigSections = configSections.Length > 1; + int sectionNameIndex = 0; + foreach (IResource resource in _locations) + { + #region Instrumentation + + if (_log.IsEnabled(LogLevel.Debug)) + { + _log.LogDebug(string.Format( + CultureInfo.InvariantCulture, + "Loading configuration from '{0}'.", resource)); + } + + #endregion + + string sectionName = configSections[sectionNameIndex]; + if (resource is ConfigSectionResource) { ConfigurationReader.PopulateFromAppConfig( properties, sectionName, _lastLocationOverrides); } - } - } - - /// - /// Apply the given properties to the supplied - /// . - /// - /// - /// The - /// used by the application context. - /// - /// The properties to apply. - /// - /// If an error occured. - /// - protected abstract void ProcessProperties( - IConfigurableListableObjectFactory factory, - NameValueCollection props); - - /// - /// Validates the supplied . - /// - /// - ///

- /// Basically, if external locations are specified, ensure that either - /// one or a like number of config sections are also specified. - ///

- ///
- /// - /// The to be validated. - /// - private void ValidateConfigSections(string[] configSections) - { - if (_locations.Length != configSections.Length) - { - // if only one config section is specified for all locations that's cool... - if (configSections.Length != 1) + else { - throw new ObjectInitializationException( - "Invalid number of config sections specified."); + if (resource.Exists) + { + ConfigurationReader.Read( + resource, sectionName, properties, _lastLocationOverrides); + } + else + { + string errorMessage = "Could not load configuration from " + resource; + if (_ignoreResourceNotFound) + { + #region Instrumentation + + if (_log.IsEnabled(LogLevel.Warning)) + { + _log.LogWarning(errorMessage); + } + + #endregion + } + else + { + throw new ObjectInitializationException(errorMessage); + } + } + } + + if (usingMultipleConfigSections) + { + ++sectionNameIndex; } } } - - /// - /// Simply initializes the supplied - /// collection with this instances default - /// (if any). - /// - /// - /// The collection to be so initialized. - /// - private void InitializeWithDefaultProperties(NameValueCollection properties) + else { - if (Properties != null) + foreach (string sectionName in configSections) { - properties.Add(Properties); + ConfigurationReader.PopulateFromAppConfig( + properties, sectionName, _lastLocationOverrides); } } } + + /// + /// Apply the given properties to the supplied + /// . + /// + /// + /// The + /// used by the application context. + /// + /// The properties to apply. + /// + /// If an error occured. + /// + protected abstract void ProcessProperties( + IConfigurableListableObjectFactory factory, + NameValueCollection props); + + /// + /// Validates the supplied . + /// + /// + ///

+ /// Basically, if external locations are specified, ensure that either + /// one or a like number of config sections are also specified. + ///

+ ///
+ /// + /// The to be validated. + /// + private void ValidateConfigSections(string[] configSections) + { + if (_locations.Length != configSections.Length) + { + // if only one config section is specified for all locations that's cool... + if (configSections.Length != 1) + { + throw new ObjectInitializationException( + "Invalid number of config sections specified."); + } + } + } + + /// + /// Simply initializes the supplied + /// collection with this instances default + /// (if any). + /// + /// + /// The collection to be so initialized. + /// + private void InitializeWithDefaultProperties(NameValueCollection properties) + { + if (Properties != null) + { + properties.Add(Properties); + } + } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/PropertyRetrievingFactoryObject.cs b/src/Spring/Spring.Core/Objects/Factory/Config/PropertyRetrievingFactoryObject.cs index fbb47b31..63005886 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/PropertyRetrievingFactoryObject.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/PropertyRetrievingFactoryObject.cs @@ -20,277 +20,284 @@ using System.Reflection; using System.Text; - using Spring.Core; using Spring.Core.TypeResolution; using Spring.Util; -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// implementation that +/// retrieves a or non-static public property value. +/// +/// +///

+/// Typically used for retrieving public property values. +///

+///
+/// Rick Evans (.NET) +[Serializable] +public class PropertyRetrievingFactoryObject : AbstractFactoryObject, IInitializingObject { - /// - /// implementation that - /// retrieves a or non-static public property value. - /// - /// - ///

- /// Typically used for retrieving public property values. - ///

- ///
- /// Rick Evans (.NET) - [Serializable] - public class PropertyRetrievingFactoryObject : AbstractFactoryObject, IInitializingObject - { - #region Constructor (s) / Destructor + #region Constructor (s) / Destructor - /// - /// Creates a new instance of the - /// class. - /// - public PropertyRetrievingFactoryObject() - { - Arguments = new object[] {}; - } + /// + /// Creates a new instance of the + /// class. + /// + public PropertyRetrievingFactoryObject() + { + Arguments = new object[] { }; + } - #endregion + #endregion - #region Properties + #region Properties - /// - /// The of the static property - /// to be retrieved. - /// - public string StaticProperty - { - set - { - AssertUtils.ArgumentNotNull(value, "StaticProperty"); - TypeAssemblyHolder info = new TypeAssemblyHolder(value); - string typeName = info.TypeName; - int indexWherePropertyStarts = 0; - do - { - try - { - indexWherePropertyStarts = typeName.LastIndexOf('.'); + /// + /// The of the static property + /// to be retrieved. + /// + public string StaticProperty + { + set + { + AssertUtils.ArgumentNotNull(value, "StaticProperty"); + TypeAssemblyHolder info = new TypeAssemblyHolder(value); + string typeName = info.TypeName; + int indexWherePropertyStarts = 0; + do + { + try + { + indexWherePropertyStarts = typeName.LastIndexOf('.'); - #region Sanity Check + #region Sanity Check - if (indexWherePropertyStarts == -1 - || indexWherePropertyStarts == typeName.Length) - { - throw new ArgumentException( - "The value passed to the StaticProperty property must be a fully " + - "qualified Type plus property name: " + - "e.g. 'Example.MyExampleClass.MyProperty, MyAssembly'"); - } + if (indexWherePropertyStarts == -1 + || indexWherePropertyStarts == typeName.Length) + { + throw new ArgumentException( + "The value passed to the StaticProperty property must be a fully " + + "qualified Type plus property name: " + + "e.g. 'Example.MyExampleClass.MyProperty, MyAssembly'"); + } - #endregion + #endregion - typeName = typeName.Substring(0, indexWherePropertyStarts); - StringBuilder buffer = new StringBuilder(typeName); - if (info.IsAssemblyQualified) - { - buffer.Append(TypeAssemblyHolder.TypeAssemblySeparator); - buffer.Append(info.AssemblyName); - } - TargetType = TypeResolutionUtils.ResolveType(buffer.ToString()); - } - catch (TypeLoadException) - { - } - } while (TargetType == null); - TargetProperty = info.TypeName.Substring(indexWherePropertyStarts + 1); - } - } + typeName = typeName.Substring(0, indexWherePropertyStarts); + StringBuilder buffer = new StringBuilder(typeName); + if (info.IsAssemblyQualified) + { + buffer.Append(TypeAssemblyHolder.TypeAssemblySeparator); + buffer.Append(info.AssemblyName); + } - /// - /// Arguments for the property invocation. - /// - /// - ///

- /// If this property is not set, or the value passed to the setter invocation - /// is a null or zero-length array, a property with no arguments is assumed. - ///

- ///
- public object[] Arguments - { - get { return _arguments; } - set - { - if (value != null) - { - this._arguments = value; - } - } - } + TargetType = TypeResolutionUtils.ResolveType(buffer.ToString()); + } + catch (TypeLoadException) + { + } + } while (TargetType == null); - /// - /// The name of the property the value of which is to be retrieved. - /// - /// - ///

- /// Refers to either a property or a non-static property, - /// depending on a target object being set. - ///

- ///
- public string TargetProperty - { - get { return _targetProperty; } - set { _targetProperty = value; } - } + TargetProperty = info.TypeName.Substring(indexWherePropertyStarts + 1); + } + } - /// - /// The object instance on which the property is defined. - /// - public object TargetObject - { - get { return _targetObject; } - set - { - _targetObject = value; - _targetObjectWrapper = new ObjectWrapper(_targetObject); - } - } + /// + /// Arguments for the property invocation. + /// + /// + ///

+ /// If this property is not set, or the value passed to the setter invocation + /// is a null or zero-length array, a property with no arguments is assumed. + ///

+ ///
+ public object[] Arguments + { + get { return _arguments; } + set + { + if (value != null) + { + this._arguments = value; + } + } + } - /// - /// The on which the property is defined. - /// - public Type TargetType - { - get { return _targetType; } - set { _targetType = value; } - } + /// + /// The name of the property the value of which is to be retrieved. + /// + /// + ///

+ /// Refers to either a property or a non-static property, + /// depending on a target object being set. + ///

+ ///
+ public string TargetProperty + { + get { return _targetProperty; } + set { _targetProperty = value; } + } - /// - /// Return the type of object that this - /// creates, or - /// if not known in advance. - /// - public override Type ObjectType - { - get { return (Property == null) ? null : Property.PropertyType; } - } + /// + /// The object instance on which the property is defined. + /// + public object TargetObject + { + get { return _targetObject; } + set + { + _targetObject = value; + _targetObjectWrapper = new ObjectWrapper(_targetObject); + } + } - private PropertyInfo Property - { - get { return _property; } - set { _property = value; } - } + /// + /// The on which the property is defined. + /// + public Type TargetType + { + get { return _targetType; } + set { _targetType = value; } + } - #endregion + /// + /// Return the type of object that this + /// creates, or + /// if not known in advance. + /// + public override Type ObjectType + { + get { return (Property == null) ? null : Property.PropertyType; } + } - #region Methods + private PropertyInfo Property + { + get { return _property; } + set { _property = value; } + } - /// - /// Invoked by an - /// after it has set all object properties supplied - /// (and satisfied - /// and ApplicationContextAware). - /// - /// - /// In the event of misconfiguration (such as failure to set an essential - /// property) or if initialization fails. - /// - public override void AfterPropertiesSet() - { - if (TargetType == null - && TargetObject == null) - { - throw new ArgumentException("One of the TargetType or TargetObject properties must be set."); - } - if (TargetProperty == null) - { - throw new ArgumentException("The TargetProperty property is required."); - } - Type targetType = null; - BindingFlags propertyFlags = BindingFlags.Public | BindingFlags.IgnoreCase; - if (TargetObject == null) - { - // a static property... - propertyFlags |= BindingFlags.Static; - targetType = TargetType; - if (TargetProperty.IndexOf(".") == -1) - { - Property = targetType.GetProperty(TargetProperty, propertyFlags); - } - else - { - // $�%#@! a nested static property... recurse to the end property - string property = TargetProperty; - int propertyIndex = property.IndexOf("."); - string startProperty = property.Substring(0, propertyIndex); - Property = targetType.GetProperty(startProperty, propertyFlags); - TargetObject = Property.GetValue(null, new object[] {}); - TargetProperty = property.Substring(propertyIndex + 1); - AfterPropertiesSet(); - } - } - else - { - // an instance property... - propertyFlags |= BindingFlags.Instance; - targetType = TargetObject.GetType(); + #endregion - // using the object wrapper does nested property lookup - Property = _targetObjectWrapper.GetPropertyInfo(TargetProperty); - } - if (Property == null) - { - throw new InvalidPropertyException(targetType, TargetProperty); - } - if (!Property.CanRead) - { - throw new NotWritablePropertyException(TargetProperty, targetType); - } - base.AfterPropertiesSet(); - } + #region Methods - /// - /// Template method that subclasses must override to construct the object - /// returned by this factory. - /// - /// - /// If an exception occured during object creation. - /// - /// The object returned by this factory. - protected override object CreateInstance() - { - object instance = null; - object target = null; - if (TargetObject != null) - { - target = TargetObject; - } - try - { - if (Arguments.Length == 0 && target != null) - { - // using object wrapper supports nested property lookup... - instance = _targetObjectWrapper.GetPropertyValue(_targetProperty); - } - else - { - instance = Property.GetValue(target, Arguments); - } - } - catch (Exception ex) - { - throw new FatalObjectException("Error reading property value.", ex); - } - return instance; - } + /// + /// Invoked by an + /// after it has set all object properties supplied + /// (and satisfied + /// and ApplicationContextAware). + /// + /// + /// In the event of misconfiguration (such as failure to set an essential + /// property) or if initialization fails. + /// + public override void AfterPropertiesSet() + { + if (TargetType == null + && TargetObject == null) + { + throw new ArgumentException("One of the TargetType or TargetObject properties must be set."); + } - #endregion + if (TargetProperty == null) + { + throw new ArgumentException("The TargetProperty property is required."); + } - #region Fields + Type targetType = null; + BindingFlags propertyFlags = BindingFlags.Public | BindingFlags.IgnoreCase; + if (TargetObject == null) + { + // a static property... + propertyFlags |= BindingFlags.Static; + targetType = TargetType; + if (TargetProperty.IndexOf(".") == -1) + { + Property = targetType.GetProperty(TargetProperty, propertyFlags); + } + else + { + // $�%#@! a nested static property... recurse to the end property + string property = TargetProperty; + int propertyIndex = property.IndexOf("."); + string startProperty = property.Substring(0, propertyIndex); + Property = targetType.GetProperty(startProperty, propertyFlags); + TargetObject = Property.GetValue(null, new object[] { }); + TargetProperty = property.Substring(propertyIndex + 1); + AfterPropertiesSet(); + } + } + else + { + // an instance property... + propertyFlags |= BindingFlags.Instance; + targetType = TargetObject.GetType(); - private string _targetProperty; - private ObjectWrapper _targetObjectWrapper; - private object _targetObject; - private Type _targetType; - private PropertyInfo _property; - private object[] _arguments; + // using the object wrapper does nested property lookup + Property = _targetObjectWrapper.GetPropertyInfo(TargetProperty); + } - #endregion - } + if (Property == null) + { + throw new InvalidPropertyException(targetType, TargetProperty); + } + + if (!Property.CanRead) + { + throw new NotWritablePropertyException(TargetProperty, targetType); + } + + base.AfterPropertiesSet(); + } + + /// + /// Template method that subclasses must override to construct the object + /// returned by this factory. + /// + /// + /// If an exception occured during object creation. + /// + /// The object returned by this factory. + protected override object CreateInstance() + { + object instance = null; + object target = null; + if (TargetObject != null) + { + target = TargetObject; + } + + try + { + if (Arguments.Length == 0 && target != null) + { + // using object wrapper supports nested property lookup... + instance = _targetObjectWrapper.GetPropertyValue(_targetProperty); + } + else + { + instance = Property.GetValue(target, Arguments); + } + } + catch (Exception ex) + { + throw new FatalObjectException("Error reading property value.", ex); + } + + return instance; + } + + #endregion + + #region Fields + + private string _targetProperty; + private ObjectWrapper _targetObjectWrapper; + private object _targetObject; + private Type _targetType; + private PropertyInfo _property; + private object[] _arguments; + + #endregion } diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/RegistryVariableSource.cs b/src/Spring/Spring.Core/Objects/Factory/Config/RegistryVariableSource.cs index e67ba677..c8230124 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/RegistryVariableSource.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/RegistryVariableSource.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -21,75 +21,76 @@ using System.Collections.Specialized; using Microsoft.Win32; -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Implementation of that +/// resolves variable name against registry key. +/// +/// Aleksandar Seovic +public class RegistryVariableSource : IVariableSource { + private static readonly object NULL = new object(); + private RegistryKey key; + /// - /// Implementation of that - /// resolves variable name against registry key. + /// Gets or sets the registry key to obtain variable values from. /// - /// Aleksandar Seovic - public class RegistryVariableSource : IVariableSource + /// + /// The registry key to obtain variable values from. + /// + public RegistryKey Key { - private static readonly object NULL = new object(); - private RegistryKey key; - - /// - /// Gets or sets the registry key to obtain variable values from. - /// - /// - /// The registry key to obtain variable values from. - /// - public RegistryKey Key - { - get { return key; } - set { key = value; } - } - - /// - /// Before requesting a variable resolution, a client should - /// ask, whether the source can resolve a particular variable name. - /// - /// the name of the variable to resolve - /// true if the variable can be resolved, false otherwise - public bool CanResolveVariable(string name) - { - return (key != null && key.GetValue(name, NULL) != NULL); - } - - /// - /// Resolves variable value for the specified variable name. - /// - /// - /// The name of the variable to resolve. - /// - /// - /// This implementation resolves REG_SZ as well as REG_MULTI_SZ values. In case of a REG_MULTI_SZ value, - /// strings are concatenated to a comma-separated list following - /// - /// - /// The variable value if able to resolve, null otherwise. - /// - public virtual string ResolveVariable(string name) - { - object res = Key.GetValue(name); - if (res is string) - { - return (string) res; - } - else if (res is string[]) - { - NameValueCollection tmp = new NameValueCollection(); - foreach(string val in (string[])res) - { - tmp.Add(name, val); - } - return tmp.Get(name); - } - else if (res is int) - { - return res.ToString(); - } - return null; - } + get { return key; } + set { key = value; } } -} \ No newline at end of file + + /// + /// Before requesting a variable resolution, a client should + /// ask, whether the source can resolve a particular variable name. + /// + /// the name of the variable to resolve + /// true if the variable can be resolved, false otherwise + public bool CanResolveVariable(string name) + { + return (key != null && key.GetValue(name, NULL) != NULL); + } + + /// + /// Resolves variable value for the specified variable name. + /// + /// + /// The name of the variable to resolve. + /// + /// + /// This implementation resolves REG_SZ as well as REG_MULTI_SZ values. In case of a REG_MULTI_SZ value, + /// strings are concatenated to a comma-separated list following + /// + /// + /// The variable value if able to resolve, null otherwise. + /// + public virtual string ResolveVariable(string name) + { + object res = Key.GetValue(name); + if (res is string) + { + return (string) res; + } + else if (res is string[]) + { + NameValueCollection tmp = new NameValueCollection(); + foreach (string val in (string[]) res) + { + tmp.Add(name, val); + } + + return tmp.Get(name); + } + else if (res is int) + { + return res.ToString(); + } + + return null; + } +} diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/ResourceHandlerConfigurer.cs b/src/Spring/Spring.Core/Objects/Factory/Config/ResourceHandlerConfigurer.cs index d8d62812..997d38e5 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/ResourceHandlerConfigurer.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/ResourceHandlerConfigurer.cs @@ -21,76 +21,74 @@ using System.Collections; using Spring.Core.IO; -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// +/// implementation that allows for convenient registration of custom +/// IResource implementations. +/// +/// +///

+/// Because the +/// class implements the +/// +/// interface, instances of this class that have been exposed in the +/// scope of an +/// will +/// automatically be picked up by the application context and made +/// available to the IoC container whenever resolution of IResources is required. +///

+///
+/// Mark Pollack +/// +/// +[Serializable] +public class ResourceHandlerConfigurer : AbstractConfigurer { + private IDictionary resourceHandlers; + /// - /// - /// implementation that allows for convenient registration of custom - /// IResource implementations. + /// The IResource implementations, i.e. resource handlers, to register. /// /// ///

- /// Because the - /// class implements the - /// - /// interface, instances of this class that have been exposed in the - /// scope of an - /// will - /// automatically be picked up by the application context and made - /// available to the IoC container whenever resolution of IResources is required. + /// The has the + /// contains the resource protocol name as the key and type as the value. + /// The key name can either be a string or an object, in which case + /// ToString() will be used to obtain the string name. + /// The value can be the fully qualified name of the IResource + /// implementation, a string, or + /// an actual of the IResource class + /// ///

///
- /// Mark Pollack - /// - /// - [Serializable] - public class ResourceHandlerConfigurer : AbstractConfigurer + public IDictionary ResourceHandlers { - private IDictionary resourceHandlers; + set { resourceHandlers = value; } + } - /// - /// The IResource implementations, i.e. resource handlers, to register. - /// - /// - ///

- /// The has the - /// contains the resource protocol name as the key and type as the value. - /// The key name can either be a string or an object, in which case - /// ToString() will be used to obtain the string name. - /// The value can be the fully qualified name of the IResource - /// implementation, a string, or - /// an actual of the IResource class - /// - ///

- ///
- public IDictionary ResourceHandlers + /// + /// Registers custom IResource implementations. The supplied + /// is not used since IResourse implementations + /// are registered with a global + /// + /// + /// The object factory. + /// + /// + /// In case of errors. + /// + public override void PostProcessObjectFactory( + IConfigurableListableObjectFactory factory) + { + if (resourceHandlers != null) { - set { resourceHandlers = value; } - } - - /// - /// Registers custom IResource implementations. The supplied - /// is not used since IResourse implementations - /// are registered with a global - /// - /// - /// The object factory. - /// - /// - /// In case of errors. - /// - public override void PostProcessObjectFactory( - IConfigurableListableObjectFactory factory) - { - if (resourceHandlers != null) + foreach (DictionaryEntry entry in resourceHandlers) { - foreach (DictionaryEntry entry in resourceHandlers) - { - string protocolName = entry.Key.ToString(); - Type type = ResolveRequiredType(entry.Value, "value", "custom IResource implementation"); - ResourceHandlerRegistry.RegisterResourceHandler(protocolName, type); - - } + string protocolName = entry.Key.ToString(); + Type type = ResolveRequiredType(entry.Value, "value", "custom IResource implementation"); + ResourceHandlerRegistry.RegisterResourceHandler(protocolName, type); } } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/ResourceManagerFactoryObject.cs b/src/Spring/Spring.Core/Objects/Factory/Config/ResourceManagerFactoryObject.cs index 031ba7d3..26b6ec11 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/ResourceManagerFactoryObject.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/ResourceManagerFactoryObject.cs @@ -20,125 +20,125 @@ using System.Reflection; using System.Resources; - using Spring.Util; -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// A convenience class to create a +/// given the resource base +/// name and assembly name. +/// +/// +///

+/// This is currently the preferred way of injecting resources into view +/// tier components (such as Windows Forms GUIs and ASP.NET ASPX pages). +/// A GUI component (typically a Windows Form) is injected with +/// an instance, and can +/// then proceed to use the various GetXxx() methods on the +/// to retrieve images, +/// strings, custom resources, etc. +///

+///
+/// Mark Pollack +/// +/// +/// +[Serializable] +public class ResourceManagerFactoryObject : AbstractFactoryObject { + private string _baseName; + private string _assemblyName; + /// - /// A convenience class to create a - /// given the resource base - /// name and assembly name. + /// The root name of the resources. /// /// ///

- /// This is currently the preferred way of injecting resources into view - /// tier components (such as Windows Forms GUIs and ASP.NET ASPX pages). - /// A GUI component (typically a Windows Form) is injected with - /// an instance, and can - /// then proceed to use the various GetXxx() methods on the - /// to retrieve images, - /// strings, custom resources, etc. + /// For example, the root name for the resource file named + /// "MyResource.en-US.resources" is "MyResource". ///

+ /// + /// The namespace is also prefixed before the resource file name. + /// ///
- /// Mark Pollack + public string BaseName + { + get { return _baseName; } + set { _baseName = value; } + } + + /// + /// The string representation of the assembly that contains the resource. + /// + public string AssemblyName + { + get { return _assemblyName; } + set { _assemblyName = value; } + } + + /// + /// The . + /// + public override Type ObjectType + { + get { return typeof(ResourceManager); } + } + + /// + /// Creates a . + /// + /// + /// If an exception occured during object creation. + /// + /// The object returned by this factory. /// /// - /// - [Serializable] - public class ResourceManagerFactoryObject : AbstractFactoryObject + protected override object CreateInstance() { - private string _baseName; - private string _assemblyName; - - /// - /// The root name of the resources. - /// - /// - ///

- /// For example, the root name for the resource file named - /// "MyResource.en-US.resources" is "MyResource". - ///

- /// - /// The namespace is also prefixed before the resource file name. - /// - ///
- public string BaseName + Assembly assembly; + try { - get { return _baseName; } - set { _baseName = value; } + assembly = Assembly.Load(AssemblyName); + } + catch (FileLoadException) + { + throw new ArgumentException("Not able to load assembly with a given name [" + _assemblyName + "]"); } - /// - /// The string representation of the assembly that contains the resource. - /// - public string AssemblyName + if (assembly == null) { - get { return _assemblyName; } - set { _assemblyName = value; } + throw new ArgumentException("Not able to load assembly with a given name [" + _assemblyName + "]"); } - /// - /// The . - /// - public override Type ObjectType + return new ResourceManager(_baseName, assembly); + } + + /// + /// Invoked by an + /// after it has set all object properties supplied + /// (and satisfied the + /// + /// and + /// interfaces). + /// + /// + /// In the event of misconfiguration (such as failure to set an essential + /// property) or if initialization fails. + /// + /// + public override void AfterPropertiesSet() + { + if (StringUtils.IsNullOrEmpty(BaseName)) { - get { return typeof(ResourceManager); } + throw new ArgumentException("The 'BaseName' property for the resource is required."); } - /// - /// Creates a . - /// - /// - /// If an exception occured during object creation. - /// - /// The object returned by this factory. - /// - /// - protected override object CreateInstance() + if (StringUtils.IsNullOrEmpty(AssemblyName)) { - Assembly assembly; - try - { - assembly = Assembly.Load(AssemblyName); - } - catch (FileLoadException) - { - throw new ArgumentException("Not able to load assembly with a given name [" + _assemblyName + "]"); - } - - if (assembly == null) - { - throw new ArgumentException("Not able to load assembly with a given name [" + _assemblyName + "]"); - } - - return new ResourceManager(_baseName, assembly); + throw new ArgumentException("The 'AssemblyName' property for the resource is required."); } - /// - /// Invoked by an - /// after it has set all object properties supplied - /// (and satisfied the - /// - /// and - /// interfaces). - /// - /// - /// In the event of misconfiguration (such as failure to set an essential - /// property) or if initialization fails. - /// - /// - public override void AfterPropertiesSet() - { - if (StringUtils.IsNullOrEmpty(BaseName)) - { - throw new ArgumentException("The 'BaseName' property for the resource is required."); - } - if (StringUtils.IsNullOrEmpty(AssemblyName)) - { - throw new ArgumentException("The 'AssemblyName' property for the resource is required."); - } - base.AfterPropertiesSet(); - } + base.AfterPropertiesSet(); } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/RuntimeObjectReference.cs b/src/Spring/Spring.Core/Objects/Factory/Config/RuntimeObjectReference.cs index da8b96b9..731ae4aa 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/RuntimeObjectReference.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/RuntimeObjectReference.cs @@ -20,143 +20,142 @@ using System.Globalization; -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Immutable placeholder class used for the value of a +/// object when it's a reference +/// to another object in this factory to be resolved at runtime. +/// +/// Rod Johnson +/// Rick Evans (.NET) +[Serializable] +public class RuntimeObjectReference { + #region Constructor (s) / Destructor + /// - /// Immutable placeholder class used for the value of a - /// object when it's a reference - /// to another object in this factory to be resolved at runtime. + /// Creates a new instance of the + /// + /// class. /// - /// Rod Johnson - /// Rick Evans (.NET) - [Serializable] - public class RuntimeObjectReference + /// + ///

+ /// This does not mark this object as being a reference to + /// another object in any parent factory. + ///

+ ///
+ /// The name of the target object. + public RuntimeObjectReference(string objectName) + : this(objectName, false) { - #region Constructor (s) / Destructor - - /// - /// Creates a new instance of the - /// - /// class. - /// - /// - ///

- /// This does not mark this object as being a reference to - /// another object in any parent factory. - ///

- ///
- /// The name of the target object. - public RuntimeObjectReference(string objectName) - : this(objectName, false) - { - } - - /// - /// Creates a new instance of the - /// - /// class. - /// - /// - ///

- /// This variant constructor allows a client to specifiy whether or not - /// this object is a reference to another object in a parent factory. - ///

- ///
- /// The name of the target object. - /// - /// Whether this object is an explicit reference to an object in a - /// parent factory. - /// - public RuntimeObjectReference(string objectName, bool isToParent) - { - _objectName = objectName; - _isToParent = isToParent; - } - - #endregion - - #region Properties - - /// - /// Return the target object name. - /// - public string ObjectName - { - get { return _objectName; } - } - - /// - /// Is this is an explicit reference to an object in the parent - /// factory? - /// - /// - /// if this is an explicit reference to an - /// object in the parent factory. - /// - public bool IsToParent - { - get { return _isToParent; } - } - - #endregion - - #region Methods - - /// - /// Returns a string representation of this instance. - /// - /// A string representation of this instance. - public override string ToString() - { - return string.Format( - CultureInfo.InvariantCulture, "<{0}>", ObjectName); - } - - #endregion - - #region Fields - - private string _objectName; - - private bool _isToParent; - - #endregion - - #region Equality Members - - /// - /// Determines whether the specified RuntimeObjectReference is equal to the current RuntimeObjectReference. - /// - /// true if the specified RuntimeObjectReference is equal to the current RuntimeObjectReference; otherwise, false. - protected bool Equals(RuntimeObjectReference other) - { - return string.Equals(_objectName, other._objectName) && _isToParent.Equals(other._isToParent); - } - - /// - /// Determines whether the specified System.Object is equal to the current RuntimeObjectReference. - /// - /// true if the specified RuntimeObjectReference is equal to the current RuntimeObjectReference; otherwise, false. - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != this.GetType()) return false; - return Equals((RuntimeObjectReference)obj); - } - - /// - /// Serves as a hash function for RuntimeObjectReference. - /// - /// A hash code for the currentRuntimeObjectReference. - public override int GetHashCode() - { - unchecked - { - return (_objectName.GetHashCode() * 397) ^ _isToParent.GetHashCode(); - } - } - - #endregion } + + /// + /// Creates a new instance of the + /// + /// class. + /// + /// + ///

+ /// This variant constructor allows a client to specifiy whether or not + /// this object is a reference to another object in a parent factory. + ///

+ ///
+ /// The name of the target object. + /// + /// Whether this object is an explicit reference to an object in a + /// parent factory. + /// + public RuntimeObjectReference(string objectName, bool isToParent) + { + _objectName = objectName; + _isToParent = isToParent; + } + + #endregion + + #region Properties + + /// + /// Return the target object name. + /// + public string ObjectName + { + get { return _objectName; } + } + + /// + /// Is this is an explicit reference to an object in the parent + /// factory? + /// + /// + /// if this is an explicit reference to an + /// object in the parent factory. + /// + public bool IsToParent + { + get { return _isToParent; } + } + + #endregion + + #region Methods + + /// + /// Returns a string representation of this instance. + /// + /// A string representation of this instance. + public override string ToString() + { + return string.Format( + CultureInfo.InvariantCulture, "<{0}>", ObjectName); + } + + #endregion + + #region Fields + + private string _objectName; + + private bool _isToParent; + + #endregion + + #region Equality Members + + /// + /// Determines whether the specified RuntimeObjectReference is equal to the current RuntimeObjectReference. + /// + /// true if the specified RuntimeObjectReference is equal to the current RuntimeObjectReference; otherwise, false. + protected bool Equals(RuntimeObjectReference other) + { + return string.Equals(_objectName, other._objectName) && _isToParent.Equals(other._isToParent); + } + + /// + /// Determines whether the specified System.Object is equal to the current RuntimeObjectReference. + /// + /// true if the specified RuntimeObjectReference is equal to the current RuntimeObjectReference; otherwise, false. + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != this.GetType()) return false; + return Equals((RuntimeObjectReference) obj); + } + + /// + /// Serves as a hash function for RuntimeObjectReference. + /// + /// A hash code for the currentRuntimeObjectReference. + public override int GetHashCode() + { + unchecked + { + return (_objectName.GetHashCode() * 397) ^ _isToParent.GetHashCode(); + } + } + + #endregion } diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/SetFactoryObject.cs b/src/Spring/Spring.Core/Objects/Factory/Config/SetFactoryObject.cs index 1347673e..c6111643 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/SetFactoryObject.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/SetFactoryObject.cs @@ -22,96 +22,99 @@ using System.Globalization; using Spring.Collections; using Spring.Util; -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Simple factory object for shared instances. +/// +/// Juergen Hoeller +/// Simon White (.NET) +[Serializable] +public class SetFactoryObject : AbstractFactoryObject { - /// - /// Simple factory object for shared instances. - /// - /// Juergen Hoeller - /// Simon White (.NET) - [Serializable] - public class SetFactoryObject : AbstractFactoryObject - { - private ISet _sourceSet; - private Type _targetSetType = typeof (HybridSet); + private ISet _sourceSet; + private Type _targetSetType = typeof(HybridSet); - /// - /// Set the source . - /// - /// - ///

- /// This value will be used to populate the - /// returned by this factory. - ///

- ///
- public ISet SourceSet - { - set { this._sourceSet = value; } - } + /// + /// Set the source . + /// + /// + ///

+ /// This value will be used to populate the + /// returned by this factory. + ///

+ ///
+ public ISet SourceSet + { + set { this._sourceSet = value; } + } - /// - /// Set the of the - /// implementation to use. - /// - /// - ///

- /// The default is the . - ///

- ///
- public Type TargetSetType - { - set - { - AssertUtils.ArgumentNotNull(value, "value"); - if (!typeof (ISet).IsAssignableFrom(value)) - { - throw new ArgumentException( - string.Format(CultureInfo.InvariantCulture, - "The Type passed to the TargetSetType property must implement the '{0}' interface.", - typeof (ISet).FullName)); - } - if (value.IsInterface) - { - throw new ArgumentException( - string.Format(CultureInfo.InvariantCulture, - "The Type passed to the TargetSetType property cannot be an interface; it must be a concrete class that implements the '{0}' interface.", - ObjectType.FullName)); - } - if (value.IsAbstract) - { - throw new ArgumentException( - string.Format(CultureInfo.InvariantCulture, - "The Type passed to the TargetSetType property cannot be abstract (MustInherit in VisualBasic.NET); it must be a concrete class that implements the '{0}' interface.", - ObjectType.FullName)); - } - this._targetSetType = value; - } - } + /// + /// Set the of the + /// implementation to use. + /// + /// + ///

+ /// The default is the . + ///

+ ///
+ public Type TargetSetType + { + set + { + AssertUtils.ArgumentNotNull(value, "value"); + if (!typeof(ISet).IsAssignableFrom(value)) + { + throw new ArgumentException( + string.Format(CultureInfo.InvariantCulture, + "The Type passed to the TargetSetType property must implement the '{0}' interface.", + typeof(ISet).FullName)); + } - /// - /// The of objects created by this factory. - /// - /// - /// Always returns the . - /// - public override Type ObjectType - { - get { return typeof (ISet); } - } + if (value.IsInterface) + { + throw new ArgumentException( + string.Format(CultureInfo.InvariantCulture, + "The Type passed to the TargetSetType property cannot be an interface; it must be a concrete class that implements the '{0}' interface.", + ObjectType.FullName)); + } - /// - /// Constructs a new instance of the target set. - /// - /// The new instance. - protected override object CreateInstance() - { - if (this._sourceSet == null) - { - throw new ArgumentException("The 'SourceSet' property cannot be null (Nothing in Visual Basic.NET)."); - } - Set result = (Set) ObjectUtils.InstantiateType(this._targetSetType); - result.AddAll(this._sourceSet); - return result; - } - } + if (value.IsAbstract) + { + throw new ArgumentException( + string.Format(CultureInfo.InvariantCulture, + "The Type passed to the TargetSetType property cannot be abstract (MustInherit in VisualBasic.NET); it must be a concrete class that implements the '{0}' interface.", + ObjectType.FullName)); + } + + this._targetSetType = value; + } + } + + /// + /// The of objects created by this factory. + /// + /// + /// Always returns the . + /// + public override Type ObjectType + { + get { return typeof(ISet); } + } + + /// + /// Constructs a new instance of the target set. + /// + /// The new instance. + protected override object CreateInstance() + { + if (this._sourceSet == null) + { + throw new ArgumentException("The 'SourceSet' property cannot be null (Nothing in Visual Basic.NET)."); + } + + Set result = (Set) ObjectUtils.InstantiateType(this._targetSetType); + result.AddAll(this._sourceSet); + return result; + } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/SharedStateAwareProcessor.cs b/src/Spring/Spring.Core/Objects/Factory/Config/SharedStateAwareProcessor.cs index 365f7b6a..4bc80750 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/SharedStateAwareProcessor.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/SharedStateAwareProcessor.cs @@ -22,121 +22,123 @@ using System.Collections; using Spring.Core; using Spring.Util; -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Configure all ISharedStateAware objects, delegating concrete handling to the list of . +/// +public class SharedStateAwareProcessor : IObjectPostProcessor, IOrdered { + // holds a list of ISharedStateProvider instances (if any) + private ISharedStateFactory[] _sharedStateFactories = new ISharedStateFactory[0]; + + // holds prio + private int _order = Int32.MaxValue; + /// - /// Configure all ISharedStateAware objects, delegating concrete handling to the list of . + /// Return the order value of this object, where a higher value means greater in + /// terms of sorting. /// - public class SharedStateAwareProcessor : IObjectPostProcessor, IOrdered + /// + ///

+ /// Normally starting with 0 or 1, with indicating + /// greatest. Same order values will result in arbitrary positions for the affected + /// objects. + ///

+ ///

+ /// Higher value can be interpreted as lower priority, consequently the first object + /// has highest priority. + ///

+ ///
+ /// The order value. + public int Order { - // holds a list of ISharedStateProvider instances (if any) - private ISharedStateFactory[] _sharedStateFactories = new ISharedStateFactory[0]; - // holds prio - private int _order = Int32.MaxValue; + get { return _order; } + set { _order = value; } + } - /// - /// Return the order value of this object, where a higher value means greater in - /// terms of sorting. - /// - /// - ///

- /// Normally starting with 0 or 1, with indicating - /// greatest. Same order values will result in arbitrary positions for the affected - /// objects. - ///

- ///

- /// Higher value can be interpreted as lower priority, consequently the first object - /// has highest priority. - ///

- ///
- /// The order value. - public int Order + /// + /// Get/Set the (already ordererd!) list of instances. + /// + /// + /// If this list is not set, the containing object factory will automatically + /// be scanned for instances. + /// + public ISharedStateFactory[] SharedStateFactories + { + get { return _sharedStateFactories; } + set { - get { return _order; } - set { _order = value; } + AssertUtils.ArgumentHasElements(value, "SharedStateFactories"); + _sharedStateFactories = value; + } + } + + /// + /// Creates a new empty instance. + /// + public SharedStateAwareProcessor() + { + } + + /// + /// Creates a new preconfigured instance. + /// + /// + /// priority value affecting order of invocation of this processor. See interface. + public SharedStateAwareProcessor(ISharedStateFactory[] sharedStateFactories, int order) + { + SharedStateFactories = sharedStateFactories; + } + + /// + /// Iterates over configured list of s until + /// the first provider is found that
+ /// a) true == provider.CanProvideState( instance, name )
+ /// b) null != provider.GetSharedState( instance, name )
+ ///
+ public object PostProcessBeforeInitialization(object instance, string name) + { + if (SharedStateFactories.Length == 0) + { + return instance; } - /// - /// Get/Set the (already ordererd!) list of instances. - /// - /// - /// If this list is not set, the containing object factory will automatically - /// be scanned for instances. - /// - public ISharedStateFactory[] SharedStateFactories + ISharedStateAware ssa = instance as ISharedStateAware; + if (ssa != null && ssa.SharedState == null) { - get { return _sharedStateFactories; } - set + // probe for first factory willing to serve shared state + foreach (ISharedStateFactory ssf in _sharedStateFactories) { - AssertUtils.ArgumentHasElements( value, "SharedStateFactories" ); - _sharedStateFactories = value; - } - } - - /// - /// Creates a new empty instance. - /// - public SharedStateAwareProcessor() - { } - - /// - /// Creates a new preconfigured instance. - /// - /// - /// priority value affecting order of invocation of this processor. See interface. - public SharedStateAwareProcessor( ISharedStateFactory[] sharedStateFactories, int order ) - { - SharedStateFactories = sharedStateFactories; - } - - /// - /// Iterates over configured list of s until - /// the first provider is found that
- /// a) true == provider.CanProvideState( instance, name )
- /// b) null != provider.GetSharedState( instance, name )
- ///
- public object PostProcessBeforeInitialization( object instance, string name ) - { - if (SharedStateFactories.Length == 0) - { - return instance; - } - - ISharedStateAware ssa = instance as ISharedStateAware; - if (ssa != null && ssa.SharedState == null) - { - // probe for first factory willing to serve shared state - foreach (ISharedStateFactory ssf in _sharedStateFactories) + if (ssf.CanProvideState(ssa, name)) { - if (ssf.CanProvideState( ssa, name )) + IDictionary sharedState = ssf.GetSharedStateFor(ssa, name); + if (sharedState != null) { - IDictionary sharedState = ssf.GetSharedStateFor( ssa, name ); - if (sharedState != null) - { - ssa.SharedState = sharedState; - break; - } + ssa.SharedState = sharedState; + break; } } } - return instance; } - /// - /// A NoOp for this processor - /// - /// - /// The new object instance. - /// - /// - /// The name of the object. - /// - /// - /// the original . - /// - public object PostProcessAfterInitialization( object instance, string name ) - { - return instance; - } + return instance; + } + + /// + /// A NoOp for this processor + /// + /// + /// The new object instance. + /// + /// + /// The name of the object. + /// + /// + /// the original . + /// + public object PostProcessAfterInitialization(object instance, string name) + { + return instance; } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/SmartInstantiationAwareObjectPostProcessor.cs b/src/Spring/Spring.Core/Objects/Factory/Config/SmartInstantiationAwareObjectPostProcessor.cs index a38d2ef8..c43e7826 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/SmartInstantiationAwareObjectPostProcessor.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/SmartInstantiationAwareObjectPostProcessor.cs @@ -20,42 +20,39 @@ using System.Reflection; -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Extension of the interface, +/// adding a callback for predicting the eventual type of a processed object. +/// +/// This interface is a special purpose interface, mainly for +/// internal use within the framework. In general, application-provided +/// post-processors should simply implement the plain +/// interface or derive from the +/// class. New methods might be added to this interface even in point releases. +/// +/// +/// Juergen Hoeller +/// Mark Pollack (.NET) +public interface SmartInstantiationAwareObjectPostProcessor : IInstantiationAwareObjectPostProcessor { /// - /// Extension of the interface, - /// adding a callback for predicting the eventual type of a processed object. + /// Predicts the type of the object to be eventually returned from this + /// processors callback. /// - /// This interface is a special purpose interface, mainly for - /// internal use within the framework. In general, application-provided - /// post-processors should simply implement the plain - /// interface or derive from the - /// class. New methods might be added to this interface even in point releases. - /// - /// - /// Juergen Hoeller - /// Mark Pollack (.NET) - public interface SmartInstantiationAwareObjectPostProcessor : IInstantiationAwareObjectPostProcessor - { - /// - /// Predicts the type of the object to be eventually returned from this - /// processors callback. - /// - /// The raw Type of the object. - /// Name of the object. - /// The type of the object, or null if not predictable. - /// in case of errors - Type PredictObjectType(Type objectType, string objectName); + /// The raw Type of the object. + /// Name of the object. + /// The type of the object, or null if not predictable. + /// in case of errors + Type PredictObjectType(Type objectType, string objectName); - - /// - /// Determines the candidate constructors to use for the given object. - /// - /// The raw Type of the object. - /// Name of the object. - /// The candidate constructors, or null if none specified - /// in case of errors - ConstructorInfo[] DetermineCandidateConstructors(Type objectType, string objectName); - - } -} + /// + /// Determines the candidate constructors to use for the given object. + /// + /// The raw Type of the object. + /// Name of the object. + /// The candidate constructors, or null if none specified + /// in case of errors + ConstructorInfo[] DetermineCandidateConstructors(Type objectType, string objectName); +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/SpecialFolderVariableSource.cs b/src/Spring/Spring.Core/Objects/Factory/Config/SpecialFolderVariableSource.cs index 29bdac8a..db50eac5 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/SpecialFolderVariableSource.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/SpecialFolderVariableSource.cs @@ -18,51 +18,50 @@ #endregion -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Implementation of that +/// resolves variable name against special folders (as defined by +/// enumeration). +/// +/// Aleksandar Seovic +[Serializable] +public class SpecialFolderVariableSource : IVariableSource { /// - /// Implementation of that - /// resolves variable name against special folders (as defined by - /// enumeration). + /// Before requesting a variable resolution, a client should + /// ask, whether the source can resolve a particular variable name. /// - /// Aleksandar Seovic - [Serializable] - public class SpecialFolderVariableSource : IVariableSource + /// the name of the variable to resolve + /// true if the variable can be resolved, false otherwise + public bool CanResolveVariable(string name) { - /// - /// Before requesting a variable resolution, a client should - /// ask, whether the source can resolve a particular variable name. - /// - /// the name of the variable to resolve - /// true if the variable can be resolved, false otherwise - public bool CanResolveVariable(string name) + return ResolveVariable(name) != null; + } + + /// + /// Resolves specified special folder to its full path. + /// + /// + /// The name of the special folder to resolve. Should be one of the values + /// defined by the enumeration. + /// + /// + /// The folder path if able to resolve, null otherwise. + /// + public string ResolveVariable(string name) + { + try { - return ResolveVariable(name) != null; + Environment.SpecialFolder folder = + (Environment.SpecialFolder) Enum.Parse(typeof(Environment.SpecialFolder), name, true); + + return Environment.GetFolderPath(folder); } - - /// - /// Resolves specified special folder to its full path. - /// - /// - /// The name of the special folder to resolve. Should be one of the values - /// defined by the enumeration. - /// - /// - /// The folder path if able to resolve, null otherwise. - /// - public string ResolveVariable(string name) + catch (Exception) { - try - { - Environment.SpecialFolder folder = - (Environment.SpecialFolder) Enum.Parse(typeof (Environment.SpecialFolder), name, true); - - return Environment.GetFolderPath(folder); - } - catch (Exception) - { - return null; - } + return null; } } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/TypeAliasConfigurer.cs b/src/Spring/Spring.Core/Objects/Factory/Config/TypeAliasConfigurer.cs index 55c3a5ee..12a482b7 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/TypeAliasConfigurer.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/TypeAliasConfigurer.cs @@ -21,80 +21,76 @@ using System.Collections; using Spring.Core.TypeResolution; -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// +/// implementation that allows for convenient registration of custom +/// type aliases. +/// +/// +/// Type aliases can be used instead of fully qualified type names anywhere +/// a type name is expected in a Spring.NET configuration file. +///

+/// Because the +/// class implements the +/// +/// interface, instances of this class that have been exposed in the +/// scope of an +/// will +/// automatically be picked up by the application context and made +/// available to the IoC container whenever resolution of type aliases is required. +///

+///
+/// Mark Pollack +/// +/// +[Serializable] +public class TypeAliasConfigurer : AbstractConfigurer { + private IDictionary types; + /// - /// - /// implementation that allows for convenient registration of custom - /// type aliases. + /// The type aliases to register. /// /// - /// Type aliases can be used instead of fully qualified type names anywhere - /// a type name is expected in a Spring.NET configuration file. ///

- /// Because the - /// class implements the - /// - /// interface, instances of this class that have been exposed in the - /// scope of an - /// will - /// automatically be picked up by the application context and made - /// available to the IoC container whenever resolution of type aliases is required. + /// The has the + /// contains the alias name as the key and type as the value. + /// The key name can either be a string or an object, in which case + /// ToString() will be used to obtain the string name. + /// the value can be the fully qualified name of the type as a string or + /// an actual of the class that + /// being aliased. ///

///
- /// Mark Pollack - /// - /// - [Serializable] - public class TypeAliasConfigurer : AbstractConfigurer + public IDictionary TypeAliases { - private IDictionary types; + set { types = value; } + } - - /// - /// The type aliases to register. - /// - /// - ///

- /// The has the - /// contains the alias name as the key and type as the value. - /// The key name can either be a string or an object, in which case - /// ToString() will be used to obtain the string name. - /// the value can be the fully qualified name of the type as a string or - /// an actual of the class that - /// being aliased. - ///

- ///
- public IDictionary TypeAliases + /// + /// Registers any type aliases. The supplied + /// is not used since type aliases + /// are registered with a global + /// + /// + /// The object factory. + /// + /// + /// In case of errors. + /// + public override void PostProcessObjectFactory( + IConfigurableListableObjectFactory factory) + { + if (types != null) { - set { types = value; } - } - - /// - /// Registers any type aliases. The supplied - /// is not used since type aliases - /// are registered with a global - /// - /// - /// The object factory. - /// - /// - /// In case of errors. - /// - public override void PostProcessObjectFactory( - IConfigurableListableObjectFactory factory) - { - if (types != null) + foreach (DictionaryEntry entry in types) { - foreach (DictionaryEntry entry in types) - { - string alias = entry.Key.ToString(); - Type type = ResolveRequiredType(entry.Value, "value", "custom type alias"); - TypeRegistry.RegisterType(alias, type); - } + string alias = entry.Key.ToString(); + Type type = ResolveRequiredType(entry.Value, "value", "custom type alias"); + TypeRegistry.RegisterType(alias, type); } } - - } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/TypedStringValue.cs b/src/Spring/Spring.Core/Objects/Factory/Config/TypedStringValue.cs index 38626362..b48b608c 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/TypedStringValue.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/TypedStringValue.cs @@ -19,210 +19,211 @@ #endregion using System.Runtime.Serialization; - using Spring.Util; using Spring.Core.TypeResolution; -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Holder for a typed value. +/// +/// +///

+/// Can be added to object definitions to explicitly specify +/// a target type for a value, +/// for example for collection +/// elements. +///

+///

+/// This holder just stores the value and the target +/// . The actual conversion will be performed by +/// the surrounding object factory. +///

+///
+/// Juergen Hoeller +/// Rick Evans (.NET) +/// Bruno Baia (.NET) +[Serializable] +public class TypedStringValue : ISerializable { + private string theValue; + private object targetType; + /// - /// Holder for a typed value. + /// Creates a new instance of the + /// + /// class. + /// + public TypedStringValue() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The value. + public TypedStringValue(string value) + { + Value = value; + } + + /// + /// Creates a new instance of the + /// + /// class. + /// + /// + /// The value that is to be converted. + /// + /// + /// The to convert to. + /// + /// + /// If the supplied is + /// . + /// + public TypedStringValue(string value, Type targetType) + { + Value = value; + TargetType = targetType; + } + + /// + /// Creates a new instance of the + /// + /// class. + /// + /// + /// The value that is to be converted. + /// + /// + /// The unresolved type to convert to. + /// + /// + /// If the supplied is a + /// or an empty string. + /// + public TypedStringValue(string value, string targetTypeName) + { + Value = value; + TargetTypeName = targetTypeName; + } + + protected TypedStringValue(SerializationInfo info, StreamingContext context) + { + var type = info.GetString("TargetTypeName"); + targetType = type != null ? Type.GetType(type) : null; + theValue = info.GetString("Value"); + } + + /// + /// The value that is to be converted. /// /// ///

- /// Can be added to object definitions to explicitly specify - /// a target type for a value, - /// for example for collection - /// elements. - ///

- ///

- /// This holder just stores the value and the target - /// . The actual conversion will be performed by - /// the surrounding object factory. + /// Obviously if the + /// + /// is the , no conversion + /// will actually be performed. ///

///
- /// Juergen Hoeller - /// Rick Evans (.NET) - /// Bruno Baia (.NET) - [Serializable] - public class TypedStringValue : ISerializable + public string Value { - private string theValue; - private object targetType; + get { return theValue; } + set { this.theValue = value; } + } - /// - /// Creates a new instance of the - /// - /// class. - /// - public TypedStringValue() + /// + /// The to convert to. + /// + /// + /// If the setter is supplied with a value. + /// + public Type TargetType + { + get { - } - - /// - /// Initializes a new instance of the class. - /// - /// The value. - public TypedStringValue(string value) - { - Value = value; - } - - /// - /// Creates a new instance of the - /// - /// class. - /// - /// - /// The value that is to be converted. - /// - /// - /// The to convert to. - /// - /// - /// If the supplied is - /// . - /// - public TypedStringValue(string value, Type targetType) - { - Value = value; - TargetType = targetType; - } - - /// - /// Creates a new instance of the - /// - /// class. - /// - /// - /// The value that is to be converted. - /// - /// - /// The unresolved type to convert to. - /// - /// - /// If the supplied is a - /// or an empty string. - /// - public TypedStringValue(string value, string targetTypeName) - { - Value = value; - TargetTypeName = targetTypeName; - } - - protected TypedStringValue(SerializationInfo info, StreamingContext context) - { - var type = info.GetString("TargetTypeName"); - targetType = type != null ? Type.GetType(type) : null; - theValue = info.GetString("Value"); - } - - /// - /// The value that is to be converted. - /// - /// - ///

- /// Obviously if the - /// - /// is the , no conversion - /// will actually be performed. - ///

- ///
- public string Value - { - get { return theValue; } - set { this.theValue = value; } - } - - /// - /// The to convert to. - /// - /// - /// If the setter is supplied with a value. - /// - public Type TargetType - { - get + if (!HasTargetType) { - if (!HasTargetType) - { - throw new ApplicationException( - "Typed String value does not carry a resolved System.Type"); - } - return (Type)targetType; + throw new ApplicationException( + "Typed String value does not carry a resolved System.Type"); } - set - { - AssertUtils.ArgumentNotNull(value, "TargetType"); - targetType = value; - } - } - /// - /// The unresolved type to convert to. - /// - /// - /// If the setter is supplied with a value or an empty string. - /// - public string TargetTypeName - { - get - { - if (targetType is Type) - { - return ((Type) targetType).FullName; - } - else - { - return targetType as string; - } - } - set - { - AssertUtils.ArgumentHasText(value, "TargetTypeName"); - targetType = value; - } + return (Type) targetType; } - - /// - /// Gets a value indicating whether this instance has target type. - /// - /// - /// true if this instance has target type; otherwise, false. - /// - public bool HasTargetType + set { - get { return targetType is Type; } - } - - /// - /// Determine the type to convert to, resolving it from a specified type name if necessary. - /// - /// The resolved type to convert to. - public Type ResolveTargetType() - { - if (this.targetType == null) - { - return null; - } - Type resolvedType = TypeResolutionUtils.ResolveType(this.TargetTypeName); - this.targetType = resolvedType; - return resolvedType; - } - - public void GetObjectData(SerializationInfo info, StreamingContext context) - { - string targetTypeName = null; - if (targetType is string x) - { - targetTypeName = x; - } - else if (targetType is Type t) - { - targetTypeName = t.AssemblyQualifiedNameWithoutVersion(); - } - info.AddValue("TargetTypeName", targetTypeName); - info.AddValue("Value", theValue); + AssertUtils.ArgumentNotNull(value, "TargetType"); + targetType = value; } } -} + + /// + /// The unresolved type to convert to. + /// + /// + /// If the setter is supplied with a value or an empty string. + /// + public string TargetTypeName + { + get + { + if (targetType is Type) + { + return ((Type) targetType).FullName; + } + else + { + return targetType as string; + } + } + set + { + AssertUtils.ArgumentHasText(value, "TargetTypeName"); + targetType = value; + } + } + + /// + /// Gets a value indicating whether this instance has target type. + /// + /// + /// true if this instance has target type; otherwise, false. + /// + public bool HasTargetType + { + get { return targetType is Type; } + } + + /// + /// Determine the type to convert to, resolving it from a specified type name if necessary. + /// + /// The resolved type to convert to. + public Type ResolveTargetType() + { + if (this.targetType == null) + { + return null; + } + + Type resolvedType = TypeResolutionUtils.ResolveType(this.TargetTypeName); + this.targetType = resolvedType; + return resolvedType; + } + + public void GetObjectData(SerializationInfo info, StreamingContext context) + { + string targetTypeName = null; + if (targetType is string x) + { + targetTypeName = x; + } + else if (targetType is Type t) + { + targetTypeName = t.AssemblyQualifiedNameWithoutVersion(); + } + + info.AddValue("TargetTypeName", targetTypeName); + info.AddValue("Value", theValue); + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/VariableAccessor.cs b/src/Spring/Spring.Core/Objects/Factory/Config/VariableAccessor.cs index f021dda5..61140bde 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/VariableAccessor.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/VariableAccessor.cs @@ -19,768 +19,767 @@ #endregion using System.Globalization; - using Spring.Util; -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Provides methods for type-safe accessing s. +/// +/// Erich Eichinger +public class VariableAccessor { + private readonly IVariableSource variableSource; + /// - /// Provides methods for type-safe accessing s. + /// Initialize a new instance of an /// - /// Erich Eichinger - public class VariableAccessor + /// The underlying to read values from. + public VariableAccessor(IVariableSource variableSource) { - private readonly IVariableSource variableSource; + this.variableSource = variableSource; + } - /// - /// Initialize a new instance of an - /// - /// The underlying to read values from. - public VariableAccessor(IVariableSource variableSource) + /// + /// Returns a that contains the value of the specified variable. + /// + /// The name of the variable to be read. + /// The value to be returned if returns null. + /// + /// A that contains the value of the specified variable + /// or , if returns null. + /// + public float GetFloat(string name, float defaultValue) + { + return GetFloat(name, defaultValue, true); + } + + /// + /// Returns a that contains the value of the specified variable. + /// + /// The name of the variable to be read. + /// The value to be returned if returns null. + /// + /// If false, suppresses exceptions if the result + /// of cannot be parsed + /// and returns instead. + /// + /// A that contains the value of the specified variable + /// or , if cannot be parsed. + /// + public float GetFloat(string name, float defaultValue, bool throwOnInvalidValue) + { + try { - this.variableSource = variableSource; + string text = GetString(name, defaultValue.ToString()); + return float.Parse(text); } - - /// - /// Returns a that contains the value of the specified variable. - /// - /// The name of the variable to be read. - /// The value to be returned if returns null. - /// - /// A that contains the value of the specified variable - /// or , if returns null. - /// - public float GetFloat(string name, float defaultValue) + catch { - return GetFloat(name, defaultValue, true); - } - - /// - /// Returns a that contains the value of the specified variable. - /// - /// The name of the variable to be read. - /// The value to be returned if returns null. - /// - /// If false, suppresses exceptions if the result - /// of cannot be parsed - /// and returns instead. - /// - /// A that contains the value of the specified variable - /// or , if cannot be parsed. - /// - public float GetFloat(string name, float defaultValue, bool throwOnInvalidValue) - { - try + if (throwOnInvalidValue) { - string text = GetString(name, defaultValue.ToString()); - return float.Parse(text); + throw; } - catch - { - if (throwOnInvalidValue) - { - throw; - } - else - { - return defaultValue; - } - } - } - - /// - /// Returns a that contains the value of the specified variable. - /// - /// The name of the variable to be read. - /// The value to be returned if returns null. - /// - /// A that contains the value of the specified variable - /// or , if returns null. - /// - public double GetDouble(string name, double defaultValue) - { - return GetDouble(name, defaultValue, true); - } - - /// - /// Returns a that contains the value of the specified variable. - /// - /// The name of the variable to be read. - /// The value to be returned if returns null. - /// - /// If false, suppresses exceptions if the result - /// of cannot be parsed - /// and returns instead. - /// - /// A that contains the value of the specified variable - /// or , if cannot be parsed. - /// - public double GetDouble(string name, double defaultValue, bool throwOnInvalidValue) - { - try - { - string text = GetString(name, defaultValue.ToString()); - return double.Parse(text); - } - catch - { - if (throwOnInvalidValue) - { - throw; - } - else - { - return defaultValue; - } - } - } - - /// - /// Returns a that contains the value of the specified variable. - /// - /// The name of the variable to be read. - /// The value to be returned if returns null. - /// - /// A that contains the value of the specified variable - /// or , if returns null. - /// - public decimal GetDecimal(string name, decimal defaultValue) - { - return GetDecimal(name, defaultValue, true); - } - - /// - /// Returns a that contains the value of the specified variable. - /// - /// The name of the variable to be read. - /// The value to be returned if returns null. - /// - /// If false, suppresses exceptions if the result - /// of cannot be parsed - /// and returns instead. - /// - /// A that contains the value of the specified variable - /// or , if cannot be parsed. - /// - public decimal GetDecimal(string name, decimal defaultValue, bool throwOnInvalidValue) - { - try - { - string text = GetString(name, defaultValue.ToString()); - return decimal.Parse(text); - } - catch - { - if (throwOnInvalidValue) - { - throw; - } - else - { - return defaultValue; - } - } - } - - /// - /// Returns a that contains the value of the specified variable. - /// - /// The name of the variable to be read. - /// The value to be returned if returns null. - /// - /// A that contains the value of the specified variable - /// or , if returns null. - /// - public long GetInt64(string name, long defaultValue) - { - return GetInt64(name, defaultValue, true); - } - - /// - /// Returns a that contains the value of the specified variable. - /// - /// The name of the variable to be read. - /// The value to be returned if returns null. - /// - /// If false, suppresses exceptions if the result - /// of cannot be parsed - /// and returns instead. - /// - /// A that contains the value of the specified variable - /// or , if cannot be parsed. - /// - public long GetInt64(string name, long defaultValue, bool throwOnInvalidValue) - { - try - { - string text = GetString(name, defaultValue.ToString()); - return Int64.Parse(text); - } - catch - { - if (throwOnInvalidValue) - { - throw; - } - else - { - return defaultValue; - } - } - } - - /// - /// Returns a that contains the value of the specified variable. - /// - /// The name of the variable to be read. - /// The value to be returned if returns null. - /// - /// A that contains the value of the specified variable - /// or , if returns null. - /// - public ulong GetUInt64(string name, ulong defaultValue) - { - return GetUInt64(name, defaultValue, true); - } - - /// - /// Returns a that contains the value of the specified variable. - /// - /// The name of the variable to be read. - /// The value to be returned if returns null. - /// - /// If false, suppresses exceptions if the result - /// of cannot be parsed - /// and returns instead. - /// - /// A that contains the value of the specified variable - /// or , if cannot be parsed. - /// - public ulong GetUInt64(string name, ulong defaultValue, bool throwOnInvalidValue) - { - try - { - string text = GetString(name, defaultValue.ToString()); - return UInt64.Parse(text); - } - catch - { - if (throwOnInvalidValue) - { - throw; - } - else - { - return defaultValue; - } - } - } - - /// - /// Returns a that contains the value of the specified variable. - /// - /// The name of the variable to be read. - /// The value to be returned if returns null. - /// - /// A that contains the value of the specified variable - /// or , if returns null. - /// - public int GetInt32(string name, int defaultValue) - { - return GetInt32(name, defaultValue, true); - } - - /// - /// Returns a that contains the value of the specified variable. - /// - /// The name of the variable to be read. - /// The value to be returned if returns null. - /// - /// If false, suppresses exceptions if the result - /// of cannot be parsed - /// and returns instead. - /// - /// A that contains the value of the specified variable - /// or , if cannot be parsed. - /// - public int GetInt32(string name, int defaultValue, bool throwOnInvalidValue) - { - try - { - string text = GetString(name, defaultValue.ToString()); - return Int32.Parse(text); - } - catch - { - if (throwOnInvalidValue) - { - throw; - } - else - { - return defaultValue; - } - } - } - - /// - /// Returns a that contains the value of the specified variable. - /// - /// The name of the variable to be read. - /// The value to be returned if returns null. - /// - /// A that contains the value of the specified variable - /// or , if returns null. - /// - public uint GetUInt32(string name, uint defaultValue) - { - return GetUInt32(name, defaultValue, true); - } - - /// - /// Returns a that contains the value of the specified variable. - /// - /// The name of the variable to be read. - /// The value to be returned if returns null. - /// - /// If false, suppresses exceptions if the result - /// of cannot be parsed - /// and returns instead. - /// - /// A that contains the value of the specified variable - /// or , if cannot be parsed. - /// - public uint GetUInt32(string name, uint defaultValue, bool throwOnInvalidValue) - { - try - { - string text = GetString(name, defaultValue.ToString()); - return UInt32.Parse(text); - } - catch - { - if (throwOnInvalidValue) - { - throw; - } - else - { - return defaultValue; - } - } - } - - /// - /// Returns a that contains the value of the specified variable. - /// - /// The name of the variable to be read. - /// The value to be returned if returns null. - /// - /// A that contains the value of the specified variable - /// or , if returns null. - /// - public short GetInt16(string name, short defaultValue) - { - return GetInt16(name, defaultValue, true); - } - - /// - /// Returns a that contains the value of the specified variable. - /// - /// The name of the variable to be read. - /// The value to be returned if returns null. - /// - /// If false, suppresses exceptions if the result - /// of cannot be parsed - /// and returns instead. - /// - /// A that contains the value of the specified variable - /// or , if cannot be parsed. - /// - public short GetInt16(string name, short defaultValue, bool throwOnInvalidValue) - { - try - { - string text = GetString(name, defaultValue.ToString()); - return Int16.Parse(text); - } - catch - { - if (throwOnInvalidValue) - { - throw; - } - else - { - return defaultValue; - } - } - } - - /// - /// Returns a that contains the value of the specified variable. - /// - /// The name of the variable to be read. - /// The value to be returned if returns null. - /// - /// A that contains the value of the specified variable - /// or , if returns null. - /// - public ushort GetUInt16(string name, ushort defaultValue) - { - return GetUInt16(name, defaultValue, true); - } - - /// - /// Returns a that contains the value of the specified variable. - /// - /// The name of the variable to be read. - /// The value to be returned if returns null. - /// - /// If false, suppresses exceptions if the result - /// of cannot be parsed - /// and returns instead. - /// - /// A that contains the value of the specified variable - /// or , if cannot be parsed. - /// - public ushort GetUInt16(string name, ushort defaultValue, bool throwOnInvalidValue) - { - try - { - string text = GetString(name, defaultValue.ToString()); - return UInt16.Parse(text); - } - catch - { - if (throwOnInvalidValue) - { - throw; - } - else - { - return defaultValue; - } - } - } - - /// - /// Returns a that contains the value of the specified variable. - /// - /// The name of the variable to be read. - /// The value to be returned if returns null. - /// - /// A that contains the value of the specified variable - /// or , if returns null. - /// - public byte GetByte(string name, byte defaultValue) - { - return GetByte(name, defaultValue, true); - } - - /// - /// Returns a that contains the value of the specified variable. - /// - /// The name of the variable to be read. - /// The value to be returned if returns null. - /// - /// If false, suppresses exceptions if the result - /// of cannot be parsed - /// and returns instead. - /// - /// A that contains the value of the specified variable - /// or , if cannot be parsed. - /// - public byte GetByte(string name, byte defaultValue, bool throwOnInvalidValue) - { - try - { - string text = GetString(name, defaultValue.ToString()); - return byte.Parse(text); - } - catch - { - if (throwOnInvalidValue) - { - throw; - } - else - { - return defaultValue; - } - } - } - - /// - /// Returns a that contains the value of the specified variable. - /// - /// The name of the variable to be read. - /// The value to be returned if returns null. - /// - /// A that contains the value of the specified variable - /// or , if returns null. - /// - public Guid GetGuid(string name, Guid defaultValue) - { - return GetGuid(name, defaultValue, true); - } - - /// - /// Returns a that contains the value of the specified variable. - /// - /// The name of the variable to be read. - /// The value to be returned if returns null. - /// - /// If false, suppresses exceptions if the result - /// of cannot be parsed - /// and returns instead. - /// - /// A that contains the value of the specified variable - /// or , if cannot be parsed. - /// - public Guid GetGuid(string name, Guid defaultValue, bool throwOnInvalidValue) - { - try - { - string text = GetString(name, defaultValue.ToString()); - return new Guid(text); - } - catch - { - if (throwOnInvalidValue) - { - throw; - } - else - { - return defaultValue; - } - } - } - - /// - /// Returns a that contains the value of the specified variable. - /// - /// The name of the variable to be read. - /// The expected format of the variable's value - /// The value to be returned if returns null. - /// - /// A that contains the value of the specified variable - /// or , if returns null. - /// - public DateTime GetDateTime(string name, string format, DateTime defaultValue) - { - return GetDateTime(name, format, defaultValue, true); - } - - /// - /// Returns a that contains the value of the specified variable. - /// - /// The name of the variable to be read. - /// The expected format of the variable's value - /// The value to be returned if returns null. - /// - /// If false, suppresses exceptions if the result - /// of cannot be parsed - /// and returns instead. - /// - /// A that contains the value of the specified variable - /// or , if cannot be parsed. - /// - public DateTime GetDateTime(string name, string format, DateTime defaultValue, bool throwOnInvalidValue) - { - try - { - string text = GetString(name, defaultValue.ToString()); - if (format == null) - { - return DateTime.Parse(text); - } - else - { - return DateTime.ParseExact(text, format, CultureInfo.InvariantCulture); - } - } - catch - { - if (throwOnInvalidValue) - { - throw; - } - else - { - return defaultValue; - } - } - } - - /// - /// Returns a that contains the value of the specified variable. - /// - /// The name of the variable to be read. - /// The value to be returned if returns null. - /// - /// A that contains the value of the specified variable - /// or , if returns null. - /// - public char GetChar(string name, char defaultValue) - { - return GetChar(name, defaultValue, true); - } - - /// - /// Returns a that contains the value of the specified variable. - /// - /// The name of the variable to be read. - /// The value to be returned if returns null. - /// - /// If false, suppresses exceptions if the result - /// of cannot be parsed - /// and returns instead. - /// - /// A that contains the value of the specified variable - /// or , if cannot be parsed. - /// - public char GetChar(string name, char defaultValue, bool throwOnInvalidValue) - { - try - { - string text = GetString(name, defaultValue.ToString()); - if (text.Length != 1) - { - throw new ArgumentException("string '{0}' can't be converted to char", text); - } - return text[0]; - } - catch - { - if (throwOnInvalidValue) - { - throw; - } - else - { - return defaultValue; - } - } - } - - /// - /// Returns a that contains the value of the specified variable. - /// - /// The name of the variable to be read. - /// The value to be returned if returns null. - /// - /// A that contains the value of the specified variable - /// or , if returns null. - /// - public bool GetBoolean(string name, bool defaultValue) - { - return GetBoolean(name, defaultValue, true); - } - - /// - /// Returns a that contains the value of the specified variable. - /// - /// The name of the variable to be read. - /// The value to be returned if returns null. - /// - /// If false, suppresses exceptions if the result - /// of cannot be parsed - /// and returns instead. - /// - /// A that contains the value of the specified variable - /// or , if cannot be parsed. - /// - public bool GetBoolean(string name, bool defaultValue, bool throwOnInvalidValue) - { - try - { - string text = GetString(name, defaultValue.ToString()); - return bool.Parse(text); - } - catch - { - if (throwOnInvalidValue) - { - throw; - } - else - { - return defaultValue; - } - } - } - - /// - /// Returns an of 's type that contains the value of the specified variable. - /// - /// The name of the variable to be read. - /// The value to be returned if returns null. - /// - /// An of 's type that contains the value of the specified variable - /// or , if returns null. - /// - public Enum GetEnum(string name, Enum defaultValue) - { - return GetEnum(name, defaultValue, true); - } - - /// - /// Returns an of 's type that contains the value of the specified variable. - /// - /// The name of the variable to be read. - /// The value to be returned if returns null. - /// - /// If false, suppresses exceptions if the result - /// of cannot be parsed - /// and returns instead. - /// - /// An of 's type that contains the value of the specified variable - /// or , if cannot be parsed. - /// - public Enum GetEnum(string name, Enum defaultValue, bool throwOnInvalidValue) - { - try - { - return (Enum)Enum.Parse(defaultValue.GetType(), GetString(name, defaultValue.ToString()), true); - } - catch - { - if (throwOnInvalidValue) - { - throw; - } - else - { - return defaultValue; - } - } - } - - /// - /// Returns a that contains the value of the specified variable. - /// - /// The name of the variable to be read. - /// The value to be returned if returns or . - /// - /// A that contains the value of the specified variable - /// or , if returns null. - /// - public string GetString(string name, string defaultValue) - { - string value = null; - if (variableSource != null && variableSource.CanResolveVariable(name)) - { - value = variableSource.ResolveVariable(name); - } - - if (!StringUtils.HasLength(value)) + else { return defaultValue; } - - return value; } } + + /// + /// Returns a that contains the value of the specified variable. + /// + /// The name of the variable to be read. + /// The value to be returned if returns null. + /// + /// A that contains the value of the specified variable + /// or , if returns null. + /// + public double GetDouble(string name, double defaultValue) + { + return GetDouble(name, defaultValue, true); + } + + /// + /// Returns a that contains the value of the specified variable. + /// + /// The name of the variable to be read. + /// The value to be returned if returns null. + /// + /// If false, suppresses exceptions if the result + /// of cannot be parsed + /// and returns instead. + /// + /// A that contains the value of the specified variable + /// or , if cannot be parsed. + /// + public double GetDouble(string name, double defaultValue, bool throwOnInvalidValue) + { + try + { + string text = GetString(name, defaultValue.ToString()); + return double.Parse(text); + } + catch + { + if (throwOnInvalidValue) + { + throw; + } + else + { + return defaultValue; + } + } + } + + /// + /// Returns a that contains the value of the specified variable. + /// + /// The name of the variable to be read. + /// The value to be returned if returns null. + /// + /// A that contains the value of the specified variable + /// or , if returns null. + /// + public decimal GetDecimal(string name, decimal defaultValue) + { + return GetDecimal(name, defaultValue, true); + } + + /// + /// Returns a that contains the value of the specified variable. + /// + /// The name of the variable to be read. + /// The value to be returned if returns null. + /// + /// If false, suppresses exceptions if the result + /// of cannot be parsed + /// and returns instead. + /// + /// A that contains the value of the specified variable + /// or , if cannot be parsed. + /// + public decimal GetDecimal(string name, decimal defaultValue, bool throwOnInvalidValue) + { + try + { + string text = GetString(name, defaultValue.ToString()); + return decimal.Parse(text); + } + catch + { + if (throwOnInvalidValue) + { + throw; + } + else + { + return defaultValue; + } + } + } + + /// + /// Returns a that contains the value of the specified variable. + /// + /// The name of the variable to be read. + /// The value to be returned if returns null. + /// + /// A that contains the value of the specified variable + /// or , if returns null. + /// + public long GetInt64(string name, long defaultValue) + { + return GetInt64(name, defaultValue, true); + } + + /// + /// Returns a that contains the value of the specified variable. + /// + /// The name of the variable to be read. + /// The value to be returned if returns null. + /// + /// If false, suppresses exceptions if the result + /// of cannot be parsed + /// and returns instead. + /// + /// A that contains the value of the specified variable + /// or , if cannot be parsed. + /// + public long GetInt64(string name, long defaultValue, bool throwOnInvalidValue) + { + try + { + string text = GetString(name, defaultValue.ToString()); + return Int64.Parse(text); + } + catch + { + if (throwOnInvalidValue) + { + throw; + } + else + { + return defaultValue; + } + } + } + + /// + /// Returns a that contains the value of the specified variable. + /// + /// The name of the variable to be read. + /// The value to be returned if returns null. + /// + /// A that contains the value of the specified variable + /// or , if returns null. + /// + public ulong GetUInt64(string name, ulong defaultValue) + { + return GetUInt64(name, defaultValue, true); + } + + /// + /// Returns a that contains the value of the specified variable. + /// + /// The name of the variable to be read. + /// The value to be returned if returns null. + /// + /// If false, suppresses exceptions if the result + /// of cannot be parsed + /// and returns instead. + /// + /// A that contains the value of the specified variable + /// or , if cannot be parsed. + /// + public ulong GetUInt64(string name, ulong defaultValue, bool throwOnInvalidValue) + { + try + { + string text = GetString(name, defaultValue.ToString()); + return UInt64.Parse(text); + } + catch + { + if (throwOnInvalidValue) + { + throw; + } + else + { + return defaultValue; + } + } + } + + /// + /// Returns a that contains the value of the specified variable. + /// + /// The name of the variable to be read. + /// The value to be returned if returns null. + /// + /// A that contains the value of the specified variable + /// or , if returns null. + /// + public int GetInt32(string name, int defaultValue) + { + return GetInt32(name, defaultValue, true); + } + + /// + /// Returns a that contains the value of the specified variable. + /// + /// The name of the variable to be read. + /// The value to be returned if returns null. + /// + /// If false, suppresses exceptions if the result + /// of cannot be parsed + /// and returns instead. + /// + /// A that contains the value of the specified variable + /// or , if cannot be parsed. + /// + public int GetInt32(string name, int defaultValue, bool throwOnInvalidValue) + { + try + { + string text = GetString(name, defaultValue.ToString()); + return Int32.Parse(text); + } + catch + { + if (throwOnInvalidValue) + { + throw; + } + else + { + return defaultValue; + } + } + } + + /// + /// Returns a that contains the value of the specified variable. + /// + /// The name of the variable to be read. + /// The value to be returned if returns null. + /// + /// A that contains the value of the specified variable + /// or , if returns null. + /// + public uint GetUInt32(string name, uint defaultValue) + { + return GetUInt32(name, defaultValue, true); + } + + /// + /// Returns a that contains the value of the specified variable. + /// + /// The name of the variable to be read. + /// The value to be returned if returns null. + /// + /// If false, suppresses exceptions if the result + /// of cannot be parsed + /// and returns instead. + /// + /// A that contains the value of the specified variable + /// or , if cannot be parsed. + /// + public uint GetUInt32(string name, uint defaultValue, bool throwOnInvalidValue) + { + try + { + string text = GetString(name, defaultValue.ToString()); + return UInt32.Parse(text); + } + catch + { + if (throwOnInvalidValue) + { + throw; + } + else + { + return defaultValue; + } + } + } + + /// + /// Returns a that contains the value of the specified variable. + /// + /// The name of the variable to be read. + /// The value to be returned if returns null. + /// + /// A that contains the value of the specified variable + /// or , if returns null. + /// + public short GetInt16(string name, short defaultValue) + { + return GetInt16(name, defaultValue, true); + } + + /// + /// Returns a that contains the value of the specified variable. + /// + /// The name of the variable to be read. + /// The value to be returned if returns null. + /// + /// If false, suppresses exceptions if the result + /// of cannot be parsed + /// and returns instead. + /// + /// A that contains the value of the specified variable + /// or , if cannot be parsed. + /// + public short GetInt16(string name, short defaultValue, bool throwOnInvalidValue) + { + try + { + string text = GetString(name, defaultValue.ToString()); + return Int16.Parse(text); + } + catch + { + if (throwOnInvalidValue) + { + throw; + } + else + { + return defaultValue; + } + } + } + + /// + /// Returns a that contains the value of the specified variable. + /// + /// The name of the variable to be read. + /// The value to be returned if returns null. + /// + /// A that contains the value of the specified variable + /// or , if returns null. + /// + public ushort GetUInt16(string name, ushort defaultValue) + { + return GetUInt16(name, defaultValue, true); + } + + /// + /// Returns a that contains the value of the specified variable. + /// + /// The name of the variable to be read. + /// The value to be returned if returns null. + /// + /// If false, suppresses exceptions if the result + /// of cannot be parsed + /// and returns instead. + /// + /// A that contains the value of the specified variable + /// or , if cannot be parsed. + /// + public ushort GetUInt16(string name, ushort defaultValue, bool throwOnInvalidValue) + { + try + { + string text = GetString(name, defaultValue.ToString()); + return UInt16.Parse(text); + } + catch + { + if (throwOnInvalidValue) + { + throw; + } + else + { + return defaultValue; + } + } + } + + /// + /// Returns a that contains the value of the specified variable. + /// + /// The name of the variable to be read. + /// The value to be returned if returns null. + /// + /// A that contains the value of the specified variable + /// or , if returns null. + /// + public byte GetByte(string name, byte defaultValue) + { + return GetByte(name, defaultValue, true); + } + + /// + /// Returns a that contains the value of the specified variable. + /// + /// The name of the variable to be read. + /// The value to be returned if returns null. + /// + /// If false, suppresses exceptions if the result + /// of cannot be parsed + /// and returns instead. + /// + /// A that contains the value of the specified variable + /// or , if cannot be parsed. + /// + public byte GetByte(string name, byte defaultValue, bool throwOnInvalidValue) + { + try + { + string text = GetString(name, defaultValue.ToString()); + return byte.Parse(text); + } + catch + { + if (throwOnInvalidValue) + { + throw; + } + else + { + return defaultValue; + } + } + } + + /// + /// Returns a that contains the value of the specified variable. + /// + /// The name of the variable to be read. + /// The value to be returned if returns null. + /// + /// A that contains the value of the specified variable + /// or , if returns null. + /// + public Guid GetGuid(string name, Guid defaultValue) + { + return GetGuid(name, defaultValue, true); + } + + /// + /// Returns a that contains the value of the specified variable. + /// + /// The name of the variable to be read. + /// The value to be returned if returns null. + /// + /// If false, suppresses exceptions if the result + /// of cannot be parsed + /// and returns instead. + /// + /// A that contains the value of the specified variable + /// or , if cannot be parsed. + /// + public Guid GetGuid(string name, Guid defaultValue, bool throwOnInvalidValue) + { + try + { + string text = GetString(name, defaultValue.ToString()); + return new Guid(text); + } + catch + { + if (throwOnInvalidValue) + { + throw; + } + else + { + return defaultValue; + } + } + } + + /// + /// Returns a that contains the value of the specified variable. + /// + /// The name of the variable to be read. + /// The expected format of the variable's value + /// The value to be returned if returns null. + /// + /// A that contains the value of the specified variable + /// or , if returns null. + /// + public DateTime GetDateTime(string name, string format, DateTime defaultValue) + { + return GetDateTime(name, format, defaultValue, true); + } + + /// + /// Returns a that contains the value of the specified variable. + /// + /// The name of the variable to be read. + /// The expected format of the variable's value + /// The value to be returned if returns null. + /// + /// If false, suppresses exceptions if the result + /// of cannot be parsed + /// and returns instead. + /// + /// A that contains the value of the specified variable + /// or , if cannot be parsed. + /// + public DateTime GetDateTime(string name, string format, DateTime defaultValue, bool throwOnInvalidValue) + { + try + { + string text = GetString(name, defaultValue.ToString()); + if (format == null) + { + return DateTime.Parse(text); + } + else + { + return DateTime.ParseExact(text, format, CultureInfo.InvariantCulture); + } + } + catch + { + if (throwOnInvalidValue) + { + throw; + } + else + { + return defaultValue; + } + } + } + + /// + /// Returns a that contains the value of the specified variable. + /// + /// The name of the variable to be read. + /// The value to be returned if returns null. + /// + /// A that contains the value of the specified variable + /// or , if returns null. + /// + public char GetChar(string name, char defaultValue) + { + return GetChar(name, defaultValue, true); + } + + /// + /// Returns a that contains the value of the specified variable. + /// + /// The name of the variable to be read. + /// The value to be returned if returns null. + /// + /// If false, suppresses exceptions if the result + /// of cannot be parsed + /// and returns instead. + /// + /// A that contains the value of the specified variable + /// or , if cannot be parsed. + /// + public char GetChar(string name, char defaultValue, bool throwOnInvalidValue) + { + try + { + string text = GetString(name, defaultValue.ToString()); + if (text.Length != 1) + { + throw new ArgumentException("string '{0}' can't be converted to char", text); + } + + return text[0]; + } + catch + { + if (throwOnInvalidValue) + { + throw; + } + else + { + return defaultValue; + } + } + } + + /// + /// Returns a that contains the value of the specified variable. + /// + /// The name of the variable to be read. + /// The value to be returned if returns null. + /// + /// A that contains the value of the specified variable + /// or , if returns null. + /// + public bool GetBoolean(string name, bool defaultValue) + { + return GetBoolean(name, defaultValue, true); + } + + /// + /// Returns a that contains the value of the specified variable. + /// + /// The name of the variable to be read. + /// The value to be returned if returns null. + /// + /// If false, suppresses exceptions if the result + /// of cannot be parsed + /// and returns instead. + /// + /// A that contains the value of the specified variable + /// or , if cannot be parsed. + /// + public bool GetBoolean(string name, bool defaultValue, bool throwOnInvalidValue) + { + try + { + string text = GetString(name, defaultValue.ToString()); + return bool.Parse(text); + } + catch + { + if (throwOnInvalidValue) + { + throw; + } + else + { + return defaultValue; + } + } + } + + /// + /// Returns an of 's type that contains the value of the specified variable. + /// + /// The name of the variable to be read. + /// The value to be returned if returns null. + /// + /// An of 's type that contains the value of the specified variable + /// or , if returns null. + /// + public Enum GetEnum(string name, Enum defaultValue) + { + return GetEnum(name, defaultValue, true); + } + + /// + /// Returns an of 's type that contains the value of the specified variable. + /// + /// The name of the variable to be read. + /// The value to be returned if returns null. + /// + /// If false, suppresses exceptions if the result + /// of cannot be parsed + /// and returns instead. + /// + /// An of 's type that contains the value of the specified variable + /// or , if cannot be parsed. + /// + public Enum GetEnum(string name, Enum defaultValue, bool throwOnInvalidValue) + { + try + { + return (Enum) Enum.Parse(defaultValue.GetType(), GetString(name, defaultValue.ToString()), true); + } + catch + { + if (throwOnInvalidValue) + { + throw; + } + else + { + return defaultValue; + } + } + } + + /// + /// Returns a that contains the value of the specified variable. + /// + /// The name of the variable to be read. + /// The value to be returned if returns or . + /// + /// A that contains the value of the specified variable + /// or , if returns null. + /// + public string GetString(string name, string defaultValue) + { + string value = null; + if (variableSource != null && variableSource.CanResolveVariable(name)) + { + value = variableSource.ResolveVariable(name); + } + + if (!StringUtils.HasLength(value)) + { + return defaultValue; + } + + return value; + } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/VariablePlaceholderConfigurer.cs b/src/Spring/Spring.Core/Objects/Factory/Config/VariablePlaceholderConfigurer.cs index f55d0e25..5ed40977 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/VariablePlaceholderConfigurer.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/VariablePlaceholderConfigurer.cs @@ -21,351 +21,357 @@ using Spring.Collections; using Spring.Core; using Spring.Util; -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Resolves placeholder values in one or more object definitions +/// +/// +/// The placeholder syntax follows the NAnt style: ${...}. +/// Placeholders values are resolved against a list of +/// s. In case of multiple definitions +/// for the same property placeholder name, the first one in the +/// list is used. +/// Variable substitution is performed on simple property values, +/// lists, dictionaries, sets, constructor +/// values, object type name, and object names in +/// runtime object references ( +/// ). +/// Furthermore, placeholder values can also cross-reference other +/// placeholders, in the manner of the following example where the +/// rootPath property is cross-referenced by the subPath +/// property. +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// If a configurer cannot resolve a placeholder, and the value of the +/// +/// property is currently set to , an +/// +/// will be thrown. +/// +/// Mark Pollack +public class VariablePlaceholderConfigurer : IObjectFactoryPostProcessor, IPriorityOrdered { /// - /// Resolves placeholder values in one or more object definitions + /// The default placeholder prefix. /// - /// - /// The placeholder syntax follows the NAnt style: ${...}. - /// Placeholders values are resolved against a list of - /// s. In case of multiple definitions - /// for the same property placeholder name, the first one in the - /// list is used. - /// Variable substitution is performed on simple property values, - /// lists, dictionaries, sets, constructor - /// values, object type name, and object names in - /// runtime object references ( - /// ). - /// Furthermore, placeholder values can also cross-reference other - /// placeholders, in the manner of the following example where the - /// rootPath property is cross-referenced by the subPath - /// property. - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// If a configurer cannot resolve a placeholder, and the value of the - /// - /// property is currently set to , an - /// - /// will be thrown. - /// - /// Mark Pollack - public class VariablePlaceholderConfigurer : IObjectFactoryPostProcessor, IPriorityOrdered + public static readonly string DefaultPlaceholderPrefix = "${"; + + /// + /// The default placeholder suffix. + /// + public static readonly string DefaultPlaceholderSuffix = "}"; + + private int order = Int32.MaxValue; // default: same as non-Ordered + + private bool includeAncestors; + private bool ignoreUnresolvablePlaceholders; + private string placeholderPrefix = DefaultPlaceholderPrefix; + private string placeholderSuffix = DefaultPlaceholderSuffix; + + private IList variableSourceList = new ArrayList(); + + /// + /// Create a new instance without any variable sources + /// + public VariablePlaceholderConfigurer() { - /// - /// The default placeholder prefix. - /// - public static readonly string DefaultPlaceholderPrefix = "${"; + } - /// - /// The default placeholder suffix. - /// - public static readonly string DefaultPlaceholderSuffix = "}"; + /// + /// Create a new instance and initialize with the given variable source + /// + /// + public VariablePlaceholderConfigurer(IVariableSource variableSource) + { + this.VariableSource = variableSource; + } - private int order = Int32.MaxValue; // default: same as non-Ordered + /// + /// Create a new instance and initialize with the given list of variable sources + /// + public VariablePlaceholderConfigurer(IList variableSources) + { + this.VariableSources = variableSources; + } - private bool includeAncestors; - private bool ignoreUnresolvablePlaceholders; - private string placeholderPrefix = DefaultPlaceholderPrefix; - private string placeholderSuffix = DefaultPlaceholderSuffix; + /// + /// Sets the list of s that will be used to resolve placeholder names. + /// + /// A list of s. + public IList VariableSources + { + set { variableSourceList = value; } + } - private IList variableSourceList = new ArrayList(); - - /// - /// Create a new instance without any variable sources - /// - public VariablePlaceholderConfigurer() - {} - - /// - /// Create a new instance and initialize with the given variable source - /// - /// - public VariablePlaceholderConfigurer(IVariableSource variableSource) + /// + /// Sets that will be used to resolve placeholder names. + /// + /// A instance. + public IVariableSource VariableSource + { + set { - this.VariableSource = variableSource; + variableSourceList = new ArrayList(); + variableSourceList.Add(value); + } + } + + /// + /// The placeholder prefix (the default is ${). + /// + /// + public string PlaceholderPrefix + { + set { placeholderPrefix = value; } + } + + /// + /// The placeholder suffix (the default is }) + /// + /// + public string PlaceholderSuffix + { + set { placeholderSuffix = value; } + } + + /// + /// Indicates whether unresolved placeholders should be ignored. + /// + public bool IgnoreUnresolvablePlaceholders + { + set { ignoreUnresolvablePlaceholders = value; } + } + + public bool IncludeAncestors + { + set { includeAncestors = value; } + } + + /// + /// Modify the application context's internal object factory after its + /// standard initialization. + /// + /// The object factory used by the application context. + /// + ///

+ /// All object definitions will have been loaded, but no objects will have + /// been instantiated yet. This allows for overriding or adding properties + /// even to eager-initializing objects. + ///

+ ///
+ /// + /// In case of errors. + /// + public void PostProcessObjectFactory(IConfigurableListableObjectFactory factory) + { + if (CollectionUtils.IsEmpty(variableSourceList)) + { + throw new ArgumentException("No VariableSources configured"); } - /// - /// Create a new instance and initialize with the given list of variable sources - /// - public VariablePlaceholderConfigurer(IList variableSources) + ICollection filtered = CollectionUtils.FindValuesOfType(this.variableSourceList, typeof(IVariableSource)); + if (filtered.Count != this.variableSourceList.Count) { - this.VariableSources = variableSources; + throw new ArgumentException("'VariableSources' must contain IVariableSource elements only", "VariableSources"); } - /// - /// Sets the list of s that will be used to resolve placeholder names. - /// - /// A list of s. - public IList VariableSources + try { - set { variableSourceList = value; } + ProcessProperties(factory); } - - /// - /// Sets that will be used to resolve placeholder names. - /// - /// A instance. - public IVariableSource VariableSource + catch (Exception ex) { - set + if (typeof(ObjectsException).IsInstanceOfType(ex)) { - variableSourceList = new ArrayList(); - variableSourceList.Add( value ); + throw; } - } - - /// - /// The placeholder prefix (the default is ${). - /// - /// - public string PlaceholderPrefix - { - set { placeholderPrefix = value; } - } - - /// - /// The placeholder suffix (the default is }) - /// - /// - public string PlaceholderSuffix - { - set { placeholderSuffix = value; } - } - - /// - /// Indicates whether unresolved placeholders should be ignored. - /// - public bool IgnoreUnresolvablePlaceholders - { - set { ignoreUnresolvablePlaceholders = value; } - } - - public bool IncludeAncestors - { - set { includeAncestors = value; } - } - - /// - /// Modify the application context's internal object factory after its - /// standard initialization. - /// - /// The object factory used by the application context. - /// - ///

- /// All object definitions will have been loaded, but no objects will have - /// been instantiated yet. This allows for overriding or adding properties - /// even to eager-initializing objects. - ///

- ///
- /// - /// In case of errors. - /// - public void PostProcessObjectFactory( IConfigurableListableObjectFactory factory ) - { - if (CollectionUtils.IsEmpty(variableSourceList)) + else { - throw new ArgumentException("No VariableSources configured"); - } - - ICollection filtered = CollectionUtils.FindValuesOfType(this.variableSourceList, typeof (IVariableSource)); - if (filtered.Count != this.variableSourceList.Count) - { - throw new ArgumentException("'VariableSources' must contain IVariableSource elements only", "VariableSources"); - } - - try - { - ProcessProperties( factory ); - } - catch (Exception ex) - { - if (typeof( ObjectsException ).IsInstanceOfType( ex )) - { - throw; - } - else - { - throw new ObjectsException( - "Errored while postprocessing an object factory.", ex ); - } - } - } - - /// - /// Return the order value of this object, where a higher value means greater in - /// terms of sorting. - /// - /// The order value. - /// - public int Order - { - get { return order; } - set { order = value; } - } - - /// - /// Apply the property replacement using the specified s for all - /// object in the supplied - /// . - /// - /// - /// The - /// used by the application context. - /// - /// - /// If an error occured. - /// - protected virtual void ProcessProperties( IConfigurableListableObjectFactory factory ) - { - CompositeVariableSource compositeVariableSource = new CompositeVariableSource(variableSourceList); - TextProcessor tp = new TextProcessor(this, compositeVariableSource); - ObjectDefinitionVisitor visitor = new ObjectDefinitionVisitor(new ObjectDefinitionVisitor.ResolveHandler(tp.ParseAndResolveVariables)); - - var objectDefinitionNames = factory.GetObjectDefinitionNames(includeAncestors); - for (int i = 0; i < objectDefinitionNames.Count; ++i) - { - string name = objectDefinitionNames[i]; - IObjectDefinition definition = factory.GetObjectDefinition( name, includeAncestors ); - - if (definition == null) - continue; - - try - { - visitor.VisitObjectDefinition( definition ); - } - catch (ObjectDefinitionStoreException ex) - { - throw new ObjectDefinitionStoreException( - definition.ResourceDescription, name, ex.Message ); - } - } - } - - private class TextProcessor - { - private readonly ILogger logger = LogManager.GetLogger(); - private readonly VariablePlaceholderConfigurer owner; - private readonly IVariableSource variableSource; - - public TextProcessor(VariablePlaceholderConfigurer owner, IVariableSource variableSource) - { - this.owner = owner; - this.variableSource = variableSource; - } - - public string ParseAndResolveVariables(string rawStringValue) - { - return ParseAndResolveVariables(rawStringValue, new HashedSet()); - } - - private string ParseAndResolveVariables(string strVal, ISet visitedPlaceholders) - { - if (strVal == null) - { - return null; - } - - int startIndex = strVal.IndexOf(owner.placeholderPrefix); - while (startIndex != -1) - { - int endIndex = strVal.IndexOf( - owner.placeholderSuffix, startIndex + owner.placeholderPrefix.Length); - if (endIndex != -1) - { - int pos = startIndex + owner.placeholderPrefix.Length; - string placeholder = strVal.Substring(pos, endIndex - pos); - if (visitedPlaceholders.Contains(placeholder)) - { - throw new ObjectDefinitionStoreException( - string.Format( - CultureInfo.InvariantCulture, - "Circular placeholder reference '{0}' detected. ", - placeholder)); - } - visitedPlaceholders.Add(placeholder); - - if (variableSource.CanResolveVariable(placeholder)) - { - string resolvedValue = variableSource.ResolveVariable(placeholder); - resolvedValue = ParseAndResolveVariables(resolvedValue, visitedPlaceholders); - - if (logger.IsEnabled(LogLevel.Debug)) - { - logger.LogDebug(string.Format( - CultureInfo.InvariantCulture, - "Resolving placeholder '{0}' to '{1}'.", placeholder, resolvedValue)); - } - - if (resolvedValue == null - && startIndex == 0 - && strVal.Length <= endIndex + owner.placeholderSuffix.Length) - { - return null; - } - strVal = strVal.Substring(0, startIndex) + resolvedValue + strVal.Substring(endIndex + owner.placeholderSuffix.Length); - startIndex = strVal.IndexOf(owner.placeholderPrefix, startIndex + (resolvedValue == null ? 0 : resolvedValue.Length)); - } - else if (owner.ignoreUnresolvablePlaceholders) - { - // simply return the unprocessed value... - return strVal; - } - else - { - throw new ObjectDefinitionStoreException(string.Format( - CultureInfo.InvariantCulture, - "Could not resolve placeholder '{0}'.", placeholder)); - } - visitedPlaceholders.Remove(placeholder); - } - else - { - startIndex = -1; - } - } - return strVal; - } - } - - private class CompositeVariableSource : IVariableSource - { - private readonly IList variableSourceList; - - public CompositeVariableSource( IList variableSourceList ) - { - this.variableSourceList = variableSourceList; - } - - public string ResolveVariable( string variableName ) - { - foreach (IVariableSource variableSource in variableSourceList) - { - if (!variableSource.CanResolveVariable(variableName)) continue; - - return variableSource.ResolveVariable( variableName ); - } - throw new ArgumentException(string.Format("cannot resolve variable '{0}'", variableName)); - } - - public bool CanResolveVariable(string variableName) - { - foreach (IVariableSource variableSource in variableSourceList) - { - if (variableSource.CanResolveVariable(variableName)) - return true; - } - return false; + throw new ObjectsException( + "Errored while postprocessing an object factory.", ex); } } } + + /// + /// Return the order value of this object, where a higher value means greater in + /// terms of sorting. + /// + /// The order value. + /// + public int Order + { + get { return order; } + set { order = value; } + } + + /// + /// Apply the property replacement using the specified s for all + /// object in the supplied + /// . + /// + /// + /// The + /// used by the application context. + /// + /// + /// If an error occured. + /// + protected virtual void ProcessProperties(IConfigurableListableObjectFactory factory) + { + CompositeVariableSource compositeVariableSource = new CompositeVariableSource(variableSourceList); + TextProcessor tp = new TextProcessor(this, compositeVariableSource); + ObjectDefinitionVisitor visitor = new ObjectDefinitionVisitor(new ObjectDefinitionVisitor.ResolveHandler(tp.ParseAndResolveVariables)); + + var objectDefinitionNames = factory.GetObjectDefinitionNames(includeAncestors); + for (int i = 0; i < objectDefinitionNames.Count; ++i) + { + string name = objectDefinitionNames[i]; + IObjectDefinition definition = factory.GetObjectDefinition(name, includeAncestors); + + if (definition == null) + continue; + + try + { + visitor.VisitObjectDefinition(definition); + } + catch (ObjectDefinitionStoreException ex) + { + throw new ObjectDefinitionStoreException( + definition.ResourceDescription, name, ex.Message); + } + } + } + + private class TextProcessor + { + private readonly ILogger logger = LogManager.GetLogger(); + private readonly VariablePlaceholderConfigurer owner; + private readonly IVariableSource variableSource; + + public TextProcessor(VariablePlaceholderConfigurer owner, IVariableSource variableSource) + { + this.owner = owner; + this.variableSource = variableSource; + } + + public string ParseAndResolveVariables(string rawStringValue) + { + return ParseAndResolveVariables(rawStringValue, new HashedSet()); + } + + private string ParseAndResolveVariables(string strVal, ISet visitedPlaceholders) + { + if (strVal == null) + { + return null; + } + + int startIndex = strVal.IndexOf(owner.placeholderPrefix); + while (startIndex != -1) + { + int endIndex = strVal.IndexOf( + owner.placeholderSuffix, startIndex + owner.placeholderPrefix.Length); + if (endIndex != -1) + { + int pos = startIndex + owner.placeholderPrefix.Length; + string placeholder = strVal.Substring(pos, endIndex - pos); + if (visitedPlaceholders.Contains(placeholder)) + { + throw new ObjectDefinitionStoreException( + string.Format( + CultureInfo.InvariantCulture, + "Circular placeholder reference '{0}' detected. ", + placeholder)); + } + + visitedPlaceholders.Add(placeholder); + + if (variableSource.CanResolveVariable(placeholder)) + { + string resolvedValue = variableSource.ResolveVariable(placeholder); + resolvedValue = ParseAndResolveVariables(resolvedValue, visitedPlaceholders); + + if (logger.IsEnabled(LogLevel.Debug)) + { + logger.LogDebug(string.Format( + CultureInfo.InvariantCulture, + "Resolving placeholder '{0}' to '{1}'.", placeholder, resolvedValue)); + } + + if (resolvedValue == null + && startIndex == 0 + && strVal.Length <= endIndex + owner.placeholderSuffix.Length) + { + return null; + } + + strVal = strVal.Substring(0, startIndex) + resolvedValue + strVal.Substring(endIndex + owner.placeholderSuffix.Length); + startIndex = strVal.IndexOf(owner.placeholderPrefix, startIndex + (resolvedValue == null ? 0 : resolvedValue.Length)); + } + else if (owner.ignoreUnresolvablePlaceholders) + { + // simply return the unprocessed value... + return strVal; + } + else + { + throw new ObjectDefinitionStoreException(string.Format( + CultureInfo.InvariantCulture, + "Could not resolve placeholder '{0}'.", placeholder)); + } + + visitedPlaceholders.Remove(placeholder); + } + else + { + startIndex = -1; + } + } + + return strVal; + } + } + + private class CompositeVariableSource : IVariableSource + { + private readonly IList variableSourceList; + + public CompositeVariableSource(IList variableSourceList) + { + this.variableSourceList = variableSourceList; + } + + public string ResolveVariable(string variableName) + { + foreach (IVariableSource variableSource in variableSourceList) + { + if (!variableSource.CanResolveVariable(variableName)) continue; + + return variableSource.ResolveVariable(variableName); + } + + throw new ArgumentException(string.Format("cannot resolve variable '{0}'", variableName)); + } + + public bool CanResolveVariable(string variableName) + { + foreach (IVariableSource variableSource in variableSourceList) + { + if (variableSource.CanResolveVariable(variableName)) + return true; + } + + return false; + } + } } diff --git a/src/Spring/Spring.Core/Objects/Factory/FactoryObjectNotInitializedException.cs b/src/Spring/Spring.Core/Objects/Factory/FactoryObjectNotInitializedException.cs index 2028d380..49f36959 100644 --- a/src/Spring/Spring.Core/Objects/Factory/FactoryObjectNotInitializedException.cs +++ b/src/Spring/Spring.Core/Objects/Factory/FactoryObjectNotInitializedException.cs @@ -21,98 +21,96 @@ using System.Runtime.Serialization; using Spring.Util; -namespace Spring.Objects.Factory +namespace Spring.Objects.Factory; + +/// +/// Exception thrown if an +/// is not fully +/// initialized, for example if it is involved in a circular reference. +/// +/// +///

+/// This is usually indicated by any of the variants of the +/// +/// method returning . +///

+///

+/// A circular reference with an +/// cannot be solved by eagerly caching singleton instances (as is the +/// case with normal objects. The reason is that every +/// needs to be fully +/// initialized before it can return the created object, while only specific +/// normal objects need to be initialized - that is, if a collaborating object +/// actually invokes them on initialization instead of just storing the reference. +///

+///
+/// Juergen Hoeller +/// Rick Evans (.NET) +[Serializable] +public class FactoryObjectNotInitializedException : ObjectCreationException { - /// - /// Exception thrown if an - /// is not fully - /// initialized, for example if it is involved in a circular reference. - /// - /// - ///

- /// This is usually indicated by any of the variants of the - /// - /// method returning . - ///

- ///

- /// A circular reference with an - /// cannot be solved by eagerly caching singleton instances (as is the - /// case with normal objects. The reason is that every - /// needs to be fully - /// initialized before it can return the created object, while only specific - /// normal objects need to be initialized - that is, if a collaborating object - /// actually invokes them on initialization instead of just storing the reference. - ///

- ///
- /// Juergen Hoeller - /// Rick Evans (.NET) - [Serializable] - public class FactoryObjectNotInitializedException : ObjectCreationException - { - /// - /// Creates a new instance of the - /// FactoryObjectNotInitializedException class. - /// - public FactoryObjectNotInitializedException() - { - } + /// + /// Creates a new instance of the + /// FactoryObjectNotInitializedException class. + /// + public FactoryObjectNotInitializedException() + { + } - /// - /// Creates a new instance of the FactoryObjectNotInitializedException class. - /// - /// - /// A message about the exception. - /// - public FactoryObjectNotInitializedException(string message) - : base(message) - { - } + /// + /// Creates a new instance of the FactoryObjectNotInitializedException class. + /// + /// + /// A message about the exception. + /// + public FactoryObjectNotInitializedException(string message) + : base(message) + { + } - /// - /// Creates a new instance of the FactoryObjectNotInitializedException class. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception that is being wrapped. - /// - public FactoryObjectNotInitializedException(string message, Exception rootCause) - : base(message, rootCause) - { - } + /// + /// Creates a new instance of the FactoryObjectNotInitializedException class. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception that is being wrapped. + /// + public FactoryObjectNotInitializedException(string message, Exception rootCause) + : base(message, rootCause) + { + } - /// - /// Creates a new instance of the - /// FactoryObjectCircularReferenceException class. - /// - /// - /// The name of the object that triggered the exception. - /// - /// - /// A message about the exception. - /// - public FactoryObjectNotInitializedException(string objectName, string message) - : base(objectName, StringUtils.HasText(message) ? message : - "Circular dependency chain detected for factory object.") - { - } + /// + /// Creates a new instance of the + /// FactoryObjectCircularReferenceException class. + /// + /// + /// The name of the object that triggered the exception. + /// + /// + /// A message about the exception. + /// + public FactoryObjectNotInitializedException(string objectName, string message) + : base(objectName, StringUtils.HasText(message) ? message : "Circular dependency chain detected for factory object.") + { + } - /// - /// Creates a new instance of the FactoryObjectCircularReferenceException class. - /// - /// - /// The - /// that holds the serialized object data about the exception being thrown. - /// - /// - /// The - /// that contains contextual information about the source or destination. - /// - protected FactoryObjectNotInitializedException( - SerializationInfo info, StreamingContext context) - : base(info, context) - { - } - } + /// + /// Creates a new instance of the FactoryObjectCircularReferenceException class. + /// + /// + /// The + /// that holds the serialized object data about the exception being thrown. + /// + /// + /// The + /// that contains contextual information about the source or destination. + /// + protected FactoryObjectNotInitializedException( + SerializationInfo info, StreamingContext context) + : base(info, context) + { + } } diff --git a/src/Spring/Spring.Core/Objects/Factory/IFactoryObject.cs b/src/Spring/Spring.Core/Objects/Factory/IFactoryObject.cs index a19937c9..497907ad 100644 --- a/src/Spring/Spring.Core/Objects/Factory/IFactoryObject.cs +++ b/src/Spring/Spring.Core/Objects/Factory/IFactoryObject.cs @@ -18,60 +18,59 @@ #endregion -namespace Spring.Objects.Factory +namespace Spring.Objects.Factory; + +/// +/// Interface to be implemented by objects used within an +/// that are themselves +/// factories. +/// +/// +///

+/// If an object implements this interface, it is used as a factory, +/// not directly as an object. s +/// can support singletons and prototypes +/// ()... +/// please note that an +/// itself can only ever be a singleton. It is a logic error to configure an +/// itself to be a prototype. +///

+/// +/// An object that implements this interface cannot be used as a normal object. +/// +///
+/// Rod Johnson +/// Juergen Hoeller +/// Rick Evans (.NET) +public interface IFactoryObject { - /// - /// Interface to be implemented by objects used within an - /// that are themselves - /// factories. - /// - /// - ///

- /// If an object implements this interface, it is used as a factory, - /// not directly as an object. s - /// can support singletons and prototypes - /// ()... - /// please note that an - /// itself can only ever be a singleton. It is a logic error to configure an - /// itself to be a prototype. - ///

- /// - /// An object that implements this interface cannot be used as a normal object. - /// - ///
- /// Rod Johnson - /// Juergen Hoeller - /// Rick Evans (.NET) - public interface IFactoryObject - { - /// - /// Return an instance (possibly shared or independent) of the object - /// managed by this factory. - /// - /// - /// - /// If this method is being called in the context of an enclosing IoC container and - /// returns , the IoC container will consider this factory - /// object as not being fully initialized and throw a corresponding (and most - /// probably fatal) exception. - /// - /// - /// - /// An instance (possibly shared or independent) of the object managed by - /// this factory. - /// - object GetObject(); + /// + /// Return an instance (possibly shared or independent) of the object + /// managed by this factory. + /// + /// + /// + /// If this method is being called in the context of an enclosing IoC container and + /// returns , the IoC container will consider this factory + /// object as not being fully initialized and throw a corresponding (and most + /// probably fatal) exception. + /// + /// + /// + /// An instance (possibly shared or independent) of the object managed by + /// this factory. + /// + object GetObject(); - /// - /// Return the of object that this - /// creates, or - /// if not known in advance. - /// - Type ObjectType { get; } + /// + /// Return the of object that this + /// creates, or + /// if not known in advance. + /// + Type ObjectType { get; } - /// - /// Is the object managed by this factory a singleton or a prototype? - /// - bool IsSingleton { get; } - } + /// + /// Is the object managed by this factory a singleton or a prototype? + /// + bool IsSingleton { get; } } diff --git a/src/Spring/Spring.Core/Objects/Factory/IGenericObjectFactory.cs b/src/Spring/Spring.Core/Objects/Factory/IGenericObjectFactory.cs index 6585586b..bc76fb6b 100644 --- a/src/Spring/Spring.Core/Objects/Factory/IGenericObjectFactory.cs +++ b/src/Spring/Spring.Core/Objects/Factory/IGenericObjectFactory.cs @@ -1,14 +1,14 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. - * + * Copyright � 2002-2011 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. @@ -18,34 +18,33 @@ #endregion -namespace Spring.Objects.Factory +namespace Spring.Objects.Factory; + +/// +/// Interface defining a factory which can return an object instance +/// (possibly shared or independent) when invoked. +/// +/// +/// This interface is typically used to encapsulate a generic factory +/// which returns a new instance (prototype) on each invocation. +/// It is similar to the , but +/// implementations of the aforementioned interface are normally meant to be defined +/// as instances by the user in an , +/// while implementations of this class are normally meant to be fed as a property to +/// other objects; as such, the +/// method +/// has different exception handling behavior. +/// +/// Colin Sampaleanu +/// Simon White (.NET) +public interface IGenericObjectFactory { - /// - /// Interface defining a factory which can return an object instance - /// (possibly shared or independent) when invoked. - /// - /// - /// This interface is typically used to encapsulate a generic factory - /// which returns a new instance (prototype) on each invocation. - /// It is similar to the , but - /// implementations of the aforementioned interface are normally meant to be defined - /// as instances by the user in an , - /// while implementations of this class are normally meant to be fed as a property to - /// other objects; as such, the - /// method - /// has different exception handling behavior. - /// - /// Colin Sampaleanu - /// Simon White (.NET) - public interface IGenericObjectFactory - { - /// - /// Return an instance (possibly shared or independent) - /// of the object managed by this factory. - /// - /// - /// An instance of the object (should never be ). - /// - object GetObject(); - } + /// + /// Return an instance (possibly shared or independent) + /// of the object managed by this factory. + /// + /// + /// An instance of the object (should never be ). + /// + object GetObject(); } diff --git a/src/Spring/Spring.Core/Objects/Factory/IHierarchicalObjectFactory.cs b/src/Spring/Spring.Core/Objects/Factory/IHierarchicalObjectFactory.cs index 082d3608..31add941 100644 --- a/src/Spring/Spring.Core/Objects/Factory/IHierarchicalObjectFactory.cs +++ b/src/Spring/Spring.Core/Objects/Factory/IHierarchicalObjectFactory.cs @@ -18,37 +18,35 @@ #endregion -namespace Spring.Objects.Factory +namespace Spring.Objects.Factory; + +/// +/// Sub-interface implemented by object factories that can be part +/// of a hierarchy. +/// +/// Rod Johnson +/// Rick Evans (.NET) +public interface IHierarchicalObjectFactory : IObjectFactory { - /// - /// Sub-interface implemented by object factories that can be part - /// of a hierarchy. - /// - /// Rod Johnson - /// Rick Evans (.NET) - public interface IHierarchicalObjectFactory : IObjectFactory - { - /// - /// Return the parent object factory, or - /// if this factory does not have a parent. - /// - /// - /// The parent object factory, or - /// if this factory does not have a parent. - /// - IObjectFactory ParentObjectFactory { get; } + /// + /// Return the parent object factory, or + /// if this factory does not have a parent. + /// + /// + /// The parent object factory, or + /// if this factory does not have a parent. + /// + IObjectFactory ParentObjectFactory { get; } - - /// - /// Determines whether the local object factory contains a bean of the given name, - /// ignoring object defined in ancestor contexts, also resolving a given alias if necessary. - /// This is an alternative to ContainsObject, ignoring an object - /// of the given name from an ancestor object factory. - /// - /// The name of the object to query. - /// - /// true if objects with the specified name is defined in the local factory; otherwise, false. - /// - bool ContainsLocalObject(string name); - } + /// + /// Determines whether the local object factory contains a bean of the given name, + /// ignoring object defined in ancestor contexts, also resolving a given alias if necessary. + /// This is an alternative to ContainsObject, ignoring an object + /// of the given name from an ancestor object factory. + /// + /// The name of the object to query. + /// + /// true if objects with the specified name is defined in the local factory; otherwise, false. + /// + bool ContainsLocalObject(string name); } diff --git a/src/Spring/Spring.Core/Objects/Factory/IInitializingObject.cs b/src/Spring/Spring.Core/Objects/Factory/IInitializingObject.cs index def90c5c..d6f5094d 100644 --- a/src/Spring/Spring.Core/Objects/Factory/IInitializingObject.cs +++ b/src/Spring/Spring.Core/Objects/Factory/IInitializingObject.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -18,63 +18,62 @@ #endregion -namespace Spring.Objects.Factory +namespace Spring.Objects.Factory; + +/// +/// Defines a simple initialization callback for objects that need to to some +/// post-initialization logic after all of their dependencies have been injected. +/// +/// +///

+/// An implementation of the +/// +/// method might perform some additional custom initialization (over and above that +/// performed by the constructor), or merely check that all mandatory properties +/// have been set (this last example is a very typical use case of this interface). +///

+/// +/// The use of the +/// interface +/// by non-Spring.NET framework code can be avoided (and is generally +/// discouraged). The Spring.NET container provides support for a generic +/// initialization method given to the object definition in the object +/// configuration store (be it XML, or a database, etc). This requires +/// slightly more configuration (one attribute-value pair in the case of +/// XML configuration), but removes any dependency on Spring.NET from the +/// class definition. +/// +///
+/// Rod Johnson +/// Rick Evans (.NET) +/// +public interface IInitializingObject { - /// - /// Defines a simple initialization callback for objects that need to to some - /// post-initialization logic after all of their dependencies have been injected. - /// - /// - ///

- /// An implementation of the - /// - /// method might perform some additional custom initialization (over and above that - /// performed by the constructor), or merely check that all mandatory properties - /// have been set (this last example is a very typical use case of this interface). - ///

- /// - /// The use of the - /// interface - /// by non-Spring.NET framework code can be avoided (and is generally - /// discouraged). The Spring.NET container provides support for a generic - /// initialization method given to the object definition in the object - /// configuration store (be it XML, or a database, etc). This requires - /// slightly more configuration (one attribute-value pair in the case of - /// XML configuration), but removes any dependency on Spring.NET from the - /// class definition. - /// - ///
- /// Rod Johnson - /// Rick Evans (.NET) - /// - public interface IInitializingObject - { - /// - /// Invoked by an - /// after it has injected all of an object's dependencies. - /// - /// - ///

- /// This method allows the object instance to perform the kind of - /// initialization only possible when all of it's dependencies have - /// been injected (set), and to throw an appropriate exception in the - /// event of misconfiguration. - ///

- ///

- /// Please do consult the class level documentation for the - /// interface for a - /// description of exactly when this method is invoked. In - /// particular, it is worth noting that the - /// - /// and - /// callbacks will have been invoked prior to this method being - /// called. - ///

- ///
- /// - /// In the event of misconfiguration (such as the failure to set a - /// required property) or if initialization fails. - /// - void AfterPropertiesSet(); - } -} \ No newline at end of file + /// + /// Invoked by an + /// after it has injected all of an object's dependencies. + /// + /// + ///

+ /// This method allows the object instance to perform the kind of + /// initialization only possible when all of it's dependencies have + /// been injected (set), and to throw an appropriate exception in the + /// event of misconfiguration. + ///

+ ///

+ /// Please do consult the class level documentation for the + /// interface for a + /// description of exactly when this method is invoked. In + /// particular, it is worth noting that the + /// + /// and + /// callbacks will have been invoked prior to this method being + /// called. + ///

+ ///
+ /// + /// In the event of misconfiguration (such as the failure to set a + /// required property) or if initialization fails. + /// + void AfterPropertiesSet(); +} diff --git a/src/Spring/Spring.Core/Objects/Factory/IListableObjectFactory.cs b/src/Spring/Spring.Core/Objects/Factory/IListableObjectFactory.cs index 848424f4..eb80c58c 100644 --- a/src/Spring/Spring.Core/Objects/Factory/IListableObjectFactory.cs +++ b/src/Spring/Spring.Core/Objects/Factory/IListableObjectFactory.cs @@ -18,323 +18,321 @@ #endregion -namespace Spring.Objects.Factory +namespace Spring.Objects.Factory; + +/// +/// Extension of the interface +/// to be implemented by object factories that can enumerate all their object instances, +/// rather than attempting object lookup by name one by one as requested by clients. +/// +/// +///

+/// implementations that preload +/// all their objects (for example, DOM-based XML factories) may implement this +/// interface. This interface is discussed in +/// "Expert One-on-One J2EE Design and Development", by Rod Johnson. +///

+///

+/// If this is an , +/// the return values will not take any +/// hierarchy into account, but +/// will relate only to the objects defined in the current factory. +/// Use the helper class to +/// get all objects. +///

+///

+/// With the exception of +/// , +/// the methods and properties in this interface are not designed for frequent +/// invocation. Implementations may be slow. +///

+///
+/// Rod Johnson +/// Rick Evans (.NET) +public interface IListableObjectFactory : IObjectFactory { - /// - /// Extension of the interface - /// to be implemented by object factories that can enumerate all their object instances, - /// rather than attempting object lookup by name one by one as requested by clients. - /// - /// - ///

- /// implementations that preload - /// all their objects (for example, DOM-based XML factories) may implement this - /// interface. This interface is discussed in - /// "Expert One-on-One J2EE Design and Development", by Rod Johnson. - ///

- ///

- /// If this is an , - /// the return values will not take any - /// hierarchy into account, but - /// will relate only to the objects defined in the current factory. - /// Use the helper class to - /// get all objects. - ///

- ///

- /// With the exception of - /// , - /// the methods and properties in this interface are not designed for frequent - /// invocation. Implementations may be slow. - ///

- ///
- /// Rod Johnson - /// Rick Evans (.NET) - public interface IListableObjectFactory : IObjectFactory - { - /// - /// Check if this object factory contains an object definition with the given name. - /// - /// - ///

- /// Does not consider any hierarchy this factory may participate in. - ///

- /// - /// Ignores any singleton objects that have been registered by other means - /// than object definitions. - /// - ///
- /// The name of the object to look for. - /// - /// if this object factory contains an object - /// definition with the given name. - /// - bool ContainsObjectDefinition(string name); + /// + /// Check if this object factory contains an object definition with the given name. + /// + /// + ///

+ /// Does not consider any hierarchy this factory may participate in. + ///

+ /// + /// Ignores any singleton objects that have been registered by other means + /// than object definitions. + /// + ///
+ /// The name of the object to look for. + /// + /// if this object factory contains an object + /// definition with the given name. + /// + bool ContainsObjectDefinition(string name); - /// - /// Return the number of objects defined in the factory. - /// - /// - /// The number of objects defined in the factory. - /// - int ObjectDefinitionCount { get; } + /// + /// Return the number of objects defined in the factory. + /// + /// + /// The number of objects defined in the factory. + /// + int ObjectDefinitionCount { get; } + /// + /// Return the names of all objects defined in this factory. + /// + /// + /// The names of all objects defined in this factory, or an empty array if none + /// are defined. + /// + IReadOnlyList GetObjectDefinitionNames(); - /// - /// Return the names of all objects defined in this factory. - /// - /// - /// The names of all objects defined in this factory, or an empty array if none - /// are defined. - /// - IReadOnlyList GetObjectDefinitionNames(); + /// + /// Return the names of all objects defined in this factory, if includeAncestors is true + /// includes all parent factories. + /// + /// to include parent factories in result + /// + /// The names of all objects defined in this factory, if includeAncestors is true includes all + /// objects defined in parent factories, or an empty array if none are defined. + /// + IReadOnlyList GetObjectDefinitionNames(bool includeAncestors); - /// - /// Return the names of all objects defined in this factory, if includeAncestors is true - /// includes all parent factories. - /// - /// to include parent factories in result - /// - /// The names of all objects defined in this factory, if includeAncestors is true includes all - /// objects defined in parent factories, or an empty array if none are defined. - /// - IReadOnlyList GetObjectDefinitionNames(bool includeAncestors); + /// + /// Return the names of objects matching the given + /// (including subclasses), judging from the object definitions. + /// + /// + ///

+ /// Does consider objects created by s, + /// or rather it considers the type of objects created by + /// (which means that + /// s will be instantiated). + ///

+ ///

+ /// Does not consider any hierarchy this factory may participate in. + ///

+ ///
+ /// + /// The (class or interface) to match, or + /// for all object names. + /// + /// + /// The names of all objects defined in this factory, or an empty array if none + /// are defined. + /// + IReadOnlyList GetObjectNamesForType(Type type); - /// - /// Return the names of objects matching the given - /// (including subclasses), judging from the object definitions. - /// - /// - ///

- /// Does consider objects created by s, - /// or rather it considers the type of objects created by - /// (which means that - /// s will be instantiated). - ///

- ///

- /// Does not consider any hierarchy this factory may participate in. - ///

- ///
- /// - /// The (class or interface) to match, or - /// for all object names. - /// - /// - /// The names of all objects defined in this factory, or an empty array if none - /// are defined. - /// - IReadOnlyList GetObjectNamesForType(Type type); + /// + /// Return the names of objects matching the given + /// (including subclasses), judging from the object definitions. + /// + /// + ///

+ /// Does consider objects created by s, + /// or rather it considers the type of objects created by + /// (which means that + /// s will be instantiated). + ///

+ ///

+ /// Does not consider any hierarchy this factory may participate in. + ///

+ ///
+ /// + /// The (class or interface) to match, or + /// for all object names. + /// + /// + /// The names of all objects defined in this factory, or an empty array if none + /// are defined. + /// + IReadOnlyList GetObjectNames(); - /// - /// Return the names of objects matching the given - /// (including subclasses), judging from the object definitions. - /// - /// - ///

- /// Does consider objects created by s, - /// or rather it considers the type of objects created by - /// (which means that - /// s will be instantiated). - ///

- ///

- /// Does not consider any hierarchy this factory may participate in. - ///

- ///
- /// - /// The (class or interface) to match, or - /// for all object names. - /// - /// - /// The names of all objects defined in this factory, or an empty array if none - /// are defined. - /// - IReadOnlyList GetObjectNames(); + /// + /// Return the names of objects matching the given + /// (including subclasses), judging from the object definitions. + /// + /// + ///

+ /// Does consider objects created by s, + /// or rather it considers the type of objects created by + /// (which means that + /// s will be instantiated). + ///

+ ///

+ /// Does not consider any hierarchy this factory may participate in. + /// Use + /// to include beans in ancestor factories too. + /// <p>Note: Does <i>not</i> ignore singleton objects that have been registered + /// by other means than bean definitions. + ///

+ ///
+ /// + /// The (class or interface) to match, or + /// for all object names. + /// + /// + /// Whether to include prototype objects too or just singletons (also applies to + /// s). + /// + /// + /// Whether to include s too + /// or just normal objects. + /// + /// + /// The names of all objects defined in this factory, or an empty array if none + /// are defined. + /// + IReadOnlyList GetObjectNamesForType(Type type, bool includePrototypes, bool includeFactoryObjects); - /// - /// Return the names of objects matching the given - /// (including subclasses), judging from the object definitions. - /// - /// - ///

- /// Does consider objects created by s, - /// or rather it considers the type of objects created by - /// (which means that - /// s will be instantiated). - ///

- ///

- /// Does not consider any hierarchy this factory may participate in. - /// Use - /// to include beans in ancestor factories too. - /// <p>Note: Does <i>not</i> ignore singleton objects that have been registered - /// by other means than bean definitions. - ///

- ///
- /// - /// The (class or interface) to match, or - /// for all object names. - /// - /// - /// Whether to include prototype objects too or just singletons (also applies to - /// s). - /// - /// - /// Whether to include s too - /// or just normal objects. - /// - /// - /// The names of all objects defined in this factory, or an empty array if none - /// are defined. - /// - IReadOnlyList GetObjectNamesForType(Type type, bool includePrototypes, bool includeFactoryObjects); + /// + /// Return the names of objects matching the given + /// (including subclasses), judging from the object definitions. + /// + /// + ///

+ /// Does consider objects created by s, + /// or rather it considers the type of objects created by + /// (which means that + /// s will be instantiated). + ///

+ ///

+ /// Does not consider any hierarchy this factory may participate in. + /// Use + /// to include beans in ancestor factories too. + /// <p>Note: Does <i>not</i> ignore singleton objects that have been registered + /// by other means than bean definitions. + ///

+ ///
+ /// + /// The (class or interface) to match, or + /// for all object names. + /// + /// + /// Whether to include prototype objects too or just singletons (also applies to + /// s). + /// + /// + /// Whether to include s too + /// or just normal objects. + /// + /// + /// The names of all objects defined in this factory, or an empty array if none + /// are defined. + /// + IReadOnlyList GetObjectNames(bool includePrototypes, bool includeFactoryObjects); - /// - /// Return the names of objects matching the given - /// (including subclasses), judging from the object definitions. - /// - /// - ///

- /// Does consider objects created by s, - /// or rather it considers the type of objects created by - /// (which means that - /// s will be instantiated). - ///

- ///

- /// Does not consider any hierarchy this factory may participate in. - /// Use - /// to include beans in ancestor factories too. - /// <p>Note: Does <i>not</i> ignore singleton objects that have been registered - /// by other means than bean definitions. - ///

- ///
- /// - /// The (class or interface) to match, or - /// for all object names. - /// - /// - /// Whether to include prototype objects too or just singletons (also applies to - /// s). - /// - /// - /// Whether to include s too - /// or just normal objects. - /// - /// - /// The names of all objects defined in this factory, or an empty array if none - /// are defined. - /// - IReadOnlyList GetObjectNames(bool includePrototypes, bool includeFactoryObjects); + /// + /// Return the object instances that match the given object + /// (including subclasses), judging from either object + /// definitions or the value of + /// in the case of + /// s. + /// + /// + ///

+ /// This version of the + /// method matches all kinds of object definitions, be they singletons, prototypes, or + /// s. Typically, the results + /// of this method call will be the same as a call to + /// IListableObjectFactory.GetObjectsOfType(type,true,true) . + ///

+ ///
+ /// + /// The (class or interface) to match. + /// + /// + /// A of the matching objects, + /// containing the object names as keys and the corresponding object instances + /// as values. + /// + /// + /// If the objects could not be created. + /// + IReadOnlyDictionary GetObjectsOfType(Type type); - /// - /// Return the object instances that match the given object - /// (including subclasses), judging from either object - /// definitions or the value of - /// in the case of - /// s. - /// - /// - ///

- /// This version of the - /// method matches all kinds of object definitions, be they singletons, prototypes, or - /// s. Typically, the results - /// of this method call will be the same as a call to - /// IListableObjectFactory.GetObjectsOfType(type,true,true) . - ///

- ///
- /// - /// The (class or interface) to match. - /// - /// - /// A of the matching objects, - /// containing the object names as keys and the corresponding object instances - /// as values. - /// - /// - /// If the objects could not be created. - /// - IReadOnlyDictionary GetObjectsOfType(Type type); + /// + /// Return the object instances that match the given object + /// (including subclasses), judging from either object + /// definitions or the value of + /// in the case of + /// s. + /// + /// + ///

+ /// This version of the + /// method matches all kinds of object definitions, be they singletons, prototypes, or + /// s. Typically, the results + /// of this method call will be the same as a call to + /// IListableObjectFactory.GetObjectsOfType(type,true,true) . + ///

+ ///
+ /// + /// The (class or interface) to match. + /// + /// + /// A of the matching objects, + /// containing the object names as keys and the corresponding object instances + /// as values. + /// + /// + /// If the objects could not be created. + /// + IReadOnlyDictionary GetObjects(); - /// - /// Return the object instances that match the given object - /// (including subclasses), judging from either object - /// definitions or the value of - /// in the case of - /// s. - /// - /// - ///

- /// This version of the - /// method matches all kinds of object definitions, be they singletons, prototypes, or - /// s. Typically, the results - /// of this method call will be the same as a call to - /// IListableObjectFactory.GetObjectsOfType(type,true,true) . - ///

- ///
- /// - /// The (class or interface) to match. - /// - /// - /// A of the matching objects, - /// containing the object names as keys and the corresponding object instances - /// as values. - /// - /// - /// If the objects could not be created. - /// - IReadOnlyDictionary GetObjects(); + /// + /// Return the object instances that match the given object + /// (including subclasses), judging from either object + /// definitions or the value of + /// in the case of + /// s. + /// + /// + /// The (class or interface) to match. + /// + /// + /// Whether to include prototype objects too or just singletons (also applies to + /// s). + /// + /// + /// Whether to include s too + /// or just normal objects. + /// + /// + /// A of the matching objects, + /// containing the object names as keys and the corresponding object instances + /// as values. + /// + /// + /// If the objects could not be created. + /// + IReadOnlyDictionary GetObjectsOfType(Type type, bool includePrototypes, bool includeFactoryObjects); - /// - /// Return the object instances that match the given object - /// (including subclasses), judging from either object - /// definitions or the value of - /// in the case of - /// s. - /// - /// - /// The (class or interface) to match. - /// - /// - /// Whether to include prototype objects too or just singletons (also applies to - /// s). - /// - /// - /// Whether to include s too - /// or just normal objects. - /// - /// - /// A of the matching objects, - /// containing the object names as keys and the corresponding object instances - /// as values. - /// - /// - /// If the objects could not be created. - /// - IReadOnlyDictionary GetObjectsOfType(Type type, bool includePrototypes, bool includeFactoryObjects); - - /// - /// Return the object instances that match the given object - /// (including subclasses), judging from either object - /// definitions or the value of - /// in the case of - /// s. - /// - /// - /// The (class or interface) to match. - /// - /// - /// Whether to include prototype objects too or just singletons (also applies to - /// s). - /// - /// - /// Whether to include s too - /// or just normal objects. - /// - /// - /// A of the matching objects, - /// containing the object names as keys and the corresponding object instances - /// as values. - /// - /// - /// If the objects could not be created. - /// - IReadOnlyDictionary GetObjects(bool includePrototypes, bool includeFactoryObjects); - } + /// + /// Return the object instances that match the given object + /// (including subclasses), judging from either object + /// definitions or the value of + /// in the case of + /// s. + /// + /// + /// The (class or interface) to match. + /// + /// + /// Whether to include prototype objects too or just singletons (also applies to + /// s). + /// + /// + /// Whether to include s too + /// or just normal objects. + /// + /// + /// A of the matching objects, + /// containing the object names as keys and the corresponding object instances + /// as values. + /// + /// + /// If the objects could not be created. + /// + IReadOnlyDictionary GetObjects(bool includePrototypes, bool includeFactoryObjects); } diff --git a/src/Spring/Spring.Core/Objects/Factory/IObjectDefinitionFactory.cs b/src/Spring/Spring.Core/Objects/Factory/IObjectDefinitionFactory.cs index 7cd98ecd..dc364881 100644 --- a/src/Spring/Spring.Core/Objects/Factory/IObjectDefinitionFactory.cs +++ b/src/Spring/Spring.Core/Objects/Factory/IObjectDefinitionFactory.cs @@ -22,44 +22,40 @@ #endregion -namespace Spring.Objects.Factory.Support +namespace Spring.Objects.Factory.Support; + +/// +/// Central interface for factories that can create +/// +/// instances. +/// +/// +///

+/// Allows for replaceable object definition factories using the Strategy +/// pattern. +///

+///
+/// Aleksandar Seovic +public interface IObjectDefinitionFactory { /// - /// Central interface for factories that can create + /// Factory style method for getting concrete /// /// instances. /// - /// - ///

- /// Allows for replaceable object definition factories using the Strategy - /// pattern. - ///

- ///
- /// Aleksandar Seovic - public interface IObjectDefinitionFactory - { - - /// - /// Factory style method for getting concrete - /// - /// instances. - /// - /// - /// The FullName of the of the defined object. - /// - /// The name of the parent object definition (if any). - /// - /// The against which any class names - /// will be resolved into instances. It can be null to register the - /// object class just by name. - /// - /// - /// An - /// - /// instance. - /// - AbstractObjectDefinition CreateObjectDefinition(string typeName, string parent, AppDomain domain); - - - } + /// + /// The FullName of the of the defined object. + /// + /// The name of the parent object definition (if any). + /// + /// The against which any class names + /// will be resolved into instances. It can be null to register the + /// object class just by name. + /// + /// + /// An + /// + /// instance. + /// + AbstractObjectDefinition CreateObjectDefinition(string typeName, string parent, AppDomain domain); } diff --git a/src/Spring/Spring.Core/Objects/Factory/IObjectFactory.cs b/src/Spring/Spring.Core/Objects/Factory/IObjectFactory.cs index 1d41218c..46c5163a 100644 --- a/src/Spring/Spring.Core/Objects/Factory/IObjectFactory.cs +++ b/src/Spring/Spring.Core/Objects/Factory/IObjectFactory.cs @@ -22,665 +22,661 @@ #endregion -namespace Spring.Objects.Factory +namespace Spring.Objects.Factory; + +/// +/// The root interface for accessing a Spring.NET IoC container. +/// +/// +/// +/// This is the basic client view of a Spring.NET IoC container; further interfaces +/// such as and +/// +/// are available for specific purposes such as enumeration and configuration. +/// +/// +/// This is the root interface to be implemented by objects that can hold a number +/// of object definitions, each uniquely identified by a +/// name. An independent instance of any of these objects can be obtained +/// (the Prototype design pattern), or a single shared instance can be obtained +/// (a superior alternative to the Singleton design pattern, in which the instance is a +/// singleton in the scope of the factory). Which type of instance +/// will be returned depends on the object factory configuration - the API is the same. +/// The Singleton approach is more useful and hence more common in practice. +/// +/// +/// The point of this approach is that the IObjectFactory is a central registry of +/// application components, and centralizes the configuring of application components +/// (no more do individual objects need to read properties files, for example). +/// See chapters 4 and 11 of "Expert One-on-One J2EE Design and Development" for a +/// discussion of the benefits of this approach. +/// +/// +/// Normally an IObjectFactory will load object definitions stored in a configuration +/// source (such as an XML document), and use the +/// namespace to configure the objects. However, an implementation could simply return +/// .NET objects it creates as necessary directly in .NET code. There are no +/// constraints on how the definitions could be stored: LDAP, RDBMS, XML, properties +/// file etc. Implementations are encouraged to support references amongst objects, +/// to either Singletons or Prototypes. +/// +/// +/// In contrast to the methods in +/// , all of the methods +/// in this interface will also check parent factories if this is an +/// . If an object is +/// not found in this factory instance, the immediate parent is asked. Objects in +/// this factory instance are supposed to override objects of the same name in any +/// parent factory. +/// +/// +/// Object factories are supposed to support the standard object lifecycle interfaces +/// as far as possible. The maximum set of initialization methods and their standard +/// order is: +/// +/// +/// +/// +/// +/// 's +/// property. +/// +/// +/// +/// +/// 's +/// property. +/// +/// +/// +/// +/// +/// (only applicable if running within an ). +/// +/// +/// +/// +/// The +/// +/// method of +/// s. +/// +/// +/// +/// +/// 's +/// method. +/// +/// +/// +/// +/// A custom init-method definition. +/// +/// +/// +/// +/// The +/// +/// method of +/// s. +/// +/// +/// +/// +///

+/// +/// On shutdown of an object factory, the following lifecycle methods apply: +/// +/// +/// +/// +/// +/// 's +/// method. +/// +/// +/// +/// +/// A custom destroy-method definition. +/// +/// +/// +/// +/// +/// Rod Johnson +/// Juergen Hoeller +/// Rick Evans (.NET) +public interface IObjectFactory : IDisposable { - ///

- /// The root interface for accessing a Spring.NET IoC container. - /// - /// - /// - /// This is the basic client view of a Spring.NET IoC container; further interfaces - /// such as and - /// - /// are available for specific purposes such as enumeration and configuration. - /// - /// - /// This is the root interface to be implemented by objects that can hold a number - /// of object definitions, each uniquely identified by a - /// name. An independent instance of any of these objects can be obtained - /// (the Prototype design pattern), or a single shared instance can be obtained - /// (a superior alternative to the Singleton design pattern, in which the instance is a - /// singleton in the scope of the factory). Which type of instance - /// will be returned depends on the object factory configuration - the API is the same. - /// The Singleton approach is more useful and hence more common in practice. - /// - /// - /// The point of this approach is that the IObjectFactory is a central registry of - /// application components, and centralizes the configuring of application components - /// (no more do individual objects need to read properties files, for example). - /// See chapters 4 and 11 of "Expert One-on-One J2EE Design and Development" for a - /// discussion of the benefits of this approach. - /// - /// - /// Normally an IObjectFactory will load object definitions stored in a configuration - /// source (such as an XML document), and use the - /// namespace to configure the objects. However, an implementation could simply return - /// .NET objects it creates as necessary directly in .NET code. There are no - /// constraints on how the definitions could be stored: LDAP, RDBMS, XML, properties - /// file etc. Implementations are encouraged to support references amongst objects, - /// to either Singletons or Prototypes. - /// - /// - /// In contrast to the methods in - /// , all of the methods - /// in this interface will also check parent factories if this is an - /// . If an object is - /// not found in this factory instance, the immediate parent is asked. Objects in - /// this factory instance are supposed to override objects of the same name in any - /// parent factory. - /// - /// - /// Object factories are supposed to support the standard object lifecycle interfaces - /// as far as possible. The maximum set of initialization methods and their standard - /// order is: - /// - /// - /// - /// - /// - /// 's - /// property. - /// - /// - /// - /// - /// 's - /// property. - /// - /// - /// - /// - /// - /// (only applicable if running within an ). - /// - /// - /// - /// - /// The - /// - /// method of - /// s. - /// - /// - /// - /// - /// 's - /// method. - /// - /// - /// - /// - /// A custom init-method definition. - /// - /// - /// - /// - /// The - /// - /// method of - /// s. - /// - /// - /// - /// - ///

- /// - /// On shutdown of an object factory, the following lifecycle methods apply: - /// - /// - /// - /// - /// - /// 's - /// method. - /// - /// - /// - /// - /// A custom destroy-method definition. - /// - /// - /// - /// - /// - /// Rod Johnson - /// Juergen Hoeller - /// Rick Evans (.NET) - public interface IObjectFactory : IDisposable - { - ///

- /// Determine whether this object factory treats object names case-sensitive or not. - /// - bool IsCaseSensitive { get; } + /// + /// Determine whether this object factory treats object names case-sensitive or not. + /// + bool IsCaseSensitive { get; } - /// - /// Is this object a singleton? - /// - /// - /// - /// That is, will - /// always return the same object? - /// - /// - /// Will ask the parent factory if the object cannot be found in this factory - /// instance. - /// - /// - /// The name of the object to query. - /// True if the named object is a singleton. - /// - /// If there's no such object definition. - /// - bool IsSingleton(string name); + /// + /// Is this object a singleton? + /// + /// + /// + /// That is, will + /// always return the same object? + /// + /// + /// Will ask the parent factory if the object cannot be found in this factory + /// instance. + /// + /// + /// The name of the object to query. + /// True if the named object is a singleton. + /// + /// If there's no such object definition. + /// + bool IsSingleton(string name); + /// + /// Determines whether the specified object name is prototype. That is, will GetObject + /// always return independent instances? + /// + /// This method returning false does not clearly indicate a singleton object. + /// It indicated non-independent instances, which may correspond to a scoped object as + /// well. use the IsSingleton property to explicitly check for a shared + /// singleton instance. + /// Translates aliases back to the corresponding canonical object name. Will ask the + /// parent factory if the object can not be found in this factory instance. + /// + /// + /// + /// The name of the object to query + /// + /// true if the specified object name will always deliver independent instances; otherwise, false. + /// + /// if there is no object with the given name. + bool IsPrototype(string name); - /// - /// Determines whether the specified object name is prototype. That is, will GetObject - /// always return independent instances? - /// - /// This method returning false does not clearly indicate a singleton object. - /// It indicated non-independent instances, which may correspond to a scoped object as - /// well. use the IsSingleton property to explicitly check for a shared - /// singleton instance. - /// Translates aliases back to the corresponding canonical object name. Will ask the - /// parent factory if the object can not be found in this factory instance. - /// - /// - /// - /// The name of the object to query - /// - /// true if the specified object name will always deliver independent instances; otherwise, false. - /// - /// if there is no object with the given name. - bool IsPrototype(string name); + /// + /// Does this object factory contain an object with the given name? + /// + /// + /// + /// The concrete lookup strategy depends on the implementation. E.g. s + /// will also search their parent factory if a name isn't found . + /// + /// + /// The name of the object to query. + /// True if an object with the given name is defined. + bool ContainsObject(string name); - /// - /// Does this object factory contain an object with the given name? - /// - /// - /// - /// The concrete lookup strategy depends on the implementation. E.g. s - /// will also search their parent factory if a name isn't found . - /// - /// - /// The name of the object to query. - /// True if an object with the given name is defined. - bool ContainsObject(string name); - - /// - /// Return the aliases for the given object name, if defined. - /// - /// - /// - /// Will ask the parent factory if the object cannot be found in this factory - /// instance. - /// - /// - /// The object name to check for aliases. - /// The aliases, or an empty array if none. - /// - /// If there's no such object definition. - /// - IReadOnlyList GetAliases(string name); + /// + /// Return the aliases for the given object name, if defined. + /// + /// + /// + /// Will ask the parent factory if the object cannot be found in this factory + /// instance. + /// + /// + /// The object name to check for aliases. + /// The aliases, or an empty array if none. + /// + /// If there's no such object definition. + /// + IReadOnlyList GetAliases(string name); #if !MONO - /// - /// Return an instance (possibly shared or independent) of the given object name. - /// - /// - /// - /// This method allows an object factory to be used as a replacement for the - /// Singleton or Prototype design pattern. - /// - /// - /// Note that callers should retain references to returned objects. There is no - /// guarantee that this method will be implemented to be efficient. For example, - /// it may be synchronized, or may need to run an RDBMS query. - /// - /// - /// Will ask the parent factory if the object cannot be found in this factory - /// instance. - /// - /// - /// This is the indexer for the - /// interface. - /// - /// - /// The name of the object to return. - /// The instance of the object. - /// - /// If there's no such object definition. - /// - /// - /// If the object could not be created. - /// + /// + /// Return an instance (possibly shared or independent) of the given object name. + /// + /// + /// + /// This method allows an object factory to be used as a replacement for the + /// Singleton or Prototype design pattern. + /// + /// + /// Note that callers should retain references to returned objects. There is no + /// guarantee that this method will be implemented to be efficient. For example, + /// it may be synchronized, or may need to run an RDBMS query. + /// + /// + /// Will ask the parent factory if the object cannot be found in this factory + /// instance. + /// + /// + /// This is the indexer for the + /// interface. + /// + /// + /// The name of the object to return. + /// The instance of the object. + /// + /// If there's no such object definition. + /// + /// + /// If the object could not be created. + /// #endif - object this[string name] { get; } + object this[string name] { get; } - /// - /// Return an instance (possibly shared or independent) of the given object name. - /// - /// - /// - /// This method allows an object factory to be used as a replacement for the - /// Singleton or Prototype design pattern. - /// - /// - /// Note that callers should retain references to returned objects. There is no - /// guarantee that this method will be implemented to be efficient. For example, - /// it may be synchronized, or may need to run an RDBMS query. - /// - /// - /// Will ask the parent factory if the object cannot be found in this factory - /// instance. - /// - /// - /// The type of the object to return. - /// The instance of the object. - /// - /// If there's no such object definition. - /// - /// - /// If there is more than a single object of the requested type defined in the factory. - /// - /// - /// If the object could not be created. - /// - T GetObject(); + /// + /// Return an instance (possibly shared or independent) of the given object name. + /// + /// + /// + /// This method allows an object factory to be used as a replacement for the + /// Singleton or Prototype design pattern. + /// + /// + /// Note that callers should retain references to returned objects. There is no + /// guarantee that this method will be implemented to be efficient. For example, + /// it may be synchronized, or may need to run an RDBMS query. + /// + /// + /// Will ask the parent factory if the object cannot be found in this factory + /// instance. + /// + /// + /// The type of the object to return. + /// The instance of the object. + /// + /// If there's no such object definition. + /// + /// + /// If there is more than a single object of the requested type defined in the factory. + /// + /// + /// If the object could not be created. + /// + T GetObject(); - /// - /// Return an instance (possibly shared or independent) of the given object name. - /// - /// - /// - /// This method allows an object factory to be used as a replacement for the - /// Singleton or Prototype design pattern. - /// - /// - /// Note that callers should retain references to returned objects. There is no - /// guarantee that this method will be implemented to be efficient. For example, - /// it may be synchronized, or may need to run an RDBMS query. - /// - /// - /// Will ask the parent factory if the object cannot be found in this factory - /// instance. - /// - /// - /// The name of the object to return. - /// The instance of the object. - /// - /// If there's no such object definition. - /// - /// - /// If the object could not be created. - /// - object GetObject(string name); + /// + /// Return an instance (possibly shared or independent) of the given object name. + /// + /// + /// + /// This method allows an object factory to be used as a replacement for the + /// Singleton or Prototype design pattern. + /// + /// + /// Note that callers should retain references to returned objects. There is no + /// guarantee that this method will be implemented to be efficient. For example, + /// it may be synchronized, or may need to run an RDBMS query. + /// + /// + /// Will ask the parent factory if the object cannot be found in this factory + /// instance. + /// + /// + /// The name of the object to return. + /// The instance of the object. + /// + /// If there's no such object definition. + /// + /// + /// If the object could not be created. + /// + object GetObject(string name); - /// - /// Return an instance (possibly shared or independent) of the given object name. - /// - /// - /// - /// This method allows an object factory to be used as a replacement for the - /// Singleton or Prototype design pattern. - /// - /// - /// Note that callers should retain references to returned objects. There is no - /// guarantee that this method will be implemented to be efficient. For example, - /// it may be synchronized, or may need to run an RDBMS query. - /// - /// - /// Will ask the parent factory if the object cannot be found in this factory - /// instance. - /// - /// - /// The type of the object to return. - /// The name of the object to return. - /// The instance of the object. - /// - /// If there's no such object definition. - /// - /// - /// If the object is not of the required type. - /// - /// - /// If the object could not be created. - /// - T GetObject(string name); + /// + /// Return an instance (possibly shared or independent) of the given object name. + /// + /// + /// + /// This method allows an object factory to be used as a replacement for the + /// Singleton or Prototype design pattern. + /// + /// + /// Note that callers should retain references to returned objects. There is no + /// guarantee that this method will be implemented to be efficient. For example, + /// it may be synchronized, or may need to run an RDBMS query. + /// + /// + /// Will ask the parent factory if the object cannot be found in this factory + /// instance. + /// + /// + /// The type of the object to return. + /// The name of the object to return. + /// The instance of the object. + /// + /// If there's no such object definition. + /// + /// + /// If the object is not of the required type. + /// + /// + /// If the object could not be created. + /// + T GetObject(string name); - /// - /// Return an instance (possibly shared or independent) of the given object name. - /// - /// - /// - /// This method allows an object factory to be used as a replacement for the - /// Singleton or Prototype design pattern. - /// - /// - /// Note that callers should retain references to returned objects. There is no - /// guarantee that this method will be implemented to be efficient. For example, - /// it may be synchronized, or may need to run an RDBMS query. - /// - /// - /// Will ask the parent factory if the object cannot be found in this factory - /// instance. - /// - /// - /// The name of the object to return. - /// - /// The arguments to use if creating a prototype using explicit arguments to - /// a static factory method. If there is no factory method and the - /// arguments are not null, then match the argument values by type and - /// call the object's constructor. - /// - /// The instance of the object. - /// - /// If there's no such object definition. - /// - /// - /// If the object could not be created. - /// - /// - /// If the supplied is . - /// - object GetObject(string name, object[] arguments); + /// + /// Return an instance (possibly shared or independent) of the given object name. + /// + /// + /// + /// This method allows an object factory to be used as a replacement for the + /// Singleton or Prototype design pattern. + /// + /// + /// Note that callers should retain references to returned objects. There is no + /// guarantee that this method will be implemented to be efficient. For example, + /// it may be synchronized, or may need to run an RDBMS query. + /// + /// + /// Will ask the parent factory if the object cannot be found in this factory + /// instance. + /// + /// + /// The name of the object to return. + /// + /// The arguments to use if creating a prototype using explicit arguments to + /// a static factory method. If there is no factory method and the + /// arguments are not null, then match the argument values by type and + /// call the object's constructor. + /// + /// The instance of the object. + /// + /// If there's no such object definition. + /// + /// + /// If the object could not be created. + /// + /// + /// If the supplied is . + /// + object GetObject(string name, object[] arguments); - /// - /// Return an instance (possibly shared or independent) of the given object name. - /// - /// - /// - /// This method allows an object factory to be used as a replacement for the - /// Singleton or Prototype design pattern. - /// - /// - /// Note that callers should retain references to returned objects. There is no - /// guarantee that this method will be implemented to be efficient. For example, - /// it may be synchronized, or may need to run an RDBMS query. - /// - /// - /// Will ask the parent factory if the object cannot be found in this factory - /// instance. - /// - /// - /// The name of the object to return. - /// - /// The arguments to use if creating a prototype using explicit arguments to - /// a static factory method. If there is no factory method and the - /// arguments are not null, then match the argument values by type and - /// call the object's constructor. - /// - /// The instance of the object. - /// - /// If there's no such object definition. - /// - /// - /// If the object could not be created. - /// - /// - /// If the object is not of the required type. - /// - /// - /// If the supplied is . - /// - T GetObject(string name, object[] arguments); + /// + /// Return an instance (possibly shared or independent) of the given object name. + /// + /// + /// + /// This method allows an object factory to be used as a replacement for the + /// Singleton or Prototype design pattern. + /// + /// + /// Note that callers should retain references to returned objects. There is no + /// guarantee that this method will be implemented to be efficient. For example, + /// it may be synchronized, or may need to run an RDBMS query. + /// + /// + /// Will ask the parent factory if the object cannot be found in this factory + /// instance. + /// + /// + /// The name of the object to return. + /// + /// The arguments to use if creating a prototype using explicit arguments to + /// a static factory method. If there is no factory method and the + /// arguments are not null, then match the argument values by type and + /// call the object's constructor. + /// + /// The instance of the object. + /// + /// If there's no such object definition. + /// + /// + /// If the object could not be created. + /// + /// + /// If the object is not of the required type. + /// + /// + /// If the supplied is . + /// + T GetObject(string name, object[] arguments); - /// - /// Return an instance (possibly shared or independent) of the given object name. - /// - /// The name of the object to return. - /// - /// The the object may match. Can be an interface or - /// superclass of the actual class. For example, if the value is the - /// class, this method will succeed whatever the - /// class of the returned instance. - /// - /// - /// The arguments to use if creating a prototype using explicit arguments to - /// a factory method. If there is no factory method and the - /// supplied array is not , then - /// match the argument values by type and call the object's constructor. - /// - /// The instance of the object. - /// - /// If there's no such object definition. - /// - /// - /// If the object could not be created. - /// - /// - /// If the object is not of the required type. - /// - /// - /// If the supplied is . - /// - /// - object GetObject(string name, Type requiredType, object[] arguments); + /// + /// Return an instance (possibly shared or independent) of the given object name. + /// + /// The name of the object to return. + /// + /// The the object may match. Can be an interface or + /// superclass of the actual class. For example, if the value is the + /// class, this method will succeed whatever the + /// class of the returned instance. + /// + /// + /// The arguments to use if creating a prototype using explicit arguments to + /// a factory method. If there is no factory method and the + /// supplied array is not , then + /// match the argument values by type and call the object's constructor. + /// + /// The instance of the object. + /// + /// If there's no such object definition. + /// + /// + /// If the object could not be created. + /// + /// + /// If the object is not of the required type. + /// + /// + /// If the supplied is . + /// + /// + object GetObject(string name, Type requiredType, object[] arguments); - /// - /// Return an instance (possibly shared or independent) of the given object name. - /// - /// - /// - /// Provides a measure of type safety by throwing an exception if the object is - /// not of the required . - /// - /// - /// This method allows an object factory to be used as a replacement for the - /// Singleton or Prototype design pattern. - /// - /// - /// Note that callers should retain references to returned objects. There is no - /// guarantee that this method will be implemented to be efficient. For example, - /// it may be synchronized, or may need to run an RDBMS query. - /// - /// - /// Will ask the parent factory if the object cannot be found in this factory - /// instance. - /// - /// - /// The name of the object to return. - /// - /// the object may match. Can be an interface or - /// superclass of the actual class. For example, if the value is the - /// class, this method will succeed whatever the - /// class of the returned instance. - /// - /// The instance of the object. - /// - /// If there's no such object definition. - /// - /// - /// If the object could not be created. - /// - /// - /// If the object is not of the required type. - /// - object GetObject(string name, Type requiredType); + /// + /// Return an instance (possibly shared or independent) of the given object name. + /// + /// + /// + /// Provides a measure of type safety by throwing an exception if the object is + /// not of the required . + /// + /// + /// This method allows an object factory to be used as a replacement for the + /// Singleton or Prototype design pattern. + /// + /// + /// Note that callers should retain references to returned objects. There is no + /// guarantee that this method will be implemented to be efficient. For example, + /// it may be synchronized, or may need to run an RDBMS query. + /// + /// + /// Will ask the parent factory if the object cannot be found in this factory + /// instance. + /// + /// + /// The name of the object to return. + /// + /// the object may match. Can be an interface or + /// superclass of the actual class. For example, if the value is the + /// class, this method will succeed whatever the + /// class of the returned instance. + /// + /// The instance of the object. + /// + /// If there's no such object definition. + /// + /// + /// If the object could not be created. + /// + /// + /// If the object is not of the required type. + /// + object GetObject(string name, Type requiredType); - /// - /// Determine the type of the object with the given name. - /// - /// - /// - /// More specifically, checks the type of object that - /// would return. - /// For an , returns the type - /// of object that the creates. - /// - /// - /// The name of the object to query. - /// - /// The type of the object or if not determinable. - /// - Type GetType(string name); + /// + /// Determine the type of the object with the given name. + /// + /// + /// + /// More specifically, checks the type of object that + /// would return. + /// For an , returns the type + /// of object that the creates. + /// + /// + /// The name of the object to query. + /// + /// The type of the object or if not determinable. + /// + Type GetType(string name); + /// + /// Determines whether the object with the given name matches the specified type. + /// + /// More specifically, check whether a GetObject call for the given name + /// would return an object that is assignable to the specified target type. + /// Translates aliases back to the corresponding canonical bean name. + /// Will ask the parent factory if the bean cannot be found in this factory instance. + /// + /// The name of the object to query. + /// Type of the target to match against. + /// + /// true if the object type matches; otherwise, false + /// if it doesn't match or cannot be determined yet. + /// + /// Ff there is no object with the given name + /// + bool IsTypeMatch(string name, Type targetType); + /// + /// Determines whether the object with the given name matches the specified type. + /// + /// More specifically, check whether a GetObject call for the given name + /// would return an object that is assignable to the specified target type. + /// Translates aliases back to the corresponding canonical bean name. + /// Will ask the parent factory if the bean cannot be found in this factory instance. + /// + /// The name of the object to query. + /// Type of the target to match against. + /// + /// true if the object type matches; otherwise, false + /// if it doesn't match or cannot be determined yet. + /// + /// Ff there is no object with the given name + /// + bool IsTypeMatch(string name); - /// - /// Determines whether the object with the given name matches the specified type. - /// - /// More specifically, check whether a GetObject call for the given name - /// would return an object that is assignable to the specified target type. - /// Translates aliases back to the corresponding canonical bean name. - /// Will ask the parent factory if the bean cannot be found in this factory instance. - /// - /// The name of the object to query. - /// Type of the target to match against. - /// - /// true if the object type matches; otherwise, false - /// if it doesn't match or cannot be determined yet. - /// - /// Ff there is no object with the given name - /// - bool IsTypeMatch(string name, Type targetType); + /// + /// Return an unconfigured(!) instance (possibly shared or independent) of the given object name. + /// + /// The name of the object to return. + /// + /// The the object may match. Can be an interface or + /// superclass of the actual class. For example, if the value is the + /// class, this method will succeed whatever the + /// class of the returned instance. + /// + /// + /// The arguments to use if creating a prototype using explicit arguments to + /// a factory method. If there is no factory method and the + /// supplied array is not , then + /// match the argument values by type and call the object's constructor. + /// + /// The unconfigured(!) instance of the object. + /// + /// If there's no such object definition. + /// + /// + /// If the object could not be created. + /// + /// + /// If the object is not of the required type. + /// + /// + /// If the supplied is . + /// + /// + /// + /// This method will only instantiate the requested object. It does NOT inject any dependencies! + /// + object CreateObject(string name, Type requiredType, object[] arguments); - /// - /// Determines whether the object with the given name matches the specified type. - /// - /// More specifically, check whether a GetObject call for the given name - /// would return an object that is assignable to the specified target type. - /// Translates aliases back to the corresponding canonical bean name. - /// Will ask the parent factory if the bean cannot be found in this factory instance. - /// - /// The name of the object to query. - /// Type of the target to match against. - /// - /// true if the object type matches; otherwise, false - /// if it doesn't match or cannot be determined yet. - /// - /// Ff there is no object with the given name - /// - bool IsTypeMatch(string name); + /// + /// Return an unconfigured(!) instance (possibly shared or independent) of the given object name. + /// + /// The name of the object to return. + /// + /// The the object may match. Can be an interface or + /// superclass of the actual class. For example, if the value is the + /// class, this method will succeed whatever the + /// class of the returned instance. + /// + /// + /// The arguments to use if creating a prototype using explicit arguments to + /// a factory method. If there is no factory method and the + /// supplied array is not , then + /// match the argument values by type and call the object's constructor. + /// + /// The unconfigured(!) instance of the object. + /// + /// If there's no such object definition. + /// + /// + /// If the object could not be created. + /// + /// + /// If the object is not of the required type. + /// + /// + /// If the supplied is . + /// + /// + /// + /// This method will only instantiate the requested object. It does NOT inject any dependencies! + /// + T CreateObject(string name, object[] arguments); - /// - /// Return an unconfigured(!) instance (possibly shared or independent) of the given object name. - /// - /// The name of the object to return. - /// - /// The the object may match. Can be an interface or - /// superclass of the actual class. For example, if the value is the - /// class, this method will succeed whatever the - /// class of the returned instance. - /// - /// - /// The arguments to use if creating a prototype using explicit arguments to - /// a factory method. If there is no factory method and the - /// supplied array is not , then - /// match the argument values by type and call the object's constructor. - /// - /// The unconfigured(!) instance of the object. - /// - /// If there's no such object definition. - /// - /// - /// If the object could not be created. - /// - /// - /// If the object is not of the required type. - /// - /// - /// If the supplied is . - /// - /// - /// - /// This method will only instantiate the requested object. It does NOT inject any dependencies! - /// - object CreateObject(string name, Type requiredType, object[] arguments); - - /// - /// Return an unconfigured(!) instance (possibly shared or independent) of the given object name. - /// - /// The name of the object to return. - /// - /// The the object may match. Can be an interface or - /// superclass of the actual class. For example, if the value is the - /// class, this method will succeed whatever the - /// class of the returned instance. - /// - /// - /// The arguments to use if creating a prototype using explicit arguments to - /// a factory method. If there is no factory method and the - /// supplied array is not , then - /// match the argument values by type and call the object's constructor. - /// - /// The unconfigured(!) instance of the object. - /// - /// If there's no such object definition. - /// - /// - /// If the object could not be created. - /// - /// - /// If the object is not of the required type. - /// - /// - /// If the supplied is . - /// - /// - /// - /// This method will only instantiate the requested object. It does NOT inject any dependencies! - /// - T CreateObject(string name, object[] arguments); - - /// - /// Injects dependencies into the supplied instance - /// using the named object definition. - /// - /// - /// - /// In addition to being generally useful, typically this method is used to provide - /// dependency injection functionality for objects that are instantiated outwith the - /// control of a developer. A case in point is the way that the current (1.1) - /// ASP.NET classes instantiate web controls... the instantiation takes place within - /// a private method of a compiled page, and thus cannot be hooked into the - /// typical Spring.NET IOC container lifecycle for dependency injection. - /// - /// - /// - /// The following code snippet assumes that the instantiated factory instance - /// has been configured with an object definition named - /// 'ExampleNamespace.BusinessObject' that has been configured to set the - /// Dao property of any ExampleNamespace.BusinessObject instance - /// to an instance of an appropriate implementation... - /// - /// namespace ExampleNamespace - /// { - /// public class BusinessObject - /// { - /// private IDao _dao; - /// - /// public BusinessObject() {} - /// - /// public IDao Dao - /// { - /// get { return _dao; } - /// set { _dao = value; } - /// } - /// } - /// } - /// - /// with the corresponding driver code looking like so... - /// - /// IObjectFactory factory = GetAnIObjectFactoryImplementation(); - /// BusinessObject instance = new BusinessObject(); - /// factory.ConfigureObject(instance, "object_definition_name"); - /// // at this point the dependencies for the 'instance' object will have been resolved... - /// - /// - /// - /// The object instance that is to be so configured. - /// - /// - /// The name of the object definition expressing the dependencies that are to - /// be injected into the supplied instance. - /// - /// - /// If there is no object definition for the supplied . - /// - /// - /// If any of the target object's dependencies could not be created. - /// - object ConfigureObject(object target, string name); - } + /// + /// Injects dependencies into the supplied instance + /// using the named object definition. + /// + /// + /// + /// In addition to being generally useful, typically this method is used to provide + /// dependency injection functionality for objects that are instantiated outwith the + /// control of a developer. A case in point is the way that the current (1.1) + /// ASP.NET classes instantiate web controls... the instantiation takes place within + /// a private method of a compiled page, and thus cannot be hooked into the + /// typical Spring.NET IOC container lifecycle for dependency injection. + /// + /// + /// + /// The following code snippet assumes that the instantiated factory instance + /// has been configured with an object definition named + /// 'ExampleNamespace.BusinessObject' that has been configured to set the + /// Dao property of any ExampleNamespace.BusinessObject instance + /// to an instance of an appropriate implementation... + /// + /// namespace ExampleNamespace + /// { + /// public class BusinessObject + /// { + /// private IDao _dao; + /// + /// public BusinessObject() {} + /// + /// public IDao Dao + /// { + /// get { return _dao; } + /// set { _dao = value; } + /// } + /// } + /// } + /// + /// with the corresponding driver code looking like so... + /// + /// IObjectFactory factory = GetAnIObjectFactoryImplementation(); + /// BusinessObject instance = new BusinessObject(); + /// factory.ConfigureObject(instance, "object_definition_name"); + /// // at this point the dependencies for the 'instance' object will have been resolved... + /// + /// + /// + /// The object instance that is to be so configured. + /// + /// + /// The name of the object definition expressing the dependencies that are to + /// be injected into the supplied instance. + /// + /// + /// If there is no object definition for the supplied . + /// + /// + /// If any of the target object's dependencies could not be created. + /// + object ConfigureObject(object target, string name); } diff --git a/src/Spring/Spring.Core/Objects/Factory/IObjectFactoryAware.cs b/src/Spring/Spring.Core/Objects/Factory/IObjectFactoryAware.cs index 80f7c130..43c0b610 100644 --- a/src/Spring/Spring.Core/Objects/Factory/IObjectFactoryAware.cs +++ b/src/Spring/Spring.Core/Objects/Factory/IObjectFactoryAware.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -20,52 +20,49 @@ #region Imports - - #endregion -namespace Spring.Objects.Factory +namespace Spring.Objects.Factory; + +/// +/// Interface to be implemented by objects that wish to be aware of their owning +/// . +/// +/// +///

+/// For example, objects can look up collaborating objects via the factory. +///

+///

+/// Note that most objects will choose to receive references to collaborating +/// objects via respective properties and / or an appropriate constructor. +///

+///

+/// For a list of all object lifecycle methods, see the +/// API documentation. +///

+///
+/// Rod Johnson +/// Rick Evans (.NET) +public interface IObjectFactoryAware { - /// - /// Interface to be implemented by objects that wish to be aware of their owning - /// . - /// - /// - ///

- /// For example, objects can look up collaborating objects via the factory. - ///

- ///

- /// Note that most objects will choose to receive references to collaborating - /// objects via respective properties and / or an appropriate constructor. - ///

- ///

- /// For a list of all object lifecycle methods, see the - /// API documentation. - ///

- ///
- /// Rod Johnson - /// Rick Evans (.NET) - public interface IObjectFactoryAware - { - /// - /// Callback that supplies the owning factory to an object instance. - /// - /// - /// Owning - /// (may not be ). The object can immediately - /// call methods on the factory. - /// - /// - ///

- /// Invoked after population of normal object properties but before an init - /// callback like 's - /// - /// method or a custom init-method. - ///

- ///
- /// - /// In case of initialization errors. - /// - IObjectFactory ObjectFactory { set; } - } -} \ No newline at end of file + /// + /// Callback that supplies the owning factory to an object instance. + /// + /// + /// Owning + /// (may not be ). The object can immediately + /// call methods on the factory. + /// + /// + ///

+ /// Invoked after population of normal object properties but before an init + /// callback like 's + /// + /// method or a custom init-method. + ///

+ ///
+ /// + /// In case of initialization errors. + /// + IObjectFactory ObjectFactory { set; } +} diff --git a/src/Spring/Spring.Core/Objects/Factory/IObjectNameAware.cs b/src/Spring/Spring.Core/Objects/Factory/IObjectNameAware.cs index b52e8023..e9c9e7ad 100644 --- a/src/Spring/Spring.Core/Objects/Factory/IObjectNameAware.cs +++ b/src/Spring/Spring.Core/Objects/Factory/IObjectNameAware.cs @@ -18,45 +18,42 @@ #endregion -namespace Spring.Objects.Factory -{ +namespace Spring.Objects.Factory; +/// +/// Interface to be implemented by objects that wish to be aware of their object +/// name in an . +/// +/// +///

+/// Note that most objects will choose to receive references to collaborating +/// objects via respective properties. +///

+///

+/// For a list of all object lifecycle methods, see the +/// API documentation. +///

+///
+/// Juergen Hoeller +/// Rick Evans (.NET) +public interface IObjectNameAware +{ /// - /// Interface to be implemented by objects that wish to be aware of their object - /// name in an . + /// Set the name of the object in the object factory that created this object. /// + /// + /// The name of the object in the factory. + /// /// ///

- /// Note that most objects will choose to receive references to collaborating - /// objects via respective properties. - ///

- ///

- /// For a list of all object lifecycle methods, see the - /// API documentation. + /// Invoked after population of normal object properties but before an init + /// callback like 's + /// + /// method or a custom init-method. ///

///
- /// Juergen Hoeller - /// Rick Evans (.NET) - public interface IObjectNameAware + string ObjectName { - - /// - /// Set the name of the object in the object factory that created this object. - /// - /// - /// The name of the object in the factory. - /// - /// - ///

- /// Invoked after population of normal object properties but before an init - /// callback like 's - /// - /// method or a custom init-method. - ///

- ///
- string ObjectName - { - set; - } - } + set; + } } diff --git a/src/Spring/Spring.Core/Objects/Factory/NoSuchObjectDefinitionException.cs b/src/Spring/Spring.Core/Objects/Factory/NoSuchObjectDefinitionException.cs index f5fcce9c..ededb9d7 100644 --- a/src/Spring/Spring.Core/Objects/Factory/NoSuchObjectDefinitionException.cs +++ b/src/Spring/Spring.Core/Objects/Factory/NoSuchObjectDefinitionException.cs @@ -23,184 +23,183 @@ using System.Runtime.Serialization; using System.Security.Permissions; using Spring.Util; -namespace Spring.Objects.Factory +namespace Spring.Objects.Factory; + +/// +/// Exception thrown when an +/// is asked for an object instance name for which it cannot find a definition. +/// +/// Rod Johnson +/// Rick Evans (.NET) +[Serializable] +public class NoSuchObjectDefinitionException : ObjectsException { - /// - /// Exception thrown when an - /// is asked for an object instance name for which it cannot find a definition. - /// - /// Rod Johnson - /// Rick Evans (.NET) - [Serializable] - public class NoSuchObjectDefinitionException : ObjectsException - { - #region Constructor (s) / Destructor + #region Constructor (s) / Destructor - /// - /// Creates a new instance of the - /// class. - /// - public NoSuchObjectDefinitionException() - { - } + /// + /// Creates a new instance of the + /// class. + /// + public NoSuchObjectDefinitionException() + { + } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - public NoSuchObjectDefinitionException(string message) - : base(message) - { - } + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + public NoSuchObjectDefinitionException(string message) + : base(message) + { + } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception that is being wrapped. - /// - public NoSuchObjectDefinitionException(string message, Exception rootCause) - : base(message, rootCause) - { - } + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception that is being wrapped. + /// + public NoSuchObjectDefinitionException(string message, Exception rootCause) + : base(message, rootCause) + { + } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// Name of the missing object. - /// - /// - /// A further, detailed message describing the problem. - /// - public NoSuchObjectDefinitionException(string name, string message) - : base(string.Format( - CultureInfo.CurrentCulture, - "No object named '{0}' is defined : {1}", - name, - StringUtils.HasText(message) ? message : "not found.")) - { - _objectName = name; - } + /// + /// Creates a new instance of the + /// class. + /// + /// + /// Name of the missing object. + /// + /// + /// A further, detailed message describing the problem. + /// + public NoSuchObjectDefinitionException(string name, string message) + : base(string.Format( + CultureInfo.CurrentCulture, + "No object named '{0}' is defined : {1}", + name, + StringUtils.HasText(message) ? message : "not found.")) + { + _objectName = name; + } - /// - /// Initializes a new instance of the class. - /// - /// The required type of the object. - /// A description of the originating dependency. - /// A message describing the problem. - public NoSuchObjectDefinitionException(Type type, string dependencyDescription, string message) - : base(string.Format( - CultureInfo.CurrentCulture, - "No matching object of type [{0}] found for dependency [{1}]: {2}", - type.FullName, dependencyDescription, message)) + /// + /// Initializes a new instance of the class. + /// + /// The required type of the object. + /// A description of the originating dependency. + /// A message describing the problem. + public NoSuchObjectDefinitionException(Type type, string dependencyDescription, string message) + : base(string.Format( + CultureInfo.CurrentCulture, + "No matching object of type [{0}] found for dependency [{1}]: {2}", + type.FullName, dependencyDescription, message)) - { - _objectType = type; - } + { + _objectType = type; + } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The of the missing object. - /// - /// - /// A further, detailed message describing the problem. - /// - public NoSuchObjectDefinitionException(Type type, string message) - : base(string.Format( - CultureInfo.CurrentCulture, - "No unique object of type [{0}] is defined : {1}", - type != null ? type.FullName : "<< no Type specified >>", - StringUtils.HasText(message) ? message : "not found.")) - { - _objectType = type; - } + /// + /// Creates a new instance of the + /// class. + /// + /// + /// The of the missing object. + /// + /// + /// A further, detailed message describing the problem. + /// + public NoSuchObjectDefinitionException(Type type, string message) + : base(string.Format( + CultureInfo.CurrentCulture, + "No unique object of type [{0}] is defined : {1}", + type != null ? type.FullName : "<< no Type specified >>", + StringUtils.HasText(message) ? message : "not found.")) + { + _objectType = type; + } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The - /// that holds the serialized object data about the exception being thrown. - /// - /// - /// The - /// that contains contextual information about the source or destination. - /// - protected NoSuchObjectDefinitionException(SerializationInfo info, StreamingContext context) - : base(info, context) - { - _objectName = info.GetString("ObjectName"); - var typeName = info.GetString("ObjectTypeName"); - _objectType = typeName != null ? Type.GetType(typeName) : null; - } + /// + /// Creates a new instance of the + /// class. + /// + /// + /// The + /// that holds the serialized object data about the exception being thrown. + /// + /// + /// The + /// that contains contextual information about the source or destination. + /// + protected NoSuchObjectDefinitionException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + _objectName = info.GetString("ObjectName"); + var typeName = info.GetString("ObjectTypeName"); + _objectType = typeName != null ? Type.GetType(typeName) : null; + } - #endregion + #endregion - #region Methods + #region Methods - /// - /// Populates a with - /// the data needed to serialize the target object. - /// - /// - /// The to populate - /// with data. - /// - /// - /// The destination (see ) - /// for this serialization. - /// - [SecurityPermission(SecurityAction.Demand, SerializationFormatter=true)] - public override void GetObjectData( - SerializationInfo info, StreamingContext context) - { - base.GetObjectData(info, context); - info.AddValue("ObjectName", ObjectName); - info.AddValue("ObjectTypeName", ObjectType?.AssemblyQualifiedNameWithoutVersion()); - } + /// + /// Populates a with + /// the data needed to serialize the target object. + /// + /// + /// The to populate + /// with data. + /// + /// + /// The destination (see ) + /// for this serialization. + /// + [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)] + public override void GetObjectData( + SerializationInfo info, StreamingContext context) + { + base.GetObjectData(info, context); + info.AddValue("ObjectName", ObjectName); + info.AddValue("ObjectTypeName", ObjectType?.AssemblyQualifiedNameWithoutVersion()); + } - #endregion + #endregion - #region Properties + #region Properties - /// - /// Return the required of object, if it was a - /// lookup by that failed. - /// - public Type ObjectType - { - get { return _objectType; } - } + /// + /// Return the required of object, if it was a + /// lookup by that failed. + /// + public Type ObjectType + { + get { return _objectType; } + } - /// - /// Return the name of the missing object, if it was a lookup by name that - /// failed. - /// - public string ObjectName - { - get { return _objectName; } - } + /// + /// Return the name of the missing object, if it was a lookup by name that + /// failed. + /// + public string ObjectName + { + get { return _objectName; } + } - #endregion + #endregion - #region Fields + #region Fields - private Type _objectType; - private string _objectName; + private Type _objectType; + private string _objectName; - #endregion - } + #endregion } diff --git a/src/Spring/Spring.Core/Objects/Factory/ObjectCreationException.cs b/src/Spring/Spring.Core/Objects/Factory/ObjectCreationException.cs index 93110101..ec7347b0 100644 --- a/src/Spring/Spring.Core/Objects/Factory/ObjectCreationException.cs +++ b/src/Spring/Spring.Core/Objects/Factory/ObjectCreationException.cs @@ -25,303 +25,303 @@ using System.Text; using Spring.Core; using Spring.Util; -namespace Spring.Objects.Factory +namespace Spring.Objects.Factory; + +/// +/// Thrown when an +/// encounters an error when attempting to create an object from an object +/// definition. +/// +/// Juergen Hoeller +/// Rick Evans (.NET) +[Serializable] +public class ObjectCreationException : FatalObjectException { - /// - /// Thrown when an - /// encounters an error when attempting to create an object from an object - /// definition. - /// - /// Juergen Hoeller - /// Rick Evans (.NET) - [Serializable] - public class ObjectCreationException : FatalObjectException - { - /// - /// Creates a new instance of the - /// class. - /// - public ObjectCreationException() - { - } + /// + /// Creates a new instance of the + /// class. + /// + public ObjectCreationException() + { + } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - public ObjectCreationException(string message) - : base(message) - { - } + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + public ObjectCreationException(string message) + : base(message) + { + } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - /// - /// The name of the object that triggered the exception. - /// - public ObjectCreationException(string objectName, string message) - : this(null, objectName, message, null) - { - } + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + /// + /// The name of the object that triggered the exception. + /// + public ObjectCreationException(string objectName, string message) + : this(null, objectName, message, null) + { + } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception that is being wrapped. - /// - public ObjectCreationException(string message, Exception rootCause) - : base(message, rootCause) + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception that is being wrapped. + /// + public ObjectCreationException(string message, Exception rootCause) + : base(message, rootCause) + { + } + + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + /// + /// The name of the object that triggered the exception. + /// + /// + /// The root exception that is being wrapped. + /// + public ObjectCreationException( + string objectName, string message, Exception rootCause) + : this(null, objectName, message, rootCause) + { + } + + /// + /// Creates a new instance of the + /// class. + /// + /// + /// The description of the resource associated with the object. + /// + /// + /// A message about the exception. + /// + /// + /// The name of the object that triggered the exception. + /// + public ObjectCreationException( + string resourceDescription, + string objectName, + string message) + : this(resourceDescription, objectName, message, null) + { + } + + /// + /// Creates a new instance of the + /// class. + /// + /// + /// The description of the resource associated with the object. + /// + /// + /// A message about the exception. + /// + /// + /// The name of the object that triggered the exception. + /// + /// + /// The root exception that is being wrapped. + /// + public ObjectCreationException( + string resourceDescription, + string objectName, + string message, + Exception rootCause) + : base(message, rootCause) + { + _resourceDescription = resourceDescription; + _objectName = objectName; + } + + /// + /// Creates a new instance of the + /// class. + /// + /// + /// The + /// that holds the serialized object data about the exception being thrown. + /// + /// + /// The + /// that contains contextual information about the source or destination. + /// + protected ObjectCreationException( + SerializationInfo info, StreamingContext context) + : base(info, context) + { + _resourceDescription = (string) info.GetValue("_resourceDescription", typeof(string)); + _objectName = (string) info.GetValue("_objectName", typeof(string)); + _callStack = (string) info.GetValue("_callStack", typeof(string)); + } + + /// + /// Populates a with + /// the data needed to serialize the target object. + /// + /// + /// The to populate + /// with data. + /// + /// + /// The destination (see ) + /// for this serialization. + /// + [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)] + public override void GetObjectData( + SerializationInfo info, StreamingContext context) + { + base.GetObjectData(info, context); + info.AddValue("_resourceDescription", ResourceDescription); + info.AddValue("_objectName", ObjectName); + info.AddValue("_callStack", _callStack); + } + + /// + /// The name of the object that triggered the exception (if any). + /// + public string ObjectName + { + get { return _objectName; } + } + + /// + /// The description of the resource associated with the object (if any). + /// + public string ResourceDescription + { + get { return _resourceDescription; } + } + + /// + /// Describes the creation failure trace of this exception. + /// + public override string Message + { + get { + string message = ObjectCreationException.FormatMessage( + _resourceDescription, + _objectName, + base.Message, + _callStack); + return message; + } + } + + private static string FormatMessage( + string resourceDescription, + string objectName, + string message, + string callStack) + { + if (StringUtils.IsNullOrEmpty(callStack)) + { + return StringUtils.IsNullOrEmpty(resourceDescription) + ? string.Format( + "Error creating object with name '{0}' : {1}", + objectName, + message) + : string.Format( + "Error creating object with name '{0}' defined in '{1}' : {2}", + objectName, + resourceDescription, + message); + } + else + { + return StringUtils.IsNullOrEmpty(resourceDescription) + ? string.Format( + "Error thrown by a dependency of object '{0}' : {1}{2}", + objectName, + message, + callStack) + : string.Format( + "Error thrown by a dependency of object '{0}' defined in '{1}' : {2}{3}", + objectName, + resourceDescription, + message, + callStack); + } + } + + internal static ObjectCreationException GetObjectCreationException( + Exception ex, string objectName, string propertyName, + string resourceDescription, string referenceName) + { + ObjectCreationException ocex = ex as ObjectCreationException; + if (ocex != null) + { + StringBuilder newCause = new StringBuilder(); + newCause.AppendFormat("{0} while resolving '{1}' to '{2}' ", + Environment.NewLine, propertyName, ocex._objectName); + if (StringUtils.HasText(ocex._resourceDescription)) + { + newCause.Append("defined in '") + .Append(ocex._resourceDescription) + .Append("'"); + } + + if (StringUtils.IsNullOrEmpty(ocex._callStack)) + { + ocex._callStack = newCause.ToString(); + } + else + { + ocex._callStack = newCause.Append(ocex._callStack).ToString(); + } + + ocex._objectName = objectName; + ocex._resourceDescription = resourceDescription; + return ocex; + } + else if (ex is PropertyAccessExceptionsException + && ex.InnerException is TypeMismatchException) + { + return new ObjectCreationException( + resourceDescription, + objectName, + string.Format( + CultureInfo.InvariantCulture, + "Invalid type for property '{0}' of object '{1}' in '{2}'.", + propertyName, + objectName, + resourceDescription), + ex); } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - /// - /// The name of the object that triggered the exception. - /// - /// - /// The root exception that is being wrapped. - /// - public ObjectCreationException( - string objectName, string message, Exception rootCause) - : this(null, objectName, message, rootCause) - { - } + return new ObjectCreationException( + resourceDescription, + objectName, + string.Format( + CultureInfo.InvariantCulture, + "Can't resolve reference to object '{0}' while setting '{1}'.", + referenceName, + propertyName), + ex); + } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The description of the resource associated with the object. - /// - /// - /// A message about the exception. - /// - /// - /// The name of the object that triggered the exception. - /// - public ObjectCreationException( - string resourceDescription, - string objectName, - string message) - : this(resourceDescription, objectName, message, null) - { - } - - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The description of the resource associated with the object. - /// - /// - /// A message about the exception. - /// - /// - /// The name of the object that triggered the exception. - /// - /// - /// The root exception that is being wrapped. - /// - public ObjectCreationException( - string resourceDescription, - string objectName, - string message, - Exception rootCause) - : base(message, rootCause) - { - _resourceDescription = resourceDescription; - _objectName = objectName; - } - - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The - /// that holds the serialized object data about the exception being thrown. - /// - /// - /// The - /// that contains contextual information about the source or destination. - /// - protected ObjectCreationException( - SerializationInfo info, StreamingContext context) - : base(info, context) - { - _resourceDescription = (string) info.GetValue("_resourceDescription", typeof (string)); - _objectName = (string) info.GetValue("_objectName", typeof (string)); - _callStack = (string) info.GetValue("_callStack", typeof (string)); - } - - /// - /// Populates a with - /// the data needed to serialize the target object. - /// - /// - /// The to populate - /// with data. - /// - /// - /// The destination (see ) - /// for this serialization. - /// - [SecurityPermission(SecurityAction.Demand, SerializationFormatter=true)] - public override void GetObjectData( - SerializationInfo info, StreamingContext context) - { - base.GetObjectData(info, context); - info.AddValue("_resourceDescription", ResourceDescription); - info.AddValue("_objectName", ObjectName); - info.AddValue("_callStack", _callStack); - } - - /// - /// The name of the object that triggered the exception (if any). - /// - public string ObjectName - { - get { return _objectName; } - } - - /// - /// The description of the resource associated with the object (if any). - /// - public string ResourceDescription - { - get { return _resourceDescription; } - } - - /// - /// Describes the creation failure trace of this exception. - /// - public override string Message - { - get - { - string message = ObjectCreationException.FormatMessage( - _resourceDescription, - _objectName, - base.Message, - _callStack); - return message; - } - } - - private static string FormatMessage( - string resourceDescription, - string objectName, - string message, - string callStack) - { - if (StringUtils.IsNullOrEmpty(callStack)) - { - return StringUtils.IsNullOrEmpty(resourceDescription) ? - string.Format( - "Error creating object with name '{0}' : {1}", - objectName, - message) - : - string.Format( - "Error creating object with name '{0}' defined in '{1}' : {2}", - objectName, - resourceDescription, - message); - } - else - { - return StringUtils.IsNullOrEmpty(resourceDescription) ? - string.Format( - "Error thrown by a dependency of object '{0}' : {1}{2}", - objectName, - message, - callStack) - : - string.Format( - "Error thrown by a dependency of object '{0}' defined in '{1}' : {2}{3}", - objectName, - resourceDescription, - message, - callStack); - } - } - - internal static ObjectCreationException GetObjectCreationException( - Exception ex, string objectName, string propertyName, - string resourceDescription, string referenceName) - { - ObjectCreationException ocex = ex as ObjectCreationException; - if (ocex != null) - { - StringBuilder newCause = new StringBuilder(); - newCause.AppendFormat("{0} while resolving '{1}' to '{2}' ", - Environment.NewLine, propertyName, ocex._objectName); - if (StringUtils.HasText(ocex._resourceDescription)) - { - newCause.Append("defined in '") - .Append(ocex._resourceDescription) - .Append("'"); - } - if (StringUtils.IsNullOrEmpty(ocex._callStack)) - { - ocex._callStack = newCause.ToString(); - } - else - { - ocex._callStack = newCause.Append(ocex._callStack).ToString(); - } - ocex._objectName = objectName; - ocex._resourceDescription = resourceDescription; - return ocex; - } - else if (ex is PropertyAccessExceptionsException - && ex.InnerException is TypeMismatchException) - { - return new ObjectCreationException( - resourceDescription, - objectName, - string.Format( - CultureInfo.InvariantCulture, - "Invalid type for property '{0}' of object '{1}' in '{2}'.", - propertyName, - objectName, - resourceDescription), - ex); - } - return new ObjectCreationException( - resourceDescription, - objectName, - string.Format( - CultureInfo.InvariantCulture, - "Can't resolve reference to object '{0}' while setting '{1}'.", - referenceName, - propertyName), - ex); - } - - private string _callStack; - private string _resourceDescription = string.Empty; - private string _objectName = string.Empty; - } + private string _callStack; + private string _resourceDescription = string.Empty; + private string _objectName = string.Empty; } diff --git a/src/Spring/Spring.Core/Objects/Factory/ObjectCurrentlyInCreationException.cs b/src/Spring/Spring.Core/Objects/Factory/ObjectCurrentlyInCreationException.cs index ebb616ee..60fe21a9 100644 --- a/src/Spring/Spring.Core/Objects/Factory/ObjectCurrentlyInCreationException.cs +++ b/src/Spring/Spring.Core/Objects/Factory/ObjectCurrentlyInCreationException.cs @@ -21,158 +21,157 @@ using System.Runtime.Serialization; using Spring.Util; -namespace Spring.Objects.Factory +namespace Spring.Objects.Factory; + +/// +/// Thrown in case of a reference to an object that is currently in creation. +/// +/// +///

+/// Typically happens when constructor autowiring matches the currently +/// constructed object. +///

+///
+/// Juergen Hoeller +/// Rick Evans +[Serializable] +public class ObjectCurrentlyInCreationException : ObjectCreationException { - /// - /// Thrown in case of a reference to an object that is currently in creation. - /// - /// - ///

- /// Typically happens when constructor autowiring matches the currently - /// constructed object. - ///

- ///
- /// Juergen Hoeller - /// Rick Evans - [Serializable] - public class ObjectCurrentlyInCreationException : ObjectCreationException - { - /// - /// The default error message text to be used, if none is specified. - /// - public const string DEFAULTMESSAGE = "Requested object is currently in creation: Is there an unresolvable circular reference?"; + /// + /// The default error message text to be used, if none is specified. + /// + public const string DEFAULTMESSAGE = "Requested object is currently in creation: Is there an unresolvable circular reference?"; - /// - /// Creates a new instance of the - /// class. - /// - public ObjectCurrentlyInCreationException() - { - } + /// + /// Creates a new instance of the + /// class. + /// + public ObjectCurrentlyInCreationException() + { + } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The name of the object that triggered the exception. - /// - public ObjectCurrentlyInCreationException(string objectName) - : this(null, objectName, null, null) - { - } + /// + /// Creates a new instance of the + /// class. + /// + /// + /// The name of the object that triggered the exception. + /// + public ObjectCurrentlyInCreationException(string objectName) + : this(null, objectName, null, null) + { + } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The name of the object that triggered the exception. - /// - /// - /// The root exception that is being wrapped. - /// - public ObjectCurrentlyInCreationException(string objectName, Exception rootCause) - : this(null, objectName, null, rootCause) - { - } + /// + /// Creates a new instance of the + /// class. + /// + /// + /// The name of the object that triggered the exception. + /// + /// + /// The root exception that is being wrapped. + /// + public ObjectCurrentlyInCreationException(string objectName, Exception rootCause) + : this(null, objectName, null, rootCause) + { + } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - /// - /// The name of the object that triggered the exception. - /// - public ObjectCurrentlyInCreationException(string objectName, string message) - : this(null, objectName, message, null) - { - } + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + /// + /// The name of the object that triggered the exception. + /// + public ObjectCurrentlyInCreationException(string objectName, string message) + : this(null, objectName, message, null) + { + } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - /// - /// The name of the object that triggered the exception. - /// - /// - /// The root exception that is being wrapped. - /// - public ObjectCurrentlyInCreationException(string objectName, string message, Exception rootCause) - : this(null, objectName, message, rootCause) - { - } + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + /// + /// The name of the object that triggered the exception. + /// + /// + /// The root exception that is being wrapped. + /// + public ObjectCurrentlyInCreationException(string objectName, string message, Exception rootCause) + : this(null, objectName, message, rootCause) + { + } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The description of the resource associated with the object. - /// - /// - /// A message about the exception. - /// - /// - /// The name of the object that triggered the exception. - /// - public ObjectCurrentlyInCreationException( - string resourceDescription, - string objectName, - string message) - : this(resourceDescription, objectName, message, null) - { - } + /// + /// Creates a new instance of the + /// class. + /// + /// + /// The description of the resource associated with the object. + /// + /// + /// A message about the exception. + /// + /// + /// The name of the object that triggered the exception. + /// + public ObjectCurrentlyInCreationException( + string resourceDescription, + string objectName, + string message) + : this(resourceDescription, objectName, message, null) + { + } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The description of the resource associated with the object. - /// - /// - /// A message about the exception. - /// - /// - /// The name of the object that triggered the exception. - /// - /// - /// The root exception that is being wrapped. - /// - public ObjectCurrentlyInCreationException( - string resourceDescription, - string objectName, - string message, - Exception rootCause) - : base(resourceDescription, - objectName, - StringUtils.HasText(message) ? message : DEFAULTMESSAGE, - rootCause) - { - } + /// + /// Creates a new instance of the + /// class. + /// + /// + /// The description of the resource associated with the object. + /// + /// + /// A message about the exception. + /// + /// + /// The name of the object that triggered the exception. + /// + /// + /// The root exception that is being wrapped. + /// + public ObjectCurrentlyInCreationException( + string resourceDescription, + string objectName, + string message, + Exception rootCause) + : base(resourceDescription, + objectName, + StringUtils.HasText(message) ? message : DEFAULTMESSAGE, + rootCause) + { + } - /// - /// Creates a new instance of the ObjectCurrentlyInCreationException class. - /// - /// - /// The - /// that holds the serialized object data about the exception being thrown. - /// - /// - /// The - /// that contains contextual information about the source or destination. - /// - protected ObjectCurrentlyInCreationException(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } - } + /// + /// Creates a new instance of the ObjectCurrentlyInCreationException class. + /// + /// + /// The + /// that holds the serialized object data about the exception being thrown. + /// + /// + /// The + /// that contains contextual information about the source or destination. + /// + protected ObjectCurrentlyInCreationException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } } diff --git a/src/Spring/Spring.Core/Objects/Factory/ObjectDefinitionException.cs b/src/Spring/Spring.Core/Objects/Factory/ObjectDefinitionException.cs index 88b3178a..82dee673 100644 --- a/src/Spring/Spring.Core/Objects/Factory/ObjectDefinitionException.cs +++ b/src/Spring/Spring.Core/Objects/Factory/ObjectDefinitionException.cs @@ -22,107 +22,114 @@ using System.Runtime.Serialization; using System.Security.Permissions; using Spring.Objects.Factory.Xml; -namespace Spring.Objects.Factory +namespace Spring.Objects.Factory; + +/// +/// Exception thrown when an +/// encounters an error when attempting to parse an object +/// definition. +/// +/// Federico Spinazzi (.NET) +[Serializable] +public class ObjectDefinitionException : Exception { + #region Fields + + private string _className; + + #endregion + + #region Constructor (s) / Destructor + /// - /// Exception thrown when an - /// encounters an error when attempting to parse an object - /// definition. + /// Creates a new instance of the ObjectDefinitionException class. /// - /// Federico Spinazzi (.NET) - [Serializable] - public class ObjectDefinitionException : Exception + public ObjectDefinitionException() { - #region Fields - private string _className; - #endregion - - #region Constructor (s) / Destructor - /// - /// Creates a new instance of the ObjectDefinitionException class. - /// - public ObjectDefinitionException () - { - } - - /// - /// Creates a new instance of the ObjectDefinitionException class. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception that is being wrapped. - /// - public ObjectDefinitionException (string message, Exception rootCause) - : base (message, rootCause) - { - } - - /// - /// Creates a new instance of the ObjectDefinitionException class. - /// - /// - /// The value of the xml class attribute thet can be resolved - /// as a type - /// - public ObjectDefinitionException (string name) - { - _className = name; - } - - /// - /// Creates a new instance of the ObjectDefinitionException class. - /// - /// - /// The - /// that holds the serialized object data about the exception being thrown. - /// - /// - /// The - /// that contains contextual information about the source or destination. - /// - protected ObjectDefinitionException ( - SerializationInfo info, StreamingContext context) - : base (info, context) - { - _className = info.GetString ("MyClassName"); - } - #endregion - - #region Properties - /// - /// The message about the exception. - /// - public override string Message - { - get - { - return String.Format("The specified name ('{0}') cannot be used to resolve any System.Type instance", _className); - } - } - #endregion - - #region Methods - /// - /// Populates a with - /// the data needed to serialize the target object. - /// - /// - /// The to populate - /// with data. - /// - /// - /// The destination (see ) - /// for this serialization. - /// - [SecurityPermission (SecurityAction.Demand,SerializationFormatter=true)] - public override void GetObjectData ( - SerializationInfo info, StreamingContext context) - { - base.GetObjectData (info, context); - info.AddValue ("MyClassName", _className); - } - #endregion } + + /// + /// Creates a new instance of the ObjectDefinitionException class. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception that is being wrapped. + /// + public ObjectDefinitionException(string message, Exception rootCause) + : base(message, rootCause) + { + } + + /// + /// Creates a new instance of the ObjectDefinitionException class. + /// + /// + /// The value of the xml class attribute thet can be resolved + /// as a type + /// + public ObjectDefinitionException(string name) + { + _className = name; + } + + /// + /// Creates a new instance of the ObjectDefinitionException class. + /// + /// + /// The + /// that holds the serialized object data about the exception being thrown. + /// + /// + /// The + /// that contains contextual information about the source or destination. + /// + protected ObjectDefinitionException( + SerializationInfo info, StreamingContext context) + : base(info, context) + { + _className = info.GetString("MyClassName"); + } + + #endregion + + #region Properties + + /// + /// The message about the exception. + /// + public override string Message + { + get + { + return String.Format("The specified name ('{0}') cannot be used to resolve any System.Type instance", _className); + } + } + + #endregion + + #region Methods + + /// + /// Populates a with + /// the data needed to serialize the target object. + /// + /// + /// The to populate + /// with data. + /// + /// + /// The destination (see ) + /// for this serialization. + /// + [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)] + public override void GetObjectData( + SerializationInfo info, StreamingContext context) + { + base.GetObjectData(info, context); + info.AddValue("MyClassName", _className); + } + + #endregion } diff --git a/src/Spring/Spring.Core/Objects/Factory/ObjectDefinitionStoreException.cs b/src/Spring/Spring.Core/Objects/Factory/ObjectDefinitionStoreException.cs index cb496b25..e8156bc4 100644 --- a/src/Spring/Spring.Core/Objects/Factory/ObjectDefinitionStoreException.cs +++ b/src/Spring/Spring.Core/Objects/Factory/ObjectDefinitionStoreException.cs @@ -22,233 +22,232 @@ using System.Runtime.Serialization; using System.Security.Permissions; using Spring.Core.IO; -namespace Spring.Objects.Factory +namespace Spring.Objects.Factory; + +/// +/// Thrown when an +/// encounters an internal error, and its definitions are invalid. +/// +/// +///

+/// An example of a situation when this exception would be thrown is +/// in the case of an XML document containing object definitions being +/// malformed. +///

+///
+/// Rod Johnson +/// Juergen Hoeller +/// Rick Evans (.NET) +[Serializable] +public class ObjectDefinitionStoreException : FatalObjectException { /// - /// Thrown when an - /// encounters an internal error, and its definitions are invalid. + /// Creates a new instance of the ObjectDefinitionStoreException class. /// - /// - ///

- /// An example of a situation when this exception would be thrown is - /// in the case of an XML document containing object definitions being - /// malformed. - ///

- ///
- /// Rod Johnson - /// Juergen Hoeller - /// Rick Evans (.NET) - [Serializable] - public class ObjectDefinitionStoreException : FatalObjectException + public ObjectDefinitionStoreException() { - /// - /// Creates a new instance of the ObjectDefinitionStoreException class. - /// - public ObjectDefinitionStoreException() - { - } - - /// - /// Creates a new instance of the ObjectDefinitionStoreException class. - /// - /// - /// A message about the exception. - /// - public ObjectDefinitionStoreException(string message) - : base(message) - { - } - - /// - /// Creates a new instance of the ObjectDefinitionStoreException class. - /// - /// - /// The description of the resource that the object definition came from - /// - /// - /// The name of the object that triggered the exception. - /// - /// - /// A message about the exception. - /// - public ObjectDefinitionStoreException( - string resourceDescription, string name, string message) - : this(resourceDescription, name, message, null) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// - /// The description of the resource that the object definition came from - /// - /// The detail message (used as exception message as-is) - /// The root cause. (may be null - public ObjectDefinitionStoreException(string resourceDescription, string msg, Exception cause) - : this(msg, cause) - { - _resourceDescription = resourceDescription; - } - - /// - /// Creates a new instance of the ObjectDefinitionStoreException class. - /// - /// - /// The resource location (e.g. an XML object definition file) associated - /// with the offending object definition. - /// - /// - /// A message about the exception. - /// - /// - /// The name of the object that triggered the exception. - /// - public ObjectDefinitionStoreException( - IResource resourceLocation, - string name, - string message) - : this - (resourceLocation == null ? string.Empty : resourceLocation.Description, - name, message) - { - } - - /// - /// Creates a new instance of the ObjectDefinitionStoreException class. - /// - /// - /// The resource location (e.g. an XML object definition file) associated - /// with the offending object definition. - /// - /// - /// A message about the exception. - /// - /// - /// The name of the object that triggered the exception. - /// - /// - /// The root exception that is being wrapped. - /// - public ObjectDefinitionStoreException( - IResource resourceLocation, - string name, - string message, - Exception rootCause) - : this((resourceLocation == null ? string.Empty : resourceLocation.Description), name, message, rootCause) - { - } - - /// - /// Creates a new instance of the ObjectDefinitionStoreException class. - /// - /// - /// The description of the resource that the object definition came from - /// - /// - /// A message about the exception. - /// - /// - /// The name of the object that triggered the exception. - /// - /// - /// The root exception that is being wrapped. - /// - public ObjectDefinitionStoreException( - string resourceDescription, - string name, - string message, - Exception rootCause) - : base( - string.Format( - "Error registering object {0}defined in '{1}' : {2}", - name == null ? string.Empty : string.Format("with name '{0}' ", name), - resourceDescription, - message), - rootCause) - { - _resourceDescription = resourceDescription; - _objectName = name; - } - - /// - /// Creates a new instance of the ObjectDefinitionStoreException class. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception that is being wrapped. - /// - public ObjectDefinitionStoreException(string message, Exception rootCause) - : base(message, rootCause) - { - } - - /// - /// Creates a new instance of the ObjectDefinitionStoreException class. - /// - /// - /// The - /// that holds the serialized object data about the exception being thrown. - /// - /// - /// The - /// that contains contextual information about the source or destination. - /// - protected ObjectDefinitionStoreException( - SerializationInfo info, StreamingContext context) - : base(info, context) - { - _resourceDescription = info.GetValue("_resourceDescription", typeof(object)) as string; - _objectName = info.GetValue("_objectName", typeof(object)) as string; - } - - /// - /// Populates a with - /// the data needed to serialize the target object. - /// - /// - /// The to populate - /// with data. - /// - /// - /// The destination (see ) - /// for this serialization. - /// - [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)] - public override void GetObjectData( - SerializationInfo info, StreamingContext context) - { - base.GetObjectData(info, context); - info.AddValue("_resourceDescription", ResourceDescription); - info.AddValue("_objectName", ObjectName); - } - - /// - /// The name of the object that triggered the exception (if any). - /// - public string ObjectName - { - get { return _objectName; } - } - - /// - /// The description of the resource associated with the object (if any). - /// - public string ResourceDescription - { - get { return _resourceDescription; } - } - - /// - /// The description of the resource associated with the object - /// - private readonly string _resourceDescription = string.Empty; - - /// - /// The name of the object that trigger the exception. - /// - private readonly string _objectName = string.Empty; } -} + + /// + /// Creates a new instance of the ObjectDefinitionStoreException class. + /// + /// + /// A message about the exception. + /// + public ObjectDefinitionStoreException(string message) + : base(message) + { + } + + /// + /// Creates a new instance of the ObjectDefinitionStoreException class. + /// + /// + /// The description of the resource that the object definition came from + /// + /// + /// The name of the object that triggered the exception. + /// + /// + /// A message about the exception. + /// + public ObjectDefinitionStoreException( + string resourceDescription, string name, string message) + : this(resourceDescription, name, message, null) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The description of the resource that the object definition came from + /// + /// The detail message (used as exception message as-is) + /// The root cause. (may be null + public ObjectDefinitionStoreException(string resourceDescription, string msg, Exception cause) + : this(msg, cause) + { + _resourceDescription = resourceDescription; + } + + /// + /// Creates a new instance of the ObjectDefinitionStoreException class. + /// + /// + /// The resource location (e.g. an XML object definition file) associated + /// with the offending object definition. + /// + /// + /// A message about the exception. + /// + /// + /// The name of the object that triggered the exception. + /// + public ObjectDefinitionStoreException( + IResource resourceLocation, + string name, + string message) + : this + (resourceLocation == null ? string.Empty : resourceLocation.Description, + name, message) + { + } + + /// + /// Creates a new instance of the ObjectDefinitionStoreException class. + /// + /// + /// The resource location (e.g. an XML object definition file) associated + /// with the offending object definition. + /// + /// + /// A message about the exception. + /// + /// + /// The name of the object that triggered the exception. + /// + /// + /// The root exception that is being wrapped. + /// + public ObjectDefinitionStoreException( + IResource resourceLocation, + string name, + string message, + Exception rootCause) + : this((resourceLocation == null ? string.Empty : resourceLocation.Description), name, message, rootCause) + { + } + + /// + /// Creates a new instance of the ObjectDefinitionStoreException class. + /// + /// + /// The description of the resource that the object definition came from + /// + /// + /// A message about the exception. + /// + /// + /// The name of the object that triggered the exception. + /// + /// + /// The root exception that is being wrapped. + /// + public ObjectDefinitionStoreException( + string resourceDescription, + string name, + string message, + Exception rootCause) + : base( + string.Format( + "Error registering object {0}defined in '{1}' : {2}", + name == null ? string.Empty : string.Format("with name '{0}' ", name), + resourceDescription, + message), + rootCause) + { + _resourceDescription = resourceDescription; + _objectName = name; + } + + /// + /// Creates a new instance of the ObjectDefinitionStoreException class. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception that is being wrapped. + /// + public ObjectDefinitionStoreException(string message, Exception rootCause) + : base(message, rootCause) + { + } + + /// + /// Creates a new instance of the ObjectDefinitionStoreException class. + /// + /// + /// The + /// that holds the serialized object data about the exception being thrown. + /// + /// + /// The + /// that contains contextual information about the source or destination. + /// + protected ObjectDefinitionStoreException( + SerializationInfo info, StreamingContext context) + : base(info, context) + { + _resourceDescription = info.GetValue("_resourceDescription", typeof(object)) as string; + _objectName = info.GetValue("_objectName", typeof(object)) as string; + } + + /// + /// Populates a with + /// the data needed to serialize the target object. + /// + /// + /// The to populate + /// with data. + /// + /// + /// The destination (see ) + /// for this serialization. + /// + [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)] + public override void GetObjectData( + SerializationInfo info, StreamingContext context) + { + base.GetObjectData(info, context); + info.AddValue("_resourceDescription", ResourceDescription); + info.AddValue("_objectName", ObjectName); + } + + /// + /// The name of the object that triggered the exception (if any). + /// + public string ObjectName + { + get { return _objectName; } + } + + /// + /// The description of the resource associated with the object (if any). + /// + public string ResourceDescription + { + get { return _resourceDescription; } + } + + /// + /// The description of the resource associated with the object + /// + private readonly string _resourceDescription = string.Empty; + + /// + /// The name of the object that trigger the exception. + /// + private readonly string _objectName = string.Empty; +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Objects/Factory/ObjectFactoryUtils.cs b/src/Spring/Spring.Core/Objects/Factory/ObjectFactoryUtils.cs index 2c51ae2f..8386d55f 100644 --- a/src/Spring/Spring.Core/Objects/Factory/ObjectFactoryUtils.cs +++ b/src/Spring/Spring.Core/Objects/Factory/ObjectFactoryUtils.cs @@ -21,420 +21,422 @@ using System.Runtime.CompilerServices; using Spring.Util; -namespace Spring.Objects.Factory +namespace Spring.Objects.Factory; + +/// +/// Convenience methods operating on object factories, returning object instances, +/// names, or counts. +/// +/// +///

+/// The nesting hierarchy of an object factory is taken into account by the various methods +/// exposed by this class. +///

+///
+/// Rod Johnson +/// Juergen Hoeller +/// Rick Evans (.NET) +public sealed class ObjectFactoryUtils { + // CLOVER:OFF + /// - /// Convenience methods operating on object factories, returning object instances, - /// names, or counts. + /// Creates a new instance of the + /// class. /// /// ///

- /// The nesting hierarchy of an object factory is taken into account by the various methods - /// exposed by this class. + /// This is a utility class, and as such has no publicly visible + /// constructors. ///

///
- /// Rod Johnson - /// Juergen Hoeller - /// Rick Evans (.NET) - public sealed class ObjectFactoryUtils + private ObjectFactoryUtils() { - // CLOVER:OFF + } - /// - /// Creates a new instance of the - /// class. - /// - /// - ///

- /// This is a utility class, and as such has no publicly visible - /// constructors. - ///

- ///
- private ObjectFactoryUtils() + // CLOVER:ON + + /// + /// Used to dereference an + /// and distinguish it from managed objects created by the factory. + /// + /// + ///

+ /// For example, if the managed object identified as foo is a + /// factory, getting &foo will return the factory, not the + /// instance returned by the factory. + ///

+ ///
+ public const string FactoryObjectPrefix = "&"; + + /// + /// The string used as a separator in the generation of synthetic id's + /// for those object definitions explicitly that aren't assigned one. + /// + /// + ///

+ /// If a name or parent object definition + /// name is not unique, "#1", "#2" etc will be appended, until such + /// time that the name becomes unique. + ///

+ ///
+ public const string GeneratedObjectNameSeparator = "#"; + + /// + /// Count all object definitions in any hierarchy in which this + /// factory participates. + /// + /// + ///

+ /// Includes counts of ancestor object factories. + ///

+ ///

+ /// Objects that are "overridden" (specified in a descendant factory + /// with the same name) are counted only once. + ///

+ ///
+ /// The object factory. + /// + /// The count of objects including those defined in ancestor factories. + /// + public static int CountObjectsIncludingAncestors(IListableObjectFactory factory) + { + return ObjectNamesIncludingAncestors(factory).Count; + } + + /// + /// Return all object names in the factory, including ancestor factories. + /// + /// The object factory. + /// The array of object names, or an empty array if none. + public static IReadOnlyList ObjectNamesIncludingAncestors(IListableObjectFactory factory) + { + return ObjectNamesForTypeIncludingAncestors(factory, typeof(object)); + } + + /// + /// Get all object names for the given type, including those defined in ancestor + /// factories. + /// + /// + ///

+ /// Will return unique names in case of overridden object definitions. + ///

+ ///

+ /// Does consider objects created by s + /// if is set to true, + /// which means that s will get initialized. + ///

+ ///
+ /// + /// If this isn't also an + /// , + /// this method will return the same as it's own + /// + /// method. + /// + /// + /// The that objects must match. + /// + /// + /// Whether to include prototype objects too or just singletons + /// (also applies to instances). + /// + /// + /// Whether to include instances + /// too or just normal objects. + /// + /// + /// The array of object names, or an empty array if none. + /// + public static List ObjectNamesForTypeIncludingAncestors( + IListableObjectFactory factory, Type type, + bool includePrototypes, bool includeFactoryObjects) + { + List result = new List(); + result.AddRange(factory.GetObjectNamesForType(type, includePrototypes, includeFactoryObjects)); + IListableObjectFactory pof = GetParentListableObjectFactoryIfAny(factory); + if (pof != null) { - } - - // CLOVER:ON - - /// - /// Used to dereference an - /// and distinguish it from managed objects created by the factory. - /// - /// - ///

- /// For example, if the managed object identified as foo is a - /// factory, getting &foo will return the factory, not the - /// instance returned by the factory. - ///

- ///
- public const string FactoryObjectPrefix = "&"; - - /// - /// The string used as a separator in the generation of synthetic id's - /// for those object definitions explicitly that aren't assigned one. - /// - /// - ///

- /// If a name or parent object definition - /// name is not unique, "#1", "#2" etc will be appended, until such - /// time that the name becomes unique. - ///

- ///
- public const string GeneratedObjectNameSeparator = "#"; - - /// - /// Count all object definitions in any hierarchy in which this - /// factory participates. - /// - /// - ///

- /// Includes counts of ancestor object factories. - ///

- ///

- /// Objects that are "overridden" (specified in a descendant factory - /// with the same name) are counted only once. - ///

- ///
- /// The object factory. - /// - /// The count of objects including those defined in ancestor factories. - /// - public static int CountObjectsIncludingAncestors(IListableObjectFactory factory) - { - return ObjectNamesIncludingAncestors(factory).Count; - } - - /// - /// Return all object names in the factory, including ancestor factories. - /// - /// The object factory. - /// The array of object names, or an empty array if none. - public static IReadOnlyList ObjectNamesIncludingAncestors(IListableObjectFactory factory) - { - return ObjectNamesForTypeIncludingAncestors(factory, typeof(object)); - } - - /// - /// Get all object names for the given type, including those defined in ancestor - /// factories. - /// - /// - ///

- /// Will return unique names in case of overridden object definitions. - ///

- ///

- /// Does consider objects created by s - /// if is set to true, - /// which means that s will get initialized. - ///

- ///
- /// - /// If this isn't also an - /// , - /// this method will return the same as it's own - /// - /// method. - /// - /// - /// The that objects must match. - /// - /// - /// Whether to include prototype objects too or just singletons - /// (also applies to instances). - /// - /// - /// Whether to include instances - /// too or just normal objects. - /// - /// - /// The array of object names, or an empty array if none. - /// - public static List ObjectNamesForTypeIncludingAncestors( - IListableObjectFactory factory, Type type, - bool includePrototypes, bool includeFactoryObjects) - { - List result = new List(); - result.AddRange(factory.GetObjectNamesForType(type, includePrototypes, includeFactoryObjects)); - IListableObjectFactory pof = GetParentListableObjectFactoryIfAny(factory); - if (pof != null) + IHierarchicalObjectFactory hof = (IHierarchicalObjectFactory) factory; + IList parentsResult = ObjectNamesForTypeIncludingAncestors(pof, type, includePrototypes, includeFactoryObjects); + foreach (string objectName in parentsResult) { - IHierarchicalObjectFactory hof = (IHierarchicalObjectFactory)factory; - IList parentsResult = ObjectNamesForTypeIncludingAncestors(pof, type, includePrototypes, includeFactoryObjects); - foreach (string objectName in parentsResult) + if (!result.Contains(objectName) && !hof.ContainsLocalObject(objectName)) { - if (!result.Contains(objectName) && !hof.ContainsLocalObject(objectName)) - { - result.Add(objectName); - } + result.Add(objectName); } } - return result; } - /// - /// Get all object names for the given type, including those defined in ancestor - /// factories. - /// - /// - ///

- /// Will return unique names in case of overridden object definitions. - ///

- ///

- /// Does consider objects created by s, - /// or rather it considers the type of objects created by - /// (which means that - /// s will be instantiated). - ///

- ///
- /// - /// If this isn't also an , - /// this method will return the same as it's own method. - /// - /// - /// The that objects must match. - /// - /// - /// The array of object names, or an empty array if none. - /// - public static IReadOnlyList ObjectNamesForTypeIncludingAncestors(IListableObjectFactory factory, Type type) + return result; + } + + /// + /// Get all object names for the given type, including those defined in ancestor + /// factories. + /// + /// + ///

+ /// Will return unique names in case of overridden object definitions. + ///

+ ///

+ /// Does consider objects created by s, + /// or rather it considers the type of objects created by + /// (which means that + /// s will be instantiated). + ///

+ ///
+ /// + /// If this isn't also an , + /// this method will return the same as it's own method. + /// + /// + /// The that objects must match. + /// + /// + /// The array of object names, or an empty array if none. + /// + public static IReadOnlyList ObjectNamesForTypeIncludingAncestors(IListableObjectFactory factory, Type type) + { + return factory.GetObjectNamesForType(type); + } + + /// + /// Return all objects of the given type or subtypes, also picking up objects + /// defined in ancestor object factories if the current object factory is an + /// . + /// + /// + ///

+ /// The return list will only contain objects of this type. + /// Useful convenience method when we don't care about object names. + ///

+ ///
+ /// The object factory. + /// The of object to match. + /// + /// Whether to include prototype objects too or just singletons + /// (also applies to instances). + /// + /// + /// Whether to include instances + /// too or just normal objects. + /// + /// + /// If the objects could not be created. + /// + /// + /// The of object instances, or an + /// empty if none. + /// + public static Dictionary ObjectsOfTypeIncludingAncestors( + IListableObjectFactory factory, Type type, + bool includePrototypes, bool includeFactoryObjects) + { + Dictionary result = new Dictionary(); + foreach (var entry in factory.GetObjectsOfType(type, includePrototypes, includeFactoryObjects)) { - return factory.GetObjectNamesForType(type); + result.Add(entry.Key, entry.Value); } - /// - /// Return all objects of the given type or subtypes, also picking up objects - /// defined in ancestor object factories if the current object factory is an - /// . - /// - /// - ///

- /// The return list will only contain objects of this type. - /// Useful convenience method when we don't care about object names. - ///

- ///
- /// The object factory. - /// The of object to match. - /// - /// Whether to include prototype objects too or just singletons - /// (also applies to instances). - /// - /// - /// Whether to include instances - /// too or just normal objects. - /// - /// - /// If the objects could not be created. - /// - /// - /// The of object instances, or an - /// empty if none. - /// - public static Dictionary ObjectsOfTypeIncludingAncestors( - IListableObjectFactory factory, Type type, - bool includePrototypes, bool includeFactoryObjects) + IListableObjectFactory pof = GetParentListableObjectFactoryIfAny(factory); + if (pof != null) { - Dictionary result = new Dictionary(); - foreach (var entry in factory.GetObjectsOfType(type, includePrototypes, includeFactoryObjects)) + IHierarchicalObjectFactory hof = (IHierarchicalObjectFactory) factory; + Dictionary parentResult = ObjectsOfTypeIncludingAncestors(pof, type, includePrototypes, includeFactoryObjects); + foreach (string objectName in parentResult.Keys) { - result.Add(entry.Key, entry.Value); - } - - IListableObjectFactory pof = GetParentListableObjectFactoryIfAny(factory); - if (pof != null) - { - IHierarchicalObjectFactory hof = (IHierarchicalObjectFactory)factory; - Dictionary parentResult = ObjectsOfTypeIncludingAncestors(pof, type, includePrototypes, includeFactoryObjects); - foreach (string objectName in parentResult.Keys) + if (!result.ContainsKey(objectName) && !hof.ContainsLocalObject(objectName)) { - if (!result.ContainsKey(objectName) && !hof.ContainsLocalObject(objectName)) - { - result.Add(objectName, parentResult[objectName]); - } + result.Add(objectName, parentResult[objectName]); } } - return result; } - /// - /// Return a single object of the given type or subtypes, also picking up objects defined - /// in ancestor object factories if the current object factory is an - /// . - /// - /// - ///

- /// Useful convenience method when we expect a single object and don't care - /// about the object name. - ///

- ///
- /// The object factory. - /// The of object to match. - /// - /// Whether to include prototype objects too or just singletons - /// (also applies to instances). - /// - /// - /// Whether to include instances - /// too or just normal objects. - /// - /// - /// If the object could not be created. - /// - /// - /// If more than one instance of an object was found. - /// - /// - /// A single object of the given type or subtypes. - /// - public static object ObjectOfTypeIncludingAncestors( - IListableObjectFactory factory, Type type, - bool includePrototypes, bool includeFactoryObjects) + return result; + } + + /// + /// Return a single object of the given type or subtypes, also picking up objects defined + /// in ancestor object factories if the current object factory is an + /// . + /// + /// + ///

+ /// Useful convenience method when we expect a single object and don't care + /// about the object name. + ///

+ ///
+ /// The object factory. + /// The of object to match. + /// + /// Whether to include prototype objects too or just singletons + /// (also applies to instances). + /// + /// + /// Whether to include instances + /// too or just normal objects. + /// + /// + /// If the object could not be created. + /// + /// + /// If more than one instance of an object was found. + /// + /// + /// A single object of the given type or subtypes. + /// + public static object ObjectOfTypeIncludingAncestors( + IListableObjectFactory factory, Type type, + bool includePrototypes, bool includeFactoryObjects) + { + var objectsOfType = ObjectsOfTypeIncludingAncestors(factory, type, includePrototypes, includeFactoryObjects); + return GrabTheOnlyObject(objectsOfType, type); + } + + /// + /// Return a single object of the given type or subtypes, not looking in + /// ancestor factories. + /// + /// + ///

+ /// Useful convenience method when we expect a single object and don't care + /// about the object name. + ///

+ ///
+ /// The object factory. + /// The of object to match. + /// + /// Whether to include prototype objects too or just singletons + /// (also applies to instances). + /// + /// + /// Whether to include instances + /// too or just normal objects. + /// + /// + /// If the object could not be created. + /// + /// + /// If not exactly one instance of an object was found. + /// + /// + /// A single object of the given type or subtypes. + /// + public static object ObjectOfType(IListableObjectFactory factory, Type type, + bool includePrototypes, bool includeFactoryObjects) + { + var objectsOfType = factory.GetObjectsOfType(type, includePrototypes, includeFactoryObjects); + return GrabTheOnlyObject(objectsOfType, type); + } + + /// + /// Return a single object of the given type or subtypes, not looking in + /// ancestor factories. + /// + /// + ///

+ /// Useful convenience method when we expect a single object and don't care + /// about the object name. + /// This version of ObjectOfType automatically includes prototypes and + /// instances. + ///

+ ///
+ /// The object factory. + /// The of object to match. + /// + /// If the object could not be created. + /// + /// + /// If not exactly one instance of an object was found. + /// + /// + /// A single object of the given type or subtypes. + /// + public static object ObjectOfType(IListableObjectFactory factory, Type type) + { + return ObjectOfType(factory, type, true, true); + } + + /// + /// Return the object name, stripping out the factory dereference prefix if necessary. + /// + /// The name of the object. + /// The object name sans any factory dereference prefix. + public static string TransformedObjectName(string name) + { + AssertUtils.ArgumentNotNull(name, "name", "Object name must not be null."); + if (!IsFactoryDereference(name)) { - var objectsOfType = ObjectsOfTypeIncludingAncestors(factory, type, includePrototypes, includeFactoryObjects); - return GrabTheOnlyObject(objectsOfType, type); + return name; } - /// - /// Return a single object of the given type or subtypes, not looking in - /// ancestor factories. - /// - /// - ///

- /// Useful convenience method when we expect a single object and don't care - /// about the object name. - ///

- ///
- /// The object factory. - /// The of object to match. - /// - /// Whether to include prototype objects too or just singletons - /// (also applies to instances). - /// - /// - /// Whether to include instances - /// too or just normal objects. - /// - /// - /// If the object could not be created. - /// - /// - /// If not exactly one instance of an object was found. - /// - /// - /// A single object of the given type or subtypes. - /// - public static object ObjectOfType(IListableObjectFactory factory, Type type, - bool includePrototypes, bool includeFactoryObjects) + string objectName = name.Substring(FactoryObjectPrefix.Length); + return objectName; + } + + /// + /// Given an (object) name, builds a corresponding factory object name such that + /// the return value can be used as a lookup name for a factory object. + /// + /// + /// The name to be used to build the resulting factory object name. + /// + /// + /// The transformed into its factory object name + /// equivalent. + /// + /// + /// + public static string BuildFactoryObjectName(string objectName) + { + return FactoryObjectPrefix + objectName; + } + + /// + /// Is the supplied a factory dereference? + /// + /// + ///

+ /// That is, does the supplied begin with + /// the + /// ? + ///

+ ///
+ /// The name to check. + /// + /// if the supplied is a + /// factory dereference; if not, or the + /// aupplied is or + /// consists solely of the + /// + /// value. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool IsFactoryDereference(string name) + { + return name != null && name.Length > 1 && name[0] == '&'; + } + + private static IListableObjectFactory GetParentListableObjectFactoryIfAny(IListableObjectFactory factory) + { + if (factory is IHierarchicalObjectFactory hierFactory) { - var objectsOfType = factory.GetObjectsOfType(type, includePrototypes, includeFactoryObjects); - return GrabTheOnlyObject(objectsOfType, type); + return hierFactory.ParentObjectFactory as IListableObjectFactory; } - /// - /// Return a single object of the given type or subtypes, not looking in - /// ancestor factories. - /// - /// - ///

- /// Useful convenience method when we expect a single object and don't care - /// about the object name. - /// This version of ObjectOfType automatically includes prototypes and - /// instances. - ///

- ///
- /// The object factory. - /// The of object to match. - /// - /// If the object could not be created. - /// - /// - /// If not exactly one instance of an object was found. - /// - /// - /// A single object of the given type or subtypes. - /// - public static object ObjectOfType(IListableObjectFactory factory, Type type) + return null; + } + + private static object GrabTheOnlyObject(IReadOnlyDictionary objectsOfType, Type type) + { + if (objectsOfType.Count == 1) { - return ObjectOfType(factory, type, true, true); + return ObjectUtils.EnumerateFirstElement(objectsOfType.Values); } - /// - /// Return the object name, stripping out the factory dereference prefix if necessary. - /// - /// The name of the object. - /// The object name sans any factory dereference prefix. - public static string TransformedObjectName(string name) - { - AssertUtils.ArgumentNotNull(name, "name", "Object name must not be null."); - if (!IsFactoryDereference(name)) - { - return name; - } - - string objectName = name.Substring(FactoryObjectPrefix.Length); - return objectName; - } - - /// - /// Given an (object) name, builds a corresponding factory object name such that - /// the return value can be used as a lookup name for a factory object. - /// - /// - /// The name to be used to build the resulting factory object name. - /// - /// - /// The transformed into its factory object name - /// equivalent. - /// - /// - /// - public static string BuildFactoryObjectName(string objectName) - { - return FactoryObjectPrefix + objectName; - } - - /// - /// Is the supplied a factory dereference? - /// - /// - ///

- /// That is, does the supplied begin with - /// the - /// ? - ///

- ///
- /// The name to check. - /// - /// if the supplied is a - /// factory dereference; if not, or the - /// aupplied is or - /// consists solely of the - /// - /// value. - /// - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool IsFactoryDereference(string name) - { - return name != null && name.Length > 1 && name[0] == '&'; - } - - private static IListableObjectFactory GetParentListableObjectFactoryIfAny(IListableObjectFactory factory) - { - if (factory is IHierarchicalObjectFactory hierFactory) - { - return hierFactory.ParentObjectFactory as IListableObjectFactory; - } - return null; - } - - private static object GrabTheOnlyObject(IReadOnlyDictionary objectsOfType, Type type) - { - if (objectsOfType.Count == 1) - { - return ObjectUtils.EnumerateFirstElement(objectsOfType.Values); - } - - throw new NoSuchObjectDefinitionException(type, "Expected single object but found " + objectsOfType.Count); - } + throw new NoSuchObjectDefinitionException(type, "Expected single object but found " + objectsOfType.Count); } } diff --git a/src/Spring/Spring.Core/Objects/Factory/ObjectInitializationException.cs b/src/Spring/Spring.Core/Objects/Factory/ObjectInitializationException.cs index 8a16517e..b88eb7be 100644 --- a/src/Spring/Spring.Core/Objects/Factory/ObjectInitializationException.cs +++ b/src/Spring/Spring.Core/Objects/Factory/ObjectInitializationException.cs @@ -20,74 +20,75 @@ using System.Runtime.Serialization; -namespace Spring.Objects.Factory +namespace Spring.Objects.Factory; + +/// +/// Exception that an object implementation is suggested to throw if its own +/// factory-aware initialization code fails. +/// thrown by object factory methods +/// themselves should simply be propagated as-is. +/// +/// +///

+/// Note that non-factory-aware initialization methods like AfterPropertiesSet () +/// or a custom "init-method" can throw any exception. +///

+///
+/// Juergen Hoeller +/// Rick Evans (.NET) +[Serializable] +public class ObjectInitializationException : FatalObjectException { + #region Constructor (s) / Destructor + /// - /// Exception that an object implementation is suggested to throw if its own - /// factory-aware initialization code fails. - /// thrown by object factory methods - /// themselves should simply be propagated as-is. + /// Creates a new instance of the ObjectInitializationException class. /// - /// - ///

- /// Note that non-factory-aware initialization methods like AfterPropertiesSet () - /// or a custom "init-method" can throw any exception. - ///

- ///
- /// Juergen Hoeller - /// Rick Evans (.NET) - [Serializable] - public class ObjectInitializationException : FatalObjectException + public ObjectInitializationException() { - #region Constructor (s) / Destructor - /// - /// Creates a new instance of the ObjectInitializationException class. - /// - public ObjectInitializationException () - { - } - - /// - /// Creates a new instance of the ObjectInitializationException class. - /// - /// - /// A message about the exception. - /// - public ObjectInitializationException (string message) - : base (message) - { - } - - /// - /// Creates a new instance of the ObjectInitializationException class. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception that is being wrapped. - /// - public ObjectInitializationException (string message, Exception rootCause) - : base (message, rootCause) - { - } - - /// - /// Creates a new instance of the ObjectInitializationException class. - /// - /// - /// The - /// that holds the serialized object data about the exception being thrown. - /// - /// - /// The - /// that contains contextual information about the source or destination. - /// - protected ObjectInitializationException ( - SerializationInfo info, StreamingContext context) - : base (info, context) - { - } - #endregion } + + /// + /// Creates a new instance of the ObjectInitializationException class. + /// + /// + /// A message about the exception. + /// + public ObjectInitializationException(string message) + : base(message) + { + } + + /// + /// Creates a new instance of the ObjectInitializationException class. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception that is being wrapped. + /// + public ObjectInitializationException(string message, Exception rootCause) + : base(message, rootCause) + { + } + + /// + /// Creates a new instance of the ObjectInitializationException class. + /// + /// + /// The + /// that holds the serialized object data about the exception being thrown. + /// + /// + /// The + /// that contains contextual information about the source or destination. + /// + protected ObjectInitializationException( + SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + + #endregion } diff --git a/src/Spring/Spring.Core/Objects/Factory/ObjectIsNotAFactoryException.cs b/src/Spring/Spring.Core/Objects/Factory/ObjectIsNotAFactoryException.cs index 4a2b0a22..d7e53681 100644 --- a/src/Spring/Spring.Core/Objects/Factory/ObjectIsNotAFactoryException.cs +++ b/src/Spring/Spring.Core/Objects/Factory/ObjectIsNotAFactoryException.cs @@ -20,90 +20,89 @@ using System.Runtime.Serialization; -namespace Spring.Objects.Factory +namespace Spring.Objects.Factory; + +/// +/// Thrown in response to an attempt to lookup a factory object, and +/// the object identified by the lookup key is not a factory. +/// +/// +///

+/// An object is a factory if it implements (either directly or indirectly +/// via inheritance) the +/// interface. +///

+///
+/// Rod Johnson +/// Rick Evans (.NET) +[Serializable] +public class ObjectIsNotAFactoryException : ObjectNotOfRequiredTypeException { /// - /// Thrown in response to an attempt to lookup a factory object, and - /// the object identified by the lookup key is not a factory. + /// Creates a new instance of the + /// class. /// - /// - ///

- /// An object is a factory if it implements (either directly or indirectly - /// via inheritance) the - /// interface. - ///

- ///
- /// Rod Johnson - /// Rick Evans (.NET) - [Serializable] - public class ObjectIsNotAFactoryException : ObjectNotOfRequiredTypeException + public ObjectIsNotAFactoryException() { - /// - /// Creates a new instance of the - /// class. - /// - public ObjectIsNotAFactoryException() - { - } + } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - public ObjectIsNotAFactoryException(string message) - : base(message) - { - } + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + public ObjectIsNotAFactoryException(string message) + : base(message) + { + } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception that is being wrapped. - /// - public ObjectIsNotAFactoryException(string message, Exception rootCause) - : base(message, rootCause) - { - } + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception that is being wrapped. + /// + public ObjectIsNotAFactoryException(string message, Exception rootCause) + : base(message, rootCause) + { + } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The name of the object that was being retrieved from the factory. - /// - /// - /// The object instance that was retrieved. - /// - public ObjectIsNotAFactoryException(string name, object actualInstance) - : base(name, typeof (IFactoryObject), actualInstance) - { - } + /// + /// Creates a new instance of the + /// class. + /// + /// + /// The name of the object that was being retrieved from the factory. + /// + /// + /// The object instance that was retrieved. + /// + public ObjectIsNotAFactoryException(string name, object actualInstance) + : base(name, typeof(IFactoryObject), actualInstance) + { + } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The - /// that holds the serialized object data about the exception being thrown. - /// - /// - /// The - /// that contains contextual information about the source or destination. - /// - protected ObjectIsNotAFactoryException( - SerializationInfo info, StreamingContext context) - : base(info, context) - { - } + /// + /// Creates a new instance of the + /// class. + /// + /// + /// The + /// that holds the serialized object data about the exception being thrown. + /// + /// + /// The + /// that contains contextual information about the source or destination. + /// + protected ObjectIsNotAFactoryException( + SerializationInfo info, StreamingContext context) + : base(info, context) + { } } diff --git a/src/Spring/Spring.Core/Objects/Factory/ObjectNotOfRequiredTypeException.cs b/src/Spring/Spring.Core/Objects/Factory/ObjectNotOfRequiredTypeException.cs index 8ea35775..57735068 100644 --- a/src/Spring/Spring.Core/Objects/Factory/ObjectNotOfRequiredTypeException.cs +++ b/src/Spring/Spring.Core/Objects/Factory/ObjectNotOfRequiredTypeException.cs @@ -21,159 +21,182 @@ using System.Runtime.Serialization; using System.Security.Permissions; -namespace Spring.Objects.Factory { +namespace Spring.Objects.Factory; + +/// +/// Thrown when an object doesn't match the required . +/// +/// Rod Johnson +/// Rick Evans (.NET) +[Serializable] +public class ObjectNotOfRequiredTypeException : ObjectsException +{ + #region Constructor (s) / Destructor + /// - /// Thrown when an object doesn't match the required . + /// Creates a new instance of the ObjectNotOfRequiredTypeException class. /// - /// Rod Johnson - /// Rick Evans (.NET) - [Serializable] - public class ObjectNotOfRequiredTypeException : ObjectsException { - #region Constructor (s) / Destructor - /// - /// Creates a new instance of the ObjectNotOfRequiredTypeException class. - /// - public ObjectNotOfRequiredTypeException () { - } - - /// - /// Creates a new instance of the ObjectNotOfRequiredTypeException class. - /// - /// - /// A message about the exception. - /// - public ObjectNotOfRequiredTypeException (string message) - : base (message) { - } - - /// - /// Creates a new instance of the ObjectNotOfRequiredTypeException class. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception that is being wrapped. - /// - public ObjectNotOfRequiredTypeException (string message, Exception rootCause) - : base (message, rootCause) { - } - - /// - /// Creates a new instance of the ObjectNotOfRequiredTypeException class. - /// - /// - /// Name of the object requested. - /// - /// - /// The required of the actual object - /// instance that was retrieved. - /// - /// - /// The instance actually returned, whose class did not match the - /// expected . - /// - public ObjectNotOfRequiredTypeException ( - string name, Type requiredType, object actualInstance) - : base ( - string.Format ( - "Object named '{0}' must be of type [{1}], but was actually of type [{2}]", - name, - requiredType.FullName, - actualInstance.GetType ().FullName)) { - this.name = name; - this.actualInstance = actualInstance; - this.requiredType = requiredType; - } - - /// - /// Creates a new instance of the ObjectNotOfRequiredTypeException class. - /// - /// - /// The - /// that holds the serialized object data about the exception being thrown. - /// - /// - /// The - /// that contains contextual information about the source or destination. - /// - protected ObjectNotOfRequiredTypeException ( - SerializationInfo info, StreamingContext context) - : base (info, context) - { - requiredType = info.GetValue ("RequiredType", typeof (Type)) as Type; - actualInstance = info.GetValue ("ActualInstance", typeof (object)); - name = info.GetString ("Name"); - } - #endregion - - #region Properties - /// - /// The actual of the actual object - /// instance that was retrieved. - /// - public Type ActualType { - get { - return ActualInstance.GetType (); - } - } - /// - /// The required of the actual object - /// instance that was retrieved. - /// - public Type RequiredType { - get { - return requiredType; - } - } - - /// - /// The instance actually returned, whose class did not match the - /// expected . - /// - public object ActualInstance { - get { - return actualInstance; - } - } - - /// - /// The name of the object requested. - /// - public string ObjectName { - get { - return name; - } - } - #endregion - - #region Methods - /// - /// Populates a with - /// the data needed to serialize the target object. - /// - /// - /// The to populate - /// with data. - /// - /// - /// The destination (see ) - /// for this serialization. - /// - [SecurityPermission (SecurityAction.Demand,SerializationFormatter=true)] - public override void GetObjectData ( - SerializationInfo info, StreamingContext context) { - base.GetObjectData (info, context); - info.AddValue ("RequiredType", requiredType); - info.AddValue ("ActualInstance", actualInstance); - info.AddValue ("Name", name); - } - #endregion - - #region Fields - private Type requiredType; - private object actualInstance; - private string name; - #endregion + public ObjectNotOfRequiredTypeException() + { } + + /// + /// Creates a new instance of the ObjectNotOfRequiredTypeException class. + /// + /// + /// A message about the exception. + /// + public ObjectNotOfRequiredTypeException(string message) + : base(message) + { + } + + /// + /// Creates a new instance of the ObjectNotOfRequiredTypeException class. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception that is being wrapped. + /// + public ObjectNotOfRequiredTypeException(string message, Exception rootCause) + : base(message, rootCause) + { + } + + /// + /// Creates a new instance of the ObjectNotOfRequiredTypeException class. + /// + /// + /// Name of the object requested. + /// + /// + /// The required of the actual object + /// instance that was retrieved. + /// + /// + /// The instance actually returned, whose class did not match the + /// expected . + /// + public ObjectNotOfRequiredTypeException( + string name, Type requiredType, object actualInstance) + : base( + string.Format( + "Object named '{0}' must be of type [{1}], but was actually of type [{2}]", + name, + requiredType.FullName, + actualInstance.GetType().FullName)) + { + this.name = name; + this.actualInstance = actualInstance; + this.requiredType = requiredType; + } + + /// + /// Creates a new instance of the ObjectNotOfRequiredTypeException class. + /// + /// + /// The + /// that holds the serialized object data about the exception being thrown. + /// + /// + /// The + /// that contains contextual information about the source or destination. + /// + protected ObjectNotOfRequiredTypeException( + SerializationInfo info, StreamingContext context) + : base(info, context) + { + requiredType = info.GetValue("RequiredType", typeof(Type)) as Type; + actualInstance = info.GetValue("ActualInstance", typeof(object)); + name = info.GetString("Name"); + } + + #endregion + + #region Properties + + /// + /// The actual of the actual object + /// instance that was retrieved. + /// + public Type ActualType + { + get + { + return ActualInstance.GetType(); + } + } + + /// + /// The required of the actual object + /// instance that was retrieved. + /// + public Type RequiredType + { + get + { + return requiredType; + } + } + + /// + /// The instance actually returned, whose class did not match the + /// expected . + /// + public object ActualInstance + { + get + { + return actualInstance; + } + } + + /// + /// The name of the object requested. + /// + public string ObjectName + { + get + { + return name; + } + } + + #endregion + + #region Methods + + /// + /// Populates a with + /// the data needed to serialize the target object. + /// + /// + /// The to populate + /// with data. + /// + /// + /// The destination (see ) + /// for this serialization. + /// + [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)] + public override void GetObjectData( + SerializationInfo info, StreamingContext context) + { + base.GetObjectData(info, context); + info.AddValue("RequiredType", requiredType); + info.AddValue("ActualInstance", actualInstance); + info.AddValue("Name", name); + } + + #endregion + + #region Fields + + private Type requiredType; + private object actualInstance; + private string name; + + #endregion } diff --git a/src/Spring/Spring.Core/Objects/Factory/Parsing/FailFastProblemReporter.cs b/src/Spring/Spring.Core/Objects/Factory/Parsing/FailFastProblemReporter.cs index be2a6c5a..16073c39 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Parsing/FailFastProblemReporter.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Parsing/FailFastProblemReporter.cs @@ -20,34 +20,31 @@ using Microsoft.Extensions.Logging; -namespace Spring.Objects.Factory.Parsing +namespace Spring.Objects.Factory.Parsing; + +public class FailFastProblemReporter : IProblemReporter { - public class FailFastProblemReporter : IProblemReporter + private static readonly ILogger _logger = LogManager.GetLogger(); + + public ILogger Logger { - private static readonly ILogger _logger = LogManager.GetLogger(); + get { return _logger; } + } - public ILogger Logger - { - get { return _logger; } - } + public void Error(Problem problem) + { + _logger.LogError(problem.Message); + throw new ObjectDefinitionParsingException(problem); + } - public void Error(Problem problem) - { - _logger.LogError(problem.Message); - throw new ObjectDefinitionParsingException(problem); - } - - public void Fatal(Problem problem) - { - _logger.LogCritical(problem.Message); - throw new ObjectDefinitionParsingException(problem); - } - - public void Warning(Problem problem) - { - _logger.LogWarning(problem.Message); - - } + public void Fatal(Problem problem) + { + _logger.LogCritical(problem.Message); + throw new ObjectDefinitionParsingException(problem); + } + public void Warning(Problem problem) + { + _logger.LogWarning(problem.Message); } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Parsing/IProblemReporter.cs b/src/Spring/Spring.Core/Objects/Factory/Parsing/IProblemReporter.cs index d8d60c7f..4768db37 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Parsing/IProblemReporter.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Parsing/IProblemReporter.cs @@ -18,12 +18,11 @@ #endregion -namespace Spring.Objects.Factory.Parsing +namespace Spring.Objects.Factory.Parsing; + +public interface IProblemReporter { - public interface IProblemReporter - { - void Fatal(Problem problem); - void Warning(Problem problem); - void Error(Problem problem); - } + void Fatal(Problem problem); + void Warning(Problem problem); + void Error(Problem problem); } diff --git a/src/Spring/Spring.Core/Objects/Factory/Parsing/Location.cs b/src/Spring/Spring.Core/Objects/Factory/Parsing/Location.cs index b14c620a..c2f53b20 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Parsing/Location.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Parsing/Location.cs @@ -20,50 +20,48 @@ using Spring.Core.IO; -namespace Spring.Objects.Factory.Parsing +namespace Spring.Objects.Factory.Parsing; + +public class Location { - public class Location + private IResource resource; + private object source; + + /// + /// Initializes a new instance of the Location class. + /// + /// + /// + public Location(IResource resource, object source) { - private IResource resource; - private object source; - - /// - /// Initializes a new instance of the Location class. - /// - /// - /// - public Location(IResource resource, object source) - { - //TODO: look into re-enabling this since resource *is* NULL when parsing config classes vs. acquiring IResources - //AssertUtils.ArgumentNotNull(resource, "resource"); - this.resource = resource; - this.source = source; - } - - /// - /// Initializes a new instance of the Location class. - /// - /// - public Location(IResource resource) - : this(resource, null) - { - - } - public IResource Resource - { - get - { - return resource; - } - } - public object Source - { - get - { - return source; - } - } - - + //TODO: look into re-enabling this since resource *is* NULL when parsing config classes vs. acquiring IResources + //AssertUtils.ArgumentNotNull(resource, "resource"); + this.resource = resource; + this.source = source; } -} + + /// + /// Initializes a new instance of the Location class. + /// + /// + public Location(IResource resource) + : this(resource, null) + { + } + + public IResource Resource + { + get + { + return resource; + } + } + + public object Source + { + get + { + return source; + } + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Objects/Factory/Parsing/ObjectDefinitionParsingException.cs b/src/Spring/Spring.Core/Objects/Factory/Parsing/ObjectDefinitionParsingException.cs index 5c1c7270..39462f9b 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Parsing/ObjectDefinitionParsingException.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Parsing/ObjectDefinitionParsingException.cs @@ -21,143 +21,141 @@ using System.Runtime.Serialization; using Spring.Core.IO; -namespace Spring.Objects.Factory.Parsing +namespace Spring.Objects.Factory.Parsing; + +[Serializable] +public class ObjectDefinitionParsingException : ObjectDefinitionStoreException { - [Serializable] - public class ObjectDefinitionParsingException : ObjectDefinitionStoreException + protected ObjectDefinitionParsingException(SerializationInfo info, StreamingContext context) { - protected ObjectDefinitionParsingException(SerializationInfo info, StreamingContext context) - { - } - /// - /// Initializes a new instance of the ObjectDefinitionParsingException class. - /// - public ObjectDefinitionParsingException(Problem problem) - : base(problem.Location.Resource, problem.ResourceDescription, problem.Message) - { + } - } - /// - /// Creates a new instance of the ObjectDefinitionParsingException class. - /// - public ObjectDefinitionParsingException() - { + /// + /// Initializes a new instance of the ObjectDefinitionParsingException class. + /// + public ObjectDefinitionParsingException(Problem problem) + : base(problem.Location.Resource, problem.ResourceDescription, problem.Message) + { + } - } - /// - /// Creates a new instance of the ObjectDefinitionParsingException class. - /// - /// - /// A message about the exception. - /// - public ObjectDefinitionParsingException(string message) - : base(message) - { + /// + /// Creates a new instance of the ObjectDefinitionParsingException class. + /// + public ObjectDefinitionParsingException() + { + } - } - /// - /// Creates a new instance of the ObjectDefinitionParsingException class. - /// - /// - /// The description of the resource that the object definition came from - /// - /// - /// The name of the object that triggered the exception. - /// - /// - /// A message about the exception. - /// - public ObjectDefinitionParsingException(string resourceDescription, string name, string message) - : base(resourceDescription, name, message) - { + /// + /// Creates a new instance of the ObjectDefinitionParsingException class. + /// + /// + /// A message about the exception. + /// + public ObjectDefinitionParsingException(string message) + : base(message) + { + } - } - /// - /// Initializes a new instance of the class. - /// - /// - /// The description of the resource that the object definition came from - /// - /// The detail message (used as exception message as-is) - /// The root cause. (may be null - public ObjectDefinitionParsingException(string resourceDescription, string msg, Exception cause) - : base(resourceDescription, msg, cause) - { + /// + /// Creates a new instance of the ObjectDefinitionParsingException class. + /// + /// + /// The description of the resource that the object definition came from + /// + /// + /// The name of the object that triggered the exception. + /// + /// + /// A message about the exception. + /// + public ObjectDefinitionParsingException(string resourceDescription, string name, string message) + : base(resourceDescription, name, message) + { + } - } - /// - /// Creates a new instance of the ObjectDefinitionParsingException class. - /// - /// - /// The resource location (e.g. an XML object definition file) associated - /// with the offending object definition. - /// - /// - /// A message about the exception. - /// - /// - /// The name of the object that triggered the exception. - /// - public ObjectDefinitionParsingException(IResource resourceLocation, string name, string message) - : base(resourceLocation, name, message) - { + /// + /// Initializes a new instance of the class. + /// + /// + /// The description of the resource that the object definition came from + /// + /// The detail message (used as exception message as-is) + /// The root cause. (may be null + public ObjectDefinitionParsingException(string resourceDescription, string msg, Exception cause) + : base(resourceDescription, msg, cause) + { + } - } - /// - /// Creates a new instance of the ObjectDefinitionParsingException class. - /// - /// - /// The resource location (e.g. an XML object definition file) associated - /// with the offending object definition. - /// - /// - /// A message about the exception. - /// - /// - /// The name of the object that triggered the exception. - /// - /// - /// The root exception that is being wrapped. - /// - public ObjectDefinitionParsingException(IResource resourceLocation, string name, string message, Exception rootCause) - : base(resourceLocation, name, message, rootCause) - { + /// + /// Creates a new instance of the ObjectDefinitionParsingException class. + /// + /// + /// The resource location (e.g. an XML object definition file) associated + /// with the offending object definition. + /// + /// + /// A message about the exception. + /// + /// + /// The name of the object that triggered the exception. + /// + public ObjectDefinitionParsingException(IResource resourceLocation, string name, string message) + : base(resourceLocation, name, message) + { + } - } - /// - /// Creates a new instance of the ObjectDefinitionParsingException class. - /// - /// - /// The description of the resource that the object definition came from - /// - /// - /// A message about the exception. - /// - /// - /// The name of the object that triggered the exception. - /// - /// - /// The root exception that is being wrapped. - /// - public ObjectDefinitionParsingException(string resourceDescription, string name, string message, Exception rootCause) - : base(resourceDescription, name, message, rootCause) - { + /// + /// Creates a new instance of the ObjectDefinitionParsingException class. + /// + /// + /// The resource location (e.g. an XML object definition file) associated + /// with the offending object definition. + /// + /// + /// A message about the exception. + /// + /// + /// The name of the object that triggered the exception. + /// + /// + /// The root exception that is being wrapped. + /// + public ObjectDefinitionParsingException(IResource resourceLocation, string name, string message, Exception rootCause) + : base(resourceLocation, name, message, rootCause) + { + } - } - /// - /// Creates a new instance of the ObjectDefinitionParsingException class. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception that is being wrapped. - /// - public ObjectDefinitionParsingException(string message, Exception rootCause) - : base(message, rootCause) - { - - } + /// + /// Creates a new instance of the ObjectDefinitionParsingException class. + /// + /// + /// The description of the resource that the object definition came from + /// + /// + /// A message about the exception. + /// + /// + /// The name of the object that triggered the exception. + /// + /// + /// The root exception that is being wrapped. + /// + public ObjectDefinitionParsingException(string resourceDescription, string name, string message, Exception rootCause) + : base(resourceDescription, name, message, rootCause) + { + } + /// + /// Creates a new instance of the ObjectDefinitionParsingException class. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception that is being wrapped. + /// + public ObjectDefinitionParsingException(string message, Exception rootCause) + : base(message, rootCause) + { } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Parsing/Problem.cs b/src/Spring/Spring.Core/Objects/Factory/Parsing/Problem.cs index c7036bd2..83c8a4ee 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Parsing/Problem.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Parsing/Problem.cs @@ -21,76 +21,70 @@ using System.Text; using Spring.Util; -namespace Spring.Objects.Factory.Parsing +namespace Spring.Objects.Factory.Parsing; + +public class Problem { - public class Problem + private string _message; + + private Location _location; + + private Exception _rootCause; + + /// + /// Initializes a new instance of the class. + /// + /// The message. + /// The location. + public Problem(string message, Location location) + : this(message, location, null) { - private string _message; + } - private Location _location; + /// + /// Initializes a new instance of the Problem class. + /// + /// + /// + /// + public Problem(string message, Location location, Exception rootCause) + { + AssertUtils.ArgumentNotNull(message, "message"); + AssertUtils.ArgumentNotNull(location, "resource"); - private Exception _rootCause; + _message = message; + _location = location; + _rootCause = rootCause; + } - - /// - /// Initializes a new instance of the class. - /// - /// The message. - /// The location. - public Problem(string message, Location location) - : this(message, location, null) + public string Message + { + get { - + return _message; } + } - /// - /// Initializes a new instance of the Problem class. - /// - /// - /// - /// - public Problem(string message, Location location, Exception rootCause) + public Location Location + { + get { - AssertUtils.ArgumentNotNull(message, "message"); - AssertUtils.ArgumentNotNull(location, "resource"); - - _message = message; - _location = location; - _rootCause = rootCause; + return _location; } + } - public string Message - { - get - { - return _message; - } - } + public string ResourceDescription + { + get { return _location.Resource != null ? _location.Resource.Description : string.Empty; } + } - public Location Location - { - get - { - return _location; - } - } - - public string ResourceDescription - { - get { return _location.Resource != null ? _location.Resource.Description : string.Empty; } - } - - public override string ToString() - { - - StringBuilder sb = new StringBuilder(); - sb.Append("Configuration problem: "); - sb.Append(Message); - sb.Append("\nOffending resource: ").Append(ResourceDescription); - - return sb.ToString(); - - } + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + sb.Append("Configuration problem: "); + sb.Append(Message); + sb.Append("\nOffending resource: ").Append(ResourceDescription); + return sb.ToString(); } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Parsing/ReaderContext.cs b/src/Spring/Spring.Core/Objects/Factory/Parsing/ReaderContext.cs index 90fd937c..ff9dba2c 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Parsing/ReaderContext.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Parsing/ReaderContext.cs @@ -20,36 +20,34 @@ using Spring.Core.IO; -namespace Spring.Objects.Factory.Parsing +namespace Spring.Objects.Factory.Parsing; + +/// +/// Context that gets passed along an object definition reading process, +/// encapsulating all relevant configuraiton as well as state. +/// +/// Rob Harrop +/// Juergen Hoeller +/// Mark Pollack (.NET) +public class ReaderContext { + private IResource resource; + /// - /// Context that gets passed along an object definition reading process, - /// encapsulating all relevant configuraiton as well as state. + /// Initializes a new instance of the class. /// - /// Rob Harrop - /// Juergen Hoeller - /// Mark Pollack (.NET) - public class ReaderContext + /// The resource. + public ReaderContext(IResource resource) { - private IResource resource; + this.resource = resource; + } - /// - /// Initializes a new instance of the class. - /// - /// The resource. - public ReaderContext(IResource resource) - { - this.resource = resource; - } - - - /// - /// Gets the resource. - /// - /// The resource. - public IResource Resource - { - get { return resource; } - } + /// + /// Gets the resource. + /// + /// The resource. + public IResource Resource + { + get { return resource; } } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/AbstractAutowireCapableObjectFactory.cs b/src/Spring/Spring.Core/Objects/Factory/Support/AbstractAutowireCapableObjectFactory.cs index c8619a2c..33f533ef 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/AbstractAutowireCapableObjectFactory.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/AbstractAutowireCapableObjectFactory.cs @@ -24,1137 +24,551 @@ using Spring.Core.TypeResolution; using Spring.Objects.Factory.Config; using Spring.Util; -namespace Spring.Objects.Factory.Support +namespace Spring.Objects.Factory.Support; + +/// +/// Abstract superclass +/// that implements default object creation. +/// +/// +///

+/// Provides object creation, initialization and wiring, supporting +/// autowiring and constructor resolution. Handles runtime object +/// references, managed collections, and object destruction. +///

+///

+/// The main template method to be implemented by subclasses is +/// , +/// used for autowiring by type. Note that this class does not implement object +/// definition registry capabilities +/// ( +/// does). +///

+///
+/// Rod Johnson +/// Juergen Hoeller +/// Rick Evans (.NET) +[Serializable] +public abstract class AbstractAutowireCapableObjectFactory : AbstractObjectFactory, IAutowireCapableObjectFactory { + private IInstantiationStrategy instantiationStrategy = new MethodInjectingInstantiationStrategy(); + /// - /// Abstract superclass - /// that implements default object creation. + /// Cache of filtered PropertyInfos: object Type -> PropertyInfo array + /// + private readonly ConcurrentDictionary> filteredPropertyDescriptorsCache = new ConcurrentDictionary>(); + + /// + /// Dependency interfaces to ignore on dependency check and autowire, as Set of + /// Class objects. By default, only the IObjectFactoryAware and IObjectNameAware + /// interfaces are ignored. + /// + private readonly HybridSet ignoredDependencyInterfaces = new HybridSet(); + + [NonSerialized] private ObjectDefinitionValueResolver cachedValueResolver; + + /// + /// The used during the invocation and + /// searching for of methods. + /// + protected const BindingFlags MethodResolutionFlags = + BindingFlags.Public | BindingFlags.InvokeMethod | BindingFlags.Static | BindingFlags.Instance | BindingFlags.IgnoreCase; + + /// + /// Creates a new instance of the + /// + /// class. /// /// ///

- /// Provides object creation, initialization and wiring, supporting - /// autowiring and constructor resolution. Handles runtime object - /// references, managed collections, and object destruction. - ///

- ///

- /// The main template method to be implemented by subclasses is - /// , - /// used for autowiring by type. Note that this class does not implement object - /// definition registry capabilities - /// ( - /// does). + /// This is an class, and as such exposes no public constructors. ///

///
- /// Rod Johnson - /// Juergen Hoeller - /// Rick Evans (.NET) - [Serializable] - public abstract class AbstractAutowireCapableObjectFactory : AbstractObjectFactory, IAutowireCapableObjectFactory + /// Flag specifying whether to make this object factory case sensitive or not. + protected AbstractAutowireCapableObjectFactory(bool caseSensitive) + : this(caseSensitive, null) { + } - private IInstantiationStrategy instantiationStrategy = new MethodInjectingInstantiationStrategy(); + /// + /// Creates a new instance of the + /// + /// class. + /// + /// + ///

+ /// This is an class, and as such exposes no public constructors. + ///

+ ///
+ /// Flag specifying whether to make this object factory case sensitive or not. + /// The parent object factory, or if none. + protected AbstractAutowireCapableObjectFactory(bool caseSensitive, IObjectFactory parentFactory) + : base(caseSensitive, parentFactory) + { + IgnoreDependencyInterface(typeof(IObjectFactoryAware)); + IgnoreDependencyInterface(typeof(IObjectNameAware)); + } - /// - /// Cache of filtered PropertyInfos: object Type -> PropertyInfo array - /// - private readonly ConcurrentDictionary> filteredPropertyDescriptorsCache = new ConcurrentDictionary>(); + /// + /// The + /// implementation to be used to instantiate managed objects. + /// + protected IInstantiationStrategy InstantiationStrategy + { + get => instantiationStrategy; + set => instantiationStrategy = value; + } - /// - /// Dependency interfaces to ignore on dependency check and autowire, as Set of - /// Class objects. By default, only the IObjectFactoryAware and IObjectNameAware - /// interfaces are ignored. - /// - private readonly HybridSet ignoredDependencyInterfaces = new HybridSet(); - - [NonSerialized] - private ObjectDefinitionValueResolver cachedValueResolver; - - /// - /// The used during the invocation and - /// searching for of methods. - /// - protected const BindingFlags MethodResolutionFlags = - BindingFlags.Public | BindingFlags.InvokeMethod | BindingFlags.Static | BindingFlags.Instance | BindingFlags.IgnoreCase; - - /// - /// Creates a new instance of the - /// - /// class. - /// - /// - ///

- /// This is an class, and as such exposes no public constructors. - ///

- ///
- /// Flag specifying whether to make this object factory case sensitive or not. - protected AbstractAutowireCapableObjectFactory(bool caseSensitive) - : this(caseSensitive, null) - { } - - /// - /// Creates a new instance of the - /// - /// class. - /// - /// - ///

- /// This is an class, and as such exposes no public constructors. - ///

- ///
- /// Flag specifying whether to make this object factory case sensitive or not. - /// The parent object factory, or if none. - protected AbstractAutowireCapableObjectFactory(bool caseSensitive, IObjectFactory parentFactory) - : base(caseSensitive, parentFactory) + /// + /// Predict the eventual object type (of the processed object instance) for the + /// specified object. + /// + /// Name of the object. + /// The merged object definition to determine the type for. May be null + /// + /// The type of the object, or null if not predictable + /// + protected override Type PredictObjectType(string objectName, RootObjectDefinition mod) + { + Type objectType; + if (mod == null) { - IgnoreDependencyInterface(typeof(IObjectFactoryAware)); - IgnoreDependencyInterface(typeof(IObjectNameAware)); - } - - /// - /// The - /// implementation to be used to instantiate managed objects. - /// - protected IInstantiationStrategy InstantiationStrategy - { - get => instantiationStrategy; - set => instantiationStrategy = value; - } - - /// - /// Predict the eventual object type (of the processed object instance) for the - /// specified object. - /// - /// Name of the object. - /// The merged object definition to determine the type for. May be null - /// - /// The type of the object, or null if not predictable - /// - protected override Type PredictObjectType(string objectName, RootObjectDefinition mod) - { - Type objectType; - if (mod == null) - { - return null; - } - - if (StringUtils.HasText(mod.FactoryMethodName)) - { - objectType = GetTypeForFactoryMethod(objectName, mod); - } - else - { - objectType = ResolveObjectType(mod, objectName); - } - return objectType; - } - - /// - /// Determines the of the object defined - /// by the supplied object . - /// - /// - /// The name associated with the supplied object . - /// - /// - /// The - /// that the is to be determined for. - /// - /// - /// The of the object defined by the supplied - /// object ; or if the - /// cannot be determined. - /// - protected override Type GetTypeForFactoryMethod(string objectName, RootObjectDefinition definition) - { - Type factoryType = null; - bool isStatic = true; - - if (StringUtils.HasText(definition.FactoryObjectName)) - { - // check declared factory method return type on factory type... - factoryType = GetType(definition.FactoryObjectName); - isStatic = false; - } - else - { - factoryType = ResolveObjectType(definition, objectName); - } - if (factoryType == null) - { - return null; - } - - // If all factory methods have the same return type, return that type. - // Can't clearly figure out exact method due to type converting / autowiring! - int minNrOfArgs = definition.ConstructorArgumentValues.GenericArgumentValues.Count; - MethodInfo[] candidates = factoryType.GetMethods(); - ISet returnTypes = new HybridSet(); - foreach (MethodInfo factoryMethod in candidates) - { - GenericArgumentsHolder genericArgsInfo = new GenericArgumentsHolder(definition.FactoryMethodName); - if (factoryMethod.IsStatic == isStatic && factoryMethod.Name.Equals(genericArgsInfo.GenericMethodName) - && ReflectionUtils.GetParameterTypes(factoryMethod).Length >= minNrOfArgs - && factoryMethod.GetGenericArguments().Length == genericArgsInfo.GetGenericArguments().Length) - { - if (genericArgsInfo.ContainsGenericArguments) - { - string[] unresolvedGenericArgs = genericArgsInfo.GetGenericArguments(); - Type[] genericArgs = new Type[unresolvedGenericArgs.Length]; - for (int j = 0; j < unresolvedGenericArgs.Length; j++) - { - genericArgs[j] = TypeResolutionUtils.ResolveType(unresolvedGenericArgs[j]); - } - returnTypes.Add(factoryMethod.MakeGenericMethod(genericArgs).ReturnType); - } - else - { - returnTypes.Add(factoryMethod.ReturnType); - } - } - } - if (returnTypes.Count == 1) - { - // clear return type found: all factory methods return same type... - return (Type)ObjectUtils.EnumerateFirstElement(returnTypes); - } - - // ambiguous return types found: return null to indicate "not determinable"... return null; } - /// - /// Apply the property values of the object definition with the supplied - /// to the supplied . - /// - /// - /// The existing object that the property values for the named object will - /// be applied to. - /// - /// - /// The name of the object definition associated with the property values that are - /// to be applied. - /// - public override void ApplyObjectPropertyValues(object instance, string name) + if (StringUtils.HasText(mod.FactoryMethodName)) { - RootObjectDefinition definition = GetMergedObjectDefinition(name, true); - if (definition != null) - { - log.LogDebug($"configuring object '{instance}' using definition '{name}'"); - ApplyPropertyValues(name, definition, new ObjectWrapper(instance), definition.PropertyValues); - } + objectType = GetTypeForFactoryMethod(objectName, mod); + } + else + { + objectType = ResolveObjectType(mod, objectName); } - /// - /// Apply the property values of the object definition with the supplied - /// to the supplied . - /// - /// - /// The existing object that the property values for the named object will - /// be applied to. - /// - /// - /// The name of the object definition associated with the property values that are - /// to be applied. - /// - /// - /// An object definition that should be used to apply property values. - /// - public override void ApplyObjectPropertyValues(object instance, string name, IObjectDefinition definition) + return objectType; + } + + /// + /// Determines the of the object defined + /// by the supplied object . + /// + /// + /// The name associated with the supplied object . + /// + /// + /// The + /// that the is to be determined for. + /// + /// + /// The of the object defined by the supplied + /// object ; or if the + /// cannot be determined. + /// + protected override Type GetTypeForFactoryMethod(string objectName, RootObjectDefinition definition) + { + Type factoryType = null; + bool isStatic = true; + + if (StringUtils.HasText(definition.FactoryObjectName)) { - MarkObjectAsCreated(name); - ApplyPropertyValues(name, new RootObjectDefinition(definition), new ObjectWrapper(instance), definition.PropertyValues); + // check declared factory method return type on factory type... + factoryType = GetType(definition.FactoryObjectName); + isStatic = false; + } + else + { + factoryType = ResolveObjectType(definition, objectName); } - /// - /// Apply any - /// s. - /// - /// - ///

- /// The returned instance may be a wrapper around the original. - ///

- ///
- /// - /// The of the object that is to be - /// instantiated. - /// - /// - /// The name of the object that is to be instantiated. - /// - /// - /// An instance to use in place of the original instance. - /// - /// - /// In case of errors. - /// - protected object ApplyObjectPostProcessorsBeforeInstantiation(Type objectType, string objectName) + if (factoryType == null) { - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug("Invoking IInstantiationAwareObjectPostProcessors before " + - $"the instantiation of '{objectName}'."); - } - - for (var i = 0; i < objectPostProcessors.Count; i++) - { - IObjectPostProcessor processor = objectPostProcessors[i]; - IInstantiationAwareObjectPostProcessor inProc = processor as IInstantiationAwareObjectPostProcessor; - object theObject = inProc?.PostProcessBeforeInstantiation(objectType, objectName); - if (theObject != null) - { - return theObject; - } - } - return null; } - /// - /// Apply s - /// to the given existing object instance, invoking their - /// - /// methods. - /// - /// - /// The existing object instance. - /// - /// - /// The name of the object. - /// - /// - public virtual void ApplyObjectPostProcessBeforeDestruction(object instance, string name) + // If all factory methods have the same return type, return that type. + // Can't clearly figure out exact method due to type converting / autowiring! + int minNrOfArgs = definition.ConstructorArgumentValues.GenericArgumentValues.Count; + MethodInfo[] candidates = factoryType.GetMethods(); + ISet returnTypes = new HybridSet(); + foreach (MethodInfo factoryMethod in candidates) { - log.LogDebug("Invoking PostProcessBeforeDestruction after IDisposal of object '{ObjectName}", name); + GenericArgumentsHolder genericArgsInfo = new GenericArgumentsHolder(definition.FactoryMethodName); + if (factoryMethod.IsStatic == isStatic && factoryMethod.Name.Equals(genericArgsInfo.GenericMethodName) + && ReflectionUtils.GetParameterTypes(factoryMethod).Length >= minNrOfArgs + && factoryMethod.GetGenericArguments().Length == genericArgsInfo.GetGenericArguments().Length) + { + if (genericArgsInfo.ContainsGenericArguments) + { + string[] unresolvedGenericArgs = genericArgsInfo.GetGenericArguments(); + Type[] genericArgs = new Type[unresolvedGenericArgs.Length]; + for (int j = 0; j < unresolvedGenericArgs.Length; j++) + { + genericArgs[j] = TypeResolutionUtils.ResolveType(unresolvedGenericArgs[j]); + } + returnTypes.Add(factoryMethod.MakeGenericMethod(genericArgs).ReturnType); + } + else + { + returnTypes.Add(factoryMethod.ReturnType); + } + } + } + + if (returnTypes.Count == 1) + { + // clear return type found: all factory methods return same type... + return (Type) ObjectUtils.EnumerateFirstElement(returnTypes); + } + + // ambiguous return types found: return null to indicate "not determinable"... + return null; + } + + /// + /// Apply the property values of the object definition with the supplied + /// to the supplied . + /// + /// + /// The existing object that the property values for the named object will + /// be applied to. + /// + /// + /// The name of the object definition associated with the property values that are + /// to be applied. + /// + public override void ApplyObjectPropertyValues(object instance, string name) + { + RootObjectDefinition definition = GetMergedObjectDefinition(name, true); + if (definition != null) + { + log.LogDebug($"configuring object '{instance}' using definition '{name}'"); + ApplyPropertyValues(name, definition, new ObjectWrapper(instance), definition.PropertyValues); + } + } + + /// + /// Apply the property values of the object definition with the supplied + /// to the supplied . + /// + /// + /// The existing object that the property values for the named object will + /// be applied to. + /// + /// + /// The name of the object definition associated with the property values that are + /// to be applied. + /// + /// + /// An object definition that should be used to apply property values. + /// + public override void ApplyObjectPropertyValues(object instance, string name, IObjectDefinition definition) + { + MarkObjectAsCreated(name); + ApplyPropertyValues(name, new RootObjectDefinition(definition), new ObjectWrapper(instance), definition.PropertyValues); + } + + /// + /// Apply any + /// s. + /// + /// + ///

+ /// The returned instance may be a wrapper around the original. + ///

+ ///
+ /// + /// The of the object that is to be + /// instantiated. + /// + /// + /// The name of the object that is to be instantiated. + /// + /// + /// An instance to use in place of the original instance. + /// + /// + /// In case of errors. + /// + protected object ApplyObjectPostProcessorsBeforeInstantiation(Type objectType, string objectName) + { + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug("Invoking IInstantiationAwareObjectPostProcessors before " + + $"the instantiation of '{objectName}'."); + } + + for (var i = 0; i < objectPostProcessors.Count; i++) + { + IObjectPostProcessor processor = objectPostProcessors[i]; + IInstantiationAwareObjectPostProcessor inProc = processor as IInstantiationAwareObjectPostProcessor; + object theObject = inProc?.PostProcessBeforeInstantiation(objectType, objectName); + if (theObject != null) + { + return theObject; + } + } + + return null; + } + + /// + /// Apply s + /// to the given existing object instance, invoking their + /// + /// methods. + /// + /// + /// The existing object instance. + /// + /// + /// The name of the object. + /// + /// + public virtual void ApplyObjectPostProcessBeforeDestruction(object instance, string name) + { + log.LogDebug("Invoking PostProcessBeforeDestruction after IDisposal of object '{ObjectName}", name); + + for (var i = 0; i < ObjectPostProcessors.Count; i++) + { + IObjectPostProcessor objectProcessor = ObjectPostProcessors[i]; + if (objectProcessor is IDestructionAwareObjectPostProcessor processor) + { + try + { + processor.PostProcessBeforeDestruction(instance, name); + } + catch (Exception ex) + { + log.LogError(ex, "Error during execution of {ProcessorName}.PostProcessBeforeDestruction for object {ObjectName}", processor.GetType().Name, name); + } + } + } + } + + /// + /// Apply the given property values, resolving any runtime references + /// to other objects in this object factory. + /// + /// + /// The object name passed for better exception information. + /// + /// + /// The definition of the named object. + /// + /// + /// The wrapping the target object. + /// + /// + /// The new property values. + /// + /// + ///

+ /// Must use deep copy, so that we don't permanently modify this property. + ///

+ ///
+ protected void ApplyPropertyValues(string name, RootObjectDefinition definition, IObjectWrapper wrapper, IPropertyValues properties) + { + if (properties == null || properties.PropertyValues.Count == 0) + { + return; + } + + ObjectDefinitionValueResolver valueResolver = CreateValueResolver(); + + MutablePropertyValues deepCopy = new MutablePropertyValues(properties); + var copiedProperties = deepCopy.PropertyValues; + for (int i = 0; i < copiedProperties.Count; ++i) + { + PropertyValue copiedProperty = copiedProperties[i]; + //(string name, RootObjectDefinition definition, string argumentName, object argumentValue) + object value = valueResolver.ResolveValueIfNecessary(name, definition, copiedProperty.Name, copiedProperty.Value); + // object value = ResolveValueIfNecessary(name, definition, copiedProperty.Name, copiedProperty.Value); + PropertyValue propertyValue = new PropertyValue(copiedProperty.Name, value, copiedProperty.Expression); + // update mutable copy... + deepCopy.SetPropertyValueAt(propertyValue, i); + } + + // set the (possibly resolved) deep copy properties... + try + { + wrapper.SetPropertyValues(deepCopy); + } + catch (ObjectsException ex) + { + // improve the message by showing the context... + throw new ObjectCreationException(definition.ResourceDescription, name, "Error setting property values: " + ex.Message, ex); + } + } + + /// + /// Create the value resolver strategy to use for resolving raw property values + /// + protected virtual ObjectDefinitionValueResolver CreateValueResolver() + { + return cachedValueResolver ?? (cachedValueResolver = new ObjectDefinitionValueResolver(this)); + } + + /// + /// Return an array of object-type property names that are unsatisfied. + /// + /// + ///

+ /// These are probably unsatisfied references to other objects in the + /// factory. Does not include simple properties like primitives or + /// s. + ///

+ ///
+ /// + /// An array of object-type property names that are unsatisfied. + /// + /// + /// The definition of the named object. + /// + /// + /// The wrapping the target object. + /// + protected string[] UnsatisfiedNonSimpleProperties(RootObjectDefinition definition, IObjectWrapper wrapper) + { + ListSet results = new ListSet(); + IPropertyValues pvs = definition.PropertyValues; + PropertyInfo[] properties = wrapper.GetPropertyInfos(); + foreach (PropertyInfo property in properties) + { + string name = property.Name; + if (property.CanWrite + && !IsExcludedFromDependencyCheck(property) + && !pvs.Contains(name) + && !ObjectUtils.IsSimpleProperty(property.PropertyType)) + { + results.Add(name); + } + } + + return (string[]) CollectionUtils.ToArray(results, typeof(string)); + } + + /// + /// Destroy all cached singletons in this factory. + /// + /// + ///

+ /// To be called on shutdown of a factory. + ///

+ ///
+ public override void Dispose() + { + //TODO: fix the calls to GetObject(...) etc. so that they are invalid during container shutdown rather than attempting to resolve + // objects and permitting calling code to even get this far; considered too invasive a breaking change for 1.3.2; recommend impl + // of this change for the 2.0 release + + base.Dispose(); + + //have to clone the collection before iterating it to avoid arbitrary code in the objects' Dispose() + // that might permit re-entering the DisposableInnerObjects collections during the iteration to destroy them + // see https://jira.springframework.org/browse/SPRNET-1334 + + ISet clone = (ISet) DisposableInnerObjects.Clone(); + + foreach (object o in clone) + { + DestroyObject(string.Format(CultureInfo.InvariantCulture, "(Inner object of Type '{0}')", o.GetType().FullName), o); + } + + DisposableInnerObjects.Clear(); + } + + /// + /// Populate the object instance in the given + /// with the property values from the + /// object definition. + /// + /// + /// The name of the object. + /// + /// + /// The definition of the named object. + /// + /// + /// The wrapping the target object. + /// + protected void PopulateObject(string name, RootObjectDefinition definition, IObjectWrapper wrapper) + { + // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the + // state of the bean before properties are set. This can be used, for example, + // to support styles of field injection. + bool continueWithPropertyPopulation = true; + + if (HasInstantiationAwareObjectPostProcessors) + { for (var i = 0; i < ObjectPostProcessors.Count; i++) { - IObjectPostProcessor objectProcessor = ObjectPostProcessors[i]; - if (objectProcessor is IDestructionAwareObjectPostProcessor processor) + IObjectPostProcessor processor = ObjectPostProcessors[i]; + if (processor is IInstantiationAwareObjectPostProcessor inProc) { - try + if (!inProc.PostProcessAfterInstantiation(wrapper.WrappedInstance, name)) { - processor.PostProcessBeforeDestruction(instance, name); - } - catch (Exception ex) - { - log.LogError(ex, "Error during execution of {ProcessorName}.PostProcessBeforeDestruction for object {ObjectName}", processor.GetType().Name, name); + continueWithPropertyPopulation = false; + break; } } } } - - /// - /// Apply the given property values, resolving any runtime references - /// to other objects in this object factory. - /// - /// - /// The object name passed for better exception information. - /// - /// - /// The definition of the named object. - /// - /// - /// The wrapping the target object. - /// - /// - /// The new property values. - /// - /// - ///

- /// Must use deep copy, so that we don't permanently modify this property. - ///

- ///
- protected void ApplyPropertyValues(string name, RootObjectDefinition definition, IObjectWrapper wrapper, IPropertyValues properties) + if (!continueWithPropertyPopulation) { - if (properties == null || properties.PropertyValues.Count == 0) - { - return; - } - ObjectDefinitionValueResolver valueResolver = CreateValueResolver(); - - MutablePropertyValues deepCopy = new MutablePropertyValues(properties); - var copiedProperties = deepCopy.PropertyValues; - for (int i = 0; i < copiedProperties.Count; ++i) - { - PropertyValue copiedProperty = copiedProperties[i]; - //(string name, RootObjectDefinition definition, string argumentName, object argumentValue) - object value = valueResolver.ResolveValueIfNecessary(name, definition, copiedProperty.Name, copiedProperty.Value); - // object value = ResolveValueIfNecessary(name, definition, copiedProperty.Name, copiedProperty.Value); - PropertyValue propertyValue = new PropertyValue(copiedProperty.Name, value, copiedProperty.Expression); - // update mutable copy... - deepCopy.SetPropertyValueAt(propertyValue, i); - } - // set the (possibly resolved) deep copy properties... - try - { - wrapper.SetPropertyValues(deepCopy); - } - catch (ObjectsException ex) - { - // improve the message by showing the context... - throw new ObjectCreationException(definition.ResourceDescription, name, "Error setting property values: " + ex.Message, ex); - } + return; } - /// - /// Create the value resolver strategy to use for resolving raw property values - /// - protected virtual ObjectDefinitionValueResolver CreateValueResolver() - { - return cachedValueResolver ?? (cachedValueResolver =new ObjectDefinitionValueResolver(this)); - } + IPropertyValues properties = definition.PropertyValues; - /// - /// Return an array of object-type property names that are unsatisfied. - /// - /// - ///

- /// These are probably unsatisfied references to other objects in the - /// factory. Does not include simple properties like primitives or - /// s. - ///

- ///
- /// - /// An array of object-type property names that are unsatisfied. - /// - /// - /// The definition of the named object. - /// - /// - /// The wrapping the target object. - /// - protected string[] UnsatisfiedNonSimpleProperties(RootObjectDefinition definition, IObjectWrapper wrapper) + if (wrapper == null) { - ListSet results = new ListSet(); - IPropertyValues pvs = definition.PropertyValues; - PropertyInfo[] properties = wrapper.GetPropertyInfos(); - foreach (PropertyInfo property in properties) + if (properties.PropertyValues.Count > 0) { - string name = property.Name; - if (property.CanWrite - && !IsExcludedFromDependencyCheck(property) - && !pvs.Contains(name) - && !ObjectUtils.IsSimpleProperty(property.PropertyType)) - { - results.Add(name); - } - } - return (string[])CollectionUtils.ToArray(results, typeof(string)); - } - - /// - /// Destroy all cached singletons in this factory. - /// - /// - ///

- /// To be called on shutdown of a factory. - ///

- ///
- public override void Dispose() - { - //TODO: fix the calls to GetObject(...) etc. so that they are invalid during container shutdown rather than attempting to resolve - // objects and permitting calling code to even get this far; considered too invasive a breaking change for 1.3.2; recommend impl - // of this change for the 2.0 release - - base.Dispose(); - - //have to clone the collection before iterating it to avoid arbitrary code in the objects' Dispose() - // that might permit re-entering the DisposableInnerObjects collections during the iteration to destroy them - // see https://jira.springframework.org/browse/SPRNET-1334 - - ISet clone = (ISet)DisposableInnerObjects.Clone(); - - foreach (object o in clone) - { - DestroyObject(string.Format(CultureInfo.InvariantCulture, "(Inner object of Type '{0}')", o.GetType().FullName), o); + throw new ObjectCreationException(definition.ResourceDescription, + name, "Cannot apply property values to null instance."); } - DisposableInnerObjects.Clear(); + // skip property population phase for null instance + return; } - /// - /// Populate the object instance in the given - /// with the property values from the - /// object definition. - /// - /// - /// The name of the object. - /// - /// - /// The definition of the named object. - /// - /// - /// The wrapping the target object. - /// - protected void PopulateObject(string name, RootObjectDefinition definition, IObjectWrapper wrapper) + if (definition.ResolvedAutowireMode == AutoWiringMode.ByName || definition.ResolvedAutowireMode == AutoWiringMode.ByType) { - // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the - // state of the bean before properties are set. This can be used, for example, - // to support styles of field injection. - bool continueWithPropertyPopulation = true; + MutablePropertyValues mpvs = new MutablePropertyValues(properties); + // add property values based on autowire by name if it's applied + if (definition.ResolvedAutowireMode == AutoWiringMode.ByName) + { + AutowireByName(name, definition, wrapper, mpvs); + } - if (HasInstantiationAwareObjectPostProcessors) + // add property values based on autowire by type if it's applied + if (definition.ResolvedAutowireMode == AutoWiringMode.ByType) + { + AutowireByType(name, definition, wrapper, mpvs); + } + + properties = mpvs; + } + //DependencyCheck(name, definition, wrapper, properties); + + bool hasInstAwareOpps = HasInstantiationAwareObjectPostProcessors; + bool needsDepCheck = (definition.DependencyCheck != DependencyCheckingMode.None); + + if (hasInstAwareOpps || needsDepCheck) + { + List filteredPropInfo = null; + if (hasInstAwareOpps) { for (var i = 0; i < ObjectPostProcessors.Count; i++) { IObjectPostProcessor processor = ObjectPostProcessors[i]; - if (processor is IInstantiationAwareObjectPostProcessor inProc) + if (processor is IInstantiationAwareObjectPostProcessor instantiationAwareObjectPostProcessor) { - if (!inProc.PostProcessAfterInstantiation(wrapper.WrappedInstance, name)) - { - continueWithPropertyPopulation = false; - break; - } - } - } - } - if (!continueWithPropertyPopulation) - { - return; - } - - IPropertyValues properties = definition.PropertyValues; - - if (wrapper == null) - { - if (properties.PropertyValues.Count > 0) - { - throw new ObjectCreationException(definition.ResourceDescription, - name, "Cannot apply property values to null instance."); - } - - // skip property population phase for null instance - return; - } - - if (definition.ResolvedAutowireMode == AutoWiringMode.ByName || definition.ResolvedAutowireMode == AutoWiringMode.ByType) - { - MutablePropertyValues mpvs = new MutablePropertyValues(properties); - // add property values based on autowire by name if it's applied - if (definition.ResolvedAutowireMode == AutoWiringMode.ByName) - { - AutowireByName(name, definition, wrapper, mpvs); - } - // add property values based on autowire by type if it's applied - if (definition.ResolvedAutowireMode == AutoWiringMode.ByType) - { - AutowireByType(name, definition, wrapper, mpvs); - } - properties = mpvs; - } - //DependencyCheck(name, definition, wrapper, properties); - - - bool hasInstAwareOpps = HasInstantiationAwareObjectPostProcessors; - bool needsDepCheck = (definition.DependencyCheck != DependencyCheckingMode.None); - - if (hasInstAwareOpps || needsDepCheck) - { - List filteredPropInfo = null; - if (hasInstAwareOpps) - { - for (var i = 0; i < ObjectPostProcessors.Count; i++) - { - IObjectPostProcessor processor = ObjectPostProcessors[i]; - if (processor is IInstantiationAwareObjectPostProcessor instantiationAwareObjectPostProcessor) - { - filteredPropInfo = filteredPropInfo ?? FilterPropertyInfoForDependencyCheck(wrapper); - properties = instantiationAwareObjectPostProcessor.PostProcessPropertyValues(properties, - filteredPropInfo, wrapper.WrappedInstance, name); - if (properties == null) - { - return; - } - } - } - } - - if (needsDepCheck) - { - filteredPropInfo = filteredPropInfo ?? FilterPropertyInfoForDependencyCheck(wrapper); - CheckDependencies(name, definition, filteredPropInfo, properties); - } - - } - - ApplyPropertyValues(name, definition, wrapper, properties); - } - - /// - /// Wires up any exposed events in the object instance in the given - /// with any event handler - /// values from the . - /// - /// - /// The name of the object. - /// - /// - /// The definition of the named object. - /// - /// - /// The wrapping the target object. - /// - protected void WireEvents(string name, IConfigurableObjectDefinition definition, IObjectWrapper wrapper) - { - foreach (string eventName in definition.EventHandlerValues.Events) - { - foreach (IEventHandlerValue handlerValue - in definition.EventHandlerValues[eventName]) - { - object handler = null; - if (handlerValue.Source is RuntimeObjectReference) - { - RuntimeObjectReference roref = (RuntimeObjectReference)handlerValue.Source; - handler = ResolveReference(definition, name, eventName, roref); - } - else if (handlerValue.Source is Type) - { - // a static Type event is being wired up; simply pass on the Type - handler = handlerValue.Source; - } - else if (handlerValue.Source is string) - { - // a static Type event is being wired up; we need to resolve the Type - handler = TypeResolutionUtils.ResolveType(handlerValue.Source as string); - } - else - { - throw new FatalObjectException("Currently, only references to other objects and Types are " + "supported as event sources."); - } - handlerValue.Wire(handler, wrapper.WrappedInstance); - } - } - } - - /// - /// Fills in any missing property values with references to - /// other objects in this factory if autowire is set to - /// . - /// - /// - /// The object name to be autowired by . - /// - /// - /// The definition of the named object to update through autowiring. - /// - /// - /// The wrapping the target object (and - /// from which we can rip out information concerning the object). - /// - /// - /// The property values to register wired objects with. - /// - protected void AutowireByName(string name, RootObjectDefinition definition, IObjectWrapper wrapper, MutablePropertyValues properties) - { - string[] propertyNames = UnsatisfiedNonSimpleProperties(definition, wrapper); - foreach (string propertyName in propertyNames) - { - // look for a matching type - if (ContainsObject(propertyName)) - { - object o = GetObject(propertyName); - properties.Add(propertyName, o); - - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug(string.Format(CultureInfo.InvariantCulture, - "Added autowiring by name from object name '{0}' via " + "property '{1}' to object named '{1}'.", name, - propertyName)); - } - } - else - { - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug(string.Format(CultureInfo.InvariantCulture, - "Not autowiring property '{0}' of object '{1}' by name: " + "no matching object found.", propertyName, name)); - } - } - } - } - - /// - /// Defines "autowire by type" (object properties by type) behavior. - /// - /// - ///

- /// This is like PicoContainer default, in which there must be exactly one object - /// of the property type in the object factory. This makes object factories simple - /// to configure for small namespaces, but doesn't work as well as standard Spring - /// behavior for bigger applications. - ///

- ///
- /// - /// The object name to be autowired by . - /// - /// - /// The definition of the named object to update through autowiring. - /// - /// - /// The wrapping the target object (and - /// from which we can rip out information concerning the object). - /// - /// - /// The property values to register wired objects with. - /// - protected void AutowireByType(string name, RootObjectDefinition definition, IObjectWrapper wrapper, MutablePropertyValues properties) - { - string[] propertyNames = UnsatisfiedNonSimpleProperties(definition, wrapper); - foreach (string propertyName in propertyNames) - { - // look for a matching type - Type requiredType = wrapper.GetPropertyType(propertyName); - IDictionary matchingObjects = FindMatchingObjects(requiredType); - if (matchingObjects != null && matchingObjects.Count == 1) - { - properties.Add(propertyName, ObjectUtils.EnumerateFirstElement(matchingObjects.Values)); - - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug(string.Format(CultureInfo.InvariantCulture, - "Autowiring by type from object name '{0}' via property " + "'{1}' to object named '{2}'.", name, - propertyName, ObjectUtils.EnumerateFirstElement(matchingObjects.Keys))); - } - } - else if (matchingObjects != null && matchingObjects.Count > 1) - { - throw new UnsatisfiedDependencyException(string.Empty, name, propertyName, - string.Format(CultureInfo.InvariantCulture, - "There are {0} objects of Type [{1}] for autowire by " - + "type, when there should have been just 1 to be able to " - + "autowire property '{2}' of object '{3}'.", matchingObjects.Count, - requiredType, propertyName, name)); - } - else - { - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug(string.Format(CultureInfo.InvariantCulture, "Not autowiring property '{0}' of object '{1}': no matching object found.", - propertyName, name)); - } - } - } - } - - /// - /// Ignore the given dependency type for autowiring - /// - /// - /// This will typically be used by application contexts to register - /// dependencies that are resolved in other ways, like IOjbectFactory through - /// IObjectFactoryAware or IApplicationContext through IApplicationContextAware. - /// By default, IObjectFactoryAware and IObjectName interfaces are ignored. - /// For further types to ignore, invoke this method for each type. - /// - /// . - public void IgnoreDependencyInterface(Type type) - { - ignoredDependencyInterfaces.Add(type); - } - - // /// - // /// Create an object instance for the given object definition. - // /// - // /// The name of the object. - // /// - // /// The object definition for the object that is to be instantiated. - // /// - // /// - // /// The arguments to use if creating a prototype using explicit arguments to - // /// a static factory method. It is invalid to use a non- arguments value - // /// in any other case. - // /// - // /// - // /// A new instance of the object. - // /// - // /// - // /// In case of errors. - // /// - // /// - // ///

- // /// Delegates to the - // /// - // /// method version with the allowEagerCaching parameter set to true. - // ///

- // ///

- // /// The object definition will already have been merged with the parent - // /// definition in case of a child definition. - // ///

- // ///

- // /// All the other methods in this class invoke this method, although objects - // /// may be cached after being instantiated by this method. All object - // /// instantiation within this class is performed by this method. - // ///

- // ///
- // protected internal override object CreateObject(string name, RootObjectDefinition definition, object[] arguments) - // { - // return CreateObject(name, definition, arguments, true, false); - // } - - /// - /// Create an object instance for the given object definition. - /// - /// The name of the object. - /// - /// The object definition for the object that is to be instantiated. - /// - /// - /// The arguments to use if creating a prototype using explicit arguments to - /// a static factory method. It is invalid to use a non- arguments value - /// in any other case. - /// - /// - /// Whether eager caching of singletons is allowed... typically true for - /// singlton objects, but never true for inner object definitions. - /// - /// - /// Suppress injecting dependencies yet. - /// - /// - /// A new instance of the object. - /// - /// - /// In case of errors. - /// - /// - ///

- /// The object definition will already have been merged with the parent - /// definition in case of a child definition. - ///

- ///

- /// All the other methods in this class invoke this method, although objects - /// may be cached after being instantiated by this method. All object - /// instantiation within this class is performed by this method. - ///

- ///
- protected internal override object InstantiateObject(string name, RootObjectDefinition definition, object[] arguments, bool allowEagerCaching, bool suppressConfigure) - { - // guarantee the initialization of objects that the current one depends on.. - if (definition.dependsOn != null) - { - for (var i = 0; i < definition.dependsOn.Count; i++) - { - string dependant = definition.dependsOn[i]; - GetObject(dependant); - } - } - - var isDebugEnabled = log.IsEnabled(LogLevel.Debug); - if (isDebugEnabled) - { - log.LogDebug($"Creating instance of Object '{name}' with merged definition [{definition}]."); - } - - // Make sure object type is actually resolved at this point. - ResolveObjectType(definition, name); - - try - { - definition.PrepareMethodOverrides(); - } - catch (ObjectDefinitionValidationException ex) - { - throw new ObjectDefinitionStoreException(definition.ResourceDescription, name, - "Validation of method overrides failed. " + ex.Message, ex); - } - - // return IObjectDefinition instance itself for an abstract object-definition - if (definition.IsTemplate) - { - return definition; - } - - object instance; - bool eagerlyCached = false; - try - { - // Give IInstantiationAwareObjectPostProcessors a chance to return a proxy instead of the target instance.... - if (definition.HasObjectType) - { - instance = ApplyObjectPostProcessorsBeforeInstantiation(definition.ObjectType, name); - if (instance != null) - { - return instance; - } - } - - var instanceWrapper = CreateObjectInstance(name, definition, arguments); - instance = instanceWrapper.WrappedInstance; - - // eagerly cache singletons to be able to resolve circular references - // even when triggered by lifecycle interfaces like IObjectFactoryAware. - if (allowEagerCaching && definition.IsSingleton) - { - if (isDebugEnabled) - { - log.LogDebug($"Eagerly caching object '{name}' to allow for resolving potential circular references"); - } - AddEagerlyCachedSingleton(name, definition, instance); - eagerlyCached = true; - } - - if (!suppressConfigure) - { - instance = ConfigureObject(name, definition, instanceWrapper); - } - } - catch (ObjectCreationException) - { - if (eagerlyCached) - { - RemoveEagerlyCachedSingleton(name, definition); - } - throw; - } - catch (Exception ex) - { - if (eagerlyCached) - { - RemoveEagerlyCachedSingleton(name, definition); - } - throw new ObjectCreationException(definition.ResourceDescription, name, "Initialization of object failed : " + ex.Message, ex); - } - return instance; - } - - /// - /// Add the created, but yet unpopulated singleton to the singleton cache - /// to be able to resolve circular references - /// - /// the name of the object to add to the cache. - /// the definition used to create and populated the object. - /// the raw object instance. - /// - /// Derived classes may override this method to select the right cache based on the object definition. - /// - protected virtual void AddEagerlyCachedSingleton(string objectName, IObjectDefinition objectDefinition, object rawSingletonInstance) - { - base.AddSingleton(objectName, rawSingletonInstance); - } - - /// - /// Remove the specified singleton from the singleton cache that has - /// been added before by a call to - /// - /// the name of the object to remove from the cache. - /// the definition used to create and populated the object. - /// - /// Derived classes may override this method to select the right cache based on the object definition. - /// - protected virtual void RemoveEagerlyCachedSingleton(string objectName, IObjectDefinition objectDefinition) - { - RemoveSingleton(objectName); - } - - /// - /// Creates an instance from the passed in - /// using constructor - /// - /// The name of the object to create - used for error messages. - /// The describing the object to be created. - /// optional arguments to pass to the constructor - /// An wrapping the already instantiated object - protected IObjectWrapper CreateObjectInstance(string objectName, RootObjectDefinition objectDefinition, object[] arguments) - { - // Make sure object class is actually resolved at this point. - Type objectType = ResolveObjectType(objectDefinition, objectName); - if (StringUtils.HasText(objectDefinition.FactoryMethodName)) - { - return InstantiateUsingFactoryMethod(objectName, objectDefinition, arguments); - } - - //TODO perf optimization when creating the same object - - ConstructorInfo[] ctors = DetermineConstructorsFromObjectPostProcessors(objectType, objectName); - if (ctors != null || - objectDefinition.ResolvedAutowireMode == AutoWiringMode.Constructor || - objectDefinition.HasConstructorArgumentValues || !ObjectUtils.IsEmpty(arguments)) - { - return AutowireConstructor(objectName, objectDefinition, ctors, arguments); - } - - // No special handling: simply use no-arg constructor. - return InstantiateObject(objectName, objectDefinition); - - /* - IObjectWrapper instanceWrapper; - if (StringUtils.HasText(definition.FactoryMethodName)) - { - instanceWrapper = InstantiateUsingFactoryMethod(name, definition, arguments); - } - //Handle case when arguments are passed in explicitly. - else if (arguments != null && arguments.Length > 0) - { - instanceWrapper = AutowireConstructor(name, definition, arguments); - } - else if (definition.ResolvedAutowireMode == AutoWiringMode.Constructor || - definition.HasConstructorArgumentValues) - { - instanceWrapper = AutowireConstructor(name, definition); - } - else - { - instanceWrapper = new ObjectWrapper(InstantiationStrategy.Instantiate(definition, name, this)); - InitObjectWrapper(instanceWrapper); - } - return instanceWrapper; - - */ - } - - /// - /// Instantiates the given object using its default constructor - /// - /// Name of the object. - /// The definition. - /// IObjectWrapper for the new instance - protected virtual IObjectWrapper InstantiateObject(string objectName, RootObjectDefinition definition) - { - return new ObjectWrapper(InstantiationStrategy.Instantiate(definition, objectName, this)); - } - - /// - /// Determines candidate constructors to use for the given object, checking all registered - /// - /// - /// Raw type of the object. - /// Name of the object. - /// the candidate constructors, or null if none specified - /// In case of errors - /// - protected virtual ConstructorInfo[] DetermineConstructorsFromObjectPostProcessors(Type objectType, string objectName) - { - if (HasInstantiationAwareObjectPostProcessors) - { - for (var i = 0; i < objectPostProcessors.Count; i++) - { - IObjectPostProcessor objectPostProcessor = objectPostProcessors[i]; - if (ObjectUtils.IsAssignable(typeof(SmartInstantiationAwareObjectPostProcessor), - objectPostProcessor)) - { - SmartInstantiationAwareObjectPostProcessor iop = - (SmartInstantiationAwareObjectPostProcessor) objectPostProcessor; - ConstructorInfo[] ctors = iop.DetermineCandidateConstructors(objectType, objectName); - if (ctors != null) - { - return ctors; - } - } - } - } - return null; - } - - /// - /// Instantiate an object instance using a named factory method. - /// - /// - ///

- /// The method may be static, if the - /// parameter specifies a class, rather than a - /// instance, or an - /// instance variable on a factory object itself configured using Dependency - /// Injection. - ///

- ///

- /// Implementation requires iterating over the static or instance methods - /// with the name specified in the supplied - /// (the method may be overloaded) and trying to match with the parameters. - /// We don't have the types attached to constructor args, so trial and error - /// is the only way to go here. - ///

- ///
- /// - /// The name associated with the supplied . - /// - /// - /// The definition describing the instance that is to be instantiated. - /// - /// - /// Any arguments to the factory method that is to be invoked. - /// - /// - /// The result of the factory method invocation (the instance). - /// - protected virtual IObjectWrapper InstantiateUsingFactoryMethod(string name, RootObjectDefinition definition, object[] arguments) - { - ConstructorResolver constructorResolver = - new ConstructorResolver(this, this, InstantiationStrategy, CreateValueResolver()); - return constructorResolver.InstantiateUsingFactoryMethod(name, definition, arguments); - } - - /// - /// "autowire constructor" (with constructor arguments by type) behaviour. - /// - /// The name of the object to autowire by type. - /// The object definition to update through autowiring. - /// The chosen candidate constructors. - /// The argument values passed in programmatically via the GetObject method, - /// or null if none (-> use constructor argument values from object definition) - /// - /// An for the new instance. - /// - /// - /// - /// Also applied if explicit constructor argument values are specified, - /// matching all remaining arguments with objects from the object factory. - /// - /// - /// This corresponds to constructor injection: in this mode, a Spring.NET - /// object factory is able to host components that expect constructor-based - /// dependency resolution. - /// - /// - protected IObjectWrapper AutowireConstructor(string name, RootObjectDefinition definition, ConstructorInfo[] ctors, object[] explicitArgs) - { - ConstructorResolver constructorResolver = - new ConstructorResolver(this, this, InstantiationStrategy, CreateValueResolver()); - return constructorResolver.AutowireConstructor(name, definition, ctors, explicitArgs); - - } - - /// - /// Perform a dependency check that all properties exposed have been set, if desired. - /// - /// - ///

- /// Dependency checks can be objects (collaborating objects), simple (primitives - /// and ), or all (both). - ///

- ///
- /// - /// The name of the object. - /// - /// - /// The definition of the named object. - /// - /// - /// The wrapping the target object. - /// - /// - /// The property values to be checked. - /// - /// - /// If all of the checked dependencies were not satisfied. - /// - protected void DependencyCheck(string name, IConfigurableObjectDefinition definition, IObjectWrapper wrapper, IPropertyValues properties) - { - DependencyCheckingMode dependencyCheck = definition.DependencyCheck; - if (dependencyCheck == DependencyCheckingMode.None) - { - return; - } - - IList filteredPropInfo = FilterPropertyInfoForDependencyCheck(wrapper); - if (HasInstantiationAwareObjectPostProcessors) - { - for (var i = 0; i < ObjectPostProcessors.Count; i++) - { - IObjectPostProcessor processor = ObjectPostProcessors[i]; - if (processor is IInstantiationAwareObjectPostProcessor inProc) - { - properties = inProc.PostProcessPropertyValues(properties, filteredPropInfo, wrapper.WrappedInstance, name); + filteredPropInfo = filteredPropInfo ?? FilterPropertyInfoForDependencyCheck(wrapper); + properties = instantiationAwareObjectPostProcessor.PostProcessPropertyValues(properties, + filteredPropInfo, wrapper.WrappedInstance, name); if (properties == null) { return; @@ -1163,823 +577,1423 @@ namespace Spring.Objects.Factory.Support } } - - CheckDependencies(name, definition, filteredPropInfo, properties); - } - - private void CheckDependencies(string name, IConfigurableObjectDefinition definition, IList filteredPropInfo, IPropertyValues properties) - { - DependencyCheckingMode dependencyCheck = definition.DependencyCheck; - IList unsatisfiedDependencies = AutowireUtils.GetUnsatisfiedDependencies(filteredPropInfo, properties, dependencyCheck); - - if (unsatisfiedDependencies.Count > 0) + if (needsDepCheck) { - throw new UnsatisfiedDependencyException(definition.ResourceDescription, name, unsatisfiedDependencies[0].Name, - "Set this property value or disable dependency checking for this object."); + filteredPropInfo = filteredPropInfo ?? FilterPropertyInfoForDependencyCheck(wrapper); + CheckDependencies(name, definition, filteredPropInfo, properties); } } - /// - /// Extract a filtered set of PropertyInfos from the given IObjectWrapper, excluding - /// ignored dependency types. - /// - /// The object wrapper the object was created with. - /// The filtered PropertyInfos - private List FilterPropertyInfoForDependencyCheck(IObjectWrapper wrapper) + ApplyPropertyValues(name, definition, wrapper, properties); + } + + /// + /// Wires up any exposed events in the object instance in the given + /// with any event handler + /// values from the . + /// + /// + /// The name of the object. + /// + /// + /// The definition of the named object. + /// + /// + /// The wrapping the target object. + /// + protected void WireEvents(string name, IConfigurableObjectDefinition definition, IObjectWrapper wrapper) + { + foreach (string eventName in definition.EventHandlerValues.Events) { - return filteredPropertyDescriptorsCache.GetOrAdd(wrapper.WrappedType, t => + foreach (IEventHandlerValue handlerValue + in definition.EventHandlerValues[eventName]) { - var list = new List(wrapper.GetPropertyInfos()); - for (int i = list.Count - 1; i >= 0; i--) + object handler = null; + if (handlerValue.Source is RuntimeObjectReference) { - PropertyInfo pi = list[i]; - if (IsExcludedFromDependencyCheck(pi)) - { - list.RemoveAt(i); - } + RuntimeObjectReference roref = (RuntimeObjectReference) handlerValue.Source; + handler = ResolveReference(definition, name, eventName, roref); + } + else if (handlerValue.Source is Type) + { + // a static Type event is being wired up; simply pass on the Type + handler = handlerValue.Source; + } + else if (handlerValue.Source is string) + { + // a static Type event is being wired up; we need to resolve the Type + handler = TypeResolutionUtils.ResolveType(handlerValue.Source as string); + } + else + { + throw new FatalObjectException("Currently, only references to other objects and Types are " + "supported as event sources."); } - return list; - }); + handlerValue.Wire(handler, wrapper.WrappedInstance); + } } + } - /// - /// Determine whether the given bean property is excluded from dependency checks. - /// This implementation excludes properties whose type matches an ignored dependency type - /// or which are defined by an ignored dependency interface. - /// - /// - /// - /// the of the object property - /// whether the object property is excluded - private bool IsExcludedFromDependencyCheck(PropertyInfo property) + /// + /// Fills in any missing property values with references to + /// other objects in this factory if autowire is set to + /// . + /// + /// + /// The object name to be autowired by . + /// + /// + /// The definition of the named object to update through autowiring. + /// + /// + /// The wrapping the target object (and + /// from which we can rip out information concerning the object). + /// + /// + /// The property values to register wired objects with. + /// + protected void AutowireByName(string name, RootObjectDefinition definition, IObjectWrapper wrapper, MutablePropertyValues properties) + { + string[] propertyNames = UnsatisfiedNonSimpleProperties(definition, wrapper); + foreach (string propertyName in propertyNames) { - bool b1 = !property.CanWrite; //AutowireUtils.IsExcludedFromDependencyCheck(pi); - bool b2 = IgnoredDependencyTypes.Contains(property.PropertyType); - bool b3 = AutowireUtils.IsSetterDefinedInInterface(property, ignoredDependencyInterfaces); - return b1 || b2 || b3; - /* - return AutowireUtils.IsExcludedFromDependencyCheck(pi) || - IgnoredDependencyTypes.Contains(pi.PropertyType) || - AutowireUtils.IsSetterDefinedInInterface(pi, ignoredDependencyInterfaces); - */ - } - - /// - /// Give an object a chance to react now all its properties are set, - /// and a chance to know about its owning object factory (this object). - /// - /// - ///

- /// This means checking whether the object implements - /// and / or - /// , and invoking the - /// necessary callback(s) if it does. - ///

- ///

- /// Custom init methods are resolved in a case-insensitive manner. - ///

- ///
- /// - /// The new object instance we may need to initialise. - /// - /// - /// The name the object has in the factory. Used for logging output. - /// - /// - /// The definition of the target object instance. - /// - protected virtual void InvokeInitMethods(object target, string name, IConfigurableObjectDefinition definition) - { - if (ObjectUtils.IsAssignableAndNotTransparentProxy(typeof(IInitializingObject), target)) + // look for a matching type + if (ContainsObject(propertyName)) { + object o = GetObject(propertyName); + properties.Add(propertyName, o); + if (log.IsEnabled(LogLevel.Debug)) { - log.LogDebug(string.Format(CultureInfo.InvariantCulture, "Calling AfterPropertiesSet() on object with name '{0}'.", name)); + log.LogDebug(string.Format(CultureInfo.InvariantCulture, + "Added autowiring by name from object name '{0}' via " + "property '{1}' to object named '{1}'.", name, + propertyName)); } - - ((IInitializingObject)target).AfterPropertiesSet(); - } - if (StringUtils.HasText(definition.InitMethodName)) - { - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug(string.Format(CultureInfo.InvariantCulture, "Calling custom init method '{0} on object with name '{1}'.", - definition.InitMethodName, name)); - } - - try - { - MethodInfo targetMethod = target.GetType().GetMethod(definition.InitMethodName, MethodResolutionFlags, null, Type.EmptyTypes, null); - if (targetMethod == null) - { - throw new ObjectCreationException(definition.ResourceDescription, name, - "Could not find the named initialization method '" + definition.InitMethodName + "'."); - } - targetMethod.Invoke(target, ObjectUtils.EmptyObjects); - } - catch (TargetInvocationException ex) - { - throw new ObjectCreationException(definition.ResourceDescription, name, - "Initialization method '" + definition.InitMethodName + "' threw exception", ex.GetBaseException()); - } - catch (Exception ex) - { - throw new ObjectCreationException(definition.ResourceDescription, name, - "Invocation of initialization method '" + definition.InitMethodName + "' failed", ex); - } - } - } - - /// - /// Invoke the specified custom destroy method on the given object. - /// - /// - ///

- /// This implementation invokes a no-arg method if found, else checking - /// for a method with a single boolean argument (passing in "true", - /// assuming a "force" parameter), else logging an error. - ///

- ///

- /// Can be overridden in subclasses for custom resolution of destroy - /// methods with arguments. - ///

- ///

- /// Custom destroy methods are resolved in a case-insensitive manner. - ///

- ///
- protected virtual void InvokeCustomDestroyMethod(string name, object target, string destroyMethodName) - { - bool usingForcingVersion = false; - MethodInfo targetMethod = target.GetType().GetMethod(destroyMethodName, MethodResolutionFlags, null, Type.EmptyTypes, null); - if (targetMethod == null) - { - // #%&^! try to find the method with a boolean "force" parameter - targetMethod = target.GetType().GetMethod(destroyMethodName, MethodResolutionFlags, null, new Type[] { typeof(bool) }, null); - if (targetMethod != null) - { - usingForcingVersion = true; - } - } - if (targetMethod == null) - { - log.LogError("Couldn't find a method named '" + destroyMethodName + "' on object with name '" + name + "'"); } else { - object[] args = usingForcingVersion ? new object[] { true } : ObjectUtils.EmptyObjects; - try + if (log.IsEnabled(LogLevel.Debug)) { - targetMethod.Invoke(target, args); - } - catch (TargetInvocationException ex) - { - string message = "Couldn't invoke destroy method '" + destroyMethodName + "' of object with name '" + name + "'"; - log.LogError(ex.GetBaseException(), message); - } - catch (Exception ex) - { - LogExceptionRaisedByCustomDestroyMethodInvocation(destroyMethodName, name, ex); + log.LogDebug(string.Format(CultureInfo.InvariantCulture, + "Not autowiring property '{0}' of object '{1}' by name: " + "no matching object found.", propertyName, name)); } } } + } - private void LogExceptionRaisedByCustomDestroyMethodInvocation(string destroyMethodName, string name, Exception ex) + /// + /// Defines "autowire by type" (object properties by type) behavior. + /// + /// + ///

+ /// This is like PicoContainer default, in which there must be exactly one object + /// of the property type in the object factory. This makes object factories simple + /// to configure for small namespaces, but doesn't work as well as standard Spring + /// behavior for bigger applications. + ///

+ ///
+ /// + /// The object name to be autowired by . + /// + /// + /// The definition of the named object to update through autowiring. + /// + /// + /// The wrapping the target object (and + /// from which we can rip out information concerning the object). + /// + /// + /// The property values to register wired objects with. + /// + protected void AutowireByType(string name, RootObjectDefinition definition, IObjectWrapper wrapper, MutablePropertyValues properties) + { + string[] propertyNames = UnsatisfiedNonSimpleProperties(definition, wrapper); + foreach (string propertyName in propertyNames) { - string message = string.Format(CultureInfo.InvariantCulture, "Couldn't invoke destroy method '{0}' of object with name '{1}'.", destroyMethodName, name); - log.LogError(ex, message); - } - - /// - /// Destroy the target object. - /// - /// - ///

- /// Must destroy objects that depend on the given object before the object itself. - /// Should not throw any exceptions. - ///

- ///
- /// - /// The name of the object. - /// - /// - /// The target object instance to destroyed. - /// - protected override void DestroyObject(string name, object target) - { - using (new DisposableObjectAdapter(target, name, GetMergedObjectDefinition(name, true), ObjectPostProcessors)) + // look for a matching type + Type requiredType = wrapper.GetPropertyType(propertyName); + IDictionary matchingObjects = FindMatchingObjects(requiredType); + if (matchingObjects != null && matchingObjects.Count == 1) { - log.LogDebug("Destroying dependant objects for object '{ObjectName}", name); - DestroyDependantObjects(name); - } - } + properties.Add(propertyName, ObjectUtils.EnumerateFirstElement(matchingObjects.Values)); - /// - /// Destroys all of the objects registered as dependant on the - /// object (definition) identified by the supplied . - /// - /// - /// The name of the root object (definition) that is itself being destroyed. - /// - private void DestroyDependantObjects(string name) - { - IList dependingObjects = GetDependingObjectNames(name); - foreach (string doName in dependingObjects) + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug(string.Format(CultureInfo.InvariantCulture, + "Autowiring by type from object name '{0}' via property " + "'{1}' to object named '{2}'.", name, + propertyName, ObjectUtils.EnumerateFirstElement(matchingObjects.Keys))); + } + } + else if (matchingObjects != null && matchingObjects.Count > 1) { - DestroySingleton(doName); + throw new UnsatisfiedDependencyException(string.Empty, name, propertyName, + string.Format(CultureInfo.InvariantCulture, + "There are {0} objects of Type [{1}] for autowire by " + + "type, when there should have been just 1 to be able to " + + "autowire property '{2}' of object '{3}'.", matchingObjects.Count, + requiredType, propertyName, name)); + } + else + { + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug(string.Format(CultureInfo.InvariantCulture, "Not autowiring property '{0}' of object '{1}': no matching object found.", + propertyName, name)); + } + } + } + } + + /// + /// Ignore the given dependency type for autowiring + /// + /// + /// This will typically be used by application contexts to register + /// dependencies that are resolved in other ways, like IOjbectFactory through + /// IObjectFactoryAware or IApplicationContext through IApplicationContextAware. + /// By default, IObjectFactoryAware and IObjectName interfaces are ignored. + /// For further types to ignore, invoke this method for each type. + /// + /// . + public void IgnoreDependencyInterface(Type type) + { + ignoredDependencyInterfaces.Add(type); + } + + // /// + // /// Create an object instance for the given object definition. + // /// + // /// The name of the object. + // /// + // /// The object definition for the object that is to be instantiated. + // /// + // /// + // /// The arguments to use if creating a prototype using explicit arguments to + // /// a static factory method. It is invalid to use a non- arguments value + // /// in any other case. + // /// + // /// + // /// A new instance of the object. + // /// + // /// + // /// In case of errors. + // /// + // /// + // ///

+ // /// Delegates to the + // /// + // /// method version with the allowEagerCaching parameter set to true. + // ///

+ // ///

+ // /// The object definition will already have been merged with the parent + // /// definition in case of a child definition. + // ///

+ // ///

+ // /// All the other methods in this class invoke this method, although objects + // /// may be cached after being instantiated by this method. All object + // /// instantiation within this class is performed by this method. + // ///

+ // ///
+ // protected internal override object CreateObject(string name, RootObjectDefinition definition, object[] arguments) + // { + // return CreateObject(name, definition, arguments, true, false); + // } + + /// + /// Create an object instance for the given object definition. + /// + /// The name of the object. + /// + /// The object definition for the object that is to be instantiated. + /// + /// + /// The arguments to use if creating a prototype using explicit arguments to + /// a static factory method. It is invalid to use a non- arguments value + /// in any other case. + /// + /// + /// Whether eager caching of singletons is allowed... typically true for + /// singlton objects, but never true for inner object definitions. + /// + /// + /// Suppress injecting dependencies yet. + /// + /// + /// A new instance of the object. + /// + /// + /// In case of errors. + /// + /// + ///

+ /// The object definition will already have been merged with the parent + /// definition in case of a child definition. + ///

+ ///

+ /// All the other methods in this class invoke this method, although objects + /// may be cached after being instantiated by this method. All object + /// instantiation within this class is performed by this method. + ///

+ ///
+ protected internal override object InstantiateObject(string name, RootObjectDefinition definition, object[] arguments, bool allowEagerCaching, bool suppressConfigure) + { + // guarantee the initialization of objects that the current one depends on.. + if (definition.dependsOn != null) + { + for (var i = 0; i < definition.dependsOn.Count; i++) + { + string dependant = definition.dependsOn[i]; + GetObject(dependant); } } - ///// - ///// Given a property value, return a value, resolving any references to other - ///// objects in the factory if necessary. - ///// - ///// - /////

- ///// The value could be : - ///// - ///// - /////

- ///// An , - ///// which leads to the creation of a corresponding new object instance. - ///// Singleton flags and names of such "inner objects" are always ignored: inner objects - ///// are anonymous prototypes. - /////

- ///// - ///// - /////

- ///// A , which must - ///// be resolved. - /////

- /////
- ///// - /////

- ///// An . This is a - ///// special placeholder collection that may contain - ///// s or - ///// collections that will need to be resolved. - /////

- /////
- ///// - /////

- ///// An ordinary object or , in which case it's left alone. - /////

- /////
- ///// - /////

- /////
- ///// - ///// The name of the object that is having the value of one of its properties resolved. - ///// - ///// - ///// The definition of the named object. - ///// - ///// - ///// The name of the property the value of which is being resolved. - ///// - ///// - ///// The value of the property that is being resolved. - ///// - // protected object ResolveValueIfNecessary(string name, RootObjectDefinition definition, string argumentName, object argumentValue) - // { - // object resolvedValue = null; - // - // AssertUtils.ArgumentNotNull(resolvedValue, "test"); - // - // // we must check the argument value to see whether it requires a runtime - // // reference to another object to be resolved. - // // if it does, we'll attempt to instantiate the object and set the reference. - // if (RemotingServices.IsTransparentProxy(argumentValue)) - // { - // resolvedValue = argumentValue; - // } - // else if (argumentValue is ObjectDefinitionHolder) - // { - // // contains an IObjectDefinition with name and aliases... - // ObjectDefinitionHolder holder = (ObjectDefinitionHolder)argumentValue; - // resolvedValue = ResolveInnerObjectDefinition(name, holder.ObjectName, argumentName, holder.ObjectDefinition, definition.IsSingleton); - // } - // else if (argumentValue is IObjectDefinition) - // { - // // resolve plain IObjectDefinition, without contained name: use dummy name... - // IObjectDefinition def = (IObjectDefinition)argumentValue; - // resolvedValue = ResolveInnerObjectDefinition(name, "(inner object)", argumentName, def, definition.IsSingleton); - // - // } - // else if (argumentValue is RuntimeObjectReference) - // { - // RuntimeObjectReference roref = (RuntimeObjectReference)argumentValue; - // resolvedValue = ResolveReference(definition, name, argumentName, roref); - // } - // else if (argumentValue is ExpressionHolder) - // { - // ExpressionHolder expHolder = (ExpressionHolder)argumentValue; - // object context = null; - // IDictionary variables = null; - // - // if (expHolder.Properties != null) - // { - // PropertyValue contextProperty = expHolder.Properties.GetPropertyValue("Context"); - // context = contextProperty == null - // ? null - // : ResolveValueIfNecessary2(name, definition, "Context", - // contextProperty.Value); - // PropertyValue variablesProperty = expHolder.Properties.GetPropertyValue("Variables"); - // object vars = (variablesProperty == null - // ? null - // : ResolveValueIfNecessary2(name, definition, "Variables", - // variablesProperty.Value)); - // if (vars is IDictionary) - // { - // variables = (IDictionary)vars; - // } - // else - // { - // if (vars != null) throw new ArgumentException("'Variables' must resolve to an IDictionary"); - // } - // } - // - // if (variables == null) variables = CollectionsUtil.CreateCaseInsensitiveHashtable(); - // // add 'this' objectfactory reference to variables - // variables.Add(Expression.ReservedVariableNames.CurrentObjectFactory, this); - // - // resolvedValue = expHolder.Expression.GetValue(context, variables); - // } - // else if (argumentValue is IManagedCollection) - // { - // resolvedValue = - // ((IManagedCollection)argumentValue).Resolve(name, definition, argumentName, - // new ManagedCollectionElementResolver(ResolveValueIfNecessary2)); - // } - // else if (argumentValue is TypedStringValue) - // { - // TypedStringValue tsv = (TypedStringValue)argumentValue; - // try - // { - // Type resolvedTargetType = ResolveTargetType(tsv); - // if (resolvedTargetType != null) - // { - // resolvedValue = TypeConversionUtils.ConvertValueIfNecessary(tsv.TargetType, tsv.Value, null); - // } - // else - // { - // resolvedValue = tsv.Value; - // } - // } - // catch (Exception ex) - // { - // throw new ObjectCreationException(definition.ResourceDescription, name, - // "Error converted typed String value for " + argumentName, ex); - // } - // - // } - // else - // { - // // no need to resolve value... - // resolvedValue = argumentValue; - // } - // return resolvedValue; - // } + var isDebugEnabled = log.IsEnabled(LogLevel.Debug); + if (isDebugEnabled) + { + log.LogDebug($"Creating instance of Object '{name}' with merged definition [{definition}]."); + } - ///// - ///// Resolve the target type of the passed . - ///// - ///// The who's target type is to be resolved - ///// The resolved target type, if any. otherwise. - // protected virtual Type ResolveTargetType(TypedStringValue value) - // { - // if (value.HasTargetType) - // { - // return value.TargetType; - // } - // else - // { - // return null; - // } - // } + // Make sure object type is actually resolved at this point. + ResolveObjectType(definition, name); - ///// - ///// Resolves an inner object definition. - ///// - ///// - ///// The name of the object that surrounds this inner object definition. - ///// - ///// - ///// The name of the inner object definition... note: this is a synthetic - ///// name assigned by the factory (since it makes no sense for inner object - ///// definitions to have names). - ///// - ///// - ///// The name of the property the value of which is being resolved. - ///// - ///// - ///// The definition of the inner object that is to be resolved. - ///// - ///// - ///// if the owner of the property is a singleton. - ///// - ///// - ///// The resolved object as defined by the inner object definition. - ///// - // protected object ResolveInnerObjectDefinition(string name, string innerObjectName, string argumentName, IObjectDefinition definition, - // bool singletonOwner) - // { - // RootObjectDefinition mod = GetMergedObjectDefinition(innerObjectName, definition); - // mod.IsSingleton = singletonOwner; - // object instance; - // object result; - // try - // { - // instance = InstantiateObject(innerObjectName, mod, ObjectUtils.EmptyObjects, false, false); - // result = GetObjectForInstance(innerObjectName, instance); - // } - // catch (ObjectsException ex) - // { - // throw ObjectCreationException.GetObjectCreationException(ex, name, argumentName, definition.ResourceDescription, innerObjectName); - // } - // if (singletonOwner && instance is IDisposable) - // { - // // keep a reference to the inner object instance, to be able to destroy - // // it on factory shutdown... - // DisposableInnerObjects.Add(instance); - // } - // return result; - // } + try + { + definition.PrepareMethodOverrides(); + } + catch (ObjectDefinitionValidationException ex) + { + throw new ObjectDefinitionStoreException(definition.ResourceDescription, name, + "Validation of method overrides failed. " + ex.Message, ex); + } - /// - /// Resolve a reference to another object in the factory. - /// - /// - /// The name of the object that is having the value of one of its properties resolved. - /// - /// - /// The definition of the named object. - /// - /// - /// The name of the property the value of which is being resolved. - /// - /// - /// The runtime reference containing the value of the property. - /// - /// A reference to another object in the factory. - protected object ResolveReference(IConfigurableObjectDefinition definition, string name, string argumentName, RuntimeObjectReference reference) + // return IObjectDefinition instance itself for an abstract object-definition + if (definition.IsTemplate) + { + return definition; + } + + object instance; + bool eagerlyCached = false; + try + { + // Give IInstantiationAwareObjectPostProcessors a chance to return a proxy instead of the target instance.... + if (definition.HasObjectType) + { + instance = ApplyObjectPostProcessorsBeforeInstantiation(definition.ObjectType, name); + if (instance != null) + { + return instance; + } + } + + var instanceWrapper = CreateObjectInstance(name, definition, arguments); + instance = instanceWrapper.WrappedInstance; + + // eagerly cache singletons to be able to resolve circular references + // even when triggered by lifecycle interfaces like IObjectFactoryAware. + if (allowEagerCaching && definition.IsSingleton) + { + if (isDebugEnabled) + { + log.LogDebug($"Eagerly caching object '{name}' to allow for resolving potential circular references"); + } + + AddEagerlyCachedSingleton(name, definition, instance); + eagerlyCached = true; + } + + if (!suppressConfigure) + { + instance = ConfigureObject(name, definition, instanceWrapper); + } + } + catch (ObjectCreationException) + { + if (eagerlyCached) + { + RemoveEagerlyCachedSingleton(name, definition); + } + + throw; + } + catch (Exception ex) + { + if (eagerlyCached) + { + RemoveEagerlyCachedSingleton(name, definition); + } + + throw new ObjectCreationException(definition.ResourceDescription, name, "Initialization of object failed : " + ex.Message, ex); + } + + return instance; + } + + /// + /// Add the created, but yet unpopulated singleton to the singleton cache + /// to be able to resolve circular references + /// + /// the name of the object to add to the cache. + /// the definition used to create and populated the object. + /// the raw object instance. + /// + /// Derived classes may override this method to select the right cache based on the object definition. + /// + protected virtual void AddEagerlyCachedSingleton(string objectName, IObjectDefinition objectDefinition, object rawSingletonInstance) + { + base.AddSingleton(objectName, rawSingletonInstance); + } + + /// + /// Remove the specified singleton from the singleton cache that has + /// been added before by a call to + /// + /// the name of the object to remove from the cache. + /// the definition used to create and populated the object. + /// + /// Derived classes may override this method to select the right cache based on the object definition. + /// + protected virtual void RemoveEagerlyCachedSingleton(string objectName, IObjectDefinition objectDefinition) + { + RemoveSingleton(objectName); + } + + /// + /// Creates an instance from the passed in + /// using constructor + /// + /// The name of the object to create - used for error messages. + /// The describing the object to be created. + /// optional arguments to pass to the constructor + /// An wrapping the already instantiated object + protected IObjectWrapper CreateObjectInstance(string objectName, RootObjectDefinition objectDefinition, object[] arguments) + { + // Make sure object class is actually resolved at this point. + Type objectType = ResolveObjectType(objectDefinition, objectName); + if (StringUtils.HasText(objectDefinition.FactoryMethodName)) + { + return InstantiateUsingFactoryMethod(objectName, objectDefinition, arguments); + } + + //TODO perf optimization when creating the same object + + ConstructorInfo[] ctors = DetermineConstructorsFromObjectPostProcessors(objectType, objectName); + if (ctors != null || + objectDefinition.ResolvedAutowireMode == AutoWiringMode.Constructor || + objectDefinition.HasConstructorArgumentValues || !ObjectUtils.IsEmpty(arguments)) + { + return AutowireConstructor(objectName, objectDefinition, ctors, arguments); + } + + // No special handling: simply use no-arg constructor. + return InstantiateObject(objectName, objectDefinition); + + /* + IObjectWrapper instanceWrapper; + if (StringUtils.HasText(definition.FactoryMethodName)) + { + instanceWrapper = InstantiateUsingFactoryMethod(name, definition, arguments); + } + //Handle case when arguments are passed in explicitly. + else if (arguments != null && arguments.Length > 0) + { + instanceWrapper = AutowireConstructor(name, definition, arguments); + } + else if (definition.ResolvedAutowireMode == AutoWiringMode.Constructor || + definition.HasConstructorArgumentValues) + { + instanceWrapper = AutowireConstructor(name, definition); + } + else + { + instanceWrapper = new ObjectWrapper(InstantiationStrategy.Instantiate(definition, name, this)); + InitObjectWrapper(instanceWrapper); + } + return instanceWrapper; + + */ + } + + /// + /// Instantiates the given object using its default constructor + /// + /// Name of the object. + /// The definition. + /// IObjectWrapper for the new instance + protected virtual IObjectWrapper InstantiateObject(string objectName, RootObjectDefinition definition) + { + return new ObjectWrapper(InstantiationStrategy.Instantiate(definition, objectName, this)); + } + + /// + /// Determines candidate constructors to use for the given object, checking all registered + /// + /// + /// Raw type of the object. + /// Name of the object. + /// the candidate constructors, or null if none specified + /// In case of errors + /// + protected virtual ConstructorInfo[] DetermineConstructorsFromObjectPostProcessors(Type objectType, string objectName) + { + if (HasInstantiationAwareObjectPostProcessors) + { + for (var i = 0; i < objectPostProcessors.Count; i++) + { + IObjectPostProcessor objectPostProcessor = objectPostProcessors[i]; + if (ObjectUtils.IsAssignable(typeof(SmartInstantiationAwareObjectPostProcessor), + objectPostProcessor)) + { + SmartInstantiationAwareObjectPostProcessor iop = + (SmartInstantiationAwareObjectPostProcessor) objectPostProcessor; + ConstructorInfo[] ctors = iop.DetermineCandidateConstructors(objectType, objectName); + if (ctors != null) + { + return ctors; + } + } + } + } + + return null; + } + + /// + /// Instantiate an object instance using a named factory method. + /// + /// + ///

+ /// The method may be static, if the + /// parameter specifies a class, rather than a + /// instance, or an + /// instance variable on a factory object itself configured using Dependency + /// Injection. + ///

+ ///

+ /// Implementation requires iterating over the static or instance methods + /// with the name specified in the supplied + /// (the method may be overloaded) and trying to match with the parameters. + /// We don't have the types attached to constructor args, so trial and error + /// is the only way to go here. + ///

+ ///
+ /// + /// The name associated with the supplied . + /// + /// + /// The definition describing the instance that is to be instantiated. + /// + /// + /// Any arguments to the factory method that is to be invoked. + /// + /// + /// The result of the factory method invocation (the instance). + /// + protected virtual IObjectWrapper InstantiateUsingFactoryMethod(string name, RootObjectDefinition definition, object[] arguments) + { + ConstructorResolver constructorResolver = + new ConstructorResolver(this, this, InstantiationStrategy, CreateValueResolver()); + return constructorResolver.InstantiateUsingFactoryMethod(name, definition, arguments); + } + + /// + /// "autowire constructor" (with constructor arguments by type) behaviour. + /// + /// The name of the object to autowire by type. + /// The object definition to update through autowiring. + /// The chosen candidate constructors. + /// The argument values passed in programmatically via the GetObject method, + /// or null if none (-> use constructor argument values from object definition) + /// + /// An for the new instance. + /// + /// + /// + /// Also applied if explicit constructor argument values are specified, + /// matching all remaining arguments with objects from the object factory. + /// + /// + /// This corresponds to constructor injection: in this mode, a Spring.NET + /// object factory is able to host components that expect constructor-based + /// dependency resolution. + /// + /// + protected IObjectWrapper AutowireConstructor(string name, RootObjectDefinition definition, ConstructorInfo[] ctors, object[] explicitArgs) + { + ConstructorResolver constructorResolver = + new ConstructorResolver(this, this, InstantiationStrategy, CreateValueResolver()); + return constructorResolver.AutowireConstructor(name, definition, ctors, explicitArgs); + } + + /// + /// Perform a dependency check that all properties exposed have been set, if desired. + /// + /// + ///

+ /// Dependency checks can be objects (collaborating objects), simple (primitives + /// and ), or all (both). + ///

+ ///
+ /// + /// The name of the object. + /// + /// + /// The definition of the named object. + /// + /// + /// The wrapping the target object. + /// + /// + /// The property values to be checked. + /// + /// + /// If all of the checked dependencies were not satisfied. + /// + protected void DependencyCheck(string name, IConfigurableObjectDefinition definition, IObjectWrapper wrapper, IPropertyValues properties) + { + DependencyCheckingMode dependencyCheck = definition.DependencyCheck; + if (dependencyCheck == DependencyCheckingMode.None) + { + return; + } + + IList filteredPropInfo = FilterPropertyInfoForDependencyCheck(wrapper); + if (HasInstantiationAwareObjectPostProcessors) + { + for (var i = 0; i < ObjectPostProcessors.Count; i++) + { + IObjectPostProcessor processor = ObjectPostProcessors[i]; + if (processor is IInstantiationAwareObjectPostProcessor inProc) + { + properties = inProc.PostProcessPropertyValues(properties, filteredPropInfo, wrapper.WrappedInstance, name); + if (properties == null) + { + return; + } + } + } + } + + CheckDependencies(name, definition, filteredPropInfo, properties); + } + + private void CheckDependencies(string name, IConfigurableObjectDefinition definition, IList filteredPropInfo, IPropertyValues properties) + { + DependencyCheckingMode dependencyCheck = definition.DependencyCheck; + IList unsatisfiedDependencies = AutowireUtils.GetUnsatisfiedDependencies(filteredPropInfo, properties, dependencyCheck); + + if (unsatisfiedDependencies.Count > 0) + { + throw new UnsatisfiedDependencyException(definition.ResourceDescription, name, unsatisfiedDependencies[0].Name, + "Set this property value or disable dependency checking for this object."); + } + } + + /// + /// Extract a filtered set of PropertyInfos from the given IObjectWrapper, excluding + /// ignored dependency types. + /// + /// The object wrapper the object was created with. + /// The filtered PropertyInfos + private List FilterPropertyInfoForDependencyCheck(IObjectWrapper wrapper) + { + return filteredPropertyDescriptorsCache.GetOrAdd(wrapper.WrappedType, t => + { + var list = new List(wrapper.GetPropertyInfos()); + for (int i = list.Count - 1; i >= 0; i--) + { + PropertyInfo pi = list[i]; + if (IsExcludedFromDependencyCheck(pi)) + { + list.RemoveAt(i); + } + } + + return list; + }); + } + + /// + /// Determine whether the given bean property is excluded from dependency checks. + /// This implementation excludes properties whose type matches an ignored dependency type + /// or which are defined by an ignored dependency interface. + /// + /// + /// + /// the of the object property + /// whether the object property is excluded + private bool IsExcludedFromDependencyCheck(PropertyInfo property) + { + bool b1 = !property.CanWrite; //AutowireUtils.IsExcludedFromDependencyCheck(pi); + bool b2 = IgnoredDependencyTypes.Contains(property.PropertyType); + bool b3 = AutowireUtils.IsSetterDefinedInInterface(property, ignoredDependencyInterfaces); + return b1 || b2 || b3; + /* + return AutowireUtils.IsExcludedFromDependencyCheck(pi) || + IgnoredDependencyTypes.Contains(pi.PropertyType) || + AutowireUtils.IsSetterDefinedInInterface(pi, ignoredDependencyInterfaces); + */ + } + + /// + /// Give an object a chance to react now all its properties are set, + /// and a chance to know about its owning object factory (this object). + /// + /// + ///

+ /// This means checking whether the object implements + /// and / or + /// , and invoking the + /// necessary callback(s) if it does. + ///

+ ///

+ /// Custom init methods are resolved in a case-insensitive manner. + ///

+ ///
+ /// + /// The new object instance we may need to initialise. + /// + /// + /// The name the object has in the factory. Used for logging output. + /// + /// + /// The definition of the target object instance. + /// + protected virtual void InvokeInitMethods(object target, string name, IConfigurableObjectDefinition definition) + { + if (ObjectUtils.IsAssignableAndNotTransparentProxy(typeof(IInitializingObject), target)) { if (log.IsEnabled(LogLevel.Debug)) { - log.LogDebug(string.Format(CultureInfo.InvariantCulture, "Resolving reference from property '{0}' in object '{1}' to object '{2}'.", - argumentName, name, reference.ObjectName)); + log.LogDebug(string.Format(CultureInfo.InvariantCulture, "Calling AfterPropertiesSet() on object with name '{0}'.", name)); + } + + ((IInitializingObject) target).AfterPropertiesSet(); + } + + if (StringUtils.HasText(definition.InitMethodName)) + { + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug(string.Format(CultureInfo.InvariantCulture, "Calling custom init method '{0} on object with name '{1}'.", + definition.InitMethodName, name)); } try { - if (reference.IsToParent) + MethodInfo targetMethod = target.GetType().GetMethod(definition.InitMethodName, MethodResolutionFlags, null, Type.EmptyTypes, null); + if (targetMethod == null) { - if (null == ParentObjectFactory) - { - throw new ObjectCreationException(definition.ResourceDescription, name, - string.Format( - "Can't resolve reference to '{0}' in parent factory: " + "no parent factory available.", - reference.ObjectName)); - } - return ParentObjectFactory.GetObject(reference.ObjectName); - } - return GetObject(reference.ObjectName); - } - catch (ObjectsException ex) - { - throw ObjectCreationException.GetObjectCreationException(ex, name, argumentName, definition.ResourceDescription, reference.ObjectName); - } - } - - /// - /// Find object instances that match the required . - /// - /// - ///

- /// Called by autowiring. If a subclass cannot obtain information about object - /// names by , a corresponding exception should be thrown. - ///

- ///
- /// - /// The of the objects to look up. - /// - /// - /// An of object names and object - /// instances that match the required , or - /// if none are found. - /// - /// - /// In case of errors. - /// - protected abstract IDictionary FindMatchingObjects(Type requiredType); - - /// - /// Return the names of the objects that depend on the given object. - /// Called by DestroyObject, to be able to destroy depending objects first. - /// - /// - /// The name of the object to find depending objects for. - /// - /// - /// The array of names of depending objects, or the empty string array if none. - /// - /// - /// In case of errors. - /// - protected abstract IList GetDependingObjectNames(string name); - - /// - /// Injects dependencies into the supplied instance - /// using the named object definition. - /// - /// - /// The object instance that is to be so configured. - /// - /// - /// The name of the object definition expressing the dependencies that are to - /// be injected into the supplied instance. - /// - /// - public override object ConfigureObject(object target, string name) - { - MarkObjectAsCreated(name); - RootObjectDefinition definition = GetMergedObjectDefinition(name, true); - if (definition != null) - { - return ConfigureObject(name, definition, new ObjectWrapper(target)); - } - - return target; - } - - /// - /// Injects dependencies into the supplied instance - /// using the supplied . - /// - /// - /// The object instance that is to be so configured. - /// - /// - /// The name of the object definition expressing the dependencies that are to - /// be injected into the supplied instance. - /// - /// - /// An object definition that should be used to configure object. - /// - /// - public override object ConfigureObject(object target, string name, IObjectDefinition definition) - { - return ConfigureObject(name, new RootObjectDefinition(definition), new ObjectWrapper(target)); - } - - /// - /// Configures object instance by injecting dependencies, satisfying Spring lifecycle - /// interfaces and applying object post-processors. - /// - /// - /// The name of the object definition expressing the dependencies that are to - /// be injected into the supplied instance. - /// - /// - /// An object definition that should be used to configure object. - /// - /// - /// A wrapped object instance that is to be so configured. - /// - /// - protected virtual object ConfigureObject(string name, RootObjectDefinition definition, IObjectWrapper wrapper) - { - object instance = wrapper.WrappedInstance; - - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug($"Configuring object using definition '{name}'"); - } - - PopulateObject(name, definition, wrapper); - WireEvents(name, definition, wrapper); - - if (ObjectUtils.IsAssignableAndNotTransparentProxy(typeof(IObjectNameAware), instance)) - { - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug($"Setting the name property on the IObjectNameAware object '{name}'."); + throw new ObjectCreationException(definition.ResourceDescription, name, + "Could not find the named initialization method '" + definition.InitMethodName + "'."); } - ((IObjectNameAware)instance).ObjectName = name; + targetMethod.Invoke(target, ObjectUtils.EmptyObjects); } - - if (ObjectUtils.IsAssignableAndNotTransparentProxy(typeof(IObjectFactoryAware), instance)) + catch (TargetInvocationException ex) { - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug($"Setting the ObjectFactory property on the IObjectFactoryAware object '{name}'."); - } - - ((IObjectFactoryAware)instance).ObjectFactory = this; + throw new ObjectCreationException(definition.ResourceDescription, name, + "Initialization method '" + definition.InitMethodName + "' threw exception", ex.GetBaseException()); + } + catch (Exception ex) + { + throw new ObjectCreationException(definition.ResourceDescription, name, + "Invocation of initialization method '" + definition.InitMethodName + "' failed", ex); } - - instance = ApplyObjectPostProcessorsBeforeInitialization(instance, name); - InvokeInitMethods(instance, name, definition); - instance = ApplyObjectPostProcessorsAfterInitialization(instance, name); - - return instance; } - - /// - /// Applies the PostProcessAfterInitialization callback of all - /// registered IObjectPostProcessors, giving them a chance to post-process - /// the object obtained from IFactoryObjects (for example, to auto-proxy them) - /// - /// The instance obtained from the IFactoryObject. - /// Name of the object. - /// The object instance to expose - /// if any post-processing failed. - protected override object PostProcessObjectFromFactoryObject(object instance, string objectName) - { - return ApplyObjectPostProcessorsAfterInitialization(instance, objectName); - } - - /// - /// Create a new object instance of the given class with the specified - /// autowire strategy. - /// - /// - /// The of the object to instantiate. - /// - /// - /// The desired autowiring mode. - /// - /// - /// Whether to perform a dependency check for objects (not applicable to - /// autowiring a constructor, thus ignored there). - /// - /// The new object instance. - /// - /// If the wiring fails. - /// - /// - public virtual object Autowire(Type type, AutoWiringMode autowireMode, bool dependencyCheck) - { - RootObjectDefinition rod = new RootObjectDefinition(type, autowireMode, dependencyCheck); - if (rod.ResolvedAutowireMode == AutoWiringMode.Constructor) - { - return AutowireConstructor(type.Name, rod, null, null).WrappedInstance; - } - - object obj = InstantiationStrategy.Instantiate(rod, string.Empty, this); - PopulateObject(obj.GetType().Name, rod, new ObjectWrapper(obj)); - return obj; - } - - /// - /// Autowire the object properties of the given object instance by name or - /// . - /// - /// - /// The existing object instance. - /// - /// - /// The desired autowiring mode. - /// - /// - /// Whether to perform a dependency check for the object. - /// - /// - /// If the wiring fails. - /// - /// - /// If the supplied is not one of the - /// or - /// - /// values. - /// - /// - public virtual void AutowireObjectProperties(object instance, AutoWiringMode autowireMode, bool dependencyCheck) - { - if (autowireMode != AutoWiringMode.ByName && autowireMode != AutoWiringMode.ByType) - { - throw new ArgumentException("Just AutoWiringMode.ByName and AutoWiringMode.ByType allowed."); - } - - RootObjectDefinition rod = new RootObjectDefinition(instance.GetType(), autowireMode, dependencyCheck); - PopulateObject(instance.GetType().Name, rod, new ObjectWrapper(instance)); - } - - /// - /// Apply s - /// to the given existing object instance, invoking their - /// - /// methods. - /// - /// - /// The existing object instance. - /// - /// - /// The name of the object. - /// - /// - /// The object instance to use, either the original or a wrapped one. - /// - /// - /// If any post-processing failed. - /// - /// - public virtual object ApplyObjectPostProcessorsBeforeInitialization(object instance, string name) - { - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug($"Invoking IObjectPostProcessors before initialization of object '{name}'"); - } - - object result = instance; - for (var i = 0; i < objectPostProcessors.Count; i++) - { - IObjectPostProcessor objectProcessor = objectPostProcessors[i]; - result = objectProcessor.PostProcessBeforeInitialization(result, name); - if (result == null) - { - throw new ObjectCreationException(name, - $"PostProcessBeforeInitialization method of IObjectPostProcessor [{objectProcessor}] " + - $" returned null for object [{instance}] with name '{name}'."); - } - } - - return result; - } - - /// - /// Apply s - /// to the given existing object instance, invoking their - /// - /// methods. - /// - /// - /// The existing object instance. - /// - /// - /// The name of the object. - /// - /// - /// The object instance to use, either the original or a wrapped one. - /// - /// - /// If any post-processing failed. - /// - /// - public virtual object ApplyObjectPostProcessorsAfterInitialization(object instance, string name) - { - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug($"Invoking IObjectPostProcessors after initialization of object '{name}'"); - } - - object result = instance; - for (var i = 0; i < objectPostProcessors.Count; i++) - { - IObjectPostProcessor objectProcessor = objectPostProcessors[i]; - result = objectProcessor.PostProcessAfterInitialization(result, name); - if (result == null) - { - throw new ObjectCreationException(name, - $"PostProcessAfterInitialization method of IObjectPostProcessor [{objectProcessor}] " + - $" returned null for object [{instance}] with name [{name}]."); - } - } - - return result; - } - - /// - /// Resolve the specified dependency against the objects defined in this factory. - /// - /// The descriptor for the dependency. - /// Name of the object which declares the present dependency. - /// A list that all names of autowired object (used for - /// resolving the present dependency) are supposed to be added to. - /// - /// the resolved object, or null if none found - /// - /// if dependency resolution failed - public abstract object ResolveDependency( - DependencyDescriptor descriptor, - string objectName, - IList autowiredObjectNames); } - internal class UnsatisfiedDependencyExceptionData + /// + /// Invoke the specified custom destroy method on the given object. + /// + /// + ///

+ /// This implementation invokes a no-arg method if found, else checking + /// for a method with a single boolean argument (passing in "true", + /// assuming a "force" parameter), else logging an error. + ///

+ ///

+ /// Can be overridden in subclasses for custom resolution of destroy + /// methods with arguments. + ///

+ ///

+ /// Custom destroy methods are resolved in a case-insensitive manner. + ///

+ ///
+ protected virtual void InvokeCustomDestroyMethod(string name, object target, string destroyMethodName) { - public UnsatisfiedDependencyExceptionData(int parameterIndex, Type parameterType, string errorMessage) + bool usingForcingVersion = false; + MethodInfo targetMethod = target.GetType().GetMethod(destroyMethodName, MethodResolutionFlags, null, Type.EmptyTypes, null); + if (targetMethod == null) { - ParameterIndex = parameterIndex; - ParameterType = parameterType; - ErrorMessage = errorMessage; + // #%&^! try to find the method with a boolean "force" parameter + targetMethod = target.GetType().GetMethod(destroyMethodName, MethodResolutionFlags, null, new Type[] { typeof(bool) }, null); + if (targetMethod != null) + { + usingForcingVersion = true; + } } - public int ParameterIndex { get; } - - public Type ParameterType { get; } - - public string ErrorMessage { get; } + if (targetMethod == null) + { + log.LogError("Couldn't find a method named '" + destroyMethodName + "' on object with name '" + name + "'"); + } + else + { + object[] args = usingForcingVersion ? new object[] { true } : ObjectUtils.EmptyObjects; + try + { + targetMethod.Invoke(target, args); + } + catch (TargetInvocationException ex) + { + string message = "Couldn't invoke destroy method '" + destroyMethodName + "' of object with name '" + name + "'"; + log.LogError(ex.GetBaseException(), message); + } + catch (Exception ex) + { + LogExceptionRaisedByCustomDestroyMethodInvocation(destroyMethodName, name, ex); + } + } } + + private void LogExceptionRaisedByCustomDestroyMethodInvocation(string destroyMethodName, string name, Exception ex) + { + string message = string.Format(CultureInfo.InvariantCulture, "Couldn't invoke destroy method '{0}' of object with name '{1}'.", destroyMethodName, name); + log.LogError(ex, message); + } + + /// + /// Destroy the target object. + /// + /// + ///

+ /// Must destroy objects that depend on the given object before the object itself. + /// Should not throw any exceptions. + ///

+ ///
+ /// + /// The name of the object. + /// + /// + /// The target object instance to destroyed. + /// + protected override void DestroyObject(string name, object target) + { + using (new DisposableObjectAdapter(target, name, GetMergedObjectDefinition(name, true), ObjectPostProcessors)) + { + log.LogDebug("Destroying dependant objects for object '{ObjectName}", name); + DestroyDependantObjects(name); + } + } + + /// + /// Destroys all of the objects registered as dependant on the + /// object (definition) identified by the supplied . + /// + /// + /// The name of the root object (definition) that is itself being destroyed. + /// + private void DestroyDependantObjects(string name) + { + IList dependingObjects = GetDependingObjectNames(name); + foreach (string doName in dependingObjects) + { + DestroySingleton(doName); + } + } + + ///// + ///// Given a property value, return a value, resolving any references to other + ///// objects in the factory if necessary. + ///// + ///// + /////

+ ///// The value could be : + ///// + ///// + /////

+ ///// An , + ///// which leads to the creation of a corresponding new object instance. + ///// Singleton flags and names of such "inner objects" are always ignored: inner objects + ///// are anonymous prototypes. + /////

+ ///// + ///// + /////

+ ///// A , which must + ///// be resolved. + /////

+ /////
+ ///// + /////

+ ///// An . This is a + ///// special placeholder collection that may contain + ///// s or + ///// collections that will need to be resolved. + /////

+ /////
+ ///// + /////

+ ///// An ordinary object or , in which case it's left alone. + /////

+ /////
+ ///// + /////

+ /////
+ ///// + ///// The name of the object that is having the value of one of its properties resolved. + ///// + ///// + ///// The definition of the named object. + ///// + ///// + ///// The name of the property the value of which is being resolved. + ///// + ///// + ///// The value of the property that is being resolved. + ///// + // protected object ResolveValueIfNecessary(string name, RootObjectDefinition definition, string argumentName, object argumentValue) + // { + // object resolvedValue = null; + // + // AssertUtils.ArgumentNotNull(resolvedValue, "test"); + // + // // we must check the argument value to see whether it requires a runtime + // // reference to another object to be resolved. + // // if it does, we'll attempt to instantiate the object and set the reference. + // if (RemotingServices.IsTransparentProxy(argumentValue)) + // { + // resolvedValue = argumentValue; + // } + // else if (argumentValue is ObjectDefinitionHolder) + // { + // // contains an IObjectDefinition with name and aliases... + // ObjectDefinitionHolder holder = (ObjectDefinitionHolder)argumentValue; + // resolvedValue = ResolveInnerObjectDefinition(name, holder.ObjectName, argumentName, holder.ObjectDefinition, definition.IsSingleton); + // } + // else if (argumentValue is IObjectDefinition) + // { + // // resolve plain IObjectDefinition, without contained name: use dummy name... + // IObjectDefinition def = (IObjectDefinition)argumentValue; + // resolvedValue = ResolveInnerObjectDefinition(name, "(inner object)", argumentName, def, definition.IsSingleton); + // + // } + // else if (argumentValue is RuntimeObjectReference) + // { + // RuntimeObjectReference roref = (RuntimeObjectReference)argumentValue; + // resolvedValue = ResolveReference(definition, name, argumentName, roref); + // } + // else if (argumentValue is ExpressionHolder) + // { + // ExpressionHolder expHolder = (ExpressionHolder)argumentValue; + // object context = null; + // IDictionary variables = null; + // + // if (expHolder.Properties != null) + // { + // PropertyValue contextProperty = expHolder.Properties.GetPropertyValue("Context"); + // context = contextProperty == null + // ? null + // : ResolveValueIfNecessary2(name, definition, "Context", + // contextProperty.Value); + // PropertyValue variablesProperty = expHolder.Properties.GetPropertyValue("Variables"); + // object vars = (variablesProperty == null + // ? null + // : ResolveValueIfNecessary2(name, definition, "Variables", + // variablesProperty.Value)); + // if (vars is IDictionary) + // { + // variables = (IDictionary)vars; + // } + // else + // { + // if (vars != null) throw new ArgumentException("'Variables' must resolve to an IDictionary"); + // } + // } + // + // if (variables == null) variables = CollectionsUtil.CreateCaseInsensitiveHashtable(); + // // add 'this' objectfactory reference to variables + // variables.Add(Expression.ReservedVariableNames.CurrentObjectFactory, this); + // + // resolvedValue = expHolder.Expression.GetValue(context, variables); + // } + // else if (argumentValue is IManagedCollection) + // { + // resolvedValue = + // ((IManagedCollection)argumentValue).Resolve(name, definition, argumentName, + // new ManagedCollectionElementResolver(ResolveValueIfNecessary2)); + // } + // else if (argumentValue is TypedStringValue) + // { + // TypedStringValue tsv = (TypedStringValue)argumentValue; + // try + // { + // Type resolvedTargetType = ResolveTargetType(tsv); + // if (resolvedTargetType != null) + // { + // resolvedValue = TypeConversionUtils.ConvertValueIfNecessary(tsv.TargetType, tsv.Value, null); + // } + // else + // { + // resolvedValue = tsv.Value; + // } + // } + // catch (Exception ex) + // { + // throw new ObjectCreationException(definition.ResourceDescription, name, + // "Error converted typed String value for " + argumentName, ex); + // } + // + // } + // else + // { + // // no need to resolve value... + // resolvedValue = argumentValue; + // } + // return resolvedValue; + // } + + ///// + ///// Resolve the target type of the passed . + ///// + ///// The who's target type is to be resolved + ///// The resolved target type, if any. otherwise. + // protected virtual Type ResolveTargetType(TypedStringValue value) + // { + // if (value.HasTargetType) + // { + // return value.TargetType; + // } + // else + // { + // return null; + // } + // } + + ///// + ///// Resolves an inner object definition. + ///// + ///// + ///// The name of the object that surrounds this inner object definition. + ///// + ///// + ///// The name of the inner object definition... note: this is a synthetic + ///// name assigned by the factory (since it makes no sense for inner object + ///// definitions to have names). + ///// + ///// + ///// The name of the property the value of which is being resolved. + ///// + ///// + ///// The definition of the inner object that is to be resolved. + ///// + ///// + ///// if the owner of the property is a singleton. + ///// + ///// + ///// The resolved object as defined by the inner object definition. + ///// + // protected object ResolveInnerObjectDefinition(string name, string innerObjectName, string argumentName, IObjectDefinition definition, + // bool singletonOwner) + // { + // RootObjectDefinition mod = GetMergedObjectDefinition(innerObjectName, definition); + // mod.IsSingleton = singletonOwner; + // object instance; + // object result; + // try + // { + // instance = InstantiateObject(innerObjectName, mod, ObjectUtils.EmptyObjects, false, false); + // result = GetObjectForInstance(innerObjectName, instance); + // } + // catch (ObjectsException ex) + // { + // throw ObjectCreationException.GetObjectCreationException(ex, name, argumentName, definition.ResourceDescription, innerObjectName); + // } + // if (singletonOwner && instance is IDisposable) + // { + // // keep a reference to the inner object instance, to be able to destroy + // // it on factory shutdown... + // DisposableInnerObjects.Add(instance); + // } + // return result; + // } + + /// + /// Resolve a reference to another object in the factory. + /// + /// + /// The name of the object that is having the value of one of its properties resolved. + /// + /// + /// The definition of the named object. + /// + /// + /// The name of the property the value of which is being resolved. + /// + /// + /// The runtime reference containing the value of the property. + /// + /// A reference to another object in the factory. + protected object ResolveReference(IConfigurableObjectDefinition definition, string name, string argumentName, RuntimeObjectReference reference) + { + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug(string.Format(CultureInfo.InvariantCulture, "Resolving reference from property '{0}' in object '{1}' to object '{2}'.", + argumentName, name, reference.ObjectName)); + } + + try + { + if (reference.IsToParent) + { + if (null == ParentObjectFactory) + { + throw new ObjectCreationException(definition.ResourceDescription, name, + string.Format( + "Can't resolve reference to '{0}' in parent factory: " + "no parent factory available.", + reference.ObjectName)); + } + + return ParentObjectFactory.GetObject(reference.ObjectName); + } + + return GetObject(reference.ObjectName); + } + catch (ObjectsException ex) + { + throw ObjectCreationException.GetObjectCreationException(ex, name, argumentName, definition.ResourceDescription, reference.ObjectName); + } + } + + /// + /// Find object instances that match the required . + /// + /// + ///

+ /// Called by autowiring. If a subclass cannot obtain information about object + /// names by , a corresponding exception should be thrown. + ///

+ ///
+ /// + /// The of the objects to look up. + /// + /// + /// An of object names and object + /// instances that match the required , or + /// if none are found. + /// + /// + /// In case of errors. + /// + protected abstract IDictionary FindMatchingObjects(Type requiredType); + + /// + /// Return the names of the objects that depend on the given object. + /// Called by DestroyObject, to be able to destroy depending objects first. + /// + /// + /// The name of the object to find depending objects for. + /// + /// + /// The array of names of depending objects, or the empty string array if none. + /// + /// + /// In case of errors. + /// + protected abstract IList GetDependingObjectNames(string name); + + /// + /// Injects dependencies into the supplied instance + /// using the named object definition. + /// + /// + /// The object instance that is to be so configured. + /// + /// + /// The name of the object definition expressing the dependencies that are to + /// be injected into the supplied instance. + /// + /// + public override object ConfigureObject(object target, string name) + { + MarkObjectAsCreated(name); + RootObjectDefinition definition = GetMergedObjectDefinition(name, true); + if (definition != null) + { + return ConfigureObject(name, definition, new ObjectWrapper(target)); + } + + return target; + } + + /// + /// Injects dependencies into the supplied instance + /// using the supplied . + /// + /// + /// The object instance that is to be so configured. + /// + /// + /// The name of the object definition expressing the dependencies that are to + /// be injected into the supplied instance. + /// + /// + /// An object definition that should be used to configure object. + /// + /// + public override object ConfigureObject(object target, string name, IObjectDefinition definition) + { + return ConfigureObject(name, new RootObjectDefinition(definition), new ObjectWrapper(target)); + } + + /// + /// Configures object instance by injecting dependencies, satisfying Spring lifecycle + /// interfaces and applying object post-processors. + /// + /// + /// The name of the object definition expressing the dependencies that are to + /// be injected into the supplied instance. + /// + /// + /// An object definition that should be used to configure object. + /// + /// + /// A wrapped object instance that is to be so configured. + /// + /// + protected virtual object ConfigureObject(string name, RootObjectDefinition definition, IObjectWrapper wrapper) + { + object instance = wrapper.WrappedInstance; + + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug($"Configuring object using definition '{name}'"); + } + + PopulateObject(name, definition, wrapper); + WireEvents(name, definition, wrapper); + + if (ObjectUtils.IsAssignableAndNotTransparentProxy(typeof(IObjectNameAware), instance)) + { + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug($"Setting the name property on the IObjectNameAware object '{name}'."); + } + + ((IObjectNameAware) instance).ObjectName = name; + } + + if (ObjectUtils.IsAssignableAndNotTransparentProxy(typeof(IObjectFactoryAware), instance)) + { + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug($"Setting the ObjectFactory property on the IObjectFactoryAware object '{name}'."); + } + + ((IObjectFactoryAware) instance).ObjectFactory = this; + } + + instance = ApplyObjectPostProcessorsBeforeInitialization(instance, name); + InvokeInitMethods(instance, name, definition); + instance = ApplyObjectPostProcessorsAfterInitialization(instance, name); + + return instance; + } + + /// + /// Applies the PostProcessAfterInitialization callback of all + /// registered IObjectPostProcessors, giving them a chance to post-process + /// the object obtained from IFactoryObjects (for example, to auto-proxy them) + /// + /// The instance obtained from the IFactoryObject. + /// Name of the object. + /// The object instance to expose + /// if any post-processing failed. + protected override object PostProcessObjectFromFactoryObject(object instance, string objectName) + { + return ApplyObjectPostProcessorsAfterInitialization(instance, objectName); + } + + /// + /// Create a new object instance of the given class with the specified + /// autowire strategy. + /// + /// + /// The of the object to instantiate. + /// + /// + /// The desired autowiring mode. + /// + /// + /// Whether to perform a dependency check for objects (not applicable to + /// autowiring a constructor, thus ignored there). + /// + /// The new object instance. + /// + /// If the wiring fails. + /// + /// + public virtual object Autowire(Type type, AutoWiringMode autowireMode, bool dependencyCheck) + { + RootObjectDefinition rod = new RootObjectDefinition(type, autowireMode, dependencyCheck); + if (rod.ResolvedAutowireMode == AutoWiringMode.Constructor) + { + return AutowireConstructor(type.Name, rod, null, null).WrappedInstance; + } + + object obj = InstantiationStrategy.Instantiate(rod, string.Empty, this); + PopulateObject(obj.GetType().Name, rod, new ObjectWrapper(obj)); + return obj; + } + + /// + /// Autowire the object properties of the given object instance by name or + /// . + /// + /// + /// The existing object instance. + /// + /// + /// The desired autowiring mode. + /// + /// + /// Whether to perform a dependency check for the object. + /// + /// + /// If the wiring fails. + /// + /// + /// If the supplied is not one of the + /// or + /// + /// values. + /// + /// + public virtual void AutowireObjectProperties(object instance, AutoWiringMode autowireMode, bool dependencyCheck) + { + if (autowireMode != AutoWiringMode.ByName && autowireMode != AutoWiringMode.ByType) + { + throw new ArgumentException("Just AutoWiringMode.ByName and AutoWiringMode.ByType allowed."); + } + + RootObjectDefinition rod = new RootObjectDefinition(instance.GetType(), autowireMode, dependencyCheck); + PopulateObject(instance.GetType().Name, rod, new ObjectWrapper(instance)); + } + + /// + /// Apply s + /// to the given existing object instance, invoking their + /// + /// methods. + /// + /// + /// The existing object instance. + /// + /// + /// The name of the object. + /// + /// + /// The object instance to use, either the original or a wrapped one. + /// + /// + /// If any post-processing failed. + /// + /// + public virtual object ApplyObjectPostProcessorsBeforeInitialization(object instance, string name) + { + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug($"Invoking IObjectPostProcessors before initialization of object '{name}'"); + } + + object result = instance; + for (var i = 0; i < objectPostProcessors.Count; i++) + { + IObjectPostProcessor objectProcessor = objectPostProcessors[i]; + result = objectProcessor.PostProcessBeforeInitialization(result, name); + if (result == null) + { + throw new ObjectCreationException(name, + $"PostProcessBeforeInitialization method of IObjectPostProcessor [{objectProcessor}] " + + $" returned null for object [{instance}] with name '{name}'."); + } + } + + return result; + } + + /// + /// Apply s + /// to the given existing object instance, invoking their + /// + /// methods. + /// + /// + /// The existing object instance. + /// + /// + /// The name of the object. + /// + /// + /// The object instance to use, either the original or a wrapped one. + /// + /// + /// If any post-processing failed. + /// + /// + public virtual object ApplyObjectPostProcessorsAfterInitialization(object instance, string name) + { + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug($"Invoking IObjectPostProcessors after initialization of object '{name}'"); + } + + object result = instance; + for (var i = 0; i < objectPostProcessors.Count; i++) + { + IObjectPostProcessor objectProcessor = objectPostProcessors[i]; + result = objectProcessor.PostProcessAfterInitialization(result, name); + if (result == null) + { + throw new ObjectCreationException(name, + $"PostProcessAfterInitialization method of IObjectPostProcessor [{objectProcessor}] " + + $" returned null for object [{instance}] with name [{name}]."); + } + } + + return result; + } + + /// + /// Resolve the specified dependency against the objects defined in this factory. + /// + /// The descriptor for the dependency. + /// Name of the object which declares the present dependency. + /// A list that all names of autowired object (used for + /// resolving the present dependency) are supposed to be added to. + /// + /// the resolved object, or null if none found + /// + /// if dependency resolution failed + public abstract object ResolveDependency( + DependencyDescriptor descriptor, + string objectName, + IList autowiredObjectNames); +} + +internal class UnsatisfiedDependencyExceptionData +{ + public UnsatisfiedDependencyExceptionData(int parameterIndex, Type parameterType, string errorMessage) + { + ParameterIndex = parameterIndex; + ParameterType = parameterType; + ErrorMessage = errorMessage; + } + + public int ParameterIndex { get; } + + public Type ParameterType { get; } + + public string ErrorMessage { get; } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/AbstractMethodReplacer.cs b/src/Spring/Spring.Core/Objects/Factory/Support/AbstractMethodReplacer.cs index 2326cc6d..3e3fd730 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/AbstractMethodReplacer.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/AbstractMethodReplacer.cs @@ -19,104 +19,102 @@ #endregion using System.Reflection; - using Spring.Util; -namespace Spring.Objects.Factory.Support +namespace Spring.Objects.Factory.Support; + +/// +/// An +/// implementation that provides some convenience support for +/// derived classes. +/// +/// +///

+/// This class is reserved for internal use within the framework; it is +/// not intended to be used by application developers using Spring.NET. +///

+///
+/// Rick Evans +public abstract class AbstractMethodReplacer : IMethodReplacer { - /// - /// An - /// implementation that provides some convenience support for - /// derived classes. - /// - /// - ///

- /// This class is reserved for internal use within the framework; it is - /// not intended to be used by application developers using Spring.NET. - ///

- ///
- /// Rick Evans - public abstract class AbstractMethodReplacer : IMethodReplacer - { - private IConfigurableObjectDefinition objectDefinition; - private IObjectFactory objectFactory; + private IConfigurableObjectDefinition objectDefinition; + private IObjectFactory objectFactory; - /// - /// Creates a new instance of the - /// - /// class. - /// - /// - ///

- /// This is an class, and as such has no - /// publicly visible constructors. - ///

- ///
- /// - /// The object definition that is the target of the method replacement. - /// - /// - /// The enclosing IoC container with which the above - /// is associated. - /// - /// - /// If either of the supplied arguments is . - /// - protected AbstractMethodReplacer( - IConfigurableObjectDefinition objectDefinition, IObjectFactory objectFactory) - { - AssertUtils.ArgumentNotNull(objectDefinition, "objectDefinition"); - AssertUtils.ArgumentNotNull(objectFactory, "objectFactory"); - this.objectDefinition = objectDefinition; - this.objectFactory = objectFactory; - } + /// + /// Creates a new instance of the + /// + /// class. + /// + /// + ///

+ /// This is an class, and as such has no + /// publicly visible constructors. + ///

+ ///
+ /// + /// The object definition that is the target of the method replacement. + /// + /// + /// The enclosing IoC container with which the above + /// is associated. + /// + /// + /// If either of the supplied arguments is . + /// + protected AbstractMethodReplacer( + IConfigurableObjectDefinition objectDefinition, IObjectFactory objectFactory) + { + AssertUtils.ArgumentNotNull(objectDefinition, "objectDefinition"); + AssertUtils.ArgumentNotNull(objectFactory, "objectFactory"); + this.objectDefinition = objectDefinition; + this.objectFactory = objectFactory; + } - /// - /// Is ; derived classes must supply an implementation. - /// - /// - /// The instance whose is to be - /// (re)implemented. - /// - /// - /// The method that is to be (re)implemented. - /// - /// The target method's arguments. - /// The result of the object lookup. - public abstract object Implement(object target, MethodInfo method, object[] arguments); + /// + /// Is ; derived classes must supply an implementation. + /// + /// + /// The instance whose is to be + /// (re)implemented. + /// + /// + /// The method that is to be (re)implemented. + /// + /// The target method's arguments. + /// The result of the object lookup. + public abstract object Implement(object target, MethodInfo method, object[] arguments); - /// - /// Helper method for subclasses to retrieve the appropriate - /// for the - /// supplied . - /// - /// - /// The to use to retrieve - /// the appropriate - /// . - /// - /// - /// The appropriate - /// . - /// - protected MethodOverride GetOverride(MethodInfo method) - { - return this.objectDefinition.MethodOverrides.GetOverride(method); - } + /// + /// Helper method for subclasses to retrieve the appropriate + /// for the + /// supplied . + /// + /// + /// The to use to retrieve + /// the appropriate + /// . + /// + /// + /// The appropriate + /// . + /// + protected MethodOverride GetOverride(MethodInfo method) + { + return this.objectDefinition.MethodOverrides.GetOverride(method); + } - /// - /// Helper method for subclasses to lookup an object from an enclosing - /// IoC container. - /// - /// - /// The name of the object that is to be looked up. - /// - /// - /// The named object. - /// - protected object GetObject(string objectName) - { - return this.objectFactory.GetObject(objectName); - } - } + /// + /// Helper method for subclasses to lookup an object from an enclosing + /// IoC container. + /// + /// + /// The name of the object that is to be looked up. + /// + /// + /// The named object. + /// + protected object GetObject(string objectName) + { + return this.objectFactory.GetObject(objectName); + } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/AbstractObjectDefinition.cs b/src/Spring/Spring.Core/Objects/Factory/Support/AbstractObjectDefinition.cs index 60684f02..027b6167 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/AbstractObjectDefinition.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/AbstractObjectDefinition.cs @@ -24,889 +24,904 @@ using Spring.Objects.Factory.Config; using Spring.Util; using Spring.Collections.Generic; -namespace Spring.Objects.Factory.Support +namespace Spring.Objects.Factory.Support; + +/// +/// Common base class for object definitions, factoring out common +/// functionality from +/// and +/// . +/// +/// Rod Johnson +/// Juergen Hoeller +/// Rick Evans (.NET) +[Serializable] +public abstract class AbstractObjectDefinition : ObjectMetadataAttributeAccessor, IConfigurableObjectDefinition, ISerializable { + private const string ScopeSingleton = "singleton"; + private const string ScopePrototype = "prototype"; + + private ConstructorArgumentValues constructorArgumentValues = new ConstructorArgumentValues(); + private MutablePropertyValues propertyValues = new MutablePropertyValues(); + private EventValues eventHandlerValues = new EventValues(); + private MethodOverrides methodOverrides = new MethodOverrides(); + private string resourceDescription; + private bool isSingleton = true; + private bool isPrototype; + private bool isLazyInit; + private bool isAbstract; + private string scope = ScopeSingleton; + private ObjectRole role = ObjectRole.ROLE_APPLICATION; + + private string objectTypeName; + private Type objectType; + + private AutoWiringMode autowireMode = AutoWiringMode.No; + private DependencyCheckingMode dependencyCheck = DependencyCheckingMode.None; + internal List dependsOn; + private bool autowireCandidate = true; + private bool primary; + private Dictionary qualifiers; + private string initMethodName; + private string destroyMethodName; + private string factoryMethodName; + private string factoryObjectName; + /// - /// Common base class for object definitions, factoring out common - /// functionality from - /// and - /// . + /// Creates a new instance of the + /// + /// class. /// - /// Rod Johnson - /// Juergen Hoeller - /// Rick Evans (.NET) - [Serializable] - public abstract class AbstractObjectDefinition : ObjectMetadataAttributeAccessor, IConfigurableObjectDefinition, ISerializable + /// + ///

+ /// This is an class, and as such exposes no + /// public constructors. + ///

+ ///
+ protected AbstractObjectDefinition() : this(null, null) { - private const string ScopeSingleton = "singleton"; - private const string ScopePrototype = "prototype"; + } - private ConstructorArgumentValues constructorArgumentValues = new ConstructorArgumentValues(); - private MutablePropertyValues propertyValues = new MutablePropertyValues(); - private EventValues eventHandlerValues = new EventValues(); - private MethodOverrides methodOverrides = new MethodOverrides(); - private string resourceDescription; - private bool isSingleton = true; - private bool isPrototype; - private bool isLazyInit; - private bool isAbstract; - private string scope = ScopeSingleton; - private ObjectRole role = ObjectRole.ROLE_APPLICATION; - - private string objectTypeName; - private Type objectType; - - private AutoWiringMode autowireMode = AutoWiringMode.No; - private DependencyCheckingMode dependencyCheck = DependencyCheckingMode.None; - internal List dependsOn; - private bool autowireCandidate = true; - private bool primary; - private Dictionary qualifiers; - private string initMethodName; - private string destroyMethodName; - private string factoryMethodName; - private string factoryObjectName; + /// + /// Creates a new instance of the + /// + /// class. + /// + /// + ///

+ /// This is an class, and as such exposes no + /// public constructors. + ///

+ ///
+ protected AbstractObjectDefinition(ConstructorArgumentValues arguments, MutablePropertyValues properties) + { + constructorArgumentValues = arguments ?? constructorArgumentValues ?? new ConstructorArgumentValues(); + propertyValues = properties ?? propertyValues ?? new MutablePropertyValues(); + } - /// - /// Creates a new instance of the - /// - /// class. - /// - /// - ///

- /// This is an class, and as such exposes no - /// public constructors. - ///

- ///
- protected AbstractObjectDefinition() : this(null, null) + /// + /// Creates a new instance of the + /// + /// class. + /// + /// + /// The object definition used to initialise the member fields of this + /// instance. + /// + /// + ///

+ /// This is an class, and as such exposes no + /// public constructors. + ///

+ ///
+ protected AbstractObjectDefinition(IObjectDefinition other) + { + AssertUtils.ArgumentNotNull(other, "other"); + OverrideFrom(other); + + AbstractObjectDefinition aod = other as AbstractObjectDefinition; + if (aod != null) { - } - - /// - /// Creates a new instance of the - /// - /// class. - /// - /// - ///

- /// This is an class, and as such exposes no - /// public constructors. - ///

- ///
- protected AbstractObjectDefinition(ConstructorArgumentValues arguments, MutablePropertyValues properties) - { - constructorArgumentValues = arguments ?? constructorArgumentValues ?? new ConstructorArgumentValues(); - propertyValues = properties ?? propertyValues ?? new MutablePropertyValues(); - } - - /// - /// Creates a new instance of the - /// - /// class. - /// - /// - /// The object definition used to initialise the member fields of this - /// instance. - /// - /// - ///

- /// This is an class, and as such exposes no - /// public constructors. - ///

- ///
- protected AbstractObjectDefinition(IObjectDefinition other) - { - AssertUtils.ArgumentNotNull(other, "other"); - OverrideFrom(other); - - AbstractObjectDefinition aod = other as AbstractObjectDefinition; - if (aod != null) + if (aod.HasObjectType) { - if (aod.HasObjectType) - { - ObjectType = other.ObjectType; - } - else - { - ObjectTypeName = other.ObjectTypeName; - } - MethodOverrides = new MethodOverrides(aod.MethodOverrides); - DependencyCheck = aod.DependencyCheck; + ObjectType = other.ObjectType; } - ParentName = other.ParentName; - IsAbstract = other.IsAbstract; -// IsSingleton = other.IsSingleton; - Scope = other.Scope; - Role = other.Role; - IsLazyInit = other.IsLazyInit; - ConstructorArgumentValues - = new ConstructorArgumentValues(other.ConstructorArgumentValues); - PropertyValues = new MutablePropertyValues(other.PropertyValues); - EventHandlerValues = new EventValues(other.EventHandlerValues); - - InitMethodName = other.InitMethodName; - DestroyMethodName = other.DestroyMethodName; - IsAutowireCandidate = other.IsAutowireCandidate; - IsPrimary = other.IsPrimary; - CopyQualifiersFrom(aod); - if (other.DependsOn.Count > 0) - { - DependsOn = other.DependsOn; - } - FactoryMethodName = other.FactoryMethodName; - FactoryObjectName = other.FactoryObjectName; - AutowireMode = other.AutowireMode; - ResourceDescription = other.ResourceDescription; - } - - /// - /// The name of the parent definition of this object definition, if any. - /// - public abstract string ParentName { get; set; } - - /// - /// The property values that are to be applied to the object - /// upon creation. - /// - /// - ///

- /// Setting the value of this property to - /// will merely result in a new (and empty) - /// - /// collection being assigned to the property value. - ///

- ///
- /// - /// The property values (if any) for this object; may be an - /// empty collection but is guaranteed not to be - /// . - /// - public MutablePropertyValues PropertyValues - { - get => propertyValues; - set => propertyValues = value ?? new MutablePropertyValues(); - } - - /// - /// Does this definition have any - /// ? - /// - /// - /// if this definition has at least one - /// . - /// - public bool HasMethodOverrides => !MethodOverrides.IsEmpty; - - /// - /// The constructor argument values for this object. - /// - /// - ///

- /// Setting the value of this property to - /// will merely result in a new (and empty) - /// - /// collection being assigned. - ///

- ///
- /// - /// The constructor argument values (if any) for this object; may be an - /// empty collection but is guaranteed not to be - /// . - /// - public ConstructorArgumentValues ConstructorArgumentValues - { - get => constructorArgumentValues; - set => constructorArgumentValues = value ?? new ConstructorArgumentValues(); - } - - /// - /// The event handler values for this object. - /// - /// - ///

- /// Setting the value of this property to - /// will merely result in a new (and empty) - /// - /// collection being assigned. - ///

- ///
- /// - /// The event handler values (if any) for this object; may be an - /// empty collection but is guaranteed not to be - /// . - /// - public EventValues EventHandlerValues - { - get => eventHandlerValues; - set => eventHandlerValues = value ?? new EventValues(); - } - - /// - /// The method overrides (if any) for this object. - /// - /// - ///

- /// Setting the value of this property to - /// will merely result in a new (and empty) - /// - /// collection being assigned to the property value. - ///

- ///
- /// - /// The method overrides (if any) for this object; may be an - /// empty collection but is guaranteed not to be - /// . - /// - public MethodOverrides MethodOverrides - { - get => methodOverrides; - set => methodOverrides = value ?? new MethodOverrides(); - } - - /// - /// The name of the target scope for the object. - /// Defaults to "singleton", ootb alternative is "prototype". Extended object factories - /// might support further scopes. - /// - public virtual string Scope - { - get => scope; - set - { - AssertUtils.ArgumentNotNull(value, "Scope"); - scope = value; - isPrototype = 0 == string.Compare(ScopePrototype, value, StringComparison.OrdinalIgnoreCase); - isSingleton = !isPrototype; // 0 == string.Compare(SCOPE_SINGLETON, value, true); - } - } - - /// - /// Get or set the role hint for this object definition - /// - public virtual ObjectRole Role - { - get => role; - set => role = value; - } - - /// - /// Is this definition a singleton, with - /// a single, shared instance returned on all calls to an enclosing - /// container (typically an - /// or - /// ). - /// - /// - ///

- /// If , an object factory will apply the - /// prototype design pattern, with each caller requesting an - /// instance getting an independent instance. How this is defined - /// will depend on the object factory implementation. singletons - /// are the commoner type. - ///

- ///
- /// - public virtual bool IsSingleton - { - get => isSingleton; - set - { - scope = (value ? ScopeSingleton : ScopePrototype); - isSingleton = value; - isPrototype = !value; - } - } - - /// - /// Gets a value indicating whether this instance is prototype, with an independent instance - /// returned for each call. - /// - /// - /// true if this instance is prototype; otherwise, false. - /// - public virtual bool IsPrototype => isPrototype; - - /// - /// Is this object lazily initialized? - /// - ///

- /// Only applicable to a singleton object. - ///

- ///

- /// If , it will get instantiated on startup - /// by object factories that perform eager initialization of - /// singletons. - ///

- ///
- public bool IsLazyInit - { - get => isLazyInit; - set => isLazyInit = value; - } - - /// - /// Is this object definition a "template", i.e. not meant to be instantiated - /// itself but rather just serving as an object definition for configuration - /// templates used by . - /// - /// - /// if this object definition is a "template". - /// - public bool IsTemplate => isAbstract || (objectType == null && StringUtils.IsNullOrEmpty(factoryObjectName)); - - /// - /// Is this object definition "abstract", i.e. not meant to be - /// instantiated itself but rather just serving as a parent for concrete - /// child object definitions. - /// - /// - /// if this object definition is "abstract". - /// - public bool IsAbstract - { - get => isAbstract; - set => isAbstract = value; - } - - /// - /// The of the object definition (if any). - /// - /// - /// A resolved object . - /// - /// - /// If the of the object definition is not a - /// resolved or . - /// - /// - public Type ObjectType - { - get - { - if (objectType == null) - { - ThrowApplicationException("Object definition does not carry a resolved System.Type"); - return null; - } - return objectType; - } - set => objectType = value; - } - - private static void ThrowApplicationException(string message) - { - throw new ApplicationException(message); - } - - /// - /// Is the of the object definition a resolved - /// ? - /// - public bool HasObjectType => objectType != null; - - /// - /// Returns the of the - /// of the object definition (if any). - /// - public string ObjectTypeName - { - get => objectTypeName ?? objectType?.FullName; - set => objectTypeName = StringUtils.GetTextOrNull(value); - } - - /// - /// A description of the resource that this object definition - /// came from (for the purpose of showing context in case of errors). - /// - public string ResourceDescription - { - get => resourceDescription; - set => resourceDescription = StringUtils.GetTextOrNull(value); - } - - /// - /// The autowire mode as specified in the object definition. - /// - /// - ///

- /// This determines whether any automagical detection and setting of - /// object references will happen. The default is - /// , - /// which means that no autowiring will be performed. - ///

- ///
- public AutoWiringMode AutowireMode - { - get => autowireMode; - set => autowireMode = value; - } - - /// - /// Gets the resolved autowire mode. - /// - /// - ///

- /// This resolves - /// - /// to one of - /// - /// or - /// . - ///

- ///
- public AutoWiringMode ResolvedAutowireMode - { - get - { - if (AutowireMode == AutoWiringMode.AutoDetect) - { - // Work out whether to apply setter autowiring or constructor autowiring. - // If it has a no-arg constructor it's deemed to be setter autowiring, - // otherwise we'll try constructor autowiring. - ConstructorInfo[] constructors = - ObjectType.GetConstructors(); - foreach (ConstructorInfo ctor in constructors) - { - if (ctor.GetParameters().Length == 0) - { - return AutoWiringMode.ByType; - } - } - return AutoWiringMode.Constructor; - } - else - { - return AutowireMode; - } - } - } - - /// - /// The dependency checking mode. - /// - /// - ///

- /// The default is - /// . - ///

- ///
- public DependencyCheckingMode DependencyCheck - { - get => dependencyCheck; - set => dependencyCheck = value; - } - - /// - /// The object names that this object depends on. - /// - /// - ///

- /// The object factory will guarantee that these objects get initialized - /// before this object definition. - ///

- /// - /// Dependencies are normally expressed through object properties - /// or constructor arguments. This property should just be necessary for - /// other kinds of dependencies such as statics (*ugh*) or database - /// preparation on startup. - /// - ///
- public IReadOnlyList DependsOn - { - get => dependsOn ?? StringUtils.EmptyStringsList; - set => dependsOn = value != null && value.Count > 0 ? new List(value) : null; - } - - /// - /// Gets or sets a value indicating whether this instance a candidate for getting autowired into some other - /// object. - /// - /// - /// true if this instance is autowire candidate; otherwise, false. - /// - public bool IsAutowireCandidate - { - get => autowireCandidate; - set => autowireCandidate = value; - } - - - /// - /// Set whether this bean is a primary autowire candidate. - /// If this value is true for exactly one bean among multiple - /// matching candidates, it will serve as a tie-breaker. - /// - public bool IsPrimary - { - get => primary; - set => primary = value; - } - - /// - /// Register a qualifier to be used for autowire candidate resolution, - /// keyed by the qualifier's type name. - /// - /// - public void AddQualifier(AutowireCandidateQualifier qualifier) - { - qualifiers = qualifiers ?? new Dictionary(); - qualifiers.Add(qualifier.TypeName, qualifier); - } - - /// - /// Return whether this bean has the specified qualifier. - /// - public bool HasQualifier(string typeName) - { - return qualifiers != null && qualifiers.ContainsKey(typeName); - } - - /// - /// Return the qualifier mapped to the provided type name. - /// - public AutowireCandidateQualifier GetQualifier(string typeName) - { - if (qualifiers != null && qualifiers.TryGetValue(typeName, out var qualifier)) - { - return qualifier; - } - - return null; - } - - /// - /// Return all registered qualifiers. - /// - /// the Set of objects. - public Set GetQualifiers() - { - return qualifiers != null - ? new OrderedSet(qualifiers.Values) - : new OrderedSet(); - } - - /// - /// Copy the qualifiers from the supplied AbstractBeanDefinition to this bean definition. - /// - /// the AbstractBeanDefinition to copy from - public void CopyQualifiersFrom(AbstractObjectDefinition source) - { - Trace.Assert(source != null, "Source must not be null"); - if (source.qualifiers != null && source.qualifiers.Count > 0) - { - qualifiers = qualifiers ?? new Dictionary(); - foreach (var qualifier in source.qualifiers) - { - if (!qualifiers.ContainsKey(qualifier.Key)) - { - qualifiers.Add(qualifier.Key, qualifier.Value); - } - } - } - } - - /// - /// The name of the initializer method. - /// - /// - ///

- /// The default value is the constant, - /// in which case there is no initializer method. - ///

- ///
- public string InitMethodName - { - get => initMethodName; - set => initMethodName = StringUtils.GetTextOrNull(value); - } - - /// - /// Return the name of the destroy method. - /// - /// - ///

- /// The default value is the constant, - /// in which case there is no destroy method. - ///

- ///
- public string DestroyMethodName - { - get => destroyMethodName; - set => destroyMethodName = StringUtils.GetTextOrNull(value); - } - - /// - /// The name of the factory method to use (if any). - /// - /// - ///

- /// This method will be invoked with constructor arguments, or with no - /// arguments if none are specified. The - /// method will be invoked on the specified - /// . - ///

- ///
- public string FactoryMethodName - { - get => factoryMethodName; - set => factoryMethodName = StringUtils.GetTextOrNull(value); - } - - /// - /// The name of the factory object to use (if any). - /// - public string FactoryObjectName - { - get => factoryObjectName; - set => factoryObjectName = StringUtils.GetTextOrNull(value); - } - - /// - /// Does this object definition have any constructor argument values? - /// - /// - /// if his object definition has at least one - /// element in it's - /// - /// property. - /// - public bool HasConstructorArgumentValues => constructorArgumentValues != null - && !constructorArgumentValues.Empty; - - /// - /// Resolves the type of the object, resolving it from a specified - /// object type name if necessary. - /// - /// - /// A resolved instance. - /// - /// - /// If the type cannot be resolved. - /// - public Type ResolveObjectType() - { - string typeName = ObjectTypeName; - if (typeName == null) - { - return null; - } - Type resolvedType = TypeResolutionUtils.ResolveType(typeName); - ObjectType = resolvedType; - return resolvedType; - } - - /// - /// Validate this object definition. - /// - /// - /// In the case of a validation failure. - /// - public virtual void Validate() - { - if (IsLazyInit && !IsSingleton) - { - throw new ObjectDefinitionValidationException( - "Lazy initialization is only applicable to singleton objects."); - } - if (HasMethodOverrides && StringUtils.HasText(FactoryMethodName)) - { - throw new ObjectDefinitionValidationException( - "Cannot combine static factory method with method overrides: " + - "the static factory method must create the instance."); - } - if (HasObjectType) - { - PrepareMethodOverrides(); - } - } - - /// - /// Validates all - /// - public virtual void PrepareMethodOverrides() - { - // ascertain that the various lookup methods exist... - foreach (MethodOverride mo in MethodOverrides) - { - PrepareMethodOverride(mo); - } - } - - /// - /// Validate the supplied . - /// - /// - /// The - /// to be validated. - /// - protected void PrepareMethodOverride(MethodOverride methodOverride) - { - if (!ReflectionUtils.HasAtLeastOneMethodWithName(ObjectType, methodOverride.MethodName)) - { - throw new ObjectDefinitionValidationException( - string.Format( - CultureInfo.InvariantCulture, - "Invalid method override: no method with name '{0}' on class [{1}].", - methodOverride.MethodName, ObjectTypeName)); - } - //TODO investigate setting overloaded at this point using MethodCountForName... - //Test SunnyDayReplaceMethod_WithArgumentAcceptingReplacerWithNoTypeFragmentsSpecified - // will fail if doing this optimization. - } - - /// - /// Override settings in this object definition from the supplied - /// object definition. - /// - /// - /// The object definition used to override the member fields of this instance. - /// - public virtual void OverrideFrom(IObjectDefinition other) - { - AssertUtils.ArgumentNotNull(other, "other"); - - IsAbstract = other.IsAbstract; - Scope = other.Scope; - IsLazyInit = other.IsLazyInit; - ConstructorArgumentValues.AddAll(other.ConstructorArgumentValues); - PropertyValues.AddAll(other.PropertyValues.PropertyValues); - EventHandlerValues.AddAll(other.EventHandlerValues); - if (StringUtils.HasText(other.ObjectTypeName)) + else { ObjectTypeName = other.ObjectTypeName; } - if (StringUtils.HasText(other.InitMethodName)) - { - InitMethodName = other.InitMethodName; - } - if (StringUtils.HasText(other.DestroyMethodName)) - { - DestroyMethodName = other.DestroyMethodName; - } - if (StringUtils.HasText(other.FactoryObjectName)) - { - FactoryObjectName = other.FactoryObjectName; - } - if (StringUtils.HasText(other.FactoryMethodName)) - { - FactoryMethodName = other.FactoryMethodName; - } - if (other.DependsOn != null && other.DependsOn.Count > 0) - { - var deps = new List(other.DependsOn.Count + (DependsOn?.Count).GetValueOrDefault()); - deps.AddRange(other.DependsOn); - if (DependsOn != null && DependsOn.Count > 0) - { - deps.AddRange(DependsOn); - } - DependsOn = deps; - } - AutowireMode = other.AutowireMode; - ResourceDescription = other.ResourceDescription; - IsPrimary = other.IsPrimary; - IsAutowireCandidate = other.IsAutowireCandidate; - if (other is AbstractObjectDefinition aod) - { - if (other.ObjectTypeName != null) - { - ObjectTypeName = other.ObjectTypeName; - } - if (aod.HasObjectType) - { - ObjectType = other.ObjectType; - } - - MethodOverrides.AddAll(aod.MethodOverrides); - DependencyCheck = aod.DependencyCheck; - CopyQualifiersFrom(aod); - } + MethodOverrides = new MethodOverrides(aod.MethodOverrides); + DependencyCheck = aod.DependencyCheck; } - /// - /// Returns a that represents the current - /// . - /// - /// - /// A that represents the current - /// . - /// - public override string ToString() + ParentName = other.ParentName; + IsAbstract = other.IsAbstract; +// IsSingleton = other.IsSingleton; + Scope = other.Scope; + Role = other.Role; + IsLazyInit = other.IsLazyInit; + ConstructorArgumentValues + = new ConstructorArgumentValues(other.ConstructorArgumentValues); + PropertyValues = new MutablePropertyValues(other.PropertyValues); + EventHandlerValues = new EventValues(other.EventHandlerValues); + + InitMethodName = other.InitMethodName; + DestroyMethodName = other.DestroyMethodName; + IsAutowireCandidate = other.IsAutowireCandidate; + IsPrimary = other.IsPrimary; + CopyQualifiersFrom(aod); + if (other.DependsOn.Count > 0) { - StringBuilder buffer = new StringBuilder(string.Format("Class [{0}]", ObjectTypeName)); - buffer.Append("; Abstract = ").Append(IsAbstract); - buffer.Append("; Parent = ").Append(ParentName); - buffer.Append("; Scope = ").Append(Scope); - buffer.Append("; Singleton = ").Append(IsSingleton); - buffer.Append("; LazyInit = ").Append(IsLazyInit); - buffer.Append("; Autowire = ").Append(AutowireMode); - buffer.Append("; Autowire-Candidate = ").Append(IsAutowireCandidate); - buffer.Append("; Primary = ").Append(IsPrimary); - buffer.Append("; DependencyCheck = ").Append(DependencyCheck); - buffer.Append("; InitMethodName = ").Append(InitMethodName); - buffer.Append("; DestroyMethodName = ").Append(DestroyMethodName); - buffer.Append("; FactoryMethodName = ").Append(FactoryMethodName); - buffer.Append("; FactoryObjectName = ").Append(FactoryObjectName); - if (StringUtils.HasText(ResourceDescription)) - { - buffer.Append("; defined in = ").Append(ResourceDescription); - } - return buffer.ToString(); + DependsOn = other.DependsOn; } - - protected AbstractObjectDefinition(SerializationInfo info, StreamingContext context) + + FactoryMethodName = other.FactoryMethodName; + FactoryObjectName = other.FactoryObjectName; + AutowireMode = other.AutowireMode; + ResourceDescription = other.ResourceDescription; + } + + /// + /// The name of the parent definition of this object definition, if any. + /// + public abstract string ParentName { get; set; } + + /// + /// The property values that are to be applied to the object + /// upon creation. + /// + /// + ///

+ /// Setting the value of this property to + /// will merely result in a new (and empty) + /// + /// collection being assigned to the property value. + ///

+ ///
+ /// + /// The property values (if any) for this object; may be an + /// empty collection but is guaranteed not to be + /// . + /// + public MutablePropertyValues PropertyValues + { + get => propertyValues; + set => propertyValues = value ?? new MutablePropertyValues(); + } + + /// + /// Does this definition have any + /// ? + /// + /// + /// if this definition has at least one + /// . + /// + public bool HasMethodOverrides => !MethodOverrides.IsEmpty; + + /// + /// The constructor argument values for this object. + /// + /// + ///

+ /// Setting the value of this property to + /// will merely result in a new (and empty) + /// + /// collection being assigned. + ///

+ ///
+ /// + /// The constructor argument values (if any) for this object; may be an + /// empty collection but is guaranteed not to be + /// . + /// + public ConstructorArgumentValues ConstructorArgumentValues + { + get => constructorArgumentValues; + set => constructorArgumentValues = value ?? new ConstructorArgumentValues(); + } + + /// + /// The event handler values for this object. + /// + /// + ///

+ /// Setting the value of this property to + /// will merely result in a new (and empty) + /// + /// collection being assigned. + ///

+ ///
+ /// + /// The event handler values (if any) for this object; may be an + /// empty collection but is guaranteed not to be + /// . + /// + public EventValues EventHandlerValues + { + get => eventHandlerValues; + set => eventHandlerValues = value ?? new EventValues(); + } + + /// + /// The method overrides (if any) for this object. + /// + /// + ///

+ /// Setting the value of this property to + /// will merely result in a new (and empty) + /// + /// collection being assigned to the property value. + ///

+ ///
+ /// + /// The method overrides (if any) for this object; may be an + /// empty collection but is guaranteed not to be + /// . + /// + public MethodOverrides MethodOverrides + { + get => methodOverrides; + set => methodOverrides = value ?? new MethodOverrides(); + } + + /// + /// The name of the target scope for the object. + /// Defaults to "singleton", ootb alternative is "prototype". Extended object factories + /// might support further scopes. + /// + public virtual string Scope + { + get => scope; + set { - constructorArgumentValues = (ConstructorArgumentValues) info.GetValue("constructorArgumentValues", typeof(ConstructorArgumentValues)); - propertyValues = (MutablePropertyValues) info.GetValue("propertyValues", typeof(MutablePropertyValues)); - eventHandlerValues= (EventValues) info.GetValue("eventHandlerValues", typeof(EventValues)); - methodOverrides= (MethodOverrides) info.GetValue("methodOverrides", typeof(MethodOverrides)); - resourceDescription = info.GetString("resourceDescription"); - isSingleton = info.GetBoolean("isSingleton"); - isPrototype = info.GetBoolean("isPrototype"); - isLazyInit = info.GetBoolean("isLazyInit"); - isAbstract = info.GetBoolean("isAbstract"); - scope= info.GetString("scope"); - role = (ObjectRole) info.GetValue("role", typeof(ObjectRole)); - - var objectTypeName = info.GetString("objectTypeName"); - objectType = objectTypeName != null ? Type.GetType(objectTypeName) : null; - - autowireMode = (AutoWiringMode) info.GetValue("autowireMode", typeof(AutoWiringMode)); - dependencyCheck= (DependencyCheckingMode) info.GetValue("dependencyCheck", typeof(DependencyCheckingMode)); - dependsOn = (List) info.GetValue("dependsOn", typeof(List)); - autowireCandidate = info.GetBoolean("autowireCandidate"); - primary = info.GetBoolean("primary"); - qualifiers = (Dictionary) info.GetValue("qualifiers", typeof(Dictionary)); - initMethodName = info.GetString("initMethodName"); - destroyMethodName = info.GetString("destroyMethodName"); - factoryMethodName = info.GetString("factoryMethodName" ); - factoryObjectName= info.GetString("factoryObjectName"); - } - - public void GetObjectData(SerializationInfo info, StreamingContext context) - { - info.AddValue("constructorArgumentValues", constructorArgumentValues); - info.AddValue("propertyValues", propertyValues); - info.AddValue("eventHandlerValues", eventHandlerValues); - info.AddValue("methodOverrides", methodOverrides); - info.AddValue("resourceDescription", resourceDescription); - info.AddValue("isSingleton", isSingleton); - info.AddValue("isPrototype", isPrototype); - info.AddValue("isLazyInit", isLazyInit); - info.AddValue("isAbstract", isAbstract); - info.AddValue("scope", scope); - info.AddValue("role", role); - info.AddValue("objectTypeName", objectType.AssemblyQualifiedName); - info.AddValue("autowireMode", autowireMode); - info.AddValue("dependencyCheck", dependencyCheck); - info.AddValue("dependsOn", dependsOn); - info.AddValue("autowireCandidate", autowireCandidate); - info.AddValue("primary", primary); - info.AddValue("qualifiers", qualifiers); - info.AddValue("initMethodName", initMethodName); - info.AddValue("destroyMethodName", destroyMethodName); - info.AddValue("factoryMethodName", factoryMethodName); - info.AddValue("factoryObjectName", factoryObjectName); + AssertUtils.ArgumentNotNull(value, "Scope"); + scope = value; + isPrototype = 0 == string.Compare(ScopePrototype, value, StringComparison.OrdinalIgnoreCase); + isSingleton = !isPrototype; // 0 == string.Compare(SCOPE_SINGLETON, value, true); } } + + /// + /// Get or set the role hint for this object definition + /// + public virtual ObjectRole Role + { + get => role; + set => role = value; + } + + /// + /// Is this definition a singleton, with + /// a single, shared instance returned on all calls to an enclosing + /// container (typically an + /// or + /// ). + /// + /// + ///

+ /// If , an object factory will apply the + /// prototype design pattern, with each caller requesting an + /// instance getting an independent instance. How this is defined + /// will depend on the object factory implementation. singletons + /// are the commoner type. + ///

+ ///
+ /// + public virtual bool IsSingleton + { + get => isSingleton; + set + { + scope = (value ? ScopeSingleton : ScopePrototype); + isSingleton = value; + isPrototype = !value; + } + } + + /// + /// Gets a value indicating whether this instance is prototype, with an independent instance + /// returned for each call. + /// + /// + /// true if this instance is prototype; otherwise, false. + /// + public virtual bool IsPrototype => isPrototype; + + /// + /// Is this object lazily initialized? + /// + ///

+ /// Only applicable to a singleton object. + ///

+ ///

+ /// If , it will get instantiated on startup + /// by object factories that perform eager initialization of + /// singletons. + ///

+ ///
+ public bool IsLazyInit + { + get => isLazyInit; + set => isLazyInit = value; + } + + /// + /// Is this object definition a "template", i.e. not meant to be instantiated + /// itself but rather just serving as an object definition for configuration + /// templates used by . + /// + /// + /// if this object definition is a "template". + /// + public bool IsTemplate => isAbstract || (objectType == null && StringUtils.IsNullOrEmpty(factoryObjectName)); + + /// + /// Is this object definition "abstract", i.e. not meant to be + /// instantiated itself but rather just serving as a parent for concrete + /// child object definitions. + /// + /// + /// if this object definition is "abstract". + /// + public bool IsAbstract + { + get => isAbstract; + set => isAbstract = value; + } + + /// + /// The of the object definition (if any). + /// + /// + /// A resolved object . + /// + /// + /// If the of the object definition is not a + /// resolved or . + /// + /// + public Type ObjectType + { + get + { + if (objectType == null) + { + ThrowApplicationException("Object definition does not carry a resolved System.Type"); + return null; + } + + return objectType; + } + set => objectType = value; + } + + private static void ThrowApplicationException(string message) + { + throw new ApplicationException(message); + } + + /// + /// Is the of the object definition a resolved + /// ? + /// + public bool HasObjectType => objectType != null; + + /// + /// Returns the of the + /// of the object definition (if any). + /// + public string ObjectTypeName + { + get => objectTypeName ?? objectType?.FullName; + set => objectTypeName = StringUtils.GetTextOrNull(value); + } + + /// + /// A description of the resource that this object definition + /// came from (for the purpose of showing context in case of errors). + /// + public string ResourceDescription + { + get => resourceDescription; + set => resourceDescription = StringUtils.GetTextOrNull(value); + } + + /// + /// The autowire mode as specified in the object definition. + /// + /// + ///

+ /// This determines whether any automagical detection and setting of + /// object references will happen. The default is + /// , + /// which means that no autowiring will be performed. + ///

+ ///
+ public AutoWiringMode AutowireMode + { + get => autowireMode; + set => autowireMode = value; + } + + /// + /// Gets the resolved autowire mode. + /// + /// + ///

+ /// This resolves + /// + /// to one of + /// + /// or + /// . + ///

+ ///
+ public AutoWiringMode ResolvedAutowireMode + { + get + { + if (AutowireMode == AutoWiringMode.AutoDetect) + { + // Work out whether to apply setter autowiring or constructor autowiring. + // If it has a no-arg constructor it's deemed to be setter autowiring, + // otherwise we'll try constructor autowiring. + ConstructorInfo[] constructors = + ObjectType.GetConstructors(); + foreach (ConstructorInfo ctor in constructors) + { + if (ctor.GetParameters().Length == 0) + { + return AutoWiringMode.ByType; + } + } + + return AutoWiringMode.Constructor; + } + else + { + return AutowireMode; + } + } + } + + /// + /// The dependency checking mode. + /// + /// + ///

+ /// The default is + /// . + ///

+ ///
+ public DependencyCheckingMode DependencyCheck + { + get => dependencyCheck; + set => dependencyCheck = value; + } + + /// + /// The object names that this object depends on. + /// + /// + ///

+ /// The object factory will guarantee that these objects get initialized + /// before this object definition. + ///

+ /// + /// Dependencies are normally expressed through object properties + /// or constructor arguments. This property should just be necessary for + /// other kinds of dependencies such as statics (*ugh*) or database + /// preparation on startup. + /// + ///
+ public IReadOnlyList DependsOn + { + get => dependsOn ?? StringUtils.EmptyStringsList; + set => dependsOn = value != null && value.Count > 0 ? new List(value) : null; + } + + /// + /// Gets or sets a value indicating whether this instance a candidate for getting autowired into some other + /// object. + /// + /// + /// true if this instance is autowire candidate; otherwise, false. + /// + public bool IsAutowireCandidate + { + get => autowireCandidate; + set => autowireCandidate = value; + } + + /// + /// Set whether this bean is a primary autowire candidate. + /// If this value is true for exactly one bean among multiple + /// matching candidates, it will serve as a tie-breaker. + /// + public bool IsPrimary + { + get => primary; + set => primary = value; + } + + /// + /// Register a qualifier to be used for autowire candidate resolution, + /// keyed by the qualifier's type name. + /// + /// + public void AddQualifier(AutowireCandidateQualifier qualifier) + { + qualifiers = qualifiers ?? new Dictionary(); + qualifiers.Add(qualifier.TypeName, qualifier); + } + + /// + /// Return whether this bean has the specified qualifier. + /// + public bool HasQualifier(string typeName) + { + return qualifiers != null && qualifiers.ContainsKey(typeName); + } + + /// + /// Return the qualifier mapped to the provided type name. + /// + public AutowireCandidateQualifier GetQualifier(string typeName) + { + if (qualifiers != null && qualifiers.TryGetValue(typeName, out var qualifier)) + { + return qualifier; + } + + return null; + } + + /// + /// Return all registered qualifiers. + /// + /// the Set of objects. + public Set GetQualifiers() + { + return qualifiers != null + ? new OrderedSet(qualifiers.Values) + : new OrderedSet(); + } + + /// + /// Copy the qualifiers from the supplied AbstractBeanDefinition to this bean definition. + /// + /// the AbstractBeanDefinition to copy from + public void CopyQualifiersFrom(AbstractObjectDefinition source) + { + Trace.Assert(source != null, "Source must not be null"); + if (source.qualifiers != null && source.qualifiers.Count > 0) + { + qualifiers = qualifiers ?? new Dictionary(); + foreach (var qualifier in source.qualifiers) + { + if (!qualifiers.ContainsKey(qualifier.Key)) + { + qualifiers.Add(qualifier.Key, qualifier.Value); + } + } + } + } + + /// + /// The name of the initializer method. + /// + /// + ///

+ /// The default value is the constant, + /// in which case there is no initializer method. + ///

+ ///
+ public string InitMethodName + { + get => initMethodName; + set => initMethodName = StringUtils.GetTextOrNull(value); + } + + /// + /// Return the name of the destroy method. + /// + /// + ///

+ /// The default value is the constant, + /// in which case there is no destroy method. + ///

+ ///
+ public string DestroyMethodName + { + get => destroyMethodName; + set => destroyMethodName = StringUtils.GetTextOrNull(value); + } + + /// + /// The name of the factory method to use (if any). + /// + /// + ///

+ /// This method will be invoked with constructor arguments, or with no + /// arguments if none are specified. The + /// method will be invoked on the specified + /// . + ///

+ ///
+ public string FactoryMethodName + { + get => factoryMethodName; + set => factoryMethodName = StringUtils.GetTextOrNull(value); + } + + /// + /// The name of the factory object to use (if any). + /// + public string FactoryObjectName + { + get => factoryObjectName; + set => factoryObjectName = StringUtils.GetTextOrNull(value); + } + + /// + /// Does this object definition have any constructor argument values? + /// + /// + /// if his object definition has at least one + /// element in it's + /// + /// property. + /// + public bool HasConstructorArgumentValues => constructorArgumentValues != null + && !constructorArgumentValues.Empty; + + /// + /// Resolves the type of the object, resolving it from a specified + /// object type name if necessary. + /// + /// + /// A resolved instance. + /// + /// + /// If the type cannot be resolved. + /// + public Type ResolveObjectType() + { + string typeName = ObjectTypeName; + if (typeName == null) + { + return null; + } + + Type resolvedType = TypeResolutionUtils.ResolveType(typeName); + ObjectType = resolvedType; + return resolvedType; + } + + /// + /// Validate this object definition. + /// + /// + /// In the case of a validation failure. + /// + public virtual void Validate() + { + if (IsLazyInit && !IsSingleton) + { + throw new ObjectDefinitionValidationException( + "Lazy initialization is only applicable to singleton objects."); + } + + if (HasMethodOverrides && StringUtils.HasText(FactoryMethodName)) + { + throw new ObjectDefinitionValidationException( + "Cannot combine static factory method with method overrides: " + + "the static factory method must create the instance."); + } + + if (HasObjectType) + { + PrepareMethodOverrides(); + } + } + + /// + /// Validates all + /// + public virtual void PrepareMethodOverrides() + { + // ascertain that the various lookup methods exist... + foreach (MethodOverride mo in MethodOverrides) + { + PrepareMethodOverride(mo); + } + } + + /// + /// Validate the supplied . + /// + /// + /// The + /// to be validated. + /// + protected void PrepareMethodOverride(MethodOverride methodOverride) + { + if (!ReflectionUtils.HasAtLeastOneMethodWithName(ObjectType, methodOverride.MethodName)) + { + throw new ObjectDefinitionValidationException( + string.Format( + CultureInfo.InvariantCulture, + "Invalid method override: no method with name '{0}' on class [{1}].", + methodOverride.MethodName, ObjectTypeName)); + } + //TODO investigate setting overloaded at this point using MethodCountForName... + //Test SunnyDayReplaceMethod_WithArgumentAcceptingReplacerWithNoTypeFragmentsSpecified + // will fail if doing this optimization. + } + + /// + /// Override settings in this object definition from the supplied + /// object definition. + /// + /// + /// The object definition used to override the member fields of this instance. + /// + public virtual void OverrideFrom(IObjectDefinition other) + { + AssertUtils.ArgumentNotNull(other, "other"); + + IsAbstract = other.IsAbstract; + Scope = other.Scope; + IsLazyInit = other.IsLazyInit; + ConstructorArgumentValues.AddAll(other.ConstructorArgumentValues); + PropertyValues.AddAll(other.PropertyValues.PropertyValues); + EventHandlerValues.AddAll(other.EventHandlerValues); + if (StringUtils.HasText(other.ObjectTypeName)) + { + ObjectTypeName = other.ObjectTypeName; + } + + if (StringUtils.HasText(other.InitMethodName)) + { + InitMethodName = other.InitMethodName; + } + + if (StringUtils.HasText(other.DestroyMethodName)) + { + DestroyMethodName = other.DestroyMethodName; + } + + if (StringUtils.HasText(other.FactoryObjectName)) + { + FactoryObjectName = other.FactoryObjectName; + } + + if (StringUtils.HasText(other.FactoryMethodName)) + { + FactoryMethodName = other.FactoryMethodName; + } + + if (other.DependsOn != null && other.DependsOn.Count > 0) + { + var deps = new List(other.DependsOn.Count + (DependsOn?.Count).GetValueOrDefault()); + deps.AddRange(other.DependsOn); + if (DependsOn != null && DependsOn.Count > 0) + { + deps.AddRange(DependsOn); + } + + DependsOn = deps; + } + + AutowireMode = other.AutowireMode; + ResourceDescription = other.ResourceDescription; + IsPrimary = other.IsPrimary; + IsAutowireCandidate = other.IsAutowireCandidate; + + if (other is AbstractObjectDefinition aod) + { + if (other.ObjectTypeName != null) + { + ObjectTypeName = other.ObjectTypeName; + } + + if (aod.HasObjectType) + { + ObjectType = other.ObjectType; + } + + MethodOverrides.AddAll(aod.MethodOverrides); + DependencyCheck = aod.DependencyCheck; + CopyQualifiersFrom(aod); + } + } + + /// + /// Returns a that represents the current + /// . + /// + /// + /// A that represents the current + /// . + /// + public override string ToString() + { + StringBuilder buffer = new StringBuilder(string.Format("Class [{0}]", ObjectTypeName)); + buffer.Append("; Abstract = ").Append(IsAbstract); + buffer.Append("; Parent = ").Append(ParentName); + buffer.Append("; Scope = ").Append(Scope); + buffer.Append("; Singleton = ").Append(IsSingleton); + buffer.Append("; LazyInit = ").Append(IsLazyInit); + buffer.Append("; Autowire = ").Append(AutowireMode); + buffer.Append("; Autowire-Candidate = ").Append(IsAutowireCandidate); + buffer.Append("; Primary = ").Append(IsPrimary); + buffer.Append("; DependencyCheck = ").Append(DependencyCheck); + buffer.Append("; InitMethodName = ").Append(InitMethodName); + buffer.Append("; DestroyMethodName = ").Append(DestroyMethodName); + buffer.Append("; FactoryMethodName = ").Append(FactoryMethodName); + buffer.Append("; FactoryObjectName = ").Append(FactoryObjectName); + if (StringUtils.HasText(ResourceDescription)) + { + buffer.Append("; defined in = ").Append(ResourceDescription); + } + + return buffer.ToString(); + } + + protected AbstractObjectDefinition(SerializationInfo info, StreamingContext context) + { + constructorArgumentValues = (ConstructorArgumentValues) info.GetValue("constructorArgumentValues", typeof(ConstructorArgumentValues)); + propertyValues = (MutablePropertyValues) info.GetValue("propertyValues", typeof(MutablePropertyValues)); + eventHandlerValues = (EventValues) info.GetValue("eventHandlerValues", typeof(EventValues)); + methodOverrides = (MethodOverrides) info.GetValue("methodOverrides", typeof(MethodOverrides)); + resourceDescription = info.GetString("resourceDescription"); + isSingleton = info.GetBoolean("isSingleton"); + isPrototype = info.GetBoolean("isPrototype"); + isLazyInit = info.GetBoolean("isLazyInit"); + isAbstract = info.GetBoolean("isAbstract"); + scope = info.GetString("scope"); + role = (ObjectRole) info.GetValue("role", typeof(ObjectRole)); + + var objectTypeName = info.GetString("objectTypeName"); + objectType = objectTypeName != null ? Type.GetType(objectTypeName) : null; + + autowireMode = (AutoWiringMode) info.GetValue("autowireMode", typeof(AutoWiringMode)); + dependencyCheck = (DependencyCheckingMode) info.GetValue("dependencyCheck", typeof(DependencyCheckingMode)); + dependsOn = (List) info.GetValue("dependsOn", typeof(List)); + autowireCandidate = info.GetBoolean("autowireCandidate"); + primary = info.GetBoolean("primary"); + qualifiers = (Dictionary) info.GetValue("qualifiers", typeof(Dictionary)); + initMethodName = info.GetString("initMethodName"); + destroyMethodName = info.GetString("destroyMethodName"); + factoryMethodName = info.GetString("factoryMethodName"); + factoryObjectName = info.GetString("factoryObjectName"); + } + + public void GetObjectData(SerializationInfo info, StreamingContext context) + { + info.AddValue("constructorArgumentValues", constructorArgumentValues); + info.AddValue("propertyValues", propertyValues); + info.AddValue("eventHandlerValues", eventHandlerValues); + info.AddValue("methodOverrides", methodOverrides); + info.AddValue("resourceDescription", resourceDescription); + info.AddValue("isSingleton", isSingleton); + info.AddValue("isPrototype", isPrototype); + info.AddValue("isLazyInit", isLazyInit); + info.AddValue("isAbstract", isAbstract); + info.AddValue("scope", scope); + info.AddValue("role", role); + info.AddValue("objectTypeName", objectType.AssemblyQualifiedName); + info.AddValue("autowireMode", autowireMode); + info.AddValue("dependencyCheck", dependencyCheck); + info.AddValue("dependsOn", dependsOn); + info.AddValue("autowireCandidate", autowireCandidate); + info.AddValue("primary", primary); + info.AddValue("qualifiers", qualifiers); + info.AddValue("initMethodName", initMethodName); + info.AddValue("destroyMethodName", destroyMethodName); + info.AddValue("factoryMethodName", factoryMethodName); + info.AddValue("factoryObjectName", factoryObjectName); + } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/AbstractObjectDefinitionReader.cs b/src/Spring/Spring.Core/Objects/Factory/Support/AbstractObjectDefinitionReader.cs index 3e56c9a0..4ff243e2 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/AbstractObjectDefinitionReader.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/AbstractObjectDefinitionReader.cs @@ -22,246 +22,248 @@ using Microsoft.Extensions.Logging; using Spring.Core.IO; using Spring.Util; -namespace Spring.Objects.Factory.Support +namespace Spring.Objects.Factory.Support; + +/// +/// Abstract base class for object definition readers. +/// +/// +///

+/// Provides common properties like the object registry to work on. +///

+///
+/// Juergen Hoeller +/// Rick Evans (.NET) +public abstract class AbstractObjectDefinitionReader : IObjectDefinitionReader { - /// - /// Abstract base class for object definition readers. - /// - /// - ///

- /// Provides common properties like the object registry to work on. - ///

- ///
- /// Juergen Hoeller - /// Rick Evans (.NET) - public abstract class AbstractObjectDefinitionReader : IObjectDefinitionReader - { - #region Constants + #region Constants - /// - /// The instance for this class (and derived classes). - /// - protected readonly ILogger log; + /// + /// The instance for this class (and derived classes). + /// + protected readonly ILogger log; - #endregion + #endregion - #region Constructor (s) / Destructor + #region Constructor (s) / Destructor - /// - /// Creates a new instance of the - /// - /// class. - /// - /// - /// The - /// instance that this reader works on. - /// - /// - ///

- /// This is an class, and as such exposes no public constructors. - ///

- ///
- protected AbstractObjectDefinitionReader(IObjectDefinitionRegistry registry) - : this(registry, AppDomain.CurrentDomain) - { - } + /// + /// Creates a new instance of the + /// + /// class. + /// + /// + /// The + /// instance that this reader works on. + /// + /// + ///

+ /// This is an class, and as such exposes no public constructors. + ///

+ ///
+ protected AbstractObjectDefinitionReader(IObjectDefinitionRegistry registry) + : this(registry, AppDomain.CurrentDomain) + { + } - /// - /// Creates a new instance of the - /// - /// class. - /// - /// - /// The - /// instance that this reader works on. - /// - /// - /// The against which any class names - /// will be resolved into instances. - /// - /// - ///

- /// This is an class, and as such exposes no public constructors. - ///

- ///
- protected AbstractObjectDefinitionReader( - IObjectDefinitionRegistry registry, - AppDomain domain) - { - log = LogManager.GetLogger(this.GetType()); + /// + /// Creates a new instance of the + /// + /// class. + /// + /// + /// The + /// instance that this reader works on. + /// + /// + /// The against which any class names + /// will be resolved into instances. + /// + /// + ///

+ /// This is an class, and as such exposes no public constructors. + ///

+ ///
+ protected AbstractObjectDefinitionReader( + IObjectDefinitionRegistry registry, + AppDomain domain) + { + log = LogManager.GetLogger(this.GetType()); - AssertUtils.ArgumentNotNull(registry, "registry", "IObjectDefinitionRegistry must not be null"); - _registry = registry; - _domain = domain; - if (registry is IResourceLoader) + AssertUtils.ArgumentNotNull(registry, "registry", "IObjectDefinitionRegistry must not be null"); + _registry = registry; + _domain = domain; + if (registry is IResourceLoader) + { + _resourceLoader = registry as IResourceLoader; + } + else + { + _resourceLoader = new ConfigurableResourceLoader(); + } + } + + #endregion + + #region Properties + + /// + /// Gets the + /// + /// instance that this reader works on. + /// + public IObjectDefinitionRegistry Registry + { + get { return _registry; } + } + + /// + /// The to use for anonymous + /// objects (wihtout explicit object name specified). + /// + /// + public IObjectNameGenerator ObjectNameGenerator + { + get { return _objectNameGenerator; } + set + { + if (value != null) { - _resourceLoader = registry as IResourceLoader; + _objectNameGenerator = value; } else { - _resourceLoader = new ConfigurableResourceLoader(); + _objectNameGenerator = new DefaultObjectNameGenerator(); } - } + } + } - #endregion + /// + /// The against which any class names + /// will be resolved into instances. + /// + public AppDomain Domain + { + get { return _domain; } + } - #region Properties + /// + /// Gets or sets the resource loader to use for resource locations. + /// + /// The resource loader. + public IResourceLoader ResourceLoader + { + get { return _resourceLoader; } + set { _resourceLoader = value; } + } - /// - /// Gets the - /// - /// instance that this reader works on. - /// - public IObjectDefinitionRegistry Registry - { - get { return _registry; } - } + #endregion + #region Methods - /// - /// The to use for anonymous - /// objects (wihtout explicit object name specified). - /// - /// - public IObjectNameGenerator ObjectNameGenerator - { - get { return _objectNameGenerator; } - set - { - if (value != null) - { - _objectNameGenerator = value; - } - else - { - _objectNameGenerator = new DefaultObjectNameGenerator(); - } - } - } + /// + /// Load object definitions from the supplied . + /// + /// + /// The resource for the object definitions that are to be loaded. + /// + /// + /// The number of object definitions that were loaded. + /// + /// + /// In the case of loading or parsing errors. + /// + public abstract int LoadObjectDefinitions(IResource resource); - /// - /// The against which any class names - /// will be resolved into instances. - /// - public AppDomain Domain - { - get { return _domain; } - } + /// + /// Load object definitions from the supplied . + /// + /// + /// The resources for the object definitions that are to be loaded. + /// + /// + /// The number of object definitions found + /// + /// + /// In the case of loading or parsing errors. + /// + public int LoadObjectDefinitions(IResource[] resources) + { + AssertUtils.ArgumentNotNull(resources, "resources"); + int counter = 0; + foreach (IResource resource in resources) + { + counter += LoadObjectDefinitions(resource); + } + return counter; + } - /// - /// Gets or sets the resource loader to use for resource locations. - /// - /// The resource loader. - public IResourceLoader ResourceLoader - { - get { return _resourceLoader; } - set { _resourceLoader = value; } - } + /// + /// Loads the object definitions from the specified resource location. + /// + /// The resource location, to be loaded with the + /// IResourceLoader location . + /// + /// The number of object definitions found + /// + public int LoadObjectDefinitions(string location) + { + if (ResourceLoader == null) + { + throw new ObjectDefinitionStoreException("Cannot import object definitions from location [" + location + + "]:" + + " no ResourceLoader available"); + } - #endregion + IResource resource; + try + { + resource = ResourceLoader.GetResource(location); + } + catch (Exception e) + { + throw new ObjectDefinitionStoreException("Could not resolve resource location [" + location + "]", e); + } - #region Methods + int loadCount = LoadObjectDefinitions(resource); - /// - /// Load object definitions from the supplied . - /// - /// - /// The resource for the object definitions that are to be loaded. - /// - /// - /// The number of object definitions that were loaded. - /// - /// - /// In the case of loading or parsing errors. - /// - public abstract int LoadObjectDefinitions(IResource resource); + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug("Loaded " + loadCount + " object definitions from location [" + location + "]"); + } - /// - /// Load object definitions from the supplied . - /// - /// - /// The resources for the object definitions that are to be loaded. - /// - /// - /// The number of object definitions found - /// - /// - /// In the case of loading or parsing errors. - /// - public int LoadObjectDefinitions(IResource[] resources) - { - AssertUtils.ArgumentNotNull(resources, "resources"); - int counter = 0; - foreach (IResource resource in resources) - { - counter += LoadObjectDefinitions(resource); - } - return counter; - } + return loadCount; + } - /// - /// Loads the object definitions from the specified resource location. - /// - /// The resource location, to be loaded with the - /// IResourceLoader location . - /// - /// The number of object definitions found - /// - public int LoadObjectDefinitions(string location) - { - if (ResourceLoader == null) - { - throw new ObjectDefinitionStoreException("Cannot import object definitions from location [" + location + - "]:" + - " no ResourceLoader available"); - } - IResource resource; - try - { - resource = ResourceLoader.GetResource(location); - } catch (Exception e) - { - throw new ObjectDefinitionStoreException("Could not resolve resource location [" + location + "]",e); - } - int loadCount = LoadObjectDefinitions(resource); + /// + /// Loads the object definitions from the specified resource locations. + /// + /// The the resource locations to be loaded with the + /// IResourceLoader of this object definition reader. + /// + /// The number of object definitions found + /// + public int LoadObjectDefinitions(string[] locations) + { + AssertUtils.ArgumentNotNull(locations, "location"); + int counter = 0; + foreach (string location in locations) + { + counter += LoadObjectDefinitions(location); + } - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug("Loaded " + loadCount + " object definitions from location [" + location + "]"); - } - return loadCount; - } + return counter; + } + #endregion - /// - /// Loads the object definitions from the specified resource locations. - /// - /// The the resource locations to be loaded with the - /// IResourceLoader of this object definition reader. - /// - /// The number of object definitions found - /// - public int LoadObjectDefinitions(string[] locations) - { - AssertUtils.ArgumentNotNull(locations, "location"); - int counter = 0; - foreach (string location in locations) - { - counter += LoadObjectDefinitions(location); - } - return counter; - } + #region Fields - #endregion + private IObjectDefinitionRegistry _registry; + private AppDomain _domain; + private IResourceLoader _resourceLoader; + private IObjectNameGenerator _objectNameGenerator = new DefaultObjectNameGenerator(); - #region Fields - - private IObjectDefinitionRegistry _registry; - private AppDomain _domain; - private IResourceLoader _resourceLoader; - private IObjectNameGenerator _objectNameGenerator = new DefaultObjectNameGenerator(); - - #endregion - } -} + #endregion +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/AbstractObjectFactory.cs b/src/Spring/Spring.Core/Objects/Factory/Support/AbstractObjectFactory.cs index ec89c220..c3b2dee9 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/AbstractObjectFactory.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/AbstractObjectFactory.cs @@ -18,8 +18,6 @@ using System.Collections; using System.Collections.Concurrent; using System.Collections.Specialized; using System.ComponentModel; - - using Spring.Collections; using Spring.Core; using Spring.Core.TypeConversion; @@ -30,1676 +28,1716 @@ using System.Threading; using System.Runtime.Serialization; using Microsoft.Extensions.Logging; -namespace Spring.Objects.Factory.Support +namespace Spring.Objects.Factory.Support; + +/// +/// Abstract superclass for +/// implementations. +/// +/// +///

+/// This class provides singleton / prototype determination, singleton caching, +/// object definition aliasing, +/// handling, and object definition merging for child object definitions. +///

+///
+/// Rod Johnson +/// Juergen Hoeller +/// Rick Evans (.NET) +[Serializable] +public abstract class AbstractObjectFactory : IConfigurableObjectFactory { /// - /// Abstract superclass for - /// implementations. + /// Marker object to be temporarily registered in the singleton cache, + /// while instantiating an object (in order to be able to detect circular references). + /// + private static readonly object CurrentlyInCreation = new object(); + + /// + /// Used as value in hashtable that keeps track of singleton names currently in the + /// process of being created. Would not be necessary if we created a case insensitive implementation of + /// ISet. + /// + private static readonly object EmptyObject = new object(); + + /// + /// The instance for this class. + /// + [NonSerialized] protected ILogger log; + + /// + /// Cache of singleton objects created by s: FactoryObject name -> product + /// + private readonly Dictionary factoryObjectProductCache = new Dictionary(); + + /// + /// Disposable object instances: object name --> disposable instance + /// + private readonly Dictionary disposableObjects = new Dictionary(); + + /// + /// root object definitons: object name --> Root Object Definition + /// + protected ConcurrentDictionary mergedObjectDefinitions = new ConcurrentDictionary(); + + /// + /// Whether to cache object metadata or rather reobtain it for every access + /// + private bool cacheObjectMetadata = true; + + /// + /// Names of object that have already been created at least once + /// + private readonly HashSet alreadyCreated = new HashSet(); + + /// + /// Creates a new instance of the + /// class. /// /// ///

- /// This class provides singleton / prototype determination, singleton caching, - /// object definition aliasing, - /// handling, and object definition merging for child object definitions. + /// This constructor implicitly creates an + /// + /// that treats the names of objects in this factory in a case-sensitive fashion. + ///

+ ///

+ /// This is an class, and as such exposes no public constructors. ///

///
- /// Rod Johnson - /// Juergen Hoeller - /// Rick Evans (.NET) - [Serializable] - public abstract class AbstractObjectFactory : IConfigurableObjectFactory + protected AbstractObjectFactory() + : this(true) { - /// - /// Marker object to be temporarily registered in the singleton cache, - /// while instantiating an object (in order to be able to detect circular references). - /// - private static readonly object CurrentlyInCreation = new object(); + } - /// - /// Used as value in hashtable that keeps track of singleton names currently in the - /// process of being created. Would not be necessary if we created a case insensitive implementation of - /// ISet. - /// - private static readonly object EmptyObject = new object(); + /// + /// Creates a new instance of the + /// class. + /// + /// + ///

+ /// This is an class, and as such exposes no public constructors. + ///

+ ///
+ /// + /// if the names of objects in this factory are to be treated in a + /// case-sensitive fashion. + /// + protected AbstractObjectFactory(bool caseSensitive) + { + log = LogManager.GetLogger(GetType()); + this.caseSensitive = caseSensitive; - /// - /// The instance for this class. - /// - [NonSerialized] protected ILogger log; + var comparer = (caseSensitive) ? StringComparer.Ordinal : StringComparer.OrdinalIgnoreCase; + aliasMap = new OrderedDictionary(comparer); + singletonCache = new OrderedDictionary(comparer); + singletonLocks = new ConcurrentDictionary>(comparer); + singletonsInCreation = new OrderedDictionary(comparer); + prototypesInCreation = new LogicalThreadContextSetVariable(); + } - /// - /// Cache of singleton objects created by s: FactoryObject name -> product - /// - private readonly Dictionary factoryObjectProductCache = new Dictionary(); + [OnDeserializing] + private void OnDeserializing(StreamingContext c) + { + log = LogManager.GetLogger(GetType()); + } - /// - /// Disposable object instances: object name --> disposable instance - /// - private readonly Dictionary disposableObjects = new Dictionary(); + /// + /// Creates a new instance of the + /// class. + /// + /// + ///

+ /// This is an class, and as such exposes no public constructors. + ///

+ ///
+ /// + /// if the names of objects in this factory are to be treated in a + /// case-sensitive fashion. + /// + /// + /// Any parent object factory; may be . + /// + protected AbstractObjectFactory(bool caseSensitive, IObjectFactory parentFactory) + : this(caseSensitive) + { + ParentObjectFactory = parentFactory; + } - /// - /// root object definitons: object name --> Root Object Definition - /// - protected ConcurrentDictionary mergedObjectDefinitions = new ConcurrentDictionary(); + /// + /// Returns, whether this factory treats object names case sensitive or not. + /// + public bool IsCaseSensitive => caseSensitive; - /// - /// Whether to cache object metadata or rather reobtain it for every access - /// - private bool cacheObjectMetadata = true; + /// + /// Gets the of + /// s + /// that will be applied to objects created by this factory. + /// + public IReadOnlyList ObjectPostProcessors => objectPostProcessors; - /// - /// Names of object that have already been created at least once - /// - private readonly HashSet alreadyCreated = new HashSet(); + /// + /// Gets the set of classes that will be ignored for autowiring. + /// + /// + ///

+ /// The elements of this are + /// s. + ///

+ ///
+ public ISet IgnoredDependencyTypes => ignoreDependencyTypes; - /// - /// Creates a new instance of the - /// class. - /// - /// - ///

- /// This constructor implicitly creates an - /// - /// that treats the names of objects in this factory in a case-sensitive fashion. - ///

- ///

- /// This is an class, and as such exposes no public constructors. - ///

- ///
- protected AbstractObjectFactory() - : this(true) + /// + /// Returns, whether this object factory instance contains objects. + /// + protected bool HasInstantiationAwareObjectPostProcessors => hasInstantiationAwareObjectPostProcessors; + + /// + /// Returns, whether this object factory instance contains objects. + /// + protected bool HasDestructionAwareObjectPostProcessors => hasDestructionAwareObjectPostProcessors; + + /// + /// Check whether this factory's bean creation phase already started, + /// i.e. whether any bean has been marked as created in the meantime. + /// + protected bool HasObjectCreationStarted => alreadyCreated.Count > 0; + + /// + /// Return an instance (possibly shared or independent) of the given object name. + /// + /// + /// + /// This method allows an object factory to be used as a replacement for the + /// Singleton or Prototype design pattern. + /// + /// + /// Note that callers should retain references to returned objects. There is no + /// guarantee that this method will be implemented to be efficient. For example, + /// it may be synchronized, or may need to run an RDBMS query. + /// + /// + /// Will ask the parent factory if the object cannot be found in this factory + /// instance. + /// + /// + /// The name of the object to return. + /// + /// The arguments to use if creating a prototype using explicit arguments to + /// a static factory method. If there is no factory method and the + /// arguments are not null, then match the argument values by type and + /// call the object's constructor. + /// + /// The instance of the object. + /// + /// If there's no such object definition. + /// + /// + /// If the object could not be created. + /// + /// + /// If the object is not of the required type. + /// + /// + /// If the supplied is . + /// + public T GetObject(string name, object[] arguments) + { + return (T) GetObject(name, typeof(T), arguments); + } + + /// + /// Return an instance (possibly shared or independent) of the given object name. + /// + /// The name of the object to return. + /// + /// The the object may match. Can be an interface or + /// superclass of the actual class. For example, if the value is the + /// class, this method will succeed whatever the + /// class of the returned instance. + /// + /// + /// The arguments to use if creating a prototype using explicit arguments to + /// a factory method. If there is no factory method and the + /// supplied array is not , then + /// match the argument values by type and call the object's constructor. + /// + /// The instance of the object. + /// + /// If there's no such object definition. + /// + /// + /// If the object could not be created. + /// + /// + /// If the object is not of the required type. + /// + /// + /// If the supplied is . + /// + /// + public object GetObject(string name, Type requiredType, object[] arguments) + { + return GetObjectInternal(name, requiredType, arguments, false); + } + + /// + /// Apply the property values of the object definition with the supplied + /// to the supplied . + /// + /// + ///

+ /// The object definition can either define a fully self-contained object, + /// reusing it's property values, or just property values meant to be used + /// for existing object instances. + ///

+ ///
+ /// + /// The existing object that the property values for the named object will + /// be applied to. + /// + /// + /// The name of the object definition associated with the property values that are + /// to be applied. + /// + /// + /// In case of errors. + /// + public virtual void ApplyObjectPropertyValues(object instance, string name) + { + // explicit no-op... + } + + /// + /// Apply the property values of the object definition with the supplied + /// to the supplied . + /// + /// + ///

+ /// The object definition can either define a fully self-contained object, + /// reusing it's property values, or just property values meant to be used + /// for existing object instances. + ///

+ ///
+ /// + /// The existing object that the property values for the named object will + /// be applied to. + /// + /// + /// The name of the object definition associated with the property values that are + /// to be applied. + /// + /// + /// An object definition that should be used to apply property values. + /// + /// + /// In case of errors. + /// + public virtual void ApplyObjectPropertyValues(object instance, string name, IObjectDefinition definition) + { + // explicit no-op... + } + + // /// + // /// Create an object instance for the given object definition. + // /// + // /// + // ///

+ // /// The object definition will already have been merged with the parent + // /// definition in case of a child definition. + // ///

+ // ///

+ // /// All the other methods in this class invoke this method, although objects + // /// may be cached after being instantiated by this method. All object + // /// instantiation within this class is performed by this method. + // ///

+ // ///
+ // /// The name of the object. + // /// + // /// The object definition for the object that is to be instantiated. + // /// + // /// + // /// The arguments to use if creating a prototype using explicit arguments to + // /// a factory method. If there is no factory method and the + // /// supplied array is not , + // /// then match the argument values by type and call the object's constructor. + // /// + // /// + // /// A new instance of the object. + // /// + // /// + // /// In case of errors. + // /// + // protected internal abstract object CreateObject(string name, RootObjectDefinition definition, object[] arguments); + + /// + /// Create an object instance for the given object definition. + /// + /// The name of the object. + /// + /// The object definition for the object that is to be instantiated. + /// + /// + /// The arguments to use if creating a prototype using explicit arguments to + /// a static factory method. It is invalid to use a non- arguments value + /// in any other case. + /// + /// + /// Whether eager caching of singletons is allowed... typically true for + /// singlton objects, but never true for inner object definitions. + /// + /// + /// Create instance only - suppress injecting dependencies yet. + /// + /// + /// A new instance of the object. + /// + /// + /// In case of errors. + /// + /// + ///

+ /// The object definition will already have been merged with the parent + /// definition in case of a child definition. + ///

+ ///

+ /// All the other methods in this class invoke this method, although objects + /// may be cached after being instantiated by this method. All object + /// instantiation within this class is performed by this method. + ///

+ ///
+ protected internal abstract object InstantiateObject(string name, RootObjectDefinition definition, object[] arguments, + bool allowEagerCaching, bool suppressConfigure); + + /// + /// Destroy the target object. + /// + /// + ///

+ /// Must destroy objects that depend on the given object before the object itself, + /// nor throw an exception. + ///

+ ///
+ /// + /// The name of the object. + /// + /// + /// The target object instance to destroyed. + /// + protected abstract void DestroyObject(string name, object target); + + /// + /// Does this object factory contain an object definition with the + /// supplied ? + /// + /// + ///

+ /// Does not consider any hierarchy this factory may participate in. + /// Invoked by + /// + /// when no cached singleton instance is found. + ///

+ ///
+ /// + /// The name of the object to look for. + /// + /// + /// if this object factory contains an object + /// definition with the supplied . + /// + public abstract bool ContainsObjectDefinition(string name); + + /// + /// Adds the supplied (object) to this factory's + /// singleton cache. + /// + /// + ///

+ /// To be called for eager registration of singletons, e.g. to be able to + /// resolve circular references. + ///

+ /// + /// If a singleton has already been registered under the same name as + /// the supplied , then the old singleton will + /// be replaced. + /// + ///
+ /// The name of the object. + /// The singleton object. + /// + /// If the argument is + /// or consists wholly of whitespace characters; or if the + /// is . + /// + protected virtual void AddSingleton(string name, object singleton) + { + AssertUtils.ArgumentHasText(name, "The object name must not be empty."); + AssertUtils.ArgumentNotNull(singleton, "singleton"); + lock (GetSingletonLockFor(name)) { + singletonCache[name] = singleton; + registeredSingletons.Add(name); + } + } + + /// + /// Return the object name, stripping out the factory dereference prefix if + /// necessary, and resolving aliases to canonical names. + /// + /// + /// The transformed name of the object. + /// + protected string TransformedObjectName(string name) + { + string objectName = ObjectFactoryUtils.TransformedObjectName(name); + + if (aliasMap.Count > 0) + { + // handle aliasing... + string canonicalName = (string) aliasMap[objectName]; + return canonicalName ?? objectName; } - /// - /// Creates a new instance of the - /// class. - /// - /// - ///

- /// This is an class, and as such exposes no public constructors. - ///

- ///
- /// - /// if the names of objects in this factory are to be treated in a - /// case-sensitive fashion. - /// - protected AbstractObjectFactory(bool caseSensitive) - { - log = LogManager.GetLogger(GetType()); - this.caseSensitive = caseSensitive; + return objectName; + } - var comparer = (caseSensitive) ? StringComparer.Ordinal : StringComparer.OrdinalIgnoreCase; - aliasMap = new OrderedDictionary(comparer); - singletonCache = new OrderedDictionary(comparer); - singletonLocks = new ConcurrentDictionary>(comparer); - singletonsInCreation = new OrderedDictionary(comparer); - prototypesInCreation = new LogicalThreadContextSetVariable(); + /// + /// Ensures, that the given name is prefixed with + /// if it incidentially already starts with this prefix. This avoids troubles when dereferencing + /// the object name during + /// + protected string OriginalObjectName(string name) + { + string objectName = TransformedObjectName(name); + if (name.StartsWith(ObjectFactoryUtils.FactoryObjectPrefix)) + { + objectName = ObjectFactoryUtils.FactoryObjectPrefix + objectName; } - [OnDeserializing] - private void OnDeserializing(StreamingContext c) - { - log = LogManager.GetLogger(GetType()); - } - - /// - /// Creates a new instance of the - /// class. - /// - /// - ///

- /// This is an class, and as such exposes no public constructors. - ///

- ///
- /// - /// if the names of objects in this factory are to be treated in a - /// case-sensitive fashion. - /// - /// - /// Any parent object factory; may be . - /// - protected AbstractObjectFactory(bool caseSensitive, IObjectFactory parentFactory) - : this(caseSensitive) - { - ParentObjectFactory = parentFactory; - } - - /// - /// Returns, whether this factory treats object names case sensitive or not. - /// - public bool IsCaseSensitive => caseSensitive; - - /// - /// Gets the of - /// s - /// that will be applied to objects created by this factory. - /// - public IReadOnlyList ObjectPostProcessors => objectPostProcessors; - - /// - /// Gets the set of classes that will be ignored for autowiring. - /// - /// - ///

- /// The elements of this are - /// s. - ///

- ///
- public ISet IgnoredDependencyTypes => ignoreDependencyTypes; - - /// - /// Returns, whether this object factory instance contains objects. - /// - protected bool HasInstantiationAwareObjectPostProcessors => hasInstantiationAwareObjectPostProcessors; - - /// - /// Returns, whether this object factory instance contains objects. - /// - protected bool HasDestructionAwareObjectPostProcessors => hasDestructionAwareObjectPostProcessors; - - /// - /// Check whether this factory's bean creation phase already started, - /// i.e. whether any bean has been marked as created in the meantime. - /// - protected bool HasObjectCreationStarted => alreadyCreated.Count > 0; - - /// - /// Return an instance (possibly shared or independent) of the given object name. - /// - /// - /// - /// This method allows an object factory to be used as a replacement for the - /// Singleton or Prototype design pattern. - /// - /// - /// Note that callers should retain references to returned objects. There is no - /// guarantee that this method will be implemented to be efficient. For example, - /// it may be synchronized, or may need to run an RDBMS query. - /// - /// - /// Will ask the parent factory if the object cannot be found in this factory - /// instance. - /// - /// - /// The name of the object to return. - /// - /// The arguments to use if creating a prototype using explicit arguments to - /// a static factory method. If there is no factory method and the - /// arguments are not null, then match the argument values by type and - /// call the object's constructor. - /// - /// The instance of the object. - /// - /// If there's no such object definition. - /// - /// - /// If the object could not be created. - /// - /// - /// If the object is not of the required type. - /// - /// - /// If the supplied is . - /// - public T GetObject(string name, object[] arguments) - { - return (T)GetObject(name, typeof(T), arguments); - } - - /// - /// Return an instance (possibly shared or independent) of the given object name. - /// - /// The name of the object to return. - /// - /// The the object may match. Can be an interface or - /// superclass of the actual class. For example, if the value is the - /// class, this method will succeed whatever the - /// class of the returned instance. - /// - /// - /// The arguments to use if creating a prototype using explicit arguments to - /// a factory method. If there is no factory method and the - /// supplied array is not , then - /// match the argument values by type and call the object's constructor. - /// - /// The instance of the object. - /// - /// If there's no such object definition. - /// - /// - /// If the object could not be created. - /// - /// - /// If the object is not of the required type. - /// - /// - /// If the supplied is . - /// - /// - public object GetObject(string name, Type requiredType, object[] arguments) - { - return GetObjectInternal(name, requiredType, arguments, false); - } - - /// - /// Apply the property values of the object definition with the supplied - /// to the supplied . - /// - /// - ///

- /// The object definition can either define a fully self-contained object, - /// reusing it's property values, or just property values meant to be used - /// for existing object instances. - ///

- ///
- /// - /// The existing object that the property values for the named object will - /// be applied to. - /// - /// - /// The name of the object definition associated with the property values that are - /// to be applied. - /// - /// - /// In case of errors. - /// - public virtual void ApplyObjectPropertyValues(object instance, string name) - { - // explicit no-op... - } - - /// - /// Apply the property values of the object definition with the supplied - /// to the supplied . - /// - /// - ///

- /// The object definition can either define a fully self-contained object, - /// reusing it's property values, or just property values meant to be used - /// for existing object instances. - ///

- ///
- /// - /// The existing object that the property values for the named object will - /// be applied to. - /// - /// - /// The name of the object definition associated with the property values that are - /// to be applied. - /// - /// - /// An object definition that should be used to apply property values. - /// - /// - /// In case of errors. - /// - public virtual void ApplyObjectPropertyValues(object instance, string name, IObjectDefinition definition) - { - // explicit no-op... - } - - // /// - // /// Create an object instance for the given object definition. - // /// - // /// - // ///

- // /// The object definition will already have been merged with the parent - // /// definition in case of a child definition. - // ///

- // ///

- // /// All the other methods in this class invoke this method, although objects - // /// may be cached after being instantiated by this method. All object - // /// instantiation within this class is performed by this method. - // ///

- // ///
- // /// The name of the object. - // /// - // /// The object definition for the object that is to be instantiated. - // /// - // /// - // /// The arguments to use if creating a prototype using explicit arguments to - // /// a factory method. If there is no factory method and the - // /// supplied array is not , - // /// then match the argument values by type and call the object's constructor. - // /// - // /// - // /// A new instance of the object. - // /// - // /// - // /// In case of errors. - // /// - // protected internal abstract object CreateObject(string name, RootObjectDefinition definition, object[] arguments); - - - /// - /// Create an object instance for the given object definition. - /// - /// The name of the object. - /// - /// The object definition for the object that is to be instantiated. - /// - /// - /// The arguments to use if creating a prototype using explicit arguments to - /// a static factory method. It is invalid to use a non- arguments value - /// in any other case. - /// - /// - /// Whether eager caching of singletons is allowed... typically true for - /// singlton objects, but never true for inner object definitions. - /// - /// - /// Create instance only - suppress injecting dependencies yet. - /// - /// - /// A new instance of the object. - /// - /// - /// In case of errors. - /// - /// - ///

- /// The object definition will already have been merged with the parent - /// definition in case of a child definition. - ///

- ///

- /// All the other methods in this class invoke this method, although objects - /// may be cached after being instantiated by this method. All object - /// instantiation within this class is performed by this method. - ///

- ///
- protected internal abstract object InstantiateObject(string name, RootObjectDefinition definition, object[] arguments, - bool allowEagerCaching, bool suppressConfigure); - - /// - /// Destroy the target object. - /// - /// - ///

- /// Must destroy objects that depend on the given object before the object itself, - /// nor throw an exception. - ///

- ///
- /// - /// The name of the object. - /// - /// - /// The target object instance to destroyed. - /// - protected abstract void DestroyObject(string name, object target); - - /// - /// Does this object factory contain an object definition with the - /// supplied ? - /// - /// - ///

- /// Does not consider any hierarchy this factory may participate in. - /// Invoked by - /// - /// when no cached singleton instance is found. - ///

- ///
- /// - /// The name of the object to look for. - /// - /// - /// if this object factory contains an object - /// definition with the supplied . - /// - public abstract bool ContainsObjectDefinition(string name); - - /// - /// Adds the supplied (object) to this factory's - /// singleton cache. - /// - /// - ///

- /// To be called for eager registration of singletons, e.g. to be able to - /// resolve circular references. - ///

- /// - /// If a singleton has already been registered under the same name as - /// the supplied , then the old singleton will - /// be replaced. - /// - ///
- /// The name of the object. - /// The singleton object. - /// - /// If the argument is - /// or consists wholly of whitespace characters; or if the - /// is . - /// - protected virtual void AddSingleton(string name, object singleton) - { - AssertUtils.ArgumentHasText(name, "The object name must not be empty."); - AssertUtils.ArgumentNotNull(singleton, "singleton"); - lock (GetSingletonLockFor(name)) - { - singletonCache[name] = singleton; - registeredSingletons.Add(name); - } - } - - /// - /// Return the object name, stripping out the factory dereference prefix if - /// necessary, and resolving aliases to canonical names. - /// - /// - /// The transformed name of the object. - /// - protected string TransformedObjectName(string name) - { - string objectName = ObjectFactoryUtils.TransformedObjectName(name); - - if (aliasMap.Count > 0) - { - // handle aliasing... - string canonicalName = (string) aliasMap[objectName]; - return canonicalName ?? objectName; - } - - return objectName; - } - - /// - /// Ensures, that the given name is prefixed with - /// if it incidentially already starts with this prefix. This avoids troubles when dereferencing - /// the object name during - /// - protected string OriginalObjectName(string name) - { - string objectName = TransformedObjectName(name); - if (name.StartsWith(ObjectFactoryUtils.FactoryObjectPrefix)) - { - objectName = ObjectFactoryUtils.FactoryObjectPrefix + objectName; - } - return objectName; - } - - /// - /// Determines whether the specified name is defined as an alias as opposed - /// to the name of an actual object definition. - /// - /// The object name to check. - /// - /// true if the specified name is alias; otherwise, false. - /// - protected bool IsAlias(string name) - { - return aliasMap.Contains(name); - } - - /// - /// Return a , - /// even by traversing parent if the parameter is a child definition. - /// - /// - /// The name of the object. - /// - /// - /// Are ancestors to be included in the merge? - /// - /// - ///

- /// Will ask the parent object factory if not found in this instance. - ///

- ///
- /// - /// A merged - /// with overridden properties. - /// - public virtual RootObjectDefinition GetMergedObjectDefinition(string name, bool includingAncestors) - { - return GetMergedObjectDefinition(name, GetObjectDefinition(name, includingAncestors)); - } - - /// - /// Return a , - /// even by traversing parent if the parameter is a child definition. - /// - /// The name. - /// The od. - /// - /// A merged - /// with overridden properties. - /// - protected internal virtual RootObjectDefinition GetMergedObjectDefinition(string name, IObjectDefinition od) - { - return GetMergedLocalObjectDefinition(name) ?? GetMergedObjectDefinitionInternal(name, od); - } - - /// - /// Return a , - /// even by traversing parent if the parameter is a child definition. - /// - /// - /// A merged - /// with overridden properties. - /// - protected internal virtual RootObjectDefinition GetMergedObjectDefinitionInternal(string name, IObjectDefinition od) - { - if (od == null) - { - return null; - } - - // Check with full lock now in order to enforce the same merged instance. - RootObjectDefinition ValueFactory(string key) - { - RootObjectDefinition mod; - if (od.ParentName == null) - { - mod = CreateRootObjectDefinition(od); - } - else - { - IObjectDefinition pod = null; - if (!key.Equals(od.ParentName)) - { - pod = GetMergedObjectDefinition(TransformedObjectName(od.ParentName), true); - } - else - { - if (ParentObjectFactory is AbstractObjectFactory factory) - { - pod = factory.GetMergedObjectDefinition(od.ParentName, true); - } - } - - if (pod == null) - { - throw new NoSuchObjectDefinitionException(od.ParentName, $"Parent name '{od.ParentName}' is equal to object name '{key}' - " + "cannot be resolved without an AbstractObjectFactory parent."); - } - - mod = CreateRootObjectDefinition(pod); - mod.OverrideFrom(od); - } - - return mod; - } - - // Only cache the merged bean definition if we're already about to create an - // instance of the object, or at least have already created an instance before. - if (CacheObjectMetadata && IsObjectEligibleForMetadataCaching(name)) - { - return mergedObjectDefinitions.GetOrAdd(name, ValueFactory); - } - - return ValueFactory(name); - } - - /// - /// Gets the merged local object definition. - /// - /// Name of the object. - /// - /// Merged RootBeanDefinition, traversing the parent bean definition - /// if the specified bean corresponds to a child bean definition. - /// - protected RootObjectDefinition GetMergedLocalObjectDefinition(string objectName) - { - mergedObjectDefinitions.TryGetValue(objectName, out var mbd); - return mbd; // ?? GetMergedObjectDefinition(objectName, GetObjectDefinition(objectName)); - } - - /// - /// Determines whether the metadata for the specified object name is eligible for caching. - /// - /// Name of the bean. - /// - /// true if [is object eligible for metadata caching] [the specified bean name]; otherwise, false. - /// - protected virtual bool IsObjectEligibleForMetadataCaching(string beanName) - { - return alreadyCreated.Contains(beanName); - } - - protected bool CacheObjectMetadata - { - get => cacheObjectMetadata; - set => cacheObjectMetadata = value; - } - - /// - /// Creates the root object definition. - /// - /// The template definition to base root definition on. - /// Root object definition. - protected virtual RootObjectDefinition CreateRootObjectDefinition(IObjectDefinition templateDefinition) - { - return new RootObjectDefinition(templateDefinition); - } - - /// - /// Register a new object definition with this registry. - /// - /// - /// The name of the object instance to register. - /// - /// - /// The definition of the object instance to register. - /// - /// - /// If the object definition is invalid. - /// - /// - public abstract void RegisterObjectDefinition(string name, IObjectDefinition objectDefinition); - - /// - /// Return the registered - /// for the - /// given object, allowing access to its property values and constructor - /// argument values. - /// - /// The name of the object. - /// - /// The registered - /// . - /// - /// - /// If there is no object with the given name. - /// - /// - /// In the case of errors. - /// - public abstract IObjectDefinition GetObjectDefinition(string name); - - /// - /// Return the registered - /// for the - /// given object, allowing access to its property values and constructor - /// argument values. - /// - /// The name of the object. - /// Whether to search parent object factories. - /// - /// The registered - /// . - /// - /// - /// If there is no object with the given name. - /// - /// - /// In the case of errors. - /// - public abstract IObjectDefinition GetObjectDefinition(string name, bool includeAncestors); - - /// - /// Gets the type for the given FactoryObject. - /// - /// The factory object instance to check. - /// the FactoryObject's object type - protected virtual Type GetTypeForFactoryObject(IFactoryObject factoryObject) - { - try - { - return factoryObject.ObjectType; - } - catch (Exception ex) - { - log.LogWarning(ex, "FactoryObject threw exception from ObjectType, despite the contract saying " + - "that it should return null if the type of its object cannot be determined yet"); - return null; - } - } - - /// - /// Gets the object type for the given FactoryObject definition, as far as possible. - /// Only called if there is no singleton instance registered for the target object already. - /// - /// - /// The default implementation creates the FactoryObject via GetObject - /// to call its ObjectType property. Subclasses are encouraged to optimize - /// this, typically by just instantiating the FactoryObject but not populating it yet, - /// trying whether its ObjectType property already returns a type. - /// If no type found, a full FactoryObject creation as performed by this implementation - /// should be used as fallback. - /// - /// Name of the object. - /// The merged object definition for the object. - /// The type for the object if determinable, or null otherwise - protected virtual Type GetTypeForFactoryObject(string objectName, RootObjectDefinition mod) - { - if (!mod.IsSingleton) - { - return null; - } - try - { - IFactoryObject factoryObject = GetFactoryObject(objectName); - return GetTypeForFactoryObject(factoryObject); - } - catch (ObjectCreationException ex) - { - // Can only happen when getting a FactoryObject. - log.LogWarning(ex, "Ignoring object creation exception on FactoryObject type check"); - return null; - } - } - - /// - /// Mark the specified bean as already created (or about to be created). - /// - /// - /// This allows the bean factory to optimize its caching for repeated - /// creation of the specified bean. - /// - /// The name of the object. - protected void MarkObjectAsCreated(string objectName) - { - if (alreadyCreated.Contains(objectName)) - { - return; - } - - lock (mergedObjectDefinitions) - { - if (!alreadyCreated.Contains(objectName)) - { - // Let the bean definition get re-merged now that we're actually creating - // the object... just in case some of its metadata changed in the meantime. - ClearMergedObjectDefinition(objectName); - alreadyCreated.Add(objectName); - } - } - } - - /// - /// Perform appropriate cleanup of cached metadata after bean creation failed. - /// - /// The name of the object - protected void CleanupAfterObjectCreationFailure(string objectName) - { - lock (mergedObjectDefinitions) - { - alreadyCreated.Remove(objectName); - } - } - - /// - /// Predict the eventual object type (of the processed object instance) for the - /// specified object. - /// - /// - /// Does not need to handle FactoryObjects specifically, since it is only - /// supposed to operate on the raw object type. - /// This implementation is simplistic in that it is not able to - /// handle factory methods and InstantiationAwareBeanPostProcessors. - /// It only predicts the object type correctly for a standard object. - /// To be overridden in subclasses, applying more sophisticated type detection. - /// - /// Name of the object. - /// The merged object definition to determine the type for. May be null - /// The type of the object, or null if not predictable - protected virtual Type PredictObjectType(string objectName, RootObjectDefinition mod) - { - if (mod == null || StringUtils.HasText(mod.FactoryObjectName)) - { - return null; - } - return ResolveObjectType(mod, objectName); - } - - /// - /// Get the object for the given object instance, either the object - /// instance itself or its created object in case of an - /// . - /// - /// The object instance. - /// - /// The name that may include the factory dereference prefix (=the requested name). - /// - /// - /// The canonical object name - /// - /// the merged object definition - /// - /// The singleton instance of the object. - /// - protected internal virtual object GetObjectForInstance(object instance, string name, string canonicalName, RootObjectDefinition rod) - { - // don't let calling code try to dereference the - // object factory if the object isn't a factory - if (IsFactoryDereference(name) && !(ObjectUtils.IsAssignable(typeof(IFactoryObject), instance))) - { - throw new ObjectIsNotAFactoryException(canonicalName, instance); - } - - // now we have the object instance, which may be a normal object - // or an IFactoryObject. If it's an IFactoryObject and the caller wants - // a reference to the factory there's nothing more to do - - - // it's a normal object ? - if (!ObjectUtils.IsAssignable(typeof(IFactoryObject), instance)) - { - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug(string.Format("Calling code asked for normal instance for name '{0}'.", canonicalName)); - } - - return instance; - } - - // the user wants the factory itself ? - if (!ObjectUtils.IsAssignable(typeof(IFactoryObject), instance) || IsFactoryDereference(name)) - { - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug(string.Format("Calling code asked for IFactoryObject instance for name '{0}'.", - TransformedObjectName(name))); - } - - return instance; - } - - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug(string.Format("Object with name '{0}' is a factory object.", canonicalName)); - } - - object resultInstance = null; - - if (rod == null) - { - factoryObjectProductCache.TryGetValue(canonicalName, out resultInstance); - } - - if (resultInstance == null) - { - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug(string.Format("Dereferencing Object with name '{0}'", canonicalName)); - } - - // return object instance from factory... - IFactoryObject factory = (IFactoryObject)instance; - - if (rod == null && ContainsObjectDefinition(canonicalName)) - { - rod = GetMergedObjectDefinition(canonicalName, true); - } - - if (factory.IsSingleton && ContainsSingleton(canonicalName)) - { - lock (factoryObjectProductCache) - { - if (!factoryObjectProductCache.TryGetValue(canonicalName, out resultInstance)) - { - resultInstance = GetObjectFromFactoryObject(factory, canonicalName, rod); - if (resultInstance != null) - { - factoryObjectProductCache[canonicalName] = resultInstance; - } - } - } - } - else - { - resultInstance = GetObjectFromFactoryObject(factory, canonicalName, rod); - } - - if (resultInstance == null) - { - throw new FactoryObjectNotInitializedException(canonicalName, - "Factory object returned null object - " - + "possible cause: not fully initialized due to " - + "circular object reference."); - } - } - else - { - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug(string.Format("Returning factory product from cache for Object with name '{0}'", canonicalName)); - } - } - return resultInstance; - } - - /// - /// Obtain an object to expose from the given IFactoryObject. - /// - /// The IFactoryObject instance. - /// Name of the object. - /// The merged object definition. - /// The object obtained from the IFactoryObject - /// If IFactoryObject object creation failed. - private object GetObjectFromFactoryObject(IFactoryObject factory, string objectName, RootObjectDefinition rod) - { - object instance; - - try - { - instance = factory.GetObject(); - } - catch (FactoryObjectNotInitializedException ex) - { - throw new ObjectCurrentlyInCreationException( - rod.ResourceDescription, objectName, ex); - } - catch (Exception ex) - { - throw new ObjectCreationException(rod.ResourceDescription, objectName, - "FactoryObject threw exception on object creation.", ex); - } - - // Do not accept a null value for a FactoryBean that's not fully - // initialized yet: Many FactoryBeans just return null then. - if (instance == null && IsSingletonCurrentlyInCreation(objectName)) - { - throw new ObjectCurrentlyInCreationException(rod.ResourceDescription, objectName, - "FactoryObject which is currently in creation returned null from GetObject."); - } - - if (factory is IConfigurableFactoryObject) - { - IConfigurableFactoryObject configurableFactory = (IConfigurableFactoryObject)factory; - - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug(string.Format("Factory object with name '{0}' is configurable.", TransformedObjectName(objectName))); - } - - if (configurableFactory.ProductTemplate != null) - { - ApplyObjectPropertyValues(instance, objectName, configurableFactory.ProductTemplate); - } - } - - if (instance != null) - { - try - { - instance = PostProcessObjectFromFactoryObject(instance, objectName); - } - catch (Exception ex) - { - throw new ObjectCreationException(rod.ResourceDescription, objectName, - "Post-processing of the FactoryObject's object failed.", ex); - } - } - - return instance; - } - - /// - /// Post-process the given object that has been obtained from the FactoryObject. - /// The resulting object will be exposed for object references. - /// - /// The default implementation simply returns the given object - /// as-is. Subclasses may override this, for example, to apply - /// post-processors. - /// The instance obtained from the IFactoryObject. - /// Name of the object. - /// The object instance to expose - /// if any post-processing failed. - protected virtual object PostProcessObjectFromFactoryObject(object instance, string objectName) - { - return instance; - } - - /// - /// Convenience method to pull an - /// from this factory. - /// - /// - /// The name of the factory object to be retrieved. If this name is not a valid - /// name, it will be converted - /// into one. - /// - /// - /// The associated with the - /// supplied . - /// - protected IFactoryObject GetFactoryObject(string objectName) - { - if (!ObjectFactoryUtils.IsFactoryDereference(objectName)) - { - objectName = ObjectFactoryUtils.BuildFactoryObjectName(objectName); - } - return (IFactoryObject)GetObject(objectName); - } - - /// - /// Is the supplied a factory object dereference? - /// - protected bool IsFactoryDereference(string name) - { - return ObjectFactoryUtils.IsFactoryDereference(name); - } - - /// - /// Determines whether the type of the given object definition matches the - /// specified target type. - /// - /// Allows for lazy load of the actual object type, provided that the - /// type match can be determined otherwise. - /// The default implementation simply delegates to the standard - /// ResolveObjectType method. Subclasses may override this to use - /// a differnt strategy. - /// - /// Name of the object (for error handling purposes). - /// The merged object definition to determine the type for. - /// Type to match against (never null). - /// - /// true if object definition matches tye specified target type; otherwise, false. - /// - /// if we failed to load the type." - protected bool IsObjectTypeMatch(string objectName, RootObjectDefinition rod, Type targetType) - { - Type objectType = ResolveObjectType(rod, objectName); - return (objectType != null && targetType.IsAssignableFrom(objectType)); - } - - /// - /// Resolves the type of the object for the specified object definition resolving - /// an object type name to a Type (if necessary) and storing the resolved Type - /// in the object definition for further use. - /// - /// The merged object definition to dertermine the type for. - /// Name of the object (for error handling purposes). - /// - protected Type ResolveObjectType(RootObjectDefinition rod, string objectName) - { - try - { - if (rod.HasObjectType) - { - return rod.ObjectType; - } - return rod.ResolveObjectType(); - } - catch (TypeLoadException e) - { - throw new CannotLoadObjectTypeException(rod.ResourceDescription, objectName, rod.ObjectTypeName, e); - } - } - - /// - /// Is the object (definition) with the supplied an - /// ? - /// - /// The name of the object to be checked. - /// - /// the object (definition) with the supplied - /// an ? - /// - protected bool IsFactoryObject(string name) - { - string objectName = TransformedObjectName(name); - object objectInstance = GetSingleton(objectName); - - if (objectInstance != null) - { - return (objectInstance is IFactoryObject); - } - else - { - RootObjectDefinition definition = GetMergedObjectDefinition(objectName, false); - if (definition != null) - { - return (definition.HasObjectType && typeof(IFactoryObject).IsAssignableFrom(definition.ObjectType)); - } - else - { - if (parentObjectFactory != null) - { - return ((AbstractObjectFactory)parentObjectFactory).IsFactoryObject(name); - } - else - { - throw new NoSuchObjectDefinitionException(objectName, - "Cannot find definition for object [" + objectName - + "]"); - } - } - } - } - - /// - /// Remove the object identified by the supplied - /// from this factory's singleton cache. - /// - /// - /// The name of the object that is to be removed from the singleton - /// cache. - /// - /// - /// If the argument is or - /// consists wholly of whitespace characters. - /// - protected void RemoveSingleton(string name) - { - AssertUtils.ArgumentHasText(name, "name"); - lock (GetSingletonLockFor(name)) - { - singletonCache.Remove(name); - } - } - - /// - /// Return the names of objects in the singleton cache that match the given - /// object type (including subclasses). - /// - /// - /// The class or interface to match, or for all object names. - /// - /// - ///

- /// Will not consider s - /// as the type of their created objects is not known before instantiation. - ///

- ///

- /// Does not consider any hierarchy this factory may participate in. - ///

- ///
- /// - /// The names of objects in the singleton cache that match the given - /// object type (including subclasses), or an empty array if none. - /// - public virtual IList GetSingletonNames(Type type) - { - lock (singletonCache) - { - List matches = new List(); - foreach (string name in singletonCache.Keys) - { - object singletonObject = singletonCache[name]; - if (singletonObject != null && type.IsAssignableFrom(singletonObject.GetType()) - && !matches.Contains(name)) - { - matches.Add(name); - } - } - return matches; - } - } - - /// - /// Determines whether the object with the given name matches the specified type. - /// - /// More specifically, check whether a GetObject call for the given name - /// would return an object that is assignable to the specified target type. - /// Translates aliases back to the corresponding canonical instance name. - /// Will ask the parent factory if the instance cannot be found in this factory instance. - /// - /// The name of the object to query. - /// Type of the target to match against. - /// - /// true if the object type matches; otherwise, false - /// if it doesn't match or cannot be determined yet. - /// - /// Ff there is no object with the given name - /// - public bool IsTypeMatch(string name, Type targetType) - { - string objectName = TransformedObjectName(name); - Type typeToMatch = (targetType != null ? targetType : typeof(object)); - - //Check manually registered singletons. - object objectInstance = GetSingleton(objectName); - if (objectInstance != null) - { - if (objectInstance is IFactoryObject) - { - if (!IsFactoryDereference(name)) - { - Type type = GetTypeForFactoryObject((IFactoryObject)objectInstance); - return (type != null && typeToMatch.IsAssignableFrom(type)); - } - else - { - return typeToMatch.IsAssignableFrom(objectInstance.GetType()); - } - } - else - { - return !IsFactoryDereference(name) && typeToMatch.IsAssignableFrom(objectInstance.GetType()); - } - } - else - { - // No singleton instance found -> check object definition - IObjectFactory parentFactory = ParentObjectFactory; - if (parentFactory != null && !ContainsObjectDefinition(name)) - { - // No object definition found in this factory -> delegate to parent - return parentFactory.IsTypeMatch(OriginalObjectName(name), targetType); - } - - RootObjectDefinition mod = GetMergedObjectDefinition(objectName, false); - Type objectType = PredictObjectType(objectName, mod); - - if (objectType == null) - { - return false; - } - - // Check object class whether we're dealing with a FactoryObject - if (typeof(IFactoryObject).IsAssignableFrom(objectType)) - { - if (!IsFactoryDereference(name)) - { - // If it's a FactoryObject, we want to look at what it creates, not the factory class. - Type type = GetTypeForFactoryObject(objectName, mod); - return (type != null && typeToMatch.IsAssignableFrom(type)); - } - else - { - return typeToMatch.IsAssignableFrom(objectType); - } - } - else - { - return !IsFactoryDereference(name) && typeToMatch.IsAssignableFrom(objectType); - } - } - } - - /// - /// Determines whether the object with the given name matches the specified type. - /// - /// More specifically, check whether a GetObject call for the given name - /// would return an object that is assignable to the specified target type. - /// Translates aliases back to the corresponding canonical instance name. - /// Will ask the parent factory if the instance cannot be found in this factory instance. - /// - /// The name of the object to query. - /// Type of the target to match against. - /// - /// true if the object type matches; otherwise, false - /// if it doesn't match or cannot be determined yet. - /// - /// Ff there is no object with the given name - /// - public bool IsTypeMatch(string name) - { - return IsTypeMatch(name, typeof(T)); - } - - /// - /// Determines the of the object with the - /// supplied . - /// - /// - ///

- /// More specifically, checks the of object that - /// would return. - /// For an , returns the - /// of object that the - /// creates. - ///

- ///

- /// Please note that (prototype) objects created via a factory method or - /// objects are handled - /// slightly differently, in that we don't want to needlessly create - /// instances of such objects just to determine the - /// of object that they create. - ///

- ///
- /// The name of the object to query. - /// - /// The of the object or - /// if not determinable. - /// - public virtual Type GetType(string name) - { - string objectName = TransformedObjectName(name); - - // check manually registered singletons... - object objectInstance = GetSingleton(objectName); - - if (objectInstance != null) - { - IFactoryObject factoryObject = objectInstance as IFactoryObject; - if (factoryObject != null & !IsFactoryDereference(objectName)) - { - return GetTypeForFactoryObject(factoryObject); - } - else - { - return objectInstance.GetType(); - } - } - else - { - // No singleton instance found -> check object definition. - IObjectFactory parentFactory = ParentObjectFactory; - if (parentFactory != null && !ContainsObjectDefinition(objectName)) - { - // No object definition found in this factory -> delegate to parent. - return parentFactory.GetType(OriginalObjectName(name)); - } - - RootObjectDefinition mod = GetMergedObjectDefinition(objectName, false); - Type objectType = PredictObjectType(objectName, mod); - - if (objectType != null && typeof(IFactoryObject).IsAssignableFrom(objectType)) - { - if (!IsFactoryDereference(name)) - { - // If it's a FactoryObject, we want to look at what it creates, not the factory class. - return GetTypeForFactoryObject(objectName, mod); - } - else - { - return objectType; - } - } - else - { - return (!IsFactoryDereference(name) ? objectType : null); - } - } - } - - /// - /// Determines the of the object defined - /// by the supplied object . - /// - /// - ///

- /// This, the default, implementation returns - /// to indicate that the type cannot be determined. Subclasses are - /// encouraged to try to determine the actual return - /// here, matching their strategy of resolving - /// factory methods in the - /// Spring.Objects.Factory.Support.AbstractObjectFactory.CreateObject - /// implementation. - ///

- ///
- /// - /// The name associated with the supplied object . - /// - /// - /// The - /// that the is to be determined for. - /// - /// - /// The of the object defined by the supplied - /// object ; or if the - /// cannot be determined. - /// - protected virtual Type GetTypeForFactoryMethod(string objectName, RootObjectDefinition definition) + return objectName; + } + + /// + /// Determines whether the specified name is defined as an alias as opposed + /// to the name of an actual object definition. + /// + /// The object name to check. + /// + /// true if the specified name is alias; otherwise, false. + /// + protected bool IsAlias(string name) + { + return aliasMap.Contains(name); + } + + /// + /// Return a , + /// even by traversing parent if the parameter is a child definition. + /// + /// + /// The name of the object. + /// + /// + /// Are ancestors to be included in the merge? + /// + /// + ///

+ /// Will ask the parent object factory if not found in this instance. + ///

+ ///
+ /// + /// A merged + /// with overridden properties. + /// + public virtual RootObjectDefinition GetMergedObjectDefinition(string name, bool includingAncestors) + { + return GetMergedObjectDefinition(name, GetObjectDefinition(name, includingAncestors)); + } + + /// + /// Return a , + /// even by traversing parent if the parameter is a child definition. + /// + /// The name. + /// The od. + /// + /// A merged + /// with overridden properties. + /// + protected internal virtual RootObjectDefinition GetMergedObjectDefinition(string name, IObjectDefinition od) + { + return GetMergedLocalObjectDefinition(name) ?? GetMergedObjectDefinitionInternal(name, od); + } + + /// + /// Return a , + /// even by traversing parent if the parameter is a child definition. + /// + /// + /// A merged + /// with overridden properties. + /// + protected internal virtual RootObjectDefinition GetMergedObjectDefinitionInternal(string name, IObjectDefinition od) + { + if (od == null) { return null; } - /// - /// Returns the names of the objects in the singleton cache. - /// - /// - ///

- /// Does not consider any hierarchy this factory may participate in. - ///

- ///
- /// The names of the objects in the singleton cache. - public virtual IList GetSingletonNames() + // Check with full lock now in order to enforce the same merged instance. + RootObjectDefinition ValueFactory(string key) { - lock (singletonCache) + RootObjectDefinition mod; + if (od.ParentName == null) { - IEnumerable keys = singletonCache.Keys.Cast(); - return new List(keys); + mod = CreateRootObjectDefinition(od); + } + else + { + IObjectDefinition pod = null; + if (!key.Equals(od.ParentName)) + { + pod = GetMergedObjectDefinition(TransformedObjectName(od.ParentName), true); + } + else + { + if (ParentObjectFactory is AbstractObjectFactory factory) + { + pod = factory.GetMergedObjectDefinition(od.ParentName, true); + } + } + + if (pod == null) + { + throw new NoSuchObjectDefinitionException(od.ParentName, $"Parent name '{od.ParentName}' is equal to object name '{key}' - " + "cannot be resolved without an AbstractObjectFactory parent."); + } + + mod = CreateRootObjectDefinition(pod); + mod.OverrideFrom(od); + } + + return mod; + } + + // Only cache the merged bean definition if we're already about to create an + // instance of the object, or at least have already created an instance before. + if (CacheObjectMetadata && IsObjectEligibleForMetadataCaching(name)) + { + return mergedObjectDefinitions.GetOrAdd(name, ValueFactory); + } + + return ValueFactory(name); + } + + /// + /// Gets the merged local object definition. + /// + /// Name of the object. + /// + /// Merged RootBeanDefinition, traversing the parent bean definition + /// if the specified bean corresponds to a child bean definition. + /// + protected RootObjectDefinition GetMergedLocalObjectDefinition(string objectName) + { + mergedObjectDefinitions.TryGetValue(objectName, out var mbd); + return mbd; // ?? GetMergedObjectDefinition(objectName, GetObjectDefinition(objectName)); + } + + /// + /// Determines whether the metadata for the specified object name is eligible for caching. + /// + /// Name of the bean. + /// + /// true if [is object eligible for metadata caching] [the specified bean name]; otherwise, false. + /// + protected virtual bool IsObjectEligibleForMetadataCaching(string beanName) + { + return alreadyCreated.Contains(beanName); + } + + protected bool CacheObjectMetadata + { + get => cacheObjectMetadata; + set => cacheObjectMetadata = value; + } + + /// + /// Creates the root object definition. + /// + /// The template definition to base root definition on. + /// Root object definition. + protected virtual RootObjectDefinition CreateRootObjectDefinition(IObjectDefinition templateDefinition) + { + return new RootObjectDefinition(templateDefinition); + } + + /// + /// Register a new object definition with this registry. + /// + /// + /// The name of the object instance to register. + /// + /// + /// The definition of the object instance to register. + /// + /// + /// If the object definition is invalid. + /// + /// + public abstract void RegisterObjectDefinition(string name, IObjectDefinition objectDefinition); + + /// + /// Return the registered + /// for the + /// given object, allowing access to its property values and constructor + /// argument values. + /// + /// The name of the object. + /// + /// The registered + /// . + /// + /// + /// If there is no object with the given name. + /// + /// + /// In the case of errors. + /// + public abstract IObjectDefinition GetObjectDefinition(string name); + + /// + /// Return the registered + /// for the + /// given object, allowing access to its property values and constructor + /// argument values. + /// + /// The name of the object. + /// Whether to search parent object factories. + /// + /// The registered + /// . + /// + /// + /// If there is no object with the given name. + /// + /// + /// In the case of errors. + /// + public abstract IObjectDefinition GetObjectDefinition(string name, bool includeAncestors); + + /// + /// Gets the type for the given FactoryObject. + /// + /// The factory object instance to check. + /// the FactoryObject's object type + protected virtual Type GetTypeForFactoryObject(IFactoryObject factoryObject) + { + try + { + return factoryObject.ObjectType; + } + catch (Exception ex) + { + log.LogWarning(ex, "FactoryObject threw exception from ObjectType, despite the contract saying " + + "that it should return null if the type of its object cannot be determined yet"); + return null; + } + } + + /// + /// Gets the object type for the given FactoryObject definition, as far as possible. + /// Only called if there is no singleton instance registered for the target object already. + /// + /// + /// The default implementation creates the FactoryObject via GetObject + /// to call its ObjectType property. Subclasses are encouraged to optimize + /// this, typically by just instantiating the FactoryObject but not populating it yet, + /// trying whether its ObjectType property already returns a type. + /// If no type found, a full FactoryObject creation as performed by this implementation + /// should be used as fallback. + /// + /// Name of the object. + /// The merged object definition for the object. + /// The type for the object if determinable, or null otherwise + protected virtual Type GetTypeForFactoryObject(string objectName, RootObjectDefinition mod) + { + if (!mod.IsSingleton) + { + return null; + } + + try + { + IFactoryObject factoryObject = GetFactoryObject(objectName); + return GetTypeForFactoryObject(factoryObject); + } + catch (ObjectCreationException ex) + { + // Can only happen when getting a FactoryObject. + log.LogWarning(ex, "Ignoring object creation exception on FactoryObject type check"); + return null; + } + } + + /// + /// Mark the specified bean as already created (or about to be created). + /// + /// + /// This allows the bean factory to optimize its caching for repeated + /// creation of the specified bean. + /// + /// The name of the object. + protected void MarkObjectAsCreated(string objectName) + { + if (alreadyCreated.Contains(objectName)) + { + return; + } + + lock (mergedObjectDefinitions) + { + if (!alreadyCreated.Contains(objectName)) + { + // Let the bean definition get re-merged now that we're actually creating + // the object... just in case some of its metadata changed in the meantime. + ClearMergedObjectDefinition(objectName); + alreadyCreated.Add(objectName); + } + } + } + + /// + /// Perform appropriate cleanup of cached metadata after bean creation failed. + /// + /// The name of the object + protected void CleanupAfterObjectCreationFailure(string objectName) + { + lock (mergedObjectDefinitions) + { + alreadyCreated.Remove(objectName); + } + } + + /// + /// Predict the eventual object type (of the processed object instance) for the + /// specified object. + /// + /// + /// Does not need to handle FactoryObjects specifically, since it is only + /// supposed to operate on the raw object type. + /// This implementation is simplistic in that it is not able to + /// handle factory methods and InstantiationAwareBeanPostProcessors. + /// It only predicts the object type correctly for a standard object. + /// To be overridden in subclasses, applying more sophisticated type detection. + /// + /// Name of the object. + /// The merged object definition to determine the type for. May be null + /// The type of the object, or null if not predictable + protected virtual Type PredictObjectType(string objectName, RootObjectDefinition mod) + { + if (mod == null || StringUtils.HasText(mod.FactoryObjectName)) + { + return null; + } + + return ResolveObjectType(mod, objectName); + } + + /// + /// Get the object for the given object instance, either the object + /// instance itself or its created object in case of an + /// . + /// + /// The object instance. + /// + /// The name that may include the factory dereference prefix (=the requested name). + /// + /// + /// The canonical object name + /// + /// the merged object definition + /// + /// The singleton instance of the object. + /// + protected internal virtual object GetObjectForInstance(object instance, string name, string canonicalName, RootObjectDefinition rod) + { + // don't let calling code try to dereference the + // object factory if the object isn't a factory + if (IsFactoryDereference(name) && !(ObjectUtils.IsAssignable(typeof(IFactoryObject), instance))) + { + throw new ObjectIsNotAFactoryException(canonicalName, instance); + } + + // now we have the object instance, which may be a normal object + // or an IFactoryObject. If it's an IFactoryObject and the caller wants + // a reference to the factory there's nothing more to do + + // it's a normal object ? + if (!ObjectUtils.IsAssignable(typeof(IFactoryObject), instance)) + { + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug(string.Format("Calling code asked for normal instance for name '{0}'.", canonicalName)); + } + + return instance; + } + + // the user wants the factory itself ? + if (!ObjectUtils.IsAssignable(typeof(IFactoryObject), instance) || IsFactoryDereference(name)) + { + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug(string.Format("Calling code asked for IFactoryObject instance for name '{0}'.", + TransformedObjectName(name))); + } + + return instance; + } + + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug(string.Format("Object with name '{0}' is a factory object.", canonicalName)); + } + + object resultInstance = null; + + if (rod == null) + { + factoryObjectProductCache.TryGetValue(canonicalName, out resultInstance); + } + + if (resultInstance == null) + { + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug(string.Format("Dereferencing Object with name '{0}'", canonicalName)); + } + + // return object instance from factory... + IFactoryObject factory = (IFactoryObject) instance; + + if (rod == null && ContainsObjectDefinition(canonicalName)) + { + rod = GetMergedObjectDefinition(canonicalName, true); + } + + if (factory.IsSingleton && ContainsSingleton(canonicalName)) + { + lock (factoryObjectProductCache) + { + if (!factoryObjectProductCache.TryGetValue(canonicalName, out resultInstance)) + { + resultInstance = GetObjectFromFactoryObject(factory, canonicalName, rod); + if (resultInstance != null) + { + factoryObjectProductCache[canonicalName] = resultInstance; + } + } + } + } + else + { + resultInstance = GetObjectFromFactoryObject(factory, canonicalName, rod); + } + + if (resultInstance == null) + { + throw new FactoryObjectNotInitializedException(canonicalName, + "Factory object returned null object - " + + "possible cause: not fully initialized due to " + + "circular object reference."); + } + } + else + { + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug(string.Format("Returning factory product from cache for Object with name '{0}'", canonicalName)); } } - /// - /// Returns the number of objects in the singleton cache. - /// - /// - ///

- /// Does not consider any hierarchy this factory may participate in. - ///

- ///
- /// The number of objects in the singleton cache. - public virtual int GetSingletonCount() + return resultInstance; + } + + /// + /// Obtain an object to expose from the given IFactoryObject. + /// + /// The IFactoryObject instance. + /// Name of the object. + /// The merged object definition. + /// The object obtained from the IFactoryObject + /// If IFactoryObject object creation failed. + private object GetObjectFromFactoryObject(IFactoryObject factory, string objectName, RootObjectDefinition rod) + { + object instance; + + try { - lock (singletonCache) + instance = factory.GetObject(); + } + catch (FactoryObjectNotInitializedException ex) + { + throw new ObjectCurrentlyInCreationException( + rod.ResourceDescription, objectName, ex); + } + catch (Exception ex) + { + throw new ObjectCreationException(rod.ResourceDescription, objectName, + "FactoryObject threw exception on object creation.", ex); + } + + // Do not accept a null value for a FactoryBean that's not fully + // initialized yet: Many FactoryBeans just return null then. + if (instance == null && IsSingletonCurrentlyInCreation(objectName)) + { + throw new ObjectCurrentlyInCreationException(rod.ResourceDescription, objectName, + "FactoryObject which is currently in creation returned null from GetObject."); + } + + if (factory is IConfigurableFactoryObject) + { + IConfigurableFactoryObject configurableFactory = (IConfigurableFactoryObject) factory; + + if (log.IsEnabled(LogLevel.Debug)) { - return singletonCache.Count; + log.LogDebug(string.Format("Factory object with name '{0}' is configurable.", TransformedObjectName(objectName))); + } + + if (configurableFactory.ProductTemplate != null) + { + ApplyObjectPropertyValues(instance, objectName, configurableFactory.ProductTemplate); } } - /// - /// Destroys the named singleton object. - /// - /// - ///

- /// Delegates to - /// - /// if a corresponding singleton instance is found. - ///

- ///
- /// - /// The name of the singleton object that is to be destroyed. - /// - /// - protected virtual void DestroySingleton(string name) + if (instance != null) { - lock (singletonLocks) + try { - object tempObject = singletonCache[name]; - singletonCache.Remove(name); - registeredSingletons.Remove(name); - - object singletonInstance = tempObject; - if (singletonInstance != null) - { - DestroyObject(name, singletonInstance); - } + instance = PostProcessObjectFromFactoryObject(instance, objectName); + } + catch (Exception ex) + { + throw new ObjectCreationException(rod.ResourceDescription, objectName, + "Post-processing of the FactoryObject's object failed.", ex); } } - /// - /// Check the supplied merged object definition for any possible - /// validation errors. - /// - /// - /// The object definition to be checked for validation errors. - /// - /// - /// The name of the object associated with the supplied object definition. - /// - /// - /// The the object may match. Can be an interface or - /// superclass of the actual class. For example, if the value is the - /// class, this method will succeed whatever the - /// class of the returned instance. - /// - /// - /// The arguments to use if creating a prototype using explicit arguments to - /// a factory method. If there is no factory method and the - /// supplied array is not , then - /// match the argument values by type and call the object's constructor. - /// - /// - /// In the case of object validation errors. - /// - protected void CheckMergedObjectDefinition(RootObjectDefinition mergedObjectDefinition, string objectName, - Type requiredType, params object[] arguments) + return instance; + } + + /// + /// Post-process the given object that has been obtained from the FactoryObject. + /// The resulting object will be exposed for object references. + /// + /// The default implementation simply returns the given object + /// as-is. Subclasses may override this, for example, to apply + /// post-processors. + /// The instance obtained from the IFactoryObject. + /// Name of the object. + /// The object instance to expose + /// if any post-processing failed. + protected virtual object PostProcessObjectFromFactoryObject(object instance, string objectName) + { + return instance; + } + + /// + /// Convenience method to pull an + /// from this factory. + /// + /// + /// The name of the factory object to be retrieved. If this name is not a valid + /// name, it will be converted + /// into one. + /// + /// + /// The associated with the + /// supplied . + /// + protected IFactoryObject GetFactoryObject(string objectName) + { + if (!ObjectFactoryUtils.IsFactoryDereference(objectName)) { - // check if required type can match according to the object definition; - // this is only possible at this early stage for conventional objects! - if (mergedObjectDefinition.HasObjectType) - { - Type objectType = mergedObjectDefinition.ObjectType; - if (requiredType != null && StringUtils.IsNullOrEmpty(mergedObjectDefinition.FactoryMethodName) - && !typeof(IFactoryObject).IsAssignableFrom(objectType) - && !requiredType.IsAssignableFrom(objectType)) - { - throw new ObjectNotOfRequiredTypeException(objectName, requiredType, objectType); - } - } - - // check validity of the usage of the args parameter; this can - // only be used for prototypes constructed via a factory method... - if (arguments != null) - { - if (mergedObjectDefinition.IsSingleton) - { - throw new ObjectDefinitionStoreException("Cannot specify arguments in the GetObject () method when " - + "referring to a singleton object definition."); - } - - if (mergedObjectDefinition.HasObjectType - && typeof(IFactoryObject).IsAssignableFrom(mergedObjectDefinition.ObjectType)) - { - throw new ObjectDefinitionStoreException("Cannot specify arguments in the GetObject () method when " - + "referring to a factory object definition."); - } - - //MLP lets skip this check for now. - /* - else if (StringUtils.IsNullOrEmpty(mergedObjectDefinition.FactoryMethodName)) - { - throw new ObjectDefinitionStoreException( - "Can only specify arguments in the GetObject () method in " + - "conjunction with a factory method."); - } - */ - } + objectName = ObjectFactoryUtils.BuildFactoryObjectName(objectName); } - /// - /// Remove the merged bean definition for the specified bean, - /// recreating it on next access. - /// - /// The bean name to clear the merged definition for - protected void ClearMergedObjectDefinition(string objectName) - { - mergedObjectDefinitions.TryRemove(objectName, out _); - } + return (IFactoryObject) GetObject(objectName); + } - /// - /// Clear the merged object definition cache, removing entries for objects - /// which are not considered eligible for full metadata caching yet. - /// - /// - /// Typically triggered after changes to the original object definitions, - /// e.g. after applying a . Note that metadata - /// for objects which have already been created at this point will be kept around. - /// - public virtual void ClearMetadataCache() + /// + /// Is the supplied a factory object dereference? + /// + protected bool IsFactoryDereference(string name) + { + return ObjectFactoryUtils.IsFactoryDereference(name); + } + + /// + /// Determines whether the type of the given object definition matches the + /// specified target type. + /// + /// Allows for lazy load of the actual object type, provided that the + /// type match can be determined otherwise. + /// The default implementation simply delegates to the standard + /// ResolveObjectType method. Subclasses may override this to use + /// a differnt strategy. + /// + /// Name of the object (for error handling purposes). + /// The merged object definition to determine the type for. + /// Type to match against (never null). + /// + /// true if object definition matches tye specified target type; otherwise, false. + /// + /// if we failed to load the type." + protected bool IsObjectTypeMatch(string objectName, RootObjectDefinition rod, Type targetType) + { + Type objectType = ResolveObjectType(rod, objectName); + return (objectType != null && targetType.IsAssignableFrom(objectType)); + } + + /// + /// Resolves the type of the object for the specified object definition resolving + /// an object type name to a Type (if necessary) and storing the resolved Type + /// in the object definition for further use. + /// + /// The merged object definition to dertermine the type for. + /// Name of the object (for error handling purposes). + /// + protected Type ResolveObjectType(RootObjectDefinition rod, string objectName) + { + try { - var keys = new List(mergedObjectDefinitions.Keys); - foreach (var key in keys) + if (rod.HasObjectType) { - if (!IsObjectEligibleForMetadataCaching(key)) + return rod.ObjectType; + } + + return rod.ResolveObjectType(); + } + catch (TypeLoadException e) + { + throw new CannotLoadObjectTypeException(rod.ResourceDescription, objectName, rod.ObjectTypeName, e); + } + } + + /// + /// Is the object (definition) with the supplied an + /// ? + /// + /// The name of the object to be checked. + /// + /// the object (definition) with the supplied + /// an ? + /// + protected bool IsFactoryObject(string name) + { + string objectName = TransformedObjectName(name); + object objectInstance = GetSingleton(objectName); + + if (objectInstance != null) + { + return (objectInstance is IFactoryObject); + } + else + { + RootObjectDefinition definition = GetMergedObjectDefinition(objectName, false); + if (definition != null) + { + return (definition.HasObjectType && typeof(IFactoryObject).IsAssignableFrom(definition.ObjectType)); + } + else + { + if (parentObjectFactory != null) { - mergedObjectDefinitions.TryRemove(key, out _); + return ((AbstractObjectFactory) parentObjectFactory).IsFactoryObject(name); + } + else + { + throw new NoSuchObjectDefinitionException(objectName, + "Cannot find definition for object [" + objectName + + "]"); } } } + } - /// - /// Gets the temporary object that is placed - /// into the singleton cache during object resolution. - /// - protected object TemporarySingletonPlaceHolder => CurrentlyInCreation; - - /// - /// Parent object factory, for object inheritance support - /// - private IObjectFactory parentObjectFactory; - - /// - /// Dependency types to ignore on dependency check and autowire, as Set of - /// Type objects: for example, string. Default is none. - /// - private HybridSet ignoreDependencyTypes = new HybridSet(); - - /// - /// ObjectPostProcessors to apply in CreateObject - /// - internal List objectPostProcessors = new List(); - - /// - /// String Resolver applied to Autowired value injections - /// - private SortedSet embeddedValueResolvers = new SortedSet(ObjectOrderComparator.ObjectOrderComparatorInstance); - - /// - /// Indicates whether any IInstantiationAwareBeanPostProcessors have been registered - /// - private bool hasInstantiationAwareObjectPostProcessors; - - /// - /// Indicates whether any IDestructionAwareBeanPostProcessors have been registered - /// - private bool hasDestructionAwareObjectPostProcessors; - - private bool caseSensitive; - private OrderedDictionary aliasMap; - private OrderedDictionary singletonCache; - private ConcurrentDictionary> singletonLocks; - - /// - /// Set of registered singletons, containing the instance names in registration order - /// - private HashSet registeredSingletons = new HashSet(); - - private readonly IDictionary singletonsInCreation; - - private readonly LogicalThreadContextSetVariable prototypesInCreation; - - /// - /// Set that holds all inner objects created by this factory that implement the IDisposable - /// interface, to be destroyed on call to Dispose. - /// - private SynchronizedSet disposableInnerObjects = new SynchronizedSet(new HybridSet()); - - /// - /// Set that holds all inner objects created by this factory that implement the IDisposable - /// interface, to be destroyed on call to Dispose. - /// - protected internal ISet DisposableInnerObjects => disposableInnerObjects; - - /// - /// The parent object factory, or if there is none. - /// - /// - /// The parent object factory, or if there is none. - /// - public IObjectFactory ParentObjectFactory + /// + /// Remove the object identified by the supplied + /// from this factory's singleton cache. + /// + /// + /// The name of the object that is to be removed from the singleton + /// cache. + /// + /// + /// If the argument is or + /// consists wholly of whitespace characters. + /// + protected void RemoveSingleton(string name) + { + AssertUtils.ArgumentHasText(name, "name"); + lock (GetSingletonLockFor(name)) { - get => parentObjectFactory; - set => parentObjectFactory = value; + singletonCache.Remove(name); } + } - /// - /// Determines whether the local object factory contains a instance of the given name, - /// ignoring object defined in ancestor contexts. - /// This is an alternative to ContainsObject, ignoring an object - /// of the given name from an ancestor object factory. - /// - /// The name of the object to query. - /// - /// true if objects with the specified name is defined in the local factory; otherwise, false. - /// - public bool ContainsLocalObject(string name) + /// + /// Return the names of objects in the singleton cache that match the given + /// object type (including subclasses). + /// + /// + /// The class or interface to match, or for all object names. + /// + /// + ///

+ /// Will not consider s + /// as the type of their created objects is not known before instantiation. + ///

+ ///

+ /// Does not consider any hierarchy this factory may participate in. + ///

+ ///
+ /// + /// The names of objects in the singleton cache that match the given + /// object type (including subclasses), or an empty array if none. + /// + public virtual IList GetSingletonNames(Type type) + { + lock (singletonCache) { - string objectName = TransformedObjectName(name); - return ((ContainsSingleton(objectName) || ContainsObjectDefinition(objectName)) && - (!ObjectFactoryUtils.IsFactoryDereference(name) || IsFactoryObject(objectName))); - } - - /// - /// Is this object a singleton? - /// - /// - public bool IsSingleton(string name) - { - string objectName = TransformedObjectName(name); - object objectInstance = GetSingleton(objectName); - if (objectInstance != null) + List matches = new List(); + foreach (string name in singletonCache.Keys) { - IFactoryObject factoryObject = objectInstance as IFactoryObject; - if (factoryObject != null) + object singletonObject = singletonCache[name]; + if (singletonObject != null && type.IsAssignableFrom(singletonObject.GetType()) + && !matches.Contains(name)) { - return IsFactoryDereference(name) || factoryObject.IsSingleton; + matches.Add(name); + } + } + + return matches; + } + } + + /// + /// Determines whether the object with the given name matches the specified type. + /// + /// More specifically, check whether a GetObject call for the given name + /// would return an object that is assignable to the specified target type. + /// Translates aliases back to the corresponding canonical instance name. + /// Will ask the parent factory if the instance cannot be found in this factory instance. + /// + /// The name of the object to query. + /// Type of the target to match against. + /// + /// true if the object type matches; otherwise, false + /// if it doesn't match or cannot be determined yet. + /// + /// Ff there is no object with the given name + /// + public bool IsTypeMatch(string name, Type targetType) + { + string objectName = TransformedObjectName(name); + Type typeToMatch = (targetType != null ? targetType : typeof(object)); + + //Check manually registered singletons. + object objectInstance = GetSingleton(objectName); + if (objectInstance != null) + { + if (objectInstance is IFactoryObject) + { + if (!IsFactoryDereference(name)) + { + Type type = GetTypeForFactoryObject((IFactoryObject) objectInstance); + return (type != null && typeToMatch.IsAssignableFrom(type)); + } + else + { + return typeToMatch.IsAssignableFrom(objectInstance.GetType()); + } + } + else + { + return !IsFactoryDereference(name) && typeToMatch.IsAssignableFrom(objectInstance.GetType()); + } + } + else + { + // No singleton instance found -> check object definition + IObjectFactory parentFactory = ParentObjectFactory; + if (parentFactory != null && !ContainsObjectDefinition(name)) + { + // No object definition found in this factory -> delegate to parent + return parentFactory.IsTypeMatch(OriginalObjectName(name), targetType); + } + + RootObjectDefinition mod = GetMergedObjectDefinition(objectName, false); + Type objectType = PredictObjectType(objectName, mod); + + if (objectType == null) + { + return false; + } + + // Check object class whether we're dealing with a FactoryObject + if (typeof(IFactoryObject).IsAssignableFrom(objectType)) + { + if (!IsFactoryDereference(name)) + { + // If it's a FactoryObject, we want to look at what it creates, not the factory class. + Type type = GetTypeForFactoryObject(objectName, mod); + return (type != null && typeToMatch.IsAssignableFrom(type)); + } + else + { + return typeToMatch.IsAssignableFrom(objectType); + } + } + else + { + return !IsFactoryDereference(name) && typeToMatch.IsAssignableFrom(objectType); + } + } + } + + /// + /// Determines whether the object with the given name matches the specified type. + /// + /// More specifically, check whether a GetObject call for the given name + /// would return an object that is assignable to the specified target type. + /// Translates aliases back to the corresponding canonical instance name. + /// Will ask the parent factory if the instance cannot be found in this factory instance. + /// + /// The name of the object to query. + /// Type of the target to match against. + /// + /// true if the object type matches; otherwise, false + /// if it doesn't match or cannot be determined yet. + /// + /// Ff there is no object with the given name + /// + public bool IsTypeMatch(string name) + { + return IsTypeMatch(name, typeof(T)); + } + + /// + /// Determines the of the object with the + /// supplied . + /// + /// + ///

+ /// More specifically, checks the of object that + /// would return. + /// For an , returns the + /// of object that the + /// creates. + ///

+ ///

+ /// Please note that (prototype) objects created via a factory method or + /// objects are handled + /// slightly differently, in that we don't want to needlessly create + /// instances of such objects just to determine the + /// of object that they create. + ///

+ ///
+ /// The name of the object to query. + /// + /// The of the object or + /// if not determinable. + /// + public virtual Type GetType(string name) + { + string objectName = TransformedObjectName(name); + + // check manually registered singletons... + object objectInstance = GetSingleton(objectName); + + if (objectInstance != null) + { + IFactoryObject factoryObject = objectInstance as IFactoryObject; + if (factoryObject != null & !IsFactoryDereference(objectName)) + { + return GetTypeForFactoryObject(factoryObject); + } + else + { + return objectInstance.GetType(); + } + } + else + { + // No singleton instance found -> check object definition. + IObjectFactory parentFactory = ParentObjectFactory; + if (parentFactory != null && !ContainsObjectDefinition(objectName)) + { + // No object definition found in this factory -> delegate to parent. + return parentFactory.GetType(OriginalObjectName(name)); + } + + RootObjectDefinition mod = GetMergedObjectDefinition(objectName, false); + Type objectType = PredictObjectType(objectName, mod); + + if (objectType != null && typeof(IFactoryObject).IsAssignableFrom(objectType)) + { + if (!IsFactoryDereference(name)) + { + // If it's a FactoryObject, we want to look at what it creates, not the factory class. + return GetTypeForFactoryObject(objectName, mod); + } + else + { + return objectType; + } + } + else + { + return (!IsFactoryDereference(name) ? objectType : null); + } + } + } + + /// + /// Determines the of the object defined + /// by the supplied object . + /// + /// + ///

+ /// This, the default, implementation returns + /// to indicate that the type cannot be determined. Subclasses are + /// encouraged to try to determine the actual return + /// here, matching their strategy of resolving + /// factory methods in the + /// Spring.Objects.Factory.Support.AbstractObjectFactory.CreateObject + /// implementation. + ///

+ ///
+ /// + /// The name associated with the supplied object . + /// + /// + /// The + /// that the is to be determined for. + /// + /// + /// The of the object defined by the supplied + /// object ; or if the + /// cannot be determined. + /// + protected virtual Type GetTypeForFactoryMethod(string objectName, RootObjectDefinition definition) + { + return null; + } + + /// + /// Returns the names of the objects in the singleton cache. + /// + /// + ///

+ /// Does not consider any hierarchy this factory may participate in. + ///

+ ///
+ /// The names of the objects in the singleton cache. + public virtual IList GetSingletonNames() + { + lock (singletonCache) + { + IEnumerable keys = singletonCache.Keys.Cast(); + return new List(keys); + } + } + + /// + /// Returns the number of objects in the singleton cache. + /// + /// + ///

+ /// Does not consider any hierarchy this factory may participate in. + ///

+ ///
+ /// The number of objects in the singleton cache. + public virtual int GetSingletonCount() + { + lock (singletonCache) + { + return singletonCache.Count; + } + } + + /// + /// Destroys the named singleton object. + /// + /// + ///

+ /// Delegates to + /// + /// if a corresponding singleton instance is found. + ///

+ ///
+ /// + /// The name of the singleton object that is to be destroyed. + /// + /// + protected virtual void DestroySingleton(string name) + { + lock (singletonLocks) + { + object tempObject = singletonCache[name]; + singletonCache.Remove(name); + registeredSingletons.Remove(name); + + object singletonInstance = tempObject; + if (singletonInstance != null) + { + DestroyObject(name, singletonInstance); + } + } + } + + /// + /// Check the supplied merged object definition for any possible + /// validation errors. + /// + /// + /// The object definition to be checked for validation errors. + /// + /// + /// The name of the object associated with the supplied object definition. + /// + /// + /// The the object may match. Can be an interface or + /// superclass of the actual class. For example, if the value is the + /// class, this method will succeed whatever the + /// class of the returned instance. + /// + /// + /// The arguments to use if creating a prototype using explicit arguments to + /// a factory method. If there is no factory method and the + /// supplied array is not , then + /// match the argument values by type and call the object's constructor. + /// + /// + /// In the case of object validation errors. + /// + protected void CheckMergedObjectDefinition(RootObjectDefinition mergedObjectDefinition, string objectName, + Type requiredType, params object[] arguments) + { + // check if required type can match according to the object definition; + // this is only possible at this early stage for conventional objects! + if (mergedObjectDefinition.HasObjectType) + { + Type objectType = mergedObjectDefinition.ObjectType; + if (requiredType != null && StringUtils.IsNullOrEmpty(mergedObjectDefinition.FactoryMethodName) + && !typeof(IFactoryObject).IsAssignableFrom(objectType) + && !requiredType.IsAssignableFrom(objectType)) + { + throw new ObjectNotOfRequiredTypeException(objectName, requiredType, objectType); + } + } + + // check validity of the usage of the args parameter; this can + // only be used for prototypes constructed via a factory method... + if (arguments != null) + { + if (mergedObjectDefinition.IsSingleton) + { + throw new ObjectDefinitionStoreException("Cannot specify arguments in the GetObject () method when " + + "referring to a singleton object definition."); + } + + if (mergedObjectDefinition.HasObjectType + && typeof(IFactoryObject).IsAssignableFrom(mergedObjectDefinition.ObjectType)) + { + throw new ObjectDefinitionStoreException("Cannot specify arguments in the GetObject () method when " + + "referring to a factory object definition."); + } + + //MLP lets skip this check for now. + /* + else if (StringUtils.IsNullOrEmpty(mergedObjectDefinition.FactoryMethodName)) + { + throw new ObjectDefinitionStoreException( + "Can only specify arguments in the GetObject () method in " + + "conjunction with a factory method."); + } + */ + } + } + + /// + /// Remove the merged bean definition for the specified bean, + /// recreating it on next access. + /// + /// The bean name to clear the merged definition for + protected void ClearMergedObjectDefinition(string objectName) + { + mergedObjectDefinitions.TryRemove(objectName, out _); + } + + /// + /// Clear the merged object definition cache, removing entries for objects + /// which are not considered eligible for full metadata caching yet. + /// + /// + /// Typically triggered after changes to the original object definitions, + /// e.g. after applying a . Note that metadata + /// for objects which have already been created at this point will be kept around. + /// + public virtual void ClearMetadataCache() + { + var keys = new List(mergedObjectDefinitions.Keys); + foreach (var key in keys) + { + if (!IsObjectEligibleForMetadataCaching(key)) + { + mergedObjectDefinitions.TryRemove(key, out _); + } + } + } + + /// + /// Gets the temporary object that is placed + /// into the singleton cache during object resolution. + /// + protected object TemporarySingletonPlaceHolder => CurrentlyInCreation; + + /// + /// Parent object factory, for object inheritance support + /// + private IObjectFactory parentObjectFactory; + + /// + /// Dependency types to ignore on dependency check and autowire, as Set of + /// Type objects: for example, string. Default is none. + /// + private HybridSet ignoreDependencyTypes = new HybridSet(); + + /// + /// ObjectPostProcessors to apply in CreateObject + /// + internal List objectPostProcessors = new List(); + + /// + /// String Resolver applied to Autowired value injections + /// + private SortedSet embeddedValueResolvers = new SortedSet(ObjectOrderComparator.ObjectOrderComparatorInstance); + + /// + /// Indicates whether any IInstantiationAwareBeanPostProcessors have been registered + /// + private bool hasInstantiationAwareObjectPostProcessors; + + /// + /// Indicates whether any IDestructionAwareBeanPostProcessors have been registered + /// + private bool hasDestructionAwareObjectPostProcessors; + + private bool caseSensitive; + private OrderedDictionary aliasMap; + private OrderedDictionary singletonCache; + private ConcurrentDictionary> singletonLocks; + + /// + /// Set of registered singletons, containing the instance names in registration order + /// + private HashSet registeredSingletons = new HashSet(); + + private readonly IDictionary singletonsInCreation; + + private readonly LogicalThreadContextSetVariable prototypesInCreation; + + /// + /// Set that holds all inner objects created by this factory that implement the IDisposable + /// interface, to be destroyed on call to Dispose. + /// + private SynchronizedSet disposableInnerObjects = new SynchronizedSet(new HybridSet()); + + /// + /// Set that holds all inner objects created by this factory that implement the IDisposable + /// interface, to be destroyed on call to Dispose. + /// + protected internal ISet DisposableInnerObjects => disposableInnerObjects; + + /// + /// The parent object factory, or if there is none. + /// + /// + /// The parent object factory, or if there is none. + /// + public IObjectFactory ParentObjectFactory + { + get => parentObjectFactory; + set => parentObjectFactory = value; + } + + /// + /// Determines whether the local object factory contains a instance of the given name, + /// ignoring object defined in ancestor contexts. + /// This is an alternative to ContainsObject, ignoring an object + /// of the given name from an ancestor object factory. + /// + /// The name of the object to query. + /// + /// true if objects with the specified name is defined in the local factory; otherwise, false. + /// + public bool ContainsLocalObject(string name) + { + string objectName = TransformedObjectName(name); + return ((ContainsSingleton(objectName) || ContainsObjectDefinition(objectName)) && + (!ObjectFactoryUtils.IsFactoryDereference(name) || IsFactoryObject(objectName))); + } + + /// + /// Is this object a singleton? + /// + /// + public bool IsSingleton(string name) + { + string objectName = TransformedObjectName(name); + object objectInstance = GetSingleton(objectName); + if (objectInstance != null) + { + IFactoryObject factoryObject = objectInstance as IFactoryObject; + if (factoryObject != null) + { + return IsFactoryDereference(name) || factoryObject.IsSingleton; + } + else + { + return !IsFactoryDereference(name); + } + } + else + { + // No singleton instance found -> check object definition + IObjectFactory pof = ParentObjectFactory; + if (pof != null && !ContainsObjectDefinition(objectName)) + { + // No object definition found in this factory -> delegate to parent + return pof.IsSingleton(OriginalObjectName(name)); + } + + RootObjectDefinition od = GetMergedObjectDefinition(objectName, false); + if (od == null) + { + throw new NoSuchObjectDefinitionException(objectName); + } + + // In case of IFactoryObject, return singleton status of created object if not a dereference + if (od.IsSingleton) + { + if (IsObjectTypeMatch(objectName, od, typeof(IFactoryObject))) + { + if (IsFactoryDereference(name)) + { + return true; + } + + IFactoryObject factoryObject = + (IFactoryObject) GetObject(ObjectFactoryUtils.BuildFactoryObjectName(objectName)); + return factoryObject.IsSingleton; } else { @@ -1708,510 +1746,500 @@ namespace Spring.Objects.Factory.Support } else { - // No singleton instance found -> check object definition - IObjectFactory pof = ParentObjectFactory; - if (pof != null && !ContainsObjectDefinition(objectName)) - { - // No object definition found in this factory -> delegate to parent - return pof.IsSingleton(OriginalObjectName(name)); - } - RootObjectDefinition od = GetMergedObjectDefinition(objectName, false); - if (od == null) - { - throw new NoSuchObjectDefinitionException(objectName); - } - // In case of IFactoryObject, return singleton status of created object if not a dereference - if (od.IsSingleton) - { - if (IsObjectTypeMatch(objectName, od, typeof(IFactoryObject))) - { - if (IsFactoryDereference(name)) - { - return true; - } - IFactoryObject factoryObject = - (IFactoryObject)GetObject(ObjectFactoryUtils.BuildFactoryObjectName(objectName)); - return factoryObject.IsSingleton; - } - else - { - return !IsFactoryDereference(name); - } - } - else - { - return false; - } + return false; } } + } - /// - /// Determines whether the specified object name is prototype. That is, will GetObject - /// always return independent instances? - /// - /// The name of the object to query - /// - /// true if the specified object name will always deliver independent instances; otherwise, false. - /// - /// This method returning false does not clearly indicate a singleton object. - /// It indicated non-independent instances, which may correspond to a scoped object as - /// well. use the IsSingleton property to explicitly check for a shared - /// singleton instance. - /// Translates aliases back to the corresponding canonical object name. Will ask the - /// parent factory if the object can not be found in this factory instance. - /// - /// - /// if there is no object with the given name. - public bool IsPrototype(string name) + /// + /// Determines whether the specified object name is prototype. That is, will GetObject + /// always return independent instances? + /// + /// The name of the object to query + /// + /// true if the specified object name will always deliver independent instances; otherwise, false. + /// + /// This method returning false does not clearly indicate a singleton object. + /// It indicated non-independent instances, which may correspond to a scoped object as + /// well. use the IsSingleton property to explicitly check for a shared + /// singleton instance. + /// Translates aliases back to the corresponding canonical object name. Will ask the + /// parent factory if the object can not be found in this factory instance. + /// + /// + /// if there is no object with the given name. + public bool IsPrototype(string name) + { + string objectName = TransformedObjectName(name); + IObjectFactory parentFactory = ParentObjectFactory; + if (parentFactory != null && !ContainsObjectDefinition(objectName)) { - string objectName = TransformedObjectName(name); - IObjectFactory parentFactory = ParentObjectFactory; - if (parentFactory != null && !ContainsObjectDefinition(objectName)) - { - // No object definition found in this factory -> delegate to parent - return parentFactory.IsPrototype(OriginalObjectName(name)); - } + // No object definition found in this factory -> delegate to parent + return parentFactory.IsPrototype(OriginalObjectName(name)); + } - RootObjectDefinition od = GetMergedObjectDefinition(objectName, false); + RootObjectDefinition od = GetMergedObjectDefinition(objectName, false); - // In case of FactoryObject, return singleton status of created object if not a dereference - if (od.IsPrototype) + // In case of FactoryObject, return singleton status of created object if not a dereference + if (od.IsPrototype) + { + return (!IsFactoryDereference(name) || IsObjectTypeMatch(objectName, od, typeof(IFactoryObject))); + } + else + { + // not a prototype, however factory object may still produce a prototype object + if (IsFactoryDereference(name) && IsObjectTypeMatch(objectName, od, typeof(IFactoryObject))) { - return (!IsFactoryDereference(name) || IsObjectTypeMatch(objectName, od, typeof(IFactoryObject))); + IFactoryObject factoryObject = GetFactoryObject(objectName); + return (!factoryObject.IsSingleton); } else { - // not a prototype, however factory object may still produce a prototype object - if (IsFactoryDereference(name) && IsObjectTypeMatch(objectName, od, typeof(IFactoryObject))) - { - IFactoryObject factoryObject = GetFactoryObject(objectName); - return (!factoryObject.IsSingleton); - } - else - { - return false; - } + return false; } } + } - /// - /// Does this object factory or one of its parent factories contain an object with the given name? - /// - /// - /// This method scans the object factory hierarchy starting with the current factory instance upwards. - /// Use if you want to explicitely check just this object factory instance. - /// - /// . - public bool ContainsObject(string name) + /// + /// Does this object factory or one of its parent factories contain an object with the given name? + /// + /// + /// This method scans the object factory hierarchy starting with the current factory instance upwards. + /// Use if you want to explicitely check just this object factory instance. + /// + /// . + public bool ContainsObject(string name) + { + string objectName = TransformedObjectName(name); + + if (ContainsSingleton(objectName) || ContainsObjectDefinition(objectName)) { - string objectName = TransformedObjectName(name); + return (!ObjectFactoryUtils.IsFactoryDereference(name) || IsFactoryObject(name)); + } - if (ContainsSingleton(objectName) || ContainsObjectDefinition(objectName)) + IObjectFactory parent = ParentObjectFactory; + return (parent != null) && parent.ContainsObject(OriginalObjectName(name)); + } + + /// + /// Return the aliases for the given object name, if defined. + /// + /// . + public IReadOnlyList GetAliases(string name) + { + return DoGetAliases(name); + } + + internal List DoGetAliases(string name) + { + string objectName = TransformedObjectName(name); + // check if object actually exists in this object factory... + bool isInSingletonCache = ContainsSingleton(objectName); + if (isInSingletonCache || ContainsObjectDefinition(objectName)) + { + // if found, gather aliases... + var matches = new List(); + foreach (DictionaryEntry aliasEntry in aliasMap) { - return (!ObjectFactoryUtils.IsFactoryDereference(name) || IsFactoryObject(name)); + if (0 == string.Compare((string) aliasEntry.Value, objectName, !IsCaseSensitive)) + { + matches.Add((string) aliasEntry.Key); + } } - IObjectFactory parent = ParentObjectFactory; - return (parent != null) && parent.ContainsObject(OriginalObjectName(name)); + return matches; } - /// - /// Return the aliases for the given object name, if defined. - /// - /// . - public IReadOnlyList GetAliases(string name) + // not found, so check parent... + if (ParentObjectFactory != null) { - return DoGetAliases(name); + return new List(ParentObjectFactory.GetAliases(objectName)); } - internal List DoGetAliases(string name) + throw new NoSuchObjectDefinitionException(objectName, ToString()); + } + + /// + /// Return an instance (possibly shared or independent) of the given object name. + /// + /// . + public object this[string name] => GetObject(name); + + /// + /// Return an unconfigured(!) instance (possibly shared or independent) of the given object name. + /// + /// + /// + /// This method will only instantiate the requested object. It does NOT inject any dependencies! + /// + public object CreateObject(string name, Type requiredType, object[] arguments) + { + return GetObjectInternal(name, requiredType, arguments, true); + } + + /// + /// Return an unconfigured(!) instance (possibly shared or independent) of the given object name. + /// + /// The name of the object to return. + /// + /// The the object may match. Can be an interface or + /// superclass of the actual class. For example, if the value is the + /// class, this method will succeed whatever the + /// class of the returned instance. + /// + /// + /// The arguments to use if creating a prototype using explicit arguments to + /// a factory method. If there is no factory method and the + /// supplied array is not , then + /// match the argument values by type and call the object's constructor. + /// + /// The unconfigured(!) instance of the object. + /// + /// If there's no such object definition. + /// + /// + /// If the object could not be created. + /// + /// + /// If the object is not of the required type. + /// + /// + /// If the supplied is . + /// + /// + /// + /// This method will only instantiate the requested object. It does NOT inject any dependencies! + /// + public T CreateObject(string name, object[] arguments) + { + return (T) CreateObject(name, typeof(T), arguments); + } + + /// + /// Return an instance (possibly shared or independent) of the given object name. + /// + /// . + public object GetObject(string name) + { + return GetObjectInternal(name, null, null, false); + } + + /// + /// Return an instance (possibly shared or independent) of the given object name. + /// + /// + /// + /// This method allows an object factory to be used as a replacement for the + /// Singleton or Prototype design pattern. + /// + /// + /// Note that callers should retain references to returned objects. There is no + /// guarantee that this method will be implemented to be efficient. For example, + /// it may be synchronized, or may need to run an RDBMS query. + /// + /// + /// Will ask the parent factory if the object cannot be found in this factory + /// instance. + /// + /// + /// The type of the object to return. + /// The instance of the object. + /// + /// If there's no such object definition. + /// + /// + /// If there is more than a single object of the requested type defined in the factory. + /// + /// + /// If the object could not be created. + /// + public abstract T GetObject(); + + /// + /// Return an instance (possibly shared or independent) of the given object name. + /// + /// + /// + /// This method allows an object factory to be used as a replacement for the + /// Singleton or Prototype design pattern. + /// + /// + /// Note that callers should retain references to returned objects. There is no + /// guarantee that this method will be implemented to be efficient. For example, + /// it may be synchronized, or may need to run an RDBMS query. + /// + /// + /// Will ask the parent factory if the object cannot be found in this factory + /// instance. + /// + /// + /// The type of the object to return. + /// The name of the object to return. + /// The instance of the object. + /// + /// If there's no such object definition. + /// + /// + /// If the object is not of the required type. + /// + /// + /// If the object could not be created. + /// + public T GetObject(string name) + { + return (T) GetObject(name); + } + + /// + /// Return an instance (possibly shared or independent) of the given object name. + /// + /// + public object GetObject(string name, Type requiredType) + { + return GetObjectInternal(name, requiredType, null, false); + } + + /// + /// Return an instance (possibly shared or independent) of the given object name. + /// + /// + ///

+ /// This method allows an object factory to be used as a replacement for the + /// Singleton or Prototype design pattern. + ///

+ ///

+ /// Note that callers should retain references to returned objects. There is no + /// guarantee that this method will be implemented to be efficient. For example, + /// it may be synchronized, or may need to run an RDBMS query. + ///

+ ///

+ /// Will ask the parent factory if the object cannot be found in this factory + /// instance. + ///

+ ///
+ /// The name of the object to return. + /// + /// The arguments to use if creating a prototype using explicit arguments to + /// a static factory method. If there is no factory method and the + /// arguments are not null, then match the argument values by type and + /// call the object's constructor. + /// + /// The instance of the object. + /// + /// If there's no such object definition. + /// + /// + /// If the object could not be created. + /// + /// + /// If the supplied is . + /// + public object GetObject(string name, object[] arguments) + { + return GetObjectInternal(name, null, arguments, false); + + // string objectName = TransformedObjectName(name); + // object instance = null; + // + // // check if object definition exists + // RootObjectDefinition mergedObjectDefinition = null; + // mergedObjectDefinition = GetMergedObjectDefinition(objectName, false); + // if (mergedObjectDefinition == null) + // { + // if (ParentObjectFactory != null) + // { + // return ParentObjectFactory.GetObject(name, arguments); + // } + // throw new NoSuchObjectDefinitionException(name, "Cannot find definition for object [" + name + "]"); + // } + // + // // Override constructor values and configure as a prototype + // RootObjectDefinition tmpObjectDefinition = new RootObjectDefinition(mergedObjectDefinition); + // tmpObjectDefinition.ConstructorArgumentValues = null; + // tmpObjectDefinition.IsSingleton = false; + // + // // create a new instance... + // instance = CreateObject(name, tmpObjectDefinition, arguments); + // + // return GetObjectForInstance(name, instance); + } + + /// + /// Return an instance (possibly shared or independent) of the given object name, + /// optionally injecting dependencies. + /// + /// The name of the object to return. + /// + /// The the object may match. Can be an interface or + /// superclass of the actual class. For example, if the value is the + /// class, this method will succeed whatever the + /// class of the returned instance. + /// + /// + /// The arguments to use if creating a prototype using explicit arguments to + /// a factory method. If there is no factory method and the + /// supplied array is not , then + /// match the argument values by type and call the object's constructor. + /// + /// whether to inject dependencies or not. + /// The instance of the object. + /// + /// If there's no such object definition. + /// + /// + /// If the object could not be created. + /// + /// + /// If the object is not of the required type. + /// + /// + /// If the supplied is . + /// + /// + /// + protected object GetObjectInternal(string name, Type requiredType, object[] arguments, bool suppressConfigure) + { + object monitor = new object(); + const int indent = 3; + bool hasErrors = false; + var isDebugEnabled = log.IsEnabled(LogLevel.Debug); + + try { string objectName = TransformedObjectName(name); - // check if object actually exists in this object factory... - bool isInSingletonCache = ContainsSingleton(objectName); - if (isInSingletonCache || ContainsObjectDefinition(objectName)) + Interlocked.Increment(ref nestingCount); + + if (isDebugEnabled) { - // if found, gather aliases... - var matches = new List(); - foreach (DictionaryEntry aliasEntry in aliasMap) + log.LogDebug(string.Format("{2}GetObjectInternal: obtaining instance for name {0} => canonical name {1}", name, objectName, new string(' ', nestingCount * indent))); + } + + object instance; + + // those are cases, where singleton cache can be used + if (arguments == null && !suppressConfigure) + { + // eagerly check singleton cache for manually registered singletons... + object sharedInstance = GetSingleton(objectName); + if (sharedInstance != null) { - if (0 == string.Compare((string) aliasEntry.Value, objectName, !IsCaseSensitive)) + if (isDebugEnabled) { - matches.Add((string) aliasEntry.Key); + if (IsSingletonCurrentlyInCreation(objectName)) + { + log.LogDebug("Returning eagerly cached instance of singleton object '" + objectName + + "' that is not fully initialized yet - a consequence of a circular reference"); + } + else + { + log.LogDebug($"Returning cached instance of singleton object '{objectName}'."); + } + } + + instance = GetObjectForInstance(sharedInstance, name, objectName, null); + return EnsureObjectIsOfRequiredType(name, instance, requiredType); + } + } + + var set = prototypesInCreation.Value; + if (set.Contains(name)) + { + throw new ObjectCurrentlyInCreationException(name); + } + + if (!suppressConfigure) + { + MarkObjectAsCreated(objectName); + } + + // check if object definition exists + var mergedObjectDefinition = GetMergedObjectDefinition(objectName, false); + if (mergedObjectDefinition == null) + { + if (ParentObjectFactory != null) + { + return ParentObjectFactory.GetObject(name, requiredType, arguments); + } + + throw new NoSuchObjectDefinitionException(name, "Cannot find definition for object [" + name + "]"); + } + + if (arguments != null || suppressConfigure) + { + // Clone ObjectDefinition + mergedObjectDefinition = CreateRootObjectDefinition(mergedObjectDefinition); + mergedObjectDefinition.IsSingleton = false; + if (arguments != null) + { + // Override constructor values and configure as a prototype if arguments are specified + mergedObjectDefinition.ConstructorArgumentValues = null; + } + } + + CheckMergedObjectDefinition(mergedObjectDefinition, objectName, requiredType, arguments); + + // return IObjectDefinition instance itself for an abstract object-definition + if (mergedObjectDefinition.IsAbstract) + { + instance = mergedObjectDefinition; + } + else if (mergedObjectDefinition.IsSingleton) + { + // create object instance... + object sharedInstance = CreateAndCacheSingletonInstance(objectName, mergedObjectDefinition, arguments); + instance = GetObjectForInstance(sharedInstance, name, objectName, mergedObjectDefinition); + } + else + { + // it's a prototype, so create a new instance... + set.Add(name); + try + { + instance = InstantiateObject(name, mergedObjectDefinition, arguments, true, suppressConfigure); + } + finally + { + if (!set.Remove(name)) + { + ThrowNotCurrentlyInCreation(name); } } - - return matches; } - // not found, so check parent... - if (ParentObjectFactory != null) - { - return new List(ParentObjectFactory.GetAliases(objectName)); - } - - throw new NoSuchObjectDefinitionException(objectName, ToString()); - } - - /// - /// Return an instance (possibly shared or independent) of the given object name. - /// - /// . - public object this[string name] => GetObject(name); - - /// - /// Return an unconfigured(!) instance (possibly shared or independent) of the given object name. - /// - /// - /// - /// This method will only instantiate the requested object. It does NOT inject any dependencies! - /// - public object CreateObject(string name, Type requiredType, object[] arguments) - { - return GetObjectInternal(name, requiredType, arguments, true); - } - - /// - /// Return an unconfigured(!) instance (possibly shared or independent) of the given object name. - /// - /// The name of the object to return. - /// - /// The the object may match. Can be an interface or - /// superclass of the actual class. For example, if the value is the - /// class, this method will succeed whatever the - /// class of the returned instance. - /// - /// - /// The arguments to use if creating a prototype using explicit arguments to - /// a factory method. If there is no factory method and the - /// supplied array is not , then - /// match the argument values by type and call the object's constructor. - /// - /// The unconfigured(!) instance of the object. - /// - /// If there's no such object definition. - /// - /// - /// If the object could not be created. - /// - /// - /// If the object is not of the required type. - /// - /// - /// If the supplied is . - /// - /// - /// - /// This method will only instantiate the requested object. It does NOT inject any dependencies! - /// - public T CreateObject(string name, object[] arguments) - { - return (T)CreateObject(name, typeof(T), arguments); - } - - /// - /// Return an instance (possibly shared or independent) of the given object name. - /// - /// . - public object GetObject(string name) - { - return GetObjectInternal(name, null, null, false); - } - - - /// - /// Return an instance (possibly shared or independent) of the given object name. - /// - /// - /// - /// This method allows an object factory to be used as a replacement for the - /// Singleton or Prototype design pattern. - /// - /// - /// Note that callers should retain references to returned objects. There is no - /// guarantee that this method will be implemented to be efficient. For example, - /// it may be synchronized, or may need to run an RDBMS query. - /// - /// - /// Will ask the parent factory if the object cannot be found in this factory - /// instance. - /// - /// - /// The type of the object to return. - /// The instance of the object. - /// - /// If there's no such object definition. - /// - /// - /// If there is more than a single object of the requested type defined in the factory. - /// - /// - /// If the object could not be created. - /// - public abstract T GetObject(); - - /// - /// Return an instance (possibly shared or independent) of the given object name. - /// - /// - /// - /// This method allows an object factory to be used as a replacement for the - /// Singleton or Prototype design pattern. - /// - /// - /// Note that callers should retain references to returned objects. There is no - /// guarantee that this method will be implemented to be efficient. For example, - /// it may be synchronized, or may need to run an RDBMS query. - /// - /// - /// Will ask the parent factory if the object cannot be found in this factory - /// instance. - /// - /// - /// The type of the object to return. - /// The name of the object to return. - /// The instance of the object. - /// - /// If there's no such object definition. - /// - /// - /// If the object is not of the required type. - /// - /// - /// If the object could not be created. - /// - public T GetObject(string name) - { - return (T)GetObject(name); - } - - /// - /// Return an instance (possibly shared or independent) of the given object name. - /// - /// - public object GetObject(string name, Type requiredType) - { - return GetObjectInternal(name, requiredType, null, false); - } - - /// - /// Return an instance (possibly shared or independent) of the given object name. - /// - /// - ///

- /// This method allows an object factory to be used as a replacement for the - /// Singleton or Prototype design pattern. - ///

- ///

- /// Note that callers should retain references to returned objects. There is no - /// guarantee that this method will be implemented to be efficient. For example, - /// it may be synchronized, or may need to run an RDBMS query. - ///

- ///

- /// Will ask the parent factory if the object cannot be found in this factory - /// instance. - ///

- ///
- /// The name of the object to return. - /// - /// The arguments to use if creating a prototype using explicit arguments to - /// a static factory method. If there is no factory method and the - /// arguments are not null, then match the argument values by type and - /// call the object's constructor. - /// - /// The instance of the object. - /// - /// If there's no such object definition. - /// - /// - /// If the object could not be created. - /// - /// - /// If the supplied is . - /// - public object GetObject(string name, object[] arguments) - { - return GetObjectInternal(name, null, arguments, false); - - // string objectName = TransformedObjectName(name); - // object instance = null; - // - // // check if object definition exists - // RootObjectDefinition mergedObjectDefinition = null; - // mergedObjectDefinition = GetMergedObjectDefinition(objectName, false); - // if (mergedObjectDefinition == null) - // { - // if (ParentObjectFactory != null) - // { - // return ParentObjectFactory.GetObject(name, arguments); - // } - // throw new NoSuchObjectDefinitionException(name, "Cannot find definition for object [" + name + "]"); - // } - // - // // Override constructor values and configure as a prototype - // RootObjectDefinition tmpObjectDefinition = new RootObjectDefinition(mergedObjectDefinition); - // tmpObjectDefinition.ConstructorArgumentValues = null; - // tmpObjectDefinition.IsSingleton = false; - // - // // create a new instance... - // instance = CreateObject(name, tmpObjectDefinition, arguments); - // - // return GetObjectForInstance(name, instance); - } - - /// - /// Return an instance (possibly shared or independent) of the given object name, - /// optionally injecting dependencies. - /// - /// The name of the object to return. - /// - /// The the object may match. Can be an interface or - /// superclass of the actual class. For example, if the value is the - /// class, this method will succeed whatever the - /// class of the returned instance. - /// - /// - /// The arguments to use if creating a prototype using explicit arguments to - /// a factory method. If there is no factory method and the - /// supplied array is not , then - /// match the argument values by type and call the object's constructor. - /// - /// whether to inject dependencies or not. - /// The instance of the object. - /// - /// If there's no such object definition. - /// - /// - /// If the object could not be created. - /// - /// - /// If the object is not of the required type. - /// - /// - /// If the supplied is . - /// - /// - /// - protected object GetObjectInternal(string name, Type requiredType, object[] arguments, bool suppressConfigure) - { - object monitor = new object(); - const int indent = 3; - bool hasErrors = false; - var isDebugEnabled = log.IsEnabled(LogLevel.Debug); - try { - string objectName = TransformedObjectName(name); - Interlocked.Increment(ref nestingCount); - - if (isDebugEnabled) - { - log.LogDebug(string.Format("{2}GetObjectInternal: obtaining instance for name {0} => canonical name {1}", name, objectName, new string(' ', nestingCount * indent))); - } - - object instance; - - // those are cases, where singleton cache can be used - if (arguments == null && !suppressConfigure) - { - // eagerly check singleton cache for manually registered singletons... - object sharedInstance = GetSingleton(objectName); - if (sharedInstance != null) - { - if (isDebugEnabled) - { - if (IsSingletonCurrentlyInCreation(objectName)) - { - log.LogDebug("Returning eagerly cached instance of singleton object '" + objectName + - "' that is not fully initialized yet - a consequence of a circular reference"); - } - else - { - log.LogDebug($"Returning cached instance of singleton object '{objectName}'."); - } - } - - instance = GetObjectForInstance(sharedInstance, name, objectName, null); - return EnsureObjectIsOfRequiredType(name, instance, requiredType); - } - } - - var set = prototypesInCreation.Value; - if (set.Contains(name)) - { - throw new ObjectCurrentlyInCreationException(name); - } - - if (!suppressConfigure) - { - MarkObjectAsCreated(objectName); - } - - // check if object definition exists - var mergedObjectDefinition = GetMergedObjectDefinition(objectName, false); - if (mergedObjectDefinition == null) - { - if (ParentObjectFactory != null) - { - return ParentObjectFactory.GetObject(name, requiredType, arguments); - } - throw new NoSuchObjectDefinitionException(name, "Cannot find definition for object [" + name + "]"); - } - - if (arguments != null || suppressConfigure) - { - // Clone ObjectDefinition - mergedObjectDefinition = CreateRootObjectDefinition(mergedObjectDefinition); - mergedObjectDefinition.IsSingleton = false; - if (arguments != null) - { - // Override constructor values and configure as a prototype if arguments are specified - mergedObjectDefinition.ConstructorArgumentValues = null; - } - } - - CheckMergedObjectDefinition(mergedObjectDefinition, objectName, requiredType, arguments); - - // return IObjectDefinition instance itself for an abstract object-definition - if (mergedObjectDefinition.IsAbstract) - { - instance = mergedObjectDefinition; - } - else if (mergedObjectDefinition.IsSingleton) - { - // create object instance... - object sharedInstance = CreateAndCacheSingletonInstance(objectName, mergedObjectDefinition, arguments); - instance = GetObjectForInstance(sharedInstance, name, objectName, mergedObjectDefinition); - } - else - { - // it's a prototype, so create a new instance... - set.Add(name); - try - { - instance = InstantiateObject(name, mergedObjectDefinition, arguments, true, suppressConfigure); - } - finally - { - if (!set.Remove(name)) - { - ThrowNotCurrentlyInCreation(name); - } - } - } - - try - { - RegisterDisposableObjectIfNecessary(name, instance, mergedObjectDefinition); - } - catch (ObjectDefinitionValidationException ex) - { - throw new ObjectCreationException(mergedObjectDefinition.ResourceDescription, name, "Invalid destruction signature", ex); - } - - return EnsureObjectIsOfRequiredType(name, instance, requiredType); + RegisterDisposableObjectIfNecessary(name, instance, mergedObjectDefinition); } - catch + catch (ObjectDefinitionValidationException ex) + { + throw new ObjectCreationException(mergedObjectDefinition.ResourceDescription, name, "Invalid destruction signature", ex); + } + + return EnsureObjectIsOfRequiredType(name, instance, requiredType); + } + catch + { + lock (monitor) + { + if (nestingCount > 0) + { + nestingCount--; + } + } + + CleanupAfterObjectCreationFailure(name); + + hasErrors = true; + if (log.IsEnabled(LogLevel.Error)) + { + log.LogError(string.Format("{1}GetObjectInternal: error obtaining object {0}", name, new string(' ', nestingCount * indent))); + } + + throw; + } + finally + { + if (!hasErrors) { lock (monitor) { @@ -2221,542 +2249,524 @@ namespace Spring.Objects.Factory.Support } } - CleanupAfterObjectCreationFailure(name); - - hasErrors = true; - if (log.IsEnabled(LogLevel.Error)) + if (isDebugEnabled) { - log.LogError(string.Format("{1}GetObjectInternal: error obtaining object {0}", name, new string(' ', nestingCount * indent))); - } - - throw; - } - finally - { - if (!hasErrors) - { - lock (monitor) - { - if (nestingCount > 0) - { - nestingCount--; - } - } - - if (isDebugEnabled) - { - log.LogDebug(string.Format("{1}GetObjectInternal: returning instance for objectname {0}", name, new string(' ', nestingCount * indent))); - } + log.LogDebug(string.Format("{1}GetObjectInternal: returning instance for objectname {0}", name, new string(' ', nestingCount * indent))); } } } + } - protected virtual void RegisterDisposableObjectIfNecessary(string name, object instance, RootObjectDefinition od) + protected virtual void RegisterDisposableObjectIfNecessary(string name, object instance, RootObjectDefinition od) + { + if (od.IsSingleton && RequiresDestruction(instance, od)) { - if (od.IsSingleton && RequiresDestruction(instance, od)) - { - // Register a DisposableObject implementation that performs all destruction - // work for the given object: DestructionAwareObjectPostProcessors, - // DisposableObject interface, custom destroy method. - RegisterDisposableObject(name, - new DisposableObjectAdapter(instance, name, od, objectPostProcessors)); - - } + // Register a DisposableObject implementation that performs all destruction + // work for the given object: DestructionAwareObjectPostProcessors, + // DisposableObject interface, custom destroy method. + RegisterDisposableObject(name, + new DisposableObjectAdapter(instance, name, od, objectPostProcessors)); } + } - /// - /// Requireses the destruction. - /// - /// The instance to check. - /// The corresponding instance definition. - /// - /// Boolean indicating whether destruction is required. - /// - - protected bool RequiresDestruction(object instance, RootObjectDefinition od) - { - return (instance != null && + /// + /// Requireses the destruction. + /// + /// The instance to check. + /// The corresponding instance definition. + /// + /// Boolean indicating whether destruction is required. + /// + protected bool RequiresDestruction(object instance, RootObjectDefinition od) + { + return (instance != null && (instance is IDisposable || od.DestroyMethodName != null || HasDestructionAwareObjectPostProcessors)); + } + + private int nestingCount; + + /// + /// Checks, if the passed instance is of the required type. + /// + /// the name of the object + /// the actual instance + /// the type contract the given instance must adhere. + /// the object instance passed in via (for more fluent usage) + /// + /// if is null or not assignable to . + /// + private object EnsureObjectIsOfRequiredType(string name, object instance, Type requiredType) + { + // check that any required type matches the type of the actual object instance... + if (requiredType != null && instance != null && !requiredType.IsAssignableFrom(instance.GetType())) + { + throw new ObjectNotOfRequiredTypeException(name, requiredType, instance); } - private int nestingCount; + return instance; + } - /// - /// Checks, if the passed instance is of the required type. - /// - /// the name of the object - /// the actual instance - /// the type contract the given instance must adhere. - /// the object instance passed in via (for more fluent usage) - /// - /// if is null or not assignable to . - /// - private object EnsureObjectIsOfRequiredType(string name, object instance, Type requiredType) + /// + /// Creates a singleton instance for the specified object name and definition. + /// + /// + /// The object name (will be used as the key in the singleton cache key). + /// + /// The object definition. + /// + /// The arguments to use if creating a prototype using explicit arguments to + /// a static factory method. If there is no factory method and the + /// arguments are not null, then match the argument values by type and + /// call the object's constructor. + /// + /// The created object instance. + protected virtual object CreateAndCacheSingletonInstance(string objectName, + RootObjectDefinition objectDefinition, + object[] arguments) + { + lock (GetSingletonLockFor(objectName)) { - // check that any required type matches the type of the actual object instance... - if (requiredType != null && instance != null && !requiredType.IsAssignableFrom(instance.GetType())) + object sharedInstance = singletonCache[objectName]; + if (sharedInstance == null) { - throw new ObjectNotOfRequiredTypeException(name, requiredType, instance); - } - - return instance; - } - - /// - /// Creates a singleton instance for the specified object name and definition. - /// - /// - /// The object name (will be used as the key in the singleton cache key). - /// - /// The object definition. - /// - /// The arguments to use if creating a prototype using explicit arguments to - /// a static factory method. If there is no factory method and the - /// arguments are not null, then match the argument values by type and - /// call the object's constructor. - /// - /// The created object instance. - protected virtual object CreateAndCacheSingletonInstance(string objectName, - RootObjectDefinition objectDefinition, - object[] arguments) - { - lock (GetSingletonLockFor(objectName)) - { - object sharedInstance = singletonCache[objectName]; - if (sharedInstance == null) + if (log.IsEnabled(LogLevel.Debug)) { - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug(string.Format("Creating shared instance of singleton object '{0}'", objectName)); - } - - BeforeSingletonCreation(objectName); - try - { - sharedInstance = InstantiateObject(objectName, objectDefinition, arguments, true, false); - } - finally - { - AfterSingletonCreation(objectName); - } - AddSingleton(objectName, sharedInstance); - - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug(string.Format("Cached shared instance of singleton object '{0}'", objectName)); - } + log.LogDebug(string.Format("Creating shared instance of singleton object '{0}'", objectName)); } - return sharedInstance; - } - } - /// - /// Injects dependencies into the supplied instance - /// using the named object definition. - /// - /// - public abstract object ConfigureObject(object target, string name); - - /// - /// Injects dependencies into the supplied instance - /// using the supplied . - /// - /// - public abstract object ConfigureObject(object target, string name, IObjectDefinition definition); - - /// - /// Destroy all cached singletons in this factory. - /// - public virtual void Dispose() - { - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug(string.Format("Destroying singletons in factory [{0}].", this)); - } - - prototypesInCreation.Dispose(); - - lock (singletonCache) - { - // copy the keys into a new set, 'cos we are going to modifying the - // original collection (_singletonCache) as we destroy each singleton. - // we also want to traverse the keys in reverse order to destroy correctly - ArrayList keys = new ArrayList(singletonCache.Keys); - keys.Reverse(); - foreach (string name in keys) + BeforeSingletonCreation(objectName); + try { - DestroySingleton(name); + sharedInstance = InstantiateObject(objectName, objectDefinition, arguments, true, false); + } + finally + { + AfterSingletonCreation(objectName); + } + + AddSingleton(objectName, sharedInstance); + + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug(string.Format("Cached shared instance of singleton object '{0}'", objectName)); } } - } - /// - /// Ignore the given dependency type for autowiring - /// - /// . - public void IgnoreDependencyType(Type type) + return sharedInstance; + } + } + + /// + /// Injects dependencies into the supplied instance + /// using the named object definition. + /// + /// + public abstract object ConfigureObject(object target, string name); + + /// + /// Injects dependencies into the supplied instance + /// using the supplied . + /// + /// + public abstract object ConfigureObject(object target, string name, IObjectDefinition definition); + + /// + /// Destroy all cached singletons in this factory. + /// + public virtual void Dispose() + { + if (log.IsEnabled(LogLevel.Debug)) { - IgnoredDependencyTypes.Add(type); + log.LogDebug(string.Format("Destroying singletons in factory [{0}].", this)); } - /// - /// Determines whether the specified object name is currently in creation.. - /// - /// Name of the object. - /// - /// true if the specified object name is currently in creation; otherwise, false. - /// - public bool IsCurrentlyInCreation(string objectName) + prototypesInCreation.Dispose(); + + lock (singletonCache) { - return IsSingletonCurrentlyInCreation(objectName) || IsPrototypeCurrentlyInCreation(objectName); + // copy the keys into a new set, 'cos we are going to modifying the + // original collection (_singletonCache) as we destroy each singleton. + // we also want to traverse the keys in reverse order to destroy correctly + ArrayList keys = new ArrayList(singletonCache.Keys); + keys.Reverse(); + foreach (string name in keys) + { + DestroySingleton(name); + } } + } - private static void ThrowNotCurrentlyInCreation(string name) + /// + /// Ignore the given dependency type for autowiring + /// + /// . + public void IgnoreDependencyType(Type type) + { + IgnoredDependencyTypes.Add(type); + } + + /// + /// Determines whether the specified object name is currently in creation.. + /// + /// Name of the object. + /// + /// true if the specified object name is currently in creation; otherwise, false. + /// + public bool IsCurrentlyInCreation(string objectName) + { + return IsSingletonCurrentlyInCreation(objectName) || IsPrototypeCurrentlyInCreation(objectName); + } + + private static void ThrowNotCurrentlyInCreation(string name) + { + throw new InvalidOperationException("Singleton " + name + " isn't currently in creation."); + } + + private bool IsPrototypeCurrentlyInCreation(string name) + { + return prototypesInCreation.Value.Contains(name); + } + + private void AfterSingletonCreation(string name) + { + if (!IsSingletonCurrentlyInCreation(name)) { throw new InvalidOperationException("Singleton " + name + " isn't currently in creation."); } - private bool IsPrototypeCurrentlyInCreation(string name) + singletonsInCreation.Remove(name); + } + + private void BeforeSingletonCreation(string name) + { + if (singletonsInCreation.Contains(name)) { - return prototypesInCreation.Value.Contains(name); + throw new ObjectCurrentlyInCreationException(name); } - private void AfterSingletonCreation(string name) + singletonsInCreation.Add(name, EmptyObject); + } + + private bool IsSingletonCurrentlyInCreation(string name) + { + return singletonsInCreation.Contains(name); + } + + /// + /// Add a String resolver for embedded values such as annotation attributes. + /// + /// the String resolver to apply to embedded values + public void AddEmbeddedValueResolver(IStringValueResolver valueResolver) + { + embeddedValueResolvers.Add(valueResolver); + } + + /// + /// Resolve the given embedded value, e.g. an annotation attribute. + /// + /// the value to resolve + /// the resolved value (may be the original value as-is) + public string ResolveEmbeddedValue(string value) + { + string result = value; + foreach (IStringValueResolver resolver in embeddedValueResolvers) { - if (!IsSingletonCurrentlyInCreation(name)) - { - throw new InvalidOperationException("Singleton " + name + " isn't currently in creation."); - } - singletonsInCreation.Remove(name); + result = resolver.ParseAndResolveVariables(result); } - private void BeforeSingletonCreation(string name) + return result; + } + + /// + /// Add a new + /// that will get applied to objects created by this factory. + /// + /// + /// The + /// to register. + /// + /// . + public void AddObjectPostProcessor(IObjectPostProcessor objectPostProcessor) + { + if (objectPostProcessor is IObjectFactoryAware) { - if (singletonsInCreation.Contains(name)) - { - throw new ObjectCurrentlyInCreationException(name); - } - singletonsInCreation.Add(name, EmptyObject); + ((IObjectFactoryAware) objectPostProcessor).ObjectFactory = this; } - private bool IsSingletonCurrentlyInCreation(string name) + // ensure the same instance doesn't get registered twice + if (!objectPostProcessors.Contains(objectPostProcessor)) { - return singletonsInCreation.Contains(name); + objectPostProcessors.Add(objectPostProcessor); } - /// - /// Add a String resolver for embedded values such as annotation attributes. - /// - /// the String resolver to apply to embedded values - public void AddEmbeddedValueResolver(IStringValueResolver valueResolver) + if (typeof(IInstantiationAwareObjectPostProcessor).IsInstanceOfType(objectPostProcessor)) { - embeddedValueResolvers.Add(valueResolver); + hasInstantiationAwareObjectPostProcessors = true; } - /// - /// Resolve the given embedded value, e.g. an annotation attribute. - /// - /// the value to resolve - /// the resolved value (may be the original value as-is) - public string ResolveEmbeddedValue(string value) + if (typeof(IDestructionAwareObjectPostProcessor).IsInstanceOfType(objectPostProcessor)) { - string result = value; - foreach (IStringValueResolver resolver in embeddedValueResolvers) - { - result = resolver.ParseAndResolveVariables(result); - } - return result; + hasDestructionAwareObjectPostProcessors = true; } + } - /// - /// Add a new - /// that will get applied to objects created by this factory. - /// - /// - /// The - /// to register. - /// - /// . - public void AddObjectPostProcessor(IObjectPostProcessor objectPostProcessor) + /// + /// Returns the current number of registered + /// s. + /// + /// + /// The current number of registered + /// s. + /// + /// . + public int ObjectPostProcessorCount => objectPostProcessors.Count; + + /// + /// Given an object name, create an alias. + /// + /// . + public void RegisterAlias(string name, string alias) + { + AssertUtils.ArgumentHasText(name, "The object name must not be empty."); + AssertUtils.ArgumentHasText(alias, "The alias must not be empty."); + + if (name == alias) { - if (objectPostProcessor is IObjectFactoryAware) - { - ((IObjectFactoryAware)objectPostProcessor).ObjectFactory = this; - } - - // ensure the same instance doesn't get registered twice - if (!objectPostProcessors.Contains(objectPostProcessor)) - { - objectPostProcessors.Add(objectPostProcessor); - } - if (typeof(IInstantiationAwareObjectPostProcessor).IsInstanceOfType(objectPostProcessor)) - { - hasInstantiationAwareObjectPostProcessors = true; - } - if (typeof(IDestructionAwareObjectPostProcessor).IsInstanceOfType(objectPostProcessor)) - { - hasDestructionAwareObjectPostProcessors = true; - } - } - - /// - /// Returns the current number of registered - /// s. - /// - /// - /// The current number of registered - /// s. - /// - /// . - public int ObjectPostProcessorCount => objectPostProcessors.Count; - - /// - /// Given an object name, create an alias. - /// - /// . - public void RegisterAlias(string name, string alias) - { - AssertUtils.ArgumentHasText(name, "The object name must not be empty."); - AssertUtils.ArgumentHasText(alias, "The alias must not be empty."); - - if (name == alias) - { - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug($"Ignoring attempt to Register alias '{alias}' for object with name '{name}' because name and alias would be the same value."); - } - - return; - } - if (log.IsEnabled(LogLevel.Debug)) { - log.LogDebug($"Registering alias '{alias}' for object with name '{name}'."); + log.LogDebug($"Ignoring attempt to Register alias '{alias}' for object with name '{name}' because name and alias would be the same value."); } - object registeredName = aliasMap[alias]; - if (registeredName != null) + return; + } + + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug($"Registering alias '{alias}' for object with name '{name}'."); + } + + object registeredName = aliasMap[alias]; + if (registeredName != null) + { + throw new ObjectDefinitionStoreException( + $"Cannot register alias '{alias}' for object with name '{name}': it's already registered for object name '{registeredName}'."); + } + + aliasMap[alias] = name; + } + + /// + /// Register the given custom + /// for all properties of the given . + /// + /// . + public void RegisterCustomConverter(Type requiredType, TypeConverter converter) + { + AssertUtils.ArgumentNotNull(requiredType, "requiredType"); + TypeConverterRegistry.RegisterConverter(requiredType, converter); + } + + /// + /// Register the given existing object as singleton in the object factory, + /// under the given object name. + /// + /// . + public virtual void RegisterSingleton(string name, object singletonObject) + { + AssertUtils.ArgumentHasText(name, "name", "The singleton object cannot be registered under an empty name."); + lock (GetSingletonLockFor(name)) + { + object oldObject = singletonCache[name]; + if (oldObject != null) { throw new ObjectDefinitionStoreException( - $"Cannot register alias '{alias}' for object with name '{name}': it's already registered for object name '{registeredName}'."); + $"Could not register object [{singletonObject}] under object name '{name}': there's already object [{oldObject}] bound."); } - aliasMap[alias] = name; + AddSingleton(name, singletonObject); } + } - /// - /// Register the given custom - /// for all properties of the given . - /// - /// . - public void RegisterCustomConverter(Type requiredType, TypeConverter converter) + /// + /// Does this object factory contains a singleton instance with the + /// supplied ? + /// + /// + public bool ContainsSingleton(string name) + { + AssertUtils.ArgumentHasText(name, "name"); + lock (GetSingletonLockFor(name)) { - AssertUtils.ArgumentNotNull(requiredType, "requiredType"); - TypeConverterRegistry.RegisterConverter(requiredType, converter); + return singletonCache.Contains(name); } + } - /// - /// Register the given existing object as singleton in the object factory, - /// under the given object name. - /// - /// . - public virtual void RegisterSingleton(string name, object singletonObject) + /// + /// Gets the names of singleton objects registered in this registry. + /// + /// The list of names as String array (never null). + /// + /// + /// Only checks already instantiated singletons; does not return names + /// for singleton instance definitions which have not been instantiated yet. + /// + /// + /// The main purpose of this method is to check manually registered singletons + /// . Can also be used to check which + /// singletons defined by an object definition have already been created. + /// + /// + /// + /// + /// + public IList SingletonNames + { + get { - AssertUtils.ArgumentHasText(name, "name", "The singleton object cannot be registered under an empty name."); - lock (GetSingletonLockFor(name)) + lock (singletonCache) { - object oldObject = singletonCache[name]; - if (oldObject != null) - { - throw new ObjectDefinitionStoreException( - $"Could not register object [{singletonObject}] under object name '{name}': there's already object [{oldObject}] bound."); - } - AddSingleton(name, singletonObject); - } - } - - /// - /// Does this object factory contains a singleton instance with the - /// supplied ? - /// - /// - public bool ContainsSingleton(string name) - { - AssertUtils.ArgumentHasText(name, "name"); - lock (GetSingletonLockFor(name)) - { - return singletonCache.Contains(name); - } - } - - /// - /// Gets the names of singleton objects registered in this registry. - /// - /// The list of names as String array (never null). - /// - /// - /// Only checks already instantiated singletons; does not return names - /// for singleton instance definitions which have not been instantiated yet. - /// - /// - /// The main purpose of this method is to check manually registered singletons - /// . Can also be used to check which - /// singletons defined by an object definition have already been created. - /// - /// - /// - /// - /// - public IList SingletonNames - { - get - { - lock (singletonCache) - { - return - StringUtils.DelimitedListToStringArray( - StringUtils.CollectionToDelimitedString(registeredSingletons, ","), ","); - - } - } - } - - /// - /// Gets the number of singleton beans registered in this registry. - /// - /// The number of singleton objects. - /// - /// - /// Only checks already instantiated singletons; does not count - /// singleton object definitions which have not been instantiated yet. - /// - /// - /// The main purpose of this method is to check manually registered singletons - /// . Can also be used to count the number of - /// singletons defined by an object definition that have already been created. - /// - /// - /// - /// - /// - public int SingletonCount - { - get - { - lock (singletonCache) - { - return registeredSingletons.Count; - } - } - } - /// - /// Tries to find a cached object for the specified name. - /// - /// Teh object name to look for. - /// The cached object if found, otherwise. - public virtual object GetSingleton(string objectName) - { - lock (GetSingletonLockFor(objectName)) - { - return singletonCache[objectName]; - } - } - - - /// - /// Registers the disposable object. - /// - /// Name of the instance. - /// The instance. - /// Add the given instance to the list of disposable beans in this registry. - /// Disposable beans usually correspond to registered singletons, - /// matching the instance name but potentially being a different instance - /// (for example, a DisposableBean adapter for a singleton that does not - /// naturally implement ). - public void RegisterDisposableObject(string objectName, IDisposable instance) - { - if (disposableObjects.ContainsKey(objectName)) return; - disposableObjects.Add(objectName, instance); - } - - - - /// - /// Determines whether the given object name is already in use within this factory, - /// i.e. whether there is a local object or alias registered under this name or - /// an inner object created with this name. - /// - /// Name of the object to check. - /// - /// true if is object name in use; otherwise, false. - /// - public bool IsObjectNameInUse(string objectName) - { - return IsAlias(objectName) || ContainsLocalObject(objectName); - } - - /// - /// Gets the singleton lock for a given object name. - /// - /// Name of the object. - /// lock object - private object GetSingletonLockFor(string objectName) - { - return singletonLocks.GetOrAdd(objectName, key => new Lazy(() => new object())).Value; - } - - [Serializable] - private class LogicalThreadContextSetVariable : IDisposable - { - private readonly string name = Guid.NewGuid().ToString(); - - public HashSet Value - { - get - { - if (!(LogicalThreadContext.GetData(name) is HashSet set)) - { - set = new HashSet(); - LogicalThreadContext.SetData(name, set); - } - return set; - } - } - - public void Dispose() - { - LogicalThreadContext.FreeNamedDataSlot(name); - } - } - - /// - /// Makes a distinction between sort order and object identity. - /// This is important when used with , since most - /// implementations assume Order == Identity - /// - [Serializable] - private class ObjectOrderComparator : OrderComparator - { - public static readonly ObjectOrderComparator ObjectOrderComparatorInstance = new ObjectOrderComparator(); - /// - /// Handle the case when both objects have equal sort order priority. By default returns 0, - /// but may be overriden for handling special cases. - /// - /// The first object to compare. - /// The second object to compare. - /// - /// -1 if first object is less then second, 1 if it is greater, or 0 if they are equal. - /// - protected override int CompareEqualOrder(object o1, object o2) - { - if (ReferenceEquals(o1, o2)) - return 0; - if (o1 == null) - return 1; - if (o2 == null) - return -1; - return o1.GetHashCode().CompareTo(o2.GetHashCode()); + return + StringUtils.DelimitedListToStringArray( + StringUtils.CollectionToDelimitedString(registeredSingletons, ","), ","); } } } + + /// + /// Gets the number of singleton beans registered in this registry. + /// + /// The number of singleton objects. + /// + /// + /// Only checks already instantiated singletons; does not count + /// singleton object definitions which have not been instantiated yet. + /// + /// + /// The main purpose of this method is to check manually registered singletons + /// . Can also be used to count the number of + /// singletons defined by an object definition that have already been created. + /// + /// + /// + /// + /// + public int SingletonCount + { + get + { + lock (singletonCache) + { + return registeredSingletons.Count; + } + } + } + + /// + /// Tries to find a cached object for the specified name. + /// + /// Teh object name to look for. + /// The cached object if found, otherwise. + public virtual object GetSingleton(string objectName) + { + lock (GetSingletonLockFor(objectName)) + { + return singletonCache[objectName]; + } + } + + /// + /// Registers the disposable object. + /// + /// Name of the instance. + /// The instance. + /// Add the given instance to the list of disposable beans in this registry. + /// Disposable beans usually correspond to registered singletons, + /// matching the instance name but potentially being a different instance + /// (for example, a DisposableBean adapter for a singleton that does not + /// naturally implement ). + public void RegisterDisposableObject(string objectName, IDisposable instance) + { + if (disposableObjects.ContainsKey(objectName)) return; + disposableObjects.Add(objectName, instance); + } + + /// + /// Determines whether the given object name is already in use within this factory, + /// i.e. whether there is a local object or alias registered under this name or + /// an inner object created with this name. + /// + /// Name of the object to check. + /// + /// true if is object name in use; otherwise, false. + /// + public bool IsObjectNameInUse(string objectName) + { + return IsAlias(objectName) || ContainsLocalObject(objectName); + } + + /// + /// Gets the singleton lock for a given object name. + /// + /// Name of the object. + /// lock object + private object GetSingletonLockFor(string objectName) + { + return singletonLocks.GetOrAdd(objectName, key => new Lazy(() => new object())).Value; + } + + [Serializable] + private class LogicalThreadContextSetVariable : IDisposable + { + private readonly string name = Guid.NewGuid().ToString(); + + public HashSet Value + { + get + { + if (!(LogicalThreadContext.GetData(name) is HashSet set)) + { + set = new HashSet(); + LogicalThreadContext.SetData(name, set); + } + + return set; + } + } + + public void Dispose() + { + LogicalThreadContext.FreeNamedDataSlot(name); + } + } + + /// + /// Makes a distinction between sort order and object identity. + /// This is important when used with , since most + /// implementations assume Order == Identity + /// + [Serializable] + private class ObjectOrderComparator : OrderComparator + { + public static readonly ObjectOrderComparator ObjectOrderComparatorInstance = new ObjectOrderComparator(); + + /// + /// Handle the case when both objects have equal sort order priority. By default returns 0, + /// but may be overriden for handling special cases. + /// + /// The first object to compare. + /// The second object to compare. + /// + /// -1 if first object is less then second, 1 if it is greater, or 0 if they are equal. + /// + protected override int CompareEqualOrder(object o1, object o2) + { + if (ReferenceEquals(o1, o2)) + return 0; + if (o1 == null) + return 1; + if (o2 == null) + return -1; + return o1.GetHashCode().CompareTo(o2.GetHashCode()); + } + } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/AutowireCandidateQualifier.cs b/src/Spring/Spring.Core/Objects/Factory/Support/AutowireCandidateQualifier.cs index 68f0e139..28945d6b 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/AutowireCandidateQualifier.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/AutowireCandidateQualifier.cs @@ -16,79 +16,75 @@ using System.Diagnostics; -namespace Spring.Objects.Factory.Support +namespace Spring.Objects.Factory.Support; + +/// +/// Qualifier for resolving autowire candidates. A bean definition that +/// includes one or more such qualifiers enables fine-grained matching +/// against annotations on a field or parameter to be autowired. +/// +public class AutowireCandidateQualifier : ObjectMetadataAttributeAccessor { + public static string VALUE_KEY = "Value"; + + private readonly string _typeName; + /// - /// Qualifier for resolving autowire candidates. A bean definition that - /// includes one or more such qualifiers enables fine-grained matching - /// against annotations on a field or parameter to be autowired. + /// Construct a qualifier to match against an annotation of the + /// given type. /// - public class AutowireCandidateQualifier : ObjectMetadataAttributeAccessor + /// type the annotation type + public AutowireCandidateQualifier(Type type) : this(type.Name) { - public static string VALUE_KEY = "Value"; + } - private readonly string _typeName; + /// + /// Construct a qualifier to match against an annotation of the + /// given type name. + ///

The type name may match the fully-qualified class name of + /// the annotation or the short class name (without the package).

+ ///
+ /// the name of the annotation type + public AutowireCandidateQualifier(string typeName) + { + Trace.Assert(typeName != null, "Type name must not be null"); + _typeName = typeName; + } + /// + /// Construct a qualifier to match against an annotation of the + /// given type whose value attribute also matches + /// the specified value. + /// + /// the annotation type + /// the annotation value to match + public AutowireCandidateQualifier(Type type, object value) : this(type.Name, value) + { + } - /// - /// Construct a qualifier to match against an annotation of the - /// given type. - /// - /// type the annotation type - public AutowireCandidateQualifier(Type type) : this(type.Name) - { - } - - /// - /// Construct a qualifier to match against an annotation of the - /// given type name. - ///

The type name may match the fully-qualified class name of - /// the annotation or the short class name (without the package).

- ///
- /// the name of the annotation type - public AutowireCandidateQualifier(string typeName) - { - Trace.Assert(typeName != null, "Type name must not be null"); - _typeName = typeName; - } - - /// - /// Construct a qualifier to match against an annotation of the - /// given type whose value attribute also matches - /// the specified value. - /// - /// the annotation type - /// the annotation value to match - public AutowireCandidateQualifier(Type type, object value) : this(type.Name, value) - { - } - - /// - /// Construct a qualifier to match against an annotation of the - /// given type name whose value attribute also matches - /// the specified value. - ///

The type name may match the fully-qualified class name of - /// the annotation or the short class name (without the package).

- ///
- /// the name of the annotation type - /// the annotation value to match - public AutowireCandidateQualifier(string typeName, object value) - { - Trace.Assert(typeName != null, "Type name must not be null"); - _typeName = typeName; - SetAttribute(VALUE_KEY, value); - } - - - /// - /// Retrieve the type name. This value will be the same as the - /// type name provided to the constructor or the fully-qualified - /// class name if a Class instance was provided to the constructor. - /// - public String TypeName - { - get { return _typeName; } - } + /// + /// Construct a qualifier to match against an annotation of the + /// given type name whose value attribute also matches + /// the specified value. + ///

The type name may match the fully-qualified class name of + /// the annotation or the short class name (without the package).

+ ///
+ /// the name of the annotation type + /// the annotation value to match + public AutowireCandidateQualifier(string typeName, object value) + { + Trace.Assert(typeName != null, "Type name must not be null"); + _typeName = typeName; + SetAttribute(VALUE_KEY, value); + } + /// + /// Retrieve the type name. This value will be the same as the + /// type name provided to the constructor or the fully-qualified + /// class name if a Class instance was provided to the constructor. + /// + public String TypeName + { + get { return _typeName; } } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/AutowireUtils.cs b/src/Spring/Spring.Core/Objects/Factory/Support/AutowireUtils.cs index 52ca54d9..99f5f8f9 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/AutowireUtils.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/AutowireUtils.cs @@ -16,352 +16,361 @@ using System.Collections; using System.Reflection; - using Spring.Collections; using Spring.Core; using Spring.Objects.Factory.Attributes; using Spring.Objects.Factory.Config; using Spring.Util; -namespace Spring.Objects.Factory.Support +namespace Spring.Objects.Factory.Support; + +/// +/// Utility class that contains various methods useful for the implementation of +/// autowire-capable object factories. +/// +/// Juergen Hoeller +/// Rick Evans (.NET) +public sealed class AutowireUtils { - /// - /// Utility class that contains various methods useful for the implementation of - /// autowire-capable object factories. - /// - /// Juergen Hoeller - /// Rick Evans (.NET) - public sealed class AutowireUtils - { - // CLOVER:OFF + // CLOVER:OFF - /// - /// Creates a new instance of the AutowireUtils class. - /// - /// - ///

- /// This is a utility class, and as such has no publicly - /// visible constructors. - ///

- ///
- private AutowireUtils() - { - } + /// + /// Creates a new instance of the AutowireUtils class. + /// + /// + ///

+ /// This is a utility class, and as such has no publicly + /// visible constructors. + ///

+ ///
+ private AutowireUtils() + { + } - // CLOVER:ON + // CLOVER:ON - /// - /// Gets those s - /// that are applicable for autowiring the supplied . - /// - /// - /// The - /// (definition) that is being autowired by constructor. - /// - /// - /// The absolute minimum number of arguments that any returned constructor - /// must have. If this parameter is equal to zero (0), then all constructors - /// are valid (regardless of their argument count), including any default - /// constructor. - /// - /// - /// Those s - /// that are applicable for autowiring the supplied . - /// - public static ConstructorInfo[] GetConstructors( - IObjectDefinition definition, int minimumArgumentCount) - { - var rootObjectDefinition = definition as RootObjectDefinition; - if (minimumArgumentCount == 0 && rootObjectDefinition?.defaultConstructor != null) - { - return rootObjectDefinition.defaultConstructor; - } - - const BindingFlags flags = - BindingFlags.Public - | BindingFlags.NonPublic - | BindingFlags.Instance - | BindingFlags.DeclaredOnly; - - ConstructorInfo[] constructors; - if (minimumArgumentCount > 0) - { - MemberInfo[] ctors = definition.ObjectType.FindMembers( - MemberTypes.Constructor, - flags, - new CriteriaMemberFilter().FilterMemberByCriteria, - new MinimumArgumentCountCriteria(minimumArgumentCount)); - constructors = (ConstructorInfo[]) ArrayList.Adapter(ctors).ToArray(typeof (ConstructorInfo)); - } - else - { - constructors = definition.ObjectType.GetConstructors(flags); - if (rootObjectDefinition != null) - { - rootObjectDefinition.defaultConstructor = constructors; - } - } - SortConstructors(constructors); - return constructors; - } - - /// - /// Determine a weight that represents the class hierarchy difference between types and - /// arguments. - /// - /// - ///

- /// A direct match, i.e. type MyInteger -> arg of class MyInteger, does not increase - /// the result - all direct matches means weight zero (0). A match between the argument type - /// and a MyInteger instance argument would increase the weight by - /// 1, due to the superclass () being one (1) steps up in the - /// class hierarchy being the last one that still matches the required type. - ///

- ///

- /// Therefore, with an argument of type , a - /// constructor taking a argument would be - /// preferred to a constructor taking an argument - /// which would be preferred to a constructor taking an - /// argument which would in turn be preferred - /// to a constructor taking an argument. - ///

- ///

- /// All argument weights get accumulated. - ///

- ///
- /// - /// The argument s to match. - /// - /// The arguments to match. - /// The accumulated weight for all arguments. - public static int GetTypeDifferenceWeightOld(ParameterInfo[] argTypes, object[] args) - { - if (argTypes.Length != args.Length) - { - throw new ArgumentException("Cannot calculate the type difference weight for argument types and arguments with differing lengths."); - } - int result = 0; - for (int i = 0; i < argTypes.Length; i++) - { - Type theParameterType = argTypes[i].ParameterType; - if (!ObjectUtils.IsAssignable(theParameterType, args[i])) - { - return int.MaxValue; - } - if (args[i] != null && args[i].GetType() != theParameterType) - { - Type superType = args[i].GetType().BaseType; - while (superType != null) - { - if (theParameterType.IsAssignableFrom(superType)) - { - ++result; - superType = superType.BaseType; - } - else - { - superType = null; - } - } - } - } - return result; - } - - /// - /// Algorithm that judges the match between the declared parameter types of a candidate method - /// and a specific list of arguments that this method is supposed to be invoked with. - /// - /// - /// Determines a weight that represents the class hierarchy difference between types and - /// arguments. The following a an example based on the Java class hierarchy for Integer. - /// A direct match, i.e. type Integer -> arg of class Integer, does not increase - /// the result - all direct matches means weight 0. A match between type Object and arg of - /// class Integer would increase the weight by 2, due to the superclass 2 steps up in the - /// hierarchy (i.e. Object) being the last one that still matches the required type Object. - /// Type Number and class Integer would increase the weight by 1 accordingly, due to the - /// superclass 1 step up the hierarchy (i.e. Number) still matching the required type Number. - /// Therefore, with an arg of type Integer, a constructor (Integer) would be preferred to a - /// constructor (Number) which would in turn be preferred to a constructor (Object). - /// All argument weights get accumulated. - /// - /// The param types. - /// The args. - /// - public static int GetTypeDifferenceWeight(Type[] paramTypes, object[] args) + /// + /// Gets those s + /// that are applicable for autowiring the supplied . + /// + /// + /// The + /// (definition) that is being autowired by constructor. + /// + /// + /// The absolute minimum number of arguments that any returned constructor + /// must have. If this parameter is equal to zero (0), then all constructors + /// are valid (regardless of their argument count), including any default + /// constructor. + /// + /// + /// Those s + /// that are applicable for autowiring the supplied . + /// + public static ConstructorInfo[] GetConstructors( + IObjectDefinition definition, int minimumArgumentCount) + { + var rootObjectDefinition = definition as RootObjectDefinition; + if (minimumArgumentCount == 0 && rootObjectDefinition?.defaultConstructor != null) { - int result = 0; - for (int i = 0; i < (uint) paramTypes.Length; i++) + return rootObjectDefinition.defaultConstructor; + } + + const BindingFlags flags = + BindingFlags.Public + | BindingFlags.NonPublic + | BindingFlags.Instance + | BindingFlags.DeclaredOnly; + + ConstructorInfo[] constructors; + if (minimumArgumentCount > 0) + { + MemberInfo[] ctors = definition.ObjectType.FindMembers( + MemberTypes.Constructor, + flags, + new CriteriaMemberFilter().FilterMemberByCriteria, + new MinimumArgumentCountCriteria(minimumArgumentCount)); + constructors = (ConstructorInfo[]) ArrayList.Adapter(ctors).ToArray(typeof(ConstructorInfo)); + } + else + { + constructors = definition.ObjectType.GetConstructors(flags); + if (rootObjectDefinition != null) { - if (!ObjectUtils.IsAssignable(paramTypes[i], args[i])) + rootObjectDefinition.defaultConstructor = constructors; + } + } + + SortConstructors(constructors); + return constructors; + } + + /// + /// Determine a weight that represents the class hierarchy difference between types and + /// arguments. + /// + /// + ///

+ /// A direct match, i.e. type MyInteger -> arg of class MyInteger, does not increase + /// the result - all direct matches means weight zero (0). A match between the argument type + /// and a MyInteger instance argument would increase the weight by + /// 1, due to the superclass () being one (1) steps up in the + /// class hierarchy being the last one that still matches the required type. + ///

+ ///

+ /// Therefore, with an argument of type , a + /// constructor taking a argument would be + /// preferred to a constructor taking an argument + /// which would be preferred to a constructor taking an + /// argument which would in turn be preferred + /// to a constructor taking an argument. + ///

+ ///

+ /// All argument weights get accumulated. + ///

+ ///
+ /// + /// The argument s to match. + /// + /// The arguments to match. + /// The accumulated weight for all arguments. + public static int GetTypeDifferenceWeightOld(ParameterInfo[] argTypes, object[] args) + { + if (argTypes.Length != args.Length) + { + throw new ArgumentException("Cannot calculate the type difference weight for argument types and arguments with differing lengths."); + } + + int result = 0; + for (int i = 0; i < argTypes.Length; i++) + { + Type theParameterType = argTypes[i].ParameterType; + if (!ObjectUtils.IsAssignable(theParameterType, args[i])) + { + return int.MaxValue; + } + + if (args[i] != null && args[i].GetType() != theParameterType) + { + Type superType = args[i].GetType().BaseType; + while (superType != null) { - return int.MaxValue; - } - if (args[i] != null) - { - Type paramType = paramTypes[i]; - Type superType = args[i].GetType().BaseType; - while (superType != null) + if (theParameterType.IsAssignableFrom(superType)) { - if (paramType == superType) - { - result = result + 2; - superType = null; - } - if (paramType.IsAssignableFrom(superType)) - { - result = result + 2; - superType = superType.BaseType; - } - else - { - superType = null; - } + ++result; + superType = superType.BaseType; } - if (paramType.IsInterface) + else { - result = result + 1; + superType = null; } } } - return result; } - /// - /// Determines whether the given object property is excluded from dependency checks. - /// - /// The PropertyInfo of the object property. - /// - /// true if is excluded from dependency check; otherwise, false. - /// - public static Boolean IsExcludedFromDependencyCheck(PropertyInfo pi) + return result; + } + + /// + /// Algorithm that judges the match between the declared parameter types of a candidate method + /// and a specific list of arguments that this method is supposed to be invoked with. + /// + /// + /// Determines a weight that represents the class hierarchy difference between types and + /// arguments. The following a an example based on the Java class hierarchy for Integer. + /// A direct match, i.e. type Integer -> arg of class Integer, does not increase + /// the result - all direct matches means weight 0. A match between type Object and arg of + /// class Integer would increase the weight by 2, due to the superclass 2 steps up in the + /// hierarchy (i.e. Object) being the last one that still matches the required type Object. + /// Type Number and class Integer would increase the weight by 1 accordingly, due to the + /// superclass 1 step up the hierarchy (i.e. Number) still matching the required type Number. + /// Therefore, with an arg of type Integer, a constructor (Integer) would be preferred to a + /// constructor (Number) which would in turn be preferred to a constructor (Object). + /// All argument weights get accumulated. + /// + /// The param types. + /// The args. + /// + public static int GetTypeDifferenceWeight(Type[] paramTypes, object[] args) + { + int result = 0; + for (int i = 0; i < (uint) paramTypes.Length; i++) { - return pi.GetSetMethod() != null; - } - - /// - /// Sorts the supplied , preferring - /// public constructors and "greedy" ones (that have lots of arguments). - /// - /// - ///

- /// The result will contain public constructors first, with a decreasing number - /// of arguments, then non-public constructors, again with a decreasing number - /// of arguments. - ///

- ///
- /// - /// The array to be sorted. - /// - public static void SortConstructors(ConstructorInfo[] constructors) - { - if (constructors != null && constructors.Length > 1) - { - Array.Sort(constructors, ConstructorComparer.Instance); - } - } - - private sealed class ConstructorComparer : IComparer - { - internal static readonly ConstructorComparer Instance = new ConstructorComparer(); - - public int Compare(object lhs, object rhs) - { - ConstructorInfo lhsCtor = (ConstructorInfo) lhs; - ConstructorInfo rhsCtor = (ConstructorInfo) rhs; - if (lhsCtor.IsPublic != rhsCtor.IsPublic) - { - return (lhsCtor.IsPublic ? -1 : 1); - } - int lhsParams = lhsCtor.GetParameters().Length; - int rhsParams = rhsCtor.GetParameters().Length; - - if (lhsParams < rhsParams) - { - return 1; - } - else if (lhsParams > rhsParams) - { - return -1; - } - else - { - return 0; - } - } - } - - private sealed class MinimumArgumentCountCriteria : ICriteria - { - private readonly int _minimumArgumentCount; - - public MinimumArgumentCountCriteria(int minimumArgumentCount) - { - _minimumArgumentCount = minimumArgumentCount; - } - - public bool IsSatisfied(object datum) - { - return ((MethodBase) datum).GetParameters().Length >= _minimumArgumentCount; - } - } - - /// - /// Determines whether the setter property is defined in any of the given interfaces. - /// - /// The PropertyInfo of the object property - /// The ISet of interfaces. - /// - /// true if setter property is defined in interface; otherwise, false. - /// - public static bool IsSetterDefinedInInterface(PropertyInfo propertyInfo, ISet interfaces) - { - MethodInfo setter = propertyInfo.GetSetMethod(); - if (setter != null) + if (!ObjectUtils.IsAssignable(paramTypes[i], args[i])) { - Type targetType = setter.DeclaringType; - foreach (Type interfaceType in interfaces) + return int.MaxValue; + } + + if (args[i] != null) + { + Type paramType = paramTypes[i]; + Type superType = args[i].GetType().BaseType; + while (superType != null) { - if (interfaceType.IsAssignableFrom(targetType) && - ReflectionUtils.GetMethod(interfaceType, setter.Name, ReflectionUtils.GetParameterTypes(setter)) != null) + if (paramType == superType) { - return true; + result = result + 2; + superType = null; + } + + if (paramType.IsAssignableFrom(superType)) + { + result = result + 2; + superType = superType.BaseType; + } + else + { + superType = null; } } - } - return false; - } - /// - /// Creates the autowire candidate resolver. - /// - /// A SimpleAutowireCandidateResolver - public static IAutowireCandidateResolver CreateAutowireCandidateResolver() - { - return new QualifierAnnotationAutowireCandidateResolver(); - } - - /// - /// Returns the list of that are not satisfied by . - /// - /// the filtered list. Is never null - public static IList GetUnsatisfiedDependencies(IList propertyInfos, IPropertyValues properties, DependencyCheckingMode dependencyCheck) - { - List unsatisfiedDependenciesList = new List(); - foreach (PropertyInfo property in propertyInfos) - { - if (property.CanWrite && properties.GetPropertyValue(property.Name) == null) + if (paramType.IsInterface) { - bool isSimple = ObjectUtils.IsSimpleProperty(property.PropertyType); - bool unsatisfied = (dependencyCheck == DependencyCheckingMode.All) || (isSimple && dependencyCheck == DependencyCheckingMode.Simple) - || (!isSimple && dependencyCheck == DependencyCheckingMode.Objects); - if (unsatisfied) - { - unsatisfiedDependenciesList.Add(property); - } + result = result + 1; } } - return unsatisfiedDependenciesList; } - } + + return result; + } + + /// + /// Determines whether the given object property is excluded from dependency checks. + /// + /// The PropertyInfo of the object property. + /// + /// true if is excluded from dependency check; otherwise, false. + /// + public static Boolean IsExcludedFromDependencyCheck(PropertyInfo pi) + { + return pi.GetSetMethod() != null; + } + + /// + /// Sorts the supplied , preferring + /// public constructors and "greedy" ones (that have lots of arguments). + /// + /// + ///

+ /// The result will contain public constructors first, with a decreasing number + /// of arguments, then non-public constructors, again with a decreasing number + /// of arguments. + ///

+ ///
+ /// + /// The array to be sorted. + /// + public static void SortConstructors(ConstructorInfo[] constructors) + { + if (constructors != null && constructors.Length > 1) + { + Array.Sort(constructors, ConstructorComparer.Instance); + } + } + + private sealed class ConstructorComparer : IComparer + { + internal static readonly ConstructorComparer Instance = new ConstructorComparer(); + + public int Compare(object lhs, object rhs) + { + ConstructorInfo lhsCtor = (ConstructorInfo) lhs; + ConstructorInfo rhsCtor = (ConstructorInfo) rhs; + if (lhsCtor.IsPublic != rhsCtor.IsPublic) + { + return (lhsCtor.IsPublic ? -1 : 1); + } + + int lhsParams = lhsCtor.GetParameters().Length; + int rhsParams = rhsCtor.GetParameters().Length; + + if (lhsParams < rhsParams) + { + return 1; + } + else if (lhsParams > rhsParams) + { + return -1; + } + else + { + return 0; + } + } + } + + private sealed class MinimumArgumentCountCriteria : ICriteria + { + private readonly int _minimumArgumentCount; + + public MinimumArgumentCountCriteria(int minimumArgumentCount) + { + _minimumArgumentCount = minimumArgumentCount; + } + + public bool IsSatisfied(object datum) + { + return ((MethodBase) datum).GetParameters().Length >= _minimumArgumentCount; + } + } + + /// + /// Determines whether the setter property is defined in any of the given interfaces. + /// + /// The PropertyInfo of the object property + /// The ISet of interfaces. + /// + /// true if setter property is defined in interface; otherwise, false. + /// + public static bool IsSetterDefinedInInterface(PropertyInfo propertyInfo, ISet interfaces) + { + MethodInfo setter = propertyInfo.GetSetMethod(); + if (setter != null) + { + Type targetType = setter.DeclaringType; + foreach (Type interfaceType in interfaces) + { + if (interfaceType.IsAssignableFrom(targetType) && + ReflectionUtils.GetMethod(interfaceType, setter.Name, ReflectionUtils.GetParameterTypes(setter)) != null) + { + return true; + } + } + } + + return false; + } + + /// + /// Creates the autowire candidate resolver. + /// + /// A SimpleAutowireCandidateResolver + public static IAutowireCandidateResolver CreateAutowireCandidateResolver() + { + return new QualifierAnnotationAutowireCandidateResolver(); + } + + /// + /// Returns the list of that are not satisfied by . + /// + /// the filtered list. Is never null + public static IList GetUnsatisfiedDependencies(IList propertyInfos, IPropertyValues properties, DependencyCheckingMode dependencyCheck) + { + List unsatisfiedDependenciesList = new List(); + foreach (PropertyInfo property in propertyInfos) + { + if (property.CanWrite && properties.GetPropertyValue(property.Name) == null) + { + bool isSimple = ObjectUtils.IsSimpleProperty(property.PropertyType); + bool unsatisfied = (dependencyCheck == DependencyCheckingMode.All) || (isSimple && dependencyCheck == DependencyCheckingMode.Simple) + || (!isSimple && dependencyCheck == DependencyCheckingMode.Objects); + if (unsatisfied) + { + unsatisfiedDependenciesList.Add(property); + } + } + } + + return unsatisfiedDependenciesList; + } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/ChildObjectDefinition.cs b/src/Spring/Spring.Core/Objects/Factory/Support/ChildObjectDefinition.cs index 28f5b1f4..c652cbc4 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/ChildObjectDefinition.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/ChildObjectDefinition.cs @@ -18,212 +18,211 @@ using System.Text; using Spring.Objects.Factory.Config; using Spring.Util; -namespace Spring.Objects.Factory.Support +namespace Spring.Objects.Factory.Support; + +/// +/// Object definition for definitions that inherit settings from their +/// parent (object definition). +/// +/// +///

+/// Will use the +/// of the parent object definition if none is specified, but can also +/// override it. In the latter case, the child's +/// +/// must be compatible with the parent, i.e. accept the parent's property values +/// and constructor argument values (if any). +///

+///

+/// A will +/// inherit all of the , +/// , and +/// from it's parent +/// object definition, with the option to add new values. If the +/// , +/// , +/// and / or +/// +/// properties are specified, they will override the corresponding parent settings. +///

+///

+/// The remaining settings will always be taken from the child definition: +/// , +/// , +/// , +/// , +/// and +/// +///

+///
+/// Rod Johnson +/// Juergen Hoeller +/// Rick Evans (.NET) +/// +[Serializable] +public class ChildObjectDefinition : AbstractObjectDefinition { /// - /// Object definition for definitions that inherit settings from their - /// parent (object definition). + /// Creates a new instance of the + /// + /// class. + /// + /// + /// The name of the parent object. + /// + public ChildObjectDefinition(string parentName) + { + this.parentName = parentName; + } + + /// + /// Creates a new instance of the + /// + /// class. + /// + /// + /// The name of the parent object. + /// + /// + /// The additional property values (if any) of the child. + /// + public ChildObjectDefinition(string parentName, MutablePropertyValues properties) + : base(null, properties) + { + this.parentName = parentName; + } + + /// + /// Creates a new instance of the + /// + /// class. + /// + /// + /// The name of the parent object. + /// + /// + /// The + /// to be applied to a new instance of the object. + /// + /// + /// The additional property values (if any) of the child. + /// + public ChildObjectDefinition( + string parentName, ConstructorArgumentValues arguments, MutablePropertyValues properties) + : base(arguments, properties) + { + this.parentName = parentName; + } + + /// + /// Creates a new instance of the + /// + /// class. + /// + /// + /// The name of the parent object. + /// + /// + /// The class of the object to instantiate. + /// + /// + /// The + /// to be applied to a new instance of the object. + /// + /// + /// The additional property values (if any) of the child. + /// + public ChildObjectDefinition( + string parentName, Type type, ConstructorArgumentValues arguments, MutablePropertyValues properties) + : base(arguments, properties) + { + this.parentName = parentName; + ObjectType = type; + } + + /// + /// Creates a new instance of the + /// + /// class. + /// + /// + /// The name of the parent object. + /// + /// + /// The of the object to + /// instantiate. + /// + /// + /// The + /// to be applied to a new instance of the object. + /// + /// + /// The additional property values (if any) of the child. + /// + public ChildObjectDefinition( + string parentName, string typeName, ConstructorArgumentValues arguments, MutablePropertyValues properties) + : base(arguments, properties) + { + this.parentName = parentName; + ObjectTypeName = typeName; + } + + /// + /// The name of the parent object definition. + /// + /// + /// This value is required. + /// + /// + /// The name of the parent object definition. + /// + public override string ParentName + { + get { return parentName; } + set { parentName = value; } + } + + /// + /// Validate this object definition. /// /// ///

- /// Will use the - /// of the parent object definition if none is specified, but can also - /// override it. In the latter case, the child's - /// - /// must be compatible with the parent, i.e. accept the parent's property values - /// and constructor argument values (if any). - ///

- ///

- /// A will - /// inherit all of the , - /// , and - /// from it's parent - /// object definition, with the option to add new values. If the - /// , - /// , - /// and / or - /// - /// properties are specified, they will override the corresponding parent settings. - ///

- ///

- /// The remaining settings will always be taken from the child definition: - /// , - /// , - /// , - /// , - /// and - /// + /// A common cause of validation failures is a missing value for the + /// + /// property; by + /// their very nature require that the + /// + /// be set. ///

///
- /// Rod Johnson - /// Juergen Hoeller - /// Rick Evans (.NET) - /// - [Serializable] - public class ChildObjectDefinition : AbstractObjectDefinition + /// + /// In the case of a validation failure. + /// + public override void Validate() { - /// - /// Creates a new instance of the - /// - /// class. - /// - /// - /// The name of the parent object. - /// - public ChildObjectDefinition(string parentName) + base.Validate(); + if (StringUtils.IsNullOrEmpty(parentName)) { - this.parentName = parentName; + throw new ObjectDefinitionValidationException( + "The 'ParentName' property must be set in ChildObjectDefinition."); } - - /// - /// Creates a new instance of the - /// - /// class. - /// - /// - /// The name of the parent object. - /// - /// - /// The additional property values (if any) of the child. - /// - public ChildObjectDefinition(string parentName, MutablePropertyValues properties) - : base(null, properties) - { - this.parentName = parentName; - } - - /// - /// Creates a new instance of the - /// - /// class. - /// - /// - /// The name of the parent object. - /// - /// - /// The - /// to be applied to a new instance of the object. - /// - /// - /// The additional property values (if any) of the child. - /// - public ChildObjectDefinition( - string parentName, ConstructorArgumentValues arguments, MutablePropertyValues properties) - : base(arguments, properties) - { - this.parentName = parentName; - } - - /// - /// Creates a new instance of the - /// - /// class. - /// - /// - /// The name of the parent object. - /// - /// - /// The class of the object to instantiate. - /// - /// - /// The - /// to be applied to a new instance of the object. - /// - /// - /// The additional property values (if any) of the child. - /// - public ChildObjectDefinition( - string parentName, Type type, ConstructorArgumentValues arguments, MutablePropertyValues properties) - : base(arguments, properties) - { - this.parentName = parentName; - ObjectType = type; - } - - /// - /// Creates a new instance of the - /// - /// class. - /// - /// - /// The name of the parent object. - /// - /// - /// The of the object to - /// instantiate. - /// - /// - /// The - /// to be applied to a new instance of the object. - /// - /// - /// The additional property values (if any) of the child. - /// - public ChildObjectDefinition( - string parentName, string typeName, ConstructorArgumentValues arguments, MutablePropertyValues properties) - : base(arguments, properties) - { - this.parentName = parentName; - ObjectTypeName = typeName; - } - - /// - /// The name of the parent object definition. - /// - /// - /// This value is required. - /// - /// - /// The name of the parent object definition. - /// - public override string ParentName - { - get { return parentName; } - set { parentName = value; } - } - - /// - /// Validate this object definition. - /// - /// - ///

- /// A common cause of validation failures is a missing value for the - /// - /// property; by - /// their very nature require that the - /// - /// be set. - ///

- ///
- /// - /// In the case of a validation failure. - /// - public override void Validate() - { - base.Validate(); - if (StringUtils.IsNullOrEmpty(parentName)) - { - throw new ObjectDefinitionValidationException( - "The 'ParentName' property must be set in ChildObjectDefinition."); - } - } - - /// - /// A that represents the current - /// . - /// - /// - /// A that represents the current - /// . - /// - public override string ToString() - { - StringBuilder buffer = new StringBuilder(); - buffer.Append(GetType().Name).Append(" with parent '"); - buffer.Append(ParentName).Append("' : ").Append(base.ToString()); - return buffer.ToString(); - } - - private string parentName; } + + /// + /// A that represents the current + /// . + /// + /// + /// A that represents the current + /// . + /// + public override string ToString() + { + StringBuilder buffer = new StringBuilder(); + buffer.Append(GetType().Name).Append(" with parent '"); + buffer.Append(ParentName).Append("' : ").Append(base.ToString()); + return buffer.ToString(); + } + + private string parentName; } diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/ConstructorResolver.cs b/src/Spring/Spring.Core/Objects/Factory/Support/ConstructorResolver.cs index 2dba0a26..372e0cee 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/ConstructorResolver.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/ConstructorResolver.cs @@ -23,660 +23,663 @@ using Spring.Core.TypeResolution; using Spring.Objects.Factory.Config; using Spring.Util; -namespace Spring.Objects.Factory.Support +namespace Spring.Objects.Factory.Support; + +/// +/// Helper class for resolving constructors and factory methods. +/// Performs constructor resolution through argument matching. +/// +/// +/// Operates on a and an . +/// Used by . +/// +/// Juergen Hoeller +/// Mark Pollack +public class ConstructorResolver { + private readonly ILogger log = LogManager.GetLogger(); + + private readonly AbstractObjectFactory objectFactory; + + private readonly IAutowireCapableObjectFactory autowireFactory; + + private readonly IInstantiationStrategy instantiationStrategy; + private readonly ObjectDefinitionValueResolver valueResolver; + /// - /// Helper class for resolving constructors and factory methods. - /// Performs constructor resolution through argument matching. + /// Initializes a new instance of the class for the given factory + /// and instantiation strategy. /// - /// - /// Operates on a and an . - /// Used by . - /// - /// Juergen Hoeller - /// Mark Pollack - public class ConstructorResolver + /// The object factory to work with. + /// The object factory as IAutowireCapableObjectFactory. + /// The instantiation strategy for creating objects. + /// the resolver to resolve property value placeholders if any + public ConstructorResolver(AbstractObjectFactory objectFactory, IAutowireCapableObjectFactory autowireFactory, + IInstantiationStrategy instantiationStrategy, ObjectDefinitionValueResolver valueResolver) { - private readonly ILogger log = LogManager.GetLogger(); + this.objectFactory = objectFactory; + this.autowireFactory = autowireFactory; + this.instantiationStrategy = instantiationStrategy; + this.valueResolver = valueResolver; + } - private readonly AbstractObjectFactory objectFactory; + /// + /// "autowire constructor" (with constructor arguments by type) behavior. + /// Also applied if explicit constructor argument values are specified, + /// matching all remaining arguments with objects from the object factory. + /// + /// + /// This corresponds to constructor injection: In this mode, a Spring + /// object factory is able to host components that expect constructor-based + /// dependency resolution. + /// + /// Name of the object. + /// The merged object definition for the object. + /// The chosen chosen candidate constructors (or null if none). + /// The explicit argument values passed in programmatically via the getBean method, + /// or null if none (-> use constructor argument values from object definition) + /// An IObjectWrapper for the new instance + public IObjectWrapper AutowireConstructor(string objectName, RootObjectDefinition rod, + ConstructorInfo[] chosenCtors, object[] explicitArgs) + { + ObjectWrapper wrapper = new ObjectWrapper(); - private readonly IAutowireCapableObjectFactory autowireFactory; + ConstructorInstantiationInfo constructorInstantiationInfo = GetConstructorInstantiationInfo( + objectName, rod, chosenCtors, explicitArgs); - private readonly IInstantiationStrategy instantiationStrategy; - private readonly ObjectDefinitionValueResolver valueResolver; + wrapper.WrappedInstance = instantiationStrategy.Instantiate(rod, objectName, objectFactory, + constructorInstantiationInfo.ConstructorInfo, constructorInstantiationInfo.ArgInstances); - /// - /// Initializes a new instance of the class for the given factory - /// and instantiation strategy. - /// - /// The object factory to work with. - /// The object factory as IAutowireCapableObjectFactory. - /// The instantiation strategy for creating objects. - /// the resolver to resolve property value placeholders if any - public ConstructorResolver(AbstractObjectFactory objectFactory, IAutowireCapableObjectFactory autowireFactory, - IInstantiationStrategy instantiationStrategy, ObjectDefinitionValueResolver valueResolver) + if (log.IsEnabled(LogLevel.Debug)) { - this.objectFactory = objectFactory; - this.autowireFactory = autowireFactory; - this.instantiationStrategy = instantiationStrategy; - this.valueResolver = valueResolver; + log.LogDebug($"Object '{objectName}' instantiated via constructor [{constructorInstantiationInfo.ConstructorInfo}]."); } - /// - /// "autowire constructor" (with constructor arguments by type) behavior. - /// Also applied if explicit constructor argument values are specified, - /// matching all remaining arguments with objects from the object factory. - /// - /// - /// This corresponds to constructor injection: In this mode, a Spring - /// object factory is able to host components that expect constructor-based - /// dependency resolution. - /// - /// Name of the object. - /// The merged object definition for the object. - /// The chosen chosen candidate constructors (or null if none). - /// The explicit argument values passed in programmatically via the getBean method, - /// or null if none (-> use constructor argument values from object definition) - /// An IObjectWrapper for the new instance - public IObjectWrapper AutowireConstructor(string objectName, RootObjectDefinition rod, - ConstructorInfo[] chosenCtors, object[] explicitArgs) + return wrapper; + } + + /// + /// Gets the constructor instantiation info given the object definition. + /// + /// Name of the object. + /// The RootObjectDefinition + /// The explicitly chosen ctors. + /// The explicit chose ctor args. + /// A ConstructorInstantiationInfo containg the specified constructor in the RootObjectDefinition or + /// one based on type matching. + public ConstructorInstantiationInfo GetConstructorInstantiationInfo( + string objectName, + RootObjectDefinition rod, + ConstructorInfo[] chosenConstructors, + object[] explicitArgs) + { + object[] argsToUse = null; + + if (explicitArgs != null) { + argsToUse = explicitArgs; + } + else + { + //TODO performance optmization on cached ctors. + } - ObjectWrapper wrapper = new ObjectWrapper(); + // Need to resolve the constructor. + bool autowiring = chosenConstructors != null || rod.ResolvedAutowireMode == AutoWiringMode.Constructor; + ConstructorArgumentValues resolvedValues = null; + ObjectWrapper wrapper = null; + ConstructorInfo constructorToUse = null; - ConstructorInstantiationInfo constructorInstantiationInfo = GetConstructorInstantiationInfo( - objectName, rod, chosenCtors, explicitArgs); + int minNrOfArgs; + if (explicitArgs != null) + { + minNrOfArgs = explicitArgs.Length; + } + else + { + ConstructorArgumentValues cargs = rod.ConstructorArgumentValues; + resolvedValues = new ConstructorArgumentValues(); + wrapper = new ObjectWrapper(); + minNrOfArgs = ResolveConstructorArguments(objectName, rod, wrapper, cargs, resolvedValues); + } - wrapper.WrappedInstance = instantiationStrategy.Instantiate(rod, objectName, objectFactory, - constructorInstantiationInfo.ConstructorInfo, constructorInstantiationInfo.ArgInstances); + // Take specified constructors, if any. + ConstructorInfo[] candidates = chosenConstructors ?? AutowireUtils.GetConstructors(rod, 0); + AutowireUtils.SortConstructors(candidates); + int minTypeDiffWeight = int.MaxValue; + + for (int i = 0; i < candidates.Length; i++) + { + ConstructorInfo candidate = candidates[i]; + var parameters = candidate.GetParameters(); + if (constructorToUse != null && argsToUse.Length > parameters.Length) + { + // already found greedy constructor that can be satisfied, so + // don't look any further, there are only less greedy constructors left... + break; + } + + if (parameters.Length < minNrOfArgs) + { + throw new ObjectCreationException(rod.ResourceDescription, objectName, + $"'{minNrOfArgs}' constructor arguments specified but no matching constructor found " + + $"in object '{objectName}' (hint: specify argument indexes, names, or " + + "types to avoid ambiguities)."); + } + + Type[] paramTypes = ReflectionUtils.GetParameterTypes(parameters); + ArgumentsHolder args; + if (resolvedValues != null) + { + // Try to resolve arguments for current constructor + + //need to check for null as indicator of no ctor arg match instead of using exceptions for flow + //control as in the Java implementation + args = CreateArgumentArray( + objectName, + rod, + resolvedValues, + wrapper, + paramTypes, + candidate, + autowiring, + out var unsatisfiedDependencyExceptionData); + + if (args == null) + { + if (i == candidates.Length - 1 && constructorToUse == null) + { + throw new UnsatisfiedDependencyException(rod.ResourceDescription, + objectName, + unsatisfiedDependencyExceptionData.ParameterIndex, + unsatisfiedDependencyExceptionData.ParameterType, + unsatisfiedDependencyExceptionData.ErrorMessage); + } + + // try next constructor... + continue; + } + } + else + { + // Explicit arguments given -> arguments length must match exactly + if (parameters.Length != explicitArgs.Length) + { + continue; + } + + args = ArgumentsHolder.Create(explicitArgs); + } + + int typeDiffWeight = args.GetTypeDifferenceWeight(paramTypes); + // Choose this constructor if it represents the closest match. + if (typeDiffWeight < minTypeDiffWeight) + { + constructorToUse = candidate; + argsToUse = args.arguments; + minTypeDiffWeight = typeDiffWeight; + } + } + + if (constructorToUse == null) + { + throw new ObjectCreationException(rod.ResourceDescription, objectName, "Could not resolve matching constructor."); + } + + return new ConstructorInstantiationInfo(constructorToUse, argsToUse); + } + + /// + /// Instantiate an object instance using a named factory method. + /// + /// + ///

+ /// The method may be static, if the + /// parameter specifies a class, rather than a + /// instance, or an + /// instance variable on a factory object itself configured using Dependency + /// Injection. + ///

+ ///

+ /// Implementation requires iterating over the static or instance methods + /// with the name specified in the supplied + /// (the method may be overloaded) and trying to match with the parameters. + /// We don't have the types attached to constructor args, so trial and error + /// is the only way to go here. + ///

+ ///
+ /// + /// The name associated with the supplied . + /// + /// + /// The definition describing the instance that is to be instantiated. + /// + /// + /// Any arguments to the factory method that is to be invoked. + /// + /// + /// The result of the factory method invocation (the instance). + /// + public virtual IObjectWrapper InstantiateUsingFactoryMethod(string name, RootObjectDefinition definition, object[] arguments) + { + ObjectWrapper wrapper = new ObjectWrapper(); + Type factoryClass = null; + bool isStatic = true; + + ConstructorArgumentValues cargs = definition.ConstructorArgumentValues; + ConstructorArgumentValues resolvedValues = new ConstructorArgumentValues(); + int expectedArgCount = 0; + + // we don't have arguments passed in programmatically, so we need to resolve the + // arguments specified in the constructor arguments held in the object definition... + if (arguments == null || arguments.Length == 0) + { + expectedArgCount = cargs.ArgumentCount; + ResolveConstructorArguments(name, definition, wrapper, cargs, resolvedValues); + } + else + { + // if we have constructor args, don't need to resolve them... + expectedArgCount = arguments.Length; + } + + if (StringUtils.HasText(definition.FactoryObjectName)) + { + // it's an instance method on the factory object's class... + factoryClass = objectFactory.GetObject(definition.FactoryObjectName).GetType(); + isStatic = false; + } + else + { + // it's a static factory method on the object class... + factoryClass = definition.ObjectType; + } + + GenericArgumentsHolder genericArgsInfo = new GenericArgumentsHolder(definition.FactoryMethodName); + IList factoryMethodCandidates = FindMethods(genericArgsInfo.GenericMethodName, expectedArgCount, isStatic, factoryClass); + + bool autowiring = (definition.AutowireMode == AutoWiringMode.Constructor); + + // try all matching methods to see if they match the constructor arguments... + for (int i = 0; i < factoryMethodCandidates.Count; i++) + { + MethodInfo factoryMethodCandidate = factoryMethodCandidates[i]; + if (genericArgsInfo.ContainsGenericArguments) + { + string[] unresolvedGenericArgs = genericArgsInfo.GetGenericArguments(); + if (factoryMethodCandidate.GetGenericArguments().Length != unresolvedGenericArgs.Length) + continue; + + Type[] paramTypes = new Type[unresolvedGenericArgs.Length]; + for (int j = 0; j < unresolvedGenericArgs.Length; j++) + { + paramTypes[j] = TypeResolutionUtils.ResolveType(unresolvedGenericArgs[j]); + } + + factoryMethodCandidate = factoryMethodCandidate.MakeGenericMethod(paramTypes); + } + + if (arguments == null || arguments.Length == 0) + { + Type[] paramTypes = ReflectionUtils.GetParameterTypes(factoryMethodCandidate.GetParameters()); + // try to create the required arguments... + UnsatisfiedDependencyExceptionData unsatisfiedDependencyExceptionData = null; + ArgumentsHolder args = CreateArgumentArray(name, definition, resolvedValues, wrapper, paramTypes, + factoryMethodCandidate, autowiring, out unsatisfiedDependencyExceptionData); + if (args == null) + { + arguments = null; + // if we failed to match this method, keep + // trying new overloaded factory methods... + continue; + } + else + { + arguments = args.arguments; + } + } + + // if we get here, we found a usable candidate factory method - check, if arguments match + //arguments = (arguments.Length == 0 ? null : arguments); + if (ReflectionUtils.GetMethodByArgumentValues(new MethodInfo[] { factoryMethodCandidate }, arguments) == null) + { + continue; + } + + object objectInstance = instantiationStrategy.Instantiate(definition, name, objectFactory, factoryMethodCandidate, arguments); + wrapper.WrappedInstance = objectInstance; if (log.IsEnabled(LogLevel.Debug)) { - log.LogDebug($"Object '{objectName}' instantiated via constructor [{constructorInstantiationInfo.ConstructorInfo}]."); + log.LogDebug($"Object '{name}' instantiated via factory method [{factoryMethodCandidate}]."); } return wrapper; } + // if we get here, we didn't match any method... + throw new ObjectDefinitionStoreException( + $"Cannot find matching factory method '{definition.FactoryMethodName} on Type [{factoryClass}]."); + } - /// - /// Gets the constructor instantiation info given the object definition. - /// - /// Name of the object. - /// The RootObjectDefinition - /// The explicitly chosen ctors. - /// The explicit chose ctor args. - /// A ConstructorInstantiationInfo containg the specified constructor in the RootObjectDefinition or - /// one based on type matching. - public ConstructorInstantiationInfo GetConstructorInstantiationInfo( - string objectName, - RootObjectDefinition rod, - ConstructorInfo[] chosenConstructors, - object[] explicitArgs) + /// + /// Create an array of arguments to invoke a constructor or static factory method, + /// given the resolved constructor arguments values. + /// + /// When return value is null the out parameter UnsatisfiedDependencyExceptionData will contain + /// information for use in throwing a UnsatisfiedDependencyException by the caller. This avoids using + /// exceptions for flow control as in the original implementation. + private ArgumentsHolder CreateArgumentArray( + string objectName, + RootObjectDefinition rod, + ConstructorArgumentValues resolvedValues, + ObjectWrapper wrapper, + Type[] paramTypes, + MethodBase methodOrCtorInfo, + bool autowiring, + out UnsatisfiedDependencyExceptionData unsatisfiedDependencyExceptionData) + { + string GetMethodType() { - object[] argsToUse = null; + return methodOrCtorInfo is ConstructorInfo ? "constructor" : "factory method"; + } - if (explicitArgs != null) + unsatisfiedDependencyExceptionData = null; + if (paramTypes.Length == 0) + { + return ArgumentsHolder.Empty; + } + + ArgumentsHolder args = new ArgumentsHolder(paramTypes.Length); + var usedValueHolders = new HybridSet(); + List autowiredObjectNames = null; + + ParameterInfo[] argTypes = methodOrCtorInfo.GetParameters(); + + for (int paramIndex = 0; paramIndex < paramTypes.Length; paramIndex++) + { + Type paramType = paramTypes[paramIndex]; + + string parameterName = argTypes[paramIndex].Name; + // If we couldn't find a direct match and are not supposed to autowire, + // let's try the next generic, untyped argument value as fallback: + // it could match after type conversion (for example, String -> int). + ConstructorArgumentValues.ValueHolder valueHolder = null; + if (resolvedValues.GetNamedArgumentValue(parameterName) != null) { - argsToUse = explicitArgs; + valueHolder = resolvedValues.GetArgumentValue(parameterName, paramType, usedValueHolders); } else { - //TODO performance optmization on cached ctors. + valueHolder = resolvedValues.GetArgumentValue(paramIndex, paramType, usedValueHolders); } - // Need to resolve the constructor. - bool autowiring = chosenConstructors != null || rod.ResolvedAutowireMode == AutoWiringMode.Constructor; - ConstructorArgumentValues resolvedValues = null; - ObjectWrapper wrapper = null; - ConstructorInfo constructorToUse = null; - - int minNrOfArgs; - if (explicitArgs != null) + if (valueHolder == null && !autowiring) { - minNrOfArgs = explicitArgs.Length; + valueHolder = resolvedValues.GetGenericArgumentValue(null, usedValueHolders); + } + + if (valueHolder != null) + { + // We found a potential match - let's give it a try. + // Do not consider the same value definition multiple times! + usedValueHolders.Add(valueHolder); + args.rawArguments[paramIndex] = valueHolder.Value; + try + { + object originalValue = valueHolder.Value; + object convertedValue = TypeConversionUtils.ConvertValueIfNecessary(paramType, originalValue, null); + args.arguments[paramIndex] = convertedValue; + + //? + args.preparedArguments[paramIndex] = convertedValue; + } + catch (TypeMismatchException ex) + { + // to avoid using exceptions for flow control, this is not a cost in Java as stack trace is lazily created. + string errorMessage = $"Could not convert {GetMethodType()} argument value [{valueHolder.Value}] to required type [{paramType}] : {ex.Message}"; + unsatisfiedDependencyExceptionData = new UnsatisfiedDependencyExceptionData(paramIndex, paramType, errorMessage); + return null; + } } else { - ConstructorArgumentValues cargs = rod.ConstructorArgumentValues; - resolvedValues = new ConstructorArgumentValues(); - wrapper = new ObjectWrapper(); - minNrOfArgs = ResolveConstructorArguments(objectName, rod, wrapper, cargs, resolvedValues); - } - // Take specified constructors, if any. - ConstructorInfo[] candidates = chosenConstructors ?? AutowireUtils.GetConstructors(rod, 0); - AutowireUtils.SortConstructors(candidates); - int minTypeDiffWeight = int.MaxValue; + // No explicit match found: we're either supposed to autowire or + // have to fail creating an argument array for the given constructor. + if (!autowiring) + { + string errorMessage = $"Ambiguous {GetMethodType()} argument types - " + + $"Did you specify the correct object references as {GetMethodType()} arguments?"; + unsatisfiedDependencyExceptionData = new UnsatisfiedDependencyExceptionData(paramIndex, paramType, errorMessage); - for (int i = 0; i < candidates.Length; i++) - { - ConstructorInfo candidate = candidates[i]; - var parameters = candidate.GetParameters(); - if (constructorToUse != null && argsToUse.Length > parameters.Length) - { - // already found greedy constructor that can be satisfied, so - // don't look any further, there are only less greedy constructors left... - break; - } - if (parameters.Length < minNrOfArgs) - { - throw new ObjectCreationException(rod.ResourceDescription, objectName, - $"'{minNrOfArgs}' constructor arguments specified but no matching constructor found " + - $"in object '{objectName}' (hint: specify argument indexes, names, or " + - "types to avoid ambiguities)."); + return null; } - Type[] paramTypes = ReflectionUtils.GetParameterTypes(parameters); - ArgumentsHolder args; - if (resolvedValues != null) + try { - // Try to resolve arguments for current constructor - - //need to check for null as indicator of no ctor arg match instead of using exceptions for flow - //control as in the Java implementation - args = CreateArgumentArray( - objectName, - rod, - resolvedValues, - wrapper, - paramTypes, - candidate, - autowiring, - out var unsatisfiedDependencyExceptionData); - - if (args == null) - { - if (i == candidates.Length - 1 && constructorToUse == null) - { - throw new UnsatisfiedDependencyException(rod.ResourceDescription, - objectName, - unsatisfiedDependencyExceptionData.ParameterIndex, - unsatisfiedDependencyExceptionData.ParameterType, - unsatisfiedDependencyExceptionData.ErrorMessage); - } - // try next constructor... - continue; - } + MethodParameter param = MethodParameter.ForMethodOrConstructor(methodOrCtorInfo, paramIndex); + autowiredObjectNames = new List(); + object autowiredArgument = ResolveAutoWiredArgument(param, objectName, autowiredObjectNames); + args.rawArguments[paramIndex] = autowiredArgument; + args.arguments[paramIndex] = autowiredArgument; + args.preparedArguments[paramIndex] = new AutowiredArgumentMarker(); } - else + catch (ObjectsException ex) { - // Explicit arguments given -> arguments length must match exactly - if (parameters.Length != explicitArgs.Length) - { - continue; - } - args = ArgumentsHolder.Create(explicitArgs); - } - int typeDiffWeight = args.GetTypeDifferenceWeight(paramTypes); - // Choose this constructor if it represents the closest match. - if (typeDiffWeight < minTypeDiffWeight) - { - constructorToUse = candidate; - argsToUse = args.arguments; - minTypeDiffWeight = typeDiffWeight; + unsatisfiedDependencyExceptionData = new UnsatisfiedDependencyExceptionData(paramIndex, paramType, ex.Message); + + return null; } } - - if (constructorToUse == null) - { - throw new ObjectCreationException(rod.ResourceDescription, objectName, "Could not resolve matching constructor."); - } - - return new ConstructorInstantiationInfo(constructorToUse, argsToUse); } - /// - /// Instantiate an object instance using a named factory method. - /// - /// - ///

- /// The method may be static, if the - /// parameter specifies a class, rather than a - /// instance, or an - /// instance variable on a factory object itself configured using Dependency - /// Injection. - ///

- ///

- /// Implementation requires iterating over the static or instance methods - /// with the name specified in the supplied - /// (the method may be overloaded) and trying to match with the parameters. - /// We don't have the types attached to constructor args, so trial and error - /// is the only way to go here. - ///

- ///
- /// - /// The name associated with the supplied . - /// - /// - /// The definition describing the instance that is to be instantiated. - /// - /// - /// Any arguments to the factory method that is to be invoked. - /// - /// - /// The result of the factory method invocation (the instance). - /// - public virtual IObjectWrapper InstantiateUsingFactoryMethod(string name, RootObjectDefinition definition, object[] arguments) + if (log.IsEnabled(LogLevel.Debug) && autowiredObjectNames != null) { - ObjectWrapper wrapper = new ObjectWrapper(); - Type factoryClass = null; - bool isStatic = true; - - - ConstructorArgumentValues cargs = definition.ConstructorArgumentValues; - ConstructorArgumentValues resolvedValues = new ConstructorArgumentValues(); - int expectedArgCount = 0; - - // we don't have arguments passed in programmatically, so we need to resolve the - // arguments specified in the constructor arguments held in the object definition... - if (arguments == null || arguments.Length == 0) + for (var i = 0; i < autowiredObjectNames.Count; i++) { - expectedArgCount = cargs.ArgumentCount; - ResolveConstructorArguments(name, definition, wrapper, cargs, resolvedValues); + string autowiredObjectName = autowiredObjectNames[i]; + log.LogDebug($"Autowiring by type from object name '{objectName}' via {GetMethodType()} to object named '{autowiredObjectName}'"); } - else - { - // if we have constructor args, don't need to resolve them... - expectedArgCount = arguments.Length; - } - - - if (StringUtils.HasText(definition.FactoryObjectName)) - { - // it's an instance method on the factory object's class... - factoryClass = objectFactory.GetObject(definition.FactoryObjectName).GetType(); - isStatic = false; - } - else - { - // it's a static factory method on the object class... - factoryClass = definition.ObjectType; - } - - GenericArgumentsHolder genericArgsInfo = new GenericArgumentsHolder(definition.FactoryMethodName); - IList factoryMethodCandidates = FindMethods(genericArgsInfo.GenericMethodName, expectedArgCount, isStatic, factoryClass); - - bool autowiring = (definition.AutowireMode == AutoWiringMode.Constructor); - - // try all matching methods to see if they match the constructor arguments... - for (int i = 0; i < factoryMethodCandidates.Count; i++) - { - MethodInfo factoryMethodCandidate = factoryMethodCandidates[i]; - if (genericArgsInfo.ContainsGenericArguments) - { - string[] unresolvedGenericArgs = genericArgsInfo.GetGenericArguments(); - if (factoryMethodCandidate.GetGenericArguments().Length != unresolvedGenericArgs.Length) - continue; - - Type[] paramTypes = new Type[unresolvedGenericArgs.Length]; - for (int j = 0; j < unresolvedGenericArgs.Length; j++) - { - paramTypes[j] = TypeResolutionUtils.ResolveType(unresolvedGenericArgs[j]); - } - factoryMethodCandidate = factoryMethodCandidate.MakeGenericMethod(paramTypes); - } - if (arguments == null || arguments.Length == 0) - { - Type[] paramTypes = ReflectionUtils.GetParameterTypes(factoryMethodCandidate.GetParameters()); - // try to create the required arguments... - UnsatisfiedDependencyExceptionData unsatisfiedDependencyExceptionData = null; - ArgumentsHolder args = CreateArgumentArray(name, definition, resolvedValues, wrapper, paramTypes, - factoryMethodCandidate, autowiring, out unsatisfiedDependencyExceptionData); - if (args == null) - { - arguments = null; - // if we failed to match this method, keep - // trying new overloaded factory methods... - continue; - } - else - { - arguments = args.arguments; - } - } - - // if we get here, we found a usable candidate factory method - check, if arguments match - //arguments = (arguments.Length == 0 ? null : arguments); - if (ReflectionUtils.GetMethodByArgumentValues(new MethodInfo[] { factoryMethodCandidate }, arguments) == null) - { - continue; - } - - object objectInstance = instantiationStrategy.Instantiate(definition, name, objectFactory, factoryMethodCandidate, arguments); - wrapper.WrappedInstance = objectInstance; - - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug($"Object '{name}' instantiated via factory method [{factoryMethodCandidate}]."); - } - - return wrapper; - } - - - - // if we get here, we didn't match any method... - throw new ObjectDefinitionStoreException( - $"Cannot find matching factory method '{definition.FactoryMethodName} on Type [{factoryClass}]."); } - /// - /// Create an array of arguments to invoke a constructor or static factory method, - /// given the resolved constructor arguments values. - /// - /// When return value is null the out parameter UnsatisfiedDependencyExceptionData will contain - /// information for use in throwing a UnsatisfiedDependencyException by the caller. This avoids using - /// exceptions for flow control as in the original implementation. - private ArgumentsHolder CreateArgumentArray( - string objectName, - RootObjectDefinition rod, - ConstructorArgumentValues resolvedValues, - ObjectWrapper wrapper, - Type[] paramTypes, - MethodBase methodOrCtorInfo, - bool autowiring, - out UnsatisfiedDependencyExceptionData unsatisfiedDependencyExceptionData) - { - string GetMethodType() - { - return methodOrCtorInfo is ConstructorInfo ? "constructor" : "factory method"; - } + return args; + } - unsatisfiedDependencyExceptionData = null; - if (paramTypes.Length == 0) - { - return ArgumentsHolder.Empty; - } + private class AutowiredArgumentMarker + { + } - ArgumentsHolder args = new ArgumentsHolder(paramTypes.Length); - var usedValueHolders = new HybridSet(); - List autowiredObjectNames = null; + private object ResolveAutoWiredArgument( + MethodParameter methodParameter, + string objectName, + List autowiredObjectNames) + { + return autowireFactory.ResolveDependency( + new DependencyDescriptor(methodParameter, true), + objectName, + autowiredObjectNames); + } - ParameterInfo[] argTypes = methodOrCtorInfo.GetParameters(); - - for (int paramIndex = 0; paramIndex < paramTypes.Length; paramIndex++) - { - Type paramType = paramTypes[paramIndex]; - - string parameterName = argTypes[paramIndex].Name; - // If we couldn't find a direct match and are not supposed to autowire, - // let's try the next generic, untyped argument value as fallback: - // it could match after type conversion (for example, String -> int). - ConstructorArgumentValues.ValueHolder valueHolder = null; - if (resolvedValues.GetNamedArgumentValue(parameterName) != null) - { - valueHolder = resolvedValues.GetArgumentValue(parameterName, paramType, usedValueHolders); - } - else - { - valueHolder = resolvedValues.GetArgumentValue(paramIndex, paramType, usedValueHolders); - } - - if (valueHolder == null && !autowiring) - { - valueHolder = resolvedValues.GetGenericArgumentValue(null, usedValueHolders); - } - if (valueHolder != null) - { - // We found a potential match - let's give it a try. - // Do not consider the same value definition multiple times! - usedValueHolders.Add(valueHolder); - args.rawArguments[paramIndex] = valueHolder.Value; - try - { - object originalValue = valueHolder.Value; - object convertedValue = TypeConversionUtils.ConvertValueIfNecessary(paramType, originalValue, null); - args.arguments[paramIndex] = convertedValue; - - //? - args.preparedArguments[paramIndex] = convertedValue; - } - catch (TypeMismatchException ex) - { - // to avoid using exceptions for flow control, this is not a cost in Java as stack trace is lazily created. - string errorMessage = $"Could not convert {GetMethodType()} argument value [{valueHolder.Value}] to required type [{paramType}] : {ex.Message}"; - unsatisfiedDependencyExceptionData = new UnsatisfiedDependencyExceptionData(paramIndex, paramType, errorMessage); - return null; - } - } - else - { - // No explicit match found: we're either supposed to autowire or - // have to fail creating an argument array for the given constructor. - if (!autowiring) - { - string errorMessage = $"Ambiguous {GetMethodType()} argument types - " + - $"Did you specify the correct object references as {GetMethodType()} arguments?"; - unsatisfiedDependencyExceptionData = new UnsatisfiedDependencyExceptionData(paramIndex, paramType, errorMessage); - - return null; - } - try - { - MethodParameter param = MethodParameter.ForMethodOrConstructor(methodOrCtorInfo, paramIndex); - autowiredObjectNames = new List(); - object autowiredArgument = ResolveAutoWiredArgument(param, objectName, autowiredObjectNames); - args.rawArguments[paramIndex] = autowiredArgument; - args.arguments[paramIndex] = autowiredArgument; - args.preparedArguments[paramIndex] = new AutowiredArgumentMarker(); - } - catch (ObjectsException ex) - { - unsatisfiedDependencyExceptionData = new UnsatisfiedDependencyExceptionData(paramIndex, paramType, ex.Message); - - return null; - } - } - } - - if (log.IsEnabled(LogLevel.Debug) && autowiredObjectNames != null) - { - for (var i = 0; i < autowiredObjectNames.Count; i++) - { - string autowiredObjectName = autowiredObjectNames[i]; - log.LogDebug($"Autowiring by type from object name '{objectName}' via {GetMethodType()} to object named '{autowiredObjectName}'"); - } - } - - return args; - } - - private class AutowiredArgumentMarker - { - } - - private object ResolveAutoWiredArgument( - MethodParameter methodParameter, - string objectName, - List autowiredObjectNames) - { - return autowireFactory.ResolveDependency( - new DependencyDescriptor(methodParameter, true), - objectName, - autowiredObjectNames); - } - - /// - /// Resolves the - /// of the supplied . - /// - /// The name of the object that is being resolved by this factory. - /// The rod. - /// The wrapper. - /// The cargs. - /// Where the resolved constructor arguments will be placed. - /// - /// The minimum number of arguments that any constructor for the supplied - /// must have. - /// - /// - ///

- /// 'Resolve' can be taken to mean that all of the s - /// constructor arguments is resolved into a concrete object that can be plugged - /// into one of the s constructors. Runtime object - /// references to other objects in this (or a parent) factory are resolved, - /// type conversion is performed, etc. - ///

- ///

- /// These resolved values are plugged into the supplied - /// object, because we wouldn't want to touch - /// the s constructor arguments in case it (or any of - /// its constructor arguments) is a prototype object definition. - ///

- ///

- /// This method is also used for handling invocations of static factory methods. - ///

- ///
- private int ResolveConstructorArguments(string objectName, RootObjectDefinition definition, ObjectWrapper wrapper, - ConstructorArgumentValues cargs, - ConstructorArgumentValues resolvedValues) - { + /// + /// Resolves the + /// of the supplied . + /// + /// The name of the object that is being resolved by this factory. + /// The rod. + /// The wrapper. + /// The cargs. + /// Where the resolved constructor arguments will be placed. + /// + /// The minimum number of arguments that any constructor for the supplied + /// must have. + /// + /// + ///

+ /// 'Resolve' can be taken to mean that all of the s + /// constructor arguments is resolved into a concrete object that can be plugged + /// into one of the s constructors. Runtime object + /// references to other objects in this (or a parent) factory are resolved, + /// type conversion is performed, etc. + ///

+ ///

+ /// These resolved values are plugged into the supplied + /// object, because we wouldn't want to touch + /// the s constructor arguments in case it (or any of + /// its constructor arguments) is a prototype object definition. + ///

+ ///

+ /// This method is also used for handling invocations of static factory methods. + ///

+ ///
+ private int ResolveConstructorArguments(string objectName, RootObjectDefinition definition, ObjectWrapper wrapper, + ConstructorArgumentValues cargs, + ConstructorArgumentValues resolvedValues) + { // ObjectDefinitionValueResolver valueResolver = new ObjectDefinitionValueResolver(objectFactory); - int minNrOfArgs = cargs.ArgumentCount; + int minNrOfArgs = cargs.ArgumentCount; - if (cargs._indexedArgumentValues != null) + if (cargs._indexedArgumentValues != null) + { + foreach (var entry in cargs._indexedArgumentValues) { - foreach (var entry in cargs._indexedArgumentValues) + int index = entry.Key; + if (index < 0) { - int index = entry.Key; - if (index < 0) - { - throw new ObjectCreationException( - definition.ResourceDescription, - objectName, - $"Invalid constructor argument index: {index}"); - } - - if (index > minNrOfArgs) - { - minNrOfArgs = index + 1; - } - - ConstructorArgumentValues.ValueHolder valueHolder = entry.Value; - string argName = "constructor argument with index " + index; - object resolvedValue = valueResolver.ResolveValueIfNecessary(objectName, definition, argName, valueHolder.Value); - resolvedValues.AddIndexedArgumentValue(index, resolvedValue, - StringUtils.HasText(valueHolder.Type) - ? TypeResolutionUtils.ResolveType(valueHolder.Type).AssemblyQualifiedName - : null); + throw new ObjectCreationException( + definition.ResourceDescription, + objectName, + $"Invalid constructor argument index: {index}"); } - } - if (definition.ConstructorArgumentValues._genericArgumentValues != null) - { - const string argName = "constructor argument"; - for (var i = 0; i < definition.ConstructorArgumentValues._genericArgumentValues.Count; i++) + if (index > minNrOfArgs) { - var valueHolder = definition.ConstructorArgumentValues._genericArgumentValues[i]; - object resolvedValue = valueResolver.ResolveValueIfNecessary(objectName, definition, argName, valueHolder.Value); - - resolvedValues.AddGenericArgumentValue( - resolvedValue, - StringUtils.HasText(valueHolder.Type) - ? TypeResolutionUtils.ResolveType(valueHolder.Type).AssemblyQualifiedName - : null); + minNrOfArgs = index + 1; } - } - if (definition.ConstructorArgumentValues._namedArgumentValues != null) - { - foreach (var entry in definition.ConstructorArgumentValues._namedArgumentValues) - { - string argumentName = entry.Key; - string syntheticArgumentName = "constructor argument with name " + argumentName; - ConstructorArgumentValues.ValueHolder valueHolder = entry.Value; - object resolvedValue = valueResolver.ResolveValueIfNecessary(objectName, definition, syntheticArgumentName, valueHolder.Value); - resolvedValues.AddNamedArgumentValue(argumentName, resolvedValue); - } + ConstructorArgumentValues.ValueHolder valueHolder = entry.Value; + string argName = "constructor argument with index " + index; + object resolvedValue = valueResolver.ResolveValueIfNecessary(objectName, definition, argName, valueHolder.Value); + resolvedValues.AddIndexedArgumentValue(index, resolvedValue, + StringUtils.HasText(valueHolder.Type) + ? TypeResolutionUtils.ResolveType(valueHolder.Type).AssemblyQualifiedName + : null); } - - return minNrOfArgs; } - /// - /// Returns an array of all of those - /// methods exposed on the - /// that match the supplied criteria. - /// - /// - /// Methods that have this name (can be in the form of a regular expression). - /// - /// - /// Methods that have exactly this many arguments. - /// - /// - /// Methods that are static / instance. - /// - /// - /// The on which the methods (if any) are to be found. - /// - /// - /// An array of all of those - /// methods exposed on the - /// that match the supplied criteria. - /// - private static IList FindMethods(string methodName, int expectedArgumentCount, bool isStatic, Type searchType) + if (definition.ConstructorArgumentValues._genericArgumentValues != null) { - ComposedCriteria methodCriteria = new ComposedCriteria(); - methodCriteria.Add(new MethodNameMatchCriteria(methodName)); - methodCriteria.Add(new MethodParametersCountCriteria(expectedArgumentCount)); - BindingFlags methodFlags = BindingFlags.Public | BindingFlags.IgnoreCase | (isStatic ? BindingFlags.Static : BindingFlags.Instance); - MemberInfo[] methods = searchType.FindMembers(MemberTypes.Method, methodFlags, new CriteriaMemberFilter().FilterMemberByCriteria, methodCriteria); - return methods.Cast().ToArray(); + const string argName = "constructor argument"; + for (var i = 0; i < definition.ConstructorArgumentValues._genericArgumentValues.Count; i++) + { + var valueHolder = definition.ConstructorArgumentValues._genericArgumentValues[i]; + object resolvedValue = valueResolver.ResolveValueIfNecessary(objectName, definition, argName, valueHolder.Value); + + resolvedValues.AddGenericArgumentValue( + resolvedValue, + StringUtils.HasText(valueHolder.Type) + ? TypeResolutionUtils.ResolveType(valueHolder.Type).AssemblyQualifiedName + : null); + } } - private class ArgumentsHolder + if (definition.ConstructorArgumentValues._namedArgumentValues != null) { - internal static readonly ArgumentsHolder Empty = new ArgumentsHolder(0); - - public readonly object[] rawArguments; - public readonly object[] arguments; - public readonly object[] preparedArguments; - - public ArgumentsHolder(int size) + foreach (var entry in definition.ConstructorArgumentValues._namedArgumentValues) { - rawArguments = size == 0 ? ObjectUtils.EmptyObjects : new object[size]; - arguments = size == 0 ? ObjectUtils.EmptyObjects : new object[size]; - preparedArguments = size == 0 ? ObjectUtils.EmptyObjects : new object[size]; + string argumentName = entry.Key; + string syntheticArgumentName = "constructor argument with name " + argumentName; + ConstructorArgumentValues.ValueHolder valueHolder = entry.Value; + object resolvedValue = valueResolver.ResolveValueIfNecessary(objectName, definition, syntheticArgumentName, valueHolder.Value); + resolvedValues.AddNamedArgumentValue(argumentName, resolvedValue); + } + } + + return minNrOfArgs; + } + + /// + /// Returns an array of all of those + /// methods exposed on the + /// that match the supplied criteria. + /// + /// + /// Methods that have this name (can be in the form of a regular expression). + /// + /// + /// Methods that have exactly this many arguments. + /// + /// + /// Methods that are static / instance. + /// + /// + /// The on which the methods (if any) are to be found. + /// + /// + /// An array of all of those + /// methods exposed on the + /// that match the supplied criteria. + /// + private static IList FindMethods(string methodName, int expectedArgumentCount, bool isStatic, Type searchType) + { + ComposedCriteria methodCriteria = new ComposedCriteria(); + methodCriteria.Add(new MethodNameMatchCriteria(methodName)); + methodCriteria.Add(new MethodParametersCountCriteria(expectedArgumentCount)); + BindingFlags methodFlags = BindingFlags.Public | BindingFlags.IgnoreCase | (isStatic ? BindingFlags.Static : BindingFlags.Instance); + MemberInfo[] methods = searchType.FindMembers(MemberTypes.Method, methodFlags, new CriteriaMemberFilter().FilterMemberByCriteria, methodCriteria); + return methods.Cast().ToArray(); + } + + private class ArgumentsHolder + { + internal static readonly ArgumentsHolder Empty = new ArgumentsHolder(0); + + public readonly object[] rawArguments; + public readonly object[] arguments; + public readonly object[] preparedArguments; + + public ArgumentsHolder(int size) + { + rawArguments = size == 0 ? ObjectUtils.EmptyObjects : new object[size]; + arguments = size == 0 ? ObjectUtils.EmptyObjects : new object[size]; + preparedArguments = size == 0 ? ObjectUtils.EmptyObjects : new object[size]; + } + + private ArgumentsHolder(object[] args) + { + rawArguments = args; + arguments = args; + preparedArguments = args; + } + + public static ArgumentsHolder Create(object[] args) + { + if (args.Length == 0) + { + return Empty; } - private ArgumentsHolder(object[] args) + return new ArgumentsHolder(args); + } + + public static ArgumentsHolder Create(int size) + { + if (size == 0) { - rawArguments = args; - arguments = args; - preparedArguments = args; + return Empty; } - public static ArgumentsHolder Create(object[] args) - { - if (args.Length == 0) - { - return Empty; - } - return new ArgumentsHolder(args); - } + return new ArgumentsHolder(size); + } - public static ArgumentsHolder Create(int size) - { - if (size == 0) - { - return Empty; - } - return new ArgumentsHolder(size); - } - - public int GetTypeDifferenceWeight(Type[] paramTypes) - { - // If valid arguments found, determine type difference weight. - // Try type difference weight on both the converted arguments and - // the raw arguments. If the raw weight is better, use it. - // Decrease raw weight by 1024 to prefer it over equal converted weight. - int typeDiffWeight = AutowireUtils.GetTypeDifferenceWeight(paramTypes, arguments); - int rawTypeDiffWeight = AutowireUtils.GetTypeDifferenceWeight(paramTypes, rawArguments) - 1024; - return (rawTypeDiffWeight < typeDiffWeight ? rawTypeDiffWeight : typeDiffWeight); - } + public int GetTypeDifferenceWeight(Type[] paramTypes) + { + // If valid arguments found, determine type difference weight. + // Try type difference weight on both the converted arguments and + // the raw arguments. If the raw weight is better, use it. + // Decrease raw weight by 1024 to prefer it over equal converted weight. + int typeDiffWeight = AutowireUtils.GetTypeDifferenceWeight(paramTypes, arguments); + int rawTypeDiffWeight = AutowireUtils.GetTypeDifferenceWeight(paramTypes, rawArguments) - 1024; + return (rawTypeDiffWeight < typeDiffWeight ? rawTypeDiffWeight : typeDiffWeight); } } } - diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/DefaultListableObjectFactory.cs b/src/Spring/Spring.Core/Objects/Factory/Support/DefaultListableObjectFactory.cs index 963434e5..077c9feb 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/DefaultListableObjectFactory.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/DefaultListableObjectFactory.cs @@ -25,569 +25,368 @@ using Spring.Expressions; using Spring.Objects.Factory.Config; using Spring.Util; -namespace Spring.Objects.Factory.Support +namespace Spring.Objects.Factory.Support; + +/// +/// Concrete implementation of the +/// and +/// +/// interfaces. +/// +/// +///

+/// This class is a full-fledged object factory based on object definitions +/// that is usable straight out of the box. +///

+///

+/// Can be used as an object factory in and of itself, or as a superclass +/// for custom object factory implementations. Note that readers for +/// specific object definition formats are typically implemented separately +/// rather than as object factory subclasses. +///

+///

+/// For an alternative implementation of the +/// interface, +/// have a look at the +/// +/// class, which manages existing object instances rather than creating new +/// ones based on object definitions. +///

+///
+/// Juergen Hoeller +/// Rick Evans (.NET) +/// +[Serializable] +public class DefaultListableObjectFactory : + AbstractAutowireCapableObjectFactory, + IConfigurableListableObjectFactory, + IObjectDefinitionRegistry { + // The mapping of object depending object names, keyed by object name. + private Dictionary> dependingObjectNamesCache; + + // The mapping of object definition objects, keyed by object name. + private readonly Dictionary objectDefinitionMap; + + // List of object definition names, in registration order. + private List objectDefinitionNames = new List(256); + + // Resolver to use for checking if an object definition is an autowire candidate + private IAutowireCandidateResolver autowireCandidateResolver = AutowireUtils.CreateAutowireCandidateResolver(); + + // Dictionary from dependency type to corresponding autowired value + private readonly IDictionary resolvableDependencies = new Dictionary(); + + // map of singleton and non-singleton bean names, keyed by dependency type + private readonly ConcurrentDictionary> allObjectNamesByType = new ConcurrentDictionary>(); + + // map of singleton-only bean names, keyed by dependency type + private readonly ConcurrentDictionary> singletonObjectNamesByType = new ConcurrentDictionary>(); + + // list of names of manually registered singletons, in registration order + private volatile OrderedSet manualSingletonNames = new OrderedSet(); + + // cached array of bean definition names in case of frozen configuration + private volatile string[] frozenObjectDefinitionNames; + + // whether bean definition metadata may be cached for all beans + private volatile bool configurationFrozen; + /// - /// Concrete implementation of the - /// and - /// - /// interfaces. + /// Creates a new instance of the + /// class. + /// + public DefaultListableObjectFactory() + : this(true, null) + { + } + + /// + /// Creates a new instance of the + /// class. + /// + /// Flag specifying whether to make this object factory case sensitive or not. + public DefaultListableObjectFactory(bool caseSensitive) + : this(caseSensitive, null) + { + } + + /// + /// Creates a new instance of the + /// class. + /// + /// The parent object factory. + public DefaultListableObjectFactory(IObjectFactory parentFactory) + : this(true, parentFactory) + { + } + + /// + /// Creates a new instance of the + /// class. + /// + /// Flag specifying whether to make this object factory case sensitive or not. + /// The parent object factory. + public DefaultListableObjectFactory(bool caseSensitive, IObjectFactory parentFactory) + : base(caseSensitive, parentFactory) + { + AllowObjectDefinitionOverriding = true; + if (caseSensitive) + { + objectDefinitionMap = new Dictionary(); + } + else + { + objectDefinitionMap = new Dictionary(StringComparer.OrdinalIgnoreCase); + } + } + + /// + /// Should object definitions registered under the same name as an + /// existing object definition be allowed? /// /// ///

- /// This class is a full-fledged object factory based on object definitions - /// that is usable straight out of the box. + /// If , then the new object definition will + /// replace (override) the existing object definition. If + /// , an exception will be thrown when + /// an attempt is made to register an object definition under the same + /// name as an already existing object definition. ///

///

- /// Can be used as an object factory in and of itself, or as a superclass - /// for custom object factory implementations. Note that readers for - /// specific object definition formats are typically implemented separately - /// rather than as object factory subclasses. - ///

- ///

- /// For an alternative implementation of the - /// interface, - /// have a look at the - /// - /// class, which manages existing object instances rather than creating new - /// ones based on object definitions. + /// The default is . ///

///
- /// Juergen Hoeller - /// Rick Evans (.NET) - /// - [Serializable] - public class DefaultListableObjectFactory : - AbstractAutowireCapableObjectFactory, - IConfigurableListableObjectFactory, - IObjectDefinitionRegistry + /// + /// is the registration of an object definition + /// under the same name as an existing object definition is allowed. + /// + public bool AllowObjectDefinitionOverriding { get; set; } + + /// + /// Get or set custom autowire candidate resolver for this IObjectFactory to use + /// when deciding whether a bean definition should be considered as a + /// candidate for autowiring. Never null + /// + public IAutowireCandidateResolver AutowireCandidateResolver { - - // The mapping of object depending object names, keyed by object name. - private Dictionary> dependingObjectNamesCache; - - // The mapping of object definition objects, keyed by object name. - private readonly Dictionary objectDefinitionMap; - - // List of object definition names, in registration order. - private List objectDefinitionNames = new List(256); - - // Resolver to use for checking if an object definition is an autowire candidate - private IAutowireCandidateResolver autowireCandidateResolver = AutowireUtils.CreateAutowireCandidateResolver(); - - // Dictionary from dependency type to corresponding autowired value - private readonly IDictionary resolvableDependencies = new Dictionary(); - - // map of singleton and non-singleton bean names, keyed by dependency type - private readonly ConcurrentDictionary> allObjectNamesByType = new ConcurrentDictionary>(); - - // map of singleton-only bean names, keyed by dependency type - private readonly ConcurrentDictionary> singletonObjectNamesByType = new ConcurrentDictionary>(); - - // list of names of manually registered singletons, in registration order - private volatile OrderedSet manualSingletonNames = new OrderedSet(); - - // cached array of bean definition names in case of frozen configuration - private volatile string[] frozenObjectDefinitionNames; - - // whether bean definition metadata may be cached for all beans - private volatile bool configurationFrozen; - - /// - /// Creates a new instance of the - /// class. - /// - public DefaultListableObjectFactory() - : this(true, null) + get { + return autowireCandidateResolver; } - - /// - /// Creates a new instance of the - /// class. - /// - /// Flag specifying whether to make this object factory case sensitive or not. - public DefaultListableObjectFactory(bool caseSensitive) - : this(caseSensitive, null) + set { + AssertUtils.ArgumentNotNull(value, "AutowireCandidateResolver"); + autowireCandidateResolver = value; } + } - /// - /// Creates a new instance of the - /// class. - /// - /// The parent object factory. - public DefaultListableObjectFactory(IObjectFactory parentFactory) - : this(true, parentFactory) - { - } + /// + /// Find object instances that match the . + /// + /// + ///

+ /// Called by autowiring. If a subclass cannot obtain information about object + /// names by , a corresponding exception should be thrown. + ///

+ ///
+ /// + /// The type of the objects to look up. + /// + /// + /// An of object names and object + /// instances that match the , or + /// if none is found. + /// + /// + /// In case of errors. + /// + protected override IDictionary FindMatchingObjects(Type requiredType) + { + return ObjectFactoryUtils.ObjectsOfTypeIncludingAncestors( + this, requiredType, true, true); + } - /// - /// Creates a new instance of the - /// class. - /// - /// Flag specifying whether to make this object factory case sensitive or not. - /// The parent object factory. - public DefaultListableObjectFactory(bool caseSensitive, IObjectFactory parentFactory) - : base(caseSensitive, parentFactory) + /// + /// Return the names of the objects that depend on the given object. + /// + /// + ///

+ /// Called by the + /// + /// so that dependant objects are able to be disposed of first. + ///

+ ///
+ /// + /// The name of the object to find depending objects for. + /// + /// + /// The array of names of depending objects, or the empty string array if none. + /// + /// + /// In case of errors. + /// + protected override IList GetDependingObjectNames(string objectName) + { + List dependingObjectNames = new List(); + if (dependingObjectNamesCache == null) { - AllowObjectDefinitionOverriding = true; - if (caseSensitive) + dependingObjectNamesCache = new Dictionary>(); + var allObjectDefinitionNames = GetObjectDefinitionNames(); + for (var i = 0; i < allObjectDefinitionNames.Count; i++) { - objectDefinitionMap = new Dictionary(); - } - else - { - objectDefinitionMap = new Dictionary(StringComparer.OrdinalIgnoreCase); - } - } - - /// - /// Should object definitions registered under the same name as an - /// existing object definition be allowed? - /// - /// - ///

- /// If , then the new object definition will - /// replace (override) the existing object definition. If - /// , an exception will be thrown when - /// an attempt is made to register an object definition under the same - /// name as an already existing object definition. - ///

- ///

- /// The default is . - ///

- ///
- /// - /// is the registration of an object definition - /// under the same name as an existing object definition is allowed. - /// - public bool AllowObjectDefinitionOverriding { get; set; } - - - /// - /// Get or set custom autowire candidate resolver for this IObjectFactory to use - /// when deciding whether a bean definition should be considered as a - /// candidate for autowiring. Never null - /// - public IAutowireCandidateResolver AutowireCandidateResolver - { - get - { - return autowireCandidateResolver; - } - set - { - AssertUtils.ArgumentNotNull(value, "AutowireCandidateResolver"); - autowireCandidateResolver = value; - } - } - - /// - /// Find object instances that match the . - /// - /// - ///

- /// Called by autowiring. If a subclass cannot obtain information about object - /// names by , a corresponding exception should be thrown. - ///

- ///
- /// - /// The type of the objects to look up. - /// - /// - /// An of object names and object - /// instances that match the , or - /// if none is found. - /// - /// - /// In case of errors. - /// - protected override IDictionary FindMatchingObjects(Type requiredType) - { - return ObjectFactoryUtils.ObjectsOfTypeIncludingAncestors( - this, requiredType, true, true); - } - - /// - /// Return the names of the objects that depend on the given object. - /// - /// - ///

- /// Called by the - /// - /// so that dependant objects are able to be disposed of first. - ///

- ///
- /// - /// The name of the object to find depending objects for. - /// - /// - /// The array of names of depending objects, or the empty string array if none. - /// - /// - /// In case of errors. - /// - protected override IList GetDependingObjectNames(string objectName) - { - List dependingObjectNames = new List(); - if (dependingObjectNamesCache == null) - { - dependingObjectNamesCache = new Dictionary>(); - var allObjectDefinitionNames = GetObjectDefinitionNames(); - for (var i = 0; i < allObjectDefinitionNames.Count; i++) - { - string name = allObjectDefinitionNames[i]; - if (ContainsObjectDefinition(name)) - { - RootObjectDefinition rod = GetMergedObjectDefinition(name, false); - if (rod.DependsOn != null) - { - foreach (var dependsOnName in rod.DependsOn) - { - if (!dependingObjectNamesCache.TryGetValue(dependsOnName, out dependingObjectNames)) - { - dependingObjectNames = new List(); - dependingObjectNamesCache.Add(dependsOnName, dependingObjectNames); - } - - dependingObjectNames.Add(name); - } - } - } - } - } - if (dependingObjectNamesCache.TryGetValue(objectName, out dependingObjectNames)) - return dependingObjectNames; - return new string[]{}; - } - - /// - /// Check whether the specified object matches the supplied . - /// - /// The name of the object to check. - /// - /// The to check for. - /// - /// - /// if the object matches the supplied , - /// or if the supplied is . - /// - private bool IsObjectTypeMatch(string objectName, Type type) - { - if (type == null) - { - return true; - } - Type objectType = GetType(objectName); - return (objectType != null && type.IsAssignableFrom(objectType)); - } - - private bool IsObjectDefinitionTypeMatch(string name, Type checkedType) - { - return IsObjectDefinitionTypeMatch(name, checkedType, false); - } - - private bool IsObjectDefinitionTypeMatch(string name, Type checkedType, bool includeAncestor) - { - if (checkedType == null) - { - return true; - } - RootObjectDefinition rod = GetMergedObjectDefinition(name, includeAncestor); - return (rod.HasObjectType && checkedType.IsAssignableFrom(rod.ObjectType)); - } - - /// - /// Return the number of objects defined in this registry. - /// - /// - /// The number of objects defined in this registry. - /// - /// - public int ObjectDefinitionCount => objectDefinitionMap.Count; - - /// - /// Check if this registry contains a object definition with the given - /// name. - /// - /// - /// The name of the object to look for. - /// - /// - /// if this object factory contains an object - /// definition with the given name. - /// - /// - public override bool ContainsObjectDefinition(string name) - { - return objectDefinitionMap.ContainsKey(name); - } - - /// - /// Register a new object definition with this registry. - /// - /// - /// The name of the object instance to register. - /// - /// - /// The definition of the object instance to register. - /// - /// - /// If the object definition is invalid. - /// - /// - public override void RegisterObjectDefinition(string name, IObjectDefinition objectDefinition) - { - if (objectDefinition is AbstractObjectDefinition abstractObjectDefinition) - { - try + string name = allObjectDefinitionNames[i]; + if (ContainsObjectDefinition(name)) { - abstractObjectDefinition.Validate(); - } - catch (ObjectDefinitionValidationException ex) - { - throw new ObjectDefinitionStoreException( - abstractObjectDefinition.ResourceDescription, - name, - "Validation of object definition failed.", - ex); - } - } - - if (objectDefinitionMap.TryGetValue(name, out var existingDefinition)) - { - if (!AllowObjectDefinitionOverriding) - { - throw new ObjectDefinitionStoreException( - $"Cannot register object definition [{objectDefinition}] for object '{name}': there's already [{existingDefinition}] bound."); - } - - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug($"Overriding object definition for object '{name}': replacing [{existingDefinition}] with [{objectDefinition}]."); - } - objectDefinitionMap[name] = objectDefinition; - } - else - { - if (HasObjectCreationStarted) - { - // Cannot modify startup-time collection elements anymore (for stable iteration) - lock (objectDefinitionMap) + RootObjectDefinition rod = GetMergedObjectDefinition(name, false); + if (rod.DependsOn != null) { - objectDefinitionMap[name] = objectDefinition; - var updatedDefinitions = new List(objectDefinitionNames.Count + 1); - updatedDefinitions.AddRange(objectDefinitionNames); - updatedDefinitions.Add(name); - objectDefinitionNames = updatedDefinitions; - if (manualSingletonNames.Contains(name)) + foreach (var dependsOnName in rod.DependsOn) { - OrderedSet updatedSingletons = new OrderedSet(manualSingletonNames); - updatedSingletons.Remove(name); - manualSingletonNames = updatedSingletons; + if (!dependingObjectNamesCache.TryGetValue(dependsOnName, out dependingObjectNames)) + { + dependingObjectNames = new List(); + dependingObjectNamesCache.Add(dependsOnName, dependingObjectNames); + } + + dependingObjectNames.Add(name); } } } - else - { - // Still in startup registration phase - objectDefinitionMap[name] = objectDefinition; - objectDefinitionNames.Add(name); - manualSingletonNames.Remove(name); - } - - frozenObjectDefinitionNames = null; - } - - - if (existingDefinition != null || ContainsSingleton(name)) - { - ResetObjectDefinition(name); - } - } - - /// - /// Reset all bean definition caches for the given bean, - /// including the caches of beans that are derived from it. - /// - /// - /// Called after an existing bean definition has been replaced or removed, - /// triggering , - /// and on the - /// given bean and on all bean definitions that have the given bean as parent. - /// - /// The name of the object to reset - protected void ResetObjectDefinition(string objectName) - { - // Remove the merged bean definition for the given bean, if already created. - ClearMergedObjectDefinition(objectName); - - // Remove corresponding bean from singleton cache, if any. Shouldn't usually - // be necessary, rather just meant for overriding a context's default beans - // (e.g. the default StaticMessageSource in a StaticApplicationContext). - DestroySingleton(objectName); - - // Notify all post-processors that the specified bean definition has been reset. - for (var i = 0; i < ObjectPostProcessors.Count; i++) - { - IObjectPostProcessor processor = ObjectPostProcessors[i]; - if (processor is IMergedObjectDefinitionPostProcessor mergedObjectDefinitionPostProcessor) - { - mergedObjectDefinitionPostProcessor.ResetObjectDefinition(objectName); - } - } - - // Reset all bean definitions that have the given bean as parent (recursively). - for (var i = 0; i < objectDefinitionNames.Count; i++) - { - string bdName = objectDefinitionNames[i]; - if (objectName != bdName) - { - var bd = objectDefinitionMap[bdName]; - if (objectName == bd.ParentName) - { - ResetObjectDefinition(bdName); - } - } } } + if (dependingObjectNamesCache.TryGetValue(objectName, out dependingObjectNames)) + return dependingObjectNames; + return new string[] { }; + } - /// - /// Ensure that all non-lazy-init singletons are instantiated, also - /// considering s. - /// - /// - /// If one of the singleton objects could not be created. - /// - /// - public void PreInstantiateSingletons() + /// + /// Check whether the specified object matches the supplied . + /// + /// The name of the object to check. + /// + /// The to check for. + /// + /// + /// if the object matches the supplied , + /// or if the supplied is . + /// + private bool IsObjectTypeMatch(string objectName, Type type) + { + if (type == null) { - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug("Pre-instantiating singletons in factory [" + this + "]"); - } + return true; + } + Type objectType = GetType(objectName); + return (objectType != null && type.IsAssignableFrom(objectType)); + } + + private bool IsObjectDefinitionTypeMatch(string name, Type checkedType) + { + return IsObjectDefinitionTypeMatch(name, checkedType, false); + } + + private bool IsObjectDefinitionTypeMatch(string name, Type checkedType, bool includeAncestor) + { + if (checkedType == null) + { + return true; + } + + RootObjectDefinition rod = GetMergedObjectDefinition(name, includeAncestor); + return (rod.HasObjectType && checkedType.IsAssignableFrom(rod.ObjectType)); + } + + /// + /// Return the number of objects defined in this registry. + /// + /// + /// The number of objects defined in this registry. + /// + /// + public int ObjectDefinitionCount => objectDefinitionMap.Count; + + /// + /// Check if this registry contains a object definition with the given + /// name. + /// + /// + /// The name of the object to look for. + /// + /// + /// if this object factory contains an object + /// definition with the given name. + /// + /// + public override bool ContainsObjectDefinition(string name) + { + return objectDefinitionMap.ContainsKey(name); + } + + /// + /// Register a new object definition with this registry. + /// + /// + /// The name of the object instance to register. + /// + /// + /// The definition of the object instance to register. + /// + /// + /// If the object definition is invalid. + /// + /// + public override void RegisterObjectDefinition(string name, IObjectDefinition objectDefinition) + { + if (objectDefinition is AbstractObjectDefinition abstractObjectDefinition) + { try { - int definitionCount = objectDefinitionNames.Count; - for (int i = 0; i < definitionCount; i++) - { - string name = objectDefinitionNames[i]; - if (!ContainsSingleton(name) && ContainsObjectDefinition(name)) - { - RootObjectDefinition definition - = GetMergedObjectDefinition(name, false); - if (!definition.IsAbstract - && definition.IsSingleton - && !definition.IsLazyInit) - { - Type objectType = ResolveObjectType(definition, name); - if (objectType != null - && typeof(IFactoryObject).IsAssignableFrom(definition.ObjectType)) - { - IFactoryObject factoryObject = (IFactoryObject)GetObject( - ObjectFactoryUtils. - BuildFactoryObjectName(name)); - if (factoryObject.IsSingleton) - { - GetObject(name); - } - } - else - { - GetObject(name); - } - } - } - } + abstractObjectDefinition.Validate(); } - catch (ObjectsException) + catch (ObjectDefinitionValidationException ex) { - // destroy already created singletons to avoid dangling resources... - try - { - Dispose(); - } - catch (Exception ex) - { - log.LogError(ex, "PreInstantiateSingletons failed but couldn't destroy any already-created singletons."); - } - throw; + throw new ObjectDefinitionStoreException( + abstractObjectDefinition.ResourceDescription, + name, + "Validation of object definition failed.", + ex); } } - /// - /// Register a special dependency type with corresponding autowired value. - /// - /// Type of the dependency to register. - /// This will typically be a base interface such as IObjectFactory, with extensions of it resolved - /// as well if declared as an autowiring dependency (e.g. IListableBeanFactory), - /// as long as the given value actually implements the extended interface. - /// The autowired value. This may also be an - /// implementation o the interface, - /// which allows for lazy resolution of the actual target value. - /// - /// This is intended for factory/context references that are supposed - /// to be autowirable but are not defined as objects in the factory: - /// e.g. a dependency of type ApplicationContext resolved to the - /// ApplicationContext instance that the object is living in. - /// - /// Note there are no such default types registered in a plain IObjectFactory, - /// not even for the IObjectFactory interface itself. - /// - /// - public void RegisterResolvableDependency(Type dependencyType, object autowiredValue) + if (objectDefinitionMap.TryGetValue(name, out var existingDefinition)) { - AssertUtils.ArgumentNotNull(dependencyType, "dependencyType"); - if (autowiredValue != null) + if (!AllowObjectDefinitionOverriding) { - AssertUtils.IsTrue((autowiredValue is IObjectFactory) || dependencyType.IsInstanceOfType(autowiredValue), - "Value [" + autowiredValue + "] does not implement specified type [" + dependencyType.Name + "]"); - if (!resolvableDependencies.ContainsKey(dependencyType)) - { - resolvableDependencies.Add(dependencyType, autowiredValue); - } + throw new ObjectDefinitionStoreException( + $"Cannot register object definition [{objectDefinition}] for object '{name}': there's already [{existingDefinition}] bound."); } - } - - public override void ClearMetadataCache() - { - base.ClearMetadataCache(); - ClearByTypeCache(); - } - - /// - /// Remove any assumptions about by-type mappings. - /// - private void ClearByTypeCache() - { - allObjectNamesByType.Clear(); - singletonObjectNamesByType.Clear(); - } - public void FreezeConfiguration() - { - configurationFrozen = true; - frozenObjectDefinitionNames = objectDefinitionNames.ToArray(); + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug($"Overriding object definition for object '{name}': replacing [{existingDefinition}] with [{objectDefinition}]."); + } + + objectDefinitionMap[name] = objectDefinition; } - - public bool ConfigurationFrozen => configurationFrozen; - - public override void RegisterSingleton(string beanName, object singletonObject) + else { - base.RegisterSingleton(beanName, singletonObject); - if (HasObjectCreationStarted) { // Cannot modify startup-time collection elements anymore (for stable iteration) lock (objectDefinitionMap) { - if (!objectDefinitionMap.ContainsKey(beanName)) + objectDefinitionMap[name] = objectDefinition; + var updatedDefinitions = new List(objectDefinitionNames.Count + 1); + updatedDefinitions.AddRange(objectDefinitionNames); + updatedDefinitions.Add(name); + objectDefinitionNames = updatedDefinitions; + if (manualSingletonNames.Contains(name)) { - var updatedSingletons = new OrderedSet(manualSingletonNames); - updatedSingletons.Add(beanName); + OrderedSet updatedSingletons = new OrderedSet(manualSingletonNames); + updatedSingletons.Remove(name); manualSingletonNames = updatedSingletons; } } @@ -595,945 +394,1162 @@ namespace Spring.Objects.Factory.Support else { // Still in startup registration phase + objectDefinitionMap[name] = objectDefinition; + objectDefinitionNames.Add(name); + manualSingletonNames.Remove(name); + } + + frozenObjectDefinitionNames = null; + } + + if (existingDefinition != null || ContainsSingleton(name)) + { + ResetObjectDefinition(name); + } + } + + /// + /// Reset all bean definition caches for the given bean, + /// including the caches of beans that are derived from it. + /// + /// + /// Called after an existing bean definition has been replaced or removed, + /// triggering , + /// and on the + /// given bean and on all bean definitions that have the given bean as parent. + /// + /// The name of the object to reset + protected void ResetObjectDefinition(string objectName) + { + // Remove the merged bean definition for the given bean, if already created. + ClearMergedObjectDefinition(objectName); + + // Remove corresponding bean from singleton cache, if any. Shouldn't usually + // be necessary, rather just meant for overriding a context's default beans + // (e.g. the default StaticMessageSource in a StaticApplicationContext). + DestroySingleton(objectName); + + // Notify all post-processors that the specified bean definition has been reset. + for (var i = 0; i < ObjectPostProcessors.Count; i++) + { + IObjectPostProcessor processor = ObjectPostProcessors[i]; + if (processor is IMergedObjectDefinitionPostProcessor mergedObjectDefinitionPostProcessor) + { + mergedObjectDefinitionPostProcessor.ResetObjectDefinition(objectName); + } + } + + // Reset all bean definitions that have the given bean as parent (recursively). + for (var i = 0; i < objectDefinitionNames.Count; i++) + { + string bdName = objectDefinitionNames[i]; + if (objectName != bdName) + { + var bd = objectDefinitionMap[bdName]; + if (objectName == bd.ParentName) + { + ResetObjectDefinition(bdName); + } + } + } + } + + /// + /// Ensure that all non-lazy-init singletons are instantiated, also + /// considering s. + /// + /// + /// If one of the singleton objects could not be created. + /// + /// + public void PreInstantiateSingletons() + { + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug("Pre-instantiating singletons in factory [" + this + "]"); + } + + try + { + int definitionCount = objectDefinitionNames.Count; + for (int i = 0; i < definitionCount; i++) + { + string name = objectDefinitionNames[i]; + if (!ContainsSingleton(name) && ContainsObjectDefinition(name)) + { + RootObjectDefinition definition + = GetMergedObjectDefinition(name, false); + if (!definition.IsAbstract + && definition.IsSingleton + && !definition.IsLazyInit) + { + Type objectType = ResolveObjectType(definition, name); + if (objectType != null + && typeof(IFactoryObject).IsAssignableFrom(definition.ObjectType)) + { + IFactoryObject factoryObject = (IFactoryObject) GetObject( + ObjectFactoryUtils.BuildFactoryObjectName(name)); + if (factoryObject.IsSingleton) + { + GetObject(name); + } + } + else + { + GetObject(name); + } + } + } + } + } + catch (ObjectsException) + { + // destroy already created singletons to avoid dangling resources... + try + { + Dispose(); + } + catch (Exception ex) + { + log.LogError(ex, "PreInstantiateSingletons failed but couldn't destroy any already-created singletons."); + } + + throw; + } + } + + /// + /// Register a special dependency type with corresponding autowired value. + /// + /// Type of the dependency to register. + /// This will typically be a base interface such as IObjectFactory, with extensions of it resolved + /// as well if declared as an autowiring dependency (e.g. IListableBeanFactory), + /// as long as the given value actually implements the extended interface. + /// The autowired value. This may also be an + /// implementation o the interface, + /// which allows for lazy resolution of the actual target value. + /// + /// This is intended for factory/context references that are supposed + /// to be autowirable but are not defined as objects in the factory: + /// e.g. a dependency of type ApplicationContext resolved to the + /// ApplicationContext instance that the object is living in. + /// + /// Note there are no such default types registered in a plain IObjectFactory, + /// not even for the IObjectFactory interface itself. + /// + /// + public void RegisterResolvableDependency(Type dependencyType, object autowiredValue) + { + AssertUtils.ArgumentNotNull(dependencyType, "dependencyType"); + if (autowiredValue != null) + { + AssertUtils.IsTrue((autowiredValue is IObjectFactory) || dependencyType.IsInstanceOfType(autowiredValue), + "Value [" + autowiredValue + "] does not implement specified type [" + dependencyType.Name + "]"); + if (!resolvableDependencies.ContainsKey(dependencyType)) + { + resolvableDependencies.Add(dependencyType, autowiredValue); + } + } + } + + public override void ClearMetadataCache() + { + base.ClearMetadataCache(); + ClearByTypeCache(); + } + + /// + /// Remove any assumptions about by-type mappings. + /// + private void ClearByTypeCache() + { + allObjectNamesByType.Clear(); + singletonObjectNamesByType.Clear(); + } + + public void FreezeConfiguration() + { + configurationFrozen = true; + frozenObjectDefinitionNames = objectDefinitionNames.ToArray(); + } + + public bool ConfigurationFrozen => configurationFrozen; + + public override void RegisterSingleton(string beanName, object singletonObject) + { + base.RegisterSingleton(beanName, singletonObject); + + if (HasObjectCreationStarted) + { + // Cannot modify startup-time collection elements anymore (for stable iteration) + lock (objectDefinitionMap) + { if (!objectDefinitionMap.ContainsKey(beanName)) { - manualSingletonNames.Add(beanName); + var updatedSingletons = new OrderedSet(manualSingletonNames); + updatedSingletons.Add(beanName); + manualSingletonNames = updatedSingletons; } } - - ClearByTypeCache(); } - - protected override void DestroySingleton(string name) + else { - base.DestroySingleton(name); - manualSingletonNames.Remove(name); - ClearByTypeCache(); - } - - /// - /// Determines whether the metadata for the specified object name is eligible for caching. - /// - /// Name of the bean. - /// - /// true if [is object eligible for metadata caching] [the specified bean name]; otherwise, false. - /// - protected override bool IsObjectEligibleForMetadataCaching(string beanName) - { - return (ConfigurationFrozen || base.IsObjectEligibleForMetadataCaching(beanName)); - } - - /// - /// Return the registered - /// for the - /// given object, allowing access to its property values and constructor - /// argument values. - /// - /// The name of the object. - /// - /// The registered , - /// or null, if specified object definitions does not exist. - /// - /// - /// If is null or empty string. - /// - /// - public override IObjectDefinition GetObjectDefinition(string name) - { - return GetObjectDefinition(name, false); - } - - /// - /// Return the registered - /// for the - /// given object, allowing access to its property values and constructor - /// argument values. - /// - /// The name of the object. - /// Whether to search parent object factories. - /// - /// The registered , - /// or null, if specified object definitions does not exist. - /// - /// - /// If is null or empty string. - /// - /// - public override IObjectDefinition GetObjectDefinition(string name, bool includeAncestors) - { - if (StringUtils.IsNullOrEmpty(name)) + // Still in startup registration phase + if (!objectDefinitionMap.ContainsKey(beanName)) { - throw new ArgumentException( - "Cannot get an object definition with a null or zero length object name string."); + manualSingletonNames.Add(beanName); + } + } + + ClearByTypeCache(); + } + + protected override void DestroySingleton(string name) + { + base.DestroySingleton(name); + manualSingletonNames.Remove(name); + ClearByTypeCache(); + } + + /// + /// Determines whether the metadata for the specified object name is eligible for caching. + /// + /// Name of the bean. + /// + /// true if [is object eligible for metadata caching] [the specified bean name]; otherwise, false. + /// + protected override bool IsObjectEligibleForMetadataCaching(string beanName) + { + return (ConfigurationFrozen || base.IsObjectEligibleForMetadataCaching(beanName)); + } + + /// + /// Return the registered + /// for the + /// given object, allowing access to its property values and constructor + /// argument values. + /// + /// The name of the object. + /// + /// The registered , + /// or null, if specified object definitions does not exist. + /// + /// + /// If is null or empty string. + /// + /// + public override IObjectDefinition GetObjectDefinition(string name) + { + return GetObjectDefinition(name, false); + } + + /// + /// Return the registered + /// for the + /// given object, allowing access to its property values and constructor + /// argument values. + /// + /// The name of the object. + /// Whether to search parent object factories. + /// + /// The registered , + /// or null, if specified object definitions does not exist. + /// + /// + /// If is null or empty string. + /// + /// + public override IObjectDefinition GetObjectDefinition(string name, bool includeAncestors) + { + if (StringUtils.IsNullOrEmpty(name)) + { + throw new ArgumentException( + "Cannot get an object definition with a null or zero length object name string."); + } + + name = TransformedObjectName(name); + if (!objectDefinitionMap.TryGetValue(name, out var definition)) + { + if (!includeAncestors || ParentObjectFactory == null) + { + return null; } - name = TransformedObjectName(name); - if (!objectDefinitionMap.TryGetValue(name, out var definition)) + if (ParentObjectFactory is AbstractObjectFactory abstractObjectFactory) { - if (!includeAncestors || ParentObjectFactory == null) - { - return null; - } - - if (ParentObjectFactory is AbstractObjectFactory abstractObjectFactory) - { - definition = abstractObjectFactory.GetObjectDefinition(name, includeAncestors); - } + definition = abstractObjectFactory.GetObjectDefinition(name, includeAncestors); } - return definition; } + return definition; + } - /// - /// Return the names of all objects defined in this factory. - /// - /// - /// The names of all objects defined in this factory, or an empty array if none - /// are defined. Respects any Parent-Child hierarchy the factory is participating in. - /// - /// - public IReadOnlyList GetObjectDefinitionNames() + /// + /// Return the names of all objects defined in this factory. + /// + /// + /// The names of all objects defined in this factory, or an empty array if none + /// are defined. Respects any Parent-Child hierarchy the factory is participating in. + /// + /// + public IReadOnlyList GetObjectDefinitionNames() + { + return GetObjectDefinitionNames(false); + } + + /// + /// Return the names of all objects defined in this factory, if includeAncestors is true + /// includes all parent factories. + /// + /// to include parent factories in result + /// + /// The names of all objects defined in this factory, if includeAncestors is true includes all + /// objects defined in parent factories, or an empty array if none are defined. + /// + public IReadOnlyList GetObjectDefinitionNames(bool includeAncestors) + { + if (!includeAncestors || !(ParentObjectFactory is IListableObjectFactory listableObjectFactory)) { - return GetObjectDefinitionNames(false); + return objectDefinitionNames; } - /// - /// Return the names of all objects defined in this factory, if includeAncestors is true - /// includes all parent factories. - /// - /// to include parent factories in result - /// - /// The names of all objects defined in this factory, if includeAncestors is true includes all - /// objects defined in parent factories, or an empty array if none are defined. - /// - public IReadOnlyList GetObjectDefinitionNames(bool includeAncestors) + var results = new List(objectDefinitionNames); + foreach (var name in listableObjectFactory.GetObjectDefinitionNames(includeAncestors: true)) { - if (!includeAncestors || !(ParentObjectFactory is IListableObjectFactory listableObjectFactory)) + if (!results.Contains(name)) { - return objectDefinitionNames; + results.Add(name); } + } - var results = new List(objectDefinitionNames); - foreach (var name in listableObjectFactory.GetObjectDefinitionNames(includeAncestors: true)) + return results; + } + + /// + /// Return the names of objects matching the given + /// (including subclasses), judging from the object definitions. + /// + /// + /// The (class or interface) to match, or + /// for all object names. + /// + /// + /// The names of all objects defined in this factory, or an empty array if none + /// are defined. + /// + /// + public IList GetObjectDefinitionNames(Type type) + { + return GetObjectDefinitionNames(type, false); + } + + public IList GetObjectDefinitionNames(Type type, bool includeAncestor) + { + List matches = new List(); + foreach (string name in GetObjectDefinitionNames(includeAncestor)) + { + if (IsObjectDefinitionTypeMatch(name, type, includeAncestor)) { - if (!results.Contains(name)) - { - results.Add(name); - } + matches.Add(name); } - - return results; } - /// - /// Return the names of objects matching the given - /// (including subclasses), judging from the object definitions. - /// - /// - /// The (class or interface) to match, or - /// for all object names. - /// - /// - /// The names of all objects defined in this factory, or an empty array if none - /// are defined. - /// - /// - public IList GetObjectDefinitionNames(Type type) + return matches; + } + + /// + /// Return the names of objects matching the given + /// (including subclasses), judging from the object definitions. + /// + /// + /// The (class or interface) to match, or + /// for all object names. + /// + /// + /// The names of all objects defined in this factory, or an empty array if none + /// are defined. + /// + /// + public IReadOnlyList GetObjectNamesForType(Type type) + { + return GetObjectNamesForType(type, true, true); + } + + /// + /// Return the names of objects matching the given + /// (including subclasses), judging from the object definitions. + /// + /// + ///

+ /// Does consider objects created by s, + /// or rather it considers the type of objects created by + /// (which means that + /// s will be instantiated). + ///

+ ///

+ /// Does not consider any hierarchy this factory may participate in. + ///

+ ///
+ /// + /// The (class or interface) to match, or + /// for all object names. + /// + /// + /// The names of all objects defined in this factory, or an empty array if none + /// are defined. + /// + public IReadOnlyList GetObjectNames() + { + return GetObjectNamesForType(typeof(T)); + } + + /// + /// Return the names of objects matching the given + /// (including subclasses), judging from the object definitions. + /// + /// + /// The (class or interface) to match, or + /// for all object names. + /// + /// + /// Whether to include prototype objects too or just singletons (also applies to + /// s). + /// + /// + /// Whether to include s too + /// or just normal objects. + /// + /// + /// The names of all objects defined in this factory, or an empty array if none + /// are defined. + /// + /// + public IReadOnlyList GetObjectNamesForType(Type type, bool includePrototypes, bool includeFactoryObjects) + { + if (!ConfigurationFrozen || type == null || !includeFactoryObjects) { - return GetObjectDefinitionNames(type, false); + return DoGetObjectNamesForType(type, includePrototypes, includeFactoryObjects); } - public IList GetObjectDefinitionNames(Type type, bool includeAncestor) + ConcurrentDictionary> cache = + (includePrototypes ? allObjectNamesByType : singletonObjectNamesByType); + + if (cache.TryGetValue(type, out var objectNames)) { - List matches = new List(); - foreach (string name in GetObjectDefinitionNames(includeAncestor)) - { - if (IsObjectDefinitionTypeMatch(name, type, includeAncestor)) - { - matches.Add(name); - } - } - return matches; - } - - /// - /// Return the names of objects matching the given - /// (including subclasses), judging from the object definitions. - /// - /// - /// The (class or interface) to match, or - /// for all object names. - /// - /// - /// The names of all objects defined in this factory, or an empty array if none - /// are defined. - /// - /// - public IReadOnlyList GetObjectNamesForType(Type type) - { - return GetObjectNamesForType(type, true, true); - } - - /// - /// Return the names of objects matching the given - /// (including subclasses), judging from the object definitions. - /// - /// - ///

- /// Does consider objects created by s, - /// or rather it considers the type of objects created by - /// (which means that - /// s will be instantiated). - ///

- ///

- /// Does not consider any hierarchy this factory may participate in. - ///

- ///
- /// - /// The (class or interface) to match, or - /// for all object names. - /// - /// - /// The names of all objects defined in this factory, or an empty array if none - /// are defined. - /// - public IReadOnlyList GetObjectNames() - { - return GetObjectNamesForType(typeof(T)); - } - - /// - /// Return the names of objects matching the given - /// (including subclasses), judging from the object definitions. - /// - /// - /// The (class or interface) to match, or - /// for all object names. - /// - /// - /// Whether to include prototype objects too or just singletons (also applies to - /// s). - /// - /// - /// Whether to include s too - /// or just normal objects. - /// - /// - /// The names of all objects defined in this factory, or an empty array if none - /// are defined. - /// - /// - public IReadOnlyList GetObjectNamesForType(Type type, bool includePrototypes, bool includeFactoryObjects) - { - if (!ConfigurationFrozen || type == null || !includeFactoryObjects) - { - return DoGetObjectNamesForType(type, includePrototypes, includeFactoryObjects); - } - - ConcurrentDictionary> cache = - (includePrototypes ? allObjectNamesByType : singletonObjectNamesByType); - - if (cache.TryGetValue(type, out var objectNames)) - { - return objectNames; - } - - objectNames = DoGetObjectNamesForType(type, includePrototypes, true); - cache[type] = objectNames; - return objectNames; } - /// - /// Return the names of objects matching the given - /// (including subclasses), judging from the object definitions. - /// - /// - ///

- /// Does consider objects created by s, - /// or rather it considers the type of objects created by - /// (which means that - /// s will be instantiated). - ///

- ///

- /// Does not consider any hierarchy this factory may participate in. - /// Use - /// to include beans in ancestor factories too. - /// <p>Note: Does <i>not</i> ignore singleton objects that have been registered - /// by other means than bean definitions. - ///

- ///
- /// - /// The (class or interface) to match, or - /// for all object names. - /// - /// - /// Whether to include prototype objects too or just singletons (also applies to - /// s). - /// - /// - /// Whether to include s too - /// or just normal objects. - /// - /// - /// The names of all objects defined in this factory, or an empty array if none - /// are defined. - /// - public IReadOnlyList GetObjectNames(bool includePrototypes, bool includeFactoryObjects) + objectNames = DoGetObjectNamesForType(type, includePrototypes, true); + cache[type] = objectNames; + + return objectNames; + } + + /// + /// Return the names of objects matching the given + /// (including subclasses), judging from the object definitions. + /// + /// + ///

+ /// Does consider objects created by s, + /// or rather it considers the type of objects created by + /// (which means that + /// s will be instantiated). + ///

+ ///

+ /// Does not consider any hierarchy this factory may participate in. + /// Use + /// to include beans in ancestor factories too. + /// <p>Note: Does <i>not</i> ignore singleton objects that have been registered + /// by other means than bean definitions. + ///

+ ///
+ /// + /// The (class or interface) to match, or + /// for all object names. + /// + /// + /// Whether to include prototype objects too or just singletons (also applies to + /// s). + /// + /// + /// Whether to include s too + /// or just normal objects. + /// + /// + /// The names of all objects defined in this factory, or an empty array if none + /// are defined. + /// + public IReadOnlyList GetObjectNames(bool includePrototypes, bool includeFactoryObjects) + { + return GetObjectNamesForType(typeof(T), includePrototypes, includeFactoryObjects); + } + + /// + /// Return the object instances that match the given object + /// (including subclasses), judging from either object + /// definitions or the value of + /// in the case of + /// s. + /// + /// + /// The (class or interface) to match. + /// + /// + /// A of the matching objects, + /// containing the object names as keys and the corresponding object instances + /// as values. + /// + /// + /// If the objects could not be created. + /// + /// + public IReadOnlyDictionary GetObjectsOfType(Type type) + { + return GetObjectsOfType(type, true, true); + } + + /// + /// Return the object instances that match the given object + /// (including subclasses), judging from either object + /// definitions or the value of + /// in the case of + /// s. + /// + /// + ///

+ /// This version of the + /// method matches all kinds of object definitions, be they singletons, prototypes, or + /// s. Typically, the results + /// of this method call will be the same as a call to + /// IListableObjectFactory.GetObjectsOfType(type,true,true) . + ///

+ ///
+ /// + /// The (class or interface) to match. + /// + /// + /// A of the matching objects, + /// containing the object names as keys and the corresponding object instances + /// as values. + /// + /// + /// If the objects could not be created. + /// + public IReadOnlyDictionary GetObjects() + { + Dictionary result = new Dictionary(); + DoGetObjectsOfType(typeof(T), true, true, result); + return result; + } + + /// + /// Return the object instances that match the given object + /// (including subclasses). + /// + /// + /// The (class or interface) to match. + /// + /// + /// Whether to include prototype objects too or just singletons (also applies to + /// s). + /// + /// + /// Whether to include s too + /// or just normal objects. + /// + /// + /// An of the matching objects, + /// containing the object names as keys and the corresponding object instances + /// as values. + /// + /// + /// If any of the objects could not be created. + /// + /// + public IReadOnlyDictionary GetObjectsOfType(Type type, bool includePrototypes, bool includeFactoryObjects) + { + Dictionary result = new Dictionary(); + DoGetObjectsOfType(type, includePrototypes, includeFactoryObjects, result); + return result; + } + + private void DoGetObjectsOfType(Type type, bool includePrototypes, bool includeFactoryObjects, IDictionary resultCollector) + { + IList objectNames = DoGetObjectNamesForType(type, includePrototypes, includeFactoryObjects); + foreach (string objectName in objectNames) { - return GetObjectNamesForType(typeof(T), includePrototypes, includeFactoryObjects); + try + { + resultCollector.Add(objectName, GetObject(objectName)); + } + catch (ObjectCreationException ex) + { + if (ex.InnerException != null + && ex.GetBaseException().GetType().Equals(typeof(ObjectCurrentlyInCreationException))) + { + // ignoring this is ok... it indicates a circular reference when autowiring + // constructors; we want to find matches other than the currently + // created object itself... + if (log.IsEnabled(LogLevel.Debug)) + { + string message = string.Format( + CultureInfo.InvariantCulture, + "Ignoring match to currently created object '{0}'.", + objectName); + log.LogDebug(ex, message); + } + } + else + { + throw; + } + } + } + } + + /// + /// Return the object instances that match the given object + /// (including subclasses), judging from either object + /// definitions or the value of + /// in the case of + /// s. + /// + /// + /// The (class or interface) to match. + /// + /// + /// Whether to include prototype objects too or just singletons (also applies to + /// s). + /// + /// + /// Whether to include s too + /// or just normal objects. + /// + /// + /// A of the matching objects, + /// containing the object names as keys and the corresponding object instances + /// as values. + /// + /// + /// If the objects could not be created. + /// + public IReadOnlyDictionary GetObjects(bool includePrototypes, bool includeFactoryObjects) + { + Dictionary result = new Dictionary(); + DoGetObjectsOfType(typeof(T), includePrototypes, includeFactoryObjects, result); + return result; + } + + /// + /// Return an instance (possibly shared or independent) of the given object name. + /// + /// + /// + /// This method allows an object factory to be used as a replacement for the + /// Singleton or Prototype design pattern. + /// + /// + /// Note that callers should retain references to returned objects. There is no + /// guarantee that this method will be implemented to be efficient. For example, + /// it may be synchronized, or may need to run an RDBMS query. + /// + /// + /// Will ask the parent factory if the object cannot be found in this factory + /// instance. + /// + /// + /// The type of the object to return. + /// The instance of the object. + /// + /// If there's no such object definition. + /// + /// + /// If there is more than a single object of the requested type defined in the factory. + /// + /// + /// If the object could not be created. + /// + public override T GetObject() + { + var objectNamesForType = GetObjectNamesForType(typeof(T)); + + if (objectNamesForType.Count > 1) + { + var autowireCandidates = new List(); + foreach (var objectName in objectNamesForType) + { + if (GetObjectDefinition(objectName).IsAutowireCandidate) + { + autowireCandidates.Add(objectName); + } + } + + if (autowireCandidates.Count > 0) + { + objectNamesForType = autowireCandidates; + } } - /// - /// Return the object instances that match the given object - /// (including subclasses), judging from either object - /// definitions or the value of - /// in the case of - /// s. - /// - /// - /// The (class or interface) to match. - /// - /// - /// A of the matching objects, - /// containing the object names as keys and the corresponding object instances - /// as values. - /// - /// - /// If the objects could not be created. - /// - /// - public IReadOnlyDictionary GetObjectsOfType(Type type) + if ((objectNamesForType == null) || objectNamesForType.Count == 0) { - return GetObjectsOfType(type, true, true); + throw new NoSuchObjectDefinitionException(typeof(T).FullName, "Requested Type not Defined in the Context."); } - /// - /// Return the object instances that match the given object - /// (including subclasses), judging from either object - /// definitions or the value of - /// in the case of - /// s. - /// - /// - ///

- /// This version of the - /// method matches all kinds of object definitions, be they singletons, prototypes, or - /// s. Typically, the results - /// of this method call will be the same as a call to - /// IListableObjectFactory.GetObjectsOfType(type,true,true) . - ///

- ///
- /// - /// The (class or interface) to match. - /// - /// - /// A of the matching objects, - /// containing the object names as keys and the corresponding object instances - /// as values. - /// - /// - /// If the objects could not be created. - /// - public IReadOnlyDictionary GetObjects() + if (objectNamesForType.Count == 1) { - Dictionary result = new Dictionary(); - DoGetObjectsOfType(typeof(T), true, true, result); - return result; + return (T) GetObject(objectNamesForType[0]); } - /// - /// Return the object instances that match the given object - /// (including subclasses). - /// - /// - /// The (class or interface) to match. - /// - /// - /// Whether to include prototype objects too or just singletons (also applies to - /// s). - /// - /// - /// Whether to include s too - /// or just normal objects. - /// - /// - /// An of the matching objects, - /// containing the object names as keys and the corresponding object instances - /// as values. - /// - /// - /// If any of the objects could not be created. - /// - /// - public IReadOnlyDictionary GetObjectsOfType(Type type, bool includePrototypes, bool includeFactoryObjects) + if (objectNamesForType.Count == 0 && ParentObjectFactory != null) { - Dictionary result = new Dictionary(); - DoGetObjectsOfType(type, includePrototypes, includeFactoryObjects, result); - return result; + return ParentObjectFactory.GetObject(); } - private void DoGetObjectsOfType(Type type, bool includePrototypes, bool includeFactoryObjects, IDictionary resultCollector) + throw new NoSuchObjectDefinitionException(typeof(T), "expected single bean but found " + + objectNamesForType.Count + ": " + StringUtils.ArrayToCommaDelimitedString(objectNamesForType)); + } + + /// + /// Return the object instances that match the given object + /// (including subclasses). + /// + /// + /// The (class or interface) to match. + /// + /// + /// Whether to include prototype objects too or just singletons (also applies to + /// s). + /// + /// + /// Whether to include s too + /// or just normal objects. + /// + /// + /// An of the matching objects, + /// containing the object names as keys and the corresponding object instances + /// as values. + /// + /// + /// If any of the objects could not be created. + /// + /// + protected List DoGetObjectNamesForType(Type type, bool includeNonSingletons, bool allowEagerInit) + { + List result = new List(); + var objectNames = GetObjectDefinitionNames(true); + for (var i = 0; i < objectNames.Count; i++) { - IList objectNames = DoGetObjectNamesForType(type, includePrototypes, includeFactoryObjects); - foreach (string objectName in objectNames) + string s = objectNames[i]; + string objectName = s; + if (!IsAlias(objectName)) { try { - resultCollector.Add(objectName, GetObject(objectName)); - } - catch (ObjectCreationException ex) - { - if (ex.InnerException != null - && ex.GetBaseException().GetType().Equals(typeof(ObjectCurrentlyInCreationException))) + RootObjectDefinition mod = GetMergedObjectDefinition(objectName, true); + // Only check object definition if it is complete + if (!mod.IsAbstract && + (allowEagerInit || + (mod.HasObjectType || !mod.IsLazyInit /*|| this.AllowEagerTypeLoading*/) && + !RequiresEagerInitForType(mod.FactoryObjectName))) { - // ignoring this is ok... it indicates a circular reference when autowiring - // constructors; we want to find matches other than the currently - // created object itself... - if (log.IsEnabled(LogLevel.Debug)) + bool isFactoryObject = IsFactoryObject(objectName, mod); + bool matchFound = + (allowEagerInit || !isFactoryObject || ContainsSingleton(objectName)) && + (includeNonSingletons || IsSingleton(objectName)) && IsTypeMatch(objectName, type); + if (!matchFound && isFactoryObject) { - string message = string.Format( - CultureInfo.InvariantCulture, - "Ignoring match to currently created object '{0}'.", - objectName); - log.LogDebug(ex, message); + // in case of a FactoryObject, try to match FactoryObject instance itself next + objectName = ObjectFactoryUtils.BuildFactoryObjectName(objectName); + matchFound = (includeNonSingletons || mod.IsSingleton) && IsTypeMatch(objectName, type); + } + + if (matchFound) + { + result.Add(objectName); } } - else + } + catch (CannotLoadObjectTypeException ex) + { + if (allowEagerInit) { throw; } + + // Probably contains a placeholder; lets ignore it for type matching purposes. + if (log.IsEnabled(LogLevel.Debug)) + { + string message = "Ignoring object class loading failure for object '" + objectName + "'"; + log.LogDebug(ex, message); + } + } + catch (ObjectDefinitionStoreException ex) + { + if (allowEagerInit) + { + throw; + } + + // Probably contains a placeholder; lets ignore it for type matching purposes. + if (log.IsEnabled(LogLevel.Debug)) + { + string message = "Ignoring unresolvable metadata in object definition '" + objectName + "'"; + log.LogDebug(ex, message); + } } } } - /// - /// Return the object instances that match the given object - /// (including subclasses), judging from either object - /// definitions or the value of - /// in the case of - /// s. - /// - /// - /// The (class or interface) to match. - /// - /// - /// Whether to include prototype objects too or just singletons (also applies to - /// s). - /// - /// - /// Whether to include s too - /// or just normal objects. - /// - /// - /// A of the matching objects, - /// containing the object names as keys and the corresponding object instances - /// as values. - /// - /// - /// If the objects could not be created. - /// - public IReadOnlyDictionary GetObjects(bool includePrototypes, bool includeFactoryObjects) + // check singletons too, to catch manually registered singletons... + foreach (string s in manualSingletonNames) { - Dictionary result = new Dictionary(); - DoGetObjectsOfType(typeof(T), includePrototypes, includeFactoryObjects, result); - return result; - } - - /// - /// Return an instance (possibly shared or independent) of the given object name. - /// - /// - /// - /// This method allows an object factory to be used as a replacement for the - /// Singleton or Prototype design pattern. - /// - /// - /// Note that callers should retain references to returned objects. There is no - /// guarantee that this method will be implemented to be efficient. For example, - /// it may be synchronized, or may need to run an RDBMS query. - /// - /// - /// Will ask the parent factory if the object cannot be found in this factory - /// instance. - /// - /// - /// The type of the object to return. - /// The instance of the object. - /// - /// If there's no such object definition. - /// - /// - /// If there is more than a single object of the requested type defined in the factory. - /// - /// - /// If the object could not be created. - /// - public override T GetObject() - { - var objectNamesForType = GetObjectNamesForType(typeof(T)); - - if (objectNamesForType.Count > 1) + string objectName = s; + // in the case of an IFactoryObject, match the object created by the IFactoryObject... + if (IsFactoryObject(objectName)) { - var autowireCandidates = new List(); - foreach (var objectName in objectNamesForType) - { - if (GetObjectDefinition(objectName).IsAutowireCandidate) - { - autowireCandidates.Add(objectName); - } - - } - - if (autowireCandidates.Count > 0) - { - objectNamesForType = autowireCandidates; - } - } - - if ((objectNamesForType == null) || objectNamesForType.Count == 0) - { - throw new NoSuchObjectDefinitionException(typeof(T).FullName, "Requested Type not Defined in the Context."); - } - - if (objectNamesForType.Count == 1) - { - return (T)GetObject(objectNamesForType[0]); - } - - if (objectNamesForType.Count == 0 && ParentObjectFactory != null) - { - return ParentObjectFactory.GetObject(); - } - - throw new NoSuchObjectDefinitionException(typeof(T), "expected single bean but found " + - objectNamesForType.Count + ": " + StringUtils.ArrayToCommaDelimitedString(objectNamesForType)); - } - - /// - /// Return the object instances that match the given object - /// (including subclasses). - /// - /// - /// The (class or interface) to match. - /// - /// - /// Whether to include prototype objects too or just singletons (also applies to - /// s). - /// - /// - /// Whether to include s too - /// or just normal objects. - /// - /// - /// An of the matching objects, - /// containing the object names as keys and the corresponding object instances - /// as values. - /// - /// - /// If any of the objects could not be created. - /// - /// - protected List DoGetObjectNamesForType(Type type, bool includeNonSingletons, bool allowEagerInit) - { - List result = new List(); - var objectNames = GetObjectDefinitionNames(true); - for (var i = 0; i < objectNames.Count; i++) - { - string s = objectNames[i]; - string objectName = s; - if (!IsAlias(objectName)) - { - try - { - RootObjectDefinition mod = GetMergedObjectDefinition(objectName, true); - // Only check object definition if it is complete - if (!mod.IsAbstract && - (allowEagerInit || - (mod.HasObjectType || !mod.IsLazyInit /*|| this.AllowEagerTypeLoading*/) && - !RequiresEagerInitForType(mod.FactoryObjectName))) - { - bool isFactoryObject = IsFactoryObject(objectName, mod); - bool matchFound = - (allowEagerInit || !isFactoryObject || ContainsSingleton(objectName)) && - (includeNonSingletons || IsSingleton(objectName)) && IsTypeMatch(objectName, type); - if (!matchFound && isFactoryObject) - { - // in case of a FactoryObject, try to match FactoryObject instance itself next - objectName = ObjectFactoryUtils.BuildFactoryObjectName(objectName); - matchFound = (includeNonSingletons || mod.IsSingleton) && IsTypeMatch(objectName, type); - } - - if (matchFound) - { - result.Add(objectName); - } - } - } - catch (CannotLoadObjectTypeException ex) - { - if (allowEagerInit) - { - throw; - } - - // Probably contains a placeholder; lets ignore it for type matching purposes. - if (log.IsEnabled(LogLevel.Debug)) - { - string message = "Ignoring object class loading failure for object '" + objectName + "'"; - log.LogDebug(ex, message); - } - } - catch (ObjectDefinitionStoreException ex) - { - if (allowEagerInit) - { - throw; - } - - // Probably contains a placeholder; lets ignore it for type matching purposes. - if (log.IsEnabled(LogLevel.Debug)) - { - string message = "Ignoring unresolvable metadata in object definition '" + objectName + "'"; - log.LogDebug(ex, message); - } - } - } - } - - // check singletons too, to catch manually registered singletons... - foreach (string s in manualSingletonNames) - { - string objectName = s; - // in the case of an IFactoryObject, match the object created by the IFactoryObject... - if (IsFactoryObject(objectName)) - { - if ((includeNonSingletons || IsSingleton(objectName)) && IsTypeMatch(objectName, type)) - { - result.Add(objectName); - continue; - } - - objectName = ObjectFactoryUtils.BuildFactoryObjectName(objectName); - } - - if (IsTypeMatch(objectName, type)) + if ((includeNonSingletons || IsSingleton(objectName)) && IsTypeMatch(objectName, type)) { result.Add(objectName); + continue; } + + objectName = ObjectFactoryUtils.BuildFactoryObjectName(objectName); } - return result; - } - - /// - /// Check whether the specified bean would need to be eagerly initialized - /// in order to determine its type. - /// - /// a factory-bean reference that the bean definition defines a factory method for - /// whether eager initialization is necessary - private bool RequiresEagerInitForType(String factoryObjectName) - { - return (factoryObjectName != null && IsFactoryObject(factoryObjectName) && !ContainsSingleton(factoryObjectName)); - } - - /// - /// Check whether the given bean is defined as a . - /// - /// the name of the object - /// the corresponding object definition - protected bool IsFactoryObject(String objectName, RootObjectDefinition rod) - { - Type objectType = PredictObjectType(objectName, rod); - return (objectType != null && typeof(IFactoryObject).IsAssignableFrom(objectType)); - } - - /// - /// Resolve the specified dependency against the objects defined in this factory. - /// - /// The descriptor for the dependency. - /// Name of the object which declares the present dependency. - /// A list that all names of autowired object (used for - /// resolving the present dependency) are supposed to be added to. - /// - /// the resolved object, or null if none found - /// - /// if dependency resolution failed - public override object ResolveDependency( - DependencyDescriptor descriptor, - string objectName, - IList autowiredObjectNames) - { - Type type = descriptor.DependencyType; - Object value = AutowireCandidateResolver.GetSuggestedValue(descriptor); - if (value != null) + if (IsTypeMatch(objectName, type)) { - if (value is string) - { - object valueBefore = value; - value = ResolveEmbeddedValue((string) value); - if (valueBefore.Equals(value)) - value = ExpressionEvaluator.GetValue(null, (string) value); - } - return TypeConversionUtils.ConvertValueIfNecessary(type, value, null); - } - - if (type.IsArray) - { - Type elementType = type.GetElementType(); - var matchingObjects = FindAutowireCandidates(objectName, elementType, descriptor); - if (matchingObjects.Count == 0) - { - if (descriptor.Required) - { - RaiseNoSuchObjectDefinitionException(elementType, "array of " + elementType.FullName, descriptor); - } - return null; - } - if (autowiredObjectNames != null) - { - foreach (var matchingObject in matchingObjects) - { - autowiredObjectNames.Add(matchingObject.Key); - } - } - return TypeConversionUtils.ConvertValueIfNecessary(type, matchingObjects.Values, null); + result.Add(objectName); } - else if (type.IsGenericType && - (type.GetGenericTypeDefinition() == typeof(IList<>) || type.GetGenericTypeDefinition() == typeof(Collections.Generic.ISet<>) || - type.GetGenericTypeDefinition() == typeof(IDictionary<,>))) + } + + return result; + } + + /// + /// Check whether the specified bean would need to be eagerly initialized + /// in order to determine its type. + /// + /// a factory-bean reference that the bean definition defines a factory method for + /// whether eager initialization is necessary + private bool RequiresEagerInitForType(String factoryObjectName) + { + return (factoryObjectName != null && IsFactoryObject(factoryObjectName) && !ContainsSingleton(factoryObjectName)); + } + + /// + /// Check whether the given bean is defined as a . + /// + /// the name of the object + /// the corresponding object definition + protected bool IsFactoryObject(String objectName, RootObjectDefinition rod) + { + Type objectType = PredictObjectType(objectName, rod); + return (objectType != null && typeof(IFactoryObject).IsAssignableFrom(objectType)); + } + + /// + /// Resolve the specified dependency against the objects defined in this factory. + /// + /// The descriptor for the dependency. + /// Name of the object which declares the present dependency. + /// A list that all names of autowired object (used for + /// resolving the present dependency) are supposed to be added to. + /// + /// the resolved object, or null if none found + /// + /// if dependency resolution failed + public override object ResolveDependency( + DependencyDescriptor descriptor, + string objectName, + IList autowiredObjectNames) + { + Type type = descriptor.DependencyType; + Object value = AutowireCandidateResolver.GetSuggestedValue(descriptor); + if (value != null) + { + if (value is string) { - var isDictionary = (type.GetGenericTypeDefinition() == typeof (IDictionary<,>)); - var elementType = isDictionary ? type.GetGenericArguments()[1] : type.GetGenericArguments()[0]; - - if (isDictionary && type.GetGenericArguments()[0] != typeof(string)) - throw new NoSuchObjectDefinitionException(type, - "expected first generic to be a string but is " + type.GetGenericArguments()[0]); - - var matchingObjects = FindAutowireCandidates(objectName, elementType, descriptor); - if (matchingObjects.Count == 0) - { - if (descriptor.Required) - { - RaiseNoSuchObjectDefinitionException(elementType, "dictionary/list/set of " + elementType.FullName, descriptor); - } - return null; - } - if (autowiredObjectNames != null) - { - foreach (var matchingObject in matchingObjects) - { - autowiredObjectNames.Add(matchingObject.Key); - } - } - - return isDictionary - ? TypeConversionUtils.ConvertValueIfNecessary(type, matchingObjects, null) - : TypeConversionUtils.ConvertValueIfNecessary(type, matchingObjects.Values, null); + object valueBefore = value; + value = ResolveEmbeddedValue((string) value); + if (valueBefore.Equals(value)) + value = ExpressionEvaluator.GetValue(null, (string) value); } - else if (typeof(ICollection).IsAssignableFrom(type) && type.IsInterface) + + return TypeConversionUtils.ConvertValueIfNecessary(type, value, null); + } + + if (type.IsArray) + { + Type elementType = type.GetElementType(); + var matchingObjects = FindAutowireCandidates(objectName, elementType, descriptor); + if (matchingObjects.Count == 0) { - //TODO - handle generic types. + if (descriptor.Required) + { + RaiseNoSuchObjectDefinitionException(elementType, "array of " + elementType.FullName, descriptor); + } + return null; - } - else + + if (autowiredObjectNames != null) { - var matchingObjects = FindAutowireCandidates(objectName, type, descriptor); - if (matchingObjects.Count == 0) + foreach (var matchingObject in matchingObjects) { - if (descriptor.Required) - { - string methodType = (descriptor.MethodParameter.ConstructorInfo != null) ? "constructor" : "method"; - throw new NoSuchObjectDefinitionException(type, - "Unsatisfied dependency of type [" + type + "]: expected at least 1 matching object to wire the [" - + descriptor.MethodParameter.ParameterName() + "] parameter on the " + methodType + " of object [" + objectName + "]"); - } - return null; + autowiredObjectNames.Add(matchingObject.Key); } - if (matchingObjects.Count > 1) - { - string primaryObjecName = DeterminePrimaryCandidate(matchingObjects, descriptor); - if (primaryObjecName == null) - { - throw new NoSuchObjectDefinitionException(type, - "expected single matching object but found " + matchingObjects.Count + ": " + matchingObjects); - } - - autowiredObjectNames?.Add(primaryObjecName); - return matchingObjects[primaryObjecName]; - } - var entry = (KeyValuePair) ObjectUtils.EnumerateFirstElement(matchingObjects); - autowiredObjectNames?.Add(entry.Key); - return entry.Value; } + + return TypeConversionUtils.ConvertValueIfNecessary(type, matchingObjects.Values, null); } - - /// - /// Determine the primary autowire candidate in the given set of beans. - /// - /// a Map of candidate names and candidate instances - /// that match the required type - /// the target dependency to match against - /// the name of the primary candidate, or null if none found - private string DeterminePrimaryCandidate(IDictionary candidateObjects, DependencyDescriptor descriptor) { - string primaryObjectName = null; - string fallbackObjectName = null; - foreach(DictionaryEntry entry in candidateObjects) - { - string candidateBeanName = entry.Key as string; - object objectInstance = entry.Value; - if (IsPrimary(candidateBeanName, objectInstance)) - { - if (primaryObjectName != null) - { - bool candidateLocal = ContainsObjectDefinition(candidateBeanName); - bool primaryLocal = ContainsObjectDefinition(primaryObjectName); - if (candidateLocal == primaryLocal) - { - throw new NoSuchObjectDefinitionException(descriptor.DependencyType, - "more than one 'primary' bean found among candidates: " + candidateObjects); - } - if (candidateLocal && !primaryLocal) - { - primaryObjectName = candidateBeanName; - } - } - else - { - primaryObjectName = candidateBeanName; - } - } - if (primaryObjectName == null && - (resolvableDependencies.Values.Contains(objectInstance) || - MatchesObjectName(candidateBeanName, descriptor.DependencyName))) - { - fallbackObjectName = candidateBeanName; - } - } - return (primaryObjectName ?? fallbackObjectName); - } - - /// - /// Return whether the object definition for the given object name has been - /// marked as a primary object. - /// - /// the name of the bean - /// the corresponding bean instance - /// whether the given bean qualifies as primary - private bool IsPrimary(string objectName, object objectInstance) { - if (ContainsObjectDefinition(objectName)) { - return GetMergedObjectDefinition(objectName, true).IsPrimary; - } - return (ParentObjectFactory is DefaultListableObjectFactory && - ((DefaultListableObjectFactory)ParentObjectFactory).IsPrimary(objectName, objectInstance)); - } - - /// - /// Determine whether the given candidate name matches the bean name or the aliases - ///stored in this bean definition. - /// - protected bool MatchesObjectName(string objectName, string candidateName) + else if (type.IsGenericType && + (type.GetGenericTypeDefinition() == typeof(IList<>) || type.GetGenericTypeDefinition() == typeof(Collections.Generic.ISet<>) || + type.GetGenericTypeDefinition() == typeof(IDictionary<,>))) { - return (candidateName != null && - (candidateName.Equals(objectName) || DoGetAliases(objectName).Contains(candidateName))); - } + var isDictionary = (type.GetGenericTypeDefinition() == typeof(IDictionary<,>)); + var elementType = isDictionary ? type.GetGenericArguments()[1] : type.GetGenericArguments()[0]; - /// - /// Raises the no such object definition exception for an unresolvable dependency - /// - /// The type. - /// The dependency description. - /// The descriptor. - private void RaiseNoSuchObjectDefinitionException(Type type, string dependencyDescription, DependencyDescriptor descriptor) - { - throw new NoSuchObjectDefinitionException(type, dependencyDescription, - "expected at least 1 object which qualifies as autowire candidate for this dependency. "); - } + if (isDictionary && type.GetGenericArguments()[0] != typeof(string)) + throw new NoSuchObjectDefinitionException(type, + "expected first generic to be a string but is " + type.GetGenericArguments()[0]); - private Dictionary FindAutowireCandidates(string objectName, Type requiredType, DependencyDescriptor descriptor) - { - var candidateNames = ObjectFactoryUtils.ObjectNamesForTypeIncludingAncestors(this, requiredType, true, descriptor.Eager); - var result = new Dictionary(candidateNames.Count); - - foreach (var entry in resolvableDependencies) + var matchingObjects = FindAutowireCandidates(objectName, elementType, descriptor); + if (matchingObjects.Count == 0) { - Type autoWiringType = entry.Key; - if (autoWiringType.IsAssignableFrom(requiredType)) + if (descriptor.Required) { - object autowiringValue = resolvableDependencies[autoWiringType]; - if (requiredType.IsInstanceOfType(autowiringValue)) - { - result.Add(ObjectUtils.IdentityToString(autowiringValue), autowiringValue); - break; - } + RaiseNoSuchObjectDefinitionException(elementType, "dictionary/list/set of " + elementType.FullName, descriptor); + } + + return null; + } + + if (autowiredObjectNames != null) + { + foreach (var matchingObject in matchingObjects) + { + autowiredObjectNames.Add(matchingObject.Key); } } - for (int i = 0; i < candidateNames.Count; i++) - { - string candidateName = candidateNames[i]; - if (!candidateName.Equals(objectName) && IsAutowireCandidate(candidateName, descriptor)) - { - result.Add(candidateName, GetObject(candidateName)); - } - } - return result; + return isDictionary + ? TypeConversionUtils.ConvertValueIfNecessary(type, matchingObjects, null) + : TypeConversionUtils.ConvertValueIfNecessary(type, matchingObjects.Values, null); } - - /// - /// Determines whether the specified object qualifies as an autowire candidate, - /// to be injected into other beans which declare a dependency of matching type. - /// This method checks ancestor factories as well. - /// - /// Name of the object to check. - /// The descriptor of the dependency to resolve. - /// - /// true if the object should be considered as an autowire candidate; otherwise, false. - /// - /// if there is no object with the given name. - public bool IsAutowireCandidate(string objectName, DependencyDescriptor descriptor) + else if (typeof(ICollection).IsAssignableFrom(type) && type.IsInterface) { - //Consider FactoryObjects as autowiring candidates. - bool isFactoryObject = (descriptor != null && descriptor.DependencyType != null && - typeof(IFactoryObject).IsAssignableFrom(descriptor.DependencyType)); - if (isFactoryObject) - { - objectName = ObjectFactoryUtils.TransformedObjectName(objectName); - } - - if (!ContainsObjectDefinition(objectName)) - { - if (ContainsSingleton(objectName)) - { - return true; - } - else if (ParentObjectFactory is IConfigurableListableObjectFactory) - { - // No object definition found in this factory -> delegate to parent - return - ((IConfigurableListableObjectFactory)ParentObjectFactory).IsAutowireCandidate(objectName, descriptor); - } - } - return IsAutowireCandidate(objectName, GetMergedObjectDefinition(objectName, true), descriptor); + //TODO - handle generic types. + return null; } - - /// - /// Determine whether the specified object definition qualifies as an autowire candidate, - /// to be injected into other beans which declare a dependency of matching type. - /// - /// Name of the object definition to check. - /// The merged object definiton to check. - /// The descriptor of the dependency to resolve. - /// - /// true if the object should be considered as an autowire candidate; otherwise, false. - /// - private bool IsAutowireCandidate(string objectName, RootObjectDefinition rod, DependencyDescriptor descriptor) + else { - ResolveObjectType(rod, objectName); - return - AutowireCandidateResolver.IsAutowireCandidate( - new ObjectDefinitionHolder(rod, objectName, GetAliases(objectName)), descriptor); + var matchingObjects = FindAutowireCandidates(objectName, type, descriptor); + if (matchingObjects.Count == 0) + { + if (descriptor.Required) + { + string methodType = (descriptor.MethodParameter.ConstructorInfo != null) ? "constructor" : "method"; + throw new NoSuchObjectDefinitionException(type, + "Unsatisfied dependency of type [" + type + "]: expected at least 1 matching object to wire the [" + + descriptor.MethodParameter.ParameterName() + "] parameter on the " + methodType + " of object [" + objectName + "]"); + } + + return null; + } + + if (matchingObjects.Count > 1) + { + string primaryObjecName = DeterminePrimaryCandidate(matchingObjects, descriptor); + if (primaryObjecName == null) + { + throw new NoSuchObjectDefinitionException(type, + "expected single matching object but found " + matchingObjects.Count + ": " + matchingObjects); + } + + autowiredObjectNames?.Add(primaryObjecName); + return matchingObjects[primaryObjecName]; + } + + var entry = (KeyValuePair) ObjectUtils.EnumerateFirstElement(matchingObjects); + autowiredObjectNames?.Add(entry.Key); + return entry.Value; } } + + /// + /// Determine the primary autowire candidate in the given set of beans. + /// + /// a Map of candidate names and candidate instances + /// that match the required type + /// the target dependency to match against + /// the name of the primary candidate, or null if none found + private string DeterminePrimaryCandidate(IDictionary candidateObjects, DependencyDescriptor descriptor) + { + string primaryObjectName = null; + string fallbackObjectName = null; + foreach (DictionaryEntry entry in candidateObjects) + { + string candidateBeanName = entry.Key as string; + object objectInstance = entry.Value; + if (IsPrimary(candidateBeanName, objectInstance)) + { + if (primaryObjectName != null) + { + bool candidateLocal = ContainsObjectDefinition(candidateBeanName); + bool primaryLocal = ContainsObjectDefinition(primaryObjectName); + if (candidateLocal == primaryLocal) + { + throw new NoSuchObjectDefinitionException(descriptor.DependencyType, + "more than one 'primary' bean found among candidates: " + candidateObjects); + } + + if (candidateLocal && !primaryLocal) + { + primaryObjectName = candidateBeanName; + } + } + else + { + primaryObjectName = candidateBeanName; + } + } + + if (primaryObjectName == null && + (resolvableDependencies.Values.Contains(objectInstance) || + MatchesObjectName(candidateBeanName, descriptor.DependencyName))) + { + fallbackObjectName = candidateBeanName; + } + } + + return (primaryObjectName ?? fallbackObjectName); + } + + /// + /// Return whether the object definition for the given object name has been + /// marked as a primary object. + /// + /// the name of the bean + /// the corresponding bean instance + /// whether the given bean qualifies as primary + private bool IsPrimary(string objectName, object objectInstance) + { + if (ContainsObjectDefinition(objectName)) + { + return GetMergedObjectDefinition(objectName, true).IsPrimary; + } + + return (ParentObjectFactory is DefaultListableObjectFactory && + ((DefaultListableObjectFactory) ParentObjectFactory).IsPrimary(objectName, objectInstance)); + } + + /// + /// Determine whether the given candidate name matches the bean name or the aliases + ///stored in this bean definition. + /// + protected bool MatchesObjectName(string objectName, string candidateName) + { + return (candidateName != null && + (candidateName.Equals(objectName) || DoGetAliases(objectName).Contains(candidateName))); + } + + /// + /// Raises the no such object definition exception for an unresolvable dependency + /// + /// The type. + /// The dependency description. + /// The descriptor. + private void RaiseNoSuchObjectDefinitionException(Type type, string dependencyDescription, DependencyDescriptor descriptor) + { + throw new NoSuchObjectDefinitionException(type, dependencyDescription, + "expected at least 1 object which qualifies as autowire candidate for this dependency. "); + } + + private Dictionary FindAutowireCandidates(string objectName, Type requiredType, DependencyDescriptor descriptor) + { + var candidateNames = ObjectFactoryUtils.ObjectNamesForTypeIncludingAncestors(this, requiredType, true, descriptor.Eager); + var result = new Dictionary(candidateNames.Count); + + foreach (var entry in resolvableDependencies) + { + Type autoWiringType = entry.Key; + if (autoWiringType.IsAssignableFrom(requiredType)) + { + object autowiringValue = resolvableDependencies[autoWiringType]; + if (requiredType.IsInstanceOfType(autowiringValue)) + { + result.Add(ObjectUtils.IdentityToString(autowiringValue), autowiringValue); + break; + } + } + } + + for (int i = 0; i < candidateNames.Count; i++) + { + string candidateName = candidateNames[i]; + if (!candidateName.Equals(objectName) && IsAutowireCandidate(candidateName, descriptor)) + { + result.Add(candidateName, GetObject(candidateName)); + } + } + + return result; + } + + /// + /// Determines whether the specified object qualifies as an autowire candidate, + /// to be injected into other beans which declare a dependency of matching type. + /// This method checks ancestor factories as well. + /// + /// Name of the object to check. + /// The descriptor of the dependency to resolve. + /// + /// true if the object should be considered as an autowire candidate; otherwise, false. + /// + /// if there is no object with the given name. + public bool IsAutowireCandidate(string objectName, DependencyDescriptor descriptor) + { + //Consider FactoryObjects as autowiring candidates. + bool isFactoryObject = (descriptor != null && descriptor.DependencyType != null && + typeof(IFactoryObject).IsAssignableFrom(descriptor.DependencyType)); + if (isFactoryObject) + { + objectName = ObjectFactoryUtils.TransformedObjectName(objectName); + } + + if (!ContainsObjectDefinition(objectName)) + { + if (ContainsSingleton(objectName)) + { + return true; + } + else if (ParentObjectFactory is IConfigurableListableObjectFactory) + { + // No object definition found in this factory -> delegate to parent + return + ((IConfigurableListableObjectFactory) ParentObjectFactory).IsAutowireCandidate(objectName, descriptor); + } + } + + return IsAutowireCandidate(objectName, GetMergedObjectDefinition(objectName, true), descriptor); + } + + /// + /// Determine whether the specified object definition qualifies as an autowire candidate, + /// to be injected into other beans which declare a dependency of matching type. + /// + /// Name of the object definition to check. + /// The merged object definiton to check. + /// The descriptor of the dependency to resolve. + /// + /// true if the object should be considered as an autowire candidate; otherwise, false. + /// + private bool IsAutowireCandidate(string objectName, RootObjectDefinition rod, DependencyDescriptor descriptor) + { + ResolveObjectType(rod, objectName); + return + AutowireCandidateResolver.IsAutowireCandidate( + new ObjectDefinitionHolder(rod, objectName, GetAliases(objectName)), descriptor); + } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/DefaultObjectDefinitionFactory.cs b/src/Spring/Spring.Core/Objects/Factory/Support/DefaultObjectDefinitionFactory.cs index fc687c14..927459a9 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/DefaultObjectDefinitionFactory.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/DefaultObjectDefinitionFactory.cs @@ -17,80 +17,79 @@ using Spring.Core.TypeResolution; using Spring.Util; -namespace Spring.Objects.Factory.Support -{ - /// - /// Default implementation of the - /// - /// interface. - /// - /// - ///

- /// Does not support per - /// loading. - ///

- ///
- /// Aleksandar Seovic - [Serializable] - public class DefaultObjectDefinitionFactory : IObjectDefinitionFactory - { - /// - /// Factory style method for getting concrete - /// - /// instances. - /// - /// /// If no parent is specified, a RootObjectDefinition is created, otherwise a - /// ChildObjectDefinition. - /// The of the defined object. - /// The name of the parent object definition (if any). - /// The against which any class names - /// will be resolved into instances. - /// - /// An - /// - /// instance. - /// - public virtual AbstractObjectDefinition CreateObjectDefinition(string typeName, string parent, AppDomain domain) - { - Type objectType = null; - if (StringUtils.HasText(typeName) && domain != null) - { - try - { - objectType = TypeResolutionUtils.ResolveType(typeName); - } - // try later.... - catch { } - } - if (StringUtils.IsNullOrEmpty(parent)) - { - if (objectType != null) - { - return new RootObjectDefinition(objectType); +namespace Spring.Objects.Factory.Support; - } - else - { - RootObjectDefinition rootObjectDefinition = new RootObjectDefinition(); - rootObjectDefinition.ObjectTypeName = typeName; - return rootObjectDefinition; - } +/// +/// Default implementation of the +/// +/// interface. +/// +/// +///

+/// Does not support per +/// loading. +///

+///
+/// Aleksandar Seovic +[Serializable] +public class DefaultObjectDefinitionFactory : IObjectDefinitionFactory +{ + /// + /// Factory style method for getting concrete + /// + /// instances. + /// + /// /// If no parent is specified, a RootObjectDefinition is created, otherwise a + /// ChildObjectDefinition. + /// The of the defined object. + /// The name of the parent object definition (if any). + /// The against which any class names + /// will be resolved into instances. + /// + /// An + /// + /// instance. + /// + public virtual AbstractObjectDefinition CreateObjectDefinition(string typeName, string parent, AppDomain domain) + { + Type objectType = null; + if (StringUtils.HasText(typeName) && domain != null) + { + try + { + objectType = TypeResolutionUtils.ResolveType(typeName); + } + // try later.... + catch { } + } + + if (StringUtils.IsNullOrEmpty(parent)) + { + if (objectType != null) + { + return new RootObjectDefinition(objectType); } else { - if (objectType != null) - { - ChildObjectDefinition childObjectDefinition = new ChildObjectDefinition(parent); - childObjectDefinition.ObjectType = objectType; - return childObjectDefinition; - } - else - { - ChildObjectDefinition childObjectDefinition = new ChildObjectDefinition(parent); - childObjectDefinition.ObjectTypeName = typeName; - return childObjectDefinition; - } + RootObjectDefinition rootObjectDefinition = new RootObjectDefinition(); + rootObjectDefinition.ObjectTypeName = typeName; + return rootObjectDefinition; } - } - } + } + else + { + if (objectType != null) + { + ChildObjectDefinition childObjectDefinition = new ChildObjectDefinition(parent); + childObjectDefinition.ObjectType = objectType; + return childObjectDefinition; + } + else + { + ChildObjectDefinition childObjectDefinition = new ChildObjectDefinition(parent); + childObjectDefinition.ObjectTypeName = typeName; + return childObjectDefinition; + } + } + } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/DefaultObjectNameGenerator.cs b/src/Spring/Spring.Core/Objects/Factory/Support/DefaultObjectNameGenerator.cs index 3f4bdf9b..60e20213 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/DefaultObjectNameGenerator.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/DefaultObjectNameGenerator.cs @@ -20,41 +20,41 @@ using Spring.Objects.Factory.Config; -namespace Spring.Objects.Factory.Support -{ - /// - /// Default implementation of the interface, deleagting to - /// 's GenerateObjectName. - /// - /// Note that this implementation is only able to handle - /// subclasses such as - /// and - /// - /// Juergen Hoeller - /// Mark Pollack (.NET) - public class DefaultObjectNameGenerator : IObjectNameGenerator - { - #region IObjectNameGenerator Members +namespace Spring.Objects.Factory.Support; - /// - /// Generates an object name for the given object definition. - /// - /// The object definition to generate a name for. - /// The object definitions registry that the given definition is - /// supposed to be registerd with - /// the generated object name - public string GenerateObjectName(IObjectDefinition definition, IObjectDefinitionRegistry registry) +/// +/// Default implementation of the interface, deleagting to +/// 's GenerateObjectName. +/// +/// Note that this implementation is only able to handle +/// subclasses such as +/// and +/// +/// Juergen Hoeller +/// Mark Pollack (.NET) +public class DefaultObjectNameGenerator : IObjectNameGenerator +{ + #region IObjectNameGenerator Members + + /// + /// Generates an object name for the given object definition. + /// + /// The object definition to generate a name for. + /// The object definitions registry that the given definition is + /// supposed to be registerd with + /// the generated object name + public string GenerateObjectName(IObjectDefinition definition, IObjectDefinitionRegistry registry) + { + IConfigurableObjectDefinition objectDef = definition as IConfigurableObjectDefinition; + if (objectDef == null) { - IConfigurableObjectDefinition objectDef = definition as IConfigurableObjectDefinition; - if (objectDef == null) - { - throw new ArgumentException( - "DefaultObjectNameGenerator is only able to handle IConfigurableObjectDefinition subclasses: " + - definition); - } - return ObjectDefinitionReaderUtils.GenerateObjectName(objectDef, registry); + throw new ArgumentException( + "DefaultObjectNameGenerator is only able to handle IConfigurableObjectDefinition subclasses: " + + definition); } - #endregion + return ObjectDefinitionReaderUtils.GenerateObjectName(objectDef, registry); } + + #endregion } diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/DelegateInvokingFactoryObject.cs b/src/Spring/Spring.Core/Objects/Factory/Support/DelegateInvokingFactoryObject.cs index 267be067..c3ff0320 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/DelegateInvokingFactoryObject.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/DelegateInvokingFactoryObject.cs @@ -18,74 +18,71 @@ #endregion -namespace Spring.Objects.Factory.Support +namespace Spring.Objects.Factory.Support; + +/// +/// Convenience implementation of the interface that +/// delegates to an arbitrary object + method to perform the object construction. +/// +/// +/// +/// Because this implementation requires a delegate +/// passed to its ctor, its only possible to configure this object and register +/// it with the via code rather than via XML. +/// +/// +/// +public class DelegateInvokingFactoryObject : IFactoryObject { + private readonly bool _isSingleton; + private readonly Func _builderDelegate; + /// - /// Convenience implementation of the interface that - /// delegates to an arbitrary object + method to perform the object construction. + /// Initializes a new instance of the class. + /// + /// The builder delegate. + /// if set to true [is singleton]. + public DelegateInvokingFactoryObject(Func builderDelegate, bool isSingleton) + { + _builderDelegate = builderDelegate; + _isSingleton = isSingleton; + } + + /// + /// Return an instance (possibly shared or independent) of the object + /// managed by this factory. /// /// - /// - /// Because this implementation requires a delegate - /// passed to its ctor, its only possible to configure this object and register - /// it with the via code rather than via XML. - /// + /// If this method is being called in the context of an enclosing IoC container and + /// returns , the IoC container will consider this factory + /// object as not being fully initialized and throw a corresponding (and most + /// probably fatal) exception. + /// /// - /// - public class DelegateInvokingFactoryObject : IFactoryObject + /// + /// An instance (possibly shared or independent) of the object managed by + /// this factory. + /// + public object GetObject() { - private readonly bool _isSingleton; - private readonly Func _builderDelegate; + return _builderDelegate.Invoke(); + } + /// + /// Return the of object that this + /// creates, or + /// if not known in advance. + /// + public Type ObjectType + { + get { return typeof(T); } + } - /// - /// Initializes a new instance of the class. - /// - /// The builder delegate. - /// if set to true [is singleton]. - public DelegateInvokingFactoryObject(Func builderDelegate, bool isSingleton) - { - _builderDelegate = builderDelegate; - _isSingleton = isSingleton; - } - - - /// - /// Return an instance (possibly shared or independent) of the object - /// managed by this factory. - /// - /// - /// If this method is being called in the context of an enclosing IoC container and - /// returns , the IoC container will consider this factory - /// object as not being fully initialized and throw a corresponding (and most - /// probably fatal) exception. - /// - /// - /// - /// An instance (possibly shared or independent) of the object managed by - /// this factory. - /// - public object GetObject() - { - return _builderDelegate.Invoke(); - } - - /// - /// Return the of object that this - /// creates, or - /// if not known in advance. - /// - public Type ObjectType - { - get { return typeof(T); } - } - - /// - /// Is the object managed by this factory a singleton or a prototype? - /// - public bool IsSingleton - { - get { return _isSingleton; } - } + /// + /// Is the object managed by this factory a singleton or a prototype? + /// + public bool IsSingleton + { + get { return _isSingleton; } } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/DelegatingMethodReplacer.cs b/src/Spring/Spring.Core/Objects/Factory/Support/DelegatingMethodReplacer.cs index 9ce08eb2..190cd076 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/DelegatingMethodReplacer.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/DelegatingMethodReplacer.cs @@ -20,65 +20,64 @@ using System.Reflection; -namespace Spring.Objects.Factory.Support -{ - /// - /// An - /// implementation that delegates to an - /// that is - /// obtained as the result of a lookup in an associated IoC container. - /// - /// - ///

- /// This class is reserved for internal use within the framework; it is - /// not intended to be used by application developers using Spring.NET. - ///

- ///
- /// Rick Evans - public sealed class DelegatingMethodReplacer : AbstractMethodReplacer - { - /// - /// Creates a new instance of the - /// - /// class. - /// - /// - /// The object definition that is the target of the method replacement. - /// - /// - /// The enclosing IoC container with which the above - /// is associated. - /// - /// - /// If either of the supplied arguments is . - /// - public DelegatingMethodReplacer(IConfigurableObjectDefinition objectDefinition, IObjectFactory objectFactory) - : base(objectDefinition, objectFactory) - { - } +namespace Spring.Objects.Factory.Support; - /// - /// Reimplements the supplied by delegating to - /// another - /// looked up in an enclosing IoC container. - /// - /// - /// The instance whose is to be - /// (re)implemented. - /// - /// - /// The method that is to be (re)implemented. - /// - /// The target method's arguments. - /// - /// The result of the delegated call to the looked up - /// . - /// - public override object Implement(object target, MethodInfo method, object[] arguments) - { - ReplacedMethodOverride ovr = (ReplacedMethodOverride) GetOverride(method); - IMethodReplacer methodReplacement = (IMethodReplacer) GetObject(ovr.MethodReplacerObjectName); - return methodReplacement.Implement(target, method, arguments); - } - } +/// +/// An +/// implementation that delegates to an +/// that is +/// obtained as the result of a lookup in an associated IoC container. +/// +/// +///

+/// This class is reserved for internal use within the framework; it is +/// not intended to be used by application developers using Spring.NET. +///

+///
+/// Rick Evans +public sealed class DelegatingMethodReplacer : AbstractMethodReplacer +{ + /// + /// Creates a new instance of the + /// + /// class. + /// + /// + /// The object definition that is the target of the method replacement. + /// + /// + /// The enclosing IoC container with which the above + /// is associated. + /// + /// + /// If either of the supplied arguments is . + /// + public DelegatingMethodReplacer(IConfigurableObjectDefinition objectDefinition, IObjectFactory objectFactory) + : base(objectDefinition, objectFactory) + { + } + + /// + /// Reimplements the supplied by delegating to + /// another + /// looked up in an enclosing IoC container. + /// + /// + /// The instance whose is to be + /// (re)implemented. + /// + /// + /// The method that is to be (re)implemented. + /// + /// The target method's arguments. + /// + /// The result of the delegated call to the looked up + /// . + /// + public override object Implement(object target, MethodInfo method, object[] arguments) + { + ReplacedMethodOverride ovr = (ReplacedMethodOverride) GetOverride(method); + IMethodReplacer methodReplacement = (IMethodReplacer) GetObject(ovr.MethodReplacerObjectName); + return methodReplacement.Implement(target, method, arguments); + } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/DependencyCheckingMode.cs b/src/Spring/Spring.Core/Objects/Factory/Support/DependencyCheckingMode.cs index 6d9cc10d..0759e04c 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/DependencyCheckingMode.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/DependencyCheckingMode.cs @@ -18,33 +18,32 @@ #endregion -namespace Spring.Objects.Factory.Support { +namespace Spring.Objects.Factory.Support; - /// - /// The various modes of dependency checking. +/// +/// The various modes of dependency checking. +/// +/// Rick Evans (.NET) +[Serializable] +public enum DependencyCheckingMode +{ + /// + /// DO not do any dependency checking. /// - /// Rick Evans (.NET) - [Serializable] - public enum DependencyCheckingMode - { - /// - /// DO not do any dependency checking. - /// - None = 0, + None = 0, - /// - /// Check object references. - /// - Objects = 1, + /// + /// Check object references. + /// + Objects = 1, - /// - /// Just check primitive (string, int, etc) values. - /// - Simple = 2, + /// + /// Just check primitive (string, int, etc) values. + /// + Simple = 2, - /// - /// Check everything. - /// - All = 3 - } + /// + /// Check everything. + /// + All = 3 } diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/DisposableObjectAdapter.cs b/src/Spring/Spring.Core/Objects/Factory/Support/DisposableObjectAdapter.cs index 8f1771e1..5d3f1ce2 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/DisposableObjectAdapter.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/DisposableObjectAdapter.cs @@ -3,247 +3,248 @@ using Microsoft.Extensions.Logging; using Spring.Objects.Factory.Config; using Spring.Util; -namespace Spring.Objects.Factory.Support +namespace Spring.Objects.Factory.Support; + +public class DisposableObjectAdapter : IDisposable { - public class DisposableObjectAdapter : IDisposable + private readonly ILogger logger = LogManager.GetLogger(); + + private object instance; + + private string objectName; + + private bool invokeDisposableObject; + + private string destroyMethodName; + + private MethodInfo destroyMethod; + + private List objectPostProcessors; + + /// + /// Create a new DisposableBeanAdapter for the given bean. + /// + /// The bean instance (never null). + /// Name of the bean. + /// The merged bean definition. + /// the List of BeanPostProcessors (potentially IDestructionAwareBeanPostProcessor), if any. + public DisposableObjectAdapter(object instance, string objectName, RootObjectDefinition objectDefinition, IReadOnlyCollection postProcessors) { - private readonly ILogger logger = LogManager.GetLogger(); + AssertUtils.ArgumentNotNull(instance, "Disposable object must not be null"); - private object instance; + this.instance = instance; + this.objectName = objectName; + this.invokeDisposableObject = (this.instance is IDisposable); // && !beanDefinition.IsExternallyManagedDestroyMethod("destroy")); - private string objectName; - - private bool invokeDisposableObject; - - private string destroyMethodName; - - private MethodInfo destroyMethod; - - private List objectPostProcessors; - - /// - /// Create a new DisposableBeanAdapter for the given bean. - /// - /// The bean instance (never null). - /// Name of the bean. - /// The merged bean definition. - /// the List of BeanPostProcessors (potentially IDestructionAwareBeanPostProcessor), if any. - public DisposableObjectAdapter(object instance, string objectName, RootObjectDefinition objectDefinition, IReadOnlyCollection postProcessors) + if (null == objectDefinition) { - AssertUtils.ArgumentNotNull(instance, "Disposable object must not be null"); - - this.instance = instance; - this.objectName = objectName; - this.invokeDisposableObject = (this.instance is IDisposable); // && !beanDefinition.IsExternallyManagedDestroyMethod("destroy")); - - if (null == objectDefinition) - { - return; - } - - InferDestroyMethodIfNecessary(objectDefinition); - - string definedDestroyMethodName = objectDefinition.DestroyMethodName; - - if (definedDestroyMethodName != null && !(this.invokeDisposableObject && "Destroy".Equals(definedDestroyMethodName))) // && !beanDefinition.isExternallyManagedDestroyMethod(destroyMethodName)) - { - this.destroyMethodName = definedDestroyMethodName; - this.destroyMethod = DetermineDestroyMethod(); - if (this.destroyMethod == null) - { - //TODO: add support for Enforcing Destroy Method - //if (beanDefinition.IsEnforceDestroyMethod()) { - // throw new BeanDefinitionValidationException("Couldn't find a destroy method named '" + - // destroyMethodName + "' on bean with name '" + beanName + "'"); - //} - } - else - { - Type[] paramTypes = ReflectionUtils.GetParameterTypes(this.destroyMethod); - if (paramTypes.Length > 1) - { - throw new ObjectDefinitionValidationException("Method '" + definedDestroyMethodName + "' of object '" + - objectName + "' has more than one parameter - not supported as Destroy Method"); - } - else if (paramTypes.Length == 1 && !(paramTypes[0] == typeof(bool))) - { - throw new ObjectDefinitionValidationException("Method '" + definedDestroyMethodName + "' of object '" + - objectName + "' has a non-boolean parameter - not supported as Destroy Method"); - } - } - } - this.objectPostProcessors = FilterPostProcessors(postProcessors); + return; } - private void InferDestroyMethodIfNecessary(RootObjectDefinition beanDefinition) + InferDestroyMethodIfNecessary(objectDefinition); + + string definedDestroyMethodName = objectDefinition.DestroyMethodName; + + if (definedDestroyMethodName != null && !(this.invokeDisposableObject && "Destroy".Equals(definedDestroyMethodName))) // && !beanDefinition.isExternallyManagedDestroyMethod(destroyMethodName)) { - if ("(Inferred)".Equals(beanDefinition.DestroyMethodName)) + this.destroyMethodName = definedDestroyMethodName; + this.destroyMethod = DetermineDestroyMethod(); + if (this.destroyMethod == null) + { + //TODO: add support for Enforcing Destroy Method + //if (beanDefinition.IsEnforceDestroyMethod()) { + // throw new BeanDefinitionValidationException("Couldn't find a destroy method named '" + + // destroyMethodName + "' on bean with name '" + beanName + "'"); + //} + } + else + { + Type[] paramTypes = ReflectionUtils.GetParameterTypes(this.destroyMethod); + if (paramTypes.Length > 1) + { + throw new ObjectDefinitionValidationException("Method '" + definedDestroyMethodName + "' of object '" + + objectName + "' has more than one parameter - not supported as Destroy Method"); + } + else if (paramTypes.Length == 1 && !(paramTypes[0] == typeof(bool))) + { + throw new ObjectDefinitionValidationException("Method '" + definedDestroyMethodName + "' of object '" + + objectName + "' has a non-boolean parameter - not supported as Destroy Method"); + } + } + } + + this.objectPostProcessors = FilterPostProcessors(postProcessors); + } + + private void InferDestroyMethodIfNecessary(RootObjectDefinition beanDefinition) + { + if ("(Inferred)".Equals(beanDefinition.DestroyMethodName)) + { + try + { + MethodInfo candidate = ReflectionUtils.GetMethod(instance.GetType(), "Close", null); + if (candidate.IsPublic) + { + beanDefinition.DestroyMethodName = candidate.Name; + } + } + catch (MissingMethodException) + { + // no candidate destroy method found + beanDefinition.DestroyMethodName = null; + } + } + } + + /// + /// Search for all s in the List. + /// + /// The List to search. + /// the filtered List of IDestructionAwareObjectPostProcessors. + private List FilterPostProcessors(IReadOnlyCollection postProcessors) + { + List filteredPostProcessors = null; + if (postProcessors != null && postProcessors.Count != 0) + { + filteredPostProcessors = new List(postProcessors.Count); + filteredPostProcessors.AddRange(postProcessors.OfType()); + } + + return filteredPostProcessors; + } + + /// + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// + public void Dispose() + { + if (this.objectPostProcessors != null && this.objectPostProcessors.Count != 0) + { + foreach (IDestructionAwareObjectPostProcessor processor in this.objectPostProcessors) { try { - MethodInfo candidate = ReflectionUtils.GetMethod(instance.GetType(), "Close", null); - if (candidate.IsPublic) - { - beanDefinition.DestroyMethodName = candidate.Name; - } - } - catch (MissingMethodException) - { - // no candidate destroy method found - beanDefinition.DestroyMethodName = null; - } - } - } - - /// - /// Search for all s in the List. - /// - /// The List to search. - /// the filtered List of IDestructionAwareObjectPostProcessors. - private List FilterPostProcessors(IReadOnlyCollection postProcessors) - { - List filteredPostProcessors = null; - if (postProcessors != null && postProcessors.Count != 0) - { - filteredPostProcessors = new List(postProcessors.Count); - filteredPostProcessors.AddRange(postProcessors.OfType()); - } - return filteredPostProcessors; - } - - /// - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - /// - public void Dispose() - { - if (this.objectPostProcessors != null && this.objectPostProcessors.Count != 0) - { - foreach (IDestructionAwareObjectPostProcessor processor in this.objectPostProcessors) - { - try - { - processor.PostProcessBeforeDestruction(this.instance, this.objectName); - } - - catch (Exception ex) - { - logger.LogError(ex, "Error during execution of {Type}.PostProcessBeforeDestruction for object {ObjectName}", processor.GetType().Name, this.objectName); - } - } - } - - if (this.invokeDisposableObject) - { - if (logger.IsEnabled(LogLevel.Debug)) - { - logger.LogDebug("Invoking Dispose() on object with name '" + this.objectName + "'"); - } - try - { - ((IDisposable)instance).Dispose(); - + processor.PostProcessBeforeDestruction(this.instance, this.objectName); } catch (Exception ex) { - string msg = "Invocation of Dispose method failed on object with name '" + this.objectName + "'"; - if (logger.IsEnabled(LogLevel.Debug)) - { - logger.LogWarning(ex, msg); - } - else - { - logger.LogWarning(msg + ": " + ex); - } - } - } - - if (this.destroyMethod != null) - { - InvokeCustomDestroyMethod(this.destroyMethod); - } - else if (this.destroyMethodName != null) - { - MethodInfo methodToCall = DetermineDestroyMethod(); - if (methodToCall != null) - { - InvokeCustomDestroyMethod(methodToCall); + logger.LogError(ex, "Error during execution of {Type}.PostProcessBeforeDestruction for object {ObjectName}", processor.GetType().Name, this.objectName); } } } - - private MethodInfo DetermineDestroyMethod() + if (this.invokeDisposableObject) { - try - { - return FindDestroyMethod(); - } - - catch (ArgumentException ex) - { - throw new ObjectDefinitionValidationException("Couldn't find a unique Destroy Method on object with name '" + - this.objectName + ": " + ex.Message); - } - } - - private MethodInfo FindDestroyMethod() - { - try - { - return ReflectionUtils.GetMethod(instance.GetType(), this.destroyMethodName, null); - } - catch (Exception) - { - return null; - } - } - - /// - /// Invokes the custom destroy method. - /// - /// The custom destroy method. - /// Invoke the specified custom destroy method on the given bean. - /// This implementation invokes a no-arg method if found, else checking - /// for a method with a single boolean argument (passing in "true", - /// assuming a "force" parameter), else logging an error. - private void InvokeCustomDestroyMethod(MethodInfo customDestroyMethod) - { - Type[] paramTypes = ReflectionUtils.GetParameterTypes(customDestroyMethod); - object[] args = new object[paramTypes.Length]; - if (paramTypes.Length == 1) - { - args[0] = true; - } if (logger.IsEnabled(LogLevel.Debug)) { - logger.LogDebug("Invoking destroy method '" + this.destroyMethodName + - "' on object with name '" + this.objectName + "'"); + logger.LogDebug("Invoking Dispose() on object with name '" + this.objectName + "'"); } + try { - - customDestroyMethod.Invoke(instance, args); + ((IDisposable) instance).Dispose(); } - catch (TargetInvocationException ex) + + catch (Exception ex) { - string msg = "Invocation of destroy method '" + this.destroyMethodName + - "' failed on object with name '" + this.objectName + "'"; + string msg = "Invocation of Dispose method failed on object with name '" + this.objectName + "'"; if (logger.IsEnabled(LogLevel.Debug)) { - logger.LogWarning(ex.InnerException, msg); + logger.LogWarning(ex, msg); } else { - logger.LogWarning(msg + ": " + ex.InnerException); + logger.LogWarning(msg + ": " + ex); } } - catch (Exception ex) + } + + if (this.destroyMethod != null) + { + InvokeCustomDestroyMethod(this.destroyMethod); + } + else if (this.destroyMethodName != null) + { + MethodInfo methodToCall = DetermineDestroyMethod(); + if (methodToCall != null) { - string message = "Couldn't invoke destroy method '" + this.destroyMethodName + - "' on object with name '" + this.objectName + "'"; - logger.LogError(ex, message); + InvokeCustomDestroyMethod(methodToCall); } } } + + private MethodInfo DetermineDestroyMethod() + { + try + { + return FindDestroyMethod(); + } + + catch (ArgumentException ex) + { + throw new ObjectDefinitionValidationException("Couldn't find a unique Destroy Method on object with name '" + + this.objectName + ": " + ex.Message); + } + } + + private MethodInfo FindDestroyMethod() + { + try + { + return ReflectionUtils.GetMethod(instance.GetType(), this.destroyMethodName, null); + } + catch (Exception) + { + return null; + } + } + + /// + /// Invokes the custom destroy method. + /// + /// The custom destroy method. + /// Invoke the specified custom destroy method on the given bean. + /// This implementation invokes a no-arg method if found, else checking + /// for a method with a single boolean argument (passing in "true", + /// assuming a "force" parameter), else logging an error. + private void InvokeCustomDestroyMethod(MethodInfo customDestroyMethod) + { + Type[] paramTypes = ReflectionUtils.GetParameterTypes(customDestroyMethod); + object[] args = new object[paramTypes.Length]; + if (paramTypes.Length == 1) + { + args[0] = true; + } + + if (logger.IsEnabled(LogLevel.Debug)) + { + logger.LogDebug("Invoking destroy method '" + this.destroyMethodName + + "' on object with name '" + this.objectName + "'"); + } + + try + { + customDestroyMethod.Invoke(instance, args); + } + catch (TargetInvocationException ex) + { + string msg = "Invocation of destroy method '" + this.destroyMethodName + + "' failed on object with name '" + this.objectName + "'"; + if (logger.IsEnabled(LogLevel.Debug)) + { + logger.LogWarning(ex.InnerException, msg); + } + else + { + logger.LogWarning(msg + ": " + ex.InnerException); + } + } + catch (Exception ex) + { + string message = "Couldn't invoke destroy method '" + this.destroyMethodName + + "' on object with name '" + this.objectName + "'"; + logger.LogError(ex, message); + } + } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/GenericObjectDefinition.cs b/src/Spring/Spring.Core/Objects/Factory/Support/GenericObjectDefinition.cs index ebfa7f0f..e094d320 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/GenericObjectDefinition.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/GenericObjectDefinition.cs @@ -20,67 +20,68 @@ using Spring.Objects.Factory.Config; -namespace Spring.Objects.Factory.Support +namespace Spring.Objects.Factory.Support; + +/// +/// GenericObjectDefinition is a one-stop shop for standard object definition purposes. +/// Like any object definition, it allows for specifying a class plus optionally +/// constructor argument values and property values. Additionally, deriving from a +/// parent bean definition can be flexibly configured through the "parentName" property. +/// +/// In general, use this class for the purpose of +/// registering user-visible object definitions (which a post-processor might operate on, +/// potentially even reconfiguring the parent name). +/// Use / +/// where parent/child relationships happen to be pre-determined. +/// +/// +/// +/// Juergen Hoeller +/// Erich Eichinger +[Serializable] +public class GenericObjectDefinition : AbstractObjectDefinition { + private string parentName; + /// - /// GenericObjectDefinition is a one-stop shop for standard object definition purposes. - /// Like any object definition, it allows for specifying a class plus optionally - /// constructor argument values and property values. Additionally, deriving from a - /// parent bean definition can be flexibly configured through the "parentName" property. + /// The name of the parent object definition. /// - /// In general, use this class for the purpose of - /// registering user-visible object definitions (which a post-processor might operate on, - /// potentially even reconfiguring the parent name). - /// Use / - /// where parent/child relationships happen to be pre-determined. + /// + /// This value is required. /// - /// - /// - /// Juergen Hoeller - /// Erich Eichinger - [Serializable] - public class GenericObjectDefinition : AbstractObjectDefinition + /// + /// The name of the parent object definition. + /// + public override string ParentName { - private string parentName; + get { return parentName; } + set { parentName = value; } + } - /// - /// The name of the parent object definition. - /// - /// - /// This value is required. - /// - /// - /// The name of the parent object definition. - /// - public override string ParentName + /// + /// Creates a new to be configured through its + /// object properties and configuration methods. + /// + public GenericObjectDefinition() + { + } + + /// + /// Creates a new as deep copy of the given + /// object definition. + /// + /// the original object definition to copy from + public GenericObjectDefinition(IObjectDefinition original) + : base(original) + { + GenericObjectDefinition god = original as GenericObjectDefinition; + if (god != null) { - get { return parentName; } - set { parentName = value; } + this.parentName = god.parentName; } + } - /// - /// Creates a new to be configured through its - /// object properties and configuration methods. - /// - public GenericObjectDefinition() - { } - - /// - /// Creates a new as deep copy of the given - /// object definition. - /// - /// the original object definition to copy from - public GenericObjectDefinition(IObjectDefinition original) - : base(original) - { - GenericObjectDefinition god = original as GenericObjectDefinition; - if (god != null) - { - this.parentName = god.parentName; - } - } - - /* TODO (EE): this is not supported atm, need to implement AbstractObjectDefinition.Equals() first */ + /* TODO (EE): this is not supported atm, need to implement AbstractObjectDefinition.Equals() first */ // /// // /// Checks, if equals this object definition. // /// @@ -97,13 +98,12 @@ namespace Spring.Objects.Factory.Support // return base.GetHashCode(); // } - /// - /// Returns a representation of this - /// for debugging purposes. - /// - public override string ToString() - { - return "Generic Object:" + base.ToString(); - } + /// + /// Returns a representation of this + /// for debugging purposes. + /// + public override string ToString() + { + return "Generic Object:" + base.ToString(); } -} +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/IAutowireCandidateResolver.cs b/src/Spring/Spring.Core/Objects/Factory/Support/IAutowireCandidateResolver.cs index 3d5e9ab6..b350f8f8 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/IAutowireCandidateResolver.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/IAutowireCandidateResolver.cs @@ -20,37 +20,34 @@ using Spring.Objects.Factory.Config; -namespace Spring.Objects.Factory.Support +namespace Spring.Objects.Factory.Support; + +/// +/// Strategy interface for determining whether a specific object definition +/// qualifies as an autowire candidate for a specific dependency. +/// +/// Mark Fisher +/// Juergen hoeller +/// Mark Pollack (.NET) +public interface IAutowireCandidateResolver { /// - /// Strategy interface for determining whether a specific object definition - /// qualifies as an autowire candidate for a specific dependency. + /// Determines whether the given object definition qualifies as an + /// autowire candidate for the given dependency. /// - /// Mark Fisher - /// Juergen hoeller - /// Mark Pollack (.NET) - public interface IAutowireCandidateResolver - { - /// - /// Determines whether the given object definition qualifies as an - /// autowire candidate for the given dependency. - /// - /// The object definition including object name and aliases. - /// The descriptor for the target method parameter or field. - /// - /// true if the object definition qualifies as autowire candidate; otherwise, false. - /// - bool IsAutowireCandidate(ObjectDefinitionHolder odHolder, DependencyDescriptor descriptor); + /// The object definition including object name and aliases. + /// The descriptor for the target method parameter or field. + /// + /// true if the object definition qualifies as autowire candidate; otherwise, false. + /// + bool IsAutowireCandidate(ObjectDefinitionHolder odHolder, DependencyDescriptor descriptor); - - /// - /// Determine whether a default value is suggested for the given dependency. - /// - /// The descriptor for the target method parameter or field - /// The value suggested (typically an expression String), - /// or null if none found - /// - Object GetSuggestedValue(DependencyDescriptor descriptor); - - } + /// + /// Determine whether a default value is suggested for the given dependency. + /// + /// The descriptor for the target method parameter or field + /// The value suggested (typically an expression String), + /// or null if none found + /// + Object GetSuggestedValue(DependencyDescriptor descriptor); } diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/IConfigurableObjectDefinition.cs b/src/Spring/Spring.Core/Objects/Factory/Support/IConfigurableObjectDefinition.cs index 0a5ab838..159af3b3 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/IConfigurableObjectDefinition.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/IConfigurableObjectDefinition.cs @@ -20,186 +20,185 @@ using Spring.Objects.Factory.Config; -namespace Spring.Objects.Factory.Support +namespace Spring.Objects.Factory.Support; + +/// +/// Describes a configurable object instance, which has property values, +/// constructor argument values, and further information supplied by concrete +/// implementations. +/// +/// Rick Evans +public interface IConfigurableObjectDefinition : IObjectDefinition { /// - /// Describes a configurable object instance, which has property values, - /// constructor argument values, and further information supplied by concrete - /// implementations. + /// Return the property values to be applied to a new instance of the object. /// - /// Rick Evans - public interface IConfigurableObjectDefinition : IObjectDefinition - { - /// - /// Return the property values to be applied to a new instance of the object. - /// - new MutablePropertyValues PropertyValues { get; set; } + new MutablePropertyValues PropertyValues { get; set; } - /// - /// Return the constructor argument values for this object. - /// - new ConstructorArgumentValues ConstructorArgumentValues { get; set; } + /// + /// Return the constructor argument values for this object. + /// + new ConstructorArgumentValues ConstructorArgumentValues { get; set; } - /// - /// The method overrides (if any) for this object. - /// - /// - /// The method overrides (if any) for this object; may be an - /// empty collection but is guaranteed not to be - /// . - /// - MethodOverrides MethodOverrides { get; set; } + /// + /// The method overrides (if any) for this object. + /// + /// + /// The method overrides (if any) for this object; may be an + /// empty collection but is guaranteed not to be + /// . + /// + MethodOverrides MethodOverrides { get; set; } - /// - /// Return the event handlers for any events exposed by this object. - /// - new EventValues EventHandlerValues { get; set; } + /// + /// Return the event handlers for any events exposed by this object. + /// + new EventValues EventHandlerValues { get; set; } - /// - /// Get or set the role hint for this object definition - /// - new ObjectRole Role { get; set; } + /// + /// Get or set the role hint for this object definition + /// + new ObjectRole Role { get; set; } - /// - /// Return a description of the resource that this object definition - /// came from (for the purpose of showing context in case of errors). - /// - new string ResourceDescription { get; set; } + /// + /// Return a description of the resource that this object definition + /// came from (for the purpose of showing context in case of errors). + /// + new string ResourceDescription { get; set; } - /// - /// Is this object definition "abstract", i.e. not meant to be instantiated - /// itself but rather just serving as parent for concrete child object - /// definitions. - /// - /// - /// if this object definition is "abstract". - /// - new bool IsAbstract { get; set; } + /// + /// Is this object definition "abstract", i.e. not meant to be instantiated + /// itself but rather just serving as parent for concrete child object + /// definitions. + /// + /// + /// if this object definition is "abstract". + /// + new bool IsAbstract { get; set; } - /// - /// Returns the of the object definition (if any). - /// - /// - /// A resolved object . - /// - /// - /// If the of the object definition is not a - /// resolved or . - /// - new Type ObjectType { get; set; } + /// + /// Returns the of the object definition (if any). + /// + /// + /// A resolved object . + /// + /// + /// If the of the object definition is not a + /// resolved or . + /// + new Type ObjectType { get; set; } - /// - /// Returns the of the - /// of the object definition (if any). - /// - new string ObjectTypeName { get; set; } + /// + /// Returns the of the + /// of the object definition (if any). + /// + new string ObjectTypeName { get; set; } - /// - /// Return whether this a Singleton, with a single, shared instance - /// returned on all calls. - /// - /// - ///

- /// If , an object factory will apply the Prototype - /// design pattern, with each caller requesting an instance getting an - /// independent instance. How this is defined will depend on the - /// object factory implementation. Singletons are the commoner type. - ///

- ///
- new bool IsSingleton { get; set; } + /// + /// Return whether this a Singleton, with a single, shared instance + /// returned on all calls. + /// + /// + ///

+ /// If , an object factory will apply the Prototype + /// design pattern, with each caller requesting an instance getting an + /// independent instance. How this is defined will depend on the + /// object factory implementation. Singletons are the commoner type. + ///

+ ///
+ new bool IsSingleton { get; set; } - /// - /// Is this object lazily initialized? - /// - ///

- /// Only applicable to a singleton object. - ///

- ///

- /// If , it will get instantiated on startup by object factories - /// that perform eager initialization of singletons. - ///

- ///
- new bool IsLazyInit { get; set; } + /// + /// Is this object lazily initialized? + /// + ///

+ /// Only applicable to a singleton object. + ///

+ ///

+ /// If , it will get instantiated on startup by object factories + /// that perform eager initialization of singletons. + ///

+ ///
+ new bool IsLazyInit { get; set; } - /// - /// The autowire mode as specified in the object definition. - /// - /// - ///

- /// This determines whether any automagical detection and setting of - /// object references will happen. Default is - /// , - /// which means there's no autowire. - ///

- ///
- new AutoWiringMode AutowireMode { get; set; } + /// + /// The autowire mode as specified in the object definition. + /// + /// + ///

+ /// This determines whether any automagical detection and setting of + /// object references will happen. Default is + /// , + /// which means there's no autowire. + ///

+ ///
+ new AutoWiringMode AutowireMode { get; set; } - /// - /// The dependency check code. - /// - DependencyCheckingMode DependencyCheck { get; set; } + /// + /// The dependency check code. + /// + DependencyCheckingMode DependencyCheck { get; set; } - /// - /// The object names that this object depends on. - /// - /// - ///

- /// The object factory will guarantee that these objects get initialized - /// before. - ///

- ///

- /// Note that dependencies are normally expressed through object properties - /// or constructor arguments. This property should just be necessary for - /// other kinds of dependencies like statics (*ugh*) or database - /// preparation on startup. - ///

- ///
- new IReadOnlyList DependsOn { get; set; } + /// + /// The object names that this object depends on. + /// + /// + ///

+ /// The object factory will guarantee that these objects get initialized + /// before. + ///

+ ///

+ /// Note that dependencies are normally expressed through object properties + /// or constructor arguments. This property should just be necessary for + /// other kinds of dependencies like statics (*ugh*) or database + /// preparation on startup. + ///

+ ///
+ new IReadOnlyList DependsOn { get; set; } - /// - /// The name of the initializer method. - /// - /// - ///

- /// The default is , in which case there is no initializer method. - ///

- ///
- new string InitMethodName { get; set; } + /// + /// The name of the initializer method. + /// + /// + ///

+ /// The default is , in which case there is no initializer method. + ///

+ ///
+ new string InitMethodName { get; set; } - /// - /// Return the name of the destroy method. - /// - /// - ///

- /// The default is , in which case there is no destroy method. - ///

- ///
- new string DestroyMethodName { get; set; } + /// + /// Return the name of the destroy method. + /// + /// + ///

+ /// The default is , in which case there is no destroy method. + ///

+ ///
+ new string DestroyMethodName { get; set; } - /// - /// The name of the factory method to use (if any). - /// - /// - ///

- /// This method will be invoked with constructor arguments, or with no - /// arguments if none are specified. The static method will be invoked on - /// the specified . - ///

- ///
- new string FactoryMethodName { get; set; } + /// + /// The name of the factory method to use (if any). + /// + /// + ///

+ /// This method will be invoked with constructor arguments, or with no + /// arguments if none are specified. The static method will be invoked on + /// the specified . + ///

+ ///
+ new string FactoryMethodName { get; set; } - /// - /// The name of the factory object to use (if any). - /// - new string FactoryObjectName { get; set; } + /// + /// The name of the factory object to use (if any). + /// + new string FactoryObjectName { get; set; } - /// - /// Gets or sets a value indicating whether this instance a candidate for getting autowired into some other - /// object. - /// - /// - /// true if this instance is autowire candidate; otherwise, false. - /// - new bool IsAutowireCandidate { get; set; } - } + /// + /// Gets or sets a value indicating whether this instance a candidate for getting autowired into some other + /// object. + /// + /// + /// true if this instance is autowire candidate; otherwise, false. + /// + new bool IsAutowireCandidate { get; set; } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/IInstantiationStrategy.cs b/src/Spring/Spring.Core/Objects/Factory/Support/IInstantiationStrategy.cs index 4197a0ec..e740c9a2 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/IInstantiationStrategy.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/IInstantiationStrategy.cs @@ -20,95 +20,94 @@ using System.Reflection; -namespace Spring.Objects.Factory.Support +namespace Spring.Objects.Factory.Support; + +/// +/// Responsible for creating instances corresponding to a +/// . +/// +/// Rod Johnson +/// Rick Evans (.NET) +public interface IInstantiationStrategy { - /// - /// Responsible for creating instances corresponding to a - /// . - /// - /// Rod Johnson - /// Rick Evans (.NET) - public interface IInstantiationStrategy - { - /// - /// Instantiate an instance of the object described by the supplied - /// from the supplied . - /// - /// - /// The definition of the object that is to be instantiated. - /// - /// - /// The name associated with the object definition. The name can be the null - /// or zero length string if we're autowiring an object that doesn't belong - /// to the supplied . - /// - /// - /// The owning - /// - /// - /// An instance of the object described by the supplied - /// from the supplied . - /// - object Instantiate( - RootObjectDefinition definition, string name, IObjectFactory factory); + /// + /// Instantiate an instance of the object described by the supplied + /// from the supplied . + /// + /// + /// The definition of the object that is to be instantiated. + /// + /// + /// The name associated with the object definition. The name can be the null + /// or zero length string if we're autowiring an object that doesn't belong + /// to the supplied . + /// + /// + /// The owning + /// + /// + /// An instance of the object described by the supplied + /// from the supplied . + /// + object Instantiate( + RootObjectDefinition definition, string name, IObjectFactory factory); - /// - /// Instantiate an instance of the object described by the supplied - /// from the supplied . - /// - /// - /// The definition of the object that is to be instantiated. - /// - /// - /// The name associated with the object definition. The name can be the null - /// or zero length string if we're autowiring an object that doesn't belong - /// to the supplied . - /// - /// - /// The owning - /// - /// - /// The to be used to instantiate - /// the object. - /// - /// - /// Any arguments to the supplied . May be null. - /// - /// - /// An instance of the object described by the supplied - /// from the supplied . - /// - object Instantiate( - RootObjectDefinition definition, string name, IObjectFactory factory, - ConstructorInfo constructor, object[] arguments); + /// + /// Instantiate an instance of the object described by the supplied + /// from the supplied . + /// + /// + /// The definition of the object that is to be instantiated. + /// + /// + /// The name associated with the object definition. The name can be the null + /// or zero length string if we're autowiring an object that doesn't belong + /// to the supplied . + /// + /// + /// The owning + /// + /// + /// The to be used to instantiate + /// the object. + /// + /// + /// Any arguments to the supplied . May be null. + /// + /// + /// An instance of the object described by the supplied + /// from the supplied . + /// + object Instantiate( + RootObjectDefinition definition, string name, IObjectFactory factory, + ConstructorInfo constructor, object[] arguments); - /// - /// Instantiate an instance of the object described by the supplied - /// from the supplied . - /// - /// - /// The definition of the object that is to be instantiated. - /// - /// - /// The name associated with the object definition. The name can be the null - /// or zero length string if we're autowiring an object that doesn't belong - /// to the supplied . - /// - /// - /// The owning - /// - /// - /// The to be used to get the object. - /// - /// - /// Any arguments to the supplied . May be null. - /// - /// - /// An instance of the object described by the supplied - /// from the supplied . - /// - object Instantiate( - RootObjectDefinition definition, string name, IObjectFactory factory, - MethodInfo factoryMethod, object[] arguments); - } + /// + /// Instantiate an instance of the object described by the supplied + /// from the supplied . + /// + /// + /// The definition of the object that is to be instantiated. + /// + /// + /// The name associated with the object definition. The name can be the null + /// or zero length string if we're autowiring an object that doesn't belong + /// to the supplied . + /// + /// + /// The owning + /// + /// + /// The to be used to get the object. + /// + /// + /// Any arguments to the supplied . May be null. + /// + /// + /// An instance of the object described by the supplied + /// from the supplied . + /// + object Instantiate( + RootObjectDefinition definition, string name, IObjectFactory factory, + MethodInfo factoryMethod, object[] arguments); } diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/IMethodReplacer.cs b/src/Spring/Spring.Core/Objects/Factory/Support/IMethodReplacer.cs index f2993488..9b1021be 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/IMethodReplacer.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/IMethodReplacer.cs @@ -20,46 +20,45 @@ using System.Reflection; -namespace Spring.Objects.Factory.Support +namespace Spring.Objects.Factory.Support; + +/// +/// Permits the (re)implementation of an arbitrary method on a Spring.NET +/// IoC container managed object. +/// +/// +///

+/// Encapsulates the notion of the Method-Injection form of Dependency +/// Injection. +///

+///

+/// Methods that are dependency injected with implementations of this +/// interface may be (but need not be) , in which +/// case the container will create a concrete subclass of the +/// class prior to instantiation. +///

+///

+/// Do not use this mechanism as a means of AOP. See the reference +/// manual for examples of appropriate usages of this interface. +///

+///
+/// Rod Johnson +/// Rick Evans (.NET) +public interface IMethodReplacer { - /// - /// Permits the (re)implementation of an arbitrary method on a Spring.NET - /// IoC container managed object. - /// - /// - ///

- /// Encapsulates the notion of the Method-Injection form of Dependency - /// Injection. - ///

- ///

- /// Methods that are dependency injected with implementations of this - /// interface may be (but need not be) , in which - /// case the container will create a concrete subclass of the - /// class prior to instantiation. - ///

- ///

- /// Do not use this mechanism as a means of AOP. See the reference - /// manual for examples of appropriate usages of this interface. - ///

- ///
- /// Rod Johnson - /// Rick Evans (.NET) - public interface IMethodReplacer - { - /// - /// Reimplement the supplied . - /// - /// - /// The instance whose is to be - /// (re)implemented. - /// - /// - /// The method that is to be (re)implemented. - /// - /// The target method's arguments. - /// - /// The result of the (re)implementation of the method call. - /// - object Implement(object target, MethodInfo method, object[] arguments); - } + /// + /// Reimplement the supplied . + /// + /// + /// The instance whose is to be + /// (re)implemented. + /// + /// + /// The method that is to be (re)implemented. + /// + /// The target method's arguments. + /// + /// The result of the (re)implementation of the method call. + /// + object Implement(object target, MethodInfo method, object[] arguments); } diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/IObjectDefinitionReader.cs b/src/Spring/Spring.Core/Objects/Factory/Support/IObjectDefinitionReader.cs index 564e4c6c..6a01c521 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/IObjectDefinitionReader.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/IObjectDefinitionReader.cs @@ -20,102 +20,100 @@ using Spring.Core.IO; -namespace Spring.Objects.Factory.Support { +namespace Spring.Objects.Factory.Support; - /// - /// Simple interface for object definition readers. +/// +/// Simple interface for object definition readers. +/// +/// Juergen Hoeller +/// Rick Evans +public interface IObjectDefinitionReader +{ + /// + /// Gets the + /// + /// instance that this reader works on. /// - /// Juergen Hoeller - /// Rick Evans - public interface IObjectDefinitionReader + IObjectDefinitionRegistry Registry { - /// - /// Gets the - /// - /// instance that this reader works on. - /// - IObjectDefinitionRegistry Registry - { - get; - } + get; + } - /// - /// The against which any class names - /// will be resolved into instances. - /// - AppDomain Domain - { - get; - } + /// + /// The against which any class names + /// will be resolved into instances. + /// + AppDomain Domain + { + get; + } - /// - /// The to use for anonymous - /// objects (wihtout explicit object name specified). - /// - IObjectNameGenerator ObjectNameGenerator - { - get; - } + /// + /// The to use for anonymous + /// objects (wihtout explicit object name specified). + /// + IObjectNameGenerator ObjectNameGenerator + { + get; + } - /// - /// Gets the resource loader to use for resource locations. - /// - /// There is also a method - /// available for loading object definitions from a resource location. This is - /// a convenience to avoid explicit ResourceLoader handling. - /// The resource loader. - IResourceLoader ResourceLoader - { - get; - } + /// + /// Gets the resource loader to use for resource locations. + /// + /// There is also a method + /// available for loading object definitions from a resource location. This is + /// a convenience to avoid explicit ResourceLoader handling. + /// The resource loader. + IResourceLoader ResourceLoader + { + get; + } - /// - /// Load object definitions from the supplied . - /// - /// - /// The resource for the object definitions that are to be loaded. - /// - /// - /// The number of object definitions found - /// - /// - /// In the case of loading or parsing errors. - /// - int LoadObjectDefinitions (IResource resource); + /// + /// Load object definitions from the supplied . + /// + /// + /// The resource for the object definitions that are to be loaded. + /// + /// + /// The number of object definitions found + /// + /// + /// In the case of loading or parsing errors. + /// + int LoadObjectDefinitions(IResource resource); - /// - /// Load object definitions from the supplied . - /// - /// - /// The resources for the object definitions that are to be loaded. - /// - /// - /// The number of object definitions found - /// - /// - /// In the case of loading or parsing errors. - /// - int LoadObjectDefinitions(IResource[] resources); + /// + /// Load object definitions from the supplied . + /// + /// + /// The resources for the object definitions that are to be loaded. + /// + /// + /// The number of object definitions found + /// + /// + /// In the case of loading or parsing errors. + /// + int LoadObjectDefinitions(IResource[] resources); + /// + /// Loads the object definitions from the specified resource location. + /// + /// The resource location, to be loaded with the + /// IResourceLoader location . + /// + /// The number of object definitions found + /// + int LoadObjectDefinitions(string location); - /// - /// Loads the object definitions from the specified resource location. - /// - /// The resource location, to be loaded with the - /// IResourceLoader location . - /// - /// The number of object definitions found - /// - int LoadObjectDefinitions(string location); - - /// - /// Loads the object definitions from the specified resource locations. - /// - /// The the resource locations to be loaded with the - /// IResourceLoader of this object definition reader. - /// - /// The number of object definitions found - /// - int LoadObjectDefinitions(string[] locations); - } + /// + /// Loads the object definitions from the specified resource locations. + /// + /// The the resource locations to be loaded with the + /// IResourceLoader of this object definition reader. + /// + /// The number of object definitions found + /// + int LoadObjectDefinitions(string[] locations); } diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/IObjectDefinitionRegistry.cs b/src/Spring/Spring.Core/Objects/Factory/Support/IObjectDefinitionRegistry.cs index d4f0e850..fed266a7 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/IObjectDefinitionRegistry.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/IObjectDefinitionRegistry.cs @@ -20,151 +20,150 @@ using Spring.Objects.Factory.Config; -namespace Spring.Objects.Factory.Support +namespace Spring.Objects.Factory.Support; + +/// +/// Interface for registries that hold object definitions, i.e. +/// +/// and +/// +/// instances. +/// +/// +///

+/// Typically implemented by object factories that work with the +/// +/// hierarchy internally. +///

+///
+/// Juergen Hoeller +/// Rick Evans (.NET) +public interface IObjectDefinitionRegistry { - /// - /// Interface for registries that hold object definitions, i.e. + /// + /// Determine whether the given object name is already in use within this registry, + /// i.e. whether there is a local object or alias registered under this name. + /// + bool IsObjectNameInUse(string objectName); + + /// + /// Return the number of objects defined in the registry. + /// + /// + /// The number of objects defined in the registry. + /// + int ObjectDefinitionCount { get; } + + /// + /// Return the names of all objects defined in this registry. + /// + /// + /// The names of all objects defined in this registry, or an empty array + /// if none defined + /// + IReadOnlyList GetObjectDefinitionNames(); + + /// + /// Return the names of all objects defined in this registry. + /// If includeAncestors is true it includes all objects in the defined parent factories. + /// + /// to include parent factories in result + /// + /// The names of all objects defined in this registry, if includeAncestors is true it includes + /// all objects in the defined parent factories, or an empty array if none defined + /// + IReadOnlyList GetObjectDefinitionNames(bool includeAncestors); + + /// + /// Check if this registry contains a object definition with the given name. + /// + /// + /// The name of the object to look for. + /// + /// + /// True if this object factory contains an object definition with the + /// given name. + /// + bool ContainsObjectDefinition(string name); + + /// + /// Returns the + /// + /// for the given object name. + /// + /// + /// The name of the object to find a definition for. + /// + /// + /// The for + /// the given name (never null). + /// + /// + /// If the object definition cannot be resolved. + /// + /// + /// In case of errors. + /// + IObjectDefinition GetObjectDefinition(string name); + + /// + /// Register a new object definition with this registry. + /// Must support /// - /// and - /// - /// instances. - /// - /// - ///

- /// Typically implemented by object factories that work with the - /// - /// hierarchy internally. - ///

+ /// and . + ///
+ /// + /// The name of the object instance to register. + /// + /// + /// The definition of the object instance to register. + /// + /// + ///

+ /// Must support + /// and + /// . + ///

///
- /// Juergen Hoeller - /// Rick Evans (.NET) - public interface IObjectDefinitionRegistry - { - /// - /// Determine whether the given object name is already in use within this registry, - /// i.e. whether there is a local object or alias registered under this name. - /// - bool IsObjectNameInUse(string objectName); + /// + /// If the object definition is invalid. + /// + void RegisterObjectDefinition(string name, IObjectDefinition definition); - /// - /// Return the number of objects defined in the registry. - /// - /// - /// The number of objects defined in the registry. - /// - int ObjectDefinitionCount { get; } + /// + /// Return the aliases for the given object name, if defined. + /// + /// the object name to check for aliases + /// + /// + ///

+ /// Will ask the parent factory if the object cannot be found in this + /// factory instance. + ///

+ ///
+ /// + /// The aliases, or an empty array if none. + /// + /// + /// If there's no such object definition. + /// + IReadOnlyList GetAliases(string name); - /// - /// Return the names of all objects defined in this registry. - /// - /// - /// The names of all objects defined in this registry, or an empty array - /// if none defined - /// - IReadOnlyList GetObjectDefinitionNames(); - - /// - /// Return the names of all objects defined in this registry. - /// If includeAncestors is true it includes all objects in the defined parent factories. - /// - /// to include parent factories in result - /// - /// The names of all objects defined in this registry, if includeAncestors is true it includes - /// all objects in the defined parent factories, or an empty array if none defined - /// - IReadOnlyList GetObjectDefinitionNames(bool includeAncestors); - - /// - /// Check if this registry contains a object definition with the given name. - /// - /// - /// The name of the object to look for. - /// - /// - /// True if this object factory contains an object definition with the - /// given name. - /// - bool ContainsObjectDefinition (string name); - - /// - /// Returns the - /// - /// for the given object name. - /// - /// - /// The name of the object to find a definition for. - /// - /// - /// The for - /// the given name (never null). - /// - /// - /// If the object definition cannot be resolved. - /// - /// - /// In case of errors. - /// - IObjectDefinition GetObjectDefinition (string name); - - /// - /// Register a new object definition with this registry. - /// Must support - /// - /// and . - /// - /// - /// The name of the object instance to register. - /// - /// - /// The definition of the object instance to register. - /// - /// - ///

- /// Must support - /// and - /// . - ///

- ///
- /// - /// If the object definition is invalid. - /// - void RegisterObjectDefinition (string name, IObjectDefinition definition); - - /// - /// Return the aliases for the given object name, if defined. - /// - /// the object name to check for aliases - /// - /// - ///

- /// Will ask the parent factory if the object cannot be found in this - /// factory instance. - ///

- ///
- /// - /// The aliases, or an empty array if none. - /// - /// - /// If there's no such object definition. - /// - IReadOnlyList GetAliases (string name); - - /// - /// Given a object name, create an alias. We typically use this method to - /// support names that are illegal within XML ids (used for object names). - /// - /// - /// The name of the object. - /// - /// - /// The alias that will behave the same as the object name. - /// - /// - /// If there is no object with the given name. - /// - /// - /// If the alias is already in use. - /// - void RegisterAlias (string name, string theAlias); - } + /// + /// Given a object name, create an alias. We typically use this method to + /// support names that are illegal within XML ids (used for object names). + /// + /// + /// The name of the object. + /// + /// + /// The alias that will behave the same as the object name. + /// + /// + /// If there is no object with the given name. + /// + /// + /// If the alias is already in use. + /// + void RegisterAlias(string name, string theAlias); } diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/IObjectDefinitionRegistryPostProcessor.cs b/src/Spring/Spring.Core/Objects/Factory/Support/IObjectDefinitionRegistryPostProcessor.cs index 42d3506c..443a8b14 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/IObjectDefinitionRegistryPostProcessor.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/IObjectDefinitionRegistryPostProcessor.cs @@ -20,10 +20,9 @@ using Spring.Objects.Factory.Config; -namespace Spring.Objects.Factory.Support +namespace Spring.Objects.Factory.Support; + +public interface IObjectDefinitionRegistryPostProcessor : IObjectFactoryPostProcessor { - public interface IObjectDefinitionRegistryPostProcessor : IObjectFactoryPostProcessor - { - void PostProcessObjectDefinitionRegistry(IObjectDefinitionRegistry registry); - } -} \ No newline at end of file + void PostProcessObjectDefinitionRegistry(IObjectDefinitionRegistry registry); +} diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/IObjectNameGenerator.cs b/src/Spring/Spring.Core/Objects/Factory/Support/IObjectNameGenerator.cs index 1888ee00..ee4ffd56 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/IObjectNameGenerator.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/IObjectNameGenerator.cs @@ -20,23 +20,21 @@ using Spring.Objects.Factory.Config; -namespace Spring.Objects.Factory.Support -{ +namespace Spring.Objects.Factory.Support; +/// +/// Strategy interface for generating object names for object definitions +/// +/// Juergen Hoeller +/// Mark Pollack (.NET) +public interface IObjectNameGenerator +{ /// - /// Strategy interface for generating object names for object definitions + /// Generates an object name for the given object definition. /// - /// Juergen Hoeller - /// Mark Pollack (.NET) - public interface IObjectNameGenerator - { - /// - /// Generates an object name for the given object definition. - /// - /// The object definition to generate a name for. - /// The object definitions registry that the given definition is - /// supposed to be registerd with - /// the generated object name - string GenerateObjectName(IObjectDefinition definition, IObjectDefinitionRegistry registry); - } + /// The object definition to generate a name for. + /// The object definitions registry that the given definition is + /// supposed to be registerd with + /// the generated object name + string GenerateObjectName(IObjectDefinition definition, IObjectDefinitionRegistry registry); } diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/Interface1.cs b/src/Spring/Spring.Core/Objects/Factory/Support/Interface1.cs index 550f1479..099da016 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/Interface1.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/Interface1.cs @@ -20,41 +20,40 @@ using Spring.Objects.Factory.Config; -namespace Spring.Objects.Factory.Support +namespace Spring.Objects.Factory.Support; + +/// +/// Post-processor callback interface for merged bean definitions at runtime. +/// implementations may implement this sub-interface in order +/// to post-process the merged bean definition (a processed copy of the original object +/// definition) that the Spring uses to create a object instance. +/// +/// +/// The method may for example introspect +/// the object definition in order to prepare some cached metadata before post-processing +/// actual instances of a object. It is also allowed to modify the object definition but +/// only for definition properties which are actually intended for concurrent +/// modification. Essentially, this only applies to operations defined on the +/// itself but not to the properties of its base classes. +/// +public interface IMergedObjectDefinitionPostProcessor : IObjectPostProcessor { /// - /// Post-processor callback interface for merged bean definitions at runtime. - /// implementations may implement this sub-interface in order - /// to post-process the merged bean definition (a processed copy of the original object - /// definition) that the Spring uses to create a object instance. + /// Post-process the given merged object definition for the specified object. + /// + /// The merged object definition for the object + /// The actual type of the managed object instance + /// The name of the object + /// + void PostProcessMergedObjectDefinition(RootObjectDefinition objectDefinition, Type objectType, string objectName); + + /// + /// A notification that the object definition for the specified name has been reset, + /// and that this post-processor should clear any metadata for the affected object. /// /// - /// The method may for example introspect - /// the object definition in order to prepare some cached metadata before post-processing - /// actual instances of a object. It is also allowed to modify the object definition but - /// only for definition properties which are actually intended for concurrent - /// modification. Essentially, this only applies to operations defined on the - /// itself but not to the properties of its base classes. + /// The default implementation is empty. /// - public interface IMergedObjectDefinitionPostProcessor : IObjectPostProcessor - { - /// - /// Post-process the given merged object definition for the specified object. - /// - /// The merged object definition for the object - /// The actual type of the managed object instance - /// The name of the object - /// - void PostProcessMergedObjectDefinition(RootObjectDefinition objectDefinition, Type objectType, string objectName); - - /// - /// A notification that the object definition for the specified name has been reset, - /// and that this post-processor should clear any metadata for the affected object. - /// - /// - /// The default implementation is empty. - /// - /// The name of the object - void ResetObjectDefinition(string objectName); - } + /// The name of the object + void ResetObjectDefinition(string objectName); } diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/LookupMethodOverride.cs b/src/Spring/Spring.Core/Objects/Factory/Support/LookupMethodOverride.cs index 4c1db91c..96f2b7b8 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/LookupMethodOverride.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/LookupMethodOverride.cs @@ -22,89 +22,88 @@ using System.Reflection; using System.Text; using Spring.Util; -namespace Spring.Objects.Factory.Support +namespace Spring.Objects.Factory.Support; + +/// +/// Represents an override of a method that looks up an object in the same IoC context. +/// +/// +///

+/// Methods eligible for lookup override must not have arguments. +///

+///
+/// Rod Johnson +/// Rick Evans (.NET) +[Serializable] +public sealed class LookupMethodOverride : MethodOverride { - /// - /// Represents an override of a method that looks up an object in the same IoC context. - /// - /// - ///

- /// Methods eligible for lookup override must not have arguments. - ///

- ///
- /// Rod Johnson - /// Rick Evans (.NET) - [Serializable] - public sealed class LookupMethodOverride : MethodOverride - { - private readonly string objectName; + private readonly string objectName; - /// - /// Creates a new instance of the - /// class. - /// - /// - ///

- /// Methods eligible for lookup override must not have arguments. - ///

- ///
- /// - /// The name of the method that is to be overridden. - /// - /// - /// The name of the object in the current IoC context that the - /// dependency injected method must return. - /// - /// - /// If either of the supplied arguments is or - /// contains only whitespace character(s). - /// - public LookupMethodOverride(string methodName, string objectName) - : base(methodName) - { - AssertUtils.ArgumentHasText(objectName, "objectName"); - this.objectName = objectName; - } + /// + /// Creates a new instance of the + /// class. + /// + /// + ///

+ /// Methods eligible for lookup override must not have arguments. + ///

+ ///
+ /// + /// The name of the method that is to be overridden. + /// + /// + /// The name of the object in the current IoC context that the + /// dependency injected method must return. + /// + /// + /// If either of the supplied arguments is or + /// contains only whitespace character(s). + /// + public LookupMethodOverride(string methodName, string objectName) + : base(methodName) + { + AssertUtils.ArgumentHasText(objectName, "objectName"); + this.objectName = objectName; + } - /// - /// The name of the object in the current IoC context that the - /// dependency injected method must return. - /// - public string ObjectName - { - get { return objectName; } - } + /// + /// The name of the object in the current IoC context that the + /// dependency injected method must return. + /// + public string ObjectName + { + get { return objectName; } + } - /// - /// Does this - /// match the supplied ? - /// - /// The method to be checked. - /// - /// if this override matches the supplied . - /// - /// - /// If the supplied is . - /// - public override bool Matches(MethodInfo method) - { - AssertUtils.ArgumentNotNull(method, "method"); - return MethodName == method.Name || method.Name.EndsWith(MethodName); - } + /// + /// Does this + /// match the supplied ? + /// + /// The method to be checked. + /// + /// if this override matches the supplied . + /// + /// + /// If the supplied is . + /// + public override bool Matches(MethodInfo method) + { + AssertUtils.ArgumentNotNull(method, "method"); + return MethodName == method.Name || method.Name.EndsWith(MethodName); + } - /// - /// A that represents the current - /// . - /// - /// - /// A that represents the current - /// . - /// - public override string ToString() - { - return new StringBuilder(GetType().Name).Append(" for method '") - .Append(MethodName).Append("'; will return object '").Append(this.objectName) - .Append("'.").ToString(); - } - } + /// + /// A that represents the current + /// . + /// + /// + /// A that represents the current + /// . + /// + public override string ToString() + { + return new StringBuilder(GetType().Name).Append(" for method '") + .Append(MethodName).Append("'; will return object '").Append(this.objectName) + .Append("'.").ToString(); + } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/LookupMethodReplacer.cs b/src/Spring/Spring.Core/Objects/Factory/Support/LookupMethodReplacer.cs index c0c28f0c..9cce46d1 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/LookupMethodReplacer.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/LookupMethodReplacer.cs @@ -20,63 +20,62 @@ using System.Reflection; -namespace Spring.Objects.Factory.Support -{ - /// - /// An - /// implementation that simply returns the result of a lookup in an - /// associated IoC container. - /// - /// - ///

- /// This class is Spring.NET's implementation of Dependency Lookup via - /// Method Injection. - ///

- ///

- /// This class is reserved for internal use within the framework; it is - /// not intended to be used by application developers using Spring.NET. - ///

- ///
- /// Rick Evans - public sealed class LookupMethodReplacer : AbstractMethodReplacer - { - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The object definition that is the target of the method replacement. - /// - /// - /// The enclosing IoC container with which the above - /// is associated. - /// - /// - /// If either of the supplied arguments is . - /// - public LookupMethodReplacer(IConfigurableObjectDefinition objectDefinition, IObjectFactory objectFactory) - : base(objectDefinition, objectFactory) - { - } +namespace Spring.Objects.Factory.Support; - /// - /// Reimplements the supplied by returning the - /// result of an object lookup in an enclosing IoC container. - /// - /// - /// The instance whose is to be - /// (re)implemented. - /// - /// - /// The method that is to be (re)implemented. - /// - /// The target method's arguments. - /// - /// The result of the object lookup. - /// - public override object Implement(object target, MethodInfo method, object[] arguments) - { - return GetObject(((LookupMethodOverride) GetOverride(method)).ObjectName); - } - } +/// +/// An +/// implementation that simply returns the result of a lookup in an +/// associated IoC container. +/// +/// +///

+/// This class is Spring.NET's implementation of Dependency Lookup via +/// Method Injection. +///

+///

+/// This class is reserved for internal use within the framework; it is +/// not intended to be used by application developers using Spring.NET. +///

+///
+/// Rick Evans +public sealed class LookupMethodReplacer : AbstractMethodReplacer +{ + /// + /// Creates a new instance of the + /// class. + /// + /// + /// The object definition that is the target of the method replacement. + /// + /// + /// The enclosing IoC container with which the above + /// is associated. + /// + /// + /// If either of the supplied arguments is . + /// + public LookupMethodReplacer(IConfigurableObjectDefinition objectDefinition, IObjectFactory objectFactory) + : base(objectDefinition, objectFactory) + { + } + + /// + /// Reimplements the supplied by returning the + /// result of an object lookup in an enclosing IoC container. + /// + /// + /// The instance whose is to be + /// (re)implemented. + /// + /// + /// The method that is to be (re)implemented. + /// + /// The target method's arguments. + /// + /// The result of the object lookup. + /// + public override object Implement(object target, MethodInfo method, object[] arguments) + { + return GetObject(((LookupMethodOverride) GetOverride(method)).ObjectName); + } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/MethodInjectingInstantiationStrategy.cs b/src/Spring/Spring.Core/Objects/Factory/Support/MethodInjectingInstantiationStrategy.cs index 856ee1c3..c7b0c05b 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/MethodInjectingInstantiationStrategy.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/MethodInjectingInstantiationStrategy.cs @@ -25,586 +25,597 @@ using System.Reflection.Emit; using Microsoft.Extensions.Logging; using Spring.Util; -namespace Spring.Objects.Factory.Support +namespace Spring.Objects.Factory.Support; + +/// +/// An +/// implementation that supports method injection. +/// +/// +///

+/// Classes that want to take advantage of method injection must meet some +/// stringent criteria. Every method that is to be method injected +/// must be defined as either or +/// . An +/// will be thrown if these criteria are not met. +///

+///
+/// Rick Evans +[Serializable] +public class MethodInjectingInstantiationStrategy : SimpleInstantiationStrategy { - /// - /// An - /// implementation that supports method injection. - /// - /// - ///

- /// Classes that want to take advantage of method injection must meet some - /// stringent criteria. Every method that is to be method injected - /// must be defined as either or - /// . An - /// will be thrown if these criteria are not met. - ///

- ///
- /// Rick Evans - [Serializable] - public class MethodInjectingInstantiationStrategy : SimpleInstantiationStrategy - { - /// - /// The name of the dynamic assembly that holds dynamically created code - /// - private const string DYNAMIC_ASSEMBLY_NAME = "Spring.MethodInjected"; + /// + /// The name of the dynamic assembly that holds dynamically created code + /// + private const string DYNAMIC_ASSEMBLY_NAME = "Spring.MethodInjected"; - /// - /// A cache of generated instances, keyed on - /// the object name for which the was generated. - /// - private IDictionary typeCache = new Hashtable(); + /// + /// A cache of generated instances, keyed on + /// the object name for which the was generated. + /// + private IDictionary typeCache = new Hashtable(); - /// - /// Instantiate an instance of the object described by the supplied - /// from the supplied , - /// injecting methods as appropriate. - /// - /// - /// The definition of the object that is to be instantiated. - /// - /// - /// The name associated with the object definition. The name can be the - /// or zero length string if we're autowiring an - /// object that doesn't belong to the supplied - /// . - /// - /// - /// The owning - /// - /// - /// An instance of the object described by the supplied - /// from the supplied . - /// - /// - protected override object InstantiateWithMethodInjection( - RootObjectDefinition definition, string objectName, IObjectFactory factory) - { - return DoInstantiate(definition, objectName, factory, Type.EmptyTypes, ObjectUtils.EmptyObjects); - } + /// + /// Instantiate an instance of the object described by the supplied + /// from the supplied , + /// injecting methods as appropriate. + /// + /// + /// The definition of the object that is to be instantiated. + /// + /// + /// The name associated with the object definition. The name can be the + /// or zero length string if we're autowiring an + /// object that doesn't belong to the supplied + /// . + /// + /// + /// The owning + /// + /// + /// An instance of the object described by the supplied + /// from the supplied . + /// + /// + protected override object InstantiateWithMethodInjection( + RootObjectDefinition definition, string objectName, IObjectFactory factory) + { + return DoInstantiate(definition, objectName, factory, Type.EmptyTypes, ObjectUtils.EmptyObjects); + } - /// - /// Instantiate an instance of the object described by the supplied - /// from the supplied , - /// injecting methods as appropriate. - /// - /// - /// The definition of the object that is to be instantiated. - /// - /// - /// The name associated with the object definition. The name can be the - /// or zero length string if we're autowiring an - /// object that doesn't belong to the supplied - /// . - /// - /// - /// The owning - /// - /// - /// The to be used to instantiate - /// the object. - /// - /// - /// Any arguments to the supplied . May be null. - /// - /// - /// An instance of the object described by the supplied - /// from the supplied . - /// - /// - protected override object InstantiateWithMethodInjection( - RootObjectDefinition definition, string objectName, IObjectFactory factory, ConstructorInfo constructor, object[] arguments) - { - return DoInstantiate(definition, objectName, factory, ReflectionUtils.GetParameterTypes(constructor), arguments); - } + /// + /// Instantiate an instance of the object described by the supplied + /// from the supplied , + /// injecting methods as appropriate. + /// + /// + /// The definition of the object that is to be instantiated. + /// + /// + /// The name associated with the object definition. The name can be the + /// or zero length string if we're autowiring an + /// object that doesn't belong to the supplied + /// . + /// + /// + /// The owning + /// + /// + /// The to be used to instantiate + /// the object. + /// + /// + /// Any arguments to the supplied . May be null. + /// + /// + /// An instance of the object described by the supplied + /// from the supplied . + /// + /// + protected override object InstantiateWithMethodInjection( + RootObjectDefinition definition, string objectName, IObjectFactory factory, ConstructorInfo constructor, object[] arguments) + { + return DoInstantiate(definition, objectName, factory, ReflectionUtils.GetParameterTypes(constructor), arguments); + } - /// - /// Instantiate an instance of the object described by the supplied - /// from the supplied , - /// injecting methods as appropriate. - /// - /// - ///

- /// This method dynamically generates a subclass that supports method - /// injection for the supplied . It then - /// instantiates an new instance of said type using the constructor - /// identified by the supplied , - /// passing the supplied to said - /// constructor. It then manually injects (generic) method replacement - /// and method lookup instances (of - /// ) into - /// the new instance: those methods that are 'method-injected' will - /// then delegate to the approriate - /// - /// instance to effect the actual method injection. - ///

- ///
- /// - /// The definition of the object that is to be instantiated. - /// - /// - /// The name associated with the object definition. The name can be the - /// or zero length string if we're autowiring an - /// object that doesn't belong to the supplied - /// . - /// - /// - /// The owning - /// - /// - /// The parameter s to use to find the - /// appropriate constructor to invoke. - /// - /// - /// The aguments that are to be passed to the appropriate constructor - /// when the object is being instantiated. - /// - /// - /// A new instance of the defined by the - /// supplied . - /// - private object DoInstantiate( - RootObjectDefinition definition, string objectName, IObjectFactory factory, Type[] ctorParameterTypes, object[] arguments) - { - Type type = GetGeneratedType(objectName, definition); - object instance = type.GetConstructor(ctorParameterTypes).Invoke(arguments); - IObjectWrapper wrapper = new ObjectWrapper(instance); - wrapper.SetPropertyValue( - MethodInjectingTypeBuilder.MethodReplacementPropertyName, - new DelegatingMethodReplacer(definition, factory)); - wrapper.SetPropertyValue( - MethodInjectingTypeBuilder.MethodLookupPropertyName, - new LookupMethodReplacer(definition, factory)); - return instance; - } + /// + /// Instantiate an instance of the object described by the supplied + /// from the supplied , + /// injecting methods as appropriate. + /// + /// + ///

+ /// This method dynamically generates a subclass that supports method + /// injection for the supplied . It then + /// instantiates an new instance of said type using the constructor + /// identified by the supplied , + /// passing the supplied to said + /// constructor. It then manually injects (generic) method replacement + /// and method lookup instances (of + /// ) into + /// the new instance: those methods that are 'method-injected' will + /// then delegate to the approriate + /// + /// instance to effect the actual method injection. + ///

+ ///
+ /// + /// The definition of the object that is to be instantiated. + /// + /// + /// The name associated with the object definition. The name can be the + /// or zero length string if we're autowiring an + /// object that doesn't belong to the supplied + /// . + /// + /// + /// The owning + /// + /// + /// The parameter s to use to find the + /// appropriate constructor to invoke. + /// + /// + /// The aguments that are to be passed to the appropriate constructor + /// when the object is being instantiated. + /// + /// + /// A new instance of the defined by the + /// supplied . + /// + private object DoInstantiate( + RootObjectDefinition definition, string objectName, IObjectFactory factory, Type[] ctorParameterTypes, object[] arguments) + { + Type type = GetGeneratedType(objectName, definition); + object instance = type.GetConstructor(ctorParameterTypes).Invoke(arguments); + IObjectWrapper wrapper = new ObjectWrapper(instance); + wrapper.SetPropertyValue( + MethodInjectingTypeBuilder.MethodReplacementPropertyName, + new DelegatingMethodReplacer(definition, factory)); + wrapper.SetPropertyValue( + MethodInjectingTypeBuilder.MethodLookupPropertyName, + new LookupMethodReplacer(definition, factory)); + return instance; + } - private Type GetGeneratedType(string objectName, RootObjectDefinition definition) - { - lock (typeCache.SyncRoot) - { - Type generatedType = (Type) typeCache[objectName]; - if (generatedType == null) - { - #region Instrumentation + private Type GetGeneratedType(string objectName, RootObjectDefinition definition) + { + lock (typeCache.SyncRoot) + { + Type generatedType = (Type) typeCache[objectName]; + if (generatedType == null) + { + #region Instrumentation - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug(string.Format(CultureInfo.InvariantCulture, - "Generating a subclass of the [{0}] class for the '{1}' " + - "object definition for the purposes of method injection.", - definition.ObjectType, objectName)); - } + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug(string.Format(CultureInfo.InvariantCulture, + "Generating a subclass of the [{0}] class for the '{1}' " + + "object definition for the purposes of method injection.", + definition.ObjectType, objectName)); + } - #endregion + #endregion - ModuleBuilder module = DynamicCodeManager.GetModuleBuilder(DYNAMIC_ASSEMBLY_NAME); - generatedType = new MethodInjectingTypeBuilder(module, definition).BuildType(); - typeCache[objectName] = generatedType; - } - return generatedType; + ModuleBuilder module = DynamicCodeManager.GetModuleBuilder(DYNAMIC_ASSEMBLY_NAME); + generatedType = new MethodInjectingTypeBuilder(module, definition).BuildType(); + typeCache[objectName] = generatedType; } - } - #region Inner Class : MethodInjectingTypeBuilder + return generatedType; + } + } - /// - /// A factory that generates subclasses of those - /// classes that have been configured for the Method-Injection form of - /// Dependency Injection. - /// - /// - ///

- /// This class is designed as for one-shot usage; i.e. it must - /// be used to generate exactly one method injected subclass and - /// then discarded (it maintains state in instance fields). - ///

- ///
- private sealed class MethodInjectingTypeBuilder - { - /// - /// The name of the generated - /// property (for method replacement). - /// - /// - ///

- /// Exists so that clients of this class can use this name to set properties reflectively - /// on the dynamically generated subclass. - ///

- ///
- internal const string MethodReplacementPropertyName = "MethodReplacement"; + #region Inner Class : MethodInjectingTypeBuilder - /// - /// The name of the generated - /// property (for method lookup). - /// - /// - ///

- /// Exists so that clients of this class can use this name to set properties reflectively - /// on the dynamically generated subclass. - ///

- ///
- internal const string MethodLookupPropertyName = "MethodLookup"; + /// + /// A factory that generates subclasses of those + /// classes that have been configured for the Method-Injection form of + /// Dependency Injection. + /// + /// + ///

+ /// This class is designed as for one-shot usage; i.e. it must + /// be used to generate exactly one method injected subclass and + /// then discarded (it maintains state in instance fields). + ///

+ ///
+ private sealed class MethodInjectingTypeBuilder + { + /// + /// The name of the generated + /// property (for method replacement). + /// + /// + ///

+ /// Exists so that clients of this class can use this name to set properties reflectively + /// on the dynamically generated subclass. + ///

+ ///
+ internal const string MethodReplacementPropertyName = "MethodReplacement"; - private RootObjectDefinition objectDefinition; - private FieldBuilder methodReplacementField; - private FieldBuilder methodLookupField; - private ModuleBuilder module; + /// + /// The name of the generated + /// property (for method lookup). + /// + /// + ///

+ /// Exists so that clients of this class can use this name to set properties reflectively + /// on the dynamically generated subclass. + ///

+ ///
+ internal const string MethodLookupPropertyName = "MethodLookup"; - private readonly MethodInfo MethodReplacerImplementMethod - = typeof (IMethodReplacer).GetMethod("Implement", new Type[] {typeof (object), typeof (MethodInfo), typeof (object[])}); + private RootObjectDefinition objectDefinition; + private FieldBuilder methodReplacementField; + private FieldBuilder methodLookupField; + private ModuleBuilder module; - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The in which - /// the generated is to be defined. - /// - /// - /// The object definition that is the target of the method injection. - /// - /// - /// If either of the supplied arguments is . - /// - public MethodInjectingTypeBuilder(ModuleBuilder module, RootObjectDefinition objectDefinition) - { - AssertUtils.ArgumentNotNull(module, "module"); - AssertUtils.ArgumentNotNull(objectDefinition, "objectDefinition"); - this.module = module; - this.objectDefinition = objectDefinition; - } + private readonly MethodInfo MethodReplacerImplementMethod + = typeof(IMethodReplacer).GetMethod("Implement", new Type[] { typeof(object), typeof(MethodInfo), typeof(object[]) }); - /// - /// Builds a suitable for Method-Injection. - /// - /// - /// A suitable for Method-Injection. - /// - public Type BuildType() - { - TypeBuilder typeBuilder = DefineType(); - DefineFields(typeBuilder); - DefineConstructors(typeBuilder); - DefineProperties(typeBuilder); - DefineMethods(typeBuilder); - return typeBuilder.CreateTypeInfo(); - } + /// + /// Creates a new instance of the + /// class. + /// + /// + /// The in which + /// the generated is to be defined. + /// + /// + /// The object definition that is the target of the method injection. + /// + /// + /// If either of the supplied arguments is . + /// + public MethodInjectingTypeBuilder(ModuleBuilder module, RootObjectDefinition objectDefinition) + { + AssertUtils.ArgumentNotNull(module, "module"); + AssertUtils.ArgumentNotNull(objectDefinition, "objectDefinition"); + this.module = module; + this.objectDefinition = objectDefinition; + } - private Type BaseType - { - get { return this.objectDefinition.ObjectType; } - } + /// + /// Builds a suitable for Method-Injection. + /// + /// + /// A suitable for Method-Injection. + /// + public Type BuildType() + { + TypeBuilder typeBuilder = DefineType(); + DefineFields(typeBuilder); + DefineConstructors(typeBuilder); + DefineProperties(typeBuilder); + DefineMethods(typeBuilder); + return typeBuilder.CreateTypeInfo(); + } - private TypeBuilder DefineProperties(TypeBuilder typeBuilder) - { - DefineWritePropertyForMethodReplacement(typeBuilder, MethodReplacementPropertyName, this.methodReplacementField); - DefineWritePropertyForMethodReplacement(typeBuilder, MethodLookupPropertyName, this.methodLookupField); - return typeBuilder; - } + private Type BaseType + { + get { return this.objectDefinition.ObjectType; } + } - private TypeBuilder DefineType() - { - // Generates unique type name - string generatedSubclassName = String.Format("{0}_{1}", - BaseType.FullName, Guid.NewGuid().ToString("N")); - return this.module.DefineType( - generatedSubclassName, TypeAttributes.BeforeFieldInit | TypeAttributes.Public, BaseType); - } + private TypeBuilder DefineProperties(TypeBuilder typeBuilder) + { + DefineWritePropertyForMethodReplacement(typeBuilder, MethodReplacementPropertyName, this.methodReplacementField); + DefineWritePropertyForMethodReplacement(typeBuilder, MethodLookupPropertyName, this.methodLookupField); + return typeBuilder; + } - private TypeBuilder DefineFields(TypeBuilder typeBuilder) - { - methodReplacementField = typeBuilder.DefineField("methodReplacement", typeof (IMethodReplacer), FieldAttributes.Private); - methodLookupField = typeBuilder.DefineField("methodLookup", typeof (IMethodReplacer), FieldAttributes.Private); - return typeBuilder; - } + private TypeBuilder DefineType() + { + // Generates unique type name + string generatedSubclassName = String.Format("{0}_{1}", + BaseType.FullName, Guid.NewGuid().ToString("N")); + return this.module.DefineType( + generatedSubclassName, TypeAttributes.BeforeFieldInit | TypeAttributes.Public, BaseType); + } - private TypeBuilder DefineConstructors(TypeBuilder typeBuilder) - { - ConstructorInfo[] constructors = BaseType.GetConstructors( - BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); - for (int i = 0; i < constructors.Length; ++i) - { - ConstructorInfo constructor = constructors[i]; - if (constructor.IsPublic || constructor.IsFamily) - { - MethodAttributes attributes = MethodAttributes.Public | - MethodAttributes.HideBySig | MethodAttributes.SpecialName | - MethodAttributes.RTSpecialName; - ConstructorBuilder cb = typeBuilder.DefineConstructor(attributes, - constructor.CallingConvention, - ReflectionUtils.GetParameterTypes(constructor.GetParameters())); - ILGenerator il = cb.GetILGenerator(); - int paramCount = constructor.GetParameters().Length; - il.Emit(OpCodes.Ldarg_0); - for (int j = 1; j <= paramCount; ++j) - { - il.Emit(OpCodes.Ldarg_S, j); - } - il.Emit(OpCodes.Call, constructor); - il.Emit(OpCodes.Ret); - } - } - return typeBuilder; - } + private TypeBuilder DefineFields(TypeBuilder typeBuilder) + { + methodReplacementField = typeBuilder.DefineField("methodReplacement", typeof(IMethodReplacer), FieldAttributes.Private); + methodLookupField = typeBuilder.DefineField("methodLookup", typeof(IMethodReplacer), FieldAttributes.Private); + return typeBuilder; + } - /// - /// Defines overrides for those methods that are configured with an appropriate - /// . - /// - /// - /// The overarching that is defining - /// the generated . - /// - private TypeBuilder DefineMethods(TypeBuilder typeBuilder) - { - MethodInfo[] methods = BaseType.GetMethods( - BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic); - for (int i = 0; i < methods.Length; ++i) - { - MethodInfo method = methods[i]; - MethodOverride methodOverride - = this.objectDefinition.MethodOverrides.GetOverride(method); - if (methodOverride != null) - { - if (!method.IsVirtual || method.IsFinal) - { - throw new ObjectCreationException( - "A replaced method must be marked as either abstract or virtual."); - } - FieldBuilder field = null; - if (methodOverride is ReplacedMethodOverride) - { - field = this.methodReplacementField; - } - else - { - // lookup methods cannot have any arguments... - if (method.GetParameters().Length > 0) - { - throw new ObjectCreationException( - "The signature of a lookup method cannot have any arguments."); - } - // lookup methods cannot return void... - if (method.ReturnType == typeof (void)) - { - throw new ObjectCreationException( - "A lookup method cannot be declared with a void return type."); - } - field = this.methodLookupField; - } - DefineReplacedMethod(typeBuilder, method, field); - } - } - return typeBuilder; - } + private TypeBuilder DefineConstructors(TypeBuilder typeBuilder) + { + ConstructorInfo[] constructors = BaseType.GetConstructors( + BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); + for (int i = 0; i < constructors.Length; ++i) + { + ConstructorInfo constructor = constructors[i]; + if (constructor.IsPublic || constructor.IsFamily) + { + MethodAttributes attributes = MethodAttributes.Public | + MethodAttributes.HideBySig | MethodAttributes.SpecialName | + MethodAttributes.RTSpecialName; + ConstructorBuilder cb = typeBuilder.DefineConstructor(attributes, + constructor.CallingConvention, + ReflectionUtils.GetParameterTypes(constructor.GetParameters())); + ILGenerator il = cb.GetILGenerator(); + int paramCount = constructor.GetParameters().Length; + il.Emit(OpCodes.Ldarg_0); + for (int j = 1; j <= paramCount; ++j) + { + il.Emit(OpCodes.Ldarg_S, j); + } - /// - /// Override the supplied with the logic - /// encapsulated by the - /// - /// defined by the supplied . - /// - /// - /// The builder for the subclass that is being generated. - /// - /// - /// The method on the superclass that is to be overridden. - /// - /// - /// The field defining the - /// - /// that the overridden method will delegate to to do the 'actual' - /// method injection logic. - /// - private void DefineReplacedMethod(TypeBuilder typeBuilder, MethodInfo method, FieldBuilder field) - { - ParameterInfo[] methodParameters = method.GetParameters(); - MethodBuilder methodBuilder - = typeBuilder.DefineMethod(method.Name, - CalculateMethodAttributes(method), - method.CallingConvention, - method.ReturnType, - ReflectionUtils.GetParameterTypes(methodParameters)); - //DefineOverrideMethodParameters(methodParameters, methodBuilder); - ILGenerator il = methodBuilder.GetILGenerator(); - LocalBuilder returnValue = DefineReturnValueIfAny(method, il); - // prepare the invocation of the 'Implement' method for the 'field' (an IMethodReplacer)... - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Ldfld, field); - PushArguments(methodParameters, il); - // invoke the 'Implement' method of the IMethodReplacer in the 'field'... - il.Emit(OpCodes.Callvirt, MethodReplacerImplementMethod); - SetupTheReturnValueIfAny(returnValue, il); - il.Emit(OpCodes.Ret); - } + il.Emit(OpCodes.Call, constructor); + il.Emit(OpCodes.Ret); + } + } - /* - /// - /// Defines the parameters to the method that is being overridden. - /// - /// - ///

- /// Since we are simply overridding a method (in this method - /// injection context), all we do here is simply copy the - /// parameters (since we want a method with the exact same parameters). - ///

- ///
- /// - /// The parameters to the original method that is being overridden. - /// - /// - /// The builder we are using to define the new overridden method. - /// - private static void DefineOverrideMethodParameters( - ParameterInfo[] methodParameters, MethodBuilder methodBuilder) - { - for (int i = 0; i < methodParameters.Length; ++i) - { - ParameterInfo parameter = methodParameters[i]; - methodBuilder.DefineParameter(i + 1, parameter.Attributes, parameter.Name); - } - } - */ + return typeBuilder; + } - /// - /// Generates the MSIL for actually returning a return value if the - /// supplied is not - /// . - /// - /// - /// The definition of the return value; if , it - /// means that no return value is to required (a void - /// return type). - /// - /// - /// The to emit - /// the MSIL to. - /// - private static void SetupTheReturnValueIfAny(LocalBuilder returnValue, ILGenerator il) - { - if (returnValue != null) - { - il.Emit(OpCodes.Castclass, returnValue.LocalType); - il.Emit(OpCodes.Stloc, returnValue); - il.Emit(OpCodes.Ldloc, returnValue); - } - else - { - il.Emit(OpCodes.Pop); - } - } + /// + /// Defines overrides for those methods that are configured with an appropriate + /// . + /// + /// + /// The overarching that is defining + /// the generated . + /// + private TypeBuilder DefineMethods(TypeBuilder typeBuilder) + { + MethodInfo[] methods = BaseType.GetMethods( + BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic); + for (int i = 0; i < methods.Length; ++i) + { + MethodInfo method = methods[i]; + MethodOverride methodOverride + = this.objectDefinition.MethodOverrides.GetOverride(method); + if (methodOverride != null) + { + if (!method.IsVirtual || method.IsFinal) + { + throw new ObjectCreationException( + "A replaced method must be marked as either abstract or virtual."); + } - /// - /// Generates the MSIL for a return value if the supplied - /// returns a value. - /// - /// - /// The method to be checked. - /// - /// - /// The to emit - /// the MSIL to. - /// - /// - /// The return value, or if the method does not - /// return a value (has a void return type). - /// - private static LocalBuilder DefineReturnValueIfAny(MethodInfo method, ILGenerator il) - { - LocalBuilder returnValue = null; - if (method.ReturnType != typeof (void)) - { - returnValue = il.DeclareLocal(method.ReturnType); - } - return returnValue; - } + FieldBuilder field = null; + if (methodOverride is ReplacedMethodOverride) + { + field = this.methodReplacementField; + } + else + { + // lookup methods cannot have any arguments... + if (method.GetParameters().Length > 0) + { + throw new ObjectCreationException( + "The signature of a lookup method cannot have any arguments."); + } - /// - /// Pushes (sets up) the arguments for a call to the - /// - /// method of an appropriate - /// . - /// - /// - /// The parameters to the original method (will be bundled - /// up into a generic object[] and passed as the third - /// argument to the - /// - /// invocation. - /// - /// - /// The to emit - /// the MSIL to. - /// - private static void PushArguments(ParameterInfo[] methodParameters, ILGenerator il) - { - // push 'this' (1st arg)... - il.Emit(OpCodes.Ldarg_0); - // push the currently executing method (2nd arg)... - il.Emit(OpCodes.Call, typeof (MethodBase).GetMethod("GetCurrentMethod", BindingFlags.Static | BindingFlags.Public)); - il.Emit(OpCodes.Castclass, typeof (MethodInfo)); - // push the arguments to the currently executing method as an object [] (3rd arg)... - il.Emit(OpCodes.Ldc_I4, methodParameters.Length); - LocalBuilder args = il.DeclareLocal(typeof (object[])); - il.Emit(OpCodes.Newarr, typeof (object)); - il.Emit(OpCodes.Stloc, args); - for (int i = 0; i < methodParameters.Length; ++i) - { - il.Emit(OpCodes.Ldloc, args); - il.Emit(OpCodes.Ldc_I4, i); - il.Emit(OpCodes.Ldarg_S, i + 1); - ParameterInfo parameter = methodParameters[i]; - if (parameter.ParameterType.IsEnum || parameter.ParameterType.IsValueType) - { - il.Emit(OpCodes.Box, parameter.ParameterType); - } - il.Emit(OpCodes.Stelem_Ref); - } - il.Emit(OpCodes.Ldloc, args); - } + // lookup methods cannot return void... + if (method.ReturnType == typeof(void)) + { + throw new ObjectCreationException( + "A lookup method cannot be declared with a void return type."); + } - /// - /// Simply generates the IL for a write only property for the - /// . - /// - /// - /// The in which the property is defined. - /// - /// - /// The name of the (to be) generated property. - /// - /// - /// The (instance) field that the property is to 'set'. - /// - private void DefineWritePropertyForMethodReplacement( - TypeBuilder typeBuilder, string propertyName, FieldBuilder field) - { - MethodBuilder setMethodBuilder = typeBuilder.DefineMethod( - "set_" + propertyName, MethodAttributes.Public | MethodAttributes.SpecialName, - typeof (void), new Type[] {typeof (IMethodReplacer)}); - ILGenerator il = setMethodBuilder.GetILGenerator(); - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Ldarg_1); - il.Emit(OpCodes.Stfld, field); - il.Emit(OpCodes.Ret); - PropertyBuilder propertyBuilder = typeBuilder.DefineProperty( - propertyName, PropertyAttributes.None, typeof (IMethodReplacer), Type.EmptyTypes); - propertyBuilder.SetSetMethod(setMethodBuilder); - } + field = this.methodLookupField; + } - private MethodAttributes CalculateMethodAttributes(MethodInfo method) - { - MethodAttributes attributes = MethodAttributes.Public | MethodAttributes.ReuseSlot - | MethodAttributes.HideBySig | MethodAttributes.Virtual; - if (method.IsSpecialName) - { - return attributes | MethodAttributes.SpecialName; - } - return attributes; - } - } + DefineReplacedMethod(typeBuilder, method, field); + } + } - #endregion - } -} + return typeBuilder; + } + + /// + /// Override the supplied with the logic + /// encapsulated by the + /// + /// defined by the supplied . + /// + /// + /// The builder for the subclass that is being generated. + /// + /// + /// The method on the superclass that is to be overridden. + /// + /// + /// The field defining the + /// + /// that the overridden method will delegate to to do the 'actual' + /// method injection logic. + /// + private void DefineReplacedMethod(TypeBuilder typeBuilder, MethodInfo method, FieldBuilder field) + { + ParameterInfo[] methodParameters = method.GetParameters(); + MethodBuilder methodBuilder + = typeBuilder.DefineMethod(method.Name, + CalculateMethodAttributes(method), + method.CallingConvention, + method.ReturnType, + ReflectionUtils.GetParameterTypes(methodParameters)); + //DefineOverrideMethodParameters(methodParameters, methodBuilder); + ILGenerator il = methodBuilder.GetILGenerator(); + LocalBuilder returnValue = DefineReturnValueIfAny(method, il); + // prepare the invocation of the 'Implement' method for the 'field' (an IMethodReplacer)... + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldfld, field); + PushArguments(methodParameters, il); + // invoke the 'Implement' method of the IMethodReplacer in the 'field'... + il.Emit(OpCodes.Callvirt, MethodReplacerImplementMethod); + SetupTheReturnValueIfAny(returnValue, il); + il.Emit(OpCodes.Ret); + } + + /* + /// + /// Defines the parameters to the method that is being overridden. + /// + /// + ///

+ /// Since we are simply overridding a method (in this method + /// injection context), all we do here is simply copy the + /// parameters (since we want a method with the exact same parameters). + ///

+ ///
+ /// + /// The parameters to the original method that is being overridden. + /// + /// + /// The builder we are using to define the new overridden method. + /// + private static void DefineOverrideMethodParameters( + ParameterInfo[] methodParameters, MethodBuilder methodBuilder) + { + for (int i = 0; i < methodParameters.Length; ++i) + { + ParameterInfo parameter = methodParameters[i]; + methodBuilder.DefineParameter(i + 1, parameter.Attributes, parameter.Name); + } + } + */ + + /// + /// Generates the MSIL for actually returning a return value if the + /// supplied is not + /// . + /// + /// + /// The definition of the return value; if , it + /// means that no return value is to required (a void + /// return type). + /// + /// + /// The to emit + /// the MSIL to. + /// + private static void SetupTheReturnValueIfAny(LocalBuilder returnValue, ILGenerator il) + { + if (returnValue != null) + { + il.Emit(OpCodes.Castclass, returnValue.LocalType); + il.Emit(OpCodes.Stloc, returnValue); + il.Emit(OpCodes.Ldloc, returnValue); + } + else + { + il.Emit(OpCodes.Pop); + } + } + + /// + /// Generates the MSIL for a return value if the supplied + /// returns a value. + /// + /// + /// The method to be checked. + /// + /// + /// The to emit + /// the MSIL to. + /// + /// + /// The return value, or if the method does not + /// return a value (has a void return type). + /// + private static LocalBuilder DefineReturnValueIfAny(MethodInfo method, ILGenerator il) + { + LocalBuilder returnValue = null; + if (method.ReturnType != typeof(void)) + { + returnValue = il.DeclareLocal(method.ReturnType); + } + + return returnValue; + } + + /// + /// Pushes (sets up) the arguments for a call to the + /// + /// method of an appropriate + /// . + /// + /// + /// The parameters to the original method (will be bundled + /// up into a generic object[] and passed as the third + /// argument to the + /// + /// invocation. + /// + /// + /// The to emit + /// the MSIL to. + /// + private static void PushArguments(ParameterInfo[] methodParameters, ILGenerator il) + { + // push 'this' (1st arg)... + il.Emit(OpCodes.Ldarg_0); + // push the currently executing method (2nd arg)... + il.Emit(OpCodes.Call, typeof(MethodBase).GetMethod("GetCurrentMethod", BindingFlags.Static | BindingFlags.Public)); + il.Emit(OpCodes.Castclass, typeof(MethodInfo)); + // push the arguments to the currently executing method as an object [] (3rd arg)... + il.Emit(OpCodes.Ldc_I4, methodParameters.Length); + LocalBuilder args = il.DeclareLocal(typeof(object[])); + il.Emit(OpCodes.Newarr, typeof(object)); + il.Emit(OpCodes.Stloc, args); + for (int i = 0; i < methodParameters.Length; ++i) + { + il.Emit(OpCodes.Ldloc, args); + il.Emit(OpCodes.Ldc_I4, i); + il.Emit(OpCodes.Ldarg_S, i + 1); + ParameterInfo parameter = methodParameters[i]; + if (parameter.ParameterType.IsEnum || parameter.ParameterType.IsValueType) + { + il.Emit(OpCodes.Box, parameter.ParameterType); + } + + il.Emit(OpCodes.Stelem_Ref); + } + + il.Emit(OpCodes.Ldloc, args); + } + + /// + /// Simply generates the IL for a write only property for the + /// . + /// + /// + /// The in which the property is defined. + /// + /// + /// The name of the (to be) generated property. + /// + /// + /// The (instance) field that the property is to 'set'. + /// + private void DefineWritePropertyForMethodReplacement( + TypeBuilder typeBuilder, string propertyName, FieldBuilder field) + { + MethodBuilder setMethodBuilder = typeBuilder.DefineMethod( + "set_" + propertyName, MethodAttributes.Public | MethodAttributes.SpecialName, + typeof(void), new Type[] { typeof(IMethodReplacer) }); + ILGenerator il = setMethodBuilder.GetILGenerator(); + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldarg_1); + il.Emit(OpCodes.Stfld, field); + il.Emit(OpCodes.Ret); + PropertyBuilder propertyBuilder = typeBuilder.DefineProperty( + propertyName, PropertyAttributes.None, typeof(IMethodReplacer), Type.EmptyTypes); + propertyBuilder.SetSetMethod(setMethodBuilder); + } + + private MethodAttributes CalculateMethodAttributes(MethodInfo method) + { + MethodAttributes attributes = MethodAttributes.Public | MethodAttributes.ReuseSlot + | MethodAttributes.HideBySig | MethodAttributes.Virtual; + if (method.IsSpecialName) + { + return attributes | MethodAttributes.SpecialName; + } + + return attributes; + } + } + + #endregion +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/MethodOverride.cs b/src/Spring/Spring.Core/Objects/Factory/Support/MethodOverride.cs index ee55cae5..9373c119 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/MethodOverride.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/MethodOverride.cs @@ -21,97 +21,96 @@ using System.Reflection; using Spring.Util; -namespace Spring.Objects.Factory.Support +namespace Spring.Objects.Factory.Support; + +/// +/// Represents the override of a method on a managed object by the IoC container. +/// +/// +///

+/// Note that the override mechanism is not intended as a generic means of +/// inserting crosscutting code: use AOP for that. +///

+///
+/// Rod Johnson +/// Rick Evans (.NET) +[Serializable] +public abstract class MethodOverride { - /// - /// Represents the override of a method on a managed object by the IoC container. - /// - /// - ///

- /// Note that the override mechanism is not intended as a generic means of - /// inserting crosscutting code: use AOP for that. - ///

- ///
- /// Rod Johnson - /// Rick Evans (.NET) - [Serializable] - public abstract class MethodOverride - { - private readonly string methodName; - private bool isOverloaded = true; + private readonly string methodName; + private bool isOverloaded = true; - /// - /// Creates a new instance of the - /// class. - /// - /// - ///

- /// This is an class, and as such exposes no - /// public constructors. - ///

- ///
- /// - /// The name of the method that is to be overridden. - /// - /// - /// If the supplied is or - /// contains only whitespace character(s). - /// - protected MethodOverride(string methodName) - { - AssertUtils.ArgumentHasText(methodName, "methodName"); - this.methodName = methodName.Trim(); - } + /// + /// Creates a new instance of the + /// class. + /// + /// + ///

+ /// This is an class, and as such exposes no + /// public constructors. + ///

+ ///
+ /// + /// The name of the method that is to be overridden. + /// + /// + /// If the supplied is or + /// contains only whitespace character(s). + /// + protected MethodOverride(string methodName) + { + AssertUtils.ArgumentHasText(methodName, "methodName"); + this.methodName = methodName.Trim(); + } - /// - /// The name of the method that is to be overridden. - /// - public string MethodName - { - get { return methodName; } - } + /// + /// The name of the method that is to be overridden. + /// + public string MethodName + { + get { return methodName; } + } - /// - /// Is the method that is ot be injected - /// () - /// to be considered as overloaded? - /// - /// - ///

- /// If (the default), then argument type matching - /// will be performed (because one would not want to override the wrong - /// method). - ///

- ///

- /// Setting the value of this property to can be used - /// to optimize runtime performance (ever so slightly). - ///

- ///
- public bool IsOverloaded - { - get { return isOverloaded; } - set { isOverloaded = value; } - } + /// + /// Is the method that is ot be injected + /// () + /// to be considered as overloaded? + /// + /// + ///

+ /// If (the default), then argument type matching + /// will be performed (because one would not want to override the wrong + /// method). + ///

+ ///

+ /// Setting the value of this property to can be used + /// to optimize runtime performance (ever so slightly). + ///

+ ///
+ public bool IsOverloaded + { + get { return isOverloaded; } + set { isOverloaded = value; } + } - /// - /// Does this - /// match the supplied ? - /// - /// - ///

- /// By 'match' one means does this particular - /// - /// instance apply to the supplied ? - ///

- ///

- /// This allows for argument list checking as well as method name checking. - ///

- ///
- /// The method to be checked. - /// - /// if this override matches the supplied - /// . - /// - public abstract bool Matches(MethodInfo method); - } + /// + /// Does this + /// match the supplied ? + /// + /// + ///

+ /// By 'match' one means does this particular + /// + /// instance apply to the supplied ? + ///

+ ///

+ /// This allows for argument list checking as well as method name checking. + ///

+ ///
+ /// The method to be checked. + /// + /// if this override matches the supplied + /// . + /// + public abstract bool Matches(MethodInfo method); } diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/MethodOverrides.cs b/src/Spring/Spring.Core/Objects/Factory/Support/MethodOverrides.cs index 85c34a07..0b4f3541 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/MethodOverrides.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/MethodOverrides.cs @@ -17,160 +17,160 @@ using System.Collections; using System.Reflection; -namespace Spring.Objects.Factory.Support +namespace Spring.Objects.Factory.Support; + +/// +/// A collection (with set semantics) of method overrides, determining which, if any, +/// methods on a managed object the Spring.NET IoC container will override at runtime. +/// +/// Rod Johnson +/// Rick Evans +[Serializable] +public class MethodOverrides : IEnumerable { - /// - /// A collection (with set semantics) of method overrides, determining which, if any, - /// methods on a managed object the Spring.NET IoC container will override at runtime. - /// - /// Rod Johnson - /// Rick Evans - [Serializable] - public class MethodOverrides : IEnumerable - { - private HashSet _overrides; + private HashSet _overrides; - private HashSet _overloadedMethodNames; + private HashSet _overloadedMethodNames; - /// - /// Creates a new instance of the - /// class. - /// - public MethodOverrides() - { - } + /// + /// Creates a new instance of the + /// class. + /// + public MethodOverrides() + { + } - /// - /// Creates a new instance of the - /// class. - /// - /// - ///

- /// Deep copy constructoe. - ///

- ///
- /// - /// The instance supplying initial overrides for this new instance. - /// - public MethodOverrides(MethodOverrides other) - { - AddAll(other); - } + /// + /// Creates a new instance of the + /// class. + /// + /// + ///

+ /// Deep copy constructoe. + ///

+ ///
+ /// + /// The instance supplying initial overrides for this new instance. + /// + public MethodOverrides(MethodOverrides other) + { + AddAll(other); + } - /// - /// Returns true if this instance contains no overrides. - /// - public bool IsEmpty => _overrides== null || _overrides.Count == 0; + /// + /// Returns true if this instance contains no overrides. + /// + public bool IsEmpty => _overrides == null || _overrides.Count == 0; - /// - /// Copy all given method overrides into this object. - /// - /// - /// The overrides to be copied into this object. - /// - public void AddAll(MethodOverrides other) - { - if (other != null) - { - if (other._overrides != null && other._overrides.Count > 0) - { - _overrides = _overrides ?? new HashSet(); - foreach (var @override in other._overrides) - { - _overrides.Add(@override); - } - } + /// + /// Copy all given method overrides into this object. + /// + /// + /// The overrides to be copied into this object. + /// + public void AddAll(MethodOverrides other) + { + if (other != null) + { + if (other._overrides != null && other._overrides.Count > 0) + { + _overrides = _overrides ?? new HashSet(); + foreach (var @override in other._overrides) + { + _overrides.Add(@override); + } + } - if (other._overloadedMethodNames != null && other._overloadedMethodNames.Count > 0) - { - _overloadedMethodNames = _overloadedMethodNames ?? new HashSet(); - foreach (var methodName in other._overloadedMethodNames) - { - _overloadedMethodNames.Add(methodName); - } - } - } - } + if (other._overloadedMethodNames != null && other._overloadedMethodNames.Count > 0) + { + _overloadedMethodNames = _overloadedMethodNames ?? new HashSet(); + foreach (var methodName in other._overloadedMethodNames) + { + _overloadedMethodNames.Add(methodName); + } + } + } + } - /// - /// Adds the supplied to the overrides contained - /// within this instance. - /// - /// - /// The to be - /// added. - /// - public void Add(MethodOverride theOverride) - { - _overrides = _overrides ?? new HashSet(); - _overrides.Add(theOverride); - } + /// + /// Adds the supplied to the overrides contained + /// within this instance. + /// + /// + /// The to be + /// added. + /// + public void Add(MethodOverride theOverride) + { + _overrides = _overrides ?? new HashSet(); + _overrides.Add(theOverride); + } - /// - /// Adds the supplied to the overloaded method names - /// contained within this instance. - /// - /// - /// The overloaded method name to be added. - /// - public void AddOverloadedMethodName(string methodName) - { - _overloadedMethodNames = _overloadedMethodNames ?? new HashSet(); - _overloadedMethodNames.Add(methodName); - } + /// + /// Adds the supplied to the overloaded method names + /// contained within this instance. + /// + /// + /// The overloaded method name to be added. + /// + public void AddOverloadedMethodName(string methodName) + { + _overloadedMethodNames = _overloadedMethodNames ?? new HashSet(); + _overloadedMethodNames.Add(methodName); + } - /// - /// Returns true if the supplied is present within - /// the overloaded method names contained within this instance. - /// - /// - /// The overloaded method name to be checked. - /// - /// - /// True if the supplied is present within - /// the overloaded method names contained within this instance. - /// - public bool IsOverloadedMethodName(string methodName) - { - return _overloadedMethodNames != null && _overloadedMethodNames.Contains(methodName); - } + /// + /// Returns true if the supplied is present within + /// the overloaded method names contained within this instance. + /// + /// + /// The overloaded method name to be checked. + /// + /// + /// True if the supplied is present within + /// the overloaded method names contained within this instance. + /// + public bool IsOverloadedMethodName(string methodName) + { + return _overloadedMethodNames != null && _overloadedMethodNames.Contains(methodName); + } - /// - /// Return the override for the given method, if any. - /// - /// - /// The method to check for overrides for. - /// - /// - /// the override for the given method, if any. - /// - public MethodOverride GetOverride(MethodInfo method) - { - if (_overrides == null) - { - return null; - } - foreach (MethodOverride ovr in _overrides) - { - if (ovr.Matches(method)) - { - return ovr; - } - } + /// + /// Return the override for the given method, if any. + /// + /// + /// The method to check for overrides for. + /// + /// + /// the override for the given method, if any. + /// + public MethodOverride GetOverride(MethodInfo method) + { + if (_overrides == null) + { + return null; + } - return null; - } + foreach (MethodOverride ovr in _overrides) + { + if (ovr.Matches(method)) + { + return ovr; + } + } - /// - public IEnumerator GetEnumerator() - { - return _overrides?.GetEnumerator() ?? Enumerable.Empty().GetEnumerator(); - } + return null; + } - /// - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - } + /// + public IEnumerator GetEnumerator() + { + return _overrides?.GetEnumerator() ?? Enumerable.Empty().GetEnumerator(); + } + + /// + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/ObjectDefinitionBuilder.cs b/src/Spring/Spring.Core/Objects/Factory/Support/ObjectDefinitionBuilder.cs index be3c3131..54559b91 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/ObjectDefinitionBuilder.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/ObjectDefinitionBuilder.cs @@ -16,387 +16,380 @@ using Spring.Objects.Factory.Config; -namespace Spring.Objects.Factory.Support +namespace Spring.Objects.Factory.Support; + +/// +/// Programmatic means of constructing a using the builder pattern. Intended primarily +/// for use when implementing custom namespace parsers. +/// +/// Set methods are used instead of properties, so that chaining of methods can be used to create +/// 'one-liner'definitions that set multiple properties at one. +/// Rod Johnson +/// Rob Harrop +/// Juergen Hoeller +/// Mark Pollack (.NET) +public class ObjectDefinitionBuilder { + private AbstractObjectDefinition objectDefinition; + + private IObjectDefinitionFactory objectDefinitionFactory; + + private int constructorArgIndex; + /// - /// Programmatic means of constructing a using the builder pattern. Intended primarily - /// for use when implementing custom namespace parsers. + /// Initializes a new instance of the class, private + /// to force use of factory methods. /// - /// Set methods are used instead of properties, so that chaining of methods can be used to create - /// 'one-liner'definitions that set multiple properties at one. - /// Rod Johnson - /// Rob Harrop - /// Juergen Hoeller - /// Mark Pollack (.NET) - public class ObjectDefinitionBuilder + private ObjectDefinitionBuilder() { - private AbstractObjectDefinition objectDefinition; + } - private IObjectDefinitionFactory objectDefinitionFactory; + /// + /// Creates a new used to construct a . + /// + public static ObjectDefinitionBuilder GenericObjectDefinition() + { + ObjectDefinitionBuilder builder = new ObjectDefinitionBuilder(); + builder.objectDefinition = new GenericObjectDefinition(); + return builder; + } - private int constructorArgIndex; + /// + /// Creates a new used to construct a . + /// + /// the of the object that the definition is being created for + public static ObjectDefinitionBuilder GenericObjectDefinition(Type objectType) + { + ObjectDefinitionBuilder builder = new ObjectDefinitionBuilder(); + builder.objectDefinition = new GenericObjectDefinition(); + builder.objectDefinition.ObjectType = objectType; + return builder; + } - /// - /// Initializes a new instance of the class, private - /// to force use of factory methods. - /// - private ObjectDefinitionBuilder() + /// + /// Creates a new used to construct a . + /// + /// the name of the of the object that the definition is being created for + public static ObjectDefinitionBuilder GenericObjectDefinition(string objectTypeName) + { + ObjectDefinitionBuilder builder = new ObjectDefinitionBuilder(); + builder.objectDefinition = new GenericObjectDefinition(); + builder.objectDefinition.ObjectTypeName = objectTypeName; + return builder; + } + + /// + /// Create a new ObjectDefinitionBuilder used to construct a root object definition. + /// + /// The object definition factory. + /// The type name of the object. + /// A new ObjectDefinitionBuilder instance. + public static ObjectDefinitionBuilder RootObjectDefinition(IObjectDefinitionFactory objectDefinitionFactory, + string objectTypeName) + { + return RootObjectDefinition(objectDefinitionFactory, objectTypeName, null); + } + + /// + /// Create a new ObjectDefinitionBuilder used to construct a root object definition. + /// + /// The object definition factory. + /// Name of the object type. + /// Name of the factory method. + /// A new ObjectDefinitionBuilder instance. + public static ObjectDefinitionBuilder RootObjectDefinition(IObjectDefinitionFactory objectDefinitionFactory, + string objectTypeName, + string factoryMethodName) + { + ObjectDefinitionBuilder builder = new ObjectDefinitionBuilder(); + + builder.objectDefinitionFactory = objectDefinitionFactory; + + // Pass in null for parent name and also AppDomain to force object definition to be register by name and not type. + builder.objectDefinition = + objectDefinitionFactory.CreateObjectDefinition(objectTypeName, null, null); + + builder.objectDefinition.FactoryMethodName = factoryMethodName; + + return builder; + } + + /// + /// Create a new ObjectDefinitionBuilder used to construct a root object definition. + /// + /// The object definition factory. + /// Type of the object. + /// A new ObjectDefinitionBuilder instance. + public static ObjectDefinitionBuilder RootObjectDefinition(IObjectDefinitionFactory objectDefinitionFactory, + Type objectType) + { + return RootObjectDefinition(objectDefinitionFactory, objectType, null); + } + + /// + /// Create a new ObjectDefinitionBuilder used to construct a root object definition. + /// + /// The object definition factory. + /// Type of the object. + /// Name of the factory method. + /// A new ObjectDefinitionBuilder instance. + public static ObjectDefinitionBuilder RootObjectDefinition(IObjectDefinitionFactory objectDefinitionFactory, + Type objectType, string factoryMethodName) + { + ObjectDefinitionBuilder builder = new ObjectDefinitionBuilder(); + + builder.objectDefinitionFactory = objectDefinitionFactory; + + builder.objectDefinition = + objectDefinitionFactory.CreateObjectDefinition(objectType.FullName, null, AppDomain.CurrentDomain); + + builder.objectDefinition.ObjectType = objectType; + builder.objectDefinition.FactoryMethodName = factoryMethodName; + return builder; + } + + /// + /// Create a new ObjectDefinitionBuilder used to construct a child object definition.. + /// + /// The object definition factory. + /// Name of the parent object. + /// + public static ObjectDefinitionBuilder ChildObjectDefinition(IObjectDefinitionFactory objectDefinitionFactory, + string parentObjectName) + { + ObjectDefinitionBuilder builder = new ObjectDefinitionBuilder(); + + builder.objectDefinitionFactory = objectDefinitionFactory; + + builder.objectDefinition = + objectDefinitionFactory.CreateObjectDefinition(null, parentObjectName, AppDomain.CurrentDomain); + + return builder; + } + + /// + /// Gets the current object definition in its raw (unvalidated) form. + /// + /// The raw object definition. + public AbstractObjectDefinition RawObjectDefinition + { + get { return objectDefinition; } + } + + /// + /// Validate and gets the object definition. + /// + /// The object definition. + public AbstractObjectDefinition ObjectDefinition + { + get { - } - - /// - /// Creates a new used to construct a . - /// - public static ObjectDefinitionBuilder GenericObjectDefinition() - { - ObjectDefinitionBuilder builder = new ObjectDefinitionBuilder(); - builder.objectDefinition = new GenericObjectDefinition(); - return builder; - } - - /// - /// Creates a new used to construct a . - /// - /// the of the object that the definition is being created for - public static ObjectDefinitionBuilder GenericObjectDefinition(Type objectType) - { - ObjectDefinitionBuilder builder = new ObjectDefinitionBuilder(); - builder.objectDefinition = new GenericObjectDefinition(); - builder.objectDefinition.ObjectType = objectType; - return builder; - } - - /// - /// Creates a new used to construct a . - /// - /// the name of the of the object that the definition is being created for - public static ObjectDefinitionBuilder GenericObjectDefinition(string objectTypeName) - { - ObjectDefinitionBuilder builder = new ObjectDefinitionBuilder(); - builder.objectDefinition = new GenericObjectDefinition(); - builder.objectDefinition.ObjectTypeName = objectTypeName; - return builder; - } - - /// - /// Create a new ObjectDefinitionBuilder used to construct a root object definition. - /// - /// The object definition factory. - /// The type name of the object. - /// A new ObjectDefinitionBuilder instance. - public static ObjectDefinitionBuilder RootObjectDefinition(IObjectDefinitionFactory objectDefinitionFactory, - string objectTypeName) - { - return RootObjectDefinition(objectDefinitionFactory, objectTypeName, null); - } - - /// - /// Create a new ObjectDefinitionBuilder used to construct a root object definition. - /// - /// The object definition factory. - /// Name of the object type. - /// Name of the factory method. - /// A new ObjectDefinitionBuilder instance. - public static ObjectDefinitionBuilder RootObjectDefinition(IObjectDefinitionFactory objectDefinitionFactory, - string objectTypeName, - string factoryMethodName) - { - ObjectDefinitionBuilder builder = new ObjectDefinitionBuilder(); - - builder.objectDefinitionFactory = objectDefinitionFactory; - - // Pass in null for parent name and also AppDomain to force object definition to be register by name and not type. - builder.objectDefinition = - objectDefinitionFactory.CreateObjectDefinition(objectTypeName, null, null); - - builder.objectDefinition.FactoryMethodName = factoryMethodName; - - return builder; - - } - - /// - /// Create a new ObjectDefinitionBuilder used to construct a root object definition. - /// - /// The object definition factory. - /// Type of the object. - /// A new ObjectDefinitionBuilder instance. - public static ObjectDefinitionBuilder RootObjectDefinition(IObjectDefinitionFactory objectDefinitionFactory, - Type objectType) - { - return RootObjectDefinition(objectDefinitionFactory, objectType, null); - } - - /// - /// Create a new ObjectDefinitionBuilder used to construct a root object definition. - /// - /// The object definition factory. - /// Type of the object. - /// Name of the factory method. - /// A new ObjectDefinitionBuilder instance. - public static ObjectDefinitionBuilder RootObjectDefinition(IObjectDefinitionFactory objectDefinitionFactory, - Type objectType, string factoryMethodName) - { - ObjectDefinitionBuilder builder = new ObjectDefinitionBuilder(); - - builder.objectDefinitionFactory = objectDefinitionFactory; - - builder.objectDefinition = - objectDefinitionFactory.CreateObjectDefinition(objectType.FullName, null, AppDomain.CurrentDomain); - - builder.objectDefinition.ObjectType = objectType; - builder.objectDefinition.FactoryMethodName = factoryMethodName; - return builder; - } - - /// - /// Create a new ObjectDefinitionBuilder used to construct a child object definition.. - /// - /// The object definition factory. - /// Name of the parent object. - /// - public static ObjectDefinitionBuilder ChildObjectDefinition(IObjectDefinitionFactory objectDefinitionFactory, - string parentObjectName) - { - ObjectDefinitionBuilder builder = new ObjectDefinitionBuilder(); - - builder.objectDefinitionFactory = objectDefinitionFactory; - - builder.objectDefinition = - objectDefinitionFactory.CreateObjectDefinition(null, parentObjectName, AppDomain.CurrentDomain); - - return builder; - } - - - /// - /// Gets the current object definition in its raw (unvalidated) form. - /// - /// The raw object definition. - public AbstractObjectDefinition RawObjectDefinition - { - get { return objectDefinition; } - - } - - /// - /// Validate and gets the object definition. - /// - /// The object definition. - public AbstractObjectDefinition ObjectDefinition - { - get - { - objectDefinition.Validate(); - return objectDefinition; - } - } - - - //TODO add expression support. - - /// - /// Adds the property value under the given name. - /// - /// The name. - /// The value. - /// The current ObjectDefinitionBuilder. - public ObjectDefinitionBuilder AddPropertyValue(string name, object value) - { - objectDefinition.PropertyValues.Add(new PropertyValue(name, value)); - return this; - } - - /// - /// Adds a reference to the specified object name under the property specified. - /// - /// The name. - /// Name of the object. - /// The current ObjectDefinitionBuilder. - public ObjectDefinitionBuilder AddPropertyReference(string name, string objectName) - { - objectDefinition.PropertyValues.Add(new PropertyValue(name, new RuntimeObjectReference(objectName))); - return this; - } - - - /// - /// Adds an index constructor arg value. The current index is tracked internally and all addtions are - /// at the present point - /// - /// The constructor arg value. - /// The current ObjectDefinitionBuilder. - public ObjectDefinitionBuilder AddConstructorArg(object value) - { - objectDefinition.ConstructorArgumentValues.AddIndexedArgumentValue(constructorArgIndex++,value); - return this; - } - - /// - /// Adds a reference to the named object as a constructor argument. - /// - /// Name of the object. - /// - public ObjectDefinitionBuilder AddConstructorArgReference(string objectName) - { - return AddConstructorArg(new RuntimeObjectReference(objectName)); - } - - - /// - /// Sets the name of the factory method to use for this definition. - /// - /// The factory method. - /// The current ObjectDefinitionBuilder. - public ObjectDefinitionBuilder SetFactoryMethod(string factoryMethod) - { - objectDefinition.FactoryMethodName = factoryMethod; - return this; - } - - /// - /// Sets the name of the factory object to use for this definition. - /// - /// The factory object. - /// The factory method. - /// The current ObjectDefinitionBuilder. - public ObjectDefinitionBuilder SetFactoryObject(string factoryObject, string factoryMethod) - { - objectDefinition.FactoryObjectName = factoryObject; - objectDefinition.FactoryMethodName = factoryMethod; - return this; - } - - /// - /// Sets whether or not this definition describes a singleton object. - /// - /// if set to true [singleton]. - /// The current ObjectDefinitionBuilder. - public ObjectDefinitionBuilder SetSingleton(bool singleton) - { - objectDefinition.IsSingleton = singleton; - return this; - } - - /// - /// Sets whether objects or not this definition is abstract. - /// - /// if set to true [flag]. - /// The current ObjectDefinitionBuilder. - public ObjectDefinitionBuilder SetAbstract(bool flag) - { - objectDefinition.IsAbstract = flag; - return this; - } - - /// - /// Sets whether objects for this definition should be lazily initialized or not. - /// - /// if set to true [lazy]. - /// The current ObjectDefinitionBuilder. - public ObjectDefinitionBuilder SetLazyInit(bool lazy) - { - objectDefinition.IsLazyInit = lazy; - return this; - } - - /// - /// Sets the autowire mode for this definition. - /// - /// The autowire mode. - /// The current ObjectDefinitionBuilder. - public ObjectDefinitionBuilder SetAutowireMode(AutoWiringMode autowireMode) - { - objectDefinition.AutowireMode = autowireMode; - return this; - } - - /// - /// Sets the autowire candidate value for this definition. - /// - /// The autowire candidate value - /// - public ObjectDefinitionBuilder SetAutowireCandidate(bool autowireCandidate) - { - objectDefinition.IsAutowireCandidate = autowireCandidate; - return this; - } - - /// - /// Sets the primary value for this definition. - /// - /// If object is primary - /// - public ObjectDefinitionBuilder SetPrimary(bool primary) - { - objectDefinition.IsPrimary = primary; - return this; - } - - /// - /// Sets the dependency check mode for this definition. - /// - /// The dependency check. - /// The current ObjectDefinitionBuilder. - public ObjectDefinitionBuilder SetDependencyCheck(DependencyCheckingMode dependencyCheck) - { - objectDefinition.DependencyCheck = dependencyCheck; - return this; - } - - - /// - /// Sets the name of the destroy method for this definition. - /// - /// Name of the method. - /// The current ObjectDefinitionBuilder. - public ObjectDefinitionBuilder SetDestroyMethodName(string methodName) - { - objectDefinition.DestroyMethodName = methodName; - return this; - } - - /// - /// Sets the name of the init method for this definition. - /// - /// Name of the method. - /// The current ObjectDefinitionBuilder. - public ObjectDefinitionBuilder SetInitMethodName(string methodName) - { - objectDefinition.InitMethodName = methodName; - return this; - } - - /// - /// Sets the resource description for this definition. - /// - /// The resource description. - /// The current ObjectDefinitionBuilder. - public ObjectDefinitionBuilder SetResourceDescription(string resourceDescription) - { - objectDefinition.ResourceDescription = resourceDescription; - return this; - } - - /// - /// Adds the specified object name to the list of objects that this definition depends on. - /// - /// Name of the object. - /// The current ObjectDefinitionBuilder. - public ObjectDefinitionBuilder AddDependsOn(string objectName) - { - if (objectDefinition.DependsOn == null) - { - objectDefinition.DependsOn = new[] {objectName}; - } - else - { - var list = new List(objectDefinition.DependsOn.Count + 1); - list.AddRange(objectDefinition.DependsOn); - list.Add(objectName); - objectDefinition.DependsOn = list; - } - return this; + objectDefinition.Validate(); + return objectDefinition; } } + + //TODO add expression support. + + /// + /// Adds the property value under the given name. + /// + /// The name. + /// The value. + /// The current ObjectDefinitionBuilder. + public ObjectDefinitionBuilder AddPropertyValue(string name, object value) + { + objectDefinition.PropertyValues.Add(new PropertyValue(name, value)); + return this; + } + + /// + /// Adds a reference to the specified object name under the property specified. + /// + /// The name. + /// Name of the object. + /// The current ObjectDefinitionBuilder. + public ObjectDefinitionBuilder AddPropertyReference(string name, string objectName) + { + objectDefinition.PropertyValues.Add(new PropertyValue(name, new RuntimeObjectReference(objectName))); + return this; + } + + /// + /// Adds an index constructor arg value. The current index is tracked internally and all addtions are + /// at the present point + /// + /// The constructor arg value. + /// The current ObjectDefinitionBuilder. + public ObjectDefinitionBuilder AddConstructorArg(object value) + { + objectDefinition.ConstructorArgumentValues.AddIndexedArgumentValue(constructorArgIndex++, value); + return this; + } + + /// + /// Adds a reference to the named object as a constructor argument. + /// + /// Name of the object. + /// + public ObjectDefinitionBuilder AddConstructorArgReference(string objectName) + { + return AddConstructorArg(new RuntimeObjectReference(objectName)); + } + + /// + /// Sets the name of the factory method to use for this definition. + /// + /// The factory method. + /// The current ObjectDefinitionBuilder. + public ObjectDefinitionBuilder SetFactoryMethod(string factoryMethod) + { + objectDefinition.FactoryMethodName = factoryMethod; + return this; + } + + /// + /// Sets the name of the factory object to use for this definition. + /// + /// The factory object. + /// The factory method. + /// The current ObjectDefinitionBuilder. + public ObjectDefinitionBuilder SetFactoryObject(string factoryObject, string factoryMethod) + { + objectDefinition.FactoryObjectName = factoryObject; + objectDefinition.FactoryMethodName = factoryMethod; + return this; + } + + /// + /// Sets whether or not this definition describes a singleton object. + /// + /// if set to true [singleton]. + /// The current ObjectDefinitionBuilder. + public ObjectDefinitionBuilder SetSingleton(bool singleton) + { + objectDefinition.IsSingleton = singleton; + return this; + } + + /// + /// Sets whether objects or not this definition is abstract. + /// + /// if set to true [flag]. + /// The current ObjectDefinitionBuilder. + public ObjectDefinitionBuilder SetAbstract(bool flag) + { + objectDefinition.IsAbstract = flag; + return this; + } + + /// + /// Sets whether objects for this definition should be lazily initialized or not. + /// + /// if set to true [lazy]. + /// The current ObjectDefinitionBuilder. + public ObjectDefinitionBuilder SetLazyInit(bool lazy) + { + objectDefinition.IsLazyInit = lazy; + return this; + } + + /// + /// Sets the autowire mode for this definition. + /// + /// The autowire mode. + /// The current ObjectDefinitionBuilder. + public ObjectDefinitionBuilder SetAutowireMode(AutoWiringMode autowireMode) + { + objectDefinition.AutowireMode = autowireMode; + return this; + } + + /// + /// Sets the autowire candidate value for this definition. + /// + /// The autowire candidate value + /// + public ObjectDefinitionBuilder SetAutowireCandidate(bool autowireCandidate) + { + objectDefinition.IsAutowireCandidate = autowireCandidate; + return this; + } + + /// + /// Sets the primary value for this definition. + /// + /// If object is primary + /// + public ObjectDefinitionBuilder SetPrimary(bool primary) + { + objectDefinition.IsPrimary = primary; + return this; + } + + /// + /// Sets the dependency check mode for this definition. + /// + /// The dependency check. + /// The current ObjectDefinitionBuilder. + public ObjectDefinitionBuilder SetDependencyCheck(DependencyCheckingMode dependencyCheck) + { + objectDefinition.DependencyCheck = dependencyCheck; + return this; + } + + /// + /// Sets the name of the destroy method for this definition. + /// + /// Name of the method. + /// The current ObjectDefinitionBuilder. + public ObjectDefinitionBuilder SetDestroyMethodName(string methodName) + { + objectDefinition.DestroyMethodName = methodName; + return this; + } + + /// + /// Sets the name of the init method for this definition. + /// + /// Name of the method. + /// The current ObjectDefinitionBuilder. + public ObjectDefinitionBuilder SetInitMethodName(string methodName) + { + objectDefinition.InitMethodName = methodName; + return this; + } + + /// + /// Sets the resource description for this definition. + /// + /// The resource description. + /// The current ObjectDefinitionBuilder. + public ObjectDefinitionBuilder SetResourceDescription(string resourceDescription) + { + objectDefinition.ResourceDescription = resourceDescription; + return this; + } + + /// + /// Adds the specified object name to the list of objects that this definition depends on. + /// + /// Name of the object. + /// The current ObjectDefinitionBuilder. + public ObjectDefinitionBuilder AddDependsOn(string objectName) + { + if (objectDefinition.DependsOn == null) + { + objectDefinition.DependsOn = new[] { objectName }; + } + else + { + var list = new List(objectDefinition.DependsOn.Count + 1); + list.AddRange(objectDefinition.DependsOn); + list.Add(objectName); + objectDefinition.DependsOn = list; + } + + return this; + } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/ObjectDefinitionReaderUtils.cs b/src/Spring/Spring.Core/Objects/Factory/Support/ObjectDefinitionReaderUtils.cs index ce4b83f1..981d7b8f 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/ObjectDefinitionReaderUtils.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/ObjectDefinitionReaderUtils.cs @@ -19,267 +19,268 @@ #endregion using System.Text.RegularExpressions; - using Spring.Objects.Factory.Config; using Spring.Objects.Factory.Xml; using Spring.Objects.Support; using Spring.Util; -namespace Spring.Objects.Factory.Support +namespace Spring.Objects.Factory.Support; + +/// +/// Utility methods that are useful for +/// +/// implementations. +/// +/// Juergen Hoeller +/// Rick Evans (.NET) +/// +public sealed class ObjectDefinitionReaderUtils { /// - /// Utility methods that are useful for - /// - /// implementations. + /// The string used as a separator in the generation of synthetic id's + /// for those object definitions explicitly that aren't assigned one. /// - /// Juergen Hoeller - /// Rick Evans (.NET) - /// - public sealed class ObjectDefinitionReaderUtils + /// + ///

+ /// If a name or parent object definition + /// name is not unique, "#1", "#2" etc will be appended, until such + /// time that the name becomes unique. + ///

+ ///
+ public const string GENERATED_OBJECT_NAME_SEPARATOR = ObjectFactoryUtils.GeneratedObjectNameSeparator; + + /// + /// Registers the supplied with the + /// supplied . + /// + /// + ///

+ /// This is a convenience method that registers the + /// + /// of the supplied under the + /// + /// property value of said . If the + /// supplied has any + /// , + /// then those aliases will also be registered with the supplied + /// . + ///

+ ///
+ /// + /// The object definition holder containing the + /// that + /// is to be registered. + /// + /// + /// The registry that the supplied + /// is to be registered with. + /// + /// + /// If either of the supplied arguments is . + /// + /// + /// If the could not be registered + /// with the . + /// + public static void RegisterObjectDefinition( + ObjectDefinitionHolder objectDefinition, IObjectDefinitionRegistry registry) { - /// - /// The string used as a separator in the generation of synthetic id's - /// for those object definitions explicitly that aren't assigned one. - /// - /// - ///

- /// If a name or parent object definition - /// name is not unique, "#1", "#2" etc will be appended, until such - /// time that the name becomes unique. - ///

- ///
- public const string GENERATED_OBJECT_NAME_SEPARATOR = ObjectFactoryUtils.GeneratedObjectNameSeparator; + AssertUtils.ArgumentNotNull(objectDefinition, "objectDefinition"); + AssertUtils.ArgumentNotNull(registry, "registry"); - /// - /// Registers the supplied with the - /// supplied . - /// - /// - ///

- /// This is a convenience method that registers the - /// - /// of the supplied under the - /// - /// property value of said . If the - /// supplied has any - /// , - /// then those aliases will also be registered with the supplied - /// . - ///

- ///
- /// - /// The object definition holder containing the - /// that - /// is to be registered. - /// - /// - /// The registry that the supplied - /// is to be registered with. - /// - /// - /// If either of the supplied arguments is . - /// - /// - /// If the could not be registered - /// with the . - /// - public static void RegisterObjectDefinition( - ObjectDefinitionHolder objectDefinition, IObjectDefinitionRegistry registry) + registry.RegisterObjectDefinition(objectDefinition.ObjectName, objectDefinition.ObjectDefinition); + var aliases = objectDefinition.Aliases; + for (int i = 0; i < aliases.Count; ++i) { - AssertUtils.ArgumentNotNull(objectDefinition, "objectDefinition"); - AssertUtils.ArgumentNotNull(registry, "registry"); + string alias = aliases[i]; + registry.RegisterAlias(objectDefinition.ObjectName, alias); + } + } - registry.RegisterObjectDefinition(objectDefinition.ObjectName, objectDefinition.ObjectDefinition); - var aliases = objectDefinition.Aliases; - for (int i = 0; i < aliases.Count; ++i) + /// + /// Generates an object definition name for the supplied + /// that is guaranteed to be unique + /// within the scope of the supplied . + /// + /// The + /// that requires a generated name. + /// The + /// + /// that the supplied is to be + /// registered with (needed so that the uniqueness of any generated + /// name can be guaranteed). + /// if set to true if the given object + /// definition will be registed as an inner object or as a top level objener objects + /// verses top level objects. + /// + /// An object definition name for the supplied + /// that is guaranteed to be unique + /// within the scope of the supplied and + /// never . + /// + /// + /// If either of the or + /// arguments is . + /// + /// + /// If a unique name cannot be generated. + /// + public static string GenerateObjectName( + IConfigurableObjectDefinition objectDefinition, IObjectDefinitionRegistry registry, bool isInnerObject) + { + AssertUtils.ArgumentNotNull(objectDefinition, "objectDefinition"); + AssertUtils.ArgumentNotNull(registry, "registry"); + + string generatedObjectName = objectDefinition.ObjectTypeName; + if (StringUtils.IsNullOrEmpty(generatedObjectName)) + { + if (objectDefinition is ChildObjectDefinition) { - string alias = aliases[i]; - registry.RegisterAlias(objectDefinition.ObjectName, alias); + generatedObjectName = ((ChildObjectDefinition) objectDefinition).ParentName + "$child"; + } + else if (objectDefinition.FactoryObjectName != null) + { + generatedObjectName = objectDefinition.FactoryObjectName + "$created"; } } - /// - /// Generates an object definition name for the supplied - /// that is guaranteed to be unique - /// within the scope of the supplied . - /// - /// The - /// that requires a generated name. - /// The - /// - /// that the supplied is to be - /// registered with (needed so that the uniqueness of any generated - /// name can be guaranteed). - /// if set to true if the given object - /// definition will be registed as an inner object or as a top level objener objects - /// verses top level objects. - /// - /// An object definition name for the supplied - /// that is guaranteed to be unique - /// within the scope of the supplied and - /// never . - /// - /// - /// If either of the or - /// arguments is . - /// - /// - /// If a unique name cannot be generated. - /// - public static string GenerateObjectName( - IConfigurableObjectDefinition objectDefinition, IObjectDefinitionRegistry registry, bool isInnerObject) + if (StringUtils.IsNullOrEmpty(generatedObjectName)) { - AssertUtils.ArgumentNotNull(objectDefinition, "objectDefinition"); - AssertUtils.ArgumentNotNull(registry, "registry"); - - string generatedObjectName = objectDefinition.ObjectTypeName; - if (StringUtils.IsNullOrEmpty(generatedObjectName)) + if (!isInnerObject) { - if (objectDefinition is ChildObjectDefinition) - { - generatedObjectName = ((ChildObjectDefinition)objectDefinition).ParentName + "$child"; - } - else if (objectDefinition.FactoryObjectName != null) - { - generatedObjectName = objectDefinition.FactoryObjectName + "$created"; - } - } - if (StringUtils.IsNullOrEmpty(generatedObjectName)) - { - if (!isInnerObject) - { - throw new ObjectDefinitionStoreException( - objectDefinition.ResourceDescription, String.Empty, - "Unnamed object definition specifies neither 'Type' nor 'Parent' " + - "nor 'FactoryObject' property values so a unique name cannot be generated."); - } - generatedObjectName = "$nested"; + throw new ObjectDefinitionStoreException( + objectDefinition.ResourceDescription, String.Empty, + "Unnamed object definition specifies neither 'Type' nor 'Parent' " + + "nor 'FactoryObject' property values so a unique name cannot be generated."); } - String id = generatedObjectName; - if (isInnerObject) - { - id = generatedObjectName + GENERATED_OBJECT_NAME_SEPARATOR + ObjectUtils.GetIdentityHexString(objectDefinition); - } - else - { - int counter = -1; - while (counter == -1 || registry.ContainsObjectDefinition(id)) - { - counter++; - id = generatedObjectName + GENERATED_OBJECT_NAME_SEPARATOR + counter; - } - } - - return id; + generatedObjectName = "$nested"; } - /// - /// Generates the name of the object for a top-level object definition unique within the given object factory. - /// - /// The object definition to generate an object name for. - /// The registry to check for existing names. - /// The generated object name - /// if no unique name can be generated for the given - /// object definition - public static string GenerateObjectName(IConfigurableObjectDefinition definition, IObjectDefinitionRegistry registry) + String id = generatedObjectName; + if (isInnerObject) { - return GenerateObjectName(definition, registry, false); + id = generatedObjectName + GENERATED_OBJECT_NAME_SEPARATOR + ObjectUtils.GetIdentityHexString(objectDefinition); + } + else + { + int counter = -1; + while (counter == -1 || registry.ContainsObjectDefinition(id)) + { + counter++; + id = generatedObjectName + GENERATED_OBJECT_NAME_SEPARATOR + counter; + } } - /// - /// Factory method for getting concrete - /// instances. - /// - /// - /// The name of the event handler method. This may be straight text, a regular - /// expression, , or empty. - /// - /// - /// The name of the event being wired. This too may be straight text, a regular - /// expression, , or empty. - /// - /// - /// A concrete - /// instance. - /// - public static IEventHandlerValue CreateEventHandlerValue( - string methodName, string eventName) + return id; + } + + /// + /// Generates the name of the object for a top-level object definition unique within the given object factory. + /// + /// The object definition to generate an object name for. + /// The registry to check for existing names. + /// The generated object name + /// if no unique name can be generated for the given + /// object definition + public static string GenerateObjectName(IConfigurableObjectDefinition definition, IObjectDefinitionRegistry registry) + { + return GenerateObjectName(definition, registry, false); + } + + /// + /// Factory method for getting concrete + /// instances. + /// + /// + /// The name of the event handler method. This may be straight text, a regular + /// expression, , or empty. + /// + /// + /// The name of the event being wired. This too may be straight text, a regular + /// expression, , or empty. + /// + /// + /// A concrete + /// instance. + /// + public static IEventHandlerValue CreateEventHandlerValue( + string methodName, string eventName) + { + bool weAreAutowiring = false; + if (StringUtils.HasText(eventName)) { - bool weAreAutowiring = false; - if (StringUtils.HasText(eventName)) + // does the value contain regular expression characters? mmm, totally trent... + if (Regex.IsMatch(eventName, @"[\*\.\[\]\{\},\(\)\$\^\+]+")) { - // does the value contain regular expression characters? mmm, totally trent... - if (Regex.IsMatch(eventName, @"[\*\.\[\]\{\},\(\)\$\^\+]+")) - { - // wildcarded event name - weAreAutowiring = true; - } - } - else - { - // we're definitely autowiring based on the event name + // wildcarded event name weAreAutowiring = true; } - if (!weAreAutowiring) + } + else + { + // we're definitely autowiring based on the event name + weAreAutowiring = true; + } + + if (!weAreAutowiring) + { + if (StringUtils.HasText(methodName)) { - if (StringUtils.HasText(methodName)) + // does the value contain the string ${event}? + if (methodName.IndexOf("${event}") >= 0) { - // does the value contain the string ${event}? - if (methodName.IndexOf("${event}") >= 0) - { - // wildcarded method name - weAreAutowiring = true; - } - } - else - { - // we're definitely autowiring based on the method name + // wildcarded method name weAreAutowiring = true; } } - IEventHandlerValue myHandler; - if (weAreAutowiring) - { - myHandler = new AutoWiringEventHandlerValue(); - } else { - myHandler = new InstanceEventHandlerValue(); + // we're definitely autowiring based on the method name + weAreAutowiring = true; } - myHandler.EventName = eventName; - myHandler.MethodName = methodName; - return myHandler; } - - public static String RegisterWithGeneratedName(AbstractObjectDefinition definition, IObjectDefinitionRegistry registry) + IEventHandlerValue myHandler; + if (weAreAutowiring) { - String generatedName = GenerateObjectName(definition, registry, false); - registry.RegisterObjectDefinition(generatedName, definition); - return generatedName; + myHandler = new AutoWiringEventHandlerValue(); } - - - #region Constructor (s) / Destructor - - // CLOVER:OFF - - /// - /// Creates a new instance of the - /// class. - /// - /// - ///

- /// This is a utility class, and as such exposes no public constructors. - ///

- ///
- private ObjectDefinitionReaderUtils() + else { + myHandler = new InstanceEventHandlerValue(); } - // CLOVER:ON - - #endregion + myHandler.EventName = eventName; + myHandler.MethodName = methodName; + return myHandler; } + + public static String RegisterWithGeneratedName(AbstractObjectDefinition definition, IObjectDefinitionRegistry registry) + { + String generatedName = GenerateObjectName(definition, registry, false); + registry.RegisterObjectDefinition(generatedName, definition); + return generatedName; + } + + #region Constructor (s) / Destructor + + // CLOVER:OFF + + /// + /// Creates a new instance of the + /// class. + /// + /// + ///

+ /// This is a utility class, and as such exposes no public constructors. + ///

+ ///
+ private ObjectDefinitionReaderUtils() + { + } + + // CLOVER:ON + + #endregion } diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/ObjectDefinitionValidationException.cs b/src/Spring/Spring.Core/Objects/Factory/Support/ObjectDefinitionValidationException.cs index 8ad2a1ef..446a0f53 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/ObjectDefinitionValidationException.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/ObjectDefinitionValidationException.cs @@ -20,69 +20,70 @@ using System.Runtime.Serialization; -namespace Spring.Objects.Factory.Support +namespace Spring.Objects.Factory.Support; + +/// +/// Thrown when the validation of an object definition failed. +/// +/// Juergen Hoeller +/// Rick Evans (.NET) +[Serializable] +public class ObjectDefinitionValidationException : FatalObjectException { + #region Constructor (s) / Destructor + /// - /// Thrown when the validation of an object definition failed. + /// Creates a new instance of the + /// + /// class. /// - /// Juergen Hoeller - /// Rick Evans (.NET) - [Serializable] - public class ObjectDefinitionValidationException : FatalObjectException + public ObjectDefinitionValidationException() { - #region Constructor (s) / Destructor - /// - /// Creates a new instance of the - /// - /// class. - /// - public ObjectDefinitionValidationException () - { - } - - /// - /// Creates a new instance of the - /// - /// class. - /// - /// The detail message. - public ObjectDefinitionValidationException (string message) - : base (message) - { - } - - /// - /// Creates a new instance of the - /// - /// class. - /// - /// - /// The detail message. - /// - /// - /// The root exception that is being wrapped. - /// - public ObjectDefinitionValidationException (string message, Exception rootCause) - : base (message, rootCause) - { - } - - /// - /// Creates a new instance of the ObjectDefinitionValidationException class. - /// - /// - /// The - /// that holds the serialized object data about the exception being thrown. - /// - /// - /// The - /// that contains contextual information about the source or destination. - /// - protected ObjectDefinitionValidationException ( - SerializationInfo info, StreamingContext context) - : base (info, context) - { - } - #endregion } + + /// + /// Creates a new instance of the + /// + /// class. + /// + /// The detail message. + public ObjectDefinitionValidationException(string message) + : base(message) + { + } + + /// + /// Creates a new instance of the + /// + /// class. + /// + /// + /// The detail message. + /// + /// + /// The root exception that is being wrapped. + /// + public ObjectDefinitionValidationException(string message, Exception rootCause) + : base(message, rootCause) + { + } + + /// + /// Creates a new instance of the ObjectDefinitionValidationException class. + /// + /// + /// The + /// that holds the serialized object data about the exception being thrown. + /// + /// + /// The + /// that contains contextual information about the source or destination. + /// + protected ObjectDefinitionValidationException( + SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + + #endregion } diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/ObjectDefinitionValueResolver.cs b/src/Spring/Spring.Core/Objects/Factory/Support/ObjectDefinitionValueResolver.cs index b1ae6af8..7e3b617c 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/ObjectDefinitionValueResolver.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/ObjectDefinitionValueResolver.cs @@ -22,353 +22,356 @@ using Spring.Core.TypeConversion; using Spring.Expressions; using Spring.Objects.Factory.Config; -namespace Spring.Objects.Factory.Support +namespace Spring.Objects.Factory.Support; + +/// +/// Helper class for use in object factory implementations, +/// resolving values contained in object definition objects +/// into the actual values applied to the target object instance. +/// +/// +/// Used by . +/// +/// Juergen Hoeller +/// Mark Pollack (.NET) +public class ObjectDefinitionValueResolver { + private readonly ILogger log; + + private readonly AbstractObjectFactory objectFactory; + /// - /// Helper class for use in object factory implementations, - /// resolving values contained in object definition objects - /// into the actual values applied to the target object instance. + /// Initializes a new instance of the class. + /// + /// The object factory. + public ObjectDefinitionValueResolver(AbstractObjectFactory objectFactory) + { + log = LogManager.GetLogger(GetType()); + + this.objectFactory = objectFactory; + } + + /// + /// Given a property value, return a value, resolving any references to other + /// objects in the factory if necessary. /// /// - /// Used by . + ///

+ /// The value could be : + /// + /// + ///

+ /// An , + /// which leads to the creation of a corresponding new object instance. + /// Singleton flags and names of such "inner objects" are always ignored: inner objects + /// are anonymous prototypes. + ///

+ /// + /// + ///

+ /// A , which must + /// be resolved. + ///

+ ///
+ /// + ///

+ /// An . This is a + /// special placeholder collection that may contain + /// s or + /// collections that will need to be resolved. + ///

+ ///
+ /// + ///

+ /// An ordinary object or , in which case it's left alone. + ///

+ ///
+ /// + ///

///
- /// Juergen Hoeller - /// Mark Pollack (.NET) - public class ObjectDefinitionValueResolver + /// + /// The name of the object that is having the value of one of its properties resolved. + /// + /// + /// The definition of the named object. + /// + /// + /// The name of the property the value of which is being resolved. + /// + /// + /// The value of the property that is being resolved. + /// + public virtual object ResolveValueIfNecessary(string name, IObjectDefinition definition, string argumentName, object argumentValue) { - private readonly ILogger log; + object resolvedValue = null; + resolvedValue = ResolvePropertyValue(name, definition, argumentName, argumentValue); + return resolvedValue; + } - private readonly AbstractObjectFactory objectFactory; + /// + /// TODO + /// + /// + /// The name of the object that is having the value of one of its properties resolved. + /// + /// + /// The definition of the named object. + /// + /// + /// The name of the property the value of which is being resolved. + /// + /// + /// The value of the property that is being resolved. + /// + private object ResolvePropertyValue(string name, IObjectDefinition definition, string argumentName, object argumentValue) + { + object resolvedValue = null; - /// - /// Initializes a new instance of the class. - /// - /// The object factory. - public ObjectDefinitionValueResolver(AbstractObjectFactory objectFactory) + // we must check the argument value to see whether it requires a runtime + // reference to another object to be resolved. + // if it does, we'll attempt to instantiate the object and set the reference. + if (RemotingServices.IsTransparentProxy(argumentValue)) { - log = LogManager.GetLogger(GetType()); + resolvedValue = argumentValue; + } + else if (argumentValue is ICustomValueReferenceHolder referenceHolder) + { + resolvedValue = referenceHolder.Resolve(objectFactory, name, definition, argumentName, referenceHolder); + } + else if (argumentValue is ObjectDefinitionHolder holder) + { + // contains an IObjectDefinition with name and aliases... + resolvedValue = ResolveInnerObjectDefinition(name, holder.ObjectName, argumentName, holder.ObjectDefinition, definition.IsSingleton); + } + else if (argumentValue is IObjectDefinition def) + { + // resolve plain IObjectDefinition, without contained name: use dummy name... + resolvedValue = ResolveInnerObjectDefinition(name, "(inner object)", argumentName, def, definition.IsSingleton); + } + else if (argumentValue is RuntimeObjectReference reference) + { + resolvedValue = ResolveReference(definition, name, argumentName, reference); + } + else if (argumentValue is ExpressionHolder expHolder) + { + object context = null; + IDictionary variables = null; - this.objectFactory = objectFactory; + if (expHolder.Properties != null) + { + PropertyValue contextProperty = expHolder.Properties.GetPropertyValue("Context"); + context = contextProperty == null + ? null + : ResolveValueIfNecessary(name, definition, "Context", + contextProperty.Value); + PropertyValue variablesProperty = expHolder.Properties.GetPropertyValue("Variables"); + object vars = (variablesProperty == null + ? null + : ResolveValueIfNecessary(name, definition, "Variables", + variablesProperty.Value)); + if (vars is IDictionary objects) + { + variables = objects; + } + + if (vars is IDictionary temp) + { + variables = new Dictionary(temp.Count); + foreach (DictionaryEntry entry in temp) + { + variables.Add((string) entry.Key, entry.Value); + } + } + else + { + if (vars != null) + { + throw new ArgumentException("'Variables' must resolve to an IDictionary"); + } + } + } + + if (variables == null) + { + variables = new Dictionary(StringComparer.OrdinalIgnoreCase); + } + + // add 'this' objectfactory reference to variables + variables.Add(Expression.ReservedVariableNames.CurrentObjectFactory, objectFactory); + + resolvedValue = expHolder.Expression.GetValue(context, variables); + } + else if (argumentValue is IManagedCollection collection) + { + resolvedValue = + collection.Resolve(name, definition, argumentName, ResolveValueIfNecessary); + } + else if (argumentValue is TypedStringValue tsv) + { + try + { + Type resolvedTargetType = ResolveTargetType(tsv); + if (resolvedTargetType != null) + { + resolvedValue = TypeConversionUtils.ConvertValueIfNecessary(tsv.TargetType, tsv.Value, null); + } + else + { + resolvedValue = tsv.Value; + } + } + catch (Exception ex) + { + throw new ObjectCreationException(definition.ResourceDescription, name, + "Error converted typed String value for " + argumentName, ex); + } + } + else + { + // no need to resolve value... + resolvedValue = argumentValue; } - /// - /// Given a property value, return a value, resolving any references to other - /// objects in the factory if necessary. - /// - /// - ///

- /// The value could be : - /// - /// - ///

- /// An , - /// which leads to the creation of a corresponding new object instance. - /// Singleton flags and names of such "inner objects" are always ignored: inner objects - /// are anonymous prototypes. - ///

- /// - /// - ///

- /// A , which must - /// be resolved. - ///

- ///
- /// - ///

- /// An . This is a - /// special placeholder collection that may contain - /// s or - /// collections that will need to be resolved. - ///

- ///
- /// - ///

- /// An ordinary object or , in which case it's left alone. - ///

- ///
- /// - ///

- ///
- /// - /// The name of the object that is having the value of one of its properties resolved. - /// - /// - /// The definition of the named object. - /// - /// - /// The name of the property the value of which is being resolved. - /// - /// - /// The value of the property that is being resolved. - /// - public virtual object ResolveValueIfNecessary(string name, IObjectDefinition definition, string argumentName, object argumentValue) + return resolvedValue; + } + + /// + /// Resolve the target type of the passed . + /// + /// The who's target type is to be resolved + /// The resolved target type, if any. otherwise. + protected virtual Type ResolveTargetType(TypedStringValue value) + { + if (value.HasTargetType) { - object resolvedValue = null; - resolvedValue = ResolvePropertyValue(name, definition, argumentName, argumentValue); - return resolvedValue; + return value.TargetType; } - /// - /// TODO - /// - /// - /// The name of the object that is having the value of one of its properties resolved. - /// - /// - /// The definition of the named object. - /// - /// - /// The name of the property the value of which is being resolved. - /// - /// - /// The value of the property that is being resolved. - /// - private object ResolvePropertyValue(string name, IObjectDefinition definition, string argumentName, object argumentValue) + return value.ResolveTargetType(); + } + + /// + /// Resolves an inner object definition. + /// + /// + /// The name of the object that surrounds this inner object definition. + /// + /// + /// The name of the inner object definition... note: this is a synthetic + /// name assigned by the factory (since it makes no sense for inner object + /// definitions to have names). + /// + /// + /// The name of the property the value of which is being resolved. + /// + /// + /// The definition of the inner object that is to be resolved. + /// + /// + /// if the owner of the property is a singleton. + /// + /// + /// The resolved object as defined by the inner object definition. + /// + protected virtual object ResolveInnerObjectDefinition(string name, string innerObjectName, string argumentName, IObjectDefinition definition, + bool singletonOwner) + { + RootObjectDefinition mod = objectFactory.GetMergedObjectDefinition(innerObjectName, definition); + + // Check given bean name whether it is unique. If not already unique, + // add counter - increasing the counter until the name is unique. + String actualInnerObjectName = innerObjectName; + if (mod.IsSingleton) { - object resolvedValue = null; + actualInnerObjectName = AdaptInnerObjectName(innerObjectName); + } - // we must check the argument value to see whether it requires a runtime - // reference to another object to be resolved. - // if it does, we'll attempt to instantiate the object and set the reference. - if (RemotingServices.IsTransparentProxy(argumentValue)) - { - resolvedValue = argumentValue; - } - else if (argumentValue is ICustomValueReferenceHolder referenceHolder) - { - resolvedValue = referenceHolder.Resolve(objectFactory, name, definition, argumentName, referenceHolder); - } - else if (argumentValue is ObjectDefinitionHolder holder) - { - // contains an IObjectDefinition with name and aliases... - resolvedValue = ResolveInnerObjectDefinition(name, holder.ObjectName, argumentName, holder.ObjectDefinition, definition.IsSingleton); - } - else if (argumentValue is IObjectDefinition def) - { - // resolve plain IObjectDefinition, without contained name: use dummy name... - resolvedValue = ResolveInnerObjectDefinition(name, "(inner object)", argumentName, def, definition.IsSingleton); + mod.IsSingleton = singletonOwner; + object instance; + object result; + try + { + //SPRNET-986 ObjectUtils.EmptyObjects -> null + instance = objectFactory.InstantiateObject(actualInnerObjectName, mod, null, false, false); + result = objectFactory.GetObjectForInstance(instance, actualInnerObjectName, actualInnerObjectName, mod); + } + catch (ObjectsException ex) + { + throw ObjectCreationException.GetObjectCreationException(ex, name, argumentName, definition.ResourceDescription, innerObjectName); + } - } - else if (argumentValue is RuntimeObjectReference reference) - { - resolvedValue = ResolveReference(definition, name, argumentName, reference); - } - else if (argumentValue is ExpressionHolder expHolder) - { - object context = null; - IDictionary variables = null; + if (singletonOwner && instance is IDisposable) + { + // keep a reference to the inner object instance, to be able to destroy + // it on factory shutdown... + objectFactory.DisposableInnerObjects.Add(instance); + } - if (expHolder.Properties != null) - { - PropertyValue contextProperty = expHolder.Properties.GetPropertyValue("Context"); - context = contextProperty == null - ? null - : ResolveValueIfNecessary(name, definition, "Context", - contextProperty.Value); - PropertyValue variablesProperty = expHolder.Properties.GetPropertyValue("Variables"); - object vars = (variablesProperty == null - ? null - : ResolveValueIfNecessary(name, definition, "Variables", - variablesProperty.Value)); - if (vars is IDictionary objects) - { - variables = objects; - } - if (vars is IDictionary temp) - { - variables = new Dictionary(temp.Count); - foreach (DictionaryEntry entry in temp) - { - variables.Add((string) entry.Key, entry.Value); - } - } - else - { - if (vars != null) - { - throw new ArgumentException("'Variables' must resolve to an IDictionary"); - } - } - } + return result; + } - if (variables == null) - { - variables = new Dictionary(StringComparer.OrdinalIgnoreCase); - } - // add 'this' objectfactory reference to variables - variables.Add(Expression.ReservedVariableNames.CurrentObjectFactory, objectFactory); + /// + /// Checks the given bean name whether it is unique. If not already unique, + /// a counter is added, increasing the counter until the name is unique. + /// + /// Original Name of the inner object. + /// The Adapted name for the inner object + private string AdaptInnerObjectName(string innerObjectName) + { + string actualInnerObjectName = innerObjectName; + int counter = 0; + while (this.objectFactory.IsObjectNameInUse(actualInnerObjectName)) + { + counter++; + actualInnerObjectName = innerObjectName + ObjectFactoryUtils.GeneratedObjectNameSeparator + counter; + } - resolvedValue = expHolder.Expression.GetValue(context, variables); - } - else if (argumentValue is IManagedCollection collection) + return actualInnerObjectName; + } + + /// + /// Resolve a reference to another object in the factory. + /// + /// + /// The name of the object that is having the value of one of its properties resolved. + /// + /// + /// The definition of the named object. + /// + /// + /// The name of the property the value of which is being resolved. + /// + /// + /// The runtime reference containing the value of the property. + /// + /// A reference to another object in the factory. + protected virtual object ResolveReference(IObjectDefinition definition, string name, string argumentName, RuntimeObjectReference reference) + { + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug(string.Format(CultureInfo.InvariantCulture, "Resolving reference from property '{0}' in object '{1}' to object '{2}'.", + argumentName, name, reference.ObjectName)); + } + + try + { + if (reference.IsToParent) { - resolvedValue = - collection.Resolve(name, definition, argumentName, ResolveValueIfNecessary); - } - else if (argumentValue is TypedStringValue tsv) - { - try - { - Type resolvedTargetType = ResolveTargetType(tsv); - if (resolvedTargetType != null) - { - resolvedValue = TypeConversionUtils.ConvertValueIfNecessary(tsv.TargetType, tsv.Value, null); - } - else - { - resolvedValue = tsv.Value; - } - } - catch (Exception ex) + if (null == objectFactory.ParentObjectFactory) { throw new ObjectCreationException(definition.ResourceDescription, name, - "Error converted typed String value for " + argumentName, ex); + $"Can't resolve reference to '{reference.ObjectName}' in parent factory: " + + "no parent factory available."); } + return objectFactory.ParentObjectFactory.GetObject(reference.ObjectName); } - else - { - // no need to resolve value... - resolvedValue = argumentValue; - } - return resolvedValue; - } - /// - /// Resolve the target type of the passed . - /// - /// The who's target type is to be resolved - /// The resolved target type, if any. otherwise. - protected virtual Type ResolveTargetType(TypedStringValue value) + return objectFactory.GetObject(reference.ObjectName); + } + catch (ObjectsException ex) { - if (value.HasTargetType) - { - return value.TargetType; - } - return value.ResolveTargetType(); + throw ObjectCreationException.GetObjectCreationException(ex, name, argumentName, definition.ResourceDescription, reference.ObjectName); } - - /// - /// Resolves an inner object definition. - /// - /// - /// The name of the object that surrounds this inner object definition. - /// - /// - /// The name of the inner object definition... note: this is a synthetic - /// name assigned by the factory (since it makes no sense for inner object - /// definitions to have names). - /// - /// - /// The name of the property the value of which is being resolved. - /// - /// - /// The definition of the inner object that is to be resolved. - /// - /// - /// if the owner of the property is a singleton. - /// - /// - /// The resolved object as defined by the inner object definition. - /// - protected virtual object ResolveInnerObjectDefinition(string name, string innerObjectName, string argumentName, IObjectDefinition definition, - bool singletonOwner) - { - RootObjectDefinition mod = objectFactory.GetMergedObjectDefinition(innerObjectName, definition); - - // Check given bean name whether it is unique. If not already unique, - // add counter - increasing the counter until the name is unique. - String actualInnerObjectName = innerObjectName; - if (mod.IsSingleton) - { - actualInnerObjectName = AdaptInnerObjectName(innerObjectName); - } - - - mod.IsSingleton = singletonOwner; - object instance; - object result; - try - { - //SPRNET-986 ObjectUtils.EmptyObjects -> null - instance = objectFactory.InstantiateObject(actualInnerObjectName, mod, null, false, false); - result = objectFactory.GetObjectForInstance(instance, actualInnerObjectName, actualInnerObjectName, mod); - } - catch (ObjectsException ex) - { - throw ObjectCreationException.GetObjectCreationException(ex, name, argumentName, definition.ResourceDescription, innerObjectName); - } - if (singletonOwner && instance is IDisposable) - { - // keep a reference to the inner object instance, to be able to destroy - // it on factory shutdown... - objectFactory.DisposableInnerObjects.Add(instance); - } - return result; - } - - /// - /// Checks the given bean name whether it is unique. If not already unique, - /// a counter is added, increasing the counter until the name is unique. - /// - /// Original Name of the inner object. - /// The Adapted name for the inner object - private string AdaptInnerObjectName(string innerObjectName) - { - string actualInnerObjectName = innerObjectName; - int counter = 0; - while (this.objectFactory.IsObjectNameInUse(actualInnerObjectName)) - { - counter++; - actualInnerObjectName = innerObjectName + ObjectFactoryUtils.GeneratedObjectNameSeparator + counter; - } - return actualInnerObjectName; - } - - /// - /// Resolve a reference to another object in the factory. - /// - /// - /// The name of the object that is having the value of one of its properties resolved. - /// - /// - /// The definition of the named object. - /// - /// - /// The name of the property the value of which is being resolved. - /// - /// - /// The runtime reference containing the value of the property. - /// - /// A reference to another object in the factory. - protected virtual object ResolveReference(IObjectDefinition definition, string name, string argumentName, RuntimeObjectReference reference) - { - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug(string.Format(CultureInfo.InvariantCulture, "Resolving reference from property '{0}' in object '{1}' to object '{2}'.", - argumentName, name, reference.ObjectName)); - } - - try - { - if (reference.IsToParent) - { - if (null == objectFactory.ParentObjectFactory) - { - throw new ObjectCreationException(definition.ResourceDescription, name, - $"Can't resolve reference to '{reference.ObjectName}' in parent factory: " + - "no parent factory available."); - } - return objectFactory.ParentObjectFactory.GetObject(reference.ObjectName); - } - return objectFactory.GetObject(reference.ObjectName); - } - catch (ObjectsException ex) - { - throw ObjectCreationException.GetObjectCreationException(ex, name, argumentName, definition.ResourceDescription, reference.ObjectName); - } - } - - } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/ObjectScope.cs b/src/Spring/Spring.Core/Objects/Factory/Support/ObjectScope.cs index a0121890..56cbf219 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/ObjectScope.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/ObjectScope.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -18,44 +18,43 @@ #endregion -namespace Spring.Objects.Factory.Support +namespace Spring.Objects.Factory.Support; + +/// +/// The possible object scope values. +/// +/// Aleksandar Seovic +public enum ObjectScope { + /// + /// + /// + Singleton = 0, + /// - /// The possible object scope values. + /// Application scope. /// - /// Aleksandar Seovic - public enum ObjectScope - { - /// - /// - /// - Singleton = 0, + Application = Singleton, - /// - /// Application scope. - /// - Application = Singleton, + /// + /// Session scope. + /// + Session = 1, - /// - /// Session scope. - /// - Session = 1, + /// + /// Request scope. + /// + Request = 2, - /// - /// Request scope. - /// - Request = 2, + /// + /// + /// + Prototype = -1, - /// - /// - /// - Prototype = -1, - - /// - /// Default scope (currently - /// ). - /// - /// - Default = Application - } -} \ No newline at end of file + /// + /// Default scope (currently + /// ). + /// + /// + Default = Application +} diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/PropertiesObjectDefinitionReader.cs b/src/Spring/Spring.Core/Objects/Factory/Support/PropertiesObjectDefinitionReader.cs index 911d2eae..c1004a69 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/PropertiesObjectDefinitionReader.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/PropertiesObjectDefinitionReader.cs @@ -26,482 +26,492 @@ using Spring.Core.IO; using Spring.Objects.Factory.Config; using Spring.Util; -namespace Spring.Objects.Factory.Support +namespace Spring.Objects.Factory.Support; + +/// +/// Object definition reader for a simple properties format. +/// +/// +/// Provides object definition registration methods for +/// and +/// instances. Typically applied to a +/// . +/// +/// Rod Johnson +/// Juergen Hoeller +/// Simon White (.NET) +public class PropertiesObjectDefinitionReader : AbstractObjectDefinitionReader { /// - /// Object definition reader for a simple properties format. + /// Value of a T/F attribute that represents true. + /// Anything else represents false. Case seNsItive. + /// + public const string TrueValue = "true"; + + /// + /// Separator between object name and property name. + /// + public const string Separator = "."; + + /// + /// Prefix for the class property of a root object definition. + /// + public const string ClassKey = "class"; + + /// + /// Special string added to distinguish if the object will be + /// a singleton. /// /// - /// Provides object definition registration methods for - /// and - /// instances. Typically applied to a - /// . + ///

+ /// Default is true. + ///

///
- /// Rod Johnson - /// Juergen Hoeller - /// Simon White (.NET) - public class PropertiesObjectDefinitionReader : AbstractObjectDefinitionReader + /// + ///

+ /// owner.(singleton)=true + ///

+ ///
+ public const string SingletonKey = "(singleton)"; + + /// + /// Special string added to distinguish if the object will be + /// lazily initialised. + /// + /// + ///

+ /// Default is false. + ///

+ ///
+ /// + ///

+ /// owner.(lazy-init)=true + ///

+ ///
+ public const string LazyInitKey = "(lazy-init)"; + + /// + /// Reserved "property" to indicate the parent of a child object definition. + /// + public const string ParentKey = "parent"; + + /// + /// Property suffix for references to other objects in the current + /// : e.g. + /// owner.dog(ref)=fido. + /// + /// + ///

+ /// Whether this is a reference to a singleton or a prototype + /// will depend on the definition of the target object. + ///

+ ///
+ public const string RefSuffix = "(ref)"; + + /// + /// Prefix before values referencing other objects. + /// + public const string RefPrefix = "*"; + + private string _defaultParentObject = string.Empty; + + private IObjectDefinitionFactory _objectDefinitionFactory = new DefaultObjectDefinitionFactory(); + + /// + /// Name of default parent object + /// + public string DefaultParentObject { - /// - /// Value of a T/F attribute that represents true. - /// Anything else represents false. Case seNsItive. - /// - public const string TrueValue = "true"; + get { return _defaultParentObject; } + set { this._defaultParentObject = value; } + } - /// - /// Separator between object name and property name. - /// - public const string Separator = "."; + /// + /// Gets or sets object definition factory to use. + /// + public IObjectDefinitionFactory ObjectDefinitionFactory + { + get { return _objectDefinitionFactory; } + set { _objectDefinitionFactory = value; } + } - /// - /// Prefix for the class property of a root object definition. - /// - public const string ClassKey = "class"; + /// + /// Creates a new instance of the + /// + /// class. + /// + /// + /// The + /// instance that this reader works on. + /// + public PropertiesObjectDefinitionReader(IObjectDefinitionRegistry registry) + : base(registry) + { + } - /// - /// Special string added to distinguish if the object will be - /// a singleton. - /// - /// - ///

- /// Default is true. - ///

- ///
- /// - ///

- /// owner.(singleton)=true - ///

- ///
- public const string SingletonKey = "(singleton)"; + /// + /// Load object definitions from the supplied . + /// + /// + /// The resource for the object definitions that are to be loaded. + /// + /// + /// The number of object definitions that were loaded. + /// + /// + /// In the case of loading or parsing errors. + /// + public override int LoadObjectDefinitions(IResource resource) + { + return LoadObjectDefinitions(resource, string.Empty); + } - /// - /// Special string added to distinguish if the object will be - /// lazily initialised. - /// - /// - ///

- /// Default is false. - ///

- ///
- /// - ///

- /// owner.(lazy-init)=true - ///

- ///
- public const string LazyInitKey = "(lazy-init)"; - - /// - /// Reserved "property" to indicate the parent of a child object definition. - /// - public const string ParentKey = "parent"; - - /// - /// Property suffix for references to other objects in the current - /// : e.g. - /// owner.dog(ref)=fido. - /// - /// - ///

- /// Whether this is a reference to a singleton or a prototype - /// will depend on the definition of the target object. - ///

- ///
- public const string RefSuffix = "(ref)"; - - /// - /// Prefix before values referencing other objects. - /// - public const string RefPrefix = "*"; - - private string _defaultParentObject = string.Empty; - - private IObjectDefinitionFactory _objectDefinitionFactory = new DefaultObjectDefinitionFactory(); - - /// - /// Name of default parent object - /// - public string DefaultParentObject + /// + /// Load object definitions from the specified properties file. + /// + /// + /// The resource descriptor for the properties file. + /// + /// + /// The match or filter for object definition names, e.g. 'objects.' + /// + /// in case of loading or parsing errors + /// the number of object definitions found + public int LoadObjectDefinitions(IResource resource, string prefix) + { + Properties props = new Properties(); + try { - get { return _defaultParentObject; } - set { this._defaultParentObject = value; } - } - - /// - /// Gets or sets object definition factory to use. - /// - public IObjectDefinitionFactory ObjectDefinitionFactory - { - get { return _objectDefinitionFactory; } - set { _objectDefinitionFactory = value; } - } - - /// - /// Creates a new instance of the - /// - /// class. - /// - /// - /// The - /// instance that this reader works on. - /// - public PropertiesObjectDefinitionReader(IObjectDefinitionRegistry registry) - : base(registry) - {} - - /// - /// Load object definitions from the supplied . - /// - /// - /// The resource for the object definitions that are to be loaded. - /// - /// - /// The number of object definitions that were loaded. - /// - /// - /// In the case of loading or parsing errors. - /// - public override int LoadObjectDefinitions(IResource resource) - { - return LoadObjectDefinitions(resource, string.Empty); - } - - /// - /// Load object definitions from the specified properties file. - /// - /// - /// The resource descriptor for the properties file. - /// - /// - /// The match or filter for object definition names, e.g. 'objects.' - /// - /// in case of loading or parsing errors - /// the number of object definitions found - public int LoadObjectDefinitions(IResource resource, string prefix) - { - Properties props = new Properties(); + Stream str = resource.InputStream; try { - Stream str = resource.InputStream; - try + props.Load(str); + } + finally + { + str.Close(); + } + + return RegisterObjectDefinitions(props, prefix, resource.Description); + } + catch (IOException ex) + { + throw new ObjectDefinitionStoreException("IOException parsing properties from " + resource, ex); + } + } + + /// + /// Register object definitions contained in a + /// , using all property keys (i.e. + /// not filtering by prefix). + /// + /// + /// The containing object definitions. + /// + /// + /// In case of loading or parsing errors. + /// + /// The number of object definitions registered. + public int RegisterObjectDefinitions(ResourceSet rs) + { + return RegisterObjectDefinitions(rs, string.Empty); + } + + /// + /// Register object definitions contained in a + /// . + /// + /// + ///

+ /// Similar syntax as for an . + /// This method is useful to enable standard .NET internationalization support. + ///

+ ///
+ /// + /// The containing object definitions. + /// + /// + /// The match or filter for object definition names, e.g. 'objects.' + /// + /// + /// In case of loading or parsing errors. + /// + /// The number of object definitions registered. + public int RegisterObjectDefinitions(ResourceSet rs, string prefix) + { + // Simply create a map and call overloaded method + IDictionary id = new Hashtable(); + foreach (DictionaryEntry de in rs) + { + id.Add(de.Key, de.Value); + } + + return RegisterObjectDefinitions(id, prefix); + } + + /// + /// Register object definitions contained in an + /// , using all property keys + /// (i.e. not filtering by prefix). + /// + /// + /// The containing object definitions. + /// + /// + /// In case of loading or parsing errors. + /// + /// The number of object definitions registered. + public int RegisterObjectDefinitions(IDictionary id) + { + return RegisterObjectDefinitions(id, string.Empty); + } + + /// + /// Registers object definitions contained in an + /// using all property keys ( i.e. not filtering by prefix ) + /// + /// The containing + /// object definitions. + /// + /// + /// In case of loading or parsing errors. + /// + /// The number of object definitions registered. + public int RegisterObjectDefinitions(NameValueCollection nameValueCollection) + { + IDictionary id = new Hashtable(); + foreach (DictionaryEntry de in nameValueCollection) + { + id.Add(de.Key, de.Value); + } + + return RegisterObjectDefinitions(id); + } + + /// + /// Register object definitions contained in a + /// . + /// + /// + ///

+ /// Ignores ineligible properties. + ///

+ ///
+ /// IDictionary name -> property (String or Object). Property values + /// will be strings if coming from a Properties file etc. Property names + /// (keys) must be strings. Type keys must be strings. + /// + /// + /// The match or filter within the keys in the map: e.g. 'objects.' + /// + /// + /// In case of loading or parsing errors. + /// + /// The number of object definitions found. + public int RegisterObjectDefinitions(IDictionary id, string prefix) + { + return RegisterObjectDefinitions(id, prefix, "(no description)"); + } + + /// + /// Register object definitions contained in a + /// . + /// + /// + ///

+ /// Ignores ineligible properties. + ///

+ ///
+ /// IDictionary name -> property (String or Object). Property values + /// will be strings if coming from a Properties file etc. Property names + /// (keys) must be strings. Type keys must be strings. + /// + /// + /// The match or filter within the keys in the map: e.g. 'objects.' + /// + /// + /// The description of the resource that the + /// came from (for logging purposes). + /// + /// + /// In case of loading or parsing errors. + /// + /// The number of object definitions found. + public int RegisterObjectDefinitions( + IDictionary id, string prefix, string resourceDescription) + { + if (prefix == null) + { + prefix = string.Empty; + } + + int objectCount = 0; + foreach (string key in id.Keys) + { + if (key.StartsWith(prefix)) + { + // Key is of form prefix.property + string nameAndProperty = key.Substring(prefix.Length); + int sepIndx = nameAndProperty.IndexOf(Separator); + if (sepIndx != -1) { - props.Load(str); + string name = nameAndProperty.Substring(0, sepIndx); + + #region Instrumentation + + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug("Found object name '" + name + "'"); + } + + #endregion + + if (!Registry.ContainsObjectDefinition(name)) + { + ++objectCount; + } + + RegisterObjectDefinition(name, id, prefix + name, resourceDescription); } - finally + else { - str.Close(); + // Ignore it: it wasn't a valid object name and property, + // although it did start with the required prefix + + #region Instrumentation + + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug("Invalid object name and property [" + nameAndProperty + "]"); + } + + #endregion } - return RegisterObjectDefinitions(props, prefix, resource.Description); - } - catch (IOException ex) + } // if the key started with the prefix we're looking for + } // while there are more keys + + return objectCount; + } + + /// + /// Get all property values, given a prefix (which will be stripped) + /// and add the object they define to the factory with the given name + /// + /// The name of the object to define. + /// + /// The containing string pairs. + /// + /// The prefix of each entry, which will be stripped. + /// + /// The description of the resource that the + /// came from (for logging purposes). + /// + /// + /// In case of loading or parsing errors. + /// + protected void RegisterObjectDefinition( + string name, IDictionary id, string prefix, string resourceDescription) + { + string typeName = null; + string parent = null; + bool singleton = true; + bool lazyInit = false; + + MutablePropertyValues pvs = new MutablePropertyValues(); + foreach (string key in id.Keys) + { + if (key.StartsWith(prefix + Separator)) { - throw new ObjectDefinitionStoreException("IOException parsing properties from " + resource, ex); - } - } - - /// - /// Register object definitions contained in a - /// , using all property keys (i.e. - /// not filtering by prefix). - /// - /// - /// The containing object definitions. - /// - /// - /// In case of loading or parsing errors. - /// - /// The number of object definitions registered. - public int RegisterObjectDefinitions(ResourceSet rs) - { - return RegisterObjectDefinitions(rs, string.Empty); - } - - /// - /// Register object definitions contained in a - /// . - /// - /// - ///

- /// Similar syntax as for an . - /// This method is useful to enable standard .NET internationalization support. - ///

- ///
- /// - /// The containing object definitions. - /// - /// - /// The match or filter for object definition names, e.g. 'objects.' - /// - /// - /// In case of loading or parsing errors. - /// - /// The number of object definitions registered. - public int RegisterObjectDefinitions(ResourceSet rs, string prefix) - { - // Simply create a map and call overloaded method - IDictionary id = new Hashtable(); - foreach (DictionaryEntry de in rs) - { - id.Add(de.Key, de.Value); - } - return RegisterObjectDefinitions(id, prefix); - } - - /// - /// Register object definitions contained in an - /// , using all property keys - /// (i.e. not filtering by prefix). - /// - /// - /// The containing object definitions. - /// - /// - /// In case of loading or parsing errors. - /// - /// The number of object definitions registered. - public int RegisterObjectDefinitions(IDictionary id) - { - return RegisterObjectDefinitions(id, string.Empty); - } - - /// - /// Registers object definitions contained in an - /// using all property keys ( i.e. not filtering by prefix ) - /// - /// The containing - /// object definitions. - /// - /// - /// In case of loading or parsing errors. - /// - /// The number of object definitions registered. - public int RegisterObjectDefinitions(NameValueCollection nameValueCollection) - { - IDictionary id = new Hashtable(); - foreach (DictionaryEntry de in nameValueCollection) - { - id.Add(de.Key, de.Value); - } - - return RegisterObjectDefinitions(id); - } - - /// - /// Register object definitions contained in a - /// . - /// - /// - ///

- /// Ignores ineligible properties. - ///

- ///
- /// IDictionary name -> property (String or Object). Property values - /// will be strings if coming from a Properties file etc. Property names - /// (keys) must be strings. Type keys must be strings. - /// - /// - /// The match or filter within the keys in the map: e.g. 'objects.' - /// - /// - /// In case of loading or parsing errors. - /// - /// The number of object definitions found. - public int RegisterObjectDefinitions(IDictionary id, string prefix) - { - return RegisterObjectDefinitions(id, prefix, "(no description)"); - } - - /// - /// Register object definitions contained in a - /// . - /// - /// - ///

- /// Ignores ineligible properties. - ///

- ///
- /// IDictionary name -> property (String or Object). Property values - /// will be strings if coming from a Properties file etc. Property names - /// (keys) must be strings. Type keys must be strings. - /// - /// - /// The match or filter within the keys in the map: e.g. 'objects.' - /// - /// - /// The description of the resource that the - /// came from (for logging purposes). - /// - /// - /// In case of loading or parsing errors. - /// - /// The number of object definitions found. - public int RegisterObjectDefinitions( - IDictionary id, string prefix, string resourceDescription) - { - if (prefix == null) - { - prefix = string.Empty; - } - int objectCount = 0; - foreach (string key in id.Keys) - { - if (key.StartsWith(prefix)) + string property = key.Substring(prefix.Length + Separator.Length); + if (property.Equals(ClassKey)) { - // Key is of form prefix.property - string nameAndProperty = key.Substring(prefix.Length); - int sepIndx = nameAndProperty.IndexOf(Separator); - if (sepIndx != -1) - { - string name = nameAndProperty.Substring(0, sepIndx); - - #region Instrumentation - - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug("Found object name '" + name + "'"); - } - - #endregion - - if (!Registry.ContainsObjectDefinition(name)) - { - ++objectCount; - } - RegisterObjectDefinition(name, id, prefix + name, resourceDescription); - } - else - { - // Ignore it: it wasn't a valid object name and property, - // although it did start with the required prefix - - #region Instrumentation - - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug("Invalid object name and property [" + nameAndProperty + "]"); - } - - #endregion - } - } // if the key started with the prefix we're looking for - } // while there are more keys - return objectCount; - } - - /// - /// Get all property values, given a prefix (which will be stripped) - /// and add the object they define to the factory with the given name - /// - /// The name of the object to define. - /// - /// The containing string pairs. - /// - /// The prefix of each entry, which will be stripped. - /// - /// The description of the resource that the - /// came from (for logging purposes). - /// - /// - /// In case of loading or parsing errors. - /// - protected void RegisterObjectDefinition( - string name, IDictionary id, string prefix, string resourceDescription) - { - string typeName = null; - string parent = null; - bool singleton = true; - bool lazyInit = false; - - MutablePropertyValues pvs = new MutablePropertyValues(); - foreach (string key in id.Keys) - { - if (key.StartsWith(prefix + Separator)) + typeName = (string) id[key]; + } + else if (property.Equals(SingletonKey)) { - string property = key.Substring(prefix.Length + Separator.Length); - if (property.Equals(ClassKey)) - { - typeName = (string) id[key]; - } - else if (property.Equals(SingletonKey)) - { - string val = (string) id[key]; - singleton = (val == null) || val.Equals(TrueValue); - } - else if (property.Equals(LazyInitKey)) - { - string val = (string) id[key]; - lazyInit = val.Equals(TrueValue); - } - else if (property.Equals(ParentKey)) - { - parent = (string) id[key]; - } - else if (property.EndsWith(RefSuffix)) - { - // This isn't a real property, but a reference to another prototype - // Extract property name: property is of form dog(ref) - property = property.Substring(0, property.Length - RefSuffix.Length); - string reference = (String) id[key]; + string val = (string) id[key]; + singleton = (val == null) || val.Equals(TrueValue); + } + else if (property.Equals(LazyInitKey)) + { + string val = (string) id[key]; + lazyInit = val.Equals(TrueValue); + } + else if (property.Equals(ParentKey)) + { + parent = (string) id[key]; + } + else if (property.EndsWith(RefSuffix)) + { + // This isn't a real property, but a reference to another prototype + // Extract property name: property is of form dog(ref) + property = property.Substring(0, property.Length - RefSuffix.Length); + string reference = (String) id[key]; - // It doesn't matter if the referenced object hasn't yet been registered: - // this will ensure that the reference is resolved at runtime - // Default is not to use singleton - object val = new RuntimeObjectReference(reference); - pvs.Add(new PropertyValue(property, val)); - } - else + // It doesn't matter if the referenced object hasn't yet been registered: + // this will ensure that the reference is resolved at runtime + // Default is not to use singleton + object val = new RuntimeObjectReference(reference); + pvs.Add(new PropertyValue(property, val)); + } + else + { + // normal object property + object val = id[key]; + if (val is String) { - // normal object property - object val = id[key]; - if (val is String) + string strVal = (string) val; + // if it starts with a reference prefix... + if (strVal.StartsWith(RefPrefix)) { - string strVal = (string) val; - // if it starts with a reference prefix... - if (strVal.StartsWith(RefPrefix)) + // expand reference + string targetName = strVal.Substring(1); + if (targetName.StartsWith(RefPrefix)) { - // expand reference - string targetName = strVal.Substring(1); - if (targetName.StartsWith(RefPrefix)) - { - // escaped prefix -> use plain value - val = targetName; - } - else - { - val = new RuntimeObjectReference(targetName); - } + // escaped prefix -> use plain value + val = targetName; + } + else + { + val = new RuntimeObjectReference(targetName); } } - pvs.Add(new PropertyValue(property, val)); } + + pvs.Add(new PropertyValue(property, val)); } } - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug(pvs.ToString()); - } - if (parent == null) - { - log.LogDebug(this.DefaultParentObject); - parent = this.DefaultParentObject; - } - if (typeName == null && parent == null) - { - throw new ObjectDefinitionStoreException(resourceDescription, name, - "Either 'type' or 'parent' is required"); - } - try - { - IConfigurableObjectDefinition objectDefinition = ObjectDefinitionFactory.CreateObjectDefinition(typeName, parent, Domain); - objectDefinition.PropertyValues = pvs; - objectDefinition.IsSingleton = singleton; - objectDefinition.IsLazyInit = lazyInit; - Registry.RegisterObjectDefinition(name, objectDefinition); - } - catch (Exception ex) - { - throw new ObjectDefinitionStoreException( - resourceDescription, name, "Unable to load type [" + typeName + "]", ex); - } + } + + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug(pvs.ToString()); + } + + if (parent == null) + { + log.LogDebug(this.DefaultParentObject); + parent = this.DefaultParentObject; + } + + if (typeName == null && parent == null) + { + throw new ObjectDefinitionStoreException(resourceDescription, name, + "Either 'type' or 'parent' is required"); + } + + try + { + IConfigurableObjectDefinition objectDefinition = ObjectDefinitionFactory.CreateObjectDefinition(typeName, parent, Domain); + objectDefinition.PropertyValues = pvs; + objectDefinition.IsSingleton = singleton; + objectDefinition.IsLazyInit = lazyInit; + Registry.RegisterObjectDefinition(name, objectDefinition); + } + catch (Exception ex) + { + throw new ObjectDefinitionStoreException( + resourceDescription, name, "Unable to load type [" + typeName + "]", ex); } } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/RootObjectDefinition.cs b/src/Spring/Spring.Core/Objects/Factory/Support/RootObjectDefinition.cs index e1d590b7..59a07ef7 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/RootObjectDefinition.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/RootObjectDefinition.cs @@ -20,294 +20,292 @@ using System.Reflection; using System.Runtime.Serialization; - using Spring.Objects.Factory.Config; -namespace Spring.Objects.Factory.Support +namespace Spring.Objects.Factory.Support; + +/// +/// A plain-vanilla object definition. +/// +/// +///

+/// This is the most common type of object definition; +/// instances +/// do not derive from a parent +/// , and usually +/// (but not always - see below) have an +/// +/// and (optionally) some +/// and +/// . +///

+///

+/// Note that +/// instances do not have to specify an +/// : +/// This can be useful for deriving +/// instances +/// from such definitions, each with it's own +/// , +/// inheriting common property values and other settings from the parent. +///

+///
+/// Rod Johnson +/// Juergen Hoeller +/// Rick Evans (.NET) +/// +[Serializable] +public class RootObjectDefinition : AbstractObjectDefinition { + internal ConstructorInfo[] defaultConstructor; + /// - /// A plain-vanilla object definition. + /// Creates a new instance of the + /// class. + /// + public RootObjectDefinition() + { + } + + /// + /// Creates a new instance of the + /// + /// class. + /// + /// + /// The of the object to instantiate. + /// + public RootObjectDefinition(Type type) + { + ObjectType = type; + } + + /// + /// Creates a new instance of the + /// + /// class. + /// + /// + /// The of the object to instantiate. + /// + /// + /// if this object definition defines a singleton object. + /// + public RootObjectDefinition(Type type, bool singleton) + { + ObjectType = type; + IsSingleton = singleton; + } + + /// + /// Creates a new instance of the + /// class + /// for a singleton, providing property values and constructor arguments. + /// + /// + /// The of the object to instantiate. + /// + /// + /// The + /// to be applied to a new instance of the object. + /// + /// + /// The to be applied to + /// a new instance of the object. + /// + public RootObjectDefinition( + Type type, ConstructorArgumentValues arguments, MutablePropertyValues properties) + : base(arguments, properties) + { + ObjectType = type; + } + + /// + /// Creates a new instance of the + /// class + /// for a singleton using the supplied + /// . + /// + /// + /// The of the object to instantiate. + /// + /// + /// The autowiring mode. + /// + public RootObjectDefinition(Type type, AutoWiringMode autowireMode) + { + ObjectType = type; + AutowireMode = autowireMode; + } + + /// + /// Creates a new instance of the + /// class + /// for a singleton using the supplied + /// . + /// + /// + /// The of the object to instantiate. + /// + /// + /// The autowiring mode. + /// + /// + /// Whether to perform a dependency check for objects (not + /// applicable to autowiring a constructor, thus ignored there) + /// + public RootObjectDefinition( + Type type, AutoWiringMode autowireMode, bool dependencyCheck) + { + ObjectType = type; + AutowireMode = autowireMode; + if (dependencyCheck + && ResolvedAutowireMode != AutoWiringMode.Constructor) + { + DependencyCheck = DependencyCheckingMode.Objects; + } + } + + /// + /// Creates a new instance of the + /// class + /// with the given singleton status, providing property values. + /// + /// + /// The of the object to instantiate. + /// + /// + /// The to be applied to + /// a new instance of the object. + /// + public RootObjectDefinition( + Type type, MutablePropertyValues properties) : base(null, properties) + { + ObjectType = type; + } + + /// + /// Creates a new instance of the + /// class + /// with the given singleton status, providing property values. + /// + /// + /// The of the object to instantiate. + /// + /// + /// The to be applied to + /// a new instance of the object. + /// + /// + /// if this object definition defines a singleton object. + /// + public RootObjectDefinition( + Type type, MutablePropertyValues properties, bool singleton) : base(null, properties) + { + ObjectType = type; + IsSingleton = singleton; + } + + /// + /// Creates a new instance of the + /// class + /// for a singleton, providing property values and constructor arguments. /// /// ///

- /// This is the most common type of object definition; - /// instances - /// do not derive from a parent - /// , and usually - /// (but not always - see below) have an - /// - /// and (optionally) some - /// and - /// . - ///

- ///

- /// Note that - /// instances do not have to specify an - /// : - /// This can be useful for deriving - /// instances - /// from such definitions, each with it's own - /// , - /// inheriting common property values and other settings from the parent. + /// Takes an object class name to avoid eager loading of the object class. ///

///
- /// Rod Johnson - /// Juergen Hoeller - /// Rick Evans (.NET) - /// - [Serializable] - public class RootObjectDefinition : AbstractObjectDefinition + /// + /// The assembly qualified of the object to instantiate. + /// + /// + /// The to be applied to + /// a new instance of the object. + /// + /// + /// The + /// to be applied to a new instance of the object. + /// + public RootObjectDefinition( + string typeName, ConstructorArgumentValues arguments, MutablePropertyValues properties) + : base(arguments, properties) { - internal ConstructorInfo[] defaultConstructor; + ObjectTypeName = typeName; + } - /// - /// Creates a new instance of the - /// class. - /// - public RootObjectDefinition() - {} + /// + /// Creates a new instance of the + /// class. + /// + /// + ///

+ /// Deep copy constructor. + ///

+ ///
+ /// + /// The definition that is to be copied. + /// + public RootObjectDefinition(IObjectDefinition other) : base(other) + { + } - /// - /// Creates a new instance of the - /// - /// class. - /// - /// - /// The of the object to instantiate. - /// - public RootObjectDefinition(Type type) + protected RootObjectDefinition(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + + /// + /// Is always null for a . + /// + /// + /// It is safe to request this property's value. Setting any other value than null will + /// raise an . + /// + /// Raised on any attempt to set a non-null value on this property. + public override string ParentName + { + get => null; + set { - ObjectType = type; - } - - /// - /// Creates a new instance of the - /// - /// class. - /// - /// - /// The of the object to instantiate. - /// - /// - /// if this object definition defines a singleton object. - /// - public RootObjectDefinition(Type type, bool singleton) - { - ObjectType = type; - IsSingleton = singleton; - } - - /// - /// Creates a new instance of the - /// class - /// for a singleton, providing property values and constructor arguments. - /// - /// - /// The of the object to instantiate. - /// - /// - /// The - /// to be applied to a new instance of the object. - /// - /// - /// The to be applied to - /// a new instance of the object. - /// - public RootObjectDefinition( - Type type, ConstructorArgumentValues arguments, MutablePropertyValues properties) - : base(arguments, properties) - { - ObjectType = type; - } - - - /// - /// Creates a new instance of the - /// class - /// for a singleton using the supplied - /// . - /// - /// - /// The of the object to instantiate. - /// - /// - /// The autowiring mode. - /// - public RootObjectDefinition(Type type, AutoWiringMode autowireMode) - { - ObjectType = type; - AutowireMode = autowireMode; - } - - /// - /// Creates a new instance of the - /// class - /// for a singleton using the supplied - /// . - /// - /// - /// The of the object to instantiate. - /// - /// - /// The autowiring mode. - /// - /// - /// Whether to perform a dependency check for objects (not - /// applicable to autowiring a constructor, thus ignored there) - /// - public RootObjectDefinition( - Type type, AutoWiringMode autowireMode, bool dependencyCheck) - { - ObjectType = type; - AutowireMode = autowireMode; - if (dependencyCheck - && ResolvedAutowireMode != AutoWiringMode.Constructor) + if (value != null) { - DependencyCheck = DependencyCheckingMode.Objects; + throw new ArgumentException("Root Object cannot be changed into a child oject with parent reference"); } } - - /// - /// Creates a new instance of the - /// class - /// with the given singleton status, providing property values. - /// - /// - /// The of the object to instantiate. - /// - /// - /// The to be applied to - /// a new instance of the object. - /// - public RootObjectDefinition( - Type type, MutablePropertyValues properties) : base(null, properties) - { - ObjectType = type; - } - - /// - /// Creates a new instance of the - /// class - /// with the given singleton status, providing property values. - /// - /// - /// The of the object to instantiate. - /// - /// - /// The to be applied to - /// a new instance of the object. - /// - /// - /// if this object definition defines a singleton object. - /// - public RootObjectDefinition( - Type type, MutablePropertyValues properties, bool singleton) : base(null, properties) - { - ObjectType = type; - IsSingleton = singleton; - } - - /// - /// Creates a new instance of the - /// class - /// for a singleton, providing property values and constructor arguments. - /// - /// - ///

- /// Takes an object class name to avoid eager loading of the object class. - ///

- ///
- /// - /// The assembly qualified of the object to instantiate. - /// - /// - /// The to be applied to - /// a new instance of the object. - /// - /// - /// The - /// to be applied to a new instance of the object. - /// - public RootObjectDefinition( - string typeName, ConstructorArgumentValues arguments, MutablePropertyValues properties) - : base(arguments, properties) - { - ObjectTypeName = typeName; - } - - /// - /// Creates a new instance of the - /// class. - /// - /// - ///

- /// Deep copy constructor. - ///

- ///
- /// - /// The definition that is to be copied. - /// - public RootObjectDefinition(IObjectDefinition other) : base(other) - { - } - - protected RootObjectDefinition(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } - - /// - /// Is always null for a . - /// - /// - /// It is safe to request this property's value. Setting any other value than null will - /// raise an . - /// - /// Raised on any attempt to set a non-null value on this property. - public override string ParentName - { - get => null; - set - { - if (value != null) - { - throw new ArgumentException("Root Object cannot be changed into a child oject with parent reference"); - } - } - } - - /// - /// Validate this object definition. - /// - /// - /// In the case of a validation failure. - /// - public override void Validate() - { - base.Validate(); - if (HasObjectType) - { - if (typeof(IFactoryObject).IsAssignableFrom(ObjectType) - && !IsSingleton) - { - throw new ObjectDefinitionValidationException( - "IFactoryObject must be defined as a singleton - " + - "IFactoryObjects themselves are not allowed to be prototypes."); - } - } - } - - /// - /// A that represents the current - /// . - /// - /// - /// A that represents the current - /// . - /// - public override string ToString() - { - return $"{GetType().Name} : {base.ToString()}"; - } + } + + /// + /// Validate this object definition. + /// + /// + /// In the case of a validation failure. + /// + public override void Validate() + { + base.Validate(); + if (HasObjectType) + { + if (typeof(IFactoryObject).IsAssignableFrom(ObjectType) + && !IsSingleton) + { + throw new ObjectDefinitionValidationException( + "IFactoryObject must be defined as a singleton - " + + "IFactoryObjects themselves are not allowed to be prototypes."); + } + } + } + + /// + /// A that represents the current + /// . + /// + /// + /// A that represents the current + /// . + /// + public override string ToString() + { + return $"{GetType().Name} : {base.ToString()}"; } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/SimpleAutowireCandidateResolver.cs b/src/Spring/Spring.Core/Objects/Factory/Support/SimpleAutowireCandidateResolver.cs index 5c291f5f..78942b59 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/SimpleAutowireCandidateResolver.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/SimpleAutowireCandidateResolver.cs @@ -20,42 +20,40 @@ using Spring.Objects.Factory.Config; -namespace Spring.Objects.Factory.Support +namespace Spring.Objects.Factory.Support; + +/// +/// A implementation to use that checks +/// the object definitions only (no attributes) +/// +/// Mark Fisher +/// Mark Pollack (.NET) +[Serializable] +public class SimpleAutowireCandidateResolver : IAutowireCandidateResolver { /// - /// A implementation to use that checks - /// the object definitions only (no attributes) + /// Determines whether the given object definition qualifies as an + /// autowire candidate for the given dependency. /// - /// Mark Fisher - /// Mark Pollack (.NET) - [Serializable] - public class SimpleAutowireCandidateResolver : IAutowireCandidateResolver + /// The object definition including object name and aliases. + /// The descriptor for the target method parameter or field. + /// + /// true if the object definition qualifies as autowire candidate; otherwise, false. + /// + public bool IsAutowireCandidate(ObjectDefinitionHolder odHolder, DependencyDescriptor descriptor) { - /// - /// Determines whether the given object definition qualifies as an - /// autowire candidate for the given dependency. - /// - /// The object definition including object name and aliases. - /// The descriptor for the target method parameter or field. - /// - /// true if the object definition qualifies as autowire candidate; otherwise, false. - /// - public bool IsAutowireCandidate(ObjectDefinitionHolder odHolder, DependencyDescriptor descriptor) - { - return odHolder.ObjectDefinition.IsAutowireCandidate; - } + return odHolder.ObjectDefinition.IsAutowireCandidate; + } - - /// - /// Determine whether a default value is suggested for the given dependency. - /// - /// The descriptor for the target method parameter or field - /// The value suggested (typically an expression String), - /// or null if none found - /// - public object GetSuggestedValue(DependencyDescriptor descriptor) - { - return null; - } + /// + /// Determine whether a default value is suggested for the given dependency. + /// + /// The descriptor for the target method parameter or field + /// The value suggested (typically an expression String), + /// or null if none found + /// + public object GetSuggestedValue(DependencyDescriptor descriptor) + { + return null; } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/SimpleInstantiationStrategy.cs b/src/Spring/Spring.Core/Objects/Factory/Support/SimpleInstantiationStrategy.cs index 19687d38..088b9cc4 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/SimpleInstantiationStrategy.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/SimpleInstantiationStrategy.cs @@ -24,279 +24,281 @@ using Microsoft.Extensions.Logging; using Spring.Core.TypeResolution; using Spring.Util; -namespace Spring.Objects.Factory.Support +namespace Spring.Objects.Factory.Support; + +/// +/// Simple object instantiation strategy for use in +/// implementations. +/// +/// +///

+/// Does not support method injection, although it provides hooks for subclasses +/// to override to add method injection support, for example by overriding methods. +///

+///
+/// Rod Johnson +/// Rick Evans (.NET) +/// +[Serializable] +public class SimpleInstantiationStrategy : IInstantiationStrategy { /// - /// Simple object instantiation strategy for use in - /// implementations. + /// The shared instance for this class (and derived classes). + /// + protected static readonly ILogger log = LogManager.GetLogger(); + + /// + /// Instantiate an instance of the object described by the supplied + /// from the supplied . + /// + /// + /// The definition of the object that is to be instantiated. + /// + /// + /// The name associated with the object definition. The name can be the null + /// or zero length string if we're autowiring an object that doesn't belong + /// to the supplied . + /// + /// + /// The owning + /// + /// + /// An instance of the object described by the supplied + /// from the supplied . + /// + public virtual object Instantiate( + RootObjectDefinition definition, string name, IObjectFactory factory) + { + AssertUtils.ArgumentNotNull(definition, "definition"); + AssertUtils.ArgumentNotNull(factory, "factory"); + + if (log.IsEnabled(LogLevel.Trace)) log.LogTrace(string.Format("instantiating object '{0}'", name)); + + if (definition.HasMethodOverrides) + { + return InstantiateWithMethodInjection(definition, name, factory); + } + else + { + Type objectType = definition.HasObjectType + ? definition.ObjectType + : TypeResolutionUtils.ResolveType(definition.ObjectTypeName); + ConstructorInfo constructor = GetZeroArgConstructorInfo(objectType); + return ObjectUtils.InstantiateType(constructor, ObjectUtils.EmptyObjects); + } + } + + /// + /// Gets the zero arg ConstructorInfo object, if the type offers such functionality. + /// + /// The type. + /// Zero argument ConstructorInfo + /// + /// If the type does not have a zero-arg constructor. + /// + private ConstructorInfo GetZeroArgConstructorInfo(Type type) + { + const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | + BindingFlags.Instance | BindingFlags.DeclaredOnly; + + ConstructorInfo constructor = type.GetConstructor(flags, null, Type.EmptyTypes, null); + if (constructor == null) + { + throw new FatalReflectionException(string.Format( + CultureInfo.InvariantCulture, "Cannot instantiate a class that does not have a no-argument constructor [{0}].", type)); + } + + return constructor; + } + + /// + /// Instantiate an instance of the object described by the supplied + /// from the supplied . + /// + /// + /// The definition of the object that is to be instantiated. + /// + /// + /// The name associated with the object definition. The name can be the null + /// or zero length string if we're autowiring an object that doesn't belong + /// to the supplied . + /// + /// + /// The owning + /// + /// + /// The to be used to instantiate + /// the object. + /// + /// + /// Any arguments to the supplied . May be null. + /// + /// + /// An instance of the object described by the supplied + /// from the supplied . + /// + public virtual object Instantiate( + RootObjectDefinition definition, string name, IObjectFactory factory, + ConstructorInfo constructor, object[] arguments) + { + if (definition.HasMethodOverrides) + { + return InstantiateWithMethodInjection(definition, name, factory, constructor, arguments); + } + else + { + return ObjectUtils.InstantiateType(constructor, arguments); + } + } + + /// + /// Instantiate an instance of the object described by the supplied + /// from the supplied . + /// + /// + /// The definition of the object that is to be instantiated. + /// + /// + /// The name associated with the object definition. The name can be the null + /// or zero length string if we're autowiring an object that doesn't belong + /// to the supplied . + /// + /// + /// The owning + /// + /// + /// The to be used to get the object. + /// + /// + /// Any arguments to the supplied . May be null. + /// + /// + /// An instance of the object described by the supplied + /// from the supplied . + /// + public virtual object Instantiate( + RootObjectDefinition definition, string name, IObjectFactory factory, + MethodInfo factoryMethod, object[] arguments) + { + object instance = null; + object target = null; + if (StringUtils.HasText(definition.FactoryObjectName)) + { + target = factory[definition.FactoryObjectName]; + } + + try + { + // the target will be null if using a static factory method + instance = factoryMethod.Invoke(target, arguments); + } + catch (TargetInvocationException ex) + { + string msg = string.Format( + CultureInfo.InvariantCulture, + "Factory method '{0}' threw an Exception.", factoryMethod); + + #region Instrumentation + + if (log.IsEnabled(LogLevel.Warning)) + { + log.LogWarning(ex.InnerException, msg); + } + + #endregion + + throw new ObjectDefinitionStoreException(msg, ex.InnerException); + } + catch (Exception ex) + { + throw new ObjectDefinitionStoreException(string.Format( + CultureInfo.InvariantCulture, + "Factory method '{0}' threw an Exception.", factoryMethod), ex); + } + + return instance; + } + + /// + /// Instantiate an instance of the object described by the supplied + /// from the supplied , + /// injecting methods as appropriate. /// /// ///

- /// Does not support method injection, although it provides hooks for subclasses - /// to override to add method injection support, for example by overriding methods. + /// The default implementation of this method is to throw a + /// . + ///

+ ///

+ /// Derived classes can override this method if they can instantiate an object + /// with the Method Injection specified in the supplied + /// . Instantiation should use a no-arg constructor. ///

///
- /// Rod Johnson - /// Rick Evans (.NET) - /// - [Serializable] - public class SimpleInstantiationStrategy : IInstantiationStrategy + /// + /// The definition of the object that is to be instantiated. + /// + /// + /// The name associated with the object definition. The name can be a + /// or zero length string if we're autowiring an object that + /// doesn't belong to the supplied . + /// + /// + /// The owning + /// + /// + /// An instance of the object described by the supplied + /// from the supplied . + /// + protected virtual object InstantiateWithMethodInjection( + RootObjectDefinition definition, string objectName, IObjectFactory factory) { - /// - /// The shared instance for this class (and derived classes). - /// - protected static readonly ILogger log = LogManager.GetLogger(); + throw new InvalidOperationException("Method Injection not supported in SimpleInstantiationStrategy"); + } - /// - /// Instantiate an instance of the object described by the supplied - /// from the supplied . - /// - /// - /// The definition of the object that is to be instantiated. - /// - /// - /// The name associated with the object definition. The name can be the null - /// or zero length string if we're autowiring an object that doesn't belong - /// to the supplied . - /// - /// - /// The owning - /// - /// - /// An instance of the object described by the supplied - /// from the supplied . - /// - public virtual object Instantiate( - RootObjectDefinition definition, string name, IObjectFactory factory) - { - AssertUtils.ArgumentNotNull(definition, "definition"); - AssertUtils.ArgumentNotNull(factory, "factory"); - - if (log.IsEnabled(LogLevel.Trace)) log.LogTrace(string.Format("instantiating object '{0}'", name)); - - if (definition.HasMethodOverrides) - { - return InstantiateWithMethodInjection(definition, name, factory); - } - else - { - Type objectType = definition.HasObjectType - ? definition.ObjectType - : TypeResolutionUtils.ResolveType(definition.ObjectTypeName); - ConstructorInfo constructor = GetZeroArgConstructorInfo(objectType); - return ObjectUtils.InstantiateType(constructor, ObjectUtils.EmptyObjects); - } - } - - /// - /// Gets the zero arg ConstructorInfo object, if the type offers such functionality. - /// - /// The type. - /// Zero argument ConstructorInfo - /// - /// If the type does not have a zero-arg constructor. - /// - private ConstructorInfo GetZeroArgConstructorInfo(Type type) - { - const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | - BindingFlags.Instance | BindingFlags.DeclaredOnly; - - ConstructorInfo constructor = type.GetConstructor(flags, null, Type.EmptyTypes, null); - if (constructor == null) - { - throw new FatalReflectionException(string.Format( - CultureInfo.InvariantCulture, "Cannot instantiate a class that does not have a no-argument constructor [{0}].", type)); - } - return constructor; - } - - /// - /// Instantiate an instance of the object described by the supplied - /// from the supplied . - /// - /// - /// The definition of the object that is to be instantiated. - /// - /// - /// The name associated with the object definition. The name can be the null - /// or zero length string if we're autowiring an object that doesn't belong - /// to the supplied . - /// - /// - /// The owning - /// - /// - /// The to be used to instantiate - /// the object. - /// - /// - /// Any arguments to the supplied . May be null. - /// - /// - /// An instance of the object described by the supplied - /// from the supplied . - /// - public virtual object Instantiate( - RootObjectDefinition definition, string name, IObjectFactory factory, - ConstructorInfo constructor, object[] arguments) - { - if (definition.HasMethodOverrides) - { - return InstantiateWithMethodInjection(definition, name, factory, constructor, arguments); - } - else - { - return ObjectUtils.InstantiateType(constructor, arguments); - } - } - - /// - /// Instantiate an instance of the object described by the supplied - /// from the supplied . - /// - /// - /// The definition of the object that is to be instantiated. - /// - /// - /// The name associated with the object definition. The name can be the null - /// or zero length string if we're autowiring an object that doesn't belong - /// to the supplied . - /// - /// - /// The owning - /// - /// - /// The to be used to get the object. - /// - /// - /// Any arguments to the supplied . May be null. - /// - /// - /// An instance of the object described by the supplied - /// from the supplied . - /// - public virtual object Instantiate( - RootObjectDefinition definition, string name, IObjectFactory factory, - MethodInfo factoryMethod, object[] arguments) - { - object instance = null; - object target = null; - if (StringUtils.HasText(definition.FactoryObjectName)) - { - target = factory[definition.FactoryObjectName]; - } - try - { - // the target will be null if using a static factory method - instance = factoryMethod.Invoke(target, arguments); - } - catch (TargetInvocationException ex) - { - string msg = string.Format( - CultureInfo.InvariantCulture, - "Factory method '{0}' threw an Exception.", factoryMethod); - - #region Instrumentation - - if (log.IsEnabled(LogLevel.Warning)) - { - log.LogWarning(ex.InnerException, msg); - } - - #endregion - - throw new ObjectDefinitionStoreException(msg, ex.InnerException); - } - catch (Exception ex) - { - throw new ObjectDefinitionStoreException(string.Format( - CultureInfo.InvariantCulture, - "Factory method '{0}' threw an Exception.", factoryMethod), ex); - } - return instance; - } - - /// - /// Instantiate an instance of the object described by the supplied - /// from the supplied , - /// injecting methods as appropriate. - /// - /// - ///

- /// The default implementation of this method is to throw a - /// . - ///

- ///

- /// Derived classes can override this method if they can instantiate an object - /// with the Method Injection specified in the supplied - /// . Instantiation should use a no-arg constructor. - ///

- ///
- /// - /// The definition of the object that is to be instantiated. - /// - /// - /// The name associated with the object definition. The name can be a - /// or zero length string if we're autowiring an object that - /// doesn't belong to the supplied . - /// - /// - /// The owning - /// - /// - /// An instance of the object described by the supplied - /// from the supplied . - /// - protected virtual object InstantiateWithMethodInjection( - RootObjectDefinition definition, string objectName, IObjectFactory factory) - { - throw new InvalidOperationException("Method Injection not supported in SimpleInstantiationStrategy"); - } - - /// - /// Instantiate an instance of the object described by the supplied - /// from the supplied , - /// injecting methods as appropriate. - /// - /// - ///

- /// The default implementation of this method is to throw a - /// . - ///

- ///

- /// Derived classes can override this method if they can instantiate an object - /// with the Method Injection specified in the supplied - /// . Instantiation should use the supplied - /// and attendant . - ///

- ///
- /// - /// The definition of the object that is to be instantiated. - /// - /// - /// The name associated with the object definition. The name can be the null - /// or zero length string if we're autowiring an object that doesn't belong - /// to the supplied . - /// - /// - /// The owning - /// - /// - /// The to be used to instantiate - /// the object. - /// - /// - /// Any arguments to the supplied . May be null. - /// - /// - /// An instance of the object described by the supplied - /// from the supplied . - /// - protected virtual object InstantiateWithMethodInjection( - RootObjectDefinition definition, string objectName, IObjectFactory factory, - ConstructorInfo constructor, object[] arguments) - { - throw new InvalidOperationException("Method Injection not supported in SimpleInstantiationStrategy"); - } + /// + /// Instantiate an instance of the object described by the supplied + /// from the supplied , + /// injecting methods as appropriate. + /// + /// + ///

+ /// The default implementation of this method is to throw a + /// . + ///

+ ///

+ /// Derived classes can override this method if they can instantiate an object + /// with the Method Injection specified in the supplied + /// . Instantiation should use the supplied + /// and attendant . + ///

+ ///
+ /// + /// The definition of the object that is to be instantiated. + /// + /// + /// The name associated with the object definition. The name can be the null + /// or zero length string if we're autowiring an object that doesn't belong + /// to the supplied . + /// + /// + /// The owning + /// + /// + /// The to be used to instantiate + /// the object. + /// + /// + /// Any arguments to the supplied . May be null. + /// + /// + /// An instance of the object described by the supplied + /// from the supplied . + /// + protected virtual object InstantiateWithMethodInjection( + RootObjectDefinition definition, string objectName, IObjectFactory factory, + ConstructorInfo constructor, object[] arguments) + { + throw new InvalidOperationException("Method Injection not supported in SimpleInstantiationStrategy"); } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/StaticListableObjectFactory.cs b/src/Spring/Spring.Core/Objects/Factory/Support/StaticListableObjectFactory.cs index d2363b83..74d93096 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/StaticListableObjectFactory.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/StaticListableObjectFactory.cs @@ -18,1009 +18,1014 @@ using System.Collections; using Spring.Objects.Factory.Config; using Spring.Util; -namespace Spring.Objects.Factory.Support +namespace Spring.Objects.Factory.Support; + +/// +/// Static factory that permits the registration of existing singleton instances. +/// +/// +///

+/// Does not have support for prototype objects, aliases, and post startup object +/// configuration. +///

+///

+/// Serves as a simple example implementation of the +/// interface, that manages existing object instances as opposed to creating new ones +/// based on object definitions. +///

+///

+/// The +/// method is not supported by this class; this class deals exclusively with +/// existing singleton instances, thus the methods mentioned previously make little sense in this context. +///

+///
+/// Rod Johnson +/// Juergen Hoeller +/// Simon White (.NET) +[Serializable] +public class StaticListableObjectFactory : IListableObjectFactory { /// - /// Static factory that permits the registration of existing singleton instances. + /// Map from object name to object instance. + /// + private Dictionary objects = new Dictionary(); + + /// + /// Determine whether this object factory treats object names case-sensitive or not. + /// + public bool IsCaseSensitive => true; + + /// + /// Return the number of objects defined in the factory. + /// + /// + /// The number of objects defined in the factory. + /// + public int ObjectDefinitionCount => objects.Count; + + /// + /// Return an instance of the given object name. + /// + /// The name of the object to return. + /// The instance of the object. + /// + public object this[string name] => GetObject(name); + + /// + /// Determines whether the object with the given name matches the specified type. + /// + /// More specifically, check whether a GetObject call for the given name + /// would return an object that is assignable to the specified target type. + /// Translates aliases back to the corresponding canonical bean name. + /// Will ask the parent factory if the bean cannot be found in this factory instance. + /// + /// The name of the object to query. + /// Type of the target to match against. + /// + /// true if the object type matches; otherwise, false + /// if it doesn't match or cannot be determined yet. + /// + /// Ff there is no object with the given name + /// + public bool IsTypeMatch(string name) + { + return IsTypeMatch(name, typeof(T)); + } + + /// + /// This method is not supported by . + /// + /// + public object CreateObject(string name, Type requiredType, object[] arguments) + { + throw new NotSupportedException("StaticListableObjectFactory does not support this method."); + } + + /// + /// Return an unconfigured(!) instance (possibly shared or independent) of the given object name. + /// + /// The name of the object to return. + /// + /// The the object may match. Can be an interface or + /// superclass of the actual class. For example, if the value is the + /// class, this method will succeed whatever the + /// class of the returned instance. + /// + /// + /// The arguments to use if creating a prototype using explicit arguments to + /// a factory method. If there is no factory method and the + /// supplied array is not , then + /// match the argument values by type and call the object's constructor. + /// + /// The unconfigured(!) instance of the object. + /// + /// If there's no such object definition. + /// + /// + /// If the object could not be created. + /// + /// + /// If the object is not of the required type. + /// + /// + /// If the supplied is . + /// + /// + /// + /// This method will only instantiate the requested object. It does NOT inject any dependencies! + /// + public T CreateObject(string name, object[] arguments) + { + return (T) CreateObject(name, typeof(T), arguments); + } + + /// + /// Return an instance of the given object name. + /// + /// The name of the object to return. + /// The instance of the object. + /// + /// is not currently supported. + /// + /// + public object GetObject(string name) + { + object instance = objects[name]; + if (instance is IFactoryObject) + { + if (instance is IConfigurableFactoryObject) + { + throw new NotSupportedException(); + } + + try + { + return ((IFactoryObject) instance).GetObject(); + } + catch (Exception ex) + { + throw new ObjectCreationException(name, + "IFactoryObject threw an exception on object creation", ex); + } + } + + if (instance == null) + { + throw new NoSuchObjectDefinitionException(name, GrabDefinedObjectsString()); + } + + return instance; + } + + /// + /// Return an instance (possibly shared or independent) of the given object name. + /// + /// + /// + /// This method allows an object factory to be used as a replacement for the + /// Singleton or Prototype design pattern. + /// + /// + /// Note that callers should retain references to returned objects. There is no + /// guarantee that this method will be implemented to be efficient. For example, + /// it may be synchronized, or may need to run an RDBMS query. + /// + /// + /// Will ask the parent factory if the object cannot be found in this factory + /// instance. + /// + /// + /// The type of the object to return. + /// The name of the object to return. + /// The instance of the object. + /// + /// If there's no such object definition. + /// + /// + /// If the object is not of the required type. + /// + /// + /// If the object could not be created. + /// + public T GetObject(string name) + { + return (T) GetObject(name, typeof(T)); + } + + /// + /// Return an instance (possibly shared or independent) of the given object name. /// /// ///

- /// Does not have support for prototype objects, aliases, and post startup object - /// configuration. + /// This method allows an object factory to be used as a replacement for the + /// Singleton or Prototype design pattern. ///

///

- /// Serves as a simple example implementation of the - /// interface, that manages existing object instances as opposed to creating new ones - /// based on object definitions. + /// Note that callers should retain references to returned objects. There is no + /// guarantee that this method will be implemented to be efficient. For example, + /// it may be synchronized, or may need to run an RDBMS query. ///

///

- /// The - /// method is not supported by this class; this class deals exclusively with - /// existing singleton instances, thus the methods mentioned previously make little sense in this context. + /// Will ask the parent factory if the object cannot be found in this factory + /// instance. ///

///
- /// Rod Johnson - /// Juergen Hoeller - /// Simon White (.NET) - [Serializable] - public class StaticListableObjectFactory : IListableObjectFactory + /// The name of the object to return. + /// + /// The arguments to use if creating a prototype using explicit arguments to + /// a static factory method. If there is no factory method and the + /// arguments are not null, then match the argument values by type and + /// call the object's constructor. + /// + /// The instance of the object. + /// + /// If there's no such object definition. + /// + /// + /// If the object could not be created. + /// + /// + /// If the supplied is . + /// + public object GetObject(string name, object[] arguments) { - /// - /// Map from object name to object instance. - /// - private Dictionary objects = new Dictionary(); + throw new NotSupportedException("StaticListableObjectFactory does not support this method."); + } - /// - /// Determine whether this object factory treats object names case-sensitive or not. - /// - public bool IsCaseSensitive => true; + /// + /// Return an instance (possibly shared or independent) of the given object name. + /// + /// + /// + /// This method allows an object factory to be used as a replacement for the + /// Singleton or Prototype design pattern. + /// + /// + /// Note that callers should retain references to returned objects. There is no + /// guarantee that this method will be implemented to be efficient. For example, + /// it may be synchronized, or may need to run an RDBMS query. + /// + /// + /// Will ask the parent factory if the object cannot be found in this factory + /// instance. + /// + /// + /// The name of the object to return. + /// + /// The arguments to use if creating a prototype using explicit arguments to + /// a static factory method. If there is no factory method and the + /// arguments are not null, then match the argument values by type and + /// call the object's constructor. + /// + /// The instance of the object. + /// + /// If there's no such object definition. + /// + /// + /// If the object could not be created. + /// + /// + /// If the object is not of the required type. + /// + /// + /// If the supplied is . + /// + public T GetObject(string name, object[] arguments) + { + return (T) GetObject(name, typeof(T), arguments); + } - /// - /// Return the number of objects defined in the factory. - /// - /// - /// The number of objects defined in the factory. - /// - public int ObjectDefinitionCount => objects.Count; + /// + /// Return an instance (possibly shared or independent) of the given object name. + /// + /// The name of the object to return. + /// + /// The the object may match. Can be an interface or + /// superclass of the actual class. For example, if the value is the + /// class, this method will succeed whatever the + /// class of the returned instance. + /// + /// + /// The arguments to use if creating a prototype using explicit arguments to + /// a factory method. If there is no factory method and the + /// supplied array is not , then + /// match the argument values by type and call the object's constructor. + /// + /// The instance of the object. + /// + /// If there's no such object definition. + /// + /// + /// If the object could not be created. + /// + /// + /// If the object is not of the required type. + /// + /// + /// If the supplied is . + /// + /// + public object GetObject(string name, Type requiredType, object[] arguments) + { + throw new NotSupportedException("StaticListableObjectFactory does not support this method."); + } - /// - /// Return an instance of the given object name. - /// - /// The name of the object to return. - /// The instance of the object. - /// - public object this[string name] => GetObject(name); - - /// - /// Determines whether the object with the given name matches the specified type. - /// - /// More specifically, check whether a GetObject call for the given name - /// would return an object that is assignable to the specified target type. - /// Translates aliases back to the corresponding canonical bean name. - /// Will ask the parent factory if the bean cannot be found in this factory instance. - /// - /// The name of the object to query. - /// Type of the target to match against. - /// - /// true if the object type matches; otherwise, false - /// if it doesn't match or cannot be determined yet. - /// - /// Ff there is no object with the given name - /// - public bool IsTypeMatch(string name) + /// + /// Return an instance of the given object name. + /// + /// The name of the object to return. + /// + /// the object may match. Can be an interface or + /// superclass of the actual class. For example, if the value is the + /// class, this method will succeed whatever the + /// class of the returned instance. + /// + /// The instance of the object. + /// + public object GetObject(string name, Type requiredType) + { + object instance = GetObject(name); + if (!requiredType.IsAssignableFrom(instance.GetType())) { - return IsTypeMatch(name, typeof(T)); + throw new ObjectNotOfRequiredTypeException(name, requiredType, instance); } - /// - /// This method is not supported by . - /// - /// - public object CreateObject(string name, Type requiredType, object[] arguments) + return instance; + } + + /// + /// Does this object factory contain an object with the given name? + /// + /// The name of the object to query. + /// True if an object with the given name is defined. + public bool ContainsObject(string name) + { + return objects.ContainsKey(name); + } + + /// + /// Is this object a singleton? + /// + /// + ///

+ /// That is, will + /// or + /// always return the same object? + ///

+ ///
+ /// The name of the object to query. + /// True if the named object is a singleton. + /// + /// If there's no such object definition. + /// + public bool IsSingleton(string name) + { + bool isSingleton = true; + object instance = GetObject(name); + // in case of IFactoryObject, return singleton status of created object + if (instance is IFactoryObject) { - throw new NotSupportedException("StaticListableObjectFactory does not support this method."); + isSingleton = ((IFactoryObject) instance).IsSingleton; } - /// - /// Return an unconfigured(!) instance (possibly shared or independent) of the given object name. - /// - /// The name of the object to return. - /// - /// The the object may match. Can be an interface or - /// superclass of the actual class. For example, if the value is the - /// class, this method will succeed whatever the - /// class of the returned instance. - /// - /// - /// The arguments to use if creating a prototype using explicit arguments to - /// a factory method. If there is no factory method and the - /// supplied array is not , then - /// match the argument values by type and call the object's constructor. - /// - /// The unconfigured(!) instance of the object. - /// - /// If there's no such object definition. - /// - /// - /// If the object could not be created. - /// - /// - /// If the object is not of the required type. - /// - /// - /// If the supplied is . - /// - /// - /// - /// This method will only instantiate the requested object. It does NOT inject any dependencies! - /// - public T CreateObject(string name, object[] arguments) + return isSingleton; + } + + /// + /// Determines whether the specified object name is prototype. That is, will GetObject + /// always return independent instances? + /// + /// This method returning false does not clearly indicate a singleton object. + /// It indicated non-independent instances, which may correspond to a scoped object as + /// well. use the IsSingleton property to explicitly check for a shared + /// singleton instance. + /// Translates aliases back to the corresponding canonical object name. Will ask the + /// parent factory if the object can not be found in this factory instance. + /// + /// + /// + /// The name of the object to query + /// + /// true if the specified object name will always deliver independent instances; otherwise, false. + /// + /// if there is no object with the given name. + public bool IsPrototype(string name) + { + bool isPrototype = true; + object instance = GetObject(name); + if (instance is IFactoryObject) { - return (T)CreateObject(name, typeof(T), arguments); + isPrototype = !((IFactoryObject) instance).IsSingleton; } - /// - /// Return an instance of the given object name. - /// - /// The name of the object to return. - /// The instance of the object. - /// - /// is not currently supported. - /// - /// - public object GetObject(string name) + return isPrototype; + } + + /// + /// Determine the type of the object with the given name. + /// + /// + ///

+ /// More specifically, checks the type of object that + /// would return. + /// For an , returns the type + /// of object that the creates. + ///

+ ///
+ /// The name of the object to query. + /// + /// The of the object or if + /// not determinable. + /// + public Type GetType(string name) + { + string objectName = ObjectFactoryUtils.TransformedObjectName(name); + object instance = objects[objectName]; + if (instance == null) + { + throw new NoSuchObjectDefinitionException(name, GrabDefinedObjectsString()); + } + + if (instance is IFactoryObject && !ObjectFactoryUtils.IsFactoryDereference(name)) + { + return ((IFactoryObject) instance).ObjectType; + } + + return instance.GetType(); + } + + /// + /// Determines whether the object with the given name matches the specified type. + /// + /// The name of the object to query. + /// Type of the target to match against. + /// + /// true if the object type matches; otherwise, false + /// if it doesn't match or cannot be determined yet. + /// + /// Ff there is no object with the given name + /// + public bool IsTypeMatch(string name, Type targetType) + { + Type type = GetType(name); + return (targetType == null || (type != null && targetType.IsAssignableFrom(type))); + } + + private string GrabDefinedObjectsString() + { + return "Defined objects are [" + + StringUtils.CollectionToDelimitedString(objects.Keys, ",") + "]"; + } + + /// + /// Return the aliases for the given object name, if defined. + /// + /// The object name to check for aliases. + /// The aliases, or an empty array if none. + /// + /// If there's no such object definition. + /// + public IReadOnlyList GetAliases(string name) + { + return StringUtils.EmptyStrings; + } + + /// + /// Not supported. + /// + /// The name of the object. + /// + /// The registered + /// . + /// + /// + /// Always, as object definitions are not supported by this + /// implementation. + /// + public IObjectDefinition GetObjectDefinition(string name) + { + throw new NotSupportedException("StaticListableObjectFactory does not contain object definitions."); + } + + /// + /// Return the registered + /// for the + /// given object, allowing access to its property values and constructor + /// argument values. + /// + /// The name of the object. + /// Whether to search parent object factories. + /// + /// The registered + /// . + /// + /// + /// If there is no object with the given name. + /// + /// + /// In the case of errors. + /// + public IObjectDefinition GetObjectDefinition(string name, bool includeAncestors) + { + throw new NotSupportedException("StaticListableObjectFactory does not contain object definitions."); + } + + /// + /// Return the names of all objects defined in this factory. + /// + /// + /// The names of all objects defined in this factory, or an empty array if none + /// are defined. + /// + public IReadOnlyList GetObjectDefinitionNames() + { + List names = new List(objects.Keys); + return names; + } + + /// + /// Return the names of all objects defined in this factory, if includeAncestors is true + /// includes all parent factories. + /// + /// to include parent factories in result + /// + /// The names of all objects defined in this factory, if includeAncestors is true includes all + /// objects defined in parent factories, or an empty array if none are defined. + /// + public IReadOnlyList GetObjectDefinitionNames(bool includeAncestors) + { + throw new NotSupportedException("StaticListableObjectFactory does not contain object definitions."); + } + + /// + /// Return the names of objects matching the given + /// (including subclasses), judging from the object definitions. + /// + /// + /// The (class or interface) to match, or + /// for all object names. + /// + /// + ///

+ /// Will not consider s, + /// as the type of their created objects is not known before instantiation. + ///

+ ///
+ /// + /// The names of all objects defined in this factory, or an empty array if none + /// are defined. + /// + public IList GetObjectDefinitionNames(Type type) + { + List matches = new List(); + foreach (string name in objects.Keys) + { + Type t = objects[name].GetType(); + if (type.IsAssignableFrom(t)) + { + matches.Add(name); + } + } + + return matches; + } + + /// + /// Return the names of objects matching the given + /// (including subclasses), judging from the object definitions. + /// + /// + /// The (class or interface) to match, or + /// for all object names. + /// + /// + ///

+ /// Does consider objects created by s, + /// or rather it considers the type of objects created by + /// (which means that + /// s will be instantiated). + ///

+ ///

+ /// Does not consider any hierarchy this factory may participate in. + ///

+ ///
+ /// + /// The names of all objects defined in this factory, or an empty array if none + /// are defined. + /// + public IReadOnlyList GetObjectNamesForType(Type type) + { + return GetObjectNamesForType(type, true, true); + } + + /// + /// Return the names of objects matching the given + /// (including subclasses), judging from the object definitions. + /// + /// + ///

+ /// Does consider objects created by s, + /// or rather it considers the type of objects created by + /// (which means that + /// s will be instantiated). + ///

+ ///

+ /// Does not consider any hierarchy this factory may participate in. + ///

+ ///
+ /// + /// The (class or interface) to match, or + /// for all object names. + /// + /// + /// The names of all objects defined in this factory, or an empty array if none + /// are defined. + /// + public IReadOnlyList GetObjectNames() + { + return GetObjectNamesForType(typeof(T)); + } + + /// + /// Return the names of objects matching the given + /// (including subclasses), judging from the object definitions. + /// + /// + ///

+ /// Since this implementation of the + /// + /// interface does not support the notion of ptototype objects, the + /// parameter is ignored. + ///

+ ///
+ /// + /// The (class or interface) to match, or + /// for all object names. + /// + /// + /// Whether to include prototype objects too or just singletons (also applies to + /// s). Ignored. + /// + /// + /// Whether to include s too + /// or just normal objects. + /// + /// + /// The names of all objects defined in this factory, or an empty array if none + /// are defined. + /// + /// + public IReadOnlyList GetObjectNamesForType(Type type, bool includePrototypes, bool includeFactoryObjects) + { + bool isFactoryType = (type != null && typeof(IFactoryObject).IsAssignableFrom(type)); + List matches = new List(); + foreach (string name in objects.Keys) { object instance = objects[name]; - if (instance is IFactoryObject) + if (instance is IFactoryObject && !isFactoryType) { - if (instance is IConfigurableFactoryObject) + if (includeFactoryObjects) { - throw new NotSupportedException(); - } - try - { - return ((IFactoryObject)instance).GetObject(); - } - catch (Exception ex) - { - throw new ObjectCreationException(name, - "IFactoryObject threw an exception on object creation", ex); - } - } - if (instance == null) - { - throw new NoSuchObjectDefinitionException(name, GrabDefinedObjectsString()); - } - return instance; - } - - /// - /// Return an instance (possibly shared or independent) of the given object name. - /// - /// - /// - /// This method allows an object factory to be used as a replacement for the - /// Singleton or Prototype design pattern. - /// - /// - /// Note that callers should retain references to returned objects. There is no - /// guarantee that this method will be implemented to be efficient. For example, - /// it may be synchronized, or may need to run an RDBMS query. - /// - /// - /// Will ask the parent factory if the object cannot be found in this factory - /// instance. - /// - /// - /// The type of the object to return. - /// The name of the object to return. - /// The instance of the object. - /// - /// If there's no such object definition. - /// - /// - /// If the object is not of the required type. - /// - /// - /// If the object could not be created. - /// - public T GetObject(string name) - { - return (T)GetObject(name, typeof(T)); - } - - /// - /// Return an instance (possibly shared or independent) of the given object name. - /// - /// - ///

- /// This method allows an object factory to be used as a replacement for the - /// Singleton or Prototype design pattern. - ///

- ///

- /// Note that callers should retain references to returned objects. There is no - /// guarantee that this method will be implemented to be efficient. For example, - /// it may be synchronized, or may need to run an RDBMS query. - ///

- ///

- /// Will ask the parent factory if the object cannot be found in this factory - /// instance. - ///

- ///
- /// The name of the object to return. - /// - /// The arguments to use if creating a prototype using explicit arguments to - /// a static factory method. If there is no factory method and the - /// arguments are not null, then match the argument values by type and - /// call the object's constructor. - /// - /// The instance of the object. - /// - /// If there's no such object definition. - /// - /// - /// If the object could not be created. - /// - /// - /// If the supplied is . - /// - public object GetObject(string name, object[] arguments) - { - throw new NotSupportedException("StaticListableObjectFactory does not support this method."); - } - - /// - /// Return an instance (possibly shared or independent) of the given object name. - /// - /// - /// - /// This method allows an object factory to be used as a replacement for the - /// Singleton or Prototype design pattern. - /// - /// - /// Note that callers should retain references to returned objects. There is no - /// guarantee that this method will be implemented to be efficient. For example, - /// it may be synchronized, or may need to run an RDBMS query. - /// - /// - /// Will ask the parent factory if the object cannot be found in this factory - /// instance. - /// - /// - /// The name of the object to return. - /// - /// The arguments to use if creating a prototype using explicit arguments to - /// a static factory method. If there is no factory method and the - /// arguments are not null, then match the argument values by type and - /// call the object's constructor. - /// - /// The instance of the object. - /// - /// If there's no such object definition. - /// - /// - /// If the object could not be created. - /// - /// - /// If the object is not of the required type. - /// - /// - /// If the supplied is . - /// - public T GetObject(string name, object[] arguments) - { - return (T)GetObject(name, typeof(T), arguments); - } - - /// - /// Return an instance (possibly shared or independent) of the given object name. - /// - /// The name of the object to return. - /// - /// The the object may match. Can be an interface or - /// superclass of the actual class. For example, if the value is the - /// class, this method will succeed whatever the - /// class of the returned instance. - /// - /// - /// The arguments to use if creating a prototype using explicit arguments to - /// a factory method. If there is no factory method and the - /// supplied array is not , then - /// match the argument values by type and call the object's constructor. - /// - /// The instance of the object. - /// - /// If there's no such object definition. - /// - /// - /// If the object could not be created. - /// - /// - /// If the object is not of the required type. - /// - /// - /// If the supplied is . - /// - /// - public object GetObject(string name, Type requiredType, object[] arguments) - { - throw new NotSupportedException("StaticListableObjectFactory does not support this method."); - } - - /// - /// Return an instance of the given object name. - /// - /// The name of the object to return. - /// - /// the object may match. Can be an interface or - /// superclass of the actual class. For example, if the value is the - /// class, this method will succeed whatever the - /// class of the returned instance. - /// - /// The instance of the object. - /// - public object GetObject(string name, Type requiredType) - { - object instance = GetObject(name); - if (!requiredType.IsAssignableFrom(instance.GetType())) - { - throw new ObjectNotOfRequiredTypeException(name, requiredType, instance); - } - return instance; - } - - /// - /// Does this object factory contain an object with the given name? - /// - /// The name of the object to query. - /// True if an object with the given name is defined. - public bool ContainsObject(string name) - { - return objects.ContainsKey(name); - } - - /// - /// Is this object a singleton? - /// - /// - ///

- /// That is, will - /// or - /// always return the same object? - ///

- ///
- /// The name of the object to query. - /// True if the named object is a singleton. - /// - /// If there's no such object definition. - /// - public bool IsSingleton(string name) - { - bool isSingleton = true; - object instance = GetObject(name); - // in case of IFactoryObject, return singleton status of created object - if (instance is IFactoryObject) - { - isSingleton = ((IFactoryObject)instance).IsSingleton; - } - return isSingleton; - } - - - /// - /// Determines whether the specified object name is prototype. That is, will GetObject - /// always return independent instances? - /// - /// This method returning false does not clearly indicate a singleton object. - /// It indicated non-independent instances, which may correspond to a scoped object as - /// well. use the IsSingleton property to explicitly check for a shared - /// singleton instance. - /// Translates aliases back to the corresponding canonical object name. Will ask the - /// parent factory if the object can not be found in this factory instance. - /// - /// - /// - /// The name of the object to query - /// - /// true if the specified object name will always deliver independent instances; otherwise, false. - /// - /// if there is no object with the given name. - public bool IsPrototype(string name) - { - bool isPrototype = true; - object instance = GetObject(name); - if (instance is IFactoryObject) - { - isPrototype = !((IFactoryObject)instance).IsSingleton; - } - return isPrototype; - - } - - /// - /// Determine the type of the object with the given name. - /// - /// - ///

- /// More specifically, checks the type of object that - /// would return. - /// For an , returns the type - /// of object that the creates. - ///

- ///
- /// The name of the object to query. - /// - /// The of the object or if - /// not determinable. - /// - public Type GetType(string name) - { - string objectName = ObjectFactoryUtils.TransformedObjectName(name); - object instance = objects[objectName]; - if (instance == null) - { - throw new NoSuchObjectDefinitionException(name, GrabDefinedObjectsString()); - } - if (instance is IFactoryObject && !ObjectFactoryUtils.IsFactoryDereference(name)) - { - return ((IFactoryObject)instance).ObjectType; - } - return instance.GetType(); - } - - - /// - /// Determines whether the object with the given name matches the specified type. - /// - /// The name of the object to query. - /// Type of the target to match against. - /// - /// true if the object type matches; otherwise, false - /// if it doesn't match or cannot be determined yet. - /// - /// Ff there is no object with the given name - /// - public bool IsTypeMatch(string name, Type targetType) - { - Type type = GetType(name); - return (targetType == null || (type != null && targetType.IsAssignableFrom(type))); - } - - private string GrabDefinedObjectsString() - { - return "Defined objects are [" + - StringUtils.CollectionToDelimitedString(objects.Keys, ",") + "]"; - } - - /// - /// Return the aliases for the given object name, if defined. - /// - /// The object name to check for aliases. - /// The aliases, or an empty array if none. - /// - /// If there's no such object definition. - /// - public IReadOnlyList GetAliases(string name) - { - return StringUtils.EmptyStrings; - } - - /// - /// Not supported. - /// - /// The name of the object. - /// - /// The registered - /// . - /// - /// - /// Always, as object definitions are not supported by this - /// implementation. - /// - public IObjectDefinition GetObjectDefinition(string name) - { - throw new NotSupportedException("StaticListableObjectFactory does not contain object definitions."); - } - - /// - /// Return the registered - /// for the - /// given object, allowing access to its property values and constructor - /// argument values. - /// - /// The name of the object. - /// Whether to search parent object factories. - /// - /// The registered - /// . - /// - /// - /// If there is no object with the given name. - /// - /// - /// In the case of errors. - /// - public IObjectDefinition GetObjectDefinition(string name, bool includeAncestors) - { - throw new NotSupportedException("StaticListableObjectFactory does not contain object definitions."); - } - - - /// - /// Return the names of all objects defined in this factory. - /// - /// - /// The names of all objects defined in this factory, or an empty array if none - /// are defined. - /// - public IReadOnlyList GetObjectDefinitionNames() - { - List names = new List(objects.Keys); - return names; - } - - /// - /// Return the names of all objects defined in this factory, if includeAncestors is true - /// includes all parent factories. - /// - /// to include parent factories in result - /// - /// The names of all objects defined in this factory, if includeAncestors is true includes all - /// objects defined in parent factories, or an empty array if none are defined. - /// - public IReadOnlyList GetObjectDefinitionNames(bool includeAncestors) - { - throw new NotSupportedException("StaticListableObjectFactory does not contain object definitions."); - } - - /// - /// Return the names of objects matching the given - /// (including subclasses), judging from the object definitions. - /// - /// - /// The (class or interface) to match, or - /// for all object names. - /// - /// - ///

- /// Will not consider s, - /// as the type of their created objects is not known before instantiation. - ///

- ///
- /// - /// The names of all objects defined in this factory, or an empty array if none - /// are defined. - /// - public IList GetObjectDefinitionNames(Type type) - { - List matches = new List(); - foreach (string name in objects.Keys) - { - Type t = objects[name].GetType(); - if (type.IsAssignableFrom(t)) - { - matches.Add(name); - } - } - return matches; - } - - /// - /// Return the names of objects matching the given - /// (including subclasses), judging from the object definitions. - /// - /// - /// The (class or interface) to match, or - /// for all object names. - /// - /// - ///

- /// Does consider objects created by s, - /// or rather it considers the type of objects created by - /// (which means that - /// s will be instantiated). - ///

- ///

- /// Does not consider any hierarchy this factory may participate in. - ///

- ///
- /// - /// The names of all objects defined in this factory, or an empty array if none - /// are defined. - /// - public IReadOnlyList GetObjectNamesForType(Type type) - { - return GetObjectNamesForType(type, true, true); - } - - /// - /// Return the names of objects matching the given - /// (including subclasses), judging from the object definitions. - /// - /// - ///

- /// Does consider objects created by s, - /// or rather it considers the type of objects created by - /// (which means that - /// s will be instantiated). - ///

- ///

- /// Does not consider any hierarchy this factory may participate in. - ///

- ///
- /// - /// The (class or interface) to match, or - /// for all object names. - /// - /// - /// The names of all objects defined in this factory, or an empty array if none - /// are defined. - /// - public IReadOnlyList GetObjectNames() - { - return GetObjectNamesForType(typeof(T)); - } - - /// - /// Return the names of objects matching the given - /// (including subclasses), judging from the object definitions. - /// - /// - ///

- /// Since this implementation of the - /// - /// interface does not support the notion of ptototype objects, the - /// parameter is ignored. - ///

- ///
- /// - /// The (class or interface) to match, or - /// for all object names. - /// - /// - /// Whether to include prototype objects too or just singletons (also applies to - /// s). Ignored. - /// - /// - /// Whether to include s too - /// or just normal objects. - /// - /// - /// The names of all objects defined in this factory, or an empty array if none - /// are defined. - /// - /// - public IReadOnlyList GetObjectNamesForType(Type type, bool includePrototypes, bool includeFactoryObjects) - { - bool isFactoryType = (type != null && typeof(IFactoryObject).IsAssignableFrom(type)); - List matches = new List(); - foreach (string name in objects.Keys) - { - object instance = objects[name]; - if (instance is IFactoryObject && !isFactoryType) - { - if (includeFactoryObjects) - { - Type objectType = ((IFactoryObject)instance).ObjectType; - if (objectType != null && type.IsAssignableFrom(objectType)) - { - matches.Add(name); - } - } - } - else - { - if (type.IsInstanceOfType(instance)) + Type objectType = ((IFactoryObject) instance).ObjectType; + if (objectType != null && type.IsAssignableFrom(objectType)) { matches.Add(name); } } } - return matches; - } - - /// - /// Return the names of objects matching the given - /// (including subclasses), judging from the object definitions. - /// - /// - ///

- /// Does consider objects created by s, - /// or rather it considers the type of objects created by - /// (which means that - /// s will be instantiated). - ///

- ///

- /// Does not consider any hierarchy this factory may participate in. - /// Use - /// to include beans in ancestor factories too. - /// <p>Note: Does <i>not</i> ignore singleton objects that have been registered - /// by other means than bean definitions. - ///

- ///
- /// - /// The (class or interface) to match, or - /// for all object names. - /// - /// - /// Whether to include prototype objects too or just singletons (also applies to - /// s). - /// - /// - /// Whether to include s too - /// or just normal objects. - /// - /// - /// The names of all objects defined in this factory, or an empty array if none - /// are defined. - /// - public IReadOnlyList GetObjectNames(bool includePrototypes, bool includeFactoryObjects) - { - return GetObjectNamesForType(typeof(T), includePrototypes, includeFactoryObjects); - } - - /// - /// Tests whether this object factory contains an object definition for the - /// specified object name. - /// - /// The object name to query. - /// - /// True if an object defintion is contained within this object factory. - /// - public bool ContainsObjectDefinition(string name) - { - return objects.ContainsKey(name); - } - - /// - /// Return the object instances that match the given object - /// (including subclasses), judging from either object - /// definitions or the value of - /// in the case of - /// s. - /// - /// - ///

- /// This version of the - /// method matches all kinds of object definitions, be they singletons, prototypes, or - /// s. Typically, the results - /// of this method call will be the same as a call to - /// IListableObjectFactory.GetObjectsOfType(type,true,true) . - ///

- ///
- /// - /// The (class or interface) to match. - /// - /// - /// A of the matching objects, - /// containing the object names as keys and the corresponding object instances - /// as values. - /// - /// - /// If the objects could not be created. - /// - public IReadOnlyDictionary GetObjectsOfType(Type type) - { - return GetObjectsOfType(type, true, true); - } - - /// - /// Return the object instances that match the given object - /// (including subclasses), judging from either object - /// definitions or the value of - /// in the case of - /// s. - /// - /// - ///

- /// This version of the - /// method matches all kinds of object definitions, be they singletons, prototypes, or - /// s. Typically, the results - /// of this method call will be the same as a call to - /// IListableObjectFactory.GetObjectsOfType(type,true,true) . - ///

- ///
- /// - /// The (class or interface) to match. - /// - /// - /// A of the matching objects, - /// containing the object names as keys and the corresponding object instances - /// as values. - /// - /// - /// If the objects could not be created. - /// - public IReadOnlyDictionary GetObjects() - { - Dictionary collector = new Dictionary(); - DoGetObjectsOfType(typeof(T), true, true, collector); - return collector; - } - - /// - /// Return the object instances that match the given object - /// (including subclasses), judging from either object - /// definitions or the value of - /// in the case of - /// s. - /// - /// - /// The (class or interface) to match. - /// - /// - /// Whether to include prototype objects too or just singletons (also applies to - /// s). - /// - /// - /// Whether to include s too - /// or just normal objects. - /// - /// - /// A of the matching objects, - /// containing the object names as keys and the corresponding object instances - /// as values. - /// - /// - /// If the objects could not be created. - /// - public IReadOnlyDictionary GetObjectsOfType(Type type, bool includePrototypes, bool includeFactoryObjects) - { - Dictionary collector = new Dictionary(); - DoGetObjectsOfType(type, includeFactoryObjects, includePrototypes, collector); - return collector; - } - - private void DoGetObjectsOfType(Type type, bool includeFactoryObjects, bool includePrototypes, IDictionary collector) - { - bool isFactoryType = (type != null && typeof(IFactoryObject).IsAssignableFrom(type)); - foreach (string name in objects.Keys) + else { - object instance = objects[name]; - if (instance is IFactoryObject && includeFactoryObjects) + if (type.IsInstanceOfType(instance)) { - IFactoryObject factory = (IFactoryObject)instance; - Type objectType = factory.ObjectType; - if ((objectType == null && factory.IsSingleton) || - ((factory.IsSingleton || includePrototypes) && - objectType != null && type.IsAssignableFrom(objectType))) - { - object createdObject = GetObject(name); - if (type.IsInstanceOfType(createdObject)) - { - collector[name] = createdObject; - } - } - } - else if (type.IsAssignableFrom(instance.GetType())) - { - if (isFactoryType) - { - collector[ObjectFactoryUtils.BuildFactoryObjectName(name)] = instance; - } - else - { - collector[name] = instance; - } + matches.Add(name); } } } - /// - /// Return the object instances that match the given object - /// (including subclasses), judging from either object - /// definitions or the value of - /// in the case of - /// s. - /// - /// - /// The (class or interface) to match. - /// - /// - /// Whether to include prototype objects too or just singletons (also applies to - /// s). - /// - /// - /// Whether to include s too - /// or just normal objects. - /// - /// - /// A of the matching objects, - /// containing the object names as keys and the corresponding object instances - /// as values. - /// - /// - /// If the objects could not be created. - /// - public IReadOnlyDictionary GetObjects(bool includePrototypes, bool includeFactoryObjects) - { - Dictionary collector = new Dictionary(); - DoGetObjectsOfType(typeof(T), includeFactoryObjects, includePrototypes, collector); - return collector; - } + return matches; + } - /// - /// Return an instance (possibly shared or independent) of the given object name. - /// - /// - /// - /// This method allows an object factory to be used as a replacement for the - /// Singleton or Prototype design pattern. - /// - /// - /// Note that callers should retain references to returned objects. There is no - /// guarantee that this method will be implemented to be efficient. For example, - /// it may be synchronized, or may need to run an RDBMS query. - /// - /// - /// Will ask the parent factory if the object cannot be found in this factory - /// instance. - /// - /// - /// The type of the object to return. - /// The instance of the object. - /// - /// If there's no such object definition. - /// - /// - /// If there is more than a single object of the requested type defined in the factory. - /// - /// - /// If the object could not be created. - /// - public T GetObject() + /// + /// Return the names of objects matching the given + /// (including subclasses), judging from the object definitions. + /// + /// + ///

+ /// Does consider objects created by s, + /// or rather it considers the type of objects created by + /// (which means that + /// s will be instantiated). + ///

+ ///

+ /// Does not consider any hierarchy this factory may participate in. + /// Use + /// to include beans in ancestor factories too. + /// <p>Note: Does <i>not</i> ignore singleton objects that have been registered + /// by other means than bean definitions. + ///

+ ///
+ /// + /// The (class or interface) to match, or + /// for all object names. + /// + /// + /// Whether to include prototype objects too or just singletons (also applies to + /// s). + /// + /// + /// Whether to include s too + /// or just normal objects. + /// + /// + /// The names of all objects defined in this factory, or an empty array if none + /// are defined. + /// + public IReadOnlyList GetObjectNames(bool includePrototypes, bool includeFactoryObjects) + { + return GetObjectNamesForType(typeof(T), includePrototypes, includeFactoryObjects); + } + + /// + /// Tests whether this object factory contains an object definition for the + /// specified object name. + /// + /// The object name to query. + /// + /// True if an object defintion is contained within this object factory. + /// + public bool ContainsObjectDefinition(string name) + { + return objects.ContainsKey(name); + } + + /// + /// Return the object instances that match the given object + /// (including subclasses), judging from either object + /// definitions or the value of + /// in the case of + /// s. + /// + /// + ///

+ /// This version of the + /// method matches all kinds of object definitions, be they singletons, prototypes, or + /// s. Typically, the results + /// of this method call will be the same as a call to + /// IListableObjectFactory.GetObjectsOfType(type,true,true) . + ///

+ ///
+ /// + /// The (class or interface) to match. + /// + /// + /// A of the matching objects, + /// containing the object names as keys and the corresponding object instances + /// as values. + /// + /// + /// If the objects could not be created. + /// + public IReadOnlyDictionary GetObjectsOfType(Type type) + { + return GetObjectsOfType(type, true, true); + } + + /// + /// Return the object instances that match the given object + /// (including subclasses), judging from either object + /// definitions or the value of + /// in the case of + /// s. + /// + /// + ///

+ /// This version of the + /// method matches all kinds of object definitions, be they singletons, prototypes, or + /// s. Typically, the results + /// of this method call will be the same as a call to + /// IListableObjectFactory.GetObjectsOfType(type,true,true) . + ///

+ ///
+ /// + /// The (class or interface) to match. + /// + /// + /// A of the matching objects, + /// containing the object names as keys and the corresponding object instances + /// as values. + /// + /// + /// If the objects could not be created. + /// + public IReadOnlyDictionary GetObjects() + { + Dictionary collector = new Dictionary(); + DoGetObjectsOfType(typeof(T), true, true, collector); + return collector; + } + + /// + /// Return the object instances that match the given object + /// (including subclasses), judging from either object + /// definitions or the value of + /// in the case of + /// s. + /// + /// + /// The (class or interface) to match. + /// + /// + /// Whether to include prototype objects too or just singletons (also applies to + /// s). + /// + /// + /// Whether to include s too + /// or just normal objects. + /// + /// + /// A of the matching objects, + /// containing the object names as keys and the corresponding object instances + /// as values. + /// + /// + /// If the objects could not be created. + /// + public IReadOnlyDictionary GetObjectsOfType(Type type, bool includePrototypes, bool includeFactoryObjects) + { + Dictionary collector = new Dictionary(); + DoGetObjectsOfType(type, includeFactoryObjects, includePrototypes, collector); + return collector; + } + + private void DoGetObjectsOfType(Type type, bool includeFactoryObjects, bool includePrototypes, IDictionary collector) + { + bool isFactoryType = (type != null && typeof(IFactoryObject).IsAssignableFrom(type)); + foreach (string name in objects.Keys) { - var objectNamesForType = GetObjectNamesForType(typeof(T)); - if ((objectNamesForType == null) || (objectNamesForType.Count == 0)) + object instance = objects[name]; + if (instance is IFactoryObject && includeFactoryObjects) { - throw new NoSuchObjectDefinitionException(typeof(T).FullName, "Requested Type not Defined in the Context."); + IFactoryObject factory = (IFactoryObject) instance; + Type objectType = factory.ObjectType; + if ((objectType == null && factory.IsSingleton) || + ((factory.IsSingleton || includePrototypes) && + objectType != null && type.IsAssignableFrom(objectType))) + { + object createdObject = GetObject(name); + if (type.IsInstanceOfType(createdObject)) + { + collector[name] = createdObject; + } + } } - - if (objectNamesForType.Count > 1) + else if (type.IsAssignableFrom(instance.GetType())) { - throw new ObjectDefinitionStoreException(string.Format("More than one definition for {0} found in the Context.", typeof(T).FullName)); + if (isFactoryType) + { + collector[ObjectFactoryUtils.BuildFactoryObjectName(name)] = instance; + } + else + { + collector[name] = instance; + } } - - return (T)GetObject(objectNamesForType[0]); - } - - /// - /// Add a new singleton object. - /// - /// - /// The name to be associated with the object name. - /// - /// The singleton object. - public void AddObject(string name, object instance) - { - objects[name] = instance; - } - - /// - /// Injects dependencies into the supplied instance - /// using the named object definition. - /// - /// - /// The object instance that is to be so configured. - /// - /// - /// The name of the object definition expressing the dependencies that are to - /// be injected into the supplied instance. - /// - /// - /// This feature is not currently supported. - /// - /// - public object ConfigureObject(object target, string name) - { - throw new NotSupportedException(); - } - - /// - /// Injects dependencies into the supplied instance - /// using the supplied . - /// - /// - /// The object instance that is to be so configured. - /// - /// - /// The name of the object definition expressing the dependencies that are to - /// be injected into the supplied instance. - /// - /// - /// An object definition that should be used to configure object. - /// - /// - public object ConfigureObject(object target, string name, IObjectDefinition definition) - { - throw new NotSupportedException(); - } - - /// - /// Defines a method to release allocated unmanaged resources. - /// - public virtual void Dispose() - { } } + + /// + /// Return the object instances that match the given object + /// (including subclasses), judging from either object + /// definitions or the value of + /// in the case of + /// s. + /// + /// + /// The (class or interface) to match. + /// + /// + /// Whether to include prototype objects too or just singletons (also applies to + /// s). + /// + /// + /// Whether to include s too + /// or just normal objects. + /// + /// + /// A of the matching objects, + /// containing the object names as keys and the corresponding object instances + /// as values. + /// + /// + /// If the objects could not be created. + /// + public IReadOnlyDictionary GetObjects(bool includePrototypes, bool includeFactoryObjects) + { + Dictionary collector = new Dictionary(); + DoGetObjectsOfType(typeof(T), includeFactoryObjects, includePrototypes, collector); + return collector; + } + + /// + /// Return an instance (possibly shared or independent) of the given object name. + /// + /// + /// + /// This method allows an object factory to be used as a replacement for the + /// Singleton or Prototype design pattern. + /// + /// + /// Note that callers should retain references to returned objects. There is no + /// guarantee that this method will be implemented to be efficient. For example, + /// it may be synchronized, or may need to run an RDBMS query. + /// + /// + /// Will ask the parent factory if the object cannot be found in this factory + /// instance. + /// + /// + /// The type of the object to return. + /// The instance of the object. + /// + /// If there's no such object definition. + /// + /// + /// If there is more than a single object of the requested type defined in the factory. + /// + /// + /// If the object could not be created. + /// + public T GetObject() + { + var objectNamesForType = GetObjectNamesForType(typeof(T)); + if ((objectNamesForType == null) || (objectNamesForType.Count == 0)) + { + throw new NoSuchObjectDefinitionException(typeof(T).FullName, "Requested Type not Defined in the Context."); + } + + if (objectNamesForType.Count > 1) + { + throw new ObjectDefinitionStoreException(string.Format("More than one definition for {0} found in the Context.", typeof(T).FullName)); + } + + return (T) GetObject(objectNamesForType[0]); + } + + /// + /// Add a new singleton object. + /// + /// + /// The name to be associated with the object name. + /// + /// The singleton object. + public void AddObject(string name, object instance) + { + objects[name] = instance; + } + + /// + /// Injects dependencies into the supplied instance + /// using the named object definition. + /// + /// + /// The object instance that is to be so configured. + /// + /// + /// The name of the object definition expressing the dependencies that are to + /// be injected into the supplied instance. + /// + /// + /// This feature is not currently supported. + /// + /// + public object ConfigureObject(object target, string name) + { + throw new NotSupportedException(); + } + + /// + /// Injects dependencies into the supplied instance + /// using the supplied . + /// + /// + /// The object instance that is to be so configured. + /// + /// + /// The name of the object definition expressing the dependencies that are to + /// be injected into the supplied instance. + /// + /// + /// An object definition that should be used to configure object. + /// + /// + public object ConfigureObject(object target, string name, IObjectDefinition definition) + { + throw new NotSupportedException(); + } + + /// + /// Defines a method to release allocated unmanaged resources. + /// + public virtual void Dispose() + { + } } diff --git a/src/Spring/Spring.Core/Objects/Factory/UnsatisfiedDependencyException.cs b/src/Spring/Spring.Core/Objects/Factory/UnsatisfiedDependencyException.cs index ab3e94d5..6af0a6fc 100644 --- a/src/Spring/Spring.Core/Objects/Factory/UnsatisfiedDependencyException.cs +++ b/src/Spring/Spring.Core/Objects/Factory/UnsatisfiedDependencyException.cs @@ -20,134 +20,133 @@ using System.Runtime.Serialization; -namespace Spring.Objects.Factory +namespace Spring.Objects.Factory; + +/// +/// Exception thrown when an object depends on other objects or simple properties +/// that were not specified in the object factory definition, although dependency +/// checking was enabled. +/// +/// Rod Johnson +/// Juergen Hoeller +/// Rick Evans (.NET) +[Serializable] +public class UnsatisfiedDependencyException : ObjectCreationException { - /// - /// Exception thrown when an object depends on other objects or simple properties - /// that were not specified in the object factory definition, although dependency - /// checking was enabled. - /// - /// Rod Johnson - /// Juergen Hoeller - /// Rick Evans (.NET) - [Serializable] - public class UnsatisfiedDependencyException : ObjectCreationException - { - /// - /// Creates a new instance of the UnsatisfiedDependencyException class. - /// - public UnsatisfiedDependencyException() - { - } + /// + /// Creates a new instance of the UnsatisfiedDependencyException class. + /// + public UnsatisfiedDependencyException() + { + } - /// - /// Creates a new instance of the UnsatisfiedDependencyException class. - /// - /// - /// A message about the exception. - /// - public UnsatisfiedDependencyException(string message) - : base(message) - { - } + /// + /// Creates a new instance of the UnsatisfiedDependencyException class. + /// + /// + /// A message about the exception. + /// + public UnsatisfiedDependencyException(string message) + : base(message) + { + } - /// - /// Creates a new instance of the UnsatisfiedDependencyException class. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception that is being wrapped. - /// - public UnsatisfiedDependencyException(string message, Exception rootCause) - : base(message, rootCause) - { - } + /// + /// Creates a new instance of the UnsatisfiedDependencyException class. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception that is being wrapped. + /// + public UnsatisfiedDependencyException(string message, Exception rootCause) + : base(message, rootCause) + { + } - /// - /// Creates a new instance of the UnsatisfiedDependencyException class. - /// - /// - /// The description of the resource associated with the object. - /// - /// - /// The name of the object that has the unsatisfied dependency. - /// - /// - /// The constructor argument index at which the dependency is - /// unsatisfied. - /// - /// - /// The of the constructor argument at - /// which the dependency is unsatisfied. - /// - /// - /// A message about the exception. - /// - public UnsatisfiedDependencyException( - string resourceDescription, - string name, - int argumentIndex, - Type argumentType, - string message) - : base( - resourceDescription, - name, - string.Format( - "Unsatisfied dependency expressed through constructor argument with index {0} of type [{1}] : {2}", - argumentIndex, - argumentType, - message)) - { - } + /// + /// Creates a new instance of the UnsatisfiedDependencyException class. + /// + /// + /// The description of the resource associated with the object. + /// + /// + /// The name of the object that has the unsatisfied dependency. + /// + /// + /// The constructor argument index at which the dependency is + /// unsatisfied. + /// + /// + /// The of the constructor argument at + /// which the dependency is unsatisfied. + /// + /// + /// A message about the exception. + /// + public UnsatisfiedDependencyException( + string resourceDescription, + string name, + int argumentIndex, + Type argumentType, + string message) + : base( + resourceDescription, + name, + string.Format( + "Unsatisfied dependency expressed through constructor argument with index {0} of type [{1}] : {2}", + argumentIndex, + argumentType, + message)) + { + } - /// - /// Creates a new instance of the UnsatisfiedDependencyException class. - /// - /// - /// The description of the resource associated with the object. - /// - /// - /// The name of the object that has the unsatisfied dependency. - /// - /// - /// The name identifying the property on which the dependency is - /// unsatisfied. - /// - /// - /// A message about the exception. - /// - public UnsatisfiedDependencyException( - string resourceDescription, - string name, - string propertyName, - string message) - : base( - resourceDescription, - name, - string.Format( - "Unsatisfied dependency expressed through object property '{0}': {1}", - propertyName, - message)) - { - } + /// + /// Creates a new instance of the UnsatisfiedDependencyException class. + /// + /// + /// The description of the resource associated with the object. + /// + /// + /// The name of the object that has the unsatisfied dependency. + /// + /// + /// The name identifying the property on which the dependency is + /// unsatisfied. + /// + /// + /// A message about the exception. + /// + public UnsatisfiedDependencyException( + string resourceDescription, + string name, + string propertyName, + string message) + : base( + resourceDescription, + name, + string.Format( + "Unsatisfied dependency expressed through object property '{0}': {1}", + propertyName, + message)) + { + } - /// - /// Creates a new instance of the UnsatisfiedDependencyException class. - /// - /// - /// The - /// that holds the serialized object data about the exception being thrown. - /// - /// - /// The - /// that contains contextual information about the source or destination. - /// - protected UnsatisfiedDependencyException( - SerializationInfo info, StreamingContext context) - : base(info, context) - { - } - } + /// + /// Creates a new instance of the UnsatisfiedDependencyException class. + /// + /// + /// The + /// that holds the serialized object data about the exception being thrown. + /// + /// + /// The + /// that contains contextual information about the source or destination. + /// + protected UnsatisfiedDependencyException( + SerializationInfo info, StreamingContext context) + : base(info, context) + { + } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Xml/AbstractObjectDefinitionParser.cs b/src/Spring/Spring.Core/Objects/Factory/Xml/AbstractObjectDefinitionParser.cs index 4dd5f28f..b4bdc3a2 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Xml/AbstractObjectDefinitionParser.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Xml/AbstractObjectDefinitionParser.cs @@ -23,220 +23,220 @@ using Spring.Objects.Factory.Config; using Spring.Objects.Factory.Support; using Spring.Util; -namespace Spring.Objects.Factory.Xml -{ +namespace Spring.Objects.Factory.Xml; +/// +/// Abstract implementation providing +/// a number of convenience methods and a +/// template method +/// that subclasses must override to provide the actual parsing logic. +/// +/// +/// Use this implementation when you want +/// to parse some arbitrarily complex XML into one or more +/// ObjectDefinitions. If you just want to parse some +/// XML into a single IObjectDefinition, you may wish to consider +/// the simpler convenience extensions of this class, namely +/// and +/// +/// +/// Rob Harrop +/// Juergen Hoeller +/// Rick Evans +/// Mark Pollack (.NET) +public abstract class AbstractObjectDefinitionParser : IObjectDefinitionParser +{ + /// + /// Constant for the ID attribute + /// + public static readonly string ID_ATTRIBUTE = "id"; + + #region Properties /// - /// Abstract implementation providing - /// a number of convenience methods and a - /// template method - /// that subclasses must override to provide the actual parsing logic. + /// Gets a value indicating whether an ID should be generated instead of read + /// from the passed in XmlElement. + /// + /// Note that this flag is about always generating an ID; the parser + /// won't even check for an "id" attribute in this case. + /// + /// true if should generate id; otherwise, false. + protected virtual bool ShouldGenerateId + { + get { return false; } + } + + /// + /// Gets a value indicating whether an ID should be generated instead if the + /// passed in XmlElement does not specify an "id" attribute explicitly. + /// + /// Disabled by default; subclasses can override this to enable ID generation + /// as fallback: The parser will first check for an "id" attribute in this case, + /// only falling back to a generated ID if no value was specified. + /// + /// true if should generate id if no value was specified; otherwise, false. + /// + protected virtual bool ShouldGenerateIdAsFallback + { + get { return false; } + } + + #endregion + + #region IObjectDefinitionParser Members + + /// + /// Parse the specified XmlElement and register the resulting + /// ObjectDefinitions with the IObjectDefinitionRegistry + /// embedded in the supplied + /// + /// The element to be parsed. + /// The object encapsulating the current state of the parsing process. + /// Provides access to a IObjectDefinitionRegistry + /// The primary object definition. + /// + ///

+ /// This method is never invoked if the parser is namespace aware + /// and was called to process the root node. + ///

+ ///
+ public virtual IObjectDefinition ParseElement(XmlElement element, ParserContext parserContext) + { + AbstractObjectDefinition definition = ParseInternal(element, parserContext); + + if (!parserContext.IsNested) + { + string id = null; + try + { + id = ResolveId(element, definition, parserContext); + if (!StringUtils.HasText(id)) + { + parserContext.ReaderContext.ReportException(element, "null", + "Id is required for element '" + element.LocalName + "' when used as a top-level tag", null); + } + + ObjectDefinitionHolder holder = new ObjectDefinitionHolder(definition, id); + RegisterObjectDefinition(holder, parserContext.Registry); + } + catch (ObjectDefinitionStoreException ex) + { + parserContext.ReaderContext.ReportException(element, id, ex.Message); + return null; + } + } + + return definition; + } + + #endregion + + #region Methods + + /// + /// Resolves the ID for the supplied . /// /// - /// Use this implementation when you want - /// to parse some arbitrarily complex XML into one or more - /// ObjectDefinitions. If you just want to parse some - /// XML into a single IObjectDefinition, you may wish to consider - /// the simpler convenience extensions of this class, namely - /// and - /// + /// When using generation, a name is generated automatically. + /// Otherwise, the ID is extracted from the "id" attribute, potentially with a + /// fallback to a generated id. /// - /// Rob Harrop - /// Juergen Hoeller - /// Rick Evans - /// Mark Pollack (.NET) - public abstract class AbstractObjectDefinitionParser : IObjectDefinitionParser + /// The element that the object definition has been built from. + /// The object definition to be registered. + /// The the object encapsulating the current state of the parsing process; + /// provides access to a + /// the resolved id + /// + /// if no unique name could be generated for the given object definition + /// + protected virtual string ResolveId(XmlElement element, AbstractObjectDefinition definition, ParserContext parserContext) { - /// - /// Constant for the ID attribute - /// - public static readonly string ID_ATTRIBUTE = "id"; - - #region Properties - - /// - /// Gets a value indicating whether an ID should be generated instead of read - /// from the passed in XmlElement. - /// - /// Note that this flag is about always generating an ID; the parser - /// won't even check for an "id" attribute in this case. - /// - /// true if should generate id; otherwise, false. - protected virtual bool ShouldGenerateId + if (ShouldGenerateId) { - get { return false; } + return parserContext.ReaderContext.GenerateObjectName(definition); } - - /// - /// Gets a value indicating whether an ID should be generated instead if the - /// passed in XmlElement does not specify an "id" attribute explicitly. - /// - /// Disabled by default; subclasses can override this to enable ID generation - /// as fallback: The parser will first check for an "id" attribute in this case, - /// only falling back to a generated ID if no value was specified. - /// - /// true if should generate id if no value was specified; otherwise, false. - /// - protected virtual bool ShouldGenerateIdAsFallback + else { - get { return false; } - } - - #endregion - - #region IObjectDefinitionParser Members - - - /// - /// Parse the specified XmlElement and register the resulting - /// ObjectDefinitions with the IObjectDefinitionRegistry - /// embedded in the supplied - /// - /// The element to be parsed. - /// The object encapsulating the current state of the parsing process. - /// Provides access to a IObjectDefinitionRegistry - /// The primary object definition. - /// - ///

- /// This method is never invoked if the parser is namespace aware - /// and was called to process the root node. - ///

- ///
- public virtual IObjectDefinition ParseElement(XmlElement element, ParserContext parserContext) - { - AbstractObjectDefinition definition = ParseInternal(element, parserContext); - - if (!parserContext.IsNested) + string id = GetAttributeValue(element, ID_ATTRIBUTE); + if (!StringUtils.HasText(id) && ShouldGenerateIdAsFallback) { - string id = null; - try - { - id = ResolveId(element, definition, parserContext); - if (!StringUtils.HasText(id)) - { - parserContext.ReaderContext.ReportException(element, "null", - "Id is required for element '" + element.LocalName + "' when used as a top-level tag", null); - } - ObjectDefinitionHolder holder = new ObjectDefinitionHolder(definition, id); - RegisterObjectDefinition(holder, parserContext.Registry); - } - catch (ObjectDefinitionStoreException ex) - { - parserContext.ReaderContext.ReportException(element, id, ex.Message); - return null; - } + id = parserContext.ReaderContext.GenerateObjectName(definition); } - return definition; - + return id; } - - #endregion - - #region Methods - - /// - /// Resolves the ID for the supplied . - /// - /// - /// When using generation, a name is generated automatically. - /// Otherwise, the ID is extracted from the "id" attribute, potentially with a - /// fallback to a generated id. - /// - /// The element that the object definition has been built from. - /// The object definition to be registered. - /// The the object encapsulating the current state of the parsing process; - /// provides access to a - /// the resolved id - /// - /// if no unique name could be generated for the given object definition - /// - protected virtual string ResolveId(XmlElement element, AbstractObjectDefinition definition, ParserContext parserContext) - { - - if (ShouldGenerateId) { - return parserContext.ReaderContext.GenerateObjectName(definition); - } - else { - string id = GetAttributeValue(element, ID_ATTRIBUTE); - if (!StringUtils.HasText(id) && ShouldGenerateIdAsFallback) { - id = parserContext.ReaderContext.GenerateObjectName(definition); - } - return id; - } - } - - /// - /// Registers the supplied with the supplied - /// . - /// - /// Subclasses can override this method to control whether or not the supplied - /// is actually even registered, or to - /// register even more objects. - /// - /// The default implementation registers the supplied - /// with the supplied only if the IsNested - /// parameter is false, because one typically does not want inner objects - /// to be registered as top level objects. - /// - /// - /// - /// The object definition to be registered. - /// The registry that the bean is to be registered with. - protected virtual void RegisterObjectDefinition(ObjectDefinitionHolder definition, IObjectDefinitionRegistry registry) - { - ObjectDefinitionReaderUtils.RegisterObjectDefinition(definition, registry); - } - - /// - /// Returns the value of the element's attribute or null, if the attribute is not specified. - /// - /// - /// This is a helper for bypassing the behavior of - /// to return if the attribute does not exist. - /// - protected static string GetAttributeValue(XmlElement element, string attributeName) - { - if (element.HasAttribute(attributeName)) - { - return element.GetAttribute(attributeName); - } - return null; - } - - /// - /// Returns the value of the element's attribute or , - /// if the attribute is not specified. - /// - /// - /// This is a helper for bypassing the behavior of - /// to return if the attribute does not exist. - /// - protected static string GetAttributeValue(XmlElement element, string attributeName, string defaultValue) - { - if (element.HasAttribute(attributeName)) - { - return element.GetAttribute(attributeName); - } - return defaultValue; - } - - #endregion - - - #region Abstract Methods - - /// - /// Central template method to actually parse the supplied XmlElement - /// into one or more IObjectDefinitions. - /// - /// The element that is to be parsed into one or more s - /// The the object encapsulating the current state of the parsing process; - /// provides access to a - /// The primary IObjectDefinition resulting from the parsing of the supplied XmlElement - protected abstract AbstractObjectDefinition ParseInternal(XmlElement element, ParserContext parserContext); - - #endregion } + + /// + /// Registers the supplied with the supplied + /// . + /// + /// Subclasses can override this method to control whether or not the supplied + /// is actually even registered, or to + /// register even more objects. + /// + /// The default implementation registers the supplied + /// with the supplied only if the IsNested + /// parameter is false, because one typically does not want inner objects + /// to be registered as top level objects. + /// + /// + /// + /// The object definition to be registered. + /// The registry that the bean is to be registered with. + protected virtual void RegisterObjectDefinition(ObjectDefinitionHolder definition, IObjectDefinitionRegistry registry) + { + ObjectDefinitionReaderUtils.RegisterObjectDefinition(definition, registry); + } + + /// + /// Returns the value of the element's attribute or null, if the attribute is not specified. + /// + /// + /// This is a helper for bypassing the behavior of + /// to return if the attribute does not exist. + /// + protected static string GetAttributeValue(XmlElement element, string attributeName) + { + if (element.HasAttribute(attributeName)) + { + return element.GetAttribute(attributeName); + } + + return null; + } + + /// + /// Returns the value of the element's attribute or , + /// if the attribute is not specified. + /// + /// + /// This is a helper for bypassing the behavior of + /// to return if the attribute does not exist. + /// + protected static string GetAttributeValue(XmlElement element, string attributeName, string defaultValue) + { + if (element.HasAttribute(attributeName)) + { + return element.GetAttribute(attributeName); + } + + return defaultValue; + } + + #endregion + + #region Abstract Methods + + /// + /// Central template method to actually parse the supplied XmlElement + /// into one or more IObjectDefinitions. + /// + /// The element that is to be parsed into one or more s + /// The the object encapsulating the current state of the parsing process; + /// provides access to a + /// The primary IObjectDefinition resulting from the parsing of the supplied XmlElement + protected abstract AbstractObjectDefinition ParseInternal(XmlElement element, ParserContext parserContext); + + #endregion } diff --git a/src/Spring/Spring.Core/Objects/Factory/Xml/AbstractSimpleObjectDefinitionParser.cs b/src/Spring/Spring.Core/Objects/Factory/Xml/AbstractSimpleObjectDefinitionParser.cs index da19e8ab..52e74ea0 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Xml/AbstractSimpleObjectDefinitionParser.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Xml/AbstractSimpleObjectDefinitionParser.cs @@ -18,19 +18,17 @@ #endregion -namespace Spring.Objects.Factory.Xml +namespace Spring.Objects.Factory.Xml; + +/// +/// Convenient base class for when there exists a one-to-one mapping +/// between attribute names on the element that is to be parsed and +/// the property names on the Type being configured. +/// +/// +/// +/// +/// Mark Pollack +public class AbstractSimpleObjectDefinitionParser : AbstractSingleObjectDefinitionParser { - /// - /// Convenient base class for when there exists a one-to-one mapping - /// between attribute names on the element that is to be parsed and - /// the property names on the Type being configured. - /// - /// - /// - /// - /// Mark Pollack - public class AbstractSimpleObjectDefinitionParser : AbstractSingleObjectDefinitionParser - { - - } -} \ No newline at end of file +} diff --git a/src/Spring/Spring.Core/Objects/Factory/Xml/AbstractSingleObjectDefinitionParser.cs b/src/Spring/Spring.Core/Objects/Factory/Xml/AbstractSingleObjectDefinitionParser.cs index 36caeab3..dc91163c 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Xml/AbstractSingleObjectDefinitionParser.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Xml/AbstractSingleObjectDefinitionParser.cs @@ -21,146 +21,145 @@ using System.Xml; using Spring.Objects.Factory.Support; -namespace Spring.Objects.Factory.Xml +namespace Spring.Objects.Factory.Xml; + +/// +/// Base Type for those implementations that +/// need to parse and define just a single IObjectDefinition. +/// +/// +/// Extend this parser Type when you want to create a single object definition +/// from an arbitrarily complex XML element. You may wish to consider extending +/// the when you want to create a +/// single Object definition from a relatively simple custom XML element. +/// The resulting ObjectDefinition will be automatically registered +/// with the ObjectDefinitionRegistry. Your job simply is to parse the +/// custom XML element into a single ObjectDefinition +/// +/// Rob Harrop +/// Juergen Hoeller +/// Rick Evans +/// Mark Pollack (.NET) +public class AbstractSingleObjectDefinitionParser : AbstractObjectDefinitionParser { + #region Methods + /// - /// Base Type for those implementations that - /// need to parse and define just a single IObjectDefinition. + /// Central template method to actually parse the supplied XmlElement + /// into one or more IObjectDefinitions. /// - /// - /// Extend this parser Type when you want to create a single object definition - /// from an arbitrarily complex XML element. You may wish to consider extending - /// the when you want to create a - /// single Object definition from a relatively simple custom XML element. - /// The resulting ObjectDefinition will be automatically registered - /// with the ObjectDefinitionRegistry. Your job simply is to parse the - /// custom XML element into a single ObjectDefinition - /// - /// Rob Harrop - /// Juergen Hoeller - /// Rick Evans - /// Mark Pollack (.NET) - public class AbstractSingleObjectDefinitionParser : AbstractObjectDefinitionParser + /// The element that is to be parsed into one or more s + /// The the object encapsulating the current state of the parsing process; + /// provides access to a + /// + /// The primary IObjectDefinition resulting from the parsing of the supplied XmlElement + /// + protected override AbstractObjectDefinition ParseInternal(XmlElement element, ParserContext parserContext) { - #region Methods - - /// - /// Central template method to actually parse the supplied XmlElement - /// into one or more IObjectDefinitions. - /// - /// The element that is to be parsed into one or more s - /// The the object encapsulating the current state of the parsing process; - /// provides access to a - /// - /// The primary IObjectDefinition resulting from the parsing of the supplied XmlElement - /// - protected override AbstractObjectDefinition ParseInternal(XmlElement element, ParserContext parserContext) + ObjectDefinitionBuilder builder = ObjectDefinitionBuilder.GenericObjectDefinition(); + string parentName = GetParentName(element); + if (parentName != null) { - ObjectDefinitionBuilder builder = ObjectDefinitionBuilder.GenericObjectDefinition(); - string parentName = GetParentName(element); - if (parentName != null) - { - builder.RawObjectDefinition.ParentName = parentName; - } + builder.RawObjectDefinition.ParentName = parentName; + } - Type objectType = GetObjectType(element); - if (objectType != null) + Type objectType = GetObjectType(element); + if (objectType != null) + { + builder.RawObjectDefinition.ObjectType = objectType; + } + else + { + string objectTypeName = GetObjectTypeName(element); + if (objectTypeName != null) { - builder.RawObjectDefinition.ObjectType = objectType; - } - else - { - string objectTypeName = GetObjectTypeName(element); - if (objectTypeName != null) - { - builder.RawObjectDefinition.ObjectTypeName = objectTypeName; - } + builder.RawObjectDefinition.ObjectTypeName = objectTypeName; } + } - // TODO (EE) + // TODO (EE) // builder.getRawBeanDefinition().setSource(parserContext.extractSource(element)); - if (parserContext.IsNested) - { - // Inner object definition must receive same singleton status as containing object. - builder.SetSingleton(parserContext.ContainingObjectDefinition.IsSingleton); - } - if (parserContext.IsDefaultLazyInit) - { - // Default-lazy-init applies to custom object definitions as well. - builder.SetLazyInit(true); - } - DoParse(element, parserContext, builder); - return builder.ObjectDefinition; - - } - - /// - /// Determine the name for the parent of the currently parsed object, - /// in case of the current object being defined as a child object. - /// The default implementation returns null - /// indicating a root object definition. - /// - /// - /// the name of the parent object for the currently parsed object. - protected virtual string GetParentName(XmlElement element) + if (parserContext.IsNested) { - return null; + // Inner object definition must receive same singleton status as containing object. + builder.SetSingleton(parserContext.ContainingObjectDefinition.IsSingleton); } - /// - /// Gets the type of the object corresponding to the supplied XmlElement. - /// - /// Note that, for application classes, it is generally preferable to override - /// GetObjectTypeName instad, in order to avoid a direct - /// dependence on the object implementation class. The ObjectDefinitionParser - /// and its IXmlObjectDefinitionParser (namespace parser) can be used within an - /// IDE add-in then, even if the application classses are not available in the add-ins - /// AppDomain. - /// - /// The element. - /// The Type of the class that is being defined via parsing the supplied - /// Element. - protected virtual Type GetObjectType(XmlElement element) + if (parserContext.IsDefaultLazyInit) { - return null; + // Default-lazy-init applies to custom object definitions as well. + builder.SetLazyInit(true); } - /// - /// Gets the name of the object type name (FullName) corresponding to the supplied XmlElement. - /// - /// The element. - /// The type name of the object that is being defined via parsing the supplied - /// XmlElement. - protected virtual string GetObjectTypeName(XmlElement element) - { - return null; - } - - /// - /// Parse the supplied XmlElement and populate the supplied ObjectDefinitionBuilder as required. - /// - /// The default implementation delegates to the DoParse version without - /// ParameterContext argument. - /// The element. - /// The parser context. - /// The builder used to define the IObjectDefinition. - protected virtual void DoParse(XmlElement element, ParserContext parserContext, ObjectDefinitionBuilder builder) - { - DoParse(element, builder); - } - - /// - /// Parse the supplied XmlElement and populate the supplied ObjectDefinitionBuilder as required. - /// - /// The default implementation does nothing. - /// The element. - /// The builder used to define the IObjectDefinition. - protected virtual void DoParse(XmlElement element, ObjectDefinitionBuilder builder) - { - - } - - #endregion + DoParse(element, parserContext, builder); + return builder.ObjectDefinition; } -} + + /// + /// Determine the name for the parent of the currently parsed object, + /// in case of the current object being defined as a child object. + /// The default implementation returns null + /// indicating a root object definition. + /// + /// + /// the name of the parent object for the currently parsed object. + protected virtual string GetParentName(XmlElement element) + { + return null; + } + + /// + /// Gets the type of the object corresponding to the supplied XmlElement. + /// + /// Note that, for application classes, it is generally preferable to override + /// GetObjectTypeName instad, in order to avoid a direct + /// dependence on the object implementation class. The ObjectDefinitionParser + /// and its IXmlObjectDefinitionParser (namespace parser) can be used within an + /// IDE add-in then, even if the application classses are not available in the add-ins + /// AppDomain. + /// + /// The element. + /// The Type of the class that is being defined via parsing the supplied + /// Element. + protected virtual Type GetObjectType(XmlElement element) + { + return null; + } + + /// + /// Gets the name of the object type name (FullName) corresponding to the supplied XmlElement. + /// + /// The element. + /// The type name of the object that is being defined via parsing the supplied + /// XmlElement. + protected virtual string GetObjectTypeName(XmlElement element) + { + return null; + } + + /// + /// Parse the supplied XmlElement and populate the supplied ObjectDefinitionBuilder as required. + /// + /// The default implementation delegates to the DoParse version without + /// ParameterContext argument. + /// The element. + /// The parser context. + /// The builder used to define the IObjectDefinition. + protected virtual void DoParse(XmlElement element, ParserContext parserContext, ObjectDefinitionBuilder builder) + { + DoParse(element, builder); + } + + /// + /// Parse the supplied XmlElement and populate the supplied ObjectDefinitionBuilder as required. + /// + /// The default implementation does nothing. + /// The element. + /// The builder used to define the IObjectDefinition. + protected virtual void DoParse(XmlElement element, ObjectDefinitionBuilder builder) + { + } + + #endregion +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Objects/Factory/Xml/DefaultNamespaceHandlerResolver.cs b/src/Spring/Spring.Core/Objects/Factory/Xml/DefaultNamespaceHandlerResolver.cs index 5bc19983..0ebff03a 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Xml/DefaultNamespaceHandlerResolver.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Xml/DefaultNamespaceHandlerResolver.cs @@ -1,43 +1,42 @@ #region License -/* - * Copyright 2002-2010 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. +/* + * Copyright 2002-2010 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 -namespace Spring.Objects.Factory.Xml +namespace Spring.Objects.Factory.Xml; + +/// +/// Default implementation of the interface. +/// Resolves namespace URIs to implementation types based on mappings. +/// +/// Erich Eichinger +/// +/// +internal class DefaultNamespaceHandlerResolver : INamespaceParserResolver { /// - /// Default implementation of the interface. - /// Resolves namespace URIs to implementation types based on mappings. + /// Resolve the namespace URI and return the corresponding + /// implementation. /// - /// Erich Eichinger - /// - /// - internal class DefaultNamespaceHandlerResolver : INamespaceParserResolver + /// the namespace URI to get the matching parser for. + /// the matching parser or null + public INamespaceParser Resolve(string namespaceUri) { - /// - /// Resolve the namespace URI and return the corresponding - /// implementation. - /// - /// the namespace URI to get the matching parser for. - /// the matching parser or null - public INamespaceParser Resolve(string namespaceUri) - { - return NamespaceParserRegistry.GetParser(namespaceUri); - } + return NamespaceParserRegistry.GetParser(namespaceUri); } -} \ No newline at end of file +} diff --git a/src/Spring/Spring.Core/Objects/Factory/Xml/DefaultObjectDefinitionDocumentReader.cs b/src/Spring/Spring.Core/Objects/Factory/Xml/DefaultObjectDefinitionDocumentReader.cs index ce8a106f..b89a72f5 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Xml/DefaultObjectDefinitionDocumentReader.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Xml/DefaultObjectDefinitionDocumentReader.cs @@ -21,291 +21,291 @@ using Spring.Core.IO; using Spring.Objects.Factory.Config; using Spring.Objects.Factory.Support; -namespace Spring.Objects.Factory.Xml +namespace Spring.Objects.Factory.Xml; + +/// +/// XML resource reader. +/// +/// +///

+/// Navigates through an XML resource and invokes parsers registered +/// with the . +///

+///
+/// Rod Johnson +/// Juergen Hoeller +/// Rick Evans (.NET) +public class DefaultObjectDefinitionDocumentReader : IObjectDefinitionDocumentReader { /// - /// XML resource reader. + /// The shared instance for this class (and derived classes). /// - /// - ///

- /// Navigates through an XML resource and invokes parsers registered - /// with the . - ///

- ///
- /// Rod Johnson - /// Juergen Hoeller - /// Rick Evans (.NET) - public class DefaultObjectDefinitionDocumentReader : IObjectDefinitionDocumentReader + protected static readonly ILogger log = LogManager.GetLogger(); + + private XmlReaderContext readerContext; + + /// + /// Creates a new instance of the DefaultObjectDefinitionDocumentReader class. + /// + public DefaultObjectDefinitionDocumentReader() { - /// - /// The shared instance for this class (and derived classes). - /// - protected static readonly ILogger log = LogManager.GetLogger(); + } - private XmlReaderContext readerContext; + /// + /// Gets the reader context. + /// + /// The reader context. + public XmlReaderContext ReaderContext + { + get { return readerContext; } + } - /// - /// Creates a new instance of the DefaultObjectDefinitionDocumentReader class. - /// - public DefaultObjectDefinitionDocumentReader() + /// + /// Read object definitions from the given DOM element, and register + /// them with the given object registry. + /// + /// The DOM element containing object definitions, usually the + /// root (document) element. + /// The current context of the reader. Includes + /// the resource being parsed + /// + /// The number of object definitions that were loaded. + /// + /// + /// In case of parsing errors. + /// + public void RegisterObjectDefinitions(XmlDocument doc, XmlReaderContext readerContext) + { + //int objectDefinitionCounter = 0; + + this.readerContext = readerContext; + + if (log.IsEnabled(LogLevel.Debug)) { + log.LogDebug("Loading object definitions."); } - /// - /// Gets the reader context. - /// - /// The reader context. - public XmlReaderContext ReaderContext + XmlElement root = doc.DocumentElement; + + ObjectDefinitionParserHelper parserHelper = CreateHelper(readerContext, root); + + PreProcessXml(root); + + ParseObjectDefinitions(root, parserHelper); + + PostProcessXml(root); + + if (log.IsEnabled(LogLevel.Debug)) { - get { return readerContext; } + log.LogDebug($"Found {readerContext.Registry.ObjectDefinitionCount} <{ObjectDefinitionConstants.ObjectElement}> elements defining objects."); } + } - /// - /// Read object definitions from the given DOM element, and register - /// them with the given object registry. - /// - /// The DOM element containing object definitions, usually the - /// root (document) element. - /// The current context of the reader. Includes - /// the resource being parsed - /// - /// The number of object definitions that were loaded. - /// - /// - /// In case of parsing errors. - /// - public void RegisterObjectDefinitions(XmlDocument doc, XmlReaderContext readerContext) + /// + /// Parses object definitions starting at the given + /// using the passed . + /// + /// The root element to start parsing from. + /// The instance to use. + /// + /// in case an error happens during parsing and registering object definitions + /// + protected virtual void ParseObjectDefinitions(XmlElement root, ObjectDefinitionParserHelper helper) + { + if (helper.IsDefaultNamespace(root.NamespaceURI)) { - //int objectDefinitionCounter = 0; - - this.readerContext = readerContext; - - if (log.IsEnabled(LogLevel.Debug)) + foreach (XmlNode node in root.ChildNodes) { - log.LogDebug("Loading object definitions."); - } + if (node.NodeType != XmlNodeType.Element) continue; - XmlElement root = doc.DocumentElement; - - ObjectDefinitionParserHelper parserHelper = CreateHelper(readerContext, root); - - - PreProcessXml(root); - - ParseObjectDefinitions(root, parserHelper); - - PostProcessXml(root); - - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug($"Found {readerContext.Registry.ObjectDefinitionCount} <{ObjectDefinitionConstants.ObjectElement}> elements defining objects."); - } - } - - /// - /// Parses object definitions starting at the given - /// using the passed . - /// - /// The root element to start parsing from. - /// The instance to use. - /// - /// in case an error happens during parsing and registering object definitions - /// - protected virtual void ParseObjectDefinitions(XmlElement root, ObjectDefinitionParserHelper helper) - { - if (helper.IsDefaultNamespace(root.NamespaceURI)) - { - foreach (XmlNode node in root.ChildNodes) + try { - if (node.NodeType != XmlNodeType.Element) continue; - - try + XmlElement element = (XmlElement) node; + if (helper.IsDefaultNamespace(element.NamespaceURI)) { - XmlElement element = (XmlElement)node; - if (helper.IsDefaultNamespace(element.NamespaceURI)) - { - ParseDefaultElement(element, helper); - } - else - { - helper.ParseCustomElement(element); - } + ParseDefaultElement(element, helper); } - catch (ObjectDefinitionStoreException) + else { - throw; - } - catch (Exception ex) - { - helper.ReaderContext.ReportException(node, null, "Failed parsing element", ex); + helper.ParseCustomElement(element); } } - } - else - { - helper.ParseCustomElement(root); - } - } - - private void ParseDefaultElement(XmlElement element, ObjectDefinitionParserHelper helper) - { - if (element.LocalName == ObjectDefinitionConstants.ImportElement) - { - ImportObjectDefinitionResource(element); - } - else if (element.LocalName == ObjectDefinitionConstants.AliasElement) - { - ParseAlias(element, helper.ReaderContext.Registry); - } - else if (element.LocalName == ObjectDefinitionConstants.ObjectElement) - { - ProcessObjectDefinition(element, helper); - } - } - - /// - /// Process an alias element. - /// - protected virtual void ProcessAlias(XmlElement element) - { - this.ParseAlias(element, this.ReaderContext.Registry); - } - - /// - /// Process the object element - /// - protected virtual void ProcessObjectDefinition(XmlElement element, ObjectDefinitionParserHelper helper) - { - // TODO: add event handling - try - { - ObjectDefinitionHolder bdHolder = helper.ParseObjectDefinitionElement(element); - if (bdHolder == null) + catch (ObjectDefinitionStoreException) { - return; + throw; } - bdHolder = helper.DecorateObjectDefinitionIfRequired(element, bdHolder); - - if (log.IsEnabled(LogLevel.Debug)) + catch (Exception ex) { - log.LogDebug(string.Format(CultureInfo.InvariantCulture, "Registering object definition with id '{0}'.", bdHolder.ObjectName)); + helper.ReaderContext.ReportException(node, null, "Failed parsing element", ex); } - - ObjectDefinitionReaderUtils.RegisterObjectDefinition(bdHolder, ReaderContext.Registry); - // TODO: Send registration event. - // ReaderContext.FireComponentRegistered(new BeanComponentDefinition(bdHolder)); - } - catch (ObjectDefinitionStoreException) - { - throw; - } - catch (Exception ex) - { - throw new ObjectDefinitionStoreException( - $"Failed parsing object definition '{element.OuterXml}'", ex); } } - - /// - /// Loads external XML object definitions from the resource described by the supplied - /// . - /// - /// The XML element describing the resource. - /// - /// If the resource could not be imported. - /// - protected virtual void ImportObjectDefinitionResource(XmlElement resource) + else { - string location = resource.GetAttribute(ObjectDefinitionConstants.ImportResourceAttribute); - try - { - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug(string.Format( - CultureInfo.InvariantCulture, - "Attempting to import object definitions from '{0}'.", location)); - } - - IResource importResource = ReaderContext.Resource.CreateRelative(location); - ReaderContext.Reader.LoadObjectDefinitions(importResource); - } - catch (IOException ex) - { - ReaderContext.ReportException(resource, null, string.Format( - CultureInfo.InvariantCulture, - "Invalid relative resource location '{0}' to import object definitions from.", - location), ex); - } + helper.ParseCustomElement(root); } + } - /// - /// Parses the given alias element, registering the alias with the registry. - /// - /// The alias element. - /// The registry. - protected virtual void ParseAlias(XmlElement aliasElement, IObjectDefinitionRegistry registry) + private void ParseDefaultElement(XmlElement element, ObjectDefinitionParserHelper helper) + { + if (element.LocalName == ObjectDefinitionConstants.ImportElement) { - string name = aliasElement.GetAttribute(ObjectDefinitionConstants.NameAttribute); - string alias = aliasElement.GetAttribute(ObjectDefinitionConstants.AliasAttribute); - registry.RegisterAlias(name, alias); + ImportObjectDefinitionResource(element); } - - /// - /// Parse an object definition and register it with the object factory.. - /// - /// The element containing the object definition. - /// The helper. - /// - protected virtual void RegisterObjectDefinition(XmlElement element, ObjectDefinitionParserHelper helper) + else if (element.LocalName == ObjectDefinitionConstants.AliasElement) + { + ParseAlias(element, helper.ReaderContext.Registry); + } + else if (element.LocalName == ObjectDefinitionConstants.ObjectElement) { ProcessObjectDefinition(element, helper); } + } - /// - /// - /// Allow the XML to be extensible by processing any custom element types last, - /// after we finished processing the objct definitions. This method is a natural - /// extension point for any other custom post-processing of the XML. - /// - /// The default implementation is empty. Subclasses can override this method to - /// convert custom elements into standard Spring object definitions, for example. - /// Implementors have access to the parser's object definition reader and the - /// underlying XML resource, through the corresponding properties. - /// - /// - /// The root. - protected virtual void PostProcessXml(XmlElement root) - { - } + /// + /// Process an alias element. + /// + protected virtual void ProcessAlias(XmlElement element) + { + this.ParseAlias(element, this.ReaderContext.Registry); + } - /// - /// Allow the XML to be extensible by processing any custom element types first, - /// before we start to process the object definitions. - /// - /// This method is a natural - /// extension point for any other custom pre-processing of the XML. - ///

The default implementation is empty. Subclasses can override this method to - /// convert custom elements into standard Spring object definitions, for example. - /// Implementors have access to the parser's object definition reader and the - /// underlying XML resource, through the corresponding properties. - ///

- ///
- /// The root element of the XML document. - protected virtual void PreProcessXml(XmlElement root) + /// + /// Process the object element + /// + protected virtual void ProcessObjectDefinition(XmlElement element, ObjectDefinitionParserHelper helper) + { + // TODO: add event handling + try { - } + ObjectDefinitionHolder bdHolder = helper.ParseObjectDefinitionElement(element); + if (bdHolder == null) + { + return; + } - /// - /// Creates an instance for the given and element. - /// - /// the to create the - /// the root to start reading from - /// a new instance - protected virtual ObjectDefinitionParserHelper CreateHelper(XmlReaderContext readerContext, XmlElement root) - { - ObjectDefinitionParserHelper helper = new ObjectDefinitionParserHelper(readerContext, root); - return helper; + bdHolder = helper.DecorateObjectDefinitionIfRequired(element, bdHolder); + + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug(string.Format(CultureInfo.InvariantCulture, "Registering object definition with id '{0}'.", bdHolder.ObjectName)); + } + + ObjectDefinitionReaderUtils.RegisterObjectDefinition(bdHolder, ReaderContext.Registry); + // TODO: Send registration event. + // ReaderContext.FireComponentRegistered(new BeanComponentDefinition(bdHolder)); } + catch (ObjectDefinitionStoreException) + { + throw; + } + catch (Exception ex) + { + throw new ObjectDefinitionStoreException( + $"Failed parsing object definition '{element.OuterXml}'", ex); + } + } + + /// + /// Loads external XML object definitions from the resource described by the supplied + /// . + /// + /// The XML element describing the resource. + /// + /// If the resource could not be imported. + /// + protected virtual void ImportObjectDefinitionResource(XmlElement resource) + { + string location = resource.GetAttribute(ObjectDefinitionConstants.ImportResourceAttribute); + try + { + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug(string.Format( + CultureInfo.InvariantCulture, + "Attempting to import object definitions from '{0}'.", location)); + } + + IResource importResource = ReaderContext.Resource.CreateRelative(location); + ReaderContext.Reader.LoadObjectDefinitions(importResource); + } + catch (IOException ex) + { + ReaderContext.ReportException(resource, null, string.Format( + CultureInfo.InvariantCulture, + "Invalid relative resource location '{0}' to import object definitions from.", + location), ex); + } + } + + /// + /// Parses the given alias element, registering the alias with the registry. + /// + /// The alias element. + /// The registry. + protected virtual void ParseAlias(XmlElement aliasElement, IObjectDefinitionRegistry registry) + { + string name = aliasElement.GetAttribute(ObjectDefinitionConstants.NameAttribute); + string alias = aliasElement.GetAttribute(ObjectDefinitionConstants.AliasAttribute); + registry.RegisterAlias(name, alias); + } + + /// + /// Parse an object definition and register it with the object factory.. + /// + /// The element containing the object definition. + /// The helper. + /// + protected virtual void RegisterObjectDefinition(XmlElement element, ObjectDefinitionParserHelper helper) + { + ProcessObjectDefinition(element, helper); + } + + /// + /// + /// Allow the XML to be extensible by processing any custom element types last, + /// after we finished processing the objct definitions. This method is a natural + /// extension point for any other custom post-processing of the XML. + /// + /// The default implementation is empty. Subclasses can override this method to + /// convert custom elements into standard Spring object definitions, for example. + /// Implementors have access to the parser's object definition reader and the + /// underlying XML resource, through the corresponding properties. + /// + /// + /// The root. + protected virtual void PostProcessXml(XmlElement root) + { + } + + /// + /// Allow the XML to be extensible by processing any custom element types first, + /// before we start to process the object definitions. + /// + /// This method is a natural + /// extension point for any other custom pre-processing of the XML. + ///

The default implementation is empty. Subclasses can override this method to + /// convert custom elements into standard Spring object definitions, for example. + /// Implementors have access to the parser's object definition reader and the + /// underlying XML resource, through the corresponding properties. + ///

+ ///
+ /// The root element of the XML document. + protected virtual void PreProcessXml(XmlElement root) + { + } + + /// + /// Creates an instance for the given and element. + /// + /// the to create the + /// the root to start reading from + /// a new instance + protected virtual ObjectDefinitionParserHelper CreateHelper(XmlReaderContext readerContext, XmlElement root) + { + ObjectDefinitionParserHelper helper = new ObjectDefinitionParserHelper(readerContext, root); + return helper; + } // private INamespaceParser GetNamespaceParser(XmlElement element, ObjectDefinitionParserHelper helper) // { @@ -321,5 +321,4 @@ namespace Spring.Objects.Factory.Xml // { // return "There is no parser registered for namespace '" + namespaceURI + "'"; // } - } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Xml/DocumentDefaultsDefinition.cs b/src/Spring/Spring.Core/Objects/Factory/Xml/DocumentDefaultsDefinition.cs index c7b95ca4..e00b9d40 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Xml/DocumentDefaultsDefinition.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Xml/DocumentDefaultsDefinition.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -18,93 +18,92 @@ #endregion -namespace Spring.Objects.Factory.Xml +namespace Spring.Objects.Factory.Xml; + +/// +/// Simple class that holds the defaults specified at the <objects> +/// level in a standard Spring XML object definition document: +/// default-lazy-init, default-autowire, etc. +/// +/// Juergen Hoeller +/// Mark Pollack (.NET) +public class DocumentDefaultsDefinition { + private string autowire; + private string dependencyCheck; + private string lazyInit; + private string merge; + private string initMethod; + private string destroyMethod; + private string autowireCandidates; + /// - /// Simple class that holds the defaults specified at the <objects> - /// level in a standard Spring XML object definition document: - /// default-lazy-init, default-autowire, etc. + /// Gets or sets the autowire setting for the document that's currently parsed. /// - /// Juergen Hoeller - /// Mark Pollack (.NET) - public class DocumentDefaultsDefinition + /// The autowire. + public string Autowire { - private string autowire; - private string dependencyCheck; - private string lazyInit; - private string merge; - private string initMethod; - private string destroyMethod; - private string autowireCandidates; + get { return autowire; } + set { autowire = value; } + } - /// - /// Gets or sets the autowire setting for the document that's currently parsed. - /// - /// The autowire. - public string Autowire - { - get { return autowire; } - set { autowire = value; } - } + /// + /// Gets or sets the dependency-check setting for the document that's currently parsed + /// + /// The dependency check. + public string DependencyCheck + { + get { return dependencyCheck; } + set { dependencyCheck = value; } + } - /// - /// Gets or sets the dependency-check setting for the document that's currently parsed - /// - /// The dependency check. - public string DependencyCheck - { - get { return dependencyCheck; } - set { dependencyCheck = value; } - } + /// + /// Gets or sets the lazy-init flag for the document that's currently parsed. + /// + /// The lazy init. + public string LazyInit + { + get { return lazyInit; } + set { lazyInit = value; } + } - /// - /// Gets or sets the lazy-init flag for the document that's currently parsed. - /// - /// The lazy init. - public string LazyInit - { - get { return lazyInit; } - set { lazyInit = value; } - } + /// + /// Gets or sets the merge setting for the document that's currently parsed. + /// + /// The merge. + public string Merge + { + get { return merge; } + set { merge = value; } + } - /// - /// Gets or sets the merge setting for the document that's currently parsed. - /// - /// The merge. - public string Merge - { - get { return merge; } - set { merge = value; } - } + /// + /// Get or sets the init method for the document that's currently parsed. + /// + /// The init method + public string InitMethod + { + get { return initMethod; } + set { initMethod = value; } + } - /// - /// Get or sets the init method for the document that's currently parsed. - /// - /// The init method - public string InitMethod - { - get { return initMethod; } - set { initMethod = value; } - } + /// + /// Gets or sets the destroy method for the document that's currently parsed. + /// + /// The destroy methood + public string DestroyMethod + { + get { return destroyMethod; } + set { destroyMethod = value; } + } - /// - /// Gets or sets the destroy method for the document that's currently parsed. - /// - /// The destroy methood - public string DestroyMethod - { - get { return destroyMethod; } - set { destroyMethod = value; } - } - - /// - /// Gets or sets autowire candidates for the document that's currently parsed - /// - /// The Autowire Candidates - public string AutowireCandidates - { - get { return autowireCandidates; } - set { autowireCandidates = value; } - } + /// + /// Gets or sets autowire candidates for the document that's currently parsed + /// + /// The Autowire Candidates + public string AutowireCandidates + { + get { return autowireCandidates; } + set { autowireCandidates = value; } } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Xml/INamespaceParser.cs b/src/Spring/Spring.Core/Objects/Factory/Xml/INamespaceParser.cs index f8ba9d12..8e162bb3 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Xml/INamespaceParser.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Xml/INamespaceParser.cs @@ -21,74 +21,69 @@ using System.Xml; using Spring.Objects.Factory.Config; -namespace Spring.Objects.Factory.Xml +namespace Spring.Objects.Factory.Xml; + +/// +/// Strategy interface for parsing XML object definitions. Equivalent to Spring/Java's NamespaceHandler interface. +/// +/// +///

+/// Used by +/// for actually parsing a DOM document or +/// fragment. +///

+///
+/// Juergen Hoeller +/// Rick Evans (.NET) +/// Sandu Turcan (.NET) +public interface INamespaceParser { + /// + /// Invoked by after construction but before any + /// elements have been parsed. + /// + void Init(); - /// - /// Strategy interface for parsing XML object definitions. Equivalent to Spring/Java's NamespaceHandler interface. - /// - /// - ///

- /// Used by - /// for actually parsing a DOM document or - /// fragment. - ///

- ///
- /// Juergen Hoeller - /// Rick Evans (.NET) - /// Sandu Turcan (.NET) - public interface INamespaceParser - { + /// + /// Parse the specified element and register any resulting + /// IObjectDefinitions with the IObjectDefinitionRegistry that is + /// embedded in the supplied ParserContext. + /// + /// + /// Implementations should return the primary IObjectDefinition + /// that results from the parse phase if they wish to used nested + /// inside (for example) a <property> tag. + /// Implementations may return null if they will not + /// be used in a nested scenario. + /// + /// + /// The element to be parsed into one or more IObjectDefinitions + /// The object encapsulating the current state of the parsing + /// process. + /// + /// The primary IObjectDefinition (can be null as explained above) + /// + IObjectDefinition ParseElement(XmlElement element, ParserContext parserContext); - /// - /// Invoked by after construction but before any - /// elements have been parsed. - /// - void Init(); - - - /// - /// Parse the specified element and register any resulting - /// IObjectDefinitions with the IObjectDefinitionRegistry that is - /// embedded in the supplied ParserContext. - /// - /// - /// Implementations should return the primary IObjectDefinition - /// that results from the parse phase if they wish to used nested - /// inside (for example) a <property> tag. - /// Implementations may return null if they will not - /// be used in a nested scenario. - /// - /// - /// The element to be parsed into one or more IObjectDefinitions - /// The object encapsulating the current state of the parsing - /// process. - /// - /// The primary IObjectDefinition (can be null as explained above) - /// - IObjectDefinition ParseElement(XmlElement element, ParserContext parserContext); - - - /// - /// Parse the specified XmlNode and decorate the supplied ObjectDefinitionHolder, - /// returning the decorated definition. - /// - /// The XmlNode may either be an XmlAttribute or an XmlElement, depending on - /// whether a custom attribute or element is being parsed. - /// Implementations may choose to return a completely new definition, - /// which will replace the original definition in the resulting IApplicationContext/IObjectFactory. - /// - /// The supplied ParserContext can be used to register any additional objects needed to support - /// the main definition. - /// - /// The source element or attribute that is to be parsed. - /// The current object definition. - /// The object encapsulating the current state of the parsing - /// process. - /// The decorated definition (to be registered in the IApplicationContext/IObjectFactory), - /// or simply the original object definition if no decoration is required. A null value is strickly - /// speaking invalid, but will leniently treated like the case where the original object definition - /// gets returned. - ObjectDefinitionHolder Decorate(XmlNode node, ObjectDefinitionHolder definition, ParserContext parserContext); - } + /// + /// Parse the specified XmlNode and decorate the supplied ObjectDefinitionHolder, + /// returning the decorated definition. + /// + /// The XmlNode may either be an XmlAttribute or an XmlElement, depending on + /// whether a custom attribute or element is being parsed. + /// Implementations may choose to return a completely new definition, + /// which will replace the original definition in the resulting IApplicationContext/IObjectFactory. + /// + /// The supplied ParserContext can be used to register any additional objects needed to support + /// the main definition. + /// + /// The source element or attribute that is to be parsed. + /// The current object definition. + /// The object encapsulating the current state of the parsing + /// process. + /// The decorated definition (to be registered in the IApplicationContext/IObjectFactory), + /// or simply the original object definition if no decoration is required. A null value is strickly + /// speaking invalid, but will leniently treated like the case where the original object definition + /// gets returned. + ObjectDefinitionHolder Decorate(XmlNode node, ObjectDefinitionHolder definition, ParserContext parserContext); } diff --git a/src/Spring/Spring.Core/Objects/Factory/Xml/INamespaceParserResolver.cs b/src/Spring/Spring.Core/Objects/Factory/Xml/INamespaceParserResolver.cs index 35c97f49..0ebdfe69 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Xml/INamespaceParserResolver.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Xml/INamespaceParserResolver.cs @@ -1,41 +1,40 @@ #region License -/* - * Copyright 2002-2010 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. +/* + * Copyright 2002-2010 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 -namespace Spring.Objects.Factory.Xml +namespace Spring.Objects.Factory.Xml; + +/// +/// Used by to locate +/// implementations for a particular namespace URI. +/// +/// TODO (EE): clarify naming of INamespaceParser (SPR/NET) vs. INamespaceHandler (SPR/Java), thus internal for now +/// Erich Eichinger +/// +/// +/// +internal interface INamespaceParserResolver { /// - /// Used by to locate - /// implementations for a particular namespace URI. + /// Lookup a for the given namespace URI. /// - /// TODO (EE): clarify naming of INamespaceParser (SPR/NET) vs. INamespaceHandler (SPR/Java), thus internal for now - /// Erich Eichinger - /// - /// - /// - internal interface INamespaceParserResolver - { - /// - /// Lookup a for the given namespace URI. - /// - /// the namespace URI - /// the located namespace handler or null - INamespaceParser Resolve(string namespaceUri); - } -} \ No newline at end of file + /// the namespace URI + /// the located namespace handler or null + INamespaceParser Resolve(string namespaceUri); +} diff --git a/src/Spring/Spring.Core/Objects/Factory/Xml/IObjectDefinitionDocumentReader.cs b/src/Spring/Spring.Core/Objects/Factory/Xml/IObjectDefinitionDocumentReader.cs index 14670c3f..bb005103 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Xml/IObjectDefinitionDocumentReader.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Xml/IObjectDefinitionDocumentReader.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -20,38 +20,37 @@ using System.Xml; -namespace Spring.Objects.Factory.Xml +namespace Spring.Objects.Factory.Xml; + +/// +/// SPI for parsing an XML document that contains Spring object definitions. +/// Used by for actually parsing a DOM +/// document. +/// +/// Instantiated per document to parse: Implementations can hold state in +/// instance variables during the execution of the RegisterObjectDefinitions +/// method, for example global settings that are defined for all object definitions +/// in the document. +/// +/// Juergen Hoeller +/// Rob Harrop +/// Mark Pollack (.NET) +/// +public interface IObjectDefinitionDocumentReader { /// - /// SPI for parsing an XML document that contains Spring object definitions. - /// Used by for actually parsing a DOM - /// document. + /// Read object definitions from the given DOM element, and register + /// them with the given object registry. /// - /// Instantiated per document to parse: Implementations can hold state in - /// instance variables during the execution of the RegisterObjectDefinitions - /// method, for example global settings that are defined for all object definitions - /// in the document. - /// - /// Juergen Hoeller - /// Rob Harrop - /// Mark Pollack (.NET) - /// - public interface IObjectDefinitionDocumentReader - { - /// - /// Read object definitions from the given DOM element, and register - /// them with the given object registry. - /// - /// The DOM element containing object definitions, usually the - /// root (document) element. - /// The current context of the reader. Includes - /// the resource being parsed - /// - /// The number of object definitions that were loaded. - /// - /// - /// In case of parsing errors. - /// - void RegisterObjectDefinitions(XmlDocument doc, XmlReaderContext readerContext); - } -} \ No newline at end of file + /// The DOM element containing object definitions, usually the + /// root (document) element. + /// The current context of the reader. Includes + /// the resource being parsed + /// + /// The number of object definitions that were loaded. + /// + /// + /// In case of parsing errors. + /// + void RegisterObjectDefinitions(XmlDocument doc, XmlReaderContext readerContext); +} diff --git a/src/Spring/Spring.Core/Objects/Factory/Xml/IObjectDefinitionParser.cs b/src/Spring/Spring.Core/Objects/Factory/Xml/IObjectDefinitionParser.cs index 0845feb5..dcc10c8e 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Xml/IObjectDefinitionParser.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Xml/IObjectDefinitionParser.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -17,42 +17,42 @@ */ #endregion + using System.Xml; using Spring.Objects.Factory.Config; -namespace Spring.Objects.Factory.Xml +namespace Spring.Objects.Factory.Xml; + +/// +/// Interface used to handle custom, top-level tags. +/// +/// Implementations are free to turn the metadata in the custom tag into as +/// many as required. +/// +/// Rob Harrop +/// Mark Pollack (.NET) +public interface IObjectDefinitionParser { /// - /// Interface used to handle custom, top-level tags. + /// Parse the specified XmlElement and register the resulting + /// ObjectDefinitions with the IObjectDefinitionRegistry + /// embedded in the supplied /// - /// Implementations are free to turn the metadata in the custom tag into as - /// many as required. + /// + ///

+ /// This method is never invoked if the parser is namespace aware + /// and was called to process the root node. + ///

///
- /// Rob Harrop - /// Mark Pollack (.NET) - public interface IObjectDefinitionParser - { - /// - /// Parse the specified XmlElement and register the resulting - /// ObjectDefinitions with the IObjectDefinitionRegistry - /// embedded in the supplied - /// - /// - ///

- /// This method is never invoked if the parser is namespace aware - /// and was called to process the root node. - ///

- ///
- /// - /// The element to be parsed. - /// - /// - /// The object encapsulating the current state of the parsing process. - /// Provides access to a IObjectDefinitionRegistry - /// - /// - /// The primary object definition. - /// - IObjectDefinition ParseElement(XmlElement element, ParserContext parserContext); - } + /// + /// The element to be parsed. + /// + /// + /// The object encapsulating the current state of the parsing process. + /// Provides access to a IObjectDefinitionRegistry + /// + /// + /// The primary object definition. + /// + IObjectDefinition ParseElement(XmlElement element, ParserContext parserContext); } diff --git a/src/Spring/Spring.Core/Objects/Factory/Xml/NamespaceParserAttribute.cs b/src/Spring/Spring.Core/Objects/Factory/Xml/NamespaceParserAttribute.cs index e5d069da..a2fcf2a2 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Xml/NamespaceParserAttribute.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Xml/NamespaceParserAttribute.cs @@ -18,65 +18,65 @@ #endregion -namespace Spring.Objects.Factory.Xml +namespace Spring.Objects.Factory.Xml; + +/// +/// Attribute that should be used to specify the default namespace +/// and schema location for a custom namespace parser. +/// +/// Aleksandar Seovic +[AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = false)] +public class NamespaceParserAttribute : Attribute { + private string ns; + private string schemaLocation; + private Type schemaLocationAssemblyHint; + /// - /// Attribute that should be used to specify the default namespace - /// and schema location for a custom namespace parser. + /// Creates a new instance of . /// - /// Aleksandar Seovic - [AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = false)] - public class NamespaceParserAttribute : Attribute + public NamespaceParserAttribute() { - private string ns; - private string schemaLocation; - private Type schemaLocationAssemblyHint; + } - /// - /// Creates a new instance of . - /// - public NamespaceParserAttribute() - {} + /// + /// Gets or sets the default namespace for the configuration parser. + /// + /// + /// The default namespace for the configuration parser. + /// + public string Namespace + { + get { return ns; } + set { ns = value; } + } - /// - /// Gets or sets the default namespace for the configuration parser. - /// - /// - /// The default namespace for the configuration parser. - /// - public string Namespace - { - get { return ns; } - set { ns = value; } - } + /// + /// Gets or sets the default schema location for the configuration parser. + /// + /// + /// The default schema location for the configuration parser. + /// + /// + /// If the property is set, the will always resolve to an assembly-resource + /// and the set will be interpreted relative to this assembly. + /// + public string SchemaLocation + { + get { return schemaLocation; } + set { schemaLocation = value; } + } - /// - /// Gets or sets the default schema location for the configuration parser. - /// - /// - /// The default schema location for the configuration parser. - /// - /// - /// If the property is set, the will always resolve to an assembly-resource - /// and the set will be interpreted relative to this assembly. - /// - public string SchemaLocation - { - get { return schemaLocation; } - set { schemaLocation = value; } - } - - /// - /// Gets or sets a type from the assembly containing the schema - /// - /// - /// If this property is set, the will always resolve to an assembly-resource - /// and the will be interpreted relative to this assembly. - /// - public Type SchemaLocationAssemblyHint - { - get { return schemaLocationAssemblyHint; } - set { schemaLocationAssemblyHint = value; } - } + /// + /// Gets or sets a type from the assembly containing the schema + /// + /// + /// If this property is set, the will always resolve to an assembly-resource + /// and the will be interpreted relative to this assembly. + /// + public Type SchemaLocationAssemblyHint + { + get { return schemaLocationAssemblyHint; } + set { schemaLocationAssemblyHint = value; } } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Xml/NamespaceParserRegistry.cs b/src/Spring/Spring.Core/Objects/Factory/Xml/NamespaceParserRegistry.cs index 414ca01e..3985a0b2 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Xml/NamespaceParserRegistry.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Xml/NamespaceParserRegistry.cs @@ -23,327 +23,243 @@ using Spring.Core.IO; using Spring.Objects.Factory.Config; using Spring.Util; -namespace Spring.Objects.Factory.Xml +namespace Spring.Objects.Factory.Xml; + +/// +/// Provides a resolution mechanism for configuration parsers. +/// +/// +///

+/// The uses this registry +/// class to find the parser handling a specific namespace. +///

+///
+/// Aleksandar Seovic +public class NamespaceParserRegistry { /// - /// Provides a resolution mechanism for configuration parsers. + /// Resolves xml entities by using the infrastructure. + /// + private class XmlResourceUrlResolver : XmlUrlResolver + { + public override object GetEntity(Uri absoluteUri, string role, Type ofObjectToReturn) + { + IResourceLoader resourceLoader = new ConfigurableResourceLoader(); + IResource resource = resourceLoader.GetResource(absoluteUri.AbsoluteUri); + return resource.InputStream; + //return base.GetEntity( absoluteUri, role, ofObjectToReturn ); + } + + public override Uri ResolveUri(Uri baseUri, string relativeUri) + { + // TODO: resolve Uri using IResource instance + return base.ResolveUri(baseUri, relativeUri); + } + } + + /// + /// Name of the .Net config section that contains definitions + /// for custom config parsers. + /// + private const string ConfigParsersSectionName = "spring/parsers"; + + private static IDictionary parsers; + private readonly static IDictionary wellknownNamespaceParserTypeNames; + private static XmlSchemaSet schemas; + + /// + /// Creates a new instance of the NamespaceParserRegistry class. + /// + static NamespaceParserRegistry() + { + wellknownNamespaceParserTypeNames = new CaseInsensitiveHashtable(); + wellknownNamespaceParserTypeNames["http://www.springframework.net/tx"] = + "Spring.Transaction.Config.TxNamespaceParser, Spring.Data"; + wellknownNamespaceParserTypeNames["http://www.springframework.net/aop"] = + "Spring.Aop.Config.AopNamespaceParser, Spring.Aop"; + wellknownNamespaceParserTypeNames["http://www.springframework.net/context"] = + "Spring.Context.Config.ContextNamespaceParser, Spring.Core"; + wellknownNamespaceParserTypeNames["http://www.springframework.net/db"] = + "Spring.Data.Config.DatabaseNamespaceParser, Spring.Data"; + wellknownNamespaceParserTypeNames["http://www.springframework.net/database"] = + "Spring.Data.Config.DatabaseNamespaceParser, Spring.Data"; + wellknownNamespaceParserTypeNames["http://www.springframework.net/remoting"] = + "Spring.Remoting.Config.RemotingNamespaceParser, Spring.Services"; + wellknownNamespaceParserTypeNames["http://www.springframework.net/wcf"] = + "Spring.ServiceModel.Config.WcfNamespaceParser, Spring.Services"; + wellknownNamespaceParserTypeNames["http://www.springframework.net/nms"] = + "Spring.Messaging.Nms.Config.NmsNamespaceParser, Spring.Messaging.Nms"; + wellknownNamespaceParserTypeNames["http://www.springframework.net/ems"] = + "Spring.Messaging.Ems.Config.EmsNamespaceParser, Spring.Messaging.Ems"; + wellknownNamespaceParserTypeNames["http://www.springframework.net/validation"] = + "Spring.Validation.Config.ValidationNamespaceParser, Spring.Core"; + wellknownNamespaceParserTypeNames["http://www.springframework.net/nvelocity"] = + "Spring.Template.Velocity.Config.TemplateNamespaceParser, Spring.Template.Velocity"; + + Reset(); + } + + /// + /// Reset the list of registered parsers to "factory"-setting + /// + /// use for unit tests only + public static void Reset() + { + parsers = new HybridDictionary(); + schemas = new XmlSchemaSet(); + schemas.XmlResolver = new XmlResourceUrlResolver(); + + RegisterParser(new ObjectsNamespaceParser()); + // register custom config parsers + ConfigurationUtils.GetSection(ConfigParsersSectionName); + } + + /// + /// Registers the type for wellknown namespaces + /// + /// true if the parser could be registered, false otherwise + internal static bool RegisterWellknownNamespaceParserType(string namespaceUri) + { + if (parsers[namespaceUri] != null) return true; + + if (wellknownNamespaceParserTypeNames.Contains(namespaceUri)) + { + string parserTypeName = (string) wellknownNamespaceParserTypeNames[namespaceUri]; + // assume, that all Spring.XXX assemblies have same version + public key + // get the ", Version=x.x.x.x, Culture=neutral, PublicKeyToken=65e474d141e25e07" part of Spring.Core and append it + string name = typeof(NamespaceParserRegistry).Assembly.GetName().Name; + string fullname = typeof(NamespaceParserRegistry).Assembly.GetName().FullName; + string versionCulturePublicKey = fullname.Substring(name.Length); + + parserTypeName = parserTypeName + versionCulturePublicKey; + Type parserType = Type.GetType(parserTypeName, true); + RegisterParser(parserType); + return true; + } + + return false; + } + + /// + /// Constructs a "assembly://..." qualified schemaLocation url using the given type + /// to obtain the assembly name. + /// + public static string GetAssemblySchemaLocation(Type schemaLocationAssemblyHint, string schemaLocation) + { + if (schemaLocationAssemblyHint != null) + { + return "assembly://" + schemaLocationAssemblyHint.Assembly.FullName + schemaLocation; + } + + return schemaLocation; + } + + /// + /// Returns a parser for the given namespace. + /// + /// + /// The namespace for which to lookup the parser implementation. + /// + /// + /// A parser for a given , or + /// if no parser was found. + /// + public static INamespaceParser GetParser(string namespaceURI) + { + INamespaceParser parser = (INamespaceParser) parsers[namespaceURI]; + if (parser == null) + { + bool ok = RegisterWellknownNamespaceParserType(namespaceURI); + if (ok) + { + parser = (INamespaceParser) parsers[namespaceURI]; + + //work-around for SPRNET-1277 where we're inconsistent re: exposing /db or /database as the final namespace element + if (parser == null && namespaceURI == "http://www.springframework.net/db") + { + parser = (INamespaceParser) parsers["http://www.springframework.net/database"]; + } + } + } + + return parser; + } + + /// + /// Returns a schema collection containing validation schemas for all registered parsers. + /// + /// + /// A schema collection containing validation schemas for all registered parsers. + /// + public static XmlSchemaSet GetSchemas() + { + return schemas; + } + + /// + /// Pegisters parser, using default namespace and schema location + /// as defined by the . + /// + /// + /// The of the parser that will be activated + /// when an element in its default namespace is encountered. + /// + /// + /// If is . + /// + public static void RegisterParser(Type parserType) + { + RegisterParser(parserType, null, null); + } + + /// + /// Associates a parser with a namespace. /// /// - ///

- /// The uses this registry - /// class to find the parser handling a specific namespace. - ///

+ /// + /// Parsers registered with the same as that + /// of a parser that has previously been registered will overwrite the existing + /// parser. + /// ///
- /// Aleksandar Seovic - public class NamespaceParserRegistry + /// + /// The of the parser that will be activated + /// when the attendant is + /// encountered. + /// + /// + /// The namespace with which to associate instance of the parser. + /// + /// + /// The location of the XML schema that should be used for validation + /// of the XML elements that belong to the specified namespace + /// (can be any valid Spring.NET resource URI). + /// + /// + /// If the is not a + /// that implements the + /// interface. + /// + /// + /// If is . + /// + public static void RegisterParser(Type parserType, string namespaceUri, string schemaLocation) { - /// - /// Resolves xml entities by using the infrastructure. - /// - private class XmlResourceUrlResolver : XmlUrlResolver - { - public override object GetEntity(Uri absoluteUri, string role, Type ofObjectToReturn) - { - IResourceLoader resourceLoader = new ConfigurableResourceLoader(); - IResource resource = resourceLoader.GetResource(absoluteUri.AbsoluteUri); - return resource.InputStream; - //return base.GetEntity( absoluteUri, role, ofObjectToReturn ); - } + AssertUtils.ArgumentNotNull(parserType, "parserType"); - public override Uri ResolveUri(Uri baseUri, string relativeUri) - { - // TODO: resolve Uri using IResource instance - return base.ResolveUri(baseUri, relativeUri); - } + INamespaceParser np = null; + + if ((typeof(INamespaceParser)).IsAssignableFrom(parserType)) + { + np = (INamespaceParser) ObjectUtils.InstantiateType(parserType); } - - /// - /// Name of the .Net config section that contains definitions - /// for custom config parsers. - /// - private const string ConfigParsersSectionName = "spring/parsers"; - - private static IDictionary parsers; - private readonly static IDictionary wellknownNamespaceParserTypeNames; - private static XmlSchemaSet schemas; - - /// - /// Creates a new instance of the NamespaceParserRegistry class. - /// - static NamespaceParserRegistry() + // TODO (EE): workaround to enable smooth transition between 1.x and 2.0 style namespace handling + else if (typeof(IObjectDefinitionParser).IsAssignableFrom(parserType)) { - wellknownNamespaceParserTypeNames = new CaseInsensitiveHashtable(); - wellknownNamespaceParserTypeNames["http://www.springframework.net/tx"] = - "Spring.Transaction.Config.TxNamespaceParser, Spring.Data"; - wellknownNamespaceParserTypeNames["http://www.springframework.net/aop"] = - "Spring.Aop.Config.AopNamespaceParser, Spring.Aop"; - wellknownNamespaceParserTypeNames["http://www.springframework.net/context"] = - "Spring.Context.Config.ContextNamespaceParser, Spring.Core"; - wellknownNamespaceParserTypeNames["http://www.springframework.net/db"] = - "Spring.Data.Config.DatabaseNamespaceParser, Spring.Data"; - wellknownNamespaceParserTypeNames["http://www.springframework.net/database"] = - "Spring.Data.Config.DatabaseNamespaceParser, Spring.Data"; - wellknownNamespaceParserTypeNames["http://www.springframework.net/remoting"] = - "Spring.Remoting.Config.RemotingNamespaceParser, Spring.Services"; - wellknownNamespaceParserTypeNames["http://www.springframework.net/wcf"] = - "Spring.ServiceModel.Config.WcfNamespaceParser, Spring.Services"; - wellknownNamespaceParserTypeNames["http://www.springframework.net/nms"] = - "Spring.Messaging.Nms.Config.NmsNamespaceParser, Spring.Messaging.Nms"; - wellknownNamespaceParserTypeNames["http://www.springframework.net/ems"] = - "Spring.Messaging.Ems.Config.EmsNamespaceParser, Spring.Messaging.Ems"; - wellknownNamespaceParserTypeNames["http://www.springframework.net/validation"] = - "Spring.Validation.Config.ValidationNamespaceParser, Spring.Core"; - wellknownNamespaceParserTypeNames["http://www.springframework.net/nvelocity"] = - "Spring.Template.Velocity.Config.TemplateNamespaceParser, Spring.Template.Velocity"; - - Reset(); - } - - /// - /// Reset the list of registered parsers to "factory"-setting - /// - /// use for unit tests only - public static void Reset() - { - parsers = new HybridDictionary(); - schemas = new XmlSchemaSet(); - schemas.XmlResolver = new XmlResourceUrlResolver(); - - RegisterParser(new ObjectsNamespaceParser()); - // register custom config parsers - ConfigurationUtils.GetSection(ConfigParsersSectionName); - } - - /// - /// Registers the type for wellknown namespaces - /// - /// true if the parser could be registered, false otherwise - internal static bool RegisterWellknownNamespaceParserType(string namespaceUri) - { - if (parsers[namespaceUri] != null) return true; - - if (wellknownNamespaceParserTypeNames.Contains(namespaceUri)) - { - string parserTypeName = (string) wellknownNamespaceParserTypeNames[namespaceUri]; - // assume, that all Spring.XXX assemblies have same version + public key - // get the ", Version=x.x.x.x, Culture=neutral, PublicKeyToken=65e474d141e25e07" part of Spring.Core and append it - string name = typeof(NamespaceParserRegistry).Assembly.GetName().Name; - string fullname = typeof(NamespaceParserRegistry).Assembly.GetName().FullName; - string versionCulturePublicKey = fullname.Substring(name.Length); - - parserTypeName = parserTypeName + versionCulturePublicKey; - Type parserType = Type.GetType(parserTypeName, true); - RegisterParser(parserType); - return true; - } - - return false; - } - - /// - /// Constructs a "assembly://..." qualified schemaLocation url using the given type - /// to obtain the assembly name. - /// - public static string GetAssemblySchemaLocation(Type schemaLocationAssemblyHint, string schemaLocation) - { - if (schemaLocationAssemblyHint != null) - { - return "assembly://" + schemaLocationAssemblyHint.Assembly.FullName + schemaLocation; - } - - return schemaLocation; - } - - /// - /// Returns a parser for the given namespace. - /// - /// - /// The namespace for which to lookup the parser implementation. - /// - /// - /// A parser for a given , or - /// if no parser was found. - /// - public static INamespaceParser GetParser(string namespaceURI) - { - INamespaceParser parser = (INamespaceParser) parsers[namespaceURI]; - if (parser == null) - { - bool ok = RegisterWellknownNamespaceParserType(namespaceURI); - if (ok) - { - parser = (INamespaceParser) parsers[namespaceURI]; - - //work-around for SPRNET-1277 where we're inconsistent re: exposing /db or /database as the final namespace element - if (parser == null && namespaceURI == "http://www.springframework.net/db") - { - parser = (INamespaceParser) parsers["http://www.springframework.net/database"]; - } - } - } - - return parser; - } - - /// - /// Returns a schema collection containing validation schemas for all registered parsers. - /// - /// - /// A schema collection containing validation schemas for all registered parsers. - /// - public static XmlSchemaSet GetSchemas() - { - return schemas; - } - - /// - /// Pegisters parser, using default namespace and schema location - /// as defined by the . - /// - /// - /// The of the parser that will be activated - /// when an element in its default namespace is encountered. - /// - /// - /// If is . - /// - public static void RegisterParser(Type parserType) - { - RegisterParser(parserType, null, null); - } - - /// - /// Associates a parser with a namespace. - /// - /// - /// - /// Parsers registered with the same as that - /// of a parser that has previously been registered will overwrite the existing - /// parser. - /// - /// - /// - /// The of the parser that will be activated - /// when the attendant is - /// encountered. - /// - /// - /// The namespace with which to associate instance of the parser. - /// - /// - /// The location of the XML schema that should be used for validation - /// of the XML elements that belong to the specified namespace - /// (can be any valid Spring.NET resource URI). - /// - /// - /// If the is not a - /// that implements the - /// interface. - /// - /// - /// If is . - /// - public static void RegisterParser(Type parserType, string namespaceUri, string schemaLocation) - { - AssertUtils.ArgumentNotNull(parserType, "parserType"); - - INamespaceParser np = null; - - if ((typeof(INamespaceParser)).IsAssignableFrom(parserType)) - { - np = (INamespaceParser) ObjectUtils.InstantiateType(parserType); - } - // TODO (EE): workaround to enable smooth transition between 1.x and 2.0 style namespace handling - else if (typeof(IObjectDefinitionParser).IsAssignableFrom(parserType)) - { - // determine and use defaults for the namespace and schema location, if necessary - if (StringUtils.IsNullOrEmpty(namespaceUri) || StringUtils.IsNullOrEmpty(schemaLocation)) - { - NamespaceParserAttribute defaults = GetDefaults(parserType); - if (defaults == null) - { - throw new ArgumentNullException( - "Either default or an explicit namespace value must be specified for a configuration parser."); - } - - if (StringUtils.IsNullOrEmpty(namespaceUri)) - { - namespaceUri = defaults.Namespace; - } - - if (StringUtils.IsNullOrEmpty(schemaLocation)) - { - schemaLocation = defaults.SchemaLocation; - if (defaults.SchemaLocationAssemblyHint != null) - { - schemaLocation = - GetAssemblySchemaLocation(defaults.SchemaLocationAssemblyHint, schemaLocation); - } - } - } - - IObjectDefinitionParser odParser = (IObjectDefinitionParser) ObjectUtils.InstantiateType(parserType); - np = new ObjectDefinitionParserNamespaceParser(odParser); - } - else - { - throw new ArgumentException( - string.Format("The [{0}] Type must implement the INamespaceParser interface.", parserType.Name) - , "parserType"); - } - - RegisterParser(np, namespaceUri, schemaLocation); - } - - /// - /// Pegisters parser, using default namespace and schema location - /// as defined by the . - /// - /// - /// The parser instance. - /// - /// - /// If is . - /// - public static void RegisterParser(INamespaceParser parser) - { - RegisterParser(parser, null, null); - } - - /// - /// Associates a parser with a namespace. - /// - /// - /// - /// Parsers registered with the same as that - /// of a parser that has previously been registered will overwrite the existing - /// parser. - /// - /// - /// - /// The namespace with which to associate instance of the parser. - /// - /// - /// The parser instance. - /// - /// - /// The location of the XML schema that should be used for validation - /// of the XML elements that belong to the specified namespace - /// (can be any valid Spring.NET resource URI). - /// - /// - /// If is , or if - /// is not specified and parser class - /// does not have default value defined using . - /// - public static void RegisterParser(INamespaceParser parser, string namespaceUri, string schemaLocation) - { - AssertUtils.ArgumentNotNull(parser, "parser"); - // determine and use defaults for the namespace and schema location, if necessary if (StringUtils.IsNullOrEmpty(namespaceUri) || StringUtils.IsNullOrEmpty(schemaLocation)) { - NamespaceParserAttribute defaults = GetDefaults(parser.GetType()); + NamespaceParserAttribute defaults = GetDefaults(parserType); if (defaults == null) { throw new ArgumentNullException( @@ -360,96 +276,179 @@ namespace Spring.Objects.Factory.Xml schemaLocation = defaults.SchemaLocation; if (defaults.SchemaLocationAssemblyHint != null) { - schemaLocation = GetAssemblySchemaLocation(defaults.SchemaLocationAssemblyHint, schemaLocation); + schemaLocation = + GetAssemblySchemaLocation(defaults.SchemaLocationAssemblyHint, schemaLocation); } } } - // initialize the parser - parser.Init(); + IObjectDefinitionParser odParser = (IObjectDefinitionParser) ObjectUtils.InstantiateType(parserType); + np = new ObjectDefinitionParserNamespaceParser(odParser); + } + else + { + throw new ArgumentException( + string.Format("The [{0}] Type must implement the INamespaceParser interface.", parserType.Name) + , "parserType"); + } - // register parser - lock (parsers.SyncRoot) - lock (schemas) + RegisterParser(np, namespaceUri, schemaLocation); + } + + /// + /// Pegisters parser, using default namespace and schema location + /// as defined by the . + /// + /// + /// The parser instance. + /// + /// + /// If is . + /// + public static void RegisterParser(INamespaceParser parser) + { + RegisterParser(parser, null, null); + } + + /// + /// Associates a parser with a namespace. + /// + /// + /// + /// Parsers registered with the same as that + /// of a parser that has previously been registered will overwrite the existing + /// parser. + /// + /// + /// + /// The namespace with which to associate instance of the parser. + /// + /// + /// The parser instance. + /// + /// + /// The location of the XML schema that should be used for validation + /// of the XML elements that belong to the specified namespace + /// (can be any valid Spring.NET resource URI). + /// + /// + /// If is , or if + /// is not specified and parser class + /// does not have default value defined using . + /// + public static void RegisterParser(INamespaceParser parser, string namespaceUri, string schemaLocation) + { + AssertUtils.ArgumentNotNull(parser, "parser"); + + // determine and use defaults for the namespace and schema location, if necessary + if (StringUtils.IsNullOrEmpty(namespaceUri) || StringUtils.IsNullOrEmpty(schemaLocation)) + { + NamespaceParserAttribute defaults = GetDefaults(parser.GetType()); + if (defaults == null) { - parsers[namespaceUri] = parser; - if (StringUtils.HasText(schemaLocation) && !schemas.Contains(namespaceUri)) + throw new ArgumentNullException( + "Either default or an explicit namespace value must be specified for a configuration parser."); + } + + if (StringUtils.IsNullOrEmpty(namespaceUri)) + { + namespaceUri = defaults.Namespace; + } + + if (StringUtils.IsNullOrEmpty(schemaLocation)) + { + schemaLocation = defaults.SchemaLocation; + if (defaults.SchemaLocationAssemblyHint != null) { - RegisterSchema(namespaceUri, schemaLocation); + schemaLocation = GetAssemblySchemaLocation(defaults.SchemaLocationAssemblyHint, schemaLocation); } } } - /// - /// Register a schema as well-known - /// - /// - /// - private static void RegisterSchema(string namespaceUri, string schemaLocation) + // initialize the parser + parser.Init(); + + // register parser + lock (parsers.SyncRoot) + lock (schemas) { - IResourceLoader resourceLoader = new ConfigurableResourceLoader(); - IResource schema = resourceLoader.GetResource(schemaLocation); - try + parsers[namespaceUri] = parser; + if (StringUtils.HasText(schemaLocation) && !schemas.Contains(namespaceUri)) { - XmlTextReader schemaDocument = new XmlTextReader(schema.Uri.AbsoluteUri, schema.InputStream); - schemas.Add(namespaceUri, schemaDocument); - } - catch (Exception e) - { - throw new ArgumentException("Could not load schema from resource = " + schema, e); - } - } - - /// - /// Returns default values for the parser namespace and schema location as - /// defined by the . - /// - /// - /// A type of the parser. - /// - /// - /// A instance containing - /// default values for the parser namsepace and schema location - /// - private static NamespaceParserAttribute GetDefaults(Type parserType) - { - object[] attrs = parserType.GetCustomAttributes(typeof(NamespaceParserAttribute), true); - if (attrs.Length > 0) - { - return (NamespaceParserAttribute) attrs[0]; - } - - return null; - } - - /// - /// Adapts the interface to . - /// Only for smooth transition between 1.x and 2.0 style namespace handling, will be dropped for 2.0 - /// - private class ObjectDefinitionParserNamespaceParser : INamespaceParser - { - private readonly IObjectDefinitionParser odParser; - - public ObjectDefinitionParserNamespaceParser(IObjectDefinitionParser odParser) - { - this.odParser = odParser; - } - - public void Init() - { - // noop - } - - public IObjectDefinition ParseElement(XmlElement element, ParserContext parserContext) - { - return odParser.ParseElement(element, parserContext); - } - - public ObjectDefinitionHolder Decorate(XmlNode node, ObjectDefinitionHolder definition, - ParserContext parserContext) - { - return null; + RegisterSchema(namespaceUri, schemaLocation); } } } + + /// + /// Register a schema as well-known + /// + /// + /// + private static void RegisterSchema(string namespaceUri, string schemaLocation) + { + IResourceLoader resourceLoader = new ConfigurableResourceLoader(); + IResource schema = resourceLoader.GetResource(schemaLocation); + try + { + XmlTextReader schemaDocument = new XmlTextReader(schema.Uri.AbsoluteUri, schema.InputStream); + schemas.Add(namespaceUri, schemaDocument); + } + catch (Exception e) + { + throw new ArgumentException("Could not load schema from resource = " + schema, e); + } + } + + /// + /// Returns default values for the parser namespace and schema location as + /// defined by the . + /// + /// + /// A type of the parser. + /// + /// + /// A instance containing + /// default values for the parser namsepace and schema location + /// + private static NamespaceParserAttribute GetDefaults(Type parserType) + { + object[] attrs = parserType.GetCustomAttributes(typeof(NamespaceParserAttribute), true); + if (attrs.Length > 0) + { + return (NamespaceParserAttribute) attrs[0]; + } + + return null; + } + + /// + /// Adapts the interface to . + /// Only for smooth transition between 1.x and 2.0 style namespace handling, will be dropped for 2.0 + /// + private class ObjectDefinitionParserNamespaceParser : INamespaceParser + { + private readonly IObjectDefinitionParser odParser; + + public ObjectDefinitionParserNamespaceParser(IObjectDefinitionParser odParser) + { + this.odParser = odParser; + } + + public void Init() + { + // noop + } + + public IObjectDefinition ParseElement(XmlElement element, ParserContext parserContext) + { + return odParser.ParseElement(element, parserContext); + } + + public ObjectDefinitionHolder Decorate(XmlNode node, ObjectDefinitionHolder definition, + ParserContext parserContext) + { + return null; + } + } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Xml/NamespaceParserSupport.cs b/src/Spring/Spring.Core/Objects/Factory/Xml/NamespaceParserSupport.cs index 3985939a..6cfaa250 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Xml/NamespaceParserSupport.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Xml/NamespaceParserSupport.cs @@ -22,97 +22,94 @@ using System.Xml; using Spring.Objects.Factory.Config; using Spring.Util; -namespace Spring.Objects.Factory.Xml +namespace Spring.Objects.Factory.Xml; + +/// +/// Support class for implementing custom namespace parsers. +/// +/// Parsing of individual elements is done via a ObjectDefintionParser. +/// Provides the RegisterObjectDefinitionParser for registering a ObjectDefintionParser +/// to handle a specific element. +/// Rob Harrop +/// Juergen Hoeller +/// Mark Pollack (.NET) +public abstract class NamespaceParserSupport : INamespaceParser { + private readonly IDictionary objectParsers = new Dictionary(); + + #region IXmlObjectDefinitionParser Members + /// - /// Support class for implementing custom namespace parsers. + /// Invoked by after construction but before any + /// elements have been parsed. /// - /// Parsing of individual elements is done via a ObjectDefintionParser. - /// Provides the RegisterObjectDefinitionParser for registering a ObjectDefintionParser - /// to handle a specific element. - /// Rob Harrop - /// Juergen Hoeller - /// Mark Pollack (.NET) - public abstract class NamespaceParserSupport : INamespaceParser + public abstract void Init(); + + /// + /// Parses an element under the root node, typically + /// an object definition or import statement. + /// + /// + /// The element to be parsed. + /// + /// + /// The parser context. + /// + /// + /// The number of object defintions created from this element. + /// + public virtual IObjectDefinition ParseElement(XmlElement element, ParserContext parserContext) { - - private readonly IDictionary objectParsers = new Dictionary(); - - #region IXmlObjectDefinitionParser Members - - /// - /// Invoked by after construction but before any - /// elements have been parsed. - /// - public abstract void Init(); - - /// - /// Parses an element under the root node, typically - /// an object definition or import statement. - /// - /// - /// The element to be parsed. - /// - /// - /// The parser context. - /// - /// - /// The number of object defintions created from this element. - /// - public virtual IObjectDefinition ParseElement(XmlElement element, ParserContext parserContext) - { - return FindParserForElement(element, parserContext).ParseElement(element, parserContext); - } - - - /// - /// Parse the specified XmlNode and decorate the supplied ObjectDefinitionHolder, - /// returning the decorated definition. - /// - /// The XmlNode may either be an XmlAttribute or an XmlElement, depending on - /// whether a custom attribute or element is being parsed. - /// Implementations may choose to return a completely new definition, - /// which will replace the original definition in the resulting IApplicationContext/IObjectFactory. - /// - /// The supplied ParserContext can be used to register any additional objects needed to support - /// the main definition. - /// - /// The source element or attribute that is to be parsed. - /// The current object definition. - /// The object encapsulating the current state of the parsing - /// process. - /// The decorated definition (to be registered in the IApplicationContext/IObjectFactory), - /// or simply the original object definition if no decoration is required. A null value is strickly - /// speaking invalid, but will leniently treated like the case where the original object definition - /// gets returned. - public ObjectDefinitionHolder Decorate(XmlNode node, ObjectDefinitionHolder definition, - ParserContext parserContext) - { - return null; - } - - private IObjectDefinitionParser FindParserForElement(XmlElement element, ParserContext parserContext) - { - IObjectDefinitionParser parser; - if (!objectParsers.TryGetValue(element.LocalName, out parser)) - { - parserContext.ReaderContext.ReportException(element, "unknown object name", "Cannot locate IObjectDefinitionParser for element [" - + element.LocalName + "]"); - } - return parser; - - } - - /// - /// Register the specified for the given - /// - protected virtual void RegisterObjectDefinitionParser(string elementName, IObjectDefinitionParser parser) - { - AssertUtils.ArgumentNotNull(elementName, "elementName"); - AssertUtils.ArgumentNotNull(parser, "parser"); - objectParsers[elementName] = parser; - } - - #endregion + return FindParserForElement(element, parserContext).ParseElement(element, parserContext); } + + /// + /// Parse the specified XmlNode and decorate the supplied ObjectDefinitionHolder, + /// returning the decorated definition. + /// + /// The XmlNode may either be an XmlAttribute or an XmlElement, depending on + /// whether a custom attribute or element is being parsed. + /// Implementations may choose to return a completely new definition, + /// which will replace the original definition in the resulting IApplicationContext/IObjectFactory. + /// + /// The supplied ParserContext can be used to register any additional objects needed to support + /// the main definition. + /// + /// The source element or attribute that is to be parsed. + /// The current object definition. + /// The object encapsulating the current state of the parsing + /// process. + /// The decorated definition (to be registered in the IApplicationContext/IObjectFactory), + /// or simply the original object definition if no decoration is required. A null value is strickly + /// speaking invalid, but will leniently treated like the case where the original object definition + /// gets returned. + public ObjectDefinitionHolder Decorate(XmlNode node, ObjectDefinitionHolder definition, + ParserContext parserContext) + { + return null; + } + + private IObjectDefinitionParser FindParserForElement(XmlElement element, ParserContext parserContext) + { + IObjectDefinitionParser parser; + if (!objectParsers.TryGetValue(element.LocalName, out parser)) + { + parserContext.ReaderContext.ReportException(element, "unknown object name", "Cannot locate IObjectDefinitionParser for element [" + + element.LocalName + "]"); + } + + return parser; + } + + /// + /// Register the specified for the given + /// + protected virtual void RegisterObjectDefinitionParser(string elementName, IObjectDefinitionParser parser) + { + AssertUtils.ArgumentNotNull(elementName, "elementName"); + AssertUtils.ArgumentNotNull(parser, "parser"); + objectParsers[elementName] = parser; + } + + #endregion } diff --git a/src/Spring/Spring.Core/Objects/Factory/Xml/ObjectDefinitionConstants.cs b/src/Spring/Spring.Core/Objects/Factory/Xml/ObjectDefinitionConstants.cs index 3c7603f0..8da802a7 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Xml/ObjectDefinitionConstants.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Xml/ObjectDefinitionConstants.cs @@ -21,802 +21,801 @@ using Spring.Objects.Factory.Config; using Spring.Objects.Factory.Support; -namespace Spring.Objects.Factory.Xml +namespace Spring.Objects.Factory.Xml; + +/// +/// Constants defining the structure and values associated with the +/// Spring.NET XML object definition format. +/// +/// Rod Johnson +/// Juergen Hoeller +/// Rick Evans (.NET) +public sealed class ObjectDefinitionConstants { - /// - /// Constants defining the structure and values associated with the - /// Spring.NET XML object definition format. - /// - /// Rod Johnson - /// Juergen Hoeller - /// Rick Evans (.NET) - public sealed class ObjectDefinitionConstants - { - /// - /// Value of a boolean attribute that represents - /// . - /// - /// - ///

- /// Anything else represents . - ///

- ///
- public const string TrueValue = "true"; - - /// - /// Value of a boolean attribute that represents - /// . - /// - public const string FalseValue = "false"; - - /// - /// Signifies that a default value is to be applied. - /// - public const string DefaultValue = "default"; - - /// - /// Defines an external XML object definition resource. - /// - public const string ImportElement = "import"; - - /// - /// Specifies the relative path to an external XML object definition - /// resource. - /// - public const string ImportResourceAttribute = "resource"; - - /// - /// Defines an alias for an object definition. - /// - public const string AliasElement = "alias"; - - /// - /// Specifies the alias of an object definition. - /// - public const string AliasAttribute = "alias"; - - /// - /// Specifies the default lazy initialization mode. - /// - public const string DefaultLazyInitAttribute = "default-lazy-init"; - - /// - /// Specifies the default dependency checking mode. - /// - public const string DefaultDependencyCheckAttribute - = "default-dependency-check"; - - /// - /// Specifies the default autowire mode. - /// - public const string DefaultAutowireAttribute = "default-autowire"; - - /// - /// Specifies the default autowire candidates. - /// - public const string DefaultAutowireCandidatesAttribute = "default-autowire-candidates"; - - /// - /// Specifies the default collection merge mode. - /// - public const string DefaultMergeAttribute = "default-merge"; - - /// - /// Specifies the default init method. - /// - public const string DefaultInitMethodAttribute = "default-init-method"; - - /// - /// Specifies the default destroy method. - /// - public const string DefaultDestroyMethodAttribute = "default-destroy-method"; - - /// - /// Defines a single named object. - /// - public const string ObjectElement = "object"; - - /// - /// Element containing informative text describing the purpose of the - /// enclosing element. - /// - /// - ///

- /// Always optional. - ///

- ///

- /// Used primarily for user documentation of XML object definition - /// documents. - ///

- ///
- public const string DescriptionElement = "description"; - - /// - /// Specifies a . - /// - /// - ///

- /// Does not have to be fully assembly qualified, but it is recommended - /// that the names of one's objects are - /// specified explicitly. - ///

- ///
- public const string TypeAttribute = "type"; - - /// - /// The name or alias of the parent object definition that a child - /// object definition inherits from. - /// - public const string ParentAttribute = "parent"; - - /// - /// Objects can be identified by an id, to enable reference checking. - /// - /// - ///

- /// There are constraints on a valid XML id: if you want to reference - /// your object in .NET code using a name that's illegal as an XML id, - /// use the optional "name" attribute - /// (). - /// If neither given, the objects name is - /// used as id. - ///

- ///
- public const string IdAttribute = "id"; - - /// - /// Can be used to create one or more aliases illegal in an id. - /// - /// - ///

- /// Multiple aliases can be separated by any number of spaces, - /// semicolons, or commas - /// (). - ///

- ///

- /// Always optional. - ///

- ///
- public const string NameAttribute = "name"; - - /// - /// Is this object a "singleton" (one shared instance, which will - /// be returned by all calls to - /// with the id), or a - /// "prototype" (independent instance resulting from each call to - /// ). - /// - /// - ///

- /// Singletons are most commonly used, and are ideal for multi-threaded - /// service objects. - ///

- ///
- /// - public const string SingletonAttribute = "singleton"; - - /// - /// Controls object scope. Only applicable to ASP.NET web applications. - /// - /// - ///

- /// Scope can be defined as either application, session or request. It - /// defines when "singleton" instances are initialized, but has no - /// effect on prototype definitions. - ///

- ///
- public const string ScopeAttribute = "scope"; - - /// - /// The names of the objects that this object depends on being - /// initialized. - /// - /// - ///

- /// The object factory will guarantee that these objects - /// get initialized before this object definition. - ///

- /// - /// Dependencies are normally expressed through object properties or - /// constructor arguments. This property should just be necessary for - /// other kinds of dependencies such as statics (*ugh*) or database - /// preparation on startup. - /// - ///
- public const string DependsOnAttribute = "depends-on"; - - /// - /// Optional attribute for the name of the custom initialization method - /// to invoke after setting object properties. - /// - /// - ///

- /// The method must have no arguments. - ///

- ///
- public const string InitMethodAttribute = "init-method"; - - /// - /// Optional attribute for the name of the custom destroy method to - /// invoke on object factory shutdown. - /// - /// - ///

- /// Valid destroy methods have either of the following signatures... - /// - /// void MethodName() - /// void MethodName(bool force) - /// - ///

- /// - /// Only invoked on singleton objects! - /// - ///
- public const string DestroyMethodAttribute = "destroy-method"; - - /// - /// A constructor argument : the constructor-arg tag can have an - /// optional type attribute, to specify the exact type of the - /// constructor argument - /// - /// - ///

- /// Only needed to avoid ambiguities, e.g. in case of 2 single - /// argument constructors that can both be converted from a - /// . - ///

- ///
- public const string ConstructorArgElement = "constructor-arg"; - - /// - /// The constructor-arg tag can have an optional index attribute, - /// to specify the exact index in the constructor argument list. - /// - /// - ///

- /// Only needed to avoid ambiguities, e.g. in case of 2 arguments of - /// the same type. - ///

- ///
- public const string IndexAttribute = "index"; - - /// - /// The constructor-arg tag can have an optional named parameter - /// attribute, to specify a named parameter in the constructor - /// argument list. - /// - public const string ArgumentNameAttribute = "name"; - - /// - /// Is this object "abstract", i.e. not meant to be instantiated itself - /// but rather just serving as parent for concrete child object - /// definitions? - /// - /// - ///

- /// Default is . Specify - /// to tell the object factory to not try to instantiate that - /// particular object in any case. - ///

- ///
- public const string AbstractAttribute = "abstract"; - - /// - /// A property definition : object definitions can have zero or more - /// properties. - /// - /// - ///

- /// Spring.NET supports primitives, references to other objects in the - /// same or related factories, lists, dictionaries, and name value - /// collections. - ///

- ///
- public const string PropertyElement = "property"; - - /// - /// A qualifier definition used for fine grained autowiring - /// - public const string QualifierElement = "qualifier"; - - /// - /// A reference to another managed object or static - /// . - /// - public const string RefElement = "ref"; - - /// - /// ID refs must specify a name of the target object. - /// - public const string IdRefElement = "idref"; - - /// - /// A reference to the name of another managed object in the same - /// context. - /// - public const string ObjectRefAttribute = "object"; - - /// - /// A reference to the name of another managed object in the same - /// context. - /// - /// - ///

- /// Local references, using the "local" attribute, have to use object - /// ids; they can be checked by a parser, thus should be preferred for - /// references within the same object factory XML file. - ///

- ///
- public const string LocalRefAttribute = "local"; - - /// - /// Alternative to type attribute for factory-method usage. - /// - /// - ///

- /// If this is specified, no type attribute should be used. This should - /// be set to the name of an object in the current or ancestor - /// factories that contains the relevant factory method. This allows - /// the factory itself to be configured using Dependency Injection, and - /// an instance (rather than static) method to be used. - ///

- ///
- public const string FactoryObjectAttribute = "factory-object"; - - /// - /// Optional attribute specifying the name of a factory method to use - /// to create this object. - /// - /// - ///

- /// Use constructor-arg elements to specify arguments to the factory - /// method, if it takes arguments. Autowiring does not apply to - /// factory methods. - ///

- ///

- /// If the "type" attribute is present, the factory method will be a - /// static method on the type specified by the "type" attribute on - /// this object definition. Often this will be the same type as that - /// of the constructed object - for example, when the factory method - /// is used as an alternative to a constructor. However, it may be on - /// a different type. In that case, the created object will *not* be - /// of the type specified in the "type" attribute. This is analogous - /// to behaviour. - ///

- ///

- /// If the "factory-object" attribute is present, the "type" attribute - /// is not used, and the factory method will be an instance method on - /// the object returned from a - /// - /// call with the specified object name. The factory object may be - /// defined as a singleton or a prototype. - ///

- ///

- /// The factory method can have any number of arguments. Use indexed - /// constructor-arg elements in conjunction with the factory-method - /// attribute. - ///

- ///

- /// Setter Injection can be used in conjunction with a factory method. - /// Method Injection cannot, as the factory method returns an instance, - /// which will be used when the container creates the object. - ///

- ///
- public const string FactoryMethodAttribute = "factory-method"; - - /// - /// A list can contain multiple inner object, ref, collection, or - /// value elements. - /// - /// - ///

- /// Lists are untyped, pending generics support, although references - /// will be strongly typed. - ///

- ///

- /// A list can also map to an array type. The necessary conversion is - /// automatically performed by the - /// . - ///

- ///
- public const string ListElement = "list"; - - /// - /// A set can contain multiple inner object, ref, collection, or value - /// elements. - /// - /// - ///

- /// Sets are untyped, pending generics support, although references - /// will be strongly typed. - ///

- ///
- public const string SetElement = "set"; - - /// - /// A Spring.NET map is a mapping from a string key to object (a .NET - /// ). - /// - /// - ///

- /// Dictionaries may be empty. - ///

- ///
- public const string DictionaryElement = "dictionary"; - - /// - /// A lookup key (for a dictionary or name / value collection). - /// - public const string KeyAttribute = "key"; - - /// - /// A lookup key (for a dictionary or name / value collection). - /// - public const string KeyElement = "key"; - - /// - /// Contains a string representation of a value. - /// - /// - ///

- /// This is used by name-value, ctor argument, and property elements. - ///

- ///
- public const string ValueAttribute = "value"; - - /// - /// Contains delimiters that should be used to split delimited string values. - /// - /// - ///

- /// This is used by name-value element. - ///

- ///
- public const string DelimitersAttribute = "delimiters"; - - /// - /// A reference to another objects. - /// - /// - ///

- /// Used as a convenience shortcut on property and constructor-arg - /// elements to refer to other objects. - ///

- ///
- public const string RefAttribute = "ref"; - - /// - /// Contains a string representation of an expression. - /// - /// - ///

- /// This is used by ctor argument and property elements. - ///

- ///
- public const string ExpressionAttribute = "expression"; - - /// - /// A map entry can be an inner object, ref, collection, or value. - /// - /// - ///

- /// The name of the property is given by the "key" attribute. - ///

- ///
- public const string EntryElement = "entry"; - - /// - /// Contains a string representation of a property value. - /// - /// - ///

- /// The property may be a string, or may be converted to the - /// required using the - /// - /// machinery. This makes it possible for application developers to - /// write custom - /// implementations that can convert strings to objects. - ///

- /// - /// This is recommended for simple objects only. Configure more complex - /// objects by setting properties to references to other objects. - /// - ///
- public const string ValueElement = "value"; - - /// - /// Contains a string representation of an expression. - /// - public const string ExpressionElement = "expression"; - - /// - /// Denotes value. - /// - /// - ///

- /// Necessary because an empty "value" tag will resolve to an empty - /// , which will not be resolved to - /// value unless a special - /// does so. - ///

- ///
- public const string NullElement = "null"; - - /// - /// 'name-values' elements differ from dictionary elements in that - /// values must be strings. - /// - /// - ///

- /// May be empty. - ///

- ///
- public const string NameValuesElement = "name-values"; - - /// - /// Element content is the string value of the property. - /// - /// - ///

- /// The "key" attribute is the name of the property. - ///

- ///
- public const string AddElement = "add"; - - /// - /// The lazy initialization mode for an individual object definition. - /// - public const string LazyInitAttribute = "lazy-init"; - - /// - /// The dependency checking mode for an individual object definition. - /// - public const string DependencyCheckAttribute = "dependency-check"; - - /// - /// Defines a subscription to one or more events published by one or - /// more event sources. - /// - public const string ListenerElement = "listener"; - - /// - /// The name of an event handling method. - /// - /// - ///

- /// Defaults to On${event}. - /// Note : this default will probably change before the first 1.0 - /// release. - ///

- ///
- public const string ListenerMethodAttribute = "method"; - - /// - /// The name of an event. - /// - public const string ListenerEventAttribute = "event"; - - /// - /// The autowiring mode for an individual object definition. - /// - public const string AutowireAttribute = "autowire"; - - /// - /// The autowiring mode for an individual object definition. - /// - public const string AutowireCandidateAttribute = "autowire-candidate"; - - /// - /// Attribute element to farther deifne the qualifier of an object - /// - public const string AttributeElement = "attribute"; - - /// - /// The primary object for autwired injection - /// - public const string PrimaryAttribute = "primary"; - - /// - /// Shortcut alternative to specifying a key element in a - /// dictionary entry element with <ref object="..."/>. - /// - public const string DictionaryKeyRefShortcutAttribute = "key-ref"; - - /// - /// Shortcut alternative to specifying a value element in a - /// dictionary entry element with <ref object="..."/>. - /// - public const string DictionaryValueRefShortcutAttribute = "value-ref"; - - /// - /// Specify if the collection values should be merged with the parent. - /// - public const string MergeAttribute = "merge"; - - /// - /// Defined meta attributes to be used for Autowire objects - /// - public const string MetaElement = "meta"; - - /// - /// The string of characters that delimit object names. - /// - public const string ObjectNameDelimiters = ",; "; - - /// - /// A lookup method causes the IoC container to override a given method and return - /// the object with the name given in the attendant object attribute. - /// - /// - ///

- /// This is a form of Method Injection. - ///

- ///

- /// It's particularly useful as an alternative to implementing the - /// interface, - /// in order to be able to make - /// - /// calls for non-singleton instances at runtime. In this case, Method Injection - /// is a less invasive alternative. - ///

- ///
- public const string LookupMethodElement = "lookup-method"; - - /// - /// The name of a lookup method. This method must take no arguments. - /// - public const string LookupMethodNameAttribute = "name"; - - /// - /// The name of the object in the IoC container that the lookup method - /// must resolve to. - /// - /// - ///

- /// Often this object will be a prototype, in which case the lookup method - /// will return a distinct instance on every invocation. This is useful - /// for single-threaded objects. - ///

- ///
- public const string LookupMethodObjectNameAttribute = "object"; - - /// - /// A replaced method causes the IoC container to override a given method - /// with an (arbitrary) implementation at runtime. - /// - /// - ///

- /// This (again) is a form of Method Injection. - ///

- ///
- public const string ReplacedMethodElement = "replaced-method"; - - /// - /// Name of the method whose implementation should be replaced by the - /// IoC container. - /// - /// - ///

- /// If this method is not overloaded, there's no need to use arg-type - /// subelements. - ///

- ///

- /// If this method is overloaded, arg-type subelements must be - /// used for all override definitions for the method. - ///

- ///
- public const string ReplacedMethodNameAttribute = "name"; - - /// - /// The object name of an implementation of the - /// interface. - /// - /// - ///

- /// This may be a singleton or prototype. If it's a prototype, a new - /// instance will be used for each method replacement. Singleton usage - /// is the norm. - ///

- ///
- public const string ReplacedMethodReplacerNameAttribute = "replacer"; - - /// - /// Subelement of replaced-method identifying an argument for a - /// replaced method in the event of method overloading. - /// - /// - public const string ReplacedMethodArgumentTypeElement = "arg-type"; - - /// - /// Specification of the of an overloaded method - /// argument as a . - /// - /// - ///

- /// For convenience, this may be a substring of the FQN. E.g. all the following would match - /// : - ///

- ///

- /// - /// - /// System.String - /// - /// - /// string - /// - /// - /// str - /// - /// - ///

- ///
- /// - public const string ReplacedMethodArgumentTypeMatchAttribute = "match"; - - /// - /// Check everything. - /// - public static readonly string DependencyCheckAllAttributeValue - = Enum.GetName(typeof (DependencyCheckingMode), DependencyCheckingMode.All); - - /// - /// Just check primitive (string, int, etc) values. - /// - public static readonly string DependencyCheckSimpleAttributeValue - = Enum.GetName(typeof (DependencyCheckingMode), DependencyCheckingMode.Simple); - - /// - /// Check object references. - /// - public static readonly string DependencyCheckObjectsAttributeValue - = Enum.GetName(typeof (DependencyCheckingMode), DependencyCheckingMode.Objects); - - /// - /// Autowire by name. - /// - public static readonly string AutowireByNameValue - = Enum.GetName(typeof (AutoWiringMode), AutoWiringMode.ByName); - - /// - /// Autowire by . - /// - public static readonly string AutowireByTypeValue - = Enum.GetName(typeof (AutoWiringMode), AutoWiringMode.ByType); - - /// - /// Autowiring by constructor. - /// - public static readonly string AutowireConstructorValue - = Enum.GetName(typeof (AutoWiringMode), AutoWiringMode.Constructor); - - /// - /// The autowiring strategy is to be determined by introspection - /// of the object's . - /// - public static readonly string AutowireAutoDetectValue - = Enum.GetName(typeof (AutoWiringMode), AutoWiringMode.AutoDetect); - - #region Constructor (s) / Destructor - - // CLOVER:OFF - - /// - /// Creates a new instance of the - /// - /// class. - /// - /// - ///

- /// This is a utility class, and as such has no publicly visible - /// constructors. - ///

- ///
- private ObjectDefinitionConstants() - { - } - - // CLOVER:ON - - #endregion - } + /// + /// Value of a boolean attribute that represents + /// . + /// + /// + ///

+ /// Anything else represents . + ///

+ ///
+ public const string TrueValue = "true"; + + /// + /// Value of a boolean attribute that represents + /// . + /// + public const string FalseValue = "false"; + + /// + /// Signifies that a default value is to be applied. + /// + public const string DefaultValue = "default"; + + /// + /// Defines an external XML object definition resource. + /// + public const string ImportElement = "import"; + + /// + /// Specifies the relative path to an external XML object definition + /// resource. + /// + public const string ImportResourceAttribute = "resource"; + + /// + /// Defines an alias for an object definition. + /// + public const string AliasElement = "alias"; + + /// + /// Specifies the alias of an object definition. + /// + public const string AliasAttribute = "alias"; + + /// + /// Specifies the default lazy initialization mode. + /// + public const string DefaultLazyInitAttribute = "default-lazy-init"; + + /// + /// Specifies the default dependency checking mode. + /// + public const string DefaultDependencyCheckAttribute + = "default-dependency-check"; + + /// + /// Specifies the default autowire mode. + /// + public const string DefaultAutowireAttribute = "default-autowire"; + + /// + /// Specifies the default autowire candidates. + /// + public const string DefaultAutowireCandidatesAttribute = "default-autowire-candidates"; + + /// + /// Specifies the default collection merge mode. + /// + public const string DefaultMergeAttribute = "default-merge"; + + /// + /// Specifies the default init method. + /// + public const string DefaultInitMethodAttribute = "default-init-method"; + + /// + /// Specifies the default destroy method. + /// + public const string DefaultDestroyMethodAttribute = "default-destroy-method"; + + /// + /// Defines a single named object. + /// + public const string ObjectElement = "object"; + + /// + /// Element containing informative text describing the purpose of the + /// enclosing element. + /// + /// + ///

+ /// Always optional. + ///

+ ///

+ /// Used primarily for user documentation of XML object definition + /// documents. + ///

+ ///
+ public const string DescriptionElement = "description"; + + /// + /// Specifies a . + /// + /// + ///

+ /// Does not have to be fully assembly qualified, but it is recommended + /// that the names of one's objects are + /// specified explicitly. + ///

+ ///
+ public const string TypeAttribute = "type"; + + /// + /// The name or alias of the parent object definition that a child + /// object definition inherits from. + /// + public const string ParentAttribute = "parent"; + + /// + /// Objects can be identified by an id, to enable reference checking. + /// + /// + ///

+ /// There are constraints on a valid XML id: if you want to reference + /// your object in .NET code using a name that's illegal as an XML id, + /// use the optional "name" attribute + /// (). + /// If neither given, the objects name is + /// used as id. + ///

+ ///
+ public const string IdAttribute = "id"; + + /// + /// Can be used to create one or more aliases illegal in an id. + /// + /// + ///

+ /// Multiple aliases can be separated by any number of spaces, + /// semicolons, or commas + /// (). + ///

+ ///

+ /// Always optional. + ///

+ ///
+ public const string NameAttribute = "name"; + + /// + /// Is this object a "singleton" (one shared instance, which will + /// be returned by all calls to + /// with the id), or a + /// "prototype" (independent instance resulting from each call to + /// ). + /// + /// + ///

+ /// Singletons are most commonly used, and are ideal for multi-threaded + /// service objects. + ///

+ ///
+ /// + public const string SingletonAttribute = "singleton"; + + /// + /// Controls object scope. Only applicable to ASP.NET web applications. + /// + /// + ///

+ /// Scope can be defined as either application, session or request. It + /// defines when "singleton" instances are initialized, but has no + /// effect on prototype definitions. + ///

+ ///
+ public const string ScopeAttribute = "scope"; + + /// + /// The names of the objects that this object depends on being + /// initialized. + /// + /// + ///

+ /// The object factory will guarantee that these objects + /// get initialized before this object definition. + ///

+ /// + /// Dependencies are normally expressed through object properties or + /// constructor arguments. This property should just be necessary for + /// other kinds of dependencies such as statics (*ugh*) or database + /// preparation on startup. + /// + ///
+ public const string DependsOnAttribute = "depends-on"; + + /// + /// Optional attribute for the name of the custom initialization method + /// to invoke after setting object properties. + /// + /// + ///

+ /// The method must have no arguments. + ///

+ ///
+ public const string InitMethodAttribute = "init-method"; + + /// + /// Optional attribute for the name of the custom destroy method to + /// invoke on object factory shutdown. + /// + /// + ///

+ /// Valid destroy methods have either of the following signatures... + /// + /// void MethodName() + /// void MethodName(bool force) + /// + ///

+ /// + /// Only invoked on singleton objects! + /// + ///
+ public const string DestroyMethodAttribute = "destroy-method"; + + /// + /// A constructor argument : the constructor-arg tag can have an + /// optional type attribute, to specify the exact type of the + /// constructor argument + /// + /// + ///

+ /// Only needed to avoid ambiguities, e.g. in case of 2 single + /// argument constructors that can both be converted from a + /// . + ///

+ ///
+ public const string ConstructorArgElement = "constructor-arg"; + + /// + /// The constructor-arg tag can have an optional index attribute, + /// to specify the exact index in the constructor argument list. + /// + /// + ///

+ /// Only needed to avoid ambiguities, e.g. in case of 2 arguments of + /// the same type. + ///

+ ///
+ public const string IndexAttribute = "index"; + + /// + /// The constructor-arg tag can have an optional named parameter + /// attribute, to specify a named parameter in the constructor + /// argument list. + /// + public const string ArgumentNameAttribute = "name"; + + /// + /// Is this object "abstract", i.e. not meant to be instantiated itself + /// but rather just serving as parent for concrete child object + /// definitions? + /// + /// + ///

+ /// Default is . Specify + /// to tell the object factory to not try to instantiate that + /// particular object in any case. + ///

+ ///
+ public const string AbstractAttribute = "abstract"; + + /// + /// A property definition : object definitions can have zero or more + /// properties. + /// + /// + ///

+ /// Spring.NET supports primitives, references to other objects in the + /// same or related factories, lists, dictionaries, and name value + /// collections. + ///

+ ///
+ public const string PropertyElement = "property"; + + /// + /// A qualifier definition used for fine grained autowiring + /// + public const string QualifierElement = "qualifier"; + + /// + /// A reference to another managed object or static + /// . + /// + public const string RefElement = "ref"; + + /// + /// ID refs must specify a name of the target object. + /// + public const string IdRefElement = "idref"; + + /// + /// A reference to the name of another managed object in the same + /// context. + /// + public const string ObjectRefAttribute = "object"; + + /// + /// A reference to the name of another managed object in the same + /// context. + /// + /// + ///

+ /// Local references, using the "local" attribute, have to use object + /// ids; they can be checked by a parser, thus should be preferred for + /// references within the same object factory XML file. + ///

+ ///
+ public const string LocalRefAttribute = "local"; + + /// + /// Alternative to type attribute for factory-method usage. + /// + /// + ///

+ /// If this is specified, no type attribute should be used. This should + /// be set to the name of an object in the current or ancestor + /// factories that contains the relevant factory method. This allows + /// the factory itself to be configured using Dependency Injection, and + /// an instance (rather than static) method to be used. + ///

+ ///
+ public const string FactoryObjectAttribute = "factory-object"; + + /// + /// Optional attribute specifying the name of a factory method to use + /// to create this object. + /// + /// + ///

+ /// Use constructor-arg elements to specify arguments to the factory + /// method, if it takes arguments. Autowiring does not apply to + /// factory methods. + ///

+ ///

+ /// If the "type" attribute is present, the factory method will be a + /// static method on the type specified by the "type" attribute on + /// this object definition. Often this will be the same type as that + /// of the constructed object - for example, when the factory method + /// is used as an alternative to a constructor. However, it may be on + /// a different type. In that case, the created object will *not* be + /// of the type specified in the "type" attribute. This is analogous + /// to behaviour. + ///

+ ///

+ /// If the "factory-object" attribute is present, the "type" attribute + /// is not used, and the factory method will be an instance method on + /// the object returned from a + /// + /// call with the specified object name. The factory object may be + /// defined as a singleton or a prototype. + ///

+ ///

+ /// The factory method can have any number of arguments. Use indexed + /// constructor-arg elements in conjunction with the factory-method + /// attribute. + ///

+ ///

+ /// Setter Injection can be used in conjunction with a factory method. + /// Method Injection cannot, as the factory method returns an instance, + /// which will be used when the container creates the object. + ///

+ ///
+ public const string FactoryMethodAttribute = "factory-method"; + + /// + /// A list can contain multiple inner object, ref, collection, or + /// value elements. + /// + /// + ///

+ /// Lists are untyped, pending generics support, although references + /// will be strongly typed. + ///

+ ///

+ /// A list can also map to an array type. The necessary conversion is + /// automatically performed by the + /// . + ///

+ ///
+ public const string ListElement = "list"; + + /// + /// A set can contain multiple inner object, ref, collection, or value + /// elements. + /// + /// + ///

+ /// Sets are untyped, pending generics support, although references + /// will be strongly typed. + ///

+ ///
+ public const string SetElement = "set"; + + /// + /// A Spring.NET map is a mapping from a string key to object (a .NET + /// ). + /// + /// + ///

+ /// Dictionaries may be empty. + ///

+ ///
+ public const string DictionaryElement = "dictionary"; + + /// + /// A lookup key (for a dictionary or name / value collection). + /// + public const string KeyAttribute = "key"; + + /// + /// A lookup key (for a dictionary or name / value collection). + /// + public const string KeyElement = "key"; + + /// + /// Contains a string representation of a value. + /// + /// + ///

+ /// This is used by name-value, ctor argument, and property elements. + ///

+ ///
+ public const string ValueAttribute = "value"; + + /// + /// Contains delimiters that should be used to split delimited string values. + /// + /// + ///

+ /// This is used by name-value element. + ///

+ ///
+ public const string DelimitersAttribute = "delimiters"; + + /// + /// A reference to another objects. + /// + /// + ///

+ /// Used as a convenience shortcut on property and constructor-arg + /// elements to refer to other objects. + ///

+ ///
+ public const string RefAttribute = "ref"; + + /// + /// Contains a string representation of an expression. + /// + /// + ///

+ /// This is used by ctor argument and property elements. + ///

+ ///
+ public const string ExpressionAttribute = "expression"; + + /// + /// A map entry can be an inner object, ref, collection, or value. + /// + /// + ///

+ /// The name of the property is given by the "key" attribute. + ///

+ ///
+ public const string EntryElement = "entry"; + + /// + /// Contains a string representation of a property value. + /// + /// + ///

+ /// The property may be a string, or may be converted to the + /// required using the + /// + /// machinery. This makes it possible for application developers to + /// write custom + /// implementations that can convert strings to objects. + ///

+ /// + /// This is recommended for simple objects only. Configure more complex + /// objects by setting properties to references to other objects. + /// + ///
+ public const string ValueElement = "value"; + + /// + /// Contains a string representation of an expression. + /// + public const string ExpressionElement = "expression"; + + /// + /// Denotes value. + /// + /// + ///

+ /// Necessary because an empty "value" tag will resolve to an empty + /// , which will not be resolved to + /// value unless a special + /// does so. + ///

+ ///
+ public const string NullElement = "null"; + + /// + /// 'name-values' elements differ from dictionary elements in that + /// values must be strings. + /// + /// + ///

+ /// May be empty. + ///

+ ///
+ public const string NameValuesElement = "name-values"; + + /// + /// Element content is the string value of the property. + /// + /// + ///

+ /// The "key" attribute is the name of the property. + ///

+ ///
+ public const string AddElement = "add"; + + /// + /// The lazy initialization mode for an individual object definition. + /// + public const string LazyInitAttribute = "lazy-init"; + + /// + /// The dependency checking mode for an individual object definition. + /// + public const string DependencyCheckAttribute = "dependency-check"; + + /// + /// Defines a subscription to one or more events published by one or + /// more event sources. + /// + public const string ListenerElement = "listener"; + + /// + /// The name of an event handling method. + /// + /// + ///

+ /// Defaults to On${event}. + /// Note : this default will probably change before the first 1.0 + /// release. + ///

+ ///
+ public const string ListenerMethodAttribute = "method"; + + /// + /// The name of an event. + /// + public const string ListenerEventAttribute = "event"; + + /// + /// The autowiring mode for an individual object definition. + /// + public const string AutowireAttribute = "autowire"; + + /// + /// The autowiring mode for an individual object definition. + /// + public const string AutowireCandidateAttribute = "autowire-candidate"; + + /// + /// Attribute element to farther deifne the qualifier of an object + /// + public const string AttributeElement = "attribute"; + + /// + /// The primary object for autwired injection + /// + public const string PrimaryAttribute = "primary"; + + /// + /// Shortcut alternative to specifying a key element in a + /// dictionary entry element with <ref object="..."/>. + /// + public const string DictionaryKeyRefShortcutAttribute = "key-ref"; + + /// + /// Shortcut alternative to specifying a value element in a + /// dictionary entry element with <ref object="..."/>. + /// + public const string DictionaryValueRefShortcutAttribute = "value-ref"; + + /// + /// Specify if the collection values should be merged with the parent. + /// + public const string MergeAttribute = "merge"; + + /// + /// Defined meta attributes to be used for Autowire objects + /// + public const string MetaElement = "meta"; + + /// + /// The string of characters that delimit object names. + /// + public const string ObjectNameDelimiters = ",; "; + + /// + /// A lookup method causes the IoC container to override a given method and return + /// the object with the name given in the attendant object attribute. + /// + /// + ///

+ /// This is a form of Method Injection. + ///

+ ///

+ /// It's particularly useful as an alternative to implementing the + /// interface, + /// in order to be able to make + /// + /// calls for non-singleton instances at runtime. In this case, Method Injection + /// is a less invasive alternative. + ///

+ ///
+ public const string LookupMethodElement = "lookup-method"; + + /// + /// The name of a lookup method. This method must take no arguments. + /// + public const string LookupMethodNameAttribute = "name"; + + /// + /// The name of the object in the IoC container that the lookup method + /// must resolve to. + /// + /// + ///

+ /// Often this object will be a prototype, in which case the lookup method + /// will return a distinct instance on every invocation. This is useful + /// for single-threaded objects. + ///

+ ///
+ public const string LookupMethodObjectNameAttribute = "object"; + + /// + /// A replaced method causes the IoC container to override a given method + /// with an (arbitrary) implementation at runtime. + /// + /// + ///

+ /// This (again) is a form of Method Injection. + ///

+ ///
+ public const string ReplacedMethodElement = "replaced-method"; + + /// + /// Name of the method whose implementation should be replaced by the + /// IoC container. + /// + /// + ///

+ /// If this method is not overloaded, there's no need to use arg-type + /// subelements. + ///

+ ///

+ /// If this method is overloaded, arg-type subelements must be + /// used for all override definitions for the method. + ///

+ ///
+ public const string ReplacedMethodNameAttribute = "name"; + + /// + /// The object name of an implementation of the + /// interface. + /// + /// + ///

+ /// This may be a singleton or prototype. If it's a prototype, a new + /// instance will be used for each method replacement. Singleton usage + /// is the norm. + ///

+ ///
+ public const string ReplacedMethodReplacerNameAttribute = "replacer"; + + /// + /// Subelement of replaced-method identifying an argument for a + /// replaced method in the event of method overloading. + /// + /// + public const string ReplacedMethodArgumentTypeElement = "arg-type"; + + /// + /// Specification of the of an overloaded method + /// argument as a . + /// + /// + ///

+ /// For convenience, this may be a substring of the FQN. E.g. all the following would match + /// : + ///

+ ///

+ /// + /// + /// System.String + /// + /// + /// string + /// + /// + /// str + /// + /// + ///

+ ///
+ /// + public const string ReplacedMethodArgumentTypeMatchAttribute = "match"; + + /// + /// Check everything. + /// + public static readonly string DependencyCheckAllAttributeValue + = Enum.GetName(typeof(DependencyCheckingMode), DependencyCheckingMode.All); + + /// + /// Just check primitive (string, int, etc) values. + /// + public static readonly string DependencyCheckSimpleAttributeValue + = Enum.GetName(typeof(DependencyCheckingMode), DependencyCheckingMode.Simple); + + /// + /// Check object references. + /// + public static readonly string DependencyCheckObjectsAttributeValue + = Enum.GetName(typeof(DependencyCheckingMode), DependencyCheckingMode.Objects); + + /// + /// Autowire by name. + /// + public static readonly string AutowireByNameValue + = Enum.GetName(typeof(AutoWiringMode), AutoWiringMode.ByName); + + /// + /// Autowire by . + /// + public static readonly string AutowireByTypeValue + = Enum.GetName(typeof(AutoWiringMode), AutoWiringMode.ByType); + + /// + /// Autowiring by constructor. + /// + public static readonly string AutowireConstructorValue + = Enum.GetName(typeof(AutoWiringMode), AutoWiringMode.Constructor); + + /// + /// The autowiring strategy is to be determined by introspection + /// of the object's . + /// + public static readonly string AutowireAutoDetectValue + = Enum.GetName(typeof(AutoWiringMode), AutoWiringMode.AutoDetect); + + #region Constructor (s) / Destructor + + // CLOVER:OFF + + /// + /// Creates a new instance of the + /// + /// class. + /// + /// + ///

+ /// This is a utility class, and as such has no publicly visible + /// constructors. + ///

+ ///
+ private ObjectDefinitionConstants() + { + } + + // CLOVER:ON + + #endregion } diff --git a/src/Spring/Spring.Core/Objects/Factory/Xml/ObjectDefinitionParserHelper.cs b/src/Spring/Spring.Core/Objects/Factory/Xml/ObjectDefinitionParserHelper.cs index a68471b2..e7de4044 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Xml/ObjectDefinitionParserHelper.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Xml/ObjectDefinitionParserHelper.cs @@ -25,550 +25,553 @@ using Spring.Objects.Factory.Config; using Spring.Objects.Factory.Support; using Spring.Util; -namespace Spring.Objects.Factory.Xml +namespace Spring.Objects.Factory.Xml; + +/// +/// Stateful class used to parse XML object definitions. +/// +/// Not all parsing code has been refactored into this class. See +/// BeanDefinitionParserDelegate in Java for how this class should evolve. +/// Rob Harrop +/// Juergen Hoeller +/// Rod Johnson +/// Mark Pollack (.NET) +public class ObjectDefinitionParserHelper { + #region Fields + /// - /// Stateful class used to parse XML object definitions. + /// The shared instance for this class (and derived classes). /// - /// Not all parsing code has been refactored into this class. See - /// BeanDefinitionParserDelegate in Java for how this class should evolve. - /// Rob Harrop - /// Juergen Hoeller - /// Rod Johnson - /// Mark Pollack (.NET) - public class ObjectDefinitionParserHelper + protected readonly ILogger log; + + private DocumentDefaultsDefinition defaults; + + private readonly XmlReaderContext readerContext; + + private readonly ObjectsNamespaceParser objectsNamespaceParser; + + private readonly HashSet usedNames = new HashSet(); + + #endregion + + /// + /// Initializes a new instance of the class. + /// + /// The reader context. + public ObjectDefinitionParserHelper(XmlReaderContext readerContext) + : this(readerContext, null) { - #region Fields + } - /// - /// The shared instance for this class (and derived classes). - /// - protected readonly ILogger log; + /// + /// Initializes a new instance of the class. + /// + /// The reader context. + /// The root element of the definition document to parse + public ObjectDefinitionParserHelper(XmlReaderContext readerContext, XmlElement root) + { + log = LogManager.GetLogger(this.GetType()); + this.readerContext = readerContext; + this.objectsNamespaceParser = (ObjectsNamespaceParser) readerContext.NamespaceParserResolver.Resolve(ObjectsNamespaceParser.Namespace); + if (root != null) + { + InitDefaults(root); + } + } - private DocumentDefaultsDefinition defaults; + /// + /// Gets the defaults definition object, or null if the + /// default have not yet been initialized. + /// + /// The defaults. + public DocumentDefaultsDefinition Defaults + { + get { return defaults; } + } - private readonly XmlReaderContext readerContext; + /// + /// Gets the reader context. + /// + /// The reader context. + public XmlReaderContext ReaderContext + { + get { return readerContext; } + } - private readonly ObjectsNamespaceParser objectsNamespaceParser; + /// + /// Initialize the default lazy-init, dependency check, and autowire settings. + /// + /// The root element + public void InitDefaults(XmlElement root) + { + DocumentDefaultsDefinition ddd = new DocumentDefaultsDefinition(); - private readonly HashSet usedNames = new HashSet(); + #region Instrumentation + + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug("Loading object definitions..."); + } #endregion - /// - /// Initializes a new instance of the class. - /// - /// The reader context. - public ObjectDefinitionParserHelper(XmlReaderContext readerContext) - :this(readerContext, null) - {} + ddd.LazyInit = GetAttributeValue(root, ObjectDefinitionConstants.DefaultLazyInitAttribute); - /// - /// Initializes a new instance of the class. - /// - /// The reader context. - /// The root element of the definition document to parse - public ObjectDefinitionParserHelper(XmlReaderContext readerContext, XmlElement root) + #region Instrumentation + + if (log.IsEnabled(LogLevel.Debug)) { - log = LogManager.GetLogger(this.GetType()); - this.readerContext = readerContext; - this.objectsNamespaceParser = (ObjectsNamespaceParser) readerContext.NamespaceParserResolver.Resolve(ObjectsNamespaceParser.Namespace); - if (root != null) + log.LogDebug(string.Format( + "Default lazy init '{0}'.", + ddd.LazyInit)); + } + + #endregion + + ddd.DependencyCheck = GetAttributeValue(root, ObjectDefinitionConstants.DefaultDependencyCheckAttribute); + + #region Instrumentation + + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug(string.Format( + "Default dependency check '{0}'.", + ddd.DependencyCheck)); + } + + #endregion + + ddd.Autowire = GetAttributeValue(root, ObjectDefinitionConstants.DefaultAutowireAttribute); + + #region Instrumentation + + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug(string.Format( + "Default autowire '{0}'.", + ddd.Autowire)); + } + + #endregion + + ddd.Merge = GetAttributeValue(root, ObjectDefinitionConstants.DefaultMergeAttribute); + + #region Instrumentation + + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug(string.Format( + "Default merge '{0}'.", + ddd.Merge)); + } + + #endregion + + ddd.AutowireCandidates = GetAttributeValue(root, ObjectDefinitionConstants.DefaultAutowireCandidatesAttribute); + + #region Instrumentation + + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug(string.Format( + "Default init method '{0}'.", + ddd.InitMethod)); + } + + #endregion + + ddd.DestroyMethod = GetAttributeValue(root, ObjectDefinitionConstants.DefaultDestroyMethodAttribute); + + #region Instrumentation + + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug(string.Format( + "Default destroy method '{0}'.", + ddd.DestroyMethod)); + } + + #endregion + + ddd.AutowireCandidates = GetAttributeValue(root, ObjectDefinitionConstants.DefaultAutowireCandidatesAttribute); + + #region Instrumentation + + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug(string.Format( + "Default autowire candidates '{0}'.", + ddd.AutowireCandidates)); + } + + #endregion + + ddd.InitMethod = GetAttributeValue(root, ObjectDefinitionConstants.DefaultInitMethodAttribute); + + #region Instrumentation + + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug(string.Format( + "Default init method '{0}'.", + ddd.InitMethod)); + } + + #endregion + + ddd.DestroyMethod = GetAttributeValue(root, ObjectDefinitionConstants.DefaultDestroyMethodAttribute); + + #region Instrumentation + + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug(string.Format( + "Default destroy method '{0}'.", + ddd.DestroyMethod)); + } + + #endregion + + defaults = ddd; + } + + /// + /// Determines whether the Spring object namespace is equal to the the specified namespace URI. + /// + /// The namespace URI. + /// + /// true if is the default Spring namespace; otherwise, false. + /// + public bool IsDefaultNamespace(string namespaceUri) + { + return + (!StringUtils.HasLength(namespaceUri) || ObjectsNamespaceParser.Namespace.Equals(namespaceUri)); + } + + /// + /// Decorates the object definition if required. + /// + /// The element. + /// The holder. + /// + public ObjectDefinitionHolder DecorateObjectDefinitionIfRequired(XmlElement element, ObjectDefinitionHolder holder) + { + //TODO decoration processing. + return holder; + } + + /// + /// Parse a standard object definition into a + /// , + /// including object name and aliases. + /// + /// The element containing the object definition. + /// + /// The parsed object definition wrapped within an + /// + /// instance. + /// + /// + /// + /// Object elements specify their canonical name via the "id" attribute + /// and their aliases as a delimited "name" attribute. + /// + /// + /// If no "id" is specified, uses the first name in the "name" attribute + /// as the canonical name, registering all others as aliases. + /// + /// + public ObjectDefinitionHolder ParseObjectDefinitionElement(XmlElement element) + { + return ParseObjectDefinitionElement(element, null); + } + + /// + /// Parse a standard object definition into a + /// , + /// including object name and aliases. + /// + /// The element containing the object definition. + /// The containing object definition if is a nested element. + /// + /// The parsed object definition wrapped within an + /// + /// instance. + /// + /// + /// + /// Object elements specify their canonical name via the "id" attribute + /// and their aliases as a delimited "name" attribute. + /// + /// + /// If no "id" is specified, uses the first name in the "name" attribute + /// as the canonical name, registering all others as aliases. + /// + /// + public ObjectDefinitionHolder ParseObjectDefinitionElement(XmlElement element, IObjectDefinition containingDefinition) + { + string id = GetAttributeValue(element, ObjectDefinitionConstants.IdAttribute); + string nameAttr = GetAttributeValue(element, ObjectDefinitionConstants.NameAttribute); + List aliases = new List(); + if (StringUtils.HasText(nameAttr)) + { + aliases.AddRange(GetObjectNames(nameAttr)); + } + + // if we ain't got an id, check if object is page definition or assign any existing (first) alias... + string objectName = id; + if (StringUtils.IsNullOrEmpty(objectName)) + { + if (aliases.Count > 0) { - InitDefaults(root); + objectName = aliases[0]; + aliases.RemoveAt(0); + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug(string.Format("No XML 'id' specified using '{0}' as object name and '{1}' as aliases", objectName, string.Join(",", aliases.ToArray()))); + } } } - /// - /// Gets the defaults definition object, or null if the - /// default have not yet been initialized. - /// - /// The defaults. - public DocumentDefaultsDefinition Defaults + objectName = PostProcessObjectNameAndAliases(objectName, aliases, element, containingDefinition); + + if (containingDefinition == null) { - get { return defaults; } + CheckNameUniqueness(objectName, aliases, element); } - - /// - /// Gets the reader context. - /// - /// The reader context. - public XmlReaderContext ReaderContext + ParserContext parserContext = new ParserContext(this, containingDefinition); + IConfigurableObjectDefinition definition = objectsNamespaceParser.ParseObjectDefinitionElement(element, objectName, parserContext); + if (definition != null) { - get { return readerContext; } - } - - /// - /// Initialize the default lazy-init, dependency check, and autowire settings. - /// - /// The root element - public void InitDefaults(XmlElement root) - { - DocumentDefaultsDefinition ddd = new DocumentDefaultsDefinition(); - #region Instrumentation - - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug("Loading object definitions..."); - } - - #endregion - - ddd.LazyInit = GetAttributeValue(root, ObjectDefinitionConstants.DefaultLazyInitAttribute); - - #region Instrumentation - - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug(string.Format( - "Default lazy init '{0}'.", - ddd.LazyInit)); - } - - #endregion - - ddd.DependencyCheck = GetAttributeValue(root, ObjectDefinitionConstants.DefaultDependencyCheckAttribute); - - #region Instrumentation - - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug(string.Format( - "Default dependency check '{0}'.", - ddd.DependencyCheck)); - } - - #endregion - - ddd.Autowire = GetAttributeValue(root, ObjectDefinitionConstants.DefaultAutowireAttribute); - - #region Instrumentation - - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug(string.Format( - "Default autowire '{0}'.", - ddd.Autowire)); - } - - #endregion - - ddd.Merge = GetAttributeValue(root, ObjectDefinitionConstants.DefaultMergeAttribute); - - #region Instrumentation - - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug(string.Format( - "Default merge '{0}'.", - ddd.Merge)); - } - - #endregion - - ddd.AutowireCandidates = GetAttributeValue(root, ObjectDefinitionConstants.DefaultAutowireCandidatesAttribute); - - #region Instrumentation - - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug(string.Format( - "Default init method '{0}'.", - ddd.InitMethod)); - } - - #endregion - - ddd.DestroyMethod = GetAttributeValue(root, ObjectDefinitionConstants.DefaultDestroyMethodAttribute); - - #region Instrumentation - - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug(string.Format( - "Default destroy method '{0}'.", - ddd.DestroyMethod)); - } - - #endregion - - ddd.AutowireCandidates = GetAttributeValue(root, ObjectDefinitionConstants.DefaultAutowireCandidatesAttribute); - - #region Instrumentation - - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug(string.Format( - "Default autowire candidates '{0}'.", - ddd.AutowireCandidates)); - } - - #endregion - - ddd.InitMethod = GetAttributeValue(root, ObjectDefinitionConstants.DefaultInitMethodAttribute); - - #region Instrumentation - - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug(string.Format( - "Default init method '{0}'.", - ddd.InitMethod)); - } - - #endregion - - ddd.DestroyMethod = GetAttributeValue(root, ObjectDefinitionConstants.DefaultDestroyMethodAttribute); - - #region Instrumentation - - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug(string.Format( - "Default destroy method '{0}'.", - ddd.DestroyMethod)); - } - - #endregion - - - defaults = ddd; - } - - - /// - /// Determines whether the Spring object namespace is equal to the the specified namespace URI. - /// - /// The namespace URI. - /// - /// true if is the default Spring namespace; otherwise, false. - /// - public bool IsDefaultNamespace(string namespaceUri) - { - return - (!StringUtils.HasLength(namespaceUri) || ObjectsNamespaceParser.Namespace.Equals(namespaceUri)); - } - - - /// - /// Decorates the object definition if required. - /// - /// The element. - /// The holder. - /// - public ObjectDefinitionHolder DecorateObjectDefinitionIfRequired(XmlElement element, ObjectDefinitionHolder holder) - { - - //TODO decoration processing. - return holder; - } - - /// - /// Parse a standard object definition into a - /// , - /// including object name and aliases. - /// - /// The element containing the object definition. - /// - /// The parsed object definition wrapped within an - /// - /// instance. - /// - /// - /// - /// Object elements specify their canonical name via the "id" attribute - /// and their aliases as a delimited "name" attribute. - /// - /// - /// If no "id" is specified, uses the first name in the "name" attribute - /// as the canonical name, registering all others as aliases. - /// - /// - public ObjectDefinitionHolder ParseObjectDefinitionElement(XmlElement element) - { - return ParseObjectDefinitionElement(element, null); - } - - /// - /// Parse a standard object definition into a - /// , - /// including object name and aliases. - /// - /// The element containing the object definition. - /// The containing object definition if is a nested element. - /// - /// The parsed object definition wrapped within an - /// - /// instance. - /// - /// - /// - /// Object elements specify their canonical name via the "id" attribute - /// and their aliases as a delimited "name" attribute. - /// - /// - /// If no "id" is specified, uses the first name in the "name" attribute - /// as the canonical name, registering all others as aliases. - /// - /// - public ObjectDefinitionHolder ParseObjectDefinitionElement(XmlElement element, IObjectDefinition containingDefinition) - { - string id = GetAttributeValue(element, ObjectDefinitionConstants.IdAttribute); - string nameAttr = GetAttributeValue(element, ObjectDefinitionConstants.NameAttribute); - List aliases = new List(); - if (StringUtils.HasText(nameAttr)) - { - aliases.AddRange(GetObjectNames(nameAttr)); - } - - // if we ain't got an id, check if object is page definition or assign any existing (first) alias... - string objectName = id; if (StringUtils.IsNullOrEmpty(objectName)) { - if (aliases.Count > 0) + if (containingDefinition != null) { - objectName = aliases[0]; - aliases.RemoveAt(0); - if (log.IsEnabled(LogLevel.Debug)) + objectName = + ObjectDefinitionReaderUtils.GenerateObjectName(definition, readerContext.Registry, true); + } + else + { + objectName = readerContext.GenerateObjectName(definition); + // Register an alias for the plain object type name, if possible. + string objectTypeName = definition.ObjectTypeName; + if (objectTypeName != null + && objectName.StartsWith(objectTypeName) + && objectName.Length > objectTypeName.Length + && !readerContext.Registry.IsObjectNameInUse(objectTypeName)) { - log.LogDebug(string.Format("No XML 'id' specified using '{0}' as object name and '{1}' as aliases", objectName, string.Join(",", aliases.ToArray()))); + aliases.Add(objectTypeName); } } - } - objectName = PostProcessObjectNameAndAliases(objectName, aliases, element, containingDefinition); + #region Instrumentation - if (containingDefinition == null) - { - CheckNameUniqueness(objectName, aliases, element); - } - - ParserContext parserContext = new ParserContext(this, containingDefinition); - IConfigurableObjectDefinition definition = objectsNamespaceParser.ParseObjectDefinitionElement(element, objectName, parserContext); - if (definition != null) - { - if (StringUtils.IsNullOrEmpty(objectName)) + if (log.IsEnabled(LogLevel.Debug)) { - if (containingDefinition != null) - { - objectName = - ObjectDefinitionReaderUtils.GenerateObjectName(definition, readerContext.Registry, true); - } - else - { - objectName = readerContext.GenerateObjectName(definition); - // Register an alias for the plain object type name, if possible. - string objectTypeName = definition.ObjectTypeName; - if (objectTypeName != null - && objectName.StartsWith(objectTypeName) - && objectName.Length>objectTypeName.Length - && !readerContext.Registry.IsObjectNameInUse(objectTypeName)) - { - aliases.Add(objectTypeName); - } - } - - #region Instrumentation - - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug(string.Format( - "Neither XML '{0}' nor '{1}' specified - using generated object name [{2}]", - ObjectDefinitionConstants.IdAttribute, ObjectDefinitionConstants.NameAttribute, objectName)); - } - - #endregion + log.LogDebug(string.Format( + "Neither XML '{0}' nor '{1}' specified - using generated object name [{2}]", + ObjectDefinitionConstants.IdAttribute, ObjectDefinitionConstants.NameAttribute, objectName)); } - return CreateObjectDefinitionHolder(element, definition, objectName, aliases); + #endregion } - return null; + + return CreateObjectDefinitionHolder(element, definition, objectName, aliases); } - /// - /// Create an instance from the given and . - /// - /// - /// This method may be used as a last resort to post-process an object definition before it gets added to the registry. - /// - protected virtual ObjectDefinitionHolder CreateObjectDefinitionHolder( - XmlElement element, - IConfigurableObjectDefinition definition, - string objectName, - IReadOnlyList aliases) - { - return new ObjectDefinitionHolder(definition, objectName, aliases); - } + return null; + } - /// - /// Allows deriving classes to post process the name and aliases for the current element. By default - /// does nothing and returns the unmodified . - /// - /// - /// The list passed in may be modified by an implementation of this method to reflect special needs. - /// - /// the object name obtained by the default algorithm from 'id' and 'name' attributes so far. - /// the object aliases obtained by the default algorithm from 'name' attribute so far. - /// the currently processed element. - /// the containing object definition, may be null - /// the new object name to be used. - protected virtual string PostProcessObjectNameAndAliases(string objectName, List aliases, XmlElement element, IObjectDefinition containingDefinition) + /// + /// Create an instance from the given and . + /// + /// + /// This method may be used as a last resort to post-process an object definition before it gets added to the registry. + /// + protected virtual ObjectDefinitionHolder CreateObjectDefinitionHolder( + XmlElement element, + IConfigurableObjectDefinition definition, + string objectName, + IReadOnlyList aliases) + { + return new ObjectDefinitionHolder(definition, objectName, aliases); + } + + /// + /// Allows deriving classes to post process the name and aliases for the current element. By default + /// does nothing and returns the unmodified . + /// + /// + /// The list passed in may be modified by an implementation of this method to reflect special needs. + /// + /// the object name obtained by the default algorithm from 'id' and 'name' attributes so far. + /// the object aliases obtained by the default algorithm from 'name' attribute so far. + /// the currently processed element. + /// the containing object definition, may be null + /// the new object name to be used. + protected virtual string PostProcessObjectNameAndAliases(string objectName, List aliases, XmlElement element, IObjectDefinition containingDefinition) + { + if (!StringUtils.HasText(objectName) && aliases.Count == 0) { - if (!StringUtils.HasText(objectName) && aliases.Count == 0) + string result = this.objectsNamespaceParser.CalculateId(element, aliases); + if (result != null) { - string result = this.objectsNamespaceParser.CalculateId(element, aliases); - if (result != null) - { - return result; - } - } - return objectName; - } - - /// - /// Validate that the specified object name and aliases have not been used already. - /// - protected virtual void CheckNameUniqueness(string objectName, List aliases, XmlElement element) - { - string foundName = null; - - if (StringUtils.HasText(objectName) && this.usedNames.Contains(objectName)) - { - foundName = objectName; - } - if (foundName == null) - { - foundName = (string) CollectionUtils.FindFirstMatch(this.usedNames, aliases); - } - if(foundName != null) - { - Error("Object name '" + foundName + "' is already used in this file", element); - } - - this.usedNames.Add(objectName); - foreach (string alias in aliases) - { - this.usedNames.Add(alias); + return result; } } - /// - /// Parses an element in a custom namespace. - /// - /// - /// the parsed object definition or null if not supported by the corresponding parser. - public IObjectDefinition ParseCustomElement(XmlElement ele) + return objectName; + } + + /// + /// Validate that the specified object name and aliases have not been used already. + /// + protected virtual void CheckNameUniqueness(string objectName, List aliases, XmlElement element) + { + string foundName = null; + + if (StringUtils.HasText(objectName) && this.usedNames.Contains(objectName)) { - return ParseCustomElement(ele, null); + foundName = objectName; } - /// - /// Parses an element in a custom namespace. - /// - /// - /// if a nested element, the containing object definition - /// the parsed object definition or null if not supported by the corresponding parser. - public IObjectDefinition ParseCustomElement(XmlElement ele, IObjectDefinition containingDefinition) + if (foundName == null) { - String namespaceUri = ele.NamespaceURI; - INamespaceParser handler = NamespaceParserRegistry.GetParser(namespaceUri); - if (handler == null) - { - Error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele); - return null; - } - return handler.ParseElement(ele, new ParserContext(this, containingDefinition)); + foundName = (string) CollectionUtils.FindFirstMatch(this.usedNames, aliases); } - /// - /// Given a string containing delimited object names, returns - /// a string array split on the object name delimeter. - /// - /// - /// The string containing delimited object names. - /// - /// - /// A string array split on the object name delimeter. - /// - /// - private string[] GetObjectNames(string value) + if (foundName != null) { - return StringUtils.Split( - value, ObjectDefinitionConstants.ObjectNameDelimiters, true, true); + Error("Object name '" + foundName + "' is already used in this file", element); } - /// - /// Determines whether the string represents a 'true' boolean value. - /// - /// The value. - /// - /// true if is 'true' string value; otherwise, false. - /// - public bool IsTrueStringValue(string value) + this.usedNames.Add(objectName); + foreach (string alias in aliases) { - return ObjectDefinitionConstants.TrueValue.Equals(value.ToLower(CultureInfo.CurrentCulture)); - } - - /// - /// Convenience method to create a builder for a root object definition. - /// - /// Name of the object type. - /// A builder for a root object definition. - public ObjectDefinitionBuilder CreateRootObjectDefinitionBuilder(string objectTypeName) - { - return ObjectDefinitionBuilder.RootObjectDefinition(this.readerContext.ObjectDefinitionFactory, objectTypeName); - } - - /// - /// Convenience method to create a builder for a root object definition. - /// - /// Type of the object. - /// a builder for a root object definition - public ObjectDefinitionBuilder CreateRootObjectDefinitionBuilder(Type objectType) - { - return ObjectDefinitionBuilder.RootObjectDefinition(this.readerContext.ObjectDefinitionFactory, objectType); - } - - /// - /// Returns the value of the element's attribute or null, if the attribute is not specified. - /// - /// - /// This is a helper for bypassing the behavior of - /// to return if the attribute does not exist. - /// - public string GetAttributeValue(XmlElement element, string attributeName) - { - if (element.HasAttribute(attributeName)) - { - return element.GetAttribute(attributeName); - } - return null; - } - - /// - /// Returns the value of the element's attribute or , - /// if the attribute is not specified. - /// - /// - /// This is a helper for bypassing the behavior of - /// to return if the attribute does not exist. - /// - public string GetAttributeValue(XmlElement element, string attributeName, string defaultValue) - { - if (element.HasAttribute(attributeName)) - { - return element.GetAttribute(attributeName); - } - return defaultValue; - } - - /// - /// Report a parser error. - /// - protected virtual void Error(string message, XmlElement element) - { - this.ReaderContext.ReportFatalException(element, message); + this.usedNames.Add(alias); } } + + /// + /// Parses an element in a custom namespace. + /// + /// + /// the parsed object definition or null if not supported by the corresponding parser. + public IObjectDefinition ParseCustomElement(XmlElement ele) + { + return ParseCustomElement(ele, null); + } + + /// + /// Parses an element in a custom namespace. + /// + /// + /// if a nested element, the containing object definition + /// the parsed object definition or null if not supported by the corresponding parser. + public IObjectDefinition ParseCustomElement(XmlElement ele, IObjectDefinition containingDefinition) + { + String namespaceUri = ele.NamespaceURI; + INamespaceParser handler = NamespaceParserRegistry.GetParser(namespaceUri); + if (handler == null) + { + Error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele); + return null; + } + + return handler.ParseElement(ele, new ParserContext(this, containingDefinition)); + } + + /// + /// Given a string containing delimited object names, returns + /// a string array split on the object name delimeter. + /// + /// + /// The string containing delimited object names. + /// + /// + /// A string array split on the object name delimeter. + /// + /// + private string[] GetObjectNames(string value) + { + return StringUtils.Split( + value, ObjectDefinitionConstants.ObjectNameDelimiters, true, true); + } + + /// + /// Determines whether the string represents a 'true' boolean value. + /// + /// The value. + /// + /// true if is 'true' string value; otherwise, false. + /// + public bool IsTrueStringValue(string value) + { + return ObjectDefinitionConstants.TrueValue.Equals(value.ToLower(CultureInfo.CurrentCulture)); + } + + /// + /// Convenience method to create a builder for a root object definition. + /// + /// Name of the object type. + /// A builder for a root object definition. + public ObjectDefinitionBuilder CreateRootObjectDefinitionBuilder(string objectTypeName) + { + return ObjectDefinitionBuilder.RootObjectDefinition(this.readerContext.ObjectDefinitionFactory, objectTypeName); + } + + /// + /// Convenience method to create a builder for a root object definition. + /// + /// Type of the object. + /// a builder for a root object definition + public ObjectDefinitionBuilder CreateRootObjectDefinitionBuilder(Type objectType) + { + return ObjectDefinitionBuilder.RootObjectDefinition(this.readerContext.ObjectDefinitionFactory, objectType); + } + + /// + /// Returns the value of the element's attribute or null, if the attribute is not specified. + /// + /// + /// This is a helper for bypassing the behavior of + /// to return if the attribute does not exist. + /// + public string GetAttributeValue(XmlElement element, string attributeName) + { + if (element.HasAttribute(attributeName)) + { + return element.GetAttribute(attributeName); + } + + return null; + } + + /// + /// Returns the value of the element's attribute or , + /// if the attribute is not specified. + /// + /// + /// This is a helper for bypassing the behavior of + /// to return if the attribute does not exist. + /// + public string GetAttributeValue(XmlElement element, string attributeName, string defaultValue) + { + if (element.HasAttribute(attributeName)) + { + return element.GetAttribute(attributeName); + } + + return defaultValue; + } + + /// + /// Report a parser error. + /// + protected virtual void Error(string message, XmlElement element) + { + this.ReaderContext.ReportFatalException(element, message); + } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Xml/ObjectFactorySectionHandler.cs b/src/Spring/Spring.Core/Objects/Factory/Xml/ObjectFactorySectionHandler.cs index 59c7f34c..5793899a 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Xml/ObjectFactorySectionHandler.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Xml/ObjectFactorySectionHandler.cs @@ -20,68 +20,67 @@ using System.Configuration; using System.Xml; - using Spring.Core.IO; -namespace Spring.Objects.Factory.Xml +namespace Spring.Objects.Factory.Xml; + +/// +/// Creates an instance +/// populated with the object definitions supplied in the configuration +/// section. +/// +/// +///

+/// Applications will typically want to use an +/// , and instantiate it +/// via the use of the +/// class (which is similar in functionality to this class). This class is +/// provided for those times when only an +/// is required. +///

+/// Creates an instance of the class XmlObjectFactory +///
+/// +///

+/// +///

+///
+/// Mark Pollack (.NET) +public class ObjectFactorySectionHandler : IConfigurationSectionHandler { /// - /// Creates an instance + /// Creates a new instance of the + /// class. + /// + public ObjectFactorySectionHandler() + { + } + + /// + /// Creates a + /// instance populated with the object definitions supplied in the + /// configuration section. + /// + /// + /// The configuration settings in a corresponding parent configuration + /// section. + /// + /// + /// The configuration context when called from the ASP.NET + /// configuration system. Otherwise, this parameter is reserved and + /// is . + /// + /// + /// The for the section. + /// + /// + /// A instance /// populated with the object definitions supplied in the configuration /// section. - ///
- /// - ///

- /// Applications will typically want to use an - /// , and instantiate it - /// via the use of the - /// class (which is similar in functionality to this class). This class is - /// provided for those times when only an - /// is required. - ///

- /// Creates an instance of the class XmlObjectFactory - ///
- /// - ///

- /// - ///

- ///
- /// Mark Pollack (.NET) - public class ObjectFactorySectionHandler : IConfigurationSectionHandler + /// + public object Create( + object parent, object configContext, XmlNode section) { - /// - /// Creates a new instance of the - /// class. - /// - public ObjectFactorySectionHandler() - {} - - /// - /// Creates a - /// instance populated with the object definitions supplied in the - /// configuration section. - /// - /// - /// The configuration settings in a corresponding parent configuration - /// section. - /// - /// - /// The configuration context when called from the ASP.NET - /// configuration system. Otherwise, this parameter is reserved and - /// is . - /// - /// - /// The for the section. - /// - /// - /// A instance - /// populated with the object definitions supplied in the configuration - /// section. - /// - public object Create( - object parent, object configContext, XmlNode section) - { - return new XmlObjectFactory(new ConfigSectionResource(section as XmlElement), true); - } + return new XmlObjectFactory(new ConfigSectionResource(section as XmlElement), true); } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Xml/ObjectsNamespaceParser.cs b/src/Spring/Spring.Core/Objects/Factory/Xml/ObjectsNamespaceParser.cs index e25eea1a..48d39d39 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Xml/ObjectsNamespaceParser.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Xml/ObjectsNamespaceParser.cs @@ -34,989 +34,1015 @@ using Spring.Util; #endregion -namespace Spring.Objects.Factory.Xml +namespace Spring.Objects.Factory.Xml; + +/// +/// Default implementation of the +/// interface. +/// +/// +///

+/// Parses object definitions according to the standard Spring.NET schema. +///

+///

+/// This schema is typically located at +/// http://www.springframework.net/xsd/spring-objects.xsd. +///

+///
+/// Rod Johnson +/// Juergen Hoeller +/// Rick Evans (.NET) +[ + NamespaceParser( + Namespace = "http://www.springframework.net", + SchemaLocationAssemblyHint = typeof(ObjectsNamespaceParser), + SchemaLocation = "/Spring.Objects.Factory.Xml/spring-objects-2.0.xsd" + ) +] +// [Obsolete("ObjectsNamespaceParser will be dropped with 2.x, use ObjectDefinitionParserHelper instead", false)] +public class ObjectsNamespaceParser : AbstractObjectDefinitionParser, INamespaceParser { /// - /// Default implementation of the - /// interface. + /// The namespace URI for the standard Spring.NET object definition schema. /// + public const string Namespace = "http://www.springframework.net"; + + /// + /// The shared instance for this class (and derived classes). + /// + protected static readonly ILogger log = LogManager.GetLogger(); + + #region IXmlObjectDefinitionParser Members + + /// + /// Invoked by after construction but before any + /// elements have been parsed. + /// + /// This is a NoOp + public void Init() + { + } + + #endregion + + /// + /// Parse the specified XmlElement and register the resulting + /// ObjectDefinitions with the IObjectDefinitionRegistry + /// embedded in the supplied + /// + /// The element to be parsed. + /// The object encapsulating the current state of the parsing process. + /// Provides access to a IObjectDefinitionRegistry + /// The primary object definition. /// - ///

- /// Parses object definitions according to the standard Spring.NET schema. - ///

- ///

- /// This schema is typically located at - /// http://www.springframework.net/xsd/spring-objects.xsd. + ///

+ /// This method is never invoked if the parser is namespace aware + /// and was called to process the root node. ///

///
- /// Rod Johnson - /// Juergen Hoeller - /// Rick Evans (.NET) - [ - NamespaceParser( - Namespace = "http://www.springframework.net", - SchemaLocationAssemblyHint = typeof(ObjectsNamespaceParser), - SchemaLocation = "/Spring.Objects.Factory.Xml/spring-objects-2.0.xsd" - ) - ] -// [Obsolete("ObjectsNamespaceParser will be dropped with 2.x, use ObjectDefinitionParserHelper instead", false)] - public class ObjectsNamespaceParser : AbstractObjectDefinitionParser, INamespaceParser - { - /// - /// The namespace URI for the standard Spring.NET object definition schema. - /// - public const string Namespace = "http://www.springframework.net"; - - /// - /// The shared instance for this class (and derived classes). - /// - protected static readonly ILogger log = LogManager.GetLogger(); - - #region IXmlObjectDefinitionParser Members - - /// - /// Invoked by after construction but before any - /// elements have been parsed. - /// - /// This is a NoOp - public void Init() - { - - } - - #endregion - - /// - /// Parse the specified XmlElement and register the resulting - /// ObjectDefinitions with the IObjectDefinitionRegistry - /// embedded in the supplied - /// - /// The element to be parsed. - /// The object encapsulating the current state of the parsing process. - /// Provides access to a IObjectDefinitionRegistry - /// The primary object definition. - /// - ///

- /// This method is never invoked if the parser is namespace aware - /// and was called to process the root node. - ///

- ///
// [Obsolete("not used anymore - ObjectsNamespaceParser will be dropped with 2.x, use ObjectDefinitionParserHelper instead", false)] - public override IObjectDefinition ParseElement(XmlElement element, ParserContext parserContext) + public override IObjectDefinition ParseElement(XmlElement element, ParserContext parserContext) + { + // TODO (EE): overridden just to stay binary compatible between 1.2.0 and 1.2.1 + return base.ParseElement(element, parserContext); + } + + /// + /// Parse the specified element and register any resulting + /// IObjectDefinitions with the IObjectDefinitionRegistry that is + /// embedded in the supplied ParserContext. + /// + /// The element to be parsed into one or more IObjectDefinitions + /// The object encapsulating the current state of the parsing + /// process. + /// + /// The primary IObjectDefinition (can be null as explained above) + /// + /// + /// Implementations should return the primary IObjectDefinition + /// that results from the parse phase if they wish to used nested + /// inside (for example) a <property> tag. + /// Implementations may return null if they will not + /// be used in a nested scenario. + /// + /// + protected override AbstractObjectDefinition ParseInternal(XmlElement element, ParserContext parserContext) + { + if (element.LocalName == ObjectDefinitionConstants.ImportElement) { - // TODO (EE): overridden just to stay binary compatible between 1.2.0 and 1.2.1 - return base.ParseElement(element, parserContext); + ImportObjectDefinitionResource(element, parserContext); } - - /// - /// Parse the specified element and register any resulting - /// IObjectDefinitions with the IObjectDefinitionRegistry that is - /// embedded in the supplied ParserContext. - /// - /// The element to be parsed into one or more IObjectDefinitions - /// The object encapsulating the current state of the parsing - /// process. - /// - /// The primary IObjectDefinition (can be null as explained above) - /// - /// - /// Implementations should return the primary IObjectDefinition - /// that results from the parse phase if they wish to used nested - /// inside (for example) a <property> tag. - /// Implementations may return null if they will not - /// be used in a nested scenario. - /// - /// - protected override AbstractObjectDefinition ParseInternal(XmlElement element, ParserContext parserContext) + else if (element.LocalName == ObjectDefinitionConstants.AliasElement) { - if (element.LocalName == ObjectDefinitionConstants.ImportElement) - { - ImportObjectDefinitionResource(element, parserContext); - } - else if (element.LocalName == ObjectDefinitionConstants.AliasElement) - { - ParseAlias(element, parserContext.ReaderContext.Registry); - } - else if (element.LocalName == ObjectDefinitionConstants.ObjectElement) - { - // atm this will call back into this ns parsers - ObjectDefinitionHolder odh = parserContext.ParserHelper.ParseObjectDefinitionElement(element); - if (odh != null) - { - return odh.ObjectDefinition as AbstractObjectDefinition; - } - } - - return null; + ParseAlias(element, parserContext.ReaderContext.Registry); } - - - /// - /// Parse the specified XmlNode and decorate the supplied ObjectDefinitionHolder, - /// returning the decorated definition. - /// - /// The XmlNode may either be an XmlAttribute or an XmlElement, depending on - /// whether a custom attribute or element is being parsed. - /// Implementations may choose to return a completely new definition, - /// which will replace the original definition in the resulting IApplicationContext/IObjectFactory. - /// - /// The supplied ParserContext can be used to register any additional objects needed to support - /// the main definition. - /// - /// The source element or attribute that is to be parsed. - /// The current object definition. - /// The object encapsulating the current state of the parsing - /// process. - /// The decorated definition (to be registered in the IApplicationContext/IObjectFactory), - /// or simply the original object definition if no decoration is required. A null value is strickly - /// speaking invalid, but will leniently treated like the case where the original object definition - /// gets returned. - [Obsolete("not used anymore - ObjectsNamespaceParser will be dropped with 2.x, use ObjectDefinitionParserHelper instead", false)] - public ObjectDefinitionHolder Decorate(XmlNode node, ObjectDefinitionHolder definition, - ParserContext parserContext) + else if (element.LocalName == ObjectDefinitionConstants.ObjectElement) { - return null; - } - - private void ParseAlias(XmlElement aliasElement, IObjectDefinitionRegistry registry) - { - string name = GetAttributeValue(aliasElement, ObjectDefinitionConstants.NameAttribute); - string alias = GetAttributeValue(aliasElement, ObjectDefinitionConstants.AliasAttribute); - registry.RegisterAlias(name, alias); - } - - /// - /// Loads external XML object definitions from the resource described by the supplied - /// . - /// - /// The XML element describing the resource. - /// The parser context. - /// - /// If the resource could not be imported. - /// - [Obsolete("not used anymore - ObjectsNamespaceParser will be dropped with 2.x, use ObjectDefinitionParserHelper instead", false)] - protected virtual void ImportObjectDefinitionResource(XmlElement resource, ParserContext parserContext) - { - string location = GetAttributeValue(resource, ObjectDefinitionConstants.ImportResourceAttribute); - try + // atm this will call back into this ns parsers + ObjectDefinitionHolder odh = parserContext.ParserHelper.ParseObjectDefinitionElement(element); + if (odh != null) { - #region Instrumentation - - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug(string.Format( - CultureInfo.InvariantCulture, - "Attempting to import object definitions from '{0}'.", location)); - } - - #endregion - - IResource importResource = parserContext.ReaderContext.Resource.CreateRelative(location); - parserContext.ReaderContext.Reader.LoadObjectDefinitions(importResource); - } - catch (IOException ex) - { - parserContext.ReaderContext.ReportException(resource, null, string.Format( - CultureInfo.InvariantCulture, - "Invalid relative resource location '{0}' to import object definitions from.", - location), ex); + return odh.ObjectDefinition as AbstractObjectDefinition; } } + return null; + } - /// Parses an event listener definition. - /// - /// The name associated with the object that the event handler is being defined on. - /// - /// The events being populated. - /// - /// The element containing the event listener definition. - /// - /// - /// The namespace-aware parser. - /// - protected virtual void ParseEventListenerDefinition( - string name, EventValues events, XmlElement element, ParserContext parserContext) + /// + /// Parse the specified XmlNode and decorate the supplied ObjectDefinitionHolder, + /// returning the decorated definition. + /// + /// The XmlNode may either be an XmlAttribute or an XmlElement, depending on + /// whether a custom attribute or element is being parsed. + /// Implementations may choose to return a completely new definition, + /// which will replace the original definition in the resulting IApplicationContext/IObjectFactory. + /// + /// The supplied ParserContext can be used to register any additional objects needed to support + /// the main definition. + /// + /// The source element or attribute that is to be parsed. + /// The current object definition. + /// The object encapsulating the current state of the parsing + /// process. + /// The decorated definition (to be registered in the IApplicationContext/IObjectFactory), + /// or simply the original object definition if no decoration is required. A null value is strickly + /// speaking invalid, but will leniently treated like the case where the original object definition + /// gets returned. + [Obsolete("not used anymore - ObjectsNamespaceParser will be dropped with 2.x, use ObjectDefinitionParserHelper instead", false)] + public ObjectDefinitionHolder Decorate(XmlNode node, ObjectDefinitionHolder definition, + ParserContext parserContext) + { + return null; + } + + private void ParseAlias(XmlElement aliasElement, IObjectDefinitionRegistry registry) + { + string name = GetAttributeValue(aliasElement, ObjectDefinitionConstants.NameAttribute); + string alias = GetAttributeValue(aliasElement, ObjectDefinitionConstants.AliasAttribute); + registry.RegisterAlias(name, alias); + } + + /// + /// Loads external XML object definitions from the resource described by the supplied + /// . + /// + /// The XML element describing the resource. + /// The parser context. + /// + /// If the resource could not be imported. + /// + [Obsolete("not used anymore - ObjectsNamespaceParser will be dropped with 2.x, use ObjectDefinitionParserHelper instead", false)] + protected virtual void ImportObjectDefinitionResource(XmlElement resource, ParserContext parserContext) + { + string location = GetAttributeValue(resource, ObjectDefinitionConstants.ImportResourceAttribute); + try { - // get an appropriate IEventHandlerValue instance based upon the - // attribute values of the listener element... - IEventHandlerValue myHandler = ObjectDefinitionReaderUtils.CreateEventHandlerValue( - GetAttributeValue(element, ObjectDefinitionConstants.ListenerMethodAttribute), - GetAttributeValue(element, ObjectDefinitionConstants.ListenerEventAttribute)); - - // and then get the source of the event (another managed object instance - // or a Type reference (i.e. a static event exposed on a class)... - XmlElement sourceElement = this.SelectSingleNode(element, ObjectDefinitionConstants.RefElement) as XmlElement; - - XmlAttribute sourceAtt = sourceElement.Attributes[0]; - if (StringUtils.IsNullOrEmpty(sourceAtt.Value)) - { - parserContext.ReaderContext.ReportFatalException(sourceElement, string.Format( - CultureInfo.InvariantCulture, - "The single attribute of the <{0}/> element cannot be empty. Specify the " + - "object id (alias) or the full, assembly qualified Type name that is the " + - "source of the event.", - ObjectDefinitionConstants.RefElement)); - return; - } - switch (sourceAtt.LocalName) - { - case ObjectDefinitionConstants.LocalRefAttribute: - case ObjectDefinitionConstants.ObjectRefAttribute: - // we're wiring up to an event exposed on another managed object (instance) - RuntimeObjectReference ror = new RuntimeObjectReference(sourceAtt.Value); - myHandler.Source = ror; - break; - case ObjectDefinitionConstants.TypeAttribute: - // we're wiring up to a static event exposed on a Type (class) - myHandler.Source = parserContext.ReaderContext.Reader.Domain == null ? - sourceAtt.Value : - TypeResolutionUtils.ResolveType(sourceAtt.Value) as object; - break; - } - events.AddHandler(myHandler); - } - - /// - /// Parse an object definition and register it with the object factory.. - /// - /// The element containing the object definition. - /// The parser context. - /// - [Obsolete("not used anymore - ObjectsNamespaceParser will be dropped with 2.x, use ObjectDefinitionParserHelper instead", false)] - protected ObjectDefinitionHolder ParseObjectDefinition(XmlElement element, ParserContext parserContext) - { - ObjectDefinitionHolder holder = null; - try - { - holder = ParseObjectDefinitionElement(element, parserContext, false); - if (holder == null) - { - return null; - } - } - catch (ObjectDefinitionStoreException) - { - throw; - } - catch (Exception ex) - { - //throw new ObjectDefinitionStoreException(string.Format("Failed parsing object definition '{0}'", element.OuterXml), ex); - parserContext.ReaderContext.ReportException(element, null, null, ex); - } - - - holder = parserContext.ParserHelper.DecorateObjectDefinitionIfRequired(element, holder); - #region Instrumentation if (log.IsEnabled(LogLevel.Debug)) { log.LogDebug(string.Format( CultureInfo.InvariantCulture, - "Registering object definition with id '{0}'.", holder.ObjectName)); + "Attempting to import object definitions from '{0}'.", location)); } #endregion - return holder; + IResource importResource = parserContext.ReaderContext.Resource.CreateRelative(location); + parserContext.ReaderContext.Reader.LoadObjectDefinitions(importResource); } - - /// - /// Parse an object definition and register it with the object factory.. - /// - /// The element containing the object definition. - /// The parser context. - /// - [Obsolete("not used anymore - ObjectsNamespaceParser will be dropped with 2.x, use ObjectDefinitionParserHelper instead", false)] - protected ObjectDefinitionHolder ParseAndRegisterObjectDefinition(XmlElement element, ParserContext parserContext) + catch (IOException ex) { - ObjectDefinitionHolder holder = ParseObjectDefinition(element, parserContext); - ObjectDefinitionReaderUtils.RegisterObjectDefinition(holder, parserContext.ReaderContext.Registry); - return holder; + parserContext.ReaderContext.ReportException(resource, null, string.Format( + CultureInfo.InvariantCulture, + "Invalid relative resource location '{0}' to import object definitions from.", + location), ex); } + } - /// - /// Parse an object definition and register it with the object factory.. - /// - /// The element containing the object definition. - /// The parser context. - /// - [Obsolete("not used anymore - ObjectsNamespaceParser will be dropped with 2.x, use ObjectDefinitionParserHelper instead", false)] - protected void RegisterObjectDefinition(XmlElement element, ParserContext parserContext) + /// Parses an event listener definition. + /// + /// The name associated with the object that the event handler is being defined on. + /// + /// The events being populated. + /// + /// The element containing the event listener definition. + /// + /// + /// The namespace-aware parser. + /// + protected virtual void ParseEventListenerDefinition( + string name, EventValues events, XmlElement element, ParserContext parserContext) + { + // get an appropriate IEventHandlerValue instance based upon the + // attribute values of the listener element... + IEventHandlerValue myHandler = ObjectDefinitionReaderUtils.CreateEventHandlerValue( + GetAttributeValue(element, ObjectDefinitionConstants.ListenerMethodAttribute), + GetAttributeValue(element, ObjectDefinitionConstants.ListenerEventAttribute)); + + // and then get the source of the event (another managed object instance + // or a Type reference (i.e. a static event exposed on a class)... + XmlElement sourceElement = this.SelectSingleNode(element, ObjectDefinitionConstants.RefElement) as XmlElement; + + XmlAttribute sourceAtt = sourceElement.Attributes[0]; + if (StringUtils.IsNullOrEmpty(sourceAtt.Value)) { - ParseAndRegisterObjectDefinition(element, parserContext); + parserContext.ReaderContext.ReportFatalException(sourceElement, string.Format( + CultureInfo.InvariantCulture, + "The single attribute of the <{0}/> element cannot be empty. Specify the " + + "object id (alias) or the full, assembly qualified Type name that is the " + + "source of the event.", + ObjectDefinitionConstants.RefElement)); + return; } - - /// - /// Parse a standard object definition into a - /// , - /// including object name and aliases. - /// - /// The element containing the object definition. - /// The parser context. - /// if set to true if we are processing an inner - /// object definition. - /// - /// The object (definition) wrapped within an - /// - /// instance. - /// - /// - ///

- /// Object elements specify their canonical name via the "id" attribute - /// and their aliases as a delimited "name" attribute. - ///

- ///

- /// If no "id" is specified, uses the first name in the "name" attribute - /// as the canonical name, registering all others as aliases. - ///

- ///
- [Obsolete("not used anymore - ObjectsNamespaceParser will be dropped with 2.x, use ObjectDefinitionParserHelper instead", false)] - protected ObjectDefinitionHolder ParseObjectDefinitionElement(XmlElement element, ParserContext parserContext, bool nestedDefinition) + switch (sourceAtt.LocalName) { - return parserContext.ParserHelper.ParseObjectDefinitionElement(element, parserContext.ContainingObjectDefinition); + case ObjectDefinitionConstants.LocalRefAttribute: + case ObjectDefinitionConstants.ObjectRefAttribute: + // we're wiring up to an event exposed on another managed object (instance) + RuntimeObjectReference ror = new RuntimeObjectReference(sourceAtt.Value); + myHandler.Source = ror; + break; + case ObjectDefinitionConstants.TypeAttribute: + // we're wiring up to a static event exposed on a Type (class) + myHandler.Source = parserContext.ReaderContext.Reader.Domain == null ? sourceAtt.Value : TypeResolutionUtils.ResolveType(sourceAtt.Value) as object; + break; } - /// - /// Calculates an id for an object definition. - /// - /// - ///

- /// Called when an object definition has not been explicitly defined - /// with an id. - ///

- ///
- /// - /// The element containing the object definition. - /// - /// - /// The list of names defined for the object; may be - /// or even empty. - /// - /// - /// A calculated object definition id. - /// - [Obsolete("This method will be dropped, override ObjectDefinitionParserHelper.PostProcessObjectNameAndAliases instead", false)] - protected internal virtual string CalculateId(XmlElement element, List aliases) + events.AddHandler(myHandler); + } + + /// + /// Parse an object definition and register it with the object factory.. + /// + /// The element containing the object definition. + /// The parser context. + /// + [Obsolete("not used anymore - ObjectsNamespaceParser will be dropped with 2.x, use ObjectDefinitionParserHelper instead", false)] + protected ObjectDefinitionHolder ParseObjectDefinition(XmlElement element, ParserContext parserContext) + { + ObjectDefinitionHolder holder = null; + try { - return null; + holder = ParseObjectDefinitionElement(element, parserContext, false); + if (holder == null) + { + return null; + } + } + catch (ObjectDefinitionStoreException) + { + throw; + } + catch (Exception ex) + { + //throw new ObjectDefinitionStoreException(string.Format("Failed parsing object definition '{0}'", element.OuterXml), ex); + parserContext.ReaderContext.ReportException(element, null, null, ex); } - /// - /// Parse a standard object definition. - /// - /// The element containing the object definition. - /// The id of the object definition. - /// parsing state holder - /// The object (definition). + holder = parserContext.ParserHelper.DecorateObjectDefinitionIfRequired(element, holder); + + #region Instrumentation + + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug(string.Format( + CultureInfo.InvariantCulture, + "Registering object definition with id '{0}'.", holder.ObjectName)); + } + + #endregion + + return holder; + } + + /// + /// Parse an object definition and register it with the object factory.. + /// + /// The element containing the object definition. + /// The parser context. + /// + [Obsolete("not used anymore - ObjectsNamespaceParser will be dropped with 2.x, use ObjectDefinitionParserHelper instead", false)] + protected ObjectDefinitionHolder ParseAndRegisterObjectDefinition(XmlElement element, ParserContext parserContext) + { + ObjectDefinitionHolder holder = ParseObjectDefinition(element, parserContext); + ObjectDefinitionReaderUtils.RegisterObjectDefinition(holder, parserContext.ReaderContext.Registry); + return holder; + } + + /// + /// Parse an object definition and register it with the object factory.. + /// + /// The element containing the object definition. + /// The parser context. + /// + [Obsolete("not used anymore - ObjectsNamespaceParser will be dropped with 2.x, use ObjectDefinitionParserHelper instead", false)] + protected void RegisterObjectDefinition(XmlElement element, ParserContext parserContext) + { + ParseAndRegisterObjectDefinition(element, parserContext); + } + + /// + /// Parse a standard object definition into a + /// , + /// including object name and aliases. + /// + /// The element containing the object definition. + /// The parser context. + /// if set to true if we are processing an inner + /// object definition. + /// + /// The object (definition) wrapped within an + /// + /// instance. + /// + /// + ///

+ /// Object elements specify their canonical name via the "id" attribute + /// and their aliases as a delimited "name" attribute. + ///

+ ///

+ /// If no "id" is specified, uses the first name in the "name" attribute + /// as the canonical name, registering all others as aliases. + ///

+ ///
+ [Obsolete("not used anymore - ObjectsNamespaceParser will be dropped with 2.x, use ObjectDefinitionParserHelper instead", false)] + protected ObjectDefinitionHolder ParseObjectDefinitionElement(XmlElement element, ParserContext parserContext, bool nestedDefinition) + { + return parserContext.ParserHelper.ParseObjectDefinitionElement(element, parserContext.ContainingObjectDefinition); + } + + /// + /// Calculates an id for an object definition. + /// + /// + ///

+ /// Called when an object definition has not been explicitly defined + /// with an id. + ///

+ ///
+ /// + /// The element containing the object definition. + /// + /// + /// The list of names defined for the object; may be + /// or even empty. + /// + /// + /// A calculated object definition id. + /// + [Obsolete("This method will be dropped, override ObjectDefinitionParserHelper.PostProcessObjectNameAndAliases instead", false)] + protected internal virtual string CalculateId(XmlElement element, List aliases) + { + return null; + } + + /// + /// Parse a standard object definition. + /// + /// The element containing the object definition. + /// The id of the object definition. + /// parsing state holder + /// The object (definition). // [Obsolete("not used anymore - ObjectsNamespaceParser will be dropped with 2.x, use ObjectDefinitionParserHelper instead", false)] - protected internal virtual IConfigurableObjectDefinition ParseObjectDefinitionElement( - XmlElement element, string id, ParserContext parserContext) + protected internal virtual IConfigurableObjectDefinition ParseObjectDefinitionElement( + XmlElement element, string id, ParserContext parserContext) + { + string typeName = null; + try { - string typeName = null; - try + if (element.HasAttribute(ObjectDefinitionConstants.TypeAttribute)) { - if (element.HasAttribute(ObjectDefinitionConstants.TypeAttribute)) - { - typeName = GetAttributeValue(element, ObjectDefinitionConstants.TypeAttribute); - if (StringUtils.IsNullOrEmpty(typeName)) - { - throw new ObjectDefinitionStoreException( - parserContext.ReaderContext.Resource, id, - "The 'type' attribute does not need to be present, but if it is it must not be empty: got '" + - typeName + "'."); - } - } - - string parent = GetAttributeValue(element, ObjectDefinitionConstants.ParentAttribute); - - - AbstractObjectDefinition od - = parserContext.ReaderContext.ObjectDefinitionFactory.CreateObjectDefinition( - typeName, parent, parserContext.ReaderContext.Reader.Domain); - - ParserContext childParserContext = new ParserContext(parserContext.ParserHelper, od); - - ParseMetaElements(element, od); - ParseQualifierElements(id, element, parserContext, od); - MutablePropertyValues pvs = ParsePropertyElements(id, element, childParserContext); - ConstructorArgumentValues arguments = ParseConstructorArgSubElements(id, element, childParserContext); - EventValues events = ParseEventHandlerSubElements(id, element, childParserContext); - MethodOverrides methodOverrides = ParseMethodOverrideSubElements(id, element, childParserContext); - - bool isPage = StringUtils.HasText(typeName) && typeName != null && typeName.ToLower().EndsWith(".aspx"); - if (!isPage) - { - od.ConstructorArgumentValues = arguments; - } - - od.PropertyValues = pvs; - od.MethodOverrides = methodOverrides; - od.EventHandlerValues = events; - if (element.HasAttribute(ObjectDefinitionConstants.DependsOnAttribute)) - { - string dependsOn = GetAttributeValue(element, ObjectDefinitionConstants.DependsOnAttribute); - od.DependsOn = GetObjectNames(dependsOn); - } - od.FactoryMethodName = GetAttributeValue(element, ObjectDefinitionConstants.FactoryMethodAttribute); - od.FactoryObjectName = GetAttributeValue(element, ObjectDefinitionConstants.FactoryObjectAttribute); - string dependencyCheck = GetAttributeValue(element, ObjectDefinitionConstants.DependencyCheckAttribute); - if (ObjectDefinitionConstants.DefaultValue.Equals(dependencyCheck)) - { - dependencyCheck = childParserContext.ParserHelper.Defaults.DependencyCheck; - } - od.DependencyCheck = GetDependencyCheck(dependencyCheck); - string autowire = GetAttributeValue(element, ObjectDefinitionConstants.AutowireAttribute); - if (ObjectDefinitionConstants.DefaultValue.Equals(autowire)) - { - autowire = childParserContext.ParserHelper.Defaults.Autowire; - } - od.AutowireMode = GetAutowireMode(autowire); - - string autowireCandidates = GetAttributeValue(element, ObjectDefinitionConstants.AutowireCandidateAttribute); - if (string.IsNullOrEmpty(autowireCandidates) || ObjectDefinitionConstants.DefaultValue.Equals(autowireCandidates)) - { - if (!string.IsNullOrEmpty(childParserContext.ParserHelper.Defaults.AutowireCandidates)) - { - string[] patterns = childParserContext.ParserHelper.Defaults.AutowireCandidates.Split(','); - od.IsAutowireCandidate = PatternMatchUtils.SimpleMatch(patterns, id); - } - } - else - { - od.IsAutowireCandidate = ObjectDefinitionConstants.TrueValue.Equals(autowireCandidates); - } - string primary = GetAttributeValue(element, ObjectDefinitionConstants.PrimaryAttribute); - if (string.IsNullOrEmpty(primary)) - { - primary = ObjectDefinitionConstants.FalseValue; - } - od.IsPrimary = IsTrueStringValue(primary); - string initMethodName = GetAttributeValue(element, ObjectDefinitionConstants.InitMethodAttribute); - if (initMethodName != null) - { - if (StringUtils.HasText(initMethodName)) - od.InitMethodName = initMethodName; - } - else - { - if (StringUtils.HasText(childParserContext.ParserHelper.Defaults.InitMethod)) - od.InitMethodName = childParserContext.ParserHelper.Defaults.InitMethod; - } - string destroyMethodName = GetAttributeValue(element, ObjectDefinitionConstants.DestroyMethodAttribute); - if (destroyMethodName != null) - { - if (StringUtils.HasText(destroyMethodName)) - { - od.DestroyMethodName = destroyMethodName; - } - } - else - { - if (StringUtils.HasText(childParserContext.ParserHelper.Defaults.DestroyMethod)) - od.DestroyMethodName = childParserContext.ParserHelper.Defaults.DestroyMethod; - } - if (element.HasAttribute(ObjectDefinitionConstants.SingletonAttribute)) - { - od.IsSingleton = IsTrueStringValue(GetAttributeValue(element, ObjectDefinitionConstants.SingletonAttribute, string.Empty).ToLower(CultureInfo.CurrentCulture)); - } - string lazyInit = GetAttributeValue(element, ObjectDefinitionConstants.LazyInitAttribute); - if (ObjectDefinitionConstants.DefaultValue.Equals(lazyInit) && od.IsSingleton) - { - // just apply default to singletons, as lazy-init has no meaning for prototypes... - lazyInit = childParserContext.ParserHelper.Defaults.LazyInit; - } - od.IsLazyInit = IsTrueStringValue(lazyInit); - - // try to get the line info - string resourceDescription = childParserContext.ParserHelper.ReaderContext.Resource.Description; - if (StringUtils.HasText(resourceDescription)) - { - int line = ConfigurationUtils.GetLineNumber(element); - if (line > 0) - { - resourceDescription += " line " + line; - } - } - od.ResourceDescription = resourceDescription; - - string isAbstract = GetAttributeValue(element, ObjectDefinitionConstants.AbstractAttribute); - if (StringUtils.HasText(isAbstract)) - { - od.IsAbstract = IsTrueStringValue(isAbstract); - } - return od; - } - catch (TypeLoadException ex) - { - parserContext.ReaderContext.ReportException( - element, - id, - string.Format( - "Object class [{0}] not found.", - typeName), - ex); - } - catch (Exception ex) - { - parserContext.ReaderContext.ReportException(element, id, string.Empty, ex); - } - return null; - } - - /// - /// Parse method override argument subelements of the given object element. - /// - protected MethodOverrides ParseMethodOverrideSubElements( - string name, XmlElement element, ParserContext parserContext) - { - MethodOverrides overrides = new MethodOverrides(); - foreach (XmlNode node in this.SelectNodes(element, ObjectDefinitionConstants.LookupMethodElement)) - { - ParseLookupMethodElement(name, overrides, (XmlElement)node, parserContext); - } - foreach (XmlNode node in this.SelectNodes(element, ObjectDefinitionConstants.ReplacedMethodElement)) - { - ParseReplacedMethodElement(name, overrides, (XmlElement)node, parserContext); - } - return overrides; - } - - /// - /// Parse element and add parsed element to - /// - protected void ParseLookupMethodElement( - string name, MethodOverrides overrides, XmlElement element, ParserContext parserContext) - { - string methodName = GetAttributeValue(element, ObjectDefinitionConstants.LookupMethodNameAttribute); - string targetObjectName = GetAttributeValue(element, ObjectDefinitionConstants.LookupMethodObjectNameAttribute); - if (StringUtils.IsNullOrEmpty(methodName)) - { - throw new ObjectDefinitionStoreException( - parserContext.ReaderContext.Resource, name, - string.Format("The '{0}' attribute is required for the '{1}' element.", - ObjectDefinitionConstants.LookupMethodNameAttribute, ObjectDefinitionConstants.LookupMethodElement)); - } - if (StringUtils.IsNullOrEmpty(targetObjectName)) - { - throw new ObjectDefinitionStoreException( - parserContext.ReaderContext.Resource, name, - string.Format("The '{0}' attribute is required for the '{1}' element.", - ObjectDefinitionConstants.LookupMethodObjectNameAttribute, ObjectDefinitionConstants.LookupMethodElement)); - } - overrides.Add(new LookupMethodOverride(methodName, targetObjectName)); - } - - /// - /// Parse element and add parsed element to - /// - protected void ParseReplacedMethodElement( - string name, MethodOverrides overrides, XmlElement element, ParserContext parserContext) - { - string methodName = GetAttributeValue(element, ObjectDefinitionConstants.ReplacedMethodNameAttribute); - string targetReplacerObjectName = GetAttributeValue(element, ObjectDefinitionConstants.ReplacedMethodReplacerNameAttribute); - if (StringUtils.IsNullOrEmpty(methodName)) - { - throw new ObjectDefinitionStoreException( - parserContext.ReaderContext.Resource, name, - string.Format("The '{0}' attribute is required for the '{1}' element.", - ObjectDefinitionConstants.ReplacedMethodNameAttribute, ObjectDefinitionConstants.ReplacedMethodElement)); - } - if (StringUtils.IsNullOrEmpty(targetReplacerObjectName)) - { - throw new ObjectDefinitionStoreException( - parserContext.ReaderContext.Resource, name, - string.Format("The '{0}' attribute is required for the '{1}' element.", - ObjectDefinitionConstants.ReplacedMethodReplacerNameAttribute, ObjectDefinitionConstants.ReplacedMethodElement)); - } - ReplacedMethodOverride theOverride = new ReplacedMethodOverride(methodName, targetReplacerObjectName); - foreach (XmlNode node in this.SelectNodes(element, ObjectDefinitionConstants.ReplacedMethodArgumentTypeElement)) - { - XmlElement argElement = (XmlElement)node; - string match = GetAttributeValue(argElement, ObjectDefinitionConstants.ReplacedMethodArgumentTypeMatchAttribute); - if (StringUtils.IsNullOrEmpty(match)) + typeName = GetAttributeValue(element, ObjectDefinitionConstants.TypeAttribute); + if (StringUtils.IsNullOrEmpty(typeName)) { throw new ObjectDefinitionStoreException( - parserContext.ReaderContext.Resource, name, - string.Format("The '{0}' attribute is required for the '{1}' element.", - ObjectDefinitionConstants.ReplacedMethodArgumentTypeMatchAttribute, ObjectDefinitionConstants.ReplacedMethodArgumentTypeElement)); + parserContext.ReaderContext.Resource, id, + "The 'type' attribute does not need to be present, but if it is it must not be empty: got '" + + typeName + "'."); } - theOverride.AddTypeIdentifier(match); - } - overrides.Add(theOverride); - } - - /// - /// Parse constructor argument subelements of the given object element. - /// - protected ConstructorArgumentValues ParseConstructorArgSubElements( - string name, XmlElement element, ParserContext parserContext) - { - ConstructorArgumentValues arguments = new ConstructorArgumentValues(); - foreach (XmlNode node in this.SelectNodes(element, ObjectDefinitionConstants.ConstructorArgElement)) - { - ParseConstructorArgElement(name, arguments, (XmlElement)node, parserContext); - } - return arguments; - } - - /// - /// Parse event handler subelements of the given object element. - /// - protected EventValues ParseEventHandlerSubElements( - string name, XmlElement element, ParserContext parserContext) - { - EventValues events = new EventValues(); - foreach (XmlNode node in this.SelectNodes(element, ObjectDefinitionConstants.ListenerElement)) - { - ParseEventListenerDefinition(name, events, (XmlElement)node, parserContext); - } - return events; - } - - /// - /// Parse the meta upplied meta attributes if the given object element - /// - protected void ParseMetaElements(XmlElement element, ObjectMetadataAttributeAccessor attributeAccessor) - { - foreach (XmlNode node in this.SelectNodes(element, ObjectDefinitionConstants.MetaElement)) - { - string key = GetAttributeValue((XmlElement)node, ObjectDefinitionConstants.KeyAttribute); - string value = GetAttributeValue((XmlElement)node, ObjectDefinitionConstants.ValueAttribute); - - ObjectMetadataAttribute attribute = new ObjectMetadataAttribute(key, value); - attribute.Source = (XmlElement)node; - attributeAccessor.AddMetadataAttribute(attribute); - } - } - - /// - /// Parse qualifier sub-elements of the given bean element. - /// - public void ParseQualifierElements(string name, XmlElement element, ParserContext parserContext, AbstractObjectDefinition od) - { - foreach (XmlNode node in this.SelectNodes(element, ObjectDefinitionConstants.QualifierElement)) - { - ParseQualifierElement(name, (XmlElement) node, parserContext, od); - } - } - - /// - /// Parse a qualifier element. - /// - public void ParseQualifierElement(string name, XmlElement element, ParserContext parserContext, AbstractObjectDefinition od) - { - string typeName = GetAttributeValue(element, ObjectDefinitionConstants.TypeAttribute); - string value = GetAttributeValue(element, ObjectDefinitionConstants.ValueAttribute); - - if (string.IsNullOrEmpty(typeName)) - { - throw new ObjectDefinitionStoreException( - parserContext.ReaderContext.Resource, name, - "Tag 'qualifier' must have a 'type' attribute"); } - var qualifier = new AutowireCandidateQualifier(typeName); - qualifier.Source = element; + string parent = GetAttributeValue(element, ObjectDefinitionConstants.ParentAttribute); - if (!string.IsNullOrEmpty(value)) - qualifier.SetAttribute(AutowireCandidateQualifier.VALUE_KEY, value); + AbstractObjectDefinition od + = parserContext.ReaderContext.ObjectDefinitionFactory.CreateObjectDefinition( + typeName, parent, parserContext.ReaderContext.Reader.Domain); - foreach (XmlNode node in this.SelectNodes(element, ObjectDefinitionConstants.AttributeElement)) + ParserContext childParserContext = new ParserContext(parserContext.ParserHelper, od); + + ParseMetaElements(element, od); + ParseQualifierElements(id, element, parserContext, od); + MutablePropertyValues pvs = ParsePropertyElements(id, element, childParserContext); + ConstructorArgumentValues arguments = ParseConstructorArgSubElements(id, element, childParserContext); + EventValues events = ParseEventHandlerSubElements(id, element, childParserContext); + MethodOverrides methodOverrides = ParseMethodOverrideSubElements(id, element, childParserContext); + + bool isPage = StringUtils.HasText(typeName) && typeName != null && typeName.ToLower().EndsWith(".aspx"); + if (!isPage) { - var attributeEle = node as XmlElement; - string attributeKey = GetAttributeValue(attributeEle, ObjectDefinitionConstants.KeyAttribute); - string attributeValue = GetAttributeValue(attributeEle, ObjectDefinitionConstants.ValueAttribute); + od.ConstructorArgumentValues = arguments; + } - if (!string.IsNullOrEmpty(attributeKey) && !string.IsNullOrEmpty(attributeValue)) + od.PropertyValues = pvs; + od.MethodOverrides = methodOverrides; + od.EventHandlerValues = events; + if (element.HasAttribute(ObjectDefinitionConstants.DependsOnAttribute)) + { + string dependsOn = GetAttributeValue(element, ObjectDefinitionConstants.DependsOnAttribute); + od.DependsOn = GetObjectNames(dependsOn); + } + + od.FactoryMethodName = GetAttributeValue(element, ObjectDefinitionConstants.FactoryMethodAttribute); + od.FactoryObjectName = GetAttributeValue(element, ObjectDefinitionConstants.FactoryObjectAttribute); + string dependencyCheck = GetAttributeValue(element, ObjectDefinitionConstants.DependencyCheckAttribute); + if (ObjectDefinitionConstants.DefaultValue.Equals(dependencyCheck)) + { + dependencyCheck = childParserContext.ParserHelper.Defaults.DependencyCheck; + } + + od.DependencyCheck = GetDependencyCheck(dependencyCheck); + string autowire = GetAttributeValue(element, ObjectDefinitionConstants.AutowireAttribute); + if (ObjectDefinitionConstants.DefaultValue.Equals(autowire)) + { + autowire = childParserContext.ParserHelper.Defaults.Autowire; + } + + od.AutowireMode = GetAutowireMode(autowire); + + string autowireCandidates = GetAttributeValue(element, ObjectDefinitionConstants.AutowireCandidateAttribute); + if (string.IsNullOrEmpty(autowireCandidates) || ObjectDefinitionConstants.DefaultValue.Equals(autowireCandidates)) + { + if (!string.IsNullOrEmpty(childParserContext.ParserHelper.Defaults.AutowireCandidates)) { - var attribute = new ObjectMetadataAttribute(attributeKey, attributeValue); - attribute.Source = attributeEle; - qualifier.AddMetadataAttribute(attribute); + string[] patterns = childParserContext.ParserHelper.Defaults.AutowireCandidates.Split(','); + od.IsAutowireCandidate = PatternMatchUtils.SimpleMatch(patterns, id); } - else - { - throw new ObjectDefinitionStoreException( - parserContext.ReaderContext.Resource, name, - "Qualifier 'attribute' tag must have a 'key' and 'value'"); - } - } - od.AddQualifier(qualifier); - } - - /// - /// Parse property value subelements of the given object element. - /// - /// - /// The name of the object (definition) associated with the property element (s) - /// - /// - /// The element containing the top level object definition. - /// - /// - /// The namespace-aware parser. - /// - /// - /// The property (s) associated with the object (definition). - /// - protected virtual MutablePropertyValues ParsePropertyElements( - string name, XmlElement element, ParserContext parserContext) - { - MutablePropertyValues properties = new MutablePropertyValues(); - foreach (XmlNode node in this.SelectNodes(element, ObjectDefinitionConstants.PropertyElement)) - { - ParsePropertyElement(name, properties, (XmlElement)node, parserContext); - } - return properties; - } - - /// - /// Parse a constructor-arg element. - /// - /// - /// The name of the object (definition) associated with the ctor arg. - /// - /// - /// The list of constructor args associated with the object (definition). - /// - /// - /// The name of the element containing the ctor arg definition. - /// - /// - /// The namespace-aware parser. - /// - protected virtual void ParseConstructorArgElement( - string name, ConstructorArgumentValues arguments, XmlElement element, ParserContext parserContext) - { - object val = ParsePropertyValue(element, name, parserContext); - string indexAttr = GetAttributeValue(element, ObjectDefinitionConstants.IndexAttribute); - string typeAttr = GetAttributeValue(element, ObjectDefinitionConstants.TypeAttribute); - string nameAttr = GetAttributeValue(element, ObjectDefinitionConstants.ArgumentNameAttribute); - - // only one of the 'index' or 'name' attributes can be present - if (StringUtils.HasText(indexAttr) - && StringUtils.HasText(nameAttr)) - { - throw new ObjectDefinitionStoreException( - parserContext.ReaderContext.Resource, name, - "Only one of the 'index' or 'name' attributes can be present per constructor argument."); - } - if (StringUtils.HasText(indexAttr)) - { - try - { - int index = int.Parse(indexAttr, CultureInfo.CurrentCulture); - if (index < 0) - { - throw new ObjectDefinitionStoreException( - parserContext.ReaderContext.Resource, name, - "'index' cannot be lower than 0"); - } - if (StringUtils.HasText(typeAttr)) - { - arguments.AddIndexedArgumentValue(index, val, typeAttr); - } - else - { - arguments.AddIndexedArgumentValue(index, val); - } - } - catch (FormatException) - { - throw new ObjectDefinitionStoreException( - parserContext.ReaderContext.Resource, name, - "Attribute 'index' of tag 'constructor-arg' must be an integer value."); - } - } - else if (StringUtils.HasText(nameAttr)) - { - if (StringUtils.HasText(typeAttr)) - { - if (log.IsEnabled(LogLevel.Warning)) - { - log.LogWarning("The 'type' attribute is redundant when the 'name' attribute has been used on a constructor argument element."); - } - } - arguments.AddNamedArgumentValue(nameAttr, val); } else { + od.IsAutowireCandidate = ObjectDefinitionConstants.TrueValue.Equals(autowireCandidates); + } + + string primary = GetAttributeValue(element, ObjectDefinitionConstants.PrimaryAttribute); + if (string.IsNullOrEmpty(primary)) + { + primary = ObjectDefinitionConstants.FalseValue; + } + + od.IsPrimary = IsTrueStringValue(primary); + string initMethodName = GetAttributeValue(element, ObjectDefinitionConstants.InitMethodAttribute); + if (initMethodName != null) + { + if (StringUtils.HasText(initMethodName)) + od.InitMethodName = initMethodName; + } + else + { + if (StringUtils.HasText(childParserContext.ParserHelper.Defaults.InitMethod)) + od.InitMethodName = childParserContext.ParserHelper.Defaults.InitMethod; + } + + string destroyMethodName = GetAttributeValue(element, ObjectDefinitionConstants.DestroyMethodAttribute); + if (destroyMethodName != null) + { + if (StringUtils.HasText(destroyMethodName)) + { + od.DestroyMethodName = destroyMethodName; + } + } + else + { + if (StringUtils.HasText(childParserContext.ParserHelper.Defaults.DestroyMethod)) + od.DestroyMethodName = childParserContext.ParserHelper.Defaults.DestroyMethod; + } + + if (element.HasAttribute(ObjectDefinitionConstants.SingletonAttribute)) + { + od.IsSingleton = IsTrueStringValue(GetAttributeValue(element, ObjectDefinitionConstants.SingletonAttribute, string.Empty).ToLower(CultureInfo.CurrentCulture)); + } + + string lazyInit = GetAttributeValue(element, ObjectDefinitionConstants.LazyInitAttribute); + if (ObjectDefinitionConstants.DefaultValue.Equals(lazyInit) && od.IsSingleton) + { + // just apply default to singletons, as lazy-init has no meaning for prototypes... + lazyInit = childParserContext.ParserHelper.Defaults.LazyInit; + } + + od.IsLazyInit = IsTrueStringValue(lazyInit); + + // try to get the line info + string resourceDescription = childParserContext.ParserHelper.ReaderContext.Resource.Description; + if (StringUtils.HasText(resourceDescription)) + { + int line = ConfigurationUtils.GetLineNumber(element); + if (line > 0) + { + resourceDescription += " line " + line; + } + } + + od.ResourceDescription = resourceDescription; + + string isAbstract = GetAttributeValue(element, ObjectDefinitionConstants.AbstractAttribute); + if (StringUtils.HasText(isAbstract)) + { + od.IsAbstract = IsTrueStringValue(isAbstract); + } + + return od; + } + catch (TypeLoadException ex) + { + parserContext.ReaderContext.ReportException( + element, + id, + string.Format( + "Object class [{0}] not found.", + typeName), + ex); + } + catch (Exception ex) + { + parserContext.ReaderContext.ReportException(element, id, string.Empty, ex); + } + + return null; + } + + /// + /// Parse method override argument subelements of the given object element. + /// + protected MethodOverrides ParseMethodOverrideSubElements( + string name, XmlElement element, ParserContext parserContext) + { + MethodOverrides overrides = new MethodOverrides(); + foreach (XmlNode node in this.SelectNodes(element, ObjectDefinitionConstants.LookupMethodElement)) + { + ParseLookupMethodElement(name, overrides, (XmlElement) node, parserContext); + } + + foreach (XmlNode node in this.SelectNodes(element, ObjectDefinitionConstants.ReplacedMethodElement)) + { + ParseReplacedMethodElement(name, overrides, (XmlElement) node, parserContext); + } + + return overrides; + } + + /// + /// Parse element and add parsed element to + /// + protected void ParseLookupMethodElement( + string name, MethodOverrides overrides, XmlElement element, ParserContext parserContext) + { + string methodName = GetAttributeValue(element, ObjectDefinitionConstants.LookupMethodNameAttribute); + string targetObjectName = GetAttributeValue(element, ObjectDefinitionConstants.LookupMethodObjectNameAttribute); + if (StringUtils.IsNullOrEmpty(methodName)) + { + throw new ObjectDefinitionStoreException( + parserContext.ReaderContext.Resource, name, + string.Format("The '{0}' attribute is required for the '{1}' element.", + ObjectDefinitionConstants.LookupMethodNameAttribute, ObjectDefinitionConstants.LookupMethodElement)); + } + + if (StringUtils.IsNullOrEmpty(targetObjectName)) + { + throw new ObjectDefinitionStoreException( + parserContext.ReaderContext.Resource, name, + string.Format("The '{0}' attribute is required for the '{1}' element.", + ObjectDefinitionConstants.LookupMethodObjectNameAttribute, ObjectDefinitionConstants.LookupMethodElement)); + } + + overrides.Add(new LookupMethodOverride(methodName, targetObjectName)); + } + + /// + /// Parse element and add parsed element to + /// + protected void ParseReplacedMethodElement( + string name, MethodOverrides overrides, XmlElement element, ParserContext parserContext) + { + string methodName = GetAttributeValue(element, ObjectDefinitionConstants.ReplacedMethodNameAttribute); + string targetReplacerObjectName = GetAttributeValue(element, ObjectDefinitionConstants.ReplacedMethodReplacerNameAttribute); + if (StringUtils.IsNullOrEmpty(methodName)) + { + throw new ObjectDefinitionStoreException( + parserContext.ReaderContext.Resource, name, + string.Format("The '{0}' attribute is required for the '{1}' element.", + ObjectDefinitionConstants.ReplacedMethodNameAttribute, ObjectDefinitionConstants.ReplacedMethodElement)); + } + + if (StringUtils.IsNullOrEmpty(targetReplacerObjectName)) + { + throw new ObjectDefinitionStoreException( + parserContext.ReaderContext.Resource, name, + string.Format("The '{0}' attribute is required for the '{1}' element.", + ObjectDefinitionConstants.ReplacedMethodReplacerNameAttribute, ObjectDefinitionConstants.ReplacedMethodElement)); + } + + ReplacedMethodOverride theOverride = new ReplacedMethodOverride(methodName, targetReplacerObjectName); + foreach (XmlNode node in this.SelectNodes(element, ObjectDefinitionConstants.ReplacedMethodArgumentTypeElement)) + { + XmlElement argElement = (XmlElement) node; + string match = GetAttributeValue(argElement, ObjectDefinitionConstants.ReplacedMethodArgumentTypeMatchAttribute); + if (StringUtils.IsNullOrEmpty(match)) + { + throw new ObjectDefinitionStoreException( + parserContext.ReaderContext.Resource, name, + string.Format("The '{0}' attribute is required for the '{1}' element.", + ObjectDefinitionConstants.ReplacedMethodArgumentTypeMatchAttribute, ObjectDefinitionConstants.ReplacedMethodArgumentTypeElement)); + } + + theOverride.AddTypeIdentifier(match); + } + + overrides.Add(theOverride); + } + + /// + /// Parse constructor argument subelements of the given object element. + /// + protected ConstructorArgumentValues ParseConstructorArgSubElements( + string name, XmlElement element, ParserContext parserContext) + { + ConstructorArgumentValues arguments = new ConstructorArgumentValues(); + foreach (XmlNode node in this.SelectNodes(element, ObjectDefinitionConstants.ConstructorArgElement)) + { + ParseConstructorArgElement(name, arguments, (XmlElement) node, parserContext); + } + + return arguments; + } + + /// + /// Parse event handler subelements of the given object element. + /// + protected EventValues ParseEventHandlerSubElements( + string name, XmlElement element, ParserContext parserContext) + { + EventValues events = new EventValues(); + foreach (XmlNode node in this.SelectNodes(element, ObjectDefinitionConstants.ListenerElement)) + { + ParseEventListenerDefinition(name, events, (XmlElement) node, parserContext); + } + + return events; + } + + /// + /// Parse the meta upplied meta attributes if the given object element + /// + protected void ParseMetaElements(XmlElement element, ObjectMetadataAttributeAccessor attributeAccessor) + { + foreach (XmlNode node in this.SelectNodes(element, ObjectDefinitionConstants.MetaElement)) + { + string key = GetAttributeValue((XmlElement) node, ObjectDefinitionConstants.KeyAttribute); + string value = GetAttributeValue((XmlElement) node, ObjectDefinitionConstants.ValueAttribute); + + ObjectMetadataAttribute attribute = new ObjectMetadataAttribute(key, value); + attribute.Source = (XmlElement) node; + attributeAccessor.AddMetadataAttribute(attribute); + } + } + + /// + /// Parse qualifier sub-elements of the given bean element. + /// + public void ParseQualifierElements(string name, XmlElement element, ParserContext parserContext, AbstractObjectDefinition od) + { + foreach (XmlNode node in this.SelectNodes(element, ObjectDefinitionConstants.QualifierElement)) + { + ParseQualifierElement(name, (XmlElement) node, parserContext, od); + } + } + + /// + /// Parse a qualifier element. + /// + public void ParseQualifierElement(string name, XmlElement element, ParserContext parserContext, AbstractObjectDefinition od) + { + string typeName = GetAttributeValue(element, ObjectDefinitionConstants.TypeAttribute); + string value = GetAttributeValue(element, ObjectDefinitionConstants.ValueAttribute); + + if (string.IsNullOrEmpty(typeName)) + { + throw new ObjectDefinitionStoreException( + parserContext.ReaderContext.Resource, name, + "Tag 'qualifier' must have a 'type' attribute"); + } + + var qualifier = new AutowireCandidateQualifier(typeName); + qualifier.Source = element; + + if (!string.IsNullOrEmpty(value)) + qualifier.SetAttribute(AutowireCandidateQualifier.VALUE_KEY, value); + + foreach (XmlNode node in this.SelectNodes(element, ObjectDefinitionConstants.AttributeElement)) + { + var attributeEle = node as XmlElement; + string attributeKey = GetAttributeValue(attributeEle, ObjectDefinitionConstants.KeyAttribute); + string attributeValue = GetAttributeValue(attributeEle, ObjectDefinitionConstants.ValueAttribute); + + if (!string.IsNullOrEmpty(attributeKey) && !string.IsNullOrEmpty(attributeValue)) + { + var attribute = new ObjectMetadataAttribute(attributeKey, attributeValue); + attribute.Source = attributeEle; + qualifier.AddMetadataAttribute(attribute); + } + else + { + throw new ObjectDefinitionStoreException( + parserContext.ReaderContext.Resource, name, + "Qualifier 'attribute' tag must have a 'key' and 'value'"); + } + } + + od.AddQualifier(qualifier); + } + + /// + /// Parse property value subelements of the given object element. + /// + /// + /// The name of the object (definition) associated with the property element (s) + /// + /// + /// The element containing the top level object definition. + /// + /// + /// The namespace-aware parser. + /// + /// + /// The property (s) associated with the object (definition). + /// + protected virtual MutablePropertyValues ParsePropertyElements( + string name, XmlElement element, ParserContext parserContext) + { + MutablePropertyValues properties = new MutablePropertyValues(); + foreach (XmlNode node in this.SelectNodes(element, ObjectDefinitionConstants.PropertyElement)) + { + ParsePropertyElement(name, properties, (XmlElement) node, parserContext); + } + + return properties; + } + + /// + /// Parse a constructor-arg element. + /// + /// + /// The name of the object (definition) associated with the ctor arg. + /// + /// + /// The list of constructor args associated with the object (definition). + /// + /// + /// The name of the element containing the ctor arg definition. + /// + /// + /// The namespace-aware parser. + /// + protected virtual void ParseConstructorArgElement( + string name, ConstructorArgumentValues arguments, XmlElement element, ParserContext parserContext) + { + object val = ParsePropertyValue(element, name, parserContext); + string indexAttr = GetAttributeValue(element, ObjectDefinitionConstants.IndexAttribute); + string typeAttr = GetAttributeValue(element, ObjectDefinitionConstants.TypeAttribute); + string nameAttr = GetAttributeValue(element, ObjectDefinitionConstants.ArgumentNameAttribute); + + // only one of the 'index' or 'name' attributes can be present + if (StringUtils.HasText(indexAttr) + && StringUtils.HasText(nameAttr)) + { + throw new ObjectDefinitionStoreException( + parserContext.ReaderContext.Resource, name, + "Only one of the 'index' or 'name' attributes can be present per constructor argument."); + } + + if (StringUtils.HasText(indexAttr)) + { + try + { + int index = int.Parse(indexAttr, CultureInfo.CurrentCulture); + if (index < 0) + { + throw new ObjectDefinitionStoreException( + parserContext.ReaderContext.Resource, name, + "'index' cannot be lower than 0"); + } + if (StringUtils.HasText(typeAttr)) { - arguments.AddGenericArgumentValue(val, typeAttr); + arguments.AddIndexedArgumentValue(index, val, typeAttr); } else { - arguments.AddGenericArgumentValue(val); + arguments.AddIndexedArgumentValue(index, val); + } + } + catch (FormatException) + { + throw new ObjectDefinitionStoreException( + parserContext.ReaderContext.Resource, name, + "Attribute 'index' of tag 'constructor-arg' must be an integer value."); + } + } + else if (StringUtils.HasText(nameAttr)) + { + if (StringUtils.HasText(typeAttr)) + { + if (log.IsEnabled(LogLevel.Warning)) + { + log.LogWarning("The 'type' attribute is redundant when the 'name' attribute has been used on a constructor argument element."); + } + } + + arguments.AddNamedArgumentValue(nameAttr, val); + } + else + { + if (StringUtils.HasText(typeAttr)) + { + arguments.AddGenericArgumentValue(val, typeAttr); + } + else + { + arguments.AddGenericArgumentValue(val); + } + } + } + + /// + /// Parse a property element. + /// + /// + /// The name of the object (definition) associated with the property. + /// + /// + /// The list of properties associated with the object (definition). + /// + /// + /// The name of the element containing the property definition. + /// + /// + /// The namespace-aware parser. + /// + protected void ParsePropertyElement( + string name, MutablePropertyValues properties, XmlElement element, ParserContext parserContext) + { + string propertyName = GetAttributeValue(element, ObjectDefinitionConstants.NameAttribute); + if (StringUtils.IsNullOrEmpty(propertyName)) + { + throw new ObjectDefinitionStoreException( + parserContext.ReaderContext.Resource, + name, + "The 'property' element must have a 'name' attribute"); + } + + object val = ParsePropertyValue(element, name, parserContext); + properties.Add(new PropertyValue(propertyName, val)); + } + + /// + /// Get the value of a property element (may be a list). + /// + ///

+ /// Please note that even though this method is named GetPropertyValue, + /// it is called by both the property and constructor argument element + /// handlers. + ///

+ ///
+ /// The property element. + /// + /// The name of the object associated with the property. + /// + /// + /// The namespace-aware parser. + /// + protected virtual object ParsePropertyValue( + XmlElement element, string name, ParserContext parserContext) + { + XmlAttribute inlineValueAtt = element.Attributes[ObjectDefinitionConstants.ValueAttribute]; + if (inlineValueAtt != null) + { + return inlineValueAtt.Value; + } + + XmlAttribute inlineRefAtt = element.Attributes[ObjectDefinitionConstants.RefAttribute]; + if (inlineRefAtt != null) + { + return new RuntimeObjectReference(inlineRefAtt.Value); + } + + XmlAttribute inlineExpressionAtt = element.Attributes[ObjectDefinitionConstants.ExpressionAttribute]; + if (inlineExpressionAtt != null) + { + return new ExpressionHolder(inlineExpressionAtt.Value); + } + + // should only have one element child: value, ref, collection... + XmlNodeList nodes = element.ChildNodes; + XmlElement valueRefOrCollectionElement = null; + for (int i = 0; i < nodes.Count; ++i) + { + XmlElement candidateEle = nodes.Item(i) as XmlElement; + if (candidateEle != null) + { + if (ObjectDefinitionConstants.DescriptionElement.Equals(candidateEle.Name)) + { + // keep going: we don't use this value for now... + } + else + { + // child element is what we're looking for... + valueRefOrCollectionElement = candidateEle; } } } - /// - /// Parse a property element. - /// - /// - /// The name of the object (definition) associated with the property. - /// - /// - /// The list of properties associated with the object (definition). - /// - /// - /// The name of the element containing the property definition. - /// - /// - /// The namespace-aware parser. - /// - protected void ParsePropertyElement( - string name, MutablePropertyValues properties, XmlElement element, ParserContext parserContext) + if (valueRefOrCollectionElement == null) { - string propertyName = GetAttributeValue(element, ObjectDefinitionConstants.NameAttribute); - if (StringUtils.IsNullOrEmpty(propertyName)) - { - throw new ObjectDefinitionStoreException( - parserContext.ReaderContext.Resource, - name, - "The 'property' element must have a 'name' attribute"); - } - object val = ParsePropertyValue(element, name, parserContext); - properties.Add(new PropertyValue(propertyName, val)); + throw new ObjectDefinitionStoreException( + parserContext.ReaderContext.Resource, + name, + "The '' element must have a subelement such as 'value' or 'ref'."); } - /// - /// Get the value of a property element (may be a list). - /// - ///

- /// Please note that even though this method is named GetPropertyValue, - /// it is called by both the property and constructor argument element - /// handlers. - ///

- ///
- /// The property element. - /// - /// The name of the object associated with the property. - /// - /// - /// The namespace-aware parser. - /// - protected virtual object ParsePropertyValue( - XmlElement element, string name, ParserContext parserContext) - { - XmlAttribute inlineValueAtt = element.Attributes[ObjectDefinitionConstants.ValueAttribute]; - if (inlineValueAtt != null) - { - return inlineValueAtt.Value; - } - XmlAttribute inlineRefAtt = element.Attributes[ObjectDefinitionConstants.RefAttribute]; - if (inlineRefAtt != null) - { - return new RuntimeObjectReference(inlineRefAtt.Value); - } - XmlAttribute inlineExpressionAtt = element.Attributes[ObjectDefinitionConstants.ExpressionAttribute]; - if (inlineExpressionAtt != null) - { - return new ExpressionHolder(inlineExpressionAtt.Value); - } + return ParsePropertySubElement(valueRefOrCollectionElement, name, parserContext); + } - // should only have one element child: value, ref, collection... - XmlNodeList nodes = element.ChildNodes; - XmlElement valueRefOrCollectionElement = null; - for (int i = 0; i < nodes.Count; ++i) - { - XmlElement candidateEle = nodes.Item(i) as XmlElement; - if (candidateEle != null) - { - if (ObjectDefinitionConstants.DescriptionElement.Equals(candidateEle.Name)) - { - // keep going: we don't use this value for now... - } - else - { - // child element is what we're looking for... - valueRefOrCollectionElement = candidateEle; - } - } - } - if (valueRefOrCollectionElement == null) - { - throw new ObjectDefinitionStoreException( - parserContext.ReaderContext.Resource, - name, - "The '' element must have a subelement such as 'value' or 'ref'."); - } - return ParsePropertySubElement(valueRefOrCollectionElement, name, parserContext); - } - - /// - /// Parse a value, ref or collection subelement of a property element. - /// - /// - /// Subelement of property element; we don't know which yet. - /// - /// - /// The name of the object (definition) associated with the top level property. - /// - /// - /// The namespace-aware parser. - /// - protected virtual object ParsePropertySubElement( - XmlElement element, string name, ParserContext parserContext) + /// + /// Parse a value, ref or collection subelement of a property element. + /// + /// + /// Subelement of property element; we don't know which yet. + /// + /// + /// The name of the object (definition) associated with the top level property. + /// + /// + /// The namespace-aware parser. + /// + protected virtual object ParsePropertySubElement( + XmlElement element, string name, ParserContext parserContext) + { + if (element.NamespaceURI == Namespace) { - if (element.NamespaceURI == Namespace) + switch (element.LocalName) { - switch(element.LocalName) - { - case ObjectDefinitionConstants.ObjectElement: - { - return parserContext.ParserHelper.ParseObjectDefinitionElement(element, parserContext.ContainingObjectDefinition); - } - case ObjectDefinitionConstants.RefElement: - { - return ParseReference(element, parserContext.ParserHelper, name); - } - case ObjectDefinitionConstants.IdRefElement: - { - return ParseIdReference(element, parserContext.ParserHelper, name); - } - case ObjectDefinitionConstants.ListElement: - { - return ParseListElement(element, name, parserContext); - } - case ObjectDefinitionConstants.SetElement: - { - return ParseSetElement(element, name, parserContext); - } - case ObjectDefinitionConstants.DictionaryElement: - { - return ParseDictionaryElement(element, name, parserContext); - } - case ObjectDefinitionConstants.NameValuesElement: - { - return ParseNameValueCollectionElement(element, name, parserContext); - } - case ObjectDefinitionConstants.ValueElement: - { - return ParseValueElement(element, name); - } - case ObjectDefinitionConstants.ExpressionElement: - { - return ParseExpressionElement(element, name, parserContext); - } - case ObjectDefinitionConstants.NullElement: - { - // it's a distinguished null value... - return null; - } + case ObjectDefinitionConstants.ObjectElement: + { + return parserContext.ParserHelper.ParseObjectDefinitionElement(element, parserContext.ContainingObjectDefinition); + } + case ObjectDefinitionConstants.RefElement: + { + return ParseReference(element, parserContext.ParserHelper, name); + } + case ObjectDefinitionConstants.IdRefElement: + { + return ParseIdReference(element, parserContext.ParserHelper, name); + } + case ObjectDefinitionConstants.ListElement: + { + return ParseListElement(element, name, parserContext); + } + case ObjectDefinitionConstants.SetElement: + { + return ParseSetElement(element, name, parserContext); + } + case ObjectDefinitionConstants.DictionaryElement: + { + return ParseDictionaryElement(element, name, parserContext); + } + case ObjectDefinitionConstants.NameValuesElement: + { + return ParseNameValueCollectionElement(element, name, parserContext); + } + case ObjectDefinitionConstants.ValueElement: + { + return ParseValueElement(element, name); + } + case ObjectDefinitionConstants.ExpressionElement: + { + return ParseExpressionElement(element, name, parserContext); + } + case ObjectDefinitionConstants.NullElement: + { + // it's a distinguished null value... + return null; + } default: - throw new ObjectDefinitionStoreException( - parserContext.ReaderContext.Resource, - name, - "Unknown subelement of : <" + element.Name + ">"); - } + throw new ObjectDefinitionStoreException( + parserContext.ReaderContext.Resource, + name, + "Unknown subelement of : <" + element.Name + ">"); } + } - return parserContext.ParserHelper.ParseCustomElement(element, parserContext.ContainingObjectDefinition); + return parserContext.ParserHelper.ParseCustomElement(element, parserContext.ContainingObjectDefinition); // parserContext.ParserHelper.parse // // it may match another Parser @@ -1032,7 +1058,7 @@ namespace Spring.Objects.Factory.Xml // parserContext.ReaderContext.Resource, // name, // "Unknown subelement of : <" + element.Name + ">"); - } + } // private static INamespaceParser GetParser(string nspace) // { @@ -1048,502 +1074,520 @@ namespace Spring.Objects.Factory.Xml // } // } - private static object ParseIdReference(XmlElement element, ObjectDefinitionParserHelper parserHelper, string name) + private static object ParseIdReference(XmlElement element, ObjectDefinitionParserHelper parserHelper, string name) + { + // a generic reference to any name of any object + string objectRef = GetAttributeValue(element, ObjectDefinitionConstants.ObjectRefAttribute); + if (StringUtils.IsNullOrEmpty(objectRef)) { - // a generic reference to any name of any object - string objectRef = GetAttributeValue(element, ObjectDefinitionConstants.ObjectRefAttribute); + // a reference to the id of another object in the same XML file + objectRef = GetAttributeValue(element, ObjectDefinitionConstants.LocalRefAttribute); if (StringUtils.IsNullOrEmpty(objectRef)) { - // a reference to the id of another object in the same XML file - objectRef = GetAttributeValue(element, ObjectDefinitionConstants.LocalRefAttribute); + throw new ObjectDefinitionStoreException( + parserHelper.ReaderContext.Resource, + name, + "Either 'object' or 'local' is required for an idref"); + } + } + + return objectRef; + } + + private object ParseReference(XmlElement element, ObjectDefinitionParserHelper parserHelper, string name) + { + // is it a generic reference to any name of any object? + string objectRef = GetAttributeValue(element, ObjectDefinitionConstants.ObjectRefAttribute); + if (StringUtils.IsNullOrEmpty(objectRef)) + { + // is it a reference to the id of another object in the same XML file? + objectRef = GetAttributeValue(element, ObjectDefinitionConstants.LocalRefAttribute); + if (StringUtils.IsNullOrEmpty(objectRef)) + { + // is it a reference to the id of another object in a parent context? + objectRef = GetAttributeValue(element, ObjectDefinitionConstants.ParentAttribute); if (StringUtils.IsNullOrEmpty(objectRef)) { throw new ObjectDefinitionStoreException( parserHelper.ReaderContext.Resource, name, - "Either 'object' or 'local' is required for an idref"); + "Either 'object' or 'local' is required for a reference"); } + + return new RuntimeObjectReference(objectRef, true); } - return objectRef; } - private object ParseReference(XmlElement element, ObjectDefinitionParserHelper parserHelper, string name) + return new RuntimeObjectReference(objectRef); + } + + private object ParseValueElement(XmlElement element, string name) + { + string valueType = GetAttributeValue(element, ObjectDefinitionConstants.TypeAttribute); + if (StringUtils.IsNullOrEmpty(valueType)) { - // is it a generic reference to any name of any object? - string objectRef = GetAttributeValue(element, ObjectDefinitionConstants.ObjectRefAttribute); - if (StringUtils.IsNullOrEmpty(objectRef)) - { - // is it a reference to the id of another object in the same XML file? - objectRef = GetAttributeValue(element, ObjectDefinitionConstants.LocalRefAttribute); - if (StringUtils.IsNullOrEmpty(objectRef)) - { - // is it a reference to the id of another object in a parent context? - objectRef = GetAttributeValue(element, ObjectDefinitionConstants.ParentAttribute); - if (StringUtils.IsNullOrEmpty(objectRef)) - { - throw new ObjectDefinitionStoreException( - parserHelper.ReaderContext.Resource, - name, - "Either 'object' or 'local' is required for a reference"); - } - return new RuntimeObjectReference(objectRef, true); - } - } - return new RuntimeObjectReference(objectRef); + return ParseTextValueElement(element, name); + } + else + { + return new TypedStringValue(ParseTextValueElement(element, name), valueType); + } + } + + private object ParseExpressionElement(XmlElement element, string name, ParserContext parserContext) + { + string expression = GetAttributeValue(element, ObjectDefinitionConstants.ValueAttribute); + ExpressionHolder holder = new ExpressionHolder(expression); + holder.Properties = ParsePropertyElements(name, element, parserContext); + return holder; + } + + /// + /// Gets a list definition. + /// + /// + /// The element describing the list definition. + /// + /// + /// The name of the object (definition) associated with the list definition. + /// + /// + /// The namespace-aware parser. + /// + /// The list definition. + protected virtual IList ParseListElement(XmlElement collectionEle, string name, ParserContext parserContext) + { + string elementTypeName = GetAttributeValue(collectionEle, "element-type"); + XmlNodeList nl = collectionEle.ChildNodes; + ManagedList target = new ManagedList(nl.Count); + + if (StringUtils.HasText(elementTypeName)) + { + target.ElementTypeName = elementTypeName; } - private object ParseValueElement(XmlElement element, string name) + target.MergeEnabled = ParseMergeAttribute(collectionEle, parserContext.ParserHelper); + + foreach (XmlNode node in collectionEle.ChildNodes) { - string valueType = GetAttributeValue(element, ObjectDefinitionConstants.TypeAttribute); - if (StringUtils.IsNullOrEmpty(valueType)) + XmlElement ele = node as XmlElement; + if (ele != null) { - return ParseTextValueElement(element, name); + target.Add(ParsePropertySubElement(ele, name, parserContext)); + } + } + + return target; + } + + private bool ParseMergeAttribute(XmlElement collectionElement, ObjectDefinitionParserHelper helper) + { + string val = collectionElement.GetAttribute(ObjectDefinitionConstants.MergeAttribute); + if (ObjectDefinitionConstants.DefaultValue.Equals(val)) + { + val = helper.Defaults.Merge; + } + + return ObjectDefinitionConstants.TrueValue.Equals(val); + } + + /// + /// Gets a set definition. + /// + /// + /// The element describing the set definition. + /// + /// + /// The name of the object (definition) associated with the set definition. + /// + /// + /// The namespace-aware parser. + /// + /// The set definition. + protected Set ParseSetElement(XmlElement collectionEle, string name, ParserContext parserContext) + { + string elementTypeName = GetAttributeValue(collectionEle, "element-type"); + XmlNodeList nl = collectionEle.ChildNodes; + ManagedSet target = new ManagedSet(nl.Count); + + if (StringUtils.HasText(elementTypeName)) + { + target.ElementTypeName = elementTypeName; + } + + target.MergeEnabled = ParseMergeAttribute(collectionEle, parserContext.ParserHelper); + + foreach (XmlNode node in collectionEle.ChildNodes) + { + XmlElement ele = node as XmlElement; + if (ele != null) + { + object sub = ParsePropertySubElement(ele, name, parserContext); + target.Add(sub); + } + } + + return target; + } + + /// + /// Gets a dictionary definition. + /// + /// The element describing the dictionary definition. + /// The name of the object (definition) associated with the dictionary definition. + /// The namespace-aware parser. + /// The dictionary definition. + protected IDictionary ParseDictionaryElement(XmlElement mapEle, string name, ParserContext parserContext) + { + ManagedDictionary dictionary = new ManagedDictionary(); + string keyTypeName = GetAttributeValue(mapEle, "key-type"); + string valueTypeName = GetAttributeValue(mapEle, "value-type"); + if (StringUtils.HasText(keyTypeName)) + { + dictionary.KeyTypeName = keyTypeName; + } + + if (StringUtils.HasText(valueTypeName)) + { + dictionary.ValueTypeName = valueTypeName; + } + + dictionary.MergeEnabled = ParseMergeAttribute(mapEle, parserContext.ParserHelper); + + XmlNodeList entryElements = SelectNodes(mapEle, ObjectDefinitionConstants.EntryElement); + foreach (XmlElement entryEle in entryElements) + { + #region Key + + object key = null; + + XmlAttribute keyAtt = entryEle.Attributes[ObjectDefinitionConstants.KeyAttribute]; + if (keyAtt != null) + { + key = keyAtt.Value; } else { - return new TypedStringValue(ParseTextValueElement(element, name), valueType); - } - } - - private object ParseExpressionElement(XmlElement element, string name, ParserContext parserContext) - { - string expression = GetAttributeValue(element, ObjectDefinitionConstants.ValueAttribute); - ExpressionHolder holder = new ExpressionHolder(expression); - holder.Properties = ParsePropertyElements(name, element, parserContext); - return holder; - } - - /// - /// Gets a list definition. - /// - /// - /// The element describing the list definition. - /// - /// - /// The name of the object (definition) associated with the list definition. - /// - /// - /// The namespace-aware parser. - /// - /// The list definition. - protected virtual IList ParseListElement(XmlElement collectionEle, string name, ParserContext parserContext) - { - string elementTypeName = GetAttributeValue(collectionEle, "element-type"); - XmlNodeList nl = collectionEle.ChildNodes; - ManagedList target = new ManagedList(nl.Count); - - if (StringUtils.HasText(elementTypeName)) - { - target.ElementTypeName = elementTypeName; - } - target.MergeEnabled = ParseMergeAttribute(collectionEle, parserContext.ParserHelper); - - foreach (XmlNode node in collectionEle.ChildNodes) - { - XmlElement ele = node as XmlElement; - if (ele != null) + // ok, we're not using the 'key' attribute; lets check for the ref shortcut... + XmlAttribute keyRefAtt = entryEle.Attributes[ObjectDefinitionConstants.DictionaryKeyRefShortcutAttribute]; + if (keyRefAtt != null) { - target.Add(ParsePropertySubElement(ele, name, parserContext)); - } - } - return target; - } - - private bool ParseMergeAttribute(XmlElement collectionElement, ObjectDefinitionParserHelper helper) - { - string val = collectionElement.GetAttribute(ObjectDefinitionConstants.MergeAttribute); - if (ObjectDefinitionConstants.DefaultValue.Equals(val)) - { - val = helper.Defaults.Merge; - } - return ObjectDefinitionConstants.TrueValue.Equals(val); - } - - /// - /// Gets a set definition. - /// - /// - /// The element describing the set definition. - /// - /// - /// The name of the object (definition) associated with the set definition. - /// - /// - /// The namespace-aware parser. - /// - /// The set definition. - protected Set ParseSetElement(XmlElement collectionEle, string name, ParserContext parserContext) - { - string elementTypeName = GetAttributeValue(collectionEle, "element-type"); - XmlNodeList nl = collectionEle.ChildNodes; - ManagedSet target = new ManagedSet(nl.Count); - - if (StringUtils.HasText(elementTypeName)) - { - target.ElementTypeName = elementTypeName; - } - target.MergeEnabled = ParseMergeAttribute(collectionEle, parserContext.ParserHelper); - - foreach (XmlNode node in collectionEle.ChildNodes) - { - XmlElement ele = node as XmlElement; - if (ele != null) - { - object sub = ParsePropertySubElement(ele, name, parserContext); - target.Add(sub); - } - } - return target; - } - - /// - /// Gets a dictionary definition. - /// - /// The element describing the dictionary definition. - /// The name of the object (definition) associated with the dictionary definition. - /// The namespace-aware parser. - /// The dictionary definition. - protected IDictionary ParseDictionaryElement(XmlElement mapEle, string name, ParserContext parserContext) - { - ManagedDictionary dictionary = new ManagedDictionary(); - string keyTypeName = GetAttributeValue(mapEle, "key-type"); - string valueTypeName = GetAttributeValue(mapEle, "value-type"); - if (StringUtils.HasText(keyTypeName)) - { - dictionary.KeyTypeName = keyTypeName; - } - if (StringUtils.HasText(valueTypeName)) - { - dictionary.ValueTypeName = valueTypeName; - } - dictionary.MergeEnabled = ParseMergeAttribute(mapEle, parserContext.ParserHelper); - - XmlNodeList entryElements = SelectNodes(mapEle, ObjectDefinitionConstants.EntryElement); - foreach (XmlElement entryEle in entryElements) - { - #region Key - - object key = null; - - XmlAttribute keyAtt = entryEle.Attributes[ObjectDefinitionConstants.KeyAttribute]; - if (keyAtt != null) - { - key = keyAtt.Value; - } - else - { - // ok, we're not using the 'key' attribute; lets check for the ref shortcut... - XmlAttribute keyRefAtt = entryEle.Attributes[ObjectDefinitionConstants.DictionaryKeyRefShortcutAttribute]; - if (keyRefAtt != null) - { - key = new RuntimeObjectReference(keyRefAtt.Value); - } - else - { - // so check for the 'key' element... - XmlNode keyNode = SelectSingleNode(entryEle, ObjectDefinitionConstants.KeyElement); - if (keyNode == null) - { - throw new ObjectDefinitionStoreException( - parserContext.ReaderContext.Resource, name, - string.Format("One of either the '{0}' element, or the the '{1}' or '{2}' attributes " + - "is required for the <{3}/> element.", - ObjectDefinitionConstants.KeyElement, - ObjectDefinitionConstants.KeyAttribute, - ObjectDefinitionConstants.DictionaryKeyRefShortcutAttribute, - ObjectDefinitionConstants.EntryElement)); - } - XmlElement keyElement = (XmlElement)keyNode; - XmlNodeList keyNodes = keyElement.GetElementsByTagName("*"); - if (keyNodes == null || keyNodes.Count == 0) - { - throw new ObjectDefinitionStoreException( - parserContext.ReaderContext.Resource, name, - string.Format("Malformed <{0}/> element... the value of the key must be " + - "specified as a child value-style element.", - ObjectDefinitionConstants.KeyElement)); - } - key = ParsePropertySubElement((XmlElement)keyNodes.Item(0), name, parserContext); - } - } - - #endregion - - #region Value - - XmlAttribute inlineValueAtt = entryEle.Attributes[ObjectDefinitionConstants.ValueAttribute]; - if (inlineValueAtt != null) - { - // ok, we're using the value attribute shortcut... - dictionary[key] = inlineValueAtt.Value; - } - else if (entryEle.Attributes[ObjectDefinitionConstants.DictionaryValueRefShortcutAttribute] != null) - { - // ok, we're using the value-ref attribute shortcut... - XmlAttribute inlineValueRefAtt = entryEle.Attributes[ObjectDefinitionConstants.DictionaryValueRefShortcutAttribute]; - RuntimeObjectReference ror = new RuntimeObjectReference(inlineValueRefAtt.Value); - dictionary[key] = ror; - } - else if (entryEle.Attributes[ObjectDefinitionConstants.ExpressionAttribute] != null) - { - // ok, we're using the expression attribute shortcut... - XmlAttribute inlineExpressionAtt = entryEle.Attributes[ObjectDefinitionConstants.ExpressionAttribute]; - ExpressionHolder expHolder = new ExpressionHolder(inlineExpressionAtt.Value); - dictionary[key] = expHolder; + key = new RuntimeObjectReference(keyRefAtt.Value); } else { + // so check for the 'key' element... XmlNode keyNode = SelectSingleNode(entryEle, ObjectDefinitionConstants.KeyElement); - if (keyNode != null) - { - entryEle.RemoveChild(keyNode); - } - // ok, we're using the original full-on value element... - XmlNodeList valueElements = entryEle.GetElementsByTagName("*"); - if (valueElements == null || valueElements.Count == 0) + if (keyNode == null) { throw new ObjectDefinitionStoreException( parserContext.ReaderContext.Resource, name, - string.Format("One of either the '{0}' or '{1}' attributes, or a value-style element " + - "is required for the <{2}/> element.", - ObjectDefinitionConstants.ValueAttribute, ObjectDefinitionConstants.DictionaryValueRefShortcutAttribute, ObjectDefinitionConstants.EntryElement)); + string.Format("One of either the '{0}' element, or the the '{1}' or '{2}' attributes " + + "is required for the <{3}/> element.", + ObjectDefinitionConstants.KeyElement, + ObjectDefinitionConstants.KeyAttribute, + ObjectDefinitionConstants.DictionaryKeyRefShortcutAttribute, + ObjectDefinitionConstants.EntryElement)); } - dictionary[key] = ParsePropertySubElement((XmlElement)valueElements.Item(0), name, parserContext); + + XmlElement keyElement = (XmlElement) keyNode; + XmlNodeList keyNodes = keyElement.GetElementsByTagName("*"); + if (keyNodes == null || keyNodes.Count == 0) + { + throw new ObjectDefinitionStoreException( + parserContext.ReaderContext.Resource, name, + string.Format("Malformed <{0}/> element... the value of the key must be " + + "specified as a child value-style element.", + ObjectDefinitionConstants.KeyElement)); + } + + key = ParsePropertySubElement((XmlElement) keyNodes.Item(0), name, parserContext); + } + } + + #endregion + + #region Value + + XmlAttribute inlineValueAtt = entryEle.Attributes[ObjectDefinitionConstants.ValueAttribute]; + if (inlineValueAtt != null) + { + // ok, we're using the value attribute shortcut... + dictionary[key] = inlineValueAtt.Value; + } + else if (entryEle.Attributes[ObjectDefinitionConstants.DictionaryValueRefShortcutAttribute] != null) + { + // ok, we're using the value-ref attribute shortcut... + XmlAttribute inlineValueRefAtt = entryEle.Attributes[ObjectDefinitionConstants.DictionaryValueRefShortcutAttribute]; + RuntimeObjectReference ror = new RuntimeObjectReference(inlineValueRefAtt.Value); + dictionary[key] = ror; + } + else if (entryEle.Attributes[ObjectDefinitionConstants.ExpressionAttribute] != null) + { + // ok, we're using the expression attribute shortcut... + XmlAttribute inlineExpressionAtt = entryEle.Attributes[ObjectDefinitionConstants.ExpressionAttribute]; + ExpressionHolder expHolder = new ExpressionHolder(inlineExpressionAtt.Value); + dictionary[key] = expHolder; + } + else + { + XmlNode keyNode = SelectSingleNode(entryEle, ObjectDefinitionConstants.KeyElement); + if (keyNode != null) + { + entryEle.RemoveChild(keyNode); + } + + // ok, we're using the original full-on value element... + XmlNodeList valueElements = entryEle.GetElementsByTagName("*"); + if (valueElements == null || valueElements.Count == 0) + { + throw new ObjectDefinitionStoreException( + parserContext.ReaderContext.Resource, name, + string.Format("One of either the '{0}' or '{1}' attributes, or a value-style element " + + "is required for the <{2}/> element.", + ObjectDefinitionConstants.ValueAttribute, ObjectDefinitionConstants.DictionaryValueRefShortcutAttribute, ObjectDefinitionConstants.EntryElement)); + } + + dictionary[key] = ParsePropertySubElement((XmlElement) valueElements.Item(0), name, parserContext); + } + + #endregion + } + + return dictionary; + } + + /// + /// Selects sub-elements with a given + /// name. + /// + /// + ///

+ /// Uses a namespace manager if necessary. + ///

+ ///
+ /// + /// The element to be searched in. + /// + /// + /// The name of the child nodes to look for. + /// + /// + /// The child s of the supplied + /// with the supplied + /// . + /// + [Obsolete("not used anymore - ObjectsNamespaceParser will be dropped with 2.x, use ObjectDefinitionParserHelper instead", false)] + protected virtual XmlNodeList SelectNodes(XmlElement element, string childElementName) + { + XmlNamespaceManager nsManager = new XmlNamespaceManager(new NameTable()); + nsManager.AddNamespace(GetNamespacePrefix(element), element.NamespaceURI); + return element.SelectNodes(GetNamespacePrefix(element) + ":" + childElementName, nsManager); + } + + /// + /// Selects a single sub-element with a given + /// name. + /// + /// + ///

+ /// Uses a namespace manager if necessary. + ///

+ ///
+ /// + /// The element to be searched in. + /// + /// + /// The name of the child node to look for. + /// + /// + /// The first child of the supplied + /// with the supplied + /// . + /// + [Obsolete("not used anymore - ObjectsNamespaceParser will be dropped with 2.x, use ObjectDefinitionParserHelper instead", false)] + protected XmlNode SelectSingleNode(XmlElement element, string childElementName) + { + XmlNamespaceManager nsManager = new XmlNamespaceManager(new NameTable()); + nsManager.AddNamespace(GetNamespacePrefix(element), element.NamespaceURI); + return element.SelectSingleNode(GetNamespacePrefix(element) + ":" + childElementName, nsManager); + } + + /// + /// Gets a name value collection mapping definition. + /// + /// + /// The element describing the name value collection mapping definition. + /// + /// + /// The name of the object (definition) associated with the + /// name value collection mapping definition. + /// + /// the context carrying parsing state information + /// The name value collection definition. + protected NameValueCollection ParseNameValueCollectionElement(XmlElement nameValueEle, string name, ParserContext parserContext) + { + ManagedNameValueCollection nvc = new ManagedNameValueCollection(); + nvc.MergeEnabled = ParseMergeAttribute(nameValueEle, parserContext.ParserHelper); + + XmlNodeList addElements = nameValueEle.GetElementsByTagName(ObjectDefinitionConstants.AddElement); + foreach (XmlElement addElement in addElements) + { + string key = GetAttributeValue(addElement, ObjectDefinitionConstants.KeyAttribute); + string value = GetAttributeValue(addElement, ObjectDefinitionConstants.ValueAttribute); + string delimiters = GetAttributeValue(addElement, ObjectDefinitionConstants.DelimitersAttribute); + + if (StringUtils.HasText(delimiters)) + { + string[] values = value.Split(delimiters.ToCharArray()); + foreach (string v in values) + { + nvc.Add(key, v); + } + } + else + { + nvc.Add(key, value); + } + } + + return nvc; + } + + /// + /// Returns the text of the supplied , + /// or the empty string value if said is empty. + /// + /// + ///

+ /// If the supplied is , + /// then the empty string value will be returned. + ///

+ ///
+ protected string ParseTextValueElement(XmlElement element, string name) + { + if (element == null) return string.Empty; + + string innerText = element.InnerText; + // check the xml:space attribute + bool preserveWhitespace = 0 == string.Compare("preserve", element.GetAttribute("space", "http://www.w3.org/XML/1998/namespace"), true); + bool isEmpty = preserveWhitespace ? innerText.Length == 0 : StringUtils.IsNullOrEmpty(innerText); + return isEmpty ? String.Empty : innerText; + } + + /// + /// Strips the dependency check value out of the supplied string. + /// + /// + ///

+ /// If the supplied is an invalid dependency + /// checking mode, the invalid value will be logged and this method will + /// return the value. + /// No exception will be raised. + ///

+ ///
+ /// + /// The string containing the dependency check value. + /// + /// The dependency check value. + /// + protected DependencyCheckingMode GetDependencyCheck(string value) + { + DependencyCheckingMode code = DependencyCheckingMode.None; + if (StringUtils.HasText(value)) + { + try + { + code = (DependencyCheckingMode) Enum.Parse( + typeof(DependencyCheckingMode), value, true); + } + catch (ArgumentException ex) + { + #region Instrumentation + + if (log.IsEnabled(LogLevel.Debug)) + { + string message = string.Format("Error while parsing dependency checking mode : '{0}' is an invalid value.", + value); + log.LogDebug(ex, message); } #endregion } - return dictionary; } - /// - /// Selects sub-elements with a given - /// name. - /// - /// - ///

- /// Uses a namespace manager if necessary. - ///

- ///
- /// - /// The element to be searched in. - /// - /// - /// The name of the child nodes to look for. - /// - /// - /// The child s of the supplied - /// with the supplied - /// . - /// - [Obsolete("not used anymore - ObjectsNamespaceParser will be dropped with 2.x, use ObjectDefinitionParserHelper instead", false)] - protected virtual XmlNodeList SelectNodes(XmlElement element, string childElementName) - { - XmlNamespaceManager nsManager = new XmlNamespaceManager(new NameTable()); - nsManager.AddNamespace(GetNamespacePrefix(element), element.NamespaceURI); - return element.SelectNodes(GetNamespacePrefix(element) + ":" + childElementName, nsManager); - } + return code; + } - /// - /// Selects a single sub-element with a given - /// name. - /// - /// - ///

- /// Uses a namespace manager if necessary. - ///

- ///
- /// - /// The element to be searched in. - /// - /// - /// The name of the child node to look for. - /// - /// - /// The first child of the supplied - /// with the supplied - /// . - /// - [Obsolete("not used anymore - ObjectsNamespaceParser will be dropped with 2.x, use ObjectDefinitionParserHelper instead", false)] - protected XmlNode SelectSingleNode(XmlElement element, string childElementName) + /// + /// Strips the autowiring mode out of the supplied string. + /// + /// + ///

+ /// If the supplied is an invalid autowiring mode, + /// the invalid value will be logged and this method will return the + /// value. No exception will be raised. + ///

+ ///
+ /// + /// The string containing the autowiring mode definition. + /// + /// The autowiring mode. + /// + protected AutoWiringMode GetAutowireMode(string value) + { + AutoWiringMode mode = AutoWiringMode.No; + if (StringUtils.HasText(value)) { - XmlNamespaceManager nsManager = new XmlNamespaceManager(new NameTable()); - nsManager.AddNamespace(GetNamespacePrefix(element), element.NamespaceURI); - return element.SelectSingleNode(GetNamespacePrefix(element) + ":" + childElementName, nsManager); - } - - /// - /// Gets a name value collection mapping definition. - /// - /// - /// The element describing the name value collection mapping definition. - /// - /// - /// The name of the object (definition) associated with the - /// name value collection mapping definition. - /// - /// the context carrying parsing state information - /// The name value collection definition. - protected NameValueCollection ParseNameValueCollectionElement(XmlElement nameValueEle, string name, ParserContext parserContext) - { - ManagedNameValueCollection nvc = new ManagedNameValueCollection(); - nvc.MergeEnabled = ParseMergeAttribute(nameValueEle, parserContext.ParserHelper); - - XmlNodeList addElements = nameValueEle.GetElementsByTagName(ObjectDefinitionConstants.AddElement); - foreach (XmlElement addElement in addElements) + try { - string key = GetAttributeValue(addElement, ObjectDefinitionConstants.KeyAttribute); - string value = GetAttributeValue(addElement, ObjectDefinitionConstants.ValueAttribute); - string delimiters = GetAttributeValue(addElement, ObjectDefinitionConstants.DelimitersAttribute); - - if (StringUtils.HasText(delimiters)) - { - string[] values = value.Split(delimiters.ToCharArray()); - foreach (string v in values) - { - nvc.Add(key, v); - } - } - else - { - nvc.Add(key, value); - } + mode = (AutoWiringMode) Enum.Parse( + typeof(AutoWiringMode), value, true); } - return nvc; - } - - /// - /// Returns the text of the supplied , - /// or the empty string value if said is empty. - /// - /// - ///

- /// If the supplied is , - /// then the empty string value will be returned. - ///

- ///
- protected string ParseTextValueElement(XmlElement element, string name) - { - if (element == null) return string.Empty; - - string innerText = element.InnerText; - // check the xml:space attribute - bool preserveWhitespace = 0 == string.Compare("preserve", element.GetAttribute("space", "http://www.w3.org/XML/1998/namespace"), true); - bool isEmpty = preserveWhitespace ? innerText.Length == 0 : StringUtils.IsNullOrEmpty(innerText); - return isEmpty ? String.Empty : innerText; - } - - /// - /// Strips the dependency check value out of the supplied string. - /// - /// - ///

- /// If the supplied is an invalid dependency - /// checking mode, the invalid value will be logged and this method will - /// return the value. - /// No exception will be raised. - ///

- ///
- /// - /// The string containing the dependency check value. - /// - /// The dependency check value. - /// - protected DependencyCheckingMode GetDependencyCheck(string value) - { - DependencyCheckingMode code = DependencyCheckingMode.None; - if (StringUtils.HasText(value)) + catch (ArgumentException ex) { - try - { - code = (DependencyCheckingMode)Enum.Parse( - typeof(DependencyCheckingMode), value, true); - } - catch (ArgumentException ex) - { - #region Instrumentation + #region Instrumentation - if (log.IsEnabled(LogLevel.Debug)) - { - string message = string.Format("Error while parsing dependency checking mode : '{0}' is an invalid value.", - value); - log.LogDebug(ex, message); - } - - #endregion + if (log.IsEnabled(LogLevel.Debug)) + { + string message = string.Format("Error while parsing autowire mode : '{0}' is an invalid value.", + value); + log.LogDebug(ex, message); } + + #endregion } - return code; } - /// - /// Strips the autowiring mode out of the supplied string. - /// - /// - ///

- /// If the supplied is an invalid autowiring mode, - /// the invalid value will be logged and this method will return the - /// value. No exception will be raised. - ///

- ///
- /// - /// The string containing the autowiring mode definition. - /// - /// The autowiring mode. - /// - protected AutoWiringMode GetAutowireMode(string value) - { - AutoWiringMode mode = AutoWiringMode.No; - if (StringUtils.HasText(value)) - { - try - { - mode = (AutoWiringMode)Enum.Parse( - typeof(AutoWiringMode), value, true); - } - catch (ArgumentException ex) - { - #region Instrumentation + return mode; + } - if (log.IsEnabled(LogLevel.Debug)) - { - string message = string.Format("Error while parsing autowire mode : '{0}' is an invalid value.", - value); - log.LogDebug(ex, message); - } + /// + /// Given a string containing delimited object names, returns + /// a string array split on the object name delimeter. + /// + /// + /// The string containing delimited object names. + /// + /// + /// A string array split on the object name delimeter. + /// + /// + private string[] GetObjectNames(string value) + { + return StringUtils.Split( + value, ObjectDefinitionConstants.ObjectNameDelimiters, true, true); + } - #endregion - } - } - return mode; - } + private static bool IsTrueStringValue(string value) + { + return ObjectDefinitionConstants.TrueValue.Equals(value); + } - /// - /// Given a string containing delimited object names, returns - /// a string array split on the object name delimeter. - /// - /// - /// The string containing delimited object names. - /// - /// - /// A string array split on the object name delimeter. - /// - /// - private string[] GetObjectNames(string value) - { - return StringUtils.Split( - value, ObjectDefinitionConstants.ObjectNameDelimiters, true, true); - } - - private static bool IsTrueStringValue(string value) - { - return ObjectDefinitionConstants.TrueValue.Equals(value); - } - - private string GetNamespacePrefix(XmlElement element) - { - return StringUtils.HasText(element.Prefix) ? element.Prefix : "spring"; - } + private string GetNamespacePrefix(XmlElement element) + { + return StringUtils.HasText(element.Prefix) ? element.Prefix : "spring"; + } // /// // /// Returns the value of the element's attribute or null, if the attribute is not specified. @@ -1577,5 +1621,4 @@ namespace Spring.Objects.Factory.Xml // } // return defaultValue; // } - } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Xml/ParserContext.cs b/src/Spring/Spring.Core/Objects/Factory/Xml/ParserContext.cs index 900be545..aa065bc4 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Xml/ParserContext.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Xml/ParserContext.cs @@ -21,103 +21,97 @@ using Spring.Objects.Factory.Config; using Spring.Objects.Factory.Support; -namespace Spring.Objects.Factory.Xml +namespace Spring.Objects.Factory.Xml; + +/// +/// Context that gets passed along an object definition parsing process, encapsulating +/// all relevant configuraiton as well as state. +/// +public class ParserContext { - /// - /// Context that gets passed along an object definition parsing process, encapsulating - /// all relevant configuraiton as well as state. - /// - public class ParserContext - { - private readonly XmlReaderContext readerContext; + private readonly XmlReaderContext readerContext; - private readonly ObjectDefinitionParserHelper parserHelper; + private readonly ObjectDefinitionParserHelper parserHelper; - private readonly IObjectDefinition containingObjectDefinition; + private readonly IObjectDefinition containingObjectDefinition; // private Stack containingComponents = new Stack(); - /// - /// Initializes a new instance of the class. - /// - /// The parser helper. - public ParserContext(ObjectDefinitionParserHelper parserHelper) - { - this.readerContext = parserHelper.ReaderContext; - this.parserHelper = parserHelper; - } + /// + /// Initializes a new instance of the class. + /// + /// The parser helper. + public ParserContext(ObjectDefinitionParserHelper parserHelper) + { + this.readerContext = parserHelper.ReaderContext; + this.parserHelper = parserHelper; + } + /// + /// Initializes a new instance of the class. + /// + /// The parser helper. + /// The containing object definition. + public ParserContext(ObjectDefinitionParserHelper parserHelper, IObjectDefinition containingObjectDefinition) + { + this.readerContext = parserHelper.ReaderContext; + this.parserHelper = parserHelper; + this.containingObjectDefinition = containingObjectDefinition; + } - /// - /// Initializes a new instance of the class. - /// - /// The parser helper. - /// The containing object definition. - public ParserContext(ObjectDefinitionParserHelper parserHelper, IObjectDefinition containingObjectDefinition) - { - this.readerContext = parserHelper.ReaderContext; - this.parserHelper = parserHelper; - this.containingObjectDefinition = containingObjectDefinition; - } + /// + /// Gets the reader context. + /// + /// The reader context. + public XmlReaderContext ReaderContext + { + get { return readerContext; } + } - /// - /// Gets the reader context. - /// - /// The reader context. - public XmlReaderContext ReaderContext - { - get { return readerContext; } - } + /// + /// Gets the registry. + /// + /// The registry. + public IObjectDefinitionRegistry Registry + { + get { return readerContext.Registry; } + } - /// - /// Gets the registry. - /// - /// The registry. - public IObjectDefinitionRegistry Registry - { - get { return readerContext.Registry; } - } + /// + /// Gets the parser helper. + /// + /// The parser helper. + public ObjectDefinitionParserHelper ParserHelper + { + get { return parserHelper; } + } + /// + /// Gets the containing object definition. + /// + /// The containing object definition. + public IObjectDefinition ContainingObjectDefinition + { + get { return containingObjectDefinition; } + } - /// - /// Gets the parser helper. - /// - /// The parser helper. - public ObjectDefinitionParserHelper ParserHelper - { - get { return parserHelper; } - } - - - /// - /// Gets the containing object definition. - /// - /// The containing object definition. - public IObjectDefinition ContainingObjectDefinition - { - get { return containingObjectDefinition; } - } - - /// - /// Gets a value indicating whether this instance is nested. - /// - /// true if this instance is nested; otherwise, false. - public bool IsNested - { - get { return containingObjectDefinition != null; } - } - - /// - /// Gets a value indicating whether this instance is default lazy init. - /// - /// - /// true if this instance is default lazy init; otherwise, false. - /// - public bool IsDefaultLazyInit - { - get { return ObjectDefinitionConstants.TrueValue.Equals(ParserHelper.Defaults.LazyInit); } - } - + /// + /// Gets a value indicating whether this instance is nested. + /// + /// true if this instance is nested; otherwise, false. + public bool IsNested + { + get { return containingObjectDefinition != null; } + } + /// + /// Gets a value indicating whether this instance is default lazy init. + /// + /// + /// true if this instance is default lazy init; otherwise, false. + /// + public bool IsDefaultLazyInit + { + get { return ObjectDefinitionConstants.TrueValue.Equals(ParserHelper.Defaults.LazyInit); } } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Xml/ReplacedMethodOverride.cs b/src/Spring/Spring.Core/Objects/Factory/Xml/ReplacedMethodOverride.cs index 9c02f43c..f6aa019f 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Xml/ReplacedMethodOverride.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Xml/ReplacedMethodOverride.cs @@ -23,132 +23,135 @@ using System.Reflection; using System.Text; using Spring.Util; -namespace Spring.Objects.Factory.Support +namespace Spring.Objects.Factory.Support; + +/// +/// Represents the replacement of a method on a managed object by the IoC +/// container. +/// +/// +///

+/// Note that this mechanism is not intended as a generic means of +/// inserting crosscutting code: use AOP for that. +///

+///
+/// Rod Johnson +/// Rick Evans (.NET) +[Serializable] +public sealed class ReplacedMethodOverride : MethodOverride { - /// - /// Represents the replacement of a method on a managed object by the IoC - /// container. - /// - /// - ///

- /// Note that this mechanism is not intended as a generic means of - /// inserting crosscutting code: use AOP for that. - ///

- ///
- /// Rod Johnson - /// Rick Evans (.NET) - [Serializable] - public sealed class ReplacedMethodOverride : MethodOverride - { - private readonly string methodReplacerObjectName; - private StringCollection typeIdentifiers = new StringCollection(); + private readonly string methodReplacerObjectName; + private StringCollection typeIdentifiers = new StringCollection(); - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The name of the method that is to be overridden. - /// - /// - /// The object name of the - /// instance in the surrounding IoC container. - /// - /// - /// If either of the supplied arguments is or - /// contains only whitespace character(s). - /// - public ReplacedMethodOverride(string methodName, string methodReplacerObjectName) - : base(methodName) - { - AssertUtils.ArgumentHasText(methodReplacerObjectName, "methodReplacerObjectName"); - this.methodReplacerObjectName = methodReplacerObjectName; - } + /// + /// Creates a new instance of the + /// class. + /// + /// + /// The name of the method that is to be overridden. + /// + /// + /// The object name of the + /// instance in the surrounding IoC container. + /// + /// + /// If either of the supplied arguments is or + /// contains only whitespace character(s). + /// + public ReplacedMethodOverride(string methodName, string methodReplacerObjectName) + : base(methodName) + { + AssertUtils.ArgumentHasText(methodReplacerObjectName, "methodReplacerObjectName"); + this.methodReplacerObjectName = methodReplacerObjectName; + } - /// - /// Add a fragment of a instance's - /// such as 'Exception or System.Excep to identify an argument - /// for a dependency injected method. - /// - /// - /// A (sub) string of a instance's . - /// - /// - /// If the supplied is or - /// contains only whitespace character(s). - /// - /// - public void AddTypeIdentifier(string identifier) - { - AssertUtils.ArgumentHasText(identifier, "identifier"); - this.typeIdentifiers.Add(identifier); - } + /// + /// Add a fragment of a instance's + /// such as 'Exception or System.Excep to identify an argument + /// for a dependency injected method. + /// + /// + /// A (sub) string of a instance's . + /// + /// + /// If the supplied is or + /// contains only whitespace character(s). + /// + /// + public void AddTypeIdentifier(string identifier) + { + AssertUtils.ArgumentHasText(identifier, "identifier"); + this.typeIdentifiers.Add(identifier); + } - /// - /// The object name of the - /// instance in the surrounding IoC container. - /// - public string MethodReplacerObjectName - { - get { return methodReplacerObjectName; } - } + /// + /// The object name of the + /// instance in the surrounding IoC container. + /// + public string MethodReplacerObjectName + { + get { return methodReplacerObjectName; } + } - /// - /// Does this - /// match the supplied ? - /// - /// The method to be checked. - /// - /// if this override matches the supplied . - /// - /// - /// If the supplied is . - /// - public override bool Matches(MethodInfo method) - { - AssertUtils.ArgumentNotNull(method, "method"); - if (MethodName != method.Name && !(method.Name.EndsWith(MethodName))) - { - // can't ever match... - return false; - } - if (!IsOverloaded) - { - // no need to worry about overloading... - return true; - } - // if we get to here, we need to insist on precise argument matching... - ParameterInfo[] parameters = method.GetParameters(); - if (this.typeIdentifiers.Count != parameters.Length) - { - return false; - } - for (int i = 0; i < typeIdentifiers.Count; ++i) - { - string identifier = this.typeIdentifiers[i]; - ParameterInfo parameter = parameters[i]; - if (parameter.ParameterType.FullName.IndexOf(identifier) == -1) - { - // this parameter cannot match, so neither can the whole override... - return false; - } - } - return true; - } + /// + /// Does this + /// match the supplied ? + /// + /// The method to be checked. + /// + /// if this override matches the supplied . + /// + /// + /// If the supplied is . + /// + public override bool Matches(MethodInfo method) + { + AssertUtils.ArgumentNotNull(method, "method"); + if (MethodName != method.Name && !(method.Name.EndsWith(MethodName))) + { + // can't ever match... + return false; + } - /// - /// A that represents the current - /// . - /// - /// - /// A that represents the current - /// . - /// - public override string ToString() - { - return new StringBuilder(GetType().Name).Append(" for method '") - .Append(MethodName).Append("'; will call object '").Append(this.methodReplacerObjectName) - .Append("'.").ToString(); - } - } + if (!IsOverloaded) + { + // no need to worry about overloading... + return true; + } + + // if we get to here, we need to insist on precise argument matching... + ParameterInfo[] parameters = method.GetParameters(); + if (this.typeIdentifiers.Count != parameters.Length) + { + return false; + } + + for (int i = 0; i < typeIdentifiers.Count; ++i) + { + string identifier = this.typeIdentifiers[i]; + ParameterInfo parameter = parameters[i]; + if (parameter.ParameterType.FullName.IndexOf(identifier) == -1) + { + // this parameter cannot match, so neither can the whole override... + return false; + } + } + + return true; + } + + /// + /// A that represents the current + /// . + /// + /// + /// A that represents the current + /// . + /// + public override string ToString() + { + return new StringBuilder(GetType().Name).Append(" for method '") + .Append(MethodName).Append("'; will call object '").Append(this.methodReplacerObjectName) + .Append("'.").ToString(); + } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Xml/XmlObjectDefinitionReader.cs b/src/Spring/Spring.Core/Objects/Factory/Xml/XmlObjectDefinitionReader.cs index 19b0d1fa..bec4e5bb 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Xml/XmlObjectDefinitionReader.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Xml/XmlObjectDefinitionReader.cs @@ -30,424 +30,432 @@ using Spring.Util; #endregion -namespace Spring.Objects.Factory.Xml +namespace Spring.Objects.Factory.Xml; + +/// +/// Object definition reader for Spring's default XML object definition format. +/// +/// +///

+/// Typically applied to a +/// instance. +///

+///

+/// This class registers each object definition with the given object factory superclass, +/// and relies on the latter's implementation of the +/// interface. +///

+///

+/// It supports singletons, prototypes, and references to either of these kinds of object. +///

+///
+/// Juergen Hoeller +/// Rick Evans (.NET) +public class XmlObjectDefinitionReader : AbstractObjectDefinitionReader { + #region Utility Classes + /// - /// Object definition reader for Spring's default XML object definition format. + /// For retrying the parse process /// - /// - ///

- /// Typically applied to a - /// instance. - ///

- ///

- /// This class registers each object definition with the given object factory superclass, - /// and relies on the latter's implementation of the - /// interface. - ///

- ///

- /// It supports singletons, prototypes, and references to either of these kinds of object. - ///

- ///
- /// Juergen Hoeller - /// Rick Evans (.NET) - public class XmlObjectDefinitionReader : AbstractObjectDefinitionReader + private class RetryParseException : Exception { - #region Utility Classes - - /// - /// For retrying the parse process - /// - private class RetryParseException : Exception + public RetryParseException() { - public RetryParseException() - { } + } + } + + #endregion + + #region Fields + + [NonSerialized] private XmlResolver resolver; + + private Type documentReaderType; + private INamespaceParserResolver namespaceParserResolver; + private IObjectDefinitionFactory objectDefinitionFactory; + + #endregion + + #region Constructor (s) / Destructor + + /// + /// Creates a new instance of the + /// class. + /// + /// + /// The + /// instance that this reader works on. + /// + public XmlObjectDefinitionReader(IObjectDefinitionRegistry registry) + : this(registry, new XmlUrlResolver()) + { + } + + /// + /// Creates a new instance of the + /// class. + /// + /// + /// The + /// instance that this reader works on. + /// + /// + /// The to be used for parsing. + /// + public XmlObjectDefinitionReader(IObjectDefinitionRegistry registry, XmlResolver resolver) + : this(registry, resolver, new DefaultObjectDefinitionFactory()) + { + Resolver = resolver; + } + + /// + /// Creates a new instance of the + /// class. + /// + /// + /// The + /// instance that this reader works on. + /// + /// + /// The to be used for parsing. + /// + /// the to use for creating new s + protected XmlObjectDefinitionReader(IObjectDefinitionRegistry registry, XmlResolver resolver, IObjectDefinitionFactory objectDefinitionFactory) + : base(registry) + { + Resolver = resolver; + this.objectDefinitionFactory = objectDefinitionFactory; + } + + #endregion + + #region Properties + + /// + /// The to be used for parsing. + /// + public XmlResolver Resolver + { + get { return resolver; } + set { resolver = value; } + } + + /// + /// Sets the IObjectDefinitionDocumentReader implementation to use, responsible for + /// the actual reading of the XML object definition document.stype of the document reader. + /// + /// The type of the document reader. + public Type DocumentReaderType + { + set + { + if (value == null || !typeof(IObjectDefinitionDocumentReader).IsAssignableFrom(value)) + { + throw new ArgumentException( + "DocumentReaderType must be an implementation of the IObjectDefinitionReader interface."); + } + + documentReaderType = value; + } + } + + /// + /// Specify a to use. If none is specified a default + /// instance will be created by + /// + internal INamespaceParserResolver NamespaceParserResolver + { + get + { + if (this.namespaceParserResolver == null) + { + this.namespaceParserResolver = CreateDefaultNamespaceParserResolver(); + } + + return this.namespaceParserResolver; + } + set + { + if (this.namespaceParserResolver != null) + { + throw new InvalidOperationException("NamespaceParserResolver is already set"); + } + + this.namespaceParserResolver = value; + } + } + + /// + /// Specify a for creating instances of . + /// + protected IObjectDefinitionFactory ObjectDefinitionFactory + { + get + { + return this.objectDefinitionFactory; + } + } + + #endregion + + #region Methods + + /// + /// Load object definitions from the supplied XML . + /// + /// + /// The XML resource for the object definitions that are to be loaded. + /// + /// + /// The number of object definitions that were loaded. + /// + /// + /// In the case of loading or parsing errors. + /// + public override int LoadObjectDefinitions(IResource resource) + { + if (resource == null) + { + throw new ObjectDefinitionStoreException + ("Resource cannot be null: expected an XML resource."); + } + + #region Instrumentation + + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug("Loading XML object definitions from " + resource); } #endregion - #region Fields - - [NonSerialized] - private XmlResolver resolver; - - private Type documentReaderType; - private INamespaceParserResolver namespaceParserResolver; - private IObjectDefinitionFactory objectDefinitionFactory; - - #endregion - - #region Constructor (s) / Destructor - - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The - /// instance that this reader works on. - /// - public XmlObjectDefinitionReader(IObjectDefinitionRegistry registry) - : this(registry, new XmlUrlResolver()) - { } - - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The - /// instance that this reader works on. - /// - /// - /// The to be used for parsing. - /// - public XmlObjectDefinitionReader(IObjectDefinitionRegistry registry, XmlResolver resolver) - : this(registry, resolver, new DefaultObjectDefinitionFactory()) + try { - Resolver = resolver; - } - - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The - /// instance that this reader works on. - /// - /// - /// The to be used for parsing. - /// - /// the to use for creating new s - protected XmlObjectDefinitionReader(IObjectDefinitionRegistry registry, XmlResolver resolver, IObjectDefinitionFactory objectDefinitionFactory) - : base(registry) - { - Resolver = resolver; - this.objectDefinitionFactory = objectDefinitionFactory; - } - - #endregion - - #region Properties - - /// - /// The to be used for parsing. - /// - public XmlResolver Resolver - { - get { return resolver; } - set { resolver = value; } - } - - - /// - /// Sets the IObjectDefinitionDocumentReader implementation to use, responsible for - /// the actual reading of the XML object definition document.stype of the document reader. - /// - /// The type of the document reader. - public Type DocumentReaderType - { - set - { - if (value == null || !typeof(IObjectDefinitionDocumentReader).IsAssignableFrom(value)) - { - throw new ArgumentException( - "DocumentReaderType must be an implementation of the IObjectDefinitionReader interface."); - } - documentReaderType = value; - } - } - - /// - /// Specify a to use. If none is specified a default - /// instance will be created by - /// - internal INamespaceParserResolver NamespaceParserResolver - { - get - { - if (this.namespaceParserResolver == null) - { - this.namespaceParserResolver = CreateDefaultNamespaceParserResolver(); - } - return this.namespaceParserResolver; - } - set - { - if (this.namespaceParserResolver != null) - { - throw new InvalidOperationException("NamespaceParserResolver is already set"); - } - this.namespaceParserResolver = value; - } - } - - /// - /// Specify a for creating instances of . - /// - protected IObjectDefinitionFactory ObjectDefinitionFactory - { - get - { - return this.objectDefinitionFactory; - } - } - - #endregion - - #region Methods - - /// - /// Load object definitions from the supplied XML . - /// - /// - /// The XML resource for the object definitions that are to be loaded. - /// - /// - /// The number of object definitions that were loaded. - /// - /// - /// In the case of loading or parsing errors. - /// - public override int LoadObjectDefinitions(IResource resource) - { - if (resource == null) - { - throw new ObjectDefinitionStoreException - ("Resource cannot be null: expected an XML resource."); - } - - #region Instrumentation - - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug("Loading XML object definitions from " + resource); - } - - #endregion - - try - { - Stream stream = resource.InputStream; - if (stream == null) - { - throw new ObjectDefinitionStoreException( - "InputStream is null from Resource = [" + resource + "]"); - } - try - { - return DoLoadObjectDefinitions(stream, resource); - } - finally - { - #region Close stream - try - { - stream.Close(); - } - catch (IOException ex) - { - #region Instrumentation - - if (log.IsEnabled(LogLevel.Warning)) - { - log.LogWarning(ex, "Could not close stream."); - } - - #endregion - } - #endregion - } - } - catch (IOException ex) + Stream stream = resource.InputStream; + if (stream == null) { throw new ObjectDefinitionStoreException( - "IOException parsing XML document from " + resource.Description, ex); + "InputStream is null from Resource = [" + resource + "]"); } - } - - /// - /// Actually load object definitions from the specified XML file. - /// - /// The input stream to read from. - /// The resource for the XML data. - /// - protected virtual int DoLoadObjectDefinitions(Stream stream, IResource resource) - { try { - // create local copy of data - byte[] xmlData = IOUtils.ToByteArray(stream); + return DoLoadObjectDefinitions(stream, resource); + } + finally + { + #region Close stream - XmlDocument doc; - // loop until no unregistered, wellknown namespaces left - while (true) + try { - XmlReader reader = null; - try - { - MemoryStream xmlDataStream = new MemoryStream(xmlData); - reader = CreateValidatingReader(xmlDataStream); - doc = new ConfigXmlDocument(); - doc.Load(reader); - break; - } - catch (RetryParseException) - { - if (reader != null) - reader.Close(); - } + stream.Close(); } - return RegisterObjectDefinitions(doc, resource); - } - catch (XmlException ex) - { - throw new ObjectDefinitionStoreException(resource.Description, - "Line " + ex.LineNumber + " in XML document from " + - resource + " is not well formed. " + ex.Message, ex); - } - catch (XmlSchemaException ex) - { - throw new ObjectDefinitionStoreException(resource.Description, - "Line " + ex.LineNumber + " in XML document from " + - resource + " violates the schema. " + ex.Message, ex); - } - catch (ObjectDefinitionStoreException) - { - throw; - } - catch (Exception ex) - { - throw new ObjectDefinitionStoreException("Unexpected exception parsing XML document from " + resource.Description + "Inner exception message= " + ex.Message, ex); - } - } - - private XmlReader CreateValidatingReader(MemoryStream stream) - { - XmlReader reader; - if (SystemUtils.MonoRuntime) - { - reader = XmlUtils.CreateReader(stream); - } - else - { - reader = XmlUtils.CreateValidatingReader(stream, Resolver, NamespaceParserRegistry.GetSchemas(), HandleValidation); - } - - #region Instrumentation - - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug("Using the following XmlReader implementation : " + reader.GetType()); - } - return reader; - - #endregion - } - - /// - /// Validation callback for a validating XML reader. - /// - /// The source of the event. - /// Any data pertinent to the event. - private void HandleValidation(object sender, ValidationEventArgs args) - { - if (args.Severity == XmlSeverityType.Error) - { - XmlSchemaException ex = args.Exception; - XmlReader xmlReader = (XmlReader)sender; - if (!NamespaceParserRegistry.GetSchemas().Contains(xmlReader.NamespaceURI) && ex is XmlSchemaValidationException) + catch (IOException ex) { - // try wellknown parsers - bool registered = NamespaceParserRegistry.RegisterWellknownNamespaceParserType(xmlReader.NamespaceURI); - if (registered) + #region Instrumentation + + if (log.IsEnabled(LogLevel.Warning)) { - throw new RetryParseException(); + log.LogWarning(ex, "Could not close stream."); } - } - throw ex; - } - else - { - #region Instrumentation - if (log.IsEnabled(LogLevel.Warning)) - { - string message = "Ignored XML validation warning: " + args.Message; - log.LogWarning(args.Exception, message); + #endregion } #endregion } } - - /// - /// Register the object definitions contained in the given DOM document. - /// - /// The DOM document. - /// - /// The original resource from where the - /// was read. - /// - /// - /// The number of object definitions that were registered. - /// - /// - /// In case of parsing errors. - /// - public int RegisterObjectDefinitions( - XmlDocument doc, IResource resource) + catch (IOException ex) { - IObjectDefinitionDocumentReader documentReader = CreateObjectDefinitionDocumentReader(); - - //TODO make void return and get object count from registry. - int countBefore = Registry.ObjectDefinitionCount; - XmlReaderContext readerContext = CreateReaderContext(resource); - readerContext.NamespaceParserResolver = this.NamespaceParserResolver; - documentReader.RegisterObjectDefinitions(doc, readerContext); - return Registry.ObjectDefinitionCount - countBefore; + throw new ObjectDefinitionStoreException( + "IOException parsing XML document from " + resource.Description, ex); } + } - /// - /// Creates the to use for actually - /// reading object definitions from an XML document. - /// - /// Default implementation instantiates the specified - /// or if no reader type is specified. - /// - protected virtual IObjectDefinitionDocumentReader CreateObjectDefinitionDocumentReader() + /// + /// Actually load object definitions from the specified XML file. + /// + /// The input stream to read from. + /// The resource for the XML data. + /// + protected virtual int DoLoadObjectDefinitions(Stream stream, IResource resource) + { + try { - if (documentReaderType == null) + // create local copy of data + byte[] xmlData = IOUtils.ToByteArray(stream); + + XmlDocument doc; + // loop until no unregistered, wellknown namespaces left + while (true) { - return new DefaultObjectDefinitionDocumentReader(); + XmlReader reader = null; + try + { + MemoryStream xmlDataStream = new MemoryStream(xmlData); + reader = CreateValidatingReader(xmlDataStream); + doc = new ConfigXmlDocument(); + doc.Load(reader); + break; + } + catch (RetryParseException) + { + if (reader != null) + reader.Close(); + } } - return (IObjectDefinitionDocumentReader)ObjectUtils.InstantiateType(documentReaderType); + + return RegisterObjectDefinitions(doc, resource); + } + catch (XmlException ex) + { + throw new ObjectDefinitionStoreException(resource.Description, + "Line " + ex.LineNumber + " in XML document from " + + resource + " is not well formed. " + ex.Message, ex); + } + catch (XmlSchemaException ex) + { + throw new ObjectDefinitionStoreException(resource.Description, + "Line " + ex.LineNumber + " in XML document from " + + resource + " violates the schema. " + ex.Message, ex); + } + catch (ObjectDefinitionStoreException) + { + throw; + } + catch (Exception ex) + { + throw new ObjectDefinitionStoreException("Unexpected exception parsing XML document from " + resource.Description + "Inner exception message= " + ex.Message, ex); + } + } + + private XmlReader CreateValidatingReader(MemoryStream stream) + { + XmlReader reader; + if (SystemUtils.MonoRuntime) + { + reader = XmlUtils.CreateReader(stream); + } + else + { + reader = XmlUtils.CreateValidatingReader(stream, Resolver, NamespaceParserRegistry.GetSchemas(), HandleValidation); } - /// - /// Creates the to be passed along - /// during the object definition reading process. - /// - /// The underlying that is currently processed. - /// A new - protected virtual XmlReaderContext CreateReaderContext(IResource resource) + #region Instrumentation + + if (log.IsEnabled(LogLevel.Debug)) { - return new XmlReaderContext(resource, this, this.objectDefinitionFactory); + log.LogDebug("Using the following XmlReader implementation : " + reader.GetType()); } - /// - /// Create a instance for handling custom namespaces. - /// - /// - /// TODO (EE): make protected virtual, see remarks on - /// - private INamespaceParserResolver CreateDefaultNamespaceParserResolver() - { - return new DefaultNamespaceHandlerResolver(); - } + return reader; #endregion } + + /// + /// Validation callback for a validating XML reader. + /// + /// The source of the event. + /// Any data pertinent to the event. + private void HandleValidation(object sender, ValidationEventArgs args) + { + if (args.Severity == XmlSeverityType.Error) + { + XmlSchemaException ex = args.Exception; + XmlReader xmlReader = (XmlReader) sender; + if (!NamespaceParserRegistry.GetSchemas().Contains(xmlReader.NamespaceURI) && ex is XmlSchemaValidationException) + { + // try wellknown parsers + bool registered = NamespaceParserRegistry.RegisterWellknownNamespaceParserType(xmlReader.NamespaceURI); + if (registered) + { + throw new RetryParseException(); + } + } + + throw ex; + } + else + { + #region Instrumentation + + if (log.IsEnabled(LogLevel.Warning)) + { + string message = "Ignored XML validation warning: " + args.Message; + log.LogWarning(args.Exception, message); + } + + #endregion + } + } + + /// + /// Register the object definitions contained in the given DOM document. + /// + /// The DOM document. + /// + /// The original resource from where the + /// was read. + /// + /// + /// The number of object definitions that were registered. + /// + /// + /// In case of parsing errors. + /// + public int RegisterObjectDefinitions( + XmlDocument doc, IResource resource) + { + IObjectDefinitionDocumentReader documentReader = CreateObjectDefinitionDocumentReader(); + + //TODO make void return and get object count from registry. + int countBefore = Registry.ObjectDefinitionCount; + XmlReaderContext readerContext = CreateReaderContext(resource); + readerContext.NamespaceParserResolver = this.NamespaceParserResolver; + documentReader.RegisterObjectDefinitions(doc, readerContext); + return Registry.ObjectDefinitionCount - countBefore; + } + + /// + /// Creates the to use for actually + /// reading object definitions from an XML document. + /// + /// Default implementation instantiates the specified + /// or if no reader type is specified. + /// + protected virtual IObjectDefinitionDocumentReader CreateObjectDefinitionDocumentReader() + { + if (documentReaderType == null) + { + return new DefaultObjectDefinitionDocumentReader(); + } + + return (IObjectDefinitionDocumentReader) ObjectUtils.InstantiateType(documentReaderType); + } + + /// + /// Creates the to be passed along + /// during the object definition reading process. + /// + /// The underlying that is currently processed. + /// A new + protected virtual XmlReaderContext CreateReaderContext(IResource resource) + { + return new XmlReaderContext(resource, this, this.objectDefinitionFactory); + } + + /// + /// Create a instance for handling custom namespaces. + /// + /// + /// TODO (EE): make protected virtual, see remarks on + /// + private INamespaceParserResolver CreateDefaultNamespaceParserResolver() + { + return new DefaultNamespaceHandlerResolver(); + } + + #endregion } diff --git a/src/Spring/Spring.Core/Objects/Factory/Xml/XmlObjectFactory.cs b/src/Spring/Spring.Core/Objects/Factory/Xml/XmlObjectFactory.cs index 2161aca8..23029ba7 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Xml/XmlObjectFactory.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Xml/XmlObjectFactory.cs @@ -17,116 +17,116 @@ using Spring.Core.IO; using Spring.Objects.Factory.Support; -namespace Spring.Objects.Factory.Xml +namespace Spring.Objects.Factory.Xml; + +/// +/// Convenience extension of +/// +/// that reads object definitions from an XML document or element. +/// +/// +///

+/// Delegates to +/// +/// underneath; effectively equivalent to using a +/// for a +/// . +///

+/// +/// objects doesn't need to be the root element of +/// the XML document: this class will parse all object definition elements in the +/// XML stream. +/// +///

+/// This class registers each object definition with the +/// +/// superclass, and relies on the latter's implementation of the +/// interface. It supports +/// singletons, prototypes and references to either of these kinds of object. +///

+///
+/// Rod Johnson +/// Juergen Hoeller +/// Rick Evans (.NET) +/// +[Serializable] +public class XmlObjectFactory : DefaultListableObjectFactory { - /// - /// Convenience extension of - /// - /// that reads object definitions from an XML document or element. - /// - /// - ///

- /// Delegates to - /// - /// underneath; effectively equivalent to using a - /// for a - /// . - ///

- /// - /// objects doesn't need to be the root element of - /// the XML document: this class will parse all object definition elements in the - /// XML stream. - /// - ///

- /// This class registers each object definition with the - /// - /// superclass, and relies on the latter's implementation of the - /// interface. It supports - /// singletons, prototypes and references to either of these kinds of object. - ///

- ///
- /// Rod Johnson - /// Juergen Hoeller - /// Rick Evans (.NET) - /// - [Serializable] - public class XmlObjectFactory : DefaultListableObjectFactory - { - /// - /// Creates a new instance of the class, - /// with the given resource, which must be parsable using DOM. - /// - /// - /// The XML resource to load object definitions from. - /// - /// - /// In the case of loading or parsing errors. - /// - public XmlObjectFactory(IResource resource) : this(resource, true, null) + /// + /// Creates a new instance of the class, + /// with the given resource, which must be parsable using DOM. + /// + /// + /// The XML resource to load object definitions from. + /// + /// + /// In the case of loading or parsing errors. + /// + public XmlObjectFactory(IResource resource) : this(resource, true, null) + { + } + + /// + /// Creates a new instance of the class, + /// with the given resource, which must be parsable using DOM. + /// + /// + /// The XML resource to load object definitions from. + /// + /// Flag specifying whether to make this object factory case sensitive or not. + /// + /// In the case of loading or parsing errors. + /// + public XmlObjectFactory(IResource resource, bool caseSensitive) : this(resource, caseSensitive, null) + { + } + + /// + /// Creates a new instance of the class, + /// with the given resource, which must be parsable using DOM, and the + /// given parent factory. + /// + /// + /// The XML resource to load object definitions from. + /// + /// The parent object factory (may be ). + /// + /// In the case of loading or parsing errors. + /// + public XmlObjectFactory( + IResource resource, IObjectFactory parentFactory) + : this(resource, true, parentFactory) + { + } + + /// + /// Creates a new instance of the class, + /// with the given resource, which must be parsable using DOM, and the + /// given parent factory. + /// + /// + /// The XML resource to load object definitions from. + /// + /// Flag specifying whether to make this object factory case sensitive or not. + /// The parent object factory (may be ). + /// + /// In the case of loading or parsing errors. + /// + public XmlObjectFactory( + IResource resource, bool caseSensitive, IObjectFactory parentFactory) + : base(caseSensitive, parentFactory) + { + ObjectDefinitionReader.LoadObjectDefinitions(resource); + } + + /// + /// Gets object definition reader to use. + /// + protected virtual IObjectDefinitionReader ObjectDefinitionReader + { + get { + return new XmlObjectDefinitionReader(this); } - - /// - /// Creates a new instance of the class, - /// with the given resource, which must be parsable using DOM. - /// - /// - /// The XML resource to load object definitions from. - /// - /// Flag specifying whether to make this object factory case sensitive or not. - /// - /// In the case of loading or parsing errors. - /// - public XmlObjectFactory(IResource resource, bool caseSensitive) : this(resource, caseSensitive, null) - { - } - - /// - /// Creates a new instance of the class, - /// with the given resource, which must be parsable using DOM, and the - /// given parent factory. - /// - /// - /// The XML resource to load object definitions from. - /// - /// The parent object factory (may be ). - /// - /// In the case of loading or parsing errors. - /// - public XmlObjectFactory( - IResource resource, IObjectFactory parentFactory) - : this(resource, true, parentFactory) - {} - - /// - /// Creates a new instance of the class, - /// with the given resource, which must be parsable using DOM, and the - /// given parent factory. - /// - /// - /// The XML resource to load object definitions from. - /// - /// Flag specifying whether to make this object factory case sensitive or not. - /// The parent object factory (may be ). - /// - /// In the case of loading or parsing errors. - /// - public XmlObjectFactory( - IResource resource, bool caseSensitive, IObjectFactory parentFactory) - : base(caseSensitive, parentFactory) - { - ObjectDefinitionReader.LoadObjectDefinitions(resource); - } - - /// - /// Gets object definition reader to use. - /// - protected virtual IObjectDefinitionReader ObjectDefinitionReader - { - get - { - return new XmlObjectDefinitionReader(this); - } - } - } + } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Xml/XmlReaderContext.cs b/src/Spring/Spring.Core/Objects/Factory/Xml/XmlReaderContext.cs index 2ef4b60e..2d508e56 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Xml/XmlReaderContext.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Xml/XmlReaderContext.cs @@ -25,228 +25,230 @@ using Spring.Objects.Factory.Parsing; using Spring.Objects.Factory.Support; using Spring.Util; -namespace Spring.Objects.Factory.Xml +namespace Spring.Objects.Factory.Xml; + +/// +/// Extension of specific to use with an XmlObjectDefinitionReader. +/// Provides access to configured in +/// +public class XmlReaderContext : ReaderContext { + private readonly IObjectDefinitionReader reader; + private readonly IObjectDefinitionFactory objectDefinitionFactory; + private INamespaceParserResolver namespaceParserResolver; + /// - /// Extension of specific to use with an XmlObjectDefinitionReader. - /// Provides access to configured in + /// The maximum length of any XML fragment displayed in the error message + /// reporting. /// - public class XmlReaderContext : ReaderContext + /// + ///

+ /// Hopefully this will display enough context so that a user + /// can pinpoint the cause of the error. + ///

+ ///
+ private const int MaxXmlErrorFragmentLength = 255; + + /// + /// Initializes a new instance of the class. + /// + /// The resource. + /// The reader. + public XmlReaderContext(IResource resource, IObjectDefinitionReader reader) + : this(resource, reader, new DefaultObjectDefinitionFactory()) { - private readonly IObjectDefinitionReader reader; - private readonly IObjectDefinitionFactory objectDefinitionFactory; - private INamespaceParserResolver namespaceParserResolver; + } - /// - /// The maximum length of any XML fragment displayed in the error message - /// reporting. - /// - /// - ///

- /// Hopefully this will display enough context so that a user - /// can pinpoint the cause of the error. - ///

- ///
- private const int MaxXmlErrorFragmentLength = 255; - - /// - /// Initializes a new instance of the class. - /// - /// The resource. - /// The reader. - public XmlReaderContext(IResource resource, IObjectDefinitionReader reader) - : this(resource, reader, new DefaultObjectDefinitionFactory()) - {} - - /// - /// Initializes a new instance of the class. - /// - /// The resource. - /// The reader. - /// The factory to use for creating new instances. - internal XmlReaderContext(IResource resource, IObjectDefinitionReader reader, IObjectDefinitionFactory objectDefinitionFactory) - : base(resource) + /// + /// Initializes a new instance of the class. + /// + /// The resource. + /// The reader. + /// The factory to use for creating new instances. + internal XmlReaderContext(IResource resource, IObjectDefinitionReader reader, IObjectDefinitionFactory objectDefinitionFactory) + : base(resource) + { + this.reader = reader; + if (reader is XmlObjectDefinitionReader) { - this.reader = reader; - if (reader is XmlObjectDefinitionReader) - { - this.namespaceParserResolver = ((XmlObjectDefinitionReader) reader).NamespaceParserResolver; - } - this.objectDefinitionFactory = objectDefinitionFactory; + this.namespaceParserResolver = ((XmlObjectDefinitionReader) reader).NamespaceParserResolver; } - /// - /// Gets the reader. - /// - /// The reader. - public IObjectDefinitionReader Reader + this.objectDefinitionFactory = objectDefinitionFactory; + } + + /// + /// Gets the reader. + /// + /// The reader. + public IObjectDefinitionReader Reader + { + get { return reader; } + } + + /// + /// Gets the resource loader. + /// + /// The resource loader. + public IResourceLoader ResourceLoader + { + get { return reader.ResourceLoader; } + } + + /// + /// Gets the registry. + /// + /// The registry. + public IObjectDefinitionRegistry Registry + { + get { - get { return reader; } + return reader.Registry; + } + } + + /// + /// Gets or sets the object definition factory. + /// + /// The object definition factory. + public IObjectDefinitionFactory ObjectDefinitionFactory + { + get { return objectDefinitionFactory; } + } + + /// + /// Get the instance to lookup parsers for custom namespaces. + /// + internal INamespaceParserResolver NamespaceParserResolver + { + get { return namespaceParserResolver; } + set { namespaceParserResolver = value; } + } + + /// + /// Generates the name of the object. + /// + /// The object definition. + /// the generated object name + public string GenerateObjectName(IObjectDefinition objectDefinition) + { + return reader.ObjectNameGenerator.GenerateObjectName(objectDefinition, Registry); + } + + /// + /// Registers the name of the with generated. + /// + /// The object definition. + /// the generated object name + public string RegisterWithGeneratedName(IObjectDefinition objectDefinition) + { + string generatedName = GenerateObjectName(objectDefinition); + Registry.RegisterObjectDefinition(generatedName, objectDefinition); + return generatedName; + } + + /// + /// Reports a parse error by loading a + /// with helpful contextual + /// information and throwing said exception. + /// + /// + ///

+ /// Derived classes can of course override this method in order to implement + /// validators capable of displaying a full list of errors found in the + /// definition. + ///

+ ///
+ /// + /// The node that triggered the parse error. + /// + /// + /// The name of the object that triggered the exception. + /// + /// + /// A message about the exception. + /// + /// + /// Always throws an instance of this exception class, that will + /// contain helpful contextual infomation about the parse error. + /// + /// + public void ReportException(XmlNode node, string name, string message) + { + ReportException(node, name, message, null); + } + + /// + /// Reports a parse error by loading a + /// with helpful contextual + /// information and throwing said exception. + /// + /// + ///

+ /// Derived classes can of course override this method in order to implement + /// validators capable of displaying a full list of errors found in the + /// definition. + ///

+ ///
+ /// + /// The node that triggered the parse error. + /// + /// + /// The name of the object that triggered the exception. + /// + /// + /// A message about the error. + /// + /// + /// The root cause of the parse error (if any - may be ). + /// + /// + /// Always throws an instance of this exception class, that will + /// contain helpful contextual infomation about the parse error. + /// + public virtual void ReportException( + XmlNode node, string name, string message, Exception cause) + { + string xmlFragment; + + if (node is XmlAttribute) + { + xmlFragment = ((XmlAttribute) node).OwnerElement.OuterXml; + } + else + { + xmlFragment = node.OuterXml; } - /// - /// Gets the resource loader. - /// - /// The resource loader. - public IResourceLoader ResourceLoader + if (xmlFragment.Length > MaxXmlErrorFragmentLength) { - get { return reader.ResourceLoader; } + xmlFragment = xmlFragment.Substring(0, MaxXmlErrorFragmentLength) + "..."; } - /// - /// Gets the registry. - /// - /// The registry. - public IObjectDefinitionRegistry Registry + string resourceDescription = Resource.Description; + int line = ConfigurationUtils.GetLineNumber(node); + if (line > 0) { - get - { - return reader.Registry; - } + string atLine = " at line " + line; + resourceDescription += atLine; } - /// - /// Gets or sets the object definition factory. - /// - /// The object definition factory. - public IObjectDefinitionFactory ObjectDefinitionFactory - { - get { return objectDefinitionFactory; } - } - - /// - /// Get the instance to lookup parsers for custom namespaces. - /// - internal INamespaceParserResolver NamespaceParserResolver - { - get { return namespaceParserResolver; } - set { namespaceParserResolver = value; } - } - - /// - /// Generates the name of the object. - /// - /// The object definition. - /// the generated object name - public string GenerateObjectName(IObjectDefinition objectDefinition) - { - return reader.ObjectNameGenerator.GenerateObjectName(objectDefinition, Registry); - } - - /// - /// Registers the name of the with generated. - /// - /// The object definition. - /// the generated object name - public string RegisterWithGeneratedName(IObjectDefinition objectDefinition) - { - string generatedName = GenerateObjectName(objectDefinition); - Registry.RegisterObjectDefinition(generatedName, objectDefinition); - return generatedName; - } - - /// - /// Reports a parse error by loading a - /// with helpful contextual - /// information and throwing said exception. - /// - /// - ///

- /// Derived classes can of course override this method in order to implement - /// validators capable of displaying a full list of errors found in the - /// definition. - ///

- ///
- /// - /// The node that triggered the parse error. - /// - /// - /// The name of the object that triggered the exception. - /// - /// - /// A message about the exception. - /// - /// - /// Always throws an instance of this exception class, that will - /// contain helpful contextual infomation about the parse error. - /// - /// - public void ReportException(XmlNode node, string name, string message) - { - ReportException(node, name, message, null); - } - - /// - /// Reports a parse error by loading a - /// with helpful contextual - /// information and throwing said exception. - /// - /// - ///

- /// Derived classes can of course override this method in order to implement - /// validators capable of displaying a full list of errors found in the - /// definition. - ///

- ///
- /// - /// The node that triggered the parse error. - /// - /// - /// The name of the object that triggered the exception. - /// - /// - /// A message about the error. - /// - /// - /// The root cause of the parse error (if any - may be ). - /// - /// - /// Always throws an instance of this exception class, that will - /// contain helpful contextual infomation about the parse error. - /// - public virtual void ReportException( - XmlNode node, string name, string message, Exception cause) - { - string xmlFragment; - - if (node is XmlAttribute) - { - xmlFragment = ((XmlAttribute)node).OwnerElement.OuterXml; - } - else - { - xmlFragment = node.OuterXml; - } - if (xmlFragment.Length > MaxXmlErrorFragmentLength) - { - xmlFragment = xmlFragment.Substring(0, MaxXmlErrorFragmentLength) + "..."; - } - - string resourceDescription = Resource.Description; - int line = ConfigurationUtils.GetLineNumber(node); - if (line > 0) - { - string atLine = " at line " + line; - resourceDescription += atLine; - } - throw new ObjectDefinitionStoreException( - resourceDescription, name, message + Environment.NewLine + xmlFragment, cause); - } - - /// - /// This method can be overwritten in order to implement validators - /// capable of displaying a full list of errors found in the definition. - /// - /// - /// The node that triggered the parse error. - /// - /// - /// A message about the exception. - /// - public virtual void ReportFatalException(XmlNode node, string message) - { - throw new FatalObjectException(message); - } + throw new ObjectDefinitionStoreException( + resourceDescription, name, message + Environment.NewLine + xmlFragment, cause); + } + /// + /// This method can be overwritten in order to implement validators + /// capable of displaying a full list of errors found in the definition. + /// + /// + /// The node that triggered the parse error. + /// + /// + /// A message about the exception. + /// + public virtual void ReportFatalException(XmlNode node, string message) + { + throw new FatalObjectException(message); } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Xml/spring-objects-1.1.xsd b/src/Spring/Spring.Core/Objects/Factory/Xml/spring-objects-1.1.xsd index badf0ef8..c7b60ca1 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Xml/spring-objects-1.1.xsd +++ b/src/Spring/Spring.Core/Objects/Factory/Xml/spring-objects-1.1.xsd @@ -1,5 +1,10 @@ - + - + + @@ -46,10 +52,12 @@ - Defines a base type for any required string. Defines a string with a minimum length of 0 + Defines a base type for any required string. Defines a string with a minimum length of + 0 + - + @@ -60,29 +68,29 @@ Used primarily for user documentation of XML object definition documents. - + - + - + - + - - - + + + - - - + + + - + - + - + - + - - + + - - + + - + - + - + - + - - - + + + @@ -196,78 +204,78 @@ Import an external file containing object definitions into this file. - + Defines an additional alias name for an object definition. - - + + - + - - + + - - + + - - - - - + + + + + - + - - + + Defines constructor argument. - + - + - + - - - - + + + + Defines property. - + - - - - + + + + @@ -275,48 +283,48 @@ Defines a single named object. - + - + - + - + - + - - + + - + - + - + @@ -326,12 +334,12 @@ in .NET code using a name that's illegal as an XML id, use the optional "name" attribute. If neither given, the object type name is used as id. --> - + - + - - + + - + - + - + - + - - - + + + - The document root. At least one object definition is required. + The document root. At least one object definition is required. - + - - - - + + + + - + - - - - + + + + - - - - - + + + + + diff --git a/src/Spring/Spring.Core/Objects/Factory/Xml/spring-objects-1.3.xsd b/src/Spring/Spring.Core/Objects/Factory/Xml/spring-objects-1.3.xsd index 41c1eee9..2d86722d 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Xml/spring-objects-1.3.xsd +++ b/src/Spring/Spring.Core/Objects/Factory/Xml/spring-objects-1.3.xsd @@ -1,5 +1,10 @@ - + - + + @@ -46,10 +52,12 @@ - Defines a base type for any required string. Defines a string with a minimum length of 0 + Defines a base type for any required string. Defines a string with a minimum length of + 0 + - + @@ -60,29 +68,29 @@ Used primarily for user documentation of XML object definition documents. - + - + - + - + - - - + + + - - - + + + - + - + - + - + - - - + + + - - - + + + - + - + - + - + - - - + + + - + Import an external file containing object definitions into this file. - + Defines an additional alias name for an object definition. - - + + - + - - - + + + - - + + - - - - - + + + + + - + - - + + Defines constructor argument. - + - + - + - - - - + + + + Defines property. - + - - - - + + + + @@ -279,48 +287,48 @@ Defines a single named object. - + - + - + - + - + - - + + - + - + - + @@ -330,12 +338,12 @@ in .NET code using a name that's illegal as an XML id, use the optional "name" attribute. If neither given, the object type name is used as id. --> - + - + - - + + - + - + - + - + - - - + + + - The document root. At least one object definition is required. + The document root. At least one object definition is required. - + - - - - + + + + - - + + - - - - + + + + - - - - - + + + + + diff --git a/src/Spring/Spring.Core/Objects/Factory/Xml/spring-objects-2.0.xsd b/src/Spring/Spring.Core/Objects/Factory/Xml/spring-objects-2.0.xsd index 68e6d122..7100c64f 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Xml/spring-objects-2.0.xsd +++ b/src/Spring/Spring.Core/Objects/Factory/Xml/spring-objects-2.0.xsd @@ -1,8 +1,13 @@ - - - - + + + - - + + - - - - - - - - - - - + + + + + + + + + + + + - - - Defines a base type for any required string. Defines a string with a minimum length of 0 - - - - - - - - - Element containing informative text describing the purpose of the enclosing - element. Always optional. - Used primarily for user documentation of XML object definition documents. - - - - - - - - - - - - - - - - - - - - - - + + + Defines a base type for any required string. Defines a string with a minimum length of + 0 + + + + + + + + + + Element containing informative text describing the purpose of the enclosing + element. Always optional. + Used primarily for user documentation of XML object definition documents. + + + + + + + + + + + + + + + + + - - - - - - - - - - - - + Defines a reference to another object in this factory or an external + factory (parent or included factory). + --> + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Import an external file containing object definitions into this file. - - - - - - Defines an additional alias name for an object definition. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Defines constructor argument. - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - + Note that this is recommended for simple objects only. + Configure more complex objects by setting properties to references + to other objects. + --> + + + + + + + + + + + + + + + + + + + + + + + + + Import an external file containing object definitions into this file. + + + + + + Defines an additional alias name for an object definition. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Defines constructor argument. + + + + + + + + + + + + - - - - - + + Defines property. + + + + + + + + + + + + + + - - - - - - - + + + + + + - - - - + + + + - - - - + + + - - - - - - - - + + + + + + + + - - - Defines a single named object. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - The document root. At least one object definition is required. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - Defines a single named object. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The document root. At least one object definition is required. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + - - - - - - + + + + + + diff --git a/src/Spring/Spring.Core/Objects/Factory/Xml/spring-tool-1.1.xsd b/src/Spring/Spring.Core/Objects/Factory/Xml/spring-tool-1.1.xsd index 009b5891..10694901 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Xml/spring-tool-1.1.xsd +++ b/src/Spring/Spring.Core/Objects/Factory/Xml/spring-tool-1.1.xsd @@ -1,62 +1,62 @@ + xmlns:xsd="http://www.w3.org/2001/XMLSchema" + targetNamespace="http://www.springframework.net/tool" + elementFormDefault="qualified"> - + - - + - + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - - - + + + - - - - Indicates that an annotated type exports an application visible component. - - - - - - The type of the exported component. May be null if the type is not known until runtime. - - - - - - - Defines an XPath query that can be executed against the node annotated with this - type to determine the identifier of any exported component. - - - - + + + + Indicates that an annotated type exports an application visible component. + + + + + + The type of the exported component. May be null if the type is not known until runtime. + + + + + + + Defines an XPath query that can be executed against the node annotated with this + type to determine the identifier of any exported component. + + + + diff --git a/src/Spring/Spring.Core/Objects/FatalObjectException.cs b/src/Spring/Spring.Core/Objects/FatalObjectException.cs index 5340e8d7..118f0107 100644 --- a/src/Spring/Spring.Core/Objects/FatalObjectException.cs +++ b/src/Spring/Spring.Core/Objects/FatalObjectException.cs @@ -20,65 +20,64 @@ using System.Runtime.Serialization; -namespace Spring.Objects +namespace Spring.Objects; + +/// +/// Thrown on an unrecoverable problem encountered in the +/// objects namespace or sub-namespaces, e.g. bad class or field. +/// +/// Rod Johnson +/// Mark Pollack (.NET) +[Serializable] +public class FatalObjectException : ObjectsException { /// - /// Thrown on an unrecoverable problem encountered in the - /// objects namespace or sub-namespaces, e.g. bad class or field. + /// Creates a new instance of the FatalObjectException class. /// - /// Rod Johnson - /// Mark Pollack (.NET) - [Serializable] - public class FatalObjectException : ObjectsException + public FatalObjectException() { - /// - /// Creates a new instance of the FatalObjectException class. - /// - public FatalObjectException() - { - } + } - /// - /// Creates a new instance of the FatalObjectException class with the - /// specified message. - /// - /// - /// A message about the exception. - /// - public FatalObjectException(string message) : base(message) - { - } + /// + /// Creates a new instance of the FatalObjectException class with the + /// specified message. + /// + /// + /// A message about the exception. + /// + public FatalObjectException(string message) : base(message) + { + } - /// - /// Creates a new instance of the FatalObjectException class with the - /// specified message. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception that is being wrapped. - /// - public FatalObjectException(string message, Exception rootCause) - : base(message, rootCause) - { - } + /// + /// Creates a new instance of the FatalObjectException class with the + /// specified message. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception that is being wrapped. + /// + public FatalObjectException(string message, Exception rootCause) + : base(message, rootCause) + { + } - /// - /// Creates a new instance of the FatalObjectException class. - /// - /// - /// The - /// that holds the serialized object data about the exception being thrown. - /// - /// - /// The - /// that contains contextual information about the source or destination. - /// - protected FatalObjectException ( - SerializationInfo info, StreamingContext context) - : base (info, context) - { - } + /// + /// Creates a new instance of the FatalObjectException class. + /// + /// + /// The + /// that holds the serialized object data about the exception being thrown. + /// + /// + /// The + /// that contains contextual information about the source or destination. + /// + protected FatalObjectException( + SerializationInfo info, StreamingContext context) + : base(info, context) + { } } diff --git a/src/Spring/Spring.Core/Objects/IEventHandlerValue.cs b/src/Spring/Spring.Core/Objects/IEventHandlerValue.cs index d873da47..860a5617 100644 --- a/src/Spring/Spring.Core/Objects/IEventHandlerValue.cs +++ b/src/Spring/Spring.Core/Objects/IEventHandlerValue.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -18,54 +18,52 @@ #endregion +namespace Spring.Objects; -namespace Spring.Objects +/// +/// Describes an event handler. +/// +/// Rick Evans +public interface IEventHandlerValue { - /// - /// Describes an event handler. + /// + /// The source of the event. /// - /// Rick Evans - public interface IEventHandlerValue + object Source { - /// - /// The source of the event. - /// - object Source - { - get; - set; - } + get; + set; + } - /// - /// The name of the method that is going to handle the event. - /// - string MethodName - { - get; - set; - } + /// + /// The name of the method that is going to handle the event. + /// + string MethodName + { + get; + set; + } - /// - /// The name of the event that is being wired up. - /// - string EventName - { - get; - set; - } + /// + /// The name of the event that is being wired up. + /// + string EventName + { + get; + set; + } - /// - /// Wires up the specified handler to the named event on the - /// supplied event source. - /// - /// - /// The object (an object instance, a , etc) - /// exposing the named event. - /// - /// - /// The handler for the event (an object instance, a - /// , etc). - /// - void Wire (object source, object handler); - } + /// + /// Wires up the specified handler to the named event on the + /// supplied event source. + /// + /// + /// The object (an object instance, a , etc) + /// exposing the named event. + /// + /// + /// The handler for the event (an object instance, a + /// , etc). + /// + void Wire(object source, object handler); } diff --git a/src/Spring/Spring.Core/Objects/IMergable.cs b/src/Spring/Spring.Core/Objects/IMergable.cs index 8ad2daec..7ac8e7d0 100644 --- a/src/Spring/Spring.Core/Objects/IMergable.cs +++ b/src/Spring/Spring.Core/Objects/IMergable.cs @@ -18,36 +18,36 @@ #endregion -namespace Spring.Objects +namespace Spring.Objects; + +/// +/// Interface representing an object whose value set can be merged with that of a parent object. +/// +/// Rob Harrop +/// Mark Pollack (.NET) +public interface IMergable { /// - /// Interface representing an object whose value set can be merged with that of a parent object. + /// Gets a value indicating whether this instance is merge enabled for this instance /// - /// Rob Harrop - /// Mark Pollack (.NET) - public interface IMergable + /// + /// true if this instance is merge enabled; otherwise, false. + /// + bool MergeEnabled { - /// - /// Gets a value indicating whether this instance is merge enabled for this instance - /// - /// - /// true if this instance is merge enabled; otherwise, false. - /// - bool MergeEnabled { - get; - } - - /// - /// Merges the current value set with that of the supplied object. - /// - /// The supplied object is considered the parent, and values in the - /// callee's value set must override those of the supplied object. - /// - /// The parent object to merge with - /// The result of the merge operation - /// If the supplied parent is null - /// If merging is not enabled for this instance, - /// (i.e. MergeEnabled equals false. - object Merge(object parent); + get; } + + /// + /// Merges the current value set with that of the supplied object. + /// + /// The supplied object is considered the parent, and values in the + /// callee's value set must override those of the supplied object. + /// + /// The parent object to merge with + /// The result of the merge operation + /// If the supplied parent is null + /// If merging is not enabled for this instance, + /// (i.e. MergeEnabled equals false. + object Merge(object parent); } diff --git a/src/Spring/Spring.Core/Objects/IObjectMetadataElement.cs b/src/Spring/Spring.Core/Objects/IObjectMetadataElement.cs index bf6db7a6..25163a88 100644 --- a/src/Spring/Spring.Core/Objects/IObjectMetadataElement.cs +++ b/src/Spring/Spring.Core/Objects/IObjectMetadataElement.cs @@ -18,18 +18,17 @@ #endregion -namespace Spring.Objects +namespace Spring.Objects; + +/// +/// Interface to be implemented by bean metadata elements +/// that carry a configuration source object. +/// +public interface IObjectMetadataElement { /// - /// Interface to be implemented by bean metadata elements - /// that carry a configuration source object. + /// Return the configuration source Object for this metadata element + /// (may be null). /// - public interface IObjectMetadataElement - { - /// - /// Return the configuration source Object for this metadata element - /// (may be null). - /// - Object Source { get; } - } + Object Source { get; } } diff --git a/src/Spring/Spring.Core/Objects/IObjectWrapper.cs b/src/Spring/Spring.Core/Objects/IObjectWrapper.cs index eb789be7..4cd8ad51 100644 --- a/src/Spring/Spring.Core/Objects/IObjectWrapper.cs +++ b/src/Spring/Spring.Core/Objects/IObjectWrapper.cs @@ -21,181 +21,179 @@ using System.Reflection; using Spring.Core; -namespace Spring.Objects +namespace Spring.Objects; + +/// +/// The central interface of Spring.NET's low-level object infrastructure. +/// +/// +///

+/// Typically not directly used by application code but rather implicitly +/// via an . +///

+///

+/// Implementing classes have the ability to get and set property values +/// (individually or in bulk), get property descriptors and query the +/// readability and writability of properties. +///

+///

+/// This interface supports nested properties enabling the setting +/// of properties on subproperties to an unlimited depth. +///

+///

+/// If a property update causes an exception, a +/// will be thrown. Bulk +/// updates continue after exceptions are encountered, throwing an exception +/// wrapping all exceptions encountered during the update. +///

+///

+/// implementations can be used +/// repeatedly, with their "target" or wrapped object changed. +///

+///
+/// Rod Johnson +/// Mark Pollack (.NET) +public interface IObjectWrapper { /// - /// The central interface of Spring.NET's low-level object infrastructure. + /// The object wrapped by the wrapper (cannot be ). /// /// ///

- /// Typically not directly used by application code but rather implicitly - /// via an . - ///

- ///

- /// Implementing classes have the ability to get and set property values - /// (individually or in bulk), get property descriptors and query the - /// readability and writability of properties. - ///

- ///

- /// This interface supports nested properties enabling the setting - /// of properties on subproperties to an unlimited depth. - ///

- ///

- /// If a property update causes an exception, a - /// will be thrown. Bulk - /// updates continue after exceptions are encountered, throwing an exception - /// wrapping all exceptions encountered during the update. - ///

- ///

- /// implementations can be used - /// repeatedly, with their "target" or wrapped object changed. + /// Implementations are required to allow the type of the wrapped + /// object to change. ///

///
- /// Rod Johnson - /// Mark Pollack (.NET) - public interface IObjectWrapper - { - /// - /// The object wrapped by the wrapper (cannot be ). - /// - /// - ///

- /// Implementations are required to allow the type of the wrapped - /// object to change. - ///

- ///
- /// The object wrapped by this wrapper. - object WrappedInstance { get; set; } + /// The object wrapped by this wrapper. + object WrappedInstance { get; set; } - /// - /// Convenience method to return the - /// of the wrapped object. - /// - /// The of the wrapped object. - Type WrappedType { get; } + /// + /// Convenience method to return the + /// of the wrapped object. + /// + /// The of the wrapped object. + Type WrappedType { get; } - /// Get the value of a property. - /// - /// The name of the property to get the value of. May be nested. - /// - /// The value of the property. - /// - /// if the property isn't readable, or if the getting the value throws - /// an exception. - /// - object GetPropertyValue(string theProperty); + /// Get the value of a property. + /// + /// The name of the property to get the value of. May be nested. + /// + /// The value of the property. + /// + /// if the property isn't readable, or if the getting the value throws + /// an exception. + /// + object GetPropertyValue(string theProperty); - /// - /// Get the for a particular - /// property. - /// - /// - /// The property to be retrieved. - /// - /// - /// The for the particular - /// property. - /// - PropertyInfo GetPropertyInfo(string theProperty); + /// + /// Get the for a particular + /// property. + /// + /// + /// The property to be retrieved. + /// + /// + /// The for the particular + /// property. + /// + PropertyInfo GetPropertyInfo(string theProperty); - /// - /// Get the for a particular property. - /// - /// - /// The property the of which is to be retrieved. - /// - /// - /// The for a particular property.. - /// - Type GetPropertyType(string theProperty); + /// + /// Get the for a particular property. + /// + /// + /// The property the of which is to be retrieved. + /// + /// + /// The for a particular property.. + /// + Type GetPropertyType(string theProperty); - /// - /// Get all of the instances for - /// all of the properties of the wrapped object. - /// - /// - /// An array of instances. - /// - PropertyInfo[] GetPropertyInfos(); + /// + /// Get all of the instances for + /// all of the properties of the wrapped object. + /// + /// + /// An array of instances. + /// + PropertyInfo[] GetPropertyInfos(); - /// - /// Set a property value. - /// - /// - ///

- /// This is the preferred way to update an individual property. - ///

- ///
- /// The new property value. - void SetPropertyValue(PropertyValue propertyValue); + /// + /// Set a property value. + /// + /// + ///

+ /// This is the preferred way to update an individual property. + ///

+ ///
+ /// The new property value. + void SetPropertyValue(PropertyValue propertyValue); - /// - /// Set a property value. - /// - /// - ///

- /// This method is provided for convenience only. The - /// - /// method is more powerful. - ///

- ///
- /// - /// The name of the property to set value of. - /// - /// The new property value. - void SetPropertyValue(string theProperty, object propertyValue); + /// + /// Set a property value. + /// + /// + ///

+ /// This method is provided for convenience only. The + /// + /// method is more powerful. + ///

+ ///
+ /// + /// The name of the property to set value of. + /// + /// The new property value. + void SetPropertyValue(string theProperty, object propertyValue); - /// Set a number of property values in bulk. - /// - ///

- /// This is the preferred way to perform a bulk update. - ///

- ///

- /// Note that performing a bulk update differs from performing a single update, - /// in that an implementation of this class will continue to update properties - /// if a recoverable error (such as a vetoed property change or a type - /// mismatch, but not an invalid property name or the like) is - /// encountered, throwing a - /// containing - /// all the individual errors. This exception can be examined later to see all - /// binding errors. Properties that were successfully updated stay changed. - ///

- ///

- /// Does not allow the setting of unknown fields. Equivalent to - /// - /// with an argument of false for the second parameter. - ///

- ///
- /// - /// The collection of instances to - /// set on the wrapped object. - /// - void SetPropertyValues(IPropertyValues values); + /// Set a number of property values in bulk. + /// + ///

+ /// This is the preferred way to perform a bulk update. + ///

+ ///

+ /// Note that performing a bulk update differs from performing a single update, + /// in that an implementation of this class will continue to update properties + /// if a recoverable error (such as a vetoed property change or a type + /// mismatch, but not an invalid property name or the like) is + /// encountered, throwing a + /// containing + /// all the individual errors. This exception can be examined later to see all + /// binding errors. Properties that were successfully updated stay changed. + ///

+ ///

+ /// Does not allow the setting of unknown fields. Equivalent to + /// + /// with an argument of false for the second parameter. + ///

+ ///
+ /// + /// The collection of instances to + /// set on the wrapped object. + /// + void SetPropertyValues(IPropertyValues values); - /// - /// Set a number of property values in bulk with full control over behavior. - /// - /// - ///

- /// Note that performing a bulk update differs from performing a single update, - /// in that an implementation of this class will continue to update properties - /// if a recoverable error (such as a vetoed property change or a type - /// mismatch, but not an invalid property name or the like) is - /// encountered, throwing a - /// containing - /// all the individual errors. This exception can be examined later to see all - /// binding errors. Properties that were successfully updated stay changed. - ///

- ///

Does not allow the setting of unknown fields. - ///

- ///
- /// - /// The to set on the target object - /// - /// - /// Should we ignore unknown values (not found in the object!?) - /// - void SetPropertyValues(IPropertyValues values, bool ignoreUnknown); - - } + /// + /// Set a number of property values in bulk with full control over behavior. + /// + /// + ///

+ /// Note that performing a bulk update differs from performing a single update, + /// in that an implementation of this class will continue to update properties + /// if a recoverable error (such as a vetoed property change or a type + /// mismatch, but not an invalid property name or the like) is + /// encountered, throwing a + /// containing + /// all the individual errors. This exception can be examined later to see all + /// binding errors. Properties that were successfully updated stay changed. + ///

+ ///

Does not allow the setting of unknown fields. + ///

+ ///
+ /// + /// The to set on the target object + /// + /// + /// Should we ignore unknown values (not found in the object!?) + /// + void SetPropertyValues(IPropertyValues values, bool ignoreUnknown); } diff --git a/src/Spring/Spring.Core/Objects/IPropertyValues.cs b/src/Spring/Spring.Core/Objects/IPropertyValues.cs index 39a5d953..ece93d2d 100644 --- a/src/Spring/Spring.Core/Objects/IPropertyValues.cs +++ b/src/Spring/Spring.Core/Objects/IPropertyValues.cs @@ -20,65 +20,64 @@ using System.Collections; -namespace Spring.Objects +namespace Spring.Objects; + +/// +/// A collection style container for +/// instances. +/// +/// Rod Johnson +/// Mark Pollack (.NET) +public interface IPropertyValues : IEnumerable { /// - /// A collection style container for - /// instances. + /// Return an array of the objects + /// held in this object. /// - /// Rod Johnson - /// Mark Pollack (.NET) - public interface IPropertyValues : IEnumerable - { - /// - /// Return an array of the objects - /// held in this object. - /// - /// - /// An array of the objects held - /// in this object. - /// - IReadOnlyList PropertyValues { get; } + /// + /// An array of the objects held + /// in this object. + /// + IReadOnlyList PropertyValues { get; } - /// - /// Return the instance with the - /// given name. - /// - /// The name to search for. - /// - /// the , or null if a - /// the with the supplied - /// did not exist in this collection. - /// - PropertyValue GetPropertyValue(string propertyName); + /// + /// Return the instance with the + /// given name. + /// + /// The name to search for. + /// + /// the , or null if a + /// the with the supplied + /// did not exist in this collection. + /// + PropertyValue GetPropertyValue(string propertyName); - /// - /// Is there a instance for this - /// property name? - /// - /// The name to search for. - /// - /// True if there is a instance for - /// the supplied . - /// - bool Contains(string propertyName); + /// + /// Is there a instance for this + /// property name? + /// + /// The name to search for. + /// + /// True if there is a instance for + /// the supplied . + /// + bool Contains(string propertyName); - /// - /// Return the difference (changes, additions, but not removals) of - /// property values between the supplied argument and the values - /// contained in the collection. - /// - /// - ///

- /// Subclasses should also override Equals. - ///

- ///
- /// The old property values. - /// - /// An containing any changes, or - /// an empty instance if there were - /// no changes. - /// - IPropertyValues ChangesSince(IPropertyValues old); - } + /// + /// Return the difference (changes, additions, but not removals) of + /// property values between the supplied argument and the values + /// contained in the collection. + /// + /// + ///

+ /// Subclasses should also override Equals. + ///

+ ///
+ /// The old property values. + /// + /// An containing any changes, or + /// an empty instance if there were + /// no changes. + /// + IPropertyValues ChangesSince(IPropertyValues old); } diff --git a/src/Spring/Spring.Core/Objects/ISharedStateAware.cs b/src/Spring/Spring.Core/Objects/ISharedStateAware.cs index 61d1a2a8..4bbeec5d 100644 --- a/src/Spring/Spring.Core/Objects/ISharedStateAware.cs +++ b/src/Spring/Spring.Core/Objects/ISharedStateAware.cs @@ -20,30 +20,29 @@ using System.Collections; -namespace Spring.Objects +namespace Spring.Objects; + +/// +/// This interface should be implemented by classes that want to +/// have access to the shared state. +/// +/// +///

+/// Shared state is very useful if you have data that needs to be shared by all instances +/// of e.g. the same webform (or other IHttpHandlers). +///

+///

+/// For example, Spring.Web.UI.Page class implements this interface, which allows +/// each page derived from it to cache localizalization resources and parsed data binding +/// expressions only once and then reuse the cached values, regardless of how many instances +/// of the page are created. +///

+///
+public interface ISharedStateAware { /// - /// This interface should be implemented by classes that want to - /// have access to the shared state. + /// Gets or sets the that should be used + /// to store shared state for this instance. /// - /// - ///

- /// Shared state is very useful if you have data that needs to be shared by all instances - /// of e.g. the same webform (or other IHttpHandlers). - ///

- ///

- /// For example, Spring.Web.UI.Page class implements this interface, which allows - /// each page derived from it to cache localizalization resources and parsed data binding - /// expressions only once and then reuse the cached values, regardless of how many instances - /// of the page are created. - ///

- ///
- public interface ISharedStateAware - { - /// - /// Gets or sets the that should be used - /// to store shared state for this instance. - /// - IDictionary SharedState { get; set; } - } -} + IDictionary SharedState { get; set; } +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Objects/ISharedStateFactory.cs b/src/Spring/Spring.Core/Objects/ISharedStateFactory.cs index 71df8fdd..bfe857a5 100644 --- a/src/Spring/Spring.Core/Objects/ISharedStateFactory.cs +++ b/src/Spring/Spring.Core/Objects/ISharedStateFactory.cs @@ -20,32 +20,31 @@ using System.Collections; -namespace Spring.Objects +namespace Spring.Objects; + +/// +/// Abstracts the state sharing strategy used +/// by +/// +/// Erich Eichinger +public interface ISharedStateFactory { /// - /// Abstracts the state sharing strategy used - /// by + /// Indicate, whether the given instance can be served by this factory /// - /// Erich Eichinger - public interface ISharedStateFactory - { - /// - /// Indicate, whether the given instance can be served by this factory - /// - /// the instance to serve state - /// the name of the instance - /// - /// a boolean value indicating, whether state can - /// be served for the given instance or not. - /// - bool CanProvideState(object instance, string name); + /// the instance to serve state + /// the name of the instance + /// + /// a boolean value indicating, whether state can + /// be served for the given instance or not. + /// + bool CanProvideState(object instance, string name); - /// - /// Returns the shared state for the given instance. - /// - /// the instance to obtain shared state for. - /// the name of this instance - /// a dictionary containing shared state for or null. - IDictionary GetSharedStateFor( object instance, string name ); - } + /// + /// Returns the shared state for the given instance. + /// + /// the instance to obtain shared state for. + /// the name of this instance + /// a dictionary containing shared state for or null. + IDictionary GetSharedStateFor(object instance, string name); } diff --git a/src/Spring/Spring.Core/Objects/MutablePropertyValues.cs b/src/Spring/Spring.Core/Objects/MutablePropertyValues.cs index c5c048d8..07eb8729 100644 --- a/src/Spring/Spring.Core/Objects/MutablePropertyValues.cs +++ b/src/Spring/Spring.Core/Objects/MutablePropertyValues.cs @@ -19,356 +19,354 @@ using System.Globalization; using System.Text; using Spring.Util; -namespace Spring.Objects +namespace Spring.Objects; + +/// +/// Default implementation of the +/// interface. +/// +/// +///

+/// Allows simple manipulation of properties, and provides constructors to +/// support deep copy and construction from a number of collection types such as +/// and +/// . +///

+///
+/// Rod Johnson +/// Mark Pollack (.NET) +/// Rick Evans (.NET) +[Serializable] +public class MutablePropertyValues : IPropertyValues { + private static readonly IReadOnlyList emptyPropertyValuesList = new List(); + private List propertyValuesList; + /// - /// Default implementation of the - /// interface. + /// Creates a new instance of the + /// class. /// /// ///

- /// Allows simple manipulation of properties, and provides constructors to - /// support deep copy and construction from a number of collection types such as - /// and - /// . + /// The returned instance is initially empty... + /// s can be added with the various + /// overloaded , + /// , + /// , + /// and + /// methods. ///

///
- /// Rod Johnson - /// Mark Pollack (.NET) - /// Rick Evans (.NET) - [Serializable] - public class MutablePropertyValues : IPropertyValues + /// + /// + public MutablePropertyValues() { - private static readonly IReadOnlyList emptyPropertyValuesList = new List(); - private List propertyValuesList; + } - /// - /// Creates a new instance of the - /// class. - /// - /// - ///

- /// The returned instance is initially empty... - /// s can be added with the various - /// overloaded , - /// , - /// , - /// and - /// methods. - ///

- ///
- /// - /// - public MutablePropertyValues() + /// + /// Creates a new instance of the + /// class. + /// + /// + ///

+ /// Deep copy constructor. Guarantees + /// references are independent, although it can't deep copy objects currently + /// referenced by individual objects. + ///

+ ///
+ public MutablePropertyValues(IPropertyValues other) + { + if (other != null) { + AddAll(other.PropertyValues); } + } - /// - /// Creates a new instance of the - /// class. - /// - /// - ///

- /// Deep copy constructor. Guarantees - /// references are independent, although it can't deep copy objects currently - /// referenced by individual objects. - ///

- ///
- public MutablePropertyValues(IPropertyValues other) + /// + /// Creates a new instance of the + /// class. + /// + /// + /// The with property values + /// keyed by property name, which must be a . + /// + public MutablePropertyValues(IReadOnlyDictionary map) + { + AddAll(map); + } + + /// + /// Property to retrieve the array of property values. + /// + public IReadOnlyList PropertyValues => propertyValuesList ?? emptyPropertyValuesList; + + /// + /// Overloaded version of Add that takes a property name and a property value. + /// + /// + /// The name of the property. + /// + /// + /// The value of the property. + /// + public void Add(string propertyName, object propertyValue) + { + Add(new PropertyValue(propertyName, propertyValue)); + } + + /// + /// Add the supplied object, + /// replacing any existing one for the respective property. + /// + /// + /// The object to add. + /// + public void Add(PropertyValue pv) + { + propertyValuesList = propertyValuesList ?? new List(); + + for (int i = 0; i < propertyValuesList.Count; ++i) { - if (other != null) + PropertyValue currentPv = propertyValuesList[i]; + if (currentPv.Name == pv.Name) { - AddAll(other.PropertyValues); + pv = MergeIfRequired(pv, currentPv); + propertyValuesList[i] = pv; + return; } } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The with property values - /// keyed by property name, which must be a . - /// - public MutablePropertyValues(IReadOnlyDictionary map) + propertyValuesList.Add(pv); + } + + /// + /// Merges the value of the supplied 'new' with that of + /// the current if merging is supported and enabled. + /// + /// + /// The new pv. + /// The current pv. + /// The possibly merged PropertyValue + private PropertyValue MergeIfRequired(PropertyValue newPv, PropertyValue currentPv) + { + object val = newPv.Value; + if (val is IMergable mergable) { - AddAll(map); - } - - /// - /// Property to retrieve the array of property values. - /// - public IReadOnlyList PropertyValues => propertyValuesList ?? emptyPropertyValuesList; - - /// - /// Overloaded version of Add that takes a property name and a property value. - /// - /// - /// The name of the property. - /// - /// - /// The value of the property. - /// - public void Add(string propertyName, object propertyValue) - { - Add(new PropertyValue(propertyName, propertyValue)); - } - - /// - /// Add the supplied object, - /// replacing any existing one for the respective property. - /// - /// - /// The object to add. - /// - public void Add(PropertyValue pv) - { - propertyValuesList = propertyValuesList ?? new List(); - - for (int i = 0; i < propertyValuesList.Count; ++i) + if (mergable.MergeEnabled) { - PropertyValue currentPv = propertyValuesList[i]; - if (currentPv.Name == pv.Name) - { - pv = MergeIfRequired(pv, currentPv); - propertyValuesList[i] = pv; - return; - } - } - - propertyValuesList.Add(pv); - } - - /// - /// Merges the value of the supplied 'new' with that of - /// the current if merging is supported and enabled. - /// - /// - /// The new pv. - /// The current pv. - /// The possibly merged PropertyValue - private PropertyValue MergeIfRequired(PropertyValue newPv, PropertyValue currentPv) - { - object val = newPv.Value; - if (val is IMergable mergable) - { - if (mergable.MergeEnabled) - { - object merged = mergable.Merge(currentPv.Value); - return new PropertyValue(newPv.Name, merged); - } - } - - return newPv; - } - - /// - /// Add all property values from the given - /// . - /// - /// - /// The map of property values, the keys of which must be - /// s. - /// - public void AddAll(IReadOnlyDictionary map) - { - if (map != null) - { - foreach (KeyValuePair pair in map) - { - Add(new PropertyValue(pair.Key, pair.Value)); - } + object merged = mergable.Merge(currentPv.Value); + return new PropertyValue(newPv.Name, merged); } } - /// - /// Add all property values from the given - /// . - /// - /// - /// The map of property values, the keys of which must be - /// s. - /// - public void AddAll(IDictionary map) + return newPv; + } + + /// + /// Add all property values from the given + /// . + /// + /// + /// The map of property values, the keys of which must be + /// s. + /// + public void AddAll(IReadOnlyDictionary map) + { + if (map != null) { - if (map != null) + foreach (KeyValuePair pair in map) { - foreach (KeyValuePair pair in map) - { - Add(new PropertyValue(pair.Key, pair.Value)); - } + Add(new PropertyValue(pair.Key, pair.Value)); } } + } - - /// - /// Add all property values from the given - /// . - /// - /// - /// The list of s to be added. - /// - public void AddAll(IReadOnlyList values) + /// + /// Add all property values from the given + /// . + /// + /// + /// The map of property values, the keys of which must be + /// s. + /// + public void AddAll(IDictionary map) + { + if (map != null) { - if (values != null) + foreach (KeyValuePair pair in map) { - for (var i = 0; i < values.Count; i++) - { - Add(values[i]); - } + Add(new PropertyValue(pair.Key, pair.Value)); } } + } - /// - /// Remove the given , if contained. - /// - /// - /// The to remove. - /// - public void Remove(PropertyValue pv) + /// + /// Add all property values from the given + /// . + /// + /// + /// The list of s to be added. + /// + public void AddAll(IReadOnlyList values) + { + if (values != null) { - propertyValuesList?.Remove(pv); - } - - /// - /// Removes the named , if contained. - /// - /// - /// The name of the property. - /// - public void Remove(string propertyName) - { - Remove(GetPropertyValue(propertyName)); - } - - /// - /// Modify a object held in this object. Indexed from 0. - /// - public void SetPropertyValueAt(PropertyValue pv, int i) - { - propertyValuesList = propertyValuesList ?? new List(); - propertyValuesList[i] = pv; - } - - /// - /// Return the property value given the name. - /// - /// - /// The property name is checked in a case-insensitive fashion. - /// - /// - /// The name of the property. - /// - /// - /// The property value. - /// - public PropertyValue GetPropertyValue(string propertyName) - { - if (propertyValuesList == null) + for (var i = 0; i < values.Count; i++) { - return null; + Add(values[i]); } + } + } - string propertyNameLowered = propertyName.ToLower(CultureInfo.CurrentCulture); - for (var i = 0; i < propertyValuesList.Count; i++) - { - PropertyValue pv = propertyValuesList[i]; - if (pv.Name.ToLower(CultureInfo.CurrentCulture).Equals(propertyNameLowered)) - { - return pv; - } - } + /// + /// Remove the given , if contained. + /// + /// + /// The to remove. + /// + public void Remove(PropertyValue pv) + { + propertyValuesList?.Remove(pv); + } + /// + /// Removes the named , if contained. + /// + /// + /// The name of the property. + /// + public void Remove(string propertyName) + { + Remove(GetPropertyValue(propertyName)); + } + + /// + /// Modify a object held in this object. Indexed from 0. + /// + public void SetPropertyValueAt(PropertyValue pv, int i) + { + propertyValuesList = propertyValuesList ?? new List(); + propertyValuesList[i] = pv; + } + + /// + /// Return the property value given the name. + /// + /// + /// The property name is checked in a case-insensitive fashion. + /// + /// + /// The name of the property. + /// + /// + /// The property value. + /// + public PropertyValue GetPropertyValue(string propertyName) + { + if (propertyValuesList == null) + { return null; } - /// - /// Does the container of properties contain one of this name. - /// - /// The name of the property to search for. - /// - /// True if the property is contained in this collection, false otherwise. - /// - public bool Contains(string propertyName) + string propertyNameLowered = propertyName.ToLower(CultureInfo.CurrentCulture); + for (var i = 0; i < propertyValuesList.Count; i++) { - return GetPropertyValue(propertyName) != null; + PropertyValue pv = propertyValuesList[i]; + if (pv.Name.ToLower(CultureInfo.CurrentCulture).Equals(propertyNameLowered)) + { + return pv; + } } - /// - /// Return the difference (changes, additions, but not removals) of - /// property values between the supplied argument and the values - /// contained in the collection. - /// - /// Another property values collection. - /// - /// The collection of property values that are different than the supplied one. - /// - public IPropertyValues ChangesSince(IPropertyValues old) + return null; + } + + /// + /// Does the container of properties contain one of this name. + /// + /// The name of the property to search for. + /// + /// True if the property is contained in this collection, false otherwise. + /// + public bool Contains(string propertyName) + { + return GetPropertyValue(propertyName) != null; + } + + /// + /// Return the difference (changes, additions, but not removals) of + /// property values between the supplied argument and the values + /// contained in the collection. + /// + /// Another property values collection. + /// + /// The collection of property values that are different than the supplied one. + /// + public IPropertyValues ChangesSince(IPropertyValues old) + { + var changes = new MutablePropertyValues(); + if (old == this || propertyValuesList == null) { - var changes = new MutablePropertyValues(); - if (old == this || propertyValuesList == null) - { - return changes; - } - - // for each property value in this (the newer set) - foreach (PropertyValue newProperty in propertyValuesList) - { - PropertyValue oldProperty = old.GetPropertyValue(newProperty.Name); - if (oldProperty == null) - { - // if there wasn't an old one, add it - changes.Add(newProperty); - } - else if (!oldProperty.Equals(newProperty)) - { - // it's changed - changes.Add(newProperty); - } - } - return changes; } - /// - /// Returns an that can iterate - /// through a collection. - /// - /// - ///

- /// The returned is the - /// exposed by the - /// - /// property. - ///

- ///
- /// - /// An that can iterate through a - /// collection. - /// - public IEnumerator GetEnumerator() + // for each property value in this (the newer set) + foreach (PropertyValue newProperty in propertyValuesList) { - return PropertyValues.GetEnumerator(); + PropertyValue oldProperty = old.GetPropertyValue(newProperty.Name); + if (oldProperty == null) + { + // if there wasn't an old one, add it + changes.Add(newProperty); + } + else if (!oldProperty.Equals(newProperty)) + { + // it's changed + changes.Add(newProperty); + } } - // CLOVER:OFF - - /// - /// Convert the object to a string representation. - /// - /// - /// A string representation of the object. - /// - public override string ToString() - { - var pvs = PropertyValues; - StringBuilder sb - = new StringBuilder( - "MutablePropertyValues: length=").Append(pvs.Count).Append("; "); - sb.Append(StringUtils.ArrayToDelimitedString(pvs, ",")); - return sb.ToString(); - } - - // CLOVER:ON + return changes; } + + /// + /// Returns an that can iterate + /// through a collection. + /// + /// + ///

+ /// The returned is the + /// exposed by the + /// + /// property. + ///

+ ///
+ /// + /// An that can iterate through a + /// collection. + /// + public IEnumerator GetEnumerator() + { + return PropertyValues.GetEnumerator(); + } + + // CLOVER:OFF + + /// + /// Convert the object to a string representation. + /// + /// + /// A string representation of the object. + /// + public override string ToString() + { + var pvs = PropertyValues; + StringBuilder sb + = new StringBuilder( + "MutablePropertyValues: length=").Append(pvs.Count).Append("; "); + sb.Append(StringUtils.ArrayToDelimitedString(pvs, ",")); + return sb.ToString(); + } + + // CLOVER:ON } diff --git a/src/Spring/Spring.Core/Objects/ObjectMetadataAttribute.cs b/src/Spring/Spring.Core/Objects/ObjectMetadataAttribute.cs index fb39ad61..bc325069 100644 --- a/src/Spring/Spring.Core/Objects/ObjectMetadataAttribute.cs +++ b/src/Spring/Spring.Core/Objects/ObjectMetadataAttribute.cs @@ -21,74 +21,73 @@ using System.Diagnostics; using Spring.Util; -namespace Spring.Objects +namespace Spring.Objects; + +/// +/// Holder for a key-value style attribute that is part of a bean definition. +/// Keeps track of the definition source in addition to the key-value pair. +/// +public class ObjectMetadataAttribute : IObjectMetadataElement { + private readonly string _name; + + private readonly object _value; + + private object _source; + /// - /// Holder for a key-value style attribute that is part of a bean definition. - /// Keeps track of the definition source in addition to the key-value pair. + /// Create a new AttributeValue instance. /// - public class ObjectMetadataAttribute : IObjectMetadataElement + /// the name of the attribute (never null) + /// the value of the attribute (possibly before type conversion) + public ObjectMetadataAttribute(string name, object value) { - private readonly string _name; + Trace.Assert(name != null, "Name must not be null"); + _name = name; + _value = value; + } - private readonly object _value; + /// + /// Return the name of the attribute. + /// + public string Name { get { return _name; } } - private object _source; + /// + /// Return the value of the attribute. + /// + public object Value { get { return _value; } } + /// + /// Set the configuration source Object for this metadata element. + ///

The exact type of the object will depend on the configuration mechanism used.

+ ///
+ public object Source { get { return _source; } set { _source = value; } } - /// - /// Create a new AttributeValue instance. - /// - /// the name of the attribute (never null) - /// the value of the attribute (possibly before type conversion) - public ObjectMetadataAttribute(string name, object value) + public override bool Equals(Object other) + { + if (this == other) { - Trace.Assert(name != null, "Name must not be null"); - _name = name; - _value = value; - } + return true; + } - - /// - /// Return the name of the attribute. - /// - public string Name { get { return _name; } } - - /// - /// Return the value of the attribute. - /// - public object Value { get { return _value; } } - - /// - /// Set the configuration source Object for this metadata element. - ///

The exact type of the object will depend on the configuration mechanism used.

- ///
- public object Source { get { return _source; } set { _source = value; } } - - - public override bool Equals(Object other) + if (!(other is ObjectMetadataAttribute)) { - if (this == other) { - return true; - } - if (!(other is ObjectMetadataAttribute)) { - return false; - } - var otherMa = (ObjectMetadataAttribute) other; - return (_name.Equals(otherMa._name) && - ObjectUtils.NullSafeEquals(_value, otherMa._value) && - ObjectUtils.NullSafeEquals(_source, otherMa._source)); - } + return false; + } + var otherMa = (ObjectMetadataAttribute) other; + return (_name.Equals(otherMa._name) && + ObjectUtils.NullSafeEquals(_value, otherMa._value) && + ObjectUtils.NullSafeEquals(_source, otherMa._source)); + } - public override int GetHashCode() - { - return _name.GetHashCode() * 29 + ObjectUtils.NullSafeHashCode(_value); - } + public override int GetHashCode() + { + return _name.GetHashCode() * 29 + ObjectUtils.NullSafeHashCode(_value); + } - public override string ToString() - { - return "metadata attribute '" + _name + "'"; - } + public override string ToString() + { + return "metadata attribute '" + _name + "'"; } } diff --git a/src/Spring/Spring.Core/Objects/ObjectMetadataAttributeAccessor.cs b/src/Spring/Spring.Core/Objects/ObjectMetadataAttributeAccessor.cs index a732a7fd..7ff1d0b8 100644 --- a/src/Spring/Spring.Core/Objects/ObjectMetadataAttributeAccessor.cs +++ b/src/Spring/Spring.Core/Objects/ObjectMetadataAttributeAccessor.cs @@ -20,65 +20,63 @@ using Spring.Core; -namespace Spring.Objects +namespace Spring.Objects; + +/// +/// Extension of , +/// holding attributes as objects in order +/// to keep track of the definition source. +/// +[Serializable] +public class ObjectMetadataAttributeAccessor : AttributeAccessorSupport, IObjectMetadataElement { + private object _source; + /// - /// Extension of , - /// holding attributes as objects in order - /// to keep track of the definition source. + /// Set the configuration source object for this metadata element. + ///

The exact type of the object will depend on the configuration mechanism used.

///
- [Serializable] - public class ObjectMetadataAttributeAccessor : AttributeAccessorSupport, IObjectMetadataElement + public object Source { - private object _source; + get { return _source; } + set { _source = value; } + } - /// - /// Set the configuration source object for this metadata element. - ///

The exact type of the object will depend on the configuration mechanism used.

- ///
- public object Source - { - get { return _source; } - set { _source = value; } - } + /// + /// Add the given BeanMetadataAttribute to this accessor's set of attributes. + /// + /// The BeanMetadataAttribute object to register + public void AddMetadataAttribute(ObjectMetadataAttribute attribute) + { + base.SetAttribute(attribute.Name, attribute); + } - /// - /// Add the given BeanMetadataAttribute to this accessor's set of attributes. - /// - /// The BeanMetadataAttribute object to register - public void AddMetadataAttribute(ObjectMetadataAttribute attribute) - { - base.SetAttribute(attribute.Name, attribute); - } + /// + /// Look up the given BeanMetadataAttribute in this accessor's set of attributes. + /// + /// the name of the attribute + /// the corresponding BeanMetadataAttribute object, + /// or null if no such attribute defined + /// + public ObjectMetadataAttribute GetMetadataAttribute(string name) + { + return (ObjectMetadataAttribute) base.GetAttribute(name); + } - /// - /// Look up the given BeanMetadataAttribute in this accessor's set of attributes. - /// - /// the name of the attribute - /// the corresponding BeanMetadataAttribute object, - /// or null if no such attribute defined - /// - public ObjectMetadataAttribute GetMetadataAttribute(string name) - { - return (ObjectMetadataAttribute) base.GetAttribute(name); - } + public override void SetAttribute(string name, object value) + { + base.SetAttribute(name, new ObjectMetadataAttribute(name, value)); + } - public override void SetAttribute(string name, object value) - { - base.SetAttribute(name, new ObjectMetadataAttribute(name, value)); - } - - public override object GetAttribute(string name) - { - var attribute = (ObjectMetadataAttribute) base.GetAttribute(name); - return (attribute != null ? attribute.Value : null); - } - - public override object RemoveAttribute(string name) - { - var attribute = (ObjectMetadataAttribute) base.RemoveAttribute(name); - return (attribute != null ? attribute.Value : null); - } + public override object GetAttribute(string name) + { + var attribute = (ObjectMetadataAttribute) base.GetAttribute(name); + return (attribute != null ? attribute.Value : null); + } + public override object RemoveAttribute(string name) + { + var attribute = (ObjectMetadataAttribute) base.RemoveAttribute(name); + return (attribute != null ? attribute.Value : null); } } diff --git a/src/Spring/Spring.Core/Objects/ObjectWrapper.cs b/src/Spring/Spring.Core/Objects/ObjectWrapper.cs index 9857753f..03ce7bba 100644 --- a/src/Spring/Spring.Core/Objects/ObjectWrapper.cs +++ b/src/Spring/Spring.Core/Objects/ObjectWrapper.cs @@ -22,488 +22,490 @@ using Spring.Core; using Spring.Expressions; using Spring.Expressions.Parser.antlr; using Spring.Util; -using StringUtils=Spring.Util.StringUtils; +using StringUtils = Spring.Util.StringUtils; -namespace Spring.Objects +namespace Spring.Objects; + +/// +/// Default implementation of the +/// interface that should be sufficient for all normal uses. +/// +/// +///

+/// will convert +/// and array +/// values to the corresponding target arrays, if necessary. Custom +/// s that deal with +/// s or arrays can be written against a +/// comma delimited as +/// arrays are converted in such a format if the array itself is not assignable. +///

+///
+/// Rod Johnson +/// Juergen Hoeller +/// Jean-Pierre Pawlak +/// Mark Pollack (.NET) +/// Aleksandar Seovic(.NET) +[Serializable] +public class ObjectWrapper : IObjectWrapper { + private static readonly ILogger Log = LogManager.GetLogger(); + + /// The wrapped object. + private object wrappedObject; + /// - /// Default implementation of the - /// interface that should be sufficient for all normal uses. + /// Creates a new instance of the class. /// /// ///

- /// will convert - /// and array - /// values to the corresponding target arrays, if necessary. Custom - /// s that deal with - /// s or arrays can be written against a - /// comma delimited as - /// arrays are converted in such a format if the array itself is not assignable. + /// The wrapped target instance will need to be set afterwards. ///

///
- /// Rod Johnson - /// Juergen Hoeller - /// Jean-Pierre Pawlak - /// Mark Pollack (.NET) - /// Aleksandar Seovic(.NET) - [Serializable] - public class ObjectWrapper : IObjectWrapper + /// + public ObjectWrapper() { - private static readonly ILogger Log = LogManager.GetLogger(); + } - /// The wrapped object. - private object wrappedObject; + /// + /// Creates a new instance of the class. + /// + /// + /// The object wrapped by this . + /// + /// + /// If the supplied is . + /// + public ObjectWrapper(object instance) + { + WrappedInstance = instance; + } - /// - /// Creates a new instance of the class. - /// - /// - ///

- /// The wrapped target instance will need to be set afterwards. - ///

- ///
- /// - public ObjectWrapper() - {} - - /// - /// Creates a new instance of the class. - /// - /// - /// The object wrapped by this . - /// - /// - /// If the supplied is . - /// - public ObjectWrapper(object instance) + /// + /// Creates a new instance of the class, + /// instantiating a new instance of the specified and using + /// it as the . + /// + /// + ///

+ /// Please note that the passed as the + /// argument must have a no-argument constructor. + /// If it does not, an exception will be thrown when this class attempts + /// to instantiate the supplied using it's + /// (non-existent) constructor. + ///

+ ///
+ /// + /// The to instantiate and wrap. + /// + /// + /// If the is , or if the + /// invocation of the s default (no-arg) constructor + /// fails (due to invalid arguments, insufficient permissions, etc). + /// + public ObjectWrapper(Type type) : this(true) + { + try { - WrappedInstance = instance; + WrappedInstance = ObjectUtils.InstantiateType(type); } + catch (FatalReflectionException e) + { + throw new FatalObjectException(e.Message, e); + } + } - /// - /// Creates a new instance of the class, - /// instantiating a new instance of the specified and using - /// it as the . - /// - /// - ///

- /// Please note that the passed as the - /// argument must have a no-argument constructor. - /// If it does not, an exception will be thrown when this class attempts - /// to instantiate the supplied using it's - /// (non-existent) constructor. - ///

- ///
- /// - /// The to instantiate and wrap. - /// - /// - /// If the is , or if the - /// invocation of the s default (no-arg) constructor - /// fails (due to invalid arguments, insufficient permissions, etc). - /// - public ObjectWrapper(Type type) : this(true) + /// + /// The object wrapped by this . + /// + /// + /// If the object cannot be changed; or an attempt is made to set the + /// value of this property to . + /// + public object WrappedInstance + { + get => wrappedObject; + set + { + if (value == null) + { + throw new FatalObjectException("Wraped instance cannot be null."); + } + + wrappedObject = value; + } + } + + /// + /// Convenience method to return the of the wrapped object. + /// + /// + ///

+ /// Do not use this (convenience) method prior to setting the + /// property. + ///

+ ///
+ /// + /// The of the wrapped object. + /// + /// + /// If the property + /// is . + /// + public Type WrappedType => WrappedInstance.GetType(); + + /// Gets the value of a property. + /// + /// The name of the property to get the value of. + /// + /// The value of the property. + /// + /// If there is no such property, if the property isn't readable, or + /// if getting the property value throws an exception. + /// + public virtual object GetPropertyValue(string propertyName) + { + try + { + IExpression propertyExpression = GetPropertyExpression(propertyName); + return GetPropertyValue(propertyExpression); + } + catch (RecognitionException e) + { + throw new InvalidPropertyException("Failed to parse property name '" + propertyName + "'.", e); + } + catch (TokenStreamRecognitionException e) + { + throw new InvalidPropertyException("Failed to parse property name '" + propertyName + "'.", e); + } + } + + /// Gets the value of a property. + /// + /// The property expression that should be used to retrieve the property value. + /// + /// The value of the property. + /// + /// If there is no such property, if the property isn't readable, or + /// if getting the property value throws an exception. + /// + public virtual object GetPropertyValue(IExpression propertyExpression) + { + return propertyExpression.GetValue(wrappedObject); + } + + /// + /// Sets a property value. + /// + /// + ///

+ /// This method is provided for convenience only. The + /// + /// method is more powerful. + ///

+ ///
+ /// + /// The name of the property to set value of. + /// + /// The new value. + public virtual void SetPropertyValue(string propertyName, object val) + { + try + { + IExpression propertyExpression = GetPropertyExpression(propertyName); + SetPropertyValue(propertyExpression, val); + } + catch (RecognitionException e) + { + throw new InvalidPropertyException("Failed to parse property name '" + propertyName + "'.", e); + } + catch (TokenStreamRecognitionException e) + { + throw new InvalidPropertyException("Failed to parse property name '" + propertyName + "'.", e); + } + } + + /// + /// Sets a property value. + /// + /// + /// The property expression that should be used to set the property value. + /// + /// The new value. + public virtual void SetPropertyValue(IExpression propertyExpression, object val) + { + propertyExpression.SetValue(wrappedObject, val); + } + + /// + /// Sets a property value. + /// + /// + ///

+ /// This is the preferred way to update an individual property. + ///

+ ///
+ /// + /// The object containing new property value. + /// + public virtual void SetPropertyValue(PropertyValue pv) + { + SetPropertyValue(pv.Expression, pv.Value); + } + + /// Set a number of property values in bulk. + /// + ///

+ /// Does not allow unknown fields. Equivalent to + /// + /// with and for + /// arguments. + ///

+ ///
+ /// + /// The to set on the target + /// object. + /// + /// + /// If an error is encountered while setting a property. + /// + /// + /// On a mismatch while setting a property, insufficient permissions, etc. + /// + /// + public virtual void SetPropertyValues(IPropertyValues pvs) + { + SetPropertyValues(pvs, false); + } + + /// + /// Perform a bulk update with full control over behavior. + /// + /// + ///

+ /// This method may throw a reflection-based exception, if there is a critical + /// failure such as no matching field... less serious exceptions will be accumulated + /// and thrown as a single . + ///

+ ///
+ /// + /// The s to set on the target object. + /// + /// + /// Should we ignore unknown values (not found in the object!?). + /// + /// + /// If an error is encountered while setting a property (only thrown if the + /// parameter is set to ). + /// + /// + /// On a mismatch while setting a property, insufficient permissions, etc. + /// + /// + public virtual void SetPropertyValues(IPropertyValues propertyValues, bool ignoreUnknown) + { + var propertyAccessExceptions = new List(); + foreach (PropertyValue pv in propertyValues) { try { - WrappedInstance = ObjectUtils.InstantiateType(type); - } catch (FatalReflectionException e) - { - throw new FatalObjectException(e.Message, e); + SetPropertyValue(pv); } - } - - /// - /// The object wrapped by this . - /// - /// - /// If the object cannot be changed; or an attempt is made to set the - /// value of this property to . - /// - public object WrappedInstance - { - get => wrappedObject; - set + catch (NotWritablePropertyException ex) { - if (value == null) - { - throw new FatalObjectException("Wraped instance cannot be null."); - } - wrappedObject = value; - } - } - - /// - /// Convenience method to return the of the wrapped object. - /// - /// - ///

- /// Do not use this (convenience) method prior to setting the - /// property. - ///

- ///
- /// - /// The of the wrapped object. - /// - /// - /// If the property - /// is . - /// - public Type WrappedType => WrappedInstance.GetType(); - - /// Gets the value of a property. - /// - /// The name of the property to get the value of. - /// - /// The value of the property. - /// - /// If there is no such property, if the property isn't readable, or - /// if getting the property value throws an exception. - /// - public virtual object GetPropertyValue(string propertyName) - { - try - { - IExpression propertyExpression = GetPropertyExpression(propertyName); - return GetPropertyValue(propertyExpression); - } - catch (RecognitionException e) - { - throw new InvalidPropertyException("Failed to parse property name '" + propertyName + "'.", e); - } - catch (TokenStreamRecognitionException e) - { - throw new InvalidPropertyException("Failed to parse property name '" + propertyName + "'.", e); - } - } - - /// Gets the value of a property. - /// - /// The property expression that should be used to retrieve the property value. - /// - /// The value of the property. - /// - /// If there is no such property, if the property isn't readable, or - /// if getting the property value throws an exception. - /// - public virtual object GetPropertyValue(IExpression propertyExpression) - { - return propertyExpression.GetValue(wrappedObject); - } - - /// - /// Sets a property value. - /// - /// - ///

- /// This method is provided for convenience only. The - /// - /// method is more powerful. - ///

- ///
- /// - /// The name of the property to set value of. - /// - /// The new value. - public virtual void SetPropertyValue(string propertyName, object val) - { - try - { - IExpression propertyExpression = GetPropertyExpression(propertyName); - SetPropertyValue(propertyExpression, val); - } - catch (RecognitionException e) - { - throw new InvalidPropertyException("Failed to parse property name '" + propertyName + "'.", e); - } - catch (TokenStreamRecognitionException e) - { - throw new InvalidPropertyException("Failed to parse property name '" + propertyName + "'.", e); - } - } - - /// - /// Sets a property value. - /// - /// - /// The property expression that should be used to set the property value. - /// - /// The new value. - public virtual void SetPropertyValue(IExpression propertyExpression, object val) - { - propertyExpression.SetValue(wrappedObject, val); - } - - /// - /// Sets a property value. - /// - /// - ///

- /// This is the preferred way to update an individual property. - ///

- ///
- /// - /// The object containing new property value. - /// - public virtual void SetPropertyValue(PropertyValue pv) - { - SetPropertyValue(pv.Expression, pv.Value); - } - - /// Set a number of property values in bulk. - /// - ///

- /// Does not allow unknown fields. Equivalent to - /// - /// with and for - /// arguments. - ///

- ///
- /// - /// The to set on the target - /// object. - /// - /// - /// If an error is encountered while setting a property. - /// - /// - /// On a mismatch while setting a property, insufficient permissions, etc. - /// - /// - public virtual void SetPropertyValues(IPropertyValues pvs) - { - SetPropertyValues(pvs, false); - } - - /// - /// Perform a bulk update with full control over behavior. - /// - /// - ///

- /// This method may throw a reflection-based exception, if there is a critical - /// failure such as no matching field... less serious exceptions will be accumulated - /// and thrown as a single . - ///

- ///
- /// - /// The s to set on the target object. - /// - /// - /// Should we ignore unknown values (not found in the object!?). - /// - /// - /// If an error is encountered while setting a property (only thrown if the - /// parameter is set to ). - /// - /// - /// On a mismatch while setting a property, insufficient permissions, etc. - /// - /// - public virtual void SetPropertyValues(IPropertyValues propertyValues, bool ignoreUnknown) - { - var propertyAccessExceptions = new List(); - foreach (PropertyValue pv in propertyValues) - { - try - { - SetPropertyValue(pv); - } - catch (NotWritablePropertyException ex) - { - if (!ignoreUnknown) - { - string message = $"Failed setting property '{pv.Name}'"; - Log.LogError(ex, message); - throw; - } - } - catch (InvalidPropertyException ex) - { - if (!ignoreUnknown) - { - string message = $"Failed setting property '{pv.Name}'"; - Log.LogError(ex, message); - throw; - } - } - catch (TypeMismatchException ex) // otherwise, just ignore it and continue... + if (!ignoreUnknown) { string message = $"Failed setting property '{pv.Name}'"; Log.LogError(ex, message); - propertyAccessExceptions.Add(ex); - } - catch (MethodInvocationException ex) - { - string message = $"Failed setting property '{pv.Name}'"; - Log.LogError(ex, message); - propertyAccessExceptions.Add(ex); - } - catch (Exception ex) - { - string message = $"Failed setting property '{pv.Name}' on instance of type '{WrappedType.FullName}'"; - Log.LogError(ex, message); throw; } } - - // if we encountered individual exceptions, throw the composite exception... - if (propertyAccessExceptions.Count > 0) + catch (InvalidPropertyException ex) { - throw new PropertyAccessExceptionsException(this, propertyAccessExceptions.ToArray()); - } - } - - /// - /// Returns PropertyInfo for the specified property - /// - /// The name of the property to search for. - /// The for the specified property. - /// If cannot be determined. - public PropertyInfo GetPropertyInfo(string propertyName) - { - return (PropertyInfo) GetPropertyOrFieldInfo(propertyName); - } - - /// - /// Get the for a particular property. - /// - /// - /// The property the of which is to be retrieved. - /// - /// - /// The for a particular property.. - /// - public Type GetPropertyType(string propertyName) - { - var memberInfo = GetPropertyOrFieldInfo(propertyName); - switch(memberInfo.MemberType) - { - case MemberTypes.Property: - return ((PropertyInfo) memberInfo).PropertyType; - case MemberTypes.Field: - return ((FieldInfo) memberInfo).FieldType; - default: - throw new FatalObjectException($"'{propertyName}' is not a valid property expression."); - } - } - - /// - /// Returns MemberInfo for the specified property or field - /// - /// The name of the property or field to search for. - /// The or for the specified property or field. - /// If does not resolve to a property or field. - private MemberInfo GetPropertyOrFieldInfo(string propertyOrFieldName) - { - if(StringUtils.IsNullOrEmpty(propertyOrFieldName)) - { - throw new FatalObjectException("Can't find property or field info for null or zero length property name."); - } - - try - { - IExpression propertyExpression = GetPropertyExpression(propertyOrFieldName); - if(propertyExpression is PropertyOrFieldNode propertyOrFieldNode) + if (!ignoreUnknown) { - return propertyOrFieldNode.GetMemberInfo(wrappedObject); + string message = $"Failed setting property '{pv.Name}'"; + Log.LogError(ex, message); + throw; } - - if(propertyExpression is IndexerNode indexerNode) - { - return indexerNode.GetPropertyInfo(wrappedObject, null); - } - - if(propertyExpression is Expression expression) - { - return expression.GetPropertyInfo(wrappedObject, null); - } - - throw new FatalObjectException($"'{propertyOrFieldName}' is not a valid property or field expression."); } - catch(RecognitionException e) + catch (TypeMismatchException ex) // otherwise, just ignore it and continue... { - throw new FatalObjectException($"Failed to parse property or field name '{propertyOrFieldName}'.", e); + string message = $"Failed setting property '{pv.Name}'"; + Log.LogError(ex, message); + propertyAccessExceptions.Add(ex); } - catch(TokenStreamRecognitionException e) + catch (MethodInvocationException ex) { - throw new FatalObjectException($"Failed to parse property or field name '{propertyOrFieldName}'.", e); - } - } - - - /// - /// Get the properties of the wrapped object. - /// - /// - /// An array of s. - /// - public PropertyInfo[] GetPropertyInfos() - { - return WrappedType.GetProperties(); - } - - /// - /// Return the collection of property descriptors. - /// - public PropertyDescriptorCollection PropertyDescriptors => TypeDescriptor.GetProperties(WrappedInstance); - - /// - /// This method is expensive! Only call for diagnostics and debugging reasons, - /// not in production. - /// - /// - /// A string describing the state of this object. - /// - public override string ToString() - { - StringBuilder sb = new StringBuilder(); - try - { - sb.Append("ObjectWrapper: wrapping class ["); - sb.Append(WrappedType.FullName); - sb.Append("]; "); - foreach (PropertyDescriptor p in PropertyDescriptors) - { - object val = GetPropertyValue(p.Name); - string valStr = (val != null) ? val.ToString() : "null"; - sb.Append(p.Name).Append("={").Append(valStr).Append("}"); - } + string message = $"Failed setting property '{pv.Name}'"; + Log.LogError(ex, message); + propertyAccessExceptions.Add(ex); } catch (Exception ex) { - sb.Append("Exception encountered: ").Append(ex); + string message = $"Failed setting property '{pv.Name}' on instance of type '{WrappedType.FullName}'"; + Log.LogError(ex, message); + throw; } - return sb.ToString(); } - private static readonly char[] propertyCharCheckArray = { '.', '[', '(', ' ', '{' }; - - /// - /// Attempts to parse property expression first and falls back to full expression - /// if that fails. Performance optimization. - /// - /// Property expression to parse. - /// Parsed proeprty expression. - internal static IExpression GetPropertyExpression(string propertyName) + // if we encountered individual exceptions, throw the composite exception... + if (propertyAccessExceptions.Count > 0) { - IExpression propertyExpression; - if (propertyName.IndexOfAny(propertyCharCheckArray) < 0) + throw new PropertyAccessExceptionsException(this, propertyAccessExceptions.ToArray()); + } + } + + /// + /// Returns PropertyInfo for the specified property + /// + /// The name of the property to search for. + /// The for the specified property. + /// If cannot be determined. + public PropertyInfo GetPropertyInfo(string propertyName) + { + return (PropertyInfo) GetPropertyOrFieldInfo(propertyName); + } + + /// + /// Get the for a particular property. + /// + /// + /// The property the of which is to be retrieved. + /// + /// + /// The for a particular property.. + /// + public Type GetPropertyType(string propertyName) + { + var memberInfo = GetPropertyOrFieldInfo(propertyName); + switch (memberInfo.MemberType) + { + case MemberTypes.Property: + return ((PropertyInfo) memberInfo).PropertyType; + case MemberTypes.Field: + return ((FieldInfo) memberInfo).FieldType; + default: + throw new FatalObjectException($"'{propertyName}' is not a valid property expression."); + } + } + + /// + /// Returns MemberInfo for the specified property or field + /// + /// The name of the property or field to search for. + /// The or for the specified property or field. + /// If does not resolve to a property or field. + private MemberInfo GetPropertyOrFieldInfo(string propertyOrFieldName) + { + if (StringUtils.IsNullOrEmpty(propertyOrFieldName)) + { + throw new FatalObjectException("Can't find property or field info for null or zero length property name."); + } + + try + { + IExpression propertyExpression = GetPropertyExpression(propertyOrFieldName); + if (propertyExpression is PropertyOrFieldNode propertyOrFieldNode) { - try - { - propertyExpression = Expression.ParseProperty(propertyName); - } - catch (Exception) - { - propertyExpression = Expression.ParsePrimary(propertyName); - } + return propertyOrFieldNode.GetMemberInfo(wrappedObject); } - else + + if (propertyExpression is IndexerNode indexerNode) + { + return indexerNode.GetPropertyInfo(wrappedObject, null); + } + + if (propertyExpression is Expression expression) + { + return expression.GetPropertyInfo(wrappedObject, null); + } + + throw new FatalObjectException($"'{propertyOrFieldName}' is not a valid property or field expression."); + } + catch (RecognitionException e) + { + throw new FatalObjectException($"Failed to parse property or field name '{propertyOrFieldName}'.", e); + } + catch (TokenStreamRecognitionException e) + { + throw new FatalObjectException($"Failed to parse property or field name '{propertyOrFieldName}'.", e); + } + } + + /// + /// Get the properties of the wrapped object. + /// + /// + /// An array of s. + /// + public PropertyInfo[] GetPropertyInfos() + { + return WrappedType.GetProperties(); + } + + /// + /// Return the collection of property descriptors. + /// + public PropertyDescriptorCollection PropertyDescriptors => TypeDescriptor.GetProperties(WrappedInstance); + + /// + /// This method is expensive! Only call for diagnostics and debugging reasons, + /// not in production. + /// + /// + /// A string describing the state of this object. + /// + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + try + { + sb.Append("ObjectWrapper: wrapping class ["); + sb.Append(WrappedType.FullName); + sb.Append("]; "); + foreach (PropertyDescriptor p in PropertyDescriptors) + { + object val = GetPropertyValue(p.Name); + string valStr = (val != null) ? val.ToString() : "null"; + sb.Append(p.Name).Append("={").Append(valStr).Append("}"); + } + } + catch (Exception ex) + { + sb.Append("Exception encountered: ").Append(ex); + } + + return sb.ToString(); + } + + private static readonly char[] propertyCharCheckArray = { '.', '[', '(', ' ', '{' }; + + /// + /// Attempts to parse property expression first and falls back to full expression + /// if that fails. Performance optimization. + /// + /// Property expression to parse. + /// Parsed proeprty expression. + internal static IExpression GetPropertyExpression(string propertyName) + { + IExpression propertyExpression; + if (propertyName.IndexOfAny(propertyCharCheckArray) < 0) + { + try + { + propertyExpression = Expression.ParseProperty(propertyName); + } + catch (Exception) { propertyExpression = Expression.ParsePrimary(propertyName); } - - return propertyExpression; } + else + { + propertyExpression = Expression.ParsePrimary(propertyName); + } + + return propertyExpression; } } diff --git a/src/Spring/Spring.Core/Objects/ObjectsException.cs b/src/Spring/Spring.Core/Objects/ObjectsException.cs index 0d2469f2..de9f675a 100644 --- a/src/Spring/Spring.Core/Objects/ObjectsException.cs +++ b/src/Spring/Spring.Core/Objects/ObjectsException.cs @@ -20,63 +20,64 @@ using System.Runtime.Serialization; -namespace Spring.Objects +namespace Spring.Objects; + +/// +/// Superclass for all exceptions thrown in the Objects namespace and sub-namespaces. +/// +/// Rod Johnson +/// Mark Pollack (.NET) +[Serializable] +public class ObjectsException : ApplicationException { - /// - /// Superclass for all exceptions thrown in the Objects namespace and sub-namespaces. - /// - /// Rod Johnson - /// Mark Pollack (.NET) - [Serializable] - public class ObjectsException : ApplicationException + #region Constructor (s) / Destructor + + /// Creates a new instance of the ObjectsException class. + public ObjectsException() { - #region Constructor (s) / Destructor - /// Creates a new instance of the ObjectsException class. - public ObjectsException() - { - } - - /// - /// Creates a new instance of the ObjectsException class. with the specified message. - /// - /// - /// A message about the exception. - /// - public ObjectsException (string message) : base(message) - { - } - - /// - /// Creates a new instance of the ObjectsException class with the specified message - /// and root cause. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception that is being wrapped. - /// - public ObjectsException (string message, Exception rootCause) - : base(message, rootCause) - { - } - - /// - /// Creates a new instance of the ObjectsException class. - /// - /// - /// The - /// that holds the serialized object data about the exception being thrown. - /// - /// - /// The - /// that contains contextual information about the source or destination. - /// - protected ObjectsException ( - SerializationInfo info, StreamingContext context) - : base (info, context) - { - } - #endregion } + + /// + /// Creates a new instance of the ObjectsException class. with the specified message. + /// + /// + /// A message about the exception. + /// + public ObjectsException(string message) : base(message) + { + } + + /// + /// Creates a new instance of the ObjectsException class with the specified message + /// and root cause. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception that is being wrapped. + /// + public ObjectsException(string message, Exception rootCause) + : base(message, rootCause) + { + } + + /// + /// Creates a new instance of the ObjectsException class. + /// + /// + /// The + /// that holds the serialized object data about the exception being thrown. + /// + /// + /// The + /// that contains contextual information about the source or destination. + /// + protected ObjectsException( + SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + + #endregion } diff --git a/src/Spring/Spring.Core/Objects/PropertyAccessExceptionsException.cs b/src/Spring/Spring.Core/Objects/PropertyAccessExceptionsException.cs index 1f20aac3..beab5ec9 100644 --- a/src/Spring/Spring.Core/Objects/PropertyAccessExceptionsException.cs +++ b/src/Spring/Spring.Core/Objects/PropertyAccessExceptionsException.cs @@ -27,228 +27,230 @@ using Spring.Core; #endregion -namespace Spring.Objects +namespace Spring.Objects; + +/// +/// Combined exception, composed of individual binding +/// s. +/// +/// +///

+/// An object of this class is created at the beginning of the binding +/// process, and errors added to it as necessary. +///

+///

+/// The binding process continues when it encounters application-level +/// s, applying those changes +/// that can be applied and storing rejected changes in an instance of this class. +///

+///
+/// Rod Johnson +/// Juergen Hoeller +/// Mark Pollack (.NET) +[Serializable] +public class PropertyAccessExceptionsException : ObjectsException { - /// - /// Combined exception, composed of individual binding - /// s. - /// - /// - ///

- /// An object of this class is created at the beginning of the binding - /// process, and errors added to it as necessary. - ///

- ///

- /// The binding process continues when it encounters application-level - /// s, applying those changes - /// that can be applied and storing rejected changes in an instance of this class. - ///

- ///
- /// Rod Johnson - /// Juergen Hoeller - /// Mark Pollack (.NET) - [Serializable] - public class PropertyAccessExceptionsException : ObjectsException - { - #region Constants + #region Constants - private static PropertyAccessException[] EmptyPropertyAccessExceptions - = new PropertyAccessException[] {}; + private static PropertyAccessException[] EmptyPropertyAccessExceptions + = new PropertyAccessException[] { }; - #endregion + #endregion - #region Constructor (s) / Destructor + #region Constructor (s) / Destructor - /// - /// Creates a new instance of the PropertyAccessExceptionsException class. - /// - public PropertyAccessExceptionsException() - { - } + /// + /// Creates a new instance of the PropertyAccessExceptionsException class. + /// + public PropertyAccessExceptionsException() + { + } - /// - /// Creates a new instance of the PropertyAccessExceptionsException class. - /// - /// - /// A message about the exception. - /// - public PropertyAccessExceptionsException(string message) - : base(message) - { - } + /// + /// Creates a new instance of the PropertyAccessExceptionsException class. + /// + /// + /// A message about the exception. + /// + public PropertyAccessExceptionsException(string message) + : base(message) + { + } - /// - /// Creates a new instance of the PropertyAccessExceptionsException class. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception that is being wrapped. - /// - public PropertyAccessExceptionsException(string message, Exception rootCause) - : base(message, rootCause) - { - } + /// + /// Creates a new instance of the PropertyAccessExceptionsException class. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception that is being wrapped. + /// + public PropertyAccessExceptionsException(string message, Exception rootCause) + : base(message, rootCause) + { + } - /// - /// Create new empty PropertyAccessExceptionsException. - /// We'll add errors to it as we attempt to bind properties. - /// - public PropertyAccessExceptionsException( - IObjectWrapper objectWrapper, - PropertyAccessException[] propertyAccessExceptions) - : base(string.Empty) - { - _objectWrapper = objectWrapper; - _propertyAccessExceptions = propertyAccessExceptions ?? EmptyPropertyAccessExceptions; - } + /// + /// Create new empty PropertyAccessExceptionsException. + /// We'll add errors to it as we attempt to bind properties. + /// + public PropertyAccessExceptionsException( + IObjectWrapper objectWrapper, + PropertyAccessException[] propertyAccessExceptions) + : base(string.Empty) + { + _objectWrapper = objectWrapper; + _propertyAccessExceptions = propertyAccessExceptions ?? EmptyPropertyAccessExceptions; + } - /// - /// Creates a new instance of the PropertyAccessExceptionsException class. - /// - /// - /// The - /// that holds the serialized object data about the exception being thrown. - /// - /// - /// The - /// that contains contextual information about the source or destination. - /// - protected PropertyAccessExceptionsException(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } + /// + /// Creates a new instance of the PropertyAccessExceptionsException class. + /// + /// + /// The + /// that holds the serialized object data about the exception being thrown. + /// + /// + /// The + /// that contains contextual information about the source or destination. + /// + protected PropertyAccessExceptionsException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } - #endregion + #endregion - /// - /// Return the that generated - /// this exception. - /// - public IObjectWrapper ObjectWrapper - { - get { return _objectWrapper; } - } + /// + /// Return the that generated + /// this exception. + /// + public IObjectWrapper ObjectWrapper + { + get { return _objectWrapper; } + } - /// - /// Return the object we're binding to. - /// - public object BindObject - { - get { return ObjectWrapper.WrappedInstance; } - } + /// + /// Return the object we're binding to. + /// + public object BindObject + { + get { return ObjectWrapper.WrappedInstance; } + } - /// - /// If this returns zero (0), no errors were encountered during binding. - /// - public int ExceptionCount - { - get { return PropertyAccessExceptions.Length; } - } + /// + /// If this returns zero (0), no errors were encountered during binding. + /// + public int ExceptionCount + { + get { return PropertyAccessExceptions.Length; } + } - /// - /// Return an array of the s - /// stored in this object. - /// - /// - ///

- /// Will return the empty array (not ) if there were no errors. - ///

- ///
- public virtual PropertyAccessException[] PropertyAccessExceptions - { - get { return _propertyAccessExceptions; } - } + /// + /// Return an array of the s + /// stored in this object. + /// + /// + ///

+ /// Will return the empty array (not ) if there were no errors. + ///

+ ///
+ public virtual PropertyAccessException[] PropertyAccessExceptions + { + get { return _propertyAccessExceptions; } + } - /// - /// Describe the group of exceptions. - /// - public override string Message - { - get - { - StringBuilder sb = new StringBuilder(); - sb.Append("PropertyAccessExceptionsException (") - .Append(ExceptionCount) - .Append(" errors)") - .Append("; nested PropertyAccessExceptions are: \n"); - for (int i = 0; i < PropertyAccessExceptions.Length; ++i) - { - PropertyAccessException pae = PropertyAccessExceptions[i]; - sb.Append("["); - sb.Append(pae.GetType().FullName); - sb.Append(": "); - sb.Append(pae.Message); - if (pae.InnerException != null) - { - sb.Append(", Inner Exception: "); - sb.Append(pae.InnerException.ToString()); - } - sb.Append(']'); - if (i < PropertyAccessExceptions.Length - 1) - { - sb.Append(", "); - } - } - return sb.ToString(); - } - } + /// + /// Describe the group of exceptions. + /// + public override string Message + { + get + { + StringBuilder sb = new StringBuilder(); + sb.Append("PropertyAccessExceptionsException (") + .Append(ExceptionCount) + .Append(" errors)") + .Append("; nested PropertyAccessExceptions are: \n"); + for (int i = 0; i < PropertyAccessExceptions.Length; ++i) + { + PropertyAccessException pae = PropertyAccessExceptions[i]; + sb.Append("["); + sb.Append(pae.GetType().FullName); + sb.Append(": "); + sb.Append(pae.Message); + if (pae.InnerException != null) + { + sb.Append(", Inner Exception: "); + sb.Append(pae.InnerException.ToString()); + } - /// - /// Populates a with - /// the data needed to serialize the target object. - /// - /// - /// The to populate - /// with data. - /// - /// - /// The destination (see ) - /// for this serialization. - /// - [SecurityPermission(SecurityAction.Demand, SerializationFormatter=true)] - public override void GetObjectData( - SerializationInfo info, StreamingContext context) - { - // TODO serialize me - base.GetObjectData(info, context); - } + sb.Append(']'); + if (i < PropertyAccessExceptions.Length - 1) + { + sb.Append(", "); + } + } - /// - /// The IObjectWrapper wrapping the target object at the root of the exception. - /// - private IObjectWrapper _objectWrapper; + return sb.ToString(); + } + } - /// The list of PropertyAccessException objects. - private PropertyAccessException[] _propertyAccessExceptions - = EmptyPropertyAccessExceptions; + /// + /// Populates a with + /// the data needed to serialize the target object. + /// + /// + /// The to populate + /// with data. + /// + /// + /// The destination (see ) + /// for this serialization. + /// + [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)] + public override void GetObjectData( + SerializationInfo info, StreamingContext context) + { + // TODO serialize me + base.GetObjectData(info, context); + } - /// - /// Return the - /// for the supplied , or - /// if there isn't one. - /// - public PropertyAccessException GetPropertyAccessException( - string propertyName) - { - foreach (PropertyAccessException pae in PropertyAccessExceptions) - { - if (propertyName.Equals(pae.PropertyChangeArgs.PropertyName)) - { - return pae; - } - } - return null; - } + /// + /// The IObjectWrapper wrapping the target object at the root of the exception. + /// + private IObjectWrapper _objectWrapper; - /// - /// Describe the number of exceptions contained in this container class. - /// - /// A description of the instance contents. - public override string ToString() - { - return Message; - } - } + /// The list of PropertyAccessException objects. + private PropertyAccessException[] _propertyAccessExceptions + = EmptyPropertyAccessExceptions; + + /// + /// Return the + /// for the supplied , or + /// if there isn't one. + /// + public PropertyAccessException GetPropertyAccessException( + string propertyName) + { + foreach (PropertyAccessException pae in PropertyAccessExceptions) + { + if (propertyName.Equals(pae.PropertyChangeArgs.PropertyName)) + { + return pae; + } + } + + return null; + } + + /// + /// Describe the number of exceptions contained in this container class. + /// + /// A description of the instance contents. + public override string ToString() + { + return Message; + } } diff --git a/src/Spring/Spring.Core/Objects/PropertyValue.cs b/src/Spring/Spring.Core/Objects/PropertyValue.cs index 8a013c50..565c2b02 100644 --- a/src/Spring/Spring.Core/Objects/PropertyValue.cs +++ b/src/Spring/Spring.Core/Objects/PropertyValue.cs @@ -24,169 +24,171 @@ using Spring.Expressions; using Spring.Expressions.Parser.antlr; using Spring.Util; -namespace Spring.Objects +namespace Spring.Objects; + +/// +/// Holds information and value for an individual property. +/// +/// +///

+/// Using an object here, rather than just storing all properties in a +/// map keyed by property name, allows for more flexibility, and the +/// ability to handle indexed properties in a special way if necessary. +///

+///

+/// Note that the value doesn't need to be the final required +/// : an +/// implementation must +/// handle any necessary conversion, as this object doesn't know anything +/// about the objects it will be applied to. +///

+///
+/// Rod Johnson +/// Mark Pollack (.NET) +[Serializable] +public class PropertyValue { + private readonly string propertyName; + private readonly object propertyValue; + private IExpression propertyExpression; + /// - /// Holds information and value for an individual property. + /// Creates a new instance of the + /// class. + /// + /// The name of the property. + /// + /// The value of the property (possibly before type conversion). + /// + /// + /// If the supplied is or + /// contains only whitespace character(s). + /// + public PropertyValue(string name, object val) + { + AssertUtils.ArgumentHasText(name, "name"); + + propertyName = name; + propertyValue = val; + } + + /// + /// Creates a new instance of the + /// class. + /// + /// The name of the property. + /// + /// The value of the property (possibly before type conversion). + /// + /// Pre-parsed property name. + /// + /// If the supplied or + /// is , or if the name contains only whitespace characters. + /// + public PropertyValue(string name, object val, IExpression expression) + { + AssertUtils.ArgumentHasText(name, "name"); + + propertyName = name; + propertyExpression = expression; + propertyValue = val; + } + + /// The name of the property. + /// The name of the property. + public string Name + { + get { return propertyName; } + } + + /// + /// Parsed property expression. + /// + public IExpression Expression + { + get + { + if (propertyExpression == null) + { + try + { + propertyExpression = ObjectWrapper.GetPropertyExpression(propertyName); + } + catch (RecognitionException e) + { + throw new InvalidPropertyException("Failed to parse property name '" + propertyName + "'.", e); + } + catch (TokenStreamRecognitionException e) + { + throw new InvalidPropertyException("Failed to parse property name '" + propertyName + "'.", e); + } + } + + return propertyExpression; + } + } + + /// + /// Return the value of the property. /// /// ///

- /// Using an object here, rather than just storing all properties in a - /// map keyed by property name, allows for more flexibility, and the - /// ability to handle indexed properties in a special way if necessary. - ///

- ///

- /// Note that the value doesn't need to be the final required - /// : an - /// implementation must - /// handle any necessary conversion, as this object doesn't know anything - /// about the objects it will be applied to. + /// Note that type conversion will not have occurred here. + /// It is the responsibility of the + /// implementation to + /// perform type conversion. ///

///
- /// Rod Johnson - /// Mark Pollack (.NET) - [Serializable] - public class PropertyValue + /// The (possibly unresolved) value of the property. + public object Value { - private readonly string propertyName; - private readonly object propertyValue; - private IExpression propertyExpression; + get { return propertyValue; } + } - /// - /// Creates a new instance of the - /// class. - /// - /// The name of the property. - /// - /// The value of the property (possibly before type conversion). - /// - /// - /// If the supplied is or - /// contains only whitespace character(s). - /// - public PropertyValue(string name, object val) + /// + /// Print a string representation of the property. + /// + /// A string representation of the property. + public override string ToString() + { + return string.Format(CultureInfo.InvariantCulture, "PropertyValue: name='{0}'; value=[{1}].", propertyName, propertyValue); + } + + /// + /// Determines whether the supplied + /// is equal to the current . + /// + /// The other instance. + /// + /// if they are equal in content. + /// + public override bool Equals(object other) + { + if (this == other) { - AssertUtils.ArgumentHasText(name, "name"); - - propertyName = name; - propertyValue = val; + return true; } - /// - /// Creates a new instance of the - /// class. - /// - /// The name of the property. - /// - /// The value of the property (possibly before type conversion). - /// - /// Pre-parsed property name. - /// - /// If the supplied or - /// is , or if the name contains only whitespace characters. - /// - public PropertyValue(string name, object val, IExpression expression) + if (!(other is PropertyValue)) { - AssertUtils.ArgumentHasText(name, "name"); - - propertyName = name; - propertyExpression = expression; - propertyValue = val; + return false; } - /// The name of the property. - /// The name of the property. - public string Name - { - get { return propertyName; } - } + PropertyValue otherPv = (PropertyValue) other; + return + (propertyName.Equals(otherPv.propertyName) + && ((propertyValue == null && otherPv.propertyValue == null) || propertyValue.Equals(otherPv.propertyValue))); + } - /// - /// Parsed property expression. - /// - public IExpression Expression - { - get - { - if (propertyExpression == null) - { - try - { - propertyExpression = ObjectWrapper.GetPropertyExpression(propertyName); - } - catch (RecognitionException e) - { - throw new InvalidPropertyException("Failed to parse property name '" + propertyName + "'.", e); - } - catch (TokenStreamRecognitionException e) - { - throw new InvalidPropertyException("Failed to parse property name '" + propertyName + "'.", e); - } - } - return propertyExpression; - } - } - - /// - /// Return the value of the property. - /// - /// - ///

- /// Note that type conversion will not have occurred here. - /// It is the responsibility of the - /// implementation to - /// perform type conversion. - ///

- ///
- /// The (possibly unresolved) value of the property. - public object Value - { - get { return propertyValue; } - } - - /// - /// Print a string representation of the property. - /// - /// A string representation of the property. - public override string ToString() - { - return string.Format(CultureInfo.InvariantCulture, "PropertyValue: name='{0}'; value=[{1}].", propertyName, propertyValue); - } - - /// - /// Determines whether the supplied - /// is equal to the current . - /// - /// The other instance. - /// - /// if they are equal in content. - /// - public override bool Equals(object other) - { - if (this == other) - { - return true; - } - if (!(other is PropertyValue)) - { - return false; - } - PropertyValue otherPv = (PropertyValue) other; - return - (propertyName.Equals(otherPv.propertyName) - && ((propertyValue == null && otherPv.propertyValue == null) || propertyValue.Equals(otherPv.propertyValue))); - } - - /// - /// Serves as a hash function for a particular type, suitable for use - /// in hashing algorithms and data structures like a hash table. - /// - /// - /// A hash code for the current . - /// - public override int GetHashCode() - { - return propertyName.GetHashCode() * 29 + (propertyValue != null ? propertyValue.GetHashCode() : 0); - } + /// + /// Serves as a hash function for a particular type, suitable for use + /// in hashing algorithms and data structures like a hash table. + /// + /// + /// A hash code for the current . + /// + public override int GetHashCode() + { + return propertyName.GetHashCode() * 29 + (propertyValue != null ? propertyValue.GetHashCode() : 0); } } diff --git a/src/Spring/Spring.Core/Objects/Support/AbstractEventHandlerValue.cs b/src/Spring/Spring.Core/Objects/Support/AbstractEventHandlerValue.cs index 60b330d3..53d01deb 100644 --- a/src/Spring/Spring.Core/Objects/Support/AbstractEventHandlerValue.cs +++ b/src/Spring/Spring.Core/Objects/Support/AbstractEventHandlerValue.cs @@ -21,128 +21,135 @@ using System.Globalization; using Spring.Util; -namespace Spring.Objects.Support +namespace Spring.Objects.Support; + +/// +/// Base class implementation for classes that describe an event handler. +/// +/// Rick Evans +public abstract class AbstractEventHandlerValue : IEventHandlerValue { - /// - /// Base class implementation for classes that describe an event handler. + #region Constructor (s) / Destructor + + /// + /// Creates a new instance of the + /// class. /// - /// Rick Evans - public abstract class AbstractEventHandlerValue : IEventHandlerValue + /// + ///

+ /// This is an class, and as such exposes no public constructors. + ///

+ ///
+ protected AbstractEventHandlerValue() { } + + /// + /// Creates a new instance of the + /// class. + /// + /// + /// The object (possibly unresolved) that is exposing the event. + /// + /// + /// The name of the method on the handler that is going to handle the event. + /// + /// + ///

+ /// This is an class, and as such exposes no public constructors. + ///

+ ///
+ protected AbstractEventHandlerValue(object source, string methodName) { - #region Constructor (s) / Destructor - /// - /// Creates a new instance of the - /// class. - /// - /// - ///

- /// This is an class, and as such exposes no public constructors. - ///

- ///
- protected AbstractEventHandlerValue() {} + _source = source; + _methodName = methodName; + } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The object (possibly unresolved) that is exposing the event. - /// - /// - /// The name of the method on the handler that is going to handle the event. - /// - /// - ///

- /// This is an class, and as such exposes no public constructors. - ///

- ///
- protected AbstractEventHandlerValue (object source, string methodName) + #endregion + + #region Properties + + /// + /// The source of the event (may be unresolved, as in the case + /// of a + /// value). + /// + public virtual object Source + { + get { - _source = source; - _methodName = methodName; + return _source; } - #endregion - - #region Properties - /// - /// The source of the event (may be unresolved, as in the case - /// of a - /// value). - /// - public virtual object Source + set { - get - { - return _source; - } - set - { - _source = value; - } + _source = value; } + } - /// - /// The name of the method that is going to handle the event. - /// - public virtual string MethodName + /// + /// The name of the method that is going to handle the event. + /// + public virtual string MethodName + { + get { - get - { - return _methodName; - } - set - { - _methodName = StringUtils.HasText (value) ? value.Trim () : string.Empty; - } + return _methodName; } - - /// - /// The name of the event that is being wired up. - /// - public virtual string EventName + set { - get - { - return _eventName; - } - set - { - _eventName = StringUtils.HasText (value) ? value.Trim () : string.Empty; - } + _methodName = StringUtils.HasText(value) ? value.Trim() : string.Empty; } - #endregion + } - #region Methods - /// - /// Wires up the specified handler to the named event on the - /// supplied event source. - /// - /// - /// The object (an object instance, a , etc) - /// exposing the named event. - /// - /// - /// The handler for the event (an object instance, a - /// , etc). - /// - public abstract void Wire (object source, object handler); - - /// - /// Returns a stringified representation of this object. - /// - /// A stringified representation of this object. - public override string ToString() + /// + /// The name of the event that is being wired up. + /// + public virtual string EventName + { + get { - return string.Format ( - CultureInfo.InvariantCulture, - "{0} [Source = '{1}', Method = '{2}']", GetType ().FullName, Source, MethodName); + return _eventName; } - #endregion + set + { + _eventName = StringUtils.HasText(value) ? value.Trim() : string.Empty; + } + } - #region Fields - private object _source; - private string _methodName; - private string _eventName; - #endregion - } + #endregion + + #region Methods + + /// + /// Wires up the specified handler to the named event on the + /// supplied event source. + /// + /// + /// The object (an object instance, a , etc) + /// exposing the named event. + /// + /// + /// The handler for the event (an object instance, a + /// , etc). + /// + public abstract void Wire(object source, object handler); + + /// + /// Returns a stringified representation of this object. + /// + /// A stringified representation of this object. + public override string ToString() + { + return string.Format( + CultureInfo.InvariantCulture, + "{0} [Source = '{1}', Method = '{2}']", GetType().FullName, Source, MethodName); + } + + #endregion + + #region Fields + + private object _source; + private string _methodName; + private string _eventName; + + #endregion } diff --git a/src/Spring/Spring.Core/Objects/Support/AbstractSharedStateFactory.cs b/src/Spring/Spring.Core/Objects/Support/AbstractSharedStateFactory.cs index fad0551a..19e82995 100644 --- a/src/Spring/Spring.Core/Objects/Support/AbstractSharedStateFactory.cs +++ b/src/Spring/Spring.Core/Objects/Support/AbstractSharedStateFactory.cs @@ -23,118 +23,118 @@ using Spring.Collections; using Spring.Core; using Spring.Util; -namespace Spring.Objects.Support -{ - /// - /// Convenience base class for implementations. - /// - public abstract class AbstractSharedStateFactory : ISharedStateFactory, IOrdered - { - private bool _caseSensitiveState; - private int _order = Int32.MaxValue; - private readonly IDictionary _sharedStateCache = new Hashtable(); +namespace Spring.Objects.Support; - /// - /// Create shared state dictionaries case-sensitive or case-insensitive? - /// - public bool CaseSensitiveState +/// +/// Convenience base class for implementations. +/// +public abstract class AbstractSharedStateFactory : ISharedStateFactory, IOrdered +{ + private bool _caseSensitiveState; + private int _order = Int32.MaxValue; + private readonly IDictionary _sharedStateCache = new Hashtable(); + + /// + /// Create shared state dictionaries case-sensitive or case-insensitive? + /// + public bool CaseSensitiveState + { + get { return _caseSensitiveState; } + set { _caseSensitiveState = value; } + } + + /// + /// Gets a dictionary acc. to the type of . + /// If no dictionary is found, create it according to + /// + /// the instance to obtain shared state for + /// the name of the instance. + /// + /// A dictionary containing the 's state, + /// or null if no state can be served by this provider. + /// + public IDictionary GetSharedStateFor(object instance, string name) + { + AssertUtils.ArgumentNotNull(instance, "instance"); + + if (!CanProvideState(instance, name)) { - get { return _caseSensitiveState; } - set { _caseSensitiveState = value; } + return null; } - /// - /// Gets a dictionary acc. to the type of . - /// If no dictionary is found, create it according to - /// - /// the instance to obtain shared state for - /// the name of the instance. - /// - /// A dictionary containing the 's state, - /// or null if no state can be served by this provider. - /// - public IDictionary GetSharedStateFor( object instance, string name ) + object key = GetKey(instance, name); + if (key == null) { - AssertUtils.ArgumentNotNull(instance, "instance"); + return null; + } - if (!CanProvideState(instance, name)) + IDictionary sharedState = (IDictionary) _sharedStateCache[key]; + if (sharedState == null) + { + lock (_sharedStateCache) { - return null; - } - - object key = GetKey(instance, name); - if (key == null) - { - return null; - } - - IDictionary sharedState = (IDictionary) _sharedStateCache[key]; - if (sharedState == null) - { - lock(_sharedStateCache) + sharedState = (IDictionary) _sharedStateCache[key]; + if (sharedState == null) { - sharedState = (IDictionary) _sharedStateCache[key]; - if (sharedState == null) - { - sharedState = CreateSharedStateDictionary(key); - _sharedStateCache[key] = sharedState; - } + sharedState = CreateSharedStateDictionary(key); + _sharedStateCache[key] = sharedState; } } - return sharedState; } - /// - /// A number indicating the priority of this ( for more). - /// - public virtual int Order - { - get { return _order; } - set { _order = value; } - } - - /// - /// Creates a dictionary to hold the shared state identified by . - /// - /// a key to create the dictionary for. - /// a dictionary according to and . - protected virtual IDictionary CreateSharedStateDictionary(object key) - { - return _caseSensitiveState ? new Hashtable() : new CaseInsensitiveHashtable(); - } - - /// - /// Indicate, whether the given instance will be served by this provider - /// - /// the instance to serve state - /// the name of the instance - /// - /// a boolean value indicating, whether state shall - /// be resolved for the given instance or not. - /// - public virtual bool CanProvideState(object instance, string name) - { - return true; - } - - /// - /// Create the key used for obtaining the state dictionary for . - /// - /// the instance to create the key for - /// the name of the instance. - /// - /// the key identifying the state dictionary to be used for - /// or null, if this state manager doesn't serve the given instance. - /// - /// - /// - /// Implementations may choose to return null from this method to indicate, - /// that they won't serve state for the given instance. - /// - /// - /// Note:Keys returned by this method are always treated case-sensitive! - /// - /// - protected abstract object GetKey(object instance, string name); + return sharedState; } + + /// + /// A number indicating the priority of this ( for more). + /// + public virtual int Order + { + get { return _order; } + set { _order = value; } + } + + /// + /// Creates a dictionary to hold the shared state identified by . + /// + /// a key to create the dictionary for. + /// a dictionary according to and . + protected virtual IDictionary CreateSharedStateDictionary(object key) + { + return _caseSensitiveState ? new Hashtable() : new CaseInsensitiveHashtable(); + } + + /// + /// Indicate, whether the given instance will be served by this provider + /// + /// the instance to serve state + /// the name of the instance + /// + /// a boolean value indicating, whether state shall + /// be resolved for the given instance or not. + /// + public virtual bool CanProvideState(object instance, string name) + { + return true; + } + + /// + /// Create the key used for obtaining the state dictionary for . + /// + /// the instance to create the key for + /// the name of the instance. + /// + /// the key identifying the state dictionary to be used for + /// or null, if this state manager doesn't serve the given instance. + /// + /// + /// + /// Implementations may choose to return null from this method to indicate, + /// that they won't serve state for the given instance. + /// + /// + /// Note:Keys returned by this method are always treated case-sensitive! + /// + /// + protected abstract object GetKey(object instance, string name); } diff --git a/src/Spring/Spring.Core/Objects/Support/AbstractWiringEventHandlerValue.cs b/src/Spring/Spring.Core/Objects/Support/AbstractWiringEventHandlerValue.cs index 392b3077..12de5817 100644 --- a/src/Spring/Spring.Core/Objects/Support/AbstractWiringEventHandlerValue.cs +++ b/src/Spring/Spring.Core/Objects/Support/AbstractWiringEventHandlerValue.cs @@ -22,132 +22,131 @@ using System.Globalization; using System.Reflection; using Spring.Util; -namespace Spring.Objects.Support +namespace Spring.Objects.Support; + +/// +/// Base class for all +/// implemenations that actually perform event wiring. +/// +/// Rick Evans +public abstract class AbstractWiringEventHandlerValue : AbstractEventHandlerValue { - /// - /// Base class for all - /// implemenations that actually perform event wiring. - /// - /// Rick Evans - public abstract class AbstractWiringEventHandlerValue : AbstractEventHandlerValue - { - #region Constructor (s) / Destructor + #region Constructor (s) / Destructor - /// - /// Creates a new instance of the - /// class. - /// - /// - ///

- /// This is an class, and as such exposes no public constructors. - ///

- ///
- protected AbstractWiringEventHandlerValue() - { - } + /// + /// Creates a new instance of the + /// class. + /// + /// + ///

+ /// This is an class, and as such exposes no public constructors. + ///

+ ///
+ protected AbstractWiringEventHandlerValue() + { + } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The object (possibly unresolved) that is exposing the event. - /// - /// - /// The name of the method on the handler that is going to handle the event. - /// - /// - ///

- /// This is an class, and as such exposes no public constructors. - ///

- ///
- protected AbstractWiringEventHandlerValue(object source, string methodName) - : base(source, methodName) - { - } + /// + /// Creates a new instance of the + /// class. + /// + /// + /// The object (possibly unresolved) that is exposing the event. + /// + /// + /// The name of the method on the handler that is going to handle the event. + /// + /// + ///

+ /// This is an class, and as such exposes no public constructors. + ///

+ ///
+ protected AbstractWiringEventHandlerValue(object source, string methodName) + : base(source, methodName) + { + } - #endregion + #endregion - #region Methods + #region Methods - /// - /// Wires up the specified handler to the named event on the - /// supplied event source. - /// - /// - /// The object (an object instance, a , etc) - /// exposing the named event. - /// - /// - /// The handler for the event (an object instance, a - /// , etc). - /// - public override void Wire(object source, object handler) - { - Type sourceType = ReflectionUtils.TypeOfOrType(source); - EventInfo eventInfo = sourceType.GetEvent(EventName); - Delegate callback = GetHandler(handler, eventInfo); - eventInfo.AddEventHandler(source, callback); - } + /// + /// Wires up the specified handler to the named event on the + /// supplied event source. + /// + /// + /// The object (an object instance, a , etc) + /// exposing the named event. + /// + /// + /// The handler for the event (an object instance, a + /// , etc). + /// + public override void Wire(object source, object handler) + { + Type sourceType = ReflectionUtils.TypeOfOrType(source); + EventInfo eventInfo = sourceType.GetEvent(EventName); + Delegate callback = GetHandler(handler, eventInfo); + eventInfo.AddEventHandler(source, callback); + } - /// - /// Gets the event handler. - /// - /// - /// The instance that is registering for the event notification. - /// - /// - /// Event metadata about the event. - /// - /// - /// The event handler. - /// - protected abstract Delegate GetHandler(object instance, EventInfo info); + /// + /// Gets the event handler. + /// + /// + /// The instance that is registering for the event notification. + /// + /// + /// Event metadata about the event. + /// + /// + /// The event handler. + /// + protected abstract Delegate GetHandler(object instance, EventInfo info); - /// - /// Resolves the method metadata that describes the method that is to be used - /// as the argument to a delegate constructor. - /// - /// - /// The exposing the method. - /// - /// - /// The of the delegate (e.g. System.EventHandler). - /// - /// - /// The custom binding flags to use when searching for the method. - /// - /// The method metadata. - /// - /// If the method could not be found. - /// - protected virtual MethodInfo ResolveHandlerMethod( - Type handlerType, Type delegateType, BindingFlags flags) - { - MethodInfo method = handlerType.GetMethod( - MethodName, - flags, - Type.DefaultBinder, - CallingConventions.Standard, - // cache this? for EventHandler types, we're always gonna get the same parameters - new DelegateInfo(delegateType).GetParameterTypes(), - null); + /// + /// Resolves the method metadata that describes the method that is to be used + /// as the argument to a delegate constructor. + /// + /// + /// The exposing the method. + /// + /// + /// The of the delegate (e.g. System.EventHandler). + /// + /// + /// The custom binding flags to use when searching for the method. + /// + /// The method metadata. + /// + /// If the method could not be found. + /// + protected virtual MethodInfo ResolveHandlerMethod( + Type handlerType, Type delegateType, BindingFlags flags) + { + MethodInfo method = handlerType.GetMethod( + MethodName, + flags, + Type.DefaultBinder, + CallingConventions.Standard, + // cache this? for EventHandler types, we're always gonna get the same parameters + new DelegateInfo(delegateType).GetParameterTypes(), + null); - #region Sanity Check + #region Sanity Check - if (method == null) - { - throw new FatalObjectException(string.Format( - CultureInfo.InvariantCulture, - "The '{0}' method could not be found on this object [{1}]", - MethodName, handlerType)); - } + if (method == null) + { + throw new FatalObjectException(string.Format( + CultureInfo.InvariantCulture, + "The '{0}' method could not be found on this object [{1}]", + MethodName, handlerType)); + } - #endregion + #endregion - return method; - } + return method; + } - #endregion - } + #endregion } diff --git a/src/Spring/Spring.Core/Objects/Support/ArgumentConvertingMethodInvoker.cs b/src/Spring/Spring.Core/Objects/Support/ArgumentConvertingMethodInvoker.cs index 6bd7ec63..188c630a 100644 --- a/src/Spring/Spring.Core/Objects/Support/ArgumentConvertingMethodInvoker.cs +++ b/src/Spring/Spring.Core/Objects/Support/ArgumentConvertingMethodInvoker.cs @@ -19,95 +19,94 @@ #endregion using System.ComponentModel; - using Spring.Core.TypeConversion; using Spring.Util; -namespace Spring.Objects.Support +namespace Spring.Objects.Support; + +/// +/// Specialisation of the class that tries +/// to convert the given arguments for the actual target method via an +/// appropriate implementation. +/// +/// Juergen Hoeller +/// Rick Evans +/// +public class ArgumentConvertingMethodInvoker : MethodInvoker { - /// - /// Specialisation of the class that tries - /// to convert the given arguments for the actual target method via an - /// appropriate implementation. - /// - /// Juergen Hoeller - /// Rick Evans - /// - public class ArgumentConvertingMethodInvoker : MethodInvoker - { - #region Constructor (s) / Destructor + #region Constructor (s) / Destructor - /// - /// Creates a new instance of the - /// class. - /// - public ArgumentConvertingMethodInvoker() - { - } + /// + /// Creates a new instance of the + /// class. + /// + public ArgumentConvertingMethodInvoker() + { + } - #endregion + #endregion - #region Properties + #region Properties - private ObjectWrapper Wrapper - { - get { return _wrapper; } - } + private ObjectWrapper Wrapper + { + get { return _wrapper; } + } - #endregion + #endregion - #region Methods + #region Methods - /// - /// Prepare the specified method. - /// - /// - ///

- /// The method can be invoked any number of times afterwards. - ///

- ///
- /// - /// If all required properties are not set. - /// - /// - /// If the specified method could not be found. - /// - public override void Prepare() - { - base.Prepare(); - // try to convert the arguments for the chosen method - Type[] requiredTypes = ReflectionUtils.GetParameterTypes(GetPreparedMethod()); - object[] arguments = PreparedArguments; - object[] convertedArguments = new object[arguments.Length]; - for (int i = 0; i < arguments.Length; ++i) - { - convertedArguments[i] = TypeConversionUtils.ConvertValueIfNecessary(requiredTypes[i], arguments[i], null); - } - PreparedArguments = convertedArguments; - } + /// + /// Prepare the specified method. + /// + /// + ///

+ /// The method can be invoked any number of times afterwards. + ///

+ ///
+ /// + /// If all required properties are not set. + /// + /// + /// If the specified method could not be found. + /// + public override void Prepare() + { + base.Prepare(); + // try to convert the arguments for the chosen method + Type[] requiredTypes = ReflectionUtils.GetParameterTypes(GetPreparedMethod()); + object[] arguments = PreparedArguments; + object[] convertedArguments = new object[arguments.Length]; + for (int i = 0; i < arguments.Length; ++i) + { + convertedArguments[i] = TypeConversionUtils.ConvertValueIfNecessary(requiredTypes[i], arguments[i], null); + } - /// - /// Register the given custom - /// for all properties of the given . - /// - /// - /// The of property. - /// - /// - /// The to register. - /// - public virtual void RegisterCustomConverter( - Type requiredType, TypeConverter typeConverter) - { - TypeConverterRegistry.RegisterConverter(requiredType, typeConverter); - } + PreparedArguments = convertedArguments; + } - #endregion + /// + /// Register the given custom + /// for all properties of the given . + /// + /// + /// The of property. + /// + /// + /// The to register. + /// + public virtual void RegisterCustomConverter( + Type requiredType, TypeConverter typeConverter) + { + TypeConverterRegistry.RegisterConverter(requiredType, typeConverter); + } - #region Fields + #endregion - private readonly ObjectWrapper _wrapper = new ObjectWrapper(); + #region Fields - #endregion - } + private readonly ObjectWrapper _wrapper = new ObjectWrapper(); + + #endregion } diff --git a/src/Spring/Spring.Core/Objects/Support/AutoWiringEventHandlerValue.cs b/src/Spring/Spring.Core/Objects/Support/AutoWiringEventHandlerValue.cs index 55da5f14..ddd7cb48 100644 --- a/src/Spring/Spring.Core/Objects/Support/AutoWiringEventHandlerValue.cs +++ b/src/Spring/Spring.Core/Objects/Support/AutoWiringEventHandlerValue.cs @@ -24,291 +24,290 @@ using Microsoft.Extensions.Logging; using Spring.Core; using Spring.Util; -namespace Spring.Objects.Support +namespace Spring.Objects.Support; + +/// +/// Describes an implementation +/// that autowires events to handler methods. +/// +/// Rick Evans +public class AutoWiringEventHandlerValue : AbstractEventHandlerValue { - /// - /// Describes an implementation - /// that autowires events to handler methods. - /// - /// Rick Evans - public class AutoWiringEventHandlerValue : AbstractEventHandlerValue - { - #region Constants + #region Constants - private const string EventNamePlaceHolder = "${event}"; + private const string EventNamePlaceHolder = "${event}"; - private const string DefaultMethodPrefix = "On"; + private const string DefaultMethodPrefix = "On"; - private const string DefaultMethodName = DefaultMethodPrefix + EventNamePlaceHolder; + private const string DefaultMethodName = DefaultMethodPrefix + EventNamePlaceHolder; - private static readonly ILogger log = LogManager.GetLogger(); + private static readonly ILogger log = LogManager.GetLogger(); - #endregion + #endregion - #region Constructor (s) / Destructor + #region Constructor (s) / Destructor - /// - /// Creates a new instance of the - /// class. - /// - public AutoWiringEventHandlerValue() - { - MethodName = DefaultMethodName; - } + /// + /// Creates a new instance of the + /// class. + /// + public AutoWiringEventHandlerValue() + { + MethodName = DefaultMethodName; + } - #endregion + #endregion - #region Properties + #region Properties - /// - /// The name of the method that is going to handle the event. - /// - public override string MethodName - { - get { return base.MethodName; } - set { base.MethodName = StringUtils.HasText(value) ? value.Trim() : DefaultMethodName; } - } + /// + /// The name of the method that is going to handle the event. + /// + public override string MethodName + { + get { return base.MethodName; } + set { base.MethodName = StringUtils.HasText(value) ? value.Trim() : DefaultMethodName; } + } - #endregion + #endregion - #region Methods + #region Methods - /// - /// Wires up the specified handler to the named event on the supplied event source. - /// - /// - /// The object (an object instance, a , etc) - /// exposing the named event. - /// - /// - /// The handler for the event (an object instance, a , - /// etc). - /// - public override void Wire(object source, object handler) - { - AssertUtils.ArgumentNotNull(source, "source"); - AssertUtils.ArgumentNotNull(handler, "handler"); - // simply delegate so that after wiring, state is wiped clean... - AutoWirer wirer = new AutoWirer(source, EventName, handler, MethodName); - wirer.Wire(); - } + /// + /// Wires up the specified handler to the named event on the supplied event source. + /// + /// + /// The object (an object instance, a , etc) + /// exposing the named event. + /// + /// + /// The handler for the event (an object instance, a , + /// etc). + /// + public override void Wire(object source, object handler) + { + AssertUtils.ArgumentNotNull(source, "source"); + AssertUtils.ArgumentNotNull(handler, "handler"); + // simply delegate so that after wiring, state is wiped clean... + AutoWirer wirer = new AutoWirer(source, EventName, handler, MethodName); + wirer.Wire(); + } - #endregion + #endregion - #region Inner Class : AutoWirer + #region Inner Class : AutoWirer - /// - /// Performs the matching up of handler methods to one or more source events. - /// - /// - ///

- /// This class merely marshals the matching of handler methods to the events exposed - /// by an event source, and then delegates to a concrete - /// implementation (such as - /// or - /// ) to do the heavy lifting of - /// actually wiring a handler method to an event. - ///

- ///

- /// Note : the order in which handler's are wired up to events is non-deterministic. - ///

- ///
- private sealed class AutoWirer - { - #region Constructor (s) / Destructor + /// + /// Performs the matching up of handler methods to one or more source events. + /// + /// + ///

+ /// This class merely marshals the matching of handler methods to the events exposed + /// by an event source, and then delegates to a concrete + /// implementation (such as + /// or + /// ) to do the heavy lifting of + /// actually wiring a handler method to an event. + ///

+ ///

+ /// Note : the order in which handler's are wired up to events is non-deterministic. + ///

+ ///
+ private sealed class AutoWirer + { + #region Constructor (s) / Destructor - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The object exposing the event (s) being wired up. - /// - /// - /// The name of the event that is being wired up. - /// - /// - /// The object exposing the method (s) being wired to the event. - /// - /// - /// The name of the method that is going to handle the event. - /// - public AutoWirer( - object source, string eventName, object handler, string methodName) - { - Source = source; - EventName = eventName; - Handler = handler; - MethodName = methodName; - } + /// + /// Creates a new instance of the + /// class. + /// + /// + /// The object exposing the event (s) being wired up. + /// + /// + /// The name of the event that is being wired up. + /// + /// + /// The object exposing the method (s) being wired to the event. + /// + /// + /// The name of the method that is going to handle the event. + /// + public AutoWirer( + object source, string eventName, object handler, string methodName) + { + Source = source; + EventName = eventName; + Handler = handler; + MethodName = methodName; + } - #endregion + #endregion - #region Methods + #region Methods - /// - /// Wires up events on the source to methods exposed on the handler. - /// - public void Wire() - { - Type sourceType = ReflectionUtils.TypeOfOrType(Source); - // create the criteria for the event search... - ICriteria criteria = new RegularExpressionEventNameCriteria(EventName); - // and grab the events that satisfy the criteria... - BindingFlags eventFlags = BindingFlags.Instance | BindingFlags.Static - | BindingFlags.Public; - MemberInfo[] events = sourceType.FindMembers( - MemberTypes.Event, - eventFlags, - new MemberFilter(new CriteriaMemberFilter().FilterMemberByCriteria), - criteria); - // and for each event that satisfied the criteria... - foreach (EventInfo evt in events) - { - WireEvent(evt); - } - } + /// + /// Wires up events on the source to methods exposed on the handler. + /// + public void Wire() + { + Type sourceType = ReflectionUtils.TypeOfOrType(Source); + // create the criteria for the event search... + ICriteria criteria = new RegularExpressionEventNameCriteria(EventName); + // and grab the events that satisfy the criteria... + BindingFlags eventFlags = BindingFlags.Instance | BindingFlags.Static + | BindingFlags.Public; + MemberInfo[] events = sourceType.FindMembers( + MemberTypes.Event, + eventFlags, + new MemberFilter(new CriteriaMemberFilter().FilterMemberByCriteria), + criteria); + // and for each event that satisfied the criteria... + foreach (EventInfo evt in events) + { + WireEvent(evt); + } + } - /// - /// Wires up the supplied event to any handler methods that match the event - /// signature. - /// - /// The event being wired up. - private void WireEvent(EventInfo theEvent) - { - // grab some info (such as the delegate's method signature) about the event - DelegateInfo eventDelegate = new DelegateInfo(theEvent); - // if the method name needs to be customised on a per event basis, do so - string customMethodName = GetMethodNameCustomisedForEvent(theEvent.Name); + /// + /// Wires up the supplied event to any handler methods that match the event + /// signature. + /// + /// The event being wired up. + private void WireEvent(EventInfo theEvent) + { + // grab some info (such as the delegate's method signature) about the event + DelegateInfo eventDelegate = new DelegateInfo(theEvent); + // if the method name needs to be customised on a per event basis, do so + string customMethodName = GetMethodNameCustomisedForEvent(theEvent.Name); - // create the criteria for the handler method search... - ComposedCriteria methodCriteria = new ComposedCriteria(); - // a candidate handlers method name must match the custom method name - methodCriteria.Add(new RegularExpressionMethodNameCriteria(customMethodName)); - // the return Type of a candidate handlers method must be the same as the return type of the event - methodCriteria.Add(new MethodReturnTypeCriteria(eventDelegate.GetReturnType())); - // a candidate handlers method parameters must match the event's parameters - methodCriteria.Add(new MethodParametersCriteria(eventDelegate.GetParameterTypes())); + // create the criteria for the handler method search... + ComposedCriteria methodCriteria = new ComposedCriteria(); + // a candidate handlers method name must match the custom method name + methodCriteria.Add(new RegularExpressionMethodNameCriteria(customMethodName)); + // the return Type of a candidate handlers method must be the same as the return type of the event + methodCriteria.Add(new MethodReturnTypeCriteria(eventDelegate.GetReturnType())); + // a candidate handlers method parameters must match the event's parameters + methodCriteria.Add(new MethodParametersCriteria(eventDelegate.GetParameterTypes())); - // and grab the methods that satisfy the criteria... - BindingFlags methodFlags = BindingFlags.Instance | BindingFlags.Static - | BindingFlags.NonPublic | BindingFlags.Public; - MemberInfo[] methods = HandlerType.FindMembers( - MemberTypes.Method, - methodFlags, - new MemberFilter(new CriteriaMemberFilter().FilterMemberByCriteria), - methodCriteria); + // and grab the methods that satisfy the criteria... + BindingFlags methodFlags = BindingFlags.Instance | BindingFlags.Static + | BindingFlags.NonPublic | BindingFlags.Public; + MemberInfo[] methods = HandlerType.FindMembers( + MemberTypes.Method, + methodFlags, + new MemberFilter(new CriteriaMemberFilter().FilterMemberByCriteria), + methodCriteria); - // and for each method that satisfied the criteria... - foreach (MethodInfo method in methods) - { - #region Instrumentation + // and for each method that satisfied the criteria... + foreach (MethodInfo method in methods) + { + #region Instrumentation - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug(string.Format( - CultureInfo.InvariantCulture, - "Wiring up this method '{0}' to this event '{1}'", - method.Name, - theEvent.Name)); - } + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug(string.Format( + CultureInfo.InvariantCulture, + "Wiring up this method '{0}' to this event '{1}'", + method.Name, + theEvent.Name)); + } - #endregion + #endregion - IEventHandlerValue myHandler = method.IsStatic ? - new StaticEventHandlerValue() : - (IEventHandlerValue) new InstanceEventHandlerValue(); - myHandler.EventName = theEvent.Name; - myHandler.MethodName = method.Name; - myHandler.Wire(Source, Handler); - } - } + IEventHandlerValue myHandler = method.IsStatic ? new StaticEventHandlerValue() : (IEventHandlerValue) new InstanceEventHandlerValue(); + myHandler.EventName = theEvent.Name; + myHandler.MethodName = method.Name; + myHandler.Wire(Source, Handler); + } + } - /// - /// Only replaces the first occurrence of the placeholder. - /// - /// The event whose name is going to be used. - /// - /// The method name customised for the name of the supplied event. - /// - private string GetMethodNameCustomisedForEvent(string eventName) - { - string methodName = MethodName; - if (MethodName.IndexOf(EventNamePlaceHolder) >= 0) - { - methodName = MethodName.Replace(EventNamePlaceHolder, eventName); - } - return methodName; - } + /// + /// Only replaces the first occurrence of the placeholder. + /// + /// The event whose name is going to be used. + /// + /// The method name customised for the name of the supplied event. + /// + private string GetMethodNameCustomisedForEvent(string eventName) + { + string methodName = MethodName; + if (MethodName.IndexOf(EventNamePlaceHolder) >= 0) + { + methodName = MethodName.Replace(EventNamePlaceHolder, eventName); + } - #endregion + return methodName; + } - #region Properties + #endregion - /// - /// The object exposing the event (s) being wired up. - /// - private object Source - { - get { return _source; } - set { _source = value; } - } + #region Properties - /// - /// The object exposing the method (s) being wired to an event source. - /// - private object Handler - { - get { return _handler; } - set { _handler = value; } - } + /// + /// The object exposing the event (s) being wired up. + /// + private object Source + { + get { return _source; } + set { _source = value; } + } - /// - /// The of the object that is handling any events. - /// - private Type HandlerType - { - get - { - if (_handlerType == null) - { - _handlerType = ReflectionUtils.TypeOfOrType(Handler); - } - return _handlerType; - } - } + /// + /// The object exposing the method (s) being wired to an event source. + /// + private object Handler + { + get { return _handler; } + set { _handler = value; } + } - /// - /// The name of the method that is going to handle the event. - /// - private string MethodName - { - get { return _methodName; } - set { _methodName = value; } - } + /// + /// The of the object that is handling any events. + /// + private Type HandlerType + { + get + { + if (_handlerType == null) + { + _handlerType = ReflectionUtils.TypeOfOrType(Handler); + } - /// - /// The name of the event that is being wired up. - /// - private string EventName - { - get { return _eventName; } - set { _eventName = value; } - } + return _handlerType; + } + } - #endregion + /// + /// The name of the method that is going to handle the event. + /// + private string MethodName + { + get { return _methodName; } + set { _methodName = value; } + } - #region Fields + /// + /// The name of the event that is being wired up. + /// + private string EventName + { + get { return _eventName; } + set { _eventName = value; } + } - private object _source; - private object _handler; - private string _methodName; - private string _eventName; - private Type _handlerType; + #endregion - #endregion - } + #region Fields - #endregion - } + private object _source; + private object _handler; + private string _methodName; + private string _eventName; + private Type _handlerType; + + #endregion + } + + #endregion } diff --git a/src/Spring/Spring.Core/Objects/Support/ByTypeSharedStateFactory.cs b/src/Spring/Spring.Core/Objects/Support/ByTypeSharedStateFactory.cs index 8e8c38fa..08924acc 100644 --- a/src/Spring/Spring.Core/Objects/Support/ByTypeSharedStateFactory.cs +++ b/src/Spring/Spring.Core/Objects/Support/ByTypeSharedStateFactory.cs @@ -18,81 +18,82 @@ #endregion -namespace Spring.Objects.Support +namespace Spring.Objects.Support; + +/// +/// Serves shared state on a by-type basis. +/// +public class ByTypeSharedStateFactory : AbstractSharedStateFactory { + private Type[] typeFilter; + /// - /// Serves shared state on a by-type basis. + /// Limit object types to be served by this state manager. /// - public class ByTypeSharedStateFactory : AbstractSharedStateFactory + /// + /// Only objects assignable to one of the types in this list + /// will be served state by this manager. + /// + public Type[] TypeFilter { - private Type[] typeFilter; + set { typeFilter = value; } + } - /// - /// Limit object types to be served by this state manager. - /// - /// - /// Only objects assignable to one of the types in this list - /// will be served state by this manager. - /// - public Type[] TypeFilter - { - set { typeFilter = value; } - } + /// + /// Creates a new instance matching all types by default. + /// + public ByTypeSharedStateFactory() + { + } - /// - /// Creates a new instance matching all types by default. - /// - public ByTypeSharedStateFactory() - {} + /// + /// Creates a new instance matching only specified list of types. + /// + /// the list of types to serve. + public ByTypeSharedStateFactory(Type[] typeFilter) + { + this.typeFilter = typeFilter; + } - /// - /// Creates a new instance matching only specified list of types. - /// - /// the list of types to serve. - public ByTypeSharedStateFactory(Type[] typeFilter) - { - this.typeFilter = typeFilter; - } - - /// - /// Indicate, whether the given instance will be served by this provider - /// - /// the instance to serve state - /// the name of the instance - /// - /// a boolean value indicating, whether state shall - /// be resolved for the given instance or not. - /// - public override bool CanProvideState( object instance, string name ) - { - if (instance == null) - return false; - - if (typeFilter == null) - return true; - - Type instanceType = instance.GetType(); - foreach (Type type in typeFilter) - { - if (type.IsAssignableFrom( instanceType )) - return true; - } + /// + /// Indicate, whether the given instance will be served by this provider + /// + /// the instance to serve state + /// the name of the instance + /// + /// a boolean value indicating, whether state shall + /// be resolved for the given instance or not. + /// + public override bool CanProvideState(object instance, string name) + { + if (instance == null) return false; + + if (typeFilter == null) + return true; + + Type instanceType = instance.GetType(); + foreach (Type type in typeFilter) + { + if (type.IsAssignableFrom(instanceType)) + return true; } - /// - /// Returns the for the given . - /// - /// the instance to obtain the key for. - /// the name of the instance (ignored by this provider) - /// instance.GetType() if it matches the list. Null otherwise. - /// - /// This method will only be called if returned true previously. - /// - protected override object GetKey( object instance, string name ) - { - Type key = instance.GetType(); - return key; - } + return false; + } + + /// + /// Returns the for the given . + /// + /// the instance to obtain the key for. + /// the name of the instance (ignored by this provider) + /// instance.GetType() if it matches the list. Null otherwise. + /// + /// This method will only be called if returned true previously. + /// + protected override object GetKey(object instance, string name) + { + Type key = instance.GetType(); + return key; } } diff --git a/src/Spring/Spring.Core/Objects/Support/ISortDefinition.cs b/src/Spring/Spring.Core/Objects/Support/ISortDefinition.cs index a961eae6..cad1a6f3 100644 --- a/src/Spring/Spring.Core/Objects/Support/ISortDefinition.cs +++ b/src/Spring/Spring.Core/Objects/Support/ISortDefinition.cs @@ -18,43 +18,42 @@ #endregion -namespace Spring.Objects.Support +namespace Spring.Objects.Support; + +/// +/// Definition for sorting object instances by a property. +/// +/// Juergen Hoeller +/// Simon White (.NET) +public interface ISortDefinition { - /// - /// Definition for sorting object instances by a property. - /// - /// Juergen Hoeller - /// Simon White (.NET) - public interface ISortDefinition - { - /// - /// The name of the property to sort by. - /// - string Property - { - get; - } + /// + /// The name of the property to sort by. + /// + string Property + { + get; + } - /// - /// Whether upper and lower case in string values should be ignored. - /// - /// - /// True if the sorting should be performed in a case-insensitive fashion. - /// - bool IgnoreCase - { - get; - } + /// + /// Whether upper and lower case in string values should be ignored. + /// + /// + /// True if the sorting should be performed in a case-insensitive fashion. + /// + bool IgnoreCase + { + get; + } - /// - /// If the sorting should be ascending or descending. - /// - /// - /// True if the sorting should be in the ascending order. - /// - bool Ascending - { - get; - } - } + /// + /// If the sorting should be ascending or descending. + /// + /// + /// True if the sorting should be in the ascending order. + /// + bool Ascending + { + get; + } } diff --git a/src/Spring/Spring.Core/Objects/Support/InstanceEventHandlerValue.cs b/src/Spring/Spring.Core/Objects/Support/InstanceEventHandlerValue.cs index b98e7e13..fa8a9599 100644 --- a/src/Spring/Spring.Core/Objects/Support/InstanceEventHandlerValue.cs +++ b/src/Spring/Spring.Core/Objects/Support/InstanceEventHandlerValue.cs @@ -21,90 +21,90 @@ using System.Reflection; using Spring.Util; -namespace Spring.Objects.Support +namespace Spring.Objects.Support; + +/// +/// Describes an event handler for an object instance. +/// +/// Rick Evans +public class InstanceEventHandlerValue : AbstractWiringEventHandlerValue { - /// - /// Describes an event handler for an object instance. - /// - /// Rick Evans - public class InstanceEventHandlerValue : AbstractWiringEventHandlerValue - { - #region Constants + #region Constants - private static readonly BindingFlags InstanceMethodFlags = - BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | - BindingFlags.IgnoreCase | BindingFlags.Static; + private static readonly BindingFlags InstanceMethodFlags = + BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | + BindingFlags.IgnoreCase | BindingFlags.Static; - #endregion + #endregion - #region Constructor (s) / Destructor + #region Constructor (s) / Destructor - /// - /// Creates a new instance of the - /// class. - /// - public InstanceEventHandlerValue() - { - } + /// + /// Creates a new instance of the + /// class. + /// + public InstanceEventHandlerValue() + { + } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The object (possibly unresolved) that is exposing the event. - /// - /// - /// The name of the method on the handler that is going to handle the event. - /// - public InstanceEventHandlerValue(object source, string methodName) - : base(source, methodName) - { - } + /// + /// Creates a new instance of the + /// class. + /// + /// + /// The object (possibly unresolved) that is exposing the event. + /// + /// + /// The name of the method on the handler that is going to handle the event. + /// + public InstanceEventHandlerValue(object source, string methodName) + : base(source, methodName) + { + } - #endregion + #endregion - #region Methods + #region Methods - /// - /// Gets the event handler. - /// - /// - /// The instance that is registering for the event notification. - /// - /// - /// Event metadata about the event. - /// - /// - /// The event handler. - /// - protected override Delegate GetHandler(object instance, EventInfo info) - { - MethodInfo methodMeta = ResolveHandlerMethod( - ReflectionUtils.TypeOfOrType(instance), - info.EventHandlerType, - InstanceEventHandlerValue.InstanceMethodFlags); - Delegate callback = null; - if (methodMeta.IsStatic) - { - // case insensitive binding to a static method on an (irrelevant) instance - callback = Delegate.CreateDelegate( - info.EventHandlerType, - methodMeta); - } - else - { - // case insensitive binding to an instance method on an instance - callback = - Delegate.CreateDelegate( - info.EventHandlerType, - instance, - MethodName, - true); - } - return callback; - } + /// + /// Gets the event handler. + /// + /// + /// The instance that is registering for the event notification. + /// + /// + /// Event metadata about the event. + /// + /// + /// The event handler. + /// + protected override Delegate GetHandler(object instance, EventInfo info) + { + MethodInfo methodMeta = ResolveHandlerMethod( + ReflectionUtils.TypeOfOrType(instance), + info.EventHandlerType, + InstanceEventHandlerValue.InstanceMethodFlags); + Delegate callback = null; + if (methodMeta.IsStatic) + { + // case insensitive binding to a static method on an (irrelevant) instance + callback = Delegate.CreateDelegate( + info.EventHandlerType, + methodMeta); + } + else + { + // case insensitive binding to an instance method on an instance + callback = + Delegate.CreateDelegate( + info.EventHandlerType, + instance, + MethodName, + true); + } - #endregion - } + return callback; + } + + #endregion } diff --git a/src/Spring/Spring.Core/Objects/Support/MethodInvoker.cs b/src/Spring/Spring.Core/Objects/Support/MethodInvoker.cs index af727bdf..19d39bf7 100644 --- a/src/Spring/Spring.Core/Objects/Support/MethodInvoker.cs +++ b/src/Spring/Spring.Core/Objects/Support/MethodInvoker.cs @@ -21,514 +21,524 @@ using System.Collections; using System.Globalization; using System.Reflection; - using Spring.Core; using Spring.Core.TypeResolution; -namespace Spring.Objects.Support +namespace Spring.Objects.Support; + +/// +/// Helper class allowing one to declaratively specify a method call for later invocation. +/// +/// +///

+/// Typically not used directly but via its subclasses such as +/// . +///

+///

+/// Usage: specify either the and +/// or the +/// and +/// properties respectively, and +/// (optionally) any arguments to the method. Then call the +/// method to prepare the invoker. +/// Once prepared, the invoker can be invoked any number of times. +///

+///
+/// +///

+/// The following example uses the class to invoke the +/// ToString() method on the Foo class using a mixture of both named and unnamed +/// arguments. +///

+/// +/// public class Foo +/// { +/// public string ToString(string name, int age, string address) +/// { +/// return string.Format("{0}, {1} years old, {2}", name, age, address); +/// } +/// +/// public static void Main() +/// { +/// Foo foo = new Foo(); +/// MethodInvoker invoker = new MethodInvoker(); +/// invoker.Arguments = new object [] {"Kaneda", "18 Kaosu Gardens, Nakatani Drive, Okinanawa"}; +/// invoker.AddNamedArgument("age", 29); +/// invoker.Prepare(); +/// // at this point, the arguments that will be passed to the method invocation +/// // will have been resolved into the following ordered array : {"Kaneda", 29, "18 Kaosu Gardens, Nakatani Drive, Okinanawa"} +/// string details = (string) invoker.Invoke(); +/// Console.WriteLine (details); +/// // will print out 'Kaneda, 29 years old, 18 Kaosu Gardens, Nakatani Drive, Okinanawa' +/// } +/// } +/// +///
+/// Colin Sampaleanu +/// Juergen Hoeller +/// Simon White (.NET) +public class MethodInvoker { - /// - /// Helper class allowing one to declaratively specify a method call for later invocation. - /// - /// - ///

- /// Typically not used directly but via its subclasses such as - /// . - ///

- ///

- /// Usage: specify either the and - /// or the - /// and - /// properties respectively, and - /// (optionally) any arguments to the method. Then call the - /// method to prepare the invoker. - /// Once prepared, the invoker can be invoked any number of times. - ///

- ///
- /// - ///

- /// The following example uses the class to invoke the - /// ToString() method on the Foo class using a mixture of both named and unnamed - /// arguments. - ///

- /// - /// public class Foo - /// { - /// public string ToString(string name, int age, string address) - /// { - /// return string.Format("{0}, {1} years old, {2}", name, age, address); - /// } - /// - /// public static void Main() - /// { - /// Foo foo = new Foo(); - /// MethodInvoker invoker = new MethodInvoker(); - /// invoker.Arguments = new object [] {"Kaneda", "18 Kaosu Gardens, Nakatani Drive, Okinanawa"}; - /// invoker.AddNamedArgument("age", 29); - /// invoker.Prepare(); - /// // at this point, the arguments that will be passed to the method invocation - /// // will have been resolved into the following ordered array : {"Kaneda", 29, "18 Kaosu Gardens, Nakatani Drive, Okinanawa"} - /// string details = (string) invoker.Invoke(); - /// Console.WriteLine (details); - /// // will print out 'Kaneda, 29 years old, 18 Kaosu Gardens, Nakatani Drive, Okinanawa' - /// } - /// } - /// - ///
- /// Colin Sampaleanu - /// Juergen Hoeller - /// Simon White (.NET) - public class MethodInvoker - { - #region Fields + #region Fields - /// - /// The value returned from the invocation of a method that returns void. - /// - public static readonly Missing Void = Missing.Value; + /// + /// The value returned from the invocation of a method that returns void. + /// + public static readonly Missing Void = Missing.Value; - private Type _targetType; - private object _targetObject; - private string _targetMethod; - private object[] _arguments; - private IDictionary _namedArguments; - private object[] _preparedArguments; + private Type _targetType; + private object _targetObject; + private string _targetMethod; + private object[] _arguments; + private IDictionary _namedArguments; + private object[] _preparedArguments; - /// - /// The method that will be invoked. - /// - private MethodInfo _methodObject; + /// + /// The method that will be invoked. + /// + private MethodInfo _methodObject; - /// - /// The used to search for - /// the method to be invoked. - /// - private const BindingFlags MethodSearchingFlags = - BindingFlags.Instance | - BindingFlags.Static | - BindingFlags.Public | - BindingFlags.NonPublic | - BindingFlags.IgnoreCase; + /// + /// The used to search for + /// the method to be invoked. + /// + private const BindingFlags MethodSearchingFlags = + BindingFlags.Instance | + BindingFlags.Static | + BindingFlags.Public | + BindingFlags.NonPublic | + BindingFlags.IgnoreCase; - #endregion + #endregion - #region Constructor (s) / Destructor + #region Constructor (s) / Destructor - /// - /// Creates a new instance of the class. - /// - public MethodInvoker() - { - Arguments = new object[] {}; - NamedArguments = new Hashtable(); - PreparedArguments = new object[] {}; - } + /// + /// Creates a new instance of the class. + /// + public MethodInvoker() + { + Arguments = new object[] { }; + NamedArguments = new Hashtable(); + PreparedArguments = new object[] { }; + } - #endregion + #endregion - #region Properties + #region Properties - /// - /// The target on which to call the target method. - /// - /// - ///

- /// Only necessary when the target method is ; - /// else, a target object needs to be specified. - ///

- ///
- public Type TargetType - { - get { return _targetType; } - set { this._targetType = value; } - } + /// + /// The target on which to call the target method. + /// + /// + ///

+ /// Only necessary when the target method is ; + /// else, a target object needs to be specified. + ///

+ ///
+ public Type TargetType + { + get { return _targetType; } + set { this._targetType = value; } + } - /// - /// The target object on which to call the target method. - /// - /// - ///

- /// Only necessary when the target method is not ; - /// else, a target class is sufficient. - ///

- ///
- public object TargetObject - { - get { return _targetObject; } - set { this._targetObject = value; } - } + /// + /// The target object on which to call the target method. + /// + /// + ///

+ /// Only necessary when the target method is not ; + /// else, a target class is sufficient. + ///

+ ///
+ public object TargetObject + { + get { return _targetObject; } + set { this._targetObject = value; } + } - /// - /// The name of the method to be invoked. - /// - /// - ///

- /// Refers to either a method - /// or a non- method, depending on - /// whether or not a target object has been set. - ///

- ///
- /// - public string TargetMethod - { - get { return _targetMethod; } - set { this._targetMethod = value; } - } + /// + /// The name of the method to be invoked. + /// + /// + ///

+ /// Refers to either a method + /// or a non- method, depending on + /// whether or not a target object has been set. + ///

+ ///
+ /// + public string TargetMethod + { + get { return _targetMethod; } + set { this._targetMethod = value; } + } - /// - /// Arguments for the method invocation. - /// - /// - ///

- /// Ordering is significant... the order of the arguments in this - /// property must match the ordering of the various parameters on the target - /// method. There does however exist a small possibility for confusion when - /// the arguments in this property are supplied in addition to one or more named - /// arguments. In this case, each named argument is slotted into the index position - /// corresponding to the named argument... once once all named arguments have been - /// resolved, the arguments in this property are slotted into any remaining (empty) - /// slots in the method parameter list (see the example in the overview of the - /// class if this is not clear). - ///

- ///

- /// If this property is not set, or the value passed to the setter invocation - /// is or a zero-length array, a method with no (un-named) arguments is assumed. - ///

- ///
- /// - public object[] Arguments - { - get { return _arguments; } - set - { - if (value != null) - { - this._arguments = value; - } - else - { - this._arguments = new object[] {}; - } - } - } - - /// - /// The resolved arguments for the method invocation. - /// - /// - /// - /// This property is not set until the target method has been resolved via a call to the - /// method). It is a combination of the - /// named and plain vanilla arguments properties, and it is this object array that - /// will actually be passed to the invocation of the target method. - /// - ///

- /// Setting the value of this property to results in basically clearing out any - /// previously prepared arguments... another call to the - /// method will then be required to prepare the arguments again (or the prepared arguments - /// can be set explicitly if so desired). - ///

- ///
- /// - /// - protected object[] PreparedArguments - { - get { return _preparedArguments; } - set - { - if (value != null) - { - this._preparedArguments = value; - } - else - { - this._preparedArguments = new object[] {}; - } - } - } - - /// - /// Named arguments for the method invocation. - /// - /// - ///

- /// The keys of this dictionary are the () names of the - /// method arguments, and the () values are the actual - /// argument values themselves. - ///

- ///

- /// If this property is not set, or the value passed to the setter invocation - /// is a reference, a method with no named arguments is assumed. - ///

- ///
- /// - public IDictionary NamedArguments - { - get { return _namedArguments; } - set - { - if (value != null) - { - this._namedArguments = value; - } - else - { - this._namedArguments.Clear(); - } - } - } - - #endregion - - #region Methods - - /// - /// Prepare the specified method. - /// - /// - ///

- /// The method can be invoked any number of times afterwards. - ///

- ///
- /// - /// If all required properties are not set, or a matching argument could not be found - /// for a named argument (typically down to a typo). - /// - /// - /// If the specified method could not be found. - /// - public virtual void Prepare() - { - if (_targetMethod == null) - { - throw new ArgumentException("The 'TargetMethod' property is required."); - } - if (_targetType == null && _targetObject == null) - { - throw new ArgumentException("One of either the 'TargetType' or 'TargetObject' properties is required."); - } - _methodObject = FindTheMethodToInvoke(); - if (TargetObject == null && !_methodObject.IsStatic) - { - throw new ArgumentException( - "The target method cannot be an instance method without a corresponding target instance on which to invoke it."); - } - PrepareArguments(); - } - - private void PrepareArguments() - { - _preparedArguments = new object[ArgumentCount]; - // ok, lets prepare any named arguments first... - if (NamedArguments.Count > 0) - { - // lets slot in all of the named arguments first... - ParameterInfo[] parameters = _methodObject.GetParameters(); - // lets figure out the index og each of the method parameters... - IDictionary argumentNamesToIndexes = new Dictionary(); - for (int i = 0; i < parameters.Length; ++i) - { - ParameterInfo parameter = parameters[i]; - argumentNamesToIndexes[parameter.Name.ToLower(CultureInfo.InvariantCulture)] = i; - } - int THE_ARGUMENT_IS_PREPARED = -12; - foreach (DictionaryEntry namedArgument in NamedArguments) - { - string argumentName = ((string) namedArgument.Key).ToLower(CultureInfo.InvariantCulture); - object argumentValue = namedArgument.Value; - if (!argumentNamesToIndexes.ContainsKey(argumentName)) - { - // whoa (Nelly); the named argument does not exist on the method... - throw new ArgumentException(string.Format( - CultureInfo.InvariantCulture, - "The named argument '{0}' could not be found on the '{1}' method of class [{2}].", - argumentName, _methodObject.Name, _methodObject.DeclaringType.FullName)); - - } - // look up the index of where in the prepared args array we're gonna stick the named argument value - int namedArgumentsIndex = argumentNamesToIndexes[argumentName]; - PreparedArguments[namedArgumentsIndex] = argumentValue; - // we've prepped this index position, so mark it as so... - argumentNamesToIndexes[argumentName] = THE_ARGUMENT_IS_PREPARED; - } - // and then fill in any remaining blanks with the plain vanilla arguments... - int plainVanillaIndex = 0; - int[] sortedIndexes = new List(argumentNamesToIndexes.Values).ToArray(); - Array.Sort(sortedIndexes); - foreach (int argumentIndex in sortedIndexes) - { - // have we previously prepped a named argument at this index position? - if (argumentIndex == THE_ARGUMENT_IS_PREPARED) - { - continue; - } - // lets stick a plain vanilla argument in at this index position (in the order that they have been supplied)... - PreparedArguments[argumentIndex] = Arguments[plainVanillaIndex++]; - } - } - else - { - PreparedArguments = Arguments; - } - } - - /// - /// Searches for and returns the method that is to be invoked. - /// - /// - /// The return value of this method call will subsequently be returned from the - /// . - /// - /// The method that is to be invoked. - /// - /// If no method could be found. - /// - /// - /// If more than one method was found. - /// - protected virtual MethodInfo FindTheMethodToInvoke() + /// + /// Arguments for the method invocation. + /// + /// + ///

+ /// Ordering is significant... the order of the arguments in this + /// property must match the ordering of the various parameters on the target + /// method. There does however exist a small possibility for confusion when + /// the arguments in this property are supplied in addition to one or more named + /// arguments. In this case, each named argument is slotted into the index position + /// corresponding to the named argument... once once all named arguments have been + /// resolved, the arguments in this property are slotted into any remaining (empty) + /// slots in the method parameter list (see the example in the overview of the + /// class if this is not clear). + ///

+ ///

+ /// If this property is not set, or the value passed to the setter invocation + /// is or a zero-length array, a method with no (un-named) arguments is assumed. + ///

+ ///
+ /// + public object[] Arguments + { + get { return _arguments; } + set { - MethodInfo theMethod = null; - Type targetType = (TargetObject != null) ? TargetObject.GetType() : TargetType; - GenericArgumentsHolder genericInfo = new GenericArgumentsHolder(TargetMethod); - - // if we don't have any named arguments, we can try to get the exact method first... - if (NamedArguments.Count == 0) - { - ComposedCriteria searchCriteria = new ComposedCriteria(); - searchCriteria.Add(new MethodNameMatchCriteria(genericInfo.GenericMethodName)); - searchCriteria.Add(new MethodParametersCountCriteria(ArgumentCount)); - searchCriteria.Add(new MethodGenericArgumentsCountCriteria(genericInfo.GetGenericArguments().Length)); - searchCriteria.Add(new MethodArgumentsCriteria(Arguments)); - - MemberInfo[] matchingMethods = targetType.FindMembers( - MemberTypes.Method, - MethodSearchingFlags, - new MemberFilter(new CriteriaMemberFilter().FilterMemberByCriteria), - searchCriteria); - - if (matchingMethods != null && matchingMethods.Length == 1) - { - theMethod = matchingMethods[0] as MethodInfo; - } - } - if (theMethod == null) + if (value != null) { - // search for a method with a matching signature... - ComposedCriteria searchCriteria = new ComposedCriteria(); - searchCriteria.Add(new MethodNameMatchCriteria(genericInfo.GenericMethodName)); - searchCriteria.Add(new MethodParametersCountCriteria(ArgumentCount)); - searchCriteria.Add(new MethodGenericArgumentsCountCriteria(genericInfo.GetGenericArguments().Length)); - - MemberInfo[] matchingMethods = targetType.FindMembers( - MemberTypes.Method, - MethodSearchingFlags, - new MemberFilter(new CriteriaMemberFilter().FilterMemberByCriteria), - searchCriteria); - - if (matchingMethods.Length == 0) - { - throw new MissingMethodException(targetType.Name, TargetMethod); - } - if (matchingMethods.Length > 1) - { - throw new ArgumentException(string.Format( - CultureInfo.InvariantCulture, - "Unable to determine which exact method to call; found '{0}' matches.", - matchingMethods.Length)); - } - theMethod = matchingMethods[0] as MethodInfo; + this._arguments = value; } - - if (genericInfo.ContainsGenericArguments) + else { - string[] unresolvedGenericArgs = genericInfo.GetGenericArguments(); - Type[] genericArgs = new Type[unresolvedGenericArgs.Length]; - for (int j = 0; j < unresolvedGenericArgs.Length; j++) - { - genericArgs[j] = TypeResolutionUtils.ResolveType(unresolvedGenericArgs[j]); - } - theMethod = theMethod.MakeGenericMethod(genericArgs); + this._arguments = new object[] { }; } + } + } - return theMethod; + /// + /// The resolved arguments for the method invocation. + /// + /// + /// + /// This property is not set until the target method has been resolved via a call to the + /// method). It is a combination of the + /// named and plain vanilla arguments properties, and it is this object array that + /// will actually be passed to the invocation of the target method. + /// + ///

+ /// Setting the value of this property to results in basically clearing out any + /// previously prepared arguments... another call to the + /// method will then be required to prepare the arguments again (or the prepared arguments + /// can be set explicitly if so desired). + ///

+ ///
+ /// + /// + protected object[] PreparedArguments + { + get { return _preparedArguments; } + set + { + if (value != null) + { + this._preparedArguments = value; + } + else + { + this._preparedArguments = new object[] { }; + } + } + } + + /// + /// Named arguments for the method invocation. + /// + /// + ///

+ /// The keys of this dictionary are the () names of the + /// method arguments, and the () values are the actual + /// argument values themselves. + ///

+ ///

+ /// If this property is not set, or the value passed to the setter invocation + /// is a reference, a method with no named arguments is assumed. + ///

+ ///
+ /// + public IDictionary NamedArguments + { + get { return _namedArguments; } + set + { + if (value != null) + { + this._namedArguments = value; + } + else + { + this._namedArguments.Clear(); + } + } + } + + #endregion + + #region Methods + + /// + /// Prepare the specified method. + /// + /// + ///

+ /// The method can be invoked any number of times afterwards. + ///

+ ///
+ /// + /// If all required properties are not set, or a matching argument could not be found + /// for a named argument (typically down to a typo). + /// + /// + /// If the specified method could not be found. + /// + public virtual void Prepare() + { + if (_targetMethod == null) + { + throw new ArgumentException("The 'TargetMethod' property is required."); } - /// - /// Adds the named argument to this instances mapping of argument names to argument values. - /// - /// - /// The name of an argument on the method that is to be invoked. - /// - /// - /// The value of the named argument on the method that is to be invoked. - /// - public void AddNamedArgument(string argumentName, object argument) - { - if (NamedArguments.Contains(argumentName)) - { - NamedArguments.Remove(argumentName); - } - NamedArguments.Add(argumentName, argument); - } + if (_targetType == null && _targetObject == null) + { + throw new ArgumentException("One of either the 'TargetType' or 'TargetObject' properties is required."); + } - private int ArgumentCount - { - get { return Arguments.Length + NamedArguments.Count; } - } + _methodObject = FindTheMethodToInvoke(); + if (TargetObject == null && !_methodObject.IsStatic) + { + throw new ArgumentException( + "The target method cannot be an instance method without a corresponding target instance on which to invoke it."); + } - /// - /// Returns the prepared object that - /// will be invoked. - /// - /// - ///

- /// A possible use case is to determine the return of the method. - ///

- ///
- /// - /// The prepared object that - /// will be invoked. - /// - public MethodInfo GetPreparedMethod() - { - return this._methodObject; - } + PrepareArguments(); + } - /// - /// Invoke the specified method. - /// - /// - ///

- /// The invoker needs to have been prepared beforehand (via a call to the - /// method). - ///

- ///
- /// - /// The object returned by the method invocation, or - /// if the method returns void. - /// - /// - /// If at least one of the arguments passed to this - /// was incompatible with the signature of the invoked method. - /// - public virtual object Invoke() - { - object result = null; - try - { - result = this._methodObject.Invoke(TargetObject, PreparedArguments); - } - catch (ArgumentException ex) - { - throw new MethodInvocationException( - string.Format(CultureInfo.InvariantCulture, - "At least one of the arguments passed to this {0} was " + - "incompatible with the signature of the invoked method.", GetType().Name), ex); - } - return (result == null ? Void : result); - } + private void PrepareArguments() + { + _preparedArguments = new object[ArgumentCount]; + // ok, lets prepare any named arguments first... + if (NamedArguments.Count > 0) + { + // lets slot in all of the named arguments first... + ParameterInfo[] parameters = _methodObject.GetParameters(); + // lets figure out the index og each of the method parameters... + IDictionary argumentNamesToIndexes = new Dictionary(); + for (int i = 0; i < parameters.Length; ++i) + { + ParameterInfo parameter = parameters[i]; + argumentNamesToIndexes[parameter.Name.ToLower(CultureInfo.InvariantCulture)] = i; + } - #endregion - } + int THE_ARGUMENT_IS_PREPARED = -12; + foreach (DictionaryEntry namedArgument in NamedArguments) + { + string argumentName = ((string) namedArgument.Key).ToLower(CultureInfo.InvariantCulture); + object argumentValue = namedArgument.Value; + if (!argumentNamesToIndexes.ContainsKey(argumentName)) + { + // whoa (Nelly); the named argument does not exist on the method... + throw new ArgumentException(string.Format( + CultureInfo.InvariantCulture, + "The named argument '{0}' could not be found on the '{1}' method of class [{2}].", + argumentName, _methodObject.Name, _methodObject.DeclaringType.FullName)); + } + + // look up the index of where in the prepared args array we're gonna stick the named argument value + int namedArgumentsIndex = argumentNamesToIndexes[argumentName]; + PreparedArguments[namedArgumentsIndex] = argumentValue; + // we've prepped this index position, so mark it as so... + argumentNamesToIndexes[argumentName] = THE_ARGUMENT_IS_PREPARED; + } + + // and then fill in any remaining blanks with the plain vanilla arguments... + int plainVanillaIndex = 0; + int[] sortedIndexes = new List(argumentNamesToIndexes.Values).ToArray(); + Array.Sort(sortedIndexes); + foreach (int argumentIndex in sortedIndexes) + { + // have we previously prepped a named argument at this index position? + if (argumentIndex == THE_ARGUMENT_IS_PREPARED) + { + continue; + } + + // lets stick a plain vanilla argument in at this index position (in the order that they have been supplied)... + PreparedArguments[argumentIndex] = Arguments[plainVanillaIndex++]; + } + } + else + { + PreparedArguments = Arguments; + } + } + + /// + /// Searches for and returns the method that is to be invoked. + /// + /// + /// The return value of this method call will subsequently be returned from the + /// . + /// + /// The method that is to be invoked. + /// + /// If no method could be found. + /// + /// + /// If more than one method was found. + /// + protected virtual MethodInfo FindTheMethodToInvoke() + { + MethodInfo theMethod = null; + Type targetType = (TargetObject != null) ? TargetObject.GetType() : TargetType; + GenericArgumentsHolder genericInfo = new GenericArgumentsHolder(TargetMethod); + + // if we don't have any named arguments, we can try to get the exact method first... + if (NamedArguments.Count == 0) + { + ComposedCriteria searchCriteria = new ComposedCriteria(); + searchCriteria.Add(new MethodNameMatchCriteria(genericInfo.GenericMethodName)); + searchCriteria.Add(new MethodParametersCountCriteria(ArgumentCount)); + searchCriteria.Add(new MethodGenericArgumentsCountCriteria(genericInfo.GetGenericArguments().Length)); + searchCriteria.Add(new MethodArgumentsCriteria(Arguments)); + + MemberInfo[] matchingMethods = targetType.FindMembers( + MemberTypes.Method, + MethodSearchingFlags, + new MemberFilter(new CriteriaMemberFilter().FilterMemberByCriteria), + searchCriteria); + + if (matchingMethods != null && matchingMethods.Length == 1) + { + theMethod = matchingMethods[0] as MethodInfo; + } + } + + if (theMethod == null) + { + // search for a method with a matching signature... + ComposedCriteria searchCriteria = new ComposedCriteria(); + searchCriteria.Add(new MethodNameMatchCriteria(genericInfo.GenericMethodName)); + searchCriteria.Add(new MethodParametersCountCriteria(ArgumentCount)); + searchCriteria.Add(new MethodGenericArgumentsCountCriteria(genericInfo.GetGenericArguments().Length)); + + MemberInfo[] matchingMethods = targetType.FindMembers( + MemberTypes.Method, + MethodSearchingFlags, + new MemberFilter(new CriteriaMemberFilter().FilterMemberByCriteria), + searchCriteria); + + if (matchingMethods.Length == 0) + { + throw new MissingMethodException(targetType.Name, TargetMethod); + } + + if (matchingMethods.Length > 1) + { + throw new ArgumentException(string.Format( + CultureInfo.InvariantCulture, + "Unable to determine which exact method to call; found '{0}' matches.", + matchingMethods.Length)); + } + + theMethod = matchingMethods[0] as MethodInfo; + } + + if (genericInfo.ContainsGenericArguments) + { + string[] unresolvedGenericArgs = genericInfo.GetGenericArguments(); + Type[] genericArgs = new Type[unresolvedGenericArgs.Length]; + for (int j = 0; j < unresolvedGenericArgs.Length; j++) + { + genericArgs[j] = TypeResolutionUtils.ResolveType(unresolvedGenericArgs[j]); + } + + theMethod = theMethod.MakeGenericMethod(genericArgs); + } + + return theMethod; + } + + /// + /// Adds the named argument to this instances mapping of argument names to argument values. + /// + /// + /// The name of an argument on the method that is to be invoked. + /// + /// + /// The value of the named argument on the method that is to be invoked. + /// + public void AddNamedArgument(string argumentName, object argument) + { + if (NamedArguments.Contains(argumentName)) + { + NamedArguments.Remove(argumentName); + } + + NamedArguments.Add(argumentName, argument); + } + + private int ArgumentCount + { + get { return Arguments.Length + NamedArguments.Count; } + } + + /// + /// Returns the prepared object that + /// will be invoked. + /// + /// + ///

+ /// A possible use case is to determine the return of the method. + ///

+ ///
+ /// + /// The prepared object that + /// will be invoked. + /// + public MethodInfo GetPreparedMethod() + { + return this._methodObject; + } + + /// + /// Invoke the specified method. + /// + /// + ///

+ /// The invoker needs to have been prepared beforehand (via a call to the + /// method). + ///

+ ///
+ /// + /// The object returned by the method invocation, or + /// if the method returns void. + /// + /// + /// If at least one of the arguments passed to this + /// was incompatible with the signature of the invoked method. + /// + public virtual object Invoke() + { + object result = null; + try + { + result = this._methodObject.Invoke(TargetObject, PreparedArguments); + } + catch (ArgumentException ex) + { + throw new MethodInvocationException( + string.Format(CultureInfo.InvariantCulture, + "At least one of the arguments passed to this {0} was " + + "incompatible with the signature of the invoked method.", GetType().Name), ex); + } + + return (result == null ? Void : result); + } + + #endregion } diff --git a/src/Spring/Spring.Core/Objects/Support/MutableSortDefinition.cs b/src/Spring/Spring.Core/Objects/Support/MutableSortDefinition.cs index 1ee9fb9f..5f3e1e64 100644 --- a/src/Spring/Spring.Core/Objects/Support/MutableSortDefinition.cs +++ b/src/Spring/Spring.Core/Objects/Support/MutableSortDefinition.cs @@ -20,193 +20,202 @@ using Spring.Util; -namespace Spring.Objects.Support +namespace Spring.Objects.Support; + +/// +/// Mutable implementation of the +/// interface that +/// supports toggling the ascending value on setting the same property again. +/// +/// Juergen Hoeller +/// Jean-Pierre Pawlak +/// Simon White (.NET) +[Serializable] +public class MutableSortDefinition : ISortDefinition { - /// - /// Mutable implementation of the - /// interface that - /// supports toggling the ascending value on setting the same property again. - /// - /// Juergen Hoeller - /// Jean-Pierre Pawlak - /// Simon White (.NET) - [Serializable] - public class MutableSortDefinition : ISortDefinition - { - private string _property = string.Empty; - private bool _ignoreCase = true; - private bool _ascending = true; - private bool _toggleAscendingOnProperty = false; + private string _property = string.Empty; + private bool _ignoreCase = true; + private bool _ascending = true; + private bool _toggleAscendingOnProperty = false; - #region Properties - private bool ToggleAscendingOnProperty - { - get - { - return _toggleAscendingOnProperty; - } - set - { - this._toggleAscendingOnProperty = value; - } - } - #endregion + #region Properties - #region ISortDefinition Properties - /// - /// The name of the property to sort by. - /// - public string Property - { - get - { - return _property; - } - set - { - if (!StringUtils.HasText (value)) - { - _property = string.Empty; - } - else - { - // implicit toggling of ascending? - if (ToggleAscendingOnProperty) - { - if (value.Equals(_property)) - { - _ascending = !_ascending; - } - } - _property = value; - } - } - } + private bool ToggleAscendingOnProperty + { + get + { + return _toggleAscendingOnProperty; + } + set + { + this._toggleAscendingOnProperty = value; + } + } - /// - /// Whether upper and lower case in string values should be ignored. - /// - /// - /// True if the sorting should be performed in a case-insensitive fashion. - /// - public bool IgnoreCase - { - get - { - return _ignoreCase; - } - } + #endregion - /// - /// If the sorting should be ascending or descending. - /// - /// - /// True if the sorting should be in the ascending order. - /// - public bool Ascending - { - get - { - return _ascending; - } - } - #endregion + #region ISortDefinition Properties - #region Constructors - /// - /// Creates a new instance of the - /// class. - /// - public MutableSortDefinition () - { - } + /// + /// The name of the property to sort by. + /// + public string Property + { + get + { + return _property; + } + set + { + if (!StringUtils.HasText(value)) + { + _property = string.Empty; + } + else + { + // implicit toggling of ascending? + if (ToggleAscendingOnProperty) + { + if (value.Equals(_property)) + { + _ascending = !_ascending; + } + } - /// - /// Creates a new instance of the - /// class using - /// the specified . - /// - /// - /// The to use - /// as a source for initial property values. - /// - public MutableSortDefinition (ISortDefinition source) - { - this._property = source.Property; - this._ignoreCase = source.IgnoreCase; - this._ascending = source.Ascending; - } + _property = value; + } + } + } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The name of the property to sort by. - /// - /// - /// Whether upper and lower case in string values should be ignored. - /// - /// - /// Whether or not the sorting should be ascending or descending. - /// - public MutableSortDefinition(string name, bool ignoreCase, bool ascending) - { - this._property = name; - this._ignoreCase = ignoreCase; - this._ascending = ascending; - } + /// + /// Whether upper and lower case in string values should be ignored. + /// + /// + /// True if the sorting should be performed in a case-insensitive fashion. + /// + public bool IgnoreCase + { + get + { + return _ignoreCase; + } + } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// Whether or not the - /// - /// property should be toggled if the same name is set on the - /// - /// property. - /// - public MutableSortDefinition (bool toggleAscendingOnSameProperty) - { - this.ToggleAscendingOnProperty = toggleAscendingOnSameProperty; - } - #endregion + /// + /// If the sorting should be ascending or descending. + /// + /// + /// True if the sorting should be in the ascending order. + /// + public bool Ascending + { + get + { + return _ascending; + } + } - #region Methods - /// - /// Overrides the default method - /// - /// - /// The object to test against this instance for equality. - /// - /// - /// True if the supplied is equal to this instance. - /// - public override bool Equals(object obj) - { - if (!(obj is ISortDefinition)) - { - return false; - } - ISortDefinition sd = (ISortDefinition) obj; - return (this.Property.Equals(sd.Property) && - this.Ascending == sd.Ascending && this.IgnoreCase == sd.IgnoreCase); - } + #endregion - /// - /// Overrides the default method. - /// - /// The hashcode for this instance. - public override int GetHashCode() - { - int result = 0; - result = this.Property.GetHashCode(); - result = 29 * result + (this.IgnoreCase ? 1 : 0); - result = 29 * result + (this.Ascending ? 1 : 0); - return result; - } - #endregion - } + #region Constructors + + /// + /// Creates a new instance of the + /// class. + /// + public MutableSortDefinition() + { + } + + /// + /// Creates a new instance of the + /// class using + /// the specified . + /// + /// + /// The to use + /// as a source for initial property values. + /// + public MutableSortDefinition(ISortDefinition source) + { + this._property = source.Property; + this._ignoreCase = source.IgnoreCase; + this._ascending = source.Ascending; + } + + /// + /// Creates a new instance of the + /// class. + /// + /// + /// The name of the property to sort by. + /// + /// + /// Whether upper and lower case in string values should be ignored. + /// + /// + /// Whether or not the sorting should be ascending or descending. + /// + public MutableSortDefinition(string name, bool ignoreCase, bool ascending) + { + this._property = name; + this._ignoreCase = ignoreCase; + this._ascending = ascending; + } + + /// + /// Creates a new instance of the + /// class. + /// + /// + /// Whether or not the + /// + /// property should be toggled if the same name is set on the + /// + /// property. + /// + public MutableSortDefinition(bool toggleAscendingOnSameProperty) + { + this.ToggleAscendingOnProperty = toggleAscendingOnSameProperty; + } + + #endregion + + #region Methods + + /// + /// Overrides the default method + /// + /// + /// The object to test against this instance for equality. + /// + /// + /// True if the supplied is equal to this instance. + /// + public override bool Equals(object obj) + { + if (!(obj is ISortDefinition)) + { + return false; + } + + ISortDefinition sd = (ISortDefinition) obj; + return (this.Property.Equals(sd.Property) && + this.Ascending == sd.Ascending && this.IgnoreCase == sd.IgnoreCase); + } + + /// + /// Overrides the default method. + /// + /// The hashcode for this instance. + public override int GetHashCode() + { + int result = 0; + result = this.Property.GetHashCode(); + result = 29 * result + (this.IgnoreCase ? 1 : 0); + result = 29 * result + (this.Ascending ? 1 : 0); + return result; + } + + #endregion } diff --git a/src/Spring/Spring.Core/Objects/Support/PropertyComparator.cs b/src/Spring/Spring.Core/Objects/Support/PropertyComparator.cs index c3bc15a9..65f542eb 100644 --- a/src/Spring/Spring.Core/Objects/Support/PropertyComparator.cs +++ b/src/Spring/Spring.Core/Objects/Support/PropertyComparator.cs @@ -1,20 +1,20 @@ #region License /* -* Copyright © 2002-2011 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. -*/ + * Copyright © 2002-2011 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 @@ -24,176 +24,179 @@ using Microsoft.Extensions.Logging; using Spring.Core; using Spring.Util; -namespace Spring.Objects.Support +namespace Spring.Objects.Support; + +/// +/// Performs a comparison of two objects, using the specified object property via +/// an . +/// +/// Juergen Hoeller +/// Jean-Pierre Pawlak +/// Simon White (.NET) +public class PropertyComparator : IComparer { + private static readonly ILogger logger = LogManager.GetLogger(); + + private ISortDefinition sortDefinition; + private readonly IDictionary cachedObjectWrappers = new Hashtable(); + /// - /// Performs a comparison of two objects, using the specified object property via - /// an . + /// Creates a new instance of the + /// class. /// - /// Juergen Hoeller - /// Jean-Pierre Pawlak - /// Simon White (.NET) - public class PropertyComparator : IComparer + /// + /// The to use for any + /// sorting. + /// + /// + /// If the supplied is . + /// + public PropertyComparator(ISortDefinition definition) { - private static readonly ILogger logger = LogManager.GetLogger(); + AssertUtils.ArgumentNotNull(definition, "definition"); + this.sortDefinition = definition; + } - private ISortDefinition sortDefinition; - private readonly IDictionary cachedObjectWrappers = new Hashtable(); + /// + /// Gets the to + /// use for any sorting. + /// + /// + /// The to use for + /// any sorting. + /// + public ISortDefinition SortDefinition + { + get { return this.sortDefinition; } + } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The to use for any - /// sorting. - /// - /// - /// If the supplied is . - /// - public PropertyComparator(ISortDefinition definition) + /// + /// Compares two objects and returns a value indicating whether one is less + /// than, equal to or greater than the other. + /// + /// The first object to compare. + /// The second object to compare. + /// + public virtual int Compare(object o1, object o2) + { + object v1 = GetPropertyValue(o1); + object v2 = GetPropertyValue(o2); + if (this.sortDefinition.IgnoreCase + && (v1 is string) + && (v2 is string)) { - AssertUtils.ArgumentNotNull(definition, "definition"); - this.sortDefinition = definition; + v1 = ((string) v1).ToLower(CultureInfo.CurrentCulture); + v2 = ((string) v2).ToLower(CultureInfo.CurrentCulture); } - /// - /// Gets the to - /// use for any sorting. - /// - /// - /// The to use for - /// any sorting. - /// - public ISortDefinition SortDefinition + int result = 0; + try { - get { return this.sortDefinition; } - } - - /// - /// Compares two objects and returns a value indicating whether one is less - /// than, equal to or greater than the other. - /// - /// The first object to compare. - /// The second object to compare. - /// - public virtual int Compare(object o1, object o2) - { - object v1 = GetPropertyValue(o1); - object v2 = GetPropertyValue(o2); - if (this.sortDefinition.IgnoreCase - && (v1 is string) - && (v2 is string)) + if (v1 != null) { - v1 = ((string) v1).ToLower(CultureInfo.CurrentCulture); - v2 = ((string) v2).ToLower(CultureInfo.CurrentCulture); - } - int result = 0; - try - { - if (v1 != null) + if (v2 != null) { - if (v2 != null) - { - result = ((IComparable) v1).CompareTo(v2); - } - else - { - result = -1; - } + result = ((IComparable) v1).CompareTo(v2); } else { - if (v2 != null) - { - result = 1; - } - else - { - result = 0; - } + result = -1; } } - catch (Exception ex) + else { - #region Instrumentation - - if (logger.IsEnabled(LogLevel.Warning)) + if (v2 != null) { - string message = "Could not sort objects [" + o1 + "] and [" + o2 + "]"; - logger.LogWarning(ex, message); + result = 1; + } + else + { + result = 0; } - - #endregion - - return 0; } - return (this.sortDefinition.Ascending ? result : -result); + } + catch (Exception ex) + { + #region Instrumentation + + if (logger.IsEnabled(LogLevel.Warning)) + { + string message = "Could not sort objects [" + o1 + "] and [" + o2 + "]"; + logger.LogWarning(ex, message); + } + + #endregion + + return 0; } - /// - /// Get the 's property - /// value for the given object. - /// - /// The object to get the property value for. - /// The property value. - private object GetPropertyValue(object obj) + return (this.sortDefinition.Ascending ? result : -result); + } + + /// + /// Get the 's property + /// value for the given object. + /// + /// The object to get the property value for. + /// The property value. + private object GetPropertyValue(object obj) + { + object propertyValue = null; + if (obj != null) { - object propertyValue = null; - if (obj != null) + IObjectWrapper ow = (IObjectWrapper) this.cachedObjectWrappers[obj]; + if (ow == null) { - IObjectWrapper ow = (IObjectWrapper) this.cachedObjectWrappers[obj]; - if (ow == null) + ow = new ObjectWrapper(obj); + this.cachedObjectWrappers.Add(obj, ow); + } + + try + { + propertyValue = ow.GetPropertyValue(this.sortDefinition.Property); + } + catch (InvalidPropertyException) + { + // the property doesn't exist in the first place, so let exception through... + throw; + } + catch (ObjectsException ex) + { + // if a nested property cannot be read, simply return null... + if (logger.IsEnabled(LogLevel.Debug)) { - ow = new ObjectWrapper(obj); - this.cachedObjectWrappers.Add(obj, ow); - } - try - { - propertyValue = ow.GetPropertyValue(this.sortDefinition.Property); - } - catch (InvalidPropertyException) - { - // the property doesn't exist in the first place, so let exception through... - throw; - } - catch (ObjectsException ex) - { - // if a nested property cannot be read, simply return null... - if (logger.IsEnabled(LogLevel.Debug)) - { - logger.LogDebug(ex, "Could not access property - treating as null for sorting."); - } + logger.LogDebug(ex, "Could not access property - treating as null for sorting."); } } - return propertyValue; } - /// - /// Sort the given according to the - /// given sort definition. - /// - /// - /// The to be sorted. - /// - /// The parameters to sort by. - /// - /// In the case of a missing property name. - /// - /// - /// If the supplied is . - /// - public static void Sort(IList source, ISortDefinition sortDefinition) - { + return propertyValue; + } + + /// + /// Sort the given according to the + /// given sort definition. + /// + /// + /// The to be sorted. + /// + /// The parameters to sort by. + /// + /// In the case of a missing property name. + /// + /// + /// If the supplied is . + /// + public static void Sort(IList source, ISortDefinition sortDefinition) + { // ArrayList.Adapter(source).Sort(new PropertyComparator(sortDefinition)); - ICollection coll = CollectionUtils.StableSort(source, new PropertyComparator(sortDefinition)); - int index = 0; - IEnumerator it = coll.GetEnumerator(); - while(it.MoveNext()) - { - source[index] = it.Current; - index++; - } + ICollection coll = CollectionUtils.StableSort(source, new PropertyComparator(sortDefinition)); + int index = 0; + IEnumerator it = coll.GetEnumerator(); + while (it.MoveNext()) + { + source[index] = it.Current; + index++; } } } diff --git a/src/Spring/Spring.Core/Objects/Support/StaticEventHandlerValue.cs b/src/Spring/Spring.Core/Objects/Support/StaticEventHandlerValue.cs index dd8198cc..4a8f0936 100644 --- a/src/Spring/Spring.Core/Objects/Support/StaticEventHandlerValue.cs +++ b/src/Spring/Spring.Core/Objects/Support/StaticEventHandlerValue.cs @@ -21,72 +21,80 @@ using System.Globalization; using System.Reflection; -namespace Spring.Objects.Support +namespace Spring.Objects.Support; + +/// +/// Describes an event handler for a static class method. +/// +/// Rick Evans +public class StaticEventHandlerValue : AbstractWiringEventHandlerValue { - /// - /// Describes an event handler for a static class method. + #region Constants + + private static readonly BindingFlags StaticMethodFlags = + BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | + BindingFlags.IgnoreCase; + + #endregion + + #region Constructor (s) / Destructor + + /// + /// Creates a new instance of the + /// class. /// - /// Rick Evans - public class StaticEventHandlerValue : AbstractWiringEventHandlerValue + public StaticEventHandlerValue() { - #region Constants - private static readonly BindingFlags StaticMethodFlags = - BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | - BindingFlags.IgnoreCase; - #endregion + } - #region Constructor (s) / Destructor - /// - /// Creates a new instance of the - /// class. - /// - public StaticEventHandlerValue () + /// + /// Creates a new instance of the + /// class. + /// + /// + /// The object (possibly unresolved) that is exposing the event. + /// + /// + /// The name of the method on the handler that is going to handle the event. + /// + public StaticEventHandlerValue(object source, string methodName) + : base(source, methodName) + { + } + + #endregion + + #region Methods + + /// + /// Gets the event handler. + /// + /// + /// The instance that is registering for the event notification. + /// + /// + /// Event metadata about the event. + /// + /// + /// The event handler. + /// + protected override Delegate GetHandler(object instance, EventInfo info) + { + Type type = instance as Type; + if (type == null) { + throw new FatalObjectException(string.Format( + CultureInfo.InvariantCulture, + "Only 'System.Type' instances can be wired by instances of " + + "the StaticEventHandlerValue class; got '{0}'", instance)); } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The object (possibly unresolved) that is exposing the event. - /// - /// - /// The name of the method on the handler that is going to handle the event. - /// - public StaticEventHandlerValue (object source, string methodName) - : base (source, methodName) {} - #endregion + MethodInfo method = ResolveHandlerMethod( + type, + info.EventHandlerType, + StaticEventHandlerValue.StaticMethodFlags); + return Delegate.CreateDelegate(info.EventHandlerType, method); + } - #region Methods - /// - /// Gets the event handler. - /// - /// - /// The instance that is registering for the event notification. - /// - /// - /// Event metadata about the event. - /// - /// - /// The event handler. - /// - protected override Delegate GetHandler(object instance, EventInfo info) - { - Type type = instance as Type; - if (type == null) - { - throw new FatalObjectException (string.Format ( - CultureInfo.InvariantCulture, - "Only 'System.Type' instances can be wired by instances of " + - "the StaticEventHandlerValue class; got '{0}'", instance)); - } - MethodInfo method = ResolveHandlerMethod ( - type, - info.EventHandlerType, - StaticEventHandlerValue.StaticMethodFlags); - return Delegate.CreateDelegate (info.EventHandlerType, method); - } - #endregion - } + #endregion } diff --git a/src/Spring/Spring.Core/Pool/IObjectPool.cs b/src/Spring/Spring.Core/Pool/IObjectPool.cs index d1834fb2..b34fb7e6 100644 --- a/src/Spring/Spring.Core/Pool/IObjectPool.cs +++ b/src/Spring/Spring.Core/Pool/IObjectPool.cs @@ -1,147 +1,146 @@ #region License /* -* Copyright � 2002-2011 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. -*/ + * Copyright � 2002-2011 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 -namespace Spring.Pool +namespace Spring.Pool; + +/// +/// A simple pooling interface for managing and monitoring a pool +/// of objects. +/// +/// +///

+/// Based on the Jakarta Commons Pool API. +///

+///
+/// Federico Spinazzi +/// +public interface IObjectPool { - /// - /// A simple pooling interface for managing and monitoring a pool - /// of objects. - /// - /// - ///

- /// Based on the Jakarta Commons Pool API. - ///

- ///
- /// Federico Spinazzi - /// - public interface IObjectPool - { - /// - /// Obtain an instance from the pool. - /// - /// - ///

- /// By contract, clients must return the borrowed - /// instance using - /// or a related method as defined in an implementation or - /// sub-interface. - ///

- ///
- /// An instance from the pool. - /// - /// In case the pool is unusable. - /// - /// - object BorrowObject(); + /// + /// Obtain an instance from the pool. + /// + /// + ///

+ /// By contract, clients must return the borrowed + /// instance using + /// or a related method as defined in an implementation or + /// sub-interface. + ///

+ ///
+ /// An instance from the pool. + /// + /// In case the pool is unusable. + /// + /// + object BorrowObject(); - /// - /// Return an instance to the pool. - /// - /// - ///

- /// By contract, the object must have been obtained using - /// - /// or a related method as defined in an implementation or sub-interface. - ///

- ///
- /// The instance to be returned to the pool. - /// - void ReturnObject(object target); + /// + /// Return an instance to the pool. + /// + /// + ///

+ /// By contract, the object must have been obtained using + /// + /// or a related method as defined in an implementation or sub-interface. + ///

+ ///
+ /// The instance to be returned to the pool. + /// + void ReturnObject(object target); - /// - /// Create an object using the factory set by - /// the property - /// or other implementation dependent mechanism - /// and place it into the pool. - /// - /// - ///

- /// This is an optional operation. AddObject is useful for "pre-loading" a - /// pool with idle objects. - ///

- ///
- /// - /// If the implementation does not support the operation. - /// - void AddObject(); + /// + /// Create an object using the factory set by + /// the property + /// or other implementation dependent mechanism + /// and place it into the pool. + /// + /// + ///

+ /// This is an optional operation. AddObject is useful for "pre-loading" a + /// pool with idle objects. + ///

+ ///
+ /// + /// If the implementation does not support the operation. + /// + void AddObject(); - /// - /// Close the pool and free any resources associated with it. - /// - void Close(); + /// + /// Close the pool and free any resources associated with it. + /// + void Close(); - /// - /// Clear objects sitting idle in the pool, releasing any - /// associated resources. - /// - /// - ///

- /// This is an optional operation. - ///

- ///
- /// - /// If the implementation does not support the operation. - /// - void Clear(); + /// + /// Clear objects sitting idle in the pool, releasing any + /// associated resources. + /// + /// + ///

+ /// This is an optional operation. + ///

+ ///
+ /// + /// If the implementation does not support the operation. + /// + void Clear(); - /// - /// Gets the number of instances currently borrowed from the pool. - /// - /// - ///

- /// This is an optional operation. - ///

- ///
- /// - /// If the implementation does not support the operation. - /// - int NumActive { get; } + /// + /// Gets the number of instances currently borrowed from the pool. + /// + /// + ///

+ /// This is an optional operation. + ///

+ ///
+ /// + /// If the implementation does not support the operation. + /// + int NumActive { get; } - /// - /// Gets the number of instances currently idle in the pool. - /// - /// - ///

- /// This is an optional operation. - ///

- ///

- /// This may be considered an approximation of the number of objects - /// that can be borrowed without creating any new instances. - ///

- ///
- /// - /// If the implementation does not support the operation. - /// - int NumIdle { get; } + /// + /// Gets the number of instances currently idle in the pool. + /// + /// + ///

+ /// This is an optional operation. + ///

+ ///

+ /// This may be considered an approximation of the number of objects + /// that can be borrowed without creating any new instances. + ///

+ ///
+ /// + /// If the implementation does not support the operation. + /// + int NumIdle { get; } - /// - /// Set the factory used to create new instances. - /// - /// - ///

- /// This is an optional operation. - ///

- ///
- /// - /// If the implementation does not support the operation. - /// - IPoolableObjectFactory PoolableObjectFactory { set; } - } + /// + /// Set the factory used to create new instances. + /// + /// + ///

+ /// This is an optional operation. + ///

+ ///
+ /// + /// If the implementation does not support the operation. + /// + IPoolableObjectFactory PoolableObjectFactory { set; } } diff --git a/src/Spring/Spring.Core/Pool/IPoolableObjectFactory.cs b/src/Spring/Spring.Core/Pool/IPoolableObjectFactory.cs index 5237a4a2..ebf77806 100644 --- a/src/Spring/Spring.Core/Pool/IPoolableObjectFactory.cs +++ b/src/Spring/Spring.Core/Pool/IPoolableObjectFactory.cs @@ -1,124 +1,123 @@ #region License /* -* Copyright © 2002-2011 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. -*/ + * Copyright � 2002-2011 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 -namespace Spring.Pool +namespace Spring.Pool; + +/// +/// Defines lifecycle methods for objects that are to be used in an +/// implementation. +/// +/// +///

+/// The following methods summarize the contract between an +/// and an +/// an . +///

+/// +/// +/// +/// is called whenever a new instance is needed. +/// +/// +/// +/// is invoked on every instance before it is returned from +/// the pool. +/// +/// +/// +/// is invoked on every instance when it is returned to the pool. +/// +/// +/// +/// is invoked on every instance when it is being dropped from the +/// pool (see +/// +/// +/// +///

+/// Based on the Jakarta Commons Pool API. +///

+///
+/// Federico Spinazzi +/// +public interface IPoolableObjectFactory { - /// - /// Defines lifecycle methods for objects that are to be used in an - /// implementation. - /// - /// - ///

- /// The following methods summarize the contract between an - /// and an - /// an . - ///

- /// - /// - /// - /// is called whenever a new instance is needed. - /// - /// - /// - /// is invoked on every instance before it is returned from - /// the pool. - /// - /// - /// - /// is invoked on every instance when it is returned to the pool. - /// - /// - /// - /// is invoked on every instance when it is being dropped from the - /// pool (see - /// - /// - /// - ///

- /// Based on the Jakarta Commons Pool API. - ///

- ///
- /// Federico Spinazzi - /// - public interface IPoolableObjectFactory - { - /// - /// Creates an instance that can be returned by the pool. - /// - /// - /// An instance that can be returned by the pool. - /// - object MakeObject(); + /// + /// Creates an instance that can be returned by the pool. + /// + /// + /// An instance that can be returned by the pool. + /// + object MakeObject(); - /// - /// Destroys an instance no longer needed by the pool. - /// - /// - ///

- /// Invoked on every instance when it is being "dropped" - /// from the pool (whether due to the return value from a call to the - /// - /// method, or for reasons specific to the pool implementation.) - ///

- ///
- /// The instance to be destroyed. - void DestroyObject(object obj); + /// + /// Destroys an instance no longer needed by the pool. + /// + /// + ///

+ /// Invoked on every instance when it is being "dropped" + /// from the pool (whether due to the return value from a call to the + /// + /// method, or for reasons specific to the pool implementation.) + ///

+ ///
+ /// The instance to be destroyed. + void DestroyObject(object obj); - /// - /// Ensures that the instance is safe to be returned by the pool. - /// Returns false if this object should be destroyed. - /// - /// - ///

- /// Invoked in an implementation-specific fashion to determine if an - /// instance is still valid to be returned by the pool. - /// It will only be invoked on an "activated" instance. - ///

- ///
- /// The instance to validate. - /// - /// if this object is not valid and - /// should be dropped from the pool, otherwise . - /// - bool ValidateObject(object obj); + /// + /// Ensures that the instance is safe to be returned by the pool. + /// Returns false if this object should be destroyed. + /// + /// + ///

+ /// Invoked in an implementation-specific fashion to determine if an + /// instance is still valid to be returned by the pool. + /// It will only be invoked on an "activated" instance. + ///

+ ///
+ /// The instance to validate. + /// + /// if this object is not valid and + /// should be dropped from the pool, otherwise . + /// + bool ValidateObject(object obj); - /// - /// Reinitialize an instance to be returned by the pool. - /// - /// - ///

- /// Invoked on every instance before it is returned from the pool. - ///

- ///
- /// The instance to be activated. - void ActivateObject(object obj); + /// + /// Reinitialize an instance to be returned by the pool. + /// + /// + ///

+ /// Invoked on every instance before it is returned from the pool. + ///

+ ///
+ /// The instance to be activated. + void ActivateObject(object obj); - /// - /// Uninitialize an instance to be returned to the pool. - /// - /// - ///

- /// Invoked on every instance when it is returned to the pool. - ///

- ///
- /// The instance returned to the pool. - void PassivateObject(object obj); - } -} \ No newline at end of file + /// + /// Uninitialize an instance to be returned to the pool. + /// + /// + ///

+ /// Invoked on every instance when it is returned to the pool. + ///

+ ///
+ /// The instance returned to the pool. + void PassivateObject(object obj); +} diff --git a/src/Spring/Spring.Core/Pool/PoolException.cs b/src/Spring/Spring.Core/Pool/PoolException.cs index f2cf3ccb..b85a4c9c 100644 --- a/src/Spring/Spring.Core/Pool/PoolException.cs +++ b/src/Spring/Spring.Core/Pool/PoolException.cs @@ -1,79 +1,80 @@ #region License + /* -* Copyright � 2002-2011 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. -*/ + * Copyright � 2002-2011 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.Runtime.Serialization; -namespace Spring.Pool +namespace Spring.Pool; + +/// +/// Base class for all pooling exceptions. +/// +/// Federico Spinazzi +[Serializable] +public class PoolException : Exception { /// - /// Base class for all pooling exceptions. + /// Creates a new instance of the + /// class. /// - /// Federico Spinazzi - [Serializable] - public class PoolException : Exception + public PoolException() { - /// - /// Creates a new instance of the - /// class. - /// - public PoolException () - { - } + } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - public PoolException (string message) : base (message) - { - } + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + public PoolException(string message) : base(message) + { + } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception that is being wrapped. - /// - public PoolException (string message, Exception innerException) : base (message, innerException) - { - } + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception that is being wrapped. + /// + public PoolException(string message, Exception innerException) : base(message, innerException) + { + } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The - /// that holds the serialized object data about the exception being thrown. - /// - /// - /// The - /// that contains contextual information about the source or destination. - /// - protected PoolException (SerializationInfo info, StreamingContext context) : base (info, context) - { - } + /// + /// Creates a new instance of the + /// class. + /// + /// + /// The + /// that holds the serialized object data about the exception being thrown. + /// + /// + /// The + /// that contains contextual information about the source or destination. + /// + protected PoolException(SerializationInfo info, StreamingContext context) : base(info, context) + { } } diff --git a/src/Spring/Spring.Core/Pool/Support/SimplePool.cs b/src/Spring/Spring.Core/Pool/Support/SimplePool.cs index 9d09ade6..29707ed5 100644 --- a/src/Spring/Spring.Core/Pool/Support/SimplePool.cs +++ b/src/Spring/Spring.Core/Pool/Support/SimplePool.cs @@ -1,20 +1,20 @@ #region License /* -* Copyright � 2002-2011 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. -*/ + * Copyright � 2002-2011 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 @@ -26,290 +26,294 @@ using Spring.Threading; #endregion -namespace Spring.Pool.Support +namespace Spring.Pool.Support; + +/// +/// A simple pool implementation +/// +/// +///

+/// Based on the implementation found in Concurrent Programming in Java, +/// 2nd ed., by Doug Lea. +///

+///
+/// Doug Lea +/// Federico Spinazzi +/// Mark Pollack +/// Zbynek Vyskovsky, kvr@centrum.cz +public class SimplePool : IObjectPool { - /// - /// A simple pool implementation - /// - /// - ///

- /// Based on the implementation found in Concurrent Programming in Java, - /// 2nd ed., by Doug Lea. - ///

- ///
- /// Doug Lea - /// Federico Spinazzi - /// Mark Pollack - /// Zbynek Vyskovsky, kvr@centrum.cz - public class SimplePool : IObjectPool - { - private readonly IPoolableObjectFactory factory; - private bool closed; - private IList free = new ArrayList(); - private IList busy = new ArrayList(); // linear search !! + private readonly IPoolableObjectFactory factory; + private bool closed; + private IList free = new ArrayList(); + private IList busy = new ArrayList(); // linear search !! - /// - /// Set of permits - /// - internal readonly Semaphore available; + /// + /// Set of permits + /// + internal readonly Semaphore available; - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The factory used to instantiate and manage the lifecycle of pooled objects. - /// - /// The initial size of the pool. - /// - /// If the supplied is . - /// - /// - /// If the supplied is less than or equal to zero. - /// - public SimplePool(IPoolableObjectFactory factory, int initialSize) - : this(factory, initialSize, initialSize) - { - } + /// + /// Creates a new instance of the + /// class. + /// + /// + /// The factory used to instantiate and manage the lifecycle of pooled objects. + /// + /// The initial size of the pool. + /// + /// If the supplied is . + /// + /// + /// If the supplied is less than or equal to zero. + /// + public SimplePool(IPoolableObjectFactory factory, int initialSize) + : this(factory, initialSize, initialSize) + { + } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The factory used to instantiate and manage the lifecycle of pooled objects. - /// - /// The maximum size of the pool. - /// The initial size of the pool. - /// - /// If the supplied is . - /// - /// - /// If the supplied is less than or equal to zero. - /// - public SimplePool(IPoolableObjectFactory factory, int maxSize, int initialSize) - { - AssertUtils.ArgumentNotNull(factory, "factory"); - this.available = new Semaphore(maxSize); - this.factory = factory; - InitItems(initialSize); - } + /// + /// Creates a new instance of the + /// class. + /// + /// + /// The factory used to instantiate and manage the lifecycle of pooled objects. + /// + /// The maximum size of the pool. + /// The initial size of the pool. + /// + /// If the supplied is . + /// + /// + /// If the supplied is less than or equal to zero. + /// + public SimplePool(IPoolableObjectFactory factory, int maxSize, int initialSize) + { + AssertUtils.ArgumentNotNull(factory, "factory"); + this.available = new Semaphore(maxSize); + this.factory = factory; + InitItems(initialSize); + } - /// - /// Obtain an instance from the pool. - /// - /// - /// In case the pool is unusable. - /// - /// - /// - public object BorrowObject() - { - available.Acquire(); - return DoBorrow(); - } + /// + /// Obtain an instance from the pool. + /// + /// + /// In case the pool is unusable. + /// + /// + /// + public object BorrowObject() + { + available.Acquire(); + return DoBorrow(); + } - /// - /// Return an instance to the pool. - /// - /// The instance to be returned to the pool. - /// - /// - public void ReturnObject(object target) - { - if (DoReturn(target)) - { - available.Release(); - } - } + /// + /// Return an instance to the pool. + /// + /// The instance to be returned to the pool. + /// + /// + public void ReturnObject(object target) + { + if (DoReturn(target)) + { + available.Release(); + } + } - /// - /// Create an object using the factory set by - /// the property - /// or other implementation dependent mechanism - /// and place it into the pool. - /// - /// - ///

- /// This implementation always throws a - /// . - ///

- ///
- /// - /// If the implementation does not support the operation. - /// - public void AddObject() - { - throw new NotSupportedException(); - } + /// + /// Create an object using the factory set by + /// the property + /// or other implementation dependent mechanism + /// and place it into the pool. + /// + /// + ///

+ /// This implementation always throws a + /// . + ///

+ ///
+ /// + /// If the implementation does not support the operation. + /// + public void AddObject() + { + throw new NotSupportedException(); + } - /// - /// Synchronized borrow logic. - /// - /// - protected object DoBorrow() - { - lock (this) - { - while (free.Count > 0) - { - int i = free.Count - 1; - object o = free[i]; - free.RemoveAt(i); - factory.ActivateObject(o); - if (factory.ValidateObject(o)) - { - busy.Add(o); - return o; - } - } - if (!closed) - { - object o = factory.MakeObject(); - busy.Add(o); - return o; - } - else - { - throw new PoolException("Pool was closed and is unusable."); - } - } - } + /// + /// Synchronized borrow logic. + /// + /// + protected object DoBorrow() + { + lock (this) + { + while (free.Count > 0) + { + int i = free.Count - 1; + object o = free[i]; + free.RemoveAt(i); + factory.ActivateObject(o); + if (factory.ValidateObject(o)) + { + busy.Add(o); + return o; + } + } - /// - /// Synchronized release logic. - /// - /// - /// The object to release to the pool. - /// - /// - /// if the object was not a busy one. - /// - protected bool DoReturn(object target) - { - lock (this) - { - if (busy.Contains(target)) - { - busy.Remove(target); - factory.PassivateObject(target); - free.Add(target); - return true; - } - return false; - } - } + if (!closed) + { + object o = factory.MakeObject(); + busy.Add(o); + return o; + } + else + { + throw new PoolException("Pool was closed and is unusable."); + } + } + } - /// - /// Instantiates the supplied number of instances and adds - /// them to the pool. - /// - /// - /// The initial number of objects to build. - /// - /// - /// If the supplied number of is - /// less than or equal to zero. - /// - protected void InitItems(int initialInstances) - { - if(initialInstances <= 0) - { - throw new ArgumentException("Cannot pool a negative number of instances.", "initialInstances"); - } - for (int i = 0; i < initialInstances; ++i) - { - free.Add(factory.MakeObject()); - } - } + /// + /// Synchronized release logic. + /// + /// + /// The object to release to the pool. + /// + /// + /// if the object was not a busy one. + /// + protected bool DoReturn(object target) + { + lock (this) + { + if (busy.Contains(target)) + { + busy.Remove(target); + factory.PassivateObject(target); + free.Add(target); + return true; + } - /// - /// Close the pool and free any resources associated with it. - /// - public void Close() - { - lock (this) - { - for (IEnumerator e = busy.GetEnumerator(); - e.MoveNext(); - e = busy.GetEnumerator()) - { - ReturnObject(e.Current); - } - foreach (object o in free) - { - factory.DestroyObject(o); - } - MakeNotUsable(); - } - } + return false; + } + } - /// - /// Clear objects sitting idle in the pool, releasing any - /// associated resources. - /// - /// - ///

- /// This implementation always throws a - /// . - ///

- ///
- /// - /// If the implementation does not support the operation. - /// - public void Clear() - { - throw new NotSupportedException(); - } + /// + /// Instantiates the supplied number of instances and adds + /// them to the pool. + /// + /// + /// The initial number of objects to build. + /// + /// + /// If the supplied number of is + /// less than or equal to zero. + /// + protected void InitItems(int initialInstances) + { + if (initialInstances <= 0) + { + throw new ArgumentException("Cannot pool a negative number of instances.", "initialInstances"); + } - /// - /// Change the state of the pool to unusable. - /// - private void MakeNotUsable() - { - free = busy = new ArrayList(); - closed = true; - } + for (int i = 0; i < initialInstances; ++i) + { + free.Add(factory.MakeObject()); + } + } - /// - /// Gets the number of instances currently borrowed from the pool. - /// - /// - /// If the implementation does not support the operation. - /// - /// - public int NumActive - { - get { return this.busy.Count; } - } + /// + /// Close the pool and free any resources associated with it. + /// + public void Close() + { + lock (this) + { + for (IEnumerator e = busy.GetEnumerator(); + e.MoveNext(); + e = busy.GetEnumerator()) + { + ReturnObject(e.Current); + } - /// - /// Gets the number of instances currently idle in the pool. - /// - /// - /// If the implementation does not support the operation. - /// - /// - public int NumIdle - { - get { return this.free.Count; } - } + foreach (object o in free) + { + factory.DestroyObject(o); + } - /// - /// Set the factory used to create new instances. - /// - /// - ///

- /// This implementation always throws a - /// . - ///

- ///
- /// - /// If the implementation does not support the operation. - /// - public IPoolableObjectFactory PoolableObjectFactory - { - set { throw new NotSupportedException(); } - } - } + MakeNotUsable(); + } + } + + /// + /// Clear objects sitting idle in the pool, releasing any + /// associated resources. + /// + /// + ///

+ /// This implementation always throws a + /// . + ///

+ ///
+ /// + /// If the implementation does not support the operation. + /// + public void Clear() + { + throw new NotSupportedException(); + } + + /// + /// Change the state of the pool to unusable. + /// + private void MakeNotUsable() + { + free = busy = new ArrayList(); + closed = true; + } + + /// + /// Gets the number of instances currently borrowed from the pool. + /// + /// + /// If the implementation does not support the operation. + /// + /// + public int NumActive + { + get { return this.busy.Count; } + } + + /// + /// Gets the number of instances currently idle in the pool. + /// + /// + /// If the implementation does not support the operation. + /// + /// + public int NumIdle + { + get { return this.free.Count; } + } + + /// + /// Set the factory used to create new instances. + /// + /// + ///

+ /// This implementation always throws a + /// . + ///

+ ///
+ /// + /// If the implementation does not support the operation. + /// + public IPoolableObjectFactory PoolableObjectFactory + { + set { throw new NotSupportedException(); } + } } diff --git a/src/Spring/Spring.Core/Proxy/AbstractProxyMethodBuilder.cs b/src/Spring/Spring.Core/Proxy/AbstractProxyMethodBuilder.cs index 79531545..0fa59745 100644 --- a/src/Spring/Spring.Core/Proxy/AbstractProxyMethodBuilder.cs +++ b/src/Spring/Spring.Core/Proxy/AbstractProxyMethodBuilder.cs @@ -22,376 +22,375 @@ using System.Reflection; using System.Reflection.Emit; - using Spring.Util; #endregion -namespace Spring.Proxy +namespace Spring.Proxy; + +/// +/// Base class for method builders that contains common functionalities. +/// +/// Bruno Baia +public abstract class AbstractProxyMethodBuilder : IProxyMethodBuilder { + #region Fields + /// - /// Base class for method builders that contains common functionalities. + /// The type builder to use. /// - /// Bruno Baia - public abstract class AbstractProxyMethodBuilder : IProxyMethodBuilder + protected TypeBuilder typeBuilder; + + /// + /// The implementation to use. + /// + protected IProxyTypeGenerator proxyGenerator; + + /// + /// Indicates whether interfaces should be implemented explicitly. + /// + protected bool explicitImplementation; + + #endregion + + #region Constructor(s) / Destructor + + /// + /// Creates a new instance of the method builder. + /// + /// The type builder to use. + /// + /// The implementation to use. + /// + /// + /// if the interface is to be + /// implemented explicitly; otherwise . + /// + public AbstractProxyMethodBuilder(TypeBuilder typeBuilder, + IProxyTypeGenerator proxyGenerator, bool explicitImplementation) { - #region Fields + this.typeBuilder = typeBuilder; + this.proxyGenerator = proxyGenerator; + this.explicitImplementation = explicitImplementation; + } - /// - /// The type builder to use. - /// - protected TypeBuilder typeBuilder; + #endregion - /// - /// The implementation to use. - /// - protected IProxyTypeGenerator proxyGenerator; + #region IProxyMethodBuilder Members - /// - /// Indicates whether interfaces should be implemented explicitly. - /// - protected bool explicitImplementation; + /// + /// Dynamically builds proxy method. + /// + /// The method to proxy. + /// + /// The interface definition of the method, if applicable. + /// + /// + /// The for the proxy method. + /// + public virtual MethodBuilder BuildProxyMethod(MethodInfo method, MethodInfo interfaceMethod) + { + MethodBuilder methodBuilder = + DefineMethod(method, interfaceMethod, explicitImplementation); - #endregion + ILGenerator il = methodBuilder.GetILGenerator(); - #region Constructor(s) / Destructor + GenerateMethod(il, method, interfaceMethod); - /// - /// Creates a new instance of the method builder. - /// - /// The type builder to use. - /// - /// The implementation to use. - /// - /// - /// if the interface is to be - /// implemented explicitly; otherwise . - /// - public AbstractProxyMethodBuilder(TypeBuilder typeBuilder, - IProxyTypeGenerator proxyGenerator, bool explicitImplementation) + il.Emit(OpCodes.Ret); + + if (explicitImplementation || + (interfaceMethod != null && interfaceMethod.Name != method.Name)) { - this.typeBuilder = typeBuilder; - this.proxyGenerator = proxyGenerator; - this.explicitImplementation = explicitImplementation; + typeBuilder.DefineMethodOverride(methodBuilder, interfaceMethod); } - #endregion + return methodBuilder; + } - #region IProxyMethodBuilder Members + #endregion - /// - /// Dynamically builds proxy method. - /// - /// The method to proxy. - /// - /// The interface definition of the method, if applicable. - /// - /// - /// The for the proxy method. - /// - public virtual MethodBuilder BuildProxyMethod(MethodInfo method, MethodInfo interfaceMethod) + #region Protected Methods + + /// + /// Generates the IL instructions that pushes + /// the proxy instance on stack. + /// + /// The IL generator to use. + protected virtual void PushProxy(ILGenerator il) + { + proxyGenerator.PushProxy(il); + } + + /// + /// Generates the IL instructions that pushes + /// the target instance on which calls should be delegated to. + /// + /// The IL generator to use. + protected virtual void PushTarget(ILGenerator il) + { + proxyGenerator.PushTarget(il); + } + + /// + /// Defines proxy method for the target object. + /// + /// The method to proxy. + /// + /// The interface definition of the method, if applicable. + /// + /// + /// if the supplied is to be + /// implemented explicitly; otherwise . + /// + /// + /// The for the proxy method. + /// + protected virtual MethodBuilder DefineMethod( + MethodInfo method, MethodInfo intfMethod, bool explicitImplementation) + { + MethodBuilder methodBuilder; + string name; + MethodAttributes attributes; + + if (intfMethod == null) { - MethodBuilder methodBuilder = - DefineMethod(method, interfaceMethod, explicitImplementation); + name = method.Name; + attributes = MethodAttributes.Public | MethodAttributes.ReuseSlot + | MethodAttributes.HideBySig | MethodAttributes.Virtual; + } + else + { + attributes = MethodAttributes.HideBySig + | MethodAttributes.NewSlot | MethodAttributes.Virtual + | MethodAttributes.Final; - ILGenerator il = methodBuilder.GetILGenerator(); - - GenerateMethod(il, method, interfaceMethod); - - il.Emit(OpCodes.Ret); - - if (explicitImplementation || - (interfaceMethod != null && interfaceMethod.Name != method.Name)) + if (explicitImplementation || method.Name.IndexOf('.') != -1) { - typeBuilder.DefineMethodOverride(methodBuilder, interfaceMethod); - } - - return methodBuilder; - } - - #endregion - - #region Protected Methods - - /// - /// Generates the IL instructions that pushes - /// the proxy instance on stack. - /// - /// The IL generator to use. - protected virtual void PushProxy(ILGenerator il) - { - proxyGenerator.PushProxy(il); - } - - /// - /// Generates the IL instructions that pushes - /// the target instance on which calls should be delegated to. - /// - /// The IL generator to use. - protected virtual void PushTarget(ILGenerator il) - { - proxyGenerator.PushTarget(il); - } - - /// - /// Defines proxy method for the target object. - /// - /// The method to proxy. - /// - /// The interface definition of the method, if applicable. - /// - /// - /// if the supplied is to be - /// implemented explicitly; otherwise . - /// - /// - /// The for the proxy method. - /// - protected virtual MethodBuilder DefineMethod( - MethodInfo method, MethodInfo intfMethod, bool explicitImplementation) - { - MethodBuilder methodBuilder; - string name; - MethodAttributes attributes; - - if (intfMethod == null) - { - name = method.Name; - attributes = MethodAttributes.Public | MethodAttributes.ReuseSlot - | MethodAttributes.HideBySig | MethodAttributes.Virtual; + name = String.Format("{0}.{1}", + intfMethod.DeclaringType.FullName, intfMethod.Name); + attributes |= MethodAttributes.Private; } else { - attributes = MethodAttributes.HideBySig - | MethodAttributes.NewSlot | MethodAttributes.Virtual - | MethodAttributes.Final; - - if (explicitImplementation || method.Name.IndexOf('.') != -1) - { - name = String.Format("{0}.{1}", - intfMethod.DeclaringType.FullName, intfMethod.Name); - attributes |= MethodAttributes.Private; - } - else - { - name = intfMethod.Name; - attributes |= MethodAttributes.Public; - } - } - - if ((intfMethod != null && intfMethod.IsSpecialName) || method.IsSpecialName) - { - attributes |= MethodAttributes.SpecialName; - } - - methodBuilder = typeBuilder.DefineMethod(name, attributes, - method.CallingConvention, method.ReturnType, - ReflectionUtils.GetParameterTypes(method.GetParameters())); - - DefineGenericParameters(methodBuilder, method); - //DefineParameters(methodBuilder, method); - - return methodBuilder; - } - - /* - /// - /// Defines method parameters based on proxied method metadata. - /// - /// - /// The to use. - /// - /// The method to proxy. - protected void DefineParameters(MethodBuilder methodBuilder, MethodInfo method) - { - int n = 1; - foreach (ParameterInfo param in method.GetParameters()) - { - ParameterBuilder pb = methodBuilder.DefineParameter(n, param.Attributes, param.Name); - n++; - } - } - */ - - /// - /// Defines generic method parameters based on proxied method metadata. - /// - /// - /// The to use. - /// - /// The method to proxy. - protected void DefineGenericParameters(MethodBuilder methodBuilder, MethodInfo method) - { - if (method.IsGenericMethodDefinition) - { - Type[] genericArguments = method.GetGenericArguments(); - - // define generic parameters - GenericTypeParameterBuilder[] gtpBuilders = - methodBuilder.DefineGenericParameters(ReflectionUtils.GetGenericParameterNames(genericArguments)); - - // define constraints for each generic parameter - for (int i = 0; i < genericArguments.Length; i++) - { - gtpBuilders[i].SetGenericParameterAttributes(genericArguments[i].GenericParameterAttributes); - - Type[] constraints = genericArguments[i].GetGenericParameterConstraints(); - System.Collections.Generic.List interfaces = new System.Collections.Generic.List(constraints.Length); - foreach (Type constraint in constraints) - { - if (constraint.IsClass) - gtpBuilders[i].SetBaseTypeConstraint(constraint); - else - interfaces.Add(constraint); - } - gtpBuilders[i].SetInterfaceConstraints(interfaces.ToArray()); - } + name = intfMethod.Name; + attributes |= MethodAttributes.Public; } } - /// - /// Generates the proxy method. - /// - /// The IL generator to use. - /// The method to proxy. - /// - /// The interface definition of the method, if applicable. - /// - protected abstract void GenerateMethod( - ILGenerator il, MethodInfo method, MethodInfo interfaceMethod); - - /// - /// Calls target method directly. - /// - /// The IL generator to use. - /// The method to invoke. - protected virtual void CallDirectTargetMethod( - ILGenerator il, MethodInfo targetMethod) + if ((intfMethod != null && intfMethod.IsSpecialName) || method.IsSpecialName) { - // TODO (EE): check for null and interface type and throw NotSupportedException - // setup target instance for CallAssertUnderstands - PushTarget(il); - CallAssertUnderstands(il, targetMethod, "target"); - - // setup target and cast to type method is on - PushTarget(il); - il.Emit(OpCodes.Castclass, targetMethod.DeclaringType); - - // setup parameters for call - ParameterInfo[] paramArray = targetMethod.GetParameters(); - for (int i = 0; i < paramArray.Length; i++) - { - il.Emit(OpCodes.Ldarg_S, i + 1); - } - - // call method - il.EmitCall(OpCodes.Callvirt, targetMethod, null); + attributes |= MethodAttributes.SpecialName; } - /// - /// Emits code to ensure that target on stack understands the method and throw a sensible exception otherwise. - /// - /// The IL generator to use. - /// The method to test for - /// the name of the target to be used in error messages - protected virtual void CallAssertUnderstands(ILGenerator il, MethodInfo method, string targetName) - { - il.Emit(OpCodes.Ldstr, targetName); - il.Emit(OpCodes.Ldtoken, method.DeclaringType); - il.Emit(OpCodes.Call, References.GetTypeFromHandleMethod); - //il.Emit(OpCodes.Ldstr, string.Format("Interface method '{0}.{1}()' was not handled by any interceptor and the target does not implement this method.", method.DeclaringType.FullName, method.Name)); - il.Emit(OpCodes.Call, References.UnderstandsMethod); - } + methodBuilder = typeBuilder.DefineMethod(name, attributes, + method.CallingConvention, method.ReturnType, + ReflectionUtils.GetParameterTypes(method.GetParameters())); - /// - /// Calls base method directly. - /// - /// The IL generator to use. - /// The method to proxy. - protected virtual void CallDirectBaseMethod(ILGenerator il, MethodInfo method) - { - // TODO (EE): check for null and interface type and throw NotSupportedException - // setup proxy instance for CallAssertUnderstands - PushProxy(il); - CallAssertUnderstands(il, method, "base"); + DefineGenericParameters(methodBuilder, method); + //DefineParameters(methodBuilder, method); - // setup proxy and cast to type method is on - PushProxy(il); - il.Emit(OpCodes.Castclass, method.DeclaringType); - - // setup parameters for call - ParameterInfo[] paramArray = method.GetParameters(); - for (int i = 0; i < paramArray.Length; i++) - { - il.Emit(OpCodes.Ldarg_S, i + 1); - } - - // call method - il.EmitCall(OpCodes.Call, method, null); - } - - /// - /// Replaces a raw reference with a reference to a proxy. - /// - /// - ///

- /// If the target object returns reference to itself -- 'this' -- - /// we need to treat it as a special case and return a reference - /// to a proxy object instead. - ///

- ///
- /// The IL generator to use. - /// The location of the return value. - protected virtual void ProcessReturnValue(ILGenerator il, LocalBuilder returnValue) - { - Label jmpMethodReturn = il.DefineLabel(); - - // check if target method returned 'this', reference to target - PushTarget(il); - il.Emit(OpCodes.Ldloc, returnValue); - il.Emit(OpCodes.Bne_Un_S, jmpMethodReturn); - - // check if proxy can be casted to the return type - PushProxy(il); - il.Emit(OpCodes.Isinst, returnValue.LocalType); - il.Emit(OpCodes.Brfalse_S, jmpMethodReturn); - - // if it did, return reference to this proxy instead - PushProxy(il); - il.Emit(OpCodes.Stloc, returnValue); - - il.MarkLabel(jmpMethodReturn); - } - - /// - /// Generates code that throws . - /// - /// IL generator to use. - /// the type of the exception to throw - /// Error message to use. - protected static void EmitThrowException(ILGenerator il, Type exceptionType, string message) - { - ConstructorInfo NewException = exceptionType.GetConstructor(new Type[] { typeof(string) }); - - il.Emit(OpCodes.Ldstr, message); - il.Emit(OpCodes.Newobj, NewException); - il.Emit(OpCodes.Throw); - } - - #endregion + return methodBuilder; } - #region References helper class definition - - internal struct References + /* + /// + /// Defines method parameters based on proxied method metadata. + /// + /// + /// The to use. + /// + /// The method to proxy. + protected void DefineParameters(MethodBuilder methodBuilder, MethodInfo method) { - // methods - public static readonly MethodInfo GetTypeFromHandleMethod = - typeof(Type).GetMethod("GetTypeFromHandle", new Type[] { typeof(RuntimeTypeHandle) }); + int n = 1; + foreach (ParameterInfo param in method.GetParameters()) + { + ParameterBuilder pb = methodBuilder.DefineParameter(n, param.Attributes, param.Name); + n++; + } + } + */ - public static readonly MethodInfo UnderstandsMethod = - typeof(AssertUtils).GetMethod("Understands", new Type[] { typeof(object), typeof(string), typeof(Type) }); + /// + /// Defines generic method parameters based on proxied method metadata. + /// + /// + /// The to use. + /// + /// The method to proxy. + protected void DefineGenericParameters(MethodBuilder methodBuilder, MethodInfo method) + { + if (method.IsGenericMethodDefinition) + { + Type[] genericArguments = method.GetGenericArguments(); + + // define generic parameters + GenericTypeParameterBuilder[] gtpBuilders = + methodBuilder.DefineGenericParameters(ReflectionUtils.GetGenericParameterNames(genericArguments)); + + // define constraints for each generic parameter + for (int i = 0; i < genericArguments.Length; i++) + { + gtpBuilders[i].SetGenericParameterAttributes(genericArguments[i].GenericParameterAttributes); + + Type[] constraints = genericArguments[i].GetGenericParameterConstraints(); + System.Collections.Generic.List interfaces = new System.Collections.Generic.List(constraints.Length); + foreach (Type constraint in constraints) + { + if (constraint.IsClass) + gtpBuilders[i].SetBaseTypeConstraint(constraint); + else + interfaces.Add(constraint); + } + + gtpBuilders[i].SetInterfaceConstraints(interfaces.ToArray()); + } + } + } + + /// + /// Generates the proxy method. + /// + /// The IL generator to use. + /// The method to proxy. + /// + /// The interface definition of the method, if applicable. + /// + protected abstract void GenerateMethod( + ILGenerator il, MethodInfo method, MethodInfo interfaceMethod); + + /// + /// Calls target method directly. + /// + /// The IL generator to use. + /// The method to invoke. + protected virtual void CallDirectTargetMethod( + ILGenerator il, MethodInfo targetMethod) + { + // TODO (EE): check for null and interface type and throw NotSupportedException + // setup target instance for CallAssertUnderstands + PushTarget(il); + CallAssertUnderstands(il, targetMethod, "target"); + + // setup target and cast to type method is on + PushTarget(il); + il.Emit(OpCodes.Castclass, targetMethod.DeclaringType); + + // setup parameters for call + ParameterInfo[] paramArray = targetMethod.GetParameters(); + for (int i = 0; i < paramArray.Length; i++) + { + il.Emit(OpCodes.Ldarg_S, i + 1); + } + + // call method + il.EmitCall(OpCodes.Callvirt, targetMethod, null); + } + + /// + /// Emits code to ensure that target on stack understands the method and throw a sensible exception otherwise. + /// + /// The IL generator to use. + /// The method to test for + /// the name of the target to be used in error messages + protected virtual void CallAssertUnderstands(ILGenerator il, MethodInfo method, string targetName) + { + il.Emit(OpCodes.Ldstr, targetName); + il.Emit(OpCodes.Ldtoken, method.DeclaringType); + il.Emit(OpCodes.Call, References.GetTypeFromHandleMethod); + //il.Emit(OpCodes.Ldstr, string.Format("Interface method '{0}.{1}()' was not handled by any interceptor and the target does not implement this method.", method.DeclaringType.FullName, method.Name)); + il.Emit(OpCodes.Call, References.UnderstandsMethod); + } + + /// + /// Calls base method directly. + /// + /// The IL generator to use. + /// The method to proxy. + protected virtual void CallDirectBaseMethod(ILGenerator il, MethodInfo method) + { + // TODO (EE): check for null and interface type and throw NotSupportedException + // setup proxy instance for CallAssertUnderstands + PushProxy(il); + CallAssertUnderstands(il, method, "base"); + + // setup proxy and cast to type method is on + PushProxy(il); + il.Emit(OpCodes.Castclass, method.DeclaringType); + + // setup parameters for call + ParameterInfo[] paramArray = method.GetParameters(); + for (int i = 0; i < paramArray.Length; i++) + { + il.Emit(OpCodes.Ldarg_S, i + 1); + } + + // call method + il.EmitCall(OpCodes.Call, method, null); + } + + /// + /// Replaces a raw reference with a reference to a proxy. + /// + /// + ///

+ /// If the target object returns reference to itself -- 'this' -- + /// we need to treat it as a special case and return a reference + /// to a proxy object instead. + ///

+ ///
+ /// The IL generator to use. + /// The location of the return value. + protected virtual void ProcessReturnValue(ILGenerator il, LocalBuilder returnValue) + { + Label jmpMethodReturn = il.DefineLabel(); + + // check if target method returned 'this', reference to target + PushTarget(il); + il.Emit(OpCodes.Ldloc, returnValue); + il.Emit(OpCodes.Bne_Un_S, jmpMethodReturn); + + // check if proxy can be casted to the return type + PushProxy(il); + il.Emit(OpCodes.Isinst, returnValue.LocalType); + il.Emit(OpCodes.Brfalse_S, jmpMethodReturn); + + // if it did, return reference to this proxy instead + PushProxy(il); + il.Emit(OpCodes.Stloc, returnValue); + + il.MarkLabel(jmpMethodReturn); + } + + /// + /// Generates code that throws . + /// + /// IL generator to use. + /// the type of the exception to throw + /// Error message to use. + protected static void EmitThrowException(ILGenerator il, Type exceptionType, string message) + { + ConstructorInfo NewException = exceptionType.GetConstructor(new Type[] { typeof(string) }); + + il.Emit(OpCodes.Ldstr, message); + il.Emit(OpCodes.Newobj, NewException); + il.Emit(OpCodes.Throw); } #endregion } + +#region References helper class definition + +internal struct References +{ + // methods + public static readonly MethodInfo GetTypeFromHandleMethod = + typeof(Type).GetMethod("GetTypeFromHandle", new Type[] { typeof(RuntimeTypeHandle) }); + + public static readonly MethodInfo UnderstandsMethod = + typeof(AssertUtils).GetMethod("Understands", new Type[] { typeof(object), typeof(string), typeof(Type) }); +} + +#endregion diff --git a/src/Spring/Spring.Core/Proxy/AbstractProxyTypeBuilder.cs b/src/Spring/Spring.Core/Proxy/AbstractProxyTypeBuilder.cs index bc9c4698..737b3b00 100644 --- a/src/Spring/Spring.Core/Proxy/AbstractProxyTypeBuilder.cs +++ b/src/Spring/Spring.Core/Proxy/AbstractProxyTypeBuilder.cs @@ -30,904 +30,911 @@ using Spring.Util; #endregion -namespace Spring.Proxy +namespace Spring.Proxy; + +/// +/// Base class for proxy builders that can be used +/// to create a proxy for any class. +/// +/// +///

+/// This class provides a set of template +/// methods that derived classes can override to provide custom behaviour +/// appropriate to the type of proxy that is being generated (one of +/// inheritance or composition-based proxying). +///

+///
+/// Aleksandar Seovic +/// Bruno Baia +public abstract class AbstractProxyTypeBuilder : IProxyTypeBuilder, IProxyTypeGenerator { - /// - /// Base class for proxy builders that can be used - /// to create a proxy for any class. - /// - /// - ///

- /// This class provides a set of template - /// methods that derived classes can override to provide custom behaviour - /// appropriate to the type of proxy that is being generated (one of - /// inheritance or composition-based proxying). - ///

- ///
- /// Aleksandar Seovic - /// Bruno Baia - public abstract class AbstractProxyTypeBuilder : IProxyTypeBuilder, IProxyTypeGenerator - { - #region Fields + #region Fields - /// - /// The shared instance for this class (and derived classes). - /// - protected static readonly ILogger log = LogManager.GetLogger(); + /// + /// The shared instance for this class (and derived classes). + /// + protected static readonly ILogger log = LogManager.GetLogger(); - private const string DEFAULT_PROXY_TYPE_NAME = "Proxy"; + private const string DEFAULT_PROXY_TYPE_NAME = "Proxy"; - private string _name; - private Type _targetType; - private Type _baseType = typeof (object); - private IList _interfaces; - private bool _proxyTargetAttributes = true; - private IList _typeAttributes = new ArrayList(); - private IDictionary _memberAttributes = new Hashtable(); + private string _name; + private Type _targetType; + private Type _baseType = typeof(object); + private IList _interfaces; + private bool _proxyTargetAttributes = true; + private IList _typeAttributes = new ArrayList(); + private IDictionary _memberAttributes = new Hashtable(); - #endregion + #endregion - #region IProxyTypeBuilder Members + #region IProxyTypeBuilder Members - /// - /// Creates the proxy type. - /// - /// The generated proxy class. - public abstract Type BuildProxyType(); + /// + /// Creates the proxy type. + /// + /// The generated proxy class. + public abstract Type BuildProxyType(); - /// - /// The name of the proxy . - /// - /// The name of the proxy . - public string Name + /// + /// The name of the proxy . + /// + /// The name of the proxy . + public string Name + { + get { - get + if (StringUtils.IsNullOrEmpty(_name)) { - if (StringUtils.IsNullOrEmpty(_name)) - { - _name = DEFAULT_PROXY_TYPE_NAME; - } - return _name; - } - set { _name = value; } - } - - /// - /// The of the target object. - /// - public Type TargetType - { - get { return _targetType; } - set { _targetType = value; } - } - - /// - /// The of the class that the proxy must - /// inherit from. - /// - /// - ///

- /// The default value of this property is the - /// . - ///

- ///
- public Type BaseType - { - get { return _baseType; } - set { _baseType = value; } - } - - /// - /// Gets or sets the list of interfaces proxy should implement. - /// - /// - /// The default value of this property is all the interfaces - /// implemented or inherited by the target type. - /// - public IList Interfaces - { - get - { - if (_interfaces == null) - { - _interfaces = GetProxiableInterfaces(TargetType.GetInterfaces()); - } - return _interfaces; - } - set { _interfaces = value; } - } - - /// - /// Should we proxy target attributes? - /// - /// - public bool ProxyTargetAttributes - { - get { return _proxyTargetAttributes; } - set { _proxyTargetAttributes = value; } - } - - /// - /// The list of custom s that the proxy - /// class must be decorated with. - /// - /// - public IList TypeAttributes - { - get { return _typeAttributes; } - set { _typeAttributes = value; } - } - - /// - /// The custom s that the proxy - /// members must be decorated with. - /// - /// - public IDictionary MemberAttributes - { - get { return _memberAttributes; } - set { _memberAttributes = value; } - } - - #endregion - - #region IProxyTypeGenerator Members - - /// - /// Generates the IL instructions that pushes - /// the proxy instance on stack. - /// - /// The IL generator to use. - public virtual void PushProxy(ILGenerator il) - { - il.Emit(OpCodes.Ldarg_0); - } - - /// - /// Generates the IL instructions that pushes - /// the target instance on which calls should be delegated to. - /// - /// The IL generator to use. - public abstract void PushTarget(ILGenerator il); - - #endregion - - #region Protected Methods - - #region Type generation - - /// - /// Creates an appropriate type builder. - /// - /// The name to use for the proxy type name. - /// The type to extends if provided. - /// The type builder to use. - protected virtual TypeBuilder CreateTypeBuilder(string name, Type baseType) - { - // Generates unique type name - string typeName = String.Format("{0}_{1}", - name, Guid.NewGuid().ToString("N")); - - return DynamicProxyManager.CreateTypeBuilder(typeName, baseType); - } - - #endregion - - #region Attributes generation - - /// - /// Applies attributes to the proxy class. - /// - /// The type builder to use. - /// The proxied class. - /// - /// - protected virtual void ApplyTypeAttributes(TypeBuilder typeBuilder, Type targetType) - { - foreach (object attr in GetTypeAttributes(targetType)) - { - if (attr is CustomAttributeBuilder) - { - typeBuilder.SetCustomAttribute((CustomAttributeBuilder)attr); - } - else if (attr is CustomAttributeData) - { - typeBuilder.SetCustomAttribute( - ReflectionUtils.CreateCustomAttribute((CustomAttributeData)attr)); - } - else if (attr is Attribute) - { - typeBuilder.SetCustomAttribute(ReflectionUtils.CreateCustomAttribute((Attribute)attr)); - } - } - } - - /// - /// Applies attributes to the proxied method. - /// - /// The method builder to use. - /// The proxied method. - /// - /// - protected virtual void ApplyMethodAttributes(MethodBuilder methodBuilder, MethodInfo targetMethod) - { - foreach (object attr in GetMethodAttributes(targetMethod)) - { - if (attr is CustomAttributeBuilder) - { - methodBuilder.SetCustomAttribute((CustomAttributeBuilder)attr); - } - else if (attr is CustomAttributeData) - { - methodBuilder.SetCustomAttribute( - ReflectionUtils.CreateCustomAttribute((CustomAttributeData)attr)); - } - else if (attr is Attribute) - { - methodBuilder.SetCustomAttribute( - ReflectionUtils.CreateCustomAttribute((Attribute)attr)); - } + _name = DEFAULT_PROXY_TYPE_NAME; } - ApplyMethodReturnTypeAttributes(methodBuilder, targetMethod); - ApplyMethodParameterAttributes(methodBuilder, targetMethod); + return _name; } + set { _name = value; } + } - /// - /// Applies attributes to the proxied method's return type. - /// - /// The method builder to use. - /// The proxied method. - /// - protected virtual void ApplyMethodReturnTypeAttributes(MethodBuilder methodBuilder, MethodInfo targetMethod) + /// + /// The of the target object. + /// + public Type TargetType + { + get { return _targetType; } + set { _targetType = value; } + } + + /// + /// The of the class that the proxy must + /// inherit from. + /// + /// + ///

+ /// The default value of this property is the + /// . + ///

+ ///
+ public Type BaseType + { + get { return _baseType; } + set { _baseType = value; } + } + + /// + /// Gets or sets the list of interfaces proxy should implement. + /// + /// + /// The default value of this property is all the interfaces + /// implemented or inherited by the target type. + /// + public IList Interfaces + { + get { - ParameterBuilder parameterBuilder = methodBuilder.DefineParameter(0, ParameterAttributes.Retval, null); - foreach (object attr in GetMethodReturnTypeAttributes(targetMethod)) + if (_interfaces == null) { - if (attr is CustomAttributeBuilder) - { - parameterBuilder.SetCustomAttribute((CustomAttributeBuilder)attr); - } - else if (attr is CustomAttributeData) - { - parameterBuilder.SetCustomAttribute( - ReflectionUtils.CreateCustomAttribute((CustomAttributeData)attr)); - } - else if (attr is Attribute) - { - parameterBuilder.SetCustomAttribute( - ReflectionUtils.CreateCustomAttribute((Attribute)attr)); - } - } - } - - /// - /// Applies attributes to proxied method's parameters. - /// - /// The method builder to use. - /// The proxied method. - /// - protected virtual void ApplyMethodParameterAttributes(MethodBuilder methodBuilder, MethodInfo targetMethod) - { - foreach (ParameterInfo paramInfo in targetMethod.GetParameters()) - { - ParameterBuilder parameterBuilder = methodBuilder.DefineParameter( - (paramInfo.Position + 1), paramInfo.Attributes, paramInfo.Name); - foreach (object attr in GetMethodParameterAttributes(targetMethod, paramInfo)) - { - if (attr is CustomAttributeBuilder) - { - parameterBuilder.SetCustomAttribute((CustomAttributeBuilder)attr); - } - else if (attr is CustomAttributeData) - { - parameterBuilder.SetCustomAttribute( - ReflectionUtils.CreateCustomAttribute((CustomAttributeData)attr)); - } - else if (attr is Attribute) - { - parameterBuilder.SetCustomAttribute( - ReflectionUtils.CreateCustomAttribute((Attribute)attr)); - } - } - } - } - - /// - /// Calculates and returns the list of attributes that apply to the - /// specified type. - /// - /// The type to find attributes for. - /// - /// A list of custom attributes that should be applied to type. - /// - /// - /// - protected virtual IList GetTypeAttributes(Type type) - { - ArrayList attributes = new ArrayList(); - - if (this.ProxyTargetAttributes && !type.Equals(typeof(object))) - { - // add attributes that apply to the target type - attributes.AddRange(ReflectionUtils.GetCustomAttributes(type)); + _interfaces = GetProxiableInterfaces(TargetType.GetInterfaces()); } - // add attributes defined by configuration - attributes.AddRange(TypeAttributes); - - return attributes; + return _interfaces; } + set { _interfaces = value; } + } - /// - /// Calculates and returns the list of attributes that apply to the - /// specified method. - /// - /// The method to find attributes for. - /// - /// A list of custom attributes that should be applied to method. - /// - /// - /// - protected virtual IList GetMethodAttributes(MethodInfo method) + /// + /// Should we proxy target attributes? + /// + /// + public bool ProxyTargetAttributes + { + get { return _proxyTargetAttributes; } + set { _proxyTargetAttributes = value; } + } + + /// + /// The list of custom s that the proxy + /// class must be decorated with. + /// + /// + public IList TypeAttributes + { + get { return _typeAttributes; } + set { _typeAttributes = value; } + } + + /// + /// The custom s that the proxy + /// members must be decorated with. + /// + /// + public IDictionary MemberAttributes + { + get { return _memberAttributes; } + set { _memberAttributes = value; } + } + + #endregion + + #region IProxyTypeGenerator Members + + /// + /// Generates the IL instructions that pushes + /// the proxy instance on stack. + /// + /// The IL generator to use. + public virtual void PushProxy(ILGenerator il) + { + il.Emit(OpCodes.Ldarg_0); + } + + /// + /// Generates the IL instructions that pushes + /// the target instance on which calls should be delegated to. + /// + /// The IL generator to use. + public abstract void PushTarget(ILGenerator il); + + #endregion + + #region Protected Methods + + #region Type generation + + /// + /// Creates an appropriate type builder. + /// + /// The name to use for the proxy type name. + /// The type to extends if provided. + /// The type builder to use. + protected virtual TypeBuilder CreateTypeBuilder(string name, Type baseType) + { + // Generates unique type name + string typeName = String.Format("{0}_{1}", + name, Guid.NewGuid().ToString("N")); + + return DynamicProxyManager.CreateTypeBuilder(typeName, baseType); + } + + #endregion + + #region Attributes generation + + /// + /// Applies attributes to the proxy class. + /// + /// The type builder to use. + /// The proxied class. + /// + /// + protected virtual void ApplyTypeAttributes(TypeBuilder typeBuilder, Type targetType) + { + foreach (object attr in GetTypeAttributes(targetType)) { - ArrayList attributes = new ArrayList(); - - if (this.ProxyTargetAttributes && - !method.DeclaringType.IsInterface) + if (attr is CustomAttributeBuilder) { - // add attributes that apply to the target method - attributes.AddRange(ReflectionUtils.GetCustomAttributes(method)); - } - - // add attributes defined by configuration - foreach (DictionaryEntry entry in MemberAttributes) - { - if (TypeResolutionUtils.MethodMatch((string)entry.Key, method)) - { - if (entry.Value is Attribute) - { - attributes.Add(entry.Value); - } - else if (entry.Value is IList) - { - attributes.AddRange(entry.Value as IList); - } - } - } - - return attributes; - } - - /// - /// Calculates and returns the list of attributes that apply to the - /// specified method's return type. - /// - /// The method to find attributes for. - /// - /// A list of custom attributes that should be applied to method's return type. - /// - /// - protected virtual IList GetMethodReturnTypeAttributes(MethodInfo method) - { - ArrayList attributes = new ArrayList(); - - if (this.ProxyTargetAttributes && - !method.DeclaringType.IsInterface) - { - // add attributes that apply to the target method' return type - object[] attrs = method.ReturnTypeCustomAttributes.GetCustomAttributes(false); - try - { - System.Collections.Generic.IList attrsData = - CustomAttributeData.GetCustomAttributes(method.ReturnParameter); - - if (attrs.Length != attrsData.Count) - { - // http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=94803 - attributes.AddRange(attrs); - } - else - { - foreach (CustomAttributeData cad in attrsData) - { - attributes.Add(cad); - } - } - } - catch (ArgumentException) - { - // http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=296032 - attributes.AddRange(attrs); - } - } - - // TODO: add attributes defined by configuration - - return attributes; - } - - /// - /// Calculates and returns the list of attributes that apply to the - /// specified method's parameters. - /// - /// The method to find attributes for. - /// The method's parameter to find attributes for. - /// - /// A list of custom attributes that should be applied to the specified method's parameter. - /// - /// - protected virtual IList GetMethodParameterAttributes(MethodInfo method, ParameterInfo paramInfo) - { - ArrayList attributes = new ArrayList(); - - if (this.ProxyTargetAttributes && - !method.DeclaringType.IsInterface) - { - // add attributes that apply to the target method's parameter - object[] attrs = paramInfo.GetCustomAttributes(false); - try - { - IList attrsData = CustomAttributeData.GetCustomAttributes(paramInfo); - - if (attrs.Length != attrsData.Count) - { - // http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=94803 - attributes.AddRange(attrs); - } - else - { - foreach (CustomAttributeData cad in attrsData) - { - attributes.Add(cad); - } - } - } - catch (ArgumentException) - { - // http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=296032 - attributes.AddRange(attrs); - } - } - - // TODO: add attributes defined by configuration - - return attributes; - } - - /// - /// Check that the specified object is matching the passed attribute type. - /// - /// - ///

- /// The specified object can be of different type : - ///

- /// - /// - /// - /// - /// - /// System.Reflection.CustomAttributeData (Only with .NET 2.0) - /// - /// - /// - /// - /// - ///
- /// The object instance to check. - /// The attribute type to test against. - /// - /// if the object instance matches the attribute type; - /// otherwise . - /// - protected virtual bool IsAttributeMatchingType(object attr, Type attrType) - { - if (attr is Attribute) - { - return (attrType == attr.GetType()); + typeBuilder.SetCustomAttribute((CustomAttributeBuilder) attr); } else if (attr is CustomAttributeData) { - return (attrType == ((CustomAttributeData)attr).Constructor.DeclaringType); + typeBuilder.SetCustomAttribute( + ReflectionUtils.CreateCustomAttribute((CustomAttributeData) attr)); } - else if (attr is CustomAttributeBuilder) + else if (attr is Attribute) { - return (attrType == ((ConstructorInfo)CustomAttributeConstructorField.GetValue(attr)).DeclaringType); - } - return false; - } - - private static readonly FieldInfo CustomAttributeConstructorField = - typeof(CustomAttributeBuilder).GetField("m_con", BindingFlags.Instance | BindingFlags.NonPublic); - - #endregion - - #region Constructors generation - - /// - /// Defines the types of the parameters for the specified constructor. - /// - /// The constructor to use. - /// The types for constructor's parameters. - protected virtual Type[] DefineConstructorParameters(ConstructorInfo constructor) - { - return ReflectionUtils.GetParameterTypes(constructor.GetParameters()); - } - - /// - /// Implements constructors for the proxy class. - /// - /// - /// The builder to use. - /// - protected virtual void ImplementConstructors(TypeBuilder typeBuilder) - { - ConstructorInfo[] constructors = TargetType.GetConstructors( - BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); - - foreach (ConstructorInfo constructor in constructors) - { - if (constructor.IsPublic || constructor.IsFamily) - { - ConstructorBuilder cb = typeBuilder.DefineConstructor( - constructor.Attributes, - constructor.CallingConvention, - DefineConstructorParameters(constructor)); - - ILGenerator il = cb.GetILGenerator(); - GenerateConstructor(cb, il, constructor); - il.Emit(OpCodes.Ret); - } + typeBuilder.SetCustomAttribute(ReflectionUtils.CreateCustomAttribute((Attribute) attr)); } } - - /// - /// Generates the proxy constructor. - /// - /// The constructor builder to use. - /// The IL generator to use. - /// The constructor to use. - protected virtual void GenerateConstructor( - ConstructorBuilder builder, ILGenerator il, ConstructorInfo constructor) - { - } - - #endregion - - #region Members generation - - /// - /// Implements an interface. - /// - /// - /// Generates proxy methods that belongs to the interface - /// using the specified . - /// - /// The type builder to use. - /// - /// The implementation to use - /// - /// The interface to implement. - /// - /// The of the target object. - /// - protected virtual void ImplementInterface(TypeBuilder typeBuilder, - IProxyMethodBuilder proxyMethodBuilder, Type intf, Type targetType) - { - ImplementInterface(typeBuilder, proxyMethodBuilder, intf, targetType, true); - } - - /// - /// Implements an interface. - /// - /// - /// Generates proxy methods that belongs to the interface - /// using the specified . - /// - /// The type builder to use. - /// - /// The implementation to use - /// - /// The interface to implement. - /// - /// The of the target object. - /// - /// - /// if target virtual methods should not be proxied; - /// otherwise . - /// - protected virtual void ImplementInterface(TypeBuilder typeBuilder, - IProxyMethodBuilder proxyMethodBuilder, Type intf, - Type targetType, bool proxyVirtualMethods) - { - Dictionary methodMap = new Dictionary(); - - InterfaceMapping mapping = GetInterfaceMapping(targetType, intf); - - typeBuilder.AddInterfaceImplementation(intf); - - for (int i = 0; i < mapping.InterfaceMethods.Length; i++) - { - if (!proxyVirtualMethods && - !mapping.TargetMethods[i].DeclaringType.IsInterface && - mapping.TargetMethods[i].IsVirtual && - !mapping.TargetMethods[i].IsFinal) - continue; - - MethodBuilder methodBuilder = proxyMethodBuilder.BuildProxyMethod( - mapping.TargetMethods[i], mapping.InterfaceMethods[i]); - - ApplyMethodAttributes(methodBuilder, mapping.TargetMethods[i]); - - methodMap[mapping.InterfaceMethods[i].Name] = methodBuilder; - } - foreach (PropertyInfo property in intf.GetProperties()) - { - ImplementProperty(typeBuilder, intf, property, methodMap); - } - foreach (EventInfo evt in intf.GetEvents()) - { - ImplementEvent(typeBuilder, intf, evt, methodMap); - } - } - - /// - /// Gets the mapping of the interface to proxy - /// into the actual methods on the target type - /// that does not need to implement that interface. - /// - /// - ///

- /// If the target type does not implement the interface, - /// we return the interfaces methods as the target methods for many reasons : - ///

    - ///
  • - /// The target object can change for an object that implements the interface. - /// (See 'Spring.Aop.Framework.DynamicProxy.IAdvisedProxyMethodBuilder' - /// implementation in the Spring AOP framework for an example) - ///
  • - ///
  • - /// Allow Transparent proxies to be proxied. - /// (See Spring Remoting framework for an example) - ///
  • - ///
  • - /// Allow null target to be proxied. - /// (See Spring AOP framework which avoid calls to the target object - /// by intercepting all methods. Think "dynamic mock") - /// (See 'Spring.Web.Services.WebServiceProxyFactory' implementation for another example) - ///
  • - ///
- ///

- ///
- /// - /// The of the target object. - /// - /// The interface to implement. - /// - /// An interface mapping for the interface to proxy. - /// - protected virtual InterfaceMapping GetInterfaceMapping( - Type targetType, Type intf) - { - InterfaceMapping mapping; - - if (intf.IsAssignableFrom(targetType)) - { - // target type implements the interface - mapping = targetType.GetInterfaceMap(intf); - } - else - { - // target type does not implement the interface - mapping.TargetType = targetType; - mapping.InterfaceType = intf; - mapping.InterfaceMethods = intf.GetMethods(); - mapping.TargetMethods = mapping.InterfaceMethods; - } - - return mapping; - } - - /// - /// Inherit from a type. - /// - /// - /// Generates proxy methods for base virtual methods - /// using the specified . - /// - /// - /// The builder to use for code generation. - /// - /// - /// The implementation to use to override base virtual methods. - /// - /// The to inherit from. - protected virtual void InheritType(TypeBuilder typeBuilder, - IProxyMethodBuilder proxyMethodBuilder, Type type) - { - InheritType(typeBuilder, proxyMethodBuilder, type, false); - } - - /// - /// Inherit from a type. - /// - /// - /// Generates proxy methods for base virtual methods - /// using the specified . - /// - /// - /// The builder to use for code generation. - /// - /// - /// The implementation to use to override base virtual methods. - /// - /// The to inherit from. - /// - /// if only members declared at the level - /// of the supplied 's hierarchy should be proxied; - /// otherwise . - /// - protected virtual void InheritType(TypeBuilder typeBuilder, - IProxyMethodBuilder proxyMethodBuilder, Type type, bool declaredMembersOnly) - { - IDictionary methodMap = new Dictionary(); - - BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic; - if (declaredMembersOnly) - { - bindingFlags |= BindingFlags.DeclaredOnly; - } - - // override virtual methods - MethodInfo[] methods = type.GetMethods(bindingFlags); - foreach (MethodInfo method in methods) - { - MethodAttributes memberAccess = method.Attributes & MethodAttributes.MemberAccessMask; - - if (method.IsVirtual && !method.IsFinal && !method.Name.Equals("Finalize") - && (memberAccess == MethodAttributes.Public || memberAccess == MethodAttributes.Family || memberAccess == MethodAttributes.FamORAssem)) - { - MethodBuilder methodBuilder = proxyMethodBuilder.BuildProxyMethod(method, null); - ApplyMethodAttributes(methodBuilder, method); - methodMap[method.Name] = methodBuilder; - } - } - // override virtual properties - foreach (PropertyInfo property in type.GetProperties(bindingFlags)) - { - ImplementProperty(typeBuilder, type, property, methodMap); - } - // override virtual events - foreach (EventInfo evt in type.GetEvents(bindingFlags)) - { - ImplementEvent(typeBuilder, type, evt, methodMap); - } - } - - /// - /// Implements the specified . - /// - /// The type builder to use. - /// The type the property is defined on. - /// The property to proxy. - /// The implemented methods map. - protected virtual void ImplementProperty( - TypeBuilder typeBuilder, Type type, PropertyInfo property, IDictionary methodMap) - { - MethodBuilder getMethod; - methodMap.TryGetValue("get_" + property.Name, out getMethod); - MethodBuilder setMethod; - methodMap.TryGetValue("set_" + property.Name, out setMethod); - - if (getMethod != null || setMethod != null) - { - string propertyName = (type.IsInterface && - ((getMethod != null && getMethod.IsPrivate) || (setMethod != null && setMethod.IsPrivate))) - ? type.FullName + "." + property.Name - : property.Name; - PropertyBuilder pb = typeBuilder.DefineProperty(propertyName, PropertyAttributes.None, - property.PropertyType, null); - - // set get/set methods - if (property.CanRead && getMethod != null) - { - pb.SetGetMethod(getMethod); - } - if (property.CanWrite && setMethod != null) - { - pb.SetSetMethod(setMethod); - } - } - } - - /// - /// Implements the specified event. - /// - /// The type builder to use. - /// The type the event is defined on. - /// The event to proxy. - /// The implemented methods map. - protected virtual void ImplementEvent(TypeBuilder typeBuilder, Type type, EventInfo evt, IDictionary methodMap) - { - MethodBuilder addOnMethod; - methodMap.TryGetValue("add_" + evt.Name, out addOnMethod); - MethodBuilder removeOnMethod; - methodMap.TryGetValue("remove_" + evt.Name, out removeOnMethod); - - if (addOnMethod != null && removeOnMethod != null) - { - string eventName = (addOnMethod.IsPrivate) - ? addOnMethod.DeclaringType.FullName + "." + evt.Name - : evt.Name; - - EventBuilder eb = typeBuilder.DefineEvent( - eventName, EventAttributes.None, evt.EventHandlerType); - - // set add/remove methods - eb.SetAddOnMethod(addOnMethod); - eb.SetRemoveOnMethod(removeOnMethod); - } - } - - #endregion - - /// - /// Returns an array of s that represent - /// the proxiable interfaces. - /// - /// - /// An interface is proxiable if it's not marked with the - /// . - /// - /// - /// The array of interfaces from which - /// we want to get the proxiable interfaces. - /// - /// - /// An array containing the interface s. - /// - protected virtual IList GetProxiableInterfaces(IList interfaces) - { - List proxiableInterfaces = new List(); - - foreach(Type intf in interfaces) - { - if (!Attribute.IsDefined(intf, typeof(ProxyIgnoreAttribute), false) && - !IsSpecialInterface(intf) && - ReflectionUtils.IsTypeVisible(intf, DynamicProxyManager.ASSEMBLY_NAME)) - { - if (!proxiableInterfaces.Contains(intf)) - { - proxiableInterfaces.Add(intf); - } - - Type[] baseInterfaces = intf.GetInterfaces(); - foreach (Type baseInterface in baseInterfaces) - { - if (!proxiableInterfaces.Contains(baseInterface)) - { - proxiableInterfaces.Add(baseInterface); - } - } - } - } - - return proxiableInterfaces; - } - - /// - /// Checks if specified interface is of a special type - /// that should never be proxied (i.e. ISerializable). - /// - /// Interface type to check. - /// - /// true if it is, false otherwise. - /// - private bool IsSpecialInterface(Type intf) - { - return intf == typeof(ISerializable); - } - - #endregion } + + /// + /// Applies attributes to the proxied method. + /// + /// The method builder to use. + /// The proxied method. + /// + /// + protected virtual void ApplyMethodAttributes(MethodBuilder methodBuilder, MethodInfo targetMethod) + { + foreach (object attr in GetMethodAttributes(targetMethod)) + { + if (attr is CustomAttributeBuilder) + { + methodBuilder.SetCustomAttribute((CustomAttributeBuilder) attr); + } + else if (attr is CustomAttributeData) + { + methodBuilder.SetCustomAttribute( + ReflectionUtils.CreateCustomAttribute((CustomAttributeData) attr)); + } + else if (attr is Attribute) + { + methodBuilder.SetCustomAttribute( + ReflectionUtils.CreateCustomAttribute((Attribute) attr)); + } + } + + ApplyMethodReturnTypeAttributes(methodBuilder, targetMethod); + ApplyMethodParameterAttributes(methodBuilder, targetMethod); + } + + /// + /// Applies attributes to the proxied method's return type. + /// + /// The method builder to use. + /// The proxied method. + /// + protected virtual void ApplyMethodReturnTypeAttributes(MethodBuilder methodBuilder, MethodInfo targetMethod) + { + ParameterBuilder parameterBuilder = methodBuilder.DefineParameter(0, ParameterAttributes.Retval, null); + foreach (object attr in GetMethodReturnTypeAttributes(targetMethod)) + { + if (attr is CustomAttributeBuilder) + { + parameterBuilder.SetCustomAttribute((CustomAttributeBuilder) attr); + } + else if (attr is CustomAttributeData) + { + parameterBuilder.SetCustomAttribute( + ReflectionUtils.CreateCustomAttribute((CustomAttributeData) attr)); + } + else if (attr is Attribute) + { + parameterBuilder.SetCustomAttribute( + ReflectionUtils.CreateCustomAttribute((Attribute) attr)); + } + } + } + + /// + /// Applies attributes to proxied method's parameters. + /// + /// The method builder to use. + /// The proxied method. + /// + protected virtual void ApplyMethodParameterAttributes(MethodBuilder methodBuilder, MethodInfo targetMethod) + { + foreach (ParameterInfo paramInfo in targetMethod.GetParameters()) + { + ParameterBuilder parameterBuilder = methodBuilder.DefineParameter( + (paramInfo.Position + 1), paramInfo.Attributes, paramInfo.Name); + foreach (object attr in GetMethodParameterAttributes(targetMethod, paramInfo)) + { + if (attr is CustomAttributeBuilder) + { + parameterBuilder.SetCustomAttribute((CustomAttributeBuilder) attr); + } + else if (attr is CustomAttributeData) + { + parameterBuilder.SetCustomAttribute( + ReflectionUtils.CreateCustomAttribute((CustomAttributeData) attr)); + } + else if (attr is Attribute) + { + parameterBuilder.SetCustomAttribute( + ReflectionUtils.CreateCustomAttribute((Attribute) attr)); + } + } + } + } + + /// + /// Calculates and returns the list of attributes that apply to the + /// specified type. + /// + /// The type to find attributes for. + /// + /// A list of custom attributes that should be applied to type. + /// + /// + /// + protected virtual IList GetTypeAttributes(Type type) + { + ArrayList attributes = new ArrayList(); + + if (this.ProxyTargetAttributes && !type.Equals(typeof(object))) + { + // add attributes that apply to the target type + attributes.AddRange(ReflectionUtils.GetCustomAttributes(type)); + } + + // add attributes defined by configuration + attributes.AddRange(TypeAttributes); + + return attributes; + } + + /// + /// Calculates and returns the list of attributes that apply to the + /// specified method. + /// + /// The method to find attributes for. + /// + /// A list of custom attributes that should be applied to method. + /// + /// + /// + protected virtual IList GetMethodAttributes(MethodInfo method) + { + ArrayList attributes = new ArrayList(); + + if (this.ProxyTargetAttributes && + !method.DeclaringType.IsInterface) + { + // add attributes that apply to the target method + attributes.AddRange(ReflectionUtils.GetCustomAttributes(method)); + } + + // add attributes defined by configuration + foreach (DictionaryEntry entry in MemberAttributes) + { + if (TypeResolutionUtils.MethodMatch((string) entry.Key, method)) + { + if (entry.Value is Attribute) + { + attributes.Add(entry.Value); + } + else if (entry.Value is IList) + { + attributes.AddRange(entry.Value as IList); + } + } + } + + return attributes; + } + + /// + /// Calculates and returns the list of attributes that apply to the + /// specified method's return type. + /// + /// The method to find attributes for. + /// + /// A list of custom attributes that should be applied to method's return type. + /// + /// + protected virtual IList GetMethodReturnTypeAttributes(MethodInfo method) + { + ArrayList attributes = new ArrayList(); + + if (this.ProxyTargetAttributes && + !method.DeclaringType.IsInterface) + { + // add attributes that apply to the target method' return type + object[] attrs = method.ReturnTypeCustomAttributes.GetCustomAttributes(false); + try + { + System.Collections.Generic.IList attrsData = + CustomAttributeData.GetCustomAttributes(method.ReturnParameter); + + if (attrs.Length != attrsData.Count) + { + // http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=94803 + attributes.AddRange(attrs); + } + else + { + foreach (CustomAttributeData cad in attrsData) + { + attributes.Add(cad); + } + } + } + catch (ArgumentException) + { + // http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=296032 + attributes.AddRange(attrs); + } + } + + // TODO: add attributes defined by configuration + + return attributes; + } + + /// + /// Calculates and returns the list of attributes that apply to the + /// specified method's parameters. + /// + /// The method to find attributes for. + /// The method's parameter to find attributes for. + /// + /// A list of custom attributes that should be applied to the specified method's parameter. + /// + /// + protected virtual IList GetMethodParameterAttributes(MethodInfo method, ParameterInfo paramInfo) + { + ArrayList attributes = new ArrayList(); + + if (this.ProxyTargetAttributes && + !method.DeclaringType.IsInterface) + { + // add attributes that apply to the target method's parameter + object[] attrs = paramInfo.GetCustomAttributes(false); + try + { + IList attrsData = CustomAttributeData.GetCustomAttributes(paramInfo); + + if (attrs.Length != attrsData.Count) + { + // http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=94803 + attributes.AddRange(attrs); + } + else + { + foreach (CustomAttributeData cad in attrsData) + { + attributes.Add(cad); + } + } + } + catch (ArgumentException) + { + // http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=296032 + attributes.AddRange(attrs); + } + } + + // TODO: add attributes defined by configuration + + return attributes; + } + + /// + /// Check that the specified object is matching the passed attribute type. + /// + /// + ///

+ /// The specified object can be of different type : + ///

+ /// + /// + /// + /// + /// + /// System.Reflection.CustomAttributeData (Only with .NET 2.0) + /// + /// + /// + /// + /// + ///
+ /// The object instance to check. + /// The attribute type to test against. + /// + /// if the object instance matches the attribute type; + /// otherwise . + /// + protected virtual bool IsAttributeMatchingType(object attr, Type attrType) + { + if (attr is Attribute) + { + return (attrType == attr.GetType()); + } + else if (attr is CustomAttributeData) + { + return (attrType == ((CustomAttributeData) attr).Constructor.DeclaringType); + } + else if (attr is CustomAttributeBuilder) + { + return (attrType == ((ConstructorInfo) CustomAttributeConstructorField.GetValue(attr)).DeclaringType); + } + + return false; + } + + private static readonly FieldInfo CustomAttributeConstructorField = + typeof(CustomAttributeBuilder).GetField("m_con", BindingFlags.Instance | BindingFlags.NonPublic); + + #endregion + + #region Constructors generation + + /// + /// Defines the types of the parameters for the specified constructor. + /// + /// The constructor to use. + /// The types for constructor's parameters. + protected virtual Type[] DefineConstructorParameters(ConstructorInfo constructor) + { + return ReflectionUtils.GetParameterTypes(constructor.GetParameters()); + } + + /// + /// Implements constructors for the proxy class. + /// + /// + /// The builder to use. + /// + protected virtual void ImplementConstructors(TypeBuilder typeBuilder) + { + ConstructorInfo[] constructors = TargetType.GetConstructors( + BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); + + foreach (ConstructorInfo constructor in constructors) + { + if (constructor.IsPublic || constructor.IsFamily) + { + ConstructorBuilder cb = typeBuilder.DefineConstructor( + constructor.Attributes, + constructor.CallingConvention, + DefineConstructorParameters(constructor)); + + ILGenerator il = cb.GetILGenerator(); + GenerateConstructor(cb, il, constructor); + il.Emit(OpCodes.Ret); + } + } + } + + /// + /// Generates the proxy constructor. + /// + /// The constructor builder to use. + /// The IL generator to use. + /// The constructor to use. + protected virtual void GenerateConstructor( + ConstructorBuilder builder, ILGenerator il, ConstructorInfo constructor) + { + } + + #endregion + + #region Members generation + + /// + /// Implements an interface. + /// + /// + /// Generates proxy methods that belongs to the interface + /// using the specified . + /// + /// The type builder to use. + /// + /// The implementation to use + /// + /// The interface to implement. + /// + /// The of the target object. + /// + protected virtual void ImplementInterface(TypeBuilder typeBuilder, + IProxyMethodBuilder proxyMethodBuilder, Type intf, Type targetType) + { + ImplementInterface(typeBuilder, proxyMethodBuilder, intf, targetType, true); + } + + /// + /// Implements an interface. + /// + /// + /// Generates proxy methods that belongs to the interface + /// using the specified . + /// + /// The type builder to use. + /// + /// The implementation to use + /// + /// The interface to implement. + /// + /// The of the target object. + /// + /// + /// if target virtual methods should not be proxied; + /// otherwise . + /// + protected virtual void ImplementInterface(TypeBuilder typeBuilder, + IProxyMethodBuilder proxyMethodBuilder, Type intf, + Type targetType, bool proxyVirtualMethods) + { + Dictionary methodMap = new Dictionary(); + + InterfaceMapping mapping = GetInterfaceMapping(targetType, intf); + + typeBuilder.AddInterfaceImplementation(intf); + + for (int i = 0; i < mapping.InterfaceMethods.Length; i++) + { + if (!proxyVirtualMethods && + !mapping.TargetMethods[i].DeclaringType.IsInterface && + mapping.TargetMethods[i].IsVirtual && + !mapping.TargetMethods[i].IsFinal) + continue; + + MethodBuilder methodBuilder = proxyMethodBuilder.BuildProxyMethod( + mapping.TargetMethods[i], mapping.InterfaceMethods[i]); + + ApplyMethodAttributes(methodBuilder, mapping.TargetMethods[i]); + + methodMap[mapping.InterfaceMethods[i].Name] = methodBuilder; + } + + foreach (PropertyInfo property in intf.GetProperties()) + { + ImplementProperty(typeBuilder, intf, property, methodMap); + } + + foreach (EventInfo evt in intf.GetEvents()) + { + ImplementEvent(typeBuilder, intf, evt, methodMap); + } + } + + /// + /// Gets the mapping of the interface to proxy + /// into the actual methods on the target type + /// that does not need to implement that interface. + /// + /// + ///

+ /// If the target type does not implement the interface, + /// we return the interfaces methods as the target methods for many reasons : + ///

    + ///
  • + /// The target object can change for an object that implements the interface. + /// (See 'Spring.Aop.Framework.DynamicProxy.IAdvisedProxyMethodBuilder' + /// implementation in the Spring AOP framework for an example) + ///
  • + ///
  • + /// Allow Transparent proxies to be proxied. + /// (See Spring Remoting framework for an example) + ///
  • + ///
  • + /// Allow null target to be proxied. + /// (See Spring AOP framework which avoid calls to the target object + /// by intercepting all methods. Think "dynamic mock") + /// (See 'Spring.Web.Services.WebServiceProxyFactory' implementation for another example) + ///
  • + ///
+ ///

+ ///
+ /// + /// The of the target object. + /// + /// The interface to implement. + /// + /// An interface mapping for the interface to proxy. + /// + protected virtual InterfaceMapping GetInterfaceMapping( + Type targetType, Type intf) + { + InterfaceMapping mapping; + + if (intf.IsAssignableFrom(targetType)) + { + // target type implements the interface + mapping = targetType.GetInterfaceMap(intf); + } + else + { + // target type does not implement the interface + mapping.TargetType = targetType; + mapping.InterfaceType = intf; + mapping.InterfaceMethods = intf.GetMethods(); + mapping.TargetMethods = mapping.InterfaceMethods; + } + + return mapping; + } + + /// + /// Inherit from a type. + /// + /// + /// Generates proxy methods for base virtual methods + /// using the specified . + /// + /// + /// The builder to use for code generation. + /// + /// + /// The implementation to use to override base virtual methods. + /// + /// The to inherit from. + protected virtual void InheritType(TypeBuilder typeBuilder, + IProxyMethodBuilder proxyMethodBuilder, Type type) + { + InheritType(typeBuilder, proxyMethodBuilder, type, false); + } + + /// + /// Inherit from a type. + /// + /// + /// Generates proxy methods for base virtual methods + /// using the specified . + /// + /// + /// The builder to use for code generation. + /// + /// + /// The implementation to use to override base virtual methods. + /// + /// The to inherit from. + /// + /// if only members declared at the level + /// of the supplied 's hierarchy should be proxied; + /// otherwise . + /// + protected virtual void InheritType(TypeBuilder typeBuilder, + IProxyMethodBuilder proxyMethodBuilder, Type type, bool declaredMembersOnly) + { + IDictionary methodMap = new Dictionary(); + + BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic; + if (declaredMembersOnly) + { + bindingFlags |= BindingFlags.DeclaredOnly; + } + + // override virtual methods + MethodInfo[] methods = type.GetMethods(bindingFlags); + foreach (MethodInfo method in methods) + { + MethodAttributes memberAccess = method.Attributes & MethodAttributes.MemberAccessMask; + + if (method.IsVirtual && !method.IsFinal && !method.Name.Equals("Finalize") + && (memberAccess == MethodAttributes.Public || memberAccess == MethodAttributes.Family || memberAccess == MethodAttributes.FamORAssem)) + { + MethodBuilder methodBuilder = proxyMethodBuilder.BuildProxyMethod(method, null); + ApplyMethodAttributes(methodBuilder, method); + methodMap[method.Name] = methodBuilder; + } + } + + // override virtual properties + foreach (PropertyInfo property in type.GetProperties(bindingFlags)) + { + ImplementProperty(typeBuilder, type, property, methodMap); + } + + // override virtual events + foreach (EventInfo evt in type.GetEvents(bindingFlags)) + { + ImplementEvent(typeBuilder, type, evt, methodMap); + } + } + + /// + /// Implements the specified . + /// + /// The type builder to use. + /// The type the property is defined on. + /// The property to proxy. + /// The implemented methods map. + protected virtual void ImplementProperty( + TypeBuilder typeBuilder, Type type, PropertyInfo property, IDictionary methodMap) + { + MethodBuilder getMethod; + methodMap.TryGetValue("get_" + property.Name, out getMethod); + MethodBuilder setMethod; + methodMap.TryGetValue("set_" + property.Name, out setMethod); + + if (getMethod != null || setMethod != null) + { + string propertyName = (type.IsInterface && + ((getMethod != null && getMethod.IsPrivate) || (setMethod != null && setMethod.IsPrivate))) + ? type.FullName + "." + property.Name + : property.Name; + PropertyBuilder pb = typeBuilder.DefineProperty(propertyName, PropertyAttributes.None, + property.PropertyType, null); + + // set get/set methods + if (property.CanRead && getMethod != null) + { + pb.SetGetMethod(getMethod); + } + + if (property.CanWrite && setMethod != null) + { + pb.SetSetMethod(setMethod); + } + } + } + + /// + /// Implements the specified event. + /// + /// The type builder to use. + /// The type the event is defined on. + /// The event to proxy. + /// The implemented methods map. + protected virtual void ImplementEvent(TypeBuilder typeBuilder, Type type, EventInfo evt, IDictionary methodMap) + { + MethodBuilder addOnMethod; + methodMap.TryGetValue("add_" + evt.Name, out addOnMethod); + MethodBuilder removeOnMethod; + methodMap.TryGetValue("remove_" + evt.Name, out removeOnMethod); + + if (addOnMethod != null && removeOnMethod != null) + { + string eventName = (addOnMethod.IsPrivate) + ? addOnMethod.DeclaringType.FullName + "." + evt.Name + : evt.Name; + + EventBuilder eb = typeBuilder.DefineEvent( + eventName, EventAttributes.None, evt.EventHandlerType); + + // set add/remove methods + eb.SetAddOnMethod(addOnMethod); + eb.SetRemoveOnMethod(removeOnMethod); + } + } + + #endregion + + /// + /// Returns an array of s that represent + /// the proxiable interfaces. + /// + /// + /// An interface is proxiable if it's not marked with the + /// . + /// + /// + /// The array of interfaces from which + /// we want to get the proxiable interfaces. + /// + /// + /// An array containing the interface s. + /// + protected virtual IList GetProxiableInterfaces(IList interfaces) + { + List proxiableInterfaces = new List(); + + foreach (Type intf in interfaces) + { + if (!Attribute.IsDefined(intf, typeof(ProxyIgnoreAttribute), false) && + !IsSpecialInterface(intf) && + ReflectionUtils.IsTypeVisible(intf, DynamicProxyManager.ASSEMBLY_NAME)) + { + if (!proxiableInterfaces.Contains(intf)) + { + proxiableInterfaces.Add(intf); + } + + Type[] baseInterfaces = intf.GetInterfaces(); + foreach (Type baseInterface in baseInterfaces) + { + if (!proxiableInterfaces.Contains(baseInterface)) + { + proxiableInterfaces.Add(baseInterface); + } + } + } + } + + return proxiableInterfaces; + } + + /// + /// Checks if specified interface is of a special type + /// that should never be proxied (i.e. ISerializable). + /// + /// Interface type to check. + /// + /// true if it is, false otherwise. + /// + private bool IsSpecialInterface(Type intf) + { + return intf == typeof(ISerializable); + } + + #endregion } diff --git a/src/Spring/Spring.Core/Proxy/BaseProxyMethodBuilder.cs b/src/Spring/Spring.Core/Proxy/BaseProxyMethodBuilder.cs index 77862473..7eaaca76 100644 --- a/src/Spring/Spring.Core/Proxy/BaseProxyMethodBuilder.cs +++ b/src/Spring/Spring.Core/Proxy/BaseProxyMethodBuilder.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -25,51 +25,50 @@ using System.Reflection.Emit; #endregion -namespace Spring.Proxy +namespace Spring.Proxy; + +/// +/// Implementation of IProxyMethodBuilder that delegates method calls to the base class. +/// +/// Bruno Baia +public class BaseProxyMethodBuilder : AbstractProxyMethodBuilder { + #region Constructor(s) / Destructor + /// - /// Implementation of IProxyMethodBuilder that delegates method calls to the base class. + /// Creates a new instance of the method builder. /// - /// Bruno Baia - public class BaseProxyMethodBuilder : AbstractProxyMethodBuilder + /// The type builder to use. + /// + /// The implementation to use. + /// + /// + /// if the interface is to be + /// implemented explicitly; otherwise . + /// + public BaseProxyMethodBuilder(TypeBuilder typeBuilder, + IProxyTypeGenerator proxyGenerator, bool explicitImplementation) + : base(typeBuilder, proxyGenerator, explicitImplementation) { - #region Constructor(s) / Destructor - - /// - /// Creates a new instance of the method builder. - /// - /// The type builder to use. - /// - /// The implementation to use. - /// - /// - /// if the interface is to be - /// implemented explicitly; otherwise . - /// - public BaseProxyMethodBuilder(TypeBuilder typeBuilder, - IProxyTypeGenerator proxyGenerator, bool explicitImplementation) - : base(typeBuilder, proxyGenerator, explicitImplementation) - { - } - - #endregion - - #region Protected Methods - - /// - /// Generates the proxy method. - /// - /// The IL generator to use. - /// The method to proxy. - /// - /// The interface definition of the method, if applicable. - /// - protected override void GenerateMethod( - ILGenerator il, MethodInfo method, MethodInfo interfaceMethod) - { - CallDirectBaseMethod(il, method); - } - - #endregion } + + #endregion + + #region Protected Methods + + /// + /// Generates the proxy method. + /// + /// The IL generator to use. + /// The method to proxy. + /// + /// The interface definition of the method, if applicable. + /// + protected override void GenerateMethod( + ILGenerator il, MethodInfo method, MethodInfo interfaceMethod) + { + CallDirectBaseMethod(il, method); + } + + #endregion } diff --git a/src/Spring/Spring.Core/Proxy/CompositionProxyTypeBuilder.cs b/src/Spring/Spring.Core/Proxy/CompositionProxyTypeBuilder.cs index 286a76bc..9cef79a7 100644 --- a/src/Spring/Spring.Core/Proxy/CompositionProxyTypeBuilder.cs +++ b/src/Spring/Spring.Core/Proxy/CompositionProxyTypeBuilder.cs @@ -25,180 +25,180 @@ using System.Reflection.Emit; #endregion -namespace Spring.Proxy +namespace Spring.Proxy; + +/// +/// Builds a proxy type using composition. +/// +/// +/// +/// In order for this builder to work, the target must implement +/// one or more interfaces. +/// +/// +/// Aleksandar Seovic +/// Bruno Baia +public class CompositionProxyTypeBuilder : AbstractProxyTypeBuilder { + #region Fields + + private bool explicitInterfaceImplementation = false; + /// - /// Builds a proxy type using composition. + /// Target instance calls should be delegated to. + /// + protected FieldBuilder targetInstance; + + #endregion + + #region Properties + + /// + /// Gets or sets a value indicating whether interfaces should be implemented explicitly. + /// + /// + /// if they should be; otherwise, . + /// + public bool ExplicitInterfaceImplementation + { + get { return explicitInterfaceImplementation; } + set { explicitInterfaceImplementation = value; } + } + + #endregion + + #region Constructor(s) / Destructor + + /// + /// Creates a new instance of the + /// class. + /// + public CompositionProxyTypeBuilder() + { + Name = "CompositionProxy"; + } + + #endregion + + #region IProxyTypeBuilder Members + + /// + /// Creates a proxy that delegates calls to an instance of the + /// target object. /// /// - /// - /// In order for this builder to work, the target must implement - /// one or more interfaces. - /// + ///

+ /// Only interfaces can be proxied using composition, so the target + /// must implement one or more interfaces. + ///

///
- /// Aleksandar Seovic - /// Bruno Baia - public class CompositionProxyTypeBuilder : AbstractProxyTypeBuilder + /// The generated proxy class. + /// + /// If the + /// does not implement any interfaces. + /// + public override Type BuildProxyType() { - #region Fields - - private bool explicitInterfaceImplementation = false; - - /// - /// Target instance calls should be delegated to. - /// - protected FieldBuilder targetInstance; - - #endregion - - #region Properties - - /// - /// Gets or sets a value indicating whether interfaces should be implemented explicitly. - /// - /// - /// if they should be; otherwise, . - /// - public bool ExplicitInterfaceImplementation + if (Interfaces == null || Interfaces.Count == 0) { - get { return explicitInterfaceImplementation; } - set { explicitInterfaceImplementation = value; } + throw new ArgumentException( + "Composition proxy target must implement at least one interface."); } - #endregion + TypeBuilder typeBuilder = CreateTypeBuilder(Name, BaseType); - #region Constructor(s) / Destructor + // apply custom attributes to the proxy type. + ApplyTypeAttributes(typeBuilder, TargetType); - /// - /// Creates a new instance of the - /// class. - /// - public CompositionProxyTypeBuilder() + // declare fields + DeclareTargetInstanceField(typeBuilder); + + // create constructors + ImplementConstructors(typeBuilder); + + // implement interfaces + foreach (Type intf in Interfaces) { - Name = "CompositionProxy"; + ImplementInterface(typeBuilder, + CreateTargetProxyMethodBuilder(typeBuilder), + intf, TargetType); } - #endregion + ImplementCustom(typeBuilder); - #region IProxyTypeBuilder Members - - /// - /// Creates a proxy that delegates calls to an instance of the - /// target object. - /// - /// - ///

- /// Only interfaces can be proxied using composition, so the target - /// must implement one or more interfaces. - ///

- ///
- /// The generated proxy class. - /// - /// If the - /// does not implement any interfaces. - /// - public override Type BuildProxyType() - { - if (Interfaces == null || Interfaces.Count == 0) - { - throw new ArgumentException( - "Composition proxy target must implement at least one interface."); - } - - TypeBuilder typeBuilder = CreateTypeBuilder(Name, BaseType); - - // apply custom attributes to the proxy type. - ApplyTypeAttributes(typeBuilder, TargetType); - - // declare fields - DeclareTargetInstanceField(typeBuilder); - - // create constructors - ImplementConstructors(typeBuilder); - - // implement interfaces - foreach (Type intf in Interfaces) - { - ImplementInterface(typeBuilder, - CreateTargetProxyMethodBuilder(typeBuilder), - intf, TargetType); - } - - ImplementCustom(typeBuilder); - - return typeBuilder.CreateTypeInfo(); - } - - /// - /// Create an to create interface implementations - /// - protected virtual IProxyMethodBuilder CreateTargetProxyMethodBuilder(TypeBuilder typeBuilder) - { - return new TargetProxyMethodBuilder(typeBuilder, this, explicitInterfaceImplementation); - } - - #endregion - - /// - /// Allows subclasses to generate additional code - /// - protected virtual void ImplementCustom(TypeBuilder builder) - { } - - #region IProxyTypeGenerator Members - - /// - /// Generates the IL instructions that pushes - /// the target instance on which calls should be delegated to. - /// - /// The IL generator to use. - public override void PushTarget(ILGenerator il) - { - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Ldfld, targetInstance); - } - - #endregion - - #region Protected Methods - - /// - /// Deaclares a field that holds the target object instance. - /// - /// - /// The builder to use for code generation. - /// - protected virtual void DeclareTargetInstanceField(TypeBuilder builder) - { - targetInstance = builder.DefineField("__proxyTarget", TargetType, FieldAttributes.Private); - } - - /// - /// Generates the proxy constructor. - /// - /// - ///

- /// This implementation creates instance of the target object for delegation - /// using constructor arguments. - ///

- ///
- /// The constructor builder to use. - /// The IL generator to use. - /// The constructor to delegate the creation to. - protected override void GenerateConstructor( - ConstructorBuilder builder, ILGenerator il, ConstructorInfo constructor) - { - int paramCount = constructor.GetParameters().Length; - il.Emit(OpCodes.Ldarg_0); - for (int i = 1; i <= paramCount; i++) - { - il.Emit(OpCodes.Ldarg_S, i); - } - - il.Emit(OpCodes.Newobj, constructor); - il.Emit(OpCodes.Stfld, targetInstance); - } - - #endregion + return typeBuilder.CreateTypeInfo(); } + + /// + /// Create an to create interface implementations + /// + protected virtual IProxyMethodBuilder CreateTargetProxyMethodBuilder(TypeBuilder typeBuilder) + { + return new TargetProxyMethodBuilder(typeBuilder, this, explicitInterfaceImplementation); + } + + #endregion + + /// + /// Allows subclasses to generate additional code + /// + protected virtual void ImplementCustom(TypeBuilder builder) + { + } + + #region IProxyTypeGenerator Members + + /// + /// Generates the IL instructions that pushes + /// the target instance on which calls should be delegated to. + /// + /// The IL generator to use. + public override void PushTarget(ILGenerator il) + { + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldfld, targetInstance); + } + + #endregion + + #region Protected Methods + + /// + /// Deaclares a field that holds the target object instance. + /// + /// + /// The builder to use for code generation. + /// + protected virtual void DeclareTargetInstanceField(TypeBuilder builder) + { + targetInstance = builder.DefineField("__proxyTarget", TargetType, FieldAttributes.Private); + } + + /// + /// Generates the proxy constructor. + /// + /// + ///

+ /// This implementation creates instance of the target object for delegation + /// using constructor arguments. + ///

+ ///
+ /// The constructor builder to use. + /// The IL generator to use. + /// The constructor to delegate the creation to. + protected override void GenerateConstructor( + ConstructorBuilder builder, ILGenerator il, ConstructorInfo constructor) + { + int paramCount = constructor.GetParameters().Length; + il.Emit(OpCodes.Ldarg_0); + for (int i = 1; i <= paramCount; i++) + { + il.Emit(OpCodes.Ldarg_S, i); + } + + il.Emit(OpCodes.Newobj, constructor); + il.Emit(OpCodes.Stfld, targetInstance); + } + + #endregion } diff --git a/src/Spring/Spring.Core/Proxy/DynamicProxyManager.cs b/src/Spring/Spring.Core/Proxy/DynamicProxyManager.cs index c5f742a4..ea5ff823 100644 --- a/src/Spring/Spring.Core/Proxy/DynamicProxyManager.cs +++ b/src/Spring/Spring.Core/Proxy/DynamicProxyManager.cs @@ -27,77 +27,76 @@ using Spring.Util; #endregion -namespace Spring.Proxy +namespace Spring.Proxy; + +/// +/// Allows easy access to existing and creation of new dynamic proxies. +/// +/// Aleksandar Seovic +/// Bruno Baia +public sealed class DynamicProxyManager { + #region Fields + /// - /// Allows easy access to existing and creation of new dynamic proxies. + /// The name of the assembly that defines proxy types created. /// - /// Aleksandar Seovic - /// Bruno Baia - public sealed class DynamicProxyManager + public const string ASSEMBLY_NAME = "Spring.Proxy"; + + /// + /// The attributes of the proxy type to generate. + /// + private const TypeAttributes TYPE_ATTRIBUTES = TypeAttributes.BeforeFieldInit | TypeAttributes.Public; + + #endregion + + #region Public Methods + + /// + /// Creates an appropriate type builder. + /// + /// The proxy type name. + /// The type to extends if provided. + /// The type builder to use. + public static TypeBuilder CreateTypeBuilder(string typeName, Type baseType) { - #region Fields + ModuleBuilder module = DynamicCodeManager.GetModuleBuilder(ASSEMBLY_NAME); - /// - /// The name of the assembly that defines proxy types created. - /// - public const string ASSEMBLY_NAME = "Spring.Proxy"; - - /// - /// The attributes of the proxy type to generate. - /// - private const TypeAttributes TYPE_ATTRIBUTES = TypeAttributes.BeforeFieldInit | TypeAttributes.Public; - - #endregion - - #region Public Methods - - /// - /// Creates an appropriate type builder. - /// - /// The proxy type name. - /// The type to extends if provided. - /// The type builder to use. - public static TypeBuilder CreateTypeBuilder(string typeName, Type baseType) + try { - ModuleBuilder module = DynamicCodeManager.GetModuleBuilder(ASSEMBLY_NAME); - - try + if (baseType == null) { - if (baseType == null) - { - return module.DefineType(typeName, TYPE_ATTRIBUTES); - } - else - { - return module.DefineType(typeName, TYPE_ATTRIBUTES, baseType); - } + return module.DefineType(typeName, TYPE_ATTRIBUTES); } - catch (ArgumentException ex) + else { - Type alreadyRegisteredType = module.GetType(typeName, true); - - string msg; - - if (alreadyRegisteredType != null) - msg = "Proxy already registered for \"{0}\" as Type \"{1}\"."; - else - msg = "Proxy already registered for \"{0}\"."; - - throw new ArgumentException(string.Format(msg, typeName, alreadyRegisteredType.FullName), ex); + return module.DefineType(typeName, TYPE_ATTRIBUTES, baseType); } } - - /// - /// Saves dynamically generated assembly to disk. - /// Can only be called in DEBUG_DYNAMIC mode, per ConditionalAttribute rules. - /// - [Conditional("DEBUG_DYNAMIC")] - public static void SaveAssembly() + catch (ArgumentException ex) { - DynamicCodeManager.SaveAssembly(ASSEMBLY_NAME); - } + Type alreadyRegisteredType = module.GetType(typeName, true); - #endregion + string msg; + + if (alreadyRegisteredType != null) + msg = "Proxy already registered for \"{0}\" as Type \"{1}\"."; + else + msg = "Proxy already registered for \"{0}\"."; + + throw new ArgumentException(string.Format(msg, typeName, alreadyRegisteredType.FullName), ex); + } } + + /// + /// Saves dynamically generated assembly to disk. + /// Can only be called in DEBUG_DYNAMIC mode, per ConditionalAttribute rules. + /// + [Conditional("DEBUG_DYNAMIC")] + public static void SaveAssembly() + { + DynamicCodeManager.SaveAssembly(ASSEMBLY_NAME); + } + + #endregion } diff --git a/src/Spring/Spring.Core/Proxy/IProxyMethodBuilder.cs b/src/Spring/Spring.Core/Proxy/IProxyMethodBuilder.cs index 26b1112d..432dd5e1 100644 --- a/src/Spring/Spring.Core/Proxy/IProxyMethodBuilder.cs +++ b/src/Spring/Spring.Core/Proxy/IProxyMethodBuilder.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -25,25 +25,24 @@ using System.Reflection.Emit; #endregion -namespace Spring.Proxy +namespace Spring.Proxy; + +/// +/// Defines interface that proxy method builders have to implement. +/// +/// Aleksandar Seovic +/// Bruno Baia +public interface IProxyMethodBuilder { /// - /// Defines interface that proxy method builders have to implement. + /// Dynamically builds proxy method. /// - /// Aleksandar Seovic - /// Bruno Baia - public interface IProxyMethodBuilder - { - /// - /// Dynamically builds proxy method. - /// - /// The method to proxy. - /// - /// The interface definition of the method, if applicable. - /// - /// - /// The for the proxy method. - /// - MethodBuilder BuildProxyMethod(MethodInfo method, MethodInfo intfMethod); - } + /// The method to proxy. + /// + /// The interface definition of the method, if applicable. + /// + /// + /// The for the proxy method. + /// + MethodBuilder BuildProxyMethod(MethodInfo method, MethodInfo intfMethod); } diff --git a/src/Spring/Spring.Core/Proxy/IProxyTypeBuilder.cs b/src/Spring/Spring.Core/Proxy/IProxyTypeBuilder.cs index d6d8ca24..5177bf7c 100644 --- a/src/Spring/Spring.Core/Proxy/IProxyTypeBuilder.cs +++ b/src/Spring/Spring.Core/Proxy/IProxyTypeBuilder.cs @@ -24,148 +24,147 @@ using System.Collections; #endregion -namespace Spring.Proxy +namespace Spring.Proxy; + +/// +/// Describes the operations for a generic proxy type builder that can be +/// used to create a proxy type for any class. +/// +/// Aleksandar Seovic +public interface IProxyTypeBuilder { - /// - /// Describes the operations for a generic proxy type builder that can be - /// used to create a proxy type for any class. - /// - /// Aleksandar Seovic - public interface IProxyTypeBuilder - { - /// - /// Creates the proxy type. - /// - /// The generated proxy class. - Type BuildProxyType(); + /// + /// Creates the proxy type. + /// + /// The generated proxy class. + Type BuildProxyType(); - /// - /// The name of the proxy . - /// - /// The name of the proxy . - string Name { get; set; } + /// + /// The name of the proxy . + /// + /// The name of the proxy . + string Name { get; set; } - /// - /// The of the target object. - /// - Type TargetType { get; set; } + /// + /// The of the target object. + /// + Type TargetType { get; set; } - /// - /// The of the class that the proxy must - /// inherit from. - /// - Type BaseType { get; set; } + /// + /// The of the class that the proxy must + /// inherit from. + /// + Type BaseType { get; set; } - /// - /// Gets or sets the list of interfaces proxy should implement. - /// - IList Interfaces { get; set; } + /// + /// Gets or sets the list of interfaces proxy should implement. + /// + IList Interfaces { get; set; } - /// - /// Should we proxy target attributes? - /// - /// - /// by default. - /// Target type attributes, method attributes, method's return type attributes - /// and method's parameter attributes are copied to the proxy. - /// - bool ProxyTargetAttributes { get; set; } + /// + /// Should we proxy target attributes? + /// + /// + /// by default. + /// Target type attributes, method attributes, method's return type attributes + /// and method's parameter attributes are copied to the proxy. + /// + bool ProxyTargetAttributes { get; set; } - /// - /// The list of custom s that the proxy - /// class must be decorated with. - /// - /// - ///

- /// Note that the list is composed of instances of the actual - /// s that are to be applied, not the - /// s of the s. - ///

- ///
- /// - ///

- /// The following code snippets show examples of how to decorate the - /// the proxied class with one or more s. - ///

- /// - /// // get a concrete implementation of an IProxyTypeBuilder... - /// IProxyTypeBuilder builder = ... ; - /// builder.TargetType = typeof( ... ); - /// - /// IDictionary typeAtts = new Hashtable(); - /// builder.TypeAttributes = typeAtts; - /// - /// // applies a single Attribute to the proxied class... - /// typeAtts = new Attribute[] { new MyCustomAttribute() }); - /// - /// // applies a number of Attributes to the proxied class... - /// typeAtts = new Attribute[] - /// { - /// new MyCustomAttribute(), - /// new AnotherAttribute(), - /// }); - /// - ///
- IList TypeAttributes { get; set; } + /// + /// The list of custom s that the proxy + /// class must be decorated with. + /// + /// + ///

+ /// Note that the list is composed of instances of the actual + /// s that are to be applied, not the + /// s of the s. + ///

+ ///
+ /// + ///

+ /// The following code snippets show examples of how to decorate the + /// the proxied class with one or more s. + ///

+ /// + /// // get a concrete implementation of an IProxyTypeBuilder... + /// IProxyTypeBuilder builder = ... ; + /// builder.TargetType = typeof( ... ); + /// + /// IDictionary typeAtts = new Hashtable(); + /// builder.TypeAttributes = typeAtts; + /// + /// // applies a single Attribute to the proxied class... + /// typeAtts = new Attribute[] { new MyCustomAttribute() }); + /// + /// // applies a number of Attributes to the proxied class... + /// typeAtts = new Attribute[] + /// { + /// new MyCustomAttribute(), + /// new AnotherAttribute(), + /// }); + /// + ///
+ IList TypeAttributes { get; set; } - /// - /// The custom s that the proxy - /// members must be decorated with. - /// - /// - ///

- /// This dictionary must use simple s for keys - /// (denoting the member names that the attributes are to be applied to), - /// with the corresponding values being - /// s. - ///

- ///

- /// The key may be wildcarded using the '*' character... if so, - /// then those proxy members that match against the key will be - /// decorated with the attendant list of - /// s. This naturally implies that using - /// the '*' character as a key will result in the attendant list - /// of s being applied to every member of - /// the proxied class. - ///

- ///
- /// - ///

- /// The following code snippets show examples of how to decorate the - /// members of a proxied class with one or more - /// s. - ///

- /// - /// // get a concrete implementation of an IProxyTypeBuilder... - /// IProxyTypeBuilder builder = ... ; - /// builder.TargetType = typeof( ... ); - /// - /// IDictionary memAtts = new Hashtable(); - /// builder.MemberAttributes = memAtts; - /// - /// // applies a single Attribute to all members of the proxied class... - /// memAtts ["*"] = new Attribute[] { new MyCustomAttribute() }); - /// - /// // applies a number of Attributes to all members of the proxied class... - /// memAtts ["*"] = new Attribute[] - /// { - /// new MyCustomAttribute(), - /// new AnotherAttribute(), - /// }); - /// - /// // applies a single Attribute to those members of the proxied class - /// // that have identifiers starting with 'Do' ... - /// memAtts ["Do*"] = new Attribute[] { new MyCustomAttribute() }); - /// - /// // applies a number of Attributes to those members of the proxied class - /// // that have identifiers starting with 'Do' ... - /// memAtts ["Do*"] = new Attribute[] - /// { - /// new MyCustomAttribute(), - /// new AnotherAttribute(), - /// }); - /// - ///
- IDictionary MemberAttributes { get; set; } - } + /// + /// The custom s that the proxy + /// members must be decorated with. + /// + /// + ///

+ /// This dictionary must use simple s for keys + /// (denoting the member names that the attributes are to be applied to), + /// with the corresponding values being + /// s. + ///

+ ///

+ /// The key may be wildcarded using the '*' character... if so, + /// then those proxy members that match against the key will be + /// decorated with the attendant list of + /// s. This naturally implies that using + /// the '*' character as a key will result in the attendant list + /// of s being applied to every member of + /// the proxied class. + ///

+ ///
+ /// + ///

+ /// The following code snippets show examples of how to decorate the + /// members of a proxied class with one or more + /// s. + ///

+ /// + /// // get a concrete implementation of an IProxyTypeBuilder... + /// IProxyTypeBuilder builder = ... ; + /// builder.TargetType = typeof( ... ); + /// + /// IDictionary memAtts = new Hashtable(); + /// builder.MemberAttributes = memAtts; + /// + /// // applies a single Attribute to all members of the proxied class... + /// memAtts ["*"] = new Attribute[] { new MyCustomAttribute() }); + /// + /// // applies a number of Attributes to all members of the proxied class... + /// memAtts ["*"] = new Attribute[] + /// { + /// new MyCustomAttribute(), + /// new AnotherAttribute(), + /// }); + /// + /// // applies a single Attribute to those members of the proxied class + /// // that have identifiers starting with 'Do' ... + /// memAtts ["Do*"] = new Attribute[] { new MyCustomAttribute() }); + /// + /// // applies a number of Attributes to those members of the proxied class + /// // that have identifiers starting with 'Do' ... + /// memAtts ["Do*"] = new Attribute[] + /// { + /// new MyCustomAttribute(), + /// new AnotherAttribute(), + /// }); + /// + ///
+ IDictionary MemberAttributes { get; set; } } diff --git a/src/Spring/Spring.Core/Proxy/IProxyTypeGenerator.cs b/src/Spring/Spring.Core/Proxy/IProxyTypeGenerator.cs index e98b18db..9066e187 100644 --- a/src/Spring/Spring.Core/Proxy/IProxyTypeGenerator.cs +++ b/src/Spring/Spring.Core/Proxy/IProxyTypeGenerator.cs @@ -17,6 +17,7 @@ */ #endregion + #region License /* @@ -39,34 +40,33 @@ using System.Reflection.Emit; -namespace Spring.Proxy +namespace Spring.Proxy; + +/// +/// Describes the operations that generates IL instructions +/// used to build the proxy type. +/// +/// Bruno Baia +public interface IProxyTypeGenerator { - /// - /// Describes the operations that generates IL instructions - /// used to build the proxy type. - /// - /// Bruno Baia - public interface IProxyTypeGenerator - { - // TODO : Why not ? + // TODO : Why not ? /* /// /// Gets the used to build the proxy type. /// TypeBuilder ProxyTypeBuilder { get; } */ - /// - /// Generates the IL instructions that pushes - /// the proxy instance on stack. - /// - /// The IL generator to use. - void PushProxy(ILGenerator il); + /// + /// Generates the IL instructions that pushes + /// the proxy instance on stack. + /// + /// The IL generator to use. + void PushProxy(ILGenerator il); - /// - /// Generates the IL instructions that pushes - /// the target instance on which calls should be delegated to. - /// - /// The IL generator to use. - void PushTarget(ILGenerator il); - } + /// + /// Generates the IL instructions that pushes + /// the target instance on which calls should be delegated to. + /// + /// The IL generator to use. + void PushTarget(ILGenerator il); } diff --git a/src/Spring/Spring.Core/Proxy/InheritanceProxyTypeBuilder.cs b/src/Spring/Spring.Core/Proxy/InheritanceProxyTypeBuilder.cs index 2d2d304f..60d023e9 100644 --- a/src/Spring/Spring.Core/Proxy/InheritanceProxyTypeBuilder.cs +++ b/src/Spring/Spring.Core/Proxy/InheritanceProxyTypeBuilder.cs @@ -21,148 +21,148 @@ using System.Reflection; using System.Reflection.Emit; -namespace Spring.Proxy +namespace Spring.Proxy; + +/// +/// Builds a proxy type using inheritance. +/// +/// +/// +/// In order for this builder to work, target methods have to be either +/// , or belong to an interface. +/// +/// +/// Aleksandar Seovic +/// Bruno Baia +public class InheritanceProxyTypeBuilder : AbstractProxyTypeBuilder { - /// - /// Builds a proxy type using inheritance. - /// - /// - /// - /// In order for this builder to work, target methods have to be either - /// , or belong to an interface. - /// - /// - /// Aleksandar Seovic - /// Bruno Baia - public class InheritanceProxyTypeBuilder : AbstractProxyTypeBuilder - { - #region Fields + #region Fields - private bool declaredMembersOnly = false; + private bool declaredMembersOnly = false; - #endregion + #endregion - #region Properties + #region Properties - /// - /// Gets or sets a value indicating whether inherited members should be proxied. - /// - /// - /// if they should be; otherwise, . - /// - public bool DeclaredMembersOnly - { - get { return declaredMembersOnly; } - set { declaredMembersOnly = value; } - } - - #endregion - - #region Constructor(s) / Destructor - - /// - /// Creates a new instance of the - /// class. - /// - public InheritanceProxyTypeBuilder() - { - Name = "InheritanceProxy"; - //ProxyTargetAttributes = false; - } - - #endregion - - #region IProxyTypeBuilder Members - - /// - /// Creates a proxy that inherits the proxied object's class. - /// - /// - ///

- /// Only (non-final) methods can be proxied, - /// unless they are members of one of the interfaces that target class - /// implements. In that case, methods will be proxied using explicit - /// interface implementation, which means that client code will have - /// to cast the proxy to a specific interface in order to invoke the - /// methods. - ///

- ///
- /// The generated proxy class. - public override Type BuildProxyType() - { - BaseType = TargetType; - if (BaseType.IsSealed) - { - throw new ArgumentException("Inheritance proxy cannot be created for a sealed class [" + BaseType.FullName + "]"); - } - - TypeBuilder typeBuilder = CreateTypeBuilder(Name, BaseType); - - // apply custom attributes to the proxy type. - ApplyTypeAttributes(typeBuilder, BaseType); - - // create constructors - ImplementConstructors(typeBuilder); - - // proxy only final methods that are members of one of the interfaces - foreach (Type intf in Interfaces) - { - ImplementInterface(typeBuilder, - new BaseProxyMethodBuilder(typeBuilder, this, true), - intf, TargetType, false); - } - - // proxy base virtual methods - InheritType(typeBuilder, - new BaseProxyMethodBuilder(typeBuilder, this, false), - BaseType, declaredMembersOnly); - - return typeBuilder.CreateTypeInfo(); - } - - #endregion - - #region IProxyTypeGenerator Members - - /// - /// Generates the IL instructions that pushes - /// the target instance on which calls should be delegated to. - /// - /// The IL generator to use. - public override void PushTarget(ILGenerator il) - { - PushProxy(il); - } - - #endregion - - #region Protected Methods - - /// - /// Generates the proxy constructor. - /// - /// - ///

- /// This implementation delegates the call to a base class constructor. - ///

- ///
- /// The constructor builder to use. - /// The IL generator to use. - /// - /// The base class constructor to delegate the call to. - /// - protected override void GenerateConstructor( - ConstructorBuilder builder, ILGenerator il, ConstructorInfo constructor) - { - int paramCount = constructor.GetParameters().Length; - il.Emit(OpCodes.Ldarg_0); - for (int i = 1; i <= paramCount; i++) - { - il.Emit(OpCodes.Ldarg_S, i); - } - il.Emit(OpCodes.Call, constructor); - } - - #endregion + /// + /// Gets or sets a value indicating whether inherited members should be proxied. + /// + /// + /// if they should be; otherwise, . + /// + public bool DeclaredMembersOnly + { + get { return declaredMembersOnly; } + set { declaredMembersOnly = value; } } + + #endregion + + #region Constructor(s) / Destructor + + /// + /// Creates a new instance of the + /// class. + /// + public InheritanceProxyTypeBuilder() + { + Name = "InheritanceProxy"; + //ProxyTargetAttributes = false; + } + + #endregion + + #region IProxyTypeBuilder Members + + /// + /// Creates a proxy that inherits the proxied object's class. + /// + /// + ///

+ /// Only (non-final) methods can be proxied, + /// unless they are members of one of the interfaces that target class + /// implements. In that case, methods will be proxied using explicit + /// interface implementation, which means that client code will have + /// to cast the proxy to a specific interface in order to invoke the + /// methods. + ///

+ ///
+ /// The generated proxy class. + public override Type BuildProxyType() + { + BaseType = TargetType; + if (BaseType.IsSealed) + { + throw new ArgumentException("Inheritance proxy cannot be created for a sealed class [" + BaseType.FullName + "]"); + } + + TypeBuilder typeBuilder = CreateTypeBuilder(Name, BaseType); + + // apply custom attributes to the proxy type. + ApplyTypeAttributes(typeBuilder, BaseType); + + // create constructors + ImplementConstructors(typeBuilder); + + // proxy only final methods that are members of one of the interfaces + foreach (Type intf in Interfaces) + { + ImplementInterface(typeBuilder, + new BaseProxyMethodBuilder(typeBuilder, this, true), + intf, TargetType, false); + } + + // proxy base virtual methods + InheritType(typeBuilder, + new BaseProxyMethodBuilder(typeBuilder, this, false), + BaseType, declaredMembersOnly); + + return typeBuilder.CreateTypeInfo(); + } + + #endregion + + #region IProxyTypeGenerator Members + + /// + /// Generates the IL instructions that pushes + /// the target instance on which calls should be delegated to. + /// + /// The IL generator to use. + public override void PushTarget(ILGenerator il) + { + PushProxy(il); + } + + #endregion + + #region Protected Methods + + /// + /// Generates the proxy constructor. + /// + /// + ///

+ /// This implementation delegates the call to a base class constructor. + ///

+ ///
+ /// The constructor builder to use. + /// The IL generator to use. + /// + /// The base class constructor to delegate the call to. + /// + protected override void GenerateConstructor( + ConstructorBuilder builder, ILGenerator il, ConstructorInfo constructor) + { + int paramCount = constructor.GetParameters().Length; + il.Emit(OpCodes.Ldarg_0); + for (int i = 1; i <= paramCount; i++) + { + il.Emit(OpCodes.Ldarg_S, i); + } + + il.Emit(OpCodes.Call, constructor); + } + + #endregion } diff --git a/src/Spring/Spring.Core/Proxy/ProxyIgnoreAttribute.cs b/src/Spring/Spring.Core/Proxy/ProxyIgnoreAttribute.cs index 2a0f622d..ae6de550 100644 --- a/src/Spring/Spring.Core/Proxy/ProxyIgnoreAttribute.cs +++ b/src/Spring/Spring.Core/Proxy/ProxyIgnoreAttribute.cs @@ -22,22 +22,21 @@ #endregion -namespace Spring.Proxy +namespace Spring.Proxy; + +/// +/// This attribute can be used to mark interfaces that should not be proxied +/// +/// Bruno Baia +[AttributeUsage(AttributeTargets.Interface, AllowMultiple = false, Inherited = false)] +[Serializable] +public sealed class ProxyIgnoreAttribute : Attribute { /// - /// This attribute can be used to mark interfaces that should not be proxied + /// Creates a new instance of the + /// class. /// - /// Bruno Baia - [AttributeUsage(AttributeTargets.Interface, AllowMultiple = false, Inherited = false)] - [Serializable] - public sealed class ProxyIgnoreAttribute : Attribute + public ProxyIgnoreAttribute() { - /// - /// Creates a new instance of the - /// class. - /// - public ProxyIgnoreAttribute() - { - } } -} +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Proxy/TargetProxyMethodBuilder.cs b/src/Spring/Spring.Core/Proxy/TargetProxyMethodBuilder.cs index caec9016..96c60f97 100644 --- a/src/Spring/Spring.Core/Proxy/TargetProxyMethodBuilder.cs +++ b/src/Spring/Spring.Core/Proxy/TargetProxyMethodBuilder.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -25,69 +25,69 @@ using System.Reflection.Emit; #endregion -namespace Spring.Proxy +namespace Spring.Proxy; + +/// +/// Implementation of IProxyMethodBuilder that delegates method calls to target object. +/// +/// Bruno Baia +public class TargetProxyMethodBuilder : AbstractProxyMethodBuilder { + #region Constructor(s) / Destructor + /// - /// Implementation of IProxyMethodBuilder that delegates method calls to target object. + /// Creates a new instance of the method builder. /// - /// Bruno Baia - public class TargetProxyMethodBuilder : AbstractProxyMethodBuilder + /// The type builder to use. + /// + /// The implementation to use. + /// + /// + /// if the interface is to be + /// implemented explicitly; otherwise . + /// + public TargetProxyMethodBuilder( + TypeBuilder typeBuilder, IProxyTypeGenerator proxyGenerator, bool explicitImplementation) + : base(typeBuilder, proxyGenerator, explicitImplementation) { - #region Constructor(s) / Destructor - - /// - /// Creates a new instance of the method builder. - /// - /// The type builder to use. - /// - /// The implementation to use. - /// - /// - /// if the interface is to be - /// implemented explicitly; otherwise . - /// - public TargetProxyMethodBuilder( - TypeBuilder typeBuilder, IProxyTypeGenerator proxyGenerator, bool explicitImplementation) - : base(typeBuilder, proxyGenerator, explicitImplementation) - { - } - - #endregion - - #region Protected Methods - - /// - /// Generates the proxy method. - /// - /// The IL generator to use. - /// The method to proxy. - /// - /// The interface definition of the method, if applicable. - /// - protected override void GenerateMethod( - ILGenerator il, MethodInfo method, MethodInfo interfaceMethod) - { - LocalBuilder returnValue = null; - if (method.ReturnType != typeof(void)) - { - returnValue = il.DeclareLocal(method.ReturnType); - } - - CallDirectTargetMethod(il, interfaceMethod); - - // unboxing is not necessary because we called the method directly - if (returnValue != null) - { - il.Emit(OpCodes.Stloc, returnValue); - - if (!method.ReturnType.IsValueType) - { - ProcessReturnValue(il, returnValue); - } - il.Emit(OpCodes.Ldloc, returnValue); - } - } - - #endregion } + + #endregion + + #region Protected Methods + + /// + /// Generates the proxy method. + /// + /// The IL generator to use. + /// The method to proxy. + /// + /// The interface definition of the method, if applicable. + /// + protected override void GenerateMethod( + ILGenerator il, MethodInfo method, MethodInfo interfaceMethod) + { + LocalBuilder returnValue = null; + if (method.ReturnType != typeof(void)) + { + returnValue = il.DeclareLocal(method.ReturnType); + } + + CallDirectTargetMethod(il, interfaceMethod); + + // unboxing is not necessary because we called the method directly + if (returnValue != null) + { + il.Emit(OpCodes.Stloc, returnValue); + + if (!method.ReturnType.IsValueType) + { + ProcessReturnValue(il, returnValue); + } + + il.Emit(OpCodes.Ldloc, returnValue); + } + } + + #endregion } diff --git a/src/Spring/Spring.Core/Reflection/Dynamic/BaseDynamicMember.cs b/src/Spring/Spring.Core/Reflection/Dynamic/BaseDynamicMember.cs index f0dea422..6c6b6d61 100644 --- a/src/Spring/Spring.Core/Reflection/Dynamic/BaseDynamicMember.cs +++ b/src/Spring/Spring.Core/Reflection/Dynamic/BaseDynamicMember.cs @@ -21,114 +21,113 @@ using System.Reflection; using System.Reflection.Emit; -namespace Spring.Reflection.Dynamic +namespace Spring.Reflection.Dynamic; + +/// +/// Base class for dynamic members. +/// +/// Aleksandar Seovic +public class BaseDynamicMember { /// - /// Base class for dynamic members. + /// Method attributes constant. /// - /// Aleksandar Seovic - public class BaseDynamicMember + protected const MethodAttributes METHOD_ATTRIBUTES = + MethodAttributes.Public | MethodAttributes.HideBySig + | MethodAttributes.NewSlot | MethodAttributes.Virtual + | MethodAttributes.Final; + + private static ConstructorInfo invalidOperationException = + typeof(InvalidOperationException).GetConstructor(new Type[] { typeof(string) }); + + /// + /// Sets up target instance for invocation. + /// + /// IL generator to use. + /// Type of target instance. + protected static void SetupTargetInstance(ILGenerator il, Type targetType) { - /// - /// Method attributes constant. - /// - protected const MethodAttributes METHOD_ATTRIBUTES = - MethodAttributes.Public | MethodAttributes.HideBySig - | MethodAttributes.NewSlot | MethodAttributes.Virtual - | MethodAttributes.Final; - - private static ConstructorInfo invalidOperationException = - typeof(InvalidOperationException).GetConstructor(new Type[] { typeof(string) }); - - /// - /// Sets up target instance for invocation. - /// - /// IL generator to use. - /// Type of target instance. - protected static void SetupTargetInstance(ILGenerator il, Type targetType) + il.Emit(OpCodes.Ldarg_1); + if (targetType.IsValueType) { - il.Emit(OpCodes.Ldarg_1); - if (targetType.IsValueType) - { - LocalBuilder target = il.DeclareLocal(targetType); - il.Emit(OpCodes.Unbox, targetType); - il.Emit(OpCodes.Ldobj, targetType); - il.Emit(OpCodes.Stloc, target); - il.Emit(OpCodes.Ldloca, target); - } - else - { - il.Emit(OpCodes.Castclass, targetType); - } + LocalBuilder target = il.DeclareLocal(targetType); + il.Emit(OpCodes.Unbox, targetType); + il.Emit(OpCodes.Ldobj, targetType); + il.Emit(OpCodes.Stloc, target); + il.Emit(OpCodes.Ldloca, target); } - - /// - /// Sets up invocation argument. - /// - /// IL generator to use. - /// Argument type. - /// Argument position. - protected static void SetupArgument(ILGenerator il, Type argumentType, int argumentPosition) + else { - il.Emit(OpCodes.Ldarg, argumentPosition); - if (argumentType.IsValueType) - { - il.Emit(OpCodes.Unbox, argumentType); - il.Emit(OpCodes.Ldobj, argumentType); - } - else - { - il.Emit(OpCodes.Castclass, argumentType); - } + il.Emit(OpCodes.Castclass, targetType); } - - /// - /// Generates method invocation code. - /// - /// IL generator to use. - /// Flag specifying whether method is static. - /// Flag specifying whether method is on the value type. - /// Method to invoke. - protected static void InvokeMethod(ILGenerator il, bool isStatic, bool isValueType, MethodInfo method) - { - if (isStatic || isValueType) - { - il.EmitCall(OpCodes.Call, method, null); - } - else - { - il.EmitCall(OpCodes.Callvirt, method, null); - } - } - - /// - /// Generates code to process return value if necessary. - /// - /// IL generator to use. - /// Type of the return value. - protected static void ProcessReturnValue(ILGenerator il, Type returnValueType) - { - if (returnValueType == typeof(void)) - { - il.Emit(OpCodes.Ldnull); - } - else if (returnValueType.IsValueType) - { - il.Emit(OpCodes.Box, returnValueType); - } - } - - /// - /// Generates code that throws . - /// - /// IL generator to use. - /// Error message to use. - protected static void ThrowInvalidOperationException(ILGenerator il, string message) - { - il.Emit(OpCodes.Ldstr, message); - il.Emit(OpCodes.Newobj, invalidOperationException); - il.Emit(OpCodes.Throw); - } -//#endif } + + /// + /// Sets up invocation argument. + /// + /// IL generator to use. + /// Argument type. + /// Argument position. + protected static void SetupArgument(ILGenerator il, Type argumentType, int argumentPosition) + { + il.Emit(OpCodes.Ldarg, argumentPosition); + if (argumentType.IsValueType) + { + il.Emit(OpCodes.Unbox, argumentType); + il.Emit(OpCodes.Ldobj, argumentType); + } + else + { + il.Emit(OpCodes.Castclass, argumentType); + } + } + + /// + /// Generates method invocation code. + /// + /// IL generator to use. + /// Flag specifying whether method is static. + /// Flag specifying whether method is on the value type. + /// Method to invoke. + protected static void InvokeMethod(ILGenerator il, bool isStatic, bool isValueType, MethodInfo method) + { + if (isStatic || isValueType) + { + il.EmitCall(OpCodes.Call, method, null); + } + else + { + il.EmitCall(OpCodes.Callvirt, method, null); + } + } + + /// + /// Generates code to process return value if necessary. + /// + /// IL generator to use. + /// Type of the return value. + protected static void ProcessReturnValue(ILGenerator il, Type returnValueType) + { + if (returnValueType == typeof(void)) + { + il.Emit(OpCodes.Ldnull); + } + else if (returnValueType.IsValueType) + { + il.Emit(OpCodes.Box, returnValueType); + } + } + + /// + /// Generates code that throws . + /// + /// IL generator to use. + /// Error message to use. + protected static void ThrowInvalidOperationException(ILGenerator il, string message) + { + il.Emit(OpCodes.Ldstr, message); + il.Emit(OpCodes.Newobj, invalidOperationException); + il.Emit(OpCodes.Throw); + } +//#endif } diff --git a/src/Spring/Spring.Core/Reflection/Dynamic/DynamicConstructor.cs b/src/Spring/Spring.Core/Reflection/Dynamic/DynamicConstructor.cs index 16763933..ea603910 100644 --- a/src/Spring/Spring.Core/Reflection/Dynamic/DynamicConstructor.cs +++ b/src/Spring/Spring.Core/Reflection/Dynamic/DynamicConstructor.cs @@ -21,112 +21,111 @@ using System.Reflection; using Spring.Util; -namespace Spring.Reflection.Dynamic +namespace Spring.Reflection.Dynamic; + +#region IDynamicConstructor interface + +/// +/// Defines constructors that dynamic constructor class has to implement. +/// +public interface IDynamicConstructor { - #region IDynamicConstructor interface + /// + /// Invokes dynamic constructor. + /// + /// + /// Constructor arguments. + /// + /// + /// A constructor value. + /// + object Invoke(object[] arguments); +} + +#endregion + +#region Safe wrapper + +/// +/// Safe wrapper for the dynamic constructor. +/// +/// +/// will attempt to use dynamic +/// constructor if possible, but it will fall back to standard +/// reflection if necessary. +/// +public class SafeConstructor : IDynamicConstructor +{ + private ConstructorInfo constructorInfo; + + #region Generated Function Cache + + private static readonly IDictionary constructorCache = new Dictionary(); /// - /// Defines constructors that dynamic constructor class has to implement. + /// Obtains cached constructor info or creates a new entry, if none is found. /// - public interface IDynamicConstructor + private static ConstructorDelegate GetOrCreateDynamicConstructor(ConstructorInfo constructorInfo) { - /// - /// Invokes dynamic constructor. - /// - /// - /// Constructor arguments. - /// - /// - /// A constructor value. - /// - object Invoke(object[] arguments); - } - - #endregion - - #region Safe wrapper - - /// - /// Safe wrapper for the dynamic constructor. - /// - /// - /// will attempt to use dynamic - /// constructor if possible, but it will fall back to standard - /// reflection if necessary. - /// - public class SafeConstructor : IDynamicConstructor - { - private ConstructorInfo constructorInfo; - - #region Generated Function Cache - - private static readonly IDictionary constructorCache = new Dictionary(); - - /// - /// Obtains cached constructor info or creates a new entry, if none is found. - /// - private static ConstructorDelegate GetOrCreateDynamicConstructor(ConstructorInfo constructorInfo) + ConstructorDelegate method; + if (!constructorCache.TryGetValue(constructorInfo, out method)) { - ConstructorDelegate method; - if (!constructorCache.TryGetValue(constructorInfo, out method)) + method = DynamicReflectionManager.CreateConstructor(constructorInfo); + lock (constructorCache) { - method = DynamicReflectionManager.CreateConstructor(constructorInfo); - lock (constructorCache) - { - constructorCache[constructorInfo] = method; - } + constructorCache[constructorInfo] = method; } - return method; } - #endregion - - private ConstructorDelegate constructor; - - /// - /// Creates a new instance of the safe constructor wrapper. - /// - /// Constructor to wrap. - public SafeConstructor(ConstructorInfo constructorInfo) - { - this.constructorInfo = constructorInfo; - this.constructor = GetOrCreateDynamicConstructor(constructorInfo); - } - - - /// - /// Invokes dynamic constructor. - /// - /// - /// Constructor arguments. - /// - /// - /// A constructor value. - /// - public object Invoke(object[] arguments) - { - return constructor(arguments); - } + return method; } #endregion - /// - /// Factory class for dynamic constructors. - /// - /// Aleksandar Seovic - public class DynamicConstructor : BaseDynamicMember - { - /// - /// Creates dynamic constructor instance for the specified . - /// - /// Constructor info to create dynamic constructor for. - /// Dynamic constructor for the specified . - public static IDynamicConstructor Create(ConstructorInfo constructorInfo) - { - AssertUtils.ArgumentNotNull(constructorInfo, "You cannot create a dynamic constructor for a null value."); + private ConstructorDelegate constructor; - return new SafeConstructor(constructorInfo); - } + /// + /// Creates a new instance of the safe constructor wrapper. + /// + /// Constructor to wrap. + public SafeConstructor(ConstructorInfo constructorInfo) + { + this.constructorInfo = constructorInfo; + this.constructor = GetOrCreateDynamicConstructor(constructorInfo); + } + + /// + /// Invokes dynamic constructor. + /// + /// + /// Constructor arguments. + /// + /// + /// A constructor value. + /// + public object Invoke(object[] arguments) + { + return constructor(arguments); } } + +#endregion + +/// +/// Factory class for dynamic constructors. +/// +/// Aleksandar Seovic +public class DynamicConstructor : BaseDynamicMember +{ + /// + /// Creates dynamic constructor instance for the specified . + /// + /// Constructor info to create dynamic constructor for. + /// Dynamic constructor for the specified . + public static IDynamicConstructor Create(ConstructorInfo constructorInfo) + { + AssertUtils.ArgumentNotNull(constructorInfo, "You cannot create a dynamic constructor for a null value."); + + return new SafeConstructor(constructorInfo); + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Reflection/Dynamic/DynamicField.cs b/src/Spring/Spring.Core/Reflection/Dynamic/DynamicField.cs index 6e01e1b1..f87ea047 100644 --- a/src/Spring/Spring.Core/Reflection/Dynamic/DynamicField.cs +++ b/src/Spring/Spring.Core/Reflection/Dynamic/DynamicField.cs @@ -21,162 +21,162 @@ using System.Reflection; using Spring.Util; -namespace Spring.Reflection.Dynamic +namespace Spring.Reflection.Dynamic; + +#region IDynamicField interface + +/// +/// Defines methods that dynamic field class has to implement. +/// +public interface IDynamicField { - #region IDynamicField interface + /// + /// Gets the value of the dynamic field for the specified target object. + /// + /// + /// Target object to get field value from. + /// + /// + /// A field value. + /// + object GetValue(object target); /// - /// Defines methods that dynamic field class has to implement. + /// Gets the value of the dynamic field for the specified target object. /// - public interface IDynamicField - { - /// - /// Gets the value of the dynamic field for the specified target object. - /// - /// - /// Target object to get field value from. - /// - /// - /// A field value. - /// - object GetValue(object target); + /// + /// Target object to set field value on. + /// + /// + /// A new field value. + /// + void SetValue(object target, object value); +} - /// - /// Gets the value of the dynamic field for the specified target object. - /// - /// - /// Target object to set field value on. - /// - /// - /// A new field value. - /// - void SetValue(object target, object value); +#endregion + +#region Safe wrapper + +/// +/// Safe wrapper for the dynamic field. +/// +/// +/// will attempt to use dynamic +/// field if possible, but it will fall back to standard +/// reflection if necessary. +/// +public class SafeField : IDynamicField +{ + private readonly FieldInfo fieldInfo; + + #region Cache + + private static readonly IDictionary fieldCache = new Dictionary(); + + /// + /// Holds cached Getter/Setter delegates for a Field + /// + private class DynamicFieldCacheEntry + { + public readonly FieldGetterDelegate Getter; + public readonly FieldSetterDelegate Setter; + + public DynamicFieldCacheEntry(FieldGetterDelegate getter, FieldSetterDelegate setter) + { + Getter = getter; + Setter = setter; + } + } + + /// + /// Obtains cached fieldInfo or creates a new entry, if none is found. + /// + private static DynamicFieldCacheEntry GetOrCreateDynamicField(FieldInfo field) + { + DynamicFieldCacheEntry fieldInfo; + if (!fieldCache.TryGetValue(field, out fieldInfo)) + { + fieldInfo = new DynamicFieldCacheEntry(DynamicReflectionManager.CreateFieldGetter(field), DynamicReflectionManager.CreateFieldSetter(field)); + lock (fieldCache) + { + fieldCache[field] = fieldInfo; + } + } + + return fieldInfo; } #endregion - #region Safe wrapper + private readonly FieldGetterDelegate getter; + private readonly FieldSetterDelegate setter; /// - /// Safe wrapper for the dynamic field. + /// Creates a new instance of the safe field wrapper. /// - /// - /// will attempt to use dynamic - /// field if possible, but it will fall back to standard - /// reflection if necessary. - /// - public class SafeField : IDynamicField + /// Field to wrap. + public SafeField(FieldInfo field) { - private readonly FieldInfo fieldInfo; + AssertUtils.ArgumentNotNull(field, "You cannot create a dynamic field for a null value."); - #region Cache - - private static readonly IDictionary fieldCache = new Dictionary(); - - /// - /// Holds cached Getter/Setter delegates for a Field - /// - private class DynamicFieldCacheEntry - { - public readonly FieldGetterDelegate Getter; - public readonly FieldSetterDelegate Setter; - - public DynamicFieldCacheEntry(FieldGetterDelegate getter, FieldSetterDelegate setter) - { - Getter = getter; - Setter = setter; - } - } - - /// - /// Obtains cached fieldInfo or creates a new entry, if none is found. - /// - private static DynamicFieldCacheEntry GetOrCreateDynamicField(FieldInfo field) - { - DynamicFieldCacheEntry fieldInfo; - if (!fieldCache.TryGetValue(field, out fieldInfo)) - { - fieldInfo = new DynamicFieldCacheEntry(DynamicReflectionManager.CreateFieldGetter(field), DynamicReflectionManager.CreateFieldSetter(field)); - lock (fieldCache) - { - fieldCache[field] = fieldInfo; - } - } - return fieldInfo; - } - - #endregion - - private readonly FieldGetterDelegate getter; - private readonly FieldSetterDelegate setter; - - /// - /// Creates a new instance of the safe field wrapper. - /// - /// Field to wrap. - public SafeField(FieldInfo field) - { - AssertUtils.ArgumentNotNull(field, "You cannot create a dynamic field for a null value."); - - fieldInfo = field; - DynamicFieldCacheEntry fi = GetOrCreateDynamicField(field); - getter = fi.Getter; - setter = fi.Setter; - } - - /// - /// Gets the value of the dynamic field for the specified target object. - /// - /// - /// Target object to get field value from. - /// - /// - /// A field value. - /// - public object GetValue(object target) - { - return getter(target); - } - - /// - /// Gets the value of the dynamic field for the specified target object. - /// - /// - /// Target object to set field value on. - /// - /// - /// A new field value. - /// - public void SetValue(object target, object value) - { - setter(target, value); - } - - internal FieldInfo FieldInfo - { - get { return fieldInfo; } - } + fieldInfo = field; + DynamicFieldCacheEntry fi = GetOrCreateDynamicField(field); + getter = fi.Getter; + setter = fi.Setter; } - #endregion + /// + /// Gets the value of the dynamic field for the specified target object. + /// + /// + /// Target object to get field value from. + /// + /// + /// A field value. + /// + public object GetValue(object target) + { + return getter(target); + } /// - /// Factory class for dynamic fields. + /// Gets the value of the dynamic field for the specified target object. /// - /// Aleksandar Seovic - public class DynamicField : BaseDynamicMember + /// + /// Target object to set field value on. + /// + /// + /// A new field value. + /// + public void SetValue(object target, object value) { - /// - /// Creates dynamic field instance for the specified . - /// - /// Field info to create dynamic field for. - /// Dynamic field for the specified . - public static IDynamicField Create(FieldInfo field) - { - AssertUtils.ArgumentNotNull(field, "You cannot create a dynamic field for a null value."); + setter(target, value); + } - IDynamicField dynamicField = new SafeField(field); - return dynamicField; - } + internal FieldInfo FieldInfo + { + get { return fieldInfo; } + } +} + +#endregion + +/// +/// Factory class for dynamic fields. +/// +/// Aleksandar Seovic +public class DynamicField : BaseDynamicMember +{ + /// + /// Creates dynamic field instance for the specified . + /// + /// Field info to create dynamic field for. + /// Dynamic field for the specified . + public static IDynamicField Create(FieldInfo field) + { + AssertUtils.ArgumentNotNull(field, "You cannot create a dynamic field for a null value."); + + IDynamicField dynamicField = new SafeField(field); + return dynamicField; } } diff --git a/src/Spring/Spring.Core/Reflection/Dynamic/DynamicIndexer.cs b/src/Spring/Spring.Core/Reflection/Dynamic/DynamicIndexer.cs index 8668149b..9b68d27c 100644 --- a/src/Spring/Spring.Core/Reflection/Dynamic/DynamicIndexer.cs +++ b/src/Spring/Spring.Core/Reflection/Dynamic/DynamicIndexer.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -18,95 +18,94 @@ #endregion -namespace Spring.Reflection.Dynamic +namespace Spring.Reflection.Dynamic; + +/// +/// Defines methods that dynamic indexer class has to implement. +/// +public interface IDynamicIndexer { /// - /// Defines methods that dynamic indexer class has to implement. + /// Gets the value of the dynamic indexer for the specified target object. /// - public interface IDynamicIndexer - { - /// - /// Gets the value of the dynamic indexer for the specified target object. - /// - /// - /// Target object to get the indexer value from. - /// - /// - /// Indexer argument. - /// - /// - /// A indexer value. - /// - object GetValue( object target, int index ); + /// + /// Target object to get the indexer value from. + /// + /// + /// Indexer argument. + /// + /// + /// A indexer value. + /// + object GetValue(object target, int index); - /// - /// Gets the value of the dynamic indexer for the specified target object. - /// - /// - /// Target object to get the indexer value from. - /// - /// - /// Indexer argument. - /// - /// - /// A indexer value. - /// - object GetValue( object target, object index ); + /// + /// Gets the value of the dynamic indexer for the specified target object. + /// + /// + /// Target object to get the indexer value from. + /// + /// + /// Indexer argument. + /// + /// + /// A indexer value. + /// + object GetValue(object target, object index); - /// - /// Gets the value of the dynamic indexer for the specified target object. - /// - /// - /// Target object to get the indexer value from. - /// - /// - /// Indexer arguments. - /// - /// - /// A indexer value. - /// - object GetValue( object target, object[] index ); + /// + /// Gets the value of the dynamic indexer for the specified target object. + /// + /// + /// Target object to get the indexer value from. + /// + /// + /// Indexer arguments. + /// + /// + /// A indexer value. + /// + object GetValue(object target, object[] index); - /// - /// Gets the value of the dynamic indexer for the specified target object. - /// - /// - /// Target object to set the indexer value on. - /// - /// - /// Indexer argument. - /// - /// - /// A new indexer value. - /// - void SetValue( object target, int index, object value ); + /// + /// Gets the value of the dynamic indexer for the specified target object. + /// + /// + /// Target object to set the indexer value on. + /// + /// + /// Indexer argument. + /// + /// + /// A new indexer value. + /// + void SetValue(object target, int index, object value); - /// - /// Gets the value of the dynamic indexer for the specified target object. - /// - /// - /// Target object to set the indexer value on. - /// - /// - /// Indexer argument. - /// - /// - /// A new indexer value. - /// - void SetValue( object target, object index, object value ); + /// + /// Gets the value of the dynamic indexer for the specified target object. + /// + /// + /// Target object to set the indexer value on. + /// + /// + /// Indexer argument. + /// + /// + /// A new indexer value. + /// + void SetValue(object target, object index, object value); - /// - /// Gets the value of the dynamic indexer for the specified target object. - /// - /// - /// Target object to set the indexer value on. - /// - /// - /// Indexer arguments. - /// - /// - /// A new indexer value. - /// - void SetValue( object target, object[] index, object value ); - } + /// + /// Gets the value of the dynamic indexer for the specified target object. + /// + /// + /// Target object to set the indexer value on. + /// + /// + /// Indexer arguments. + /// + /// + /// A new indexer value. + /// + void SetValue(object target, object[] index, object value); } diff --git a/src/Spring/Spring.Core/Reflection/Dynamic/DynamicMethod.cs b/src/Spring/Spring.Core/Reflection/Dynamic/DynamicMethod.cs index 6977ad0c..18733eda 100644 --- a/src/Spring/Spring.Core/Reflection/Dynamic/DynamicMethod.cs +++ b/src/Spring/Spring.Core/Reflection/Dynamic/DynamicMethod.cs @@ -22,165 +22,165 @@ using System.Collections; using System.Reflection; using Spring.Util; -namespace Spring.Reflection.Dynamic +namespace Spring.Reflection.Dynamic; + +#region IDynamicMethod interface + +/// +/// Defines methods that dynamic method class has to implement. +/// +public interface IDynamicMethod { - #region IDynamicMethod interface + /// + /// Invokes dynamic method on the specified target object. + /// + /// + /// Target object to invoke method on. + /// + /// + /// Method arguments. + /// + /// + /// A method return value. + /// + object Invoke(object target, params object[] arguments); +} + +#endregion + +#region Safe wrapper + +/// +/// Safe wrapper for the dynamic method. +/// +/// +/// will attempt to use dynamic +/// method if possible, but it will fall back to standard +/// reflection if necessary. +/// +public class SafeMethod : IDynamicMethod +{ + private readonly MethodInfo methodInfo; /// - /// Defines methods that dynamic method class has to implement. + /// Gets the class, that declares this method /// - public interface IDynamicMethod + public Type DeclaringType { - /// - /// Invokes dynamic method on the specified target object. - /// - /// - /// Target object to invoke method on. - /// - /// - /// Method arguments. - /// - /// - /// A method return value. - /// - object Invoke(object target, params object[] arguments); + get { return methodInfo.DeclaringType; } } + #region Generated Function Cache + + private class SafeMethodState + { + public readonly FunctionDelegate method; + public readonly object[] nullArguments; + + public SafeMethodState(FunctionDelegate method, object[] nullArguments) + { + this.method = method; + this.nullArguments = nullArguments; + } + } + + private class IdentityTable : Hashtable + { + public IdentityTable() + { + } + + protected override int GetHash(object key) + { + return key.GetHashCode(); + } + + protected override bool KeyEquals(object item, object key) + { + return ReferenceEquals(item, key); + } + } + + private static readonly Hashtable stateCache = new IdentityTable(); + #endregion - #region Safe wrapper + private readonly SafeMethodState state; /// - /// Safe wrapper for the dynamic method. + /// Creates a new instance of the safe method wrapper. /// - /// - /// will attempt to use dynamic - /// method if possible, but it will fall back to standard - /// reflection if necessary. - /// - public class SafeMethod : IDynamicMethod + /// Method to wrap. + public SafeMethod(MethodInfo methodInfo) { - private readonly MethodInfo methodInfo; + AssertUtils.ArgumentNotNull(methodInfo, "You cannot create a dynamic method for a null value."); - /// - /// Gets the class, that declares this method - /// - public Type DeclaringType + state = (SafeMethodState) stateCache[methodInfo]; + if (state == null) { - get { return methodInfo.DeclaringType; } - } - - #region Generated Function Cache - - private class SafeMethodState - { - public readonly FunctionDelegate method; - public readonly object[] nullArguments; - - public SafeMethodState(FunctionDelegate method, object[] nullArguments) - { - this.method = method; - this.nullArguments = nullArguments; - } - } - - private class IdentityTable : Hashtable - { - public IdentityTable() - { } - - protected override int GetHash(object key) - { - return key.GetHashCode(); - } - - protected override bool KeyEquals(object item, object key) - { - return ReferenceEquals(item, key); - } - } - - private static readonly Hashtable stateCache = new IdentityTable(); - - #endregion - - private readonly SafeMethodState state; - - /// - /// Creates a new instance of the safe method wrapper. - /// - /// Method to wrap. - public SafeMethod(MethodInfo methodInfo) - { - AssertUtils.ArgumentNotNull(methodInfo, "You cannot create a dynamic method for a null value."); - - state = (SafeMethodState)stateCache[methodInfo]; - if (state == null) - { - SafeMethodState newState = new SafeMethodState(DynamicReflectionManager.CreateMethod(methodInfo), + SafeMethodState newState = new SafeMethodState(DynamicReflectionManager.CreateMethod(methodInfo), new object[methodInfo.GetParameters().Length] - ); + ); - lock (stateCache.SyncRoot) + lock (stateCache.SyncRoot) + { + state = (SafeMethodState) stateCache[methodInfo]; + if (state == null) { - state = (SafeMethodState)stateCache[methodInfo]; - if (state == null) - { - state = newState; - stateCache[methodInfo] = state; - } + state = newState; + stateCache[methodInfo] = state; } } - - this.methodInfo = methodInfo; } - /// - /// Invokes dynamic method. - /// - /// - /// Target object to invoke method on. - /// - /// - /// Method arguments. - /// - /// - /// A method return value. - /// - public object Invoke(object target, params object[] arguments) - { - // special case - when calling Invoke(null,null) it is undecidible if the second null is an argument or the argument array - object[] nullArguments = state.nullArguments; - if (arguments == null && nullArguments.Length == 1) arguments = nullArguments; - int arglen = (arguments == null ? 0 : arguments.Length); - if (nullArguments.Length != arglen) - { - throw new ArgumentException(string.Format("Invalid number of arguments passed into method {0} - expected {1}, but was {2}", methodInfo.Name, nullArguments.Length, arglen)); - } - - return this.state.method(target, arguments); - } + this.methodInfo = methodInfo; } - #endregion - /// - /// Factory class for dynamic methods. + /// Invokes dynamic method. /// - /// Aleksandar Seovic - public class DynamicMethod : BaseDynamicMember + /// + /// Target object to invoke method on. + /// + /// + /// Method arguments. + /// + /// + /// A method return value. + /// + public object Invoke(object target, params object[] arguments) { - /// - /// Creates dynamic method instance for the specified . - /// - /// Method info to create dynamic method for. - /// Dynamic method for the specified . - public static IDynamicMethod Create(MethodInfo method) + // special case - when calling Invoke(null,null) it is undecidible if the second null is an argument or the argument array + object[] nullArguments = state.nullArguments; + if (arguments == null && nullArguments.Length == 1) arguments = nullArguments; + int arglen = (arguments == null ? 0 : arguments.Length); + if (nullArguments.Length != arglen) { - AssertUtils.ArgumentNotNull(method, "You cannot create a dynamic method for a null value."); - - IDynamicMethod dynamicMethod = new SafeMethod(method); - return dynamicMethod; + throw new ArgumentException(string.Format("Invalid number of arguments passed into method {0} - expected {1}, but was {2}", methodInfo.Name, nullArguments.Length, arglen)); } + + return this.state.method(target, arguments); + } +} + +#endregion + +/// +/// Factory class for dynamic methods. +/// +/// Aleksandar Seovic +public class DynamicMethod : BaseDynamicMember +{ + /// + /// Creates dynamic method instance for the specified . + /// + /// Method info to create dynamic method for. + /// Dynamic method for the specified . + public static IDynamicMethod Create(MethodInfo method) + { + AssertUtils.ArgumentNotNull(method, "You cannot create a dynamic method for a null value."); + + IDynamicMethod dynamicMethod = new SafeMethod(method); + return dynamicMethod; } } diff --git a/src/Spring/Spring.Core/Reflection/Dynamic/DynamicProperty.cs b/src/Spring/Spring.Core/Reflection/Dynamic/DynamicProperty.cs index 3ecf62a1..da771c2d 100644 --- a/src/Spring/Spring.Core/Reflection/Dynamic/DynamicProperty.cs +++ b/src/Spring/Spring.Core/Reflection/Dynamic/DynamicProperty.cs @@ -21,235 +21,235 @@ using System.Reflection; using Spring.Util; -namespace Spring.Reflection.Dynamic +namespace Spring.Reflection.Dynamic; + +#region IDynamicProperty interface + +/// +/// Defines methods that dynamic property class has to implement. +/// +public interface IDynamicProperty { - #region IDynamicProperty interface + /// + /// Gets the value of the dynamic property for the specified target object. + /// + /// + /// Target object to get property value from. + /// + /// + /// A property value. + /// + object GetValue(object target); /// - /// Defines methods that dynamic property class has to implement. + /// Gets the value of the dynamic property for the specified target object. /// - public interface IDynamicProperty + /// + /// Target object to set property value on. + /// + /// + /// A new property value. + /// + void SetValue(object target, object value); + + /// + /// Gets the value of the dynamic property for the specified target object. + /// + /// + /// Target object to get property value from. + /// + /// Optional index values for indexed properties. This value should be null reference for non-indexed properties. + /// + /// A property value. + /// + object GetValue(object target, params object[] index); + + /// + /// Gets the value of the dynamic property for the specified target object. + /// + /// + /// Target object to set property value on. + /// + /// + /// A new property value. + /// + /// Optional index values for indexed properties. This value should be null reference for non-indexed properties. + void SetValue(object target, object value, params object[] index); +} + +#endregion + +#region Safe wrapper + +/// +/// Safe wrapper for the dynamic property. +/// +/// +/// will attempt to use dynamic +/// property if possible, but it will fall back to standard +/// reflection if necessary. +/// +public class SafeProperty : IDynamicProperty +{ + private readonly PropertyInfo propertyInfo; + + #region Cache + + private static readonly IDictionary propertyCache = new Dictionary(); + + /// + /// Holds cached Getter/Setter delegates for a Property + /// + private class DynamicPropertyCacheEntry { - /// - /// Gets the value of the dynamic property for the specified target object. - /// - /// - /// Target object to get property value from. - /// - /// - /// A property value. - /// - object GetValue(object target); + public readonly PropertyGetterDelegate Getter; + public readonly PropertySetterDelegate Setter; - /// - /// Gets the value of the dynamic property for the specified target object. - /// - /// - /// Target object to set property value on. - /// - /// - /// A new property value. - /// - void SetValue(object target, object value); + public DynamicPropertyCacheEntry(PropertyGetterDelegate getter, PropertySetterDelegate setter) + { + Getter = getter; + Setter = setter; + } + } - /// - /// Gets the value of the dynamic property for the specified target object. - /// - /// - /// Target object to get property value from. - /// - /// Optional index values for indexed properties. This value should be null reference for non-indexed properties. - /// - /// A property value. - /// - object GetValue(object target, params object[] index); + /// + /// Obtains cached property info or creates a new entry, if none is found. + /// + private static DynamicPropertyCacheEntry GetOrCreateDynamicProperty(PropertyInfo property) + { + DynamicPropertyCacheEntry propertyInfo; + if (!propertyCache.TryGetValue(property, out propertyInfo)) + { + propertyInfo = new DynamicPropertyCacheEntry(DynamicReflectionManager.CreatePropertyGetter(property), DynamicReflectionManager.CreatePropertySetter(property)); + lock (propertyCache) + { + propertyCache[property] = propertyInfo; + } + } - /// - /// Gets the value of the dynamic property for the specified target object. - /// - /// - /// Target object to set property value on. - /// - /// - /// A new property value. - /// - /// Optional index values for indexed properties. This value should be null reference for non-indexed properties. - void SetValue(object target, object value, params object[] index); + return propertyInfo; } #endregion - #region Safe wrapper + private readonly PropertyGetterDelegate getter; + private readonly PropertySetterDelegate setter; /// - /// Safe wrapper for the dynamic property. + /// Creates a new instance of the safe property wrapper. /// - /// - /// will attempt to use dynamic - /// property if possible, but it will fall back to standard - /// reflection if necessary. - /// - public class SafeProperty : IDynamicProperty + /// Property to wrap. + public SafeProperty(PropertyInfo propertyInfo) { - private readonly PropertyInfo propertyInfo; + AssertUtils.ArgumentNotNull(propertyInfo, "You cannot create a dynamic property for a null value."); - #region Cache - - private static readonly IDictionary propertyCache = new Dictionary(); - - /// - /// Holds cached Getter/Setter delegates for a Property - /// - private class DynamicPropertyCacheEntry - { - public readonly PropertyGetterDelegate Getter; - public readonly PropertySetterDelegate Setter; - - public DynamicPropertyCacheEntry(PropertyGetterDelegate getter, PropertySetterDelegate setter) - { - Getter = getter; - Setter = setter; - } - } - - /// - /// Obtains cached property info or creates a new entry, if none is found. - /// - private static DynamicPropertyCacheEntry GetOrCreateDynamicProperty(PropertyInfo property) - { - DynamicPropertyCacheEntry propertyInfo; - if (!propertyCache.TryGetValue(property, out propertyInfo)) - { - propertyInfo = new DynamicPropertyCacheEntry(DynamicReflectionManager.CreatePropertyGetter(property), DynamicReflectionManager.CreatePropertySetter(property)); - lock (propertyCache) - { - propertyCache[property] = propertyInfo; - } - } - return propertyInfo; - } - - #endregion - - private readonly PropertyGetterDelegate getter; - private readonly PropertySetterDelegate setter; - - /// - /// Creates a new instance of the safe property wrapper. - /// - /// Property to wrap. - public SafeProperty(PropertyInfo propertyInfo) - { - AssertUtils.ArgumentNotNull(propertyInfo, "You cannot create a dynamic property for a null value."); - - this.propertyInfo = propertyInfo; - DynamicPropertyCacheEntry pi = GetOrCreateDynamicProperty(propertyInfo); - getter = pi.Getter; - setter = pi.Setter; - } - - /// - /// Gets the value of the dynamic property for the specified target object. - /// - /// - /// Target object to get property value from. - /// - /// - /// A property value. - /// - public object GetValue(object target) - { - return getter(target); - } - - /// - /// Gets the value of the dynamic property for the specified target object. - /// - /// - /// Target object to get property value from. - /// - /// Optional index values for indexed properties. This value should be null reference for non-indexed properties. - /// - /// A property value. - /// - public object GetValue(object target, params object[] index) - { - return getter(target, index); - } - - /// - /// Gets the value of the dynamic property for the specified target object. - /// - /// - /// Target object to set property value on. - /// - /// - /// A new property value. - /// - public void SetValue(object target, object value) - { - setter(target, value); - } - - /// - /// Gets the value of the dynamic property for the specified target object. - /// - /// - /// Target object to set property value on. - /// - /// - /// A new property value. - /// - /// Optional index values for indexed properties. This value should be null reference for non-indexed properties. - public void SetValue(object target, object value, params object[] index) - { - setter(target, value, index); - } - - /// - /// Internal PropertyInfo accessor. - /// - internal PropertyInfo PropertyInfo - { - get { return propertyInfo; } - } + this.propertyInfo = propertyInfo; + DynamicPropertyCacheEntry pi = GetOrCreateDynamicProperty(propertyInfo); + getter = pi.Getter; + setter = pi.Setter; } - #endregion + /// + /// Gets the value of the dynamic property for the specified target object. + /// + /// + /// Target object to get property value from. + /// + /// + /// A property value. + /// + public object GetValue(object target) + { + return getter(target); + } /// - /// Factory class for dynamic properties. + /// Gets the value of the dynamic property for the specified target object. /// - /// Aleksandar Seovic - public class DynamicProperty : BaseDynamicMember + /// + /// Target object to get property value from. + /// + /// Optional index values for indexed properties. This value should be null reference for non-indexed properties. + /// + /// A property value. + /// + public object GetValue(object target, params object[] index) { - /// - /// Creates safe dynamic property instance for the specified . - /// - /// - ///

This factory method will create a dynamic property with a "safe" wrapper.

- ///

Safe wrapper will attempt to use generated dynamic property if possible, - /// but it will fall back to standard reflection if necessary.

- ///
- /// Property info to create dynamic property for. - /// Safe dynamic property for the specified . - /// - public static IDynamicProperty CreateSafe(PropertyInfo property) - { - return new SafeProperty(property); - } + return getter(target, index); + } - /// - /// Creates dynamic property instance for the specified . - /// - /// Property info to create dynamic property for. - /// Dynamic property for the specified . - public static IDynamicProperty Create(PropertyInfo property) - { - AssertUtils.ArgumentNotNull(property, "You cannot create a dynamic property for a null value."); + /// + /// Gets the value of the dynamic property for the specified target object. + /// + /// + /// Target object to set property value on. + /// + /// + /// A new property value. + /// + public void SetValue(object target, object value) + { + setter(target, value); + } - IDynamicProperty dynamicProperty = new SafeProperty(property); - return dynamicProperty; - } + /// + /// Gets the value of the dynamic property for the specified target object. + /// + /// + /// Target object to set property value on. + /// + /// + /// A new property value. + /// + /// Optional index values for indexed properties. This value should be null reference for non-indexed properties. + public void SetValue(object target, object value, params object[] index) + { + setter(target, value, index); + } + + /// + /// Internal PropertyInfo accessor. + /// + internal PropertyInfo PropertyInfo + { + get { return propertyInfo; } + } +} + +#endregion + +/// +/// Factory class for dynamic properties. +/// +/// Aleksandar Seovic +public class DynamicProperty : BaseDynamicMember +{ + /// + /// Creates safe dynamic property instance for the specified . + /// + /// + ///

This factory method will create a dynamic property with a "safe" wrapper.

+ ///

Safe wrapper will attempt to use generated dynamic property if possible, + /// but it will fall back to standard reflection if necessary.

+ ///
+ /// Property info to create dynamic property for. + /// Safe dynamic property for the specified . + /// + public static IDynamicProperty CreateSafe(PropertyInfo property) + { + return new SafeProperty(property); + } + + /// + /// Creates dynamic property instance for the specified . + /// + /// Property info to create dynamic property for. + /// Dynamic property for the specified . + public static IDynamicProperty Create(PropertyInfo property) + { + AssertUtils.ArgumentNotNull(property, "You cannot create a dynamic property for a null value."); + + IDynamicProperty dynamicProperty = new SafeProperty(property); + return dynamicProperty; } } diff --git a/src/Spring/Spring.Core/Reflection/Dynamic/DynamicReflectionManager.cs b/src/Spring/Spring.Core/Reflection/Dynamic/DynamicReflectionManager.cs index 230e732a..a9db06af 100644 --- a/src/Spring/Spring.Core/Reflection/Dynamic/DynamicReflectionManager.cs +++ b/src/Spring/Spring.Core/Reflection/Dynamic/DynamicReflectionManager.cs @@ -24,441 +24,406 @@ using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Security; using Spring.Util; - using NetDynamicMethod = System.Reflection.Emit.DynamicMethod; -namespace Spring.Reflection.Dynamic +namespace Spring.Reflection.Dynamic; + +/// +/// Represents a Get method +/// +/// the target instance when calling an instance method +/// the value return by the Get method +public delegate object FieldGetterDelegate(object target); + +/// +/// Represents a Set method +/// +/// the target instance when calling an instance method +/// the value to be set +public delegate void FieldSetterDelegate(object target, object value); + +/// +/// Represents an Indexer Get method +/// +/// the target instance when calling an instance method +/// +/// the value return by the Get method +public delegate object PropertyGetterDelegate(object target, params object[] index); + +/// +/// Represents a Set method +/// +/// the target instance when calling an instance method +/// the value to be set +/// +public delegate void PropertySetterDelegate(object target, object value, params object[] index); + +/// +/// Represents a method +/// +/// the target instance when calling an instance method +/// arguments to be passed to the method +/// the value return by the method. null when calling a void method +public delegate object FunctionDelegate(object target, params object[] args); + +/// +/// Represents a constructor +/// +/// arguments to be passed to the method +/// the new object instance +public delegate object ConstructorDelegate(params object[] args); + +/// +/// Allows easy access to existing and creation of new dynamic relection members. +/// +/// Aleksandar Seovic +public sealed class DynamicReflectionManager { /// - /// Represents a Get method + /// Create a new Get method delegate for the specified field using /// - /// the target instance when calling an instance method - /// the value return by the Get method - public delegate object FieldGetterDelegate(object target); - - /// - /// Represents a Set method - /// - /// the target instance when calling an instance method - /// the value to be set - public delegate void FieldSetterDelegate(object target, object value); - - /// - /// Represents an Indexer Get method - /// - /// the target instance when calling an instance method - /// - /// the value return by the Get method - public delegate object PropertyGetterDelegate(object target, params object[] index); - - /// - /// Represents a Set method - /// - /// the target instance when calling an instance method - /// the value to be set - /// - public delegate void PropertySetterDelegate(object target, object value, params object[] index); - - /// - /// Represents a method - /// - /// the target instance when calling an instance method - /// arguments to be passed to the method - /// the value return by the method. null when calling a void method - public delegate object FunctionDelegate(object target, params object[] args); - - /// - /// Represents a constructor - /// - /// arguments to be passed to the method - /// the new object instance - public delegate object ConstructorDelegate(params object[] args); - - /// - /// Allows easy access to existing and creation of new dynamic relection members. - /// - /// Aleksandar Seovic - public sealed class DynamicReflectionManager + /// the field to create the delegate for + /// a delegate that can be used to read the field + public static FieldGetterDelegate CreateFieldGetter(FieldInfo fieldInfo) { - /// - /// Create a new Get method delegate for the specified field using - /// - /// the field to create the delegate for - /// a delegate that can be used to read the field - public static FieldGetterDelegate CreateFieldGetter(FieldInfo fieldInfo) + AssertUtils.ArgumentNotNull(fieldInfo, "You cannot create a delegate for a null value."); + + bool skipVisibility = true; //!IsPublic(fieldInfo); + Type[] argumentTypes = new Type[] { typeof(object) }; + System.Reflection.Emit.DynamicMethod dmGetter = CreateDynamicMethod("get_" + fieldInfo.Name, typeof(object), argumentTypes, fieldInfo, skipVisibility); + ILGenerator il = dmGetter.GetILGenerator(); + EmitFieldGetter(il, fieldInfo, false); + return (FieldGetterDelegate) dmGetter.CreateDelegate(typeof(FieldGetterDelegate)); + } + + /// + /// Create a new Set method delegate for the specified field using + /// + /// the field to create the delegate for + /// a delegate that can be used to read the field. + /// + /// If the field's returns true, the returned method + /// will throw an when called. + /// + public static FieldSetterDelegate CreateFieldSetter(FieldInfo fieldInfo) + { + AssertUtils.ArgumentNotNull(fieldInfo, "You cannot create a delegate for a null value."); + + bool skipVisibility = true; // !IsPublic(fieldInfo); + System.Reflection.Emit.DynamicMethod dmSetter = CreateDynamicMethod("set_" + fieldInfo.Name, null, new Type[] { typeof(object), typeof(object) }, fieldInfo, skipVisibility); + ILGenerator il = dmSetter.GetILGenerator(); + EmitFieldSetter(il, fieldInfo, false); + return (FieldSetterDelegate) dmSetter.CreateDelegate(typeof(FieldSetterDelegate)); + } + + /// + /// Create a new Get method delegate for the specified property using + /// + /// the property to create the delegate for + /// a delegate that can be used to read the property. + /// + /// If the property's returns false, the returned method + /// will throw an when called. + /// + public static PropertyGetterDelegate CreatePropertyGetter(PropertyInfo propertyInfo) + { + AssertUtils.ArgumentNotNull(propertyInfo, "You cannot create a delegate for a null value."); + + MethodInfo getMethod = propertyInfo.GetGetMethod(); + bool skipVisibility = true; // (null == getMethod || !IsPublic(getMethod)); // getter is public + NetDynamicMethod dm = CreateDynamicMethod("get_" + propertyInfo.Name, typeof(object), new Type[] { typeof(object), typeof(object[]) }, propertyInfo, skipVisibility); + ILGenerator il = dm.GetILGenerator(); + EmitPropertyGetter(il, propertyInfo, false); + return (PropertyGetterDelegate) dm.CreateDelegate(typeof(PropertyGetterDelegate)); + } + + /// + /// Create a new Set method delegate for the specified property using + /// + /// the property to create the delegate for + /// a delegate that can be used to write the property. + /// + /// If the property's returns false, the returned method + /// will throw an when called. + /// + public static PropertySetterDelegate CreatePropertySetter(PropertyInfo propertyInfo) + { + AssertUtils.ArgumentNotNull(propertyInfo, "You cannot create a delegate for a null value."); + + MethodInfo setMethod = propertyInfo.GetSetMethod(); + bool skipVisibility = true; // (null == setMethod || !IsPublic(setMethod)); // setter is public + Type[] argumentTypes = new Type[] { typeof(object), typeof(object), typeof(object[]) }; + NetDynamicMethod dm = CreateDynamicMethod("set_" + propertyInfo.Name, null, argumentTypes, propertyInfo, skipVisibility); + ILGenerator il = dm.GetILGenerator(); + EmitPropertySetter(il, propertyInfo, false); + return (PropertySetterDelegate) dm.CreateDelegate(typeof(PropertySetterDelegate)); + } + + /// + /// Create a new method delegate for the specified method using + /// + /// the method to create the delegate for + /// a delegate that can be used to invoke the method. + public static FunctionDelegate CreateMethod(MethodInfo methodInfo) + { + AssertUtils.ArgumentNotNull(methodInfo, "You cannot create a delegate for a null value."); + + bool skipVisibility = true; // !IsPublic(methodInfo); + NetDynamicMethod dm = CreateDynamicMethod(methodInfo.Name, typeof(object), new Type[] { typeof(object), typeof(object[]) }, methodInfo, skipVisibility); + ILGenerator il = dm.GetILGenerator(); + EmitInvokeMethod(il, methodInfo, false); + return (FunctionDelegate) dm.CreateDelegate(typeof(FunctionDelegate)); + } + + /// + /// Creates a new delegate for the specified constructor. + /// + ///the constructor to create the delegate for + ///delegate that can be used to invoke the constructor. + public static ConstructorDelegate CreateConstructor(ConstructorInfo constructorInfo) + { + AssertUtils.ArgumentNotNull(constructorInfo, "You cannot create a dynamic constructor for a null value."); + + bool skipVisibility = true; //!IsPublic(constructorInfo); + System.Reflection.Emit.DynamicMethod dmGetter; + Type[] argumentTypes = new Type[] { typeof(object[]) }; + dmGetter = CreateDynamicMethod(constructorInfo.Name, typeof(object), argumentTypes, constructorInfo, skipVisibility); + ILGenerator il = dmGetter.GetILGenerator(); + EmitInvokeConstructor(il, constructorInfo, false); + ConstructorDelegate ctor = (ConstructorDelegate) dmGetter.CreateDelegate(typeof(ConstructorDelegate)); + return ctor; + } + + /// + /// Creates a instance with the highest possible code access security. + /// + /// + /// If allowed by security policy, associates the method with the s declaring type. + /// Otherwise associates the dynamic method with . + /// + [MethodImpl(MethodImplOptions.NoInlining)] + private static NetDynamicMethod CreateDynamicMethod(string methodName, Type returnType, Type[] argumentTypes, MemberInfo member, bool skipVisibility) + { + NetDynamicMethod dmGetter = null; + methodName = "_dynamic_" + member.DeclaringType.FullName + "." + methodName; + try { - AssertUtils.ArgumentNotNull(fieldInfo, "You cannot create a delegate for a null value."); - - bool skipVisibility = true; //!IsPublic(fieldInfo); - Type[] argumentTypes = new Type[] { typeof(object) }; - System.Reflection.Emit.DynamicMethod dmGetter = CreateDynamicMethod("get_" + fieldInfo.Name, typeof(object), argumentTypes, fieldInfo, skipVisibility); - ILGenerator il = dmGetter.GetILGenerator(); - EmitFieldGetter(il, fieldInfo, false); - return (FieldGetterDelegate)dmGetter.CreateDelegate(typeof(FieldGetterDelegate)); - } - - /// - /// Create a new Set method delegate for the specified field using - /// - /// the field to create the delegate for - /// a delegate that can be used to read the field. - /// - /// If the field's returns true, the returned method - /// will throw an when called. - /// - public static FieldSetterDelegate CreateFieldSetter(FieldInfo fieldInfo) - { - AssertUtils.ArgumentNotNull(fieldInfo, "You cannot create a delegate for a null value."); - - bool skipVisibility = true; // !IsPublic(fieldInfo); - System.Reflection.Emit.DynamicMethod dmSetter = CreateDynamicMethod("set_" + fieldInfo.Name, null, new Type[] { typeof(object), typeof(object) }, fieldInfo, skipVisibility); - ILGenerator il = dmSetter.GetILGenerator(); - EmitFieldSetter(il, fieldInfo, false); - return (FieldSetterDelegate)dmSetter.CreateDelegate(typeof(FieldSetterDelegate)); - } - - /// - /// Create a new Get method delegate for the specified property using - /// - /// the property to create the delegate for - /// a delegate that can be used to read the property. - /// - /// If the property's returns false, the returned method - /// will throw an when called. - /// - public static PropertyGetterDelegate CreatePropertyGetter(PropertyInfo propertyInfo) - { - AssertUtils.ArgumentNotNull(propertyInfo, "You cannot create a delegate for a null value."); - - MethodInfo getMethod = propertyInfo.GetGetMethod(); - bool skipVisibility = true; // (null == getMethod || !IsPublic(getMethod)); // getter is public - NetDynamicMethod dm = CreateDynamicMethod("get_" + propertyInfo.Name, typeof(object), new Type[] { typeof(object), typeof(object[]) }, propertyInfo, skipVisibility); - ILGenerator il = dm.GetILGenerator(); - EmitPropertyGetter(il, propertyInfo, false); - return (PropertyGetterDelegate)dm.CreateDelegate(typeof(PropertyGetterDelegate)); - } - - /// - /// Create a new Set method delegate for the specified property using - /// - /// the property to create the delegate for - /// a delegate that can be used to write the property. - /// - /// If the property's returns false, the returned method - /// will throw an when called. - /// - public static PropertySetterDelegate CreatePropertySetter(PropertyInfo propertyInfo) - { - AssertUtils.ArgumentNotNull(propertyInfo, "You cannot create a delegate for a null value."); - - MethodInfo setMethod = propertyInfo.GetSetMethod(); - bool skipVisibility = true; // (null == setMethod || !IsPublic(setMethod)); // setter is public - Type[] argumentTypes = new Type[] { typeof(object), typeof(object), typeof(object[]) }; - NetDynamicMethod dm = CreateDynamicMethod("set_" + propertyInfo.Name, null, argumentTypes, propertyInfo, skipVisibility); - ILGenerator il = dm.GetILGenerator(); - EmitPropertySetter(il, propertyInfo, false); - return (PropertySetterDelegate)dm.CreateDelegate(typeof(PropertySetterDelegate)); - } - - /// - /// Create a new method delegate for the specified method using - /// - /// the method to create the delegate for - /// a delegate that can be used to invoke the method. - public static FunctionDelegate CreateMethod(MethodInfo methodInfo) - { - AssertUtils.ArgumentNotNull(methodInfo, "You cannot create a delegate for a null value."); - - bool skipVisibility = true; // !IsPublic(methodInfo); - NetDynamicMethod dm = CreateDynamicMethod(methodInfo.Name, typeof(object), new Type[] { typeof(object), typeof(object[]) }, methodInfo, skipVisibility); - ILGenerator il = dm.GetILGenerator(); - EmitInvokeMethod(il, methodInfo, false); - return (FunctionDelegate)dm.CreateDelegate(typeof(FunctionDelegate)); - } - - /// - /// Creates a new delegate for the specified constructor. - /// - ///the constructor to create the delegate for - ///delegate that can be used to invoke the constructor. - public static ConstructorDelegate CreateConstructor(ConstructorInfo constructorInfo) - { - AssertUtils.ArgumentNotNull(constructorInfo, "You cannot create a dynamic constructor for a null value."); - - bool skipVisibility = true; //!IsPublic(constructorInfo); - System.Reflection.Emit.DynamicMethod dmGetter; - Type[] argumentTypes = new Type[] { typeof(object[]) }; - dmGetter = CreateDynamicMethod(constructorInfo.Name, typeof(object), argumentTypes, constructorInfo, skipVisibility); - ILGenerator il = dmGetter.GetILGenerator(); - EmitInvokeConstructor(il, constructorInfo, false); - ConstructorDelegate ctor = (ConstructorDelegate)dmGetter.CreateDelegate(typeof(ConstructorDelegate)); - return ctor; - } - - /// - /// Creates a instance with the highest possible code access security. - /// - /// - /// If allowed by security policy, associates the method with the s declaring type. - /// Otherwise associates the dynamic method with . - /// - [MethodImpl(MethodImplOptions.NoInlining)] - private static NetDynamicMethod CreateDynamicMethod(string methodName, Type returnType, Type[] argumentTypes, MemberInfo member, bool skipVisibility) - { - NetDynamicMethod dmGetter = null; - methodName = "_dynamic_" + member.DeclaringType.FullName + "." + methodName; - try - { #if !NETSTANDARD new PermissionSet(System.Security.Permissions.PermissionState.Unrestricted).Demand(); #endif - dmGetter = CreateDynamicMethodInternal(methodName, returnType, argumentTypes, member, skipVisibility); - } - catch(SecurityException) - { - dmGetter = CreateDynamicMethodInternal(methodName, returnType, argumentTypes, MethodBase.GetCurrentMethod(), false); - } - return dmGetter; + dmGetter = CreateDynamicMethodInternal(methodName, returnType, argumentTypes, member, skipVisibility); } - - private static NetDynamicMethod CreateDynamicMethodInternal(string methodName, Type returnType, Type[] argumentTypes, MemberInfo member, bool skipVisibility) + catch (SecurityException) { - NetDynamicMethod dm; - dm = new NetDynamicMethod(methodName, returnType, argumentTypes, member.Module, skipVisibility); - return dm; + dmGetter = CreateDynamicMethodInternal(methodName, returnType, argumentTypes, MethodBase.GetCurrentMethod(), false); } - /* TODO (EE): I am not sure, if "skipVisibility" in "CreateDynamicMethodInternal" may be true all the time or if visibility needs to be calculated like below - * - private static bool IsPublic(MemberInfo member) + return dmGetter; + } + + private static NetDynamicMethod CreateDynamicMethodInternal(string methodName, Type returnType, Type[] argumentTypes, MemberInfo member, bool skipVisibility) + { + NetDynamicMethod dm; + dm = new NetDynamicMethod(methodName, returnType, argumentTypes, member.Module, skipVisibility); + return dm; + } + + /* TODO (EE): I am not sure, if "skipVisibility" in "CreateDynamicMethodInternal" may be true all the time or if visibility needs to be calculated like below + * + private static bool IsPublic(MemberInfo member) + { + if (member == null) return true; + + switch(member.MemberType) { - if (member == null) return true; + case MemberTypes.Event: + { + bool isPublic = ((EventInfo) member).GetAddMethod() != null; + return isPublic && IsPublic(member.DeclaringType); + } + case MemberTypes.Field: + { + bool isPublic = ((FieldInfo)member).IsPublic; + return isPublic && IsPublic(member.DeclaringType); + } + case MemberTypes.Property: + { + throw new NotSupportedException(); + } + case MemberTypes.Constructor: + case MemberTypes.Method: + { + MethodBase methodBase = ((MethodBase)member); + bool isPublic = methodBase.IsPublic; + if (!isPublic) + { + return false; + } + if (!IsPublic(methodBase.DeclaringType)) + { + return false; + } + if (member.MemberType == MemberTypes.Method + && !IsPublic(((MethodInfo)methodBase).ReturnType)) + { + return false; + } + foreach(ParameterInfo arg in methodBase.GetParameters()) + { + if (!IsPublic(arg.ParameterType)) return false; + } - switch(member.MemberType) - { - case MemberTypes.Event: + return true; + } + case MemberTypes.NestedType: + case MemberTypes.TypeInfo: + { + Type type = (Type)member; + bool isPublic = type.IsPublic; + if (type.IsNested && !IsPublic(type.DeclaringType)) { - bool isPublic = ((EventInfo) member).GetAddMethod() != null; - return isPublic && IsPublic(member.DeclaringType); + return false; } - case MemberTypes.Field: + if (type.IsGenericType) { - bool isPublic = ((FieldInfo)member).IsPublic; - return isPublic && IsPublic(member.DeclaringType); - } - case MemberTypes.Property: - { - throw new NotSupportedException(); - } - case MemberTypes.Constructor: - case MemberTypes.Method: - { - MethodBase methodBase = ((MethodBase)member); - bool isPublic = methodBase.IsPublic; - if (!isPublic) + foreach(Type genericTypeArg in type.GetGenericArguments()) { - return false; - } - if (!IsPublic(methodBase.DeclaringType)) - { - return false; - } - if (member.MemberType == MemberTypes.Method - && !IsPublic(((MethodInfo)methodBase).ReturnType)) - { - return false; - } - foreach(ParameterInfo arg in methodBase.GetParameters()) - { - if (!IsPublic(arg.ParameterType)) return false; - } - - return true; - } - case MemberTypes.NestedType: - case MemberTypes.TypeInfo: - { - Type type = (Type)member; - bool isPublic = type.IsPublic; - if (type.IsNested && !IsPublic(type.DeclaringType)) - { - return false; - } - if (type.IsGenericType) - { - foreach(Type genericTypeArg in type.GetGenericArguments()) + if (!IsPublic(genericTypeArg)) { - if (!IsPublic(genericTypeArg)) - { - return false; - } + return false; } } - return true; } - default: - throw new NotSupportedException(); - } + return true; + } + default: + throw new NotSupportedException(); } - */ + } + */ - #region Shared Code Generation + #region Shared Code Generation - private static void EmitFieldGetter(ILGenerator il, FieldInfo fieldInfo, bool isInstanceMethod) + private static void EmitFieldGetter(ILGenerator il, FieldInfo fieldInfo, bool isInstanceMethod) + { + if (fieldInfo.IsLiteral) + { + object value = fieldInfo.GetValue(null); + EmitConstant(il, value); + } + else if (fieldInfo.IsStatic) { - if (fieldInfo.IsLiteral) - { - object value = fieldInfo.GetValue(null); - EmitConstant(il, value); - } - else if (fieldInfo.IsStatic) - { // object v = fieldInfo.GetValue(null); // ensure type is initialized... - il.Emit(OpCodes.Ldsfld, fieldInfo); - } - else + il.Emit(OpCodes.Ldsfld, fieldInfo); + } + else + { + EmitTarget(il, fieldInfo.DeclaringType, isInstanceMethod); + il.Emit(OpCodes.Ldfld, fieldInfo); + } + + if (fieldInfo.FieldType.IsValueType) + { + il.Emit(OpCodes.Box, fieldInfo.FieldType); + } + + il.Emit(OpCodes.Ret); + } + + internal static void EmitFieldSetter(ILGenerator il, FieldInfo fieldInfo, bool isInstanceMethod) + { + if (!fieldInfo.IsLiteral + && !fieldInfo.IsInitOnly + && !(fieldInfo.DeclaringType.IsValueType && !fieldInfo.IsStatic)) + { + if (!fieldInfo.IsStatic) { EmitTarget(il, fieldInfo.DeclaringType, isInstanceMethod); - il.Emit(OpCodes.Ldfld, fieldInfo); } + il.Emit(OpCodes.Ldarg_1); if (fieldInfo.FieldType.IsValueType) { - il.Emit(OpCodes.Box, fieldInfo.FieldType); + EmitUnbox(il, fieldInfo.FieldType); } + else + { + il.Emit(OpCodes.Castclass, fieldInfo.FieldType); + } + + if (fieldInfo.IsStatic) + { + il.Emit(OpCodes.Stsfld, fieldInfo); + } + else + { + il.Emit(OpCodes.Stfld, fieldInfo); + } + il.Emit(OpCodes.Ret); } - - internal static void EmitFieldSetter(ILGenerator il, FieldInfo fieldInfo, bool isInstanceMethod) + else { - if (!fieldInfo.IsLiteral - && !fieldInfo.IsInitOnly - && !(fieldInfo.DeclaringType.IsValueType && !fieldInfo.IsStatic)) - { - if (!fieldInfo.IsStatic) - { - EmitTarget(il, fieldInfo.DeclaringType, isInstanceMethod); - } - - il.Emit(OpCodes.Ldarg_1); - if (fieldInfo.FieldType.IsValueType) - { - EmitUnbox(il, fieldInfo.FieldType); - } - else - { - il.Emit(OpCodes.Castclass, fieldInfo.FieldType); - } - - if (fieldInfo.IsStatic) - { - il.Emit(OpCodes.Stsfld, fieldInfo); - } - else - { - il.Emit(OpCodes.Stfld, fieldInfo); - } - il.Emit(OpCodes.Ret); - } - else - { - EmitThrowInvalidOperationException(il, string.Format("Cannot write to read-only field '{0}.{1}'", fieldInfo.DeclaringType.FullName, fieldInfo.Name)); - } + EmitThrowInvalidOperationException(il, string.Format("Cannot write to read-only field '{0}.{1}'", fieldInfo.DeclaringType.FullName, fieldInfo.Name)); } + } - internal static void EmitPropertyGetter(ILGenerator il, PropertyInfo propertyInfo, bool isInstanceMethod) + internal static void EmitPropertyGetter(ILGenerator il, PropertyInfo propertyInfo, bool isInstanceMethod) + { + if (propertyInfo.CanRead) { - if (propertyInfo.CanRead) - { - MethodInfo getMethod = propertyInfo.GetGetMethod(true); - EmitInvokeMethod(il, getMethod, isInstanceMethod); - } - else - { - EmitThrowInvalidOperationException(il, string.Format("Cannot read from write-only property '{0}.{1}'", propertyInfo.DeclaringType.FullName, propertyInfo.Name)); - } + MethodInfo getMethod = propertyInfo.GetGetMethod(true); + EmitInvokeMethod(il, getMethod, isInstanceMethod); } - - internal static void EmitPropertySetter(ILGenerator il, PropertyInfo propertyInfo, bool isInstanceMethod) + else { - MethodInfo method = propertyInfo.GetSetMethod(true); - - if (propertyInfo.CanWrite - && !(propertyInfo.DeclaringType.IsValueType && !method.IsStatic)) - { - // Note: last arg is property value! - // property set method signature: - // void set_MyOtherProperty( [indexArg1, indexArg2, ...], string value) - - const int paramsArrayPosition = 2; - IDictionary outArgs = new Hashtable(); - ParameterInfo[] args = propertyInfo.GetIndexParameters(); // get indexParameters here! - for (int i = 0; i < args.Length; i++) - { - SetupOutputArgument(il, paramsArrayPosition, args[i], outArgs); - } - - // load target - if (!method.IsStatic) - { - EmitTarget(il, method.DeclaringType, isInstanceMethod); - } - - // load indexer arguments - for (int i = 0; i < args.Length; i++) - { - SetupMethodArgument(il, paramsArrayPosition, args[i], outArgs); - } - - // load value - il.Emit(OpCodes.Ldarg_1); - if (propertyInfo.PropertyType.IsValueType) - { - EmitUnbox(il, propertyInfo.PropertyType); - } - else - { - il.Emit(OpCodes.Castclass, propertyInfo.PropertyType); - } - - // call setter - EmitCall(il, method); - - for (int i = 0; i < args.Length; i++) - { - ProcessOutputArgument(il, paramsArrayPosition, args[i], outArgs); - } - il.Emit(OpCodes.Ret); - } - else - { - EmitThrowInvalidOperationException(il, string.Format("Cannot write to read-only property '{0}.{1}'", propertyInfo.DeclaringType.FullName, propertyInfo.Name)); - } + EmitThrowInvalidOperationException(il, string.Format("Cannot read from write-only property '{0}.{1}'", propertyInfo.DeclaringType.FullName, propertyInfo.Name)); } + } - /// - /// Delegates a Method(object target, params object[] args) call to the actual underlying method. - /// - internal static void EmitInvokeMethod(ILGenerator il, MethodInfo method, bool isInstanceMethod) + internal static void EmitPropertySetter(ILGenerator il, PropertyInfo propertyInfo, bool isInstanceMethod) + { + MethodInfo method = propertyInfo.GetSetMethod(true); + + if (propertyInfo.CanWrite + && !(propertyInfo.DeclaringType.IsValueType && !method.IsStatic)) { - int paramsArrayPosition = (isInstanceMethod) ? 2 : 1; - ParameterInfo[] args = method.GetParameters(); + // Note: last arg is property value! + // property set method signature: + // void set_MyOtherProperty( [indexArg1, indexArg2, ...], string value) + + const int paramsArrayPosition = 2; IDictionary outArgs = new Hashtable(); + ParameterInfo[] args = propertyInfo.GetIndexParameters(); // get indexParameters here! for (int i = 0; i < args.Length; i++) { SetupOutputArgument(il, paramsArrayPosition, args[i], outArgs); } + // load target if (!method.IsStatic) { EmitTarget(il, method.DeclaringType, isInstanceMethod); } + // load indexer arguments for (int i = 0; i < args.Length; i++) { SetupMethodArgument(il, paramsArrayPosition, args[i], outArgs); } + // load value + il.Emit(OpCodes.Ldarg_1); + if (propertyInfo.PropertyType.IsValueType) + { + EmitUnbox(il, propertyInfo.PropertyType); + } + else + { + il.Emit(OpCodes.Castclass, propertyInfo.PropertyType); + } + + // call setter EmitCall(il, method); for (int i = 0; i < args.Length; i++) @@ -466,298 +431,343 @@ namespace Spring.Reflection.Dynamic ProcessOutputArgument(il, paramsArrayPosition, args[i], outArgs); } - EmitMethodReturn(il, method.ReturnType); - } - - internal static void EmitInvokeConstructor(ILGenerator il, ConstructorInfo constructor, bool isInstanceMethod) - { - int paramsArrayPosition = (isInstanceMethod) ? 1 : 0; - ParameterInfo[] args = constructor.GetParameters(); - - IDictionary outArgs = new Hashtable(); - for (int i = 0; i < args.Length; i++) - { - SetupOutputArgument(il, paramsArrayPosition, args[i], outArgs); - } - - for (int i = 0; i < args.Length; i++) - { - SetupMethodArgument(il, paramsArrayPosition, args[i], null); - } - - il.Emit(OpCodes.Newobj, constructor); - - for (int i = 0; i < args.Length; i++) - { - ProcessOutputArgument(il, paramsArrayPosition, args[i], outArgs); - } - - EmitMethodReturn(il, constructor.DeclaringType); - } - - #endregion - - private static OpCode[] LdArgOpCodes = { OpCodes.Ldarg_0, OpCodes.Ldarg_1, OpCodes.Ldarg_2 }; - - private static void SetupOutputArgument(ILGenerator il, int paramsArrayPosition, ParameterInfo argInfo, IDictionary outArgs) - { - if (!IsOutputOrRefArgument(argInfo)) - return; - - Type argType = argInfo.ParameterType.GetElementType(); - - LocalBuilder lb = il.DeclareLocal(argType); - if (!argInfo.IsOut) - { - PushParamsArgumentValue(il, paramsArrayPosition, argType, argInfo.Position); - il.Emit(OpCodes.Stloc, lb); - } - outArgs[argInfo.Position] = lb; - } - - private static bool IsOutputOrRefArgument(ParameterInfo argInfo) - { - return argInfo.IsOut || argInfo.ParameterType.Name.EndsWith("&"); - } - - private static void ProcessOutputArgument(ILGenerator il, int paramsArrayPosition, ParameterInfo argInfo, IDictionary outArgs) - { - if (!IsOutputOrRefArgument(argInfo)) - return; - - Type argType = argInfo.ParameterType.GetElementType(); - - il.Emit(LdArgOpCodes[paramsArrayPosition]); - il.Emit(OpCodes.Ldc_I4, argInfo.Position); - il.Emit(OpCodes.Ldloc, (LocalBuilder)outArgs[argInfo.Position]); - if (argType.IsValueType) - { - il.Emit(OpCodes.Box, argType); - } - il.Emit(OpCodes.Stelem_Ref); - } - - private static void SetupMethodArgument(ILGenerator il, int paramsArrayPosition, ParameterInfo argInfo, IDictionary outArgs) - { - if (IsOutputOrRefArgument(argInfo)) - { - il.Emit(OpCodes.Ldloca_S, (LocalBuilder)outArgs[argInfo.Position]); - } - else - { - PushParamsArgumentValue(il, paramsArrayPosition, argInfo.ParameterType, argInfo.Position); - } - } - - private static void PushParamsArgumentValue(ILGenerator il, int paramsArrayPosition, Type argumentType, int argumentPosition) - { - il.Emit(LdArgOpCodes[paramsArrayPosition]); - il.Emit(OpCodes.Ldc_I4, argumentPosition); - il.Emit(OpCodes.Ldelem_Ref); - if (argumentType.IsValueType) - { - // call ConvertArgumentIfNecessary() to convert e.g. int32 to double if necessary - il.Emit(OpCodes.Ldtoken, argumentType); - EmitCall(il, FnGetTypeFromHandle); - il.Emit(OpCodes.Ldc_I4, argumentPosition); - EmitCall(il, FnConvertArgumentIfNecessary); - EmitUnbox(il, argumentType); - } - else - { - il.Emit(OpCodes.Castclass, argumentType); - } - } - - private static void EmitUnbox(ILGenerator il, Type argumentType) - { - il.Emit(OpCodes.Unbox_Any, argumentType); - } - - /// - /// Generates code to process return value if necessary. - /// - /// IL generator to use. - /// Type of the return value. - private static void EmitMethodReturn(ILGenerator il, Type returnValueType) - { - if (returnValueType == typeof(void)) - { - il.Emit(OpCodes.Ldnull); - } - else if (returnValueType.IsValueType) - { - il.Emit(OpCodes.Box, returnValueType); - } il.Emit(OpCodes.Ret); } - - private delegate Type GetTypeFromHandleDelegate(RuntimeTypeHandle handle); - private static readonly MethodInfo FnGetTypeFromHandle = new GetTypeFromHandleDelegate(Type.GetTypeFromHandle).Method; - private delegate object ChangeTypeDelegate(object value, Type targetType, int argIndex); - private static readonly MethodInfo FnConvertArgumentIfNecessary = new ChangeTypeDelegate(ConvertValueTypeArgumentIfNecessary).Method; - - /// - /// Converts to an instance of if necessary to - /// e.g. avoid e.g. double/int cast exceptions. - /// - /// - /// - /// This method mimics the behavior of the compiler that - /// automatically performs casts like int to double in "Math.Sqrt(4)".
- /// See about implicit, widening type conversions on MSDN - Type Conversion Tables - ///
- /// - /// Note: is expected to be a value type! - /// - ///
- public static object ConvertValueTypeArgumentIfNecessary(object value, Type targetType, int argIndex) + else { - if (value == null) - { - if (ReflectionUtils.IsNullableType(targetType)) - { - return null; - } - throw new InvalidCastException(string.Format("Cannot convert NULL at position {0} to argument type {1}", argIndex, targetType.FullName)); - } + EmitThrowInvalidOperationException(il, string.Format("Cannot write to read-only property '{0}.{1}'", propertyInfo.DeclaringType.FullName, propertyInfo.Name)); + } + } - Type valueType = value.GetType(); - - if (ReflectionUtils.IsNullableType(targetType)) - { - targetType = Nullable.GetUnderlyingType(targetType); - } - - // no conversion necessary? - if (valueType == targetType) - { - return value; - } - - if (!valueType.IsValueType) - { - // we're facing a reftype/valuetype mix that never can convert - throw new InvalidCastException(string.Format("Cannot convert value '{0}' of type {1} at position {2} to argument type {3}", value, valueType.FullName, argIndex, targetType.FullName)); - } - - // we're dealing only with ValueType's now - try to convert them - try - { - // TODO: allow widening conversions only - return Convert.ChangeType(value, targetType); - } - catch (Exception ex) - { - throw new InvalidCastException(string.Format("Cannot convert value '{0}' of type {1} at position {2} to argument type {3}", value, valueType.FullName, argIndex, targetType.FullName), ex); - } + /// + /// Delegates a Method(object target, params object[] args) call to the actual underlying method. + /// + internal static void EmitInvokeMethod(ILGenerator il, MethodInfo method, bool isInstanceMethod) + { + int paramsArrayPosition = (isInstanceMethod) ? 2 : 1; + ParameterInfo[] args = method.GetParameters(); + IDictionary outArgs = new Hashtable(); + for (int i = 0; i < args.Length; i++) + { + SetupOutputArgument(il, paramsArrayPosition, args[i], outArgs); } - private static void EmitTarget(ILGenerator il, Type targetType, bool isInstanceMethod) + if (!method.IsStatic) { - il.Emit((isInstanceMethod) ? OpCodes.Ldarg_1 : OpCodes.Ldarg_0); - if (targetType.IsValueType) + EmitTarget(il, method.DeclaringType, isInstanceMethod); + } + + for (int i = 0; i < args.Length; i++) + { + SetupMethodArgument(il, paramsArrayPosition, args[i], outArgs); + } + + EmitCall(il, method); + + for (int i = 0; i < args.Length; i++) + { + ProcessOutputArgument(il, paramsArrayPosition, args[i], outArgs); + } + + EmitMethodReturn(il, method.ReturnType); + } + + internal static void EmitInvokeConstructor(ILGenerator il, ConstructorInfo constructor, bool isInstanceMethod) + { + int paramsArrayPosition = (isInstanceMethod) ? 1 : 0; + ParameterInfo[] args = constructor.GetParameters(); + + IDictionary outArgs = new Hashtable(); + for (int i = 0; i < args.Length; i++) + { + SetupOutputArgument(il, paramsArrayPosition, args[i], outArgs); + } + + for (int i = 0; i < args.Length; i++) + { + SetupMethodArgument(il, paramsArrayPosition, args[i], null); + } + + il.Emit(OpCodes.Newobj, constructor); + + for (int i = 0; i < args.Length; i++) + { + ProcessOutputArgument(il, paramsArrayPosition, args[i], outArgs); + } + + EmitMethodReturn(il, constructor.DeclaringType); + } + + #endregion + + private static OpCode[] LdArgOpCodes = { OpCodes.Ldarg_0, OpCodes.Ldarg_1, OpCodes.Ldarg_2 }; + + private static void SetupOutputArgument(ILGenerator il, int paramsArrayPosition, ParameterInfo argInfo, IDictionary outArgs) + { + if (!IsOutputOrRefArgument(argInfo)) + return; + + Type argType = argInfo.ParameterType.GetElementType(); + + LocalBuilder lb = il.DeclareLocal(argType); + if (!argInfo.IsOut) + { + PushParamsArgumentValue(il, paramsArrayPosition, argType, argInfo.Position); + il.Emit(OpCodes.Stloc, lb); + } + + outArgs[argInfo.Position] = lb; + } + + private static bool IsOutputOrRefArgument(ParameterInfo argInfo) + { + return argInfo.IsOut || argInfo.ParameterType.Name.EndsWith("&"); + } + + private static void ProcessOutputArgument(ILGenerator il, int paramsArrayPosition, ParameterInfo argInfo, IDictionary outArgs) + { + if (!IsOutputOrRefArgument(argInfo)) + return; + + Type argType = argInfo.ParameterType.GetElementType(); + + il.Emit(LdArgOpCodes[paramsArrayPosition]); + il.Emit(OpCodes.Ldc_I4, argInfo.Position); + il.Emit(OpCodes.Ldloc, (LocalBuilder) outArgs[argInfo.Position]); + if (argType.IsValueType) + { + il.Emit(OpCodes.Box, argType); + } + + il.Emit(OpCodes.Stelem_Ref); + } + + private static void SetupMethodArgument(ILGenerator il, int paramsArrayPosition, ParameterInfo argInfo, IDictionary outArgs) + { + if (IsOutputOrRefArgument(argInfo)) + { + il.Emit(OpCodes.Ldloca_S, (LocalBuilder) outArgs[argInfo.Position]); + } + else + { + PushParamsArgumentValue(il, paramsArrayPosition, argInfo.ParameterType, argInfo.Position); + } + } + + private static void PushParamsArgumentValue(ILGenerator il, int paramsArrayPosition, Type argumentType, int argumentPosition) + { + il.Emit(LdArgOpCodes[paramsArrayPosition]); + il.Emit(OpCodes.Ldc_I4, argumentPosition); + il.Emit(OpCodes.Ldelem_Ref); + if (argumentType.IsValueType) + { + // call ConvertArgumentIfNecessary() to convert e.g. int32 to double if necessary + il.Emit(OpCodes.Ldtoken, argumentType); + EmitCall(il, FnGetTypeFromHandle); + il.Emit(OpCodes.Ldc_I4, argumentPosition); + EmitCall(il, FnConvertArgumentIfNecessary); + EmitUnbox(il, argumentType); + } + else + { + il.Emit(OpCodes.Castclass, argumentType); + } + } + + private static void EmitUnbox(ILGenerator il, Type argumentType) + { + il.Emit(OpCodes.Unbox_Any, argumentType); + } + + /// + /// Generates code to process return value if necessary. + /// + /// IL generator to use. + /// Type of the return value. + private static void EmitMethodReturn(ILGenerator il, Type returnValueType) + { + if (returnValueType == typeof(void)) + { + il.Emit(OpCodes.Ldnull); + } + else if (returnValueType.IsValueType) + { + il.Emit(OpCodes.Box, returnValueType); + } + + il.Emit(OpCodes.Ret); + } + + private delegate Type GetTypeFromHandleDelegate(RuntimeTypeHandle handle); + + private static readonly MethodInfo FnGetTypeFromHandle = new GetTypeFromHandleDelegate(Type.GetTypeFromHandle).Method; + + private delegate object ChangeTypeDelegate(object value, Type targetType, int argIndex); + + private static readonly MethodInfo FnConvertArgumentIfNecessary = new ChangeTypeDelegate(ConvertValueTypeArgumentIfNecessary).Method; + + /// + /// Converts to an instance of if necessary to + /// e.g. avoid e.g. double/int cast exceptions. + /// + /// + /// + /// This method mimics the behavior of the compiler that + /// automatically performs casts like int to double in "Math.Sqrt(4)".
+ /// See about implicit, widening type conversions on MSDN - Type Conversion Tables + ///
+ /// + /// Note: is expected to be a value type! + /// + ///
+ public static object ConvertValueTypeArgumentIfNecessary(object value, Type targetType, int argIndex) + { + if (value == null) + { + if (ReflectionUtils.IsNullableType(targetType)) { - LocalBuilder local = il.DeclareLocal(targetType); - EmitUnbox(il, targetType); - il.Emit(OpCodes.Stloc_0); - il.Emit(OpCodes.Ldloca_S, 0); + return null; + } + + throw new InvalidCastException(string.Format("Cannot convert NULL at position {0} to argument type {1}", argIndex, targetType.FullName)); + } + + Type valueType = value.GetType(); + + if (ReflectionUtils.IsNullableType(targetType)) + { + targetType = Nullable.GetUnderlyingType(targetType); + } + + // no conversion necessary? + if (valueType == targetType) + { + return value; + } + + if (!valueType.IsValueType) + { + // we're facing a reftype/valuetype mix that never can convert + throw new InvalidCastException(string.Format("Cannot convert value '{0}' of type {1} at position {2} to argument type {3}", value, valueType.FullName, argIndex, targetType.FullName)); + } + + // we're dealing only with ValueType's now - try to convert them + try + { + // TODO: allow widening conversions only + return Convert.ChangeType(value, targetType); + } + catch (Exception ex) + { + throw new InvalidCastException(string.Format("Cannot convert value '{0}' of type {1} at position {2} to argument type {3}", value, valueType.FullName, argIndex, targetType.FullName), ex); + } + } + + private static void EmitTarget(ILGenerator il, Type targetType, bool isInstanceMethod) + { + il.Emit((isInstanceMethod) ? OpCodes.Ldarg_1 : OpCodes.Ldarg_0); + if (targetType.IsValueType) + { + LocalBuilder local = il.DeclareLocal(targetType); + EmitUnbox(il, targetType); + il.Emit(OpCodes.Stloc_0); + il.Emit(OpCodes.Ldloca_S, 0); + } + else + { + il.Emit(OpCodes.Castclass, targetType); + } + } + + private static void EmitCall(ILGenerator il, MethodInfo method) + { + il.EmitCall((method.IsVirtual) ? OpCodes.Callvirt : OpCodes.Call, method, null); + } + + private static void EmitConstant(ILGenerator il, object value) + { + if (value is String) + { + il.Emit(OpCodes.Ldstr, (string) value); + return; + } + + if (value is bool) + { + if ((bool) value) + { + il.Emit(OpCodes.Ldc_I4_1); } else { - il.Emit(OpCodes.Castclass, targetType); + il.Emit(OpCodes.Ldc_I4_0); } + + return; } - private static void EmitCall(ILGenerator il, MethodInfo method) + if (value is Char) { - il.EmitCall((method.IsVirtual) ? OpCodes.Callvirt : OpCodes.Call, method, null); + il.Emit(OpCodes.Ldc_I4, (Char) value); + il.Emit(OpCodes.Conv_I2); + return; } - private static void EmitConstant(ILGenerator il, object value) + if (value is byte) { - if (value is String) - { - il.Emit(OpCodes.Ldstr, (string)value); - return; - } - - if (value is bool) - { - if ((bool)value) - { - il.Emit(OpCodes.Ldc_I4_1); - } - else - { - il.Emit(OpCodes.Ldc_I4_0); - } - return; - } - - if (value is Char) - { - il.Emit(OpCodes.Ldc_I4, (Char)value); - il.Emit(OpCodes.Conv_I2); - return; - } - - if (value is byte) - { - il.Emit(OpCodes.Ldc_I4_S, (byte)value); - il.Emit(OpCodes.Conv_I1); - } - else if (value is Int16) - { - il.Emit(OpCodes.Ldc_I4, (Int16)value); - il.Emit(OpCodes.Conv_I2); - } - else if (value is Int32) - { - il.Emit(OpCodes.Ldc_I4, (Int32)value); - } - else if (value is Int64) - { - il.Emit(OpCodes.Ldc_I8, (Int64)value); - } - else if (value is UInt16) - { - il.Emit(OpCodes.Ldc_I4, (UInt16)value); - il.Emit(OpCodes.Conv_U2); - } - else if (value is UInt32) - { - il.Emit(OpCodes.Ldc_I4, (UInt32)value); - il.Emit(OpCodes.Conv_U4); - } - else if (value is UInt64) - { - il.Emit(OpCodes.Ldc_I8, (UInt64)value); - il.Emit(OpCodes.Conv_U8); - } - else if (value is Single) - { - il.Emit(OpCodes.Ldc_R4, (Single)value); - } - else if (value is Double) - { - il.Emit(OpCodes.Ldc_R8, (Double)value); - } + il.Emit(OpCodes.Ldc_I4_S, (byte) value); + il.Emit(OpCodes.Conv_I1); } - - private static readonly ConstructorInfo NewInvalidOperationException = - typeof(InvalidOperationException).GetConstructor(new Type[] { typeof(string) }); - - /// - /// Generates code that throws . - /// - /// IL generator to use. - /// Error message to use. - private static void EmitThrowInvalidOperationException(ILGenerator il, string message) + else if (value is Int16) { - il.Emit(OpCodes.Ldstr, message); - il.Emit(OpCodes.Newobj, NewInvalidOperationException); - il.Emit(OpCodes.Throw); + il.Emit(OpCodes.Ldc_I4, (Int16) value); + il.Emit(OpCodes.Conv_I2); + } + else if (value is Int32) + { + il.Emit(OpCodes.Ldc_I4, (Int32) value); + } + else if (value is Int64) + { + il.Emit(OpCodes.Ldc_I8, (Int64) value); + } + else if (value is UInt16) + { + il.Emit(OpCodes.Ldc_I4, (UInt16) value); + il.Emit(OpCodes.Conv_U2); + } + else if (value is UInt32) + { + il.Emit(OpCodes.Ldc_I4, (UInt32) value); + il.Emit(OpCodes.Conv_U4); + } + else if (value is UInt64) + { + il.Emit(OpCodes.Ldc_I8, (UInt64) value); + il.Emit(OpCodes.Conv_U8); + } + else if (value is Single) + { + il.Emit(OpCodes.Ldc_R4, (Single) value); + } + else if (value is Double) + { + il.Emit(OpCodes.Ldc_R8, (Double) value); } } + + private static readonly ConstructorInfo NewInvalidOperationException = + typeof(InvalidOperationException).GetConstructor(new Type[] { typeof(string) }); + + /// + /// Generates code that throws . + /// + /// IL generator to use. + /// Error message to use. + private static void EmitThrowInvalidOperationException(ILGenerator il, string message) + { + il.Emit(OpCodes.Ldstr, message); + il.Emit(OpCodes.Newobj, NewInvalidOperationException); + il.Emit(OpCodes.Throw); + } } diff --git a/src/Spring/Spring.Core/Resources/Strings.resx b/src/Spring/Spring.Core/Resources/Strings.resx index 88d19390..78a12762 100644 --- a/src/Spring/Spring.Core/Resources/Strings.resx +++ b/src/Spring/Spring.Core/Resources/Strings.resx @@ -1,6 +1,7 @@ - + @@ -34,9 +35,13 @@ 1.0.0.0 - System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.3300.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.3300.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + \ No newline at end of file diff --git a/src/Spring/Spring.Core/Stereotype/ComponentAttribute.cs b/src/Spring/Spring.Core/Stereotype/ComponentAttribute.cs index 54f6790b..b04456cb 100644 --- a/src/Spring/Spring.Core/Stereotype/ComponentAttribute.cs +++ b/src/Spring/Spring.Core/Stereotype/ComponentAttribute.cs @@ -1,52 +1,46 @@ +namespace Spring.Stereotype; - -namespace Spring.Stereotype { +/// +/// Indicates that an annotated class is a "component". +/// Such classes are considered as candidates for future features such +/// as auto-detection when using attribute-based configuration and assembly scanning. +/// +/// Other class-level annotations may be considered as identifying +/// a component as well, typically a special kind of component: +/// e.g. the Repository attribute. +/// +/// Mark Fisher +/// Mark Pollack (.NET) +/// +[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, Inherited = true)] +[Serializable] +public class ComponentAttribute : Attribute +{ + private string name = ""; /// - /// Indicates that an annotated class is a "component". - /// Such classes are considered as candidates for future features such - /// as auto-detection when using attribute-based configuration and assembly scanning. + /// Initializes a new instance of the class. /// - /// Other class-level annotations may be considered as identifying - /// a component as well, typically a special kind of component: - /// e.g. the Repository attribute. - /// - /// Mark Fisher - /// Mark Pollack (.NET) - /// - [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, Inherited = true)] - [Serializable] - public class ComponentAttribute : Attribute + public ComponentAttribute() { - private string name = ""; - - - /// - /// Initializes a new instance of the class. - /// - public ComponentAttribute() - { - } - - - /// - /// Initializes a new instance of the class. - /// - /// The name of the component. - public ComponentAttribute(string name) - { - this.name = name; - } - - - /// - /// Gets or sets the name of the component - /// - /// The name of the component. - public string Name - { - get { return name; } - set { name = value; } - } } -} + + /// + /// Initializes a new instance of the class. + /// + /// The name of the component. + public ComponentAttribute(string name) + { + this.name = name; + } + + /// + /// Gets or sets the name of the component + /// + /// The name of the component. + public string Name + { + get { return name; } + set { name = value; } + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Stereotype/ControllerAttribute.cs b/src/Spring/Spring.Core/Stereotype/ControllerAttribute.cs index 889a537a..04902ec3 100644 --- a/src/Spring/Spring.Core/Stereotype/ControllerAttribute.cs +++ b/src/Spring/Spring.Core/Stereotype/ControllerAttribute.cs @@ -18,37 +18,33 @@ #endregion -namespace Spring.Stereotype +namespace Spring.Stereotype; + +/// +/// Indicates that an annotated class is a "Controller" (e.g. a MVC Controller). +/// +/// +/// +/// This attribute also serves as a specialization of the ComponentAttribute, allowing implementation +/// classes to be autodetected in future releases through assembly scanning. +/// +/// +/// Thomas Trageser +public class ControllerAttribute : ComponentAttribute { /// - /// Indicates that an annotated class is a "Controller" (e.g. a MVC Controller). + /// Initializes a new instance of the class. /// - /// - /// - /// This attribute also serves as a specialization of the ComponentAttribute, allowing implementation - /// classes to be autodetected in future releases through assembly scanning. - /// - /// - /// Thomas Trageser - public class ControllerAttribute : ComponentAttribute + public ControllerAttribute() { - - /// - /// Initializes a new instance of the class. - /// - public ControllerAttribute() - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The name. - public ControllerAttribute(string name) - : base(name) - { - } - - } -} \ No newline at end of file + + /// + /// Initializes a new instance of the class. + /// + /// The name. + public ControllerAttribute(string name) + : base(name) + { + } +} diff --git a/src/Spring/Spring.Core/Stereotype/RepositoryAttribute.cs b/src/Spring/Spring.Core/Stereotype/RepositoryAttribute.cs index fd18dc51..fd989b39 100644 --- a/src/Spring/Spring.Core/Stereotype/RepositoryAttribute.cs +++ b/src/Spring/Spring.Core/Stereotype/RepositoryAttribute.cs @@ -18,41 +18,38 @@ #endregion -namespace Spring.Stereotype +namespace Spring.Stereotype; + +/// +/// Indicates that an annotated class is a "Repository" (or "DAO"). +/// +/// +/// A class with this attribute is eligible for Spring DataAccessException translation. A class +/// with the Repository attribute is also clarified as to its role in the overall application +/// architecture for the purpose of tools, aspects, etc. +/// +/// This attribute also serves as a specialization of the ComponentAttribute, allowing implementation +/// classes to be autodetected in future releases through assembly scanning. +/// +/// +/// Rod Johnson +/// Jueren Hoeller +/// Mark Pollack (.NET) +/// +public class RepositoryAttribute : ComponentAttribute { /// - /// Indicates that an annotated class is a "Repository" (or "DAO"). + /// Initializes a new instance of the class. /// - /// - /// A class with this attribute is eligible for Spring DataAccessException translation. A class - /// with the Repository attribute is also clarified as to its role in the overall application - /// architecture for the purpose of tools, aspects, etc. - /// - /// This attribute also serves as a specialization of the ComponentAttribute, allowing implementation - /// classes to be autodetected in future releases through assembly scanning. - /// - /// - /// Rod Johnson - /// Jueren Hoeller - /// Mark Pollack (.NET) - /// - public class RepositoryAttribute : ComponentAttribute + public RepositoryAttribute() { - /// - /// Initializes a new instance of the class. - /// - public RepositoryAttribute() - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The name of the repository. - public RepositoryAttribute(string name) : base(name) - { - } - - } -} \ No newline at end of file + + /// + /// Initializes a new instance of the class. + /// + /// The name of the repository. + public RepositoryAttribute(string name) : base(name) + { + } +} diff --git a/src/Spring/Spring.Core/Stereotype/ServiceAttribute.cs b/src/Spring/Spring.Core/Stereotype/ServiceAttribute.cs index b458f4d2..351f5e45 100644 --- a/src/Spring/Spring.Core/Stereotype/ServiceAttribute.cs +++ b/src/Spring/Spring.Core/Stereotype/ServiceAttribute.cs @@ -18,37 +18,33 @@ #endregion -namespace Spring.Stereotype +namespace Spring.Stereotype; + +/// +/// Indicates that an annotated class is a "Service" (e.g. a business service facade). +/// +/// +/// +/// This attribute also serves as a specialization of the ComponentAttribute, allowing implementation +/// classes to be autodetected in future releases through assembly scanning. +/// +/// +/// Juergen Hoeller +/// Mark Pollack (.NET) +public class ServiceAttribute : ComponentAttribute { /// - /// Indicates that an annotated class is a "Service" (e.g. a business service facade). + /// Initializes a new instance of the class. /// - /// - /// - /// This attribute also serves as a specialization of the ComponentAttribute, allowing implementation - /// classes to be autodetected in future releases through assembly scanning. - /// - /// - /// Juergen Hoeller - /// Mark Pollack (.NET) - public class ServiceAttribute : ComponentAttribute + public ServiceAttribute() { - - /// - /// Initializes a new instance of the class. - /// - public ServiceAttribute() - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The name. - public ServiceAttribute(string name) : base(name) - { - } - - } -} \ No newline at end of file + + /// + /// Initializes a new instance of the class. + /// + /// The name. + public ServiceAttribute(string name) : base(name) + { + } +} diff --git a/src/Spring/Spring.Core/Threading/CallContextStorage.cs b/src/Spring/Spring.Core/Threading/CallContextStorage.cs index 123d6e9a..4aff0249 100644 --- a/src/Spring/Spring.Core/Threading/CallContextStorage.cs +++ b/src/Spring/Spring.Core/Threading/CallContextStorage.cs @@ -1,40 +1,39 @@ using System.Runtime.Remoting.Messaging; -namespace Spring.Threading +namespace Spring.Threading; + +/// +/// Implements by using . +/// +/// Erich Eichinger +public class CallContextStorage : IThreadStorage { /// - /// Implements by using . + /// Retrieves an object with the specified name. /// - /// Erich Eichinger - public class CallContextStorage : IThreadStorage + /// The name of the item. + /// The object in the call context associated with the specified name or null if no object has been stored previously + public object GetData(string name) { - /// - /// Retrieves an object with the specified name. - /// - /// The name of the item. - /// The object in the call context associated with the specified name or null if no object has been stored previously - public object GetData(string name) - { - return CallContext.GetData(name); - } + return CallContext.GetData(name); + } - /// - /// Stores a given object and associates it with the specified name. - /// - /// The name with which to associate the new item. - /// The object to store in the call context. - public void SetData(string name, object value) - { - CallContext.SetData(name, value); - } + /// + /// Stores a given object and associates it with the specified name. + /// + /// The name with which to associate the new item. + /// The object to store in the call context. + public void SetData(string name, object value) + { + CallContext.SetData(name, value); + } - /// - /// Empties a data slot with the specified name. - /// - /// The name of the data slot to empty. - public void FreeNamedDataSlot(string name) - { - CallContext.FreeNamedDataSlot(name); - } + /// + /// Empties a data slot with the specified name. + /// + /// The name of the data slot to empty. + public void FreeNamedDataSlot(string name) + { + CallContext.FreeNamedDataSlot(name); } } diff --git a/src/Spring/Spring.Core/Threading/ISync.cs b/src/Spring/Spring.Core/Threading/ISync.cs index 2253742d..d9127c92 100644 --- a/src/Spring/Spring.Core/Threading/ISync.cs +++ b/src/Spring/Spring.Core/Threading/ISync.cs @@ -1,91 +1,92 @@ #region License + /* -* Copyright © 2002-2011 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. -*/ + * Copyright � 2002-2011 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 -namespace Spring.Threading -{ - /// - /// Acquire/Release protocol, base of many concurrency utilities. - /// - /// - /// - ///

objects isolate waiting and notification for particular logical - /// states, resource availability, events, and the like that are shared - /// across multiple threads.

- /// - ///

Use of s sometimes (but by no means always) adds - /// flexibility and efficiency compared to the use of plain - /// .Net monitor methods and locking, and are sometimes (but by no means - /// always) simpler to program with.

- /// - ///

Used for implementation of a

- ///
- /// - /// Doug Lea - /// Federico Spinazzi (.Net) - public interface ISync - { - /// Wait (possibly forever) until successful passage. - /// Fail only upon interuption. Interruptions always result in - /// `clean' failures. On failure, you can be sure that it has not - /// been acquired, and that no - /// corresponding release should be performed. Conversely, - /// a normal return guarantees that the acquire was successful. - /// - /// - void Acquire(); +namespace Spring.Threading; - /// Potentially enable others to pass. - ///

- /// Because release does not raise exceptions, - /// it can be used in `finally' clauses without requiring extra - /// embedded try/catch blocks. But keep in mind that - /// as with any java method, implementations may - /// still throw unchecked exceptions such as Error or NullPointerException - /// when faced with uncontinuable errors. However, these should normally - /// only be caught by higher-level error handlers. - ///

- ///
- void Release (); - - /// - /// Wait at most msecs to pass; report whether passed. - ///

- /// The method has best-effort semantics: - /// The msecs bound cannot - /// be guaranteed to be a precise upper bound on wait time in Java. - /// Implementations generally can only attempt to return as soon as possible - /// after the specified bound. Also, timers in Java do not stop during garbage - /// collection, so timeouts can occur just because a GC intervened. - /// So, msecs arguments should be used in - /// a coarse-grained manner. Further, - /// implementations cannot always guarantee that this method - /// will return at all without blocking indefinitely when used in - /// unintended ways. For example, deadlocks may be encountered - /// when called in an unintended context. - ///

- ///
- /// the number of milleseconds to wait - /// An argument less than or equal to zero means not to wait at all. - /// However, this may still require - /// access to a synchronization lock, which can impose unbounded - /// delay if there is a lot of contention among threads. - /// - /// true if acquired - bool Attempt(long msecs); - } +/// +/// Acquire/Release protocol, base of many concurrency utilities. +/// +/// +/// +///

objects isolate waiting and notification for particular logical +/// states, resource availability, events, and the like that are shared +/// across multiple threads.

+/// +///

Use of s sometimes (but by no means always) adds +/// flexibility and efficiency compared to the use of plain +/// .Net monitor methods and locking, and are sometimes (but by no means +/// always) simpler to program with.

+/// +///

Used for implementation of a

+///
+/// +/// Doug Lea +/// Federico Spinazzi (.Net) +public interface ISync +{ + /// Wait (possibly forever) until successful passage. + /// Fail only upon interuption. Interruptions always result in + /// `clean' failures. On failure, you can be sure that it has not + /// been acquired, and that no + /// corresponding release should be performed. Conversely, + /// a normal return guarantees that the acquire was successful. + /// + /// + void Acquire(); + + /// Potentially enable others to pass. + ///

+ /// Because release does not raise exceptions, + /// it can be used in `finally' clauses without requiring extra + /// embedded try/catch blocks. But keep in mind that + /// as with any java method, implementations may + /// still throw unchecked exceptions such as Error or NullPointerException + /// when faced with uncontinuable errors. However, these should normally + /// only be caught by higher-level error handlers. + ///

+ ///
+ void Release(); + + /// + /// Wait at most msecs to pass; report whether passed. + ///

+ /// The method has best-effort semantics: + /// The msecs bound cannot + /// be guaranteed to be a precise upper bound on wait time in Java. + /// Implementations generally can only attempt to return as soon as possible + /// after the specified bound. Also, timers in Java do not stop during garbage + /// collection, so timeouts can occur just because a GC intervened. + /// So, msecs arguments should be used in + /// a coarse-grained manner. Further, + /// implementations cannot always guarantee that this method + /// will return at all without blocking indefinitely when used in + /// unintended ways. For example, deadlocks may be encountered + /// when called in an unintended context. + ///

+ ///
+ /// the number of milleseconds to wait + /// An argument less than or equal to zero means not to wait at all. + /// However, this may still require + /// access to a synchronization lock, which can impose unbounded + /// delay if there is a lot of contention among threads. + /// + /// true if acquired + bool Attempt(long msecs); } diff --git a/src/Spring/Spring.Core/Threading/IThreadStorage.cs b/src/Spring/Spring.Core/Threading/IThreadStorage.cs index d7dcade9..304b202e 100644 --- a/src/Spring/Spring.Core/Threading/IThreadStorage.cs +++ b/src/Spring/Spring.Core/Threading/IThreadStorage.cs @@ -1,39 +1,38 @@ -namespace Spring.Threading +namespace Spring.Threading; + +/// +/// Specifies the contract a strategy must be implement to store and +/// retrieve data that is specific to the executing thread. +/// +/// +/// All implementations of this interface must treat keys case-sensitive. +/// +/// Erich Eichinger +public interface IThreadStorage { /// - /// Specifies the contract a strategy must be implement to store and - /// retrieve data that is specific to the executing thread. + /// Retrieves an object with the specified . + /// + /// The name of the item. + /// + /// The object in the current thread's context associated with the + /// specified or null if no object has been stored previously + /// + object GetData(string name); + + /// + /// Stores a given object and associates it with the specified . + /// + /// The name with which to associate the new item. + /// The object to store in the current thread's context. + void SetData(string name, object value); + + /// + /// Empties a data slot with the specified name. /// /// - /// All implementations of this interface must treat keys case-sensitive. + /// If the object with the specified is not found, the method does nothing. /// - /// Erich Eichinger - public interface IThreadStorage - { - /// - /// Retrieves an object with the specified . - /// - /// The name of the item. - /// - /// The object in the current thread's context associated with the - /// specified or null if no object has been stored previously - /// - object GetData(string name); - - /// - /// Stores a given object and associates it with the specified . - /// - /// The name with which to associate the new item. - /// The object to store in the current thread's context. - void SetData(string name, object value); - - /// - /// Empties a data slot with the specified name. - /// - /// - /// If the object with the specified is not found, the method does nothing. - /// - /// The name of the object to remove. - void FreeNamedDataSlot(string name); - } -} \ No newline at end of file + /// The name of the object to remove. + void FreeNamedDataSlot(string name); +} diff --git a/src/Spring/Spring.Core/Threading/Latch.cs b/src/Spring/Spring.Core/Threading/Latch.cs index 87632a70..476c66af 100644 --- a/src/Spring/Spring.Core/Threading/Latch.cs +++ b/src/Spring/Spring.Core/Threading/Latch.cs @@ -1,130 +1,131 @@ #region License + /* -* Copyright � 2002-2011 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. -*/ + * Copyright � 2002-2011 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.Threading; -namespace Spring.Threading -{ - /// A latch is a boolean condition that is set at most once, ever. - /// Once a single release is issued, all acquires will pass. - ///

- /// Sample usage. Here are a set of classes that use - /// a latch as a start signal for a group of worker threads that - /// are created and started beforehand, and then later enabled. - ///

- /// - /// class Worker implements IRunnable { - /// private readonly Latch startSignal; - /// Worker(Latch l) - /// { - /// startSignal = l; - /// } - /// - /// public void Run() { - /// startSignal.acquire(); - /// DoWork(); - /// } - /// - /// void DoWork() { ... } - /// } - /// - /// class Driver { // ... - /// void Main() { - /// Latch go = new Latch(); - /// for (int i = 0; i < N; ++i) // make threads - /// new Thread(new ThreadStart(new Worker(go)).Start(); - /// DoSomethingElse(); // don't let run yet - /// go.Release(); // let all threads proceed - /// } - /// } - /// - ///
- /// Doug Lea - /// Federico Spinazzi (.Net) - public class Latch : ISync - { - /// - /// can acquire ? - /// - protected bool latched_ = false; +namespace Spring.Threading; - /// - /// Method mainly used by clients who are trying to get the latch - /// - public void Acquire () +/// A latch is a boolean condition that is set at most once, ever. +/// Once a single release is issued, all acquires will pass. +///

+/// Sample usage. Here are a set of classes that use +/// a latch as a start signal for a group of worker threads that +/// are created and started beforehand, and then later enabled. +///

+/// +/// class Worker implements IRunnable { +/// private readonly Latch startSignal; +/// Worker(Latch l) +/// { +/// startSignal = l; +/// } +/// +/// public void Run() { +/// startSignal.acquire(); +/// DoWork(); +/// } +/// +/// void DoWork() { ... } +/// } +/// +/// class Driver { // ... +/// void Main() { +/// Latch go = new Latch(); +/// for (int i = 0; i < N; ++i) // make threads +/// new Thread(new ThreadStart(new Worker(go)).Start(); +/// DoSomethingElse(); // don't let run yet +/// go.Release(); // let all threads proceed +/// } +/// } +/// +///
+/// Doug Lea +/// Federico Spinazzi (.Net) +public class Latch : ISync +{ + /// + /// can acquire ? + /// + protected bool latched_ = false; + + /// + /// Method mainly used by clients who are trying to get the latch + /// + public void Acquire() + { + lock (this) { - lock (this) + while (!latched_) { - while (!latched_) - { - Monitor.Wait (this); - } + Monitor.Wait(this); } } + } - /// Wait at most msecs millisconds for a permit - public bool Attempt (long msecs) + /// Wait at most msecs millisconds for a permit + public bool Attempt(long msecs) + { + lock (this) { - lock (this) + if (latched_) { - if (latched_) + return true; + } + else if (msecs <= 0) + { + return false; + } + else + { + long waitTime = msecs; + //double start = new TimeSpan(DateTime.UtcNow.Ticks).TotalMilliseconds; + double start = Utils.CurrentTimeMillis; + for (;;) { - return true; - } - else if (msecs <= 0) - { - return false; - } - else - { - long waitTime = msecs; - //double start = new TimeSpan(DateTime.UtcNow.Ticks).TotalMilliseconds; - double start = Utils.CurrentTimeMillis; - for (;;) + Monitor.Wait(this, TimeSpan.FromMilliseconds(waitTime)); + if (latched_) { - Monitor.Wait (this, TimeSpan.FromMilliseconds(waitTime)); - if (latched_) + return true; + } + else + { + waitTime = (long) (msecs - (Utils.CurrentTimeMillis - start)); + if (waitTime <= 0) { - return true; - } - else - { - waitTime = (long) (msecs - (Utils.CurrentTimeMillis - start)); - if (waitTime <= 0) - { - return false; - } + return false; } } } } } + } - /// - /// Enable all current and future acquires to pass - /// - public void Release () + /// + /// Enable all current and future acquires to pass + /// + public void Release() + { + lock (this) { - lock (this) - { - latched_ = true; - Monitor.PulseAll(this); - } + latched_ = true; + Monitor.PulseAll(this); } } } diff --git a/src/Spring/Spring.Core/Threading/LogicalThreadContext.cs b/src/Spring/Spring.Core/Threading/LogicalThreadContext.cs index 38114d5a..0467e9c7 100644 --- a/src/Spring/Spring.Core/Threading/LogicalThreadContext.cs +++ b/src/Spring/Spring.Core/Threading/LogicalThreadContext.cs @@ -24,75 +24,74 @@ using Spring.Util; #endregion -namespace Spring.Threading +namespace Spring.Threading; + +/// +/// An abstraction to safely store "ThreadStatic" data. +/// +/// +/// You may switch the storage strategy by calling .

+/// NOTE: Access to the underlying storage is not synchronized for performance reasons. +/// You should call only once at application startup! +/// +/// Erich Eichinger +public sealed class LogicalThreadContext { ///

- /// An abstraction to safely store "ThreadStatic" data. + /// Holds the current strategy. /// /// - /// You may switch the storage strategy by calling .

- /// NOTE: Access to the underlying storage is not synchronized for performance reasons. - /// You should call only once at application startup! + /// Access to this variable is not synchronized on purpose for performance reasons. + /// Setting a different strategy should happen only once + /// at application startup. /// - /// Erich Eichinger - public sealed class LogicalThreadContext - { - ///

- /// Holds the current strategy. - /// - /// - /// Access to this variable is not synchronized on purpose for performance reasons. - /// Setting a different strategy should happen only once - /// at application startup. - /// - private static IThreadStorage threadStorage = + private static IThreadStorage threadStorage = #if NETSTANDARD new ThreadStaticStorage(); #else - new CallContextStorage(); + new CallContextStorage(); #endif - /// - /// Set the new strategy. - /// - public static void SetStorage(IThreadStorage storage) - { - AssertUtils.ArgumentNotNull(storage, "storage"); - threadStorage = storage; - } + /// + /// Set the new strategy. + /// + public static void SetStorage(IThreadStorage storage) + { + AssertUtils.ArgumentNotNull(storage, "storage"); + threadStorage = storage; + } - private LogicalThreadContext() - { - throw new NotSupportedException("must not be instantiated"); - } + private LogicalThreadContext() + { + throw new NotSupportedException("must not be instantiated"); + } - /// - /// Retrieves an object with the specified name. - /// - /// The name of the item. - /// The object in the context associated with the specified name or null if no object has been stored previously - public static object GetData(string name) - { - return threadStorage.GetData(name); - } + /// + /// Retrieves an object with the specified name. + /// + /// The name of the item. + /// The object in the context associated with the specified name or null if no object has been stored previously + public static object GetData(string name) + { + return threadStorage.GetData(name); + } - /// - /// Stores a given object and associates it with the specified name. - /// - /// The name with which to associate the new item. - /// The object to store in the current thread's context. - public static void SetData(string name, object value) - { - threadStorage.SetData(name, value); - } + /// + /// Stores a given object and associates it with the specified name. + /// + /// The name with which to associate the new item. + /// The object to store in the current thread's context. + public static void SetData(string name, object value) + { + threadStorage.SetData(name, value); + } - /// - /// Empties a data slot with the specified name. - /// - /// The name of the data slot to empty. - public static void FreeNamedDataSlot(string name) - { - threadStorage.FreeNamedDataSlot(name); - } + /// + /// Empties a data slot with the specified name. + /// + /// The name of the data slot to empty. + public static void FreeNamedDataSlot(string name) + { + threadStorage.FreeNamedDataSlot(name); } } diff --git a/src/Spring/Spring.Core/Threading/Semaphore.cs b/src/Spring/Spring.Core/Threading/Semaphore.cs index da005c4c..c0ed60c1 100644 --- a/src/Spring/Spring.Core/Threading/Semaphore.cs +++ b/src/Spring/Spring.Core/Threading/Semaphore.cs @@ -1,185 +1,184 @@ #region License + /* -* Copyright � 2002-2011 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. -*/ + * Copyright � 2002-2011 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.Threading; -namespace Spring.Threading +namespace Spring.Threading; + +/// +///

Base class for counting semaphores based on Semaphore implementation +/// from Doug Lea.

+///
+/// +/// +///

Conceptually, a semaphore +/// maintains a set of permits. Each acquire() blocks if +/// necessary until a permit is available, and then takes it.

+/// +///

Each release adds a permit. However, no actual permit objects are used; +/// the Semaphore just keeps a count of the number available +/// and acts accordingly.

+/// +///

A semaphore initialized to 1 can serve as a mutual exclusion lock.

+/// +/// Used for implementation of a +///
+/// Doug Lea +/// Federico Spinazzi (.Net) +public class Semaphore : ISync { - /// - ///

Base class for counting semaphores based on Semaphore implementation - /// from Doug Lea.

+ /// + /// current number of available permits /// - /// - /// - ///

Conceptually, a semaphore - /// maintains a set of permits. Each acquire() blocks if - /// necessary until a permit is available, and then takes it.

- /// - ///

Each release adds a permit. However, no actual permit objects are used; - /// the Semaphore just keeps a count of the number available - /// and acts accordingly.

- /// - ///

A semaphore initialized to 1 can serve as a mutual exclusion lock.

- /// - /// Used for implementation of a - ///
- /// Doug Lea - /// Federico Spinazzi (.Net) - public class Semaphore : ISync - { - /// - /// current number of available permits - /// - protected long nPermits; + protected long nPermits; - /// - ///

Create a Semaphore with the given initial number of permits.

- ///

Using a seed of 1 makes the semaphore act as a mutual - /// exclusion lock.

- /// - ///

Negative seeds are also allowed, - /// in which case no acquires will proceed until the number of - /// releases has pushed the number of permits past 0.

- ///
- public Semaphore(long initialPermits) - { - nPermits = initialPermits; - } + /// + ///

Create a Semaphore with the given initial number of permits.

+ ///

Using a seed of 1 makes the semaphore act as a mutual + /// exclusion lock.

+ /// + ///

Negative seeds are also allowed, + /// in which case no acquires will proceed until the number of + /// releases has pushed the number of permits past 0.

+ ///
+ public Semaphore(long initialPermits) + { + nPermits = initialPermits; + } - /// - /// Release a permit - /// - public virtual void Release () - { - lock (this) - { - ++nPermits; - Monitor.Pulse(this); - } - } - - /// - /// Acquire a permit - /// - public virtual void Acquire () - { - lock (this) - { - try - { - while (nPermits <= 0) - Monitor.Wait(this); - --nPermits; - } - catch (ThreadInterruptedException) - { - Monitor.Pulse(this); - throw; - } - } - } - - /// - /// Wait at most msecs millisconds for a permit - /// - /// number of ms to wait - /// true if aquired - public virtual bool Attempt(long msecs) + /// + /// Release a permit + /// + public virtual void Release() + { + lock (this) { - lock (this) - { - if (nPermits > 0) - { - --nPermits; - return true; - } - else if (msecs <= 0) - return false; - else - { - try - { - double startTime = Utils.CurrentTimeMillis; - long waitTime = msecs; + ++nPermits; + Monitor.Pulse(this); + } + } - for (; ; ) + /// + /// Acquire a permit + /// + public virtual void Acquire() + { + lock (this) + { + try + { + while (nPermits <= 0) + Monitor.Wait(this); + --nPermits; + } + catch (ThreadInterruptedException) + { + Monitor.Pulse(this); + throw; + } + } + } + + /// + /// Wait at most msecs millisconds for a permit + /// + /// number of ms to wait + /// true if aquired + public virtual bool Attempt(long msecs) + { + lock (this) + { + if (nPermits > 0) + { + --nPermits; + return true; + } + else if (msecs <= 0) + return false; + else + { + try + { + double startTime = Utils.CurrentTimeMillis; + long waitTime = msecs; + + for (;;) + { + Monitor.Wait(this, TimeSpan.FromMilliseconds(waitTime)); + if (nPermits > 0) { - Monitor.Wait(this, TimeSpan.FromMilliseconds(waitTime)); - if (nPermits > 0) - { - --nPermits; - return true; - } - else - { - waitTime = (long) (msecs - (Utils.CurrentTimeMillis - startTime)); - if (waitTime <= 0) - return false; - } + --nPermits; + return true; + } + else + { + waitTime = (long) (msecs - (Utils.CurrentTimeMillis - startTime)); + if (waitTime <= 0) + return false; } } - catch (ThreadInterruptedException) - { - Monitor.Pulse(this); - throw; - } + } + catch (ThreadInterruptedException) + { + Monitor.Pulse(this); + throw; } } } + } - /// Release N permits. release(n) is - /// equivalent in effect to: - ///
-        /// for (int i = 0; i < n; ++i) release();
-        /// 
- /// But may be more efficient in some semaphore implementations. - ///
- /// if n is negative. - /// - /// - public virtual void Release(long n) + /// Release N permits. release(n) is + /// equivalent in effect to: + ///
+    /// for (int i = 0; i < n; ++i) release();
+    /// 
+ /// But may be more efficient in some semaphore implementations. + ///
+ /// if n is negative. + /// + /// + public virtual void Release(long n) + { + lock (this) + { + if (n < 0) + throw new ArgumentOutOfRangeException("n", n, "Negative argument"); + + nPermits += n; + for (long i = 0; i < n; ++i) + Monitor.Pulse(this); + } + } + + /// Return the current number of available permits. + /// Returns an accurate, but possibly unstable value, + /// that may change immediately after returning. + /// + public virtual long Permits + { + get { lock (this) { - if (n < 0) - throw new ArgumentOutOfRangeException("n", n, "Negative argument"); - - nPermits += n; - for (long i = 0; i < n; ++i) - Monitor.Pulse(this); + return nPermits; } } - - /// Return the current number of available permits. - /// Returns an accurate, but possibly unstable value, - /// that may change immediately after returning. - /// - public virtual long Permits - { - get - { - lock (this) - { - return nPermits; - } - } - } - - - } + } } diff --git a/src/Spring/Spring.Core/Threading/SyncHolder.cs b/src/Spring/Spring.Core/Threading/SyncHolder.cs index 304e91f2..e06cfdba 100644 --- a/src/Spring/Spring.Core/Threading/SyncHolder.cs +++ b/src/Spring/Spring.Core/Threading/SyncHolder.cs @@ -1,68 +1,69 @@ #region License + /* -* Copyright � 2002-2011 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. -*/ + * Copyright � 2002-2011 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 -namespace Spring.Threading +namespace Spring.Threading; + +/// +/// Utility class to use an with the +/// C# using () {} idiom +/// +public class SyncHolder : IDisposable { - /// - /// Utility class to use an with the - /// C# using () {} idiom - /// - public class SyncHolder : IDisposable - { - ISync _sync; + ISync _sync; - /// - /// Creates a new trying to the given - /// - /// - /// the to be held - public SyncHolder (ISync sync) - { - Init (sync); - } + /// + /// Creates a new trying to the given + /// + /// + /// the to be held + public SyncHolder(ISync sync) + { + Init(sync); + } - /// - /// Creates a new trying to the given - /// - /// - /// the to be held - /// millisecond to try to acquire the lock - public SyncHolder (ISync sync, long msecs) - { - Init(new TimeoutSync(sync, msecs)); - } + /// + /// Creates a new trying to the given + /// + /// + /// the to be held + /// millisecond to try to acquire the lock + public SyncHolder(ISync sync, long msecs) + { + Init(new TimeoutSync(sync, msecs)); + } - /// - /// Releases the held - /// - public void Dispose () - { - _sync.Release(); - } + /// + /// Releases the held + /// + public void Dispose() + { + _sync.Release(); + } - /// - /// initializes and acquire access to the - /// - /// - private void Init (ISync sync) - { - this._sync = sync; - _sync.Acquire(); - } + /// + /// initializes and acquire access to the + /// + /// + private void Init(ISync sync) + { + this._sync = sync; + _sync.Acquire(); } } diff --git a/src/Spring/Spring.Core/Threading/ThreadStaticStorage.cs b/src/Spring/Spring.Core/Threading/ThreadStaticStorage.cs index d7c09d68..90dd0762 100644 --- a/src/Spring/Spring.Core/Threading/ThreadStaticStorage.cs +++ b/src/Spring/Spring.Core/Threading/ThreadStaticStorage.cs @@ -1,4 +1,5 @@ #region License + // /* // * Copyright 2022 the original author or authors. // * @@ -14,73 +15,73 @@ // * See the License for the specific language governing permissions and // * limitations under the License. // */ + #endregion using System.Collections; using System.Threading; -namespace Spring.Threading +namespace Spring.Threading; + +/// +/// Implements by using a hashtable. +/// +/// Erich Eichinger +public class ThreadStaticStorage : IThreadStorage { + [ThreadStatic] private static Hashtable _dataThreadStatic; + + // AsyncLocal for it to work in async NMS lib + private static AsyncLocal _dataAsyncLocal = new AsyncLocal(); + /// - /// Implements by using a hashtable. + /// Allows to switch how context is being held, if true, then it will use AsyncLocal /// - /// Erich Eichinger - public class ThreadStaticStorage : IThreadStorage + public static bool UseAsyncLocal { get; set; } = false; + + private static Hashtable Data { - [ThreadStatic] - private static Hashtable _dataThreadStatic; - // AsyncLocal for it to work in async NMS lib - private static AsyncLocal _dataAsyncLocal = new AsyncLocal(); - - /// - /// Allows to switch how context is being held, if true, then it will use AsyncLocal - /// - public static bool UseAsyncLocal { get; set; } = false; - - private static Hashtable Data + get { - get + if (UseAsyncLocal) { - if (UseAsyncLocal) - { - if (_dataAsyncLocal.Value == null) _dataAsyncLocal.Value = new Hashtable(); - return _dataAsyncLocal.Value; - } - else - { - if (_dataThreadStatic == null) _dataThreadStatic = new Hashtable(); - return _dataThreadStatic; - } + if (_dataAsyncLocal.Value == null) _dataAsyncLocal.Value = new Hashtable(); + return _dataAsyncLocal.Value; + } + else + { + if (_dataThreadStatic == null) _dataThreadStatic = new Hashtable(); + return _dataThreadStatic; } } - - /// - /// Retrieves an object with the specified name. - /// - /// The name of the item. - /// The object in the call context associated with the specified name or null if no object has been stored previously - public object GetData(string name) - { - return Data[name]; - } - - /// - /// Stores a given object and associates it with the specified name. - /// - /// The name with which to associate the new item. - /// The object to store in the call context. - public void SetData(string name, object value) - { - Data[name] = value; - } - - /// - /// Empties a data slot with the specified name. - /// - /// The name of the data slot to empty. - public void FreeNamedDataSlot(string name) - { - Data.Remove(name); - } } -} + + /// + /// Retrieves an object with the specified name. + /// + /// The name of the item. + /// The object in the call context associated with the specified name or null if no object has been stored previously + public object GetData(string name) + { + return Data[name]; + } + + /// + /// Stores a given object and associates it with the specified name. + /// + /// The name with which to associate the new item. + /// The object to store in the call context. + public void SetData(string name, object value) + { + Data[name] = value; + } + + /// + /// Empties a data slot with the specified name. + /// + /// The name of the data slot to empty. + public void FreeNamedDataSlot(string name) + { + Data.Remove(name); + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Threading/TimeoutException.cs b/src/Spring/Spring.Core/Threading/TimeoutException.cs index 8fd86bd4..6f307f02 100644 --- a/src/Spring/Spring.Core/Threading/TimeoutException.cs +++ b/src/Spring/Spring.Core/Threading/TimeoutException.cs @@ -1,127 +1,133 @@ #region License /* -* Copyright � 2002-2011 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. -*/ + * Copyright � 2002-2011 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.Runtime.Serialization; using System.Threading; - /* Originally written by Doug Lea and released into the public domain. This may be used for any purposes whatsoever without acknowledgment. Thanks for the assistance and support of Sun Microsystems Labs, and everyone contributing, testing, and using this code. */ -namespace Spring.Threading +namespace Spring.Threading; + +/// Thrown by synchronization classes that report +/// timeouts via exceptions. The exception is treated +/// as a form (subclass) of InterruptedException. This both +/// simplifies handling, and conceptually reflects the fact that +/// timed-out operations are artificially interrupted by timers. +/// +/// +[Serializable] +public class TimeoutException : ThreadInterruptedException { - /// Thrown by synchronization classes that report - /// timeouts via exceptions. The exception is treated - /// as a form (subclass) of InterruptedException. This both - /// simplifies handling, and conceptually reflects the fact that - /// timed-out operations are artificially interrupted by timers. - /// - /// - [Serializable] - public class TimeoutException : ThreadInterruptedException - { - /// The approximate time that the operation lasted before - /// this timeout exception was thrown. - /// - /// - private readonly long _duration; - /// - /// Creates a new instance of the - /// class. - /// - public TimeoutException( ) : base(){} - /// - /// Creates a new instance of the - /// class with the - /// specified message. - /// - /// - /// A message about the exception. - /// - public TimeoutException( string message ) : base( message ){} - /// - /// Creates a new instance of the - /// class with the - /// specified message. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception that is being wrapped. - /// - public TimeoutException( string message, Exception innerException ) : base( message, innerException ){} - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The - /// that holds the serialized object data about the exception being thrown. - /// - /// - /// The - /// that contains contextual information about the source or destination. - /// - protected TimeoutException( SerializationInfo info, StreamingContext context ) - : base( info, context ) - { - _duration = info.GetInt32( "duration" ); - } - /// - /// Override of GetObjectData to allow for private serialization - /// - /// serialization info - /// streaming context - public override void GetObjectData(SerializationInfo info, StreamingContext context) - { - info.AddValue( "duration", _duration ); - base.GetObjectData( info, context ); - } - /// Constructs a TimeoutException with given duration value. - /// - /// - public TimeoutException( long time ) - { - _duration = time; - } - /// Constructs a TimeoutException with the - /// specified duration value and detail message. - /// - public TimeoutException( long time, String message ) : base( message ) - { - _duration = time; - } - /// - /// Gets the approximate time that the operation lasted before - /// this timeout exception was thrown. - /// - public long Duration - { - get - { - return _duration; - } - } - } + /// The approximate time that the operation lasted before + /// this timeout exception was thrown. + /// + /// + private readonly long _duration; + + /// + /// Creates a new instance of the + /// class. + /// + public TimeoutException() : base() { } + + /// + /// Creates a new instance of the + /// class with the + /// specified message. + /// + /// + /// A message about the exception. + /// + public TimeoutException(string message) : base(message) { } + + /// + /// Creates a new instance of the + /// class with the + /// specified message. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception that is being wrapped. + /// + public TimeoutException(string message, Exception innerException) : base(message, innerException) { } + + /// + /// Creates a new instance of the + /// class. + /// + /// + /// The + /// that holds the serialized object data about the exception being thrown. + /// + /// + /// The + /// that contains contextual information about the source or destination. + /// + protected TimeoutException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + _duration = info.GetInt32("duration"); + } + + /// + /// Override of GetObjectData to allow for private serialization + /// + /// serialization info + /// streaming context + public override void GetObjectData(SerializationInfo info, StreamingContext context) + { + info.AddValue("duration", _duration); + base.GetObjectData(info, context); + } + + /// Constructs a TimeoutException with given duration value. + /// + /// + public TimeoutException(long time) + { + _duration = time; + } + + /// Constructs a TimeoutException with the + /// specified duration value and detail message. + /// + public TimeoutException(long time, String message) : base(message) + { + _duration = time; + } + + /// + /// Gets the approximate time that the operation lasted before + /// this timeout exception was thrown. + /// + public long Duration + { + get + { + return _duration; + } + } } diff --git a/src/Spring/Spring.Core/Threading/TimeoutSync.cs b/src/Spring/Spring.Core/Threading/TimeoutSync.cs index c7445cb0..9247c0dc 100644 --- a/src/Spring/Spring.Core/Threading/TimeoutSync.cs +++ b/src/Spring/Spring.Core/Threading/TimeoutSync.cs @@ -1,20 +1,23 @@ #region License + /* -* Copyright © 2002-2011 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. -*/ + * Copyright � 2002-2011 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 + /* Originally written by Doug Lea and released into the public domain. This may be used for any purposes whatsoever without acknowledgment. @@ -22,58 +25,57 @@ Thanks for the assistance and support of Sun Microsystems Labs, and everyone contributing, testing, and using this code. */ -namespace Spring.Threading -{ - - /// A TimeoutSync is an adaptor class that transforms all - /// calls to acquire to instead invoke attempt with a predetermined - /// timeout value. - /// - /// - public class TimeoutSync : ISync - { - /// - /// the adapted sync - /// - protected readonly internal ISync sync_; - /// - /// timeout value - /// - protected readonly internal long timeout_; - - /// Create a TimeoutSync using the given Sync object, and - /// using the given timeout value for all calls to acquire. - /// - public TimeoutSync(ISync sync, long timeout) - { - sync_ = sync; - timeout_ = timeout; - } - - /// - /// Try to acquire the sync before the timeout - /// - /// In case a time out occurred - public virtual void Acquire() - { - if (!sync_.Attempt(timeout_)) - throw new TimeoutException(timeout_); - } +namespace Spring.Threading; - /// - /// - /// - public virtual bool Attempt(long msecs) - { - return sync_.Attempt(msecs); - } - - /// - /// - /// - public virtual void Release() - { - sync_.Release(); - } - } -} \ No newline at end of file +/// A TimeoutSync is an adaptor class that transforms all +/// calls to acquire to instead invoke attempt with a predetermined +/// timeout value. +/// +/// +public class TimeoutSync : ISync +{ + /// + /// the adapted sync + /// + protected readonly internal ISync sync_; + + /// + /// timeout value + /// + protected readonly internal long timeout_; + + /// Create a TimeoutSync using the given Sync object, and + /// using the given timeout value for all calls to acquire. + /// + public TimeoutSync(ISync sync, long timeout) + { + sync_ = sync; + timeout_ = timeout; + } + + /// + /// Try to acquire the sync before the timeout + /// + /// In case a time out occurred + public virtual void Acquire() + { + if (!sync_.Attempt(timeout_)) + throw new TimeoutException(timeout_); + } + + /// + /// + /// + public virtual bool Attempt(long msecs) + { + return sync_.Attempt(msecs); + } + + /// + /// + /// + public virtual void Release() + { + sync_.Release(); + } +} diff --git a/src/Spring/Spring.Core/Threading/Utils.cs b/src/Spring/Spring.Core/Threading/Utils.cs index 4ad5a3dd..99378415 100644 --- a/src/Spring/Spring.Core/Threading/Utils.cs +++ b/src/Spring/Spring.Core/Threading/Utils.cs @@ -1,135 +1,136 @@ #region License /* -* Copyright � 2002-2011 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. -*/ + * Copyright � 2002-2011 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.Threading; -namespace Spring.Threading +namespace Spring.Threading; + +/// +/// Support to account for differences between java nad .NET: +///
    +///
+///
+public class Utils { - /// - /// Support to account for differences between java nad .NET: - ///
    - ///
- ///
- public class Utils - { - private Utils() - { - } + private Utils() + { + } - /// - /// .NET threads have not a method to check if they have been interrupted. - /// Moreover, differently from java threads, when entering locked - /// blocks, Monitor, Sleep, SpinWait and so on, a - /// will be raised by the runtime. - ///

Spring.Threading classes usually call this method before entering a lock block, to mirror java code - ///

Usually this is non issue because the same exception will be raised entering the monitor - /// associated with the lock () - ///

- ///
- /// if the thread has been interrupted - public static void FailFastIfInterrupted() - { - Thread.Sleep(0); - } + /// + /// .NET threads have not a method to check if they have been interrupted. + /// Moreover, differently from java threads, when entering locked + /// blocks, Monitor, Sleep, SpinWait and so on, a + /// will be raised by the runtime. + ///

Spring.Threading classes usually call this method before entering a lock block, to mirror java code + ///

Usually this is non issue because the same exception will be raised entering the monitor + /// associated with the lock () + ///

+ ///
+ /// if the thread has been interrupted + public static void FailFastIfInterrupted() + { + Thread.Sleep(0); + } - /// - /// Placeholder for java.lang.System.currentTimeMillis - /// - /// The current machine time in milliseconds - public static long CurrentTimeMillis - { - get { return ToTimeMillis(DateTime.Now); } - } + /// + /// Placeholder for java.lang.System.currentTimeMillis + /// + /// The current machine time in milliseconds + public static long CurrentTimeMillis + { + get { return ToTimeMillis(DateTime.Now); } + } - /// - /// Normalize the given so that - /// is is comparable with . - /// - /// Date. - /// - public static long ToTimeMillis(DateTime date) - { - // may be also new TimeSpan(DateTime.UtcNow.Ticks).TotalMilliseconds; - // see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dv_jlca/html/vberrjavalangsystemcurrenttimemillis.asp - return (date.Ticks - 621355968000000000)/10000; - } + /// + /// Normalize the given so that + /// is is comparable with . + /// + /// Date. + /// + public static long ToTimeMillis(DateTime date) + { + // may be also new TimeSpan(DateTime.UtcNow.Ticks).TotalMilliseconds; + // see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dv_jlca/html/vberrjavalangsystemcurrenttimemillis.asp + return (date.Ticks - 621355968000000000) / 10000; + } - /// - /// - /// - /// - /// - /// the difference between millisecodns of the first and second date - public static long DeltaTimeMillis(DateTime one, DateTime another) - { - return (one.Ticks - another.Ticks)/10000; - } + /// + /// + /// + /// + /// + /// the difference between millisecodns of the first and second date + public static long DeltaTimeMillis(DateTime one, DateTime another) + { + return (one.Ticks - another.Ticks) / 10000; + } - /// - /// Returns the number of nanoseconds for the current value of - /// - /// Current number of nanoseconds - public static long CurrentNanoSeconds() - { - return (DateTime.Now.Ticks - 621355968000000000)/10000*1000000; - } + /// + /// Returns the number of nanoseconds for the current value of + /// + /// Current number of nanoseconds + public static long CurrentNanoSeconds() + { + return (DateTime.Now.Ticks - 621355968000000000) / 10000 * 1000000; + } - /// - /// Returns the number of nano seconds represented by the - /// - /// to use - /// Number of nano seconds for - public static long TimeSpanNanoSeconds(TimeSpan timeSpan) - { - return (timeSpan.Ticks - 621355968000000000)/10000*1000000; - } - /// - /// Returns a representing the number of nanoseconds passed in via . - /// - /// Number of nanoseconds. - /// representing the number of nanoseconds passed in. - public static TimeSpan NanoSecondsTimeSpan(long nanoSeconds ) - { - int milliseconds = Convert.ToInt32(nanoSeconds / 1000000); - return new TimeSpan(0,0,0,0, milliseconds); - } + /// + /// Returns the number of nano seconds represented by the + /// + /// to use + /// Number of nano seconds for + public static long TimeSpanNanoSeconds(TimeSpan timeSpan) + { + return (timeSpan.Ticks - 621355968000000000) / 10000 * 1000000; + } - /// - /// Has been interrupted this thread - /// - public static bool ThreadInterrupted - { - get - { - bool interrupted = false; - try - { - Utils.FailFastIfInterrupted(); - } - catch (ThreadInterruptedException) - { - Thread.CurrentThread.Interrupt(); - interrupted = true; - } - return interrupted; - } - } - } + /// + /// Returns a representing the number of nanoseconds passed in via . + /// + /// Number of nanoseconds. + /// representing the number of nanoseconds passed in. + public static TimeSpan NanoSecondsTimeSpan(long nanoSeconds) + { + int milliseconds = Convert.ToInt32(nanoSeconds / 1000000); + return new TimeSpan(0, 0, 0, 0, milliseconds); + } + + /// + /// Has been interrupted this thread + /// + public static bool ThreadInterrupted + { + get + { + bool interrupted = false; + try + { + Utils.FailFastIfInterrupted(); + } + catch (ThreadInterruptedException) + { + Thread.CurrentThread.Interrupt(); + interrupted = true; + } + + return interrupted; + } + } } diff --git a/src/Spring/Spring.Core/Util/ArrayUtils.cs b/src/Spring/Spring.Core/Util/ArrayUtils.cs index 5ae15c1c..d84d44e4 100644 --- a/src/Spring/Spring.Core/Util/ArrayUtils.cs +++ b/src/Spring/Spring.Core/Util/ArrayUtils.cs @@ -25,207 +25,212 @@ using System.Text; #endregion -namespace Spring.Util +namespace Spring.Util; + +/// +/// Various utility methods relating to the manipulation of arrays. +/// +/// Aleksandar Seovic +public sealed class ArrayUtils { /// - /// Various utility methods relating to the manipulation of arrays. + /// Checks if the given array or collection has elements and none of the elements is null. /// - /// Aleksandar Seovic - public sealed class ArrayUtils + /// the collection to be checked. + /// true if the collection has a length and contains only non-null elements. + public static bool HasElements(ICollection collection) { - /// - /// Checks if the given array or collection has elements and none of the elements is null. - /// - /// the collection to be checked. - /// true if the collection has a length and contains only non-null elements. - public static bool HasElements(ICollection collection) + if (!HasLength(collection)) { - if (!HasLength(collection)) + return false; + } + + foreach (var item in collection) + { + if (item == null) { return false; } + } - foreach (var item in collection) - { - if (item == null) - { - return false; - } - } + return true; + } + + /// + /// Use this sort method instead of to overcome + /// bugs in Mono. + /// + public static void Sort(Array array, IComparer comparer) + { + if (SystemUtils.MonoRuntime) + { + ArrayList list = new ArrayList(array); + list.Sort(comparer); + list.ToArray().CopyTo(array, list.Count); + return; + } + + Array.Sort(array, comparer); + } + + /// + /// Checks if the given array or collection is null or has no elements. + /// + /// + /// + public static bool HasLength(ICollection collection) + { + return collection != null && collection.Count > 0; + } + + /// + /// Tests equality of two single-dimensional arrays by checking each element + /// for equality. + /// + /// The first array to be checked. + /// The second array to be checked. + /// True if arrays are the same, false otherwise. + public static bool AreEqual(Array a, Array b) + { + if (a == null && b == null) + { return true; } - /// - /// Use this sort method instead of to overcome - /// bugs in Mono. - /// - public static void Sort(Array array, IComparer comparer) + if (a != null && b != null) { - if (SystemUtils.MonoRuntime) + if (a.Length == b.Length) { - ArrayList list = new ArrayList(array); - list.Sort(comparer); - list.ToArray().CopyTo(array, list.Count); - return; - } - Array.Sort(array, comparer); - } - /// - /// Checks if the given array or collection is null or has no elements. - /// - /// - /// - public static bool HasLength(ICollection collection) - { - return collection != null && collection.Count > 0; - } - - /// - /// Tests equality of two single-dimensional arrays by checking each element - /// for equality. - /// - /// The first array to be checked. - /// The second array to be checked. - /// True if arrays are the same, false otherwise. - public static bool AreEqual(Array a, Array b) - { - if (a == null && b == null) - { - return true; - } - - if (a != null && b != null) - { - if (a.Length == b.Length) + for (int i = 0; i < a.Length; i++) { - for (int i = 0; i < a.Length; i++) - { - object elemA = a.GetValue(i); - object elemB = b.GetValue(i); + object elemA = a.GetValue(i); + object elemB = b.GetValue(i); - if (elemA is Array && elemB is Array) - { - if (!AreEqual(elemA as Array, elemB as Array)) - { - return false; - } - } - else if (!Equals(elemA, elemB)) + if (elemA is Array && elemB is Array) + { + if (!AreEqual(elemA as Array, elemB as Array)) { return false; } } - return true; + else if (!Equals(elemA, elemB)) + { + return false; + } } + + return true; } - return false; } - /// - /// Returns hash code for an array that is generated based on the elements. - /// - /// - /// Hash code returned by this method is guaranteed to be the same for - /// arrays with equal elements. - /// - /// - /// Array to calculate hash code for. - /// - /// - /// A hash code for the specified array. - /// - public static int GetHashCode(Array array) - { - int hashCode = 0; + return false; + } - if (array != null) + /// + /// Returns hash code for an array that is generated based on the elements. + /// + /// + /// Hash code returned by this method is guaranteed to be the same for + /// arrays with equal elements. + /// + /// + /// Array to calculate hash code for. + /// + /// + /// A hash code for the specified array. + /// + public static int GetHashCode(Array array) + { + int hashCode = 0; + + if (array != null) + { + for (int i = 0; i < array.Length; i++) { - for (int i = 0; i < array.Length; i++) + object el = array.GetValue(i); + if (el != null) { - object el = array.GetValue(i); - if (el != null) + if (el is Array) { - if (el is Array) - { - hashCode += 17 * GetHashCode(el as Array); - } - else - { - hashCode += 13 * el.GetHashCode(); - } + hashCode += 17 * GetHashCode(el as Array); + } + else + { + hashCode += 13 * el.GetHashCode(); } } } - - return hashCode; } - /// - /// Returns string representation of an array. - /// - /// - /// Array to return as a string. - /// - /// - /// String representation of the specified . - /// - public static string ToString(Array array) + return hashCode; + } + + /// + /// Returns string representation of an array. + /// + /// + /// Array to return as a string. + /// + /// + /// String representation of the specified . + /// + public static string ToString(Array array) + { + if (array == null) { - if (array == null) - { - return "null"; - } - - StringBuilder sb = new StringBuilder(); - sb.Append('{'); - - for (int i = 0; i < array.Length; i++) - { - object val = array.GetValue(i); - sb.Append(val == null ? "null" : val.ToString()); - - if (i < array.Length - 1) - { - sb.Append(", "); - } - } - - sb.Append('}'); - - return sb.ToString(); + return "null"; } - /// - /// Concatenates 2 arrays of compatible element types - /// - /// - /// If either of the arguments is null, the other array is returned as the result. - /// The array element types may differ as long as they are assignable. The result array will be of the "smaller" element type. - /// - public static Array Concat(Array first, Array second) + StringBuilder sb = new StringBuilder(); + sb.Append('{'); + + for (int i = 0; i < array.Length; i++) { - if (first == null) return second; - if (second == null) return first; + object val = array.GetValue(i); + sb.Append(val == null ? "null" : val.ToString()); - Type resultElementType; - Type firstElementType = first.GetType().GetElementType(); - Type secondElementType = second.GetType().GetElementType(); - if (firstElementType.IsAssignableFrom(secondElementType)) + if (i < array.Length - 1) { - resultElementType = firstElementType; + sb.Append(", "); } - else if (secondElementType.IsAssignableFrom(firstElementType)) - { - resultElementType = secondElementType; - } - else - { - throw new ArgumentException(string.Format("Array element types '{0}' and '{1}' are not compatible", firstElementType, secondElementType)); - } - Array result = Array.CreateInstance(resultElementType, first.Length + second.Length); - Array.Copy( first, result, first.Length ); - Array.Copy(second, 0, result, first.Length, second.Length); - return result; } + + sb.Append('}'); + + return sb.ToString(); + } + + /// + /// Concatenates 2 arrays of compatible element types + /// + /// + /// If either of the arguments is null, the other array is returned as the result. + /// The array element types may differ as long as they are assignable. The result array will be of the "smaller" element type. + /// + public static Array Concat(Array first, Array second) + { + if (first == null) return second; + if (second == null) return first; + + Type resultElementType; + Type firstElementType = first.GetType().GetElementType(); + Type secondElementType = second.GetType().GetElementType(); + if (firstElementType.IsAssignableFrom(secondElementType)) + { + resultElementType = firstElementType; + } + else if (secondElementType.IsAssignableFrom(firstElementType)) + { + resultElementType = secondElementType; + } + else + { + throw new ArgumentException(string.Format("Array element types '{0}' and '{1}' are not compatible", firstElementType, secondElementType)); + } + + Array result = Array.CreateInstance(resultElementType, first.Length + second.Length); + Array.Copy(first, result, first.Length); + Array.Copy(second, 0, result, first.Length, second.Length); + return result; } } diff --git a/src/Spring/Spring.Core/Util/AssertUtils.cs b/src/Spring/Spring.Core/Util/AssertUtils.cs index 8b6f0043..63a9a786 100644 --- a/src/Spring/Spring.Core/Util/AssertUtils.cs +++ b/src/Spring/Spring.Core/Util/AssertUtils.cs @@ -23,77 +23,77 @@ using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Remoting; -namespace Spring.Util +namespace Spring.Util; + +/// +/// Assertion utility methods that simplify things such as argument checks. +/// +/// +///

+/// Not intended to be used directly by applications. +///

+///
+/// Aleksandar Seovic +/// Erich Eichinger +public static class AssertUtils { - /// - /// Assertion utility methods that simplify things such as argument checks. - /// - /// - ///

- /// Not intended to be used directly by applications. - ///

- ///
- /// Aleksandar Seovic - /// Erich Eichinger - public static class AssertUtils - { - /// - /// Checks, whether may be invoked on . - /// Supports testing transparent proxies. - /// - ///the target instance or null - ///the name of the target to be used in error messages - ///the method to test for - /// - /// if is null - /// - /// - /// if it is not possible to invoke on - /// - public static void Understands(object target, string targetName, MethodBase method) + /// + /// Checks, whether may be invoked on . + /// Supports testing transparent proxies. + /// + ///the target instance or null + ///the name of the target to be used in error messages + ///the method to test for + /// + /// if is null + /// + /// + /// if it is not possible to invoke on + /// + public static void Understands(object target, string targetName, MethodBase method) + { + ArgumentNotNull(method, "method"); + + if (target == null) { - ArgumentNotNull(method, "method"); - - if (target == null) - { - if (method.IsStatic) - { - return; - } - - ThrowNotSupportedException( - $"Target '{targetName}' is null and target method '{method.DeclaringType.FullName}.{method.Name}' is not static."); - } - - Understands(target, targetName, method.DeclaringType); - } - - /// - /// checks, whether supports the methods of . - /// Supports testing transparent proxies. - /// - ///the target instance or null - ///the name of the target to be used in error messages - ///the type to test for - /// - /// if is null - /// - /// - /// if it is not possible to invoke methods of - /// type on - /// - public static void Understands(object target, string targetName, Type requiredType) - { - ArgumentNotNull(requiredType, "requiredType"); - - if (target == null) + if (method.IsStatic) { - ThrowNotSupportedException($"Target '{targetName}' is null."); + return; } - Type targetType = null; - if (RemotingServices.IsTransparentProxy(target)) - { + ThrowNotSupportedException( + $"Target '{targetName}' is null and target method '{method.DeclaringType.FullName}.{method.Name}' is not static."); + } + + Understands(target, targetName, method.DeclaringType); + } + + /// + /// checks, whether supports the methods of . + /// Supports testing transparent proxies. + /// + ///the target instance or null + ///the name of the target to be used in error messages + ///the type to test for + /// + /// if is null + /// + /// + /// if it is not possible to invoke methods of + /// type on + /// + public static void Understands(object target, string targetName, Type requiredType) + { + ArgumentNotNull(requiredType, "requiredType"); + + if (target == null) + { + ThrowNotSupportedException($"Target '{targetName}' is null."); + } + + Type targetType = null; + if (RemotingServices.IsTransparentProxy(target)) + { #if !NETSTANDARD System.Runtime.Remoting.Proxies.RealProxy rp = RemotingServices.GetRealProxy(target); IRemotingTypeInfo rti = rp as IRemotingTypeInfo; @@ -103,264 +103,265 @@ namespace Spring.Util { return; } - ThrowNotSupportedException( - $"Target '{targetName}' is a transparent proxy that does not support methods of '{requiredType.FullName}'."); + + ThrowNotSupportedException( + $"Target '{targetName}' is a transparent proxy that does not support methods of '{requiredType.FullName}'."); } + targetType = rp.GetProxiedType(); #endif - } - else - { - targetType = target.GetType(); - } - - if (!requiredType.IsAssignableFrom(targetType)) - { - ThrowNotSupportedException($"Target '{targetName}' of type '{targetType}' does not support methods of '{requiredType.FullName}'."); - } } - - /// - /// Checks the value of the supplied and throws an - /// if it is . - /// - /// The object to check. - /// The argument name. - /// - /// If the supplied is . - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void ArgumentNotNull(object argument, string name) - { - if (argument == null) - { - ThrowArgumentNullException(name); - } - } - - /// - /// Checks the value of the supplied and throws an - /// if it is . - /// - /// The object to check. - /// The argument name. - /// - /// An arbitrary message that will be passed to any thrown - /// . - /// - /// - /// If the supplied is . - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void ArgumentNotNull(object argument, string name, string message) - { - if (argument == null) - { - ThrowArgumentNullException(name, message); - } - } - - /// - /// Checks the value of the supplied string and throws an - /// if it is or - /// contains only whitespace character(s). - /// - /// The string to check. - /// The argument name. - /// - /// If the supplied is or - /// contains only whitespace character(s). - /// - public static void ArgumentHasText(string argument, string name) - { - if (StringUtils.IsNullOrEmpty(argument)) - { - ThrowArgumentNullException( - name, - $"Argument '{name}' cannot be null or resolve to an empty string : '{argument}'."); - } - } - - /// - /// Checks the value of the supplied string and throws an - /// if it is or - /// contains only whitespace character(s). - /// - /// The string to check. - /// The argument name. - /// - /// An arbitrary message that will be passed to any thrown - /// . - /// - /// - /// If the supplied is or - /// contains only whitespace character(s). - /// - public static void ArgumentHasText(string argument, string name, string message) - { - if (StringUtils.IsNullOrEmpty(argument)) - { - ThrowArgumentNullException(name, message); - } - } - - /// - /// Checks the value of the supplied and throws - /// an if it is or contains no elements. - /// - /// The array or collection to check. - /// The argument name. - /// - /// If the supplied is or - /// contains no elements. - /// - public static void ArgumentHasLength(ICollection argument, string name) + else { - if (!ArrayUtils.HasLength(argument)) - { - ThrowArgumentNullException( - name, - $"Argument '{name}' cannot be null or resolve to an empty array"); - } + targetType = target.GetType(); } - /// - /// Checks the value of the supplied and throws - /// an if it is or contains no elements. - /// - /// The array or collection to check. - /// The argument name. - /// An arbitrary message that will be passed to any thrown . - /// - /// If the supplied is or - /// contains no elements. - /// - public static void ArgumentHasLength(ICollection argument, string name, string message) + if (!requiredType.IsAssignableFrom(targetType)) { - if(!ArrayUtils.HasLength(argument)) - { - ThrowArgumentNullException(name, message); - } + ThrowNotSupportedException($"Target '{targetName}' of type '{targetType}' does not support methods of '{requiredType.FullName}'."); } + } - /// - /// Checks the value of the supplied and throws - /// an if it is , contains no elements or only null elements. - /// - /// The array or collection to check. - /// The argument name. - /// - /// If the supplied is , - /// contains no elements or only null elements. - /// - public static void ArgumentHasElements(ICollection argument, string name) + /// + /// Checks the value of the supplied and throws an + /// if it is . + /// + /// The object to check. + /// The argument name. + /// + /// If the supplied is . + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void ArgumentNotNull(object argument, string name) + { + if (argument == null) { - if (!ArrayUtils.HasElements(argument)) - { - ThrowArgumentException( - name, - $"Argument '{name}' must not be null or resolve to an empty collection and must contain non-null elements"); - } + ThrowArgumentNullException(name); } + } - /// - /// Checks whether the specified can be cast - /// into the . - /// - /// - /// The argument to check. - /// - /// - /// The name of the argument to check. - /// - /// - /// The required type for the argument. - /// - /// - /// An arbitrary message that will be passed to any thrown - /// . - /// - public static void AssertArgumentType(object argument, string argumentName, Type requiredType, string message) + /// + /// Checks the value of the supplied and throws an + /// if it is . + /// + /// The object to check. + /// The argument name. + /// + /// An arbitrary message that will be passed to any thrown + /// . + /// + /// + /// If the supplied is . + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void ArgumentNotNull(object argument, string name, string message) + { + if (argument == null) { - if (argument != null && requiredType != null && !requiredType.IsInstanceOfType(argument)) - { - ThrowArgumentException(message, argumentName); - } + ThrowArgumentNullException(name, message); } + } - /// - /// Assert a boolean expression, throwing ArgumentException - /// if the test result is false. - /// - /// a boolean expression. - /// The exception message to use if the assertion fails. - /// - /// if expression is false - /// - public static void IsTrue(bool expression, string message) + /// + /// Checks the value of the supplied string and throws an + /// if it is or + /// contains only whitespace character(s). + /// + /// The string to check. + /// The argument name. + /// + /// If the supplied is or + /// contains only whitespace character(s). + /// + public static void ArgumentHasText(string argument, string name) + { + if (StringUtils.IsNullOrEmpty(argument)) { - if (!expression) - { - ThrowArgumentException(message); - } + ThrowArgumentNullException( + name, + $"Argument '{name}' cannot be null or resolve to an empty string : '{argument}'."); } + } - /// - /// Assert a boolean expression, throwing ArgumentException - /// if the test result is false. - /// - /// a boolean expression. - /// - /// if expression is false - /// - public static void IsTrue(bool expression) + /// + /// Checks the value of the supplied string and throws an + /// if it is or + /// contains only whitespace character(s). + /// + /// The string to check. + /// The argument name. + /// + /// An arbitrary message that will be passed to any thrown + /// . + /// + /// + /// If the supplied is or + /// contains only whitespace character(s). + /// + public static void ArgumentHasText(string argument, string name, string message) + { + if (StringUtils.IsNullOrEmpty(argument)) { - IsTrue(expression, "[Assertion failed] - this expression must be true"); + ThrowArgumentNullException(name, message); } + } - /// - /// Assert a bool expression, throwing InvalidOperationException - /// if the expression is false. - /// - /// a boolean expression. - /// The exception message to use if the assertion fails - /// if expression is false - public static void State(bool expression, string message) + /// + /// Checks the value of the supplied and throws + /// an if it is or contains no elements. + /// + /// The array or collection to check. + /// The argument name. + /// + /// If the supplied is or + /// contains no elements. + /// + public static void ArgumentHasLength(ICollection argument, string name) + { + if (!ArrayUtils.HasLength(argument)) { - if (!expression) - { - ThrowInvalidOperationException(message); - } + ThrowArgumentNullException( + name, + $"Argument '{name}' cannot be null or resolve to an empty array"); } + } - private static void ThrowInvalidOperationException(string message) - { - throw new InvalidOperationException(message); - } + /// + /// Checks the value of the supplied and throws + /// an if it is or contains no elements. + /// + /// The array or collection to check. + /// The argument name. + /// An arbitrary message that will be passed to any thrown . + /// + /// If the supplied is or + /// contains no elements. + /// + public static void ArgumentHasLength(ICollection argument, string name, string message) + { + if (!ArrayUtils.HasLength(argument)) + { + ThrowArgumentNullException(name, message); + } + } - private static void ThrowNotSupportedException(string message) - { - throw new NotSupportedException(message); - } + /// + /// Checks the value of the supplied and throws + /// an if it is , contains no elements or only null elements. + /// + /// The array or collection to check. + /// The argument name. + /// + /// If the supplied is , + /// contains no elements or only null elements. + /// + public static void ArgumentHasElements(ICollection argument, string name) + { + if (!ArrayUtils.HasElements(argument)) + { + ThrowArgumentException( + name, + $"Argument '{name}' must not be null or resolve to an empty collection and must contain non-null elements"); + } + } - private static void ThrowArgumentNullException(string paramName) - { - throw new ArgumentNullException(paramName, $"Argument '{paramName}' cannot be null."); - } + /// + /// Checks whether the specified can be cast + /// into the . + /// + /// + /// The argument to check. + /// + /// + /// The name of the argument to check. + /// + /// + /// The required type for the argument. + /// + /// + /// An arbitrary message that will be passed to any thrown + /// . + /// + public static void AssertArgumentType(object argument, string argumentName, Type requiredType, string message) + { + if (argument != null && requiredType != null && !requiredType.IsInstanceOfType(argument)) + { + ThrowArgumentException(message, argumentName); + } + } - private static void ThrowArgumentNullException(string paramName, string message) - { - throw new ArgumentNullException(paramName, message); - } + /// + /// Assert a boolean expression, throwing ArgumentException + /// if the test result is false. + /// + /// a boolean expression. + /// The exception message to use if the assertion fails. + /// + /// if expression is false + /// + public static void IsTrue(bool expression, string message) + { + if (!expression) + { + ThrowArgumentException(message); + } + } - private static void ThrowArgumentException(string message) - { - throw new ArgumentException(message); - } + /// + /// Assert a boolean expression, throwing ArgumentException + /// if the test result is false. + /// + /// a boolean expression. + /// + /// if expression is false + /// + public static void IsTrue(bool expression) + { + IsTrue(expression, "[Assertion failed] - this expression must be true"); + } - private static void ThrowArgumentException(string message, string paramName) - { - throw new ArgumentException(message, paramName); - } - } -} + /// + /// Assert a bool expression, throwing InvalidOperationException + /// if the expression is false. + /// + /// a boolean expression. + /// The exception message to use if the assertion fails + /// if expression is false + public static void State(bool expression, string message) + { + if (!expression) + { + ThrowInvalidOperationException(message); + } + } + + private static void ThrowInvalidOperationException(string message) + { + throw new InvalidOperationException(message); + } + + private static void ThrowNotSupportedException(string message) + { + throw new NotSupportedException(message); + } + + private static void ThrowArgumentNullException(string paramName) + { + throw new ArgumentNullException(paramName, $"Argument '{paramName}' cannot be null."); + } + + private static void ThrowArgumentNullException(string paramName, string message) + { + throw new ArgumentNullException(paramName, message); + } + + private static void ThrowArgumentException(string message) + { + throw new ArgumentException(message); + } + + private static void ThrowArgumentException(string message, string paramName) + { + throw new ArgumentException(message, paramName); + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Util/AttributeUtils.cs b/src/Spring/Spring.Core/Util/AttributeUtils.cs index c405c8bc..8626f108 100644 --- a/src/Spring/Spring.Core/Util/AttributeUtils.cs +++ b/src/Spring/Spring.Core/Util/AttributeUtils.cs @@ -1,83 +1,86 @@ -namespace Spring.Util +namespace Spring.Util; + +/// +/// General utility methods for working with annotations +/// +public class AttributeUtils { /// - /// General utility methods for working with annotations + /// Find a single Attribute of the type 'attributeType' from the supplied class, + /// traversing it interfaces and super classes if no attribute can be found on the + /// class iteslf. /// - public class AttributeUtils + /// + /// This method explicitly handles class-level attributes which are not declared as + /// inherited as well as attributes on interfaces. + /// + /// The class to look for attributes on . + /// Type of the attribibute to look for. + /// the attribute of the given type found, or null + public static Attribute FindAttribute(Type type, Type attributeType) { - /// - /// Find a single Attribute of the type 'attributeType' from the supplied class, - /// traversing it interfaces and super classes if no attribute can be found on the - /// class iteslf. - /// - /// - /// This method explicitly handles class-level attributes which are not declared as - /// inherited as well as attributes on interfaces. - /// - /// The class to look for attributes on . - /// Type of the attribibute to look for. - /// the attribute of the given type found, or null - public static Attribute FindAttribute(Type type, Type attributeType) + Attribute[] attributes = Attribute.GetCustomAttributes(type, attributeType, false); // we will traverse hierarchy ourselves. + if (attributes.Length > 0) { - Attribute[] attributes = Attribute.GetCustomAttributes(type, attributeType, false); // we will traverse hierarchy ourselves. - if (attributes.Length > 0) - { - return attributes[0]; - } - foreach (Type interfaceType in type.GetInterfaces()) - { - Attribute attrib = FindAttribute(interfaceType, attributeType); - if (attrib != null) - { - return attrib; - } - } - if (type.BaseType == null) - { - return null; - } - return FindAttribute(type.BaseType, attributeType); + return attributes[0]; } - /// - /// Get all attribute properties with values for a specific attribute type - /// - /// attribute to check against - /// collection of all properties with values - public static IDictionary GetAttributeProperties(Attribute attribute) + foreach (Type interfaceType in type.GetInterfaces()) { - Type attributeType = attribute.GetType(); - IDictionary attributes = new Dictionary(); - foreach(var property in attributeType.GetProperties()) + Attribute attrib = FindAttribute(interfaceType, attributeType); + if (attrib != null) { - object value = property.GetValue(attribute, null); - attributes.Add(property.Name, value); + return attrib; } - return attributes; } - /// - /// Get the default name value of an attribute and a specific property - /// - /// attribute from where to get the default value - /// property to get the default value - /// - public static object GetDefaultValue(Attribute attribute, string propertyName) + if (type.BaseType == null) { - Type attributeType = attribute.GetType(); - try - { - var property = attributeType.GetProperty(propertyName); - if (property == null) - return null; - var instance = Activator.CreateInstance(attributeType); + return null; + } - return property.GetValue(instance, null); - } - catch (Exception) - { + return FindAttribute(type.BaseType, attributeType); + } + + /// + /// Get all attribute properties with values for a specific attribute type + /// + /// attribute to check against + /// collection of all properties with values + public static IDictionary GetAttributeProperties(Attribute attribute) + { + Type attributeType = attribute.GetType(); + IDictionary attributes = new Dictionary(); + foreach (var property in attributeType.GetProperties()) + { + object value = property.GetValue(attribute, null); + attributes.Add(property.Name, value); + } + + return attributes; + } + + /// + /// Get the default name value of an attribute and a specific property + /// + /// attribute from where to get the default value + /// property to get the default value + /// + public static object GetDefaultValue(Attribute attribute, string propertyName) + { + Type attributeType = attribute.GetType(); + try + { + var property = attributeType.GetProperty(propertyName); + if (property == null) return null; - } + var instance = Activator.CreateInstance(attributeType); + + return property.GetValue(instance, null); + } + catch (Exception) + { + return null; } } } diff --git a/src/Spring/Spring.Core/Util/CollectionUtils.cs b/src/Spring/Spring.Core/Util/CollectionUtils.cs index ec9f93fe..a439d2eb 100644 --- a/src/Spring/Spring.Core/Util/CollectionUtils.cs +++ b/src/Spring/Spring.Core/Util/CollectionUtils.cs @@ -17,550 +17,574 @@ using System.Collections; using System.Reflection; -namespace Spring.Util +namespace Spring.Util; + +/// +/// Miscellaneous collection utility methods. +/// +/// +/// Mainly for internal use within the framework. +/// +/// Mark Pollack (.NET) +public sealed class CollectionUtils { /// - /// Miscellaneous collection utility methods. + /// Checks if the given array or collection has elements and none of the elements is null. /// - /// - /// Mainly for internal use within the framework. - /// - /// Mark Pollack (.NET) - public sealed class CollectionUtils + /// the collection to be checked. + /// true if the collection has a length and contains only non-null elements. + public static bool HasElements(ICollection collection) { - /// - /// Checks if the given array or collection has elements and none of the elements is null. - /// - /// the collection to be checked. - /// true if the collection has a length and contains only non-null elements. - public static bool HasElements(ICollection collection) + return ArrayUtils.HasElements(collection); + } + + /// + /// Checks if the given array or collection is null or has no elements. + /// + /// + /// + public static bool HasLength(ICollection collection) + { + return ArrayUtils.HasLength(collection); + } + + /// + /// Determine whether a given collection only contains + /// a single unique object + /// + /// + /// + public static bool HasUniqueObject(ICollection coll) + { + if (coll.Count == 0) { - return ArrayUtils.HasElements(collection); + return false; } - /// - /// Checks if the given array or collection is null or has no elements. - /// - /// - /// - public static bool HasLength(ICollection collection) + object candidate = null; + foreach (object elem in coll) { - return ArrayUtils.HasLength(collection); - } - - /// - /// Determine whether a given collection only contains - /// a single unique object - /// - /// - /// - public static bool HasUniqueObject(ICollection coll) - { - if (coll.Count == 0) + if (candidate == null) + { + candidate = elem; + } + else if (candidate != elem) { return false; } - object candidate = null; - foreach (object elem in coll) + } + + return true; + } + + /// + /// Determines whether the contains the specified . + /// + /// The collection to check. + /// The object to locate in the collection. + /// if the element is in the collection, otherwise. + public static bool Contains(IEnumerable collection, Object element) + { + if (collection == null) + { + return false; + } + + if (collection is IList) + { + return ((IList) collection).Contains(element); + } + + if (collection is IDictionary) + { + return ((IDictionary) collection).Contains(element); + } + + MethodInfo method = collection.GetType().GetMethod("contains", BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public); + if (null != method) + { + return (bool) method.Invoke(collection, new Object[] { element }); + } + + foreach (object item in collection) + { + if (object.Equals(item, element)) { - if (candidate == null) - { - candidate = elem; - } - else if (candidate != elem) - { - return false; - } + return true; } + } + + return false; + } + + /// + /// Adds the specified to the specified . + /// + /// The collection to add the element to. + /// The object to add to the collection. + public static void Add(ICollection collection, object element) + { + Add((IEnumerable) collection, element); + } + + /// + /// Adds the specified to the specified . + /// + /// The enumerable to add the element to. + /// The object to add to the collection. + public static void Add(IEnumerable enumerable, object element) + { + if (enumerable == null) + { + throw new ArgumentNullException("enumerable", "Collection cannot be null."); + } + + if (enumerable is IList) + { + ((IList) enumerable).Add(element); + return; + } + + MethodInfo method; + method = enumerable.GetType().GetMethod("add", BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public); + if (null == method) + { + throw new InvalidOperationException("Enumerable type " + enumerable.GetType() + " does not implement a Add() method."); + } + + method.Invoke(enumerable, new Object[] { element }); + } + + /// + /// Determines whether the collection contains all the elements in the specified collection. + /// + /// The collection to check. + /// Collection whose elements would be checked for containment. + /// true if the target collection contains all the elements of the specified collection. + public static bool ContainsAll(ICollection targetCollection, ICollection sourceCollection) + { + if (targetCollection == null) + { + throw new ArgumentNullException("targetCollection", "Collection cannot be null."); + } + + if (sourceCollection == null) + { + throw new ArgumentNullException("sourceCollection", "Collection cannot be null."); + } + + if (sourceCollection.Count == 0 && targetCollection.Count > 1) return true; - } - /// - /// Determines whether the contains the specified . - /// - /// The collection to check. - /// The object to locate in the collection. - /// if the element is in the collection, otherwise. - public static bool Contains(IEnumerable collection, Object element) + IEnumerator sourceCollectionEnumerator = sourceCollection.GetEnumerator(); + + bool contains = false; + + MethodInfo method; + method = targetCollection.GetType().GetMethod("containsAll", BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public); + + if (method != null) + contains = (bool) method.Invoke(targetCollection, new Object[] { sourceCollection }); + else { - if (collection == null) + method = targetCollection.GetType().GetMethod("Contains", BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public); + if (method == null) { - return false; + throw new InvalidOperationException("Target collection does not implment a Contains() or ContainsAll() method."); } - if (collection is IList) + while (sourceCollectionEnumerator.MoveNext() == true) { - return ((IList) collection).Contains(element); - } - - if (collection is IDictionary) - { - return ((IDictionary) collection).Contains(element); - } - - MethodInfo method = collection.GetType().GetMethod("contains", BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public); - if (null != method) - { - return (bool)method.Invoke(collection, new Object[] { element }); - } - foreach (object item in collection) - { - if (object.Equals(item, element)) - { - return true; - } - } - return false; - } - - /// - /// Adds the specified to the specified . - /// - /// The collection to add the element to. - /// The object to add to the collection. - public static void Add(ICollection collection, object element) - { - Add((IEnumerable)collection, element); - } - - /// - /// Adds the specified to the specified . - /// - /// The enumerable to add the element to. - /// The object to add to the collection. - public static void Add(IEnumerable enumerable, object element) - { - if (enumerable == null) - { - throw new ArgumentNullException("enumerable", "Collection cannot be null."); - } - if (enumerable is IList) - { - ((IList)enumerable).Add(element); - return; - } - MethodInfo method; - method = enumerable.GetType().GetMethod("add", BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public); - if (null == method) - { - throw new InvalidOperationException("Enumerable type " + enumerable.GetType() + " does not implement a Add() method."); - } - method.Invoke(enumerable, new Object[] { element }); - } - - /// - /// Determines whether the collection contains all the elements in the specified collection. - /// - /// The collection to check. - /// Collection whose elements would be checked for containment. - /// true if the target collection contains all the elements of the specified collection. - public static bool ContainsAll(ICollection targetCollection, ICollection sourceCollection) - { - if (targetCollection == null) - { - throw new ArgumentNullException("targetCollection", "Collection cannot be null."); - } - if (sourceCollection == null) - { - throw new ArgumentNullException("sourceCollection", "Collection cannot be null."); - } - if (sourceCollection.Count == 0 && targetCollection.Count > 1) - return true; - - IEnumerator sourceCollectionEnumerator = sourceCollection.GetEnumerator(); - - bool contains = false; - - MethodInfo method; - method = targetCollection.GetType().GetMethod("containsAll", BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public); - - if (method != null) - contains = (bool)method.Invoke(targetCollection, new Object[] { sourceCollection }); - else - { - method = targetCollection.GetType().GetMethod("Contains", BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public); - if (method == null) - { - throw new InvalidOperationException("Target collection does not implment a Contains() or ContainsAll() method."); - } - while (sourceCollectionEnumerator.MoveNext() == true) - { - if ((contains = (bool)method.Invoke(targetCollection, new Object[] { sourceCollectionEnumerator.Current })) == false) - break; - } - } - return contains; - } - - /// - /// Removes all the elements from the target collection that are contained in the source collection. - /// - /// Collection where the elements will be removed. - /// Elements to remove from the target collection. - public static void RemoveAll(ICollection targetCollection, ICollection sourceCollection) - { - if (targetCollection == null || sourceCollection == null) - { - throw new ArgumentNullException("Collection cannot be null."); - } - ArrayList al = ToArrayList(sourceCollection); - - MethodInfo method; - method = targetCollection.GetType().GetMethod("removeAll", BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public); - - if (method != null) - method.Invoke(targetCollection, new Object[] { al }); - else - { - method = targetCollection.GetType().GetMethod("Remove", BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(object) }, null); - MethodInfo methodContains = targetCollection.GetType().GetMethod("Contains", BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public); - if (method == null) - { - throw new InvalidOperationException("Target Collection must implement either a RemoveAll() or Remove() method."); - } - if (methodContains == null) - { - throw new InvalidOperationException("TargetCollection must implement a Contains() method."); - } - IEnumerator e = al.GetEnumerator(); - while (e.MoveNext() == true) - { - while ((bool)methodContains.Invoke(targetCollection, new Object[] { e.Current }) == true) - method.Invoke(targetCollection, new Object[] { e.Current }); - } + if ((contains = (bool) method.Invoke(targetCollection, new Object[] { sourceCollectionEnumerator.Current })) == false) + break; } } - /// - /// Converts an instance to an instance. - /// - /// The instance to be converted. - /// An instance in which its elements are the elements of the instance. - /// if the is null. - public static ArrayList ToArrayList(ICollection inputCollection) + return contains; + } + + /// + /// Removes all the elements from the target collection that are contained in the source collection. + /// + /// Collection where the elements will be removed. + /// Elements to remove from the target collection. + public static void RemoveAll(ICollection targetCollection, ICollection sourceCollection) + { + if (targetCollection == null || sourceCollection == null) { - if (inputCollection == null) - { - throw new ArgumentNullException("Collection cannot be null."); - } - return new ArrayList(inputCollection); + throw new ArgumentNullException("Collection cannot be null."); } - /// - /// Copies the elements of the to a - /// new array of the specified element type. - /// - /// The instance to be converted. - /// The element of the destination array to create and copy elements to - /// An array of the specified element type containing copies of the elements of the . - public static Array ToArray(ICollection inputCollection, Type elementType) + ArrayList al = ToArrayList(sourceCollection); + + MethodInfo method; + method = targetCollection.GetType().GetMethod("removeAll", BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public); + + if (method != null) + method.Invoke(targetCollection, new Object[] { al }); + else { - Array array = Array.CreateInstance(elementType, inputCollection.Count); - inputCollection.CopyTo(array, 0); - return array; - } - - /// - /// Returns the first element contained in both, and . - /// - /// The implementation assumes that <<< - /// the source enumerable. may be null - /// the list of candidates to match against elements. may be null - /// the first element found in both enumerables or null - public static object FindFirstMatch(IEnumerable source, IEnumerable candidates) - { - if (IsEmpty(source) || IsEmpty(candidates)) + method = targetCollection.GetType().GetMethod("Remove", BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(object) }, null); + MethodInfo methodContains = targetCollection.GetType().GetMethod("Contains", BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public); + if (method == null) { - return null; + throw new InvalidOperationException("Target Collection must implement either a RemoveAll() or Remove() method."); } - IList candidateList = candidates as IList; - if (candidateList == null) + if (methodContains == null) { - if (candidates is ICollection) - { - candidateList = new ArrayList((ICollection)candidates); - } - else - { - candidateList = new ArrayList(); - foreach (object el in candidates) - { - candidateList.Add(el); - } - } + throw new InvalidOperationException("TargetCollection must implement a Contains() method."); } - foreach (object sourceElement in source) + IEnumerator e = al.GetEnumerator(); + while (e.MoveNext() == true) { - if (candidateList.Contains(sourceElement)) - { - return sourceElement; - } - } - return null; - } - - /// - /// Finds a value of the given type in the given collection. - /// - /// The collection to search. - /// The type to look for. - /// a value of the given type found, or null if none. - /// If more than one value of the given type is found - public static object FindValueOfType(ICollection collection, Type type) - { - if (IsEmpty(collection)) - { - return null; - } - Type typeToUse = (type != null ? type : typeof(object)); - object val = null; - foreach (object obj in collection) - { - if (typeToUse.IsAssignableFrom(obj.GetType())) - { - if (val != null) - { - throw new ArgumentException("More than one value of type[" + typeToUse.Name + "] found."); - } - val = obj; - } - } - return val; - } - - /// - /// Finds a value of the given type in the given collection. - /// - /// The collection to search. - /// The type to look for. - /// a collection of matching values of the given type found, empty if none found, or null if the input collection was null. - public static ICollection FindValuesOfType(IEnumerable collection, Type type) - { - if (IsEmpty(collection)) - { - return null; - } - Type typeToUse = (type != null ? type : typeof(object)); - ArrayList results = new ArrayList(); - foreach (object obj in collection) - { - if (typeToUse.IsAssignableFrom(obj.GetType())) - { - results.Add(obj); - } - } - return results; - } - - /// - /// Find a value of one of the given types in the given Collection, - /// searching the Collection for a value of the first type, then - /// searching for a value of the second type, etc. - /// - /// The collection to search. - /// The types to look for, in prioritized order. - /// a value of the given types found, or null if none - /// If more than one value of the given type is found - public static object FindValueOfType(ICollection collection, Type[] types) - { - if (IsEmpty(collection) || ObjectUtils.IsEmpty(types)) - { - return null; - } - foreach (Type type in types) - { - object val = FindValueOfType(collection, type); - if (val != null) - { - return val; - } - } - return null; - } - - /// - /// Determines whether the specified collection is null or empty. - /// - /// The collection to check. - /// - /// true if the specified collection is empty or null; otherwise, false. - /// - public static bool IsEmpty(IEnumerable enumerable) - { - if (enumerable == null) - return true; - - if (enumerable is ICollection) - { - return (0 == ((ICollection)enumerable).Count); - } - - IEnumerator it = enumerable.GetEnumerator(); - if (!it.MoveNext()) - { - return true; - } - return false; - } - - /// - /// Determines whether the specified collection is null or empty. - /// - /// The collection to check. - /// - /// true if the specified collection is empty or null; otherwise, false. - /// - public static bool IsEmpty(ICollection collection) - { - return (collection == null || collection.Count == 0); - } - - /// - /// Determines whether the specified dictionary is null empty. - /// - /// The dictionary to check. - /// - /// true if the specified dictionary is empty or null; otherwise, false. - /// - public static bool IsEmpty(IDictionary dictionary) - { - return (dictionary == null || dictionary.Count == 0); - } - - /// - /// A callback method used for comparing to items. - /// - /// - /// - /// the first object to compare - /// the second object to compare - /// Value Condition Less than zero x is less than y. Zero x equals y. Greater than zero x is greater than y. - /// - /// - public delegate int CompareCallback(object left, object right); - - /// - /// A simple stable sorting routine - far from being efficient, only for small collections. - /// - /// - /// - /// - public static ICollection StableSort(IEnumerable input, IComparer comparer) - { - return StableSort(input, new CompareCallback(comparer.Compare)); - } - - /// - /// A simple stable sorting routine - far from being efficient, only for small collections. - /// - /// - /// Sorting is not(!) done in-place. Instead a sorted copy of the original input is returned. - /// - /// input collection of items to sort - /// the for comparing 2 items in . - /// a new collection of stable sorted items. - public static ICollection StableSort(IEnumerable input, CompareCallback comparer) - { - ArrayList ehancedInput = new ArrayList(); - IEnumerator it = input.GetEnumerator(); - int index = 0; - while (it.MoveNext()) - { - ehancedInput.Add(new Entry(index, it.Current)); - index++; - } - - ehancedInput.Sort(Entry.GetComparer(comparer)); - - for (int i = 0; i < ehancedInput.Count; i++) - { - ehancedInput[i] = ((Entry)ehancedInput[i]).Value; - } - - return ehancedInput; - } - - /// - /// A simple stable sorting routine - far from being efficient, only for small collections. - /// - /// - /// Sorting is not(!) done in-place. Instead a sorted copy of the original input is returned. - /// - /// input collection of items to sort - /// the for comparing 2 items in . - /// a new collection of stable sorted items. - public static void StableSortInPlace(IList input, IComparer comparer) - { - StableSortInPlace(input, new CompareCallback(comparer.Compare)); - } - - /// - /// A simple stable sorting routine - far from being efficient, only for small collections. - /// - /// - /// Sorting is not(!) done in-place. Instead a sorted copy of the original input is returned. - /// - /// input collection of items to sort - /// the for comparing 2 items in . - /// a new collection of stable sorted items. - public static void StableSortInPlace(IList input, CompareCallback comparer) - { - ArrayList ehancedInput = new ArrayList(); - IEnumerator it = input.GetEnumerator(); - int index = 0; - while (it.MoveNext()) - { - ehancedInput.Add(new Entry(index, it.Current)); - index++; - } - - ehancedInput.Sort(Entry.GetComparer(comparer)); - - for (int i = 0; i < ehancedInput.Count; i++) - { - input[i] = ((Entry)ehancedInput[i]).Value; - } - } - - private class Entry - { - private class EntryComparer : IComparer - { - private readonly CompareCallback innerComparer; - - public EntryComparer(CompareCallback innerComparer) - { - this.innerComparer = innerComparer; - } - - public int Compare(object x, object y) - { - Entry ex = (Entry)x; - Entry ey = (Entry)y; - int result = innerComparer(ex.Value, ey.Value); - if (result == 0) - { - result = ex.Index.CompareTo(ey.Index); - } - return result; - } - } - - public static IComparer GetComparer(CompareCallback innerComparer) - { - return new EntryComparer(innerComparer); - } - - public readonly int Index; - public readonly object Value; - - public Entry(int index, object value) - { - Index = index; - Value = value; + while ((bool) methodContains.Invoke(targetCollection, new Object[] { e.Current }) == true) + method.Invoke(targetCollection, new Object[] { e.Current }); } } } + + /// + /// Converts an instance to an instance. + /// + /// The instance to be converted. + /// An instance in which its elements are the elements of the instance. + /// if the is null. + public static ArrayList ToArrayList(ICollection inputCollection) + { + if (inputCollection == null) + { + throw new ArgumentNullException("Collection cannot be null."); + } + + return new ArrayList(inputCollection); + } + + /// + /// Copies the elements of the to a + /// new array of the specified element type. + /// + /// The instance to be converted. + /// The element of the destination array to create and copy elements to + /// An array of the specified element type containing copies of the elements of the . + public static Array ToArray(ICollection inputCollection, Type elementType) + { + Array array = Array.CreateInstance(elementType, inputCollection.Count); + inputCollection.CopyTo(array, 0); + return array; + } + + /// + /// Returns the first element contained in both, and . + /// + /// The implementation assumes that <<< + /// the source enumerable. may be null + /// the list of candidates to match against elements. may be null + /// the first element found in both enumerables or null + public static object FindFirstMatch(IEnumerable source, IEnumerable candidates) + { + if (IsEmpty(source) || IsEmpty(candidates)) + { + return null; + } + + IList candidateList = candidates as IList; + if (candidateList == null) + { + if (candidates is ICollection) + { + candidateList = new ArrayList((ICollection) candidates); + } + else + { + candidateList = new ArrayList(); + foreach (object el in candidates) + { + candidateList.Add(el); + } + } + } + + foreach (object sourceElement in source) + { + if (candidateList.Contains(sourceElement)) + { + return sourceElement; + } + } + + return null; + } + + /// + /// Finds a value of the given type in the given collection. + /// + /// The collection to search. + /// The type to look for. + /// a value of the given type found, or null if none. + /// If more than one value of the given type is found + public static object FindValueOfType(ICollection collection, Type type) + { + if (IsEmpty(collection)) + { + return null; + } + + Type typeToUse = (type != null ? type : typeof(object)); + object val = null; + foreach (object obj in collection) + { + if (typeToUse.IsAssignableFrom(obj.GetType())) + { + if (val != null) + { + throw new ArgumentException("More than one value of type[" + typeToUse.Name + "] found."); + } + + val = obj; + } + } + + return val; + } + + /// + /// Finds a value of the given type in the given collection. + /// + /// The collection to search. + /// The type to look for. + /// a collection of matching values of the given type found, empty if none found, or null if the input collection was null. + public static ICollection FindValuesOfType(IEnumerable collection, Type type) + { + if (IsEmpty(collection)) + { + return null; + } + + Type typeToUse = (type != null ? type : typeof(object)); + ArrayList results = new ArrayList(); + foreach (object obj in collection) + { + if (typeToUse.IsAssignableFrom(obj.GetType())) + { + results.Add(obj); + } + } + + return results; + } + + /// + /// Find a value of one of the given types in the given Collection, + /// searching the Collection for a value of the first type, then + /// searching for a value of the second type, etc. + /// + /// The collection to search. + /// The types to look for, in prioritized order. + /// a value of the given types found, or null if none + /// If more than one value of the given type is found + public static object FindValueOfType(ICollection collection, Type[] types) + { + if (IsEmpty(collection) || ObjectUtils.IsEmpty(types)) + { + return null; + } + + foreach (Type type in types) + { + object val = FindValueOfType(collection, type); + if (val != null) + { + return val; + } + } + + return null; + } + + /// + /// Determines whether the specified collection is null or empty. + /// + /// The collection to check. + /// + /// true if the specified collection is empty or null; otherwise, false. + /// + public static bool IsEmpty(IEnumerable enumerable) + { + if (enumerable == null) + return true; + + if (enumerable is ICollection) + { + return (0 == ((ICollection) enumerable).Count); + } + + IEnumerator it = enumerable.GetEnumerator(); + if (!it.MoveNext()) + { + return true; + } + + return false; + } + + /// + /// Determines whether the specified collection is null or empty. + /// + /// The collection to check. + /// + /// true if the specified collection is empty or null; otherwise, false. + /// + public static bool IsEmpty(ICollection collection) + { + return (collection == null || collection.Count == 0); + } + + /// + /// Determines whether the specified dictionary is null empty. + /// + /// The dictionary to check. + /// + /// true if the specified dictionary is empty or null; otherwise, false. + /// + public static bool IsEmpty(IDictionary dictionary) + { + return (dictionary == null || dictionary.Count == 0); + } + + /// + /// A callback method used for comparing to items. + /// + /// + /// + /// the first object to compare + /// the second object to compare + /// Value Condition Less than zero x is less than y. Zero x equals y. Greater than zero x is greater than y. + /// + /// + public delegate int CompareCallback(object left, object right); + + /// + /// A simple stable sorting routine - far from being efficient, only for small collections. + /// + /// + /// + /// + public static ICollection StableSort(IEnumerable input, IComparer comparer) + { + return StableSort(input, new CompareCallback(comparer.Compare)); + } + + /// + /// A simple stable sorting routine - far from being efficient, only for small collections. + /// + /// + /// Sorting is not(!) done in-place. Instead a sorted copy of the original input is returned. + /// + /// input collection of items to sort + /// the for comparing 2 items in . + /// a new collection of stable sorted items. + public static ICollection StableSort(IEnumerable input, CompareCallback comparer) + { + ArrayList ehancedInput = new ArrayList(); + IEnumerator it = input.GetEnumerator(); + int index = 0; + while (it.MoveNext()) + { + ehancedInput.Add(new Entry(index, it.Current)); + index++; + } + + ehancedInput.Sort(Entry.GetComparer(comparer)); + + for (int i = 0; i < ehancedInput.Count; i++) + { + ehancedInput[i] = ((Entry) ehancedInput[i]).Value; + } + + return ehancedInput; + } + + /// + /// A simple stable sorting routine - far from being efficient, only for small collections. + /// + /// + /// Sorting is not(!) done in-place. Instead a sorted copy of the original input is returned. + /// + /// input collection of items to sort + /// the for comparing 2 items in . + /// a new collection of stable sorted items. + public static void StableSortInPlace(IList input, IComparer comparer) + { + StableSortInPlace(input, new CompareCallback(comparer.Compare)); + } + + /// + /// A simple stable sorting routine - far from being efficient, only for small collections. + /// + /// + /// Sorting is not(!) done in-place. Instead a sorted copy of the original input is returned. + /// + /// input collection of items to sort + /// the for comparing 2 items in . + /// a new collection of stable sorted items. + public static void StableSortInPlace(IList input, CompareCallback comparer) + { + ArrayList ehancedInput = new ArrayList(); + IEnumerator it = input.GetEnumerator(); + int index = 0; + while (it.MoveNext()) + { + ehancedInput.Add(new Entry(index, it.Current)); + index++; + } + + ehancedInput.Sort(Entry.GetComparer(comparer)); + + for (int i = 0; i < ehancedInput.Count; i++) + { + input[i] = ((Entry) ehancedInput[i]).Value; + } + } + + private class Entry + { + private class EntryComparer : IComparer + { + private readonly CompareCallback innerComparer; + + public EntryComparer(CompareCallback innerComparer) + { + this.innerComparer = innerComparer; + } + + public int Compare(object x, object y) + { + Entry ex = (Entry) x; + Entry ey = (Entry) y; + int result = innerComparer(ex.Value, ey.Value); + if (result == 0) + { + result = ex.Index.CompareTo(ey.Index); + } + + return result; + } + } + + public static IComparer GetComparer(CompareCallback innerComparer) + { + return new EntryComparer(innerComparer); + } + + public readonly int Index; + public readonly object Value; + + public Entry(int index, object value) + { + Index = index; + Value = value; + } + } } diff --git a/src/Spring/Spring.Core/Util/CompareUtils.cs b/src/Spring/Spring.Core/Util/CompareUtils.cs index 09de2a60..58ad0a8f 100644 --- a/src/Spring/Spring.Core/Util/CompareUtils.cs +++ b/src/Spring/Spring.Core/Util/CompareUtils.cs @@ -22,66 +22,65 @@ #endregion -namespace Spring.Util +namespace Spring.Util; + +/// +/// Utility class containing helper methods for object comparison. +/// +/// Aleksandar Seovic +public class CompareUtils { - /// - /// Utility class containing helper methods for object comparison. - /// - /// Aleksandar Seovic - public class CompareUtils + /// Compares two objects. + /// First object. + /// Second object. + /// + /// 0, if objects are equal; + /// less than zero, if the first object is smaller than the second one; + /// greater than zero, if the first object is greater than the second one. + public static int Compare(object first, object second) { - /// Compares two objects. - /// First object. - /// Second object. - /// - /// 0, if objects are equal; - /// less than zero, if the first object is smaller than the second one; - /// greater than zero, if the first object is greater than the second one. - public static int Compare(object first, object second) + // anything is greater than null, unless both operands are null + if (first == null) { - // anything is greater than null, unless both operands are null - if (first == null) - { - return (second == null ? 0 : -1); - } - else if (second == null) - { - return 1; - } + return (second == null ? 0 : -1); + } + else if (second == null) + { + return 1; + } - if (!first.GetType().Equals(second.GetType())) + if (!first.GetType().Equals(second.GetType())) + { + if (!CoerceTypes(ref first, ref second)) { - if (!CoerceTypes(ref first, ref second)) - { - throw new ArgumentException("Cannot compare instances of [" - + first.GetType().FullName - + "] and [" - + second.GetType().FullName - + "] because they cannot be coerced to the same type."); - } - } - - if (first is IComparable) - { - return ((IComparable)first).CompareTo(second); - } - else - { - throw new ArgumentException("Cannot compare instances of the type [" - + first.GetType().FullName - + "] because it doesn't implement IComparable"); + throw new ArgumentException("Cannot compare instances of [" + + first.GetType().FullName + + "] and [" + + second.GetType().FullName + + "] because they cannot be coerced to the same type."); } } - private static bool CoerceTypes(ref object left, ref object right) + if (first is IComparable) { - if (NumberUtils.IsNumber(left) && NumberUtils.IsNumber(right)) - { - NumberUtils.CoerceTypes(ref right, ref left); - return true; - } - return false; + return ((IComparable) first).CompareTo(second); + } + else + { + throw new ArgumentException("Cannot compare instances of the type [" + + first.GetType().FullName + + "] because it doesn't implement IComparable"); + } + } + + private static bool CoerceTypes(ref object left, ref object right) + { + if (NumberUtils.IsNumber(left) && NumberUtils.IsNumber(right)) + { + NumberUtils.CoerceTypes(ref right, ref left); + return true; } + return false; } } diff --git a/src/Spring/Spring.Core/Util/ConfigXmlAttribute.cs b/src/Spring/Spring.Core/Util/ConfigXmlAttribute.cs index cc15f170..46294a68 100644 --- a/src/Spring/Spring.Core/Util/ConfigXmlAttribute.cs +++ b/src/Spring/Spring.Core/Util/ConfigXmlAttribute.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -24,64 +24,64 @@ using System.Xml; #endregion -namespace Spring.Util +namespace Spring.Util; + +/// +/// An holding information about its original text source location. +/// +/// Erich Eichinger +public class ConfigXmlAttribute : XmlAttribute, ITextPosition { - /// - /// An holding information about its original text source location. - /// - /// Erich Eichinger - public class ConfigXmlAttribute : XmlAttribute, ITextPosition + private ITextPosition _textPositionInfo; + + /// + /// Creates a new instance of , storing a copy of the passed + /// . + /// + public ConfigXmlAttribute(ITextPosition currentTextPositionPositionInfo, string prefix, string localName, string namespaceURI, XmlDocument doc) + : base(prefix, localName, namespaceURI, doc) { - private ITextPosition _textPositionInfo; - - /// - /// Creates a new instance of , storing a copy of the passed - /// . - /// - public ConfigXmlAttribute(ITextPosition currentTextPositionPositionInfo, string prefix, string localName, string namespaceURI, XmlDocument doc) - : base(prefix, localName, namespaceURI, doc) - { - // TODO: for NET 2.0 may check for "System.Configuration.Internal.IConfigErrorInfo" - _textPositionInfo = new TextPositionInfo(currentTextPositionPositionInfo); - } - - /// - /// The name of the resource this element was read from - /// - public string Filename - { - get { return _textPositionInfo.Filename; } - } - - /// - /// The line number within the resource this element was read from - /// - public int LineNumber - { - get { return _textPositionInfo.LineNumber; } - } - - /// - /// The line position within the resource this element was read from. - /// - public int LinePosition - { - get { return _textPositionInfo.LinePosition; } - } - - /// - ///Creates a duplicate of this node. - /// - ///true to recursively clone the subtree under the specified node; false to clone only the node itself - public override XmlNode CloneNode(bool deep) - { - XmlNode node = base.CloneNode(deep); - ConfigXmlAttribute element = node as ConfigXmlAttribute; - if (element != null) - { - element._textPositionInfo = new TextPositionInfo(this._textPositionInfo); - } - return node; - } + // TODO: for NET 2.0 may check for "System.Configuration.Internal.IConfigErrorInfo" + _textPositionInfo = new TextPositionInfo(currentTextPositionPositionInfo); } -} \ No newline at end of file + + /// + /// The name of the resource this element was read from + /// + public string Filename + { + get { return _textPositionInfo.Filename; } + } + + /// + /// The line number within the resource this element was read from + /// + public int LineNumber + { + get { return _textPositionInfo.LineNumber; } + } + + /// + /// The line position within the resource this element was read from. + /// + public int LinePosition + { + get { return _textPositionInfo.LinePosition; } + } + + /// + ///Creates a duplicate of this node. + /// + ///true to recursively clone the subtree under the specified node; false to clone only the node itself + public override XmlNode CloneNode(bool deep) + { + XmlNode node = base.CloneNode(deep); + ConfigXmlAttribute element = node as ConfigXmlAttribute; + if (element != null) + { + element._textPositionInfo = new TextPositionInfo(this._textPositionInfo); + } + + return node; + } +} diff --git a/src/Spring/Spring.Core/Util/ConfigXmlDocument.cs b/src/Spring/Spring.Core/Util/ConfigXmlDocument.cs index e1aa4d21..3d165024 100644 --- a/src/Spring/Spring.Core/Util/ConfigXmlDocument.cs +++ b/src/Spring/Spring.Core/Util/ConfigXmlDocument.cs @@ -24,262 +24,261 @@ using System.Xml; #endregion -namespace Spring.Util +namespace Spring.Util; + +/// +/// An implementation, who's elements retain information +/// about their location in the original XML text document the were read from. +/// +/// +/// When loading a document, the used must implement . +/// Typical XmlReader implementations like support this interface. +/// +/// Erich Eichinger +public class ConfigXmlDocument : XmlDocument { /// - /// An implementation, who's elements retain information - /// about their location in the original XML text document the were read from. + /// Holds the current text position during loading a document /// - /// - /// When loading a document, the used must implement . - /// Typical XmlReader implementations like support this interface. - /// - /// Erich Eichinger - public class ConfigXmlDocument : XmlDocument + private class CurrentTextPositionHolder : ITextPosition { - /// - /// Holds the current text position during loading a document - /// - private class CurrentTextPositionHolder : ITextPosition + private string _currentResourceName; + private IXmlLineInfo _currentXmlLineInfo; + + public IXmlLineInfo CurrentXmlLineInfo { - private string _currentResourceName; - private IXmlLineInfo _currentXmlLineInfo; - - public IXmlLineInfo CurrentXmlLineInfo - { - //get { return _currentXmlLineInfo; } - set { _currentXmlLineInfo = value; } - } - - public string CurrentResourceName - { - //get { return _currentResourceName; } - set { _currentResourceName = value; } - } - - public string Filename - { - get { return _currentResourceName; } - } - - public int LineNumber - { - get { return (_currentXmlLineInfo != null) ? _currentXmlLineInfo.LineNumber : 0; } - } - - public int LinePosition - { - get { return (_currentXmlLineInfo != null) ? _currentXmlLineInfo.LinePosition : 0; } - } + //get { return _currentXmlLineInfo; } + set { _currentXmlLineInfo = value; } } - private readonly CurrentTextPositionHolder _currentTextPositionHolder = new CurrentTextPositionHolder(); - - /// - /// Get info about the current text position during loading a document. - /// Outside loading a document, the properties of - /// will always be null. - /// - protected ITextPosition CurrentTextPosition + public string CurrentResourceName { - get { return _currentTextPositionHolder; } + //get { return _currentResourceName; } + set { _currentResourceName = value; } } - /// - /// Overridden to create a retaining the current - /// text position information. - /// - public override XmlElement CreateElement(string prefix, string localName, string namespaceURI) + public string Filename { - return new ConfigXmlElement(this.CurrentTextPosition, prefix, localName, namespaceURI, this); + get { return _currentResourceName; } } - /// - /// Overridden to create a retaining the current - /// text position information. - /// - public override XmlAttribute CreateAttribute(string prefix, string localName, string namespaceURI) + public int LineNumber { - return new ConfigXmlAttribute(this.CurrentTextPosition, prefix, localName, namespaceURI, this); + get { return (_currentXmlLineInfo != null) ? _currentXmlLineInfo.LineNumber : 0; } } - /// - /// Load the document from the given . - /// Child nodes will store as their property. - /// - ///the name of the resource - ///The XML source - public void LoadXml(string resourceName, string xml) + public int LinePosition { - try - { - _currentTextPositionHolder.CurrentResourceName = resourceName; - base.LoadXml(xml); - } - finally - { - _currentTextPositionHolder.CurrentResourceName = null; - } + get { return (_currentXmlLineInfo != null) ? _currentXmlLineInfo.LinePosition : 0; } } + } - /// - /// Load the document from the given . - /// - ///The XML source - public override void Load(string filePath) + private readonly CurrentTextPositionHolder _currentTextPositionHolder = new CurrentTextPositionHolder(); + + /// + /// Get info about the current text position during loading a document. + /// Outside loading a document, the properties of + /// will always be null. + /// + protected ITextPosition CurrentTextPosition + { + get { return _currentTextPositionHolder; } + } + + /// + /// Overridden to create a retaining the current + /// text position information. + /// + public override XmlElement CreateElement(string prefix, string localName, string namespaceURI) + { + return new ConfigXmlElement(this.CurrentTextPosition, prefix, localName, namespaceURI, this); + } + + /// + /// Overridden to create a retaining the current + /// text position information. + /// + public override XmlAttribute CreateAttribute(string prefix, string localName, string namespaceURI) + { + return new ConfigXmlAttribute(this.CurrentTextPosition, prefix, localName, namespaceURI, this); + } + + /// + /// Load the document from the given . + /// Child nodes will store as their property. + /// + ///the name of the resource + ///The XML source + public void LoadXml(string resourceName, string xml) + { + try { - try - { - Uri baseUri = new Uri(Directory.GetCurrentDirectory()); - Stream istm = (Stream) new XmlUrlResolver().GetEntity(new Uri(baseUri, filePath), null, typeof (Stream)); - base.Load(istm); - } - finally - { - _currentTextPositionHolder.CurrentResourceName = null; - } + _currentTextPositionHolder.CurrentResourceName = resourceName; + base.LoadXml(xml); } - - /// - /// Load the document from the given . - /// Child nodes will store as their property. - /// - ///the name of the resource - ///The XML source - public void Load(string resourceName, string filePath) + finally { - try - { - _currentTextPositionHolder.CurrentResourceName = resourceName; - Uri baseUri = new Uri(Directory.GetCurrentDirectory()); - Stream istm = (Stream) new XmlUrlResolver().GetEntity(new Uri(baseUri, filePath), null, typeof (Stream)); - base.Load(istm); - } - finally - { - _currentTextPositionHolder.CurrentResourceName = null; - } + _currentTextPositionHolder.CurrentResourceName = null; } + } - /// - /// Load the document from the given . - /// Child nodes will store as their property. - /// - ///the name of the resource - ///The XML source - public void Load(string resourceName, Stream stream) + /// + /// Load the document from the given . + /// + ///The XML source + public override void Load(string filePath) + { + try { - try - { - _currentTextPositionHolder.CurrentResourceName = resourceName; - base.Load (stream ); - } - finally - { - _currentTextPositionHolder.CurrentResourceName = null; - } + Uri baseUri = new Uri(Directory.GetCurrentDirectory()); + Stream istm = (Stream) new XmlUrlResolver().GetEntity(new Uri(baseUri, filePath), null, typeof(Stream)); + base.Load(istm); } - - /// - /// Load the document from the given . - /// Child nodes will store as their property. - /// - ///the name of the resource - ///The XML source - public void Load(string resourceName, TextReader reader) + finally { - try - { - _currentTextPositionHolder.CurrentResourceName = resourceName; - base.Load (reader ); - } - finally - { - _currentTextPositionHolder.CurrentResourceName = null; - } + _currentTextPositionHolder.CurrentResourceName = null; } + } - /// - /// Load the document from the given . - /// Child nodes will store as their property. - /// - ///the name of the resource - ///The XML source - public void Load(string resourceName, XmlReader reader) + /// + /// Load the document from the given . + /// Child nodes will store as their property. + /// + ///the name of the resource + ///The XML source + public void Load(string resourceName, string filePath) + { + try { - try - { - _currentTextPositionHolder.CurrentResourceName = resourceName; - this.Load (reader); - } - finally - { - _currentTextPositionHolder.CurrentResourceName = null; - } + _currentTextPositionHolder.CurrentResourceName = resourceName; + Uri baseUri = new Uri(Directory.GetCurrentDirectory()); + Stream istm = (Stream) new XmlUrlResolver().GetEntity(new Uri(baseUri, filePath), null, typeof(Stream)); + base.Load(istm); } - - /// - /// Load the document from the given . - /// Child nodes will store null as their property. - /// - /// The XML source - public override void Load(XmlReader reader) + finally { - try - { - _currentTextPositionHolder.CurrentXmlLineInfo = reader as IXmlLineInfo; - base.Load (reader); - } - finally - { - _currentTextPositionHolder.CurrentXmlLineInfo = null; - } + _currentTextPositionHolder.CurrentResourceName = null; } + } - /// - ///Creates an object based on the information in the . The reader must be positioned on a node or attribute. - ///Child nodes will store as their property. - /// - /// - ///The new XmlNode or null if no more nodes exist. - /// - ///the name of the resource - ///The XML source - ///The reader is positioned on a node type that does not translate to a valid DOM node (for example, EndElement or EndEntity). - public XmlNode ReadNode(string resourceName, XmlReader reader) + /// + /// Load the document from the given . + /// Child nodes will store as their property. + /// + ///the name of the resource + ///The XML source + public void Load(string resourceName, Stream stream) + { + try { - try - { - _currentTextPositionHolder.CurrentResourceName = resourceName; - _currentTextPositionHolder.CurrentXmlLineInfo = reader as IXmlLineInfo; - return this.ReadNode (reader); - } - finally - { - _currentTextPositionHolder.CurrentXmlLineInfo = null; - } + _currentTextPositionHolder.CurrentResourceName = resourceName; + base.Load(stream); } - - /// - ///Creates an object based on the information in the . The reader must be positioned on a node or attribute. - ///Child nodes will store null as their property. - /// - /// - ///The new XmlNode or null if no more nodes exist. - /// - ///The XML source - ///The reader is positioned on a node type that does not translate to a valid DOM node (for example, EndElement or EndEntity). - public override XmlNode ReadNode(XmlReader reader) + finally { - try - { - _currentTextPositionHolder.CurrentXmlLineInfo = reader as IXmlLineInfo; - return base.ReadNode (reader); - } - finally - { - _currentTextPositionHolder.CurrentXmlLineInfo = null; - } + _currentTextPositionHolder.CurrentResourceName = null; + } + } + + /// + /// Load the document from the given . + /// Child nodes will store as their property. + /// + ///the name of the resource + ///The XML source + public void Load(string resourceName, TextReader reader) + { + try + { + _currentTextPositionHolder.CurrentResourceName = resourceName; + base.Load(reader); + } + finally + { + _currentTextPositionHolder.CurrentResourceName = null; + } + } + + /// + /// Load the document from the given . + /// Child nodes will store as their property. + /// + ///the name of the resource + ///The XML source + public void Load(string resourceName, XmlReader reader) + { + try + { + _currentTextPositionHolder.CurrentResourceName = resourceName; + this.Load(reader); + } + finally + { + _currentTextPositionHolder.CurrentResourceName = null; + } + } + + /// + /// Load the document from the given . + /// Child nodes will store null as their property. + /// + /// The XML source + public override void Load(XmlReader reader) + { + try + { + _currentTextPositionHolder.CurrentXmlLineInfo = reader as IXmlLineInfo; + base.Load(reader); + } + finally + { + _currentTextPositionHolder.CurrentXmlLineInfo = null; + } + } + + /// + ///Creates an object based on the information in the . The reader must be positioned on a node or attribute. + ///Child nodes will store as their property. + /// + /// + ///The new XmlNode or null if no more nodes exist. + /// + ///the name of the resource + ///The XML source + ///The reader is positioned on a node type that does not translate to a valid DOM node (for example, EndElement or EndEntity). + public XmlNode ReadNode(string resourceName, XmlReader reader) + { + try + { + _currentTextPositionHolder.CurrentResourceName = resourceName; + _currentTextPositionHolder.CurrentXmlLineInfo = reader as IXmlLineInfo; + return this.ReadNode(reader); + } + finally + { + _currentTextPositionHolder.CurrentXmlLineInfo = null; + } + } + + /// + ///Creates an object based on the information in the . The reader must be positioned on a node or attribute. + ///Child nodes will store null as their property. + /// + /// + ///The new XmlNode or null if no more nodes exist. + /// + ///The XML source + ///The reader is positioned on a node type that does not translate to a valid DOM node (for example, EndElement or EndEntity). + public override XmlNode ReadNode(XmlReader reader) + { + try + { + _currentTextPositionHolder.CurrentXmlLineInfo = reader as IXmlLineInfo; + return base.ReadNode(reader); + } + finally + { + _currentTextPositionHolder.CurrentXmlLineInfo = null; } } } diff --git a/src/Spring/Spring.Core/Util/ConfigXmlElement.cs b/src/Spring/Spring.Core/Util/ConfigXmlElement.cs index 3b5a8a95..0ab7000d 100644 --- a/src/Spring/Spring.Core/Util/ConfigXmlElement.cs +++ b/src/Spring/Spring.Core/Util/ConfigXmlElement.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -24,63 +24,63 @@ using System.Xml; #endregion -namespace Spring.Util +namespace Spring.Util; + +/// +/// An holding information about its original text source location. +/// +/// Erich Eichinger +public class ConfigXmlElement : XmlElement, ITextPosition { - /// - /// An holding information about its original text source location. - /// - /// Erich Eichinger - public class ConfigXmlElement : XmlElement, ITextPosition + private ITextPosition _textPositionInfo; + + /// + /// Creates a new instance of , storing a copy of the passed + /// . + /// + public ConfigXmlElement(ITextPosition currentTextPositionPositionInfo, string prefix, string localName, string namespaceURI, XmlDocument doc) + : base(prefix, localName, namespaceURI, doc) { - private ITextPosition _textPositionInfo; - - /// - /// Creates a new instance of , storing a copy of the passed - /// . - /// - public ConfigXmlElement(ITextPosition currentTextPositionPositionInfo, string prefix, string localName, string namespaceURI, XmlDocument doc) - : base(prefix, localName, namespaceURI, doc) - { - _textPositionInfo = new TextPositionInfo(currentTextPositionPositionInfo); - } - - /// - /// The name of the resource this element was read from - /// - public string Filename - { - get { return _textPositionInfo.Filename; } - } - - /// - /// The line number within the resource this element was read from - /// - public int LineNumber - { - get { return _textPositionInfo.LineNumber; } - } - - /// - /// The line position within the resource this element was read from. - /// - public int LinePosition - { - get { return _textPositionInfo.LinePosition; } - } - - /// - ///Creates a duplicate of this node. - /// - ///true to recursively clone the subtree under the specified node; false to clone only the node itself - public override XmlNode CloneNode(bool deep) - { - XmlNode node = base.CloneNode(deep); - ConfigXmlElement element = node as ConfigXmlElement; - if (element != null) - { - element._textPositionInfo = new TextPositionInfo(this._textPositionInfo); - } - return node; - } + _textPositionInfo = new TextPositionInfo(currentTextPositionPositionInfo); } -} \ No newline at end of file + + /// + /// The name of the resource this element was read from + /// + public string Filename + { + get { return _textPositionInfo.Filename; } + } + + /// + /// The line number within the resource this element was read from + /// + public int LineNumber + { + get { return _textPositionInfo.LineNumber; } + } + + /// + /// The line position within the resource this element was read from. + /// + public int LinePosition + { + get { return _textPositionInfo.LinePosition; } + } + + /// + ///Creates a duplicate of this node. + /// + ///true to recursively clone the subtree under the specified node; false to clone only the node itself + public override XmlNode CloneNode(bool deep) + { + XmlNode node = base.CloneNode(deep); + ConfigXmlElement element = node as ConfigXmlElement; + if (element != null) + { + element._textPositionInfo = new TextPositionInfo(this._textPositionInfo); + } + + return node; + } +} diff --git a/src/Spring/Spring.Core/Util/ConfigurationUtils.cs b/src/Spring/Spring.Core/Util/ConfigurationUtils.cs index 2ff98b71..4767d65e 100644 --- a/src/Spring/Spring.Core/Util/ConfigurationUtils.cs +++ b/src/Spring/Spring.Core/Util/ConfigurationUtils.cs @@ -20,265 +20,270 @@ using System.Reflection; using System.Xml; using ConfigurationException = System.Configuration.ConfigurationException; -namespace Spring.Util -{ - /// - /// Utility class for .NET configuration files management. - /// - /// Aleksandar Seovic - public static class ConfigurationUtils - { - private static readonly ConcurrentDictionary cachedSections = - new ConcurrentDictionary(); +namespace Spring.Util; - /// - /// Parses the configuration section. - /// - /// - ///

- /// Primary purpose of this method is to allow us to parse and - /// load configuration sections using the same API regardless - /// of the .NET framework version. - ///

- ///

- /// If Microsoft paid a bit more attention to preserving backwards - /// compatibility we would not even need it, but... :( - ///

- ///
- /// Name of the configuration section. - /// Object created by a corresponding . - public static object GetSection(string sectionName) +/// +/// Utility class for .NET configuration files management. +/// +/// Aleksandar Seovic +public static class ConfigurationUtils +{ + private static readonly ConcurrentDictionary cachedSections = + new ConcurrentDictionary(); + + /// + /// Parses the configuration section. + /// + /// + ///

+ /// Primary purpose of this method is to allow us to parse and + /// load configuration sections using the same API regardless + /// of the .NET framework version. + ///

+ ///

+ /// If Microsoft paid a bit more attention to preserving backwards + /// compatibility we would not even need it, but... :( + ///

+ ///
+ /// Name of the configuration section. + /// Object created by a corresponding . + public static object GetSection(string sectionName) + { + return cachedSections.GetOrAdd(sectionName, DoGetSection); + } + + private static object DoGetSection(string sectionName) + { + try { - return cachedSections.GetOrAdd(sectionName, DoGetSection); + var name = sectionName.TrimEnd('/'); + var section = ConfigurationManager.GetSection(name); + return section; + } + catch (ConfigurationException) + { + throw; + } + catch (Exception ex) + { + throw CreateConfigurationException($"Error reading section {sectionName}", ex); + } + } + + internal static void ClearCache() + { + cachedSections.Clear(); + } + + /// + /// Refresh the configuration section. + /// + /// + ///

+ /// Primary purpose of this method is to allow us to parse and + /// load configuration sections using the same API regardless + /// of the .NET framework version. + ///

+ ///

+ /// If Microsoft paid a bit more attention to preserving backwards + /// compatibility we would not even need it, but... :( + ///

+ ///
+ /// Name of the configuration section. + public static void RefreshSection(string sectionName) + { + ConfigurationManager.RefreshSection(sectionName); + } + + /// + /// Creates the configuration exception. + /// + /// The message to display to the client when the exception is thrown. + /// The inner exception. + /// Name of the configuration file. + /// The line where exception occured. + /// Configuration exception. + public static Exception CreateConfigurationException(string message, Exception inner, string fileName, int line) + { + return new ConfigurationErrorsException(message, inner, fileName, line); + } + + /// + /// Creates the configuration exception. + /// + /// The message to display to the client when the exception is thrown. + /// Name of the configuration file. + /// The line where exception occured. + /// Configuration exception. + public static Exception CreateConfigurationException(string message, string fileName, int line) + { + return CreateConfigurationException(message, null, fileName, line); + } + + /// + /// Creates the configuration exception. + /// + /// The message to display to the client when the exception is thrown. + /// The inner exception. + /// XML node where exception occured. + /// Configuration exception. + public static Exception CreateConfigurationException(string message, Exception inner, XmlNode node) + { + return new ConfigurationErrorsException(message, inner, node); + } + + /// + /// Creates the configuration exception. + /// + /// The message to display to the client when the exception is thrown. + /// XML node where exception occured. + /// Configuration exception. + public static Exception CreateConfigurationException(string message, XmlNode node) + { + return CreateConfigurationException(message, null, node); + } + + /// + /// Creates the configuration exception. + /// + /// The message to display to the client when the exception is thrown. + /// The inner exception. + /// Configuration exception. + public static Exception CreateConfigurationException(string message, Exception inner) + { + return new ConfigurationErrorsException(message, inner); + } + + /// + /// Creates the configuration exception. + /// + /// The message to display to the client when the exception is thrown. + /// Configuration exception. + public static Exception CreateConfigurationException(string message) + { + return CreateConfigurationException(message, (Exception) null); + } + + /// + /// Creates the configuration exception. + /// + /// Configuration exception. + public static Exception CreateConfigurationException() + { + return CreateConfigurationException(null, (Exception) null); + } + + /// + /// Determines whether the specified exception is configuration exception. + /// + /// The exception to check. + /// + /// true if the specified exception is configuration exception; otherwise, false. + /// + public static bool IsConfigurationException(Exception exception) + { + return exception is ConfigurationErrorsException; + } + + /// + /// Returns the line number of the specified node. + /// + /// Node to get the line number for. + /// The line number of the specified node. + public static int GetLineNumber(XmlNode node) + { + if (node is ITextPosition) + { + return ((ITextPosition) node).LineNumber; } - private static object DoGetSection(string sectionName) + return ConfigurationErrorsException.GetLineNumber(node); + } + + /// + /// Returns the name of the file specified node is defined in. + /// + /// Node to get the file name for. + /// The name of the file specified node is defined in. + public static string GetFileName(XmlNode node) + { + if (node is ITextPosition) { - try + return ((ITextPosition) node).Filename; + } + + return ConfigurationErrorsException.GetFilename(node); + } + + /// + /// Sets the current to be used by . + /// + /// + /// �f implements , this method invokes + /// on the new configSystem to chain them.
+ /// Note, that this method requires reflection on internals of + ///
+ /// the configuration system to set + /// bypasses the check if the current system has already been initialized + /// the previous config system, if any + public static System.Configuration.Internal.IInternalConfigSystem SetConfigurationSystem(System.Configuration.Internal.IInternalConfigSystem configSystem, bool enforce) + { + FieldInfo s_configSystem = typeof(ConfigurationManager).GetField("s_configSystem", BindingFlags.Static | BindingFlags.NonPublic); + // for MONO + if (s_configSystem == null) + { + s_configSystem = typeof(ConfigurationManager).GetField("configSystem", BindingFlags.Static | BindingFlags.NonPublic); + } + + System.Configuration.Internal.IInternalConfigSystem innerConfigSystem = (System.Configuration.Internal.IInternalConfigSystem) s_configSystem.GetValue(null); + if (configSystem is IChainableConfigSystem) + { + ((IChainableConfigSystem) configSystem).SetInnerConfigurationSystem(innerConfigSystem); + } + + try + { + MethodInfo mi = typeof(ConfigurationManager).GetMethod("SetConfigurationSystem", BindingFlags.Static | BindingFlags.NonPublic); + if (mi == null) { - var name = sectionName.TrimEnd('/'); - var section = ConfigurationManager.GetSection(name); - return section; + mi = typeof(ConfigurationManager).GetMethod("ChangeConfigurationSystem", BindingFlags.Static | BindingFlags.NonPublic); + mi.Invoke(null, new object[] { configSystem }); } - catch (ConfigurationException) + else + { + if (enforce) + { + ResetConfigurationSystem(); + } + + mi.Invoke(null, new object[] { configSystem, true }); + } + } + catch (InvalidOperationException) + { + if (!enforce) { throw; } - catch (Exception ex) - { - throw CreateConfigurationException($"Error reading section {sectionName}", ex); - } + + s_configSystem.SetValue(null, configSystem); } - internal static void ClearCache() + return innerConfigSystem; + } + + /// + /// Resets the global configuration system instance. Use for unit testing only! + /// + public static void ResetConfigurationSystem() + { + if (SystemUtils.MonoRuntime) { - cachedSections.Clear(); + return; } - /// - /// Refresh the configuration section. - /// - /// - ///

- /// Primary purpose of this method is to allow us to parse and - /// load configuration sections using the same API regardless - /// of the .NET framework version. - ///

- ///

- /// If Microsoft paid a bit more attention to preserving backwards - /// compatibility we would not even need it, but... :( - ///

- ///
- /// Name of the configuration section. - public static void RefreshSection(string sectionName) - { - ConfigurationManager.RefreshSection(sectionName); - } - - /// - /// Creates the configuration exception. - /// - /// The message to display to the client when the exception is thrown. - /// The inner exception. - /// Name of the configuration file. - /// The line where exception occured. - /// Configuration exception. - public static Exception CreateConfigurationException(string message, Exception inner, string fileName, int line) - { - return new ConfigurationErrorsException(message, inner, fileName, line); - } - - /// - /// Creates the configuration exception. - /// - /// The message to display to the client when the exception is thrown. - /// Name of the configuration file. - /// The line where exception occured. - /// Configuration exception. - public static Exception CreateConfigurationException(string message, string fileName, int line) - { - return CreateConfigurationException(message, null, fileName, line); - } - - /// - /// Creates the configuration exception. - /// - /// The message to display to the client when the exception is thrown. - /// The inner exception. - /// XML node where exception occured. - /// Configuration exception. - public static Exception CreateConfigurationException(string message, Exception inner, XmlNode node) - { - return new ConfigurationErrorsException(message, inner, node); - } - - /// - /// Creates the configuration exception. - /// - /// The message to display to the client when the exception is thrown. - /// XML node where exception occured. - /// Configuration exception. - public static Exception CreateConfigurationException(string message, XmlNode node) - { - return CreateConfigurationException(message, null, node); - } - - /// - /// Creates the configuration exception. - /// - /// The message to display to the client when the exception is thrown. - /// The inner exception. - /// Configuration exception. - public static Exception CreateConfigurationException(string message, Exception inner) - { - return new ConfigurationErrorsException(message, inner); - } - - /// - /// Creates the configuration exception. - /// - /// The message to display to the client when the exception is thrown. - /// Configuration exception. - public static Exception CreateConfigurationException(string message) - { - return CreateConfigurationException(message, (Exception)null); - } - - /// - /// Creates the configuration exception. - /// - /// Configuration exception. - public static Exception CreateConfigurationException() - { - return CreateConfigurationException(null, (Exception)null); - } - - /// - /// Determines whether the specified exception is configuration exception. - /// - /// The exception to check. - /// - /// true if the specified exception is configuration exception; otherwise, false. - /// - public static bool IsConfigurationException(Exception exception) - { - return exception is ConfigurationErrorsException; - } - - /// - /// Returns the line number of the specified node. - /// - /// Node to get the line number for. - /// The line number of the specified node. - public static int GetLineNumber(XmlNode node) - { - if (node is ITextPosition) - { - return ((ITextPosition)node).LineNumber; - } - return ConfigurationErrorsException.GetLineNumber(node); - } - - /// - /// Returns the name of the file specified node is defined in. - /// - /// Node to get the file name for. - /// The name of the file specified node is defined in. - public static string GetFileName(XmlNode node) - { - if (node is ITextPosition) - { - return ((ITextPosition)node).Filename; - } - return ConfigurationErrorsException.GetFilename(node); - } - - /// - /// Sets the current to be used by . - /// - /// - /// �f implements , this method invokes - /// on the new configSystem to chain them.
- /// Note, that this method requires reflection on internals of - ///
- /// the configuration system to set - /// bypasses the check if the current system has already been initialized - /// the previous config system, if any - public static System.Configuration.Internal.IInternalConfigSystem SetConfigurationSystem(System.Configuration.Internal.IInternalConfigSystem configSystem, bool enforce) - { - FieldInfo s_configSystem = typeof(ConfigurationManager).GetField("s_configSystem", BindingFlags.Static | BindingFlags.NonPublic); - // for MONO - if (s_configSystem == null) - { - s_configSystem = typeof(ConfigurationManager).GetField("configSystem", BindingFlags.Static | BindingFlags.NonPublic); - } - System.Configuration.Internal.IInternalConfigSystem innerConfigSystem = (System.Configuration.Internal.IInternalConfigSystem)s_configSystem.GetValue(null); - if (configSystem is IChainableConfigSystem) - { - ((IChainableConfigSystem)configSystem).SetInnerConfigurationSystem(innerConfigSystem); - } - - try - { - MethodInfo mi = typeof(ConfigurationManager).GetMethod("SetConfigurationSystem", BindingFlags.Static | BindingFlags.NonPublic); - if (mi == null) - { - mi = typeof(ConfigurationManager).GetMethod("ChangeConfigurationSystem", BindingFlags.Static | BindingFlags.NonPublic); - mi.Invoke(null, new object[] { configSystem }); - } - else - { - if (enforce) - { - ResetConfigurationSystem(); - } - mi.Invoke(null, new object[] { configSystem, true }); - } - } - catch (InvalidOperationException) - { - if (!enforce) - { - throw; - } - s_configSystem.SetValue(null, configSystem); - } - - return innerConfigSystem; - } - - /// - /// Resets the global configuration system instance. Use for unit testing only! - /// - public static void ResetConfigurationSystem() - { - if (SystemUtils.MonoRuntime) - { - return; - } - FieldInfo initStateRef = typeof(ConfigurationManager).GetField("s_initState", BindingFlags.NonPublic | BindingFlags.Static); - object notStarted = Activator.CreateInstance(initStateRef.FieldType); - initStateRef.SetValue(null, notStarted); - } + FieldInfo initStateRef = typeof(ConfigurationManager).GetField("s_initState", BindingFlags.NonPublic | BindingFlags.Static); + object notStarted = Activator.CreateInstance(initStateRef.FieldType); + initStateRef.SetValue(null, notStarted); } } diff --git a/src/Spring/Spring.Core/Util/ConstructorInstantiationInfo.cs b/src/Spring/Spring.Core/Util/ConstructorInstantiationInfo.cs index fb3fe70f..4445f292 100644 --- a/src/Spring/Spring.Core/Util/ConstructorInstantiationInfo.cs +++ b/src/Spring/Spring.Core/Util/ConstructorInstantiationInfo.cs @@ -20,44 +20,43 @@ using System.Reflection; -namespace Spring.Util +namespace Spring.Util; + +/// +/// Collects information on the constructor to use to create the instance and the argument instances to pass into the +/// constructor. +/// +public class ConstructorInstantiationInfo { + private ConstructorInfo constructorInfo; + private object[] argInstances; + /// - /// Collects information on the constructor to use to create the instance and the argument instances to pass into the - /// constructor. + /// Initializes a new instance of the class. /// - public class ConstructorInstantiationInfo + /// The constructor info. + /// The arg instances. + public ConstructorInstantiationInfo(ConstructorInfo constructorInfo, object[] argInstances) { - private ConstructorInfo constructorInfo; - private object[] argInstances; - - /// - /// Initializes a new instance of the class. - /// - /// The constructor info. - /// The arg instances. - public ConstructorInstantiationInfo(ConstructorInfo constructorInfo, object[] argInstances) - { - this.constructorInfo = constructorInfo; - this.argInstances = argInstances; - } - - /// - /// Gets the constructor info. - /// - /// The constructor info. - public ConstructorInfo ConstructorInfo - { - get { return constructorInfo; } - } - - /// - /// Gets the arg instances. - /// - /// The arg instances. - public object[] ArgInstances - { - get { return argInstances; } - } + this.constructorInfo = constructorInfo; + this.argInstances = argInstances; } -} \ No newline at end of file + + /// + /// Gets the constructor info. + /// + /// The constructor info. + public ConstructorInfo ConstructorInfo + { + get { return constructorInfo; } + } + + /// + /// Gets the arg instances. + /// + /// The arg instances. + public object[] ArgInstances + { + get { return argInstances; } + } +} diff --git a/src/Spring/Spring.Core/Util/DelegateInfo.cs b/src/Spring/Spring.Core/Util/DelegateInfo.cs index 27d56040..5d0f9874 100644 --- a/src/Spring/Spring.Core/Util/DelegateInfo.cs +++ b/src/Spring/Spring.Core/Util/DelegateInfo.cs @@ -24,230 +24,232 @@ using System.Reflection; #endregion -namespace Spring.Util +namespace Spring.Util; + +/// +/// Discovers the attributes of a +/// and provides access to the +/// s metadata. +/// +/// Rick Evans +public sealed class DelegateInfo { - /// - /// Discovers the attributes of a - /// and provides access to the - /// s metadata. - /// - /// Rick Evans - public sealed class DelegateInfo - { - #region Constants + #region Constants - /// - /// The method name associated with a delegate invocation. - /// - private const string InvocationMethod = "Invoke"; + /// + /// The method name associated with a delegate invocation. + /// + private const string InvocationMethod = "Invoke"; - #endregion + #endregion - #region Constructor (s) / Destructor + #region Constructor (s) / Destructor - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The event used to extract the delegate - /// from. - /// - /// - /// if the supplied is - /// . - /// - public DelegateInfo(EventInfo eventMeta) : this(eventMeta.EventHandlerType) - { - } + /// + /// Creates a new instance of the + /// class. + /// + /// + /// The event used to extract the delegate + /// from. + /// + /// + /// if the supplied is + /// . + /// + public DelegateInfo(EventInfo eventMeta) : this(eventMeta.EventHandlerType) + { + } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The delegate . - /// - /// - /// If the supplied is not a subclass of the - /// class, or is . - /// - public DelegateInfo(Type type) - { - DelegateType = type; - } + /// + /// Creates a new instance of the + /// class. + /// + /// + /// The delegate . + /// + /// + /// If the supplied is not a subclass of the + /// class, or is . + /// + public DelegateInfo(Type type) + { + DelegateType = type; + } - #endregion + #endregion - #region Properties + #region Properties - /// - /// The of the delegate. - /// - private Type DelegateType - { - get { return _delegateType; } - set - { - if (!DelegateInfo.IsDelegate(value)) - { - throw new ArgumentException("Not a delegate Type"); - } - _delegateType = value; - } - } + /// + /// The of the delegate. + /// + private Type DelegateType + { + get { return _delegateType; } + set + { + if (!DelegateInfo.IsDelegate(value)) + { + throw new ArgumentException("Not a delegate Type"); + } - #endregion + _delegateType = value; + } + } - #region Methods + #endregion - /// - /// Checks to see if the method encapsulated by the supplied method - /// metadata is compatible with the method signature associated with - /// this delegate type. - /// - /// The method to be checked. - /// - /// if the method signature is compatible with - /// the signature of this delegate; if not, or - /// if the supplied parameter is - /// . - /// - public bool IsSignatureCompatible(MethodInfo method) - { - if (method != null && - method.ReturnType.Equals(GetReturnType())) - { - ParameterInfo[] methodParameters = - method.GetParameters(); - Type[] delegateParameters = GetParameterTypes(); - if (methodParameters.Length == delegateParameters.Length) - { - for (int i = 0; i < methodParameters.Length; ++i) - { - if (!methodParameters[i].ParameterType. - Equals(delegateParameters[i])) - { - return false; - } - } - return true; - } - } - return false; - } + #region Methods - /// - /// Gets the s of the parameters of the - /// method signature associated with this delegate type. - /// - /// - ///

- /// This method will never return ; the returned - /// array may be empty, but it most certainly - /// will not be . - ///

- ///
- /// - /// A array of the parameter - /// s; or the - /// array if the method signature has no parameters. - /// - public Type[] GetParameterTypes() - { - ParameterInfo[] parameters = GetMethod().GetParameters(); - if (parameters != null - && parameters.Length > 0) - { - Type[] types = new Type[parameters.Length]; - for (int i = 0; i < parameters.Length; ++i) - { - types[i] = parameters[i].ParameterType; - } - return types; - } - return Type.EmptyTypes; - } + /// + /// Checks to see if the method encapsulated by the supplied method + /// metadata is compatible with the method signature associated with + /// this delegate type. + /// + /// The method to be checked. + /// + /// if the method signature is compatible with + /// the signature of this delegate; if not, or + /// if the supplied parameter is + /// . + /// + public bool IsSignatureCompatible(MethodInfo method) + { + if (method != null && + method.ReturnType.Equals(GetReturnType())) + { + ParameterInfo[] methodParameters = + method.GetParameters(); + Type[] delegateParameters = GetParameterTypes(); + if (methodParameters.Length == delegateParameters.Length) + { + for (int i = 0; i < methodParameters.Length; ++i) + { + if (!methodParameters[i].ParameterType.Equals(delegateParameters[i])) + { + return false; + } + } - /// - /// Gets the return of the - /// method signature associated with this delegate type. - /// - /// The return . - public Type GetReturnType() - { - return GetMethod().ReturnType; - } + return true; + } + } - /// - /// Gets the metadata about the method signature associated - /// with this delegate type. - /// - /// - /// The metadata about the method signature associated - /// with this delegate type. - /// - public MethodInfo GetMethod() - { - return DelegateType.GetMethod(DelegateInfo.InvocationMethod); - } + return false; + } - /// - /// Determines whether the supplied - /// is a type. - /// - /// - /// The to be checked. - /// - /// - /// if the supplied - /// is a ; - /// if not or the supplied - /// is . - /// - public static bool IsDelegate(Type type) - { - return type == null ? - false : - type.IsSubclassOf(typeof (Delegate)); - } + /// + /// Gets the s of the parameters of the + /// method signature associated with this delegate type. + /// + /// + ///

+ /// This method will never return ; the returned + /// array may be empty, but it most certainly + /// will not be . + ///

+ ///
+ /// + /// A array of the parameter + /// s; or the + /// array if the method signature has no parameters. + /// + public Type[] GetParameterTypes() + { + ParameterInfo[] parameters = GetMethod().GetParameters(); + if (parameters != null + && parameters.Length > 0) + { + Type[] types = new Type[parameters.Length]; + for (int i = 0; i < parameters.Length; ++i) + { + types[i] = parameters[i].ParameterType; + } - /// - /// Checks if the signature of the supplied - /// is compatible with the signature expected by the supplied - /// . - /// - /// The event to be checked against. - /// - /// The method signature to check for compatibility. - /// - /// - /// if the signature of the supplied - /// is compatible with the signature - /// expected by the supplied ; - /// if not or either of the supplied - /// parameters is . - /// - /// - public static bool IsSignatureCompatible( - EventInfo eventMeta, MethodInfo handlerMethod) - { - bool compatible = false; - if (eventMeta != null - && DelegateInfo.IsDelegate(eventMeta.EventHandlerType)) - { - compatible = new DelegateInfo(eventMeta.EventHandlerType) - .IsSignatureCompatible(handlerMethod); - } - return compatible; - } + return types; + } - #endregion + return Type.EmptyTypes; + } - #region Fields + /// + /// Gets the return of the + /// method signature associated with this delegate type. + /// + /// The return . + public Type GetReturnType() + { + return GetMethod().ReturnType; + } - private Type _delegateType; + /// + /// Gets the metadata about the method signature associated + /// with this delegate type. + /// + /// + /// The metadata about the method signature associated + /// with this delegate type. + /// + public MethodInfo GetMethod() + { + return DelegateType.GetMethod(DelegateInfo.InvocationMethod); + } - #endregion - } + /// + /// Determines whether the supplied + /// is a type. + /// + /// + /// The to be checked. + /// + /// + /// if the supplied + /// is a ; + /// if not or the supplied + /// is . + /// + public static bool IsDelegate(Type type) + { + return type == null ? false : type.IsSubclassOf(typeof(Delegate)); + } + + /// + /// Checks if the signature of the supplied + /// is compatible with the signature expected by the supplied + /// . + /// + /// The event to be checked against. + /// + /// The method signature to check for compatibility. + /// + /// + /// if the signature of the supplied + /// is compatible with the signature + /// expected by the supplied ; + /// if not or either of the supplied + /// parameters is . + /// + /// + public static bool IsSignatureCompatible( + EventInfo eventMeta, MethodInfo handlerMethod) + { + bool compatible = false; + if (eventMeta != null + && DelegateInfo.IsDelegate(eventMeta.EventHandlerType)) + { + compatible = new DelegateInfo(eventMeta.EventHandlerType) + .IsSignatureCompatible(handlerMethod); + } + + return compatible; + } + + #endregion + + #region Fields + + private Type _delegateType; + + #endregion } diff --git a/src/Spring/Spring.Core/Util/DynamicCodeManager.cs b/src/Spring/Spring.Core/Util/DynamicCodeManager.cs index c083639a..682ec7da 100644 --- a/src/Spring/Spring.Core/Util/DynamicCodeManager.cs +++ b/src/Spring/Spring.Core/Util/DynamicCodeManager.cs @@ -28,83 +28,84 @@ using Spring.Collections; #endregion -namespace Spring.Util +namespace Spring.Util; + +/// +/// Use this class for obtaining instances for dynamic code generation. +/// +/// +///

+/// The purpose of this class is to provide a simple abstraction for creating and managing dynamic assemblies. +///

+/// +/// Using this factory you can't define several modules within a single dynamic assembly - only a simple one2one relation between assembly/module is used. +/// +///
+/// +///

The following excerpt from demonstrates usage:

+/// +/// public class DynamicProxyManager +/// { +/// public const string PROXY_ASSEMBLY_NAME = "Spring.Proxy"; +/// +/// public static TypeBuilder CreateTypeBuilder(string name, Type baseType) +/// { +/// // Generates type name +/// string typeName = String.Format("{0}.{1}_{2}", PROXY_ASSEMBLY_NAME, name, Guid.NewGuid().ToString("N")); +/// ModuleBuilder module = DynamicCodeManager.GetModuleBuilder(PROXY_ASSEMBLY_NAME); +/// return module.DefineType(typeName, PROXY_TYPE_ATTRIBUTES); +/// } +/// } +/// +///
+/// Erich Eichinger +/// +/// +/// +public sealed class DynamicCodeManager { + private static readonly Hashtable s_moduleCache = new CaseInsensitiveHashtable(); //CollectionsUtil.CreateCaseInsensitiveHashtable(); + /// - /// Use this class for obtaining instances for dynamic code generation. + /// prevent instantiation + /// + private DynamicCodeManager() + { + throw new InvalidOperationException(); + } + + /// + /// Returns the for the dynamic module within the specified assembly. /// /// - ///

- /// The purpose of this class is to provide a simple abstraction for creating and managing dynamic assemblies. - ///

- /// - /// Using this factory you can't define several modules within a single dynamic assembly - only a simple one2one relation between assembly/module is used. - /// + /// If the assembly does not exist yet, it will be created.
+ /// This factory caches any dynamic assembly it creates - calling GetModule() twice with + /// the same name will *not* create 2 distinct modules! ///
- /// - ///

The following excerpt from demonstrates usage:

- /// - /// public class DynamicProxyManager - /// { - /// public const string PROXY_ASSEMBLY_NAME = "Spring.Proxy"; - /// - /// public static TypeBuilder CreateTypeBuilder(string name, Type baseType) - /// { - /// // Generates type name - /// string typeName = String.Format("{0}.{1}_{2}", PROXY_ASSEMBLY_NAME, name, Guid.NewGuid().ToString("N")); - /// ModuleBuilder module = DynamicCodeManager.GetModuleBuilder(PROXY_ASSEMBLY_NAME); - /// return module.DefineType(typeName, PROXY_TYPE_ATTRIBUTES); - /// } - /// } - /// - ///
- /// Erich Eichinger - /// - /// - /// - public sealed class DynamicCodeManager + /// The assembly-name of the module to be returned + /// the that can be used to define new types within the specified assembly + public static ModuleBuilder GetModuleBuilder(string assemblyName) { - private static readonly Hashtable s_moduleCache = new CaseInsensitiveHashtable(); //CollectionsUtil.CreateCaseInsensitiveHashtable(); - - /// - /// prevent instantiation - /// - private DynamicCodeManager() + lock (s_moduleCache.SyncRoot) { - throw new InvalidOperationException(); - } - - /// - /// Returns the for the dynamic module within the specified assembly. - /// - /// - /// If the assembly does not exist yet, it will be created.
- /// This factory caches any dynamic assembly it creates - calling GetModule() twice with - /// the same name will *not* create 2 distinct modules! - ///
- /// The assembly-name of the module to be returned - /// the that can be used to define new types within the specified assembly - public static ModuleBuilder GetModuleBuilder( string assemblyName ) - { - lock(s_moduleCache.SyncRoot) + ModuleBuilder module = (ModuleBuilder) s_moduleCache[assemblyName]; + if (module == null) { - ModuleBuilder module = (ModuleBuilder) s_moduleCache[assemblyName]; - if (module == null) - { - AssemblyName an = new AssemblyName(); - an.Name = assemblyName; - module = BuildModule(an); - s_moduleCache[assemblyName] = module; - } - return module; + AssemblyName an = new AssemblyName(); + an.Name = assemblyName; + module = BuildModule(an); + s_moduleCache[assemblyName] = module; } + + return module; } + } #if !NETSTANDARD private static ModuleBuilder BuildModule(AssemblyName an) { #if DEBUG_DYNAMIC - AssemblyBuilder assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.RunAndSave, null, null, null, null,null, true ); + AssemblyBuilder assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.RunAndSave, null, null, null, null, null, true); var module = assembly.DefineDynamicModule(an.Name, an.Name + ".dll", true); #else an.SetPublicKey(Assembly.GetExecutingAssembly().GetName().GetPublicKey()); @@ -118,53 +119,52 @@ namespace Spring.Util return module; } #else - private static ModuleBuilder BuildModule(AssemblyName an) - { - var assembly = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName(Guid.NewGuid().ToString()), AssemblyBuilderAccess.Run); - var module = assembly.DefineDynamicModule(an.Name); - return module; - } + private static ModuleBuilder BuildModule(AssemblyName an) + { + var assembly = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName(Guid.NewGuid().ToString()), AssemblyBuilderAccess.Run); + var module = assembly.DefineDynamicModule(an.Name); + return module; + } #endif - /// - /// Persists the specified dynamic assembly to the file-system - /// - /// the name of the dynamic assembly to persist - /// - /// Can only be called in DEBUG_DYNAMIC mode, per ConditionalAttribute rules. - /// - [Conditional("DEBUG_DYNAMIC")] - public static void SaveAssembly( string assemblyName ) + /// + /// Persists the specified dynamic assembly to the file-system + /// + /// the name of the dynamic assembly to persist + /// + /// Can only be called in DEBUG_DYNAMIC mode, per ConditionalAttribute rules. + /// + [Conditional("DEBUG_DYNAMIC")] + public static void SaveAssembly(string assemblyName) + { + AssertUtils.ArgumentHasText(assemblyName, "assemblyName"); + + ModuleBuilder module = null; + lock (s_moduleCache.SyncRoot) { - AssertUtils.ArgumentHasText(assemblyName, "assemblyName"); + module = (ModuleBuilder) s_moduleCache[assemblyName]; + } - ModuleBuilder module = null; - lock(s_moduleCache.SyncRoot) - { - module = (ModuleBuilder) s_moduleCache[assemblyName]; - } + if (module == null) + { + throw new ArgumentException(string.Format("'{0}' is not a valid dynamic assembly name", assemblyName), "assemblyName"); + } - if(module == null) - { - throw new ArgumentException(string.Format("'{0}' is not a valid dynamic assembly name", assemblyName), "assemblyName"); - } - - AssemblyBuilder assembly = (AssemblyBuilder) module.Assembly; + AssemblyBuilder assembly = (AssemblyBuilder) module.Assembly; #if !NETSTANDARD assembly.Save(assembly.GetName().Name + ".dll"); #endif - } + } - /// - /// Removes all registered s. - /// - public static void Clear() + /// + /// Removes all registered s. + /// + public static void Clear() + { + lock (s_moduleCache.SyncRoot) { - lock (s_moduleCache.SyncRoot) - { - s_moduleCache.Clear(); - } + s_moduleCache.Clear(); } } } diff --git a/src/Spring/Spring.Core/Util/EventUtils.cs b/src/Spring/Spring.Core/Util/EventUtils.cs index 6d35d2b6..921f2224 100644 --- a/src/Spring/Spring.Core/Util/EventUtils.cs +++ b/src/Spring/Spring.Core/Util/EventUtils.cs @@ -22,142 +22,142 @@ using System.Diagnostics; using System.Reflection; using Microsoft.Extensions.Logging; -namespace Spring.Util +namespace Spring.Util; + +/// +/// A utility class for raising events in a generic and consistent fashion. +/// +/// Rick Evans +public class EventRaiser { - /// - /// A utility class for raising events in a generic and consistent fashion. - /// - /// Rick Evans - public class EventRaiser + protected class EventExceptionsCollector : IEventExceptionsCollector { - protected class EventExceptionsCollector : IEventExceptionsCollector + private readonly Dictionary _eventExceptions; + + public EventExceptionsCollector() { - private readonly Dictionary _eventExceptions; + _eventExceptions = new Dictionary(); + } - public EventExceptionsCollector() - { - _eventExceptions = new Dictionary(); - } + public bool HasExceptions + { + get { return _eventExceptions.Count > 0; } + } - public bool HasExceptions - { - get { return _eventExceptions.Count > 0; } - } + public IList Sources + { + get { return new List(_eventExceptions.Keys); } + } - public IList Sources - { - get { return new List(_eventExceptions.Keys); } - } + public IList Exceptions + { + get { return new List(_eventExceptions.Values); } + } - public IList Exceptions + public Exception this[Delegate source] + { + get { - get { return new List(_eventExceptions.Values); } - } - - public Exception this[Delegate source] - { - get - { - Exception exception; - _eventExceptions.TryGetValue(source, out exception); - return exception; - } - } - - public void Add(Delegate source, Exception exception) - { - _eventExceptions.Add(source, exception); + Exception exception; + _eventExceptions.TryGetValue(source, out exception); + return exception; } } - protected readonly ILogger Log; - - /// - /// Create a new EventRaiser instance - /// - public EventRaiser() + public void Add(Delegate source, Exception exception) { - Log = LogManager.GetLogger(this.GetType()); - } - - /// - /// Raises the event encapsulated by the supplied - /// , passing the supplied - /// to the event. - /// - /// The event to be raised. - /// The arguments to the event. - /// a map of sink/exception entries that occurred during event raising - public virtual IEventExceptionsCollector Raise(Delegate source, params object[] arguments) - { - EventExceptionsCollector exceptions = new EventExceptionsCollector(); - - if (source != null) - { - Delegate [] delegates = source.GetInvocationList (); - foreach (Delegate sink in delegates) - { - Invoke (sink, arguments, exceptions); - } - } - return exceptions; - } - - /// - /// Invokes the supplied , passing the supplied - /// to the sink. - /// - /// The sink to be invoked. - /// The arguments to the sink. - /// the map of sink/exception entries to add any exception to - protected virtual void Invoke(Delegate sink, object[] arguments, EventExceptionsCollector exceptions) - { - try - { - sink.DynamicInvoke (arguments); - } - catch (TargetInvocationException ex) - { - // unwrap the exception that actually caused the TargetInvocationException and throw that... - Exception cause = ReflectionUtils.UnwrapTargetInvocationException(ex); - exceptions.Add(sink, cause); - throw cause; - } + _eventExceptions.Add(source, exception); } } + protected readonly ILogger Log; + /// - /// Raises events defensively. + /// Create a new EventRaiser instance /// - /// - ///

- /// Raising events defensively means that as the raised event is passed to each handler, - /// any thrown by a handler will be caught and silently - /// ignored. - ///

- ///
- /// Rick Evans - public class DefensiveEventRaiser : EventRaiser + public EventRaiser() { - /// - /// Defensively invokes the supplied , passing the - /// supplied to the sink. - /// - /// The sink to be invoked. - /// The arguments to the sink. - /// the map of sink/exception entries to add any exception to - protected override void Invoke(Delegate sink, object[] arguments, EventExceptionsCollector exceptions) + Log = LogManager.GetLogger(this.GetType()); + } + + /// + /// Raises the event encapsulated by the supplied + /// , passing the supplied + /// to the event. + /// + /// The event to be raised. + /// The arguments to the event. + /// a map of sink/exception entries that occurred during event raising + public virtual IEventExceptionsCollector Raise(Delegate source, params object[] arguments) + { + EventExceptionsCollector exceptions = new EventExceptionsCollector(); + + if (source != null) { - try + Delegate[] delegates = source.GetInvocationList(); + foreach (Delegate sink in delegates) { - sink.DynamicInvoke (arguments); - } - catch(Exception ex) - { - string message = "Error during raising an event from " + new StackTrace(); - Log.LogWarning(ex, message); - exceptions.Add(sink, ex); + Invoke(sink, arguments, exceptions); } } + + return exceptions; + } + + /// + /// Invokes the supplied , passing the supplied + /// to the sink. + /// + /// The sink to be invoked. + /// The arguments to the sink. + /// the map of sink/exception entries to add any exception to + protected virtual void Invoke(Delegate sink, object[] arguments, EventExceptionsCollector exceptions) + { + try + { + sink.DynamicInvoke(arguments); + } + catch (TargetInvocationException ex) + { + // unwrap the exception that actually caused the TargetInvocationException and throw that... + Exception cause = ReflectionUtils.UnwrapTargetInvocationException(ex); + exceptions.Add(sink, cause); + throw cause; + } + } +} + +/// +/// Raises events defensively. +/// +/// +///

+/// Raising events defensively means that as the raised event is passed to each handler, +/// any thrown by a handler will be caught and silently +/// ignored. +///

+///
+/// Rick Evans +public class DefensiveEventRaiser : EventRaiser +{ + /// + /// Defensively invokes the supplied , passing the + /// supplied to the sink. + /// + /// The sink to be invoked. + /// The arguments to the sink. + /// the map of sink/exception entries to add any exception to + protected override void Invoke(Delegate sink, object[] arguments, EventExceptionsCollector exceptions) + { + try + { + sink.DynamicInvoke(arguments); + } + catch (Exception ex) + { + string message = "Error during raising an event from " + new StackTrace(); + Log.LogWarning(ex, message); + exceptions.Add(sink, ex); + } } } diff --git a/src/Spring/Spring.Core/Util/FatalReflectionException.cs b/src/Spring/Spring.Core/Util/FatalReflectionException.cs index c4d86347..6b486b23 100644 --- a/src/Spring/Spring.Core/Util/FatalReflectionException.cs +++ b/src/Spring/Spring.Core/Util/FatalReflectionException.cs @@ -24,65 +24,64 @@ using System.Runtime.Serialization; #endregion -namespace Spring.Util +namespace Spring.Util; + +/// +/// Thrown on an unrecoverable problem encountered in the +/// objects namespace or sub-namespaces, e.g. bad class or field. +/// +/// Rod Johnson +/// Mark Pollack (.NET) +[Serializable] +public class FatalReflectionException : ReflectionException { /// - /// Thrown on an unrecoverable problem encountered in the - /// objects namespace or sub-namespaces, e.g. bad class or field. + /// Creates a new instance of the FatalObjectException class. /// - /// Rod Johnson - /// Mark Pollack (.NET) - [Serializable] - public class FatalReflectionException : ReflectionException + public FatalReflectionException() { - /// - /// Creates a new instance of the FatalObjectException class. - /// - public FatalReflectionException() - { - } + } - /// - /// Creates a new instance of the FatalObjectException class with the - /// specified message. - /// - /// - /// A message about the exception. - /// - public FatalReflectionException(string message) : base(message) - { - } + /// + /// Creates a new instance of the FatalObjectException class with the + /// specified message. + /// + /// + /// A message about the exception. + /// + public FatalReflectionException(string message) : base(message) + { + } - /// - /// Creates a new instance of the FatalObjectException class with the - /// specified message. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception that is being wrapped. - /// - public FatalReflectionException(string message, Exception rootCause) - : base(message, rootCause) - { - } + /// + /// Creates a new instance of the FatalObjectException class with the + /// specified message. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception that is being wrapped. + /// + public FatalReflectionException(string message, Exception rootCause) + : base(message, rootCause) + { + } - /// - /// Creates a new instance of the FatalObjectException class. - /// - /// - /// The - /// that holds the serialized object data about the exception being thrown. - /// - /// - /// The - /// that contains contextual information about the source or destination. - /// - protected FatalReflectionException ( - SerializationInfo info, StreamingContext context) - : base (info, context) - { - } + /// + /// Creates a new instance of the FatalObjectException class. + /// + /// + /// The + /// that holds the serialized object data about the exception being thrown. + /// + /// + /// The + /// that contains contextual information about the source or destination. + /// + protected FatalReflectionException( + SerializationInfo info, StreamingContext context) + : base(info, context) + { } } diff --git a/src/Spring/Spring.Core/Util/Generic/CollectionUtils.cs b/src/Spring/Spring.Core/Util/Generic/CollectionUtils.cs index 1bf0914d..30ffc3d4 100644 --- a/src/Spring/Spring.Core/Util/Generic/CollectionUtils.cs +++ b/src/Spring/Spring.Core/Util/Generic/CollectionUtils.cs @@ -25,130 +25,139 @@ using System.Reflection; #endregion -namespace Spring.Util.Generic +namespace Spring.Util.Generic; + +/// +/// Miscellaneous generic collection utility methods. +/// +/// +/// Mainly for internal use within the framework. +/// +/// Mark Pollack (.NET) +public sealed class CollectionUtils { - /// - /// Miscellaneous generic collection utility methods. - /// - /// - /// Mainly for internal use within the framework. - /// - /// Mark Pollack (.NET) - public sealed class CollectionUtils - { - #region Methods + #region Methods - /// - /// Determine whether a given collection only contains - /// a single unique object - /// - /// - /// - public static bool HasUniqueObject(ICollection coll) - { - if (coll.Count == 0) - { - return false; - } - object candidate = null; - foreach (object elem in coll) - { - if (candidate == null) - { - candidate = elem; - } - else if (candidate != elem) - { - return false; - } - } - return true; - } - - /// - /// Determines whether the contains the specified . - /// - /// The collection to check. - /// The object to locate in the collection. - /// if the element is in the collection, otherwise. - public static bool Contains(ICollection collection, Object element) - { - if (collection == null) - { - throw new ArgumentNullException("Collection cannot be null."); - } - MethodInfo method; - method = collection.GetType().GetMethod("contains", BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public); - if (null == method) - { - throw new InvalidOperationException("Collection type " + collection.GetType() + " does not implement a Contains() method."); - } - return (bool) method.Invoke(collection, new Object[] {element}); - } - - /// - /// Determines whether the collection contains all the elements in the specified collection. - /// - /// The collection to check. - /// Collection whose elements would be checked for containment. - /// true if the target collection contains all the elements of the specified collection. - public static bool ContainsAll(ICollection targetCollection, ICollection sourceCollection) - { - if (targetCollection == null || sourceCollection == null) - { - throw new ArgumentNullException("Collection cannot be null."); - } - if ( sourceCollection.Count == 0 && targetCollection.Count > 1 ) - return true; - - IEnumerator sourceCollectionEnumerator = sourceCollection.GetEnumerator(); - - bool contains = false; - - MethodInfo method; - method = targetCollection.GetType().GetMethod("containsAll", BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public); - - if (method != null) - contains = (bool) method.Invoke(targetCollection, new Object[] {sourceCollection}); - else - { - method = targetCollection.GetType().GetMethod("Contains", BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public); - if (method == null) - { - throw new InvalidOperationException("Target collection does not implment a Contains() or ContainsAll() method."); - } - while (sourceCollectionEnumerator.MoveNext()) - { - if ((contains = (bool) method.Invoke(targetCollection, new Object[] {sourceCollectionEnumerator.Current})) == false) - break; - } - } - return contains; - } - /// - /// Removes all the elements from the target collection that are contained in the source collection. - /// - /// Collection where the elements will be removed. - /// Elements to remove from the target collection. - public static void RemoveAll(ICollection targetCollection, ICollection sourceCollection) + /// + /// Determine whether a given collection only contains + /// a single unique object + /// + /// + /// + public static bool HasUniqueObject(ICollection coll) + { + if (coll.Count == 0) { - if (targetCollection == null) - { - throw new ArgumentNullException("targetCollection", "Collection cannot be null."); - } + return false; + } - if (sourceCollection == null) + object candidate = null; + foreach (object elem in coll) + { + if (candidate == null) { - throw new ArgumentNullException("sourceCollection", "Collection cannot be null."); + candidate = elem; } - foreach (T element in sourceCollection) + else if (candidate != elem) { - if (targetCollection.Contains(element)) - { - targetCollection.Remove(element); - } + return false; } } - #endregion - } + + return true; + } + + /// + /// Determines whether the contains the specified . + /// + /// The collection to check. + /// The object to locate in the collection. + /// if the element is in the collection, otherwise. + public static bool Contains(ICollection collection, Object element) + { + if (collection == null) + { + throw new ArgumentNullException("Collection cannot be null."); + } + + MethodInfo method; + method = collection.GetType().GetMethod("contains", BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public); + if (null == method) + { + throw new InvalidOperationException("Collection type " + collection.GetType() + " does not implement a Contains() method."); + } + + return (bool) method.Invoke(collection, new Object[] { element }); + } + + /// + /// Determines whether the collection contains all the elements in the specified collection. + /// + /// The collection to check. + /// Collection whose elements would be checked for containment. + /// true if the target collection contains all the elements of the specified collection. + public static bool ContainsAll(ICollection targetCollection, ICollection sourceCollection) + { + if (targetCollection == null || sourceCollection == null) + { + throw new ArgumentNullException("Collection cannot be null."); + } + + if (sourceCollection.Count == 0 && targetCollection.Count > 1) + return true; + + IEnumerator sourceCollectionEnumerator = sourceCollection.GetEnumerator(); + + bool contains = false; + + MethodInfo method; + method = targetCollection.GetType().GetMethod("containsAll", BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public); + + if (method != null) + contains = (bool) method.Invoke(targetCollection, new Object[] { sourceCollection }); + else + { + method = targetCollection.GetType().GetMethod("Contains", BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public); + if (method == null) + { + throw new InvalidOperationException("Target collection does not implment a Contains() or ContainsAll() method."); + } + + while (sourceCollectionEnumerator.MoveNext()) + { + if ((contains = (bool) method.Invoke(targetCollection, new Object[] { sourceCollectionEnumerator.Current })) == false) + break; + } + } + + return contains; + } + + /// + /// Removes all the elements from the target collection that are contained in the source collection. + /// + /// Collection where the elements will be removed. + /// Elements to remove from the target collection. + public static void RemoveAll(ICollection targetCollection, ICollection sourceCollection) + { + if (targetCollection == null) + { + throw new ArgumentNullException("targetCollection", "Collection cannot be null."); + } + + if (sourceCollection == null) + { + throw new ArgumentNullException("sourceCollection", "Collection cannot be null."); + } + + foreach (T element in sourceCollection) + { + if (targetCollection.Contains(element)) + { + targetCollection.Remove(element); + } + } + } + + #endregion } diff --git a/src/Spring/Spring.Core/Util/IChainableConfigSystem.cs b/src/Spring/Spring.Core/Util/IChainableConfigSystem.cs index ccf67ffb..70272e0a 100644 --- a/src/Spring/Spring.Core/Util/IChainableConfigSystem.cs +++ b/src/Spring/Spring.Core/Util/IChainableConfigSystem.cs @@ -20,18 +20,17 @@ using System.Configuration.Internal; -namespace Spring.Util +namespace Spring.Util; + +/// +/// Implement this interface to create your own, delegating +/// and set them using +/// +public interface IChainableConfigSystem : IInternalConfigSystem { /// - /// Implement this interface to create your own, delegating - /// and set them using + /// /// - public interface IChainableConfigSystem : IInternalConfigSystem - { - /// - /// - /// - /// - void SetInnerConfigurationSystem(IInternalConfigSystem innerConfigSystem); - } + /// + void SetInnerConfigurationSystem(IInternalConfigSystem innerConfigSystem); } diff --git a/src/Spring/Spring.Core/Util/IErrorHandler.cs b/src/Spring/Spring.Core/Util/IErrorHandler.cs index 82cf42a0..bb069852 100644 --- a/src/Spring/Spring.Core/Util/IErrorHandler.cs +++ b/src/Spring/Spring.Core/Util/IErrorHandler.cs @@ -18,23 +18,20 @@ #endregion -namespace Spring.Util +namespace Spring.Util; + +/// +/// A strategy for handling errors. This is especially useful for handling +/// errors that occur during asynchronous execution as in such cases it may not be +/// possible to throw the error to the original caller. +/// +/// Mark Fisher +/// Mark Pollack (.NET) +public interface IErrorHandler { /// - /// A strategy for handling errors. This is especially useful for handling - /// errors that occur during asynchronous execution as in such cases it may not be - /// possible to throw the error to the original caller. + /// Handles the error. /// - /// Mark Fisher - /// Mark Pollack (.NET) - public interface IErrorHandler - { - /// - /// Handles the error. - /// - /// The exception. - void HandleError(Exception exception); - - } - + /// The exception. + void HandleError(Exception exception); } diff --git a/src/Spring/Spring.Core/Util/IEventExceptionsCollector.cs b/src/Spring/Spring.Core/Util/IEventExceptionsCollector.cs index ee1fbd8b..f3a86331 100644 --- a/src/Spring/Spring.Core/Util/IEventExceptionsCollector.cs +++ b/src/Spring/Spring.Core/Util/IEventExceptionsCollector.cs @@ -1,10 +1,9 @@ -namespace Spring.Util +namespace Spring.Util; + +public interface IEventExceptionsCollector { - public interface IEventExceptionsCollector - { - bool HasExceptions { get; } - IList Sources { get;} - IList Exceptions { get; } - Exception this[Delegate source] { get; } - } + bool HasExceptions { get; } + IList Sources { get; } + IList Exceptions { get; } + Exception this[Delegate source] { get; } } diff --git a/src/Spring/Spring.Core/Util/IStringValueResolver.cs b/src/Spring/Spring.Core/Util/IStringValueResolver.cs index 1d492bec..ae6f5161 100644 --- a/src/Spring/Spring.Core/Util/IStringValueResolver.cs +++ b/src/Spring/Spring.Core/Util/IStringValueResolver.cs @@ -1,15 +1,14 @@ -namespace Spring.Util +namespace Spring.Util; + +/// +/// Simple strategy interface for resolving a String value. +/// +public interface IStringValueResolver { /// - /// Simple strategy interface for resolving a String value. + /// Resolve the given String value, for example parsing placeholders. /// - public interface IStringValueResolver - { - /// - /// Resolve the given String value, for example parsing placeholders. - /// - /// the original String value - /// the resolved String value - string ParseAndResolveVariables(string value); - } + /// the original String value + /// the resolved String value + string ParseAndResolveVariables(string value); } diff --git a/src/Spring/Spring.Core/Util/ITextPosition.cs b/src/Spring/Spring.Core/Util/ITextPosition.cs index 36b9ac5e..6d3db614 100644 --- a/src/Spring/Spring.Core/Util/ITextPosition.cs +++ b/src/Spring/Spring.Core/Util/ITextPosition.cs @@ -18,26 +18,27 @@ #endregion -namespace Spring.Util +namespace Spring.Util; + +/// +/// Holds text position information for e.g. error reporting purposes. +/// +/// +/// +public interface ITextPosition : System.Configuration.Internal.IConfigErrorInfo { + /// + /// Gets a string specifying the file/resource name related to the configuration details. + /// + new string Filename { get; } + + /// + /// Gets an integer specifying the line number related to the configuration details. + /// + new int LineNumber { get; } + /// - /// Holds text position information for e.g. error reporting purposes. + /// Gets an integer specifying the line position related to the configuration details. /// - /// - /// - public interface ITextPosition : System.Configuration.Internal.IConfigErrorInfo - { - /// - /// Gets a string specifying the file/resource name related to the configuration details. - /// - new string Filename { get; } - /// - /// Gets an integer specifying the line number related to the configuration details. - /// - new int LineNumber { get; } - /// - /// Gets an integer specifying the line position related to the configuration details. - /// - int LinePosition { get; } - } + int LinePosition { get; } } diff --git a/src/Spring/Spring.Core/Util/IoUtils.cs b/src/Spring/Spring.Core/Util/IoUtils.cs index ed187e11..71f9449a 100644 --- a/src/Spring/Spring.Core/Util/IoUtils.cs +++ b/src/Spring/Spring.Core/Util/IoUtils.cs @@ -1,47 +1,45 @@ -namespace Spring.Util +namespace Spring.Util; + +/// +/// Utility methods for IO handling +/// +internal sealed class IOUtils { - /// - /// Utility methods for IO handling - /// - internal sealed class IOUtils + private IOUtils() { - private IOUtils() + throw new InvalidOperationException("instantiation not supported"); + } + + /// + /// Copies one stream into another. + /// (Don't forget to call on the destination stream!) + /// + /// + /// Does not close the input stream! + /// + public static void CopyStream(Stream src, Stream dest) + { + int bufferSize = 2048; + byte[] buffer = new byte[bufferSize]; + + int bytesRead = 0; + while ((bytesRead = src.Read(buffer, 0, bufferSize)) > 0) { - throw new InvalidOperationException("instantiation not supported"); - } - - /// - /// Copies one stream into another. - /// (Don't forget to call on the destination stream!) - /// - /// - /// Does not close the input stream! - /// - public static void CopyStream(Stream src, Stream dest) - { - int bufferSize = 2048; - byte[] buffer = new byte[bufferSize]; - - int bytesRead = 0; - while ((bytesRead = src.Read(buffer, 0, bufferSize)) > 0) - { - dest.Write(buffer, 0, bytesRead); - } - } - - /// - /// Reads a stream into a byte array. - /// - /// - /// Does not close the input stream! - /// - public static byte[] ToByteArray(Stream src) - { - MemoryStream stm = new MemoryStream(); - CopyStream(src, stm); - stm.Close(); - return stm.ToArray(); + dest.Write(buffer, 0, bytesRead); } + } + /// + /// Reads a stream into a byte array. + /// + /// + /// Does not close the input stream! + /// + public static byte[] ToByteArray(Stream src) + { + MemoryStream stm = new MemoryStream(); + CopyStream(src, stm); + stm.Close(); + return stm.ToArray(); } } diff --git a/src/Spring/Spring.Core/Util/NumberUtils.cs b/src/Spring/Spring.Core/Util/NumberUtils.cs index fcf4c68a..1e51cca6 100644 --- a/src/Spring/Spring.Core/Util/NumberUtils.cs +++ b/src/Spring/Spring.Core/Util/NumberUtils.cs @@ -20,558 +20,558 @@ using System.ComponentModel; -namespace Spring.Util +namespace Spring.Util; + +/// +/// Various utility methods relating to numbers. +/// +/// +///

+/// Mainly for internal use within the framework. +///

+///
+/// Aleksandar Seovic +public sealed class NumberUtils { /// - /// Various utility methods relating to numbers. + /// Determines whether the supplied is an integer. /// - /// - ///

- /// Mainly for internal use within the framework. - ///

- ///
- /// Aleksandar Seovic - public sealed class NumberUtils + /// The object to check. + /// + /// if the supplied is an integer. + /// + public static bool IsInteger(object number) { - /// - /// Determines whether the supplied is an integer. - /// - /// The object to check. - /// - /// if the supplied is an integer. - /// - public static bool IsInteger(object number) - { - return (number is Int32 || number is Int16 || number is Int64 || number is UInt32 + return (number is Int32 || number is Int16 || number is Int64 || number is UInt32 || number is UInt16 || number is UInt64 || number is Byte || number is SByte); - } + } - /// - /// Determines whether the supplied is a decimal number. - /// - /// The object to check. - /// - /// if the supplied is a decimal number. - /// - public static bool IsDecimal(object number) - { + /// + /// Determines whether the supplied is a decimal number. + /// + /// The object to check. + /// + /// if the supplied is a decimal number. + /// + public static bool IsDecimal(object number) + { + return (number is Single || number is Double || number is Decimal); + } - return (number is Single || number is Double || number is Decimal); - } + /// + /// Determines whether the supplied is of numeric type. + /// + /// The object to check. + /// + /// true if the specified object is of numeric type; otherwise, false. + /// + public static bool IsNumber(object number) + { + return (IsInteger(number) || IsDecimal(number)); + } - /// - /// Determines whether the supplied is of numeric type. - /// - /// The object to check. - /// - /// true if the specified object is of numeric type; otherwise, false. - /// - public static bool IsNumber(object number) - { - return (IsInteger(number) || IsDecimal(number)); - } - - /// - /// Determines whether the supplied can be converted to an integer. - /// - /// The object to check. - /// - /// if the supplied can be converted to an integer. - /// - public static bool CanConvertToInteger(object number) - { - TypeConverter converter = TypeDescriptor.GetConverter(number); - return (converter.CanConvertTo(typeof(Int32)) + /// + /// Determines whether the supplied can be converted to an integer. + /// + /// The object to check. + /// + /// if the supplied can be converted to an integer. + /// + public static bool CanConvertToInteger(object number) + { + TypeConverter converter = TypeDescriptor.GetConverter(number); + return (converter.CanConvertTo(typeof(Int32)) || converter.CanConvertTo(typeof(Int16)) || converter.CanConvertTo(typeof(Int64)) || converter.CanConvertTo(typeof(UInt16)) || converter.CanConvertTo(typeof(UInt64)) || converter.CanConvertTo(typeof(Byte)) || converter.CanConvertTo(typeof(SByte)) - ); - } + ); + } - /// - /// Determines whether the supplied can be converted to an integer. - /// - /// The object to check. - /// - /// if the supplied can be converted to an integer. - /// - public static bool CanConvertToDecimal(object number) - { - TypeConverter converter = TypeDescriptor.GetConverter(number); - return (converter.CanConvertTo(typeof(Single)) + /// + /// Determines whether the supplied can be converted to an integer. + /// + /// The object to check. + /// + /// if the supplied can be converted to an integer. + /// + public static bool CanConvertToDecimal(object number) + { + TypeConverter converter = TypeDescriptor.GetConverter(number); + return (converter.CanConvertTo(typeof(Single)) || converter.CanConvertTo(typeof(Double)) || converter.CanConvertTo(typeof(Decimal)) - ); - } + ); + } - /// - /// Determines whether the supplied can be converted to a number. - /// - /// The object to check. - /// - /// true if the specified object is decimal number; otherwise, false. - /// - public static bool CanConvertToNumber(object number) + /// + /// Determines whether the supplied can be converted to a number. + /// + /// The object to check. + /// + /// true if the specified object is decimal number; otherwise, false. + /// + public static bool CanConvertToNumber(object number) + { + return (CanConvertToInteger(number) || CanConvertToDecimal(number)); + } + + /// + /// Is the supplied equal to zero (0)? + /// + /// The number to check. + /// + /// id the supplied is equal to zero (0). + /// + public static bool IsZero(object number) + { + if (number is Int32) + return ((Int32) number) == 0; + else if (number is Int16) + return ((Int16) number) == 0; + else if (number is Int64) + return ((Int64) number) == 0; + else if (number is UInt16) + return ((UInt16) number) == 0; + else if (number is UInt32) + return ((UInt32) number) == 0; + else if (number is UInt64) + return (Convert.ToDecimal(number) == 0); + else if (number is Byte) + return ((Byte) number) == 0; + else if (number is SByte) + return ((SByte) number) == 0; + else if (number is Single) + return ((Single) number) == 0f; + else if (number is Double) + return ((Double) number) == 0d; + else if (number is Decimal) + return ((Decimal) number) == 0m; + return false; + } + + /// + /// Negates the supplied . + /// + /// The number to negate. + /// The supplied negated. + /// + /// If the supplied is not a supported numeric type. + /// + public static object Negate(object number) + { + if (number is Int32) + return -((Int32) number); + else if (number is Int16) + return -((Int16) number); + else if (number is Int64) + return -((Int64) number); + else if (number is UInt16) + return -((Int32) number); + else if (number is UInt32) + return -((Int64) number); + else if (number is UInt64) + return -(Convert.ToDecimal(number)); + else if (number is Byte) + return -((Int16) number); + else if (number is SByte) + return -((Int16) number); + else if (number is Single) + return -((Single) number); + else if (number is Double) + return -((Double) number); + else if (number is Decimal) + return -((Decimal) number); + else { - return (CanConvertToInteger(number) || CanConvertToDecimal(number)); + throw new ArgumentException(string.Format("'{0}' is not one of the supported numeric types.", number)); } + } - /// - /// Is the supplied equal to zero (0)? - /// - /// The number to check. - /// - /// id the supplied is equal to zero (0). - /// - public static bool IsZero(object number) + /// + /// Returns the bitwise not (~) of the supplied . + /// + /// The number. + /// The value of ~. + /// + /// If the supplied is not a supported numeric type. + /// + public static object BitwiseNot(object number) + { + if (number is bool) + return !((bool) number); + else if (number is Int32) + return ~((Int32) number); + else if (number is Int16) + return ~((Int16) number); + else if (number is Int64) + return ~((Int64) number); + else if (number is UInt16) + return ~((UInt16) number); + else if (number is UInt32) + return ~((UInt32) number); + else if (number is UInt64) + return ~((UInt64) number); + else if (number is Byte) + return ~((Byte) number); + else if (number is SByte) + return ~((SByte) number); + else { - if (number is Int32) - return ((Int32)number) == 0; - else if (number is Int16) - return ((Int16)number) == 0; - else if (number is Int64) - return ((Int64)number) == 0; - else if (number is UInt16) - return ((UInt16)number) == 0; - else if (number is UInt32) - return ((UInt32)number) == 0; - else if (number is UInt64) - return (Convert.ToDecimal(number) == 0); - else if (number is Byte) - return ((Byte)number) == 0; - else if (number is SByte) - return ((SByte)number) == 0; - else if (number is Single) - return ((Single)number) == 0f; - else if (number is Double) - return ((Double)number) == 0d; - else if (number is Decimal) - return ((Decimal)number) == 0m; - return false; + throw new ArgumentException(string.Format("'{0}' is not one of the supported integer types.", number)); } + } - /// - /// Negates the supplied . - /// - /// The number to negate. - /// The supplied negated. - /// - /// If the supplied is not a supported numeric type. - /// - public static object Negate(object number) + /// + /// Bitwise ANDs (&) the specified integral values. + /// + /// The first number. + /// The second number. + /// + /// If one of the supplied arguments is not a supported integral types. + /// + public static object BitwiseAnd(object m, object n) + { + CoerceTypes(ref m, ref n); + + if (n is bool) + return (bool) m & (bool) n; + else if (n is Int32) + return (Int32) m & (Int32) n; + else if (n is Int16) + return (Int16) m & (Int16) n; + else if (n is Int64) + return (Int64) m & (Int64) n; + else if (n is UInt16) + return (UInt16) m & (UInt16) n; + else if (n is UInt32) + return (UInt32) m & (UInt32) n; + else if (n is UInt64) + return (UInt64) m & (UInt64) n; + else if (n is Byte) + return (Byte) m & (Byte) n; + else if (n is SByte) + return (SByte) m & (SByte) n; + else { - if (number is Int32) - return -((Int32)number); - else if (number is Int16) - return -((Int16)number); - else if (number is Int64) - return -((Int64)number); - else if (number is UInt16) - return -((Int32)number); - else if (number is UInt32) - return -((Int64)number); - else if (number is UInt64) - return -(Convert.ToDecimal(number)); - else if (number is Byte) - return -((Int16)number); - else if (number is SByte) - return -((Int16)number); - else if (number is Single) - return -((Single)number); - else if (number is Double) - return -((Double)number); - else if (number is Decimal) - return -((Decimal)number); - else - { - throw new ArgumentException(string.Format("'{0}' is not one of the supported numeric types.", number)); - } - } - - /// - /// Returns the bitwise not (~) of the supplied . - /// - /// The number. - /// The value of ~. - /// - /// If the supplied is not a supported numeric type. - /// - public static object BitwiseNot(object number) - { - if (number is bool) - return !((bool)number); - else if (number is Int32) - return ~((Int32)number); - else if (number is Int16) - return ~((Int16)number); - else if (number is Int64) - return ~((Int64)number); - else if (number is UInt16) - return ~((UInt16)number); - else if (number is UInt32) - return ~((UInt32)number); - else if (number is UInt64) - return ~((UInt64)number); - else if (number is Byte) - return ~((Byte)number); - else if (number is SByte) - return ~((SByte)number); - else - { - throw new ArgumentException(string.Format("'{0}' is not one of the supported integer types.", number)); - } - } - - /// - /// Bitwise ANDs (&) the specified integral values. - /// - /// The first number. - /// The second number. - /// - /// If one of the supplied arguments is not a supported integral types. - /// - public static object BitwiseAnd(object m, object n) - { - CoerceTypes(ref m, ref n); - - if (n is bool) - return (bool)m & (bool)n; - else if (n is Int32) - return (Int32)m & (Int32)n; - else if (n is Int16) - return (Int16)m & (Int16)n; - else if (n is Int64) - return (Int64)m & (Int64)n; - else if (n is UInt16) - return (UInt16)m & (UInt16)n; - else if (n is UInt32) - return (UInt32)m & (UInt32)n; - else if (n is UInt64) - return (UInt64)m & (UInt64)n; - else if (n is Byte) - return (Byte)m & (Byte)n; - else if (n is SByte) - return (SByte)m & (SByte)n; - else - { - throw new ArgumentException(string.Format("'{0}' and/or '{1}' are not one of the supported integral types.", m, n)); - } - } - - /// - /// Bitwise ORs (|) the specified integral values. - /// - /// The first number. - /// The second number. - /// - /// If one of the supplied arguments is not a supported integral types. - /// - public static object BitwiseOr(object m, object n) - { - CoerceTypes(ref m, ref n); - - if (n is bool) - return (bool)m | (bool)n; - else if (n is Int32) - return (Int32)m | (Int32)n; - else if (n is Int16) - return (Int16)m | (Int16)n; - else if (n is Int64) - return (Int64)m | (Int64)n; - else if (n is UInt16) - return (UInt16)m | (UInt16)n; - else if (n is UInt32) - return (UInt32)m | (UInt32)n; - else if (n is UInt64) - return (UInt64)m | (UInt64)n; - else if (n is Byte) - return (Byte)m | (Byte)n; - else if (n is SByte) - { - if (SystemUtils.MonoRuntime) - { - SByte x = (sbyte) n; - SByte y = (sbyte) m; - int result = (int) x | (int) y; - return SByte.Parse(result.ToString()); - } - return (SByte) ((SByte) m | (SByte) n); - } throw new ArgumentException(string.Format("'{0}' and/or '{1}' are not one of the supported integral types.", m, n)); } - - /// - /// Bitwise XORs (^) the specified integral values. - /// - /// The first number. - /// The second number. - /// - /// If one of the supplied arguments is not a supported integral types. - /// - public static object BitwiseXor(object m, object n) - { - CoerceTypes(ref m, ref n); - - if (n is bool) - return (bool)m ^ (bool)n; - else if (n is Int32) - return (Int32)m ^ (Int32)n; - else if (n is Int16) - return (Int16)m ^ (Int16)n; - else if (n is Int64) - return (Int64)m ^ (Int64)n; - else if (n is UInt16) - return (UInt16)m ^ (UInt16)n; - else if (n is UInt32) - return (UInt32)m ^ (UInt32)n; - else if (n is UInt64) - return (UInt64)m ^ (UInt64)n; - else if (n is Byte) - return (Byte)m ^ (Byte)n; - else if (n is SByte) - return (SByte)m ^ (SByte)n; - else - { - throw new ArgumentException(string.Format("'{0}' and/or '{1}' are not one of the supported integral types.", m, n)); - } - } - - /// - /// Adds the specified numbers. - /// - /// The first number. - /// The second number. - public static object Add(object m, object n) - { - CoerceTypes(ref m, ref n); - - if (n is Int32) - return (Int32)m + (Int32)n; - else if (n is Int16) - return (Int16)m + (Int16)n; - else if (n is Int64) - return (Int64)m + (Int64)n; - else if (n is UInt16) - return (UInt16)m + (UInt16)n; - else if (n is UInt32) - return (UInt32)m + (UInt32)n; - else if (n is UInt64) - return (UInt64)m + (UInt64)n; - else if (n is Byte) - return (Byte)m + (Byte)n; - else if (n is SByte) - return (SByte)m + (SByte)n; - else if (n is Single) - return (Single)m + (Single)n; - else if (n is Double) - return (Double)m + (Double)n; - else if (n is Decimal) - return (Decimal)m + (Decimal)n; - else - { - throw new ArgumentException(string.Format("'{0}' and/or '{1}' are not one of the supported numeric types.", m, n)); - } - } - - /// - /// Subtracts the specified numbers. - /// - /// The first number. - /// The second number. - public static object Subtract(object m, object n) - { - CoerceTypes(ref m, ref n); - - if (n is Int32) - return (Int32)m - (Int32)n; - else if (n is Int16) - return (Int16)m - (Int16)n; - else if (n is Int64) - return (Int64)m - (Int64)n; - else if (n is UInt16) - return (UInt16)m - (UInt16)n; - else if (n is UInt32) - return (UInt32)m - (UInt32)n; - else if (n is UInt64) - return (UInt64)m - (UInt64)n; - else if (n is Byte) - return (Byte)m - (Byte)n; - else if (n is SByte) - return (SByte)m - (SByte)n; - else if (n is Single) - return (Single)m - (Single)n; - else if (n is Double) - return (Double)m - (Double)n; - else if (n is Decimal) - return (Decimal)m - (Decimal)n; - else - { - throw new ArgumentException(string.Format("'{0}' and/or '{1}' are not one of the supported numeric types.", m, n)); - } - } - - /// - /// Multiplies the specified numbers. - /// - /// The first number. - /// The second number. - public static object Multiply(object m, object n) - { - CoerceTypes(ref m, ref n); - - if (n is Int32) - return (Int32)m * (Int32)n; - else if (n is Int16) - return (Int16)m * (Int16)n; - else if (n is Int64) - return (Int64)m * (Int64)n; - else if (n is UInt16) - return (UInt16)m * (UInt16)n; - else if (n is UInt32) - return (UInt32)m * (UInt32)n; - else if (n is UInt64) - return (UInt64)m * (UInt64)n; - else if (n is Byte) - return (Byte)m * (Byte)n; - else if (n is SByte) - return (SByte)m * (SByte)n; - else if (n is Single) - return (Single)m * (Single)n; - else if (n is Double) - return (Double)m * (Double)n; - else if (n is Decimal) - return (Decimal)m * (Decimal)n; - else - { - throw new ArgumentException(string.Format("'{0}' and/or '{1}' are not one of the supported numeric types.", m, n)); - } - } - - /// - /// Divides the specified numbers. - /// - /// The first number. - /// The second number. - public static object Divide(object m, object n) - { - CoerceTypes(ref m, ref n); - - if (n is Int32) - return (Int32)m / (Int32)n; - else if (n is Int16) - return (Int16)m / (Int16)n; - else if (n is Int64) - return (Int64)m / (Int64)n; - else if (n is UInt16) - return (UInt16)m / (UInt16)n; - else if (n is UInt32) - return (UInt32)m / (UInt32)n; - else if (n is UInt64) - return (UInt64)m / (UInt64)n; - else if (n is Byte) - return (Byte)m / (Byte)n; - else if (n is SByte) - return (SByte)m / (SByte)n; - else if (n is Single) - return (Single)m / (Single)n; - else if (n is Double) - return (Double)m / (Double)n; - else if (n is Decimal) - return (Decimal)m / (Decimal)n; - else - { - throw new ArgumentException(string.Format("'{0}' and/or '{1}' are not one of the supported numeric types.", m, n)); - } - } - - /// - /// Calculates remainder for the specified numbers. - /// - /// The first number (dividend). - /// The second number (divisor). - public static object Modulus(object m, object n) - { - CoerceTypes(ref m, ref n); - - if (n is Int32) - return (Int32)m % (Int32)n; - else if (n is Int16) - return (Int16)m % (Int16)n; - else if (n is Int64) - return (Int64)m % (Int64)n; - else if (n is UInt16) - return (UInt16)m % (UInt16)n; - else if (n is UInt32) - return (UInt32)m % (UInt32)n; - else if (n is UInt64) - return (UInt64)m % (UInt64)n; - else if (n is Byte) - return (Byte)m % (Byte)n; - else if (n is SByte) - return (SByte)m % (SByte)n; - else if (n is Single) - return (Single)m % (Single)n; - else if (n is Double) - return (Double)m % (Double)n; - else if (n is Decimal) - return (Decimal)m % (Decimal)n; - else - { - throw new ArgumentException(string.Format("'{0}' and/or '{1}' are not one of the supported numeric types.", m, n)); - } - } - - /// - /// Raises first number to the power of the second one. - /// - /// The first number. - /// The second number. - public static object Power(object m, object n) - { - return Math.Pow(Convert.ToDouble(m), Convert.ToDouble(n)); - } - - /// - /// Coerces the types so they can be compared. - /// - /// The right. - /// The left. - public static void CoerceTypes(ref object m, ref object n) - { - TypeCode leftTypeCode = Convert.GetTypeCode(m); - TypeCode rightTypeCode = Convert.GetTypeCode(n); - - if (leftTypeCode > rightTypeCode) - { - n = Convert.ChangeType(n, leftTypeCode); - } - else - { - m = Convert.ChangeType(m, rightTypeCode); - } - } - - #region Constructor (s) / Destructor - - // CLOVER:OFF - - /// - /// Creates a new instance of the class. - /// - /// - ///

- /// This is a utility class, and as such exposes no public constructors. - ///

- ///
- private NumberUtils() - { - } - - // CLOVER:ON - - #endregion } + + /// + /// Bitwise ORs (|) the specified integral values. + /// + /// The first number. + /// The second number. + /// + /// If one of the supplied arguments is not a supported integral types. + /// + public static object BitwiseOr(object m, object n) + { + CoerceTypes(ref m, ref n); + + if (n is bool) + return (bool) m | (bool) n; + else if (n is Int32) + return (Int32) m | (Int32) n; + else if (n is Int16) + return (Int16) m | (Int16) n; + else if (n is Int64) + return (Int64) m | (Int64) n; + else if (n is UInt16) + return (UInt16) m | (UInt16) n; + else if (n is UInt32) + return (UInt32) m | (UInt32) n; + else if (n is UInt64) + return (UInt64) m | (UInt64) n; + else if (n is Byte) + return (Byte) m | (Byte) n; + else if (n is SByte) + { + if (SystemUtils.MonoRuntime) + { + SByte x = (sbyte) n; + SByte y = (sbyte) m; + int result = (int) x | (int) y; + return SByte.Parse(result.ToString()); + } + + return (SByte) ((SByte) m | (SByte) n); + } + + throw new ArgumentException(string.Format("'{0}' and/or '{1}' are not one of the supported integral types.", m, n)); + } + + /// + /// Bitwise XORs (^) the specified integral values. + /// + /// The first number. + /// The second number. + /// + /// If one of the supplied arguments is not a supported integral types. + /// + public static object BitwiseXor(object m, object n) + { + CoerceTypes(ref m, ref n); + + if (n is bool) + return (bool) m ^ (bool) n; + else if (n is Int32) + return (Int32) m ^ (Int32) n; + else if (n is Int16) + return (Int16) m ^ (Int16) n; + else if (n is Int64) + return (Int64) m ^ (Int64) n; + else if (n is UInt16) + return (UInt16) m ^ (UInt16) n; + else if (n is UInt32) + return (UInt32) m ^ (UInt32) n; + else if (n is UInt64) + return (UInt64) m ^ (UInt64) n; + else if (n is Byte) + return (Byte) m ^ (Byte) n; + else if (n is SByte) + return (SByte) m ^ (SByte) n; + else + { + throw new ArgumentException(string.Format("'{0}' and/or '{1}' are not one of the supported integral types.", m, n)); + } + } + + /// + /// Adds the specified numbers. + /// + /// The first number. + /// The second number. + public static object Add(object m, object n) + { + CoerceTypes(ref m, ref n); + + if (n is Int32) + return (Int32) m + (Int32) n; + else if (n is Int16) + return (Int16) m + (Int16) n; + else if (n is Int64) + return (Int64) m + (Int64) n; + else if (n is UInt16) + return (UInt16) m + (UInt16) n; + else if (n is UInt32) + return (UInt32) m + (UInt32) n; + else if (n is UInt64) + return (UInt64) m + (UInt64) n; + else if (n is Byte) + return (Byte) m + (Byte) n; + else if (n is SByte) + return (SByte) m + (SByte) n; + else if (n is Single) + return (Single) m + (Single) n; + else if (n is Double) + return (Double) m + (Double) n; + else if (n is Decimal) + return (Decimal) m + (Decimal) n; + else + { + throw new ArgumentException(string.Format("'{0}' and/or '{1}' are not one of the supported numeric types.", m, n)); + } + } + + /// + /// Subtracts the specified numbers. + /// + /// The first number. + /// The second number. + public static object Subtract(object m, object n) + { + CoerceTypes(ref m, ref n); + + if (n is Int32) + return (Int32) m - (Int32) n; + else if (n is Int16) + return (Int16) m - (Int16) n; + else if (n is Int64) + return (Int64) m - (Int64) n; + else if (n is UInt16) + return (UInt16) m - (UInt16) n; + else if (n is UInt32) + return (UInt32) m - (UInt32) n; + else if (n is UInt64) + return (UInt64) m - (UInt64) n; + else if (n is Byte) + return (Byte) m - (Byte) n; + else if (n is SByte) + return (SByte) m - (SByte) n; + else if (n is Single) + return (Single) m - (Single) n; + else if (n is Double) + return (Double) m - (Double) n; + else if (n is Decimal) + return (Decimal) m - (Decimal) n; + else + { + throw new ArgumentException(string.Format("'{0}' and/or '{1}' are not one of the supported numeric types.", m, n)); + } + } + + /// + /// Multiplies the specified numbers. + /// + /// The first number. + /// The second number. + public static object Multiply(object m, object n) + { + CoerceTypes(ref m, ref n); + + if (n is Int32) + return (Int32) m * (Int32) n; + else if (n is Int16) + return (Int16) m * (Int16) n; + else if (n is Int64) + return (Int64) m * (Int64) n; + else if (n is UInt16) + return (UInt16) m * (UInt16) n; + else if (n is UInt32) + return (UInt32) m * (UInt32) n; + else if (n is UInt64) + return (UInt64) m * (UInt64) n; + else if (n is Byte) + return (Byte) m * (Byte) n; + else if (n is SByte) + return (SByte) m * (SByte) n; + else if (n is Single) + return (Single) m * (Single) n; + else if (n is Double) + return (Double) m * (Double) n; + else if (n is Decimal) + return (Decimal) m * (Decimal) n; + else + { + throw new ArgumentException(string.Format("'{0}' and/or '{1}' are not one of the supported numeric types.", m, n)); + } + } + + /// + /// Divides the specified numbers. + /// + /// The first number. + /// The second number. + public static object Divide(object m, object n) + { + CoerceTypes(ref m, ref n); + + if (n is Int32) + return (Int32) m / (Int32) n; + else if (n is Int16) + return (Int16) m / (Int16) n; + else if (n is Int64) + return (Int64) m / (Int64) n; + else if (n is UInt16) + return (UInt16) m / (UInt16) n; + else if (n is UInt32) + return (UInt32) m / (UInt32) n; + else if (n is UInt64) + return (UInt64) m / (UInt64) n; + else if (n is Byte) + return (Byte) m / (Byte) n; + else if (n is SByte) + return (SByte) m / (SByte) n; + else if (n is Single) + return (Single) m / (Single) n; + else if (n is Double) + return (Double) m / (Double) n; + else if (n is Decimal) + return (Decimal) m / (Decimal) n; + else + { + throw new ArgumentException(string.Format("'{0}' and/or '{1}' are not one of the supported numeric types.", m, n)); + } + } + + /// + /// Calculates remainder for the specified numbers. + /// + /// The first number (dividend). + /// The second number (divisor). + public static object Modulus(object m, object n) + { + CoerceTypes(ref m, ref n); + + if (n is Int32) + return (Int32) m % (Int32) n; + else if (n is Int16) + return (Int16) m % (Int16) n; + else if (n is Int64) + return (Int64) m % (Int64) n; + else if (n is UInt16) + return (UInt16) m % (UInt16) n; + else if (n is UInt32) + return (UInt32) m % (UInt32) n; + else if (n is UInt64) + return (UInt64) m % (UInt64) n; + else if (n is Byte) + return (Byte) m % (Byte) n; + else if (n is SByte) + return (SByte) m % (SByte) n; + else if (n is Single) + return (Single) m % (Single) n; + else if (n is Double) + return (Double) m % (Double) n; + else if (n is Decimal) + return (Decimal) m % (Decimal) n; + else + { + throw new ArgumentException(string.Format("'{0}' and/or '{1}' are not one of the supported numeric types.", m, n)); + } + } + + /// + /// Raises first number to the power of the second one. + /// + /// The first number. + /// The second number. + public static object Power(object m, object n) + { + return Math.Pow(Convert.ToDouble(m), Convert.ToDouble(n)); + } + + /// + /// Coerces the types so they can be compared. + /// + /// The right. + /// The left. + public static void CoerceTypes(ref object m, ref object n) + { + TypeCode leftTypeCode = Convert.GetTypeCode(m); + TypeCode rightTypeCode = Convert.GetTypeCode(n); + + if (leftTypeCode > rightTypeCode) + { + n = Convert.ChangeType(n, leftTypeCode); + } + else + { + m = Convert.ChangeType(m, rightTypeCode); + } + } + + #region Constructor (s) / Destructor + + // CLOVER:OFF + + /// + /// Creates a new instance of the class. + /// + /// + ///

+ /// This is a utility class, and as such exposes no public constructors. + ///

+ ///
+ private NumberUtils() + { + } + + // CLOVER:ON + + #endregion } diff --git a/src/Spring/Spring.Core/Util/ObjectUtils.cs b/src/Spring/Spring.Core/Util/ObjectUtils.cs index 1fe167e0..93ca4c6e 100644 --- a/src/Spring/Spring.Core/Util/ObjectUtils.cs +++ b/src/Spring/Spring.Core/Util/ObjectUtils.cs @@ -25,546 +25,557 @@ using System.Runtime.Remoting.Proxies; using Spring.Reflection.Dynamic; -namespace Spring.Util +namespace Spring.Util; + +/// +/// Helper methods with regard to objects, types, properties, etc. +/// +/// +///

+/// Not intended to be used directly by applications. +///

+///
+/// Rod Johnson +/// Juergen Hoeller +/// Rick Evans (.NET) +public sealed class ObjectUtils { /// - /// Helper methods with regard to objects, types, properties, etc. + /// The instance for this class. + /// + private static readonly ILogger log = LogManager.GetLogger(); + + /// + /// An empty object array. + /// + public static readonly object[] EmptyObjects = { }; + + private static readonly MethodInfo GetHashCodeMethodInfo; + + static ObjectUtils() + { + Type type = typeof(object); + GetHashCodeMethodInfo = type.GetMethod("GetHashCode"); + } + + // CLOVER:OFF + + /// + /// Creates a new instance of the class. /// /// ///

- /// Not intended to be used directly by applications. + /// This is a utility class, and as such exposes no public constructors. ///

///
- /// Rod Johnson - /// Juergen Hoeller - /// Rick Evans (.NET) - public sealed class ObjectUtils + private ObjectUtils() { - /// - /// The instance for this class. - /// - private static readonly ILogger log = LogManager.GetLogger(); + } - /// - /// An empty object array. - /// - public static readonly object[] EmptyObjects = { }; + // CLOVER:ON - private static readonly MethodInfo GetHashCodeMethodInfo; - - static ObjectUtils() - { - Type type = typeof(object); - GetHashCodeMethodInfo = type.GetMethod("GetHashCode"); - } - - // CLOVER:OFF - - /// - /// Creates a new instance of the class. - /// - /// - ///

- /// This is a utility class, and as such exposes no public constructors. - ///

- ///
- private ObjectUtils() + /// + /// Instantiates the type using the assembly specified to load the type. + /// + /// This is a convenience in the case of needing to instantiate a type but not + /// wanting to specify in the string the version, culture and public key token. + /// The assembly. + /// Name of the type. + /// + /// + /// If the or is + /// + /// + /// If cannot load the type from the assembly or the call to InstantiateType(Type) fails. + /// + public static object InstantiateType(Assembly assembly, string typeName) + { + AssertUtils.ArgumentNotNull(assembly, "assembly"); + AssertUtils.ArgumentNotNull(typeName, "typeName"); + Type resolvedType = assembly.GetType(typeName, false, false); + if (resolvedType == null) { + throw new FatalReflectionException( + string.Format( + CultureInfo.InvariantCulture, "Cannot load type named [{0}] from assembly [{1}].", typeName, assembly)); } - // CLOVER:ON + return InstantiateType(resolvedType); + } - /// - /// Instantiates the type using the assembly specified to load the type. - /// - /// This is a convenience in the case of needing to instantiate a type but not - /// wanting to specify in the string the version, culture and public key token. - /// The assembly. - /// Name of the type. - /// - /// - /// If the or is - /// - /// - /// If cannot load the type from the assembly or the call to InstantiateType(Type) fails. - /// - public static object InstantiateType(Assembly assembly, string typeName) - { - AssertUtils.ArgumentNotNull(assembly, "assembly"); - AssertUtils.ArgumentNotNull(typeName, "typeName"); - Type resolvedType = assembly.GetType(typeName, false, false); - if (resolvedType == null) - { - throw new FatalReflectionException( - string.Format( - CultureInfo.InvariantCulture, "Cannot load type named [{0}] from assembly [{1}].", typeName, assembly)); - } - return InstantiateType(resolvedType); - } - /// - /// Convenience method to instantiate a using - /// its no-arg constructor. - /// - /// - ///

- /// As this method doesn't try to instantiate s - /// by name, it should avoid loading issues. - ///

- ///
- /// - /// The to instantiate* - /// - /// A new instance of the . - /// - /// If the is - /// - /// - /// If the is an abstract class, an interface, - /// an open generic type or does not have a public no-argument constructor. - /// - public static object InstantiateType(Type type) - { - AssertUtils.ArgumentNotNull(type, "type"); + /// + /// Convenience method to instantiate a using + /// its no-arg constructor. + /// + /// + ///

+ /// As this method doesn't try to instantiate s + /// by name, it should avoid loading issues. + ///

+ ///
+ /// + /// The to instantiate* + /// + /// A new instance of the . + /// + /// If the is + /// + /// + /// If the is an abstract class, an interface, + /// an open generic type or does not have a public no-argument constructor. + /// + public static object InstantiateType(Type type) + { + AssertUtils.ArgumentNotNull(type, "type"); - ConstructorInfo constructor = GetZeroArgConstructorInfo(type); - return InstantiateType(constructor, EmptyObjects); + ConstructorInfo constructor = GetZeroArgConstructorInfo(type); + return InstantiateType(constructor, EmptyObjects); + } + + /// + /// Gets the zero arg ConstructorInfo object, if the type offers such functionality. + /// + /// The type. + /// Zero argument ConstructorInfo + /// + /// If the type is an interface, abstract, open generic type, or does not have a zero-arg constructor. + /// + public static ConstructorInfo GetZeroArgConstructorInfo(Type type) + { + IsInstantiable(type); + ConstructorInfo constructor = type.GetConstructor(Type.EmptyTypes); + if (constructor == null) + { + throw new FatalReflectionException( + string.Format( + CultureInfo.InvariantCulture, "Cannot instantiate a class that does not have a public no-argument constructor [{0}].", type)); } - /// - /// Gets the zero arg ConstructorInfo object, if the type offers such functionality. - /// - /// The type. - /// Zero argument ConstructorInfo - /// - /// If the type is an interface, abstract, open generic type, or does not have a zero-arg constructor. - /// - public static ConstructorInfo GetZeroArgConstructorInfo(Type type) + return constructor; + } + + /// + /// Determines whether the specified type is instantiable, i.e. not an interface, abstract class or contains + /// open generic type parameters. + /// + /// The type. + public static void IsInstantiable(Type type) + { + if (type.IsInterface) { - IsInstantiable(type); - ConstructorInfo constructor = type.GetConstructor(Type.EmptyTypes); - if (constructor == null) - { - throw new FatalReflectionException( - string.Format( - CultureInfo.InvariantCulture, "Cannot instantiate a class that does not have a public no-argument constructor [{0}].", type)); - } - return constructor; + throw new FatalReflectionException( + string.Format( + CultureInfo.InvariantCulture, "Cannot instantiate an interface [{0}].", type)); } - /// - /// Determines whether the specified type is instantiable, i.e. not an interface, abstract class or contains - /// open generic type parameters. - /// - /// The type. - public static void IsInstantiable(Type type) + if (type.IsAbstract) { - if (type.IsInterface) - { - throw new FatalReflectionException( - string.Format( - CultureInfo.InvariantCulture, "Cannot instantiate an interface [{0}].", type)); - } - if (type.IsAbstract) - { - throw new FatalReflectionException( - string.Format( - CultureInfo.InvariantCulture, "Cannot instantiate an abstract class [{0}].", type)); - } - if (type.ContainsGenericParameters) - { - throw new FatalReflectionException( - string.Format( - CultureInfo.InvariantCulture, "Cannot instantiate an open generic type [{0}].", type)); - } + throw new FatalReflectionException( + string.Format( + CultureInfo.InvariantCulture, "Cannot instantiate an abstract class [{0}].", type)); } - /// - /// Convenience method to instantiate a using - /// the given constructor. - /// - /// - ///

- /// As this method doesn't try to instantiate s - /// by name, it should avoid loading issues. - ///

- ///
- /// - /// The constructor to use for the instantiation. - /// - /// - /// The arguments to be passed to the constructor. - /// - /// A new instance. - /// - /// If the is - /// - /// - /// If the 's declaring type is an abstract class, - /// an interface, an open generic type or does not have a public no-argument constructor. - /// - public static object InstantiateType(ConstructorInfo constructor, object[] arguments) + if (type.ContainsGenericParameters) { - AssertUtils.ArgumentNotNull(constructor, "constructor"); - - if (log.IsEnabled(LogLevel.Trace)) log.LogTrace(string.Format("instantiating type [{0}] using constructor [{1}]", constructor.DeclaringType, constructor)); - - if (constructor.DeclaringType.IsInterface) - { - throw new FatalReflectionException( - string.Format( - CultureInfo.InvariantCulture, "Cannot instantiate an interface [{0}].", constructor.DeclaringType)); - } - if (constructor.DeclaringType.IsAbstract) - { - throw new FatalReflectionException( - string.Format( - CultureInfo.InvariantCulture, "Cannot instantiate an abstract class [{0}].", constructor.DeclaringType)); - } - if (constructor.DeclaringType.ContainsGenericParameters) - { - throw new FatalReflectionException( - string.Format( - CultureInfo.InvariantCulture, "Cannot instantiate an open generic type [{0}].", constructor.DeclaringType)); - } - try - { - // replaced with SafeConstructor() to avoid nasty "TargetInvocationException"s in NET >= 2.0 - return (new SafeConstructor(constructor)).Invoke(arguments); - } - catch (Exception ex) - { - Type ctorType = constructor.DeclaringType; - throw new FatalReflectionException( - string.Format( - CultureInfo.InvariantCulture, - "Cannot instantiate Type [{0}] using ctor [{1}] : '{2}'", - constructor.DeclaringType, constructor, ex.Message), - ex); - } - } - - /// - /// Checks whether the supplied is not a transparent proxy and is - /// assignable to the supplied . - /// - /// - ///

- /// Neccessary when dealing with server-activated remote objects, because the - /// object is of the type TransparentProxy and regular is testing for assignable - /// types does not work. - ///

- ///

- /// Transparent proxy instances always return when tested - /// with the 'is' operator (C#). This method only checks if the object - /// is assignable to the type if it is not a transparent proxy. - ///

- ///
- /// The target to be checked. - /// The value that should be assigned to the type. - /// - /// if the supplied is not a - /// transparent proxy and is assignable to the supplied . - /// - public static bool IsAssignableAndNotTransparentProxy(Type type, object instance) - { - if (!RemotingServices.IsTransparentProxy(instance)) - { - return IsAssignable(type, instance); - } - return false; - } - - /// - /// Determine if the given is assignable from the - /// given value, assuming setting by reflection and taking care of transparent proxies. - /// - /// - ///

- /// Considers primitive wrapper classes as assignable to the - /// corresponding primitive types. - ///

- ///

- /// For example used in an object factory's constructor resolution. - ///

- ///
- /// The target . - /// The value that should be assigned to the type. - /// True if the type is assignable from the value. - public static bool IsAssignable(Type type, object obj) - { - AssertUtils.ArgumentNotNull(type, "type"); - if (!type.IsPrimitive && obj == null) - { - return true; - } - -#if !NETSTANDARD - if (RemotingServices.IsTransparentProxy(obj)) - { - RealProxy rp = RemotingServices.GetRealProxy(obj); - if (rp is IRemotingTypeInfo remotingTypeInfo) - { - return remotingTypeInfo.CanCastTo(type, obj); - } - - if (rp != null) - { - type = rp.GetProxiedType(); - } - - if (type == null) - { - // cannot decide - return false; - } - } - #endif - if (type.IsInstanceOfType(obj)) - { - return true; - } - - return type.IsPrimitive && - type == typeof(bool) && obj is bool || - type == typeof(byte) && obj is byte || - type == typeof(char) && obj is char || - type == typeof(sbyte) && obj is sbyte || - type == typeof(int) && obj is int || - type == typeof(short) && obj is short || - type == typeof(long) && obj is long || - type == typeof(float) && obj is float || - type == typeof(double) && obj is double; - } - - /// - /// Check if the given represents a - /// "simple" property, - /// i.e. a primitive, a , a - /// , or a corresponding array. - /// - /// - ///

- /// Used to determine properties to check for a "simple" dependency-check. - ///

- ///
- /// - /// The to check. - /// - public static bool IsSimpleProperty(Type type) - { - return type.IsPrimitive - || type.Equals(typeof(string)) - || type.Equals(typeof(string[])) - || IsPrimitiveArray(type) - || type.Equals(typeof(Type)) - || type.Equals(typeof(Type[])); - } - - /// - /// Check if the given class represents a primitive array, - /// i.e. boolean, byte, char, short, int, long, float, or double. - /// - public static bool IsPrimitiveArray(Type type) - { - return typeof(bool[]).Equals(type) - || typeof(sbyte[]).Equals(type) - || typeof(char[]).Equals(type) - || typeof(short[]).Equals(type) - || typeof(int[]).Equals(type) - || typeof(long[]).Equals(type) - || typeof(float[]).Equals(type) - || typeof(double[]).Equals(type); - } - - - /// - /// Determines whether the specified array is null or empty. - /// - /// The array to check. - /// - /// true if the specified array is null empty; otherwise, false. - /// - public static bool IsEmpty(object[] array) - { - return (array == null || array.Length == 0); - } - /// - /// Determine if the given objects are equal, returning - /// if both are respectively - /// if only one is . - /// - /// The first object to compare. - /// The second object to compare. - /// - /// if the given objects are equal. - /// - public static bool NullSafeEquals(object o1, object o2) - { - return (o1 == o2 || (o1 != null && o1.Equals(o2))); - } - - - /// - /// Return as hash code for the given object; typically the value of - /// {@link Object#hashCode()}. If the object is an array, - /// this method will delegate to any of the nullSafeHashCode - /// methods for arrays in this class. If the object is null, - /// this method returns 0. - /// - public static int NullSafeHashCode(object o1) - { - return (o1 != null ? o1.GetHashCode() : 0); - } - - /// - /// Returns the first element in the supplied . - /// - /// - /// The to use to enumerate - /// elements. - /// - /// - /// The first element in the supplied . - /// - /// - /// If the supplied did not have any elements. - /// - public static object EnumerateFirstElement(IEnumerator enumerator) - { - return EnumerateElementAtIndex(enumerator, 0); - } - - /// - /// Returns the first element in the supplied . - /// - /// - /// The to use to enumerate - /// elements. - /// - /// - /// The first element in the supplied . - /// - /// - /// If the supplied did not have any elements. - /// - /// - /// If the supplied is . - /// - public static object EnumerateFirstElement(IEnumerable enumerable) - { - AssertUtils.ArgumentNotNull(enumerable, "enumerable"); - return EnumerateElementAtIndex(enumerable.GetEnumerator(), 0); - } - - /// - /// Returns the element at the specified index using the supplied - /// . - /// - /// - /// The to use to enumerate - /// elements until the supplied is reached. - /// - /// - /// The index of the element in the enumeration to return. - /// - /// - /// The element at the specified index using the supplied - /// . - /// - /// - /// If the supplied was less than zero, or the - /// supplied did not contain enough elements - /// to be able to reach the supplied . - /// - public static object EnumerateElementAtIndex(IEnumerator enumerator, int index) - { - if (index < 0) - { - throw new ArgumentOutOfRangeException(); - } - object element = null; - int i = 0; - while (enumerator.MoveNext()) - { - element = enumerator.Current; - if (++i > index) - { - break; - } - } - if (i < index) - { - throw new ArgumentOutOfRangeException(); - } - return element; - } - - /// - /// Returns the element at the specified index using the supplied - /// . - /// - /// - /// The to use to enumerate - /// elements until the supplied is reached. - /// - /// - /// The index of the element in the enumeration to return. - /// - /// - /// The element at the specified index using the supplied - /// . - /// - /// - /// If the supplied was less than zero, or the - /// supplied did not contain enough elements - /// to be able to reach the supplied . - /// - /// - /// If the supplied is . - /// - public static object EnumerateElementAtIndex(IEnumerable enumerable, int index) - { - AssertUtils.ArgumentNotNull(enumerable, "enumerable"); - return EnumerateElementAtIndex(enumerable.GetEnumerator(), index); - } - - /// - /// Gets the qualified name of the given method, consisting of - /// fully qualified interface/class name + "." method name. - /// - /// The method. - /// qualified name of the method. - public static string GetQualifiedMethodName(MethodInfo method) - { - AssertUtils.ArgumentNotNull(method, "method", "MethodInfo must not be null"); - return method.DeclaringType.FullName + "." + method.Name; - } - - /// - /// Return a String representation of an object's overall identity. - /// - /// The object (may be null). - /// The object's identity as String representation, - /// or an empty String if the object was null - /// - public static string IdentityToString(object obj) - { - if (obj == null) - { - return string.Empty; - } - return obj.GetType().FullName + "@" + GetIdentityHexString(obj); - } - - /// - /// Gets a hex String form of an object's identity hash code. - /// - /// The obj. - /// The object's identity code in hex notation - public static string GetIdentityHexString(object obj) - { - int hashcode = (int)GetHashCodeMethodInfo.Invoke(obj, null); - return hashcode.ToString("X6"); + throw new FatalReflectionException( + string.Format( + CultureInfo.InvariantCulture, "Cannot instantiate an open generic type [{0}].", type)); } } + + /// + /// Convenience method to instantiate a using + /// the given constructor. + /// + /// + ///

+ /// As this method doesn't try to instantiate s + /// by name, it should avoid loading issues. + ///

+ ///
+ /// + /// The constructor to use for the instantiation. + /// + /// + /// The arguments to be passed to the constructor. + /// + /// A new instance. + /// + /// If the is + /// + /// + /// If the 's declaring type is an abstract class, + /// an interface, an open generic type or does not have a public no-argument constructor. + /// + public static object InstantiateType(ConstructorInfo constructor, object[] arguments) + { + AssertUtils.ArgumentNotNull(constructor, "constructor"); + + if (log.IsEnabled(LogLevel.Trace)) log.LogTrace(string.Format("instantiating type [{0}] using constructor [{1}]", constructor.DeclaringType, constructor)); + + if (constructor.DeclaringType.IsInterface) + { + throw new FatalReflectionException( + string.Format( + CultureInfo.InvariantCulture, "Cannot instantiate an interface [{0}].", constructor.DeclaringType)); + } + + if (constructor.DeclaringType.IsAbstract) + { + throw new FatalReflectionException( + string.Format( + CultureInfo.InvariantCulture, "Cannot instantiate an abstract class [{0}].", constructor.DeclaringType)); + } + + if (constructor.DeclaringType.ContainsGenericParameters) + { + throw new FatalReflectionException( + string.Format( + CultureInfo.InvariantCulture, "Cannot instantiate an open generic type [{0}].", constructor.DeclaringType)); + } + + try + { + // replaced with SafeConstructor() to avoid nasty "TargetInvocationException"s in NET >= 2.0 + return (new SafeConstructor(constructor)).Invoke(arguments); + } + catch (Exception ex) + { + Type ctorType = constructor.DeclaringType; + throw new FatalReflectionException( + string.Format( + CultureInfo.InvariantCulture, + "Cannot instantiate Type [{0}] using ctor [{1}] : '{2}'", + constructor.DeclaringType, constructor, ex.Message), + ex); + } + } + + /// + /// Checks whether the supplied is not a transparent proxy and is + /// assignable to the supplied . + /// + /// + ///

+ /// Neccessary when dealing with server-activated remote objects, because the + /// object is of the type TransparentProxy and regular is testing for assignable + /// types does not work. + ///

+ ///

+ /// Transparent proxy instances always return when tested + /// with the 'is' operator (C#). This method only checks if the object + /// is assignable to the type if it is not a transparent proxy. + ///

+ ///
+ /// The target to be checked. + /// The value that should be assigned to the type. + /// + /// if the supplied is not a + /// transparent proxy and is assignable to the supplied . + /// + public static bool IsAssignableAndNotTransparentProxy(Type type, object instance) + { + if (!RemotingServices.IsTransparentProxy(instance)) + { + return IsAssignable(type, instance); + } + + return false; + } + + /// + /// Determine if the given is assignable from the + /// given value, assuming setting by reflection and taking care of transparent proxies. + /// + /// + ///

+ /// Considers primitive wrapper classes as assignable to the + /// corresponding primitive types. + ///

+ ///

+ /// For example used in an object factory's constructor resolution. + ///

+ ///
+ /// The target . + /// The value that should be assigned to the type. + /// True if the type is assignable from the value. + public static bool IsAssignable(Type type, object obj) + { + AssertUtils.ArgumentNotNull(type, "type"); + if (!type.IsPrimitive && obj == null) + { + return true; + } + +#if !NETSTANDARD + if (RemotingServices.IsTransparentProxy(obj)) + { + RealProxy rp = RemotingServices.GetRealProxy(obj); + if (rp is IRemotingTypeInfo remotingTypeInfo) + { + return remotingTypeInfo.CanCastTo(type, obj); + } + + if (rp != null) + { + type = rp.GetProxiedType(); + } + + if (type == null) + { + // cannot decide + return false; + } + } +#endif + if (type.IsInstanceOfType(obj)) + { + return true; + } + + return type.IsPrimitive && + type == typeof(bool) && obj is bool || + type == typeof(byte) && obj is byte || + type == typeof(char) && obj is char || + type == typeof(sbyte) && obj is sbyte || + type == typeof(int) && obj is int || + type == typeof(short) && obj is short || + type == typeof(long) && obj is long || + type == typeof(float) && obj is float || + type == typeof(double) && obj is double; + } + + /// + /// Check if the given represents a + /// "simple" property, + /// i.e. a primitive, a , a + /// , or a corresponding array. + /// + /// + ///

+ /// Used to determine properties to check for a "simple" dependency-check. + ///

+ ///
+ /// + /// The to check. + /// + public static bool IsSimpleProperty(Type type) + { + return type.IsPrimitive + || type.Equals(typeof(string)) + || type.Equals(typeof(string[])) + || IsPrimitiveArray(type) + || type.Equals(typeof(Type)) + || type.Equals(typeof(Type[])); + } + + /// + /// Check if the given class represents a primitive array, + /// i.e. boolean, byte, char, short, int, long, float, or double. + /// + public static bool IsPrimitiveArray(Type type) + { + return typeof(bool[]).Equals(type) + || typeof(sbyte[]).Equals(type) + || typeof(char[]).Equals(type) + || typeof(short[]).Equals(type) + || typeof(int[]).Equals(type) + || typeof(long[]).Equals(type) + || typeof(float[]).Equals(type) + || typeof(double[]).Equals(type); + } + + /// + /// Determines whether the specified array is null or empty. + /// + /// The array to check. + /// + /// true if the specified array is null empty; otherwise, false. + /// + public static bool IsEmpty(object[] array) + { + return (array == null || array.Length == 0); + } + + /// + /// Determine if the given objects are equal, returning + /// if both are respectively + /// if only one is . + /// + /// The first object to compare. + /// The second object to compare. + /// + /// if the given objects are equal. + /// + public static bool NullSafeEquals(object o1, object o2) + { + return (o1 == o2 || (o1 != null && o1.Equals(o2))); + } + + /// + /// Return as hash code for the given object; typically the value of + /// {@link Object#hashCode()}. If the object is an array, + /// this method will delegate to any of the nullSafeHashCode + /// methods for arrays in this class. If the object is null, + /// this method returns 0. + /// + public static int NullSafeHashCode(object o1) + { + return (o1 != null ? o1.GetHashCode() : 0); + } + + /// + /// Returns the first element in the supplied . + /// + /// + /// The to use to enumerate + /// elements. + /// + /// + /// The first element in the supplied . + /// + /// + /// If the supplied did not have any elements. + /// + public static object EnumerateFirstElement(IEnumerator enumerator) + { + return EnumerateElementAtIndex(enumerator, 0); + } + + /// + /// Returns the first element in the supplied . + /// + /// + /// The to use to enumerate + /// elements. + /// + /// + /// The first element in the supplied . + /// + /// + /// If the supplied did not have any elements. + /// + /// + /// If the supplied is . + /// + public static object EnumerateFirstElement(IEnumerable enumerable) + { + AssertUtils.ArgumentNotNull(enumerable, "enumerable"); + return EnumerateElementAtIndex(enumerable.GetEnumerator(), 0); + } + + /// + /// Returns the element at the specified index using the supplied + /// . + /// + /// + /// The to use to enumerate + /// elements until the supplied is reached. + /// + /// + /// The index of the element in the enumeration to return. + /// + /// + /// The element at the specified index using the supplied + /// . + /// + /// + /// If the supplied was less than zero, or the + /// supplied did not contain enough elements + /// to be able to reach the supplied . + /// + public static object EnumerateElementAtIndex(IEnumerator enumerator, int index) + { + if (index < 0) + { + throw new ArgumentOutOfRangeException(); + } + + object element = null; + int i = 0; + while (enumerator.MoveNext()) + { + element = enumerator.Current; + if (++i > index) + { + break; + } + } + + if (i < index) + { + throw new ArgumentOutOfRangeException(); + } + + return element; + } + + /// + /// Returns the element at the specified index using the supplied + /// . + /// + /// + /// The to use to enumerate + /// elements until the supplied is reached. + /// + /// + /// The index of the element in the enumeration to return. + /// + /// + /// The element at the specified index using the supplied + /// . + /// + /// + /// If the supplied was less than zero, or the + /// supplied did not contain enough elements + /// to be able to reach the supplied . + /// + /// + /// If the supplied is . + /// + public static object EnumerateElementAtIndex(IEnumerable enumerable, int index) + { + AssertUtils.ArgumentNotNull(enumerable, "enumerable"); + return EnumerateElementAtIndex(enumerable.GetEnumerator(), index); + } + + /// + /// Gets the qualified name of the given method, consisting of + /// fully qualified interface/class name + "." method name. + /// + /// The method. + /// qualified name of the method. + public static string GetQualifiedMethodName(MethodInfo method) + { + AssertUtils.ArgumentNotNull(method, "method", "MethodInfo must not be null"); + return method.DeclaringType.FullName + "." + method.Name; + } + + /// + /// Return a String representation of an object's overall identity. + /// + /// The object (may be null). + /// The object's identity as String representation, + /// or an empty String if the object was null + /// + public static string IdentityToString(object obj) + { + if (obj == null) + { + return string.Empty; + } + + return obj.GetType().FullName + "@" + GetIdentityHexString(obj); + } + + /// + /// Gets a hex String form of an object's identity hash code. + /// + /// The obj. + /// The object's identity code in hex notation + public static string GetIdentityHexString(object obj) + { + int hashcode = (int) GetHashCodeMethodInfo.Invoke(obj, null); + return hashcode.ToString("X6"); + } } diff --git a/src/Spring/Spring.Core/Util/PathMatcher.cs b/src/Spring/Spring.Core/Util/PathMatcher.cs index 67110885..2e651d55 100644 --- a/src/Spring/Spring.Core/Util/PathMatcher.cs +++ b/src/Spring/Spring.Core/Util/PathMatcher.cs @@ -1,21 +1,22 @@ //// + #region License /* -* Copyright � 2002-2011 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. -*/ + * Copyright � 2002-2011 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 @@ -26,202 +27,205 @@ using System.Text.RegularExpressions; #endregion -namespace Spring.Util +namespace Spring.Util; + +/// +/// Support matching of file system paths in a manner similar to that of the +/// NAnt FileSet. +/// +/// +///

+/// Any (back)slashes are converted to forward slashes. +///

+///
+/// +/// +/// // true +/// PathMatcher.Match("c:/*.bat", @"c:\autoexec.bat"); +/// PathMatcher.Match("c:\fo*\*.bat", @"c:/foobar/autoexec.bat"); +/// PathMatcher.Match("c:\fo?\*.bat", @"c:/foo/autoexec.bat"); +/// // false +/// PathMatcher.Match("c:\fo?\*.bat", @"c:/fo/autoexec.bat"); +/// +/// +/// Federico Spinazzi +public sealed class PathMatcher { - /// - /// Support matching of file system paths in a manner similar to that of the - /// NAnt FileSet. - /// - /// - ///

- /// Any (back)slashes are converted to forward slashes. - ///

- ///
- /// - /// - /// // true - /// PathMatcher.Match("c:/*.bat", @"c:\autoexec.bat"); - /// PathMatcher.Match("c:\fo*\*.bat", @"c:/foobar/autoexec.bat"); - /// PathMatcher.Match("c:\fo?\*.bat", @"c:/foo/autoexec.bat"); - /// // false - /// PathMatcher.Match("c:\fo?\*.bat", @"c:/fo/autoexec.bat"); - /// - /// - /// Federico Spinazzi - public sealed class PathMatcher - { - private const string AllFilesInThisDirectory = "*.*"; + private const string AllFilesInThisDirectory = "*.*"; - /// - /// Determines if a given path matches a NAnt-like pattern. - /// - /// - /// A forward or back-slashed fileset-like pattern. - /// - /// A forward or back-slashed full path. - /// should the match consider the case - /// - /// if the path is matched by the pattern; - /// otherwise . - /// - //// - public static bool Match(string pattern, string path, bool ignoreCase) - //// - { - return Match(ToLower(pattern), ToLower(path)); - } + /// + /// Determines if a given path matches a NAnt-like pattern. + /// + /// + /// A forward or back-slashed fileset-like pattern. + /// + /// A forward or back-slashed full path. + /// should the match consider the case + /// + /// if the path is matched by the pattern; + /// otherwise . + /// + //// + public static bool Match(string pattern, string path, bool ignoreCase) + //// + { + return Match(ToLower(pattern), ToLower(path)); + } - /// - /// Determines if a given path matches a NAnt-like pattern. - /// - /// - /// A forward or back-slashed fileset-like pattern. - /// - /// A forward or back-slashed full path. - /// - /// if the path is matched by the pattern; - /// otherwise . - /// - //// - public static bool Match(string pattern, string path) - //// - { - pattern = ForwardifySlashes(pattern); - path = ForwardifySlashes(path); + /// + /// Determines if a given path matches a NAnt-like pattern. + /// + /// + /// A forward or back-slashed fileset-like pattern. + /// + /// A forward or back-slashed full path. + /// + /// if the path is matched by the pattern; + /// otherwise . + /// + //// + public static bool Match(string pattern, string path) + //// + { + pattern = ForwardifySlashes(pattern); + path = ForwardifySlashes(path); - if (MatchAll(pattern)) - return true; + if (MatchAll(pattern)) + return true; - String regex = BuildRegex(pattern); - return Regex.Match(path, regex).Success; - } + String regex = BuildRegex(pattern); + return Regex.Match(path, regex).Success; + } - /// - /// Replaces back(slashes) with forward slashes. - /// - /// - /// The path or the pattern to modify. - /// - /// A forward-slashed string. - public static string ForwardifySlashes(string path) - { - return path.Replace("\\", "/"); - } + /// + /// Replaces back(slashes) with forward slashes. + /// + /// + /// The path or the pattern to modify. + /// + /// A forward-slashed string. + public static string ForwardifySlashes(string path) + { + return path.Replace("\\", "/"); + } - /// - /// Helper method to convert a NAnt-like pattern into the - /// appropriate pattern for a regular expression. - /// - /// The NAnt-like pattern. - /// A regex-compatible pattern. - public static String BuildRegex(string pattern) - { - if (AllFilesInThisDirectory.Equals(pattern)) - { - return "^[^/]*$"; - } - string[] parts = pattern.Split('/'); - int indexOfLastSplittedPart = parts.Length - 1; - int indexOfTheCurrentSplittedPart = 0; - StringBuilder regex = new StringBuilder(); - foreach (string currentSplittedPart in parts) - { - bool currentPartIsTheLast = indexOfTheCurrentSplittedPart == indexOfLastSplittedPart; - string partToAdd = currentSplittedPart; - switch (currentSplittedPart) - { - case "**": - partToAdd = TranslateDoubleAsterisk(currentPartIsTheLast); - break; - default: - partToAdd = TranslateDot(partToAdd); - partToAdd = TranslateAsterisk(partToAdd); - partToAdd = TranslateQuestionMark(partToAdd); - partToAdd = TranslateLiteral(partToAdd, currentPartIsTheLast); - break; - } - regex.Append(partToAdd); - indexOfTheCurrentSplittedPart++; - } - return regex.ToString(); - } - - private static string ToLower(string pattern) + /// + /// Helper method to convert a NAnt-like pattern into the + /// appropriate pattern for a regular expression. + /// + /// The NAnt-like pattern. + /// A regex-compatible pattern. + public static String BuildRegex(string pattern) + { + if (AllFilesInThisDirectory.Equals(pattern)) { - return pattern == null ? pattern : pattern.ToLower(); + return "^[^/]*$"; } - private static string TranslateLiteral(string part, bool isLastPart) - { - if (isLastPart) - { - return part + "$"; - } - else - { - return part + "/?"; - } - } + string[] parts = pattern.Split('/'); + int indexOfLastSplittedPart = parts.Length - 1; + int indexOfTheCurrentSplittedPart = 0; + StringBuilder regex = new StringBuilder(); + foreach (string currentSplittedPart in parts) + { + bool currentPartIsTheLast = indexOfTheCurrentSplittedPart == indexOfLastSplittedPart; + string partToAdd = currentSplittedPart; + switch (currentSplittedPart) + { + case "**": + partToAdd = TranslateDoubleAsterisk(currentPartIsTheLast); + break; + default: + partToAdd = TranslateDot(partToAdd); + partToAdd = TranslateAsterisk(partToAdd); + partToAdd = TranslateQuestionMark(partToAdd); + partToAdd = TranslateLiteral(partToAdd, currentPartIsTheLast); + break; + } - private static string TranslateDoubleAsterisk(bool isLastPart) - { - string slashTerminated = "(.*/?(?<=/))"; - if (isLastPart) - slashTerminated = String.Format("($|(?<=/){0}*)", slashTerminated); - return slashTerminated; - } + regex.Append(partToAdd); + indexOfTheCurrentSplittedPart++; + } - private static string TranslateQuestionMark(string thisPart) - { - return thisPart.Replace("?", "[^./]"); - } + return regex.ToString(); + } - private static string TranslateAsterisk(string thisPart) - { - return thisPart.Replace("*", "[^/]*"); - } + private static string ToLower(string pattern) + { + return pattern == null ? pattern : pattern.ToLower(); + } - private static string TranslateDot(string thisPart) - { - return thisPart.Replace(".", @"\."); - } + private static string TranslateLiteral(string part, bool isLastPart) + { + if (isLastPart) + { + return part + "$"; + } + else + { + return part + "/?"; + } + } - private static bool MatchAll(string pattern) - { - if (AllFilesInThisDirectory.Equals(pattern)) - { - return false; - } + private static string TranslateDoubleAsterisk(bool isLastPart) + { + string slashTerminated = "(.*/?(?<=/))"; + if (isLastPart) + slashTerminated = String.Format("($|(?<=/){0}*)", slashTerminated); + return slashTerminated; + } - foreach (char c in pattern) - { - if (c != '*' && c != '/' && c != '.') - { - return false; - } - } - return true; - } + private static string TranslateQuestionMark(string thisPart) + { + return thisPart.Replace("?", "[^./]"); + } - #region Constructor (s) / Destructor + private static string TranslateAsterisk(string thisPart) + { + return thisPart.Replace("*", "[^/]*"); + } - // CLOVER:OFF + private static string TranslateDot(string thisPart) + { + return thisPart.Replace(".", @"\."); + } - /// - /// Creates a new instance of the class. - /// - /// - ///

- /// This is a utility class, and as such exposes no public constructors. - ///

- ///
- private PathMatcher() - { - } + private static bool MatchAll(string pattern) + { + if (AllFilesInThisDirectory.Equals(pattern)) + { + return false; + } - // CLOVER:ON + foreach (char c in pattern) + { + if (c != '*' && c != '/' && c != '.') + { + return false; + } + } - #endregion - } + return true; + } + + #region Constructor (s) / Destructor + + // CLOVER:OFF + + /// + /// Creates a new instance of the class. + /// + /// + ///

+ /// This is a utility class, and as such exposes no public constructors. + ///

+ ///
+ private PathMatcher() + { + } + + // CLOVER:ON + + #endregion } ////
diff --git a/src/Spring/Spring.Core/Util/PatternMatchUtils.cs b/src/Spring/Spring.Core/Util/PatternMatchUtils.cs index c44728d5..fffe74fb 100644 --- a/src/Spring/Spring.Core/Util/PatternMatchUtils.cs +++ b/src/Spring/Spring.Core/Util/PatternMatchUtils.cs @@ -18,74 +18,77 @@ #endregion -namespace Spring.Util +namespace Spring.Util; + +/// Utility methods for simple pattern matching, in particular for +/// Spring's typical "xxx*", "*xxx" and "*xxx*" pattern styles. +/// +/// Juergen Hoeller +/// Mark Pollack +public abstract class PatternMatchUtils { - /// Utility methods for simple pattern matching, in particular for - /// Spring's typical "xxx*", "*xxx" and "*xxx*" pattern styles. + /// Match a String against the given pattern, supporting the following simple + /// pattern styles: "xxx*", "*xxx" and "*xxx*" matches, as well as direct equality. /// - /// Juergen Hoeller - /// Mark Pollack - public abstract class PatternMatchUtils + /// the pattern to match against + /// + /// the String to match + /// + /// whether the String matches the given pattern + /// + public static bool SimpleMatch(System.String pattern, System.String str) { - /// Match a String against the given pattern, supporting the following simple - /// pattern styles: "xxx*", "*xxx" and "*xxx*" matches, as well as direct equality. - /// - /// the pattern to match against - /// - /// the String to match - /// - /// whether the String matches the given pattern - /// - public static bool SimpleMatch(System.String pattern, System.String str) + if (ObjectUtils.NullSafeEquals(pattern, str) || "*".Equals(pattern)) + { + return true; + } + + if (pattern == null || str == null) { - if (ObjectUtils.NullSafeEquals(pattern, str) || "*".Equals(pattern)) - { - return true; - } - if (pattern == null || str == null) - { - return false; - } - if (pattern.StartsWith("*") && pattern.EndsWith("*") && - str.IndexOf(pattern.Substring(1, (pattern.Length - 1) - (1))) != -1) - { - return true; - } - if (pattern.StartsWith("*") && str.EndsWith(pattern.Substring(1, (pattern.Length) - (1)))) - { - return true; - } - if (pattern.EndsWith("*") && str.StartsWith(pattern.Substring(0, (pattern.Length - 1) - (0)))) - { - return true; - } return false; } - /// Match a String against the given patterns, supporting the following simple - /// pattern styles: "xxx*", "*xxx" and "*xxx*" matches, as well as direct equality. - /// - /// the patterns to match against - /// - /// the String to match - /// - /// whether the String matches any of the given patterns - /// - public static bool SimpleMatch(System.String[] patterns, System.String str) + if (pattern.StartsWith("*") && pattern.EndsWith("*") && + str.IndexOf(pattern.Substring(1, (pattern.Length - 1) - (1))) != -1) { - if (patterns != null) - { - for (int i = 0; i < patterns.Length; i++) - { + return true; + } - if (SimpleMatch(patterns[i], str)) - { - return true; - } + if (pattern.StartsWith("*") && str.EndsWith(pattern.Substring(1, (pattern.Length) - (1)))) + { + return true; + } + + if (pattern.EndsWith("*") && str.StartsWith(pattern.Substring(0, (pattern.Length - 1) - (0)))) + { + return true; + } + + return false; + } + + /// Match a String against the given patterns, supporting the following simple + /// pattern styles: "xxx*", "*xxx" and "*xxx*" matches, as well as direct equality. + /// + /// the patterns to match against + /// + /// the String to match + /// + /// whether the String matches any of the given patterns + /// + public static bool SimpleMatch(System.String[] patterns, System.String str) + { + if (patterns != null) + { + for (int i = 0; i < patterns.Length; i++) + { + if (SimpleMatch(patterns[i], str)) + { + return true; } } - return false; } + return false; } -} +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Util/Properties.cs b/src/Spring/Spring.Core/Util/Properties.cs index 3cd6d05b..8d5ff0f7 100644 --- a/src/Spring/Spring.Core/Util/Properties.cs +++ b/src/Spring/Spring.Core/Util/Properties.cs @@ -20,328 +20,329 @@ using System.Collections; -namespace Spring.Util +namespace Spring.Util; + +/// +/// An implementation of the Java Properties class. +/// +/// +/// For the complete syntax see java.util.Properties JavaDoc. +/// This class supports an extended syntax. There may also be sole keys on a line, in that case values are treated as null. +/// +/// +/// key1 = value +/// key2: +/// key3 +/// +/// will result in the name/value pairs: +/// +/// key1:="value" +/// key2:=string.Empty +/// key3:=<null> +/// +/// note, that to specify a null value, the key must not be followed by any character except newline. +/// +/// +/// Simon White +[Serializable] +public class Properties : Hashtable { - /// - /// An implementation of the Java Properties class. - /// - /// - /// For the complete syntax see java.util.Properties JavaDoc. - /// This class supports an extended syntax. There may also be sole keys on a line, in that case values are treated as null. - /// - /// - /// key1 = value - /// key2: - /// key3 - /// - /// will result in the name/value pairs: - /// - /// key1:="value" - /// key2:=string.Empty - /// key3:=<null> - /// - /// note, that to specify a null value, the key must not be followed by any character except newline. - /// - /// - /// Simon White - [Serializable] - public class Properties : Hashtable - { - #region Constants + #region Constants - private const string Comments = "#!"; - private const string Separators = ":="; - private const string Whitespace = " \t\r\n"; - private const string WhitespaceWithSeparators = Whitespace + Separators; + private const string Comments = "#!"; + private const string Separators = ":="; + private const string Whitespace = " \t\r\n"; + private const string WhitespaceWithSeparators = Whitespace + Separators; - #endregion + #endregion - #region Constructor (s) / Destructor + #region Constructor (s) / Destructor - /// - /// Creates an empty property list with no default values. - /// - public Properties() - { - } + /// + /// Creates an empty property list with no default values. + /// + public Properties() + { + } - /// - /// Creates a property list with the specified initial properties. - /// - /// The initial properties. - public Properties(Properties p) : base(p) - { - } + /// + /// Creates a property list with the specified initial properties. + /// + /// The initial properties. + public Properties(Properties p) : base(p) + { + } - #endregion + #endregion - #region Methods + #region Methods - /// - /// Reads a property list (key and element pairs) from the input stream. - /// - /// The stream to load from. - public void Load(Stream stream) - { - Load(this, stream); - } + /// + /// Reads a property list (key and element pairs) from the input stream. + /// + /// The stream to load from. + public void Load(Stream stream) + { + Load(this, stream); + } - /// - /// Reads a property list (key and element pairs) from a text reader. - /// - /// The text reader to load from. - public void Load(TextReader textReader) - { - Load(this, textReader); - } + /// + /// Reads a property list (key and element pairs) from a text reader. + /// + /// The text reader to load from. + public void Load(TextReader textReader) + { + Load(this, textReader); + } - /// - /// Reads a property list (key and element pairs) from the input stream. - /// - /// the dictionary to put it in - /// The stream to load from. - public static void Load(IDictionary dictionary, Stream stream) - { - using (StreamReader streamReader = new StreamReader(stream)) - { - Load(dictionary, streamReader); - } - } + /// + /// Reads a property list (key and element pairs) from the input stream. + /// + /// the dictionary to put it in + /// The stream to load from. + public static void Load(IDictionary dictionary, Stream stream) + { + using (StreamReader streamReader = new StreamReader(stream)) + { + Load(dictionary, streamReader); + } + } - /// - /// Reads a property list (key and element pairs) from a text reader. - /// - /// the dictionary to put it in - /// The text reader to load from. - public static void Load(IDictionary dictionary, TextReader textReader) - { - bool isContinuation = false; - string key = null; - string value = null; - string line = null; - while ((line = textReader.ReadLine()) != null) - { - line = RemoveLeadingWhitespace(line); - if (line != null && line.Length>0 && Comments.IndexOf(line[0]) == -1) - { - if (!isContinuation) - { - string[] keyvalue = SplitLine(line); - if (keyvalue == null) - { - continue; - } - key = keyvalue[0]; - value = keyvalue[1]; - - if (value != null && value.EndsWith("\\")) - { - value = value.Substring(0, value.Length - 1); - isContinuation = true; - } - else - { - dictionary[key] = StringUtils.ConvertEscapedCharacters(value); - } - } - else - { - if (line.EndsWith("\\")) - { - value += line.Substring(0, line.Length - 1); - } - else - { - value += line; - isContinuation = false; - dictionary[key] = StringUtils.ConvertEscapedCharacters(value); - } - } - } - } - } - - /// - /// Strips whitespace from the front of the specified string. - /// - /// The string. - /// The string with all leading whitespace removed. - private static string RemoveLeadingWhitespace(string line) - { - if (line == null) return null; - - string trimmed = string.Empty; - for (int i = 0; i < line.Length; i++) - { - if (Whitespace.IndexOf(line[i]) == -1) - { - trimmed = line.Substring(i); - break; - } - } - return trimmed; - } - - /// - /// Splits the specified string into a key / value pair. - /// - /// The line to split. - /// An array containing the key / value pair. - private static string[] SplitLine(string line) - { - string key = line; - string value = null; - - int index = 0; - int len = line.Length; - for (; index < len; index++) - { - if (WhitespaceWithSeparators.IndexOf(line[index]) != -1) - { - if (line[index - 1].Equals('\\')) - { - line = line.Remove(index - 1, 1); - len--; - index--; - } - else - { - key = line.Substring(0, index); - break; - } - } - } - - // got key, now find the start of the value - // first ignore leading whitespace and initial separator - // (if one's there) - index++; - if (index > len) - { - // this is an extension to support key-only lines and specifying null values - value = null; - } - else if (index == len) + /// + /// Reads a property list (key and element pairs) from a text reader. + /// + /// the dictionary to put it in + /// The text reader to load from. + public static void Load(IDictionary dictionary, TextReader textReader) + { + bool isContinuation = false; + string key = null; + string value = null; + string line = null; + while ((line = textReader.ReadLine()) != null) + { + line = RemoveLeadingWhitespace(line); + if (line != null && line.Length > 0 && Comments.IndexOf(line[0]) == -1) { - value = string.Empty; + if (!isContinuation) + { + string[] keyvalue = SplitLine(line); + if (keyvalue == null) + { + continue; + } + + key = keyvalue[0]; + value = keyvalue[1]; + + if (value != null && value.EndsWith("\\")) + { + value = value.Substring(0, value.Length - 1); + isContinuation = true; + } + else + { + dictionary[key] = StringUtils.ConvertEscapedCharacters(value); + } + } + else + { + if (line.EndsWith("\\")) + { + value += line.Substring(0, line.Length - 1); + } + else + { + value += line; + isContinuation = false; + dictionary[key] = StringUtils.ConvertEscapedCharacters(value); + } + } } - else + } + } + + /// + /// Strips whitespace from the front of the specified string. + /// + /// The string. + /// The string with all leading whitespace removed. + private static string RemoveLeadingWhitespace(string line) + { + if (line == null) return null; + + string trimmed = string.Empty; + for (int i = 0; i < line.Length; i++) + { + if (Whitespace.IndexOf(line[i]) == -1) { - value = line.Substring(index); - value = RemoveLeadingWhitespace(value); + trimmed = line.Substring(i); + break; } + } - if (value != null && value.Length > 0 - && Separators.IndexOf(value[0]) != -1) - { - value = value.Substring(1); - value = RemoveLeadingWhitespace(value); - } + return trimmed; + } - return new string[] {key, value}; - } + /// + /// Splits the specified string into a key / value pair. + /// + /// The line to split. + /// An array containing the key / value pair. + private static string[] SplitLine(string line) + { + string key = line; + string value = null; - /// - /// Searches for the property with the specified key in this property list. - /// - /// The key. - /// The property, or null if the key was not found. - public string GetProperty(string key) - { - return this[key] as string; - } + int index = 0; + int len = line.Length; + for (; index < len; index++) + { + if (WhitespaceWithSeparators.IndexOf(line[index]) != -1) + { + if (line[index - 1].Equals('\\')) + { + line = line.Remove(index - 1, 1); + len--; + index--; + } + else + { + key = line.Substring(0, index); + break; + } + } + } - /// - /// Searches for the property with the specified key in this property list. - /// - /// The key. - /// - /// The default value to be returned if the key is not found. - /// - /// The property, or the default value. - public string GetProperty(string key, string def) - { - string val = this[key] as string; - return (val != null ? val : def); - } + // got key, now find the start of the value + // first ignore leading whitespace and initial separator + // (if one's there) + index++; + if (index > len) + { + // this is an extension to support key-only lines and specifying null values + value = null; + } + else if (index == len) + { + value = string.Empty; + } + else + { + value = line.Substring(index); + value = RemoveLeadingWhitespace(value); + } - /// - /// Writes this property list out to the specified stream. - /// - /// The stream to write to. - public void List(Stream stream) - { - using (StreamWriter sw = new StreamWriter(stream)) - { - foreach (DictionaryEntry de in this) - { - sw.WriteLine(de.Key + "=" + de.Value); - } - } - } + if (value != null && value.Length > 0 + && Separators.IndexOf(value[0]) != -1) + { + value = value.Substring(1); + value = RemoveLeadingWhitespace(value); + } - /// - /// Sets the specified property key / value pair. - /// - /// The key. - /// The value. - public void SetProperty(string key, string theValue) - { - this[key] = theValue; - } + return new string[] { key, value }; + } - /// - /// Writes the properties in this instance out to the supplied stream. - /// - /// The stream to write to. - /// Arbitrary header information. - public void Store(Stream stream, string header) - { - using (StreamWriter sw = new StreamWriter(stream)) - { - sw.WriteLine(header); + /// + /// Searches for the property with the specified key in this property list. + /// + /// The key. + /// The property, or null if the key was not found. + public string GetProperty(string key) + { + return this[key] as string; + } - foreach (DictionaryEntry de in this) - { - sw.WriteLine(de.Key + "=" + de.Value); - } - } - } + /// + /// Searches for the property with the specified key in this property list. + /// + /// The key. + /// + /// The default value to be returned if the key is not found. + /// + /// The property, or the default value. + public string GetProperty(string key, string def) + { + string val = this[key] as string; + return (val != null ? val : def); + } - #endregion + /// + /// Writes this property list out to the specified stream. + /// + /// The stream to write to. + public void List(Stream stream) + { + using (StreamWriter sw = new StreamWriter(stream)) + { + foreach (DictionaryEntry de in this) + { + sw.WriteLine(de.Key + "=" + de.Value); + } + } + } - #region IDictionary Members + /// + /// Sets the specified property key / value pair. + /// + /// The key. + /// The value. + public void SetProperty(string key, string theValue) + { + this[key] = theValue; + } - /// - /// Adds the specified key / object pair to this collection. - /// - public override object this[object key] - { - get { return base[key as string]; } - set { base[key as string] = value as string; } - } + /// + /// Writes the properties in this instance out to the supplied stream. + /// + /// The stream to write to. + /// Arbitrary header information. + public void Store(Stream stream, string header) + { + using (StreamWriter sw = new StreamWriter(stream)) + { + sw.WriteLine(header); - /// - /// Removes the key / value pair identified by the supplied key. - /// - /// - /// The key identifying the key / value pair to be removed. - /// - public override void Remove(object key) - { - base.Remove(key as string); - } + foreach (DictionaryEntry de in this) + { + sw.WriteLine(de.Key + "=" + de.Value); + } + } + } - /// - /// Adds the specified key / object pair to this collection. - /// - /// The key. - /// The value. - public override void Add(object key, object value) - { - base.Add(key as string, value as string); - } + #endregion - #endregion - } + #region IDictionary Members + + /// + /// Adds the specified key / object pair to this collection. + /// + public override object this[object key] + { + get { return base[key as string]; } + set { base[key as string] = value as string; } + } + + /// + /// Removes the key / value pair identified by the supplied key. + /// + /// + /// The key identifying the key / value pair to be removed. + /// + public override void Remove(object key) + { + base.Remove(key as string); + } + + /// + /// Adds the specified key / object pair to this collection. + /// + /// The key. + /// The value. + public override void Add(object key, object value) + { + base.Add(key as string, value as string); + } + + #endregion } diff --git a/src/Spring/Spring.Core/Util/ReflectionException.cs b/src/Spring/Spring.Core/Util/ReflectionException.cs index 680207f4..54a18b5b 100644 --- a/src/Spring/Spring.Core/Util/ReflectionException.cs +++ b/src/Spring/Spring.Core/Util/ReflectionException.cs @@ -24,63 +24,64 @@ using System.Runtime.Serialization; #endregion -namespace Spring.Util +namespace Spring.Util; + +/// +/// Superclass for all exceptions thrown in the Objects namespace and sub-namespaces. +/// +/// Rod Johnson +/// Mark Pollack (.NET) +[Serializable] +public class ReflectionException : ApplicationException { - /// - /// Superclass for all exceptions thrown in the Objects namespace and sub-namespaces. - /// - /// Rod Johnson - /// Mark Pollack (.NET) - [Serializable] - public class ReflectionException : ApplicationException + #region Constructor (s) / Destructor + + /// Creates a new instance of the ObjectsException class. + public ReflectionException() { - #region Constructor (s) / Destructor - /// Creates a new instance of the ObjectsException class. - public ReflectionException() - { - } - - /// - /// Creates a new instance of the ObjectsException class. with the specified message. - /// - /// - /// A message about the exception. - /// - public ReflectionException (string message) : base(message) - { - } - - /// - /// Creates a new instance of the ObjectsException class with the specified message - /// and root cause. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception that is being wrapped. - /// - public ReflectionException (string message, Exception rootCause) - : base(message, rootCause) - { - } - - /// - /// Creates a new instance of the ObjectsException class. - /// - /// - /// The - /// that holds the serialized object data about the exception being thrown. - /// - /// - /// The - /// that contains contextual information about the source or destination. - /// - protected ReflectionException ( - SerializationInfo info, StreamingContext context) - : base (info, context) - { - } - #endregion } + + /// + /// Creates a new instance of the ObjectsException class. with the specified message. + /// + /// + /// A message about the exception. + /// + public ReflectionException(string message) : base(message) + { + } + + /// + /// Creates a new instance of the ObjectsException class with the specified message + /// and root cause. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception that is being wrapped. + /// + public ReflectionException(string message, Exception rootCause) + : base(message, rootCause) + { + } + + /// + /// Creates a new instance of the ObjectsException class. + /// + /// + /// The + /// that holds the serialized object data about the exception being thrown. + /// + /// + /// The + /// that contains contextual information about the source or destination. + /// + protected ReflectionException( + SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + + #endregion } diff --git a/src/Spring/Spring.Core/Util/ReflectionUtils.cs b/src/Spring/Spring.Core/Util/ReflectionUtils.cs index ae394642..f077dfdb 100644 --- a/src/Spring/Spring.Core/Util/ReflectionUtils.cs +++ b/src/Spring/Spring.Core/Util/ReflectionUtils.cs @@ -26,1768 +26,1790 @@ using System.Security.Permissions; using System.Text; using System.Runtime.CompilerServices; -namespace Spring.Util +namespace Spring.Util; + +/// +/// Various reflection related methods that are missing from the standard library. +/// +/// Rod Johnson +/// Juergen Hoeller +/// Aleksandar Seovic (.NET) +/// Stan Dvoychenko (.NET) +/// Bruno Baia (.NET) +public sealed class ReflectionUtils { + internal static Type[] EmptyTypes = new Type[0]; + /// - /// Various reflection related methods that are missing from the standard library. + /// Convenience value that will + /// match all private and public, static and instance members on a class + /// in a case inSenSItivE fashion. /// - /// Rod Johnson - /// Juergen Hoeller - /// Aleksandar Seovic (.NET) - /// Stan Dvoychenko (.NET) - /// Bruno Baia (.NET) - public sealed class ReflectionUtils + public const BindingFlags AllMembersCaseInsensitiveFlags = BindingFlags.Public | + BindingFlags.NonPublic | BindingFlags.Instance + | BindingFlags.Static + | BindingFlags.IgnoreCase; + + /// + /// Avoid BeforeFieldInit problem + /// + static ReflectionUtils() { - internal static Type[] EmptyTypes = new Type[0]; + } - /// - /// Convenience value that will - /// match all private and public, static and instance members on a class - /// in a case inSenSItivE fashion. - /// - public const BindingFlags AllMembersCaseInsensitiveFlags = BindingFlags.Public | - BindingFlags.NonPublic | BindingFlags.Instance - | BindingFlags.Static - | BindingFlags.IgnoreCase; + /// + /// Checks, if the specified type is a nullable + /// + public static bool IsNullableType(Type type) + { + return (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)); + } - /// - /// Avoid BeforeFieldInit problem - /// - static ReflectionUtils() - { } - - /// - /// Checks, if the specified type is a nullable - /// - public static bool IsNullableType(Type type) + /// + /// Returns signature for the specified , method name and argument + /// s. + /// + /// The the method is in. + /// The method name. + /// + /// The argument s. + /// + /// The method signature. + public static string GetSignature( + Type type, string method, Type[] argumentTypes) + { + StringBuilder sb = new StringBuilder(); + sb.Append(type.FullName).Append("::").Append(method).Append("("); + string separator = ""; + for (int i = 0; i < argumentTypes.Length; i++) { - return (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)); + sb.Append(separator).Append(argumentTypes[i].FullName); + separator = ","; } - /// - /// Returns signature for the specified , method name and argument - /// s. - /// - /// The the method is in. - /// The method name. - /// - /// The argument s. - /// - /// The method signature. - public static string GetSignature( - Type type, string method, Type[] argumentTypes) + sb.Append(")"); + return sb.ToString(); + } + + /// + /// Returns method for the specified , method + /// name and argument + /// s. + /// + /// + /// Searches with BindingFlags + /// When dealing with interface methods, you probable want to 'normalize' method references by calling + /// . + /// + /// + /// + /// The target to find the method on. + /// + /// The method to find. + /// + /// The argument s. May be + /// if the method has no arguments. + /// + /// The target method. + /// + public static MethodInfo GetMethod( + Type targetType, string method, Type[] argumentTypes) + { + return GetMethod(targetType, method, argumentTypes, 0); + } + + /// + /// Returns method for the specified , method + /// name and argument + /// s. + /// + /// + /// Searches with BindingFlags + /// When dealing with interface methods, you probable want to 'normalize' method references by calling + /// . + /// + /// + /// + /// The target to find the method on. + /// + /// The method to find. + /// + /// The argument s. May be + /// if the method has no arguments. + /// + /// Number of Generic Arguments in the method + /// The target method. + /// + public static MethodInfo GetMethod( + Type targetType, string method, Type[] argumentTypes, int genericArgumentsCount) + { + AssertUtils.ArgumentNotNull(targetType, "Type must not be null"); + + MethodInfo retMethod = null; + + MethodInfo[] methods = targetType.GetMethods(ReflectionUtils.AllMembersCaseInsensitiveFlags); + + foreach (MethodInfo candidate in methods) { - StringBuilder sb = new StringBuilder(); - sb.Append(type.FullName).Append("::").Append(method).Append("("); - string separator = ""; - for (int i = 0; i < argumentTypes.Length; i++) + if (candidate.Name.ToLower() == method.ToLower()) { - sb.Append(separator).Append(argumentTypes[i].FullName); - separator = ","; - } - sb.Append(")"); - return sb.ToString(); - } + Type[] parameterTypes = Array.ConvertAll(candidate.GetParameters(), delegate(ParameterInfo i) { return i.ParameterType; }); + bool typesMatch = false; + bool zeroTypeArguments = null == argumentTypes || argumentTypes.Length == 0; - /// - /// Returns method for the specified , method - /// name and argument - /// s. - /// - /// - /// Searches with BindingFlags - /// When dealing with interface methods, you probable want to 'normalize' method references by calling - /// . - /// - /// - /// - /// The target to find the method on. - /// - /// The method to find. - /// - /// The argument s. May be - /// if the method has no arguments. - /// - /// The target method. - /// - public static MethodInfo GetMethod( - Type targetType, string method, Type[] argumentTypes) - { - return GetMethod(targetType, method, argumentTypes, 0); - } - - /// - /// Returns method for the specified , method - /// name and argument - /// s. - /// - /// - /// Searches with BindingFlags - /// When dealing with interface methods, you probable want to 'normalize' method references by calling - /// . - /// - /// - /// - /// The target to find the method on. - /// - /// The method to find. - /// - /// The argument s. May be - /// if the method has no arguments. - /// - /// Number of Generic Arguments in the method - /// The target method. - /// - public static MethodInfo GetMethod( - Type targetType, string method, Type[] argumentTypes, int genericArgumentsCount) - { - AssertUtils.ArgumentNotNull(targetType, "Type must not be null"); - - MethodInfo retMethod = null; - - MethodInfo[] methods = targetType.GetMethods(ReflectionUtils.AllMembersCaseInsensitiveFlags); - - foreach (MethodInfo candidate in methods) - { - if (candidate.Name.ToLower() == method.ToLower()) + if (!zeroTypeArguments && parameterTypes.Length == argumentTypes.Length) { - Type[] parameterTypes = Array.ConvertAll(candidate.GetParameters(), delegate(ParameterInfo i) { return i.ParameterType; }); - bool typesMatch = false; - - bool zeroTypeArguments = null == argumentTypes || argumentTypes.Length == 0; - - if (!zeroTypeArguments && parameterTypes.Length == argumentTypes.Length) + for (int i = 0; i < parameterTypes.Length; i++) { - for (int i = 0; i < parameterTypes.Length; i++) + typesMatch = parameterTypes[i] == argumentTypes[i]; + if (!typesMatch) { - typesMatch = parameterTypes[i] == argumentTypes[i]; - if (!typesMatch) - { - break; - } - } - } - - if (typesMatch || zeroTypeArguments) - { - if (candidate.GetGenericArguments().Length == genericArgumentsCount) - { - retMethod = candidate; break; } } } - } - /*return (from method in type.GetMethods() - where method.Name == name - where parameterTypes.SequenceEqual(method.GetParameters().Select(p => p.ParameterType)) - where method.GetGenericArguments().Count() == genericArguments - select method).Single();*/ - - - if (retMethod == null) - { - // try explicit interface implementation... - int idx = method.LastIndexOf('.'); - if (idx > -1) + if (typesMatch || zeroTypeArguments) { - method = method.Substring(idx + 1); - retMethod = ReflectionUtils.GetMethod(targetType, method, argumentTypes); + if (candidate.GetGenericArguments().Length == genericArgumentsCount) + { + retMethod = candidate; + break; + } } } - return retMethod; } - /// - /// Resolves a given to the representing the actual implementation. - /// - /// - /// see article How To Get an Explicit Interface Implementation Method. - /// - /// a - /// the type to lookup - /// the representing the actual implementation method of the specified - public static MethodInfo MapInterfaceMethodToImplementationIfNecessary(MethodInfo methodInfo, System.Type implementingType) + /*return (from method in type.GetMethods() + where method.Name == name + where parameterTypes.SequenceEqual(method.GetParameters().Select(p => p.ParameterType)) + where method.GetGenericArguments().Count() == genericArguments + select method).Single();*/ + + if (retMethod == null) { - AssertUtils.ArgumentNotNull(methodInfo, "methodInfo"); - AssertUtils.ArgumentNotNull(implementingType, "implementingType"); - AssertUtils.IsTrue(methodInfo.DeclaringType.IsAssignableFrom(implementingType), "methodInfo and implementingType are unrelated"); - - MethodInfo concreteMethodInfo = methodInfo; - - if (methodInfo.DeclaringType.IsInterface) + // try explicit interface implementation... + int idx = method.LastIndexOf('.'); + if (idx > -1) { - InterfaceMapping interfaceMapping = implementingType.GetInterfaceMap(methodInfo.DeclaringType); - int methodIndex = Array.IndexOf(interfaceMapping.InterfaceMethods, methodInfo); - concreteMethodInfo = interfaceMapping.TargetMethods[methodIndex]; + method = method.Substring(idx + 1); + retMethod = ReflectionUtils.GetMethod(targetType, method, argumentTypes); } - - return concreteMethodInfo; } - /// - /// Returns an array of parameter s for the specified method - /// or constructor. - /// - /// The method (or constructor). - /// An array containing the parameter s. - /// - /// If is . - /// - public static Type[] GetParameterTypes(MethodBase method) + return retMethod; + } + + /// + /// Resolves a given to the representing the actual implementation. + /// + /// + /// see article How To Get an Explicit Interface Implementation Method. + /// + /// a + /// the type to lookup + /// the representing the actual implementation method of the specified + public static MethodInfo MapInterfaceMethodToImplementationIfNecessary(MethodInfo methodInfo, System.Type implementingType) + { + AssertUtils.ArgumentNotNull(methodInfo, "methodInfo"); + AssertUtils.ArgumentNotNull(implementingType, "implementingType"); + AssertUtils.IsTrue(methodInfo.DeclaringType.IsAssignableFrom(implementingType), "methodInfo and implementingType are unrelated"); + + MethodInfo concreteMethodInfo = methodInfo; + + if (methodInfo.DeclaringType.IsInterface) { - AssertUtils.ArgumentNotNull(method, "method"); - return GetParameterTypes(method.GetParameters()); + InterfaceMapping interfaceMapping = implementingType.GetInterfaceMap(methodInfo.DeclaringType); + int methodIndex = Array.IndexOf(interfaceMapping.InterfaceMethods, methodInfo); + concreteMethodInfo = interfaceMapping.TargetMethods[methodIndex]; } - /// - /// Returns an array of parameter s for the - /// specified parameter info array. - /// - /// The parameter info array. - /// An array containing parameter s. - /// - /// If is or any of the - /// elements is . - /// - public static Type[] GetParameterTypes(ParameterInfo[] args) + return concreteMethodInfo; + } + + /// + /// Returns an array of parameter s for the specified method + /// or constructor. + /// + /// The method (or constructor). + /// An array containing the parameter s. + /// + /// If is . + /// + public static Type[] GetParameterTypes(MethodBase method) + { + AssertUtils.ArgumentNotNull(method, "method"); + return GetParameterTypes(method.GetParameters()); + } + + /// + /// Returns an array of parameter s for the + /// specified parameter info array. + /// + /// The parameter info array. + /// An array containing parameter s. + /// + /// If is or any of the + /// elements is . + /// + public static Type[] GetParameterTypes(ParameterInfo[] args) + { + AssertUtils.ArgumentNotNull(args, "args"); + + if (args.Length == 0) { - AssertUtils.ArgumentNotNull(args, "args"); - - if (args.Length == 0) - { - return EmptyTypes; - } - - var types = new Type[args.Length]; - for (int i = 0; i < (uint) args.Length; i++) - { - types[i] = args[i].ParameterType; - } - return types; + return EmptyTypes; } - /// - /// Returns an array of s that represent - /// the names of the generic type parameter. - /// - /// The method. - /// An array containing the parameter names. - /// - /// If is . - /// - public static string[] GetGenericParameterNames(MethodInfo method) + var types = new Type[args.Length]; + for (int i = 0; i < (uint) args.Length; i++) { - AssertUtils.ArgumentNotNull(method, "method"); - return GetGenericParameterNames(method.GetGenericArguments()); + types[i] = args[i].ParameterType; } - /// - /// Returns an array of s that represent - /// the names of the generic type parameter. - /// - /// The parameter info array. - /// An array containing parameter names. - /// - /// If is or any of the - /// elements is . - /// - public static string[] GetGenericParameterNames(Type[] args) + return types; + } + + /// + /// Returns an array of s that represent + /// the names of the generic type parameter. + /// + /// The method. + /// An array containing the parameter names. + /// + /// If is . + /// + public static string[] GetGenericParameterNames(MethodInfo method) + { + AssertUtils.ArgumentNotNull(method, "method"); + return GetGenericParameterNames(method.GetGenericArguments()); + } + + /// + /// Returns an array of s that represent + /// the names of the generic type parameter. + /// + /// The parameter info array. + /// An array containing parameter names. + /// + /// If is or any of the + /// elements is . + /// + public static string[] GetGenericParameterNames(Type[] args) + { + AssertUtils.ArgumentNotNull(args, "args"); + string[] names = new string[args.Length]; + for (int i = 0; i < args.Length; i++) { - AssertUtils.ArgumentNotNull(args, "args"); - string[] names = new string[args.Length]; - for (int i = 0; i < args.Length; i++) - { - names[i] = args[i].Name; - } - return names; + names[i] = args[i].Name; } - public static MethodInfo GetGenericMethod(Type type, string methodName, Type[] typeArguments, Type[] parameterTypes) - { - MethodInfo methodInfo = null; + return names; + } - if (typeArguments == null) + public static MethodInfo GetGenericMethod(Type type, string methodName, Type[] typeArguments, Type[] parameterTypes) + { + MethodInfo methodInfo = null; + + if (typeArguments == null) + { + // Non-Generic Method + methodInfo = type.GetMethod(methodName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, parameterTypes, null); + } + else + { + // Generic Method + MethodInfo[] methods = type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); + // Loop thru all Methods + foreach (MethodInfo method in methods) { - // Non-Generic Method - methodInfo = type.GetMethod(methodName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, parameterTypes, null); - } - else - { - // Generic Method - MethodInfo[] methods = type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); - // Loop thru all Methods - foreach (MethodInfo method in methods) + if (method.Name != methodName) { - if (method.Name != methodName) - { - // Name does not match - continue; - } - - if (!method.IsGenericMethod) - { - // Non-Generic - continue; - } - - // Compare the Method Parameters - bool paramsOk = false; - if (method.GetParameters().Length == parameterTypes.Length) - { - // Count Matches - paramsOk = true; - // Check each Type - for (int i = 0; i < method.GetParameters().Length; i++) - { - if (method.GetParameters()[i].ParameterType != parameterTypes[i]) - { - // Parameter Type doesn't Match - paramsOk = false; - break; - } - } - } - if (!paramsOk) - { - // Parameters didn't match - continue; - } - - // Check the Generic Arguments - bool argsOk = false; - if (method.GetGenericArguments().Length == typeArguments.Length) - { - // Count Matches - argsOk = true; - // TODO: Check for "where" Limitation in the Generic Definition - } - if (!argsOk) - { - // Generic Arguments didn't match - continue; - } - - // If we're here, we got the right Method - methodInfo = method.MakeGenericMethod(typeArguments); - break; + // Name does not match + continue; } - } - return methodInfo; - } - /// - /// From a given list of methods, selects the method having an exact match on the given ' types. - /// - /// the list of methods to choose from - /// the arguments to the method - /// the method matching exactly the passed ' types - /// - /// If more than 1 matching methods are found in the list. - /// - public static MethodInfo GetMethodByArgumentValues(IEnumerable methods, object[] argValues) where T : MethodBase - { - return (MethodInfo)GetMethodBaseByArgumentValues("method", methods, argValues); - } - - /// - /// From a given list of methods, selects the method having an exact match on the given ' types. - /// - /// the type of method (used for exception reporting only) - /// the list of methods to choose from - /// the arguments to the method - /// the method matching exactly the passed ' types - /// - /// If more than 1 matching methods are found in the list. - /// - private static MethodBase GetMethodBaseByArgumentValues(string methodTypeName, IEnumerable methods, object[] argValues) where T : MethodBase - { - MethodBase match = null; - int matchCount = 0; - - foreach (MethodBase m in methods) - { - ParameterInfo[] parameters = m.GetParameters(); - bool isMatch = true; - bool isExactMatch = true; - object[] paramValues = (argValues == null) ? new object[0] : argValues; - - try + if (!method.IsGenericMethod) { - if (parameters.Length > 0) + // Non-Generic + continue; + } + + // Compare the Method Parameters + bool paramsOk = false; + if (method.GetParameters().Length == parameterTypes.Length) + { + // Count Matches + paramsOk = true; + // Check each Type + for (int i = 0; i < method.GetParameters().Length; i++) { - ParameterInfo lastParameter = parameters[parameters.Length - 1]; - if (lastParameter.GetCustomAttributes(typeof(ParamArrayAttribute), false).Length > 0 && argValues.Length >= parameters.Length) + if (method.GetParameters()[i].ParameterType != parameterTypes[i]) { - paramValues = - PackageParamArray(argValues, parameters.Length, - lastParameter.ParameterType.GetElementType()); - } - } - - if (parameters.Length != paramValues.Length) - { - isMatch = false; - } - else - { - for (int i = 0; i < parameters.Length; i++) - { - Type paramType = parameters[i].ParameterType; - object paramValue = paramValues[i]; - - if ((paramValue == null && paramType.IsValueType && !IsNullableType(paramType)) - || (paramValue != null && !paramType.IsAssignableFrom(paramValue.GetType()))) - { - isMatch = false; - break; - } - - if (paramValue == null || paramType != paramValue.GetType()) - { - isExactMatch = false; - } + // Parameter Type doesn't Match + paramsOk = false; + break; } } } - catch (InvalidCastException) + + if (!paramsOk) + { + // Parameters didn't match + continue; + } + + // Check the Generic Arguments + bool argsOk = false; + if (method.GetGenericArguments().Length == typeArguments.Length) + { + // Count Matches + argsOk = true; + // TODO: Check for "where" Limitation in the Generic Definition + } + + if (!argsOk) + { + // Generic Arguments didn't match + continue; + } + + // If we're here, we got the right Method + methodInfo = method.MakeGenericMethod(typeArguments); + break; + } + } + + return methodInfo; + } + + /// + /// From a given list of methods, selects the method having an exact match on the given ' types. + /// + /// the list of methods to choose from + /// the arguments to the method + /// the method matching exactly the passed ' types + /// + /// If more than 1 matching methods are found in the list. + /// + public static MethodInfo GetMethodByArgumentValues(IEnumerable methods, object[] argValues) where T : MethodBase + { + return (MethodInfo) GetMethodBaseByArgumentValues("method", methods, argValues); + } + + /// + /// From a given list of methods, selects the method having an exact match on the given ' types. + /// + /// the type of method (used for exception reporting only) + /// the list of methods to choose from + /// the arguments to the method + /// the method matching exactly the passed ' types + /// + /// If more than 1 matching methods are found in the list. + /// + private static MethodBase GetMethodBaseByArgumentValues(string methodTypeName, IEnumerable methods, object[] argValues) where T : MethodBase + { + MethodBase match = null; + int matchCount = 0; + + foreach (MethodBase m in methods) + { + ParameterInfo[] parameters = m.GetParameters(); + bool isMatch = true; + bool isExactMatch = true; + object[] paramValues = (argValues == null) ? new object[0] : argValues; + + try + { + if (parameters.Length > 0) + { + ParameterInfo lastParameter = parameters[parameters.Length - 1]; + if (lastParameter.GetCustomAttributes(typeof(ParamArrayAttribute), false).Length > 0 && argValues.Length >= parameters.Length) + { + paramValues = + PackageParamArray(argValues, parameters.Length, + lastParameter.ParameterType.GetElementType()); + } + } + + if (parameters.Length != paramValues.Length) { isMatch = false; } - - if (isMatch) + else { - if (isExactMatch) + for (int i = 0; i < parameters.Length; i++) { - return m; - } + Type paramType = parameters[i].ParameterType; + object paramValue = paramValues[i]; - matchCount++; - if (matchCount == 1) - { - match = m; - } - else - { - throw new AmbiguousMatchException( - string.Format("Ambiguous match for {0} '{1}' for the specified number and types of arguments.", methodTypeName, - m.Name)); + if ((paramValue == null && paramType.IsValueType && !IsNullableType(paramType)) + || (paramValue != null && !paramType.IsAssignableFrom(paramValue.GetType()))) + { + isMatch = false; + break; + } + + if (paramValue == null || paramType != paramValue.GetType()) + { + isExactMatch = false; + } } } } - - return match; - } - - /// - /// From a given list of constructors, selects the constructor having an exact match on the given ' types. - /// - /// the list of constructors to choose from - /// the arguments to the method - /// the constructor matching exactly the passed ' types - /// - /// If more than 1 matching methods are found in the list. - /// - public static ConstructorInfo GetConstructorByArgumentValues(IList methods, object[] argValues) where T : MethodBase - { - return (ConstructorInfo)GetMethodBaseByArgumentValues("constructor", methods, argValues); - } - - - /// - /// Packages arguments into argument list containing parameter array as a last argument. - /// - /// Argument vaklues to package. - /// Total number of oarameters. - /// Type of the param array element. - /// Packaged arguments. - public static object[] PackageParamArray(object[] argValues, int argCount, Type elementType) - { - object[] values = new object[argCount]; - int i = 0; - - // copy regular arguments - while (i < argCount - 1) + catch (InvalidCastException) { - values[i] = argValues[i]; - i++; + isMatch = false; } - // package param array into last argument - Array paramArray = Array.CreateInstance(elementType, argValues.Length - i); - int j = 0; - while (i < argValues.Length) + if (isMatch) { - paramArray.SetValue(argValues[i++], j++); - } - values[values.Length - 1] = paramArray; - - return values; - } - - /// - /// Convenience method to convert an interface - /// to a array that contains - /// all the interfaces inherited and the specified interface. - /// - /// The interface to convert. - /// An array of interface s. - /// - /// If the specified is not an interface. - /// - /// - /// If is . - /// - public static IList ToInterfaceArray(Type intf) - { - AssertUtils.ArgumentNotNull(intf, "intf"); - - if (!intf.IsInterface) - { - throw new ArgumentException( - string.Format(CultureInfo.InvariantCulture, - "[{0}] is a class.", - intf.FullName)); - } - - List interfaces = new List(intf.GetInterfaces()); - interfaces.Add(intf); - - return interfaces; - } - - /// - /// Is the supplied the default indexer for the - /// supplied ? - /// - /// - /// The name of the property on the supplied to be checked. - /// - /// - /// The to be checked. - /// - /// - /// if the supplied is the - /// default indexer for the supplied . - /// - /// - /// If the supplied is . - /// - public static bool PropertyIsIndexer(string propertyName, Type type) - { - DefaultMemberAttribute[] attribs = - (DefaultMemberAttribute[])type.GetCustomAttributes(typeof(DefaultMemberAttribute), true); - if (attribs.Length != 0) - { - foreach (DefaultMemberAttribute attrib in attribs) + if (isExactMatch) { - if (attrib.MemberName.Equals(propertyName)) - { - return true; - } + return m; + } + + matchCount++; + if (matchCount == 1) + { + match = m; + } + else + { + throw new AmbiguousMatchException( + string.Format("Ambiguous match for {0} '{1}' for the specified number and types of arguments.", methodTypeName, + m.Name)); } } + } + + return match; + } + + /// + /// From a given list of constructors, selects the constructor having an exact match on the given ' types. + /// + /// the list of constructors to choose from + /// the arguments to the method + /// the constructor matching exactly the passed ' types + /// + /// If more than 1 matching methods are found in the list. + /// + public static ConstructorInfo GetConstructorByArgumentValues(IList methods, object[] argValues) where T : MethodBase + { + return (ConstructorInfo) GetMethodBaseByArgumentValues("constructor", methods, argValues); + } + + /// + /// Packages arguments into argument list containing parameter array as a last argument. + /// + /// Argument vaklues to package. + /// Total number of oarameters. + /// Type of the param array element. + /// Packaged arguments. + public static object[] PackageParamArray(object[] argValues, int argCount, Type elementType) + { + object[] values = new object[argCount]; + int i = 0; + + // copy regular arguments + while (i < argCount - 1) + { + values[i] = argValues[i]; + i++; + } + + // package param array into last argument + Array paramArray = Array.CreateInstance(elementType, argValues.Length - i); + int j = 0; + while (i < argValues.Length) + { + paramArray.SetValue(argValues[i++], j++); + } + + values[values.Length - 1] = paramArray; + + return values; + } + + /// + /// Convenience method to convert an interface + /// to a array that contains + /// all the interfaces inherited and the specified interface. + /// + /// The interface to convert. + /// An array of interface s. + /// + /// If the specified is not an interface. + /// + /// + /// If is . + /// + public static IList ToInterfaceArray(Type intf) + { + AssertUtils.ArgumentNotNull(intf, "intf"); + + if (!intf.IsInterface) + { + throw new ArgumentException( + string.Format(CultureInfo.InvariantCulture, + "[{0}] is a class.", + intf.FullName)); + } + + List interfaces = new List(intf.GetInterfaces()); + interfaces.Add(intf); + + return interfaces; + } + + /// + /// Is the supplied the default indexer for the + /// supplied ? + /// + /// + /// The name of the property on the supplied to be checked. + /// + /// + /// The to be checked. + /// + /// + /// if the supplied is the + /// default indexer for the supplied . + /// + /// + /// If the supplied is . + /// + public static bool PropertyIsIndexer(string propertyName, Type type) + { + DefaultMemberAttribute[] attribs = + (DefaultMemberAttribute[]) type.GetCustomAttributes(typeof(DefaultMemberAttribute), true); + if (attribs.Length != 0) + { + foreach (DefaultMemberAttribute attrib in attribs) + { + if (attrib.MemberName.Equals(propertyName)) + { + return true; + } + } + } + + return false; + } + + /// + /// Is the supplied declared on one of these interfaces? + /// + /// The method to check. + /// The array of interfaces we want to check. + /// + /// if the method is declared on one of these interfaces. + /// + /// + /// If any of the s specified is not an interface. + /// + /// + /// If or any of the specified interfaces is + /// . + /// + public static bool MethodIsOnOneOfTheseInterfaces(MethodBase method, Type[] interfaces) + { + AssertUtils.ArgumentNotNull(method, "method"); + if (interfaces == null) + { return false; } - /// - /// Is the supplied declared on one of these interfaces? - /// - /// The method to check. - /// The array of interfaces we want to check. - /// - /// if the method is declared on one of these interfaces. - /// - /// - /// If any of the s specified is not an interface. - /// - /// - /// If or any of the specified interfaces is - /// . - /// - public static bool MethodIsOnOneOfTheseInterfaces(MethodBase method, Type[] interfaces) + Type[] paramTypes = GetParameterTypes(method.GetParameters()); + for (int i = 0; i < interfaces.Length; i++) { - AssertUtils.ArgumentNotNull(method, "method"); - if (interfaces == null) + Type interfaceType = interfaces[i]; + AssertUtils.ArgumentNotNull(interfaceType, StringUtils.Surround("interfaces[", i, "]")); + if (!interfaceType.IsInterface) { - return false; + throw new ArgumentException(interfaces[i].FullName + " is not an interface"); } - Type[] paramTypes = GetParameterTypes(method.GetParameters()); - for (int i = 0; i < interfaces.Length; i++) + + try { - Type interfaceType = interfaces[i]; - AssertUtils.ArgumentNotNull(interfaceType, StringUtils.Surround("interfaces[", i, "]")); - if (!interfaceType.IsInterface) + MethodInfo mi = interfaceType.GetMethod( + method.Name, + BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly, + null, paramTypes, null); + if (mi != null) { - throw new ArgumentException(interfaces[i].FullName + " is not an interface"); - } - try - { - MethodInfo mi = interfaceType.GetMethod( - method.Name, - BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly, - null, paramTypes, null); - if (mi != null) - { - // found it... - return true; - } - } - catch - { - // didn't find it, so keep going... + // found it... + return true; } } + catch + { + // didn't find it, so keep going... + } + } + + return false; + } + + /// + /// Returns the default value for the specified + /// + /// + ///

+ /// Follows the standard .NET conventions for default values where + /// relevant; for example, all numeric types default to the value + /// 0. + ///

+ ///
+ /// + /// The to return default value for. + /// + /// + /// The default value for the specified . + /// + /// + /// If the supplied is an enumerated type that + /// has no values. + /// + public static object GetDefaultValue(Type type) + { + if (!type.IsValueType) + { + return null; + } + + if (type == typeof(Boolean)) + { return false; } - /// - /// Returns the default value for the specified - /// - /// - ///

- /// Follows the standard .NET conventions for default values where - /// relevant; for example, all numeric types default to the value - /// 0. - ///

- ///
- /// - /// The to return default value for. - /// - /// - /// The default value for the specified . - /// - /// - /// If the supplied is an enumerated type that - /// has no values. - /// - public static object GetDefaultValue(Type type) + if (type == typeof(DateTime)) { - if (!type.IsValueType) + return DateTime.MinValue; + } + + if (type == typeof(Char)) + { + return Char.MinValue; + } + + if (type.IsEnum) + { + Array values = Enum.GetValues(type); + if (values == null || values.Length == 0) { - return null; + throw new ArgumentException("Bad 'enum' Type : cannot get default value because 'enum' has no values."); } - if (type == typeof(Boolean)) + + return values.GetValue(0); + } + + return 0; + } + + /// + /// Returns an array consisting of the default values for the supplied + /// . + /// + /// + /// The array of s to return default values for. + /// + /// + /// An array consisting of the default values for the supplied + /// . + /// + /// + /// If any of the elements in the supplied + /// array is an enumerated type that has no values. + /// + /// + public static object[] GetDefaultValues(Type[] types) + { + object[] defaults = new object[types.Length]; + for (int i = 0; i < types.Length; ++i) + { + defaults[i] = GetDefaultValue(types[i]); + } + + return defaults; + } + + /// + /// Checks that the parameter s of the + /// supplied match the parameter + /// s of the supplied + /// . + /// + /// The method to be checked. + /// + /// The array of parameter s to check against. + /// + /// + /// if the parameter s + /// match. + /// + public static bool ParameterTypesMatch( + MethodInfo candidate, Type[] parameterTypes) + { + #region Sanity Checks + + AssertUtils.ArgumentNotNull(candidate, "candidate"); + AssertUtils.ArgumentNotNull(parameterTypes, "parameterTypes"); + + #endregion + + Type[] candidatesParameterTypes + = ReflectionUtils.GetParameterTypes(candidate); + if (candidatesParameterTypes.Length != parameterTypes.Length) + { + return false; + } + + for (int i = 0; i < candidatesParameterTypes.Length; ++i) + { + if (!candidatesParameterTypes[i].Equals(parameterTypes[i])) { return false; } - if (type == typeof(DateTime)) - { - return DateTime.MinValue; - } - if (type == typeof(Char)) - { - return Char.MinValue; - } - if (type.IsEnum) - { - Array values = Enum.GetValues(type); - if (values == null || values.Length == 0) - { - throw new ArgumentException("Bad 'enum' Type : cannot get default value because 'enum' has no values."); - } - return values.GetValue(0); - } - return 0; } - /// - /// Returns an array consisting of the default values for the supplied - /// . - /// - /// - /// The array of s to return default values for. - /// - /// - /// An array consisting of the default values for the supplied - /// . - /// - /// - /// If any of the elements in the supplied - /// array is an enumerated type that has no values. - /// - /// - public static object[] GetDefaultValues(Type[] types) + return true; + } + + /// + /// Returns an array containing the s of the + /// objects in the supplied array. + /// + /// + /// The objects array for which the corresponding s + /// are needed. + /// + /// + /// An array containing the s of the objects + /// in the supplied array; this array will be empty (but not + /// if the supplied + /// is null or has no elements. + /// + /// + ///

+ /// [C#]
+ /// Given an array containing the following objects, + /// [83, "Foo", new object ()], the + /// array returned from this method call would consist of the following + /// elements... + /// [Int32, String, Object]. + ///

+ ///
+ public static Type[] GetTypes(object[] args) + { + if (args == null || args.Length == 0) { - object[] defaults = new object[types.Length]; - for (int i = 0; i < types.Length; ++i) - { - defaults[i] = GetDefaultValue(types[i]); - } - return defaults; + return Type.EmptyTypes; } - /// - /// Checks that the parameter s of the - /// supplied match the parameter - /// s of the supplied - /// . - /// - /// The method to be checked. - /// - /// The array of parameter s to check against. - /// - /// - /// if the parameter s - /// match. - /// - public static bool ParameterTypesMatch( - MethodInfo candidate, Type[] parameterTypes) + Type[] paramsType = new Type[args.Length]; + for (int i = 0; i < args.Length; ++i) { - #region Sanity Checks - - AssertUtils.ArgumentNotNull(candidate, "candidate"); - AssertUtils.ArgumentNotNull(parameterTypes, "parameterTypes"); - - #endregion - - Type[] candidatesParameterTypes - = ReflectionUtils.GetParameterTypes(candidate); - if (candidatesParameterTypes.Length != parameterTypes.Length) - { - return false; - } - for (int i = 0; i < candidatesParameterTypes.Length; ++i) - { - if (!candidatesParameterTypes[i].Equals(parameterTypes[i])) - { - return false; - } - } - return true; + object arg = args[i]; + paramsType[i] = (arg != null) ? args[i].GetType() : typeof(object); } - /// - /// Returns an array containing the s of the - /// objects in the supplied array. - /// - /// - /// The objects array for which the corresponding s - /// are needed. - /// - /// - /// An array containing the s of the objects - /// in the supplied array; this array will be empty (but not - /// if the supplied - /// is null or has no elements. - /// - /// - ///

- /// [C#]
- /// Given an array containing the following objects, - /// [83, "Foo", new object ()], the - /// array returned from this method call would consist of the following - /// elements... - /// [Int32, String, Object]. - ///

- ///
- public static Type[] GetTypes(object[] args) - { - if (args == null || args.Length == 0) - { - return Type.EmptyTypes; - } - Type[] paramsType = new Type[args.Length]; - for (int i = 0; i < args.Length; ++i) - { - object arg = args[i]; - paramsType[i] = (arg != null) ? args[i].GetType() : typeof(object); - } - return paramsType; - } + return paramsType; + } - - /// - /// Given the return its representation as - /// it would appear in the source code files. - /// - /// - /// Largely intended to handle generic types where .ToString() will typically return: - /// "System.Collections.Generic.List`1[System.Collections.Generic.Dictionary`2[System.String,System.Int32]]" - /// and this method will instead return: - /// "System.Collections.Generic.List<System.Collections.Generic.Dictionary<string,int>>" - /// - /// The type. - /// Friendly string representing the Type - public static string GetTypeFriendlyName(Type type) - { + /// + /// Given the return its representation as + /// it would appear in the source code files. + /// + /// + /// Largely intended to handle generic types where .ToString() will typically return: + /// "System.Collections.Generic.List`1[System.Collections.Generic.Dictionary`2[System.String,System.Int32]]" + /// and this method will instead return: + /// "System.Collections.Generic.List<System.Collections.Generic.Dictionary<string,int>>" + /// + /// The type. + /// Friendly string representing the Type + public static string GetTypeFriendlyName(Type type) + { #if MONO //no csharp services in mono (verify this!) so have to fall back to returning the ToString() for now //TODO: investigate whether there is another equivalent manner of providing this functionality under MONO return type.ToString(); #endif - return (new Microsoft.CSharp.CSharpCodeProvider()).GetTypeOutput(new System.CodeDom.CodeTypeReference(type)); + return (new Microsoft.CSharp.CSharpCodeProvider()).GetTypeOutput(new System.CodeDom.CodeTypeReference(type)); + } + + /// + /// Does the given and/or it's superclasses + /// have at least one or more methods with the given name (with any + /// argument types)? + /// + /// + ///

+ /// Includes non-public methods in the methods searched. + ///

+ ///
+ /// + /// The to be checked. + /// + /// + /// The name of the method to be searched for. Case inSenSItivE. + /// + /// + /// if the given or / and it's + /// superclasses have at least one or more methods (with any argument types); + /// if not, or either of the parameters is . + /// + public static bool HasAtLeastOneMethodWithName(Type type, string name) + { + if (type == null || StringUtils.IsNullOrEmpty(name)) + { + return false; } + return MethodCountForName(type, name) > 0; + } - /// - /// Does the given and/or it's superclasses - /// have at least one or more methods with the given name (with any - /// argument types)? - /// - /// - ///

- /// Includes non-public methods in the methods searched. - ///

- ///
- /// - /// The to be checked. - /// - /// - /// The name of the method to be searched for. Case inSenSItivE. - /// - /// - /// if the given or / and it's - /// superclasses have at least one or more methods (with any argument types); - /// if not, or either of the parameters is . - /// - public static bool HasAtLeastOneMethodWithName(Type type, string name) + /// + /// Within , counts the number of overloads for the method with the given (case-insensitive!) + /// + /// The type to be searched + /// the name of the method for which overloads shall be counted + /// The number of overloads for method within type + public static int MethodCountForName(Type type, string name) + { + AssertUtils.ArgumentNotNull(type, "type", "Type must not be null"); + AssertUtils.ArgumentNotNull(name, "name", "Method name must not be null"); + MemberInfo[] methods = type.FindMembers( + MemberTypes.Method, + ReflectionUtils.AllMembersCaseInsensitiveFlags, + new MemberFilter(ReflectionUtils.MethodNameFilter), + name); + return methods.Length; + } + + private static bool MethodNameFilter(MemberInfo member, object criteria) + { + MethodInfo method = member as MethodInfo; + string name = criteria as string; + return String.Compare(method.Name, name, true, CultureInfo.InvariantCulture) == 0; + } + + /// + /// Creates a . + /// + /// + ///

+ /// Note that if a non- + /// is supplied, any read write properties exposed by the + /// will be used to overwrite values that may have been passed in via the + /// . That is, the will be used + /// to initialize the custom attribute, and then any read-write properties on the + /// will be plugged in. + ///

+ ///
+ /// + /// The desired . + /// + /// + /// Any constructor arguments for the attribute (may be + /// in the case of no arguments). + /// + /// + /// Source attribute to copy properties from (may be ). + /// + /// A custom attribute builder. + /// + /// If the parameter is . + /// + /// + /// If the parameter is not a + /// that derives from the class. + /// + /// + public static CustomAttributeBuilder CreateCustomAttribute( + Type type, object[] ctorArgs, Attribute sourceAttribute) + { + #region Sanity Checks + + AssertUtils.ArgumentNotNull(type, "type"); + if (!typeof(Attribute).IsAssignableFrom(type)) { - if (type == null || StringUtils.IsNullOrEmpty(name)) + throw new ArgumentException( + string.Format("[{0}] does not derive from the [System.Attribute] class.", + type.FullName)); + } + + #endregion + + ConstructorInfo ci = type.GetConstructor(ReflectionUtils.GetTypes(ctorArgs)); + if (ci == null && ctorArgs.Length == 0) + { + ci = type.GetConstructors()[0]; + ctorArgs = GetDefaultValues(GetParameterTypes(ci.GetParameters())); + } + + if (sourceAttribute != null) + { + object defaultAttribute = null; + try { - return false; + defaultAttribute = ci.Invoke(ctorArgs); } - return MethodCountForName(type, name) > 0; - } - - /// - /// Within , counts the number of overloads for the method with the given (case-insensitive!) - /// - /// The type to be searched - /// the name of the method for which overloads shall be counted - /// The number of overloads for method within type - public static int MethodCountForName(Type type, string name) - { - AssertUtils.ArgumentNotNull(type, "type", "Type must not be null"); - AssertUtils.ArgumentNotNull(name, "name", "Method name must not be null"); - MemberInfo[] methods = type.FindMembers( - MemberTypes.Method, - ReflectionUtils.AllMembersCaseInsensitiveFlags, - new MemberFilter(ReflectionUtils.MethodNameFilter), - name); - return methods.Length; - } - - private static bool MethodNameFilter(MemberInfo member, object criteria) - { - MethodInfo method = member as MethodInfo; - string name = criteria as string; - return String.Compare(method.Name, name, true, CultureInfo.InvariantCulture) == 0; - } - - /// - /// Creates a . - /// - /// - ///

- /// Note that if a non- - /// is supplied, any read write properties exposed by the - /// will be used to overwrite values that may have been passed in via the - /// . That is, the will be used - /// to initialize the custom attribute, and then any read-write properties on the - /// will be plugged in. - ///

- ///
- /// - /// The desired . - /// - /// - /// Any constructor arguments for the attribute (may be - /// in the case of no arguments). - /// - /// - /// Source attribute to copy properties from (may be ). - /// - /// A custom attribute builder. - /// - /// If the parameter is . - /// - /// - /// If the parameter is not a - /// that derives from the class. - /// - /// - public static CustomAttributeBuilder CreateCustomAttribute( - Type type, object[] ctorArgs, Attribute sourceAttribute) - { - #region Sanity Checks - - AssertUtils.ArgumentNotNull(type, "type"); - if (!typeof(Attribute).IsAssignableFrom(type)) + catch { - throw new ArgumentException( - string.Format("[{0}] does not derive from the [System.Attribute] class.", - type.FullName)); } - #endregion - - ConstructorInfo ci = type.GetConstructor(ReflectionUtils.GetTypes(ctorArgs)); - if (ci == null && ctorArgs.Length == 0) + IList getSetProps = new List(); + IList getSetValues = new ArrayList(); + IList readOnlyProps = new List(); + IList readOnlyValues = new ArrayList(); + foreach (PropertyInfo pi in type.GetProperties(BindingFlags.Instance | BindingFlags.Public)) { - ci = type.GetConstructors()[0]; - ctorArgs = GetDefaultValues(GetParameterTypes(ci.GetParameters())); - } + if (pi.DeclaringType == typeof(Attribute)) + continue; - if (sourceAttribute != null) - { - object defaultAttribute = null; - try + if (pi.CanRead) { - defaultAttribute = ci.Invoke(ctorArgs); - } - catch - { - } - - IList getSetProps = new List(); - IList getSetValues = new ArrayList(); - IList readOnlyProps = new List(); - IList readOnlyValues = new ArrayList(); - foreach (PropertyInfo pi in type.GetProperties(BindingFlags.Instance | BindingFlags.Public)) - { - if (pi.DeclaringType == typeof(Attribute)) - continue; - - if (pi.CanRead) + if (pi.CanWrite) { - if (pi.CanWrite) + object propValue = pi.GetValue(sourceAttribute, null); + if (defaultAttribute != null) { - object propValue = pi.GetValue(sourceAttribute, null); - if (defaultAttribute != null) - { - object defaultValue = pi.GetValue(defaultAttribute, null); - if ((propValue == null && defaultValue == null) || - (propValue != null && propValue.Equals(defaultValue))) - continue; - } - getSetProps.Add(pi); - getSetValues.Add(propValue); - } - else - { - readOnlyProps.Add(pi); - readOnlyValues.Add(pi.GetValue(sourceAttribute, null)); + object defaultValue = pi.GetValue(defaultAttribute, null); + if ((propValue == null && defaultValue == null) || + (propValue != null && propValue.Equals(defaultValue))) + continue; } + + getSetProps.Add(pi); + getSetValues.Add(propValue); + } + else + { + readOnlyProps.Add(pi); + readOnlyValues.Add(pi.GetValue(sourceAttribute, null)); } } + } - if (readOnlyProps.Count == 1) + if (readOnlyProps.Count == 1) + { + PropertyInfo pi = readOnlyProps[0]; + ConstructorInfo ciTemp = type.GetConstructor(new Type[1] { pi.PropertyType }); + if (ciTemp != null) { - PropertyInfo pi = readOnlyProps[0]; - ConstructorInfo ciTemp = type.GetConstructor(new Type[1] { pi.PropertyType }); + ci = ciTemp; + ctorArgs = new object[1] { readOnlyValues[0] }; + } + else + { + ciTemp = type.GetConstructor(new Type[1] { readOnlyValues[0].GetType() }); if (ciTemp != null) { ci = ciTemp; ctorArgs = new object[1] { readOnlyValues[0] }; } - else + } + } + + PropertyInfo[] propertyInfos = new PropertyInfo[getSetProps.Count]; + getSetProps.CopyTo(propertyInfos, 0); + + object[] propertyValues = new object[getSetValues.Count]; + getSetValues.CopyTo(propertyValues, 0); + + return new CustomAttributeBuilder(ci, ctorArgs, propertyInfos, propertyValues); + } + else + { + return new CustomAttributeBuilder(ci, ctorArgs); + } + } + + /// + /// Creates a . + /// + /// + /// The desired . + /// + /// + /// Source attribute to copy properties from (may be ). + /// + /// A custom attribute builder. + public static CustomAttributeBuilder CreateCustomAttribute( + Type type, Attribute sourceAttribute) + { + return CreateCustomAttribute(type, new object[] { }, sourceAttribute); + } + + /// + /// Creates a . + /// + /// + /// The source attribute to copy properties from. + /// + /// A custom attribute builder. + /// + /// If the supplied is + /// . + /// + public static CustomAttributeBuilder CreateCustomAttribute(Attribute sourceAttribute) + { + return CreateCustomAttribute(sourceAttribute.GetType(), sourceAttribute); + } + + /// + /// Creates a . + /// + /// + /// The desired . + /// + /// A custom attribute builder. + public static CustomAttributeBuilder CreateCustomAttribute(Type type) + { + return CreateCustomAttribute(type, new object[] { }, null); + } + + /// + /// Creates a . + /// + /// + /// The desired . + /// + /// + /// Any constructor arguments for the attribute (may be + /// in the case of no arguments). + /// + /// A custom attribute builder. + public static CustomAttributeBuilder CreateCustomAttribute( + Type type, params object[] ctorArgs) + { + return CreateCustomAttribute(type, ctorArgs, null); + } + + /// + /// Creates a . + /// + /// + /// The to create + /// the custom attribute builder from. + /// + /// A custom attribute builder. + public static CustomAttributeBuilder CreateCustomAttribute(CustomAttributeData attributeData) + { + object[] parameterValues = new object[attributeData.ConstructorArguments.Count]; + Type[] parameterTypes = new Type[attributeData.ConstructorArguments.Count]; + + IList namedParameterValues = new ArrayList(); + IList namedFieldValues = new ArrayList(); + + // Fill arrays of the constructor parameters + for (int i = 0; i < attributeData.ConstructorArguments.Count; i++) + { + parameterTypes[i] = attributeData.ConstructorArguments[i].ArgumentType; + parameterValues[i] = ConvertConstructorArgsToObjectArrayIfNecessary(attributeData.ConstructorArguments[i].Value); + } + + Type attributeType = attributeData.Constructor.DeclaringType; + PropertyInfo[] attributeProperties = attributeType.GetProperties( + BindingFlags.Instance | BindingFlags.Public); + FieldInfo[] attributeFields = attributeType.GetFields( + BindingFlags.Instance | BindingFlags.Public); + + // Not using generics bellow as probably Spring.NET tries to keep + // it on .NET1 compatibility level right now I believe (SD) + // In case of using List the above note makes + // no sense (SD:) + IList propertiesToSet = new ArrayList(); + + IList fieldsToSet = new ArrayList(); + + // Fills arrays of the constructor named parameters + foreach (CustomAttributeNamedArgument namedArgument in attributeData.NamedArguments) + { + bool noMatchingProperty = false; + + // Now iterate through all of the PropertyInfo, find the + // one with the corresponding to the NamedProperty name + // and add it to the array of properties to set. + for (int j = 0; j < attributeProperties.Length; j++) + { + if (attributeProperties[j].Name == namedArgument.MemberInfo.Name) + { + propertiesToSet.Add(attributeProperties[j]); + namedParameterValues.Add(ConvertConstructorArgsToObjectArrayIfNecessary(namedArgument.TypedValue.Value)); + break; + } + else + { + if (j == attributeProperties.Length - 1) { - ciTemp = type.GetConstructor(new Type[1] { readOnlyValues[0].GetType() }); - if (ciTemp != null) - { - ci = ciTemp; - ctorArgs = new object[1] { readOnlyValues[0] }; - } + // In case of no match, throw + noMatchingProperty = true; + /* + throw new InvalidOperationException( + String.Format(CultureInfo.InvariantCulture, + "The property with name {0} can't be found in the " + + "type {1}, but is present as a named property " + + "on the attributeData {2}", namedArgument.MemberInfo.Name, + attributeType.FullName, attributeData)); + */ } } - - PropertyInfo[] propertyInfos = new PropertyInfo[getSetProps.Count]; - getSetProps.CopyTo(propertyInfos, 0); - - object[] propertyValues = new object[getSetValues.Count]; - getSetValues.CopyTo(propertyValues, 0); - - return new CustomAttributeBuilder(ci, ctorArgs, propertyInfos, propertyValues); - } - else - { - return new CustomAttributeBuilder(ci, ctorArgs); - } - } - - /// - /// Creates a . - /// - /// - /// The desired . - /// - /// - /// Source attribute to copy properties from (may be ). - /// - /// A custom attribute builder. - public static CustomAttributeBuilder CreateCustomAttribute( - Type type, Attribute sourceAttribute) - { - return CreateCustomAttribute(type, new object[] { }, sourceAttribute); - } - - /// - /// Creates a . - /// - /// - /// The source attribute to copy properties from. - /// - /// A custom attribute builder. - /// - /// If the supplied is - /// . - /// - public static CustomAttributeBuilder CreateCustomAttribute(Attribute sourceAttribute) - { - return CreateCustomAttribute(sourceAttribute.GetType(), sourceAttribute); - } - - /// - /// Creates a . - /// - /// - /// The desired . - /// - /// A custom attribute builder. - public static CustomAttributeBuilder CreateCustomAttribute(Type type) - { - return CreateCustomAttribute(type, new object[] { }, null); - } - - /// - /// Creates a . - /// - /// - /// The desired . - /// - /// - /// Any constructor arguments for the attribute (may be - /// in the case of no arguments). - /// - /// A custom attribute builder. - public static CustomAttributeBuilder CreateCustomAttribute( - Type type, params object[] ctorArgs) - { - return CreateCustomAttribute(type, ctorArgs, null); - } - - /// - /// Creates a . - /// - /// - /// The to create - /// the custom attribute builder from. - /// - /// A custom attribute builder. - public static CustomAttributeBuilder CreateCustomAttribute(CustomAttributeData attributeData) - { - object[] parameterValues = new object[attributeData.ConstructorArguments.Count]; - Type[] parameterTypes = new Type[attributeData.ConstructorArguments.Count]; - - IList namedParameterValues = new ArrayList(); - IList namedFieldValues = new ArrayList(); - - // Fill arrays of the constructor parameters - for (int i = 0; i < attributeData.ConstructorArguments.Count; i++) - { - parameterTypes[i] = attributeData.ConstructorArguments[i].ArgumentType; - parameterValues[i] = ConvertConstructorArgsToObjectArrayIfNecessary(attributeData.ConstructorArguments[i].Value); } - Type attributeType = attributeData.Constructor.DeclaringType; - PropertyInfo[] attributeProperties = attributeType.GetProperties( - BindingFlags.Instance | BindingFlags.Public); - FieldInfo[] attributeFields = attributeType.GetFields( - BindingFlags.Instance | BindingFlags.Public); - - // Not using generics bellow as probably Spring.NET tries to keep - // it on .NET1 compatibility level right now I believe (SD) - // In case of using List the above note makes - // no sense (SD:) - IList propertiesToSet = new ArrayList(); - - IList fieldsToSet = new ArrayList(); - - // Fills arrays of the constructor named parameters - foreach (CustomAttributeNamedArgument namedArgument in attributeData.NamedArguments) + if (noMatchingProperty) { - bool noMatchingProperty = false; - - // Now iterate through all of the PropertyInfo, find the - // one with the corresponding to the NamedProperty name - // and add it to the array of properties to set. - for (int j = 0; j < attributeProperties.Length; j++) + for (int j = 0; j < attributeFields.Length; j++) { - if (attributeProperties[j].Name == namedArgument.MemberInfo.Name) + if (attributeFields[j].Name == namedArgument.MemberInfo.Name) { - propertiesToSet.Add(attributeProperties[j]); - namedParameterValues.Add(ConvertConstructorArgsToObjectArrayIfNecessary(namedArgument.TypedValue.Value)); + fieldsToSet.Add(attributeFields[j]); + namedFieldValues.Add(ConvertConstructorArgsToObjectArrayIfNecessary(namedArgument.TypedValue.Value)); break; } else { - if (j == attributeProperties.Length - 1) + if (j == attributeFields.Length - 1) { - // In case of no match, throw - noMatchingProperty = true; - /* throw new InvalidOperationException( String.Format(CultureInfo.InvariantCulture, - "The property with name {0} can't be found in the " + - "type {1}, but is present as a named property " + - "on the attributeData {2}", namedArgument.MemberInfo.Name, - attributeType.FullName, attributeData)); - */ + "A property or public field with name {0} can't be found in the " + + "type {1}, but is present as a named property " + + "on the attributeData {2}", namedArgument.MemberInfo.Name, + attributeType.FullName, attributeData)); } } } - if (noMatchingProperty) + } + } + + // Get constructor corresponding to the parameters and their types + ConstructorInfo constructor = attributeType.GetConstructor(parameterTypes); + + PropertyInfo[] namedProperties = new PropertyInfo[propertiesToSet.Count]; + propertiesToSet.CopyTo(namedProperties, 0); + + object[] propertyValues = new object[namedParameterValues.Count]; + namedParameterValues.CopyTo(propertyValues, 0); + + if (fieldsToSet.Count == 0) + { + return new CustomAttributeBuilder( + constructor, parameterValues, namedProperties, propertyValues); + } + else + { + FieldInfo[] namedFields = new FieldInfo[fieldsToSet.Count]; + fieldsToSet.CopyTo(namedFields, 0); + + object[] fieldValues = new object[namedFieldValues.Count]; + namedFieldValues.CopyTo(fieldValues, 0); + + return new CustomAttributeBuilder( + constructor, parameterValues, namedProperties, propertyValues, namedFields, fieldValues); + } + } + + private static object ConvertConstructorArgsToObjectArrayIfNecessary(object value) + { + if (value == null) + return value; + + IList constructorArguments = value as IList; + + if (constructorArguments == null) + return value; + + object[] arguments = new object[constructorArguments.Count]; + + for (int i = 0; i < constructorArguments.Count; i++) + { + arguments[i] = constructorArguments[i].Value; + } + + return arguments; + } + + /// + /// Calculates and returns the list of attributes that apply to the + /// specified type or method. + /// + /// The type or method to find attributes for. + /// + /// A list of custom attributes (CustomAttributeData or Attribute instances) + /// that should be applied to type or method. + /// + public static IList GetCustomAttributes(MemberInfo member) + { + ArrayList attributes = new ArrayList(); + + // add attributes that apply to the target type or method + object[] attrs = member.GetCustomAttributes(false); + try + { + IList attrsData = CustomAttributeData.GetCustomAttributes(member); + + if (attrs.Length != attrsData.Count) + { + // http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=94803 + attributes.AddRange(attrs); + } + else if (attrsData.Count > 0) + { + bool hasSecurityAttribute = false; + foreach (CustomAttributeData cad in attrsData) { - for (int j = 0; j < attributeFields.Length; j++) + if (typeof(SecurityAttribute).IsAssignableFrom(cad.Constructor.DeclaringType)) { - if (attributeFields[j].Name == namedArgument.MemberInfo.Name) - { - fieldsToSet.Add(attributeFields[j]); - namedFieldValues.Add(ConvertConstructorArgsToObjectArrayIfNecessary(namedArgument.TypedValue.Value)); - break; - } - else - { - if (j == attributeFields.Length - 1) - { - throw new InvalidOperationException( - String.Format(CultureInfo.InvariantCulture, - "A property or public field with name {0} can't be found in the " + - "type {1}, but is present as a named property " + - "on the attributeData {2}", namedArgument.MemberInfo.Name, - attributeType.FullName, attributeData)); - } - } + hasSecurityAttribute = true; + break; } } - } - // Get constructor corresponding to the parameters and their types - ConstructorInfo constructor = attributeType.GetConstructor(parameterTypes); - PropertyInfo[] namedProperties = new PropertyInfo[propertiesToSet.Count]; - propertiesToSet.CopyTo(namedProperties, 0); - - object[] propertyValues = new object[namedParameterValues.Count]; - namedParameterValues.CopyTo(propertyValues, 0); - - if (fieldsToSet.Count == 0) - { - return new CustomAttributeBuilder( - constructor, parameterValues, namedProperties, propertyValues); - } - else - { - FieldInfo[] namedFields = new FieldInfo[fieldsToSet.Count]; - fieldsToSet.CopyTo(namedFields, 0); - - object[] fieldValues = new object[namedFieldValues.Count]; - namedFieldValues.CopyTo(fieldValues, 0); - - return new CustomAttributeBuilder( - constructor, parameterValues, namedProperties, propertyValues, namedFields, fieldValues); - } - - - - } - - private static object ConvertConstructorArgsToObjectArrayIfNecessary(object value) - { - if (value == null) - return value; - - IList constructorArguments = value as IList; - - if (constructorArguments == null) - return value; - - object[] arguments = new object[constructorArguments.Count]; - - for (int i = 0; i < constructorArguments.Count; i++) - { - arguments[i] = constructorArguments[i].Value; - } - - return arguments; - } - - /// - /// Calculates and returns the list of attributes that apply to the - /// specified type or method. - /// - /// The type or method to find attributes for. - /// - /// A list of custom attributes (CustomAttributeData or Attribute instances) - /// that should be applied to type or method. - /// - public static IList GetCustomAttributes(MemberInfo member) - { - ArrayList attributes = new ArrayList(); - - // add attributes that apply to the target type or method - object[] attrs = member.GetCustomAttributes(false); - try - { - IList attrsData = CustomAttributeData.GetCustomAttributes(member); - - if (attrs.Length != attrsData.Count) + if (hasSecurityAttribute) { - // http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=94803 attributes.AddRange(attrs); } - else if (attrsData.Count > 0) + else { - bool hasSecurityAttribute = false; foreach (CustomAttributeData cad in attrsData) { - if (typeof(SecurityAttribute).IsAssignableFrom(cad.Constructor.DeclaringType)) - { - hasSecurityAttribute = true; - break; - } - } - - if (hasSecurityAttribute) - { - attributes.AddRange(attrs); - } - else - { - foreach (CustomAttributeData cad in attrsData) - { - attributes.Add(cad); - } + attributes.Add(cad); } } } - catch (ArgumentException) - { - // http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=296032 - attributes.AddRange(attrs); - } - catch (CustomAttributeFormatException) - { - // http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=161522 - attributes.AddRange(attrs); - } - return attributes; + } + catch (ArgumentException) + { + // http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=296032 + attributes.AddRange(attrs); + } + catch (CustomAttributeFormatException) + { + // http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=161522 + attributes.AddRange(attrs); } - /// - /// Tries to find matching methods in the specified - /// for each method in the supplied list. - /// - /// - /// The to look for matching methods in. - /// - /// The methods to match. - /// - /// A flag that specifies whether to throw an exception if a matching - /// method is not found. - /// - /// A list of the matched methods. - /// - /// If either of the or - /// parameters are . - /// - public static MethodInfo[] GetMatchingMethods(Type type, MethodInfo[] methods, bool strict) + return attributes; + } + + /// + /// Tries to find matching methods in the specified + /// for each method in the supplied list. + /// + /// + /// The to look for matching methods in. + /// + /// The methods to match. + /// + /// A flag that specifies whether to throw an exception if a matching + /// method is not found. + /// + /// A list of the matched methods. + /// + /// If either of the or + /// parameters are . + /// + public static MethodInfo[] GetMatchingMethods(Type type, MethodInfo[] methods, bool strict) + { + AssertUtils.ArgumentNotNull(type, "type"); + AssertUtils.ArgumentNotNull(methods, "methods"); + + BindingFlags flags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase; + + MethodInfo[] matched = new MethodInfo[methods.Length]; + for (int i = 0; i < methods.Length; i++) { - AssertUtils.ArgumentNotNull(type, "type"); - AssertUtils.ArgumentNotNull(methods, "methods"); - - BindingFlags flags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase; - - MethodInfo[] matched = new MethodInfo[methods.Length]; - for (int i = 0; i < methods.Length; i++) + MethodInfo method = methods[i]; + MethodInfo match = type.GetMethod(method.Name, flags, null, ReflectionUtils.GetParameterTypes(method), null); + if ((match == null || match.ReturnType != method.ReturnType) && strict) { - MethodInfo method = methods[i]; - MethodInfo match = type.GetMethod(method.Name, flags, null, ReflectionUtils.GetParameterTypes(method), null); - if ((match == null || match.ReturnType != method.ReturnType) && strict) - { - throw new Exception( - string.Format("Method '{0}' could not be matched in the target class [{1}].", - method.Name, type.FullName)); - } - matched[i] = match; + throw new Exception( + string.Format("Method '{0}' could not be matched in the target class [{1}].", + method.Name, type.FullName)); } - return matched; + + matched[i] = match; } - /// - /// Returns the of the supplied - /// . - /// - /// - ///

- /// If the is a - /// instance, the return value of this method call with be the - /// parameter cast to a - /// . If the is - /// anything other than a , the return value - /// will be the result of invoking the 's - /// method. - ///

- ///
- /// - /// A or instance. - /// - /// - /// The argument if it is a - /// or the result of invoking - /// on the argument if it - /// is an . - /// - /// - /// If the is . - /// - public static Type TypeOfOrType(object source) + return matched; + } + + /// + /// Returns the of the supplied + /// . + /// + /// + ///

+ /// If the is a + /// instance, the return value of this method call with be the + /// parameter cast to a + /// . If the is + /// anything other than a , the return value + /// will be the result of invoking the 's + /// method. + ///

+ ///
+ /// + /// A or instance. + /// + /// + /// The argument if it is a + /// or the result of invoking + /// on the argument if it + /// is an . + /// + /// + /// If the is . + /// + public static Type TypeOfOrType(object source) + { + return source is Type ? source as Type : source.GetType(); + } + + private static readonly MethodInfo Exception_InternalPreserveStackTrace = + typeof(Exception).GetMethod("InternalPreserveStackTrace", BindingFlags.Instance | BindingFlags.NonPublic); + + /// + /// Unwraps the supplied + /// and returns the inner exception preserving the stack trace. + /// + /// + /// The to unwrap. + /// + /// The unwrapped exception. + public static Exception UnwrapTargetInvocationException(TargetInvocationException ex) + { + if (SystemUtils.MonoRuntime) { - return source is Type ? source as Type : source.GetType(); - } - - - private static readonly MethodInfo Exception_InternalPreserveStackTrace = - typeof(Exception).GetMethod("InternalPreserveStackTrace", BindingFlags.Instance | BindingFlags.NonPublic); - - /// - /// Unwraps the supplied - /// and returns the inner exception preserving the stack trace. - /// - /// - /// The to unwrap. - /// - /// The unwrapped exception. - public static Exception UnwrapTargetInvocationException(TargetInvocationException ex) - { - if (SystemUtils.MonoRuntime) - { - return ex.InnerException; - } - Exception_InternalPreserveStackTrace.Invoke(ex.InnerException, new Object[] { }); return ex.InnerException; } - /// - /// Is the supplied can be accessed outside the assembly ? - /// - /// The type to check. - /// - /// if the type can be accessed outside the assembly; - /// Otherwise . - /// - public static bool IsTypeVisible(Type type) - { - return IsTypeVisible(type, null); - } + Exception_InternalPreserveStackTrace.Invoke(ex.InnerException, new Object[] { }); + return ex.InnerException; + } - /// - /// Determines whether the specified type is nullable. - /// - /// The type. - /// - /// true if the specified type is ullable]; otherwise, false. - /// - public static bool IsTypeNullable(Type type) - { - return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>); - } + /// + /// Is the supplied can be accessed outside the assembly ? + /// + /// The type to check. + /// + /// if the type can be accessed outside the assembly; + /// Otherwise . + /// + public static bool IsTypeVisible(Type type) + { + return IsTypeVisible(type, null); + } - /// - /// Is the supplied can be accessed - /// from the supplied friendly assembly ? - /// - /// The type to check. - /// The friendly assembly name. - /// - /// if the type can be accessed - /// from the supplied friendly assembly; Otherwise . - /// - public static bool IsTypeVisible(Type type, string friendlyAssemblyName) + /// + /// Determines whether the specified type is nullable. + /// + /// The type. + /// + /// true if the specified type is ullable]; otherwise, false. + /// + public static bool IsTypeNullable(Type type) + { + return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>); + } + + /// + /// Is the supplied can be accessed + /// from the supplied friendly assembly ? + /// + /// The type to check. + /// The friendly assembly name. + /// + /// if the type can be accessed + /// from the supplied friendly assembly; Otherwise . + /// + public static bool IsTypeVisible(Type type, string friendlyAssemblyName) + { + if (type.IsVisible) { - if (type.IsVisible) + return true; + } + else + { + if (friendlyAssemblyName != null + && friendlyAssemblyName.Length > 0 + && (!type.IsNested || type.IsNestedPublic || + (!type.IsNestedPrivate && (type.IsNestedAssembly || type.IsNestedFamORAssem)))) { - return true; - } - else - { - if (friendlyAssemblyName != null - && friendlyAssemblyName.Length > 0 - && (!type.IsNested || type.IsNestedPublic || - (!type.IsNestedPrivate && (type.IsNestedAssembly || type.IsNestedFamORAssem)))) + object[] attrs = type.Assembly.GetCustomAttributes(typeof(InternalsVisibleToAttribute), false); + foreach (InternalsVisibleToAttribute ivta in attrs) { - object[] attrs = type.Assembly.GetCustomAttributes(typeof(InternalsVisibleToAttribute), false); - foreach (InternalsVisibleToAttribute ivta in attrs) + if (ivta.AssemblyName.Split(',')[0] == friendlyAssemblyName) { - if (ivta.AssemblyName.Split(',')[0] == friendlyAssemblyName) - { - return true; - } + return true; } } } - return false; } - /// - /// Gets all of the interfaces implemented by - /// the specified . - /// - /// - /// The object to get the interfaces of. - /// - /// - /// All of the interfaces implemented by the - /// . - /// - public static Type[] GetInterfaces(Type type) - { - AssertUtils.ArgumentNotNull(type, "type"); + return false; + } - if (type.IsInterface) - { - List interfaces = new List(); - interfaces.Add(type); - interfaces.AddRange(type.GetInterfaces()); - return interfaces.ToArray(); - } - else - { - return type.GetInterfaces(); - } + /// + /// Gets all of the interfaces implemented by + /// the specified . + /// + /// + /// The object to get the interfaces of. + /// + /// + /// All of the interfaces implemented by the + /// . + /// + public static Type[] GetInterfaces(Type type) + { + AssertUtils.ArgumentNotNull(type, "type"); + + if (type.IsInterface) + { + List interfaces = new List(); + interfaces.Add(type); + interfaces.AddRange(type.GetInterfaces()); + return interfaces.ToArray(); + } + else + { + return type.GetInterfaces(); + } + } + + /// + /// Returns the explicit that is the root cause of an exception. + /// + /// + /// If the InnerException property of the current exception is a null reference + /// or a , returns the current exception. + /// + /// The last exception thrown. + /// + /// The first explicit exception thrown in a chain of exceptions. + /// + public static Exception GetExplicitBaseException(Exception ex) + { + Exception innerEx = ex.InnerException; + while (innerEx != null && + !(innerEx is NullReferenceException)) + { + ex = innerEx; + innerEx = innerEx.InnerException; } - /// - /// Returns the explicit that is the root cause of an exception. - /// - /// - /// If the InnerException property of the current exception is a null reference - /// or a , returns the current exception. - /// - /// The last exception thrown. - /// - /// The first explicit exception thrown in a chain of exceptions. - /// - public static Exception GetExplicitBaseException(Exception ex) + return ex; + } + + /// + /// Copies all fields from one object to another. + /// + /// + /// The types of both objects must be related. This means, that either of the following is true: + /// + /// fromObject.GetType() == toObject.GetType() + /// fromObject.GetType() is derived from toObject.GetType() + /// toObject.GetType() is derived from fromObject.GetType() + /// + /// + /// The source object + /// The object, who's fields will be populated with values from the source object + /// If the object's types are not related + public static void MemberwiseCopy(object fromObject, object toObject) + { + Type fromType = fromObject.GetType(); + Type toType = toObject.GetType(); + + Type smallerType; + + if (fromType.IsAssignableFrom(toType)) { - Exception innerEx = ex.InnerException; - while (innerEx != null && - !(innerEx is NullReferenceException)) - { - ex = innerEx; - innerEx = innerEx.InnerException; - } - return ex; + smallerType = fromType; + } + else if (toType.IsAssignableFrom(fromType)) + { + smallerType = toType; + } + else + { + throw new ArgumentException("object types are not related"); } - /// - /// Copies all fields from one object to another. - /// - /// - /// The types of both objects must be related. This means, that either of the following is true: - /// - /// fromObject.GetType() == toObject.GetType() - /// fromObject.GetType() is derived from toObject.GetType() - /// toObject.GetType() is derived from fromObject.GetType() - /// - /// - /// The source object - /// The object, who's fields will be populated with values from the source object - /// If the object's types are not related - public static void MemberwiseCopy(object fromObject, object toObject) + MemberwiseCopyInternal(fromObject, toObject, smallerType); + } + + /// + /// Convenience method that uses reflection to return the value of a non-public field of a given object. + /// + /// Useful in certain instances during testing to avoid the need to add protected properties, etc. to a class just to facilitate testing. + /// The instance of the object from which to retrieve the field value. + /// Name of the field on the object from which to retrieve the value. + /// + public static object GetInstanceFieldValue(object obj, string fieldName) + { + if (obj == null) + throw new ArgumentNullException("obj", "obj is null."); + if (StringUtils.IsNullOrEmpty(fieldName)) + throw new ArgumentException("fieldName is null or empty.", "fieldName"); + + FieldInfo f = obj.GetType().GetField(fieldName, BindingFlags.SetField | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); + if (f != null) + return f.GetValue(obj); + else { - Type fromType = fromObject.GetType(); - Type toType = toObject.GetType(); + throw new ArgumentException(string.Format("Non-public instance field '{0}' could not be found in class of type '{1}'", fieldName, obj.GetType().ToString())); + } + } - Type smallerType; + /// + /// Convenience method that uses reflection to set the value of a non-public field of a given object. + /// + /// Useful in certain instances during testing to avoid the need to add protected properties, etc. to a class just to facilitate testing. + /// The instance of the object from which to set the field value. + /// Name of the field on the object to which to set the value. + /// The field value to set. + public static void SetInstanceFieldValue(object obj, string fieldName, object fieldValue) + { + if (obj == null) + throw new ArgumentNullException("obj", "obj is null."); + if (StringUtils.IsNullOrEmpty(fieldName)) + throw new ArgumentException("fieldName is null or empty.", "fieldName"); + if (fieldValue == null) + throw new ArgumentNullException("fieldValue", "fieldValue is null."); - if (fromType.IsAssignableFrom(toType)) - { - smallerType = fromType; - } - else if (toType.IsAssignableFrom(fromType)) - { - smallerType = toType; - } - else - { - throw new ArgumentException("object types are not related"); - } + FieldInfo f = obj.GetType().GetField(fieldName, BindingFlags.SetField | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); - MemberwiseCopyInternal(fromObject, toObject, smallerType); + if (f != null) + { + if (f.FieldType != fieldValue.GetType()) + throw new ArgumentException(string.Format("fieldValue for fieldName '{0}' of object type '{1}' must be of type '{2}' but was of type '{3}'", fieldName, obj.GetType().ToString(), f.FieldType.ToString(), fieldValue.GetType().ToString()), "fieldValue"); + + f.SetValue(obj, fieldValue); + } + else + { + throw new ArgumentException(string.Format("Non-public instance field '{0}' could not be found in class of type '{1}'", fieldName, obj.GetType().ToString())); + } + } + + private static void MemberwiseCopyInternal(object fromObject, object toObject, Type smallerType) + { + MemberwiseCopyHandler impl = GetImpl(smallerType); + impl(fromObject, toObject); + } + + private delegate void MemberwiseCopyHandler(object a, object b); + + private static readonly Dictionary s_handlerCache = new Dictionary(); + + private static MemberwiseCopyHandler GetImpl(Type type) + { + MemberwiseCopyHandler handler; + if (s_handlerCache.TryGetValue(type, out handler)) + { + return handler; } - - /// - /// Convenience method that uses reflection to return the value of a non-public field of a given object. - /// - /// Useful in certain instances during testing to avoid the need to add protected properties, etc. to a class just to facilitate testing. - /// The instance of the object from which to retrieve the field value. - /// Name of the field on the object from which to retrieve the value. - /// - public static object GetInstanceFieldValue(object obj, string fieldName) + lock (s_handlerCache) { - if (obj == null) - throw new ArgumentNullException("obj", "obj is null."); - if (StringUtils.IsNullOrEmpty(fieldName)) - throw new ArgumentException("fieldName is null or empty.", "fieldName"); - - FieldInfo f = obj.GetType().GetField(fieldName, BindingFlags.SetField | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); - if (f != null) - return f.GetValue(obj); - else - { - throw new ArgumentException(string.Format("Non-public instance field '{0}' could not be found in class of type '{1}'", fieldName, obj.GetType().ToString())); - } - } - - /// - /// Convenience method that uses reflection to set the value of a non-public field of a given object. - /// - /// Useful in certain instances during testing to avoid the need to add protected properties, etc. to a class just to facilitate testing. - /// The instance of the object from which to set the field value. - /// Name of the field on the object to which to set the value. - /// The field value to set. - public static void SetInstanceFieldValue(object obj, string fieldName, object fieldValue) - { - - if (obj == null) - throw new ArgumentNullException("obj", "obj is null."); - if (StringUtils.IsNullOrEmpty(fieldName)) - throw new ArgumentException("fieldName is null or empty.", "fieldName"); - if (fieldValue == null) - throw new ArgumentNullException("fieldValue", "fieldValue is null."); - - FieldInfo f = obj.GetType().GetField(fieldName, BindingFlags.SetField | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); - - if (f != null) - { - if (f.FieldType != fieldValue.GetType()) - throw new ArgumentException(string.Format("fieldValue for fieldName '{0}' of object type '{1}' must be of type '{2}' but was of type '{3}'", fieldName, obj.GetType().ToString(), f.FieldType.ToString(), fieldValue.GetType().ToString()), "fieldValue"); - - f.SetValue(obj, fieldValue); - } - else - { - throw new ArgumentException(string.Format("Non-public instance field '{0}' could not be found in class of type '{1}'", fieldName, obj.GetType().ToString())); - } - } - - private static void MemberwiseCopyInternal(object fromObject, object toObject, Type smallerType) - { - MemberwiseCopyHandler impl = GetImpl(smallerType); - impl(fromObject, toObject); - } - - private delegate void MemberwiseCopyHandler(object a, object b); - - private static readonly Dictionary s_handlerCache = new Dictionary(); - - private static MemberwiseCopyHandler GetImpl(Type type) - { - MemberwiseCopyHandler handler; if (s_handlerCache.TryGetValue(type, out handler)) { return handler; } - lock (s_handlerCache) + FieldInfo[] fields = GetFields(type); + Action callback = () => { - if (s_handlerCache.TryGetValue(type, out handler)) + DynamicMethod dm = new DynamicMethod(type.FullName + ".ShallowCopy", null, new Type[] { typeof(object), typeof(object) }, type.Module, true); + ILGenerator ilGen = dm.GetILGenerator(); + ilGen.DeclareLocal(type); + ilGen.DeclareLocal(type); + ilGen.Emit(OpCodes.Ldarg_0); + ilGen.Emit(OpCodes.Castclass, type); + ilGen.Emit(OpCodes.Stloc_0); + ilGen.Emit(OpCodes.Ldarg_1); + ilGen.Emit(OpCodes.Castclass, type); + ilGen.Emit(OpCodes.Stloc_1); + + foreach (FieldInfo field in fields) { - return handler; + ilGen.Emit(OpCodes.Ldloc_1); + ilGen.Emit(OpCodes.Ldloc_0); + ilGen.Emit(OpCodes.Ldfld, field); + ilGen.Emit(OpCodes.Stfld, field); } - FieldInfo[] fields = GetFields(type); - Action callback = () => - { - DynamicMethod dm = new DynamicMethod(type.FullName + ".ShallowCopy", null, new Type[] {typeof(object), typeof(object)}, type.Module, true); - ILGenerator ilGen = dm.GetILGenerator(); - ilGen.DeclareLocal(type); - ilGen.DeclareLocal(type); - ilGen.Emit(OpCodes.Ldarg_0); - ilGen.Emit(OpCodes.Castclass, type); - ilGen.Emit(OpCodes.Stloc_0); - ilGen.Emit(OpCodes.Ldarg_1); - ilGen.Emit(OpCodes.Castclass, type); - ilGen.Emit(OpCodes.Stloc_1); + ilGen.Emit(OpCodes.Ret); - foreach (FieldInfo field in fields) - { - ilGen.Emit(OpCodes.Ldloc_1); - ilGen.Emit(OpCodes.Ldloc_0); - ilGen.Emit(OpCodes.Ldfld, field); - ilGen.Emit(OpCodes.Stfld, field); - } - - ilGen.Emit(OpCodes.Ret); - - handler = (MemberwiseCopyHandler) dm.CreateDelegate(typeof(MemberwiseCopyHandler)); - }; + handler = (MemberwiseCopyHandler) dm.CreateDelegate(typeof(MemberwiseCopyHandler)); + }; #if NETSTANDARD callback(); #else - SecurityCritical.ExecutePrivileged(new System.Security.PermissionSet(PermissionState.Unrestricted), callback); + SecurityCritical.ExecutePrivileged(new System.Security.PermissionSet(PermissionState.Unrestricted), callback); #endif - s_handlerCache[type] = handler; - } - return handler; + s_handlerCache[type] = handler; } + return handler; + } - #region Field Cache Management for "MemberwiseCopy" + #region Field Cache Management for "MemberwiseCopy" - private const BindingFlags FIELDBINDINGS = - BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic; + private const BindingFlags FIELDBINDINGS = + BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic; - private static readonly Dictionary s_fieldCache = new Dictionary(); + private static readonly Dictionary s_fieldCache = new Dictionary(); - private static FieldInfo[] GetFields(Type type) + private static FieldInfo[] GetFields(Type type) + { + lock (s_fieldCache) { - lock (s_fieldCache) + FieldInfo[] fields; + if (!s_fieldCache.TryGetValue(type, out fields)) { - FieldInfo[] fields; - if (!s_fieldCache.TryGetValue(type, out fields)) - { - List fieldList = new List(); - CollectFieldsRecursive(type, fieldList); - fields = fieldList.ToArray(); - s_fieldCache[type] = fields; - } - return fields; + List fieldList = new List(); + CollectFieldsRecursive(type, fieldList); + fields = fieldList.ToArray(); + s_fieldCache[type] = fields; } + + return fields; } + } - private static void CollectFieldsRecursive(Type type, List fieldList) - { - if (type == typeof(object)) - return; + private static void CollectFieldsRecursive(Type type, List fieldList) + { + if (type == typeof(object)) + return; - FieldInfo[] fields = type.GetFields(FIELDBINDINGS); - fieldList.AddRange(fields); - CollectFieldsRecursive(type.BaseType, fieldList); - } + FieldInfo[] fields = type.GetFields(FIELDBINDINGS); + fieldList.AddRange(fields); + CollectFieldsRecursive(type.BaseType, fieldList); + } - #endregion Field Cache Management for "MemberwiseCopy" + #endregion Field Cache Management for "MemberwiseCopy" + #region CustomAttributeBuilderBuilder inner class definition - #region CustomAttributeBuilderBuilder inner class definition + /// + /// Creates a . + /// + /// Bruno Baia + public class CustomAttributeBuilderBuilder + { + #region Fields + + private Type type; + private ArrayList constructorArgs; + private List namedProperties; + private List propertyValues; + + #endregion + + #region Constructor(s) / Destructor /// - /// Creates a . + /// Creates a new instance of the + /// class. /// - /// Bruno Baia - public class CustomAttributeBuilderBuilder + /// The custom attribute type. + public CustomAttributeBuilderBuilder(Type attributeType) + : + this(attributeType, ObjectUtils.EmptyObjects) { - #region Fields + } - private Type type; - private ArrayList constructorArgs; - private List namedProperties; - private List propertyValues; - - #endregion - - #region Constructor(s) / Destructor - - /// - /// Creates a new instance of the - /// class. - /// - /// The custom attribute type. - public CustomAttributeBuilderBuilder(Type attributeType) - : - this(attributeType, ObjectUtils.EmptyObjects) + /// + /// Creates a new instance of the + /// class. + /// + /// The custom attribute type. + /// The custom attribute constructor arguments. + public CustomAttributeBuilderBuilder(Type attributeType, params object[] constructorArgs) + { + AssertUtils.ArgumentNotNull(attributeType, "attributeType"); + if (!typeof(Attribute).IsAssignableFrom(attributeType)) { + throw new ArgumentException( + string.Format("[{0}] does not derive from the [System.Attribute] class.", + attributeType.FullName)); } - /// - /// Creates a new instance of the - /// class. - /// - /// The custom attribute type. - /// The custom attribute constructor arguments. - public CustomAttributeBuilderBuilder(Type attributeType, params object[] constructorArgs) + this.type = attributeType; + this.constructorArgs = new ArrayList(constructorArgs); + this.namedProperties = new List(); + this.propertyValues = new List(); + } + + #endregion + + #region Public Methods + + /// + /// Adds the specified values to the constructor argument list + /// used to create the custom attribute. + /// + /// An array of argument values. + public void AddContructorArgument(params object[] values) + { + this.constructorArgs.AddRange(values); + } + + /// + /// Adds a property value to the custom attribute. + /// + /// The property name. + /// The property value. + public void AddPropertyValue(string name, object value) + { + PropertyInfo propertyInfo = this.type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public); + if (propertyInfo == null) { - AssertUtils.ArgumentNotNull(attributeType, "attributeType"); - if (!typeof(Attribute).IsAssignableFrom(attributeType)) - { - throw new ArgumentException( - string.Format("[{0}] does not derive from the [System.Attribute] class.", - attributeType.FullName)); - } - this.type = attributeType; - this.constructorArgs = new ArrayList(constructorArgs); - this.namedProperties = new List(); - this.propertyValues = new List(); + throw new ArgumentException( + String.Format("The property '{0}' does no exist in the attribute '{1}'.", name, this.type)); } - #endregion + this.namedProperties.Add(propertyInfo); + this.propertyValues.Add(value); + } - #region Public Methods - - /// - /// Adds the specified values to the constructor argument list - /// used to create the custom attribute. - /// - /// An array of argument values. - public void AddContructorArgument(params object[] values) + /// + /// Creates the . + /// + /// The created . + public CustomAttributeBuilder Build() + { + object[] caArray = (object[]) this.constructorArgs.ToArray(typeof(object)); + ConstructorInfo ci = this.type.GetConstructor(ReflectionUtils.GetTypes(caArray)); + if (ci == null && caArray.Length == 0) { - this.constructorArgs.AddRange(values); + ci = this.type.GetConstructors()[0]; + caArray = ReflectionUtils.GetDefaultValues(ReflectionUtils.GetParameterTypes(ci.GetParameters())); } - /// - /// Adds a property value to the custom attribute. - /// - /// The property name. - /// The property value. - public void AddPropertyValue(string name, object value) + if (namedProperties.Count > 0) { - PropertyInfo propertyInfo = this.type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public); - if (propertyInfo == null) - { - throw new ArgumentException( - String.Format("The property '{0}' does no exist in the attribute '{1}'.", name, this.type)); - } - - this.namedProperties.Add(propertyInfo); - this.propertyValues.Add(value); + PropertyInfo[] npArray = this.namedProperties.ToArray(); + object[] pvArray = this.propertyValues.ToArray(); + return new CustomAttributeBuilder(ci, caArray, npArray, pvArray); } - - /// - /// Creates the . - /// - /// The created . - public CustomAttributeBuilder Build() + else { - object[] caArray = (object[])this.constructorArgs.ToArray(typeof(object)); - ConstructorInfo ci = this.type.GetConstructor(ReflectionUtils.GetTypes(caArray)); - if (ci == null && caArray.Length == 0) - { - ci = this.type.GetConstructors()[0]; - caArray = ReflectionUtils.GetDefaultValues(ReflectionUtils.GetParameterTypes(ci.GetParameters())); - } - - if (namedProperties.Count > 0) - { - PropertyInfo[] npArray = this.namedProperties.ToArray(); - object[] pvArray = this.propertyValues.ToArray(); - return new CustomAttributeBuilder(ci, caArray, npArray, pvArray); - } - else - { - return new CustomAttributeBuilder(ci, caArray); - } - + return new CustomAttributeBuilder(ci, caArray); } - - #endregion } #endregion } + + #endregion } diff --git a/src/Spring/Spring.Core/Util/Shims.cs b/src/Spring/Spring.Core/Util/Shims.cs index 81fb52ef..983babbe 100644 --- a/src/Spring/Spring.Core/Util/Shims.cs +++ b/src/Spring/Spring.Core/Util/Shims.cs @@ -7,4 +7,4 @@ namespace System.Runtime.Remoting public static bool IsTransparentProxy(object o) => false; } } -#endif \ No newline at end of file +#endif diff --git a/src/Spring/Spring.Core/Util/StringUtils.cs b/src/Spring/Spring.Core/Util/StringUtils.cs index d9c8031a..4aab0f85 100644 --- a/src/Spring/Spring.Core/Util/StringUtils.cs +++ b/src/Spring/Spring.Core/Util/StringUtils.cs @@ -18,658 +18,677 @@ using System.Globalization; using System.Runtime.CompilerServices; using System.Text; -namespace Spring.Util +namespace Spring.Util; + +/// +/// Miscellaneous utility methods. +/// +/// +///

+/// Mainly for internal use within the framework. +///

+///
+/// Rod Johnson +/// Juergen Hoeller +/// Keith Donald +/// Aleksandar Seovic (.NET) +/// Mark Pollack (.NET) +/// Rick Evans (.NET) +/// Erich Eichinger (.NET) +public static class StringUtils { /// - /// Miscellaneous utility methods. + /// An empty array of instances. + /// + public static readonly string[] EmptyStrings = { }; + + public static readonly IReadOnlyList EmptyStringsList = new List(); + + /// + /// The string that signals the start of an Ant-style expression. + /// + private const string AntExpressionPrefix = "${"; + + /// + /// The string that signals the end of an Ant-style expression. + /// + private const string AntExpressionSuffix = "}"; + + /// + /// Tokenize the given into a + /// array. /// /// ///

- /// Mainly for internal use within the framework. + /// If is , returns an empty + /// array. + ///

+ ///

+ /// If is or the empty + /// , returns a array with one + /// element: itself. ///

///
- /// Rod Johnson - /// Juergen Hoeller - /// Keith Donald - /// Aleksandar Seovic (.NET) - /// Mark Pollack (.NET) - /// Rick Evans (.NET) - /// Erich Eichinger (.NET) - public static class StringUtils + /// The to tokenize. + /// + /// The delimiter characters, assembled as a . + /// + /// + /// Trim the tokens via . + /// + /// + /// Omit empty tokens from the result array. + /// An array of the tokens. + public static string[] Split( + string s, string delimiters, bool trimTokens, bool ignoreEmptyTokens) { - /// - /// An empty array of instances. - /// - public static readonly string[] EmptyStrings = { }; + return Split(s, delimiters, trimTokens, ignoreEmptyTokens, null); + } - public static readonly IReadOnlyList EmptyStringsList = new List(); - - /// - /// The string that signals the start of an Ant-style expression. - /// - private const string AntExpressionPrefix = "${"; - - /// - /// The string that signals the end of an Ant-style expression. - /// - private const string AntExpressionSuffix = "}"; - - /// - /// Tokenize the given into a - /// array. - /// - /// - ///

- /// If is , returns an empty - /// array. - ///

- ///

- /// If is or the empty - /// , returns a array with one - /// element: itself. - ///

- ///
- /// The to tokenize. - /// - /// The delimiter characters, assembled as a . - /// - /// - /// Trim the tokens via . - /// - /// - /// Omit empty tokens from the result array. - /// An array of the tokens. - public static string[] Split( - string s, string delimiters, bool trimTokens, bool ignoreEmptyTokens) + /// + /// Tokenize the given into a + /// array. + /// + /// + ///

+ /// If is , returns an empty + /// array. + ///

+ ///

+ /// If is or the empty + /// , returns a array with one + /// element: itself. + ///

+ ///
+ /// The to tokenize. + /// + /// The delimiter characters, assembled as a . + /// + /// + /// Trim the tokens via . + /// + /// + /// Omit empty tokens from the result array. + /// + /// + /// Pairs of quote characters. within a pair of quotes are ignored + /// + /// An array of the tokens. + public static string[] Split( + string s, string delimiters, bool trimTokens, bool ignoreEmptyTokens, string quoteChars) + { + if (s == null) { - return Split(s, delimiters, trimTokens, ignoreEmptyTokens, null); + return new string[0]; } - /// - /// Tokenize the given into a - /// array. - /// - /// - ///

- /// If is , returns an empty - /// array. - ///

- ///

- /// If is or the empty - /// , returns a array with one - /// element: itself. - ///

- ///
- /// The to tokenize. - /// - /// The delimiter characters, assembled as a . - /// - /// - /// Trim the tokens via . - /// - /// - /// Omit empty tokens from the result array. - /// - /// - /// Pairs of quote characters. within a pair of quotes are ignored - /// - /// An array of the tokens. - public static string[] Split( - string s, string delimiters, bool trimTokens, bool ignoreEmptyTokens, string quoteChars) + if (string.IsNullOrEmpty(delimiters)) { - if (s == null) - { - return new string[0]; - } - if (string.IsNullOrEmpty(delimiters)) - { - return new[] { s }; - } - if (quoteChars == null) - { - quoteChars = string.Empty; - } - AssertUtils.IsTrue( quoteChars.Length % 2 == 0, "the number of quote characters must be even" ); - - char[] delimiterChars = delimiters.ToCharArray(); - - // scan separator positions - int[] delimiterPositions = new int[s.Length]; - int count = MakeDelimiterPositionList(s, delimiterChars, quoteChars, delimiterPositions); - - List tokens = new List(count+1); - int startIndex = 0; - for (int ixSep = 0; ixSep < count; ixSep++) - { - string token = s.Substring(startIndex, delimiterPositions[ixSep] - startIndex); - if (trimTokens) - { - token = token.Trim(); - } - if (!(ignoreEmptyTokens && token.Length == 0)) - { - tokens.Add(token); - } - startIndex = delimiterPositions[ixSep] + 1; - } - // add remainder - if (startIndex < s.Length) - { - string token = s.Substring(startIndex); - if (trimTokens) - { - token = token.Trim(); - } - if (!(ignoreEmptyTokens && token.Length == 0)) - { - tokens.Add(token); - } - } - else if (startIndex == s.Length) - { - if (!(ignoreEmptyTokens)) - { - tokens.Add(string.Empty); - } - } - - return tokens.ToArray(); + return new[] { s }; } - private static int MakeDelimiterPositionList(string s, char[] delimiters, string quoteChars, int[] delimiterPositions) + if (quoteChars == null) { - int count = 0; - int quoteNestingDepth = 0; - char expectedQuoteOpenChar = '\0'; - char expectedQuoteCloseChar = '\0'; + quoteChars = string.Empty; + } - for (int ixCurChar = 0; ixCurChar < s.Length; ixCurChar++) + AssertUtils.IsTrue(quoteChars.Length % 2 == 0, "the number of quote characters must be even"); + + char[] delimiterChars = delimiters.ToCharArray(); + + // scan separator positions + int[] delimiterPositions = new int[s.Length]; + int count = MakeDelimiterPositionList(s, delimiterChars, quoteChars, delimiterPositions); + + List tokens = new List(count + 1); + int startIndex = 0; + for (int ixSep = 0; ixSep < count; ixSep++) + { + string token = s.Substring(startIndex, delimiterPositions[ixSep] - startIndex); + if (trimTokens) { - char curChar = s[ixCurChar]; + token = token.Trim(); + } - for (int ixCurDelim = 0; ixCurDelim < delimiters.Length; ixCurDelim++) + if (!(ignoreEmptyTokens && token.Length == 0)) + { + tokens.Add(token); + } + + startIndex = delimiterPositions[ixSep] + 1; + } + + // add remainder + if (startIndex < s.Length) + { + string token = s.Substring(startIndex); + if (trimTokens) + { + token = token.Trim(); + } + + if (!(ignoreEmptyTokens && token.Length == 0)) + { + tokens.Add(token); + } + } + else if (startIndex == s.Length) + { + if (!(ignoreEmptyTokens)) + { + tokens.Add(string.Empty); + } + } + + return tokens.ToArray(); + } + + private static int MakeDelimiterPositionList(string s, char[] delimiters, string quoteChars, int[] delimiterPositions) + { + int count = 0; + int quoteNestingDepth = 0; + char expectedQuoteOpenChar = '\0'; + char expectedQuoteCloseChar = '\0'; + + for (int ixCurChar = 0; ixCurChar < s.Length; ixCurChar++) + { + char curChar = s[ixCurChar]; + + for (int ixCurDelim = 0; ixCurDelim < delimiters.Length; ixCurDelim++) + { + if (delimiters[ixCurDelim] == curChar) { - if (delimiters[ixCurDelim] == curChar) - { - if (quoteNestingDepth == 0) - { - delimiterPositions[count] = ixCurChar; - count++; - break; - } - } - if (quoteNestingDepth == 0) { - // check, if we're facing an opening char - for (int ixCurQuoteChar = 0; ixCurQuoteChar < quoteChars.Length; ixCurQuoteChar+=2) - { - if (quoteChars[ixCurQuoteChar] == curChar) - { - quoteNestingDepth++; - expectedQuoteOpenChar = curChar; - expectedQuoteCloseChar = quoteChars[ixCurQuoteChar + 1]; - break; - } - } + delimiterPositions[count] = ixCurChar; + count++; + break; } - else + } + + if (quoteNestingDepth == 0) + { + // check, if we're facing an opening char + for (int ixCurQuoteChar = 0; ixCurQuoteChar < quoteChars.Length; ixCurQuoteChar += 2) { - // check if we're facing an expected open or close char - if (curChar == expectedQuoteOpenChar) + if (quoteChars[ixCurQuoteChar] == curChar) { quoteNestingDepth++; + expectedQuoteOpenChar = curChar; + expectedQuoteCloseChar = quoteChars[ixCurQuoteChar + 1]; + break; } - else if (curChar == expectedQuoteCloseChar) - { - quoteNestingDepth--; - } - } - } - } - return count; - } - - /// - /// Convert a CSV list into an array of s. - /// - /// - /// Values may also be quoted using doublequotes. - /// - /// A CSV list. - /// - /// An array of s, or the empty array - /// if is . - /// - public static string[] CommaDelimitedListToStringArray(string s) - { - return Split(s, ",", false, false, "\"\""); - } - - /// - /// Take a which is a delimited list - /// and convert it to a array. - /// - /// - ///

- /// If the supplied is a - /// or zero-length string, then a single element - /// array composed of the supplied - /// will be - /// eturned. If the supplied - /// is , then an empty, - /// zero-length array will be returned. - ///

- ///
- /// - /// The to be parsed. - /// - /// - /// The delimeter (this will not be returned). Note that only the first - /// character of the supplied is used. - /// - /// - /// An array of the tokens in the list. - /// - public static string[] DelimitedListToStringArray(string input, string delimiter) - { - if (input == null) - { - return new string[0]; - } - if (!HasLength(delimiter)) - { - return new string[] { input }; - } - // return input.Split(delimiter[0]); - return Split(input, delimiter, false, false, null); - } - - /// - /// Convenience method to return an - /// as a delimited - /// (e.g. CSV) . - /// - /// - /// The to parse. - /// - /// - /// The delimiter to use (probably a ','). - /// - /// The delimited string representation. - public static string CollectionToDelimitedString( - IEnumerable c, string delimiter) - { - if (c == null) - { - return "null"; - } - StringBuilder sb = new StringBuilder(); - int i = 0; - foreach (object obj in c) - { - if (i++ > 0) - { - sb.Append(delimiter); - } - sb.Append(obj); - } - return sb.ToString(); - } - - /// - /// Convenience method to return an - /// as a CSV - /// . - /// - /// - /// The to display. - /// - /// The delimited string representation. - public static string CollectionToCommaDelimitedString(IEnumerable collection) - { - return CollectionToDelimitedString(collection, ","); - } - - /// - /// Convenience method to return an array as a CSV - /// . - /// - /// - /// The array to parse. Elements may be of any type ( - /// will be called on each - /// element). - /// - public static string ArrayToCommaDelimitedString(IEnumerable source) - { - return ArrayToDelimitedString(source, ","); - } - - /// - /// Convenience method to return a - /// array as a delimited (e.g. CSV) . - /// - /// - /// The array to parse. Elements may be of any type ( - /// will be called on each - /// element). - /// - /// - /// The delimiter to use (probably a ','). - /// - public static string ArrayToDelimitedString(IEnumerable source, string delimiter) - { - if (source == null) - { - return "null"; - } - - return CollectionToDelimitedString(source, delimiter); - } - - /// Checks if a string has length. - /// - /// The string to check, may be . - /// - /// - /// if the string has length and is not - /// . - /// - /// - /// - /// StringUtils.HasLength(null) = false - /// StringUtils.HasLength("") = false - /// StringUtils.HasLength(" ") = true - /// StringUtils.HasLength("Hello") = true - /// - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool HasLength(string target) - { - return !string.IsNullOrEmpty(target); - } - - /// - /// Checks if a has text. - /// - /// - ///

- /// More specifically, returns if the string is - /// not , it's is > - /// zero (0), and it has at least one non-whitespace character. - ///

- ///
- /// - /// The string to check, may be . - /// - /// - /// if the is not - /// , - /// > zero (0), and does not consist - /// solely of whitespace. - /// - /// - /// - /// StringUtils.HasText(null) = false - /// StringUtils.HasText("") = false - /// StringUtils.HasText(" ") = false - /// StringUtils.HasText("12345") = true - /// StringUtils.HasText(" 12345 ") = true - /// - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool HasText(string target) - { - return !string.IsNullOrWhiteSpace(target); - } - - /// - /// Checks if a is - /// or an empty string. - /// - /// - ///

- /// More specifically, returns if the string is - /// , it's is equal - /// to zero (0), or it is composed entirely of whitespace - /// characters. - ///

- ///
- /// - /// The string to check, may (obviously) be . - /// - /// - /// if the is - /// , has a length equal to zero (0), or - /// is composed entirely of whitespace characters. - /// - /// - /// - /// StringUtils.IsNullOrEmpty(null) = true - /// StringUtils.IsNullOrEmpty("") = true - /// StringUtils.IsNullOrEmpty(" ") = true - /// StringUtils.IsNullOrEmpty("12345") = false - /// StringUtils.IsNullOrEmpty(" 12345 ") = false - /// - /// - public static bool IsNullOrEmpty(string target) - { - return !HasText(target); - } - - /// - /// Returns , if it contains non-whitespaces. null otherwise. - /// - public static string GetTextOrNull(string value) - { - if (!HasText(value)) - { - return null; - } - return value; - } - - /// - /// Strips first and last character off the string. - /// - /// The string to strip. - /// The stripped string. - public static string StripFirstAndLastCharacter(string text) - { - if (text != null - && text.Length > 2) - { - return text.Substring(1, text.Length - 2); - } - else - { - return String.Empty; - } - } - - /// - /// Returns a list of Ant-style expressions from the specified text. - /// - /// The text to inspect. - /// - /// A list of expressions that exist in the specified text. - /// - /// - /// If any of the expressions in the supplied - /// is empty (${}). - /// - public static IList GetAntExpressions(string text) - { - List expressions = new List(); - if (StringUtils.HasText(text)) - { - int start = text.IndexOf(AntExpressionPrefix); - while (start >= 0) - { - int end = text.IndexOf(AntExpressionSuffix, start + 2); - if (end == -1) - { - // terminator character not found, so let's quit... - start = -1; - } - else - { - string exp = text.Substring(start + 2, end - start - 2); - if (StringUtils.IsNullOrEmpty(exp)) - { - throw new FormatException( - string.Format("Empty {0}{1} value found in text : '{2}'.", - AntExpressionPrefix, - AntExpressionSuffix, - text)); - } - if (expressions.IndexOf(exp) < 0) - { - expressions.Add(exp); - } - start = text.IndexOf(AntExpressionPrefix, end); - } - } - } - return expressions; - } - - /// - /// Replaces Ant-style expression placeholder with expression value. - /// - /// - ///

- /// - ///

- ///
- /// The string to set the value in. - /// The name of the expression to set. - /// The expression value. - /// - /// A new string with the expression value set; the - /// value if the supplied - /// is , has a length - /// equal to zero (0), or is composed entirely of whitespace - /// characters. - /// - public static string SetAntExpression(string text, string expression, object expValue) - { - if (StringUtils.IsNullOrEmpty(text)) - { - return String.Empty; - } - if (expValue == null) - { - expValue = String.Empty; - } - return text.Replace( - StringUtils.Surround(AntExpressionPrefix, expression, AntExpressionSuffix), expValue.ToString()); - } - - /// - /// Surrounds (prepends and appends) the string value of the supplied - /// to the supplied . - /// - /// - ///

- /// The return value of this method call is always guaranteed to be non - /// . If every value passed as a parameter to this method is - /// , the string will be returned. - ///

- ///
- /// - /// The prefix and suffix that respectively will be prepended and - /// appended to the target . If this value - /// is not a value, it's attendant - /// value will be used. - /// - /// - /// The target that is to be surrounded. If this value is not a - /// value, it's attendant - /// value will be used. - /// - /// The surrounded string. - public static string Surround(object fix, object target) - { - return StringUtils.Surround(fix, target, fix); - } - - /// - /// Surrounds (prepends and appends) the string values of the supplied - /// and to the supplied - /// . - /// - /// - ///

- /// The return value of this method call is always guaranteed to be non - /// . If every value passed as a parameter to this method is - /// , the string will be returned. - ///

- ///
- /// - /// The value that will be prepended to the . If this value - /// is not a value, it's attendant - /// value will be used. - /// - /// - /// The target that is to be surrounded. If this value is not a - /// value, it's attendant - /// value will be used. - /// - /// - /// The value that will be appended to the . If this value - /// is not a value, it's attendant - /// value will be used. - /// - /// The surrounded string. - public static string Surround(object prefix, object target, object suffix) - { - return string.Format( - CultureInfo.InvariantCulture, "{0}{1}{2}", prefix, target, suffix); - } - - /// - /// Converts escaped characters (for example "\t") within a string - /// to their real character. - /// - /// The string to convert. - /// The converted string. - public static string ConvertEscapedCharacters(string inputString) - { - if (inputString == null) return null; - StringBuilder sb = new StringBuilder(inputString.Length); - for (int i = 0; i < inputString.Length; i++) - { - if (inputString[i].Equals('\\')) - { - i++; - if (inputString[i].Equals('t')) - { - sb.Append('\t'); - } - else if (inputString[i].Equals('r')) - { - sb.Append('\r'); - } - else if (inputString[i].Equals('n')) - { - sb.Append('\n'); - } - else if (inputString[i].Equals('\\')) - { - sb.Append('\\'); - } - else - { - sb.Append("\\" + inputString[i]); } } else { - sb.Append(inputString[i]); + // check if we're facing an expected open or close char + if (curChar == expectedQuoteOpenChar) + { + quoteNestingDepth++; + } + else if (curChar == expectedQuoteCloseChar) + { + quoteNestingDepth--; + } } } - return sb.ToString(); + } + + return count; + } + + /// + /// Convert a CSV list into an array of s. + /// + /// + /// Values may also be quoted using doublequotes. + /// + /// A CSV list. + /// + /// An array of s, or the empty array + /// if is . + /// + public static string[] CommaDelimitedListToStringArray(string s) + { + return Split(s, ",", false, false, "\"\""); + } + + /// + /// Take a which is a delimited list + /// and convert it to a array. + /// + /// + ///

+ /// If the supplied is a + /// or zero-length string, then a single element + /// array composed of the supplied + /// will be + /// eturned. If the supplied + /// is , then an empty, + /// zero-length array will be returned. + ///

+ ///
+ /// + /// The to be parsed. + /// + /// + /// The delimeter (this will not be returned). Note that only the first + /// character of the supplied is used. + /// + /// + /// An array of the tokens in the list. + /// + public static string[] DelimitedListToStringArray(string input, string delimiter) + { + if (input == null) + { + return new string[0]; + } + + if (!HasLength(delimiter)) + { + return new string[] { input }; + } + + // return input.Split(delimiter[0]); + return Split(input, delimiter, false, false, null); + } + + /// + /// Convenience method to return an + /// as a delimited + /// (e.g. CSV) . + /// + /// + /// The to parse. + /// + /// + /// The delimiter to use (probably a ','). + /// + /// The delimited string representation. + public static string CollectionToDelimitedString( + IEnumerable c, string delimiter) + { + if (c == null) + { + return "null"; + } + + StringBuilder sb = new StringBuilder(); + int i = 0; + foreach (object obj in c) + { + if (i++ > 0) + { + sb.Append(delimiter); + } + + sb.Append(obj); + } + + return sb.ToString(); + } + + /// + /// Convenience method to return an + /// as a CSV + /// . + /// + /// + /// The to display. + /// + /// The delimited string representation. + public static string CollectionToCommaDelimitedString(IEnumerable collection) + { + return CollectionToDelimitedString(collection, ","); + } + + /// + /// Convenience method to return an array as a CSV + /// . + /// + /// + /// The array to parse. Elements may be of any type ( + /// will be called on each + /// element). + /// + public static string ArrayToCommaDelimitedString(IEnumerable source) + { + return ArrayToDelimitedString(source, ","); + } + + /// + /// Convenience method to return a + /// array as a delimited (e.g. CSV) . + /// + /// + /// The array to parse. Elements may be of any type ( + /// will be called on each + /// element). + /// + /// + /// The delimiter to use (probably a ','). + /// + public static string ArrayToDelimitedString(IEnumerable source, string delimiter) + { + if (source == null) + { + return "null"; + } + + return CollectionToDelimitedString(source, delimiter); + } + + /// Checks if a string has length. + /// + /// The string to check, may be . + /// + /// + /// if the string has length and is not + /// . + /// + /// + /// + /// StringUtils.HasLength(null) = false + /// StringUtils.HasLength("") = false + /// StringUtils.HasLength(" ") = true + /// StringUtils.HasLength("Hello") = true + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool HasLength(string target) + { + return !string.IsNullOrEmpty(target); + } + + /// + /// Checks if a has text. + /// + /// + ///

+ /// More specifically, returns if the string is + /// not , it's is > + /// zero (0), and it has at least one non-whitespace character. + ///

+ ///
+ /// + /// The string to check, may be . + /// + /// + /// if the is not + /// , + /// > zero (0), and does not consist + /// solely of whitespace. + /// + /// + /// + /// StringUtils.HasText(null) = false + /// StringUtils.HasText("") = false + /// StringUtils.HasText(" ") = false + /// StringUtils.HasText("12345") = true + /// StringUtils.HasText(" 12345 ") = true + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool HasText(string target) + { + return !string.IsNullOrWhiteSpace(target); + } + + /// + /// Checks if a is + /// or an empty string. + /// + /// + ///

+ /// More specifically, returns if the string is + /// , it's is equal + /// to zero (0), or it is composed entirely of whitespace + /// characters. + ///

+ ///
+ /// + /// The string to check, may (obviously) be . + /// + /// + /// if the is + /// , has a length equal to zero (0), or + /// is composed entirely of whitespace characters. + /// + /// + /// + /// StringUtils.IsNullOrEmpty(null) = true + /// StringUtils.IsNullOrEmpty("") = true + /// StringUtils.IsNullOrEmpty(" ") = true + /// StringUtils.IsNullOrEmpty("12345") = false + /// StringUtils.IsNullOrEmpty(" 12345 ") = false + /// + /// + public static bool IsNullOrEmpty(string target) + { + return !HasText(target); + } + + /// + /// Returns , if it contains non-whitespaces. null otherwise. + /// + public static string GetTextOrNull(string value) + { + if (!HasText(value)) + { + return null; + } + + return value; + } + + /// + /// Strips first and last character off the string. + /// + /// The string to strip. + /// The stripped string. + public static string StripFirstAndLastCharacter(string text) + { + if (text != null + && text.Length > 2) + { + return text.Substring(1, text.Length - 2); + } + else + { + return String.Empty; } } + + /// + /// Returns a list of Ant-style expressions from the specified text. + /// + /// The text to inspect. + /// + /// A list of expressions that exist in the specified text. + /// + /// + /// If any of the expressions in the supplied + /// is empty (${}). + /// + public static IList GetAntExpressions(string text) + { + List expressions = new List(); + if (StringUtils.HasText(text)) + { + int start = text.IndexOf(AntExpressionPrefix); + while (start >= 0) + { + int end = text.IndexOf(AntExpressionSuffix, start + 2); + if (end == -1) + { + // terminator character not found, so let's quit... + start = -1; + } + else + { + string exp = text.Substring(start + 2, end - start - 2); + if (StringUtils.IsNullOrEmpty(exp)) + { + throw new FormatException( + string.Format("Empty {0}{1} value found in text : '{2}'.", + AntExpressionPrefix, + AntExpressionSuffix, + text)); + } + + if (expressions.IndexOf(exp) < 0) + { + expressions.Add(exp); + } + + start = text.IndexOf(AntExpressionPrefix, end); + } + } + } + + return expressions; + } + + /// + /// Replaces Ant-style expression placeholder with expression value. + /// + /// + ///

+ /// + ///

+ ///
+ /// The string to set the value in. + /// The name of the expression to set. + /// The expression value. + /// + /// A new string with the expression value set; the + /// value if the supplied + /// is , has a length + /// equal to zero (0), or is composed entirely of whitespace + /// characters. + /// + public static string SetAntExpression(string text, string expression, object expValue) + { + if (StringUtils.IsNullOrEmpty(text)) + { + return String.Empty; + } + + if (expValue == null) + { + expValue = String.Empty; + } + + return text.Replace( + StringUtils.Surround(AntExpressionPrefix, expression, AntExpressionSuffix), expValue.ToString()); + } + + /// + /// Surrounds (prepends and appends) the string value of the supplied + /// to the supplied . + /// + /// + ///

+ /// The return value of this method call is always guaranteed to be non + /// . If every value passed as a parameter to this method is + /// , the string will be returned. + ///

+ ///
+ /// + /// The prefix and suffix that respectively will be prepended and + /// appended to the target . If this value + /// is not a value, it's attendant + /// value will be used. + /// + /// + /// The target that is to be surrounded. If this value is not a + /// value, it's attendant + /// value will be used. + /// + /// The surrounded string. + public static string Surround(object fix, object target) + { + return StringUtils.Surround(fix, target, fix); + } + + /// + /// Surrounds (prepends and appends) the string values of the supplied + /// and to the supplied + /// . + /// + /// + ///

+ /// The return value of this method call is always guaranteed to be non + /// . If every value passed as a parameter to this method is + /// , the string will be returned. + ///

+ ///
+ /// + /// The value that will be prepended to the . If this value + /// is not a value, it's attendant + /// value will be used. + /// + /// + /// The target that is to be surrounded. If this value is not a + /// value, it's attendant + /// value will be used. + /// + /// + /// The value that will be appended to the . If this value + /// is not a value, it's attendant + /// value will be used. + /// + /// The surrounded string. + public static string Surround(object prefix, object target, object suffix) + { + return string.Format( + CultureInfo.InvariantCulture, "{0}{1}{2}", prefix, target, suffix); + } + + /// + /// Converts escaped characters (for example "\t") within a string + /// to their real character. + /// + /// The string to convert. + /// The converted string. + public static string ConvertEscapedCharacters(string inputString) + { + if (inputString == null) return null; + StringBuilder sb = new StringBuilder(inputString.Length); + for (int i = 0; i < inputString.Length; i++) + { + if (inputString[i].Equals('\\')) + { + i++; + if (inputString[i].Equals('t')) + { + sb.Append('\t'); + } + else if (inputString[i].Equals('r')) + { + sb.Append('\r'); + } + else if (inputString[i].Equals('n')) + { + sb.Append('\n'); + } + else if (inputString[i].Equals('\\')) + { + sb.Append('\\'); + } + else + { + sb.Append("\\" + inputString[i]); + } + } + else + { + sb.Append(inputString[i]); + } + } + + return sb.ToString(); + } } diff --git a/src/Spring/Spring.Core/Util/SystemUtils.cs b/src/Spring/Spring.Core/Util/SystemUtils.cs index 01aab3ee..15fc1574 100644 --- a/src/Spring/Spring.Core/Util/SystemUtils.cs +++ b/src/Spring/Spring.Core/Util/SystemUtils.cs @@ -25,91 +25,90 @@ using System.Threading; #endregion -namespace Spring.Util +namespace Spring.Util; + +/// +/// Utility class containing miscellaneous system-level functionality. +/// +/// Aleksandar Seovic +public sealed class SystemUtils { - /// - /// Utility class containing miscellaneous system-level functionality. - /// - /// Aleksandar Seovic - public sealed class SystemUtils + private static bool assemblyResolverRegistered = false; + private static readonly object assemblyResolverLock; + + private static readonly bool isMono; + + static SystemUtils() { - private static bool assemblyResolverRegistered = false; - private static readonly object assemblyResolverLock; + isMono = Type.GetType("Mono.Runtime") != null; + assemblyResolverLock = new object(); + } - private static readonly bool isMono; - - static SystemUtils() + /// + /// Registers assembly resolver that iterates over the + /// assemblies loaded into the current + /// in order to find an assembly that cannot be resolved. + /// + /// + /// This method has to be called if you need to serialize dynamically + /// generated types in transient assemblies, such as Spring AOP proxies, + /// because standard .NET serialization engine always tries to load + /// assembly from the disk. + /// + public static void RegisterLoadedAssemblyResolver() + { + if (!assemblyResolverRegistered) { - isMono = Type.GetType("Mono.Runtime") != null; - assemblyResolverLock = new object(); - } - - /// - /// Registers assembly resolver that iterates over the - /// assemblies loaded into the current - /// in order to find an assembly that cannot be resolved. - /// - /// - /// This method has to be called if you need to serialize dynamically - /// generated types in transient assemblies, such as Spring AOP proxies, - /// because standard .NET serialization engine always tries to load - /// assembly from the disk. - /// - public static void RegisterLoadedAssemblyResolver() - { - if (!assemblyResolverRegistered) + lock (assemblyResolverLock) { - lock (assemblyResolverLock) - { - AppDomain.CurrentDomain.AssemblyResolve += LoadedAssemblyResolver; - assemblyResolverRegistered = true; - } - } - } - - private static Assembly LoadedAssemblyResolver(object sender, ResolveEventArgs args) - { - Assembly[] loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies(); - foreach (Assembly assembly in loadedAssemblies) - { - if (assembly.FullName == args.Name) - { - return assembly; - } - } - return null; - } - - - /// - /// Returns true if running on Mono - /// - /// Tests for the presence of the type Mono.Runtime - public static bool MonoRuntime - { - get { return isMono; } - } - - /// - /// Gets the thread id for the current thread. Use thread name is available, - /// otherwise use CurrentThread.GetHashCode() for .NET 1.0/1.1 and - /// CurrentThread.ManagedThreadId otherwise. - /// - /// The thread id. - public static string ThreadId - { - get - { - string name = Thread.CurrentThread.Name; - if (StringUtils.HasText(name)) - { - return name; - } - else - { - return Thread.CurrentThread.ManagedThreadId.ToString(); - } + AppDomain.CurrentDomain.AssemblyResolve += LoadedAssemblyResolver; + assemblyResolverRegistered = true; } } } -} + + private static Assembly LoadedAssemblyResolver(object sender, ResolveEventArgs args) + { + Assembly[] loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies(); + foreach (Assembly assembly in loadedAssemblies) + { + if (assembly.FullName == args.Name) + { + return assembly; + } + } + + return null; + } + + /// + /// Returns true if running on Mono + /// + /// Tests for the presence of the type Mono.Runtime + public static bool MonoRuntime + { + get { return isMono; } + } + + /// + /// Gets the thread id for the current thread. Use thread name is available, + /// otherwise use CurrentThread.GetHashCode() for .NET 1.0/1.1 and + /// CurrentThread.ManagedThreadId otherwise. + /// + /// The thread id. + public static string ThreadId + { + get + { + string name = Thread.CurrentThread.Name; + if (StringUtils.HasText(name)) + { + return name; + } + else + { + return Thread.CurrentThread.ManagedThreadId.ToString(); + } + } + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Util/TextPositionInfo.cs b/src/Spring/Spring.Core/Util/TextPositionInfo.cs index 1089ff00..df2f8abe 100644 --- a/src/Spring/Spring.Core/Util/TextPositionInfo.cs +++ b/src/Spring/Spring.Core/Util/TextPositionInfo.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -22,64 +22,63 @@ #endregion -namespace Spring.Util +namespace Spring.Util; + +/// +/// Holds text position information for e.g. error reporting purposes. +/// +/// +/// +public class TextPositionInfo : ITextPosition { + private readonly string _filename; + private readonly int _lineNumber; + private readonly int _linePosition; + /// - /// Holds text position information for e.g. error reporting purposes. + /// Creates a new TextPositionInfo instance. /// - /// - /// - public class TextPositionInfo : ITextPosition + public TextPositionInfo(string filename, int lineNumber, int linePosition) { - private readonly string _filename; - private readonly int _lineNumber; - private readonly int _linePosition; + _filename = filename; + _lineNumber = lineNumber; + _linePosition = linePosition; + } - /// - /// Creates a new TextPositionInfo instance. - /// - public TextPositionInfo(string filename, int lineNumber, int linePosition) + /// + /// Creates a new TextPositionInfo instance, copying values from another instance. + /// + public TextPositionInfo(ITextPosition other) + { + if (other != null) { - _filename = filename; - _lineNumber = lineNumber; - _linePosition = linePosition; - } - - /// - /// Creates a new TextPositionInfo instance, copying values from another instance. - /// - public TextPositionInfo(ITextPosition other) - { - if (other != null) - { - this._filename = other.Filename; - this._lineNumber = other.LineNumber; - this._linePosition = other.LinePosition; - } - } - - /// - /// The filename related to this text position - /// - public string Filename - { - get { return _filename; } - } - - /// - /// The line number related to this text position - /// - public int LineNumber - { - get { return _lineNumber; } - } - - /// - /// The line position related to this text position - /// - public int LinePosition - { - get { return _linePosition; } + this._filename = other.Filename; + this._lineNumber = other.LineNumber; + this._linePosition = other.LinePosition; } } -} \ No newline at end of file + + /// + /// The filename related to this text position + /// + public string Filename + { + get { return _filename; } + } + + /// + /// The line number related to this text position + /// + public int LineNumber + { + get { return _lineNumber; } + } + + /// + /// The line position related to this text position + /// + public int LinePosition + { + get { return _linePosition; } + } +} diff --git a/src/Spring/Spring.Core/Util/TypeExtensions.cs b/src/Spring/Spring.Core/Util/TypeExtensions.cs index f33f12c2..a2ff741f 100644 --- a/src/Spring/Spring.Core/Util/TypeExtensions.cs +++ b/src/Spring/Spring.Core/Util/TypeExtensions.cs @@ -1,10 +1,9 @@ using System.Reflection; -namespace Spring.Util +namespace Spring.Util; + +internal static class TypeExtensions { - internal static class TypeExtensions - { - internal static string AssemblyQualifiedNameWithoutVersion(this Type type) - => type.FullName + ", " + type.GetTypeInfo().Assembly.GetName().Name; - } + internal static string AssemblyQualifiedNameWithoutVersion(this Type type) + => type.FullName + ", " + type.GetTypeInfo().Assembly.GetName().Name; } diff --git a/src/Spring/Spring.Core/Util/UniqueKey.cs b/src/Spring/Spring.Core/Util/UniqueKey.cs index 334d67e7..a91e0996 100644 --- a/src/Spring/Spring.Core/Util/UniqueKey.cs +++ b/src/Spring/Spring.Core/Util/UniqueKey.cs @@ -27,145 +27,146 @@ using Spring.Core.TypeConversion; #endregion -namespace Spring.Util +namespace Spring.Util; + +/// +/// UniqueKey allows for generating keys unique to a type or particular instance and a partial name, +/// that can e.g. be used as keys in . +/// +/// +/// // shows usage type-scoped keys +/// UniqueKey classAKey = UniqueKey.GetTypeScoped(typeof(ClassA), "myKey"); +/// UniqueKey classBKey = UniqueKey.GetTypeScoped(typeof(ClassB), "myKey"); +/// +/// HttpContext.Current.Items.Add( classAKey, "some value unqiue for class A having key 'myKey'"); +/// object value = HttpContext.Current.Items[ UniqueKey.GetTypeScoped(typeof(ClassA), "myKey") ]; +/// Assert.AreEqual( "some value unique for class A having key 'myKey'", value); +/// +/// HttpContext.Current.Items.Add( classBKey, "some value unqiue for class B having key 'myKey'"); +/// object value = HttpContext.Current.Items[ UniqueKey.GetTypeScoped(typeof(ClassB), "myKey") ]; +/// Assert.AreEqual( "some value unique for class B having key 'myKey'", value); +/// +[Serializable] +[TypeConverter(typeof(UniqueKeyConverter))] +public sealed class UniqueKey : IEquatable { - /// - /// UniqueKey allows for generating keys unique to a type or particular instance and a partial name, - /// that can e.g. be used as keys in . - /// - /// - /// // shows usage type-scoped keys - /// UniqueKey classAKey = UniqueKey.GetTypeScoped(typeof(ClassA), "myKey"); - /// UniqueKey classBKey = UniqueKey.GetTypeScoped(typeof(ClassB), "myKey"); - /// - /// HttpContext.Current.Items.Add( classAKey, "some value unqiue for class A having key 'myKey'"); - /// object value = HttpContext.Current.Items[ UniqueKey.GetTypeScoped(typeof(ClassA), "myKey") ]; - /// Assert.AreEqual( "some value unique for class A having key 'myKey'", value); - /// - /// HttpContext.Current.Items.Add( classBKey, "some value unqiue for class B having key 'myKey'"); - /// object value = HttpContext.Current.Items[ UniqueKey.GetTypeScoped(typeof(ClassB), "myKey") ]; - /// Assert.AreEqual( "some value unique for class B having key 'myKey'", value); - /// - [Serializable] - [TypeConverter(typeof(UniqueKeyConverter))] - public sealed class UniqueKey : IEquatable + private readonly string _generatedKey; + + /// + /// Initialize a new instance of from its string representation. + /// See and See for details. + /// + /// The string representation of the new instance. + internal UniqueKey(string key) { - private readonly string _generatedKey; - - /// - /// Initialize a new instance of from its string representation. - /// See and See for details. - /// - /// The string representation of the new instance. - internal UniqueKey(string key) - { - AssertUtils.ArgumentNotNull(key, "key"); - _generatedKey = key; - } - - /// - /// Compares this instance to another. - /// - public bool Equals(UniqueKey uniqueKey) - { - if (uniqueKey == null) return false; - return Equals(_generatedKey, uniqueKey._generatedKey); - } - - /// - /// Compares this instance to another. - /// - public override bool Equals(object obj) - { - if (ReferenceEquals(this, obj)) return true; - return Equals(obj as UniqueKey); - } - - /// - /// Returns the hash code for this key. - /// - /// - public override int GetHashCode() - { - return _generatedKey.GetHashCode(); - } - - /// - /// Returns a string representation of this key. - /// - public override string ToString() - { - return _generatedKey; - } - - /// - /// Creates a new key instance unique to the given instance. - /// - /// The instance the key shall be unique to - /// The partial key to be made unique - /// - /// - /// If is of type - public static UniqueKey GetInstanceScoped(object instance, string partialKey) - { - if (instance is Type) - { - throw new ArgumentException( - "please use GetTypeScoped(Type,string) for creating type specific keys", "instance"); - } - return new UniqueKey(GetInstanceScopedString(instance, partialKey)); - } - - /// - /// Creates a new key instance unique to the given type. - /// - /// The type the key shall be unique to - /// The partial key to be made unique - public static UniqueKey GetTypeScoped(Type type, string partialKey) - { - return new UniqueKey(GetTypeScopedString(type, partialKey)); - } - - /// - /// Returns a key unique for the given instance. - /// - /// The instance the key shall be unique to - /// The partial key to be made unique - /// A key formatted as typename[instance-id].partialkey - public static string GetInstanceScopedString(object instance, string partialKey) - { - AssertUtils.ArgumentNotNull(instance, "instance"); - AssertUtils.ArgumentHasText(partialKey, "partialKey"); - - if (instance is Type) - { - throw new ArgumentException( - "please use GetUniqueKey(Type,string) for creating type specific keys", "instance"); - } - return GetUniqueKey(instance.GetType(), instance, partialKey); - } - - /// - /// Returns a key unique for the given type. - /// - /// The type the key shall be unique to - /// The partial key to be made unique - /// A key formatted as typename.partialkey - public static string GetTypeScopedString(Type type, string partialKey) - { - AssertUtils.ArgumentNotNull(type, "type"); - AssertUtils.ArgumentHasText(partialKey, "partialKey"); - - return GetUniqueKey(type, null, partialKey); - } - - private static string GetUniqueKey(Type type, object instance, string partialKey) - { - StringBuilder sb = new StringBuilder(); - sb.Append(type.FullName); - if (instance != null) sb.Append('[').Append(instance.GetHashCode()).Append(']'); - sb.Append('.').Append(partialKey); - return sb.ToString(); - } + AssertUtils.ArgumentNotNull(key, "key"); + _generatedKey = key; } -} + + /// + /// Compares this instance to another. + /// + public bool Equals(UniqueKey uniqueKey) + { + if (uniqueKey == null) return false; + return Equals(_generatedKey, uniqueKey._generatedKey); + } + + /// + /// Compares this instance to another. + /// + public override bool Equals(object obj) + { + if (ReferenceEquals(this, obj)) return true; + return Equals(obj as UniqueKey); + } + + /// + /// Returns the hash code for this key. + /// + /// + public override int GetHashCode() + { + return _generatedKey.GetHashCode(); + } + + /// + /// Returns a string representation of this key. + /// + public override string ToString() + { + return _generatedKey; + } + + /// + /// Creates a new key instance unique to the given instance. + /// + /// The instance the key shall be unique to + /// The partial key to be made unique + /// + /// + /// If is of type + public static UniqueKey GetInstanceScoped(object instance, string partialKey) + { + if (instance is Type) + { + throw new ArgumentException( + "please use GetTypeScoped(Type,string) for creating type specific keys", "instance"); + } + + return new UniqueKey(GetInstanceScopedString(instance, partialKey)); + } + + /// + /// Creates a new key instance unique to the given type. + /// + /// The type the key shall be unique to + /// The partial key to be made unique + public static UniqueKey GetTypeScoped(Type type, string partialKey) + { + return new UniqueKey(GetTypeScopedString(type, partialKey)); + } + + /// + /// Returns a key unique for the given instance. + /// + /// The instance the key shall be unique to + /// The partial key to be made unique + /// A key formatted as typename[instance-id].partialkey + public static string GetInstanceScopedString(object instance, string partialKey) + { + AssertUtils.ArgumentNotNull(instance, "instance"); + AssertUtils.ArgumentHasText(partialKey, "partialKey"); + + if (instance is Type) + { + throw new ArgumentException( + "please use GetUniqueKey(Type,string) for creating type specific keys", "instance"); + } + + return GetUniqueKey(instance.GetType(), instance, partialKey); + } + + /// + /// Returns a key unique for the given type. + /// + /// The type the key shall be unique to + /// The partial key to be made unique + /// A key formatted as typename.partialkey + public static string GetTypeScopedString(Type type, string partialKey) + { + AssertUtils.ArgumentNotNull(type, "type"); + AssertUtils.ArgumentHasText(partialKey, "partialKey"); + + return GetUniqueKey(type, null, partialKey); + } + + private static string GetUniqueKey(Type type, object instance, string partialKey) + { + StringBuilder sb = new StringBuilder(); + sb.Append(type.FullName); + if (instance != null) sb.Append('[').Append(instance.GetHashCode()).Append(']'); + sb.Append('.').Append(partialKey); + return sb.ToString(); + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Util/XmlUtils.cs b/src/Spring/Spring.Core/Util/XmlUtils.cs index 7bf48a93..8e9e372d 100644 --- a/src/Spring/Spring.Core/Util/XmlUtils.cs +++ b/src/Spring/Spring.Core/Util/XmlUtils.cs @@ -25,73 +25,72 @@ using System.Xml.Schema; #endregion -namespace Spring.Util +namespace Spring.Util; + +/// +/// XML utility methods. +/// +/// Aleksandar Seovic +public class XmlUtils { /// - /// XML utility methods. + /// Gets an appropriate implementation + /// for the supplied . /// - /// Aleksandar Seovic - public class XmlUtils + /// The XML that is going to be read. + /// XML schemas that should be used for validation. + /// Validation event handler. + /// + /// A validating implementation. + /// + public static XmlReader CreateValidatingReader(Stream stream, XmlSchemaSet schemas, ValidationEventHandler eventHandler) { - /// - /// Gets an appropriate implementation - /// for the supplied . - /// - /// The XML that is going to be read. - /// XML schemas that should be used for validation. - /// Validation event handler. - /// - /// A validating implementation. - /// - public static XmlReader CreateValidatingReader(Stream stream, XmlSchemaSet schemas, ValidationEventHandler eventHandler) - { - return CreateValidatingReader(stream, new XmlUrlResolver(), schemas, eventHandler); - } + return CreateValidatingReader(stream, new XmlUrlResolver(), schemas, eventHandler); + } - /// - /// Gets an appropriate implementation - /// for the supplied . - /// - /// The XML that is going to be read. - /// to be used for resolving external references - /// XML schemas that should be used for validation. - /// Validation event handler. - /// - /// A validating implementation. - /// - public static XmlReader CreateValidatingReader(Stream stream, XmlResolver xmlResolver, XmlSchemaSet schemas, ValidationEventHandler eventHandler) + /// + /// Gets an appropriate implementation + /// for the supplied . + /// + /// The XML that is going to be read. + /// to be used for resolving external references + /// XML schemas that should be used for validation. + /// Validation event handler. + /// + /// A validating implementation. + /// + public static XmlReader CreateValidatingReader(Stream stream, XmlResolver xmlResolver, XmlSchemaSet schemas, ValidationEventHandler eventHandler) + { + lock (typeof(XmlUtils)) { - lock (typeof(XmlUtils)) + if (!schemas.IsCompiled) { - if (!schemas.IsCompiled) - { - schemas.Compile(); - } - - XmlReaderSettings settings = new XmlReaderSettings(); - settings.Schemas.XmlResolver = xmlResolver; - settings.Schemas.Add(schemas); - settings.ValidationType = ValidationType.Schema; - if (eventHandler != null) - { - settings.ValidationEventHandler += eventHandler; - } - - return XmlReader.Create(stream, settings); + schemas.Compile(); } - } - /// - /// Gets an appropriate implementation - /// for the supplied . - /// - /// The XML that is going to be read. - /// - /// A non-validating implementation. - /// - public static XmlReader CreateReader(Stream stream) - { - return XmlReader.Create(stream); + XmlReaderSettings settings = new XmlReaderSettings(); + settings.Schemas.XmlResolver = xmlResolver; + settings.Schemas.Add(schemas); + settings.ValidationType = ValidationType.Schema; + if (eventHandler != null) + { + settings.ValidationEventHandler += eventHandler; + } + + return XmlReader.Create(stream, settings); } } + + /// + /// Gets an appropriate implementation + /// for the supplied . + /// + /// The XML that is going to be read. + /// + /// A non-validating implementation. + /// + public static XmlReader CreateReader(Stream stream) + { + return XmlReader.Create(stream); + } } diff --git a/src/Spring/Spring.Core/Validation/Actions/ErrorMessageAction.cs b/src/Spring/Spring.Core/Validation/Actions/ErrorMessageAction.cs index fb0d0daf..870aabbe 100644 --- a/src/Spring/Spring.Core/Validation/Actions/ErrorMessageAction.cs +++ b/src/Spring/Spring.Core/Validation/Actions/ErrorMessageAction.cs @@ -22,97 +22,94 @@ using System.Collections; using Spring.Expressions; using Spring.Util; -namespace Spring.Validation.Actions +namespace Spring.Validation.Actions; + +/// +/// Implementation of that adds error message +/// to the validation errors container. +/// +/// Aleksandar Seovic +public class ErrorMessageAction : BaseValidationAction { + private string messageId; + private IExpression[] messageParams; + private string[] providers; + /// - /// Implementation of that adds error message - /// to the validation errors container. + /// Initializes a new instance of the class. /// - /// Aleksandar Seovic - public class ErrorMessageAction : BaseValidationAction + /// Error message resource identifier. + /// Names of the error providers this message should be added to. + public ErrorMessageAction(string messageId, params string[] providers) { - private string messageId; - private IExpression[] messageParams; - private string[] providers; - - /// - /// Initializes a new instance of the class. - /// - /// Error message resource identifier. - /// Names of the error providers this message should be added to. - public ErrorMessageAction(string messageId, params string[] providers) + AssertUtils.ArgumentHasText(messageId, "messageId"); + if (providers == null || providers.Length == 0) { - AssertUtils.ArgumentHasText(messageId, "messageId"); - if (providers == null || providers.Length == 0) - { - throw new ArgumentException("At least one error provider has to be specified.", "providers"); - } - - this.messageId = messageId; - this.providers = providers; + throw new ArgumentException("At least one error provider has to be specified.", "providers"); } - /// - /// Sets the expressions that should be resolved to error message parameters. - /// - /// The expressions that should be resolved to error message parameters. - public IExpression[] Parameters + this.messageId = messageId; + this.providers = providers; + } + + /// + /// Sets the expressions that should be resolved to error message parameters. + /// + /// The expressions that should be resolved to error message parameters. + public IExpression[] Parameters + { + set { messageParams = value; } + } + + /// + /// Called when associated validator is invalid. + /// + /// Validation context. + /// Additional context parameters. + /// Validation errors container. + protected override void OnInvalid(object validationContext, IDictionary contextParams, IValidationErrors errors) + { + ErrorMessage error = CreateErrorMessage(validationContext, contextParams); + foreach (string provider in this.providers) { - set { messageParams = value; } + errors.AddError(provider.Trim(), error); + } + } + + /// + /// Resolves the error message. + /// + /// Validation context to resolve message parameters against. + /// Additional context parameters. + /// Resolved error message + private ErrorMessage CreateErrorMessage(object validationContext, IDictionary contextParams) + { + if (messageParams != null && messageParams.Length > 0) + { + object[] parameters = ResolveMessageParameters(messageParams, validationContext, contextParams); + return new ErrorMessage(messageId, parameters); + } + else + { + return new ErrorMessage(messageId, null); + } + } + + /// + /// Resolves the message parameters. + /// + /// List of parameters to resolve. + /// Validation context to resolve parameters against. + /// Additional context parameters. + /// Resolved message parameters. + private object[] ResolveMessageParameters(IList messageParams, object validationContext, IDictionary contextParams) + { + object[] parameters = new object[messageParams.Count]; + for (int i = 0; i < messageParams.Count; i++) + { + parameters[i] = ((IExpression) messageParams[i]).GetValue(validationContext, contextParams); } - /// - /// Called when associated validator is invalid. - /// - /// Validation context. - /// Additional context parameters. - /// Validation errors container. - protected override void OnInvalid(object validationContext, IDictionary contextParams, IValidationErrors errors) - { - ErrorMessage error = CreateErrorMessage(validationContext, contextParams); - foreach (string provider in this.providers) - { - errors.AddError(provider.Trim(), error); - } - } - - /// - /// Resolves the error message. - /// - /// Validation context to resolve message parameters against. - /// Additional context parameters. - /// Resolved error message - private ErrorMessage CreateErrorMessage(object validationContext, IDictionary contextParams) - { - if (messageParams != null && messageParams.Length > 0) - { - object[] parameters = ResolveMessageParameters(messageParams, validationContext, contextParams); - return new ErrorMessage(messageId, parameters); - } - else - { - return new ErrorMessage(messageId, null); - } - } - - /// - /// Resolves the message parameters. - /// - /// List of parameters to resolve. - /// Validation context to resolve parameters against. - /// Additional context parameters. - /// Resolved message parameters. - private object[] ResolveMessageParameters(IList messageParams, object validationContext, IDictionary contextParams) - { - object[] parameters = new object[messageParams.Count]; - for (int i = 0; i < messageParams.Count; i++) - { - parameters[i] = ((IExpression) messageParams[i]).GetValue(validationContext, contextParams); - } - - return parameters; - } - - + return parameters; } } diff --git a/src/Spring/Spring.Core/Validation/Actions/ExceptionAction.cs b/src/Spring/Spring.Core/Validation/Actions/ExceptionAction.cs index fcce249a..204767c3 100644 --- a/src/Spring/Spring.Core/Validation/Actions/ExceptionAction.cs +++ b/src/Spring/Spring.Core/Validation/Actions/ExceptionAction.cs @@ -21,75 +21,76 @@ using Microsoft.Extensions.Logging; using Spring.Expressions; -namespace Spring.Validation.Actions +namespace Spring.Validation.Actions; + +public class ExceptionAction : BaseValidationAction { - public class ExceptionAction : BaseValidationAction + private static readonly ILogger log = LogManager.GetLogger(); + private IExpression throwsExpression; + + /// + /// Initializes a new instance of the class. + /// + public ExceptionAction() { - private static readonly ILogger log = LogManager.GetLogger(); - private IExpression throwsExpression; + } - /// - /// Initializes a new instance of the class. - /// - public ExceptionAction() + /// + /// Initializes a new instance of the class. + /// + /// Expression that defines the exception to throw when the validator is not valid. + public ExceptionAction(string exceptionExpression) + : this((exceptionExpression != null ? Expression.Parse(exceptionExpression) : null)) + { + } + + /// + /// Initializes a new instance of the class with an expression + /// that defines the exception to throw. + /// + public ExceptionAction(IExpression throwsExpression) + { + this.throwsExpression = throwsExpression; + } + + /// + /// Gets or sets the exception to throw + /// + /// The throws. + public IExpression ThrowsExpression + { + get { return throwsExpression; } + set { throwsExpression = value; } + } + + /// + /// Called when associated validator is invalid. + /// + /// Validation context. + /// Additional context parameters. + /// Validation errors container. + protected override void OnInvalid(object validationContext, IDictionary contextParams, IValidationErrors errors) + { + if (throwsExpression != null) { - } - - /// - /// Initializes a new instance of the class. - /// - /// Expression that defines the exception to throw when the validator is not valid. - public ExceptionAction(string exceptionExpression) - : this((exceptionExpression != null ? Expression.Parse(exceptionExpression) : null)) - {} - - /// - /// Initializes a new instance of the class with an expression - /// that defines the exception to throw. - /// - public ExceptionAction(IExpression throwsExpression) - { - this.throwsExpression = throwsExpression; - } - - /// - /// Gets or sets the exception to throw - /// - /// The throws. - public IExpression ThrowsExpression - { - get { return throwsExpression; } - set { throwsExpression = value; } - } - - /// - /// Called when associated validator is invalid. - /// - /// Validation context. - /// Additional context parameters. - /// Validation errors container. - protected override void OnInvalid(object validationContext, IDictionary contextParams, IValidationErrors errors) - { - if (throwsExpression != null) + object o = null; + try { - object o = null; - try - { - o = throwsExpression.GetValue(null, contextParams); - } - catch (Exception e) - { - string message = "Was not able to evaluate action expression [" + throwsExpression + "]"; - log.LogError(e, message); - } - Exception exception = o as Exception; - if (exception != null) - { - throw exception; - } + o = throwsExpression.GetValue(null, contextParams); + } + catch (Exception e) + { + string message = "Was not able to evaluate action expression [" + throwsExpression + "]"; + log.LogError(e, message); + } + + Exception exception = o as Exception; + if (exception != null) + { + throw exception; } - throw new ValidationException(errors); } + throw new ValidationException(errors); } } diff --git a/src/Spring/Spring.Core/Validation/Actions/ExpressionAction.cs b/src/Spring/Spring.Core/Validation/Actions/ExpressionAction.cs index 337c1209..9b06e998 100644 --- a/src/Spring/Spring.Core/Validation/Actions/ExpressionAction.cs +++ b/src/Spring/Spring.Core/Validation/Actions/ExpressionAction.cs @@ -20,91 +20,92 @@ using Spring.Expressions; -namespace Spring.Validation.Actions +namespace Spring.Validation.Actions; + +/// +/// Implementation of that allows you +/// to define Spring.NET expressions that should be evaluated after +/// validation. +/// +/// Aleksandar Seovic +public class ExpressionAction : BaseValidationAction { + private IExpression onValid; + private IExpression onInvalid; + /// - /// Implementation of that allows you - /// to define Spring.NET expressions that should be evaluated after - /// validation. + /// Initializes a new instance of the class. /// - /// Aleksandar Seovic - public class ExpressionAction : BaseValidationAction + public ExpressionAction() { - private IExpression onValid; - private IExpression onInvalid; + } - /// - /// Initializes a new instance of the class. - /// - public ExpressionAction() - {} + /// + /// Initializes a new instance of the class. + /// + /// Expression to execute when validator is valid. + /// Expression to execute when validator is not valid. + public ExpressionAction(string onValid, string onInvalid) + : this((onValid != null ? Expression.Parse(onValid) : null), (onInvalid != null ? Expression.Parse(onInvalid) : null)) + { + } - /// - /// Initializes a new instance of the class. - /// - /// Expression to execute when validator is valid. - /// Expression to execute when validator is not valid. - public ExpressionAction(string onValid, string onInvalid) - : this((onValid != null ? Expression.Parse(onValid) : null), (onInvalid != null ? Expression.Parse(onInvalid) : null)) - {} + /// + /// Initializes a new instance of the class. + /// + /// Expression to execute when validator is valid. + /// Expression to execute when validator is not valid. + public ExpressionAction(IExpression onValid, IExpression onInvalid) + { + this.onValid = onValid; + this.onInvalid = onInvalid; + } - /// - /// Initializes a new instance of the class. - /// - /// Expression to execute when validator is valid. - /// Expression to execute when validator is not valid. - public ExpressionAction(IExpression onValid, IExpression onInvalid) + /// + /// Gets or sets the expression to execute when validator is valid. + /// + /// The expression to execute when validator is valid. + public IExpression Valid + { + get { return onValid; } + set { onValid = value; } + } + + /// + /// Gets or sets the expression to execute when validator is not valid. + /// + /// The expression to execute when validator is not valid. + public IExpression Invalid + { + get { return onInvalid; } + set { onInvalid = value; } + } + + /// + /// Called when associated validator is valid. + /// + /// Validation context. + /// Additional context parameters. + /// Validation errors container. + protected override void OnValid(object validationContext, IDictionary contextParams, IValidationErrors errors) + { + if (Valid != null) { - this.onValid = onValid; - this.onInvalid = onInvalid; + Valid.GetValue(validationContext, contextParams); } + } - /// - /// Gets or sets the expression to execute when validator is valid. - /// - /// The expression to execute when validator is valid. - public IExpression Valid + /// + /// Called when associated validator is invalid. + /// + /// Validation context. + /// Additional context parameters. + /// Validation errors container. + protected override void OnInvalid(object validationContext, IDictionary contextParams, IValidationErrors errors) + { + if (Invalid != null) { - get { return onValid; } - set { onValid = value; } - } - - /// - /// Gets or sets the expression to execute when validator is not valid. - /// - /// The expression to execute when validator is not valid. - public IExpression Invalid - { - get { return onInvalid; } - set { onInvalid = value; } - } - - /// - /// Called when associated validator is valid. - /// - /// Validation context. - /// Additional context parameters. - /// Validation errors container. - protected override void OnValid(object validationContext, IDictionary contextParams, IValidationErrors errors) - { - if (Valid != null) - { - Valid.GetValue(validationContext, contextParams); - } - } - - /// - /// Called when associated validator is invalid. - /// - /// Validation context. - /// Additional context parameters. - /// Validation errors container. - protected override void OnInvalid(object validationContext, IDictionary contextParams, IValidationErrors errors) - { - if (Invalid != null) - { - Invalid.GetValue(validationContext, contextParams); - } + Invalid.GetValue(validationContext, contextParams); } } } diff --git a/src/Spring/Spring.Core/Validation/AnyValidatorGroup.cs b/src/Spring/Spring.Core/Validation/AnyValidatorGroup.cs index 73b89920..18eba113 100644 --- a/src/Spring/Spring.Core/Validation/AnyValidatorGroup.cs +++ b/src/Spring/Spring.Core/Validation/AnyValidatorGroup.cs @@ -20,85 +20,85 @@ using Spring.Expressions; -namespace Spring.Validation +namespace Spring.Validation; + +/// +/// implementation that supports grouping of validators. +/// +/// +///

+/// This validator will be valid when one or more of the validators in the Validators +/// collection are valid. +///

+///

+/// ValidationErrors property will return a union of all validation error messages +/// for the contained validators, but only if this validator is not valid (meaning, when none +/// of the contained validators are valid). +///

+///

Note, that defaults to true for this validator type!

+///
+/// Aleksandar Seovic +/// Erich Eichinger +public class AnyValidatorGroup : BaseValidatorGroup { + #region Constructors + /// - /// implementation that supports grouping of validators. + /// Initializes a new instance of the class. /// - /// - ///

- /// This validator will be valid when one or more of the validators in the Validators - /// collection are valid. - ///

- ///

- /// ValidationErrors property will return a union of all validation error messages - /// for the contained validators, but only if this validator is not valid (meaning, when none - /// of the contained validators are valid). - ///

- ///

Note, that defaults to true for this validator type!

- ///
- /// Aleksandar Seovic - /// Erich Eichinger - public class AnyValidatorGroup : BaseValidatorGroup + public AnyValidatorGroup() { - #region Constructors + this.FastValidate = true; + } - /// - /// Initializes a new instance of the class. - /// - public AnyValidatorGroup() + /// + /// Initializes a new instance of the class. + /// + /// The expression that determines if this validator should be evaluated. + public AnyValidatorGroup(string when) + : base(when) + { + this.FastValidate = true; + } + + /// + /// Initializes a new instance of the class. + /// + /// The expression that determines if this validator should be evaluated. + public AnyValidatorGroup(IExpression when) + : base(when) + { + this.FastValidate = true; + } + + #endregion + + /// + /// Validates the specified object. + /// + /// Additional context parameters. + /// instance to add error messages to. + /// The object to validate. + /// True if validation was successful, False otherwise. + protected override bool ValidateGroup(IDictionary contextParams, IValidationErrors errors, object validationContext) + { + // capture errors in separate collection to only add them to the error collector in case of errors + ValidationErrors tmpErrors = new ValidationErrors(); + bool valid = false; + foreach (IValidator validator in Validators) { - this.FastValidate = true; - } - - /// - /// Initializes a new instance of the class. - /// - /// The expression that determines if this validator should be evaluated. - public AnyValidatorGroup(string when) - : base(when) - { - this.FastValidate = true; - } - - /// - /// Initializes a new instance of the class. - /// - /// The expression that determines if this validator should be evaluated. - public AnyValidatorGroup(IExpression when) - : base(when) - { - this.FastValidate = true; - } - - #endregion - - /// - /// Validates the specified object. - /// - /// Additional context parameters. - /// instance to add error messages to. - /// The object to validate. - /// True if validation was successful, False otherwise. - protected override bool ValidateGroup(IDictionary contextParams, IValidationErrors errors, object validationContext) - { - // capture errors in separate collection to only add them to the error collector in case of errors - ValidationErrors tmpErrors = new ValidationErrors(); - bool valid = false; - foreach (IValidator validator in Validators) + valid = validator.Validate(validationContext, contextParams, tmpErrors) || valid; + if (valid && FastValidate) { - valid = validator.Validate(validationContext, contextParams, tmpErrors) || valid; - if (valid && FastValidate) - { - break; - } + break; } - - if (!valid) - { - errors.MergeErrors(tmpErrors); - } - return valid; } + + if (!valid) + { + errors.MergeErrors(tmpErrors); + } + + return valid; } } diff --git a/src/Spring/Spring.Core/Validation/BaseSimpleValidator.cs b/src/Spring/Spring.Core/Validation/BaseSimpleValidator.cs index 90ba38c4..10ab04d8 100644 --- a/src/Spring/Spring.Core/Validation/BaseSimpleValidator.cs +++ b/src/Spring/Spring.Core/Validation/BaseSimpleValidator.cs @@ -20,103 +20,103 @@ using Spring.Expressions; -namespace Spring.Validation +namespace Spring.Validation; + +/// +/// Base class that defines common properties for all single validators. +/// +/// +///

+/// Custom single validators should always extend this class instead of +/// simply implementing interface, in +/// order to inherit common validator functionality. +///

+///
+/// Aleksandar Seovic +/// Erich Eichinger +public abstract class BaseSimpleValidator : BaseValidator { + private IExpression test; + /// - /// Base class that defines common properties for all single validators. + /// Gets or sets the test expression. /// - /// - ///

- /// Custom single validators should always extend this class instead of - /// simply implementing interface, in - /// order to inherit common validator functionality. - ///

- ///
- /// Aleksandar Seovic - /// Erich Eichinger - public abstract class BaseSimpleValidator : BaseValidator + /// The test expression. + public IExpression Test { - private IExpression test; + get { return test; } + set { test = value; } + } - /// - /// Gets or sets the test expression. - /// - /// The test expression. - public IExpression Test + /// + /// Creates a new instance of the validator without any + /// and criteria + /// + public BaseSimpleValidator() + { + } + + /// + /// Creates a new instance of the class. + /// + /// The expression to validate. + /// The expression that determines if this validator should be evaluated. + public BaseSimpleValidator(string test, string when) + : base(when) + { + this.test = (test != null ? Expression.Parse(test) : null); + } + + /// + /// Creates a new instance of the class. + /// + /// The expression to validate. + /// The expression that determines if this validator should be evaluated. + public BaseSimpleValidator(IExpression test, IExpression when) : base(when) + { + this.test = test; + } + + /// + /// Validates the specified object. + /// + /// The object to validate. + /// Additional context parameters. + /// instance to add error messages to. + /// True if validation was successful, False otherwise. + public override bool Validate(object validationContext, IDictionary contextParams, IValidationErrors errors) + { + bool valid = true; + + if (EvaluateWhen(validationContext, contextParams)) { - get { return test; } - set { test = value; } + valid = Validate(EvaluateTest(validationContext, contextParams)); + ProcessActions(valid, validationContext, contextParams, errors); } - /// - /// Creates a new instance of the validator without any - /// and criteria - /// - public BaseSimpleValidator() + return valid; + } + + /// + /// Validates test object. + /// + /// Object to validate. + /// True if specified object is valid, False otherwise. + protected abstract bool Validate(object objectToValidate); + + /// + /// Evaluates test expression. + /// + /// Root context to use for expression evaluation. + /// Additional context parameters. + /// Result of the test expression evaluation, or validation context if test is null. + protected object EvaluateTest(object rootContext, IDictionary contextParams) + { + if (Test == null) { + return rootContext; } - /// - /// Creates a new instance of the class. - /// - /// The expression to validate. - /// The expression that determines if this validator should be evaluated. - public BaseSimpleValidator(string test, string when) - : base( when) - { - this.test = (test != null ? Expression.Parse(test) : null); - } - - /// - /// Creates a new instance of the class. - /// - /// The expression to validate. - /// The expression that determines if this validator should be evaluated. - public BaseSimpleValidator(IExpression test, IExpression when):base(when) - { - this.test = test; - } - - /// - /// Validates the specified object. - /// - /// The object to validate. - /// Additional context parameters. - /// instance to add error messages to. - /// True if validation was successful, False otherwise. - public override bool Validate(object validationContext, IDictionary contextParams, IValidationErrors errors) - { - bool valid = true; - - if (EvaluateWhen(validationContext, contextParams)) - { - valid = Validate(EvaluateTest(validationContext, contextParams)); - ProcessActions(valid, validationContext, contextParams, errors); - } - - return valid; - } - - /// - /// Validates test object. - /// - /// Object to validate. - /// True if specified object is valid, False otherwise. - protected abstract bool Validate(object objectToValidate); - - /// - /// Evaluates test expression. - /// - /// Root context to use for expression evaluation. - /// Additional context parameters. - /// Result of the test expression evaluation, or validation context if test is null. - protected object EvaluateTest(object rootContext, IDictionary contextParams) - { - if (Test == null) - { - return rootContext; - } - return Test.GetValue(rootContext, contextParams); - } + return Test.GetValue(rootContext, contextParams); } } diff --git a/src/Spring/Spring.Core/Validation/BaseValidationAction.cs b/src/Spring/Spring.Core/Validation/BaseValidationAction.cs index 2ae89e3e..349837d6 100644 --- a/src/Spring/Spring.Core/Validation/BaseValidationAction.cs +++ b/src/Spring/Spring.Core/Validation/BaseValidationAction.cs @@ -20,119 +20,121 @@ using Spring.Expressions; -namespace Spring.Validation +namespace Spring.Validation; + +/// +/// Abstract base class that should be extended by all +/// validation actions. +/// +/// +///

+/// This class implements template Execute method +/// and defines OnValid and OnInvalid methods that +/// can be overriden +/// by specific validation actions. +///

+///
+/// Aleksandar Seovic +public abstract class BaseValidationAction : IValidationAction { + #region Fields + + private IExpression when; + + #endregion + + #region Constructors + /// - /// Abstract base class that should be extended by all - /// validation actions. + /// Initializes a new instance of the class. /// - /// - ///

- /// This class implements template Execute method - /// and defines OnValid and OnInvalid methods that - /// can be overriden - /// by specific validation actions. - ///

- ///
- /// Aleksandar Seovic - public abstract class BaseValidationAction : IValidationAction + public BaseValidationAction() { - #region Fields - - private IExpression when; - - #endregion - - #region Constructors - - /// - /// Initializes a new instance of the class. - /// - public BaseValidationAction() - {} - - #endregion - - #region Properties - - /// - /// Gets or sets the expression that determines if this validator should be evaluated. - /// - /// The expression that determines if this validator should be evaluated. - public IExpression When - { - get { return when; } - set { when = value; } - } - - #endregion - - /// - /// Executes the action. - /// - /// Whether associated validator is valid or not. - /// Validation context. - /// Additional context parameters. - /// Validation errors container. - public virtual void Execute(bool isValid, object validationContext, IDictionary contextParams, IValidationErrors errors) - { - if (EvaluateWhen(validationContext, contextParams)) - { - if (isValid) - { - OnValid(validationContext, contextParams, errors); - } - else - { - OnInvalid(validationContext, contextParams, errors); - } - } - } - - #region Abstract methods - - // CLOVER:OFF - - /// - /// Called when associated validator is valid. - /// - /// Validation context. - /// Additional context parameters. - /// Validation errors container. - protected virtual void OnValid(object validationContext, IDictionary contextParams, IValidationErrors errors) - {} - - /// - /// Called when associated validator is not valid. - /// - /// Validation context. - /// Additional context parameters. - /// Validation errors container. - protected virtual void OnInvalid(object validationContext, IDictionary contextParams, IValidationErrors errors) - {} - - // CLOVER:ON - - #endregion - - #region Helper methods - - /// - /// Evaluates 'when' expression. - /// - /// Root context to use for expression evaluation. - /// Additional context parameters. - /// True if the condition is true, False otherwise. - protected bool EvaluateWhen(object rootContext, IDictionary contextParams) - { - if (When == null) - { - return true; - } - - return Convert.ToBoolean(When.GetValue(rootContext, contextParams)); - } - - #endregion } + + #endregion + + #region Properties + + /// + /// Gets or sets the expression that determines if this validator should be evaluated. + /// + /// The expression that determines if this validator should be evaluated. + public IExpression When + { + get { return when; } + set { when = value; } + } + + #endregion + + /// + /// Executes the action. + /// + /// Whether associated validator is valid or not. + /// Validation context. + /// Additional context parameters. + /// Validation errors container. + public virtual void Execute(bool isValid, object validationContext, IDictionary contextParams, IValidationErrors errors) + { + if (EvaluateWhen(validationContext, contextParams)) + { + if (isValid) + { + OnValid(validationContext, contextParams, errors); + } + else + { + OnInvalid(validationContext, contextParams, errors); + } + } + } + + #region Abstract methods + + // CLOVER:OFF + + /// + /// Called when associated validator is valid. + /// + /// Validation context. + /// Additional context parameters. + /// Validation errors container. + protected virtual void OnValid(object validationContext, IDictionary contextParams, IValidationErrors errors) + { + } + + /// + /// Called when associated validator is not valid. + /// + /// Validation context. + /// Additional context parameters. + /// Validation errors container. + protected virtual void OnInvalid(object validationContext, IDictionary contextParams, IValidationErrors errors) + { + } + + // CLOVER:ON + + #endregion + + #region Helper methods + + /// + /// Evaluates 'when' expression. + /// + /// Root context to use for expression evaluation. + /// Additional context parameters. + /// True if the condition is true, False otherwise. + protected bool EvaluateWhen(object rootContext, IDictionary contextParams) + { + if (When == null) + { + return true; + } + + return Convert.ToBoolean(When.GetValue(rootContext, contextParams)); + } + + #endregion } diff --git a/src/Spring/Spring.Core/Validation/BaseValidator.cs b/src/Spring/Spring.Core/Validation/BaseValidator.cs index 297f9313..6705b9cd 100644 --- a/src/Spring/Spring.Core/Validation/BaseValidator.cs +++ b/src/Spring/Spring.Core/Validation/BaseValidator.cs @@ -20,137 +20,138 @@ using Spring.Expressions; -namespace Spring.Validation +namespace Spring.Validation; + +/// +/// Base class that defines common properties for all validators. +/// +/// +///

+/// Custom validators should always extend this class instead of +/// simply implementing interface, in +/// order to inherit common validator functionality. +///

+///
+/// Aleksandar Seovic +/// Erich Eichinger +public abstract class BaseValidator : IValidator { + #region Fields + + private IList actions = new List(); + + private IExpression when; + + #endregion + + #region Constructors + /// - /// Base class that defines common properties for all validators. + /// Creates a new instance of the class. /// - /// - ///

- /// Custom validators should always extend this class instead of - /// simply implementing interface, in - /// order to inherit common validator functionality. - ///

- ///
- /// Aleksandar Seovic - /// Erich Eichinger - public abstract class BaseValidator : IValidator + public BaseValidator() { - #region Fields - - private IList actions = new List(); - - private IExpression when; - - #endregion - - #region Constructors - - /// - /// Creates a new instance of the class. - /// - public BaseValidator() - {} - - /// - /// Creates a new instance of the class. - /// - /// The expression that determines if this validator should be evaluated. - public BaseValidator(string when) - : this((when != null ? Expression.Parse(when) : null)) - {} - - /// - /// Creates a new instance of the class. - /// - /// The expression that determines if this validator should be evaluated. - public BaseValidator(IExpression when) - { - this.when = when; - } - - #endregion - - #region Properties - - /// - /// Gets or sets the expression that determines if this validator should be evaluated. - /// - /// The expression that determines if this validator should be evaluated. - public IExpression When - { - get { return when; } - set { when = value; } - } - - /// - /// Gets or sets the validation actions. - /// - /// The actions that should be executed after validation. - public IList Actions - { - get { return actions; } - set { actions = value; } - } - - #endregion - - /// - /// Validates the specified object. - /// - /// The object to validate. - /// instance to add error messages to. - /// True if validation was successful, False otherwise. - public bool Validate(object validationContext, IValidationErrors errors) - { - return Validate(validationContext, null, errors); - } - - /// - /// Validates the specified object. - /// - /// The object to validate. - /// Additional context parameters. - /// instance to add error messages to. - /// True if validation was successful, False otherwise. - public abstract bool Validate(object validationContext, IDictionary contextParams, IValidationErrors errors); - - #region Helper Methods - - /// - /// Evaluates when expression. - /// - /// Root context to use for expression evaluation. - /// Additional context parameters. - /// True if the condition is true, False otherwise. - protected bool EvaluateWhen(object rootContext, IDictionary contextParams) - { - if (When == null) - { - return true; - } - - return Convert.ToBoolean(When.GetValue(rootContext, contextParams)); - } - - /// - /// Processes the error messages. - /// - /// Whether validator is valid or not. - /// Validation context. - /// Additional context parameters. - /// Validation errors container. - protected void ProcessActions(bool isValid, object validationContext, IDictionary contextParams, IValidationErrors errors) - { - if (actions != null && actions.Count > 0) - { - foreach (IValidationAction action in actions) - { - action.Execute(isValid, validationContext, contextParams, errors); - } - } - } - - #endregion } + + /// + /// Creates a new instance of the class. + /// + /// The expression that determines if this validator should be evaluated. + public BaseValidator(string when) + : this((when != null ? Expression.Parse(when) : null)) + { + } + + /// + /// Creates a new instance of the class. + /// + /// The expression that determines if this validator should be evaluated. + public BaseValidator(IExpression when) + { + this.when = when; + } + + #endregion + + #region Properties + + /// + /// Gets or sets the expression that determines if this validator should be evaluated. + /// + /// The expression that determines if this validator should be evaluated. + public IExpression When + { + get { return when; } + set { when = value; } + } + + /// + /// Gets or sets the validation actions. + /// + /// The actions that should be executed after validation. + public IList Actions + { + get { return actions; } + set { actions = value; } + } + + #endregion + + /// + /// Validates the specified object. + /// + /// The object to validate. + /// instance to add error messages to. + /// True if validation was successful, False otherwise. + public bool Validate(object validationContext, IValidationErrors errors) + { + return Validate(validationContext, null, errors); + } + + /// + /// Validates the specified object. + /// + /// The object to validate. + /// Additional context parameters. + /// instance to add error messages to. + /// True if validation was successful, False otherwise. + public abstract bool Validate(object validationContext, IDictionary contextParams, IValidationErrors errors); + + #region Helper Methods + + /// + /// Evaluates when expression. + /// + /// Root context to use for expression evaluation. + /// Additional context parameters. + /// True if the condition is true, False otherwise. + protected bool EvaluateWhen(object rootContext, IDictionary contextParams) + { + if (When == null) + { + return true; + } + + return Convert.ToBoolean(When.GetValue(rootContext, contextParams)); + } + + /// + /// Processes the error messages. + /// + /// Whether validator is valid or not. + /// Validation context. + /// Additional context parameters. + /// Validation errors container. + protected void ProcessActions(bool isValid, object validationContext, IDictionary contextParams, IValidationErrors errors) + { + if (actions != null && actions.Count > 0) + { + foreach (IValidationAction action in actions) + { + action.Execute(isValid, validationContext, contextParams, errors); + } + } + } + + #endregion } diff --git a/src/Spring/Spring.Core/Validation/BaseValidatorGroup.cs b/src/Spring/Spring.Core/Validation/BaseValidatorGroup.cs index 6cf43a20..04b445b8 100644 --- a/src/Spring/Spring.Core/Validation/BaseValidatorGroup.cs +++ b/src/Spring/Spring.Core/Validation/BaseValidatorGroup.cs @@ -21,91 +21,93 @@ using System.Collections; using Spring.Expressions; -namespace Spring.Validation +namespace Spring.Validation; + +/// +/// Base class for composite validators +/// +public abstract class BaseValidatorGroup : BaseValidator { + // TODO (EE): extend validation schema for "FastValidate" + + private IList validators = new ArrayList(); + private bool fastValidate = false; + /// - /// Base class for composite validators + /// Initializes a new instance /// - public abstract class BaseValidatorGroup : BaseValidator + public BaseValidatorGroup() { - // TODO (EE): extend validation schema for "FastValidate" - - private IList validators = new ArrayList(); - private bool fastValidate = false; - - /// - /// Initializes a new instance - /// - public BaseValidatorGroup() - {} - - /// - /// Initializes a new instance - /// - /// The expression that determines if this validator should be evaluated. - public BaseValidatorGroup(string when) - : base(when) - {} - - /// - /// Initializes a new instance - /// - /// The expression that determines if this validator should be evaluated. - public BaseValidatorGroup(IExpression when) - : base(when) - {} - - /// - /// Gets or sets the child validators. - /// - /// The validators. - public IList Validators - { - get { return validators; } - set { validators = value; } - } - - /// - /// When set true, shortcircuits evaluation. - /// - /// - /// Setting this property true causes the evaluation process to prematurely abort - /// if the end result is known. Any remaining child validators will not be considered then. - /// Setting this value false causes implementations to evaluate all child validators, regardless - /// of the potentially already known result. - /// - public bool FastValidate - { - get { return fastValidate; } - set { fastValidate = value; } - } - - /// - /// Validates the specified object. - /// - /// The object to validate. - /// Additional context parameters. - /// instance to add error messages to. - /// True if validation was successful, False otherwise. - public override bool Validate(object validationContext, IDictionary contextParams, IValidationErrors errors) - { - if (EvaluateWhen(validationContext, contextParams)) - { - bool valid = ValidateGroup(contextParams, errors, validationContext); - ProcessActions(valid, validationContext, contextParams, errors); - return valid; - } - - return true; - } - - /// - /// Actual implementation how to validate the specified object. - /// - /// Additional context parameters. - /// instance to add error messages to. - /// The object to validate. - /// True if validation was successful, False otherwise. - protected abstract bool ValidateGroup(IDictionary contextParams, IValidationErrors errors, object validationContext); } + + /// + /// Initializes a new instance + /// + /// The expression that determines if this validator should be evaluated. + public BaseValidatorGroup(string when) + : base(when) + { + } + + /// + /// Initializes a new instance + /// + /// The expression that determines if this validator should be evaluated. + public BaseValidatorGroup(IExpression when) + : base(when) + { + } + + /// + /// Gets or sets the child validators. + /// + /// The validators. + public IList Validators + { + get { return validators; } + set { validators = value; } + } + + /// + /// When set true, shortcircuits evaluation. + /// + /// + /// Setting this property true causes the evaluation process to prematurely abort + /// if the end result is known. Any remaining child validators will not be considered then. + /// Setting this value false causes implementations to evaluate all child validators, regardless + /// of the potentially already known result. + /// + public bool FastValidate + { + get { return fastValidate; } + set { fastValidate = value; } + } + + /// + /// Validates the specified object. + /// + /// The object to validate. + /// Additional context parameters. + /// instance to add error messages to. + /// True if validation was successful, False otherwise. + public override bool Validate(object validationContext, IDictionary contextParams, IValidationErrors errors) + { + if (EvaluateWhen(validationContext, contextParams)) + { + bool valid = ValidateGroup(contextParams, errors, validationContext); + ProcessActions(valid, validationContext, contextParams, errors); + return valid; + } + + return true; + } + + /// + /// Actual implementation how to validate the specified object. + /// + /// Additional context parameters. + /// instance to add error messages to. + /// The object to validate. + /// True if validation was successful, False otherwise. + protected abstract bool ValidateGroup(IDictionary contextParams, IValidationErrors errors, object validationContext); } diff --git a/src/Spring/Spring.Core/Validation/CollectionValidator.cs b/src/Spring/Spring.Core/Validation/CollectionValidator.cs index dda34e2a..5e2cf719 100644 --- a/src/Spring/Spring.Core/Validation/CollectionValidator.cs +++ b/src/Spring/Spring.Core/Validation/CollectionValidator.cs @@ -21,196 +21,193 @@ using System.Collections; using Spring.Expressions; -namespace Spring.Validation +namespace Spring.Validation; + +/// +/// implementation that supports validating collections. +/// +/// +///

+/// This validator will be valid only when all of the validators in the Validators +/// collection are valid for all of the objects in the specified collection. +///

+///

+/// You can specify if you want to validate all of the collection elements regardless of the errors by +/// setting the property to false. +///

+///

Note, that defaults to true for this validator type!

+///

+/// If you set the IncludeElementErrors property to true, +/// ValidationErrors collection will contain a union of all validation error messages +/// for the contained validators; +/// Otherwise it will contain only error messages that were set for this Validator. +///

+///
+/// Damjan Tomic +/// Aleksandar Seovic +public class CollectionValidator : BaseValidatorGroup { + #region Fields + + private bool includeElementErrors = false; + private IExpression context; + + #endregion + + #region Properties + /// - /// implementation that supports validating collections. + /// Gets or sets the value that indicates whether to validate all elements of the collection + /// regardless of the errors. /// - /// - ///

- /// This validator will be valid only when all of the validators in the Validators - /// collection are valid for all of the objects in the specified collection. - ///

- ///

- /// You can specify if you want to validate all of the collection elements regardless of the errors by - /// setting the property to false. - ///

- ///

Note, that defaults to true for this validator type!

- ///

- /// If you set the IncludeElementErrors property to true, - /// ValidationErrors collection will contain a union of all validation error messages + /// This is just an alias for property + public bool ValidateAll + { + get { return !base.FastValidate; } + set { base.FastValidate = !value; } + } + + ///

+ /// Gets or sets the value that indicates whether to capture all the errors of the specific + /// elements of the collection + /// + public bool IncludeElementErrors + { + get { return includeElementErrors; } + set { includeElementErrors = value; } + } + + /// + /// Gets or sets the expression that should be used to narrow validation context. + /// + /// The expression that should be used to narrow validation context. + public IExpression Context + { + get { return context; } + set { context = value; } + } + + #endregion + + #region Constructors + + /// + /// Initializes a new instance of the class. + /// + public CollectionValidator() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The bool that determines if all elements of the collection should be evaluated. + /// regardless of the Errors + /// + /// The bool that determines whether Validate method should collect + /// all error messages returned by the item validators + public CollectionValidator(bool validateAll, bool includeElementErrors) + { + this.FastValidate = validateAll; + this.includeElementErrors = includeElementErrors; + } + + /// + /// Initializes a new instance of the class. + /// + /// The expression that determines if this validator should be evaluated. + /// The bool that determines if this all elements of the collection should be evaluated. + /// regardless of the Errors + /// + /// The bool that determines whether Validate method should collect + /// all error messages returned by the item validators + public CollectionValidator(string when, bool validateAll, bool includeElementErrors) + : this((when != null ? Expression.Parse(when) : null), validateAll, includeElementErrors) + { + this.FastValidate = validateAll; + } + + /// + /// Initializes a new instance of the class. + /// + /// The expression that determines if this validator should be evaluated. + /// The bool that determines if this all elements of the collection should be evaluated. + /// regardless of the Errors + /// + /// The bool that determines whether Validate method should collect + /// all error messages returned by the item validators + public CollectionValidator(IExpression when, bool validateAll, bool includeElementErrors) + : base(when) + { + this.FastValidate = validateAll; + this.includeElementErrors = includeElementErrors; + } + + #endregion + + /// + /// Validates the specified collection of objects. + /// If the IncludeElementErrors property was set to true, + /// collection will contain a union of all validation error messages /// for the contained validators; /// Otherwise it will contain only error messages that were set for this Validator. - ///

- /// - /// Damjan Tomic - /// Aleksandar Seovic - public class CollectionValidator : BaseValidatorGroup + ///
+ /// The collection to validate. + /// Additional context parameters. + /// instance to add error messages to. + /// True if validation was successful, False otherwise. + public override bool Validate(object validationContext, IDictionary contextParams, IValidationErrors errors) { - #region Fields - - private bool includeElementErrors = false; - private IExpression context; - - #endregion - - #region Properties - - /// - /// Gets or sets the value that indicates whether to validate all elements of the collection - /// regardless of the errors. - /// - /// This is just an alias for property - public bool ValidateAll + if (Context != null) { - get { return !base.FastValidate; } - set { base.FastValidate = !value; } + validationContext = Context.GetValue(validationContext, contextParams); } - /// - /// Gets or sets the value that indicates whether to capture all the errors of the specific - /// elements of the collection - /// - public bool IncludeElementErrors + if (!(validationContext is IEnumerable)) { - get { return includeElementErrors; } - set { includeElementErrors = value; } + throw new ArgumentException("The type of the object for validation must be subtype of IEnumerable."); } + return base.Validate(validationContext, contextParams, errors); + } - /// - /// Gets or sets the expression that should be used to narrow validation context. - /// - /// The expression that should be used to narrow validation context. - public IExpression Context + /// + /// Actual implementation how to validate the specified object. + /// + /// Additional context parameters. + /// instance to add error messages to. + /// The object to validate. + /// True if validation was successful, False otherwise. + protected override bool ValidateGroup(IDictionary contextParams, IValidationErrors errors, object validationContext) + { + bool valid = true; + IEnumerable collectionToValidate = (validationContext is IDictionary + ? ((IDictionary) validationContext).Values + : (IEnumerable) validationContext); + + // decide whether to pass new validation errors collection + //(and discard error messages returned by the item validators) + // OR to pass validation errors collection that was passed to this method + //(and collect all error messages returned by the item validators) + IValidationErrors err = (includeElementErrors) ? errors : new ValidationErrors(); + + foreach (object objectToValidate in collectionToValidate) { - get { return context; } - set { context = value; } - } - - #endregion - - #region Constructors - - /// - /// Initializes a new instance of the class. - /// - public CollectionValidator() - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The bool that determines if all elements of the collection should be evaluated. - /// regardless of the Errors - /// - /// The bool that determines whether Validate method should collect - /// all error messages returned by the item validators - public CollectionValidator(bool validateAll, bool includeElementErrors) - { - this.FastValidate = validateAll; - this.includeElementErrors = includeElementErrors; - } - - /// - /// Initializes a new instance of the class. - /// - /// The expression that determines if this validator should be evaluated. - /// The bool that determines if this all elements of the collection should be evaluated. - /// regardless of the Errors - /// - /// The bool that determines whether Validate method should collect - /// all error messages returned by the item validators - public CollectionValidator(string when, bool validateAll, bool includeElementErrors) - : this((when != null ? Expression.Parse(when) : null), validateAll,includeElementErrors) - { - this.FastValidate = validateAll; - } - - /// - /// Initializes a new instance of the class. - /// - /// The expression that determines if this validator should be evaluated. - /// The bool that determines if this all elements of the collection should be evaluated. - /// regardless of the Errors - /// - /// The bool that determines whether Validate method should collect - /// all error messages returned by the item validators - - public CollectionValidator(IExpression when, bool validateAll, bool includeElementErrors) - : base(when) - { - this.FastValidate = validateAll; - this.includeElementErrors = includeElementErrors; - } - - #endregion - - /// - /// Validates the specified collection of objects. - /// If the IncludeElementErrors property was set to true, - /// collection will contain a union of all validation error messages - /// for the contained validators; - /// Otherwise it will contain only error messages that were set for this Validator. - /// - /// The collection to validate. - /// Additional context parameters. - /// instance to add error messages to. - /// True if validation was successful, False otherwise. - public override bool Validate(object validationContext, IDictionary contextParams, IValidationErrors errors) - { - if (Context != null) + foreach (IValidator validator in this.Validators) { - validationContext = Context.GetValue(validationContext, contextParams); - } - - if (!(validationContext is IEnumerable)) - { - throw new ArgumentException("The type of the object for validation must be subtype of IEnumerable."); - } - - return base.Validate(validationContext, contextParams, errors); - } - - /// - /// Actual implementation how to validate the specified object. - /// - /// Additional context parameters. - /// instance to add error messages to. - /// The object to validate. - /// True if validation was successful, False otherwise. - protected override bool ValidateGroup(IDictionary contextParams, IValidationErrors errors, object validationContext) - { - bool valid = true; - IEnumerable collectionToValidate = (validationContext is IDictionary - ? ((IDictionary) validationContext).Values - : (IEnumerable) validationContext); - - // decide whether to pass new validation errors collection - //(and discard error messages returned by the item validators) - // OR to pass validation errors collection that was passed to this method - //(and collect all error messages returned by the item validators) - IValidationErrors err = (includeElementErrors)? errors : new ValidationErrors(); - - foreach (object objectToValidate in collectionToValidate) - { - foreach (IValidator validator in this.Validators) - { - valid = validator.Validate(objectToValidate, contextParams, err) && valid; - if (!valid && this.FastValidate) - { - break; - } - } - + valid = validator.Validate(objectToValidate, contextParams, err) && valid; if (!valid && this.FastValidate) { break; } } - return valid; + + if (!valid && this.FastValidate) + { + break; + } } + return valid; } } diff --git a/src/Spring/Spring.Core/Validation/Config/ValidationNamespaceParser.cs b/src/Spring/Spring.Core/Validation/Config/ValidationNamespaceParser.cs index 7ba8584f..4ab005b6 100644 --- a/src/Spring/Spring.Core/Validation/Config/ValidationNamespaceParser.cs +++ b/src/Spring/Spring.Core/Validation/Config/ValidationNamespaceParser.cs @@ -19,7 +19,6 @@ #endregion using System.Xml; - using Spring.Core.TypeResolution; using Spring.Expressions; using Spring.Objects; @@ -29,109 +28,108 @@ using Spring.Objects.Factory.Support; using Spring.Objects.Factory.Xml; using Spring.Util; -namespace Spring.Validation.Config +namespace Spring.Validation.Config; + +/// +/// Implementation of the custom configuration parser for validator definitions. +/// +/// Aleksandar Seovic +[ + NamespaceParser( + Namespace = "http://www.springframework.net/validation", + SchemaLocationAssemblyHint = typeof(ValidationNamespaceParser), + SchemaLocation = "/Spring.Validation.Config/spring-validation-1.3.xsd") +] +public sealed class ValidationNamespaceParser : ObjectsNamespaceParser { - /// - /// Implementation of the custom configuration parser for validator definitions. - /// - /// Aleksandar Seovic - [ - NamespaceParser( - Namespace = "http://www.springframework.net/validation", - SchemaLocationAssemblyHint = typeof(ValidationNamespaceParser), - SchemaLocation = "/Spring.Validation.Config/spring-validation-1.3.xsd") - ] - public sealed class ValidationNamespaceParser : ObjectsNamespaceParser + private const string ValidatorTypePrefix = "validator: "; + + [ThreadStatic] private int definitionCount = 0; + + static ValidationNamespaceParser() { - private const string ValidatorTypePrefix = "validator: "; + TypeRegistry.RegisterType(ValidatorTypePrefix + "group", typeof(ValidatorGroup)); + TypeRegistry.RegisterType(ValidatorTypePrefix + "any", typeof(AnyValidatorGroup)); + TypeRegistry.RegisterType(ValidatorTypePrefix + "exclusive", typeof(ExclusiveValidatorGroup)); + TypeRegistry.RegisterType(ValidatorTypePrefix + "collection", typeof(CollectionValidator)); + TypeRegistry.RegisterType(ValidatorTypePrefix + "required", typeof(RequiredValidator)); + TypeRegistry.RegisterType(ValidatorTypePrefix + "condition", typeof(ConditionValidator)); + TypeRegistry.RegisterType(ValidatorTypePrefix + "regex", typeof(RegularExpressionValidator)); + } - [ThreadStatic] - private int definitionCount = 0; + /// + /// Initializes a new instance of the class. + /// + public ValidationNamespaceParser() + { + // generate unique key for instance field to be stored in LogicalThreadContext + string FIELDPREFIX = typeof(ValidationNamespaceParser).FullName + base.GetHashCode(); + } - static ValidationNamespaceParser() + /// + /// Parse the specified element and register any resulting + /// IObjectDefinitions with the IObjectDefinitionRegistry that is + /// embedded in the supplied ParserContext. + /// + /// The element to be parsed into one or more IObjectDefinitions + /// The object encapsulating the current state of the parsing + /// process. + /// + /// The primary IObjectDefinition (can be null as explained above) + /// + /// + /// Implementations should return the primary IObjectDefinition + /// that results from the parse phase if they wish to used nested + /// inside (for example) a <property> tag. + /// Implementations may return null if they will not + /// be used in a nested scenario. + /// + /// + public override IObjectDefinition ParseElement(XmlElement element, ParserContext parserContext) + { + if (!element.HasAttribute("id")) { - TypeRegistry.RegisterType(ValidatorTypePrefix + "group", typeof(ValidatorGroup)); - TypeRegistry.RegisterType(ValidatorTypePrefix + "any", typeof(AnyValidatorGroup)); - TypeRegistry.RegisterType(ValidatorTypePrefix + "exclusive", typeof(ExclusiveValidatorGroup)); - TypeRegistry.RegisterType(ValidatorTypePrefix + "collection", typeof(CollectionValidator)); - TypeRegistry.RegisterType(ValidatorTypePrefix + "required", typeof(RequiredValidator)); - TypeRegistry.RegisterType(ValidatorTypePrefix + "condition", typeof(ConditionValidator)); - TypeRegistry.RegisterType(ValidatorTypePrefix + "regex", typeof(RegularExpressionValidator)); + throw new ObjectDefinitionStoreException(parserContext.ReaderContext.Resource, "validator", "Top-level validator element must have an 'id' attribute defined."); } - /// - /// Initializes a new instance of the class. - /// - public ValidationNamespaceParser() - { - // generate unique key for instance field to be stored in LogicalThreadContext - string FIELDPREFIX = typeof(ValidationNamespaceParser).FullName + base.GetHashCode(); - } + this.definitionCount = 0; + ParseAndRegisterValidator(element, parserContext); - /// - /// Parse the specified element and register any resulting - /// IObjectDefinitions with the IObjectDefinitionRegistry that is - /// embedded in the supplied ParserContext. - /// - /// The element to be parsed into one or more IObjectDefinitions - /// The object encapsulating the current state of the parsing - /// process. - /// - /// The primary IObjectDefinition (can be null as explained above) - /// - /// - /// Implementations should return the primary IObjectDefinition - /// that results from the parse phase if they wish to used nested - /// inside (for example) a <property> tag. - /// Implementations may return null if they will not - /// be used in a nested scenario. - /// - /// - public override IObjectDefinition ParseElement(XmlElement element, ParserContext parserContext) - { - if (!element.HasAttribute("id")) - { - throw new ObjectDefinitionStoreException(parserContext.ReaderContext.Resource, "validator", "Top-level validator element must have an 'id' attribute defined."); - } - this.definitionCount = 0; + return null; + //return definitionCount; + } - ParseAndRegisterValidator(element, parserContext); + /// + /// Parses the validator definition. + /// + /// Validator's identifier. + /// The element to parse. + /// The parser helper. + /// Validator object definition. + private IObjectDefinition ParseValidator(string id, XmlElement element, ParserContext parserContext) + { + string typeName = GetTypeName(element); + string parent = GetAttributeValue(element, ObjectDefinitionConstants.ParentAttribute); - return null; - //return definitionCount; - } + string name = "validator: " + (StringUtils.HasText(id) ? id : this.definitionCount.ToString()); - /// - /// Parses the validator definition. - /// - /// Validator's identifier. - /// The element to parse. - /// The parser helper. - /// Validator object definition. - private IObjectDefinition ParseValidator(string id, XmlElement element, ParserContext parserContext) - { - string typeName = GetTypeName(element); - string parent = GetAttributeValue(element, ObjectDefinitionConstants.ParentAttribute); + MutablePropertyValues properties = new MutablePropertyValues(); + IConfigurableObjectDefinition od + = parserContext.ReaderContext.ObjectDefinitionFactory.CreateObjectDefinition( + typeName, parent, parserContext.ReaderContext.Reader.Domain); - string name = "validator: " + (StringUtils.HasText(id) ? id : this.definitionCount.ToString()); + od.PropertyValues = properties; + od.IsSingleton = true; + od.IsLazyInit = true; - MutablePropertyValues properties = new MutablePropertyValues(); - IConfigurableObjectDefinition od - = parserContext.ReaderContext.ObjectDefinitionFactory.CreateObjectDefinition( - typeName, parent, parserContext.ReaderContext.Reader.Domain); - - od.PropertyValues = properties; - od.IsSingleton = true; - od.IsLazyInit = true; - - ParseAttributeIntoProperty(element, ValidatorDefinitionConstants.TestAttribute, properties, "Test"); - ParseAttributeIntoProperty(element, ValidatorDefinitionConstants.WhenAttribute, properties, "When"); - ParseAttributeIntoProperty(element, ValidatorDefinitionConstants.GroupFastValidateAttribute, properties, "FastValidate"); - ParseAttributeIntoProperty(element, ValidatorDefinitionConstants.RegexExpressionAttribute, properties, "Expression"); - ParseAttributeIntoProperty(element, ValidatorDefinitionConstants.CollectionValidateAllAttribute, properties, "ValidateAll"); - ParseAttributeIntoProperty(element, ValidatorDefinitionConstants.CollectionContextAttribute, properties, "Context"); - ParseAttributeIntoProperty(element, ValidatorDefinitionConstants.CollectionIncludeElementsErrors, properties, "IncludeElementErrors"); + ParseAttributeIntoProperty(element, ValidatorDefinitionConstants.TestAttribute, properties, "Test"); + ParseAttributeIntoProperty(element, ValidatorDefinitionConstants.WhenAttribute, properties, "When"); + ParseAttributeIntoProperty(element, ValidatorDefinitionConstants.GroupFastValidateAttribute, properties, "FastValidate"); + ParseAttributeIntoProperty(element, ValidatorDefinitionConstants.RegexExpressionAttribute, properties, "Expression"); + ParseAttributeIntoProperty(element, ValidatorDefinitionConstants.CollectionValidateAllAttribute, properties, "ValidateAll"); + ParseAttributeIntoProperty(element, ValidatorDefinitionConstants.CollectionContextAttribute, properties, "Context"); + ParseAttributeIntoProperty(element, ValidatorDefinitionConstants.CollectionIncludeElementsErrors, properties, "IncludeElementErrors"); // TODO: (EE) - is this a mistake to check 'validateAll' but add 'context' then? // if (StringUtils.HasText(validateAll)) @@ -139,258 +137,262 @@ namespace Spring.Validation.Config // properties.Add("Context", context); // } - ManagedList nestedValidators = new ManagedList(); - ManagedList actions = new ManagedList(); - ParserContext childParserContext = new ParserContext(parserContext.ParserHelper, od); - foreach (XmlNode node in element.ChildNodes) + ManagedList nestedValidators = new ManagedList(); + ManagedList actions = new ManagedList(); + ParserContext childParserContext = new ParserContext(parserContext.ParserHelper, od); + foreach (XmlNode node in element.ChildNodes) + { + XmlElement child = node as XmlElement; + if (child != null) { - XmlElement child = node as XmlElement; - if (child != null) + switch (child.LocalName) { - switch (child.LocalName) - { - case ValidatorDefinitionConstants.PropertyElement: - string propertyName = GetAttributeValue(child, ValidatorDefinitionConstants.PropertyNameAttribute); - properties.Add(propertyName, base.ParsePropertyValue(child, name, childParserContext)); - break; - case ValidatorDefinitionConstants.MessageElement: - actions.Add(ParseErrorMessageAction(child, childParserContext)); - break; - case ValidatorDefinitionConstants.ActionElement: - actions.Add(ParseGenericAction(child, childParserContext)); - break; - case ValidatorDefinitionConstants.ExceptionElement: - actions.Add(ParseExceptionAction(child, childParserContext)); - break; - case ValidatorDefinitionConstants.ReferenceElement: - nestedValidators.Add(ParseValidatorReference(child, childParserContext)); - break; - default: - nestedValidators.Add(ParseAndRegisterValidator(child, childParserContext)); - break; - } + case ValidatorDefinitionConstants.PropertyElement: + string propertyName = GetAttributeValue(child, ValidatorDefinitionConstants.PropertyNameAttribute); + properties.Add(propertyName, base.ParsePropertyValue(child, name, childParserContext)); + break; + case ValidatorDefinitionConstants.MessageElement: + actions.Add(ParseErrorMessageAction(child, childParserContext)); + break; + case ValidatorDefinitionConstants.ActionElement: + actions.Add(ParseGenericAction(child, childParserContext)); + break; + case ValidatorDefinitionConstants.ExceptionElement: + actions.Add(ParseExceptionAction(child, childParserContext)); + break; + case ValidatorDefinitionConstants.ReferenceElement: + nestedValidators.Add(ParseValidatorReference(child, childParserContext)); + break; + default: + nestedValidators.Add(ParseAndRegisterValidator(child, childParserContext)); + break; } } - if (nestedValidators.Count > 0) - { - properties.Add("Validators", nestedValidators); - } - if (actions.Count > 0) - { - properties.Add("Actions", actions); - } - - return od; } - /// - /// Parses the attribute of the given from the XmlElement and, if available, adds a property of the given with - /// the parsed value. - /// - private void ParseAttributeIntoProperty(XmlElement element, string attName, MutablePropertyValues properties, string propName) + if (nestedValidators.Count > 0) { - string test = GetAttributeValue(element, attName); - if (StringUtils.HasText(test)) - { - properties.Add(propName, test); - } + properties.Add("Validators", nestedValidators); } - /// - /// Parses and potentially registers a validator. - /// - /// - /// Only validators that have id attribute specified are registered - /// as separate object definitions within application context. - /// - /// Validator XML element. - /// The parser helper. - /// Validator object definition. - private IObjectDefinition ParseAndRegisterValidator(XmlElement element, ParserContext parserContext) + if (actions.Count > 0) { - string id = GetAttributeValue(element, ObjectDefinitionConstants.IdAttribute); - IObjectDefinition validator = ParseValidator(id, element, parserContext); - if (StringUtils.HasText(id)) - { - parserContext.ReaderContext.Registry.RegisterObjectDefinition(id, validator); - this.definitionCount++; - } - return validator; + properties.Add("Actions", actions); } - /// - /// Gets the name of the object type for the specified element. - /// - /// The element. - /// The name of the object type. - private string GetTypeName(XmlElement element) - { - string typeName = GetAttributeValue(element, ObjectDefinitionConstants.TypeAttribute); - if (StringUtils.IsNullOrEmpty(typeName)) - { - return ValidatorTypePrefix + element.LocalName; - } - return typeName; - } - - /// - /// Creates an error message action based on the specified message element. - /// - /// The message element. - /// The parser helper. - /// The error message action definition. - private static IObjectDefinition ParseErrorMessageAction(XmlElement message, ParserContext parserContext) - { - string messageId = GetAttributeValue(message, MessageConstants.IdAttribute); - string[] providers = GetAttributeValue(message, MessageConstants.ProvidersAttribute).Split(','); - List parameters = new List(); - - foreach (XmlElement param in message.ChildNodes) - { - IExpression paramExpression = Expression.Parse(GetAttributeValue(param, MessageConstants.ParameterValueAttribute)); - parameters.Add(paramExpression); - } - - string typeName = "Spring.Validation.Actions.ErrorMessageAction, Spring.Core"; - ConstructorArgumentValues ctorArgs = new ConstructorArgumentValues(); - ctorArgs.AddGenericArgumentValue(messageId); - ctorArgs.AddGenericArgumentValue(providers); - - string when = GetAttributeValue(message, ValidatorDefinitionConstants.WhenAttribute); - MutablePropertyValues properties = new MutablePropertyValues(); - if (StringUtils.HasText(when)) - { - properties.Add("When", when); - } - if (parameters.Count > 0) - { - properties.Add("Parameters", parameters.ToArray()); - } - - IConfigurableObjectDefinition action = - parserContext.ReaderContext.ObjectDefinitionFactory.CreateObjectDefinition(typeName, null, parserContext.ReaderContext.Reader.Domain); - action.ConstructorArgumentValues = ctorArgs; - action.PropertyValues = properties; - - return action; - } - - private IObjectDefinition ParseExceptionAction(XmlElement element, ParserContext parserContext) - { - string typeName = "Spring.Validation.Actions.ExceptionAction, Spring.Core"; - string throwExpression = GetAttributeValue(element, ValidatorDefinitionConstants.ThrowAttribute); - - - ConstructorArgumentValues ctorArgs = new ConstructorArgumentValues(); - ctorArgs.AddGenericArgumentValue(throwExpression); - - string when = GetAttributeValue(element, ValidatorDefinitionConstants.WhenAttribute); - MutablePropertyValues properties = new MutablePropertyValues(); - if (StringUtils.HasText(when)) - { - properties.Add("When", when); - } - - IConfigurableObjectDefinition action = - parserContext.ReaderContext.ObjectDefinitionFactory.CreateObjectDefinition(typeName, null, parserContext.ReaderContext.Reader.Domain); - action.ConstructorArgumentValues = ctorArgs; - action.PropertyValues = properties; - - return action; - } - - /// - /// Creates a generic action based on the specified element. - /// - /// The action definition element. - /// The parser helper. - /// Generic validation action definition. - private IObjectDefinition ParseGenericAction(XmlElement element, ParserContext parserContext) - { - string typeName = GetAttributeValue(element, ObjectDefinitionConstants.TypeAttribute); - string when = GetAttributeValue(element, ValidatorDefinitionConstants.WhenAttribute); - MutablePropertyValues properties = base.ParsePropertyElements("validator:action", element, parserContext); - if (StringUtils.HasText(when)) - { - properties.Add("When", when); - } - - IConfigurableObjectDefinition action = - parserContext.ReaderContext.ObjectDefinitionFactory.CreateObjectDefinition(typeName, null, parserContext.ReaderContext.Reader.Domain); - action.PropertyValues = properties; - - return action; - } - - /// - /// Creates object definition for the validator reference. - /// - /// The action definition element. - /// The parser helper. - /// Generic validation action definition. - private IObjectDefinition ParseValidatorReference(XmlElement element, ParserContext parserContext) - { - string typeName = "Spring.Validation.ValidatorReference, Spring.Core"; - string name = GetAttributeValue(element, ValidatorDefinitionConstants.ReferenceNameAttribute); - string context = GetAttributeValue(element, ValidatorDefinitionConstants.ReferenceContextAttribute); - string when = GetAttributeValue(element, ValidatorDefinitionConstants.WhenAttribute); - - MutablePropertyValues properties = new MutablePropertyValues(); - properties.Add("Name", name); - if (StringUtils.HasText(context)) - { - properties.Add("Context", context); - } - if (StringUtils.HasText(when)) - { - properties.Add("When", when); - } - - IConfigurableObjectDefinition reference = - parserContext.ReaderContext.ObjectDefinitionFactory.CreateObjectDefinition(typeName, null, parserContext.ReaderContext.Reader.Domain); - reference.PropertyValues = properties; - return reference; - } - - #region Element & Attribute Name Constants - - private class ValidatorDefinitionConstants - { - public const string PropertyElement = "property"; - public const string MessageElement = "message"; - public const string ActionElement = "action"; - public const string ExceptionElement = "exception"; - public const string ReferenceElement = "ref"; - - public const string TypeAttribute = "type"; - public const string TestAttribute = "test"; - public const string NameAttribute = "name"; - public const string WhenAttribute = "when"; - public const string ThrowAttribute = "throw"; - - public const string PropertyNameAttribute = "name"; - - public const string ReferenceNameAttribute = "name"; - public const string ReferenceContextAttribute = "context"; - - public const string RegexExpressionAttribute = "expression"; - - public const string GroupFastValidateAttribute = "fast-validate"; - - public const string CollectionValidateAllAttribute = "validate-all"; - public const string CollectionContextAttribute = "context"; - public const string CollectionIncludeElementsErrors = "include-element-errors"; - } - - private class MessageConstants - { - public const string ParamElement = "param"; - - public const string IdAttribute = "id"; - public const string ProvidersAttribute = "providers"; - public const string ParameterValueAttribute = "value"; - } - - #endregion + return od; } + + /// + /// Parses the attribute of the given from the XmlElement and, if available, adds a property of the given with + /// the parsed value. + /// + private void ParseAttributeIntoProperty(XmlElement element, string attName, MutablePropertyValues properties, string propName) + { + string test = GetAttributeValue(element, attName); + if (StringUtils.HasText(test)) + { + properties.Add(propName, test); + } + } + + /// + /// Parses and potentially registers a validator. + /// + /// + /// Only validators that have id attribute specified are registered + /// as separate object definitions within application context. + /// + /// Validator XML element. + /// The parser helper. + /// Validator object definition. + private IObjectDefinition ParseAndRegisterValidator(XmlElement element, ParserContext parserContext) + { + string id = GetAttributeValue(element, ObjectDefinitionConstants.IdAttribute); + IObjectDefinition validator = ParseValidator(id, element, parserContext); + if (StringUtils.HasText(id)) + { + parserContext.ReaderContext.Registry.RegisterObjectDefinition(id, validator); + this.definitionCount++; + } + + return validator; + } + + /// + /// Gets the name of the object type for the specified element. + /// + /// The element. + /// The name of the object type. + private string GetTypeName(XmlElement element) + { + string typeName = GetAttributeValue(element, ObjectDefinitionConstants.TypeAttribute); + if (StringUtils.IsNullOrEmpty(typeName)) + { + return ValidatorTypePrefix + element.LocalName; + } + + return typeName; + } + + /// + /// Creates an error message action based on the specified message element. + /// + /// The message element. + /// The parser helper. + /// The error message action definition. + private static IObjectDefinition ParseErrorMessageAction(XmlElement message, ParserContext parserContext) + { + string messageId = GetAttributeValue(message, MessageConstants.IdAttribute); + string[] providers = GetAttributeValue(message, MessageConstants.ProvidersAttribute).Split(','); + List parameters = new List(); + + foreach (XmlElement param in message.ChildNodes) + { + IExpression paramExpression = Expression.Parse(GetAttributeValue(param, MessageConstants.ParameterValueAttribute)); + parameters.Add(paramExpression); + } + + string typeName = "Spring.Validation.Actions.ErrorMessageAction, Spring.Core"; + ConstructorArgumentValues ctorArgs = new ConstructorArgumentValues(); + ctorArgs.AddGenericArgumentValue(messageId); + ctorArgs.AddGenericArgumentValue(providers); + + string when = GetAttributeValue(message, ValidatorDefinitionConstants.WhenAttribute); + MutablePropertyValues properties = new MutablePropertyValues(); + if (StringUtils.HasText(when)) + { + properties.Add("When", when); + } + + if (parameters.Count > 0) + { + properties.Add("Parameters", parameters.ToArray()); + } + + IConfigurableObjectDefinition action = + parserContext.ReaderContext.ObjectDefinitionFactory.CreateObjectDefinition(typeName, null, parserContext.ReaderContext.Reader.Domain); + action.ConstructorArgumentValues = ctorArgs; + action.PropertyValues = properties; + + return action; + } + + private IObjectDefinition ParseExceptionAction(XmlElement element, ParserContext parserContext) + { + string typeName = "Spring.Validation.Actions.ExceptionAction, Spring.Core"; + string throwExpression = GetAttributeValue(element, ValidatorDefinitionConstants.ThrowAttribute); + + ConstructorArgumentValues ctorArgs = new ConstructorArgumentValues(); + ctorArgs.AddGenericArgumentValue(throwExpression); + + string when = GetAttributeValue(element, ValidatorDefinitionConstants.WhenAttribute); + MutablePropertyValues properties = new MutablePropertyValues(); + if (StringUtils.HasText(when)) + { + properties.Add("When", when); + } + + IConfigurableObjectDefinition action = + parserContext.ReaderContext.ObjectDefinitionFactory.CreateObjectDefinition(typeName, null, parserContext.ReaderContext.Reader.Domain); + action.ConstructorArgumentValues = ctorArgs; + action.PropertyValues = properties; + + return action; + } + + /// + /// Creates a generic action based on the specified element. + /// + /// The action definition element. + /// The parser helper. + /// Generic validation action definition. + private IObjectDefinition ParseGenericAction(XmlElement element, ParserContext parserContext) + { + string typeName = GetAttributeValue(element, ObjectDefinitionConstants.TypeAttribute); + string when = GetAttributeValue(element, ValidatorDefinitionConstants.WhenAttribute); + MutablePropertyValues properties = base.ParsePropertyElements("validator:action", element, parserContext); + if (StringUtils.HasText(when)) + { + properties.Add("When", when); + } + + IConfigurableObjectDefinition action = + parserContext.ReaderContext.ObjectDefinitionFactory.CreateObjectDefinition(typeName, null, parserContext.ReaderContext.Reader.Domain); + action.PropertyValues = properties; + + return action; + } + + /// + /// Creates object definition for the validator reference. + /// + /// The action definition element. + /// The parser helper. + /// Generic validation action definition. + private IObjectDefinition ParseValidatorReference(XmlElement element, ParserContext parserContext) + { + string typeName = "Spring.Validation.ValidatorReference, Spring.Core"; + string name = GetAttributeValue(element, ValidatorDefinitionConstants.ReferenceNameAttribute); + string context = GetAttributeValue(element, ValidatorDefinitionConstants.ReferenceContextAttribute); + string when = GetAttributeValue(element, ValidatorDefinitionConstants.WhenAttribute); + + MutablePropertyValues properties = new MutablePropertyValues(); + properties.Add("Name", name); + if (StringUtils.HasText(context)) + { + properties.Add("Context", context); + } + + if (StringUtils.HasText(when)) + { + properties.Add("When", when); + } + + IConfigurableObjectDefinition reference = + parserContext.ReaderContext.ObjectDefinitionFactory.CreateObjectDefinition(typeName, null, parserContext.ReaderContext.Reader.Domain); + reference.PropertyValues = properties; + return reference; + } + + #region Element & Attribute Name Constants + + private class ValidatorDefinitionConstants + { + public const string PropertyElement = "property"; + public const string MessageElement = "message"; + public const string ActionElement = "action"; + public const string ExceptionElement = "exception"; + public const string ReferenceElement = "ref"; + + public const string TypeAttribute = "type"; + public const string TestAttribute = "test"; + public const string NameAttribute = "name"; + public const string WhenAttribute = "when"; + public const string ThrowAttribute = "throw"; + + public const string PropertyNameAttribute = "name"; + + public const string ReferenceNameAttribute = "name"; + public const string ReferenceContextAttribute = "context"; + + public const string RegexExpressionAttribute = "expression"; + + public const string GroupFastValidateAttribute = "fast-validate"; + + public const string CollectionValidateAllAttribute = "validate-all"; + public const string CollectionContextAttribute = "context"; + public const string CollectionIncludeElementsErrors = "include-element-errors"; + } + + private class MessageConstants + { + public const string ParamElement = "param"; + + public const string IdAttribute = "id"; + public const string ProvidersAttribute = "providers"; + public const string ParameterValueAttribute = "value"; + } + + #endregion } diff --git a/src/Spring/Spring.Core/Validation/Config/spring-validation-1.1.xsd b/src/Spring/Spring.Core/Validation/Config/spring-validation-1.1.xsd index b89886f2..4a5463a9 100644 --- a/src/Spring/Spring.Core/Validation/Config/spring-validation-1.1.xsd +++ b/src/Spring/Spring.Core/Validation/Config/spring-validation-1.1.xsd @@ -1,13 +1,15 @@  + xmlns:objects="http://www.springframework.net" + xmlns:xs="http://www.w3.org/2001/XMLSchema" + xmlns:vs="http://schemas.microsoft.com/Visual-Studio-Intellisense" + targetNamespace="http://www.springframework.net/validation" + elementFormDefault="qualified" attributeFormDefault="unqualified" + vs:friendlyname="Spring.NET Validation Framework Configuration" vs:ishtmlschema="false" + vs:iscasesensitive="true" vs:requireattributequotes="true" vs:defaultnamespacequalifier="" + vs:defaultnsprefix=""> - + @@ -28,18 +30,18 @@ Defines a message type. - + - - - + + + Defines a message parameter type. - + @@ -47,18 +49,18 @@ Defines an action type. - + - - + + Defines a validator reference type. - - + + @@ -66,13 +68,13 @@ Defines base validator type. - - + + - - - - + + + + @@ -80,15 +82,15 @@ Defines a generic validator type. - - - + + + - - - - - + + + + + @@ -96,14 +98,14 @@ Defines a regex validator type. - - - + + + - - - - + + + + @@ -112,25 +114,25 @@ - - + + - - - + + + - - - - - + + + + + - + - - - + + + @@ -139,21 +141,21 @@ - - - + + + - - - - + + + + - - - - + + + + diff --git a/src/Spring/Spring.Core/Validation/Config/spring-validation-1.3.xsd b/src/Spring/Spring.Core/Validation/Config/spring-validation-1.3.xsd index 82dec005..3952862b 100644 --- a/src/Spring/Spring.Core/Validation/Config/spring-validation-1.3.xsd +++ b/src/Spring/Spring.Core/Validation/Config/spring-validation-1.3.xsd @@ -1,13 +1,15 @@  + xmlns:objects="http://www.springframework.net" + xmlns:xs="http://www.w3.org/2001/XMLSchema" + xmlns:vs="http://schemas.microsoft.com/Visual-Studio-Intellisense" + targetNamespace="http://www.springframework.net/validation" + elementFormDefault="qualified" attributeFormDefault="unqualified" + vs:friendlyname="Spring.NET Validation Framework Configuration v" vs:ishtmlschema="false" + vs:iscasesensitive="true" vs:requireattributequotes="true" vs:defaultnamespacequalifier="v" + vs:defaultnsprefix="v"> - + @@ -25,17 +27,20 @@ - + + - + + - + + @@ -48,12 +53,14 @@ - + + - + + @@ -63,7 +70,7 @@ - + @@ -72,25 +79,29 @@ - + + - - - - - + + - - - - - - + + + + + + + + + + + + @@ -104,13 +115,15 @@ - + + - - - + + + + @@ -119,33 +132,36 @@ Defines common validator attributes and elements. - + - - + + - + + - + - + + - + - + + - + @@ -158,7 +174,8 @@ - + + @@ -174,9 +191,10 @@ - + + - + @@ -191,7 +209,9 @@ - The regular expression to match the result of evaluation the 'test' expression against. + The regular expression to match the result of evaluation the 'test' expression + against. + @@ -209,10 +229,10 @@ - + - + @@ -220,9 +240,10 @@ - + + - + @@ -237,17 +258,22 @@ - Whether to force validating all collection elements, regardless of errors. This attribute is just an alias for 'fast-validate' and kept for backwards compatibility. + Whether to force validating all collection elements, regardless of errors. + This attribute is just an alias for 'fast-validate' and kept for backwards compatibility. + - Whether to include individual element's error messages in the resulting list of messages. + Whether to include individual element's error messages in the resulting list + of messages. + - an SpEL expression to narrow the validation context for each element + an SpEL expression to narrow the validation context for each element + @@ -256,7 +282,8 @@ - Defines a custom validator, allowing to specify the CLR typename of the validator class. + Defines a custom validator, allowing to specify the CLR typename of the validator class. + diff --git a/src/Spring/Spring.Core/Validation/ErrorMessage.cs b/src/Spring/Spring.Core/Validation/ErrorMessage.cs index b10a049c..353def3f 100644 --- a/src/Spring/Spring.Core/Validation/ErrorMessage.cs +++ b/src/Spring/Spring.Core/Validation/ErrorMessage.cs @@ -23,192 +23,193 @@ using System.Xml.Schema; using System.Xml.Serialization; using Spring.Context; -namespace Spring.Validation +namespace Spring.Validation; + +/// +/// Represents a single validation error message. +/// +/// Aleksandar Seovic +/// Goran Milosavljevic +[Serializable] +public class ErrorMessage : IXmlSerializable { + #region Constructors + /// - /// Represents a single validation error message. + /// Default constructor. /// - /// Aleksandar Seovic - /// Goran Milosavljevic - [Serializable] - public class ErrorMessage : IXmlSerializable + public ErrorMessage() { - #region Constructors + } - /// - /// Default constructor. - /// - public ErrorMessage() - {} + /// + /// Initializes a new instance of the class. + /// + /// Error message resource identifier. + /// Parameters that should be used for message resolution. + public ErrorMessage(string id, params object[] parameters) + { + this.id = id; + this.parameters = parameters; + } - /// - /// Initializes a new instance of the class. - /// - /// Error message resource identifier. - /// Parameters that should be used for message resolution. - public ErrorMessage(string id, params object[] parameters) + /// + /// Initializes a new instance of the class copying values from another instance. + /// + /// Another Error message instance to copy values from. + protected ErrorMessage(ErrorMessage other) + { + this.id = other.id; + this.parameters = other.parameters; + } + + #endregion + + #region Properties + + /// + /// Gets or sets the resource identifier for this message. + /// + /// The resource identifier for this message. + public string Id + { + get { return id; } + } + + /// + /// Gets or sets the message parameters. + /// + /// The message parameters. + public object[] Parameters + { + get { return parameters; } + } + + #endregion + + #region IXmlSerializable implementations + + /// + /// This property is reserved, apply the + /// + /// to the class instead. + /// + /// + /// An + /// that describes the XML representation of the object that + /// is produced by the + /// + /// method and consumed by the + /// + /// method. + /// + /// + public XmlSchema GetSchema() + { + return null; + } + + /// + /// Generates an object from its XML representation. + /// + /// + /// The stream + /// from which the object is deserialized. + /// + public virtual void ReadXml(XmlReader reader) + { + id = reader.GetAttribute("Id"); + if (!reader.IsEmptyElement) { - this.id = id; - this.parameters = parameters; - } - - /// - /// Initializes a new instance of the class copying values from another instance. - /// - /// Another Error message instance to copy values from. - protected ErrorMessage(ErrorMessage other) - { - this.id = other.id; - this.parameters = other.parameters; - } - - #endregion - - #region Properties - - /// - /// Gets or sets the resource identifier for this message. - /// - /// The resource identifier for this message. - public string Id - { - get { return id; } - } - - /// - /// Gets or sets the message parameters. - /// - /// The message parameters. - public object[] Parameters - { - get { return parameters; } - } - - #endregion - - #region IXmlSerializable implementations - - /// - /// This property is reserved, apply the - /// - /// to the class instead. - /// - /// - /// An - /// that describes the XML representation of the object that - /// is produced by the - /// - /// method and consumed by the - /// - /// method. - /// - /// - public XmlSchema GetSchema() - { - return null; - } - - /// - /// Generates an object from its XML representation. - /// - /// - /// The stream - /// from which the object is deserialized. - /// - public virtual void ReadXml(XmlReader reader) - { - id = reader.GetAttribute("Id"); - if (!reader.IsEmptyElement) - { - reader.Read(); - reader.Read(); - XmlSerializer xs = new XmlSerializer(typeof(object[])); - parameters = (object[])xs.Deserialize(reader); - reader.Read(); - } + reader.Read(); + reader.Read(); + XmlSerializer xs = new XmlSerializer(typeof(object[])); + parameters = (object[]) xs.Deserialize(reader); reader.Read(); } - /// - /// Converts an object into its XML representation. - /// - /// - /// The stream - /// to which the object is serialized. - /// - public virtual void WriteXml(XmlWriter writer) - { - writer.WriteAttributeString("Id", id); - - if (parameters != null) - { - writer.WriteStartElement("Parameters"); - - XmlSerializer xs = new XmlSerializer(parameters.GetType()); - xs.Serialize(writer, parameters); - - writer.WriteEndElement(); - } - } - - #endregion - - #region ErrorMessage methods - - /// - /// Resolves the message against specified . - /// - /// Message source to resolve this error message against. - /// Resolved error message. - public string GetMessage(IMessageSource messageSource) - { - if (messageSource == null) - { - return Id; - } - - if (Parameters == null) - { - return messageSource.GetMessage(Id); - } - else - { - return messageSource.GetMessage(Id, Parameters); - } - } - - #endregion - - /// - ///Determines whether the specified is equal to the current . - /// - /// - ///true if the specified is equal to the current ; otherwise, false. - /// - ///The to compare with the current . 2 - public override bool Equals(object obj) - { - ErrorMessage other = obj as ErrorMessage; - return (other != null) - && (this.id == other.Id); - } - - /// - ///Serves as a hash function for a particular type. is suitable for use in hashing algorithms and data structures like a hash table. - /// - /// - ///A hash code for the current . - /// - public override int GetHashCode() - { - return id.GetHashCode(); - } - - #region Data members - - private string id; - private object[] parameters; - - #endregion + reader.Read(); } + + /// + /// Converts an object into its XML representation. + /// + /// + /// The stream + /// to which the object is serialized. + /// + public virtual void WriteXml(XmlWriter writer) + { + writer.WriteAttributeString("Id", id); + + if (parameters != null) + { + writer.WriteStartElement("Parameters"); + + XmlSerializer xs = new XmlSerializer(parameters.GetType()); + xs.Serialize(writer, parameters); + + writer.WriteEndElement(); + } + } + + #endregion + + #region ErrorMessage methods + + /// + /// Resolves the message against specified . + /// + /// Message source to resolve this error message against. + /// Resolved error message. + public string GetMessage(IMessageSource messageSource) + { + if (messageSource == null) + { + return Id; + } + + if (Parameters == null) + { + return messageSource.GetMessage(Id); + } + else + { + return messageSource.GetMessage(Id, Parameters); + } + } + + #endregion + + /// + ///Determines whether the specified is equal to the current . + /// + /// + ///true if the specified is equal to the current ; otherwise, false. + /// + ///The to compare with the current . 2 + public override bool Equals(object obj) + { + ErrorMessage other = obj as ErrorMessage; + return (other != null) + && (this.id == other.Id); + } + + /// + ///Serves as a hash function for a particular type. is suitable for use in hashing algorithms and data structures like a hash table. + /// + /// + ///A hash code for the current . + /// + public override int GetHashCode() + { + return id.GetHashCode(); + } + + #region Data members + + private string id; + private object[] parameters; + + #endregion } diff --git a/src/Spring/Spring.Core/Validation/ExclusiveValidatorGroup.cs b/src/Spring/Spring.Core/Validation/ExclusiveValidatorGroup.cs index 71397925..93bf9434 100644 --- a/src/Spring/Spring.Core/Validation/ExclusiveValidatorGroup.cs +++ b/src/Spring/Spring.Core/Validation/ExclusiveValidatorGroup.cs @@ -20,95 +20,93 @@ using Spring.Expressions; -namespace Spring.Validation +namespace Spring.Validation; + +/// +/// implementation that supports grouping of validators. +/// +/// +///

+/// This validator will be valid when one and only one of the validators in the Validators collection are valid +///

+///

+/// ValidationErrors property will return a union of all validation error messages +/// for the contained validators, but only if this validator is not valid (meaning, when none +/// of the contained validators are valid). +///

+///

+/// By default, this validator group uses == true semantics. +///

+///
+/// Aleksandar Seovic +/// Erich Eichinger +public class ExclusiveValidatorGroup : BaseValidatorGroup { + #region Constructors + /// - /// implementation that supports grouping of validators. + /// Initializes a new instance of the class. /// - /// - ///

- /// This validator will be valid when one and only one of the validators in the Validators collection are valid - ///

- ///

- /// ValidationErrors property will return a union of all validation error messages - /// for the contained validators, but only if this validator is not valid (meaning, when none - /// of the contained validators are valid). - ///

- ///

- /// By default, this validator group uses == true semantics. - ///

- ///
- /// Aleksandar Seovic - /// Erich Eichinger - public class ExclusiveValidatorGroup : BaseValidatorGroup + public ExclusiveValidatorGroup() { - #region Constructors + this.FastValidate = true; + } - /// - /// Initializes a new instance of the class. - /// - public ExclusiveValidatorGroup() + /// + /// Initializes a new instance of the class. + /// + /// The expression that determines if this validator should be evaluated. + public ExclusiveValidatorGroup(string when) + : base(when) + { + this.FastValidate = true; + } + + /// + /// Initializes a new instance of the class. + /// + /// The expression that determines if this validator should be evaluated. + public ExclusiveValidatorGroup(IExpression when) + : base(when) + { + this.FastValidate = true; + } + + #endregion + + /// + /// Actual implementation how to validate the specified object. + /// + /// Additional context parameters. + /// instance to add error messages to. + /// The object to validate. + /// True if validation was successful, False otherwise. + protected override bool ValidateGroup(IDictionary contextParams, IValidationErrors errors, object validationContext) + { + ValidationErrors tmpErrors = new ValidationErrors(); + bool valid = false; + foreach (IValidator validator in Validators) { - this.FastValidate = true; - } - - /// - /// Initializes a new instance of the class. - /// - /// The expression that determines if this validator should be evaluated. - public ExclusiveValidatorGroup(string when) - : base(when) - { - this.FastValidate = true; - } - - /// - /// Initializes a new instance of the class. - /// - /// The expression that determines if this validator should be evaluated. - public ExclusiveValidatorGroup(IExpression when) - : base(when) - { - this.FastValidate = true; - } - - #endregion - - /// - /// Actual implementation how to validate the specified object. - /// - /// Additional context parameters. - /// instance to add error messages to. - /// The object to validate. - /// True if validation was successful, False otherwise. - protected override bool ValidateGroup(IDictionary contextParams, IValidationErrors errors, object validationContext) - { - ValidationErrors tmpErrors = new ValidationErrors(); - bool valid = false; - foreach (IValidator validator in Validators) + bool tmpValid = validator.Validate(validationContext, contextParams, tmpErrors); + if (valid && tmpValid) { - bool tmpValid = validator.Validate(validationContext, contextParams, tmpErrors); - if (valid && tmpValid) + valid = false; + if (this.FastValidate) { - valid = false; - if (this.FastValidate) - { - break; - } - } - else if (tmpValid) - { - valid = true; + break; } } - - if (!valid) + else if (tmpValid) { - errors.MergeErrors(tmpErrors); + valid = true; } - - return valid; } + if (!valid) + { + errors.MergeErrors(tmpErrors); + } + + return valid; } } diff --git a/src/Spring/Spring.Core/Validation/IValidationAction.cs b/src/Spring/Spring.Core/Validation/IValidationAction.cs index 173fbf03..004e55d9 100644 --- a/src/Spring/Spring.Core/Validation/IValidationAction.cs +++ b/src/Spring/Spring.Core/Validation/IValidationAction.cs @@ -20,31 +20,30 @@ using Spring.Validation.Actions; -namespace Spring.Validation +namespace Spring.Validation; + +/// +/// An action that should be executed after validator is evaluated. +/// +/// +///

+/// This interface allows us to define the actions that should be executed +/// after validation in a generic fashion. +///

+///

+/// For example, addition of error messages to validation errors collection +/// is performed by one specific implementation of this interface, . +///

+///
+/// Aleksandar Seovic +public interface IValidationAction { /// - /// An action that should be executed after validator is evaluated. + /// Executes the action. /// - /// - ///

- /// This interface allows us to define the actions that should be executed - /// after validation in a generic fashion. - ///

- ///

- /// For example, addition of error messages to validation errors collection - /// is performed by one specific implementation of this interface, . - ///

- ///
- /// Aleksandar Seovic - public interface IValidationAction - { - /// - /// Executes the action. - /// - /// Whether associated validator is valid or not. - /// Validation context. - /// Additional context parameters. - /// Validation errors container. - void Execute(bool isValid, object validationContext, IDictionary contextParams, IValidationErrors errors); - } + /// Whether associated validator is valid or not. + /// Validation context. + /// Additional context parameters. + /// Validation errors container. + void Execute(bool isValid, object validationContext, IDictionary contextParams, IValidationErrors errors); } diff --git a/src/Spring/Spring.Core/Validation/IValidationErrors.cs b/src/Spring/Spring.Core/Validation/IValidationErrors.cs index c552bb64..8bed88a1 100644 --- a/src/Spring/Spring.Core/Validation/IValidationErrors.cs +++ b/src/Spring/Spring.Core/Validation/IValidationErrors.cs @@ -1,88 +1,87 @@ using Spring.Context; -namespace Spring.Validation +namespace Spring.Validation; + +/// +/// An interface that validation errors containers have to implement. +/// +/// Aleksandar Seovic +public interface IValidationErrors { /// - /// An interface that validation errors containers have to implement. + /// Does this instance contain any validation errors? /// - /// Aleksandar Seovic - public interface IValidationErrors - { - /// - /// Does this instance contain any validation errors? - /// - /// - ///

- /// If this returns , this means that it (obviously) - /// contains no validation errors. - ///

- ///
- /// if this instance is empty. - bool IsEmpty { get; } + /// + ///

+ /// If this returns , this means that it (obviously) + /// contains no validation errors. + ///

+ ///
+ /// if this instance is empty. + bool IsEmpty { get; } - /// - /// Gets the list of all error providers. - /// - IList Providers { get; } + /// + /// Gets the list of all error providers. + /// + IList Providers { get; } - /// - /// Adds the supplied to this - /// instance's collection of errors. - /// - /// - /// The provider that should be used for message grouping; can't be - /// . - /// - /// The error message to add. - /// - /// If the supplied or is . - /// - void AddError(string provider, ErrorMessage message); + /// + /// Adds the supplied to this + /// instance's collection of errors. + /// + /// + /// The provider that should be used for message grouping; can't be + /// . + /// + /// The error message to add. + /// + /// If the supplied or is . + /// + void AddError(string provider, ErrorMessage message); - /// - /// Merges another instance of into this one. - /// - /// - ///

- /// If the supplied is , - /// then no errors will be added to this instance, and this method will - /// (silently) return. - ///

- ///
- /// - /// The validation errors to merge; can be . - /// - void MergeErrors(IValidationErrors errorsToMerge); + /// + /// Merges another instance of into this one. + /// + /// + ///

+ /// If the supplied is , + /// then no errors will be added to this instance, and this method will + /// (silently) return. + ///

+ ///
+ /// + /// The validation errors to merge; can be . + /// + void MergeErrors(IValidationErrors errorsToMerge); - /// - /// Gets the list of errors for the supplied error . - /// - /// - ///

- /// If there are no errors for the supplied , - /// an empty will be returned. - ///

- ///
- /// Error key that was used to group messages. - /// - /// A list of all s for the supplied lookup . - /// - IList GetErrors(string provider); + /// + /// Gets the list of errors for the supplied error . + /// + /// + ///

+ /// If there are no errors for the supplied , + /// an empty will be returned. + ///

+ ///
+ /// Error key that was used to group messages. + /// + /// A list of all s for the supplied lookup . + /// + IList GetErrors(string provider); - /// - /// Gets the list of resolved error messages for the supplied lookup . - /// - /// - ///

- /// If there are no errors for the supplied lookup , - /// an empty will be returned. - ///

- ///
- /// Error key that was used to group messages. - /// to resolve messages against. - /// - /// A list of resolved error messages for the supplied lookup . - /// - IList GetResolvedErrors(string provider, IMessageSource messageSource); - } + /// + /// Gets the list of resolved error messages for the supplied lookup . + /// + /// + ///

+ /// If there are no errors for the supplied lookup , + /// an empty will be returned. + ///

+ ///
+ /// Error key that was used to group messages. + /// to resolve messages against. + /// + /// A list of resolved error messages for the supplied lookup . + /// + IList GetResolvedErrors(string provider, IMessageSource messageSource); } diff --git a/src/Spring/Spring.Core/Validation/IValidator.cs b/src/Spring/Spring.Core/Validation/IValidator.cs index b2869753..85e04d4a 100644 --- a/src/Spring/Spring.Core/Validation/IValidator.cs +++ b/src/Spring/Spring.Core/Validation/IValidator.cs @@ -18,58 +18,56 @@ #endregion -namespace Spring.Validation +namespace Spring.Validation; + +/// +/// An object that can validate application-specific objects. +/// +/// +///

+/// The primary motivation for this interface is to enable validation to be +/// decoupled from the (user) interface and placed in business objects. +///

+///

+/// Application developers writing their own custom +/// implementations will +/// typically not implement this interface directly. In most cases, custom +/// validators woud be better served deriving from the +/// class, with the +/// custom validation ligic being implemented in an override of the +/// +/// +/// template method. +///

+///
+/// Aleksandar Seovic +/// +public interface IValidator { /// - /// An object that can validate application-specific objects. + /// Validates the specified object. /// - /// - ///

- /// The primary motivation for this interface is to enable validation to be - /// decoupled from the (user) interface and placed in business objects. - ///

- ///

- /// Application developers writing their own custom - /// implementations will - /// typically not implement this interface directly. In most cases, custom - /// validators woud be better served deriving from the - /// class, with the - /// custom validation ligic being implemented in an override of the - /// - /// - /// template method. - ///

- ///
- /// Aleksandar Seovic - /// - public interface IValidator - { - /// - /// Validates the specified object. - /// - /// The object to validate. - /// - /// The instance to add any error - /// messages to in the case of validation failure. - /// - /// - /// if validation was successful. - /// - bool Validate(object validationContext, IValidationErrors errors); + /// The object to validate. + /// + /// The instance to add any error + /// messages to in the case of validation failure. + /// + /// + /// if validation was successful. + /// + bool Validate(object validationContext, IValidationErrors errors); - /// - /// Validates the specified object. - /// - /// The object to validate. - /// Additional context parameters. - /// - /// The instance to add any error - /// messages to in the case of validation failure. - /// - /// - /// if validation was successful. - /// - bool Validate(object validationContext, IDictionary contextParams, IValidationErrors errors); - - } -} + /// + /// Validates the specified object. + /// + /// The object to validate. + /// Additional context parameters. + /// + /// The instance to add any error + /// messages to in the case of validation failure. + /// + /// + /// if validation was successful. + /// + bool Validate(object validationContext, IDictionary contextParams, IValidationErrors errors); +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Validation/ValidatedAttribute.cs b/src/Spring/Spring.Core/Validation/ValidatedAttribute.cs index b1950a2b..d27f47bd 100644 --- a/src/Spring/Spring.Core/Validation/ValidatedAttribute.cs +++ b/src/Spring/Spring.Core/Validation/ValidatedAttribute.cs @@ -1,36 +1,35 @@ -namespace Spring.Validation +namespace Spring.Validation; + +/// +/// Allows developers to specify which validator should be used +/// to validate method argument. +/// +/// Damjan Tomic +/// Aleksandar Seovic +[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = true)] +[Serializable] +public class ValidatedAttribute : Attribute { + private readonly string validatorName; + /// - /// Allows developers to specify which validator should be used - /// to validate method argument. + /// Creates an attribute instance. /// - /// Damjan Tomic - /// Aleksandar Seovic - [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = true)] - [Serializable] - public class ValidatedAttribute : Attribute + /// + /// The name of the validator to use (must be defined within + /// Spring application context). + /// + public ValidatedAttribute(string validatorName) { - private readonly string validatorName; + this.validatorName = validatorName; + } - /// - /// Creates an attribute instance. - /// - /// - /// The name of the validator to use (must be defined within - /// Spring application context). - /// - public ValidatedAttribute(string validatorName) - { - this.validatorName = validatorName; - } - - /// - /// Gets the name of the validator to use. - /// - /// The name of the validator to use. - public string ValidatorName - { - get { return validatorName; } - } + /// + /// Gets the name of the validator to use. + /// + /// The name of the validator to use. + public string ValidatorName + { + get { return validatorName; } } } diff --git a/src/Spring/Spring.Core/Validation/ValidationErrors.cs b/src/Spring/Spring.Core/Validation/ValidationErrors.cs index 9ffe5b19..48258297 100644 --- a/src/Spring/Spring.Core/Validation/ValidationErrors.cs +++ b/src/Spring/Spring.Core/Validation/ValidationErrors.cs @@ -24,200 +24,203 @@ using System.Xml.Serialization; using Spring.Context; using Spring.Util; -namespace Spring.Validation +namespace Spring.Validation; + +/// +/// A container for validation errors. +/// +/// +///

+/// This class groups validation errors by validator names and allows +/// access to both the complete errors collection and to the errors for a +/// certain validator. +///

+///
+/// Aleksandar Seovic +/// Goran Milosavljevic +[Serializable] +public class ValidationErrors : IValidationErrors, IXmlSerializable { + #region Constructors + /// - /// A container for validation errors. + /// Default constructor. + /// + public ValidationErrors() + { + } + + #endregion + + #region IXmlSerializable implementations + + /// + /// This property is reserved, apply the + /// + /// to the class instead. + /// + /// + /// An that describes the + /// XML representation of the object that is produced by + /// the + /// method and consumed by the + /// + /// method. + /// + public XmlSchema GetSchema() + { + return null; + } + + /// + /// Generates an object from its XML representation. + /// + /// + /// The stream + /// from which the object is deserialized. + /// + public void ReadXml(XmlReader reader) + { + if (!reader.IsEmptyElement) + { + reader.Read(); + while (reader.Name == "Provider") + { + string key = reader.GetAttribute("Id"); + reader.Read(); + while (reader.Name == "ErrorMessage") + { + XmlSerializer xs = new XmlSerializer(typeof(ErrorMessage)); + ErrorMessage value = (ErrorMessage) xs.Deserialize(reader); + + List mapValue; + + if (!errorMap.TryGetValue(key, out mapValue)) + { + mapValue = new List(); + errorMap[key] = mapValue; + } + + mapValue.Add(value); + } + + reader.Read(); + } + } + } + + /// + /// Converts an object into its XML representation. + /// + /// + /// The stream + /// to which the object is serialized. + /// + public void WriteXml(XmlWriter writer) + { + foreach (KeyValuePair> entry in errorMap) + { + writer.WriteStartElement("Provider"); + writer.WriteAttributeString("Id", entry.Key); + + if (entry.Value != null) + { + IList errorsList = entry.Value; + foreach (ErrorMessage error in errorsList) + { + XmlSerializer xs = new XmlSerializer(typeof(ErrorMessage)); + xs.Serialize(writer, error); + } + } + + writer.WriteEndElement(); + } + } + + #endregion + + #region ValidationErrors methods + + /// + /// Does this instance contain any validation errors? /// /// ///

- /// This class groups validation errors by validator names and allows - /// access to both the complete errors collection and to the errors for a - /// certain validator. + /// If this returns , this means that it (obviously) + /// contains no validation errors. ///

///
- /// Aleksandar Seovic - /// Goran Milosavljevic - [Serializable] - public class ValidationErrors : IValidationErrors, IXmlSerializable + /// if this instance is empty. + public bool IsEmpty { - #region Constructors + get { return this.errorMap.Count == 0; } + } - /// - /// Default constructor. - /// - public ValidationErrors() - {} + /// + /// Gets the list of all providers. + /// + public IList Providers + { + get { return new List(this.errorMap.Keys); } + } - #endregion + /// + /// Adds the supplied to this + /// instance's collection of errors. + /// + /// + /// The provider that should be used for message grouping; can't be + /// . + /// + /// The error message to add. + /// + /// If the supplied or is . + /// + public void AddError(string provider, ErrorMessage message) + { + AssertUtils.ArgumentNotNull(provider, "provider"); + AssertUtils.ArgumentNotNull(message, "errorMessage"); - #region IXmlSerializable implementations - - /// - /// This property is reserved, apply the - /// - /// to the class instead. - /// - /// - /// An that describes the - /// XML representation of the object that is produced by - /// the - /// method and consumed by the - /// - /// method. - /// - public XmlSchema GetSchema() + List errors; + if (!errorMap.TryGetValue(provider, out errors)) { - return null; + errors = new List(); + errorMap[provider] = errors; } - /// - /// Generates an object from its XML representation. - /// - /// - /// The stream - /// from which the object is deserialized. - /// - public void ReadXml(XmlReader reader) + errors.Add(message); + } + + /// + /// Merges another instance of into this one. + /// + /// + ///

+ /// If the supplied is , + /// then no errors will be added to this instance, and this method will + /// (silently) return. + ///

+ ///
+ /// + /// The validation errors to merge; can be . + /// + public void MergeErrors(IValidationErrors errorsToMerge) + { + if (errorsToMerge != null) { - if (!reader.IsEmptyElement) + foreach (string provider in errorsToMerge.Providers) { - reader.Read(); - while (reader.Name == "Provider") + List errList; + List other = new List(errorsToMerge.GetErrors(provider)); + if (!errorMap.TryGetValue(provider, out errList)) { - string key = reader.GetAttribute("Id"); - reader.Read(); - while (reader.Name == "ErrorMessage") - { - XmlSerializer xs = new XmlSerializer(typeof(ErrorMessage)); - ErrorMessage value = (ErrorMessage) xs.Deserialize(reader); - - List mapValue; - - if (!errorMap.TryGetValue(key, out mapValue)) - { - mapValue = new List(); - errorMap[key] = mapValue; - } - - mapValue.Add(value); - } - reader.Read(); + this.errorMap[provider] = other; + } + else + { + errList.AddRange(other); } } - } - - /// - /// Converts an object into its XML representation. - /// - /// - /// The stream - /// to which the object is serialized. - /// - public void WriteXml(XmlWriter writer) - { - foreach (KeyValuePair> entry in errorMap) - { - writer.WriteStartElement("Provider"); - writer.WriteAttributeString("Id", entry.Key); - - if (entry.Value != null) - { - IList errorsList = entry.Value; - foreach (ErrorMessage error in errorsList) - { - XmlSerializer xs = new XmlSerializer(typeof(ErrorMessage)); - xs.Serialize(writer, error); - } - } - - writer.WriteEndElement(); - } - } - - #endregion - - #region ValidationErrors methods - - /// - /// Does this instance contain any validation errors? - /// - /// - ///

- /// If this returns , this means that it (obviously) - /// contains no validation errors. - ///

- ///
- /// if this instance is empty. - public bool IsEmpty - { - get { return this.errorMap.Count == 0; } - } - - /// - /// Gets the list of all providers. - /// - public IList Providers - { - get { return new List(this.errorMap.Keys); } - } - - /// - /// Adds the supplied to this - /// instance's collection of errors. - /// - /// - /// The provider that should be used for message grouping; can't be - /// . - /// - /// The error message to add. - /// - /// If the supplied or is . - /// - public void AddError(string provider, ErrorMessage message) - { - AssertUtils.ArgumentNotNull(provider, "provider"); - AssertUtils.ArgumentNotNull(message, "errorMessage"); - - List errors; - if (!errorMap.TryGetValue(provider, out errors)) - { - errors = new List(); - errorMap[provider] = errors; - } - errors.Add(message); - } - - /// - /// Merges another instance of into this one. - /// - /// - ///

- /// If the supplied is , - /// then no errors will be added to this instance, and this method will - /// (silently) return. - ///

- ///
- /// - /// The validation errors to merge; can be . - /// - public void MergeErrors(IValidationErrors errorsToMerge) - { - if (errorsToMerge != null) - { - foreach(string provider in errorsToMerge.Providers) - { - List errList; - List other = new List(errorsToMerge.GetErrors(provider)); - if (!errorMap.TryGetValue(provider, out errList)) - { - this.errorMap[provider] = other; - } - else - { - errList.AddRange(other); - } - } // foreach (DictionaryEntry errorEntry in errorsToMerge.errorMap) // { // ArrayList errList = (ArrayList) this.errorMap[errorEntry.Key]; @@ -230,66 +233,65 @@ namespace Spring.Validation // errList.AddRange((IList) errorEntry.Value); // } // } - } } - - /// - /// Gets the list of errors for the supplied lookup . - /// - /// - ///

- /// If there are no errors for the supplied lookup , - /// an empty will be returned. - ///

- ///
- /// Error key that was used to group messages. - /// - /// A list of all s for the supplied lookup . - /// - public IList GetErrors(string provider) - { - List errors; - errorMap.TryGetValue(provider, out errors); - return errors ?? new List(0); - } - - /// - /// Gets the list of resolved error messages for the supplied lookup . - /// - /// - ///

- /// If there are no errors for the supplied lookup , - /// an empty will be returned. - ///

- ///
- /// Error key that was used to group messages. - /// to resolve messages against. - /// - /// A list of resolved error messages for the supplied lookup . - /// - public IList GetResolvedErrors(string provider, IMessageSource messageSource) - { - AssertUtils.ArgumentNotNull(provider, "provider"); - - IList messages = new List(); - List errors; - if (errorMap.TryGetValue(provider, out errors)) - { - foreach (ErrorMessage error in errors) - { - messages.Add(error.GetMessage(messageSource)); - } - } - - return messages; - } - - #endregion - - #region Data members - - private readonly IDictionary> errorMap = new Dictionary>(); - - #endregion } + + /// + /// Gets the list of errors for the supplied lookup . + /// + /// + ///

+ /// If there are no errors for the supplied lookup , + /// an empty will be returned. + ///

+ ///
+ /// Error key that was used to group messages. + /// + /// A list of all s for the supplied lookup . + /// + public IList GetErrors(string provider) + { + List errors; + errorMap.TryGetValue(provider, out errors); + return errors ?? new List(0); + } + + /// + /// Gets the list of resolved error messages for the supplied lookup . + /// + /// + ///

+ /// If there are no errors for the supplied lookup , + /// an empty will be returned. + ///

+ ///
+ /// Error key that was used to group messages. + /// to resolve messages against. + /// + /// A list of resolved error messages for the supplied lookup . + /// + public IList GetResolvedErrors(string provider, IMessageSource messageSource) + { + AssertUtils.ArgumentNotNull(provider, "provider"); + + IList messages = new List(); + List errors; + if (errorMap.TryGetValue(provider, out errors)) + { + foreach (ErrorMessage error in errors) + { + messages.Add(error.GetMessage(messageSource)); + } + } + + return messages; + } + + #endregion + + #region Data members + + private readonly IDictionary> errorMap = new Dictionary>(); + + #endregion } diff --git a/src/Spring/Spring.Core/Validation/ValidationException.cs b/src/Spring/Spring.Core/Validation/ValidationException.cs index 4e4bfee1..08492643 100644 --- a/src/Spring/Spring.Core/Validation/ValidationException.cs +++ b/src/Spring/Spring.Core/Validation/ValidationException.cs @@ -20,140 +20,139 @@ using System.Runtime.Serialization; -namespace Spring.Validation +namespace Spring.Validation; + +/// +/// Thrown by the validation advice if the method parameters validation fails. +/// +/// Aleksandar Seovic +[Serializable] +public class ValidationException : Exception { + private readonly IValidationErrors errors; + /// - /// Thrown by the validation advice if the method parameters validation fails. + /// Creates a new instance of the ValidationException class. /// - /// Aleksandar Seovic - [Serializable] - public class ValidationException : Exception + public ValidationException() { - private readonly IValidationErrors errors; + } - /// - /// Creates a new instance of the ValidationException class. - /// - public ValidationException() - { - } + /// + /// Creates a new instance of the ValidationException class with + /// specified validation errors. + /// + /// + /// Validation errors. + /// + public ValidationException(IValidationErrors errors) + { + this.errors = errors; + } - /// - /// Creates a new instance of the ValidationException class with - /// specified validation errors. - /// - /// - /// Validation errors. - /// - public ValidationException(IValidationErrors errors) - { - this.errors = errors; - } + /// + /// Creates a new instance of the ValidationException class with the + /// specified message. + /// + /// + /// A message about the exception. + /// + public ValidationException(string message) + : base(message) + { + } - /// - /// Creates a new instance of the ValidationException class with the - /// specified message. - /// - /// - /// A message about the exception. - /// - public ValidationException(string message) - : base(message) - { - } + /// + /// Creates a new instance of the ValidationException class with the + /// specified message and validation errors. + /// + /// + /// A message about the exception. + /// + /// + /// Validation errors. + /// + public ValidationException(string message, IValidationErrors errors) + : base(message) + { + this.errors = errors; + } - /// - /// Creates a new instance of the ValidationException class with the - /// specified message and validation errors. - /// - /// - /// A message about the exception. - /// - /// - /// Validation errors. - /// - public ValidationException(string message, IValidationErrors errors) - : base(message) - { - this.errors = errors; - } + /// + /// Creates a new instance of the ValidationException class with the + /// specified message and root cause. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception that is being wrapped. + /// + public ValidationException(string message, Exception rootCause) + : base(message, rootCause) + { + } - /// - /// Creates a new instance of the ValidationException class with the - /// specified message and root cause. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception that is being wrapped. - /// - public ValidationException(string message, Exception rootCause) - : base(message, rootCause) - { - } + /// + /// Creates a new instance of the ValidationException class with the + /// specified message, root cause and validation errors. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception that is being wrapped. + /// + /// + /// Validation errors. + /// + public ValidationException(string message, Exception rootCause, IValidationErrors errors) + : base(message, rootCause) + { + this.errors = errors; + } - /// - /// Creates a new instance of the ValidationException class with the - /// specified message, root cause and validation errors. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception that is being wrapped. - /// - /// - /// Validation errors. - /// - public ValidationException(string message, Exception rootCause, IValidationErrors errors) - : base(message, rootCause) - { - this.errors = errors; - } + /// + /// Creates a new instance of the ValidationException class. + /// + /// + /// The + /// that holds the serialized object data about the exception being thrown. + /// + /// + /// The + /// that contains contextual information about the source or destination. + /// + protected ValidationException( + SerializationInfo info, StreamingContext context) + : base(info, context) + { + this.errors = (IValidationErrors) info.GetValue("errors", typeof(IValidationErrors)); + } - /// - /// Creates a new instance of the ValidationException class. - /// - /// - /// The - /// that holds the serialized object data about the exception being thrown. - /// - /// - /// The - /// that contains contextual information about the source or destination. - /// - protected ValidationException ( - SerializationInfo info, StreamingContext context) - : base (info, context) - { - this.errors = (IValidationErrors) info.GetValue("errors", typeof (IValidationErrors)); - } + /// + /// Implements object serialization. + /// + /// + /// The + /// that holds the serialized object data about the exception being thrown. + /// + /// + /// The + /// that contains contextual information about the source or destination. + /// + public override void GetObjectData(SerializationInfo info, StreamingContext context) + { + base.GetObjectData(info, context); + info.AddValue("errors", this.errors); + } - /// - /// Implements object serialization. - /// - /// - /// The - /// that holds the serialized object data about the exception being thrown. - /// - /// - /// The - /// that contains contextual information about the source or destination. - /// - public override void GetObjectData(SerializationInfo info, StreamingContext context) - { - base.GetObjectData(info, context); - info.AddValue("errors", this.errors); - } - - /// - /// Gets validation errors. - /// - /// Validation errors. - public IValidationErrors ValidationErrors - { - get { return errors; } - } + /// + /// Gets validation errors. + /// + /// Validation errors. + public IValidationErrors ValidationErrors + { + get { return errors; } } } diff --git a/src/Spring/Spring.Core/Validation/ValidatorGroup.cs b/src/Spring/Spring.Core/Validation/ValidatorGroup.cs index fc498c88..985621be 100644 --- a/src/Spring/Spring.Core/Validation/ValidatorGroup.cs +++ b/src/Spring/Spring.Core/Validation/ValidatorGroup.cs @@ -20,71 +20,71 @@ using Spring.Expressions; -namespace Spring.Validation +namespace Spring.Validation; + +/// +/// implementation that supports grouping of validators. +/// +/// +///

+/// This validator will be valid only when all of the validators in the Validators +/// collection are valid. +///

+///

+/// ValidationErrors property will return a union of all validation error messages +/// for the contained validators. +///

+///
+/// Aleksandar Seovic +/// Erich Eichinger +public class ValidatorGroup : BaseValidatorGroup { + #region Constructors + /// - /// implementation that supports grouping of validators. + /// Initializes a new instance /// - /// - ///

- /// This validator will be valid only when all of the validators in the Validators - /// collection are valid. - ///

- ///

- /// ValidationErrors property will return a union of all validation error messages - /// for the contained validators. - ///

- ///
- /// Aleksandar Seovic - /// Erich Eichinger - public class ValidatorGroup : BaseValidatorGroup + public ValidatorGroup() : base() { - #region Constructors + } - /// - /// Initializes a new instance - /// - public ValidatorGroup() : base() + /// + /// Initializes a new instance + /// + /// The expression that determines if this validator should be evaluated. + public ValidatorGroup(string when) : base(when) + { + } + + /// + /// Initializes a new instance + /// + /// The expression that determines if this validator should be evaluated. + public ValidatorGroup(IExpression when) : base(when) + { + } + + #endregion + + /// + /// Actual implementation how to validate the specified object. + /// + /// Additional context parameters. + /// instance to add error messages to. + /// The object to validate. + /// True if validation was successful, False otherwise. + protected override bool ValidateGroup(IDictionary contextParams, IValidationErrors errors, object validationContext) + { + bool valid = true; + foreach (IValidator validator in this.Validators) { - } - - /// - /// Initializes a new instance - /// - /// The expression that determines if this validator should be evaluated. - public ValidatorGroup(string when) : base(when) - { - } - - /// - /// Initializes a new instance - /// - /// The expression that determines if this validator should be evaluated. - public ValidatorGroup(IExpression when) : base(when) - { - } - - #endregion - - /// - /// Actual implementation how to validate the specified object. - /// - /// Additional context parameters. - /// instance to add error messages to. - /// The object to validate. - /// True if validation was successful, False otherwise. - protected override bool ValidateGroup(IDictionary contextParams, IValidationErrors errors, object validationContext) - { - bool valid = true; - foreach (IValidator validator in this.Validators) + valid = validator.Validate(validationContext, contextParams, errors) && valid; + if (!valid && this.FastValidate) { - valid = validator.Validate(validationContext, contextParams, errors) && valid; - if (!valid && this.FastValidate) - { - break; - } + break; } - return valid; } + + return valid; } } diff --git a/src/Spring/Spring.Core/Validation/ValidatorReference.cs b/src/Spring/Spring.Core/Validation/ValidatorReference.cs index c9f6c85e..6f43437c 100644 --- a/src/Spring/Spring.Core/Validation/ValidatorReference.cs +++ b/src/Spring/Spring.Core/Validation/ValidatorReference.cs @@ -21,161 +21,164 @@ using Spring.Expressions; using Spring.Objects.Factory; -namespace Spring.Validation +namespace Spring.Validation; + +/// +/// Represents a reference to an externally defined validator object +/// +/// +///

+/// This class allows validation groups to reference validators that +/// are defined outside of the group itself. +///

+///

+/// It also allows users to narrow the context for the referenced validator +/// by specifying value for the Context property. +///

+///
+/// Aleksandar Seovic +public class ValidatorReference : IValidator, IObjectFactoryAware { + #region Fields + + private IObjectFactory objectFactory; + + private string name; + private IExpression context; + private IExpression when; + private IValidator validator; + + #endregion + + #region Constructors + /// - /// Represents a reference to an externally defined validator object + /// Creates a new instance of the class. /// - /// - ///

- /// This class allows validation groups to reference validators that - /// are defined outside of the group itself. - ///

- ///

- /// It also allows users to narrow the context for the referenced validator - /// by specifying value for the Context property. - ///

- ///
- /// Aleksandar Seovic - public class ValidatorReference : IValidator, IObjectFactoryAware + public ValidatorReference() { - #region Fields + } - private IObjectFactory objectFactory; + /// + /// Creates a new instance of the class. + /// + /// + /// The expression that determines if this validator should be evaluated. + /// + public ValidatorReference(string when) + : this((when != null ? Expression.Parse(when) : null)) + { + } - private string name; - private IExpression context; - private IExpression when; - private IValidator validator; + /// + /// Creates a new instance of the class. + /// + /// + /// The expression that determines if this validator should be evaluated. + /// + public ValidatorReference(IExpression when) + { + this.when = when; + } - #endregion + #endregion - #region Constructors + #region Properties - /// - /// Creates a new instance of the class. - /// - public ValidatorReference() - {} + /// + /// Gets or sets the name of the referenced validator. + /// + /// The name of the referenced validator. + public string Name + { + get { return name; } + set { name = value; } + } - /// - /// Creates a new instance of the class. - /// - /// - /// The expression that determines if this validator should be evaluated. - /// - public ValidatorReference(string when) - : this((when != null ? Expression.Parse(when) : null)) - {} + /// + /// Gets or sets the expression that should be used to narrow validation context. + /// + /// The expression that should be used to narrow validation context. + public IExpression Context + { + get { return context; } + set { context = value; } + } - /// - /// Creates a new instance of the class. - /// - /// - /// The expression that determines if this validator should be evaluated. - /// - public ValidatorReference(IExpression when) + /// + /// Gets or sets the expression that determines if this validator should be evaluated. + /// + /// The expression that determines if this validator should be evaluated. + public IExpression When + { + get { return when; } + set { when = value; } + } + + #endregion + + /// + /// Validates the specified object. + /// + /// The object to validate. + /// instance to add error messages to. + /// True if validation was successful, False otherwise. + public bool Validate(object validationContext, IValidationErrors errors) + { + return Validate(validationContext, null, errors); + } + + /// + /// Validates the specified object. + /// + /// The object to validate. + /// Additional context parameters. + /// instance to add error messages to. + /// True if validation was successful, False otherwise. + public bool Validate(object validationContext, IDictionary contextParams, IValidationErrors errors) + { + bool valid = true; + + if (When == null || + Convert.ToBoolean(When.GetValue(validationContext, contextParams))) { - this.when = when; - } - - #endregion - - #region Properties - - /// - /// Gets or sets the name of the referenced validator. - /// - /// The name of the referenced validator. - public string Name - { - get { return name; } - set { name = value; } - } - - /// - /// Gets or sets the expression that should be used to narrow validation context. - /// - /// The expression that should be used to narrow validation context. - public IExpression Context - { - get { return context; } - set { context = value; } - } - - /// - /// Gets or sets the expression that determines if this validator should be evaluated. - /// - /// The expression that determines if this validator should be evaluated. - public IExpression When - { - get { return when; } - set { when = value; } - } - - #endregion - - /// - /// Validates the specified object. - /// - /// The object to validate. - /// instance to add error messages to. - /// True if validation was successful, False otherwise. - public bool Validate(object validationContext, IValidationErrors errors) - { - return Validate(validationContext, null, errors); - } - - /// - /// Validates the specified object. - /// - /// The object to validate. - /// Additional context parameters. - /// instance to add error messages to. - /// True if validation was successful, False otherwise. - public bool Validate(object validationContext, IDictionary contextParams, IValidationErrors errors) - { - bool valid = true; - - if (When == null || - Convert.ToBoolean(When.GetValue(validationContext, contextParams))) + if (Context != null) { - if (Context != null) - { - validationContext = Context.GetValue(validationContext, contextParams); - } - if (validator == null) - { - validator = (IValidator)objectFactory.GetObject(Name); - } - valid = validator.Validate(validationContext, contextParams, errors); + validationContext = Context.GetValue(validationContext, contextParams); } - return valid; + if (validator == null) + { + validator = (IValidator) objectFactory.GetObject(Name); + } + + valid = validator.Validate(validationContext, contextParams, errors); } - /// - /// Callback that supplies the owning factory to an object instance. - /// - /// - /// Owning - /// (may not be ). The object can immediately - /// call methods on the factory. - /// - /// - ///

- /// Invoked after population of normal object properties but before an init - /// callback like 's - /// - /// method or a custom init-method. - ///

- ///
- /// - /// In case of initialization errors. - /// - public IObjectFactory ObjectFactory - { - set { objectFactory = value; } - } + return valid; + } + + /// + /// Callback that supplies the owning factory to an object instance. + /// + /// + /// Owning + /// (may not be ). The object can immediately + /// call methods on the factory. + /// + /// + ///

+ /// Invoked after population of normal object properties but before an init + /// callback like 's + /// + /// method or a custom init-method. + ///

+ ///
+ /// + /// In case of initialization errors. + /// + public IObjectFactory ObjectFactory + { + set { objectFactory = value; } } } diff --git a/src/Spring/Spring.Core/Validation/Validators/ConditionValidator.cs b/src/Spring/Spring.Core/Validation/Validators/ConditionValidator.cs index 870e8421..aedc7c47 100644 --- a/src/Spring/Spring.Core/Validation/Validators/ConditionValidator.cs +++ b/src/Spring/Spring.Core/Validation/Validators/ConditionValidator.cs @@ -21,61 +21,61 @@ using Spring.Expressions; using Spring.Util; -namespace Spring.Validation +namespace Spring.Validation; + +/// +/// Evaluates validator test using condition evaluator. +/// +/// Aleksandar Seovic +public class ConditionValidator : BaseSimpleValidator { - /// - /// Evaluates validator test using condition evaluator. - /// - /// Aleksandar Seovic - public class ConditionValidator : BaseSimpleValidator - { - #region Constructors + #region Constructors - /// - /// Creates a new instance of the class. - /// - public ConditionValidator() - {} + /// + /// Creates a new instance of the class. + /// + public ConditionValidator() + { + } - /// - /// Creates a new instance of the class. - /// - /// The expression to validate. - /// The expression that determines if this validator should be evaluated. - public ConditionValidator(string test, string when) : base(test, when) - { - AssertUtils.ArgumentHasText(test, "test"); - } + /// + /// Creates a new instance of the class. + /// + /// The expression to validate. + /// The expression that determines if this validator should be evaluated. + public ConditionValidator(string test, string when) : base(test, when) + { + AssertUtils.ArgumentHasText(test, "test"); + } - /// - /// Creates a new instance of the class. - /// - /// The expression to validate. - /// The expression that determines if this validator should be evaluated. - public ConditionValidator(IExpression test, IExpression when) : base(test, when) - { - AssertUtils.ArgumentNotNull(test, "test"); - } + /// + /// Creates a new instance of the class. + /// + /// The expression to validate. + /// The expression that determines if this validator should be evaluated. + public ConditionValidator(IExpression test, IExpression when) : base(test, when) + { + AssertUtils.ArgumentNotNull(test, "test"); + } - #endregion + #endregion - /// - /// Evaluates the test using condition evaluator. - /// - /// - ///

- /// Test can be any logical expression that is supported by the Spring.NET logical - /// expression evaluation engine, and can use any variables that can be resolved - /// by the variable resolver used by the validation engine. - ///

- ///
- /// The object to validate. - /// - /// if the supplied is valid. - /// - protected override bool Validate(object objectToValidate) - { - return Convert.ToBoolean(objectToValidate); - } - } + /// + /// Evaluates the test using condition evaluator. + /// + /// + ///

+ /// Test can be any logical expression that is supported by the Spring.NET logical + /// expression evaluation engine, and can use any variables that can be resolved + /// by the variable resolver used by the validation engine. + ///

+ ///
+ /// The object to validate. + /// + /// if the supplied is valid. + /// + protected override bool Validate(object objectToValidate) + { + return Convert.ToBoolean(objectToValidate); + } } diff --git a/src/Spring/Spring.Core/Validation/Validators/CreditCardValidator.cs b/src/Spring/Spring.Core/Validation/Validators/CreditCardValidator.cs index 80693018..f5babff4 100644 --- a/src/Spring/Spring.Core/Validation/Validators/CreditCardValidator.cs +++ b/src/Spring/Spring.Core/Validation/Validators/CreditCardValidator.cs @@ -21,296 +21,298 @@ using Spring.Expressions; using Spring.Util; -namespace Spring.Validation.Validators +namespace Spring.Validation.Validators; + +/// +/// Perform credit card validations. +/// +/// +/// By default, all supported card types are allowed. You can specify +/// which credit card type validator should be used by setting +/// the value of property to a concrete +/// instance. +/// +public class CreditCardValidator : BaseSimpleValidator { + #region Properties + /// - /// Perform credit card validations. + /// Credit card type validator to use. /// /// - /// By default, all supported card types are allowed. You can specify - /// which credit card type validator should be used by setting - /// the value of property to a concrete - /// instance. + /// Can be concrete implementations of + /// interface. The following are available implementations: + /// , , , + /// . /// - public class CreditCardValidator : BaseSimpleValidator + public ICreditCardType CardType { - #region Properties - - /// - /// Credit card type validator to use. - /// - /// - /// Can be concrete implementations of - /// interface. The following are available implementations: - /// , , , - /// . - /// - public ICreditCardType CardType - { - get { return m_cardType; } - set { m_cardType = value; } - } - - #endregion - - #region Constructors - - /// - /// Creates a new instance of the UrlValidator class. - /// - public CreditCardValidator() - {} - - /// - /// Creates a new instance of the UrlValidator class. - /// - /// The expression to validate. - /// The expression that determines if this validator should be evaluated. - /// Credit Card type validator to use. - public CreditCardValidator(string test, string when, ICreditCardType cardType) - : base(test, when) - { - AssertUtils.ArgumentHasText(test, "test"); - this.m_cardType = cardType; - } - - /// - /// Creates a new instance of the UrlValidator class. - /// - /// The expression to validate. - /// The expression that determines if this validator should be evaluated. - /// Credit Card type validator to use. - public CreditCardValidator(IExpression test, IExpression when, ICreditCardType cardType) - : base(test, when) - { - AssertUtils.ArgumentNotNull(test, "test"); - this.m_cardType = cardType; - } - - #endregion - - #region BaseValidator methods - - /// - /// Validates the supplied . - /// - /// - /// In the case of the class, - /// the test should be a string variable that will be evaluated and the object - /// obtained as a result of this evaluation will be checked if it is - /// a valid credit card number. - /// - /// The object to validate. - /// - /// if the supplied is valid - /// credit card number. - /// - protected override bool Validate(object objectToValidate) - { - string text = objectToValidate as string; - if (StringUtils.IsNullOrEmpty(text)) - { - return true; - } - - return IsValid(text); - } - - #endregion - - #region CreditCardValidator methods - - /// - /// Checks if the is a valid credit card number. - /// - /// - /// The card number to validate. - /// - /// - /// true if the card number is valid. - /// - public bool IsValid(String card) - { - // check card number length - if ((card == null) || (card.Length < 13) || (card.Length > 19)) - { - return false; - } - - // check if the card is a valid credit card number - if (!LuhnCheck(card)) - { - return false; - } - - // validate card with credit card type validator - if (CardType != null) - { - return ValidateCard(card); - } - else - { - throw new ArgumentException("Property CardType cannot be null."); - } - } - - /// - /// Validates card number with the specified validator. - /// - /// - /// Credit card number to validate. - /// - /// - /// true if credit card number is a valid number of credit card type specified. - /// - private bool ValidateCard(string cardNumber) - { - String card = cardNumber == null ? null : cardNumber.Trim(); - - if (card == null) - { - return false; - } - - return CardType.Matches(card); - } - - /// - /// Checks for a valid credit card number. - /// - /// - /// Credit Card Number. - /// - /// - /// true if the card number passes the LuhnCheck. - /// - private bool LuhnCheck(string cardNumber) - { - // number must be validated as 0..9 numeric first!! - int digits = cardNumber.Length; - int oddOrEven = digits & 1; - long sum = 0; - for (int count = 0; count < digits; count++) - { - int digit; - try - { - digit = Int32.Parse(cardNumber[count] + ""); - } - catch (FormatException) - { - return false; - } - - if (((count & 1) ^ oddOrEven) == 0) - { // not - digit *= 2; - if (digit > 9) - { - digit -= 9; - } - } - sum += digit; - } - - return (sum == 0) ? false : (sum % 10 == 0); - } - - #endregion - - #region Data members - - private ICreditCardType m_cardType; - - #endregion - } - - #region CreditCardType classes - - /// - /// CreditCardType interface defines how validation is performed - /// for one type/brand of credit card. - /// - public interface ICreditCardType - { - /// - /// Returns true if the card number matches this type of - /// credit card. - /// - /// - /// The card number, never null. - /// - /// - /// true if the number matches. - /// - bool Matches(String card); - } - - /// - /// Visa credit card type validation support. - /// - public class Visa : ICreditCardType - { - private static readonly String PREFIX = "4"; - - /// - /// Indicates, wheter the given credit card number matches a visa number. - /// - public bool Matches(String card) - { - return (card.Substring(0, 1).Equals(PREFIX) && (card.Length == 13 || card.Length == 16)); - } - } - - /// - /// American Express credit card type validation support. - /// - public class Amex : ICreditCardType - { - private static readonly String PREFIX = "34,37,"; - - /// - /// Indicates, wheter the given credit card number matches an amex number. - /// - public bool Matches(String card) - { - String prefix2 = card.Substring(0, 2) + ","; - return ((PREFIX.IndexOf(prefix2) != -1) && (card.Length == 15)); - } - } - - /// - /// Discover credit card type validation support. - /// - public class Discover : ICreditCardType - { - private static readonly String PREFIX = "6011"; - - /// - /// Indicates, wheter the given credit card number matches a discover number. - /// - public bool Matches(String card) - { - return (card.Substring(0, 4).Equals(PREFIX) && (card.Length == 16)); - } - } - - /// - /// Mastercard credit card type validation support. - /// - public class Mastercard : ICreditCardType - { - private static readonly String PREFIX = "51,52,53,54,55,"; - - /// - /// Indicates, wheter the given credit card number matches a mastercard number. - /// - public bool Matches(String card) - { - String prefix2 = card.Substring(0, 2) + ","; - return ((PREFIX.IndexOf(prefix2) != -1) && (card.Length == 16)); - } + get { return m_cardType; } + set { m_cardType = value; } } #endregion + + #region Constructors + + /// + /// Creates a new instance of the UrlValidator class. + /// + public CreditCardValidator() + { + } + + /// + /// Creates a new instance of the UrlValidator class. + /// + /// The expression to validate. + /// The expression that determines if this validator should be evaluated. + /// Credit Card type validator to use. + public CreditCardValidator(string test, string when, ICreditCardType cardType) + : base(test, when) + { + AssertUtils.ArgumentHasText(test, "test"); + this.m_cardType = cardType; + } + + /// + /// Creates a new instance of the UrlValidator class. + /// + /// The expression to validate. + /// The expression that determines if this validator should be evaluated. + /// Credit Card type validator to use. + public CreditCardValidator(IExpression test, IExpression when, ICreditCardType cardType) + : base(test, when) + { + AssertUtils.ArgumentNotNull(test, "test"); + this.m_cardType = cardType; + } + + #endregion + + #region BaseValidator methods + + /// + /// Validates the supplied . + /// + /// + /// In the case of the class, + /// the test should be a string variable that will be evaluated and the object + /// obtained as a result of this evaluation will be checked if it is + /// a valid credit card number. + /// + /// The object to validate. + /// + /// if the supplied is valid + /// credit card number. + /// + protected override bool Validate(object objectToValidate) + { + string text = objectToValidate as string; + if (StringUtils.IsNullOrEmpty(text)) + { + return true; + } + + return IsValid(text); + } + + #endregion + + #region CreditCardValidator methods + + /// + /// Checks if the is a valid credit card number. + /// + /// + /// The card number to validate. + /// + /// + /// true if the card number is valid. + /// + public bool IsValid(String card) + { + // check card number length + if ((card == null) || (card.Length < 13) || (card.Length > 19)) + { + return false; + } + + // check if the card is a valid credit card number + if (!LuhnCheck(card)) + { + return false; + } + + // validate card with credit card type validator + if (CardType != null) + { + return ValidateCard(card); + } + else + { + throw new ArgumentException("Property CardType cannot be null."); + } + } + + /// + /// Validates card number with the specified validator. + /// + /// + /// Credit card number to validate. + /// + /// + /// true if credit card number is a valid number of credit card type specified. + /// + private bool ValidateCard(string cardNumber) + { + String card = cardNumber == null ? null : cardNumber.Trim(); + + if (card == null) + { + return false; + } + + return CardType.Matches(card); + } + + /// + /// Checks for a valid credit card number. + /// + /// + /// Credit Card Number. + /// + /// + /// true if the card number passes the LuhnCheck. + /// + private bool LuhnCheck(string cardNumber) + { + // number must be validated as 0..9 numeric first!! + int digits = cardNumber.Length; + int oddOrEven = digits & 1; + long sum = 0; + for (int count = 0; count < digits; count++) + { + int digit; + try + { + digit = Int32.Parse(cardNumber[count] + ""); + } + catch (FormatException) + { + return false; + } + + if (((count & 1) ^ oddOrEven) == 0) + { + // not + digit *= 2; + if (digit > 9) + { + digit -= 9; + } + } + + sum += digit; + } + + return (sum == 0) ? false : (sum % 10 == 0); + } + + #endregion + + #region Data members + + private ICreditCardType m_cardType; + + #endregion } + +#region CreditCardType classes + +/// +/// CreditCardType interface defines how validation is performed +/// for one type/brand of credit card. +/// +public interface ICreditCardType +{ + /// + /// Returns true if the card number matches this type of + /// credit card. + /// + /// + /// The card number, never null. + /// + /// + /// true if the number matches. + /// + bool Matches(String card); +} + +/// +/// Visa credit card type validation support. +/// +public class Visa : ICreditCardType +{ + private static readonly String PREFIX = "4"; + + /// + /// Indicates, wheter the given credit card number matches a visa number. + /// + public bool Matches(String card) + { + return (card.Substring(0, 1).Equals(PREFIX) && (card.Length == 13 || card.Length == 16)); + } +} + +/// +/// American Express credit card type validation support. +/// +public class Amex : ICreditCardType +{ + private static readonly String PREFIX = "34,37,"; + + /// + /// Indicates, wheter the given credit card number matches an amex number. + /// + public bool Matches(String card) + { + String prefix2 = card.Substring(0, 2) + ","; + return ((PREFIX.IndexOf(prefix2) != -1) && (card.Length == 15)); + } +} + +/// +/// Discover credit card type validation support. +/// +public class Discover : ICreditCardType +{ + private static readonly String PREFIX = "6011"; + + /// + /// Indicates, wheter the given credit card number matches a discover number. + /// + public bool Matches(String card) + { + return (card.Substring(0, 4).Equals(PREFIX) && (card.Length == 16)); + } +} + +/// +/// Mastercard credit card type validation support. +/// +public class Mastercard : ICreditCardType +{ + private static readonly String PREFIX = "51,52,53,54,55,"; + + /// + /// Indicates, wheter the given credit card number matches a mastercard number. + /// + public bool Matches(String card) + { + String prefix2 = card.Substring(0, 2) + ","; + return ((PREFIX.IndexOf(prefix2) != -1) && (card.Length == 16)); + } +} + +#endregion diff --git a/src/Spring/Spring.Core/Validation/Validators/EmailValidator.cs b/src/Spring/Spring.Core/Validation/Validators/EmailValidator.cs index 514770d8..551d4858 100644 --- a/src/Spring/Spring.Core/Validation/Validators/EmailValidator.cs +++ b/src/Spring/Spring.Core/Validation/Validators/EmailValidator.cs @@ -22,89 +22,89 @@ using System.Text.RegularExpressions; using Spring.Expressions; using Spring.Util; -namespace Spring.Validation.Validators +namespace Spring.Validation.Validators; + +/// +/// Perform email validations. +/// +/// +///

+/// This implementation is not guaranteed to catch all possible errors in an +/// email address. For example, an address like nobody@noplace.nowhere will +/// pass validator, even though there is no TLD "nowhere". +/// +/// Goran Milosavljevic +public class EmailValidator : BaseSimpleValidator { + #region Constructors + ///

- /// Perform email validations. + /// Creates a new instance of the EmailValidator class. + /// + public EmailValidator() + { + } + + /// + /// Creates a new instance of the EmailValidator class. + /// + /// The expression to validate. + /// The expression that determines if this validator should be evaluated. + public EmailValidator(string test, string when) + : base(test, when) + { + AssertUtils.ArgumentHasText(test, "test"); + } + + /// + /// Creates a new instance of the EmailValidator class. + /// + /// The expression to validate. + /// The expression that determines if this validator should be evaluated. + public EmailValidator(IExpression test, IExpression when) + : base(test, when) + { + AssertUtils.ArgumentNotNull(test, "test"); + } + + #endregion + + #region BaseValidator methods + + /// + /// Validates the supplied . /// /// - ///

- /// This implementation is not guaranteed to catch all possible errors in an - /// email address. For example, an address like nobody@noplace.nowhere will - /// pass validator, even though there is no TLD "nowhere". + /// In the case of the class, + /// the test should be a string variable that will be evaluated and the object + /// obtained as a result of this evaluation will be checked if it is + /// a valid e-mail address. /// - /// Goran Milosavljevic - public class EmailValidator : BaseSimpleValidator + /// The object to validate. + /// + /// if the supplied is valid + /// e-mail address. + /// + protected override bool Validate(object objectToValidate) { - #region Constructors - - ///

- /// Creates a new instance of the EmailValidator class. - /// - public EmailValidator() - {} - - /// - /// Creates a new instance of the EmailValidator class. - /// - /// The expression to validate. - /// The expression that determines if this validator should be evaluated. - public EmailValidator(string test, string when) - : base(test, when) + string text = objectToValidate as string; + if (StringUtils.IsNullOrEmpty(text)) { - AssertUtils.ArgumentHasText(test, "test"); + return true; } - /// - /// Creates a new instance of the EmailValidator class. - /// - /// The expression to validate. - /// The expression that determines if this validator should be evaluated. - public EmailValidator(IExpression test, IExpression when) - : base(test, when) - { - AssertUtils.ArgumentNotNull(test, "test"); - } - - #endregion - - #region BaseValidator methods - - /// - /// Validates the supplied . - /// - /// - /// In the case of the class, - /// the test should be a string variable that will be evaluated and the object - /// obtained as a result of this evaluation will be checked if it is - /// a valid e-mail address. - /// - /// The object to validate. - /// - /// if the supplied is valid - /// e-mail address. - /// - protected override bool Validate(object objectToValidate) - { - string text = objectToValidate as string; - if (StringUtils.IsNullOrEmpty(text)) - { - return true; - } - - Match match = Regex.Match(text, emailCheck); - return match.Success && match.Index == 0 && match.Length == text.Length; - } - - #endregion - - #region Data members - - /// - /// Regular expression used for validation of object passed to this . - /// - private static string emailCheck = @"^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$"; - - #endregion + Match match = Regex.Match(text, emailCheck); + return match.Success && match.Index == 0 && match.Length == text.Length; } + + #endregion + + #region Data members + + /// + /// Regular expression used for validation of object passed to this . + /// + private static string emailCheck = @"^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$"; + + #endregion } diff --git a/src/Spring/Spring.Core/Validation/Validators/ISBNValidator.cs b/src/Spring/Spring.Core/Validation/Validators/ISBNValidator.cs index 8bba8800..7ddb506e 100644 --- a/src/Spring/Spring.Core/Validation/Validators/ISBNValidator.cs +++ b/src/Spring/Spring.Core/Validation/Validators/ISBNValidator.cs @@ -22,141 +22,141 @@ using System.Text.RegularExpressions; using Spring.Expressions; using Spring.Util; -namespace Spring.Validation.Validators +namespace Spring.Validation.Validators; + +/// +/// Validates that the object is valid ISBN-10 or ISBN-13 value. +/// +/// Goran Milosavljevic +public class ISBNValidator : BaseSimpleValidator { + #region Constructors + /// - /// Validates that the object is valid ISBN-10 or ISBN-13 value. + /// Creates a new instance of the ISBNValidator class. /// - /// Goran Milosavljevic - public class ISBNValidator : BaseSimpleValidator + public ISBNValidator() { - #region Constructors - - /// - /// Creates a new instance of the ISBNValidator class. - /// - public ISBNValidator() - {} - - /// - /// Creates a new instance of the ISBNValidator class. - /// - /// The expression to validate. - /// The expression that determines if this validator should be evaluated. - public ISBNValidator(string test, string when) - : base(test, when) - { - AssertUtils.ArgumentHasText(test, "test"); - } - - /// - /// Creates a new instance of the ISBNValidator class. - /// - /// The expression to validate. - /// The expression that determines if this validator should be evaluated. - public ISBNValidator(IExpression test, IExpression when) - : base(test, when) - { - AssertUtils.ArgumentNotNull(test, "test"); - } - - #endregion - - #region BaseValidator methods - - /// - /// Validates the supplied . - /// - /// - /// In the case of the class, - /// the test should be a string variable that will be evaluated and the object - /// obtained as a result of this evaluation will be tested using the ISBN-10 or - /// ISBN-13 validation rules. - /// - /// The object to validate. - /// - /// if the supplied is valid ISBN. - /// - protected override bool Validate(object objectToValidate) - { - String isbn = objectToValidate as String; - if (StringUtils.IsNullOrEmpty(isbn)) - { - return true; - } - - return IsValid(isbn); - } - - #endregion - - #region ISBNValidator methods - - /// - /// Validates against ISBN-10 or ISBN-13 validation - /// rules. - /// - /// - /// ISBN string to validate. - /// - /// - /// true if is a valid ISBN-10 or ISBN-13 code. - /// - private bool IsValid(String isbn) - { - String code = (isbn == null ? null : isbn.Trim().Replace("-", "").Replace(" ", "")); - - // check the length - if ((code == null) || (code.Length < 10 || code.Length>13)) - { - return false; - } - - // validate/reformat using regular expression - Match match; - String pattern; - if (code.Length == 10) - { - pattern = ISBN10_PATTERN; - } - else - { - pattern = ISBN13_PATTERN; - } - - match = Regex.Match(code, pattern); - return match.Success && match.Index == 0 && match.Length == code.Length; - } - - #endregion - - #region Data members - - private static readonly String SEP = "(?:\\-|\\s)"; - private static readonly String GROUP = "(\\d{1,5})"; - private static readonly String PUBLISHER = "(\\d{1,7})"; - private static readonly String TITLE = "(\\d{1,6})"; - - /// - /// ISBN-10 consists of 4 groups of numbers separated by either - /// dashes (-) or spaces. - /// - /// - /// The first group is 1-5 characters, second 1-7, third 1-6, - /// and fourth is 1 digit or an X. - /// - static readonly String ISBN10_PATTERN = "^(?:(\\d{9}[0-9X])|(?:" + GROUP + SEP + PUBLISHER + SEP + TITLE + SEP + "([0-9X])))$"; - - /// - /// ISBN-13 consists of 5 groups of numbers separated by either - /// dashes (-) or spaces. - /// - /// - /// The first group is 978 or 979, the second group is - /// 1-5 characters, third 1-7, fourth 1-6, and fifth is 1 digit. - /// - static readonly String ISBN13_PATTERN = "^(978|979)(?:(\\d{10})|(?:" + SEP + GROUP + SEP + PUBLISHER + SEP + TITLE + SEP + "([0-9])))$"; - - #endregion } + + /// + /// Creates a new instance of the ISBNValidator class. + /// + /// The expression to validate. + /// The expression that determines if this validator should be evaluated. + public ISBNValidator(string test, string when) + : base(test, when) + { + AssertUtils.ArgumentHasText(test, "test"); + } + + /// + /// Creates a new instance of the ISBNValidator class. + /// + /// The expression to validate. + /// The expression that determines if this validator should be evaluated. + public ISBNValidator(IExpression test, IExpression when) + : base(test, when) + { + AssertUtils.ArgumentNotNull(test, "test"); + } + + #endregion + + #region BaseValidator methods + + /// + /// Validates the supplied . + /// + /// + /// In the case of the class, + /// the test should be a string variable that will be evaluated and the object + /// obtained as a result of this evaluation will be tested using the ISBN-10 or + /// ISBN-13 validation rules. + /// + /// The object to validate. + /// + /// if the supplied is valid ISBN. + /// + protected override bool Validate(object objectToValidate) + { + String isbn = objectToValidate as String; + if (StringUtils.IsNullOrEmpty(isbn)) + { + return true; + } + + return IsValid(isbn); + } + + #endregion + + #region ISBNValidator methods + + /// + /// Validates against ISBN-10 or ISBN-13 validation + /// rules. + /// + /// + /// ISBN string to validate. + /// + /// + /// true if is a valid ISBN-10 or ISBN-13 code. + /// + private bool IsValid(String isbn) + { + String code = (isbn == null ? null : isbn.Trim().Replace("-", "").Replace(" ", "")); + + // check the length + if ((code == null) || (code.Length < 10 || code.Length > 13)) + { + return false; + } + + // validate/reformat using regular expression + Match match; + String pattern; + if (code.Length == 10) + { + pattern = ISBN10_PATTERN; + } + else + { + pattern = ISBN13_PATTERN; + } + + match = Regex.Match(code, pattern); + return match.Success && match.Index == 0 && match.Length == code.Length; + } + + #endregion + + #region Data members + + private static readonly String SEP = "(?:\\-|\\s)"; + private static readonly String GROUP = "(\\d{1,5})"; + private static readonly String PUBLISHER = "(\\d{1,7})"; + private static readonly String TITLE = "(\\d{1,6})"; + + /// + /// ISBN-10 consists of 4 groups of numbers separated by either + /// dashes (-) or spaces. + /// + /// + /// The first group is 1-5 characters, second 1-7, third 1-6, + /// and fourth is 1 digit or an X. + /// + static readonly String ISBN10_PATTERN = "^(?:(\\d{9}[0-9X])|(?:" + GROUP + SEP + PUBLISHER + SEP + TITLE + SEP + "([0-9X])))$"; + + /// + /// ISBN-13 consists of 5 groups of numbers separated by either + /// dashes (-) or spaces. + /// + /// + /// The first group is 978 or 979, the second group is + /// 1-5 characters, third 1-7, fourth 1-6, and fifth is 1 digit. + /// + static readonly String ISBN13_PATTERN = "^(978|979)(?:(\\d{10})|(?:" + SEP + GROUP + SEP + PUBLISHER + SEP + TITLE + SEP + "([0-9])))$"; + + #endregion } diff --git a/src/Spring/Spring.Core/Validation/Validators/RegularExpressionValidator.cs b/src/Spring/Spring.Core/Validation/Validators/RegularExpressionValidator.cs index 2dc1bf3f..04a0b980 100644 --- a/src/Spring/Spring.Core/Validation/Validators/RegularExpressionValidator.cs +++ b/src/Spring/Spring.Core/Validation/Validators/RegularExpressionValidator.cs @@ -17,6 +17,7 @@ */ #endregion + #region License /* @@ -38,144 +39,142 @@ #endregion using System.Text.RegularExpressions; - using Spring.Expressions; using Spring.Util; -namespace Spring.Validation +namespace Spring.Validation; + +/// +/// Validates that object matches specified regular expression. +/// +/// +///

+/// The test expression must evaluate to a ; +/// otherwise, an exception is thrown. +///

+///
+/// Aleksandar Seovic +public class RegularExpressionValidator : BaseSimpleValidator { + #region Fields + + private string expression = string.Empty; + private bool allowPartialMatching = false; + private RegexOptions options; + + #endregion + + #region Constructors + /// - /// Validates that object matches specified regular expression. + /// Creates a new instance of the class. /// - /// - ///

- /// The test expression must evaluate to a ; - /// otherwise, an exception is thrown. - ///

- ///
- /// Aleksandar Seovic - public class RegularExpressionValidator : BaseSimpleValidator + public RegularExpressionValidator() { - #region Fields + } - private string expression = string.Empty; - private bool allowPartialMatching = false; - private RegexOptions options; + /// + /// Creates a new instance of the class. + /// + /// The expression to validate. + /// The expression that determines if this validator should be evaluated. + /// The regular expression to match against. + public RegularExpressionValidator(string test, string when, string expression) + : base(test, when) + { + AssertUtils.ArgumentHasText(test, "test"); + this.expression = expression; + } - #endregion + /// + /// Creates a new instance of the class. + /// + /// The expression to validate. + /// The expression that determines if this validator should be evaluated. + /// The regular expression to match against. + public RegularExpressionValidator(IExpression test, IExpression when, string expression) + : base(test, when) + { + AssertUtils.ArgumentNotNull(test, "test"); + this.expression = expression; + } - #region Constructors + #endregion - /// - /// Creates a new instance of the class. - /// - public RegularExpressionValidator() + #region Properties + + /// + /// The regular expression text to match against. + /// + /// The regular expression text. + public string Expression + { + get { return expression; } + set { expression = value; } + } + + /// + /// Gets or sets a value indicating whether to do a partial match instead of a full match. + /// Default is false. + /// + public bool AllowPartialMatching + { + get { return allowPartialMatching; } + set { allowPartialMatching = value; } + } + + /// + /// The for the regular expression evaluation. + /// + /// The regular expression evaluation options. + /// + public RegexOptions Options + { + get { return options; } + set { options = value; } + } + + #endregion + + /// + /// Validates an object. + /// + /// Object to validate. + /// + /// if the supplied + /// object is valid. + /// + /// + /// If the supplied is not a + /// + /// + protected override bool Validate(object objectToValidate) + { + string text = objectToValidate as string; + + if (text == null) { + throw new ArgumentException("Test for RegularExpressionValidator must evaluate to a string."); } - /// - /// Creates a new instance of the class. - /// - /// The expression to validate. - /// The expression that determines if this validator should be evaluated. - /// The regular expression to match against. - public RegularExpressionValidator(string test, string when, string expression) - : base(test, when) + if (!StringUtils.HasLength(text)) { - AssertUtils.ArgumentHasText(test, "test"); - this.expression = expression; + return true; } - /// - /// Creates a new instance of the class. - /// - /// The expression to validate. - /// The expression that determines if this validator should be evaluated. - /// The regular expression to match against. - public RegularExpressionValidator(IExpression test, IExpression when, string expression) - : base(test, when) + if (!StringUtils.HasLength(text.Trim()) && !StringUtils.HasLength(expression)) { - AssertUtils.ArgumentNotNull(test, "test"); - this.expression = expression; + return false; } - #endregion - - #region Properties - - /// - /// The regular expression text to match against. - /// - /// The regular expression text. - public string Expression + Match match = Regex.Match(text, this.Expression, this.Options); + if (allowPartialMatching) { - get { return expression; } - set { expression = value; } + return match.Success; } - - /// - /// Gets or sets a value indicating whether to do a partial match instead of a full match. - /// Default is false. - /// - public bool AllowPartialMatching + else { - get { return allowPartialMatching; } - set { allowPartialMatching = value; } - } - - /// - /// The for the regular expression evaluation. - /// - /// The regular expression evaluation options. - /// - public RegexOptions Options - { - get { return options; } - set { options = value; } - } - - #endregion - - /// - /// Validates an object. - /// - /// Object to validate. - /// - /// if the supplied - /// object is valid. - /// - /// - /// If the supplied is not a - /// - /// - protected override bool Validate(object objectToValidate) - { - string text = objectToValidate as string; - - if (text == null) - { - throw new ArgumentException("Test for RegularExpressionValidator must evaluate to a string."); - } - - if (!StringUtils.HasLength(text)) - { - return true; - } - - if (!StringUtils.HasLength(text.Trim()) && !StringUtils.HasLength(expression)) - { - return false; - } - - Match match = Regex.Match(text, this.Expression, this.Options); - if (allowPartialMatching) - { - return match.Success; - } - else - { - return match.Success && match.Index == 0 && match.Length == text.Length; - } + return match.Success && match.Index == 0 && match.Length == text.Length; } } -} +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Validation/Validators/RequiredValidator.cs b/src/Spring/Spring.Core/Validation/Validators/RequiredValidator.cs index ce4a3384..57956c28 100644 --- a/src/Spring/Spring.Core/Validation/Validators/RequiredValidator.cs +++ b/src/Spring/Spring.Core/Validation/Validators/RequiredValidator.cs @@ -21,116 +21,117 @@ using Spring.Expressions; using Spring.Util; -namespace Spring.Validation +namespace Spring.Validation; + +/// +/// Validates that required value is not empty. +/// +/// +///

+/// This validator uses following rules to determine if target value is valid: +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +///
Target Valid Value
A .Not or an empty string.
A .Not and not .
One of the number types.Not zero.
A .Not or whitespace.
Any reference type other than .Not .
+///

+///

+/// You cannot use this validator to validate any value types other than the ones +/// specified in the table above. +///

+///
+/// Aleksandar Seovic +public class RequiredValidator : BaseSimpleValidator { + #region Constructors + /// - /// Validates that required value is not empty. + /// Creates a new instance of the class. + /// + public RequiredValidator() + { + } + + /// + /// Creates a new instance of the class. + /// + /// The expression to validate. + /// The expression that determines if this validator should be evaluated. + public RequiredValidator(string test, string when) : base(test, when) + { + AssertUtils.ArgumentHasText(test, "test"); + } + + /// + /// Creates a new instance of the class. + /// + /// The expression to validate. + /// The expression that determines if this validator should be evaluated. + public RequiredValidator(IExpression test, IExpression when) : base(test, when) + { + AssertUtils.ArgumentNotNull(test, "test"); + } + + #endregion + + /// + /// Validates the supplied . /// /// - ///

- /// This validator uses following rules to determine if target value is valid: - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - ///
Target Valid Value
A .Not or an empty string.
A .Not and not .
One of the number types.Not zero.
A .Not or whitespace.
Any reference type other than .Not .
- ///

- ///

- /// You cannot use this validator to validate any value types other than the ones - /// specified in the table above. - ///

+ /// In the case of the class, + /// the test should be a variable expression that will be evaluated and the object + /// obtained as a result of this evaluation will be tested using the rules described + /// in the class overview of the + /// class. ///
- /// Aleksandar Seovic - public class RequiredValidator : BaseSimpleValidator + /// The object to validate. + /// + /// if the supplied is valid. + /// + protected override bool Validate(object objectToValidate) { - #region Constructors - - /// - /// Creates a new instance of the class. - /// - public RequiredValidator() - {} - - /// - /// Creates a new instance of the class. - /// - /// The expression to validate. - /// The expression that determines if this validator should be evaluated. - public RequiredValidator(string test, string when) : base(test, when) + if (objectToValidate is String && StringUtils.IsNullOrEmpty((string) objectToValidate)) { - AssertUtils.ArgumentHasText(test, "test"); + return false; + } + else if (objectToValidate is DateTime && (((DateTime) objectToValidate) == DateTime.MinValue || ((DateTime) objectToValidate) == DateTime.MaxValue)) + { + return false; + } + else if (NumberUtils.IsInteger(objectToValidate) && NumberUtils.IsZero(objectToValidate)) + { + return false; + } + else if (objectToValidate is Char && (((char) objectToValidate) == Char.MinValue || Char.IsWhiteSpace((char) objectToValidate))) + { + return false; + } + else if (NumberUtils.IsDecimal(objectToValidate) && NumberUtils.IsZero(objectToValidate)) + { + return false; } - /// - /// Creates a new instance of the class. - /// - /// The expression to validate. - /// The expression that determines if this validator should be evaluated. - public RequiredValidator(IExpression test, IExpression when) : base(test, when) - { - AssertUtils.ArgumentNotNull(test, "test"); - } - - #endregion - - /// - /// Validates the supplied . - /// - /// - /// In the case of the class, - /// the test should be a variable expression that will be evaluated and the object - /// obtained as a result of this evaluation will be tested using the rules described - /// in the class overview of the - /// class. - /// - /// The object to validate. - /// - /// if the supplied is valid. - /// - protected override bool Validate(object objectToValidate) - { - if (objectToValidate is String && StringUtils.IsNullOrEmpty((string) objectToValidate)) - { - return false; - } - else if (objectToValidate is DateTime && (((DateTime) objectToValidate) == DateTime.MinValue || ((DateTime) objectToValidate) == DateTime.MaxValue)) - { - return false; - } - else if (NumberUtils.IsInteger(objectToValidate) && NumberUtils.IsZero(objectToValidate)) - { - return false; - } - else if (objectToValidate is Char && (((char) objectToValidate) == Char.MinValue || Char.IsWhiteSpace((char) objectToValidate))) - { - return false; - } - else if (NumberUtils.IsDecimal(objectToValidate) && NumberUtils.IsZero(objectToValidate)) - { - return false; - } - return objectToValidate != null; - } + return objectToValidate != null; } } diff --git a/src/Spring/Spring.Core/Validation/Validators/UrlValidator.cs b/src/Spring/Spring.Core/Validation/Validators/UrlValidator.cs index 7c4ac792..2e09ad06 100644 --- a/src/Spring/Spring.Core/Validation/Validators/UrlValidator.cs +++ b/src/Spring/Spring.Core/Validation/Validators/UrlValidator.cs @@ -22,82 +22,81 @@ using System.Text.RegularExpressions; using Spring.Expressions; using Spring.Util; -namespace Spring.Validation.Validators +namespace Spring.Validation.Validators; + +/// +/// Validates that the value is valid URL. +/// +/// Goran Milosavljevic +public class UrlValidator : BaseSimpleValidator { + #region Constructors + /// - /// Validates that the value is valid URL. + /// Creates a new instance of the UrlValidator class. /// - /// Goran Milosavljevic - public class UrlValidator : BaseSimpleValidator + public UrlValidator() { - #region Constructors - - /// - /// Creates a new instance of the UrlValidator class. - /// - public UrlValidator() - { - } - - /// - /// Creates a new instance of the UrlValidator class. - /// - /// The expression to validate. - /// The expression that determines if this validator should be evaluated. - public UrlValidator(string test, string when) - : base(test, when) - { - AssertUtils.ArgumentHasText(test, "test"); - } - - /// - /// Creates a new instance of the UrlValidator class. - /// - /// The expression to validate. - /// The expression that determines if this validator should be evaluated. - public UrlValidator(IExpression test, IExpression when) - : base(test, when) - { - AssertUtils.ArgumentNotNull(test, "test"); - } - - #endregion - - #region BaseValidator methods - - /// - /// Validates the supplied . - /// - /// - /// In the case of the class, - /// the test should be a string variable that will be evaluated and the object - /// obtained as a result of this evaluation will be tested using the URL validation rules. - /// - /// The object to validate. - /// - /// if the supplied is valid. - /// - protected override bool Validate(object objectToValidate) - { - string text = objectToValidate as string; - if (StringUtils.IsNullOrEmpty(text)) - { - return true; - } - - Match match = Regex.Match(text, urlCheck); - return match.Success && match.Index == 0 && match.Length == text.Length; - } - - #endregion - - #region Data members - - /// - /// Regular expression used for validation of object passed to this . - /// - private static string urlCheck = "((http|https)://)?[a-z0-9]+([-.]{1}[a-z0-9]+)*.[a-z]{2,5}(([0-9]{1,5})?/.*)?"; - - #endregion } + + /// + /// Creates a new instance of the UrlValidator class. + /// + /// The expression to validate. + /// The expression that determines if this validator should be evaluated. + public UrlValidator(string test, string when) + : base(test, when) + { + AssertUtils.ArgumentHasText(test, "test"); + } + + /// + /// Creates a new instance of the UrlValidator class. + /// + /// The expression to validate. + /// The expression that determines if this validator should be evaluated. + public UrlValidator(IExpression test, IExpression when) + : base(test, when) + { + AssertUtils.ArgumentNotNull(test, "test"); + } + + #endregion + + #region BaseValidator methods + + /// + /// Validates the supplied . + /// + /// + /// In the case of the class, + /// the test should be a string variable that will be evaluated and the object + /// obtained as a result of this evaluation will be tested using the URL validation rules. + /// + /// The object to validate. + /// + /// if the supplied is valid. + /// + protected override bool Validate(object objectToValidate) + { + string text = objectToValidate as string; + if (StringUtils.IsNullOrEmpty(text)) + { + return true; + } + + Match match = Regex.Match(text, urlCheck); + return match.Success && match.Index == 0 && match.Length == text.Length; + } + + #endregion + + #region Data members + + /// + /// Regular expression used for validation of object passed to this . + /// + private static string urlCheck = "((http|https)://)?[a-z0-9]+([-.]{1}[a-z0-9]+)*.[a-z]{2,5}(([0-9]{1,5})?/.*)?"; + + #endregion } diff --git a/src/Spring/Spring.Data.NHibernate5/AssemblyInfo.cs b/src/Spring/Spring.Data.NHibernate5/AssemblyInfo.cs index 403626b8..4e6fa3fd 100644 --- a/src/Spring/Spring.Data.NHibernate5/AssemblyInfo.cs +++ b/src/Spring/Spring.Data.NHibernate5/AssemblyInfo.cs @@ -1,4 +1,4 @@ using System.Reflection; [assembly: AssemblyTitle("Spring.Net NHibernate 5.0 support")] -[assembly: AssemblyDescription("Interfaces and classes that provide NHibernate 5.0 support in Spring.Net")] \ No newline at end of file +[assembly: AssemblyDescription("Interfaces and classes that provide NHibernate 5.0 support in Spring.Net")] diff --git a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Bytecode/BytecodeProvider.cs b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Bytecode/BytecodeProvider.cs index ed4dcbbb..f2bd8a5a 100644 --- a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Bytecode/BytecodeProvider.cs +++ b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Bytecode/BytecodeProvider.cs @@ -19,69 +19,67 @@ using NHibernate.Properties; using NHibernate.Type; using Spring.Objects.Factory; -namespace Spring.Data.NHibernate.Bytecode +namespace Spring.Data.NHibernate.Bytecode; + +/// +/// The Spring for .NET-backed ByteCodeprovider for NHibernate +/// +/// Fabio Maulo +public class BytecodeProvider : IBytecodeProvider { - /// - /// The Spring for .NET-backed ByteCodeprovider for NHibernate - /// - /// Fabio Maulo - public class BytecodeProvider : IBytecodeProvider + private readonly IListableObjectFactory listableObjectFactory; + private readonly IObjectsFactory objectsFactory; + private readonly DefaultCollectionTypeFactory collectionTypefactory; + private readonly IProxyFactoryFactory proxyFactoryFactory; + + /// + /// Creates a new bytecode Provider instance using the specified object factory + /// + /// + public BytecodeProvider(IListableObjectFactory listableObjectFactory) { - private readonly IListableObjectFactory listableObjectFactory; - private readonly IObjectsFactory objectsFactory; - private readonly DefaultCollectionTypeFactory collectionTypefactory; - private readonly IProxyFactoryFactory proxyFactoryFactory; + this.listableObjectFactory = listableObjectFactory; + this.objectsFactory = new ObjectsFactory(listableObjectFactory); + this.collectionTypefactory = new DefaultCollectionTypeFactory(); + this.proxyFactoryFactory = new ProxyFactoryFactory(); + } - /// - /// Creates a new bytecode Provider instance using the specified object factory - /// - /// - public BytecodeProvider(IListableObjectFactory listableObjectFactory) - { - this.listableObjectFactory = listableObjectFactory; - this.objectsFactory = new ObjectsFactory(listableObjectFactory); - this.collectionTypefactory = new DefaultCollectionTypeFactory(); - this.proxyFactoryFactory = new ProxyFactoryFactory(); - } + /// + /// Retrieve the delegate for this provider + /// capable of generating reflection optimization components. + /// + /// The class to be reflected upon.All property getters to be accessed via reflection.All property setters to be accessed via reflection. + /// The reflection optimization delegate. + public IReflectionOptimizer GetReflectionOptimizer(Type clazz, IGetter[] getters, ISetter[] setters) + { + return new ReflectionOptimizer(listableObjectFactory, clazz, getters, setters); + } - /// - /// Retrieve the delegate for this provider - /// capable of generating reflection optimization components. - /// - /// The class to be reflected upon.All property getters to be accessed via reflection.All property setters to be accessed via reflection. - /// The reflection optimization delegate. - public IReflectionOptimizer GetReflectionOptimizer(Type clazz, IGetter[] getters, ISetter[] setters) - { - return new ReflectionOptimizer(listableObjectFactory, clazz, getters, setters); - } + /// + /// The specific factory for this provider capable of + /// generating run-time proxies for lazy-loading purposes. + /// + public IProxyFactoryFactory ProxyFactoryFactory + { + get { return this.proxyFactoryFactory; } + } - /// - /// The specific factory for this provider capable of - /// generating run-time proxies for lazy-loading purposes. - /// - public IProxyFactoryFactory ProxyFactoryFactory - { - get { return this.proxyFactoryFactory; } - } - - /// - /// NHibernate's object instaciator. - /// - /// - /// For entities and its implementations. - /// - public IObjectsFactory ObjectsFactory - { - get { return this.objectsFactory; } - } - - /// - /// Instanciator of NHibernate's collections default types. - /// - public ICollectionTypeFactory CollectionTypeFactory - { - get { return this.collectionTypefactory; } - } + /// + /// NHibernate's object instaciator. + /// + /// + /// For entities and its implementations. + /// + public IObjectsFactory ObjectsFactory + { + get { return this.objectsFactory; } + } + /// + /// Instanciator of NHibernate's collections default types. + /// + public ICollectionTypeFactory CollectionTypeFactory + { + get { return this.collectionTypefactory; } } } diff --git a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Bytecode/LazyInitializer.cs b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Bytecode/LazyInitializer.cs index 8c8fd225..c5afd4f7 100644 --- a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Bytecode/LazyInitializer.cs +++ b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Bytecode/LazyInitializer.cs @@ -22,98 +22,97 @@ using NHibernate.Type; using Spring.Aop; using Spring.Reflection.Dynamic; -namespace Spring.Data.NHibernate.Bytecode +namespace Spring.Data.NHibernate.Bytecode; + +/// +/// +/// +/// Fabio Maulo +[Serializable] +public class LazyInitializer : BasicLazyInitializer, IMethodInterceptor, ITargetSource { - /// - /// - /// - /// Fabio Maulo - [Serializable] - public class LazyInitializer : BasicLazyInitializer, IMethodInterceptor, ITargetSource + private static readonly MethodInfo exceptionInternalPreserveStackTrace; + + static LazyInitializer() { - private static readonly MethodInfo exceptionInternalPreserveStackTrace; - - static LazyInitializer() - { - exceptionInternalPreserveStackTrace = typeof(Exception).GetMethod("InternalPreserveStackTrace", BindingFlags.Instance | BindingFlags.NonPublic); - } - - /// - /// - /// - /// - /// - /// - /// - /// - /// - public LazyInitializer(string entityName, Type persistentClass, object id, MethodInfo getIdentifierMethod, - MethodInfo setIdentifierMethod, IAbstractComponentType componentIdType, - ISessionImplementor session) - : base( - entityName, - persistentClass, - id, - getIdentifierMethod, - setIdentifierMethod, - componentIdType, - session, - overridesEquals: false - ) - { - } - - /// - /// Implement this method to perform extra treatments before and after - /// the call to the supplied . - /// - /// - ///

- /// Polite implementations would certainly like to invoke - /// . - ///

- ///
- /// - /// The method invocation that is being intercepted. - /// - /// - /// The result of the call to the - /// method of - /// the supplied ; this return value may - /// well have been intercepted by the interceptor. - /// - /// - /// If any of the interceptors in the chain or the target object itself - /// throws an exception. - /// - public object Invoke(IMethodInvocation invocation) - { - try - { - MethodInfo methodInfo = invocation.Method; - object returnValue = base.Invoke(methodInfo, invocation.Arguments, invocation.Proxy); - - if (returnValue != InvokeImplementation) - { - return returnValue; - } - - SafeMethod method = new SafeMethod(methodInfo); - return method.Invoke(GetImplementation(), invocation.Arguments); - } - catch (TargetInvocationException ex) - { - exceptionInternalPreserveStackTrace.Invoke(ex.InnerException, new Object[] { }); - throw ex.InnerException; - } - } - - object ITargetSource.GetTarget() => Target; - - void ITargetSource.ReleaseTarget(object target) { } - - Type ITargetSource.TargetType => PersistentClass; - - bool ITargetSource.IsStatic => false; + exceptionInternalPreserveStackTrace = typeof(Exception).GetMethod("InternalPreserveStackTrace", BindingFlags.Instance | BindingFlags.NonPublic); } + + /// + /// + /// + /// + /// + /// + /// + /// + /// + public LazyInitializer(string entityName, Type persistentClass, object id, MethodInfo getIdentifierMethod, + MethodInfo setIdentifierMethod, IAbstractComponentType componentIdType, + ISessionImplementor session) + : base( + entityName, + persistentClass, + id, + getIdentifierMethod, + setIdentifierMethod, + componentIdType, + session, + overridesEquals: false + ) + { + } + + /// + /// Implement this method to perform extra treatments before and after + /// the call to the supplied . + /// + /// + ///

+ /// Polite implementations would certainly like to invoke + /// . + ///

+ ///
+ /// + /// The method invocation that is being intercepted. + /// + /// + /// The result of the call to the + /// method of + /// the supplied ; this return value may + /// well have been intercepted by the interceptor. + /// + /// + /// If any of the interceptors in the chain or the target object itself + /// throws an exception. + /// + public object Invoke(IMethodInvocation invocation) + { + try + { + MethodInfo methodInfo = invocation.Method; + object returnValue = base.Invoke(methodInfo, invocation.Arguments, invocation.Proxy); + + if (returnValue != InvokeImplementation) + { + return returnValue; + } + + SafeMethod method = new SafeMethod(methodInfo); + return method.Invoke(GetImplementation(), invocation.Arguments); + } + catch (TargetInvocationException ex) + { + exceptionInternalPreserveStackTrace.Invoke(ex.InnerException, new Object[] { }); + throw ex.InnerException; + } + } + + object ITargetSource.GetTarget() => Target; + + void ITargetSource.ReleaseTarget(object target) { } + + Type ITargetSource.TargetType => PersistentClass; + + bool ITargetSource.IsStatic => false; } diff --git a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Bytecode/ObjectsFactory.cs b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Bytecode/ObjectsFactory.cs index 41baa903..50f37b70 100644 --- a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Bytecode/ObjectsFactory.cs +++ b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Bytecode/ObjectsFactory.cs @@ -15,58 +15,55 @@ */ using NHibernate.Bytecode; - using Spring.Objects.Factory; -namespace Spring.Data.NHibernate.Bytecode +namespace Spring.Data.NHibernate.Bytecode; + +/// +/// +/// +/// Fabio Maulo +public class ObjectsFactory : IObjectsFactory { - /// - /// - /// - /// Fabio Maulo - public class ObjectsFactory : IObjectsFactory + private readonly IListableObjectFactory listableObjectFactory; + + /// + /// + /// + public ObjectsFactory(IListableObjectFactory listableObjectFactory) { - private readonly IListableObjectFactory listableObjectFactory; + this.listableObjectFactory = listableObjectFactory; + } - /// - /// - /// - public ObjectsFactory(IListableObjectFactory listableObjectFactory) - { - this.listableObjectFactory = listableObjectFactory; - } + /// + /// Creates an instance of the specified type. + /// + /// The type of object to create. + /// A reference to the created object. + public object CreateInstance(Type type) + { + var namesForType = listableObjectFactory.GetObjectNamesForType(type); + return namesForType.Count > 0 ? listableObjectFactory.GetObject(namesForType[0], type) : Activator.CreateInstance(type); + } - /// - /// Creates an instance of the specified type. - /// - /// The type of object to create. - /// A reference to the created object. - public object CreateInstance(Type type) - { - var namesForType = listableObjectFactory.GetObjectNamesForType(type); - return namesForType.Count > 0 ? listableObjectFactory.GetObject(namesForType[0], type) : Activator.CreateInstance(type); - } - - /// - /// Creates an instance of the specified type. - /// - /// The type of object to create.true if a public or nonpublic default constructor can match; false if only a public default constructor can match. - /// A reference to the created object - public object CreateInstance(Type type, bool nonPublic) - { - var namesForType = listableObjectFactory.GetObjectNamesForType(type); - return namesForType.Count > 0 ? listableObjectFactory.GetObject(namesForType[0], type) : Activator.CreateInstance(type); - } - - /// - /// Creates an instance of the specified type using the constructor that best matches the specified parameters. - /// - /// The type of object to create.An array of constructor arguments. - /// A reference to the created object. - public object CreateInstance(Type type, params object[] ctorArgs) - { - return Activator.CreateInstance(type, ctorArgs); - } + /// + /// Creates an instance of the specified type. + /// + /// The type of object to create.true if a public or nonpublic default constructor can match; false if only a public default constructor can match. + /// A reference to the created object + public object CreateInstance(Type type, bool nonPublic) + { + var namesForType = listableObjectFactory.GetObjectNamesForType(type); + return namesForType.Count > 0 ? listableObjectFactory.GetObject(namesForType[0], type) : Activator.CreateInstance(type); + } + /// + /// Creates an instance of the specified type using the constructor that best matches the specified parameters. + /// + /// The type of object to create.An array of constructor arguments. + /// A reference to the created object. + public object CreateInstance(Type type, params object[] ctorArgs) + { + return Activator.CreateInstance(type, ctorArgs); } } diff --git a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Bytecode/ProxyFactory.cs b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Bytecode/ProxyFactory.cs index 6609b922..5948d82c 100644 --- a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Bytecode/ProxyFactory.cs +++ b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Bytecode/ProxyFactory.cs @@ -19,57 +19,56 @@ using NHibernate; using NHibernate.Engine; using NHibernate.Proxy; -namespace Spring.Data.NHibernate.Bytecode +namespace Spring.Data.NHibernate.Bytecode; + +/// +/// A Spring for .NET backed implementation for creating +/// NHibernate proxies. +/// +/// +/// Erich Eichinger +public class ProxyFactory : AbstractProxyFactory { - /// - /// A Spring for .NET backed implementation for creating - /// NHibernate proxies. - /// - /// - /// Erich Eichinger - public class ProxyFactory : AbstractProxyFactory + private static readonly ILogger log = LogManager.GetLogger(); + + [Serializable] + private class SerializableProxyFactory : global::Spring.Aop.Framework.ProxyFactory { - private static readonly ILogger log = LogManager.GetLogger(); - - [Serializable] - private class SerializableProxyFactory : global::Spring.Aop.Framework.ProxyFactory + // ensure proxy types are generated as Serializable + public override bool IsSerializable { - // ensure proxy types are generated as Serializable - public override bool IsSerializable - { - get { return true; } - } + get { return true; } } + } - /// - /// Creates a new proxy. - /// - /// The id value for the proxy to be generated. - /// The session to which the generated proxy will be associated. - /// The generated proxy. - /// Indicates problems generating requested proxy. - public override INHibernateProxy GetProxy(object id, ISessionImplementor session) + /// + /// Creates a new proxy. + /// + /// The id value for the proxy to be generated. + /// The session to which the generated proxy will be associated. + /// The generated proxy. + /// Indicates problems generating requested proxy. + public override INHibernateProxy GetProxy(object id, ISessionImplementor session) + { + try { - try - { - // PersistentClass = PersistentClass.IsInterface ? typeof(object) : PersistentClass - LazyInitializer initializer = new LazyInitializer(EntityName, PersistentClass, - id, GetIdentifierMethod, SetIdentifierMethod, ComponentIdType, session); + // PersistentClass = PersistentClass.IsInterface ? typeof(object) : PersistentClass + LazyInitializer initializer = new LazyInitializer(EntityName, PersistentClass, + id, GetIdentifierMethod, SetIdentifierMethod, ComponentIdType, session); - SerializableProxyFactory proxyFactory = new SerializableProxyFactory(); - proxyFactory.Interfaces = Interfaces; - proxyFactory.TargetSource = initializer; - proxyFactory.ProxyTargetType = IsClassProxy; - proxyFactory.AddAdvice(initializer); + SerializableProxyFactory proxyFactory = new SerializableProxyFactory(); + proxyFactory.Interfaces = Interfaces; + proxyFactory.TargetSource = initializer; + proxyFactory.ProxyTargetType = IsClassProxy; + proxyFactory.AddAdvice(initializer); - object proxyInstance = proxyFactory.GetProxy(); - return (INHibernateProxy)proxyInstance; - } - catch (Exception ex) - { - log.LogError(ex, "Creating a proxy instance failed"); - throw new HibernateException("Creating a proxy instance failed", ex); - } + object proxyInstance = proxyFactory.GetProxy(); + return (INHibernateProxy) proxyInstance; + } + catch (Exception ex) + { + log.LogError(ex, "Creating a proxy instance failed"); + throw new HibernateException("Creating a proxy instance failed", ex); } } } diff --git a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Bytecode/ProxyFactoryFactory.cs b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Bytecode/ProxyFactoryFactory.cs index baa65924..61b190a5 100644 --- a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Bytecode/ProxyFactoryFactory.cs +++ b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Bytecode/ProxyFactoryFactory.cs @@ -17,42 +17,41 @@ using NHibernate.Bytecode; using NHibernate.Proxy; -namespace Spring.Data.NHibernate.Bytecode +namespace Spring.Data.NHibernate.Bytecode; + +/// +/// Creates a Spring for .NET backed instance. +/// +/// Erich Eichinger +public class ProxyFactoryFactory : IProxyFactoryFactory { /// - /// Creates a Spring for .NET backed instance. + /// Build a proxy factory specifically for handling runtime lazy loading. /// - /// Erich Eichinger - public class ProxyFactoryFactory : IProxyFactoryFactory + /// The lazy-load proxy factory. + public IProxyFactory BuildProxyFactory() { - /// - /// Build a proxy factory specifically for handling runtime lazy loading. - /// - /// The lazy-load proxy factory. - public IProxyFactory BuildProxyFactory() - { - return new ProxyFactory(); - } + return new ProxyFactory(); + } - /// - /// - public bool IsInstrumented(Type entityClass) - { - return false; - } + /// + /// + public bool IsInstrumented(Type entityClass) + { + return false; + } - /// - /// - public bool IsProxy(object entity) - { - return (entity is INHibernateProxy); - } + /// + /// + public bool IsProxy(object entity) + { + return (entity is INHibernateProxy); + } - /// - /// - public IProxyValidator ProxyValidator - { - get { return new DynProxyTypeValidator(); } - } + /// + /// + public IProxyValidator ProxyValidator + { + get { return new DynProxyTypeValidator(); } } } diff --git a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Bytecode/ReflectionOptimizer.cs b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Bytecode/ReflectionOptimizer.cs index 31f1263b..9a874bae 100644 --- a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Bytecode/ReflectionOptimizer.cs +++ b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Bytecode/ReflectionOptimizer.cs @@ -15,55 +15,53 @@ */ using NHibernate.Properties; - using Spring.Objects.Factory; -namespace Spring.Data.NHibernate.Bytecode +namespace Spring.Data.NHibernate.Bytecode; + +/// +/// +/// +/// Fabio Maulo +public class ReflectionOptimizer : global::NHibernate.Bytecode.Lightweight.ReflectionOptimizer { - /// - /// - /// - /// Fabio Maulo - public class ReflectionOptimizer : global::NHibernate.Bytecode.Lightweight.ReflectionOptimizer + private readonly IListableObjectFactory listableObjectFactory; + + /// + /// + /// + /// + /// + /// + public ReflectionOptimizer(IListableObjectFactory listableObjectFactory, Type mappedType, IGetter[] getters, + ISetter[] setters) + : base(mappedType, getters, setters) { - private readonly IListableObjectFactory listableObjectFactory; + this.listableObjectFactory = listableObjectFactory; + } - /// - /// - /// - /// - /// - /// - public ReflectionOptimizer(IListableObjectFactory listableObjectFactory, Type mappedType, IGetter[] getters, - ISetter[] setters) - : base(mappedType, getters, setters) + /// + /// Perform instantiation of an instance of the underlying class. + /// + /// The new instance. + public override object CreateInstance() + { + var namesForType = listableObjectFactory.GetObjectNamesForType(mappedType); + if (namesForType.Count > 0) { - this.listableObjectFactory = listableObjectFactory; + return listableObjectFactory.GetObject(namesForType[0], mappedType); } - - /// - /// Perform instantiation of an instance of the underlying class. - /// - /// The new instance. - public override object CreateInstance() - { - var namesForType = listableObjectFactory.GetObjectNamesForType(mappedType); - if (namesForType.Count > 0) - { - return listableObjectFactory.GetObject(namesForType[0], mappedType); - } - else - { - return base.CreateInstance(); - } - } - - /// - /// - /// - /// - protected override void ThrowExceptionForNoDefaultCtor(Type type) + else { + return base.CreateInstance(); } } + + /// + /// + /// + /// + protected override void ThrowExceptionForNoDefaultCtor(Type type) + { + } } diff --git a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/DelegatingLocalSessionFactoryObject.cs b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/DelegatingLocalSessionFactoryObject.cs index a783d488..ab59c73c 100644 --- a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/DelegatingLocalSessionFactoryObject.cs +++ b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/DelegatingLocalSessionFactoryObject.cs @@ -1,54 +1,52 @@ using System.Configuration; using NHibernate; - using Configuration = NHibernate.Cfg.Configuration; -namespace Spring.Data.NHibernate +namespace Spring.Data.NHibernate; + +/// +/// Delegates to an implementation of ISessionFactory that can select among multiple instances based on +/// thread local storage. +/// +public class DelegatingLocalSessionFactoryObject : LocalSessionFactoryObject { - /// - /// Delegates to an implementation of ISessionFactory that can select among multiple instances based on - /// thread local storage. - /// - public class DelegatingLocalSessionFactoryObject : LocalSessionFactoryObject + /// + /// Subclasses can override this method to perform custom initialization + /// of the SessionFactory instance, creating it via the given Configuration + /// object that got prepared by this LocalSessionFactoryObject. + /// + /// + ///

The default implementation invokes Configuration's BuildSessionFactory. + /// A custom implementation could prepare the instance in a specific way, + /// or use a custom ISessionFactory subclass. + ///

+ ///
+ /// The ISessionFactory instance. + protected override ISessionFactory NewSessionFactory(Configuration config) { - /// - /// Subclasses can override this method to perform custom initialization - /// of the SessionFactory instance, creating it via the given Configuration - /// object that got prepared by this LocalSessionFactoryObject. - /// - /// - ///

The default implementation invokes Configuration's BuildSessionFactory. - /// A custom implementation could prepare the instance in a specific way, - /// or use a custom ISessionFactory subclass. - ///

- ///
- /// The ISessionFactory instance. - protected override ISessionFactory NewSessionFactory(Configuration config) + return new SimpleDelegatingSessionFactory(config); + } + + /// + /// PostProcessConfiguration + /// + /// + protected override void PostProcessConfiguration(Configuration config) + { + // called before NewSessionFactory + string connectionStringName; + config.Properties.TryGetValue(global::NHibernate.Cfg.Environment.ConnectionStringName, out connectionStringName); + var settings = ConfigurationManager.ConnectionStrings[connectionStringName ?? string.Empty]; + + if (settings != null) { - return new SimpleDelegatingSessionFactory(config); + config.Properties.Add(new KeyValuePair(global::NHibernate.Cfg.Environment.ConnectionString, settings.ConnectionString)); } - /// - /// PostProcessConfiguration - /// - /// - protected override void PostProcessConfiguration(Configuration config) + // called before NewSessionFactory + if (!config.Properties.ContainsKey(global::NHibernate.Cfg.Environment.ConnectionString)) { - // called before NewSessionFactory - string connectionStringName; - config.Properties.TryGetValue(global::NHibernate.Cfg.Environment.ConnectionStringName, out connectionStringName); - var settings = ConfigurationManager.ConnectionStrings[connectionStringName ?? string.Empty]; - - if (settings != null) - { - config.Properties.Add(new KeyValuePair(global::NHibernate.Cfg.Environment.ConnectionString, settings.ConnectionString)); - } - - // called before NewSessionFactory - if (!config.Properties.ContainsKey(global::NHibernate.Cfg.Environment.ConnectionString)) - { - throw new System.ArgumentException("Must specify connection string. If connection_string_name is set to a value, make sure there exists a connection string with that name."); - } + throw new System.ArgumentException("Must specify connection string. If connection_string_name is set to a value, make sure there exists a connection string with that name."); } } } diff --git a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/DelegatingSessionFactory.cs b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/DelegatingSessionFactory.cs index 2d5605f0..90489066 100644 --- a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/DelegatingSessionFactory.cs +++ b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/DelegatingSessionFactory.cs @@ -4,110 +4,108 @@ using NHibernate.Engine; using NHibernate.Metadata; using NHibernate.Stat; -namespace Spring.Data.NHibernate -{ +namespace Spring.Data.NHibernate; #pragma warning disable 1591 - /// - /// DelegatingSessionFactory class - /// - public abstract class DelegatingSessionFactory : ISessionFactory - { - public abstract ISessionFactory TargetSessionFactory { get; } +/// +/// DelegatingSessionFactory class +/// +public abstract class DelegatingSessionFactory : ISessionFactory +{ + public abstract ISessionFactory TargetSessionFactory { get; } - public ICollection DefinedFilterNames => TargetSessionFactory.DefinedFilterNames; + public ICollection DefinedFilterNames => TargetSessionFactory.DefinedFilterNames; - public bool IsClosed => TargetSessionFactory.IsClosed; + public bool IsClosed => TargetSessionFactory.IsClosed; - public IStatistics Statistics => TargetSessionFactory.Statistics; + public IStatistics Statistics => TargetSessionFactory.Statistics; - public void Close() => TargetSessionFactory.Close(); + public void Close() => TargetSessionFactory.Close(); - public void Dispose() => TargetSessionFactory.Dispose(); + public void Dispose() => TargetSessionFactory.Dispose(); - public void Evict(Type persistentClass, object id) => TargetSessionFactory.Evict(persistentClass, id); + public void Evict(Type persistentClass, object id) => TargetSessionFactory.Evict(persistentClass, id); - public void Evict(Type persistentClass) => TargetSessionFactory.Evict(persistentClass); + public void Evict(Type persistentClass) => TargetSessionFactory.Evict(persistentClass); - public void EvictCollection(string roleName, object id) => TargetSessionFactory.EvictCollection(roleName, id); + public void EvictCollection(string roleName, object id) => TargetSessionFactory.EvictCollection(roleName, id); - public void EvictCollection(string roleName) => TargetSessionFactory.EvictCollection(roleName); + public void EvictCollection(string roleName) => TargetSessionFactory.EvictCollection(roleName); - public void EvictEntity(string entityName) => TargetSessionFactory.EvictEntity(entityName); + public void EvictEntity(string entityName) => TargetSessionFactory.EvictEntity(entityName); - public void EvictEntity(string entityName, object id) => TargetSessionFactory.EvictEntity(entityName, id); + public void EvictEntity(string entityName, object id) => TargetSessionFactory.EvictEntity(entityName, id); - public void EvictQueries(string cacheRegion) => TargetSessionFactory.EvictQueries(cacheRegion); + public void EvictQueries(string cacheRegion) => TargetSessionFactory.EvictQueries(cacheRegion); - public void EvictQueries() => TargetSessionFactory.EvictQueries(); + public void EvictQueries() => TargetSessionFactory.EvictQueries(); - public IDictionary GetAllClassMetadata() => TargetSessionFactory.GetAllClassMetadata(); + public IDictionary GetAllClassMetadata() => TargetSessionFactory.GetAllClassMetadata(); - public IDictionary GetAllCollectionMetadata() - => TargetSessionFactory.GetAllCollectionMetadata(); + public IDictionary GetAllCollectionMetadata() + => TargetSessionFactory.GetAllCollectionMetadata(); - public IStatelessSession OpenStatelessSession(DbConnection connection) - => TargetSessionFactory.OpenStatelessSession(connection); + public IStatelessSession OpenStatelessSession(DbConnection connection) + => TargetSessionFactory.OpenStatelessSession(connection); - public IClassMetadata GetClassMetadata(Type persistentType) - => TargetSessionFactory.GetClassMetadata(persistentType); + public IClassMetadata GetClassMetadata(Type persistentType) + => TargetSessionFactory.GetClassMetadata(persistentType); - public IClassMetadata GetClassMetadata(string entityName) - => TargetSessionFactory.GetClassMetadata(entityName); + public IClassMetadata GetClassMetadata(string entityName) + => TargetSessionFactory.GetClassMetadata(entityName); - public ICollectionMetadata GetCollectionMetadata(string roleName) - => TargetSessionFactory.GetCollectionMetadata(roleName); + public ICollectionMetadata GetCollectionMetadata(string roleName) + => TargetSessionFactory.GetCollectionMetadata(roleName); - public ISession GetCurrentSession() => TargetSessionFactory.GetCurrentSession(); + public ISession GetCurrentSession() => TargetSessionFactory.GetCurrentSession(); - public FilterDefinition GetFilterDefinition(string filterName) - => TargetSessionFactory.GetFilterDefinition(filterName); + public FilterDefinition GetFilterDefinition(string filterName) + => TargetSessionFactory.GetFilterDefinition(filterName); - public Task CloseAsync(CancellationToken cancellationToken = new CancellationToken()) - => TargetSessionFactory.CloseAsync(cancellationToken); + public Task CloseAsync(CancellationToken cancellationToken = new CancellationToken()) + => TargetSessionFactory.CloseAsync(cancellationToken); - public Task EvictAsync(Type persistentClass, CancellationToken cancellationToken = new CancellationToken()) - => TargetSessionFactory.EvictAsync(persistentClass, cancellationToken); + public Task EvictAsync(Type persistentClass, CancellationToken cancellationToken = new CancellationToken()) + => TargetSessionFactory.EvictAsync(persistentClass, cancellationToken); - public Task EvictAsync(Type persistentClass, object id, CancellationToken cancellationToken = new CancellationToken()) - => TargetSessionFactory.EvictAsync(persistentClass, id, cancellationToken); + public Task EvictAsync(Type persistentClass, object id, CancellationToken cancellationToken = new CancellationToken()) + => TargetSessionFactory.EvictAsync(persistentClass, id, cancellationToken); - public Task EvictEntityAsync(string entityName, CancellationToken cancellationToken = new CancellationToken()) - => TargetSessionFactory.EvictEntityAsync(entityName, cancellationToken); + public Task EvictEntityAsync(string entityName, CancellationToken cancellationToken = new CancellationToken()) + => TargetSessionFactory.EvictEntityAsync(entityName, cancellationToken); - public Task EvictEntityAsync(string entityName, object id, CancellationToken cancellationToken = new CancellationToken()) - => TargetSessionFactory.EvictEntityAsync(entityName, id, cancellationToken); + public Task EvictEntityAsync(string entityName, object id, CancellationToken cancellationToken = new CancellationToken()) + => TargetSessionFactory.EvictEntityAsync(entityName, id, cancellationToken); - public Task EvictCollectionAsync(string roleName, CancellationToken cancellationToken = new CancellationToken()) - => TargetSessionFactory.EvictCollectionAsync(roleName, cancellationToken); + public Task EvictCollectionAsync(string roleName, CancellationToken cancellationToken = new CancellationToken()) + => TargetSessionFactory.EvictCollectionAsync(roleName, cancellationToken); - public Task EvictCollectionAsync(string roleName, object id, CancellationToken cancellationToken = new CancellationToken()) - => TargetSessionFactory.EvictCollectionAsync(roleName, id, cancellationToken); + public Task EvictCollectionAsync(string roleName, object id, CancellationToken cancellationToken = new CancellationToken()) + => TargetSessionFactory.EvictCollectionAsync(roleName, id, cancellationToken); - public Task EvictQueriesAsync(CancellationToken cancellationToken = new CancellationToken()) - => TargetSessionFactory.EvictQueriesAsync(cancellationToken); + public Task EvictQueriesAsync(CancellationToken cancellationToken = new CancellationToken()) + => TargetSessionFactory.EvictQueriesAsync(cancellationToken); - public Task EvictQueriesAsync(string cacheRegion, CancellationToken cancellationToken = new CancellationToken()) - => TargetSessionFactory.EvictQueriesAsync(cacheRegion, cancellationToken); + public Task EvictQueriesAsync(string cacheRegion, CancellationToken cancellationToken = new CancellationToken()) + => TargetSessionFactory.EvictQueriesAsync(cacheRegion, cancellationToken); - public ISessionBuilder WithOptions() => TargetSessionFactory.WithOptions(); + public ISessionBuilder WithOptions() => TargetSessionFactory.WithOptions(); - public IStatelessSessionBuilder WithStatelessOptions() => TargetSessionFactory.WithStatelessOptions(); + public IStatelessSessionBuilder WithStatelessOptions() => TargetSessionFactory.WithStatelessOptions(); - public ISession OpenSession(IInterceptor interceptor) => TargetSessionFactory.OpenSession(interceptor); + public ISession OpenSession(IInterceptor interceptor) => TargetSessionFactory.OpenSession(interceptor); - public ISession OpenSession() => TargetSessionFactory.OpenSession(); + public ISession OpenSession() => TargetSessionFactory.OpenSession(); - public ISession OpenSession(DbConnection conn, IInterceptor interceptor) - => TargetSessionFactory.OpenSession(conn, interceptor); + public ISession OpenSession(DbConnection conn, IInterceptor interceptor) + => TargetSessionFactory.OpenSession(conn, interceptor); - public ISession OpenSession(DbConnection conn) => TargetSessionFactory.OpenSession(conn); + public ISession OpenSession(DbConnection conn) => TargetSessionFactory.OpenSession(conn); - public IStatelessSession OpenStatelessSession() => TargetSessionFactory.OpenStatelessSession(); + public IStatelessSession OpenStatelessSession() => TargetSessionFactory.OpenStatelessSession(); - IDictionary ISessionFactory.GetAllClassMetadata() - => TargetSessionFactory.GetAllClassMetadata(); + IDictionary ISessionFactory.GetAllClassMetadata() + => TargetSessionFactory.GetAllClassMetadata(); - IDictionary ISessionFactory.GetAllCollectionMetadata() - => TargetSessionFactory.GetAllCollectionMetadata(); - } + IDictionary ISessionFactory.GetAllCollectionMetadata() + => TargetSessionFactory.GetAllCollectionMetadata(); } diff --git a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/FilterDefinitionFactoryObject.cs b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/FilterDefinitionFactoryObject.cs index 41f673a5..75283437 100644 --- a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/FilterDefinitionFactoryObject.cs +++ b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/FilterDefinitionFactoryObject.cs @@ -17,152 +17,149 @@ using System.Collections; using NHibernate.Engine; using NHibernate.Type; - using Spring.Objects.Factory; -namespace Spring.Data.NHibernate +namespace Spring.Data.NHibernate; + +/// +/// Convenient FactoryObject for defining Hibernate FilterDefinitions. +/// Exposes a corresponding Hibernate FilterDefinition object. +/// +/// +/// +///

+/// Typically defined as an inner object within a LocalSessionFactoryObject +/// definition, as the list element for the "filterDefinitions" object property. +/// For example: +///

+/// +///
+/// <objectn id="sessionFactory" type="Spring.Data.NHibernate.LocalSessionFactoryObject, Spring.Data.NHibernate">
+///   ...
+///   <property name="FilterDefinitions">
+///    <list>
+///       <object type="Spring.Data.NHibernate.FilterDefinitionFactoryObject, Spring.Data.NHibernate">
+///         <property name="FilterName" value="myFilter"/>
+///         <property name="ParameterTypes">
+///           <props>
+///             <prop key="MyParam">string</prop>
+///             <prop key="MyOtherParam">long</prop>
+///           </props>
+///         </property>
+///       </object>
+///     </list>
+///   </property>
+///   ...
+/// </object>
+/// 
+///

+/// Alternatively, specify an object id (or name) attribute for the inner object, +/// instead of the "FilterName" property. +///

+///
+/// Juergen Hoeller +/// Marko Lahma (.NET) +/// +/// +/// $Id: FilterDefiniitionFactoryObject.cs,v 1.1 2008/04/07 20:12:53 lahma Exp $ +public class FilterDefinitionFactoryObject : IFactoryObject, IObjectNameAware, IInitializingObject { + private string filterName; + + private IDictionary parameterTypeMap = new Dictionary(); + + private string defaultFilterCondition; + + private FilterDefinition filterDefinition; + /// - /// Convenient FactoryObject for defining Hibernate FilterDefinitions. - /// Exposes a corresponding Hibernate FilterDefinition object. + /// Set the name of the filter. /// - /// - /// - ///

- /// Typically defined as an inner object within a LocalSessionFactoryObject - /// definition, as the list element for the "filterDefinitions" object property. - /// For example: - ///

- /// - ///
-    /// <objectn id="sessionFactory" type="Spring.Data.NHibernate.LocalSessionFactoryObject, Spring.Data.NHibernate">
-    ///   ...
-    ///   <property name="FilterDefinitions">
-    ///    <list>
-    ///       <object type="Spring.Data.NHibernate.FilterDefinitionFactoryObject, Spring.Data.NHibernate">
-    ///         <property name="FilterName" value="myFilter"/>
-    ///         <property name="ParameterTypes">
-    ///           <props>
-    ///             <prop key="MyParam">string</prop>
-    ///             <prop key="MyOtherParam">long</prop>
-    ///           </props>
-    ///         </property>
-    ///       </object>
-    ///     </list>
-    ///   </property>
-    ///   ...
-    /// </object>
-    /// 
- ///

- /// Alternatively, specify an object id (or name) attribute for the inner object, - /// instead of the "FilterName" property. - ///

- ///
- /// Juergen Hoeller - /// Marko Lahma (.NET) - /// - /// - /// $Id: FilterDefiniitionFactoryObject.cs,v 1.1 2008/04/07 20:12:53 lahma Exp $ - public class FilterDefinitionFactoryObject : IFactoryObject, IObjectNameAware, IInitializingObject + public string FilterName { - private string filterName; + set { this.filterName = value; } + } - private IDictionary parameterTypeMap = new Dictionary(); - - private string defaultFilterCondition; - - private FilterDefinition filterDefinition; - - /// - /// Set the name of the filter. - /// - public string FilterName + /// + /// Set the parameter types for the filter, + /// with parameter names as keys and type names as values. + /// + /// + public IDictionary ParameterTypes + { + set { - set { this.filterName = value; } - } - - /// - /// Set the parameter types for the filter, - /// with parameter names as keys and type names as values. - /// - /// - public IDictionary ParameterTypes - { - set + if (value != null) { - if (value != null) + this.parameterTypeMap = new Dictionary(value.Count); + foreach (DictionaryEntry entry in value) { - this.parameterTypeMap = new Dictionary(value.Count); - foreach (DictionaryEntry entry in value) - { - string paramName = (string) entry.Key; - string typeName = (string) entry.Value; - this.parameterTypeMap.Add(paramName, TypeFactory.HeuristicType(typeName)); - } - } - else - { - this.parameterTypeMap = new Dictionary(); + string paramName = (string) entry.Key; + string typeName = (string) entry.Value; + this.parameterTypeMap.Add(paramName, TypeFactory.HeuristicType(typeName)); } } - } - - /// - /// Specify a default filter condition for the filter, if any. - /// - public string DefaultFilterCondition - { - set { this.defaultFilterCondition = value; } - } - - /// - /// If no explicit filter name has been specified, the object name of - /// the FilterDefinitionFactoryObject will be used. - /// - /// - public string ObjectName - { - set + else { - if (this.filterName == null) - { - this.filterName = value; - } + this.parameterTypeMap = new Dictionary(); } } + } - /// - /// Initializes the filter definitions. - /// - public void AfterPropertiesSet() + /// + /// Specify a default filter condition for the filter, if any. + /// + public string DefaultFilterCondition + { + set { this.defaultFilterCondition = value; } + } + + /// + /// If no explicit filter name has been specified, the object name of + /// the FilterDefinitionFactoryObject will be used. + /// + /// + public string ObjectName + { + set { - this.filterDefinition = new FilterDefinition(this.filterName, this.defaultFilterCondition, this.parameterTypeMap, true); + if (this.filterName == null) + { + this.filterName = value; + } } + } - /// - /// Returns the singleton filter definition. - /// - /// - public object GetObject() - { - return this.filterDefinition; - } + /// + /// Initializes the filter definitions. + /// + public void AfterPropertiesSet() + { + this.filterDefinition = new FilterDefinition(this.filterName, this.defaultFilterCondition, this.parameterTypeMap, true); + } - /// - /// Returns the type of the object this factory produces. - /// - public Type ObjectType - { - get { return typeof(FilterDefinition); } - } + /// + /// Returns the singleton filter definition. + /// + /// + public object GetObject() + { + return this.filterDefinition; + } - /// - /// Returns whether this factory produces singletons, always true. - /// - public bool IsSingleton - { - get { return true; } - } + /// + /// Returns the type of the object this factory produces. + /// + public Type ObjectType + { + get { return typeof(FilterDefinition); } + } + /// + /// Returns whether this factory produces singletons, always true. + /// + public bool IsSingleton + { + get { return true; } } } diff --git a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Generic/FindHibernateDelegate.cs b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Generic/FindHibernateDelegate.cs index 2f2ec93f..28669fd5 100644 --- a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Generic/FindHibernateDelegate.cs +++ b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Generic/FindHibernateDelegate.cs @@ -1,12 +1,12 @@ /* * Copyright � 2002-2011 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. @@ -16,21 +16,20 @@ using NHibernate; -namespace Spring.Data.NHibernate.Generic -{ - /// - /// Gets called by HibernateTemplate with an active - /// Hibernate Session. Does not need to care about activating or closing - /// the Session, or handling transactions. - /// - /// - ///

- /// Allows for returning an IList of result objects created within the callback. - /// Note that there's special support for single step actions: - /// see HibernateTemplate.find etc. - ///

- ///
- /// The type of result object - /// Sree Nivask (.NET) - public delegate IList FindHibernateDelegate(ISession session); -} +namespace Spring.Data.NHibernate.Generic; + +/// +/// Gets called by HibernateTemplate with an active +/// Hibernate Session. Does not need to care about activating or closing +/// the Session, or handling transactions. +/// +/// +///

+/// Allows for returning an IList of result objects created within the callback. +/// Note that there's special support for single step actions: +/// see HibernateTemplate.find etc. +///

+///
+/// The type of result object +/// Sree Nivask (.NET) +public delegate IList FindHibernateDelegate(ISession session); diff --git a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Generic/HibernateDaoSupport.cs b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Generic/HibernateDaoSupport.cs index d841bcf8..bfd394fb 100644 --- a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Generic/HibernateDaoSupport.cs +++ b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Generic/HibernateDaoSupport.cs @@ -1,12 +1,12 @@ /* * Copyright � 2002-2011 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. @@ -18,192 +18,191 @@ using NHibernate; using Spring.Dao; using Spring.Dao.Support; -namespace Spring.Data.NHibernate.Generic.Support +namespace Spring.Data.NHibernate.Generic.Support; + +/// +/// Convenient super class for Hibernate data access objects. +/// +/// +/// Requires a SessionFactory to be set, providing a HibernateTemplate +/// based on it to subclasses. Can alternatively be initialized directly with +/// a HibernateTemplate, to reuse the latter's settings such as the SessionFactory, +/// exception translator, flush mode, etc +/// +/// This base call is mainly intended for HibernateTemplate usage. +/// +/// This class will create its own HibernateTemplate if only a SessionFactory +/// is passed in. The "allowCreate" flag on that HibernateTemplate will be "true" +/// by default. A custom HibernateTemplate instance can be used through overriding +/// CreateHibernateTemplate. +/// +/// +/// Sree Nivask (.NET) +/// Mark Pollack (.NET) +public abstract class HibernateDaoSupport : DaoSupport { + private HibernateTemplate hibernateTemplate; + /// - /// Convenient super class for Hibernate data access objects. + /// Initializes a new instance of the class. + /// + public HibernateDaoSupport() + { + } + + /// + /// Gets or sets the hibernate template. + /// + /// Set the HibernateTemplate for this DAO explicitly, + /// as an alternative to specifying a SessionFactory. + /// + /// The hibernate template. + public HibernateTemplate HibernateTemplate + { + get + { + return hibernateTemplate; + } + set + { + hibernateTemplate = value; + } + } + + /// + /// Gets or sets the session factory to be used by this DAO. + /// Will automatically create a HibernateTemplate for the given SessionFactory. + /// + /// The session factory. + public ISessionFactory SessionFactory + { + get + { + return (this.hibernateTemplate != null ? this.hibernateTemplate.SessionFactory : null); + } + set + { + hibernateTemplate = CreateHibernateTemplate(value); + } + } + + /// + /// Get a Hibernate Session, either from the current transaction or a new one. + /// The latter is only allowed if the "allowCreate" setting of this object's + /// HibernateTemplate is true. /// /// - /// Requires a SessionFactory to be set, providing a HibernateTemplate - /// based on it to subclasses. Can alternatively be initialized directly with - /// a HibernateTemplate, to reuse the latter's settings such as the SessionFactory, - /// exception translator, flush mode, etc - /// - /// This base call is mainly intended for HibernateTemplate usage. + ///

Note that this is not meant to be invoked from HibernateTemplate code + /// but rather just in plain Hibernate code. Use it in combination with + /// ReleaseSession. + ///

+ ///

In general, it is recommended to use HibernateTemplate, either with + /// the provided convenience operations or with a custom HibernateCallback + /// that provides you with a Session to work on. HibernateTemplate will care + /// for all resource management and for proper exception conversion. + ///

+ ///
+ /// The Hibernate session. + public ISession Session + { + get + { + return DoGetSession(HibernateTemplate.AllowCreate); + } + } + + /// + /// Create a HibernateTemplate for the given ISessionFactory. + /// + /// + /// Only invoked if populating the DAO with a ISessionFactory reference! + ///

Can be overridden in subclasses to provide a HibernateTemplate instance + /// with different configuration, or a custom HibernateTemplate subclass. + ///

+ ///
+ /// The new HibernateTemplate instance + protected virtual HibernateTemplate CreateHibernateTemplate(ISessionFactory sessionFactory) + { + return new HibernateTemplate(sessionFactory); + } + + /// + /// Check if the hibernate template property has been set. + /// + /// If HibernateTemplate property is null. + protected override void CheckDaoConfig() + { + if (this.hibernateTemplate == null) + { + throw new ArgumentException("sessionFactory or hibernateTemplate is required"); + } + } + + /// + /// Get a Hibernate Session, either from the current transaction or + /// a new one. The latter is only allowed if "allowCreate" is true. + /// + /// Note that this is not meant to be invoked from HibernateTemplate code + /// but rather just in plain Hibernate code. Either rely on a thread-bound + /// Session (via HibernateInterceptor), or use it in combination with + /// ReleaseSession. /// - /// This class will create its own HibernateTemplate if only a SessionFactory - /// is passed in. The "allowCreate" flag on that HibernateTemplate will be "true" - /// by default. A custom HibernateTemplate instance can be used through overriding - /// CreateHibernateTemplate. + /// In general, it is recommended to use HibernateTemplate, either with + /// the provided convenience operations or with a custom HibernateCallback + /// that provides you with a Session to work on. HibernateTemplate will care + /// for all resource management and for proper exception conversion. /// /// - /// Sree Nivask (.NET) - /// Mark Pollack (.NET) - public abstract class HibernateDaoSupport : DaoSupport - { - private HibernateTemplate hibernateTemplate; + /// if a non-transactional Session should be created when no + /// transactional Session can be found for the current thread + /// + /// Hibernate session. + /// + /// If the Session couldn't be created + /// + /// + /// if no thread-bound Session found and allowCreate false + /// + /// + protected ISession DoGetSession(bool allowCreate) + { + return (!allowCreate + ? SessionFactoryUtils.GetSession(SessionFactory, false) + : SessionFactoryUtils.GetSession( + SessionFactory, + this.hibernateTemplate.EntityInterceptor, + this.hibernateTemplate.AdoExceptionTranslator)); + } - /// - /// Initializes a new instance of the class. - /// - public HibernateDaoSupport() - { + /// + /// Convert the given HibernateException to an appropriate exception from the + /// org.springframework.dao hierarchy. Will automatically detect + /// wrapped ADO.NET Exceptions and convert them accordingly. + /// + /// HibernateException that occured. + /// + /// The corresponding DataAccessException instance + /// + /// + /// The default implementation delegates to SessionFactoryUtils + /// and convertAdoAccessException. Can be overridden in subclasses. + /// + protected DataAccessException ConvertHibernateAccessException(HibernateException ex) + { + return hibernateTemplate.ConvertHibernateAccessException(ex); + } - } - - /// - /// Gets or sets the hibernate template. - /// - /// Set the HibernateTemplate for this DAO explicitly, - /// as an alternative to specifying a SessionFactory. - /// - /// The hibernate template. - public HibernateTemplate HibernateTemplate - { - get - { - return hibernateTemplate; - } - set - { - hibernateTemplate = value; - } - } - - /// - /// Gets or sets the session factory to be used by this DAO. - /// Will automatically create a HibernateTemplate for the given SessionFactory. - /// - /// The session factory. - public ISessionFactory SessionFactory - { - get - { - return (this.hibernateTemplate != null ? this.hibernateTemplate.SessionFactory : null); - } - set - { - hibernateTemplate = CreateHibernateTemplate(value); - } - } - - /// - /// Get a Hibernate Session, either from the current transaction or a new one. - /// The latter is only allowed if the "allowCreate" setting of this object's - /// HibernateTemplate is true. - /// - /// - ///

Note that this is not meant to be invoked from HibernateTemplate code - /// but rather just in plain Hibernate code. Use it in combination with - /// ReleaseSession. - ///

- ///

In general, it is recommended to use HibernateTemplate, either with - /// the provided convenience operations or with a custom HibernateCallback - /// that provides you with a Session to work on. HibernateTemplate will care - /// for all resource management and for proper exception conversion. - ///

- ///
- /// The Hibernate session. - public ISession Session - { - get - { - return DoGetSession(HibernateTemplate.AllowCreate); - } - } - - /// - /// Create a HibernateTemplate for the given ISessionFactory. - /// - /// - /// Only invoked if populating the DAO with a ISessionFactory reference! - ///

Can be overridden in subclasses to provide a HibernateTemplate instance - /// with different configuration, or a custom HibernateTemplate subclass. - ///

- ///
- /// The new HibernateTemplate instance - protected virtual HibernateTemplate CreateHibernateTemplate(ISessionFactory sessionFactory) - { - return new HibernateTemplate(sessionFactory); - } - - /// - /// Check if the hibernate template property has been set. - /// - /// If HibernateTemplate property is null. - protected override void CheckDaoConfig() - { - if (this.hibernateTemplate == null) - { - throw new ArgumentException("sessionFactory or hibernateTemplate is required"); - } - } - /// - /// Get a Hibernate Session, either from the current transaction or - /// a new one. The latter is only allowed if "allowCreate" is true. - /// - /// Note that this is not meant to be invoked from HibernateTemplate code - /// but rather just in plain Hibernate code. Either rely on a thread-bound - /// Session (via HibernateInterceptor), or use it in combination with - /// ReleaseSession. - /// - /// In general, it is recommended to use HibernateTemplate, either with - /// the provided convenience operations or with a custom HibernateCallback - /// that provides you with a Session to work on. HibernateTemplate will care - /// for all resource management and for proper exception conversion. - /// - /// - /// if a non-transactional Session should be created when no - /// transactional Session can be found for the current thread - /// - /// Hibernate session. - /// - /// If the Session couldn't be created - /// - /// - /// if no thread-bound Session found and allowCreate false - /// - /// - protected ISession DoGetSession(bool allowCreate) - { - return (!allowCreate ? - SessionFactoryUtils.GetSession(SessionFactory, false) : - SessionFactoryUtils.GetSession( - SessionFactory, - this.hibernateTemplate.EntityInterceptor, - this.hibernateTemplate.AdoExceptionTranslator)); - } - - /// - /// Convert the given HibernateException to an appropriate exception from the - /// org.springframework.dao hierarchy. Will automatically detect - /// wrapped ADO.NET Exceptions and convert them accordingly. - /// - /// HibernateException that occured. - /// - /// The corresponding DataAccessException instance - /// - /// - /// The default implementation delegates to SessionFactoryUtils - /// and convertAdoAccessException. Can be overridden in subclasses. - /// - protected DataAccessException ConvertHibernateAccessException(HibernateException ex) - { - return hibernateTemplate.ConvertHibernateAccessException(ex); - } - - /// - /// Close the given Hibernate Session, created via this DAO's SessionFactory, - /// if it isn't bound to the thread. - /// - /// - /// Typically used in plain Hibernate code, in combination with the - /// Session property and ConvertHibernateAccessException. - /// - /// The session to close. - protected void ReleaseSession(ISession session) - { - SessionFactoryUtils.ReleaseSession(session, SessionFactory); - } - } + /// + /// Close the given Hibernate Session, created via this DAO's SessionFactory, + /// if it isn't bound to the thread. + /// + /// + /// Typically used in plain Hibernate code, in combination with the + /// Session property and ConvertHibernateAccessException. + /// + /// The session to close. + protected void ReleaseSession(ISession session) + { + SessionFactoryUtils.ReleaseSession(session, SessionFactory); + } } diff --git a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Generic/HibernateDelegate.cs b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Generic/HibernateDelegate.cs index d069d44d..804e96d1 100644 --- a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Generic/HibernateDelegate.cs +++ b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Generic/HibernateDelegate.cs @@ -1,12 +1,12 @@ /* - * Copyright © 2002-2011 the original author or authors. - * + * Copyright � 2002-2011 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. @@ -16,21 +16,20 @@ using NHibernate; -namespace Spring.Data.NHibernate.Generic -{ - /// - /// Gets called by HibernateTemplate with an active - /// Hibernate Session. Does not need to care about activating or closing - /// the Session, or handling transactions. - /// - /// - ///

- /// Allows for returning the result object created within the callback. - /// Note that there's special support for single step actions: - /// see HibernateTemplate.find etc. - ///

- ///
- /// The type of result object - /// Sree Nivask (.NET) - public delegate T HibernateDelegate(ISession session); -} +namespace Spring.Data.NHibernate.Generic; + +/// +/// Gets called by HibernateTemplate with an active +/// Hibernate Session. Does not need to care about activating or closing +/// the Session, or handling transactions. +/// +/// +///

+/// Allows for returning the result object created within the callback. +/// Note that there's special support for single step actions: +/// see HibernateTemplate.find etc. +///

+///
+/// The type of result object +/// Sree Nivask (.NET) +public delegate T HibernateDelegate(ISession session); diff --git a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Generic/HibernateTemplate.cs b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Generic/HibernateTemplate.cs index 42478cbd..e6f53d83 100644 --- a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Generic/HibernateTemplate.cs +++ b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Generic/HibernateTemplate.cs @@ -22,1637 +22,1642 @@ using Spring.Data.Common; using Spring.Data.Support; using Spring.Objects.Factory; -namespace Spring.Data.NHibernate.Generic +namespace Spring.Data.NHibernate.Generic; + +/// +/// Generic version of the Helper class that simplifies NHibernate data access code +/// +/// +///

Typically used to implement data access or business logic services that +/// use NHibernate within their implementation but are Hibernate-agnostic in their +/// interface. The latter or code calling the latter only have to deal with +/// domain objects.

+/// +///

The central method is Execute() supporting Hibernate access code which +/// implements the HibernateCallback interface. It provides NHibernate Session +/// handling such that neither the IHibernateCallback implementation nor the calling +/// code needs to explicitly care about retrieving/closing NHibernate Sessions, +/// or handling Session lifecycle exceptions. For typical single step actions, +/// there are various convenience methods (Find, Load, SaveOrUpdate, Delete). +///

+/// +///

Can be used within a service implementation via direct instantiation +/// with a ISessionFactory reference, or get prepared in an application context +/// and given to services as an object reference. Note: The ISessionFactory should +/// always be configured as an object in the application context, in the first case +/// given to the service directly, in the second case to the prepared template. +///

+/// +///

This class can be considered as a direct alternative to working with the raw +/// Hibernate Session API (through SessionFactoryUtils.Session). +///

+/// +///

LocalSessionFactoryObject is the preferred way of obtaining a reference +/// to a specific NHibernate ISessionFactory. +///

+///
+/// Sree Nivask (.NET) +/// Mark Pollack (.NET) +public class HibernateTemplate : HibernateAccessor, IHibernateOperations { + NHibernate.HibernateTemplate classicHibernateTemplate; + /// - /// Generic version of the Helper class that simplifies NHibernate data access code + /// Initializes a new instance of the class. /// + public HibernateTemplate() + { + classicHibernateTemplate = new NHibernate.HibernateTemplate(); + } + + /// + /// Initializes a new instance of the class. + /// + /// Allows creation of a new non-transactional session when no + /// transactional Session can be found for the current thread + /// The session factory to create sessions. + public HibernateTemplate(ISessionFactory sessionFactory) + { + classicHibernateTemplate = new Spring.Data.NHibernate.HibernateTemplate(sessionFactory); + AfterPropertiesSet(); + } + + /// + /// Initializes a new instance of the class. + /// + /// The session factory to create sessions. + /// if set to true allow creation + /// of a new non-transactional session when no transactional Session can be found + /// for the current thread. + public HibernateTemplate(ISessionFactory sessionFactory, bool allowCreate) + { + classicHibernateTemplate = new Spring.Data.NHibernate.HibernateTemplate(sessionFactory, allowCreate); + AfterPropertiesSet(); + } + + /// + /// Gets or sets if a new Session should be created when no transactional Session + /// can be found for the current thread. + /// + /// + /// true if allowed to create non-transaction session; + /// otherwise, false. + /// /// - ///

Typically used to implement data access or business logic services that - /// use NHibernate within their implementation but are Hibernate-agnostic in their - /// interface. The latter or code calling the latter only have to deal with - /// domain objects.

- /// - ///

The central method is Execute() supporting Hibernate access code which - /// implements the HibernateCallback interface. It provides NHibernate Session - /// handling such that neither the IHibernateCallback implementation nor the calling - /// code needs to explicitly care about retrieving/closing NHibernate Sessions, - /// or handling Session lifecycle exceptions. For typical single step actions, - /// there are various convenience methods (Find, Load, SaveOrUpdate, Delete). - ///

- /// - ///

Can be used within a service implementation via direct instantiation - /// with a ISessionFactory reference, or get prepared in an application context - /// and given to services as an object reference. Note: The ISessionFactory should - /// always be configured as an object in the application context, in the first case - /// given to the service directly, in the second case to the prepared template. - ///

- /// - ///

This class can be considered as a direct alternative to working with the raw - /// Hibernate Session API (through SessionFactoryUtils.Session). - ///

- /// - ///

LocalSessionFactoryObject is the preferred way of obtaining a reference - /// to a specific NHibernate ISessionFactory. + ///

HibernateTemplate is aware of a corresponding Session bound to the + /// current thread, for example when using HibernateTransactionManager. + /// If allowCreate is true, a new non-transactional Session will be created + /// if none found, which needs to be closed at the end of the operation. + /// If false, an InvalidOperationException will get thrown in this case. ///

///
- /// Sree Nivask (.NET) - /// Mark Pollack (.NET) - public class HibernateTemplate : HibernateAccessor, IHibernateOperations + public override bool AllowCreate { - NHibernate.HibernateTemplate classicHibernateTemplate; + get { return classicHibernateTemplate.AllowCreate; } + set { classicHibernateTemplate.AllowCreate = value; } + } - /// - /// Initializes a new instance of the class. - /// - public HibernateTemplate() + /// + /// Gets or sets a value indicating whether to always + /// use a new Hibernate Session for this template. + /// + /// true if always use new session; otherwise, false. + /// + ///

+ /// Default is "false"; if activated, all operations on this template will + /// work on a new NHibernate ISession even in case of a pre-bound ISession + /// (for example, within a transaction). + ///

+ ///

Within a transaction, a new NHibernate ISession used by this template + /// will participate in the transaction through using the same ADO.NET + /// Connection. In such a scenario, multiple Sessions will participate + /// in the same database transaction. + ///

+ ///

Turn this on for operations that are supposed to always execute + /// independently, without side effects caused by a shared NHibernate ISession. + ///

+ ///
+ public override bool AlwaysUseNewSession + { + get { return classicHibernateTemplate.AlwaysUseNewSession; } + set { classicHibernateTemplate.AlwaysUseNewSession = value; } + } + + /// + /// Set whether to expose the native Hibernate Session to IHibernateCallback + /// code. Default is "false": a Session proxy will be returned, + /// suppressing close calls and automatically applying + /// query cache settings and transaction timeouts. + /// + /// true if expose native session; otherwise, false. + public override bool ExposeNativeSession + { + get { return classicHibernateTemplate.ExposeNativeSession; } + set { classicHibernateTemplate.ExposeNativeSession = value; } + } + + /// + /// Gets or sets the template flush mode. + /// + /// + /// Default is Auto. Will get applied to any new ISession + /// created by the template. + /// + /// The template flush mode. + public override TemplateFlushMode TemplateFlushMode + { + get { return classicHibernateTemplate.TemplateFlushMode; } + set { classicHibernateTemplate.TemplateFlushMode = value; } + } + + /// + /// Gets or sets the entity interceptor that allows to inspect and change + /// property values before writing to and reading from the database. + /// + /// + /// Will get applied to any new ISession created by this object. + ///

Such an interceptor can either be set at the ISessionFactory level, + /// i.e. on LocalSessionFactoryObject, or at the ISession level, i.e. on + /// HibernateTemplate, HibernateInterceptor, and HibernateTransactionManager. + /// It's preferable to set it on LocalSessionFactoryObject or HibernateTransactionManager + /// to avoid repeated configuration and guarantee consistent behavior in transactions. + ///

+ ///
+ /// The interceptor. + public override IInterceptor EntityInterceptor + { + get { return classicHibernateTemplate.EntityInterceptor; } + set { classicHibernateTemplate.EntityInterceptor = value; } + } + + /// + /// Set the object name of a Hibernate entity interceptor that allows to inspect + /// and change property values before writing to and reading from the database. + /// + /// + /// Will get applied to any new Session created by this transaction manager. + ///

Requires the object factory to be known, to be able to resolve the object + /// name to an interceptor instance on session creation. Typically used for + /// prototype interceptors, i.e. a new interceptor instance per session. + ///

+ ///

Can also be used for shared interceptor instances, but it is recommended + /// to set the interceptor reference directly in such a scenario. + ///

+ ///
+ /// The name of the entity interceptor in the object factory/application context. + public override string EntityInterceptorObjectName + { + set { classicHibernateTemplate.EntityInterceptorObjectName = value; } + } + + /// + /// Gets or sets the session factory that should be used to create + /// NHibernate ISessions. + /// + /// The session factory. + public override ISessionFactory SessionFactory + { + get { return classicHibernateTemplate.SessionFactory; } + set { classicHibernateTemplate.SessionFactory = value; } + } + + /// + /// Set the object factory instance. + /// + /// The object factory instance + public override IObjectFactory ObjectFactory + { + set { classicHibernateTemplate.ObjectFactory = value; } + } + + /// + /// Gets or sets a value indicating whether to + /// cache all queries executed by this template. + /// + /// + /// If this is true, all IQuery and ICriteria objects created by + /// this template will be marked as cacheable (including all + /// queries through find methods). + ///

To specify the query region to be used for queries cached + /// by this template, set the QueryCacheRegion property. + ///

+ ///
+ /// true if cache queries; otherwise, false. + public override bool CacheQueries + { + get { return classicHibernateTemplate.CacheQueries; } + set { classicHibernateTemplate.CacheQueries = value; } + } + + /// + /// Gets or sets the name of the cache region for queries executed by this template. + /// + /// + /// If this is specified, it will be applied to all IQuery and ICriteria objects + /// created by this template (including all queries through find methods). + ///

The cache region will not take effect unless queries created by this + /// template are configured to be cached via the CacheQueries property. + ///

+ ///
+ /// The query cache region. + public override string QueryCacheRegion + { + get { return classicHibernateTemplate.QueryCacheRegion; } + set { classicHibernateTemplate.QueryCacheRegion = value; } + } + + /// + /// Gets or sets the fetch size for this HibernateTemplate. + /// + /// The size of the fetch. + /// This is important for processing + /// large result sets: Setting this higher than the default value will increase + /// processing speed at the cost of memory consumption; setting this lower can + /// avoid transferring row data that will never be read by the application. + ///

Default is 0, indicating to use the driver's default.

+ ///
+ public override int FetchSize + { + get { return classicHibernateTemplate.FetchSize; } + set { classicHibernateTemplate.FetchSize = value; } + } + + /// + /// Gets or sets the maximum number of rows for this HibernateTemplate. + /// + /// The max results. + /// + /// This is important + /// for processing subsets of large result sets, avoiding to read and hold + /// the entire result set in the database or in the ADO.NET driver if we're + /// never interested in the entire result in the first place (for example, + /// when performing searches that might return a large number of matches). + ///

Default is 0, indicating to use the driver's default.

+ ///
+ public override int MaxResults + { + get { return classicHibernateTemplate.MaxResults; } + set { classicHibernateTemplate.MaxResults = value; } + } + + /// + /// Set the ADO.NET exception translator for this instance. + /// Applied to System.Data.Common.DbException (or provider specific exception type + /// in .NET 1.1) thrown by callback code, be it direct + /// DbException or wrapped Hibernate ADOExceptions. + ///

The default exception translator is either a ErrorCodeExceptionTranslator + /// if a DbProvider is available, or a FalbackExceptionTranslator otherwise + ///

+ ///
+ /// The ADO exception translator. + public override IAdoExceptionTranslator AdoExceptionTranslator + { + get { return classicHibernateTemplate.AdoExceptionTranslator; } + set { classicHibernateTemplate.AdoExceptionTranslator = value; } + } + + /// + /// Gets the classic hibernate template for access to non-generic methods. + /// + /// The classic hibernate template. + public NHibernate.HibernateTemplate ClassicHibernateTemplate + { + get { return classicHibernateTemplate; } + } + + /// + /// Gets or sets the proxy factory. + /// + /// This may be useful to set if you create many instances of + /// HibernateTemplate and/or HibernateDaoSupport. This allows the same + /// ProxyFactory implementation to be used thereby limiting the + /// number of dynamic proxy types created in the temporary assembly, which + /// are never garbage collected due to .NET runtime semantics. + /// + /// The proxy factory. + public virtual ProxyFactory ProxyFactory + { + get { return classicHibernateTemplate.ProxyFactory; } + set { classicHibernateTemplate.ProxyFactory = value; } + } + + /// + /// Remove all objects from the Session cache, and cancel all pending saves, + /// updates and deletes. + /// + public void Clear() + { + classicHibernateTemplate.Clear(); + } + + /// + /// Delete the given persistent instance. + /// + /// The persistent instance to delete. + /// In case of Hibernate errors + public void Delete(object entity) + { + classicHibernateTemplate.Delete(entity); + } + + /// + /// Delete the given persistent instance. + /// + /// The persistent instance to delete. + /// The lock mode to obtain. + /// + /// Obtains the specified lock mode if the instance exists, implicitly + /// checking whether the corresponding database entry still exists + /// (throwing an OptimisticLockingFailureException if not found). + /// + /// In case of Hibernate errors + public void Delete(object entity, LockMode lockMode) + { + classicHibernateTemplate.Delete(entity, lockMode); + } + + /// + /// Delete all objects returned by the query. + /// + /// a query expressed in Hibernate's query language. + /// The number of entity instances deleted. + /// In case of Hibernate errors + public int Delete(string queryString) + { + return classicHibernateTemplate.Delete(queryString); + } + + /// + /// Delete all objects returned by the query. + /// + /// a query expressed in Hibernate's query language. + /// The value of the parameter. + /// The Hibernate type of the parameter (or null). + /// The number of entity instances deleted. + /// In case of Hibernate errors + public int Delete(string queryString, object value, IType type) + { + return classicHibernateTemplate.Delete(queryString, value, type); + } + + /// + /// Delete all objects returned by the query. + /// + /// a query expressed in Hibernate's query language. + /// The values of the parameters. + /// Hibernate types of the parameters (or null) + /// The number of entity instances deleted. + /// In case of Hibernate errors + public int Delete(string queryString, object[] values, IType[] types) + { + return classicHibernateTemplate.Delete(queryString, values, types); + } + + /// + /// Flush all pending saves, updates and deletes to the database. + /// + /// + /// Only invoke this for selective eager flushing, for example when ADO.NET code + /// needs to see certain changes within the same transaction. Else, it's preferable + /// to rely on auto-flushing at transaction completion. + /// + /// In case of Hibernate errors + public void Flush() + { + classicHibernateTemplate.Flush(); + } + + /// + /// Load the persistent instance with the given identifier + /// into the given object, throwing an exception if not found. + /// + /// Entity the object (of the target class) to load into. + /// An identifier of the persistent instance. + /// If object not found. + /// In case of Hibernate errors + public void Load(object entity, object id) + { + classicHibernateTemplate.Load(entity, id); + } + + /// + /// Re-read the state of the given persistent instance. + /// + /// The persistent instance to re-read. + /// In case of Hibernate errors + public void Refresh(object entity) + { + classicHibernateTemplate.Refresh(entity); + } + + /// + /// Re-read the state of the given persistent instance. + /// Obtains the specified lock mode for the instance. + /// + /// The persistent instance to re-read. + /// The lock mode to obtain. + /// In case of Hibernate errors + public void Refresh(object entity, LockMode lockMode) + { + classicHibernateTemplate.Refresh(entity, lockMode); + } + + /// + /// Determines whether the given object is in the Session cache. + /// + /// the persistence instance to check. + /// + /// true if session cache contains the specified entity; otherwise, false. + /// + /// In case of Hibernate errors + public bool Contains(object entity) + { + return classicHibernateTemplate.Contains(entity); + } + + /// + /// Remove the given object from the Session cache. + /// + /// The persistent instance to evict. + /// In case of Hibernate errors + public void Evict(object entity) + { + classicHibernateTemplate.Evict(entity); + } + + /// + /// Obtain the specified lock level upon the given object, implicitly + /// checking whether the corresponding database entry still exists + /// (throwing an OptimisticLockingFailureException if not found). + /// + /// The he persistent instance to lock. + /// The lock mode to obtain. + /// If not found + /// In case of Hibernate errors + public void Lock(object entity, LockMode lockMode) + { + classicHibernateTemplate.Lock(entity, lockMode); + } + + /// + /// Persist the given transient instance. + /// + /// The transient instance to persist. + /// The generated identifier. + /// In case of Hibernate errors + public object Save(object entity) + { + return classicHibernateTemplate.Save(entity); + } + + /// + /// Persist the given transient instance with the given identifier. + /// + /// The transient instance to persist. + /// The identifier to assign. + /// In case of Hibernate errors + public void Save(object entity, object id) + { + classicHibernateTemplate.Save(entity, id); + } + + /// + /// Update the given persistent instance. + /// + /// The persistent instance to update. + /// In case of Hibernate errors + public void Update(object entity) + { + classicHibernateTemplate.Update(entity); + } + + /// + /// Update the given persistent instance. + /// Obtains the specified lock mode if the instance exists, implicitly + /// checking whether the corresponding database entry still exists + /// (throwing an OptimisticLockingFailureException if not found). + /// + /// The persistent instance to update. + /// The lock mode to obtain. + /// In case of Hibernate errors + public void Update(object entity, LockMode lockMode) + { + classicHibernateTemplate.Update(entity, lockMode); + } + + /// + /// Save or update the given persistent instance, + /// according to its id (matching the configured "unsaved-value"?). + /// + /// The persistent instance to save or update + /// (to be associated with the Hibernate Session). + /// In case of Hibernate errors + public void SaveOrUpdate(object entity) + { + classicHibernateTemplate.SaveOrUpdate(entity); + } + + /// + /// Copy the state of the given object onto the persistent object with the same identifier. + /// If there is no persistent instance currently associated with the session, it will be loaded. + /// Return the persistent instance. If the given instance is unsaved, + /// save a copy of and return it as a newly persistent instance. + /// The given instance does not become associated with the session. + /// This operation cascades to associated instances if the association is mapped with cascade="merge". + /// The semantics of this method are defined by JSR-220. + /// + /// The persistent object to merge. + /// (not necessarily to be associated with the Hibernate Session) + /// + /// An updated persistent instance + /// In case of Hibernate errors + public object Merge(object entity) + { + return classicHibernateTemplate.Merge(entity); + } + + /// + /// Return the persistent instance of the given entity type + /// with the given identifier, or null if not found. + /// Obtains the specified lock mode if the instance exists. + /// + /// The object type to get. + /// The id of the object to get. + /// the persistent instance, or null if not found + /// In case of Hibernate errors + public T Get(object id) + { + return Get(id, null); + } + + /// + /// Return the persistent instance of the given entity type + /// with the given identifier, or null if not found. + /// Obtains the specified lock mode if the instance exists. + /// + /// The object type to get. + /// The lock mode to obtain. + /// The lock mode. + /// the persistent instance, or null if not found + /// In case of Hibernate errors + public T Get(object id, LockMode lockMode) + { + return Execute(new GetByTypeHibernateCallback(id, lockMode), true); + } + + /// + /// Return the persistent instance of the given entity class + /// with the given identifier, throwing an exception if not found. + /// + /// The object type to load. + /// An identifier of the persistent instance. + /// The persistent instance + /// If not found + /// In case of Hibernate errors + public T Load(object id) + { + return Load(id, null); + } + + /// + /// Return the persistent instance of the given entity class + /// with the given identifier, throwing an exception if not found. + /// Obtains the specified lock mode if the instance exists. + /// + /// The object type to load. + /// An identifier of the persistent instance. + /// The lock mode. + /// The persistent instance + /// If not found + /// In case of Hibernate errors + public T Load(object id, LockMode lockMode) + { + return Execute(new LoadByTypeHibernateCallback(id, lockMode), true); + } + + /// + /// Return all persistent instances of the given entity class. + /// Note: Use queries or criteria for retrieving a specific subset. + /// + /// The object type to load. + /// A generic List containing 0 or more persistent instances + /// In case of Hibernate errors + public IList LoadAll() + { + return ExecuteFind(new LoadAllByTypeHibernateCallback(this), true); + } + + /// + /// Execute a query for persistent instances. + /// + /// The object type to find. + /// a query expressed in Hibernate's query language + /// + /// a generic List containing 0 or more persistent instances + /// + /// In case of Hibernate errors + public IList Find(string queryString) + { + return Find(queryString, (object[]) null, (IType[]) null); + } + + /// + /// Execute a query for persistent instances, binding + /// one value to a "?" parameter in the query string. + /// + /// The object type to find. + /// a query expressed in Hibernate's query language + /// the value of the parameter + /// + /// a generic List containing 0 or more persistent instances + /// + /// In case of Hibernate errors + public IList Find(string queryString, object value) + { + return Find(queryString, new object[] { value }, (IType[]) null); + } + + /// + /// Execute a query for persistent instances, binding one value + /// to a "?" parameter of the given type in the query string. + /// + /// The object type to find. + /// a query expressed in Hibernate's query language + /// The value of the parameter. + /// Hibernate type of the parameter (or null) + /// + /// a generic List containing 0 or more persistent instances + /// + /// In case of Hibernate errors + public IList Find(string queryString, object value, IType type) + { + return Find(queryString, new object[] { value }, new IType[] { type }); + } + + /// + /// Execute a query for persistent instances, binding a + /// number of values to "?" parameters in the query string. + /// + /// The object type to find. + /// a query expressed in Hibernate's query language + /// the values of the parameters + /// a generic List containing 0 or more persistent instances + /// In case of Hibernate errors + public IList Find(string queryString, object[] values) + { + return Find(queryString, values, (IType[]) null); + } + + /// + /// Execute a query for persistent instances, binding a number of + /// values to "?" parameters of the given types in the query string. + /// + /// The object type to find. + /// A query expressed in Hibernate's query language + /// The values of the parameters + /// Hibernate types of the parameters (or null) + /// + /// a generic List containing 0 or more persistent instances + /// + /// In case of Hibernate errors + /// If values and types are not null and their lengths are not equal + public IList Find(string queryString, object[] values, IType[] types) + { + if (values != null && types != null && values.Length != types.Length) { - classicHibernateTemplate = new NHibernate.HibernateTemplate(); + throw new ArgumentException("Length of values array must match length of types array"); } - /// - /// Initializes a new instance of the class. - /// - /// Allows creation of a new non-transactional session when no - /// transactional Session can be found for the current thread - /// The session factory to create sessions. - public HibernateTemplate(ISessionFactory sessionFactory) + return ExecuteFind(new FindHibernateCallback(this, queryString, values, types), true); + } + + /// + /// Execute a query for persistent instances, binding + /// one value to a named parameter in the query string. + /// + /// The object type to find. + /// The name of a Hibernate query in a mapping file + /// The name of the parameter + /// The value of the parameter + /// a generic List containing 0 or more persistent instances + /// In case of Hibernate errors + public IList FindByNamedParam(string queryName, string paramName, object value) + { + return FindByNamedParam(queryName, paramName, value, null); + } + + /// + /// Execute a query for persistent instances, binding + /// one value to a named parameter in the query string. + /// + /// The object type to find. + /// The name of a Hibernate query in a mapping file + /// The name of the parameter + /// The value of the parameter + /// Hibernate type of the parameter (or null) + /// A generic List containing 0 or more persistent instances + /// In case of Hibernate errors + public IList FindByNamedParam(string queryName, string paramName, object value, IType type) + { + return FindByNamedParam(queryName, new string[] { paramName }, new object[] { value }, new IType[] { type }); + } + + /// + /// Execute a query for persistent instances, binding a + /// number of values to named parameters in the query string. + /// + /// The object type to find. + /// A query expressed in Hibernate's query language + /// The names of the parameters + /// The values of the parameters + /// A generic List containing 0 or more persistent instances + /// In case of Hibernate errors + public IList FindByNamedParam(string queryString, string[] paramNames, object[] values) + { + return FindByNamedParam(queryString, paramNames, values, null); + } + + /// + /// Execute a query for persistent instances, binding a + /// number of values to named parameters in the query string. + /// + /// The object type to find. + /// A query expressed in Hibernate's query language + /// The names of the parameters + /// The values of the parameters + /// Hibernate types of the parameters (or null) + /// A generic List containing 0 or more persistent instances + /// In case of Hibernate errors + /// If paramNames length is not equal to values length or + /// if paramNames length is not equal to types length (when types is not null) + public IList FindByNamedParam(string queryString, string[] paramNames, object[] values, IType[] types) + { + if (paramNames.Length != values.Length) { - classicHibernateTemplate = new Spring.Data.NHibernate.HibernateTemplate(sessionFactory); - AfterPropertiesSet(); + throw new ArgumentOutOfRangeException("paramNames", + "Length of paramNames array must match length of values array"); } - /// - /// Initializes a new instance of the class. - /// - /// The session factory to create sessions. - /// if set to true allow creation - /// of a new non-transactional session when no transactional Session can be found - /// for the current thread. - public HibernateTemplate(ISessionFactory sessionFactory, bool allowCreate) + if (types != null && paramNames.Length != types.Length) { - classicHibernateTemplate = new Spring.Data.NHibernate.HibernateTemplate(sessionFactory, allowCreate); - AfterPropertiesSet(); + throw new ArgumentOutOfRangeException("paramNames", + "Length of paramNames array must match length of types array"); } - /// - /// Gets or sets if a new Session should be created when no transactional Session - /// can be found for the current thread. - /// - /// - /// true if allowed to create non-transaction session; - /// otherwise, false. - /// - /// - ///

HibernateTemplate is aware of a corresponding Session bound to the - /// current thread, for example when using HibernateTransactionManager. - /// If allowCreate is true, a new non-transactional Session will be created - /// if none found, which needs to be closed at the end of the operation. - /// If false, an InvalidOperationException will get thrown in this case. - ///

- ///
- public override bool AllowCreate + return + ExecuteFind(new FindByNamedParamHibernateCallback(this, queryString, paramNames, values, types), true); + } + + /// + /// Execute a named query for persistent instances. + /// A named query is defined in a Hibernate mapping file. + /// + /// The object type to find. + /// The name of a Hibernate query in a mapping file + /// A generic List containing 0 or more persistent instances + /// In case of Hibernate errors + public IList FindByNamedQuery(string queryName) + { + return FindByNamedQuery(queryName, (object[]) null, (IType[]) null); + } + + /// + /// Execute a named query for persistent instances, binding + /// one value to a "?" parameter in the query string. + /// A named query is defined in a Hibernate mapping file. + /// + /// The object type to find. + /// The name of a Hibernate query in a mapping file + /// The value of the parameter + /// A generic List containing 0 or more persistent instances + /// In case of Hibernate errors + public IList FindByNamedQuery(string queryName, object value) + { + return FindByNamedQuery(queryName, new object[] { value }, (IType[]) null); + } + + /// + /// Execute a named query for persistent instances, binding + /// one value to a "?" parameter in the query string. + /// A named query is defined in a Hibernate mapping file. + /// + /// The object type to find. + /// The name of a Hibernate query in a mapping file + /// The value of the parameter + /// Hibernate type of the parameter (or null) + /// A generic List containing 0 or more persistent instances + /// In case of Hibernate errors + public IList FindByNamedQuery(string queryName, object value, IType type) + { + return FindByNamedQuery(queryName, new object[] { value }, new IType[] { type }); + } + + /// + /// Execute a named query for persistent instances, binding a + /// number of values to "?" parameters in the query string. + /// A named query is defined in a Hibernate mapping file. + /// + /// The object type to find. + /// The name of a Hibernate query in a mapping file + /// The values of the parameters + /// A generic List containing 0 or more persistent instances + /// In case of Hibernate errors + public IList FindByNamedQuery(string queryName, object[] values) + { + return FindByNamedQuery(queryName, values, (IType[]) null); + } + + /// + /// Execute a named query for persistent instances, binding a + /// number of values to "?" parameters in the query string. + /// A named query is defined in a Hibernate mapping file. + /// + /// The object type to find. + /// The name of a Hibernate query in a mapping file + /// The values of the parameters + /// Hibernate types of the parameters (or null) + /// A generic List containing 0 or more persistent instances + /// In case of Hibernate errors + /// If values and types are not null and their lengths differ. + public IList FindByNamedQuery(string queryName, object[] values, IType[] types) + { + if (values != null && types != null && values.Length != types.Length) { - get { return classicHibernateTemplate.AllowCreate; } - set { classicHibernateTemplate.AllowCreate = value; } - } - /// - /// Gets or sets a value indicating whether to always - /// use a new Hibernate Session for this template. - /// - /// true if always use new session; otherwise, false. - /// - ///

- /// Default is "false"; if activated, all operations on this template will - /// work on a new NHibernate ISession even in case of a pre-bound ISession - /// (for example, within a transaction). - ///

- ///

Within a transaction, a new NHibernate ISession used by this template - /// will participate in the transaction through using the same ADO.NET - /// Connection. In such a scenario, multiple Sessions will participate - /// in the same database transaction. - ///

- ///

Turn this on for operations that are supposed to always execute - /// independently, without side effects caused by a shared NHibernate ISession. - ///

- ///
- public override bool AlwaysUseNewSession - { - get { return classicHibernateTemplate.AlwaysUseNewSession; } - set { classicHibernateTemplate.AlwaysUseNewSession = value; } + throw new ArgumentOutOfRangeException("Length of values array must match length of types array"); } + return ExecuteFind(new FindByNamedQueryHibernateCallback(this, queryName, values, types), true); + } - /// - /// Set whether to expose the native Hibernate Session to IHibernateCallback - /// code. Default is "false": a Session proxy will be returned, - /// suppressing close calls and automatically applying - /// query cache settings and transaction timeouts. - /// - /// true if expose native session; otherwise, false. - public override bool ExposeNativeSession + /// + /// Execute a named query for persistent instances, binding + /// one value to a named parameter in the query string. + /// A named query is defined in a Hibernate mapping file. + /// + /// The object type to find. + /// The name of a Hibernate query in a mapping file + /// Name of the parameter + /// The value of the parameter + /// A generic List containing 0 or more persistent instances + /// In case of Hibernate errors + public IList FindByNamedQueryAndNamedParam(string queryName, string paramName, object value) + { + return FindByNamedQueryAndNamedParam(queryName, paramName, value, null); + } + + /// + /// Execute a named query for persistent instances, binding + /// one value to a named parameter in the query string. + /// A named query is defined in a Hibernate mapping file. + /// + /// The object type to find. + /// The name of a Hibernate query in a mapping file + /// Name of the parameter + /// The value of the parameter + /// The Hibernate type of the parameter (or null) + /// A generic List containing 0 or more persistent instances + /// In case of Hibernate errors + public IList FindByNamedQueryAndNamedParam(string queryName, string paramName, object value, IType type) + { + return FindByNamedQueryAndNamedParam( + queryName, new string[] { paramName }, new object[] { value }, new IType[] { type }); + } + + /// + /// Execute a named query for persistent instances, binding + /// number of values to named parameters in the query string. + /// A named query is defined in a Hibernate mapping file. + /// + /// The object type to find. + /// The name of a Hibernate query in a mapping file + /// The names of the parameters + /// The values of the parameters. + /// A generic List containing 0 or more persistent instances + /// In case of Hibernate errors + public IList FindByNamedQueryAndNamedParam(string queryName, string[] paramNames, object[] values) + { + return FindByNamedQueryAndNamedParam(queryName, paramNames, values, null); + } + + /// + /// Execute a named query for persistent instances, binding + /// number of values to named parameters in the query string. + /// A named query is defined in a Hibernate mapping file. + /// + /// The object type to find. + /// The name of a Hibernate query in a mapping file + /// The names of the parameters + /// The values of the parameters. + /// Hibernate types of the parameters (or null) + /// A generic List containing 0 or more persistent instances + /// In case of Hibernate errors + /// If paramNames length is not equal to values length or + /// if paramNames length is not equal to types length (when types is not null) + public IList FindByNamedQueryAndNamedParam(string queryName, string[] paramNames, object[] values, + IType[] types) + { + if (paramNames != null && values != null && paramNames.Length != values.Length) { - get { return classicHibernateTemplate.ExposeNativeSession; } - set { classicHibernateTemplate.ExposeNativeSession = value; } + throw new ArgumentOutOfRangeException("paramNames", + "Length of paramNames array must match length of values array"); } - /// - /// Gets or sets the template flush mode. - /// - /// - /// Default is Auto. Will get applied to any new ISession - /// created by the template. - /// - /// The template flush mode. - public override TemplateFlushMode TemplateFlushMode + if (paramNames != null && types != null && paramNames.Length != types.Length) { - get { return classicHibernateTemplate.TemplateFlushMode; } - set { classicHibernateTemplate.TemplateFlushMode = value; } + throw new ArgumentOutOfRangeException("paramNams", + "Length of paramNames array must match length of types array"); } - /// - /// Gets or sets the entity interceptor that allows to inspect and change - /// property values before writing to and reading from the database. - /// - /// - /// Will get applied to any new ISession created by this object. - ///

Such an interceptor can either be set at the ISessionFactory level, - /// i.e. on LocalSessionFactoryObject, or at the ISession level, i.e. on - /// HibernateTemplate, HibernateInterceptor, and HibernateTransactionManager. - /// It's preferable to set it on LocalSessionFactoryObject or HibernateTransactionManager - /// to avoid repeated configuration and guarantee consistent behavior in transactions. - ///

- ///
- /// The interceptor. - public override IInterceptor EntityInterceptor + return + ExecuteFind( + new FindByNamedQueryAndNamedParamHibernateCallback(this, queryName, paramNames, values, types), + true); + } + + /// + /// Execute a named query for persistent instances, binding the properties + /// of the given object to named parameters in the query string. + /// A named query is defined in a Hibernate mapping file. + /// + /// The object type to find. + /// The name of a Hibernate query in a mapping file + /// The values of the parameters + /// A generic List containing 0 or more persistent instances + /// In case of Hibernate errors + public IList FindByNamedQueryAndValueObject(string queryName, object valueObject) + { + return + ExecuteFind(new FindByNamedQueryAndValueObjectHibernateCallback(this, queryName, valueObject), true); + } + + /// + /// Execute a query for persistent instances, binding the properties + /// of the given object to named parameters in the query string. + /// + /// The object type to find. + /// A query expressed in Hibernate's query language + /// The values of the parameters + /// A generic List containing 0 or more persistent instances + /// In case of Hibernate errors + public IList FindByValueObject(string queryString, object valueObject) + { + return ExecuteFind(new FindByValueObjectHibernateCallback(this, queryString, valueObject), true); + } + + /// + /// Execute the action specified by the given action object within a Session. + /// + /// + /// Application exceptions thrown by the action object get propagated to the + /// caller (can only be unchecked). Hibernate exceptions are transformed into + /// appropriate DAO ones. Allows for returning the result object. + ///

Note: Callback code is not supposed to handle transactions itself! + /// Use an appropriate transaction manager like HibernateTransactionManager. + /// Generally, callback code must not touch any Session lifecycle methods, + /// like close, disconnect, or reconnect, to let the template do its work. + ///

+ ///
+ /// The object type retrieved. + /// The delegate callback object that specifies the Hibernate action. + /// a result object returned by the action, or null + /// + /// In case of Hibernate errors + public T Execute(HibernateDelegate del) + { + return Execute(new ExecuteHibernateCallbackUsingDelegate(del)); + } + + /// + /// Execute the action specified by the delegate within a Session. + /// + /// The object type retrieved. + /// The HibernateDelegate that specifies the action + /// to perform. + /// if set to true expose the native hibernate session to + /// callback code. + /// a result object returned by the action, or null + /// + /// In case of Hibernate errors + public T Execute(HibernateDelegate del, bool exposeNativeSession) + { + return Execute(new ExecuteHibernateCallbackUsingDelegate(del), true); + } + + /// + /// Execute the action specified by the given action object within a Session. + /// + /// The object type retrieved. + /// The callback object that specifies the Hibernate action. + /// + /// a result object returned by the action, or null + /// + /// + /// Application exceptions thrown by the action object get propagated to the + /// caller (can only be unchecked). Hibernate exceptions are transformed into + /// appropriate DAO ones. Allows for returning the result object. + ///

Note: Callback code is not supposed to handle transactions itself! + /// Use an appropriate transaction manager like HibernateTransactionManager. + /// Generally, callback code must not touch any Session lifecycle methods, + /// like close, disconnect, or reconnect, to let the template do its work. + ///

+ ///
+ /// In case of Hibernate errors + public T Execute(IHibernateCallback action) + { + return Execute(action, ExposeNativeSession); + } + + /// + /// Execute the action specified by the given action object within a Session. + /// + /// The object type retrieved. + /// callback object that specifies the Hibernate action. + /// if set to true expose the native hibernate session to + /// callback code. + /// + /// a result object returned by the action, or null + /// + /// In case of Hibernate errors + public T Execute(IHibernateCallback action, bool exposeNativeSession) + { + ISession session = Session; + + bool existingTransaction = SessionFactoryUtils.IsSessionTransactional(session, SessionFactory); + if (existingTransaction) { - get { return classicHibernateTemplate.EntityInterceptor; } - set { classicHibernateTemplate.EntityInterceptor = value; } + //log.Debug("Found thread-bound Session for HibernateTemplate"); } - /// - /// Set the object name of a Hibernate entity interceptor that allows to inspect - /// and change property values before writing to and reading from the database. - /// - /// - /// Will get applied to any new Session created by this transaction manager. - ///

Requires the object factory to be known, to be able to resolve the object - /// name to an interceptor instance on session creation. Typically used for - /// prototype interceptors, i.e. a new interceptor instance per session. - ///

- ///

Can also be used for shared interceptor instances, but it is recommended - /// to set the interceptor reference directly in such a scenario. - ///

- ///
- /// The name of the entity interceptor in the object factory/application context. - public override string EntityInterceptorObjectName + FlushModeHolder previousFlushModeHolder = new FlushModeHolder(); + try { - set { classicHibernateTemplate.EntityInterceptorObjectName = value;} + previousFlushModeHolder = ApplyFlushMode(session, existingTransaction); + ISession sessionToExpose = (exposeNativeSession ? session : classicHibernateTemplate.CreateSessionProxy(session)); + T result = action.DoInHibernate(sessionToExpose); + FlushIfNecessary(session, existingTransaction); + return result; } - - /// - /// Gets or sets the session factory that should be used to create - /// NHibernate ISessions. - /// - /// The session factory. - public override ISessionFactory SessionFactory + catch (ADOException ex) { - get { return classicHibernateTemplate.SessionFactory; } - set { classicHibernateTemplate.SessionFactory = value; } - } - - /// - /// Set the object factory instance. - /// - /// The object factory instance - public override IObjectFactory ObjectFactory - { - set { classicHibernateTemplate.ObjectFactory = value; } - } - - /// - /// Gets or sets a value indicating whether to - /// cache all queries executed by this template. - /// - /// - /// If this is true, all IQuery and ICriteria objects created by - /// this template will be marked as cacheable (including all - /// queries through find methods). - ///

To specify the query region to be used for queries cached - /// by this template, set the QueryCacheRegion property. - ///

- ///
- /// true if cache queries; otherwise, false. - public override bool CacheQueries - { - get { return classicHibernateTemplate.CacheQueries; } - set { classicHibernateTemplate.CacheQueries = value; } - } - - /// - /// Gets or sets the name of the cache region for queries executed by this template. - /// - /// - /// If this is specified, it will be applied to all IQuery and ICriteria objects - /// created by this template (including all queries through find methods). - ///

The cache region will not take effect unless queries created by this - /// template are configured to be cached via the CacheQueries property. - ///

- ///
- /// The query cache region. - public override string QueryCacheRegion - { - get { return classicHibernateTemplate.QueryCacheRegion; } - set { classicHibernateTemplate.QueryCacheRegion = value; } - } - - /// - /// Gets or sets the fetch size for this HibernateTemplate. - /// - /// The size of the fetch. - /// This is important for processing - /// large result sets: Setting this higher than the default value will increase - /// processing speed at the cost of memory consumption; setting this lower can - /// avoid transferring row data that will never be read by the application. - ///

Default is 0, indicating to use the driver's default.

- ///
- public override int FetchSize - { - get { return classicHibernateTemplate.FetchSize; } - set { classicHibernateTemplate.FetchSize = value; } - } - - /// - /// Gets or sets the maximum number of rows for this HibernateTemplate. - /// - /// The max results. - /// - /// This is important - /// for processing subsets of large result sets, avoiding to read and hold - /// the entire result set in the database or in the ADO.NET driver if we're - /// never interested in the entire result in the first place (for example, - /// when performing searches that might return a large number of matches). - ///

Default is 0, indicating to use the driver's default.

- ///
- public override int MaxResults - { - get { return classicHibernateTemplate.MaxResults; } - set { classicHibernateTemplate.MaxResults = value; } - } - - /// - /// Set the ADO.NET exception translator for this instance. - /// Applied to System.Data.Common.DbException (or provider specific exception type - /// in .NET 1.1) thrown by callback code, be it direct - /// DbException or wrapped Hibernate ADOExceptions. - ///

The default exception translator is either a ErrorCodeExceptionTranslator - /// if a DbProvider is available, or a FalbackExceptionTranslator otherwise - ///

- ///
- /// The ADO exception translator. - public override IAdoExceptionTranslator AdoExceptionTranslator - { - get { return classicHibernateTemplate.AdoExceptionTranslator; } - set { classicHibernateTemplate.AdoExceptionTranslator = value; } - } - - /// - /// Gets the classic hibernate template for access to non-generic methods. - /// - /// The classic hibernate template. - public NHibernate.HibernateTemplate ClassicHibernateTemplate - { - get { return classicHibernateTemplate; } - } - - /// - /// Gets or sets the proxy factory. - /// - /// This may be useful to set if you create many instances of - /// HibernateTemplate and/or HibernateDaoSupport. This allows the same - /// ProxyFactory implementation to be used thereby limiting the - /// number of dynamic proxy types created in the temporary assembly, which - /// are never garbage collected due to .NET runtime semantics. - /// - /// The proxy factory. - public virtual ProxyFactory ProxyFactory - { - get { return classicHibernateTemplate.ProxyFactory; } - set { classicHibernateTemplate.ProxyFactory = value; } - } - - /// - /// Remove all objects from the Session cache, and cancel all pending saves, - /// updates and deletes. - /// - public void Clear() - { - classicHibernateTemplate.Clear(); - } - - - /// - /// Delete the given persistent instance. - /// - /// The persistent instance to delete. - /// In case of Hibernate errors - public void Delete(object entity) - { - classicHibernateTemplate.Delete(entity); - } - - - /// - /// Delete the given persistent instance. - /// - /// The persistent instance to delete. - /// The lock mode to obtain. - /// - /// Obtains the specified lock mode if the instance exists, implicitly - /// checking whether the corresponding database entry still exists - /// (throwing an OptimisticLockingFailureException if not found). - /// - /// In case of Hibernate errors - public void Delete(object entity, LockMode lockMode) - { - classicHibernateTemplate.Delete(entity, lockMode); - } - - /// - /// Delete all objects returned by the query. - /// - /// a query expressed in Hibernate's query language. - /// The number of entity instances deleted. - /// In case of Hibernate errors - public int Delete(string queryString) - { - return classicHibernateTemplate.Delete(queryString); - } - - /// - /// Delete all objects returned by the query. - /// - /// a query expressed in Hibernate's query language. - /// The value of the parameter. - /// The Hibernate type of the parameter (or null). - /// The number of entity instances deleted. - /// In case of Hibernate errors - public int Delete(string queryString, object value, IType type) - { - return classicHibernateTemplate.Delete(queryString, value, type); - } - - /// - /// Delete all objects returned by the query. - /// - /// a query expressed in Hibernate's query language. - /// The values of the parameters. - /// Hibernate types of the parameters (or null) - /// The number of entity instances deleted. - /// In case of Hibernate errors - public int Delete(string queryString, object[] values, IType[] types) - { - return classicHibernateTemplate.Delete(queryString, values, types); - } - - /// - /// Flush all pending saves, updates and deletes to the database. - /// - /// - /// Only invoke this for selective eager flushing, for example when ADO.NET code - /// needs to see certain changes within the same transaction. Else, it's preferable - /// to rely on auto-flushing at transaction completion. - /// - /// In case of Hibernate errors - public void Flush() - { - classicHibernateTemplate.Flush(); - } - - /// - /// Load the persistent instance with the given identifier - /// into the given object, throwing an exception if not found. - /// - /// Entity the object (of the target class) to load into. - /// An identifier of the persistent instance. - /// If object not found. - /// In case of Hibernate errors - public void Load(object entity, object id) - { - classicHibernateTemplate.Load(entity, id); - } - - /// - /// Re-read the state of the given persistent instance. - /// - /// The persistent instance to re-read. - /// In case of Hibernate errors - public void Refresh(object entity) - { - classicHibernateTemplate.Refresh(entity); - } - - /// - /// Re-read the state of the given persistent instance. - /// Obtains the specified lock mode for the instance. - /// - /// The persistent instance to re-read. - /// The lock mode to obtain. - /// In case of Hibernate errors - public void Refresh(object entity, LockMode lockMode) - { - classicHibernateTemplate.Refresh(entity, lockMode); - } - - /// - /// Determines whether the given object is in the Session cache. - /// - /// the persistence instance to check. - /// - /// true if session cache contains the specified entity; otherwise, false. - /// - /// In case of Hibernate errors - public bool Contains(object entity) - { - return classicHibernateTemplate.Contains(entity); - } - - /// - /// Remove the given object from the Session cache. - /// - /// The persistent instance to evict. - /// In case of Hibernate errors - public void Evict(object entity) - { - classicHibernateTemplate.Evict(entity); - } - - /// - /// Obtain the specified lock level upon the given object, implicitly - /// checking whether the corresponding database entry still exists - /// (throwing an OptimisticLockingFailureException if not found). - /// - /// The he persistent instance to lock. - /// The lock mode to obtain. - /// If not found - /// In case of Hibernate errors - public void Lock(object entity, LockMode lockMode) - { - classicHibernateTemplate.Lock(entity, lockMode); - } - - /// - /// Persist the given transient instance. - /// - /// The transient instance to persist. - /// The generated identifier. - /// In case of Hibernate errors - public object Save(object entity) - { - return classicHibernateTemplate.Save(entity); - } - - /// - /// Persist the given transient instance with the given identifier. - /// - /// The transient instance to persist. - /// The identifier to assign. - /// In case of Hibernate errors - public void Save(object entity, object id) - { - classicHibernateTemplate.Save(entity, id); - } - - /// - /// Update the given persistent instance. - /// - /// The persistent instance to update. - /// In case of Hibernate errors - public void Update(object entity) - { - classicHibernateTemplate.Update(entity); - } - - /// - /// Update the given persistent instance. - /// Obtains the specified lock mode if the instance exists, implicitly - /// checking whether the corresponding database entry still exists - /// (throwing an OptimisticLockingFailureException if not found). - /// - /// The persistent instance to update. - /// The lock mode to obtain. - /// In case of Hibernate errors - public void Update(object entity, LockMode lockMode) - { - classicHibernateTemplate.Update(entity, lockMode); - } - - /// - /// Save or update the given persistent instance, - /// according to its id (matching the configured "unsaved-value"?). - /// - /// The persistent instance to save or update - /// (to be associated with the Hibernate Session). - /// In case of Hibernate errors - public void SaveOrUpdate(object entity) - { - classicHibernateTemplate.SaveOrUpdate(entity); - } - - /// - /// Copy the state of the given object onto the persistent object with the same identifier. - /// If there is no persistent instance currently associated with the session, it will be loaded. - /// Return the persistent instance. If the given instance is unsaved, - /// save a copy of and return it as a newly persistent instance. - /// The given instance does not become associated with the session. - /// This operation cascades to associated instances if the association is mapped with cascade="merge". - /// The semantics of this method are defined by JSR-220. - /// - /// The persistent object to merge. - /// (not necessarily to be associated with the Hibernate Session) - /// - /// An updated persistent instance - /// In case of Hibernate errors - public object Merge(object entity) - { - return classicHibernateTemplate.Merge(entity); - } - - /// - /// Return the persistent instance of the given entity type - /// with the given identifier, or null if not found. - /// Obtains the specified lock mode if the instance exists. - /// - /// The object type to get. - /// The id of the object to get. - /// the persistent instance, or null if not found - /// In case of Hibernate errors - public T Get(object id) - { - return Get(id, null); - } - - /// - /// Return the persistent instance of the given entity type - /// with the given identifier, or null if not found. - /// Obtains the specified lock mode if the instance exists. - /// - /// The object type to get. - /// The lock mode to obtain. - /// The lock mode. - /// the persistent instance, or null if not found - /// In case of Hibernate errors - public T Get(object id, LockMode lockMode) - { - return Execute(new GetByTypeHibernateCallback(id, lockMode), true); - } - - /// - /// Return the persistent instance of the given entity class - /// with the given identifier, throwing an exception if not found. - /// - /// The object type to load. - /// An identifier of the persistent instance. - /// The persistent instance - /// If not found - /// In case of Hibernate errors - public T Load(object id) - { - return Load(id, null); - } - - /// - /// Return the persistent instance of the given entity class - /// with the given identifier, throwing an exception if not found. - /// Obtains the specified lock mode if the instance exists. - /// - /// The object type to load. - /// An identifier of the persistent instance. - /// The lock mode. - /// The persistent instance - /// If not found - /// In case of Hibernate errors - public T Load(object id, LockMode lockMode) - { - return Execute(new LoadByTypeHibernateCallback(id, lockMode), true); - } - - /// - /// Return all persistent instances of the given entity class. - /// Note: Use queries or criteria for retrieving a specific subset. - /// - /// The object type to load. - /// A generic List containing 0 or more persistent instances - /// In case of Hibernate errors - public IList LoadAll() - { - return ExecuteFind(new LoadAllByTypeHibernateCallback(this), true); - } - - /// - /// Execute a query for persistent instances. - /// - /// The object type to find. - /// a query expressed in Hibernate's query language - /// - /// a generic List containing 0 or more persistent instances - /// - /// In case of Hibernate errors - public IList Find(string queryString) - { - return Find(queryString, (object[]) null, (IType[]) null); - } - - /// - /// Execute a query for persistent instances, binding - /// one value to a "?" parameter in the query string. - /// - /// The object type to find. - /// a query expressed in Hibernate's query language - /// the value of the parameter - /// - /// a generic List containing 0 or more persistent instances - /// - /// In case of Hibernate errors - public IList Find(string queryString, object value) - { - return Find(queryString, new object[] {value}, (IType[]) null); - } - - /// - /// Execute a query for persistent instances, binding one value - /// to a "?" parameter of the given type in the query string. - /// - /// The object type to find. - /// a query expressed in Hibernate's query language - /// The value of the parameter. - /// Hibernate type of the parameter (or null) - /// - /// a generic List containing 0 or more persistent instances - /// - /// In case of Hibernate errors - public IList Find(string queryString, object value, IType type) - { - return Find(queryString, new object[] {value}, new IType[] {type}); - } - - /// - /// Execute a query for persistent instances, binding a - /// number of values to "?" parameters in the query string. - /// - /// The object type to find. - /// a query expressed in Hibernate's query language - /// the values of the parameters - /// a generic List containing 0 or more persistent instances - /// In case of Hibernate errors - public IList Find(string queryString, object[] values) - { - return Find(queryString, values, (IType[]) null); - } - - /// - /// Execute a query for persistent instances, binding a number of - /// values to "?" parameters of the given types in the query string. - /// - /// The object type to find. - /// A query expressed in Hibernate's query language - /// The values of the parameters - /// Hibernate types of the parameters (or null) - /// - /// a generic List containing 0 or more persistent instances - /// - /// In case of Hibernate errors - /// If values and types are not null and their lengths are not equal - public IList Find(string queryString, object[] values, IType[] types) - { - if (values != null && types != null && values.Length != types.Length) + IDbProvider dbProvider = SessionFactoryUtils.GetDbProvider(SessionFactory); + if (dbProvider != null && dbProvider.IsDataAccessException(ex.InnerException)) { - throw new ArgumentException("Length of values array must match length of types array"); + throw ConvertAdoAccessException(ex); } - return ExecuteFind(new FindHibernateCallback(this, queryString, values, types), true); - } - - /// - /// Execute a query for persistent instances, binding - /// one value to a named parameter in the query string. - /// - /// The object type to find. - /// The name of a Hibernate query in a mapping file - /// The name of the parameter - /// The value of the parameter - /// a generic List containing 0 or more persistent instances - /// In case of Hibernate errors - public IList FindByNamedParam(string queryName, string paramName, object value) - { - return FindByNamedParam(queryName, paramName, value, null); - } - - /// - /// Execute a query for persistent instances, binding - /// one value to a named parameter in the query string. - /// - /// The object type to find. - /// The name of a Hibernate query in a mapping file - /// The name of the parameter - /// The value of the parameter - /// Hibernate type of the parameter (or null) - /// A generic List containing 0 or more persistent instances - /// In case of Hibernate errors - public IList FindByNamedParam(string queryName, string paramName, object value, IType type) - { - return FindByNamedParam(queryName, new string[] {paramName}, new object[] {value}, new IType[] {type}); - } - - /// - /// Execute a query for persistent instances, binding a - /// number of values to named parameters in the query string. - /// - /// The object type to find. - /// A query expressed in Hibernate's query language - /// The names of the parameters - /// The values of the parameters - /// A generic List containing 0 or more persistent instances - /// In case of Hibernate errors - public IList FindByNamedParam(string queryString, string[] paramNames, object[] values) - { - return FindByNamedParam(queryString, paramNames, values, null); - } - - /// - /// Execute a query for persistent instances, binding a - /// number of values to named parameters in the query string. - /// - /// The object type to find. - /// A query expressed in Hibernate's query language - /// The names of the parameters - /// The values of the parameters - /// Hibernate types of the parameters (or null) - /// A generic List containing 0 or more persistent instances - /// In case of Hibernate errors - /// If paramNames length is not equal to values length or - /// if paramNames length is not equal to types length (when types is not null) - public IList FindByNamedParam(string queryString, string[] paramNames, object[] values, IType[] types) - { - if (paramNames.Length != values.Length) + else { - throw new ArgumentOutOfRangeException("paramNames", - "Length of paramNames array must match length of values array"); + throw new HibernateSystemException(ex); } - if (types != null && paramNames.Length != types.Length) + } + catch (HibernateException ex) + { + throw ConvertHibernateAccessException(ex); + } + catch (Exception ex) + { + IDbProvider dbProvider = SessionFactoryUtils.GetDbProvider(SessionFactory); + if (dbProvider != null && dbProvider.IsDataAccessException(ex)) { - throw new ArgumentOutOfRangeException("paramNames", - "Length of paramNames array must match length of types array"); + throw ConvertAdoAccessException(ex); } - - return - ExecuteFind(new FindByNamedParamHibernateCallback(this, queryString, paramNames, values, types), true); - } - - /// - /// Execute a named query for persistent instances. - /// A named query is defined in a Hibernate mapping file. - /// - /// The object type to find. - /// The name of a Hibernate query in a mapping file - /// A generic List containing 0 or more persistent instances - /// In case of Hibernate errors - public IList FindByNamedQuery(string queryName) - { - return FindByNamedQuery(queryName, (object[]) null, (IType[]) null); - } - - /// - /// Execute a named query for persistent instances, binding - /// one value to a "?" parameter in the query string. - /// A named query is defined in a Hibernate mapping file. - /// - /// The object type to find. - /// The name of a Hibernate query in a mapping file - /// The value of the parameter - /// A generic List containing 0 or more persistent instances - /// In case of Hibernate errors - public IList FindByNamedQuery(string queryName, object value) - { - return FindByNamedQuery(queryName, new object[] {value}, (IType[]) null); - } - - /// - /// Execute a named query for persistent instances, binding - /// one value to a "?" parameter in the query string. - /// A named query is defined in a Hibernate mapping file. - /// - /// The object type to find. - /// The name of a Hibernate query in a mapping file - /// The value of the parameter - /// Hibernate type of the parameter (or null) - /// A generic List containing 0 or more persistent instances - /// In case of Hibernate errors - public IList FindByNamedQuery(string queryName, object value, IType type) - { - return FindByNamedQuery(queryName, new object[] {value}, new IType[] {type}); - } - - /// - /// Execute a named query for persistent instances, binding a - /// number of values to "?" parameters in the query string. - /// A named query is defined in a Hibernate mapping file. - /// - /// The object type to find. - /// The name of a Hibernate query in a mapping file - /// The values of the parameters - /// A generic List containing 0 or more persistent instances - /// In case of Hibernate errors - public IList FindByNamedQuery(string queryName, object[] values) - { - return FindByNamedQuery(queryName, values, (IType[]) null); - } - - /// - /// Execute a named query for persistent instances, binding a - /// number of values to "?" parameters in the query string. - /// A named query is defined in a Hibernate mapping file. - /// - /// The object type to find. - /// The name of a Hibernate query in a mapping file - /// The values of the parameters - /// Hibernate types of the parameters (or null) - /// A generic List containing 0 or more persistent instances - /// In case of Hibernate errors - /// If values and types are not null and their lengths differ. - public IList FindByNamedQuery(string queryName, object[] values, IType[] types) - { - if (values != null && types != null && values.Length != types.Length) + else { - throw new ArgumentOutOfRangeException("Length of values array must match length of types array"); + // Callback code throw application exception or other non DB related exception. + throw; } - return ExecuteFind(new FindByNamedQueryHibernateCallback(this, queryName, values, types), true); } - - /// - /// Execute a named query for persistent instances, binding - /// one value to a named parameter in the query string. - /// A named query is defined in a Hibernate mapping file. - /// - /// The object type to find. - /// The name of a Hibernate query in a mapping file - /// Name of the parameter - /// The value of the parameter - /// A generic List containing 0 or more persistent instances - /// In case of Hibernate errors - public IList FindByNamedQueryAndNamedParam(string queryName, string paramName, object value) + finally { - return FindByNamedQueryAndNamedParam(queryName, paramName, value, null); - } - - /// - /// Execute a named query for persistent instances, binding - /// one value to a named parameter in the query string. - /// A named query is defined in a Hibernate mapping file. - /// - /// The object type to find. - /// The name of a Hibernate query in a mapping file - /// Name of the parameter - /// The value of the parameter - /// The Hibernate type of the parameter (or null) - /// A generic List containing 0 or more persistent instances - /// In case of Hibernate errors - public IList FindByNamedQueryAndNamedParam(string queryName, string paramName, object value, IType type) - { - return FindByNamedQueryAndNamedParam( - queryName, new string[] {paramName}, new object[] {value}, new IType[] {type}); - } - - /// - /// Execute a named query for persistent instances, binding - /// number of values to named parameters in the query string. - /// A named query is defined in a Hibernate mapping file. - /// - /// The object type to find. - /// The name of a Hibernate query in a mapping file - /// The names of the parameters - /// The values of the parameters. - /// A generic List containing 0 or more persistent instances - /// In case of Hibernate errors - public IList FindByNamedQueryAndNamedParam(string queryName, string[] paramNames, object[] values) - { - return FindByNamedQueryAndNamedParam(queryName, paramNames, values, null); - } - - /// - /// Execute a named query for persistent instances, binding - /// number of values to named parameters in the query string. - /// A named query is defined in a Hibernate mapping file. - /// - /// The object type to find. - /// The name of a Hibernate query in a mapping file - /// The names of the parameters - /// The values of the parameters. - /// Hibernate types of the parameters (or null) - /// A generic List containing 0 or more persistent instances - /// In case of Hibernate errors - /// If paramNames length is not equal to values length or - /// if paramNames length is not equal to types length (when types is not null) - public IList FindByNamedQueryAndNamedParam(string queryName, string[] paramNames, object[] values, - IType[] types) - { - if (paramNames != null && values != null && paramNames.Length != values.Length) - { - throw new ArgumentOutOfRangeException("paramNames", - "Length of paramNames array must match length of values array"); - } - if (paramNames != null && types != null && paramNames.Length != types.Length) - { - throw new ArgumentOutOfRangeException("paramNams", - "Length of paramNames array must match length of types array"); - } - return - ExecuteFind( - new FindByNamedQueryAndNamedParamHibernateCallback(this, queryName, paramNames, values, types), - true); - } - - /// - /// Execute a named query for persistent instances, binding the properties - /// of the given object to named parameters in the query string. - /// A named query is defined in a Hibernate mapping file. - /// - /// The object type to find. - /// The name of a Hibernate query in a mapping file - /// The values of the parameters - /// A generic List containing 0 or more persistent instances - /// In case of Hibernate errors - public IList FindByNamedQueryAndValueObject(string queryName, object valueObject) - { - return - ExecuteFind(new FindByNamedQueryAndValueObjectHibernateCallback(this, queryName, valueObject), true); - } - - /// - /// Execute a query for persistent instances, binding the properties - /// of the given object to named parameters in the query string. - /// - /// The object type to find. - /// A query expressed in Hibernate's query language - /// The values of the parameters - /// A generic List containing 0 or more persistent instances - /// In case of Hibernate errors - public IList FindByValueObject(string queryString, object valueObject) - { - return ExecuteFind(new FindByValueObjectHibernateCallback(this, queryString, valueObject), true); - } - - /// - /// Execute the action specified by the given action object within a Session. - /// - /// - /// Application exceptions thrown by the action object get propagated to the - /// caller (can only be unchecked). Hibernate exceptions are transformed into - /// appropriate DAO ones. Allows for returning the result object. - ///

Note: Callback code is not supposed to handle transactions itself! - /// Use an appropriate transaction manager like HibernateTransactionManager. - /// Generally, callback code must not touch any Session lifecycle methods, - /// like close, disconnect, or reconnect, to let the template do its work. - ///

- ///
- /// The object type retrieved. - /// The delegate callback object that specifies the Hibernate action. - /// a result object returned by the action, or null - /// - /// In case of Hibernate errors - public T Execute(HibernateDelegate del) - { - return Execute(new ExecuteHibernateCallbackUsingDelegate(del)); - } - - /// - /// Execute the action specified by the delegate within a Session. - /// - /// The object type retrieved. - /// The HibernateDelegate that specifies the action - /// to perform. - /// if set to true expose the native hibernate session to - /// callback code. - /// a result object returned by the action, or null - /// - /// In case of Hibernate errors - public T Execute(HibernateDelegate del, bool exposeNativeSession) - { - return Execute(new ExecuteHibernateCallbackUsingDelegate(del), true); - } - - /// - /// Execute the action specified by the given action object within a Session. - /// - /// The object type retrieved. - /// The callback object that specifies the Hibernate action. - /// - /// a result object returned by the action, or null - /// - /// - /// Application exceptions thrown by the action object get propagated to the - /// caller (can only be unchecked). Hibernate exceptions are transformed into - /// appropriate DAO ones. Allows for returning the result object. - ///

Note: Callback code is not supposed to handle transactions itself! - /// Use an appropriate transaction manager like HibernateTransactionManager. - /// Generally, callback code must not touch any Session lifecycle methods, - /// like close, disconnect, or reconnect, to let the template do its work. - ///

- ///
- /// In case of Hibernate errors - public T Execute(IHibernateCallback action) - { - return Execute(action, ExposeNativeSession); - } - - /// - /// Execute the action specified by the given action object within a Session. - /// - /// The object type retrieved. - /// callback object that specifies the Hibernate action. - /// if set to true expose the native hibernate session to - /// callback code. - /// - /// a result object returned by the action, or null - /// - /// In case of Hibernate errors - public T Execute(IHibernateCallback action, bool exposeNativeSession) - { - ISession session = Session; - - bool existingTransaction = SessionFactoryUtils.IsSessionTransactional(session, SessionFactory); if (existingTransaction) { - //log.Debug("Found thread-bound Session for HibernateTemplate"); - } - - FlushModeHolder previousFlushModeHolder = new FlushModeHolder(); - try - { - previousFlushModeHolder = ApplyFlushMode(session, existingTransaction); - ISession sessionToExpose = (exposeNativeSession ? session : classicHibernateTemplate.CreateSessionProxy(session)); - T result = action.DoInHibernate(sessionToExpose); - FlushIfNecessary(session, existingTransaction); - return result; - } - catch (ADOException ex) - { - IDbProvider dbProvider = SessionFactoryUtils.GetDbProvider(SessionFactory); - if (dbProvider != null && dbProvider.IsDataAccessException(ex.InnerException)) + //log.Debug("Not closing pre-bound Hibernate Session after HibernateTemplate"); + if (previousFlushModeHolder.ModeWasSet) { - throw ConvertAdoAccessException(ex); + session.FlushMode = previousFlushModeHolder.Mode; } - else - { - throw new HibernateSystemException(ex); - } - } - catch (HibernateException ex) - { - throw ConvertHibernateAccessException(ex); - } - catch (Exception ex) - { - IDbProvider dbProvider = SessionFactoryUtils.GetDbProvider(SessionFactory); - if (dbProvider != null && dbProvider.IsDataAccessException(ex)) - { - throw ConvertAdoAccessException(ex); - } - else - { - // Callback code throw application exception or other non DB related exception. - throw; - } - } - finally - { - if (existingTransaction) - { - //log.Debug("Not closing pre-bound Hibernate Session after HibernateTemplate"); - if (previousFlushModeHolder.ModeWasSet) - { - session.FlushMode = previousFlushModeHolder.Mode; - } - } - else - { - SessionFactoryUtils.ReleaseSession(session, SessionFactory); - } - } - } - - /// - /// Execute the action specified by the given action object within a Session assuming that an IList is returned. - /// - /// The object type to find. - /// callback object that specifies the Hibernate action. - /// if set to true expose the native hibernate session to - /// callback code. - /// - /// an IList returned by the action, or null - /// - /// In case of Hibernate errors - public IList ExecuteFind(IFindHibernateCallback action, bool exposeNativeSession) - { - ISession session = Session; - - bool existingTransaction = SessionFactoryUtils.IsSessionTransactional(session, SessionFactory); - - FlushModeHolder previousFlushModeHolder = new FlushModeHolder(); - try - { - previousFlushModeHolder = ApplyFlushMode(session, existingTransaction); - ISession sessionToExpose = (exposeNativeSession ? session : classicHibernateTemplate.CreateSessionProxy(session)); - IList result = action.DoInHibernate(sessionToExpose); - FlushIfNecessary(session, existingTransaction); - return result; - } - catch (ADOException ex) - { - IDbProvider dbProvider = SessionFactoryUtils.GetDbProvider(SessionFactory); - if (dbProvider != null && dbProvider.IsDataAccessException(ex.InnerException)) - { - throw ConvertAdoAccessException(ex); - } - else - { - // Callback code throw application exception or other non DB related exception. - throw; - } - } - catch (HibernateException ex) - { - throw ConvertHibernateAccessException(ex); - } - catch (Exception ex) - { - IDbProvider dbProvider = SessionFactoryUtils.GetDbProvider(SessionFactory); - if (dbProvider != null && dbProvider.IsDataAccessException(ex)) - { - throw ConvertAdoAccessException(ex); - } - else - { - // Callback code throw application exception or other non DB related exception. - throw; - } - } - finally - { - if (existingTransaction) - { - if (previousFlushModeHolder.ModeWasSet) - { - session.FlushMode = previousFlushModeHolder.Mode; - } - } - else - { - SessionFactoryUtils.ReleaseSession(session, SessionFactory); - } - } - } - - /// - /// Execute the action specified by the given action object within a Session. - /// - /// - /// Application exceptions thrown by the action object get propagated to the - /// caller (can only be unchecked). Hibernate exceptions are transformed into - /// appropriate DAO ones. Allows for returning the result object. - ///

Note: Callback code is not supposed to handle transactions itself! - /// Use an appropriate transaction manager like HibernateTransactionManager. - /// Generally, callback code must not touch any Session lifecycle methods, - /// like close, disconnect, or reconnect, to let the template do its work. - ///

- ///
- /// The object type to find. - /// The delegate callback object that specifies the Hibernate action. - /// A generic IList returned by the action, or null - /// - /// In case of Hibernate errors - public IList ExecuteFind(FindHibernateDelegate del) - { - return ExecuteFind(new ExecuteFindHibernateCallbackUsingDelegate(del)); - } - - /// - /// Execute the action specified by the delegate within a Session. - /// - /// The object type to find. - /// The FindHibernateDelegate that specifies the action - /// to perform. - /// if set to true expose the native hibernate session to - /// callback code. - /// A generic IList returned by the action, or null - /// - /// In case of Hibernate errors - public IList ExecuteFind(FindHibernateDelegate del, bool exposeNativeSession) - { - return ExecuteFind(new ExecuteFindHibernateCallbackUsingDelegate(del), true); - } - - /// - /// Execute the action specified by the given action object within a Session. - /// - /// The object type to find. - /// The callback object that specifies the Hibernate action. - /// - /// A generic IList returned by the action, or null - /// - /// - /// Application exceptions thrown by the action object get propagated to the - /// caller (can only be unchecked). Hibernate exceptions are transformed into - /// appropriate DAO ones. Allows for returning the result object. - ///

Note: Callback code is not supposed to handle transactions itself! - /// Use an appropriate transaction manager like HibernateTransactionManager. - /// Generally, callback code must not touch any Session lifecycle methods, - /// like close, disconnect, or reconnect, to let the template do its work. - ///

- ///
- public IList ExecuteFind(IFindHibernateCallback action) - { - return ExecuteFind(action, ExposeNativeSession); - } - } - - internal class ExecuteHibernateCallbackUsingDelegate : IHibernateCallback - { - private HibernateDelegate del; - - public ExecuteHibernateCallbackUsingDelegate(HibernateDelegate d) - { - del = d; - } - - public T DoInHibernate(ISession session) - { - return del(session); - } - } - - internal class GetByTypeHibernateCallback : IHibernateCallback - { - private object id; - private LockMode lockMode; - - public GetByTypeHibernateCallback(object id, LockMode lockMode) - { - this.id = id; - this.lockMode = lockMode; - } - - /// - /// Gets called by HibernateTemplate with an active - /// Hibernate Session. Does not need to care about activating or closing - /// the Session, or handling transactions. - /// - /// - ///

- /// Allows for returning a result object created within the callback, i.e. - /// a domain object or a collection of domain objects. Note that there's - /// special support for single step actions: see HibernateTemplate.find etc. - ///

- ///
- public T DoInHibernate(ISession session) - { - if (lockMode != null) - { - return session.Get(id, lockMode); } else { - return session.Get(id); + SessionFactoryUtils.ReleaseSession(session, SessionFactory); } } } - internal class LoadByTypeHibernateCallback : IHibernateCallback + /// + /// Execute the action specified by the given action object within a Session assuming that an IList is returned. + /// + /// The object type to find. + /// callback object that specifies the Hibernate action. + /// if set to true expose the native hibernate session to + /// callback code. + /// + /// an IList returned by the action, or null + /// + /// In case of Hibernate errors + public IList ExecuteFind(IFindHibernateCallback action, bool exposeNativeSession) { - private object id; - private LockMode lockMode; + ISession session = Session; - public LoadByTypeHibernateCallback(object id, LockMode lockMode) + bool existingTransaction = SessionFactoryUtils.IsSessionTransactional(session, SessionFactory); + + FlushModeHolder previousFlushModeHolder = new FlushModeHolder(); + try { - this.id = id; - this.lockMode = lockMode; + previousFlushModeHolder = ApplyFlushMode(session, existingTransaction); + ISession sessionToExpose = (exposeNativeSession ? session : classicHibernateTemplate.CreateSessionProxy(session)); + IList result = action.DoInHibernate(sessionToExpose); + FlushIfNecessary(session, existingTransaction); + return result; } - - /// - /// Gets called by HibernateTemplate with an active - /// Hibernate Session. Does not need to care about activating or closing - /// the Session, or handling transactions. - /// - /// - ///

- /// Allows for returning a result object created within the callback, i.e. - /// a domain object or a collection of domain objects. Note that there's - /// special support for single step actions: see HibernateTemplate.find etc. - ///

- ///
- public T DoInHibernate(ISession session) + catch (ADOException ex) { - if (lockMode != null) + IDbProvider dbProvider = SessionFactoryUtils.GetDbProvider(SessionFactory); + if (dbProvider != null && dbProvider.IsDataAccessException(ex.InnerException)) { - return session.Load(id, lockMode); + throw ConvertAdoAccessException(ex); } else { - return session.Load(id); + // Callback code throw application exception or other non DB related exception. + throw; } } - } - - internal class LoadAllByTypeHibernateCallback : IFindHibernateCallback - { - private HibernateTemplate outer; - - public LoadAllByTypeHibernateCallback(HibernateTemplate template) + catch (HibernateException ex) { - outer = template; + throw ConvertHibernateAccessException(ex); } - - /// - /// Gets called by HibernateTemplate with an active - /// Hibernate Session. Does not need to care about activating or closing - /// the Session, or handling transactions. - /// - /// - ///

- /// Allows for returning a result object created within the callback, i.e. - /// a domain object or a collection of domain objects. Note that there's - /// special support for single step actions: see HibernateTemplate.find etc. - ///

- ///
- public IList DoInHibernate(ISession session) + catch (Exception ex) { - ICriteria criteria = session.CreateCriteria(typeof (T)); - outer.PrepareCriteria(criteria); - return criteria.List(); - } - } - - internal class FindHibernateCallback : IFindHibernateCallback - { - private HibernateTemplate outer; - private string queryString; - private object[] values; - private IType[] types; - - public FindHibernateCallback(HibernateTemplate template, string queryString, object[] values, IType[] types) - { - outer = template; - this.queryString = queryString; - this.values = values; - this.types = types; - } - - /// - /// Gets called by HibernateTemplate with an active - /// Hibernate Session. Does not need to care about activating or closing - /// the Session, or handling transactions. - /// - /// - ///

- /// Allows for returning a result object created within the callback, i.e. - /// a domain object or a collection of domain objects. Note that there's - /// special support for single step actions: see HibernateTemplate.find etc. - ///

- ///
- public IList DoInHibernate(ISession session) - { - IQuery queryObject = session.CreateQuery(queryString); - outer.PrepareQuery(queryObject); - - if (values != null) + IDbProvider dbProvider = SessionFactoryUtils.GetDbProvider(SessionFactory); + if (dbProvider != null && dbProvider.IsDataAccessException(ex)) { - for (int i = 0; i < values.Length; i++) + throw ConvertAdoAccessException(ex); + } + else + { + // Callback code throw application exception or other non DB related exception. + throw; + } + } + finally + { + if (existingTransaction) + { + if (previousFlushModeHolder.ModeWasSet) { - if (types != null && types[i] != null) - { - queryObject.SetParameter(i, values[i], types[i]); - } - else - { - queryObject.SetParameter(i, values[i]); - } + session.FlushMode = previousFlushModeHolder.Mode; } } - - return queryObject.List(); - } - } - - internal class FindByNamedParamHibernateCallback : IFindHibernateCallback - { - HibernateTemplate outer; - private string queryString; - private string[] paramNames; - private object[] values; - private IType[] types; - - public FindByNamedParamHibernateCallback(HibernateTemplate template, string queryString, string[] paramNames, - object[] values, IType[] types) - { - outer = template; - this.queryString = queryString; - this.paramNames = paramNames; - this.values = values; - this.types = types; - } - - /// - /// Gets called by HibernateTemplate with an active - /// Hibernate Session. Does not need to care about activating or closing - /// the Session, or handling transactions. - /// - /// - ///

- /// Allows for returning a result object created within the callback, i.e. - /// a domain object or a collection of domain objects. Note that there's - /// special support for single step actions: see HibernateTemplate.find etc. - ///

- ///
- public IList DoInHibernate(ISession session) - { - IQuery queryObject = session.CreateQuery(queryString); - outer.PrepareQuery(queryObject); - if (values != null) + else { - for (int i = 0; i < values.Length; i++) - { - outer.ApplyNamedParameterToQuery(queryObject, paramNames[i], values[i], - (types != null ? types[i] : null)); - } + SessionFactoryUtils.ReleaseSession(session, SessionFactory); } - return queryObject.List(); } } - internal class FindByNamedQueryHibernateCallback : IFindHibernateCallback + /// + /// Execute the action specified by the given action object within a Session. + /// + /// + /// Application exceptions thrown by the action object get propagated to the + /// caller (can only be unchecked). Hibernate exceptions are transformed into + /// appropriate DAO ones. Allows for returning the result object. + ///

Note: Callback code is not supposed to handle transactions itself! + /// Use an appropriate transaction manager like HibernateTransactionManager. + /// Generally, callback code must not touch any Session lifecycle methods, + /// like close, disconnect, or reconnect, to let the template do its work. + ///

+ ///
+ /// The object type to find. + /// The delegate callback object that specifies the Hibernate action. + /// A generic IList returned by the action, or null + /// + /// In case of Hibernate errors + public IList ExecuteFind(FindHibernateDelegate del) { - HibernateTemplate outer; - private string queryName; - private object[] values; - private IType[] types; - - public FindByNamedQueryHibernateCallback(HibernateTemplate template, string queryName, object[] values, - IType[] types) - { - outer = template; - this.queryName = queryName; - this.values = values; - this.types = types; - } - - /// - /// Gets called by HibernateTemplate with an active - /// Hibernate Session. Does not need to care about activating or closing - /// the Session, or handling transactions. - /// - /// - ///

- /// Allows for returning a result object created within the callback, i.e. - /// a domain object or a collection of domain objects. Note that there's - /// special support for single step actions: see HibernateTemplate.find etc. - ///

- ///
- public IList DoInHibernate(ISession session) - { - IQuery queryObject = session.GetNamedQuery(queryName); - outer.PrepareQuery(queryObject); - if (values != null) - { - for (int i = 0; i < values.Length; i++) - { - if (types != null && types[i] != null) - { - queryObject.SetParameter(i, values[i], types[i]); - } - else - { - queryObject.SetParameter(i, values[i]); - } - } - } - return queryObject.List(); - } + return ExecuteFind(new ExecuteFindHibernateCallbackUsingDelegate(del)); } - internal class FindByNamedQueryAndNamedParamHibernateCallback : IFindHibernateCallback + /// + /// Execute the action specified by the delegate within a Session. + /// + /// The object type to find. + /// The FindHibernateDelegate that specifies the action + /// to perform. + /// if set to true expose the native hibernate session to + /// callback code. + /// A generic IList returned by the action, or null + /// + /// In case of Hibernate errors + public IList ExecuteFind(FindHibernateDelegate del, bool exposeNativeSession) { - HibernateTemplate outer; - private string queryName; - private string[] paramNames; - private object[] values; - private IType[] types; - - public FindByNamedQueryAndNamedParamHibernateCallback(HibernateTemplate template, string queryName, - string[] paramNames, object[] values, IType[] types) - { - outer = template; - this.queryName = queryName; - this.paramNames = paramNames; - this.values = values; - this.types = types; - } - - /// - /// Gets called by HibernateTemplate with an active - /// Hibernate Session. Does not need to care about activating or closing - /// the Session, or handling transactions. - /// - /// - ///

- /// Allows for returning a result object created within the callback, i.e. - /// a domain object or a collection of domain objects. Note that there's - /// special support for single step actions: see HibernateTemplate.find etc. - ///

- ///
- public IList DoInHibernate(ISession session) - { - IQuery queryObject = session.GetNamedQuery(queryName); - outer.PrepareQuery(queryObject); - if (values != null) - { - for (int i = 0; i < values.Length; i++) - { - outer.ApplyNamedParameterToQuery(queryObject, paramNames[i], values[i], - (types != null ? types[i] : null)); - } - } - return queryObject.List(); - } + return ExecuteFind(new ExecuteFindHibernateCallbackUsingDelegate(del), true); } - internal class FindByNamedQueryAndValueObjectHibernateCallback : IFindHibernateCallback + /// + /// Execute the action specified by the given action object within a Session. + /// + /// The object type to find. + /// The callback object that specifies the Hibernate action. + /// + /// A generic IList returned by the action, or null + /// + /// + /// Application exceptions thrown by the action object get propagated to the + /// caller (can only be unchecked). Hibernate exceptions are transformed into + /// appropriate DAO ones. Allows for returning the result object. + ///

Note: Callback code is not supposed to handle transactions itself! + /// Use an appropriate transaction manager like HibernateTransactionManager. + /// Generally, callback code must not touch any Session lifecycle methods, + /// like close, disconnect, or reconnect, to let the template do its work. + ///

+ ///
+ public IList ExecuteFind(IFindHibernateCallback action) { - HibernateTemplate outer; - private string queryName; - private object valueObject; + return ExecuteFind(action, ExposeNativeSession); + } +} - public FindByNamedQueryAndValueObjectHibernateCallback(HibernateTemplate template, string queryName, - object valueObject) - { - outer = template; - this.queryName = queryName; - this.valueObject = valueObject; - } +internal class ExecuteHibernateCallbackUsingDelegate : IHibernateCallback +{ + private HibernateDelegate del; - /// - /// Gets called by HibernateTemplate with an active - /// Hibernate Session. Does not need to care about activating or closing - /// the Session, or handling transactions. - /// - /// - ///

- /// Allows for returning a result object created within the callback, i.e. - /// a domain object or a collection of domain objects. Note that there's - /// special support for single step actions: see HibernateTemplate.find etc. - ///

- ///
- public IList DoInHibernate(ISession session) - { - IQuery queryObject = session.GetNamedQuery(queryName); - outer.PrepareQuery(queryObject); - queryObject.SetProperties(valueObject); - return queryObject.List(); - } + public ExecuteHibernateCallbackUsingDelegate(HibernateDelegate d) + { + del = d; } - internal class FindByValueObjectHibernateCallback : IFindHibernateCallback + public T DoInHibernate(ISession session) { - HibernateTemplate outer; - private string queryString; - private object valueObject; + return del(session); + } +} - public FindByValueObjectHibernateCallback(HibernateTemplate template, string queryString, object valueObject) - { - outer = template; - this.queryString = queryString; - this.valueObject = valueObject; - } +internal class GetByTypeHibernateCallback : IHibernateCallback +{ + private object id; + private LockMode lockMode; - public IList DoInHibernate(ISession session) - { - IQuery queryObject = session.CreateQuery(queryString); - outer.PrepareQuery(queryObject); - queryObject.SetProperties(valueObject); - return queryObject.List(); - } + public GetByTypeHibernateCallback(object id, LockMode lockMode) + { + this.id = id; + this.lockMode = lockMode; } - internal class ExecuteFindHibernateCallbackUsingDelegate : IFindHibernateCallback + /// + /// Gets called by HibernateTemplate with an active + /// Hibernate Session. Does not need to care about activating or closing + /// the Session, or handling transactions. + /// + /// + ///

+ /// Allows for returning a result object created within the callback, i.e. + /// a domain object or a collection of domain objects. Note that there's + /// special support for single step actions: see HibernateTemplate.find etc. + ///

+ ///
+ public T DoInHibernate(ISession session) { - private FindHibernateDelegate del; - - public ExecuteFindHibernateCallbackUsingDelegate(FindHibernateDelegate d) + if (lockMode != null) { - del = d; + return session.Get(id, lockMode); } - - public IList DoInHibernate(ISession session) + else { - return del(session); + return session.Get(id); } } } + +internal class LoadByTypeHibernateCallback : IHibernateCallback +{ + private object id; + private LockMode lockMode; + + public LoadByTypeHibernateCallback(object id, LockMode lockMode) + { + this.id = id; + this.lockMode = lockMode; + } + + /// + /// Gets called by HibernateTemplate with an active + /// Hibernate Session. Does not need to care about activating or closing + /// the Session, or handling transactions. + /// + /// + ///

+ /// Allows for returning a result object created within the callback, i.e. + /// a domain object or a collection of domain objects. Note that there's + /// special support for single step actions: see HibernateTemplate.find etc. + ///

+ ///
+ public T DoInHibernate(ISession session) + { + if (lockMode != null) + { + return session.Load(id, lockMode); + } + else + { + return session.Load(id); + } + } +} + +internal class LoadAllByTypeHibernateCallback : IFindHibernateCallback +{ + private HibernateTemplate outer; + + public LoadAllByTypeHibernateCallback(HibernateTemplate template) + { + outer = template; + } + + /// + /// Gets called by HibernateTemplate with an active + /// Hibernate Session. Does not need to care about activating or closing + /// the Session, or handling transactions. + /// + /// + ///

+ /// Allows for returning a result object created within the callback, i.e. + /// a domain object or a collection of domain objects. Note that there's + /// special support for single step actions: see HibernateTemplate.find etc. + ///

+ ///
+ public IList DoInHibernate(ISession session) + { + ICriteria criteria = session.CreateCriteria(typeof(T)); + outer.PrepareCriteria(criteria); + return criteria.List(); + } +} + +internal class FindHibernateCallback : IFindHibernateCallback +{ + private HibernateTemplate outer; + private string queryString; + private object[] values; + private IType[] types; + + public FindHibernateCallback(HibernateTemplate template, string queryString, object[] values, IType[] types) + { + outer = template; + this.queryString = queryString; + this.values = values; + this.types = types; + } + + /// + /// Gets called by HibernateTemplate with an active + /// Hibernate Session. Does not need to care about activating or closing + /// the Session, or handling transactions. + /// + /// + ///

+ /// Allows for returning a result object created within the callback, i.e. + /// a domain object or a collection of domain objects. Note that there's + /// special support for single step actions: see HibernateTemplate.find etc. + ///

+ ///
+ public IList DoInHibernate(ISession session) + { + IQuery queryObject = session.CreateQuery(queryString); + outer.PrepareQuery(queryObject); + + if (values != null) + { + for (int i = 0; i < values.Length; i++) + { + if (types != null && types[i] != null) + { + queryObject.SetParameter(i, values[i], types[i]); + } + else + { + queryObject.SetParameter(i, values[i]); + } + } + } + + return queryObject.List(); + } +} + +internal class FindByNamedParamHibernateCallback : IFindHibernateCallback +{ + HibernateTemplate outer; + private string queryString; + private string[] paramNames; + private object[] values; + private IType[] types; + + public FindByNamedParamHibernateCallback(HibernateTemplate template, string queryString, string[] paramNames, + object[] values, IType[] types) + { + outer = template; + this.queryString = queryString; + this.paramNames = paramNames; + this.values = values; + this.types = types; + } + + /// + /// Gets called by HibernateTemplate with an active + /// Hibernate Session. Does not need to care about activating or closing + /// the Session, or handling transactions. + /// + /// + ///

+ /// Allows for returning a result object created within the callback, i.e. + /// a domain object or a collection of domain objects. Note that there's + /// special support for single step actions: see HibernateTemplate.find etc. + ///

+ ///
+ public IList DoInHibernate(ISession session) + { + IQuery queryObject = session.CreateQuery(queryString); + outer.PrepareQuery(queryObject); + if (values != null) + { + for (int i = 0; i < values.Length; i++) + { + outer.ApplyNamedParameterToQuery(queryObject, paramNames[i], values[i], + (types != null ? types[i] : null)); + } + } + + return queryObject.List(); + } +} + +internal class FindByNamedQueryHibernateCallback : IFindHibernateCallback +{ + HibernateTemplate outer; + private string queryName; + private object[] values; + private IType[] types; + + public FindByNamedQueryHibernateCallback(HibernateTemplate template, string queryName, object[] values, + IType[] types) + { + outer = template; + this.queryName = queryName; + this.values = values; + this.types = types; + } + + /// + /// Gets called by HibernateTemplate with an active + /// Hibernate Session. Does not need to care about activating or closing + /// the Session, or handling transactions. + /// + /// + ///

+ /// Allows for returning a result object created within the callback, i.e. + /// a domain object or a collection of domain objects. Note that there's + /// special support for single step actions: see HibernateTemplate.find etc. + ///

+ ///
+ public IList DoInHibernate(ISession session) + { + IQuery queryObject = session.GetNamedQuery(queryName); + outer.PrepareQuery(queryObject); + if (values != null) + { + for (int i = 0; i < values.Length; i++) + { + if (types != null && types[i] != null) + { + queryObject.SetParameter(i, values[i], types[i]); + } + else + { + queryObject.SetParameter(i, values[i]); + } + } + } + + return queryObject.List(); + } +} + +internal class FindByNamedQueryAndNamedParamHibernateCallback : IFindHibernateCallback +{ + HibernateTemplate outer; + private string queryName; + private string[] paramNames; + private object[] values; + private IType[] types; + + public FindByNamedQueryAndNamedParamHibernateCallback(HibernateTemplate template, string queryName, + string[] paramNames, object[] values, IType[] types) + { + outer = template; + this.queryName = queryName; + this.paramNames = paramNames; + this.values = values; + this.types = types; + } + + /// + /// Gets called by HibernateTemplate with an active + /// Hibernate Session. Does not need to care about activating or closing + /// the Session, or handling transactions. + /// + /// + ///

+ /// Allows for returning a result object created within the callback, i.e. + /// a domain object or a collection of domain objects. Note that there's + /// special support for single step actions: see HibernateTemplate.find etc. + ///

+ ///
+ public IList DoInHibernate(ISession session) + { + IQuery queryObject = session.GetNamedQuery(queryName); + outer.PrepareQuery(queryObject); + if (values != null) + { + for (int i = 0; i < values.Length; i++) + { + outer.ApplyNamedParameterToQuery(queryObject, paramNames[i], values[i], + (types != null ? types[i] : null)); + } + } + + return queryObject.List(); + } +} + +internal class FindByNamedQueryAndValueObjectHibernateCallback : IFindHibernateCallback +{ + HibernateTemplate outer; + private string queryName; + private object valueObject; + + public FindByNamedQueryAndValueObjectHibernateCallback(HibernateTemplate template, string queryName, + object valueObject) + { + outer = template; + this.queryName = queryName; + this.valueObject = valueObject; + } + + /// + /// Gets called by HibernateTemplate with an active + /// Hibernate Session. Does not need to care about activating or closing + /// the Session, or handling transactions. + /// + /// + ///

+ /// Allows for returning a result object created within the callback, i.e. + /// a domain object or a collection of domain objects. Note that there's + /// special support for single step actions: see HibernateTemplate.find etc. + ///

+ ///
+ public IList DoInHibernate(ISession session) + { + IQuery queryObject = session.GetNamedQuery(queryName); + outer.PrepareQuery(queryObject); + queryObject.SetProperties(valueObject); + return queryObject.List(); + } +} + +internal class FindByValueObjectHibernateCallback : IFindHibernateCallback +{ + HibernateTemplate outer; + private string queryString; + private object valueObject; + + public FindByValueObjectHibernateCallback(HibernateTemplate template, string queryString, object valueObject) + { + outer = template; + this.queryString = queryString; + this.valueObject = valueObject; + } + + public IList DoInHibernate(ISession session) + { + IQuery queryObject = session.CreateQuery(queryString); + outer.PrepareQuery(queryObject); + queryObject.SetProperties(valueObject); + return queryObject.List(); + } +} + +internal class ExecuteFindHibernateCallbackUsingDelegate : IFindHibernateCallback +{ + private FindHibernateDelegate del; + + public ExecuteFindHibernateCallbackUsingDelegate(FindHibernateDelegate d) + { + del = d; + } + + public IList DoInHibernate(ISession session) + { + return del(session); + } +} diff --git a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Generic/IFindHibernateCallback.cs b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Generic/IFindHibernateCallback.cs index b624535b..90b5e11b 100644 --- a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Generic/IFindHibernateCallback.cs +++ b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Generic/IFindHibernateCallback.cs @@ -1,12 +1,12 @@ /* * Copyright � 2002-2011 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. @@ -16,35 +16,34 @@ using NHibernate; -namespace Spring.Data.NHibernate.Generic +namespace Spring.Data.NHibernate.Generic; + +/// +/// Callback interface (Generic version) for NHibernate code that +/// returns a List of objects. +/// +/// The type of result object +/// To be used with HibernateTemplate execute +/// method. The typical implementation will call +/// Session.load/find/save/update to perform +/// some operations on persistent objects. +/// +/// Sree Nivask (.NET) +/// Mark Pollack (.NET) +public interface IFindHibernateCallback { /// - /// Callback interface (Generic version) for NHibernate code that - /// returns a List of objects. + /// Gets called by HibernateTemplate with an active + /// Hibernate Session. Does not need to care about activating or closing + /// the Session, or handling transactions. /// - /// The type of result object - /// To be used with HibernateTemplate execute - /// method. The typical implementation will call - /// Session.load/find/save/update to perform - /// some operations on persistent objects. - /// - /// Sree Nivask (.NET) - /// Mark Pollack (.NET) - public interface IFindHibernateCallback - { - /// - /// Gets called by HibernateTemplate with an active - /// Hibernate Session. Does not need to care about activating or closing - /// the Session, or handling transactions. - /// - /// - ///

- /// Allows for returning a result object created within the callback, i.e. - /// a domain object or a collection of domain objects. Note that there's - /// special support for single step actions: see HibernateTemplate.find etc. - ///

- ///
- /// Collection result object. - IList DoInHibernate(ISession session); - } + /// + ///

+ /// Allows for returning a result object created within the callback, i.e. + /// a domain object or a collection of domain objects. Note that there's + /// special support for single step actions: see HibernateTemplate.find etc. + ///

+ ///
+ /// Collection result object. + IList DoInHibernate(ISession session); } diff --git a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Generic/IHibernateCallback.cs b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Generic/IHibernateCallback.cs index ac5a0b57..522e6347 100644 --- a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Generic/IHibernateCallback.cs +++ b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Generic/IHibernateCallback.cs @@ -1,12 +1,12 @@ /* - * Copyright © 2002-2011 the original author or authors. - * + * Copyright � 2002-2011 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. @@ -16,35 +16,34 @@ using NHibernate; -namespace Spring.Data.NHibernate.Generic +namespace Spring.Data.NHibernate.Generic; + +/// +/// Callback interface (Generic version) for NHibernate code. +/// +/// The type of result object +/// To be used with HibernateTemplate execute +/// method. The typical implementation will call +/// Session.load/find/save/update to perform +/// some operations on persistent objects. +/// +/// +/// Sree Nivask (.NET) +public interface IHibernateCallback { - /// - /// Callback interface (Generic version) for NHibernate code. + /// + /// Gets called by HibernateTemplate with an active + /// Hibernate Session. Does not need to care about activating or closing + /// the Session, or handling transactions. /// - /// The type of result object - /// To be used with HibernateTemplate execute - /// method. The typical implementation will call - /// Session.load/find/save/update to perform - /// some operations on persistent objects. - /// - /// - /// Sree Nivask (.NET) - public interface IHibernateCallback - { - /// - /// Gets called by HibernateTemplate with an active - /// Hibernate Session. Does not need to care about activating or closing - /// the Session, or handling transactions. - /// - /// - ///

- /// Allows for returning a result object created within the callback, i.e. - /// a domain object or a collection of domain objects. Note that there's - /// special support for single step actions: see HibernateTemplate.find etc. - ///

- ///
- /// A result object. - /// The active Hibernate session - T DoInHibernate(ISession session); - } + /// + ///

+ /// Allows for returning a result object created within the callback, i.e. + /// a domain object or a collection of domain objects. Note that there's + /// special support for single step actions: see HibernateTemplate.find etc. + ///

+ ///
+ /// A result object. + /// The active Hibernate session + T DoInHibernate(ISession session); } diff --git a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Generic/IHibernateOperations.cs b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Generic/IHibernateOperations.cs index a836b4e1..038849e3 100644 --- a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Generic/IHibernateOperations.cs +++ b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Generic/IHibernateOperations.cs @@ -1,12 +1,12 @@ /* * Copyright � 2002-2011 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. @@ -18,468 +18,466 @@ using NHibernate; using NHibernate.Type; using Spring.Dao; -namespace Spring.Data.NHibernate.Generic +namespace Spring.Data.NHibernate.Generic; + +/// +/// Interface that specifies a basic set of Hibernate operations. +/// +/// +/// Implemented by HibernateTemplate. Not often used, but a useful option +/// to enhance testability, as it can easily be mocked or stubbed. +///

Provides HibernateTemplate's data access methods that mirror +/// various Session methods. See the NHibernate ISession documentation +/// for details on those methods. +///

+///
+/// +/// Sree Nivask (.NET) +/// Mark Pollack (.NET) +public interface IHibernateOperations : ICommonHibernateOperations { /// - /// Interface that specifies a basic set of Hibernate operations. + /// Return the persistent instance of the given entity type + /// with the given identifier, or if not found. + /// Obtains the specified lock mode if the instance exists. + /// + /// The object type to get. + /// The id of the object to get. + /// the persistent instance, or if not found + /// In case of Hibernate errors + T Get(object id); + + /// + /// Return the persistent instance of the given entity type + /// with the given identifier, or null if not found. + /// Obtains the specified lock mode if the instance exists. + /// + /// The object type to get. + /// The lock mode to obtain. + /// The lock mode. + /// the persistent instance, or null if not found + /// In case of Hibernate errors + T Get(object id, LockMode lockMode); + + /// + /// Return the persistent instance of the given entity class + /// with the given identifier, throwing an exception if not found. + /// + /// The object type to load. + /// An identifier of the persistent instance. + /// The persistent instance + /// If not found + /// In case of Hibernate errors + T Load(object id); + + /// + /// Return the persistent instance of the given entity class + /// with the given identifier, throwing an exception if not found. + /// Obtains the specified lock mode if the instance exists. + /// + /// The object type to load. + /// An identifier of the persistent instance. + /// The lock mode. + /// The persistent instance + /// If not found + /// In case of Hibernate errors + T Load(object id, LockMode lockMode); + + /// + /// Return all persistent instances of the given entity class. + /// Note: Use queries or criteria for retrieving a specific subset. + /// + /// The object type to load. + /// A generic List containing 0 or more persistent instances + /// In case of Hibernate errors + IList LoadAll(); + + /// + /// Execute a query for persistent instances. + /// + /// The object type to find. + /// a query expressed in Hibernate's query language + /// + /// a generic List containing 0 or more persistent instances + /// + /// In case of Hibernate errors + IList Find(string queryString); + + /// + /// Execute a query for persistent instances, binding + /// one value to a "?" parameter in the query string. + /// + /// The object type to find. + /// a query expressed in Hibernate's query language + /// the value of the parameter + /// + /// a generic List containing 0 or more persistent instances + /// + /// In case of Hibernate errors + IList Find(string queryString, object value); + + /// + /// Execute a query for persistent instances, binding one value + /// to a "?" parameter of the given type in the query string. + /// + /// The object type to find. + /// a query expressed in Hibernate's query language + /// The value of the parameter. + /// Hibernate type of the parameter (or null) + /// + /// a generic List containing 0 or more persistent instances + /// + /// In case of Hibernate errors + IList Find(string queryString, object value, IType type); + + /// + /// Execute a query for persistent instances, binding a + /// number of values to "?" parameters in the query string. + /// + /// The object type to find. + /// a query expressed in Hibernate's query language + /// the values of the parameters + /// a generic List containing 0 or more persistent instances + /// In case of Hibernate errors + IList Find(string queryString, object[] values); + + /// + /// Execute a query for persistent instances, binding a number of + /// values to "?" parameters of the given types in the query string. + /// + /// The object type to find. + /// A query expressed in Hibernate's query language + /// The values of the parameters + /// Hibernate types of the parameters (or null) + /// + /// a generic List containing 0 or more persistent instances + /// + /// In case of Hibernate errors + /// If values and types are not null and their lenths are not equal + IList Find(string queryString, object[] values, IType[] types); + + /// + /// Execute a query for persistent instances, binding + /// one value to a named parameter in the query string. + /// + /// The object type to find. + /// The name of a Hibernate query in a mapping file + /// The name of the parameter + /// The value of the parameter + /// a generic List containing 0 or more persistent instances + /// In case of Hibernate errors + IList FindByNamedParam(string queryName, string paramName, object value); + + /// + /// Execute a query for persistent instances, binding + /// one value to a named parameter in the query string. + /// + /// The object type to find. + /// The name of a Hibernate query in a mapping file + /// The name of the parameter + /// The value of the parameter + /// Hibernate type of the parameter (or null) + /// A generic List containing 0 or more persistent instances + /// In case of Hibernate errors + IList FindByNamedParam(string queryName, string paramName, object value, IType type); + + /// + /// Execute a query for persistent instances, binding a + /// number of values to named parameters in the query string. + /// + /// The object type to find. + /// A query expressed in Hibernate's query language + /// The names of the parameters + /// The values of the parameters + /// A generic List containing 0 or more persistent instances + /// In case of Hibernate errors + IList FindByNamedParam(string queryString, string[] paramNames, object[] values); + + /// + /// Execute a query for persistent instances, binding a + /// number of values to named parameters in the query string. + /// + /// The object type to find. + /// A query expressed in Hibernate's query language + /// The names of the parameters + /// The values of the parameters + /// Hibernate types of the parameters (or null) + /// A generic List containing 0 or more persistent instances + /// In case of Hibernate errors + /// If paramNames length is not equal to values length or + /// if paramNames length is not equal to types length (when types is not null) + IList FindByNamedParam(string queryString, string[] paramNames, object[] values, IType[] types); + + /// + /// Execute a named query for persistent instances. + /// A named query is defined in a Hibernate mapping file. + /// + /// The object type to find. + /// The name of a Hibernate query in a mapping file + /// A generic List containing 0 or more persistent instances + /// In case of Hibernate errors + IList FindByNamedQuery(string queryName); + + /// + /// Execute a named query for persistent instances, binding + /// one value to a "?" parameter in the query string. + /// A named query is defined in a Hibernate mapping file. + /// + /// The object type to find. + /// The name of a Hibernate query in a mapping file + /// The value of the parameter + /// A generic List containing 0 or more persistent instances + /// In case of Hibernate errors + IList FindByNamedQuery(string queryName, object value); + + /// + /// Execute a named query for persistent instances, binding + /// one value to a "?" parameter in the query string. + /// A named query is defined in a Hibernate mapping file. + /// + /// The object type to find. + /// The name of a Hibernate query in a mapping file + /// The value of the parameter + /// Hibernate type of the parameter (or null) + /// A generic List containing 0 or more persistent instances + /// In case of Hibernate errors + IList FindByNamedQuery(string queryName, object value, IType type); + + /// + /// Execute a named query for persistent instances, binding a + /// number of values to "?" parameters in the query string. + /// A named query is defined in a Hibernate mapping file. + /// + /// The object type to find. + /// The name of a Hibernate query in a mapping file + /// The values of the parameters + /// A generic List containing 0 or more persistent instances + /// In case of Hibernate errors + IList FindByNamedQuery(string queryName, object[] values); + + /// + /// Execute a named query for persistent instances, binding a + /// number of values to "?" parameters in the query string. + /// A named query is defined in a Hibernate mapping file. + /// + /// The object type to find. + /// The name of a Hibernate query in a mapping file + /// The values of the parameters + /// Hibernate types of the parameters (or null) + /// A generic List containing 0 or more persistent instances + /// In case of Hibernate errors + /// If values and types are not null and their lengths differ. + IList FindByNamedQuery(string queryName, object[] values, IType[] types); + + /// + /// Execute a named query for persistent instances, binding + /// one value to a named parameter in the query string. + /// A named query is defined in a Hibernate mapping file. + /// + /// The object type to find. + /// The name of a Hibernate query in a mapping file + /// Name of the parameter + /// The value of the parameter + /// A generic List containing 0 or more persistent instances + /// In case of Hibernate errors + IList FindByNamedQueryAndNamedParam(string queryName, string paramName, object value); + + /// + /// Execute a named query for persistent instances, binding + /// one value to a named parameter in the query string. + /// A named query is defined in a Hibernate mapping file. + /// + /// The object type to find. + /// The name of a Hibernate query in a mapping file + /// Name of the parameter + /// The value of the parameter + /// The Hibernate type of the parameter (or null) + /// A generic List containing 0 or more persistent instances + /// In case of Hibernate errors + IList FindByNamedQueryAndNamedParam(string queryName, string paramName, object value, IType type); + + /// + /// Execute a named query for persistent instances, binding + /// number of values to named parameters in the query string. + /// A named query is defined in a Hibernate mapping file. + /// + /// The object type to find. + /// The name of a Hibernate query in a mapping file + /// The names of the parameters + /// The values of the parameters. + /// A generic List containing 0 or more persistent instances + /// In case of Hibernate errors + IList FindByNamedQueryAndNamedParam(string queryName, string[] paramNames, object[] values); + + /// + /// Execute a named query for persistent instances, binding + /// number of values to named parameters in the query string. + /// A named query is defined in a Hibernate mapping file. + /// + /// The object type to find. + /// The name of a Hibernate query in a mapping file + /// The names of the parameters + /// The values of the parameters. + /// Hibernate types of the parameters (or null) + /// A generic List containing 0 or more persistent instances + /// In case of Hibernate errors + /// If paramNames length is not equal to values length or + /// if paramNames length is not equal to types length (when types is not null) + IList FindByNamedQueryAndNamedParam(string queryName, string[] paramNames, object[] values, IType[] types); + + /// + /// Execute a named query for persistent instances, binding the properties + /// of the given object to named parameters in the query string. + /// A named query is defined in a Hibernate mapping file. + /// + /// The object type to find. + /// The name of a Hibernate query in a mapping file + /// The values of the parameters + /// A generic List containing 0 or more persistent instances + /// In case of Hibernate errors + IList FindByNamedQueryAndValueObject(string queryName, object valueObject); + + /// + /// Execute a query for persistent instances, binding the properties + /// of the given object to named parameters in the query string. + /// + /// The object type to find. + /// A query expressed in Hibernate's query language + /// The values of the parameters + /// A generic List containing 0 or more persistent instances + /// In case of Hibernate errors + IList FindByValueObject(string queryString, object valueObject); + + /// + /// Execute the action specified by the given action object within a Session. /// /// - /// Implemented by HibernateTemplate. Not often used, but a useful option - /// to enhance testability, as it can easily be mocked or stubbed. - ///

Provides HibernateTemplate's data access methods that mirror - /// various Session methods. See the NHibernate ISession documentation - /// for details on those methods. + /// Application exceptions thrown by the action object get propagated to the + /// caller (can only be unchecked). Hibernate exceptions are transformed into + /// appropriate DAO ones. Allows for returning the result object. + ///

Note: Callback code is not supposed to handle transactions itself! + /// Use an appropriate transaction manager like HibernateTransactionManager. + /// Generally, callback code must not touch any Session lifecycle methods, + /// like close, disconnect, or reconnect, to let the template do its work. ///

///
- /// - /// Sree Nivask (.NET) - /// Mark Pollack (.NET) - public interface IHibernateOperations : ICommonHibernateOperations - { - - /// - /// Return the persistent instance of the given entity type - /// with the given identifier, or if not found. - /// Obtains the specified lock mode if the instance exists. - /// - /// The object type to get. - /// The id of the object to get. - /// the persistent instance, or if not found - /// In case of Hibernate errors - T Get(object id); + /// The object type retrieved. + /// The delegate callback object that specifies the Hibernate action. + /// a result object returned by the action, or null + /// + /// In case of Hibernate errors + T Execute(HibernateDelegate del); - /// - /// Return the persistent instance of the given entity type - /// with the given identifier, or null if not found. - /// Obtains the specified lock mode if the instance exists. - /// - /// The object type to get. - /// The lock mode to obtain. - /// The lock mode. - /// the persistent instance, or null if not found - /// In case of Hibernate errors - T Get(object id, LockMode lockMode); + /// + /// Execute the action specified by the delegate within a Session. + /// + /// The object type retrieved. + /// The HibernateDelegate that specifies the action + /// to perform. + /// if set to true expose the native hibernate session to + /// callback code. + /// a result object returned by the action, or null + /// + /// In case of Hibernate errors + T Execute(HibernateDelegate del, bool exposeNativeSession); - /// - /// Return the persistent instance of the given entity class - /// with the given identifier, throwing an exception if not found. - /// - /// The object type to load. - /// An identifier of the persistent instance. - /// The persistent instance - /// If not found - /// In case of Hibernate errors - T Load(object id); + /// + /// Execute the action specified by the given action object within a Session. + /// + /// The object type retrieved. + /// The callback object that specifies the Hibernate action. + /// + /// a result object returned by the action, or null + /// + /// + /// Application exceptions thrown by the action object get propagated to the + /// caller (can only be unchecked). Hibernate exceptions are transformed into + /// appropriate DAO ones. Allows for returning the result object. + ///

Note: Callback code is not supposed to handle transactions itself! + /// Use an appropriate transaction manager like HibernateTransactionManager. + /// Generally, callback code must not touch any Session lifecycle methods, + /// like close, disconnect, or reconnect, to let the template do its work. + ///

+ ///
+ /// In case of Hibernate errors + T Execute(IHibernateCallback action); - /// - /// Return the persistent instance of the given entity class - /// with the given identifier, throwing an exception if not found. - /// Obtains the specified lock mode if the instance exists. - /// - /// The object type to load. - /// An identifier of the persistent instance. - /// The lock mode. - /// The persistent instance - /// If not found - /// In case of Hibernate errors - T Load(object id, LockMode lockMode); + /// + /// Execute the action specified by the given action object within a Session. + /// + /// The object type retrieved. + /// callback object that specifies the Hibernate action. + /// if set to true expose the native hibernate session to + /// callback code. + /// + /// a result object returned by the action, or null + /// + /// In case of Hibernate errors + T Execute(IHibernateCallback action, bool exposeNativeSession); - /// - /// Return all persistent instances of the given entity class. - /// Note: Use queries or criteria for retrieving a specific subset. - /// - /// The object type to load. - /// A generic List containing 0 or more persistent instances - /// In case of Hibernate errors - IList LoadAll(); + /// + /// Execute the action specified by the given action object within a Session. + /// + /// + /// Application exceptions thrown by the action object get propagated to the + /// caller (can only be unchecked). Hibernate exceptions are transformed into + /// appropriate DAO ones. Allows for returning the result object. + ///

Note: Callback code is not supposed to handle transactions itself! + /// Use an appropriate transaction manager like HibernateTransactionManager. + /// Generally, callback code must not touch any Session lifecycle methods, + /// like close, disconnect, or reconnect, to let the template do its work. + ///

+ ///
+ /// The object type to find. + /// The delegate callback object that specifies the Hibernate action. + /// A generic IList returned by the action, or null + /// + /// In case of Hibernate errors + IList ExecuteFind(FindHibernateDelegate del); - /// - /// Execute a query for persistent instances. - /// - /// The object type to find. - /// a query expressed in Hibernate's query language - /// - /// a generic List containing 0 or more persistent instances - /// - /// In case of Hibernate errors - IList Find(string queryString); + /// + /// Execute the action specified by the delegate within a Session. + /// + /// The object type to find. + /// The FindHibernateDelegate that specifies the action + /// to perform. + /// if set to true expose the native hibernate session to + /// callback code. + /// A generic IList returned by the action, or null + /// + /// In case of Hibernate errors + IList ExecuteFind(FindHibernateDelegate del, bool exposeNativeSession); - /// - /// Execute a query for persistent instances, binding - /// one value to a "?" parameter in the query string. - /// - /// The object type to find. - /// a query expressed in Hibernate's query language - /// the value of the parameter - /// - /// a generic List containing 0 or more persistent instances - /// - /// In case of Hibernate errors - IList Find(string queryString, object value); + /// + /// Execute the action specified by the given action object within a Session. + /// + /// The object type to find. + /// The callback object that specifies the Hibernate action. + /// + /// A generic IList returned by the action, or null + /// + /// + /// Application exceptions thrown by the action object get propagated to the + /// caller (can only be unchecked). Hibernate exceptions are transformed into + /// appropriate DAO ones. Allows for returning the result object. + ///

Note: Callback code is not supposed to handle transactions itself! + /// Use an appropriate transaction manager like HibernateTransactionManager. + /// Generally, callback code must not touch any Session lifecycle methods, + /// like close, disconnect, or reconnect, to let the template do its work. + ///

+ ///
+ IList ExecuteFind(IFindHibernateCallback action); - /// - /// Execute a query for persistent instances, binding one value - /// to a "?" parameter of the given type in the query string. - /// - /// The object type to find. - /// a query expressed in Hibernate's query language - /// The value of the parameter. - /// Hibernate type of the parameter (or null) - /// - /// a generic List containing 0 or more persistent instances - /// - /// In case of Hibernate errors - IList Find(string queryString, object value, IType type); - - /// - /// Execute a query for persistent instances, binding a - /// number of values to "?" parameters in the query string. - /// - /// The object type to find. - /// a query expressed in Hibernate's query language - /// the values of the parameters - /// a generic List containing 0 or more persistent instances - /// In case of Hibernate errors - IList Find(string queryString, object[] values); - - /// - /// Execute a query for persistent instances, binding a number of - /// values to "?" parameters of the given types in the query string. - /// - /// The object type to find. - /// A query expressed in Hibernate's query language - /// The values of the parameters - /// Hibernate types of the parameters (or null) - /// - /// a generic List containing 0 or more persistent instances - /// - /// In case of Hibernate errors - /// If values and types are not null and their lenths are not equal - IList Find(string queryString, object[] values, IType[] types); - - /// - /// Execute a query for persistent instances, binding - /// one value to a named parameter in the query string. - /// - /// The object type to find. - /// The name of a Hibernate query in a mapping file - /// The name of the parameter - /// The value of the parameter - /// a generic List containing 0 or more persistent instances - /// In case of Hibernate errors - IList FindByNamedParam(string queryName, string paramName, object value); - - /// - /// Execute a query for persistent instances, binding - /// one value to a named parameter in the query string. - /// - /// The object type to find. - /// The name of a Hibernate query in a mapping file - /// The name of the parameter - /// The value of the parameter - /// Hibernate type of the parameter (or null) - /// A generic List containing 0 or more persistent instances - /// In case of Hibernate errors - IList FindByNamedParam(string queryName, string paramName, object value, IType type); - - /// - /// Execute a query for persistent instances, binding a - /// number of values to named parameters in the query string. - /// - /// The object type to find. - /// A query expressed in Hibernate's query language - /// The names of the parameters - /// The values of the parameters - /// A generic List containing 0 or more persistent instances - /// In case of Hibernate errors - IList FindByNamedParam(string queryString, string[] paramNames, object[] values); - - /// - /// Execute a query for persistent instances, binding a - /// number of values to named parameters in the query string. - /// - /// The object type to find. - /// A query expressed in Hibernate's query language - /// The names of the parameters - /// The values of the parameters - /// Hibernate types of the parameters (or null) - /// A generic List containing 0 or more persistent instances - /// In case of Hibernate errors - /// If paramNames length is not equal to values length or - /// if paramNames length is not equal to types length (when types is not null) - IList FindByNamedParam(string queryString, string[] paramNames, object[] values, IType[] types); - - /// - /// Execute a named query for persistent instances. - /// A named query is defined in a Hibernate mapping file. - /// - /// The object type to find. - /// The name of a Hibernate query in a mapping file - /// A generic List containing 0 or more persistent instances - /// In case of Hibernate errors - IList FindByNamedQuery(string queryName); - - /// - /// Execute a named query for persistent instances, binding - /// one value to a "?" parameter in the query string. - /// A named query is defined in a Hibernate mapping file. - /// - /// The object type to find. - /// The name of a Hibernate query in a mapping file - /// The value of the parameter - /// A generic List containing 0 or more persistent instances - /// In case of Hibernate errors - IList FindByNamedQuery(string queryName, object value); - - /// - /// Execute a named query for persistent instances, binding - /// one value to a "?" parameter in the query string. - /// A named query is defined in a Hibernate mapping file. - /// - /// The object type to find. - /// The name of a Hibernate query in a mapping file - /// The value of the parameter - /// Hibernate type of the parameter (or null) - /// A generic List containing 0 or more persistent instances - /// In case of Hibernate errors - IList FindByNamedQuery(string queryName, object value, IType type); - - /// - /// Execute a named query for persistent instances, binding a - /// number of values to "?" parameters in the query string. - /// A named query is defined in a Hibernate mapping file. - /// - /// The object type to find. - /// The name of a Hibernate query in a mapping file - /// The values of the parameters - /// A generic List containing 0 or more persistent instances - /// In case of Hibernate errors - IList FindByNamedQuery(string queryName, object[] values); - - /// - /// Execute a named query for persistent instances, binding a - /// number of values to "?" parameters in the query string. - /// A named query is defined in a Hibernate mapping file. - /// - /// The object type to find. - /// The name of a Hibernate query in a mapping file - /// The values of the parameters - /// Hibernate types of the parameters (or null) - /// A generic List containing 0 or more persistent instances - /// In case of Hibernate errors - /// If values and types are not null and their lengths differ. - IList FindByNamedQuery(string queryName, object[] values, IType[] types); - - /// - /// Execute a named query for persistent instances, binding - /// one value to a named parameter in the query string. - /// A named query is defined in a Hibernate mapping file. - /// - /// The object type to find. - /// The name of a Hibernate query in a mapping file - /// Name of the parameter - /// The value of the parameter - /// A generic List containing 0 or more persistent instances - /// In case of Hibernate errors - IList FindByNamedQueryAndNamedParam(string queryName, string paramName, object value); - - /// - /// Execute a named query for persistent instances, binding - /// one value to a named parameter in the query string. - /// A named query is defined in a Hibernate mapping file. - /// - /// The object type to find. - /// The name of a Hibernate query in a mapping file - /// Name of the parameter - /// The value of the parameter - /// The Hibernate type of the parameter (or null) - /// A generic List containing 0 or more persistent instances - /// In case of Hibernate errors - IList FindByNamedQueryAndNamedParam(string queryName, string paramName, object value, IType type); - - /// - /// Execute a named query for persistent instances, binding - /// number of values to named parameters in the query string. - /// A named query is defined in a Hibernate mapping file. - /// - /// The object type to find. - /// The name of a Hibernate query in a mapping file - /// The names of the parameters - /// The values of the parameters. - /// A generic List containing 0 or more persistent instances - /// In case of Hibernate errors - IList FindByNamedQueryAndNamedParam(string queryName, string[] paramNames, object[] values); - - /// - /// Execute a named query for persistent instances, binding - /// number of values to named parameters in the query string. - /// A named query is defined in a Hibernate mapping file. - /// - /// The object type to find. - /// The name of a Hibernate query in a mapping file - /// The names of the parameters - /// The values of the parameters. - /// Hibernate types of the parameters (or null) - /// A generic List containing 0 or more persistent instances - /// In case of Hibernate errors - /// If paramNames length is not equal to values length or - /// if paramNames length is not equal to types length (when types is not null) - IList FindByNamedQueryAndNamedParam(string queryName, string[] paramNames, object[] values, IType[] types); - - /// - /// Execute a named query for persistent instances, binding the properties - /// of the given object to named parameters in the query string. - /// A named query is defined in a Hibernate mapping file. - /// - /// The object type to find. - /// The name of a Hibernate query in a mapping file - /// The values of the parameters - /// A generic List containing 0 or more persistent instances - /// In case of Hibernate errors - IList FindByNamedQueryAndValueObject(string queryName, object valueObject); - - /// - /// Execute a query for persistent instances, binding the properties - /// of the given object to named parameters in the query string. - /// - /// The object type to find. - /// A query expressed in Hibernate's query language - /// The values of the parameters - /// A generic List containing 0 or more persistent instances - /// In case of Hibernate errors - IList FindByValueObject(string queryString, object valueObject); - - /// - /// Execute the action specified by the given action object within a Session. - /// - /// - /// Application exceptions thrown by the action object get propagated to the - /// caller (can only be unchecked). Hibernate exceptions are transformed into - /// appropriate DAO ones. Allows for returning the result object. - ///

Note: Callback code is not supposed to handle transactions itself! - /// Use an appropriate transaction manager like HibernateTransactionManager. - /// Generally, callback code must not touch any Session lifecycle methods, - /// like close, disconnect, or reconnect, to let the template do its work. - ///

- ///
- /// The object type retrieved. - /// The delegate callback object that specifies the Hibernate action. - /// a result object returned by the action, or null - /// - /// In case of Hibernate errors - T Execute(HibernateDelegate del); - - /// - /// Execute the action specified by the delegate within a Session. - /// - /// The object type retrieved. - /// The HibernateDelegate that specifies the action - /// to perform. - /// if set to true expose the native hibernate session to - /// callback code. - /// a result object returned by the action, or null - /// - /// In case of Hibernate errors - T Execute(HibernateDelegate del, bool exposeNativeSession); - - /// - /// Execute the action specified by the given action object within a Session. - /// - /// The object type retrieved. - /// The callback object that specifies the Hibernate action. - /// - /// a result object returned by the action, or null - /// - /// - /// Application exceptions thrown by the action object get propagated to the - /// caller (can only be unchecked). Hibernate exceptions are transformed into - /// appropriate DAO ones. Allows for returning the result object. - ///

Note: Callback code is not supposed to handle transactions itself! - /// Use an appropriate transaction manager like HibernateTransactionManager. - /// Generally, callback code must not touch any Session lifecycle methods, - /// like close, disconnect, or reconnect, to let the template do its work. - ///

- ///
- /// In case of Hibernate errors - T Execute(IHibernateCallback action); - - /// - /// Execute the action specified by the given action object within a Session. - /// - /// The object type retrieved. - /// callback object that specifies the Hibernate action. - /// if set to true expose the native hibernate session to - /// callback code. - /// - /// a result object returned by the action, or null - /// - /// In case of Hibernate errors - T Execute(IHibernateCallback action, bool exposeNativeSession); - - /// - /// Execute the action specified by the given action object within a Session. - /// - /// - /// Application exceptions thrown by the action object get propagated to the - /// caller (can only be unchecked). Hibernate exceptions are transformed into - /// appropriate DAO ones. Allows for returning the result object. - ///

Note: Callback code is not supposed to handle transactions itself! - /// Use an appropriate transaction manager like HibernateTransactionManager. - /// Generally, callback code must not touch any Session lifecycle methods, - /// like close, disconnect, or reconnect, to let the template do its work. - ///

- ///
- /// The object type to find. - /// The delegate callback object that specifies the Hibernate action. - /// A generic IList returned by the action, or null - /// - /// In case of Hibernate errors - IList ExecuteFind(FindHibernateDelegate del); - - /// - /// Execute the action specified by the delegate within a Session. - /// - /// The object type to find. - /// The FindHibernateDelegate that specifies the action - /// to perform. - /// if set to true expose the native hibernate session to - /// callback code. - /// A generic IList returned by the action, or null - /// - /// In case of Hibernate errors - IList ExecuteFind(FindHibernateDelegate del, bool exposeNativeSession); - - /// - /// Execute the action specified by the given action object within a Session. - /// - /// The object type to find. - /// The callback object that specifies the Hibernate action. - /// - /// A generic IList returned by the action, or null - /// - /// - /// Application exceptions thrown by the action object get propagated to the - /// caller (can only be unchecked). Hibernate exceptions are transformed into - /// appropriate DAO ones. Allows for returning the result object. - ///

Note: Callback code is not supposed to handle transactions itself! - /// Use an appropriate transaction manager like HibernateTransactionManager. - /// Generally, callback code must not touch any Session lifecycle methods, - /// like close, disconnect, or reconnect, to let the template do its work. - ///

- ///
- IList ExecuteFind(IFindHibernateCallback action); - - /// - /// Execute the action specified by the given action object within a Session assuming that an IList is returned. - /// - /// The object type to find. - /// callback object that specifies the Hibernate action. - /// if set to true expose the native hibernate session to - /// callback code. - /// - /// an IList returned by the action, or null - /// - /// In case of Hibernate errors - IList ExecuteFind(IFindHibernateCallback action, bool exposeNativeSession); - } + /// + /// Execute the action specified by the given action object within a Session assuming that an IList is returned. + /// + /// The object type to find. + /// callback object that specifies the Hibernate action. + /// if set to true expose the native hibernate session to + /// callback code. + /// + /// an IList returned by the action, or null + /// + /// In case of Hibernate errors + IList ExecuteFind(IFindHibernateCallback action, bool exposeNativeSession); } diff --git a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/HibernateAccessor.cs b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/HibernateAccessor.cs index 073ba6b1..e98975d0 100644 --- a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/HibernateAccessor.cs +++ b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/HibernateAccessor.cs @@ -1,12 +1,12 @@ /* * Copyright � 2002-2011 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. @@ -25,675 +25,665 @@ using Spring.Core.TypeResolution; using Spring.Dao; using Spring.Data.Support; using Spring.Objects.Factory; -using IInterceptor=NHibernate.IInterceptor; -using ICriteria=NHibernate.ICriteria; +using IInterceptor = NHibernate.IInterceptor; +using ICriteria = NHibernate.ICriteria; -namespace Spring.Data.NHibernate +namespace Spring.Data.NHibernate; + +/// +/// Base class for HibernateTemplate defining common +/// properties like SessionFactory and flushing behavior. +/// +/// +///

Not intended to be used directly. See HibernateTemplate. +///

+///
+/// Mark Pollack (.NET) +public abstract class HibernateAccessor : IInitializingObject, IObjectFactoryAware { - /// - /// Base class for HibernateTemplate defining common - /// properties like SessionFactory and flushing behavior. - /// - /// - ///

Not intended to be used directly. See HibernateTemplate. - ///

- ///
- /// Mark Pollack (.NET) - public abstract class HibernateAccessor : IInitializingObject, IObjectFactoryAware - { + private Type criteriaType; - private Type criteriaType; + /// + /// The instance for this class. + /// + private readonly ILogger log = LogManager.GetLogger(); - /// - /// The instance for this class. - /// - private readonly ILogger log = LogManager.GetLogger(); - - /// - /// Initializes a new instance of the class. - /// - public HibernateAccessor() - { - - } - - /// - /// Gets or sets if a new Session should be created when no transactional Session - /// can be found for the current thread. - /// - /// - /// true if allowed to create non-transaction session; - /// otherwise, false. - /// - /// - ///

HibernateTemplate is aware of a corresponding Session bound to the - /// current thread, for example when using HibernateTransactionManager. - /// If allowCreate is true, a new non-transactional Session will be created - /// if none found, which needs to be closed at the end of the operation. - /// If false, an InvalidOperationException will get thrown in this case. - ///

- ///
- public abstract bool AllowCreate - { - get; - set; - } - - /// - /// Gets or sets a value indicating whether to always - /// use a new Hibernate Session for this template. - /// - /// true if always use new session; otherwise, false. - /// - ///

- /// Default is "false"; if activated, all operations on this template will - /// work on a new NHibernate ISession even in case of a pre-bound ISession - /// (for example, within a transaction). - ///

- ///

Within a transaction, a new NHibernate ISession used by this template - /// will participate in the transaction through using the same ADO.NET - /// Connection. In such a scenario, multiple Sessions will participate - /// in the same database transaction. - ///

- ///

Turn this on for operations that are supposed to always execute - /// independently, without side effects caused by a shared NHibernate ISession. - ///

- ///
- public abstract bool AlwaysUseNewSession - { - get; - set; - } - - /// - /// Set whether to expose the native Hibernate Session to IHibernateCallback - /// code. Default is "false": a Session proxy will be returned, - /// suppressing close calls and automatically applying - /// query cache settings and transaction timeouts. - /// - /// true if expose native session; otherwise, false. - public abstract bool ExposeNativeSession - { - get; - set; - } - - /// - /// Gets or sets the template flush mode. - /// - /// - /// Default is Auto. Will get applied to any new ISession - /// created by the template. - /// - /// The template flush mode. - public abstract TemplateFlushMode TemplateFlushMode - { - get; - set; - } - - /// - /// Gets or sets the entity interceptor that allows to inspect and change - /// property values before writing to and reading from the database. - /// - /// - /// Will get applied to any new ISession created by this object. - ///

Such an interceptor can either be set at the ISessionFactory level, - /// i.e. on LocalSessionFactoryObject, or at the ISession level, i.e. on - /// HibernateTemplate, HibernateInterceptor, and HibernateTransactionManager. - /// It's preferable to set it on LocalSessionFactoryObject or HibernateTransactionManager - /// to avoid repeated configuration and guarantee consistent behavior in transactions. - ///

- ///
- /// The interceptor. - public abstract IInterceptor EntityInterceptor - { - get; - set; - } - - /// - /// Set the object name of a Hibernate entity interceptor that allows to inspect - /// and change property values before writing to and reading from the database. - /// - /// - /// Will get applied to any new Session created by this transaction manager. - ///

Requires the object factory to be known, to be able to resolve the object - /// name to an interceptor instance on session creation. Typically used for - /// prototype interceptors, i.e. a new interceptor instance per session. - ///

- ///

Can also be used for shared interceptor instances, but it is recommended - /// to set the interceptor reference directly in such a scenario. - ///

- ///
- /// The name of the entity interceptor in the object factory/application context. - public abstract string EntityInterceptorObjectName - { - set; - } - - /// - /// Gets or sets the session factory that should be used to create - /// NHibernate ISessions. - /// - /// The session factory. - public abstract ISessionFactory SessionFactory - { - get; - set; - } - - /// - /// Set the object factory instance. - /// - /// The object factory instance. - public abstract IObjectFactory ObjectFactory - { - set; - } - - /// - /// Gets or sets a value indicating whether to - /// cache all queries executed by this template. - /// - /// - /// If this is true, all IQuery and ICriteria objects created by - /// this template will be marked as cacheable (including all - /// queries through find methods). - ///

To specify the query region to be used for queries cached - /// by this template, set the QueryCacheRegion property. - ///

- ///
- /// true if cache queries; otherwise, false. - public abstract bool CacheQueries - { - get; - set; - } - - /// - /// Gets or sets the name of the cache region for queries executed by this template. - /// - /// - /// If this is specified, it will be applied to all IQuery and ICriteria objects - /// created by this template (including all queries through find methods). - ///

The cache region will not take effect unless queries created by this - /// template are configured to be cached via the CacheQueries property. - ///

- ///
- /// The query cache region. - public abstract string QueryCacheRegion - { - get; - set; - } - - /// - /// Gets or sets the fetch size for this HibernateTemplate. - /// - /// The size of the fetch. - /// This is important for processing - /// large result sets: Setting this higher than the default value will increase - /// processing speed at the cost of memory consumption; setting this lower can - /// avoid transferring row data that will never be read by the application. - ///

Default is 0, indicating to use the driver's default.

- ///
- public abstract int FetchSize - { - get; - set; - } - - /// - /// Gets or sets the maximum number of rows for this HibernateTemplate. - /// - /// The max results. - /// - /// This is important - /// for processing subsets of large result sets, avoiding to read and hold - /// the entire result set in the database or in the ADO.NET driver if we're - /// never interested in the entire result in the first place (for example, - /// when performing searches that might return a large number of matches). - ///

Default is 0, indicating to use the driver's default.

- ///
- public abstract int MaxResults - { - get; - set; - } - - /// - /// Set the ADO.NET exception translator for this instance. - /// Applied to System.Data.Common.DbException (or provider specific exception type - /// in .NET 1.1) thrown by callback code, be it direct - /// DbException or wrapped Hibernate ADOExceptions. - ///

The default exception translator is either a ErrorCodeExceptionTranslator - /// if a DbProvider is available, or a FalbackExceptionTranslator otherwise - ///

- ///
- /// The ADO exception translator. - public abstract IAdoExceptionTranslator AdoExceptionTranslator - { - set; - get; - } - - /// - /// Gets a Session for use by this template. - /// - /// The session. - /// - /// - Returns a new Session in case of "alwaysUseNewSession" (using the same ADO.NET connection as a transaction Session, if applicable) - /// - a pre-bound Session in case of "AllowCreate" is set to false (not the default) - /// - or a pre-bound Session or new Session if no transactional or other pre-bound Session exists. - /// - protected ISession Session - { - get - { - if (AlwaysUseNewSession) - { - return SessionFactoryUtils.GetNewSession(SessionFactory, EntityInterceptor); - } - else if (!AllowCreate) - { - return SessionFactoryUtils.GetSession(SessionFactory, false); - } - else - { - return SessionFactoryUtils.GetSession( - SessionFactory, EntityInterceptor, AdoExceptionTranslator); - } - - } - - } - - /// - /// Apply the flush mode that's been specified for this accessor - /// to the given Session. - /// - /// The current Hibernate Session. - /// if set to true - /// if executing within an existing transaction. - /// - /// the previous flush mode to restore after the operation, - /// or null if none - /// - protected FlushModeHolder ApplyFlushMode(ISession session, bool existingTransaction) - { - if (TemplateFlushMode == TemplateFlushMode.Never) - { - if (existingTransaction) - { - FlushMode previousFlushMode = session.FlushMode; - if (previousFlushMode != FlushMode.Never) - { - session.FlushMode = FlushMode.Never; - return new FlushModeHolder(previousFlushMode); - } - } - else - { - session.FlushMode = FlushMode.Never; - } - } - else if (TemplateFlushMode == TemplateFlushMode.Eager) - { - if (existingTransaction) - { - FlushMode previousFlushMode = session.FlushMode; - if (previousFlushMode != FlushMode.Auto) - { - session.FlushMode = FlushMode.Auto; - return new FlushModeHolder(previousFlushMode); - } - } - else - { - // rely on default FlushMode.AUTO - } - } - else if (TemplateFlushMode == TemplateFlushMode.Commit) - { - if (existingTransaction) - { - FlushMode previousFlushMode = session.FlushMode; - if (previousFlushMode == FlushMode.Auto) - { - session.FlushMode = FlushMode.Commit; - return new FlushModeHolder(previousFlushMode); - } - } - else - { - session.FlushMode = FlushMode.Commit; - } - } - return new FlushModeHolder(); - } - - - /// - /// Flush the given Hibernate Session if necessary. - /// - /// The current Hibernate Session. - /// if set to true - /// if executing within an existing transaction. - protected void FlushIfNecessary(ISession session, bool existingTransaction) - { - if (TemplateFlushMode == TemplateFlushMode.Eager || - (!existingTransaction && TemplateFlushMode != TemplateFlushMode.Never)) - { - log.LogDebug("Eagerly flushing Hibernate session"); - session.Flush(); - } - } - - /// - /// Convert the given HibernateException to an appropriate exception from the - /// org.springframework.dao hierarchy. Will automatically detect - /// wrapped ADO.NET Exceptions and convert them accordingly. - /// - /// HibernateException that occured. - /// - /// The corresponding DataAccessException instance - /// - /// - /// The default implementation delegates to SessionFactoryUtils - /// and convertAdoAccessException. Can be overridden in subclasses. - /// - public virtual DataAccessException ConvertHibernateAccessException(HibernateException ex) - { - if (ex is ADOException) - { - return ConvertAdoAccessException((ADOException) ex); - } - return SessionFactoryUtils.ConvertHibernateAccessException(ex); - } - - /// - /// Converts the ADO.NET access exception to an appropriate exception from the - /// org.springframework.dao hierarchy. Can be overridden in subclasses. - /// - /// ADOException that occured, wrapping underlying ADO.NET exception. - /// - /// the corresponding DataAccessException instance - /// - protected virtual DataAccessException ConvertAdoAccessException(ADOException ex) - { - return SessionFactoryUtils.ConvertAdoAccessException(AdoExceptionTranslator, ex); - } - - /// - /// Converts the ADO.NET access exception to an appropriate exception from the - /// org.springframework.dao hierarchy. Can be overridden in subclasses. - /// - /// - /// - /// Note that a direct SQLException can just occur when callback code - /// performs direct ADO.NET access via ISession.Connection(). - /// - /// - /// The ADO.NET exception. - /// The corresponding DataAccessException instance - protected virtual DataAccessException ConvertAdoAccessException(Exception ex) - { - return AdoExceptionTranslator.Translate("Hibernate operation", null, ex); - } - - - /// - /// Prepare the given IQuery object, applying cache settings and/or - /// a transaction timeout. - /// - /// The query object to prepare. - public virtual void PrepareQuery(IQuery queryObject) - { - if (CacheQueries) - { - queryObject.SetCacheable(true); - if (QueryCacheRegion != null) - { - queryObject.SetCacheRegion(QueryCacheRegion); - } - } - - if (FetchSize > 0) - { - AbstractQueryImpl queryImpl = queryObject as AbstractQueryImpl; - if (queryImpl != null) - { - queryImpl.SetFetchSize(FetchSize); - } - else - { - log.LogWarning("Could not set FetchSize for IQuery. Expected Implemention to be of type AbstractQueryImpl"); - } - } - - if (MaxResults > 0) - { - queryObject.SetMaxResults(MaxResults); - } - - SessionFactoryUtils.ApplyTransactionTimeout(queryObject, SessionFactory); - - } - - /// - /// Apply the given name parameter to the given Query object. - /// - /// The query object. - /// Name of the parameter - /// The value of the parameter - /// The NHibernate type of the parameter (or null if none specified) - public virtual void ApplyNamedParameterToQuery(IQuery queryObject, string paramName, object value, IType type) - { - - if (value is ICollection) - { - if (type != null) - { - queryObject.SetParameterList(paramName, (ICollection)value, type); - } - else - { - queryObject.SetParameterList(paramName, (ICollection)value); - } - } - else if (value is Object[]) - { - - //TODO investigate support for this conversion. - if (type != null) - { - queryObject.SetParameterList(paramName, (Object[])value, type); - } - else - { - queryObject.SetParameterList(paramName, (Object[])value); - } - } - else - { - if (type != null) - { - queryObject.SetParameter(paramName, value, type); - } - else - { - queryObject.SetParameter(paramName, value); - } - } - } - - /// - /// Prepare the given Criteria object, applying cache settings and/or - /// a transaction timeout. - /// - /// - /// Note that for NHibernate 1.2 this only works if the - /// implementation is of the type CriteriaImpl, which should generally - /// be the case. The SetFetchSize method is not available on the - /// ICriteria interface - /// - /// This is a no-op for NHibernate 1.0.x since - /// the SetFetchSize method is not on the ICriteria interface and - /// the implementation class is has internal access. - /// - /// To remove the method completely for Spring's NHibernate 1.0 - /// support while reusing code for NHibernate 1.2 would not be - /// possible. So now this ineffectual operation is left in tact for - /// NHibernate 1.0.2 support. - /// - /// The criteria object to prepare - public void PrepareCriteria(ICriteria criteria) - { - if (CacheQueries) - { - criteria.SetCacheable(true); - if (QueryCacheRegion != null) - { - criteria.SetCacheRegion(QueryCacheRegion); - } - } - - - - if (FetchSize > 0) - { - //TODO see if we can optimize performance. - //CriteriaImpl is internal in NH 1.0.x - object[] args = new object[] { FetchSize }; - try - { - Type t = TypeResolutionUtils.ResolveType("NHibernate.Impl.CriteriaImpl, NHibernate"); - if (t != null) - { - t.InvokeMember("SetFetchSize", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance - | BindingFlags.InvokeMethod, - null, criteria, args); - } - } - catch (TypeLoadException e) - { - log.LogWarning(e, "Can't set FetchSize for ICriteria"); - } - } - - if (MaxResults > 0) - { - criteria.SetMaxResults(MaxResults); - } - - SessionFactoryUtils.ApplyTransactionTimeout(criteria, SessionFactory); - } - - private void InitCriteriaType() - { - - try - { - criteriaType = TypeResolutionUtils.ResolveType("Hibernate.Impl.CriteriaImpl, NHibernate"); - } - catch (TypeLoadException e) - { - log.LogWarning(e, "CriteriaImpl not available. FetchSize can not be set on ICriteria objects"); - } - } - - /// - /// Ensure SessionFactory is not null - /// - /// If SessionFactory property is null. - public virtual void AfterPropertiesSet() - { - if (SessionFactory == null) - { - throw new ArgumentException("sessionFactory is required"); - } - } - - /// - /// Helper class to determine if the FlushMode enumeration - /// was changed from its default value - /// - protected class FlushModeHolder - { - /// - /// Gets or sets a value indicating whether the FlushMode - /// property was set.. - /// - /// true if FlushMode was set; otherwise, false. - public bool ModeWasSet - { - get { return modeWasSet; } - set { modeWasSet = value; } - } - - /// - /// Gets or sets the FlushMode. - /// - /// The FlushMode. - public FlushMode Mode - { - get { return flushMode; } - set { flushMode = value; } - } - - private bool modeWasSet = false; - private FlushMode flushMode; - - /// - /// Initializes a new instance of the class. - /// - public FlushModeHolder() - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The flush mode. - public FlushModeHolder(FlushMode mode) - { - Mode = mode; - ModeWasSet = true; - } - - } - } - - internal class CloseSuppressingMethodInterceptor : IMethodInterceptor + /// + /// Initializes a new instance of the class. + /// + public HibernateAccessor() { - private HibernateAccessor hibernateAccessor; + } - public CloseSuppressingMethodInterceptor(HibernateAccessor accessor) - { - hibernateAccessor = accessor; - } + /// + /// Gets or sets if a new Session should be created when no transactional Session + /// can be found for the current thread. + /// + /// + /// true if allowed to create non-transaction session; + /// otherwise, false. + /// + /// + ///

HibernateTemplate is aware of a corresponding Session bound to the + /// current thread, for example when using HibernateTransactionManager. + /// If allowCreate is true, a new non-transactional Session will be created + /// if none found, which needs to be closed at the end of the operation. + /// If false, an InvalidOperationException will get thrown in this case. + ///

+ ///
+ public abstract bool AllowCreate + { + get; + set; + } - public object Invoke(IMethodInvocation invocation) + /// + /// Gets or sets a value indicating whether to always + /// use a new Hibernate Session for this template. + /// + /// true if always use new session; otherwise, false. + /// + ///

+ /// Default is "false"; if activated, all operations on this template will + /// work on a new NHibernate ISession even in case of a pre-bound ISession + /// (for example, within a transaction). + ///

+ ///

Within a transaction, a new NHibernate ISession used by this template + /// will participate in the transaction through using the same ADO.NET + /// Connection. In such a scenario, multiple Sessions will participate + /// in the same database transaction. + ///

+ ///

Turn this on for operations that are supposed to always execute + /// independently, without side effects caused by a shared NHibernate ISession. + ///

+ ///
+ public abstract bool AlwaysUseNewSession + { + get; + set; + } + + /// + /// Set whether to expose the native Hibernate Session to IHibernateCallback + /// code. Default is "false": a Session proxy will be returned, + /// suppressing close calls and automatically applying + /// query cache settings and transaction timeouts. + /// + /// true if expose native session; otherwise, false. + public abstract bool ExposeNativeSession + { + get; + set; + } + + /// + /// Gets or sets the template flush mode. + /// + /// + /// Default is Auto. Will get applied to any new ISession + /// created by the template. + /// + /// The template flush mode. + public abstract TemplateFlushMode TemplateFlushMode + { + get; + set; + } + + /// + /// Gets or sets the entity interceptor that allows to inspect and change + /// property values before writing to and reading from the database. + /// + /// + /// Will get applied to any new ISession created by this object. + ///

Such an interceptor can either be set at the ISessionFactory level, + /// i.e. on LocalSessionFactoryObject, or at the ISession level, i.e. on + /// HibernateTemplate, HibernateInterceptor, and HibernateTransactionManager. + /// It's preferable to set it on LocalSessionFactoryObject or HibernateTransactionManager + /// to avoid repeated configuration and guarantee consistent behavior in transactions. + ///

+ ///
+ /// The interceptor. + public abstract IInterceptor EntityInterceptor + { + get; + set; + } + + /// + /// Set the object name of a Hibernate entity interceptor that allows to inspect + /// and change property values before writing to and reading from the database. + /// + /// + /// Will get applied to any new Session created by this transaction manager. + ///

Requires the object factory to be known, to be able to resolve the object + /// name to an interceptor instance on session creation. Typically used for + /// prototype interceptors, i.e. a new interceptor instance per session. + ///

+ ///

Can also be used for shared interceptor instances, but it is recommended + /// to set the interceptor reference directly in such a scenario. + ///

+ ///
+ /// The name of the entity interceptor in the object factory/application context. + public abstract string EntityInterceptorObjectName + { + set; + } + + /// + /// Gets or sets the session factory that should be used to create + /// NHibernate ISessions. + /// + /// The session factory. + public abstract ISessionFactory SessionFactory + { + get; + set; + } + + /// + /// Set the object factory instance. + /// + /// The object factory instance. + public abstract IObjectFactory ObjectFactory + { + set; + } + + /// + /// Gets or sets a value indicating whether to + /// cache all queries executed by this template. + /// + /// + /// If this is true, all IQuery and ICriteria objects created by + /// this template will be marked as cacheable (including all + /// queries through find methods). + ///

To specify the query region to be used for queries cached + /// by this template, set the QueryCacheRegion property. + ///

+ ///
+ /// true if cache queries; otherwise, false. + public abstract bool CacheQueries + { + get; + set; + } + + /// + /// Gets or sets the name of the cache region for queries executed by this template. + /// + /// + /// If this is specified, it will be applied to all IQuery and ICriteria objects + /// created by this template (including all queries through find methods). + ///

The cache region will not take effect unless queries created by this + /// template are configured to be cached via the CacheQueries property. + ///

+ ///
+ /// The query cache region. + public abstract string QueryCacheRegion + { + get; + set; + } + + /// + /// Gets or sets the fetch size for this HibernateTemplate. + /// + /// The size of the fetch. + /// This is important for processing + /// large result sets: Setting this higher than the default value will increase + /// processing speed at the cost of memory consumption; setting this lower can + /// avoid transferring row data that will never be read by the application. + ///

Default is 0, indicating to use the driver's default.

+ ///
+ public abstract int FetchSize + { + get; + set; + } + + /// + /// Gets or sets the maximum number of rows for this HibernateTemplate. + /// + /// The max results. + /// + /// This is important + /// for processing subsets of large result sets, avoiding to read and hold + /// the entire result set in the database or in the ADO.NET driver if we're + /// never interested in the entire result in the first place (for example, + /// when performing searches that might return a large number of matches). + ///

Default is 0, indicating to use the driver's default.

+ ///
+ public abstract int MaxResults + { + get; + set; + } + + /// + /// Set the ADO.NET exception translator for this instance. + /// Applied to System.Data.Common.DbException (or provider specific exception type + /// in .NET 1.1) thrown by callback code, be it direct + /// DbException or wrapped Hibernate ADOExceptions. + ///

The default exception translator is either a ErrorCodeExceptionTranslator + /// if a DbProvider is available, or a FalbackExceptionTranslator otherwise + ///

+ ///
+ /// The ADO exception translator. + public abstract IAdoExceptionTranslator AdoExceptionTranslator + { + set; + get; + } + + /// + /// Gets a Session for use by this template. + /// + /// The session. + /// + /// - Returns a new Session in case of "alwaysUseNewSession" (using the same ADO.NET connection as a transaction Session, if applicable) + /// - a pre-bound Session in case of "AllowCreate" is set to false (not the default) + /// - or a pre-bound Session or new Session if no transactional or other pre-bound Session exists. + /// + protected ISession Session + { + get { - //anything special for equals/hashcode? - if (invocation.Method.Name.Equals("Close")) + if (AlwaysUseNewSession) { - return null; + return SessionFactoryUtils.GetNewSession(SessionFactory, EntityInterceptor); + } + else if (!AllowCreate) + { + return SessionFactoryUtils.GetSession(SessionFactory, false); } else { - object retValue = invocation.Proceed(); - if (retValue is IQuery) - { - hibernateAccessor.PrepareQuery((IQuery)retValue); - } - if (retValue is ICriteria) - { - hibernateAccessor.PrepareCriteria((ICriteria)retValue); - } - return retValue; + return SessionFactoryUtils.GetSession( + SessionFactory, EntityInterceptor, AdoExceptionTranslator); } } } + + /// + /// Apply the flush mode that's been specified for this accessor + /// to the given Session. + /// + /// The current Hibernate Session. + /// if set to true + /// if executing within an existing transaction. + /// + /// the previous flush mode to restore after the operation, + /// or null if none + /// + protected FlushModeHolder ApplyFlushMode(ISession session, bool existingTransaction) + { + if (TemplateFlushMode == TemplateFlushMode.Never) + { + if (existingTransaction) + { + FlushMode previousFlushMode = session.FlushMode; + if (previousFlushMode != FlushMode.Never) + { + session.FlushMode = FlushMode.Never; + return new FlushModeHolder(previousFlushMode); + } + } + else + { + session.FlushMode = FlushMode.Never; + } + } + else if (TemplateFlushMode == TemplateFlushMode.Eager) + { + if (existingTransaction) + { + FlushMode previousFlushMode = session.FlushMode; + if (previousFlushMode != FlushMode.Auto) + { + session.FlushMode = FlushMode.Auto; + return new FlushModeHolder(previousFlushMode); + } + } + else + { + // rely on default FlushMode.AUTO + } + } + else if (TemplateFlushMode == TemplateFlushMode.Commit) + { + if (existingTransaction) + { + FlushMode previousFlushMode = session.FlushMode; + if (previousFlushMode == FlushMode.Auto) + { + session.FlushMode = FlushMode.Commit; + return new FlushModeHolder(previousFlushMode); + } + } + else + { + session.FlushMode = FlushMode.Commit; + } + } + + return new FlushModeHolder(); + } + + /// + /// Flush the given Hibernate Session if necessary. + /// + /// The current Hibernate Session. + /// if set to true + /// if executing within an existing transaction. + protected void FlushIfNecessary(ISession session, bool existingTransaction) + { + if (TemplateFlushMode == TemplateFlushMode.Eager || + (!existingTransaction && TemplateFlushMode != TemplateFlushMode.Never)) + { + log.LogDebug("Eagerly flushing Hibernate session"); + session.Flush(); + } + } + + /// + /// Convert the given HibernateException to an appropriate exception from the + /// org.springframework.dao hierarchy. Will automatically detect + /// wrapped ADO.NET Exceptions and convert them accordingly. + /// + /// HibernateException that occured. + /// + /// The corresponding DataAccessException instance + /// + /// + /// The default implementation delegates to SessionFactoryUtils + /// and convertAdoAccessException. Can be overridden in subclasses. + /// + public virtual DataAccessException ConvertHibernateAccessException(HibernateException ex) + { + if (ex is ADOException) + { + return ConvertAdoAccessException((ADOException) ex); + } + + return SessionFactoryUtils.ConvertHibernateAccessException(ex); + } + + /// + /// Converts the ADO.NET access exception to an appropriate exception from the + /// org.springframework.dao hierarchy. Can be overridden in subclasses. + /// + /// ADOException that occured, wrapping underlying ADO.NET exception. + /// + /// the corresponding DataAccessException instance + /// + protected virtual DataAccessException ConvertAdoAccessException(ADOException ex) + { + return SessionFactoryUtils.ConvertAdoAccessException(AdoExceptionTranslator, ex); + } + + /// + /// Converts the ADO.NET access exception to an appropriate exception from the + /// org.springframework.dao hierarchy. Can be overridden in subclasses. + /// + /// + /// + /// Note that a direct SQLException can just occur when callback code + /// performs direct ADO.NET access via ISession.Connection(). + /// + /// + /// The ADO.NET exception. + /// The corresponding DataAccessException instance + protected virtual DataAccessException ConvertAdoAccessException(Exception ex) + { + return AdoExceptionTranslator.Translate("Hibernate operation", null, ex); + } + + /// + /// Prepare the given IQuery object, applying cache settings and/or + /// a transaction timeout. + /// + /// The query object to prepare. + public virtual void PrepareQuery(IQuery queryObject) + { + if (CacheQueries) + { + queryObject.SetCacheable(true); + if (QueryCacheRegion != null) + { + queryObject.SetCacheRegion(QueryCacheRegion); + } + } + + if (FetchSize > 0) + { + AbstractQueryImpl queryImpl = queryObject as AbstractQueryImpl; + if (queryImpl != null) + { + queryImpl.SetFetchSize(FetchSize); + } + else + { + log.LogWarning("Could not set FetchSize for IQuery. Expected Implemention to be of type AbstractQueryImpl"); + } + } + + if (MaxResults > 0) + { + queryObject.SetMaxResults(MaxResults); + } + + SessionFactoryUtils.ApplyTransactionTimeout(queryObject, SessionFactory); + } + + /// + /// Apply the given name parameter to the given Query object. + /// + /// The query object. + /// Name of the parameter + /// The value of the parameter + /// The NHibernate type of the parameter (or null if none specified) + public virtual void ApplyNamedParameterToQuery(IQuery queryObject, string paramName, object value, IType type) + { + if (value is ICollection) + { + if (type != null) + { + queryObject.SetParameterList(paramName, (ICollection) value, type); + } + else + { + queryObject.SetParameterList(paramName, (ICollection) value); + } + } + else if (value is Object[]) + { + //TODO investigate support for this conversion. + if (type != null) + { + queryObject.SetParameterList(paramName, (Object[]) value, type); + } + else + { + queryObject.SetParameterList(paramName, (Object[]) value); + } + } + else + { + if (type != null) + { + queryObject.SetParameter(paramName, value, type); + } + else + { + queryObject.SetParameter(paramName, value); + } + } + } + + /// + /// Prepare the given Criteria object, applying cache settings and/or + /// a transaction timeout. + /// + /// + /// Note that for NHibernate 1.2 this only works if the + /// implementation is of the type CriteriaImpl, which should generally + /// be the case. The SetFetchSize method is not available on the + /// ICriteria interface + /// + /// This is a no-op for NHibernate 1.0.x since + /// the SetFetchSize method is not on the ICriteria interface and + /// the implementation class is has internal access. + /// + /// To remove the method completely for Spring's NHibernate 1.0 + /// support while reusing code for NHibernate 1.2 would not be + /// possible. So now this ineffectual operation is left in tact for + /// NHibernate 1.0.2 support. + /// + /// The criteria object to prepare + public void PrepareCriteria(ICriteria criteria) + { + if (CacheQueries) + { + criteria.SetCacheable(true); + if (QueryCacheRegion != null) + { + criteria.SetCacheRegion(QueryCacheRegion); + } + } + + if (FetchSize > 0) + { + //TODO see if we can optimize performance. + //CriteriaImpl is internal in NH 1.0.x + object[] args = new object[] { FetchSize }; + try + { + Type t = TypeResolutionUtils.ResolveType("NHibernate.Impl.CriteriaImpl, NHibernate"); + if (t != null) + { + t.InvokeMember("SetFetchSize", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance + | BindingFlags.InvokeMethod, + null, criteria, args); + } + } + catch (TypeLoadException e) + { + log.LogWarning(e, "Can't set FetchSize for ICriteria"); + } + } + + if (MaxResults > 0) + { + criteria.SetMaxResults(MaxResults); + } + + SessionFactoryUtils.ApplyTransactionTimeout(criteria, SessionFactory); + } + + private void InitCriteriaType() + { + try + { + criteriaType = TypeResolutionUtils.ResolveType("Hibernate.Impl.CriteriaImpl, NHibernate"); + } + catch (TypeLoadException e) + { + log.LogWarning(e, "CriteriaImpl not available. FetchSize can not be set on ICriteria objects"); + } + } + + /// + /// Ensure SessionFactory is not null + /// + /// If SessionFactory property is null. + public virtual void AfterPropertiesSet() + { + if (SessionFactory == null) + { + throw new ArgumentException("sessionFactory is required"); + } + } + + /// + /// Helper class to determine if the FlushMode enumeration + /// was changed from its default value + /// + protected class FlushModeHolder + { + /// + /// Gets or sets a value indicating whether the FlushMode + /// property was set.. + /// + /// true if FlushMode was set; otherwise, false. + public bool ModeWasSet + { + get { return modeWasSet; } + set { modeWasSet = value; } + } + + /// + /// Gets or sets the FlushMode. + /// + /// The FlushMode. + public FlushMode Mode + { + get { return flushMode; } + set { flushMode = value; } + } + + private bool modeWasSet = false; + private FlushMode flushMode; + + /// + /// Initializes a new instance of the class. + /// + public FlushModeHolder() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The flush mode. + public FlushModeHolder(FlushMode mode) + { + Mode = mode; + ModeWasSet = true; + } + } +} + +internal class CloseSuppressingMethodInterceptor : IMethodInterceptor +{ + private HibernateAccessor hibernateAccessor; + + public CloseSuppressingMethodInterceptor(HibernateAccessor accessor) + { + hibernateAccessor = accessor; + } + + public object Invoke(IMethodInvocation invocation) + { + //anything special for equals/hashcode? + if (invocation.Method.Name.Equals("Close")) + { + return null; + } + else + { + object retValue = invocation.Proceed(); + if (retValue is IQuery) + { + hibernateAccessor.PrepareQuery((IQuery) retValue); + } + + if (retValue is ICriteria) + { + hibernateAccessor.PrepareCriteria((ICriteria) retValue); + } + + return retValue; + } + } } diff --git a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/HibernateAdoException.cs b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/HibernateAdoException.cs index d7804062..a4c9d388 100644 --- a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/HibernateAdoException.cs +++ b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/HibernateAdoException.cs @@ -1,12 +1,12 @@ /* * Copyright � 2002-2011 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. @@ -18,66 +18,65 @@ using System.Runtime.Serialization; using NHibernate; using Spring.Dao; -namespace Spring.Data.NHibernate +namespace Spring.Data.NHibernate; + +/// +/// Hibernate-specific subclass of UncategorizedDataAccessException, +/// for ADO.NET exceptions that Hibernate rethrew and could not be +/// mapped into the DAO exception heirarchy. +/// +/// Mark Pollack (.NET) +[Serializable] +public class HibernateAdoException : UncategorizedDataAccessException { /// - /// Hibernate-specific subclass of UncategorizedDataAccessException, - /// for ADO.NET exceptions that Hibernate rethrew and could not be - /// mapped into the DAO exception heirarchy. + /// Initializes a new instance of the class. /// - /// Mark Pollack (.NET) - [Serializable] - public class HibernateAdoException : UncategorizedDataAccessException + public HibernateAdoException() : base() { - /// - /// Initializes a new instance of the class. - /// - public HibernateAdoException() : base() - { - } + } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - public HibernateAdoException(string message) : base(message) - { - } + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + public HibernateAdoException(string message) : base(message) + { + } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception from the underlying data access API - ADO.NET - /// - public HibernateAdoException(string message, ADOException rootCause) : base(message, rootCause) - { - } + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception from the underlying data access API - ADO.NET + /// + public HibernateAdoException(string message, ADOException rootCause) : base(message, rootCause) + { + } - /// - /// Creates a new instance of the HibernateSystemException class with the specified message - /// and root cause. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception that is being wrapped. - /// - public HibernateAdoException(string message, Exception rootCause) : base(message, rootCause) - { - } + /// + /// Creates a new instance of the HibernateSystemException class with the specified message + /// and root cause. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception that is being wrapped. + /// + public HibernateAdoException(string message, Exception rootCause) : base(message, rootCause) + { + } - /// - protected HibernateAdoException(SerializationInfo info, StreamingContext context) : base(info, context) - { - } + /// + protected HibernateAdoException(SerializationInfo info, StreamingContext context) : base(info, context) + { } } diff --git a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/HibernateDelegate.cs b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/HibernateDelegate.cs index b5eaa2c0..a3517faf 100644 --- a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/HibernateDelegate.cs +++ b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/HibernateDelegate.cs @@ -1,12 +1,12 @@ /* - * Copyright © 2002-2011 the original author or authors. - * + * Copyright � 2002-2011 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. @@ -16,19 +16,18 @@ using NHibernate; -namespace Spring.Data.NHibernate -{ - /// - /// Gets called by HibernateTemplate with an active - /// Hibernate Session. Does not need to care about activating or closing - /// the Session, or handling transactions. - /// - /// - ///

- /// Allows for returning a result object created within the callback, i.e. - /// a domain object or a collection of domain objects. Note that there's - /// special support for single step actions: see HibernateTemplate.find etc. - ///

- ///
- public delegate object HibernateDelegate(ISession session); -} +namespace Spring.Data.NHibernate; + +/// +/// Gets called by HibernateTemplate with an active +/// Hibernate Session. Does not need to care about activating or closing +/// the Session, or handling transactions. +/// +/// +///

+/// Allows for returning a result object created within the callback, i.e. +/// a domain object or a collection of domain objects. Note that there's +/// special support for single step actions: see HibernateTemplate.find etc. +///

+///
+public delegate object HibernateDelegate(ISession session); diff --git a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/HibernateObjectRetrievalFailureException.cs b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/HibernateObjectRetrievalFailureException.cs index 0578968f..eef96eaf 100644 --- a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/HibernateObjectRetrievalFailureException.cs +++ b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/HibernateObjectRetrievalFailureException.cs @@ -1,12 +1,12 @@ /* * Copyright � 2002-2011 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. @@ -18,93 +18,92 @@ using System.Runtime.Serialization; using NHibernate; using Spring.Dao; -namespace Spring.Data.NHibernate +namespace Spring.Data.NHibernate; + +/// +/// Hibernate-specific subclass of ObjectRetrievalFailureException. +/// +/// +/// Converts Hibernate's UnresolvableObjectException, ObjectNotFoundException, +/// ObjectDeletedException, and WrongClassException. +/// +/// Mark Pollack (.NET) +/// $Id: HibernateObjectRetrievalFailureException.cs,v 1.1 2008/04/07 20:12:53 lahma Exp $ +[Serializable] +public class HibernateObjectRetrievalFailureException : ObjectRetrievalFailureException { /// - /// Hibernate-specific subclass of ObjectRetrievalFailureException. - /// - /// - /// Converts Hibernate's UnresolvableObjectException, ObjectNotFoundException, - /// ObjectDeletedException, and WrongClassException. - /// - /// Mark Pollack (.NET) - /// $Id: HibernateObjectRetrievalFailureException.cs,v 1.1 2008/04/07 20:12:53 lahma Exp $ - [Serializable] - public class HibernateObjectRetrievalFailureException : ObjectRetrievalFailureException + /// Initializes a new instance of the class. + ///
+ public HibernateObjectRetrievalFailureException() { - /// - /// Initializes a new instance of the class. - /// - public HibernateObjectRetrievalFailureException() - { - } + } - /// - /// Initializes a new instance of the class. - /// - /// The message. - public HibernateObjectRetrievalFailureException(string message) - : base(message) - { - } + /// + /// Initializes a new instance of the class. + /// + /// The message. + public HibernateObjectRetrievalFailureException(string message) + : base(message) + { + } - /// - /// Initializes a new instance of the class. - /// - /// The ex. - public HibernateObjectRetrievalFailureException(UnresolvableObjectException ex) : base(ex.PersistentClass, - ex.Identifier, ex.Message, ex) - { - } + /// + /// Initializes a new instance of the class. + /// + /// The ex. + public HibernateObjectRetrievalFailureException(UnresolvableObjectException ex) : base(ex.PersistentClass, + ex.Identifier, ex.Message, ex) + { + } - /// - /// Initializes a new instance of the class. - /// - /// The ex. - public HibernateObjectRetrievalFailureException(ObjectNotFoundException ex) : base(ex.PersistentClass, - ex.Identifier, ex.Message, ex) + /// + /// Initializes a new instance of the class. + /// + /// The ex. + public HibernateObjectRetrievalFailureException(ObjectNotFoundException ex) : base(ex.PersistentClass, + ex.Identifier, ex.Message, ex) - { - } + { + } - /// - /// Initializes a new instance of the class. - /// - /// The ex. - public HibernateObjectRetrievalFailureException(ObjectDeletedException ex) : base(ex.PersistentClass, - ex.Identifier, ex.Message, ex) - { - } + /// + /// Initializes a new instance of the class. + /// + /// The ex. + public HibernateObjectRetrievalFailureException(ObjectDeletedException ex) : base(ex.PersistentClass, + ex.Identifier, ex.Message, ex) + { + } - //TODO investigate WrongClassException.Type as equivalent to ex.PersistentClass - /// - /// Initializes a new instance of the class. - /// - /// The ex. - public HibernateObjectRetrievalFailureException(WrongClassException ex) : base(ex.EntityName, ex.Identifier, - ex.Message, ex) - { - } + //TODO investigate WrongClassException.Type as equivalent to ex.PersistentClass + /// + /// Initializes a new instance of the class. + /// + /// The ex. + public HibernateObjectRetrievalFailureException(WrongClassException ex) : base(ex.EntityName, ex.Identifier, + ex.Message, ex) + { + } - /// - /// Creates a new instance of the HibernateObjectRetrievalFailureException class with the specified message - /// and root cause. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception that is being wrapped. - /// - public HibernateObjectRetrievalFailureException(string message, Exception rootCause) - : base(message, rootCause) - { - } + /// + /// Creates a new instance of the HibernateObjectRetrievalFailureException class with the specified message + /// and root cause. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception that is being wrapped. + /// + public HibernateObjectRetrievalFailureException(string message, Exception rootCause) + : base(message, rootCause) + { + } - /// - protected HibernateObjectRetrievalFailureException( - SerializationInfo info, StreamingContext context) : base(info, context) - { - } + /// + protected HibernateObjectRetrievalFailureException( + SerializationInfo info, StreamingContext context) : base(info, context) + { } } diff --git a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/HibernateOptimisticLockingFailureException.cs b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/HibernateOptimisticLockingFailureException.cs index 1dd18184..fd6ff213 100644 --- a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/HibernateOptimisticLockingFailureException.cs +++ b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/HibernateOptimisticLockingFailureException.cs @@ -18,74 +18,73 @@ using System.Runtime.Serialization; using NHibernate; using Spring.Dao; -namespace Spring.Data.NHibernate +namespace Spring.Data.NHibernate; + +/// +/// Hibernate-specific subclass of ObjectOptimisticLockingFailureException. +/// +/// +/// Converts Hibernate's StaleObjectStateException. +/// +/// Mark Pollack (.NET) +/// $Id: HibernateOptimisticLockingFailureException.cs,v 1.2 2008/04/23 11:41:41 lahma Exp $ +/// +[Serializable] +public class HibernateOptimisticLockingFailureException : ObjectOptimisticLockingFailureException { /// - /// Hibernate-specific subclass of ObjectOptimisticLockingFailureException. + /// Initializes a new instance of the class. /// - /// - /// Converts Hibernate's StaleObjectStateException. - /// - /// Mark Pollack (.NET) - /// $Id: HibernateOptimisticLockingFailureException.cs,v 1.2 2008/04/23 11:41:41 lahma Exp $ - /// - [Serializable] - public class HibernateOptimisticLockingFailureException : ObjectOptimisticLockingFailureException + public HibernateOptimisticLockingFailureException() { - /// - /// Initializes a new instance of the class. - /// - public HibernateOptimisticLockingFailureException() - { - } + } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - public HibernateOptimisticLockingFailureException(string message) : base(message) - { - } + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + public HibernateOptimisticLockingFailureException(string message) : base(message) + { + } - /// - /// Initializes a new instance of the class. - /// - /// The ex. - public HibernateOptimisticLockingFailureException(StaleObjectStateException ex) : base(ex.EntityName, - ex.Identifier, ex.Message, ex) - { - } + /// + /// Initializes a new instance of the class. + /// + /// The ex. + public HibernateOptimisticLockingFailureException(StaleObjectStateException ex) : base(ex.EntityName, + ex.Identifier, ex.Message, ex) + { + } - /// - /// Initializes a new instance of the class. - /// - /// The StaleStateException. - public HibernateOptimisticLockingFailureException(StaleStateException ex) : base(ex.Message, ex) - { - } + /// + /// Initializes a new instance of the class. + /// + /// The StaleStateException. + public HibernateOptimisticLockingFailureException(StaleStateException ex) : base(ex.Message, ex) + { + } - /// - /// Creates a new instance of the HibernateOptimisticLockingFailureException class with the specified message - /// and root cause. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception that is being wrapped. - /// - public HibernateOptimisticLockingFailureException(string message, Exception rootCause) - : base(message, rootCause) - { - } + /// + /// Creates a new instance of the HibernateOptimisticLockingFailureException class with the specified message + /// and root cause. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception that is being wrapped. + /// + public HibernateOptimisticLockingFailureException(string message, Exception rootCause) + : base(message, rootCause) + { + } - /// - protected HibernateOptimisticLockingFailureException(SerializationInfo info, StreamingContext context) : base( - info, context) - { - } + /// + protected HibernateOptimisticLockingFailureException(SerializationInfo info, StreamingContext context) : base( + info, context) + { } } diff --git a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/HibernateQueryException.cs b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/HibernateQueryException.cs index 8edd266f..a90d9f58 100644 --- a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/HibernateQueryException.cs +++ b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/HibernateQueryException.cs @@ -1,12 +1,12 @@ /* * Copyright � 2002-2011 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. @@ -18,69 +18,68 @@ using System.Runtime.Serialization; using NHibernate; using Spring.Dao; -namespace Spring.Data.NHibernate +namespace Spring.Data.NHibernate; + +/// +/// Hibernate-specific subclass of InvalidDataAccessResourceUsageException, +/// thrown on invalid HQL query syntax. +/// +/// Mark Pollack (.NET) +[Serializable] +public class HibernateQueryException : InvalidDataAccessResourceUsageException { /// - /// Hibernate-specific subclass of InvalidDataAccessResourceUsageException, - /// thrown on invalid HQL query syntax. + /// Initializes a new instance of the class. /// - /// Mark Pollack (.NET) - [Serializable] - public class HibernateQueryException : InvalidDataAccessResourceUsageException + public HibernateQueryException() { - /// - /// Initializes a new instance of the class. - /// - public HibernateQueryException() - { - } + } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - public HibernateQueryException(string message) : base(message) - { - } + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + public HibernateQueryException(string message) : base(message) + { + } - /// - /// Initializes a new instance of the class. - /// - /// The ex. - public HibernateQueryException(QueryException ex) : base(ex.Message, ex) - { - } + /// + /// Initializes a new instance of the class. + /// + /// The ex. + public HibernateQueryException(QueryException ex) : base(ex.Message, ex) + { + } - /// - /// Creates a new instance of the HibernateQueryException class with the specified message - /// and root cause. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception that is being wrapped. - /// - public HibernateQueryException(string message, Exception rootCause) - : base(message, rootCause) - { - } + /// + /// Creates a new instance of the HibernateQueryException class with the specified message + /// and root cause. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception that is being wrapped. + /// + public HibernateQueryException(string message, Exception rootCause) + : base(message, rootCause) + { + } - /// - /// Gets the query string that was invalid. - /// - /// The query string that was invalid. - public string QueryString - { - get { return ((QueryException) this.InnerException).QueryString; } - } + /// + /// Gets the query string that was invalid. + /// + /// The query string that was invalid. + public string QueryString + { + get { return ((QueryException) this.InnerException).QueryString; } + } - /// - protected HibernateQueryException(SerializationInfo info, StreamingContext context) : base(info, context) - { - } + /// + protected HibernateQueryException(SerializationInfo info, StreamingContext context) : base(info, context) + { } } diff --git a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/HibernateSystemException.cs b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/HibernateSystemException.cs index 48ba0fb0..2325bf94 100644 --- a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/HibernateSystemException.cs +++ b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/HibernateSystemException.cs @@ -1,12 +1,12 @@ /* * Copyright � 2002-2011 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. @@ -18,57 +18,56 @@ using System.Runtime.Serialization; using NHibernate; using Spring.Dao; -namespace Spring.Data.NHibernate +namespace Spring.Data.NHibernate; + +/// +/// Hibernate-specific subclass of UncategorizedDataAccessException, +/// for Hibernate system errors that do not match any concrete +/// Spring.Dao exceptions. +/// +/// Mark Pollack (.NET) +[Serializable] +public class HibernateSystemException : UncategorizedDataAccessException { /// - /// Hibernate-specific subclass of UncategorizedDataAccessException, - /// for Hibernate system errors that do not match any concrete - /// Spring.Dao exceptions. + /// Initializes a new instance of the class. /// - /// Mark Pollack (.NET) - [Serializable] - public class HibernateSystemException : UncategorizedDataAccessException + public HibernateSystemException() { - /// - /// Initializes a new instance of the class. - /// - public HibernateSystemException() - { - } + } - /// - /// Initializes a new instance of the class. - /// - /// The message. - public HibernateSystemException(string message) : base(message) - { - } + /// + /// Initializes a new instance of the class. + /// + /// The message. + public HibernateSystemException(string message) : base(message) + { + } - /// - /// Creates a new instance of the HibernateSystemException class with the specified message - /// and root cause. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception that is being wrapped. - /// - public HibernateSystemException(string message, Exception rootCause) : base(message, rootCause) - { - } + /// + /// Creates a new instance of the HibernateSystemException class with the specified message + /// and root cause. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception that is being wrapped. + /// + public HibernateSystemException(string message, Exception rootCause) : base(message, rootCause) + { + } - /// - /// Initializes a new instance of the class. - /// - /// The cause. - public HibernateSystemException(HibernateException cause) : base(cause != null ? cause.Message : null, cause) - { - } + /// + /// Initializes a new instance of the class. + /// + /// The cause. + public HibernateSystemException(HibernateException cause) : base(cause != null ? cause.Message : null, cause) + { + } - /// - protected HibernateSystemException(SerializationInfo info, StreamingContext context) : base(info, context) - { - } + /// + protected HibernateSystemException(SerializationInfo info, StreamingContext context) : base(info, context) + { } } diff --git a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/HibernateTemplate.cs b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/HibernateTemplate.cs index 98f619f2..e3ce44f9 100644 --- a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/HibernateTemplate.cs +++ b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/HibernateTemplate.cs @@ -1,12 +1,12 @@ /* * Copyright © 2002-2011 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. @@ -19,2106 +19,2120 @@ using Microsoft.Extensions.Logging; using Spring.Aop.Framework; using Spring.Data.Common; using Spring.Data.Support; - using IInterceptor = NHibernate.IInterceptor; - using NHibernate; using NHibernate.Type; - using Spring.Dao; using Spring.Objects.Factory; -namespace Spring.Data.NHibernate +namespace Spring.Data.NHibernate; + +/// +/// Helper class that simplifies NHibernate data access code +/// +/// +///

Typically used to implement data access or business logic services that +/// use NHibernate within their implementation but are Hibernate-agnostic in their +/// interface. The latter or code calling the latter only have to deal with +/// domain objects.

+/// +///

The central method is Execute supporting Hibernate access code +/// implementing the HibernateCallback interface. It provides NHibernate Session +/// handling such that neither the IHibernateCallback implementation nor the calling +/// code needs to explicitly care about retrieving/closing NHibernate Sessions, +/// or handling Session lifecycle exceptions. For typical single step actions, +/// there are various convenience methods (Find, Load, SaveOrUpdate, Delete). +///

+/// +///

Can be used within a service implementation via direct instantiation +/// with a ISessionFactory reference, or get prepared in an application context +/// and given to services as an object reference. Note: The ISessionFactory should +/// always be configured as an object in the application context, in the first case +/// given to the service directly, in the second case to the prepared template. +///

+/// +///

This class can be considered as direct alternative to working with the raw +/// Hibernate Session API (through SessionFactoryUtils.Session). +///

+/// +///

LocalSessionFactoryObject is the preferred way of obtaining a reference +/// to a specific NHibernate ISessionFactory. +///

+///
+/// Mark Pollack (.NET) +public class HibernateTemplate : HibernateAccessor, IHibernateOperations { /// - /// Helper class that simplifies NHibernate data access code + /// The instance for this class. /// + private readonly ILogger log = LogManager.GetLogger(); + + private bool checkWriteOperations = true; + + private bool exposeNativeSession = false; + + private bool alwaysUseNewSession = false; + private int maxResults = 0; + private TemplateFlushMode templateFlushMode = TemplateFlushMode.Auto; + private bool allowCreate = true; + private ISessionFactory sessionFactory; + private object entityInterceptor; + private IObjectFactory objectFactory; + private bool cacheQueries = false; + private string queryCacheRegion; + private int fetchSize = 0; + + private IAdoExceptionTranslator adoExceptionTranslator; + + private readonly object syncRoot = new object(); + private ProxyFactory sessionProxyFactory; + + /// + /// Initializes a new instance of the class. + /// + public HibernateTemplate() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The default for creating a new non-transactional + /// session when no transactional Session can be found for the current thread + /// is set to true. + /// The session factory to create sessions. + public HibernateTemplate(ISessionFactory sessionFactory) + { + SessionFactory = sessionFactory; + AfterPropertiesSet(); + } + + /// + /// Initializes a new instance of the class. + /// + /// The session factory to create sessions. + /// if set to true allow creation + /// of a new non-transactional when no transactional Session can be found + /// for the current thread. + public HibernateTemplate(ISessionFactory sessionFactory, bool allowCreate) + { + SessionFactory = sessionFactory; + AllowCreate = allowCreate; + AfterPropertiesSet(); + } + + /// + /// Gets or sets if a new Session should be created when no transactional Session + /// can be found for the current thread. + /// + /// + /// true if allowed to create non-transaction session; + /// otherwise, false. + /// /// - ///

Typically used to implement data access or business logic services that - /// use NHibernate within their implementation but are Hibernate-agnostic in their - /// interface. The latter or code calling the latter only have to deal with - /// domain objects.

- /// - ///

The central method is Execute supporting Hibernate access code - /// implementing the HibernateCallback interface. It provides NHibernate Session - /// handling such that neither the IHibernateCallback implementation nor the calling - /// code needs to explicitly care about retrieving/closing NHibernate Sessions, - /// or handling Session lifecycle exceptions. For typical single step actions, - /// there are various convenience methods (Find, Load, SaveOrUpdate, Delete). - ///

- /// - ///

Can be used within a service implementation via direct instantiation - /// with a ISessionFactory reference, or get prepared in an application context - /// and given to services as an object reference. Note: The ISessionFactory should - /// always be configured as an object in the application context, in the first case - /// given to the service directly, in the second case to the prepared template. - ///

- /// - ///

This class can be considered as direct alternative to working with the raw - /// Hibernate Session API (through SessionFactoryUtils.Session). - ///

- /// - ///

LocalSessionFactoryObject is the preferred way of obtaining a reference - /// to a specific NHibernate ISessionFactory. + ///

HibernateTemplate is aware of a corresponding Session bound to the + /// current thread, for example when using HibernateTransactionManager. + /// If allowCreate is true, a new non-transactional Session will be created + /// if none found, which needs to be closed at the end of the operation. + /// If false, an InvalidOperationException will get thrown in this case. ///

///
- /// Mark Pollack (.NET) - public class HibernateTemplate : HibernateAccessor, IHibernateOperations + public override bool AllowCreate { - /// - /// The instance for this class. - /// - private readonly ILogger log = LogManager.GetLogger(); + get { return allowCreate; } + set { allowCreate = value; } + } - private bool checkWriteOperations = true; + /// + /// Gets or sets a value indicating whether to always + /// use a new Hibernate Session for this template. + /// + /// true if always use new session; otherwise, false. + /// + ///

+ /// Default is "false"; if activated, all operations on this template will + /// work on a new NHibernate ISession even in case of a pre-bound ISession + /// (for example, within a transaction). + ///

+ ///

Within a transaction, a new NHibernate ISession used by this template + /// will participate in the transaction through using the same ADO.NET + /// Connection. In such a scenario, multiple Sessions will participate + /// in the same database transaction. + ///

+ ///

Turn this on for operations that are supposed to always execute + /// independently, without side effects caused by a shared NHibernate ISession. + ///

+ ///
+ public override bool AlwaysUseNewSession + { + get { return alwaysUseNewSession; } + set { alwaysUseNewSession = value; } + } - private bool exposeNativeSession = false; + /// + /// Gets or sets the template flush mode. + /// + /// + /// Default is Auto. Will get applied to any new ISession + /// created by the template. + /// + /// The template flush mode. + public override TemplateFlushMode TemplateFlushMode + { + get { return templateFlushMode; } + set { templateFlushMode = value; } + } - private bool alwaysUseNewSession = false; - private int maxResults = 0; - private TemplateFlushMode templateFlushMode = TemplateFlushMode.Auto; - private bool allowCreate = true; - private ISessionFactory sessionFactory; - private object entityInterceptor; - private IObjectFactory objectFactory; - private bool cacheQueries = false; - private string queryCacheRegion; - private int fetchSize = 0; - - private IAdoExceptionTranslator adoExceptionTranslator; - - private readonly object syncRoot = new object(); - private ProxyFactory sessionProxyFactory; - - /// - /// Initializes a new instance of the class. - /// - public HibernateTemplate() + /// + /// Gets or sets the entity interceptor that allows to inspect and change + /// property values before writing to and reading from the database. + /// + /// + /// Will get applied to any new ISession created by this object. + ///

Such an interceptor can either be set at the ISessionFactory level, + /// i.e. on LocalSessionFactoryObject, or at the ISession level, i.e. on + /// HibernateTemplate, HibernateInterceptor, and HibernateTransactionManager. + /// It's preferable to set it on LocalSessionFactoryObject or HibernateTransactionManager + /// to avoid repeated configuration and guarantee consistent behavior in transactions. + ///

+ ///
+ /// The interceptor. + /// If object factory is not set and need to retrieve entity interceptor by name. + public override IInterceptor EntityInterceptor + { + get { - } - - /// - /// Initializes a new instance of the class. - /// - /// The default for creating a new non-transactional - /// session when no transactional Session can be found for the current thread - /// is set to true. - /// The session factory to create sessions. - public HibernateTemplate(ISessionFactory sessionFactory) - { - SessionFactory = sessionFactory; - AfterPropertiesSet(); - } - - /// - /// Initializes a new instance of the class. - /// - /// The session factory to create sessions. - /// if set to true allow creation - /// of a new non-transactional when no transactional Session can be found - /// for the current thread. - public HibernateTemplate(ISessionFactory sessionFactory, bool allowCreate) - { - SessionFactory = sessionFactory; - AllowCreate = allowCreate; - AfterPropertiesSet(); - } - - /// - /// Gets or sets if a new Session should be created when no transactional Session - /// can be found for the current thread. - /// - /// - /// true if allowed to create non-transaction session; - /// otherwise, false. - /// - /// - ///

HibernateTemplate is aware of a corresponding Session bound to the - /// current thread, for example when using HibernateTransactionManager. - /// If allowCreate is true, a new non-transactional Session will be created - /// if none found, which needs to be closed at the end of the operation. - /// If false, an InvalidOperationException will get thrown in this case. - ///

- ///
- public override bool AllowCreate - { - get { return allowCreate; } - set { allowCreate = value; } - } - - /// - /// Gets or sets a value indicating whether to always - /// use a new Hibernate Session for this template. - /// - /// true if always use new session; otherwise, false. - /// - ///

- /// Default is "false"; if activated, all operations on this template will - /// work on a new NHibernate ISession even in case of a pre-bound ISession - /// (for example, within a transaction). - ///

- ///

Within a transaction, a new NHibernate ISession used by this template - /// will participate in the transaction through using the same ADO.NET - /// Connection. In such a scenario, multiple Sessions will participate - /// in the same database transaction. - ///

- ///

Turn this on for operations that are supposed to always execute - /// independently, without side effects caused by a shared NHibernate ISession. - ///

- ///
- public override bool AlwaysUseNewSession - { - get { return alwaysUseNewSession; } - set { alwaysUseNewSession = value; } - } - - /// - /// Gets or sets the template flush mode. - /// - /// - /// Default is Auto. Will get applied to any new ISession - /// created by the template. - /// - /// The template flush mode. - public override TemplateFlushMode TemplateFlushMode - { - get { return templateFlushMode; } - set { templateFlushMode = value; } - } - - /// - /// Gets or sets the entity interceptor that allows to inspect and change - /// property values before writing to and reading from the database. - /// - /// - /// Will get applied to any new ISession created by this object. - ///

Such an interceptor can either be set at the ISessionFactory level, - /// i.e. on LocalSessionFactoryObject, or at the ISession level, i.e. on - /// HibernateTemplate, HibernateInterceptor, and HibernateTransactionManager. - /// It's preferable to set it on LocalSessionFactoryObject or HibernateTransactionManager - /// to avoid repeated configuration and guarantee consistent behavior in transactions. - ///

- ///
- /// The interceptor. - /// If object factory is not set and need to retrieve entity interceptor by name. - public override IInterceptor EntityInterceptor - { - get + if (this.entityInterceptor is string) { - if (this.entityInterceptor is string) + if (this.objectFactory == null) { - if (this.objectFactory == null) - { - throw new InvalidOperationException("Cannot get entity interceptor via object name if no object factory set"); - } - return (IInterceptor) this.objectFactory.GetObject((String) this.entityInterceptor, typeof (IInterceptor)); + throw new InvalidOperationException("Cannot get entity interceptor via object name if no object factory set"); } - return (IInterceptor) entityInterceptor; + return (IInterceptor) this.objectFactory.GetObject((String) this.entityInterceptor, typeof(IInterceptor)); } - set { entityInterceptor = value; } - } - /// - /// Gets or sets the name of the cache region for queries executed by this template. - /// - /// - /// If this is specified, it will be applied to all IQuery and ICriteria objects - /// created by this template (including all queries through find methods). - ///

The cache region will not take effect unless queries created by this - /// template are configured to be cached via the CacheQueries property. - ///

- ///
- /// The query cache region. - public override string QueryCacheRegion - { - get { return queryCacheRegion; } - set { queryCacheRegion = value; } + return (IInterceptor) entityInterceptor; } + set { entityInterceptor = value; } + } - /// - /// Gets or sets a value indicating whether to - /// cache all queries executed by this template. - /// - /// - /// If this is true, all IQuery and ICriteria objects created by - /// this template will be marked as cacheable (including all - /// queries through find methods). - ///

To specify the query region to be used for queries cached - /// by this template, set the QueryCacheRegion property. - ///

- ///
- /// true if cache queries; otherwise, false. - public override bool CacheQueries - { - get { return cacheQueries; } - set { cacheQueries = value; } - } + /// + /// Gets or sets the name of the cache region for queries executed by this template. + /// + /// + /// If this is specified, it will be applied to all IQuery and ICriteria objects + /// created by this template (including all queries through find methods). + ///

The cache region will not take effect unless queries created by this + /// template are configured to be cached via the CacheQueries property. + ///

+ ///
+ /// The query cache region. + public override string QueryCacheRegion + { + get { return queryCacheRegion; } + set { queryCacheRegion = value; } + } - /// - /// Gets or sets the maximum number of rows for this HibernateTemplate. - /// - /// The max results. - /// - /// This is important - /// for processing subsets of large result sets, avoiding to read and hold - /// the entire result set in the database or in the ADO.NET driver if we're - /// never interested in the entire result in the first place (for example, - /// when performing searches that might return a large number of matches). - ///

Default is 0, indicating to use the driver's default.

- ///
- public override int MaxResults - { - get { return maxResults; } - set { maxResults = value; } - } + /// + /// Gets or sets a value indicating whether to + /// cache all queries executed by this template. + /// + /// + /// If this is true, all IQuery and ICriteria objects created by + /// this template will be marked as cacheable (including all + /// queries through find methods). + ///

To specify the query region to be used for queries cached + /// by this template, set the QueryCacheRegion property. + ///

+ ///
+ /// true if cache queries; otherwise, false. + public override bool CacheQueries + { + get { return cacheQueries; } + set { cacheQueries = value; } + } - /// - /// Set whether to expose the native Hibernate Session to IHibernateCallback - /// code. Default is "false": a Session proxy will be returned, - /// suppressing close calls and automatically applying - /// query cache settings and transaction timeouts. - /// - /// true if expose native session; otherwise, false. - public override bool ExposeNativeSession - { - get { return exposeNativeSession; } - set { exposeNativeSession = value; } - } + /// + /// Gets or sets the maximum number of rows for this HibernateTemplate. + /// + /// The max results. + /// + /// This is important + /// for processing subsets of large result sets, avoiding to read and hold + /// the entire result set in the database or in the ADO.NET driver if we're + /// never interested in the entire result in the first place (for example, + /// when performing searches that might return a large number of matches). + ///

Default is 0, indicating to use the driver's default.

+ ///
+ public override int MaxResults + { + get { return maxResults; } + set { maxResults = value; } + } - /// - /// Gets or sets whether to check that the Hibernate Session is not in read-only mode - /// in case of write operations (save/update/delete). - /// - /// - /// true if check that the Hibernate Session is not in read-only mode - /// in case of write operations; otherwise, false. - /// - /// - /// Default is "true", for fail-fast behavior when attempting write operations - /// within a read-only transaction. Turn this off to allow save/update/delete - /// on a Session with flush mode NEVER. - /// - public virtual bool CheckWriteOperations - { - get { return checkWriteOperations; } - set { checkWriteOperations = value; } - } + /// + /// Set whether to expose the native Hibernate Session to IHibernateCallback + /// code. Default is "false": a Session proxy will be returned, + /// suppressing close calls and automatically applying + /// query cache settings and transaction timeouts. + /// + /// true if expose native session; otherwise, false. + public override bool ExposeNativeSession + { + get { return exposeNativeSession; } + set { exposeNativeSession = value; } + } - /// - /// Set the object name of a Hibernate entity interceptor that allows to inspect - /// and change property values before writing to and reading from the database. - /// - /// - /// Will get applied to any new Session created by this transaction manager. - ///

Requires the object factory to be known, to be able to resolve the object - /// name to an interceptor instance on session creation. Typically used for - /// prototype interceptors, i.e. a new interceptor instance per session. - ///

- ///

Can also be used for shared interceptor instances, but it is recommended - /// to set the interceptor reference directly in such a scenario. - ///

- ///
- /// The name of the entity interceptor in the object factory/application context. - public override string EntityInterceptorObjectName - { - set { this.entityInterceptor = value; } - } + /// + /// Gets or sets whether to check that the Hibernate Session is not in read-only mode + /// in case of write operations (save/update/delete). + /// + /// + /// true if check that the Hibernate Session is not in read-only mode + /// in case of write operations; otherwise, false. + /// + /// + /// Default is "true", for fail-fast behavior when attempting write operations + /// within a read-only transaction. Turn this off to allow save/update/delete + /// on a Session with flush mode NEVER. + /// + public virtual bool CheckWriteOperations + { + get { return checkWriteOperations; } + set { checkWriteOperations = value; } + } - /// - /// Set the object factory instance. - /// - /// The object factory instance - public override IObjectFactory ObjectFactory - { - set { objectFactory = value; } - } + /// + /// Set the object name of a Hibernate entity interceptor that allows to inspect + /// and change property values before writing to and reading from the database. + /// + /// + /// Will get applied to any new Session created by this transaction manager. + ///

Requires the object factory to be known, to be able to resolve the object + /// name to an interceptor instance on session creation. Typically used for + /// prototype interceptors, i.e. a new interceptor instance per session. + ///

+ ///

Can also be used for shared interceptor instances, but it is recommended + /// to set the interceptor reference directly in such a scenario. + ///

+ ///
+ /// The name of the entity interceptor in the object factory/application context. + public override string EntityInterceptorObjectName + { + set { this.entityInterceptor = value; } + } - /// - /// Gets or sets the session factory that should be used to create - /// NHibernate ISessions. - /// - /// The session factory. - public override ISessionFactory SessionFactory - { - get { return sessionFactory; } - set { sessionFactory = value; } - } + /// + /// Set the object factory instance. + /// + /// The object factory instance + public override IObjectFactory ObjectFactory + { + set { objectFactory = value; } + } - /// - /// Gets or sets the fetch size for this HibernateTemplate. - /// - /// The size of the fetch. - /// This is important for processing - /// large result sets: Setting this higher than the default value will increase - /// processing speed at the cost of memory consumption; setting this lower can - /// avoid transferring row data that will never be read by the application. - ///

Default is 0, indicating to use the driver's default.

- ///
- public override int FetchSize - { - get { return fetchSize; } - set { fetchSize = value; } - } + /// + /// Gets or sets the session factory that should be used to create + /// NHibernate ISessions. + /// + /// The session factory. + public override ISessionFactory SessionFactory + { + get { return sessionFactory; } + set { sessionFactory = value; } + } - /// - /// Gets or sets the proxy factory. - /// - /// This may be useful to set if you create many instances of - /// HibernateTemplate and/or HibernateDaoSupport. This allows the same - /// ProxyFactory implementation to be used thereby limiting the - /// number of dynamic proxy types created in the temporary assembly, which - /// are never garbage collected due to .NET runtime semantics. - /// - /// The proxy factory. - public virtual ProxyFactory ProxyFactory - { - get { return sessionProxyFactory; } - set { sessionProxyFactory = value; } - } + /// + /// Gets or sets the fetch size for this HibernateTemplate. + /// + /// The size of the fetch. + /// This is important for processing + /// large result sets: Setting this higher than the default value will increase + /// processing speed at the cost of memory consumption; setting this lower can + /// avoid transferring row data that will never be read by the application. + ///

Default is 0, indicating to use the driver's default.

+ ///
+ public override int FetchSize + { + get { return fetchSize; } + set { fetchSize = value; } + } - /// - /// Set the ADO.NET exception translator for this instance. - /// Applied to System.Data.Common.DbException (or provider specific exception type - /// in .NET 1.1) thrown by callback code, be it direct - /// DbException or wrapped Hibernate ADOExceptions. - ///

The default exception translator is either a ErrorCodeExceptionTranslator - /// if a DbProvider is available, or a FalbackExceptionTranslator otherwise - ///

- ///
- /// The ADO exception translator. - public override IAdoExceptionTranslator AdoExceptionTranslator + /// + /// Gets or sets the proxy factory. + /// + /// This may be useful to set if you create many instances of + /// HibernateTemplate and/or HibernateDaoSupport. This allows the same + /// ProxyFactory implementation to be used thereby limiting the + /// number of dynamic proxy types created in the temporary assembly, which + /// are never garbage collected due to .NET runtime semantics. + /// + /// The proxy factory. + public virtual ProxyFactory ProxyFactory + { + get { return sessionProxyFactory; } + set { sessionProxyFactory = value; } + } + + /// + /// Set the ADO.NET exception translator for this instance. + /// Applied to System.Data.Common.DbException (or provider specific exception type + /// in .NET 1.1) thrown by callback code, be it direct + /// DbException or wrapped Hibernate ADOExceptions. + ///

The default exception translator is either a ErrorCodeExceptionTranslator + /// if a DbProvider is available, or a FalbackExceptionTranslator otherwise + ///

+ ///
+ /// The ADO exception translator. + public override IAdoExceptionTranslator AdoExceptionTranslator + { + set { adoExceptionTranslator = value; } + get { - set { adoExceptionTranslator = value; } - get + if (adoExceptionTranslator == null) { - if (adoExceptionTranslator == null) - { - adoExceptionTranslator = SessionFactoryUtils.NewAdoExceptionTranslator(SessionFactory); - } - return adoExceptionTranslator; + adoExceptionTranslator = SessionFactoryUtils.NewAdoExceptionTranslator(SessionFactory); } + + return adoExceptionTranslator; + } + } + + /// + /// Delegate function that clears the session. + /// + /// The hibernate session. + /// null + protected object ClearAction(ISession session) + { + session.Clear(); + return null; + } + + /// + /// Flush all pending saves, updates and deletes to the database. + /// + /// + /// Only invoke this for selective eager flushing, for example when ADO.NET code + /// needs to see certain changes within the same transaction. Else, it's preferable + /// to rely on auto-flushing at transaction completion. + /// + /// In case of Hibernate errors + public void Flush() + { + Execute(new HibernateDelegate(FlushAction), true); + } + + private object FlushAction(ISession session) + { + session.Flush(); + return null; + } + + /// + /// Return the persistent instance of the given entity type + /// with the given identifier, or null if not found. + /// + /// The type. + /// An identifier of the persistent instance. + /// The persistent instance, or null if not found + /// In case of Hibernate errors + public object Get(Type entityType, object id) + { + return Get(entityType, id, null); + } + + /// + /// Return the persistent instance of the given entity type + /// with the given identifier, or null if not found. + /// Obtains the specified lock mode if the instance exists. + /// + /// The type. + /// The lock mode to obtain. + /// The lock mode. + /// the persistent instance, or null if not found + /// the persistent instance, or null if not found + /// In case of Hibernate errors + public object Get(Type type, object id, LockMode lockMode) + { + return Execute(new GetByTypeHibernateCallback(type, id, lockMode), true); + } + + /// + /// Return the persistent instance of the given entity class + /// with the given identifier, throwing an exception if not found. + /// + /// Type of the entity. + /// An identifier of the persistent instance. + /// The persistent instance + /// If not found + /// In case of Hibernate errors + public object Load(Type entityType, object id) + { + return Load(entityType, id, null); + } + + /// + /// Return the persistent instance of the given entity class + /// with the given identifier, throwing an exception if not found. + /// Obtains the specified lock mode if the instance exists. + /// + /// Type of the entity. + /// An identifier of the persistent instance. + /// The lock mode. + /// The persistent instance + /// If not found + /// In case of Hibernate errors + public object Load(Type entityType, object id, LockMode lockMode) + { + return Execute(new LoadByTypeHibernateCallback(entityType, id, lockMode), true); + } + + /// + /// Load the persistent instance with the given identifier + /// into the given object, throwing an exception if not found. + /// + /// Entity the object (of the target class) to load into. + /// An identifier of the persistent instance. + /// If object not found. + /// In case of Hibernate errors + public void Load(object entity, object id) + { + Execute(new LoadByEntityHibernateCallback(entity, id), true); + } + + /// + /// Return all persistent instances of the given entity class. + /// Note: Use queries or criteria for retrieving a specific subset. + /// + /// Type of the entity. + /// A List containing 0 or more persistent instances + /// In case of Hibernate errors + public IList LoadAll(Type entityType) + { + return (IList) Execute(new LoadAllByTypeHibernateCallback(this, entityType), true); + } + + /// + /// Re-read the state of the given persistent instance. + /// + /// The persistent instance to re-read. + /// In case of Hibernate errors + public void Refresh(object entity) + { + Refresh(entity, null); + } + + /// + /// Re-read the state of the given persistent instance. + /// Obtains the specified lock mode for the instance. + /// + /// The persistent instance to re-read. + /// The lock mode to obtain. + /// In case of Hibernate errors + public void Refresh(object entity, LockMode lockMode) + { + Execute(new RefreshHibernateCallback(entity, lockMode), true); + } + + /// + /// Obtain the specified lock level upon the given object, implicitly + /// checking whether the corresponding database entry still exists + /// (throwing an OptimisticLockingFailureException if not found). + /// + /// The he persistent instance to lock. + /// The lock mode to obtain. + /// If not found + /// In case of Hibernate errors + public void Lock(object entity, LockMode lockMode) + { + Execute(new LockHibernateCallback(entity, lockMode), true); + } + + /// + /// Persist the given transient instance. + /// + /// The transient instance to persist. + /// The generated identifier. + /// In case of Hibernate errors + public object Save(object entity) + { + return Execute(new SaveObjectHibernateCallback(this, entity), true); + } + + /// + /// Persist the given transient instance with the given identifier. + /// + /// The transient instance to persist. + /// The identifier to assign. + /// In case of Hibernate errors + public void Save(object entity, object id) + { + Execute(new SaveObjectWithIdHibernateCallback(this, entity, id), true); + } + + /// + /// Update the given persistent instance. + /// + /// The persistent instance to update. + /// In case of Hibernate errors + public void Update(object entity) + { + Update(entity, null); + } + + /// + /// Update the given persistent instance. + /// Obtains the specified lock mode if the instance exists, implicitly + /// checking whether the corresponding database entry still exists + /// (throwing an OptimisticLockingFailureException if not found). + /// + /// The persistent instance to update. + /// The lock mode to obtain. + /// In case of Hibernate errors + public void Update(object entity, LockMode lockMode) + { + Execute(new UpdateObjectHibernateCallback(this, entity, lockMode), true); + } + + /// + /// Save or update the given persistent instance, + /// according to its id (matching the configured "unsaved-value"?). + /// + /// The persistent instance to save or update + /// (to be associated with the Hibernate Session). + /// In case of Hibernate errors + public void SaveOrUpdate(object entity) + { + Execute(new SaveOrUpdateObjectHibernateCallback(this, entity), true); + } + + /// + /// Save or update all given persistent instances, + /// according to its id (matching the configured "unsaved-value"?). + /// + /// The persistent instances to save or update + /// (to be associated with the Hibernate Session)he entities. + /// In case of Hibernate errors + public void SaveOrUpdateAll(ICollection entities) + { + Execute(new SaveOrUpdateAllHibernateCallback(this, entities), true); + } + + /// + /// Copy the state of the given object onto the persistent object with the same identifier. + /// If there is no persistent instance currently associated with the session, it will be loaded. + /// Return the persistent instance. If the given instance is unsaved, + /// save a copy of and return it as a newly persistent instance. + /// The given instance does not become associated with the session. + /// This operation cascades to associated instances if the association is mapped with cascade="merge". + /// The semantics of this method are defined by JSR-220. + /// + /// The persistent object to merge. + /// (not necessarily to be associated with the Hibernate Session) + /// + /// An updated persistent instance + /// In case of Hibernate errors + public object Merge(object entity) + { + return Execute(new MergeHibernateCallback(this, entity), true); + } + + /// + /// Remove all objects from the Session cache, and cancel all pending saves, + /// updates and deletes. + /// + public void Clear() + { + Execute(new HibernateDelegate(ClearAction), true); + } + + /// + /// Determines whether the given object is in the Session cache. + /// + /// the persistence instance to check. + /// + /// true if session cache contains the specified entity; otherwise, false. + /// + /// In case of Hibernate errors + public bool Contains(object entity) + { + return (bool) Execute(new ContainsHibernateCallback(entity)); + } + + /// + /// Remove the given object from the Session cache. + /// + /// The persistent instance to evict. + /// In case of Hibernate errors + public void Evict(object entity) + { + Execute(new EvictHibernateCallback(entity), true); + } + + /// + /// Delete the given persistent instance. + /// + /// The persistent instance to delete. + /// In case of Hibernate errors + public void Delete(object entity) + { + Delete(entity, null); + } + + /// + /// Delete the given persistent instance. + /// + /// The persistent instance to delete. + /// The lock mode to obtain. + /// + /// Obtains the specified lock mode if the instance exists, implicitly + /// checking whether the corresponding database entry still exists + /// (throwing an OptimisticLockingFailureException if not found). + /// + /// In case of Hibernate errors + public void Delete(object entity, LockMode lockMode) + { + Execute(new DeleteLockModeHibernateCallback(this, entity, lockMode), true); + } + + /// + /// Delete all objects returned by the query. + /// + /// a query expressed in Hibernate's query language. + /// The number of entity instances deleted. + /// In case of Hibernate errors + public int Delete(string queryString) + { + return Delete(queryString, (Object[]) null, (IType[]) null); + } + + /// + /// Delete all objects returned by the query. + /// + /// a query expressed in Hibernate's query language. + /// The value of the parameter. + /// The Hibernate type of the parameter (or null). + /// The number of entity instances deleted. + /// In case of Hibernate errors + public int Delete(string queryString, object value, IType type) + { + return Delete(queryString, new Object[] { value }, new IType[] { type }); + } + + /// + /// Delete all objects returned by the query. + /// + /// a query expressed in Hibernate's query language. + /// The values of the parameters. + /// Hibernate types of the parameters (or null) + /// The number of entity instances deleted. + /// In case of Hibernate errors + /// If length for argument values and types are not equal. + public int Delete(String queryString, Object[] values, IType[] types) + { + if (values != null && types != null && values.Length != types.Length) + { + throw new ArgumentOutOfRangeException("values", "Length of values array must match length of types array"); } - /// - /// Delegate function that clears the session. - /// - /// The hibernate session. - /// null - protected object ClearAction(ISession session) + return (int) Execute(new DeletebyQueryHibernateCallback(this, queryString, values, types), true); + } + + /// + /// Delete all given persistent instances. + /// + /// The persistent instances to delete. + /// + /// This can be combined with any of the find methods to delete by query + /// in two lines of code, similar to Session's delete by query methods. + /// + /// In case of Hibernate errors + public void DeleteAll(ICollection entities) + { + Execute(new DeleteAllHibernateCallback(this, entities), true); + } + + /// + /// Execute the action specified by the given action object within a Session. + /// + /// + /// Application exceptions thrown by the action object get propagated to the + /// caller (can only be unchecked). Hibernate exceptions are transformed into + /// appropriate DAO ones. Allows for returning a result object, i.e. a domain + /// object or a collection of domain objects. + ///

Note: Callback code is not supposed to handle transactions itself! + /// Use an appropriate transaction manager like HibernateTransactionManager. + /// Generally, callback code must not touch any Session lifecycle methods, + /// like close, disconnect, or reconnect, to let the template do its work. + ///

+ ///
+ /// The delegate callback object that specifies the Hibernate action. + /// a result object returned by the action, or null + /// + /// In case of Hibernate errors + public object Execute(HibernateDelegate del) + { + return Execute(new ExecuteHibernateCallbackUsingDelegate(del)); + } + + /// + /// Execute the action specified by the delegate within a Session. + /// + /// The HibernateDelegate that specifies the action + /// to perform. + /// if set to true expose the native hibernate session to + /// callback code. + /// a result object returned by the action, or null + /// + public object Execute(HibernateDelegate del, bool exposeNativeSession) + { + return Execute(new ExecuteHibernateCallbackUsingDelegate(del), true); + } + + /// + /// Execute the action specified by the given action object within a Session. + /// + /// The callback object that specifies the Hibernate action. + /// + /// a result object returned by the action, or null + /// + /// + /// Application exceptions thrown by the action object get propagated to the + /// caller (can only be unchecked). Hibernate exceptions are transformed into + /// appropriate DAO ones. Allows for returning a result object, i.e. a domain + /// object or a collection of domain objects. + ///

Note: Callback code is not supposed to handle transactions itself! + /// Use an appropriate transaction manager like HibernateTransactionManager. + /// Generally, callback code must not touch any Session lifecycle methods, + /// like close, disconnect, or reconnect, to let the template do its work. + ///

+ ///
+ /// In case of Hibernate errors + public object Execute(IHibernateCallback action) + { + return Execute(action, ExposeNativeSession); + } + + /// + /// Execute the specified action assuming that the result object is a List. + /// + /// + /// This is a convenience method for executing Hibernate find calls or + /// queries within an action. + /// + /// The calback object that specifies the Hibernate action. + /// A IList returned by the action, or null + /// + /// In case of Hibernate errors + public IList ExecuteFind(IHibernateCallback action) + { + Object result = Execute(action, ExposeNativeSession); + if (result != null && !(result is IList)) { - session.Clear(); - return null; + throw new InvalidDataAccessApiUsageException( + "Result object returned from HibernateCallback isn't a List: [" + result + "]"); } - /// - /// Flush all pending saves, updates and deletes to the database. - /// - /// - /// Only invoke this for selective eager flushing, for example when ADO.NET code - /// needs to see certain changes within the same transaction. Else, it's preferable - /// to rely on auto-flushing at transaction completion. - /// - /// In case of Hibernate errors - public void Flush() - { - Execute(new HibernateDelegate(FlushAction), true); - } + return (IList) result; + } - private object FlushAction(ISession session) - { - session.Flush(); - return null; - } + /// + /// Execute the action specified by the given action object within a Session. + /// + /// callback object that specifies the Hibernate action. + /// if set to true expose the native hibernate session to + /// callback code. + /// + /// a result object returned by the action, or null + /// + public object Execute(IHibernateCallback action, bool exposeNativeSession) + { + ISession session = Session; - /// - /// Return the persistent instance of the given entity type - /// with the given identifier, or null if not found. - /// - /// The type. - /// An identifier of the persistent instance. - /// The persistent instance, or null if not found - /// In case of Hibernate errors - public object Get(Type entityType, object id) + bool existingTransaction = SessionFactoryUtils.IsSessionTransactional(session, SessionFactory); + if (existingTransaction) { - return Get(entityType, id, null); - } - - /// - /// Return the persistent instance of the given entity type - /// with the given identifier, or null if not found. - /// Obtains the specified lock mode if the instance exists. - /// - /// The type. - /// The lock mode to obtain. - /// The lock mode. - /// the persistent instance, or null if not found - /// the persistent instance, or null if not found - /// In case of Hibernate errors - public object Get(Type type, object id, LockMode lockMode) - { - return Execute(new GetByTypeHibernateCallback(type, id, lockMode), true); - } - - /// - /// Return the persistent instance of the given entity class - /// with the given identifier, throwing an exception if not found. - /// - /// Type of the entity. - /// An identifier of the persistent instance. - /// The persistent instance - /// If not found - /// In case of Hibernate errors - public object Load(Type entityType, object id) - { - return Load(entityType, id, null); - } - - /// - /// Return the persistent instance of the given entity class - /// with the given identifier, throwing an exception if not found. - /// Obtains the specified lock mode if the instance exists. - /// - /// Type of the entity. - /// An identifier of the persistent instance. - /// The lock mode. - /// The persistent instance - /// If not found - /// In case of Hibernate errors - public object Load(Type entityType, object id, LockMode lockMode) - { - return Execute(new LoadByTypeHibernateCallback(entityType, id, lockMode), true); - } - - /// - /// Load the persistent instance with the given identifier - /// into the given object, throwing an exception if not found. - /// - /// Entity the object (of the target class) to load into. - /// An identifier of the persistent instance. - /// If object not found. - /// In case of Hibernate errors - public void Load(object entity, object id) - { - Execute(new LoadByEntityHibernateCallback(entity, id), true); - } - - /// - /// Return all persistent instances of the given entity class. - /// Note: Use queries or criteria for retrieving a specific subset. - /// - /// Type of the entity. - /// A List containing 0 or more persistent instances - /// In case of Hibernate errors - public IList LoadAll(Type entityType) - { - return (IList) Execute(new LoadAllByTypeHibernateCallback(this, entityType), true); - } - - /// - /// Re-read the state of the given persistent instance. - /// - /// The persistent instance to re-read. - /// In case of Hibernate errors - public void Refresh(object entity) - { - Refresh(entity, null); - } - - /// - /// Re-read the state of the given persistent instance. - /// Obtains the specified lock mode for the instance. - /// - /// The persistent instance to re-read. - /// The lock mode to obtain. - /// In case of Hibernate errors - public void Refresh(object entity, LockMode lockMode) - { - Execute(new RefreshHibernateCallback(entity, lockMode), true); - } - - /// - /// Obtain the specified lock level upon the given object, implicitly - /// checking whether the corresponding database entry still exists - /// (throwing an OptimisticLockingFailureException if not found). - /// - /// The he persistent instance to lock. - /// The lock mode to obtain. - /// If not found - /// In case of Hibernate errors - public void Lock(object entity, LockMode lockMode) - { - Execute(new LockHibernateCallback(entity, lockMode), true); - } - - /// - /// Persist the given transient instance. - /// - /// The transient instance to persist. - /// The generated identifier. - /// In case of Hibernate errors - public object Save(object entity) - { - return Execute(new SaveObjectHibernateCallback(this, entity), true); - } - - /// - /// Persist the given transient instance with the given identifier. - /// - /// The transient instance to persist. - /// The identifier to assign. - /// In case of Hibernate errors - public void Save(object entity, object id) - { - Execute(new SaveObjectWithIdHibernateCallback(this, entity, id), true); - } - - /// - /// Update the given persistent instance. - /// - /// The persistent instance to update. - /// In case of Hibernate errors - public void Update(object entity) - { - Update(entity, null); - } - - /// - /// Update the given persistent instance. - /// Obtains the specified lock mode if the instance exists, implicitly - /// checking whether the corresponding database entry still exists - /// (throwing an OptimisticLockingFailureException if not found). - /// - /// The persistent instance to update. - /// The lock mode to obtain. - /// In case of Hibernate errors - public void Update(object entity, LockMode lockMode) - { - Execute(new UpdateObjectHibernateCallback(this, entity, lockMode), true); - } - - /// - /// Save or update the given persistent instance, - /// according to its id (matching the configured "unsaved-value"?). - /// - /// The persistent instance to save or update - /// (to be associated with the Hibernate Session). - /// In case of Hibernate errors - public void SaveOrUpdate(object entity) - { - Execute(new SaveOrUpdateObjectHibernateCallback(this, entity), true); - } - - /// - /// Save or update all given persistent instances, - /// according to its id (matching the configured "unsaved-value"?). - /// - /// The persistent instances to save or update - /// (to be associated with the Hibernate Session)he entities. - /// In case of Hibernate errors - public void SaveOrUpdateAll(ICollection entities) - { - Execute(new SaveOrUpdateAllHibernateCallback(this, entities), true); - } - - /// - /// Copy the state of the given object onto the persistent object with the same identifier. - /// If there is no persistent instance currently associated with the session, it will be loaded. - /// Return the persistent instance. If the given instance is unsaved, - /// save a copy of and return it as a newly persistent instance. - /// The given instance does not become associated with the session. - /// This operation cascades to associated instances if the association is mapped with cascade="merge". - /// The semantics of this method are defined by JSR-220. - /// - /// The persistent object to merge. - /// (not necessarily to be associated with the Hibernate Session) - /// - /// An updated persistent instance - /// In case of Hibernate errors - public object Merge(object entity) - { - return Execute(new MergeHibernateCallback(this, entity), true); - } - - /// - /// Remove all objects from the Session cache, and cancel all pending saves, - /// updates and deletes. - /// - public void Clear() - { - Execute(new HibernateDelegate(ClearAction), true); - } - - /// - /// Determines whether the given object is in the Session cache. - /// - /// the persistence instance to check. - /// - /// true if session cache contains the specified entity; otherwise, false. - /// - /// In case of Hibernate errors - public bool Contains(object entity) - { - return (bool) Execute(new ContainsHibernateCallback(entity)); - } - - /// - /// Remove the given object from the Session cache. - /// - /// The persistent instance to evict. - /// In case of Hibernate errors - public void Evict(object entity) - { - Execute(new EvictHibernateCallback(entity), true); - } - - /// - /// Delete the given persistent instance. - /// - /// The persistent instance to delete. - /// In case of Hibernate errors - public void Delete(object entity) - { - Delete(entity, null); - } - - /// - /// Delete the given persistent instance. - /// - /// The persistent instance to delete. - /// The lock mode to obtain. - /// - /// Obtains the specified lock mode if the instance exists, implicitly - /// checking whether the corresponding database entry still exists - /// (throwing an OptimisticLockingFailureException if not found). - /// - /// In case of Hibernate errors - public void Delete(object entity, LockMode lockMode) - { - Execute(new DeleteLockModeHibernateCallback(this, entity, lockMode), true); - } - - /// - /// Delete all objects returned by the query. - /// - /// a query expressed in Hibernate's query language. - /// The number of entity instances deleted. - /// In case of Hibernate errors - public int Delete(string queryString) - { - return Delete(queryString, (Object[]) null, (IType[]) null); - } - - /// - /// Delete all objects returned by the query. - /// - /// a query expressed in Hibernate's query language. - /// The value of the parameter. - /// The Hibernate type of the parameter (or null). - /// The number of entity instances deleted. - /// In case of Hibernate errors - public int Delete(string queryString, object value, IType type) - { - return Delete(queryString, new Object[] {value}, new IType[] {type}); - } - - /// - /// Delete all objects returned by the query. - /// - /// a query expressed in Hibernate's query language. - /// The values of the parameters. - /// Hibernate types of the parameters (or null) - /// The number of entity instances deleted. - /// In case of Hibernate errors - /// If length for argument values and types are not equal. - public int Delete(String queryString, Object[] values, IType[] types) - { - if (values != null && types != null && values.Length != types.Length) + if (log.IsEnabled(LogLevel.Debug)) { - throw new ArgumentOutOfRangeException("values", "Length of values array must match length of types array"); + log.LogDebug("Found thread-bound Session for HibernateTemplate"); } - return (int) Execute(new DeletebyQueryHibernateCallback(this, queryString, values, types), true); } - /// - /// Delete all given persistent instances. - /// - /// The persistent instances to delete. - /// - /// This can be combined with any of the find methods to delete by query - /// in two lines of code, similar to Session's delete by query methods. - /// - /// In case of Hibernate errors - public void DeleteAll(ICollection entities) + FlushModeHolder previousFlushModeHolder = new FlushModeHolder(); + try { - Execute(new DeleteAllHibernateCallback(this, entities), true); + previousFlushModeHolder = ApplyFlushMode(session, existingTransaction); + ISession sessionToExpose = (exposeNativeSession ? session : CreateSessionProxy(session)); + Object result = action.DoInHibernate(sessionToExpose); + FlushIfNecessary(session, existingTransaction); + return result; } - - /// - /// Execute the action specified by the given action object within a Session. - /// - /// - /// Application exceptions thrown by the action object get propagated to the - /// caller (can only be unchecked). Hibernate exceptions are transformed into - /// appropriate DAO ones. Allows for returning a result object, i.e. a domain - /// object or a collection of domain objects. - ///

Note: Callback code is not supposed to handle transactions itself! - /// Use an appropriate transaction manager like HibernateTransactionManager. - /// Generally, callback code must not touch any Session lifecycle methods, - /// like close, disconnect, or reconnect, to let the template do its work. - ///

- ///
- /// The delegate callback object that specifies the Hibernate action. - /// a result object returned by the action, or null - /// - /// In case of Hibernate errors - public object Execute(HibernateDelegate del) + catch (ADOException ex) { - return Execute(new ExecuteHibernateCallbackUsingDelegate(del)); - } - - /// - /// Execute the action specified by the delegate within a Session. - /// - /// The HibernateDelegate that specifies the action - /// to perform. - /// if set to true expose the native hibernate session to - /// callback code. - /// a result object returned by the action, or null - /// - public object Execute(HibernateDelegate del, bool exposeNativeSession) - { - return Execute(new ExecuteHibernateCallbackUsingDelegate(del), true); - } - - /// - /// Execute the action specified by the given action object within a Session. - /// - /// The callback object that specifies the Hibernate action. - /// - /// a result object returned by the action, or null - /// - /// - /// Application exceptions thrown by the action object get propagated to the - /// caller (can only be unchecked). Hibernate exceptions are transformed into - /// appropriate DAO ones. Allows for returning a result object, i.e. a domain - /// object or a collection of domain objects. - ///

Note: Callback code is not supposed to handle transactions itself! - /// Use an appropriate transaction manager like HibernateTransactionManager. - /// Generally, callback code must not touch any Session lifecycle methods, - /// like close, disconnect, or reconnect, to let the template do its work. - ///

- ///
- /// In case of Hibernate errors - public object Execute(IHibernateCallback action) - { - return Execute(action, ExposeNativeSession); - } - - /// - /// Execute the specified action assuming that the result object is a List. - /// - /// - /// This is a convenience method for executing Hibernate find calls or - /// queries within an action. - /// - /// The calback object that specifies the Hibernate action. - /// A IList returned by the action, or null - /// - /// In case of Hibernate errors - public IList ExecuteFind(IHibernateCallback action) - { - Object result = Execute(action, ExposeNativeSession); - if (result != null && !(result is IList)) + IDbProvider dbProvider = SessionFactoryUtils.GetDbProvider(SessionFactory); + if (dbProvider != null && dbProvider.IsDataAccessException(ex.InnerException)) { - throw new InvalidDataAccessApiUsageException( - "Result object returned from HibernateCallback isn't a List: [" + result + "]"); + throw ConvertAdoAccessException(ex); + } + else + { + throw new HibernateSystemException(ex); } - return (IList) result; } - - /// - /// Execute the action specified by the given action object within a Session. - /// - /// callback object that specifies the Hibernate action. - /// if set to true expose the native hibernate session to - /// callback code. - /// - /// a result object returned by the action, or null - /// - public object Execute(IHibernateCallback action, bool exposeNativeSession) + catch (HibernateException ex) + { + throw ConvertHibernateAccessException(ex); + } + catch (Exception ex) + { + IDbProvider dbProvider = SessionFactoryUtils.GetDbProvider(SessionFactory); + if (dbProvider != null && dbProvider.IsDataAccessException(ex)) + { + throw ConvertAdoAccessException(ex); + } + else + { + // Callback code throw application exception or other non DB related exception. + throw; + } + } + finally { - ISession session = Session; - - bool existingTransaction = SessionFactoryUtils.IsSessionTransactional(session, SessionFactory); if (existingTransaction) { if (log.IsEnabled(LogLevel.Debug)) { - log.LogDebug("Found thread-bound Session for HibernateTemplate"); + log.LogDebug("Not closing pre-bound Hibernate Session after HibernateTemplate"); + } + + if (previousFlushModeHolder.ModeWasSet) + { + session.FlushMode = previousFlushModeHolder.Mode; } } - - FlushModeHolder previousFlushModeHolder = new FlushModeHolder(); - try + else { - previousFlushModeHolder = ApplyFlushMode(session, existingTransaction); - ISession sessionToExpose = (exposeNativeSession ? session : CreateSessionProxy(session)); - Object result = action.DoInHibernate(sessionToExpose); - FlushIfNecessary(session, existingTransaction); - return result; - } - catch (ADOException ex) - { - IDbProvider dbProvider = SessionFactoryUtils.GetDbProvider(SessionFactory); - if (dbProvider != null && dbProvider.IsDataAccessException(ex.InnerException)) + // Never use deferred close for an explicitly new Session. + if (AlwaysUseNewSession) { - throw ConvertAdoAccessException(ex); + SessionFactoryUtils.CloseSession(session); } else { - throw new HibernateSystemException(ex); - } - } - catch (HibernateException ex) - { - throw ConvertHibernateAccessException(ex); - } - catch (Exception ex) - { - IDbProvider dbProvider = SessionFactoryUtils.GetDbProvider(SessionFactory); - if (dbProvider != null && dbProvider.IsDataAccessException(ex)) - { - throw ConvertAdoAccessException(ex); - } - else - { - // Callback code throw application exception or other non DB related exception. - throw; - } - } - finally - { - if (existingTransaction) - { - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug("Not closing pre-bound Hibernate Session after HibernateTemplate"); - } - if (previousFlushModeHolder.ModeWasSet) - { - session.FlushMode = previousFlushModeHolder.Mode; - } - } - else - { - // Never use deferred close for an explicitly new Session. - if (AlwaysUseNewSession) - { - SessionFactoryUtils.CloseSession(session); - } - else - { - SessionFactoryUtils.CloseSessionOrRegisterDeferredClose(session, SessionFactory); - } + SessionFactoryUtils.CloseSessionOrRegisterDeferredClose(session, SessionFactory); } } } + } - /// - /// Execute a query for persistent instances. - /// - /// a query expressed in Hibernate's query language - /// - /// a List containing 0 or more persistent instances - /// - /// In case of Hibernate errors - public IList Find(string queryString) + /// + /// Execute a query for persistent instances. + /// + /// a query expressed in Hibernate's query language + /// + /// a List containing 0 or more persistent instances + /// + /// In case of Hibernate errors + public IList Find(string queryString) + { + return Find(queryString, (object[]) null, (IType[]) null); + } + + /// + /// Execute a query for persistent instances, binding + /// one value to a "?" parameter in the query string. + /// + /// a query expressed in Hibernate's query language + /// the value of the parameter + /// + /// a List containing 0 or more persistent instances + /// + /// In case of Hibernate errors + public IList Find(string queryString, object value) + { + return Find(queryString, new object[] { value }, (IType[]) null); + } + + /// + /// Execute a query for persistent instances, binding one value + /// to a "?" parameter of the given type in the query string. + /// + /// a query expressed in Hibernate's query language + /// The value of the parameter. + /// Hibernate type of the parameter (or null) + /// + /// a List containing 0 or more persistent instances + /// + /// In case of Hibernate errors + public IList Find(string queryString, object value, IType type) + { + return Find(queryString, new object[] { value }, new IType[] { type }); + } + + /// + /// Execute a query for persistent instances, binding a + /// number of values to "?" parameters in the query string. + /// + /// a query expressed in Hibernate's query language + /// the values of the parameters + /// a List containing 0 or more persistent instances + /// In case of Hibernate errors + public IList Find(string queryString, object[] values) + { + return Find(queryString, values, (IType[]) null); + } + + /// + /// Execute a query for persistent instances, binding a number of + /// values to "?" parameters of the given types in the query string. + /// + /// A query expressed in Hibernate's query language + /// The values of the parameters + /// Hibernate types of the parameters (or null) + /// + /// a List containing 0 or more persistent instances + /// + /// In case of Hibernate errors + /// If values and types are not null and their lengths are not equal + public IList Find(string queryString, object[] values, IType[] types) + { + if (values != null && types != null && values.Length != types.Length) { - return Find(queryString, (object[]) null, (IType[]) null); + throw new ArgumentException("Length of values array must match length of types array"); } - /// - /// Execute a query for persistent instances, binding - /// one value to a "?" parameter in the query string. - /// - /// a query expressed in Hibernate's query language - /// the value of the parameter - /// - /// a List containing 0 or more persistent instances - /// - /// In case of Hibernate errors - public IList Find(string queryString, object value) + return (IList) Execute(new FindHibernateCallback(this, queryString, values, types), true); + } + + /// + /// Execute a query for persistent instances, binding + /// one value to a named parameter in the query string. + /// + /// The name of a Hibernate query in a mapping file + /// The name of the parameter + /// The value of the parameter + /// a List containing 0 or more persistent instances + /// In case of Hibernate errors + public IList FindByNamedParam(string queryName, string paramName, object value) + { + return FindByNamedParam(queryName, paramName, value, null); + } + + /// + /// Execute a query for persistent instances, binding + /// one value to a named parameter in the query string. + /// + /// The name of a Hibernate query in a mapping file + /// The name of the parameter + /// The value of the parameter + /// Hibernate type of the parameter (or null) + /// A List containing 0 or more persistent instances + /// In case of Hibernate errors + public IList FindByNamedParam(string queryName, string paramName, object value, IType type) + { + return FindByNamedParam(queryName, new string[] { paramName }, new object[] { value }, new IType[] { type }); + } + + /// + /// Execute a query for persistent instances, binding a + /// number of values to named parameters in the query string. + /// + /// A query expressed in Hibernate's query language + /// The names of the parameters + /// The values of the parameters + /// A List containing 0 or more persistent instances + /// In case of Hibernate errors + public IList FindByNamedParam(string queryString, string[] paramNames, object[] values) + { + return FindByNamedParam(queryString, paramNames, values, null); + } + + /// + /// Execute a query for persistent instances, binding a + /// number of values to named parameters in the query string. + /// + /// A query expressed in Hibernate's query language + /// The names of the parameters + /// The values of the parameters + /// Hibernate types of the parameters (or null) + /// A List containing 0 or more persistent instances + /// In case of Hibernate errors + /// If paramNames length is not equal to values length or + /// if paramNames length is not equal to types length (when types is not null) + public IList FindByNamedParam(string queryString, string[] paramNames, object[] values, IType[] types) + { + if (paramNames.Length != values.Length) { - return Find(queryString, new object[] {value}, (IType[]) null); + throw new ArgumentOutOfRangeException("paramNames", "Length of paramNames array must match length of values array"); } - /// - /// Execute a query for persistent instances, binding one value - /// to a "?" parameter of the given type in the query string. - /// - /// a query expressed in Hibernate's query language - /// The value of the parameter. - /// Hibernate type of the parameter (or null) - /// - /// a List containing 0 or more persistent instances - /// - /// In case of Hibernate errors - public IList Find(string queryString, object value, IType type) + if (types != null && paramNames.Length != types.Length) { - return Find(queryString, new object[] {value}, new IType[] {type}); + throw new ArgumentOutOfRangeException("paramNames", "Length of paramNames array must match length of types array"); } - /// - /// Execute a query for persistent instances, binding a - /// number of values to "?" parameters in the query string. - /// - /// a query expressed in Hibernate's query language - /// the values of the parameters - /// a List containing 0 or more persistent instances - /// In case of Hibernate errors - public IList Find(string queryString, object[] values) + return (IList) Execute(new FindByNamedParamHibernateCallback(this, queryString, paramNames, values, types), true); + } + + /// + /// Execute a named query for persistent instances. + /// A named query is defined in a Hibernate mapping file. + /// + /// The name of a Hibernate query in a mapping file + /// A List containing 0 or more persistent instances + /// In case of Hibernate errors + public IList FindByNamedQuery(string queryName) + { + return FindByNamedQuery(queryName, (object[]) null, (IType[]) null); + } + + /// + /// Execute a named query for persistent instances, binding + /// one value to a "?" parameter in the query string. + /// A named query is defined in a Hibernate mapping file. + /// + /// The name of a Hibernate query in a mapping file + /// The value of the parameter + /// A List containing 0 or more persistent instances + /// In case of Hibernate errors + public IList FindByNamedQuery(string queryName, object value) + { + return FindByNamedQuery(queryName, new object[] { value }, (IType[]) null); + } + + /// + /// Execute a named query for persistent instances, binding + /// one value to a "?" parameter in the query string. + /// A named query is defined in a Hibernate mapping file. + /// + /// The name of a Hibernate query in a mapping file + /// The value of the parameter + /// Hibernate type of the parameter (or null) + /// A List containing 0 or more persistent instances + /// In case of Hibernate errors + public IList FindByNamedQuery(string queryName, object value, IType type) + { + return FindByNamedQuery(queryName, new object[] { value }, new IType[] { type }); + } + + /// + /// Execute a named query for persistent instances, binding a + /// number of values to "?" parameters in the query string. + /// A named query is defined in a Hibernate mapping file. + /// + /// The name of a Hibernate query in a mapping file + /// The values of the parameters + /// A List containing 0 or more persistent instances + /// In case of Hibernate errors + public IList FindByNamedQuery(string queryName, object[] values) + { + return FindByNamedQuery(queryName, values, (IType[]) null); + } + + /// + /// Execute a named query for persistent instances, binding a + /// number of values to "?" parameters in the query string. + /// A named query is defined in a Hibernate mapping file. + /// + /// The name of a Hibernate query in a mapping file + /// The values of the parameters + /// Hibernate types of the parameters (or null) + /// A List containing 0 or more persistent instances + /// In case of Hibernate errors + /// If values and types are not null and their lengths differ. + public IList FindByNamedQuery(string queryName, object[] values, IType[] types) + { + if (values != null && types != null && values.Length != types.Length) { - return Find(queryString, values, (IType[]) null); + throw new ArgumentOutOfRangeException("Length of values array must match length of types array"); } - /// - /// Execute a query for persistent instances, binding a number of - /// values to "?" parameters of the given types in the query string. - /// - /// A query expressed in Hibernate's query language - /// The values of the parameters - /// Hibernate types of the parameters (or null) - /// - /// a List containing 0 or more persistent instances - /// - /// In case of Hibernate errors - /// If values and types are not null and their lengths are not equal - public IList Find(string queryString, object[] values, IType[] types) + return (IList) Execute(new FindByNamedQueryHibernateCallback(this, queryName, values, types), true); + } + + /// + /// Execute a named query for persistent instances, binding + /// one value to a named parameter in the query string. + /// A named query is defined in a Hibernate mapping file. + /// + /// The name of a Hibernate query in a mapping file + /// Name of the parameter + /// The value of the parameter + /// A List containing 0 or more persistent instances + /// In case of Hibernate errors + public IList FindByNamedQueryAndNamedParam(string queryName, string paramName, object value) + { + return FindByNamedQueryAndNamedParam(queryName, paramName, value, null); + } + + /// + /// Execute a named query for persistent instances, binding + /// one value to a named parameter in the query string. + /// A named query is defined in a Hibernate mapping file. + /// + /// The name of a Hibernate query in a mapping file + /// Name of the parameter + /// The value of the parameter + /// The Hibernate type of the parameter (or null) + /// A List containing 0 or more persistent instances + public IList FindByNamedQueryAndNamedParam(string queryName, string paramName, object value, IType type) + { + return FindByNamedQueryAndNamedParam( + queryName, new string[] { paramName }, new object[] { value }, new IType[] { type }); + } + + /// + /// Execute a named query for persistent instances, binding + /// number of values to named parameters in the query string. + /// A named query is defined in a Hibernate mapping file. + /// + /// The name of a Hibernate query in a mapping file + /// The names of the parameters + /// The values of the parameters. + /// A List containing 0 or more persistent instances + /// In case of Hibernate errors + public IList FindByNamedQueryAndNamedParam(string queryName, string[] paramNames, object[] values) + { + return FindByNamedQueryAndNamedParam(queryName, paramNames, values, null); + } + + /// + /// Execute a named query for persistent instances, binding + /// number of values to named parameters in the query string. + /// A named query is defined in a Hibernate mapping file. + /// + /// The name of a Hibernate query in a mapping file + /// The names of the parameters + /// The values of the parameters. + /// Hibernate types of the parameters (or null) + /// A List containing 0 or more persistent instances + /// In case of Hibernate errors + /// If paramNames length is not equal to values length or + /// if paramNames length is not equal to types length (when types is not null) + public IList FindByNamedQueryAndNamedParam(string queryName, string[] paramNames, object[] values, IType[] types) + { + if (paramNames != null && values != null && paramNames.Length != values.Length) { - if (values != null && types != null && values.Length != types.Length) + throw new ArgumentOutOfRangeException("paramNames", "Length of paramNames array must match length of values array"); + } + + if (paramNames != null && types != null && paramNames.Length != types.Length) + { + throw new ArgumentOutOfRangeException("paramNams", "Length of paramNames array must match length of types array"); + } + + return (IList) Execute(new FindByNamedQueryAndNamedParamHibernateCallback(this, queryName, paramNames, values, types), true); + } + + /// + /// Execute a named query for persistent instances, binding the properties + /// of the given object to named parameters in the query string. + /// A named query is defined in a Hibernate mapping file. + /// + /// The name of a Hibernate query in a mapping file + /// The values of the parameters + /// A List containing 0 or more persistent instances + /// In case of Hibernate errors + public IList FindByNamedQueryAndValueObject(string queryName, object valueObject) + { + return (IList) Execute(new FindByNamedQueryAndValueObjectHibernateCallback(this, queryName, valueObject), true); + } + + /// + /// Execute a query for persistent instances, binding the properties + /// of the given object to named parameters in the query string. + /// + /// A query expressed in Hibernate's query language + /// The values of the parameters + /// A List containing 0 or more persistent instances + /// In case of Hibernate errors + public IList FindByValueObject(string queryString, object valueObject) + { + return (IList) Execute(new FindByValueObjectHibernateCallback(this, queryString, valueObject), true); + } + + /// + /// Create a close-suppressing proxy for the given Hibernate Session. + /// The proxy also prepares returned Query and Criteria objects. + /// + /// The session. + /// The session proxy. + public virtual ISession CreateSessionProxy(ISession session) + { + //TODO can move to HibernateAccessor and make protected + // if issue reported with AOP+Multiple Threads resolve. + // have not been able to reproduce so added lock as a precaution. + // + lock (syncRoot) + { + if (sessionProxyFactory == null) { - throw new ArgumentException("Length of values array must match length of types array"); - } - return (IList) Execute(new FindHibernateCallback(this, queryString, values, types), true); - } - - /// - /// Execute a query for persistent instances, binding - /// one value to a named parameter in the query string. - /// - /// The name of a Hibernate query in a mapping file - /// The name of the parameter - /// The value of the parameter - /// a List containing 0 or more persistent instances - /// In case of Hibernate errors - public IList FindByNamedParam(string queryName, string paramName, object value) - { - return FindByNamedParam(queryName, paramName, value, null); - } - - /// - /// Execute a query for persistent instances, binding - /// one value to a named parameter in the query string. - /// - /// The name of a Hibernate query in a mapping file - /// The name of the parameter - /// The value of the parameter - /// Hibernate type of the parameter (or null) - /// A List containing 0 or more persistent instances - /// In case of Hibernate errors - public IList FindByNamedParam(string queryName, string paramName, object value, IType type) - { - return FindByNamedParam(queryName, new string[] {paramName}, new object[] {value}, new IType[] {type}); - } - - /// - /// Execute a query for persistent instances, binding a - /// number of values to named parameters in the query string. - /// - /// A query expressed in Hibernate's query language - /// The names of the parameters - /// The values of the parameters - /// A List containing 0 or more persistent instances - /// In case of Hibernate errors - public IList FindByNamedParam(string queryString, string[] paramNames, object[] values) - { - return FindByNamedParam(queryString, paramNames, values, null); - } - - /// - /// Execute a query for persistent instances, binding a - /// number of values to named parameters in the query string. - /// - /// A query expressed in Hibernate's query language - /// The names of the parameters - /// The values of the parameters - /// Hibernate types of the parameters (or null) - /// A List containing 0 or more persistent instances - /// In case of Hibernate errors - /// If paramNames length is not equal to values length or - /// if paramNames length is not equal to types length (when types is not null) - public IList FindByNamedParam(string queryString, string[] paramNames, object[] values, IType[] types) - { - if (paramNames.Length != values.Length) - { - throw new ArgumentOutOfRangeException("paramNames", "Length of paramNames array must match length of values array"); - } - if (types != null && paramNames.Length != types.Length) - { - throw new ArgumentOutOfRangeException("paramNames", "Length of paramNames array must match length of types array"); + sessionProxyFactory = new ProxyFactory(); + sessionProxyFactory.AddAdvice(new CloseSuppressingMethodInterceptor(this)); } - return (IList) Execute(new FindByNamedParamHibernateCallback(this, queryString, paramNames, values, types), true); - } + sessionProxyFactory.Target = session; - /// - /// Execute a named query for persistent instances. - /// A named query is defined in a Hibernate mapping file. - /// - /// The name of a Hibernate query in a mapping file - /// A List containing 0 or more persistent instances - /// In case of Hibernate errors - public IList FindByNamedQuery(string queryName) - { - return FindByNamedQuery(queryName, (object[]) null, (IType[]) null); - } - - /// - /// Execute a named query for persistent instances, binding - /// one value to a "?" parameter in the query string. - /// A named query is defined in a Hibernate mapping file. - /// - /// The name of a Hibernate query in a mapping file - /// The value of the parameter - /// A List containing 0 or more persistent instances - /// In case of Hibernate errors - public IList FindByNamedQuery(string queryName, object value) - { - return FindByNamedQuery(queryName, new object[] {value}, (IType[]) null); - } - - /// - /// Execute a named query for persistent instances, binding - /// one value to a "?" parameter in the query string. - /// A named query is defined in a Hibernate mapping file. - /// - /// The name of a Hibernate query in a mapping file - /// The value of the parameter - /// Hibernate type of the parameter (or null) - /// A List containing 0 or more persistent instances - /// In case of Hibernate errors - public IList FindByNamedQuery(string queryName, object value, IType type) - { - return FindByNamedQuery(queryName, new object[] {value}, new IType[] {type}); - } - - /// - /// Execute a named query for persistent instances, binding a - /// number of values to "?" parameters in the query string. - /// A named query is defined in a Hibernate mapping file. - /// - /// The name of a Hibernate query in a mapping file - /// The values of the parameters - /// A List containing 0 or more persistent instances - /// In case of Hibernate errors - public IList FindByNamedQuery(string queryName, object[] values) - { - return FindByNamedQuery(queryName, values, (IType[]) null); - } - - /// - /// Execute a named query for persistent instances, binding a - /// number of values to "?" parameters in the query string. - /// A named query is defined in a Hibernate mapping file. - /// - /// The name of a Hibernate query in a mapping file - /// The values of the parameters - /// Hibernate types of the parameters (or null) - /// A List containing 0 or more persistent instances - /// In case of Hibernate errors - /// If values and types are not null and their lengths differ. - public IList FindByNamedQuery(string queryName, object[] values, IType[] types) - { - if (values != null && types != null && values.Length != types.Length) - { - throw new ArgumentOutOfRangeException("Length of values array must match length of types array"); - } - return (IList) Execute(new FindByNamedQueryHibernateCallback(this, queryName, values, types), true); - } - - /// - /// Execute a named query for persistent instances, binding - /// one value to a named parameter in the query string. - /// A named query is defined in a Hibernate mapping file. - /// - /// The name of a Hibernate query in a mapping file - /// Name of the parameter - /// The value of the parameter - /// A List containing 0 or more persistent instances - /// In case of Hibernate errors - public IList FindByNamedQueryAndNamedParam(string queryName, string paramName, object value) - { - return FindByNamedQueryAndNamedParam(queryName, paramName, value, null); - } - - /// - /// Execute a named query for persistent instances, binding - /// one value to a named parameter in the query string. - /// A named query is defined in a Hibernate mapping file. - /// - /// The name of a Hibernate query in a mapping file - /// Name of the parameter - /// The value of the parameter - /// The Hibernate type of the parameter (or null) - /// A List containing 0 or more persistent instances - public IList FindByNamedQueryAndNamedParam(string queryName, string paramName, object value, IType type) - { - return FindByNamedQueryAndNamedParam( - queryName, new string[] {paramName}, new object[] {value}, new IType[] {type}); - } - - /// - /// Execute a named query for persistent instances, binding - /// number of values to named parameters in the query string. - /// A named query is defined in a Hibernate mapping file. - /// - /// The name of a Hibernate query in a mapping file - /// The names of the parameters - /// The values of the parameters. - /// A List containing 0 or more persistent instances - /// In case of Hibernate errors - public IList FindByNamedQueryAndNamedParam(string queryName, string[] paramNames, object[] values) - { - return FindByNamedQueryAndNamedParam(queryName, paramNames, values, null); - } - - /// - /// Execute a named query for persistent instances, binding - /// number of values to named parameters in the query string. - /// A named query is defined in a Hibernate mapping file. - /// - /// The name of a Hibernate query in a mapping file - /// The names of the parameters - /// The values of the parameters. - /// Hibernate types of the parameters (or null) - /// A List containing 0 or more persistent instances - /// In case of Hibernate errors - /// If paramNames length is not equal to values length or - /// if paramNames length is not equal to types length (when types is not null) - public IList FindByNamedQueryAndNamedParam(string queryName, string[] paramNames, object[] values, IType[] types) - { - if (paramNames != null && values != null && paramNames.Length != values.Length) - { - throw new ArgumentOutOfRangeException("paramNames", "Length of paramNames array must match length of values array"); - } - if (paramNames != null && types != null && paramNames.Length != types.Length) - { - throw new ArgumentOutOfRangeException("paramNams", "Length of paramNames array must match length of types array"); - } - return (IList) Execute(new FindByNamedQueryAndNamedParamHibernateCallback(this, queryName, paramNames, values, types), true); - } - - /// - /// Execute a named query for persistent instances, binding the properties - /// of the given object to named parameters in the query string. - /// A named query is defined in a Hibernate mapping file. - /// - /// The name of a Hibernate query in a mapping file - /// The values of the parameters - /// A List containing 0 or more persistent instances - /// In case of Hibernate errors - public IList FindByNamedQueryAndValueObject(string queryName, object valueObject) - { - return (IList) Execute(new FindByNamedQueryAndValueObjectHibernateCallback(this, queryName, valueObject), true); - } - - /// - /// Execute a query for persistent instances, binding the properties - /// of the given object to named parameters in the query string. - /// - /// A query expressed in Hibernate's query language - /// The values of the parameters - /// A List containing 0 or more persistent instances - /// In case of Hibernate errors - public IList FindByValueObject(string queryString, object valueObject) - { - return (IList) Execute(new FindByValueObjectHibernateCallback(this, queryString, valueObject), true); - } - - /// - /// Create a close-suppressing proxy for the given Hibernate Session. - /// The proxy also prepares returned Query and Criteria objects. - /// - /// The session. - /// The session proxy. - public virtual ISession CreateSessionProxy(ISession session) - { - //TODO can move to HibernateAccessor and make protected - // if issue reported with AOP+Multiple Threads resolve. - // have not been able to reproduce so added lock as a precaution. - // - lock (syncRoot) - { - if (sessionProxyFactory == null) - { - sessionProxyFactory = new ProxyFactory(); - sessionProxyFactory.AddAdvice(new CloseSuppressingMethodInterceptor(this)); - } - - sessionProxyFactory.Target = session; - - return (ISession) sessionProxyFactory.GetProxy(); - } - } - - /// - /// Check whether write operations are allowed on the given Session. - /// - /// - /// Default implementation throws an InvalidDataAccessApiUsageException - /// in case of FlushMode.Never. Can be overridden in subclasses. - /// - /// The current Hibernate session. - /// If write operation is attempted in read-only mode - /// - public virtual void CheckWriteOperationAllowed(ISession session) - { - if (CheckWriteOperations && TemplateFlushMode != TemplateFlushMode.Eager && - AreEqualFlushMode(TemplateFlushMode.Never, session.FlushMode)) - { - throw new InvalidDataAccessApiUsageException( - "Write operations are not allowed in read-only mode (FlushMode.NEVER) - turn your Session " + - "into FlushMode.AUTO or remove 'readOnly' marker from transaction definition"); - } - } - - /// - /// Compares if the flush mode enumerations, Spring's - /// TemplateFlushMode and NHibernates FlushMode have equal - /// settings. - /// - /// The template flush mode. - /// The NHibernate flush mode. - /// - /// Returns true if both are Never, Auto, or Commit, false - /// otherwise. - /// - protected bool AreEqualFlushMode(TemplateFlushMode tfm, FlushMode fm) - { - if ((tfm == TemplateFlushMode.Never && fm == FlushMode.Never) || - (tfm == TemplateFlushMode.Auto && fm == FlushMode.Auto) || - (tfm == TemplateFlushMode.Commit && fm == FlushMode.Commit)) - { - return true; - } - else - { - return false; - } - //TODO other combinations. + return (ISession) sessionProxyFactory.GetProxy(); } } - //TODO see if can create common base class for some callbacks. - - internal class ContainsHibernateCallback : IHibernateCallback + /// + /// Check whether write operations are allowed on the given Session. + /// + /// + /// Default implementation throws an InvalidDataAccessApiUsageException + /// in case of FlushMode.Never. Can be overridden in subclasses. + /// + /// The current Hibernate session. + /// If write operation is attempted in read-only mode + /// + public virtual void CheckWriteOperationAllowed(ISession session) { - private object entity; - - public ContainsHibernateCallback(object entity) + if (CheckWriteOperations && TemplateFlushMode != TemplateFlushMode.Eager && + AreEqualFlushMode(TemplateFlushMode.Never, session.FlushMode)) { - this.entity = entity; - } - - public object DoInHibernate(ISession session) - { - return session.Contains(entity); + throw new InvalidDataAccessApiUsageException( + "Write operations are not allowed in read-only mode (FlushMode.NEVER) - turn your Session " + + "into FlushMode.AUTO or remove 'readOnly' marker from transaction definition"); } } - internal class DeleteLockModeHibernateCallback : IHibernateCallback + /// + /// Compares if the flush mode enumerations, Spring's + /// TemplateFlushMode and NHibernates FlushMode have equal + /// settings. + /// + /// The template flush mode. + /// The NHibernate flush mode. + /// + /// Returns true if both are Never, Auto, or Commit, false + /// otherwise. + /// + protected bool AreEqualFlushMode(TemplateFlushMode tfm, FlushMode fm) { - private HibernateTemplate outer; - private object entity; - private LockMode lockMode; - - public DeleteLockModeHibernateCallback(HibernateTemplate template, object entity, LockMode lockMode) + if ((tfm == TemplateFlushMode.Never && fm == FlushMode.Never) || + (tfm == TemplateFlushMode.Auto && fm == FlushMode.Auto) || + (tfm == TemplateFlushMode.Commit && fm == FlushMode.Commit)) { - this.outer = template; - this.entity = entity; - this.lockMode = lockMode; + return true; } - - public object DoInHibernate(ISession session) + else { - outer.CheckWriteOperationAllowed(session); - if (lockMode != null) - { - session.Lock(entity, lockMode); - } - session.Delete(entity); - return null; + return false; } + //TODO other combinations. + } +} + +//TODO see if can create common base class for some callbacks. + +internal class ContainsHibernateCallback : IHibernateCallback +{ + private object entity; + + public ContainsHibernateCallback(object entity) + { + this.entity = entity; } - internal class DeletebyQueryHibernateCallback : IHibernateCallback + public object DoInHibernate(ISession session) { - private HibernateTemplate outer; - private string queryString; - private object[] values; - private IType[] types; + return session.Contains(entity); + } +} - public DeletebyQueryHibernateCallback(HibernateTemplate template, string queryString, object[] values, IType[] types) - { - this.outer = template; - this.queryString = queryString; - this.values = values; - this.types = types; - } +internal class DeleteLockModeHibernateCallback : IHibernateCallback +{ + private HibernateTemplate outer; + private object entity; + private LockMode lockMode; - /// - /// Gets called by HibernateTemplate with an active - /// Hibernate Session. Does not need to care about activating or closing - /// the Session, or handling transactions. - /// - /// - ///

- /// Allows for returning a result object created within the callback, i.e. - /// a domain object or a collection of domain objects. Note that there's - /// special support for single step actions: see HibernateTemplate.find etc. - ///

- ///
- public object DoInHibernate(ISession session) - { - outer.CheckWriteOperationAllowed(session); - if (values != null) - { - return session.Delete(queryString, values, types); - } - else - { - return session.Delete(queryString); - } - } + public DeleteLockModeHibernateCallback(HibernateTemplate template, object entity, LockMode lockMode) + { + this.outer = template; + this.entity = entity; + this.lockMode = lockMode; } - internal class DeleteAllHibernateCallback : IHibernateCallback + public object DoInHibernate(ISession session) { - private HibernateTemplate outer; - private ICollection entities; - - public DeleteAllHibernateCallback(HibernateTemplate template, ICollection entities) - { - this.outer = template; - this.entities = entities; - } - - /// - /// Gets called by HibernateTemplate with an active - /// Hibernate Session. Does not need to care about activating or closing - /// the Session, or handling transactions. - /// - /// - ///

- /// Allows for returning a result object created within the callback, i.e. - /// a domain object or a collection of domain objects. Note that there's - /// special support for single step actions: see HibernateTemplate.find etc. - ///

- ///
- public object DoInHibernate(ISession session) - { - outer.CheckWriteOperationAllowed(session); - foreach (object entity in entities) - { - session.Delete(entity); - } - return null; - } - } - - internal class EvictHibernateCallback : IHibernateCallback - { - private object entity; - - public EvictHibernateCallback(object entity) - { - this.entity = entity; - } - - /// - /// Gets called by HibernateTemplate with an active - /// Hibernate Session. Does not need to care about activating or closing - /// the Session, or handling transactions. - /// - /// - ///

- /// Allows for returning a result object created within the callback, i.e. - /// a domain object or a collection of domain objects. Note that there's - /// special support for single step actions: see HibernateTemplate.find etc. - ///

- ///
- public object DoInHibernate(ISession session) - { - session.Evict(entity); - return null; - } - } - - internal class FindHibernateCallback : IHibernateCallback - { - private HibernateTemplate outer; - private string queryString; - private object[] values; - private IType[] types; - - public FindHibernateCallback(HibernateTemplate template, string queryString, object[] values, IType[] types) - { - this.outer = template; - this.queryString = queryString; - this.values = values; - this.types = types; - } - - /// - /// Gets called by HibernateTemplate with an active - /// Hibernate Session. Does not need to care about activating or closing - /// the Session, or handling transactions. - /// - /// - ///

- /// Allows for returning a result object created within the callback, i.e. - /// a domain object or a collection of domain objects. Note that there's - /// special support for single step actions: see HibernateTemplate.find etc. - ///

- ///
- public object DoInHibernate(ISession session) - { - IQuery queryObject = session.CreateQuery(queryString); - outer.PrepareQuery(queryObject); - if (values != null) - { - for (int i = 0; i < values.Length; i++) - { - if (types != null && types[i] != null) - { - queryObject.SetParameter(i, values[i], types[i]); - } - else - { - queryObject.SetParameter(i, values[i]); - } - } - } - - return queryObject.List(); - } - } - - internal class FindByNamedParamHibernateCallback : IHibernateCallback - { - private HibernateTemplate outer; - private string queryString; - private string[] paramNames; - private object[] values; - private IType[] types; - - public FindByNamedParamHibernateCallback(HibernateTemplate template, string queryString, string[] paramNames, object[] values, IType[] types) - { - this.outer = template; - this.queryString = queryString; - this.paramNames = paramNames; - this.values = values; - this.types = types; - } - - /// - /// Gets called by HibernateTemplate with an active - /// Hibernate Session. Does not need to care about activating or closing - /// the Session, or handling transactions. - /// - /// - ///

- /// Allows for returning a result object created within the callback, i.e. - /// a domain object or a collection of domain objects. Note that there's - /// special support for single step actions: see HibernateTemplate.find etc. - ///

- ///
- public object DoInHibernate(ISession session) - { - IQuery queryObject = session.CreateQuery(queryString); - outer.PrepareQuery(queryObject); - if (values != null) - { - for (int i = 0; i < values.Length; i++) - { - outer.ApplyNamedParameterToQuery(queryObject, paramNames[i], values[i], (types != null ? types[i] : null)); - } - } - return queryObject.List(); - } - } - - internal class FindByNamedQueryHibernateCallback : IHibernateCallback - { - private HibernateTemplate outer; - private string queryName; - private object[] values; - private IType[] types; - - public FindByNamedQueryHibernateCallback(HibernateTemplate template, string queryName, object[] values, IType[] types) - { - this.outer = template; - this.queryName = queryName; - this.values = values; - this.types = types; - } - - /// - /// Gets called by HibernateTemplate with an active - /// Hibernate Session. Does not need to care about activating or closing - /// the Session, or handling transactions. - /// - /// - ///

- /// Allows for returning a result object created within the callback, i.e. - /// a domain object or a collection of domain objects. Note that there's - /// special support for single step actions: see HibernateTemplate.find etc. - ///

- ///
- public object DoInHibernate(ISession session) - { - IQuery queryObject = session.GetNamedQuery(queryName); - outer.PrepareQuery(queryObject); - if (values != null) - { - for (int i = 0; i < values.Length; i++) - { - if (types != null && types[i] != null) - { - queryObject.SetParameter(i, values[i], types[i]); - } - else - { - queryObject.SetParameter(i, values[i]); - } - } - } - return queryObject.List(); - } - } - - internal class FindByNamedQueryAndNamedParamHibernateCallback : IHibernateCallback - { - private HibernateTemplate outer; - private string queryName; - private string[] paramNames; - private object[] values; - private IType[] types; - - public FindByNamedQueryAndNamedParamHibernateCallback(HibernateTemplate template, string queryName, string[] paramNames, object[] values, IType[] types) - { - this.outer = template; - this.queryName = queryName; - this.paramNames = paramNames; - this.values = values; - this.types = types; - } - - /// - /// Gets called by HibernateTemplate with an active - /// Hibernate Session. Does not need to care about activating or closing - /// the Session, or handling transactions. - /// - /// - ///

- /// Allows for returning a result object created within the callback, i.e. - /// a domain object or a collection of domain objects. Note that there's - /// special support for single step actions: see HibernateTemplate.find etc. - ///

- ///
- public object DoInHibernate(ISession session) - { - IQuery queryObject = session.GetNamedQuery(queryName); - outer.PrepareQuery(queryObject); - if (values != null) - { - for (int i = 0; i < values.Length; i++) - { - outer.ApplyNamedParameterToQuery(queryObject, paramNames[i], values[i], (types != null ? types[i] : null)); - } - } - return queryObject.List(); - } - } - - internal class FindByNamedQueryAndValueObjectHibernateCallback : IHibernateCallback - { - private HibernateTemplate outer; - private string queryName; - private object valueObject; - - public FindByNamedQueryAndValueObjectHibernateCallback(HibernateTemplate template, string queryName, object valueObject) - { - this.outer = template; - this.queryName = queryName; - this.valueObject = valueObject; - } - - /// - /// Gets called by HibernateTemplate with an active - /// Hibernate Session. Does not need to care about activating or closing - /// the Session, or handling transactions. - /// - /// - ///

- /// Allows for returning a result object created within the callback, i.e. - /// a domain object or a collection of domain objects. Note that there's - /// special support for single step actions: see HibernateTemplate.find etc. - ///

- ///
- public object DoInHibernate(ISession session) - { - IQuery queryObject = session.GetNamedQuery(queryName); - outer.PrepareQuery(queryObject); - queryObject.SetProperties(valueObject); - return queryObject.List(); - } - } - - internal class FindByValueObjectHibernateCallback : IHibernateCallback - { - private HibernateTemplate outer; - private string queryString; - private object valueObject; - - public FindByValueObjectHibernateCallback(HibernateTemplate template, string queryString, object valueObject) - { - this.outer = template; - this.queryString = queryString; - this.valueObject = valueObject; - } - - public object DoInHibernate(ISession session) - { - IQuery queryObject = session.CreateQuery(queryString); - outer.PrepareQuery(queryObject); - queryObject.SetProperties(valueObject); - return queryObject.List(); - } - } - - internal class ExecuteHibernateCallbackUsingDelegate : IHibernateCallback - { - private HibernateDelegate del; - - public ExecuteHibernateCallbackUsingDelegate(HibernateDelegate d) - { - del = d; - } - - public object DoInHibernate(ISession session) - { - return del(session); - } - } - - internal class GetByTypeHibernateCallback : IHibernateCallback - { - private Type entityType; - private object id; - private LockMode lockMode; - - public GetByTypeHibernateCallback(Type entityType, object id, LockMode lockMode) - { - this.entityType = entityType; - this.id = id; - this.lockMode = lockMode; - } - - /// - /// Gets called by HibernateTemplate with an active - /// Hibernate Session. Does not need to care about activating or closing - /// the Session, or handling transactions. - /// - /// - ///

- /// Allows for returning a result object created within the callback, i.e. - /// a domain object or a collection of domain objects. Note that there's - /// special support for single step actions: see HibernateTemplate.find etc. - ///

- ///
- public object DoInHibernate(ISession session) - { - if (lockMode != null) - { - return session.Get(entityType, id, lockMode); - } - else - { - return session.Get(entityType, id); - } - } - } - - internal class LoadByTypeHibernateCallback : IHibernateCallback - { - private Type entityType; - private object id; - private LockMode lockMode; - - public LoadByTypeHibernateCallback(Type entityType, object id, LockMode lockMode) - { - this.entityType = entityType; - this.id = id; - this.lockMode = lockMode; - } - - /// - /// Gets called by HibernateTemplate with an active - /// Hibernate Session. Does not need to care about activating or closing - /// the Session, or handling transactions. - /// - /// - ///

- /// Allows for returning a result object created within the callback, i.e. - /// a domain object or a collection of domain objects. Note that there's - /// special support for single step actions: see HibernateTemplate.find etc. - ///

- ///
- public object DoInHibernate(ISession session) - { - if (lockMode != null) - { - return session.Load(entityType, id, lockMode); - } - else - { - return session.Load(entityType, id); - } - } - } - - internal class LoadByEntityHibernateCallback : IHibernateCallback - { - private object entity; - private object id; - - public LoadByEntityHibernateCallback(object entity, object id) - { - this.entity = entity; - this.id = id; - } - - /// - /// Gets called by HibernateTemplate with an active - /// Hibernate Session. Does not need to care about activating or closing - /// the Session, or handling transactions. - /// - /// - ///

- /// Allows for returning a result object created within the callback, i.e. - /// a domain object or a collection of domain objects. Note that there's - /// special support for single step actions: see HibernateTemplate.find etc. - ///

- ///
- public object DoInHibernate(ISession session) - { - session.Load(entity, id); - return null; - } - } - - internal class LoadAllByTypeHibernateCallback : IHibernateCallback - { - private HibernateTemplate outer; - private Type entityType; - - public LoadAllByTypeHibernateCallback(HibernateTemplate template, Type entityType) - { - outer = template; - this.entityType = entityType; - } - - /// - /// Gets called by HibernateTemplate with an active - /// Hibernate Session. Does not need to care about activating or closing - /// the Session, or handling transactions. - /// - /// - ///

- /// Allows for returning a result object created within the callback, i.e. - /// a domain object or a collection of domain objects. Note that there's - /// special support for single step actions: see HibernateTemplate.find etc. - ///

- ///
- public object DoInHibernate(ISession session) - { - ICriteria criteria = session.CreateCriteria(entityType); - outer.PrepareCriteria(criteria); - return criteria.List(); - } - } - - internal class LockHibernateCallback : IHibernateCallback - { - private object entity; - private LockMode lockMode; - - public LockHibernateCallback(object entity, LockMode lockMode) - { - this.entity = entity; - this.lockMode = lockMode; - } - - /// - /// Gets called by HibernateTemplate with an active - /// Hibernate Session. Does not need to care about activating or closing - /// the Session, or handling transactions. - /// - /// - ///

- /// Allows for returning a result object created within the callback, i.e. - /// a domain object or a collection of domain objects. Note that there's - /// special support for single step actions: see HibernateTemplate.find etc. - ///

- ///
- public object DoInHibernate(ISession session) + outer.CheckWriteOperationAllowed(session); + if (lockMode != null) { session.Lock(entity, lockMode); - return null; } + + session.Delete(entity); + return null; + } +} + +internal class DeletebyQueryHibernateCallback : IHibernateCallback +{ + private HibernateTemplate outer; + private string queryString; + private object[] values; + private IType[] types; + + public DeletebyQueryHibernateCallback(HibernateTemplate template, string queryString, object[] values, IType[] types) + { + this.outer = template; + this.queryString = queryString; + this.values = values; + this.types = types; } - internal class RefreshHibernateCallback : IHibernateCallback + /// + /// Gets called by HibernateTemplate with an active + /// Hibernate Session. Does not need to care about activating or closing + /// the Session, or handling transactions. + /// + /// + ///

+ /// Allows for returning a result object created within the callback, i.e. + /// a domain object or a collection of domain objects. Note that there's + /// special support for single step actions: see HibernateTemplate.find etc. + ///

+ ///
+ public object DoInHibernate(ISession session) { - private object entity; - private LockMode lockMode; - - public RefreshHibernateCallback(object entity, LockMode lockMode) + outer.CheckWriteOperationAllowed(session); + if (values != null) { - this.entity = entity; - this.lockMode = lockMode; + return session.Delete(queryString, values, types); } - - /// - /// Gets called by HibernateTemplate with an active - /// Hibernate Session. Does not need to care about activating or closing - /// the Session, or handling transactions. - /// - /// - ///

- /// Allows for returning a result object created within the callback, i.e. - /// a domain object or a collection of domain objects. Note that there's - /// special support for single step actions: see HibernateTemplate.find etc. - ///

- ///
- public object DoInHibernate(ISession session) + else { - if (lockMode != null) - { - session.Refresh(entity, lockMode); - } - else - { - session.Refresh(entity); - } - return null; - } - } - - internal class SaveObjectHibernateCallback : IHibernateCallback - { - private HibernateTemplate outer; - private object entity; - - public SaveObjectHibernateCallback(HibernateTemplate template, object entity) - { - this.outer = template; - this.entity = entity; - } - - /// - /// Gets called by HibernateTemplate with an active - /// Hibernate Session. Does not need to care about activating or closing - /// the Session, or handling transactions. - /// - /// - ///

- /// Allows for returning a result object created within the callback, i.e. - /// a domain object or a collection of domain objects. Note that there's - /// special support for single step actions: see HibernateTemplate.find etc. - ///

- ///
- public object DoInHibernate(ISession session) - { - outer.CheckWriteOperationAllowed(session); - return session.Save(entity); - } - } - - internal class SaveObjectWithIdHibernateCallback : IHibernateCallback - { - private HibernateTemplate outer; - private object entity; - private object id; - - public SaveObjectWithIdHibernateCallback(HibernateTemplate template, object entity, object id) - { - this.outer = template; - this.entity = entity; - this.id = id; - } - - /// - /// Gets called by HibernateTemplate with an active - /// Hibernate Session. Does not need to care about activating or closing - /// the Session, or handling transactions. - /// - /// - ///

- /// Allows for returning a result object created within the callback, i.e. - /// a domain object or a collection of domain objects. Note that there's - /// special support for single step actions: see HibernateTemplate.find etc. - ///

- ///
- public object DoInHibernate(ISession session) - { - outer.CheckWriteOperationAllowed(session); - session.Save(entity, id); - return null; - } - } - - internal class UpdateObjectHibernateCallback : IHibernateCallback - { - private HibernateTemplate outer; - private object entity; - private LockMode lockMode; - - public UpdateObjectHibernateCallback(HibernateTemplate template, object entity, LockMode lockMode) - { - this.outer = template; - this.entity = entity; - this.lockMode = lockMode; - } - - /// - /// Gets called by HibernateTemplate with an active - /// Hibernate Session. Does not need to care about activating or closing - /// the Session, or handling transactions. - /// - /// - ///

- /// Allows for returning a result object created within the callback, i.e. - /// a domain object or a collection of domain objects. Note that there's - /// special support for single step actions: see HibernateTemplate.find etc. - ///

- ///
- public object DoInHibernate(ISession session) - { - outer.CheckWriteOperationAllowed(session); - session.Update(entity); - if (lockMode != null) - { - session.Lock(entity, lockMode); - } - return null; - } - } - - internal class SaveOrUpdateObjectHibernateCallback : IHibernateCallback - { - private HibernateTemplate outer; - private object entity; - - public SaveOrUpdateObjectHibernateCallback(HibernateTemplate template, object entity) - { - this.outer = template; - this.entity = entity; - } - - /// - /// Gets called by HibernateTemplate with an active - /// Hibernate Session. Does not need to care about activating or closing - /// the Session, or handling transactions. - /// - /// - ///

- /// Allows for returning a result object created within the callback, i.e. - /// a domain object or a collection of domain objects. Note that there's - /// special support for single step actions: see HibernateTemplate.find etc. - ///

- ///
- public object DoInHibernate(ISession session) - { - outer.CheckWriteOperationAllowed(session); - session.SaveOrUpdate(entity); - return null; - } - } - - internal class SaveOrUpdateAllHibernateCallback : IHibernateCallback - { - private HibernateTemplate outer; - private ICollection entities; - - public SaveOrUpdateAllHibernateCallback(HibernateTemplate template, ICollection entities) - { - this.outer = template; - this.entities = entities; - } - - /// - /// Gets called by HibernateTemplate with an active - /// Hibernate Session. Does not need to care about activating or closing - /// the Session, or handling transactions. - /// - /// - ///

- /// Allows for returning a result object created within the callback, i.e. - /// a domain object or a collection of domain objects. Note that there's - /// special support for single step actions: see HibernateTemplate.find etc. - ///

- ///
- public object DoInHibernate(ISession session) - { - outer.CheckWriteOperationAllowed(session); - foreach (object entity in entities) - { - session.SaveOrUpdate(entity); - } - return null; - } - } - - internal class MergeHibernateCallback : IHibernateCallback - { - private HibernateTemplate outer; - private object entity; - - public MergeHibernateCallback(HibernateTemplate template, object entity) - { - this.outer = template; - this.entity = entity; - } - - /// - /// Gets called by HibernateTemplate with an active - /// Hibernate Session. Does not need to care about activating or closing - /// the Session, or handling transactions. - /// - /// - ///

- /// Allows for returning a result object created within the callback, i.e. - /// a domain object or a collection of domain objects. Note that there's - /// special support for single step actions: see HibernateTemplate.find etc. - ///

- ///
- public object DoInHibernate(ISession session) - { - outer.CheckWriteOperationAllowed(session); - return session.Merge(entity); + return session.Delete(queryString); } } } + +internal class DeleteAllHibernateCallback : IHibernateCallback +{ + private HibernateTemplate outer; + private ICollection entities; + + public DeleteAllHibernateCallback(HibernateTemplate template, ICollection entities) + { + this.outer = template; + this.entities = entities; + } + + /// + /// Gets called by HibernateTemplate with an active + /// Hibernate Session. Does not need to care about activating or closing + /// the Session, or handling transactions. + /// + /// + ///

+ /// Allows for returning a result object created within the callback, i.e. + /// a domain object or a collection of domain objects. Note that there's + /// special support for single step actions: see HibernateTemplate.find etc. + ///

+ ///
+ public object DoInHibernate(ISession session) + { + outer.CheckWriteOperationAllowed(session); + foreach (object entity in entities) + { + session.Delete(entity); + } + + return null; + } +} + +internal class EvictHibernateCallback : IHibernateCallback +{ + private object entity; + + public EvictHibernateCallback(object entity) + { + this.entity = entity; + } + + /// + /// Gets called by HibernateTemplate with an active + /// Hibernate Session. Does not need to care about activating or closing + /// the Session, or handling transactions. + /// + /// + ///

+ /// Allows for returning a result object created within the callback, i.e. + /// a domain object or a collection of domain objects. Note that there's + /// special support for single step actions: see HibernateTemplate.find etc. + ///

+ ///
+ public object DoInHibernate(ISession session) + { + session.Evict(entity); + return null; + } +} + +internal class FindHibernateCallback : IHibernateCallback +{ + private HibernateTemplate outer; + private string queryString; + private object[] values; + private IType[] types; + + public FindHibernateCallback(HibernateTemplate template, string queryString, object[] values, IType[] types) + { + this.outer = template; + this.queryString = queryString; + this.values = values; + this.types = types; + } + + /// + /// Gets called by HibernateTemplate with an active + /// Hibernate Session. Does not need to care about activating or closing + /// the Session, or handling transactions. + /// + /// + ///

+ /// Allows for returning a result object created within the callback, i.e. + /// a domain object or a collection of domain objects. Note that there's + /// special support for single step actions: see HibernateTemplate.find etc. + ///

+ ///
+ public object DoInHibernate(ISession session) + { + IQuery queryObject = session.CreateQuery(queryString); + outer.PrepareQuery(queryObject); + if (values != null) + { + for (int i = 0; i < values.Length; i++) + { + if (types != null && types[i] != null) + { + queryObject.SetParameter(i, values[i], types[i]); + } + else + { + queryObject.SetParameter(i, values[i]); + } + } + } + + return queryObject.List(); + } +} + +internal class FindByNamedParamHibernateCallback : IHibernateCallback +{ + private HibernateTemplate outer; + private string queryString; + private string[] paramNames; + private object[] values; + private IType[] types; + + public FindByNamedParamHibernateCallback(HibernateTemplate template, string queryString, string[] paramNames, object[] values, IType[] types) + { + this.outer = template; + this.queryString = queryString; + this.paramNames = paramNames; + this.values = values; + this.types = types; + } + + /// + /// Gets called by HibernateTemplate with an active + /// Hibernate Session. Does not need to care about activating or closing + /// the Session, or handling transactions. + /// + /// + ///

+ /// Allows for returning a result object created within the callback, i.e. + /// a domain object or a collection of domain objects. Note that there's + /// special support for single step actions: see HibernateTemplate.find etc. + ///

+ ///
+ public object DoInHibernate(ISession session) + { + IQuery queryObject = session.CreateQuery(queryString); + outer.PrepareQuery(queryObject); + if (values != null) + { + for (int i = 0; i < values.Length; i++) + { + outer.ApplyNamedParameterToQuery(queryObject, paramNames[i], values[i], (types != null ? types[i] : null)); + } + } + + return queryObject.List(); + } +} + +internal class FindByNamedQueryHibernateCallback : IHibernateCallback +{ + private HibernateTemplate outer; + private string queryName; + private object[] values; + private IType[] types; + + public FindByNamedQueryHibernateCallback(HibernateTemplate template, string queryName, object[] values, IType[] types) + { + this.outer = template; + this.queryName = queryName; + this.values = values; + this.types = types; + } + + /// + /// Gets called by HibernateTemplate with an active + /// Hibernate Session. Does not need to care about activating or closing + /// the Session, or handling transactions. + /// + /// + ///

+ /// Allows for returning a result object created within the callback, i.e. + /// a domain object or a collection of domain objects. Note that there's + /// special support for single step actions: see HibernateTemplate.find etc. + ///

+ ///
+ public object DoInHibernate(ISession session) + { + IQuery queryObject = session.GetNamedQuery(queryName); + outer.PrepareQuery(queryObject); + if (values != null) + { + for (int i = 0; i < values.Length; i++) + { + if (types != null && types[i] != null) + { + queryObject.SetParameter(i, values[i], types[i]); + } + else + { + queryObject.SetParameter(i, values[i]); + } + } + } + + return queryObject.List(); + } +} + +internal class FindByNamedQueryAndNamedParamHibernateCallback : IHibernateCallback +{ + private HibernateTemplate outer; + private string queryName; + private string[] paramNames; + private object[] values; + private IType[] types; + + public FindByNamedQueryAndNamedParamHibernateCallback(HibernateTemplate template, string queryName, string[] paramNames, object[] values, IType[] types) + { + this.outer = template; + this.queryName = queryName; + this.paramNames = paramNames; + this.values = values; + this.types = types; + } + + /// + /// Gets called by HibernateTemplate with an active + /// Hibernate Session. Does not need to care about activating or closing + /// the Session, or handling transactions. + /// + /// + ///

+ /// Allows for returning a result object created within the callback, i.e. + /// a domain object or a collection of domain objects. Note that there's + /// special support for single step actions: see HibernateTemplate.find etc. + ///

+ ///
+ public object DoInHibernate(ISession session) + { + IQuery queryObject = session.GetNamedQuery(queryName); + outer.PrepareQuery(queryObject); + if (values != null) + { + for (int i = 0; i < values.Length; i++) + { + outer.ApplyNamedParameterToQuery(queryObject, paramNames[i], values[i], (types != null ? types[i] : null)); + } + } + + return queryObject.List(); + } +} + +internal class FindByNamedQueryAndValueObjectHibernateCallback : IHibernateCallback +{ + private HibernateTemplate outer; + private string queryName; + private object valueObject; + + public FindByNamedQueryAndValueObjectHibernateCallback(HibernateTemplate template, string queryName, object valueObject) + { + this.outer = template; + this.queryName = queryName; + this.valueObject = valueObject; + } + + /// + /// Gets called by HibernateTemplate with an active + /// Hibernate Session. Does not need to care about activating or closing + /// the Session, or handling transactions. + /// + /// + ///

+ /// Allows for returning a result object created within the callback, i.e. + /// a domain object or a collection of domain objects. Note that there's + /// special support for single step actions: see HibernateTemplate.find etc. + ///

+ ///
+ public object DoInHibernate(ISession session) + { + IQuery queryObject = session.GetNamedQuery(queryName); + outer.PrepareQuery(queryObject); + queryObject.SetProperties(valueObject); + return queryObject.List(); + } +} + +internal class FindByValueObjectHibernateCallback : IHibernateCallback +{ + private HibernateTemplate outer; + private string queryString; + private object valueObject; + + public FindByValueObjectHibernateCallback(HibernateTemplate template, string queryString, object valueObject) + { + this.outer = template; + this.queryString = queryString; + this.valueObject = valueObject; + } + + public object DoInHibernate(ISession session) + { + IQuery queryObject = session.CreateQuery(queryString); + outer.PrepareQuery(queryObject); + queryObject.SetProperties(valueObject); + return queryObject.List(); + } +} + +internal class ExecuteHibernateCallbackUsingDelegate : IHibernateCallback +{ + private HibernateDelegate del; + + public ExecuteHibernateCallbackUsingDelegate(HibernateDelegate d) + { + del = d; + } + + public object DoInHibernate(ISession session) + { + return del(session); + } +} + +internal class GetByTypeHibernateCallback : IHibernateCallback +{ + private Type entityType; + private object id; + private LockMode lockMode; + + public GetByTypeHibernateCallback(Type entityType, object id, LockMode lockMode) + { + this.entityType = entityType; + this.id = id; + this.lockMode = lockMode; + } + + /// + /// Gets called by HibernateTemplate with an active + /// Hibernate Session. Does not need to care about activating or closing + /// the Session, or handling transactions. + /// + /// + ///

+ /// Allows for returning a result object created within the callback, i.e. + /// a domain object or a collection of domain objects. Note that there's + /// special support for single step actions: see HibernateTemplate.find etc. + ///

+ ///
+ public object DoInHibernate(ISession session) + { + if (lockMode != null) + { + return session.Get(entityType, id, lockMode); + } + else + { + return session.Get(entityType, id); + } + } +} + +internal class LoadByTypeHibernateCallback : IHibernateCallback +{ + private Type entityType; + private object id; + private LockMode lockMode; + + public LoadByTypeHibernateCallback(Type entityType, object id, LockMode lockMode) + { + this.entityType = entityType; + this.id = id; + this.lockMode = lockMode; + } + + /// + /// Gets called by HibernateTemplate with an active + /// Hibernate Session. Does not need to care about activating or closing + /// the Session, or handling transactions. + /// + /// + ///

+ /// Allows for returning a result object created within the callback, i.e. + /// a domain object or a collection of domain objects. Note that there's + /// special support for single step actions: see HibernateTemplate.find etc. + ///

+ ///
+ public object DoInHibernate(ISession session) + { + if (lockMode != null) + { + return session.Load(entityType, id, lockMode); + } + else + { + return session.Load(entityType, id); + } + } +} + +internal class LoadByEntityHibernateCallback : IHibernateCallback +{ + private object entity; + private object id; + + public LoadByEntityHibernateCallback(object entity, object id) + { + this.entity = entity; + this.id = id; + } + + /// + /// Gets called by HibernateTemplate with an active + /// Hibernate Session. Does not need to care about activating or closing + /// the Session, or handling transactions. + /// + /// + ///

+ /// Allows for returning a result object created within the callback, i.e. + /// a domain object or a collection of domain objects. Note that there's + /// special support for single step actions: see HibernateTemplate.find etc. + ///

+ ///
+ public object DoInHibernate(ISession session) + { + session.Load(entity, id); + return null; + } +} + +internal class LoadAllByTypeHibernateCallback : IHibernateCallback +{ + private HibernateTemplate outer; + private Type entityType; + + public LoadAllByTypeHibernateCallback(HibernateTemplate template, Type entityType) + { + outer = template; + this.entityType = entityType; + } + + /// + /// Gets called by HibernateTemplate with an active + /// Hibernate Session. Does not need to care about activating or closing + /// the Session, or handling transactions. + /// + /// + ///

+ /// Allows for returning a result object created within the callback, i.e. + /// a domain object or a collection of domain objects. Note that there's + /// special support for single step actions: see HibernateTemplate.find etc. + ///

+ ///
+ public object DoInHibernate(ISession session) + { + ICriteria criteria = session.CreateCriteria(entityType); + outer.PrepareCriteria(criteria); + return criteria.List(); + } +} + +internal class LockHibernateCallback : IHibernateCallback +{ + private object entity; + private LockMode lockMode; + + public LockHibernateCallback(object entity, LockMode lockMode) + { + this.entity = entity; + this.lockMode = lockMode; + } + + /// + /// Gets called by HibernateTemplate with an active + /// Hibernate Session. Does not need to care about activating or closing + /// the Session, or handling transactions. + /// + /// + ///

+ /// Allows for returning a result object created within the callback, i.e. + /// a domain object or a collection of domain objects. Note that there's + /// special support for single step actions: see HibernateTemplate.find etc. + ///

+ ///
+ public object DoInHibernate(ISession session) + { + session.Lock(entity, lockMode); + return null; + } +} + +internal class RefreshHibernateCallback : IHibernateCallback +{ + private object entity; + private LockMode lockMode; + + public RefreshHibernateCallback(object entity, LockMode lockMode) + { + this.entity = entity; + this.lockMode = lockMode; + } + + /// + /// Gets called by HibernateTemplate with an active + /// Hibernate Session. Does not need to care about activating or closing + /// the Session, or handling transactions. + /// + /// + ///

+ /// Allows for returning a result object created within the callback, i.e. + /// a domain object or a collection of domain objects. Note that there's + /// special support for single step actions: see HibernateTemplate.find etc. + ///

+ ///
+ public object DoInHibernate(ISession session) + { + if (lockMode != null) + { + session.Refresh(entity, lockMode); + } + else + { + session.Refresh(entity); + } + + return null; + } +} + +internal class SaveObjectHibernateCallback : IHibernateCallback +{ + private HibernateTemplate outer; + private object entity; + + public SaveObjectHibernateCallback(HibernateTemplate template, object entity) + { + this.outer = template; + this.entity = entity; + } + + /// + /// Gets called by HibernateTemplate with an active + /// Hibernate Session. Does not need to care about activating or closing + /// the Session, or handling transactions. + /// + /// + ///

+ /// Allows for returning a result object created within the callback, i.e. + /// a domain object or a collection of domain objects. Note that there's + /// special support for single step actions: see HibernateTemplate.find etc. + ///

+ ///
+ public object DoInHibernate(ISession session) + { + outer.CheckWriteOperationAllowed(session); + return session.Save(entity); + } +} + +internal class SaveObjectWithIdHibernateCallback : IHibernateCallback +{ + private HibernateTemplate outer; + private object entity; + private object id; + + public SaveObjectWithIdHibernateCallback(HibernateTemplate template, object entity, object id) + { + this.outer = template; + this.entity = entity; + this.id = id; + } + + /// + /// Gets called by HibernateTemplate with an active + /// Hibernate Session. Does not need to care about activating or closing + /// the Session, or handling transactions. + /// + /// + ///

+ /// Allows for returning a result object created within the callback, i.e. + /// a domain object or a collection of domain objects. Note that there's + /// special support for single step actions: see HibernateTemplate.find etc. + ///

+ ///
+ public object DoInHibernate(ISession session) + { + outer.CheckWriteOperationAllowed(session); + session.Save(entity, id); + return null; + } +} + +internal class UpdateObjectHibernateCallback : IHibernateCallback +{ + private HibernateTemplate outer; + private object entity; + private LockMode lockMode; + + public UpdateObjectHibernateCallback(HibernateTemplate template, object entity, LockMode lockMode) + { + this.outer = template; + this.entity = entity; + this.lockMode = lockMode; + } + + /// + /// Gets called by HibernateTemplate with an active + /// Hibernate Session. Does not need to care about activating or closing + /// the Session, or handling transactions. + /// + /// + ///

+ /// Allows for returning a result object created within the callback, i.e. + /// a domain object or a collection of domain objects. Note that there's + /// special support for single step actions: see HibernateTemplate.find etc. + ///

+ ///
+ public object DoInHibernate(ISession session) + { + outer.CheckWriteOperationAllowed(session); + session.Update(entity); + if (lockMode != null) + { + session.Lock(entity, lockMode); + } + + return null; + } +} + +internal class SaveOrUpdateObjectHibernateCallback : IHibernateCallback +{ + private HibernateTemplate outer; + private object entity; + + public SaveOrUpdateObjectHibernateCallback(HibernateTemplate template, object entity) + { + this.outer = template; + this.entity = entity; + } + + /// + /// Gets called by HibernateTemplate with an active + /// Hibernate Session. Does not need to care about activating or closing + /// the Session, or handling transactions. + /// + /// + ///

+ /// Allows for returning a result object created within the callback, i.e. + /// a domain object or a collection of domain objects. Note that there's + /// special support for single step actions: see HibernateTemplate.find etc. + ///

+ ///
+ public object DoInHibernate(ISession session) + { + outer.CheckWriteOperationAllowed(session); + session.SaveOrUpdate(entity); + return null; + } +} + +internal class SaveOrUpdateAllHibernateCallback : IHibernateCallback +{ + private HibernateTemplate outer; + private ICollection entities; + + public SaveOrUpdateAllHibernateCallback(HibernateTemplate template, ICollection entities) + { + this.outer = template; + this.entities = entities; + } + + /// + /// Gets called by HibernateTemplate with an active + /// Hibernate Session. Does not need to care about activating or closing + /// the Session, or handling transactions. + /// + /// + ///

+ /// Allows for returning a result object created within the callback, i.e. + /// a domain object or a collection of domain objects. Note that there's + /// special support for single step actions: see HibernateTemplate.find etc. + ///

+ ///
+ public object DoInHibernate(ISession session) + { + outer.CheckWriteOperationAllowed(session); + foreach (object entity in entities) + { + session.SaveOrUpdate(entity); + } + + return null; + } +} + +internal class MergeHibernateCallback : IHibernateCallback +{ + private HibernateTemplate outer; + private object entity; + + public MergeHibernateCallback(HibernateTemplate template, object entity) + { + this.outer = template; + this.entity = entity; + } + + /// + /// Gets called by HibernateTemplate with an active + /// Hibernate Session. Does not need to care about activating or closing + /// the Session, or handling transactions. + /// + /// + ///

+ /// Allows for returning a result object created within the callback, i.e. + /// a domain object or a collection of domain objects. Note that there's + /// special support for single step actions: see HibernateTemplate.find etc. + ///

+ ///
+ public object DoInHibernate(ISession session) + { + outer.CheckWriteOperationAllowed(session); + return session.Merge(entity); + } +} diff --git a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/HibernateTransactionManager.cs b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/HibernateTransactionManager.cs index 25acfc65..3ff67c05 100644 --- a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/HibernateTransactionManager.cs +++ b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/HibernateTransactionManager.cs @@ -1,12 +1,12 @@ /* * Copyright � 2002-2011 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. @@ -19,7 +19,6 @@ using System.Reflection; using Microsoft.Extensions.Logging; using NHibernate; using NHibernate.Transaction; - using Spring.Core.TypeResolution; using Spring.Dao; using Spring.Data.Common; @@ -27,927 +26,921 @@ using Spring.Data.Support; using Spring.Objects.Factory; using Spring.Transaction; using Spring.Transaction.Support; - using HibernateTransactionException = NHibernate.TransactionException; -namespace Spring.Data.NHibernate +namespace Spring.Data.NHibernate; + +/// +/// PlatformTransactionManager implementation for a single Hibernate SessionFactory. +/// Binds a Hibernate Session from the specified factory to the thread, potentially +/// allowing for one thread Session per factory +/// +/// +/// SessionFactoryUtils and HibernateTemplate are aware of thread-bound Sessions and participate in such +/// transactions automatically. Using either of those is required for Hibernate +/// access code that needs to support this transaction handling mechanism. +/// +/// Supports custom isolation levels at the start of the transaction +/// , and timeouts that get applied as appropriate +/// Hibernate query timeouts. To support the latter, application code must either use +/// HibernateTemplate (which by default applies the timeouts) or call +/// SessionFactoryUtils.applyTransactionTimeout for each created +/// Hibernate Query object. +/// +/// Note that you can specify a Spring IDbProvider instance which if shared with +/// a corresponding instance of AdoTemplate will allow for mixing ADO.NET/NHibernate +/// operations within a single transaction. +/// +/// Mark Pollack (.NET) +public class HibernateTransactionManager : AbstractPlatformTransactionManager, IResourceTransactionManager, IObjectFactoryAware, IInitializingObject { + private ISessionFactory sessionFactory; + + private IDbProvider dbProvider; + + private bool autodetectDbProvider = true; + + private Object entityInterceptor; + + private IAdoExceptionTranslator adoExceptionTranslator; + + private IAdoExceptionTranslator defaultExceptionTranslator; + /// - /// PlatformTransactionManager implementation for a single Hibernate SessionFactory. - /// Binds a Hibernate Session from the specified factory to the thread, potentially - /// allowing for one thread Session per factory + /// Just needed for entityInterceptorBeanName. + /// + private IObjectFactory objectFactory; + + /// + /// Initializes a new instance of the class. + /// + public HibernateTransactionManager() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The session factory. + public HibernateTransactionManager(ISessionFactory sessionFactory) + { + this.sessionFactory = sessionFactory; + AfterPropertiesSet(); + } + + /// + /// Gets or sets the db provider. + /// + /// The db provider. + public IDbProvider DbProvider + { + get { return dbProvider; } + set { dbProvider = value; } + } + + /// + /// Gets or sets a Hibernate entity interceptor that allows to inspect and change + /// property values before writing to and reading from the database. + /// When getting, return the current Hibernate entity interceptor, or null if none. + /// + /// The entity interceptor. + /// + /// Resolves an entity interceptor object name via the object factory, + /// if necessary. + /// Will get applied to any new Session created by this transaction manager. + /// Such an interceptor can either be set at the SessionFactory level, + /// i.e. on LocalSessionFactoryObject, or at the Session level, i.e. on + /// HibernateTemplate, HibernateInterceptor, and HibernateTransactionManager. + /// It's preferable to set it on LocalSessionFactoryObject or HibernateTransactionManager + /// to avoid repeated configuration and guarantee consistent behavior in transactions. + /// + /// If object factory is null and need to get entity interceptor via object name. + public IInterceptor EntityInterceptor + { + get + { + if (this.entityInterceptor is IInterceptor) + { + return (IInterceptor) entityInterceptor; + } + else if (this.entityInterceptor is string) + { + if (this.objectFactory == null) + { + throw new InvalidOperationException("Cannot get entity interceptor via object name if no object factory set"); + } + + String objectName = (String) this.entityInterceptor; + return (IInterceptor) this.objectFactory.GetObject(objectName, typeof(IInterceptor)); + } + else + { + return null; + } + } + set + { + entityInterceptor = value; + } + } + + /// + /// Sets the object name of a Hibernate entity interceptor that + /// allows to inspect and change property values before writing to and reading from the database. + /// + /// The name of the entity interceptor object. + /// + /// Will get applied to any new Session created by this transaction manager. + ///

Requires the object factory to be known, to be able to resolve the object + /// name to an interceptor instance on session creation. Typically used for + /// prototype interceptors, i.e. a new interceptor instance per session. + ///

+ ///

Can also be used for shared interceptor instances, but it is recommended + /// to set the interceptor reference directly in such a scenario. + ///

+ ///
+ public string EntityInterceptorObjectName + { + set + { + entityInterceptor = value; + } + } + + /// + /// Gets or sets the ADO.NET exception translator for this transaction manager. /// /// - /// SessionFactoryUtils and HibernateTemplate are aware of thread-bound Sessions and participate in such - /// transactions automatically. Using either of those is required for Hibernate - /// access code that needs to support this transaction handling mechanism. - /// - /// Supports custom isolation levels at the start of the transaction - /// , and timeouts that get applied as appropriate - /// Hibernate query timeouts. To support the latter, application code must either use - /// HibernateTemplate (which by default applies the timeouts) or call - /// SessionFactoryUtils.applyTransactionTimeout for each created - /// Hibernate Query object. - /// - /// Note that you can specify a Spring IDbProvider instance which if shared with - /// a corresponding instance of AdoTemplate will allow for mixing ADO.NET/NHibernate - /// operations within a single transaction. + /// Applied to ADO.NET Exceptions (wrapped by Hibernate's ADOException) /// - /// Mark Pollack (.NET) - public class HibernateTransactionManager : AbstractPlatformTransactionManager, IResourceTransactionManager, IObjectFactoryAware, IInitializingObject + /// The ADO exception translator. + public IAdoExceptionTranslator AdoExceptionTranslator { - private ISessionFactory sessionFactory; + get { return adoExceptionTranslator; } + set { adoExceptionTranslator = value; } + } - private IDbProvider dbProvider; - - private bool autodetectDbProvider = true; - - private Object entityInterceptor; - - private IAdoExceptionTranslator adoExceptionTranslator; - - private IAdoExceptionTranslator defaultExceptionTranslator; - - /// - /// Just needed for entityInterceptorBeanName. - /// - private IObjectFactory objectFactory; - - /// - /// Initializes a new instance of the class. - /// - public HibernateTransactionManager() + /// + /// Gets the default IAdoException translator, lazily creating it if nece + /// + /// The default IAdoException translator. + public IAdoExceptionTranslator DefaultAdoExceptionTranslator + { + get { - } - - /// - /// Initializes a new instance of the class. - /// - /// The session factory. - public HibernateTransactionManager(ISessionFactory sessionFactory) - { - this.sessionFactory = sessionFactory; - AfterPropertiesSet(); - } - - /// - /// Gets or sets the db provider. - /// - /// The db provider. - public IDbProvider DbProvider - { - get { return dbProvider; } - set { dbProvider = value; } - } - - /// - /// Gets or sets a Hibernate entity interceptor that allows to inspect and change - /// property values before writing to and reading from the database. - /// When getting, return the current Hibernate entity interceptor, or null if none. - /// - /// The entity interceptor. - /// - /// Resolves an entity interceptor object name via the object factory, - /// if necessary. - /// Will get applied to any new Session created by this transaction manager. - /// Such an interceptor can either be set at the SessionFactory level, - /// i.e. on LocalSessionFactoryObject, or at the Session level, i.e. on - /// HibernateTemplate, HibernateInterceptor, and HibernateTransactionManager. - /// It's preferable to set it on LocalSessionFactoryObject or HibernateTransactionManager - /// to avoid repeated configuration and guarantee consistent behavior in transactions. - /// - /// If object factory is null and need to get entity interceptor via object name. - public IInterceptor EntityInterceptor - { - get + lock (this) { - if (this.entityInterceptor is IInterceptor) + if (defaultExceptionTranslator == null) { - return (IInterceptor)entityInterceptor; - } - else if (this.entityInterceptor is string) - { - if (this.objectFactory == null) + if (dbProvider != null) { - throw new InvalidOperationException("Cannot get entity interceptor via object name if no object factory set"); + defaultExceptionTranslator = new ErrorCodeExceptionTranslator(dbProvider); } - String objectName = (String)this.entityInterceptor; - return (IInterceptor)this.objectFactory.GetObject(objectName, typeof(IInterceptor)); - } - else - { - return null; - } - } - set - { - entityInterceptor = value; - } - } - - /// - /// Sets the object name of a Hibernate entity interceptor that - /// allows to inspect and change property values before writing to and reading from the database. - /// - /// The name of the entity interceptor object. - /// - /// Will get applied to any new Session created by this transaction manager. - ///

Requires the object factory to be known, to be able to resolve the object - /// name to an interceptor instance on session creation. Typically used for - /// prototype interceptors, i.e. a new interceptor instance per session. - ///

- ///

Can also be used for shared interceptor instances, but it is recommended - /// to set the interceptor reference directly in such a scenario. - ///

- ///
- public string EntityInterceptorObjectName - { - set - { - entityInterceptor = value; - } - } - - /// - /// Gets or sets the ADO.NET exception translator for this transaction manager. - /// - /// - /// Applied to ADO.NET Exceptions (wrapped by Hibernate's ADOException) - /// - /// The ADO exception translator. - public IAdoExceptionTranslator AdoExceptionTranslator - { - get { return adoExceptionTranslator; } - set { adoExceptionTranslator = value; } - } - - /// - /// Gets the default IAdoException translator, lazily creating it if nece - /// - /// The default IAdoException translator. - public IAdoExceptionTranslator DefaultAdoExceptionTranslator - { - get - { - lock (this) - { - if (defaultExceptionTranslator == null) + else { - if (dbProvider != null) - { - defaultExceptionTranslator = new ErrorCodeExceptionTranslator(dbProvider); - } - else - { - defaultExceptionTranslator = SessionFactoryUtils.NewAdoExceptionTranslator(SessionFactory); - } + defaultExceptionTranslator = SessionFactoryUtils.NewAdoExceptionTranslator(SessionFactory); } - return defaultExceptionTranslator; } + + return defaultExceptionTranslator; + } + } + } + + /// + /// Gets or sets the SessionFactory that this instance should manage transactions for. + /// + /// The session factory. + public ISessionFactory SessionFactory + { + get { return sessionFactory; } + set { sessionFactory = value; } + } + + /// + /// Gets the resource factory that this transaction manager operates on, + /// For the HibenratePlatformTransactionManager this the SessionFactory + /// + /// The SessionFactory. + public object ResourceFactory + { + get { return sessionFactory; } + } + + /// + /// Set whether to autodetect a ADO.NET connection used by the Hibernate SessionFactory, + /// if set via LocalSessionFactoryObject's DbProvider. Default is "true". + /// + /// + /// true if [autodetect data source]; otherwise, false. + /// + /// + ///

Can be turned off to deliberately ignore an available IDbProvider, + /// to not expose Hibernate transactions as ADO.NET transactions for that IDbProvider. + ///

+ ///
+ public bool AutodetectDbProvider + { + set { autodetectDbProvider = value; } + } + + /// + /// The object factory just needs to be known for resolving entity interceptor + /// It does not need to be set for any other mode of operation. + /// + /// + /// Owning + /// (may not be ). The object can immediately + /// call methods on the factory. + /// + public IObjectFactory ObjectFactory + { + set + { + objectFactory = value; + } + } + + /// + /// Return the current transaction object. + /// + /// The current transaction object. + /// + /// If transaction support is not available. + /// + /// + /// In the case of lookup or system errors. + /// + protected override object DoGetTransaction() + { + HibernateTransactionObject txObject = new HibernateTransactionObject(); + txObject.SavepointAllowed = NestedTransactionsAllowed; + if (TransactionSynchronizationManager.HasResource(SessionFactory)) + { + SessionHolder sessionHolder = + (SessionHolder) TransactionSynchronizationManager.GetResource(SessionFactory); + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug("Found thread-bound Session [" + sessionHolder.Session + + "] for Hibernate transaction"); + } + + txObject.SetSessionHolder(sessionHolder, false); + if (DbProvider != null) + { + ConnectionHolder conHolder = (ConnectionHolder) + TransactionSynchronizationManager.GetResource(DbProvider); + txObject.ConnectionHolder = conHolder; } } - /// - /// Gets or sets the SessionFactory that this instance should manage transactions for. - /// - /// The session factory. - public ISessionFactory SessionFactory + return txObject; + } + + /// + /// Check if the given transaction object indicates an existing, + /// i.e. already begun, transaction. + /// + /// + /// Transaction object returned by + /// . + /// + /// True if there is an existing transaction. + /// + /// In the case of system errors. + /// + protected override bool IsExistingTransaction(object transaction) + { + return ((HibernateTransactionObject) transaction).HasTransaction(); + } + + /// + /// Begin a new transaction with the given transaction definition. + /// + /// + /// Transaction object returned by + /// . + /// + /// + /// instance, describing + /// propagation behavior, isolation level, timeout etc. + /// + /// + /// Does not have to care about applying the propagation behavior, + /// as this has already been handled by this abstract manager. + /// + /// + /// In the case of creation or system errors. + /// + protected override void DoBegin(object transaction, ITransactionDefinition definition) + { + HibernateTransactionObject txObject = (HibernateTransactionObject) transaction; + + if (DbProvider != null && TransactionSynchronizationManager.HasResource(DbProvider) + && !txObject.ConnectionHolder.SynchronizedWithTransaction) { - get { return sessionFactory; } - set { sessionFactory = value; } + throw new IllegalTransactionStateException( + "Pre-bound ADO.NET Connection found - HibernateTransactionManager does not support " + + "running within AdoTransactionManager if told to manage the DbProvider itself. " + + "It is recommended to use a single HibernateTransactionManager for all transactions " + + "on a single DbProvider, no matter whether Hibernate or ADO.NET access."); } - - /// - /// Gets the resource factory that this transaction manager operates on, - /// For the HibenratePlatformTransactionManager this the SessionFactory - /// - /// The SessionFactory. - public object ResourceFactory + ISession session = null; + try { - get { return sessionFactory; } - } - - /// - /// Set whether to autodetect a ADO.NET connection used by the Hibernate SessionFactory, - /// if set via LocalSessionFactoryObject's DbProvider. Default is "true". - /// - /// - /// true if [autodetect data source]; otherwise, false. - /// - /// - ///

Can be turned off to deliberately ignore an available IDbProvider, - /// to not expose Hibernate transactions as ADO.NET transactions for that IDbProvider. - ///

- ///
- public bool AutodetectDbProvider - { - set { autodetectDbProvider = value; } - } - - /// - /// The object factory just needs to be known for resolving entity interceptor - /// It does not need to be set for any other mode of operation. - /// - /// - /// Owning - /// (may not be ). The object can immediately - /// call methods on the factory. - /// - public IObjectFactory ObjectFactory - { - set - { - objectFactory = value; - } - } - - /// - /// Return the current transaction object. - /// - /// The current transaction object. - /// - /// If transaction support is not available. - /// - /// - /// In the case of lookup or system errors. - /// - protected override object DoGetTransaction() - { - HibernateTransactionObject txObject = new HibernateTransactionObject(); - txObject.SavepointAllowed = NestedTransactionsAllowed; - if (TransactionSynchronizationManager.HasResource(SessionFactory)) - { - SessionHolder sessionHolder = - (SessionHolder)TransactionSynchronizationManager.GetResource(SessionFactory); - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug("Found thread-bound Session [" + sessionHolder.Session + - "] for Hibernate transaction"); - } - txObject.SetSessionHolder(sessionHolder, false); - if (DbProvider != null) - { - ConnectionHolder conHolder = (ConnectionHolder) - TransactionSynchronizationManager.GetResource(DbProvider); - txObject.ConnectionHolder = conHolder; - } - } - return txObject; - } - - /// - /// Check if the given transaction object indicates an existing, - /// i.e. already begun, transaction. - /// - /// - /// Transaction object returned by - /// . - /// - /// True if there is an existing transaction. - /// - /// In the case of system errors. - /// - protected override bool IsExistingTransaction(object transaction) - { - return ((HibernateTransactionObject)transaction).HasTransaction(); - } - - /// - /// Begin a new transaction with the given transaction definition. - /// - /// - /// Transaction object returned by - /// . - /// - /// - /// instance, describing - /// propagation behavior, isolation level, timeout etc. - /// - /// - /// Does not have to care about applying the propagation behavior, - /// as this has already been handled by this abstract manager. - /// - /// - /// In the case of creation or system errors. - /// - protected override void DoBegin(object transaction, ITransactionDefinition definition) - { - HibernateTransactionObject txObject = (HibernateTransactionObject)transaction; - - if (DbProvider != null && TransactionSynchronizationManager.HasResource(DbProvider) - && !txObject.ConnectionHolder.SynchronizedWithTransaction) - { - throw new IllegalTransactionStateException( - "Pre-bound ADO.NET Connection found - HibernateTransactionManager does not support " + - "running within AdoTransactionManager if told to manage the DbProvider itself. " + - "It is recommended to use a single HibernateTransactionManager for all transactions " + - "on a single DbProvider, no matter whether Hibernate or ADO.NET access."); - } - ISession session = null; - try - { - - - if (txObject.SessionHolder == null || txObject.SessionHolder.SynchronizedWithTransaction) + if (txObject.SessionHolder == null || txObject.SessionHolder.SynchronizedWithTransaction) //if (txObject.SessionHolder == null || (txObject.SessionHolder.SynchronizedWithTransaction && TransactionSynchronizationManager.SynchronizationActive)) //if (txObject.SessionHolder == null || (txObject.SessionHolder.SynchronizedWithTransaction && TransactionSynchronizationManager.ActualTransactionActive)) + { + IInterceptor interceptor = EntityInterceptor; + ISession newSession = (interceptor != null ? SessionFactory.OpenSession(interceptor) : SessionFactory.OpenSession()); + + if (log.IsEnabled(LogLevel.Debug)) { - IInterceptor interceptor = EntityInterceptor; - ISession newSession = (interceptor != null ? - SessionFactory.OpenSession(interceptor) : SessionFactory.OpenSession()); - - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug("Opened new Session [" + newSession + "] for Hibernate transaction"); - } - txObject.SetSessionHolder(new SessionHolder(newSession), true); - - } - txObject.SessionHolder.SynchronizedWithTransaction = true; - session = txObject.SessionHolder.Session; - - IDbConnection con = session.Connection; - //TODO isolation level mgmt - //IsolationLevel previousIsolationLevel = - - if (definition.ReadOnly && txObject.NewSessionHolder) - { - // Just set to NEVER in case of a new Session for this transaction. - session.FlushMode = FlushMode.Never; + log.LogDebug("Opened new Session [" + newSession + "] for Hibernate transaction"); } - if (!definition.ReadOnly && !txObject.NewSessionHolder) + txObject.SetSessionHolder(new SessionHolder(newSession), true); + } + + txObject.SessionHolder.SynchronizedWithTransaction = true; + session = txObject.SessionHolder.Session; + + IDbConnection con = session.Connection; + //TODO isolation level mgmt + //IsolationLevel previousIsolationLevel = + + if (definition.ReadOnly && txObject.NewSessionHolder) + { + // Just set to NEVER in case of a new Session for this transaction. + session.FlushMode = FlushMode.Never; + } + + if (!definition.ReadOnly && !txObject.NewSessionHolder) + { + // We need AUTO or COMMIT for a non-read-only transaction. + FlushMode flushMode = session.FlushMode; + if (FlushMode.Never == flushMode) { - // We need AUTO or COMMIT for a non-read-only transaction. - FlushMode flushMode = session.FlushMode; - if (FlushMode.Never == flushMode) - { - session.FlushMode = FlushMode.Auto; - txObject.SessionHolder.PreviousFlushMode = flushMode; - } + session.FlushMode = FlushMode.Auto; + txObject.SessionHolder.PreviousFlushMode = flushMode; } + } - // Add the Hibernate transaction to the session holder. - // for now pass in tx options isolation level. - ITransaction hibernateTx = session.BeginTransaction(definition.TransactionIsolationLevel); - IDbTransaction adoTx = GetIDbTransaction(hibernateTx); + // Add the Hibernate transaction to the session holder. + // for now pass in tx options isolation level. + ITransaction hibernateTx = session.BeginTransaction(definition.TransactionIsolationLevel); + IDbTransaction adoTx = GetIDbTransaction(hibernateTx); - // Add the Hibernate transaction to the session holder. - txObject.SessionHolder.Transaction = hibernateTx; + // Add the Hibernate transaction to the session holder. + txObject.SessionHolder.Transaction = hibernateTx; - // Register transaction timeout. - int timeout = DetermineTimeout(definition); + // Register transaction timeout. + int timeout = DetermineTimeout(definition); + if (timeout != DefaultTransactionDefinition.TIMEOUT_DEFAULT) + { + txObject.SessionHolder.TimeoutInSeconds = timeout; + } + + // Register the Hibernate Session's ADO.NET Connection/TX pair for the DbProvider, if set. + if (DbProvider != null) + { + //investigate passing null for tx. + ConnectionHolder conHolder = new ConnectionHolder(con, adoTx); if (timeout != DefaultTransactionDefinition.TIMEOUT_DEFAULT) { - txObject.SessionHolder.TimeoutInSeconds = timeout; + conHolder.TimeoutInSeconds = timeout; } - // Register the Hibernate Session's ADO.NET Connection/TX pair for the DbProvider, if set. - if (DbProvider != null) + if (log.IsEnabled(LogLevel.Debug)) { - //investigate passing null for tx. - ConnectionHolder conHolder = new ConnectionHolder(con, adoTx); - if (timeout != DefaultTransactionDefinition.TIMEOUT_DEFAULT) - { - conHolder.TimeoutInSeconds = timeout; - } - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug("Exposing Hibernate transaction as ADO transaction [" + con + "]"); - } - TransactionSynchronizationManager.BindResource(DbProvider, conHolder); - txObject.ConnectionHolder = conHolder; + log.LogDebug("Exposing Hibernate transaction as ADO transaction [" + con + "]"); } - // Bind the session holder to the thread. - if (txObject.NewSessionHolder) - { - TransactionSynchronizationManager.BindResource(SessionFactory, txObject.SessionHolder); - } - - } - catch (Exception ex) - { - SessionFactoryUtils.CloseSession(session); - throw new CannotCreateTransactionException("Could not open Hibernate Session for transaction", ex); + TransactionSynchronizationManager.BindResource(DbProvider, conHolder); + txObject.ConnectionHolder = conHolder; } - - } - - - - - /// - /// Suspend the resources of the current transaction. - /// - /// - /// Transaction object returned by - /// . - /// - /// - /// An object that holds suspended resources (will be kept unexamined for passing it into - /// .) - /// - /// - /// Transaction synchronization will already have been suspended. - /// - /// - /// If suspending is not supported by the transaction manager implementation. - /// - /// - /// in case of system errors. - /// - protected override object DoSuspend(object transaction) - { - HibernateTransactionObject txObject = (HibernateTransactionObject)transaction; - txObject.SetSessionHolder(null, false); - SessionHolder sessionHolder = - (SessionHolder)TransactionSynchronizationManager.UnbindResource(SessionFactory); - ConnectionHolder connectionHolder = null; - if (DbProvider != null) + // Bind the session holder to the thread. + if (txObject.NewSessionHolder) { - connectionHolder = (ConnectionHolder)TransactionSynchronizationManager.UnbindResource(DbProvider); - } - return new SuspendedResourcesHolder(sessionHolder, connectionHolder); - - } - - /// - /// Resume the resources of the current transaction. - /// - /// - /// Transaction object returned by - /// . - /// - /// - /// The object that holds suspended resources as returned by - /// . - /// - /// - /// Transaction synchronization will be resumed afterwards. - /// - /// - /// If suspending is not supported by the transaction manager implementation. - /// - /// - /// In the case of system errors. - /// - protected override void DoResume(object transaction, object suspendedResources) - { - SuspendedResourcesHolder resourcesHolder = (SuspendedResourcesHolder)suspendedResources; - if (TransactionSynchronizationManager.HasResource(SessionFactory)) - { - // From non-transactional code running in active transaction synchronization - // -> can be safely removed, will be closed on transaction completion. - TransactionSynchronizationManager.UnbindResource(SessionFactory); - } - TransactionSynchronizationManager.BindResource(SessionFactory, resourcesHolder.SessionHolder); - if (DbProvider != null) - { - TransactionSynchronizationManager.BindResource(DbProvider, resourcesHolder.ConnectionHolder); + TransactionSynchronizationManager.BindResource(SessionFactory, txObject.SessionHolder); } } - - /// - /// Perform an actual commit on the given transaction. - /// - /// The status representation of the transaction. - /// - ///

- /// An implementation does not need to check the rollback-only flag. - ///

- ///
- /// - /// In the case of system errors. - /// - protected override void DoCommit(DefaultTransactionStatus status) + catch (Exception ex) { - HibernateTransactionObject txObject = (HibernateTransactionObject)status.Transaction; - if (status.Debug) + SessionFactoryUtils.CloseSession(session); + throw new CannotCreateTransactionException("Could not open Hibernate Session for transaction", ex); + } + } + + /// + /// Suspend the resources of the current transaction. + /// + /// + /// Transaction object returned by + /// . + /// + /// + /// An object that holds suspended resources (will be kept unexamined for passing it into + /// .) + /// + /// + /// Transaction synchronization will already have been suspended. + /// + /// + /// If suspending is not supported by the transaction manager implementation. + /// + /// + /// in case of system errors. + /// + protected override object DoSuspend(object transaction) + { + HibernateTransactionObject txObject = (HibernateTransactionObject) transaction; + txObject.SetSessionHolder(null, false); + SessionHolder sessionHolder = + (SessionHolder) TransactionSynchronizationManager.UnbindResource(SessionFactory); + ConnectionHolder connectionHolder = null; + if (DbProvider != null) + { + connectionHolder = (ConnectionHolder) TransactionSynchronizationManager.UnbindResource(DbProvider); + } + + return new SuspendedResourcesHolder(sessionHolder, connectionHolder); + } + + /// + /// Resume the resources of the current transaction. + /// + /// + /// Transaction object returned by + /// . + /// + /// + /// The object that holds suspended resources as returned by + /// . + /// + /// + /// Transaction synchronization will be resumed afterwards. + /// + /// + /// If suspending is not supported by the transaction manager implementation. + /// + /// + /// In the case of system errors. + /// + protected override void DoResume(object transaction, object suspendedResources) + { + SuspendedResourcesHolder resourcesHolder = (SuspendedResourcesHolder) suspendedResources; + if (TransactionSynchronizationManager.HasResource(SessionFactory)) + { + // From non-transactional code running in active transaction synchronization + // -> can be safely removed, will be closed on transaction completion. + TransactionSynchronizationManager.UnbindResource(SessionFactory); + } + + TransactionSynchronizationManager.BindResource(SessionFactory, resourcesHolder.SessionHolder); + if (DbProvider != null) + { + TransactionSynchronizationManager.BindResource(DbProvider, resourcesHolder.ConnectionHolder); + } + } + + /// + /// Perform an actual commit on the given transaction. + /// + /// The status representation of the transaction. + /// + ///

+ /// An implementation does not need to check the rollback-only flag. + ///

+ ///
+ /// + /// In the case of system errors. + /// + protected override void DoCommit(DefaultTransactionStatus status) + { + HibernateTransactionObject txObject = (HibernateTransactionObject) status.Transaction; + if (status.Debug) + { + log.LogDebug("Committing Hibernate transaction on Session [" + + txObject.SessionHolder.Session + "]"); + } + + try + { + txObject.SessionHolder.Transaction.Commit(); + } + // Note, unfortunate collision of namespaces/classname for NHibernate.TransactionException + // and Spring.Data.NHibernate requires this wierd construct. + catch (Exception ex) + { + Type nhibTxExceptiontype = TypeResolutionUtils.ResolveType("NHibernate.TransactionException, NHibernate"); + if (ex.GetType().Equals(nhibTxExceptiontype)) { - log.LogDebug("Committing Hibernate transaction on Session [" + - txObject.SessionHolder.Session + "]"); + // assumably from commit call to the underlying ADO.NET connection + throw new TransactionSystemException("Could not commit Hibernate transaction", ex); } + + HibernateException hibEx = ex as HibernateException; + if (hibEx != null) + { + // assumably failed to flush changes to database + throw ConvertHibernateAccessException(hibEx); + } + + throw; + } + } + + /// + /// Perform an actual rollback on the given transaction. + /// + /// The status representation of the transaction. + /// + /// An implementation does not need to check the new transaction flag. + /// + /// + /// In the case of system errors. + /// + protected override void DoRollback(DefaultTransactionStatus status) + { + HibernateTransactionObject txObject = (HibernateTransactionObject) status.Transaction; + + if (status.Debug) + { + log.LogDebug("Rolling back Hibernate transaction on Session [" + + txObject.SessionHolder.Session + "]"); + } + + try + { + IDbTransaction adoTx = GetIDbTransaction(txObject.SessionHolder.Transaction); + + if (adoTx != null && adoTx.Connection != null) + { + txObject.SessionHolder.Transaction.Rollback(); + } + } + catch (HibernateTransactionException ex) + { + throw new TransactionSystemException("Could not roll back Hibernate transaction", ex); + } + catch (HibernateException ex) + { + // Shouldn't really happen, as a rollback doesn't cause a flush. + throw ConvertHibernateAccessException(ex); + } + finally + { + if (!txObject.NewSessionHolder) + { + // Clear all pending inserts/updates/deletes in the Session. + // Necessary for pre-bound Sessions, to avoid inconsistent state. + txObject.SessionHolder.Session.Clear(); + } + } + } + + /// + /// Set the given transaction rollback-only. Only called on rollback + /// if the current transaction takes part in an existing one. + /// + /// The status representation of the transaction. + /// + /// In the case of system errors. + /// + protected override void DoSetRollbackOnly(DefaultTransactionStatus status) + { + HibernateTransactionObject txObject = (HibernateTransactionObject) status.Transaction; + if (status.Debug) + { + log.LogDebug("Setting Hibernate transaction on Session [" + + txObject.SessionHolder.Session + "] rollback-only"); + } + + txObject.SetRollbackOnly(); + } + + /// + /// Gets the ADO.NET IDbTransaction object from the NHibernate ITransaction object. + /// + /// The hibernate transaction. + /// The ADO.NET transaction. Null if could not get the transaction. Warning + /// messages will be logged in that case. + protected virtual IDbTransaction GetIDbTransaction(ITransaction hibernateTx) + { + AdoTransaction hibernateAdoTx = hibernateTx as AdoTransaction; + + IDbTransaction adoTransaction = null; + if (hibernateAdoTx != null) + { try { - txObject.SessionHolder.Transaction.Commit(); + FieldInfo fi = typeof(AdoTransaction).GetField("trans", BindingFlags.Instance | BindingFlags.NonPublic); + adoTransaction = fi.GetValue(hibernateAdoTx) as IDbTransaction; } - // Note, unfortunate collision of namespaces/classname for NHibernate.TransactionException - // and Spring.Data.NHibernate requires this wierd construct. - catch (Exception ex) + catch (Exception e) { - Type nhibTxExceptiontype = TypeResolutionUtils.ResolveType("NHibernate.TransactionException, NHibernate"); - if (ex.GetType().Equals(nhibTxExceptiontype)) - { - // assumably from commit call to the underlying ADO.NET connection - throw new TransactionSystemException("Could not commit Hibernate transaction", ex); - } - HibernateException hibEx = ex as HibernateException; - if (hibEx != null) - { - // assumably failed to flush changes to database - throw ConvertHibernateAccessException(hibEx); - } - throw; + log.LogWarning(e, "Could not extract IDbTransaction from Hibernate AdoTransaction using field name trans."); + } + } + else + { + log.LogWarning("Hibernate ITransaction not of expected type AdoTransaction. Could not extract IDbTransaction from Hibernate AdoTransaction."); + } + + return adoTransaction; + } + + /// + /// Convert the given HibernateException to an appropriate exception from + /// the Spring.Dao hierarchy. Can be overridden in subclasses. + /// + /// The HibernateException that occured. + /// The corresponding DataAccessException instance + protected virtual DataAccessException ConvertHibernateAccessException(HibernateException ex) + { + if (AdoExceptionTranslator != null && ex is ADOException) + { + return ConvertAdoAccessException((ADOException) ex, AdoExceptionTranslator); + } + else if (ex is ADOException) + { + return ConvertAdoAccessException((ADOException) ex, DefaultAdoExceptionTranslator); + } + + return SessionFactoryUtils.ConvertHibernateAccessException(ex); + } + + /// + /// Convert the given ADOException to an appropriate exception from the + /// the Spring.Dao hierarchy. Can be overridden in subclasses. + /// + /// The ADOException that occured, wrapping the underlying + /// ADO.NET thrown exception. + /// The translator to convert hibernate ADOExceptions. + /// + /// The corresponding DataAccessException instance + /// + protected virtual DataAccessException ConvertAdoAccessException(ADOException ex, IAdoExceptionTranslator translator) + { + return translator.Translate("Hibernate flusing: " + ex.Message, null, ex.InnerException); + } + + /// + /// Cleanup resources after transaction completion. + /// + /// Transaction object returned by + /// . + /// + /// + /// This implemenation unbinds the SessionFactory and + /// DbProvider from thread local storage and closes the + /// ISession. + /// + ///

+ /// Called after + /// and + /// + /// execution on any outcome. + ///

+ ///

+ /// Should not throw any exceptions but just issue warnings on errors. + ///

+ ///
+ protected override void DoCleanupAfterCompletion(object transaction) + { + HibernateTransactionObject txObject = (HibernateTransactionObject) transaction; + + // Remove the session holder from the thread. + if (txObject.NewSessionHolder) + { + TransactionSynchronizationManager.UnbindResource(SessionFactory); + } + + // Remove the ADO.NET connection holder from the thread, if exposed. + if (DbProvider != null) + { + TransactionSynchronizationManager.UnbindResource(DbProvider); + } + + ISession session = txObject.SessionHolder.Session; + if (txObject.NewSessionHolder) + { + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug("Closing Hibernate Session [" + session + "] after transaction"); + } + + SessionFactoryUtils.CloseSessionOrRegisterDeferredClose(session, SessionFactory); + } + else + { + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug("Not closing pre-bound Hibernate Session [" + session + "] after transaction"); + } + + if (txObject.SessionHolder.AssignedPreviousFlushMode) + { + session.FlushMode = txObject.SessionHolder.PreviousFlushMode; + } + } + + txObject.SessionHolder.Clear(); + } + + /// + /// Hibernate-specific Tx-Aware Object + /// + protected class HibernateTransactionObject : AdoTransactionObjectSupport + { + private SessionHolder sessionHolder; + + private bool newSessionHolder; + + /// + /// Sets the session holder. + /// + /// The session holder. + /// if set to true [new session holder]. + public void SetSessionHolder(SessionHolder sessionHolder, bool newSessionHolder) + { + this.sessionHolder = sessionHolder; + this.newSessionHolder = newSessionHolder; + } + + /// + /// Gets the session holder. + /// + /// + /// The session holder. + /// + public SessionHolder SessionHolder + { + get + { + return sessionHolder; } } /// - /// Perform an actual rollback on the given transaction. + /// Gets a value indicating whether a new session holder is present. /// - /// The status representation of the transaction. - /// - /// An implementation does not need to check the new transaction flag. - /// - /// - /// In the case of system errors. - /// - protected override void DoRollback(DefaultTransactionStatus status) + /// + /// true if new session holder; otherwise, false. + /// + public bool NewSessionHolder { - HibernateTransactionObject txObject = (HibernateTransactionObject)status.Transaction; - - if (status.Debug) + get { - log.LogDebug("Rolling back Hibernate transaction on Session [" + - txObject.SessionHolder.Session + "]"); + return newSessionHolder; } - try - { - IDbTransaction adoTx = GetIDbTransaction(txObject.SessionHolder.Transaction); - - if (adoTx != null && adoTx.Connection != null) - { - txObject.SessionHolder.Transaction.Rollback(); - } - } - catch (HibernateTransactionException ex) - { - throw new TransactionSystemException("Could not roll back Hibernate transaction", ex); - } - catch (HibernateException ex) - { - // Shouldn't really happen, as a rollback doesn't cause a flush. - throw ConvertHibernateAccessException(ex); - } - finally - { - if (!txObject.NewSessionHolder) - { - // Clear all pending inserts/updates/deletes in the Session. - // Necessary for pre-bound Sessions, to avoid inconsistent state. - txObject.SessionHolder.Session.Clear(); - } - } - - - } - /// - /// Set the given transaction rollback-only. Only called on rollback - /// if the current transaction takes part in an existing one. + /// Determines whether this instance has a transaction. /// - /// The status representation of the transaction. - /// - /// In the case of system errors. - /// - protected override void DoSetRollbackOnly(DefaultTransactionStatus status) + /// + public bool HasTransaction() { - HibernateTransactionObject txObject = (HibernateTransactionObject)status.Transaction; - if (status.Debug) - { - log.LogDebug("Setting Hibernate transaction on Session [" + - txObject.SessionHolder.Session + "] rollback-only"); - } - txObject.SetRollbackOnly(); + return (this.sessionHolder != null && this.sessionHolder.Transaction != null); } + /// + /// Sets the transaction as internally marked as rollback-only. + /// + public void SetRollbackOnly() + { + SessionHolder.RollbackOnly = true; + if (ConnectionHolder != null) + { + ConnectionHolder.RollbackOnly = true; + } + } /// - /// Gets the ADO.NET IDbTransaction object from the NHibernate ITransaction object. + /// Return whether the transaction is internally marked as rollback-only. /// - /// The hibernate transaction. - /// The ADO.NET transaction. Null if could not get the transaction. Warning - /// messages will be logged in that case. - protected virtual IDbTransaction GetIDbTransaction(ITransaction hibernateTx) + /// + /// True of the transaction is marked as rollback-only. + public override bool RollbackOnly { - AdoTransaction hibernateAdoTx = hibernateTx as AdoTransaction; - - IDbTransaction adoTransaction = null; - if (hibernateAdoTx != null) + get { - try + return SessionHolder.RollbackOnly || + (ConnectionHolder != null && ConnectionHolder.RollbackOnly); + } + } + } + + /// + /// Holds Suspended Resources + /// + protected class SuspendedResourcesHolder + { + private readonly SessionHolder sessionHolder; + + private readonly ConnectionHolder connectionHolder; + + /// + /// Initializes a new instance of the class. + /// + /// The session holder. + /// The connection holder. + public SuspendedResourcesHolder(SessionHolder sessionHolder, ConnectionHolder conHolder) + { + this.sessionHolder = sessionHolder; + this.connectionHolder = conHolder; + } + + /// + /// Gets the session holder. + /// + /// + /// The session holder. + /// + public SessionHolder SessionHolder + { + get + { + return sessionHolder; + } + } + + /// + /// Gets the connection holder. + /// + /// + /// The connection holder. + /// + public ConnectionHolder ConnectionHolder + { + get + { + return connectionHolder; + } + } + } + + /// + /// Invoked by an + /// after it has injected all of an object's dependencies. + /// + /// + ///

+ /// This method allows the object instance to perform the kind of + /// initialization only possible when all of it's dependencies have + /// been injected (set), and to throw an appropriate exception in the + /// event of misconfiguration. + ///

+ ///

+ /// Please do consult the class level documentation for the + /// interface for a + /// description of exactly when this method is invoked. In + /// particular, it is worth noting that the + /// + /// and + /// callbacks will have been invoked prior to this method being + /// called. + ///

+ ///
+ /// + /// In the event of misconfiguration (such as the failure to set a + /// required property) or if initialization fails. + /// + public void AfterPropertiesSet() + { + if (SessionFactory == null) + { + throw new ArgumentException("sessionFactory is required"); + } + + if (this.entityInterceptor is string && this.objectFactory == null) + { + throw new ArgumentException("objectFactory is required for entityInterceptorBeanName"); + } + + // Try to derive a DbProvider given the SessionFactory. + if (this.autodetectDbProvider && DbProvider == null) + { + IDbProvider sfDbProvider = SessionFactoryUtils.GetDbProvider(SessionFactory); + if (sfDbProvider != null) + { + // Use the SessionFactory's DataSource for exposing transactions to ADO.NET code. + if (log.IsEnabled(LogLevel.Information)) { - FieldInfo fi = typeof(AdoTransaction).GetField("trans", BindingFlags.Instance | BindingFlags.NonPublic); - adoTransaction = fi.GetValue(hibernateAdoTx) as IDbTransaction; - } - catch (Exception e) - { - log.LogWarning(e, "Could not extract IDbTransaction from Hibernate AdoTransaction using field name trans."); + log.LogInformation("Derived DbProvider [" + sfDbProvider.DbMetadata.ProductName + + "] of Hibernate SessionFactory for HibernateTransactionManager"); } + + DbProvider = sfDbProvider; } else { - log.LogWarning("Hibernate ITransaction not of expected type AdoTransaction. Could not extract IDbTransaction from Hibernate AdoTransaction."); - } - return adoTransaction; - } - - /// - /// Convert the given HibernateException to an appropriate exception from - /// the Spring.Dao hierarchy. Can be overridden in subclasses. - /// - /// The HibernateException that occured. - /// The corresponding DataAccessException instance - protected virtual DataAccessException ConvertHibernateAccessException(HibernateException ex) - { - if (AdoExceptionTranslator != null && ex is ADOException) - { - return ConvertAdoAccessException((ADOException)ex, AdoExceptionTranslator); - } - else if (ex is ADOException) - { - return ConvertAdoAccessException((ADOException)ex, DefaultAdoExceptionTranslator); - } - return SessionFactoryUtils.ConvertHibernateAccessException(ex); - } - - /// - /// Convert the given ADOException to an appropriate exception from the - /// the Spring.Dao hierarchy. Can be overridden in subclasses. - /// - /// The ADOException that occured, wrapping the underlying - /// ADO.NET thrown exception. - /// The translator to convert hibernate ADOExceptions. - /// - /// The corresponding DataAccessException instance - /// - protected virtual DataAccessException ConvertAdoAccessException(ADOException ex, IAdoExceptionTranslator translator) - { - return translator.Translate("Hibernate flusing: " + ex.Message, null, ex.InnerException); - } - - /// - /// Cleanup resources after transaction completion. - /// - /// Transaction object returned by - /// . - /// - /// - /// This implemenation unbinds the SessionFactory and - /// DbProvider from thread local storage and closes the - /// ISession. - /// - ///

- /// Called after - /// and - /// - /// execution on any outcome. - ///

- ///

- /// Should not throw any exceptions but just issue warnings on errors. - ///

- ///
- protected override void DoCleanupAfterCompletion(object transaction) - { - HibernateTransactionObject txObject = (HibernateTransactionObject)transaction; - - // Remove the session holder from the thread. - if (txObject.NewSessionHolder) - { - TransactionSynchronizationManager.UnbindResource(SessionFactory); - } - // Remove the ADO.NET connection holder from the thread, if exposed. - if (DbProvider != null) - { - TransactionSynchronizationManager.UnbindResource(DbProvider); - } - - ISession session = txObject.SessionHolder.Session; - if (txObject.NewSessionHolder) - { - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug("Closing Hibernate Session [" + session + "] after transaction"); - } - SessionFactoryUtils.CloseSessionOrRegisterDeferredClose(session, SessionFactory); - } - else - { - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug("Not closing pre-bound Hibernate Session [" + session + "] after transaction"); - } - if (txObject.SessionHolder.AssignedPreviousFlushMode) - { - session.FlushMode = txObject.SessionHolder.PreviousFlushMode; - } - } - txObject.SessionHolder.Clear(); - - - } - - - /// - /// Hibernate-specific Tx-Aware Object - /// - protected class HibernateTransactionObject : AdoTransactionObjectSupport - { - - private SessionHolder sessionHolder; - - private bool newSessionHolder; - - - /// - /// Sets the session holder. - /// - /// The session holder. - /// if set to true [new session holder]. - public void SetSessionHolder(SessionHolder sessionHolder, bool newSessionHolder) - { - this.sessionHolder = sessionHolder; - this.newSessionHolder = newSessionHolder; - } - - - /// - /// Gets the session holder. - /// - /// - /// The session holder. - /// - public SessionHolder SessionHolder - { - get - { - return sessionHolder; - } - } - - /// - /// Gets a value indicating whether a new session holder is present. - /// - /// - /// true if new session holder; otherwise, false. - /// - public bool NewSessionHolder - { - get - { - return newSessionHolder; - } - } - - /// - /// Determines whether this instance has a transaction. - /// - /// - public bool HasTransaction() - { - return (this.sessionHolder != null && this.sessionHolder.Transaction != null); - } - - /// - /// Sets the transaction as internally marked as rollback-only. - /// - public void SetRollbackOnly() - { - SessionHolder.RollbackOnly = true; - if (ConnectionHolder != null) - { - ConnectionHolder.RollbackOnly = true; - } - } - - /// - /// Return whether the transaction is internally marked as rollback-only. - /// - /// - /// True of the transaction is marked as rollback-only. - public override bool RollbackOnly - { - get - { - return SessionHolder.RollbackOnly || - (ConnectionHolder != null && ConnectionHolder.RollbackOnly); - } - } - } - - - /// - /// Holds Suspended Resources - /// - protected class SuspendedResourcesHolder - { - - private readonly SessionHolder sessionHolder; - - private readonly ConnectionHolder connectionHolder; - - /// - /// Initializes a new instance of the class. - /// - /// The session holder. - /// The connection holder. - public SuspendedResourcesHolder(SessionHolder sessionHolder, ConnectionHolder conHolder) - { - this.sessionHolder = sessionHolder; - this.connectionHolder = conHolder; - } - - /// - /// Gets the session holder. - /// - /// - /// The session holder. - /// - public SessionHolder SessionHolder - { - get - { - return sessionHolder; - } - - } - - /// - /// Gets the connection holder. - /// - /// - /// The connection holder. - /// - public ConnectionHolder ConnectionHolder - { - get - { - return connectionHolder; - } - - } - } - - /// - /// Invoked by an - /// after it has injected all of an object's dependencies. - /// - /// - ///

- /// This method allows the object instance to perform the kind of - /// initialization only possible when all of it's dependencies have - /// been injected (set), and to throw an appropriate exception in the - /// event of misconfiguration. - ///

- ///

- /// Please do consult the class level documentation for the - /// interface for a - /// description of exactly when this method is invoked. In - /// particular, it is worth noting that the - /// - /// and - /// callbacks will have been invoked prior to this method being - /// called. - ///

- ///
- /// - /// In the event of misconfiguration (such as the failure to set a - /// required property) or if initialization fails. - /// - public void AfterPropertiesSet() - { - if (SessionFactory == null) - { - throw new ArgumentException("sessionFactory is required"); - } - if (this.entityInterceptor is string && this.objectFactory == null) - { - throw new ArgumentException("objectFactory is required for entityInterceptorBeanName"); - } - - // Try to derive a DbProvider given the SessionFactory. - if (this.autodetectDbProvider && DbProvider == null) - { - IDbProvider sfDbProvider = SessionFactoryUtils.GetDbProvider(SessionFactory); - if (sfDbProvider != null) - { - // Use the SessionFactory's DataSource for exposing transactions to ADO.NET code. - if (log.IsEnabled(LogLevel.Information)) - { - log.LogInformation("Derived DbProvider [" + sfDbProvider.DbMetadata.ProductName + - "] of Hibernate SessionFactory for HibernateTransactionManager"); - } - DbProvider = sfDbProvider; - } - else - { - log.LogInformation("Could not auto detect DbProvider from SessionFactory configuration"); - } - + log.LogInformation("Could not auto detect DbProvider from SessionFactory configuration"); } } } diff --git a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/HibernateTxScopeTransactionManager.cs b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/HibernateTxScopeTransactionManager.cs index 22ee4c88..10b524a6 100644 --- a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/HibernateTxScopeTransactionManager.cs +++ b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/HibernateTxScopeTransactionManager.cs @@ -1,12 +1,12 @@ /* * Copyright � 2002-2011 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. @@ -20,7 +20,6 @@ using System.Transactions; using Microsoft.Extensions.Logging; using NHibernate; using NHibernate.Transaction; - using Spring.Core.TypeResolution; using Spring.Dao; using Spring.Data.Common; @@ -30,678 +29,674 @@ using Spring.Objects.Factory; using Spring.Transaction; using Spring.Transaction.Support; -namespace Spring.Data.NHibernate +namespace Spring.Data.NHibernate; + +/// +/// PlatformTransactionManager implementation for a single Hibernate SessionFactory. +/// Binds a Hibernate Session from the specified factory to the thread, potentially +/// allowing for one thread Session per factory +/// +/// +/// SessionFactoryUtils and HibernateTemplate are aware of thread-bound Sessions and participate in such +/// transactions automatically. Using either of those is required for Hibernate +/// access code that needs to support this transaction handling mechanism. +/// +/// Supports custom isolation levels at the start of the transaction +/// , and timeouts that get applied as appropriate +/// Hibernate query timeouts. To support the latter, application code must either use +/// HibernateTemplate (which by default applies the timeouts) or call +/// SessionFactoryUtils.applyTransactionTimeout for each created +/// Hibernate Query object. +/// +/// Note that you can specify a Spring IDbProvider instance which if shared with +/// a corresponding instance of AdoTemplate will allow for mixing ADO.NET/NHibernate +/// operations within a single transaction. +/// +/// Mark Pollack (.NET) +public class HibernateTxScopeTransactionManager : AbstractPlatformTransactionManager, IResourceTransactionManager, IObjectFactoryAware, IInitializingObject { + private ISessionFactory sessionFactory; + + private IDbProvider dbProvider; + + private bool autodetectDbProvider = true; + + private Object entityInterceptor; + + private IAdoExceptionTranslator adoExceptionTranslator; + + private IAdoExceptionTranslator defaultExceptionTranslator; + /// - /// PlatformTransactionManager implementation for a single Hibernate SessionFactory. - /// Binds a Hibernate Session from the specified factory to the thread, potentially - /// allowing for one thread Session per factory + /// Just needed for entityInterceptorBeanName. /// - /// - /// SessionFactoryUtils and HibernateTemplate are aware of thread-bound Sessions and participate in such - /// transactions automatically. Using either of those is required for Hibernate - /// access code that needs to support this transaction handling mechanism. - /// - /// Supports custom isolation levels at the start of the transaction - /// , and timeouts that get applied as appropriate - /// Hibernate query timeouts. To support the latter, application code must either use - /// HibernateTemplate (which by default applies the timeouts) or call - /// SessionFactoryUtils.applyTransactionTimeout for each created - /// Hibernate Query object. - /// - /// Note that you can specify a Spring IDbProvider instance which if shared with - /// a corresponding instance of AdoTemplate will allow for mixing ADO.NET/NHibernate - /// operations within a single transaction. - /// - /// Mark Pollack (.NET) - public class HibernateTxScopeTransactionManager : AbstractPlatformTransactionManager, IResourceTransactionManager, IObjectFactoryAware, IInitializingObject + private IObjectFactory objectFactory; + + private TxScopeTransactionManager txScopeTranactionManager; + + /// + /// Initializes a new instance of the class. + /// + public HibernateTxScopeTransactionManager() { - private ISessionFactory sessionFactory; + txScopeTranactionManager = new TxScopeTransactionManager(); + } - private IDbProvider dbProvider; + /// + /// Initializes a new instance of the class. + /// + /// The session factory. + public HibernateTxScopeTransactionManager(ISessionFactory sessionFactory) + { + this.sessionFactory = sessionFactory; + AfterPropertiesSet(); + } - private bool autodetectDbProvider = true; + /// + /// Gets or sets the db provider. + /// + /// The db provider. + public IDbProvider DbProvider + { + get { return dbProvider; } + set { dbProvider = value; } + } - private Object entityInterceptor; - - private IAdoExceptionTranslator adoExceptionTranslator; - - private IAdoExceptionTranslator defaultExceptionTranslator; - - /// - /// Just needed for entityInterceptorBeanName. - /// - private IObjectFactory objectFactory; - - private TxScopeTransactionManager txScopeTranactionManager; - - /// - /// Initializes a new instance of the class. - /// - public HibernateTxScopeTransactionManager() + /// + /// Gets or sets a Hibernate entity interceptor that allows to inspect and change + /// property values before writing to and reading from the database. + /// When getting, return the current Hibernate entity interceptor, or null if none. + /// + /// The entity interceptor. + /// + /// Resolves an entity interceptor object name via the object factory, + /// if necessary. + /// Will get applied to any new Session created by this transaction manager. + /// Such an interceptor can either be set at the SessionFactory level, + /// i.e. on LocalSessionFactoryObject, or at the Session level, i.e. on + /// HibernateTemplate, HibernateInterceptor, and HibernateTransactionManager. + /// It's preferable to set it on LocalSessionFactoryObject or HibernateTransactionManager + /// to avoid repeated configuration and guarantee consistent behavior in transactions. + /// + /// If object factory is null and need to get entity interceptor via object name. + public IInterceptor EntityInterceptor + { + get { - txScopeTranactionManager = new TxScopeTransactionManager(); - } - - /// - /// Initializes a new instance of the class. - /// - /// The session factory. - public HibernateTxScopeTransactionManager(ISessionFactory sessionFactory) - { - this.sessionFactory = sessionFactory; - AfterPropertiesSet(); - } - - /// - /// Gets or sets the db provider. - /// - /// The db provider. - public IDbProvider DbProvider - { - get { return dbProvider; } - set { dbProvider = value; } - } - - /// - /// Gets or sets a Hibernate entity interceptor that allows to inspect and change - /// property values before writing to and reading from the database. - /// When getting, return the current Hibernate entity interceptor, or null if none. - /// - /// The entity interceptor. - /// - /// Resolves an entity interceptor object name via the object factory, - /// if necessary. - /// Will get applied to any new Session created by this transaction manager. - /// Such an interceptor can either be set at the SessionFactory level, - /// i.e. on LocalSessionFactoryObject, or at the Session level, i.e. on - /// HibernateTemplate, HibernateInterceptor, and HibernateTransactionManager. - /// It's preferable to set it on LocalSessionFactoryObject or HibernateTransactionManager - /// to avoid repeated configuration and guarantee consistent behavior in transactions. - /// - /// If object factory is null and need to get entity interceptor via object name. - public IInterceptor EntityInterceptor - { - get + if (this.entityInterceptor is IInterceptor) { - if (this.entityInterceptor is IInterceptor) + return (IInterceptor) entityInterceptor; + } + else if (this.entityInterceptor is string) + { + if (this.objectFactory == null) { - return (IInterceptor)entityInterceptor; - } - else if (this.entityInterceptor is string) - { - if (this.objectFactory == null) - { - throw new InvalidOperationException("Cannot get entity interceptor via object name if no object factory set"); - } - String objectName = (String)this.entityInterceptor; - return (IInterceptor)this.objectFactory.GetObject(objectName, typeof(IInterceptor)); - } - else - { - return null; - } - } - set - { - entityInterceptor = value; - } - } - - /// - /// Sets the object name of a Hibernate entity interceptor that - /// allows to inspect and change property values before writing to and reading from the database. - /// - /// The name of the entity interceptor object. - /// - /// Will get applied to any new Session created by this transaction manager. - ///

Requires the object factory to be known, to be able to resolve the object - /// name to an interceptor instance on session creation. Typically used for - /// prototype interceptors, i.e. a new interceptor instance per session. - ///

- ///

Can also be used for shared interceptor instances, but it is recommended - /// to set the interceptor reference directly in such a scenario. - ///

- ///
- public string EntityInterceptorObjectName - { - set - { - entityInterceptor = value; - } - } - - /// - /// Gets or sets the ADO.NET exception translator for this transaction manager. - /// - /// - /// Applied to ADO.NET Exceptions (wrapped by Hibernate's ADOException) - /// - /// The ADO exception translator. - public IAdoExceptionTranslator AdoExceptionTranslator - { - get { return adoExceptionTranslator; } - set { adoExceptionTranslator = value; } - } - - /// - /// Gets the default IAdoException translator, lazily creating it if nece - /// - /// The default IAdoException translator. - public IAdoExceptionTranslator DefaultAdoExceptionTranslator - { - get - { - lock (this) - { - if (defaultExceptionTranslator == null) - { - if (dbProvider != null) - { - defaultExceptionTranslator = new ErrorCodeExceptionTranslator(dbProvider); - } - else - { - defaultExceptionTranslator = SessionFactoryUtils.NewAdoExceptionTranslator(SessionFactory); - } - } - return defaultExceptionTranslator; - } - } - } - - /// - /// Gets or sets the SessionFactory that this instance should manage transactions for. - /// - /// The session factory. - public ISessionFactory SessionFactory - { - get { return sessionFactory; } - set { sessionFactory = value; } - } - - - /// - /// Gets the resource factory that this transaction manager operates on, - /// For the HibenratePlatformTransactionManager this the SessionFactory - /// - /// The SessionFactory. - public object ResourceFactory - { - get { return sessionFactory; } - } - - /// - /// Set whether to autodetect a ADO.NET connection used by the Hibernate SessionFactory, - /// if set via LocalSessionFactoryObject's DbProvider. Default is "true". - /// - /// - /// true if [autodetect data source]; otherwise, false. - /// - /// - ///

Can be turned off to deliberately ignore an available IDbProvider, - /// to not expose Hibernate transactions as ADO.NET transactions for that IDbProvider. - ///

- ///
- public bool AutodetectDbProvider - { - set { autodetectDbProvider = value; } - } - - /// - /// The object factory just needs to be known for resolving entity interceptor - /// It does not need to be set for any other mode of operation. - /// - /// - /// Owning - /// (may not be ). The object can immediately - /// call methods on the factory. - /// - public IObjectFactory ObjectFactory - { - set - { - objectFactory = value; - } - } - - /// - /// Return the current transaction object. - /// - /// The current transaction object. - /// - /// If transaction support is not available. - /// - /// - /// In the case of lookup or system errors. - /// - protected override object DoGetTransaction() - { - - - HibernateTransactionObject txObject = new HibernateTransactionObject(); - txObject.SavepointAllowed = NestedTransactionsAllowed; - if (TransactionSynchronizationManager.HasResource(SessionFactory)) - { - SessionHolder sessionHolder = - (SessionHolder)TransactionSynchronizationManager.GetResource(SessionFactory); - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug("Found thread-bound Session [" + sessionHolder.Session + - "] for Hibernate transaction"); - } - txObject.SetSessionHolder(sessionHolder, false); - if (DbProvider != null) - { - ConnectionHolder conHolder = (ConnectionHolder) - TransactionSynchronizationManager.GetResource(DbProvider); - txObject.ConnectionHolder = conHolder; - } - } - txObject.PromotableTxScopeTransactionObject = new TxScopeTransactionManager.PromotableTxScopeTransactionObject(); - - return txObject; - } - - /// - /// Check if the given transaction object indicates an existing, - /// i.e. already begun, transaction. - /// - /// - /// Transaction object returned by - /// . - /// - /// True if there is an existing transaction. - /// - /// In the case of system errors. - /// - protected override bool IsExistingTransaction(object transaction) - { - var hibernateTransactionObject = ((HibernateTransactionObject) transaction); - - var hasExistingPromotableTxScopeTransaction = hibernateTransactionObject.PromotableTxScopeTransactionObject.TxScopeAdapter.IsExistingTransaction; - var hasExistingTransaction = hibernateTransactionObject.HasTransaction(); - - return hasExistingPromotableTxScopeTransaction && hasExistingTransaction; - } - - /// - /// Begin a new transaction with the given transaction definition. - /// - /// - /// Transaction object returned by - /// . - /// - /// - /// instance, describing - /// propagation behavior, isolation level, timeout etc. - /// - /// - /// Does not have to care about applying the propagation behavior, - /// as this has already been handled by this abstract manager. - /// - /// - /// In the case of creation or system errors. - /// - protected override void DoBegin(object transaction, ITransactionDefinition definition) - { - - TxScopeTransactionManager.PromotableTxScopeTransactionObject promotableTxScopeTransactionObject = - ((HibernateTransactionObject)transaction).PromotableTxScopeTransactionObject; - try - { - DoTxScopeBegin(promotableTxScopeTransactionObject, definition); - } - catch (Exception e) - { - throw new CannotCreateTransactionException("Transaction Scope failure on begin", e); - } - - HibernateTransactionObject txObject = (HibernateTransactionObject)transaction; - - if (DbProvider != null && TransactionSynchronizationManager.HasResource(DbProvider) - && !txObject.ConnectionHolder.SynchronizedWithTransaction) - { - throw new IllegalTransactionStateException( - "Pre-bound ADO.NET Connection found - HibernateTransactionManager does not support " + - "running within AdoTransactionManager if told to manage the DbProvider itself. " + - "It is recommended to use a single HibernateTransactionManager for all transactions " + - "on a single DbProvider, no matter whether Hibernate or ADO.NET access."); - } - ISession session = null; - try - { - - if (txObject.SessionHolder == null || txObject.SessionHolder.SynchronizedWithTransaction) - { - IInterceptor interceptor = EntityInterceptor; - ISession newSession = (interceptor != null ? - SessionFactory.OpenSession(interceptor) : SessionFactory.OpenSession()); - - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug("Opened new Session [" + newSession + "] for Hibernate transaction"); - } - txObject.SetSessionHolder(new SessionHolder(newSession), true); - - } - txObject.SessionHolder.SynchronizedWithTransaction = true; - session = txObject.SessionHolder.Session; - - IDbConnection con = session.Connection; - //TODO isolation level mgmt - //IsolationLevel previousIsolationLevel = - - if (definition.ReadOnly && txObject.NewSessionHolder) - { - // Just set to NEVER in case of a new Session for this transaction. - session.FlushMode = FlushMode.Never; + throw new InvalidOperationException("Cannot get entity interceptor via object name if no object factory set"); } - if (!definition.ReadOnly && !txObject.NewSessionHolder) - { - // We need AUTO or COMMIT for a non-read-only transaction. - FlushMode flushMode = session.FlushMode; - if (FlushMode.Never == flushMode) - { - session.FlushMode = FlushMode.Auto; - txObject.SessionHolder.PreviousFlushMode = flushMode; - } - } - - // Add the Hibernate transaction to the session holder. - // for now pass in tx options isolation level. - ITransaction hibernateTx = session.BeginTransaction(definition.TransactionIsolationLevel); - IDbTransaction adoTx = GetIDbTransaction(hibernateTx); - - // Add the Hibernate transaction to the session holder. - txObject.SessionHolder.Transaction = hibernateTx; - - // Register transaction timeout. - int timeout = DetermineTimeout(definition); - if (timeout != DefaultTransactionDefinition.TIMEOUT_DEFAULT) - { - txObject.SessionHolder.TimeoutInSeconds = timeout; - } - - // Register the Hibernate Session's ADO.NET Connection/TX pair for the DbProvider, if set. - if (DbProvider != null) - { - //investigate passing null for tx. - ConnectionHolder conHolder = new ConnectionHolder(con, adoTx); - if (timeout != DefaultTransactionDefinition.TIMEOUT_DEFAULT) - { - conHolder.TimeoutInSeconds = timeout; - } - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug("Exposing Hibernate transaction as ADO transaction [" + con + "]"); - } - TransactionSynchronizationManager.BindResource(DbProvider, conHolder); - txObject.ConnectionHolder = conHolder; - } - - // Bind the session holder to the thread. - if (txObject.NewSessionHolder) - { - TransactionSynchronizationManager.BindResource(SessionFactory, txObject.SessionHolder); - } - - } - catch (Exception ex) - { - SessionFactoryUtils.CloseSession(session); - throw new CannotCreateTransactionException("Could not open Hibernate Session for transaction", ex); - } - - - } - - private void DoTxScopeBegin(TxScopeTransactionManager.PromotableTxScopeTransactionObject txObject, - Spring.Transaction.ITransactionDefinition definition) - { - - TransactionScopeOption txScopeOption = CreateTransactionScopeOptions(definition); - TransactionOptions txOptions = CreateTransactionOptions(definition); - txObject.TxScopeAdapter.CreateTransactionScope(txScopeOption, txOptions, definition.AsyncFlowOption); - - } - - private static TransactionScopeOption CreateTransactionScopeOptions(ITransactionDefinition definition) - { - TransactionScopeOption txScopeOption; - if (definition.PropagationBehavior == TransactionPropagation.Required) - { - txScopeOption = TransactionScopeOption.Required; - } - else if (definition.PropagationBehavior == TransactionPropagation.RequiresNew) - { - txScopeOption = TransactionScopeOption.RequiresNew; - } - else if (definition.PropagationBehavior == TransactionPropagation.NotSupported) - { - txScopeOption = TransactionScopeOption.Suppress; + String objectName = (String) this.entityInterceptor; + return (IInterceptor) this.objectFactory.GetObject(objectName, typeof(IInterceptor)); } else { - throw new Spring.Transaction.TransactionSystemException("Transaction Propagation Behavior" + - definition.PropagationBehavior + - " not supported by TransactionScope. Use Required or RequiredNew"); + return null; } - return txScopeOption; } - - - private static TransactionOptions CreateTransactionOptions(ITransactionDefinition definition) + set { - TransactionOptions txOptions = new TransactionOptions(); - switch (definition.TransactionIsolationLevel) - { - case System.Data.IsolationLevel.Chaos: - txOptions.IsolationLevel = System.Transactions.IsolationLevel.Chaos; - break; - case System.Data.IsolationLevel.ReadCommitted: - txOptions.IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted; - break; - case System.Data.IsolationLevel.ReadUncommitted: - txOptions.IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted; - break; - case System.Data.IsolationLevel.RepeatableRead: - txOptions.IsolationLevel = System.Transactions.IsolationLevel.RepeatableRead; - break; - case System.Data.IsolationLevel.Serializable: - txOptions.IsolationLevel = System.Transactions.IsolationLevel.Serializable; - break; - case System.Data.IsolationLevel.Snapshot: - txOptions.IsolationLevel = System.Transactions.IsolationLevel.Snapshot; - break; - case System.Data.IsolationLevel.Unspecified: - txOptions.IsolationLevel = System.Transactions.IsolationLevel.Unspecified; - break; - } - - if (definition.TransactionTimeout != DefaultTransactionDefinition.TIMEOUT_DEFAULT) - { - txOptions.Timeout = new TimeSpan(0, 0, definition.TransactionTimeout); - } - return txOptions; + entityInterceptor = value; } + } - - - /// - /// Suspend the resources of the current transaction. - /// - /// - /// Transaction object returned by - /// . - /// - /// - /// An object that holds suspended resources (will be kept unexamined for passing it into - /// .) - /// - /// - /// Transaction synchronization will already have been suspended. - /// - /// - /// If suspending is not supported by the transaction manager implementation. - /// - /// - /// in case of system errors. - /// - protected override object DoSuspend(object transaction) + /// + /// Sets the object name of a Hibernate entity interceptor that + /// allows to inspect and change property values before writing to and reading from the database. + /// + /// The name of the entity interceptor object. + /// + /// Will get applied to any new Session created by this transaction manager. + ///

Requires the object factory to be known, to be able to resolve the object + /// name to an interceptor instance on session creation. Typically used for + /// prototype interceptors, i.e. a new interceptor instance per session. + ///

+ ///

Can also be used for shared interceptor instances, but it is recommended + /// to set the interceptor reference directly in such a scenario. + ///

+ ///
+ public string EntityInterceptorObjectName + { + set + { + entityInterceptor = value; + } + } + + /// + /// Gets or sets the ADO.NET exception translator for this transaction manager. + /// + /// + /// Applied to ADO.NET Exceptions (wrapped by Hibernate's ADOException) + /// + /// The ADO exception translator. + public IAdoExceptionTranslator AdoExceptionTranslator + { + get { return adoExceptionTranslator; } + set { adoExceptionTranslator = value; } + } + + /// + /// Gets the default IAdoException translator, lazily creating it if nece + /// + /// The default IAdoException translator. + public IAdoExceptionTranslator DefaultAdoExceptionTranslator + { + get + { + lock (this) + { + if (defaultExceptionTranslator == null) + { + if (dbProvider != null) + { + defaultExceptionTranslator = new ErrorCodeExceptionTranslator(dbProvider); + } + else + { + defaultExceptionTranslator = SessionFactoryUtils.NewAdoExceptionTranslator(SessionFactory); + } + } + + return defaultExceptionTranslator; + } + } + } + + /// + /// Gets or sets the SessionFactory that this instance should manage transactions for. + /// + /// The session factory. + public ISessionFactory SessionFactory + { + get { return sessionFactory; } + set { sessionFactory = value; } + } + + /// + /// Gets the resource factory that this transaction manager operates on, + /// For the HibenratePlatformTransactionManager this the SessionFactory + /// + /// The SessionFactory. + public object ResourceFactory + { + get { return sessionFactory; } + } + + /// + /// Set whether to autodetect a ADO.NET connection used by the Hibernate SessionFactory, + /// if set via LocalSessionFactoryObject's DbProvider. Default is "true". + /// + /// + /// true if [autodetect data source]; otherwise, false. + /// + /// + ///

Can be turned off to deliberately ignore an available IDbProvider, + /// to not expose Hibernate transactions as ADO.NET transactions for that IDbProvider. + ///

+ ///
+ public bool AutodetectDbProvider + { + set { autodetectDbProvider = value; } + } + + /// + /// The object factory just needs to be known for resolving entity interceptor + /// It does not need to be set for any other mode of operation. + /// + /// + /// Owning + /// (may not be ). The object can immediately + /// call methods on the factory. + /// + public IObjectFactory ObjectFactory + { + set + { + objectFactory = value; + } + } + + /// + /// Return the current transaction object. + /// + /// The current transaction object. + /// + /// If transaction support is not available. + /// + /// + /// In the case of lookup or system errors. + /// + protected override object DoGetTransaction() + { + HibernateTransactionObject txObject = new HibernateTransactionObject(); + txObject.SavepointAllowed = NestedTransactionsAllowed; + if (TransactionSynchronizationManager.HasResource(SessionFactory)) { - HibernateTransactionObject txObject = (HibernateTransactionObject)transaction; - txObject.SetSessionHolder(null, false); SessionHolder sessionHolder = - (SessionHolder)TransactionSynchronizationManager.UnbindResource(SessionFactory); - ConnectionHolder connectionHolder = null; + (SessionHolder) TransactionSynchronizationManager.GetResource(SessionFactory); + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug("Found thread-bound Session [" + sessionHolder.Session + + "] for Hibernate transaction"); + } + + txObject.SetSessionHolder(sessionHolder, false); if (DbProvider != null) { - connectionHolder = (ConnectionHolder)TransactionSynchronizationManager.UnbindResource(DbProvider); + ConnectionHolder conHolder = (ConnectionHolder) + TransactionSynchronizationManager.GetResource(DbProvider); + txObject.ConnectionHolder = conHolder; } - return new SuspendedResourcesHolder(sessionHolder, connectionHolder); - } - /// - /// Resume the resources of the current transaction. - /// - /// - /// Transaction object returned by - /// . - /// - /// - /// The object that holds suspended resources as returned by - /// . - /// - /// - /// Transaction synchronization will be resumed afterwards. - /// - /// - /// If suspending is not supported by the transaction manager implementation. - /// - /// - /// In the case of system errors. - /// - protected override void DoResume(object transaction, object suspendedResources) + txObject.PromotableTxScopeTransactionObject = new TxScopeTransactionManager.PromotableTxScopeTransactionObject(); + + return txObject; + } + + /// + /// Check if the given transaction object indicates an existing, + /// i.e. already begun, transaction. + /// + /// + /// Transaction object returned by + /// . + /// + /// True if there is an existing transaction. + /// + /// In the case of system errors. + /// + protected override bool IsExistingTransaction(object transaction) + { + var hibernateTransactionObject = ((HibernateTransactionObject) transaction); + + var hasExistingPromotableTxScopeTransaction = hibernateTransactionObject.PromotableTxScopeTransactionObject.TxScopeAdapter.IsExistingTransaction; + var hasExistingTransaction = hibernateTransactionObject.HasTransaction(); + + return hasExistingPromotableTxScopeTransaction && hasExistingTransaction; + } + + /// + /// Begin a new transaction with the given transaction definition. + /// + /// + /// Transaction object returned by + /// . + /// + /// + /// instance, describing + /// propagation behavior, isolation level, timeout etc. + /// + /// + /// Does not have to care about applying the propagation behavior, + /// as this has already been handled by this abstract manager. + /// + /// + /// In the case of creation or system errors. + /// + protected override void DoBegin(object transaction, ITransactionDefinition definition) + { + TxScopeTransactionManager.PromotableTxScopeTransactionObject promotableTxScopeTransactionObject = + ((HibernateTransactionObject) transaction).PromotableTxScopeTransactionObject; + try { - SuspendedResourcesHolder resourcesHolder = (SuspendedResourcesHolder)suspendedResources; - if (TransactionSynchronizationManager.HasResource(SessionFactory)) + DoTxScopeBegin(promotableTxScopeTransactionObject, definition); + } + catch (Exception e) + { + throw new CannotCreateTransactionException("Transaction Scope failure on begin", e); + } + + HibernateTransactionObject txObject = (HibernateTransactionObject) transaction; + + if (DbProvider != null && TransactionSynchronizationManager.HasResource(DbProvider) + && !txObject.ConnectionHolder.SynchronizedWithTransaction) + { + throw new IllegalTransactionStateException( + "Pre-bound ADO.NET Connection found - HibernateTransactionManager does not support " + + "running within AdoTransactionManager if told to manage the DbProvider itself. " + + "It is recommended to use a single HibernateTransactionManager for all transactions " + + "on a single DbProvider, no matter whether Hibernate or ADO.NET access."); + } + + ISession session = null; + try + { + if (txObject.SessionHolder == null || txObject.SessionHolder.SynchronizedWithTransaction) { - // From non-transactional code running in active transaction synchronization - // -> can be safely removed, will be closed on transaction completion. - TransactionSynchronizationManager.UnbindResource(SessionFactory); + IInterceptor interceptor = EntityInterceptor; + ISession newSession = (interceptor != null ? SessionFactory.OpenSession(interceptor) : SessionFactory.OpenSession()); + + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug("Opened new Session [" + newSession + "] for Hibernate transaction"); + } + + txObject.SetSessionHolder(new SessionHolder(newSession), true); } - TransactionSynchronizationManager.BindResource(SessionFactory, resourcesHolder.SessionHolder); + + txObject.SessionHolder.SynchronizedWithTransaction = true; + session = txObject.SessionHolder.Session; + + IDbConnection con = session.Connection; + //TODO isolation level mgmt + //IsolationLevel previousIsolationLevel = + + if (definition.ReadOnly && txObject.NewSessionHolder) + { + // Just set to NEVER in case of a new Session for this transaction. + session.FlushMode = FlushMode.Never; + } + + if (!definition.ReadOnly && !txObject.NewSessionHolder) + { + // We need AUTO or COMMIT for a non-read-only transaction. + FlushMode flushMode = session.FlushMode; + if (FlushMode.Never == flushMode) + { + session.FlushMode = FlushMode.Auto; + txObject.SessionHolder.PreviousFlushMode = flushMode; + } + } + + // Add the Hibernate transaction to the session holder. + // for now pass in tx options isolation level. + ITransaction hibernateTx = session.BeginTransaction(definition.TransactionIsolationLevel); + IDbTransaction adoTx = GetIDbTransaction(hibernateTx); + + // Add the Hibernate transaction to the session holder. + txObject.SessionHolder.Transaction = hibernateTx; + + // Register transaction timeout. + int timeout = DetermineTimeout(definition); + if (timeout != DefaultTransactionDefinition.TIMEOUT_DEFAULT) + { + txObject.SessionHolder.TimeoutInSeconds = timeout; + } + + // Register the Hibernate Session's ADO.NET Connection/TX pair for the DbProvider, if set. if (DbProvider != null) { - TransactionSynchronizationManager.BindResource(DbProvider, resourcesHolder.ConnectionHolder); - } - } - - /// - /// Perform an actual commit on the given transaction. - /// - /// The status representation of the transaction. - /// - ///

- /// An implementation does not need to check the rollback-only flag. - ///

- ///
- /// - /// In the case of system errors. - /// - protected override void DoCommit(DefaultTransactionStatus status) - { - HibernateTransactionObject txObject = (HibernateTransactionObject)status.Transaction; - if (status.Debug) - { - log.LogDebug("Committing Hibernate transaction on Session [" + - txObject.SessionHolder.Session + "]"); - } - try - { - txObject.SessionHolder.Transaction.Commit(); - } - // Note, unfortunate collision of namespaces/classname for NHibernate.TransactionException - // and Spring.Data.NHibernate requires this wierd construct. - catch (Exception ex) - { - Type nhibTxExceptiontype = TypeResolutionUtils.ResolveType("NHibernate.TransactionException, NHibernate"); - if (ex.GetType().Equals(nhibTxExceptiontype)) + //investigate passing null for tx. + ConnectionHolder conHolder = new ConnectionHolder(con, adoTx); + if (timeout != DefaultTransactionDefinition.TIMEOUT_DEFAULT) { - // assumably from commit call to the underlying ADO.NET connection - throw new TransactionSystemException("Could not commit Hibernate transaction", ex); + conHolder.TimeoutInSeconds = timeout; } - HibernateException hibEx = ex as HibernateException; - if (hibEx != null) + + if (log.IsEnabled(LogLevel.Debug)) { - // assumably failed to flush changes to database - throw ConvertHibernateAccessException(hibEx); + log.LogDebug("Exposing Hibernate transaction as ADO transaction [" + con + "]"); } - throw; - } - finally - { - DoTxScopeCommit(status); + + TransactionSynchronizationManager.BindResource(DbProvider, conHolder); + txObject.ConnectionHolder = conHolder; } - - - } - - /// - /// Does the tx scope commit. - /// - /// The status. - protected void DoTxScopeCommit(DefaultTransactionStatus status) - { - TxScopeTransactionManager.PromotableTxScopeTransactionObject txObject = - ((HibernateTransactionObject)status.Transaction).PromotableTxScopeTransactionObject; - try + // Bind the session holder to the thread. + if (txObject.NewSessionHolder) { - txObject.TxScopeAdapter.Complete(); - txObject.TxScopeAdapter.Dispose(); - } - catch (TransactionAbortedException ex) - { - throw new UnexpectedRollbackException("Transaction unexpectedly rolled back (maybe due to a timeout)", ex); - } - catch (TransactionInDoubtException ex) - { - throw new HeuristicCompletionException(TransactionOutcomeState.Unknown, ex); - } - catch (Exception ex) - { - throw new TransactionSystemException("Failure on Transaction Scope Commit", ex); + TransactionSynchronizationManager.BindResource(SessionFactory, txObject.SessionHolder); } } - - /// - /// Perform an actual rollback on the given transaction. - /// - /// The status representation of the transaction. - /// - /// An implementation does not need to check the new transaction flag. - /// - /// - /// In the case of system errors. - /// - protected override void DoRollback(DefaultTransactionStatus status) + catch (Exception ex) { - HibernateTransactionObject txObject = (HibernateTransactionObject)status.Transaction; + SessionFactoryUtils.CloseSession(session); + throw new CannotCreateTransactionException("Could not open Hibernate Session for transaction", ex); + } + } - if (!txObject.NewSessionHolder) + private void DoTxScopeBegin(TxScopeTransactionManager.PromotableTxScopeTransactionObject txObject, + Spring.Transaction.ITransactionDefinition definition) + { + TransactionScopeOption txScopeOption = CreateTransactionScopeOptions(definition); + TransactionOptions txOptions = CreateTransactionOptions(definition); + txObject.TxScopeAdapter.CreateTransactionScope(txScopeOption, txOptions, definition.AsyncFlowOption); + } + + private static TransactionScopeOption CreateTransactionScopeOptions(ITransactionDefinition definition) + { + TransactionScopeOption txScopeOption; + if (definition.PropagationBehavior == TransactionPropagation.Required) + { + txScopeOption = TransactionScopeOption.Required; + } + else if (definition.PropagationBehavior == TransactionPropagation.RequiresNew) + { + txScopeOption = TransactionScopeOption.RequiresNew; + } + else if (definition.PropagationBehavior == TransactionPropagation.NotSupported) + { + txScopeOption = TransactionScopeOption.Suppress; + } + else + { + throw new Spring.Transaction.TransactionSystemException("Transaction Propagation Behavior" + + definition.PropagationBehavior + + " not supported by TransactionScope. Use Required or RequiredNew"); + } + + return txScopeOption; + } + + private static TransactionOptions CreateTransactionOptions(ITransactionDefinition definition) + { + TransactionOptions txOptions = new TransactionOptions(); + switch (definition.TransactionIsolationLevel) + { + case System.Data.IsolationLevel.Chaos: + txOptions.IsolationLevel = System.Transactions.IsolationLevel.Chaos; + break; + case System.Data.IsolationLevel.ReadCommitted: + txOptions.IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted; + break; + case System.Data.IsolationLevel.ReadUncommitted: + txOptions.IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted; + break; + case System.Data.IsolationLevel.RepeatableRead: + txOptions.IsolationLevel = System.Transactions.IsolationLevel.RepeatableRead; + break; + case System.Data.IsolationLevel.Serializable: + txOptions.IsolationLevel = System.Transactions.IsolationLevel.Serializable; + break; + case System.Data.IsolationLevel.Snapshot: + txOptions.IsolationLevel = System.Transactions.IsolationLevel.Snapshot; + break; + case System.Data.IsolationLevel.Unspecified: + txOptions.IsolationLevel = System.Transactions.IsolationLevel.Unspecified; + break; + } + + if (definition.TransactionTimeout != DefaultTransactionDefinition.TIMEOUT_DEFAULT) + { + txOptions.Timeout = new TimeSpan(0, 0, definition.TransactionTimeout); + } + + return txOptions; + } + + /// + /// Suspend the resources of the current transaction. + /// + /// + /// Transaction object returned by + /// . + /// + /// + /// An object that holds suspended resources (will be kept unexamined for passing it into + /// .) + /// + /// + /// Transaction synchronization will already have been suspended. + /// + /// + /// If suspending is not supported by the transaction manager implementation. + /// + /// + /// in case of system errors. + /// + protected override object DoSuspend(object transaction) + { + HibernateTransactionObject txObject = (HibernateTransactionObject) transaction; + txObject.SetSessionHolder(null, false); + SessionHolder sessionHolder = + (SessionHolder) TransactionSynchronizationManager.UnbindResource(SessionFactory); + ConnectionHolder connectionHolder = null; + if (DbProvider != null) + { + connectionHolder = (ConnectionHolder) TransactionSynchronizationManager.UnbindResource(DbProvider); + } + + return new SuspendedResourcesHolder(sessionHolder, connectionHolder); + } + + /// + /// Resume the resources of the current transaction. + /// + /// + /// Transaction object returned by + /// . + /// + /// + /// The object that holds suspended resources as returned by + /// . + /// + /// + /// Transaction synchronization will be resumed afterwards. + /// + /// + /// If suspending is not supported by the transaction manager implementation. + /// + /// + /// In the case of system errors. + /// + protected override void DoResume(object transaction, object suspendedResources) + { + SuspendedResourcesHolder resourcesHolder = (SuspendedResourcesHolder) suspendedResources; + if (TransactionSynchronizationManager.HasResource(SessionFactory)) + { + // From non-transactional code running in active transaction synchronization + // -> can be safely removed, will be closed on transaction completion. + TransactionSynchronizationManager.UnbindResource(SessionFactory); + } + + TransactionSynchronizationManager.BindResource(SessionFactory, resourcesHolder.SessionHolder); + if (DbProvider != null) + { + TransactionSynchronizationManager.BindResource(DbProvider, resourcesHolder.ConnectionHolder); + } + } + + /// + /// Perform an actual commit on the given transaction. + /// + /// The status representation of the transaction. + /// + ///

+ /// An implementation does not need to check the rollback-only flag. + ///

+ ///
+ /// + /// In the case of system errors. + /// + protected override void DoCommit(DefaultTransactionStatus status) + { + HibernateTransactionObject txObject = (HibernateTransactionObject) status.Transaction; + if (status.Debug) + { + log.LogDebug("Committing Hibernate transaction on Session [" + + txObject.SessionHolder.Session + "]"); + } + + try + { + txObject.SessionHolder.Transaction.Commit(); + } + // Note, unfortunate collision of namespaces/classname for NHibernate.TransactionException + // and Spring.Data.NHibernate requires this wierd construct. + catch (Exception ex) + { + Type nhibTxExceptiontype = TypeResolutionUtils.ResolveType("NHibernate.TransactionException, NHibernate"); + if (ex.GetType().Equals(nhibTxExceptiontype)) { - // Clear all pending inserts/updates/deletes in the Session. - // Necessary for pre-bound Sessions, to avoid inconsistent state. - txObject.SessionHolder.Session.Clear(); + // assumably from commit call to the underlying ADO.NET connection + throw new TransactionSystemException("Could not commit Hibernate transaction", ex); } - - DoTxScopeRollback(status); - return; + HibernateException hibEx = ex as HibernateException; + if (hibEx != null) + { + // assumably failed to flush changes to database + throw ConvertHibernateAccessException(hibEx); + } + + throw; + } + finally + { + DoTxScopeCommit(status); + } + } + + /// + /// Does the tx scope commit. + /// + /// The status. + protected void DoTxScopeCommit(DefaultTransactionStatus status) + { + TxScopeTransactionManager.PromotableTxScopeTransactionObject txObject = + ((HibernateTransactionObject) status.Transaction).PromotableTxScopeTransactionObject; + try + { + txObject.TxScopeAdapter.Complete(); + txObject.TxScopeAdapter.Dispose(); + } + catch (TransactionAbortedException ex) + { + throw new UnexpectedRollbackException("Transaction unexpectedly rolled back (maybe due to a timeout)", ex); + } + catch (TransactionInDoubtException ex) + { + throw new HeuristicCompletionException(TransactionOutcomeState.Unknown, ex); + } + catch (Exception ex) + { + throw new TransactionSystemException("Failure on Transaction Scope Commit", ex); + } + } + + /// + /// Perform an actual rollback on the given transaction. + /// + /// The status representation of the transaction. + /// + /// An implementation does not need to check the new transaction flag. + /// + /// + /// In the case of system errors. + /// + protected override void DoRollback(DefaultTransactionStatus status) + { + HibernateTransactionObject txObject = (HibernateTransactionObject) status.Transaction; + + if (!txObject.NewSessionHolder) + { + // Clear all pending inserts/updates/deletes in the Session. + // Necessary for pre-bound Sessions, to avoid inconsistent state. + txObject.SessionHolder.Session.Clear(); + } + + DoTxScopeRollback(status); + return; /* HibernateTransactionObject txObject = (HibernateTransactionObject)status.Transaction; @@ -752,368 +747,367 @@ namespace Spring.Data.NHibernate } DoTxScopeRollback(status); }*/ + } + + /// + /// Does the tx scope rollback. + /// + /// The status. + protected void DoTxScopeRollback(DefaultTransactionStatus status) + { + TxScopeTransactionManager.PromotableTxScopeTransactionObject txObject = + ((HibernateTransactionObject) status.Transaction).PromotableTxScopeTransactionObject; + + try + { + txObject.TxScopeAdapter.Dispose(); + } + catch (Exception e) + { + throw new Spring.Transaction.TransactionSystemException("Failure on Transaction Scope rollback.", e); + } + } + + /// + /// Set the given transaction rollback-only. Only called on rollback + /// if the current transaction takes part in an existing one. + /// + /// The status representation of the transaction. + /// + /// In the case of system errors. + /// + protected override void DoSetRollbackOnly(DefaultTransactionStatus status) + { + HibernateTransactionObject txObject = (HibernateTransactionObject) status.Transaction; + if (status.Debug) + { + log.LogDebug("Setting Hibernate transaction on Session [" + + txObject.SessionHolder.Session + "] rollback-only"); } - /// - /// Does the tx scope rollback. - /// - /// The status. - protected void DoTxScopeRollback(DefaultTransactionStatus status) - { - TxScopeTransactionManager.PromotableTxScopeTransactionObject txObject = - ((HibernateTransactionObject)status.Transaction).PromotableTxScopeTransactionObject; + txObject.SetRollbackOnly(); + DoTxScopeSetRollbackOnly(status); + } + + /// + /// Does the tx scope set rollback only. + /// + /// The status. + protected void DoTxScopeSetRollbackOnly(DefaultTransactionStatus status) + { + if (status.Debug) + { + log.LogDebug("Setting transaction rollback-only"); + } + + try + { + System.Transactions.Transaction.Current.Rollback(); + } + catch (Exception ex) + { + throw new TransactionSystemException("Failure on System.Transactions.Transaction.Current.Rollback", ex); + } + } + + /// + /// Gets the ADO.NET IDbTransaction object from the NHibernate ITransaction object. + /// + /// The hibernate transaction. + /// The ADO.NET transaction. Null if could not get the transaction. Warning + /// messages will be logged in that case. + protected IDbTransaction GetIDbTransaction(ITransaction hibernateTx) + { + AdoTransaction hibernateAdoTx = hibernateTx as AdoTransaction; + + IDbTransaction adoTransaction = null; + if (hibernateAdoTx != null) + { try { - - txObject.TxScopeAdapter.Dispose(); + FieldInfo fi = hibernateAdoTx.GetType().GetField("trans", BindingFlags.Instance | BindingFlags.NonPublic); + adoTransaction = fi.GetValue(hibernateAdoTx) as IDbTransaction; } catch (Exception e) { - throw new Spring.Transaction.TransactionSystemException("Failure on Transaction Scope rollback.", e); + log.LogWarning(e, "Could not extract IDbTransaction from Hibernate AdoTransaction using field name trans."); + } + } + else + { + log.LogWarning("Hibernate ITransaction not of expected type AdoTransaction. Could not extract IDbTransaction from Hibernate AdoTransaction."); + } + + return adoTransaction; + } + + /// + /// Convert the given HibernateException to an appropriate exception from + /// the Spring.Dao hierarchy. Can be overridden in subclasses. + /// + /// The HibernateException that occured. + /// The corresponding DataAccessException instance + protected virtual DataAccessException ConvertHibernateAccessException(HibernateException ex) + { + if (AdoExceptionTranslator != null && ex is ADOException) + { + return ConvertAdoAccessException((ADOException) ex, AdoExceptionTranslator); + } + else if (ex is ADOException) + { + return ConvertAdoAccessException((ADOException) ex, DefaultAdoExceptionTranslator); + } + + return SessionFactoryUtils.ConvertHibernateAccessException(ex); + } + + /// + /// Convert the given ADOException to an appropriate exception from the + /// the Spring.Dao hierarchy. Can be overridden in subclasses. + /// + /// The ADOException that occured, wrapping the underlying + /// ADO.NET thrown exception. + /// The translator to convert hibernate ADOExceptions. + /// + /// The corresponding DataAccessException instance + /// + protected virtual DataAccessException ConvertAdoAccessException(ADOException ex, IAdoExceptionTranslator translator) + { + return translator.Translate("Hibernate flushing: " + ex.Message, null, ex.InnerException); + } + + /// + /// Cleanup resources after transaction completion. + /// + /// Transaction object returned by + /// . + /// + /// + /// This implemenation unbinds the SessionFactory and + /// DbProvider from thread local storage and closes the + /// ISession. + /// + ///

+ /// Called after + /// and + /// + /// execution on any outcome. + ///

+ ///

+ /// Should not throw any exceptions but just issue warnings on errors. + ///

+ ///
+ protected override void DoCleanupAfterCompletion(object transaction) + { + HibernateTransactionObject txObject = (HibernateTransactionObject) transaction; + + // Remove the session holder from the thread. + if (txObject.NewSessionHolder) + { + TransactionSynchronizationManager.UnbindResource(SessionFactory); + } + + // Remove the ADO.NET connection holder from the thread, if exposed. + if (DbProvider != null) + { + TransactionSynchronizationManager.UnbindResource(DbProvider); + } + + /* + try + { + //TODO investigate isolation level settings... + //IDbConnection con = txObject.SessionHolder.Session.Connection; + //AdoUtils.ResetConnectionAfterTransaction(con, txObject.PreviousIsolationLevel); + } + catch (HibernateException ex) + { + log.Info("Could not access ADO.NET IDbConnection of Hibernate Session", ex); + } + */ + ISession session = txObject.SessionHolder.Session; + + if (txObject.NewSessionHolder) + { + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug("Closing Hibernate Session [" + session + "] after transaction"); + } + + SessionFactoryUtils.CloseSessionOrRegisterDeferredClose(session, SessionFactory); + } + else + { + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug("Not closing pre-bound Hibernate Session [" + session + "] after transaction"); + } + + if (txObject.SessionHolder.AssignedPreviousFlushMode) + { + session.FlushMode = txObject.SessionHolder.PreviousFlushMode; + } + } + + txObject.SessionHolder.Clear(); + } + + private class HibernateTransactionObject : AdoTransactionObjectSupport + { + private SessionHolder sessionHolder; + + private bool newSessionHolder; + + private TxScopeTransactionManager.PromotableTxScopeTransactionObject promotableTxScopeTransactionObject; + + public void SetSessionHolder(SessionHolder sessionHolder, bool newSessionHolder) + { + this.sessionHolder = sessionHolder; + this.newSessionHolder = newSessionHolder; + } + + public TxScopeTransactionManager.PromotableTxScopeTransactionObject PromotableTxScopeTransactionObject + { + get { return promotableTxScopeTransactionObject; } + set { this.promotableTxScopeTransactionObject = value; } + } + + public SessionHolder SessionHolder + { + get + { + return sessionHolder; + } + } + + public bool NewSessionHolder + { + get + { + return newSessionHolder; + } + } + + public bool HasTransaction() + { + return (this.sessionHolder != null && this.sessionHolder.Transaction != null); + } + + public void SetRollbackOnly() + { + if (SessionHolder != null) + { + SessionHolder.RollbackOnly = true; + } + + if (ConnectionHolder != null) + { + ConnectionHolder.RollbackOnly = true; } } /// - /// Set the given transaction rollback-only. Only called on rollback - /// if the current transaction takes part in an existing one. + /// Return whether the transaction is internally marked as rollback-only. /// - /// The status representation of the transaction. - /// - /// In the case of system errors. - /// - protected override void DoSetRollbackOnly(DefaultTransactionStatus status) + /// + /// True of the transaction is marked as rollback-only. + public override bool RollbackOnly { - HibernateTransactionObject txObject = (HibernateTransactionObject)status.Transaction; - if (status.Debug) + get { - log.LogDebug("Setting Hibernate transaction on Session [" + - txObject.SessionHolder.Session + "] rollback-only"); - } - txObject.SetRollbackOnly(); - - DoTxScopeSetRollbackOnly(status); - } - - /// - /// Does the tx scope set rollback only. - /// - /// The status. - protected void DoTxScopeSetRollbackOnly(DefaultTransactionStatus status) - { - if (status.Debug) - { - log.LogDebug("Setting transaction rollback-only"); - } - try - { - System.Transactions.Transaction.Current.Rollback(); - } - catch (Exception ex) - { - throw new TransactionSystemException("Failure on System.Transactions.Transaction.Current.Rollback", ex); - } - } - - - /// - /// Gets the ADO.NET IDbTransaction object from the NHibernate ITransaction object. - /// - /// The hibernate transaction. - /// The ADO.NET transaction. Null if could not get the transaction. Warning - /// messages will be logged in that case. - protected IDbTransaction GetIDbTransaction(ITransaction hibernateTx) - { - AdoTransaction hibernateAdoTx = hibernateTx as AdoTransaction; - - IDbTransaction adoTransaction = null; - if (hibernateAdoTx != null) - { - try - { - FieldInfo fi = hibernateAdoTx.GetType().GetField("trans", BindingFlags.Instance | BindingFlags.NonPublic); - adoTransaction = fi.GetValue(hibernateAdoTx) as IDbTransaction; - } - catch (Exception e) - { - log.LogWarning(e, "Could not extract IDbTransaction from Hibernate AdoTransaction using field name trans."); - } - } - else - { - log.LogWarning("Hibernate ITransaction not of expected type AdoTransaction. Could not extract IDbTransaction from Hibernate AdoTransaction."); - } - return adoTransaction; - } - - /// - /// Convert the given HibernateException to an appropriate exception from - /// the Spring.Dao hierarchy. Can be overridden in subclasses. - /// - /// The HibernateException that occured. - /// The corresponding DataAccessException instance - protected virtual DataAccessException ConvertHibernateAccessException(HibernateException ex) - { - if (AdoExceptionTranslator != null && ex is ADOException) - { - return ConvertAdoAccessException((ADOException)ex, AdoExceptionTranslator); - } - else if (ex is ADOException) - { - return ConvertAdoAccessException((ADOException)ex, DefaultAdoExceptionTranslator); - } - return SessionFactoryUtils.ConvertHibernateAccessException(ex); - } - - /// - /// Convert the given ADOException to an appropriate exception from the - /// the Spring.Dao hierarchy. Can be overridden in subclasses. - /// - /// The ADOException that occured, wrapping the underlying - /// ADO.NET thrown exception. - /// The translator to convert hibernate ADOExceptions. - /// - /// The corresponding DataAccessException instance - /// - protected virtual DataAccessException ConvertAdoAccessException(ADOException ex, IAdoExceptionTranslator translator) - { - return translator.Translate("Hibernate flushing: " + ex.Message, null, ex.InnerException); - } - - /// - /// Cleanup resources after transaction completion. - /// - /// Transaction object returned by - /// . - /// - /// - /// This implemenation unbinds the SessionFactory and - /// DbProvider from thread local storage and closes the - /// ISession. - /// - ///

- /// Called after - /// and - /// - /// execution on any outcome. - ///

- ///

- /// Should not throw any exceptions but just issue warnings on errors. - ///

- ///
- protected override void DoCleanupAfterCompletion(object transaction) - { - HibernateTransactionObject txObject = (HibernateTransactionObject)transaction; - - // Remove the session holder from the thread. - if (txObject.NewSessionHolder) - { - TransactionSynchronizationManager.UnbindResource(SessionFactory); - } - // Remove the ADO.NET connection holder from the thread, if exposed. - if (DbProvider != null) - { - TransactionSynchronizationManager.UnbindResource(DbProvider); - } - /* - try - { - //TODO investigate isolation level settings... - //IDbConnection con = txObject.SessionHolder.Session.Connection; - //AdoUtils.ResetConnectionAfterTransaction(con, txObject.PreviousIsolationLevel); - } - catch (HibernateException ex) - { - log.Info("Could not access ADO.NET IDbConnection of Hibernate Session", ex); - } - */ - ISession session = txObject.SessionHolder.Session; - - if (txObject.NewSessionHolder) - { - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug("Closing Hibernate Session [" + session + "] after transaction"); - } - - SessionFactoryUtils.CloseSessionOrRegisterDeferredClose(session, SessionFactory); - } - else - { - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug("Not closing pre-bound Hibernate Session [" + session + "] after transaction"); - } - if (txObject.SessionHolder.AssignedPreviousFlushMode) - { - session.FlushMode = txObject.SessionHolder.PreviousFlushMode; - } - } - - txObject.SessionHolder.Clear(); - } - - private class HibernateTransactionObject : AdoTransactionObjectSupport - { - - private SessionHolder sessionHolder; - - private bool newSessionHolder; - - private TxScopeTransactionManager.PromotableTxScopeTransactionObject promotableTxScopeTransactionObject; - - - public void SetSessionHolder(SessionHolder sessionHolder, bool newSessionHolder) - { - this.sessionHolder = sessionHolder; - this.newSessionHolder = newSessionHolder; - } - - public TxScopeTransactionManager.PromotableTxScopeTransactionObject PromotableTxScopeTransactionObject - { - get { return promotableTxScopeTransactionObject; } - set { this.promotableTxScopeTransactionObject = value; } - } - - public SessionHolder SessionHolder - { - get - { - return sessionHolder; - } - } - - public bool NewSessionHolder - { - get - { - return newSessionHolder; - } - } - - public bool HasTransaction() - { - return (this.sessionHolder != null && this.sessionHolder.Transaction != null); - } - - public void SetRollbackOnly() - { - if (SessionHolder != null) - { - SessionHolder.RollbackOnly = true; - } - if (ConnectionHolder != null) - { - ConnectionHolder.RollbackOnly = true; - } - } - - /// - /// Return whether the transaction is internally marked as rollback-only. - /// - /// - /// True of the transaction is marked as rollback-only. - public override bool RollbackOnly - { - get - { - return ((SessionHolder != null && SessionHolder.RollbackOnly) || - (ConnectionHolder != null && ConnectionHolder.RollbackOnly)); - } - } - } - - private class SuspendedResourcesHolder - { - - private readonly SessionHolder sessionHolder; - - private readonly ConnectionHolder connectionHolder; - - public SuspendedResourcesHolder(SessionHolder sessionHolder, ConnectionHolder conHolder) - { - this.sessionHolder = sessionHolder; - this.connectionHolder = conHolder; - } - - public SessionHolder SessionHolder - { - get - { - return sessionHolder; - } - - } - - public ConnectionHolder ConnectionHolder - { - get - { - return connectionHolder; - } - - } - } - - /// - /// Invoked by an - /// after it has injected all of an object's dependencies. - /// - /// - ///

- /// This method allows the object instance to perform the kind of - /// initialization only possible when all of it's dependencies have - /// been injected (set), and to throw an appropriate exception in the - /// event of misconfiguration. - ///

- ///

- /// Please do consult the class level documentation for the - /// interface for a - /// description of exactly when this method is invoked. In - /// particular, it is worth noting that the - /// - /// and - /// callbacks will have been invoked prior to this method being - /// called. - ///

- ///
- /// - /// In the event of misconfiguration (such as the failure to set a - /// required property) or if initialization fails. - /// - public void AfterPropertiesSet() - { - if (SessionFactory == null) - { - throw new ArgumentException("sessionFactory is required"); - } - if (this.entityInterceptor is string && this.objectFactory == null) - { - throw new ArgumentException("objectFactory is required for entityInterceptorBeanName"); - } - - // Try to derive a DbProvider given the SessionFactory. - if (this.autodetectDbProvider && DbProvider == null) - { - IDbProvider sfDbProvider = SessionFactoryUtils.GetDbProvider(SessionFactory); - if (sfDbProvider != null) - { - // Use the SessionFactory's DataSource for exposing transactions to ADO.NET code. - if (log.IsEnabled(LogLevel.Information)) - { - log.LogInformation("Derived DbProvider [" + sfDbProvider.DbMetadata.ProductName + - "] of Hibernate SessionFactory for HibernateTransactionManager"); - } - DbProvider = sfDbProvider; - } - else - { - log.LogInformation("Could not auto detect DbProvider from SessionFactory configuration"); - } - + return ((SessionHolder != null && SessionHolder.RollbackOnly) || + (ConnectionHolder != null && ConnectionHolder.RollbackOnly)); } } } + private class SuspendedResourcesHolder + { + private readonly SessionHolder sessionHolder; + private readonly ConnectionHolder connectionHolder; + + public SuspendedResourcesHolder(SessionHolder sessionHolder, ConnectionHolder conHolder) + { + this.sessionHolder = sessionHolder; + this.connectionHolder = conHolder; + } + + public SessionHolder SessionHolder + { + get + { + return sessionHolder; + } + } + + public ConnectionHolder ConnectionHolder + { + get + { + return connectionHolder; + } + } + } + + /// + /// Invoked by an + /// after it has injected all of an object's dependencies. + /// + /// + ///

+ /// This method allows the object instance to perform the kind of + /// initialization only possible when all of it's dependencies have + /// been injected (set), and to throw an appropriate exception in the + /// event of misconfiguration. + ///

+ ///

+ /// Please do consult the class level documentation for the + /// interface for a + /// description of exactly when this method is invoked. In + /// particular, it is worth noting that the + /// + /// and + /// callbacks will have been invoked prior to this method being + /// called. + ///

+ ///
+ /// + /// In the event of misconfiguration (such as the failure to set a + /// required property) or if initialization fails. + /// + public void AfterPropertiesSet() + { + if (SessionFactory == null) + { + throw new ArgumentException("sessionFactory is required"); + } + + if (this.entityInterceptor is string && this.objectFactory == null) + { + throw new ArgumentException("objectFactory is required for entityInterceptorBeanName"); + } + + // Try to derive a DbProvider given the SessionFactory. + if (this.autodetectDbProvider && DbProvider == null) + { + IDbProvider sfDbProvider = SessionFactoryUtils.GetDbProvider(SessionFactory); + if (sfDbProvider != null) + { + // Use the SessionFactory's DataSource for exposing transactions to ADO.NET code. + if (log.IsEnabled(LogLevel.Information)) + { + log.LogInformation("Derived DbProvider [" + sfDbProvider.DbMetadata.ProductName + + "] of Hibernate SessionFactory for HibernateTransactionManager"); + } + + DbProvider = sfDbProvider; + } + else + { + log.LogInformation("Could not auto detect DbProvider from SessionFactory configuration"); + } + } + } } diff --git a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/ICommonHibernateOperations.cs b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/ICommonHibernateOperations.cs index 45d3a579..775deca7 100644 --- a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/ICommonHibernateOperations.cs +++ b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/ICommonHibernateOperations.cs @@ -1,12 +1,12 @@ /* * Copyright � 2002-2011 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. @@ -18,208 +18,201 @@ using NHibernate; using NHibernate.Type; using Spring.Dao; -namespace Spring.Data.NHibernate +namespace Spring.Data.NHibernate; + +/// +/// Interface that specifies a set of Hibernate operations that +/// are common across versions of Hibernate. +/// +/// +/// Base interface for generic and non generic IHibernateOperations interfaces +/// Not often used, but a useful option +/// to enhance testability, as it can easily be mocked or stubbed. +///

Provides HibernateTemplate's data access methods that mirror +/// various Session methods. See the NHibernate ISession documentation +/// for details on those methods. +///

+///
+/// Mark Pollack (.NET) +/// +public interface ICommonHibernateOperations { /// - /// Interface that specifies a set of Hibernate operations that - /// are common across versions of Hibernate. + /// Remove all objects from the Session cache, and cancel all pending saves, + /// updates and deletes. + /// + /// In case of Hibernate errors + void Clear(); + + /// + /// Delete the given persistent instance. + /// + /// The persistent instance to delete. + /// In case of Hibernate errors + void Delete(object entity); + + /// + /// Delete the given persistent instance. /// /// - /// Base interface for generic and non generic IHibernateOperations interfaces - /// Not often used, but a useful option - /// to enhance testability, as it can easily be mocked or stubbed. - ///

Provides HibernateTemplate's data access methods that mirror - /// various Session methods. See the NHibernate ISession documentation - /// for details on those methods. - ///

- ///
- /// Mark Pollack (.NET) - /// - public interface ICommonHibernateOperations - { - /// - /// Remove all objects from the Session cache, and cancel all pending saves, - /// updates and deletes. - /// - /// In case of Hibernate errors - void Clear(); + /// Obtains the specified lock mode if the instance exists, implicitly + /// checking whether the corresponding database entry still exists + /// (throwing an OptimisticLockingFailureException if not found). + ///
+ /// The persistent instance to delete. + /// The lock mode to obtain. + /// In case of Hibernate errors + void Delete(object entity, LockMode lockMode); + /// + /// Delete all objects returned by the query. + /// + /// a query expressed in Hibernate's query language. + /// The number of entity instances deleted. + /// In case of Hibernate errors + int Delete(string queryString); - /// - /// Delete the given persistent instance. - /// - /// The persistent instance to delete. - /// In case of Hibernate errors - void Delete(object entity); + /// + /// Delete all objects returned by the query. + /// + /// a query expressed in Hibernate's query language. + /// The value of the parameter. + /// The Hibernate type of the parameter (or null). + /// The number of entity instances deleted. + /// In case of Hibernate errors + int Delete(string queryString, object value, IType type); - /// - /// Delete the given persistent instance. - /// - /// - /// Obtains the specified lock mode if the instance exists, implicitly - /// checking whether the corresponding database entry still exists - /// (throwing an OptimisticLockingFailureException if not found). - /// - /// The persistent instance to delete. - /// The lock mode to obtain. - /// In case of Hibernate errors - void Delete(object entity, LockMode lockMode); + /// + /// Delete all objects returned by the query. + /// + /// a query expressed in Hibernate's query language. + /// The values of the parameters. + /// Hibernate types of the parameters (or null) + /// The number of entity instances deleted. + /// In case of Hibernate errors + int Delete(string queryString, object[] values, IType[] types); + /// + /// Flush all pending saves, updates and deletes to the database. + /// + /// + /// Only invoke this for selective eager flushing, for example when ADO.NET code + /// needs to see certain changes within the same transaction. Else, it's preferable + /// to rely on auto-flushing at transaction completion. + /// + /// In case of Hibernate errors + void Flush(); - /// - /// Delete all objects returned by the query. - /// - /// a query expressed in Hibernate's query language. - /// The number of entity instances deleted. - /// In case of Hibernate errors - int Delete(string queryString); + /// + /// Load the persistent instance with the given identifier + /// into the given object, throwing an exception if not found. + /// + /// Entity the object (of the target class) to load into. + /// An identifier of the persistent instance. + /// If object not found. + /// In case of Hibernate errors + void Load(object entity, object id); - /// - /// Delete all objects returned by the query. - /// - /// a query expressed in Hibernate's query language. - /// The value of the parameter. - /// The Hibernate type of the parameter (or null). - /// The number of entity instances deleted. - /// In case of Hibernate errors - int Delete(string queryString, object value, IType type); + /// + /// Re-read the state of the given persistent instance. + /// + /// The persistent instance to re-read. + /// In case of Hibernate errors + void Refresh(object entity); + /// + /// Re-read the state of the given persistent instance. + /// Obtains the specified lock mode for the instance. + /// + /// The persistent instance to re-read. + /// The lock mode to obtain. + /// In case of Hibernate errors + void Refresh(object entity, LockMode lockMode); - /// - /// Delete all objects returned by the query. - /// - /// a query expressed in Hibernate's query language. - /// The values of the parameters. - /// Hibernate types of the parameters (or null) - /// The number of entity instances deleted. - /// In case of Hibernate errors - int Delete(string queryString, object[] values, IType[] types); + /// + /// Determines whether the given object is in the Session cache. + /// + /// the persistence instance to check. + /// + /// true if session cache contains the specified entity; otherwise, false. + /// + /// In case of Hibernate errors + bool Contains(object entity); + /// + /// Remove the given object from the Session cache. + /// + /// The persistent instance to evict. + /// In case of Hibernate errors + void Evict(object entity); - /// - /// Flush all pending saves, updates and deletes to the database. - /// - /// - /// Only invoke this for selective eager flushing, for example when ADO.NET code - /// needs to see certain changes within the same transaction. Else, it's preferable - /// to rely on auto-flushing at transaction completion. - /// - /// In case of Hibernate errors - void Flush(); + /// + /// Obtain the specified lock level upon the given object, implicitly + /// checking whether the corresponding database entry still exists + /// (throwing an OptimisticLockingFailureException if not found). + /// + /// The he persistent instance to lock. + /// The lock mode to obtain. + /// If not found + /// In case of Hibernate errors + void Lock(object entity, LockMode lockMode); - /// - /// Load the persistent instance with the given identifier - /// into the given object, throwing an exception if not found. - /// - /// Entity the object (of the target class) to load into. - /// An identifier of the persistent instance. - /// If object not found. - /// In case of Hibernate errors - void Load(object entity, object id); + /// + /// Persist the given transient instance. + /// + /// The transient instance to persist. + /// The generated identifier. + /// In case of Hibernate errors + object Save(object entity); + /// + /// Persist the given transient instance with the given identifier. + /// + /// The transient instance to persist. + /// The identifier to assign. + /// In case of Hibernate errors + void Save(object entity, object id); - /// - /// Re-read the state of the given persistent instance. - /// - /// The persistent instance to re-read. - /// In case of Hibernate errors - void Refresh(object entity); + /// + /// Update the given persistent instance. + /// + /// The persistent instance to update. + /// In case of Hibernate errors + void Update(object entity); - /// - /// Re-read the state of the given persistent instance. - /// Obtains the specified lock mode for the instance. - /// - /// The persistent instance to re-read. - /// The lock mode to obtain. - /// In case of Hibernate errors - void Refresh(object entity, LockMode lockMode); + /// + /// Update the given persistent instance. + /// Obtains the specified lock mode if the instance exists, implicitly + /// checking whether the corresponding database entry still exists + /// (throwing an OptimisticLockingFailureException if not found). + /// + /// The persistent instance to update. + /// The lock mode to obtain. + /// In case of Hibernate errors + void Update(object entity, LockMode lockMode); - /// - /// Determines whether the given object is in the Session cache. - /// - /// the persistence instance to check. - /// - /// true if session cache contains the specified entity; otherwise, false. - /// - /// In case of Hibernate errors - bool Contains(object entity); + /// + /// Save or update the given persistent instance, + /// according to its id (matching the configured "unsaved-value"?). + /// + /// The persistent instance to save or update + /// (to be associated with the Hibernate Session). + /// In case of Hibernate errors + void SaveOrUpdate(object entity); - /// - /// Remove the given object from the Session cache. - /// - /// The persistent instance to evict. - /// In case of Hibernate errors - void Evict(object entity); - - /// - /// Obtain the specified lock level upon the given object, implicitly - /// checking whether the corresponding database entry still exists - /// (throwing an OptimisticLockingFailureException if not found). - /// - /// The he persistent instance to lock. - /// The lock mode to obtain. - /// If not found - /// In case of Hibernate errors - void Lock(object entity, LockMode lockMode); - - - /// - /// Persist the given transient instance. - /// - /// The transient instance to persist. - /// The generated identifier. - /// In case of Hibernate errors - object Save(object entity); - - /// - /// Persist the given transient instance with the given identifier. - /// - /// The transient instance to persist. - /// The identifier to assign. - /// In case of Hibernate errors - void Save(object entity, object id); - - /// - /// Update the given persistent instance. - /// - /// The persistent instance to update. - /// In case of Hibernate errors - void Update(object entity); - - /// - /// Update the given persistent instance. - /// Obtains the specified lock mode if the instance exists, implicitly - /// checking whether the corresponding database entry still exists - /// (throwing an OptimisticLockingFailureException if not found). - /// - /// The persistent instance to update. - /// The lock mode to obtain. - /// In case of Hibernate errors - void Update(object entity, LockMode lockMode); - - /// - /// Save or update the given persistent instance, - /// according to its id (matching the configured "unsaved-value"?). - /// - /// The persistent instance to save or update - /// (to be associated with the Hibernate Session). - /// In case of Hibernate errors - void SaveOrUpdate(object entity); - - /// - /// Copy the state of the given object onto the persistent object with the same identifier. - /// If there is no persistent instance currently associated with the session, it will be loaded. - /// Return the persistent instance. If the given instance is unsaved, - /// save a copy of and return it as a newly persistent instance. - /// The given instance does not become associated with the session. - /// This operation cascades to associated instances if the association is mapped with cascade="merge". - /// The semantics of this method are defined by JSR-220. - /// - /// The persistent object to merge. - /// (not necessarily to be associated with the Hibernate Session) - /// - /// An updated persistent instance - /// In case of Hibernate errors - object Merge(object entity); - } -} \ No newline at end of file + /// + /// Copy the state of the given object onto the persistent object with the same identifier. + /// If there is no persistent instance currently associated with the session, it will be loaded. + /// Return the persistent instance. If the given instance is unsaved, + /// save a copy of and return it as a newly persistent instance. + /// The given instance does not become associated with the session. + /// This operation cascades to associated instances if the association is mapped with cascade="merge". + /// The semantics of this method are defined by JSR-220. + /// + /// The persistent object to merge. + /// (not necessarily to be associated with the Hibernate Session) + /// + /// An updated persistent instance + /// In case of Hibernate errors + object Merge(object entity); +} diff --git a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/IHibernateCallback.cs b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/IHibernateCallback.cs index 6aba22be..2598730a 100644 --- a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/IHibernateCallback.cs +++ b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/IHibernateCallback.cs @@ -1,12 +1,12 @@ /* - * Copyright © 2002-2011 the original author or authors. - * + * Copyright � 2002-2011 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. @@ -16,32 +16,31 @@ using NHibernate; -namespace Spring.Data.NHibernate +namespace Spring.Data.NHibernate; + +/// +/// Callback interface for NHibernate code. +/// +/// To be used with HibernateTemplate execute +/// method. The typical implementation will call +/// Session.load/find/save/update to perform +/// some operations on persistent objects. +/// +/// Mark Pollack (.NET) +public interface IHibernateCallback { - /// - /// Callback interface for NHibernate code. + /// + /// Gets called by HibernateTemplate with an active + /// Hibernate Session. Does not need to care about activating or closing + /// the Session, or handling transactions. /// - /// To be used with HibernateTemplate execute - /// method. The typical implementation will call - /// Session.load/find/save/update to perform - /// some operations on persistent objects. - /// - /// Mark Pollack (.NET) - public interface IHibernateCallback - { - /// - /// Gets called by HibernateTemplate with an active - /// Hibernate Session. Does not need to care about activating or closing - /// the Session, or handling transactions. - /// - /// - ///

- /// Allows for returning a result object created within the callback, i.e. - /// a domain object or a collection of domain objects. Note that there's - /// special support for single step actions: see HibernateTemplate.find etc. - ///

- ///
- /// A result object, or null if none. - object DoInHibernate(ISession session); - } + /// + ///

+ /// Allows for returning a result object created within the callback, i.e. + /// a domain object or a collection of domain objects. Note that there's + /// special support for single step actions: see HibernateTemplate.find etc. + ///

+ ///
+ /// A result object, or null if none. + object DoInHibernate(ISession session); } diff --git a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/IHibernateOperations.cs b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/IHibernateOperations.cs index 2b21a429..106fd466 100644 --- a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/IHibernateOperations.cs +++ b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/IHibernateOperations.cs @@ -1,12 +1,12 @@ /* * Copyright � 2002-2011 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. @@ -19,393 +19,377 @@ using NHibernate; using NHibernate.Type; using Spring.Dao; -namespace Spring.Data.NHibernate +namespace Spring.Data.NHibernate; + +/// +/// Interface that specifies a basic set of Hibernate operations. +/// +/// +/// Implemented by HibernateTemplate. Not often used, but a useful option +/// to enhance testability, as it can easily be mocked or stubbed. +///

Provides HibernateTemplate's data access methods that mirror +/// various Session methods. See the NHibernate ISession documentation +/// for details on those methods. +///

+///
+/// +/// Mark Pollack (.NET) +public interface IHibernateOperations : ICommonHibernateOperations { - /// - /// Interface that specifies a basic set of Hibernate operations. + /// + /// Delete all given persistent instances. + /// + /// The persistent instances to delete. + /// + /// This can be combined with any of the find methods to delete by query + /// in two lines of code, similar to Session's delete by query methods. + /// + /// In case of Hibernate errors + void DeleteAll(ICollection entities); + + /// + /// Execute the action specified by the given action object within a Session. /// /// - /// Implemented by HibernateTemplate. Not often used, but a useful option - /// to enhance testability, as it can easily be mocked or stubbed. - ///

Provides HibernateTemplate's data access methods that mirror - /// various Session methods. See the NHibernate ISession documentation - /// for details on those methods. + /// Application exceptions thrown by the action object get propagated to the + /// caller (can only be unchecked). Hibernate exceptions are transformed into + /// appropriate DAO ones. Allows for returning a result object, i.e. a domain + /// object or a collection of domain objects. + ///

Note: Callback code is not supposed to handle transactions itself! + /// Use an appropriate transaction manager like HibernateTransactionManager. + /// Generally, callback code must not touch any Session lifecycle methods, + /// like close, disconnect, or reconnect, to let the template do its work. ///

///
- /// - /// Mark Pollack (.NET) - public interface IHibernateOperations : ICommonHibernateOperations - { + /// The delegate callback object that specifies the Hibernate action. + /// a result object returned by the action, or null + /// + /// In case of Hibernate errors + object Execute(HibernateDelegate del); - /// - /// Delete all given persistent instances. - /// - /// The persistent instances to delete. - /// - /// This can be combined with any of the find methods to delete by query - /// in two lines of code, similar to Session's delete by query methods. - /// - /// In case of Hibernate errors - void DeleteAll(ICollection entities); + /// + /// Execute the action specified by the given action object within a Session. + /// + /// + /// Application exceptions thrown by the action object get propagated to the + /// caller (can only be unchecked). Hibernate exceptions are transformed into + /// appropriate DAO ones. Allows for returning a result object, i.e. a domain + /// object or a collection of domain objects. + ///

Note: Callback code is not supposed to handle transactions itself! + /// Use an appropriate transaction manager like HibernateTransactionManager. + /// Generally, callback code must not touch any Session lifecycle methods, + /// like close, disconnect, or reconnect, to let the template do its work. + ///

+ ///
+ /// The callback object that specifies the Hibernate action. + /// a result object returned by the action, or null + /// + /// In case of Hibernate errors + object Execute(IHibernateCallback action); - /// - /// Execute the action specified by the given action object within a Session. - /// - /// - /// Application exceptions thrown by the action object get propagated to the - /// caller (can only be unchecked). Hibernate exceptions are transformed into - /// appropriate DAO ones. Allows for returning a result object, i.e. a domain - /// object or a collection of domain objects. - ///

Note: Callback code is not supposed to handle transactions itself! - /// Use an appropriate transaction manager like HibernateTransactionManager. - /// Generally, callback code must not touch any Session lifecycle methods, - /// like close, disconnect, or reconnect, to let the template do its work. - ///

- ///
- /// The delegate callback object that specifies the Hibernate action. - /// a result object returned by the action, or null - /// - /// In case of Hibernate errors - object Execute(HibernateDelegate del); + /// + /// Execute the specified action assuming that the result object is a List. + /// + /// + /// This is a convenience method for executing Hibernate find calls or + /// queries within an action. + /// + /// The calback object that specifies the Hibernate action. + /// A IList returned by the action, or null + /// + /// In case of Hibernate errors + IList ExecuteFind(IHibernateCallback action); - /// - /// Execute the action specified by the given action object within a Session. - /// - /// - /// Application exceptions thrown by the action object get propagated to the - /// caller (can only be unchecked). Hibernate exceptions are transformed into - /// appropriate DAO ones. Allows for returning a result object, i.e. a domain - /// object or a collection of domain objects. - ///

Note: Callback code is not supposed to handle transactions itself! - /// Use an appropriate transaction manager like HibernateTransactionManager. - /// Generally, callback code must not touch any Session lifecycle methods, - /// like close, disconnect, or reconnect, to let the template do its work. - ///

- ///
- /// The callback object that specifies the Hibernate action. - /// a result object returned by the action, or null - /// - /// In case of Hibernate errors - object Execute(IHibernateCallback action); + /// + /// Execute a query for persistent instances. + /// + /// a query expressed in Hibernate's query language + /// a List containing 0 or more persistent instances + /// In case of Hibernate errors + IList Find(string queryString); + /// + /// Execute a query for persistent instances, binding + /// one value to a "?" parameter in the query string. + /// + /// a query expressed in Hibernate's query language + /// the value of the parameter + /// a List containing 0 or more persistent instances + /// In case of Hibernate errors + IList Find(string queryString, object value); - /// - /// Execute the specified action assuming that the result object is a List. - /// - /// - /// This is a convenience method for executing Hibernate find calls or - /// queries within an action. - /// - /// The calback object that specifies the Hibernate action. - /// A IList returned by the action, or null - /// - /// In case of Hibernate errors - IList ExecuteFind(IHibernateCallback action); + /// + /// Execute a query for persistent instances, binding one value + /// to a "?" parameter of the given type in the query string. + /// + /// a query expressed in Hibernate's query language + /// The value of the parameter. + /// Hibernate type of the parameter (or null) + /// a List containing 0 or more persistent instances + /// In case of Hibernate errors + IList Find(string queryString, object value, IType type); - /// - /// Execute a query for persistent instances. - /// - /// a query expressed in Hibernate's query language - /// a List containing 0 or more persistent instances - /// In case of Hibernate errors - IList Find(string queryString); + /// + /// Execute a query for persistent instances, binding a + /// number of values to "?" parameters in the query string. + /// + /// a query expressed in Hibernate's query language + /// the values of the parameters + /// a List containing 0 or more persistent instances + /// In case of Hibernate errors + IList Find(string queryString, object[] values); + /// + /// Execute a query for persistent instances, binding a number of + /// values to "?" parameters of the given types in the query string. + /// + /// A query expressed in Hibernate's query language + /// The values of the parameters + /// Hibernate types of the parameters (or null) + /// a List containing 0 or more persistent instances + /// In case of Hibernate errors + /// If values and types are not null and their lengths are not equal + IList Find(string queryString, object[] values, IType[] types); - /// - /// Execute a query for persistent instances, binding - /// one value to a "?" parameter in the query string. - /// - /// a query expressed in Hibernate's query language - /// the value of the parameter - /// a List containing 0 or more persistent instances - /// In case of Hibernate errors - IList Find(string queryString, object value); + /// + /// Execute a query for persistent instances, binding + /// one value to a named parameter in the query string. + /// + /// The name of a Hibernate query in a mapping file + /// The name of the parameter + /// The value of the parameter + /// a List containing 0 or more persistent instances + /// In case of Hibernate errors + IList FindByNamedParam(string queryName, string paramName, object value); - /// - /// Execute a query for persistent instances, binding one value - /// to a "?" parameter of the given type in the query string. - /// - /// a query expressed in Hibernate's query language - /// The value of the parameter. - /// Hibernate type of the parameter (or null) - /// a List containing 0 or more persistent instances - /// In case of Hibernate errors - IList Find(string queryString, object value, IType type); + /// + /// Execute a query for persistent instances, binding + /// one value to a named parameter in the query string. + /// + /// The name of a Hibernate query in a mapping file + /// The name of the parameter + /// The value of the parameter + /// Hibernate type of the parameter (or null) + /// A List containing 0 or more persistent instances + /// In case of Hibernate errors + IList FindByNamedParam(string queryName, string paramName, object value, IType type); + /// + /// Execute a query for persistent instances, binding a + /// number of values to named parameters in the query string. + /// + /// A query expressed in Hibernate's query language + /// The names of the parameters + /// The values of the parameters + /// A List containing 0 or more persistent instances + /// In case of Hibernate errors + IList FindByNamedParam(string queryString, string[] paramNames, object[] values); - /// - /// Execute a query for persistent instances, binding a - /// number of values to "?" parameters in the query string. - /// - /// a query expressed in Hibernate's query language - /// the values of the parameters - /// a List containing 0 or more persistent instances - /// In case of Hibernate errors - IList Find(string queryString, object[] values); + /// + /// Execute a query for persistent instances, binding a + /// number of values to named parameters in the query string. + /// + /// A query expressed in Hibernate's query language + /// The names of the parameters + /// The values of the parameters + /// Hibernate types of the parameters (or null) + /// A List containing 0 or more persistent instances + /// In case of Hibernate errors + /// If paramNames length is not equal to values length or + /// if paramNames length is not equal to types length (when types is not null) + IList FindByNamedParam(string queryString, string[] paramNames, object[] values, IType[] types); + /// + /// Execute a named query for persistent instances. + /// A named query is defined in a Hibernate mapping file. + /// + /// The name of a Hibernate query in a mapping file + /// A List containing 0 or more persistent instances + /// In case of Hibernate errors + IList FindByNamedQuery(string queryName); + /// + /// Execute a named query for persistent instances, binding + /// one value to a "?" parameter in the query string. + /// A named query is defined in a Hibernate mapping file. + /// + /// The name of a Hibernate query in a mapping file + /// The value of the parameter + /// A List containing 0 or more persistent instances + /// In case of Hibernate errors + IList FindByNamedQuery(string queryName, object value); - /// - /// Execute a query for persistent instances, binding a number of - /// values to "?" parameters of the given types in the query string. - /// - /// A query expressed in Hibernate's query language - /// The values of the parameters - /// Hibernate types of the parameters (or null) - /// a List containing 0 or more persistent instances - /// In case of Hibernate errors - /// If values and types are not null and their lengths are not equal - IList Find(string queryString, object[] values, IType[] types); + /// + /// Execute a named query for persistent instances, binding + /// one value to a "?" parameter in the query string. + /// A named query is defined in a Hibernate mapping file. + /// + /// The name of a Hibernate query in a mapping file + /// The value of the parameter + /// Hibernate type of the parameter (or null) + /// A List containing 0 or more persistent instances + /// In case of Hibernate errors + IList FindByNamedQuery(string queryName, object value, IType type); + /// + /// Execute a named query for persistent instances, binding a + /// number of values to "?" parameters in the query string. + /// A named query is defined in a Hibernate mapping file. + /// + /// The name of a Hibernate query in a mapping file + /// The values of the parameters + /// A List containing 0 or more persistent instances + /// In case of Hibernate errors + IList FindByNamedQuery(string queryName, object[] values); - /// - /// Execute a query for persistent instances, binding - /// one value to a named parameter in the query string. - /// - /// The name of a Hibernate query in a mapping file - /// The name of the parameter - /// The value of the parameter - /// a List containing 0 or more persistent instances - /// In case of Hibernate errors - IList FindByNamedParam(string queryName, string paramName, object value); + /// + /// Execute a named query for persistent instances, binding a + /// number of values to "?" parameters in the query string. + /// A named query is defined in a Hibernate mapping file. + /// + /// The name of a Hibernate query in a mapping file + /// The values of the parameters + /// Hibernate types of the parameters (or null) + /// A List containing 0 or more persistent instances + /// In case of Hibernate errors + /// If values and types are not null and their lengths differ. + IList FindByNamedQuery(string queryName, object[] values, IType[] types); - /// - /// Execute a query for persistent instances, binding - /// one value to a named parameter in the query string. - /// - /// The name of a Hibernate query in a mapping file - /// The name of the parameter - /// The value of the parameter - /// Hibernate type of the parameter (or null) - /// A List containing 0 or more persistent instances - /// In case of Hibernate errors - IList FindByNamedParam(string queryName, string paramName, object value, IType type); + /// + /// Execute a named query for persistent instances, binding + /// one value to a named parameter in the query string. + /// A named query is defined in a Hibernate mapping file. + /// + /// The name of a Hibernate query in a mapping file + /// Name of the parameter + /// The value of the parameter + /// A List containing 0 or more persistent instances + /// In case of Hibernate errors + IList FindByNamedQueryAndNamedParam(string queryName, string paramName, object value); - /// - /// Execute a query for persistent instances, binding a - /// number of values to named parameters in the query string. - /// - /// A query expressed in Hibernate's query language - /// The names of the parameters - /// The values of the parameters - /// A List containing 0 or more persistent instances - /// In case of Hibernate errors - IList FindByNamedParam(string queryString, string[] paramNames, object[] values); + /// + /// Execute a named query for persistent instances, binding + /// one value to a named parameter in the query string. + /// A named query is defined in a Hibernate mapping file. + /// + /// The name of a Hibernate query in a mapping file + /// Name of the parameter + /// The value of the parameter + /// The Hibernate type of the parameter (or null) + /// A List containing 0 or more persistent instances + /// In case of Hibernate errors + IList FindByNamedQueryAndNamedParam(string queryName, string paramName, object value, IType type); + /// + /// Execute a named query for persistent instances, binding + /// number of values to named parameters in the query string. + /// A named query is defined in a Hibernate mapping file. + /// + /// The name of a Hibernate query in a mapping file + /// The names of the parameters + /// The values of the parameters. + /// A List containing 0 or more persistent instances + /// In case of Hibernate errors + IList FindByNamedQueryAndNamedParam(string queryName, string[] paramNames, object[] values); - /// - /// Execute a query for persistent instances, binding a - /// number of values to named parameters in the query string. - /// - /// A query expressed in Hibernate's query language - /// The names of the parameters - /// The values of the parameters - /// Hibernate types of the parameters (or null) - /// A List containing 0 or more persistent instances - /// In case of Hibernate errors - /// If paramNames length is not equal to values length or - /// if paramNames length is not equal to types length (when types is not null) - IList FindByNamedParam(string queryString, string[] paramNames, object[] values, IType[] types); + /// + /// Execute a named query for persistent instances, binding + /// number of values to named parameters in the query string. + /// A named query is defined in a Hibernate mapping file. + /// + /// The name of a Hibernate query in a mapping file + /// The names of the parameters + /// The values of the parameters. + /// Hibernate types of the parameters (or null) + /// A List containing 0 or more persistent instances + /// In case of Hibernate errors + /// If paramNames length is not equal to values length or + /// if paramNames length is not equal to types length (when types is not null) + IList FindByNamedQueryAndNamedParam(string queryName, string[] paramNames, object[] values, IType[] types); - /// - /// Execute a named query for persistent instances. - /// A named query is defined in a Hibernate mapping file. - /// - /// The name of a Hibernate query in a mapping file - /// A List containing 0 or more persistent instances - /// In case of Hibernate errors - IList FindByNamedQuery(string queryName); + /// + /// Execute a named query for persistent instances, binding the properties + /// of the given object to named parameters in the query string. + /// A named query is defined in a Hibernate mapping file. + /// + /// The name of a Hibernate query in a mapping file + /// The values of the parameters + /// A List containing 0 or more persistent instances + /// In case of Hibernate errors + IList FindByNamedQueryAndValueObject(string queryName, object valueObject); - /// - /// Execute a named query for persistent instances, binding - /// one value to a "?" parameter in the query string. - /// A named query is defined in a Hibernate mapping file. - /// - /// The name of a Hibernate query in a mapping file - /// The value of the parameter - /// A List containing 0 or more persistent instances - /// In case of Hibernate errors - IList FindByNamedQuery(string queryName, object value); + /// + /// Execute a query for persistent instances, binding the properties + /// of the given object to named parameters in the query string. + /// + /// A query expressed in Hibernate's query language + /// The values of the parameters + /// A List containing 0 or more persistent instances + /// In case of Hibernate errors + IList FindByValueObject(string queryString, object valueObject); - /// - /// Execute a named query for persistent instances, binding - /// one value to a "?" parameter in the query string. - /// A named query is defined in a Hibernate mapping file. - /// - /// The name of a Hibernate query in a mapping file - /// The value of the parameter - /// Hibernate type of the parameter (or null) - /// A List containing 0 or more persistent instances - /// In case of Hibernate errors - IList FindByNamedQuery(string queryName, object value, IType type); + /// + /// Return the persistent instance of the given entity type + /// with the given identifier, or null if not found. + /// + /// a persistent type. + /// An identifier of the persistent instance. + /// the persistent instance, or null if not found + /// In case of Hibernate errors + object Get(Type entityType, object id); - - /// - /// Execute a named query for persistent instances, binding a - /// number of values to "?" parameters in the query string. - /// A named query is defined in a Hibernate mapping file. - /// - /// The name of a Hibernate query in a mapping file - /// The values of the parameters - /// A List containing 0 or more persistent instances - /// In case of Hibernate errors - IList FindByNamedQuery(string queryName, object[] values); + /// + /// Return the persistent instance of the given entity type + /// with the given identifier, or null if not found. + /// Obtains the specified lock mode if the instance exists. + /// + /// A persistent class. + /// An identifier of the persistent instance. + /// The lock mode. + /// the persistent instance, or null if not found + /// the persistent instance, or null if not found + /// In case of Hibernate errors + object Get(Type entityType, object id, LockMode lockMode); + /// + /// Return the persistent instance of the given entity class + /// with the given identifier, throwing an exception if not found. + /// + /// Type of the entity. + /// An identifier of the persistent instance. + /// The persistent instance + /// If not found + /// In case of Hibernate errors + object Load(Type entityType, object id); - /// - /// Execute a named query for persistent instances, binding a - /// number of values to "?" parameters in the query string. - /// A named query is defined in a Hibernate mapping file. - /// - /// The name of a Hibernate query in a mapping file - /// The values of the parameters - /// Hibernate types of the parameters (or null) - /// A List containing 0 or more persistent instances - /// In case of Hibernate errors - /// If values and types are not null and their lengths differ. - IList FindByNamedQuery(string queryName, object[] values, IType[] types); + /// + /// Return the persistent instance of the given entity class + /// with the given identifier, throwing an exception if not found. + /// Obtains the specified lock mode if the instance exists. + /// + /// Type of the entity. + /// An identifier of the persistent instance. + /// The lock mode. + /// The persistent instance + /// If not found + /// In case of Hibernate errors + object Load(Type entityType, object id, LockMode lockMode); - /// - /// Execute a named query for persistent instances, binding - /// one value to a named parameter in the query string. - /// A named query is defined in a Hibernate mapping file. - /// - /// The name of a Hibernate query in a mapping file - /// Name of the parameter - /// The value of the parameter - /// A List containing 0 or more persistent instances - /// In case of Hibernate errors - IList FindByNamedQueryAndNamedParam(string queryName, string paramName, object value); - - /// - /// Execute a named query for persistent instances, binding - /// one value to a named parameter in the query string. - /// A named query is defined in a Hibernate mapping file. - /// - /// The name of a Hibernate query in a mapping file - /// Name of the parameter - /// The value of the parameter - /// The Hibernate type of the parameter (or null) - /// A List containing 0 or more persistent instances - /// In case of Hibernate errors - IList FindByNamedQueryAndNamedParam(string queryName, string paramName, object value, IType type); - - /// - /// Execute a named query for persistent instances, binding - /// number of values to named parameters in the query string. - /// A named query is defined in a Hibernate mapping file. - /// - /// The name of a Hibernate query in a mapping file - /// The names of the parameters - /// The values of the parameters. - /// A List containing 0 or more persistent instances - /// In case of Hibernate errors - IList FindByNamedQueryAndNamedParam(string queryName, string[] paramNames, object[] values); + /// + /// Return all persistent instances of the given entity class. + /// Note: Use queries or criteria for retrieving a specific subset. + /// + /// Type of the entity. + /// A List containing 0 or more persistent instances + /// In case of Hibernate errors + IList LoadAll(Type entityType); - - /// - /// Execute a named query for persistent instances, binding - /// number of values to named parameters in the query string. - /// A named query is defined in a Hibernate mapping file. - /// - /// The name of a Hibernate query in a mapping file - /// The names of the parameters - /// The values of the parameters. - /// Hibernate types of the parameters (or null) - /// A List containing 0 or more persistent instances - /// In case of Hibernate errors - /// If paramNames length is not equal to values length or - /// if paramNames length is not equal to types length (when types is not null) - IList FindByNamedQueryAndNamedParam(string queryName, string[] paramNames, object[] values, IType[] types); - - - /// - /// Execute a named query for persistent instances, binding the properties - /// of the given object to named parameters in the query string. - /// A named query is defined in a Hibernate mapping file. - /// - /// The name of a Hibernate query in a mapping file - /// The values of the parameters - /// A List containing 0 or more persistent instances - /// In case of Hibernate errors - IList FindByNamedQueryAndValueObject(string queryName, object valueObject); - - /// - /// Execute a query for persistent instances, binding the properties - /// of the given object to named parameters in the query string. - /// - /// A query expressed in Hibernate's query language - /// The values of the parameters - /// A List containing 0 or more persistent instances - /// In case of Hibernate errors - IList FindByValueObject(string queryString, object valueObject); - - /// - /// Return the persistent instance of the given entity type - /// with the given identifier, or null if not found. - /// - /// a persistent type. - /// An identifier of the persistent instance. - /// the persistent instance, or null if not found - /// In case of Hibernate errors - object Get(Type entityType, object id); - - /// - /// Return the persistent instance of the given entity type - /// with the given identifier, or null if not found. - /// Obtains the specified lock mode if the instance exists. - /// - /// A persistent class. - /// An identifier of the persistent instance. - /// The lock mode. - /// the persistent instance, or null if not found - /// the persistent instance, or null if not found - /// In case of Hibernate errors - object Get(Type entityType, object id, LockMode lockMode); - - /// - /// Return the persistent instance of the given entity class - /// with the given identifier, throwing an exception if not found. - /// - /// Type of the entity. - /// An identifier of the persistent instance. - /// The persistent instance - /// If not found - /// In case of Hibernate errors - object Load(Type entityType, object id); - - /// - /// Return the persistent instance of the given entity class - /// with the given identifier, throwing an exception if not found. - /// Obtains the specified lock mode if the instance exists. - /// - /// Type of the entity. - /// An identifier of the persistent instance. - /// The lock mode. - /// The persistent instance - /// If not found - /// In case of Hibernate errors - object Load(Type entityType, object id, LockMode lockMode); - - - - /// - /// Return all persistent instances of the given entity class. - /// Note: Use queries or criteria for retrieving a specific subset. - /// - /// Type of the entity. - /// A List containing 0 or more persistent instances - /// In case of Hibernate errors - IList LoadAll(Type entityType); - - - /// - /// Save or update all given persistent instances, - /// according to its id (matching the configured "unsaved-value"?). - /// - /// The persistent instances to save or update - /// (to be associated with the Hibernate Session)he entities. - /// In case of Hibernate errors - void SaveOrUpdateAll(ICollection entities); - } + /// + /// Save or update all given persistent instances, + /// according to its id (matching the configured "unsaved-value"?). + /// + /// The persistent instances to save or update + /// (to be associated with the Hibernate Session)he entities. + /// In case of Hibernate errors + void SaveOrUpdateAll(ICollection entities); } diff --git a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/LocalSessionFactoryObject.cs b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/LocalSessionFactoryObject.cs index b24adcc7..f4163b5e 100644 --- a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/LocalSessionFactoryObject.cs +++ b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/LocalSessionFactoryObject.cs @@ -36,954 +36,957 @@ using Spring.Data.Support; using Spring.Objects.Factory; using Spring.Objects.Factory.Config; using Spring.Util; - using Environment = NHibernate.Cfg.Environment; using Configuration = NHibernate.Cfg.Configuration; -namespace Spring.Data.NHibernate +namespace Spring.Data.NHibernate; + +/// +/// An IFactoryObject that creates a local Hibernate SessionFactory instance. +/// Behaves like a SessionFactory instance when used as bean reference, +/// e.g. for HibernateTemplate's "SessionFactory" property. +/// +/// +/// The typical usage will be to register this as singleton factory +/// in an application context and give objects references to application services +/// that need it. +/// +/// Hibernate configuration settings can be set using the IDictionary property 'HibernateProperties'. +/// +/// +/// This class implements the interface, +/// as autodetected by Spring's +/// for AOP-based translation of PersistenceExceptionTranslationPostProcessor. +/// Hence, the presence of e.g. LocalSessionFactoryBean automatically enables +/// a PersistenceExceptionTranslationPostProcessor to translate Hibernate exceptions. +/// +/// +/// Mark Pollack (.NET) +public class LocalSessionFactoryObject : IFactoryObject, IInitializingObject, IPersistenceExceptionTranslator, IDisposable + , IApplicationContextAware { - /// - /// An IFactoryObject that creates a local Hibernate SessionFactory instance. - /// Behaves like a SessionFactory instance when used as bean reference, - /// e.g. for HibernateTemplate's "SessionFactory" property. - /// - /// - /// The typical usage will be to register this as singleton factory - /// in an application context and give objects references to application services - /// that need it. - /// - /// Hibernate configuration settings can be set using the IDictionary property 'HibernateProperties'. - /// - /// - /// This class implements the interface, - /// as autodetected by Spring's - /// for AOP-based translation of PersistenceExceptionTranslationPostProcessor. - /// Hence, the presence of e.g. LocalSessionFactoryBean automatically enables - /// a PersistenceExceptionTranslationPostProcessor to translate Hibernate exceptions. - /// - /// - /// Mark Pollack (.NET) - public class LocalSessionFactoryObject : IFactoryObject, IInitializingObject, IPersistenceExceptionTranslator, IDisposable - , IApplicationContextAware - { - private Configuration configuration; + private Configuration configuration; - private ISessionFactory sessionFactory; + private ISessionFactory sessionFactory; - private string[] mappingAssemblies; + private string[] mappingAssemblies; - private string[] mappingResources; + private string[] mappingResources; - private string[] configFilenames; + private string[] configFilenames; - private IDictionary hibernateProperties; + private IDictionary hibernateProperties; - private IDbProvider dbProvider; + private IDbProvider dbProvider; - private IInterceptor entityInterceptor; + private IInterceptor entityInterceptor; - private INamingStrategy namingStrategy; + private INamingStrategy namingStrategy; - private IObjectDefinition[] typeDefinitions; + private IObjectDefinition[] typeDefinitions; - private FilterDefinition[] filterDefinitions; + private FilterDefinition[] filterDefinitions; - private Properties entityCacheStrategies; + private Properties entityCacheStrategies; - private Properties collectionCacheStrategies; + private Properties collectionCacheStrategies; - private IDictionary eventListeners; + private IDictionary eventListeners; - private bool schemaUpdate = false; + private bool schemaUpdate = false; - private IAdoExceptionTranslator adoExceptionTranslator; + private IAdoExceptionTranslator adoExceptionTranslator; - private IResourceLoader resourceLoader; + private IResourceLoader resourceLoader; - private IApplicationContext applicationContext; + private IApplicationContext applicationContext; - // Configuration time DB provider. - // This will not be available after configuration has been done. - private static IDbProvider configTimeDbProvider; + // Configuration time DB provider. + // This will not be available after configuration has been done. + private static IDbProvider configTimeDbProvider; - private IBytecodeProvider bytecodeProvider; + private IBytecodeProvider bytecodeProvider; - /// - /// The shared instance for this class (and derived classes). - /// - protected static readonly ILogger log = LogManager.GetLogger(); + /// + /// The shared instance for this class (and derived classes). + /// + protected static readonly ILogger log = LogManager.GetLogger(); - /// - /// Initializes a new instance of the class. - /// - public LocalSessionFactoryObject() - { + /// + /// Initializes a new instance of the class. + /// + public LocalSessionFactoryObject() + { + } - } + /// + /// Setting the Application Context determines were resources are loaded from + /// + public IApplicationContext ApplicationContext + { + set { applicationContext = value; } + protected get { return applicationContext; } + } - /// - /// Setting the Application Context determines were resources are loaded from - /// - public IApplicationContext ApplicationContext - { - set { applicationContext = value; } - protected get { return applicationContext; } - } - - /// - /// Gets or sets the to use for loading mapping assemblies etc. - /// - public IResourceLoader ResourceLoader - { - get - { - if (resourceLoader == null) - { - resourceLoader = new ConfigurableResourceLoader(); - } - return resourceLoader; - } - set => resourceLoader = value; - } - - /// - /// Sets the assemblies to load that contain mapping files. - /// - /// The mapping assemblies. - public string[] MappingAssemblies - { - set => mappingAssemblies = value; - } - - /// - /// Sets the hibernate configuration files to load, i.e. hibernate.cfg.xml. - /// - public string[] ConfigFilenames - { - set => configFilenames = value; - } - - /// - /// Sets the locations of Spring IResources that contain mapping - /// files. - /// - /// The location of mapping resources. - public string[] MappingResources - { - set => mappingResources = value; - } - - /// - /// Return the Configuration object used to build the SessionFactory. - /// Allows access to configuration metadata stored there (rarely needed). - /// - /// The hibernate configuration. - public Configuration Configuration => configuration; - - /// - /// Set NHibernate configuration properties, like "hibernate.dialect". - /// - /// The hibernate properties. - /// - ///

Can be used to override values in a NHibernate XML config file, - /// or to specify all necessary properties locally. - ///

- ///

Note: Do not specify a transaction provider here when using - /// Spring-driven transactions. It is also advisable to omit connection - /// provider settings and use a Spring-set IDbProvider instead. - ///

- ///
- public IDictionary HibernateProperties - { - get - { - if (hibernateProperties == null) - { - hibernateProperties = new Dictionary(); - } - return hibernateProperties; - } - set => hibernateProperties = value; - } - - /// - /// Get or set the DataSource to be used by the SessionFactory. - /// - /// The db provider. - /// - /// If set, this will override corresponding settings in Hibernate properties. - /// Note: If this is set, the Hibernate settings should not define - /// a connection string - /// (hibernate.connection.connection_string) to avoid meaningless double configuration. - /// - /// - public IDbProvider DbProvider - { - set => dbProvider = value; - get => dbProvider; - } - - /// - /// Gets or sets a value indicating whether to expose a transaction aware session factory. - /// - /// - /// true if want to expose transaction aware session factory; otherwise, false. - /// - public bool ExposeTransactionAwareSessionFactory { set; get; } = false; - - - /// - /// Set a NHibernate entity interceptor that allows to inspect and change - /// property values before writing to and reading from the database. - /// Will get applied to any new Session created by this factory. - ///

Such an interceptor can either be set at the SessionFactory level, i.e. on - /// LocalSessionFactoryObject, or at the Session level, i.e. on HibernateTemplate, - /// HibernateInterceptor, and HibernateTransactionManager. It's preferable to set - /// it on LocalSessionFactoryObject or HibernateTransactionManager to avoid repeated - /// configuration and guarantee consistent behavior in transactions.

- ///
- /// - /// - public IInterceptor EntityInterceptor + /// + /// Gets or sets the to use for loading mapping assemblies etc. + /// + public IResourceLoader ResourceLoader + { + get { - set => entityInterceptor = value; - } - - /// - /// Set a Hibernate NamingStrategy for the SessionFactory, determining the - /// physical column and table names given the info in the mapping document. - /// - public INamingStrategy NamingStrategy - { - set => namingStrategy = value; - } - - /// - /// Specify the Hibernate type definitions to register with the SessionFactory, - /// as Spring IObjectDefinition instances. This is an alternative to specifying - /// <typedef> elements in Hibernate mapping files. - ///

Unfortunately, Hibernate itself does not define a complete object that - /// represents a type definition, hence the need for Spring's TypeDefinitionBean.

- /// @see TypeDefinitionBean - /// @see org.hibernate.cfg.Mappings#addTypeDef(String, String, java.util.Properties) - ///
- public IObjectDefinition[] TypeDefinitions - { - set => typeDefinitions = value; - } - - - /// - /// Specify the NHibernate FilterDefinitions to register with the SessionFactory. - /// This is an alternative to specifying <filter-def> elements in - /// Hibernate mapping files. - /// - /// - /// Typically, the passed-in FilterDefinition objects will have been defined - /// as Spring FilterDefinitionFactoryBeans, probably as inner beans within the - /// LocalSessionFactoryObject definition. - /// - /// - public FilterDefinition[] FilterDefinitions - { - set => filterDefinitions = value; - } - - /// - /// Specify the cache strategies for entities (persistent classes or named entities). - /// This configuration setting corresponds to the <class-cache> entry - /// in the "hibernate.cfg.xml" configuration format. - ///

For example: - ///

-        /// <property name="entityCacheStrategies">
-        ///   <props>
-        ///     <prop key="MyCompany.Customer">read-write</prop>
-        ///     <prop key="MyCompany.Product">read-only,myRegion</prop>
-        ///   </props>
-        /// </property>
- ///

- ///
- public Properties EntityCacheStrategies - { - set => entityCacheStrategies = value; - } - - /// - /// Specify the cache strategies for persistent collections (with specific roles). - /// This configuration setting corresponds to the <collection-cache> entry - /// in the "hibernate.cfg.xml" configuration format. - ///

For example: - ///

-        /// <property name="CollectionCacheStrategies">
-        ///   <props>
-        ///     <prop key="MyCompany.Order.Items">read-write</prop>
-        ///     <prop key="MyCompany.Product.Categories">read-only,myRegion</prop>
-        ///   </props>
-        /// </property>
- ///

- ///
- public Properties CollectionCacheStrategies - { - set => collectionCacheStrategies = value; - } - - - /// - /// Specify the NHibernate event listeners to register, with listener types - /// as keys and listener objects as values. - ///

- /// Instead of a single listener object, you can also pass in a list - /// or set of listeners objects as value. - ///

- ///
- /// listener objects as values - /// - /// See the NHibernate documentation for further details on listener types - /// and associated listener interfaces. - /// - public IDictionary EventListeners - { - set => eventListeners = value; - } - - /// - /// Set whether to execute a schema update after SessionFactory initialization. - ///

- /// For details on how to make schema update scripts work, see the NHibernate - /// documentation, as this class leverages the same schema update script support - /// in as NHibernate's own SchemaUpdate tool. - ///

- ///
- public bool SchemaUpdate - { - set => schemaUpdate = value; - } - - /// - /// Set the ADO.NET exception translator for this instance. - /// Applied to System.Data.Common.DbException (or provider specific exception type - /// in .NET 1.1) thrown by callback code, be it direct - /// DbException or wrapped Hibernate ADOExceptions. - ///

The default exception translator is either a ErrorCodeExceptionTranslator - /// if a DbProvider is available, or a FalbackExceptionTranslator otherwise - ///

- ///
- /// The ADO exception translator. - public virtual IAdoExceptionTranslator AdoExceptionTranslator - { - set => adoExceptionTranslator = value; - get + if (resourceLoader == null) { - if (adoExceptionTranslator == null) + resourceLoader = new ConfigurableResourceLoader(); + } + + return resourceLoader; + } + set => resourceLoader = value; + } + + /// + /// Sets the assemblies to load that contain mapping files. + /// + /// The mapping assemblies. + public string[] MappingAssemblies + { + set => mappingAssemblies = value; + } + + /// + /// Sets the hibernate configuration files to load, i.e. hibernate.cfg.xml. + /// + public string[] ConfigFilenames + { + set => configFilenames = value; + } + + /// + /// Sets the locations of Spring IResources that contain mapping + /// files. + /// + /// The location of mapping resources. + public string[] MappingResources + { + set => mappingResources = value; + } + + /// + /// Return the Configuration object used to build the SessionFactory. + /// Allows access to configuration metadata stored there (rarely needed). + /// + /// The hibernate configuration. + public Configuration Configuration => configuration; + + /// + /// Set NHibernate configuration properties, like "hibernate.dialect". + /// + /// The hibernate properties. + /// + ///

Can be used to override values in a NHibernate XML config file, + /// or to specify all necessary properties locally. + ///

+ ///

Note: Do not specify a transaction provider here when using + /// Spring-driven transactions. It is also advisable to omit connection + /// provider settings and use a Spring-set IDbProvider instead. + ///

+ ///
+ public IDictionary HibernateProperties + { + get + { + if (hibernateProperties == null) + { + hibernateProperties = new Dictionary(); + } + + return hibernateProperties; + } + set => hibernateProperties = value; + } + + /// + /// Get or set the DataSource to be used by the SessionFactory. + /// + /// The db provider. + /// + /// If set, this will override corresponding settings in Hibernate properties. + /// Note: If this is set, the Hibernate settings should not define + /// a connection string + /// (hibernate.connection.connection_string) to avoid meaningless double configuration. + /// + /// + public IDbProvider DbProvider + { + set => dbProvider = value; + get => dbProvider; + } + + /// + /// Gets or sets a value indicating whether to expose a transaction aware session factory. + /// + /// + /// true if want to expose transaction aware session factory; otherwise, false. + /// + public bool ExposeTransactionAwareSessionFactory { set; get; } = false; + + /// + /// Set a NHibernate entity interceptor that allows to inspect and change + /// property values before writing to and reading from the database. + /// Will get applied to any new Session created by this factory. + ///

Such an interceptor can either be set at the SessionFactory level, i.e. on + /// LocalSessionFactoryObject, or at the Session level, i.e. on HibernateTemplate, + /// HibernateInterceptor, and HibernateTransactionManager. It's preferable to set + /// it on LocalSessionFactoryObject or HibernateTransactionManager to avoid repeated + /// configuration and guarantee consistent behavior in transactions.

+ ///
+ /// + /// + public IInterceptor EntityInterceptor + { + set => entityInterceptor = value; + } + + /// + /// Set a Hibernate NamingStrategy for the SessionFactory, determining the + /// physical column and table names given the info in the mapping document. + /// + public INamingStrategy NamingStrategy + { + set => namingStrategy = value; + } + + /// + /// Specify the Hibernate type definitions to register with the SessionFactory, + /// as Spring IObjectDefinition instances. This is an alternative to specifying + /// <typedef> elements in Hibernate mapping files. + ///

Unfortunately, Hibernate itself does not define a complete object that + /// represents a type definition, hence the need for Spring's TypeDefinitionBean.

+ /// @see TypeDefinitionBean + /// @see org.hibernate.cfg.Mappings#addTypeDef(String, String, java.util.Properties) + ///
+ public IObjectDefinition[] TypeDefinitions + { + set => typeDefinitions = value; + } + + /// + /// Specify the NHibernate FilterDefinitions to register with the SessionFactory. + /// This is an alternative to specifying <filter-def> elements in + /// Hibernate mapping files. + /// + /// + /// Typically, the passed-in FilterDefinition objects will have been defined + /// as Spring FilterDefinitionFactoryBeans, probably as inner beans within the + /// LocalSessionFactoryObject definition. + /// + /// + public FilterDefinition[] FilterDefinitions + { + set => filterDefinitions = value; + } + + /// + /// Specify the cache strategies for entities (persistent classes or named entities). + /// This configuration setting corresponds to the <class-cache> entry + /// in the "hibernate.cfg.xml" configuration format. + ///

For example: + ///

+    /// <property name="entityCacheStrategies">
+    ///   <props>
+    ///     <prop key="MyCompany.Customer">read-write</prop>
+    ///     <prop key="MyCompany.Product">read-only,myRegion</prop>
+    ///   </props>
+    /// </property>
+ ///

+ ///
+ public Properties EntityCacheStrategies + { + set => entityCacheStrategies = value; + } + + /// + /// Specify the cache strategies for persistent collections (with specific roles). + /// This configuration setting corresponds to the <collection-cache> entry + /// in the "hibernate.cfg.xml" configuration format. + ///

For example: + ///

+    /// <property name="CollectionCacheStrategies">
+    ///   <props>
+    ///     <prop key="MyCompany.Order.Items">read-write</prop>
+    ///     <prop key="MyCompany.Product.Categories">read-only,myRegion</prop>
+    ///   </props>
+    /// </property>
+ ///

+ ///
+ public Properties CollectionCacheStrategies + { + set => collectionCacheStrategies = value; + } + + /// + /// Specify the NHibernate event listeners to register, with listener types + /// as keys and listener objects as values. + ///

+ /// Instead of a single listener object, you can also pass in a list + /// or set of listeners objects as value. + ///

+ ///
+ /// listener objects as values + /// + /// See the NHibernate documentation for further details on listener types + /// and associated listener interfaces. + /// + public IDictionary EventListeners + { + set => eventListeners = value; + } + + /// + /// Set whether to execute a schema update after SessionFactory initialization. + ///

+ /// For details on how to make schema update scripts work, see the NHibernate + /// documentation, as this class leverages the same schema update script support + /// in as NHibernate's own SchemaUpdate tool. + ///

+ ///
+ public bool SchemaUpdate + { + set => schemaUpdate = value; + } + + /// + /// Set the ADO.NET exception translator for this instance. + /// Applied to System.Data.Common.DbException (or provider specific exception type + /// in .NET 1.1) thrown by callback code, be it direct + /// DbException or wrapped Hibernate ADOExceptions. + ///

The default exception translator is either a ErrorCodeExceptionTranslator + /// if a DbProvider is available, or a FalbackExceptionTranslator otherwise + ///

+ ///
+ /// The ADO exception translator. + public virtual IAdoExceptionTranslator AdoExceptionTranslator + { + set => adoExceptionTranslator = value; + get + { + if (adoExceptionTranslator == null) + { + adoExceptionTranslator = SessionFactoryUtils.NewAdoExceptionTranslator(sessionFactory); + } + + return adoExceptionTranslator; + } + } + + /// + /// Sets custom byte code provider implementation to be used. This corresponds to setting + /// the property before NHibernate session factory + /// configuration. + /// + public virtual IBytecodeProvider BytecodeProvider + { + get => bytecodeProvider; + set => bytecodeProvider = value; + } + + /// + /// Return the singleon session factory. + /// + /// The singleon session factory. + public object GetObject() + { + return sessionFactory; + } + + /// + /// Return the type or subclass. + /// + /// The type created by this factory + public Type ObjectType => (sessionFactory != null) ? sessionFactory.GetType() : typeof(ISessionFactory); + + /// + /// Returns true + /// + /// true + public bool IsSingleton => true; + + /// + /// Initialize the SessionFactory for the given or the + /// default location. + /// + public virtual void AfterPropertiesSet() + { + // Create Configuration instance. + Configuration config = NewConfiguration(); + + if (dbProvider != null) + { + config.SetProperty(Environment.ConnectionString, dbProvider.ConnectionString); + config.SetProperty(Environment.ConnectionProvider, typeof(DbProviderWrapper).AssemblyQualifiedName); + configTimeDbProvider = dbProvider; + } + + if (ExposeTransactionAwareSessionFactory) + { + // Set ICurrentSessionContext implementation, + // providing the Spring-managed ISession s current Session. + // Can be overridden by a custom value for the corresponding Hibernate property + config.SetProperty(Environment.CurrentSessionContextClass, typeof(SpringSessionContext).AssemblyQualifiedName); + } + + if (entityInterceptor != null) + { + // Set given entity interceptor at SessionFactory level. + config.SetInterceptor(entityInterceptor); + } + + if (namingStrategy != null) + { + // Pass given naming strategy to Hibernate Configuration. + config.SetNamingStrategy(namingStrategy); + } + + if (typeDefinitions != null) + { + // Register specified Hibernate type definitions. + IDictionary typedProperties = new Dictionary(); + foreach (KeyValuePair entry in hibernateProperties) + { + typedProperties.Add(entry.Key, entry.Value); + } + + Dialect dialect = Dialect.GetDialect(typedProperties); + Mappings mappings = config.CreateMappings(dialect); + for (int i = 0; i < typeDefinitions.Length; i++) + { + IObjectDefinition typeDef = typeDefinitions[i]; + Dictionary typedParamMap = new Dictionary(); + foreach (DictionaryEntry entry in typeDef.PropertyValues) { - adoExceptionTranslator = SessionFactoryUtils.NewAdoExceptionTranslator(sessionFactory); + typedParamMap.Add((string) entry.Key, (string) entry.Value); } - return adoExceptionTranslator; + + mappings.AddTypeDef(typeDef.ObjectTypeName, typeDef.ObjectTypeName, typedParamMap); } } - /// - /// Sets custom byte code provider implementation to be used. This corresponds to setting - /// the property before NHibernate session factory - /// configuration. - /// - public virtual IBytecodeProvider BytecodeProvider - { - get => bytecodeProvider; - set => bytecodeProvider = value; - } - - /// - /// Return the singleon session factory. - /// - /// The singleon session factory. - public object GetObject() - { - return sessionFactory; - } - - /// - /// Return the type or subclass. - /// - /// The type created by this factory - public Type ObjectType => (sessionFactory != null) ? sessionFactory.GetType() : typeof(ISessionFactory); - - /// - /// Returns true - /// - /// true - public bool IsSingleton => true; - - /// - /// Initialize the SessionFactory for the given or the - /// default location. - /// - public virtual void AfterPropertiesSet() - { - // Create Configuration instance. - Configuration config = NewConfiguration(); - - if (dbProvider != null) - { - config.SetProperty(Environment.ConnectionString, dbProvider.ConnectionString); - config.SetProperty(Environment.ConnectionProvider, typeof(DbProviderWrapper).AssemblyQualifiedName); - configTimeDbProvider = dbProvider; - } - - if (ExposeTransactionAwareSessionFactory) - { - // Set ICurrentSessionContext implementation, - // providing the Spring-managed ISession s current Session. - // Can be overridden by a custom value for the corresponding Hibernate property - config.SetProperty(Environment.CurrentSessionContextClass, typeof(SpringSessionContext).AssemblyQualifiedName); - } - - if (entityInterceptor != null) - { - // Set given entity interceptor at SessionFactory level. - config.SetInterceptor(entityInterceptor); - } - - if (namingStrategy != null) - { - // Pass given naming strategy to Hibernate Configuration. - config.SetNamingStrategy(namingStrategy); - } - - if (typeDefinitions != null) - { - // Register specified Hibernate type definitions. - IDictionary typedProperties = new Dictionary(); - foreach (KeyValuePair entry in hibernateProperties) - { - typedProperties.Add(entry.Key, entry.Value); - } - - Dialect dialect = Dialect.GetDialect(typedProperties); - Mappings mappings = config.CreateMappings(dialect); - for (int i = 0; i < typeDefinitions.Length; i++) - { - IObjectDefinition typeDef = typeDefinitions[i]; - Dictionary typedParamMap = new Dictionary(); - foreach (DictionaryEntry entry in typeDef.PropertyValues) - { - typedParamMap.Add((string) entry.Key, (string) entry.Value); - } - mappings.AddTypeDef(typeDef.ObjectTypeName, typeDef.ObjectTypeName, typedParamMap); - } - } - - if (filterDefinitions != null) - { - // Register specified NHibernate FilterDefinitions. - for (int i = 0; i < filterDefinitions.Length; i++) - { - config.AddFilterDefinition(filterDefinitions[i]); - } - } - - if (hibernateProperties != null) - { - if (config.GetProperty(Environment.ConnectionProvider) != null && - hibernateProperties.ContainsKey(Environment.ConnectionProvider)) - { - if (log.IsEnabled(LogLevel.Information)) - { - log.LogInformation("Overriding use of Spring's Hibernate Connection Provider with [" + - hibernateProperties[Environment.ConnectionProvider] + "]"); - } - - config.Properties.Remove(Environment.ConnectionProvider); - } - - Dictionary genericHibernateProperties = new Dictionary(); - foreach (KeyValuePair entry in hibernateProperties) - { - genericHibernateProperties.Add(entry.Key, entry.Value); - } - config.AddProperties(genericHibernateProperties); - } - if (mappingAssemblies != null) - { - foreach (string assemblyName in mappingAssemblies) - { - config.AddAssembly(assemblyName); - } - } - - if (mappingResources != null) - { - IResourceLoader loader = ResourceLoader; - if (loader == null) - { - loader = applicationContext; - } - foreach (string resourceName in mappingResources) - { - config.AddInputStream(loader.GetResource(resourceName).InputStream); - } - } - - if (configFilenames != null) - { - foreach (string configFilename in configFilenames) - { - config.Configure(configFilename); - } - } - - // Tell Hibernate to eagerly compile the mappings that we registered, - // for availability of the mapping information in further processing. - PostProcessMappings(config); - config.BuildMappings(); - - if (entityCacheStrategies != null) - { - // Register cache strategies for mapped entities. - foreach (string className in entityCacheStrategies.Keys) - { - string[] strategyAndRegion = StringUtils.CommaDelimitedListToStringArray(entityCacheStrategies.GetProperty(className)); - if (strategyAndRegion.Length > 1) - { - config.SetCacheConcurrencyStrategy(className, strategyAndRegion[0], strategyAndRegion[1]); - } - else if (strategyAndRegion.Length > 0) - { - config.SetCacheConcurrencyStrategy(className, strategyAndRegion[0]); - } - } - } - - if (collectionCacheStrategies != null) - { - // Register cache strategies for mapped collections. - foreach (string collRole in collectionCacheStrategies.Keys) - { - string[] strategyAndRegion = StringUtils.CommaDelimitedListToStringArray(collectionCacheStrategies.GetProperty(collRole)); - if (strategyAndRegion.Length > 1) - { - throw new Exception("Collection cache concurrency strategy region definition not supported yet"); - //config.SetCollectionCacheConcurrencyStrategy(collRole, strategyAndRegion[0], strategyAndRegion[1]); - } - else if (strategyAndRegion.Length > 0) - { - config.SetCollectionCacheConcurrencyStrategy(collRole, strategyAndRegion[0]); - } - } - } - - if (eventListeners != null) - { - // Register specified NHibernate event listeners. - foreach (DictionaryEntry entry in eventListeners) - { - ListenerType listenerType; - try - { - listenerType = (ListenerType) Enum.Parse(typeof (ListenerType), (string) entry.Key); - } - catch - { - throw new ArgumentException(string.Format("Unable to parse string '{0}' as valid {1}", entry.Key, typeof (ListenerType))); - } - - object listenerObject = entry.Value; - if (listenerObject is ICollection) - { - ICollection listeners = (ICollection) listenerObject; - EventListeners listenerRegistry = config.EventListeners; - - // create the array and check that types are valid at the same time - ArrayList items = new ArrayList(listeners); - object[] listenerArray = (object[])items.ToArray(listenerRegistry.GetListenerClassFor(listenerType)); - config.SetListeners(listenerType, listenerArray); - } - else - { - config.SetListener(listenerType, listenerObject); - } - } - } - - // Perform custom post-processing in subclasses. - PostProcessConfiguration(config); - - if (BytecodeProvider != null) - { - // set custom IBytecodeProvider - Environment.BytecodeProvider = BytecodeProvider; - } - else - { - // use Spring's as default - // Environment.BytecodeProvider = new Bytecode.BytecodeProvider(this.applicationContext); - } - - // Build SessionFactory instance. - log.LogInformation("Building new Hibernate SessionFactory"); - configuration = config; - sessionFactory = NewSessionFactory(config); - - AfterSessionFactoryCreation(); - - // set config time DB provider back to null - configTimeDbProvider = null; - } - - /// - /// Close the SessionFactory on application context shutdown. - /// - public void Dispose() - { - if (sessionFactory != null) - { - if (log.IsEnabled(LogLevel.Information)) - { - log.LogInformation("Closing Hibernate SessionFactory"); - } - - sessionFactory.Close(); - } - - } - - /// - /// Subclasses can override this method to perform custom initialization - /// of the Configuration instance used for ISessionFactory creation. - /// - /// - /// The properties of this LocalSessionFactoryObject will be applied to - /// the Configuration object that gets returned here. - ///

The default implementation creates a new Configuration instance. - /// A custom implementation could prepare the instance in a specific way, - /// or use a custom Configuration subclass. - ///

- ///
- /// The configuration instance. - protected virtual Configuration NewConfiguration() + if (filterDefinitions != null) { - return new Configuration(); - } - - /// - /// To be implemented by subclasses that want to to register further mappings - /// on the Configuration object after this FactoryObject registered its specified - /// mappings. - /// - /// - /// Invoked before the BuildMappings call, - /// so that it can still extend and modify the mapping information. - /// - /// the current Configuration object - protected virtual void PostProcessMappings(Configuration config) - { - } - - /// - /// To be implemented by subclasses that want to to perform custom - /// post-processing of the Configuration object after this FactoryObject - /// performed its default initialization. - /// - /// The current configuration object. - protected virtual void PostProcessConfiguration(Configuration config) - { - } - - /// - /// Executes schema update if requested. - /// - protected virtual void AfterSessionFactoryCreation() - { - if (schemaUpdate) + // Register specified NHibernate FilterDefinitions. + for (int i = 0; i < filterDefinitions.Length; i++) { - UpdateDatabaseSchema(); + config.AddFilterDefinition(filterDefinitions[i]); } } - /// - /// Execute schema drop script, determined by the Configuration object - /// used for creating the SessionFactory. A replacement for NHibernate's - /// SchemaExport class, to be invoked on application setup. - /// - /// - /// Fetch the LocalSessionFactoryBean itself rather than the exposed - /// SessionFactory to be able to invoke this method, e.g. via - /// LocalSessionFactoryObject lsfb = (LocalSessionFactoryObject) ctx.GetObject("mySessionFactory");. - ///

- /// Uses the SessionFactory that this bean generates for accessing a ADO.NET - /// connection to perform the script. - ///

- ///
- public void DropDatabaseSchema() + if (hibernateProperties != null) { - log.LogInformation("Dropping database schema for NHibernate SessionFactory"); - HibernateTemplate hibernateTemplate = new HibernateTemplate(sessionFactory); - hibernateTemplate.Execute( - new HibernateDelegate(session => - { - IDbConnection con = session.Connection; - Dialect dialect = Dialect.GetDialect(Configuration.Properties); - string[] sql = Configuration.GenerateDropSchemaScript(dialect); - ExecuteSchemaScript(con, sql); - return null; - })); - - } - - /// - /// Execute schema creation script, determined by the Configuration object - /// used for creating the SessionFactory. A replacement for NHibernate's - /// SchemaExport class, to be invoked on application setup. - /// - /// - /// Fetch the LocalSessionFactoryObject itself rather than the exposed - /// SessionFactory to be able to invoke this method, e.g. via - /// LocalSessionFactoryObject lsfo = (LocalSessionFactoryObject) ctx.GetObject("mySessionFactory");. - ///

- /// Uses the SessionFactory that this bean generates for accessing a ADO.NET - /// connection to perform the script. - ///

- ///
- public void CreateDatabaseSchema() - { - log.LogInformation("Creating database schema for Hibernate SessionFactory"); - HibernateTemplate hibernateTemplate = new HibernateTemplate(sessionFactory); - hibernateTemplate.Execute( - new HibernateDelegate(session => - { - IDbConnection con = session.Connection; - Dialect dialect = Dialect.GetDialect(Configuration.Properties); - string[] sql = Configuration.GenerateSchemaCreationScript(dialect); - ExecuteSchemaScript(con, sql); - return null; - - })); - } - - /// - /// Execute schema update script, determined by the Configuration object - /// used for creating the SessionFactory. A replacement for NHibernate's - /// SchemaUpdate class, for automatically executing schema update scripts - /// on application startup. Can also be invoked manually. - /// - /// - /// Fetch the LocalSessionFactoryObject itself rather than the exposed - /// SessionFactory to be able to invoke this method, e.g. via - /// LocalSessionFactoryObject lsfo = (LocalSessionFactoryObject) ctx.GetObject("mySessionFactory");. - ///

- /// Uses the SessionFactory that this bean generates for accessing a ADO.NET - /// connection to perform the script. - ///

- ///
- public virtual void UpdateDatabaseSchema() - { - log.LogInformation("Updating database schema for Hibernate SessionFactory"); - HibernateTemplate hibernateTemplate = new HibernateTemplate(sessionFactory); - hibernateTemplate.TemplateFlushMode = TemplateFlushMode.Never; - hibernateTemplate.Execute( - new HibernateDelegate(session => - { - IDbConnection con = session.Connection; - Dialect dialect = Dialect.GetDialect(Configuration.Properties); - DatabaseMetadata metadata = new DatabaseMetadata((DbConnection) con, dialect); - string[] sql = Configuration.GenerateSchemaUpdateScript(dialect, metadata); - ExecuteSchemaScript(con, sql); - return null; - })); - } - - - /// - /// Execute the given schema script on the given ADO.NET Connection. - /// - /// - /// Note that the default implementation will log unsuccessful statements - /// and continue to execute. Override the ExecuteSchemaStatement - /// method to treat failures differently. - /// - /// The connection to use. - /// The SQL statement to execute. - protected virtual void ExecuteSchemaScript(IDbConnection con, string[] sql) - { - if (sql != null && sql.Length > 0) + if (config.GetProperty(Environment.ConnectionProvider) != null && + hibernateProperties.ContainsKey(Environment.ConnectionProvider)) { - IDbCommand cmd = con.CreateCommand(); - try + if (log.IsEnabled(LogLevel.Information)) { - for (int i = 0; i < sql.Length; i++) - { - ExecuteSchemaStatement(cmd, sql[i]); - } - } - finally - { - AdoUtils.DisposeCommand(cmd); - } - } - } - - /// - /// Execute the given schema SQL on the given ADO.NET command. - /// - /// - /// Note that the default implementation will log unsuccessful statements - /// and continue to execute. Override this method to treat failures differently. - /// - /// - /// - protected virtual void ExecuteSchemaStatement(IDbCommand cmd, string sql) - { - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug("Executing schema statement: " + sql); - } - try - { - cmd.CommandText = sql; - cmd.ExecuteNonQuery(); - } - catch (ADOException ex) - { - if (log.IsEnabled(LogLevel.Warning)) - { - string message = "Unsuccessful schema statement: " + sql; - log.LogWarning((Exception) ex, message); + log.LogInformation("Overriding use of Spring's Hibernate Connection Provider with [" + + hibernateProperties[Environment.ConnectionProvider] + "]"); } - } - } - /// - /// Subclasses can override this method to perform custom initialization - /// of the SessionFactory instance, creating it via the given Configuration - /// object that got prepared by this LocalSessionFactoryObject. - /// - /// - ///

The default implementation invokes Configuration's BuildSessionFactory. - /// A custom implementation could prepare the instance in a specific way, - /// or use a custom ISessionFactory subclass. - ///

- ///
- /// The ISessionFactory instance. - protected virtual ISessionFactory NewSessionFactory(Configuration config) - { - ISessionFactory sf = config.BuildSessionFactory(); - ISessionFactoryImplementor sfImplementor = sf as ISessionFactoryImplementor; - - if (sfImplementor != null) - { - DbProviderWrapper dbProviderWrapper = sfImplementor.ConnectionProvider as DbProviderWrapper; - - if (dbProviderWrapper != null) - { - dbProviderWrapper.DbProvider = dbProvider; - } + config.Properties.Remove(Environment.ConnectionProvider); } - return sf; + + Dictionary genericHibernateProperties = new Dictionary(); + foreach (KeyValuePair entry in hibernateProperties) + { + genericHibernateProperties.Add(entry.Key, entry.Value); + } + + config.AddProperties(genericHibernateProperties); } - internal class DbProviderWrapper : ConnectionProvider + if (mappingAssemblies != null) { - public IDbProvider DbProvider { get; set; } - - public override async Task GetConnectionAsync(CancellationToken cancellationToken) + foreach (string assemblyName in mappingAssemblies) { - IDbProvider provider = DbProvider; - if (provider == null && configTimeDbProvider != null) - { - // NH 2.1 has a need to access db provider before - // it has been set "the natural way" (it gets the DB's reserved words) - // allow it via configuration time db provider reference - provider = configTimeDbProvider; - } - - if (provider == null) - { - throw new Exception("There was no DB provider available, unable to create connection"); - } - var dbCon = (DbConnection) provider.CreateConnection(); - await dbCon.OpenAsync(cancellationToken).ConfigureAwait(false); - return dbCon; - } - - public override void CloseConnection(DbConnection conn) - { - base.CloseConnection(conn); - conn.Dispose(); - } - - public override DbConnection GetConnection() - { - IDbProvider provider = DbProvider; - if (provider == null && configTimeDbProvider != null) - { - // NH 2.1 has a need to access db provider before - // it has been set "the natural way" (it gets the DB's reserved words) - // allow it via configuration time db provider reference - provider = configTimeDbProvider; - } - - if (provider == null) - { - throw new Exception("There was no DB provider available, unable to create connection"); - } - var dbCon = provider.CreateConnection(); - dbCon.Open(); - return (DbConnection) dbCon; + config.AddAssembly(assemblyName); } } - - /// - /// Implementation of the PersistenceExceptionTranslator interface, - /// as autodetected by Spring's PersistenceExceptionTranslationPostProcessor. - /// Converts the exception if it is a HibernateException; - /// else returns null to indicate an unknown exception. - /// translate the given exception thrown by a persistence framework to a - /// corresponding exception from Spring's generic DataAccessException hierarchy, - /// if possible. - /// - /// The exception thrown. - /// - /// the corresponding DataAccessException (or null if the - /// exception could not be translated. - /// - /// - public DataAccessException TranslateExceptionIfPossible(Exception ex) - { - if (ex is HibernateException) - { - return ConvertHibernateException((HibernateException) ex); - } - return null; - } - /// - /// Convert the given HibernateException to an appropriate exception from the - /// Spring's DAO Exception hierarchy. - /// Will automatically apply a specified IAdoExceptionTranslator to a - /// Hibernate ADOException, else rely on Hibernate's default translation. - /// - /// The Hibernate exception that occured. - /// A corresponding DataAccessException - protected virtual DataAccessException ConvertHibernateException(HibernateException ex) - { - if (ex is ADOException) - { - return ConvertAdoAccessException((ADOException)ex); - } - return SessionFactoryUtils.ConvertHibernateAccessException(ex); - } - - /// - /// Converts the ADO.NET access exception to an appropriate exception from the - /// org.springframework.dao hierarchy. Can be overridden in subclasses. - /// - /// ADOException that occured, wrapping underlying ADO.NET exception. - /// - /// the corresponding DataAccessException instance - /// - protected virtual DataAccessException ConvertAdoAccessException(ADOException ex) + if (mappingResources != null) { - return SessionFactoryUtils.ConvertAdoAccessException(AdoExceptionTranslator, ex); + IResourceLoader loader = ResourceLoader; + if (loader == null) + { + loader = applicationContext; + } + + foreach (string resourceName in mappingResources) + { + config.AddInputStream(loader.GetResource(resourceName).InputStream); + } } - } + + if (configFilenames != null) + { + foreach (string configFilename in configFilenames) + { + config.Configure(configFilename); + } + } + + // Tell Hibernate to eagerly compile the mappings that we registered, + // for availability of the mapping information in further processing. + PostProcessMappings(config); + config.BuildMappings(); + + if (entityCacheStrategies != null) + { + // Register cache strategies for mapped entities. + foreach (string className in entityCacheStrategies.Keys) + { + string[] strategyAndRegion = StringUtils.CommaDelimitedListToStringArray(entityCacheStrategies.GetProperty(className)); + if (strategyAndRegion.Length > 1) + { + config.SetCacheConcurrencyStrategy(className, strategyAndRegion[0], strategyAndRegion[1]); + } + else if (strategyAndRegion.Length > 0) + { + config.SetCacheConcurrencyStrategy(className, strategyAndRegion[0]); + } + } + } + + if (collectionCacheStrategies != null) + { + // Register cache strategies for mapped collections. + foreach (string collRole in collectionCacheStrategies.Keys) + { + string[] strategyAndRegion = StringUtils.CommaDelimitedListToStringArray(collectionCacheStrategies.GetProperty(collRole)); + if (strategyAndRegion.Length > 1) + { + throw new Exception("Collection cache concurrency strategy region definition not supported yet"); + //config.SetCollectionCacheConcurrencyStrategy(collRole, strategyAndRegion[0], strategyAndRegion[1]); + } + else if (strategyAndRegion.Length > 0) + { + config.SetCollectionCacheConcurrencyStrategy(collRole, strategyAndRegion[0]); + } + } + } + + if (eventListeners != null) + { + // Register specified NHibernate event listeners. + foreach (DictionaryEntry entry in eventListeners) + { + ListenerType listenerType; + try + { + listenerType = (ListenerType) Enum.Parse(typeof(ListenerType), (string) entry.Key); + } + catch + { + throw new ArgumentException(string.Format("Unable to parse string '{0}' as valid {1}", entry.Key, typeof(ListenerType))); + } + + object listenerObject = entry.Value; + if (listenerObject is ICollection) + { + ICollection listeners = (ICollection) listenerObject; + EventListeners listenerRegistry = config.EventListeners; + + // create the array and check that types are valid at the same time + ArrayList items = new ArrayList(listeners); + object[] listenerArray = (object[]) items.ToArray(listenerRegistry.GetListenerClassFor(listenerType)); + config.SetListeners(listenerType, listenerArray); + } + else + { + config.SetListener(listenerType, listenerObject); + } + } + } + + // Perform custom post-processing in subclasses. + PostProcessConfiguration(config); + + if (BytecodeProvider != null) + { + // set custom IBytecodeProvider + Environment.BytecodeProvider = BytecodeProvider; + } + else + { + // use Spring's as default + // Environment.BytecodeProvider = new Bytecode.BytecodeProvider(this.applicationContext); + } + + // Build SessionFactory instance. + log.LogInformation("Building new Hibernate SessionFactory"); + configuration = config; + sessionFactory = NewSessionFactory(config); + + AfterSessionFactoryCreation(); + + // set config time DB provider back to null + configTimeDbProvider = null; + } + + /// + /// Close the SessionFactory on application context shutdown. + /// + public void Dispose() + { + if (sessionFactory != null) + { + if (log.IsEnabled(LogLevel.Information)) + { + log.LogInformation("Closing Hibernate SessionFactory"); + } + + sessionFactory.Close(); + } + } + + /// + /// Subclasses can override this method to perform custom initialization + /// of the Configuration instance used for ISessionFactory creation. + /// + /// + /// The properties of this LocalSessionFactoryObject will be applied to + /// the Configuration object that gets returned here. + ///

The default implementation creates a new Configuration instance. + /// A custom implementation could prepare the instance in a specific way, + /// or use a custom Configuration subclass. + ///

+ ///
+ /// The configuration instance. + protected virtual Configuration NewConfiguration() + { + return new Configuration(); + } + + /// + /// To be implemented by subclasses that want to to register further mappings + /// on the Configuration object after this FactoryObject registered its specified + /// mappings. + /// + /// + /// Invoked before the BuildMappings call, + /// so that it can still extend and modify the mapping information. + /// + /// the current Configuration object + protected virtual void PostProcessMappings(Configuration config) + { + } + + /// + /// To be implemented by subclasses that want to to perform custom + /// post-processing of the Configuration object after this FactoryObject + /// performed its default initialization. + /// + /// The current configuration object. + protected virtual void PostProcessConfiguration(Configuration config) + { + } + + /// + /// Executes schema update if requested. + /// + protected virtual void AfterSessionFactoryCreation() + { + if (schemaUpdate) + { + UpdateDatabaseSchema(); + } + } + + /// + /// Execute schema drop script, determined by the Configuration object + /// used for creating the SessionFactory. A replacement for NHibernate's + /// SchemaExport class, to be invoked on application setup. + /// + /// + /// Fetch the LocalSessionFactoryBean itself rather than the exposed + /// SessionFactory to be able to invoke this method, e.g. via + /// LocalSessionFactoryObject lsfb = (LocalSessionFactoryObject) ctx.GetObject("mySessionFactory");. + ///

+ /// Uses the SessionFactory that this bean generates for accessing a ADO.NET + /// connection to perform the script. + ///

+ ///
+ public void DropDatabaseSchema() + { + log.LogInformation("Dropping database schema for NHibernate SessionFactory"); + HibernateTemplate hibernateTemplate = new HibernateTemplate(sessionFactory); + hibernateTemplate.Execute( + new HibernateDelegate(session => + { + IDbConnection con = session.Connection; + Dialect dialect = Dialect.GetDialect(Configuration.Properties); + string[] sql = Configuration.GenerateDropSchemaScript(dialect); + ExecuteSchemaScript(con, sql); + return null; + })); + } + + /// + /// Execute schema creation script, determined by the Configuration object + /// used for creating the SessionFactory. A replacement for NHibernate's + /// SchemaExport class, to be invoked on application setup. + /// + /// + /// Fetch the LocalSessionFactoryObject itself rather than the exposed + /// SessionFactory to be able to invoke this method, e.g. via + /// LocalSessionFactoryObject lsfo = (LocalSessionFactoryObject) ctx.GetObject("mySessionFactory");. + ///

+ /// Uses the SessionFactory that this bean generates for accessing a ADO.NET + /// connection to perform the script. + ///

+ ///
+ public void CreateDatabaseSchema() + { + log.LogInformation("Creating database schema for Hibernate SessionFactory"); + HibernateTemplate hibernateTemplate = new HibernateTemplate(sessionFactory); + hibernateTemplate.Execute( + new HibernateDelegate(session => + { + IDbConnection con = session.Connection; + Dialect dialect = Dialect.GetDialect(Configuration.Properties); + string[] sql = Configuration.GenerateSchemaCreationScript(dialect); + ExecuteSchemaScript(con, sql); + return null; + })); + } + + /// + /// Execute schema update script, determined by the Configuration object + /// used for creating the SessionFactory. A replacement for NHibernate's + /// SchemaUpdate class, for automatically executing schema update scripts + /// on application startup. Can also be invoked manually. + /// + /// + /// Fetch the LocalSessionFactoryObject itself rather than the exposed + /// SessionFactory to be able to invoke this method, e.g. via + /// LocalSessionFactoryObject lsfo = (LocalSessionFactoryObject) ctx.GetObject("mySessionFactory");. + ///

+ /// Uses the SessionFactory that this bean generates for accessing a ADO.NET + /// connection to perform the script. + ///

+ ///
+ public virtual void UpdateDatabaseSchema() + { + log.LogInformation("Updating database schema for Hibernate SessionFactory"); + HibernateTemplate hibernateTemplate = new HibernateTemplate(sessionFactory); + hibernateTemplate.TemplateFlushMode = TemplateFlushMode.Never; + hibernateTemplate.Execute( + new HibernateDelegate(session => + { + IDbConnection con = session.Connection; + Dialect dialect = Dialect.GetDialect(Configuration.Properties); + DatabaseMetadata metadata = new DatabaseMetadata((DbConnection) con, dialect); + string[] sql = Configuration.GenerateSchemaUpdateScript(dialect, metadata); + ExecuteSchemaScript(con, sql); + return null; + })); + } + + /// + /// Execute the given schema script on the given ADO.NET Connection. + /// + /// + /// Note that the default implementation will log unsuccessful statements + /// and continue to execute. Override the ExecuteSchemaStatement + /// method to treat failures differently. + /// + /// The connection to use. + /// The SQL statement to execute. + protected virtual void ExecuteSchemaScript(IDbConnection con, string[] sql) + { + if (sql != null && sql.Length > 0) + { + IDbCommand cmd = con.CreateCommand(); + try + { + for (int i = 0; i < sql.Length; i++) + { + ExecuteSchemaStatement(cmd, sql[i]); + } + } + finally + { + AdoUtils.DisposeCommand(cmd); + } + } + } + + /// + /// Execute the given schema SQL on the given ADO.NET command. + /// + /// + /// Note that the default implementation will log unsuccessful statements + /// and continue to execute. Override this method to treat failures differently. + /// + /// + /// + protected virtual void ExecuteSchemaStatement(IDbCommand cmd, string sql) + { + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug("Executing schema statement: " + sql); + } + + try + { + cmd.CommandText = sql; + cmd.ExecuteNonQuery(); + } + catch (ADOException ex) + { + if (log.IsEnabled(LogLevel.Warning)) + { + string message = "Unsuccessful schema statement: " + sql; + log.LogWarning((Exception) ex, message); + } + } + } + + /// + /// Subclasses can override this method to perform custom initialization + /// of the SessionFactory instance, creating it via the given Configuration + /// object that got prepared by this LocalSessionFactoryObject. + /// + /// + ///

The default implementation invokes Configuration's BuildSessionFactory. + /// A custom implementation could prepare the instance in a specific way, + /// or use a custom ISessionFactory subclass. + ///

+ ///
+ /// The ISessionFactory instance. + protected virtual ISessionFactory NewSessionFactory(Configuration config) + { + ISessionFactory sf = config.BuildSessionFactory(); + ISessionFactoryImplementor sfImplementor = sf as ISessionFactoryImplementor; + + if (sfImplementor != null) + { + DbProviderWrapper dbProviderWrapper = sfImplementor.ConnectionProvider as DbProviderWrapper; + + if (dbProviderWrapper != null) + { + dbProviderWrapper.DbProvider = dbProvider; + } + } + + return sf; + } + + internal class DbProviderWrapper : ConnectionProvider + { + public IDbProvider DbProvider { get; set; } + + public override async Task GetConnectionAsync(CancellationToken cancellationToken) + { + IDbProvider provider = DbProvider; + if (provider == null && configTimeDbProvider != null) + { + // NH 2.1 has a need to access db provider before + // it has been set "the natural way" (it gets the DB's reserved words) + // allow it via configuration time db provider reference + provider = configTimeDbProvider; + } + + if (provider == null) + { + throw new Exception("There was no DB provider available, unable to create connection"); + } + + var dbCon = (DbConnection) provider.CreateConnection(); + await dbCon.OpenAsync(cancellationToken).ConfigureAwait(false); + return dbCon; + } + + public override void CloseConnection(DbConnection conn) + { + base.CloseConnection(conn); + conn.Dispose(); + } + + public override DbConnection GetConnection() + { + IDbProvider provider = DbProvider; + if (provider == null && configTimeDbProvider != null) + { + // NH 2.1 has a need to access db provider before + // it has been set "the natural way" (it gets the DB's reserved words) + // allow it via configuration time db provider reference + provider = configTimeDbProvider; + } + + if (provider == null) + { + throw new Exception("There was no DB provider available, unable to create connection"); + } + + var dbCon = provider.CreateConnection(); + dbCon.Open(); + return (DbConnection) dbCon; + } + } + + /// + /// Implementation of the PersistenceExceptionTranslator interface, + /// as autodetected by Spring's PersistenceExceptionTranslationPostProcessor. + /// Converts the exception if it is a HibernateException; + /// else returns null to indicate an unknown exception. + /// translate the given exception thrown by a persistence framework to a + /// corresponding exception from Spring's generic DataAccessException hierarchy, + /// if possible. + /// + /// The exception thrown. + /// + /// the corresponding DataAccessException (or null if the + /// exception could not be translated. + /// + /// + public DataAccessException TranslateExceptionIfPossible(Exception ex) + { + if (ex is HibernateException) + { + return ConvertHibernateException((HibernateException) ex); + } + + return null; + } + + /// + /// Convert the given HibernateException to an appropriate exception from the + /// Spring's DAO Exception hierarchy. + /// Will automatically apply a specified IAdoExceptionTranslator to a + /// Hibernate ADOException, else rely on Hibernate's default translation. + /// + /// The Hibernate exception that occured. + /// A corresponding DataAccessException + protected virtual DataAccessException ConvertHibernateException(HibernateException ex) + { + if (ex is ADOException) + { + return ConvertAdoAccessException((ADOException) ex); + } + + return SessionFactoryUtils.ConvertHibernateAccessException(ex); + } + + /// + /// Converts the ADO.NET access exception to an appropriate exception from the + /// org.springframework.dao hierarchy. Can be overridden in subclasses. + /// + /// ADOException that occured, wrapping underlying ADO.NET exception. + /// + /// the corresponding DataAccessException instance + /// + protected virtual DataAccessException ConvertAdoAccessException(ADOException ex) + { + return SessionFactoryUtils.ConvertAdoAccessException(AdoExceptionTranslator, ex); + } } diff --git a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/SessionFactoryUtils.cs b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/SessionFactoryUtils.cs index 7bacdc56..e56300c0 100644 --- a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/SessionFactoryUtils.cs +++ b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/SessionFactoryUtils.cs @@ -1,12 +1,12 @@ /* * Copyright © 2002-2011 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. @@ -30,693 +30,700 @@ using Spring.Threading; using Spring.Transaction.Support; using Spring.Util; -namespace Spring.Data.NHibernate +namespace Spring.Data.NHibernate; + +/// +/// Helper class featuring methods for Hibernate Session handling, +/// allowing for reuse of Hibernate Session instances within transactions. +/// Also provides support for exception translation. +/// +/// Mark Pollack (.NET) +public abstract class SessionFactoryUtils { - /// - /// Helper class featuring methods for Hibernate Session handling, - /// allowing for reuse of Hibernate Session instances within transactions. - /// Also provides support for exception translation. - /// - /// Mark Pollack (.NET) - public abstract class SessionFactoryUtils - { - /// - /// The instance for this class. - /// - private static readonly ILogger log = LogManager.GetLogger(); + /// + /// The instance for this class. + /// + private static readonly ILogger log = LogManager.GetLogger(); - /// - /// The ordering value for synchronizaiton this session resources. - /// Set to be lower than ADO.NET synchronization. - /// - public static readonly int SESSION_SYNCHRONIZATION_ORDER = - AdoUtils.CONNECTION_SYNCHRONIZATION_ORDER - 100; + /// + /// The ordering value for synchronizaiton this session resources. + /// Set to be lower than ADO.NET synchronization. + /// + public static readonly int SESSION_SYNCHRONIZATION_ORDER = + AdoUtils.CONNECTION_SYNCHRONIZATION_ORDER - 100; - private static readonly string DeferredCloseHolderDataSlotName = "Spring.Data.NHibernate:deferredCloseHolder"; + private static readonly string DeferredCloseHolderDataSlotName = "Spring.Data.NHibernate:deferredCloseHolder"; - /// - /// Initializes a new instance of the class. - /// - public SessionFactoryUtils() - { + /// + /// Initializes a new instance of the class. + /// + public SessionFactoryUtils() + { + } - } - - /// - /// Get a new Hibernate Session from the given SessionFactory. - /// Will return a new Session even if there already is a pre-bound - /// Session for the given SessionFactory. - /// - /// - /// Within a transaction, this method will create a new Session - /// that shares the transaction's ADO.NET Connection. More specifically, - /// it will use the same ADO.NET Connection as the pre-bound Hibernate Session. - /// - /// The session factory to create the session with. - /// The Hibernate entity interceptor, or null if none. - /// The new session. - /// If could not open Hibernate session - public static ISession GetNewSession(ISessionFactory sessionFactory, IInterceptor interceptor) - { - try - { - SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager.GetResource(sessionFactory); - if (sessionHolder != null && !sessionHolder.IsEmpty) - { - if (interceptor != null) - { - return sessionFactory.OpenSession(sessionHolder.AnySession.Connection, interceptor); - } - else - { - return sessionFactory.OpenSession(sessionHolder.AnySession.Connection); - } - } - else - { - if (interceptor != null) - { - return sessionFactory.OpenSession(interceptor); - } - else - { - return sessionFactory.OpenSession(); - } - } - } - catch (HibernateException ex) - { - throw new DataAccessResourceFailureException("Could not open Hibernate Session", ex); - } - } - - /// - /// Get a Hibernate Session for the given SessionFactory. Is aware of and will - /// return any existing corresponding Session bound to the current thread, for - /// example when using HibernateTransactionManager. Will always create a new - /// Session otherwise. - /// - /// - /// Supports setting a Session-level Hibernate entity interceptor that allows - /// to inspect and change property values before writing to and reading from the - /// database. Such an interceptor can also be set at the SessionFactory level - /// (i.e. on LocalSessionFactoryObject), on HibernateTransactionManager, or on - /// HibernateInterceptor/HibernateTemplate. - /// - /// The session factory to create the - /// session with. - /// Hibernate entity interceptor, or null if none. - /// AdoExceptionTranslator to use for flushing the - /// Session on transaction synchronization (can be null; only used when actually - /// registering a transaction synchronization). - /// The Hibernate Session - /// - /// If the session couldn't be created. - /// - /// - /// If no thread-bound Session found and allowCreate is false. - /// - public static ISession GetSession( - ISessionFactory sessionFactory, IInterceptor entityInterceptor, - IAdoExceptionTranslator adoExceptionTranslator) + /// + /// Get a new Hibernate Session from the given SessionFactory. + /// Will return a new Session even if there already is a pre-bound + /// Session for the given SessionFactory. + /// + /// + /// Within a transaction, this method will create a new Session + /// that shares the transaction's ADO.NET Connection. More specifically, + /// it will use the same ADO.NET Connection as the pre-bound Hibernate Session. + /// + /// The session factory to create the session with. + /// The Hibernate entity interceptor, or null if none. + /// The new session. + /// If could not open Hibernate session + public static ISession GetNewSession(ISessionFactory sessionFactory, IInterceptor interceptor) + { + try { - try - { - return GetSession(sessionFactory, entityInterceptor, adoExceptionTranslator, true); - } - catch (HibernateException ex) - { - throw new DataAccessResourceFailureException("Could not open Hibernate Session", ex); - } - } - - /// - /// Get a Hibernate Session for the given SessionFactory. Is aware of and will - /// return any existing corresponding Session bound to the current thread, for - /// example when using . Will create a new Session - /// otherwise, if allowCreate is true. - /// - /// The session factory to create the session with. - /// if set to true create a non-transactional Session when no - /// transactional Session can be found for the current thread. - /// The hibernate session - /// - /// If the session couldn't be created. - /// - /// - /// If no thread-bound Session found and allowCreate is false. - /// - public static ISession GetSession(ISessionFactory sessionFactory, bool allowCreate) - { - try - { - return GetSession(sessionFactory, null, null, allowCreate); - } - catch (HibernateException ex) - { - throw new DataAccessResourceFailureException("Could not open Hibernate Session", ex); - } - } - - /// - /// Get a Hibernate Session for the given SessionFactory. - /// - /// Is aware of and will return any existing corresponding - /// Session bound to the current thread, for example whenusing - /// . Will create a new - /// Session otherwise, if "allowCreate" is true. - ///

Throws the orginal HibernateException, in contrast to - /// . - ///

- /// The session factory. - /// if set to true [allow create]. - /// The Hibernate Session - /// - /// if the Session couldn't be created - /// - /// - /// If no thread-bound Session found and allowCreate is false. - /// - public static ISession DoGetSession(ISessionFactory sessionFactory, bool allowCreate) - { - return DoGetSession(sessionFactory, null, null, allowCreate); - } - - private static ISession GetSession( - ISessionFactory sessionFactory, IInterceptor entityInterceptor, - IAdoExceptionTranslator adoExceptionTranslator, bool allowCreate) - { - try - { - return DoGetSession(sessionFactory, entityInterceptor, adoExceptionTranslator, allowCreate); - } - catch (HibernateException ex) - { - throw new DataAccessResourceFailureException("Could not open Hibernate Session", ex); - } - } - - - private static ISession DoGetSession( - ISessionFactory sessionFactory, IInterceptor entityInterceptor, - IAdoExceptionTranslator adoExceptionTranslator, bool allowCreate) - { - AssertUtils.ArgumentNotNull(sessionFactory, "sessionFactory", "SessionFactory can not be null"); - SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager.GetResource(sessionFactory); - if (sessionHolder != null && !sessionHolder.IsEmpty) + if (sessionHolder != null && !sessionHolder.IsEmpty) { - // pre-bound Hibernate Session - ISession session = null; - if (TransactionSynchronizationManager.SynchronizationActive && - sessionHolder.DoesNotHoldNonDefaultSession) + if (interceptor != null) { - // Spring transaction management is active -> - // register pre-bound Session with it for transactional flushing. - session = sessionHolder.ValidatedSession; - if (session != null && !sessionHolder.SynchronizedWithTransaction) + return sessionFactory.OpenSession(sessionHolder.AnySession.Connection, interceptor); + } + else + { + return sessionFactory.OpenSession(sessionHolder.AnySession.Connection); + } + } + else + { + if (interceptor != null) + { + return sessionFactory.OpenSession(interceptor); + } + else + { + return sessionFactory.OpenSession(); + } + } + } + catch (HibernateException ex) + { + throw new DataAccessResourceFailureException("Could not open Hibernate Session", ex); + } + } + + /// + /// Get a Hibernate Session for the given SessionFactory. Is aware of and will + /// return any existing corresponding Session bound to the current thread, for + /// example when using HibernateTransactionManager. Will always create a new + /// Session otherwise. + /// + /// + /// Supports setting a Session-level Hibernate entity interceptor that allows + /// to inspect and change property values before writing to and reading from the + /// database. Such an interceptor can also be set at the SessionFactory level + /// (i.e. on LocalSessionFactoryObject), on HibernateTransactionManager, or on + /// HibernateInterceptor/HibernateTemplate. + /// + /// The session factory to create the + /// session with. + /// Hibernate entity interceptor, or null if none. + /// AdoExceptionTranslator to use for flushing the + /// Session on transaction synchronization (can be null; only used when actually + /// registering a transaction synchronization). + /// The Hibernate Session + /// + /// If the session couldn't be created. + /// + /// + /// If no thread-bound Session found and allowCreate is false. + /// + public static ISession GetSession( + ISessionFactory sessionFactory, IInterceptor entityInterceptor, + IAdoExceptionTranslator adoExceptionTranslator) + { + try + { + return GetSession(sessionFactory, entityInterceptor, adoExceptionTranslator, true); + } + catch (HibernateException ex) + { + throw new DataAccessResourceFailureException("Could not open Hibernate Session", ex); + } + } + + /// + /// Get a Hibernate Session for the given SessionFactory. Is aware of and will + /// return any existing corresponding Session bound to the current thread, for + /// example when using . Will create a new Session + /// otherwise, if allowCreate is true. + /// + /// The session factory to create the session with. + /// if set to true create a non-transactional Session when no + /// transactional Session can be found for the current thread. + /// The hibernate session + /// + /// If the session couldn't be created. + /// + /// + /// If no thread-bound Session found and allowCreate is false. + /// + public static ISession GetSession(ISessionFactory sessionFactory, bool allowCreate) + { + try + { + return GetSession(sessionFactory, null, null, allowCreate); + } + catch (HibernateException ex) + { + throw new DataAccessResourceFailureException("Could not open Hibernate Session", ex); + } + } + + /// + /// Get a Hibernate Session for the given SessionFactory. + /// + /// Is aware of and will return any existing corresponding + /// Session bound to the current thread, for example whenusing + /// . Will create a new + /// Session otherwise, if "allowCreate" is true. + ///

Throws the orginal HibernateException, in contrast to + /// . + ///

+ /// The session factory. + /// if set to true [allow create]. + /// The Hibernate Session + /// + /// if the Session couldn't be created + /// + /// + /// If no thread-bound Session found and allowCreate is false. + /// + public static ISession DoGetSession(ISessionFactory sessionFactory, bool allowCreate) + { + return DoGetSession(sessionFactory, null, null, allowCreate); + } + + private static ISession GetSession( + ISessionFactory sessionFactory, IInterceptor entityInterceptor, + IAdoExceptionTranslator adoExceptionTranslator, bool allowCreate) + { + try + { + return DoGetSession(sessionFactory, entityInterceptor, adoExceptionTranslator, allowCreate); + } + catch (HibernateException ex) + { + throw new DataAccessResourceFailureException("Could not open Hibernate Session", ex); + } + } + + private static ISession DoGetSession( + ISessionFactory sessionFactory, IInterceptor entityInterceptor, + IAdoExceptionTranslator adoExceptionTranslator, bool allowCreate) + { + AssertUtils.ArgumentNotNull(sessionFactory, "sessionFactory", "SessionFactory can not be null"); + + SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager.GetResource(sessionFactory); + if (sessionHolder != null && !sessionHolder.IsEmpty) + { + // pre-bound Hibernate Session + ISession session = null; + if (TransactionSynchronizationManager.SynchronizationActive && + sessionHolder.DoesNotHoldNonDefaultSession) + { + // Spring transaction management is active -> + // register pre-bound Session with it for transactional flushing. + session = sessionHolder.ValidatedSession; + if (session != null && !sessionHolder.SynchronizedWithTransaction) + { + log.LogDebug("Registering Spring transaction synchronization for existing Hibernate Session"); + TransactionSynchronizationManager.RegisterSynchronization( + new SpringSessionSynchronization(sessionHolder, sessionFactory, adoExceptionTranslator, false)); + sessionHolder.SynchronizedWithTransaction = true; + // Switch to FlushMode.AUTO if we're not within a read-only transaction. + FlushMode flushMode = session.FlushMode; + if (FlushMode.Never == flushMode && + !TransactionSynchronizationManager.CurrentTransactionReadOnly) { - log.LogDebug("Registering Spring transaction synchronization for existing Hibernate Session"); - TransactionSynchronizationManager.RegisterSynchronization( - new SpringSessionSynchronization(sessionHolder, sessionFactory, adoExceptionTranslator, false)); - sessionHolder.SynchronizedWithTransaction = true; - // Switch to FlushMode.AUTO if we're not within a read-only transaction. - FlushMode flushMode = session.FlushMode; - if (FlushMode.Never == flushMode && - !TransactionSynchronizationManager.CurrentTransactionReadOnly) + session.FlushMode = FlushMode.Auto; + sessionHolder.PreviousFlushMode = flushMode; + } + } + } + else + { + // No Spring transaction management active -> simply return default thread-bound Session, if any + // (possibly from OpenSessionInViewModule) + session = sessionHolder.ValidatedSession; + } + + if (session != null) + { + return session; + } + } + + ISession sess = OpenSession(sessionFactory, entityInterceptor); + // Set Session to FlushMode.Never if we're within a read-only transaction. + // Use same Session for further Hibernate actions within the transaction. + // Thread object will get removed by synchronization at transaction completion. + if (TransactionSynchronizationManager.SynchronizationActive) + { + log.LogDebug("Registering Spring transaction synchronization for new Hibernate Session"); + SessionHolder holderToUse = sessionHolder; + if (holderToUse == null) + { + holderToUse = new SessionHolder(sess); + } + else + { + holderToUse.AddSession(sess); + } + + if (TransactionSynchronizationManager.CurrentTransactionReadOnly) + { + sess.FlushMode = FlushMode.Never; + } + + TransactionSynchronizationManager.RegisterSynchronization( + new SpringSessionSynchronization(holderToUse, sessionFactory, adoExceptionTranslator, true)); + holderToUse.SynchronizedWithTransaction = true; + if (holderToUse != sessionHolder) + { + TransactionSynchronizationManager.BindResource(sessionFactory, holderToUse); + } + } + + // Check whether we are allowed to return the Session. + if (!allowCreate && !IsSessionTransactional(sess, sessionFactory)) + { + CloseSession(sess); + throw new InvalidOperationException("No Hibernate Session bound to thread, " + + "and configuration does not allow creation of non-transactional one here"); + } + + return sess; + } + + /// + /// Open a new Session from the factory. + /// + /// The session factory to create the session with. + /// Hibernate entity interceptor, or null if none. + /// the newly opened session + internal static ISession OpenSession(ISessionFactory sessionFactory, IInterceptor entityInterceptor) + { + log.LogDebug("Opening Hibernate Session"); + ISession session = ( + (entityInterceptor != null) + ? sessionFactory.OpenSession(entityInterceptor) + : sessionFactory.OpenSession() + ); + + return session; + } + + /// + /// Perform the actual closing of the Hibernate Session + /// catching and logging any cleanup exceptions thrown. + /// + /// The hibernate session to close + public static void CloseSession(ISession session) + { + if (session != null) + { + log.LogDebug("Closing Hibernate Session"); + try + { + session.Close(); + } + catch (HibernateException ex) + { + log.LogError(ex, "Could not close Hibernate Session"); + } + catch (Exception ex) + { + log.LogError(ex, "Unexpected exception on closing Hibernate Session"); + } + } + } + + /// + /// Return whether the given Hibernate Session is transactional, that is, + /// bound to the current thread by Spring's transaction facilities. + /// + /// The hibernate session to check + /// The session factory that the session + /// was created with, can be null. + /// + /// true if the session transactional; otherwise, false. + /// + public static bool IsSessionTransactional(ISession session, ISessionFactory sessionFactory) + { + if (sessionFactory == null) + { + return false; + } + + SessionHolder sessionHolder = + (SessionHolder) TransactionSynchronizationManager.GetResource(sessionFactory); + return (sessionHolder != null && sessionHolder.ContainsSession(session)); + } + + /// + /// Converts a Hibernate ADOException to a Spring DataAccessExcption, extracting the underlying error code from + /// ADO.NET. Will extract the ADOException Message and SqlString properties and pass them to the translate method + /// of the provided IAdoExceptionTranslator. + /// + /// The IAdoExceptionTranslator, may be a user provided implementation as configured on + /// HibernateTemplate. + /// + /// The ADOException throw + /// The translated DataAccessException or UncategorizedAdoException in case of an error in translation + /// itself. + public static DataAccessException ConvertAdoAccessException(IAdoExceptionTranslator translator, ADOException ex) + { + try + { + string sqlString = (ex.SqlString != null) + ? ex.SqlString.ToString() + : string.Empty; + return translator.Translate( + "Hibernate operation: " + ex.Message, sqlString, ex.InnerException); + } + catch (Exception e) + { + string message = "Exception thrown during exception translation. Message = [" + e.Message + "]"; + log.LogError(e, message); + string message1 = "Exception that was attempted to be translated was [" + ex.Message + "]"; + log.LogError((Exception) ex, message1); + if (ex.InnerException != null) + { + string message2 = " Inner Exception was [" + ex.InnerException.Message + "]"; + log.LogError(ex.InnerException, message2); + } + + throw new UncategorizedAdoException(e.Message, "", "", e); + } + } + + /// + /// Convert the given HibernateException to an appropriate exception from the + /// Spring.Dao hierarchy. Note that it is advisable to + /// handle AdoException specifically by using a AdoExceptionTranslator for the + /// underlying ADO.NET exception. + /// + /// The Hibernate exception that occured. + /// DataAccessException instance + public static DataAccessException ConvertHibernateAccessException(HibernateException ex) + { + if (ex is ADOException) + { + // ADOException during Hibernate access: only passed in here from custom code, + // as HibernateTemplate etc will use AdoExceptionTranslator-based handling. + return new HibernateAdoException("Ado Exception", (ADOException) ex); + } + + if (ex is UnresolvableObjectException) + { + return new HibernateObjectRetrievalFailureException((UnresolvableObjectException) ex); + } + + if (ex is ObjectDeletedException) + { + return new InvalidDataAccessApiUsageException(ex.Message, ex); + } + + if (ex is WrongClassException) + { + return new HibernateObjectRetrievalFailureException((WrongClassException) ex); + } + + if (ex is StaleObjectStateException) + { + return new HibernateOptimisticLockingFailureException((StaleObjectStateException) ex); + } + + if (ex is StaleStateException) + { + return new HibernateOptimisticLockingFailureException((StaleStateException) ex); + } + + if (ex is QueryException) + { + return new HibernateQueryException((QueryException) ex); + } + + if (ex is PersistentObjectException) + { + return new InvalidDataAccessApiUsageException(ex.Message, ex); + } + + if (ex is TransientObjectException) + { + return new InvalidDataAccessApiUsageException(ex.Message, ex); + } + + if (ex is PropertyValueException) + { + return new DataIntegrityViolationException(ex.Message, ex); + } + + if (ex is PersistentObjectException) + { + return new InvalidDataAccessApiUsageException(ex.Message, ex); + } + + if (ex is NonUniqueResultException) + { + return new IncorrectResultSizeDataAccessException(ex.Message, 1); + } + + // fallback + return new HibernateSystemException(ex); + } + + /// + /// Close the given Session, created via the given factory, + /// if it is not managed externally (i.e. not bound to the thread). + /// + /// The hibernate session to close + /// The hibernate SessionFactory that + /// the session was created with. + public static void ReleaseSession(ISession session, ISessionFactory sessionFactory) + { + if (session == null) + { + return; + } + + // Only close non-transactional Sessions. + if (!IsSessionTransactional(session, sessionFactory)) + { + CloseSessionOrRegisterDeferredClose(session, sessionFactory); + } + } + + /// + /// Close the given Session or register it for deferred close. + /// + /// The session. + /// The session factory. + internal static void CloseSessionOrRegisterDeferredClose(ISession session, ISessionFactory sessionFactory) + { + IDictionary holderDictionary = LogicalThreadContext.GetData(DeferredCloseHolderDataSlotName) as IDictionary; + + if (holderDictionary != null && sessionFactory != null && holderDictionary.Contains(sessionFactory)) + { + log.LogDebug("Registering Hibernate Session for deferred close"); + // Switch Session to FlushMode.NEVER for remaining lifetime. + session.FlushMode = FlushMode.Never; + Set sessions = (Set) holderDictionary[sessionFactory]; + sessions.Add(session); + } + else + { + CloseSession(session); + } + } + + /// + ///Initialize deferred close for the current thread and the given SessionFactory. + /// Sessions will not be actually closed on close calls then, but rather at a + /// processDeferredClose call at a finishing point (like request completion). + /// + /// The session factory. + public static void InitDeferredClose(ISessionFactory sessionFactory) + { + AssertUtils.ArgumentNotNull(sessionFactory, "No SessionFactory specified"); + + log.LogDebug("Initializing deferred close of Hibernate Sessions"); + + IDictionary holderDictionary = LogicalThreadContext.GetData(DeferredCloseHolderDataSlotName) as IDictionary; + + if (holderDictionary == null) + { + holderDictionary = new Hashtable(); + LogicalThreadContext.SetData(DeferredCloseHolderDataSlotName, holderDictionary); + } + + holderDictionary.Add(sessionFactory, new ListSet()); + } + + /// + /// Return if deferred close is active for the current thread + /// and the given SessionFactory. + /// The session factory. + /// + /// true if [is deferred close active] [the specified session factory]; otherwise, false. + /// + /// If SessionFactory argument is null. + public static bool IsDeferredCloseActive(ISessionFactory sessionFactory) + { + if (sessionFactory == null) + { + throw new ArgumentNullException("sessionFactory", "No SessionFactory specified"); + } + + IDictionary holderDictionary = LogicalThreadContext.GetData(DeferredCloseHolderDataSlotName) as IDictionary; + return (holderDictionary != null && holderDictionary.Contains(sessionFactory)); + } + + /// + /// Process Sessions that have been registered for deferred close + /// for the given SessionFactory. + /// + /// The session factory. + /// If there is no session factory associated with the thread. + public static void ProcessDeferredClose(ISessionFactory sessionFactory) + { + AssertUtils.ArgumentNotNull(sessionFactory, "No SessionFactory specified"); + + IDictionary holderDictionary = LogicalThreadContext.GetData(DeferredCloseHolderDataSlotName) as IDictionary; + + if (holderDictionary == null || !holderDictionary.Contains(sessionFactory)) + { + throw new InvalidOperationException("Deferred close not active for SessionFactory [" + sessionFactory + "]"); + } + + log.LogDebug("Processing deferred close of Hibernate Sessions"); + Set sessions = (Set) holderDictionary[sessionFactory]; + holderDictionary.Remove(sessionFactory); + foreach (ISession session in sessions) + { + CloseSession(session); + } + + if (holderDictionary.Count == 0) + { + LogicalThreadContext.FreeNamedDataSlot(DeferredCloseHolderDataSlotName); + } + } + + /// + /// Applies the current transaction timeout, if any, to the given + /// criteria object + /// + /// The Hibernate Criteria object. + /// Hibernate SessionFactory that the Criteria was created for + /// (can be null). + /// If criteria argument is null. + public static void ApplyTransactionTimeout(ICriteria criteria, ISessionFactory sessionFactory) + { + if (criteria == null) + { + throw new ArgumentNullException("criteria", "No Criteria object specified"); + } + + SessionHolder sessionHolder = + (SessionHolder) TransactionSynchronizationManager.GetResource(sessionFactory); + if (sessionHolder != null && sessionHolder.HasTimeout) + { + criteria.SetTimeout(sessionHolder.TimeToLiveInSeconds); + } + } + + /// + /// Applies the current transaction timeout, if any, to the given + /// Hibenrate query object. + /// + /// The Hibernate Query object. + /// Hibernate SessionFactory that the Query was created for + /// (can be null). + /// If query argument is null. + public static void ApplyTransactionTimeout(IQuery query, ISessionFactory sessionFactory) + { + if (query == null) + { + throw new ArgumentNullException("queryObject", "No query object specified"); + } + + if (sessionFactory != null) + { + SessionHolder sessionHolder = + (SessionHolder) TransactionSynchronizationManager.GetResource(sessionFactory); + if (sessionHolder != null && sessionHolder.HasTimeout) + { + query.SetTimeout(sessionHolder.TimeToLiveInSeconds); + } + } + } + + /// + /// Gets the Spring IDbProvider given the ISessionFactory. + /// + /// The matching is performed by comparing the assembly qualified + /// name string of the hibernate Driver.ConnectionType to those in + /// the DbProviderFactory definitions. No connections are created + /// in performing this comparison. + /// The session factory. + /// The corresponding IDbProvider, null if no mapping was found. + /// If DbProviderFactory's ApplicaitonContext is not + /// an instance of IConfigurableApplicaitonContext. + public static IDbProvider GetDbProvider(ISessionFactory sessionFactory) + { + ISessionFactoryImplementor sfi = sessionFactory as ISessionFactoryImplementor; + if (sfi != null) + { + IConnectionProvider cp = sfi.ConnectionProvider; + if (cp != null) + { + IConfigurableApplicationContext ctx = + DbProviderFactory.ApplicationContext as IConfigurableApplicationContext; + if (ctx == null) + { + throw new InvalidOperationException( + "Implementations of IApplicationContext must also implement IConfigurableApplicationContext"); + } + + DriverBase db = cp.Driver as DriverBase; + if (db != null) + { + Type hibCommandType = db.CreateCommand().GetType(); + + var providerNames = ctx.GetObjectNamesForType(typeof(DbProvider), true, false); + string hibCommandAQN = hibCommandType.AssemblyQualifiedName; + string hibCommandAQNWithoutVersion = hibCommandType.FullName + ", " + hibCommandType.Assembly.GetName().Name; + foreach (string providerName in providerNames) + { + IObjectDefinition objectdef = ctx.ObjectFactory.GetObjectDefinition(providerName); + ConstructorArgumentValues ctorArgs = objectdef.ConstructorArgumentValues; + ConstructorArgumentValues.ValueHolder vh = ctorArgs.NamedArgumentValues["dbmetadata"] as ConstructorArgumentValues.ValueHolder; + IObjectDefinition od = ((ObjectDefinitionHolder) vh.Value).ObjectDefinition; + ConstructorArgumentValues dbmdCtorArgs = od.ConstructorArgumentValues; + string commandType = dbmdCtorArgs.GetArgumentValue("commandType", typeof(string)).Value as string; + + if (hibCommandAQN.Equals(commandType) || hibCommandAQNWithoutVersion.Equals(commandType)) { - session.FlushMode = FlushMode.Auto; - sessionHolder.PreviousFlushMode = flushMode; + IDbProvider prov = DbProviderFactory.GetDbProvider(providerName); + return prov; } } } else { - // No Spring transaction management active -> simply return default thread-bound Session, if any - // (possibly from OpenSessionInViewModule) - session = sessionHolder.ValidatedSession; - } - - if (session != null) - { - return session; - } - - } - - - ISession sess = OpenSession(sessionFactory, entityInterceptor); - // Set Session to FlushMode.Never if we're within a read-only transaction. - // Use same Session for further Hibernate actions within the transaction. - // Thread object will get removed by synchronization at transaction completion. - if (TransactionSynchronizationManager.SynchronizationActive) - { - log.LogDebug("Registering Spring transaction synchronization for new Hibernate Session"); - SessionHolder holderToUse = sessionHolder; - if (holderToUse == null) - { - holderToUse = new SessionHolder(sess); - } - else - { - holderToUse.AddSession(sess); - } - if (TransactionSynchronizationManager.CurrentTransactionReadOnly) - { - sess.FlushMode = FlushMode.Never; - } - TransactionSynchronizationManager.RegisterSynchronization( - new SpringSessionSynchronization(holderToUse, sessionFactory, adoExceptionTranslator, true)); - holderToUse.SynchronizedWithTransaction = true; - if (holderToUse != sessionHolder) - { - TransactionSynchronizationManager.BindResource(sessionFactory, holderToUse); - } - } - - - - // Check whether we are allowed to return the Session. - if (!allowCreate && !IsSessionTransactional(sess, sessionFactory)) - { - CloseSession(sess); - throw new InvalidOperationException ("No Hibernate Session bound to thread, " + - "and configuration does not allow creation of non-transactional one here"); - } - - return sess; - - - } - - /// - /// Open a new Session from the factory. - /// - /// The session factory to create the session with. - /// Hibernate entity interceptor, or null if none. - /// the newly opened session - internal static ISession OpenSession(ISessionFactory sessionFactory, IInterceptor entityInterceptor) - { - log.LogDebug("Opening Hibernate Session"); - ISession session = ( - (entityInterceptor != null) - ? sessionFactory.OpenSession(entityInterceptor) - : sessionFactory.OpenSession() - ); - - return session; - } - - /// - /// Perform the actual closing of the Hibernate Session - /// catching and logging any cleanup exceptions thrown. - /// - /// The hibernate session to close - public static void CloseSession(ISession session) - { - if (session != null) - { - log.LogDebug("Closing Hibernate Session"); - try - { - session.Close(); - } - catch (HibernateException ex) - { - log.LogError(ex, "Could not close Hibernate Session"); - } - catch (Exception ex) - { - log.LogError(ex, "Unexpected exception on closing Hibernate Session"); + log.LogInformation("Could not derive IDbProvider from SessionFactory"); } } } - /// - /// Return whether the given Hibernate Session is transactional, that is, - /// bound to the current thread by Spring's transaction facilities. - /// - /// The hibernate session to check - /// The session factory that the session - /// was created with, can be null. - /// - /// true if the session transactional; otherwise, false. - /// - public static bool IsSessionTransactional(ISession session, ISessionFactory sessionFactory) + return null; + } + + /// + /// Create a IAdoExceptionTranslator from the given SessionFactory. + /// + /// If a corresponding IDbProvider is found, a ErrorcodeExceptionTranslator + /// for the IDbProvider is created. Otherwise, a FallbackException is created. + /// The session factory to create the translator for + /// An IAdoExceptionTranslator + public static IAdoExceptionTranslator NewAdoExceptionTranslator(ISessionFactory sessionFactory) + { + IDbProvider dbProvider = GetDbProvider(sessionFactory); + if (dbProvider != null) { - if (sessionFactory == null) - { - return false; - } - SessionHolder sessionHolder = - (SessionHolder) TransactionSynchronizationManager.GetResource(sessionFactory); - return (sessionHolder != null && sessionHolder.ContainsSession(session)); + return new ErrorCodeExceptionTranslator(dbProvider); } - /// - /// Converts a Hibernate ADOException to a Spring DataAccessExcption, extracting the underlying error code from - /// ADO.NET. Will extract the ADOException Message and SqlString properties and pass them to the translate method - /// of the provided IAdoExceptionTranslator. - /// - /// The IAdoExceptionTranslator, may be a user provided implementation as configured on - /// HibernateTemplate. - /// - /// The ADOException throw - /// The translated DataAccessException or UncategorizedAdoException in case of an error in translation - /// itself. - public static DataAccessException ConvertAdoAccessException(IAdoExceptionTranslator translator, ADOException ex) - { - try - { - string sqlString = (ex.SqlString != null) - ? ex.SqlString.ToString() - : string.Empty; - return translator.Translate( - "Hibernate operation: " + ex.Message, sqlString, ex.InnerException); - } catch (Exception e) - { - string message = "Exception thrown during exception translation. Message = [" + e.Message + "]"; - log.LogError(e, message); - string message1 = "Exception that was attempted to be translated was [" + ex.Message + "]"; - log.LogError((Exception) ex, message1); - if (ex.InnerException != null) - { - string message2 = " Inner Exception was [" + ex.InnerException.Message + "]"; - log.LogError(ex.InnerException, message2); - } - throw new UncategorizedAdoException(e.Message, "", "", e); - } - } - - /// - /// Convert the given HibernateException to an appropriate exception from the - /// Spring.Dao hierarchy. Note that it is advisable to - /// handle AdoException specifically by using a AdoExceptionTranslator for the - /// underlying ADO.NET exception. - /// - /// The Hibernate exception that occured. - /// DataAccessException instance - public static DataAccessException ConvertHibernateAccessException(HibernateException ex) - { - if (ex is ADOException) - { - // ADOException during Hibernate access: only passed in here from custom code, - // as HibernateTemplate etc will use AdoExceptionTranslator-based handling. - return new HibernateAdoException("Ado Exception", (ADOException) ex); - } - if (ex is UnresolvableObjectException) - { - return new HibernateObjectRetrievalFailureException((UnresolvableObjectException) ex); - } - if (ex is ObjectDeletedException) - { - return new InvalidDataAccessApiUsageException(ex.Message, ex); - } - if (ex is WrongClassException) - { - return new HibernateObjectRetrievalFailureException((WrongClassException) ex); - } - if (ex is StaleObjectStateException) - { - return new HibernateOptimisticLockingFailureException((StaleObjectStateException) ex); - } - if (ex is StaleStateException) - { - return new HibernateOptimisticLockingFailureException((StaleStateException)ex); - } - if (ex is QueryException) - { - return new HibernateQueryException((QueryException) ex); - } - - if (ex is PersistentObjectException) - { - return new InvalidDataAccessApiUsageException(ex.Message, ex); - } - if (ex is TransientObjectException) - { - return new InvalidDataAccessApiUsageException(ex.Message, ex); - } - - if (ex is PropertyValueException) - { - return new DataIntegrityViolationException(ex.Message, ex); - } - if (ex is PersistentObjectException) - { - return new InvalidDataAccessApiUsageException(ex.Message, ex); - } - if (ex is NonUniqueResultException) - { - return new IncorrectResultSizeDataAccessException(ex.Message, 1); - } - // fallback - return new HibernateSystemException(ex); - } - - /// - /// Close the given Session, created via the given factory, - /// if it is not managed externally (i.e. not bound to the thread). - /// - /// The hibernate session to close - /// The hibernate SessionFactory that - /// the session was created with. - public static void ReleaseSession(ISession session, ISessionFactory sessionFactory) - { - if (session == null) - { - return; - } - // Only close non-transactional Sessions. - if (!IsSessionTransactional(session, sessionFactory)) - { - CloseSessionOrRegisterDeferredClose(session, sessionFactory); - } - } - - /// - /// Close the given Session or register it for deferred close. - /// - /// The session. - /// The session factory. - internal static void CloseSessionOrRegisterDeferredClose(ISession session, ISessionFactory sessionFactory) - { - IDictionary holderDictionary = LogicalThreadContext.GetData(DeferredCloseHolderDataSlotName) as IDictionary; - - if (holderDictionary != null && sessionFactory != null && holderDictionary.Contains(sessionFactory)) - { - log.LogDebug("Registering Hibernate Session for deferred close"); - // Switch Session to FlushMode.NEVER for remaining lifetime. - session.FlushMode = FlushMode.Never; - Set sessions = (Set) holderDictionary[sessionFactory]; - sessions.Add(session); - } - else - { - CloseSession(session); - } - } - - /// - ///Initialize deferred close for the current thread and the given SessionFactory. - /// Sessions will not be actually closed on close calls then, but rather at a - /// processDeferredClose call at a finishing point (like request completion). - /// - /// The session factory. - public static void InitDeferredClose(ISessionFactory sessionFactory) - { - AssertUtils.ArgumentNotNull(sessionFactory, "No SessionFactory specified"); - - log.LogDebug("Initializing deferred close of Hibernate Sessions"); - - IDictionary holderDictionary = LogicalThreadContext.GetData(DeferredCloseHolderDataSlotName) as IDictionary; - - if (holderDictionary == null) - { - holderDictionary = new Hashtable(); - LogicalThreadContext.SetData(DeferredCloseHolderDataSlotName, holderDictionary); - } - holderDictionary.Add(sessionFactory, new ListSet()); - } - - /// - /// Return if deferred close is active for the current thread - /// and the given SessionFactory. - /// The session factory. - /// - /// true if [is deferred close active] [the specified session factory]; otherwise, false. - /// - /// If SessionFactory argument is null. - public static bool IsDeferredCloseActive(ISessionFactory sessionFactory) - { - if (sessionFactory == null) - { - throw new ArgumentNullException("sessionFactory", "No SessionFactory specified"); - } - IDictionary holderDictionary = LogicalThreadContext.GetData(DeferredCloseHolderDataSlotName) as IDictionary; - return (holderDictionary != null && holderDictionary.Contains(sessionFactory)); - } - - /// - /// Process Sessions that have been registered for deferred close - /// for the given SessionFactory. - /// - /// The session factory. - /// If there is no session factory associated with the thread. - public static void ProcessDeferredClose(ISessionFactory sessionFactory) - { - AssertUtils.ArgumentNotNull(sessionFactory, "No SessionFactory specified"); - - IDictionary holderDictionary = LogicalThreadContext.GetData(DeferredCloseHolderDataSlotName) as IDictionary; - - if (holderDictionary == null || !holderDictionary.Contains(sessionFactory)) - { - throw new InvalidOperationException("Deferred close not active for SessionFactory [" + sessionFactory + "]"); - } - log.LogDebug("Processing deferred close of Hibernate Sessions"); - Set sessions = (Set) holderDictionary[sessionFactory]; - holderDictionary.Remove(sessionFactory); - foreach (ISession session in sessions) - { - CloseSession(session); - } - - if (holderDictionary.Count == 0) - { - LogicalThreadContext.FreeNamedDataSlot(DeferredCloseHolderDataSlotName); - } - - - } - - /// - /// Applies the current transaction timeout, if any, to the given - /// criteria object - /// - /// The Hibernate Criteria object. - /// Hibernate SessionFactory that the Criteria was created for - /// (can be null). - /// If criteria argument is null. - public static void ApplyTransactionTimeout(ICriteria criteria, ISessionFactory sessionFactory) - { - if (criteria == null) - { - throw new ArgumentNullException("criteria", "No Criteria object specified"); - } - - SessionHolder sessionHolder = - (SessionHolder) TransactionSynchronizationManager.GetResource(sessionFactory); - if (sessionHolder != null && sessionHolder.HasTimeout) - { - criteria.SetTimeout(sessionHolder.TimeToLiveInSeconds); - } - } - - /// - /// Applies the current transaction timeout, if any, to the given - /// Hibenrate query object. - /// - /// The Hibernate Query object. - /// Hibernate SessionFactory that the Query was created for - /// (can be null). - /// If query argument is null. - public static void ApplyTransactionTimeout(IQuery query, ISessionFactory sessionFactory) - { - if (query == null) - { - throw new ArgumentNullException("queryObject", "No query object specified"); - } - if (sessionFactory != null) - { - SessionHolder sessionHolder = - (SessionHolder) TransactionSynchronizationManager.GetResource(sessionFactory); - if (sessionHolder != null && sessionHolder.HasTimeout) - { - query.SetTimeout(sessionHolder.TimeToLiveInSeconds); - } - } - } - /// - /// Gets the Spring IDbProvider given the ISessionFactory. - /// - /// The matching is performed by comparing the assembly qualified - /// name string of the hibernate Driver.ConnectionType to those in - /// the DbProviderFactory definitions. No connections are created - /// in performing this comparison. - /// The session factory. - /// The corresponding IDbProvider, null if no mapping was found. - /// If DbProviderFactory's ApplicaitonContext is not - /// an instance of IConfigurableApplicaitonContext. - public static IDbProvider GetDbProvider(ISessionFactory sessionFactory) - { - ISessionFactoryImplementor sfi = sessionFactory as ISessionFactoryImplementor; - if (sfi != null) - { - - IConnectionProvider cp = sfi.ConnectionProvider; - if (cp != null) - { - IConfigurableApplicationContext ctx = - DbProviderFactory.ApplicationContext as IConfigurableApplicationContext; - if (ctx == null) - { - throw new InvalidOperationException( - "Implementations of IApplicationContext must also implement IConfigurableApplicationContext"); - } - - - DriverBase db = cp.Driver as DriverBase; - if (db != null) - { - Type hibCommandType = db.CreateCommand().GetType(); - - var providerNames = ctx.GetObjectNamesForType(typeof(DbProvider), true, false); - string hibCommandAQN = hibCommandType.AssemblyQualifiedName; - string hibCommandAQNWithoutVersion = hibCommandType.FullName + ", " + hibCommandType.Assembly.GetName().Name; - foreach (string providerName in providerNames) - { - IObjectDefinition objectdef = ctx.ObjectFactory.GetObjectDefinition(providerName); - ConstructorArgumentValues ctorArgs = objectdef.ConstructorArgumentValues; - ConstructorArgumentValues.ValueHolder vh = ctorArgs.NamedArgumentValues["dbmetadata"] as ConstructorArgumentValues.ValueHolder; - IObjectDefinition od = ((ObjectDefinitionHolder)vh.Value).ObjectDefinition; - ConstructorArgumentValues dbmdCtorArgs = od.ConstructorArgumentValues; - string commandType = dbmdCtorArgs.GetArgumentValue("commandType", typeof(string)).Value as string; - - if (hibCommandAQN.Equals(commandType) || hibCommandAQNWithoutVersion.Equals(commandType)) - { - IDbProvider prov = DbProviderFactory.GetDbProvider(providerName); - return prov; - } - } - } - else - { - log.LogInformation("Could not derive IDbProvider from SessionFactory"); - } - } - - - } - return null; - } - - /// - /// Create a IAdoExceptionTranslator from the given SessionFactory. - /// - /// If a corresponding IDbProvider is found, a ErrorcodeExceptionTranslator - /// for the IDbProvider is created. Otherwise, a FallbackException is created. - /// The session factory to create the translator for - /// An IAdoExceptionTranslator - public static IAdoExceptionTranslator NewAdoExceptionTranslator(ISessionFactory sessionFactory) - { - IDbProvider dbProvider = GetDbProvider(sessionFactory); - if (dbProvider != null) - { - return new ErrorCodeExceptionTranslator(dbProvider); - } - log.LogWarning("Using FallbackException Translator. Could not translate from ISessionFactory to IDbProvider"); - return new FallbackExceptionTranslator(); - - } - } + log.LogWarning("Using FallbackException Translator. Could not translate from ISessionFactory to IDbProvider"); + return new FallbackExceptionTranslator(); + } } diff --git a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/SessionHolder.cs b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/SessionHolder.cs index b1729b9d..c558cc56 100644 --- a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/SessionHolder.cs +++ b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/SessionHolder.cs @@ -1,12 +1,12 @@ /* * Copyright � 2002-2011 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. @@ -18,333 +18,332 @@ using System.Collections; using System.Data; using Microsoft.Extensions.Logging; using NHibernate; - using Spring.Transaction.Support; using Spring.Util; -namespace Spring.Data.NHibernate +namespace Spring.Data.NHibernate; + +/// +/// Session holder, wrapping a NHibernate ISession and a NHibernate Transaction. +/// HibernateTransactionManager binds instances of this class +/// to the thread, for a given ISessionFactory. +/// +/// +/// Note: This is an SPI class, not intended to be used by applications. +/// +/// Mark Pollack (.NET) +public class SessionHolder : ResourceHolderSupport { - /// - /// Session holder, wrapping a NHibernate ISession and a NHibernate Transaction. - /// HibernateTransactionManager binds instances of this class - /// to the thread, for a given ISessionFactory. - /// - /// - /// Note: This is an SPI class, not intended to be used by applications. - /// - /// Mark Pollack (.NET) - public class SessionHolder : ResourceHolderSupport - { - private static readonly object DEFAULT_KEY = new object(); + private static readonly object DEFAULT_KEY = new object(); - private readonly object sessionDictionaryLock = new object(); - private readonly Dictionary sessionDictionary = new Dictionary(1); - - private IDbConnection connection; + private readonly object sessionDictionaryLock = new object(); + private readonly Dictionary sessionDictionary = new Dictionary(1); - private ITransaction transaction; + private IDbConnection connection; - private FlushMode flushMode; + private ITransaction transaction; - //needed to see if we actually assigned the enum value... - private bool assignedPreviousFlushMode = false; + private FlushMode flushMode; - private static readonly ILogger log = LogManager.GetLogger(); + //needed to see if we actually assigned the enum value... + private bool assignedPreviousFlushMode = false; - /// - /// May be used by derived classes to create an empty SessionHolder. - /// - /// - /// When using this ctor in your derived class, you MUST override ! - /// - protected SessionHolder() - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The session. - public SessionHolder(ISession session) - { - AddSession(session); - } + private static readonly ILogger log = LogManager.GetLogger(); - /// - /// Initializes a new instance of the class. - /// - /// The key to store the session under. - /// The hibernate session. - public SessionHolder(object key, ISession session) - { - AddSession(key, session); - } - - /// - /// May be overridden in a derived class to e.g. lazily create a session - /// - protected virtual void EnsureInitialized() - { - // noop here - but may be overridden to lazily create a session - } + /// + /// May be used by derived classes to create an empty SessionHolder. + /// + /// + /// When using this ctor in your derived class, you MUST override ! + /// + protected SessionHolder() + { + } - /// - /// Gets the session using the default key - /// - /// The hibernate session. - public ISession Session - { - get - { - lock (sessionDictionaryLock) - { - EnsureInitialized(); - ISession session; - sessionDictionary.TryGetValue(DEFAULT_KEY, out session); - return session; - } - } - } + /// + /// Initializes a new instance of the class. + /// + /// The session. + public SessionHolder(ISession session) + { + AddSession(session); + } - /// - /// Gets the first session based on iteration over - /// the IDictionary storage. - /// - /// Any hibernate session. - public ISession AnySession - { - get - { - lock(sessionDictionaryLock) - { - EnsureInitialized(); - if (sessionDictionary.Count > 0) - { - IEnumerator enumerator = sessionDictionary.Values.GetEnumerator(); - enumerator.MoveNext(); - return (ISession)enumerator.Current; - } - return null; - } - } - } + /// + /// Initializes a new instance of the class. + /// + /// The key to store the session under. + /// The hibernate session. + public SessionHolder(object key, ISession session) + { + AddSession(key, session); + } - /// - /// Gets a value indicating whether dictionary of - /// hibernate sessions is empty. - /// - /// - /// true if this session holder is empty; otherwise, false. - /// - public bool IsEmpty - { - get - { - lock(sessionDictionaryLock) - { - EnsureInitialized(); - return (sessionDictionary.Count > 0 ? false : true); - } - } - } + /// + /// May be overridden in a derived class to e.g. lazily create a session + /// + protected virtual void EnsureInitialized() + { + // noop here - but may be overridden to lazily create a session + } - /// - /// Gets a value indicating whether this SessionHolder - /// does not hold non default session. - /// - /// - /// true if does not hold non default session; otherwise, false. - /// - public bool DoesNotHoldNonDefaultSession - { - get - { - lock (sessionDictionaryLock) - { - EnsureInitialized(); - return ( - sessionDictionary.Count == 0 || - (sessionDictionary.Count == 1 && sessionDictionary.ContainsKey(DEFAULT_KEY)) - ); - - } - } - } - - /// - /// Gets or sets the hibernate transaction. - /// - /// The transaction. - public ITransaction Transaction - { - get { return transaction; } - set { transaction = value; } - } - - /// - /// Gets or sets the ADO.NET Connection used to create the session. - /// - /// The ADO.NET connection. - public IDbConnection Connection - { - get { return connection; } - set { connection = value; } - } - - /// - /// Gets or sets the previous flush mode. - /// - /// The previous flush mode. - public FlushMode PreviousFlushMode - { - get { return flushMode; } - set - { - flushMode = value; - assignedPreviousFlushMode = true; - } - } - - /// - /// Gets a value indicating whether the PreviousFlushMode property - /// was set. - /// - /// - /// true if assigned PreviousFlushMode property; otherwise, false. - /// - public bool AssignedPreviousFlushMode - { - get - { - return assignedPreviousFlushMode; - } - } - - /// - /// Gets the validated session. - /// - /// The validated session. - public ISession ValidatedSession - { - get - { - return GetValidatedSession(DEFAULT_KEY); - } - } - - /// - /// Gets the session given key identifier - /// - /// The key. - /// A hibernate session - public ISession GetSession(object key) + /// + /// Gets the session using the default key + /// + /// The hibernate session. + public ISession Session + { + get { lock (sessionDictionaryLock) { EnsureInitialized(); ISession session; - sessionDictionary.TryGetValue(key, out session); + sessionDictionary.TryGetValue(DEFAULT_KEY, out session); return session; } } + } - - /// - /// Gets the session given the key and removes the session from - /// the dictionary storage. - /// - /// The key. - /// A hibernate session - public ISession GetValidatedSession(object key) + /// + /// Gets the first session based on iteration over + /// the IDictionary storage. + /// + /// Any hibernate session. + public ISession AnySession + { + get { lock (sessionDictionaryLock) { - EnsureInitialized(); - ISession session; - // Check for dangling Session that's around but already closed. - // Effectively an assertion: that should never happen in practice. - // We'll seamlessly remove the Session here, to not let it cause - // any side effects. - if (sessionDictionary.TryGetValue(key, out session) && !session.IsOpen) + EnsureInitialized(); + if (sessionDictionary.Count > 0) { - sessionDictionary.Remove(key); - session = null; + IEnumerator enumerator = sessionDictionary.Values.GetEnumerator(); + enumerator.MoveNext(); + return (ISession) enumerator.Current; } - return session; + + return null; } } - /// - /// Adds the session to the dictionary storage using the default key. - /// - /// The hibernate session. - public void AddSession(ISession session) - { - AddSession(DEFAULT_KEY, session); - } + } - /// - /// Adds the session to the dictionary storage using the supplied key. - /// - /// The key. - /// The hibernate session. - public void AddSession(object key, ISession session) + /// + /// Gets a value indicating whether dictionary of + /// hibernate sessions is empty. + /// + /// + /// true if this session holder is empty; otherwise, false. + /// + public bool IsEmpty + { + get { - AssertUtils.ArgumentNotNull(key, "key", "Key must not be null"); - AssertUtils.ArgumentNotNull(session, "session", "Session must not be null"); - lock (sessionDictionaryLock) { - if (sessionDictionary.ContainsKey(key)) - { - log.LogDebug("Overwriting Session in SessionHolder with key = "+ key); - } - - sessionDictionary[key] = session; + EnsureInitialized(); + return (sessionDictionary.Count > 0 ? false : true); } } + } - /// - /// Removes the session from the dictionary storage for the given key. - /// - /// The key. - /// The session that was previously contained in the - /// dictionary storage. - public ISession RemoveSession(object key) + /// + /// Gets a value indicating whether this SessionHolder + /// does not hold non default session. + /// + /// + /// true if does not hold non default session; otherwise, false. + /// + public bool DoesNotHoldNonDefaultSession + { + get { - lock(sessionDictionaryLock) + lock (sessionDictionaryLock) + { + EnsureInitialized(); + return ( + sessionDictionary.Count == 0 || + (sessionDictionary.Count == 1 && sessionDictionary.ContainsKey(DEFAULT_KEY)) + ); + } + } + } + + /// + /// Gets or sets the hibernate transaction. + /// + /// The transaction. + public ITransaction Transaction + { + get { return transaction; } + set { transaction = value; } + } + + /// + /// Gets or sets the ADO.NET Connection used to create the session. + /// + /// The ADO.NET connection. + public IDbConnection Connection + { + get { return connection; } + set { connection = value; } + } + + /// + /// Gets or sets the previous flush mode. + /// + /// The previous flush mode. + public FlushMode PreviousFlushMode + { + get { return flushMode; } + set + { + flushMode = value; + assignedPreviousFlushMode = true; + } + } + + /// + /// Gets a value indicating whether the PreviousFlushMode property + /// was set. + /// + /// + /// true if assigned PreviousFlushMode property; otherwise, false. + /// + public bool AssignedPreviousFlushMode + { + get + { + return assignedPreviousFlushMode; + } + } + + /// + /// Gets the validated session. + /// + /// The validated session. + public ISession ValidatedSession + { + get + { + return GetValidatedSession(DEFAULT_KEY); + } + } + + /// + /// Gets the session given key identifier + /// + /// The key. + /// A hibernate session + public ISession GetSession(object key) + { + lock (sessionDictionaryLock) + { + EnsureInitialized(); + ISession session; + sessionDictionary.TryGetValue(key, out session); + return session; + } + } + + /// + /// Gets the session given the key and removes the session from + /// the dictionary storage. + /// + /// The key. + /// A hibernate session + public ISession GetValidatedSession(object key) + { + lock (sessionDictionaryLock) + { + EnsureInitialized(); + ISession session; + // Check for dangling Session that's around but already closed. + // Effectively an assertion: that should never happen in practice. + // We'll seamlessly remove the Session here, to not let it cause + // any side effects. + if (sessionDictionary.TryGetValue(key, out session) && !session.IsOpen) { - ISession oldSession; - sessionDictionary.TryGetValue(key, out oldSession); sessionDictionary.Remove(key); - return oldSession; + session = null; } - } - /// - /// Determines whether the holder the specified session. - /// - /// The session. - /// - /// true if the holder contains the specified session; otherwise, false. - /// - public bool ContainsSession(ISession session) + return session; + } + } + + /// + /// Adds the session to the dictionary storage using the default key. + /// + /// The hibernate session. + public void AddSession(ISession session) + { + AddSession(DEFAULT_KEY, session); + } + + /// + /// Adds the session to the dictionary storage using the supplied key. + /// + /// The key. + /// The hibernate session. + public void AddSession(object key, ISession session) + { + AssertUtils.ArgumentNotNull(key, "key", "Key must not be null"); + AssertUtils.ArgumentNotNull(session, "session", "Session must not be null"); + + lock (sessionDictionaryLock) { - lock (sessionDictionaryLock) + if (sessionDictionary.ContainsKey(key)) { - EnsureInitialized(); - return sessionDictionary.ContainsValue(session); + log.LogDebug("Overwriting Session in SessionHolder with key = " + key); } - } - /// - /// Clear the transaction state of this resource holder. - /// - public override void Clear() - { - base.Clear(); - Transaction = null; - assignedPreviousFlushMode = false; - Connection = null; + sessionDictionary[key] = session; } - } + } + + /// + /// Removes the session from the dictionary storage for the given key. + /// + /// The key. + /// The session that was previously contained in the + /// dictionary storage. + public ISession RemoveSession(object key) + { + lock (sessionDictionaryLock) + { + ISession oldSession; + sessionDictionary.TryGetValue(key, out oldSession); + sessionDictionary.Remove(key); + return oldSession; + } + } + + /// + /// Determines whether the holder the specified session. + /// + /// The session. + /// + /// true if the holder contains the specified session; otherwise, false. + /// + public bool ContainsSession(ISession session) + { + lock (sessionDictionaryLock) + { + EnsureInitialized(); + return sessionDictionary.ContainsValue(session); + } + } + + /// + /// Clear the transaction state of this resource holder. + /// + public override void Clear() + { + base.Clear(); + Transaction = null; + assignedPreviousFlushMode = false; + Connection = null; + } } diff --git a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/SimpleDelegatingSessionFactory.cs b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/SimpleDelegatingSessionFactory.cs index 364317d6..dcba9230 100644 --- a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/SimpleDelegatingSessionFactory.cs +++ b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/SimpleDelegatingSessionFactory.cs @@ -1,129 +1,124 @@ using System.Collections; - using NHibernate; using NHibernate.Cfg; using NhCfg = NHibernate.Cfg; - using Spring.Collections; using Spring.Threading; using Spring.Data.Common; using Spring.Context.Support; using NHibernate.Engine; -namespace Spring.Data.NHibernate +namespace Spring.Data.NHibernate; + +/// +/// SimpleDelegatingSessionFactory class +/// +public class SimpleDelegatingSessionFactory : DelegatingSessionFactory { /// - /// SimpleDelegatingSessionFactory class + /// Connection string config element name /// - public class SimpleDelegatingSessionFactory : DelegatingSessionFactory + public const string CONNECTION_STRING = "SimpleDelegatingSessionFactory.ConnectionString"; + + /// + /// Cache region prefix config element name + /// + public const string CACHE_REGION_PREFIX_STRING = "SimpleDelegatingSessionFactory.CacheRegionPrefix"; + + private Configuration _configuration; + + private string _defaultConnectionString; + + private object _monitor = new object(); + + private IDictionary _targetSessionFactories = new SynchronizedHashtable(); + + /// + /// public Constructor + /// + /// + public SimpleDelegatingSessionFactory(Configuration defaultConfiguration) { - /// - /// Connection string config element name - /// - public const string CONNECTION_STRING = "SimpleDelegatingSessionFactory.ConnectionString"; - - /// - /// Cache region prefix config element name - /// - public const string CACHE_REGION_PREFIX_STRING = "SimpleDelegatingSessionFactory.CacheRegionPrefix"; - - private Configuration _configuration; - - private string _defaultConnectionString; - - private object _monitor = new object(); - - private IDictionary _targetSessionFactories = new SynchronizedHashtable(); - - /// - /// public Constructor - /// - /// - public SimpleDelegatingSessionFactory(Configuration defaultConfiguration) + if (defaultConfiguration == null) { - if (defaultConfiguration == null) - { - throw new ArgumentException("Configuration cannot be null", "defaultConfiguration"); - } - - _configuration = defaultConfiguration; - if (!_configuration.Properties.ContainsKey(NhCfg.Environment.ConnectionString)) - { - throw new ArgumentException("Must specify connection string"); - } - - _defaultConnectionString = _configuration.Properties[NhCfg.Environment.ConnectionString] as string; - if (_defaultConnectionString == null) - { - throw new ArgumentException("Connection string property must be of type string, not " + - _configuration.Properties[NhCfg.Environment.ConnectionString].GetType().FullName); - } + throw new ArgumentException("Configuration cannot be null", "defaultConfiguration"); } - /// - /// TargetSessionFactory - /// - public override ISessionFactory TargetSessionFactory + _configuration = defaultConfiguration; + if (!_configuration.Properties.ContainsKey(NhCfg.Environment.ConnectionString)) { - get + throw new ArgumentException("Must specify connection string"); + } + + _defaultConnectionString = _configuration.Properties[NhCfg.Environment.ConnectionString] as string; + if (_defaultConnectionString == null) + { + throw new ArgumentException("Connection string property must be of type string, not " + + _configuration.Properties[NhCfg.Environment.ConnectionString].GetType().FullName); + } + } + + /// + /// TargetSessionFactory + /// + public override ISessionFactory TargetSessionFactory + { + get + { + string connectionString = LogicalThreadContext.GetData(CONNECTION_STRING) as string; + + System.Diagnostics.Trace.WriteLine(String.Format("{0} = {1}", System.Threading.Thread.CurrentThread.GetHashCode(), connectionString)); + + if (connectionString == null) { - string connectionString = LogicalThreadContext.GetData(CONNECTION_STRING) as string; + connectionString = _defaultConnectionString; + } - System.Diagnostics.Trace.WriteLine(String.Format("{0} = {1}", System.Threading.Thread.CurrentThread.GetHashCode(), connectionString)); - - if (connectionString == null) + lock (_monitor) + { + if (!_targetSessionFactories.Contains(connectionString)) { - connectionString = _defaultConnectionString; - } + System.Diagnostics.Trace.WriteLine(System.Threading.Thread.CurrentThread.GetHashCode().ToString() + " = (created) "); - lock (_monitor) - { - if (!_targetSessionFactories.Contains(connectionString)) + string originalPrefix = string.Empty; + + if (_configuration.Properties.ContainsKey(NhCfg.Environment.CacheRegionPrefix)) { - System.Diagnostics.Trace.WriteLine(System.Threading.Thread.CurrentThread.GetHashCode().ToString() + " = (created) "); - - string originalPrefix = string.Empty; - - if (_configuration.Properties.ContainsKey(NhCfg.Environment.CacheRegionPrefix)) - { - originalPrefix = _configuration.Properties[NhCfg.Environment.CacheRegionPrefix]; - } - - string cacheRegionPrefix = LogicalThreadContext.GetData(CACHE_REGION_PREFIX_STRING) as string; - - if (!string.IsNullOrEmpty(cacheRegionPrefix)) - { - _configuration.Properties[NhCfg.Environment.CacheRegionPrefix] = originalPrefix + cacheRegionPrefix; - System.Diagnostics.Trace.WriteLine(String.Format("{0} = (cache region prefix) {1}", System.Threading.Thread.CurrentThread.GetHashCode(), cacheRegionPrefix)); - - } - - _configuration.Properties[NhCfg.Environment.ConnectionString] = connectionString; - ISessionFactory sessionFactory = _configuration.BuildSessionFactory(); - - LocalSessionFactoryObject.DbProviderWrapper dbProviderWrapper = ((ISessionFactoryImplementor)sessionFactory).ConnectionProvider as LocalSessionFactoryObject.DbProviderWrapper; - if (dbProviderWrapper != null) - { - dbProviderWrapper.DbProvider = (IDbProvider)ContextRegistry.GetContext().GetObject("DbProvider"); - } - - //Reset the Cache Region Prefix to the original value - // This is so other cache region prefixes are not appended together. - _configuration.Properties[NhCfg.Environment.CacheRegionPrefix] = originalPrefix; - - _targetSessionFactories[connectionString] = sessionFactory; + originalPrefix = _configuration.Properties[NhCfg.Environment.CacheRegionPrefix]; } - else - System.Diagnostics.Trace.WriteLine(System.Threading.Thread.CurrentThread.GetHashCode().ToString() + " = (cached) "); - ISessionFactory factory = _targetSessionFactories[connectionString] as ISessionFactory; + string cacheRegionPrefix = LogicalThreadContext.GetData(CACHE_REGION_PREFIX_STRING) as string; - System.Diagnostics.Trace.WriteLine(String.Format("{0} = {1}", System.Threading.Thread.CurrentThread.GetHashCode(), connectionString)); + if (!string.IsNullOrEmpty(cacheRegionPrefix)) + { + _configuration.Properties[NhCfg.Environment.CacheRegionPrefix] = originalPrefix + cacheRegionPrefix; + System.Diagnostics.Trace.WriteLine(String.Format("{0} = (cache region prefix) {1}", System.Threading.Thread.CurrentThread.GetHashCode(), cacheRegionPrefix)); + } - return factory; + _configuration.Properties[NhCfg.Environment.ConnectionString] = connectionString; + ISessionFactory sessionFactory = _configuration.BuildSessionFactory(); + + LocalSessionFactoryObject.DbProviderWrapper dbProviderWrapper = ((ISessionFactoryImplementor) sessionFactory).ConnectionProvider as LocalSessionFactoryObject.DbProviderWrapper; + if (dbProviderWrapper != null) + { + dbProviderWrapper.DbProvider = (IDbProvider) ContextRegistry.GetContext().GetObject("DbProvider"); + } + + //Reset the Cache Region Prefix to the original value + // This is so other cache region prefixes are not appended together. + _configuration.Properties[NhCfg.Environment.CacheRegionPrefix] = originalPrefix; + + _targetSessionFactories[connectionString] = sessionFactory; } + else + System.Diagnostics.Trace.WriteLine(System.Threading.Thread.CurrentThread.GetHashCode().ToString() + " = (cached) "); + + ISessionFactory factory = _targetSessionFactories[connectionString] as ISessionFactory; + + System.Diagnostics.Trace.WriteLine(String.Format("{0} = {1}", System.Threading.Thread.CurrentThread.GetHashCode(), connectionString)); + + return factory; } } - } } diff --git a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/SpringSessionContext.cs b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/SpringSessionContext.cs index 7c96ad3b..b3cf7827 100644 --- a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/SpringSessionContext.cs +++ b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/SpringSessionContext.cs @@ -1,12 +1,12 @@ /* * Copyright � 2002-2011 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. @@ -18,50 +18,49 @@ using NHibernate; using NHibernate.Context; using NHibernate.Engine; -namespace Spring.Data.NHibernate +namespace Spring.Data.NHibernate; + +/// +/// Implementation of NHibernates 1.2's ICurrentSessionContext interface +/// that delegates to Spring's SessionFactoryUtils for providing a +/// Spirng-managed current Session. +/// +/// Used by Spring's LocalSessionFactoryBean if told to expose +/// a transaction-aware SessionFactory. +///

This ICurrentSessionContext implementation can also be specified in +/// custom ISessionFactory setup through the +/// "hibernate.current_session_context_class" property, with the fully +/// qualified name of this class as value.

+/// Juergen Hoeller +/// Mark Pollack (.NET) +/// +public class SpringSessionContext : ICurrentSessionContext { + private readonly ISessionFactoryImplementor sessionFactory; + /// - /// Implementation of NHibernates 1.2's ICurrentSessionContext interface - /// that delegates to Spring's SessionFactoryUtils for providing a - /// Spirng-managed current Session. + /// Initializes a new instance of the class /// - /// Used by Spring's LocalSessionFactoryBean if told to expose - /// a transaction-aware SessionFactory. - ///

This ICurrentSessionContext implementation can also be specified in - /// custom ISessionFactory setup through the - /// "hibernate.current_session_context_class" property, with the fully - /// qualified name of this class as value.

- /// Juergen Hoeller - /// Mark Pollack (.NET) - /// - public class SpringSessionContext : ICurrentSessionContext + /// The NHibernate session factory. + public SpringSessionContext(ISessionFactoryImplementor sessionFactory) { - private readonly ISessionFactoryImplementor sessionFactory; + this.sessionFactory = sessionFactory; + } - /// - /// Initializes a new instance of the class - /// - /// The NHibernate session factory. - public SpringSessionContext(ISessionFactoryImplementor sessionFactory) + /// + /// Retrieve the Spring-managed Session for the current thread. + /// + /// Current session associated with the thread + /// On errors retrieving thread bound session. + public ISession CurrentSession() + { + try { - this.sessionFactory = sessionFactory; + return SessionFactoryUtils.DoGetSession(sessionFactory, false); } - - /// - /// Retrieve the Spring-managed Session for the current thread. - /// - /// Current session associated with the thread - /// On errors retrieving thread bound session. - public ISession CurrentSession() + catch (InvalidOperationException ex) { - try - { - return SessionFactoryUtils.DoGetSession(sessionFactory, false); - } - catch (InvalidOperationException ex) - { - throw new HibernateException(ex.Message); - } + throw new HibernateException(ex.Message); } } } diff --git a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/SpringSessionSynchronization.cs b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/SpringSessionSynchronization.cs index 9f877a07..33436913 100644 --- a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/SpringSessionSynchronization.cs +++ b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/SpringSessionSynchronization.cs @@ -1,12 +1,12 @@ /* * Copyright © 2002-2011 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. @@ -21,230 +21,229 @@ using Spring.Core; using Spring.Data.Support; using Spring.Transaction.Support; -namespace Spring.Data.NHibernate +namespace Spring.Data.NHibernate; + +/// +/// NHibnerations actions taken during the transaction lifecycle. +/// +/// Mark Pollack (.NET) +public class SpringSessionSynchronization : TransactionSynchronizationAdapter, IOrdered { /// - /// NHibnerations actions taken during the transaction lifecycle. + /// The instance for this class. /// - /// Mark Pollack (.NET) - public class SpringSessionSynchronization : TransactionSynchronizationAdapter, IOrdered + private readonly ILogger log = LogManager.GetLogger(); + + private readonly SessionHolder sessionHolder; + + private readonly ISessionFactory sessionFactory; + + private readonly IAdoExceptionTranslator adoExceptionTranslator; + + private readonly bool newSession; + + private bool holderActive = true; + + /// + /// Initializes a new instance of the class. + /// + public SpringSessionSynchronization(SessionHolder sessionHolder, ISessionFactory sessionFactory, + IAdoExceptionTranslator adoExceptionTranslator, bool newSession) { - /// - /// The instance for this class. - /// - private readonly ILogger log = LogManager.GetLogger(); + this.sessionHolder = sessionHolder; + this.sessionFactory = sessionFactory; + this.adoExceptionTranslator = adoExceptionTranslator; + this.newSession = newSession; + } - private readonly SessionHolder sessionHolder; + /// + /// Return the order value of this object, where a higher value means greater in + /// terms of sorting. + /// + /// + ///

+ /// Normally starting with 0 or 1, with indicating + /// greatest. Same order values will result in arbitrary positions for the affected + /// objects. + ///

+ ///

+ /// Higher value can be interpreted as lower priority, consequently the first object + /// has highest priority. + ///

+ ///
+ /// The order value. + public int Order + { + get { return SessionFactoryUtils.SESSION_SYNCHRONIZATION_ORDER; } + } - private readonly ISessionFactory sessionFactory; - - private readonly IAdoExceptionTranslator adoExceptionTranslator; - - private readonly bool newSession; - - private bool holderActive = true; - - /// - /// Initializes a new instance of the class. - /// - public SpringSessionSynchronization(SessionHolder sessionHolder, ISessionFactory sessionFactory, - IAdoExceptionTranslator adoExceptionTranslator, bool newSession) + /// + /// Suspend this synchronization. + /// + /// + ///

+ /// Unbind Hibernate resources (SessionHolder) from + /// + /// if managing any. + ///

+ ///
+ public override void Suspend() + { + if (this.holderActive) { - this.sessionHolder = sessionHolder; - this.sessionFactory = sessionFactory; - this.adoExceptionTranslator = adoExceptionTranslator; - this.newSession = newSession; + TransactionSynchronizationManager.UnbindResource(this.sessionFactory); } + } - /// - /// Return the order value of this object, where a higher value means greater in - /// terms of sorting. - /// - /// - ///

- /// Normally starting with 0 or 1, with indicating - /// greatest. Same order values will result in arbitrary positions for the affected - /// objects. - ///

- ///

- /// Higher value can be interpreted as lower priority, consequently the first object - /// has highest priority. - ///

- ///
- /// The order value. - public int Order + /// + /// Resume this synchronization. + /// + /// + ///

+ /// Rebind Hibernate resources from + /// + /// if managing any. + ///

+ ///
+ public override void Resume() + { + if (this.holderActive) { - get { return SessionFactoryUtils.SESSION_SYNCHRONIZATION_ORDER; } + TransactionSynchronizationManager.BindResource(this.sessionFactory, this.sessionHolder); } + } - /// - /// Suspend this synchronization. - /// - /// - ///

- /// Unbind Hibernate resources (SessionHolder) from - /// - /// if managing any. - ///

- ///
- public override void Suspend() + /// + /// Invoked before transaction commit (before + /// ) + /// + /// + /// If the transaction is defined as a read-only transaction. + /// + /// + ///

+ /// Can flush transactional sessions to the database. + ///

+ ///

+ /// Note that exceptions will get propagated to the commit caller and + /// cause a rollback of the transaction. + ///

+ ///
+ public override void BeforeCommit(bool readOnly) + { + if (!readOnly) { - if (this.holderActive) + // read-write transaction -> flush the Hibernate Session + log.LogDebug("Flushing Hibernate Session on transaction synchronization"); + ISession session = this.sessionHolder.Session; + //Further check: only flush when not FlushMode.NEVER + if (session.FlushMode != FlushMode.Never) { - TransactionSynchronizationManager.UnbindResource(this.sessionFactory); - } - } - - /// - /// Resume this synchronization. - /// - /// - ///

- /// Rebind Hibernate resources from - /// - /// if managing any. - ///

- ///
- public override void Resume() - { - if (this.holderActive) - { - TransactionSynchronizationManager.BindResource(this.sessionFactory, this.sessionHolder); - } - } - - /// - /// Invoked before transaction commit (before - /// ) - /// - /// - /// If the transaction is defined as a read-only transaction. - /// - /// - ///

- /// Can flush transactional sessions to the database. - ///

- ///

- /// Note that exceptions will get propagated to the commit caller and - /// cause a rollback of the transaction. - ///

- ///
- public override void BeforeCommit(bool readOnly) - { - if (!readOnly) - { - // read-write transaction -> flush the Hibernate Session - log.LogDebug("Flushing Hibernate Session on transaction synchronization"); - ISession session = this.sessionHolder.Session; - //Further check: only flush when not FlushMode.NEVER - if (session.FlushMode != FlushMode.Never) + try { - try + session.Flush(); + //TODO can throw System.ObjectDisposedException... + } + catch (ADOException ex) + { + if (this.adoExceptionTranslator != null) { - session.Flush(); - //TODO can throw System.ObjectDisposedException... + //TODO investigate how ADOException wraps inner exception. + throw this.adoExceptionTranslator.Translate( + "Hibernate transaction synchronization: " + ex.Message, null, ex.InnerException); } - catch (ADOException ex) + else { - if (this.adoExceptionTranslator != null) - { - //TODO investigate how ADOException wraps inner exception. - throw this.adoExceptionTranslator.Translate( - "Hibernate transaction synchronization: " + ex.Message, null, ex.InnerException); - } - else - { - throw new HibernateAdoException("ADO.NET Exception", ex); - } - } - catch (HibernateException ex) - { - throw SessionFactoryUtils.ConvertHibernateAccessException(ex); + throw new HibernateAdoException("ADO.NET Exception", ex); } } - } - } - - /// - /// Invoked before transaction commit (before - /// ) - /// Can e.g. flush transactional O/R Mapping sessions to the database - /// - /// - /// - /// This callback does not mean that the transaction will actually be - /// commited. A rollback decision can still occur after this method - /// has been called. This callback is rather meant to perform work - /// that's only relevant if a commit still has a chance - /// to happen, such as flushing SQL statements to the database. - /// - /// - /// Note that exceptions will get propagated to the commit caller and cause a - /// rollback of the transaction. - /// - /// (note: do not throw TransactionException subclasses here!) - /// - /// - public override void BeforeCompletion() - { - if (this.newSession) - { - // Default behavior: unbind and close the thread-bound Hibernate Session. - TransactionSynchronizationManager.UnbindResource(this.sessionFactory); - this.holderActive = false; - } - else if (this.sessionHolder.AssignedPreviousFlushMode == true) - { - // In case of pre-bound Session, restore previous flush mode. - this.sessionHolder.Session.FlushMode = (this.sessionHolder.PreviousFlushMode); - } - } - - /// - /// Invoked after transaction commit/rollback. - /// - /// - /// Status according to - /// - /// - /// Can e.g. perform resource cleanup, in this case after transaction completion. - ///

- /// Note that exceptions will get propagated to the commit or rollback - /// caller, although they will not influence the outcome of the transaction. - ///

- ///
- public override void AfterCompletion(TransactionSynchronizationStatus status) - { - if (!newSession) - { - ISession session = sessionHolder.Session; - - // Provide correct transaction status for releasing the Session's cache locks, - // if possible. Else, closing will release all cache locks assuming a rollback. - ISessionImplementor sessionImplementor = session as ISessionImplementor; - if (sessionImplementor != null) + catch (HibernateException ex) { - sessionImplementor.AfterTransactionCompletion(status == TransactionSynchronizationStatus.Committed, - sessionHolder.Transaction); + throw SessionFactoryUtils.ConvertHibernateAccessException(ex); } - - if (newSession) - { - SessionFactoryUtils.CloseSessionOrRegisterDeferredClose(session, sessionFactory); - } - } - - if (!newSession && status != TransactionSynchronizationStatus.Committed) - { - // Clear all pending inserts/updates/deletes in the Session. - // Necessary for pre-bound Sessions, to avoid inconsistent state. - sessionHolder.Session.Clear(); - } - - if (this.sessionHolder.DoesNotHoldNonDefaultSession) - { - sessionHolder.SynchronizedWithTransaction = false; } } } + + /// + /// Invoked before transaction commit (before + /// ) + /// Can e.g. flush transactional O/R Mapping sessions to the database + /// + /// + /// + /// This callback does not mean that the transaction will actually be + /// commited. A rollback decision can still occur after this method + /// has been called. This callback is rather meant to perform work + /// that's only relevant if a commit still has a chance + /// to happen, such as flushing SQL statements to the database. + /// + /// + /// Note that exceptions will get propagated to the commit caller and cause a + /// rollback of the transaction. + /// + /// (note: do not throw TransactionException subclasses here!) + /// + /// + public override void BeforeCompletion() + { + if (this.newSession) + { + // Default behavior: unbind and close the thread-bound Hibernate Session. + TransactionSynchronizationManager.UnbindResource(this.sessionFactory); + this.holderActive = false; + } + else if (this.sessionHolder.AssignedPreviousFlushMode == true) + { + // In case of pre-bound Session, restore previous flush mode. + this.sessionHolder.Session.FlushMode = (this.sessionHolder.PreviousFlushMode); + } + } + + /// + /// Invoked after transaction commit/rollback. + /// + /// + /// Status according to + /// + /// + /// Can e.g. perform resource cleanup, in this case after transaction completion. + ///

+ /// Note that exceptions will get propagated to the commit or rollback + /// caller, although they will not influence the outcome of the transaction. + ///

+ ///
+ public override void AfterCompletion(TransactionSynchronizationStatus status) + { + if (!newSession) + { + ISession session = sessionHolder.Session; + + // Provide correct transaction status for releasing the Session's cache locks, + // if possible. Else, closing will release all cache locks assuming a rollback. + ISessionImplementor sessionImplementor = session as ISessionImplementor; + if (sessionImplementor != null) + { + sessionImplementor.AfterTransactionCompletion(status == TransactionSynchronizationStatus.Committed, + sessionHolder.Transaction); + } + + if (newSession) + { + SessionFactoryUtils.CloseSessionOrRegisterDeferredClose(session, sessionFactory); + } + } + + if (!newSession && status != TransactionSynchronizationStatus.Committed) + { + // Clear all pending inserts/updates/deletes in the Session. + // Necessary for pre-bound Sessions, to avoid inconsistent state. + sessionHolder.Session.Clear(); + } + + if (this.sessionHolder.DoesNotHoldNonDefaultSession) + { + sessionHolder.SynchronizedWithTransaction = false; + } + } } diff --git a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Support/ConfigSectionSessionScopeSettings.cs b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Support/ConfigSectionSessionScopeSettings.cs index 6a979ca8..d16066c7 100644 --- a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Support/ConfigSectionSessionScopeSettings.cs +++ b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Support/ConfigSectionSessionScopeSettings.cs @@ -1,12 +1,12 @@ /* * Copyright © 2002-2011 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. @@ -20,93 +20,94 @@ using Spring.Context.Support; using Spring.Objects.Factory.Config; using Spring.Util; -namespace Spring.Data.NHibernate.Support +namespace Spring.Data.NHibernate.Support; + +/// +/// Holds the references and configuration settings for a instance. +/// References are resolved by looking up the given object names in the root obtained by . +/// +public class ConfigSectionSessionScopeSettings + : SessionScopeSettings { /// - /// Holds the references and configuration settings for a instance. - /// References are resolved by looking up the given object names in the root obtained by . + /// The default session factory name to use when retrieving the Hibernate session factory from + /// the root context. /// - public class ConfigSectionSessionScopeSettings - : SessionScopeSettings + public static readonly string DEFAULT_SESSION_FACTORY_OBJECT_NAME = "SessionFactory"; + + private readonly string sessionFactoryObjectName = DEFAULT_SESSION_FACTORY_OBJECT_NAME; + private readonly string entityInterceptorObjectName = null; + + /// + /// Initializes a new instance. + /// + /// The type, who's name will be used to prefix setting variables with + public ConfigSectionSessionScopeSettings(Type ownerType) + : this(ownerType, "appSettings") { - /// - /// The default session factory name to use when retrieving the Hibernate session factory from - /// the root context. - /// - public static readonly string DEFAULT_SESSION_FACTORY_OBJECT_NAME = "SessionFactory"; + // noop + } - private readonly string sessionFactoryObjectName = DEFAULT_SESSION_FACTORY_OBJECT_NAME; - private readonly string entityInterceptorObjectName = null; + /// + /// Initializes a new instance. + /// + /// The type, who's name will be used to prefix setting variables with + /// The configuration section to read setting variables from. + public ConfigSectionSessionScopeSettings(Type ownerType, string sectionName) + : this(ownerType, new ConfigSectionVariableSource(sectionName)) + { + // noop + } - /// - /// Initializes a new instance. - /// - /// The type, who's name will be used to prefix setting variables with - public ConfigSectionSessionScopeSettings(Type ownerType) - : this(ownerType, "appSettings") + /// + /// Initializes a new instance. + /// + /// The type, who's name will be used to prefix setting variables with + /// The variable source to obtain settings from. + public ConfigSectionSessionScopeSettings(Type ownerType, IVariableSource variableSource) + : base() + { + string sessionFactoryObjectNameSettingsKey = UniqueKey.GetTypeScopedString(ownerType, "SessionFactoryObjectName"); + string entityInterceptorObjectNameSettingsKey = UniqueKey.GetTypeScopedString(ownerType, "EntityInterceptorObjectName"); + string singleSessionSettingsKey = UniqueKey.GetTypeScopedString(ownerType, "SingleSession"); + string defaultFlushModeSettingsKey = UniqueKey.GetTypeScopedString(ownerType, "DefaultFlushMode"); + + VariableAccessor variables = new VariableAccessor(variableSource); + this.sessionFactoryObjectName = variables.GetString(sessionFactoryObjectNameSettingsKey, DEFAULT_SESSION_FACTORY_OBJECT_NAME); + this.entityInterceptorObjectName = variables.GetString(entityInterceptorObjectNameSettingsKey, null); + this.SingleSession = variables.GetBoolean(singleSessionSettingsKey, this.SingleSession); + this.DefaultFlushMode = (FlushMode) variables.GetEnum(defaultFlushModeSettingsKey, this.DefaultFlushMode); + + AssertUtils.ArgumentNotNull(sessionFactoryObjectName, "sessionFactoryObjectName"); // just to be sure + } + + /// + /// Resolve the entityInterceptor by looking up + /// in the root application context. + /// + /// The resolved instance or + protected override IInterceptor ResolveEntityInterceptor() + { + if (StringUtils.HasText(entityInterceptorObjectName)) { - // noop + return (IInterceptor) ContextRegistry.GetContext().GetObject(entityInterceptorObjectName); } - /// - /// Initializes a new instance. - /// - /// The type, who's name will be used to prefix setting variables with - /// The configuration section to read setting variables from. - public ConfigSectionSessionScopeSettings(Type ownerType, string sectionName) - : this(ownerType, new ConfigSectionVariableSource(sectionName)) + return null; + } + + /// + /// Resolve the by looking up + /// in the root application context. + /// + /// The resolved instance or + protected override ISessionFactory ResolveSessionFactory() + { + if (StringUtils.HasText(sessionFactoryObjectName)) { - // noop + return (ISessionFactory) ContextRegistry.GetContext().GetObject(sessionFactoryObjectName); } - /// - /// Initializes a new instance. - /// - /// The type, who's name will be used to prefix setting variables with - /// The variable source to obtain settings from. - public ConfigSectionSessionScopeSettings(Type ownerType, IVariableSource variableSource) - : base() - { - string sessionFactoryObjectNameSettingsKey = UniqueKey.GetTypeScopedString(ownerType, "SessionFactoryObjectName"); - string entityInterceptorObjectNameSettingsKey = UniqueKey.GetTypeScopedString(ownerType, "EntityInterceptorObjectName"); - string singleSessionSettingsKey = UniqueKey.GetTypeScopedString(ownerType, "SingleSession"); - string defaultFlushModeSettingsKey = UniqueKey.GetTypeScopedString(ownerType, "DefaultFlushMode"); - - VariableAccessor variables = new VariableAccessor(variableSource); - this.sessionFactoryObjectName = variables.GetString(sessionFactoryObjectNameSettingsKey, DEFAULT_SESSION_FACTORY_OBJECT_NAME); - this.entityInterceptorObjectName = variables.GetString(entityInterceptorObjectNameSettingsKey, null); - this.SingleSession = variables.GetBoolean(singleSessionSettingsKey, this.SingleSession); - this.DefaultFlushMode = (FlushMode)variables.GetEnum(defaultFlushModeSettingsKey, this.DefaultFlushMode); - - AssertUtils.ArgumentNotNull(sessionFactoryObjectName, "sessionFactoryObjectName"); // just to be sure - } - - /// - /// Resolve the entityInterceptor by looking up - /// in the root application context. - /// - /// The resolved instance or - protected override IInterceptor ResolveEntityInterceptor() - { - if (StringUtils.HasText(entityInterceptorObjectName)) - { - return (IInterceptor)ContextRegistry.GetContext().GetObject(entityInterceptorObjectName); - } - return null; - } - - /// - /// Resolve the by looking up - /// in the root application context. - /// - /// The resolved instance or - protected override ISessionFactory ResolveSessionFactory() - { - if (StringUtils.HasText(sessionFactoryObjectName)) - { - return (ISessionFactory)ContextRegistry.GetContext().GetObject(sessionFactoryObjectName); - } - return null; - } + return null; } } diff --git a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Support/HibernateDaoSupport.cs b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Support/HibernateDaoSupport.cs index 75d3a56b..282e67be 100644 --- a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Support/HibernateDaoSupport.cs +++ b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Support/HibernateDaoSupport.cs @@ -1,12 +1,12 @@ /* * Copyright � 2002-2011 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. @@ -18,190 +18,188 @@ using NHibernate; using Spring.Dao; using Spring.Dao.Support; -namespace Spring.Data.NHibernate.Support +namespace Spring.Data.NHibernate.Support; + +/// +/// Convenient super class for Hibernate data access objects. +/// +/// +/// Requires a SessionFactory to be set, providing a HibernateTemplate +/// based on it to subclasses. Can alternatively be initialized directly with +/// a HibernateTemplate, to reuse the latter's settings such as the SessionFactory, +/// exception translator, flush mode, etc +/// +/// This base call is mainly intended for HibernateTemplate usage. +/// +/// This class will create its own HibernateTemplate if only a SessionFactory +/// is passed in. The "allowCreate" flag on that HibernateTemplate will be "true" +/// by default. A custom HibernateTemplate instance can be used through overriding +/// CreateHibernateTemplate. +/// +/// +/// Mark Pollack (.NET) +public abstract class HibernateDaoSupport : DaoSupport { - /// - /// Convenient super class for Hibernate data access objects. - /// - /// - /// Requires a SessionFactory to be set, providing a HibernateTemplate - /// based on it to subclasses. Can alternatively be initialized directly with - /// a HibernateTemplate, to reuse the latter's settings such as the SessionFactory, - /// exception translator, flush mode, etc - /// - /// This base call is mainly intended for HibernateTemplate usage. + private HibernateTemplate hibernateTemplate; + + /// + /// Initializes a new instance of the class. + /// + public HibernateDaoSupport() + { + } + + /// + /// Gets or sets the hibernate template. + /// + /// Set the HibernateTemplate for this DAO explicitly, + /// as an alternative to specifying a SessionFactory. + /// + /// The hibernate template. + public HibernateTemplate HibernateTemplate + { + get + { + return hibernateTemplate; + } + set + { + hibernateTemplate = value; + } + } + + /// + /// Gets or sets the session factory to be used by this DAO. + /// Will automatically create a HibernateTemplate for the given SessionFactory. + /// + /// The session factory. + public ISessionFactory SessionFactory + { + get + { + return (this.hibernateTemplate != null ? this.hibernateTemplate.SessionFactory : null); + } + set + { + hibernateTemplate = CreateHibernateTemplate(value); + } + } + + /// + /// Get a Hibernate Session, either from the current transaction or a new one. + /// The latter is only allowed if the "allowCreate" setting of this object's + /// HibernateTemplate is true. + /// + /// + ///

Note that this is not meant to be invoked from HibernateTemplate code + /// but rather just in plain Hibernate code. Use it in combination with + /// ReleaseSession. + ///

+ ///

In general, it is recommended to use HibernateTemplate, either with + /// the provided convenience operations or with a custom HibernateCallback + /// that provides you with a Session to work on. HibernateTemplate will care + /// for all resource management and for proper exception conversion. + ///

+ ///
+ /// The Hibernate session. + public ISession Session + { + get + { + return DoGetSession(HibernateTemplate.AllowCreate); + } + } + + /// + /// Create a HibernateTemplate for the given ISessionFactory. + /// + /// + /// Only invoked if populating the DAO with a ISessionFactory reference! + ///

Can be overridden in subclasses to provide a HibernateTemplate instance + /// with different configuration, or a custom HibernateTemplate subclass. + ///

+ ///
+ protected virtual HibernateTemplate CreateHibernateTemplate(ISessionFactory sessionFactory) + { + return new HibernateTemplate(sessionFactory); + } + + /// + /// Check if the hibernate template property has been set. + /// + protected override void CheckDaoConfig() + { + if (this.hibernateTemplate == null) + { + throw new ArgumentException("sessionFactory or hibernateTemplate is required"); + } + } + + /// + /// Get a Hibernate Session, either from the current transaction or + /// a new one. The latter is only allowed if "allowCreate" is true. + /// + /// Note that this is not meant to be invoked from HibernateTemplate code + /// but rather just in plain Hibernate code. Either rely on a thread-bound + /// Session (via HibernateInterceptor), or use it in combination with + /// ReleaseSession. /// - /// This class will create its own HibernateTemplate if only a SessionFactory - /// is passed in. The "allowCreate" flag on that HibernateTemplate will be "true" - /// by default. A custom HibernateTemplate instance can be used through overriding - /// CreateHibernateTemplate. + /// In general, it is recommended to use HibernateTemplate, either with + /// the provided convenience operations or with a custom HibernateCallback + /// that provides you with a Session to work on. HibernateTemplate will care + /// for all resource management and for proper exception conversion. /// - /// - /// Mark Pollack (.NET) - public abstract class HibernateDaoSupport : DaoSupport - { - private HibernateTemplate hibernateTemplate; + ///
+ /// if a non-transactional Session should be created when no + /// transactional Session can be found for the current thread + /// + /// Hibernate session. + /// + /// If the Session couldn't be created + /// + /// + /// if no thread-bound Session found and allowCreate false + /// + /// + protected ISession DoGetSession(bool allowCreate) + { + return (!allowCreate + ? SessionFactoryUtils.GetSession(SessionFactory, false) + : SessionFactoryUtils.GetSession( + SessionFactory, + this.hibernateTemplate.EntityInterceptor, + this.hibernateTemplate.AdoExceptionTranslator)); + } - /// - /// Initializes a new instance of the class. - /// - public HibernateDaoSupport() - { + /// + /// Convert the given HibernateException to an appropriate exception from the + /// org.springframework.dao hierarchy. Will automatically detect + /// wrapped ADO.NET Exceptions and convert them accordingly. + /// + /// HibernateException that occured. + /// + /// The corresponding DataAccessException instance + /// + /// + /// The default implementation delegates to SessionFactoryUtils + /// and convertAdoAccessException. Can be overridden in subclasses. + /// + protected DataAccessException ConvertHibernateAccessException(HibernateException ex) + { + return hibernateTemplate.ConvertHibernateAccessException(ex); + } - } - - /// - /// Gets or sets the hibernate template. - /// - /// Set the HibernateTemplate for this DAO explicitly, - /// as an alternative to specifying a SessionFactory. - /// - /// The hibernate template. - public HibernateTemplate HibernateTemplate - { - get - { - return hibernateTemplate; - } - set - { - hibernateTemplate = value; - } - } - - /// - /// Gets or sets the session factory to be used by this DAO. - /// Will automatically create a HibernateTemplate for the given SessionFactory. - /// - /// The session factory. - public ISessionFactory SessionFactory - { - get - { - return (this.hibernateTemplate != null ? this.hibernateTemplate.SessionFactory : null); - } - set - { - hibernateTemplate = CreateHibernateTemplate(value); - } - } - - /// - /// Get a Hibernate Session, either from the current transaction or a new one. - /// The latter is only allowed if the "allowCreate" setting of this object's - /// HibernateTemplate is true. - /// - /// - ///

Note that this is not meant to be invoked from HibernateTemplate code - /// but rather just in plain Hibernate code. Use it in combination with - /// ReleaseSession. - ///

- ///

In general, it is recommended to use HibernateTemplate, either with - /// the provided convenience operations or with a custom HibernateCallback - /// that provides you with a Session to work on. HibernateTemplate will care - /// for all resource management and for proper exception conversion. - ///

- ///
- /// The Hibernate session. - public ISession Session - { - get - { - return DoGetSession(HibernateTemplate.AllowCreate); - } - } - - /// - /// Create a HibernateTemplate for the given ISessionFactory. - /// - /// - /// Only invoked if populating the DAO with a ISessionFactory reference! - ///

Can be overridden in subclasses to provide a HibernateTemplate instance - /// with different configuration, or a custom HibernateTemplate subclass. - ///

- ///
- protected virtual HibernateTemplate CreateHibernateTemplate(ISessionFactory sessionFactory) - { - return new HibernateTemplate(sessionFactory); - } - - /// - /// Check if the hibernate template property has been set. - /// - protected override void CheckDaoConfig() - { - if (this.hibernateTemplate == null) - { - throw new ArgumentException("sessionFactory or hibernateTemplate is required"); - } - } - - /// - /// Get a Hibernate Session, either from the current transaction or - /// a new one. The latter is only allowed if "allowCreate" is true. - /// - /// Note that this is not meant to be invoked from HibernateTemplate code - /// but rather just in plain Hibernate code. Either rely on a thread-bound - /// Session (via HibernateInterceptor), or use it in combination with - /// ReleaseSession. - /// - /// In general, it is recommended to use HibernateTemplate, either with - /// the provided convenience operations or with a custom HibernateCallback - /// that provides you with a Session to work on. HibernateTemplate will care - /// for all resource management and for proper exception conversion. - /// - /// - /// if a non-transactional Session should be created when no - /// transactional Session can be found for the current thread - /// - /// Hibernate session. - /// - /// If the Session couldn't be created - /// - /// - /// if no thread-bound Session found and allowCreate false - /// - /// - protected ISession DoGetSession(bool allowCreate) - { - return (!allowCreate ? - SessionFactoryUtils.GetSession(SessionFactory, false) : - SessionFactoryUtils.GetSession( - SessionFactory, - this.hibernateTemplate.EntityInterceptor, - this.hibernateTemplate.AdoExceptionTranslator)); - } - - /// - /// Convert the given HibernateException to an appropriate exception from the - /// org.springframework.dao hierarchy. Will automatically detect - /// wrapped ADO.NET Exceptions and convert them accordingly. - /// - /// HibernateException that occured. - /// - /// The corresponding DataAccessException instance - /// - /// - /// The default implementation delegates to SessionFactoryUtils - /// and convertAdoAccessException. Can be overridden in subclasses. - /// - protected DataAccessException ConvertHibernateAccessException(HibernateException ex) - { - return hibernateTemplate.ConvertHibernateAccessException(ex); - } - - - /// - /// Close the given Hibernate Session, created via this DAO's SessionFactory, - /// if it isn't bound to the thread. - /// - /// - /// Typically used in plain Hibernate code, in combination with the - /// Session property and ConvertHibernateAccessException. - /// - /// The session to close. - protected void ReleaseSession(ISession session) { - SessionFactoryUtils.ReleaseSession(session, SessionFactory); - } - } + /// + /// Close the given Hibernate Session, created via this DAO's SessionFactory, + /// if it isn't bound to the thread. + /// + /// + /// Typically used in plain Hibernate code, in combination with the + /// Session property and ConvertHibernateAccessException. + /// + /// The session to close. + protected void ReleaseSession(ISession session) + { + SessionFactoryUtils.ReleaseSession(session, SessionFactory); + } } diff --git a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Support/OpenSessionInViewModule.cs b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Support/OpenSessionInViewModule.cs index 92861f58..937b1f8d 100644 --- a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Support/OpenSessionInViewModule.cs +++ b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Support/OpenSessionInViewModule.cs @@ -20,54 +20,53 @@ using System.Web; -namespace Spring.Data.NHibernate.Support +namespace Spring.Data.NHibernate.Support; + +/// +/// Provide support for the open session in view pattern for lazily loaded hibernate objects +/// used in ASP.NET pages. +/// +/// jjx: http://forum.springframework.net/member.php?u=29 +/// Mark Pollack (.NET) +/// Erich Eichinger +/// Harald Radi +public class OpenSessionInViewModule : SessionScope, IHttpModule { /// - /// Provide support for the open session in view pattern for lazily loaded hibernate objects - /// used in ASP.NET pages. + /// Initializes a new instance of the class. Creates a SessionScope, + /// but does not yet associate a session with a thread, that is left to the lifecycle of the request. /// - /// jjx: http://forum.springframework.net/member.php?u=29 - /// Mark Pollack (.NET) - /// Erich Eichinger - /// Harald Radi - public class OpenSessionInViewModule : SessionScope, IHttpModule + public OpenSessionInViewModule() : base("appSettings", typeof(OpenSessionInViewModule), false) { - /// - /// Initializes a new instance of the class. Creates a SessionScope, - /// but does not yet associate a session with a thread, that is left to the lifecycle of the request. - /// - public OpenSessionInViewModule() : base("appSettings", typeof(OpenSessionInViewModule), false) - { + } - } + /// + /// Register context handler and look up SessionFactoryObjectName under the application configuration key, + /// Spring.Data.NHibernate.Support.OpenSessionInViewModule.SessionFactoryObjectName if not using the default value + /// (i.e. sessionFactory) and look up the SingleSession setting under the application configuration key, + /// Spring.Data.NHibernate.Support.OpenSessionInViewModule.SingleSession if not using the default value of true. + /// + /// The standard HTTP application context + public void Init(HttpApplication context) + { + context.BeginRequest += context_BeginRequest; + context.EndRequest += context_EndRequest; + } - /// - /// Register context handler and look up SessionFactoryObjectName under the application configuration key, - /// Spring.Data.NHibernate.Support.OpenSessionInViewModule.SessionFactoryObjectName if not using the default value - /// (i.e. sessionFactory) and look up the SingleSession setting under the application configuration key, - /// Spring.Data.NHibernate.Support.OpenSessionInViewModule.SingleSession if not using the default value of true. - /// - /// The standard HTTP application context - public void Init( HttpApplication context ) - { - context.BeginRequest += context_BeginRequest; - context.EndRequest += context_EndRequest; - } - /// - /// A do nothing dispose method. - /// - public override void Dispose() - { - } + /// + /// A do nothing dispose method. + /// + public override void Dispose() + { + } - private void context_BeginRequest(object sender, EventArgs e) - { - Open(); - } + private void context_BeginRequest(object sender, EventArgs e) + { + Open(); + } - private void context_EndRequest(object sender, EventArgs e) - { - Close(); - } + private void context_EndRequest(object sender, EventArgs e) + { + Close(); } } diff --git a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Support/SessionScope.cs b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Support/SessionScope.cs index 462fbeef..6aa17821 100644 --- a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Support/SessionScope.cs +++ b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Support/SessionScope.cs @@ -1,12 +1,12 @@ /* * Copyright � 2002-2011 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. @@ -21,440 +21,438 @@ using Spring.Threading; using Spring.Transaction.Support; using Spring.Util; -namespace Spring.Data.NHibernate.Support +namespace Spring.Data.NHibernate.Support; + +/// +/// Implementation of SessionScope that associates a single session within the using scope. +/// +/// +/// It is recommended to be used in the following type of scenario: +/// +/// using (new SessionScope()) +/// { +/// ... do multiple operation, possibly in multiple transactions. +/// } +/// +/// At the end of "using", the session is automatically closed. All transactions within the scope use the same session, +/// if you are using Spring's HibernateTemplate or using Spring's implementation of NHibernate 1.2's +/// ICurrentSessionContext interface. +/// +/// +/// It is assumed that the session factory object name is called "SessionFactory". In case that you named the object +/// in different way you can specify your can specify it in the application settings using the key +/// Spring.Data.NHibernate.Support.SessionScope.SessionFactoryObjectName. Values for EntityInterceptorObjectName +/// and SingleSessionMode can be specified similarly. +/// +/// +/// Note: +/// The session is managed on a per thread basis on the thread that opens the scope instance. This means that you must +/// never pass a reference to a instance over to another thread! +/// +/// +/// Robert M. (.NET) +/// Harald Radi (.NET) +public class SessionScope : IDisposable { /// - /// Implementation of SessionScope that associates a single session within the using scope. + /// The logging instance. + /// + protected readonly ILogger log = LogManager.GetLogger(MethodInfo.GetCurrentMethod().DeclaringType); + + private readonly SessionScopeSettings settings; + + // Keys into LogicalThreadContext for runtime values. + private readonly string PARTICIPATE_KEY; + private readonly string ISOPEN_KEY; + + /// + /// Initializes a new instance of the class in single session mode, + /// associating a session with the thread. The session is opened lazily on demand. + /// + public SessionScope() + : this(true) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// If set to true associate a session with the thread. If false, another + /// collaborating class will associate the session with the thread, potentially by calling + /// the Open method on this class. + /// + public SessionScope(bool open) + : this("appSettings", open) + { + // noop + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The name of the configuration section to read configuration settings from. + /// See for more info. + /// + /// + /// If set to true associate a session with the thread. If false, another + /// collaborating class will associate the session with the thread, potentially by calling + /// the Open method on this class. + /// + public SessionScope(string sectionName, bool open) + : this(sectionName, typeof(SessionScope), open) + { + // noop + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The name of the configuration section to read configuration settings from. + /// See for more info. + /// + /// The type, who's full name is used for prefixing appSetting keys + /// + /// If set to true associate a session with the thread. If false, another + /// collaborating class will associate the session with the thread, potentially by calling + /// the Open method on this class. + /// + public SessionScope(string sectionName, Type namespaceType, bool open) + : this(new ConfigSectionSessionScopeSettings(namespaceType, sectionName), open) + { + // noop + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The instance to be used for obtaining instances. + /// + /// + /// If set to true associate a session with the thread. If false, another + /// collaborating class will associate the session with the thread, potentially by calling + /// the Open method on this class. + /// + public SessionScope(ISessionFactory sessionFactory, bool open) + : this(new SessionScopeSettings(sessionFactory), open) + { + // noop + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The instance to be used for obtaining instances. + /// + /// + /// Specify the to be set on each session provided by this instance. + /// + /// + /// Set whether to use a single session for each request. See property for details. + /// + /// + /// Specify the flushmode to be applied on each session provided by this instance. + /// + /// + /// If set to true associate a session with the thread. If false, another + /// collaborating class will associate the session with the thread, potentially by calling + /// the Open method on this class. + /// + public SessionScope(ISessionFactory sessionFactory, IInterceptor entityInterceptor, bool singleSession, FlushMode defaultFlushMode, bool open) + : this(new SessionScopeSettings(sessionFactory, entityInterceptor, singleSession, defaultFlushMode), open) + { + // noop + } + + /// + /// Initializes a new instance of the class. + /// + /// An instance holding the scope configuration + /// + /// If set to true associate a session with the thread. If false, another + /// collaborating class will associate the session with the thread, potentially by calling + /// the Open method on this class. + /// + public SessionScope(SessionScopeSettings settings, bool open) + { + log = LogManager.GetLogger(this.GetType()); + this.settings = settings; + + PARTICIPATE_KEY = UniqueKey.GetInstanceScopedString(this, "Participate"); + ISOPEN_KEY = UniqueKey.GetInstanceScopedString(this, "IsOpen"); + + if (open) + { + Open(); + } + } + + /// + /// Set whether to use a single session for each request. Default is "true". + /// If set to false, each data access operation or transaction will use + /// its own session (like without Open Session in View). Each of those + /// sessions will be registered for deferred close, though, actually + /// processed at request completion. + /// + public bool SingleSession + { + get { return settings.SingleSession; } + } + + /// + /// Gets the flushmode to be applied on each newly created session. /// /// - /// It is recommended to be used in the following type of scenario: - /// - /// using (new SessionScope()) - /// { - /// ... do multiple operation, possibly in multiple transactions. - /// } - /// - /// At the end of "using", the session is automatically closed. All transactions within the scope use the same session, - /// if you are using Spring's HibernateTemplate or using Spring's implementation of NHibernate 1.2's - /// ICurrentSessionContext interface. - /// - /// - /// It is assumed that the session factory object name is called "SessionFactory". In case that you named the object - /// in different way you can specify your can specify it in the application settings using the key - /// Spring.Data.NHibernate.Support.SessionScope.SessionFactoryObjectName. Values for EntityInterceptorObjectName - /// and SingleSessionMode can be specified similarly. - /// - /// - /// Note: - /// The session is managed on a per thread basis on the thread that opens the scope instance. This means that you must - /// never pass a reference to a instance over to another thread! - /// + /// This property defaults to to ensure that modifying objects outside the boundaries + /// of a transaction will not be persisted. It is recommended to not change this value but wrap any modifying operation + /// within a transaction. /// - /// Robert M. (.NET) - /// Harald Radi (.NET) - public class SessionScope : IDisposable + public FlushMode DefaultFlushMode { - /// - /// The logging instance. - /// - protected readonly ILogger log = LogManager.GetLogger(MethodInfo.GetCurrentMethod().DeclaringType); + get { return settings.DefaultFlushMode; } + } - private readonly SessionScopeSettings settings; - - // Keys into LogicalThreadContext for runtime values. - private readonly string PARTICIPATE_KEY; - private readonly string ISOPEN_KEY; - - /// - /// Initializes a new instance of the class in single session mode, - /// associating a session with the thread. The session is opened lazily on demand. - /// - public SessionScope() - : this(true) + /// + /// Get or set the configured SessionFactory + /// + public ISessionFactory SessionFactory + { + get { + return settings.SessionFactory; + } + } + + /// + /// Get or set the configured EntityInterceptor + /// + public IInterceptor EntityInterceptor + { + get + { + return settings.EntityInterceptor; + } + } + + /// + /// Gets a flag, whether this scope is in "open" state on the current logical thread. + /// + public bool IsOpen + { + get + { + return (null != LogicalThreadContext.GetData(ISOPEN_KEY)); + } + } + + /// + /// Gets a flag, whether this scope manages it's own session for the current logical thread or not. + /// + public bool IsParticipating + { + get + { + return (null != LogicalThreadContext.GetData(PARTICIPATE_KEY)); + } + } + + /// + /// Sets a flag, whether this scope is in "open" state on the current logical thread. + /// + private void SetOpen(bool isOpen) + { + if (isOpen) + { + LogicalThreadContext.SetData(ISOPEN_KEY, ISOPEN_KEY); + } + else + { + LogicalThreadContext.FreeNamedDataSlot(ISOPEN_KEY); + } + } + + /// + /// Gets/Sets a flag, whether this scope manages it's own session for the current logical thread or not. + /// + /// false if session is managed by this module. false otherwise + private void SetParticipating(bool participating) + { + if (participating) + { + LogicalThreadContext.SetData(PARTICIPATE_KEY, PARTICIPATE_KEY); + } + else + { + LogicalThreadContext.FreeNamedDataSlot(PARTICIPATE_KEY); + } + } + + /// + /// Call Close(), + /// + public virtual void Dispose() + { + Close(); + } + + /// + /// Opens a new session or participates in an existing session and + /// registers with spring's . + /// + public void Open() + { + if (IsParticipating || IsOpen) + { + throw new InvalidOperationException("This scope is already open"); } + bool isDebugEnabled = log.IsEnabled(LogLevel.Debug); - /// - /// Initializes a new instance of the class. - /// - /// - /// If set to true associate a session with the thread. If false, another - /// collaborating class will associate the session with the thread, potentially by calling - /// the Open method on this class. - /// - public SessionScope(bool open) - : this("appSettings", open) + if (SingleSession) { - // noop - } - - /// - /// Initializes a new instance of the class. - /// - /// - /// The name of the configuration section to read configuration settings from. - /// See for more info. - /// - /// - /// If set to true associate a session with the thread. If false, another - /// collaborating class will associate the session with the thread, potentially by calling - /// the Open method on this class. - /// - public SessionScope(string sectionName, bool open) - : this( sectionName, typeof(SessionScope), open) - { - // noop - } - - - /// - /// Initializes a new instance of the class. - /// - /// - /// The name of the configuration section to read configuration settings from. - /// See for more info. - /// - /// The type, who's full name is used for prefixing appSetting keys - /// - /// If set to true associate a session with the thread. If false, another - /// collaborating class will associate the session with the thread, potentially by calling - /// the Open method on this class. - /// - public SessionScope(string sectionName, Type namespaceType, bool open) - : this(new ConfigSectionSessionScopeSettings(namespaceType, sectionName), open) - { - // noop - } - - /// - /// Initializes a new instance of the class. - /// - /// - /// The instance to be used for obtaining instances. - /// - /// - /// If set to true associate a session with the thread. If false, another - /// collaborating class will associate the session with the thread, potentially by calling - /// the Open method on this class. - /// - public SessionScope(ISessionFactory sessionFactory, bool open) - : this(new SessionScopeSettings(sessionFactory), open) - { - // noop - } - - /// - /// Initializes a new instance of the class. - /// - /// - /// The instance to be used for obtaining instances. - /// - /// - /// Specify the to be set on each session provided by this instance. - /// - /// - /// Set whether to use a single session for each request. See property for details. - /// - /// - /// Specify the flushmode to be applied on each session provided by this instance. - /// - /// - /// If set to true associate a session with the thread. If false, another - /// collaborating class will associate the session with the thread, potentially by calling - /// the Open method on this class. - /// - public SessionScope(ISessionFactory sessionFactory, IInterceptor entityInterceptor, bool singleSession, FlushMode defaultFlushMode, bool open) - :this(new SessionScopeSettings(sessionFactory, entityInterceptor, singleSession, defaultFlushMode), open) - { - // noop - } - - /// - /// Initializes a new instance of the class. - /// - /// An instance holding the scope configuration - /// - /// If set to true associate a session with the thread. If false, another - /// collaborating class will associate the session with the thread, potentially by calling - /// the Open method on this class. - /// - public SessionScope(SessionScopeSettings settings, bool open) - { - log = LogManager.GetLogger(this.GetType()); - this.settings = settings; - - PARTICIPATE_KEY = UniqueKey.GetInstanceScopedString(this, "Participate"); - ISOPEN_KEY = UniqueKey.GetInstanceScopedString(this, "IsOpen"); - - if (open) + // single session mode + if (TransactionSynchronizationManager.HasResource(SessionFactory)) { - Open(); - } - } - - /// - /// Set whether to use a single session for each request. Default is "true". - /// If set to false, each data access operation or transaction will use - /// its own session (like without Open Session in View). Each of those - /// sessions will be registered for deferred close, though, actually - /// processed at request completion. - /// - public bool SingleSession - { - get { return settings.SingleSession; } - } - - /// - /// Gets the flushmode to be applied on each newly created session. - /// - /// - /// This property defaults to to ensure that modifying objects outside the boundaries - /// of a transaction will not be persisted. It is recommended to not change this value but wrap any modifying operation - /// within a transaction. - /// - public FlushMode DefaultFlushMode - { - get { return settings.DefaultFlushMode; } - } - - /// - /// Get or set the configured SessionFactory - /// - public ISessionFactory SessionFactory - { - get - { - return settings.SessionFactory; - } - } - - /// - /// Get or set the configured EntityInterceptor - /// - public IInterceptor EntityInterceptor - { - get - { - return settings.EntityInterceptor; - } - } - - /// - /// Gets a flag, whether this scope is in "open" state on the current logical thread. - /// - public bool IsOpen - { - get - { - return (null != LogicalThreadContext.GetData(ISOPEN_KEY)); - } - } - - /// - /// Gets a flag, whether this scope manages it's own session for the current logical thread or not. - /// - public bool IsParticipating - { - get - { - return (null != LogicalThreadContext.GetData(PARTICIPATE_KEY)); - } - } - - /// - /// Sets a flag, whether this scope is in "open" state on the current logical thread. - /// - private void SetOpen(bool isOpen) - { - if (isOpen) - { - LogicalThreadContext.SetData(ISOPEN_KEY, ISOPEN_KEY); + // Do not modify the Session: just set the participate flag. + if (isDebugEnabled) log.LogDebug("Participating in existing Hibernate SessionFactory"); + SetParticipating(true); } else { - LogicalThreadContext.FreeNamedDataSlot(ISOPEN_KEY); + if (isDebugEnabled) log.LogDebug("Opening single Hibernate Session in SessionScope"); + TransactionSynchronizationManager.BindResource(SessionFactory, new LazySessionHolder(this)); } } - - /// - /// Gets/Sets a flag, whether this scope manages it's own session for the current logical thread or not. - /// - /// false if session is managed by this module. false otherwise - private void SetParticipating(bool participating) + else { - if (participating) + // deferred close mode + if (SessionFactoryUtils.IsDeferredCloseActive(SessionFactory)) { - LogicalThreadContext.SetData(PARTICIPATE_KEY, PARTICIPATE_KEY); + // Do not modify deferred close: just set the participate flag. + if (isDebugEnabled) log.LogDebug("Participating in active deferred close mode"); + SetParticipating(true); } else { - LogicalThreadContext.FreeNamedDataSlot(PARTICIPATE_KEY); + if (isDebugEnabled) log.LogDebug("Initializing deferred close mode"); + SessionFactoryUtils.InitDeferredClose(SessionFactory); } } - /// - /// Call Close(), - /// - public virtual void Dispose() - { - Close(); - } + SetOpen(true); + } - /// - /// Opens a new session or participates in an existing session and - /// registers with spring's . - /// - public void Open() + /// + /// Close the current view's session and unregisters + /// from spring's . + /// + public void Close() + { + bool isDebugEnabled = log.IsEnabled(LogLevel.Debug); + if (isDebugEnabled) log.LogDebug("Trying to close SessionScope"); + + if (IsOpen) { - if (IsParticipating || IsOpen) + try { - throw new InvalidOperationException("This scope is already open"); + DoClose(isDebugEnabled); } + finally + { + SetOpen(false); + SetParticipating(false); + } + } + else + { + if (isDebugEnabled) log.LogDebug("SessionScope is already closed - doing nothing"); + } + } - bool isDebugEnabled = log.IsEnabled(LogLevel.Debug); - + private void DoClose(bool isLogDebugEnabled) + { + if (!IsParticipating) + { if (SingleSession) { // single session mode - if (TransactionSynchronizationManager.HasResource(SessionFactory)) - { - // Do not modify the Session: just set the participate flag. - if (isDebugEnabled) log.LogDebug("Participating in existing Hibernate SessionFactory"); - SetParticipating(true); - } - else - { - if (isDebugEnabled) log.LogDebug("Opening single Hibernate Session in SessionScope"); - TransactionSynchronizationManager.BindResource(SessionFactory, new LazySessionHolder(this)); - } + if (isLogDebugEnabled) log.LogDebug("Closing single Hibernate Session in SessionScope"); + LazySessionHolder holder = (LazySessionHolder) TransactionSynchronizationManager.UnbindResource(SessionFactory); + holder.Close(); } else { // deferred close mode - if (SessionFactoryUtils.IsDeferredCloseActive(SessionFactory)) - { - // Do not modify deferred close: just set the participate flag. - if (isDebugEnabled) log.LogDebug("Participating in active deferred close mode"); - SetParticipating(true); - } - else - { - if (isDebugEnabled) log.LogDebug("Initializing deferred close mode"); - SessionFactoryUtils.InitDeferredClose(SessionFactory); - } + if (isLogDebugEnabled) log.LogDebug("Closing all Hibernate Sessions"); + SessionFactoryUtils.ProcessDeferredClose(SessionFactory); } + } + else + { + if (isLogDebugEnabled) log.LogDebug("Only participated Hibernate Session - doing nothing"); + } + } - SetOpen(true); + private ISession DoOpenSession() + { + ISession session = SessionFactoryUtils.OpenSession(SessionFactory, EntityInterceptor); + session.FlushMode = DefaultFlushMode; + return session; + } + + /// + /// This sessionHolder creates a default session only if it is needed. + /// + /// + /// Although a NHibernateSession deferes creation of db-connections until they are really + /// needed, instantiation a session is imho still more expensive than this LazySessionHolder. (EE) + /// + private class LazySessionHolder : SessionHolder + { + private readonly ILogger log = LogManager.GetLogger(); + private SessionScope owner; + private ISession session; + + /// + /// Initialize a new instance. + /// + public LazySessionHolder(SessionScope owner) + { + if (log.IsEnabled(LogLevel.Debug)) log.LogDebug("Created LazySessionHolder"); + this.owner = owner; } /// - /// Close the current view's session and unregisters - /// from spring's . + /// Create a new session on demand + /// + protected override void EnsureInitialized() + { + if (session == null) + { + if (log.IsEnabled(LogLevel.Debug)) log.LogDebug("session instance requested - opening new session"); + session = owner.DoOpenSession(); + AddSession(session); + } + } + + /// + /// Ensure session is closed (if any) and remove circular references to avoid memory leaks! /// public void Close() { - bool isDebugEnabled = log.IsEnabled(LogLevel.Debug); - if (isDebugEnabled) log.LogDebug("Trying to close SessionScope"); - - if (IsOpen) + owner = null; + if (session != null) { - try - { - DoClose(isDebugEnabled); - } - finally - { - SetOpen(false); - SetParticipating(false); - } - } - else - { - if (isDebugEnabled) log.LogDebug("SessionScope is already closed - doing nothing"); - } - } - - private void DoClose(bool isLogDebugEnabled) - { - if (!IsParticipating) - { - if (SingleSession) - { - // single session mode - if (isLogDebugEnabled) log.LogDebug("Closing single Hibernate Session in SessionScope"); - LazySessionHolder holder = (LazySessionHolder)TransactionSynchronizationManager.UnbindResource(SessionFactory); - holder.Close(); - } - else - { - // deferred close mode - if (isLogDebugEnabled) log.LogDebug("Closing all Hibernate Sessions"); - SessionFactoryUtils.ProcessDeferredClose(SessionFactory); - } - } - else - { - if (isLogDebugEnabled) log.LogDebug("Only participated Hibernate Session - doing nothing"); - } - } - - private ISession DoOpenSession() - { - ISession session = SessionFactoryUtils.OpenSession(SessionFactory, EntityInterceptor); - session.FlushMode = DefaultFlushMode; - return session; - } - - /// - /// This sessionHolder creates a default session only if it is needed. - /// - /// - /// Although a NHibernateSession deferes creation of db-connections until they are really - /// needed, instantiation a session is imho still more expensive than this LazySessionHolder. (EE) - /// - private class LazySessionHolder : SessionHolder - { - private readonly ILogger log = LogManager.GetLogger(); - private SessionScope owner; - private ISession session; - - /// - /// Initialize a new instance. - /// - public LazySessionHolder(SessionScope owner) - { - if (log.IsEnabled(LogLevel.Debug)) log.LogDebug("Created LazySessionHolder"); - this.owner = owner; + ISession tmpSession = session; + session = null; + SessionFactoryUtils.CloseSession(tmpSession); } - /// - /// Create a new session on demand - /// - protected override void EnsureInitialized() - { - if (session == null) - { - if (log.IsEnabled(LogLevel.Debug)) log.LogDebug("session instance requested - opening new session"); - session = owner.DoOpenSession(); - AddSession(session); - } - } - - /// - /// Ensure session is closed (if any) and remove circular references to avoid memory leaks! - /// - public void Close() - { - owner = null; - if (session != null) - { - ISession tmpSession = session; - session = null; - SessionFactoryUtils.CloseSession(tmpSession); - } - if (log.IsEnabled(LogLevel.Debug)) log.LogDebug("Closed LazySessionHolder"); - } + if (log.IsEnabled(LogLevel.Debug)) log.LogDebug("Closed LazySessionHolder"); } } } diff --git a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Support/SessionScopeSettings.cs b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Support/SessionScopeSettings.cs index bc68e91b..d99abf05 100644 --- a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Support/SessionScopeSettings.cs +++ b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/Support/SessionScopeSettings.cs @@ -17,179 +17,181 @@ using NHibernate; using Spring.Util; -namespace Spring.Data.NHibernate.Support +namespace Spring.Data.NHibernate.Support; + +/// +/// Holds the references and configuration settings for a instance. +/// +public class SessionScopeSettings { /// - /// Holds the references and configuration settings for a instance. + /// Default value for property. /// - public class SessionScopeSettings + public static readonly bool SINGLESESSION_DEFAULT = true; + + /// + /// Default value for property. + /// + public static readonly FlushMode FLUSHMODE_DEFAULT = FlushMode.Never; + + private ISessionFactory sessionFactory; + private bool sessionFactoryInitialized; + private IInterceptor entityInterceptor; + private bool entityInterceptorInitialized; + private bool singleSession; + private FlushMode defaultFlushMode; + + /// + /// Initialize a new instance of with default values. + /// + /// + /// Calling this constructor from your derived class leaves and + /// uninitialized. See and for more. + /// + protected SessionScopeSettings() { - /// - /// Default value for property. - /// - public static readonly bool SINGLESESSION_DEFAULT = true; - /// - /// Default value for property. - /// - public static readonly FlushMode FLUSHMODE_DEFAULT = FlushMode.Never; + this.sessionFactory = null; + this.sessionFactoryInitialized = false; + this.entityInterceptor = null; + this.entityInterceptorInitialized = false; + this.singleSession = SINGLESESSION_DEFAULT; + this.defaultFlushMode = FLUSHMODE_DEFAULT; + } - private ISessionFactory sessionFactory; - private bool sessionFactoryInitialized; - private IInterceptor entityInterceptor; - private bool entityInterceptorInitialized; - private bool singleSession; - private FlushMode defaultFlushMode; + /// + /// Initialize a new instance of with the given sessionFactory + /// and default values for all other settings. + /// + /// + /// The instance to be used for obtaining instances. + /// + /// + /// Calling this constructor marks all properties initialized. + /// + public SessionScopeSettings(ISessionFactory sessionFactory) + : this(sessionFactory, null, SINGLESESSION_DEFAULT, FLUSHMODE_DEFAULT) + { + // noop + this.entityInterceptorInitialized = false; + } - /// - /// Initialize a new instance of with default values. - /// - /// - /// Calling this constructor from your derived class leaves and - /// uninitialized. See and for more. - /// - protected SessionScopeSettings() + /// + /// Initialize a new instance of with the given values and references. + /// + /// + /// The instance to be used for obtaining instances. + /// + /// + /// Specify the to be set on each session provided by the instance. + /// + /// + /// Set whether to use a single session for each request. See property for details. + /// + /// + /// Specify the flushmode to be applied on each session provided by the instance. + /// + /// + /// Calling this constructor marks all properties initialized. + /// + public SessionScopeSettings(ISessionFactory sessionFactory, IInterceptor entityInterceptor, bool singleSession, FlushMode defaultFlushMode) + { + AssertUtils.ArgumentNotNull(sessionFactory, "sessionFactory"); + + this.sessionFactory = sessionFactory; + this.sessionFactoryInitialized = true; + this.entityInterceptor = entityInterceptor; + this.entityInterceptorInitialized = true; + this.singleSession = singleSession; + this.defaultFlushMode = defaultFlushMode; + } + + /// + /// Gets the configured instance to be used. + /// + /// + /// If the entity interceptor is not set by the constructor, this property calls + /// to obtain an instance. This allows derived classes to + /// override the behaviour of how to obtain the concrete instance. + /// + public IInterceptor EntityInterceptor + { + get { - this.sessionFactory = null; - this.sessionFactoryInitialized = false; - this.entityInterceptor = null; - this.entityInterceptorInitialized = false; - this.singleSession = SINGLESESSION_DEFAULT; - this.defaultFlushMode = FLUSHMODE_DEFAULT; - } - - /// - /// Initialize a new instance of with the given sessionFactory - /// and default values for all other settings. - /// - /// - /// The instance to be used for obtaining instances. - /// - /// - /// Calling this constructor marks all properties initialized. - /// - public SessionScopeSettings(ISessionFactory sessionFactory) - :this(sessionFactory, null, SINGLESESSION_DEFAULT, FLUSHMODE_DEFAULT) - { - // noop - this.entityInterceptorInitialized = false; - } - - /// - /// Initialize a new instance of with the given values and references. - /// - /// - /// The instance to be used for obtaining instances. - /// - /// - /// Specify the to be set on each session provided by the instance. - /// - /// - /// Set whether to use a single session for each request. See property for details. - /// - /// - /// Specify the flushmode to be applied on each session provided by the instance. - /// - /// - /// Calling this constructor marks all properties initialized. - /// - public SessionScopeSettings(ISessionFactory sessionFactory, IInterceptor entityInterceptor, bool singleSession, FlushMode defaultFlushMode) - { - AssertUtils.ArgumentNotNull(sessionFactory, "sessionFactory"); - - this.sessionFactory = sessionFactory; - this.sessionFactoryInitialized = true; - this.entityInterceptor = entityInterceptor; - this.entityInterceptorInitialized = true; - this.singleSession = singleSession; - this.defaultFlushMode = defaultFlushMode; - } - - /// - /// Gets the configured instance to be used. - /// - /// - /// If the entity interceptor is not set by the constructor, this property calls - /// to obtain an instance. This allows derived classes to - /// override the behaviour of how to obtain the concrete instance. - /// - public IInterceptor EntityInterceptor - { - get + if (!entityInterceptorInitialized) { - if (!entityInterceptorInitialized) - { - return ResolveEntityInterceptor(); - } - return entityInterceptor; + return ResolveEntityInterceptor(); } - } - /// - /// Gets the configured instance to be used. - /// - /// - /// If this property is requested for the first time, is called. - /// This allows derived classes to override the behaviour of how to obtain the concrete instance. - /// - /// If the instance cannot be resolved. - public ISessionFactory SessionFactory - { - get - { - if (!sessionFactoryInitialized) - { - sessionFactoryInitialized = true; - sessionFactory = ResolveSessionFactory(); - if (sessionFactory == null) - { - throw new ArgumentException(string.Format("mandatory SessionFactory not found")); - } - } - return sessionFactory; - } - } - - /// - /// Set whether to use a single session for each request. Default is "true". - /// If set to false, each data access operation or transaction will use - /// its own session (like without Open Session in View). Each of those - /// sessions will be registered for deferred close, though, actually - /// processed at request completion. - /// - public bool SingleSession - { - get { return singleSession; } - set { singleSession = value; } - } - - /// - /// Gets or Sets the flushmode to be applied on each newly created session. - /// - /// - /// This property defaults to to ensure that modifying objects outside the boundaries - /// of a transaction will not be persisted. It is recommended to not change this value but wrap any modifying operation - /// within a transaction. - /// - public FlushMode DefaultFlushMode - { - get { return defaultFlushMode; } - set { defaultFlushMode = value; } - } - - /// - /// Override this method to resolve an instance according to your chosen strategy. - /// - protected virtual IInterceptor ResolveEntityInterceptor() - { - return null; - } - - /// - /// Override this method to resolve an instance according to your chosen strategy. - /// - protected virtual ISessionFactory ResolveSessionFactory() - { - throw new NotSupportedException("you need to override this method to resolve an ISessionFactory instance"); + return entityInterceptor; } } + + /// + /// Gets the configured instance to be used. + /// + /// + /// If this property is requested for the first time, is called. + /// This allows derived classes to override the behaviour of how to obtain the concrete instance. + /// + /// If the instance cannot be resolved. + public ISessionFactory SessionFactory + { + get + { + if (!sessionFactoryInitialized) + { + sessionFactoryInitialized = true; + sessionFactory = ResolveSessionFactory(); + if (sessionFactory == null) + { + throw new ArgumentException(string.Format("mandatory SessionFactory not found")); + } + } + + return sessionFactory; + } + } + + /// + /// Set whether to use a single session for each request. Default is "true". + /// If set to false, each data access operation or transaction will use + /// its own session (like without Open Session in View). Each of those + /// sessions will be registered for deferred close, though, actually + /// processed at request completion. + /// + public bool SingleSession + { + get { return singleSession; } + set { singleSession = value; } + } + + /// + /// Gets or Sets the flushmode to be applied on each newly created session. + /// + /// + /// This property defaults to to ensure that modifying objects outside the boundaries + /// of a transaction will not be persisted. It is recommended to not change this value but wrap any modifying operation + /// within a transaction. + /// + public FlushMode DefaultFlushMode + { + get { return defaultFlushMode; } + set { defaultFlushMode = value; } + } + + /// + /// Override this method to resolve an instance according to your chosen strategy. + /// + protected virtual IInterceptor ResolveEntityInterceptor() + { + return null; + } + + /// + /// Override this method to resolve an instance according to your chosen strategy. + /// + protected virtual ISessionFactory ResolveSessionFactory() + { + throw new NotSupportedException("you need to override this method to resolve an ISessionFactory instance"); + } } diff --git a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/TemplateFlushMode.cs b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/TemplateFlushMode.cs index c4a8c8fe..c7c0203a 100644 --- a/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/TemplateFlushMode.cs +++ b/src/Spring/Spring.Data.NHibernate5/Data/NHibernate/TemplateFlushMode.cs @@ -1,12 +1,12 @@ /* - * Copyright © 2002-2011 the original author or authors. - * + * Copyright � 2002-2011 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. @@ -14,79 +14,77 @@ * limitations under the License. */ -namespace Spring.Data.NHibernate +namespace Spring.Data.NHibernate; + +/// +/// Enumeration for the various Hibernate flush modes. +/// +/// Mark Pollack (.NET) +public enum TemplateFlushMode { - /// - /// Enumeration for the various Hibernate flush modes. - /// - /// Mark Pollack (.NET) - public enum TemplateFlushMode - { - /// Never flush is a good strategy for read-only units of work. - /// - /// - /// Hibernate will not track and look for changes in this case, - /// avoiding any overhead of modification detection. - ///

In case of an existing ISession, TemplateFlushMode.Never will turn - /// the hibenrate flush mode - /// to FlushMode.Never for the scope of the current operation, resetting the previous - /// flush mode afterwards. - ///

- ///
- Never, + /// Never flush is a good strategy for read-only units of work. + /// + /// + /// Hibernate will not track and look for changes in this case, + /// avoiding any overhead of modification detection. + ///

In case of an existing ISession, TemplateFlushMode.Never will turn + /// the hibenrate flush mode + /// to FlushMode.Never for the scope of the current operation, resetting the previous + /// flush mode afterwards. + ///

+ ///
+ Never, - /// Automatic flushing is the default mode for a Hibernate Session. - /// - /// - /// A session will get flushed on transaction commit, and on certain find - /// operations that might involve already modified instances, but not - /// after each unit of work like with eager flushing. - ///

In case of an existing Session, TemplateFlushMode.Auto - /// will participate in the existing flush mode, not modifying - /// it for the current operation. - /// This in particular means that this setting will not modify an existing - /// hibernate flush mode FlushMode.Never, in contrast to TemplateFlushMode.Eager. - ///

- ///
- Auto, + /// Automatic flushing is the default mode for a Hibernate Session. + /// + /// + /// A session will get flushed on transaction commit, and on certain find + /// operations that might involve already modified instances, but not + /// after each unit of work like with eager flushing. + ///

In case of an existing Session, TemplateFlushMode.Auto + /// will participate in the existing flush mode, not modifying + /// it for the current operation. + /// This in particular means that this setting will not modify an existing + /// hibernate flush mode FlushMode.Never, in contrast to TemplateFlushMode.Eager. + ///

+ ///
+ Auto, - /// - /// Eager flushing leads to immediate synchronization with the database, - /// even if in a transaction. - /// - /// - /// This causes inconsistencies to show up and throw - /// a respective exception immediately, and ADO access code that participates - /// in the same transaction will see the changes as the database is already - /// aware of them then. But the drawbacks are: - ///
    - ///
  • additional communication roundtrips with the database, instead of a - /// single batch at transaction commit;
  • - ///
  • the fact that an actual database rollback is needed if the Hibernate - /// transaction rolls back (due to already submitted SQL statements).
  • - ///
- ///

In case of an existing Session, TemplateFlushMode.Eager - /// will turn the NHibernate flush mode - /// to FlushMode.Auto for the scope of the current operation and issue a flush at the - /// end, resetting the previous flush mode afterwards. - ///

- ///
- Eager, + /// + /// Eager flushing leads to immediate synchronization with the database, + /// even if in a transaction. + /// + /// + /// This causes inconsistencies to show up and throw + /// a respective exception immediately, and ADO access code that participates + /// in the same transaction will see the changes as the database is already + /// aware of them then. But the drawbacks are: + ///
    + ///
  • additional communication roundtrips with the database, instead of a + /// single batch at transaction commit;
  • + ///
  • the fact that an actual database rollback is needed if the Hibernate + /// transaction rolls back (due to already submitted SQL statements).
  • + ///
+ ///

In case of an existing Session, TemplateFlushMode.Eager + /// will turn the NHibernate flush mode + /// to FlushMode.Auto for the scope of the current operation and issue a flush at the + /// end, resetting the previous flush mode afterwards. + ///

+ ///
+ Eager, - /// - /// Flushing at commit only is intended for units of work where no - /// intermediate flushing is desired, not even for find operations - /// that might involve already modified instances. - /// - /// - ///

In case of an existing Session, TemplateFlushMode.Commit - /// will turn the NHibernate flush mode - /// to FlushMode.Commit for the scope of the current operation, resetting the previous - /// flush mode afterwards. The only exception is an existing flush mode - /// FlushMode.Never, which will not be modified through this setting. - ///

- ///
- Commit - - } + /// + /// Flushing at commit only is intended for units of work where no + /// intermediate flushing is desired, not even for find operations + /// that might involve already modified instances. + /// + /// + ///

In case of an existing Session, TemplateFlushMode.Commit + /// will turn the NHibernate flush mode + /// to FlushMode.Commit for the scope of the current operation, resetting the previous + /// flush mode afterwards. The only exception is an existing flush mode + /// FlushMode.Never, which will not be modified through this setting. + ///

+ ///
+ Commit } diff --git a/src/Spring/Spring.Data/AssemblyInfo.cs b/src/Spring/Spring.Data/AssemblyInfo.cs index e252c721..6eea99b8 100644 --- a/src/Spring/Spring.Data/AssemblyInfo.cs +++ b/src/Spring/Spring.Data/AssemblyInfo.cs @@ -1,4 +1,4 @@ using System.Reflection; [assembly: AssemblyTitle("Spring.Data")] -[assembly: AssemblyDescription("Interfaces and classes that provide Data access support in Spring.Net")] \ No newline at end of file +[assembly: AssemblyDescription("Interfaces and classes that provide Data access support in Spring.Net")] diff --git a/src/Spring/Spring.Data/Dao/Attributes/PersistenceExceptionTranslationAdvisor.cs b/src/Spring/Spring.Data/Dao/Attributes/PersistenceExceptionTranslationAdvisor.cs index e13e145d..b472319b 100644 --- a/src/Spring/Spring.Data/Dao/Attributes/PersistenceExceptionTranslationAdvisor.cs +++ b/src/Spring/Spring.Data/Dao/Attributes/PersistenceExceptionTranslationAdvisor.cs @@ -24,72 +24,71 @@ using Spring.Aop.Support; using Spring.Dao.Support; using Spring.Objects.Factory; -namespace Spring.Dao.Attributes +namespace Spring.Dao.Attributes; + +/// +/// Spring AOP exception translation aspect for use at Repository or DAO layer level. +/// Translates native persistence exceptions into Spring's DataAccessException hierarchy, +/// based on a given PersistenceExceptionTranslator. +/// +/// Rod Johnson +/// Juergen Hoeller +/// Mark Pollack (.NET) +public class PersistenceExceptionTranslationAdvisor : AbstractPointcutAdvisor { + private PersistenceExceptionTranslationInterceptor advice; + + private AttributeMatchingPointcut pointcut; + /// - /// Spring AOP exception translation aspect for use at Repository or DAO layer level. - /// Translates native persistence exceptions into Spring's DataAccessException hierarchy, - /// based on a given PersistenceExceptionTranslator. + /// Initializes a new instance of the class. /// - /// Rod Johnson - /// Juergen Hoeller - /// Mark Pollack (.NET) - public class PersistenceExceptionTranslationAdvisor : AbstractPointcutAdvisor + /// The persistence exception translator to use. + /// Type of the repository attribute to check for. + public PersistenceExceptionTranslationAdvisor(IPersistenceExceptionTranslator persistenceExceptionTranslator, + Type repositoryAttributeType) { - private PersistenceExceptionTranslationInterceptor advice; + this.advice = new PersistenceExceptionTranslationInterceptor(persistenceExceptionTranslator); + this.pointcut = new AttributeMatchingPointcut(repositoryAttributeType, true); + } - private AttributeMatchingPointcut pointcut; + /// + /// Initializes a new instance of the class. + /// + /// The object factory to obtain all IPersistenceExceptionTranslators from. + /// Type of the repository attribute to check for. + public PersistenceExceptionTranslationAdvisor(IListableObjectFactory objectFactory, Type repositoryAttributeType) + { + this.advice = new PersistenceExceptionTranslationInterceptor(objectFactory); + this.pointcut = new AttributeMatchingPointcut(repositoryAttributeType, true); + } - /// - /// Initializes a new instance of the class. - /// - /// The persistence exception translator to use. - /// Type of the repository attribute to check for. - public PersistenceExceptionTranslationAdvisor(IPersistenceExceptionTranslator persistenceExceptionTranslator, - Type repositoryAttributeType) - { - this.advice = new PersistenceExceptionTranslationInterceptor(persistenceExceptionTranslator); - this.pointcut = new AttributeMatchingPointcut(repositoryAttributeType, true); - } - - /// - /// Initializes a new instance of the class. - /// - /// The object factory to obtain all IPersistenceExceptionTranslators from. - /// Type of the repository attribute to check for. - public PersistenceExceptionTranslationAdvisor(IListableObjectFactory objectFactory, Type repositoryAttributeType) - { - this.advice = new PersistenceExceptionTranslationInterceptor(objectFactory); - this.pointcut = new AttributeMatchingPointcut(repositoryAttributeType, true); - } + /// + /// Return the advice part of this aspect. + /// + /// + /// + ///

+ /// An advice may be an interceptor, a throws advice, before advice, + /// introduction etc. + ///

+ ///
+ /// + /// The advice that should apply if the pointcut matches. + /// + public override IAdvice Advice + { + get { return this.advice; } + set { } + } - /// - /// Return the advice part of this aspect. - /// - /// - /// - ///

- /// An advice may be an interceptor, a throws advice, before advice, - /// introduction etc. - ///

- ///
- /// - /// The advice that should apply if the pointcut matches. - /// - public override IAdvice Advice - { - get { return this.advice; } - set { } - } - - /// - /// The that drives this advisor. - /// - /// - public override IPointcut Pointcut - { - get { return this.pointcut; } - set { } - } + /// + /// The that drives this advisor. + /// + /// + public override IPointcut Pointcut + { + get { return this.pointcut; } + set { } } } diff --git a/src/Spring/Spring.Data/Dao/Attributes/PersistenceExceptionTranslationPostProcessor.cs b/src/Spring/Spring.Data/Dao/Attributes/PersistenceExceptionTranslationPostProcessor.cs index 11350630..78e07648 100644 --- a/src/Spring/Spring.Data/Dao/Attributes/PersistenceExceptionTranslationPostProcessor.cs +++ b/src/Spring/Spring.Data/Dao/Attributes/PersistenceExceptionTranslationPostProcessor.cs @@ -26,149 +26,152 @@ using Spring.Objects.Factory.Config; using Spring.Stereotype; using Spring.Util; -namespace Spring.Dao.Attributes +namespace Spring.Dao.Attributes; + +/// +/// Object post-processor that automatically applies persistence exception +/// translation to any bean that carries the +/// attribute, adding a corresponding +/// to the exposed proxy (either an existing AOP proxy or a newly generated +/// proxy that implements all of the target's interfaces). +/// +/// +/// Translates native resource exceptions to Spring's +/// hierarchy. Autodetects object that implement the +/// interface, which are subsequently asked to translate candidate exceptions. +/// +/// All of Spring's applicable resource factories implement the +/// IPersistenceExceptionTranslator interface out of the box. +/// As a consequence, all that is usually needed to enable automatic exception +/// translation is marking all affected objects (such as DAOs) with the +/// Repository annotation, along with defining this post-processor +/// in the application context. +/// +/// +/// Rod Johnson +/// Juergen Hoeller +/// Mark Pollack (.NET) +/// +/// +/// +/// +public class PersistenceExceptionTranslationPostProcessor : ProxyConfig, IObjectPostProcessor, IObjectFactoryAware, IOrdered { + private Type repositoryAttributeType = typeof(RepositoryAttribute); + + private PersistenceExceptionTranslationAdvisor persistenceExceptionTranslationAdvisor; + /// - /// Object post-processor that automatically applies persistence exception - /// translation to any bean that carries the - /// attribute, adding a corresponding - /// to the exposed proxy (either an existing AOP proxy or a newly generated - /// proxy that implements all of the target's interfaces). + /// Sets the type of the repository attribute. The default required attribute type is the + /// attirbute. This setter property exists so that developers + /// can provide their own (non-Spring-specific) attribute type to indicate that a class has a + /// repository role. /// - /// - /// Translates native resource exceptions to Spring's - /// hierarchy. Autodetects object that implement the - /// interface, which are subsequently asked to translate candidate exceptions. - /// - /// All of Spring's applicable resource factories implement the - /// IPersistenceExceptionTranslator interface out of the box. - /// As a consequence, all that is usually needed to enable automatic exception - /// translation is marking all affected objects (such as DAOs) with the - /// Repository annotation, along with defining this post-processor - /// in the application context. - /// - /// - /// Rod Johnson - /// Juergen Hoeller - /// Mark Pollack (.NET) - /// - /// - /// - /// - public class PersistenceExceptionTranslationPostProcessor : ProxyConfig, IObjectPostProcessor, IObjectFactoryAware, IOrdered + /// The desitred type of the repository attribute. + public Type RepositoryAttributeType { - private Type repositoryAttributeType = typeof(RepositoryAttribute); - - private PersistenceExceptionTranslationAdvisor persistenceExceptionTranslationAdvisor; - - - /// - /// Sets the type of the repository attribute. The default required attribute type is the - /// attirbute. This setter property exists so that developers - /// can provide their own (non-Spring-specific) attribute type to indicate that a class has a - /// repository role. - /// - /// The desitred type of the repository attribute. - public Type RepositoryAttributeType + set { - set + AssertUtils.ArgumentNotNull(value, "'RepositoryAttributeType' must not be null"); + repositoryAttributeType = value; + } + } + + /// + /// Callback that supplies the owning factory to an object instance. + /// + public IObjectFactory ObjectFactory + { + set + { + IListableObjectFactory lof = value as IListableObjectFactory; + if (lof == null) { - AssertUtils.ArgumentNotNull(value, "'RepositoryAttributeType' must not be null"); - repositoryAttributeType = value; + throw new ArgumentException("Cannot use PersistenceExceptionTranslator autodetection without IListableObjectFactory"); } + + this.persistenceExceptionTranslationAdvisor = + new PersistenceExceptionTranslationAdvisor(lof, this.repositoryAttributeType); + } + } + + public int Order + { + get + { + return Int32.MaxValue; + // lowest precidence value + // This should run after all other post-processors, so that it can just add + // an advisor to existing proxies rather than double-proxy. + } + } + + /// + /// Just return the passed in object instance + /// + /// The new object instance. + /// The name of the object. + /// + /// The passed in object instance + /// + /// + /// In case of errors. + /// + public object PostProcessBeforeInitialization(object instance, string name) + { + return instance; + } + + /// + /// Add PersistenceExceptionTranslationAdvice to candidate object if it is a match. + /// Create AOP proxy if necessary or add advice to existing advice chain. + /// + /// The new object instance. + /// The name of the object. + /// + /// The object instance to use, wrapped with either the original or a wrapped one. + /// + /// + /// In case of errors. + /// + public object PostProcessAfterInitialization(object instance, string objectName) + { + IAdvised advised = instance as IAdvised; + Type targetType; + if (advised != null) + { + targetType = advised.TargetSource.TargetType; + } + else + { + targetType = instance.GetType(); } - /// - /// Callback that supplies the owning factory to an object instance. - /// - public IObjectFactory ObjectFactory - { - set - { - IListableObjectFactory lof = value as IListableObjectFactory; - if (lof == null) - { - throw new ArgumentException("Cannot use PersistenceExceptionTranslator autodetection without IListableObjectFactory"); - } - this.persistenceExceptionTranslationAdvisor = - new PersistenceExceptionTranslationAdvisor(lof, this.repositoryAttributeType); - } - } - - public int Order - { - get { - return Int32.MaxValue; - // lowest precidence value - // This should run after all other post-processors, so that it can just add - // an advisor to existing proxies rather than double-proxy. - } - } - - /// - /// Just return the passed in object instance - /// - /// The new object instance. - /// The name of the object. - /// - /// The passed in object instance - /// - /// - /// In case of errors. - /// - public object PostProcessBeforeInitialization(object instance, string name) + if (targetType == null) { + // Can't do much here return instance; } - /// - /// Add PersistenceExceptionTranslationAdvice to candidate object if it is a match. - /// Create AOP proxy if necessary or add advice to existing advice chain. - /// - /// The new object instance. - /// The name of the object. - /// - /// The object instance to use, wrapped with either the original or a wrapped one. - /// - /// - /// In case of errors. - /// - public object PostProcessAfterInitialization(object instance, string objectName) + if (AopUtils.CanApply(this.persistenceExceptionTranslationAdvisor, targetType, ReflectionUtils.GetInterfaces(targetType))) { - IAdvised advised = instance as IAdvised; - Type targetType; if (advised != null) { - targetType = advised.TargetSource.TargetType; - } else - { - targetType = instance.GetType(); - } - if (targetType == null) - { - // Can't do much here + advised.AddAdvisor(this.persistenceExceptionTranslationAdvisor); return instance; } - - if (AopUtils.CanApply(this.persistenceExceptionTranslationAdvisor, targetType, ReflectionUtils.GetInterfaces(targetType))) + else { - if (advised != null) - { - advised.AddAdvisor(this.persistenceExceptionTranslationAdvisor); - return instance; - } - else - { - ProxyFactory proxyFactory = new ProxyFactory(instance); - // copy our properties inherited from ProxyConfig - proxyFactory.CopyFrom(this); - proxyFactory.AddAdvisor(this.persistenceExceptionTranslationAdvisor); - return proxyFactory.GetProxy(); - } - } else - { - return instance; + ProxyFactory proxyFactory = new ProxyFactory(instance); + // copy our properties inherited from ProxyConfig + proxyFactory.CopyFrom(this); + proxyFactory.AddAdvisor(this.persistenceExceptionTranslationAdvisor); + return proxyFactory.GetProxy(); } } + else + { + return instance; + } } } diff --git a/src/Spring/Spring.Data/Dao/CannotAcquireLockException.cs b/src/Spring/Spring.Data/Dao/CannotAcquireLockException.cs index 64917b29..04bdc6a0 100644 --- a/src/Spring/Spring.Data/Dao/CannotAcquireLockException.cs +++ b/src/Spring/Spring.Data/Dao/CannotAcquireLockException.cs @@ -20,53 +20,56 @@ using System.Runtime.Serialization; -namespace Spring.Dao +namespace Spring.Dao; + +/// +/// Exception thrown on failure to aquire a lock during an update i.e a select for +/// update statement. +/// +/// +///

+/// This exception will be thrown either by O/R mapping tools or by custom DAO +/// implementations. +///

+///
+/// Rod Johnson +/// Griffin Caprio (.NET) +[Serializable] +public class CannotAcquireLockException : PessimisticLockingFailureException { - /// - /// Exception thrown on failure to aquire a lock during an update i.e a select for - /// update statement. - /// - /// - ///

- /// This exception will be thrown either by O/R mapping tools or by custom DAO - /// implementations. - ///

- ///
- /// Rod Johnson - /// Griffin Caprio (.NET) - [Serializable] - public class CannotAcquireLockException : PessimisticLockingFailureException - { - /// - /// Creates a new instance of the - /// class. - /// - public CannotAcquireLockException() {} + /// + /// Creates a new instance of the + /// class. + /// + public CannotAcquireLockException() { } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - public CannotAcquireLockException( string message ) : base( message ) {} + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + public CannotAcquireLockException(string message) : base(message) { } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception (from the underlying data access API, such as ADO.NET). - /// - public CannotAcquireLockException( string message, Exception rootCause) - : base( message , rootCause ) {} + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception (from the underlying data access API, such as ADO.NET). + /// + public CannotAcquireLockException(string message, Exception rootCause) + : base(message, rootCause) + { + } - /// - protected CannotAcquireLockException( - SerializationInfo info, StreamingContext context ) : base( info, context ) {} - } + /// + protected CannotAcquireLockException( + SerializationInfo info, StreamingContext context) : base(info, context) + { + } } diff --git a/src/Spring/Spring.Data/Dao/CannotSerializeTransactionException.cs b/src/Spring/Spring.Data/Dao/CannotSerializeTransactionException.cs index fe0d987f..89160433 100644 --- a/src/Spring/Spring.Data/Dao/CannotSerializeTransactionException.cs +++ b/src/Spring/Spring.Data/Dao/CannotSerializeTransactionException.cs @@ -20,53 +20,56 @@ using System.Runtime.Serialization; -namespace Spring.Dao +namespace Spring.Dao; + +/// +/// Exception thrown on failure to complete a transaction in serialized mode due to +/// update conflicts. +/// +/// +///

+/// This exception will be thrown either by O/R mapping tools or by custom DAO +/// implementations. +///

+///
+/// Rod Johnson +/// Griffin Caprio (.NET) +[Serializable] +public class CannotSerializeTransactionException : PessimisticLockingFailureException { - /// - /// Exception thrown on failure to complete a transaction in serialized mode due to - /// update conflicts. - /// - /// - ///

- /// This exception will be thrown either by O/R mapping tools or by custom DAO - /// implementations. - ///

- ///
- /// Rod Johnson - /// Griffin Caprio (.NET) - [Serializable] - public class CannotSerializeTransactionException : PessimisticLockingFailureException - { - /// - /// Creates a new instance of the - /// class. - /// - public CannotSerializeTransactionException() {} + /// + /// Creates a new instance of the + /// class. + /// + public CannotSerializeTransactionException() { } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - public CannotSerializeTransactionException( string message ) : base( message ) {} + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + public CannotSerializeTransactionException(string message) : base(message) { } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception (from the underlying data access API, such as ADO.NET). - /// - public CannotSerializeTransactionException( string message, Exception rootCause) - : base( message , rootCause ) {} + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception (from the underlying data access API, such as ADO.NET). + /// + public CannotSerializeTransactionException(string message, Exception rootCause) + : base(message, rootCause) + { + } - /// - protected CannotSerializeTransactionException( - SerializationInfo info, StreamingContext context ) : base( info, context ) {} - } + /// + protected CannotSerializeTransactionException( + SerializationInfo info, StreamingContext context) : base(info, context) + { + } } diff --git a/src/Spring/Spring.Data/Dao/CleanupFailureDataAccessException.cs b/src/Spring/Spring.Data/Dao/CleanupFailureDataAccessException.cs index 33a4472e..64faf557 100644 --- a/src/Spring/Spring.Data/Dao/CleanupFailureDataAccessException.cs +++ b/src/Spring/Spring.Data/Dao/CleanupFailureDataAccessException.cs @@ -20,58 +20,61 @@ using System.Runtime.Serialization; -namespace Spring.Dao +namespace Spring.Dao; + +/// +/// Exception thrown when we couldn't cleanup after a data access operation, +/// but the actual operation went OK. +/// +/// +///

+/// For example, this exception or a subclass might be thrown if an ADO.NET +/// connection couldn't be closed after it had been used successfully. +///

+///

+/// Note that data access code might perform resource cleanup in a +/// finally block and therefore log cleanup failure rather than rethrow it, +/// to keep the original data access exception, if any. +///

+///
+/// Rod Johnson +/// Griffin Caprio (.NET) +[Serializable] +public class CleanupFailureDataAccessException : NonTransientDataAccessException { - /// - /// Exception thrown when we couldn't cleanup after a data access operation, - /// but the actual operation went OK. - /// - /// - ///

- /// For example, this exception or a subclass might be thrown if an ADO.NET - /// connection couldn't be closed after it had been used successfully. - ///

- ///

- /// Note that data access code might perform resource cleanup in a - /// finally block and therefore log cleanup failure rather than rethrow it, - /// to keep the original data access exception, if any. - ///

- ///
- /// Rod Johnson - /// Griffin Caprio (.NET) - [Serializable] - public class CleanupFailureDataAccessException : NonTransientDataAccessException - { - /// - /// Creates a new instance of the - /// class. - /// - public CleanupFailureDataAccessException() {} + /// + /// Creates a new instance of the + /// class. + /// + public CleanupFailureDataAccessException() { } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - public CleanupFailureDataAccessException( string message ) : base( message ) {} + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + public CleanupFailureDataAccessException(string message) : base(message) { } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception (from the underlying data access API, such as ADO.NET). - /// - public CleanupFailureDataAccessException( string message, Exception rootCause) - : base( message , rootCause ) {} + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception (from the underlying data access API, such as ADO.NET). + /// + public CleanupFailureDataAccessException(string message, Exception rootCause) + : base(message, rootCause) + { + } - /// - protected CleanupFailureDataAccessException( - SerializationInfo info, StreamingContext context ) : base( info, context ) {} - } + /// + protected CleanupFailureDataAccessException( + SerializationInfo info, StreamingContext context) : base(info, context) + { + } } diff --git a/src/Spring/Spring.Data/Dao/ConcurrencyFailureException.cs b/src/Spring/Spring.Data/Dao/ConcurrencyFailureException.cs index d90b3d0e..f4f004c5 100644 --- a/src/Spring/Spring.Data/Dao/ConcurrencyFailureException.cs +++ b/src/Spring/Spring.Data/Dao/ConcurrencyFailureException.cs @@ -20,54 +20,57 @@ using System.Runtime.Serialization; -namespace Spring.Dao +namespace Spring.Dao; + +/// +/// Exception thrown on concurrency failure. This exception should be +/// sublassed to indicate the type of failure - optimistic locking, +/// failure to acquire lock, etc. +/// +/// +///

+/// This exception will be thrown either by O/R mapping tools or by custom DAO +/// implementations. +///

+///
+/// Thomas Risberg +/// Griffin Caprio (.NET) +[Serializable] +public class ConcurrencyFailureException : TransientDataAccessException { /// - /// Exception thrown on concurrency failure. This exception should be - /// sublassed to indicate the type of failure - optimistic locking, - /// failure to acquire lock, etc. + /// Creates a new instance of the + /// class. /// - /// - ///

- /// This exception will be thrown either by O/R mapping tools or by custom DAO - /// implementations. - ///

- ///
- /// Thomas Risberg - /// Griffin Caprio (.NET) - [Serializable] - public class ConcurrencyFailureException : TransientDataAccessException - { - /// - /// Creates a new instance of the - /// class. - /// - public ConcurrencyFailureException() : base("No Exception Message") {} + public ConcurrencyFailureException() : base("No Exception Message") { } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - public ConcurrencyFailureException( string message ) : base( message ) {} + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + public ConcurrencyFailureException(string message) : base(message) { } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception (from the underlying data access API, such as ADO.NET). - /// - public ConcurrencyFailureException( string message, Exception rootCause) - : base( message , rootCause ) {} + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception (from the underlying data access API, such as ADO.NET). + /// + public ConcurrencyFailureException(string message, Exception rootCause) + : base(message, rootCause) + { + } - /// - protected ConcurrencyFailureException( - SerializationInfo info, StreamingContext context ) : base( info, context ) {} - } + /// + protected ConcurrencyFailureException( + SerializationInfo info, StreamingContext context) : base(info, context) + { + } } diff --git a/src/Spring/Spring.Data/Dao/DataAccessException.cs b/src/Spring/Spring.Data/Dao/DataAccessException.cs index 4ab1f43f..0196fe30 100644 --- a/src/Spring/Spring.Data/Dao/DataAccessException.cs +++ b/src/Spring/Spring.Data/Dao/DataAccessException.cs @@ -20,46 +20,49 @@ using System.Runtime.Serialization; -namespace Spring.Dao +namespace Spring.Dao; + +/// +/// Root of the hierarchy of data access exceptions +/// +/// Rod Johnson +/// Griffin Caprio (.NET) +[Serializable] +public abstract class DataAccessException : Exception { - /// - /// Root of the hierarchy of data access exceptions - /// - /// Rod Johnson - /// Griffin Caprio (.NET) - [Serializable] - public abstract class DataAccessException : Exception - { - /// - /// Creates a new instance of the - /// class. - /// - protected DataAccessException() {} + /// + /// Creates a new instance of the + /// class. + /// + protected DataAccessException() { } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - protected DataAccessException( string message ) : base( message ) {} + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + protected DataAccessException(string message) : base(message) { } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception (from the underlying data access API, such as ADO.NET). - /// - protected DataAccessException( string message, Exception rootCause) - : base( message , rootCause ) {} + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception (from the underlying data access API, such as ADO.NET). + /// + protected DataAccessException(string message, Exception rootCause) + : base(message, rootCause) + { + } - /// - protected DataAccessException( - SerializationInfo info, StreamingContext context ) : base( info, context ) {} - } + /// + protected DataAccessException( + SerializationInfo info, StreamingContext context) : base(info, context) + { + } } diff --git a/src/Spring/Spring.Data/Dao/DataAccessResourceFailureException.cs b/src/Spring/Spring.Data/Dao/DataAccessResourceFailureException.cs index 025fdb3c..567f1ed7 100644 --- a/src/Spring/Spring.Data/Dao/DataAccessResourceFailureException.cs +++ b/src/Spring/Spring.Data/Dao/DataAccessResourceFailureException.cs @@ -20,47 +20,50 @@ using System.Runtime.Serialization; -namespace Spring.Dao +namespace Spring.Dao; + +/// +/// Data access exception thrown when a resource fails completely: +/// for example, if we can't connect to a database using ADO.NET. +/// +/// Rod Johnson +/// Griffin Caprio (.NET) +[Serializable] +public class DataAccessResourceFailureException : DataAccessException { - /// - /// Data access exception thrown when a resource fails completely: - /// for example, if we can't connect to a database using ADO.NET. - /// - /// Rod Johnson - /// Griffin Caprio (.NET) - [Serializable] - public class DataAccessResourceFailureException : DataAccessException - { - /// - /// Creates a new instance of the - /// class. - /// - public DataAccessResourceFailureException() {} + /// + /// Creates a new instance of the + /// class. + /// + public DataAccessResourceFailureException() { } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - public DataAccessResourceFailureException( string message ) : base( message ) {} + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + public DataAccessResourceFailureException(string message) : base(message) { } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception (from the underlying data access API, such as ADO.NET). - /// - public DataAccessResourceFailureException( string message, Exception rootCause) - : base( message , rootCause ) {} + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception (from the underlying data access API, such as ADO.NET). + /// + public DataAccessResourceFailureException(string message, Exception rootCause) + : base(message, rootCause) + { + } - /// - protected DataAccessResourceFailureException( - SerializationInfo info, StreamingContext context ) : base( info, context ) {} - } + /// + protected DataAccessResourceFailureException( + SerializationInfo info, StreamingContext context) : base(info, context) + { + } } diff --git a/src/Spring/Spring.Data/Dao/DataIntegrityViolationException.cs b/src/Spring/Spring.Data/Dao/DataIntegrityViolationException.cs index b624f2f9..fe1bcf6d 100644 --- a/src/Spring/Spring.Data/Dao/DataIntegrityViolationException.cs +++ b/src/Spring/Spring.Data/Dao/DataIntegrityViolationException.cs @@ -20,53 +20,56 @@ using System.Runtime.Serialization; -namespace Spring.Dao +namespace Spring.Dao; + +/// +/// Exception thrown when an attempt to insert or update data +/// results in violation of an integrity constraint. +/// +/// +///

+/// Note that this is not purely a relational concept; unique primary keys are +/// required by most database types. +///

+///
+/// Rod Johnson +/// Griffin Caprio (.NET) +[Serializable] +public class DataIntegrityViolationException : NonTransientDataAccessException { - /// - /// Exception thrown when an attempt to insert or update data - /// results in violation of an integrity constraint. - /// - /// - ///

- /// Note that this is not purely a relational concept; unique primary keys are - /// required by most database types. - ///

- ///
- /// Rod Johnson - /// Griffin Caprio (.NET) - [Serializable] - public class DataIntegrityViolationException : NonTransientDataAccessException - { - /// - /// Creates a new instance of the - /// class. - /// - public DataIntegrityViolationException() {} + /// + /// Creates a new instance of the + /// class. + /// + public DataIntegrityViolationException() { } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - public DataIntegrityViolationException( string message ) : base( message ) {} + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + public DataIntegrityViolationException(string message) : base(message) { } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception (from the underlying data access API, such as ADO.NET). - /// - public DataIntegrityViolationException( string message, Exception rootCause) - : base( message , rootCause ) {} + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception (from the underlying data access API, such as ADO.NET). + /// + public DataIntegrityViolationException(string message, Exception rootCause) + : base(message, rootCause) + { + } - /// - protected DataIntegrityViolationException( - SerializationInfo info, StreamingContext context ) : base( info, context ) {} - } + /// + protected DataIntegrityViolationException( + SerializationInfo info, StreamingContext context) : base(info, context) + { + } } diff --git a/src/Spring/Spring.Data/Dao/DataRetrievalFailureException.cs b/src/Spring/Spring.Data/Dao/DataRetrievalFailureException.cs index 9719fb4e..687437e3 100644 --- a/src/Spring/Spring.Data/Dao/DataRetrievalFailureException.cs +++ b/src/Spring/Spring.Data/Dao/DataRetrievalFailureException.cs @@ -20,53 +20,56 @@ using System.Runtime.Serialization; -namespace Spring.Dao +namespace Spring.Dao; + +/// +/// Exception thrown if certain expected data could not be retrieved, e.g. +/// when looking up specific data via a known identifier. +/// +/// +///

+/// This exception will be thrown either by O/R mapping tools or by custom DAO +/// implementations. +///

+///
+/// Juergen Hoeller +/// Griffin Caprio (.NET) +[Serializable] +public class DataRetrievalFailureException : NonTransientDataAccessException { - /// - /// Exception thrown if certain expected data could not be retrieved, e.g. - /// when looking up specific data via a known identifier. - /// - /// - ///

- /// This exception will be thrown either by O/R mapping tools or by custom DAO - /// implementations. - ///

- ///
- /// Juergen Hoeller - /// Griffin Caprio (.NET) - [Serializable] - public class DataRetrievalFailureException : NonTransientDataAccessException - { - /// - /// Creates a new instance of the - /// class. - /// - public DataRetrievalFailureException() {} + /// + /// Creates a new instance of the + /// class. + /// + public DataRetrievalFailureException() { } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - public DataRetrievalFailureException( string message ) : base( message ) {} + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + public DataRetrievalFailureException(string message) : base(message) { } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception (from the underlying data access API, such as ADO.NET). - /// - public DataRetrievalFailureException( string message, Exception rootCause) - : base( message , rootCause ) {} + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception (from the underlying data access API, such as ADO.NET). + /// + public DataRetrievalFailureException(string message, Exception rootCause) + : base(message, rootCause) + { + } - /// - protected DataRetrievalFailureException( - SerializationInfo info, StreamingContext context ) : base( info, context ) {} - } + /// + protected DataRetrievalFailureException( + SerializationInfo info, StreamingContext context) : base(info, context) + { + } } diff --git a/src/Spring/Spring.Data/Dao/DeadlockLoserDataAccessException.cs b/src/Spring/Spring.Data/Dao/DeadlockLoserDataAccessException.cs index fce35742..085d8d25 100644 --- a/src/Spring/Spring.Data/Dao/DeadlockLoserDataAccessException.cs +++ b/src/Spring/Spring.Data/Dao/DeadlockLoserDataAccessException.cs @@ -20,47 +20,50 @@ using System.Runtime.Serialization; -namespace Spring.Dao +namespace Spring.Dao; + +/// +/// Generic exception thrown when the current process was +/// a deadlock loser, and its transaction rolled back. +/// +/// Rod Johnson +/// Griffin Caprio (.NET) +[Serializable] +public class DeadlockLoserDataAccessException : PessimisticLockingFailureException { - /// - /// Generic exception thrown when the current process was - /// a deadlock loser, and its transaction rolled back. - /// - /// Rod Johnson - /// Griffin Caprio (.NET) - [Serializable] - public class DeadlockLoserDataAccessException : PessimisticLockingFailureException - { - /// - /// Creates a new instance of the - /// class. - /// - public DeadlockLoserDataAccessException() {} + /// + /// Creates a new instance of the + /// class. + /// + public DeadlockLoserDataAccessException() { } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - public DeadlockLoserDataAccessException( string message ) : base( message ) {} + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + public DeadlockLoserDataAccessException(string message) : base(message) { } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception (from the underlying data access API, such as ADO.NET). - /// - public DeadlockLoserDataAccessException( string message, Exception rootCause) - : base( message , rootCause ) {} + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception (from the underlying data access API, such as ADO.NET). + /// + public DeadlockLoserDataAccessException(string message, Exception rootCause) + : base(message, rootCause) + { + } - /// - protected DeadlockLoserDataAccessException( - SerializationInfo info, StreamingContext context ) : base( info, context ) {} - } + /// + protected DeadlockLoserDataAccessException( + SerializationInfo info, StreamingContext context) : base(info, context) + { + } } diff --git a/src/Spring/Spring.Data/Dao/EmptyResultDataAccessException.cs b/src/Spring/Spring.Data/Dao/EmptyResultDataAccessException.cs index 1fd4fa2a..314fff7e 100644 --- a/src/Spring/Spring.Data/Dao/EmptyResultDataAccessException.cs +++ b/src/Spring/Spring.Data/Dao/EmptyResultDataAccessException.cs @@ -20,69 +20,66 @@ using System.Runtime.Serialization; -namespace Spring.Dao +namespace Spring.Dao; + +/// +/// Data access exception thrown when a result was not of the expected size, +/// for example when expecting a single row but getting 0 or more than 1 rows. +/// +/// Mark Pollack (.NET) +/// Juergen Hoeller +[Serializable] +public class EmptyResultDataAccessException : IncorrectResultSizeDataAccessException { - /// - /// Data access exception thrown when a result was not of the expected size, - /// for example when expecting a single row but getting 0 or more than 1 rows. - /// - /// Mark Pollack (.NET) - /// Juergen Hoeller - [Serializable] - public class EmptyResultDataAccessException : IncorrectResultSizeDataAccessException + /// + /// Initializes a new instance of the class. + /// + public EmptyResultDataAccessException() : base() { + } - /// - /// Initializes a new instance of the class. - /// - public EmptyResultDataAccessException() : base () - { - } + /// + /// Initializes a new instance of the class. + /// + /// The message. + public EmptyResultDataAccessException(string message) : base(message) + { + } - /// - /// Initializes a new instance of the class. - /// - /// The message. - public EmptyResultDataAccessException(string message) : base (message) - { - } + /// + /// Initializes a new instance of the class. + /// + /// The message. + /// The inner exception. + public EmptyResultDataAccessException(string message, Exception innerException) : base(message, innerException) + { + } - /// - /// Initializes a new instance of the class. - /// - /// The message. - /// The inner exception. - public EmptyResultDataAccessException(string message, Exception innerException) : base (message, innerException) - { - } + /// + /// Creates a new instance of the + /// class. + /// + /// The expected size. + public EmptyResultDataAccessException(int expectedSize) : base(expectedSize, 0) + { + } - /// - /// Creates a new instance of the - /// class. - /// - /// The expected size. - public EmptyResultDataAccessException(int expectedSize) : base (expectedSize, 0) - { - } + /// + /// Creates a new instance of the + /// class. + /// + /// A message about the exception. + /// The expected size. + public EmptyResultDataAccessException(string message, int expectedSize) : base(message, expectedSize, 0) { } - /// - /// Creates a new instance of the - /// class. - /// - /// A message about the exception. - /// The expected size. - public EmptyResultDataAccessException( string message, int expectedSize ) : base( message, expectedSize, 0 ) {} - - - /// - /// Initializes a new instance of the class. - /// - /// The that holds the serialized object data about the exception being thrown. - /// The that contains contextual information about the source or destination. - /// The parameter is . - /// The class name is or is zero (0). - protected EmptyResultDataAccessException( SerializationInfo info, StreamingContext context ) : base( info, context ) - { - } + /// + /// Initializes a new instance of the class. + /// + /// The that holds the serialized object data about the exception being thrown. + /// The that contains contextual information about the source or destination. + /// The parameter is . + /// The class name is or is zero (0). + protected EmptyResultDataAccessException(SerializationInfo info, StreamingContext context) : base(info, context) + { } } diff --git a/src/Spring/Spring.Data/Dao/IncorrectResultSizeDataAccessException.cs b/src/Spring/Spring.Data/Dao/IncorrectResultSizeDataAccessException.cs index 47a0b228..195d41f8 100644 --- a/src/Spring/Spring.Data/Dao/IncorrectResultSizeDataAccessException.cs +++ b/src/Spring/Spring.Data/Dao/IncorrectResultSizeDataAccessException.cs @@ -20,124 +20,123 @@ using System.Runtime.Serialization; -namespace Spring.Dao +namespace Spring.Dao; + +/// +/// Data access exception thrown when a result was not of the expected size, +/// for example when expecting a single row but getting 0 or more than 1 rows. +/// +/// Juergen Hoeller +/// Griffin Caprio (.NET) +[Serializable] +public class IncorrectResultSizeDataAccessException : InvalidDataAccessApiUsageException, ISerializable { - /// - /// Data access exception thrown when a result was not of the expected size, - /// for example when expecting a single row but getting 0 or more than 1 rows. - /// - /// Juergen Hoeller - /// Griffin Caprio (.NET) - [Serializable] - public class IncorrectResultSizeDataAccessException : InvalidDataAccessApiUsageException, ISerializable - { - private int _expectedSize; - private int _actualSize; + private int _expectedSize; + private int _actualSize; - /// Return the expected result size. - public virtual int ExpectedSize - { - get - { - return _expectedSize; - } - } - - /// Return the actual result size (or -1 if unknown). - public virtual int ActualSize - { - get - { - return _actualSize; - } - } - - /// - /// Creates a new instance of the - /// class. - /// - public IncorrectResultSizeDataAccessException() : this( -1, -1 ) {} - - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - public IncorrectResultSizeDataAccessException( string message ) : this( message, -1, -1 ) - { - } - - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception (from the underlying data access API, such as ADO.NET). - /// - public IncorrectResultSizeDataAccessException( string message, Exception rootCause ) - : base( message, rootCause ) - { - _expectedSize = -1; - _actualSize = -1; - } - - /// - /// Creates a new instance of the - /// class. - /// - /// The expected result size. - /// The actual result size (or -1 if unknown). - public IncorrectResultSizeDataAccessException( int expectedSize, int actualSize ) - : this ( "Incorrect result size: expected " + expectedSize + ", actual " + actualSize, expectedSize, actualSize) - { - } - - /// - /// Creates a new instance of the - /// class. - /// > - /// - /// A message about the exception. - /// - /// The expected result size. - /// The actual result size (or -1 if unknown). - public IncorrectResultSizeDataAccessException( string message, int expectedSize, int actualSize ) - : base( message ) - { - this._expectedSize = expectedSize; - this._actualSize = actualSize; - } - - /// - /// Initializes a new instance of the class. - /// - /// A message about the exception - /// The expected result size. - public IncorrectResultSizeDataAccessException(string message, int expectedSize) - : base(message) + /// Return the expected result size. + public virtual int ExpectedSize + { + get { - this._expectedSize = expectedSize; - this._actualSize = -1; + return _expectedSize; } + } - /// - protected IncorrectResultSizeDataAccessException( SerializationInfo info, StreamingContext context ) : base( info, context ) - { - _expectedSize = info.GetInt32( "expectedSize" ); - _actualSize = info.GetInt32( "actualSize" ); - } + /// Return the actual result size (or -1 if unknown). + public virtual int ActualSize + { + get + { + return _actualSize; + } + } - /// - public override void GetObjectData(SerializationInfo info, StreamingContext context) - { - info.AddValue( "expectedSize", _expectedSize ); - info.AddValue( "actualSize", _actualSize ); - base.GetObjectData( info, context ); - } - } + /// + /// Creates a new instance of the + /// class. + /// + public IncorrectResultSizeDataAccessException() : this(-1, -1) { } + + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + public IncorrectResultSizeDataAccessException(string message) : this(message, -1, -1) + { + } + + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception (from the underlying data access API, such as ADO.NET). + /// + public IncorrectResultSizeDataAccessException(string message, Exception rootCause) + : base(message, rootCause) + { + _expectedSize = -1; + _actualSize = -1; + } + + /// + /// Creates a new instance of the + /// class. + /// + /// The expected result size. + /// The actual result size (or -1 if unknown). + public IncorrectResultSizeDataAccessException(int expectedSize, int actualSize) + : this("Incorrect result size: expected " + expectedSize + ", actual " + actualSize, expectedSize, actualSize) + { + } + + /// + /// Creates a new instance of the + /// class. + /// > + /// + /// A message about the exception. + /// + /// The expected result size. + /// The actual result size (or -1 if unknown). + public IncorrectResultSizeDataAccessException(string message, int expectedSize, int actualSize) + : base(message) + { + this._expectedSize = expectedSize; + this._actualSize = actualSize; + } + + /// + /// Initializes a new instance of the class. + /// + /// A message about the exception + /// The expected result size. + public IncorrectResultSizeDataAccessException(string message, int expectedSize) + : base(message) + { + this._expectedSize = expectedSize; + this._actualSize = -1; + } + + /// + protected IncorrectResultSizeDataAccessException(SerializationInfo info, StreamingContext context) : base(info, context) + { + _expectedSize = info.GetInt32("expectedSize"); + _actualSize = info.GetInt32("actualSize"); + } + + /// + public override void GetObjectData(SerializationInfo info, StreamingContext context) + { + info.AddValue("expectedSize", _expectedSize); + info.AddValue("actualSize", _actualSize); + base.GetObjectData(info, context); + } } diff --git a/src/Spring/Spring.Data/Dao/IncorrectUpdateSemanticsDataAccessException.cs b/src/Spring/Spring.Data/Dao/IncorrectUpdateSemanticsDataAccessException.cs index c03f64f2..10f22819 100644 --- a/src/Spring/Spring.Data/Dao/IncorrectUpdateSemanticsDataAccessException.cs +++ b/src/Spring/Spring.Data/Dao/IncorrectUpdateSemanticsDataAccessException.cs @@ -20,61 +20,64 @@ using System.Runtime.Serialization; -namespace Spring.Dao +namespace Spring.Dao; + +/// +/// Data access exception thrown when something unintended appears to have +/// happened with an update, but the transaction hasn't already been rolled back. +/// +/// +///

+/// Thrown, for example, when we wanted to update 1 row in an RDBMS but actually +/// updated 3. +///

+///
+/// Rod Johnson +/// Griffin Caprio (.NET) +[Serializable] +public abstract class IncorrectUpdateSemanticsDataAccessException + : InvalidDataAccessResourceUsageException { - /// - /// Data access exception thrown when something unintended appears to have - /// happened with an update, but the transaction hasn't already been rolled back. - /// - /// - ///

- /// Thrown, for example, when we wanted to update 1 row in an RDBMS but actually - /// updated 3. - ///

- ///
- /// Rod Johnson - /// Griffin Caprio (.NET) - [Serializable] - public abstract class IncorrectUpdateSemanticsDataAccessException - : InvalidDataAccessResourceUsageException - { - /// Return whether or not data was updated. - /// - /// True if data was updated (as opposed to being incorrectly - /// updated). If this property returns false, there's nothing to roll back. - /// - public abstract bool DataWasUpdated { get; } + /// Return whether or not data was updated. + /// + /// True if data was updated (as opposed to being incorrectly + /// updated). If this property returns false, there's nothing to roll back. + /// + public abstract bool DataWasUpdated { get; } - /// - /// Creates a new instance of the - /// class. - /// - protected IncorrectUpdateSemanticsDataAccessException() {} + /// + /// Creates a new instance of the + /// class. + /// + protected IncorrectUpdateSemanticsDataAccessException() { } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - protected IncorrectUpdateSemanticsDataAccessException( string message ) : base( message ) {} + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + protected IncorrectUpdateSemanticsDataAccessException(string message) : base(message) { } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception (from the underlying data access API, such as ADO.NET). - /// - protected IncorrectUpdateSemanticsDataAccessException( string message, Exception rootCause) - : base( message , rootCause ) {} + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception (from the underlying data access API, such as ADO.NET). + /// + protected IncorrectUpdateSemanticsDataAccessException(string message, Exception rootCause) + : base(message, rootCause) + { + } - /// - protected IncorrectUpdateSemanticsDataAccessException( - SerializationInfo info, StreamingContext context ) : base( info, context ) {} - } + /// + protected IncorrectUpdateSemanticsDataAccessException( + SerializationInfo info, StreamingContext context) : base(info, context) + { + } } diff --git a/src/Spring/Spring.Data/Dao/InvalidDataAccessApiUsageException.cs b/src/Spring/Spring.Data/Dao/InvalidDataAccessApiUsageException.cs index 64e7bdec..0698530c 100644 --- a/src/Spring/Spring.Data/Dao/InvalidDataAccessApiUsageException.cs +++ b/src/Spring/Spring.Data/Dao/InvalidDataAccessApiUsageException.cs @@ -20,53 +20,56 @@ using System.Runtime.Serialization; -namespace Spring.Dao +namespace Spring.Dao; + +/// +/// Exception thrown on incorrect usage of the API, such as failing to "compile" a query +/// object that needed compilation before execution. +/// +/// +///

+/// This represents a problem in our data access framework, not the underlying data access +/// infrastructure. +///

+///
+/// Rod Johnson +/// Griffin Caprio (.NET) +[Serializable] +public class InvalidDataAccessApiUsageException : NonTransientDataAccessException { - /// - /// Exception thrown on incorrect usage of the API, such as failing to "compile" a query - /// object that needed compilation before execution. - /// - /// - ///

- /// This represents a problem in our data access framework, not the underlying data access - /// infrastructure. - ///

- ///
- /// Rod Johnson - /// Griffin Caprio (.NET) - [Serializable] - public class InvalidDataAccessApiUsageException : NonTransientDataAccessException - { - /// - /// Creates a new instance of the - /// class. - /// - public InvalidDataAccessApiUsageException() {} + /// + /// Creates a new instance of the + /// class. + /// + public InvalidDataAccessApiUsageException() { } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - public InvalidDataAccessApiUsageException( string message ) : base( message ) {} + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + public InvalidDataAccessApiUsageException(string message) : base(message) { } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception (from the underlying data access API, such as ADO.NET). - /// - public InvalidDataAccessApiUsageException( string message, Exception rootCause) - : base( message , rootCause ) {} + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception (from the underlying data access API, such as ADO.NET). + /// + public InvalidDataAccessApiUsageException(string message, Exception rootCause) + : base(message, rootCause) + { + } - /// - protected InvalidDataAccessApiUsageException( - SerializationInfo info, StreamingContext context ) : base( info, context ) {} - } + /// + protected InvalidDataAccessApiUsageException( + SerializationInfo info, StreamingContext context) : base(info, context) + { + } } diff --git a/src/Spring/Spring.Data/Dao/InvalidDataAccessResourceUsageException.cs b/src/Spring/Spring.Data/Dao/InvalidDataAccessResourceUsageException.cs index fa4995e8..57490ef2 100644 --- a/src/Spring/Spring.Data/Dao/InvalidDataAccessResourceUsageException.cs +++ b/src/Spring/Spring.Data/Dao/InvalidDataAccessResourceUsageException.cs @@ -20,52 +20,55 @@ using System.Runtime.Serialization; -namespace Spring.Dao +namespace Spring.Dao; + +/// +/// Root for exceptions thrown when we use a data access resource incorrectly. +/// +/// +///

+/// Thrown for example on specifying bad SQL when using a RDBMS. +/// Resource-specific subclasses will probably be supplied by data access packages. +///

+///
+/// Rod Johnson +/// Griffin Caprio (.NET) +[Serializable] +public class InvalidDataAccessResourceUsageException : DataAccessException { - /// - /// Root for exceptions thrown when we use a data access resource incorrectly. - /// - /// - ///

- /// Thrown for example on specifying bad SQL when using a RDBMS. - /// Resource-specific subclasses will probably be supplied by data access packages. - ///

- ///
- /// Rod Johnson - /// Griffin Caprio (.NET) - [Serializable] - public class InvalidDataAccessResourceUsageException : DataAccessException - { - /// - /// Creates a new instance of the - /// class. - /// - public InvalidDataAccessResourceUsageException() {} + /// + /// Creates a new instance of the + /// class. + /// + public InvalidDataAccessResourceUsageException() { } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - public InvalidDataAccessResourceUsageException( string message ) : base( message ) {} + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + public InvalidDataAccessResourceUsageException(string message) : base(message) { } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception (from the underlying data access API, such as ADO.NET). - /// - public InvalidDataAccessResourceUsageException( string message, Exception rootCause) - : base( message , rootCause ) {} + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception (from the underlying data access API, such as ADO.NET). + /// + public InvalidDataAccessResourceUsageException(string message, Exception rootCause) + : base(message, rootCause) + { + } - /// - protected InvalidDataAccessResourceUsageException( - SerializationInfo info, StreamingContext context ) : base( info, context ) {} - } -} + /// + protected InvalidDataAccessResourceUsageException( + SerializationInfo info, StreamingContext context) : base(info, context) + { + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Data/Dao/NonTransientDataAccessException.cs b/src/Spring/Spring.Data/Dao/NonTransientDataAccessException.cs index f79d2333..11014b2a 100644 --- a/src/Spring/Spring.Data/Dao/NonTransientDataAccessException.cs +++ b/src/Spring/Spring.Data/Dao/NonTransientDataAccessException.cs @@ -20,48 +20,51 @@ using System.Runtime.Serialization; -namespace Spring.Dao +namespace Spring.Dao; + +/// +/// Root of the hierarchy of data access exception that are considered non-transient - +/// where a retry of the same operation would fail unless the cause of the Exception is +/// corrected. +/// +/// Thomas Risberg +/// Mark Pollack (.NET) +[Serializable] +public abstract class NonTransientDataAccessException : DataAccessException { /// - /// Root of the hierarchy of data access exception that are considered non-transient - - /// where a retry of the same operation would fail unless the cause of the Exception is - /// corrected. + /// Creates a new instance of the + /// class. /// - /// Thomas Risberg - /// Mark Pollack (.NET) - [Serializable] - public abstract class NonTransientDataAccessException : DataAccessException - { - /// - /// Creates a new instance of the - /// class. - /// - public NonTransientDataAccessException() : base("No Exception Message") {} + public NonTransientDataAccessException() : base("No Exception Message") { } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - public NonTransientDataAccessException( string message ) : base( message ) {} + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + public NonTransientDataAccessException(string message) : base(message) { } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception (from the underlying data access API, such as ADO.NET). - /// - public NonTransientDataAccessException( string message, Exception rootCause) - : base( message , rootCause ) {} + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception (from the underlying data access API, such as ADO.NET). + /// + public NonTransientDataAccessException(string message, Exception rootCause) + : base(message, rootCause) + { + } - /// - protected NonTransientDataAccessException( - SerializationInfo info, StreamingContext context ) : base( info, context ) {} - } + /// + protected NonTransientDataAccessException( + SerializationInfo info, StreamingContext context) : base(info, context) + { + } } diff --git a/src/Spring/Spring.Data/Dao/NonTransientDataAccessResourceException.cs b/src/Spring/Spring.Data/Dao/NonTransientDataAccessResourceException.cs index a4e978f0..10abc274 100644 --- a/src/Spring/Spring.Data/Dao/NonTransientDataAccessResourceException.cs +++ b/src/Spring/Spring.Data/Dao/NonTransientDataAccessResourceException.cs @@ -20,46 +20,49 @@ using System.Runtime.Serialization; -namespace Spring.Dao +namespace Spring.Dao; + +/// +/// Data access exception thrown when a resource fails completely and the failure is permanent. +/// +/// Thomas Risberg +/// Mark Pollack (.NET) +[Serializable] +public abstract class NonTransientDataAccessResourceException : NonTransientDataAccessException { /// - /// Data access exception thrown when a resource fails completely and the failure is permanent. + /// Creates a new instance of the + /// class. /// - /// Thomas Risberg - /// Mark Pollack (.NET) - [Serializable] - public abstract class NonTransientDataAccessResourceException : NonTransientDataAccessException - { - /// - /// Creates a new instance of the - /// class. - /// - public NonTransientDataAccessResourceException() : base("No Exception Message") {} + public NonTransientDataAccessResourceException() : base("No Exception Message") { } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - public NonTransientDataAccessResourceException( string message ) : base( message ) {} + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + public NonTransientDataAccessResourceException(string message) : base(message) { } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception (from the underlying data access API, such as ADO.NET). - /// - public NonTransientDataAccessResourceException( string message, Exception rootCause) - : base( message , rootCause ) {} + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception (from the underlying data access API, such as ADO.NET). + /// + public NonTransientDataAccessResourceException(string message, Exception rootCause) + : base(message, rootCause) + { + } - /// - protected NonTransientDataAccessResourceException( - SerializationInfo info, StreamingContext context ) : base( info, context ) {} - } + /// + protected NonTransientDataAccessResourceException( + SerializationInfo info, StreamingContext context) : base(info, context) + { + } } diff --git a/src/Spring/Spring.Data/Dao/ObjectOptimisticLockingFailureException.cs b/src/Spring/Spring.Data/Dao/ObjectOptimisticLockingFailureException.cs index 1382b370..0c745ad0 100644 --- a/src/Spring/Spring.Data/Dao/ObjectOptimisticLockingFailureException.cs +++ b/src/Spring/Spring.Data/Dao/ObjectOptimisticLockingFailureException.cs @@ -20,140 +20,134 @@ using System.Runtime.Serialization; -namespace Spring.Dao +namespace Spring.Dao; + +/// +/// Exception thrown on an optimistic locking violation for a mapped object. +/// Provides information about the persistent class and the identifier. +/// +/// Mark Pollack (.NET) +[Serializable] +public class ObjectOptimisticLockingFailureException : OptimisticLockingFailureException, ISerializable { + #region Fields + + private object persistentClass; + + private object identifier; + + #endregion + + #region Constructor (s) + /// - /// Exception thrown on an optimistic locking violation for a mapped object. - /// Provides information about the persistent class and the identifier. + /// Initializes a new instance of the class. /// - /// Mark Pollack (.NET) - [Serializable] - public class ObjectOptimisticLockingFailureException : OptimisticLockingFailureException, ISerializable + public ObjectOptimisticLockingFailureException() { - #region Fields - - private object persistentClass; - - private object identifier; - - #endregion - - #region Constructor (s) - - /// - /// Initializes a new instance of the class. - /// - public ObjectOptimisticLockingFailureException() - { - } - - /// - /// Initializes a new instance of the class. - /// - /// A message about the exception.. - public ObjectOptimisticLockingFailureException(string message) : base(message) - { - } - - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception from the underlying data access API - /// - public ObjectOptimisticLockingFailureException(string message, Exception rootCause) : base(message, rootCause) - { - } - - public ObjectOptimisticLockingFailureException(Type persistentClass, Object identifier) : this(persistentClass, identifier, - "Object of class [" + persistentClass.Name + "] with identifier [" + identifier + - "]: optimistic locking failed", null) - { - - } - - public ObjectOptimisticLockingFailureException( - Type persistentClass, Object identifier, String msg, Exception ex) : base(msg, ex) - { - this.persistentClass = persistentClass; - this.identifier = identifier; - } - - public ObjectOptimisticLockingFailureException(String persistentClassName, Object identifier) : this(persistentClassName, identifier, - "Object of class [" + persistentClassName + "] with identifier [" + identifier + - "]: optimistic locking failed", null) - { - - } - - public ObjectOptimisticLockingFailureException( - String persistentClassName, Object identifier, String msg, Exception ex) : base(msg, ex) - { - this.persistentClass = persistentClassName; - this.identifier = identifier; - } - - /// - protected ObjectOptimisticLockingFailureException(SerializationInfo info, StreamingContext context) : base(info, context) - { - } - - #endregion - - public Type PersistentClass - { - get { return persistentClass as Type;} - } - - public object Identifier - { - get { return identifier; } - } - - public string PersistentClassName - { - get - { - if (this.persistentClass is Type) - { - return ((Type) this.persistentClass).Name; - } - return (this.persistentClass != null ? this.persistentClass.ToString() : null); - - } - } - - - - - #region Properties - - #endregion - - #region Methods - - #endregion - - #region ISerializable Members - - /// - /// When overridden in a derived class, sets the - /// with information about the exception. - /// - /// The that holds the serialized object data about the exception being thrown. - /// The that contains contextual information about the source or destination. - /// The parameter is a null reference ( in Visual Basic). - public override void GetObjectData(SerializationInfo info, StreamingContext context) - { - info.AddValue( "persistentClass", persistentClass ); - info.AddValue( "identifier", identifier ); - base.GetObjectData( info, context ); - } - - #endregion } -} + + /// + /// Initializes a new instance of the class. + /// + /// A message about the exception.. + public ObjectOptimisticLockingFailureException(string message) : base(message) + { + } + + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception from the underlying data access API + /// + public ObjectOptimisticLockingFailureException(string message, Exception rootCause) : base(message, rootCause) + { + } + + public ObjectOptimisticLockingFailureException(Type persistentClass, Object identifier) : this(persistentClass, identifier, + "Object of class [" + persistentClass.Name + "] with identifier [" + identifier + + "]: optimistic locking failed", null) + { + } + + public ObjectOptimisticLockingFailureException( + Type persistentClass, Object identifier, String msg, Exception ex) : base(msg, ex) + { + this.persistentClass = persistentClass; + this.identifier = identifier; + } + + public ObjectOptimisticLockingFailureException(String persistentClassName, Object identifier) : this(persistentClassName, identifier, + "Object of class [" + persistentClassName + "] with identifier [" + identifier + + "]: optimistic locking failed", null) + { + } + + public ObjectOptimisticLockingFailureException( + String persistentClassName, Object identifier, String msg, Exception ex) : base(msg, ex) + { + this.persistentClass = persistentClassName; + this.identifier = identifier; + } + + /// + protected ObjectOptimisticLockingFailureException(SerializationInfo info, StreamingContext context) : base(info, context) + { + } + + #endregion + + public Type PersistentClass + { + get { return persistentClass as Type; } + } + + public object Identifier + { + get { return identifier; } + } + + public string PersistentClassName + { + get + { + if (this.persistentClass is Type) + { + return ((Type) this.persistentClass).Name; + } + + return (this.persistentClass != null ? this.persistentClass.ToString() : null); + } + } + + #region Properties + + #endregion + + #region Methods + + #endregion + + #region ISerializable Members + + /// + /// When overridden in a derived class, sets the + /// with information about the exception. + /// + /// The that holds the serialized object data about the exception being thrown. + /// The that contains contextual information about the source or destination. + /// The parameter is a null reference ( in Visual Basic). + public override void GetObjectData(SerializationInfo info, StreamingContext context) + { + info.AddValue("persistentClass", persistentClass); + info.AddValue("identifier", identifier); + base.GetObjectData(info, context); + } + + #endregion +} \ No newline at end of file diff --git a/src/Spring/Spring.Data/Dao/ObjectRetrievalFailureException.cs b/src/Spring/Spring.Data/Dao/ObjectRetrievalFailureException.cs index 4c5dc6ba..2d248514 100644 --- a/src/Spring/Spring.Data/Dao/ObjectRetrievalFailureException.cs +++ b/src/Spring/Spring.Data/Dao/ObjectRetrievalFailureException.cs @@ -20,121 +20,116 @@ using System.Runtime.Serialization; -namespace Spring.Dao +namespace Spring.Dao; + +/// +/// Exception thrown if a mapped object could not be retrieved via its identifier. +/// Provides information about the persistent class and the identifier. +/// +/// Mark Pollack (.NET) +[Serializable] +public class ObjectRetrievalFailureException : DataRetrievalFailureException { + private object persistentClass; + + private object identifier; + + #region Constructor (s) + /// - /// Exception thrown if a mapped object could not be retrieved via its identifier. - /// Provides information about the persistent class and the identifier. + /// Creates a new instance of the + /// class. /// - /// Mark Pollack (.NET) - [Serializable] - public class ObjectRetrievalFailureException : DataRetrievalFailureException + public ObjectRetrievalFailureException() { } + + /// + /// Initializes a new instance of the class. + /// + /// A message about the exception. + public ObjectRetrievalFailureException(string message) : base(message) { - private object persistentClass; + } - private object identifier; + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception from the underlying data access API + /// + public ObjectRetrievalFailureException(string message, Exception rootCause) : base(message, rootCause) + { + } - #region Constructor (s) + public ObjectRetrievalFailureException(Type persistentClass, object identifier) : this(persistentClass, identifier, "Object of class [" + persistentClass.Name + "] with identifier [" + identifier + "]: not found", null) + { + } - /// - /// Creates a new instance of the - /// class. - /// - public ObjectRetrievalFailureException() {} + public ObjectRetrievalFailureException( + Type persistentClass, Object identifier, String msg, Exception ex) : base(msg, ex) + { + this.persistentClass = persistentClass; + this.identifier = identifier; + } - /// - /// Initializes a new instance of the class. - /// - /// A message about the exception. - public ObjectRetrievalFailureException(string message) : base(message) + public ObjectRetrievalFailureException(String persistentClassName, Object identifier) : this(persistentClassName, identifier, + "Object of class [" + persistentClassName + "] with identifier [" + identifier + "]: not found", + null) + { + } + + public ObjectRetrievalFailureException( + String persistentClassName, Object identifier, String msg, Exception ex) : base(msg, ex) + { + this.persistentClass = persistentClassName; + this.identifier = identifier; + } + + /// + protected ObjectRetrievalFailureException( + SerializationInfo info, StreamingContext context) : base(info, context) + { + } + + #endregion + + public object PersistentClass + { + get { return persistentClass; } + } + + public object Identifier + { + get { return identifier; } + } + + public string PersistentClassName + { + get { - - } - - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception from the underlying data access API - /// - public ObjectRetrievalFailureException(string message, Exception rootCause) : base(message, rootCause) - { - } - - - public ObjectRetrievalFailureException(Type persistentClass, object identifier) : this(persistentClass, identifier, "Object of class [" + persistentClass.Name + "] with identifier [" + identifier + "]: not found", null) - { - } - - - public ObjectRetrievalFailureException( - Type persistentClass, Object identifier, String msg, Exception ex) : base(msg, ex) - { - this.persistentClass = persistentClass; - this.identifier = identifier; - } - - public ObjectRetrievalFailureException(String persistentClassName, Object identifier) : this(persistentClassName, identifier, - "Object of class [" + persistentClassName + "] with identifier [" + identifier + "]: not found", - null) - { - - } - - public ObjectRetrievalFailureException( - String persistentClassName, Object identifier, String msg, Exception ex) : base(msg, ex) - { - this.persistentClass = persistentClassName; - this.identifier = identifier; - } - - /// - protected ObjectRetrievalFailureException( - SerializationInfo info, StreamingContext context ) : base( info, context ) {} - - - #endregion - - public object PersistentClass - { - get { return persistentClass; } - } - - public object Identifier - { - get { return identifier; } - } - - public string PersistentClassName - { - get + if (this.persistentClass is Type) { - if (this.persistentClass is Type) - { - return ((Type) this.persistentClass).Name; - } - return (this.persistentClass != null ? this.persistentClass.ToString() : null); - + return ((Type) this.persistentClass).Name; } - } - /// - /// When overridden in a derived class, sets the - /// with information about the exception. - /// - /// The that holds the serialized object data about the exception being thrown. - /// The that contains contextual information about the source or destination. - /// The parameter is a null reference ( in Visual Basic). - public override void GetObjectData(SerializationInfo info, StreamingContext context) - { - info.AddValue( "persistentClass", persistentClass ); - info.AddValue( "identifier", identifier ); - base.GetObjectData( info, context ); + return (this.persistentClass != null ? this.persistentClass.ToString() : null); } + } + /// + /// When overridden in a derived class, sets the + /// with information about the exception. + /// + /// The that holds the serialized object data about the exception being thrown. + /// The that contains contextual information about the source or destination. + /// The parameter is a null reference ( in Visual Basic). + public override void GetObjectData(SerializationInfo info, StreamingContext context) + { + info.AddValue("persistentClass", persistentClass); + info.AddValue("identifier", identifier); + base.GetObjectData(info, context); } } diff --git a/src/Spring/Spring.Data/Dao/OptimisticLockingFailureException.cs b/src/Spring/Spring.Data/Dao/OptimisticLockingFailureException.cs index f6d93b04..354a5498 100644 --- a/src/Spring/Spring.Data/Dao/OptimisticLockingFailureException.cs +++ b/src/Spring/Spring.Data/Dao/OptimisticLockingFailureException.cs @@ -20,52 +20,55 @@ using System.Runtime.Serialization; -namespace Spring.Dao +namespace Spring.Dao; + +/// +/// Exception thrown on an optimistic locking violation. +/// +/// +///

+/// This exception will be thrown either by O/R mapping tools or by custom DAO +/// implementations. +///

+///
+/// Rod Johnson +/// Griffin Caprio (.NET) +[Serializable] +public class OptimisticLockingFailureException : ConcurrencyFailureException { - /// - /// Exception thrown on an optimistic locking violation. - /// - /// - ///

- /// This exception will be thrown either by O/R mapping tools or by custom DAO - /// implementations. - ///

- ///
- /// Rod Johnson - /// Griffin Caprio (.NET) - [Serializable] - public class OptimisticLockingFailureException : ConcurrencyFailureException - { - /// - /// Creates a new instance of the - /// class. - /// - public OptimisticLockingFailureException() {} + /// + /// Creates a new instance of the + /// class. + /// + public OptimisticLockingFailureException() { } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - public OptimisticLockingFailureException( string message ) : base( message ) {} + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + public OptimisticLockingFailureException(string message) : base(message) { } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception (from the underlying data access API, such as ADO.NET). - /// - public OptimisticLockingFailureException( string message, Exception rootCause) - : base( message , rootCause ) {} + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception (from the underlying data access API, such as ADO.NET). + /// + public OptimisticLockingFailureException(string message, Exception rootCause) + : base(message, rootCause) + { + } - /// - protected OptimisticLockingFailureException( - SerializationInfo info, StreamingContext context ) : base( info, context ) {} - } -} + /// + protected OptimisticLockingFailureException( + SerializationInfo info, StreamingContext context) : base(info, context) + { + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Data/Dao/PermissionDeniedDataAccessException.cs b/src/Spring/Spring.Data/Dao/PermissionDeniedDataAccessException.cs index ee24a0c5..30f8d84d 100644 --- a/src/Spring/Spring.Data/Dao/PermissionDeniedDataAccessException.cs +++ b/src/Spring/Spring.Data/Dao/PermissionDeniedDataAccessException.cs @@ -20,47 +20,50 @@ using System.Runtime.Serialization; -namespace Spring.Dao +namespace Spring.Dao; + +/// +/// Exception thrown when the underlyingresource denied a permission to +/// access a specific element, such as a specific database table. +/// +/// Juergen Hoeller +/// Mark Pollack (.NET) +[Serializable] +public class PermissionDeniedDataAccessException : NonTransientDataAccessException { - /// - /// Exception thrown when the underlyingresource denied a permission to - /// access a specific element, such as a specific database table. - /// - /// Juergen Hoeller - /// Mark Pollack (.NET) - [Serializable] - public class PermissionDeniedDataAccessException : NonTransientDataAccessException - { - /// - /// Creates a new instance of the - /// class. - /// - public PermissionDeniedDataAccessException() {} + /// + /// Creates a new instance of the + /// class. + /// + public PermissionDeniedDataAccessException() { } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - public PermissionDeniedDataAccessException( string message ) : base( message ) {} + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + public PermissionDeniedDataAccessException(string message) : base(message) { } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception (from the underlying data access API, such as ADO.NET). - /// - public PermissionDeniedDataAccessException( string message, Exception rootCause) - : base( message , rootCause ) {} + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception (from the underlying data access API, such as ADO.NET). + /// + public PermissionDeniedDataAccessException(string message, Exception rootCause) + : base(message, rootCause) + { + } - /// - protected PermissionDeniedDataAccessException( - SerializationInfo info, StreamingContext context ) : base( info, context ) {} - } + /// + protected PermissionDeniedDataAccessException( + SerializationInfo info, StreamingContext context) : base(info, context) + { + } } diff --git a/src/Spring/Spring.Data/Dao/PessimisticLockingFailureException.cs b/src/Spring/Spring.Data/Dao/PessimisticLockingFailureException.cs index 68981fc8..d93e15b0 100644 --- a/src/Spring/Spring.Data/Dao/PessimisticLockingFailureException.cs +++ b/src/Spring/Spring.Data/Dao/PessimisticLockingFailureException.cs @@ -20,55 +20,58 @@ using System.Runtime.Serialization; -namespace Spring.Dao +namespace Spring.Dao; + +/// +/// Exception thrown on a pessimistic locking violation. +/// +/// +/// Serves as a superclass for more specific exceptions, like +/// CannotAcquireLockException and DeadlockLoserDataAccessException +/// +/// +/// This exception will be thrown either by O/R mapping tools or by custom DAO +/// implementations. +/// +/// +/// Rod Johnson +/// Mark Pollack (.NET) +[Serializable] +public class PessimisticLockingFailureException : ConcurrencyFailureException { - /// - /// Exception thrown on a pessimistic locking violation. - /// - /// - /// Serves as a superclass for more specific exceptions, like - /// CannotAcquireLockException and DeadlockLoserDataAccessException - /// - /// - /// This exception will be thrown either by O/R mapping tools or by custom DAO - /// implementations. - /// - /// - /// Rod Johnson - /// Mark Pollack (.NET) - [Serializable] - public class PessimisticLockingFailureException : ConcurrencyFailureException - { - /// - /// Creates a new instance of the - /// class. - /// - public PessimisticLockingFailureException() {} + /// + /// Creates a new instance of the + /// class. + /// + public PessimisticLockingFailureException() { } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - public PessimisticLockingFailureException( string message ) : base( message ) {} + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + public PessimisticLockingFailureException(string message) : base(message) { } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception (from the underlying data access API, such as ADO.NET). - /// - public PessimisticLockingFailureException( string message, Exception rootCause) - : base( message , rootCause ) {} + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception (from the underlying data access API, such as ADO.NET). + /// + public PessimisticLockingFailureException(string message, Exception rootCause) + : base(message, rootCause) + { + } - /// - protected PessimisticLockingFailureException( - SerializationInfo info, StreamingContext context ) : base( info, context ) {} - } + /// + protected PessimisticLockingFailureException( + SerializationInfo info, StreamingContext context) : base(info, context) + { + } } diff --git a/src/Spring/Spring.Data/Dao/Support/ChainedPersistenceExceptionTranslator.cs b/src/Spring/Spring.Data/Dao/Support/ChainedPersistenceExceptionTranslator.cs index b8258a42..09bcb3be 100644 --- a/src/Spring/Spring.Data/Dao/Support/ChainedPersistenceExceptionTranslator.cs +++ b/src/Spring/Spring.Data/Dao/Support/ChainedPersistenceExceptionTranslator.cs @@ -22,78 +22,75 @@ using System.Collections; using Spring.Data.Support; using Spring.Util; -namespace Spring.Dao.Support +namespace Spring.Dao.Support; + +/// +/// Implementation of PersistenceExceptionTranslator that supports chaining, +/// allowing the addition of PersistenceExceptionTranslator instances in order. +/// Returns non-null on the first (if any) match. +/// +/// Rod Johnson +/// Juergen Hoeller +/// Mark Pollack (.NET) +public class ChainedPersistenceExceptionTranslator : IPersistenceExceptionTranslator { + private readonly ArrayList translatorList = new ArrayList(4); + /// - /// Implementation of PersistenceExceptionTranslator that supports chaining, - /// allowing the addition of PersistenceExceptionTranslator instances in order. - /// Returns non-null on the first (if any) match. + /// Adds the translator to the translator list. /// - /// Rod Johnson - /// Juergen Hoeller - /// Mark Pollack (.NET) - public class ChainedPersistenceExceptionTranslator : IPersistenceExceptionTranslator + /// The translator. + public void AddTranslator(IPersistenceExceptionTranslator translator) { - private readonly ArrayList translatorList = new ArrayList(4); + AssertUtils.ArgumentNotNull(translator, "PersistenceExceptionTranslator must not be null"); + this.translatorList.Add(translator); + } - /// - /// Adds the translator to the translator list. - /// - /// The translator. - public void AddTranslator(IPersistenceExceptionTranslator translator) + /// + /// Gets all registered IPersistenceExceptionTranslator as an array. + /// + /// The IPersistenceExceptionTranslators. + public IPersistenceExceptionTranslator[] Translators + { + get { - AssertUtils.ArgumentNotNull(translator, "PersistenceExceptionTranslator must not be null"); - this.translatorList.Add(translator); + return (IPersistenceExceptionTranslator[]) translatorList.ToArray(typeof(IPersistenceExceptionTranslator)); + } + } + + /// + /// Translate the given exception thrown by a persistence framework to a + /// corresponding exception from Spring's generic DataAccessException hierarchy, + /// if possible. + /// + /// The exception thrown. + /// + /// the corresponding DataAccessException (or null if the + /// exception could not be translated, as in this case it may result from + /// user code rather than an actual persistence problem) + /// + /// + /// + /// Do not translate exceptions that are not understand by this translator: + /// for example, if coming from another persistence framework, or resulting + /// from user code and unrelated to persistence. + /// + /// + /// Of particular importance is the correct translation to + /// for example on constraint violation. Implementations may use Spring ADO.NET Framework's + /// sophisticated exception translation to provide further information in the event of SQLException as a root cause. + /// + /// + /// + /// + public DataAccessException TranslateExceptionIfPossible(Exception ex) + { + DataAccessException translatedDex = null; + foreach (IPersistenceExceptionTranslator pet in translatorList) + { + translatedDex = pet.TranslateExceptionIfPossible(ex); } - - /// - /// Gets all registered IPersistenceExceptionTranslator as an array. - /// - /// The IPersistenceExceptionTranslators. - public IPersistenceExceptionTranslator[] Translators - { - get - { - return (IPersistenceExceptionTranslator[]) translatorList.ToArray(typeof (IPersistenceExceptionTranslator)); - } - } - - /// - /// Translate the given exception thrown by a persistence framework to a - /// corresponding exception from Spring's generic DataAccessException hierarchy, - /// if possible. - /// - /// The exception thrown. - /// - /// the corresponding DataAccessException (or null if the - /// exception could not be translated, as in this case it may result from - /// user code rather than an actual persistence problem) - /// - /// - /// - /// Do not translate exceptions that are not understand by this translator: - /// for example, if coming from another persistence framework, or resulting - /// from user code and unrelated to persistence. - /// - /// - /// Of particular importance is the correct translation to - /// for example on constraint violation. Implementations may use Spring ADO.NET Framework's - /// sophisticated exception translation to provide further information in the event of SQLException as a root cause. - /// - /// - /// - /// - public DataAccessException TranslateExceptionIfPossible(Exception ex) - { - DataAccessException translatedDex = null; - foreach (IPersistenceExceptionTranslator pet in translatorList) - { - translatedDex = pet.TranslateExceptionIfPossible(ex); - } - return translatedDex; - } - - + return translatedDex; } } diff --git a/src/Spring/Spring.Data/Dao/Support/DaoSupport.cs b/src/Spring/Spring.Data/Dao/Support/DaoSupport.cs index 46d8410f..7e0625e6 100644 --- a/src/Spring/Spring.Data/Dao/Support/DaoSupport.cs +++ b/src/Spring/Spring.Data/Dao/Support/DaoSupport.cs @@ -21,88 +21,85 @@ using Microsoft.Extensions.Logging; using Spring.Objects.Factory; -namespace Spring.Dao.Support +namespace Spring.Dao.Support; + +/// +/// Generic base class for DAOs, defining template methods for DAO initialization. +/// +/// +/// Extended by Spring's specific DAO support classes, such as: +/// AdoDaoSupport, HibernateDaoSupport, etc. +/// +/// Mark Pollack (.NET) +public abstract class DaoSupport : IInitializingObject { - /// - /// Generic base class for DAOs, defining template methods for DAO initialization. - /// - /// - /// Extended by Spring's specific DAO support classes, such as: - /// AdoDaoSupport, HibernateDaoSupport, etc. - /// - /// Mark Pollack (.NET) - public abstract class DaoSupport : IInitializingObject - { - #region Fields + #region Fields - #endregion + #endregion - #region Constants + #region Constants - /// - /// The shared instance for this class (and derived classes). - /// - protected static readonly ILogger log = LogManager.GetLogger(typeof (DaoSupport)); + /// + /// The shared instance for this class (and derived classes). + /// + protected static readonly ILogger log = LogManager.GetLogger(typeof(DaoSupport)); - #endregion + #endregion - #region Constructor (s) - /// - /// Initializes a new instance of the class. - /// - public DaoSupport() - { + #region Constructor (s) - } + /// + /// Initializes a new instance of the class. + /// + public DaoSupport() + { + } - #endregion + #endregion - #region Properties + #region Properties - #endregion + #endregion - #region Methods + #region Methods - /// - /// Abstract subclasses must override this to check their configuration. - /// - /// - ///

Implementors should be marked as sealed, to make it clear that - /// concrete subclasses are not supposed to override this template method themselves. - ///

- ///
- protected abstract void CheckDaoConfig(); + /// + /// Abstract subclasses must override this to check their configuration. + /// + /// + ///

Implementors should be marked as sealed, to make it clear that + /// concrete subclasses are not supposed to override this template method themselves. + ///

+ ///
+ protected abstract void CheckDaoConfig(); - /// - /// Concrete subclasses can override this for custom initialization behavior. - /// - /// - /// Gets called after population of this instance's object properties. - /// Exception thrown if InitDao fails will be rethrown as - /// a ObjectInitializationException. - /// - protected virtual void InitDao() + /// + /// Concrete subclasses can override this for custom initialization behavior. + /// + /// + /// Gets called after population of this instance's object properties. + /// Exception thrown if InitDao fails will be rethrown as + /// a ObjectInitializationException. + /// + protected virtual void InitDao() + { + } + + #endregion + + public void AfterPropertiesSet() + { + // Let abstract subclasses check their configuration. + CheckDaoConfig(); + + // Let concrete implementations initialize themselves. + try { - + InitDao(); } - - - #endregion - - public void AfterPropertiesSet() - { - // Let abstract subclasses check their configuration. - CheckDaoConfig(); - - // Let concrete implementations initialize themselves. - try - { - InitDao(); - } - catch (Exception ex) - { - throw new ObjectInitializationException("Initialization of DAO failed: " + ex.Message, ex); - } - } - } + catch (Exception ex) + { + throw new ObjectInitializationException("Initialization of DAO failed: " + ex.Message, ex); + } + } } diff --git a/src/Spring/Spring.Data/Dao/Support/DataAccessUtils.cs b/src/Spring/Spring.Data/Dao/Support/DataAccessUtils.cs index 8e08dd74..56fcc00e 100644 --- a/src/Spring/Spring.Data/Dao/Support/DataAccessUtils.cs +++ b/src/Spring/Spring.Data/Dao/Support/DataAccessUtils.cs @@ -21,60 +21,59 @@ using System.Collections; using Spring.Util; -namespace Spring.Dao.Support +namespace Spring.Dao.Support; + +/// +/// Miscellaneous utility methods for DAO implementations. +/// Useful with any data access technology. +/// +/// Mark Pollack (.NET) +public class DataAccessUtils { - /// - /// Miscellaneous utility methods for DAO implementations. - /// Useful with any data access technology. - /// - /// Mark Pollack (.NET) - public class DataAccessUtils - { + #region Constructor (s) - #region Constructor (s) - /// - /// Initializes a new instance of the class. - /// - public DataAccessUtils() - { + /// + /// Initializes a new instance of the class. + /// + public DataAccessUtils() + { + } - } + #endregion - #endregion + #region Methods - #region Methods - - public static object RequiredUniqueResultSet(IList results) - { - int size = (results != null ? results.Count : 0); - if (size == 0) - { - throw new EmptyResultDataAccessException(1); - } - if ( ! CollectionUtils.HasUniqueObject(results)) - { - throw new IncorrectResultSizeDataAccessException(1, size); - } - IEnumerator enumerator = results.GetEnumerator(); - enumerator.MoveNext(); - return enumerator.Current; - } - - /// - /// Return a translated exception if this is appropriate, or null if the exception could - /// not be translated. - /// - /// The raw exception we may wish to translate. - /// The PersistenceExceptionTranslator to use to perform the translation. - /// A translated exception if translation is possible, or or null if the exception could - /// not be translated. - public static DataAccessException TranslateIfNecessary(Exception rawException, IPersistenceExceptionTranslator pet) + public static object RequiredUniqueResultSet(IList results) + { + int size = (results != null ? results.Count : 0); + if (size == 0) { - AssertUtils.ArgumentNotNull(pet, "PersistenceExceptionTranslator must not be null"); - return pet.TranslateExceptionIfPossible(rawException); + throw new EmptyResultDataAccessException(1); } - #endregion - } + if (!CollectionUtils.HasUniqueObject(results)) + { + throw new IncorrectResultSizeDataAccessException(1, size); + } + IEnumerator enumerator = results.GetEnumerator(); + enumerator.MoveNext(); + return enumerator.Current; + } + + /// + /// Return a translated exception if this is appropriate, or null if the exception could + /// not be translated. + /// + /// The raw exception we may wish to translate. + /// The PersistenceExceptionTranslator to use to perform the translation. + /// A translated exception if translation is possible, or or null if the exception could + /// not be translated. + public static DataAccessException TranslateIfNecessary(Exception rawException, IPersistenceExceptionTranslator pet) + { + AssertUtils.ArgumentNotNull(pet, "PersistenceExceptionTranslator must not be null"); + return pet.TranslateExceptionIfPossible(rawException); + } + + #endregion } diff --git a/src/Spring/Spring.Data/Dao/Support/Generic/DataAccessUtils.cs b/src/Spring/Spring.Data/Dao/Support/Generic/DataAccessUtils.cs index 359691df..524997c4 100644 --- a/src/Spring/Spring.Data/Dao/Support/Generic/DataAccessUtils.cs +++ b/src/Spring/Spring.Data/Dao/Support/Generic/DataAccessUtils.cs @@ -20,46 +20,45 @@ using Spring.Util.Generic; -namespace Spring.Dao.Support.Generic +namespace Spring.Dao.Support.Generic; + +/// +/// Miscellaneous utility methods for DAO implementations. +/// Useful with any data access technology. +/// +/// Mark Pollack (.NET) +public class DataAccessUtils { - /// - /// Miscellaneous utility methods for DAO implementations. - /// Useful with any data access technology. - /// - /// Mark Pollack (.NET) - public class DataAccessUtils - { + #region Constructor (s) - #region Constructor (s) - /// - /// Initializes a new instance of the class. - /// - public DataAccessUtils() - { + /// + /// Initializes a new instance of the class. + /// + public DataAccessUtils() + { + } - } + #endregion - #endregion + #region Methods - #region Methods + public static T RequiredUniqueResultSet(IList results) + { + int size = (results != null ? results.Count : 0); + if (size == 0) + { + throw new EmptyResultDataAccessException(1); + } - public static T RequiredUniqueResultSet(IList results) - { - int size = (results != null ? results.Count : 0); - if (size == 0) - { - throw new EmptyResultDataAccessException(1); - } - if ( ! CollectionUtils.HasUniqueObject(results)) - { - throw new IncorrectResultSizeDataAccessException(1, size); - } - IEnumerator enumerator = results.GetEnumerator(); - enumerator.MoveNext(); - return enumerator.Current; - } + if (!CollectionUtils.HasUniqueObject(results)) + { + throw new IncorrectResultSizeDataAccessException(1, size); + } - #endregion - } + IEnumerator enumerator = results.GetEnumerator(); + enumerator.MoveNext(); + return enumerator.Current; + } + #endregion } diff --git a/src/Spring/Spring.Data/Dao/Support/IPersistenceExceptionTranslator.cs b/src/Spring/Spring.Data/Dao/Support/IPersistenceExceptionTranslator.cs index 51940f33..d2442e79 100644 --- a/src/Spring/Spring.Data/Dao/Support/IPersistenceExceptionTranslator.cs +++ b/src/Spring/Spring.Data/Dao/Support/IPersistenceExceptionTranslator.cs @@ -1,5 +1,3 @@ - - #region License /* @@ -22,48 +20,47 @@ using Spring.Data.Support; -namespace Spring.Dao.Support +namespace Spring.Dao.Support; + +/// +/// Interface implemented by Spring integrations with data access technologies +/// that throw exceptions. +/// +/// +/// This allows consistent usage of combined exception translation functionality, +/// without forcing a single translator to understand every single possible type +/// of exception. +/// +/// Rod Johnson +/// Mark Pollack (.NET) +public interface IPersistenceExceptionTranslator { /// - /// Interface implemented by Spring integrations with data access technologies - /// that throw exceptions. + /// Translate the given exception thrown by a persistence framework to a + /// corresponding exception from Spring's generic DataAccessException hierarchy, + /// if possible. /// /// - /// This allows consistent usage of combined exception translation functionality, - /// without forcing a single translator to understand every single possible type - /// of exception. + /// + /// Do not translate exceptions that are not understand by this translator: + /// for example, if coming from another persistence framework, or resulting + /// from user code and unrelated to persistence. + /// + /// + /// Of particular importance is the correct translation to + /// for example on constraint violation. Implementations may use Spring ADO.NET Framework's + /// sophisticated exception translation to provide further information in the event of SQLException as a root cause. + /// /// + /// The exception thrown. + /// the corresponding DataAccessException (or null if the + /// exception could not be translated, as in this case it may result from + /// user code rather than an actual persistence problem) + /// + /// + /// /// Rod Johnson + /// Juergen Hoeller /// Mark Pollack (.NET) - public interface IPersistenceExceptionTranslator - { - /// - /// Translate the given exception thrown by a persistence framework to a - /// corresponding exception from Spring's generic DataAccessException hierarchy, - /// if possible. - /// - /// - /// - /// Do not translate exceptions that are not understand by this translator: - /// for example, if coming from another persistence framework, or resulting - /// from user code and unrelated to persistence. - /// - /// - /// Of particular importance is the correct translation to - /// for example on constraint violation. Implementations may use Spring ADO.NET Framework's - /// sophisticated exception translation to provide further information in the event of SQLException as a root cause. - /// - /// - /// The exception thrown. - /// the corresponding DataAccessException (or null if the - /// exception could not be translated, as in this case it may result from - /// user code rather than an actual persistence problem) - /// - /// - /// - /// Rod Johnson - /// Juergen Hoeller - /// Mark Pollack (.NET) - DataAccessException TranslateExceptionIfPossible(Exception ex); - } + DataAccessException TranslateExceptionIfPossible(Exception ex); } diff --git a/src/Spring/Spring.Data/Dao/Support/PersistenceExceptionTranslationInterceptor.cs b/src/Spring/Spring.Data/Dao/Support/PersistenceExceptionTranslationInterceptor.cs index 8dc46390..a9e37b53 100644 --- a/src/Spring/Spring.Data/Dao/Support/PersistenceExceptionTranslationInterceptor.cs +++ b/src/Spring/Spring.Data/Dao/Support/PersistenceExceptionTranslationInterceptor.cs @@ -22,170 +22,169 @@ using AopAlliance.Intercept; using Spring.Objects.Factory; using Spring.Util; -namespace Spring.Dao.Support +namespace Spring.Dao.Support; + +/// +/// AOP MethodInterceptor that provides persistence exception translation +/// based on a given PersistenceExceptionTranslator. +/// +/// +/// Delegates to the given to translate +/// an Exception thrown into Spring's DataAccessException hierarchy +/// (if appropriate). +/// +/// Rod Johnson +/// Juergen Hoeller +/// Mark Pollack (.NET) +public class PersistenceExceptionTranslationInterceptor : IMethodInterceptor, IObjectFactoryAware, IInitializingObject { + private IPersistenceExceptionTranslator persistenceExceptionTranslator; + /// - /// AOP MethodInterceptor that provides persistence exception translation - /// based on a given PersistenceExceptionTranslator. + /// Initializes a new instance of the class. + /// Needs to be configured with a PersistenceExceptionTranslator afterwards. /// - /// - /// Delegates to the given to translate - /// an Exception thrown into Spring's DataAccessException hierarchy - /// (if appropriate). - /// - /// Rod Johnson - /// Juergen Hoeller - /// Mark Pollack (.NET) - public class PersistenceExceptionTranslationInterceptor : IMethodInterceptor, IObjectFactoryAware, IInitializingObject + public PersistenceExceptionTranslationInterceptor() { - private IPersistenceExceptionTranslator persistenceExceptionTranslator; + } + /// + /// Initializes a new instance of the class for the + /// given IPersistenceExceptionTranslator + /// + /// The persistence exception translator to use. + public PersistenceExceptionTranslationInterceptor(IPersistenceExceptionTranslator persistenceExceptionTranslator) + { + this.persistenceExceptionTranslator = persistenceExceptionTranslator; + } - /// - /// Initializes a new instance of the class. - /// Needs to be configured with a PersistenceExceptionTranslator afterwards. - /// - public PersistenceExceptionTranslationInterceptor() + /// + /// Initializes a new instance of the class, autodetecting + /// IPersistenceExceptionTranslators in the given object factory. + /// + /// The object factory to obtain all IPersistenceExceptionTranslators from. + public PersistenceExceptionTranslationInterceptor(IListableObjectFactory objectFactory) + { + this.persistenceExceptionTranslator = DetectPersistenceExceptionTranslators(objectFactory); + } + + /// + /// Sets the persistence exception translator. The default is to autodetect all IPersistenceExceptionTranslators + /// in the containing object factory, using them in a chain. + /// + /// The persistence exception translator. + public IPersistenceExceptionTranslator PersistenceExceptionTranslator + { + set { + AssertUtils.ArgumentNotNull(value, "IPersistenceExceptionTranslator must not be null"); + persistenceExceptionTranslator = value; } + } - - /// - /// Initializes a new instance of the class for the - /// given IPersistenceExceptionTranslator - /// - /// The persistence exception translator to use. - public PersistenceExceptionTranslationInterceptor(IPersistenceExceptionTranslator persistenceExceptionTranslator) - { - this.persistenceExceptionTranslator = persistenceExceptionTranslator; - } - - /// - /// Initializes a new instance of the class, autodetecting - /// IPersistenceExceptionTranslators in the given object factory. - /// - /// The object factory to obtain all IPersistenceExceptionTranslators from. - public PersistenceExceptionTranslationInterceptor(IListableObjectFactory objectFactory) - { - this.persistenceExceptionTranslator = DetectPersistenceExceptionTranslators(objectFactory); - } - - - /// - /// Sets the persistence exception translator. The default is to autodetect all IPersistenceExceptionTranslators - /// in the containing object factory, using them in a chain. - /// - /// The persistence exception translator. - public IPersistenceExceptionTranslator PersistenceExceptionTranslator - { - set - { - AssertUtils.ArgumentNotNull(value, "IPersistenceExceptionTranslator must not be null"); - persistenceExceptionTranslator = value; - } - } - - - /// - /// Callback that supplies the owning factory to an object instance. - /// - /// - /// Owning - /// (may not be ). The object can immediately - /// call methods on the factory. - /// - /// - ///

- /// Invoked after population of normal object properties but before an init - /// callback like 's - /// - /// method or a custom init-method. - ///

- ///
- /// - /// In case of initialization errors. - /// - public IObjectFactory ObjectFactory - { - set - { - if (this.persistenceExceptionTranslator == null) - { - // No explicit exception translator specified - perform autodetection. - IListableObjectFactory owningFactory = value as IListableObjectFactory; - if (owningFactory == null) - { - throw new ArgumentException("Cannot use IPersistenceExceptionTranslator autodetection without IListableObjectFactory"); - } - this.persistenceExceptionTranslator = DetectPersistenceExceptionTranslators(owningFactory); - } - } - } - - /// - /// Ensures that the property PersistenceExceptionTranslator has been set. - /// Invoked by an - /// after it has injected all of an object's dependencies. - /// - /// - /// In the event of misconfiguration (such as the failure to set a - /// required property) or if initialization fails. - /// - public void AfterPropertiesSet() + /// + /// Callback that supplies the owning factory to an object instance. + /// + /// + /// Owning + /// (may not be ). The object can immediately + /// call methods on the factory. + /// + /// + ///

+ /// Invoked after population of normal object properties but before an init + /// callback like 's + /// + /// method or a custom init-method. + ///

+ ///
+ /// + /// In case of initialization errors. + /// + public IObjectFactory ObjectFactory + { + set { if (this.persistenceExceptionTranslator == null) { - throw new ArgumentException("Property 'PersistenceExceptionTranslator' is required"); - } - } - - /// - /// Detects the petsistence exception translators in the given object factory. - /// - /// The object factory for obtaining all IPersistenceExceptionTranslators. - /// A chained IPersistenceExceptionTranslator, combining all PersistenceExceptionTranslators found in the factory - /// - /// - protected IPersistenceExceptionTranslator DetectPersistenceExceptionTranslators(IListableObjectFactory objectFactory) - { - // Find all translators, being careful not to activate FactoryObjects. - IDictionary pets = - ObjectFactoryUtils.ObjectsOfTypeIncludingAncestors(objectFactory, - typeof (IPersistenceExceptionTranslator), false, - false); - if (pets.Count == 0) - { - throw new InvalidOperationException("No persistence exception translators found in container. Cannot perform exception translation."); - } - - ChainedPersistenceExceptionTranslator cpet = new ChainedPersistenceExceptionTranslator(); - foreach (KeyValuePair pet in pets) - { - cpet.AddTranslator((IPersistenceExceptionTranslator)pet.Value); - } - return cpet; - } - - /// - /// Return a translated exception if this is appropriate, otherwise rethrow the original exception. - /// - /// - /// - public object Invoke(IMethodInvocation invocation) - { - try - { - return invocation.Proceed(); - } catch (Exception ex) - { - DataAccessException dex = DataAccessUtils.TranslateIfNecessary(ex, persistenceExceptionTranslator); - if (dex == null) + // No explicit exception translator specified - perform autodetection. + IListableObjectFactory owningFactory = value as IListableObjectFactory; + if (owningFactory == null) { - throw; - } else - { - throw dex; + throw new ArgumentException("Cannot use IPersistenceExceptionTranslator autodetection without IListableObjectFactory"); } + + this.persistenceExceptionTranslator = DetectPersistenceExceptionTranslators(owningFactory); + } + } + } + + /// + /// Ensures that the property PersistenceExceptionTranslator has been set. + /// Invoked by an + /// after it has injected all of an object's dependencies. + /// + /// + /// In the event of misconfiguration (such as the failure to set a + /// required property) or if initialization fails. + /// + public void AfterPropertiesSet() + { + if (this.persistenceExceptionTranslator == null) + { + throw new ArgumentException("Property 'PersistenceExceptionTranslator' is required"); + } + } + + /// + /// Detects the petsistence exception translators in the given object factory. + /// + /// The object factory for obtaining all IPersistenceExceptionTranslators. + /// A chained IPersistenceExceptionTranslator, combining all PersistenceExceptionTranslators found in the factory + /// + /// + protected IPersistenceExceptionTranslator DetectPersistenceExceptionTranslators(IListableObjectFactory objectFactory) + { + // Find all translators, being careful not to activate FactoryObjects. + IDictionary pets = + ObjectFactoryUtils.ObjectsOfTypeIncludingAncestors(objectFactory, + typeof(IPersistenceExceptionTranslator), false, + false); + if (pets.Count == 0) + { + throw new InvalidOperationException("No persistence exception translators found in container. Cannot perform exception translation."); + } + + ChainedPersistenceExceptionTranslator cpet = new ChainedPersistenceExceptionTranslator(); + foreach (KeyValuePair pet in pets) + { + cpet.AddTranslator((IPersistenceExceptionTranslator) pet.Value); + } + + return cpet; + } + + /// + /// Return a translated exception if this is appropriate, otherwise rethrow the original exception. + /// + /// + /// + public object Invoke(IMethodInvocation invocation) + { + try + { + return invocation.Proceed(); + } + catch (Exception ex) + { + DataAccessException dex = DataAccessUtils.TranslateIfNecessary(ex, persistenceExceptionTranslator); + if (dex == null) + { + throw; + } + else + { + throw dex; } } } diff --git a/src/Spring/Spring.Data/Dao/TransientDataAccessException.cs b/src/Spring/Spring.Data/Dao/TransientDataAccessException.cs index 33daf34e..dac1e16f 100644 --- a/src/Spring/Spring.Data/Dao/TransientDataAccessException.cs +++ b/src/Spring/Spring.Data/Dao/TransientDataAccessException.cs @@ -20,48 +20,51 @@ using System.Runtime.Serialization; -namespace Spring.Dao +namespace Spring.Dao; + +/// +/// Root of the hierarchy of data access exception that are considered transient - +/// where a previously failed operation might be able to succeed when the operation +/// is retried without any intervention by application-level functionality. +/// +/// Thomas Risberg +/// Mark Pollack (.NET) +[Serializable] +public abstract class TransientDataAccessException : DataAccessException { /// - /// Root of the hierarchy of data access exception that are considered transient - - /// where a previously failed operation might be able to succeed when the operation - /// is retried without any intervention by application-level functionality. + /// Creates a new instance of the + /// class. /// - /// Thomas Risberg - /// Mark Pollack (.NET) - [Serializable] - public abstract class TransientDataAccessException : DataAccessException - { - /// - /// Creates a new instance of the - /// class. - /// - public TransientDataAccessException() : base("No Exception Message") {} + public TransientDataAccessException() : base("No Exception Message") { } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - public TransientDataAccessException( string message ) : base( message ) {} + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + public TransientDataAccessException(string message) : base(message) { } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception (from the underlying data access API, such as ADO.NET). - /// - public TransientDataAccessException( string message, Exception rootCause) - : base( message , rootCause ) {} + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception (from the underlying data access API, such as ADO.NET). + /// + public TransientDataAccessException(string message, Exception rootCause) + : base(message, rootCause) + { + } - /// - protected TransientDataAccessException( - SerializationInfo info, StreamingContext context ) : base( info, context ) {} - } + /// + protected TransientDataAccessException( + SerializationInfo info, StreamingContext context) : base(info, context) + { + } } diff --git a/src/Spring/Spring.Data/Dao/TransientDataAccessResourceException.cs b/src/Spring/Spring.Data/Dao/TransientDataAccessResourceException.cs index 58661a6e..55658f65 100644 --- a/src/Spring/Spring.Data/Dao/TransientDataAccessResourceException.cs +++ b/src/Spring/Spring.Data/Dao/TransientDataAccessResourceException.cs @@ -20,47 +20,50 @@ using System.Runtime.Serialization; -namespace Spring.Dao +namespace Spring.Dao; + +/// +/// RDta access exception thrown when a resource fails temporarily and the operation can be +/// retried. +/// +/// Thomas Risberg +/// Mark Pollack (.NET) +[Serializable] +public class TransientDataAccessResourceException : TransientDataAccessException { /// - /// RDta access exception thrown when a resource fails temporarily and the operation can be - /// retried. + /// Creates a new instance of the + /// class. /// - /// Thomas Risberg - /// Mark Pollack (.NET) - [Serializable] - public class TransientDataAccessResourceException : TransientDataAccessException - { - /// - /// Creates a new instance of the - /// class. - /// - public TransientDataAccessResourceException() : base("No Exception Message") {} + public TransientDataAccessResourceException() : base("No Exception Message") { } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - public TransientDataAccessResourceException( string message ) : base( message ) {} + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + public TransientDataAccessResourceException(string message) : base(message) { } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception (from the underlying data access API, such as ADO.NET). - /// - public TransientDataAccessResourceException( string message, Exception rootCause) - : base( message , rootCause ) {} + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception (from the underlying data access API, such as ADO.NET). + /// + public TransientDataAccessResourceException(string message, Exception rootCause) + : base(message, rootCause) + { + } - /// - protected TransientDataAccessResourceException( - SerializationInfo info, StreamingContext context ) : base( info, context ) {} - } + /// + protected TransientDataAccessResourceException( + SerializationInfo info, StreamingContext context) : base(info, context) + { + } } diff --git a/src/Spring/Spring.Data/Dao/TypeMismatchDataAccessException.cs b/src/Spring/Spring.Data/Dao/TypeMismatchDataAccessException.cs index b891ebbb..990b8486 100644 --- a/src/Spring/Spring.Data/Dao/TypeMismatchDataAccessException.cs +++ b/src/Spring/Spring.Data/Dao/TypeMismatchDataAccessException.cs @@ -20,48 +20,51 @@ using System.Runtime.Serialization; -namespace Spring.Dao +namespace Spring.Dao; + +/// +/// Exception thrown on mismatch between CLS type and database type: +/// for example on an attempt to set an object of the wrong type +/// in an RDBMS column. +/// +/// Rod Johnson +/// Griffin Caprio (.NET) +[Serializable] +public class TypeMismatchDataAccessException : InvalidDataAccessResourceUsageException { - /// - /// Exception thrown on mismatch between CLS type and database type: - /// for example on an attempt to set an object of the wrong type - /// in an RDBMS column. - /// - /// Rod Johnson - /// Griffin Caprio (.NET) - [Serializable] - public class TypeMismatchDataAccessException : InvalidDataAccessResourceUsageException - { - /// - /// Creates a new instance of the - /// class. - /// - public TypeMismatchDataAccessException() {} + /// + /// Creates a new instance of the + /// class. + /// + public TypeMismatchDataAccessException() { } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - public TypeMismatchDataAccessException( string message ) : base( message ) {} + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + public TypeMismatchDataAccessException(string message) : base(message) { } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception (from the underlying data access API, such as ADO.NET). - /// - public TypeMismatchDataAccessException( string message, Exception rootCause) - : base( message , rootCause ) {} + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception (from the underlying data access API, such as ADO.NET). + /// + public TypeMismatchDataAccessException(string message, Exception rootCause) + : base(message, rootCause) + { + } - /// - protected TypeMismatchDataAccessException( - SerializationInfo info, StreamingContext context ) : base( info, context ) {} - } + /// + protected TypeMismatchDataAccessException( + SerializationInfo info, StreamingContext context) : base(info, context) + { + } } diff --git a/src/Spring/Spring.Data/Dao/UncategorizedDataAccessException.cs b/src/Spring/Spring.Data/Dao/UncategorizedDataAccessException.cs index 7b26ef89..d434302e 100644 --- a/src/Spring/Spring.Data/Dao/UncategorizedDataAccessException.cs +++ b/src/Spring/Spring.Data/Dao/UncategorizedDataAccessException.cs @@ -20,48 +20,51 @@ using System.Runtime.Serialization; -namespace Spring.Dao +namespace Spring.Dao; + +/// +/// Normal superclass when we can't distinguish anything more specific +/// than "something went wrong with the underlying resource": for example, +/// a SQLException from Sql Server that we can't pinpoint more precisely. +/// +/// Rod Johnson +/// Griffin Caprio (.NET) +[Serializable] +public abstract class UncategorizedDataAccessException : NonTransientDataAccessException { - /// - /// Normal superclass when we can't distinguish anything more specific - /// than "something went wrong with the underlying resource": for example, - /// a SQLException from Sql Server that we can't pinpoint more precisely. - /// - /// Rod Johnson - /// Griffin Caprio (.NET) - [Serializable] - public abstract class UncategorizedDataAccessException : NonTransientDataAccessException - { - /// - /// Creates a new instance of the - /// class. - /// - public UncategorizedDataAccessException() {} + /// + /// Creates a new instance of the + /// class. + /// + public UncategorizedDataAccessException() { } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - public UncategorizedDataAccessException( string message ) : base( message ) {} + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + public UncategorizedDataAccessException(string message) : base(message) { } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception (from the underlying data access API, such as ADO.NET). - /// - public UncategorizedDataAccessException( string message, Exception rootCause) - : base( message , rootCause ) {} + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception (from the underlying data access API, such as ADO.NET). + /// + public UncategorizedDataAccessException(string message, Exception rootCause) + : base(message, rootCause) + { + } - /// - protected UncategorizedDataAccessException( - SerializationInfo info, StreamingContext context ) : base( info, context ) {} - } + /// + protected UncategorizedDataAccessException( + SerializationInfo info, StreamingContext context) : base(info, context) + { + } } diff --git a/src/Spring/Spring.Data/Data/BadSqlGrammarException.cs b/src/Spring/Spring.Data/Data/BadSqlGrammarException.cs index 5d3e9a91..2d66f167 100644 --- a/src/Spring/Spring.Data/Data/BadSqlGrammarException.cs +++ b/src/Spring/Spring.Data/Data/BadSqlGrammarException.cs @@ -21,93 +21,92 @@ using System.Runtime.Serialization; using Spring.Dao; -namespace Spring.Data +namespace Spring.Data; + +/// +/// Exception thrown when SQL specified is invalid. +/// +/// Mark Pollack (.NET) +[Serializable] +public class BadSqlGrammarException : InvalidDataAccessResourceUsageException, ISerializable { - /// - /// Exception thrown when SQL specified is invalid. - /// - /// Mark Pollack (.NET) - [Serializable] - public class BadSqlGrammarException : InvalidDataAccessResourceUsageException, ISerializable - { - #region Fields + #region Fields - /// - /// SQL that led to the problem - /// - private string sql; + /// + /// SQL that led to the problem + /// + private string sql; - #endregion + #endregion - #region Constructor (s) - /// - /// Initializes a new instance of the class. - /// - public BadSqlGrammarException() - { - } + #region Constructor (s) - /// - /// Initializes a new instance of the class. - /// - /// A message about the exception. - public BadSqlGrammarException(string message): base(message) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// A message about the exception. - /// The inner exception. - public BadSqlGrammarException(string message, Exception inner): base(message, inner) - { - } - - - /// - /// Initializes a new instance of the class. - /// - /// name of the current task. - /// The offending SQL statment - /// The root cause. - public BadSqlGrammarException(string task, String sql, Exception ex) : base(task + "; bad SQL grammar [" + sql + "]; " + ex.Message, ex) - { - this.sql = sql; - } - - /// - protected BadSqlGrammarException( SerializationInfo info, StreamingContext context ) : base( info, context ) {} - - #endregion - - #region Properties - - public string Sql - { - get - { - return sql; - } - } - #endregion - - - #region ISerializable Members - - /// - /// When overridden in a derived class, sets the - /// with information about the exception. - /// - /// The that holds the serialized object data about the exception being thrown. - /// The that contains contextual information about the source or destination. - /// The parameter is a null reference ( in Visual Basic). - public override void GetObjectData(SerializationInfo info, StreamingContext context) - { - info.AddValue( "sql", sql ); - base.GetObjectData( info, context ); - } - - #endregion + /// + /// Initializes a new instance of the class. + /// + public BadSqlGrammarException() + { } + + /// + /// Initializes a new instance of the class. + /// + /// A message about the exception. + public BadSqlGrammarException(string message) : base(message) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// A message about the exception. + /// The inner exception. + public BadSqlGrammarException(string message, Exception inner) : base(message, inner) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// name of the current task. + /// The offending SQL statment + /// The root cause. + public BadSqlGrammarException(string task, String sql, Exception ex) : base(task + "; bad SQL grammar [" + sql + "]; " + ex.Message, ex) + { + this.sql = sql; + } + + /// + protected BadSqlGrammarException(SerializationInfo info, StreamingContext context) : base(info, context) { } + + #endregion + + #region Properties + + public string Sql + { + get + { + return sql; + } + } + + #endregion + + #region ISerializable Members + + /// + /// When overridden in a derived class, sets the + /// with information about the exception. + /// + /// The that holds the serialized object data about the exception being thrown. + /// The that contains contextual information about the source or destination. + /// The parameter is a null reference ( in Visual Basic). + public override void GetObjectData(SerializationInfo info, StreamingContext context) + { + info.AddValue("sql", sql); + base.GetObjectData(info, context); + } + + #endregion } diff --git a/src/Spring/Spring.Data/Data/CannotGetAdoConnectionException.cs b/src/Spring/Spring.Data/Data/CannotGetAdoConnectionException.cs index a16268dc..08ceb1d0 100644 --- a/src/Spring/Spring.Data/Data/CannotGetAdoConnectionException.cs +++ b/src/Spring/Spring.Data/Data/CannotGetAdoConnectionException.cs @@ -21,48 +21,45 @@ using System.Runtime.Serialization; using Spring.Dao; -namespace Spring.Data +namespace Spring.Data; + +/// +/// Fatal exception thrown when we can't connect to an RDBMS using ADO.NET +/// +/// Rod Johnson +/// Mark Pollack (.NET) +[Serializable] +public class CannotGetAdoConnectionException : InvalidDataAccessResourceUsageException { - /// - /// Fatal exception thrown when we can't connect to an RDBMS using ADO.NET + #region Constructor (s) + + /// + /// Initializes a new instance of the class. /// - /// Rod Johnson - /// Mark Pollack (.NET) - [Serializable] - public class CannotGetAdoConnectionException : InvalidDataAccessResourceUsageException - { - - #region Constructor (s) - /// - /// Initializes a new instance of the class. - /// - public CannotGetAdoConnectionException() - { - } - - /// - /// Initializes a new instance of the class. - /// - /// A message about the exception. - public CannotGetAdoConnectionException(string message): base(message) - { - } - - - /// - /// Initializes a new instance of the class. - /// - /// A message about the exception. - /// The inner exception. - public CannotGetAdoConnectionException(string message, Exception inner) - : base(message, inner) - { - } - - /// - protected CannotGetAdoConnectionException(SerializationInfo info, StreamingContext context) : base(info, context) { } - - #endregion - + public CannotGetAdoConnectionException() + { } + + /// + /// Initializes a new instance of the class. + /// + /// A message about the exception. + public CannotGetAdoConnectionException(string message) : base(message) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// A message about the exception. + /// The inner exception. + public CannotGetAdoConnectionException(string message, Exception inner) + : base(message, inner) + { + } + + /// + protected CannotGetAdoConnectionException(SerializationInfo info, StreamingContext context) : base(info, context) { } + + #endregion } diff --git a/src/Spring/Spring.Data/Data/CommandDelegate.cs b/src/Spring/Spring.Data/Data/CommandDelegate.cs index 029ae7df..37b51a97 100644 --- a/src/Spring/Spring.Data/Data/CommandDelegate.cs +++ b/src/Spring/Spring.Data/Data/CommandDelegate.cs @@ -1,14 +1,14 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. - * + * Copyright � 2002-2011 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. @@ -20,23 +20,22 @@ using System.Data; -namespace Spring.Data -{ - /// - /// Callback delegate for code that operates on a IDbCommand. - /// - /// the ADO.NET command object. - /// - ///

Allows you to execute any number of operations - /// on a single IDbCommand, for example a single ExecuteScalar - /// call or repeated execute calls with varying parameters. - ///

- ///

Used internally by AdoTemplate, but also useful for - /// application code. Note that the passed in IDbCommand - /// has been created by the framework and will have its - /// Connection property set and the Transaction property - /// set based on the transaction context.

- ///
- /// Mark Pollack - public delegate object CommandDelegate(IDbCommand command); -} +namespace Spring.Data; + +/// +/// Callback delegate for code that operates on a IDbCommand. +/// +/// the ADO.NET command object. +/// +///

Allows you to execute any number of operations +/// on a single IDbCommand, for example a single ExecuteScalar +/// call or repeated execute calls with varying parameters. +///

+///

Used internally by AdoTemplate, but also useful for +/// application code. Note that the passed in IDbCommand +/// has been created by the framework and will have its +/// Connection property set and the Transaction property +/// set based on the transaction context.

+///
+/// Mark Pollack +public delegate object CommandDelegate(IDbCommand command); diff --git a/src/Spring/Spring.Data/Data/CommandSetterDelegate.cs b/src/Spring/Spring.Data/Data/CommandSetterDelegate.cs index c66231d6..86706515 100644 --- a/src/Spring/Spring.Data/Data/CommandSetterDelegate.cs +++ b/src/Spring/Spring.Data/Data/CommandSetterDelegate.cs @@ -1,14 +1,14 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. - * + * Copyright � 2002-2011 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. @@ -20,15 +20,13 @@ using System.Data; -namespace Spring.Data -{ - /// - /// Callback delegate to set any necessary parameters or other - /// properties on the command object. The CommandType and - /// CommandText properties will have already been supplied - /// - /// The database command object. - /// Mark Pollack - public delegate void CommandSetterDelegate(IDbCommand dbCommand); +namespace Spring.Data; -} +/// +/// Callback delegate to set any necessary parameters or other +/// properties on the command object. The CommandType and +/// CommandText properties will have already been supplied +/// +/// The database command object. +/// Mark Pollack +public delegate void CommandSetterDelegate(IDbCommand dbCommand); diff --git a/src/Spring/Spring.Data/Data/Common/DbMetadata.cs b/src/Spring/Spring.Data/Data/Common/DbMetadata.cs index a8ac148a..12c2cc53 100644 --- a/src/Spring/Spring.Data/Data/Common/DbMetadata.cs +++ b/src/Spring/Spring.Data/Data/Common/DbMetadata.cs @@ -21,393 +21,380 @@ using System.Reflection; using Spring.Util; -namespace Spring.Data.Common +namespace Spring.Data.Common; + +/// +/// Provides database metdata information. +/// +/// Mark Pollack (.NET) +public class DbMetadata : IDbMetadata { + #region Fields + + private bool supportsDeriveParametersMethod = true; + + private string productName; + private string assemblyName; + private Type connectionType; + private Type commandType; + private Type parameterType; + private Type dataAdapterType; + + private Type parameterDbType; + private PropertyInfo parameterDbTypeProperty; + private PropertyInfo parameterIsNullableProperty; + private string parameterNamePrefix; + + private Type exceptionType; + private bool useParameterNamePrefixInParameterCollection; + private bool useParameterPrefixInSql; + private bool bindByName; + + private Type commandBuilderType; + private MethodInfo commandBuilderDeriveParametersMethod; + + private string errorCodeExceptionExpression = string.Empty; + + private ErrorCodes errorCodes; + + #endregion + + #region Constructor (s) + /// - /// Provides database metdata information. + /// Initializes a new instance of the class. /// - /// Mark Pollack (.NET) - public class DbMetadata : IDbMetadata + /// Name of the product. + /// Name of the assembly. + /// Type of the connection. + /// Type of the command. + /// Type of the parameter. + /// Type of the data adapter. + /// Type of the command builder. + /// The command builder derive parameters method. + /// Type of the parameter db. + /// The parameter db type property. + /// The parameter is nullable property. + /// The parameter name prefix. + /// Type of the exception. + /// if set to true [use parameter name prefix in parameter collection]. + /// if set to true [use parameter prefix in SQL]. + /// if set to true [bind by name]. + /// The error code exception expression. + public DbMetadata(string productName, + string assemblyName, + Type connectionType, + Type commandType, + Type parameterType, + Type dataAdapterType, + Type commandBuilderType, + string commandBuilderDeriveParametersMethod, + Type parameterDbType, + string parameterDbTypeProperty, + string parameterIsNullableProperty, + string parameterNamePrefix, + Type exceptionType, + bool useParameterNamePrefixInParameterCollection, + bool useParameterPrefixInSql, + bool bindByName, + string errorCodeExceptionExpression + ) { - #region Fields + AssertUtils.ArgumentHasText(productName, "ProductName"); + this.productName = productName; + AssertUtils.ArgumentHasText(assemblyName, "assemblyName", GetErrorMessage()); + AssertUtils.ArgumentNotNull(connectionType, "connectionType", GetErrorMessage()); + AssertUtils.ArgumentNotNull(commandType, "commandType", GetErrorMessage()); + AssertUtils.ArgumentNotNull(parameterType, "parameterType", GetErrorMessage()); + AssertUtils.ArgumentNotNull(dataAdapterType, "dataAdapterType", GetErrorMessage()); + AssertUtils.ArgumentNotNull(commandBuilderType, "commandBuilderType", GetErrorMessage()); + AssertUtils.ArgumentHasText(commandBuilderDeriveParametersMethod, "commandBuilderDeriveParametersMethod", GetErrorMessage()); + AssertUtils.ArgumentNotNull(parameterDbType, "parameterDbType", GetErrorMessage()); + AssertUtils.ArgumentHasText(parameterDbTypeProperty, "parameterDbTypeProperty", GetErrorMessage()); + AssertUtils.ArgumentHasText(parameterIsNullableProperty, "parameterIsNullableProperty", GetErrorMessage()); + AssertUtils.ArgumentHasText(parameterNamePrefix, "parameterNamePrefix", GetErrorMessage()); + AssertUtils.ArgumentNotNull(exceptionType, "exceptionType", GetErrorMessage()); - private bool supportsDeriveParametersMethod = true; + this.assemblyName = assemblyName; - private string productName; - private string assemblyName; - private Type connectionType; - private Type commandType; - private Type parameterType; - private Type dataAdapterType; + this.connectionType = connectionType; + this.commandType = commandType; + this.parameterType = parameterType; + this.dataAdapterType = dataAdapterType; + this.commandBuilderType = commandBuilderType; - - private Type parameterDbType; - private PropertyInfo parameterDbTypeProperty; - private PropertyInfo parameterIsNullableProperty; - private string parameterNamePrefix; - - private Type exceptionType; - private bool useParameterNamePrefixInParameterCollection; - private bool useParameterPrefixInSql; - private bool bindByName; - - - - - private Type commandBuilderType; - private MethodInfo commandBuilderDeriveParametersMethod; - - private string errorCodeExceptionExpression = string.Empty; - - private ErrorCodes errorCodes; - - #endregion - - #region Constructor (s) - - /// - /// Initializes a new instance of the class. - /// - /// Name of the product. - /// Name of the assembly. - /// Type of the connection. - /// Type of the command. - /// Type of the parameter. - /// Type of the data adapter. - /// Type of the command builder. - /// The command builder derive parameters method. - /// Type of the parameter db. - /// The parameter db type property. - /// The parameter is nullable property. - /// The parameter name prefix. - /// Type of the exception. - /// if set to true [use parameter name prefix in parameter collection]. - /// if set to true [use parameter prefix in SQL]. - /// if set to true [bind by name]. - /// The error code exception expression. - public DbMetadata(string productName, - string assemblyName, - Type connectionType, - Type commandType, - Type parameterType, - Type dataAdapterType, - Type commandBuilderType, - string commandBuilderDeriveParametersMethod, - Type parameterDbType, - string parameterDbTypeProperty, - string parameterIsNullableProperty, - string parameterNamePrefix, - Type exceptionType, - bool useParameterNamePrefixInParameterCollection, - bool useParameterPrefixInSql, - bool bindByName, - string errorCodeExceptionExpression - - ) + if (commandBuilderDeriveParametersMethod.ToLower().Trim().Equals("not supported")) { + supportsDeriveParametersMethod = false; + } - AssertUtils.ArgumentHasText(productName, "ProductName"); - this.productName = productName; - AssertUtils.ArgumentHasText(assemblyName, "assemblyName", GetErrorMessage() ); - AssertUtils.ArgumentNotNull(connectionType, "connectionType", GetErrorMessage() ); - AssertUtils.ArgumentNotNull(commandType, "commandType", GetErrorMessage()); - AssertUtils.ArgumentNotNull(parameterType, "parameterType", GetErrorMessage()); - AssertUtils.ArgumentNotNull(dataAdapterType, "dataAdapterType", GetErrorMessage()); - AssertUtils.ArgumentNotNull(commandBuilderType, "commandBuilderType", GetErrorMessage()); - AssertUtils.ArgumentHasText(commandBuilderDeriveParametersMethod, "commandBuilderDeriveParametersMethod", GetErrorMessage()); - AssertUtils.ArgumentNotNull(parameterDbType, "parameterDbType", GetErrorMessage()); - AssertUtils.ArgumentHasText(parameterDbTypeProperty, "parameterDbTypeProperty", GetErrorMessage()); - AssertUtils.ArgumentHasText(parameterIsNullableProperty, "parameterIsNullableProperty", GetErrorMessage()); - AssertUtils.ArgumentHasText(parameterNamePrefix, "parameterNamePrefix", GetErrorMessage()); - AssertUtils.ArgumentNotNull(exceptionType, "exceptionType", GetErrorMessage()); + if (supportsDeriveParametersMethod) + { + this.commandBuilderDeriveParametersMethod = + ReflectionUtils.GetMethod(this.commandBuilderType, commandBuilderDeriveParametersMethod, + new Type[] { this.commandType }); - this.assemblyName = assemblyName; + AssertUtils.ArgumentNotNull(this.commandBuilderDeriveParametersMethod, + "commandBuilderDeriveParametersMethod", GetErrorMessage() + + ", could not resolve commandBuilderDeriveParametersMethod " + + commandBuilderDeriveParametersMethod + + " to MethodInfo. Please check dbproviders.xml entry for correct metadata listing."); + } - this.connectionType = connectionType; - this.commandType = commandType; - this.parameterType = parameterType; - this.dataAdapterType = dataAdapterType; - this.commandBuilderType = commandBuilderType; + this.commandType = commandType; - if (commandBuilderDeriveParametersMethod.ToLower().Trim().Equals("not supported")) - { - supportsDeriveParametersMethod = false; - } + this.parameterDbType = parameterDbType; + this.parameterDbTypeProperty = this.parameterType.GetProperty(parameterDbTypeProperty, + BindingFlags.Instance | BindingFlags.Public); + AssertUtils.ArgumentNotNull(this.parameterDbTypeProperty, "parameterDbTypeProperty", GetErrorMessage() + + ", could not resolve parameterDbTypeProperty " + + parameterDbTypeProperty + + " to PropertyInfo. Please check dbproviders.xml entry for correct metadata listing."); + + this.parameterIsNullableProperty = this.parameterType.GetProperty(parameterIsNullableProperty, + BindingFlags.Instance | BindingFlags.Public); + + AssertUtils.ArgumentNotNull(this.parameterIsNullableProperty, "parameterIsNullableProperty", GetErrorMessage() + + ", could not resolve parameterIsNullableProperty " + + parameterIsNullableProperty + + " to PropertyInfo. Please check dbproviders.xml entry for correct metadata listing."); + + this.parameterNamePrefix = parameterNamePrefix; + this.exceptionType = exceptionType; + + this.useParameterNamePrefixInParameterCollection = useParameterNamePrefixInParameterCollection; + this.useParameterPrefixInSql = useParameterPrefixInSql; + this.bindByName = bindByName; + + this.errorCodeExceptionExpression = errorCodeExceptionExpression; + + errorCodes = new ErrorCodes(); + } + + private string GetErrorMessage() + { + return "DbProvider product name = " + productName; + } + + #endregion + + #region IDbMetadata Members + + /// + /// Gets a value indicating whether to use param name prefix in parameter collection. + /// + /// + /// true if should use param name prefix in parameter collection; otherwise, false. + /// + public bool UseParamNamePrefixInParameterCollection + { + get { return useParameterNamePrefixInParameterCollection; } + } + + /// + /// Gets the name of the assembly. + /// + /// Example: System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + /// The name of the assembly. + public string AssemblyName + { + get { return assemblyName; } + } + + /// + /// Gets a descriptive name of the product. + /// + /// Example: Microsoft SQL Server, provider V2.0.0.0 in framework .NET V2.0 + /// The name of the product. + public string ProductName + { + get { return productName; } + } + + /// + /// Gets the type of the connection. The fully qualified type name is given since some providers, + /// notably for SqlServerCe, do not use the same namespace for all data access types. + /// + /// Example: System.Data.SqlClient.SqlCommand, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + /// The type of the connection. + public Type ConnectionType + { + get { return connectionType; } + } + + /// + /// Gets the type of the command. + /// + /// Example: System.Data.SqlClient.SqlCommand, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + /// The type of the command. + public Type CommandType + { + get { return commandType; } + } + + /// + /// Gets the type of the parameter. + /// + /// Example: System.Data.SqlClient.SqlParameter, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + /// The type of the parameter. + public Type ParameterType + { + get { return parameterType; } + } + + /// + /// Gets the type of the data adapter. + /// + /// Example: System.Data.SqlClient.SqlDataAdapter, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + /// The type of the data adapter. + public Type DataAdapterType + { + get { return dataAdapterType; } + } + + /// + /// Gets the type of the command builder. + /// + /// Example: System.Data.SqlClient.SqlCommandBuilder, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + /// The type of the command builder. + public Type CommandBuilderType + { + get { return commandBuilderType; } + } + + /// + /// Gets the command builder derive parameters method. + /// + /// If the value 'not supported' is specified then this method will throw an ArgumentException + /// Example: DeriveParameters + /// The command builder derive parameters method. + public MethodInfo CommandBuilderDeriveParametersMethod + { + get + { if (supportsDeriveParametersMethod) { - this.commandBuilderDeriveParametersMethod = - ReflectionUtils.GetMethod(this.commandBuilderType, commandBuilderDeriveParametersMethod, - new Type[] {this.commandType}); - - AssertUtils.ArgumentNotNull(this.commandBuilderDeriveParametersMethod, - "commandBuilderDeriveParametersMethod", GetErrorMessage() + - ", could not resolve commandBuilderDeriveParametersMethod " + - commandBuilderDeriveParametersMethod + - " to MethodInfo. Please check dbproviders.xml entry for correct metadata listing."); + return commandBuilderDeriveParametersMethod; } - - this.commandType = commandType; - - this.parameterDbType = parameterDbType; - - this.parameterDbTypeProperty = this.parameterType.GetProperty(parameterDbTypeProperty, - BindingFlags.Instance | BindingFlags.Public); - AssertUtils.ArgumentNotNull(this.parameterDbTypeProperty, "parameterDbTypeProperty", GetErrorMessage() + - ", could not resolve parameterDbTypeProperty " + - parameterDbTypeProperty + - " to PropertyInfo. Please check dbproviders.xml entry for correct metadata listing."); - - this.parameterIsNullableProperty = this.parameterType.GetProperty(parameterIsNullableProperty, - BindingFlags.Instance | BindingFlags.Public); - - AssertUtils.ArgumentNotNull(this.parameterIsNullableProperty, "parameterIsNullableProperty", GetErrorMessage() + - ", could not resolve parameterIsNullableProperty " + - parameterIsNullableProperty + - " to PropertyInfo. Please check dbproviders.xml entry for correct metadata listing."); - - this.parameterNamePrefix = parameterNamePrefix; - this.exceptionType = exceptionType; - - this.useParameterNamePrefixInParameterCollection = useParameterNamePrefixInParameterCollection; - this.useParameterPrefixInSql = useParameterPrefixInSql; - this.bindByName = bindByName; - - this.errorCodeExceptionExpression = errorCodeExceptionExpression; - - - errorCodes = new ErrorCodes(); - - - } - - private string GetErrorMessage() - { - return "DbProvider product name = " + productName; - } - - - #endregion - - #region IDbMetadata Members - - /// - /// Gets a value indicating whether to use param name prefix in parameter collection. - /// - /// - /// true if should use param name prefix in parameter collection; otherwise, false. - /// - public bool UseParamNamePrefixInParameterCollection - { - get { return useParameterNamePrefixInParameterCollection; } - } - - /// - /// Gets the name of the assembly. - /// - /// Example: System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - /// The name of the assembly. - public string AssemblyName - { - get { return assemblyName; } - } - - /// - /// Gets a descriptive name of the product. - /// - /// Example: Microsoft SQL Server, provider V2.0.0.0 in framework .NET V2.0 - /// The name of the product. - public string ProductName - { - get { return productName; } - } - - /// - /// Gets the type of the connection. The fully qualified type name is given since some providers, - /// notably for SqlServerCe, do not use the same namespace for all data access types. - /// - /// Example: System.Data.SqlClient.SqlCommand, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - /// The type of the connection. - public Type ConnectionType - { - get { return connectionType; } - } - - /// - /// Gets the type of the command. - /// - /// Example: System.Data.SqlClient.SqlCommand, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - /// The type of the command. - public Type CommandType - { - get { return commandType; } - } - - /// - /// Gets the type of the parameter. - /// - /// Example: System.Data.SqlClient.SqlParameter, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - /// The type of the parameter. - public Type ParameterType - { - get { return parameterType; } - } - - /// - /// Gets the type of the data adapter. - /// - /// Example: System.Data.SqlClient.SqlDataAdapter, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - /// The type of the data adapter. - public Type DataAdapterType - { - get { return dataAdapterType; } - } - - /// - /// Gets the type of the command builder. - /// - /// Example: System.Data.SqlClient.SqlCommandBuilder, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - /// The type of the command builder. - public Type CommandBuilderType - { - get { return commandBuilderType; } - } - - /// - /// Gets the command builder derive parameters method. - /// - /// If the value 'not supported' is specified then this method will throw an ArgumentException - /// Example: DeriveParameters - /// The command builder derive parameters method. - public MethodInfo CommandBuilderDeriveParametersMethod - { - get + else { - if (supportsDeriveParametersMethod) - { - return commandBuilderDeriveParametersMethod; - } else - { - throw new ArgumentException("This provider does not support the DeriveParameters functionality"); - } + throw new ArgumentException("This provider does not support the DeriveParameters functionality"); } } - - /// - /// Provide the prefix used to indentify named parameters in SQL text. - /// - /// @ for Sql Server - public string ParameterNamePrefix - { - get { return parameterNamePrefix; } - } - - /// - /// Gets the type of the exception. - /// - /// Example: System.Data.SqlClient.SqlException, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - /// The type of the exception. - public Type ExceptionType - { - get { return exceptionType; } - } - - /// - /// Does the driver require the use of the parameter prefix when - /// specifying the name of the parameter in the Command's - /// Parameter collection. - /// - /// - /// If true, then commamd.Parameters["@parameterName"] is - /// used, otherwise, command.Parameters["parameterName"]. - /// - public bool UseParameterNamePrefixInParameterCollection - { - get { return useParameterNamePrefixInParameterCollection; } - } - - - /// - /// Gets a value indicating whether the Provider requires - /// the use of a named prefix in the SQL string. - /// - /// - /// true if use parameter prefix in SQL; otherwise, false. - /// - /// - /// The OLE DB/ODBC .NET Provider does not support named parameters for - /// passing parameters to an SQL Statement or a stored procedure called - /// by an IDbCommand when CommandType is set to Text. - /// - public bool UseParameterPrefixInSql - { - get { return useParameterPrefixInSql; } - } - - /// - /// For providers that allow you to choose between binding parameters - /// to a command by name (true) or by position (false). - /// - /// - public bool BindByName - { - get { return bindByName; } - set { bindByName = value; } - } - - /// - /// Gets the type of the parameter db. - /// - /// Example: System.Data.SqlDbType, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - /// The type of the parameter db. - public Type ParameterDbType - { - get { return parameterDbType; } - } - - /// - /// Gets the parameter db type property. - /// - /// Example: SqlDbType for SqlServer - /// The parameter db type property. - public PropertyInfo ParameterDbTypeProperty - { - get { return parameterDbTypeProperty; } - } - - /// - /// Gets the parameter is nullable property. - /// - /// Example: IsNullable for Sql Server - /// The parameter is nullable property. - public PropertyInfo ParameterIsNullableProperty - { - get { return parameterIsNullableProperty; } - } - - /// - /// Gets or sets the error codes. - /// - /// The collection of error codes to map error code integer values to Spring's DAO exception hierarchy - /// The error codes. - public ErrorCodes ErrorCodes - { - get { return errorCodes; } - set { errorCodes = value;} - } - - /// - /// Gets the error code exception expression. - /// - /// Example Errors[0].Number.ToString() for Sql Server - /// The error code exception expression. - public string ErrorCodeExceptionExpression - { - get { return errorCodeExceptionExpression; } - } - - #endregion - - } + + /// + /// Provide the prefix used to indentify named parameters in SQL text. + /// + /// @ for Sql Server + public string ParameterNamePrefix + { + get { return parameterNamePrefix; } + } + + /// + /// Gets the type of the exception. + /// + /// Example: System.Data.SqlClient.SqlException, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + /// The type of the exception. + public Type ExceptionType + { + get { return exceptionType; } + } + + /// + /// Does the driver require the use of the parameter prefix when + /// specifying the name of the parameter in the Command's + /// Parameter collection. + /// + /// + /// If true, then commamd.Parameters["@parameterName"] is + /// used, otherwise, command.Parameters["parameterName"]. + /// + public bool UseParameterNamePrefixInParameterCollection + { + get { return useParameterNamePrefixInParameterCollection; } + } + + /// + /// Gets a value indicating whether the Provider requires + /// the use of a named prefix in the SQL string. + /// + /// + /// true if use parameter prefix in SQL; otherwise, false. + /// + /// + /// The OLE DB/ODBC .NET Provider does not support named parameters for + /// passing parameters to an SQL Statement or a stored procedure called + /// by an IDbCommand when CommandType is set to Text. + /// + public bool UseParameterPrefixInSql + { + get { return useParameterPrefixInSql; } + } + + /// + /// For providers that allow you to choose between binding parameters + /// to a command by name (true) or by position (false). + /// + /// + public bool BindByName + { + get { return bindByName; } + set { bindByName = value; } + } + + /// + /// Gets the type of the parameter db. + /// + /// Example: System.Data.SqlDbType, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + /// The type of the parameter db. + public Type ParameterDbType + { + get { return parameterDbType; } + } + + /// + /// Gets the parameter db type property. + /// + /// Example: SqlDbType for SqlServer + /// The parameter db type property. + public PropertyInfo ParameterDbTypeProperty + { + get { return parameterDbTypeProperty; } + } + + /// + /// Gets the parameter is nullable property. + /// + /// Example: IsNullable for Sql Server + /// The parameter is nullable property. + public PropertyInfo ParameterIsNullableProperty + { + get { return parameterIsNullableProperty; } + } + + /// + /// Gets or sets the error codes. + /// + /// The collection of error codes to map error code integer values to Spring's DAO exception hierarchy + /// The error codes. + public ErrorCodes ErrorCodes + { + get { return errorCodes; } + set { errorCodes = value; } + } + + /// + /// Gets the error code exception expression. + /// + /// Example Errors[0].Number.ToString() for Sql Server + /// The error code exception expression. + public string ErrorCodeExceptionExpression + { + get { return errorCodeExceptionExpression; } + } + + #endregion } diff --git a/src/Spring/Spring.Data/Data/Common/DbParameter.cs b/src/Spring/Spring.Data/Data/Common/DbParameter.cs index c8a88f3b..c9211245 100644 --- a/src/Spring/Spring.Data/Data/Common/DbParameter.cs +++ b/src/Spring/Spring.Data/Data/Common/DbParameter.cs @@ -20,169 +20,171 @@ using System.Data; -namespace Spring.Data.Common +namespace Spring.Data.Common; + +/// +/// A parameter class used by +/// +/// Mark Pollack (.NET) +public class DbParameter : Spring.Data.Common.IDbParameter { - /// - /// A parameter class used by - /// - /// Mark Pollack (.NET) - public class DbParameter : Spring.Data.Common.IDbParameter - { - #region Fields - private Enum dbType; - private ParameterDirection direction; - private bool isNullable; - private string name; - private string sourceColumn; - private DataRowVersion sourceVersion; - private object val; - private byte precision; - private byte scale; - private int size; - #endregion + #region Fields - #region Constructor (s) - /// - /// Initializes a new instance of the class. - /// - /// - /// Sets the SourceVersion to be Default and the ParameterDirection to be Input. - /// - public DbParameter() - { - sourceVersion = DataRowVersion.Default; - direction = ParameterDirection.Input; - } + private Enum dbType; + private ParameterDirection direction; + private bool isNullable; + private string name; + private string sourceColumn; + private DataRowVersion sourceVersion; + private object val; + private byte precision; + private byte scale; + private int size; - #endregion + #endregion - #region IDbParameter Members + #region Constructor (s) - public Enum DbType + /// + /// Initializes a new instance of the class. + /// + /// + /// Sets the SourceVersion to be Default and the ParameterDirection to be Input. + /// + public DbParameter() + { + sourceVersion = DataRowVersion.Default; + direction = ParameterDirection.Input; + } + + #endregion + + #region IDbParameter Members + + public Enum DbType + { + set { - set - { - dbType = value; - } + dbType = value; } + } - #endregion + #endregion - public IDbParameter Type(Enum dbType) - { - this.dbType = dbType; - return this; - } + public IDbParameter Type(Enum dbType) + { + this.dbType = dbType; + return this; + } - public IDbParameter Type(Enum dbType, int size) - { - this.dbType = dbType; - this.size = size; - return this; - } + public IDbParameter Type(Enum dbType, int size) + { + this.dbType = dbType; + this.size = size; + return this; + } - public Enum GetDbType() - { - return dbType; - } + public Enum GetDbType() + { + return dbType; + } - public IDbParameter Direction(ParameterDirection direction) - { - this.direction = direction; - return this; - } + public IDbParameter Direction(ParameterDirection direction) + { + this.direction = direction; + return this; + } - public ParameterDirection GetDirection() - { - return direction; - } + public ParameterDirection GetDirection() + { + return direction; + } - public IDbParameter IsNullable(bool isNullable) - { - this.isNullable = isNullable; - return this; - } + public IDbParameter IsNullable(bool isNullable) + { + this.isNullable = isNullable; + return this; + } - public bool GetIsNullable() - { - return isNullable; - } + public bool GetIsNullable() + { + return isNullable; + } - public IDbParameter Name(string name) - { - this.name = name; - return this; - } + public IDbParameter Name(string name) + { + this.name = name; + return this; + } - public string GetName() - { - return name; - } + public string GetName() + { + return name; + } - public IDbParameter SourceColumn(string sourceColumn) - { - this.sourceColumn = sourceColumn; - return this; - } + public IDbParameter SourceColumn(string sourceColumn) + { + this.sourceColumn = sourceColumn; + return this; + } - public string GetSourceColumn() - { - return sourceColumn; - } + public string GetSourceColumn() + { + return sourceColumn; + } - public IDbParameter SourceVersion(DataRowVersion sourceVersion) - { - this.sourceVersion = sourceVersion; - return this; - } + public IDbParameter SourceVersion(DataRowVersion sourceVersion) + { + this.sourceVersion = sourceVersion; + return this; + } - public DataRowVersion GetSourceVersion() - { - return sourceVersion; - } + public DataRowVersion GetSourceVersion() + { + return sourceVersion; + } - public IDbParameter Value(object val) - { - this.val = val; - return this; - } + public IDbParameter Value(object val) + { + this.val = val; + return this; + } - public object GetValue() - { - return val; - } + public object GetValue() + { + return val; + } - public IDbParameter Precision(byte precision) - { - this.precision = precision; - return this; - } + public IDbParameter Precision(byte precision) + { + this.precision = precision; + return this; + } - public byte GetPrecision() - { - return precision; - } + public byte GetPrecision() + { + return precision; + } - public IDbParameter Scale(byte scale) - { - this.scale = scale; - return this; - } + public IDbParameter Scale(byte scale) + { + this.scale = scale; + return this; + } - public byte GetScale() - { - return scale; - } + public byte GetScale() + { + return scale; + } - public IDbParameter Size(int size) - { - this.size = size; - return this; - } + public IDbParameter Size(int size) + { + this.size = size; + return this; + } - public int GetSize() - { - return size; - } - } + public int GetSize() + { + return size; + } } diff --git a/src/Spring/Spring.Data/Data/Common/DbParameters.cs b/src/Spring/Spring.Data/Data/Common/DbParameters.cs index e5b81e0b..180efe42 100644 --- a/src/Spring/Spring.Data/Data/Common/DbParameters.cs +++ b/src/Spring/Spring.Data/Data/Common/DbParameters.cs @@ -22,280 +22,278 @@ using System.Data; using System.Reflection; using Spring.Dao; -namespace Spring.Data.Common +namespace Spring.Data.Common; + +/// +/// A more portable means to create a collection of ADO.NET +/// parameters. +/// +/// Mark Pollack (.NET) +public class DbParameters : IDbParameters { + #region Fields + + private IDbProvider dbProvider; + + //Just used as a container for the underlying parameter collection. + private IDbCommand dbCommand; + private IDataParameterCollection dataParameterCollection; + + #endregion + + #region Constructor (s) + /// - /// A more portable means to create a collection of ADO.NET - /// parameters. + /// Initializes a new instance of the class. /// - /// Mark Pollack (.NET) - public class DbParameters : IDbParameters + public DbParameters(IDbProvider dbProvider) { + this.dbProvider = dbProvider; + dbCommand = dbProvider.CreateCommand(); + dataParameterCollection = dbCommand.Parameters; + } - #region Fields + #endregion - private IDbProvider dbProvider; + #region Properties - //Just used as a container for the underlying parameter collection. - private IDbCommand dbCommand; - private IDataParameterCollection dataParameterCollection; + #endregion - #endregion + #region Methods - #region Constructor (s) + #endregion - /// - /// Initializes a new instance of the class. - /// - public DbParameters(IDbProvider dbProvider) + public IDataParameter this[string parameterName] + { + get { return (IDbDataParameter) dataParameterCollection[parameterName]; } + set { dataParameterCollection[parameterName] = value; } + } + + public IDataParameter this[int index] + { + get { return (IDbDataParameter) dataParameterCollection[index]; } + set { dataParameterCollection[index] = value; } + } + + public IDataParameterCollection DataParameterCollection + { + get { return dataParameterCollection; } + } + + public int Count + { + get { - this.dbProvider = dbProvider; - dbCommand = dbProvider.CreateCommand(); - dataParameterCollection = dbCommand.Parameters; + return dataParameterCollection.Count; + } + } + + public bool Contains(string parameterName) + { + return dataParameterCollection.Contains(parameterName); + } + + public void AddParameter(IDataParameter dbParameter) + { + dataParameterCollection.Add(dbParameter); + } + + public IDbDataParameter AddParameter(string name, + Enum parameterType, + int size, + ParameterDirection direction, + bool isNullable, + byte precision, + byte scale, + string sourceColumn, + DataRowVersion sourceVersion, + object parameterValue) + { + IDbDataParameter parameter = dbCommand.CreateParameter(); + + parameter.ParameterName = dbProvider.CreateParameterNameForCollection(name); + + AssignParameterType(parameter, parameterType); + + if (size > 0) + { + parameter.Size = size; } - #endregion + parameter.Direction = direction; - #region Properties - - #endregion - - #region Methods - - #endregion - - public IDataParameter this[string parameterName] + if (isNullable) { - get { return (IDbDataParameter) dataParameterCollection[parameterName]; } - set { dataParameterCollection[parameterName] = value; } + AssignIsNullable(isNullable, parameter); } - public IDataParameter this[int index] + parameter.Precision = precision; + + if (scale > 0) { - get { return (IDbDataParameter) dataParameterCollection[index]; } - set { dataParameterCollection[index] = value; } + parameter.Scale = scale; } - public IDataParameterCollection DataParameterCollection + if (sourceColumn != null && sourceColumn != string.Empty) { - get { return dataParameterCollection; } + parameter.SourceColumn = sourceColumn; } - public int Count + parameter.SourceVersion = sourceVersion; + + parameter.Value = (parameterValue == null) ? DBNull.Value : parameterValue; + + dataParameterCollection.Add(parameter); + + return parameter; + } + + public IDbDataParameter AddParameter(string name, + Enum parameterType, + ParameterDirection direction, + bool isNullable, + byte precision, + byte scale, + string sourceColumn, + DataRowVersion sourceVersion, + object parameterValue) + { + return AddParameter(name, parameterType, 0, direction, isNullable, precision, scale, sourceColumn, sourceVersion, + parameterValue); + } + + public int Add(object parameterValue) + { + IDbDataParameter parameter = dbCommand.CreateParameter(); + parameter.Value = (parameterValue == null) ? DBNull.Value : parameterValue; + dataParameterCollection.Add(parameter); + return dataParameterCollection.Count - 1; + } + + public void AddRange(Array values) + { + foreach (Array value in values) { - get - { - return dataParameterCollection.Count; - } + Add(value); } - public bool Contains(string parameterName) + } + + public IDbDataParameter AddWithValue(string name, object parameterValue) + { + return AddParameter(name, null, -1, ParameterDirection.Input, false, + 0, 0, null, DataRowVersion.Default, parameterValue); + } + + public IDbDataParameter Add(string name, Enum parameterType) + { + return AddParameter(name, parameterType, -1, ParameterDirection.Input, + false, 0, 0, null, DataRowVersion.Default, null); + } + + public IDbDataParameter Add(string name, Enum parameterType, int size) + { + return AddParameter(name, parameterType, size, ParameterDirection.Input, + false, 0, 0, null, DataRowVersion.Default, null); + } + + public IDbDataParameter Add(string name, Enum parameterType, int size, string sourceColumn) + { + return AddParameter(name, parameterType, size, ParameterDirection.Input, + false, 0, 0, sourceColumn, DataRowVersion.Default, null); + } + + public IDbDataParameter AddOut(string name, Enum parameterType) + { + return AddParameter(name, parameterType, -1, ParameterDirection.Output, + false, 0, 0, null, DataRowVersion.Default, null); + } + + public IDbDataParameter AddOut(string name, Enum parameterType, int size) + { + return AddParameter(name, parameterType, size, ParameterDirection.Output, + false, 0, 0, null, DataRowVersion.Default, null); + } + + public IDbDataParameter AddInOut(string name, Enum parameterType) + { + return AddParameter(name, parameterType, -1, ParameterDirection.InputOutput, + false, 0, 0, null, DataRowVersion.Default, null); + } + + public IDbDataParameter AddInOut(string name, Enum parameterType, int size) + { + return AddParameter(name, parameterType, size, ParameterDirection.InputOutput, + false, 0, 0, null, DataRowVersion.Default, null); + } + + public IDbDataParameter AddReturn(string name, Enum parameterType) + { + return AddParameter(name, parameterType, -1, ParameterDirection.ReturnValue, + false, 0, 0, null, DataRowVersion.Default, null); + } + + public IDbDataParameter AddReturn(string name, Enum parameterType, int size) + { + return AddParameter(name, parameterType, size, ParameterDirection.ReturnValue, + false, 0, 0, null, DataRowVersion.Default, null); + } + + public object GetValue(string name) + { + IDataParameter parameter = dataParameterCollection[dbProvider.CreateParameterNameForCollection(name)] as IDataParameter; + if (parameter != null) { - return dataParameterCollection.Contains(parameterName); + return parameter.Value; } - public void AddParameter(IDataParameter dbParameter) + throw new InvalidDataAccessApiUsageException( + "object in IDataParameterCollection is not of the type IDataParameter, it is type [" + + dataParameterCollection[dbProvider.CreateParameterNameForCollection(name)].GetType() + "]."); + } + + public void SetValue(string name, object parameterValue) + { + IDbDataParameter parameter = dataParameterCollection[dbProvider.CreateParameterNameForCollection(name)] as IDbDataParameter; + if (parameter != null) { - dataParameterCollection.Add(dbParameter); - } - - - public IDbDataParameter AddParameter(string name, - Enum parameterType, - int size, - ParameterDirection direction, - bool isNullable, - byte precision, - byte scale, - string sourceColumn, - DataRowVersion sourceVersion, - object parameterValue) - { - IDbDataParameter parameter = dbCommand.CreateParameter(); - - parameter.ParameterName = dbProvider.CreateParameterNameForCollection(name); - - AssignParameterType(parameter, parameterType); - - if (size > 0) - { - parameter.Size = size; - } - parameter.Direction = direction; - - if (isNullable) - { - AssignIsNullable(isNullable, parameter); - } - - parameter.Precision = precision; - - if (scale > 0) - { - parameter.Scale = scale; - } - - if (sourceColumn != null && sourceColumn != string.Empty) - { - parameter.SourceColumn = sourceColumn; - } - - parameter.SourceVersion = sourceVersion; - parameter.Value = (parameterValue == null) ? DBNull.Value : parameterValue; - - dataParameterCollection.Add(parameter); - - return parameter; } + } - public IDbDataParameter AddParameter(string name, - Enum parameterType, - ParameterDirection direction, - bool isNullable, - byte precision, - byte scale, - string sourceColumn, - DataRowVersion sourceVersion, - object parameterValue) + protected void AssignParameterType(IDbDataParameter parameter, Enum parameterType) + { + if (parameterType != null) { - return AddParameter(name, parameterType, 0, direction, isNullable, precision, scale, sourceColumn, sourceVersion, - parameterValue); - } - - - public int Add(object parameterValue) - { - IDbDataParameter parameter = dbCommand.CreateParameter(); - parameter.Value = (parameterValue == null) ? DBNull.Value : parameterValue; - dataParameterCollection.Add(parameter); - return dataParameterCollection.Count - 1; - } - - public void AddRange(Array values) - { - foreach (Array value in values) + if (parameterType is DbType) { - Add(value); + parameter.DbType = (DbType) parameterType; } - } - - public IDbDataParameter AddWithValue(string name, object parameterValue) - { - return AddParameter(name, null, -1, ParameterDirection.Input, false, - 0, 0, null, DataRowVersion.Default, parameterValue); - } - - public IDbDataParameter Add(string name, Enum parameterType) - { - return AddParameter(name, parameterType, -1, ParameterDirection.Input, - false, 0, 0, null, DataRowVersion.Default, null); - } - - public IDbDataParameter Add(string name, Enum parameterType, int size) - { - return AddParameter(name, parameterType, size, ParameterDirection.Input, - false, 0, 0, null, DataRowVersion.Default, null); - } - - public IDbDataParameter Add(string name, Enum parameterType, int size, string sourceColumn) - { - return AddParameter(name, parameterType, size, ParameterDirection.Input, - false, 0, 0, sourceColumn, DataRowVersion.Default, null); - } - - public IDbDataParameter AddOut(string name, Enum parameterType) - { - return AddParameter(name, parameterType, -1, ParameterDirection.Output, - false, 0, 0, null, DataRowVersion.Default, null); - } - - public IDbDataParameter AddOut(string name, Enum parameterType, int size) - { - return AddParameter(name, parameterType, size, ParameterDirection.Output, - false, 0, 0, null, DataRowVersion.Default, null); - } - - public IDbDataParameter AddInOut(string name, Enum parameterType) - { - return AddParameter(name, parameterType, -1, ParameterDirection.InputOutput, - false, 0, 0, null, DataRowVersion.Default, null); - } - - public IDbDataParameter AddInOut(string name, Enum parameterType, int size) - { - return AddParameter(name, parameterType, size, ParameterDirection.InputOutput, - false, 0, 0, null, DataRowVersion.Default, null); - } - - public IDbDataParameter AddReturn(string name, Enum parameterType) - { - return AddParameter(name, parameterType, -1, ParameterDirection.ReturnValue, - false, 0, 0, null, DataRowVersion.Default, null); - } - - public IDbDataParameter AddReturn(string name, Enum parameterType, int size) - { - return AddParameter(name, parameterType, size, ParameterDirection.ReturnValue, - false, 0, 0, null, DataRowVersion.Default, null); - } - - - public object GetValue(string name) - { - IDataParameter parameter = dataParameterCollection[dbProvider.CreateParameterNameForCollection(name)] as IDataParameter; - if (parameter != null) + else { - return parameter.Value; - } - throw new InvalidDataAccessApiUsageException( - "object in IDataParameterCollection is not of the type IDataParameter, it is type [" + - dataParameterCollection[dbProvider.CreateParameterNameForCollection(name)].GetType() + "]."); - } - - public void SetValue(string name, object parameterValue) - { - IDbDataParameter parameter = dataParameterCollection[dbProvider.CreateParameterNameForCollection(name)] as IDbDataParameter; - if (parameter != null) - { - parameter.Value = (parameterValue == null) ? DBNull.Value : parameterValue; - } - } - - - protected void AssignParameterType(IDbDataParameter parameter, Enum parameterType) - { - if (parameterType != null) - { - if (parameterType is DbType) + if (parameterType.GetType() != dbProvider.DbMetadata.ParameterDbType) { - parameter.DbType = (DbType) parameterType; - } - else - { - if (parameterType.GetType() != dbProvider.DbMetadata.ParameterDbType) - { - throw new TypeMismatchDataAccessException("Invalid parameter type specified for parameter name [" - + parameter.ParameterName + "]. [" - + parameterType.GetType().AssemblyQualifiedName + "] is not of expected type [" - + dbProvider.DbMetadata.ParameterDbType.AssemblyQualifiedName + "]"); - } - dbProvider.DbMetadata.ParameterDbTypeProperty.SetValue(parameter, parameterType, null); + throw new TypeMismatchDataAccessException("Invalid parameter type specified for parameter name [" + + parameter.ParameterName + "]. [" + + parameterType.GetType().AssemblyQualifiedName + "] is not of expected type [" + + dbProvider.DbMetadata.ParameterDbType.AssemblyQualifiedName + "]"); } + + dbProvider.DbMetadata.ParameterDbTypeProperty.SetValue(parameter, parameterType, null); } } + } - protected void AssignIsNullable(bool isNullable, IDbDataParameter parameter) + protected void AssignIsNullable(bool isNullable, IDbDataParameter parameter) + { + PropertyInfo propertyInfo = dbProvider.DbMetadata.ParameterIsNullableProperty; + if (propertyInfo != null) { - PropertyInfo propertyInfo = dbProvider.DbMetadata.ParameterIsNullableProperty; - if (propertyInfo != null) - { - propertyInfo.SetValue(parameter, isNullable, null); - } - if (parameter.Value == null) - { - parameter.Value = DBNull.Value; - } + propertyInfo.SetValue(parameter, isNullable, null); } + if (parameter.Value == null) + { + parameter.Value = DBNull.Value; + } } } diff --git a/src/Spring/Spring.Data/Data/Common/DbParametersBuilder.cs b/src/Spring/Spring.Data/Data/Common/DbParametersBuilder.cs index a668daa6..97668979 100644 --- a/src/Spring/Spring.Data/Data/Common/DbParametersBuilder.cs +++ b/src/Spring/Spring.Data/Data/Common/DbParametersBuilder.cs @@ -20,72 +20,71 @@ using System.Collections; -namespace Spring.Data.Common +namespace Spring.Data.Common; + +/// +/// Assists in creating a collection of parameters by keeping track of all +/// IDbParameters its creates. After creating a number of parameters ask for the collection +/// with the GetParameters methods. +/// +/// This builder is stateful, you must create a new one for each collection +/// of parameters you would like to create. +/// Mark Pollack (.NET) +public class DbParametersBuilder : IDbParametersBuilder { + #region Fields + + private IDbProvider dbProvider; + private IList parameterList; + + #endregion + + #region Constructor (s) + /// - /// Assists in creating a collection of parameters by keeping track of all - /// IDbParameters its creates. After creating a number of parameters ask for the collection - /// with the GetParameters methods. + /// Initializes a new instance of the class. /// - /// This builder is stateful, you must create a new one for each collection - /// of parameters you would like to create. - /// Mark Pollack (.NET) - public class DbParametersBuilder : IDbParametersBuilder + public DbParametersBuilder(IDbProvider dbProvider) { - #region Fields - - private IDbProvider dbProvider; - private IList parameterList; - - #endregion - - #region Constructor (s) - - /// - /// Initializes a new instance of the class. - /// - public DbParametersBuilder(IDbProvider dbProvider) - { - this.dbProvider = dbProvider; - parameterList = new ArrayList(); - } - - #endregion - - #region Methods - - public IDbParameter Create() - { - IDbParameter p = new DbParameter(); - parameterList.Add(p); - return p; - } - - public IDbParameters GetParameters() - { - IDbParameters dbParameters = CreateDbParameters(); - foreach (IDbParameter parameter in parameterList) - { - dbParameters.AddParameter(parameter.GetName(), - parameter.GetDbType(), - parameter.GetSize(), - parameter.GetDirection(), - parameter.GetIsNullable(), - parameter.GetPrecision(), - parameter.GetScale(), - parameter.GetSourceColumn(), - parameter.GetSourceVersion(), - parameter.GetValue()); - } - return dbParameters; - } - - - protected IDbParameters CreateDbParameters() - { - return new DbParameters(dbProvider); - } - - #endregion + this.dbProvider = dbProvider; + parameterList = new ArrayList(); } + + #endregion + + #region Methods + + public IDbParameter Create() + { + IDbParameter p = new DbParameter(); + parameterList.Add(p); + return p; + } + + public IDbParameters GetParameters() + { + IDbParameters dbParameters = CreateDbParameters(); + foreach (IDbParameter parameter in parameterList) + { + dbParameters.AddParameter(parameter.GetName(), + parameter.GetDbType(), + parameter.GetSize(), + parameter.GetDirection(), + parameter.GetIsNullable(), + parameter.GetPrecision(), + parameter.GetScale(), + parameter.GetSourceColumn(), + parameter.GetSourceVersion(), + parameter.GetValue()); + } + + return dbParameters; + } + + protected IDbParameters CreateDbParameters() + { + return new DbParameters(dbProvider); + } + + #endregion } diff --git a/src/Spring/Spring.Data/Data/Common/DbProvider.cs b/src/Spring/Spring.Data/Data/Common/DbProvider.cs index b91f6114..233bb1cd 100644 --- a/src/Spring/Spring.Data/Data/Common/DbProvider.cs +++ b/src/Spring/Spring.Data/Data/Common/DbProvider.cs @@ -2,13 +2,13 @@ /* * Copyright � 2002-2011 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. @@ -19,220 +19,220 @@ #endregion using System.Data; - using Spring.Expressions; using Spring.Reflection.Dynamic; using Spring.Util; -namespace Spring.Data.Common +namespace Spring.Data.Common; + +/// +/// Implemenation of of DbProvider that uses metadata to create provider specific ADO.NET objects. +/// +public class DbProvider : IDbProvider { + private string connectionString; + private readonly IDbMetadata dbMetadata; + private readonly IDynamicConstructor newCommand; + private readonly IDynamicProperty commandBindByName; + private readonly IDynamicConstructor newConnection; + private readonly IDynamicConstructor newCommandBuilder; + private readonly IDynamicConstructor newDataAdapter; + private readonly IDynamicConstructor newParameter; + /// - /// Implemenation of of DbProvider that uses metadata to create provider specific ADO.NET objects. + /// Initializes a new instance of the class. /// - public class DbProvider : IDbProvider + /// The db metadata. + public DbProvider(IDbMetadata dbMetadata) { - private string connectionString; - private readonly IDbMetadata dbMetadata; - private readonly IDynamicConstructor newCommand; - private readonly IDynamicProperty commandBindByName; - private readonly IDynamicConstructor newConnection; - private readonly IDynamicConstructor newCommandBuilder; - private readonly IDynamicConstructor newDataAdapter; - private readonly IDynamicConstructor newParameter; + this.dbMetadata = dbMetadata; + newCommand = DynamicConstructor.Create(dbMetadata.CommandType.GetConstructor(Type.EmptyTypes)); - /// - /// Initializes a new instance of the class. - /// - /// The db metadata. - public DbProvider(IDbMetadata dbMetadata) + // Oracle needs custom bind by name property set to true as it's false by default + var bindByNameProperty = dbMetadata.CommandType.GetProperty("BindByName"); + if (bindByNameProperty != null && bindByNameProperty.CanWrite) { - this.dbMetadata = dbMetadata; - newCommand = DynamicConstructor.Create(dbMetadata.CommandType.GetConstructor(Type.EmptyTypes)); - - // Oracle needs custom bind by name property set to true as it's false by default - var bindByNameProperty = dbMetadata.CommandType.GetProperty("BindByName"); - if (bindByNameProperty != null && bindByNameProperty.CanWrite) + commandBindByName = DynamicProperty.Create(bindByNameProperty); + } + + newConnection = DynamicConstructor.Create(dbMetadata.ConnectionType.GetConstructor(Type.EmptyTypes)); + newCommandBuilder = DynamicConstructor.Create(dbMetadata.CommandBuilderType.GetConstructor(Type.EmptyTypes)); + newDataAdapter = DynamicConstructor.Create(dbMetadata.DataAdapterType.GetConstructor(Type.EmptyTypes)); + newParameter = DynamicConstructor.Create(dbMetadata.ParameterType.GetConstructor(Type.EmptyTypes)); + } + + /// + /// Returns a new command object for executing SQL statments/Stored Procedures + /// against the database. + /// + /// An new + public IDbCommand CreateCommand() + { + var command = newCommand.Invoke(ObjectUtils.EmptyObjects) as IDbCommand; + if (command != null && commandBindByName != null) + { + commandBindByName.SetValue(command, dbMetadata.BindByName); + } + + return command; + } + + /// + /// Returns a new instance of the providers CommandBuilder class. + /// + /// A new Command Builder + /// In .NET 1.1 there was no common base class or interface + /// for command builders, hence the return signature is object to + /// be portable (but more loosely typed) across .NET 1.1/2.0 + public object CreateCommandBuilder() + { + return newCommandBuilder.Invoke(ObjectUtils.EmptyObjects); + } + + /// + /// Returns a new connection object to communicate with the database. + /// + /// A new + public IDbConnection CreateConnection() + { + IDbConnection conn = newConnection.Invoke(ObjectUtils.EmptyObjects) as IDbConnection; + if (conn != null) + { + conn.ConnectionString = ConnectionString; + } + + return conn; + } + + /// + /// Returns a new adapter objects for use with offline DataSets. + /// + /// A new + public IDbDataAdapter CreateDataAdapter() + { + return newDataAdapter.Invoke(ObjectUtils.EmptyObjects) as IDbDataAdapter; + } + + /// + /// Returns a new parameter object for binding values to parameter + /// placeholders in SQL statements or Stored Procedure variables. + /// + /// A new + public IDbDataParameter CreateParameter() + { + return newParameter.Invoke(ObjectUtils.EmptyObjects) as IDbDataParameter; + } + + /// + /// Creates the name of the parameter in the format appropriate to use inside IDbCommand.CommandText. + /// + /// The unformatted name of the parameter. + /// + /// The parameter name formatted foran IDbCommand.CommandText. + /// + /// In most cases this adds the parameter prefix to the name passed into this method. + public string CreateParameterName(string name) + { + if (dbMetadata.BindByName) + { + if (DbMetadata.UseParameterPrefixInSql) { - commandBindByName = DynamicProperty.Create(bindByNameProperty); - } - - newConnection = DynamicConstructor.Create(dbMetadata.ConnectionType.GetConstructor(Type.EmptyTypes)); - newCommandBuilder = DynamicConstructor.Create(dbMetadata.CommandBuilderType.GetConstructor(Type.EmptyTypes)); - newDataAdapter = DynamicConstructor.Create(dbMetadata.DataAdapterType.GetConstructor(Type.EmptyTypes)); - newParameter = DynamicConstructor.Create(dbMetadata.ParameterType.GetConstructor(Type.EmptyTypes)); - } - - /// - /// Returns a new command object for executing SQL statments/Stored Procedures - /// against the database. - /// - /// An new - public IDbCommand CreateCommand() - { - var command = newCommand.Invoke(ObjectUtils.EmptyObjects) as IDbCommand; - if (command != null && commandBindByName != null) - { - commandBindByName.SetValue(command, dbMetadata.BindByName); - } - return command; - } - - /// - /// Returns a new instance of the providers CommandBuilder class. - /// - /// A new Command Builder - /// In .NET 1.1 there was no common base class or interface - /// for command builders, hence the return signature is object to - /// be portable (but more loosely typed) across .NET 1.1/2.0 - public object CreateCommandBuilder() - { - return newCommandBuilder.Invoke(ObjectUtils.EmptyObjects); - } - - /// - /// Returns a new connection object to communicate with the database. - /// - /// A new - public IDbConnection CreateConnection() - { - IDbConnection conn = newConnection.Invoke(ObjectUtils.EmptyObjects) as IDbConnection; - if (conn != null) - { - conn.ConnectionString = ConnectionString; - } - return conn; - } - - /// - /// Returns a new adapter objects for use with offline DataSets. - /// - /// A new - public IDbDataAdapter CreateDataAdapter() - { - return newDataAdapter.Invoke(ObjectUtils.EmptyObjects) as IDbDataAdapter; - } - - /// - /// Returns a new parameter object for binding values to parameter - /// placeholders in SQL statements or Stored Procedure variables. - /// - /// A new - public IDbDataParameter CreateParameter() - { - return newParameter.Invoke(ObjectUtils.EmptyObjects) as IDbDataParameter; - } - - /// - /// Creates the name of the parameter in the format appropriate to use inside IDbCommand.CommandText. - /// - /// The unformatted name of the parameter. - /// - /// The parameter name formatted foran IDbCommand.CommandText. - /// - /// In most cases this adds the parameter prefix to the name passed into this method. - public string CreateParameterName(string name) - { - if (dbMetadata.BindByName) - { - if (DbMetadata.UseParameterPrefixInSql) - { - return DbMetadata.ParameterNamePrefix + name; - } - else - { - return name; - } + return DbMetadata.ParameterNamePrefix + name; } else { - return DbMetadata.ParameterNamePrefix; + return name; } } - - /// - /// Creates the name ofthe parameter in the format appropriate for an IDataParameter, i.e. to be - /// part of a IDataParameterCollection. - /// - /// The unformatted name of the parameter. - /// - /// The parameter name formatted for an IDataParameter - /// - public string CreateParameterNameForCollection(string name) + else { - if (dbMetadata.BindByName) + return DbMetadata.ParameterNamePrefix; + } + } + + /// + /// Creates the name ofthe parameter in the format appropriate for an IDataParameter, i.e. to be + /// part of a IDataParameterCollection. + /// + /// The unformatted name of the parameter. + /// + /// The parameter name formatted for an IDataParameter + /// + public string CreateParameterNameForCollection(string name) + { + if (dbMetadata.BindByName) + { + if (DbMetadata.UseParameterNamePrefixInParameterCollection) { - if (DbMetadata.UseParameterNamePrefixInParameterCollection) - { - return DbMetadata.ParameterNamePrefix + name; - } - else - { - return name; - } + return DbMetadata.ParameterNamePrefix + name; } else { - return DbMetadata.ParameterNamePrefix; + return name; } } - - /// - /// Return metadata information about the database provider - /// - /// - public IDbMetadata DbMetadata + else { - get { return dbMetadata; } + return DbMetadata.ParameterNamePrefix; } + } - /// - /// Connection string used to create connections. - /// - /// - public string ConnectionString + /// + /// Return metadata information about the database provider + /// + /// + public IDbMetadata DbMetadata + { + get { return dbMetadata; } + } + + /// + /// Connection string used to create connections. + /// + /// + public string ConnectionString + { + get { return connectionString; } + set { connectionString = value; } + } + + /// + /// Extracts the provider specific error code as a string. + /// + /// The data access exception. + /// The provider specific error code + public string ExtractError(Exception e) + { + if (!StringUtils.IsNullOrEmpty(dbMetadata.ErrorCodeExceptionExpression)) { - get { return connectionString; } - set { connectionString = value; } + return ExpressionEvaluator.GetValue(e, dbMetadata.ErrorCodeExceptionExpression).ToString(); } - - /// - /// Extracts the provider specific error code as a string. - /// - /// The data access exception. - /// The provider specific error code - public string ExtractError(Exception e) + else { - if (!StringUtils.IsNullOrEmpty(dbMetadata.ErrorCodeExceptionExpression)) - { - return ExpressionEvaluator.GetValue(e, dbMetadata.ErrorCodeExceptionExpression).ToString(); - } - else - { - return "Could not extract error code exception type." + e.GetType(); - } + return "Could not extract error code exception type." + e.GetType(); } + } - /// - /// Determines whether the provided exception is in fact related - /// to database access. This can be provider dependent in .NET 1.1 since - /// there isn't a common base class for ADO.NET exceptions. - /// - /// The exception thrown when performing data access - /// operations. - /// - /// true if is a valid data access exception for the specified - /// exception; otherwise, false. - /// - public bool IsDataAccessException(Exception e) + /// + /// Determines whether the provided exception is in fact related + /// to database access. This can be provider dependent in .NET 1.1 since + /// there isn't a common base class for ADO.NET exceptions. + /// + /// The exception thrown when performing data access + /// operations. + /// + /// true if is a valid data access exception for the specified + /// exception; otherwise, false. + /// + public bool IsDataAccessException(Exception e) + { + if (e is System.Data.Common.DbException) { - if (e is System.Data.Common.DbException) - { - return true; - } - else - { - return false; - } + return true; + } + else + { + return false; } } } diff --git a/src/Spring/Spring.Data/Data/Common/DbProviderConfigurer.cs b/src/Spring/Spring.Data/Data/Common/DbProviderConfigurer.cs index 150436d1..2d4a3c98 100644 --- a/src/Spring/Spring.Data/Data/Common/DbProviderConfigurer.cs +++ b/src/Spring/Spring.Data/Data/Common/DbProviderConfigurer.cs @@ -23,79 +23,79 @@ using Spring.Core; using Spring.Core.IO; using Spring.Objects.Factory.Config; -namespace Spring.Data.Common +namespace Spring.Data.Common; + +/// +/// +/// +/// Mark Pollack +public class DbProviderConfigurer : IObjectFactoryPostProcessor, IOrdered { + #region Fields + + private static readonly ILogger log = LogManager.GetLogger(); + + private int order = Int32.MinValue; + + private IResource providerResource; + + #endregion + + #region Constructor + /// - /// + /// Initializes a new instance of the class. /// - /// Mark Pollack - public class DbProviderConfigurer : IObjectFactoryPostProcessor, IOrdered + public DbProviderConfigurer() { - #region Fields - - private static readonly ILogger log = LogManager.GetLogger(); - - private int order = Int32.MinValue; - - private IResource providerResource; - - #endregion - - #region Constructor - /// - /// Initializes a new instance of the class. - /// - public DbProviderConfigurer() - { - } - #endregion - - #region Properties - - /// - /// Gets or sets the provider resource which contains additional IDbProvider definitions. - /// - /// The provider resource. - public IResource ProviderResource - { - get { return providerResource; } - set { providerResource = value; } - } - - #endregion - - #region Implementation of IObjectFactoryPostProcessor - - /// - /// Modify the application context's internal object factory after its - /// standard initialization. - /// - /// The object factory used by the application context. - /// - ///

- /// All object definitions will have been loaded, but no objects will have - /// been instantiated yet. This allows for overriding or adding properties - /// even to eager-initializing objects. - ///

- ///
- /// - /// In case of errors. - /// - public void PostProcessObjectFactory(IConfigurableListableObjectFactory factory) - { - DbProviderFactory.DBPROVIDER_ADDITIONAL_RESOURCE_NAME = providerResource.Uri.AbsoluteUri; - } - - #endregion - - #region Implementation of IOrdered - - public int Order - { - get { return order; } - } - - #endregion } + #endregion + + #region Properties + + /// + /// Gets or sets the provider resource which contains additional IDbProvider definitions. + /// + /// The provider resource. + public IResource ProviderResource + { + get { return providerResource; } + set { providerResource = value; } + } + + #endregion + + #region Implementation of IObjectFactoryPostProcessor + + /// + /// Modify the application context's internal object factory after its + /// standard initialization. + /// + /// The object factory used by the application context. + /// + ///

+ /// All object definitions will have been loaded, but no objects will have + /// been instantiated yet. This allows for overriding or adding properties + /// even to eager-initializing objects. + ///

+ ///
+ /// + /// In case of errors. + /// + public void PostProcessObjectFactory(IConfigurableListableObjectFactory factory) + { + DbProviderFactory.DBPROVIDER_ADDITIONAL_RESOURCE_NAME = providerResource.Uri.AbsoluteUri; + } + + #endregion + + #region Implementation of IOrdered + + public int Order + { + get { return order; } + } + + #endregion } diff --git a/src/Spring/Spring.Data/Data/Common/DbProviderFactory.cs b/src/Spring/Spring.Data/Data/Common/DbProviderFactory.cs index af0dbd72..c72e0906 100644 --- a/src/Spring/Spring.Data/Data/Common/DbProviderFactory.cs +++ b/src/Spring/Spring.Data/Data/Common/DbProviderFactory.cs @@ -20,125 +20,121 @@ using Spring.Context.Support; using Spring.Core.IO; using Spring.Util; -namespace Spring.Data.Common +namespace Spring.Data.Common; + +/// +/// Create DbProviders based on configuration information in assembly resource +/// dbproviders.xml +/// +/// +/// +/// +/// TODO: Provide over-ride resource location. +/// TODO: Add error codes to provider. +/// +/// Mark Pollack (.NET) +public class DbProviderFactory { /// - /// Create DbProviders based on configuration information in assembly resource - /// dbproviders.xml - /// - /// + /// The shared log instance for this class (and derived classes). + /// + protected static ILogger log = LogManager.GetLogger(); + + private static readonly string DBPROVIDER_DEFAULT_RESOURCE_NAME = + "assembly://" + typeof(DbProviderFactory).Assembly.FullName + "/Spring.Data.Common/dbproviders.xml"; + + public static string DBPROVIDER_ADDITIONAL_RESOURCE_NAME = + "file://dbProviders.xml"; + + private static readonly string DBPROVIDER_CONTEXTNAME = "DBPROVIDERFACTORY_CONTEXT"; + + private volatile static XmlApplicationContext ctx; + + /// + /// Initializes a new instance of the class. + /// + static DbProviderFactory() + { + } + + /// + /// Gets the DbProvider given an identifying name. /// /// - /// TODO: Provide over-ride resource location. - /// TODO: Add error codes to provider. + /// Familiar names for the .NET 2.0 provider model are supported, i.e. + /// System.Data.SqlClient. Refer to the documentation for a complete + /// listing of supported DbProviders and their names. You may + /// also use the method GetDbProviderClasses or obtain the + /// underlying IApplicationContext to progammatically obtain information + /// about supported providers. /// - /// Mark Pollack (.NET) - public class DbProviderFactory + /// Name of the provider invariant. + /// + public static IDbProvider GetDbProvider(string providerInvariantName) { - /// - /// The shared log instance for this class (and derived classes). - /// - protected static ILogger log = LogManager.GetLogger(); + InitializeDbProviderFactoryIfNeeded(); - private static readonly string DBPROVIDER_DEFAULT_RESOURCE_NAME = - "assembly://" + typeof(DbProviderFactory).Assembly.FullName + "/Spring.Data.Common/dbproviders.xml"; + return ctx.GetObject(providerInvariantName, typeof(IDbProvider)) as IDbProvider; + } - public static string DBPROVIDER_ADDITIONAL_RESOURCE_NAME = - "file://dbProviders.xml"; - - private static readonly string DBPROVIDER_CONTEXTNAME = "DBPROVIDERFACTORY_CONTEXT"; - - private volatile static XmlApplicationContext ctx; - - /// - /// Initializes a new instance of the class. - /// - static DbProviderFactory() - { - } - - /// - /// Gets the DbProvider given an identifying name. - /// - /// - /// Familiar names for the .NET 2.0 provider model are supported, i.e. - /// System.Data.SqlClient. Refer to the documentation for a complete - /// listing of supported DbProviders and their names. You may - /// also use the method GetDbProviderClasses or obtain the - /// underlying IApplicationContext to progammatically obtain information - /// about supported providers. - /// - /// Name of the provider invariant. - /// - public static IDbProvider GetDbProvider(string providerInvariantName) + /// + /// Gets the application context that contains the definitions of the + /// various providers. + /// + /// This method should rarely, if ever, be used in + /// application code. It is used by the framework itself + /// to map other data access products abstractions for a 'DbProvider/DataSource' + /// onto Spring's model. + /// The application context. + public static IApplicationContext ApplicationContext + { + get { InitializeDbProviderFactoryIfNeeded(); - - return ctx.GetObject(providerInvariantName, typeof(IDbProvider)) as IDbProvider; - + return ctx; } + } - /// - /// Gets the application context that contains the definitions of the - /// various providers. - /// - /// This method should rarely, if ever, be used in - /// application code. It is used by the framework itself - /// to map other data access products abstractions for a 'DbProvider/DataSource' - /// onto Spring's model. - /// The application context. - public static IApplicationContext ApplicationContext + //TODO GetDbProviderClasses + private static void InitializeDbProviderFactoryIfNeeded() + { + if (ctx == null) { - get + lock (typeof(DbProviderFactory)) { - InitializeDbProviderFactoryIfNeeded(); - return ctx; - } - } + if (ctx == null) + { + try + { + ConfigurableResourceLoader loader = new ConfigurableResourceLoader(DBPROVIDER_ADDITIONAL_RESOURCE_NAME); - //TODO GetDbProviderClasses - private static void InitializeDbProviderFactoryIfNeeded() - { - if (ctx == null) - { - lock(typeof(DbProviderFactory)) - { - if (ctx == null) - { - try - { - ConfigurableResourceLoader loader = new ConfigurableResourceLoader(DBPROVIDER_ADDITIONAL_RESOURCE_NAME); + if (loader.GetResource(DBPROVIDER_ADDITIONAL_RESOURCE_NAME).Exists) + { + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug("Loading additional DbProviders from " + DBPROVIDER_ADDITIONAL_RESOURCE_NAME); + } + ctx = new XmlApplicationContext(DBPROVIDER_CONTEXTNAME, true, new string[] { DBPROVIDER_DEFAULT_RESOURCE_NAME, DBPROVIDER_ADDITIONAL_RESOURCE_NAME }); + } + else + { + ctx = new XmlApplicationContext(DBPROVIDER_CONTEXTNAME, true, new string[] { DBPROVIDER_DEFAULT_RESOURCE_NAME }); + } - if (loader.GetResource(DBPROVIDER_ADDITIONAL_RESOURCE_NAME).Exists) - { - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug("Loading additional DbProviders from " + DBPROVIDER_ADDITIONAL_RESOURCE_NAME); - } - - ctx = new XmlApplicationContext(DBPROVIDER_CONTEXTNAME, true, new string[] { DBPROVIDER_DEFAULT_RESOURCE_NAME, - DBPROVIDER_ADDITIONAL_RESOURCE_NAME}); - } - else - { - ctx = new XmlApplicationContext(DBPROVIDER_CONTEXTNAME, true, new string[] { DBPROVIDER_DEFAULT_RESOURCE_NAME }); - } - - if (log.IsEnabled(LogLevel.Information)) - { - var dbProviderNames = ctx.GetObjectNames(); - log.LogInformation($"{dbProviderNames.Count} DbProviders Available. [{StringUtils.CollectionToCommaDelimitedString(dbProviderNames)}]"); - } - } - catch (Exception e) - { - string message = "Error processing " + DBPROVIDER_DEFAULT_RESOURCE_NAME; - log.LogError(e, message); - throw; - } - } - } + if (log.IsEnabled(LogLevel.Information)) + { + var dbProviderNames = ctx.GetObjectNames(); + log.LogInformation($"{dbProviderNames.Count} DbProviders Available. [{StringUtils.CollectionToCommaDelimitedString(dbProviderNames)}]"); + } + } + catch (Exception e) + { + string message = "Error processing " + DBPROVIDER_DEFAULT_RESOURCE_NAME; + log.LogError(e, message); + throw; + } + } } } } diff --git a/src/Spring/Spring.Data/Data/Common/DbProviderFactoryObject.cs b/src/Spring/Spring.Data/Data/Common/DbProviderFactoryObject.cs index 0e3b4477..64ea3e09 100644 --- a/src/Spring/Spring.Data/Data/Common/DbProviderFactoryObject.cs +++ b/src/Spring/Spring.Data/Data/Common/DbProviderFactoryObject.cs @@ -21,166 +21,166 @@ using Spring.Objects.Factory; using Spring.Util; -namespace Spring.Data.Common +namespace Spring.Data.Common; + +/// +/// A implementation that +/// creates instances of the class. +/// +/// Typically used as a convenience for retrieving shared +/// in a Spring XML configuration file as compared to +/// using explict factory method support. +/// +public class DbProviderFactoryObject : IFactoryObject, IInitializingObject { + #region Fields + + private string provider; + private string connectionString; + private IDbProvider dbProvider; + + #endregion + + #region Constructor + /// - /// A implementation that - /// creates instances of the class. + /// Creates a new instance of the class. /// - /// Typically used as a convenience for retrieving shared - /// in a Spring XML configuration file as compared to - /// using explict factory method support. - /// - public class DbProviderFactoryObject : IFactoryObject, IInitializingObject + public DbProviderFactoryObject() { - #region Fields - - private string provider; - private string connectionString; - private IDbProvider dbProvider; - - #endregion - - #region Constructor - - /// - /// Creates a new instance of the class. - /// - public DbProviderFactoryObject() - { - } - - #endregion - - #region Properties - - /// - /// Gets or sets the name of the database provider. - /// - /// The name of the database provider. - public string Provider - { - get { return provider; } - set - { - AssertUtils.ArgumentHasText(value, "The 'Provider' property must have a value."); - provider = value.Trim(); - } - } - - /// - /// Gets or sets the connection string. - /// - /// The connection string. - public string ConnectionString - { - get { return connectionString; } - set - { - AssertUtils.ArgumentHasText(value, "The 'ConnectionString' property must have a value."); - connectionString = value.Trim(); - } - } - - #endregion - - #region IFactoryObject Members - - /// - /// Return an instance of and IDbProvider as configured by this factory - /// managed by this factory. - /// - /// - /// The same (singleton) instance of the IDbProvider managed by - /// this factory. - /// - /// - /// - /// If this method is being called in the context of an enclosing IoC container and - /// returns , the IoC container will consider this factory - /// object as not being fully initialized and throw a corresponding (and most - /// probably fatal) exception. - /// - /// - public virtual object GetObject() - { - lock (this) - { - if (dbProvider == null) - { - ValidateProperties(); - dbProvider = CreateProviderInstance(); - } - - return dbProvider; - } - } - - /// - /// Create the actual provider instance as specified by this factory's configuration properties. - /// - /// the fully configured provider - protected virtual IDbProvider CreateProviderInstance() - { - IDbProvider providerInstance = DbProviderFactory.GetDbProvider(Provider); - if (connectionString != null) - { - providerInstance.ConnectionString = this.connectionString; - } - return providerInstance; - } - - /// - /// Return the type of - /// - public virtual Type ObjectType - { - get { return typeof (IDbProvider); } - } - - /// - /// Returns true, as the the object managed by this factory is a singleton. - /// - /// - public virtual bool IsSingleton - { - get { return true; } - } - - #endregion - - #region IInitializingObject Memebers - - /// - /// Validates that the provider name is specified. - /// - /// - /// Invoked by an - /// after it has injected all of an object's dependencies. - /// - /// - /// In the event of not setting the ProviderName. - /// - public virtual void AfterPropertiesSet() - { - ValidateProperties(); - } - - #endregion - - #region Private Memebers - - /// - /// Validates the properties. - /// - private void ValidateProperties() - { - if (StringUtils.IsNullOrEmpty(Provider)) - { - throw new ArgumentException("The 'DbProviderName' property has not been set."); - } - } - - #endregion } + + #endregion + + #region Properties + + /// + /// Gets or sets the name of the database provider. + /// + /// The name of the database provider. + public string Provider + { + get { return provider; } + set + { + AssertUtils.ArgumentHasText(value, "The 'Provider' property must have a value."); + provider = value.Trim(); + } + } + + /// + /// Gets or sets the connection string. + /// + /// The connection string. + public string ConnectionString + { + get { return connectionString; } + set + { + AssertUtils.ArgumentHasText(value, "The 'ConnectionString' property must have a value."); + connectionString = value.Trim(); + } + } + + #endregion + + #region IFactoryObject Members + + /// + /// Return an instance of and IDbProvider as configured by this factory + /// managed by this factory. + /// + /// + /// The same (singleton) instance of the IDbProvider managed by + /// this factory. + /// + /// + /// + /// If this method is being called in the context of an enclosing IoC container and + /// returns , the IoC container will consider this factory + /// object as not being fully initialized and throw a corresponding (and most + /// probably fatal) exception. + /// + /// + public virtual object GetObject() + { + lock (this) + { + if (dbProvider == null) + { + ValidateProperties(); + dbProvider = CreateProviderInstance(); + } + + return dbProvider; + } + } + + /// + /// Create the actual provider instance as specified by this factory's configuration properties. + /// + /// the fully configured provider + protected virtual IDbProvider CreateProviderInstance() + { + IDbProvider providerInstance = DbProviderFactory.GetDbProvider(Provider); + if (connectionString != null) + { + providerInstance.ConnectionString = this.connectionString; + } + + return providerInstance; + } + + /// + /// Return the type of + /// + public virtual Type ObjectType + { + get { return typeof(IDbProvider); } + } + + /// + /// Returns true, as the the object managed by this factory is a singleton. + /// + /// + public virtual bool IsSingleton + { + get { return true; } + } + + #endregion + + #region IInitializingObject Memebers + + /// + /// Validates that the provider name is specified. + /// + /// + /// Invoked by an + /// after it has injected all of an object's dependencies. + /// + /// + /// In the event of not setting the ProviderName. + /// + public virtual void AfterPropertiesSet() + { + ValidateProperties(); + } + + #endregion + + #region Private Memebers + + /// + /// Validates the properties. + /// + private void ValidateProperties() + { + if (StringUtils.IsNullOrEmpty(Provider)) + { + throw new ArgumentException("The 'DbProviderName' property has not been set."); + } + } + + #endregion } diff --git a/src/Spring/Spring.Data/Data/Common/DelegatingDbProvider.cs b/src/Spring/Spring.Data/Data/Common/DelegatingDbProvider.cs index 69494d7e..f3689082 100644 --- a/src/Spring/Spring.Data/Data/Common/DelegatingDbProvider.cs +++ b/src/Spring/Spring.Data/Data/Common/DelegatingDbProvider.cs @@ -22,205 +22,201 @@ using System.Data; using Spring.Objects.Factory; using Spring.Util; -namespace Spring.Data.Common +namespace Spring.Data.Common; + +/// +/// IDbProvider implementation that delegates all calls to a given target +/// IDbProvider +/// +/// Mark Pollack +public class DelegatingDbProvider : IDbProvider, IInitializingObject { + private IDbProvider targetDbProvider; + /// - /// IDbProvider implementation that delegates all calls to a given target - /// IDbProvider + /// Initializes a new instance of the class. /// - /// Mark Pollack - public class DelegatingDbProvider : IDbProvider, IInitializingObject + public DelegatingDbProvider() { - private IDbProvider targetDbProvider; - - - /// - /// Initializes a new instance of the class. - /// - public DelegatingDbProvider() - { - } - - - /// - /// Initializes a new instance of the class. - /// - /// The target db provider. - public DelegatingDbProvider(IDbProvider targetDbProvider) - { - this.targetDbProvider = targetDbProvider; - } - - - /// - /// Gets or sets the target IDbProvider that this IDbProvider should delegate to - /// - /// The target db provider. - public IDbProvider TargetDbProvider - { - get { return targetDbProvider; } - set - { - AssertUtils.ArgumentNotNull(value,"TargetDbProvider"); - targetDbProvider = value; - } - } - - #region IDbProvider Members - - /// - /// Returns a new command object for executing SQL statments/Stored Procedures - /// against the database. - /// - /// An new - public virtual IDbCommand CreateCommand() - { - return TargetDbProvider.CreateCommand(); - } - - /// - /// Returns a new instance of the providers CommandBuilder class. - /// - /// In .NET 1.1 there was no common base class or interface - /// for command builders, hence the return signature is object to - /// be portable (but more loosely typed) across .NET 1.1/2.0 - /// A new Command Builder - public virtual object CreateCommandBuilder() - { - return TargetDbProvider.CreateCommandBuilder(); - } - - /// - /// Returns a new connection object to communicate with the database. - /// - /// A new - public virtual IDbConnection CreateConnection() - { - return TargetDbProvider.CreateConnection(); - } - - /// - /// Returns a new adapter objects for use with offline DataSets. - /// - /// A new - public virtual IDbDataAdapter CreateDataAdapter() - { - return TargetDbProvider.CreateDataAdapter(); - } - - /// - /// Returns a new parameter object for binding values to parameter - /// placeholders in SQL statements or Stored Procedure variables. - /// - /// A new - public virtual IDbDataParameter CreateParameter() - { - return TargetDbProvider.CreateParameter(); - } - - /// - /// Creates the name of the parameter in the format appropriate to use inside IDbCommand.CommandText. - /// - /// In most cases this adds the parameter prefix to the name passed into this method. - /// The unformatted name of the parameter. - /// The parameter name formatted foran IDbCommand.CommandText. - public virtual string CreateParameterName(string name) - { - return TargetDbProvider.CreateParameterName(name); - } - - /// - /// Creates the name ofthe parameter in the format appropriate for an IDataParameter, i.e. to be - /// part of a IDataParameterCollection. - /// - /// The unformatted name of the parameter. - /// The parameter name formatted for an IDataParameter - public virtual string CreateParameterNameForCollection(string name) - { - return TargetDbProvider.CreateParameterNameForCollection(name); - } - - /// - /// Return metadata information about the database provider - /// - public virtual IDbMetadata DbMetadata - { - get { return TargetDbProvider.DbMetadata; } - } - - /// - /// Connection string used to create connections. - /// - public virtual string ConnectionString - { - get { return TargetDbProvider.ConnectionString; } - set { TargetDbProvider.ConnectionString = value; } - } - - /// - /// Extracts the provider specific error code as a string. - /// - /// The data access exception. - /// The provider specific error code - public virtual string ExtractError(Exception e) - { - return TargetDbProvider.ExtractError(e); - } - - /// - /// Determines whether the provided exception is in fact related - /// to database access. This can be provider dependent in .NET 1.1 since - /// there isn't a common base class for ADO.NET exceptions. - /// - /// The exception thrown when performing data access - /// operations. - /// - /// true if is a valid data access exception for the specified - /// exception; otherwise, false. - /// - public virtual bool IsDataAccessException(Exception e) - { - return TargetDbProvider.IsDataAccessException(e); - } - - #endregion - - #region IInitializingObject Members - - /// - /// Invoked by an - /// after it has injected all of an object's dependencies. - /// - /// - ///

- /// This method allows the object instance to perform the kind of - /// initialization only possible when all of it's dependencies have - /// been injected (set), and to throw an appropriate exception in the - /// event of misconfiguration. - ///

- ///

- /// Please do consult the class level documentation for the - /// interface for a - /// description of exactly when this method is invoked. In - /// particular, it is worth noting that the - /// - /// and - /// callbacks will have been invoked prior to this method being - /// called. - ///

- ///
- /// - /// In the event of misconfiguration (such as the failure to set a - /// required property) or if initialization fails. - /// - public virtual void AfterPropertiesSet() - { - if (TargetDbProvider == null) - { - throw new ArgumentNullException("Property 'TargetDbProvider' is required."); - } - } - - #endregion } + + /// + /// Initializes a new instance of the class. + /// + /// The target db provider. + public DelegatingDbProvider(IDbProvider targetDbProvider) + { + this.targetDbProvider = targetDbProvider; + } + + /// + /// Gets or sets the target IDbProvider that this IDbProvider should delegate to + /// + /// The target db provider. + public IDbProvider TargetDbProvider + { + get { return targetDbProvider; } + set + { + AssertUtils.ArgumentNotNull(value, "TargetDbProvider"); + targetDbProvider = value; + } + } + + #region IDbProvider Members + + /// + /// Returns a new command object for executing SQL statments/Stored Procedures + /// against the database. + /// + /// An new + public virtual IDbCommand CreateCommand() + { + return TargetDbProvider.CreateCommand(); + } + + /// + /// Returns a new instance of the providers CommandBuilder class. + /// + /// In .NET 1.1 there was no common base class or interface + /// for command builders, hence the return signature is object to + /// be portable (but more loosely typed) across .NET 1.1/2.0 + /// A new Command Builder + public virtual object CreateCommandBuilder() + { + return TargetDbProvider.CreateCommandBuilder(); + } + + /// + /// Returns a new connection object to communicate with the database. + /// + /// A new + public virtual IDbConnection CreateConnection() + { + return TargetDbProvider.CreateConnection(); + } + + /// + /// Returns a new adapter objects for use with offline DataSets. + /// + /// A new + public virtual IDbDataAdapter CreateDataAdapter() + { + return TargetDbProvider.CreateDataAdapter(); + } + + /// + /// Returns a new parameter object for binding values to parameter + /// placeholders in SQL statements or Stored Procedure variables. + /// + /// A new + public virtual IDbDataParameter CreateParameter() + { + return TargetDbProvider.CreateParameter(); + } + + /// + /// Creates the name of the parameter in the format appropriate to use inside IDbCommand.CommandText. + /// + /// In most cases this adds the parameter prefix to the name passed into this method. + /// The unformatted name of the parameter. + /// The parameter name formatted foran IDbCommand.CommandText. + public virtual string CreateParameterName(string name) + { + return TargetDbProvider.CreateParameterName(name); + } + + /// + /// Creates the name ofthe parameter in the format appropriate for an IDataParameter, i.e. to be + /// part of a IDataParameterCollection. + /// + /// The unformatted name of the parameter. + /// The parameter name formatted for an IDataParameter + public virtual string CreateParameterNameForCollection(string name) + { + return TargetDbProvider.CreateParameterNameForCollection(name); + } + + /// + /// Return metadata information about the database provider + /// + public virtual IDbMetadata DbMetadata + { + get { return TargetDbProvider.DbMetadata; } + } + + /// + /// Connection string used to create connections. + /// + public virtual string ConnectionString + { + get { return TargetDbProvider.ConnectionString; } + set { TargetDbProvider.ConnectionString = value; } + } + + /// + /// Extracts the provider specific error code as a string. + /// + /// The data access exception. + /// The provider specific error code + public virtual string ExtractError(Exception e) + { + return TargetDbProvider.ExtractError(e); + } + + /// + /// Determines whether the provided exception is in fact related + /// to database access. This can be provider dependent in .NET 1.1 since + /// there isn't a common base class for ADO.NET exceptions. + /// + /// The exception thrown when performing data access + /// operations. + /// + /// true if is a valid data access exception for the specified + /// exception; otherwise, false. + /// + public virtual bool IsDataAccessException(Exception e) + { + return TargetDbProvider.IsDataAccessException(e); + } + + #endregion + + #region IInitializingObject Members + + /// + /// Invoked by an + /// after it has injected all of an object's dependencies. + /// + /// + ///

+ /// This method allows the object instance to perform the kind of + /// initialization only possible when all of it's dependencies have + /// been injected (set), and to throw an appropriate exception in the + /// event of misconfiguration. + ///

+ ///

+ /// Please do consult the class level documentation for the + /// interface for a + /// description of exactly when this method is invoked. In + /// particular, it is worth noting that the + /// + /// and + /// callbacks will have been invoked prior to this method being + /// called. + ///

+ ///
+ /// + /// In the event of misconfiguration (such as the failure to set a + /// required property) or if initialization fails. + /// + public virtual void AfterPropertiesSet() + { + if (TargetDbProvider == null) + { + throw new ArgumentNullException("Property 'TargetDbProvider' is required."); + } + } + + #endregion } diff --git a/src/Spring/Spring.Data/Data/Common/ErrorCodes.cs b/src/Spring/Spring.Data/Data/Common/ErrorCodes.cs index d855ff48..23cfa7a3 100644 --- a/src/Spring/Spring.Data/Data/Common/ErrorCodes.cs +++ b/src/Spring/Spring.Data/Data/Common/ErrorCodes.cs @@ -18,133 +18,133 @@ #endregion -namespace Spring.Data.Common +namespace Spring.Data.Common; + +/// +/// Holds ADO.NET error codes for a particular provider. +/// +/// +/// Used by ErrorCodeExceptionTranslator. The embedded resource +/// "dbProviders.xml" in Spring.Data.Common contains default +/// ErrorCodes instances for various providers. +/// +/// Mark Pollack (.NET) +public class ErrorCodes { + #region Fields + + private string[] databaseProductNames; + + private string[] badSqlGrammarCodes = new String[0]; + + private string[] invalidResultSetAccessCodes = new String[0]; + + private string[] duplicateKeyCodes = new string[0]; + + private string[] dataIntegrityViolationCodes = new String[0]; + + private string[] permissionDeniedCodes = new String[0]; + + private string[] dataAccessResourceFailureCodes = new String[0]; + + private string[] transientAccessResourceFailureCodes = new String[0]; + + private string[] cannotAcquireLockCodes = new String[0]; + + private string[] deadlockLoserCodes = new String[0]; + + private string[] cannotSerializeTransactionCodes = new String[0]; + + // CustomErrorCodesTranslation[] customTranslations; + + #endregion + + #region Constructor (s) + /// - /// Holds ADO.NET error codes for a particular provider. + /// Initializes a new instance of the class. /// - /// - /// Used by ErrorCodeExceptionTranslator. The embedded resource - /// "dbProviders.xml" in Spring.Data.Common contains default - /// ErrorCodes instances for various providers. - /// - /// Mark Pollack (.NET) - public class ErrorCodes + public ErrorCodes() { - #region Fields - private string[] databaseProductNames; - - private string[] badSqlGrammarCodes = new String[0]; - - private string[] invalidResultSetAccessCodes = new String[0]; - - private string[] duplicateKeyCodes = new string[0]; - - private string[] dataIntegrityViolationCodes = new String[0]; - - private string[] permissionDeniedCodes = new String[0]; - - private string[] dataAccessResourceFailureCodes = new String[0]; - - private string[] transientAccessResourceFailureCodes = new String[0]; - - private string[] cannotAcquireLockCodes = new String[0]; - - private string[] deadlockLoserCodes = new String[0]; - - private string[] cannotSerializeTransactionCodes = new String[0]; - - // CustomErrorCodesTranslation[] customTranslations; - #endregion - - #region Constructor (s) - /// - /// Initializes a new instance of the class. - /// - public ErrorCodes() - { - - } - - #endregion - - #region Properties - public string DatabaseProductName - { - get - { - return (databaseProductNames != null && databaseProductNames.Length > 0 ? - databaseProductNames[0] : null); - } - } - - public string[] DatabaseProductNames - { - get { return databaseProductNames; } - set { databaseProductNames = value; } - } - - public string[] BadSqlGrammarCodes - { - get { return badSqlGrammarCodes; } - set { badSqlGrammarCodes = value; } - } - - public string[] InvalidResultSetAccessCodes - { - get { return invalidResultSetAccessCodes; } - set { invalidResultSetAccessCodes = value; } - } - - public string[] DataAccessResourceFailureCodes - { - get { return dataAccessResourceFailureCodes; } - set { dataAccessResourceFailureCodes = value; } - } - - public string[] PermissionDeniedCodes - { - get { return permissionDeniedCodes; } - set { permissionDeniedCodes = value; } - } - - public string[] DataIntegrityViolationCodes - { - get { return dataIntegrityViolationCodes; } - set { dataIntegrityViolationCodes = value; } - } - - public string[] CannotAcquireLockCodes - { - get { return cannotAcquireLockCodes; } - set { cannotAcquireLockCodes = value; } - } - - public string[] TransientAccessResourceFailureCodes - { - get { return transientAccessResourceFailureCodes; } - set { transientAccessResourceFailureCodes = value; } - } - - public string[] DeadlockLoserCodes - { - get { return deadlockLoserCodes; } - set { deadlockLoserCodes = value; } - } - - public string[] CannotSerializeTransactionCodes - { - get { return cannotSerializeTransactionCodes; } - set { cannotSerializeTransactionCodes = value; } - } - - public string[] DuplicateKeyCodes - { - get { return duplicateKeyCodes; } - set { duplicateKeyCodes = value; } - } - - #endregion - } + + #endregion + + #region Properties + + public string DatabaseProductName + { + get + { + return (databaseProductNames != null && databaseProductNames.Length > 0 ? databaseProductNames[0] : null); + } + } + + public string[] DatabaseProductNames + { + get { return databaseProductNames; } + set { databaseProductNames = value; } + } + + public string[] BadSqlGrammarCodes + { + get { return badSqlGrammarCodes; } + set { badSqlGrammarCodes = value; } + } + + public string[] InvalidResultSetAccessCodes + { + get { return invalidResultSetAccessCodes; } + set { invalidResultSetAccessCodes = value; } + } + + public string[] DataAccessResourceFailureCodes + { + get { return dataAccessResourceFailureCodes; } + set { dataAccessResourceFailureCodes = value; } + } + + public string[] PermissionDeniedCodes + { + get { return permissionDeniedCodes; } + set { permissionDeniedCodes = value; } + } + + public string[] DataIntegrityViolationCodes + { + get { return dataIntegrityViolationCodes; } + set { dataIntegrityViolationCodes = value; } + } + + public string[] CannotAcquireLockCodes + { + get { return cannotAcquireLockCodes; } + set { cannotAcquireLockCodes = value; } + } + + public string[] TransientAccessResourceFailureCodes + { + get { return transientAccessResourceFailureCodes; } + set { transientAccessResourceFailureCodes = value; } + } + + public string[] DeadlockLoserCodes + { + get { return deadlockLoserCodes; } + set { deadlockLoserCodes = value; } + } + + public string[] CannotSerializeTransactionCodes + { + get { return cannotSerializeTransactionCodes; } + set { cannotSerializeTransactionCodes = value; } + } + + public string[] DuplicateKeyCodes + { + get { return duplicateKeyCodes; } + set { duplicateKeyCodes = value; } + } + + #endregion } diff --git a/src/Spring/Spring.Data/Data/Common/IDbMetadata.cs b/src/Spring/Spring.Data/Data/Common/IDbMetadata.cs index 9966799a..7254f338 100644 --- a/src/Spring/Spring.Data/Data/Common/IDbMetadata.cs +++ b/src/Spring/Spring.Data/Data/Common/IDbMetadata.cs @@ -20,148 +20,147 @@ using System.Reflection; -namespace Spring.Data.Common +namespace Spring.Data.Common; + +/// +/// Provides minimal database metadata information to support the +/// functionality in Spring.NET ADO.NET Framework. +/// +/// +/// Mark Pollack (.NET) +public interface IDbMetadata { /// - /// Provides minimal database metadata information to support the - /// functionality in Spring.NET ADO.NET Framework. + /// Gets a descriptive name of the product. /// - /// - /// Mark Pollack (.NET) - public interface IDbMetadata + /// Example: Microsoft SQL Server, provider V2.0.0.0 in framework .NET V2.0 + /// The name of the product. + string ProductName { get; } + + /// + /// Gets the type of the connection. The fully qualified type name is given since some providers, + /// notably for SqlServerCe, do not use the same namespace for all data access types. + /// + /// Example: System.Data.SqlClient.SqlCommand, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + /// The type of the connection. + Type ConnectionType { get; } + + /// + /// Gets the type of the command. + /// + /// Example: System.Data.SqlClient.SqlCommand, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + /// The type of the command. + Type CommandType { get; } + + /// + /// Gets the type of the parameter. + /// + /// Example: System.Data.SqlClient.SqlParameter, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + /// The type of the parameter. + Type ParameterType { get; } + + /// + /// Gets the type of the data adapter. + /// + /// Example: System.Data.SqlClient.SqlDataAdapter, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + /// The type of the data adapter. + Type DataAdapterType { get; } + + /// + /// Gets the type of the command builder. + /// + /// Example: System.Data.SqlClient.SqlCommandBuilder, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + /// The type of the command builder. + Type CommandBuilderType { get; } + + /// + /// Gets the type of the exception. + /// + /// Example: System.Data.SqlClient.SqlException, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + /// The type of the exception. + Type ExceptionType { get; } + + /// + /// Gets the error code exception expression. + /// + /// Example Errors[0].Number.ToString() for Sql Server + /// The error code exception expression. + string ErrorCodeExceptionExpression { get; } + + /// + /// Gets the command builder derive parameters method. + /// + /// If the value 'not supported' is specified then this method will throw an ArgumentException + /// Example: DeriveParameters + /// The command builder derive parameters method. + MethodInfo CommandBuilderDeriveParametersMethod { get; } + + /// + /// Provide the prefix used to indentify named parameters in SQL text. + /// + /// @ for Sql Server + string ParameterNamePrefix { get; } + + /// + /// Does the driver require the use of the parameter prefix when + /// specifying the name of the parameter in the Command's + /// Parameter collection. + /// + /// If true, then commamd.Parameters["@parameterName"] is + /// used, otherwise, command.Parameters["parameterName"]. + /// + bool UseParameterNamePrefixInParameterCollection { get; } + + /// + /// Gets a value indicating whether the Provider requires + /// the use of a named prefix in the SQL string. + /// + /// + /// The OLE DB/ODBC .NET Provider does not support named parameters for + /// passing parameters to an SQL Statement or a stored procedure called + /// by an IDbCommand when CommandType is set to Text. + /// + /// + /// true if use parameter prefix in SQL; otherwise, false. + /// + bool UseParameterPrefixInSql { get; } + + /// + /// For providers that allow you to choose between binding parameters + /// to a command by name (true) or by position (false). + /// + bool BindByName { - /// - /// Gets a descriptive name of the product. - /// - /// Example: Microsoft SQL Server, provider V2.0.0.0 in framework .NET V2.0 - /// The name of the product. - string ProductName { get; } - - /// - /// Gets the type of the connection. The fully qualified type name is given since some providers, - /// notably for SqlServerCe, do not use the same namespace for all data access types. - /// - /// Example: System.Data.SqlClient.SqlCommand, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - /// The type of the connection. - Type ConnectionType { get; } - - /// - /// Gets the type of the command. - /// - /// Example: System.Data.SqlClient.SqlCommand, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - /// The type of the command. - Type CommandType { get; } - - /// - /// Gets the type of the parameter. - /// - /// Example: System.Data.SqlClient.SqlParameter, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - /// The type of the parameter. - Type ParameterType { get; } - - /// - /// Gets the type of the data adapter. - /// - /// Example: System.Data.SqlClient.SqlDataAdapter, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - /// The type of the data adapter. - Type DataAdapterType { get; } - - /// - /// Gets the type of the command builder. - /// - /// Example: System.Data.SqlClient.SqlCommandBuilder, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - /// The type of the command builder. - Type CommandBuilderType { get; } - - /// - /// Gets the type of the exception. - /// - /// Example: System.Data.SqlClient.SqlException, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - /// The type of the exception. - Type ExceptionType { get; } - - /// - /// Gets the error code exception expression. - /// - /// Example Errors[0].Number.ToString() for Sql Server - /// The error code exception expression. - string ErrorCodeExceptionExpression { get; } - - /// - /// Gets the command builder derive parameters method. - /// - /// If the value 'not supported' is specified then this method will throw an ArgumentException - /// Example: DeriveParameters - /// The command builder derive parameters method. - MethodInfo CommandBuilderDeriveParametersMethod { get; } - - /// - /// Provide the prefix used to indentify named parameters in SQL text. - /// - /// @ for Sql Server - string ParameterNamePrefix { get; } - - /// - /// Does the driver require the use of the parameter prefix when - /// specifying the name of the parameter in the Command's - /// Parameter collection. - /// - /// If true, then commamd.Parameters["@parameterName"] is - /// used, otherwise, command.Parameters["parameterName"]. - /// - bool UseParameterNamePrefixInParameterCollection { get; } - - - /// - /// Gets a value indicating whether the Provider requires - /// the use of a named prefix in the SQL string. - /// - /// - /// The OLE DB/ODBC .NET Provider does not support named parameters for - /// passing parameters to an SQL Statement or a stored procedure called - /// by an IDbCommand when CommandType is set to Text. - /// - /// - /// true if use parameter prefix in SQL; otherwise, false. - /// - bool UseParameterPrefixInSql { get; } - - /// - /// For providers that allow you to choose between binding parameters - /// to a command by name (true) or by position (false). - /// - bool BindByName { - get; - //TODO will go away when make all of this fully configuration driven. - set; - } - - /// - /// Gets the type of the parameter db. - /// - /// Example: System.Data.SqlDbType, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - /// The type of the parameter db. - Type ParameterDbType { get; } - - /// - /// Gets the parameter db type property. - /// - /// Example: SqlDbType for SqlServer - /// The parameter db type property. - PropertyInfo ParameterDbTypeProperty { get; } - - /// - /// Gets the parameter is nullable property. - /// - /// Example: IsNullable for Sql Server - /// The parameter is nullable property. - PropertyInfo ParameterIsNullableProperty { get; } - - /// - /// Gets or sets the error codes. - /// - /// The collection of error codes to map error code integer values to Spring's DAO exception hierarchy - /// The error codes. - ErrorCodes ErrorCodes { get; } + get; + //TODO will go away when make all of this fully configuration driven. + set; } + + /// + /// Gets the type of the parameter db. + /// + /// Example: System.Data.SqlDbType, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + /// The type of the parameter db. + Type ParameterDbType { get; } + + /// + /// Gets the parameter db type property. + /// + /// Example: SqlDbType for SqlServer + /// The parameter db type property. + PropertyInfo ParameterDbTypeProperty { get; } + + /// + /// Gets the parameter is nullable property. + /// + /// Example: IsNullable for Sql Server + /// The parameter is nullable property. + PropertyInfo ParameterIsNullableProperty { get; } + + /// + /// Gets or sets the error codes. + /// + /// The collection of error codes to map error code integer values to Spring's DAO exception hierarchy + /// The error codes. + ErrorCodes ErrorCodes { get; } } diff --git a/src/Spring/Spring.Data/Data/Common/IDbParameter.cs b/src/Spring/Spring.Data/Data/Common/IDbParameter.cs index fe36b191..e30f9306 100644 --- a/src/Spring/Spring.Data/Data/Common/IDbParameter.cs +++ b/src/Spring/Spring.Data/Data/Common/IDbParameter.cs @@ -20,59 +20,53 @@ using System.Data; -namespace Spring.Data.Common +namespace Spring.Data.Common; + +/// +/// A parameter interface used by +/// +/// Mark Pollack (.NET) +public interface IDbParameter { - /// - /// A parameter interface used by - /// - /// Mark Pollack (.NET) - public interface IDbParameter - { + IDbParameter Type(Enum dbType); - IDbParameter Type(Enum dbType); + IDbParameter Type(Enum dbType, int size); - IDbParameter Type(Enum dbType, int size); + Enum GetDbType(); - Enum GetDbType(); + IDbParameter Direction(ParameterDirection direction); - IDbParameter Direction(ParameterDirection direction); + ParameterDirection GetDirection(); - ParameterDirection GetDirection(); + IDbParameter IsNullable(bool isNullable); - IDbParameter IsNullable(bool isNullable); + bool GetIsNullable(); - bool GetIsNullable(); + IDbParameter Name(string name); - IDbParameter Name(string name); + string GetName(); - string GetName(); + IDbParameter SourceColumn(string sourceColumn); - IDbParameter SourceColumn(string sourceColumn); + string GetSourceColumn(); - string GetSourceColumn(); + IDbParameter SourceVersion(DataRowVersion sourceVersion); - IDbParameter SourceVersion(DataRowVersion sourceVersion); + DataRowVersion GetSourceVersion(); - DataRowVersion GetSourceVersion(); + IDbParameter Value(object val); + object GetValue(); - IDbParameter Value(object val); + IDbParameter Precision(byte precision); - object GetValue(); + byte GetPrecision(); - IDbParameter Precision(byte precision); + IDbParameter Scale(byte scale); - byte GetPrecision(); + byte GetScale(); + IDbParameter Size(int size); - IDbParameter Scale(byte scale); - - byte GetScale(); - - - IDbParameter Size(int size); - - int GetSize(); - - } + int GetSize(); } diff --git a/src/Spring/Spring.Data/Data/Common/IDbParameters.cs b/src/Spring/Spring.Data/Data/Common/IDbParameters.cs index 52db4053..8a2ec14f 100644 --- a/src/Spring/Spring.Data/Data/Common/IDbParameters.cs +++ b/src/Spring/Spring.Data/Data/Common/IDbParameters.cs @@ -1,129 +1,126 @@ using System.Data; -namespace Spring.Data.Common +namespace Spring.Data.Common; + +public interface IDbParameters { - public interface IDbParameters + //TODO implement IDataParameterCollection....? + + //TODO should add methods return IDbDataParameter? + +#if !MONO // EE: mono/win32 doesn't accept comments on indexer?!? + /// + /// Gets the underlying standard ADO.NET for the specified parameter name. + /// +#endif + IDataParameter this[string parameterName] { get; set; } + +#if !MONO // EE: mono/win32 doesn't accept comments on indexer?!? + /// + /// Gets the underlying standard ADO.NET for the specified index. + /// +#endif + IDataParameter this[int index] { get; set; } + + int Count { - //TODO implement IDataParameterCollection....? - - //TODO should add methods return IDbDataParameter? - -#if !MONO // EE: mono/win32 doesn't accept comments on indexer?!? - /// - /// Gets the underlying standard ADO.NET for the specified parameter name. - /// -#endif - IDataParameter this[string parameterName] { get; set; } - -#if !MONO // EE: mono/win32 doesn't accept comments on indexer?!? - /// - /// Gets the underlying standard ADO.NET for the specified index. - /// -#endif - IDataParameter this[int index] { get; set; } - - int Count - { - get; - } - - /// - /// Determines whether this collection contains the specified parameter name. - /// - /// Name of the parameter. - /// - /// true if contains the specified parameter name; otherwise, false. - /// - bool Contains(string parameterName); - - /// - /// Returns the underlying standard ADO.NET parameters collection. - /// - IDataParameterCollection DataParameterCollection { get; } - - /// - /// Add an instance of . - /// - /// - void AddParameter(IDataParameter dbParameter); - - /// - /// Add a parameter specifying the all the individual properties of a - /// IDbDataParameter. - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// The newly created parameter - IDbDataParameter AddParameter(string name, Enum parameterType, int size, ParameterDirection direction, bool isNullable, - byte precision, byte scale, string sourceColumn, DataRowVersion sourceVersion, object parameterValue); - - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// The newly created parameter - IDbDataParameter AddParameter(string name, Enum parameterType, ParameterDirection direction, bool isNullable, byte precision, - byte scale, string sourceColumn, DataRowVersion sourceVersion, object parameterValue); - - - /// - /// Adds a value to the parameter collection - /// - /// This method can not be used with stored procedures for - /// providers that require named parameters. However, it is of - /// great convenience for other cases. - /// The value of the parameter. - /// Index of added parameter. - int Add(object parameterValue); - - /// - /// Adds a range of vlaues to the parameter collection. - /// - /// This method can not be used with stored procedures for - /// providers that require named parameters. However, it is of - /// great convenience for other cases. - /// - void AddRange(Array values); - - IDbDataParameter AddWithValue(string name, object parameterValue); - - IDbDataParameter Add(string name, Enum parameterType); - - IDbDataParameter Add(string name, Enum parameterType, int size); - - IDbDataParameter Add(string name, Enum parameterType, int size, string sourceColumn); - - IDbDataParameter AddOut(string name, Enum parameterType); - - IDbDataParameter AddOut(string name, Enum parameterType, int size); - - IDbDataParameter AddInOut(string name, Enum parameterType); - - IDbDataParameter AddInOut(string name, Enum parameterType, int size); - - IDbDataParameter AddReturn(string name, Enum parameterType); - - IDbDataParameter AddReturn(string name, Enum parameterType, int size); - - object GetValue(string name); - - void SetValue(string name, object parameterValue); - + get; } + + /// + /// Determines whether this collection contains the specified parameter name. + /// + /// Name of the parameter. + /// + /// true if contains the specified parameter name; otherwise, false. + /// + bool Contains(string parameterName); + + /// + /// Returns the underlying standard ADO.NET parameters collection. + /// + IDataParameterCollection DataParameterCollection { get; } + + /// + /// Add an instance of . + /// + /// + void AddParameter(IDataParameter dbParameter); + + /// + /// Add a parameter specifying the all the individual properties of a + /// IDbDataParameter. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// The newly created parameter + IDbDataParameter AddParameter(string name, Enum parameterType, int size, ParameterDirection direction, bool isNullable, + byte precision, byte scale, string sourceColumn, DataRowVersion sourceVersion, object parameterValue); + + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// The newly created parameter + IDbDataParameter AddParameter(string name, Enum parameterType, ParameterDirection direction, bool isNullable, byte precision, + byte scale, string sourceColumn, DataRowVersion sourceVersion, object parameterValue); + + /// + /// Adds a value to the parameter collection + /// + /// This method can not be used with stored procedures for + /// providers that require named parameters. However, it is of + /// great convenience for other cases. + /// The value of the parameter. + /// Index of added parameter. + int Add(object parameterValue); + + /// + /// Adds a range of vlaues to the parameter collection. + /// + /// This method can not be used with stored procedures for + /// providers that require named parameters. However, it is of + /// great convenience for other cases. + /// + void AddRange(Array values); + + IDbDataParameter AddWithValue(string name, object parameterValue); + + IDbDataParameter Add(string name, Enum parameterType); + + IDbDataParameter Add(string name, Enum parameterType, int size); + + IDbDataParameter Add(string name, Enum parameterType, int size, string sourceColumn); + + IDbDataParameter AddOut(string name, Enum parameterType); + + IDbDataParameter AddOut(string name, Enum parameterType, int size); + + IDbDataParameter AddInOut(string name, Enum parameterType); + + IDbDataParameter AddInOut(string name, Enum parameterType, int size); + + IDbDataParameter AddReturn(string name, Enum parameterType); + + IDbDataParameter AddReturn(string name, Enum parameterType, int size); + + object GetValue(string name); + + void SetValue(string name, object parameterValue); } diff --git a/src/Spring/Spring.Data/Data/Common/IDbParametersBuilder.cs b/src/Spring/Spring.Data/Data/Common/IDbParametersBuilder.cs index 5f8fcfc2..50b0d0ab 100644 --- a/src/Spring/Spring.Data/Data/Common/IDbParametersBuilder.cs +++ b/src/Spring/Spring.Data/Data/Common/IDbParametersBuilder.cs @@ -1,26 +1,25 @@ -namespace Spring.Data.Common -{ - /// - /// A builder to create a collection of ADO.NET parameters. - /// - /// The chaining of IDbParameter methods does the - /// building of the parameter details while the builder class - /// itself keeps track of the collection. - /// - /// Mark Pollack (.NET) - public interface IDbParametersBuilder - { - /// - /// Creates a IDbParameter object and adds it to an internal collection for - /// later retrieval via the GetParameters method. - /// - /// - IDbParameter Create(); +namespace Spring.Data.Common; - /// - /// Gets all the parameters created and configured via the Create method. - /// - /// An instance of IDbParameters - IDbParameters GetParameters(); - } +/// +/// A builder to create a collection of ADO.NET parameters. +/// +/// The chaining of IDbParameter methods does the +/// building of the parameter details while the builder class +/// itself keeps track of the collection. +/// +/// Mark Pollack (.NET) +public interface IDbParametersBuilder +{ + /// + /// Creates a IDbParameter object and adds it to an internal collection for + /// later retrieval via the GetParameters method. + /// + /// + IDbParameter Create(); + + /// + /// Gets all the parameters created and configured via the Create method. + /// + /// An instance of IDbParameters + IDbParameters GetParameters(); } diff --git a/src/Spring/Spring.Data/Data/Common/IDbProvider.cs b/src/Spring/Spring.Data/Data/Common/IDbProvider.cs index fb5b537e..bcdef397 100644 --- a/src/Spring/Spring.Data/Data/Common/IDbProvider.cs +++ b/src/Spring/Spring.Data/Data/Common/IDbProvider.cs @@ -20,106 +20,98 @@ using System.Data; -namespace Spring.Data.Common +namespace Spring.Data.Common; + +/// +/// Factory interface to create provider specific ADO.NET objects. +/// +public interface IDbProvider { /// - /// Factory interface to create provider specific ADO.NET objects. + /// Returns a new command object for executing SQL statments/Stored Procedures + /// against the database. /// - public interface IDbProvider + /// An new + IDbCommand CreateCommand(); + + /// + /// Returns a new instance of the providers CommandBuilder class. + /// + /// In .NET 1.1 there was no common base class or interface + /// for command builders, hence the return signature is object to + /// be portable (but more loosely typed) across .NET 1.1/2.0 + /// A new Command Builder + object CreateCommandBuilder(); + + /// + /// Returns a new connection object to communicate with the database. + /// + /// A new + IDbConnection CreateConnection(); + + /// + /// Returns a new adapter objects for use with offline DataSets. + /// + /// A new + IDbDataAdapter CreateDataAdapter(); + + /// + /// Returns a new parameter object for binding values to parameter + /// placeholders in SQL statements or Stored Procedure variables. + /// + /// A new + IDbDataParameter CreateParameter(); + + /// + /// Creates the name of the parameter in the format appropriate to use inside IDbCommand.CommandText. + /// + /// In most cases this adds the parameter prefix to the name passed into this method. + /// The unformatted name of the parameter. + /// The parameter name formatted foran IDbCommand.CommandText. + string CreateParameterName(string name); + + /// + /// Creates the name ofthe parameter in the format appropriate for an IDataParameter, i.e. to be + /// part of a IDataParameterCollection. + /// + /// The unformatted name of the parameter. + /// The parameter name formatted for an IDataParameter + string CreateParameterNameForCollection(string name); + + /// + /// Return metadata information about the database provider + /// + IDbMetadata DbMetadata { - - /// - /// Returns a new command object for executing SQL statments/Stored Procedures - /// against the database. - /// - /// An new - IDbCommand CreateCommand(); - - /// - /// Returns a new instance of the providers CommandBuilder class. - /// - /// In .NET 1.1 there was no common base class or interface - /// for command builders, hence the return signature is object to - /// be portable (but more loosely typed) across .NET 1.1/2.0 - /// A new Command Builder - object CreateCommandBuilder(); - - /// - /// Returns a new connection object to communicate with the database. - /// - /// A new - IDbConnection CreateConnection(); - - - /// - /// Returns a new adapter objects for use with offline DataSets. - /// - /// A new - IDbDataAdapter CreateDataAdapter(); - - /// - /// Returns a new parameter object for binding values to parameter - /// placeholders in SQL statements or Stored Procedure variables. - /// - /// A new - IDbDataParameter CreateParameter(); - - - /// - /// Creates the name of the parameter in the format appropriate to use inside IDbCommand.CommandText. - /// - /// In most cases this adds the parameter prefix to the name passed into this method. - /// The unformatted name of the parameter. - /// The parameter name formatted foran IDbCommand.CommandText. - string CreateParameterName(string name); - - /// - /// Creates the name ofthe parameter in the format appropriate for an IDataParameter, i.e. to be - /// part of a IDataParameterCollection. - /// - /// The unformatted name of the parameter. - /// The parameter name formatted for an IDataParameter - string CreateParameterNameForCollection(string name); - - /// - /// Return metadata information about the database provider - /// - IDbMetadata DbMetadata - { - get; - } - - - - /// - /// Connection string used to create connections. - /// - string ConnectionString - { - set; - get; - } - - - /// - /// Extracts the provider specific error code as a string. - /// - /// The data access exception. - /// The provider specific error code - string ExtractError(Exception e); - - /// - /// Determines whether the provided exception is in fact related - /// to database access. This can be provider dependent in .NET 1.1 since - /// there isn't a common base class for ADO.NET exceptions. - /// - /// The exception thrown when performing data access - /// operations. - /// - /// true if is a valid data access exception for the specified - /// exception; otherwise, false. - /// - bool IsDataAccessException(Exception e); - + get; } + + /// + /// Connection string used to create connections. + /// + string ConnectionString + { + set; + get; + } + + /// + /// Extracts the provider specific error code as a string. + /// + /// The data access exception. + /// The provider specific error code + string ExtractError(Exception e); + + /// + /// Determines whether the provided exception is in fact related + /// to database access. This can be provider dependent in .NET 1.1 since + /// there isn't a common base class for ADO.NET exceptions. + /// + /// The exception thrown when performing data access + /// operations. + /// + /// true if is a valid data access exception for the specified + /// exception; otherwise, false. + /// + bool IsDataAccessException(Exception e); } diff --git a/src/Spring/Spring.Data/Data/Common/MultiDelegatingDbProvider.cs b/src/Spring/Spring.Data/Data/Common/MultiDelegatingDbProvider.cs index 50c8daae..04adf140 100644 --- a/src/Spring/Spring.Data/Data/Common/MultiDelegatingDbProvider.cs +++ b/src/Spring/Spring.Data/Data/Common/MultiDelegatingDbProvider.cs @@ -26,282 +26,285 @@ using Spring.Dao; using Spring.Objects.Factory; using Spring.Threading; +namespace Spring.Data.Common; -namespace Spring.Data.Common +/// +/// A wrapper implementation for IDbProvider such that multiple DbProvider instances can be +/// selected at runtime, say based on web request criteria. +/// +/// +/// The name of which DbProvider to use, as provided to the IDictionary property TargetDbProviders +/// is "dbProviderName". Once the target dbprovider name is known, set the name via a call to +/// LogicalThreadContext.SetData(MultiDelegatingDbProvider.CURRENT_DBPROVIDER_SLOTNAME, "database1ProviderName"). The value +/// "database1ProviderName" must match a key in the provided TargetDbProviders dictionary. +/// +/// Mark Pollack +public class MultiDelegatingDbProvider : IDbProvider, IInitializingObject { + public static readonly string CURRENT_DBPROVIDER_SLOTNAME = Spring.Util.UniqueKey.GetTypeScopedString(typeof(MultiDelegatingDbProvider), "Current"); + + private IDbProvider defaultDbProvider; + + private IDictionary targetDbProviders = new SynchronizedHashtable(); + + #region Logging Definition + + private static readonly ILogger LOG = LogManager.GetLogger(); + + #endregion + + #region Constructors + /// - /// A wrapper implementation for IDbProvider such that multiple DbProvider instances can be - /// selected at runtime, say based on web request criteria. + /// Initializes a new instance of the class. /// - /// - /// The name of which DbProvider to use, as provided to the IDictionary property TargetDbProviders - /// is "dbProviderName". Once the target dbprovider name is known, set the name via a call to - /// LogicalThreadContext.SetData(MultiDelegatingDbProvider.CURRENT_DBPROVIDER_SLOTNAME, "database1ProviderName"). The value - /// "database1ProviderName" must match a key in the provided TargetDbProviders dictionary. - /// - /// Mark Pollack - public class MultiDelegatingDbProvider : IDbProvider, IInitializingObject + public MultiDelegatingDbProvider() { - public static readonly string CURRENT_DBPROVIDER_SLOTNAME = Spring.Util.UniqueKey.GetTypeScopedString(typeof(MultiDelegatingDbProvider), "Current"); + } - private IDbProvider defaultDbProvider; + /// + /// Initializes a new instance of the class. + /// + /// The target db providers. + public MultiDelegatingDbProvider(IDictionary targetDbProviders) + { + this.targetDbProviders = targetDbProviders; + } - private IDictionary targetDbProviders = new SynchronizedHashtable(); + #endregion - #region Logging Definition + /// + /// Sets the default IDbProvider. This will be returned if no DbProvider is found in thread local storage. + /// + /// The default db provider. + public IDbProvider DefaultDbProvider + { + set { defaultDbProvider = value; } + } - private static readonly ILogger LOG = LogManager.GetLogger(); + /// + /// Sets the target db providers. + /// + /// The target db providers. + public IDictionary TargetDbProviders + { + set { targetDbProviders = value; } + } - #endregion - - #region Constructors - /// - /// Initializes a new instance of the class. - /// - public MultiDelegatingDbProvider() + /// + /// Ensures that the there are values in the TargetDbProviders dictionary and that the + /// key is of the type string and value is of the type IDbProvider. + /// + /// If the above conditions are not met. + public void AfterPropertiesSet() + { + if (targetDbProviders.Count == 0) { - + throw new ArgumentException("Target DbProvider collection required."); } - /// - /// Initializes a new instance of the class. - /// - /// The target db providers. - public MultiDelegatingDbProvider(IDictionary targetDbProviders) + foreach (DictionaryEntry entry in targetDbProviders) { - this.targetDbProviders = targetDbProviders; - } - - #endregion - - /// - /// Sets the default IDbProvider. This will be returned if no DbProvider is found in thread local storage. - /// - /// The default db provider. - public IDbProvider DefaultDbProvider - { - set { defaultDbProvider = value; } - } - - /// - /// Sets the target db providers. - /// - /// The target db providers. - public IDictionary TargetDbProviders - { - set { targetDbProviders = value; } - } - - /// - /// Ensures that the there are values in the TargetDbProviders dictionary and that the - /// key is of the type string and value is of the type IDbProvider. - /// - /// If the above conditions are not met. - public void AfterPropertiesSet() - { - if (targetDbProviders.Count == 0) + if (!entry.Key.GetType().Equals(typeof(string))) { - throw new ArgumentException("Target DbProvider collection required."); + throw new ArgumentException("Key identifying target IDbProvider in TargetDbProviders dictionary property is required to be of type string. Key = [" + entry.Key + "], type = [" + entry.Key.GetType() + "]"); } - foreach (DictionaryEntry entry in targetDbProviders) + + IDbProvider targetProvider = entry.Value as IDbProvider; + if (targetProvider == null) { - if (! entry.Key.GetType().Equals(typeof(string))) - { - throw new ArgumentException("Key identifying target IDbProvider in TargetDbProviders dictionary property is required to be of type string. Key = [" + entry.Key + "], type = [" + entry.Key.GetType() + "]"); - } - IDbProvider targetProvider = entry.Value as IDbProvider; - if (targetProvider == null) - { - throw new ArgumentException("Value in TargetDbProviders dictionary is not of type IDbProvider. Type = [" + entry.Value.GetType() + "]"); - } - } - } - - #region IDbProvider methods - - - /// - /// Returns a new command object for executing SQL statments/Stored Procedures - /// against the database. - /// - /// An new - public IDbCommand CreateCommand() - { - return GetTargetProvider().CreateCommand(); - } - - /// - /// Returns a new connection object to communicate with the database. - /// - /// A new - public IDbConnection CreateConnection() - { - return GetTargetProvider().CreateConnection(); - } - - /// - /// Returns a new parameter object for binding values to parameter - /// placeholders in SQL statements or Stored Procedure variables. - /// - /// A new - public IDbDataParameter CreateParameter() - { - return GetTargetProvider().CreateParameter(); - } - - /// - /// Returns a new adapter objects for use with offline DataSets. - /// - /// A new - public IDbDataAdapter CreateDataAdapter() - { - return GetTargetProvider().CreateDataAdapter(); - } - - /// - /// Returns a new instance of the providers CommandBuilder class. - /// - /// A new Command Builder - /// In .NET 1.1 there was no common base class or interface - /// for command builders, hence the return signature is object to - /// be portable (but more loosely typed) across .NET 1.1/2.0 - public object CreateCommandBuilder() - { - return GetTargetProvider().CreateCommandBuilder(); - } - - /// - /// Creates the name of the parameter in the format appropriate to use inside IDbCommand.CommandText. - /// - /// The unformatted name of the parameter. - /// - /// The parameter name formatted foran IDbCommand.CommandText. - /// - /// In most cases this adds the parameter prefix to the name passed into this method. - public string CreateParameterName(string name) - { - return GetTargetProvider().CreateParameterName(name); - } - - - /// - /// Creates the name ofthe parameter in the format appropriate for an IDataParameter, i.e. to be - /// part of a IDataParameterCollection. - /// - /// The unformatted name of the parameter. - /// - /// The parameter name formatted for an IDataParameter - /// - public string CreateParameterNameForCollection(string name) - { - return GetTargetProvider().CreateParameterNameForCollection(name); - } - - /// - /// Return metadata information about the database provider - /// - /// - public IDbMetadata DbMetadata - { - get { return GetTargetProvider().DbMetadata; } - } - - /// - /// Connection string used to create connections. - /// - /// - public string ConnectionString - { - get { return GetTargetProvider().ConnectionString; } - set { GetTargetProvider().ConnectionString = value; } - } - - /// - /// Extracts the provider specific error code as a string. - /// - /// The data access exception. - /// The provider specific error code - public string ExtractError(Exception e) - { - return GetTargetProvider().ExtractError(e); - } - - /// - /// Determines whether the provided exception is in fact related - /// to database access. This can be provider dependent in .NET 1.1 since - /// there isn't a common base class for ADO.NET exceptions. - /// - /// The exception thrown when performing data access - /// operations. - /// - /// true if is a valid data access exception for the specified - /// exception; otherwise, false. - /// - public bool IsDataAccessException(Exception e) - { - if (e is System.Data.Common.DbException) - { - return true; - } - else - { - return false; - } - } - - /// - /// Determines whether is data access exception in .NET 1.1 for the specified exception. - /// - /// The candidate exception. - /// - /// true if is data access exception in .NET 1.1 for the specified exception; otherwise, false. - /// - public bool IsDataAccessExceptionBCL11(Exception e) - { - return false; - } - #endregion - - /// - /// Gets the target provider based on the thread local name "dbProviderName" - /// - /// The corresonding IDbProvider. - protected virtual IDbProvider GetTargetProvider() - { - string dbProviderName = (string)LogicalThreadContext.GetData(CURRENT_DBPROVIDER_SLOTNAME); - if (dbProviderName != null && targetDbProviders.Contains(dbProviderName)) - { - return (IDbProvider)targetDbProviders[dbProviderName]; - } - //Fall back to default if available - if (defaultDbProvider != null) - { - if (LOG.IsEnabled(LogLevel.Debug)) - { - LOG.LogDebug("No DbProvider defined in thread local storage, falling back to use DefaultDbProvider."); - } - return defaultDbProvider; - } - if (dbProviderName == null) - { - throw new InvalidDataAccessApiUsageException( - "No provider name found in thread local storage. Consider setting the property DefaultDbProvider to fallback to a default value."); - } - throw new InvalidDataAccessApiUsageException("'" + dbProviderName + "'" - + " was not under the thread local key 'dbProviderName' and no default IDbProvider was set."); - } - - /// - /// Convenience method to sets the name of the DbProvider that will be used for the - /// the current thread's procesing. - /// - /// The name of the DbProvider to use for the current threads processing. - public static string CurrentDbProviderName - { - set - { - LogicalThreadContext.SetData(CURRENT_DBPROVIDER_SLOTNAME, value); + throw new ArgumentException("Value in TargetDbProviders dictionary is not of type IDbProvider. Type = [" + entry.Value.GetType() + "]"); } } } + + #region IDbProvider methods + + /// + /// Returns a new command object for executing SQL statments/Stored Procedures + /// against the database. + /// + /// An new + public IDbCommand CreateCommand() + { + return GetTargetProvider().CreateCommand(); + } + + /// + /// Returns a new connection object to communicate with the database. + /// + /// A new + public IDbConnection CreateConnection() + { + return GetTargetProvider().CreateConnection(); + } + + /// + /// Returns a new parameter object for binding values to parameter + /// placeholders in SQL statements or Stored Procedure variables. + /// + /// A new + public IDbDataParameter CreateParameter() + { + return GetTargetProvider().CreateParameter(); + } + + /// + /// Returns a new adapter objects for use with offline DataSets. + /// + /// A new + public IDbDataAdapter CreateDataAdapter() + { + return GetTargetProvider().CreateDataAdapter(); + } + + /// + /// Returns a new instance of the providers CommandBuilder class. + /// + /// A new Command Builder + /// In .NET 1.1 there was no common base class or interface + /// for command builders, hence the return signature is object to + /// be portable (but more loosely typed) across .NET 1.1/2.0 + public object CreateCommandBuilder() + { + return GetTargetProvider().CreateCommandBuilder(); + } + + /// + /// Creates the name of the parameter in the format appropriate to use inside IDbCommand.CommandText. + /// + /// The unformatted name of the parameter. + /// + /// The parameter name formatted foran IDbCommand.CommandText. + /// + /// In most cases this adds the parameter prefix to the name passed into this method. + public string CreateParameterName(string name) + { + return GetTargetProvider().CreateParameterName(name); + } + + /// + /// Creates the name ofthe parameter in the format appropriate for an IDataParameter, i.e. to be + /// part of a IDataParameterCollection. + /// + /// The unformatted name of the parameter. + /// + /// The parameter name formatted for an IDataParameter + /// + public string CreateParameterNameForCollection(string name) + { + return GetTargetProvider().CreateParameterNameForCollection(name); + } + + /// + /// Return metadata information about the database provider + /// + /// + public IDbMetadata DbMetadata + { + get { return GetTargetProvider().DbMetadata; } + } + + /// + /// Connection string used to create connections. + /// + /// + public string ConnectionString + { + get { return GetTargetProvider().ConnectionString; } + set { GetTargetProvider().ConnectionString = value; } + } + + /// + /// Extracts the provider specific error code as a string. + /// + /// The data access exception. + /// The provider specific error code + public string ExtractError(Exception e) + { + return GetTargetProvider().ExtractError(e); + } + + /// + /// Determines whether the provided exception is in fact related + /// to database access. This can be provider dependent in .NET 1.1 since + /// there isn't a common base class for ADO.NET exceptions. + /// + /// The exception thrown when performing data access + /// operations. + /// + /// true if is a valid data access exception for the specified + /// exception; otherwise, false. + /// + public bool IsDataAccessException(Exception e) + { + if (e is System.Data.Common.DbException) + { + return true; + } + else + { + return false; + } + } + + /// + /// Determines whether is data access exception in .NET 1.1 for the specified exception. + /// + /// The candidate exception. + /// + /// true if is data access exception in .NET 1.1 for the specified exception; otherwise, false. + /// + public bool IsDataAccessExceptionBCL11(Exception e) + { + return false; + } + + #endregion + + /// + /// Gets the target provider based on the thread local name "dbProviderName" + /// + /// The corresonding IDbProvider. + protected virtual IDbProvider GetTargetProvider() + { + string dbProviderName = (string) LogicalThreadContext.GetData(CURRENT_DBPROVIDER_SLOTNAME); + if (dbProviderName != null && targetDbProviders.Contains(dbProviderName)) + { + return (IDbProvider) targetDbProviders[dbProviderName]; + } + + //Fall back to default if available + if (defaultDbProvider != null) + { + if (LOG.IsEnabled(LogLevel.Debug)) + { + LOG.LogDebug("No DbProvider defined in thread local storage, falling back to use DefaultDbProvider."); + } + + return defaultDbProvider; + } + + if (dbProviderName == null) + { + throw new InvalidDataAccessApiUsageException( + "No provider name found in thread local storage. Consider setting the property DefaultDbProvider to fallback to a default value."); + } + + throw new InvalidDataAccessApiUsageException("'" + dbProviderName + "'" + + " was not under the thread local key 'dbProviderName' and no default IDbProvider was set."); + } + + /// + /// Convenience method to sets the name of the DbProvider that will be used for the + /// the current thread's procesing. + /// + /// The name of the DbProvider to use for the current threads processing. + public static string CurrentDbProviderName + { + set + { + LogicalThreadContext.SetData(CURRENT_DBPROVIDER_SLOTNAME, value); + } + } } diff --git a/src/Spring/Spring.Data/Data/Common/UserCredentialsDbProvider.cs b/src/Spring/Spring.Data/Data/Common/UserCredentialsDbProvider.cs index 424197b8..8487658b 100644 --- a/src/Spring/Spring.Data/Data/Common/UserCredentialsDbProvider.cs +++ b/src/Spring/Spring.Data/Data/Common/UserCredentialsDbProvider.cs @@ -1,14 +1,14 @@ #region Licence /* - * Copyright © 2002-2011 the original author or authors. - * + * Copyright � 2002-2011 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. @@ -22,116 +22,112 @@ using System.Data; using Spring.Threading; using Spring.Util; -namespace Spring.Data.Common +namespace Spring.Data.Common; + +/// +/// An adapter for a target IDbProvider, applying the specified user credentials +/// to the connection string for every GetConnection call. +/// +public class UserCredentialsDbProvider : DelegatingDbProvider { + private string username; + + private string password; + + private string separator = ";"; + + private const string USERNAME = "UserCredentialsDbProvider.UserName"; + + private const string PASSWORD = "UserCredentialsDbProvider.Password"; + /// - /// An adapter for a target IDbProvider, applying the specified user credentials - /// to the connection string for every GetConnection call. + /// Sets the username string that will be appended to the connection string. /// - public class UserCredentialsDbProvider : DelegatingDbProvider + /// The username. + public string Username { - private string username; + set { username = value; } + } - private string password; + /// + /// Sets the password string that will be appended to the connection string. + /// + /// The password. + public string Password + { + set { password = value; } + } - private string separator = ";"; + /// + /// Sets the separator used to separate elements of the connection string. Default is ';'. + /// + /// + /// The separator used to separate elements in the connection string. + public string Separator + { + set { separator = value; } + } - private const string USERNAME = "UserCredentialsDbProvider.UserName"; + /// + /// Sets the user credentials for current thread. The given username and password + /// strings will be added to the connection string for all subsequent GetConnection + /// requests. This will override any statically specified user credentials, that is, + /// set by the properties Username nad Password. + /// + /// The username part of the connection string. + /// The password part of the connection string. + public void SetCredentialsForCurrentThread(string user, string pass) + { + LogicalThreadContext.SetData(USERNAME, user); + LogicalThreadContext.SetData(PASSWORD, pass); + } - private const string PASSWORD = "UserCredentialsDbProvider.Password"; + /// + /// Removes the user credentials from current thread. Use statically specified + /// credentials afterwards. + /// + public void RemoveCredentialsFromCurrentThread() + { + LogicalThreadContext.FreeNamedDataSlot(USERNAME); + LogicalThreadContext.FreeNamedDataSlot(PASSWORD); + } - /// - /// Sets the username string that will be appended to the connection string. - /// - /// The username. - public string Username + /// + /// Returns a new connection object to communicate with the database. + /// Determine if there are currently thread-bound credentials, using them if + /// available, falling back to the statically specified username and password + /// (i.e. values of the properties 'Username' and 'Password') otherwise. + /// The username and password will be concatenated on the connection string + /// using string in the Separator property + /// + /// A new + public override IDbConnection CreateConnection() + { + string user = LogicalThreadContext.GetData(USERNAME) as string; + string pass = LogicalThreadContext.GetData(PASSWORD) as string; + if (user != null && pass != null) { - set { username = value; } + return DoCreateConnection(user, pass); } - - /// - /// Sets the password string that will be appended to the connection string. - /// - /// The password. - public string Password + else { - set { password = value; } - } - - - /// - /// Sets the separator used to separate elements of the connection string. Default is ';'. - /// - /// - /// The separator used to separate elements in the connection string. - public string Separator - { - set { separator = value; } - } - - /// - /// Sets the user credentials for current thread. The given username and password - /// strings will be added to the connection string for all subsequent GetConnection - /// requests. This will override any statically specified user credentials, that is, - /// set by the properties Username nad Password. - /// - /// The username part of the connection string. - /// The password part of the connection string. - public void SetCredentialsForCurrentThread(string user, string pass) - { - LogicalThreadContext.SetData(USERNAME, user); - LogicalThreadContext.SetData(PASSWORD, pass); - } - - /// - /// Removes the user credentials from current thread. Use statically specified - /// credentials afterwards. - /// - public void RemoveCredentialsFromCurrentThread() - { - LogicalThreadContext.FreeNamedDataSlot(USERNAME); - LogicalThreadContext.FreeNamedDataSlot(PASSWORD); - } - - - /// - /// Returns a new connection object to communicate with the database. - /// Determine if there are currently thread-bound credentials, using them if - /// available, falling back to the statically specified username and password - /// (i.e. values of the properties 'Username' and 'Password') otherwise. - /// The username and password will be concatenated on the connection string - /// using string in the Separator property - /// - /// A new - public override IDbConnection CreateConnection() - { - string user = LogicalThreadContext.GetData(USERNAME) as string; - string pass = LogicalThreadContext.GetData(PASSWORD) as string; - if (user != null && pass != null) - { - return DoCreateConnection(user, pass); - } - else - { - return DoCreateConnection(username, password); - } - } - - protected virtual IDbConnection DoCreateConnection(string user, string pass) - { - AssertUtils.ArgumentNotNull(TargetDbProvider,"TargetDbProvider"); - if (StringUtils.HasLength(user)) - { - IDbConnection conn = TargetDbProvider.CreateConnection(); - string s= ConnectionString + separator + user + separator + pass; - conn.ConnectionString = s; - return conn; - } - else - { - return TargetDbProvider.CreateConnection(); - } + return DoCreateConnection(username, password); } } -} \ No newline at end of file + protected virtual IDbConnection DoCreateConnection(string user, string pass) + { + AssertUtils.ArgumentNotNull(TargetDbProvider, "TargetDbProvider"); + if (StringUtils.HasLength(user)) + { + IDbConnection conn = TargetDbProvider.CreateConnection(); + string s = ConnectionString + separator + user + separator + pass; + conn.ConnectionString = s; + return conn; + } + else + { + return TargetDbProvider.CreateConnection(); + } + } +} diff --git a/src/Spring/Spring.Data/Data/Common/dbproviders.xml b/src/Spring/Spring.Data/Data/Common/dbproviders.xml index b274d853..c8c28c61 100644 --- a/src/Spring/Spring.Data/Data/Common/dbproviders.xml +++ b/src/Spring/Spring.Data/Data/Common/dbproviders.xml @@ -4,2306 +4,2733 @@ - Database Provider definitions. --> + xmlns="http://www.springframework.net" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.springframework.net http://www.springframework.net/xsd/spring-objects.xsd"> - - - - - - - - - - - - - - - - - - - - - - + - - - 102,156,170,207,208 - - - 229 - - - 544,2627,8114,8115 - - - 1205 - - - + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - + + 102,156,170,207,208 + + + 229 + + + 544,2627,8114,8115 + + + 1205 + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - 102,156,170,207,208 - - - 229 - - - 544,2627,8114,8115 - - - 1205 - - - + - + + + 102,156,170,207,208 + + + 229 + + + 544,2627,8114,8115 + + + 1205 + + + - - - - - - - - - - - - - - - - - - - - - + - - - 102,156,170,207,208 - - - 229 - - - 544,2627,8114,8115 - - - 1205 - - - + + + 102,156,170,207,208 + + + 229 + + + 544,2627,8114,8115 + + + 1205 + + + - +
- + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + - - 156,170,207,208 - - - 229 - - - 2627,8114,8115 - - - 1205 - - - - - - - - - - - - - - - - - - - - - - - - - - + + 156,170,207,208 + + + 229 + + + 2627,8114,8115 + + + 1205 + + + + - + + + - - 156,170,207,208 - - - 229 - - - 2627,8114,8115 - - - 1205 - - - + + 156,170,207,208 + + + 229 + + + 2627,8114,8115 + + + 1205 + + + -
+
- - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - 156,170,207,208 - - - 229 - - - 2627,8114,8115 - - - 1205 - - - + + 156,170,207,208 + + + 229 + + + 2627,8114,8115 + + + 1205 + + + - + - + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - + - - 900,903,904,917,936,942,17006 - - - 17003 - - - 17002,17447 - - - 1,1400,1722,2291,2292 - - - 54 - - - 8177 - - - 60 - - - - + + 900,903,904,917,936,942,17006 + + + 17003 + + + 17002,17447 + + + 1,1400,1722,2291,2292 + + + 54 + + + 8177 + + + 60 + + + + - + - - - - - - - - - - - - - - - - - - - - - + - - 900,903,904,917,936,942,17006 - - - 17003 - - - 1 - - - 17002,17447 - - - 1,1400,1722,2291,2292 - - - 54 - - - 8177 - - - 60 - - - - + + 900,903,904,917,936,942,17006 + + + 17003 + + + 1 + + + 17002,17447 + + + 1,1400,1722,2291,2292 + + + 54 + + + 8177 + + + 60 + +
+ +
- + - + - - - - - - - - - - - - - - - - - - - - - + - - 900,903,904,917,936,942,17006 - - - 17003 - - - 1 - - - 17002,17447 - - - 1,1400,1722,2291,2292 - - - 54 - - - 8177 - - - 60 - - - - + + 900,903,904,917,936,942,17006 + + + 17003 + + + 1 + + + 17002,17447 + + + 1,1400,1722,2291,2292 + + + 54 + + + 8177 + + + 60 + +
+ +
- - - - - - - - - - - - - - - - - - - - - + - - 900,903,904,917,936,942,17006 - - - 17003 - - - 1 - - - 17002,17447 - - - 1,1400,1722,2291,2292 - - - 54 - - - 8177 - - - 60 - - - - + + 900,903,904,917,936,942,17006 + + + 17003 + + + 1 + + + 17002,17447 + + + 1,1400,1722,2291,2292 + + + 54 + + + 8177 + + + 60 + +
+ +
- - - - - - - - - - - - - - - - - - - - - + - - 900,903,904,917,936,942,17006 - - - 17003 - - - 1 - - - 17002,17447 - - - 1,1400,1722,2291,2292 - - - 54 - - - 8177 - - - 60 - - - - + + 900,903,904,917,936,942,17006 + + + 17003 + + + 1 + + + 17002,17447 + + + 1,1400,1722,2291,2292 + + + 54 + + + 8177 + + + 60 + +
+ +
- - - - - - - - - - - - - - - - - - - - - + - - 900,903,904,917,936,942,17006 - - - 17003 - - - 1 - - - 17002,17447 - - - 1,1400,1722,2291,2292 - - - 54 - - - 8177 - - - 60 - - - - + + 900,903,904,917,936,942,17006 + + + 17003 + + + 1 + + + 17002,17447 + + + 1,1400,1722,2291,2292 + + + 54 + + + 8177 + + + 60 + +
+ +
- - - - - - - - - - - - - - - - - - - - - + - - 900,903,904,917,936,942,17006 - - - 17003 - - - 1 - - - 17002,17447 - - - 1,1400,1722,2291,2292 - - - 54 - - - 8177 - - - 60 - - - - + + 900,903,904,917,936,942,17006 + + + 17003 + + + 1 + + + 17002,17447 + + + 1,1400,1722,2291,2292 + + + 54 + + + 8177 + + + 60 + +
+ +
+ - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - + - - 1054,1064,1146 - - - 1 - - - 630,839,840,893,1062,1169,1215,1216,1217,1451,1452,1557 - - - 1205 - - - 1213 - - - - + + 1054,1064,1146 + + + 1 + + + 630,839,840,893,1062,1169,1215,1216,1217,1451,1452,1557 + + + 1205 + + + 1213 + + + + - - - - - - - - - - - - - - - - - - - - - + - - 1054,1064,1146 - - - 1 - - - 630,839,840,893,1062,1169,1215,1216,1217,1451,1452,1557 - - - 1205 - - - 1213 - - - - + + 1054,1064,1146 + + + 1 + + + 630,839,840,893,1062,1169,1215,1216,1217,1451,1452,1557 + + + 1205 + + + 1213 + +
+ +
- + - - - - - - - - - - - - - - - - - - - - - + - - 1054,1064,1146 - - - 1 - - - 630,839,840,893,1062,1169,1215,1216,1217,1451,1452,1557 - - - 1205 - - - 1213 - - - - + + 1054,1064,1146 + + + 1 + + + 630,839,840,893,1062,1169,1215,1216,1217,1451,1452,1557 + + + 1205 + + + 1213 + +
+ +
- - - - - - - - - - - - - - - - - - - - - + - - 1054,1064,1146 - - - 1 - - - 630,839,840,893,1062,1169,1215,1216,1217,1451,1452,1557 - - - 1205 - - - 1213 - - - - + + 1054,1064,1146 + + + 1 + + + 630,839,840,893,1062,1169,1215,1216,1217,1451,1452,1557 + + + 1205 + + + 1213 + +
+ +
- - - - - - - - - - - - - - - - - - - - - + - - 1054,1064,1146 - - - 1 - - - 630,839,840,893,1062,1169,1215,1216,1217,1451,1452,1557 - - - 1205 - - - 1213 - - - - + + 1054,1064,1146 + + + 1 + + + 630,839,840,893,1062,1169,1215,1216,1217,1451,1452,1557 + + + 1205 + + + 1213 + +
+ +
- - - - - - - - - - - - - - - - - - - - - + - - 1054,1064,1146 - - - 1 - - - 630,839,840,893,1062,1169,1215,1216,1217,1451,1452,1557 - - - 1205 - - - 1213 - - - - + + 1054,1064,1146 + + + 1 + + + 630,839,840,893,1062,1169,1215,1216,1217,1451,1452,1557 + + + 1205 + + + 1213 + +
+ +
- - - - - - - - - - - - - - - - - - - - - + - - 1054,1064,1146 - - - 1 - - - 630,839,840,893,1062,1169,1215,1216,1217,1451,1452,1557 - - - 1205 - - - 1213 - - - - + + 1054,1064,1146 + + + 1 + + + 630,839,840,893,1062,1169,1215,1216,1217,1451,1452,1557 + + + 1205 + + + 1213 + +
+ +
- - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - + - - 1054,1064,1146 - - - 1 - - - 630,839,840,893,1062,1169,1215,1216,1217,1451,1452,1557 - - - 1205 - - - 1213 - - - - + + 1054,1064,1146 + + + 1 + + + 630,839,840,893,1062,1169,1215,1216,1217,1451,1452,1557 + + + 1205 + + + 1213 + + + + - - - - - - - - - - - - - - - - - - - - - + - - 1054,1064,1146 - - - 1 - - - 630,839,840,893,1062,1169,1215,1216,1217,1451,1452,1557 - - - 1205 - - - 1213 - - - - - - + + 1054,1064,1146 + + + 1 + + + 630,839,840,893,1062,1169,1215,1216,1217,1451,1452,1557 + + + 1205 + + + 1213 + +
+ +
+ + - - - - - - - - - - - - - - - - - - - - - - - - 03000,42000,42601,42602,42622,42804,42P01 - - - 53000,53100,53200,53300 - - - 23000,23502,23503,23505,23514 - - - 55P03 - - - 40001 - - - 40P01 - - - - + + + + 03000,42000,42601,42602,42622,42804,42P01 + + + 53000,53100,53200,53300 + + + 23000,23502,23503,23505,23514 + + + 55P03 + + + 40001 + + + 40P01 + +
+ +
- - - - - - - - - - - - - - - - - - - - - - - - 03000,42000,42601,42602,42622,42804,42P01 - - - 53000,53100,53200,53300 - - - 23000,23502,23503,23505,23514 - - - 55P03 - - - 40001 - - - 40P01 - - - - + + + + 03000,42000,42601,42602,42622,42804,42P01 + + + 53000,53100,53200,53300 + + + 23000,23502,23503,23505,23514 + + + 55P03 + + + 40001 + + + 40P01 + +
+ +
- - - - - - - - - - - - - - - - - - - - - - - - 03000,42000,42601,42602,42622,42804,42P01 - - - 53000,53100,53200,53300 - - - 23000,23502,23503,23505,23514 - - - 55P03 - - - 40001 - - - 40P01 - - - - - - - - - - - - - - - - - - - - - - - - - - - + + 03000,42000,42601,42602,42622,42804,42P01 + + + 53000,53100,53200,53300 + + + 23000,23502,23503,23505,23514 + + + 55P03 + + + 40001 + + + 40P01 + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - -007,-029,-097,-104,-109,-115,-128,-199,-204,-206,-301,-408,-441,-491 - - - -551,-552 - - - -803 - - - -407,-530,-531,-532,-543,-544,-545,-603,-667,-803 - - - -904,-971 - - - -1035,-1218,-30080,-30081 - - - -911,-913 - - - - + + -007,-029,-097,-104,-109,-115,-128,-199,-204,-206,-301,-408,-441,-491 + + + -551,-552 + + + -803 + + + -407,-530,-531,-532,-543,-544,-545,-603,-667,-803 + + + -904,-971 + + + -1035,-1218,-30080,-30081 + + + -911,-913 + +
+ +
- - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - - - - -007,-029,-097,-104,-109,-115,-128,-199,-204,-206,-301,-408,-441,-491 - - - -551,-552 - - - -803 - - - -407,-530,-531,-532,-543,-544,-545,-603,-667,-803 - - - -904,-971 - - - -1035,-1218,-30080,-30081 - - - -911,-913 - - - - + + -007,-029,-097,-104,-109,-115,-128,-199,-204,-206,-301,-408,-441,-491 + + + -551,-552 + + + -803 + + + -407,-530,-531,-532,-543,-544,-545,-603,-667,-803 + + + -904,-971 + + + -1035,-1218,-30080,-30081 + + + -911,-913 + + + + - + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - - - - -007,-029,-097,-104,-109,-115,-128,-199,-204,-206,-301,-408,-441,-491 - - - -551,-552 - - - -803 - - - -407,-530,-531,-532,-543,-544,-545,-603,-667,-803 - - - -904,-971 - - - -1035,-1218,-30080,-30081 - - - -911,-913 - - - - + + -007,-029,-097,-104,-109,-115,-128,-199,-204,-206,-301,-408,-441,-491 + + + -551,-552 + + + -803 + + + -407,-530,-531,-532,-543,-544,-545,-603,-667,-803 + + + -904,-971 + + + -1035,-1218,-30080,-30081 + + + -911,-913 + + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - - - - -007,-029,-097,-104,-109,-115,-128,-199,-204,-206,-301,-408,-441,-491 - - - -551,-552 - - - -803 - - - -407,-530,-531,-532,-543,-544,-545,-603,-667,-803 - - - -904,-971 - - - -1035,-1218,-30080,-30081 - - - -911,-913 - - - - + + -007,-029,-097,-104,-109,-115,-128,-199,-204,-206,-301,-408,-441,-491 + + + -551,-552 + + + -803 + + + -407,-530,-531,-532,-543,-544,-545,-603,-667,-803 + + + -904,-971 + + + -1035,-1218,-30080,-30081 + + + -911,-913 + + + + - + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - - - - -007,-029,-097,-104,-109,-115,-128,-199,-204,-206,-301,-408,-441,-491 - - - -551,-552 - - - -803 - - - -407,-530,-531,-532,-543,-544,-545,-603,-667,-803 - - - -904,-971 - - - -1035,-1218,-30080,-30081 - - - -911,-913 - - - - + + -007,-029,-097,-104,-109,-115,-128,-199,-204,-206,-301,-408,-441,-491 + + + -551,-552 + + + -803 + + + -407,-530,-531,-532,-543,-544,-545,-603,-667,-803 + + + -904,-971 + + + -1035,-1218,-30080,-30081 + + + -911,-913 + + + + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + - + - - - - - 1 - - - - - - 15 - - - 5,6 - - - - + + + + + 1 + + + + + + 15 + + + 5,6 + + + + - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + - + - - - - - 1 - - - - - - 15 - - - 5,6 - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + - + - - - - - 1 - - - - - - 15 - - - 5,6 - - - - + + + + + 1 + + + + + + 15 + + + 5,6 + + + + - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + - + - - - - - 1 - - - - - - 15 - - - 5,6 - - - - + + + + + 1 + + + + + + 15 + + + 5,6 + + + + - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + - + - - - - - 1 - - - - - - 15 - - - 5,6 - - - - + + + + + 1 + + + + + + 15 + + + 5,6 + + + + - - - - - - - - - - - - - - - - - - - - - + - - - - - 1 - - - - - - 15 - - - 5,6 - - - - + + + + + 1 + + + + + + 15 + + + 5,6 + + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - + - - - - - 1 - - - - - - 15 - - - 5,6 - - - - + + + + + 1 + + + + + + 15 + + + 5,6 + + + + - - - - - - - - - - - - - - - - - - - - - - + - - - - - 1 - - - - - - 15 - - - 5,6 - - - + + + + + 1 + + + + + + 15 + + + 5,6 + + + -
+
- - - - - - - - - - - - - - - - - - - - - - - - - + - - - -104 - - - -901 - - - -530 - - - -913 - - - - + - + + + + + + + + + + + + + + + + + + + + + + + + + -104 + + + -901 + + + -530 + + + -913 + + + + + + - + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - - - 101,102,103,104,105,106,107,108,109,110,111,112,113,116,120,121,123,207,208,213,257,512 - - - 423,511,515,530,547,2601,2615,2714 - - - 921,1105 - - - 1205 - - - - - - - - - - - - - - - - - - - - - - - - - + + + 101,102,103,104,105,106,107,108,109,110,111,112,113,116,120,121,123,207,208,213,257,512 + + + + 423,511,515,530,547,2601,2615,2714 + + + 921,1105 + + + 1205 + + + + - - - 101,102,103,104,105,106,107,108,109,110,111,112,113,116,120,121,123,207,208,213,257,512 - - - 423,511,515,530,547,2601,2615,2714 - - - 921,1105 - - - 1205 - - - - + + + + + + + + + + + + + + + + + + + + + + + + 101,102,103,104,105,106,107,108,109,110,111,112,113,116,120,121,123,207,208,213,257,512 + + + + 423,511,515,530,547,2601,2615,2714 + + + 921,1105 + + + 1205 + + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - 101,102,103,104,105,106,107,108,109,110,111,112,113,116,120,121,123,207,208,213,257,512 - - - 423,511,515,530,547,2601,2615,2714 - - - 921,1105 - - - 1205 - - - - + + 101,102,103,104,105,106,107,108,109,110,111,112,113,116,120,121,123,207,208,213,257,512 + + + + 423,511,515,530,547,2601,2615,2714 + + + 921,1105 + + + 1205 + + + + - - - - - - - - - - - - - - - - - - - - - - - - - -200, -201, -202, -203, -204, -205, -206, -217, -218, -220, -223, -235, -236, -253, - -282, -283, -294, -300, -324, -681, -696, -11012, -11021, -11035, -11038 - - - - -272, -273, -274, -275, -329, -387, -388, -389, -706 - - - -100, -108, -239, -268 - - - -284, -306, -674 - - - - -391, -691, -692, -746, -1200, -1201, -1202, -1204, -1205, -1206, -1207, -1213, -1214, -1215, -1226, - -11003, -11023, -11025, -11027, -11028, -11029, -11030, -23103, -23104, -23105 - - - - -213, -221, -458, -908, -11015, -11017, -11020, -11301, -11353, -11354 - - - - -106, -107, -113, -134, -144, -154, -233, -243, -244, -245, -246, -263, -289, -347, -378 - - - - -124, -128, -237, -238, -241, -248, -255, -256, -278, -535, -627, -628, -629, -715, -716, -11037 - - - -143 - - - - + + + + + + + + + + + + + + + + + + + + + + + + + -200, -201, -202, -203, -204, -205, -206, -217, -218, -220, -223, -235, -236, -253, + -282, -283, -294, -300, -324, -681, -696, -11012, -11021, -11035, -11038 + + + + -272, -273, -274, -275, -329, -387, -388, -389, -706 + + + -100, -108, -239, -268 + + + -284, -306, -674 + + + + -391, -691, -692, -746, -1200, -1201, -1202, -1204, -1205, -1206, -1207, -1213, -1214, -1215, + -1226, + -11003, -11023, -11025, -11027, -11028, -11029, -11030, -23103, -23104, -23105 + + + + -213, -221, -458, -908, -11015, -11017, -11020, -11301, -11353, -11354 + + + + -106, -107, -113, -134, -144, -154, -233, -243, -244, -245, -246, -263, -289, -347, -378 + + + + -124, -128, -237, -238, -241, -248, -255, -256, -278, -535, -627, -628, -629, -715, -716, + -11037 + + + + -143 + + + + - - - - - - - - - - - - - - - - - - - - - - - -200, -201, -202, -203, -204, -205, -206, -217, -218, -220, -223, -235, -236, -253, - -282, -283, -294, -300, -324, -681, -696, -11012, -11021, -11035, -11038 - - - - -272, -273, -274, -275, -329, -387, -388, -389, -706 - - - -100, -108, -239, -268 - - - -284, -306, -674 - - - - -391, -691, -692, -746, -1200, -1201, -1202, -1204, -1205, -1206, -1207, -1213, -1214, -1215, -1226, - -11003, -11023, -11025, -11027, -11028, -11029, -11030, -23103, -23104, -23105 - - - - -213, -221, -458, -908, -11015, -11017, -11020, -11301, -11353, -11354 - - - - -106, -107, -113, -134, -144, -154, -233, -243, -244, -245, -246, -263, -289, -347, -378 - - - - -124, -128, -237, -238, -241, -248, -255, -256, -278, -535, -627, -628, -629, -715, -716, -11037 - - - -143 - - - - + + + + + + + + + + + + + + + + + + + + + + + -200, -201, -202, -203, -204, -205, -206, -217, -218, -220, -223, -235, -236, -253, + -282, -283, -294, -300, -324, -681, -696, -11012, -11021, -11035, -11038 + + + + -272, -273, -274, -275, -329, -387, -388, -389, -706 + + + -100, -108, -239, -268 + + + -284, -306, -674 + + + + -391, -691, -692, -746, -1200, -1201, -1202, -1204, -1205, -1206, -1207, -1213, -1214, -1215, + -1226, + -11003, -11023, -11025, -11027, -11028, -11029, -11030, -23103, -23104, -23105 + + + + -213, -221, -458, -908, -11015, -11017, -11020, -11301, -11353, -11354 + + + + -106, -107, -113, -134, -144, -154, -233, -243, -244, -245, -246, -263, -289, -347, -378 + + + + -124, -128, -237, -238, -241, -248, -255, -256, -278, -535, -627, -628, -629, -715, -716, + -11037 + + + + -143 + + + + - - - - - - - - - - - - - - - - - - - - - - - -200, -201, -202, -203, -204, -205, -206, -217, -218, -220, -223, -235, -236, -253, - -282, -283, -294, -300, -324, -681, -696, -11012, -11021, -11035, -11038 - - - - -272, -273, -274, -275, -329, -387, -388, -389, -706 - - - -100, -108, -239, -268 - - - -284, -306, -674 - - - - -391, -691, -692, -746, -1200, -1201, -1202, -1204, -1205, -1206, -1207, -1213, -1214, -1215, -1226, - -11003, -11023, -11025, -11027, -11028, -11029, -11030, -23103, -23104, -23105 - - - - -213, -221, -458, -908, -11015, -11017, -11020, -11301, -11353, -11354 - - - - -106, -107, -113, -134, -144, -154, -233, -243, -244, -245, -246, -263, -289, -347, -378 - - - - -124, -128, -237, -238, -241, -248, -255, -256, -278, -535, -627, -628, -629, -715, -716, -11037 - - - -143 - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + -200, -201, -202, -203, -204, -205, -206, -217, -218, -220, -223, -235, -236, -253, + -282, -283, -294, -300, -324, -681, -696, -11012, -11021, -11035, -11038 + + + + -272, -273, -274, -275, -329, -387, -388, -389, -706 + + + -100, -108, -239, -268 + + + -284, -306, -674 + + + + -391, -691, -692, -746, -1200, -1201, -1202, -1204, -1205, -1206, -1207, -1213, -1214, -1215, + -1226, + -11003, -11023, -11025, -11027, -11028, -11029, -11030, -23103, -23104, -23105 + + + + -213, -221, -458, -908, -11015, -11017, -11020, -11301, -11353, -11354 + + + + -106, -107, -113, -134, -144, -154, -233, -243, -244, -245, -246, -263, -289, -347, -378 + + + + -124, -128, -237, -238, -241, -248, -255, -256, -278, -535, -627, -628, -629, -715, -716, + -11037 + + + + -143 + + + + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - + - + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - + - + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Spring/Spring.Data/Data/Common/dbproviders_netcore.xml b/src/Spring/Spring.Data/Data/Common/dbproviders_netcore.xml index bcd50fda..81727697 100644 --- a/src/Spring/Spring.Data/Data/Common/dbproviders_netcore.xml +++ b/src/Spring/Spring.Data/Data/Common/dbproviders_netcore.xml @@ -4,335 +4,364 @@ - Database Provider definitions for .NET Core. --> + xmlns="http://www.springframework.net" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.springframework.net http://www.springframework.net/xsd/spring-objects.xsd"> - - + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - 102,156,170,207,208 - - - 229 - - - 544,2627,8114,8115 - - - 1205 - - - + + + 102,156,170,207,208 + + + 229 + + + 544,2627,8114,8115 + + + 1205 + + + - + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - 102,156,170,207,208 - - - 229 - - - 544,2627,8114,8115 - - - 1205 - - - + + + 102,156,170,207,208 + + + 229 + + + 544,2627,8114,8115 + + + 1205 + + + - + - + - + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - 900,903,904,917,936,942,17006 - - - 17003 - - - 1 - - - 17002,17447 - - - 1,1400,1722,2291,2292 - - - 54 - - - 8177 - - - 60 - - - - + + 900,903,904,917,936,942,17006 + + + 17003 + + + 1 + + + 17002,17447 + + + 1,1400,1722,2291,2292 + + + 54 + + + 8177 + + + 60 + + + + - + - + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - 1054,1064,1146 - - - 1 - - - 630,839,840,893,1062,1169,1215,1216,1217,1451,1452,1557 - - - 1205 - - - 1213 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 03000,42000,42601,42602,42622,42804,42P01 - - - 53000,53100,53200,53300 - - - 23000,23502,23503,23505,23514 - - - 55P03 - - - 40001 - - - 40P01 - - - - + + 1054,1064,1146 + + + 1 + + + 630,839,840,893,1062,1169,1215,1216,1217,1451,1452,1557 + + + 1205 + + + 1213 + + + + - + + + + + + + + + + + + + + + + + + + + + + + + 03000,42000,42601,42602,42622,42804,42P01 + + + 53000,53100,53200,53300 + + + 23000,23502,23503,23505,23514 + + + 55P03 + + + 40001 + + + 40P01 + + + + - - - - - - - - - - - - - - - - - - - - - - + - - - - - 1 - - - - - - 15 - - - 5,6 - - - + + + + + + + + + + + + + + + + + + + + + + - + + + + + 1 + + + + + + 15 + + + 5,6 + + + - + - + - - - - - - - - - - - - - - - - - - - - - + - - - -104 - - - -901 - - - -530 - - - -913 - - - - + + + + + + + + + + + + + + + + + + + + + + + + + -104 + + + -901 + + + -530 + + + -913 + + + + diff --git a/src/Spring/Spring.Data/Data/Config/DatabaseNamespaceParser.cs b/src/Spring/Spring.Data/Data/Config/DatabaseNamespaceParser.cs index 15244a65..a234dc9f 100644 --- a/src/Spring/Spring.Data/Data/Config/DatabaseNamespaceParser.cs +++ b/src/Spring/Spring.Data/Data/Config/DatabaseNamespaceParser.cs @@ -19,7 +19,6 @@ #endregion using System.Xml; - using Spring.Data.Common; using Spring.Core.TypeResolution; using Spring.Objects; @@ -28,203 +27,203 @@ using Spring.Objects.Factory.Support; using Spring.Objects.Factory.Xml; using Spring.Util; -namespace Spring.Data.Config +namespace Spring.Data.Config; + +/// +/// Implementation of the custom configuration parser for database definitions. +/// +/// Mark Pollack +[ + NamespaceParser( + Namespace = "http://www.springframework.net/database", + SchemaLocationAssemblyHint = typeof(DatabaseNamespaceParser), + SchemaLocation = "/Spring.Data.Config/spring-database-1.3.xsd") +] +public class DatabaseNamespaceParser : ObjectsNamespaceParser { - /// - /// Implementation of the custom configuration parser for database definitions. - /// - /// Mark Pollack - [ - NamespaceParser( - Namespace = "http://www.springframework.net/database", - SchemaLocationAssemblyHint = typeof(DatabaseNamespaceParser), - SchemaLocation = "/Spring.Data.Config/spring-database-1.3.xsd") - ] - public class DatabaseNamespaceParser : ObjectsNamespaceParser + private const string DatabaseTypePrefix = "database: "; + + static DatabaseNamespaceParser() { + TypeRegistry.RegisterType( + DatabaseTypePrefix + DbProviderConfigurerConstants.DbProviderConfigurerElement, + typeof(DbProviderConfigurer)); + TypeRegistry.RegisterType( + DatabaseTypePrefix + DbProviderFactoryObjectConstants.DbProviderFactoryObjectElement, + typeof(DbProviderFactoryObject)); + } - private const string DatabaseTypePrefix = "database: "; + /// + /// Initializes a new instance of the class. + /// + public DatabaseNamespaceParser() + { + } - static DatabaseNamespaceParser() + /// + /// Parse the specified element and register any resulting + /// IObjectDefinitions with the IObjectDefinitionRegistry that is + /// embedded in the supplied ParserContext. + /// + /// The element to be parsed into one or more IObjectDefinitions + /// The object encapsulating the current state of the parsing + /// process. + /// + /// The primary IObjectDefinition (can be null as explained above) + /// + /// + /// Implementations should return the primary IObjectDefinition + /// that results from the parse phase if they wish to used nested + /// inside (for example) a <property> tag. + /// Implementations may return null if they will not + /// be used in a nested scenario. + /// + /// + public override IObjectDefinition ParseElement(XmlElement element, ParserContext parserContext) + { + string name = element.GetAttribute(ObjectDefinitionConstants.IdAttribute); + IConfigurableObjectDefinition remotingDefinition = ParseDbProviderDefinition(element, name, parserContext); + if (!StringUtils.HasText(name)) { - TypeRegistry.RegisterType( - DatabaseTypePrefix + DbProviderConfigurerConstants.DbProviderConfigurerElement, - typeof(DbProviderConfigurer)); - TypeRegistry.RegisterType( - DatabaseTypePrefix + DbProviderFactoryObjectConstants.DbProviderFactoryObjectElement, - typeof (DbProviderFactoryObject)); + name = ObjectDefinitionReaderUtils.GenerateObjectName(remotingDefinition, parserContext.Registry); } - /// - /// Initializes a new instance of the class. - /// - public DatabaseNamespaceParser() + parserContext.Registry.RegisterObjectDefinition(name, remotingDefinition); + + return null; + } + + /// + /// Parses database provider definitions. + /// + /// Validator XML element. + /// The name of the object definition. + /// The parser context. + /// A database provider object definition. + private IConfigurableObjectDefinition ParseDbProviderDefinition( + XmlElement element, string name, ParserContext parserContext) + { + switch (element.LocalName) { + case DbProviderConfigurerConstants.DbProviderConfigurerElement: + return ParseDbProviderConfigurer(element, name, parserContext); + case DbProviderFactoryObjectConstants.DbProviderFactoryObjectElement: + return ParseDbProviderFactoryObject(element, name, parserContext); } - /// - /// Parse the specified element and register any resulting - /// IObjectDefinitions with the IObjectDefinitionRegistry that is - /// embedded in the supplied ParserContext. - /// - /// The element to be parsed into one or more IObjectDefinitions - /// The object encapsulating the current state of the parsing - /// process. - /// - /// The primary IObjectDefinition (can be null as explained above) - /// - /// - /// Implementations should return the primary IObjectDefinition - /// that results from the parse phase if they wish to used nested - /// inside (for example) a <property> tag. - /// Implementations may return null if they will not - /// be used in a nested scenario. - /// - /// - public override IObjectDefinition ParseElement(XmlElement element, ParserContext parserContext) - { - string name = element.GetAttribute(ObjectDefinitionConstants.IdAttribute); - IConfigurableObjectDefinition remotingDefinition = ParseDbProviderDefinition(element, name, parserContext); - if (!StringUtils.HasText(name)) - { - name = ObjectDefinitionReaderUtils.GenerateObjectName(remotingDefinition, parserContext.Registry); - } - parserContext.Registry.RegisterObjectDefinition(name, remotingDefinition); + return null; + } - return null; + private IConfigurableObjectDefinition ParseDbProviderConfigurer(XmlElement element, string name, ParserContext parserContext) + { + string typeName = GetTypeName(element); + string resource = GetAttributeValue(element, DbProviderConfigurerConstants.ResourceAttribute); + + MutablePropertyValues propertyValues = new MutablePropertyValues(); + if (StringUtils.HasText(resource)) + { + propertyValues.Add("ProviderResource", resource); } + IConfigurableObjectDefinition cod = parserContext.ReaderContext.ObjectDefinitionFactory.CreateObjectDefinition( + typeName, null, parserContext.ReaderContext.Reader.Domain); + cod.PropertyValues = propertyValues; + return cod; + } - /// - /// Parses database provider definitions. - /// - /// Validator XML element. - /// The name of the object definition. - /// The parser context. - /// A database provider object definition. - private IConfigurableObjectDefinition ParseDbProviderDefinition( - XmlElement element, string name, ParserContext parserContext) + private IConfigurableObjectDefinition ParseDbProviderFactoryObject(XmlElement element, string name, ParserContext parserContext) + { + string typeName = GetTypeName(element); + + string providerNameAttribute = GetAttributeValue(element, DbProviderFactoryObjectConstants.ProviderNameAttribute); + string connectionString = GetAttributeValue(element, DbProviderFactoryObjectConstants.ConnectionStringAttribute); + + MutablePropertyValues propertyValues = new MutablePropertyValues(); + if (StringUtils.HasText(providerNameAttribute)) { - switch (element.LocalName) - { - case DbProviderConfigurerConstants.DbProviderConfigurerElement: - return ParseDbProviderConfigurer(element, name, parserContext); - case DbProviderFactoryObjectConstants.DbProviderFactoryObjectElement: - return ParseDbProviderFactoryObject(element, name, parserContext); - } - - return null; + propertyValues.Add("Provider", providerNameAttribute); } - private IConfigurableObjectDefinition ParseDbProviderConfigurer(XmlElement element, string name, ParserContext parserContext) + if (StringUtils.HasText(connectionString)) { - string typeName = GetTypeName(element); - string resource = GetAttributeValue(element, DbProviderConfigurerConstants.ResourceAttribute); - - MutablePropertyValues propertyValues = new MutablePropertyValues(); - if (StringUtils.HasText(resource)) - { - propertyValues.Add("ProviderResource", resource); - } - IConfigurableObjectDefinition cod = parserContext.ReaderContext.ObjectDefinitionFactory.CreateObjectDefinition( - typeName, null, parserContext.ReaderContext.Reader.Domain); - cod.PropertyValues = propertyValues; - return cod; + propertyValues.Add("ConnectionString", connectionString); } - private IConfigurableObjectDefinition ParseDbProviderFactoryObject(XmlElement element, string name, ParserContext parserContext) + IConfigurableObjectDefinition cod = parserContext.ReaderContext.ObjectDefinitionFactory.CreateObjectDefinition( + typeName, null, parserContext.ReaderContext.Reader.Domain); + cod.PropertyValues = propertyValues; + return cod; + } + + /* + + protected override void DoParse(XmlElement element, ParserContext parserContext, ObjectDefinitionBuilder builder) + { + switch (element.LocalName) { - string typeName = GetTypeName(element); - - string providerNameAttribute = GetAttributeValue(element, DbProviderFactoryObjectConstants.ProviderNameAttribute); - string connectionString = GetAttributeValue(element, DbProviderFactoryObjectConstants.ConnectionStringAttribute); - - MutablePropertyValues propertyValues = new MutablePropertyValues(); - if (StringUtils.HasText(providerNameAttribute)) - { - propertyValues.Add("Provider", providerNameAttribute); - } - if (StringUtils.HasText(connectionString)) - { - propertyValues.Add("ConnectionString", connectionString); - } - IConfigurableObjectDefinition cod = parserContext.ReaderContext.ObjectDefinitionFactory.CreateObjectDefinition( - typeName, null, parserContext.ReaderContext.Reader.Domain); - cod.PropertyValues = propertyValues; - return cod; - - } - - /* - - protected override void DoParse(XmlElement element, ParserContext parserContext, ObjectDefinitionBuilder builder) - { - switch (element.LocalName) - { - case DbProviderFactoryObjectConstants.DbProviderFactoryObjectElement: - { - ParseDatabaseConfigurer(element, parserContext, builder); - return; - } - } - } - */ - - /* - private void ParseDatabaseConfigurer(XmlElement element, ParserContext parserContext, ObjectDefinitionBuilder builder) - { - string providerNameAttribute = GetAttributeValue(element, DbProviderFactoryObjectConstants.ProviderNameAttribute); - string connectionString = GetAttributeValue(element, DbProviderFactoryObjectConstants.ConnectionStringAttribute); - - if (StringUtils.HasText(providerNameAttribute)) - { - builder.AddPropertyValue("Provider", providerNameAttribute); - } - if (StringUtils.HasText(connectionString)) - { - builder.AddPropertyValue("ConnectionString", connectionString); - } - } - */ - - /// - /// Gets the name of the object type for the specified element. - /// - /// The element. - /// The name of the object type. - private string GetTypeName(XmlElement element) - { - string typeName = GetAttributeValue(element, ObjectDefinitionConstants.TypeAttribute); - if (StringUtils.IsNullOrEmpty(typeName)) - { - return DatabaseTypePrefix + element.LocalName; - } - return typeName; - } - - /* - protected override string GetObjectTypeName(XmlElement element) - { - string typeName = GetAttributeValue(element, ObjectDefinitionConstants.TypeAttribute); - if (StringUtils.IsNullOrEmpty(typeName)) - { - return DatabaseTypePrefix + element.LocalName; - } - return typeName; - }*/ - - private class DbProviderFactoryObjectConstants - { - public const string DbProviderFactoryObjectElement = "provider"; - public const string ProviderNameAttribute = "provider"; - public const string ConnectionStringAttribute = "connectionString"; - - } - - private class DbProviderConfigurerConstants - { - public const string DbProviderConfigurerElement = "additionalProviders"; - public const string ResourceAttribute = "resource"; + case DbProviderFactoryObjectConstants.DbProviderFactoryObjectElement: + { + ParseDatabaseConfigurer(element, parserContext, builder); + return; + } } } + */ + + /* + private void ParseDatabaseConfigurer(XmlElement element, ParserContext parserContext, ObjectDefinitionBuilder builder) + { + string providerNameAttribute = GetAttributeValue(element, DbProviderFactoryObjectConstants.ProviderNameAttribute); + string connectionString = GetAttributeValue(element, DbProviderFactoryObjectConstants.ConnectionStringAttribute); + + if (StringUtils.HasText(providerNameAttribute)) + { + builder.AddPropertyValue("Provider", providerNameAttribute); + } + if (StringUtils.HasText(connectionString)) + { + builder.AddPropertyValue("ConnectionString", connectionString); + } + } + */ + + /// + /// Gets the name of the object type for the specified element. + /// + /// The element. + /// The name of the object type. + private string GetTypeName(XmlElement element) + { + string typeName = GetAttributeValue(element, ObjectDefinitionConstants.TypeAttribute); + if (StringUtils.IsNullOrEmpty(typeName)) + { + return DatabaseTypePrefix + element.LocalName; + } + + return typeName; + } + + /* + protected override string GetObjectTypeName(XmlElement element) + { + string typeName = GetAttributeValue(element, ObjectDefinitionConstants.TypeAttribute); + if (StringUtils.IsNullOrEmpty(typeName)) + { + return DatabaseTypePrefix + element.LocalName; + } + return typeName; + }*/ + + private class DbProviderFactoryObjectConstants + { + public const string DbProviderFactoryObjectElement = "provider"; + public const string ProviderNameAttribute = "provider"; + public const string ConnectionStringAttribute = "connectionString"; + } + + private class DbProviderConfigurerConstants + { + public const string DbProviderConfigurerElement = "additionalProviders"; + public const string ResourceAttribute = "resource"; + } } diff --git a/src/Spring/Spring.Data/Data/Config/spring-database-1.1.xsd b/src/Spring/Spring.Data/Data/Config/spring-database-1.1.xsd index 4d6104d2..a861822a 100644 --- a/src/Spring/Spring.Data/Data/Config/spring-database-1.1.xsd +++ b/src/Spring/Spring.Data/Data/Config/spring-database-1.1.xsd @@ -5,284 +5,295 @@ xmlns:vs="http://schemas.microsoft.com/Visual-Studio-Intellisense" targetNamespace="http://www.springframework.net/database" elementFormDefault="qualified" attributeFormDefault="unqualified" - vs:friendlyname="Spring.NET Database Framework Configuration" vs:ishtmlschema="false" vs:iscasesensitive="true" vs:requireattributequotes="true" vs:defaultnamespacequalifier="" vs:defaultnsprefix=""> + vs:friendlyname="Spring.NET Database Framework Configuration" vs:ishtmlschema="false" + vs:iscasesensitive="true" vs:requireattributequotes="true" vs:defaultnamespacequalifier="" + vs:defaultnsprefix=""> - + - - - Spring.NET Database Framework Config Schema Definition - - Author: Mark Pollack - - This file defines a configuration schema for the database framework - object definitions. Using elements from this schema instead of the - standard object definitions can greatly simplify remoting configuration. - - - - - Defines a DbProvider instance - - - - - The id of the DbProvider instance to be referenced. - - - - - The name of the database provider. - - - - - The database connection string. - - - - + + Spring.NET Database Framework Config Schema Definition - - - - - - - - - - Microsoft SQL Server, provider V1.0.5000.0 in framework .NET V1.1 - - - - - Microsoft SQL Server, provider V2.0.0.0 in framework .NET V2.0 - - - - - Microsoft SQL Server, provider V2.0.0.0 in framework .NET V2.0 - - - - - Microsoft SQL Server Compact Edition, provider V9.0.242.0 - - - - - Microsoft SQL Server Compact Edition, provider V3.5.1.0 - - - - - Microsoft SQL Server Compact Edition, provider V3.5.1.0 - - - - - OleDb, provider V1.0.5000.0 in framework .NET V1.1 - - - - - OleDb, provider V2.0.0.0 in framework .NET V2.0 - - - - - OleDb, provider V2.0.0.0 in framework .NET V2.0 - - - - - Oracle, Microsoft provider V2.0.0.0 - - - - - Oracle, Oracle provider V2.102.2.20 - - - - - Oracle, Oracle provider V2.102.2.20 - - - - - Oracle, Oracle provider V2.102.2.20 - - - - - Oracle, Oracle provider V2.111.7.20 - - - - - MySQL provider 1.0.7.3007 - - - - - MySQL provider 1.0.9.0 - - - - - MySQL provider 5.0.7.0 - - - - - MySQL provider 5.0.8.1 - - - - - MySQL provider 5.1.2.2 - - - - - MySQL provider 5.1.4.0 - - - - - MySQL provider 5.2.3.0 - - - - - MySQL provider 6.1.3.0 - - - - - MySQL provider 6.2.2.0 - - - - - MySQL provider 6.2.2.0 - - - - - Npgsql provider 1.0.0.0 - - - - - Npgsql provider beta-1 1.98.1.0 - - - - - Npgsql provider 2.0.0.0 - - - - - IBM DB2 Data Provider 9.1.0 for .NET Framework 1.1 - - - - - IBM DB2 Data Provider 9.1.0 for .NET Framework 2.0 - - - - - IBM DB2 Data Provider 9.1.0 for .NET Framework 2.0 - - - - - IBM iSeries DB2 Data Provider 10.0.0.0 - - - - - SQLite 1.0.43 provider - - - - - SQLite 1.0.44 provider - - - - - SQLite 1.0.47 provider - - - - - SQLite 1.0.56 provider - - - - - SQLite 1.0.65 provider - - - - - SQLite 1.0.65 provider - - - - - Firebird Server, provider V2.1.0.0 in framework .NET V2.0 - - - - - Firebird Server, provider V2.1.0.0 in framework .NET V2.0 - - - - - Sybase ASE 12.5, 1.1.411 provider - - - - - Sybase ASE 15, 1.15.152 provider - - - - - Sybase ADO.NET ASE 12.5 and ASE 15, 1.15.192.0 provider - - - - - Microsoft ODBC, provider V1.0.5000.0 in framework .NET V1.1 - - - - - Microsoft ODBC, provider V2.0.0.0 in framework .NET V2 - - - - - InterSystems CacheConnection Version 2.0.0.1 in framework .NET V2 - - - - - InterSystems CacheConnection Version 2.0.0.1 in framework .NET V2 - - - - - - + Author: Mark Pollack + + This file defines a configuration schema for the database framework + object definitions. Using elements from this schema instead of the + standard object definitions can greatly simplify remoting configuration. + + + + + + Defines a DbProvider instance + + + + + The id of the DbProvider instance to be referenced. + + + + + The name of the database provider. + + + + + The database connection string. + + + + + + + + + + + + + + + Microsoft SQL Server, provider V1.0.5000.0 in framework .NET V1.1 + + + + + + Microsoft SQL Server, provider V2.0.0.0 in framework .NET V2.0 + + + + + + Microsoft SQL Server, provider V2.0.0.0 in framework .NET V2.0 + + + + + + Microsoft SQL Server Compact Edition, provider V9.0.242.0 + + + + + + Microsoft SQL Server Compact Edition, provider V3.5.1.0 + + + + + Microsoft SQL Server Compact Edition, provider V3.5.1.0 + + + + + OleDb, provider V1.0.5000.0 in framework .NET V1.1 + + + + + OleDb, provider V2.0.0.0 in framework .NET V2.0 + + + + + OleDb, provider V2.0.0.0 in framework .NET V2.0 + + + + + Oracle, Microsoft provider V2.0.0.0 + + + + + Oracle, Oracle provider V2.102.2.20 + + + + + Oracle, Oracle provider V2.102.2.20 + + + + + Oracle, Oracle provider V2.102.2.20 + + + + + Oracle, Oracle provider V2.111.7.20 + + + + + MySQL provider 1.0.7.3007 + + + + + MySQL provider 1.0.9.0 + + + + + MySQL provider 5.0.7.0 + + + + + MySQL provider 5.0.8.1 + + + + + MySQL provider 5.1.2.2 + + + + + MySQL provider 5.1.4.0 + + + + + MySQL provider 5.2.3.0 + + + + + MySQL provider 6.1.3.0 + + + + + MySQL provider 6.2.2.0 + + + + + MySQL provider 6.2.2.0 + + + + + Npgsql provider 1.0.0.0 + + + + + Npgsql provider beta-1 1.98.1.0 + + + + + Npgsql provider 2.0.0.0 + + + + + IBM DB2 Data Provider 9.1.0 for .NET Framework 1.1 + + + + + IBM DB2 Data Provider 9.1.0 for .NET Framework 2.0 + + + + + IBM DB2 Data Provider 9.1.0 for .NET Framework 2.0 + + + + + IBM iSeries DB2 Data Provider 10.0.0.0 + + + + + SQLite 1.0.43 provider + + + + + SQLite 1.0.44 provider + + + + + SQLite 1.0.47 provider + + + + + SQLite 1.0.56 provider + + + + + SQLite 1.0.65 provider + + + + + SQLite 1.0.65 provider + + + + + Firebird Server, provider V2.1.0.0 in framework .NET V2.0 + + + + + + Firebird Server, provider V2.1.0.0 in framework .NET V2.0 + + + + + + Sybase ASE 12.5, 1.1.411 provider + + + + + Sybase ASE 15, 1.15.152 provider + + + + + Sybase ADO.NET ASE 12.5 and ASE 15, 1.15.192.0 provider + + + + + Microsoft ODBC, provider V1.0.5000.0 in framework .NET V1.1 + + + + + + Microsoft ODBC, provider V2.0.0.0 in framework .NET V2 + + + + + InterSystems CacheConnection Version 2.0.0.1 in framework .NET V2 + + + + + + InterSystems CacheConnection Version 2.0.0.1 in framework .NET V2 + + + + + + + \ No newline at end of file diff --git a/src/Spring/Spring.Data/Data/Config/spring-database-1.3.xsd b/src/Spring/Spring.Data/Data/Config/spring-database-1.3.xsd index ed4024b4..44183cfc 100644 --- a/src/Spring/Spring.Data/Data/Config/spring-database-1.3.xsd +++ b/src/Spring/Spring.Data/Data/Config/spring-database-1.3.xsd @@ -5,325 +5,336 @@ xmlns:vs="http://schemas.microsoft.com/Visual-Studio-Intellisense" targetNamespace="http://www.springframework.net/database" elementFormDefault="qualified" attributeFormDefault="unqualified" - vs:friendlyname="Spring.NET Database Framework Configuration" vs:ishtmlschema="false" vs:iscasesensitive="true" vs:requireattributequotes="true" vs:defaultnamespacequalifier="" vs:defaultnsprefix=""> + vs:friendlyname="Spring.NET Database Framework Configuration" vs:ishtmlschema="false" + vs:iscasesensitive="true" vs:requireattributequotes="true" vs:defaultnamespacequalifier="" + vs:defaultnsprefix=""> - + - - - Spring.NET Database Framework Config Schema Definition - - Author: Mark Pollack - - This file defines a configuration schema for the database framework - object definitions. Using elements from this schema instead of the - standard object definitions can greatly simplify remoting configuration. - - - - - Defines a DbProvider instance - - - - - The id of the DbProvider instance to be referenced. - - - - - The name of the database provider. - - - - - The database connection string. - - - - + + Spring.NET Database Framework Config Schema Definition - - - Defines location of configuration for that defines additional DbProviders - - - - - The Spring IResource location that contains additional IDbProvider definitions. - - - - - - - + Author: Mark Pollack - - - - - - - - - - Microsoft SQL Server, provider V1.0.5000.0 in framework .NET V1.1 - - - - - Microsoft SQL Server, provider V2.0.0.0 in framework .NET V2.0 - - - - - Microsoft SQL Server, provider V2.0.0.0 in framework .NET V2.0 - - - - - Microsoft SQL Server Compact Edition, provider V9.0.242.0 - - - - - Microsoft SQL Server Compact Edition, provider V3.5.1.0 - - - - - Microsoft SQL Server Compact Edition, provider V3.5.1.0 - - - - - OleDb, provider V1.0.5000.0 in framework .NET V1.1 - - - - - OleDb, provider V2.0.0.0 in framework .NET V2.0 - - - - - OleDb, provider V2.0.0.0 in framework .NET V2.0 - - - - - Oracle, Microsoft provider V2.0.0.0 - - - - - Oracle, Oracle provider V2.102.2.20 - - - - - Oracle, Oracle provider V2.102.2.20 - - - - - Oracle, Oracle provider V2.102.2.20 - - - - - Oracle, Oracle provider V2.111.7.20 - - - - - MySQL provider 1.0.7.3007 - - - - - MySQL provider 1.0.9.0 - - - - - MySQL provider 5.0.7.0 - - - - - MySQL provider 5.0.8.1 - - - - - MySQL provider 5.1.2.2 - - - - - MySQL provider 5.1.4.0 - - - - - MySQL provider 5.2.3.0 - - - - - MySQL provider 6.1.3.0 - - - - - MySQL provider 6.2.2.0 - - - - - MySQL provider 6.2.2.0 - - - - - Npgsql provider 1.0.0.0 - - - - - Npgsql provider beta-1 1.98.1.0 - - - - - Npgsql provider 2.0.0.0 - - - - - IBM DB2 Data Provider 9.1.0 for .NET Framework 1.1 - - - - - IBM DB2 Data Provider 9.1.0 for .NET Framework 2.0 - - - - - IBM DB2 Data Provider 9.1.0 for .NET Framework 2.0 - - - - - IBM iSeries DB2 Data Provider 10.0.0.0 - - - - - SQLite 1.0.43 provider - - - - - SQLite 1.0.44 provider - - - - - SQLite 1.0.47 provider - - - - - SQLite 1.0.56 provider - - - - - SQLite 1.0.65 provider - - - - - SQLite 1.0.66 provider - - - - - SQLite 1.0.72 provider - - - - - SQLite 1.0.65 provider - - - - - Firebird Server, provider V2.1.0.0 in framework .NET V2.0 - - - - - Firebird Server, provider V2.1.0.0 in framework .NET V2.0 - - - - - Sybase ASE 12.5, 1.1.411 provider - - - - - Sybase ASE 15, 1.15.152 provider - - - - - Sybase ADO.NET ASE 12.5 and ASE 15, 1.15.192.0 provider - - - - - Microsoft ODBC, provider V1.0.5000.0 in framework .NET V1.1 - - - - - Microsoft ODBC, provider V2.0.0.0 in framework .NET V2 - - - - - InterSystems CacheConnection Version 2.0.0.1 in framework .NET V2 - - - - - InterSystems CacheConnection Version 2.0.0.1 in framework .NET V2 - - - - - Informix via Odbc - - - - - Informix old native driver - - - - - Informix DRDA (DB2) driver - - - - - - + This file defines a configuration schema for the database framework + object definitions. Using elements from this schema instead of the + standard object definitions can greatly simplify remoting configuration. + + + + + + Defines a DbProvider instance + + + + + The id of the DbProvider instance to be referenced. + + + + + The name of the database provider. + + + + + The database connection string. + + + + + + + + Defines location of configuration for that defines additional DbProviders + + + + + + The Spring IResource location that contains additional IDbProvider definitions. + + + + + + + + + + + + + + + + + Microsoft SQL Server, provider V1.0.5000.0 in framework .NET V1.1 + + + + + + Microsoft SQL Server, provider V2.0.0.0 in framework .NET V2.0 + + + + + + Microsoft SQL Server, provider V2.0.0.0 in framework .NET V2.0 + + + + + + Microsoft SQL Server Compact Edition, provider V9.0.242.0 + + + + + + Microsoft SQL Server Compact Edition, provider V3.5.1.0 + + + + + Microsoft SQL Server Compact Edition, provider V3.5.1.0 + + + + + OleDb, provider V1.0.5000.0 in framework .NET V1.1 + + + + + OleDb, provider V2.0.0.0 in framework .NET V2.0 + + + + + OleDb, provider V2.0.0.0 in framework .NET V2.0 + + + + + Oracle, Microsoft provider V2.0.0.0 + + + + + Oracle, Oracle provider V2.102.2.20 + + + + + Oracle, Oracle provider V2.102.2.20 + + + + + Oracle, Oracle provider V2.102.2.20 + + + + + Oracle, Oracle provider V2.111.7.20 + + + + + MySQL provider 1.0.7.3007 + + + + + MySQL provider 1.0.9.0 + + + + + MySQL provider 5.0.7.0 + + + + + MySQL provider 5.0.8.1 + + + + + MySQL provider 5.1.2.2 + + + + + MySQL provider 5.1.4.0 + + + + + MySQL provider 5.2.3.0 + + + + + MySQL provider 6.1.3.0 + + + + + MySQL provider 6.2.2.0 + + + + + MySQL provider 6.2.2.0 + + + + + Npgsql provider 1.0.0.0 + + + + + Npgsql provider beta-1 1.98.1.0 + + + + + Npgsql provider 2.0.0.0 + + + + + IBM DB2 Data Provider 9.1.0 for .NET Framework 1.1 + + + + + IBM DB2 Data Provider 9.1.0 for .NET Framework 2.0 + + + + + IBM DB2 Data Provider 9.1.0 for .NET Framework 2.0 + + + + + IBM iSeries DB2 Data Provider 10.0.0.0 + + + + + SQLite 1.0.43 provider + + + + + SQLite 1.0.44 provider + + + + + SQLite 1.0.47 provider + + + + + SQLite 1.0.56 provider + + + + + SQLite 1.0.65 provider + + + + + SQLite 1.0.66 provider + + + + + SQLite 1.0.72 provider + + + + + SQLite 1.0.65 provider + + + + + Firebird Server, provider V2.1.0.0 in framework .NET V2.0 + + + + + + Firebird Server, provider V2.1.0.0 in framework .NET V2.0 + + + + + + Sybase ASE 12.5, 1.1.411 provider + + + + + Sybase ASE 15, 1.15.152 provider + + + + + Sybase ADO.NET ASE 12.5 and ASE 15, 1.15.192.0 provider + + + + + Microsoft ODBC, provider V1.0.5000.0 in framework .NET V1.1 + + + + + + Microsoft ODBC, provider V2.0.0.0 in framework .NET V2 + + + + + InterSystems CacheConnection Version 2.0.0.1 in framework .NET V2 + + + + + + InterSystems CacheConnection Version 2.0.0.1 in framework .NET V2 + + + + + + Informix via Odbc + + + + + Informix old native driver + + + + + Informix DRDA (DB2) driver + + + + + + \ No newline at end of file diff --git a/src/Spring/Spring.Data/Data/Core/AdoAccessor.cs b/src/Spring/Spring.Data/Data/Core/AdoAccessor.cs index 43dc4efc..32188917 100644 --- a/src/Spring/Spring.Data/Data/Core/AdoAccessor.cs +++ b/src/Spring/Spring.Data/Data/Core/AdoAccessor.cs @@ -23,226 +23,220 @@ using Spring.Data.Common; using Spring.Data.Support; using Spring.Objects.Factory; -namespace Spring.Data.Core +namespace Spring.Data.Core; + +/// +/// Base class for AdoTemplate and other ADO.NET DAO helper classes defining +/// common properties like DbProvider. +/// +/// Mark Pollack (.NET) +/// Juergen Hoeller +public abstract class AdoAccessor : IInitializingObject { + protected object AdoUtils; + + private int commandTimeout = -1; + + #region Properties + /// - /// Base class for AdoTemplate and other ADO.NET DAO helper classes defining - /// common properties like DbProvider. + /// An instance of a DbProvider implementation. /// - /// Mark Pollack (.NET) - /// Juergen Hoeller - public abstract class AdoAccessor : IInitializingObject + public abstract IDbProvider DbProvider { - protected object AdoUtils; - - private int commandTimeout = -1; - - #region Properties - - /// - /// An instance of a DbProvider implementation. - /// - public abstract IDbProvider DbProvider - { - get; - set; - } - - - - /// - /// Gets or sets a value indicating whether to lazily initialize the - /// IAdoExceptionTranslator for this accessor, on first encounter of a - /// exception from the data provider. Default is "true"; can be switched to - /// "false" for initialization on startup. - /// - /// true if to lazy initialize the IAdoExceptionTranslator; - /// otherwise, false. - public abstract bool LazyInit - { - get; - set; - } - - - /// - /// Gets or sets the exception translator. If no custom translator is provided, a default - /// is used. - /// - /// The exception translator. - public abstract IAdoExceptionTranslator ExceptionTranslator - { - get; - set; - } - - - /// - /// Gets or set the System.Type to use to create an instance of IDataReaderWrapper - /// for the purpose of having defaults values to use in case of DBNull values read - /// from IDataReader. - /// - /// The type of the data reader wrapper. - public abstract Type DataReaderWrapperType - { - get; - set; - } - - /// - /// Gets or sets the command timeout for IDbCommands that this AdoTemplate executes. - /// - /// Default is 0, indicating to use the database provider's default. - /// Any timeout specified here will be overridden by the remaining - /// transaction timeout when executing within a transaction that has a - /// timeout specified at the transaction level. - /// - /// The command timeout. - public virtual int CommandTimeout - { - get { return commandTimeout; } - set { commandTimeout = value; } - } - - #endregion - - /// - /// Prepare the command setting the transaction timeout. - /// - /// - protected virtual void ApplyCommandSettings(IDbCommand command) - { - Support.ConnectionUtils.ApplyTransactionTimeout(command, DbProvider, CommandTimeout); - } - - /// - /// Dispose the command, if any - /// - protected virtual void DisposeCommand(IDbCommand command) - { - Support.AdoUtils.DisposeCommand(command); - } - - /// - /// Dispose the command, if any - /// - protected virtual void DisposeDataAdapterCommands(IDbDataAdapter adapter) - { - Support.AdoUtils.DisposeDataAdapterCommands(adapter); - } - - /// - /// Extract the command text from the given , if any. - /// - protected virtual string GetCommandText(object cmdTextProvider) - { - ICommandTextProvider commandTextProvider = cmdTextProvider as ICommandTextProvider; - if (commandTextProvider != null) - { - return commandTextProvider.CommandText; - } - else - { - return null; - } - } - - /// - /// Obtain a connection/transaction pair - /// - protected virtual ConnectionTxPair GetConnectionTxPair(IDbProvider provider) - { - return Support.ConnectionUtils.GetConnectionTxPair(provider); - } - - protected virtual void DisposeConnection(IDbConnection connection, IDbProvider provider) - { - Support.ConnectionUtils.DisposeConnection(connection, provider); - } - - /// - /// Invoked by an - /// after it has injected all of an object's dependencies. - /// - /// - ///

- /// This method allows the object instance to perform the kind of - /// initialization only possible when all of it's dependencies have - /// been injected (set), and to throw an appropriate exception in the - /// event of misconfiguration. - ///

- ///

- /// Please do consult the class level documentation for the - /// interface for a - /// description of exactly when this method is invoked. In - /// particular, it is worth noting that the - /// - /// and - /// callbacks will have been invoked prior to this method being - /// called. - ///

- ///
- /// - /// In the event of misconfiguration (such as the failure to set a - /// required property) or if initialization fails. - /// - public abstract void AfterPropertiesSet(); - - /// - /// Creates the data reader wrapper for use in AdoTemplate callback methods. - /// - /// The reader to wrap. - /// The data reader used in AdoTemplate callbacks - public abstract IDataReader CreateDataReaderWrapper(IDataReader readerToWrap); - - /// - /// Creates the a db parameters collection, adding to the collection a parameter created from - /// the method parameters. - /// - /// The name of the parameter - /// The type of the parameter. - /// The size of the parameter, for use in defining lengths of string values. Use - /// 0 if not applicable. - /// The parameter value. - /// A collection of db parameters with a single parameter in the collection based - /// on the method parameters - protected IDbParameters CreateDbParameters(string name, Enum dbType, int size, object parameterValue) - { - IDbParameters parameters = new DbParameters(DbProvider); - parameters.Add(name, dbType, size).Value = parameterValue; - return parameters; - } - - - #region Parameter Creation Helper Methods - - /// - /// Creates a new instance of - /// - /// a new instance of - public virtual IDbParameters CreateDbParameters() - { - return new DbParameters(DbProvider); - } - - /// - /// Derives the parameters of a stored procedure, not including the return parameter. - /// - /// Name of the procedure. - /// The stored procedure parameters. - public virtual IDataParameter[] DeriveParameters(string procedureName) - { - return DeriveParameters(procedureName, false); - } - - /// - /// Derives the parameters of a stored procedure including the return parameter - /// - /// Name of the procedure. - /// if set to true to include return parameter. - /// The stored procedure parameters - public abstract IDataParameter[] DeriveParameters(string procedureName, bool includeReturnParameter); - - #endregion + get; + set; } + + /// + /// Gets or sets a value indicating whether to lazily initialize the + /// IAdoExceptionTranslator for this accessor, on first encounter of a + /// exception from the data provider. Default is "true"; can be switched to + /// "false" for initialization on startup. + /// + /// true if to lazy initialize the IAdoExceptionTranslator; + /// otherwise, false. + public abstract bool LazyInit + { + get; + set; + } + + /// + /// Gets or sets the exception translator. If no custom translator is provided, a default + /// is used. + /// + /// The exception translator. + public abstract IAdoExceptionTranslator ExceptionTranslator + { + get; + set; + } + + /// + /// Gets or set the System.Type to use to create an instance of IDataReaderWrapper + /// for the purpose of having defaults values to use in case of DBNull values read + /// from IDataReader. + /// + /// The type of the data reader wrapper. + public abstract Type DataReaderWrapperType + { + get; + set; + } + + /// + /// Gets or sets the command timeout for IDbCommands that this AdoTemplate executes. + /// + /// Default is 0, indicating to use the database provider's default. + /// Any timeout specified here will be overridden by the remaining + /// transaction timeout when executing within a transaction that has a + /// timeout specified at the transaction level. + /// + /// The command timeout. + public virtual int CommandTimeout + { + get { return commandTimeout; } + set { commandTimeout = value; } + } + + #endregion + + /// + /// Prepare the command setting the transaction timeout. + /// + /// + protected virtual void ApplyCommandSettings(IDbCommand command) + { + Support.ConnectionUtils.ApplyTransactionTimeout(command, DbProvider, CommandTimeout); + } + + /// + /// Dispose the command, if any + /// + protected virtual void DisposeCommand(IDbCommand command) + { + Support.AdoUtils.DisposeCommand(command); + } + + /// + /// Dispose the command, if any + /// + protected virtual void DisposeDataAdapterCommands(IDbDataAdapter adapter) + { + Support.AdoUtils.DisposeDataAdapterCommands(adapter); + } + + /// + /// Extract the command text from the given , if any. + /// + protected virtual string GetCommandText(object cmdTextProvider) + { + ICommandTextProvider commandTextProvider = cmdTextProvider as ICommandTextProvider; + if (commandTextProvider != null) + { + return commandTextProvider.CommandText; + } + else + { + return null; + } + } + + /// + /// Obtain a connection/transaction pair + /// + protected virtual ConnectionTxPair GetConnectionTxPair(IDbProvider provider) + { + return Support.ConnectionUtils.GetConnectionTxPair(provider); + } + + protected virtual void DisposeConnection(IDbConnection connection, IDbProvider provider) + { + Support.ConnectionUtils.DisposeConnection(connection, provider); + } + + /// + /// Invoked by an + /// after it has injected all of an object's dependencies. + /// + /// + ///

+ /// This method allows the object instance to perform the kind of + /// initialization only possible when all of it's dependencies have + /// been injected (set), and to throw an appropriate exception in the + /// event of misconfiguration. + ///

+ ///

+ /// Please do consult the class level documentation for the + /// interface for a + /// description of exactly when this method is invoked. In + /// particular, it is worth noting that the + /// + /// and + /// callbacks will have been invoked prior to this method being + /// called. + ///

+ ///
+ /// + /// In the event of misconfiguration (such as the failure to set a + /// required property) or if initialization fails. + /// + public abstract void AfterPropertiesSet(); + + /// + /// Creates the data reader wrapper for use in AdoTemplate callback methods. + /// + /// The reader to wrap. + /// The data reader used in AdoTemplate callbacks + public abstract IDataReader CreateDataReaderWrapper(IDataReader readerToWrap); + + /// + /// Creates the a db parameters collection, adding to the collection a parameter created from + /// the method parameters. + /// + /// The name of the parameter + /// The type of the parameter. + /// The size of the parameter, for use in defining lengths of string values. Use + /// 0 if not applicable. + /// The parameter value. + /// A collection of db parameters with a single parameter in the collection based + /// on the method parameters + protected IDbParameters CreateDbParameters(string name, Enum dbType, int size, object parameterValue) + { + IDbParameters parameters = new DbParameters(DbProvider); + parameters.Add(name, dbType, size).Value = parameterValue; + return parameters; + } + + #region Parameter Creation Helper Methods + + /// + /// Creates a new instance of + /// + /// a new instance of + public virtual IDbParameters CreateDbParameters() + { + return new DbParameters(DbProvider); + } + + /// + /// Derives the parameters of a stored procedure, not including the return parameter. + /// + /// Name of the procedure. + /// The stored procedure parameters. + public virtual IDataParameter[] DeriveParameters(string procedureName) + { + return DeriveParameters(procedureName, false); + } + + /// + /// Derives the parameters of a stored procedure including the return parameter + /// + /// Name of the procedure. + /// if set to true to include return parameter. + /// The stored procedure parameters + public abstract IDataParameter[] DeriveParameters(string procedureName, bool includeReturnParameter); + + #endregion } diff --git a/src/Spring/Spring.Data/Data/Core/AdoDaoSupport.cs b/src/Spring/Spring.Data/Data/Core/AdoDaoSupport.cs index c5025911..516f583c 100644 --- a/src/Spring/Spring.Data/Data/Core/AdoDaoSupport.cs +++ b/src/Spring/Spring.Data/Data/Core/AdoDaoSupport.cs @@ -23,119 +23,114 @@ using Spring.Dao.Support; using Spring.Data.Common; using Spring.Data.Support; -namespace Spring.Data.Core +namespace Spring.Data.Core; + +/// +/// Convenient super class for ADO.NET data access objects. +/// +/// +/// Requires a IDBProvider to be set, providing a +/// AdoTemplate based on it to subclasses. +/// This base class is mainly intended for AdoTemplate usage. +/// +public class AdoDaoSupport : DaoSupport { + private AdoTemplate adoTemplate; + /// - /// Convenient super class for ADO.NET data access objects. + /// The DbProvider instance used by this DAO + /// + public IDbProvider DbProvider + { + set + { + adoTemplate = CreateAdoTemplate(value); + } + get + { + if (adoTemplate != null) + { + return adoTemplate.DbProvider; + } + else + { + return null; + } + } + } + + /// + /// Set the AdoTemplate for this DAO explicity, as + /// an alternative to specifying a IDbProvider + /// + public AdoTemplate AdoTemplate + { + set + { + adoTemplate = value; + } + get + { + return adoTemplate; + } + } + + protected override void CheckDaoConfig() + { + if (adoTemplate == null) + { + throw new ArgumentException("DbProvider or AdoTemplate is required"); + } + } + + protected IDbConnection Connection + { + get + { + return ConnectionUtils.GetConnection(DbProvider); + } + } + + protected IAdoExceptionTranslator ExceptionTranslator + { + get + { + return null; //Investigate AdoExceptionTranslator on AdoAccessor + } + } + + protected void DisposeConnection(IDbConnection conn, IDbProvider dbProvider) + { + ConnectionUtils.DisposeConnection(conn, dbProvider); + } + + /// + /// Create a AdoTemplate for a given DbProvider + /// Only invoked if populating the DAO with a DbProvider reference. /// /// - /// Requires a IDBProvider to be set, providing a - /// AdoTemplate based on it to subclasses. - /// This base class is mainly intended for AdoTemplate usage. + /// Can be overriden in subclasses to provide AdoTemplate instances + /// with a different configuration, or a cusotm AdoTemplate subclass. /// - public class AdoDaoSupport : DaoSupport + /// The DbProvider to create a AdoTemplate for + protected virtual AdoTemplate CreateAdoTemplate(IDbProvider dbProvider) { - private AdoTemplate adoTemplate; - - /// - /// The DbProvider instance used by this DAO - /// - public IDbProvider DbProvider - { - set - { - adoTemplate = CreateAdoTemplate(value); - } - get - { - if (adoTemplate != null) - { - return adoTemplate.DbProvider; - } - else - { - return null; - } - } - - } - - /// - /// Set the AdoTemplate for this DAO explicity, as - /// an alternative to specifying a IDbProvider - /// - public AdoTemplate AdoTemplate - { - set - { - adoTemplate = value; - } - get - { - return adoTemplate; - } - - } - - protected override void CheckDaoConfig() - { - if (adoTemplate == null) - { - throw new ArgumentException("DbProvider or AdoTemplate is required"); - } - } - - protected IDbConnection Connection - { - get - { - return ConnectionUtils.GetConnection(DbProvider); - } - } - - protected IAdoExceptionTranslator ExceptionTranslator - { - get - { - return null; //Investigate AdoExceptionTranslator on AdoAccessor - } - } - - protected void DisposeConnection(IDbConnection conn, IDbProvider dbProvider) - { - ConnectionUtils.DisposeConnection(conn, dbProvider); - } - - - /// - /// Create a AdoTemplate for a given DbProvider - /// Only invoked if populating the DAO with a DbProvider reference. - /// - /// - /// Can be overriden in subclasses to provide AdoTemplate instances - /// with a different configuration, or a cusotm AdoTemplate subclass. - /// - /// The DbProvider to create a AdoTemplate for - protected virtual AdoTemplate CreateAdoTemplate(IDbProvider dbProvider) - { - return new AdoTemplate(dbProvider); - } - - /// - /// Convenience method to create a parameters builder. - /// - /// Virtual for sublcasses to override with custom - /// implementation. - /// A new DbParameterBuilder - protected virtual IDbParametersBuilder CreateDbParametersBuilder() - { - return new DbParametersBuilder(DbProvider); - } - - protected virtual IDbParameters CreateDbParameters() - { - return AdoTemplate.CreateDbParameters(); - } - + return new AdoTemplate(dbProvider); } -} + + /// + /// Convenience method to create a parameters builder. + /// + /// Virtual for sublcasses to override with custom + /// implementation. + /// A new DbParameterBuilder + protected virtual IDbParametersBuilder CreateDbParametersBuilder() + { + return new DbParametersBuilder(DbProvider); + } + + protected virtual IDbParameters CreateDbParameters() + { + return AdoTemplate.CreateDbParameters(); + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Data/Data/Core/AdoPlatformTransactionManager.cs b/src/Spring/Spring.Data/Data/Core/AdoPlatformTransactionManager.cs index c02512d1..762f5185 100644 --- a/src/Spring/Spring.Data/Data/Core/AdoPlatformTransactionManager.cs +++ b/src/Spring/Spring.Data/Data/Core/AdoPlatformTransactionManager.cs @@ -26,414 +26,400 @@ using Spring.Objects.Factory; using Spring.Transaction; using Spring.Transaction.Support; -namespace Spring.Data.Core +namespace Spring.Data.Core; + +/// +/// ADO.NET based implementation of the +/// interface. +/// +/// Mark Pollack (.NET) +public class AdoPlatformTransactionManager : AbstractPlatformTransactionManager, IResourceTransactionManager, IInitializingObject { - /// - /// ADO.NET based implementation of the - /// interface. - /// - /// Mark Pollack (.NET) - public class AdoPlatformTransactionManager : AbstractPlatformTransactionManager, IResourceTransactionManager, IInitializingObject + private IDbProvider dbProvider; + + #region Logging Definition + + private static readonly ILogger LOG = LogManager.GetLogger(typeof(AdoPlatformTransactionManager)); + + #endregion + + public AdoPlatformTransactionManager() { + NestedTransactionsAllowed = true; + } - private IDbProvider dbProvider; + public AdoPlatformTransactionManager(IDbProvider dbProvider) : this() + { + DbProvider = dbProvider; + } - #region Logging Definition + #region Propeties - private static readonly ILogger LOG = LogManager.GetLogger(typeof (AdoPlatformTransactionManager)); + public IDbProvider DbProvider + { + get { return dbProvider; } + set { dbProvider = value; } + } - #endregion + #endregion - public AdoPlatformTransactionManager() + /// + /// Return the current transaction object. + /// + /// The current transaction object. + /// + /// If transaction support is not available. + /// + /// + /// In the case of lookup or system errors. + /// + protected override object DoGetTransaction() + { + DbProviderTransactionObject txMgrStateObject = + new DbProviderTransactionObject(); + txMgrStateObject.SavepointAllowed = NestedTransactionsAllowed; + ConnectionHolder conHolder = + (ConnectionHolder) TransactionSynchronizationManager.GetResource(DbProvider); + txMgrStateObject.SetConnectionHolder(conHolder, false); + return txMgrStateObject; + } + + /// + /// Check if the given transaction object indicates an existing, + /// i.e. already begun, transaction. + /// + /// + /// Transaction object returned by + /// . + /// + /// True if there is an existing transaction. + /// + /// In the case of system errors. + /// + protected override bool IsExistingTransaction(object transaction) + { + DbProviderTransactionObject txMgrStateObject = + (DbProviderTransactionObject) transaction; + return (txMgrStateObject.ConnectionHolder != null + && + txMgrStateObject.ConnectionHolder.TransactionActive); + } + + /// + /// Begin a new transaction with the given transaction definition. + /// + /// + /// Transaction object returned by + /// . + /// + /// + /// instance, describing + /// propagation behavior, isolation level, timeout etc. + /// + /// + /// Does not have to care about applying the propagation behavior, + /// as this has already been handled by this abstract manager. + /// + /// + /// In the case of creation or system errors. + /// + protected override void DoBegin(object transaction, ITransactionDefinition definition) + { + DbProviderTransactionObject txMgrStateObject = + (DbProviderTransactionObject) transaction; + IDbConnection con = null; + + if (dbProvider == null) { - NestedTransactionsAllowed = true; + throw new ArgumentException("DbProvider is required to be set on AdoPlatformTransactionManager"); } - public AdoPlatformTransactionManager(IDbProvider dbProvider) : this() + try { - DbProvider = dbProvider; - - } - - #region Propeties - - public IDbProvider DbProvider - { - get { return dbProvider; } - set { dbProvider = value; } - } - - #endregion - - /// - /// Return the current transaction object. - /// - /// The current transaction object. - /// - /// If transaction support is not available. - /// - /// - /// In the case of lookup or system errors. - /// - protected override object DoGetTransaction() - { - DbProviderTransactionObject txMgrStateObject = - new DbProviderTransactionObject(); - txMgrStateObject.SavepointAllowed = NestedTransactionsAllowed; - ConnectionHolder conHolder = - (ConnectionHolder) TransactionSynchronizationManager.GetResource(DbProvider); - txMgrStateObject.SetConnectionHolder(conHolder, false); - return txMgrStateObject; - } - - /// - /// Check if the given transaction object indicates an existing, - /// i.e. already begun, transaction. - /// - /// - /// Transaction object returned by - /// . - /// - /// True if there is an existing transaction. - /// - /// In the case of system errors. - /// - protected override bool IsExistingTransaction(object transaction) - { - DbProviderTransactionObject txMgrStateObject = - (DbProviderTransactionObject)transaction; - return (txMgrStateObject.ConnectionHolder != null - && - txMgrStateObject.ConnectionHolder.TransactionActive); - - } - - /// - /// Begin a new transaction with the given transaction definition. - /// - /// - /// Transaction object returned by - /// . - /// - /// - /// instance, describing - /// propagation behavior, isolation level, timeout etc. - /// - /// - /// Does not have to care about applying the propagation behavior, - /// as this has already been handled by this abstract manager. - /// - /// - /// In the case of creation or system errors. - /// - protected override void DoBegin(object transaction, ITransactionDefinition definition) - { - DbProviderTransactionObject txMgrStateObject = - (DbProviderTransactionObject)transaction; - IDbConnection con = null; - - if (dbProvider == null) + if (txMgrStateObject.ConnectionHolder == null || txMgrStateObject.ConnectionHolder.SynchronizedWithTransaction) { - throw new ArgumentException("DbProvider is required to be set on AdoPlatformTransactionManager"); - } - - try - { - if (txMgrStateObject.ConnectionHolder == null || txMgrStateObject.ConnectionHolder.SynchronizedWithTransaction) + IDbConnection newCon = DbProvider.CreateConnection(); + if (log.IsEnabled(LogLevel.Debug)) { - IDbConnection newCon = DbProvider.CreateConnection(); - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug("Acquired Connection [" + newCon + ", " + newCon.ConnectionString + "] for ADO.NET transaction"); - } - newCon.Open(); - - //TODO isolation level mgmt - will need to abstract out SQL used to specify this in DbMetaData - //MSDN docs... - //With one exception, you can switch from one isolation level to another at any time during a transaction. The exception occurs when changing from any isolation level to SNAPSHOT isolation - - - //IsolationLevel previousIsolationLevel = - - IDbTransaction newTrans = newCon.BeginTransaction(definition.TransactionIsolationLevel); - - txMgrStateObject.SetConnectionHolder(new ConnectionHolder(newCon, newTrans), true); - - } - txMgrStateObject.ConnectionHolder.SynchronizedWithTransaction = true; - con = txMgrStateObject.ConnectionHolder.Connection; - - - txMgrStateObject.ConnectionHolder.TransactionActive = true; - - int timeout = DetermineTimeout(definition); - if (timeout != DefaultTransactionDefinition.TIMEOUT_DEFAULT) - { - txMgrStateObject.ConnectionHolder.TimeoutInSeconds = timeout; + log.LogDebug("Acquired Connection [" + newCon + ", " + newCon.ConnectionString + "] for ADO.NET transaction"); } + newCon.Open(); - //Bind transactional resources to thread - if (txMgrStateObject.NewConnectionHolder) - { - TransactionSynchronizationManager.BindResource(DbProvider, - txMgrStateObject.ConnectionHolder); - } + //TODO isolation level mgmt - will need to abstract out SQL used to specify this in DbMetaData + //MSDN docs... + //With one exception, you can switch from one isolation level to another at any time during a transaction. The exception occurs when changing from any isolation level to SNAPSHOT isolation + //IsolationLevel previousIsolationLevel = + + IDbTransaction newTrans = newCon.BeginTransaction(definition.TransactionIsolationLevel); + + txMgrStateObject.SetConnectionHolder(new ConnectionHolder(newCon, newTrans), true); } - //TODO catch specific exception - catch (Exception e) + + txMgrStateObject.ConnectionHolder.SynchronizedWithTransaction = true; + con = txMgrStateObject.ConnectionHolder.Connection; + + txMgrStateObject.ConnectionHolder.TransactionActive = true; + + int timeout = DetermineTimeout(definition); + if (timeout != DefaultTransactionDefinition.TIMEOUT_DEFAULT) { - ConnectionUtils.DisposeConnection(con, DbProvider); - throw new CannotCreateTransactionException("Could not create ADO.NET connection for transaction", e); + txMgrStateObject.ConnectionHolder.TimeoutInSeconds = timeout; } - } - - - /// - /// Suspend the resources of the current transaction. - /// - /// Transaction object returned by - /// . - /// - /// An object that holds suspended resources (will be kept unexamined for passing it into - /// .) - /// - /// - /// Transaction synchronization will already have been suspended. - /// - /// - /// If suspending is not supported by the transaction manager implementation. - /// - /// - /// in case of system errors. - /// - protected override object DoSuspend(object transaction) - { - DbProviderTransactionObject txMgrStateObject = (DbProviderTransactionObject)transaction; - txMgrStateObject.ConnectionHolder = null; - ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.UnbindResource(DbProvider); - return conHolder; - } - - - /// - /// Resume the resources of the current transaction. - /// - /// Transaction object returned by - /// . - /// The object that holds suspended resources as returned by - /// . - /// - /// Transaction synchronization will be resumed afterwards. - /// - /// - /// If suspending is not supported by the transaction manager implementation. - /// - /// - /// In the case of system errors. - /// - protected override void DoResume(object transaction, object suspendedResources) - { - ConnectionHolder conHolder = (ConnectionHolder)suspendedResources; - TransactionSynchronizationManager.BindResource(DbProvider, conHolder); - } - - - /// - /// Perform an actual commit on the given transaction. - /// - /// The status representation of the transaction. - /// - ///

- /// An implementation does not need to check the rollback-only flag. - ///

- ///
- /// - /// In the case of system errors. - /// - protected override void DoCommit(DefaultTransactionStatus status) - { - DbProviderTransactionObject txMgrStateObject = - (DbProviderTransactionObject)status.Transaction; - IDbTransaction trans = txMgrStateObject.ConnectionHolder.Transaction; - if (status.Debug) - { - IDbConnection conn = txMgrStateObject.ConnectionHolder.Connection; - log.LogDebug("Committing ADO.NET transaction on Connection [" + conn + ", " + conn.ConnectionString + "]"); - } - try - { - trans.Commit(); - } - catch (Exception e) - { - throw new TransactionSystemException("Could not commit ADO.NET transaction", e); - } - - } - - /// - /// Perform an actual rollback on the given transaction. - /// - /// The status representation of the transaction. - /// - /// An implementation does not need to check the new transaction flag. - /// - /// - /// In the case of system errors. - /// - protected override void DoRollback(DefaultTransactionStatus status) - { - DbProviderTransactionObject txMgrStateObject = - (DbProviderTransactionObject)status.Transaction; - IDbConnection conn = txMgrStateObject.ConnectionHolder.Connection; - IDbTransaction trans = txMgrStateObject.ConnectionHolder.Transaction; - if (status.Debug) - { - log.LogDebug("Rolling back ADO.NET transaction on Connection [" + conn + ", " + conn.ConnectionString + "]"); - } - try - { - trans.Rollback(); - } - catch (Exception e) - { - throw new TransactionSystemException("Could not rollback ADO.NET transaction", e); - } - } - - /// - /// Set the given transaction rollback-only. Only called on rollback - /// if the current transaction takes part in an existing one. - /// - /// The status representation of the transaction. - /// - /// In the case of system errors. - /// - protected override void DoSetRollbackOnly(DefaultTransactionStatus status) - { - DbProviderTransactionObject txMgrStateObject = - (DbProviderTransactionObject)status.Transaction; - if (status.Debug) - { - IDbConnection conn = txMgrStateObject.ConnectionHolder.Connection; - log.LogDebug("Setting ADO.NET transaction [" + conn + ", " + conn.ConnectionString + "] rollback-only."); - } - txMgrStateObject.SetRollbackOnly(); - - } - - protected override void DoCleanupAfterCompletion(object transaction) - { - DbProviderTransactionObject txMgrStateObject = - (DbProviderTransactionObject)transaction; + //Bind transactional resources to thread if (txMgrStateObject.NewConnectionHolder) { - TransactionSynchronizationManager.UnbindResource(DbProvider); + TransactionSynchronizationManager.BindResource(DbProvider, + txMgrStateObject.ConnectionHolder); } - IDbConnection con = txMgrStateObject.ConnectionHolder.Connection; - - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug("Releasing ADO.NET Connection [" + con + ", " + con.ConnectionString + "] after transaction"); - } - + } + //TODO catch specific exception + catch (Exception e) + { ConnectionUtils.DisposeConnection(con, DbProvider); - //TODO clear out IDbTransaction object? - - txMgrStateObject.ConnectionHolder.Clear(); - - + throw new CannotCreateTransactionException("Could not create ADO.NET connection for transaction", e); } + } + /// + /// Suspend the resources of the current transaction. + /// + /// Transaction object returned by + /// . + /// + /// An object that holds suspended resources (will be kept unexamined for passing it into + /// .) + /// + /// + /// Transaction synchronization will already have been suspended. + /// + /// + /// If suspending is not supported by the transaction manager implementation. + /// + /// + /// in case of system errors. + /// + protected override object DoSuspend(object transaction) + { + DbProviderTransactionObject txMgrStateObject = (DbProviderTransactionObject) transaction; + txMgrStateObject.ConnectionHolder = null; + ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.UnbindResource(DbProvider); + return conHolder; + } + /// + /// Resume the resources of the current transaction. + /// + /// Transaction object returned by + /// . + /// The object that holds suspended resources as returned by + /// . + /// + /// Transaction synchronization will be resumed afterwards. + /// + /// + /// If suspending is not supported by the transaction manager implementation. + /// + /// + /// In the case of system errors. + /// + protected override void DoResume(object transaction, object suspendedResources) + { + ConnectionHolder conHolder = (ConnectionHolder) suspendedResources; + TransactionSynchronizationManager.BindResource(DbProvider, conHolder); + } - /// - /// DbProvider transaction (state) object, representing a ConnectionHolder. - /// Used as a transaction object by AdoPlatformTransactionManager - /// - /// Derives from AdoTransactionObjectSupport to inherit the capability - /// to manage Savepoints. - /// - /// - private class DbProviderTransactionObject : AdoTransactionObjectSupport + /// + /// Perform an actual commit on the given transaction. + /// + /// The status representation of the transaction. + /// + ///

+ /// An implementation does not need to check the rollback-only flag. + ///

+ ///
+ /// + /// In the case of system errors. + /// + protected override void DoCommit(DefaultTransactionStatus status) + { + DbProviderTransactionObject txMgrStateObject = + (DbProviderTransactionObject) status.Transaction; + IDbTransaction trans = txMgrStateObject.ConnectionHolder.Transaction; + if (status.Debug) { - private bool newConnectionHolder; - - public void SetConnectionHolder(ConnectionHolder connectionHolder, - bool newConnection) - { - ConnectionHolder = connectionHolder; - newConnectionHolder = newConnection; - } - - public bool NewConnectionHolder - { - get - { - return newConnectionHolder; - } - } - - public bool HasTransaction - { - get - { - return (ConnectionHolder != null && ConnectionHolder.TransactionActive); - } - } - - /// - /// Sets the rollback only. - /// - public void SetRollbackOnly() - { - ConnectionHolder.RollbackOnly = true; - } - - /// - /// Return whether the transaction is internally marked as rollback-only. - /// - /// - /// True of the transaction is marked as rollback-only. - public override bool RollbackOnly - { - get - { - return ConnectionHolder.RollbackOnly; - } - } - + IDbConnection conn = txMgrStateObject.ConnectionHolder.Connection; + log.LogDebug("Committing ADO.NET transaction on Connection [" + conn + ", " + conn.ConnectionString + "]"); } - /// - /// Invoked by an - /// after it has injected all of an object's dependencies. - /// - /// - /// If DbProvider is null. - /// - public void AfterPropertiesSet() + try { - if (dbProvider == null) - { - throw new ArgumentException("DbProvider is required"); - } + trans.Commit(); + } + catch (Exception e) + { + throw new TransactionSystemException("Could not commit ADO.NET transaction", e); + } + } + + /// + /// Perform an actual rollback on the given transaction. + /// + /// The status representation of the transaction. + /// + /// An implementation does not need to check the new transaction flag. + /// + /// + /// In the case of system errors. + /// + protected override void DoRollback(DefaultTransactionStatus status) + { + DbProviderTransactionObject txMgrStateObject = + (DbProviderTransactionObject) status.Transaction; + IDbConnection conn = txMgrStateObject.ConnectionHolder.Connection; + IDbTransaction trans = txMgrStateObject.ConnectionHolder.Transaction; + if (status.Debug) + { + log.LogDebug("Rolling back ADO.NET transaction on Connection [" + conn + ", " + conn.ConnectionString + "]"); } - /// - /// Gets the resource factory that this transaction manager operates on, - /// For the AdoPlatformTransactionManager this is the DbProvider - /// - /// The DbProvider. - public object ResourceFactory + try + { + trans.Rollback(); + } + catch (Exception e) + { + throw new TransactionSystemException("Could not rollback ADO.NET transaction", e); + } + } + + /// + /// Set the given transaction rollback-only. Only called on rollback + /// if the current transaction takes part in an existing one. + /// + /// The status representation of the transaction. + /// + /// In the case of system errors. + /// + protected override void DoSetRollbackOnly(DefaultTransactionStatus status) + { + DbProviderTransactionObject txMgrStateObject = + (DbProviderTransactionObject) status.Transaction; + if (status.Debug) + { + IDbConnection conn = txMgrStateObject.ConnectionHolder.Connection; + log.LogDebug("Setting ADO.NET transaction [" + conn + ", " + conn.ConnectionString + "] rollback-only."); + } + + txMgrStateObject.SetRollbackOnly(); + } + + protected override void DoCleanupAfterCompletion(object transaction) + { + DbProviderTransactionObject txMgrStateObject = + (DbProviderTransactionObject) transaction; + if (txMgrStateObject.NewConnectionHolder) + { + TransactionSynchronizationManager.UnbindResource(DbProvider); + } + + IDbConnection con = txMgrStateObject.ConnectionHolder.Connection; + + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug("Releasing ADO.NET Connection [" + con + ", " + con.ConnectionString + "] after transaction"); + } + + ConnectionUtils.DisposeConnection(con, DbProvider); + //TODO clear out IDbTransaction object? + + txMgrStateObject.ConnectionHolder.Clear(); + } + + /// + /// DbProvider transaction (state) object, representing a ConnectionHolder. + /// Used as a transaction object by AdoPlatformTransactionManager + /// + /// Derives from AdoTransactionObjectSupport to inherit the capability + /// to manage Savepoints. + /// + /// + private class DbProviderTransactionObject : AdoTransactionObjectSupport + { + private bool newConnectionHolder; + + public void SetConnectionHolder(ConnectionHolder connectionHolder, + bool newConnection) + { + ConnectionHolder = connectionHolder; + newConnectionHolder = newConnection; + } + + public bool NewConnectionHolder { get { - return dbProvider; + return newConnectionHolder; + } + } + + public bool HasTransaction + { + get + { + return (ConnectionHolder != null && ConnectionHolder.TransactionActive); + } + } + + /// + /// Sets the rollback only. + /// + public void SetRollbackOnly() + { + ConnectionHolder.RollbackOnly = true; + } + + /// + /// Return whether the transaction is internally marked as rollback-only. + /// + /// + /// True of the transaction is marked as rollback-only. + public override bool RollbackOnly + { + get + { + return ConnectionHolder.RollbackOnly; } } } + + /// + /// Invoked by an + /// after it has injected all of an object's dependencies. + /// + /// + /// If DbProvider is null. + /// + public void AfterPropertiesSet() + { + if (dbProvider == null) + { + throw new ArgumentException("DbProvider is required"); + } + } + + /// + /// Gets the resource factory that this transaction manager operates on, + /// For the AdoPlatformTransactionManager this is the DbProvider + /// + /// The DbProvider. + public object ResourceFactory + { + get + { + return dbProvider; + } + } } diff --git a/src/Spring/Spring.Data/Data/Core/AdoTemplate.cs b/src/Spring/Spring.Data/Data/Core/AdoTemplate.cs index d89b60b0..cba6f990 100644 --- a/src/Spring/Spring.Data/Data/Core/AdoTemplate.cs +++ b/src/Spring/Spring.Data/Data/Core/AdoTemplate.cs @@ -30,3019 +30,3005 @@ using Spring.Data.Support; using Spring.Reflection.Dynamic; using Spring.Util; -namespace Spring.Data.Core +namespace Spring.Data.Core; + +/// +/// This is the central class in the Spring.Data namespace. +/// It simplifies the use of ADO.NET and helps to avoid commons errors. +/// +/// Mark Pollack (.NET) +public class AdoTemplate : AdoAccessor, IAdoOperations { + #region Logging Definition + + private static readonly ILogger LOG = LogManager.GetLogger(); + + #endregion + + #region Fields + + private IDbProvider dbProvider; + + private IAdoExceptionTranslator exceptionTranslator; + + private bool lazyInit = true; + private Type dataReaderWrapperType; + protected IDynamicConstructor newDataReaderWrapper; + + #endregion + + #region Constructors + /// - /// This is the central class in the Spring.Data namespace. - /// It simplifies the use of ADO.NET and helps to avoid commons errors. + /// Initializes a new instance of the class. /// - /// Mark Pollack (.NET) - public class AdoTemplate : AdoAccessor, IAdoOperations + public AdoTemplate() + : base() { - #region Logging Definition + } - private static readonly ILogger LOG = LogManager.GetLogger(); + /// + /// Initializes a new instance of the class. + /// + /// The database provider. + public AdoTemplate(IDbProvider provider) + { + DbProvider = provider; + AfterPropertiesSet(); + } - #endregion + /// + /// Initializes a new instance of the class. + /// + /// The database provider. + /// if set to false + /// lazily initialize the ErrorCodeExceptionTranslator. + public AdoTemplate(IDbProvider provider, bool lazyInit) + { + DbProvider = provider; + LazyInit = lazyInit; + AfterPropertiesSet(); + } - #region Fields + #endregion - private IDbProvider dbProvider; + #region Properties - private IAdoExceptionTranslator exceptionTranslator; - - private bool lazyInit = true; - private Type dataReaderWrapperType; - protected IDynamicConstructor newDataReaderWrapper; - - #endregion - - #region Constructors - - /// - /// Initializes a new instance of the class. - /// - public AdoTemplate() - : base() + /// + /// An instance of a DbProvider implementation. + /// + public override IDbProvider DbProvider + { + get { return dbProvider; } + set { + dbProvider = value; } + } - /// - /// Initializes a new instance of the class. - /// - /// The database provider. - public AdoTemplate(IDbProvider provider) + /// + /// Gets or sets a value indicating whether to lazily initialize the + /// IAdoExceptionTranslator for this accessor, on first encounter of a + /// exception from the data provider. Default is "true"; can be switched to + /// "false" for initialization on startup. + /// + /// true if to lazy initialize the IAdoExceptionTranslator; + /// otherwise, false. + public override bool LazyInit + { + get { return lazyInit; } + set { lazyInit = value; } + } + + /// + /// Gets or sets the exception translator. If no custom translator is provided, a default + /// is used. + /// + /// The exception translator. + public override IAdoExceptionTranslator ExceptionTranslator + { + get { - DbProvider = provider; - AfterPropertiesSet(); + InitExceptionTranslator(); + return exceptionTranslator; } - - /// - /// Initializes a new instance of the class. - /// - /// The database provider. - /// if set to false - /// lazily initialize the ErrorCodeExceptionTranslator. - public AdoTemplate(IDbProvider provider, bool lazyInit) + set { - DbProvider = provider; - LazyInit = lazyInit; - AfterPropertiesSet(); + exceptionTranslator = value; } + } - #endregion - - #region Properties - - /// - /// An instance of a DbProvider implementation. - /// - public override IDbProvider DbProvider + /// + /// Gets or set the System.Type to use to create an instance of IDataReaderWrapper + /// for the purpose of having defaults values to use in case of DBNull values read + /// from IDataReader. + /// + /// The type of the data reader wrapper. + public override Type DataReaderWrapperType + { + get { return dataReaderWrapperType; } + set { - get { return dbProvider; } - set + if (dataReaderWrapperType == null) { - dbProvider = value; - } - } - - /// - /// Gets or sets a value indicating whether to lazily initialize the - /// IAdoExceptionTranslator for this accessor, on first encounter of a - /// exception from the data provider. Default is "true"; can be switched to - /// "false" for initialization on startup. - /// - /// true if to lazy initialize the IAdoExceptionTranslator; - /// otherwise, false. - public override bool LazyInit - { - get { return lazyInit; } - set { lazyInit = value; } - } - - /// - /// Gets or sets the exception translator. If no custom translator is provided, a default - /// is used. - /// - /// The exception translator. - public override IAdoExceptionTranslator ExceptionTranslator - { - get - { - InitExceptionTranslator(); - return exceptionTranslator; - } - set - { - exceptionTranslator = value; - } - } - - /// - /// Gets or set the System.Type to use to create an instance of IDataReaderWrapper - /// for the purpose of having defaults values to use in case of DBNull values read - /// from IDataReader. - /// - /// The type of the data reader wrapper. - public override Type DataReaderWrapperType - { - get { return dataReaderWrapperType; } - set - { - if (dataReaderWrapperType == null) + if (typeof(IDataReaderWrapper).IsAssignableFrom(value)) { - if (typeof(IDataReaderWrapper).IsAssignableFrom(value)) - { - dataReaderWrapperType = value; - ConstructorInfo constructor = ObjectUtils.GetZeroArgConstructorInfo(dataReaderWrapperType); - newDataReaderWrapper = DynamicConstructor.Create(constructor); - - } - else - { - throw new ArgumentException("DataReaderWrapper type must implement IDataReaderWrapper. Implemented interfaces on " - + value.GetType().Name + "are [" + - StringUtils.CollectionToCommaDelimitedString(ReflectionUtils.ToInterfaceArray(value)) + "]"); - - } + dataReaderWrapperType = value; + ConstructorInfo constructor = ObjectUtils.GetZeroArgConstructorInfo(dataReaderWrapperType); + newDataReaderWrapper = DynamicConstructor.Create(constructor); } else { - LOG.LogWarning("Ignoring assignment of DataReaderWrapperType since it has already been assigned."); + throw new ArgumentException("DataReaderWrapper type must implement IDataReaderWrapper. Implemented interfaces on " + + value.GetType().Name + "are [" + + StringUtils.CollectionToCommaDelimitedString(ReflectionUtils.ToInterfaceArray(value)) + "]"); } - - } - - } - - #endregion - - - public override void AfterPropertiesSet() - { - if (DbProvider == null) - { - throw new ArgumentException("DbProvider is required"); - } - if (!LazyInit) - { - InitExceptionTranslator(); - } - } - - - #region General Execute Callback Methods - /// - /// Execute a ADO.NET operation on a command object using a delegate callback. - /// - /// The delegate called with a command object. - /// - /// A result object returned by the action or null - /// - /// This allows for implementing arbitrary data access operations - /// on a single command within Spring's managed ADO.NET environment. - public virtual Object Execute(CommandDelegate del) - { - return Execute(new ExecuteCommandCallbackUsingDelegate(del)); - } - - /// - /// Callback to execute a IDbCommand. - /// - /// the callback to execute - /// object returned from callback - public virtual object Execute(ICommandCallback action) - { - ConnectionTxPair connectionTxPairToUse = GetConnectionTxPair(DbProvider); - - IDbCommand command = null; - try - { - command = DbProvider.CreateCommand(); - command.Connection = connectionTxPairToUse.Connection; - command.Transaction = connectionTxPairToUse.Transaction; - //TODO collect warnings... - //RegisterEventHandlers(command.Connection); - ApplyCommandSettings(command); - Object result = action.DoInCommand(command); - //SqlWarnings sqlWarnings = GetSqlWarnings() - //ThrowExceptionOnWarningIfNotIgnoringWarnings(sqlWarnings); - return result; - } - catch (Exception e) - { - DisposeCommand(command); - command = null; - DisposeConnection(connectionTxPairToUse.Connection, DbProvider); - connectionTxPairToUse.Connection = null; - if (DbProvider.IsDataAccessException(e)) - { - throw ExceptionTranslator.Translate("CommandCallback", GetCommandText(action), e); - } - else - { - throw; - } - - - } - finally - { - DisposeCommand(command); - DisposeConnection(connectionTxPairToUse.Connection, DbProvider); - } - - } - - /// - /// Executes ADO.NET operations on a command object, created by the provided IDbCommandCreator, - /// using the interface based callback IDbCommandCallback. - /// - /// The command creator. - /// The callback to execute based on IDbCommand - /// A result object returned by the action or null - public virtual object Execute(IDbCommandCreator commandCreator, ICommandCallback action) - { - AssertUtils.ArgumentNotNull(commandCreator, "commandCreator", "IDbCommandCreator must not be null"); - AssertUtils.ArgumentNotNull(action, "action", "Callback object must not be null"); - - ConnectionTxPair connectionTxPairToUse = GetConnectionTxPair(DbProvider); - - - IDbCommand command = null; - try - { - command = commandCreator.CreateDbCommand(DbProvider); - command.Connection = connectionTxPairToUse.Connection; - command.Transaction = connectionTxPairToUse.Transaction; - ApplyCommandSettings(command); - //TODO collect warnings... - //RegisterEventHandlers(command.Connection); - Object result = action.DoInCommand(command); - - //SqlWarnings sqlWarnings = GetSqlWarnings() - //ThrowExceptionOnWarningIfNotIgnoringWarnings(sqlWarnings); - - return result; - } - catch (Exception e) - { - commandCreator = null; - DisposeCommand(command); - command = null; - DisposeConnection(connectionTxPairToUse.Connection, DbProvider); - connectionTxPairToUse.Connection = null; - if (DbProvider.IsDataAccessException(e)) - { - throw ExceptionTranslator.Translate("CommandCallback", GetCommandText(action), e); - } - else - { - throw; - } - } - finally - { - DisposeCommand(command); - DisposeConnection(connectionTxPairToUse.Connection, DbProvider); - } - - } - - /// - /// Execute ADO.NET operations on a IDbDataAdapter object using an interface based callback. - /// - /// This allows for implementing abritrary data access operations - /// on a single DataAdapter within Spring's managed ADO.NET environment. - /// - /// The data adapter callback. - /// A result object returned by the callback or null - public virtual object Execute(IDataAdapterCallback dataAdapterCallback) - { - ConnectionTxPair connectionTxPairToUse = GetConnectionTxPair(DbProvider); - IDbDataAdapter dataAdapter = null; - try - { - dataAdapter = DbProvider.CreateDataAdapter(); - //TODO row updated event handling... - dataAdapter.SelectCommand = DbProvider.CreateCommand(); - dataAdapter.SelectCommand.Connection = connectionTxPairToUse.Connection; - //TODO register for warnings on connection. - dataAdapter.SelectCommand.Transaction = connectionTxPairToUse.Transaction; - ApplyCommandSettings(dataAdapter.SelectCommand); - object result = dataAdapterCallback.DoInDataAdapter(dataAdapter); - return result; - - } - catch (Exception) - { - DisposeDataAdapterCommands(dataAdapter); - //TODO set dataAdapter command's = null; ? - //TODO exception translation? different hierarchy for data set operations. - DisposeConnection(connectionTxPairToUse.Connection, DbProvider); - connectionTxPairToUse.Connection = null; - throw; - } - finally - { - DisposeDataAdapterCommands(dataAdapter); - DisposeConnection(connectionTxPairToUse.Connection, DbProvider); - } - - - } - - #endregion - - #region ExecuteNonQuery - - - /// - /// Executes a non query returning the number of rows affected. - /// - /// The command type. - /// The command text to execute. - /// The number of rows affected. - public virtual int ExecuteNonQuery(CommandType cmdType, string cmdText) - { - #region Instrumentation - if (LOG.IsEnabled(LogLevel.Debug)) - { - LOG.LogDebug("Executing NonQuery " + cmdType + "[" + cmdText + "]"); - } - #endregion - - return (int)Execute(new ExecuteNonQueryCallbackWithParameters(cmdType, cmdText, null)); - } - - /// - /// Executes a non query returning the number of rows affected. - /// - /// The command type. - /// The command text to execute. - /// The name of the parameter to map. - /// One of the database parameter type enumerations. - /// The length of the parameter. 0 if not applicable to parameter type. - /// The parameter value. - /// The number of rows affected. - public virtual int ExecuteNonQuery(CommandType cmdType, string cmdText, - string parameterName, Enum dbType, int size, object parameterValue) - { - return (int)Execute(new ExecuteNonQueryCallbackWithParameters(cmdType, cmdText, - CreateDbParameters(parameterName, dbType, size, parameterValue))); - - - } - - /// - /// Executes a non query returning the number of rows affected. - /// - /// The command type. - /// The command text to execute. - /// The parameter collection to map. - /// The number of rows affected. - public virtual int ExecuteNonQuery(CommandType cmdType, string cmdText, - IDbParameters parameters) - { - #region Instrumentation - if (LOG.IsEnabled(LogLevel.Debug)) - { - LOG.LogDebug("Executing NonQuery. " + cmdType + "[" + cmdText + "]"); - } - #endregion - - return (int)Execute(new ExecuteNonQueryCallbackWithParameters(cmdType, cmdText, parameters)); - - } - - /// - /// Executes a non query with parameters set via the - /// command setter, returning the number of rows affected. - /// - /// The command type. - /// The command text to execute. - /// The command setter. - /// The number of rows affected. - public virtual int ExecuteNonQuery(CommandType cmdType, string cmdText, - ICommandSetter commandSetter) - { - #region Instrumentation - if (LOG.IsEnabled(LogLevel.Debug)) - { - LOG.LogDebug("Executing NonQuery. " + cmdType + "[" + cmdText + "]"); - } - #endregion - - return (int)Execute(new ExecuteNonQueryCallbackWithCommandSetter(cmdType, cmdText, commandSetter)); - } - - - /// - /// Executes a non query with a command created via IDbCommandCreator and - /// parameters. - /// - /// Output parameters can be retrieved via the returned - /// dictionary. - /// - /// More commonly used as a lower level support method within the framework, - /// for example StoredProcedure/AdoScalar. - /// - /// - /// The callback to create a IDbCommand. - /// The number of rows affected. - public virtual IDictionary ExecuteNonQuery(IDbCommandCreator commandCreator) - { - - return (IDictionary)Execute(commandCreator, new AdoNonQueryWithOutputParamsCommandCallback()); - - } - - #endregion - - #region ExecuteScalar - - /// - /// Execute the query with the specified command text. - /// - /// No parameters are used. As with - /// IDbCommand.ExecuteScalar, it returns the first column of the first row in the resultset - /// returned by the query. Extra columns or row are ignored. - /// The command type - /// The command text to execute. - /// The first column of the first row in the result set - public virtual object ExecuteScalar(CommandType cmdType, string cmdText) - { - return Execute(new ExecuteScalarCallbackWithParameters(cmdType, cmdText, null)); - } - - /// - /// Execute the query with the specified command text and parameter returning a scalar result - /// - /// The command type - /// The command text to execute. - /// The name of the parameter to map. - /// One of the database parameter type enumerations. - /// The length of the parameter. 0 if not applicable to parameter type. - /// The parameter value. - /// The first column of the first row in the result set - public virtual object ExecuteScalar(CommandType cmdType, string cmdText, - string parameterName, Enum dbType, int size, object parameterValue) - { - return Execute(new ExecuteScalarCallbackWithParameters(cmdType, cmdText, - CreateDbParameters(parameterName, dbType, size, parameterValue))); - - } - - - /// - /// Execute the query with the specified command text and parameters returning a scalar result - /// - /// The command type - /// The command text to execute. - /// The parameter collection to map. - /// The first column of the first row in the result set - public virtual object ExecuteScalar(CommandType cmdType, string cmdText, - IDbParameters parameters) - { - return Execute(new ExecuteScalarCallbackWithParameters(cmdType, cmdText, parameters)); - - } - - /// - /// Execute the query with the specified command text and parameters set via the - /// command setter, returning a scalar result - /// - /// The command type - /// The command text to execute. - /// The command setter. - /// The first column of the first row in the result set - public virtual object ExecuteScalar(CommandType cmdType, string cmdText, - ICommandSetter commandSetter) - { - #region Instrumentation - if (LOG.IsEnabled(LogLevel.Debug)) - { - LOG.LogDebug("Executing ExecuteScalar. " + cmdType + "[" + cmdText + "]"); - } - #endregion - - return Execute(new ExecuteScalarCallbackWithCommandSetter(cmdType, cmdText, commandSetter)); - - } - - /// - /// Execute the query with a command created via IDbCommandCreator and - /// parameters - /// - /// Output parameters can be retrieved via the returned - /// dictionary. - /// - /// More commonly used as a lower level support method within the framework, - /// for example for StoredProcedure/AdoScalar. - /// - /// The callback to create a IDbCommand. - /// A dictionary containing output parameters, if any - public virtual IDictionary ExecuteScalar(IDbCommandCreator commandCreator) - { - return (IDictionary)Execute(commandCreator, new AdoStoredProcedureScalarCommandCallback()); - } - - #endregion - - #region Query with RowCallback - - /// - /// Execute a query given IDbCommand's type and text, reading a - /// single result set on a per-row basis with a . - /// - /// The type of command - /// The text of the query. - /// callback that will extract results - /// one row at a time. - /// - public virtual void QueryWithRowCallback(CommandType cmdType, string cmdText, IRowCallback rowCallback) - { - QueryWithResultSetExtractor(cmdType, cmdText, new RowCallbackResultSetExtractor(rowCallback)); - } - - /// - /// Execute a query given IDbCommand's type and text by - /// passing the created IDbCommand to a ICommandSetter implementation - /// that knows how to bind values to the IDbCommand, reading a - /// single result set on a per-row basis with a . - /// - /// The type of command - /// The text of the query. - /// callback that will extract results - /// one row at a time. - /// - /// The command setter. - public virtual void QueryWithRowCallback(CommandType cmdType, string cmdText, IRowCallback rowCallback, - ICommandSetter commandSetter) - { - QueryWithResultSetExtractor(cmdType, cmdText, new RowCallbackResultSetExtractor(rowCallback), commandSetter); - - } - - /// - /// Execute a query given IDbCommand's type and text and provided parameter - /// information, reading a - /// single result set on a per-row basis with a . - /// - /// The type of command - /// The text of the query. - /// callback that will extract results - /// one row at a time. - /// - /// The name of the parameter to map. - /// One of the database parameter type enumerations. - /// The length of the parameter. 0 if not applicable to parameter type. - /// The parameter value. - public virtual void QueryWithRowCallback(CommandType cmdType, string cmdText, IRowCallback rowCallback, - string parameterName, Enum dbType, int size, object parameterValue) - { - QueryWithResultSetExtractor(cmdType, cmdText, new RowCallbackResultSetExtractor(rowCallback), parameterName, dbType, size, parameterValue); - } - - - public virtual void QueryWithRowCallback(CommandType cmdType, string cmdText, IRowCallback rowCallback, IDbParameters parameters) - { - QueryWithResultSetExtractor(cmdType, cmdText, new RowCallbackResultSetExtractor(rowCallback), parameters); - } - - #endregion - - // RowCallback with Delegate Questionable for 1.1 since no anonymous delegates and there isn't a collecting parameter - // in the delegate method signature. - - #region Query with RowCallback Delegate - - public virtual void QueryWithRowCallbackDelegate(CommandType cmdType, string sql, RowCallbackDelegate rowCallbackDelegate) - { - QueryWithResultSetExtractor(cmdType, sql, new RowCallbackResultSetExtractor(rowCallbackDelegate)); - - } - public virtual void QueryWithRowCallbackDelegate(CommandType cmdType, string sql, RowCallbackDelegate rowCallbackDelegate, ICommandSetter commandSetter) - { - QueryWithResultSetExtractor(cmdType, sql, new RowCallbackResultSetExtractor(rowCallbackDelegate), commandSetter); - - } - - public virtual void QueryWithRowCallbackDelegate(CommandType cmdType, string sql, RowCallbackDelegate rowCallbackDelegate, - string name, Enum dbType, int size, object parameterValue) - { - QueryWithResultSetExtractor(cmdType, sql, new RowCallbackResultSetExtractor(rowCallbackDelegate), name, dbType, size, parameterValue); - - } - - public virtual void QueryWithRowCallbackDelegate(CommandType cmdType, string sql, RowCallbackDelegate rowCallbackDelegate, IDbParameters parameters) - { - QueryWithResultSetExtractor(cmdType, sql, new RowCallbackResultSetExtractor(rowCallbackDelegate), parameters); - - } - - - - #endregion - - #region Query with RowMapper - - public virtual IList QueryWithRowMapper(CommandType cmdType, string cmdText, IRowMapper rowMapper) - { - return (IList)QueryWithResultSetExtractor(cmdType, cmdText, new RowMapperResultSetExtractor(rowMapper)); - } - - public virtual IList QueryWithRowMapper(CommandType cmdType, string cmdText, IRowMapper rowMapper, ICommandSetter commandSetter) - { - - return (IList)QueryWithResultSetExtractor(cmdType, cmdText, - new RowMapperResultSetExtractor(rowMapper), commandSetter); - - } - - - public virtual IList QueryWithRowMapper(CommandType cmdType, string cmdText, IRowMapper rowMapper, - string name, Enum dbType, int size, object parameterValue) - { - return (IList)QueryWithResultSetExtractor(cmdType, cmdText, new RowMapperResultSetExtractor(rowMapper), name, dbType, size, parameterValue); - } - - - public virtual IList QueryWithRowMapper(CommandType cmdType, string cmdText, IRowMapper rowMapper, IDbParameters parameters) - { - return (IList)QueryWithResultSetExtractor(cmdType, cmdText, new RowMapperResultSetExtractor(rowMapper), parameters); - } - - - #endregion - - #region Query With RowMapper Delegate - - public virtual IList QueryWithRowMapperDelegate(CommandType cmdType, string cmdText, RowMapperDelegate rowMapperDelegate) - { - return (IList)QueryWithResultSetExtractor(cmdType, cmdText, new RowMapperResultSetExtractor(rowMapperDelegate)); - } - - public virtual IList QueryWithRowMapperDelegate(CommandType cmdType, string cmdText, RowMapperDelegate rowMapperDelegate, ICommandSetter commandSetter) - { - return (IList)QueryWithResultSetExtractor(cmdType, cmdText, new RowMapperResultSetExtractor(rowMapperDelegate), commandSetter); - } - - - public virtual IList QueryWithRowMapperDelegate(CommandType cmdType, string cmdText, RowMapperDelegate rowMapperDelegate, - string parameterName, Enum dbType, int size, object parameterValue) - { - return (IList)QueryWithResultSetExtractor(cmdType, cmdText, new RowMapperResultSetExtractor(rowMapperDelegate), parameterName, dbType, size, parameterValue); - } - - - public virtual IList QueryWithRowMapperDelegate(CommandType cmdType, string cmdText, RowMapperDelegate rowMapperDelegate, - IDbParameters parameters) - { - return (IList)QueryWithResultSetExtractor(cmdType, cmdText, new RowMapperResultSetExtractor(rowMapperDelegate), parameters); - } - - #endregion - - #region Query with ResultSetExtractor - - /// - /// Execute a query given static SQL/Stored Procedure name - /// and process a single result set with an instance of IResultSetExtractor - /// - /// The type of command. - /// The SQL/Stored Procedure to execute - /// Object that will extract all rows of a result set - /// An arbitrary result object, as returned by the IResultSetExtractor - public virtual object QueryWithResultSetExtractor(CommandType cmdType, string sql, IResultSetExtractor rse) - { - AssertUtils.ArgumentNotNull(sql, "sql", "SQL must not be null"); - - //TODO check for parameter placeholders... - - if (LOG.IsEnabled(LogLevel.Debug)) - { - LOG.LogDebug("Executing SQL [" + sql + "]"); - } - - return Execute(new QueryCallback(this, cmdType, sql, rse, null)); - - } - - public virtual object QueryWithResultSetExtractor(CommandType cmdType, string cmdText, IResultSetExtractor resultSetExtractor, ICommandSetter commandSetter) - { - AssertUtils.ArgumentNotNull(resultSetExtractor, "resultSetExtractor", "Result Set Extractor must not be null"); - return Execute(new QueryCallbackWithCommandSetter(this, cmdType, cmdText, - resultSetExtractor, commandSetter)); - } - - - public virtual object QueryWithResultSetExtractor(CommandType cmdType, string cmdText, IResultSetExtractor resultSetExtractor, - string name, Enum dbType, int size, object parameterValue) - { - AssertUtils.ArgumentNotNull(resultSetExtractor, "resultSetExtractor", "Result Set Extractor must not be null"); - return Execute(new QueryCallback(this, cmdType, cmdText, resultSetExtractor, CreateDbParameters(name, dbType, size, parameterValue))); - } - - public virtual object QueryWithResultSetExtractor(CommandType cmdType, string cmdText, IResultSetExtractor resultSetExtractor, - IDbParameters parameters) - { - AssertUtils.ArgumentNotNull(resultSetExtractor, "resultSetExtractor", "Result Set Extractor must not be null"); - return Execute(new QueryCallback(this, cmdType, cmdText, resultSetExtractor, parameters)); - } - - - #endregion - - - #region Query with ResultSetExtractorDelegate - - /// - /// Execute a query given static SQL/Stored Procedure name - /// and process a single result set with an instance of IResultSetExtractor - /// - /// The type of command. - /// The SQL/Stored Procedure to execute - /// Delegate that will extract all rows of a result set - /// An arbitrary result object, as returned by the IResultSetExtractor - public virtual object QueryWithResultSetExtractorDelegate(CommandType cmdType, string sql, ResultSetExtractorDelegate resultSetExtractorDelegate) - { - AssertUtils.ArgumentNotNull(sql, "sql", "SQL must not be null"); - - //TODO check for parameter placeholders... - - if (LOG.IsEnabled(LogLevel.Debug)) - { - LOG.LogDebug("Executing SQL [" + sql + "]"); - } - - return Execute(new QueryCallback(this, cmdType, sql, resultSetExtractorDelegate, null)); - - } - - public virtual object QueryWithResultSetExtractorDelegate(CommandType cmdType, string cmdText, ResultSetExtractorDelegate resultSetExtractorDelegate, - ICommandSetter commandSetter) - { - AssertUtils.ArgumentNotNull(resultSetExtractorDelegate, "resultSetExtractorDelegate", "Result set extractor delegate must not be null"); - return Execute(new QueryCallbackWithCommandSetter(this, cmdType, cmdText, - resultSetExtractorDelegate, commandSetter)); - } - - - public virtual object QueryWithResultSetExtractorDelegate(CommandType cmdType, string cmdText, ResultSetExtractorDelegate resultSetExtractorDelegate, - string name, Enum dbType, int size, object parameterValue) - { - AssertUtils.ArgumentNotNull(resultSetExtractorDelegate, "resultSetExtractorDelegate", "Result set extractor delegate must not be null"); - return Execute(new QueryCallback(this, cmdType, cmdText, resultSetExtractorDelegate, CreateDbParameters(name, dbType, size, parameterValue))); - } - - public virtual object QueryWithResultSetExtractorDelegate(CommandType cmdType, string cmdText, ResultSetExtractorDelegate resultSetExtractorDelegate, - IDbParameters parameters) - { - AssertUtils.ArgumentNotNull(resultSetExtractorDelegate, "resultSetExtractorDelegate", "Result set extractor delegate must not be null"); - return Execute(new QueryCallback(this, cmdType, cmdText, resultSetExtractorDelegate, parameters)); - } - - - #endregion - - #region Query for Object - - /// - /// Execute a query with the specified command text, mapping a single result - /// row to an object via a RowMapper. - /// - /// The command type. - /// The command text to execute. - /// object that will map one object per row - /// The single mapped object. - /// - /// If the query does not return exactly one row. - /// - /// - /// If there is any problem executing the query. - /// - public virtual object QueryForObject(CommandType cmdType, string cmdText, IRowMapper rowMapper) - { - IList results = QueryWithRowMapper(cmdType, cmdText, rowMapper); - return DataAccessUtils.RequiredUniqueResultSet(results); - } - - /// - /// Execute a query with the specified command text and parameters set via the - /// command setter, mapping a single result row to an object via a RowMapper. - /// - /// The command type. - /// The command text to execute. - /// object that will map one object per row - /// The command setter. - /// The single mapped object. - /// - /// If the query does not return exactly one row. - /// - /// - /// If there is any problem executing the query. - /// - public virtual object QueryForObject(CommandType cmdType, string cmdText, IRowMapper rowMapper, ICommandSetter commandSetter) - { - IList results = QueryWithRowMapper(cmdType, cmdText, rowMapper, commandSetter); - return DataAccessUtils.RequiredUniqueResultSet(results); - } - - /// - /// Execute a query with the specified command text and parameters, mapping a single result row - /// to an object via a RowMapper. - /// - /// The command type. - /// The command text to execute. - /// object that will map one object per row - /// The parameter collection to use in the query. - /// The single mapped object. - /// - /// If the query does not return exactly one row. - /// - /// - /// If there is any problem executing the query. - /// - public virtual object QueryForObject(CommandType cmdType, string cmdText, IRowMapper rowMapper, IDbParameters parameters) - { - IList results = QueryWithRowMapper(cmdType, cmdText, rowMapper, parameters); - return DataAccessUtils.RequiredUniqueResultSet(results); - } - - /// - /// Execute a query with the specified command text and parameter, mapping a single result row - /// to an object via a RowMapper. - /// - /// The command type. - /// The command text to execute. - /// object that will map one object per row - /// The name of the parameter to map. - /// One of the database parameter type enumerations. - /// The length of the parameter. 0 if not applicable to parameter type. - /// The parameter value. - /// The single mapped object. - /// - /// If the query does not return exactly one row. - /// - /// - /// If there is any problem executing the query. - /// - public virtual object QueryForObject(CommandType cmdType, string cmdText, IRowMapper rowMapper, string parameterName, Enum dbType, int size, - object parameterValue) - { - IList results = QueryWithRowMapper(cmdType, cmdText, rowMapper, parameterName, dbType, size, parameterValue); - return DataAccessUtils.RequiredUniqueResultSet(results); - } - - #endregion - - #region Query for ObjectDelegate - - /// - /// Execute a query with the specified command text, mapping a single result - /// row to an object via a RowMapper. - /// - /// The command type. - /// The command text to execute. - /// delegate that will map one object per row - /// The single mapped object. - /// - /// If the query does not return exactly one row. - /// - /// - /// If there is any problem executing the query. - /// - public virtual object QueryForObjectDelegate(CommandType cmdType, string cmdText, RowMapperDelegate rowMapperDelegate) - { - IList results = QueryWithRowMapperDelegate(cmdType, cmdText, rowMapperDelegate); - return DataAccessUtils.RequiredUniqueResultSet(results); - } - - - /// - /// Execute a query with the specified command text and parameters set via the - /// command setter, mapping a single result row to an object via a RowMapper. - /// - /// The command type. - /// The command text to execute. - /// delegate that will map one object per row - /// The command setter. - /// The single mapped object. - /// - /// If the query does not return exactly one row. - /// - /// - /// If there is any problem executing the query. - /// - public virtual object QueryForObjectDelegate(CommandType cmdType, string cmdText, RowMapperDelegate rowMapperDelegate, ICommandSetter commandSetter) - { - IList results = QueryWithRowMapperDelegate(cmdType, cmdText, rowMapperDelegate, commandSetter); - return DataAccessUtils.RequiredUniqueResultSet(results); - } - - /// - /// Execute a query with the specified command text and parameters, mapping a single result row - /// to an object via a RowMapper. - /// - /// The command type. - /// The command text to execute. - /// delegate that will map one object per row - /// The parameter collection to use in the query. - /// The single mapped object. - /// - /// If the query does not return exactly one row. - /// - /// - /// If there is any problem executing the query. - /// - public virtual object QueryForObjectDelegate(CommandType cmdType, string cmdText, RowMapperDelegate rowMapperDelegate, IDbParameters parameters) - { - IList results = QueryWithRowMapperDelegate(cmdType, cmdText, rowMapperDelegate, parameters); - return DataAccessUtils.RequiredUniqueResultSet(results); - } - - /// - /// Execute a query with the specified command text and parameter, mapping a single result row - /// to an object via a RowMapper. - /// - /// The command type. - /// The command text to execute. - /// delegate that will map one object per row - /// The name of the parameter to map. - /// One of the database parameter type enumerations. - /// The length of the parameter. 0 if not applicable to parameter type. - /// The parameter value. - /// The single mapped object. - /// - /// If the query does not return exactly one row. - /// - /// - /// If there is any problem executing the query. - /// - public virtual object QueryForObjectDelegate(CommandType cmdType, string cmdText, RowMapperDelegate rowMapperDelegate, string parameterName, Enum dbType, int size, - object parameterValue) - { - IList results = QueryWithRowMapperDelegate(cmdType, cmdText, rowMapperDelegate, parameterName, dbType, size, parameterValue); - return DataAccessUtils.RequiredUniqueResultSet(results); - } - - #endregion - - #region Query with CommandCreator - - public virtual object QueryWithCommandCreator(IDbCommandCreator cc, IResultSetExtractor rse) - { - return QueryWithCommandCreator(cc, rse, null); - } - - public virtual void QueryWithCommandCreator(IDbCommandCreator cc, IRowCallback rowCallback) - { - QueryWithCommandCreator(cc, rowCallback, null); - } - - public virtual IList QueryWithCommandCreator(IDbCommandCreator cc, IRowMapper rowMapper) - { - return QueryWithCommandCreator(cc, rowMapper, null); - } - - public virtual object QueryWithCommandCreator(IDbCommandCreator cc, IResultSetExtractor rse, IDictionary returnedParameters) - { - if (rse == null) - { - throw new ArgumentNullException("Result Set Extractor must not be null"); - } - - return Execute(cc, new AdoResultSetExtractorWithOutputParamsCommandCallback(this, rse, returnedParameters)); - } - - public virtual void QueryWithCommandCreator(IDbCommandCreator cc, IRowCallback rowCallback, IDictionary returnedParameters) - { - if (rowCallback == null) - { - throw new ArgumentNullException("RowCallback must not be null"); - } - Execute(cc, new AdoRowCallbackCommandCallback(this, rowCallback, returnedParameters)); - } - - public virtual IList QueryWithCommandCreator(IDbCommandCreator cc, IRowMapper rowMapper, IDictionary returnedParameters) - { - if (rowMapper == null) - { - throw new ArgumentNullException("rowMapper must not be null"); - } - - return (IList)Execute(cc, new AdoRowMapperQueryCommandCallback(this, rowMapper, returnedParameters)); - } - - - - - public IDictionary QueryWithCommandCreator(IDbCommandCreator cc, IList namedResultSetProcessors) - { - return (IDictionary)Execute(cc, new AdoResultProcessorsQueryCommandCallback(this, namedResultSetProcessors)); - } - - #endregion - - // DataSet/DataTable related methods. - - #region DataTable Create operations without parameters - - public virtual DataTable DataTableCreate(CommandType commandType, string sql) - { - DataTable dataTable = CreateDataTable(); - DataTableFill(dataTable, commandType, sql); - return dataTable; - } - - public virtual DataTable DataTableCreate(CommandType commandType, string sql, - string tableMappingName) - { - DataTable dataTable = CreateDataTable(); - DataTableFill(dataTable, commandType, sql, tableMappingName); - return dataTable; - } - - public virtual DataTable DataTableCreate(CommandType commandType, string sql, - ITableMapping tableMapping) - { - DataTable dataTable = CreateDataTable(); - DataTableFill(dataTable, commandType, sql, tableMapping); - return dataTable; - } - - public virtual DataTable DataTableCreate(CommandType commandType, string sql, - ITableMapping tableMapping, - IDataAdapterSetter setter) - { - DataTable dataTable = CreateDataTable(); - DataTableFill(dataTable, commandType, sql, tableMapping, setter); - return dataTable; - } - - #endregion - - #region DataTable Create operations with parameters - - public virtual DataTable DataTableCreateWithParams(CommandType commandType, string sql, - IDbParameters parameters) - { - DataTable dataTable = CreateDataTable(); - DataTableFillWithParams(dataTable, commandType, sql, parameters); - return dataTable; - } - - public virtual DataTable DataTableCreateWithParams(CommandType commandType, string sql, - IDbParameters parameters, - string tableMappingName) - { - DataTable dataTable = CreateDataTable(); - DataTableFillWithParams(dataTable, commandType, sql, parameters, tableMappingName); - return dataTable; - } - - public virtual DataTable DataTableCreateWithParams(CommandType commandType, string sql, - IDbParameters parameters, - ITableMapping tableMapping) - { - DataTable dataTable = CreateDataTable(); - DataTableFillWithParams(dataTable, commandType, sql, parameters, tableMapping); - return dataTable; - } - - public virtual DataTable DataTableCreateWithParams(CommandType commandType, string sql, - IDbParameters parameters, - ITableMapping tableMapping, - IDataAdapterSetter dataAdapterSetter) - { - DataTable dataTable = CreateDataTable(); - DataTableFillWithParams(dataTable, commandType, sql, parameters, tableMapping, dataAdapterSetter); - return dataTable; - } - - - #endregion - - #region DataTable Fill operations without parameters - /// - /// Fill a based on a select command that requires no parameters. - /// - /// The to populate - /// The type of command - /// SQL query to execute - /// The number of rows successfully added to or refreshed in the - public virtual int DataTableFill(DataTable dataTable, CommandType commandType, string sql) - { - ValidateFillArguments(dataTable, sql); - - #region Instrumentation - if (LOG.IsEnabled(LogLevel.Debug)) - { - LOG.LogDebug("Executing DataTableFill " + commandType + "[" + sql + "]"); - } - #endregion - - ITableMappingCollection mappingCollection = DoCreateMappingCollection(null); - return (int)Execute(new DataAdapterFillCallback(dataTable, - commandType, sql, - mappingCollection, null, null, null)); - } - - public virtual int DataTableFill(DataTable dataTable, CommandType commandType, string sql, - string tableMappingName) - { - ValidateFillArguments(dataTable, sql); - - #region Instrumentation - if (LOG.IsEnabled(LogLevel.Debug)) - { - LOG.LogDebug("Executing DataTableFill " + commandType + "[" + sql + "] with table mapping name " + tableMappingName); - } - #endregion - - if (tableMappingName == null) - { - tableMappingName = "Table"; - } - ITableMappingCollection mappingCollection = DoCreateMappingCollection(new string[] { tableMappingName }); - return (int)Execute(new DataAdapterFillCallback(dataTable, - commandType, sql, - mappingCollection, null, null, null)); - - } - - public virtual int DataTableFill(DataTable dataTable, CommandType commandType, string sql, - ITableMapping tableMapping) - { - ValidateFillArguments(dataTable, sql, tableMapping); - ITableMappingCollection mappingCollection = new DataTableMappingCollection(); - mappingCollection.Add((object)tableMapping); - - return (int)Execute(new DataAdapterFillCallback(dataTable, - commandType, sql, - mappingCollection, null, null, null)); - } - - public virtual int DataTableFill(DataTable dataTable, CommandType commandType, string sql, - ITableMapping tableMapping, - IDataAdapterSetter setter) - { - ValidateFillArguments(dataTable, sql, tableMapping); - ITableMappingCollection mappingCollection = new DataTableMappingCollection(); - mappingCollection.Add((object)tableMapping); - return (int)Execute(new DataAdapterFillCallback(dataTable, - commandType, sql, - mappingCollection, setter, null, null)); - } - - - #endregion - - #region DataTable Fill operations with parameters - - public virtual int DataTableFillWithParams(DataTable dataTable, CommandType commandType, string sql, - IDbParameters parameters) - { - ValidateFillWithParameterArguments(dataTable, sql, parameters); - ITableMappingCollection mappingCollection = DoCreateMappingCollection(null); - return (int)Execute(new DataAdapterFillCallback(dataTable, - commandType, sql, - mappingCollection, null, null, - parameters)); - } - - public virtual int DataTableFillWithParams(DataTable dataTable, CommandType commandType, string sql, - IDbParameters parameters, - string tableMappingName) - { - ValidateFillWithParameterArguments(dataTable, sql, parameters); - if (tableMappingName == null) - { - tableMappingName = "Table"; - } - ITableMappingCollection mappingCollection = DoCreateMappingCollection(new string[] { tableMappingName }); - return (int)Execute(new DataAdapterFillCallback(dataTable, - commandType, sql, - mappingCollection, null, null, parameters)); - } - - public virtual int DataTableFillWithParams(DataTable dataTable, CommandType commandType, string sql, - IDbParameters parameters, - ITableMapping tableMapping) - { - ValidateFillWithParameterArguments(dataTable, sql, parameters, tableMapping); - ITableMappingCollection mappingCollection = new DataTableMappingCollection(); - mappingCollection.Add((object)tableMapping); - return (int)Execute(new DataAdapterFillCallback(dataTable, - commandType, sql, - mappingCollection, null, null, parameters)); - } - - public virtual int DataTableFillWithParams(DataTable dataTable, CommandType commandType, string sql, - IDbParameters parameters, - ITableMapping tableMapping, - IDataAdapterSetter dataAdapterSetter) - { - ValidateFillWithParameterArguments(dataTable, sql, parameters, tableMapping); - ITableMappingCollection mappingCollection = new DataTableMappingCollection(); - mappingCollection.Add((object)tableMapping); - return (int)Execute(new DataAdapterFillCallback(dataTable, - commandType, sql, - mappingCollection, dataAdapterSetter, null, parameters)); - } - - - #endregion - - #region DataTable Update operations - //TODO conflict options... - - public virtual int DataTableUpdateWithCommandBuilder(DataTable dataTable, - CommandType commandType, - string selectSql, - IDbParameters parameters, - string tableName) - { - ValidateUpdateWithCommandBuilderArguments(dataTable, tableName, selectSql); - ITableMappingCollection mappingCollection = DoCreateMappingCollection(new string[] { tableName }); - return (int)Execute(new DataAdapterUpdateWithCommandBuilderCallback(dataTable, - DbProvider.CreateCommandBuilder(), - mappingCollection, - commandType, - selectSql, - parameters, - null)); - } - - public virtual int DataTableUpdateWithCommandBuilder(DataTable dataTable, - CommandType commandType, - string selectSql, - IDbParameters parameters, - string tableName, - IDataAdapterSetter dataAdapterSetter) - { - ValidateUpdateWithCommandBuilderArguments(dataTable, tableName, selectSql); - ITableMappingCollection mappingCollection = DoCreateMappingCollection(new string[] { tableName }); - return (int)Execute(new DataAdapterUpdateWithCommandBuilderCallback(dataTable, - DbProvider.CreateCommandBuilder(), - mappingCollection, - commandType, - selectSql, - parameters, - dataAdapterSetter)); - } - - - public virtual int DataTableUpdateWithCommandBuilder(DataTable dataTable, - CommandType commandType, - string selectSql, - IDbParameters parameters, - ITableMapping tableMapping, - IDataAdapterSetter dataAdapterSetter) - { - ValidateUpdateWithCommandBuilderArguments(dataTable, tableMapping, selectSql); - ITableMappingCollection mappingCollection = new DataTableMappingCollection(); - mappingCollection.Add(tableMapping); - return (int)Execute(new DataAdapterUpdateWithCommandBuilderCallback(dataTable, - DbProvider.CreateCommandBuilder(), - mappingCollection, - commandType, - selectSql, - parameters, - dataAdapterSetter)); - } - - - - public virtual int DataTableUpdate(DataTable dataTable, - string tableName, - CommandType insertCommandtype, string insertSql, IDbParameters insertParameters, - CommandType updateCommandtype, string updateSql, IDbParameters updateParameters, - CommandType deleteCommandtype, string deleteSql, IDbParameters deleteParameters) - { - ValidateUpdateArguments(dataTable, tableName); - ITableMappingCollection mappingCollection = DoCreateMappingCollection(new string[] { tableName }); - return DataTableUpdate(dataTable, mappingCollection, - insertCommandtype, insertSql, insertParameters, - updateCommandtype, updateSql, updateParameters, - deleteCommandtype, deleteSql, deleteParameters, - null); - - } - - public virtual int DataTableUpdate(DataTable dataTable, - string tableName, - CommandType insertCommandtype, string insertSql, IDbParameters insertParameters, - CommandType updateCommandtype, string updateSql, IDbParameters updateParameters, - CommandType deleteCommandtype, string deleteSql, IDbParameters deleteParameters, - IDataAdapterSetter dataAdapterSetter) - { - ValidateUpdateArguments(dataTable, tableName); - ITableMappingCollection mappingCollection = DoCreateMappingCollection(new string[] { tableName }); - return DataTableUpdate(dataTable, mappingCollection, - insertCommandtype, insertSql, insertParameters, - updateCommandtype, updateSql, updateParameters, - deleteCommandtype, deleteSql, deleteParameters, - dataAdapterSetter); - } - - public virtual int DataTableUpdate(DataTable dataTable, - ITableMapping tableMapping, - CommandType insertCommandtype, string insertSql, IDbParameters insertParameters, - CommandType updateCommandtype, string updateSql, IDbParameters updateParameters, - CommandType deleteCommandtype, string deleteSql, IDbParameters deleteParameters, - IDataAdapterSetter dataAdapterSetter) - { - ValidateUpdateArguments(dataTable, tableMapping); - ITableMappingCollection mappingCollection = new DataTableMappingCollection(); - - mappingCollection.Add((object)tableMapping); - - return DataTableUpdate(dataTable, mappingCollection, - insertCommandtype, insertSql, insertParameters, - updateCommandtype, updateSql, updateParameters, - deleteCommandtype, deleteSql, deleteParameters, - dataAdapterSetter); - - - } - - - - #endregion - - #region DataSet Create operations without parameters - - public virtual DataSet DataSetCreate(CommandType commandType, string sql) - { - DataSet dataSet = CreateDataSet(); - DataSetFill(dataSet, commandType, sql); - return dataSet; - } - - - public virtual DataSet DataSetCreate(CommandType commandType, string sql, - string[] tableNames) - { - DataSet dataSet = CreateDataSet(); - DataSetFill(dataSet, commandType, sql, tableNames); - return dataSet; - } - - public virtual DataSet DataSetCreate(CommandType commandType, string sql, - ITableMappingCollection tableMapping) - { - DataSet dataSet = CreateDataSet(); - DataSetFill(dataSet, commandType, sql, tableMapping); - return dataSet; - } - - public virtual DataSet DataSetCreate(CommandType commandType, string sql, - ITableMappingCollection tableMapping, - IDataAdapterSetter setter) - { - DataSet dataSet = CreateDataSet(); - DataSetFill(dataSet, commandType, sql, tableMapping, setter); - return dataSet; - } - - public virtual DataSet DataSetCreate(CommandType commandType, string sql, - ITableMappingCollection tableMapping, - IDataAdapterSetter setter, - IDataSetFillLifecycleProcessor fillLifecycleProcessor) - { - DataSet dataSet = CreateDataSet(); - DataSetFill(dataSet, commandType, sql, tableMapping, setter, fillLifecycleProcessor); - return dataSet; - } - #endregion - - #region DataSet Create operations with parameters - - public virtual DataSet DataSetCreateWithParams(CommandType commandType, string sql, - IDbParameters parameters) - { - DataSet dataSet = CreateDataSet(); - DataSetFillWithParameters(dataSet, commandType, sql, parameters); - return dataSet; - } - - public virtual DataSet DataSetCreateWithParams(CommandType commandType, string sql, - IDbParameters parameters, - string[] tableNames) - { - DataSet dataSet = CreateDataSet(); - DataSetFillWithParameters(dataSet, commandType, sql, parameters, tableNames); - return dataSet; - } - - public virtual DataSet DataSetCreateWithParams(CommandType commandType, string sql, - IDbParameters parameters, - ITableMappingCollection tableMapping) - { - DataSet dataSet = CreateDataSet(); - DataSetFillWithParameters(dataSet, commandType, sql, parameters, tableMapping); - return dataSet; - } - - public virtual DataSet DataSetCreateWithParams(CommandType commandType, string sql, - IDbParameters parameters, - ITableMappingCollection tableMapping, - IDataAdapterSetter dataAdapterSetter) - { - DataSet dataSet = CreateDataSet(); - DataSetFillWithParameters(dataSet, commandType, sql, parameters, tableMapping, dataAdapterSetter); - return dataSet; - } - - public virtual DataSet DataSetCreateWithParams(CommandType commandType, string sql, - IDbParameters parameters, - ITableMappingCollection tableMapping, - IDataAdapterSetter dataAdapterSetter, - IDataSetFillLifecycleProcessor fillLifecycleProcessor) - { - DataSet dataSet = CreateDataSet(); - DataSetFillWithParameters(dataSet, commandType, sql, parameters, tableMapping, dataAdapterSetter, fillLifecycleProcessor); - return dataSet; - } - - #endregion - - #region DataSet Fill operations without parameters - - public virtual int DataSetFill(DataSet dataSet, CommandType commandType, string sql) - { - ValidateFillArguments(dataSet, sql); - - #region Instrumentation - if (LOG.IsEnabled(LogLevel.Debug)) - { - LOG.LogDebug("Executing DataSetFill " + commandType + "[" + sql + "]"); - } - #endregion - - - ITableMappingCollection mappingCollection = DoCreateMappingCollection(null); - return (int)Execute(new DataAdapterFillCallback(dataSet, - commandType, sql, - mappingCollection, null, null, null)); - } - - - - public virtual int DataSetFill(DataSet dataSet, CommandType commandType, string sql, string[] tableNames) - { - ValidateFillArguments(dataSet, sql); - - #region Instrumentation - if (LOG.IsEnabled(LogLevel.Debug)) - { - LOG.LogDebug("Executing DataSetFill " + commandType + "[" + sql + "] with table names " + tableNames); - } - #endregion - - if (tableNames == null) - { - tableNames = new string[] { "Table" }; - } - ITableMappingCollection mappingCollection = DoCreateMappingCollection(tableNames); - return (int)Execute(new DataAdapterFillCallback(dataSet, - commandType, sql, - mappingCollection, null, null, null)); - } - - - public virtual int DataSetFill(DataSet dataSet, CommandType commandType, string sql, - ITableMappingCollection tableMapping) - { - ValidateFillArguments(dataSet, sql, tableMapping); - return (int)Execute(new DataAdapterFillCallback(dataSet, - commandType, sql, - tableMapping, null, null, null)); - - } - - public virtual int DataSetFill(DataSet dataSet, CommandType commandType, string sql, - ITableMappingCollection tableMapping, - IDataAdapterSetter setter) - { - ValidateFillArguments(dataSet, sql, tableMapping); - return (int)Execute(new DataAdapterFillCallback(dataSet, - commandType, sql, - tableMapping, setter, null, null)); - - } - - public virtual int DataSetFill(DataSet dataSet, CommandType commandType, string sql, - ITableMappingCollection tableMapping, - IDataAdapterSetter setter, - IDataSetFillLifecycleProcessor fillLifecycleProcessor) - { - ValidateFillArguments(dataSet, sql, tableMapping); - return (int)Execute(new DataAdapterFillCallback(dataSet, - commandType, sql, - tableMapping, setter, fillLifecycleProcessor, null)); - - } - - #endregion - - #region DataSet Fill operations with parameters - - public virtual int DataSetFillWithParameters(DataSet dataSet, CommandType commandType, string sql, - IDbParameters parameters) - { - ValidateFillWithParameterArguments(dataSet, sql, parameters); - ITableMappingCollection mappingCollection = DoCreateMappingCollection(null); - return (int)Execute(new DataAdapterFillCallback(dataSet, - commandType, sql, - mappingCollection, null, null, - parameters)); - } - - public virtual int DataSetFillWithParameters(DataSet dataSet, CommandType commandType, string sql, - IDbParameters parameters, - string[] tableNames) - { - ValidateFillWithParameterArguments(dataSet, sql, parameters); - if (tableNames == null) - { - tableNames = new string[] { "Table" }; - } - ITableMappingCollection tableMapping = DoCreateMappingCollection(tableNames); - return (int)Execute(new DataAdapterFillCallback(dataSet, - commandType, sql, - tableMapping, null, null, parameters)); - - } - - public virtual int DataSetFillWithParameters(DataSet dataSet, CommandType commandType, string sql, - IDbParameters parameters, - ITableMappingCollection tableMapping) - { - ValidateFillWithParameterArguments(dataSet, sql, parameters, tableMapping); - return (int)Execute(new DataAdapterFillCallback(dataSet, - commandType, sql, - tableMapping, null, null, parameters)); - } - - public virtual int DataSetFillWithParameters(DataSet dataSet, CommandType commandType, string sql, - IDbParameters parameters, - ITableMappingCollection tableMapping, - IDataAdapterSetter dataAdapterSetter) - { - ValidateFillWithParameterArguments(dataSet, sql, parameters, tableMapping); - return (int)Execute(new DataAdapterFillCallback(dataSet, - commandType, sql, - tableMapping, dataAdapterSetter, null, parameters)); - } - - public virtual int DataSetFillWithParameters(DataSet dataSet, CommandType commandType, string sql, - IDbParameters parameters, - ITableMappingCollection tableMapping, - IDataAdapterSetter dataAdapterSetter, - IDataSetFillLifecycleProcessor fillLifecycleProcessor) - { - ValidateFillWithParameterArguments(dataSet, sql, parameters, tableMapping); - return (int)Execute(new DataAdapterFillCallback(dataSet, - commandType, sql, - tableMapping, dataAdapterSetter, fillLifecycleProcessor, parameters)); - } - - #endregion - - #region DataSet Update operations - public virtual int DataSetUpdateWithCommandBuilder(DataSet dataSet, - CommandType commandType, - string selectSql, - IDbParameters selectParameters, - string tableName) - { - ValidateUpdateWithCommandBuilderArguments(dataSet, tableName, selectSql); - ITableMappingCollection mappingCollection = DoCreateMappingCollection(new string[] { tableName }); - return (int)Execute(new DataAdapterUpdateWithCommandBuilderCallback(dataSet, - DbProvider.CreateCommandBuilder(), - mappingCollection, - commandType, - selectSql, - selectParameters, - null)); - } - - public virtual int DataSetUpdateWithCommandBuilder(DataSet dataSet, - CommandType commandType, - string selectSql, - IDbParameters selectParameters, - string tableName, - IDataAdapterSetter dataAdapterSetter) - { - ValidateUpdateWithCommandBuilderArguments(dataSet, tableName, selectSql); - ITableMappingCollection mappingCollection = DoCreateMappingCollection(new string[] { tableName }); - return (int)Execute(new DataAdapterUpdateWithCommandBuilderCallback(dataSet, - DbProvider.CreateCommandBuilder(), - mappingCollection, - commandType, - selectSql, - selectParameters, - dataAdapterSetter)); - } - - public virtual int DataSetUpdateWithCommandBuilder(DataSet dataSet, - CommandType commandType, - string selectSql, - IDbParameters selectParameters, - ITableMappingCollection mappingCollection, - IDataAdapterSetter dataAdapterSetter) - { - ValidateUpdateWithCommandBuilderArguments(dataSet, mappingCollection, selectSql); - return (int)Execute(new DataAdapterUpdateWithCommandBuilderCallback(dataSet, - DbProvider.CreateCommandBuilder(), - mappingCollection, - commandType, - selectSql, - selectParameters, - dataAdapterSetter)); - } - - public virtual int DataSetUpdate(DataSet dataSet, - string tableName, - IDbCommand insertCommand, - IDbCommand updateCommand, - IDbCommand deleteCommand) - { - ValidateUpdateArguments(dataSet, tableName); - - ITableMappingCollection mappingCollection = DoCreateMappingCollection(new string[] { tableName }); - - return (int)Execute(new DataAdapterUpdateCallback(dataSet, - mappingCollection, - insertCommand, - updateCommand, - deleteCommand, - null)); - } - - public virtual int DataSetUpdate(DataSet dataSet, - string tableName, - CommandType insertCommandtype, string insertSql, IDbParameters insertParameters, - CommandType updateCommandtype, string updateSql, IDbParameters updateParameters, - CommandType deleteCommandtype, string deleteSql, IDbParameters deleteParameters) - { - ValidateUpdateArguments(dataSet, tableName); - IDbCommand insertCommand = null; - if (insertSql != null) - { - insertCommand = DbProvider.CreateCommand(); - insertCommand.CommandType = insertCommandtype; - insertCommand.CommandText = insertSql; - ParameterUtils.CopyParameters(insertCommand, insertParameters); - } - IDbCommand updateCommand = null; - if (updateSql != null) - { - updateCommand = DbProvider.CreateCommand(); - updateCommand.CommandType = updateCommandtype; - updateCommand.CommandText = updateSql; - ParameterUtils.CopyParameters(updateCommand, updateParameters); - } - IDbCommand deleteCommand = null; - if (deleteSql != null) - { - deleteCommand = DbProvider.CreateCommand(); - deleteCommand.CommandType = deleteCommandtype; - deleteCommand.CommandText = deleteSql; - ParameterUtils.CopyParameters(deleteCommand, deleteParameters); - } - ITableMappingCollection mappingCollection = DoCreateMappingCollection(new string[] { tableName }); - - int returnVal = (int)Execute(new DataAdapterUpdateCallback(dataSet, mappingCollection, - insertCommand, updateCommand, deleteCommand, null)); - - if (insertSql != null) - { - ParameterUtils.CopyParameters(insertParameters, insertCommand); - } - if (updateSql != null) - { - ParameterUtils.CopyParameters(updateParameters, updateCommand); - } - if (deleteSql != null) - { - ParameterUtils.CopyParameters(deleteParameters, deleteCommand); - } - return returnVal; - } - - - - public virtual int DataSetUpdate(DataSet dataSet, - string tableName, - IDbCommand insertCommand, - IDbCommand updateCommand, - IDbCommand deleteCommand, - IDataAdapterSetter dataAdapterSetter) - { - ValidateUpdateArguments(dataSet, tableName); - ITableMappingCollection tableMapping = DoCreateMappingCollection(new string[] { tableName }); - return (int)Execute(new DataAdapterUpdateCallback(dataSet, - tableMapping, - insertCommand, - updateCommand, - deleteCommand, - dataAdapterSetter)); - } - - - public virtual int DataSetUpdate(DataSet dataSet, - ITableMappingCollection tableMapping, - IDbCommand insertCommand, - IDbCommand updateCommand, - IDbCommand deleteCommand) - { - ValidateUpdateArguments(dataSet, tableMapping); - return (int)Execute(new DataAdapterUpdateCallback(dataSet, - tableMapping, - insertCommand, - updateCommand, - deleteCommand, - null)); - } - - public virtual int DataSetUpdate(DataSet dataSet, - ITableMappingCollection tableMapping, - IDbCommand insertCommand, - IDbCommand updateCommand, - IDbCommand deleteCommand, - IDataAdapterSetter dataAdapterSetter) - { - ValidateUpdateArguments(dataSet, tableMapping); - return (int)Execute(new DataAdapterUpdateCallback(dataSet, - tableMapping, - insertCommand, - updateCommand, - deleteCommand, - dataAdapterSetter)); - } - - #endregion - - #region Parameter Creation Helper Methods - - public override IDataParameter[] DeriveParameters(string procedureName, bool includeReturnParameter) - { - return (IDataParameter[])Execute(new DeriveParametersCommandCallback(DbProvider, procedureName, includeReturnParameter)); - - } - - #endregion - - #region Private Helper Methods - - private IDbParameters CreateDbParameters(IDbDataParameter parameter) - { - IDbParameters parameters = new DbParameters(DbProvider); - parameters.AddParameter(parameter); - return parameters; - } - - private IDbParameters CreateDbParameters(IList parameterList) - { - IDbParameters parameters = null; - if (parameterList != null) - { - parameters = new DbParameters(DbProvider); - foreach (IDbDataParameter parameter in parameterList) - { - parameters.AddParameter(parameter); - } - } - return parameters; - } - - private IDbParameters CreateDbParameters(object[] parameterValues) - { - IDbParameters parameters = null; - if (parameterValues != null) - { - parameters = new DbParameters(DbProvider); - foreach (object parameterValue in parameterValues) - { - parameters.Add(parameterValue); - } - } - return parameters; - } - - public int DataTableUpdate(DataTable dataTable, - ITableMappingCollection mappingCollection, - CommandType insertCommandtype, string insertSql, IDbParameters insertParameters, - CommandType updateCommandtype, string updateSql, IDbParameters updateParameters, - CommandType deleteCommandtype, string deleteSql, IDbParameters deleteParameters, - IDataAdapterSetter dataAdapterSetter) - { - //TODO - refactor to remove cut-n-pasted code. - IDbCommand insertCommand = null; - if (insertSql != null) - { - insertCommand = DbProvider.CreateCommand(); - insertCommand.CommandType = insertCommandtype; - insertCommand.CommandText = insertSql; - ParameterUtils.CopyParameters(insertCommand, insertParameters); - } - IDbCommand updateCommand = null; - if (updateSql != null) - { - updateCommand = DbProvider.CreateCommand(); - updateCommand.CommandType = updateCommandtype; - updateCommand.CommandText = updateSql; - ParameterUtils.CopyParameters(updateCommand, updateParameters); - } - IDbCommand deleteCommand = null; - if (deleteSql != null) - { - deleteCommand = DbProvider.CreateCommand(); - deleteCommand.CommandType = deleteCommandtype; - deleteCommand.CommandText = deleteSql; - ParameterUtils.CopyParameters(deleteCommand, deleteParameters); - } - - int returnVal = (int)Execute(new DataAdapterUpdateCallback(dataTable, mappingCollection, - insertCommand, updateCommand, deleteCommand, null)); - - if (insertSql != null) - { - ParameterUtils.CopyParameters(insertParameters, insertCommand); - } - if (updateSql != null) - { - ParameterUtils.CopyParameters(updateParameters, updateCommand); - } - if (deleteSql != null) - { - ParameterUtils.CopyParameters(deleteParameters, deleteCommand); - } - return returnVal; - } - #endregion - - #region Protected Helper Methods - - protected virtual void InitExceptionTranslator() - { - if (exceptionTranslator == null) - { - IDbProvider provider = DbProvider; - if (provider != null) - { - exceptionTranslator = new ErrorCodeExceptionTranslator(provider); - } - else - { - exceptionTranslator = new FallbackExceptionTranslator(); - } - } - } - - #endregion - - #region Protected DataAdapter Helper methods - - protected virtual DataTable CreateDataTable() - { - DataTable dataTable = new DataTable(); - dataTable.Locale = CultureInfo.InvariantCulture; - return dataTable; - } - - protected virtual DataSet CreateDataSet() - { - DataSet dataSet = new DataSet(); - dataSet.Locale = CultureInfo.InvariantCulture; - return dataSet; - } - - protected virtual void ValidateFillArguments(DataTable dataTable, string sql) - { - if (dataTable == null) - { - throw new ArgumentNullException("dataTable", "DataTable argument can not be null"); - } - if (sql == null) - { - throw new ArgumentNullException("sql", "SQL for DataSet Fill operation can not be null"); - } - } - protected virtual void ValidateFillArguments(DataSet dataSet, string sql) - { - if (dataSet == null) - { - throw new ArgumentNullException("dataSet", "DataSet argument can not be null"); - } - if (sql == null) - { - throw new ArgumentNullException("sql", "SQL for DataSet Fill operation can not be null"); - } - } - protected virtual void ValidateFillArguments(DataTable dataTable, string sql, - ITableMapping tableMapping) - { - ValidateFillArguments(dataTable, sql); - if (tableMapping == null) - { - throw new ArgumentNullException("tableMapping", "ITableMapping for DataTable Fill operations can not be null"); - } - } - - protected virtual void ValidateFillArguments(DataSet dataSet, string sql, - ITableMappingCollection tableMappingCollection) - { - ValidateFillArguments(dataSet, sql); - if (tableMappingCollection == null) - { - throw new ArgumentNullException("tableMappingCollection", "ITableMappingCollection for DataSet Fill operations can not be null"); - } - } - protected virtual void ValidateFillWithParameterArguments(DataTable dataTable, string sql, IDbParameters parameters) - { - ValidateFillArguments(dataTable, sql); - if (parameters == null) - { - throw new ArgumentNullException("parameters", "IDbParameters for DataTable Fill operations can not be null"); - } - } - protected virtual void ValidateFillWithParameterArguments(DataSet dataSet, string sql, IDbParameters parameters) - { - ValidateFillArguments(dataSet, sql); - if (parameters == null) - { - throw new ArgumentNullException("parameters", "IDbParameters for DataSet Fill operations can not be null"); - } - } - protected virtual void ValidateFillWithParameterArguments(DataTable dataTable, string sql, IDbParameters parameters, ITableMapping tableMapping) - { - ValidateFillWithParameterArguments(dataTable, sql, parameters); - if (tableMapping == null) - { - throw new ArgumentNullException("tableMapping", "ITableMappingCollection for DataTable Fill operations can not be null"); - } - } - protected virtual void ValidateFillWithParameterArguments(DataSet dataSet, string sql, IDbParameters parameters, ITableMappingCollection tableMapping) - { - ValidateFillWithParameterArguments(dataSet, sql, parameters); - if (tableMapping == null) - { - throw new ArgumentNullException("tableMapping", "ITableMappingCollection for DataSet Fill operations can not be null"); - } - } - - protected virtual void ValidateUpdateArguments(DataSet dataSet, ITableMappingCollection tableMapping) - { - if (dataSet == null) - { - throw new ArgumentNullException("dataSet", "DataSet argument can not be null for update operation"); - } - if (tableMapping == null) - { - throw new ArgumentNullException("tableMapping", "TableMappings for DataSet Update operation can not be null"); - } - } - - protected virtual void ValidateUpdateArguments(DataSet dataSet, string tableName) - { - if (dataSet == null) - { - throw new ArgumentNullException("dataSet", "DataSet argument can not be null for update operation"); - } - if (tableName == null) - { - throw new ArgumentNullException("tableName", "TableName for DataSet Update operation can not be null"); - } - } - - protected virtual void ValidateUpdateArguments(DataTable dataTable, ITableMapping tableMapping) - { - if (dataTable == null) - { - throw new ArgumentNullException("dataTable", "DataTable argument can not be null for DataTable update operation"); - } - if (tableMapping == null) - { - throw new ArgumentNullException("tableMapping", "TableMapping for DataTable Update operation can not be null"); - } - } - protected virtual void ValidateUpdateArguments(DataTable dataTable, string tableName) - { - if (dataTable == null) - { - throw new ArgumentNullException("dataTable", "DataTable argument can not be null for DataTable update operation"); - } - if (tableName == null) - { - throw new ArgumentNullException("tableName", "TableName for DataTable Update operation can not be null"); - } - } - protected virtual void ValidateUpdateWithCommandBuilderArguments(DataSet dataSet, ITableMappingCollection tableMapping, string selectSql) - { - if (dataSet == null) - { - throw new ArgumentNullException("dataSet", "DataSet can not be null for update operation"); - } - if (tableMapping == null) - { - throw new ArgumentNullException("tableMapping", "TableMapping for DataSet Update operation can not be null"); - } - if (selectSql == null) - { - throw new ArgumentNullException("selectSql", "SelectSql for DataSet Update operations can not be null"); - } - } - - protected virtual void ValidateUpdateWithCommandBuilderArguments(DataTable dataTable, string tableName, string selectSql) - { - if (dataTable == null) - { - throw new ArgumentNullException("dataTable", "DataTable can not be null for update operation"); - } - if (tableName == null) - { - throw new ArgumentNullException("tableName", "TableName for DataSet Update operation can not be null"); - } - if (selectSql == null) - { - throw new ArgumentNullException("selectSql", "SelectSql for DataSet Update operations can not be null"); - } - } - - protected virtual void ValidateUpdateWithCommandBuilderArguments(DataTable dataTable, ITableMapping tableMapping, string selectSql) - { - if (dataTable == null) - { - throw new ArgumentNullException("dataTable", "DataTable can not be null for update operation"); - } - if (tableMapping == null) - { - throw new ArgumentNullException("tableMapping", "TableMapping for DataSet Update operation can not be null"); - } - if (selectSql == null) - { - throw new ArgumentNullException("selectSql", "SelectSql for DataSet Update operations can not be null"); - } - } - protected virtual void ValidateUpdateWithCommandBuilderArguments(DataSet dataSet, string tableName, string selectSql) - { - if (dataSet == null) - { - throw new ArgumentNullException("dataSet", "DataSet can not be null for update operation"); - } - if (tableName == null) - { - throw new ArgumentNullException("tableName", "TableName for DataSet Update operation can not be null"); - } - if (selectSql == null) - { - throw new ArgumentNullException("selectSql", "SelectSql for DataSet Update operations can not be null"); - } - } - - - protected virtual ITableMappingCollection DoCreateMappingCollection(string[] dataSetTableNames) - { - DataTableMappingCollection mappingCollection; - - if (dataSetTableNames == null) - { - dataSetTableNames = new string[] { "Table" }; - } - foreach (string tableName in dataSetTableNames) - { - if (StringUtils.IsNullOrEmpty(tableName)) - { - throw new ArgumentException("TableName for DataTable mapping can not be null or empty"); - } - } - mappingCollection = new DataTableMappingCollection(); - int counter = 0; - bool isFirstTable = true; - foreach (string dataSetTableName in dataSetTableNames) - { - string sourceTableName; - if (isFirstTable) - { - sourceTableName = "Table"; - isFirstTable = false; - } - else - { - sourceTableName = "Table" + ++counter; - } - mappingCollection.Add(sourceTableName, dataSetTableName); - } - return mappingCollection; - } - - #endregion - - #region Private DataAdapter Helper callbacks - - - - private class DataAdapterFillCallback : IDataAdapterCallback - { - private bool containsDataSet; - private DataSet dataSet; - private DataTable dataTable; - private CommandType commandType; - private string sql; - private ITableMappingCollection mappingCollection; - private IDataAdapterSetter dataAdapterSetter; - private IDataSetFillLifecycleProcessor fillLifecycleProcessor; - private IDbParameters parameters; - - public DataAdapterFillCallback(DataSet dataSet, - CommandType commandType, - string sql, - ITableMappingCollection mappingCollection, - IDataAdapterSetter dataAdapterSetter, - IDataSetFillLifecycleProcessor fillLifecycleProcessor, - IDbParameters parameters) - { - containsDataSet = true; - this.dataSet = dataSet; - this.commandType = commandType; - this.sql = sql; - this.mappingCollection = mappingCollection; - this.dataAdapterSetter = dataAdapterSetter; - this.fillLifecycleProcessor = fillLifecycleProcessor; - this.parameters = parameters; - } - - public DataAdapterFillCallback(DataTable dataTable, - CommandType commandType, - string sql, - ITableMappingCollection mappingCollection, - IDataAdapterSetter dataAdapterSetter, - IDataSetFillLifecycleProcessor fillLifecycleProcessor, - IDbParameters parameters) - { - containsDataSet = false; - this.dataTable = dataTable; - this.commandType = commandType; - this.sql = sql; - this.mappingCollection = mappingCollection; - this.dataAdapterSetter = dataAdapterSetter; - this.fillLifecycleProcessor = fillLifecycleProcessor; - this.parameters = parameters; - } - - - - public object DoInDataAdapter(IDbDataAdapter dataAdapter) - { - dataAdapter.SelectCommand.CommandType = commandType; - dataAdapter.SelectCommand.CommandText = sql; - //TODO investigate performance of cloning....would need to change signature to - // DataTableMapping[] otherwise... - foreach (DataTableMapping dataTableMapping in mappingCollection) - { - dataAdapter.TableMappings.Add(((ICloneable)dataTableMapping).Clone()); - } - - ParameterUtils.CopyParameters(dataAdapter.SelectCommand, parameters); - - //TODO Review these lifecycle hooks... - if (dataAdapterSetter != null) - { - dataAdapterSetter.SetValues(dataAdapter); - } - if (fillLifecycleProcessor != null) - { - fillLifecycleProcessor.BeforeFill(dataSet, dataAdapter.TableMappings); - } - - int returnVal; - if (containsDataSet) - { - returnVal = dataAdapter.Fill(dataSet); - } - else - { - //TODO should query metadata to see if supports filling dataTable directly. - if (dataAdapter is DbDataAdapter) - { - returnVal = ((DbDataAdapter)dataAdapter).Fill(dataTable); - } - else - { - //TODO could create DataSet and extract DataTable... for now just throw - throw new DataException("Provider does not support filling DataTable directly"); - } - } - - ParameterUtils.CopyParameters(parameters, dataAdapter.SelectCommand); - - if (fillLifecycleProcessor != null) - { - fillLifecycleProcessor.AfterFill(dataSet, dataAdapter.TableMappings); - } - return returnVal; - } - } - - - private class DataAdapterUpdateCallback : IDataAdapterCallback - { - private bool containsDataSet; - private DataSet dataSet; - private DataTable dataTable; - private ITableMappingCollection mappingCollection; - private IDbCommand insertCommand; - private IDbCommand updateCommand; - private IDbCommand deleteCommand; - private IDataAdapterSetter dataAdapterSetter; - - public DataAdapterUpdateCallback(DataSet dataSet, - ITableMappingCollection mappingCollection, - IDbCommand insertCommand, - IDbCommand updateCommand, - IDbCommand deleteCommand, - IDataAdapterSetter dataAdapterSetter) - { - containsDataSet = true; - this.dataSet = dataSet; - this.mappingCollection = mappingCollection; - this.insertCommand = insertCommand; - this.updateCommand = updateCommand; - this.deleteCommand = deleteCommand; - this.dataAdapterSetter = dataAdapterSetter; - } - - public DataAdapterUpdateCallback(DataTable dataTable, - ITableMappingCollection mappingCollection, - IDbCommand insertCommand, - IDbCommand updateCommand, - IDbCommand deleteCommand, - IDataAdapterSetter dataAdapterSetter) - { - containsDataSet = false; - this.dataTable = dataTable; - this.mappingCollection = mappingCollection; - this.insertCommand = insertCommand; - this.updateCommand = updateCommand; - this.deleteCommand = deleteCommand; - this.dataAdapterSetter = dataAdapterSetter; - } - #region IDataAdapterCallback Members - - public object DoInDataAdapter(IDbDataAdapter dataAdapter) - { - //TODO - did not make copies of parameters... - if (insertCommand == null && updateCommand == null && deleteCommand == null) - { - throw new ArgumentException("All commands for DataSet Update operation are null"); - } - - if (insertCommand != null) - { - dataAdapter.InsertCommand = insertCommand; - ApplyConnectionAndTx(dataAdapter.InsertCommand, dataAdapter.SelectCommand); - } - if (updateCommand != null) - { - dataAdapter.UpdateCommand = updateCommand; - ApplyConnectionAndTx(dataAdapter.UpdateCommand, dataAdapter.SelectCommand); - } - if (deleteCommand != null) - { - dataAdapter.DeleteCommand = deleteCommand; - ApplyConnectionAndTx(dataAdapter.DeleteCommand, dataAdapter.SelectCommand); - } - foreach (DataTableMapping dataTableMapping in mappingCollection) - { - dataAdapter.TableMappings.Add(((ICloneable)dataTableMapping).Clone()); - } - - if (dataAdapterSetter != null) - { - dataAdapterSetter.SetValues(dataAdapter); - } - - if (containsDataSet) - { - return dataAdapter.Update(dataSet); - } - else - { - //TODO should query metadata to see if supports filling dataTable directly. - if (dataAdapter is DbDataAdapter) - { - return ((DbDataAdapter)dataAdapter).Update(dataTable); - } - else - { - //TODO could create DataSet and extract DataTable... for now just throw - throw new DataException("Provider does not support filling DataTable directly"); - } - } - } - - private static void ApplyConnectionAndTx(IDbCommand dbCommand, IDbCommand sourceCommand) - { - dbCommand.Connection = sourceCommand.Connection; - dbCommand.Transaction = sourceCommand.Transaction; - } - - #endregion - - } - - private class DataAdapterUpdateWithCommandBuilderCallback : IDataAdapterCallback - { - private bool containsDataSet; - private DataSet dataSet; - private DataTable dataTable; - private object commandBuilder; - private ITableMappingCollection mappingCollection; - private CommandType selectCommandType; - private string selectSql; - private IDbParameters selectParameters; - private IDataAdapterSetter dataAdapterSetter; - - public DataAdapterUpdateWithCommandBuilderCallback(DataSet dataSet, - object commandBuilder, - ITableMappingCollection mappingCollection, - CommandType selectCommandType, - string selectSql, - IDbParameters selectParameters, - IDataAdapterSetter dataAdapterSetter) - { - containsDataSet = true; - this.dataSet = dataSet; - this.commandBuilder = commandBuilder; - this.mappingCollection = mappingCollection; - this.selectCommandType = selectCommandType; - this.selectSql = selectSql; - this.selectParameters = selectParameters; - this.dataAdapterSetter = dataAdapterSetter; - } - - public DataAdapterUpdateWithCommandBuilderCallback(DataTable dataTable, - object commandBuilder, - ITableMappingCollection mappingCollection, - CommandType selectCommandType, - string selectSql, - IDbParameters selectParameters, - IDataAdapterSetter dataAdapterSetter) - { - containsDataSet = false; - this.dataTable = dataTable; - this.commandBuilder = commandBuilder; - this.mappingCollection = mappingCollection; - this.selectCommandType = selectCommandType; - this.selectSql = selectSql; - this.selectParameters = selectParameters; - this.dataAdapterSetter = dataAdapterSetter; - } - #region IDataAdapterCallback Members - - public object DoInDataAdapter(IDbDataAdapter dataAdapter) - { - dataAdapter.SelectCommand.CommandType = selectCommandType; - dataAdapter.SelectCommand.CommandText = selectSql; - ParameterUtils.CopyParameters(dataAdapter.SelectCommand, selectParameters); - - - foreach (DataTableMapping dataTableMapping in mappingCollection) - { - dataAdapter.TableMappings.Add(((ICloneable)dataTableMapping).Clone()); - } - - if (dataAdapterSetter != null) - { - dataAdapterSetter.SetValues(dataAdapter); - } - - //TODO consider refactoring to put this inside IDbMetadata - PropertyInfo selectCommandProperty = commandBuilder.GetType().GetProperty("DataAdapter", - BindingFlags.DeclaredOnly | - BindingFlags.GetProperty | - BindingFlags.Public | - BindingFlags.Instance - ); - - selectCommandProperty.SetValue(commandBuilder, dataAdapter, null); - - ParameterUtils.CopyParameters(selectParameters, dataAdapter.SelectCommand); - if (containsDataSet) - { - return dataAdapter.Update(dataSet); - } - else - { - //TODO should query metadata to see if supports filling dataTable directly. - if (dataAdapter is DbDataAdapter) - { - return ((DbDataAdapter)dataAdapter).Update(dataTable); - } - else - { - //TODO could create DataSet and extract DataTable... for now just throw - throw new DataException("Provider does not support filling DataTable directly"); - } - } - } - - private static void ApplyConnectionAndTx(IDbCommand dbCommand, IDbCommand sourceCommand) - { - dbCommand.Connection = sourceCommand.Connection; - dbCommand.Transaction = sourceCommand.Transaction; - } - - #endregion - - } - #endregion - - #region Private Helper Classes - - private class AdoStoredProcedureScalarCommandCallback : ICommandCallback - { - - public object DoInCommand(IDbCommand command) - { - IDictionary returnedResults = new Hashtable(); - object scalar = command.ExecuteScalar(); - ParameterUtils.ExtractOutputParameters(returnedResults, command); - returnedResults.Add("scalar", scalar); - return returnedResults; - - } - } - - private class AdoNonQueryWithOutputParamsCommandCallback : ICommandCallback - { - - public object DoInCommand(IDbCommand command) - { - IDictionary returnedResults = new Hashtable(); - int rowsAffected = command.ExecuteNonQuery(); - ParameterUtils.ExtractOutputParameters(returnedResults, command); - returnedResults.Add("rowsAffected", rowsAffected); - return returnedResults; - - } - } - - - private class AdoResultProcessorsQueryCommandCallback : ICommandCallback - { - private AdoTemplate adoTemplate; - private IList namedResultSetProcessors; - //private IDbParameters declaredParameters; - - public AdoResultProcessorsQueryCommandCallback(AdoTemplate adoTemplate, IList namedResultSetProcessors) - { - //AssertUtils.ArgumentHasLength(namedResultSetProcessors, "namedResultSetProcessors"); - - this.adoTemplate = adoTemplate; - this.namedResultSetProcessors = namedResultSetProcessors; - //this.declaredParameters = declaredParameters; - } - - public object DoInCommand(IDbCommand command) - { - IDictionary returnedResults = new Hashtable(); - int resultSetIndex = 0; - IDataReader reader = null; - try - { - reader = adoTemplate.CreateDataReaderWrapper(command.ExecuteReader()); - - //TODO On >= .NET 2.0 platforms make use of DbDataReader.HasRows property to - // see if there is a result set. now currently assuming matching - // NamedResultSetProcessor/ResultSet pairs. - - do - { - if (namedResultSetProcessors.Count == 0) - { - //We could just have output parameters and/or return value, that is, no result sets - //If we didn't register a result set processor, it is likely that a result set wasn't expected. - break; - } - NamedResultSetProcessor namedResultSetProcessor = null; - try - { - namedResultSetProcessor - = namedResultSetProcessors[resultSetIndex] as NamedResultSetProcessor; - //Will only have possibility of run-time type error if using QueryWithCommandCreator - if (namedResultSetProcessor == null) - { - LOG.LogError("NamedResultSetProcessor for result set index " + resultSetIndex + - ", is not of expected type NamedResultSetProcessor. Type = " + - namedResultSetProcessors[resultSetIndex].GetType() + - "; Skipping processing for this result set."); - continue; - } - } - catch (IndexOutOfRangeException e) - { - string message = "No NamedResultSetProcessor associated with result set index " + resultSetIndex; - LOG.LogError(e, message); - continue; - } - catch (ArgumentOutOfRangeException e) - { - string message = "No NamedResultSetProcessor associated with result set index " + resultSetIndex; - LOG.LogError(e, message); - continue; - } - - - string parameterName = namedResultSetProcessor.Name; - if (namedResultSetProcessor.ResultSetProcessor is IResultSetExtractor) - { - IResultSetExtractor rse = (IResultSetExtractor)namedResultSetProcessor.ResultSetProcessor; - object result = rse.ExtractData(reader); - returnedResults.Add(parameterName, result); - } - else if (namedResultSetProcessor.ResultSetProcessor is IRowMapper) - { - IRowMapper rowMapper = (IRowMapper)namedResultSetProcessor.ResultSetProcessor; - object result = (new RowMapperResultSetExtractor(rowMapper)).ExtractData(reader); - returnedResults.Add(parameterName, result); - } - else if (namedResultSetProcessor.ResultSetProcessor is IRowCallback) - { - IRowCallback rowCallback = (IRowCallback)namedResultSetProcessor.ResultSetProcessor; - (new RowCallbackResultSetExtractor(rowCallback)).ExtractData(reader); - returnedResults.Add(parameterName, "ResultSet returned was processed by an IRowCallback"); - } - resultSetIndex++; - - } while (reader.NextResult()); - } - finally - { - Support.AdoUtils.CloseReader(reader); - } - ParameterUtils.ExtractOutputParameters(returnedResults, command); - return returnedResults; - } - } - - - private class DeriveParametersCommandCallback : ICommandCallback, ICommandTextProvider - { - private IDbProvider provider; - private string procedureName; - private bool includeReturnParameter; - - public DeriveParametersCommandCallback(IDbProvider provider, string procedureName, bool includeReturnParameter) - { - this.provider = provider; - this.procedureName = procedureName; - this.includeReturnParameter = includeReturnParameter; - } - - public string CommandText - { - get { return procedureName; } - } - - public object DoInCommand(IDbCommand command) - { - command.CommandType = CommandType.StoredProcedure; - command.CommandText = procedureName; - - //The DeriveParameter is static in all providers...it seems.... - Type commandBuilderType = provider.DbMetadata.CommandBuilderType; - commandBuilderType.InvokeMember(provider.DbMetadata.CommandBuilderDeriveParametersMethod.Name, - BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod, null, null, - new object[] { command }); - - if (command.Parameters.Count > 0) - { - IDataParameter param = (IDataParameter)command.Parameters[0]; - if (param.Direction == ParameterDirection.ReturnValue) - { - if (!includeReturnParameter) - { - command.Parameters.RemoveAt(0); - } - } - } - return ParameterUtils.CloneParameters(command); - } - } - - private class AdoRowCallbackCommandCallback : ICommandCallback - { - private AdoTemplate adoTemplate; - private IRowCallback rowCallback; - private IDictionary returnedParameters; - - public AdoRowCallbackCommandCallback(AdoTemplate adoTemplate, IRowCallback rowCallback, IDictionary returnedParameters) - { - this.adoTemplate = adoTemplate; - this.rowCallback = rowCallback; - this.returnedParameters = returnedParameters; - } - - public object DoInCommand(IDbCommand command) - { - //Extract the single returned result set - IDataReader reader = null; - try - { - reader = adoTemplate.CreateDataReaderWrapper(command.ExecuteReader()); - rowCallback.ProcessRow(reader); - } - finally - { - Support.AdoUtils.CloseReader(reader); - } - ParameterUtils.ExtractOutputParameters(returnedParameters, command); - return null; - } - } - private class AdoResultSetExtractorWithOutputParamsCommandCallback : ICommandCallback - { - private AdoTemplate adoTemplate; - private IResultSetExtractor rse; - private IDictionary returnedParameters; - - public AdoResultSetExtractorWithOutputParamsCommandCallback(AdoTemplate adoTemplate, IResultSetExtractor rse, IDictionary returnedParameters) - { - this.adoTemplate = adoTemplate; - this.rse = rse; - this.returnedParameters = returnedParameters; - } - - public object DoInCommand(IDbCommand command) - { - object returnVal = null; - //Extract the single returned result set - IDataReader reader = null; - try - { - reader = adoTemplate.CreateDataReaderWrapper(command.ExecuteReader()); - returnVal = rse.ExtractData(reader); - } - finally - { - Support.AdoUtils.CloseReader(reader); - } - ParameterUtils.ExtractOutputParameters(returnedParameters, command); - return returnVal; - } - } - - - private class AdoRowMapperQueryCommandCallback : ICommandCallback - { - private AdoTemplate adoTemplate; - private IRowMapper rowMapper; - //private IDbParameters declaredParameters; - private IDictionary returnedParameters; - - public AdoRowMapperQueryCommandCallback(AdoTemplate adoTemplate, IRowMapper rowMapper, IDictionary returnedParameters) - { - this.adoTemplate = adoTemplate; - this.rowMapper = rowMapper; - //this.declaredParameters = declaredParameters; - this.returnedParameters = returnedParameters; - } - - public object DoInCommand(IDbCommand command) - { - IList objectList = null; - //Extract the single returned result set - IDataReader reader = null; - try - { - reader = adoTemplate.CreateDataReaderWrapper(command.ExecuteReader()); - RowMapperResultSetExtractor rse = new RowMapperResultSetExtractor(rowMapper, 1); - objectList = (IList)rse.ExtractData(reader); - } - finally - { - Support.AdoUtils.CloseReader(reader); - } - ParameterUtils.ExtractOutputParameters(returnedParameters, command); - return objectList; - } - } - - - private class ExecuteNonQueryCallbackWithParameters : ICommandCallback, ICommandTextProvider - { - private CommandType commandType; - private string commandText; - private IDbParameters parameters; - - public ExecuteNonQueryCallbackWithParameters(CommandType commandType, string commandText, IDbParameters dbParameters) - { - this.commandType = commandType; - this.commandText = commandText; - parameters = dbParameters; - } - - public string CommandText - { - get { return commandText; } - } - - public Object DoInCommand(IDbCommand command) - { - command.CommandType = commandType; - command.CommandText = commandText; - ParameterUtils.CopyParameters(command, parameters); - Object returnValue = command.ExecuteNonQuery(); - ParameterUtils.CopyParameters(parameters, command); - return returnValue; - } - - } - - - private class ExecuteNonQueryCallbackWithCommandSetter : ICommandCallback, ICommandTextProvider - { - private CommandType commandType; - private string commandText; - private ICommandSetter commandSetter; - - public ExecuteNonQueryCallbackWithCommandSetter(CommandType commandType, string commandText, ICommandSetter commandSetter) - { - this.commandType = commandType; - this.commandText = commandText; - this.commandSetter = commandSetter; - } - - public string CommandText - { - get { return commandText; } - } - - public Object DoInCommand(IDbCommand command) - { - command.CommandType = commandType; - command.CommandText = commandText; - if (commandSetter != null) - { - commandSetter.SetValues(command); - } - Object rowsAffected = command.ExecuteNonQuery(); - if (LOG.IsEnabled(LogLevel.Debug)) - { - LOG.LogDebug("ExecuteNonQuery affected " + rowsAffected + " rows"); - } - return rowsAffected; - } - - } - - - private class ExecuteScalarCallbackWithParameters : ICommandCallback, ICommandTextProvider - { - private CommandType commandType = CommandType.Text; - private string commandText; - private IDbParameters parameters; - - public ExecuteScalarCallbackWithParameters(CommandType cmdType, string cmdText, IDbParameters dbParameters) - { - commandType = cmdType; - commandText = cmdText; - parameters = dbParameters; - } - - public string CommandText - { - get { return commandText; } - } - - public Object DoInCommand(IDbCommand command) - { - command.CommandType = commandType; - command.CommandText = commandText; - ParameterUtils.CopyParameters(command, parameters); - Object returnValue = command.ExecuteScalar(); - ParameterUtils.CopyParameters(parameters, command); - return returnValue; - } - } - - private class ExecuteScalarCallbackWithCommandSetter : ICommandCallback, ICommandTextProvider - { - private CommandType commandType; - private string commandText; - private ICommandSetter commandSetter; - - public ExecuteScalarCallbackWithCommandSetter(CommandType commandType, string commandText, ICommandSetter commandSetter) - { - this.commandType = commandType; - this.commandText = commandText; - this.commandSetter = commandSetter; - } - - public string CommandText - { - get { return commandText; } - } - - public Object DoInCommand(IDbCommand command) - { - command.CommandType = commandType; - command.CommandText = commandText; - if (commandSetter != null) - { - commandSetter.SetValues(command); - } - Object returnValue = command.ExecuteScalar(); - if (LOG.IsEnabled(LogLevel.Debug)) - { - LOG.LogDebug("ExecuteScalar return value = " + returnValue); - } - return returnValue; - } - - } - - - private class ExecuteCommandCallbackUsingDelegate : ICommandCallback, ICommandTextProvider - { - private CommandDelegate del; - private string commandText; - - public ExecuteCommandCallbackUsingDelegate(CommandDelegate d) - { - del = d; - } - - public string CommandText - { - get { return commandText; } - } - - public Object DoInCommand(IDbCommand command) - { - try - { - return del(command); - } - catch (Exception e) - { - e.GetType(); - commandText = command.CommandText; - throw; - } - } - } - - - - private class QueryCallbackWithCommandSetter : ICommandCallback, ICommandTextProvider - { - private AdoTemplate adoTemplate; - private IResultSetExtractor rse; - private ResultSetExtractorDelegate resultSetExtractorDelegate; - private ICommandSetter commandSetter; - private CommandType commandType; - private string commandText; - - public QueryCallbackWithCommandSetter(AdoTemplate adoTemplate, CommandType cmdType, string cmdText, IResultSetExtractor rse, ICommandSetter commandSetter) - { - this.adoTemplate = adoTemplate; - commandType = cmdType; - commandText = cmdText; - this.rse = rse; - this.commandSetter = commandSetter; - } - - public QueryCallbackWithCommandSetter(AdoTemplate adoTemplate, CommandType cmdType, string cmdText, ResultSetExtractorDelegate resultSetExtractorDelegate, ICommandSetter commandSetter) - { - this.adoTemplate = adoTemplate; - commandType = cmdType; - commandText = cmdText; - this.resultSetExtractorDelegate = resultSetExtractorDelegate; - this.commandSetter = commandSetter; - } - - public string CommandText - { - get { return commandText; } - } - - public object DoInCommand(IDbCommand command) - { - IDataReader reader = null; - try - { - command.CommandType = commandType; - command.CommandText = commandText; - if (commandSetter != null) - { - commandSetter.SetValues(command); - } - reader = adoTemplate.CreateDataReaderWrapper(command.ExecuteReader()); - if (rse != null) - { - return rse.ExtractData(reader); - } - else - { - return resultSetExtractorDelegate(reader); - } - } - finally - { - Support.AdoUtils.CloseReader(reader); - } - } - - } - - private class QueryCallback : ICommandCallback, ICommandTextProvider - { - private AdoTemplate adoTemplate; - private IResultSetExtractor rse; - private ResultSetExtractorDelegate resultSetExtractorDelegate; - private CommandType commandType; - private string commandText; - private IDbParameters parameters; - - public QueryCallback(AdoTemplate adoTemplate, CommandType cmdType, string cmdText, IResultSetExtractor rse, IDbParameters dbParameters) - { - this.adoTemplate = adoTemplate; - commandType = cmdType; - commandText = cmdText; - this.rse = rse; - parameters = dbParameters; - } - - public QueryCallback(AdoTemplate adoTemplate, CommandType cmdType, string cmdText, ResultSetExtractorDelegate resultSetExtractorDelegate, IDbParameters dbParameters) - { - this.adoTemplate = adoTemplate; - commandType = cmdType; - commandText = cmdText; - this.resultSetExtractorDelegate = resultSetExtractorDelegate; - parameters = dbParameters; - } - - - public string CommandText - { - get { return commandText; } - } - - public object DoInCommand(IDbCommand command) - { - IDataReader reader = null; - try - { - command.CommandType = commandType; - command.CommandText = commandText; - ParameterUtils.CopyParameters(command, parameters); - reader = adoTemplate.CreateDataReaderWrapper(command.ExecuteReader()); - object returnValue; - if (rse != null) - { - returnValue = rse.ExtractData(reader); - } - else - { - returnValue = resultSetExtractorDelegate(reader); - } - return returnValue; - } - finally - { - Support.AdoUtils.CloseReader(reader); - ParameterUtils.CopyParameters(parameters, command); - } - } - } - - #endregion - - /// - /// Creates the data reader wrapper for use in AdoTemplate callback methods. - /// - /// The reader to wrap. - /// The data reader used in AdoTemplate callbacks - public override IDataReader CreateDataReaderWrapper(IDataReader readerToWrap) - { - if (dataReaderWrapperType != null && newDataReaderWrapper != null) - { - IDataReaderWrapper wrapper = (IDataReaderWrapper) newDataReaderWrapper.Invoke(ObjectUtils.EmptyObjects); - wrapper.WrappedReader = readerToWrap; - return wrapper; } else { - return readerToWrap; + LOG.LogWarning("Ignoring assignment of DataReaderWrapperType since it has already been assigned."); } } } + #endregion + + public override void AfterPropertiesSet() + { + if (DbProvider == null) + { + throw new ArgumentException("DbProvider is required"); + } + + if (!LazyInit) + { + InitExceptionTranslator(); + } + } + + #region General Execute Callback Methods + + /// + /// Execute a ADO.NET operation on a command object using a delegate callback. + /// + /// The delegate called with a command object. + /// + /// A result object returned by the action or null + /// + /// This allows for implementing arbitrary data access operations + /// on a single command within Spring's managed ADO.NET environment. + public virtual Object Execute(CommandDelegate del) + { + return Execute(new ExecuteCommandCallbackUsingDelegate(del)); + } + + /// + /// Callback to execute a IDbCommand. + /// + /// the callback to execute + /// object returned from callback + public virtual object Execute(ICommandCallback action) + { + ConnectionTxPair connectionTxPairToUse = GetConnectionTxPair(DbProvider); + + IDbCommand command = null; + try + { + command = DbProvider.CreateCommand(); + command.Connection = connectionTxPairToUse.Connection; + command.Transaction = connectionTxPairToUse.Transaction; + //TODO collect warnings... + //RegisterEventHandlers(command.Connection); + ApplyCommandSettings(command); + Object result = action.DoInCommand(command); + //SqlWarnings sqlWarnings = GetSqlWarnings() + //ThrowExceptionOnWarningIfNotIgnoringWarnings(sqlWarnings); + return result; + } + catch (Exception e) + { + DisposeCommand(command); + command = null; + DisposeConnection(connectionTxPairToUse.Connection, DbProvider); + connectionTxPairToUse.Connection = null; + if (DbProvider.IsDataAccessException(e)) + { + throw ExceptionTranslator.Translate("CommandCallback", GetCommandText(action), e); + } + else + { + throw; + } + } + finally + { + DisposeCommand(command); + DisposeConnection(connectionTxPairToUse.Connection, DbProvider); + } + } + + /// + /// Executes ADO.NET operations on a command object, created by the provided IDbCommandCreator, + /// using the interface based callback IDbCommandCallback. + /// + /// The command creator. + /// The callback to execute based on IDbCommand + /// A result object returned by the action or null + public virtual object Execute(IDbCommandCreator commandCreator, ICommandCallback action) + { + AssertUtils.ArgumentNotNull(commandCreator, "commandCreator", "IDbCommandCreator must not be null"); + AssertUtils.ArgumentNotNull(action, "action", "Callback object must not be null"); + + ConnectionTxPair connectionTxPairToUse = GetConnectionTxPair(DbProvider); + + IDbCommand command = null; + try + { + command = commandCreator.CreateDbCommand(DbProvider); + command.Connection = connectionTxPairToUse.Connection; + command.Transaction = connectionTxPairToUse.Transaction; + ApplyCommandSettings(command); + //TODO collect warnings... + //RegisterEventHandlers(command.Connection); + Object result = action.DoInCommand(command); + + //SqlWarnings sqlWarnings = GetSqlWarnings() + //ThrowExceptionOnWarningIfNotIgnoringWarnings(sqlWarnings); + + return result; + } + catch (Exception e) + { + commandCreator = null; + DisposeCommand(command); + command = null; + DisposeConnection(connectionTxPairToUse.Connection, DbProvider); + connectionTxPairToUse.Connection = null; + if (DbProvider.IsDataAccessException(e)) + { + throw ExceptionTranslator.Translate("CommandCallback", GetCommandText(action), e); + } + else + { + throw; + } + } + finally + { + DisposeCommand(command); + DisposeConnection(connectionTxPairToUse.Connection, DbProvider); + } + } + + /// + /// Execute ADO.NET operations on a IDbDataAdapter object using an interface based callback. + /// + /// This allows for implementing abritrary data access operations + /// on a single DataAdapter within Spring's managed ADO.NET environment. + /// + /// The data adapter callback. + /// A result object returned by the callback or null + public virtual object Execute(IDataAdapterCallback dataAdapterCallback) + { + ConnectionTxPair connectionTxPairToUse = GetConnectionTxPair(DbProvider); + IDbDataAdapter dataAdapter = null; + try + { + dataAdapter = DbProvider.CreateDataAdapter(); + //TODO row updated event handling... + dataAdapter.SelectCommand = DbProvider.CreateCommand(); + dataAdapter.SelectCommand.Connection = connectionTxPairToUse.Connection; + //TODO register for warnings on connection. + dataAdapter.SelectCommand.Transaction = connectionTxPairToUse.Transaction; + ApplyCommandSettings(dataAdapter.SelectCommand); + object result = dataAdapterCallback.DoInDataAdapter(dataAdapter); + return result; + } + catch (Exception) + { + DisposeDataAdapterCommands(dataAdapter); + //TODO set dataAdapter command's = null; ? + //TODO exception translation? different hierarchy for data set operations. + DisposeConnection(connectionTxPairToUse.Connection, DbProvider); + connectionTxPairToUse.Connection = null; + throw; + } + finally + { + DisposeDataAdapterCommands(dataAdapter); + DisposeConnection(connectionTxPairToUse.Connection, DbProvider); + } + } + + #endregion + + #region ExecuteNonQuery + + /// + /// Executes a non query returning the number of rows affected. + /// + /// The command type. + /// The command text to execute. + /// The number of rows affected. + public virtual int ExecuteNonQuery(CommandType cmdType, string cmdText) + { + #region Instrumentation + + if (LOG.IsEnabled(LogLevel.Debug)) + { + LOG.LogDebug("Executing NonQuery " + cmdType + "[" + cmdText + "]"); + } + + #endregion + + return (int) Execute(new ExecuteNonQueryCallbackWithParameters(cmdType, cmdText, null)); + } + + /// + /// Executes a non query returning the number of rows affected. + /// + /// The command type. + /// The command text to execute. + /// The name of the parameter to map. + /// One of the database parameter type enumerations. + /// The length of the parameter. 0 if not applicable to parameter type. + /// The parameter value. + /// The number of rows affected. + public virtual int ExecuteNonQuery(CommandType cmdType, string cmdText, + string parameterName, Enum dbType, int size, object parameterValue) + { + return (int) Execute(new ExecuteNonQueryCallbackWithParameters(cmdType, cmdText, + CreateDbParameters(parameterName, dbType, size, parameterValue))); + } + + /// + /// Executes a non query returning the number of rows affected. + /// + /// The command type. + /// The command text to execute. + /// The parameter collection to map. + /// The number of rows affected. + public virtual int ExecuteNonQuery(CommandType cmdType, string cmdText, + IDbParameters parameters) + { + #region Instrumentation + + if (LOG.IsEnabled(LogLevel.Debug)) + { + LOG.LogDebug("Executing NonQuery. " + cmdType + "[" + cmdText + "]"); + } + + #endregion + + return (int) Execute(new ExecuteNonQueryCallbackWithParameters(cmdType, cmdText, parameters)); + } + + /// + /// Executes a non query with parameters set via the + /// command setter, returning the number of rows affected. + /// + /// The command type. + /// The command text to execute. + /// The command setter. + /// The number of rows affected. + public virtual int ExecuteNonQuery(CommandType cmdType, string cmdText, + ICommandSetter commandSetter) + { + #region Instrumentation + + if (LOG.IsEnabled(LogLevel.Debug)) + { + LOG.LogDebug("Executing NonQuery. " + cmdType + "[" + cmdText + "]"); + } + + #endregion + + return (int) Execute(new ExecuteNonQueryCallbackWithCommandSetter(cmdType, cmdText, commandSetter)); + } + + /// + /// Executes a non query with a command created via IDbCommandCreator and + /// parameters. + /// + /// Output parameters can be retrieved via the returned + /// dictionary. + /// + /// More commonly used as a lower level support method within the framework, + /// for example StoredProcedure/AdoScalar. + /// + /// + /// The callback to create a IDbCommand. + /// The number of rows affected. + public virtual IDictionary ExecuteNonQuery(IDbCommandCreator commandCreator) + { + return (IDictionary) Execute(commandCreator, new AdoNonQueryWithOutputParamsCommandCallback()); + } + + #endregion + + #region ExecuteScalar + + /// + /// Execute the query with the specified command text. + /// + /// No parameters are used. As with + /// IDbCommand.ExecuteScalar, it returns the first column of the first row in the resultset + /// returned by the query. Extra columns or row are ignored. + /// The command type + /// The command text to execute. + /// The first column of the first row in the result set + public virtual object ExecuteScalar(CommandType cmdType, string cmdText) + { + return Execute(new ExecuteScalarCallbackWithParameters(cmdType, cmdText, null)); + } + + /// + /// Execute the query with the specified command text and parameter returning a scalar result + /// + /// The command type + /// The command text to execute. + /// The name of the parameter to map. + /// One of the database parameter type enumerations. + /// The length of the parameter. 0 if not applicable to parameter type. + /// The parameter value. + /// The first column of the first row in the result set + public virtual object ExecuteScalar(CommandType cmdType, string cmdText, + string parameterName, Enum dbType, int size, object parameterValue) + { + return Execute(new ExecuteScalarCallbackWithParameters(cmdType, cmdText, + CreateDbParameters(parameterName, dbType, size, parameterValue))); + } + + /// + /// Execute the query with the specified command text and parameters returning a scalar result + /// + /// The command type + /// The command text to execute. + /// The parameter collection to map. + /// The first column of the first row in the result set + public virtual object ExecuteScalar(CommandType cmdType, string cmdText, + IDbParameters parameters) + { + return Execute(new ExecuteScalarCallbackWithParameters(cmdType, cmdText, parameters)); + } + + /// + /// Execute the query with the specified command text and parameters set via the + /// command setter, returning a scalar result + /// + /// The command type + /// The command text to execute. + /// The command setter. + /// The first column of the first row in the result set + public virtual object ExecuteScalar(CommandType cmdType, string cmdText, + ICommandSetter commandSetter) + { + #region Instrumentation + + if (LOG.IsEnabled(LogLevel.Debug)) + { + LOG.LogDebug("Executing ExecuteScalar. " + cmdType + "[" + cmdText + "]"); + } + + #endregion + + return Execute(new ExecuteScalarCallbackWithCommandSetter(cmdType, cmdText, commandSetter)); + } + + /// + /// Execute the query with a command created via IDbCommandCreator and + /// parameters + /// + /// Output parameters can be retrieved via the returned + /// dictionary. + /// + /// More commonly used as a lower level support method within the framework, + /// for example for StoredProcedure/AdoScalar. + /// + /// The callback to create a IDbCommand. + /// A dictionary containing output parameters, if any + public virtual IDictionary ExecuteScalar(IDbCommandCreator commandCreator) + { + return (IDictionary) Execute(commandCreator, new AdoStoredProcedureScalarCommandCallback()); + } + + #endregion + + #region Query with RowCallback + + /// + /// Execute a query given IDbCommand's type and text, reading a + /// single result set on a per-row basis with a . + /// + /// The type of command + /// The text of the query. + /// callback that will extract results + /// one row at a time. + /// + public virtual void QueryWithRowCallback(CommandType cmdType, string cmdText, IRowCallback rowCallback) + { + QueryWithResultSetExtractor(cmdType, cmdText, new RowCallbackResultSetExtractor(rowCallback)); + } + + /// + /// Execute a query given IDbCommand's type and text by + /// passing the created IDbCommand to a ICommandSetter implementation + /// that knows how to bind values to the IDbCommand, reading a + /// single result set on a per-row basis with a . + /// + /// The type of command + /// The text of the query. + /// callback that will extract results + /// one row at a time. + /// + /// The command setter. + public virtual void QueryWithRowCallback(CommandType cmdType, string cmdText, IRowCallback rowCallback, + ICommandSetter commandSetter) + { + QueryWithResultSetExtractor(cmdType, cmdText, new RowCallbackResultSetExtractor(rowCallback), commandSetter); + } + + /// + /// Execute a query given IDbCommand's type and text and provided parameter + /// information, reading a + /// single result set on a per-row basis with a . + /// + /// The type of command + /// The text of the query. + /// callback that will extract results + /// one row at a time. + /// + /// The name of the parameter to map. + /// One of the database parameter type enumerations. + /// The length of the parameter. 0 if not applicable to parameter type. + /// The parameter value. + public virtual void QueryWithRowCallback(CommandType cmdType, string cmdText, IRowCallback rowCallback, + string parameterName, Enum dbType, int size, object parameterValue) + { + QueryWithResultSetExtractor(cmdType, cmdText, new RowCallbackResultSetExtractor(rowCallback), parameterName, dbType, size, parameterValue); + } + + public virtual void QueryWithRowCallback(CommandType cmdType, string cmdText, IRowCallback rowCallback, IDbParameters parameters) + { + QueryWithResultSetExtractor(cmdType, cmdText, new RowCallbackResultSetExtractor(rowCallback), parameters); + } + + #endregion + + // RowCallback with Delegate Questionable for 1.1 since no anonymous delegates and there isn't a collecting parameter + // in the delegate method signature. + + #region Query with RowCallback Delegate + + public virtual void QueryWithRowCallbackDelegate(CommandType cmdType, string sql, RowCallbackDelegate rowCallbackDelegate) + { + QueryWithResultSetExtractor(cmdType, sql, new RowCallbackResultSetExtractor(rowCallbackDelegate)); + } + + public virtual void QueryWithRowCallbackDelegate(CommandType cmdType, string sql, RowCallbackDelegate rowCallbackDelegate, ICommandSetter commandSetter) + { + QueryWithResultSetExtractor(cmdType, sql, new RowCallbackResultSetExtractor(rowCallbackDelegate), commandSetter); + } + + public virtual void QueryWithRowCallbackDelegate(CommandType cmdType, string sql, RowCallbackDelegate rowCallbackDelegate, + string name, Enum dbType, int size, object parameterValue) + { + QueryWithResultSetExtractor(cmdType, sql, new RowCallbackResultSetExtractor(rowCallbackDelegate), name, dbType, size, parameterValue); + } + + public virtual void QueryWithRowCallbackDelegate(CommandType cmdType, string sql, RowCallbackDelegate rowCallbackDelegate, IDbParameters parameters) + { + QueryWithResultSetExtractor(cmdType, sql, new RowCallbackResultSetExtractor(rowCallbackDelegate), parameters); + } + + #endregion + + #region Query with RowMapper + + public virtual IList QueryWithRowMapper(CommandType cmdType, string cmdText, IRowMapper rowMapper) + { + return (IList) QueryWithResultSetExtractor(cmdType, cmdText, new RowMapperResultSetExtractor(rowMapper)); + } + + public virtual IList QueryWithRowMapper(CommandType cmdType, string cmdText, IRowMapper rowMapper, ICommandSetter commandSetter) + { + return (IList) QueryWithResultSetExtractor(cmdType, cmdText, + new RowMapperResultSetExtractor(rowMapper), commandSetter); + } + + public virtual IList QueryWithRowMapper(CommandType cmdType, string cmdText, IRowMapper rowMapper, + string name, Enum dbType, int size, object parameterValue) + { + return (IList) QueryWithResultSetExtractor(cmdType, cmdText, new RowMapperResultSetExtractor(rowMapper), name, dbType, size, parameterValue); + } + + public virtual IList QueryWithRowMapper(CommandType cmdType, string cmdText, IRowMapper rowMapper, IDbParameters parameters) + { + return (IList) QueryWithResultSetExtractor(cmdType, cmdText, new RowMapperResultSetExtractor(rowMapper), parameters); + } + + #endregion + + #region Query With RowMapper Delegate + + public virtual IList QueryWithRowMapperDelegate(CommandType cmdType, string cmdText, RowMapperDelegate rowMapperDelegate) + { + return (IList) QueryWithResultSetExtractor(cmdType, cmdText, new RowMapperResultSetExtractor(rowMapperDelegate)); + } + + public virtual IList QueryWithRowMapperDelegate(CommandType cmdType, string cmdText, RowMapperDelegate rowMapperDelegate, ICommandSetter commandSetter) + { + return (IList) QueryWithResultSetExtractor(cmdType, cmdText, new RowMapperResultSetExtractor(rowMapperDelegate), commandSetter); + } + + public virtual IList QueryWithRowMapperDelegate(CommandType cmdType, string cmdText, RowMapperDelegate rowMapperDelegate, + string parameterName, Enum dbType, int size, object parameterValue) + { + return (IList) QueryWithResultSetExtractor(cmdType, cmdText, new RowMapperResultSetExtractor(rowMapperDelegate), parameterName, dbType, size, parameterValue); + } + + public virtual IList QueryWithRowMapperDelegate(CommandType cmdType, string cmdText, RowMapperDelegate rowMapperDelegate, + IDbParameters parameters) + { + return (IList) QueryWithResultSetExtractor(cmdType, cmdText, new RowMapperResultSetExtractor(rowMapperDelegate), parameters); + } + + #endregion + + #region Query with ResultSetExtractor + + /// + /// Execute a query given static SQL/Stored Procedure name + /// and process a single result set with an instance of IResultSetExtractor + /// + /// The type of command. + /// The SQL/Stored Procedure to execute + /// Object that will extract all rows of a result set + /// An arbitrary result object, as returned by the IResultSetExtractor + public virtual object QueryWithResultSetExtractor(CommandType cmdType, string sql, IResultSetExtractor rse) + { + AssertUtils.ArgumentNotNull(sql, "sql", "SQL must not be null"); + + //TODO check for parameter placeholders... + + if (LOG.IsEnabled(LogLevel.Debug)) + { + LOG.LogDebug("Executing SQL [" + sql + "]"); + } + + return Execute(new QueryCallback(this, cmdType, sql, rse, null)); + } + + public virtual object QueryWithResultSetExtractor(CommandType cmdType, string cmdText, IResultSetExtractor resultSetExtractor, ICommandSetter commandSetter) + { + AssertUtils.ArgumentNotNull(resultSetExtractor, "resultSetExtractor", "Result Set Extractor must not be null"); + return Execute(new QueryCallbackWithCommandSetter(this, cmdType, cmdText, + resultSetExtractor, commandSetter)); + } + + public virtual object QueryWithResultSetExtractor(CommandType cmdType, string cmdText, IResultSetExtractor resultSetExtractor, + string name, Enum dbType, int size, object parameterValue) + { + AssertUtils.ArgumentNotNull(resultSetExtractor, "resultSetExtractor", "Result Set Extractor must not be null"); + return Execute(new QueryCallback(this, cmdType, cmdText, resultSetExtractor, CreateDbParameters(name, dbType, size, parameterValue))); + } + + public virtual object QueryWithResultSetExtractor(CommandType cmdType, string cmdText, IResultSetExtractor resultSetExtractor, + IDbParameters parameters) + { + AssertUtils.ArgumentNotNull(resultSetExtractor, "resultSetExtractor", "Result Set Extractor must not be null"); + return Execute(new QueryCallback(this, cmdType, cmdText, resultSetExtractor, parameters)); + } + + #endregion + + #region Query with ResultSetExtractorDelegate + + /// + /// Execute a query given static SQL/Stored Procedure name + /// and process a single result set with an instance of IResultSetExtractor + /// + /// The type of command. + /// The SQL/Stored Procedure to execute + /// Delegate that will extract all rows of a result set + /// An arbitrary result object, as returned by the IResultSetExtractor + public virtual object QueryWithResultSetExtractorDelegate(CommandType cmdType, string sql, ResultSetExtractorDelegate resultSetExtractorDelegate) + { + AssertUtils.ArgumentNotNull(sql, "sql", "SQL must not be null"); + + //TODO check for parameter placeholders... + + if (LOG.IsEnabled(LogLevel.Debug)) + { + LOG.LogDebug("Executing SQL [" + sql + "]"); + } + + return Execute(new QueryCallback(this, cmdType, sql, resultSetExtractorDelegate, null)); + } + + public virtual object QueryWithResultSetExtractorDelegate(CommandType cmdType, string cmdText, ResultSetExtractorDelegate resultSetExtractorDelegate, + ICommandSetter commandSetter) + { + AssertUtils.ArgumentNotNull(resultSetExtractorDelegate, "resultSetExtractorDelegate", "Result set extractor delegate must not be null"); + return Execute(new QueryCallbackWithCommandSetter(this, cmdType, cmdText, + resultSetExtractorDelegate, commandSetter)); + } + + public virtual object QueryWithResultSetExtractorDelegate(CommandType cmdType, string cmdText, ResultSetExtractorDelegate resultSetExtractorDelegate, + string name, Enum dbType, int size, object parameterValue) + { + AssertUtils.ArgumentNotNull(resultSetExtractorDelegate, "resultSetExtractorDelegate", "Result set extractor delegate must not be null"); + return Execute(new QueryCallback(this, cmdType, cmdText, resultSetExtractorDelegate, CreateDbParameters(name, dbType, size, parameterValue))); + } + + public virtual object QueryWithResultSetExtractorDelegate(CommandType cmdType, string cmdText, ResultSetExtractorDelegate resultSetExtractorDelegate, + IDbParameters parameters) + { + AssertUtils.ArgumentNotNull(resultSetExtractorDelegate, "resultSetExtractorDelegate", "Result set extractor delegate must not be null"); + return Execute(new QueryCallback(this, cmdType, cmdText, resultSetExtractorDelegate, parameters)); + } + + #endregion + + #region Query for Object + + /// + /// Execute a query with the specified command text, mapping a single result + /// row to an object via a RowMapper. + /// + /// The command type. + /// The command text to execute. + /// object that will map one object per row + /// The single mapped object. + /// + /// If the query does not return exactly one row. + /// + /// + /// If there is any problem executing the query. + /// + public virtual object QueryForObject(CommandType cmdType, string cmdText, IRowMapper rowMapper) + { + IList results = QueryWithRowMapper(cmdType, cmdText, rowMapper); + return DataAccessUtils.RequiredUniqueResultSet(results); + } + + /// + /// Execute a query with the specified command text and parameters set via the + /// command setter, mapping a single result row to an object via a RowMapper. + /// + /// The command type. + /// The command text to execute. + /// object that will map one object per row + /// The command setter. + /// The single mapped object. + /// + /// If the query does not return exactly one row. + /// + /// + /// If there is any problem executing the query. + /// + public virtual object QueryForObject(CommandType cmdType, string cmdText, IRowMapper rowMapper, ICommandSetter commandSetter) + { + IList results = QueryWithRowMapper(cmdType, cmdText, rowMapper, commandSetter); + return DataAccessUtils.RequiredUniqueResultSet(results); + } + + /// + /// Execute a query with the specified command text and parameters, mapping a single result row + /// to an object via a RowMapper. + /// + /// The command type. + /// The command text to execute. + /// object that will map one object per row + /// The parameter collection to use in the query. + /// The single mapped object. + /// + /// If the query does not return exactly one row. + /// + /// + /// If there is any problem executing the query. + /// + public virtual object QueryForObject(CommandType cmdType, string cmdText, IRowMapper rowMapper, IDbParameters parameters) + { + IList results = QueryWithRowMapper(cmdType, cmdText, rowMapper, parameters); + return DataAccessUtils.RequiredUniqueResultSet(results); + } + + /// + /// Execute a query with the specified command text and parameter, mapping a single result row + /// to an object via a RowMapper. + /// + /// The command type. + /// The command text to execute. + /// object that will map one object per row + /// The name of the parameter to map. + /// One of the database parameter type enumerations. + /// The length of the parameter. 0 if not applicable to parameter type. + /// The parameter value. + /// The single mapped object. + /// + /// If the query does not return exactly one row. + /// + /// + /// If there is any problem executing the query. + /// + public virtual object QueryForObject(CommandType cmdType, string cmdText, IRowMapper rowMapper, string parameterName, Enum dbType, int size, + object parameterValue) + { + IList results = QueryWithRowMapper(cmdType, cmdText, rowMapper, parameterName, dbType, size, parameterValue); + return DataAccessUtils.RequiredUniqueResultSet(results); + } + + #endregion + + #region Query for ObjectDelegate + + /// + /// Execute a query with the specified command text, mapping a single result + /// row to an object via a RowMapper. + /// + /// The command type. + /// The command text to execute. + /// delegate that will map one object per row + /// The single mapped object. + /// + /// If the query does not return exactly one row. + /// + /// + /// If there is any problem executing the query. + /// + public virtual object QueryForObjectDelegate(CommandType cmdType, string cmdText, RowMapperDelegate rowMapperDelegate) + { + IList results = QueryWithRowMapperDelegate(cmdType, cmdText, rowMapperDelegate); + return DataAccessUtils.RequiredUniqueResultSet(results); + } + + /// + /// Execute a query with the specified command text and parameters set via the + /// command setter, mapping a single result row to an object via a RowMapper. + /// + /// The command type. + /// The command text to execute. + /// delegate that will map one object per row + /// The command setter. + /// The single mapped object. + /// + /// If the query does not return exactly one row. + /// + /// + /// If there is any problem executing the query. + /// + public virtual object QueryForObjectDelegate(CommandType cmdType, string cmdText, RowMapperDelegate rowMapperDelegate, ICommandSetter commandSetter) + { + IList results = QueryWithRowMapperDelegate(cmdType, cmdText, rowMapperDelegate, commandSetter); + return DataAccessUtils.RequiredUniqueResultSet(results); + } + + /// + /// Execute a query with the specified command text and parameters, mapping a single result row + /// to an object via a RowMapper. + /// + /// The command type. + /// The command text to execute. + /// delegate that will map one object per row + /// The parameter collection to use in the query. + /// The single mapped object. + /// + /// If the query does not return exactly one row. + /// + /// + /// If there is any problem executing the query. + /// + public virtual object QueryForObjectDelegate(CommandType cmdType, string cmdText, RowMapperDelegate rowMapperDelegate, IDbParameters parameters) + { + IList results = QueryWithRowMapperDelegate(cmdType, cmdText, rowMapperDelegate, parameters); + return DataAccessUtils.RequiredUniqueResultSet(results); + } + + /// + /// Execute a query with the specified command text and parameter, mapping a single result row + /// to an object via a RowMapper. + /// + /// The command type. + /// The command text to execute. + /// delegate that will map one object per row + /// The name of the parameter to map. + /// One of the database parameter type enumerations. + /// The length of the parameter. 0 if not applicable to parameter type. + /// The parameter value. + /// The single mapped object. + /// + /// If the query does not return exactly one row. + /// + /// + /// If there is any problem executing the query. + /// + public virtual object QueryForObjectDelegate(CommandType cmdType, string cmdText, RowMapperDelegate rowMapperDelegate, string parameterName, Enum dbType, int size, + object parameterValue) + { + IList results = QueryWithRowMapperDelegate(cmdType, cmdText, rowMapperDelegate, parameterName, dbType, size, parameterValue); + return DataAccessUtils.RequiredUniqueResultSet(results); + } + + #endregion + + #region Query with CommandCreator + + public virtual object QueryWithCommandCreator(IDbCommandCreator cc, IResultSetExtractor rse) + { + return QueryWithCommandCreator(cc, rse, null); + } + + public virtual void QueryWithCommandCreator(IDbCommandCreator cc, IRowCallback rowCallback) + { + QueryWithCommandCreator(cc, rowCallback, null); + } + + public virtual IList QueryWithCommandCreator(IDbCommandCreator cc, IRowMapper rowMapper) + { + return QueryWithCommandCreator(cc, rowMapper, null); + } + + public virtual object QueryWithCommandCreator(IDbCommandCreator cc, IResultSetExtractor rse, IDictionary returnedParameters) + { + if (rse == null) + { + throw new ArgumentNullException("Result Set Extractor must not be null"); + } + + return Execute(cc, new AdoResultSetExtractorWithOutputParamsCommandCallback(this, rse, returnedParameters)); + } + + public virtual void QueryWithCommandCreator(IDbCommandCreator cc, IRowCallback rowCallback, IDictionary returnedParameters) + { + if (rowCallback == null) + { + throw new ArgumentNullException("RowCallback must not be null"); + } + + Execute(cc, new AdoRowCallbackCommandCallback(this, rowCallback, returnedParameters)); + } + + public virtual IList QueryWithCommandCreator(IDbCommandCreator cc, IRowMapper rowMapper, IDictionary returnedParameters) + { + if (rowMapper == null) + { + throw new ArgumentNullException("rowMapper must not be null"); + } + + return (IList) Execute(cc, new AdoRowMapperQueryCommandCallback(this, rowMapper, returnedParameters)); + } + + public IDictionary QueryWithCommandCreator(IDbCommandCreator cc, IList namedResultSetProcessors) + { + return (IDictionary) Execute(cc, new AdoResultProcessorsQueryCommandCallback(this, namedResultSetProcessors)); + } + + #endregion + + // DataSet/DataTable related methods. + + #region DataTable Create operations without parameters + + public virtual DataTable DataTableCreate(CommandType commandType, string sql) + { + DataTable dataTable = CreateDataTable(); + DataTableFill(dataTable, commandType, sql); + return dataTable; + } + + public virtual DataTable DataTableCreate(CommandType commandType, string sql, + string tableMappingName) + { + DataTable dataTable = CreateDataTable(); + DataTableFill(dataTable, commandType, sql, tableMappingName); + return dataTable; + } + + public virtual DataTable DataTableCreate(CommandType commandType, string sql, + ITableMapping tableMapping) + { + DataTable dataTable = CreateDataTable(); + DataTableFill(dataTable, commandType, sql, tableMapping); + return dataTable; + } + + public virtual DataTable DataTableCreate(CommandType commandType, string sql, + ITableMapping tableMapping, + IDataAdapterSetter setter) + { + DataTable dataTable = CreateDataTable(); + DataTableFill(dataTable, commandType, sql, tableMapping, setter); + return dataTable; + } + + #endregion + + #region DataTable Create operations with parameters + + public virtual DataTable DataTableCreateWithParams(CommandType commandType, string sql, + IDbParameters parameters) + { + DataTable dataTable = CreateDataTable(); + DataTableFillWithParams(dataTable, commandType, sql, parameters); + return dataTable; + } + + public virtual DataTable DataTableCreateWithParams(CommandType commandType, string sql, + IDbParameters parameters, + string tableMappingName) + { + DataTable dataTable = CreateDataTable(); + DataTableFillWithParams(dataTable, commandType, sql, parameters, tableMappingName); + return dataTable; + } + + public virtual DataTable DataTableCreateWithParams(CommandType commandType, string sql, + IDbParameters parameters, + ITableMapping tableMapping) + { + DataTable dataTable = CreateDataTable(); + DataTableFillWithParams(dataTable, commandType, sql, parameters, tableMapping); + return dataTable; + } + + public virtual DataTable DataTableCreateWithParams(CommandType commandType, string sql, + IDbParameters parameters, + ITableMapping tableMapping, + IDataAdapterSetter dataAdapterSetter) + { + DataTable dataTable = CreateDataTable(); + DataTableFillWithParams(dataTable, commandType, sql, parameters, tableMapping, dataAdapterSetter); + return dataTable; + } + + #endregion + + #region DataTable Fill operations without parameters + + /// + /// Fill a based on a select command that requires no parameters. + /// + /// The to populate + /// The type of command + /// SQL query to execute + /// The number of rows successfully added to or refreshed in the + public virtual int DataTableFill(DataTable dataTable, CommandType commandType, string sql) + { + ValidateFillArguments(dataTable, sql); + + #region Instrumentation + + if (LOG.IsEnabled(LogLevel.Debug)) + { + LOG.LogDebug("Executing DataTableFill " + commandType + "[" + sql + "]"); + } + + #endregion + + ITableMappingCollection mappingCollection = DoCreateMappingCollection(null); + return (int) Execute(new DataAdapterFillCallback(dataTable, + commandType, sql, + mappingCollection, null, null, null)); + } + + public virtual int DataTableFill(DataTable dataTable, CommandType commandType, string sql, + string tableMappingName) + { + ValidateFillArguments(dataTable, sql); + + #region Instrumentation + + if (LOG.IsEnabled(LogLevel.Debug)) + { + LOG.LogDebug("Executing DataTableFill " + commandType + "[" + sql + "] with table mapping name " + tableMappingName); + } + + #endregion + + if (tableMappingName == null) + { + tableMappingName = "Table"; + } + + ITableMappingCollection mappingCollection = DoCreateMappingCollection(new string[] { tableMappingName }); + return (int) Execute(new DataAdapterFillCallback(dataTable, + commandType, sql, + mappingCollection, null, null, null)); + } + + public virtual int DataTableFill(DataTable dataTable, CommandType commandType, string sql, + ITableMapping tableMapping) + { + ValidateFillArguments(dataTable, sql, tableMapping); + ITableMappingCollection mappingCollection = new DataTableMappingCollection(); + mappingCollection.Add((object) tableMapping); + + return (int) Execute(new DataAdapterFillCallback(dataTable, + commandType, sql, + mappingCollection, null, null, null)); + } + + public virtual int DataTableFill(DataTable dataTable, CommandType commandType, string sql, + ITableMapping tableMapping, + IDataAdapterSetter setter) + { + ValidateFillArguments(dataTable, sql, tableMapping); + ITableMappingCollection mappingCollection = new DataTableMappingCollection(); + mappingCollection.Add((object) tableMapping); + return (int) Execute(new DataAdapterFillCallback(dataTable, + commandType, sql, + mappingCollection, setter, null, null)); + } + + #endregion + + #region DataTable Fill operations with parameters + + public virtual int DataTableFillWithParams(DataTable dataTable, CommandType commandType, string sql, + IDbParameters parameters) + { + ValidateFillWithParameterArguments(dataTable, sql, parameters); + ITableMappingCollection mappingCollection = DoCreateMappingCollection(null); + return (int) Execute(new DataAdapterFillCallback(dataTable, + commandType, sql, + mappingCollection, null, null, + parameters)); + } + + public virtual int DataTableFillWithParams(DataTable dataTable, CommandType commandType, string sql, + IDbParameters parameters, + string tableMappingName) + { + ValidateFillWithParameterArguments(dataTable, sql, parameters); + if (tableMappingName == null) + { + tableMappingName = "Table"; + } + + ITableMappingCollection mappingCollection = DoCreateMappingCollection(new string[] { tableMappingName }); + return (int) Execute(new DataAdapterFillCallback(dataTable, + commandType, sql, + mappingCollection, null, null, parameters)); + } + + public virtual int DataTableFillWithParams(DataTable dataTable, CommandType commandType, string sql, + IDbParameters parameters, + ITableMapping tableMapping) + { + ValidateFillWithParameterArguments(dataTable, sql, parameters, tableMapping); + ITableMappingCollection mappingCollection = new DataTableMappingCollection(); + mappingCollection.Add((object) tableMapping); + return (int) Execute(new DataAdapterFillCallback(dataTable, + commandType, sql, + mappingCollection, null, null, parameters)); + } + + public virtual int DataTableFillWithParams(DataTable dataTable, CommandType commandType, string sql, + IDbParameters parameters, + ITableMapping tableMapping, + IDataAdapterSetter dataAdapterSetter) + { + ValidateFillWithParameterArguments(dataTable, sql, parameters, tableMapping); + ITableMappingCollection mappingCollection = new DataTableMappingCollection(); + mappingCollection.Add((object) tableMapping); + return (int) Execute(new DataAdapterFillCallback(dataTable, + commandType, sql, + mappingCollection, dataAdapterSetter, null, parameters)); + } + + #endregion + + #region DataTable Update operations + + //TODO conflict options... + + public virtual int DataTableUpdateWithCommandBuilder(DataTable dataTable, + CommandType commandType, + string selectSql, + IDbParameters parameters, + string tableName) + { + ValidateUpdateWithCommandBuilderArguments(dataTable, tableName, selectSql); + ITableMappingCollection mappingCollection = DoCreateMappingCollection(new string[] { tableName }); + return (int) Execute(new DataAdapterUpdateWithCommandBuilderCallback(dataTable, + DbProvider.CreateCommandBuilder(), + mappingCollection, + commandType, + selectSql, + parameters, + null)); + } + + public virtual int DataTableUpdateWithCommandBuilder(DataTable dataTable, + CommandType commandType, + string selectSql, + IDbParameters parameters, + string tableName, + IDataAdapterSetter dataAdapterSetter) + { + ValidateUpdateWithCommandBuilderArguments(dataTable, tableName, selectSql); + ITableMappingCollection mappingCollection = DoCreateMappingCollection(new string[] { tableName }); + return (int) Execute(new DataAdapterUpdateWithCommandBuilderCallback(dataTable, + DbProvider.CreateCommandBuilder(), + mappingCollection, + commandType, + selectSql, + parameters, + dataAdapterSetter)); + } + + public virtual int DataTableUpdateWithCommandBuilder(DataTable dataTable, + CommandType commandType, + string selectSql, + IDbParameters parameters, + ITableMapping tableMapping, + IDataAdapterSetter dataAdapterSetter) + { + ValidateUpdateWithCommandBuilderArguments(dataTable, tableMapping, selectSql); + ITableMappingCollection mappingCollection = new DataTableMappingCollection(); + mappingCollection.Add(tableMapping); + return (int) Execute(new DataAdapterUpdateWithCommandBuilderCallback(dataTable, + DbProvider.CreateCommandBuilder(), + mappingCollection, + commandType, + selectSql, + parameters, + dataAdapterSetter)); + } + + public virtual int DataTableUpdate(DataTable dataTable, + string tableName, + CommandType insertCommandtype, string insertSql, IDbParameters insertParameters, + CommandType updateCommandtype, string updateSql, IDbParameters updateParameters, + CommandType deleteCommandtype, string deleteSql, IDbParameters deleteParameters) + { + ValidateUpdateArguments(dataTable, tableName); + ITableMappingCollection mappingCollection = DoCreateMappingCollection(new string[] { tableName }); + return DataTableUpdate(dataTable, mappingCollection, + insertCommandtype, insertSql, insertParameters, + updateCommandtype, updateSql, updateParameters, + deleteCommandtype, deleteSql, deleteParameters, + null); + } + + public virtual int DataTableUpdate(DataTable dataTable, + string tableName, + CommandType insertCommandtype, string insertSql, IDbParameters insertParameters, + CommandType updateCommandtype, string updateSql, IDbParameters updateParameters, + CommandType deleteCommandtype, string deleteSql, IDbParameters deleteParameters, + IDataAdapterSetter dataAdapterSetter) + { + ValidateUpdateArguments(dataTable, tableName); + ITableMappingCollection mappingCollection = DoCreateMappingCollection(new string[] { tableName }); + return DataTableUpdate(dataTable, mappingCollection, + insertCommandtype, insertSql, insertParameters, + updateCommandtype, updateSql, updateParameters, + deleteCommandtype, deleteSql, deleteParameters, + dataAdapterSetter); + } + + public virtual int DataTableUpdate(DataTable dataTable, + ITableMapping tableMapping, + CommandType insertCommandtype, string insertSql, IDbParameters insertParameters, + CommandType updateCommandtype, string updateSql, IDbParameters updateParameters, + CommandType deleteCommandtype, string deleteSql, IDbParameters deleteParameters, + IDataAdapterSetter dataAdapterSetter) + { + ValidateUpdateArguments(dataTable, tableMapping); + ITableMappingCollection mappingCollection = new DataTableMappingCollection(); + + mappingCollection.Add((object) tableMapping); + + return DataTableUpdate(dataTable, mappingCollection, + insertCommandtype, insertSql, insertParameters, + updateCommandtype, updateSql, updateParameters, + deleteCommandtype, deleteSql, deleteParameters, + dataAdapterSetter); + } + + #endregion + + #region DataSet Create operations without parameters + + public virtual DataSet DataSetCreate(CommandType commandType, string sql) + { + DataSet dataSet = CreateDataSet(); + DataSetFill(dataSet, commandType, sql); + return dataSet; + } + + public virtual DataSet DataSetCreate(CommandType commandType, string sql, + string[] tableNames) + { + DataSet dataSet = CreateDataSet(); + DataSetFill(dataSet, commandType, sql, tableNames); + return dataSet; + } + + public virtual DataSet DataSetCreate(CommandType commandType, string sql, + ITableMappingCollection tableMapping) + { + DataSet dataSet = CreateDataSet(); + DataSetFill(dataSet, commandType, sql, tableMapping); + return dataSet; + } + + public virtual DataSet DataSetCreate(CommandType commandType, string sql, + ITableMappingCollection tableMapping, + IDataAdapterSetter setter) + { + DataSet dataSet = CreateDataSet(); + DataSetFill(dataSet, commandType, sql, tableMapping, setter); + return dataSet; + } + + public virtual DataSet DataSetCreate(CommandType commandType, string sql, + ITableMappingCollection tableMapping, + IDataAdapterSetter setter, + IDataSetFillLifecycleProcessor fillLifecycleProcessor) + { + DataSet dataSet = CreateDataSet(); + DataSetFill(dataSet, commandType, sql, tableMapping, setter, fillLifecycleProcessor); + return dataSet; + } + + #endregion + + #region DataSet Create operations with parameters + + public virtual DataSet DataSetCreateWithParams(CommandType commandType, string sql, + IDbParameters parameters) + { + DataSet dataSet = CreateDataSet(); + DataSetFillWithParameters(dataSet, commandType, sql, parameters); + return dataSet; + } + + public virtual DataSet DataSetCreateWithParams(CommandType commandType, string sql, + IDbParameters parameters, + string[] tableNames) + { + DataSet dataSet = CreateDataSet(); + DataSetFillWithParameters(dataSet, commandType, sql, parameters, tableNames); + return dataSet; + } + + public virtual DataSet DataSetCreateWithParams(CommandType commandType, string sql, + IDbParameters parameters, + ITableMappingCollection tableMapping) + { + DataSet dataSet = CreateDataSet(); + DataSetFillWithParameters(dataSet, commandType, sql, parameters, tableMapping); + return dataSet; + } + + public virtual DataSet DataSetCreateWithParams(CommandType commandType, string sql, + IDbParameters parameters, + ITableMappingCollection tableMapping, + IDataAdapterSetter dataAdapterSetter) + { + DataSet dataSet = CreateDataSet(); + DataSetFillWithParameters(dataSet, commandType, sql, parameters, tableMapping, dataAdapterSetter); + return dataSet; + } + + public virtual DataSet DataSetCreateWithParams(CommandType commandType, string sql, + IDbParameters parameters, + ITableMappingCollection tableMapping, + IDataAdapterSetter dataAdapterSetter, + IDataSetFillLifecycleProcessor fillLifecycleProcessor) + { + DataSet dataSet = CreateDataSet(); + DataSetFillWithParameters(dataSet, commandType, sql, parameters, tableMapping, dataAdapterSetter, fillLifecycleProcessor); + return dataSet; + } + + #endregion + + #region DataSet Fill operations without parameters + + public virtual int DataSetFill(DataSet dataSet, CommandType commandType, string sql) + { + ValidateFillArguments(dataSet, sql); + + #region Instrumentation + + if (LOG.IsEnabled(LogLevel.Debug)) + { + LOG.LogDebug("Executing DataSetFill " + commandType + "[" + sql + "]"); + } + + #endregion + + ITableMappingCollection mappingCollection = DoCreateMappingCollection(null); + return (int) Execute(new DataAdapterFillCallback(dataSet, + commandType, sql, + mappingCollection, null, null, null)); + } + + public virtual int DataSetFill(DataSet dataSet, CommandType commandType, string sql, string[] tableNames) + { + ValidateFillArguments(dataSet, sql); + + #region Instrumentation + + if (LOG.IsEnabled(LogLevel.Debug)) + { + LOG.LogDebug("Executing DataSetFill " + commandType + "[" + sql + "] with table names " + tableNames); + } + + #endregion + + if (tableNames == null) + { + tableNames = new string[] { "Table" }; + } + + ITableMappingCollection mappingCollection = DoCreateMappingCollection(tableNames); + return (int) Execute(new DataAdapterFillCallback(dataSet, + commandType, sql, + mappingCollection, null, null, null)); + } + + public virtual int DataSetFill(DataSet dataSet, CommandType commandType, string sql, + ITableMappingCollection tableMapping) + { + ValidateFillArguments(dataSet, sql, tableMapping); + return (int) Execute(new DataAdapterFillCallback(dataSet, + commandType, sql, + tableMapping, null, null, null)); + } + + public virtual int DataSetFill(DataSet dataSet, CommandType commandType, string sql, + ITableMappingCollection tableMapping, + IDataAdapterSetter setter) + { + ValidateFillArguments(dataSet, sql, tableMapping); + return (int) Execute(new DataAdapterFillCallback(dataSet, + commandType, sql, + tableMapping, setter, null, null)); + } + + public virtual int DataSetFill(DataSet dataSet, CommandType commandType, string sql, + ITableMappingCollection tableMapping, + IDataAdapterSetter setter, + IDataSetFillLifecycleProcessor fillLifecycleProcessor) + { + ValidateFillArguments(dataSet, sql, tableMapping); + return (int) Execute(new DataAdapterFillCallback(dataSet, + commandType, sql, + tableMapping, setter, fillLifecycleProcessor, null)); + } + + #endregion + + #region DataSet Fill operations with parameters + + public virtual int DataSetFillWithParameters(DataSet dataSet, CommandType commandType, string sql, + IDbParameters parameters) + { + ValidateFillWithParameterArguments(dataSet, sql, parameters); + ITableMappingCollection mappingCollection = DoCreateMappingCollection(null); + return (int) Execute(new DataAdapterFillCallback(dataSet, + commandType, sql, + mappingCollection, null, null, + parameters)); + } + + public virtual int DataSetFillWithParameters(DataSet dataSet, CommandType commandType, string sql, + IDbParameters parameters, + string[] tableNames) + { + ValidateFillWithParameterArguments(dataSet, sql, parameters); + if (tableNames == null) + { + tableNames = new string[] { "Table" }; + } + + ITableMappingCollection tableMapping = DoCreateMappingCollection(tableNames); + return (int) Execute(new DataAdapterFillCallback(dataSet, + commandType, sql, + tableMapping, null, null, parameters)); + } + + public virtual int DataSetFillWithParameters(DataSet dataSet, CommandType commandType, string sql, + IDbParameters parameters, + ITableMappingCollection tableMapping) + { + ValidateFillWithParameterArguments(dataSet, sql, parameters, tableMapping); + return (int) Execute(new DataAdapterFillCallback(dataSet, + commandType, sql, + tableMapping, null, null, parameters)); + } + + public virtual int DataSetFillWithParameters(DataSet dataSet, CommandType commandType, string sql, + IDbParameters parameters, + ITableMappingCollection tableMapping, + IDataAdapterSetter dataAdapterSetter) + { + ValidateFillWithParameterArguments(dataSet, sql, parameters, tableMapping); + return (int) Execute(new DataAdapterFillCallback(dataSet, + commandType, sql, + tableMapping, dataAdapterSetter, null, parameters)); + } + + public virtual int DataSetFillWithParameters(DataSet dataSet, CommandType commandType, string sql, + IDbParameters parameters, + ITableMappingCollection tableMapping, + IDataAdapterSetter dataAdapterSetter, + IDataSetFillLifecycleProcessor fillLifecycleProcessor) + { + ValidateFillWithParameterArguments(dataSet, sql, parameters, tableMapping); + return (int) Execute(new DataAdapterFillCallback(dataSet, + commandType, sql, + tableMapping, dataAdapterSetter, fillLifecycleProcessor, parameters)); + } + + #endregion + + #region DataSet Update operations + + public virtual int DataSetUpdateWithCommandBuilder(DataSet dataSet, + CommandType commandType, + string selectSql, + IDbParameters selectParameters, + string tableName) + { + ValidateUpdateWithCommandBuilderArguments(dataSet, tableName, selectSql); + ITableMappingCollection mappingCollection = DoCreateMappingCollection(new string[] { tableName }); + return (int) Execute(new DataAdapterUpdateWithCommandBuilderCallback(dataSet, + DbProvider.CreateCommandBuilder(), + mappingCollection, + commandType, + selectSql, + selectParameters, + null)); + } + + public virtual int DataSetUpdateWithCommandBuilder(DataSet dataSet, + CommandType commandType, + string selectSql, + IDbParameters selectParameters, + string tableName, + IDataAdapterSetter dataAdapterSetter) + { + ValidateUpdateWithCommandBuilderArguments(dataSet, tableName, selectSql); + ITableMappingCollection mappingCollection = DoCreateMappingCollection(new string[] { tableName }); + return (int) Execute(new DataAdapterUpdateWithCommandBuilderCallback(dataSet, + DbProvider.CreateCommandBuilder(), + mappingCollection, + commandType, + selectSql, + selectParameters, + dataAdapterSetter)); + } + + public virtual int DataSetUpdateWithCommandBuilder(DataSet dataSet, + CommandType commandType, + string selectSql, + IDbParameters selectParameters, + ITableMappingCollection mappingCollection, + IDataAdapterSetter dataAdapterSetter) + { + ValidateUpdateWithCommandBuilderArguments(dataSet, mappingCollection, selectSql); + return (int) Execute(new DataAdapterUpdateWithCommandBuilderCallback(dataSet, + DbProvider.CreateCommandBuilder(), + mappingCollection, + commandType, + selectSql, + selectParameters, + dataAdapterSetter)); + } + + public virtual int DataSetUpdate(DataSet dataSet, + string tableName, + IDbCommand insertCommand, + IDbCommand updateCommand, + IDbCommand deleteCommand) + { + ValidateUpdateArguments(dataSet, tableName); + + ITableMappingCollection mappingCollection = DoCreateMappingCollection(new string[] { tableName }); + + return (int) Execute(new DataAdapterUpdateCallback(dataSet, + mappingCollection, + insertCommand, + updateCommand, + deleteCommand, + null)); + } + + public virtual int DataSetUpdate(DataSet dataSet, + string tableName, + CommandType insertCommandtype, string insertSql, IDbParameters insertParameters, + CommandType updateCommandtype, string updateSql, IDbParameters updateParameters, + CommandType deleteCommandtype, string deleteSql, IDbParameters deleteParameters) + { + ValidateUpdateArguments(dataSet, tableName); + IDbCommand insertCommand = null; + if (insertSql != null) + { + insertCommand = DbProvider.CreateCommand(); + insertCommand.CommandType = insertCommandtype; + insertCommand.CommandText = insertSql; + ParameterUtils.CopyParameters(insertCommand, insertParameters); + } + + IDbCommand updateCommand = null; + if (updateSql != null) + { + updateCommand = DbProvider.CreateCommand(); + updateCommand.CommandType = updateCommandtype; + updateCommand.CommandText = updateSql; + ParameterUtils.CopyParameters(updateCommand, updateParameters); + } + + IDbCommand deleteCommand = null; + if (deleteSql != null) + { + deleteCommand = DbProvider.CreateCommand(); + deleteCommand.CommandType = deleteCommandtype; + deleteCommand.CommandText = deleteSql; + ParameterUtils.CopyParameters(deleteCommand, deleteParameters); + } + + ITableMappingCollection mappingCollection = DoCreateMappingCollection(new string[] { tableName }); + + int returnVal = (int) Execute(new DataAdapterUpdateCallback(dataSet, mappingCollection, + insertCommand, updateCommand, deleteCommand, null)); + + if (insertSql != null) + { + ParameterUtils.CopyParameters(insertParameters, insertCommand); + } + + if (updateSql != null) + { + ParameterUtils.CopyParameters(updateParameters, updateCommand); + } + + if (deleteSql != null) + { + ParameterUtils.CopyParameters(deleteParameters, deleteCommand); + } + + return returnVal; + } + + public virtual int DataSetUpdate(DataSet dataSet, + string tableName, + IDbCommand insertCommand, + IDbCommand updateCommand, + IDbCommand deleteCommand, + IDataAdapterSetter dataAdapterSetter) + { + ValidateUpdateArguments(dataSet, tableName); + ITableMappingCollection tableMapping = DoCreateMappingCollection(new string[] { tableName }); + return (int) Execute(new DataAdapterUpdateCallback(dataSet, + tableMapping, + insertCommand, + updateCommand, + deleteCommand, + dataAdapterSetter)); + } + + public virtual int DataSetUpdate(DataSet dataSet, + ITableMappingCollection tableMapping, + IDbCommand insertCommand, + IDbCommand updateCommand, + IDbCommand deleteCommand) + { + ValidateUpdateArguments(dataSet, tableMapping); + return (int) Execute(new DataAdapterUpdateCallback(dataSet, + tableMapping, + insertCommand, + updateCommand, + deleteCommand, + null)); + } + + public virtual int DataSetUpdate(DataSet dataSet, + ITableMappingCollection tableMapping, + IDbCommand insertCommand, + IDbCommand updateCommand, + IDbCommand deleteCommand, + IDataAdapterSetter dataAdapterSetter) + { + ValidateUpdateArguments(dataSet, tableMapping); + return (int) Execute(new DataAdapterUpdateCallback(dataSet, + tableMapping, + insertCommand, + updateCommand, + deleteCommand, + dataAdapterSetter)); + } + + #endregion + + #region Parameter Creation Helper Methods + + public override IDataParameter[] DeriveParameters(string procedureName, bool includeReturnParameter) + { + return (IDataParameter[]) Execute(new DeriveParametersCommandCallback(DbProvider, procedureName, includeReturnParameter)); + } + + #endregion + + #region Private Helper Methods + + private IDbParameters CreateDbParameters(IDbDataParameter parameter) + { + IDbParameters parameters = new DbParameters(DbProvider); + parameters.AddParameter(parameter); + return parameters; + } + + private IDbParameters CreateDbParameters(IList parameterList) + { + IDbParameters parameters = null; + if (parameterList != null) + { + parameters = new DbParameters(DbProvider); + foreach (IDbDataParameter parameter in parameterList) + { + parameters.AddParameter(parameter); + } + } + + return parameters; + } + + private IDbParameters CreateDbParameters(object[] parameterValues) + { + IDbParameters parameters = null; + if (parameterValues != null) + { + parameters = new DbParameters(DbProvider); + foreach (object parameterValue in parameterValues) + { + parameters.Add(parameterValue); + } + } + + return parameters; + } + + public int DataTableUpdate(DataTable dataTable, + ITableMappingCollection mappingCollection, + CommandType insertCommandtype, string insertSql, IDbParameters insertParameters, + CommandType updateCommandtype, string updateSql, IDbParameters updateParameters, + CommandType deleteCommandtype, string deleteSql, IDbParameters deleteParameters, + IDataAdapterSetter dataAdapterSetter) + { + //TODO - refactor to remove cut-n-pasted code. + IDbCommand insertCommand = null; + if (insertSql != null) + { + insertCommand = DbProvider.CreateCommand(); + insertCommand.CommandType = insertCommandtype; + insertCommand.CommandText = insertSql; + ParameterUtils.CopyParameters(insertCommand, insertParameters); + } + + IDbCommand updateCommand = null; + if (updateSql != null) + { + updateCommand = DbProvider.CreateCommand(); + updateCommand.CommandType = updateCommandtype; + updateCommand.CommandText = updateSql; + ParameterUtils.CopyParameters(updateCommand, updateParameters); + } + + IDbCommand deleteCommand = null; + if (deleteSql != null) + { + deleteCommand = DbProvider.CreateCommand(); + deleteCommand.CommandType = deleteCommandtype; + deleteCommand.CommandText = deleteSql; + ParameterUtils.CopyParameters(deleteCommand, deleteParameters); + } + + int returnVal = (int) Execute(new DataAdapterUpdateCallback(dataTable, mappingCollection, + insertCommand, updateCommand, deleteCommand, null)); + + if (insertSql != null) + { + ParameterUtils.CopyParameters(insertParameters, insertCommand); + } + + if (updateSql != null) + { + ParameterUtils.CopyParameters(updateParameters, updateCommand); + } + + if (deleteSql != null) + { + ParameterUtils.CopyParameters(deleteParameters, deleteCommand); + } + + return returnVal; + } + + #endregion + + #region Protected Helper Methods + + protected virtual void InitExceptionTranslator() + { + if (exceptionTranslator == null) + { + IDbProvider provider = DbProvider; + if (provider != null) + { + exceptionTranslator = new ErrorCodeExceptionTranslator(provider); + } + else + { + exceptionTranslator = new FallbackExceptionTranslator(); + } + } + } + + #endregion + + #region Protected DataAdapter Helper methods + + protected virtual DataTable CreateDataTable() + { + DataTable dataTable = new DataTable(); + dataTable.Locale = CultureInfo.InvariantCulture; + return dataTable; + } + + protected virtual DataSet CreateDataSet() + { + DataSet dataSet = new DataSet(); + dataSet.Locale = CultureInfo.InvariantCulture; + return dataSet; + } + + protected virtual void ValidateFillArguments(DataTable dataTable, string sql) + { + if (dataTable == null) + { + throw new ArgumentNullException("dataTable", "DataTable argument can not be null"); + } + + if (sql == null) + { + throw new ArgumentNullException("sql", "SQL for DataSet Fill operation can not be null"); + } + } + + protected virtual void ValidateFillArguments(DataSet dataSet, string sql) + { + if (dataSet == null) + { + throw new ArgumentNullException("dataSet", "DataSet argument can not be null"); + } + + if (sql == null) + { + throw new ArgumentNullException("sql", "SQL for DataSet Fill operation can not be null"); + } + } + + protected virtual void ValidateFillArguments(DataTable dataTable, string sql, + ITableMapping tableMapping) + { + ValidateFillArguments(dataTable, sql); + if (tableMapping == null) + { + throw new ArgumentNullException("tableMapping", "ITableMapping for DataTable Fill operations can not be null"); + } + } + + protected virtual void ValidateFillArguments(DataSet dataSet, string sql, + ITableMappingCollection tableMappingCollection) + { + ValidateFillArguments(dataSet, sql); + if (tableMappingCollection == null) + { + throw new ArgumentNullException("tableMappingCollection", "ITableMappingCollection for DataSet Fill operations can not be null"); + } + } + + protected virtual void ValidateFillWithParameterArguments(DataTable dataTable, string sql, IDbParameters parameters) + { + ValidateFillArguments(dataTable, sql); + if (parameters == null) + { + throw new ArgumentNullException("parameters", "IDbParameters for DataTable Fill operations can not be null"); + } + } + + protected virtual void ValidateFillWithParameterArguments(DataSet dataSet, string sql, IDbParameters parameters) + { + ValidateFillArguments(dataSet, sql); + if (parameters == null) + { + throw new ArgumentNullException("parameters", "IDbParameters for DataSet Fill operations can not be null"); + } + } + + protected virtual void ValidateFillWithParameterArguments(DataTable dataTable, string sql, IDbParameters parameters, ITableMapping tableMapping) + { + ValidateFillWithParameterArguments(dataTable, sql, parameters); + if (tableMapping == null) + { + throw new ArgumentNullException("tableMapping", "ITableMappingCollection for DataTable Fill operations can not be null"); + } + } + + protected virtual void ValidateFillWithParameterArguments(DataSet dataSet, string sql, IDbParameters parameters, ITableMappingCollection tableMapping) + { + ValidateFillWithParameterArguments(dataSet, sql, parameters); + if (tableMapping == null) + { + throw new ArgumentNullException("tableMapping", "ITableMappingCollection for DataSet Fill operations can not be null"); + } + } + + protected virtual void ValidateUpdateArguments(DataSet dataSet, ITableMappingCollection tableMapping) + { + if (dataSet == null) + { + throw new ArgumentNullException("dataSet", "DataSet argument can not be null for update operation"); + } + + if (tableMapping == null) + { + throw new ArgumentNullException("tableMapping", "TableMappings for DataSet Update operation can not be null"); + } + } + + protected virtual void ValidateUpdateArguments(DataSet dataSet, string tableName) + { + if (dataSet == null) + { + throw new ArgumentNullException("dataSet", "DataSet argument can not be null for update operation"); + } + + if (tableName == null) + { + throw new ArgumentNullException("tableName", "TableName for DataSet Update operation can not be null"); + } + } + + protected virtual void ValidateUpdateArguments(DataTable dataTable, ITableMapping tableMapping) + { + if (dataTable == null) + { + throw new ArgumentNullException("dataTable", "DataTable argument can not be null for DataTable update operation"); + } + + if (tableMapping == null) + { + throw new ArgumentNullException("tableMapping", "TableMapping for DataTable Update operation can not be null"); + } + } + + protected virtual void ValidateUpdateArguments(DataTable dataTable, string tableName) + { + if (dataTable == null) + { + throw new ArgumentNullException("dataTable", "DataTable argument can not be null for DataTable update operation"); + } + + if (tableName == null) + { + throw new ArgumentNullException("tableName", "TableName for DataTable Update operation can not be null"); + } + } + + protected virtual void ValidateUpdateWithCommandBuilderArguments(DataSet dataSet, ITableMappingCollection tableMapping, string selectSql) + { + if (dataSet == null) + { + throw new ArgumentNullException("dataSet", "DataSet can not be null for update operation"); + } + + if (tableMapping == null) + { + throw new ArgumentNullException("tableMapping", "TableMapping for DataSet Update operation can not be null"); + } + + if (selectSql == null) + { + throw new ArgumentNullException("selectSql", "SelectSql for DataSet Update operations can not be null"); + } + } + + protected virtual void ValidateUpdateWithCommandBuilderArguments(DataTable dataTable, string tableName, string selectSql) + { + if (dataTable == null) + { + throw new ArgumentNullException("dataTable", "DataTable can not be null for update operation"); + } + + if (tableName == null) + { + throw new ArgumentNullException("tableName", "TableName for DataSet Update operation can not be null"); + } + + if (selectSql == null) + { + throw new ArgumentNullException("selectSql", "SelectSql for DataSet Update operations can not be null"); + } + } + + protected virtual void ValidateUpdateWithCommandBuilderArguments(DataTable dataTable, ITableMapping tableMapping, string selectSql) + { + if (dataTable == null) + { + throw new ArgumentNullException("dataTable", "DataTable can not be null for update operation"); + } + + if (tableMapping == null) + { + throw new ArgumentNullException("tableMapping", "TableMapping for DataSet Update operation can not be null"); + } + + if (selectSql == null) + { + throw new ArgumentNullException("selectSql", "SelectSql for DataSet Update operations can not be null"); + } + } + + protected virtual void ValidateUpdateWithCommandBuilderArguments(DataSet dataSet, string tableName, string selectSql) + { + if (dataSet == null) + { + throw new ArgumentNullException("dataSet", "DataSet can not be null for update operation"); + } + + if (tableName == null) + { + throw new ArgumentNullException("tableName", "TableName for DataSet Update operation can not be null"); + } + + if (selectSql == null) + { + throw new ArgumentNullException("selectSql", "SelectSql for DataSet Update operations can not be null"); + } + } + + protected virtual ITableMappingCollection DoCreateMappingCollection(string[] dataSetTableNames) + { + DataTableMappingCollection mappingCollection; + + if (dataSetTableNames == null) + { + dataSetTableNames = new string[] { "Table" }; + } + + foreach (string tableName in dataSetTableNames) + { + if (StringUtils.IsNullOrEmpty(tableName)) + { + throw new ArgumentException("TableName for DataTable mapping can not be null or empty"); + } + } + + mappingCollection = new DataTableMappingCollection(); + int counter = 0; + bool isFirstTable = true; + foreach (string dataSetTableName in dataSetTableNames) + { + string sourceTableName; + if (isFirstTable) + { + sourceTableName = "Table"; + isFirstTable = false; + } + else + { + sourceTableName = "Table" + ++counter; + } + + mappingCollection.Add(sourceTableName, dataSetTableName); + } + + return mappingCollection; + } + + #endregion + + #region Private DataAdapter Helper callbacks + + private class DataAdapterFillCallback : IDataAdapterCallback + { + private bool containsDataSet; + private DataSet dataSet; + private DataTable dataTable; + private CommandType commandType; + private string sql; + private ITableMappingCollection mappingCollection; + private IDataAdapterSetter dataAdapterSetter; + private IDataSetFillLifecycleProcessor fillLifecycleProcessor; + private IDbParameters parameters; + + public DataAdapterFillCallback(DataSet dataSet, + CommandType commandType, + string sql, + ITableMappingCollection mappingCollection, + IDataAdapterSetter dataAdapterSetter, + IDataSetFillLifecycleProcessor fillLifecycleProcessor, + IDbParameters parameters) + { + containsDataSet = true; + this.dataSet = dataSet; + this.commandType = commandType; + this.sql = sql; + this.mappingCollection = mappingCollection; + this.dataAdapterSetter = dataAdapterSetter; + this.fillLifecycleProcessor = fillLifecycleProcessor; + this.parameters = parameters; + } + + public DataAdapterFillCallback(DataTable dataTable, + CommandType commandType, + string sql, + ITableMappingCollection mappingCollection, + IDataAdapterSetter dataAdapterSetter, + IDataSetFillLifecycleProcessor fillLifecycleProcessor, + IDbParameters parameters) + { + containsDataSet = false; + this.dataTable = dataTable; + this.commandType = commandType; + this.sql = sql; + this.mappingCollection = mappingCollection; + this.dataAdapterSetter = dataAdapterSetter; + this.fillLifecycleProcessor = fillLifecycleProcessor; + this.parameters = parameters; + } + + public object DoInDataAdapter(IDbDataAdapter dataAdapter) + { + dataAdapter.SelectCommand.CommandType = commandType; + dataAdapter.SelectCommand.CommandText = sql; + //TODO investigate performance of cloning....would need to change signature to + // DataTableMapping[] otherwise... + foreach (DataTableMapping dataTableMapping in mappingCollection) + { + dataAdapter.TableMappings.Add(((ICloneable) dataTableMapping).Clone()); + } + + ParameterUtils.CopyParameters(dataAdapter.SelectCommand, parameters); + + //TODO Review these lifecycle hooks... + if (dataAdapterSetter != null) + { + dataAdapterSetter.SetValues(dataAdapter); + } + + if (fillLifecycleProcessor != null) + { + fillLifecycleProcessor.BeforeFill(dataSet, dataAdapter.TableMappings); + } + + int returnVal; + if (containsDataSet) + { + returnVal = dataAdapter.Fill(dataSet); + } + else + { + //TODO should query metadata to see if supports filling dataTable directly. + if (dataAdapter is DbDataAdapter) + { + returnVal = ((DbDataAdapter) dataAdapter).Fill(dataTable); + } + else + { + //TODO could create DataSet and extract DataTable... for now just throw + throw new DataException("Provider does not support filling DataTable directly"); + } + } + + ParameterUtils.CopyParameters(parameters, dataAdapter.SelectCommand); + + if (fillLifecycleProcessor != null) + { + fillLifecycleProcessor.AfterFill(dataSet, dataAdapter.TableMappings); + } + + return returnVal; + } + } + + private class DataAdapterUpdateCallback : IDataAdapterCallback + { + private bool containsDataSet; + private DataSet dataSet; + private DataTable dataTable; + private ITableMappingCollection mappingCollection; + private IDbCommand insertCommand; + private IDbCommand updateCommand; + private IDbCommand deleteCommand; + private IDataAdapterSetter dataAdapterSetter; + + public DataAdapterUpdateCallback(DataSet dataSet, + ITableMappingCollection mappingCollection, + IDbCommand insertCommand, + IDbCommand updateCommand, + IDbCommand deleteCommand, + IDataAdapterSetter dataAdapterSetter) + { + containsDataSet = true; + this.dataSet = dataSet; + this.mappingCollection = mappingCollection; + this.insertCommand = insertCommand; + this.updateCommand = updateCommand; + this.deleteCommand = deleteCommand; + this.dataAdapterSetter = dataAdapterSetter; + } + + public DataAdapterUpdateCallback(DataTable dataTable, + ITableMappingCollection mappingCollection, + IDbCommand insertCommand, + IDbCommand updateCommand, + IDbCommand deleteCommand, + IDataAdapterSetter dataAdapterSetter) + { + containsDataSet = false; + this.dataTable = dataTable; + this.mappingCollection = mappingCollection; + this.insertCommand = insertCommand; + this.updateCommand = updateCommand; + this.deleteCommand = deleteCommand; + this.dataAdapterSetter = dataAdapterSetter; + } + + #region IDataAdapterCallback Members + + public object DoInDataAdapter(IDbDataAdapter dataAdapter) + { + //TODO - did not make copies of parameters... + if (insertCommand == null && updateCommand == null && deleteCommand == null) + { + throw new ArgumentException("All commands for DataSet Update operation are null"); + } + + if (insertCommand != null) + { + dataAdapter.InsertCommand = insertCommand; + ApplyConnectionAndTx(dataAdapter.InsertCommand, dataAdapter.SelectCommand); + } + + if (updateCommand != null) + { + dataAdapter.UpdateCommand = updateCommand; + ApplyConnectionAndTx(dataAdapter.UpdateCommand, dataAdapter.SelectCommand); + } + + if (deleteCommand != null) + { + dataAdapter.DeleteCommand = deleteCommand; + ApplyConnectionAndTx(dataAdapter.DeleteCommand, dataAdapter.SelectCommand); + } + + foreach (DataTableMapping dataTableMapping in mappingCollection) + { + dataAdapter.TableMappings.Add(((ICloneable) dataTableMapping).Clone()); + } + + if (dataAdapterSetter != null) + { + dataAdapterSetter.SetValues(dataAdapter); + } + + if (containsDataSet) + { + return dataAdapter.Update(dataSet); + } + else + { + //TODO should query metadata to see if supports filling dataTable directly. + if (dataAdapter is DbDataAdapter) + { + return ((DbDataAdapter) dataAdapter).Update(dataTable); + } + else + { + //TODO could create DataSet and extract DataTable... for now just throw + throw new DataException("Provider does not support filling DataTable directly"); + } + } + } + + private static void ApplyConnectionAndTx(IDbCommand dbCommand, IDbCommand sourceCommand) + { + dbCommand.Connection = sourceCommand.Connection; + dbCommand.Transaction = sourceCommand.Transaction; + } + + #endregion + } + + private class DataAdapterUpdateWithCommandBuilderCallback : IDataAdapterCallback + { + private bool containsDataSet; + private DataSet dataSet; + private DataTable dataTable; + private object commandBuilder; + private ITableMappingCollection mappingCollection; + private CommandType selectCommandType; + private string selectSql; + private IDbParameters selectParameters; + private IDataAdapterSetter dataAdapterSetter; + + public DataAdapterUpdateWithCommandBuilderCallback(DataSet dataSet, + object commandBuilder, + ITableMappingCollection mappingCollection, + CommandType selectCommandType, + string selectSql, + IDbParameters selectParameters, + IDataAdapterSetter dataAdapterSetter) + { + containsDataSet = true; + this.dataSet = dataSet; + this.commandBuilder = commandBuilder; + this.mappingCollection = mappingCollection; + this.selectCommandType = selectCommandType; + this.selectSql = selectSql; + this.selectParameters = selectParameters; + this.dataAdapterSetter = dataAdapterSetter; + } + + public DataAdapterUpdateWithCommandBuilderCallback(DataTable dataTable, + object commandBuilder, + ITableMappingCollection mappingCollection, + CommandType selectCommandType, + string selectSql, + IDbParameters selectParameters, + IDataAdapterSetter dataAdapterSetter) + { + containsDataSet = false; + this.dataTable = dataTable; + this.commandBuilder = commandBuilder; + this.mappingCollection = mappingCollection; + this.selectCommandType = selectCommandType; + this.selectSql = selectSql; + this.selectParameters = selectParameters; + this.dataAdapterSetter = dataAdapterSetter; + } + + #region IDataAdapterCallback Members + + public object DoInDataAdapter(IDbDataAdapter dataAdapter) + { + dataAdapter.SelectCommand.CommandType = selectCommandType; + dataAdapter.SelectCommand.CommandText = selectSql; + ParameterUtils.CopyParameters(dataAdapter.SelectCommand, selectParameters); + + foreach (DataTableMapping dataTableMapping in mappingCollection) + { + dataAdapter.TableMappings.Add(((ICloneable) dataTableMapping).Clone()); + } + + if (dataAdapterSetter != null) + { + dataAdapterSetter.SetValues(dataAdapter); + } + + //TODO consider refactoring to put this inside IDbMetadata + PropertyInfo selectCommandProperty = commandBuilder.GetType().GetProperty("DataAdapter", + BindingFlags.DeclaredOnly | + BindingFlags.GetProperty | + BindingFlags.Public | + BindingFlags.Instance + ); + + selectCommandProperty.SetValue(commandBuilder, dataAdapter, null); + + ParameterUtils.CopyParameters(selectParameters, dataAdapter.SelectCommand); + if (containsDataSet) + { + return dataAdapter.Update(dataSet); + } + else + { + //TODO should query metadata to see if supports filling dataTable directly. + if (dataAdapter is DbDataAdapter) + { + return ((DbDataAdapter) dataAdapter).Update(dataTable); + } + else + { + //TODO could create DataSet and extract DataTable... for now just throw + throw new DataException("Provider does not support filling DataTable directly"); + } + } + } + + private static void ApplyConnectionAndTx(IDbCommand dbCommand, IDbCommand sourceCommand) + { + dbCommand.Connection = sourceCommand.Connection; + dbCommand.Transaction = sourceCommand.Transaction; + } + + #endregion + } + + #endregion + + #region Private Helper Classes + + private class AdoStoredProcedureScalarCommandCallback : ICommandCallback + { + public object DoInCommand(IDbCommand command) + { + IDictionary returnedResults = new Hashtable(); + object scalar = command.ExecuteScalar(); + ParameterUtils.ExtractOutputParameters(returnedResults, command); + returnedResults.Add("scalar", scalar); + return returnedResults; + } + } + + private class AdoNonQueryWithOutputParamsCommandCallback : ICommandCallback + { + public object DoInCommand(IDbCommand command) + { + IDictionary returnedResults = new Hashtable(); + int rowsAffected = command.ExecuteNonQuery(); + ParameterUtils.ExtractOutputParameters(returnedResults, command); + returnedResults.Add("rowsAffected", rowsAffected); + return returnedResults; + } + } + + private class AdoResultProcessorsQueryCommandCallback : ICommandCallback + { + private AdoTemplate adoTemplate; + private IList namedResultSetProcessors; + //private IDbParameters declaredParameters; + + public AdoResultProcessorsQueryCommandCallback(AdoTemplate adoTemplate, IList namedResultSetProcessors) + { + //AssertUtils.ArgumentHasLength(namedResultSetProcessors, "namedResultSetProcessors"); + + this.adoTemplate = adoTemplate; + this.namedResultSetProcessors = namedResultSetProcessors; + //this.declaredParameters = declaredParameters; + } + + public object DoInCommand(IDbCommand command) + { + IDictionary returnedResults = new Hashtable(); + int resultSetIndex = 0; + IDataReader reader = null; + try + { + reader = adoTemplate.CreateDataReaderWrapper(command.ExecuteReader()); + + //TODO On >= .NET 2.0 platforms make use of DbDataReader.HasRows property to + // see if there is a result set. now currently assuming matching + // NamedResultSetProcessor/ResultSet pairs. + + do + { + if (namedResultSetProcessors.Count == 0) + { + //We could just have output parameters and/or return value, that is, no result sets + //If we didn't register a result set processor, it is likely that a result set wasn't expected. + break; + } + + NamedResultSetProcessor namedResultSetProcessor = null; + try + { + namedResultSetProcessor + = namedResultSetProcessors[resultSetIndex] as NamedResultSetProcessor; + //Will only have possibility of run-time type error if using QueryWithCommandCreator + if (namedResultSetProcessor == null) + { + LOG.LogError("NamedResultSetProcessor for result set index " + resultSetIndex + + ", is not of expected type NamedResultSetProcessor. Type = " + + namedResultSetProcessors[resultSetIndex].GetType() + + "; Skipping processing for this result set."); + continue; + } + } + catch (IndexOutOfRangeException e) + { + string message = "No NamedResultSetProcessor associated with result set index " + resultSetIndex; + LOG.LogError(e, message); + continue; + } + catch (ArgumentOutOfRangeException e) + { + string message = "No NamedResultSetProcessor associated with result set index " + resultSetIndex; + LOG.LogError(e, message); + continue; + } + + string parameterName = namedResultSetProcessor.Name; + if (namedResultSetProcessor.ResultSetProcessor is IResultSetExtractor) + { + IResultSetExtractor rse = (IResultSetExtractor) namedResultSetProcessor.ResultSetProcessor; + object result = rse.ExtractData(reader); + returnedResults.Add(parameterName, result); + } + else if (namedResultSetProcessor.ResultSetProcessor is IRowMapper) + { + IRowMapper rowMapper = (IRowMapper) namedResultSetProcessor.ResultSetProcessor; + object result = (new RowMapperResultSetExtractor(rowMapper)).ExtractData(reader); + returnedResults.Add(parameterName, result); + } + else if (namedResultSetProcessor.ResultSetProcessor is IRowCallback) + { + IRowCallback rowCallback = (IRowCallback) namedResultSetProcessor.ResultSetProcessor; + (new RowCallbackResultSetExtractor(rowCallback)).ExtractData(reader); + returnedResults.Add(parameterName, "ResultSet returned was processed by an IRowCallback"); + } + + resultSetIndex++; + } while (reader.NextResult()); + } + finally + { + Support.AdoUtils.CloseReader(reader); + } + + ParameterUtils.ExtractOutputParameters(returnedResults, command); + return returnedResults; + } + } + + private class DeriveParametersCommandCallback : ICommandCallback, ICommandTextProvider + { + private IDbProvider provider; + private string procedureName; + private bool includeReturnParameter; + + public DeriveParametersCommandCallback(IDbProvider provider, string procedureName, bool includeReturnParameter) + { + this.provider = provider; + this.procedureName = procedureName; + this.includeReturnParameter = includeReturnParameter; + } + + public string CommandText + { + get { return procedureName; } + } + + public object DoInCommand(IDbCommand command) + { + command.CommandType = CommandType.StoredProcedure; + command.CommandText = procedureName; + + //The DeriveParameter is static in all providers...it seems.... + Type commandBuilderType = provider.DbMetadata.CommandBuilderType; + commandBuilderType.InvokeMember(provider.DbMetadata.CommandBuilderDeriveParametersMethod.Name, + BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod, null, null, + new object[] { command }); + + if (command.Parameters.Count > 0) + { + IDataParameter param = (IDataParameter) command.Parameters[0]; + if (param.Direction == ParameterDirection.ReturnValue) + { + if (!includeReturnParameter) + { + command.Parameters.RemoveAt(0); + } + } + } + + return ParameterUtils.CloneParameters(command); + } + } + + private class AdoRowCallbackCommandCallback : ICommandCallback + { + private AdoTemplate adoTemplate; + private IRowCallback rowCallback; + private IDictionary returnedParameters; + + public AdoRowCallbackCommandCallback(AdoTemplate adoTemplate, IRowCallback rowCallback, IDictionary returnedParameters) + { + this.adoTemplate = adoTemplate; + this.rowCallback = rowCallback; + this.returnedParameters = returnedParameters; + } + + public object DoInCommand(IDbCommand command) + { + //Extract the single returned result set + IDataReader reader = null; + try + { + reader = adoTemplate.CreateDataReaderWrapper(command.ExecuteReader()); + rowCallback.ProcessRow(reader); + } + finally + { + Support.AdoUtils.CloseReader(reader); + } + + ParameterUtils.ExtractOutputParameters(returnedParameters, command); + return null; + } + } + + private class AdoResultSetExtractorWithOutputParamsCommandCallback : ICommandCallback + { + private AdoTemplate adoTemplate; + private IResultSetExtractor rse; + private IDictionary returnedParameters; + + public AdoResultSetExtractorWithOutputParamsCommandCallback(AdoTemplate adoTemplate, IResultSetExtractor rse, IDictionary returnedParameters) + { + this.adoTemplate = adoTemplate; + this.rse = rse; + this.returnedParameters = returnedParameters; + } + + public object DoInCommand(IDbCommand command) + { + object returnVal = null; + //Extract the single returned result set + IDataReader reader = null; + try + { + reader = adoTemplate.CreateDataReaderWrapper(command.ExecuteReader()); + returnVal = rse.ExtractData(reader); + } + finally + { + Support.AdoUtils.CloseReader(reader); + } + + ParameterUtils.ExtractOutputParameters(returnedParameters, command); + return returnVal; + } + } + + private class AdoRowMapperQueryCommandCallback : ICommandCallback + { + private AdoTemplate adoTemplate; + + private IRowMapper rowMapper; + + //private IDbParameters declaredParameters; + private IDictionary returnedParameters; + + public AdoRowMapperQueryCommandCallback(AdoTemplate adoTemplate, IRowMapper rowMapper, IDictionary returnedParameters) + { + this.adoTemplate = adoTemplate; + this.rowMapper = rowMapper; + //this.declaredParameters = declaredParameters; + this.returnedParameters = returnedParameters; + } + + public object DoInCommand(IDbCommand command) + { + IList objectList = null; + //Extract the single returned result set + IDataReader reader = null; + try + { + reader = adoTemplate.CreateDataReaderWrapper(command.ExecuteReader()); + RowMapperResultSetExtractor rse = new RowMapperResultSetExtractor(rowMapper, 1); + objectList = (IList) rse.ExtractData(reader); + } + finally + { + Support.AdoUtils.CloseReader(reader); + } + + ParameterUtils.ExtractOutputParameters(returnedParameters, command); + return objectList; + } + } + + private class ExecuteNonQueryCallbackWithParameters : ICommandCallback, ICommandTextProvider + { + private CommandType commandType; + private string commandText; + private IDbParameters parameters; + + public ExecuteNonQueryCallbackWithParameters(CommandType commandType, string commandText, IDbParameters dbParameters) + { + this.commandType = commandType; + this.commandText = commandText; + parameters = dbParameters; + } + + public string CommandText + { + get { return commandText; } + } + + public Object DoInCommand(IDbCommand command) + { + command.CommandType = commandType; + command.CommandText = commandText; + ParameterUtils.CopyParameters(command, parameters); + Object returnValue = command.ExecuteNonQuery(); + ParameterUtils.CopyParameters(parameters, command); + return returnValue; + } + } + + private class ExecuteNonQueryCallbackWithCommandSetter : ICommandCallback, ICommandTextProvider + { + private CommandType commandType; + private string commandText; + private ICommandSetter commandSetter; + + public ExecuteNonQueryCallbackWithCommandSetter(CommandType commandType, string commandText, ICommandSetter commandSetter) + { + this.commandType = commandType; + this.commandText = commandText; + this.commandSetter = commandSetter; + } + + public string CommandText + { + get { return commandText; } + } + + public Object DoInCommand(IDbCommand command) + { + command.CommandType = commandType; + command.CommandText = commandText; + if (commandSetter != null) + { + commandSetter.SetValues(command); + } + + Object rowsAffected = command.ExecuteNonQuery(); + if (LOG.IsEnabled(LogLevel.Debug)) + { + LOG.LogDebug("ExecuteNonQuery affected " + rowsAffected + " rows"); + } + + return rowsAffected; + } + } + + private class ExecuteScalarCallbackWithParameters : ICommandCallback, ICommandTextProvider + { + private CommandType commandType = CommandType.Text; + private string commandText; + private IDbParameters parameters; + + public ExecuteScalarCallbackWithParameters(CommandType cmdType, string cmdText, IDbParameters dbParameters) + { + commandType = cmdType; + commandText = cmdText; + parameters = dbParameters; + } + + public string CommandText + { + get { return commandText; } + } + + public Object DoInCommand(IDbCommand command) + { + command.CommandType = commandType; + command.CommandText = commandText; + ParameterUtils.CopyParameters(command, parameters); + Object returnValue = command.ExecuteScalar(); + ParameterUtils.CopyParameters(parameters, command); + return returnValue; + } + } + + private class ExecuteScalarCallbackWithCommandSetter : ICommandCallback, ICommandTextProvider + { + private CommandType commandType; + private string commandText; + private ICommandSetter commandSetter; + + public ExecuteScalarCallbackWithCommandSetter(CommandType commandType, string commandText, ICommandSetter commandSetter) + { + this.commandType = commandType; + this.commandText = commandText; + this.commandSetter = commandSetter; + } + + public string CommandText + { + get { return commandText; } + } + + public Object DoInCommand(IDbCommand command) + { + command.CommandType = commandType; + command.CommandText = commandText; + if (commandSetter != null) + { + commandSetter.SetValues(command); + } + + Object returnValue = command.ExecuteScalar(); + if (LOG.IsEnabled(LogLevel.Debug)) + { + LOG.LogDebug("ExecuteScalar return value = " + returnValue); + } + + return returnValue; + } + } + + private class ExecuteCommandCallbackUsingDelegate : ICommandCallback, ICommandTextProvider + { + private CommandDelegate del; + private string commandText; + + public ExecuteCommandCallbackUsingDelegate(CommandDelegate d) + { + del = d; + } + + public string CommandText + { + get { return commandText; } + } + + public Object DoInCommand(IDbCommand command) + { + try + { + return del(command); + } + catch (Exception e) + { + e.GetType(); + commandText = command.CommandText; + throw; + } + } + } + + private class QueryCallbackWithCommandSetter : ICommandCallback, ICommandTextProvider + { + private AdoTemplate adoTemplate; + private IResultSetExtractor rse; + private ResultSetExtractorDelegate resultSetExtractorDelegate; + private ICommandSetter commandSetter; + private CommandType commandType; + private string commandText; + + public QueryCallbackWithCommandSetter(AdoTemplate adoTemplate, CommandType cmdType, string cmdText, IResultSetExtractor rse, ICommandSetter commandSetter) + { + this.adoTemplate = adoTemplate; + commandType = cmdType; + commandText = cmdText; + this.rse = rse; + this.commandSetter = commandSetter; + } + + public QueryCallbackWithCommandSetter(AdoTemplate adoTemplate, CommandType cmdType, string cmdText, ResultSetExtractorDelegate resultSetExtractorDelegate, ICommandSetter commandSetter) + { + this.adoTemplate = adoTemplate; + commandType = cmdType; + commandText = cmdText; + this.resultSetExtractorDelegate = resultSetExtractorDelegate; + this.commandSetter = commandSetter; + } + + public string CommandText + { + get { return commandText; } + } + + public object DoInCommand(IDbCommand command) + { + IDataReader reader = null; + try + { + command.CommandType = commandType; + command.CommandText = commandText; + if (commandSetter != null) + { + commandSetter.SetValues(command); + } + + reader = adoTemplate.CreateDataReaderWrapper(command.ExecuteReader()); + if (rse != null) + { + return rse.ExtractData(reader); + } + else + { + return resultSetExtractorDelegate(reader); + } + } + finally + { + Support.AdoUtils.CloseReader(reader); + } + } + } + + private class QueryCallback : ICommandCallback, ICommandTextProvider + { + private AdoTemplate adoTemplate; + private IResultSetExtractor rse; + private ResultSetExtractorDelegate resultSetExtractorDelegate; + private CommandType commandType; + private string commandText; + private IDbParameters parameters; + + public QueryCallback(AdoTemplate adoTemplate, CommandType cmdType, string cmdText, IResultSetExtractor rse, IDbParameters dbParameters) + { + this.adoTemplate = adoTemplate; + commandType = cmdType; + commandText = cmdText; + this.rse = rse; + parameters = dbParameters; + } + + public QueryCallback(AdoTemplate adoTemplate, CommandType cmdType, string cmdText, ResultSetExtractorDelegate resultSetExtractorDelegate, IDbParameters dbParameters) + { + this.adoTemplate = adoTemplate; + commandType = cmdType; + commandText = cmdText; + this.resultSetExtractorDelegate = resultSetExtractorDelegate; + parameters = dbParameters; + } + + public string CommandText + { + get { return commandText; } + } + + public object DoInCommand(IDbCommand command) + { + IDataReader reader = null; + try + { + command.CommandType = commandType; + command.CommandText = commandText; + ParameterUtils.CopyParameters(command, parameters); + reader = adoTemplate.CreateDataReaderWrapper(command.ExecuteReader()); + object returnValue; + if (rse != null) + { + returnValue = rse.ExtractData(reader); + } + else + { + returnValue = resultSetExtractorDelegate(reader); + } + + return returnValue; + } + finally + { + Support.AdoUtils.CloseReader(reader); + ParameterUtils.CopyParameters(parameters, command); + } + } + } + + #endregion + + /// + /// Creates the data reader wrapper for use in AdoTemplate callback methods. + /// + /// The reader to wrap. + /// The data reader used in AdoTemplate callbacks + public override IDataReader CreateDataReaderWrapper(IDataReader readerToWrap) + { + if (dataReaderWrapperType != null && newDataReaderWrapper != null) + { + IDataReaderWrapper wrapper = (IDataReaderWrapper) newDataReaderWrapper.Invoke(ObjectUtils.EmptyObjects); + wrapper.WrappedReader = readerToWrap; + return wrapper; + } + else + { + return readerToWrap; + } + } } diff --git a/src/Spring/Spring.Data/Data/Core/RowMapperResultSetExtractor.cs b/src/Spring/Spring.Data/Data/Core/RowMapperResultSetExtractor.cs index ef25b1f1..59a7e3c3 100644 --- a/src/Spring/Spring.Data/Data/Core/RowMapperResultSetExtractor.cs +++ b/src/Spring/Spring.Data/Data/Core/RowMapperResultSetExtractor.cs @@ -1,12 +1,12 @@ /* * Copyright � 2002-2011 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. @@ -14,89 +14,90 @@ * limitations under the License. */ -namespace Spring.Data.Core +namespace Spring.Data.Core; + +/// +/// Adapter implementation of the ResultSetExtractor interface that delegates +/// to a RowMapper which is supposed to create an object for each row. +/// Each object is added to the results List of this ResultSetExtractor. +/// +/// +/// Useful for the typical case of one object per row in the database table. +/// The number of entries in the results list will match the number of rows. +///

+/// Note that a RowMapper object is typically stateless and thus reusable; +/// just the RowMapperResultSetExtractor adapter is stateful. +///

+///

+/// As an alternative consider subclassing MappingAdoQuery from the +/// Spring.Data.Objects namespace: Instead of working with separate +/// AdoTemplate and IRowMapper objects you can have executable +/// query objects (containing row-mapping logic) there. +///

+///
+/// Mark Pollack (.NET) +public class RowMapperResultSetExtractor : IResultSetExtractor { + private readonly IRowMapper rowMapper; + private readonly RowMapperDelegate rowMapperDelegate; + private readonly int rowsExpected; + /// - /// Adapter implementation of the ResultSetExtractor interface that delegates - /// to a RowMapper which is supposed to create an object for each row. - /// Each object is added to the results List of this ResultSetExtractor. + /// Initializes a new instance of the class. /// - /// - /// Useful for the typical case of one object per row in the database table. - /// The number of entries in the results list will match the number of rows. - ///

- /// Note that a RowMapper object is typically stateless and thus reusable; - /// just the RowMapperResultSetExtractor adapter is stateful. - ///

- ///

- /// As an alternative consider subclassing MappingAdoQuery from the - /// Spring.Data.Objects namespace: Instead of working with separate - /// AdoTemplate and IRowMapper objects you can have executable - /// query objects (containing row-mapping logic) there. - ///

- ///
- /// Mark Pollack (.NET) - public class RowMapperResultSetExtractor : IResultSetExtractor + public RowMapperResultSetExtractor(IRowMapper rowMapper) : this(rowMapper, 0, null) { - private readonly IRowMapper rowMapper; - private readonly RowMapperDelegate rowMapperDelegate; - private readonly int rowsExpected; + } - /// - /// Initializes a new instance of the class. - /// - public RowMapperResultSetExtractor(IRowMapper rowMapper) : this(rowMapper,0, null) - { - } - - public RowMapperResultSetExtractor(IRowMapper rowMapper, int rowsExpected) : this(rowMapper, rowsExpected, null) - { - } - public RowMapperResultSetExtractor(IRowMapper rowMapper, int rowsExpected, IDataReaderWrapper dataReaderWrapper) - { - //TODO use datareaderwrapper - this.rowMapper = rowMapper ?? throw new ArgumentNullException(nameof(rowMapper)); - this.rowsExpected = rowsExpected; - } + public RowMapperResultSetExtractor(IRowMapper rowMapper, int rowsExpected) : this(rowMapper, rowsExpected, null) + { + } - public RowMapperResultSetExtractor(RowMapperDelegate rowMapperDelegate) - : this(rowMapperDelegate, 0, null) - { - } + public RowMapperResultSetExtractor(IRowMapper rowMapper, int rowsExpected, IDataReaderWrapper dataReaderWrapper) + { + //TODO use datareaderwrapper + this.rowMapper = rowMapper ?? throw new ArgumentNullException(nameof(rowMapper)); + this.rowsExpected = rowsExpected; + } - public RowMapperResultSetExtractor(RowMapperDelegate rowMapperDelegate, int rowsExpected) - : this(rowMapperDelegate, rowsExpected, null) - { - } - public RowMapperResultSetExtractor(RowMapperDelegate rowMapperDelegate, int rowsExpected, IDataReaderWrapper dataReaderWrapper) - { - //TODO use datareaderwrapper - this.rowMapperDelegate = rowMapperDelegate ?? throw new ArgumentNullException(nameof(rowMapperDelegate)); - this.rowsExpected = rowsExpected; - } + public RowMapperResultSetExtractor(RowMapperDelegate rowMapperDelegate) + : this(rowMapperDelegate, 0, null) + { + } - public object ExtractData(System.Data.IDataReader reader) + public RowMapperResultSetExtractor(RowMapperDelegate rowMapperDelegate, int rowsExpected) + : this(rowMapperDelegate, rowsExpected, null) + { + } + + public RowMapperResultSetExtractor(RowMapperDelegate rowMapperDelegate, int rowsExpected, IDataReaderWrapper dataReaderWrapper) + { + //TODO use datareaderwrapper + this.rowMapperDelegate = rowMapperDelegate ?? throw new ArgumentNullException(nameof(rowMapperDelegate)); + this.rowsExpected = rowsExpected; + } + + public object ExtractData(System.Data.IDataReader reader) + { + // Use the more efficient collection if we know how many rows to expect: + // ArrayList in case of a known row count, LinkedList if unknown + var results = new List(rowsExpected); + int rowNum = 0; + if (rowMapper != null) { - // Use the more efficient collection if we know how many rows to expect: - // ArrayList in case of a known row count, LinkedList if unknown - var results = new List(rowsExpected); - int rowNum = 0; - if (rowMapper != null) + while (reader.Read()) { - while (reader.Read()) - { - results.Add(rowMapper.MapRow(reader, rowNum++)); - } + results.Add(rowMapper.MapRow(reader, rowNum++)); } - else - { - while (reader.Read()) - { - results.Add(rowMapperDelegate(reader, rowNum++)); - } - } - - return results; } + else + { + while (reader.Read()) + { + results.Add(rowMapperDelegate(reader, rowNum++)); + } + } + + return results; } } diff --git a/src/Spring/Spring.Data/Data/Core/ServiceDomainPlatformTransactionManager.cs b/src/Spring/Spring.Data/Data/Core/ServiceDomainPlatformTransactionManager.cs index b25b9ddd..7bb167cf 100644 --- a/src/Spring/Spring.Data/Data/Core/ServiceDomainPlatformTransactionManager.cs +++ b/src/Spring/Spring.Data/Data/Core/ServiceDomainPlatformTransactionManager.cs @@ -25,364 +25,358 @@ using Spring.Objects.Factory; using Spring.Transaction; using Spring.Transaction.Support; -namespace Spring.Data.Core +namespace Spring.Data.Core; + +/// +/// Transaction Manager that uses EnterpriseServices to access the +/// MS-DTC. It requires the support of 'Services without Components' +/// functionality which is available on Win 2003 and Win XP SP2. +/// +/// Mark Pollack (.NET) +public class ServiceDomainPlatformTransactionManager : AbstractPlatformTransactionManager, IInitializingObject { + private IServiceDomainAdapter txAdapter; + + private bool trackingEnabled = true; + private string trackingAppName = "Spring.NET"; + private string trackingComponentName = "ServiceDomainPlatformTransactionManager"; + + #region Constructor (s) + /// - /// Transaction Manager that uses EnterpriseServices to access the - /// MS-DTC. It requires the support of 'Services without Components' - /// functionality which is available on Win 2003 and Win XP SP2. + /// Initializes a new instance of the class. /// - /// Mark Pollack (.NET) - public class ServiceDomainPlatformTransactionManager : AbstractPlatformTransactionManager, IInitializingObject + public ServiceDomainPlatformTransactionManager() { - private IServiceDomainAdapter txAdapter; + } - private bool trackingEnabled = true; - private string trackingAppName = "Spring.NET"; - private string trackingComponentName = "ServiceDomainPlatformTransactionManager"; + /// + /// Initializes a new instance of the class. + /// + /// This is indented only for unit testing purposes and should not be + /// called by production application code. + /// The tx adapter. + public ServiceDomainPlatformTransactionManager(IServiceDomainAdapter txAdapter) + { + this.txAdapter = txAdapter; + } - #region Constructor (s) - /// - /// Initializes a new instance of the class. - /// - public ServiceDomainPlatformTransactionManager() + #endregion + + /// + /// Gets or sets a value indicating whether tracking is enabled. + /// + /// true if tracking is enabled; otherwise, false. + public bool TrackingEnabled + { + get { return trackingEnabled; } + set { trackingEnabled = value; } + } + + /// + /// Gets or sets a text string that corresponds to the application ID under which tracker information is reported. + /// The default value is 'Spring.NET' + /// + /// The name of the tracking app. + public string TrackingAppName + { + get { return trackingAppName; } + set { trackingAppName = value; } + } + + /// + /// Gets or sets a text string that corresponds to the context name under which tracker information is reported. + /// + /// The name of the tracking component. + public string TrackingComponentName + { + get { return trackingComponentName; } + set { trackingComponentName = value; } + } + + public void AfterPropertiesSet() + { + //TODO decide what should be validated for advanced configurations. + } + + protected override object DoGetTransaction() + { + ServiceDomainTransactionObject txObject = new ServiceDomainTransactionObject(); + if (txAdapter != null) { - + txObject.ServiceDomainAdapter = txAdapter; } - /// - /// Initializes a new instance of the class. - /// - /// This is indented only for unit testing purposes and should not be - /// called by production application code. - /// The tx adapter. - public ServiceDomainPlatformTransactionManager(IServiceDomainAdapter txAdapter) + return txObject; + } + + protected override bool IsExistingTransaction(object transaction) + { + ServiceDomainTransactionObject txObject = (ServiceDomainTransactionObject) transaction; + if (txObject.ServiceDomainAdapter.IsInTransaction) { - this.txAdapter = txAdapter; + return true; + } + else + { + return false; + } + } + + protected override void DoBegin(object transaction, ITransactionDefinition definition) + { + try + { + ServiceDomainTransactionObject txObject = (ServiceDomainTransactionObject) transaction; + + DoServiceDomainBegin(txObject, definition); + } + catch (PlatformNotSupportedException ex) + { + throw new TransactionSystemException("ServiceDomain failure on begin of transaction. Platform does not support EnterpriseServices 'Services without Components'", ex); + } + catch (Exception e) + { + throw new CannotCreateTransactionException("ServiceDomain failure on begin of transaction", e); + } + } + + private void DoServiceDomainBegin(ServiceDomainTransactionObject serviceDomainTxObject, ITransactionDefinition definition) + { + SimpleServiceConfig serviceConfig = CreateServiceConfig(definition); + //The context is created when we call Enter. + serviceDomainTxObject.ServiceDomainAdapter.Enter(serviceConfig); + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug("Context created. TransactionId = " + ContextUtil.TransactionId + + ", ActivityId = " + ContextUtil.ActivityId); + } + } + + protected override object DoSuspend(object transaction) + { + // Passing the current transaction object, literally an 'object' as the 'suspended resource', + // even though it is not used just to avoid passing null + // ServiceDomainPlatformTransactionManager is not binding any resources to the local thread, instead delegating to + // System.EnterpriseServices to handle thread local resources. + return transaction; + } + + protected override void DoResume(object transaction, object suspendedResources) + { + } + + private SimpleServiceConfig CreateServiceConfig(ITransactionDefinition definition) + { + SimpleServiceConfig serviceConfig = new SimpleServiceConfig(); + + //TODO investigate BringYourOwnTransaction and TipUrl properties of ServiceConfig + serviceConfig.TransactionDescription = definition.Name; + + serviceConfig.TrackingEnabled = TrackingEnabled; + serviceConfig.TrackingAppName = TrackingAppName; + serviceConfig.TrackingComponentName = TrackingComponentName; + + ApplyPropagationBehavior(serviceConfig, definition); + + ApplyIsolationLevel(serviceConfig, definition); + + // infinite==-1 would cause transactions to be aborted immediately! + if (definition.TransactionTimeout != Timeout.Infinite) + { + serviceConfig.TransactionTimeout = definition.TransactionTimeout; } - #endregion + return serviceConfig; + } - - /// - /// Gets or sets a value indicating whether tracking is enabled. - /// - /// true if tracking is enabled; otherwise, false. - public bool TrackingEnabled + protected void ApplyIsolationLevel(SimpleServiceConfig serviceConfig, ITransactionDefinition definition) + { + switch (definition.TransactionIsolationLevel) { - get { return trackingEnabled; } - set { trackingEnabled = value; } + case System.Data.IsolationLevel.Chaos: + if (log.IsEnabled(LogLevel.Information)) + { + log.LogInformation("IsolationLevel Chaos does not have a direct counterpart in EnterpriseServices, using Any"); + } + + serviceConfig.IsolationLevel = TransactionIsolationLevel.Any; + break; + case System.Data.IsolationLevel.ReadCommitted: + serviceConfig.IsolationLevel = TransactionIsolationLevel.ReadCommitted; + break; + case System.Data.IsolationLevel.ReadUncommitted: + serviceConfig.IsolationLevel = TransactionIsolationLevel.ReadUncommitted; + break; + case System.Data.IsolationLevel.RepeatableRead: + serviceConfig.IsolationLevel = TransactionIsolationLevel.RepeatableRead; + break; + case System.Data.IsolationLevel.Serializable: + serviceConfig.IsolationLevel = TransactionIsolationLevel.Serializable; + break; + case System.Data.IsolationLevel.Snapshot: + if (log.IsEnabled(LogLevel.Information)) + { + log.LogInformation("IsolationLevel Snapshot does not have a direct counterpart in EnterpriseServices, using ReadCommitted. Introduced in SqlServer 2005. Consider using System.Transactions for transaction management instead."); + } + + serviceConfig.IsolationLevel = TransactionIsolationLevel.ReadCommitted; //err on the side of consistency + break; + case System.Data.IsolationLevel.Unspecified: + serviceConfig.IsolationLevel = TransactionIsolationLevel.Any; + break; } + } - /// - /// Gets or sets a text string that corresponds to the application ID under which tracker information is reported. - /// The default value is 'Spring.NET' - /// - /// The name of the tracking app. - public string TrackingAppName + protected void ApplyPropagationBehavior(SimpleServiceConfig serviceConfig, ITransactionDefinition definition) + { + if (definition.PropagationBehavior == TransactionPropagation.Required) { - get { return trackingAppName; } - set { trackingAppName = value; } + serviceConfig.TransactionOption = TransactionOption.Required; } - - /// - /// Gets or sets a text string that corresponds to the context name under which tracker information is reported. - /// - /// The name of the tracking component. - public string TrackingComponentName + else if (definition.PropagationBehavior == TransactionPropagation.RequiresNew) { - get { return trackingComponentName; } - set { trackingComponentName = value; } + serviceConfig.TransactionOption = TransactionOption.RequiresNew; } - - public void AfterPropertiesSet() + else if (definition.PropagationBehavior == TransactionPropagation.Supports) { - //TODO decide what should be validated for advanced configurations. + serviceConfig.TransactionOption = TransactionOption.Supported; } - - protected override object DoGetTransaction() + else if (definition.PropagationBehavior == TransactionPropagation.NotSupported) { - ServiceDomainTransactionObject txObject = new ServiceDomainTransactionObject(); - if (txAdapter != null) - { - txObject.ServiceDomainAdapter = txAdapter; - } - return txObject; + serviceConfig.TransactionOption = TransactionOption.NotSupported; } - - - - protected override bool IsExistingTransaction(object transaction) + else if (definition.PropagationBehavior == TransactionPropagation.Never) + { + //TODO check the validity of this mapping + serviceConfig.TransactionOption = TransactionOption.Disabled; + } + else + { + //TODO Should we throw an exception instead? + log.LogWarning("The requested transaction propagation option " + + definition.PropagationBehavior + " is not supported. " + + "Defaulting to Never(Disabled) "); + } + } + + protected override void DoCommit(DefaultTransactionStatus status) + { + ServiceDomainTransactionObject txObject = (ServiceDomainTransactionObject) status.Transaction; + bool globalRollbackOnly = status.GlobalRollbackOnly; + try { - ServiceDomainTransactionObject txObject = (ServiceDomainTransactionObject)transaction; if (txObject.ServiceDomainAdapter.IsInTransaction) { - return true; - } - else - { - return false; - } - } - - protected override void DoBegin(object transaction, ITransactionDefinition definition) - { - try - { - ServiceDomainTransactionObject txObject = (ServiceDomainTransactionObject)transaction; - - DoServiceDomainBegin(txObject, definition); - } - catch (PlatformNotSupportedException ex) - { - throw new TransactionSystemException("ServiceDomain failure on begin of transaction. Platform does not support EnterpriseServices 'Services without Components'", ex); - } - catch (Exception e) - { - throw new CannotCreateTransactionException("ServiceDomain failure on begin of transaction", e); - } - } - - private void DoServiceDomainBegin(ServiceDomainTransactionObject serviceDomainTxObject, ITransactionDefinition definition) - { - SimpleServiceConfig serviceConfig = CreateServiceConfig(definition); - //The context is created when we call Enter. - serviceDomainTxObject.ServiceDomainAdapter.Enter(serviceConfig); - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug("Context created. TransactionId = " + ContextUtil.TransactionId - + ", ActivityId = " + ContextUtil.ActivityId); - } - } - - protected override object DoSuspend(object transaction) - { - // Passing the current transaction object, literally an 'object' as the 'suspended resource', - // even though it is not used just to avoid passing null - // ServiceDomainPlatformTransactionManager is not binding any resources to the local thread, instead delegating to - // System.EnterpriseServices to handle thread local resources. - return transaction; - } - - protected override void DoResume(object transaction, object suspendedResources) - { - } - - private SimpleServiceConfig CreateServiceConfig(ITransactionDefinition definition) - { - SimpleServiceConfig serviceConfig = new SimpleServiceConfig(); - - //TODO investigate BringYourOwnTransaction and TipUrl properties of ServiceConfig - serviceConfig.TransactionDescription = definition.Name; - - serviceConfig.TrackingEnabled = TrackingEnabled; - serviceConfig.TrackingAppName = TrackingAppName; - serviceConfig.TrackingComponentName = TrackingComponentName; - - ApplyPropagationBehavior(serviceConfig, definition); - - ApplyIsolationLevel(serviceConfig, definition); - - // infinite==-1 would cause transactions to be aborted immediately! - if(definition.TransactionTimeout != Timeout.Infinite) - { - serviceConfig.TransactionTimeout = definition.TransactionTimeout; - } - return serviceConfig; - } - - protected void ApplyIsolationLevel(SimpleServiceConfig serviceConfig, ITransactionDefinition definition) - { - switch (definition.TransactionIsolationLevel) - { - - case System.Data.IsolationLevel.Chaos: - if (log.IsEnabled(LogLevel.Information)) - { - log.LogInformation("IsolationLevel Chaos does not have a direct counterpart in EnterpriseServices, using Any"); - } - serviceConfig.IsolationLevel = TransactionIsolationLevel.Any; - break; - case System.Data.IsolationLevel.ReadCommitted: - serviceConfig.IsolationLevel = TransactionIsolationLevel.ReadCommitted; - break; - case System.Data.IsolationLevel.ReadUncommitted: - serviceConfig.IsolationLevel = TransactionIsolationLevel.ReadUncommitted; - break; - case System.Data.IsolationLevel.RepeatableRead: - serviceConfig.IsolationLevel = TransactionIsolationLevel.RepeatableRead; - break; - case System.Data.IsolationLevel.Serializable: - serviceConfig.IsolationLevel = TransactionIsolationLevel.Serializable; - break; - case System.Data.IsolationLevel.Snapshot: - if (log.IsEnabled(LogLevel.Information)) - { - log.LogInformation("IsolationLevel Snapshot does not have a direct counterpart in EnterpriseServices, using ReadCommitted. Introduced in SqlServer 2005. Consider using System.Transactions for transaction management instead."); - } - serviceConfig.IsolationLevel = TransactionIsolationLevel.ReadCommitted; //err on the side of consistency - break; - case System.Data.IsolationLevel.Unspecified: - serviceConfig.IsolationLevel = TransactionIsolationLevel.Any; - break; - } - - } - - protected void ApplyPropagationBehavior(SimpleServiceConfig serviceConfig, ITransactionDefinition definition) - { - if (definition.PropagationBehavior == TransactionPropagation.Required) - { - serviceConfig.TransactionOption = TransactionOption.Required; - } - else if (definition.PropagationBehavior == TransactionPropagation.RequiresNew) - { - serviceConfig.TransactionOption = TransactionOption.RequiresNew; - } - else if (definition.PropagationBehavior == TransactionPropagation.Supports) - { - serviceConfig.TransactionOption = TransactionOption.Supported; - } - else if (definition.PropagationBehavior == TransactionPropagation.NotSupported) - { - serviceConfig.TransactionOption = TransactionOption.NotSupported; - } - else if (definition.PropagationBehavior == TransactionPropagation.Never) - { - //TODO check the validity of this mapping - serviceConfig.TransactionOption = TransactionOption.Disabled; - } else - { - //TODO Should we throw an exception instead? - log.LogWarning("The requested transaction propagation option " + - definition.PropagationBehavior + " is not supported. " + - "Defaulting to Never(Disabled) "); - } - } - - - - - protected override void DoCommit(DefaultTransactionStatus status) - { - ServiceDomainTransactionObject txObject = (ServiceDomainTransactionObject) status.Transaction; - bool globalRollbackOnly = status.GlobalRollbackOnly; - try - { - if (txObject.ServiceDomainAdapter.IsInTransaction) + if (txObject.ServiceDomainAdapter.MyTransactionVote == TransactionVote.Commit) { - - if (txObject.ServiceDomainAdapter.MyTransactionVote == TransactionVote.Commit) - { - txObject.ServiceDomainAdapter.SetComplete(); - } - else - { - txObject.ServiceDomainAdapter.SetAbort(); - } + txObject.ServiceDomainAdapter.SetComplete(); } - TransactionStatus serviceDomainTxstatus = txObject.ServiceDomainAdapter.Leave(); - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug("ServiceDomain Transaction Status upon leaving ServiceDomain = " + serviceDomainTxstatus); - } - txObject.TransactionStatus = serviceDomainTxstatus; - if (!globalRollbackOnly && serviceDomainTxstatus == TransactionStatus.Aborted) - { - throw new UnexpectedRollbackException("Transaction unexpectedly rolled-back (maybe due to a timeout)"); - } - } - catch (PlatformNotSupportedException ex) - { - throw new TransactionSystemException("Failure on Commit. Platform does not support EnterpriseServices 'Services without Components'", ex); - } - catch (Exception e) - { - throw new TransactionSystemException("Failure upon Leaving ServiceDomain (for Commit)", e); - } - - } - - protected override void DoRollback(DefaultTransactionStatus status) - { - ServiceDomainTransactionObject txObject = (ServiceDomainTransactionObject)status.Transaction; - if (txObject.ServiceDomainAdapter.IsInTransaction) - { - try + else { txObject.ServiceDomainAdapter.SetAbort(); - txObject.ServiceDomainAdapter.Leave(); - } - catch (PlatformNotSupportedException ex) - { - throw new TransactionSystemException("Failure on Rollback. Platform does not support EnterpriseServices 'Services without Components'", ex); - } - catch (Exception e) - { - throw new Spring.Transaction.TransactionSystemException("Failure upon Leaving ServiceDomain (for Rollback)", e); } } + + TransactionStatus serviceDomainTxstatus = txObject.ServiceDomainAdapter.Leave(); + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug("ServiceDomain Transaction Status upon leaving ServiceDomain = " + serviceDomainTxstatus); + } + + txObject.TransactionStatus = serviceDomainTxstatus; + if (!globalRollbackOnly && serviceDomainTxstatus == TransactionStatus.Aborted) + { + throw new UnexpectedRollbackException("Transaction unexpectedly rolled-back (maybe due to a timeout)"); + } } - - protected override void DoSetRollbackOnly(DefaultTransactionStatus status) + catch (PlatformNotSupportedException ex) + { + throw new TransactionSystemException("Failure on Commit. Platform does not support EnterpriseServices 'Services without Components'", ex); + } + catch (Exception e) + { + throw new TransactionSystemException("Failure upon Leaving ServiceDomain (for Commit)", e); + } + } + + protected override void DoRollback(DefaultTransactionStatus status) + { + ServiceDomainTransactionObject txObject = (ServiceDomainTransactionObject) status.Transaction; + if (txObject.ServiceDomainAdapter.IsInTransaction) { - ServiceDomainTransactionObject txObject = (ServiceDomainTransactionObject)status.Transaction; - if (status.Debug) - { - log.LogDebug("Setting transaction rollback-only"); - } try { - txObject.ServiceDomainAdapter.MyTransactionVote = TransactionVote.Abort; + txObject.ServiceDomainAdapter.SetAbort(); + txObject.ServiceDomainAdapter.Leave(); } - catch (Exception ex) + catch (PlatformNotSupportedException ex) { - throw new TransactionSystemException("Failure on System.Transactions.Transaction.Current.Rollback", ex); + throw new TransactionSystemException("Failure on Rollback. Platform does not support EnterpriseServices 'Services without Components'", ex); } + catch (Exception e) + { + throw new Spring.Transaction.TransactionSystemException("Failure upon Leaving ServiceDomain (for Rollback)", e); + } + } + } + protected override void DoSetRollbackOnly(DefaultTransactionStatus status) + { + ServiceDomainTransactionObject txObject = (ServiceDomainTransactionObject) status.Transaction; + if (status.Debug) + { + log.LogDebug("Setting transaction rollback-only"); } - protected override bool ShouldCommitOnGlobalRollbackOnly + try { - get { return true; } + txObject.ServiceDomainAdapter.MyTransactionVote = TransactionVote.Abort; + } + catch (Exception ex) + { + throw new TransactionSystemException("Failure on System.Transactions.Transaction.Current.Rollback", ex); + } + } + + protected override bool ShouldCommitOnGlobalRollbackOnly + { + get { return true; } + } + + public class ServiceDomainTransactionObject : ISmartTransactionObject + { + private TransactionStatus transactionStatus; + private IServiceDomainAdapter serviceDomainAdapter; + + public ServiceDomainTransactionObject() + { + serviceDomainAdapter = new DefaultServiceDomainAdapter(); } - - public class ServiceDomainTransactionObject : ISmartTransactionObject + public IServiceDomainAdapter ServiceDomainAdapter { - private TransactionStatus transactionStatus; - private IServiceDomainAdapter serviceDomainAdapter; + get { return serviceDomainAdapter; } + set { serviceDomainAdapter = value; } + } + public TransactionStatus TransactionStatus + { + get { return transactionStatus; } + set { transactionStatus = value; } + } - public ServiceDomainTransactionObject() + public bool RollbackOnly + { + get { - serviceDomainAdapter = new DefaultServiceDomainAdapter(); - } - - public IServiceDomainAdapter ServiceDomainAdapter - { - get { return serviceDomainAdapter; } - set { serviceDomainAdapter = value; } - } - - public TransactionStatus TransactionStatus - { - get { return transactionStatus; } - set { transactionStatus = value; } - } - - public bool RollbackOnly - { - get + if (serviceDomainAdapter.MyTransactionVote == TransactionVote.Abort) { - if ( serviceDomainAdapter.MyTransactionVote == TransactionVote.Abort) - { - return true; - } - else - { - return false; - } + return true; + } + else + { + return false; } } } diff --git a/src/Spring/Spring.Data/Data/Core/TxScopeTransactionManager.cs b/src/Spring/Spring.Data/Data/Core/TxScopeTransactionManager.cs index 7ad8b35e..bb1da75e 100644 --- a/src/Spring/Spring.Data/Data/Core/TxScopeTransactionManager.cs +++ b/src/Spring/Spring.Data/Data/Core/TxScopeTransactionManager.cs @@ -21,254 +21,253 @@ using Spring.Objects.Factory; using Spring.Transaction; using Spring.Transaction.Support; -namespace Spring.Data.Core +namespace Spring.Data.Core; + +/// +/// TransactionManager that uses TransactionScope provided by System.Transactions. +/// +/// Mark Pollack (.NET) +public class TxScopeTransactionManager : AbstractPlatformTransactionManager, IInitializingObject { + private readonly ITransactionScopeAdapter txAdapter; + /// - /// TransactionManager that uses TransactionScope provided by System.Transactions. + /// Initializes a new instance of the class. /// - /// Mark Pollack (.NET) - public class TxScopeTransactionManager : AbstractPlatformTransactionManager, IInitializingObject + public TxScopeTransactionManager() { - private readonly ITransactionScopeAdapter txAdapter; + // noop + } - /// - /// Initializes a new instance of the class. - /// - public TxScopeTransactionManager() + /// + /// Initializes a new instance of the class. + /// + /// This is indented only for unit testing purposes and should not be + /// called by production application code. + /// The tx adapter. + public TxScopeTransactionManager(ITransactionScopeAdapter txAdapter) + { + this.txAdapter = txAdapter; + } + + /// + /// No-op initialization + /// + public void AfterPropertiesSet() + { + // placeholder for more advanced configurations. + } + + protected override object DoGetTransaction() + { + PromotableTxScopeTransactionObject txObject = new PromotableTxScopeTransactionObject(); + + if (txAdapter != null) { - // noop + txObject.TxScopeAdapter = txAdapter; } - /// - /// Initializes a new instance of the class. - /// - /// This is indented only for unit testing purposes and should not be - /// called by production application code. - /// The tx adapter. - public TxScopeTransactionManager(ITransactionScopeAdapter txAdapter) + return txObject; + } + + protected override bool IsExistingTransaction(object transaction) + { + PromotableTxScopeTransactionObject txObject = + (PromotableTxScopeTransactionObject) transaction; + return txObject.TxScopeAdapter.IsExistingTransaction; + } + + protected override void DoBegin(object transaction, ITransactionDefinition definition) + { + PromotableTxScopeTransactionObject txObject = + (PromotableTxScopeTransactionObject) transaction; + try { - this.txAdapter = txAdapter; + DoTxScopeBegin(txObject, definition); } - - /// - /// No-op initialization - /// - public void AfterPropertiesSet() + catch (Exception e) { - // placeholder for more advanced configurations. - } - - protected override object DoGetTransaction() - { - PromotableTxScopeTransactionObject txObject = new PromotableTxScopeTransactionObject(); - - if (txAdapter != null) - { - txObject.TxScopeAdapter = txAdapter; - } - - return txObject; - } - - protected override bool IsExistingTransaction(object transaction) - { - PromotableTxScopeTransactionObject txObject = - (PromotableTxScopeTransactionObject) transaction; - return txObject.TxScopeAdapter.IsExistingTransaction; - } - - protected override void DoBegin(object transaction, ITransactionDefinition definition) - { - PromotableTxScopeTransactionObject txObject = - (PromotableTxScopeTransactionObject) transaction; - try - { - DoTxScopeBegin(txObject, definition); - } - catch (Exception e) - { - throw new CannotCreateTransactionException("Transaction Scope failure on begin", e); - } - } - - protected override object DoSuspend(object transaction) - { - // Passing the current TxScopeAdapter as the 'suspended resource', even though it is not used just to avoid passing null - // TxScopeTransactionManager is not binding any resources to the local thread, instead delegating to - // System.Transactions to handle thread local resources. - PromotableTxScopeTransactionObject txMgrStateObject = (PromotableTxScopeTransactionObject) transaction; - return txMgrStateObject.TxScopeAdapter; - } - - protected override void DoResume(object transaction, object suspendedResources) - { - } - - protected override void DoCommit(DefaultTransactionStatus status) - { - PromotableTxScopeTransactionObject txObject = - (PromotableTxScopeTransactionObject) status.Transaction; - try - { - txObject.TxScopeAdapter.Complete(); - txObject.TxScopeAdapter.Dispose(); - } - catch (TransactionAbortedException ex) - { - throw new UnexpectedRollbackException("Transaction unexpectedly rolled back (maybe due to a timeout)", - ex); - } - catch (TransactionInDoubtException ex) - { - throw new HeuristicCompletionException(TransactionOutcomeState.Unknown, ex); - } - catch (Exception ex) - { - throw new TransactionSystemException("Failure on Transaction Scope Commit", ex); - } - } - - protected override void DoRollback(DefaultTransactionStatus status) - { - PromotableTxScopeTransactionObject txObject = - (PromotableTxScopeTransactionObject) status.Transaction; - - try - { - txObject.TxScopeAdapter.Dispose(); - } - catch (Exception e) - { - throw new TransactionSystemException("Failure on Transaction Scope rollback.", e); - } - } - - protected override void DoSetRollbackOnly(DefaultTransactionStatus status) - { - if (status.Debug) - { - log.LogDebug("Setting transaction rollback-only"); - } - - try - { - System.Transactions.Transaction.Current.Rollback(); - } - catch (Exception ex) - { - throw new TransactionSystemException("Failure on System.Transactions.Transaction.Current.Rollback", ex); - } - } - - protected override bool ShouldCommitOnGlobalRollbackOnly => true; - - private void DoTxScopeBegin( - PromotableTxScopeTransactionObject txObject, - ITransactionDefinition definition) - { - TransactionScopeOption txScopeOption = CreateTransactionScopeOptions(definition); - TransactionOptions txOptions = CreateTransactionOptions(definition); - txObject.TxScopeAdapter.CreateTransactionScope( - txScopeOption, - txOptions, - definition.AsyncFlowOption); - } - - private static TransactionOptions CreateTransactionOptions(ITransactionDefinition definition) - { - TransactionOptions txOptions = new TransactionOptions(); - switch (definition.TransactionIsolationLevel) - { - case System.Data.IsolationLevel.Chaos: - txOptions.IsolationLevel = IsolationLevel.Chaos; - break; - case System.Data.IsolationLevel.ReadCommitted: - txOptions.IsolationLevel = IsolationLevel.ReadCommitted; - break; - case System.Data.IsolationLevel.ReadUncommitted: - txOptions.IsolationLevel = IsolationLevel.ReadUncommitted; - break; - case System.Data.IsolationLevel.RepeatableRead: - txOptions.IsolationLevel = IsolationLevel.RepeatableRead; - break; - case System.Data.IsolationLevel.Serializable: - txOptions.IsolationLevel = IsolationLevel.Serializable; - break; - case System.Data.IsolationLevel.Snapshot: - txOptions.IsolationLevel = IsolationLevel.Snapshot; - break; - case System.Data.IsolationLevel.Unspecified: - txOptions.IsolationLevel = IsolationLevel.Unspecified; - break; - } - - if (definition.TransactionTimeout != DefaultTransactionDefinition.TIMEOUT_DEFAULT) - { - txOptions.Timeout = new TimeSpan(0, 0, definition.TransactionTimeout); - } - - return txOptions; - } - - private static TransactionScopeOption CreateTransactionScopeOptions(ITransactionDefinition definition) - { - TransactionScopeOption txScopeOption; - if (definition.PropagationBehavior == TransactionPropagation.Required) - { - txScopeOption = TransactionScopeOption.Required; - } - else if (definition.PropagationBehavior == TransactionPropagation.RequiresNew) - { - txScopeOption = TransactionScopeOption.RequiresNew; - } - else if (definition.PropagationBehavior == TransactionPropagation.NotSupported) - { - txScopeOption = TransactionScopeOption.Suppress; - } - else - { - throw new TransactionSystemException("Transaction Propagation Behavior" + - definition.PropagationBehavior + - " not supported by TransactionScope. Use Required or RequiredNew"); - } - - return txScopeOption; - } - - /// - /// The transaction resource object that encapsulates the state and functionality - /// contained in TransactionScope and Transaction.Current via the ITransactionScopeAdapter - /// property. - /// - public class PromotableTxScopeTransactionObject : ISmartTransactionObject - { - private ITransactionScopeAdapter txScopeAdapter; - - /// - /// Initializes a new instance of the class. - /// Will create an instance of . - /// - public PromotableTxScopeTransactionObject() - { - txScopeAdapter = new DefaultTransactionScopeAdapter(); - } - - /// - /// Gets or sets the transaction scope adapter. - /// - /// The transaction scope adapter. - public ITransactionScopeAdapter TxScopeAdapter - { - get => txScopeAdapter; - set => txScopeAdapter = value; - } - - /// - /// Return whether the transaction is internally marked as rollback-only. - /// - /// - /// True of the transaction is marked as rollback-only. - public bool RollbackOnly => txScopeAdapter.RollbackOnly; + throw new CannotCreateTransactionException("Transaction Scope failure on begin", e); } } + + protected override object DoSuspend(object transaction) + { + // Passing the current TxScopeAdapter as the 'suspended resource', even though it is not used just to avoid passing null + // TxScopeTransactionManager is not binding any resources to the local thread, instead delegating to + // System.Transactions to handle thread local resources. + PromotableTxScopeTransactionObject txMgrStateObject = (PromotableTxScopeTransactionObject) transaction; + return txMgrStateObject.TxScopeAdapter; + } + + protected override void DoResume(object transaction, object suspendedResources) + { + } + + protected override void DoCommit(DefaultTransactionStatus status) + { + PromotableTxScopeTransactionObject txObject = + (PromotableTxScopeTransactionObject) status.Transaction; + try + { + txObject.TxScopeAdapter.Complete(); + txObject.TxScopeAdapter.Dispose(); + } + catch (TransactionAbortedException ex) + { + throw new UnexpectedRollbackException("Transaction unexpectedly rolled back (maybe due to a timeout)", + ex); + } + catch (TransactionInDoubtException ex) + { + throw new HeuristicCompletionException(TransactionOutcomeState.Unknown, ex); + } + catch (Exception ex) + { + throw new TransactionSystemException("Failure on Transaction Scope Commit", ex); + } + } + + protected override void DoRollback(DefaultTransactionStatus status) + { + PromotableTxScopeTransactionObject txObject = + (PromotableTxScopeTransactionObject) status.Transaction; + + try + { + txObject.TxScopeAdapter.Dispose(); + } + catch (Exception e) + { + throw new TransactionSystemException("Failure on Transaction Scope rollback.", e); + } + } + + protected override void DoSetRollbackOnly(DefaultTransactionStatus status) + { + if (status.Debug) + { + log.LogDebug("Setting transaction rollback-only"); + } + + try + { + System.Transactions.Transaction.Current.Rollback(); + } + catch (Exception ex) + { + throw new TransactionSystemException("Failure on System.Transactions.Transaction.Current.Rollback", ex); + } + } + + protected override bool ShouldCommitOnGlobalRollbackOnly => true; + + private void DoTxScopeBegin( + PromotableTxScopeTransactionObject txObject, + ITransactionDefinition definition) + { + TransactionScopeOption txScopeOption = CreateTransactionScopeOptions(definition); + TransactionOptions txOptions = CreateTransactionOptions(definition); + txObject.TxScopeAdapter.CreateTransactionScope( + txScopeOption, + txOptions, + definition.AsyncFlowOption); + } + + private static TransactionOptions CreateTransactionOptions(ITransactionDefinition definition) + { + TransactionOptions txOptions = new TransactionOptions(); + switch (definition.TransactionIsolationLevel) + { + case System.Data.IsolationLevel.Chaos: + txOptions.IsolationLevel = IsolationLevel.Chaos; + break; + case System.Data.IsolationLevel.ReadCommitted: + txOptions.IsolationLevel = IsolationLevel.ReadCommitted; + break; + case System.Data.IsolationLevel.ReadUncommitted: + txOptions.IsolationLevel = IsolationLevel.ReadUncommitted; + break; + case System.Data.IsolationLevel.RepeatableRead: + txOptions.IsolationLevel = IsolationLevel.RepeatableRead; + break; + case System.Data.IsolationLevel.Serializable: + txOptions.IsolationLevel = IsolationLevel.Serializable; + break; + case System.Data.IsolationLevel.Snapshot: + txOptions.IsolationLevel = IsolationLevel.Snapshot; + break; + case System.Data.IsolationLevel.Unspecified: + txOptions.IsolationLevel = IsolationLevel.Unspecified; + break; + } + + if (definition.TransactionTimeout != DefaultTransactionDefinition.TIMEOUT_DEFAULT) + { + txOptions.Timeout = new TimeSpan(0, 0, definition.TransactionTimeout); + } + + return txOptions; + } + + private static TransactionScopeOption CreateTransactionScopeOptions(ITransactionDefinition definition) + { + TransactionScopeOption txScopeOption; + if (definition.PropagationBehavior == TransactionPropagation.Required) + { + txScopeOption = TransactionScopeOption.Required; + } + else if (definition.PropagationBehavior == TransactionPropagation.RequiresNew) + { + txScopeOption = TransactionScopeOption.RequiresNew; + } + else if (definition.PropagationBehavior == TransactionPropagation.NotSupported) + { + txScopeOption = TransactionScopeOption.Suppress; + } + else + { + throw new TransactionSystemException("Transaction Propagation Behavior" + + definition.PropagationBehavior + + " not supported by TransactionScope. Use Required or RequiredNew"); + } + + return txScopeOption; + } + + /// + /// The transaction resource object that encapsulates the state and functionality + /// contained in TransactionScope and Transaction.Current via the ITransactionScopeAdapter + /// property. + /// + public class PromotableTxScopeTransactionObject : ISmartTransactionObject + { + private ITransactionScopeAdapter txScopeAdapter; + + /// + /// Initializes a new instance of the class. + /// Will create an instance of . + /// + public PromotableTxScopeTransactionObject() + { + txScopeAdapter = new DefaultTransactionScopeAdapter(); + } + + /// + /// Gets or sets the transaction scope adapter. + /// + /// The transaction scope adapter. + public ITransactionScopeAdapter TxScopeAdapter + { + get => txScopeAdapter; + set => txScopeAdapter = value; + } + + /// + /// Return whether the transaction is internally marked as rollback-only. + /// + /// + /// True of the transaction is marked as rollback-only. + public bool RollbackOnly => txScopeAdapter.RollbackOnly; + } } diff --git a/src/Spring/Spring.Data/Data/DuplicateKeyException.cs b/src/Spring/Spring.Data/Data/DuplicateKeyException.cs index 236d23a5..44661e91 100644 --- a/src/Spring/Spring.Data/Data/DuplicateKeyException.cs +++ b/src/Spring/Spring.Data/Data/DuplicateKeyException.cs @@ -21,103 +21,104 @@ using System.Runtime.Serialization; using Spring.Dao; -namespace Spring.Data +namespace Spring.Data; + +/// +/// Exception thrown when an attempt to insert or update data +/// results in violation of an primary key or unique constraint. +/// Note that this is not necessarily a purely relational concept; +/// unique primary keys are required by most database types. +/// +/// Thomas Risberg +/// Mark Pollack (.NET) +[Serializable] +public class DuplicateKeyException : DataIntegrityViolationException { - /// - /// Exception thrown when an attempt to insert or update data - /// results in violation of an primary key or unique constraint. - /// Note that this is not necessarily a purely relational concept; - /// unique primary keys are required by most database types. - /// - /// Thomas Risberg - /// Mark Pollack (.NET) - [Serializable] - public class DuplicateKeyException : DataIntegrityViolationException - { - #region Fields + #region Fields - /// - /// SQL that led to the problem - /// - private string sql; + /// + /// SQL that led to the problem + /// + private string sql; - #endregion + #endregion - #region Constructor (s) - /// - /// Initializes a new instance of the class. - /// - public DuplicateKeyException() - { - } + #region Constructor (s) - /// - /// Initializes a new instance of the class. - /// - /// A message about the exception. - public DuplicateKeyException(string message): base(message) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// A message about the exception. - /// The inner exception. - public DuplicateKeyException(string message, Exception inner): base(message, inner) - { - } - - - /// - /// Initializes a new instance of the class. - /// - /// name of the current task. - /// The offending SQL statment - /// The root cause. - public DuplicateKeyException(string task, String sql, Exception ex) : base(task + "; Duplicate key for SQL [" + sql + "]; " + ex.Message, ex) - { - this.sql = sql; - } - /// - protected DuplicateKeyException(SerializationInfo info, StreamingContext context) : base(info, context) { } - - #endregion - - #region Properties - - /// - /// Gets the SQL that caused the exception - /// - /// The SQL that caused the exception. - public string Sql - { - get - { - return sql; - } - } - #endregion - - #region Methods - - #endregion - - #region ISerializable Members - - /// - /// When overridden in a derived class, sets the - /// with information about the exception. - /// - /// The that holds the serialized object data about the exception being thrown. - /// The that contains contextual information about the source or destination. - /// The parameter is a null reference ( in Visual Basic). - public override void GetObjectData(SerializationInfo info, StreamingContext context) - { - info.AddValue( "sql", sql ); - base.GetObjectData( info, context ); - } - - #endregion + /// + /// Initializes a new instance of the class. + /// + public DuplicateKeyException() + { } + + /// + /// Initializes a new instance of the class. + /// + /// A message about the exception. + public DuplicateKeyException(string message) : base(message) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// A message about the exception. + /// The inner exception. + public DuplicateKeyException(string message, Exception inner) : base(message, inner) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// name of the current task. + /// The offending SQL statment + /// The root cause. + public DuplicateKeyException(string task, String sql, Exception ex) : base(task + "; Duplicate key for SQL [" + sql + "]; " + ex.Message, ex) + { + this.sql = sql; + } + + /// + protected DuplicateKeyException(SerializationInfo info, StreamingContext context) : base(info, context) { } + + #endregion + + #region Properties + + /// + /// Gets the SQL that caused the exception + /// + /// The SQL that caused the exception. + public string Sql + { + get + { + return sql; + } + } + + #endregion + + #region Methods + + #endregion + + #region ISerializable Members + + /// + /// When overridden in a derived class, sets the + /// with information about the exception. + /// + /// The that holds the serialized object data about the exception being thrown. + /// The that contains contextual information about the source or destination. + /// The parameter is a null reference ( in Visual Basic). + public override void GetObjectData(SerializationInfo info, StreamingContext context) + { + info.AddValue("sql", sql); + base.GetObjectData(info, context); + } + + #endregion } diff --git a/src/Spring/Spring.Data/Data/Generic/AdoDaoSupport.cs b/src/Spring/Spring.Data/Data/Generic/AdoDaoSupport.cs index 0f564a5d..07cda015 100644 --- a/src/Spring/Spring.Data/Data/Generic/AdoDaoSupport.cs +++ b/src/Spring/Spring.Data/Data/Generic/AdoDaoSupport.cs @@ -23,122 +23,114 @@ using Spring.Dao.Support; using Spring.Data.Common; using Spring.Data.Support; -namespace Spring.Data.Generic +namespace Spring.Data.Generic; + +/// +/// Convenient super class for ADO.NET data access objects using generics. +/// +/// +/// Requires a IDBProvider to be set, providing a +/// AdoTemplate based on it to subclasses. +/// This base class is mainly intended for AdoTemplate usage. +/// +public class AdoDaoSupport : DaoSupport { + private AdoTemplate adoTemplate; + /// - /// Convenient super class for ADO.NET data access objects using generics. + /// The DbProvider instance used by this DAO + /// + public IDbProvider DbProvider + { + set + { + adoTemplate = CreateAdoTemplate(value); + } + get + { + if (adoTemplate != null) + { + return adoTemplate.DbProvider; + } + else + { + return null; + } + } + } + + /// + /// Set the AdoTemplate for this DAO explicity, as + /// an alternative to specifying a IDbProvider + /// + public AdoTemplate AdoTemplate + { + set + { + adoTemplate = value; + } + get + { + return adoTemplate; + } + } + + protected override void CheckDaoConfig() + { + if (adoTemplate == null) + { + throw new ArgumentException("DbProvider or AdoTemplate is required"); + } + } + + protected IDbConnection Connection + { + get + { + return ConnectionUtils.GetConnection(DbProvider); + } + } + + protected IAdoExceptionTranslator ExceptionTranslator + { + get + { + return null; //Investigate AdoExceptionTranslator on AdoAccessor + } + } + + protected void DisposeConnection(IDbConnection conn, IDbProvider dbProvider) + { + ConnectionUtils.DisposeConnection(conn, dbProvider); + } + + /// + /// Create a AdoTemplate for a given DbProvider + /// Only invoked if populating the DAO with a DbProvider reference. /// /// - /// Requires a IDBProvider to be set, providing a - /// AdoTemplate based on it to subclasses. - /// This base class is mainly intended for AdoTemplate usage. + /// Can be overriden in subclasses to provide AdoTemplate instances + /// with a different configuration, or a cusotm AdoTemplate subclass. /// - public class AdoDaoSupport : DaoSupport + /// The DbProvider to create a AdoTemplate for + protected virtual AdoTemplate CreateAdoTemplate(IDbProvider dbProvider) { - private AdoTemplate adoTemplate; - - /// - /// The DbProvider instance used by this DAO - /// - public IDbProvider DbProvider - { - set - { - adoTemplate = CreateAdoTemplate(value); - } - get - { - if (adoTemplate != null) - { - return adoTemplate.DbProvider; - } - else - { - return null; - } - } - - } - - /// - /// Set the AdoTemplate for this DAO explicity, as - /// an alternative to specifying a IDbProvider - /// - public AdoTemplate AdoTemplate - { - set - { - adoTemplate = value; - } - get - { - return adoTemplate; - } - - } - - protected override void CheckDaoConfig() - { - if (adoTemplate == null) - { - throw new ArgumentException("DbProvider or AdoTemplate is required"); - } - } - - protected IDbConnection Connection - { - get - { - return ConnectionUtils.GetConnection(DbProvider); - } - } - - protected IAdoExceptionTranslator ExceptionTranslator - { - get - { - return null; //Investigate AdoExceptionTranslator on AdoAccessor - } - } - - protected void DisposeConnection(IDbConnection conn, IDbProvider dbProvider) - { - ConnectionUtils.DisposeConnection(conn, dbProvider); - } - - - /// - /// Create a AdoTemplate for a given DbProvider - /// Only invoked if populating the DAO with a DbProvider reference. - /// - /// - /// Can be overriden in subclasses to provide AdoTemplate instances - /// with a different configuration, or a cusotm AdoTemplate subclass. - /// - /// The DbProvider to create a AdoTemplate for - protected virtual AdoTemplate CreateAdoTemplate(IDbProvider dbProvider) - { - return new AdoTemplate(dbProvider); - } - - /// - /// Convenience method to create a parameters builder. - /// - /// Virtual for sublcasses to override with custom - /// implementation. - /// A new DbParameterBuilder - protected virtual IDbParametersBuilder CreateDbParametersBuilder() - { - return new DbParametersBuilder(DbProvider); - } - - protected virtual IDbParameters CreateDbParameters() - { - return AdoTemplate.CreateDbParameters(); - } - - + return new AdoTemplate(dbProvider); + } + /// + /// Convenience method to create a parameters builder. + /// + /// Virtual for sublcasses to override with custom + /// implementation. + /// A new DbParameterBuilder + protected virtual IDbParametersBuilder CreateDbParametersBuilder() + { + return new DbParametersBuilder(DbProvider); + } + protected virtual IDbParameters CreateDbParameters() + { + return AdoTemplate.CreateDbParameters(); } } diff --git a/src/Spring/Spring.Data/Data/Generic/AdoTemplate.cs b/src/Spring/Spring.Data/Data/Generic/AdoTemplate.cs index 115801ac..571ea1fc 100644 --- a/src/Spring/Spring.Data/Data/Generic/AdoTemplate.cs +++ b/src/Spring/Spring.Data/Data/Generic/AdoTemplate.cs @@ -29,1675 +29,1627 @@ using Spring.Data.Core; using Spring.Data.Support; using Spring.Util; -namespace Spring.Data.Generic +namespace Spring.Data.Generic; + +/// +/// This is the central class in the Spring.Data.Generic namespace. +/// It simplifies the use of ADO.NET and helps to avoid commons errors. +/// +/// Mark Pollack (.NET) +public class AdoTemplate : AdoAccessor, IAdoOperations { + #region Logging Definition + + private static readonly ILogger LOG = LogManager.GetLogger(); + + #endregion + + #region Fields + + private Core.AdoTemplate classicAdoTemplate; + + #endregion + + #region Constructors + /// - /// This is the central class in the Spring.Data.Generic namespace. - /// It simplifies the use of ADO.NET and helps to avoid commons errors. + /// Initializes a new instance of the class. /// - /// Mark Pollack (.NET) - public class AdoTemplate : AdoAccessor, IAdoOperations + public AdoTemplate() + : base() { + classicAdoTemplate = new Core.AdoTemplate(); + } - #region Logging Definition + /// + /// Initializes a new instance of the class. + /// + /// The provider. + public AdoTemplate(IDbProvider provider) + { + classicAdoTemplate = new Core.AdoTemplate(provider); + AfterPropertiesSet(); + } - private static readonly ILogger LOG = LogManager.GetLogger(); + /// + /// Initializes a new instance of the class. + /// + /// The database provider. + /// if set to false + /// lazily initialize the ErrorCodeExceptionTranslator. + public AdoTemplate(IDbProvider provider, bool lazyInit) + { + classicAdoTemplate = new Core.AdoTemplate(provider, lazyInit); + AfterPropertiesSet(); + } - #endregion + /// + /// Initializes a new instance of the class. + /// + /// Useful if you have a subclass of Spring.Data.Core.AdoTemplate. + /// The classic ADO template. + public AdoTemplate(Core.AdoTemplate classicAdoTemplate) + { + this.classicAdoTemplate = classicAdoTemplate; + AfterPropertiesSet(); + } - #region Fields + #endregion - private Core.AdoTemplate classicAdoTemplate; + #region Properties - #endregion + /// + /// An instance of a DbProvider implementation. + /// + public override IDbProvider DbProvider + { + get { return classicAdoTemplate.DbProvider; } + set { classicAdoTemplate.DbProvider = value; } + } - #region Constructors + /// + /// Gets or sets a value indicating whether to lazily initialize the + /// IAdoExceptionTranslator for this accessor, on first encounter of a + /// exception from the data provider. Default is "true"; can be switched to + /// "false" for initialization on startup. + /// + /// true if to lazy initialize the IAdoExceptionTranslator; + /// otherwise, false. + public override bool LazyInit + { + get { return classicAdoTemplate.LazyInit; } + set { classicAdoTemplate.LazyInit = value; } + } - /// - /// Initializes a new instance of the class. - /// - public AdoTemplate() - : base() + /// + /// Gets or sets the exception translator. If no custom translator is provided, a default + /// is used. + /// + /// The exception translator. + public override IAdoExceptionTranslator ExceptionTranslator + { + get { return classicAdoTemplate.ExceptionTranslator; } + set { classicAdoTemplate.ExceptionTranslator = value; } + } + + /// + /// Gets or set the System.Type to use to create an instance of IDataReaderWrapper + /// for the purpose of having defaults values to use in case of DBNull values read + /// from IDataReader. + /// + /// The type of the data reader wrapper. + public override Type DataReaderWrapperType + { + get { return classicAdoTemplate.DataReaderWrapperType; } + set { classicAdoTemplate.DataReaderWrapperType = value; } + } + + /// + /// Gets the 'Classic' AdoTemplate in Spring.Data + /// + /// + /// Useful to access methods that return non-generic collections. + /// + /// The 'Classic; AdoTemplate in Spring.Data. + public Core.AdoTemplate ClassicAdoTemplate + { + get { return classicAdoTemplate; } + } + + /// + /// Gets or sets the command timeout for IDbCommands that this AdoTemplate executes. It also + /// sets the value of the contained 'ClassicAdoTemplate'. + /// + /// The command timeout. + /// Default is 0, indicating to use the database provider's default. + /// Any timeout specified here will be overridden by the remaining + /// transaction timeout when executing within a transaction that has a + /// timeout specified at the transaction level. + /// + public override int CommandTimeout + { + get { return base.CommandTimeout; } + set { - classicAdoTemplate = new Core.AdoTemplate(); + base.CommandTimeout = value; + classicAdoTemplate.CommandTimeout = value; } + } - /// - /// Initializes a new instance of the class. - /// - /// The provider. - public AdoTemplate(IDbProvider provider) + #endregion + + #region General Execute Callback methods + + /// + /// Execute a ADO.NET operation on a command object using a interface based callback. + /// + /// the callback to execute + /// object returned from callback + public virtual T Execute(ICommandCallback action) + { + ConnectionTxPair connectionTxPairToUse = GetConnectionTxPair(DbProvider); + + IDbCommand command = null; + try { - classicAdoTemplate = new Core.AdoTemplate(provider); - AfterPropertiesSet(); - } - - /// - /// Initializes a new instance of the class. - /// - /// The database provider. - /// if set to false - /// lazily initialize the ErrorCodeExceptionTranslator. - public AdoTemplate(IDbProvider provider, bool lazyInit) - { - classicAdoTemplate = new Core.AdoTemplate(provider, lazyInit); - AfterPropertiesSet(); - } - - /// - /// Initializes a new instance of the class. - /// - /// Useful if you have a subclass of Spring.Data.Core.AdoTemplate. - /// The classic ADO template. - public AdoTemplate(Core.AdoTemplate classicAdoTemplate) - { - this.classicAdoTemplate = classicAdoTemplate; - AfterPropertiesSet(); - } - #endregion - - #region Properties - - /// - /// An instance of a DbProvider implementation. - /// - public override IDbProvider DbProvider - { - get { return classicAdoTemplate.DbProvider; } - set { classicAdoTemplate.DbProvider = value; } - } - - /// - /// Gets or sets a value indicating whether to lazily initialize the - /// IAdoExceptionTranslator for this accessor, on first encounter of a - /// exception from the data provider. Default is "true"; can be switched to - /// "false" for initialization on startup. - /// - /// true if to lazy initialize the IAdoExceptionTranslator; - /// otherwise, false. - public override bool LazyInit - { - get { return classicAdoTemplate.LazyInit; } - set { classicAdoTemplate.LazyInit = value; } - } - - /// - /// Gets or sets the exception translator. If no custom translator is provided, a default - /// is used. - /// - /// The exception translator. - public override IAdoExceptionTranslator ExceptionTranslator - { - get { return classicAdoTemplate.ExceptionTranslator; } - set { classicAdoTemplate.ExceptionTranslator = value; } - } - - - /// - /// Gets or set the System.Type to use to create an instance of IDataReaderWrapper - /// for the purpose of having defaults values to use in case of DBNull values read - /// from IDataReader. - /// - /// The type of the data reader wrapper. - public override Type DataReaderWrapperType - { - get { return classicAdoTemplate.DataReaderWrapperType; } - set { classicAdoTemplate.DataReaderWrapperType = value; } - } - - /// - /// Gets the 'Classic' AdoTemplate in Spring.Data - /// - /// - /// Useful to access methods that return non-generic collections. - /// - /// The 'Classic; AdoTemplate in Spring.Data. - public Core.AdoTemplate ClassicAdoTemplate - { - get { return classicAdoTemplate; } - } - - /// - /// Gets or sets the command timeout for IDbCommands that this AdoTemplate executes. It also - /// sets the value of the contained 'ClassicAdoTemplate'. - /// - /// The command timeout. - /// Default is 0, indicating to use the database provider's default. - /// Any timeout specified here will be overridden by the remaining - /// transaction timeout when executing within a transaction that has a - /// timeout specified at the transaction level. - /// - public override int CommandTimeout - { - get { return base.CommandTimeout; } - set + command = DbProvider.CreateCommand(); + command.Connection = connectionTxPairToUse.Connection; + command.Transaction = connectionTxPairToUse.Transaction; + //TODO collect warnings... + //RegisterEventHandlers(command.Connection); + ApplyCommandSettings(command); + //TODO explicit check to cast to base class. + DbCommand commandToUse = command as DbCommand; + if (commandToUse != null) { - base.CommandTimeout = value; - classicAdoTemplate.CommandTimeout = value; - } - } - - #endregion - - #region General Execute Callback methods - - /// - /// Execute a ADO.NET operation on a command object using a interface based callback. - /// - /// the callback to execute - /// object returned from callback - public virtual T Execute(ICommandCallback action) - { - ConnectionTxPair connectionTxPairToUse = GetConnectionTxPair(DbProvider); - - IDbCommand command = null; - try - { - command = DbProvider.CreateCommand(); - command.Connection = connectionTxPairToUse.Connection; - command.Transaction = connectionTxPairToUse.Transaction; - //TODO collect warnings... - //RegisterEventHandlers(command.Connection); - ApplyCommandSettings(command); - //TODO explicit check to cast to base class. - DbCommand commandToUse = command as DbCommand; - if (commandToUse != null) - { - T result = action.DoInCommand((DbCommand)command); - //SqlWarnings sqlWarnings = GetSqlWarnings() - //ThrowExceptionOnWarningIfNotIgnoringWarnings(sqlWarnings); - return result; - } - else - { - throw new InvalidDataAccessApiUsageException( - "Providers implementation of IDbCommand does not inherit from System.Data.Common.DbCommand. Use the alternative overloaded Execute method that specifies IDbCommandCallback as a parameter."); - } - - } - catch (Exception e) - { - DisposeCommand(command); - command = null; - DisposeConnection(connectionTxPairToUse.Connection, DbProvider); - connectionTxPairToUse.Connection = null; - if (DbProvider.IsDataAccessException(e)) - { - throw ExceptionTranslator.Translate("CommandCallback", GetCommandText(action), e); - } - else - { - throw; - } - - - } - finally - { - DisposeCommand(command); - DisposeConnection(connectionTxPairToUse.Connection, DbProvider); - } - } - - /// - /// Execute a ADO.NET operation on a command object using a delegate callback. - /// - /// This allows for implementing arbitrary data access operations - /// on a single command within Spring's managed ADO.NET environment. - /// The delegate called with a command object. - /// A result object returned by the action or null - public virtual T Execute(CommandDelegate del) - { - ConnectionTxPair connectionTxPairToUse = GetConnectionTxPair(DbProvider); - - IDbCommand command = null; - try - { - command = DbProvider.CreateCommand(); - command.Connection = connectionTxPairToUse.Connection; - command.Transaction = connectionTxPairToUse.Transaction; - //TODO collect warnings... - //RegisterEventHandlers(command.Connection); - ApplyCommandSettings(command); - DbCommand commandToUse = command as DbCommand; - if (commandToUse != null) - { - T result = del((DbCommand) command); - //SqlWarnings sqlWarnings = GetSqlWarnings() - //ThrowExceptionOnWarningIfNotIgnoringWarnings(sqlWarnings); - return result; - } - else - { - throw new InvalidDataAccessApiUsageException( - "Providers implementation of IDbCommand does not inherit from System.Data.Common.DbCommand. Use the alternative overloaded Execute method that specifies IDbCommandDelegate as a parameter."); - } - } - catch (Exception e) - { - string commandText = command.CommandText; - DisposeCommand(command); - command = null; - DisposeConnection(connectionTxPairToUse.Connection, DbProvider); - connectionTxPairToUse.Connection = null; - if (DbProvider.IsDataAccessException(e)) - { - throw ExceptionTranslator.Translate("CommandCallback", commandText, e); - } - else - { - throw; - } - - - } - finally - { - DisposeCommand(command); - DisposeConnection(connectionTxPairToUse.Connection, DbProvider); - } - } - - - /// - /// Execute a ADO.NET operation on a command object using a interface based callback. - /// - /// the callback to execute - /// object returned from callback - public virtual T Execute(IDbCommandCallback action) - { - ConnectionTxPair connectionTxPairToUse = GetConnectionTxPair(DbProvider); - - IDbCommand command = null; - try - { - command = DbProvider.CreateCommand(); - command.Connection = connectionTxPairToUse.Connection; - command.Transaction = connectionTxPairToUse.Transaction; - //TODO collect warnings... - //RegisterEventHandlers(command.Connection); - ApplyCommandSettings(command); - T result = action.DoInCommand(command); + T result = action.DoInCommand((DbCommand) command); //SqlWarnings sqlWarnings = GetSqlWarnings() //ThrowExceptionOnWarningIfNotIgnoringWarnings(sqlWarnings); return result; } - catch (Exception e) + else { - DisposeCommand(command); - command = null; - DisposeConnection(connectionTxPairToUse.Connection, DbProvider); - connectionTxPairToUse.Connection = null; - if (DbProvider.IsDataAccessException(e)) - { - throw ExceptionTranslator.Translate("CommandCallback", GetCommandText(action), e); - } - else - { - throw; - } - - - } - finally - { - DisposeCommand(command); - DisposeConnection(connectionTxPairToUse.Connection, DbProvider); + throw new InvalidDataAccessApiUsageException( + "Providers implementation of IDbCommand does not inherit from System.Data.Common.DbCommand. Use the alternative overloaded Execute method that specifies IDbCommandCallback as a parameter."); } } - - /// - /// Execute a ADO.NET operation on a command object using a delegate callback. - /// - /// This allows for implementing arbitrary data access operations - /// on a single command within Spring's managed ADO.NET environment. - /// The delegate called with a command object. - /// A result object returned by the action or null - public virtual T Execute(IDbCommandDelegate del) + catch (Exception e) { - ConnectionTxPair connectionTxPairToUse = GetConnectionTxPair(DbProvider); - - IDbCommand command = null; - try + DisposeCommand(command); + command = null; + DisposeConnection(connectionTxPairToUse.Connection, DbProvider); + connectionTxPairToUse.Connection = null; + if (DbProvider.IsDataAccessException(e)) { - command = DbProvider.CreateCommand(); - command.Connection = connectionTxPairToUse.Connection; - command.Transaction = connectionTxPairToUse.Transaction; - //TODO collect warnings... - //RegisterEventHandlers(command.Connection); - ApplyCommandSettings(command); - T result = del(command); - //SqlWarnings sqlWarnings = GetSqlWarnings() - //ThrowExceptionOnWarningIfNotIgnoringWarnings(sqlWarnings); - return result; + throw ExceptionTranslator.Translate("CommandCallback", GetCommandText(action), e); } - catch (Exception e) + else { - string commandText = command.CommandText; - DisposeCommand(command); - command = null; - DisposeConnection(connectionTxPairToUse.Connection, DbProvider); - connectionTxPairToUse.Connection = null; - if (DbProvider.IsDataAccessException(e)) - { - throw ExceptionTranslator.Translate("CommandCallback", commandText, e); - } - else - { - throw; - } - - - } - finally - { - DisposeCommand(command); - DisposeConnection(connectionTxPairToUse.Connection, DbProvider); - } - } - - - /// - /// Executes ADO.NET operations on a command object, created by the provided IDbCommandCreator, - /// using the interface based callback IDbCommandCallback. - /// - /// The type of object returned from the callback. - /// The command creator. - /// The callback to execute based on IDbCommand - /// - /// A result object returned by the action or null - /// - public virtual T Execute(IDbCommandCreator commandCreator, IDbCommandCallback action) - { - AssertUtils.ArgumentNotNull(commandCreator, "commandCreator", "IDbCommandCreator must not be null"); - AssertUtils.ArgumentNotNull(action, "action", "Callback object must not be null"); - ConnectionTxPair connectionTxPairToUse = GetConnectionTxPair(DbProvider); - - IDbCommand command = null; - try - { - command = commandCreator.CreateDbCommand(DbProvider); - command.Connection = connectionTxPairToUse.Connection; - command.Transaction = connectionTxPairToUse.Transaction; - //TODO collect warnings... - //RegisterEventHandlers(command.Connection); - ApplyCommandSettings(command); - T result = action.DoInCommand(command); - //SqlWarnings sqlWarnings = GetSqlWarnings() - //ThrowExceptionOnWarningIfNotIgnoringWarnings(sqlWarnings); - return result; - } - catch (Exception e) - { - DisposeCommand(command); - command = null; - DisposeConnection(connectionTxPairToUse.Connection, DbProvider); - connectionTxPairToUse.Connection = null; - if (DbProvider.IsDataAccessException(e)) - { - throw ExceptionTranslator.Translate("CommandCallback", GetCommandText(action), e); - } - else - { - throw; - } - - - } - finally - { - DisposeCommand(command); - DisposeConnection(connectionTxPairToUse.Connection, DbProvider); - } - - } - - /// - /// Execute ADO.NET operations on a IDbDataAdapter object using an interface based callback. - /// - /// The type of object returned from the callback. - /// The data adapter callback. - /// - /// A result object returned by the callback or null - /// - /// This allows for implementing abritrary data access operations - /// on a single DataAdapter within Spring's managed ADO.NET environment. - /// - public virtual T Execute(IDataAdapterCallback dataAdapterCallback) - { - ConnectionTxPair connectionTxPairToUse = GetConnectionTxPair(DbProvider); - IDbDataAdapter dataAdapter = null; - try - { - dataAdapter = DbProvider.CreateDataAdapter(); - //TODO row updated event handling... - dataAdapter.SelectCommand = DbProvider.CreateCommand(); - dataAdapter.SelectCommand.Connection = connectionTxPairToUse.Connection; - //TODO register for warnings on connection. - dataAdapter.SelectCommand.Transaction = connectionTxPairToUse.Transaction; - ApplyCommandSettings(dataAdapter.SelectCommand); - T result = dataAdapterCallback.DoInDataAdapter(dataAdapter); - return result; - } - catch (Exception) - { - DisposeDataAdapterCommands(dataAdapter); - //TODO set dataAdapter command's = null; ? - //TODO exception translation? different hierarchy for data set operations. - DisposeConnection(connectionTxPairToUse.Connection, DbProvider); - connectionTxPairToUse.Connection = null; throw; } - finally - { - DisposeDataAdapterCommands(dataAdapter); - DisposeConnection(connectionTxPairToUse.Connection, DbProvider); - } - - } - - /// - /// Execute ADO.NET operations on a IDbDataAdapter object using an delgate based callback. - /// - /// This allows for implementing abritrary data access operations - /// on a single DataAdapter within Spring's managed ADO.NET environment. - /// - /// The type of object returned from the callback. - /// The delegate called with a IDbDataAdapter object. - /// A result object returned by the callback or null - public virtual T Execute(DataAdapterDelegate dataAdapterCallback) + finally { - ConnectionTxPair connectionTxPairToUse = GetConnectionTxPair(DbProvider); - IDbDataAdapter dataAdapter = null; - try - { - dataAdapter = DbProvider.CreateDataAdapter(); - //TODO row updated event handling... - dataAdapter.SelectCommand = DbProvider.CreateCommand(); - dataAdapter.SelectCommand.Connection = connectionTxPairToUse.Connection; - //TODO register for warnings on connection. - dataAdapter.SelectCommand.Transaction = connectionTxPairToUse.Transaction; - ApplyCommandSettings(dataAdapter.SelectCommand); - T result = dataAdapterCallback(dataAdapter); - return result; + DisposeCommand(command); + DisposeConnection(connectionTxPairToUse.Connection, DbProvider); + } + } - } - catch (Exception) + /// + /// Execute a ADO.NET operation on a command object using a delegate callback. + /// + /// This allows for implementing arbitrary data access operations + /// on a single command within Spring's managed ADO.NET environment. + /// The delegate called with a command object. + /// A result object returned by the action or null + public virtual T Execute(CommandDelegate del) + { + ConnectionTxPair connectionTxPairToUse = GetConnectionTxPair(DbProvider); + + IDbCommand command = null; + try + { + command = DbProvider.CreateCommand(); + command.Connection = connectionTxPairToUse.Connection; + command.Transaction = connectionTxPairToUse.Transaction; + //TODO collect warnings... + //RegisterEventHandlers(command.Connection); + ApplyCommandSettings(command); + DbCommand commandToUse = command as DbCommand; + if (commandToUse != null) + { + T result = del((DbCommand) command); + //SqlWarnings sqlWarnings = GetSqlWarnings() + //ThrowExceptionOnWarningIfNotIgnoringWarnings(sqlWarnings); + return result; + } + else + { + throw new InvalidDataAccessApiUsageException( + "Providers implementation of IDbCommand does not inherit from System.Data.Common.DbCommand. Use the alternative overloaded Execute method that specifies IDbCommandDelegate as a parameter."); + } + } + catch (Exception e) + { + string commandText = command.CommandText; + DisposeCommand(command); + command = null; + DisposeConnection(connectionTxPairToUse.Connection, DbProvider); + connectionTxPairToUse.Connection = null; + if (DbProvider.IsDataAccessException(e)) + { + throw ExceptionTranslator.Translate("CommandCallback", commandText, e); + } + else { - DisposeDataAdapterCommands(dataAdapter); - //TODO set dataAdapter command's = null; ? - //TODO exception translation? different hierarchy for data set operations. - DisposeConnection(connectionTxPairToUse.Connection, DbProvider); - connectionTxPairToUse.Connection = null; throw; } + } + finally + { + DisposeCommand(command); + DisposeConnection(connectionTxPairToUse.Connection, DbProvider); + } + } + + /// + /// Execute a ADO.NET operation on a command object using a interface based callback. + /// + /// the callback to execute + /// object returned from callback + public virtual T Execute(IDbCommandCallback action) + { + ConnectionTxPair connectionTxPairToUse = GetConnectionTxPair(DbProvider); + + IDbCommand command = null; + try + { + command = DbProvider.CreateCommand(); + command.Connection = connectionTxPairToUse.Connection; + command.Transaction = connectionTxPairToUse.Transaction; + //TODO collect warnings... + //RegisterEventHandlers(command.Connection); + ApplyCommandSettings(command); + T result = action.DoInCommand(command); + //SqlWarnings sqlWarnings = GetSqlWarnings() + //ThrowExceptionOnWarningIfNotIgnoringWarnings(sqlWarnings); + return result; + } + catch (Exception e) + { + DisposeCommand(command); + command = null; + DisposeConnection(connectionTxPairToUse.Connection, DbProvider); + connectionTxPairToUse.Connection = null; + if (DbProvider.IsDataAccessException(e)) + { + throw ExceptionTranslator.Translate("CommandCallback", GetCommandText(action), e); + } + else + { + throw; + } + } + finally + { + DisposeCommand(command); + DisposeConnection(connectionTxPairToUse.Connection, DbProvider); + } + } + + /// + /// Execute a ADO.NET operation on a command object using a delegate callback. + /// + /// This allows for implementing arbitrary data access operations + /// on a single command within Spring's managed ADO.NET environment. + /// The delegate called with a command object. + /// A result object returned by the action or null + public virtual T Execute(IDbCommandDelegate del) + { + ConnectionTxPair connectionTxPairToUse = GetConnectionTxPair(DbProvider); + + IDbCommand command = null; + try + { + command = DbProvider.CreateCommand(); + command.Connection = connectionTxPairToUse.Connection; + command.Transaction = connectionTxPairToUse.Transaction; + //TODO collect warnings... + //RegisterEventHandlers(command.Connection); + ApplyCommandSettings(command); + T result = del(command); + //SqlWarnings sqlWarnings = GetSqlWarnings() + //ThrowExceptionOnWarningIfNotIgnoringWarnings(sqlWarnings); + return result; + } + catch (Exception e) + { + string commandText = command.CommandText; + DisposeCommand(command); + command = null; + DisposeConnection(connectionTxPairToUse.Connection, DbProvider); + connectionTxPairToUse.Connection = null; + if (DbProvider.IsDataAccessException(e)) + { + throw ExceptionTranslator.Translate("CommandCallback", commandText, e); + } + else + { + throw; + } + } + finally + { + DisposeCommand(command); + DisposeConnection(connectionTxPairToUse.Connection, DbProvider); + } + } + + /// + /// Executes ADO.NET operations on a command object, created by the provided IDbCommandCreator, + /// using the interface based callback IDbCommandCallback. + /// + /// The type of object returned from the callback. + /// The command creator. + /// The callback to execute based on IDbCommand + /// + /// A result object returned by the action or null + /// + public virtual T Execute(IDbCommandCreator commandCreator, IDbCommandCallback action) + { + AssertUtils.ArgumentNotNull(commandCreator, "commandCreator", "IDbCommandCreator must not be null"); + AssertUtils.ArgumentNotNull(action, "action", "Callback object must not be null"); + ConnectionTxPair connectionTxPairToUse = GetConnectionTxPair(DbProvider); + + IDbCommand command = null; + try + { + command = commandCreator.CreateDbCommand(DbProvider); + command.Connection = connectionTxPairToUse.Connection; + command.Transaction = connectionTxPairToUse.Transaction; + //TODO collect warnings... + //RegisterEventHandlers(command.Connection); + ApplyCommandSettings(command); + T result = action.DoInCommand(command); + //SqlWarnings sqlWarnings = GetSqlWarnings() + //ThrowExceptionOnWarningIfNotIgnoringWarnings(sqlWarnings); + return result; + } + catch (Exception e) + { + DisposeCommand(command); + command = null; + DisposeConnection(connectionTxPairToUse.Connection, DbProvider); + connectionTxPairToUse.Connection = null; + if (DbProvider.IsDataAccessException(e)) + { + throw ExceptionTranslator.Translate("CommandCallback", GetCommandText(action), e); + } + else + { + throw; + } + } + finally + { + DisposeCommand(command); + DisposeConnection(connectionTxPairToUse.Connection, DbProvider); + } + } + + /// + /// Execute ADO.NET operations on a IDbDataAdapter object using an interface based callback. + /// + /// The type of object returned from the callback. + /// The data adapter callback. + /// + /// A result object returned by the callback or null + /// + /// This allows for implementing abritrary data access operations + /// on a single DataAdapter within Spring's managed ADO.NET environment. + /// + public virtual T Execute(IDataAdapterCallback dataAdapterCallback) + { + ConnectionTxPair connectionTxPairToUse = GetConnectionTxPair(DbProvider); + IDbDataAdapter dataAdapter = null; + try + { + dataAdapter = DbProvider.CreateDataAdapter(); + //TODO row updated event handling... + dataAdapter.SelectCommand = DbProvider.CreateCommand(); + dataAdapter.SelectCommand.Connection = connectionTxPairToUse.Connection; + //TODO register for warnings on connection. + dataAdapter.SelectCommand.Transaction = connectionTxPairToUse.Transaction; + ApplyCommandSettings(dataAdapter.SelectCommand); + T result = dataAdapterCallback.DoInDataAdapter(dataAdapter); + return result; + } + catch (Exception) + { + DisposeDataAdapterCommands(dataAdapter); + //TODO set dataAdapter command's = null; ? + //TODO exception translation? different hierarchy for data set operations. + DisposeConnection(connectionTxPairToUse.Connection, DbProvider); + connectionTxPairToUse.Connection = null; + throw; + } + finally + { + DisposeDataAdapterCommands(dataAdapter); + DisposeConnection(connectionTxPairToUse.Connection, DbProvider); + } + } + + /// + /// Execute ADO.NET operations on a IDbDataAdapter object using an delgate based callback. + /// + /// This allows for implementing abritrary data access operations + /// on a single DataAdapter within Spring's managed ADO.NET environment. + /// + /// The type of object returned from the callback. + /// The delegate called with a IDbDataAdapter object. + /// A result object returned by the callback or null + public virtual T Execute(DataAdapterDelegate dataAdapterCallback) + { + ConnectionTxPair connectionTxPairToUse = GetConnectionTxPair(DbProvider); + IDbDataAdapter dataAdapter = null; + try + { + dataAdapter = DbProvider.CreateDataAdapter(); + //TODO row updated event handling... + dataAdapter.SelectCommand = DbProvider.CreateCommand(); + dataAdapter.SelectCommand.Connection = connectionTxPairToUse.Connection; + //TODO register for warnings on connection. + dataAdapter.SelectCommand.Transaction = connectionTxPairToUse.Transaction; + ApplyCommandSettings(dataAdapter.SelectCommand); + T result = dataAdapterCallback(dataAdapter); + return result; + } + catch (Exception) + { + DisposeDataAdapterCommands(dataAdapter); + //TODO set dataAdapter command's = null; ? + //TODO exception translation? different hierarchy for data set operations. + DisposeConnection(connectionTxPairToUse.Connection, DbProvider); + connectionTxPairToUse.Connection = null; + throw; + } + finally + { + DisposeDataAdapterCommands(dataAdapter); + DisposeConnection(connectionTxPairToUse.Connection, DbProvider); + } + } + + #endregion + + #region ExecuteNonQuery + + /// + /// Executes a non query returning the number of rows affected. + /// + /// The command type. + /// The command text to execute. + /// The number of rows affected. + public virtual int ExecuteNonQuery(CommandType cmdType, string cmdText) + { + return classicAdoTemplate.ExecuteNonQuery(cmdType, cmdText); + } + + /// + /// Executes a non query returning the number of rows affected. + /// + /// The command type. + /// The command text to execute. + /// The name of the parameter to map. + /// One of the database parameter type enumerations. + /// The length of the parameter. 0 if not applicable to parameter type. + /// The parameter value. + /// The number of rows affected. + public virtual int ExecuteNonQuery(CommandType cmdType, string cmdText, + string parameterName, Enum dbType, int size, object parameterValue) + { + return classicAdoTemplate.ExecuteNonQuery(cmdType, cmdText, parameterName, dbType, size, parameterValue); + } + + /// + /// Executes a non query returning the number of rows affected. + /// + /// The command type. + /// The command text to execute. + /// The parameter collection to map. + /// The number of rows affected. + public virtual int ExecuteNonQuery(CommandType cmdType, string cmdText, + IDbParameters parameters) + { + return classicAdoTemplate.ExecuteNonQuery(cmdType, cmdText, parameters); + } + + /// + /// Executes a non query with parameters set via the + /// command setter, returning the number of rows affected. + /// + /// The command type. + /// The command text to execute. + /// The command setter. + /// The number of rows affected. + public virtual int ExecuteNonQuery(CommandType cmdType, string cmdText, + ICommandSetter commandSetter) + { + return classicAdoTemplate.ExecuteNonQuery(cmdType, cmdText, commandSetter); + } + + /// + /// Executes a non query with a command created via IDbCommandCreator and + /// parameters. + /// + /// Output parameters can be retrieved via the returned + /// dictionary. + /// + /// More commonly used as a lower level support method within the framework, + /// for example StoredProcedure/AdoScalar. + /// + /// + /// The callback to create a IDbCommand. + /// The number of rows affected. + public virtual IDictionary ExecuteNonQuery(IDbCommandCreator commandCreator) + { + return classicAdoTemplate.ExecuteNonQuery(commandCreator); + } + + #endregion + + #region ExecuteScalar + + /// + /// Execute the query with the specified command text. + /// + /// No parameters are used. As with + /// IDbCommand.ExecuteScalar, it returns the first column of the first row in the result set + /// returned by the query. Extra columns or row are ignored. + /// The command type + /// The command text to execute. + /// The first column of the first row in the result set + public virtual object ExecuteScalar(CommandType cmdType, string cmdText) + { + return classicAdoTemplate.ExecuteScalar(cmdType, cmdText); + } + + /// + /// Execute the query with the specified command text and parameter returning a scalar result + /// + /// The command type + /// The command text to execute. + /// The name of the parameter to map. + /// One of the database parameter type enumerations. + /// The length of the parameter. 0 if not applicable to parameter type. + /// The parameter value. + /// The first column of the first row in the result set + public virtual object ExecuteScalar(CommandType cmdType, string cmdText, + string parameterName, Enum dbType, int size, object parameterValue) + { + return classicAdoTemplate.ExecuteScalar(cmdType, cmdText, parameterName, dbType, size, parameterValue); + } + + /// + /// Execute the query with the specified command text and parameters returning a scalar result + /// + /// The command type + /// The command text to execute. + /// The parameter collection to map. + /// The first column of the first row in the result set + public virtual object ExecuteScalar(CommandType cmdType, string cmdText, + IDbParameters parameters) + { + return classicAdoTemplate.ExecuteScalar(cmdType, cmdText, parameters); + } + + /// + /// Execute the query with the specified command text and parameters set via the + /// command setter, returning a scalar result + /// + /// The command type + /// The command text to execute. + /// The command setter. + /// The first column of the first row in the result set + public virtual object ExecuteScalar(CommandType cmdType, string cmdText, + ICommandSetter commandSetter) + { + return classicAdoTemplate.ExecuteScalar(cmdType, cmdText, commandSetter); + } + + /// + /// Execute the query with a command created via IDbCommandCreator and + /// parameters + /// + /// Output parameters can be retrieved via the returned + /// dictionary. + /// + /// More commonly used as a lower level support method within the framework, + /// for example for StoredProcedure/AdoScalar. + /// + /// The callback to create a IDbCommand. + /// A dictionary containing output parameters, if any + public virtual IDictionary ExecuteScalar(IDbCommandCreator commandCreator) + { + return classicAdoTemplate.ExecuteScalar(commandCreator); + } + + #endregion + + #region Queries with RowCallback + + /// + /// Execute a query given IDbCommand's type and text by + /// passing the created IDbCommand to a ICommandSetter implementation + /// that knows how to bind values to the IDbCommand, reading a + /// single result set on a per-row basis with a . + /// + /// The type of command + /// The text of the query. + /// callback that will extract results + /// one row at a time. + /// + /// The command setter. + public virtual void QueryWithRowCallback(CommandType cmdType, string cmdText, IRowCallback rowCallback, + ICommandSetter commandSetter) + { + classicAdoTemplate.QueryWithRowCallback(cmdType, cmdText, rowCallback, commandSetter); + } + + /// + /// Execute a query given IDbCommand's type and text, reading a + /// single result set on a per-row basis with a . + /// + /// The type of command + /// The text of the query. + /// callback that will extract results + /// one row at a time. + /// + public virtual void QueryWithRowCallback(CommandType cmdType, string cmdText, IRowCallback rowCallback) + { + classicAdoTemplate.QueryWithRowCallback(cmdType, cmdText, rowCallback); + } + + /// + /// Execute a query given IDbCommand's type and text and provided parameter + /// information, reading a + /// single result set on a per-row basis with a . + /// + /// The type of command + /// The text of the query. + /// callback that will extract results + /// one row at a time. + /// + /// The name of the parameter to map. + /// One of the database parameter type enumerations. + /// The length of the parameter. 0 if not applicable to parameter type. + /// The parameter value. + public virtual void QueryWithRowCallback(CommandType cmdType, string cmdText, IRowCallback rowCallback, + string parameterName, Enum dbType, int size, object parameterValue) + { + classicAdoTemplate.QueryWithRowCallback(cmdType, cmdText, rowCallback, + parameterName, dbType, size, parameterValue); + } + + /// + /// Execute a query given IDbCommand's type and text and provided IDbParameters, + /// reading a single result set on a per-row basis with a . + /// + /// Type of the command. + /// The text of the query. + /// callback that will extract results + /// one row at a time. + /// The parameter collection to map. + public virtual void QueryWithRowCallback(CommandType cmdType, string cmdText, IRowCallback rowCallback, + IDbParameters parameter) + { + classicAdoTemplate.QueryWithRowCallback(cmdType, cmdText, rowCallback, + parameter); + } + + #endregion + + #region Queries with RowCallback Delegate + + public virtual void QueryWithRowCallbackDelegate(CommandType cmdType, string sql, RowCallbackDelegate rowCallbackDelegate) + { + classicAdoTemplate.QueryWithRowCallbackDelegate(cmdType, sql, rowCallbackDelegate); + } + + public virtual void QueryWithRowCallbackDelegate(CommandType cmdType, string sql, RowCallbackDelegate rowCallbackDelegate, ICommandSetter commandSetter) + { + classicAdoTemplate.QueryWithRowCallbackDelegate(cmdType, sql, rowCallbackDelegate, commandSetter); + } + + public virtual void QueryWithRowCallbackDelegate(CommandType cmdType, string sql, RowCallbackDelegate rowCallbackDelegate, + string parameterName, Enum dbType, int size, object parameterValue) + { + classicAdoTemplate.QueryWithRowCallbackDelegate(cmdType, sql, rowCallbackDelegate, + parameterName, dbType, size, parameterValue); + } + + public virtual void QueryWithRowCallbackDelegate(CommandType cmdType, string sql, RowCallbackDelegate rowCallbackDelegate, IDbParameters parameters) + { + classicAdoTemplate.QueryWithRowCallbackDelegate(cmdType, sql, rowCallbackDelegate, parameters); + } + + #endregion + + #region Queries with RowMapper + + public virtual IList QueryWithRowMapper(CommandType cmdType, string cmdText, IRowMapper rowMapper) + { + return QueryWithResultSetExtractor(cmdType, cmdText, new RowMapperResultSetExtractor(rowMapper)); + } + + public virtual IList QueryWithRowMapper(CommandType cmdType, String cmdText, IRowMapper rowMapper, + ICommandSetter commandSetter) + { + return QueryWithResultSetExtractor(cmdType, cmdText, new RowMapperResultSetExtractor(rowMapper), commandSetter); + } + + public virtual IList QueryWithRowMapper(CommandType cmdType, string cmdText, IRowMapper rowMapper, + string parameterName, Enum dbType, int size, object parameterValue) + { + return QueryWithResultSetExtractor(cmdType, cmdText, new RowMapperResultSetExtractor(rowMapper), parameterName, dbType, size, parameterValue); + } + + public virtual IList QueryWithRowMapper(CommandType cmdType, string cmdText, IRowMapper rowMapper, IDbParameters parameters) + { + return QueryWithResultSetExtractor(cmdType, cmdText, new RowMapperResultSetExtractor(rowMapper), parameters); + } + + #endregion + + #region Queries with RowMapperDelegate + + public virtual IList QueryWithRowMapperDelegate(CommandType cmdType, string cmdText, RowMapperDelegate rowMapperDelegate) + { + return QueryWithResultSetExtractor(cmdType, cmdText, new RowMapperResultSetExtractor(rowMapperDelegate)); + } + + public virtual IList QueryWithRowMapperDelegate(CommandType cmdType, string cmdText, RowMapperDelegate rowMapperDelegate, + ICommandSetter commandSetter) + { + return QueryWithResultSetExtractor(cmdType, cmdText, new RowMapperResultSetExtractor(rowMapperDelegate), + commandSetter); + } + + public virtual IList QueryWithRowMapperDelegate(CommandType cmdType, string cmdText, RowMapperDelegate rowMapperDelegate, + string parameterName, Enum dbType, int size, object parameterValue) + { + return QueryWithResultSetExtractor(cmdType, cmdText, new RowMapperResultSetExtractor(rowMapperDelegate), + parameterName, dbType, size, parameterValue); + } + + public virtual IList QueryWithRowMapperDelegate(CommandType cmdType, string cmdText, RowMapperDelegate rowMapperDelegate, + IDbParameters parameters) + { + return QueryWithResultSetExtractor(cmdType, cmdText, new RowMapperResultSetExtractor(rowMapperDelegate), + parameters); + } + + #endregion + + #region Queries with ResultSetExtractor + + public virtual T QueryWithResultSetExtractor(CommandType cmdType, + string cmdText, + IResultSetExtractor resultSetExtractor) + { + AssertUtils.ArgumentNotNull(cmdText, "cmdText", "CommandText must not be null"); + if (LOG.IsEnabled(LogLevel.Debug)) + { + LOG.LogDebug("Executing CommandText [" + cmdText + "]"); + } + + return Execute(new QueryCallback(this, cmdType, cmdText, resultSetExtractor, null)); + } + + public virtual T QueryWithResultSetExtractor(CommandType commandType, string cmdText, IResultSetExtractor resultSetExtractor, + string name, Enum dbType, int size, object parameterValue) + { + AssertUtils.ArgumentNotNull(resultSetExtractor, "resultSetExtractor", "Result Set Extractor must not be null"); + return Execute(new QueryCallback(this, commandType, cmdText, resultSetExtractor, + CreateDbParameters(name, dbType, size, parameterValue))); + } + + public virtual T QueryWithResultSetExtractor(CommandType commandType, string cmdText, + IResultSetExtractor resultSetExtractor, + IDbParameters parameters) + { + AssertUtils.ArgumentNotNull(resultSetExtractor, "resultSetExtractor", "Result Set Extractor must not be null"); + return Execute(new QueryCallback(this, commandType, cmdText, resultSetExtractor, parameters)); + } + + public virtual T QueryWithResultSetExtractor(CommandType cmdType, string cmdText, + IResultSetExtractor resultSetExtractor, + ICommandSetter commandSetter) + { + AssertUtils.ArgumentNotNull(resultSetExtractor, "resultSetExtractor", "Result Set Extractor must not be null"); + return Execute(new QueryCallbackWithCommandSetter(this, cmdType, cmdText, + resultSetExtractor, + commandSetter)); + } + + public virtual T QueryWithResultSetExtractor(CommandType cmdType, string cmdText, + IResultSetExtractor resultSetExtractor, + CommandSetterDelegate commandSetterDelegate) + { + AssertUtils.ArgumentNotNull(resultSetExtractor, "resultSetExtractor", "Result Set Extractor must not be null"); + return Execute(new QueryCallbackWithCommandSetterDelegate(this, cmdType, cmdText, + resultSetExtractor, + commandSetterDelegate)); + } + + #endregion + + #region Queries with ResultSetExtractorDelegate + + public virtual T QueryWithResultSetExtractorDelegate(CommandType cmdType, + string cmdText, + ResultSetExtractorDelegate resultSetExtractorDelegate) + { + AssertUtils.ArgumentNotNull(cmdText, "cmdText", "CommandText must not be null"); + AssertUtils.ArgumentNotNull(resultSetExtractorDelegate, "resultSetExtractorDelegate", "Result set extractor delegate must not be null"); + if (LOG.IsEnabled(LogLevel.Debug)) + { + LOG.LogDebug("Executing CommandText [" + cmdText + "]"); + } + + return Execute(new QueryCallback(this, cmdType, cmdText, resultSetExtractorDelegate, null)); + } + + public virtual T QueryWithResultSetExtractorDelegate(CommandType commandType, string cmdText, ResultSetExtractorDelegate resultSetExtractorDelegate, + string paramenterName, Enum dbType, int size, object parameterValue) + { + AssertUtils.ArgumentNotNull(cmdText, "cmdText", "CommandText must not be null"); + AssertUtils.ArgumentNotNull(resultSetExtractorDelegate, "resultSetExtractorDelegate", "Result set extractor delegate must not be null"); + return Execute(new QueryCallback(this, commandType, cmdText, resultSetExtractorDelegate, + CreateDbParameters(paramenterName, dbType, size, parameterValue))); + } + + public virtual T QueryWithResultSetExtractorDelegate(CommandType commandType, string cmdText, ResultSetExtractorDelegate resultSetExtractorDelegate, + IDbParameters parameters) + { + AssertUtils.ArgumentNotNull(cmdText, "cmdText", "CommandText must not be null"); + AssertUtils.ArgumentNotNull(resultSetExtractorDelegate, "resultSetExtractorDelegate", "Result set extractor delegate must not be null"); + return Execute(new QueryCallback(this, commandType, cmdText, resultSetExtractorDelegate, parameters)); + } + + public virtual T QueryWithResultSetExtractorDelegate(CommandType cmdType, string cmdText, ResultSetExtractorDelegate resultSetExtractorDelegate, + ICommandSetter commandSetter) + { + AssertUtils.ArgumentNotNull(cmdText, "cmdText", "CommandText must not be null"); + AssertUtils.ArgumentNotNull(resultSetExtractorDelegate, "resultSetExtractorDelegate", "Result set extractor delegate must not be null"); + return Execute(new QueryCallbackWithCommandSetter(this, cmdType, cmdText, + resultSetExtractorDelegate, + commandSetter)); + } + + public virtual T QueryWithResultSetExtractorDelegate(CommandType cmdType, string cmdText, ResultSetExtractorDelegate resultSetExtractorDelegate, + CommandSetterDelegate commandSetterDelegate) + { + AssertUtils.ArgumentNotNull(resultSetExtractorDelegate, "resultSetExtractorDelegate", "Result set extractor delegate must not be null"); + return Execute(new QueryCallbackWithCommandSetterDelegate(this, cmdType, cmdText, + resultSetExtractorDelegate, + commandSetterDelegate)); + } + + #endregion + + #region Query for Object + + public virtual T QueryForObject(CommandType cmdType, string cmdText, IRowMapper rowMapper) + { + IList results = QueryWithRowMapper(cmdType, cmdText, rowMapper); + return DataAccessUtils.RequiredUniqueResultSet(results); + } + + public virtual T QueryForObject(CommandType cmdType, string cmdText, IRowMapper rowMapper, ICommandSetter commandSetter) + { + IList results = QueryWithRowMapper(cmdType, cmdText, rowMapper, commandSetter); + return DataAccessUtils.RequiredUniqueResultSet(results); + } + + public virtual T QueryForObject(CommandType cmdType, string cmdText, IRowMapper rowMapper, IDbParameters parameters) + { + IList results = QueryWithRowMapper(cmdType, cmdText, rowMapper, parameters); + return DataAccessUtils.RequiredUniqueResultSet(results); + } + + public virtual T QueryForObject(CommandType cmdType, string cmdText, IRowMapper rowMapper, + string parameterName, Enum dbType, int size, object parameterValue) + { + IList results = QueryWithRowMapper(cmdType, cmdText, rowMapper, parameterName, dbType, size, parameterValue); + return DataAccessUtils.RequiredUniqueResultSet(results); + } + + #endregion + + #region Query for ObjectDelegate + + public virtual T QueryForObjectDelegate(CommandType cmdType, string cmdText, RowMapperDelegate rowMapperDelegate) + { + IList results = QueryWithRowMapperDelegate(cmdType, cmdText, rowMapperDelegate); + return DataAccessUtils.RequiredUniqueResultSet(results); + } + + public virtual T QueryForObjectDelegate(CommandType cmdType, string cmdText, RowMapperDelegate rowMapperDelegate, ICommandSetter commandSetter) + { + IList results = QueryWithRowMapperDelegate(cmdType, cmdText, rowMapperDelegate, commandSetter); + return DataAccessUtils.RequiredUniqueResultSet(results); + } + + public virtual T QueryForObjectDelegate(CommandType cmdType, string cmdText, RowMapperDelegate rowMapperDelegate, IDbParameters parameters) + { + IList results = QueryWithRowMapperDelegate(cmdType, cmdText, rowMapperDelegate, parameters); + return DataAccessUtils.RequiredUniqueResultSet(results); + } + + public virtual T QueryForObjectDelegate(CommandType cmdType, string cmdText, RowMapperDelegate rowMapperDelegate, + string parameterName, Enum dbType, int size, object parameterValue) + { + IList results = QueryWithRowMapperDelegate(cmdType, cmdText, rowMapperDelegate, parameterName, dbType, size, parameterValue); + return DataAccessUtils.RequiredUniqueResultSet(results); + } + + #endregion + + #region Query with CommandCreator + + public virtual T QueryWithCommandCreator(IDbCommandCreator cc, IResultSetExtractor rse) + { + return QueryWithCommandCreator(cc, rse, null); + } + + public virtual void QueryWithCommandCreator(IDbCommandCreator cc, IRowCallback rowCallback) + { + classicAdoTemplate.QueryWithCommandCreator(cc, rowCallback, null); + } + + public virtual IList QueryWithCommandCreator(IDbCommandCreator cc, IRowMapper rowMapper) + { + return QueryWithCommandCreator(cc, rowMapper, null); + } + + public virtual T QueryWithCommandCreator(IDbCommandCreator cc, IResultSetExtractor rse, IDictionary returnedParameters) + { + if (rse == null) + { + throw new ArgumentNullException("Result Set Extractor must not be null"); + } + + return Execute(cc, new AdoResultSetExtractorWithOutputParamsCommandCallback(this, rse, returnedParameters)); + } + + public virtual void QueryWithCommandCreator(IDbCommandCreator cc, IRowCallback rowCallback, IDictionary returnedParameters) + { + classicAdoTemplate.QueryWithCommandCreator(cc, rowCallback, returnedParameters); + } + + public virtual IList QueryWithCommandCreator(IDbCommandCreator cc, IRowMapper rowMapper, IDictionary returnedParameters) + { + if (rowMapper == null) + { + throw new ArgumentNullException("rowMapper must not be null"); + } + + return Execute(cc, new AdoRowMapperQueryCommandCallback(this, rowMapper, returnedParameters)); + } + + public virtual IDictionary QueryWithCommandCreator(IDbCommandCreator cc, IList namedResultSetProcessors) + { + return classicAdoTemplate.Execute(cc, new AdoResultProcessorsQueryCommandCallback(this, namedResultSetProcessors)) as IDictionary; + } + + public virtual IDictionary QueryWithCommandCreator(IDbCommandCreator cc, IList namedResultSetProcessors) + { + return classicAdoTemplate.Execute(cc, new AdoResultProcessorsQueryCommandCallback(this, namedResultSetProcessors)) as IDictionary; + } + + #endregion + + #region General Helper Methods + + /// + /// Checks if DbProvider is not null and creates ExceptionTranslator if not LazyInit. + /// + public override void AfterPropertiesSet() + { + classicAdoTemplate.AfterPropertiesSet(); + classicAdoTemplate.CommandTimeout = CommandTimeout; + } + + /// + /// Creates the data reader wrapper for use in AdoTemplate callback methods. + /// + /// The reader to wrap. + /// The data reader used in AdoTemplate callbacks + public override IDataReader CreateDataReaderWrapper(IDataReader readerToWrap) + { + return classicAdoTemplate.CreateDataReaderWrapper(readerToWrap); + } + + #endregion + + #region Parameter Creation Helper Methods + + /// + /// Derives the parameters of a stored procedure including the return parameter + /// + /// Name of the procedure. + /// if set to true to include return parameter. + /// The stored procedure parameters + public override IDataParameter[] DeriveParameters(string procedureName, bool includeReturnParameter) + { + return classicAdoTemplate.DeriveParameters(procedureName, includeReturnParameter); + } + + #endregion + + #region Internal Helper classes + + internal class QueryCallback : IDbCommandCallback, ICommandTextProvider + { + private AdoTemplate adoTemplate; + private IResultSetExtractor rse; + private ResultSetExtractorDelegate resultSetExtractorDelegate; + private CommandType commandType; + private string commandText; + private IDbParameters parameters; + + public QueryCallback(AdoTemplate adoTemplate, + CommandType cmdType, + string cmdText, + IResultSetExtractor rse, + IDbParameters dbParameters) + { + this.adoTemplate = adoTemplate; + commandType = cmdType; + commandText = cmdText; + this.rse = rse; + parameters = dbParameters; + } + + public QueryCallback(AdoTemplate adoTemplate, + CommandType cmdType, + string cmdText, + ResultSetExtractorDelegate resultSetExtractorDelegate, + IDbParameters dbParameters) + { + this.adoTemplate = adoTemplate; + commandType = cmdType; + commandText = cmdText; + this.resultSetExtractorDelegate = resultSetExtractorDelegate; + parameters = dbParameters; + } + + public string CommandText + { + get { return commandText; } + } + + public T DoInCommand(IDbCommand command) + { + IDataReader reader = null; + try + { + command.CommandType = commandType; + command.CommandText = commandText; + ParameterUtils.CopyParameters(command, parameters); + reader = adoTemplate.CreateDataReaderWrapper(command.ExecuteReader()); + T returnValue = default(T); + if (rse != null) + { + returnValue = rse.ExtractData(reader); + } + else + { + returnValue = resultSetExtractorDelegate(reader); + } + + return returnValue; + } finally { - DisposeDataAdapterCommands(dataAdapter); - DisposeConnection(connectionTxPairToUse.Connection, DbProvider); + Support.AdoUtils.CloseReader(reader); + ParameterUtils.CopyParameters(parameters, command); } } + } - #endregion + internal class QueryCallbackWithCommandSetter : IDbCommandCallback, ICommandTextProvider + { + private AdoTemplate adoTemplate; + private IResultSetExtractor rse; + private ResultSetExtractorDelegate resultSetExtractorDelegate; + private CommandType commandType; + private string commandText; + private ICommandSetter commandSetter; - #region ExecuteNonQuery - - /// - /// Executes a non query returning the number of rows affected. - /// - /// The command type. - /// The command text to execute. - /// The number of rows affected. - public virtual int ExecuteNonQuery(CommandType cmdType, string cmdText) + public QueryCallbackWithCommandSetter(AdoTemplate adoTemplate, + CommandType cmdType, + string cmdText, + IResultSetExtractor rse, + ICommandSetter commandSetter) { - return classicAdoTemplate.ExecuteNonQuery(cmdType, cmdText); + this.adoTemplate = adoTemplate; + commandType = cmdType; + commandText = cmdText; + this.rse = rse; + this.commandSetter = commandSetter; } - - /// - /// Executes a non query returning the number of rows affected. - /// - /// The command type. - /// The command text to execute. - /// The name of the parameter to map. - /// One of the database parameter type enumerations. - /// The length of the parameter. 0 if not applicable to parameter type. - /// The parameter value. - /// The number of rows affected. - public virtual int ExecuteNonQuery(CommandType cmdType, string cmdText, - string parameterName, Enum dbType, int size, object parameterValue) + public QueryCallbackWithCommandSetter(AdoTemplate adoTemplate, + CommandType cmdType, + string cmdText, + ResultSetExtractorDelegate resultSetExtractorDelegate, + ICommandSetter commandSetter) { - return classicAdoTemplate.ExecuteNonQuery(cmdType, cmdText, parameterName, dbType, size, parameterValue); - - + this.adoTemplate = adoTemplate; + commandType = cmdType; + commandText = cmdText; + this.resultSetExtractorDelegate = resultSetExtractorDelegate; + this.commandSetter = commandSetter; } - /// - /// Executes a non query returning the number of rows affected. - /// - /// The command type. - /// The command text to execute. - /// The parameter collection to map. - /// The number of rows affected. - public virtual int ExecuteNonQuery(CommandType cmdType, string cmdText, - IDbParameters parameters) + public string CommandText { - return classicAdoTemplate.ExecuteNonQuery(cmdType, cmdText, parameters); - + get { return commandText; } } - /// - /// Executes a non query with parameters set via the - /// command setter, returning the number of rows affected. - /// - /// The command type. - /// The command text to execute. - /// The command setter. - /// The number of rows affected. - public virtual int ExecuteNonQuery(CommandType cmdType, string cmdText, - ICommandSetter commandSetter) + public T DoInCommand(IDbCommand command) { - return classicAdoTemplate.ExecuteNonQuery(cmdType, cmdText, commandSetter); - } - - /// - /// Executes a non query with a command created via IDbCommandCreator and - /// parameters. - /// - /// Output parameters can be retrieved via the returned - /// dictionary. - /// - /// More commonly used as a lower level support method within the framework, - /// for example StoredProcedure/AdoScalar. - /// - /// - /// The callback to create a IDbCommand. - /// The number of rows affected. - public virtual IDictionary ExecuteNonQuery(IDbCommandCreator commandCreator) - { - return classicAdoTemplate.ExecuteNonQuery(commandCreator); - } - - #endregion - - #region ExecuteScalar - - /// - /// Execute the query with the specified command text. - /// - /// No parameters are used. As with - /// IDbCommand.ExecuteScalar, it returns the first column of the first row in the result set - /// returned by the query. Extra columns or row are ignored. - /// The command type - /// The command text to execute. - /// The first column of the first row in the result set - public virtual object ExecuteScalar(CommandType cmdType, string cmdText) - { - return classicAdoTemplate.ExecuteScalar(cmdType, cmdText); - } - - /// - /// Execute the query with the specified command text and parameter returning a scalar result - /// - /// The command type - /// The command text to execute. - /// The name of the parameter to map. - /// One of the database parameter type enumerations. - /// The length of the parameter. 0 if not applicable to parameter type. - /// The parameter value. - /// The first column of the first row in the result set - public virtual object ExecuteScalar(CommandType cmdType, string cmdText, - string parameterName, Enum dbType, int size, object parameterValue) - { - return classicAdoTemplate.ExecuteScalar(cmdType, cmdText, parameterName, dbType, size, parameterValue); - - } - - - /// - /// Execute the query with the specified command text and parameters returning a scalar result - /// - /// The command type - /// The command text to execute. - /// The parameter collection to map. - /// The first column of the first row in the result set - public virtual object ExecuteScalar(CommandType cmdType, string cmdText, - IDbParameters parameters) - { - return classicAdoTemplate.ExecuteScalar(cmdType, cmdText, parameters); - } - - /// - /// Execute the query with the specified command text and parameters set via the - /// command setter, returning a scalar result - /// - /// The command type - /// The command text to execute. - /// The command setter. - /// The first column of the first row in the result set - public virtual object ExecuteScalar(CommandType cmdType, string cmdText, - ICommandSetter commandSetter) - { - return classicAdoTemplate.ExecuteScalar(cmdType, cmdText, commandSetter); - } - - /// - /// Execute the query with a command created via IDbCommandCreator and - /// parameters - /// - /// Output parameters can be retrieved via the returned - /// dictionary. - /// - /// More commonly used as a lower level support method within the framework, - /// for example for StoredProcedure/AdoScalar. - /// - /// The callback to create a IDbCommand. - /// A dictionary containing output parameters, if any - public virtual IDictionary ExecuteScalar(IDbCommandCreator commandCreator) - { - return classicAdoTemplate.ExecuteScalar(commandCreator); - } - - #endregion - - #region Queries with RowCallback - - /// - /// Execute a query given IDbCommand's type and text by - /// passing the created IDbCommand to a ICommandSetter implementation - /// that knows how to bind values to the IDbCommand, reading a - /// single result set on a per-row basis with a . - /// - /// The type of command - /// The text of the query. - /// callback that will extract results - /// one row at a time. - /// - /// The command setter. - public virtual void QueryWithRowCallback(CommandType cmdType, string cmdText, IRowCallback rowCallback, - ICommandSetter commandSetter) - { - classicAdoTemplate.QueryWithRowCallback(cmdType, cmdText, rowCallback, commandSetter); - } - /// - /// Execute a query given IDbCommand's type and text, reading a - /// single result set on a per-row basis with a . - /// - /// The type of command - /// The text of the query. - /// callback that will extract results - /// one row at a time. - /// - public virtual void QueryWithRowCallback(CommandType cmdType, string cmdText, IRowCallback rowCallback) - { - classicAdoTemplate.QueryWithRowCallback(cmdType, cmdText, rowCallback); - } - - /// - /// Execute a query given IDbCommand's type and text and provided parameter - /// information, reading a - /// single result set on a per-row basis with a . - /// - /// The type of command - /// The text of the query. - /// callback that will extract results - /// one row at a time. - /// - /// The name of the parameter to map. - /// One of the database parameter type enumerations. - /// The length of the parameter. 0 if not applicable to parameter type. - /// The parameter value. - public virtual void QueryWithRowCallback(CommandType cmdType, string cmdText, IRowCallback rowCallback, - string parameterName, Enum dbType, int size, object parameterValue) - { - classicAdoTemplate.QueryWithRowCallback(cmdType, cmdText, rowCallback, - parameterName, dbType, size, parameterValue); - } - - /// - /// Execute a query given IDbCommand's type and text and provided IDbParameters, - /// reading a single result set on a per-row basis with a . - /// - /// Type of the command. - /// The text of the query. - /// callback that will extract results - /// one row at a time. - /// The parameter collection to map. - public virtual void QueryWithRowCallback(CommandType cmdType, string cmdText, IRowCallback rowCallback, - IDbParameters parameter) - { - classicAdoTemplate.QueryWithRowCallback(cmdType, cmdText, rowCallback, - parameter); - } - - #endregion - - #region Queries with RowCallback Delegate - - public virtual void QueryWithRowCallbackDelegate(CommandType cmdType, string sql, RowCallbackDelegate rowCallbackDelegate) - { - classicAdoTemplate.QueryWithRowCallbackDelegate(cmdType, sql, rowCallbackDelegate); - - } - public virtual void QueryWithRowCallbackDelegate(CommandType cmdType, string sql, RowCallbackDelegate rowCallbackDelegate, ICommandSetter commandSetter) - { - classicAdoTemplate.QueryWithRowCallbackDelegate(cmdType, sql, rowCallbackDelegate, commandSetter); - } - - public virtual void QueryWithRowCallbackDelegate(CommandType cmdType, string sql, RowCallbackDelegate rowCallbackDelegate, - string parameterName, Enum dbType, int size, object parameterValue) - { - classicAdoTemplate.QueryWithRowCallbackDelegate(cmdType, sql, rowCallbackDelegate, - parameterName, dbType, size, parameterValue); - - } - - public virtual void QueryWithRowCallbackDelegate(CommandType cmdType, string sql, RowCallbackDelegate rowCallbackDelegate, IDbParameters parameters) - { - classicAdoTemplate.QueryWithRowCallbackDelegate(cmdType, sql, rowCallbackDelegate, parameters); - - } - - #endregion - - #region Queries with RowMapper - - public virtual IList QueryWithRowMapper(CommandType cmdType, string cmdText, IRowMapper rowMapper) - { - return QueryWithResultSetExtractor(cmdType, cmdText, new RowMapperResultSetExtractor(rowMapper)); - - } - - - public virtual IList QueryWithRowMapper(CommandType cmdType, String cmdText, IRowMapper rowMapper, - ICommandSetter commandSetter) - { - return QueryWithResultSetExtractor(cmdType, cmdText, new RowMapperResultSetExtractor(rowMapper), commandSetter); - - } - - public virtual IList QueryWithRowMapper(CommandType cmdType, string cmdText, IRowMapper rowMapper, - string parameterName, Enum dbType, int size, object parameterValue) - { - return QueryWithResultSetExtractor(cmdType, cmdText, new RowMapperResultSetExtractor(rowMapper), parameterName, dbType, size, parameterValue); - - } - - public virtual IList QueryWithRowMapper(CommandType cmdType, string cmdText, IRowMapper rowMapper, IDbParameters parameters) - { - return QueryWithResultSetExtractor(cmdType, cmdText, new RowMapperResultSetExtractor(rowMapper), parameters); - - } - - - - #endregion - - #region Queries with RowMapperDelegate - - public virtual IList QueryWithRowMapperDelegate(CommandType cmdType, string cmdText, RowMapperDelegate rowMapperDelegate) - { - return QueryWithResultSetExtractor(cmdType, cmdText, new RowMapperResultSetExtractor(rowMapperDelegate)); - - } - - public virtual IList QueryWithRowMapperDelegate(CommandType cmdType, string cmdText, RowMapperDelegate rowMapperDelegate, - ICommandSetter commandSetter) - { - return QueryWithResultSetExtractor(cmdType, cmdText, new RowMapperResultSetExtractor(rowMapperDelegate), - commandSetter); - } - - public virtual IList QueryWithRowMapperDelegate(CommandType cmdType, string cmdText, RowMapperDelegate rowMapperDelegate, - string parameterName, Enum dbType, int size, object parameterValue) - { - return QueryWithResultSetExtractor(cmdType, cmdText, new RowMapperResultSetExtractor(rowMapperDelegate), - parameterName, dbType, size, parameterValue); - } - - public virtual IList QueryWithRowMapperDelegate(CommandType cmdType, string cmdText, RowMapperDelegate rowMapperDelegate, - IDbParameters parameters) - { - return QueryWithResultSetExtractor(cmdType, cmdText, new RowMapperResultSetExtractor(rowMapperDelegate), - parameters); - } - #endregion - - #region Queries with ResultSetExtractor - - public virtual T QueryWithResultSetExtractor(CommandType cmdType, - string cmdText, - IResultSetExtractor resultSetExtractor) - { - AssertUtils.ArgumentNotNull(cmdText, "cmdText", "CommandText must not be null"); - if (LOG.IsEnabled(LogLevel.Debug)) + IDataReader reader = null; + try { - LOG.LogDebug("Executing CommandText [" + cmdText + "]"); - } - return Execute(new QueryCallback(this, cmdType, cmdText, resultSetExtractor, null)); - } - - public virtual T QueryWithResultSetExtractor(CommandType commandType, string cmdText, IResultSetExtractor resultSetExtractor, - string name, Enum dbType, int size, object parameterValue) - { - AssertUtils.ArgumentNotNull(resultSetExtractor, "resultSetExtractor", "Result Set Extractor must not be null"); - return Execute(new QueryCallback(this, commandType, cmdText, resultSetExtractor, - CreateDbParameters(name, dbType, size, parameterValue))); - } - - public virtual T QueryWithResultSetExtractor(CommandType commandType, string cmdText, - IResultSetExtractor resultSetExtractor, - IDbParameters parameters) - { - AssertUtils.ArgumentNotNull(resultSetExtractor, "resultSetExtractor", "Result Set Extractor must not be null"); - return Execute(new QueryCallback(this, commandType, cmdText, resultSetExtractor, parameters)); - } - - public virtual T QueryWithResultSetExtractor(CommandType cmdType, string cmdText, - IResultSetExtractor resultSetExtractor, - ICommandSetter commandSetter) - { - AssertUtils.ArgumentNotNull(resultSetExtractor, "resultSetExtractor", "Result Set Extractor must not be null"); - return Execute(new QueryCallbackWithCommandSetter(this, cmdType, cmdText, - resultSetExtractor, - commandSetter)); - } - - public virtual T QueryWithResultSetExtractor(CommandType cmdType, string cmdText, - IResultSetExtractor resultSetExtractor, - CommandSetterDelegate commandSetterDelegate) - { - AssertUtils.ArgumentNotNull(resultSetExtractor, "resultSetExtractor", "Result Set Extractor must not be null"); - return Execute(new QueryCallbackWithCommandSetterDelegate(this, cmdType, cmdText, - resultSetExtractor, - commandSetterDelegate)); - } - - #endregion - - - #region Queries with ResultSetExtractorDelegate - - public virtual T QueryWithResultSetExtractorDelegate(CommandType cmdType, - string cmdText, - ResultSetExtractorDelegate resultSetExtractorDelegate) - { - AssertUtils.ArgumentNotNull(cmdText, "cmdText", "CommandText must not be null"); - AssertUtils.ArgumentNotNull(resultSetExtractorDelegate, "resultSetExtractorDelegate", "Result set extractor delegate must not be null"); - if (LOG.IsEnabled(LogLevel.Debug)) - { - LOG.LogDebug("Executing CommandText [" + cmdText + "]"); - } - - return Execute(new QueryCallback(this, cmdType, cmdText, resultSetExtractorDelegate, null)); - } - - public virtual T QueryWithResultSetExtractorDelegate(CommandType commandType, string cmdText, ResultSetExtractorDelegate resultSetExtractorDelegate, - string paramenterName, Enum dbType, int size, object parameterValue) - { - AssertUtils.ArgumentNotNull(cmdText, "cmdText", "CommandText must not be null"); - AssertUtils.ArgumentNotNull(resultSetExtractorDelegate, "resultSetExtractorDelegate", "Result set extractor delegate must not be null"); - return Execute(new QueryCallback(this, commandType, cmdText, resultSetExtractorDelegate, - CreateDbParameters(paramenterName, dbType, size, parameterValue))); - } - - public virtual T QueryWithResultSetExtractorDelegate(CommandType commandType, string cmdText, ResultSetExtractorDelegate resultSetExtractorDelegate, - IDbParameters parameters) - { - AssertUtils.ArgumentNotNull(cmdText, "cmdText", "CommandText must not be null"); - AssertUtils.ArgumentNotNull(resultSetExtractorDelegate, "resultSetExtractorDelegate", "Result set extractor delegate must not be null"); - return Execute(new QueryCallback(this, commandType, cmdText, resultSetExtractorDelegate, parameters)); - } - - public virtual T QueryWithResultSetExtractorDelegate(CommandType cmdType, string cmdText, ResultSetExtractorDelegate resultSetExtractorDelegate, - ICommandSetter commandSetter) - { - AssertUtils.ArgumentNotNull(cmdText, "cmdText", "CommandText must not be null"); - AssertUtils.ArgumentNotNull(resultSetExtractorDelegate, "resultSetExtractorDelegate", "Result set extractor delegate must not be null"); - return Execute(new QueryCallbackWithCommandSetter(this, cmdType, cmdText, - resultSetExtractorDelegate, - commandSetter)); - } - - public virtual T QueryWithResultSetExtractorDelegate(CommandType cmdType, string cmdText, ResultSetExtractorDelegate resultSetExtractorDelegate, - CommandSetterDelegate commandSetterDelegate) - { - AssertUtils.ArgumentNotNull(resultSetExtractorDelegate, "resultSetExtractorDelegate", "Result set extractor delegate must not be null"); - return Execute(new QueryCallbackWithCommandSetterDelegate(this, cmdType, cmdText, - resultSetExtractorDelegate, - commandSetterDelegate)); - } - - #endregion - - #region Query for Object - - public virtual T QueryForObject(CommandType cmdType, string cmdText, IRowMapper rowMapper) - { - IList results = QueryWithRowMapper(cmdType, cmdText, rowMapper); - return DataAccessUtils.RequiredUniqueResultSet(results); - } - - public virtual T QueryForObject(CommandType cmdType, string cmdText, IRowMapper rowMapper, ICommandSetter commandSetter) - { - IList results = QueryWithRowMapper(cmdType, cmdText, rowMapper, commandSetter); - return DataAccessUtils.RequiredUniqueResultSet(results); - } - - public virtual T QueryForObject(CommandType cmdType, string cmdText, IRowMapper rowMapper, IDbParameters parameters) - { - IList results = QueryWithRowMapper(cmdType, cmdText, rowMapper, parameters); - return DataAccessUtils.RequiredUniqueResultSet(results); - } - - - public virtual T QueryForObject(CommandType cmdType, string cmdText, IRowMapper rowMapper, - string parameterName, Enum dbType, int size, object parameterValue) - { - IList results = QueryWithRowMapper(cmdType, cmdText, rowMapper, parameterName, dbType, size, parameterValue); - return DataAccessUtils.RequiredUniqueResultSet(results); - } - #endregion - - #region Query for ObjectDelegate - - public virtual T QueryForObjectDelegate(CommandType cmdType, string cmdText, RowMapperDelegate rowMapperDelegate) - { - IList results = QueryWithRowMapperDelegate(cmdType, cmdText, rowMapperDelegate); - return DataAccessUtils.RequiredUniqueResultSet(results); - } - - public virtual T QueryForObjectDelegate(CommandType cmdType, string cmdText, RowMapperDelegate rowMapperDelegate, ICommandSetter commandSetter) - { - IList results = QueryWithRowMapperDelegate(cmdType, cmdText, rowMapperDelegate, commandSetter); - return DataAccessUtils.RequiredUniqueResultSet(results); - } - - public virtual T QueryForObjectDelegate(CommandType cmdType, string cmdText, RowMapperDelegate rowMapperDelegate, IDbParameters parameters) - { - IList results = QueryWithRowMapperDelegate(cmdType, cmdText, rowMapperDelegate, parameters); - return DataAccessUtils.RequiredUniqueResultSet(results); - } - - - public virtual T QueryForObjectDelegate(CommandType cmdType, string cmdText, RowMapperDelegate rowMapperDelegate, - string parameterName, Enum dbType, int size, object parameterValue) - { - IList results = QueryWithRowMapperDelegate(cmdType, cmdText, rowMapperDelegate, parameterName, dbType, size, parameterValue); - return DataAccessUtils.RequiredUniqueResultSet(results); - } - #endregion - - - #region Query with CommandCreator - - public virtual T QueryWithCommandCreator(IDbCommandCreator cc, IResultSetExtractor rse) - { - return QueryWithCommandCreator(cc, rse, null); - } - - public virtual void QueryWithCommandCreator(IDbCommandCreator cc, IRowCallback rowCallback) - { - classicAdoTemplate.QueryWithCommandCreator(cc, rowCallback, null); - } - - public virtual IList QueryWithCommandCreator(IDbCommandCreator cc, IRowMapper rowMapper) - { - return QueryWithCommandCreator(cc, rowMapper, null); - } - - public virtual T QueryWithCommandCreator(IDbCommandCreator cc, IResultSetExtractor rse, IDictionary returnedParameters) - { - if (rse == null) - { - throw new ArgumentNullException("Result Set Extractor must not be null"); - } - - return Execute(cc, new AdoResultSetExtractorWithOutputParamsCommandCallback(this, rse, returnedParameters)); - } - - - public virtual void QueryWithCommandCreator(IDbCommandCreator cc, IRowCallback rowCallback, IDictionary returnedParameters) - { - classicAdoTemplate.QueryWithCommandCreator(cc, rowCallback, returnedParameters); - } - - - public virtual IList QueryWithCommandCreator(IDbCommandCreator cc, IRowMapper rowMapper, IDictionary returnedParameters) - { - if (rowMapper == null) - { - throw new ArgumentNullException("rowMapper must not be null"); - } - - return Execute(cc, new AdoRowMapperQueryCommandCallback(this, rowMapper, returnedParameters)); - } - - - public virtual IDictionary QueryWithCommandCreator(IDbCommandCreator cc, IList namedResultSetProcessors) - { - return classicAdoTemplate.Execute(cc, new AdoResultProcessorsQueryCommandCallback(this, namedResultSetProcessors)) as IDictionary; - } - - - public virtual IDictionary QueryWithCommandCreator(IDbCommandCreator cc, IList namedResultSetProcessors) - { - return classicAdoTemplate.Execute(cc, new AdoResultProcessorsQueryCommandCallback(this, namedResultSetProcessors)) as IDictionary; - } - - - #endregion - - #region General Helper Methods - - /// - /// Checks if DbProvider is not null and creates ExceptionTranslator if not LazyInit. - /// - public override void AfterPropertiesSet() - { - classicAdoTemplate.AfterPropertiesSet(); - classicAdoTemplate.CommandTimeout = CommandTimeout; - } - - /// - /// Creates the data reader wrapper for use in AdoTemplate callback methods. - /// - /// The reader to wrap. - /// The data reader used in AdoTemplate callbacks - public override IDataReader CreateDataReaderWrapper(IDataReader readerToWrap) - { - return classicAdoTemplate.CreateDataReaderWrapper(readerToWrap); - } - - #endregion - - #region Parameter Creation Helper Methods - - /// - /// Derives the parameters of a stored procedure including the return parameter - /// - /// Name of the procedure. - /// if set to true to include return parameter. - /// The stored procedure parameters - public override IDataParameter[] DeriveParameters(string procedureName, bool includeReturnParameter) - { - return classicAdoTemplate.DeriveParameters(procedureName, includeReturnParameter); - } - - #endregion - - - - - - #region Internal Helper classes - - internal class QueryCallback : IDbCommandCallback, ICommandTextProvider - { - private AdoTemplate adoTemplate; - private IResultSetExtractor rse; - private ResultSetExtractorDelegate resultSetExtractorDelegate; - private CommandType commandType; - private string commandText; - private IDbParameters parameters; - - public QueryCallback(AdoTemplate adoTemplate, - CommandType cmdType, - string cmdText, - IResultSetExtractor rse, - IDbParameters dbParameters) - { - this.adoTemplate = adoTemplate; - commandType = cmdType; - commandText = cmdText; - this.rse = rse; - parameters = dbParameters; - } - - public QueryCallback(AdoTemplate adoTemplate, - CommandType cmdType, - string cmdText, - ResultSetExtractorDelegate resultSetExtractorDelegate, - IDbParameters dbParameters) - { - this.adoTemplate = adoTemplate; - commandType = cmdType; - commandText = cmdText; - this.resultSetExtractorDelegate = resultSetExtractorDelegate; - parameters = dbParameters; - } - - public string CommandText - { - get { return commandText; } - } - - public T DoInCommand(IDbCommand command) - { - IDataReader reader = null; - try + command.CommandType = commandType; + command.CommandText = commandText; + if (commandSetter != null) { - command.CommandType = commandType; - command.CommandText = commandText; - ParameterUtils.CopyParameters(command, parameters); - reader = adoTemplate.CreateDataReaderWrapper(command.ExecuteReader()); - T returnValue = default(T); - if (rse != null) - { - returnValue = rse.ExtractData(reader); - } - else - { - returnValue = resultSetExtractorDelegate(reader); - } - return returnValue; + commandSetter.SetValues(command); } - finally + + reader = adoTemplate.CreateDataReaderWrapper(command.ExecuteReader()); + if (rse != null) { - Support.AdoUtils.CloseReader(reader); - ParameterUtils.CopyParameters(parameters, command); + return rse.ExtractData(reader); + } + else + { + return resultSetExtractorDelegate(reader); } } + finally + { + Support.AdoUtils.CloseReader(reader); + } + } + } + internal class QueryCallbackWithCommandSetterDelegate : IDbCommandCallback, ICommandTextProvider + { + private AdoTemplate adoTemplate; + private IResultSetExtractor rse; + private ResultSetExtractorDelegate resultSetExtractorDelegate; + private CommandType commandType; + private string commandText; + private CommandSetterDelegate commandSetterDelegate; + public QueryCallbackWithCommandSetterDelegate(AdoTemplate adoTemplate, + CommandType cmdType, + string cmdText, + IResultSetExtractor rse, + CommandSetterDelegate commandSetterDelegate) + { + this.adoTemplate = adoTemplate; + commandType = cmdType; + commandText = cmdText; + this.rse = rse; + this.commandSetterDelegate = commandSetterDelegate; } - internal class QueryCallbackWithCommandSetter : IDbCommandCallback, ICommandTextProvider + public QueryCallbackWithCommandSetterDelegate(AdoTemplate adoTemplate, + CommandType cmdType, + string cmdText, + ResultSetExtractorDelegate resultSetExtractorDelegate, + CommandSetterDelegate commandSetterDelegate) { - private AdoTemplate adoTemplate; - private IResultSetExtractor rse; - private ResultSetExtractorDelegate resultSetExtractorDelegate; - private CommandType commandType; - private string commandText; - private ICommandSetter commandSetter; + this.adoTemplate = adoTemplate; + commandType = cmdType; + commandText = cmdText; + this.resultSetExtractorDelegate = resultSetExtractorDelegate; + this.commandSetterDelegate = commandSetterDelegate; + } - public QueryCallbackWithCommandSetter(AdoTemplate adoTemplate, - CommandType cmdType, - string cmdText, - IResultSetExtractor rse, - ICommandSetter commandSetter) - { - this.adoTemplate = adoTemplate; - commandType = cmdType; - commandText = cmdText; - this.rse = rse; - this.commandSetter = commandSetter; - } + public string CommandText + { + get { return commandText; } + } - public QueryCallbackWithCommandSetter(AdoTemplate adoTemplate, - CommandType cmdType, - string cmdText, - ResultSetExtractorDelegate resultSetExtractorDelegate, - ICommandSetter commandSetter) + public T DoInCommand(IDbCommand command) + { + IDataReader reader = null; + try { - this.adoTemplate = adoTemplate; - commandType = cmdType; - commandText = cmdText; - this.resultSetExtractorDelegate = resultSetExtractorDelegate; - this.commandSetter = commandSetter; - } - - public string CommandText - { - get { return commandText; } - } - - public T DoInCommand(IDbCommand command) - { - IDataReader reader = null; - try + command.CommandType = commandType; + command.CommandText = commandText; + if (commandSetterDelegate != null) { - command.CommandType = commandType; - command.CommandText = commandText; - if (commandSetter != null) + commandSetterDelegate(command); + } + + reader = adoTemplate.CreateDataReaderWrapper(command.ExecuteReader()); + if (rse != null) + { + return rse.ExtractData(reader); + } + else + { + return resultSetExtractorDelegate(reader); + } + } + finally + { + Support.AdoUtils.CloseReader(reader); + } + } + } + + internal class AdoRowMapperQueryCommandCallback : IDbCommandCallback> + { + private AdoTemplate adoTemplate; + private IRowMapper rowMapper; + private IDictionary returnedParameters; + + public AdoRowMapperQueryCommandCallback(AdoTemplate adoTemplate, IRowMapper rowMapper, IDictionary returnedParameters) + { + this.adoTemplate = adoTemplate; + this.rowMapper = rowMapper; + this.returnedParameters = returnedParameters; + } + + public IList DoInCommand(IDbCommand command) + { + IList objectList; + //Extract the single returned result set + IDataReader reader = null; + try + { + reader = adoTemplate.CreateDataReaderWrapper(command.ExecuteReader()); + RowMapperResultSetExtractor rse = new RowMapperResultSetExtractor(rowMapper, 1); + objectList = rse.ExtractData(reader); + } + finally + { + Support.AdoUtils.CloseReader(reader); + } + + ParameterUtils.ExtractOutputParameters(returnedParameters, command); + return objectList; + } + } + + internal class AdoResultSetExtractorWithOutputParamsCommandCallback : IDbCommandCallback + { + private AdoTemplate adoTemplate; + private IResultSetExtractor rse; + private IDictionary returnedParameters; + + public AdoResultSetExtractorWithOutputParamsCommandCallback(AdoTemplate adoTemplate, IResultSetExtractor rse, IDictionary returnedParameters) + { + this.adoTemplate = adoTemplate; + this.rse = rse; + this.returnedParameters = returnedParameters; + } + + public T DoInCommand(IDbCommand command) + { + T returnVal; + //Extract the single returned result set + IDataReader reader = null; + try + { + reader = adoTemplate.CreateDataReaderWrapper(command.ExecuteReader()); + returnVal = rse.ExtractData(reader); + } + finally + { + Support.AdoUtils.CloseReader(reader); + } + + ParameterUtils.ExtractOutputParameters(returnedParameters, command); + return returnVal; + } + } + + internal class BaseAdoResultProcessorsQueryCommandCallback + { + public static void ProcessNonGenericResultSetProcessor(NamedResultSetProcessor otherResultSetProcessor, IDataReader reader, IDictionary returnedResults) + { + string parameterName = otherResultSetProcessor.Name; + if (otherResultSetProcessor.ResultSetProcessor is IResultSetExtractor) + { + IResultSetExtractor rse = (IResultSetExtractor) otherResultSetProcessor.ResultSetProcessor; + object result = rse.ExtractData(reader); + returnedResults.Add(parameterName, result); + } + else if (otherResultSetProcessor.ResultSetProcessor is IRowMapper) + { + IRowMapper rowMapper = (IRowMapper) otherResultSetProcessor.ResultSetProcessor; + object result = (new RowMapperResultSetExtractor(rowMapper)).ExtractData(reader); + returnedResults.Add(parameterName, result); + } + else if (otherResultSetProcessor.ResultSetProcessor is IRowCallback) + { + IRowCallback rowCallback = (IRowCallback) otherResultSetProcessor.ResultSetProcessor; + (new RowCallbackResultSetExtractor(rowCallback)).ExtractData(reader); + returnedResults.Add(parameterName, "ResultSet returned was processed by an IRowCallback"); + } + } + + public static void ProcessFirstGenericResultSetProcessor(NamedResultSetProcessor firstResultSetProcessor, IDataReader reader, IDictionary returnedResults) + { + string parameterName = firstResultSetProcessor.Name; + if (firstResultSetProcessor.ResultSetExtractor != null) + { + IResultSetExtractor rse = firstResultSetProcessor.ResultSetExtractor; + T result = rse.ExtractData(reader); + returnedResults.Add(parameterName, result); + } + else if (firstResultSetProcessor.RowMapper != null) + { + IRowMapper rowMapper = firstResultSetProcessor.RowMapper; + object result = (new RowMapperResultSetExtractor(rowMapper)).ExtractData(reader); + returnedResults.Add(parameterName, result); + } + else if (firstResultSetProcessor.RowCallback != null) + { + IRowCallback rowCallback = firstResultSetProcessor.RowCallback; + (new RowCallbackResultSetExtractor(rowCallback)).ExtractData(reader); + returnedResults.Add(parameterName, "ResultSet returned was processed by an IRowCallback"); + } + } + } + + internal class AdoResultProcessorsQueryCommandCallback : BaseAdoResultProcessorsQueryCommandCallback, ICommandCallback + { + private AdoTemplate adoTemplate; + private IList namedResultSetProcessors; + + public AdoResultProcessorsQueryCommandCallback(AdoTemplate adoTemplate, IList namedResultSetProcessors) + { + this.adoTemplate = adoTemplate; + this.namedResultSetProcessors = namedResultSetProcessors; + } + + public object DoInCommand(IDbCommand command) + { + IDictionary returnedResults = new Hashtable(); + int resultSetIndex = 0; + IDataReader reader = null; + try + { + reader = adoTemplate.CreateDataReaderWrapper(command.ExecuteReader()); + + //TODO On >= .NET 2.0 platforms make use of DbDataReader.HasRows property to + // see if there is a result set. now currently assuming matching + // NamedResultSetProcessor/ResultSet pairs. + + do + { + if (namedResultSetProcessors.Count == 0) { - commandSetter.SetValues(command); - } - reader = adoTemplate.CreateDataReaderWrapper(command.ExecuteReader()); - if (rse != null) - { - return rse.ExtractData(reader); - } - else - { - return resultSetExtractorDelegate(reader); + //We could just have output parameters and/or return value, that is, no result sets + //If we didn't register a result set processor, it is likely that a result set wasn't expected. + break; } - } - finally - { - Support.AdoUtils.CloseReader(reader); - } - } - - - } - - internal class QueryCallbackWithCommandSetterDelegate : IDbCommandCallback, ICommandTextProvider - { - private AdoTemplate adoTemplate; - private IResultSetExtractor rse; - private ResultSetExtractorDelegate resultSetExtractorDelegate; - private CommandType commandType; - private string commandText; - private CommandSetterDelegate commandSetterDelegate; - - public QueryCallbackWithCommandSetterDelegate(AdoTemplate adoTemplate, - CommandType cmdType, - string cmdText, - IResultSetExtractor rse, - CommandSetterDelegate commandSetterDelegate) - { - this.adoTemplate = adoTemplate; - commandType = cmdType; - commandText = cmdText; - this.rse = rse; - this.commandSetterDelegate = commandSetterDelegate; - } - - public QueryCallbackWithCommandSetterDelegate(AdoTemplate adoTemplate, - CommandType cmdType, - string cmdText, - ResultSetExtractorDelegate resultSetExtractorDelegate, - CommandSetterDelegate commandSetterDelegate) - { - this.adoTemplate = adoTemplate; - commandType = cmdType; - commandText = cmdText; - this.resultSetExtractorDelegate = resultSetExtractorDelegate; - this.commandSetterDelegate = commandSetterDelegate; - } - - public string CommandText - { - get { return commandText; } - } - - public T DoInCommand(IDbCommand command) - { - IDataReader reader = null; - try - { - command.CommandType = commandType; - command.CommandText = commandText; - if (commandSetterDelegate != null) + NamedResultSetProcessor firstResultSetProcessor = null; + NamedResultSetProcessor otherResultSetProcessor = null; + try { - commandSetterDelegate(command); - } - reader = adoTemplate.CreateDataReaderWrapper(command.ExecuteReader()); - if (rse != null) - { - return rse.ExtractData(reader); - } - else - { - return resultSetExtractorDelegate(reader); - } - } - finally - { - Support.AdoUtils.CloseReader(reader); - } - } - - - } - - internal class AdoRowMapperQueryCommandCallback : IDbCommandCallback> - { - private AdoTemplate adoTemplate; - private IRowMapper rowMapper; - private IDictionary returnedParameters; - - public AdoRowMapperQueryCommandCallback(AdoTemplate adoTemplate, IRowMapper rowMapper, IDictionary returnedParameters) - { - this.adoTemplate = adoTemplate; - this.rowMapper = rowMapper; - this.returnedParameters = returnedParameters; - } - - public IList DoInCommand(IDbCommand command) - { - IList objectList; - //Extract the single returned result set - IDataReader reader = null; - try - { - reader = adoTemplate.CreateDataReaderWrapper(command.ExecuteReader()); - RowMapperResultSetExtractor rse = new RowMapperResultSetExtractor(rowMapper, 1); - objectList = rse.ExtractData(reader); - } - finally - { - Support.AdoUtils.CloseReader(reader); - } - ParameterUtils.ExtractOutputParameters(returnedParameters, command); - return objectList; - } - } - - internal class AdoResultSetExtractorWithOutputParamsCommandCallback : IDbCommandCallback - { - private AdoTemplate adoTemplate; - private IResultSetExtractor rse; - private IDictionary returnedParameters; - - public AdoResultSetExtractorWithOutputParamsCommandCallback(AdoTemplate adoTemplate, IResultSetExtractor rse, IDictionary returnedParameters) - { - this.adoTemplate = adoTemplate; - this.rse = rse; - this.returnedParameters = returnedParameters; - } - - public T DoInCommand(IDbCommand command) - { - T returnVal; - //Extract the single returned result set - IDataReader reader = null; - try - { - reader = adoTemplate.CreateDataReaderWrapper(command.ExecuteReader()); - returnVal = rse.ExtractData(reader); - } - finally - { - Support.AdoUtils.CloseReader(reader); - } - ParameterUtils.ExtractOutputParameters(returnedParameters, command); - return returnVal; - } - } - - internal class BaseAdoResultProcessorsQueryCommandCallback - { - public static void ProcessNonGenericResultSetProcessor(NamedResultSetProcessor otherResultSetProcessor, IDataReader reader, IDictionary returnedResults) - { - string parameterName = otherResultSetProcessor.Name; - if (otherResultSetProcessor.ResultSetProcessor is IResultSetExtractor) - { - IResultSetExtractor rse = (IResultSetExtractor)otherResultSetProcessor.ResultSetProcessor; - object result = rse.ExtractData(reader); - returnedResults.Add(parameterName, result); - } - else if (otherResultSetProcessor.ResultSetProcessor is IRowMapper) - { - IRowMapper rowMapper = (IRowMapper)otherResultSetProcessor.ResultSetProcessor; - object result = (new RowMapperResultSetExtractor(rowMapper)).ExtractData(reader); - returnedResults.Add(parameterName, result); - } - else if (otherResultSetProcessor.ResultSetProcessor is IRowCallback) - { - IRowCallback rowCallback = (IRowCallback)otherResultSetProcessor.ResultSetProcessor; - (new RowCallbackResultSetExtractor(rowCallback)).ExtractData(reader); - returnedResults.Add(parameterName, "ResultSet returned was processed by an IRowCallback"); - } - } - - public static void ProcessFirstGenericResultSetProcessor(NamedResultSetProcessor firstResultSetProcessor, IDataReader reader, IDictionary returnedResults) - { - string parameterName = firstResultSetProcessor.Name; - if (firstResultSetProcessor.ResultSetExtractor != null) - { - IResultSetExtractor rse = firstResultSetProcessor.ResultSetExtractor; - T result = rse.ExtractData(reader); - returnedResults.Add(parameterName, result); - } - else if (firstResultSetProcessor.RowMapper != null) - { - IRowMapper rowMapper = firstResultSetProcessor.RowMapper; - object result = (new RowMapperResultSetExtractor(rowMapper)).ExtractData(reader); - returnedResults.Add(parameterName, result); - } - else if (firstResultSetProcessor.RowCallback != null) - { - IRowCallback rowCallback = firstResultSetProcessor.RowCallback; - (new RowCallbackResultSetExtractor(rowCallback)).ExtractData(reader); - returnedResults.Add(parameterName, "ResultSet returned was processed by an IRowCallback"); - } - } - } - - internal class AdoResultProcessorsQueryCommandCallback : BaseAdoResultProcessorsQueryCommandCallback, ICommandCallback - { - private AdoTemplate adoTemplate; - private IList namedResultSetProcessors; - - public AdoResultProcessorsQueryCommandCallback(AdoTemplate adoTemplate, IList namedResultSetProcessors) - { - this.adoTemplate = adoTemplate; - this.namedResultSetProcessors = namedResultSetProcessors; - } - - public object DoInCommand(IDbCommand command) - { - IDictionary returnedResults = new Hashtable(); - int resultSetIndex = 0; - IDataReader reader = null; - try - { - reader = adoTemplate.CreateDataReaderWrapper(command.ExecuteReader()); - - //TODO On >= .NET 2.0 platforms make use of DbDataReader.HasRows property to - // see if there is a result set. now currently assuming matching - // NamedResultSetProcessor/ResultSet pairs. - - do - { - if (namedResultSetProcessors.Count == 0) - { - //We could just have output parameters and/or return value, that is, no result sets - //If we didn't register a result set processor, it is likely that a result set wasn't expected. - break; - } - NamedResultSetProcessor firstResultSetProcessor = null; - NamedResultSetProcessor otherResultSetProcessor = null; - try - { - if (resultSetIndex == 0) - { - firstResultSetProcessor - = namedResultSetProcessors[resultSetIndex] as NamedResultSetProcessor; - //Will have possibility of run-time type error if using QueryWithCommandCreator - if (firstResultSetProcessor == null) - { - LOG.LogError("NamedResultSetProcessor for result set index " + resultSetIndex + - ", is not of expected type NamedResultSetProcessor. Type = " + - namedResultSetProcessors[resultSetIndex].GetType() + - "; Skipping processing for this result set."); - continue; - } - } - else - { - otherResultSetProcessor = - namedResultSetProcessors[resultSetIndex] as NamedResultSetProcessor; - if (otherResultSetProcessor == null) - { - - LOG.LogError("NamedResultSetProcessor for result set index " + resultSetIndex + - ", is not of expected type NamedResultSetProcessor Type = " + - namedResultSetProcessors[resultSetIndex].GetType() + - "; Skipping processing for this result set."); - continue; - } - } - } - catch (IndexOutOfRangeException e) - { - string message = "No NamedResultSetProcessor associated with result set index " + resultSetIndex; - LOG.LogError(e, message); - continue; - } - catch (ArgumentOutOfRangeException e) - { - string message = "No NamedResultSetProcessor associated with result set index " + resultSetIndex; - LOG.LogError(e, message); - continue; - } - - if (resultSetIndex == 0) { - ProcessFirstGenericResultSetProcessor(firstResultSetProcessor, reader, returnedResults); + firstResultSetProcessor + = namedResultSetProcessors[resultSetIndex] as NamedResultSetProcessor; + //Will have possibility of run-time type error if using QueryWithCommandCreator + if (firstResultSetProcessor == null) + { + LOG.LogError("NamedResultSetProcessor for result set index " + resultSetIndex + + ", is not of expected type NamedResultSetProcessor. Type = " + + namedResultSetProcessors[resultSetIndex].GetType() + + "; Skipping processing for this result set."); + continue; + } } else { - ProcessNonGenericResultSetProcessor(otherResultSetProcessor, reader, returnedResults); + otherResultSetProcessor = + namedResultSetProcessors[resultSetIndex] as NamedResultSetProcessor; + if (otherResultSetProcessor == null) + { + LOG.LogError("NamedResultSetProcessor for result set index " + resultSetIndex + + ", is not of expected type NamedResultSetProcessor Type = " + + namedResultSetProcessors[resultSetIndex].GetType() + + "; Skipping processing for this result set."); + continue; + } } - resultSetIndex++; + } + catch (IndexOutOfRangeException e) + { + string message = "No NamedResultSetProcessor associated with result set index " + resultSetIndex; + LOG.LogError(e, message); + continue; + } + catch (ArgumentOutOfRangeException e) + { + string message = "No NamedResultSetProcessor associated with result set index " + resultSetIndex; + LOG.LogError(e, message); + continue; + } - } while (reader.NextResult()); - } - finally - { - Support.AdoUtils.CloseReader(reader); - } - ParameterUtils.ExtractOutputParameters(returnedResults, command); - return returnedResults; + if (resultSetIndex == 0) + { + ProcessFirstGenericResultSetProcessor(firstResultSetProcessor, reader, returnedResults); + } + else + { + ProcessNonGenericResultSetProcessor(otherResultSetProcessor, reader, returnedResults); + } + + resultSetIndex++; + } while (reader.NextResult()); } + finally + { + Support.AdoUtils.CloseReader(reader); + } + + ParameterUtils.ExtractOutputParameters(returnedResults, command); + return returnedResults; + } + } + + internal class AdoResultProcessorsQueryCommandCallback : BaseAdoResultProcessorsQueryCommandCallback, ICommandCallback + { + private AdoTemplate adoTemplate; + private IList namedResultSetProcessors; + + public AdoResultProcessorsQueryCommandCallback(AdoTemplate adoTemplate, IList namedResultSetProcessors) + { + this.adoTemplate = adoTemplate; + this.namedResultSetProcessors = namedResultSetProcessors; } - - internal class AdoResultProcessorsQueryCommandCallback : BaseAdoResultProcessorsQueryCommandCallback, ICommandCallback + public object DoInCommand(IDbCommand command) { - private AdoTemplate adoTemplate; - private IList namedResultSetProcessors; - - public AdoResultProcessorsQueryCommandCallback(AdoTemplate adoTemplate, IList namedResultSetProcessors) + IDictionary returnedResults = new Hashtable(); + int resultSetIndex = 0; + IDataReader reader = null; + try { - this.adoTemplate = adoTemplate; - this.namedResultSetProcessors = namedResultSetProcessors; - } + reader = adoTemplate.CreateDataReaderWrapper(command.ExecuteReader()); - public object DoInCommand(IDbCommand command) - { - IDictionary returnedResults = new Hashtable(); - int resultSetIndex = 0; - IDataReader reader = null; - try + //TODO On >= .NET 2.0 platforms make use of DbDataReader.HasRows property to + // see if there is a result set. now currently assuming matching + // NamedResultSetProcessor/ResultSet pairs. + + do { - reader = adoTemplate.CreateDataReaderWrapper(command.ExecuteReader()); - - //TODO On >= .NET 2.0 platforms make use of DbDataReader.HasRows property to - // see if there is a result set. now currently assuming matching - // NamedResultSetProcessor/ResultSet pairs. - - do + if (namedResultSetProcessors.Count == 0) { - if (namedResultSetProcessors.Count == 0) - { - //We could just have output parameters and/or return value, that is, no result sets - //If we didn't register a result set processor, it is likely that a result set wasn't expected. - break; - } - NamedResultSetProcessor firstResultSetProcessor = null; - NamedResultSetProcessor secondResultSetProcessor = null; - NamedResultSetProcessor otherResultSetProcessor = null; - try - { - if (resultSetIndex == 0) - { - firstResultSetProcessor = namedResultSetProcessors[resultSetIndex] as NamedResultSetProcessor; - //Will only have possibility of run-time type error if using QueryWithCommandCreator - if (firstResultSetProcessor == null) - { - - LOG.LogError("NamedResultSetProcessor for result set index " + resultSetIndex + - ", is not of expected type NamedResultSetProcessor Type = " + - namedResultSetProcessors[resultSetIndex].GetType() + - "; Skipping processing for this result set."); - continue; - } - } else if (resultSetIndex == 1) - { - secondResultSetProcessor - = namedResultSetProcessors[resultSetIndex] as NamedResultSetProcessor; - if (secondResultSetProcessor == null) - { - - LOG.LogError("NamedResultSetProcessor for result set index " + resultSetIndex + - ", is not of expected type NamedResultSetProcessor Type = " + - namedResultSetProcessors[resultSetIndex].GetType() + - "; Skipping processing for this result set."); - continue; - } - } else - { - otherResultSetProcessor = - namedResultSetProcessors[resultSetIndex] as NamedResultSetProcessor; - if (otherResultSetProcessor == null) - { - - LOG.LogError("NamedResultSetProcessor for result set index " + resultSetIndex + - ", is not of expected type NamedResultSetProcessor Type = " + - namedResultSetProcessors[resultSetIndex].GetType() + - "; Skipping processing for this result set."); - continue; - } - } - - } - catch (IndexOutOfRangeException e) - { - string message = "No NamedResultSetProcessor associated with result set index " + resultSetIndex; - LOG.LogError(e, message); - continue; - } - catch (ArgumentOutOfRangeException e) - { - string message = "No NamedResultSetProcessor associated with result set index " + resultSetIndex; - LOG.LogError(e, message); - continue; - } + //We could just have output parameters and/or return value, that is, no result sets + //If we didn't register a result set processor, it is likely that a result set wasn't expected. + break; + } + NamedResultSetProcessor firstResultSetProcessor = null; + NamedResultSetProcessor secondResultSetProcessor = null; + NamedResultSetProcessor otherResultSetProcessor = null; + try + { if (resultSetIndex == 0) { - ProcessFirstGenericResultSetProcessor(firstResultSetProcessor, reader, returnedResults); + firstResultSetProcessor = namedResultSetProcessors[resultSetIndex] as NamedResultSetProcessor; + //Will only have possibility of run-time type error if using QueryWithCommandCreator + if (firstResultSetProcessor == null) + { + LOG.LogError("NamedResultSetProcessor for result set index " + resultSetIndex + + ", is not of expected type NamedResultSetProcessor Type = " + + namedResultSetProcessors[resultSetIndex].GetType() + + "; Skipping processing for this result set."); + continue; + } } else if (resultSetIndex == 1) { - string parameterName = secondResultSetProcessor.Name; - if (secondResultSetProcessor.ResultSetExtractor != null) + secondResultSetProcessor + = namedResultSetProcessors[resultSetIndex] as NamedResultSetProcessor; + if (secondResultSetProcessor == null) { - IResultSetExtractor rse = secondResultSetProcessor.ResultSetExtractor; - U result = rse.ExtractData(reader); - returnedResults.Add(parameterName, result); - } - else if (secondResultSetProcessor.RowMapper != null) - { - IRowMapper rowMapper = secondResultSetProcessor.RowMapper; - object result = (new RowMapperResultSetExtractor(rowMapper)).ExtractData(reader); - returnedResults.Add(parameterName, result); - } - else if (secondResultSetProcessor.RowCallback != null) - { - //In this case a dummy type parameter would need to be specified a better alternative would - //be to to use the single type parameterization of this callback. - IRowCallback rowCallback = secondResultSetProcessor.RowCallback; - (new RowCallbackResultSetExtractor(rowCallback)).ExtractData(reader); - returnedResults.Add(parameterName, "ResultSet returned was processed by an IRowCallback"); + LOG.LogError("NamedResultSetProcessor for result set index " + resultSetIndex + + ", is not of expected type NamedResultSetProcessor Type = " + + namedResultSetProcessors[resultSetIndex].GetType() + + "; Skipping processing for this result set."); + continue; } } else { - ProcessNonGenericResultSetProcessor(otherResultSetProcessor, reader, returnedResults); + otherResultSetProcessor = + namedResultSetProcessors[resultSetIndex] as NamedResultSetProcessor; + if (otherResultSetProcessor == null) + { + LOG.LogError("NamedResultSetProcessor for result set index " + resultSetIndex + + ", is not of expected type NamedResultSetProcessor Type = " + + namedResultSetProcessors[resultSetIndex].GetType() + + "; Skipping processing for this result set."); + continue; + } } - resultSetIndex++; + } + catch (IndexOutOfRangeException e) + { + string message = "No NamedResultSetProcessor associated with result set index " + resultSetIndex; + LOG.LogError(e, message); + continue; + } + catch (ArgumentOutOfRangeException e) + { + string message = "No NamedResultSetProcessor associated with result set index " + resultSetIndex; + LOG.LogError(e, message); + continue; + } - } while (reader.NextResult()); - } - finally - { - Support.AdoUtils.CloseReader(reader); - } - ParameterUtils.ExtractOutputParameters(returnedResults, command); - return returnedResults; + if (resultSetIndex == 0) + { + ProcessFirstGenericResultSetProcessor(firstResultSetProcessor, reader, returnedResults); + } + else if (resultSetIndex == 1) + { + string parameterName = secondResultSetProcessor.Name; + if (secondResultSetProcessor.ResultSetExtractor != null) + { + IResultSetExtractor rse = secondResultSetProcessor.ResultSetExtractor; + U result = rse.ExtractData(reader); + returnedResults.Add(parameterName, result); + } + else if (secondResultSetProcessor.RowMapper != null) + { + IRowMapper rowMapper = secondResultSetProcessor.RowMapper; + object result = (new RowMapperResultSetExtractor(rowMapper)).ExtractData(reader); + returnedResults.Add(parameterName, result); + } + else if (secondResultSetProcessor.RowCallback != null) + { + //In this case a dummy type parameter would need to be specified a better alternative would + //be to to use the single type parameterization of this callback. + IRowCallback rowCallback = secondResultSetProcessor.RowCallback; + (new RowCallbackResultSetExtractor(rowCallback)).ExtractData(reader); + returnedResults.Add(parameterName, "ResultSet returned was processed by an IRowCallback"); + } + } + else + { + ProcessNonGenericResultSetProcessor(otherResultSetProcessor, reader, returnedResults); + } + + resultSetIndex++; + } while (reader.NextResult()); + } + finally + { + Support.AdoUtils.CloseReader(reader); } - + ParameterUtils.ExtractOutputParameters(returnedResults, command); + return returnedResults; } - #endregion - } + + #endregion } diff --git a/src/Spring/Spring.Data/Data/Generic/CommandDelegate.cs b/src/Spring/Spring.Data/Data/Generic/CommandDelegate.cs index eaf4db89..9317deb6 100644 --- a/src/Spring/Spring.Data/Data/Generic/CommandDelegate.cs +++ b/src/Spring/Spring.Data/Data/Generic/CommandDelegate.cs @@ -1,14 +1,14 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. - * + * Copyright � 2002-2011 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. @@ -20,27 +20,26 @@ using System.Data.Common; -namespace Spring.Data.Generic -{ - /// - /// Generic callback delegate for code that operates on a DbCommand. - /// - /// - ///

Allows you to execute any number of operations - /// on a single DbCommand, for example a single ExecuteScalar - /// call or repeated execute calls with varying parameters. - ///

- ///

Used internally by AdoTemplate, but also useful for - /// application code. Note that the passed in DbCommand - /// has been created by the framework and will have its - /// Connection property set and the Transaction property - /// set based on the transaction context.

- ///
- /// The return type from executing the - /// callback - /// The ADO.NET DbCommand object - /// The object returned from processing with the - /// provided DbCommand - /// Mark Pollack - public delegate T CommandDelegate(DbCommand command); -} +namespace Spring.Data.Generic; + +/// +/// Generic callback delegate for code that operates on a DbCommand. +/// +/// +///

Allows you to execute any number of operations +/// on a single DbCommand, for example a single ExecuteScalar +/// call or repeated execute calls with varying parameters. +///

+///

Used internally by AdoTemplate, but also useful for +/// application code. Note that the passed in DbCommand +/// has been created by the framework and will have its +/// Connection property set and the Transaction property +/// set based on the transaction context.

+///
+/// The return type from executing the +/// callback +/// The ADO.NET DbCommand object +/// The object returned from processing with the +/// provided DbCommand +/// Mark Pollack +public delegate T CommandDelegate(DbCommand command); diff --git a/src/Spring/Spring.Data/Data/Generic/DataAdapterDelegate.cs b/src/Spring/Spring.Data/Data/Generic/DataAdapterDelegate.cs index ce4ec752..ad6f496e 100644 --- a/src/Spring/Spring.Data/Data/Generic/DataAdapterDelegate.cs +++ b/src/Spring/Spring.Data/Data/Generic/DataAdapterDelegate.cs @@ -1,14 +1,14 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. - * + * Copyright � 2002-2011 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. @@ -20,17 +20,15 @@ using System.Data; -namespace Spring.Data.Generic -{ - /// - /// Called by AdoTemplate.Execute with an preconfigured - /// ADO.NET IDbDataAdapter instance with its SelectCommand - /// property populated with CommandType and Text values - /// along with Connection/Transaction properties based on the - /// calling transaction context. - /// - /// An active IDbDataAdapter instance - /// The result object - public delegate T DataAdapterDelegate(IDbDataAdapter dataAdapter); - -} +namespace Spring.Data.Generic; + +/// +/// Called by AdoTemplate.Execute with an preconfigured +/// ADO.NET IDbDataAdapter instance with its SelectCommand +/// property populated with CommandType and Text values +/// along with Connection/Transaction properties based on the +/// calling transaction context. +/// +/// An active IDbDataAdapter instance +/// The result object +public delegate T DataAdapterDelegate(IDbDataAdapter dataAdapter); diff --git a/src/Spring/Spring.Data/Data/Generic/IAdoOperations.cs b/src/Spring/Spring.Data/Data/Generic/IAdoOperations.cs index 7a137d7b..9c133a5d 100644 --- a/src/Spring/Spring.Data/Data/Generic/IAdoOperations.cs +++ b/src/Spring/Spring.Data/Data/Generic/IAdoOperations.cs @@ -22,254 +22,236 @@ using System.Collections; using System.Data; using Spring.Data.Common; -namespace Spring.Data.Generic +namespace Spring.Data.Generic; + +/// +/// Interface that defines ADO.NET related database operations using generics +/// +/// Mark Pollack (.NET) +public interface IAdoOperations : ICommonAdoOperations { + #region General Execute Callback Methods + /// - /// Interface that defines ADO.NET related database operations using generics + /// Execute a ADO.NET operation on a command object using a generic interface based callback. /// - /// Mark Pollack (.NET) - public interface IAdoOperations : ICommonAdoOperations - { - - #region General Execute Callback Methods - - - /// - /// Execute a ADO.NET operation on a command object using a generic interface based callback. - /// - /// The type of object returned from the callback. - /// the callback to execute based on DbCommand - /// An object returned from callback - T Execute(ICommandCallback action); + /// The type of object returned from the callback. + /// the callback to execute based on DbCommand + /// An object returned from callback + T Execute(ICommandCallback action); + + /// + /// Execute a ADO.NET operation on a command object using a generic interface based callback. + /// + /// The type of object returned from the callback. + /// The callback to execute based on IDbCommand + /// An object returned from callback + T Execute(IDbCommandCallback action); + + /// + /// Execute a ADO.NET operation on a command object using a generic delegate callback. + /// + /// The type of object returned from the callback. + /// This allows for implementing arbitrary data access operations + /// on a single command within Spring's managed ADO.NET environment. + /// The delegate called with a DbCommand object. + /// A result object returned by the action or null + T Execute(CommandDelegate del); - /// - /// Execute a ADO.NET operation on a command object using a generic interface based callback. - /// - /// The type of object returned from the callback. - /// The callback to execute based on IDbCommand - /// An object returned from callback - T Execute(IDbCommandCallback action); + /// + /// Execute a ADO.NET operation on a command object using a generic delegate callback. + /// + /// The type of object returned from the callback. + /// This allows for implementing arbitrary data access operations + /// on a single command within Spring's managed ADO.NET environment. + /// The delegate called with a IDbCommand object. + /// A result object returned by the action or null + T Execute(IDbCommandDelegate del); - /// - /// Execute a ADO.NET operation on a command object using a generic delegate callback. - /// - /// The type of object returned from the callback. - /// This allows for implementing arbitrary data access operations - /// on a single command within Spring's managed ADO.NET environment. - /// The delegate called with a DbCommand object. - /// A result object returned by the action or null - T Execute(CommandDelegate del); + /// + /// Executes ADO.NET operations on a command object, created by the provided IDbCommandCreator, + /// using the interface based callback IDbCommandCallback. + /// + /// The type of object returned from the callback. + /// The command creator. + /// The callback to execute based on IDbCommand + /// A result object returned by the action or null + T Execute(IDbCommandCreator commandCreator, IDbCommandCallback action); - /// - /// Execute a ADO.NET operation on a command object using a generic delegate callback. - /// - /// The type of object returned from the callback. - /// This allows for implementing arbitrary data access operations - /// on a single command within Spring's managed ADO.NET environment. - /// The delegate called with a IDbCommand object. - /// A result object returned by the action or null - T Execute(IDbCommandDelegate del); + /// + /// Execute ADO.NET operations on a IDbDataAdapter object using an interface based callback. + /// + /// This allows for implementing abritrary data access operations + /// on a single DataAdapter within Spring's managed ADO.NET environment. + /// + /// The type of object returned from the callback. + /// The data adapter callback. + /// A result object returned by the callback or null + T Execute(IDataAdapterCallback dataAdapterCallback); - /// - /// Executes ADO.NET operations on a command object, created by the provided IDbCommandCreator, - /// using the interface based callback IDbCommandCallback. - /// - /// The type of object returned from the callback. - /// The command creator. - /// The callback to execute based on IDbCommand - /// A result object returned by the action or null - T Execute(IDbCommandCreator commandCreator, IDbCommandCallback action); + /// + /// Execute ADO.NET operations on a IDbDataAdapter object using an delgate based callback. + /// + /// This allows for implementing abritrary data access operations + /// on a single DataAdapter within Spring's managed ADO.NET environment. + /// + /// The type of object returned from the callback. + /// The delegate called with a IDbDataAdapter object. + /// A result object returned by the callback or null + T Execute(DataAdapterDelegate del); - /// - /// Execute ADO.NET operations on a IDbDataAdapter object using an interface based callback. - /// - /// This allows for implementing abritrary data access operations - /// on a single DataAdapter within Spring's managed ADO.NET environment. - /// - /// The type of object returned from the callback. - /// The data adapter callback. - /// A result object returned by the callback or null - T Execute(IDataAdapterCallback dataAdapterCallback); + #endregion - /// - /// Execute ADO.NET operations on a IDbDataAdapter object using an delgate based callback. - /// - /// This allows for implementing abritrary data access operations - /// on a single DataAdapter within Spring's managed ADO.NET environment. - /// - /// The type of object returned from the callback. - /// The delegate called with a IDbDataAdapter object. - /// A result object returned by the callback or null - T Execute(DataAdapterDelegate del); + #region Queries with RowMapper - #endregion + IList QueryWithRowMapper(CommandType cmdType, string cmdText, IRowMapper rowMapper); - #region Queries with RowMapper + IList QueryWithRowMapper(CommandType cmdType, string cmdText, IRowMapper rowMapper, + ICommandSetter commandSetter); - IList QueryWithRowMapper(CommandType cmdType, string cmdText, IRowMapper rowMapper); + IList QueryWithRowMapper(CommandType cmdType, string cmdText, IRowMapper rowMapper, + string parameterName, Enum dbType, int size, object parameterValue); - IList QueryWithRowMapper(CommandType cmdType, string cmdText, IRowMapper rowMapper, - ICommandSetter commandSetter); + IList QueryWithRowMapper(CommandType cmdType, string cmdText, IRowMapper rowMapper, + IDbParameters parameters); - IList QueryWithRowMapper(CommandType cmdType, string cmdText, IRowMapper rowMapper, - string parameterName, Enum dbType, int size, object parameterValue); + #endregion - IList QueryWithRowMapper(CommandType cmdType, string cmdText, IRowMapper rowMapper, - IDbParameters parameters); + #region Queries with RowMapperDelegate + IList QueryWithRowMapperDelegate(CommandType cmdType, string cmdText, RowMapperDelegate rowMapperDelegate); - #endregion + IList QueryWithRowMapperDelegate(CommandType cmdType, string cmdText, RowMapperDelegate rowMapperDelegate, + ICommandSetter commandSetter); - #region Queries with RowMapperDelegate + IList QueryWithRowMapperDelegate(CommandType cmdType, string cmdText, RowMapperDelegate rowMapperDelegate, + string parameterName, Enum dbType, int size, object parameterValue); - IList QueryWithRowMapperDelegate(CommandType cmdType, string cmdText, RowMapperDelegate rowMapperDelegate); + IList QueryWithRowMapperDelegate(CommandType cmdType, string cmdText, RowMapperDelegate rowMapperDelegate, + IDbParameters parameters); - IList QueryWithRowMapperDelegate(CommandType cmdType, string cmdText, RowMapperDelegate rowMapperDelegate, - ICommandSetter commandSetter); + #endregion + #region Queries with ResultSetExtractor - IList QueryWithRowMapperDelegate(CommandType cmdType, string cmdText, RowMapperDelegate rowMapperDelegate, - string parameterName, Enum dbType, int size, object parameterValue); + T QueryWithResultSetExtractor(CommandType cmdType, string cmdText, IResultSetExtractor resultSetExtractor); - IList QueryWithRowMapperDelegate(CommandType cmdType, string cmdText, RowMapperDelegate rowMapperDelegate, - IDbParameters parameters); + T QueryWithResultSetExtractor(CommandType cmdType, string cmdText, IResultSetExtractor resultSetExtractor, + string name, Enum dbType, int size, object parameterValue); + T QueryWithResultSetExtractor(CommandType cmdType, string cmdText, IResultSetExtractor resultSetExtractor, + IDbParameters parameters); - #endregion + T QueryWithResultSetExtractor(CommandType cmdType, string cmdText, IResultSetExtractor resultSetExtractor, + ICommandSetter commandSetter); - #region Queries with ResultSetExtractor + T QueryWithResultSetExtractor(CommandType cmdType, string cmdText, IResultSetExtractor resultSetExtractor, + CommandSetterDelegate commandSetterDelegate); - T QueryWithResultSetExtractor(CommandType cmdType, string cmdText, IResultSetExtractor resultSetExtractor); + #endregion - T QueryWithResultSetExtractor(CommandType cmdType, string cmdText, IResultSetExtractor resultSetExtractor, - string name, Enum dbType, int size, object parameterValue); + #region Queries with ResultSetExtractorDelegate - T QueryWithResultSetExtractor(CommandType cmdType, string cmdText, IResultSetExtractor resultSetExtractor, - IDbParameters parameters); + T QueryWithResultSetExtractorDelegate(CommandType cmdType, string cmdText, ResultSetExtractorDelegate resultSetExtractor); - T QueryWithResultSetExtractor(CommandType cmdType, string cmdText, IResultSetExtractor resultSetExtractor, - ICommandSetter commandSetter); + T QueryWithResultSetExtractorDelegate(CommandType cmdType, string cmdText, ResultSetExtractorDelegate resultSetExtractor, + string paramenterName, Enum dbType, int size, object parameterValue); - T QueryWithResultSetExtractor(CommandType cmdType, string cmdText, IResultSetExtractor resultSetExtractor, - CommandSetterDelegate commandSetterDelegate); - #endregion + T QueryWithResultSetExtractorDelegate(CommandType cmdType, string cmdText, ResultSetExtractorDelegate resultSetExtractor, + IDbParameters parameters); + T QueryWithResultSetExtractorDelegate(CommandType cmdType, string cmdText, ResultSetExtractorDelegate resultSetExtractor, + ICommandSetter commandSetter); - #region Queries with ResultSetExtractorDelegate + T QueryWithResultSetExtractorDelegate(CommandType cmdType, string cmdText, ResultSetExtractorDelegate resultSetExtractor, + CommandSetterDelegate commandSetterDelegate); - T QueryWithResultSetExtractorDelegate(CommandType cmdType, string cmdText, ResultSetExtractorDelegate resultSetExtractor); + #endregion - T QueryWithResultSetExtractorDelegate(CommandType cmdType, string cmdText, ResultSetExtractorDelegate resultSetExtractor, - string paramenterName, Enum dbType, int size, object parameterValue); + #region Queries for Object - T QueryWithResultSetExtractorDelegate(CommandType cmdType, string cmdText, ResultSetExtractorDelegate resultSetExtractor, - IDbParameters parameters); + T QueryForObject(CommandType cmdType, string sql, IRowMapper rowMapper); - T QueryWithResultSetExtractorDelegate(CommandType cmdType, string cmdText, ResultSetExtractorDelegate resultSetExtractor, - ICommandSetter commandSetter); + T QueryForObject(CommandType cmdType, string sql, IRowMapper rowMapper, ICommandSetter commandSetter); - T QueryWithResultSetExtractorDelegate(CommandType cmdType, string cmdText, ResultSetExtractorDelegate resultSetExtractor, - CommandSetterDelegate commandSetterDelegate); - #endregion + T QueryForObject(CommandType cmdType, string sql, IRowMapper rowMapper, IDbParameters parameters); - #region Queries for Object + T QueryForObject(CommandType cmdType, string sql, IRowMapper rowMapper, + string name, Enum dbType, int size, object parameterValue); - T QueryForObject(CommandType cmdType, string sql, IRowMapper rowMapper); + #endregion + #region Queries for ObjectDelegate - T QueryForObject(CommandType cmdType, string sql, IRowMapper rowMapper, ICommandSetter commandSetter); + T QueryForObjectDelegate(CommandType cmdType, string sql, RowMapperDelegate rowMapper); + T QueryForObjectDelegate(CommandType cmdType, string sql, RowMapperDelegate rowMapper, ICommandSetter commandSetter); - T QueryForObject(CommandType cmdType, string sql, IRowMapper rowMapper, IDbParameters parameters); + T QueryForObjectDelegate(CommandType cmdType, string sql, RowMapperDelegate rowMapper, IDbParameters parameters); + T QueryForObjectDelegate(CommandType cmdType, string sql, RowMapperDelegate rowMapper, + string name, Enum dbType, int size, object parameterValue); - T QueryForObject(CommandType cmdType, string sql, IRowMapper rowMapper, - string name, Enum dbType, int size, object parameterValue); + #endregion + #region Query With CommandCreator + T QueryWithCommandCreator(IDbCommandCreator cc, IResultSetExtractor rse); - #endregion + IList QueryWithCommandCreator(IDbCommandCreator cc, IRowMapper rowMapper); - #region Queries for ObjectDelegate + T QueryWithCommandCreator(IDbCommandCreator cc, IResultSetExtractor rse, IDictionary returnedParameters); - T QueryForObjectDelegate(CommandType cmdType, string sql, RowMapperDelegate rowMapper); + IList QueryWithCommandCreator(IDbCommandCreator cc, IRowMapper rowMapper, + IDictionary returnedParameters); + IDictionary QueryWithCommandCreator(IDbCommandCreator cc, IList namedResultSetProcessors); - T QueryForObjectDelegate(CommandType cmdType, string sql, RowMapperDelegate rowMapper, ICommandSetter commandSetter); + IDictionary QueryWithCommandCreator(IDbCommandCreator cc, IList namedResultSetProcessors); + #endregion - T QueryForObjectDelegate(CommandType cmdType, string sql, RowMapperDelegate rowMapper, IDbParameters parameters); + #region Parameter Creation Helper Methods + IDbParameters CreateDbParameters(); - T QueryForObjectDelegate(CommandType cmdType, string sql, RowMapperDelegate rowMapper, - string name, Enum dbType, int size, object parameterValue); + /// + /// Note that output parameters are marked input/output after derivation.... + /// (TODO - double check....) + /// + /// + /// + IDataParameter[] DeriveParameters(string procedureName); + IDataParameter[] DeriveParameters(string procedureName, bool includeReturnParameter); + #endregion - #endregion + #region Behavioral Control Properties - #region Query With CommandCreator + /// + /// An instance of a DbProvider implementation. + /// + IDbProvider DbProvider { get; set; } - T QueryWithCommandCreator(IDbCommandCreator cc, IResultSetExtractor rse); + /// + /// Gets or set the System.Type to use to create an instance of IDataReaderWrapper + /// for the purpose of having defaults values to use in case of DBNull values read + /// from IDataReader. + /// + /// The type of the data reader wrapper. + Type DataReaderWrapperType { get; set; } - IList QueryWithCommandCreator(IDbCommandCreator cc, IRowMapper rowMapper); + /// + /// Gets or sets the command timeout for IDbCommands that this AdoTemplate executes. + /// + /// Default is 0, indicating to use the database provider's default. + /// Any timeout specified here will be overridden by the remaining + /// transaction timeout when executing within a transaction that has a + /// timeout specified at the transaction level. + /// + /// The command timeout. + int CommandTimeout { get; set; } - T QueryWithCommandCreator(IDbCommandCreator cc, IResultSetExtractor rse, IDictionary returnedParameters); - - IList QueryWithCommandCreator(IDbCommandCreator cc, IRowMapper rowMapper, - IDictionary returnedParameters); - - - IDictionary QueryWithCommandCreator(IDbCommandCreator cc, IList namedResultSetProcessors); - - IDictionary QueryWithCommandCreator(IDbCommandCreator cc, IList namedResultSetProcessors); - - #endregion - - #region Parameter Creation Helper Methods - - IDbParameters CreateDbParameters(); - - /// - /// Note that output parameters are marked input/output after derivation.... - /// (TODO - double check....) - /// - /// - /// - IDataParameter[] DeriveParameters(string procedureName); - - IDataParameter[] DeriveParameters(string procedureName, bool includeReturnParameter); - - #endregion - - #region Behavioral Control Properties - - /// - /// An instance of a DbProvider implementation. - /// - IDbProvider DbProvider { get; set; } - - /// - /// Gets or set the System.Type to use to create an instance of IDataReaderWrapper - /// for the purpose of having defaults values to use in case of DBNull values read - /// from IDataReader. - /// - /// The type of the data reader wrapper. - Type DataReaderWrapperType { get; set; } - - /// - /// Gets or sets the command timeout for IDbCommands that this AdoTemplate executes. - /// - /// Default is 0, indicating to use the database provider's default. - /// Any timeout specified here will be overridden by the remaining - /// transaction timeout when executing within a transaction that has a - /// timeout specified at the transaction level. - /// - /// The command timeout. - int CommandTimeout { get; set; } - - - #endregion - - } + #endregion } diff --git a/src/Spring/Spring.Data/Data/Generic/ICommandCallback.cs b/src/Spring/Spring.Data/Data/Generic/ICommandCallback.cs index 5cdd5803..f8dbacb8 100644 --- a/src/Spring/Spring.Data/Data/Generic/ICommandCallback.cs +++ b/src/Spring/Spring.Data/Data/Generic/ICommandCallback.cs @@ -1,14 +1,14 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. - * + * Copyright � 2002-2011 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. @@ -20,38 +20,36 @@ using System.Data.Common; -namespace Spring.Data.Generic -{ +namespace Spring.Data.Generic; +/// +/// Generic callback interface for code that operates on a +/// DbCommand. +/// +/// The return type from executing the +/// callback +/// +///

Allows you to execute any number of operations +/// on a single DbCommand, for example a single ExecuteScalar +/// call or repeated execute calls with varying parameters. +///

+///

Used internally by AdoTemplate, but also useful for +/// application code. Note that the passed in DbCommand +/// has been created by the framework and will have its +/// Connection property set and the Transaction property +/// set based on the transaction context.

+///
+/// Mark Pollack +public interface ICommandCallback +{ /// - /// Generic callback interface for code that operates on a - /// DbCommand. + /// Called by AdoTemplate.Execute with an active ADO.NET IDbCommand. + /// The calling code does not need to care about closing the + /// command or the connection, or + /// about handling transactions: this will all be handled by + /// Spring's AdoTemplate /// - /// The return type from executing the - /// callback - /// - ///

Allows you to execute any number of operations - /// on a single DbCommand, for example a single ExecuteScalar - /// call or repeated execute calls with varying parameters. - ///

- ///

Used internally by AdoTemplate, but also useful for - /// application code. Note that the passed in DbCommand - /// has been created by the framework and will have its - /// Connection property set and the Transaction property - /// set based on the transaction context.

- ///
- /// Mark Pollack - public interface ICommandCallback - { - /// - /// Called by AdoTemplate.Execute with an active ADO.NET IDbCommand. - /// The calling code does not need to care about closing the - /// command or the connection, or - /// about handling transactions: this will all be handled by - /// Spring's AdoTemplate - /// - /// An active IDbCommand instance - /// The result object - T DoInCommand(DbCommand command); - } -} + /// An active IDbCommand instance + /// The result object + T DoInCommand(DbCommand command); +} \ No newline at end of file diff --git a/src/Spring/Spring.Data/Data/Generic/IDataAdapterCallback.cs b/src/Spring/Spring.Data/Data/Generic/IDataAdapterCallback.cs index d37ece79..4de4f955 100644 --- a/src/Spring/Spring.Data/Data/Generic/IDataAdapterCallback.cs +++ b/src/Spring/Spring.Data/Data/Generic/IDataAdapterCallback.cs @@ -1,14 +1,14 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. - * + * Copyright � 2002-2011 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. @@ -20,39 +20,38 @@ using System.Data; -namespace Spring.Data.Generic +namespace Spring.Data.Generic; + +/// +/// Generic callback interface for code that operates on a +/// IDbDataAdapter. +/// +/// +///

Allows you to execute any number of operations +/// on a IDbDataAdapter, for example to Fill a DataSet +/// or other more advanced operations such as the transfering +/// data between two different DataSets. +///

+///

Note that the passed in IDbDataAdapter +/// has been created by the framework and its SelectCommand +/// will be populated with values for CommandType and Text properties +/// along with Connection/Transaction properties based on the +/// calling transaction context. +///

+/// Execute(IDataAdapterCallback dataAdapterCallback) +/// method. +///
+/// Mark Pollack (.NET) +public interface IDataAdapterCallback { /// - /// Generic callback interface for code that operates on a - /// IDbDataAdapter. - /// - /// - ///

Allows you to execute any number of operations - /// on a IDbDataAdapter, for example to Fill a DataSet - /// or other more advanced operations such as the transfering - /// data between two different DataSets. - ///

- ///

Note that the passed in IDbDataAdapter - /// has been created by the framework and its SelectCommand - /// will be populated with values for CommandType and Text properties + /// Called by AdoTemplate.Execute with an preconfigured + /// ADO.NET IDbDataAdapter instance with its SelectCommand + /// property populated with CommandType and Text values /// along with Connection/Transaction properties based on the /// calling transaction context. - ///

- /// Execute(IDataAdapterCallback dataAdapterCallback) - /// method. - ///
- /// Mark Pollack (.NET) - public interface IDataAdapterCallback - { - /// - /// Called by AdoTemplate.Execute with an preconfigured - /// ADO.NET IDbDataAdapter instance with its SelectCommand - /// property populated with CommandType and Text values - /// along with Connection/Transaction properties based on the - /// calling transaction context. - /// - /// An active IDbDataAdapter instance - /// The result object - T DoInDataAdapter(IDbDataAdapter dataAdapter); - } + /// + /// An active IDbDataAdapter instance + /// The result object + T DoInDataAdapter(IDbDataAdapter dataAdapter); } diff --git a/src/Spring/Spring.Data/Data/Generic/IDbCommandCallback.cs b/src/Spring/Spring.Data/Data/Generic/IDbCommandCallback.cs index 5cc30e2e..ee9a38cb 100644 --- a/src/Spring/Spring.Data/Data/Generic/IDbCommandCallback.cs +++ b/src/Spring/Spring.Data/Data/Generic/IDbCommandCallback.cs @@ -1,14 +1,14 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. - * + * Copyright � 2002-2011 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. @@ -20,43 +20,42 @@ using System.Data; -namespace Spring.Data.Generic +namespace Spring.Data.Generic; + +/// +/// Generic callback interface for code that operates on a +/// IDbCommand. +/// +/// The return type from executing the +/// callback +/// +///

Allows you to execute any number of operations +/// on a single IDbCommand, for example a single ExecuteScalar +/// call or repeated execute calls with varying parameters. +///

+///

Used internally by AdoTemplate, but also useful for +/// application code. Note that the passed in IDbCommand +/// has been created by the framework and will have its +/// Connection property set and the Transaction property +/// set based on the transaction context.

+///

As an alternative to using this interface you can use +/// the delegate version which is particularly nice when using +/// anonymous delegates for writing more terse code and having +/// easy access to the variables in the calling class.

+///

See for a version that has the +/// base class DbCommand as the callback argument.

+///
+/// Mark Pollack +public interface IDbCommandCallback { /// - /// Generic callback interface for code that operates on a - /// IDbCommand. + /// Called by AdoTemplate.Execute with an active ADO.NET IDbCommand. + /// The calling code does not need to care about closing the + /// command or the connection, or + /// about handling transactions: this will all be handled by + /// Spring's AdoTemplate /// - /// The return type from executing the - /// callback - /// - ///

Allows you to execute any number of operations - /// on a single IDbCommand, for example a single ExecuteScalar - /// call or repeated execute calls with varying parameters. - ///

- ///

Used internally by AdoTemplate, but also useful for - /// application code. Note that the passed in IDbCommand - /// has been created by the framework and will have its - /// Connection property set and the Transaction property - /// set based on the transaction context.

- ///

As an alternative to using this interface you can use - /// the delegate version which is particularly nice when using - /// anonymous delegates for writing more terse code and having - /// easy access to the variables in the calling class.

- ///

See for a version that has the - /// base class DbCommand as the callback argument.

- ///
- /// Mark Pollack - public interface IDbCommandCallback - { - /// - /// Called by AdoTemplate.Execute with an active ADO.NET IDbCommand. - /// The calling code does not need to care about closing the - /// command or the connection, or - /// about handling transactions: this will all be handled by - /// Spring's AdoTemplate - /// - /// An active IDbCommand instance - /// The result object - T DoInCommand(IDbCommand command); - } + /// An active IDbCommand instance + /// The result object + T DoInCommand(IDbCommand command); } diff --git a/src/Spring/Spring.Data/Data/Generic/IDbCommandDelegate.cs b/src/Spring/Spring.Data/Data/Generic/IDbCommandDelegate.cs index 7e1b6efb..e193b6a2 100644 --- a/src/Spring/Spring.Data/Data/Generic/IDbCommandDelegate.cs +++ b/src/Spring/Spring.Data/Data/Generic/IDbCommandDelegate.cs @@ -1,14 +1,14 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. - * + * Copyright � 2002-2011 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. @@ -20,27 +20,26 @@ using System.Data; -namespace Spring.Data.Generic -{ - /// - /// Generic callback delegate for code that operates on a IDbCommand. - /// - /// - ///

Allows you to execute any number of operations - /// on a single IDbCommand, for example a single ExecuteScalar - /// call or repeated execute calls with varying parameters. - ///

- ///

Used internally by AdoTemplate, but also useful for - /// application code. Note that the passed in DbCommand - /// has been created by the framework and will have its - /// Connection property set and the Transaction property - /// set based on the transaction context.

- ///
- /// The return type from executing the - /// callback - /// The ADO.NET DbCommand object - /// The object returned from processing with the - /// provided DbCommand - /// Mark Pollack - public delegate T IDbCommandDelegate(IDbCommand command); -} +namespace Spring.Data.Generic; + +/// +/// Generic callback delegate for code that operates on a IDbCommand. +/// +/// +///

Allows you to execute any number of operations +/// on a single IDbCommand, for example a single ExecuteScalar +/// call or repeated execute calls with varying parameters. +///

+///

Used internally by AdoTemplate, but also useful for +/// application code. Note that the passed in DbCommand +/// has been created by the framework and will have its +/// Connection property set and the Transaction property +/// set based on the transaction context.

+///
+/// The return type from executing the +/// callback +/// The ADO.NET DbCommand object +/// The object returned from processing with the +/// provided DbCommand +/// Mark Pollack +public delegate T IDbCommandDelegate(IDbCommand command); diff --git a/src/Spring/Spring.Data/Data/Generic/IResultSetExtractor.cs b/src/Spring/Spring.Data/Data/Generic/IResultSetExtractor.cs index 0f74497e..70235504 100644 --- a/src/Spring/Spring.Data/Data/Generic/IResultSetExtractor.cs +++ b/src/Spring/Spring.Data/Data/Generic/IResultSetExtractor.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -20,40 +20,37 @@ using System.Data; -namespace Spring.Data.Generic +namespace Spring.Data.Generic; + +/// +/// Callback interface to process all results sets and rows in +/// an AdoTemplate query method. +/// +/// Implementations of this interface perform the work +/// of extracting results but don't need worry about managing +/// ADO.NET resources, such as closing the reader. +///

+/// This interface is mainly used within the ADO.NET +/// framework. An IResultSetExtractor is usually a simpler choice +/// for result set (DataReader) processing, in particular a +/// RowMapperResultSetExtractor in combination with a IRowMapper. +///

+/// Note: in contracts to a IRowCallbackHandler, a ResultSetExtractor +/// is usually stateless and thus reusable, as long as it doesn't access +/// stateful resources or keep result state within the object. +/// +///
+/// +public interface IResultSetExtractor { /// - /// Callback interface to process all results sets and rows in - /// an AdoTemplate query method. + /// Implementations must implement this method to process all + /// result set and rows in the IDataReader. /// - /// Implementations of this interface perform the work - /// of extracting results but don't need worry about managing - /// ADO.NET resources, such as closing the reader. - ///

- /// This interface is mainly used within the ADO.NET - /// framework. An IResultSetExtractor is usually a simpler choice - /// for result set (DataReader) processing, in particular a - /// RowMapperResultSetExtractor in combination with a IRowMapper. - ///

- /// Note: in contracts to a IRowCallbackHandler, a ResultSetExtractor - /// is usually stateless and thus reusable, as long as it doesn't access - /// stateful resources or keep result state within the object. - /// - ///
- /// - public interface IResultSetExtractor - { - /// - /// Implementations must implement this method to process all - /// result set and rows in the IDataReader. - /// - /// The IDataReader to extract data from. - /// Implementations should not close this: it will be closed - /// by the AdoTemplate. - /// An arbitrary result object or null if none. The - /// extractor will typically be stateful in the latter case. - T ExtractData(IDataReader reader); - - - } + /// The IDataReader to extract data from. + /// Implementations should not close this: it will be closed + /// by the AdoTemplate. + /// An arbitrary result object or null if none. The + /// extractor will typically be stateful in the latter case. + T ExtractData(IDataReader reader); } diff --git a/src/Spring/Spring.Data/Data/Generic/IRowMapper.cs b/src/Spring/Spring.Data/Data/Generic/IRowMapper.cs index e8ca3cba..bfa7555c 100644 --- a/src/Spring/Spring.Data/Data/Generic/IRowMapper.cs +++ b/src/Spring/Spring.Data/Data/Generic/IRowMapper.cs @@ -1,14 +1,14 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. - * + * Copyright � 2002-2011 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. @@ -20,36 +20,35 @@ using System.Data; -namespace Spring.Data.Generic +namespace Spring.Data.Generic; + +/// +/// Generic callback to process each row of data in a result set to an object. +/// +/// Implementations of this interface perform the actual work +/// of mapping rows, but don't need worry about managing +/// ADO.NET resources, such as closing the reader. +///

+/// Typically used for AdoTemplate's query methods (with RowMapperResultSetExtractor +/// adapters). RowMapper objects are typically stateless and thus +/// reusable; they are ideal choices for implementing row-mapping logic in a single +/// place. +///

+///

Alternatively, consider subclassing MappingSqlQuery from the Spring.Data.Object +/// namespace: Instead of working with separate AdoTemplate and RowMapper objects, +/// you can have executable query objects (containing row-mapping logic) there. +///

+///
+/// Mark Pollack (.NET) +public interface IRowMapper { /// - /// Generic callback to process each row of data in a result set to an object. + /// Implementations must implement this method to map each row of data in the + /// result set (DataReader). This method should not call Next() on the + /// DataReader; it should only extract the values of the current row. /// - /// Implementations of this interface perform the actual work - /// of mapping rows, but don't need worry about managing - /// ADO.NET resources, such as closing the reader. - ///

- /// Typically used for AdoTemplate's query methods (with RowMapperResultSetExtractor - /// adapters). RowMapper objects are typically stateless and thus - /// reusable; they are ideal choices for implementing row-mapping logic in a single - /// place. - ///

- ///

Alternatively, consider subclassing MappingSqlQuery from the Spring.Data.Object - /// namespace: Instead of working with separate AdoTemplate and RowMapper objects, - /// you can have executable query objects (containing row-mapping logic) there. - ///

- ///
- /// Mark Pollack (.NET) - public interface IRowMapper - { - /// - /// Implementations must implement this method to map each row of data in the - /// result set (DataReader). This method should not call Next() on the - /// DataReader; it should only extract the values of the current row. - /// - /// The IDataReader to map (pre-initialized to the current row) - /// The number of the current row.. - /// The specific typed result object for the current row. - T MapRow(IDataReader reader, int rowNum); - } + /// The IDataReader to map (pre-initialized to the current row) + /// The number of the current row.. + /// The specific typed result object for the current row. + T MapRow(IDataReader reader, int rowNum); } diff --git a/src/Spring/Spring.Data/Data/Generic/NamedResultSetProcessor.cs b/src/Spring/Spring.Data/Data/Generic/NamedResultSetProcessor.cs index 42dcc004..c3255f30 100644 --- a/src/Spring/Spring.Data/Data/Generic/NamedResultSetProcessor.cs +++ b/src/Spring/Spring.Data/Data/Generic/NamedResultSetProcessor.cs @@ -1,12 +1,12 @@ /* * Copyright © 2002-2011 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. @@ -14,79 +14,77 @@ * limitations under the License. */ -namespace Spring.Data.Generic +namespace Spring.Data.Generic; + +/// +/// Provides a name to a ResultSetProcessor for use with AdoOperation subclasses +/// such as StoredProcedure. +/// +/// Mark Pollack (.NET) +public class NamedResultSetProcessor { - /// - /// Provides a name to a ResultSetProcessor for use with AdoOperation subclasses - /// such as StoredProcedure. - /// - /// Mark Pollack (.NET) - public class NamedResultSetProcessor - { - private readonly IRowCallback rowCallback; - private readonly IRowMapper rowMapper; - private readonly IResultSetExtractor resultSetExtractor; - private readonly string name; + private readonly IRowCallback rowCallback; + private readonly IRowMapper rowMapper; + private readonly IResultSetExtractor resultSetExtractor; + private readonly string name; - /// - /// Initializes a new instance of the class with a - /// IRowCallback instance - /// - /// The name of the associated row callback for use with output - /// result set mappers. - /// A row callback instance. - public NamedResultSetProcessor(string name, IRowCallback rowcallback) - { - this.name = name; - this.rowCallback = rowcallback; - } - - /// - /// Initializes a new instance of the class with a - /// IRowMapper instance - /// - /// The name of the associated row mapper. - /// A IRowMapper instance. - public NamedResultSetProcessor(string name, IRowMapper rowMapper) - { - this.name = name; - this.rowMapper = rowMapper; - } - - /// - /// Initializes a new instance of the class with a - /// IResultSetExtractor instance - /// - /// The name of the associated result set extractor. - /// A IResultSetExtractor instance. - public NamedResultSetProcessor(string name, IResultSetExtractor resultSetExtractor) + /// + /// Initializes a new instance of the class with a + /// IRowCallback instance + /// + /// The name of the associated row callback for use with output + /// result set mappers. + /// A row callback instance. + public NamedResultSetProcessor(string name, IRowCallback rowcallback) + { + this.name = name; + this.rowCallback = rowcallback; + } + + /// + /// Initializes a new instance of the class with a + /// IRowMapper instance + /// + /// The name of the associated row mapper. + /// A IRowMapper instance. + public NamedResultSetProcessor(string name, IRowMapper rowMapper) + { + this.name = name; + this.rowMapper = rowMapper; + } + + /// + /// Initializes a new instance of the class with a + /// IResultSetExtractor instance + /// + /// The name of the associated result set extractor. + /// A IResultSetExtractor instance. + public NamedResultSetProcessor(string name, IResultSetExtractor resultSetExtractor) + { + this.name = name; + this.resultSetExtractor = resultSetExtractor; + } + + public string Name + { + get { - this.name = name; - this.resultSetExtractor = resultSetExtractor; + return name; } + } - public string Name - { - get - { - return name; - } - } + public IRowCallback RowCallback + { + get { return rowCallback; } + } + public IRowMapper RowMapper + { + get { return rowMapper; } + } - public IRowCallback RowCallback - { - get { return rowCallback; } - } - - public IRowMapper RowMapper - { - get { return rowMapper; } - } - - public IResultSetExtractor ResultSetExtractor - { - get { return resultSetExtractor; } - } - } + public IResultSetExtractor ResultSetExtractor + { + get { return resultSetExtractor; } + } } diff --git a/src/Spring/Spring.Data/Data/Generic/ResultSetExtractorDelegate.cs b/src/Spring/Spring.Data/Data/Generic/ResultSetExtractorDelegate.cs index 6359bc16..7a37d05e 100644 --- a/src/Spring/Spring.Data/Data/Generic/ResultSetExtractorDelegate.cs +++ b/src/Spring/Spring.Data/Data/Generic/ResultSetExtractorDelegate.cs @@ -1,14 +1,14 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. - * + * Copyright � 2002-2011 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. @@ -20,17 +20,15 @@ using System.Data; -namespace Spring.Data.Generic -{ +namespace Spring.Data.Generic; - /// - /// Callback delegate to process all result sets and row in an - /// AdoTemplate query method. - /// - /// The type returned from the result set mapping. - /// The IDataReader to extract data from. - /// Implementations should not close this: it will be closed - /// by the AdoTemplate. - /// An arbitrary result object or null if none. - public delegate T ResultSetExtractorDelegate(IDataReader reader); -} +/// +/// Callback delegate to process all result sets and row in an +/// AdoTemplate query method. +/// +/// The type returned from the result set mapping. +/// The IDataReader to extract data from. +/// Implementations should not close this: it will be closed +/// by the AdoTemplate. +/// An arbitrary result object or null if none. +public delegate T ResultSetExtractorDelegate(IDataReader reader); diff --git a/src/Spring/Spring.Data/Data/Generic/RowMapperDelegate.cs b/src/Spring/Spring.Data/Data/Generic/RowMapperDelegate.cs index aad77a7d..fb08d304 100644 --- a/src/Spring/Spring.Data/Data/Generic/RowMapperDelegate.cs +++ b/src/Spring/Spring.Data/Data/Generic/RowMapperDelegate.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -20,15 +20,14 @@ using System.Data; -namespace Spring.Data.Generic -{ - /// - /// Callback delegate to process each row of data in a result set to an object. - /// - /// The type of the object returned from the mapping operation. - /// The IDataReader to map - /// the number of the current row. - /// An abrirary object, typically derived from data - /// in the result set. - public delegate T RowMapperDelegate(IDataReader dataReader, int rowNum); -} +namespace Spring.Data.Generic; + +/// +/// Callback delegate to process each row of data in a result set to an object. +/// +/// The type of the object returned from the mapping operation. +/// The IDataReader to map +/// the number of the current row. +/// An abrirary object, typically derived from data +/// in the result set. +public delegate T RowMapperDelegate(IDataReader dataReader, int rowNum); diff --git a/src/Spring/Spring.Data/Data/Generic/RowMapperResultSetExtractor.cs b/src/Spring/Spring.Data/Data/Generic/RowMapperResultSetExtractor.cs index b5008fc4..ccd44249 100644 --- a/src/Spring/Spring.Data/Data/Generic/RowMapperResultSetExtractor.cs +++ b/src/Spring/Spring.Data/Data/Generic/RowMapperResultSetExtractor.cs @@ -21,120 +21,122 @@ using System.Data; using Spring.Util; -namespace Spring.Data.Generic +namespace Spring.Data.Generic; + +/// +/// Adapter implementation of the ResultSetExtractor interface that delegates +/// to a RowMapper which is supposed to create an object for each row. +/// Each object is added to the results List of this ResultSetExtractor. +/// +/// +/// Useful for the typical case of one object per row in the database table. +/// The number of entries in the results list will match the number of rows. +///

+/// Note that a RowMapper object is typically stateless and thus reusable; +/// just the RowMapperResultSetExtractor adapter is stateful. +///

+///

+/// As an alternative consider subclassing MappingAdoQuery from the +/// Spring.Data.Objects namespace: Instead of working with separate +/// AdoTemplate and IRowMapper objects you can have executable +/// query objects (containing row-mapping logic) there. +///

+///
+/// Mark Pollack (.NET) +public class RowMapperResultSetExtractor : IResultSetExtractor> { - /// - /// Adapter implementation of the ResultSetExtractor interface that delegates - /// to a RowMapper which is supposed to create an object for each row. - /// Each object is added to the results List of this ResultSetExtractor. - /// - /// - /// Useful for the typical case of one object per row in the database table. - /// The number of entries in the results list will match the number of rows. - ///

- /// Note that a RowMapper object is typically stateless and thus reusable; - /// just the RowMapperResultSetExtractor adapter is stateful. - ///

- ///

- /// As an alternative consider subclassing MappingAdoQuery from the - /// Spring.Data.Objects namespace: Instead of working with separate - /// AdoTemplate and IRowMapper objects you can have executable - /// query objects (containing row-mapping logic) there. - ///

- ///
- /// Mark Pollack (.NET) - public class RowMapperResultSetExtractor : IResultSetExtractor> - { - #region Fields + #region Fields - private IRowMapper rowMapper; + private IRowMapper rowMapper; - private RowMapperDelegate rowMapperDelegate; + private RowMapperDelegate rowMapperDelegate; - private int rowsExpected; + private int rowsExpected; - #endregion + #endregion - #region Constructor (s) - /// - /// Initializes a new instance of the class. - /// - public RowMapperResultSetExtractor(IRowMapper rowMapper) : this(rowMapper,0, null) - { - } + #region Constructor (s) - /// - /// Initializes a new instance of the class. - /// - /// The row mapper. - /// The rows expected. - public RowMapperResultSetExtractor(IRowMapper rowMapper, int rowsExpected) : this(rowMapper, rowsExpected, null) - { - } - public RowMapperResultSetExtractor(IRowMapper rowMapper, int rowsExpected, IDataReaderWrapper dataReaderWrapper) - { - //TODO use datareaderwrapper - AssertUtils.ArgumentNotNull(rowMapper, "rowMapper"); - - this.rowMapper = rowMapper; - this.rowsExpected = rowsExpected; - } - - public RowMapperResultSetExtractor(RowMapperDelegate rowMapperDelegate) - : this(rowMapperDelegate, 0, null) - { - } - - public RowMapperResultSetExtractor(RowMapperDelegate rowMapperDelegate, int rowsExpected) - : this(rowMapperDelegate, rowsExpected, null) - { - } - public RowMapperResultSetExtractor(RowMapperDelegate rowMapperDelegate, int rowsExpected, IDataReaderWrapper dataReaderWrapper) - { - //TODO use datareaderwrapper - - AssertUtils.ArgumentNotNull(rowMapperDelegate, "rowMapperDelegate"); - - this.rowMapperDelegate = rowMapperDelegate; - this.rowsExpected = rowsExpected; - } - - #endregion - - #region IResultSetExtractor Members - - public IList ExtractData(IDataReader reader) - { - // Use the more efficient collection if we know how many rows to expect: - // ArrayList in case of a known row count, LinkedList if unknown - //IList results = (rowsExpected > 0) ? new List(rowsExpected) : new LinkedList(); - - //how come LinkedList doesn't implement IList ?!?!?! - //some web entries claim slow indexer... need to write our own again? return ICollection instead? - //http://blogs.msdn.com/kcwalina/archive/2005/09/23/Collections.aspx - //We did not implement IList on LinkedList because the indexer would be - //very slow. If you really need the interface, you probably can inherit from - //LinkedList and implement the interface on the subtype. - IList results = new List(); - int rowNum = 0; - if (rowMapper != null) - { - while (reader.Read()) - { - results.Add(rowMapper.MapRow(reader, rowNum++)); - } - } - else - { - while (reader.Read()) - { - results.Add(rowMapperDelegate(reader, rowNum++)); - } - } - - return results; - } - - #endregion + /// + /// Initializes a new instance of the class. + /// + public RowMapperResultSetExtractor(IRowMapper rowMapper) : this(rowMapper, 0, null) + { } + + /// + /// Initializes a new instance of the class. + /// + /// The row mapper. + /// The rows expected. + public RowMapperResultSetExtractor(IRowMapper rowMapper, int rowsExpected) : this(rowMapper, rowsExpected, null) + { + } + + public RowMapperResultSetExtractor(IRowMapper rowMapper, int rowsExpected, IDataReaderWrapper dataReaderWrapper) + { + //TODO use datareaderwrapper + AssertUtils.ArgumentNotNull(rowMapper, "rowMapper"); + + this.rowMapper = rowMapper; + this.rowsExpected = rowsExpected; + } + + public RowMapperResultSetExtractor(RowMapperDelegate rowMapperDelegate) + : this(rowMapperDelegate, 0, null) + { + } + + public RowMapperResultSetExtractor(RowMapperDelegate rowMapperDelegate, int rowsExpected) + : this(rowMapperDelegate, rowsExpected, null) + { + } + + public RowMapperResultSetExtractor(RowMapperDelegate rowMapperDelegate, int rowsExpected, IDataReaderWrapper dataReaderWrapper) + { + //TODO use datareaderwrapper + + AssertUtils.ArgumentNotNull(rowMapperDelegate, "rowMapperDelegate"); + + this.rowMapperDelegate = rowMapperDelegate; + this.rowsExpected = rowsExpected; + } + + #endregion + + #region IResultSetExtractor Members + + public IList ExtractData(IDataReader reader) + { + // Use the more efficient collection if we know how many rows to expect: + // ArrayList in case of a known row count, LinkedList if unknown + //IList results = (rowsExpected > 0) ? new List(rowsExpected) : new LinkedList(); + + //how come LinkedList doesn't implement IList ?!?!?! + //some web entries claim slow indexer... need to write our own again? return ICollection instead? + //http://blogs.msdn.com/kcwalina/archive/2005/09/23/Collections.aspx + //We did not implement IList on LinkedList because the indexer would be + //very slow. If you really need the interface, you probably can inherit from + //LinkedList and implement the interface on the subtype. + IList results = new List(); + int rowNum = 0; + if (rowMapper != null) + { + while (reader.Read()) + { + results.Add(rowMapper.MapRow(reader, rowNum++)); + } + } + else + { + while (reader.Read()) + { + results.Add(rowMapperDelegate(reader, rowNum++)); + } + } + + return results; + } + + #endregion } diff --git a/src/Spring/Spring.Data/Data/IAdoOperations.cs b/src/Spring/Spring.Data/Data/IAdoOperations.cs index 82700e5c..38df2e23 100644 --- a/src/Spring/Spring.Data/Data/IAdoOperations.cs +++ b/src/Spring/Spring.Data/Data/IAdoOperations.cs @@ -22,773 +22,742 @@ using System.Collections; using System.Data; using Spring.Data.Common; -namespace Spring.Data +namespace Spring.Data; + +/// +/// Interface that defines ADO.NET related database operations. +/// +/// Mark Pollack (.NET) +public interface IAdoOperations : ICommonAdoOperations { - /// - /// Interface that defines ADO.NET related database operations. - /// - /// Mark Pollack (.NET) - public interface IAdoOperations : ICommonAdoOperations - { - - #region General Execute Methods with Callbacks - /// - /// Execute a ADO.NET operation on a command object using a delegate callback. - /// - /// This allows for implementing arbitrary data access operations - /// on a single command within Spring's managed ADO.NET environment. - /// The delegate called with a command object. - /// A result object returned by the action or null - object Execute(CommandDelegate del); - - /// - /// Execute a ADO.NET operation on a command object using an interface based callback. - /// - /// the callback to execute - /// object returned from callback - object Execute(ICommandCallback action); - - /// - /// Executes ADO.NET operations on a command object, created by the provided IDbCommandCreator, - /// using the interface based callback IDbCommandCallback. - /// - /// The command creator. - /// The callback to execute based on IDbCommand - /// A result object returned by the action or null - object Execute(IDbCommandCreator commandCreator, ICommandCallback action); - - /// - /// Execute ADO.NET operations on a IDbDataAdapter object using an interface based callback. - /// - /// This allows for implementing abritrary data access operations - /// on a single DataAdapter within Spring's managed ADO.NET environment. - /// - /// The data adapter callback. - /// A result object returned by the callback or null - object Execute(IDataAdapterCallback dataAdapterCallback); - - #endregion - - #region Queries With ResultSetExtractor - - // Static Queries - - /// - /// Execute a query given IDbCommand's type and text, processing a - /// single result set with an instance of IResultSetExtractor - /// - /// The type of command - /// The text of the query. - /// Object that will extract all rows of a result set - /// An arbitrary result object, as returned by the IResultSetExtractor - /// - /// If there is any problem executing the query. - /// - object QueryWithResultSetExtractor(CommandType cmdType, string cmdText, IResultSetExtractor resultSetExtractor); - - - // Parameterized Queries - // Only input parameters can be used... - - - /// - /// Execute a query given the CommandType and text with parameters set - /// via the command setter, processing a - /// single result set with an instance of IResultSetExtractor - /// - /// The command type. - /// The command text to execute. - /// The result set extractor. - /// The command setter. - /// An arbitrary result object, as returned by the IResultSetExtractor - /// - /// If there is any problem executing the query. - /// - object QueryWithResultSetExtractor(CommandType cmdType, string cmdText, IResultSetExtractor resultSetExtractor, - ICommandSetter commandSetter); - - /// - /// Execute a query given the CommandType and text specifying a single parameter and process a single result set with an - /// instance of IResultSetExtractor. - /// - /// Convention is to use 0 For the size if it does not make sense for the given data type - /// - /// The command type. - /// The command text to execute. - /// The result set extractor. - /// The name of the parameters - /// The enumeration of the parameter type - /// The size of the parmeter - e.g. string length. Use 0 if not relevant for specific data type - /// The value of the parameters - /// An arbitrary result object, as returned by the IResultSetExtractor - /// - /// If there is any problem executing the query. - /// - object QueryWithResultSetExtractor(CommandType cmdType, string cmdText, IResultSetExtractor resultSetExtractor, - string parameterName, Enum dbType, int size, object parameterValue); - - /// - /// Execute a query given the CommandType and text specifying a collection of parameters and process a single result set with an - /// instance of IResultSetExtractor. - /// - /// The command type. - /// The command text to execute. - /// The result set extractor. - /// The query parameters - /// An arbitrary result object, as returned by the IResultSetExtractor - /// - /// If there is any problem executing the query. - /// - object QueryWithResultSetExtractor(CommandType cmdType, string cmdText, IResultSetExtractor resultSetExtractor, - IDbParameters parameters); - - - #endregion - - #region Queries With ResultSetExtractorDelegate - - // Static Queries - - /// - /// Execute a query given static SQL/Stored Procedure name - /// and process a single result set with an instance of ResultSetExtractorDelegate - /// - /// The type of command. - /// The command text. - /// Delegate that will process all rows of a result set - /// An arbitrary result object, as returned by the IResultSetExtractor - /// - /// If there is any problem executing the query. - /// - object QueryWithResultSetExtractorDelegate(CommandType cmdType, string cmdText, ResultSetExtractorDelegate resultSetExtractorDelegate); - - - // Parameterized Queries - // only input parameters can be used... - - /// - /// Execute a query given the CommandType and text with parameters set - /// via the command setter, processing a - /// single result set with an instance of IResultSetExtractor - /// - /// The command type. - /// The command text to execute. - /// Delegate that will process all rows of a result set - /// The command setter. - /// An arbitrary result object, as returned by the IResultSetExtractor - /// - /// If there is any problem executing the query. - /// - object QueryWithResultSetExtractorDelegate(CommandType cmdType, string cmdText, ResultSetExtractorDelegate resultSetExtractorDelegate, - ICommandSetter commandSetter); - - - /// - /// Execute a query given the CommandType and text specifying a single parameter and process a single result set with an - /// instance of IResultSetExtractor. - /// - /// Convention is to use 0 For the size if it does not make sense for the given data type - /// - /// The command type. - /// The command text to execute. - /// Delegate that will process all rows of a result set - /// The name of the parameters - /// The enumeration of the parameter type - /// The size of the parmeter - e.g. string length. Use 0 if not relevant for specific data type - /// The value of the parameters - /// An arbitrary result object, as returned by the IResultSetExtractor - /// - /// If there is any problem executing the query. - /// - object QueryWithResultSetExtractorDelegate(CommandType cmdType, string cmdText, ResultSetExtractorDelegate resultSetExtractorDelegate, - string parameterName, Enum dbType, int size, object parameterValue); - - /// - /// Execute a query given the CommandType and text specifying a collection of parameters and process a single result set with an - /// instance of IResultSetExtractor. - /// - /// The command type. - /// The command text to execute. - /// Delegate that will process all rows of a result set - /// The query parameters - /// An arbitrary result object, as returned by the IResultSetExtractor - /// - /// If there is any problem executing the query. - /// - object QueryWithResultSetExtractorDelegate(CommandType cmdType, string cmdText, ResultSetExtractorDelegate resultSetExtractorDelegate, - IDbParameters parameters); - - - #endregion - - #region Queries with RowMapperDelegate - - /// - /// Execute a query given static SQL, mapping each row to a .NET object - /// via a RowMapper - /// - /// The type of command - /// SQL query to execute - /// delegate/lambda that will map one object per row - /// The result list containing mapped objects - IList QueryWithRowMapperDelegate(CommandType cmdType, string cmdText, RowMapperDelegate rowMapperDelgate); - - IList QueryWithRowMapperDelegate(CommandType cmdType, string cmdText, RowMapperDelegate rowMapperDelgate, ICommandSetter commandSetter); - - IList QueryWithRowMapperDelegate(CommandType cmdType, string cmdText, RowMapperDelegate rowMapperDelgate, - string parameterName, Enum dbType, int size, object parameterValue); - - IList QueryWithRowMapperDelegate(CommandType cmdType, string cmdText, RowMapperDelegate rowMapperDelgate, IDbParameters parameter); - - - #endregion - - #region Queries with RowMapper - - // Static Queries - - - /// - /// Execute a query given static SQL, mapping each row to a .NET object - /// via a RowMapper - /// - /// The type of command - /// SQL query to execute - /// object that will map one object per row - /// the result list containing mapped objects - IList QueryWithRowMapper(CommandType cmdType, string cmdText, IRowMapper rowMapper); - - // Parameterized Queries - - //Using IRowMapper to process 1 result set - IList QueryWithRowMapper(CommandType cmdType, string cmdText, IRowMapper rowMapper, ICommandSetter commandSetter); - - IList QueryWithRowMapper(CommandType cmdType, string cmdText, IRowMapper rowMapper, - string name, Enum dbType, int size, object parameterValue); - - IList QueryWithRowMapper(CommandType cmdType, string cmdText, IRowMapper rowMapper, IDbParameters parameter); - - - - #endregion - - #region Query for Object - - - - - - /// - /// Execute a query with the specified command text, mapping a single result - /// row to an object via a RowMapper. - /// - /// The command type. - /// The command text to execute. - /// object that will map one object per row - /// The single mapped object. - /// - /// If the query does not return exactly one row. - /// - /// - /// If there is any problem executing the query. - /// - object QueryForObject(CommandType cmdType, string cmdText, IRowMapper rowMapper); - - - /// - /// Execute a query with the specified command text and parameters set via the - /// command setter, mapping a single result row to an object via a RowMapper. - /// - /// The command type. - /// The command text to execute. - /// object that will map one object per row - /// The command setter. - /// The single mapped object. - /// - /// If the query does not return exactly one row. - /// - /// - /// If there is any problem executing the query. - /// - object QueryForObject(CommandType cmdType, string cmdText, IRowMapper rowMapper, ICommandSetter commandSetter); - - /// - /// Execute a query with the specified command text and parameters, mapping a single result row - /// to an object via a RowMapper. - /// - /// The command type. - /// The command text to execute. - /// object that will map one object per row - /// The parameter collection to use in the query. - /// The single mapped object. - /// - /// If the query does not return exactly one row. - /// - /// - /// If there is any problem executing the query. - /// - object QueryForObject(CommandType cmdType, string cmdText, IRowMapper rowMapper, IDbParameters parameters); - - /// - /// Execute a query with the specified command text and parameter, mapping a single result row - /// to an object via a RowMapper. - /// - /// The command type. - /// The command text to execute. - /// object that will map one object per row - /// The name of the parameter to map. - /// One of the database parameter type enumerations. - /// The length of the parameter. 0 if not applicable to parameter type. - /// The parameter value. - /// The single mapped object. - /// - /// If the query does not return exactly one row. - /// - /// - /// If there is any problem executing the query. - /// - object QueryForObject(CommandType cmdType, string cmdText, IRowMapper rowMapper, - string parameterName, Enum dbType, int size, object parameterValue); - - - #endregion - - #region Query for ObjectDelegate - - /// - /// Execute a query with the specified command text, mapping a single result - /// row to an object via a RowMapper. - /// - /// The command type. - /// The command text to execute. - /// delegate that will map one object per row - /// The single mapped object. - /// - /// If the query does not return exactly one row. - /// - /// - /// If there is any problem executing the query. - /// - object QueryForObjectDelegate(CommandType cmdType, string cmdText, RowMapperDelegate rowMapperDelgate); - - - - /// - /// Execute a query with the specified command text and parameters set via the - /// command setter, mapping a single result row to an object via a RowMapper. - /// - /// The command type. - /// The command text to execute. - /// delegate that will map one object per row - /// The command setter. - /// The single mapped object. - /// - /// If the query does not return exactly one row. - /// - /// - /// If there is any problem executing the query. - /// - object QueryForObjectDelegate(CommandType cmdType, string cmdText, RowMapperDelegate rowMapperDelegate, ICommandSetter commandSetter); - - - /// - /// Execute a query with the specified command text and parameters, mapping a single result row - /// to an object via a RowMapper. - /// - /// The command type. - /// The command text to execute. - /// delegate that will map one object per row - /// The parameter collection to use in the query. - /// The single mapped object. - /// - /// If the query does not return exactly one row. - /// - /// - /// If there is any problem executing the query. - /// - object QueryForObjectDelegate(CommandType cmdType, string cmdText, RowMapperDelegate rowMapperDelegate, IDbParameters parameters); - - - /// - /// Execute a query with the specified command text and parameter, mapping a single result row - /// to an object via a RowMapper. - /// - /// The command type. - /// The command text to execute. - /// delegate that will map one object per row - /// The name of the parameter to map. - /// One of the database parameter type enumerations. - /// The length of the parameter. 0 if not applicable to parameter type. - /// The parameter value. - /// - object QueryForObjectDelegate(CommandType cmdType, string cmdText, RowMapperDelegate rowMapperDelegate, - string parameterName, Enum dbType, int size, object parameterValue); - - - #endregion - - #region Query With CommandCreator - - // Using IResultSetExtractor to process one result set. - object QueryWithCommandCreator(IDbCommandCreator commandCreator, IResultSetExtractor resultSetExtractor); - - IList QueryWithCommandCreator(IDbCommandCreator cc, IRowMapper rowMapper); - - // Using IResultSetExtractor to return one result set, multiple output parameters. - object QueryWithCommandCreator(IDbCommandCreator commandCreator, IResultSetExtractor resultSetExtractor, IDictionary returnedParameters); + #region General Execute Methods with Callbacks + + /// + /// Execute a ADO.NET operation on a command object using a delegate callback. + /// + /// This allows for implementing arbitrary data access operations + /// on a single command within Spring's managed ADO.NET environment. + /// The delegate called with a command object. + /// A result object returned by the action or null + object Execute(CommandDelegate del); + + /// + /// Execute a ADO.NET operation on a command object using an interface based callback. + /// + /// the callback to execute + /// object returned from callback + object Execute(ICommandCallback action); + + /// + /// Executes ADO.NET operations on a command object, created by the provided IDbCommandCreator, + /// using the interface based callback IDbCommandCallback. + /// + /// The command creator. + /// The callback to execute based on IDbCommand + /// A result object returned by the action or null + object Execute(IDbCommandCreator commandCreator, ICommandCallback action); + + /// + /// Execute ADO.NET operations on a IDbDataAdapter object using an interface based callback. + /// + /// This allows for implementing abritrary data access operations + /// on a single DataAdapter within Spring's managed ADO.NET environment. + /// + /// The data adapter callback. + /// A result object returned by the callback or null + object Execute(IDataAdapterCallback dataAdapterCallback); + + #endregion + + #region Queries With ResultSetExtractor + + // Static Queries + + /// + /// Execute a query given IDbCommand's type and text, processing a + /// single result set with an instance of IResultSetExtractor + /// + /// The type of command + /// The text of the query. + /// Object that will extract all rows of a result set + /// An arbitrary result object, as returned by the IResultSetExtractor + /// + /// If there is any problem executing the query. + /// + object QueryWithResultSetExtractor(CommandType cmdType, string cmdText, IResultSetExtractor resultSetExtractor); + + // Parameterized Queries + // Only input parameters can be used... + + /// + /// Execute a query given the CommandType and text with parameters set + /// via the command setter, processing a + /// single result set with an instance of IResultSetExtractor + /// + /// The command type. + /// The command text to execute. + /// The result set extractor. + /// The command setter. + /// An arbitrary result object, as returned by the IResultSetExtractor + /// + /// If there is any problem executing the query. + /// + object QueryWithResultSetExtractor(CommandType cmdType, string cmdText, IResultSetExtractor resultSetExtractor, + ICommandSetter commandSetter); + + /// + /// Execute a query given the CommandType and text specifying a single parameter and process a single result set with an + /// instance of IResultSetExtractor. + /// + /// Convention is to use 0 For the size if it does not make sense for the given data type + /// + /// The command type. + /// The command text to execute. + /// The result set extractor. + /// The name of the parameters + /// The enumeration of the parameter type + /// The size of the parmeter - e.g. string length. Use 0 if not relevant for specific data type + /// The value of the parameters + /// An arbitrary result object, as returned by the IResultSetExtractor + /// + /// If there is any problem executing the query. + /// + object QueryWithResultSetExtractor(CommandType cmdType, string cmdText, IResultSetExtractor resultSetExtractor, + string parameterName, Enum dbType, int size, object parameterValue); + + /// + /// Execute a query given the CommandType and text specifying a collection of parameters and process a single result set with an + /// instance of IResultSetExtractor. + /// + /// The command type. + /// The command text to execute. + /// The result set extractor. + /// The query parameters + /// An arbitrary result object, as returned by the IResultSetExtractor + /// + /// If there is any problem executing the query. + /// + object QueryWithResultSetExtractor(CommandType cmdType, string cmdText, IResultSetExtractor resultSetExtractor, + IDbParameters parameters); + + #endregion + + #region Queries With ResultSetExtractorDelegate + + // Static Queries + + /// + /// Execute a query given static SQL/Stored Procedure name + /// and process a single result set with an instance of ResultSetExtractorDelegate + /// + /// The type of command. + /// The command text. + /// Delegate that will process all rows of a result set + /// An arbitrary result object, as returned by the IResultSetExtractor + /// + /// If there is any problem executing the query. + /// + object QueryWithResultSetExtractorDelegate(CommandType cmdType, string cmdText, ResultSetExtractorDelegate resultSetExtractorDelegate); + + // Parameterized Queries + // only input parameters can be used... + + /// + /// Execute a query given the CommandType and text with parameters set + /// via the command setter, processing a + /// single result set with an instance of IResultSetExtractor + /// + /// The command type. + /// The command text to execute. + /// Delegate that will process all rows of a result set + /// The command setter. + /// An arbitrary result object, as returned by the IResultSetExtractor + /// + /// If there is any problem executing the query. + /// + object QueryWithResultSetExtractorDelegate(CommandType cmdType, string cmdText, ResultSetExtractorDelegate resultSetExtractorDelegate, + ICommandSetter commandSetter); + + /// + /// Execute a query given the CommandType and text specifying a single parameter and process a single result set with an + /// instance of IResultSetExtractor. + /// + /// Convention is to use 0 For the size if it does not make sense for the given data type + /// + /// The command type. + /// The command text to execute. + /// Delegate that will process all rows of a result set + /// The name of the parameters + /// The enumeration of the parameter type + /// The size of the parmeter - e.g. string length. Use 0 if not relevant for specific data type + /// The value of the parameters + /// An arbitrary result object, as returned by the IResultSetExtractor + /// + /// If there is any problem executing the query. + /// + object QueryWithResultSetExtractorDelegate(CommandType cmdType, string cmdText, ResultSetExtractorDelegate resultSetExtractorDelegate, + string parameterName, Enum dbType, int size, object parameterValue); + + /// + /// Execute a query given the CommandType and text specifying a collection of parameters and process a single result set with an + /// instance of IResultSetExtractor. + /// + /// The command type. + /// The command text to execute. + /// Delegate that will process all rows of a result set + /// The query parameters + /// An arbitrary result object, as returned by the IResultSetExtractor + /// + /// If there is any problem executing the query. + /// + object QueryWithResultSetExtractorDelegate(CommandType cmdType, string cmdText, ResultSetExtractorDelegate resultSetExtractorDelegate, + IDbParameters parameters); + + #endregion + + #region Queries with RowMapperDelegate + + /// + /// Execute a query given static SQL, mapping each row to a .NET object + /// via a RowMapper + /// + /// The type of command + /// SQL query to execute + /// delegate/lambda that will map one object per row + /// The result list containing mapped objects + IList QueryWithRowMapperDelegate(CommandType cmdType, string cmdText, RowMapperDelegate rowMapperDelgate); + + IList QueryWithRowMapperDelegate(CommandType cmdType, string cmdText, RowMapperDelegate rowMapperDelgate, ICommandSetter commandSetter); + + IList QueryWithRowMapperDelegate(CommandType cmdType, string cmdText, RowMapperDelegate rowMapperDelgate, + string parameterName, Enum dbType, int size, object parameterValue); + + IList QueryWithRowMapperDelegate(CommandType cmdType, string cmdText, RowMapperDelegate rowMapperDelgate, IDbParameters parameter); + + #endregion + + #region Queries with RowMapper + + // Static Queries + + /// + /// Execute a query given static SQL, mapping each row to a .NET object + /// via a RowMapper + /// + /// The type of command + /// SQL query to execute + /// object that will map one object per row + /// the result list containing mapped objects + IList QueryWithRowMapper(CommandType cmdType, string cmdText, IRowMapper rowMapper); + + // Parameterized Queries + + //Using IRowMapper to process 1 result set + IList QueryWithRowMapper(CommandType cmdType, string cmdText, IRowMapper rowMapper, ICommandSetter commandSetter); + + IList QueryWithRowMapper(CommandType cmdType, string cmdText, IRowMapper rowMapper, + string name, Enum dbType, int size, object parameterValue); + + IList QueryWithRowMapper(CommandType cmdType, string cmdText, IRowMapper rowMapper, IDbParameters parameter); + + #endregion + + #region Query for Object + + /// + /// Execute a query with the specified command text, mapping a single result + /// row to an object via a RowMapper. + /// + /// The command type. + /// The command text to execute. + /// object that will map one object per row + /// The single mapped object. + /// + /// If the query does not return exactly one row. + /// + /// + /// If there is any problem executing the query. + /// + object QueryForObject(CommandType cmdType, string cmdText, IRowMapper rowMapper); + + /// + /// Execute a query with the specified command text and parameters set via the + /// command setter, mapping a single result row to an object via a RowMapper. + /// + /// The command type. + /// The command text to execute. + /// object that will map one object per row + /// The command setter. + /// The single mapped object. + /// + /// If the query does not return exactly one row. + /// + /// + /// If there is any problem executing the query. + /// + object QueryForObject(CommandType cmdType, string cmdText, IRowMapper rowMapper, ICommandSetter commandSetter); + + /// + /// Execute a query with the specified command text and parameters, mapping a single result row + /// to an object via a RowMapper. + /// + /// The command type. + /// The command text to execute. + /// object that will map one object per row + /// The parameter collection to use in the query. + /// The single mapped object. + /// + /// If the query does not return exactly one row. + /// + /// + /// If there is any problem executing the query. + /// + object QueryForObject(CommandType cmdType, string cmdText, IRowMapper rowMapper, IDbParameters parameters); + + /// + /// Execute a query with the specified command text and parameter, mapping a single result row + /// to an object via a RowMapper. + /// + /// The command type. + /// The command text to execute. + /// object that will map one object per row + /// The name of the parameter to map. + /// One of the database parameter type enumerations. + /// The length of the parameter. 0 if not applicable to parameter type. + /// The parameter value. + /// The single mapped object. + /// + /// If the query does not return exactly one row. + /// + /// + /// If there is any problem executing the query. + /// + object QueryForObject(CommandType cmdType, string cmdText, IRowMapper rowMapper, + string parameterName, Enum dbType, int size, object parameterValue); + + #endregion + + #region Query for ObjectDelegate + + /// + /// Execute a query with the specified command text, mapping a single result + /// row to an object via a RowMapper. + /// + /// The command type. + /// The command text to execute. + /// delegate that will map one object per row + /// The single mapped object. + /// + /// If the query does not return exactly one row. + /// + /// + /// If there is any problem executing the query. + /// + object QueryForObjectDelegate(CommandType cmdType, string cmdText, RowMapperDelegate rowMapperDelgate); + + /// + /// Execute a query with the specified command text and parameters set via the + /// command setter, mapping a single result row to an object via a RowMapper. + /// + /// The command type. + /// The command text to execute. + /// delegate that will map one object per row + /// The command setter. + /// The single mapped object. + /// + /// If the query does not return exactly one row. + /// + /// + /// If there is any problem executing the query. + /// + object QueryForObjectDelegate(CommandType cmdType, string cmdText, RowMapperDelegate rowMapperDelegate, ICommandSetter commandSetter); + + /// + /// Execute a query with the specified command text and parameters, mapping a single result row + /// to an object via a RowMapper. + /// + /// The command type. + /// The command text to execute. + /// delegate that will map one object per row + /// The parameter collection to use in the query. + /// The single mapped object. + /// + /// If the query does not return exactly one row. + /// + /// + /// If there is any problem executing the query. + /// + object QueryForObjectDelegate(CommandType cmdType, string cmdText, RowMapperDelegate rowMapperDelegate, IDbParameters parameters); + + /// + /// Execute a query with the specified command text and parameter, mapping a single result row + /// to an object via a RowMapper. + /// + /// The command type. + /// The command text to execute. + /// delegate that will map one object per row + /// The name of the parameter to map. + /// One of the database parameter type enumerations. + /// The length of the parameter. 0 if not applicable to parameter type. + /// The parameter value. + /// + object QueryForObjectDelegate(CommandType cmdType, string cmdText, RowMapperDelegate rowMapperDelegate, + string parameterName, Enum dbType, int size, object parameterValue); + + #endregion + + #region Query With CommandCreator + + // Using IResultSetExtractor to process one result set. + object QueryWithCommandCreator(IDbCommandCreator commandCreator, IResultSetExtractor resultSetExtractor); + + IList QueryWithCommandCreator(IDbCommandCreator cc, IRowMapper rowMapper); + + // Using IResultSetExtractor to return one result set, multiple output parameters. + object QueryWithCommandCreator(IDbCommandCreator commandCreator, IResultSetExtractor resultSetExtractor, IDictionary returnedParameters); + + // Using IRowMapper to return one result set, multiple output parameters. + IList QueryWithCommandCreator(IDbCommandCreator commandCreator, IRowMapper rowMapper, IDictionary returnedParameters); + + // Multiple return result sets, (A list of lists) + // each with either a IRowMapper, IResultSetExtractor, IRowCallback + // and multiple output parameters. + IDictionary QueryWithCommandCreator(IDbCommandCreator commandCreator, IList resultProcessors); + + #endregion + + #region DataTable Create operations without parameters + + DataTable DataTableCreate(CommandType commandType, string sql); + + DataTable DataTableCreate(CommandType commandType, string sql, + string tableMappingName); + + DataTable DataTableCreate(CommandType commandType, string sql, + ITableMapping tableMapping); + + DataTable DataTableCreate(CommandType commandType, string sql, + ITableMapping tableMapping, + IDataAdapterSetter setter); + + #endregion + + #region DataTable Create operations with parameters + + DataTable DataTableCreateWithParams(CommandType commandType, string sql, + IDbParameters parameters); + + DataTable DataTableCreateWithParams(CommandType commandType, string sql, + IDbParameters parameters, + string tableMappingName); + + DataTable DataTableCreateWithParams(CommandType commandType, string sql, + IDbParameters parameters, + ITableMapping tableMapping); + + DataTable DataTableCreateWithParams(CommandType commandType, string sql, + IDbParameters parameters, + ITableMapping tableMapping, + IDataAdapterSetter dataAdapterSetter); + + #endregion + + #region DataTable Fill operations without parameters + + /// + /// Fill a based on a select command that requires no parameters. + /// + /// The to populate + /// The type of command + /// SQL query to execute + /// The number of rows successfully added to or refreshed in the + int DataTableFill(DataTable dataTable, CommandType commandType, string sql); - // Using IRowMapper to return one result set, multiple output parameters. - IList QueryWithCommandCreator(IDbCommandCreator commandCreator, IRowMapper rowMapper, IDictionary returnedParameters); + int DataTableFill(DataTable dataTable, CommandType commandType, string sql, + string tableMappingName); + int DataTableFill(DataTable dataTable, CommandType commandType, string sql, + ITableMapping tableMapping); - // Multiple return result sets, (A list of lists) - // each with either a IRowMapper, IResultSetExtractor, IRowCallback - // and multiple output parameters. - IDictionary QueryWithCommandCreator(IDbCommandCreator commandCreator, IList resultProcessors); + int DataTableFill(DataTable dataTable, CommandType commandType, string sql, + ITableMapping tableMapping, + IDataAdapterSetter setter); - #endregion + #endregion - #region DataTable Create operations without parameters + #region DataTable Fill operations with parameters - DataTable DataTableCreate(CommandType commandType, string sql); + int DataTableFillWithParams(DataTable dataTable, CommandType commandType, string sql, + IDbParameters parameters); - DataTable DataTableCreate(CommandType commandType, string sql, - string tableMappingName); - - DataTable DataTableCreate(CommandType commandType, string sql, - ITableMapping tableMapping); - - DataTable DataTableCreate(CommandType commandType, string sql, - ITableMapping tableMapping, - IDataAdapterSetter setter); - - #endregion + int DataTableFillWithParams(DataTable dataTable, CommandType commandType, string sql, + IDbParameters parameters, + string tableName); - #region DataTable Create operations with parameters + int DataTableFillWithParams(DataTable dataTable, CommandType commandType, string sql, + IDbParameters parameters, + ITableMapping tableMapping); - DataTable DataTableCreateWithParams(CommandType commandType, string sql, - IDbParameters parameters); + int DataTableFillWithParams(DataTable dataTable, CommandType commandType, string sql, + IDbParameters parameters, + ITableMapping tableMapping, + IDataAdapterSetter dataAdapterSetter); - DataTable DataTableCreateWithParams(CommandType commandType, string sql, - IDbParameters parameters, - string tableMappingName); + #endregion - DataTable DataTableCreateWithParams(CommandType commandType, string sql, - IDbParameters parameters, - ITableMapping tableMapping); + #region DataTable Update operations - DataTable DataTableCreateWithParams(CommandType commandType, string sql, - IDbParameters parameters, - ITableMapping tableMapping, - IDataAdapterSetter dataAdapterSetter); + int DataTableUpdateWithCommandBuilder(DataTable dataTable, + CommandType commandType, + string selectSql, + IDbParameters parameters, + string tableName); + int DataTableUpdateWithCommandBuilder(DataTable dataTable, + CommandType commandType, + string selectSql, + IDbParameters parameters, + string tableName, + IDataAdapterSetter dataAdapterSetter); + int DataTableUpdateWithCommandBuilder(DataTable dataTable, + CommandType commandType, + string selectSql, + IDbParameters parameters, + ITableMapping tableMapping, + IDataAdapterSetter dataAdapterSetter); - #endregion - - #region DataTable Fill operations without parameters - /// - /// Fill a based on a select command that requires no parameters. - /// - /// The to populate - /// The type of command - /// SQL query to execute - /// The number of rows successfully added to or refreshed in the - int DataTableFill(DataTable dataTable, CommandType commandType, string sql); - - int DataTableFill(DataTable dataTable, CommandType commandType, string sql, - string tableMappingName); - - int DataTableFill(DataTable dataTable, CommandType commandType, string sql, - ITableMapping tableMapping); - - int DataTableFill(DataTable dataTable, CommandType commandType, string sql, - ITableMapping tableMapping, - IDataAdapterSetter setter); - - - #endregion - - #region DataTable Fill operations with parameters - - int DataTableFillWithParams(DataTable dataTable, CommandType commandType, string sql, - IDbParameters parameters); - - int DataTableFillWithParams(DataTable dataTable, CommandType commandType, string sql, - IDbParameters parameters, - string tableName); - - int DataTableFillWithParams(DataTable dataTable, CommandType commandType, string sql, - IDbParameters parameters, - ITableMapping tableMapping); - - int DataTableFillWithParams(DataTable dataTable, CommandType commandType, string sql, - IDbParameters parameters, - ITableMapping tableMapping, - IDataAdapterSetter dataAdapterSetter); - - #endregion - - #region DataTable Update operations - - int DataTableUpdateWithCommandBuilder(DataTable dataTable, - CommandType commandType, - string selectSql, - IDbParameters parameters, - string tableName); - - int DataTableUpdateWithCommandBuilder(DataTable dataTable, - CommandType commandType, - string selectSql, - IDbParameters parameters, - string tableName, - IDataAdapterSetter dataAdapterSetter); - - int DataTableUpdateWithCommandBuilder(DataTable dataTable, - CommandType commandType, - string selectSql, - IDbParameters parameters, - ITableMapping tableMapping, - IDataAdapterSetter dataAdapterSetter); - - int DataTableUpdate(DataTable dataTable, - string tableName, - CommandType insertCommandtype, string insertSql, IDbParameters insertParameters, - CommandType updateCommandtype, string updateSql, IDbParameters updateParameters, - CommandType deleteCommandtype, string deleteSql, IDbParameters deleteParameters); - - int DataTableUpdate(DataTable dataTable, - string tableName, - CommandType insertCommandtype, string insertSql, IDbParameters insertParameters, - CommandType updateCommandtype, string updateSql, IDbParameters updateParameters, - CommandType deleteCommandtype, string deleteSql, IDbParameters deleteParameters, - IDataAdapterSetter dataAdapterSetter); - - int DataTableUpdate(DataTable dataTable, - ITableMapping tableMapping, - CommandType insertCommandtype, string insertSql, IDbParameters insertParameters, - CommandType updateCommandtype, string updateSql, IDbParameters updateParameters, - CommandType deleteCommandtype, string deleteSql, IDbParameters deleteParameters, - IDataAdapterSetter dataAdapterSetter); - - - - #endregion - - #region DataSet Create operations without parameters - - DataSet DataSetCreate(CommandType commandType, string sql); - - DataSet DataSetCreate(CommandType commandType, string sql, - string[] tableNames); - - DataSet DataSetCreate(CommandType commandType, string sql, - ITableMappingCollection tableMapping); - - DataSet DataSetCreate(CommandType commandType, string sql, - ITableMappingCollection tableMapping, - IDataAdapterSetter setter); - - DataSet DataSetCreate(CommandType commandType, string sql, - ITableMappingCollection tableMapping, - IDataAdapterSetter setter, - IDataSetFillLifecycleProcessor fillLifecycleProcessor); - #endregion - - #region DataSet Create operations with parameters - - DataSet DataSetCreateWithParams(CommandType commandType, string sql, - IDbParameters parameters); - - DataSet DataSetCreateWithParams(CommandType commandType, string sql, - IDbParameters parameters, - string[] tableNames); - - DataSet DataSetCreateWithParams(CommandType commandType, string sql, - IDbParameters parameters, - ITableMappingCollection tableMapping); - - DataSet DataSetCreateWithParams(CommandType commandType, string sql, - IDbParameters parameters, - ITableMappingCollection tableMapping, - IDataAdapterSetter dataAdapterSetter); - - DataSet DataSetCreateWithParams(CommandType commandType, string sql, - IDbParameters parameters, - ITableMappingCollection tableMapping, - IDataAdapterSetter dataAdapterSetter, - IDataSetFillLifecycleProcessor fillLifecycleProcessor); - - #endregion - - #region DataSet Fill operations without parameters - - /// - /// Fill a based on a select command that requires no parameters. - /// - /// The to populate - /// The type of command - /// SQL query to execute - /// The number of rows successfully added to or refreshed in the - int DataSetFill(DataSet dataSet, CommandType commandType, string sql); - - /// - /// Fill a based on a select command that requires no parameters - /// that returns one or more result sets that are added as - /// s to the - /// - /// The to populate - /// The type of command - /// SQL query to execute - /// The mapping of table names for each - /// created - /// - int DataSetFill(DataSet dataSet, CommandType commandType, string sql, - string[] tableNames); - - int DataSetFill(DataSet dataSet, CommandType commandType, string sql, - ITableMappingCollection tableMapping); - - int DataSetFill(DataSet dataSet, CommandType commandType, string sql, - ITableMappingCollection tableMapping, - IDataAdapterSetter setter); - - int DataSetFill(DataSet dataSet, CommandType commandType, string sql, - ITableMappingCollection tableMapping, - IDataAdapterSetter setter, - IDataSetFillLifecycleProcessor fillLifecycleProcessor); - - #endregion - - #region DataSet Fill operations with parameters - - int DataSetFillWithParameters(DataSet dataSet, CommandType commandType, string sql, - IDbParameters parameters); - - int DataSetFillWithParameters(DataSet dataSet, CommandType commandType, string sql, - IDbParameters parameters, - string[] tableNames); - - int DataSetFillWithParameters(DataSet dataSet, CommandType commandType, string sql, - IDbParameters parameters, - ITableMappingCollection tableMapping); - - int DataSetFillWithParameters(DataSet dataSet, CommandType commandType, string sql, - IDbParameters parameters, - ITableMappingCollection tableMapping, - IDataAdapterSetter dataAdapterSetter); - - int DataSetFillWithParameters(DataSet dataSet, CommandType commandType, string sql, - IDbParameters parameters, - ITableMappingCollection tableMapping, - IDataAdapterSetter dataAdapterSetter, - IDataSetFillLifecycleProcessor fillLifecycleProcessor); - - #endregion - - #region DataSet Update operations - - int DataSetUpdateWithCommandBuilder(DataSet dataSet, - CommandType commandType, - string selectSql, - IDbParameters selectParameters, - string tableName); - - int DataSetUpdateWithCommandBuilder(DataSet dataSet, - CommandType commandType, - string selectSql, - IDbParameters selectParameters, - string tableName, - IDataAdapterSetter dataAdapterSetter); - - int DataSetUpdateWithCommandBuilder(DataSet dataSet, - CommandType commandType, - string selectSql, - IDbParameters selectParameters, - ITableMappingCollection tableMapping, - IDataAdapterSetter dataAdapterSetter); - - - int DataSetUpdate(DataSet dataSet, - string tableName, - IDbCommand insertCommand, - IDbCommand updateCommand, - IDbCommand deleteCommand); - - - int DataSetUpdate(DataSet dataSet, - string tableName, - CommandType insertCommandtype, string insertSql, IDbParameters insertParameters, - CommandType updateCommandtype, string updateSql, IDbParameters updateParameters, - CommandType deleteCommandtype, string deleteSql, IDbParameters deleteParameters); - - - int DataSetUpdate(DataSet dataSet, - string tableName, - IDbCommand insertCommand, - IDbCommand updateCommand, - IDbCommand deleteCommand, - IDataAdapterSetter dataAdapterSetter); - - int DataSetUpdate(DataSet dataSet, - ITableMappingCollection tableMapping, - IDbCommand insertCommand, - IDbCommand updateCommand, - IDbCommand deleteCommand); - - int DataSetUpdate(DataSet dataSet, - ITableMappingCollection tableMapping, - IDbCommand insertCommand, - IDbCommand updateCommand, - IDbCommand deleteCommand, - IDataAdapterSetter dataAdapterSetter); - - #endregion - - #region Parameter Creation Helper Methods - - IDbParameters CreateDbParameters(); - - /// - /// Note that output parameters are marked input/output after derivation.... - /// (TODO - double check....) - /// - /// - /// - IDataParameter[] DeriveParameters(string procedureName); - - IDataParameter[] DeriveParameters(string procedureName, bool includeReturnParameter); - - #endregion - - #region Behavioral Control Properties - - /// - /// An instance of a DbProvider implementation. - /// - IDbProvider DbProvider { get; set; } - - /// - /// Gets or set the System.Type to use to create an instance of IDataReaderWrapper - /// for the purpose of having defaults values to use in case of DBNull values read - /// from IDataReader. - /// - /// The type of the data reader wrapper. - Type DataReaderWrapperType { get; set; } - - /// - /// Gets or sets the command timeout for IDbCommands that this AdoTemplate executes. - /// - /// Default is 0, indicating to use the database provider's default. - /// Any timeout specified here will be overridden by the remaining - /// transaction timeout when executing within a transaction that has a - /// timeout specified at the transaction level. - /// - /// The command timeout. - int CommandTimeout { get; set; } - - #endregion - } + int DataTableUpdate(DataTable dataTable, + string tableName, + CommandType insertCommandtype, string insertSql, IDbParameters insertParameters, + CommandType updateCommandtype, string updateSql, IDbParameters updateParameters, + CommandType deleteCommandtype, string deleteSql, IDbParameters deleteParameters); + int DataTableUpdate(DataTable dataTable, + string tableName, + CommandType insertCommandtype, string insertSql, IDbParameters insertParameters, + CommandType updateCommandtype, string updateSql, IDbParameters updateParameters, + CommandType deleteCommandtype, string deleteSql, IDbParameters deleteParameters, + IDataAdapterSetter dataAdapterSetter); + int DataTableUpdate(DataTable dataTable, + ITableMapping tableMapping, + CommandType insertCommandtype, string insertSql, IDbParameters insertParameters, + CommandType updateCommandtype, string updateSql, IDbParameters updateParameters, + CommandType deleteCommandtype, string deleteSql, IDbParameters deleteParameters, + IDataAdapterSetter dataAdapterSetter); + + #endregion + + #region DataSet Create operations without parameters + + DataSet DataSetCreate(CommandType commandType, string sql); + + DataSet DataSetCreate(CommandType commandType, string sql, + string[] tableNames); + + DataSet DataSetCreate(CommandType commandType, string sql, + ITableMappingCollection tableMapping); + + DataSet DataSetCreate(CommandType commandType, string sql, + ITableMappingCollection tableMapping, + IDataAdapterSetter setter); + + DataSet DataSetCreate(CommandType commandType, string sql, + ITableMappingCollection tableMapping, + IDataAdapterSetter setter, + IDataSetFillLifecycleProcessor fillLifecycleProcessor); + + #endregion + + #region DataSet Create operations with parameters + + DataSet DataSetCreateWithParams(CommandType commandType, string sql, + IDbParameters parameters); + + DataSet DataSetCreateWithParams(CommandType commandType, string sql, + IDbParameters parameters, + string[] tableNames); + + DataSet DataSetCreateWithParams(CommandType commandType, string sql, + IDbParameters parameters, + ITableMappingCollection tableMapping); + + DataSet DataSetCreateWithParams(CommandType commandType, string sql, + IDbParameters parameters, + ITableMappingCollection tableMapping, + IDataAdapterSetter dataAdapterSetter); + + DataSet DataSetCreateWithParams(CommandType commandType, string sql, + IDbParameters parameters, + ITableMappingCollection tableMapping, + IDataAdapterSetter dataAdapterSetter, + IDataSetFillLifecycleProcessor fillLifecycleProcessor); + + #endregion + + #region DataSet Fill operations without parameters + + /// + /// Fill a based on a select command that requires no parameters. + /// + /// The to populate + /// The type of command + /// SQL query to execute + /// The number of rows successfully added to or refreshed in the + int DataSetFill(DataSet dataSet, CommandType commandType, string sql); + + /// + /// Fill a based on a select command that requires no parameters + /// that returns one or more result sets that are added as + /// s to the + /// + /// The to populate + /// The type of command + /// SQL query to execute + /// The mapping of table names for each + /// created + /// + int DataSetFill(DataSet dataSet, CommandType commandType, string sql, + string[] tableNames); + + int DataSetFill(DataSet dataSet, CommandType commandType, string sql, + ITableMappingCollection tableMapping); + + int DataSetFill(DataSet dataSet, CommandType commandType, string sql, + ITableMappingCollection tableMapping, + IDataAdapterSetter setter); + + int DataSetFill(DataSet dataSet, CommandType commandType, string sql, + ITableMappingCollection tableMapping, + IDataAdapterSetter setter, + IDataSetFillLifecycleProcessor fillLifecycleProcessor); + + #endregion + + #region DataSet Fill operations with parameters + + int DataSetFillWithParameters(DataSet dataSet, CommandType commandType, string sql, + IDbParameters parameters); + + int DataSetFillWithParameters(DataSet dataSet, CommandType commandType, string sql, + IDbParameters parameters, + string[] tableNames); + + int DataSetFillWithParameters(DataSet dataSet, CommandType commandType, string sql, + IDbParameters parameters, + ITableMappingCollection tableMapping); + + int DataSetFillWithParameters(DataSet dataSet, CommandType commandType, string sql, + IDbParameters parameters, + ITableMappingCollection tableMapping, + IDataAdapterSetter dataAdapterSetter); + + int DataSetFillWithParameters(DataSet dataSet, CommandType commandType, string sql, + IDbParameters parameters, + ITableMappingCollection tableMapping, + IDataAdapterSetter dataAdapterSetter, + IDataSetFillLifecycleProcessor fillLifecycleProcessor); + + #endregion + + #region DataSet Update operations + + int DataSetUpdateWithCommandBuilder(DataSet dataSet, + CommandType commandType, + string selectSql, + IDbParameters selectParameters, + string tableName); + + int DataSetUpdateWithCommandBuilder(DataSet dataSet, + CommandType commandType, + string selectSql, + IDbParameters selectParameters, + string tableName, + IDataAdapterSetter dataAdapterSetter); + + int DataSetUpdateWithCommandBuilder(DataSet dataSet, + CommandType commandType, + string selectSql, + IDbParameters selectParameters, + ITableMappingCollection tableMapping, + IDataAdapterSetter dataAdapterSetter); + + int DataSetUpdate(DataSet dataSet, + string tableName, + IDbCommand insertCommand, + IDbCommand updateCommand, + IDbCommand deleteCommand); + + int DataSetUpdate(DataSet dataSet, + string tableName, + CommandType insertCommandtype, string insertSql, IDbParameters insertParameters, + CommandType updateCommandtype, string updateSql, IDbParameters updateParameters, + CommandType deleteCommandtype, string deleteSql, IDbParameters deleteParameters); + + int DataSetUpdate(DataSet dataSet, + string tableName, + IDbCommand insertCommand, + IDbCommand updateCommand, + IDbCommand deleteCommand, + IDataAdapterSetter dataAdapterSetter); + + int DataSetUpdate(DataSet dataSet, + ITableMappingCollection tableMapping, + IDbCommand insertCommand, + IDbCommand updateCommand, + IDbCommand deleteCommand); + + int DataSetUpdate(DataSet dataSet, + ITableMappingCollection tableMapping, + IDbCommand insertCommand, + IDbCommand updateCommand, + IDbCommand deleteCommand, + IDataAdapterSetter dataAdapterSetter); + + #endregion + + #region Parameter Creation Helper Methods + + IDbParameters CreateDbParameters(); + + /// + /// Note that output parameters are marked input/output after derivation.... + /// (TODO - double check....) + /// + /// + /// + IDataParameter[] DeriveParameters(string procedureName); + + IDataParameter[] DeriveParameters(string procedureName, bool includeReturnParameter); + + #endregion + + #region Behavioral Control Properties + + /// + /// An instance of a DbProvider implementation. + /// + IDbProvider DbProvider { get; set; } + + /// + /// Gets or set the System.Type to use to create an instance of IDataReaderWrapper + /// for the purpose of having defaults values to use in case of DBNull values read + /// from IDataReader. + /// + /// The type of the data reader wrapper. + Type DataReaderWrapperType { get; set; } + + /// + /// Gets or sets the command timeout for IDbCommands that this AdoTemplate executes. + /// + /// Default is 0, indicating to use the database provider's default. + /// Any timeout specified here will be overridden by the remaining + /// transaction timeout when executing within a transaction that has a + /// timeout specified at the transaction level. + /// + /// The command timeout. + int CommandTimeout { get; set; } + + #endregion } diff --git a/src/Spring/Spring.Data/Data/ICommandCallback.cs b/src/Spring/Spring.Data/Data/ICommandCallback.cs index 888e125b..e03cfcc7 100644 --- a/src/Spring/Spring.Data/Data/ICommandCallback.cs +++ b/src/Spring/Spring.Data/Data/ICommandCallback.cs @@ -1,14 +1,14 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. - * + * Copyright � 2002-2011 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. @@ -20,33 +20,32 @@ using System.Data; -namespace Spring.Data +namespace Spring.Data; + +/// +/// Generic callback interface for code that operates on a +/// IDbCommand. +/// +/// +///

Allows you to execute any number of operations +/// on a single IDbCommand, for example a single ExecuteScalar +/// call or repeated execute calls with varying parameters. +///

+///

Used internally by AdoTemplate, but also useful for +/// application code. Note that the passed in IDbCommand +/// has been created by the framework.

+///
+/// Mark Pollack +public interface ICommandCallback { - /// - /// Generic callback interface for code that operates on a - /// IDbCommand. - /// - /// - ///

Allows you to execute any number of operations - /// on a single IDbCommand, for example a single ExecuteScalar - /// call or repeated execute calls with varying parameters. - ///

- ///

Used internally by AdoTemplate, but also useful for - /// application code. Note that the passed in IDbCommand - /// has been created by the framework.

- ///
- /// Mark Pollack - public interface ICommandCallback - { - /// - /// Called by AdoTemplate.Execute with an active ADO.NET IDbCommand. - /// The calling code does not need to care about closing the - /// command or the connection, or - /// about handling transactions: this will all be handled by - /// Spring's AdoTemplate - /// - /// An active IDbCommand instance - /// The result object - object DoInCommand(IDbCommand command); - } + /// + /// Called by AdoTemplate.Execute with an active ADO.NET IDbCommand. + /// The calling code does not need to care about closing the + /// command or the connection, or + /// about handling transactions: this will all be handled by + /// Spring's AdoTemplate + /// + /// An active IDbCommand instance + /// The result object + object DoInCommand(IDbCommand command); } diff --git a/src/Spring/Spring.Data/Data/ICommandSetter.cs b/src/Spring/Spring.Data/Data/ICommandSetter.cs index c8a16c76..a1a5ed8b 100644 --- a/src/Spring/Spring.Data/Data/ICommandSetter.cs +++ b/src/Spring/Spring.Data/Data/ICommandSetter.cs @@ -20,19 +20,15 @@ using System.Data; -namespace Spring.Data +namespace Spring.Data; + +/// +/// Called by the AdoTemplate class to allow implementations +/// to set any necessary parameters on the command object. +/// The CommandType and CommandText will have already been supplied. +/// +/// Mark Pollack (.NET) +public interface ICommandSetter { - - /// - /// Called by the AdoTemplate class to allow implementations - /// to set any necessary parameters on the command object. - /// The CommandType and CommandText will have already been supplied. - /// - /// Mark Pollack (.NET) - public interface ICommandSetter - { - - - void SetValues(IDbCommand dbCommand); - } + void SetValues(IDbCommand dbCommand); } diff --git a/src/Spring/Spring.Data/Data/ICommandTextProvider.cs b/src/Spring/Spring.Data/Data/ICommandTextProvider.cs index 5353977f..70947c88 100644 --- a/src/Spring/Spring.Data/Data/ICommandTextProvider.cs +++ b/src/Spring/Spring.Data/Data/ICommandTextProvider.cs @@ -18,22 +18,21 @@ #endregion -namespace Spring.Data +namespace Spring.Data; + +/// +/// Interface to be implemented by objects that can provide SQL strings +/// +/// Typically implemented by IDbCommandCreator and +/// ICommandCallbacks that want to expose the CommandText they +/// use to create their ADO.NET commands, to allow for better +/// contextual information in case of exceptions +/// Mark Pollack(.NET) +/// Juergen Hoeller +public interface ICommandTextProvider { - /// - /// Interface to be implemented by objects that can provide SQL strings - /// - /// Typically implemented by IDbCommandCreator and - /// ICommandCallbacks that want to expose the CommandText they - /// use to create their ADO.NET commands, to allow for better - /// contextual information in case of exceptions - /// Mark Pollack(.NET) - /// Juergen Hoeller - public interface ICommandTextProvider + string CommandText { - string CommandText - { - get; - } + get; } } diff --git a/src/Spring/Spring.Data/Data/ICommonAdoOperations.cs b/src/Spring/Spring.Data/Data/ICommonAdoOperations.cs index ef67c0c2..8eac154e 100644 --- a/src/Spring/Spring.Data/Data/ICommonAdoOperations.cs +++ b/src/Spring/Spring.Data/Data/ICommonAdoOperations.cs @@ -22,222 +22,213 @@ using System.Collections; using System.Data; using Spring.Data.Common; -namespace Spring.Data +namespace Spring.Data; + +public interface ICommonAdoOperations { - public interface ICommonAdoOperations - { - #region ExecuteScalar + #region ExecuteScalar - /// - /// Execute the query with the specified command text returning a scalar result - /// - /// No parameters are used. As with - /// IDbCommand.ExecuteScalar, it returns the first column of the first row in the resultset - /// returned by the query. Extra columns or row are ignored. - /// The command type - /// The command text to execute. - /// The first column of the first row in the result set. - object ExecuteScalar(CommandType cmdType, string cmdText); + /// + /// Execute the query with the specified command text returning a scalar result + /// + /// No parameters are used. As with + /// IDbCommand.ExecuteScalar, it returns the first column of the first row in the resultset + /// returned by the query. Extra columns or row are ignored. + /// The command type + /// The command text to execute. + /// The first column of the first row in the result set. + object ExecuteScalar(CommandType cmdType, string cmdText); + /// + /// Execute the query with the specified command text and parameter returning a scalar result + /// + /// The command type + /// The command text to execute. + /// The name of the parameter to map. + /// One of the database parameter type enumerations. + /// The length of the parameter. 0 if not applicable to parameter type. + /// The parameter value. + /// The first column of the first row in the result set + object ExecuteScalar(CommandType cmdType, string cmdText, + string parameterName, Enum dbType, int size, object parameterValue); - /// - /// Execute the query with the specified command text and parameter returning a scalar result - /// - /// The command type - /// The command text to execute. - /// The name of the parameter to map. - /// One of the database parameter type enumerations. - /// The length of the parameter. 0 if not applicable to parameter type. - /// The parameter value. - /// The first column of the first row in the result set - object ExecuteScalar(CommandType cmdType, string cmdText, - string parameterName, Enum dbType, int size, object parameterValue); + /// + /// Execute the query with the specified command text and parameters returning a scalar result + /// + /// The command type + /// The command text to execute. + /// The parameter collection to map. + /// The first column of the first row in the result set + object ExecuteScalar(CommandType cmdType, string cmdText, + IDbParameters parameters); - /// - /// Execute the query with the specified command text and parameters returning a scalar result - /// - /// The command type - /// The command text to execute. - /// The parameter collection to map. - /// The first column of the first row in the result set - object ExecuteScalar(CommandType cmdType, string cmdText, - IDbParameters parameters); + /// + /// Execute the query with the specified command text and parameters set via the + /// command setter, returning a scalar result + /// + /// The command type + /// The command text to execute. + /// The command setter. + /// The first column of the first row in the result set + object ExecuteScalar(CommandType cmdType, + string cmdText, + ICommandSetter commandSetter); - /// - /// Execute the query with the specified command text and parameters set via the - /// command setter, returning a scalar result - /// - /// The command type - /// The command text to execute. - /// The command setter. - /// The first column of the first row in the result set - object ExecuteScalar(CommandType cmdType, - string cmdText, - ICommandSetter commandSetter); + /// + /// Execute the query with a command created via IDbCommandCreator and + /// parameters + /// + /// Output parameters can be retrieved via the returned + /// dictionary. + /// + /// More commonly used as a lower level support method within the framework, + /// for example StoredProcedure/AdoScalar. + /// + /// + /// The callback to create a IDbCommand. + /// A dictionary containing output parameters, if any + IDictionary ExecuteScalar(IDbCommandCreator commandCreator); - /// - /// Execute the query with a command created via IDbCommandCreator and - /// parameters - /// - /// Output parameters can be retrieved via the returned - /// dictionary. - /// - /// More commonly used as a lower level support method within the framework, - /// for example StoredProcedure/AdoScalar. - /// - /// - /// The callback to create a IDbCommand. - /// A dictionary containing output parameters, if any - IDictionary ExecuteScalar(IDbCommandCreator commandCreator); + #endregion - #endregion + #region ExecuteNonQuery - #region ExecuteNonQuery + /// + /// Executes a non query returning the number of rows affected. + /// + /// The command type. + /// The command text to execute. + /// The number of rows affected. + int ExecuteNonQuery(CommandType cmdType, string cmdText); - /// - /// Executes a non query returning the number of rows affected. - /// - /// The command type. - /// The command text to execute. - /// The number of rows affected. - int ExecuteNonQuery(CommandType cmdType, string cmdText); + /// + /// Executes a non query returning the number of rows affected. + /// + /// The command type. + /// The command text to execute. + /// The name of the parameter to map. + /// One of the database parameter type enumerations. + /// The length of the parameter. 0 if not applicable to parameter type. + /// The parameter value. + /// The number of rows affected. + int ExecuteNonQuery(CommandType cmdType, string cmdText, + string parameterName, Enum dbType, int size, object parameterValue); - /// - /// Executes a non query returning the number of rows affected. - /// - /// The command type. - /// The command text to execute. - /// The name of the parameter to map. - /// One of the database parameter type enumerations. - /// The length of the parameter. 0 if not applicable to parameter type. - /// The parameter value. - /// The number of rows affected. - int ExecuteNonQuery(CommandType cmdType, string cmdText, - string parameterName, Enum dbType, int size, object parameterValue); + /// + /// Executes a non query returning the number of rows affected. + /// + /// The command type. + /// The command text to execute. + /// The parameter collection to map. + /// The number of rows affected. + int ExecuteNonQuery(CommandType cmdType, string cmdText, + IDbParameters parameters); - /// - /// Executes a non query returning the number of rows affected. - /// - /// The command type. - /// The command text to execute. - /// The parameter collection to map. - /// The number of rows affected. - int ExecuteNonQuery(CommandType cmdType, string cmdText, - IDbParameters parameters); + /// + /// Executes a non query with parameters set via the + /// command setter, returning the number of rows affected. + /// + /// The command type. + /// The command text to execute. + /// The command setter. + /// The number of rows affected. + int ExecuteNonQuery(CommandType cmdType, string cmdText, + ICommandSetter commandSetter); - /// - /// Executes a non query with parameters set via the - /// command setter, returning the number of rows affected. - /// - /// The command type. - /// The command text to execute. - /// The command setter. - /// The number of rows affected. - int ExecuteNonQuery(CommandType cmdType, string cmdText, - ICommandSetter commandSetter); + /// + /// Executes a non query with a command created via IDbCommandCreator and + /// parameters. + /// + /// Output parameters can be retrieved via the returned + /// dictionary. + /// + /// More commonly used as a lower level support method within the framework, + /// for example StoredProcedure/AdoScalar. + /// + /// + /// The callback to create a IDbCommand. + /// The number of rows affected. + IDictionary ExecuteNonQuery(IDbCommandCreator commandCreator); + #endregion - /// - /// Executes a non query with a command created via IDbCommandCreator and - /// parameters. - /// - /// Output parameters can be retrieved via the returned - /// dictionary. - /// - /// More commonly used as a lower level support method within the framework, - /// for example StoredProcedure/AdoScalar. - /// - /// - /// The callback to create a IDbCommand. - /// The number of rows affected. - IDictionary ExecuteNonQuery(IDbCommandCreator commandCreator); + #region Query with RowCallback + /// + /// Execute a query given IDbCommand's type and text, reading a + /// single result set on a per-row basis with a . + /// + /// The type of command. + /// The text of the query. + /// callback that will extract results + /// one row at a time. + /// + void QueryWithRowCallback(CommandType cmdType, string cmdText, IRowCallback rowCallback); - #endregion + /// + /// Execute a query given IDbCommand's type and text and provided parameter + /// information, reading a + /// single result set on a per-row basis with a . + /// + /// The type of command + /// The text of the query. + /// callback that will extract results + /// one row at a time. + /// + /// The name of the parameter to map. + /// One of the database parameter type enumerations. + /// The length of the parameter. 0 if not applicable to parameter type. + /// The parameter value. + void QueryWithRowCallback(CommandType cmdType, string cmdText, IRowCallback rowCallback, + string parameterName, Enum dbType, int size, object parameterValue); - #region Query with RowCallback + /// + /// Execute a query given IDbCommand's type and text and provided IDbParameters, + /// reading a single result set on a per-row basis with a . + /// + /// Type of the command. + /// The text of the query. + /// callback that will extract results + /// one row at a time. + /// The parameter collection to map. + void QueryWithRowCallback(CommandType cmdType, string cmdText, IRowCallback rowCallback, + IDbParameters parameters); - /// - /// Execute a query given IDbCommand's type and text, reading a - /// single result set on a per-row basis with a . - /// - /// The type of command. - /// The text of the query. - /// callback that will extract results - /// one row at a time. - /// - void QueryWithRowCallback(CommandType cmdType, string cmdText, IRowCallback rowCallback); + /// + /// Execute a query given IDbCommand's type and text by + /// passing the created IDbCommand to a ICommandSetter implementation + /// that knows how to bind values to the IDbCommand, reading a + /// single result set on a per-row basis with a . + /// + /// The type of command + /// The text of the query. + /// callback that will extract results + /// one row at a time. + /// + /// The command setter. + void QueryWithRowCallback(CommandType cmdType, String cmdText, IRowCallback rowCallback, + ICommandSetter commandSetter); + #endregion - /// - /// Execute a query given IDbCommand's type and text and provided parameter - /// information, reading a - /// single result set on a per-row basis with a . - /// - /// The type of command - /// The text of the query. - /// callback that will extract results - /// one row at a time. - /// - /// The name of the parameter to map. - /// One of the database parameter type enumerations. - /// The length of the parameter. 0 if not applicable to parameter type. - /// The parameter value. - void QueryWithRowCallback(CommandType cmdType, string cmdText, IRowCallback rowCallback, - string parameterName, Enum dbType, int size, object parameterValue); + #region Query with RowCallback Delegate - /// - /// Execute a query given IDbCommand's type and text and provided IDbParameters, - /// reading a single result set on a per-row basis with a . - /// - /// Type of the command. - /// The text of the query. - /// callback that will extract results - /// one row at a time. - /// The parameter collection to map. - void QueryWithRowCallback(CommandType cmdType, string cmdText, IRowCallback rowCallback, - IDbParameters parameters); + void QueryWithRowCallbackDelegate(CommandType cmdType, string sql, RowCallbackDelegate rowCallbackDelegate); - /// - /// Execute a query given IDbCommand's type and text by - /// passing the created IDbCommand to a ICommandSetter implementation - /// that knows how to bind values to the IDbCommand, reading a - /// single result set on a per-row basis with a . - /// - /// The type of command - /// The text of the query. - /// callback that will extract results - /// one row at a time. - /// - /// The command setter. - void QueryWithRowCallback(CommandType cmdType, String cmdText, IRowCallback rowCallback, - ICommandSetter commandSetter); + void QueryWithRowCallbackDelegate(CommandType cmdType, string sql, RowCallbackDelegate rowCallbackDelegate, ICommandSetter commandSetter); + void QueryWithRowCallbackDelegate(CommandType cmdType, string sql, RowCallbackDelegate rowCallbackDelegate, + string name, Enum dbType, int size, object parameterValue); - #endregion + void QueryWithRowCallbackDelegate(CommandType cmdType, string sql, RowCallbackDelegate rowCallbackDelegate, IDbParameters parameters); - #region Query with RowCallback Delegate + #endregion - void QueryWithRowCallbackDelegate(CommandType cmdType, string sql, RowCallbackDelegate rowCallbackDelegate); + #region Query with CommandCreator - void QueryWithRowCallbackDelegate(CommandType cmdType, string sql, RowCallbackDelegate rowCallbackDelegate, ICommandSetter commandSetter); + void QueryWithCommandCreator(IDbCommandCreator cc, IRowCallback rowCallback); + void QueryWithCommandCreator(IDbCommandCreator cc, IRowCallback rowCallback, IDictionary returnedParameters); - void QueryWithRowCallbackDelegate(CommandType cmdType, string sql, RowCallbackDelegate rowCallbackDelegate, - string name, Enum dbType, int size, object parameterValue); - - - void QueryWithRowCallbackDelegate(CommandType cmdType, string sql, RowCallbackDelegate rowCallbackDelegate, IDbParameters parameters); - - #endregion - - #region Query with CommandCreator - - void QueryWithCommandCreator(IDbCommandCreator cc, IRowCallback rowCallback); - - void QueryWithCommandCreator(IDbCommandCreator cc, IRowCallback rowCallback, IDictionary returnedParameters); - - #endregion - - } + #endregion } diff --git a/src/Spring/Spring.Data/Data/IDataAdapterCallback.cs b/src/Spring/Spring.Data/Data/IDataAdapterCallback.cs index 93d24f27..a5d95d25 100644 --- a/src/Spring/Spring.Data/Data/IDataAdapterCallback.cs +++ b/src/Spring/Spring.Data/Data/IDataAdapterCallback.cs @@ -20,39 +20,38 @@ using System.Data; -namespace Spring.Data +namespace Spring.Data; + +/// +/// Generic callback interface for code that operates on a +/// IDbDataAdapter. +/// +/// +///

Allows you to execute any number of operations +/// on a IDbDataAdapter, for example to Fill a DataSet +/// or other more advanced operations such as the transfering +/// data between two different DataSets. +///

+///

Note that the passed in IDbDataAdapter +/// has been created by the framework and its SelectCommand +/// will be populated with values for CommandType and Text properties +/// along with Connection/Transaction properties based on the +/// calling transaction context. +///

+/// Execute(IDataAdapterCallback dataAdapterCallback) +/// method. +///
+/// Mark Pollack (.NET) +public interface IDataAdapterCallback { /// - /// Generic callback interface for code that operates on a - /// IDbDataAdapter. - /// - /// - ///

Allows you to execute any number of operations - /// on a IDbDataAdapter, for example to Fill a DataSet - /// or other more advanced operations such as the transfering - /// data between two different DataSets. - ///

- ///

Note that the passed in IDbDataAdapter - /// has been created by the framework and its SelectCommand - /// will be populated with values for CommandType and Text properties + /// Called by AdoTemplate.Execute with an preconfigured + /// ADO.NET IDbDataAdapter instance with its SelectCommand + /// property populated with CommandType and Text values /// along with Connection/Transaction properties based on the /// calling transaction context. - ///

- /// Execute(IDataAdapterCallback dataAdapterCallback) - /// method. - ///
- /// Mark Pollack (.NET) - public interface IDataAdapterCallback - { - /// - /// Called by AdoTemplate.Execute with an preconfigured - /// ADO.NET IDbDataAdapter instance with its SelectCommand - /// property populated with CommandType and Text values - /// along with Connection/Transaction properties based on the - /// calling transaction context. - /// - /// An active IDbDataAdapter instance - /// The result object - object DoInDataAdapter(IDbDataAdapter dataAdapter); - } + /// + /// An active IDbDataAdapter instance + /// The result object + object DoInDataAdapter(IDbDataAdapter dataAdapter); } diff --git a/src/Spring/Spring.Data/Data/IDataAdapterSetter.cs b/src/Spring/Spring.Data/Data/IDataAdapterSetter.cs index 4a03d3da..5c79453f 100644 --- a/src/Spring/Spring.Data/Data/IDataAdapterSetter.cs +++ b/src/Spring/Spring.Data/Data/IDataAdapterSetter.cs @@ -20,32 +20,31 @@ using System.Data; -namespace Spring.Data +namespace Spring.Data; + +/// +/// Called by the AdoTemplate class to allow implementations +/// to set any necessary properties on the DbDataAdapter object. +/// +/// +///

For example, this callback can be used to set the +/// AcceptChangesDuringFill property, register an event handler +/// for the FillErrors event, set update batch sizes if your provider +/// supports such functionality, set the ContinueUpdateOnError property, +/// or in .NET 2.0 to set the property AcceptChangesDuringUpdate. +///

+///

+/// Downcast to the appropriate subtype to access vendor specific +/// functionality.

+///

+/// The DataAdapter SelectCommand will be already be +/// populated with values for CommandType and Text properties +/// along with Connection/Transaction properties based on the +/// calling transaction context. +///

+///
+/// Mark Pollack (.NET) +public interface IDataAdapterSetter { - /// - /// Called by the AdoTemplate class to allow implementations - /// to set any necessary properties on the DbDataAdapter object. - /// - /// - ///

For example, this callback can be used to set the - /// AcceptChangesDuringFill property, register an event handler - /// for the FillErrors event, set update batch sizes if your provider - /// supports such functionality, set the ContinueUpdateOnError property, - /// or in .NET 2.0 to set the property AcceptChangesDuringUpdate. - ///

- ///

- /// Downcast to the appropriate subtype to access vendor specific - /// functionality.

- ///

- /// The DataAdapter SelectCommand will be already be - /// populated with values for CommandType and Text properties - /// along with Connection/Transaction properties based on the - /// calling transaction context. - ///

- ///
- /// Mark Pollack (.NET) - public interface IDataAdapterSetter - { - void SetValues(IDbDataAdapter dataAdapter); - } + void SetValues(IDbDataAdapter dataAdapter); } diff --git a/src/Spring/Spring.Data/Data/IDataReaderWrapper.cs b/src/Spring/Spring.Data/Data/IDataReaderWrapper.cs index 4a0a5554..3a25b96c 100644 --- a/src/Spring/Spring.Data/Data/IDataReaderWrapper.cs +++ b/src/Spring/Spring.Data/Data/IDataReaderWrapper.cs @@ -20,30 +20,28 @@ using System.Data; -namespace Spring.Data +namespace Spring.Data; + +/// +/// Custom data reader implementations often delegate to an underlying +/// instance. This interface captures that relationship for reuse in +/// the framework. +/// +/// Implementations will typically add behavior to standard IDataReader methods, +/// for example, by providing default values for DbNull values. +/// See as an example. +/// +/// Mark Pollack (.NET) +public interface IDataReaderWrapper : IDataReader { /// - /// Custom data reader implementations often delegate to an underlying - /// instance. This interface captures that relationship for reuse in - /// the framework. + /// The underlying reader implementation to delegate to for accessing data + /// from a returned result sets. /// - /// Implementations will typically add behavior to standard IDataReader methods, - /// for example, by providing default values for DbNull values. - /// See as an example. - /// - /// Mark Pollack (.NET) - public interface IDataReaderWrapper : IDataReader + /// The wrapped reader. + IDataReader WrappedReader { - /// - /// The underlying reader implementation to delegate to for accessing data - /// from a returned result sets. - /// - /// The wrapped reader. - IDataReader WrappedReader - { - get; - set; - } - + get; + set; } } diff --git a/src/Spring/Spring.Data/Data/IDataSetFillLifecycleProcessor.cs b/src/Spring/Spring.Data/Data/IDataSetFillLifecycleProcessor.cs index eb503d91..2744c385 100644 --- a/src/Spring/Spring.Data/Data/IDataSetFillLifecycleProcessor.cs +++ b/src/Spring/Spring.Data/Data/IDataSetFillLifecycleProcessor.cs @@ -20,42 +20,40 @@ using System.Data; -namespace Spring.Data +namespace Spring.Data; + +/// +/// Lifecycle callback methods that can be registered when +/// performing Fill operations with AdoTemplate. +/// +/// +///

+/// The methods let you set various properties and invoke +/// methods on the DataSet before and after it gets filled by a DataAdapter. +/// For example, EnforceConstraints, BeginLoadData, and EndLoadData +/// can be called to optimize the loading of large DataSets with +/// many related tables. +///

+///

Vendors may expose other propriety methods on their DataSet +/// implementation, downcast to access this specific functionality. +///

+///
+/// Mark Pollack (.NET) +public interface IDataSetFillLifecycleProcessor { - /// - /// Lifecycle callback methods that can be registered when - /// performing Fill operations with AdoTemplate. - /// - /// - ///

- /// The methods let you set various properties and invoke - /// methods on the DataSet before and after it gets filled by a DataAdapter. - /// For example, EnforceConstraints, BeginLoadData, and EndLoadData - /// can be called to optimize the loading of large DataSets with - /// many related tables. - ///

- ///

Vendors may expose other propriety methods on their DataSet - /// implementation, downcast to access this specific functionality. - ///

- ///
- /// Mark Pollack (.NET) - public interface IDataSetFillLifecycleProcessor - { - /// - /// Called before a DataAdapter is used to fill a DataSet - /// the the provided tablename. - /// - /// The DataSet to be filled with a DataTable - /// The table collection to be filled - void BeforeFill(DataSet ds, ITableMappingCollection tableMappingCollection); + /// + /// Called before a DataAdapter is used to fill a DataSet + /// the the provided tablename. + /// + /// The DataSet to be filled with a DataTable + /// The table collection to be filled + void BeforeFill(DataSet ds, ITableMappingCollection tableMappingCollection); - /// - /// Called after a DataAdapter is used to fill a DataSet - /// the the provided tablename. - /// - /// The DataSet to be filled with a DataTable - /// The table collection to be filled - void AfterFill(DataSet ds, ITableMappingCollection tableMappingCollection); - - } + /// + /// Called after a DataAdapter is used to fill a DataSet + /// the the provided tablename. + /// + /// The DataSet to be filled with a DataTable + /// The table collection to be filled + void AfterFill(DataSet ds, ITableMappingCollection tableMappingCollection); } diff --git a/src/Spring/Spring.Data/Data/IDbCommandCreator.cs b/src/Spring/Spring.Data/Data/IDbCommandCreator.cs index 54db8a2c..4fc1a052 100644 --- a/src/Spring/Spring.Data/Data/IDbCommandCreator.cs +++ b/src/Spring/Spring.Data/Data/IDbCommandCreator.cs @@ -21,23 +21,22 @@ using System.Data; using Spring.Data.Common; -namespace Spring.Data +namespace Spring.Data; + +/// +/// One of the central callback interfaces used by the AdoTemplate class +/// This interface creates a IDbCommand. Implementations are responsible +/// for configuring the created command with command type, command text and +/// any necessary parameters. +/// +/// Mark Pollack (.NET) +public interface IDbCommandCreator { - /// - /// One of the central callback interfaces used by the AdoTemplate class - /// This interface creates a IDbCommand. Implementations are responsible - /// for configuring the created command with command type, command text and - /// any necessary parameters. - /// - /// Mark Pollack (.NET) - public interface IDbCommandCreator - { - /// - /// Creates a IDbCommand. - /// - /// The IDbProvider reference that can be used to create the command in a - /// provider independent manner. The provider supplied is the same as used in configuration of AdoTemplate. - /// - IDbCommand CreateDbCommand(IDbProvider dbProvider); - } + /// + /// Creates a IDbCommand. + /// + /// The IDbProvider reference that can be used to create the command in a + /// provider independent manner. The provider supplied is the same as used in configuration of AdoTemplate. + /// + IDbCommand CreateDbCommand(IDbProvider dbProvider); } diff --git a/src/Spring/Spring.Data/Data/IDbCommandCreatorFactory.cs b/src/Spring/Spring.Data/Data/IDbCommandCreatorFactory.cs index 00ef3f8e..8879425c 100644 --- a/src/Spring/Spring.Data/Data/IDbCommandCreatorFactory.cs +++ b/src/Spring/Spring.Data/Data/IDbCommandCreatorFactory.cs @@ -23,204 +23,201 @@ using System.Data; using Spring.Dao; using Spring.Data.Common; -namespace Spring.Data +namespace Spring.Data; + +/// +/// Helper class that can efficiently create multiple IDbCommand +/// objects with different parameters based on a SQL statement and a single +/// set of parameter declarations. +/// +/// Mark Pollack (.NET) +public class IDbCommandCreatorFactory { - /// - /// Helper class that can efficiently create multiple IDbCommand - /// objects with different parameters based on a SQL statement and a single - /// set of parameter declarations. - /// - /// Mark Pollack (.NET) - public class IDbCommandCreatorFactory - { - #region Fields + #region Fields - private String sql; + private String sql; - private IDbParameters declaredParameters; + private IDbParameters declaredParameters; - private IDbProvider dbProvider; + private IDbProvider dbProvider; - private CommandType commandType; + private CommandType commandType; - #endregion + #endregion + #region Constructor (s) - #region Constructor (s) - /// - /// Initializes a new instance of the class. - /// - public IDbCommandCreatorFactory(IDbProvider dbProvider, CommandType commandType, string sql, IDbParameters declaredParameters) - { - this.dbProvider = dbProvider; - this.sql = sql; - this.commandType = commandType; - this.declaredParameters = declaredParameters; - } + /// + /// Initializes a new instance of the class. + /// + public IDbCommandCreatorFactory(IDbProvider dbProvider, CommandType commandType, string sql, IDbParameters declaredParameters) + { + this.dbProvider = dbProvider; + this.sql = sql; + this.commandType = commandType; + this.declaredParameters = declaredParameters; + } - #endregion + #endregion - #region Properties + #region Properties - public IDbParameters DeclaredParameters - { - get - { - return declaredParameters; - } - } - - public string Sql + public IDbParameters DeclaredParameters + { + get { - get { return sql; } + return declaredParameters; + } + } + + public string Sql + { + get { return sql; } + } + + public IDbProvider DbProvider + { + get { return dbProvider; } + } + + public CommandType CommandType + { + get { return commandType; } + } + + #endregion + + #region Methods + + public IDbCommandCreator NewDbCommandCreatorWithParamValues(params object[] inParamValues) + { + return new CommandCreatorWithParamValues(this, inParamValues != null ? ArrayList.Adapter(inParamValues) : new ArrayList()); + } + + public IDbCommandCreator NewDbCommandCreator(IDictionary inParameters) + { + return new CommandCreatorImpl(this, inParameters != null ? inParameters : new Hashtable()); + } + + #endregion + + private class CommandCreatorWithParamValues : IDbCommandCreator + { + private IDbCommandCreatorFactory factory; + private IList inParamValues; + + public CommandCreatorWithParamValues(IDbCommandCreatorFactory factory, IList inParamValues) + { + this.factory = factory; + this.inParamValues = inParamValues; } - public IDbProvider DbProvider + public IDbCommand CreateDbCommand(IDbProvider provider) { - get { return dbProvider; } - } - - public CommandType CommandType - { - get { return commandType; } - } - #endregion - - #region Methods - - public IDbCommandCreator NewDbCommandCreatorWithParamValues(params object[] inParamValues) - { - - return new CommandCreatorWithParamValues(this, inParamValues != null ? ArrayList.Adapter(inParamValues) : new ArrayList()); - } - - - public IDbCommandCreator NewDbCommandCreator(IDictionary inParameters) - { - - return new CommandCreatorImpl(this, inParameters != null ? inParameters : new Hashtable()); - } - - #endregion - - private class CommandCreatorWithParamValues : IDbCommandCreator - { - private IDbCommandCreatorFactory factory; - private IList inParamValues; - - public CommandCreatorWithParamValues(IDbCommandCreatorFactory factory, IList inParamValues) + IDbCommand command = factory.dbProvider.CreateCommand(); + command.CommandText = factory.sql; + command.CommandType = factory.commandType; + if (factory.declaredParameters != null) { - this.factory = factory; - this.inParamValues = inParamValues; - } - - public IDbCommand CreateDbCommand(IDbProvider provider) - { - IDbCommand command = factory.dbProvider.CreateCommand(); - command.CommandText = factory.sql; - command.CommandType = factory.commandType; - if (factory.declaredParameters != null) + int parameterIndex = 0; + foreach (IDbDataParameter declaredParameter in factory.declaredParameters.DataParameterCollection) { - int parameterIndex = 0; - foreach ( IDbDataParameter declaredParameter in factory.declaredParameters.DataParameterCollection) + IDbDataParameter clonedParameter = (IDbDataParameter) ((ICloneable) declaredParameter).Clone(); + if (!(clonedParameter.Direction == ParameterDirection.Output) && + !(clonedParameter.Direction == ParameterDirection.ReturnValue)) { - IDbDataParameter clonedParameter = (IDbDataParameter)((ICloneable)declaredParameter).Clone(); - if (!(clonedParameter.Direction == ParameterDirection.Output) && - !(clonedParameter.Direction == ParameterDirection.ReturnValue)) + if (clonedParameter.Direction == ParameterDirection.InputOutput) { - if (clonedParameter.Direction == ParameterDirection.InputOutput) - { - //heuristic for case when have output parameter from stored procedure discovery classified - //as in-out. Assume out parameters come last in the stored proc definition and ignore - //setting values if there are not enough input values as passed in by the user. - if (parameterIndex < inParamValues.Count) - { - //The value may still be null - Object inValue = inParamValues[parameterIndex]; - clonedParameter.Value = (inValue == null) ? DBNull.Value : inValue; - } else - { - //Since it thinks it is an input-output value and we have no value from the user - pass in null - //as a workaround. - clonedParameter.Value = DBNull.Value; - } - - } - else + //heuristic for case when have output parameter from stored procedure discovery classified + //as in-out. Assume out parameters come last in the stored proc definition and ignore + //setting values if there are not enough input values as passed in by the user. + if (parameterIndex < inParamValues.Count) { //The value may still be null Object inValue = inParamValues[parameterIndex]; clonedParameter.Value = (inValue == null) ? DBNull.Value : inValue; } - // only increment index if we could assign a value from the user specified inputs. - parameterIndex++; + else + { + //Since it thinks it is an input-output value and we have no value from the user - pass in null + //as a workaround. + clonedParameter.Value = DBNull.Value; + } } - - command.Parameters.Add(clonedParameter); - - } - } - return command; - } - - } - private class CommandCreatorImpl : IDbCommandCreator{ - - private IDbCommandCreatorFactory factory; - private IDictionary inParams; - - - public CommandCreatorImpl(IDbCommandCreatorFactory factory, IDictionary inParameters) - { - this.factory = factory; - this.inParams = inParameters; - } - - public IDbCommand CreateDbCommand(IDbProvider provider) - { - IDbCommand command = factory.dbProvider.CreateCommand(); - command.CommandText = factory.sql; - command.CommandType = factory.commandType; - if (factory.declaredParameters != null) - { - foreach ( IDbDataParameter declaredParameter in factory.declaredParameters.DataParameterCollection) - { - IDbDataParameter clonedParameter = (IDbDataParameter)((ICloneable)declaredParameter).Clone(); - - if (IsInputParamter(clonedParameter) && !inParams.Contains(clonedParameter.ParameterName)) - { - throw new InvalidDataAccessApiUsageException("Required input parameter '" + - clonedParameter.ParameterName + "' is missing"); - } - //The value may still be null -// Object inValue = -// inParams[factory.dbProvider.CreateParameterName(clonedParameter.ParameterName)]; - - // TODO: The above code doesn't work as it duplicates parameter prefix, thus failing - // to obtain parameter values. The whole parameter handling mechanism should be refactored - // not to require parameter prefix to be specified when populating named parameters collection - // within AdoOperations. Code below is just a temporary workaround until this issue is resolved. - - Object inValue = inParams[clonedParameter.ParameterName]; - if (!(clonedParameter.Direction == ParameterDirection.Output) && - !(clonedParameter.Direction == ParameterDirection.ReturnValue)) + else { + //The value may still be null + Object inValue = inParamValues[parameterIndex]; clonedParameter.Value = (inValue == null) ? DBNull.Value : inValue; } - command.Parameters.Add(clonedParameter); + // only increment index if we could assign a value from the user specified inputs. + parameterIndex++; } - } - return command; - } - private bool IsInputParamter(IDataParameter parameter) - { - //Due to quirk in DeriveParameters can only verify Input parameter as output parameters - //are incorrectly listed as InputOutput - return (parameter.Direction == ParameterDirection.Input); + command.Parameters.Add(clonedParameter); + } } - } - } + return command; + } + } + + private class CommandCreatorImpl : IDbCommandCreator + { + private IDbCommandCreatorFactory factory; + private IDictionary inParams; + + public CommandCreatorImpl(IDbCommandCreatorFactory factory, IDictionary inParameters) + { + this.factory = factory; + this.inParams = inParameters; + } + + public IDbCommand CreateDbCommand(IDbProvider provider) + { + IDbCommand command = factory.dbProvider.CreateCommand(); + command.CommandText = factory.sql; + command.CommandType = factory.commandType; + if (factory.declaredParameters != null) + { + foreach (IDbDataParameter declaredParameter in factory.declaredParameters.DataParameterCollection) + { + IDbDataParameter clonedParameter = (IDbDataParameter) ((ICloneable) declaredParameter).Clone(); + + if (IsInputParamter(clonedParameter) && !inParams.Contains(clonedParameter.ParameterName)) + { + throw new InvalidDataAccessApiUsageException("Required input parameter '" + + clonedParameter.ParameterName + "' is missing"); + } + //The value may still be null +// Object inValue = +// inParams[factory.dbProvider.CreateParameterName(clonedParameter.ParameterName)]; + + // TODO: The above code doesn't work as it duplicates parameter prefix, thus failing + // to obtain parameter values. The whole parameter handling mechanism should be refactored + // not to require parameter prefix to be specified when populating named parameters collection + // within AdoOperations. Code below is just a temporary workaround until this issue is resolved. + + Object inValue = inParams[clonedParameter.ParameterName]; + if (!(clonedParameter.Direction == ParameterDirection.Output) && + !(clonedParameter.Direction == ParameterDirection.ReturnValue)) + { + clonedParameter.Value = (inValue == null) ? DBNull.Value : inValue; + } + + command.Parameters.Add(clonedParameter); + } + } + + return command; + } + + private bool IsInputParamter(IDataParameter parameter) + { + //Due to quirk in DeriveParameters can only verify Input parameter as output parameters + //are incorrectly listed as InputOutput + return (parameter.Direction == ParameterDirection.Input); + } + } } diff --git a/src/Spring/Spring.Data/Data/IDbDataAdapterCreator.cs b/src/Spring/Spring.Data/Data/IDbDataAdapterCreator.cs index 89261aef..726a56f7 100644 --- a/src/Spring/Spring.Data/Data/IDbDataAdapterCreator.cs +++ b/src/Spring/Spring.Data/Data/IDbDataAdapterCreator.cs @@ -20,25 +20,24 @@ using System.Data; -namespace Spring.Data +namespace Spring.Data; + +/// +/// This interface creates a IDbDataAdapterCommand. +/// Implementations are responsible +/// for configuring the created command with appropriate +/// select and actions commands along with their parameters. +/// +/// +/// Generally used to to support the DataSet functionality in +/// the Spring.Data.Objects namespace. +/// +/// Mark Pollack (.NET) +public interface IDbDataAdapterCreator { - /// - /// This interface creates a IDbDataAdapterCommand. - /// Implementations are responsible - /// for configuring the created command with appropriate - /// select and actions commands along with their parameters. - /// - /// - /// Generally used to to support the DataSet functionality in - /// the Spring.Data.Objects namespace. - /// - /// Mark Pollack (.NET) - public interface IDbDataAdapterCreator - { - /// - /// Creates the data adapter. - /// - /// A new IDbDataAdapter instance - IDbDataAdapter CreateDataAdapter(); - } + /// + /// Creates the data adapter. + /// + /// A new IDbDataAdapter instance + IDbDataAdapter CreateDataAdapter(); } diff --git a/src/Spring/Spring.Data/Data/IResultSetExtractor.cs b/src/Spring/Spring.Data/Data/IResultSetExtractor.cs index 73770b59..99121819 100644 --- a/src/Spring/Spring.Data/Data/IResultSetExtractor.cs +++ b/src/Spring/Spring.Data/Data/IResultSetExtractor.cs @@ -1,14 +1,14 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. - * + * Copyright � 2002-2011 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. @@ -18,43 +18,39 @@ #endregion - using System.Data; -namespace Spring.Data +namespace Spring.Data; + +/// +/// Callback interface to process all result sets and rows in +/// an AdoTemplate query method. +/// +/// Implementations of this interface perform the work +/// of extracting results but don't need worry about managing +/// ADO.NET resources, such as closing the reader or transaction management. +///

+/// This interface is mainly used within the ADO.NET +/// framework. An IResultSetExtractor is usually a simpler choice +/// for result set (DataReader) processing, in particular a +/// RowMapperResultSetExtractor in combination with a IRowMapper. +///

+/// Note: in contracts to a IRowCallbackHandler, a ResultSetExtractor +/// is usually stateless and thus reusable, as long as it doesn't access +/// stateful resources or keep result state within the object. +/// +///
+/// +public interface IResultSetExtractor { /// - /// Callback interface to process all result sets and rows in - /// an AdoTemplate query method. + /// Implementations must implement this method to process all + /// result set and rows in the IDataReader. /// - /// Implementations of this interface perform the work - /// of extracting results but don't need worry about managing - /// ADO.NET resources, such as closing the reader or transaction management. - ///

- /// This interface is mainly used within the ADO.NET - /// framework. An IResultSetExtractor is usually a simpler choice - /// for result set (DataReader) processing, in particular a - /// RowMapperResultSetExtractor in combination with a IRowMapper. - ///

- /// Note: in contracts to a IRowCallbackHandler, a ResultSetExtractor - /// is usually stateless and thus reusable, as long as it doesn't access - /// stateful resources or keep result state within the object. - /// - ///
- /// - public interface IResultSetExtractor - { - /// - /// Implementations must implement this method to process all - /// result set and rows in the IDataReader. - /// - /// The IDataReader to extract data from. - /// Implementations should not close this: it will be closed - /// by the AdoTemplate. - /// An arbitrary result object or null if none. The - /// extractor will typically be stateful in the latter case. - object ExtractData(IDataReader reader); - - - } -} \ No newline at end of file + /// The IDataReader to extract data from. + /// Implementations should not close this: it will be closed + /// by the AdoTemplate. + /// An arbitrary result object or null if none. The + /// extractor will typically be stateful in the latter case. + object ExtractData(IDataReader reader); +} diff --git a/src/Spring/Spring.Data/Data/IRowCallback.cs b/src/Spring/Spring.Data/Data/IRowCallback.cs index 7733d198..75b11050 100644 --- a/src/Spring/Spring.Data/Data/IRowCallback.cs +++ b/src/Spring/Spring.Data/Data/IRowCallback.cs @@ -1,35 +1,31 @@ - - using System.Data; -namespace Spring.Data -{ - /// - /// Callback to process each row of data in an AdoOperation's Query method. - /// - /// - /// Implementations of this interface perform the actual work of extracting - /// results. In contrast to a IResultSetExtractor, a IRowCallback object is typically - /// stateful. It keeps the result state within the object, to be available - /// for later inspection. - /// - /// - public interface IRowCallback - { - /// - /// Implementations must implement this method to process each row of data - /// in the data reader. - /// - /// - /// This method should not advance the cursor by calling Read() - /// on IDataReader but only extract the current values. The - /// caller does not need to care about closing the reader, command, connection, or - /// about handling transactions: this will all be handled by - /// Spring's AdoTemplate - /// - /// An active IDataReader instance - /// The result object - void ProcessRow(IDataReader reader); +namespace Spring.Data; - } -} +/// +/// Callback to process each row of data in an AdoOperation's Query method. +/// +/// +/// Implementations of this interface perform the actual work of extracting +/// results. In contrast to a IResultSetExtractor, a IRowCallback object is typically +/// stateful. It keeps the result state within the object, to be available +/// for later inspection. +/// +/// +public interface IRowCallback +{ + /// + /// Implementations must implement this method to process each row of data + /// in the data reader. + /// + /// + /// This method should not advance the cursor by calling Read() + /// on IDataReader but only extract the current values. The + /// caller does not need to care about closing the reader, command, connection, or + /// about handling transactions: this will all be handled by + /// Spring's AdoTemplate + /// + /// An active IDataReader instance + /// The result object + void ProcessRow(IDataReader reader); +} \ No newline at end of file diff --git a/src/Spring/Spring.Data/Data/IRowMapper.cs b/src/Spring/Spring.Data/Data/IRowMapper.cs index 6c3f62d1..ac4c8012 100644 --- a/src/Spring/Spring.Data/Data/IRowMapper.cs +++ b/src/Spring/Spring.Data/Data/IRowMapper.cs @@ -20,36 +20,35 @@ using System.Data; -namespace Spring.Data +namespace Spring.Data; + +/// +/// Callback to process each row of data in a result set to an object. +/// +/// Implementations of this interface perform the actual work +/// of mapping rows, but don't need worry about managing +/// ADO.NET resources, such as closing the reader. +///

+/// Typically used for AdoTemplate's query methods (with RowMapperResultSetExtractor +/// adapters). RowMapper objects are typically stateless and thus +/// reusable; they are ideal choices for implementing row-mapping logic in a single +/// place. +///

+///

Alternatively, consider subclassing MappingSqlQuery from the Spring.Data.Object +/// namespace: Instead of working with separate AdoTemplate and RowMapper objects, +/// you can have executable query objects (containing row-mapping logic) there. +///

+///
+/// Mark Pollack (.NET) +public interface IRowMapper { - /// - /// Callback to process each row of data in a result set to an object. - /// - /// Implementations of this interface perform the actual work - /// of mapping rows, but don't need worry about managing - /// ADO.NET resources, such as closing the reader. - ///

- /// Typically used for AdoTemplate's query methods (with RowMapperResultSetExtractor - /// adapters). RowMapper objects are typically stateless and thus - /// reusable; they are ideal choices for implementing row-mapping logic in a single - /// place. - ///

- ///

Alternatively, consider subclassing MappingSqlQuery from the Spring.Data.Object - /// namespace: Instead of working with separate AdoTemplate and RowMapper objects, - /// you can have executable query objects (containing row-mapping logic) there. - ///

- ///
- /// Mark Pollack (.NET) - public interface IRowMapper - { - /// - /// Implementations must implement this method to map each row of data in the - /// result set (DataReader). This method should not call Next() on the - /// DataReader; it should only extract the values of the current row. - /// - /// The IDataReader to map (pre-initialized for the current row) - /// The number of the current row. - /// The result object for the current row. - object MapRow(IDataReader reader, int rowNum); - } + /// + /// Implementations must implement this method to map each row of data in the + /// result set (DataReader). This method should not call Next() on the + /// DataReader; it should only extract the values of the current row. + /// + /// The IDataReader to map (pre-initialized for the current row) + /// The number of the current row. + /// The result object for the current row. + object MapRow(IDataReader reader, int rowNum); } diff --git a/src/Spring/Spring.Data/Data/InvalidResultSetAccessException.cs b/src/Spring/Spring.Data/Data/InvalidResultSetAccessException.cs index d964488f..744c6164 100644 --- a/src/Spring/Spring.Data/Data/InvalidResultSetAccessException.cs +++ b/src/Spring/Spring.Data/Data/InvalidResultSetAccessException.cs @@ -21,100 +21,100 @@ using System.Runtime.Serialization; using Spring.Dao; -namespace Spring.Data +namespace Spring.Data; + +/// +/// Exception thrown when a result set has been accessed in an invalid fashion. +/// +/// Mark Pollack (.NET) +[Serializable] +public class InvalidResultSetAccessException : InvalidDataAccessResourceUsageException, ISerializable { - /// - /// Exception thrown when a result set has been accessed in an invalid fashion. - /// - /// Mark Pollack (.NET) - [Serializable] - public class InvalidResultSetAccessException : InvalidDataAccessResourceUsageException, ISerializable - { - #region Fields + #region Fields - /// - /// SQL that led to the problem - /// - private string sql; + /// + /// SQL that led to the problem + /// + private string sql; - #endregion + #endregion - #region Constructor (s) - /// - /// Initializes a new instance of the class. - /// - public InvalidResultSetAccessException() - { - } + #region Constructor (s) - /// - /// Initializes a new instance of the class. - /// - /// A message about the exception. - public InvalidResultSetAccessException(string message): base(message) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// A message about the exception. - /// The inner exception. - public InvalidResultSetAccessException(string message, Exception inner): base(message, inner) - { - } - - - /// - /// Initializes a new instance of the class. - /// - /// name of the current task. - /// The offending SQL statment - /// The root cause. - public InvalidResultSetAccessException(string task, String sql, Exception ex) : base(task + "; invalid ResultSet access for SQL [" + sql + "]; " + ex.Message, ex) - { - this.sql = sql; - } - - /// - protected InvalidResultSetAccessException( SerializationInfo info, StreamingContext context ) : base( info, context ) {} - - #endregion - - #region Properties - - /// - /// Gets the SQL that caused the exception - /// - /// The SQL that caused the exception. - public string Sql - { - get - { - return sql; - } - } - #endregion - - #region Methods - - #endregion - - #region ISerializable Members - - /// - /// When overridden in a derived class, sets the - /// with information about the exception. - /// - /// The that holds the serialized object data about the exception being thrown. - /// The that contains contextual information about the source or destination. - /// The parameter is a null reference ( in Visual Basic). - public override void GetObjectData(SerializationInfo info, StreamingContext context) - { - info.AddValue( "sql", sql ); - base.GetObjectData( info, context ); - } - - #endregion + /// + /// Initializes a new instance of the class. + /// + public InvalidResultSetAccessException() + { } + + /// + /// Initializes a new instance of the class. + /// + /// A message about the exception. + public InvalidResultSetAccessException(string message) : base(message) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// A message about the exception. + /// The inner exception. + public InvalidResultSetAccessException(string message, Exception inner) : base(message, inner) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// name of the current task. + /// The offending SQL statment + /// The root cause. + public InvalidResultSetAccessException(string task, String sql, Exception ex) : base(task + "; invalid ResultSet access for SQL [" + sql + "]; " + ex.Message, ex) + { + this.sql = sql; + } + + /// + protected InvalidResultSetAccessException(SerializationInfo info, StreamingContext context) : base(info, context) { } + + #endregion + + #region Properties + + /// + /// Gets the SQL that caused the exception + /// + /// The SQL that caused the exception. + public string Sql + { + get + { + return sql; + } + } + + #endregion + + #region Methods + + #endregion + + #region ISerializable Members + + /// + /// When overridden in a derived class, sets the + /// with information about the exception. + /// + /// The that holds the serialized object data about the exception being thrown. + /// The that contains contextual information about the source or destination. + /// The parameter is a null reference ( in Visual Basic). + public override void GetObjectData(SerializationInfo info, StreamingContext context) + { + info.AddValue("sql", sql); + base.GetObjectData(info, context); + } + + #endregion } diff --git a/src/Spring/Spring.Data/Data/Objects/AbstractAdoOperation.cs b/src/Spring/Spring.Data/Data/Objects/AbstractAdoOperation.cs index 2fec9c09..d8b7b94e 100644 --- a/src/Spring/Spring.Data/Data/Objects/AbstractAdoOperation.cs +++ b/src/Spring/Spring.Data/Data/Objects/AbstractAdoOperation.cs @@ -25,306 +25,299 @@ using Spring.Dao; using Spring.Data.Common; using Spring.Objects.Factory; -namespace Spring.Data.Objects +namespace Spring.Data.Objects; + +/// +/// Abstract base class providing common functionality for generic and non +/// generic implementations of "AdoOperation" subclasses. +/// +/// Mark Pollack (.NET) +public abstract class AbstractAdoOperation : IInitializingObject { + #region Logging Definition + + protected readonly ILogger log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + + #endregion + + #region Fields + + private string sql; + + private CommandType commandType = CommandType.Text; + + private IDbParameters declaredParameters; + /// - /// Abstract base class providing common functionality for generic and non - /// generic implementations of "AdoOperation" subclasses. + /// Has this operation been compiled? Compilation means at + /// least checking that a IDbProvider and sql have been provided, + /// but subclasses may also implement their own custom validation. /// - /// Mark Pollack (.NET) - public abstract class AbstractAdoOperation : IInitializingObject + private bool compiled; + + /// + /// Object enabling us to create IDbCommands + /// efficiently, based on this class's declared parameters. + /// + private IDbCommandCreatorFactory commandFactory; + + #endregion + + #region Properties + + /// + /// Gets or sets the type of the command. + /// + /// The type of the command. + public CommandType CommandType { - #region Logging Definition + get { return commandType; } + set { commandType = value; } + } - protected readonly ILogger log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + /// + /// Gets or sets the db provider. + /// + /// The db provider. + public abstract IDbProvider DbProvider + { + get; + set; + } - #endregion - - #region Fields - - private string sql; - - private CommandType commandType = CommandType.Text; - - private IDbParameters declaredParameters; - - - /// - /// Has this operation been compiled? Compilation means at - /// least checking that a IDbProvider and sql have been provided, - /// but subclasses may also implement their own custom validation. - /// - private bool compiled; - - /// - /// Object enabling us to create IDbCommands - /// efficiently, based on this class's declared parameters. - /// - private IDbCommandCreatorFactory commandFactory; - - #endregion - - - #region Properties - - - /// - /// Gets or sets the type of the command. - /// - /// The type of the command. - public CommandType CommandType + /// + /// Gets or sets the SQL to execute + /// + /// The SQL. + public string Sql + { + get { - get { return commandType; } - set { commandType = value; } + return sql; } - - /// - /// Gets or sets the db provider. - /// - /// The db provider. - public abstract IDbProvider DbProvider + set { - get; set; + sql = value; } + } - /// - /// Gets or sets the SQL to execute - /// - /// The SQL. - public string Sql + /// + /// Gets or sets the declared parameters. + /// + /// The declared parameters. + public IDbParameters DeclaredParameters + { + get { - get + return declaredParameters; + } + set + { + if (Compiled) { - return sql; + throw new InvalidDataAccessApiUsageException("Cannot add parameters once operation is compiled"); } - set - { - sql = value; - } - } - /// - /// Gets or sets the declared parameters. - /// - /// The declared parameters. - public IDbParameters DeclaredParameters - { - get - { - return declaredParameters; - } - set - { - if (Compiled) - { - throw new InvalidDataAccessApiUsageException("Cannot add parameters once operation is compiled"); - } - declaredParameters = value; - } - } - - /// - /// Gets a value indicating whether this is compiled. - /// - /// Compilation means that the operation is fully configured, - /// and ready to use. The exact meaning of compilation will vary between subclasses. - /// true if compiled; otherwise, false. - public bool Compiled - { - get { return compiled; } - protected set { compiled = value; } - } - - /// - /// Sets the command timeout for IDbCommands that this AdoTemplate executes. - /// - /// Default is 0, indicating to use the database provider's default. - /// Any timeout specified here will be overridden by the remaining - /// transaction timeout when executing within a transaction that has a - /// timeout specified at the transaction level. - /// - /// The command timeout. - public abstract int CommandTimeout - { - set; - } - - - #endregion - - #region Methods - - /// - /// Ensures compilation if used in an IApplicationContext - /// - public void AfterPropertiesSet() + declaredParameters = value; + } + } + + /// + /// Gets a value indicating whether this is compiled. + /// + /// Compilation means that the operation is fully configured, + /// and ready to use. The exact meaning of compilation will vary between subclasses. + /// true if compiled; otherwise, false. + public bool Compiled + { + get { return compiled; } + protected set { compiled = value; } + } + + /// + /// Sets the command timeout for IDbCommands that this AdoTemplate executes. + /// + /// Default is 0, indicating to use the database provider's default. + /// Any timeout specified here will be overridden by the remaining + /// transaction timeout when executing within a transaction that has a + /// timeout specified at the transaction level. + /// + /// The command timeout. + public abstract int CommandTimeout + { + set; + } + + #endregion + + #region Methods + + /// + /// Ensures compilation if used in an IApplicationContext + /// + public void AfterPropertiesSet() + { + Compile(); + } + + /// + /// Compiles this operation. Ignores subsequent attempts to compile. + /// + public abstract void Compile(); + + /// + /// Check whether this operation has been compiled already; + /// lazily compile it if not already compiled. + /// + /// Automatically called by ValidateParameters and ValidateNamedParameters + protected void CheckCompiled() + { + if (!Compiled) { + log.LogDebug("ADO operation not compiled before execution - invoking compile"); Compile(); } - - /// - /// Compiles this operation. Ignores subsequent attempts to compile. - /// - public abstract void Compile(); - - - - - /// - /// Check whether this operation has been compiled already; - /// lazily compile it if not already compiled. - /// - /// Automatically called by ValidateParameters and ValidateNamedParameters - protected void CheckCompiled() - { - if (!Compiled) - { - log.LogDebug("ADO operation not compiled before execution - invoking compile"); - Compile(); - } - } - - - protected virtual void ValidateParameters(params object[] inParamValues) - { - CheckCompiled(); - int declaredInParameters = 0; - if (DeclaredParameters != null) - { - for (int i = 0; i < declaredParameters.Count; i++) - { - IDataParameter declaredParameter = DeclaredParameters[i]; - if (IsInputParameter(declaredParameter)) - { - declaredInParameters++; - } - } - } - - if (inParamValues != null) - { - if (DeclaredParameters == null) - { - throw new InvalidDataAccessApiUsageException( - "Didn't expect any parameters: none were declared"); - } - if (inParamValues.Length < declaredInParameters) - { - throw new InvalidDataAccessApiUsageException( - inParamValues.Length + " parameters were supplied, but " + - declaredInParameters + " in parameters were declared in class [" + - GetType().AssemblyQualifiedName + "]"); - } - if (inParamValues.Length > declaredInParameters) - { - throw new InvalidDataAccessApiUsageException( - inParamValues.Length + " parameters were supplied, but " + - DeclaredParameters.Count + " parameters were declared " + - "in class [" + GetType().AssemblyQualifiedName + "]"); - } - } - else - { - // No parameters were supplied - if (DeclaredParameters != null && !(DeclaredParameters.Count == 0)) - { - throw new InvalidDataAccessApiUsageException( - DeclaredParameters.Count + " parameters must be supplied"); - } - } - } - - protected virtual bool IsInputParameter(IDataParameter parameter) - { - return (parameter.Direction == ParameterDirection.Input - || parameter.Direction == ParameterDirection.InputOutput); - } - - /// - /// Validates the named parameters passed to an AdoTemplate ExecuteXXX method based on - /// declared parameters. - /// - /// - /// Subclasses should invoke this method very every ExecuteXXX method. - /// - /// The parameter dictionary supplied. May by null. - protected virtual void ValidateNamedParameters(IDictionary parameters) - { - CheckCompiled(); - IDictionary paramsToUse = (parameters != null ? parameters : new Hashtable()); - - if (declaredParameters != null) - { - for (int i = 0; i < declaredParameters.Count; i++) - { - IDataParameter declaredParameter = DeclaredParameters[i]; - if (declaredParameter.ParameterName == null) - { - throw new InvalidDataAccessApiUsageException( - "All parameters must have name specified when using the methods " + - "dedicated to named parameter support"); - } - if (IsInputParameter(declaredParameter) && !paramsToUse.Contains(declaredParameter.ParameterName)) - { - throw new InvalidDataAccessApiUsageException( - "The parameter named '" + declaredParameter + - "' was not among the parameters supplied: " + paramsToUse.Keys); - } - } - } - - - if (DeclaredParameters != null && DeclaredParameters.Count > 0) - { - if (DeclaredParameters == null) - { - throw new InvalidDataAccessApiUsageException( - "Didn't expect any parameters: none were declared"); - } - } - else - { - // No parameters were supplied - if (DeclaredParameters != null && !(DeclaredParameters.Count == 0)) - { - throw new InvalidDataAccessApiUsageException( - "Parameters must be supplied"); - } - } - - } - - /// - /// Subclasses must implement to perform their own compilation. - /// Invoked after this class's compilation is complete. - /// Subclasses can assume that SQL has been supplied and that - /// a IDbProvider has been supplied. - /// - protected virtual void CompileInternal() - { - commandFactory = new IDbCommandCreatorFactory(DbProvider, CommandType, Sql, DeclaredParameters); - OnCompileInternal(); - - - } - /// - /// Hook method that subclasses may override to react to compilation. - /// This implementation does nothing. - /// - protected virtual void OnCompileInternal() - { - } - - protected virtual IDbCommandCreator NewCommandCreator(IDictionary inParams) - { - return commandFactory.NewDbCommandCreator(inParams); - } - - protected virtual IDbCommandCreator NewCommandCreatorWithParamValues(params object[] inParams) - { - return commandFactory.NewDbCommandCreatorWithParamValues(inParams); - } - - #endregion } + + protected virtual void ValidateParameters(params object[] inParamValues) + { + CheckCompiled(); + int declaredInParameters = 0; + if (DeclaredParameters != null) + { + for (int i = 0; i < declaredParameters.Count; i++) + { + IDataParameter declaredParameter = DeclaredParameters[i]; + if (IsInputParameter(declaredParameter)) + { + declaredInParameters++; + } + } + } + + if (inParamValues != null) + { + if (DeclaredParameters == null) + { + throw new InvalidDataAccessApiUsageException( + "Didn't expect any parameters: none were declared"); + } + + if (inParamValues.Length < declaredInParameters) + { + throw new InvalidDataAccessApiUsageException( + inParamValues.Length + " parameters were supplied, but " + + declaredInParameters + " in parameters were declared in class [" + + GetType().AssemblyQualifiedName + "]"); + } + + if (inParamValues.Length > declaredInParameters) + { + throw new InvalidDataAccessApiUsageException( + inParamValues.Length + " parameters were supplied, but " + + DeclaredParameters.Count + " parameters were declared " + + "in class [" + GetType().AssemblyQualifiedName + "]"); + } + } + else + { + // No parameters were supplied + if (DeclaredParameters != null && !(DeclaredParameters.Count == 0)) + { + throw new InvalidDataAccessApiUsageException( + DeclaredParameters.Count + " parameters must be supplied"); + } + } + } + + protected virtual bool IsInputParameter(IDataParameter parameter) + { + return (parameter.Direction == ParameterDirection.Input + || parameter.Direction == ParameterDirection.InputOutput); + } + + /// + /// Validates the named parameters passed to an AdoTemplate ExecuteXXX method based on + /// declared parameters. + /// + /// + /// Subclasses should invoke this method very every ExecuteXXX method. + /// + /// The parameter dictionary supplied. May by null. + protected virtual void ValidateNamedParameters(IDictionary parameters) + { + CheckCompiled(); + IDictionary paramsToUse = (parameters != null ? parameters : new Hashtable()); + + if (declaredParameters != null) + { + for (int i = 0; i < declaredParameters.Count; i++) + { + IDataParameter declaredParameter = DeclaredParameters[i]; + if (declaredParameter.ParameterName == null) + { + throw new InvalidDataAccessApiUsageException( + "All parameters must have name specified when using the methods " + + "dedicated to named parameter support"); + } + + if (IsInputParameter(declaredParameter) && !paramsToUse.Contains(declaredParameter.ParameterName)) + { + throw new InvalidDataAccessApiUsageException( + "The parameter named '" + declaredParameter + + "' was not among the parameters supplied: " + paramsToUse.Keys); + } + } + } + + if (DeclaredParameters != null && DeclaredParameters.Count > 0) + { + if (DeclaredParameters == null) + { + throw new InvalidDataAccessApiUsageException( + "Didn't expect any parameters: none were declared"); + } + } + else + { + // No parameters were supplied + if (DeclaredParameters != null && !(DeclaredParameters.Count == 0)) + { + throw new InvalidDataAccessApiUsageException( + "Parameters must be supplied"); + } + } + } + + /// + /// Subclasses must implement to perform their own compilation. + /// Invoked after this class's compilation is complete. + /// Subclasses can assume that SQL has been supplied and that + /// a IDbProvider has been supplied. + /// + protected virtual void CompileInternal() + { + commandFactory = new IDbCommandCreatorFactory(DbProvider, CommandType, Sql, DeclaredParameters); + OnCompileInternal(); + } + + /// + /// Hook method that subclasses may override to react to compilation. + /// This implementation does nothing. + /// + protected virtual void OnCompileInternal() + { + } + + protected virtual IDbCommandCreator NewCommandCreator(IDictionary inParams) + { + return commandFactory.NewDbCommandCreator(inParams); + } + + protected virtual IDbCommandCreator NewCommandCreatorWithParamValues(params object[] inParams) + { + return commandFactory.NewDbCommandCreatorWithParamValues(inParams); + } + + #endregion } diff --git a/src/Spring/Spring.Data/Data/Objects/AdoNonQuery.cs b/src/Spring/Spring.Data/Data/Objects/AdoNonQuery.cs index 1e45aab4..b72933df 100644 --- a/src/Spring/Spring.Data/Data/Objects/AdoNonQuery.cs +++ b/src/Spring/Spring.Data/Data/Objects/AdoNonQuery.cs @@ -19,61 +19,61 @@ #endregion using System.Collections; - using Spring.Data.Common; -namespace Spring.Data.Objects +namespace Spring.Data.Objects; + +/// +/// Encapsulate Command.ExecuteNonQuery operations within a reusable class. +/// +/// Mark Pollack (.NET) +/// The default CommandType is CommandType.Text +public class AdoNonQuery : AdoOperation { - /// - /// Encapsulate Command.ExecuteNonQuery operations within a reusable class. - /// - /// Mark Pollack (.NET) - /// The default CommandType is CommandType.Text - public class AdoNonQuery : AdoOperation - { - #region Constructor (s) + #region Constructor (s) - /// - /// Initializes a new instance of the class. - /// - public AdoNonQuery() - {} + /// + /// Initializes a new instance of the class. + /// + public AdoNonQuery() + { + } - /// - /// Initializes a new instance of the class. - /// - public AdoNonQuery(IDbProvider provider) - : base(provider) - {} + /// + /// Initializes a new instance of the class. + /// + public AdoNonQuery(IDbProvider provider) + : base(provider) + { + } - /// - /// Initializes a new instance of the class. - /// - public AdoNonQuery(IDbProvider dbProvider, string sql) - : base(dbProvider, sql) - {} + /// + /// Initializes a new instance of the class. + /// + public AdoNonQuery(IDbProvider dbProvider, string sql) + : base(dbProvider, sql) + { + } - #endregion + #endregion - #region Properties + #region Properties - #endregion + #endregion - #region Methods + #region Methods - public IDictionary ExecuteNonQuery(params object[] inParameterValues) - { - ValidateParameters(inParameterValues); - return AdoTemplate.ExecuteNonQuery(NewCommandCreatorWithParamValues(inParameterValues)); - } + public IDictionary ExecuteNonQuery(params object[] inParameterValues) + { + ValidateParameters(inParameterValues); + return AdoTemplate.ExecuteNonQuery(NewCommandCreatorWithParamValues(inParameterValues)); + } + public IDictionary ExecuteNonQueryByNamedParam(IDictionary inParams) + { + ValidateNamedParameters(inParams); + return AdoTemplate.ExecuteNonQuery(NewCommandCreator(inParams)); + } - public IDictionary ExecuteNonQueryByNamedParam(IDictionary inParams) - { - ValidateNamedParameters(inParams); - return AdoTemplate.ExecuteNonQuery(NewCommandCreator(inParams)); - } - - #endregion - } + #endregion } diff --git a/src/Spring/Spring.Data/Data/Objects/AdoOperation.cs b/src/Spring/Spring.Data/Data/Objects/AdoOperation.cs index 1898b0d4..591c2478 100644 --- a/src/Spring/Spring.Data/Data/Objects/AdoOperation.cs +++ b/src/Spring/Spring.Data/Data/Objects/AdoOperation.cs @@ -22,154 +22,155 @@ using Spring.Dao; using Spring.Data.Common; using Spring.Data.Core; -namespace Spring.Data.Objects +namespace Spring.Data.Objects; + +/// +/// A "AdoOperation" is a thread-safe, reusable object representing +/// an ADO Query, "NonQuery" (Create, Update, Delete), stored procedure +/// or DataSet manipualtions. +/// +/// +/// Subclasses should set Command Text and add parameters before invoking +/// Compile(). The order in which parameters are added is generally +/// significant when using providers or functionality that do not use +/// named parameters. +/// +/// +/// Mark Pollack (.NET) +public abstract class AdoOperation : AbstractAdoOperation { + #region Fields + + private AdoTemplate adoTemplate = new AdoTemplate(); + + #endregion + + #region Constructor (s) + /// - /// A "AdoOperation" is a thread-safe, reusable object representing - /// an ADO Query, "NonQuery" (Create, Update, Delete), stored procedure - /// or DataSet manipualtions. + /// Initializes a new instance of the class. /// - /// - /// Subclasses should set Command Text and add parameters before invoking - /// Compile(). The order in which parameters are added is generally - /// significant when using providers or functionality that do not use - /// named parameters. - /// + /// A DbProvider, SQL and any parameters must be supplied + /// before invoking the compile method and using this object. /// - /// Mark Pollack (.NET) - public abstract class AdoOperation : AbstractAdoOperation + public AdoOperation() { - #region Fields - - private AdoTemplate adoTemplate = new AdoTemplate(); - - #endregion - - #region Constructor (s) - - /// - /// Initializes a new instance of the class. - /// - /// A DbProvider, SQL and any parameters must be supplied - /// before invoking the compile method and using this object. - /// - public AdoOperation() - { - } - - /// - /// Initializes a new instance of the class. - /// - /// A DbProvider, SQL and any parameters must be supplied - /// before invoking the compile method and using this object. - /// - /// Database provider to use. - public AdoOperation(IDbProvider provider) - : this(provider, null) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// A DbProvider, SQL and any parameters must be supplied - /// before invoking the compile method and using this object. - /// - /// Database provider to use. - /// SQL query or stored procedure name. - public AdoOperation(IDbProvider provider, String sql) - { - //intialized AdoTemplate with the DbProvider - DbProvider = provider; - Sql = sql; - } - - #endregion - - #region Properties - - /// - /// Gets or sets the ADO template. - /// - /// The ADO template. - public AdoTemplate AdoTemplate - { - set - { - if (value == null) - { - throw new ArgumentNullException("AdoTemplate"); - } - adoTemplate = value; - } - get { return adoTemplate; } - } - - /// - /// Gets or sets the db provider. - /// - /// The db provider. - public override IDbProvider DbProvider - { - set - { - adoTemplate.DbProvider = value; - if (DeclaredParameters == null) - { - DeclaredParameters = new DbParameters(value); - } - } - get { return adoTemplate.DbProvider; } - } - - /// - /// Sets the command timeout for IDbCommands that this AdoTemplate executes. - /// - /// Default is 0, indicating to use the database provider's default. - /// Any timeout specified here will be overridden by the remaining - /// transaction timeout when executing within a transaction that has a - /// timeout specified at the transaction level. - /// - /// The command timeout. - public override int CommandTimeout - { - set { adoTemplate.CommandTimeout = value; } - } - - #endregion - - #region Methods - - /// - /// Compiles this operation. Ignores subsequent attempts to compile. - /// - public override void Compile() - { - if (!Compiled) - { - if (Sql == null) - { - throw new InvalidDataAccessApiUsageException("Setting of Sql is required"); - } - if (CommandType == 0) - { - throw new InvalidDataAccessApiUsageException("Setting of CommandType is required"); - } - - try - { - adoTemplate.AfterPropertiesSet(); - } - catch (ArgumentException ex) - { - throw new InvalidDataAccessApiUsageException(ex.Message); - } - - CompileInternal(); - Compiled = true; - } - } - - #endregion } + + /// + /// Initializes a new instance of the class. + /// + /// A DbProvider, SQL and any parameters must be supplied + /// before invoking the compile method and using this object. + /// + /// Database provider to use. + public AdoOperation(IDbProvider provider) + : this(provider, null) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// A DbProvider, SQL and any parameters must be supplied + /// before invoking the compile method and using this object. + /// + /// Database provider to use. + /// SQL query or stored procedure name. + public AdoOperation(IDbProvider provider, String sql) + { + //intialized AdoTemplate with the DbProvider + DbProvider = provider; + Sql = sql; + } + + #endregion + + #region Properties + + /// + /// Gets or sets the ADO template. + /// + /// The ADO template. + public AdoTemplate AdoTemplate + { + set + { + if (value == null) + { + throw new ArgumentNullException("AdoTemplate"); + } + + adoTemplate = value; + } + get { return adoTemplate; } + } + + /// + /// Gets or sets the db provider. + /// + /// The db provider. + public override IDbProvider DbProvider + { + set + { + adoTemplate.DbProvider = value; + if (DeclaredParameters == null) + { + DeclaredParameters = new DbParameters(value); + } + } + get { return adoTemplate.DbProvider; } + } + + /// + /// Sets the command timeout for IDbCommands that this AdoTemplate executes. + /// + /// Default is 0, indicating to use the database provider's default. + /// Any timeout specified here will be overridden by the remaining + /// transaction timeout when executing within a transaction that has a + /// timeout specified at the transaction level. + /// + /// The command timeout. + public override int CommandTimeout + { + set { adoTemplate.CommandTimeout = value; } + } + + #endregion + + #region Methods + + /// + /// Compiles this operation. Ignores subsequent attempts to compile. + /// + public override void Compile() + { + if (!Compiled) + { + if (Sql == null) + { + throw new InvalidDataAccessApiUsageException("Setting of Sql is required"); + } + + if (CommandType == 0) + { + throw new InvalidDataAccessApiUsageException("Setting of CommandType is required"); + } + + try + { + adoTemplate.AfterPropertiesSet(); + } + catch (ArgumentException ex) + { + throw new InvalidDataAccessApiUsageException(ex.Message); + } + + CompileInternal(); + Compiled = true; + } + } + + #endregion } diff --git a/src/Spring/Spring.Data/Data/Objects/AdoQuery.cs b/src/Spring/Spring.Data/Data/Objects/AdoQuery.cs index 6223a666..f334dcff 100644 --- a/src/Spring/Spring.Data/Data/Objects/AdoQuery.cs +++ b/src/Spring/Spring.Data/Data/Objects/AdoQuery.cs @@ -22,86 +22,83 @@ using System.Collections; using Spring.Dao.Support; using Spring.Data.Common; -namespace Spring.Data.Objects +namespace Spring.Data.Objects; + +/// +/// Place together the mapping logic to a plain .NET object +/// for one result set within the same class. +/// +/// Mark Pollack (.NET) +public abstract class AdoQuery : AdoOperation { - /// - /// Place together the mapping logic to a plain .NET object - /// for one result set within the same class. - /// - /// Mark Pollack (.NET) - public abstract class AdoQuery : AdoOperation - { - #region Fields + #region Fields - #endregion + #endregion - #region Constructor (s) - /// - /// Initializes a new instance of the class. - /// - public AdoQuery() - { + #region Constructor (s) - } + /// + /// Initializes a new instance of the class. + /// + public AdoQuery() + { + } - public AdoQuery(IDbProvider provider, string sql) - { - DbProvider = provider; - Sql = sql; - } + public AdoQuery(IDbProvider provider, string sql) + { + DbProvider = provider; + Sql = sql; + } - #endregion + #endregion - #region Properties + #region Properties - #endregion + #endregion - #region Methods + #region Methods - public IList Query() - { - return QueryByNamedParam(null); - } + public IList Query() + { + return QueryByNamedParam(null); + } - public IList QueryByNamedParam(IDictionary inParams) - { - return QueryByNamedParam(inParams, null); - } + public IList QueryByNamedParam(IDictionary inParams) + { + return QueryByNamedParam(inParams, null); + } - public IList QueryByNamedParam(IDictionary inParams, IDictionary returnedParameters) - { - return QueryByNamedParam(inParams, returnedParameters, null); - } + public IList QueryByNamedParam(IDictionary inParams, IDictionary returnedParameters) + { + return QueryByNamedParam(inParams, returnedParameters, null); + } - public IList QueryByNamedParam(IDictionary inParams, IDictionary returnedParameters, IDictionary callingContext) - { - ValidateNamedParameters(inParams); - IRowMapper rowMapper = NewRowMapper(inParams, callingContext); - return AdoTemplate.QueryWithCommandCreator(NewCommandCreator(inParams), rowMapper, returnedParameters); - } + public IList QueryByNamedParam(IDictionary inParams, IDictionary returnedParameters, IDictionary callingContext) + { + ValidateNamedParameters(inParams); + IRowMapper rowMapper = NewRowMapper(inParams, callingContext); + return AdoTemplate.QueryWithCommandCreator(NewCommandCreator(inParams), rowMapper, returnedParameters); + } - public object QueryForObject(IDictionary inParams) - { - IList results = QueryByNamedParam(inParams); - return DataAccessUtils.RequiredUniqueResultSet(results); - } + public object QueryForObject(IDictionary inParams) + { + IList results = QueryByNamedParam(inParams); + return DataAccessUtils.RequiredUniqueResultSet(results); + } - public object QueryForObject(IDictionary inParams, IDictionary returnedParameters) - { - IList results = QueryByNamedParam(inParams, returnedParameters); - return DataAccessUtils.RequiredUniqueResultSet(results); - } + public object QueryForObject(IDictionary inParams, IDictionary returnedParameters) + { + IList results = QueryByNamedParam(inParams, returnedParameters); + return DataAccessUtils.RequiredUniqueResultSet(results); + } - public object QueryForObject(IDictionary inParams, IDictionary returnedParameters, IDictionary callingContext) - { - IList results = QueryByNamedParam(inParams, returnedParameters, callingContext); - return DataAccessUtils.RequiredUniqueResultSet(results); - } + public object QueryForObject(IDictionary inParams, IDictionary returnedParameters, IDictionary callingContext) + { + IList results = QueryByNamedParam(inParams, returnedParameters, callingContext); + return DataAccessUtils.RequiredUniqueResultSet(results); + } + protected abstract IRowMapper NewRowMapper(IDictionary inParams, IDictionary callingContext); - protected abstract IRowMapper NewRowMapper(IDictionary inParams, IDictionary callingContext); - - #endregion - - } + #endregion } diff --git a/src/Spring/Spring.Data/Data/Objects/AdoScalar.cs b/src/Spring/Spring.Data/Data/Objects/AdoScalar.cs index 15069ab2..3e79dfe8 100644 --- a/src/Spring/Spring.Data/Data/Objects/AdoScalar.cs +++ b/src/Spring/Spring.Data/Data/Objects/AdoScalar.cs @@ -19,56 +19,57 @@ #endregion using System.Collections; - using Spring.Data.Common; -namespace Spring.Data.Objects +namespace Spring.Data.Objects; + +/// +/// Encapsulate Command ExecuteScalar operations within a reusable class. +/// +/// The default CommandType is CommandType.Text +/// Mark Pollack (.NET) +public class AdoScalar : AdoOperation { + #region Constructor (s) + /// - /// Encapsulate Command ExecuteScalar operations within a reusable class. + /// Initializes a new instance of the class. /// - /// The default CommandType is CommandType.Text - /// Mark Pollack (.NET) - public class AdoScalar : AdoOperation + public AdoScalar() { - #region Constructor (s) - - /// - /// Initializes a new instance of the class. - /// - public AdoScalar() - {} - - /// - /// Initializes a new instance of the class. - /// - public AdoScalar(IDbProvider provider) - : base(provider) - {} - - /// - /// Initializes a new instance of the class. - /// - public AdoScalar(IDbProvider dbProvider, string sql) - : base(dbProvider, sql) - {} - - #endregion - - #region Methods - - public IDictionary ExecuteScalar(params object[] inParameterValues) - { - ValidateParameters(inParameterValues); - return AdoTemplate.ExecuteScalar(NewCommandCreatorWithParamValues(inParameterValues)); - } - - public IDictionary ExecuteScalarByNamedParam(IDictionary inParams) - { - ValidateNamedParameters(inParams); - return AdoTemplate.ExecuteScalar(NewCommandCreator(inParams)); - } - - #endregion } -} + + /// + /// Initializes a new instance of the class. + /// + public AdoScalar(IDbProvider provider) + : base(provider) + { + } + + /// + /// Initializes a new instance of the class. + /// + public AdoScalar(IDbProvider dbProvider, string sql) + : base(dbProvider, sql) + { + } + + #endregion + + #region Methods + + public IDictionary ExecuteScalar(params object[] inParameterValues) + { + ValidateParameters(inParameterValues); + return AdoTemplate.ExecuteScalar(NewCommandCreatorWithParamValues(inParameterValues)); + } + + public IDictionary ExecuteScalarByNamedParam(IDictionary inParams) + { + ValidateNamedParameters(inParams); + return AdoTemplate.ExecuteScalar(NewCommandCreator(inParams)); + } + + #endregion +} \ No newline at end of file diff --git a/src/Spring/Spring.Data/Data/Objects/Generic/AdoOperation.cs b/src/Spring/Spring.Data/Data/Objects/Generic/AdoOperation.cs index b11f16a5..690c3bba 100644 --- a/src/Spring/Spring.Data/Data/Objects/Generic/AdoOperation.cs +++ b/src/Spring/Spring.Data/Data/Objects/Generic/AdoOperation.cs @@ -21,154 +21,155 @@ using Spring.Dao; using Spring.Data.Common; -namespace Spring.Data.Objects.Generic +namespace Spring.Data.Objects.Generic; + +/// +/// A "AdoOperation" is a thread-safe, reusable object representing +/// an ADO Query, "NonQuery" (Create, Update, Delete), stored procedure +/// or DataSet manipualtions. +/// +/// +/// Subclasses should set Command Text and add parameters before invoking +/// Compile(). The order in which parameters are added is generally +/// significant when using providers or functionality that do not use +/// named parameters. +/// +/// +/// Mark Pollack (.NET) +public abstract class AdoOperation : AbstractAdoOperation { + #region Fields + + private Data.Generic.AdoTemplate adoTemplate = new Data.Generic.AdoTemplate(); + + #endregion + + #region Constructor (s) + /// - /// A "AdoOperation" is a thread-safe, reusable object representing - /// an ADO Query, "NonQuery" (Create, Update, Delete), stored procedure - /// or DataSet manipualtions. + /// Initializes a new instance of the class. /// - /// - /// Subclasses should set Command Text and add parameters before invoking - /// Compile(). The order in which parameters are added is generally - /// significant when using providers or functionality that do not use - /// named parameters. - /// + /// A DbProvider, SQL and any parameters must be supplied + /// before invoking the compile method and using this object. /// - /// Mark Pollack (.NET) - public abstract class AdoOperation : AbstractAdoOperation + public AdoOperation() { - #region Fields - - private Data.Generic.AdoTemplate adoTemplate = new Data.Generic.AdoTemplate(); - - #endregion - - #region Constructor (s) - - /// - /// Initializes a new instance of the class. - /// - /// A DbProvider, SQL and any parameters must be supplied - /// before invoking the compile method and using this object. - /// - public AdoOperation() - { - } - - /// - /// Initializes a new instance of the class. - /// - /// A DbProvider, SQL and any parameters must be supplied - /// before invoking the compile method and using this object. - /// - /// Database provider to use. - public AdoOperation(IDbProvider provider) - : this(provider, null) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// A DbProvider, SQL and any parameters must be supplied - /// before invoking the compile method and using this object. - /// - /// Database provider to use. - /// SQL query or stored procedure name. - public AdoOperation(IDbProvider provider, String sql) - { - //intialized AdoTemplate with the DbProvider - DbProvider = provider; - Sql = sql; - } - - #endregion - - #region Properties - - /// - /// Gets or sets the ADO template. - /// - /// The ADO template. - public Data.Generic.AdoTemplate AdoTemplate - { - set - { - if (value == null) - { - throw new ArgumentNullException("AdoTemplate"); - } - adoTemplate = value; - } - get { return adoTemplate; } - } - - /// - /// Gets or sets the db provider. - /// - /// The db provider. - public override IDbProvider DbProvider - { - set - { - adoTemplate.DbProvider = value; - if (DeclaredParameters == null) - { - DeclaredParameters = new DbParameters(value); - } - } - get { return adoTemplate.DbProvider; } - } - - /// - /// Sets the command timeout for IDbCommands that this AdoTemplate executes. - /// - /// Default is 0, indicating to use the database provider's default. - /// Any timeout specified here will be overridden by the remaining - /// transaction timeout when executing within a transaction that has a - /// timeout specified at the transaction level. - /// - /// The command timeout. - public override int CommandTimeout - { - set { adoTemplate.CommandTimeout = value; } - } - - #endregion - - #region Methods - - /// - /// Compiles this operation. Ignores subsequent attempts to compile. - /// - public override void Compile() - { - if (!Compiled) - { - if (Sql == null) - { - throw new InvalidDataAccessApiUsageException("Setting of Sql is required"); - } - if (CommandType == 0) - { - throw new InvalidDataAccessApiUsageException("Setting of CommandType is required"); - } - - try - { - adoTemplate.AfterPropertiesSet(); - } - catch (ArgumentException ex) - { - throw new InvalidDataAccessApiUsageException(ex.Message); - } - - CompileInternal(); - Compiled = true; - } - } - - #endregion } + + /// + /// Initializes a new instance of the class. + /// + /// A DbProvider, SQL and any parameters must be supplied + /// before invoking the compile method and using this object. + /// + /// Database provider to use. + public AdoOperation(IDbProvider provider) + : this(provider, null) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// A DbProvider, SQL and any parameters must be supplied + /// before invoking the compile method and using this object. + /// + /// Database provider to use. + /// SQL query or stored procedure name. + public AdoOperation(IDbProvider provider, String sql) + { + //intialized AdoTemplate with the DbProvider + DbProvider = provider; + Sql = sql; + } + + #endregion + + #region Properties + + /// + /// Gets or sets the ADO template. + /// + /// The ADO template. + public Data.Generic.AdoTemplate AdoTemplate + { + set + { + if (value == null) + { + throw new ArgumentNullException("AdoTemplate"); + } + + adoTemplate = value; + } + get { return adoTemplate; } + } + + /// + /// Gets or sets the db provider. + /// + /// The db provider. + public override IDbProvider DbProvider + { + set + { + adoTemplate.DbProvider = value; + if (DeclaredParameters == null) + { + DeclaredParameters = new DbParameters(value); + } + } + get { return adoTemplate.DbProvider; } + } + + /// + /// Sets the command timeout for IDbCommands that this AdoTemplate executes. + /// + /// Default is 0, indicating to use the database provider's default. + /// Any timeout specified here will be overridden by the remaining + /// transaction timeout when executing within a transaction that has a + /// timeout specified at the transaction level. + /// + /// The command timeout. + public override int CommandTimeout + { + set { adoTemplate.CommandTimeout = value; } + } + + #endregion + + #region Methods + + /// + /// Compiles this operation. Ignores subsequent attempts to compile. + /// + public override void Compile() + { + if (!Compiled) + { + if (Sql == null) + { + throw new InvalidDataAccessApiUsageException("Setting of Sql is required"); + } + + if (CommandType == 0) + { + throw new InvalidDataAccessApiUsageException("Setting of CommandType is required"); + } + + try + { + adoTemplate.AfterPropertiesSet(); + } + catch (ArgumentException ex) + { + throw new InvalidDataAccessApiUsageException(ex.Message); + } + + CompileInternal(); + Compiled = true; + } + } + + #endregion } diff --git a/src/Spring/Spring.Data/Data/Objects/Generic/AdoQuery.cs b/src/Spring/Spring.Data/Data/Objects/Generic/AdoQuery.cs index 32628423..e958cb90 100644 --- a/src/Spring/Spring.Data/Data/Objects/Generic/AdoQuery.cs +++ b/src/Spring/Spring.Data/Data/Objects/Generic/AdoQuery.cs @@ -22,121 +22,117 @@ using Spring.Dao.Support.Generic; using Spring.Data.Common; using Spring.Data.Generic; -namespace Spring.Data.Objects.Generic +namespace Spring.Data.Objects.Generic; + +/// +/// Place together the mapping logic to a plain .NET object +/// for one result set within the same class. +/// +/// Mark Pollack (.NET) +public abstract class AdoQuery : AdoOperation { - /// - /// Place together the mapping logic to a plain .NET object - /// for one result set within the same class. - /// - /// Mark Pollack (.NET) - public abstract class AdoQuery : AdoOperation - { - #region Fields + #region Fields - #endregion + #endregion - #region Constructor (s) - /// - /// Initializes a new instance of the class. - /// - public AdoQuery() - { + #region Constructor (s) - } + /// + /// Initializes a new instance of the class. + /// + public AdoQuery() + { + } - /// - /// Initializes a new instance of the class. - /// - /// The database provider. - /// The SQL to execute - public AdoQuery(IDbProvider provider, string sql) - { - DbProvider = provider; - Sql = sql; - } + /// + /// Initializes a new instance of the class. + /// + /// The database provider. + /// The SQL to execute + public AdoQuery(IDbProvider provider, string sql) + { + DbProvider = provider; + Sql = sql; + } - #endregion + #endregion - #region Properties + #region Properties - #endregion + #endregion - #region Methods + #region Methods + /// + /// Convenient method to execute query without parameters or calling context. + /// + /// The type parameter for the returned collection + /// List of mapped objects + public IList Query() + { + return QueryByNamedParam(null); + } - /// - /// Convenient method to execute query without parameters or calling context. - /// - /// The type parameter for the returned collection - /// List of mapped objects - public IList Query() - { - return QueryByNamedParam(null); - } + /// + /// Convenient method to execute query with parameters but without calling context. + /// + /// The type parameter for the returned collection + /// The parameters for the query. + /// + public IList QueryByNamedParam(System.Collections.IDictionary inParams) + { + return QueryByNamedParam(inParams, null); + } - /// - /// Convenient method to execute query with parameters but without calling context. - /// - /// The type parameter for the returned collection - /// The parameters for the query. - /// - public IList QueryByNamedParam(System.Collections.IDictionary inParams) - { - return QueryByNamedParam(inParams, null); - } + /// + /// Convenient method to execute query with parameters and access to output parameter values. + /// + /// The type parameter for the returned collection + /// The parameters for the query. + /// The returned output parameters. + /// + public IList QueryByNamedParam(System.Collections.IDictionary inParams, + System.Collections.IDictionary outParams) + { + return QueryByNamedParam(inParams, outParams, null); + } - /// - /// Convenient method to execute query with parameters and access to output parameter values. - /// - /// The type parameter for the returned collection - /// The parameters for the query. - /// The returned output parameters. - /// - public IList QueryByNamedParam(System.Collections.IDictionary inParams, - System.Collections.IDictionary outParams) - { - return QueryByNamedParam(inParams, outParams, null); - } + /// + /// Central execution method. All named parameter execution goes through this method. + /// + /// the type parameter for the returned collection + /// The in params. + /// The out params. + /// The calling context. + /// + public IList QueryByNamedParam(System.Collections.IDictionary inParams, + System.Collections.IDictionary outParams, + System.Collections.IDictionary callingContext) + { + ValidateNamedParameters(inParams); + IRowMapper rowMapper = NewRowMapper(inParams, callingContext); + return AdoTemplate.QueryWithCommandCreator(NewCommandCreator(inParams), rowMapper, outParams); + } - /// - /// Central execution method. All named parameter execution goes through this method. - /// - /// the type parameter for the returned collection - /// The in params. - /// The out params. - /// The calling context. - /// - public IList QueryByNamedParam(System.Collections.IDictionary inParams, - System.Collections.IDictionary outParams, - System.Collections.IDictionary callingContext) - { - ValidateNamedParameters(inParams); - IRowMapper rowMapper = NewRowMapper(inParams, callingContext); - return AdoTemplate.QueryWithCommandCreator(NewCommandCreator(inParams), rowMapper, outParams); - } + public T QueryForObject(System.Collections.IDictionary inParams) + { + IList results = QueryByNamedParam(inParams); + return DataAccessUtils.RequiredUniqueResultSet(results); + } - public T QueryForObject(System.Collections.IDictionary inParams) - { - IList results = QueryByNamedParam(inParams); - return DataAccessUtils.RequiredUniqueResultSet(results); - } + public T QueryForObject(System.Collections.IDictionary inParams, System.Collections.IDictionary returnedParameters) + { + IList results = QueryByNamedParam(inParams, returnedParameters); + return DataAccessUtils.RequiredUniqueResultSet(results); + } - public T QueryForObject(System.Collections.IDictionary inParams, System.Collections.IDictionary returnedParameters) - { - IList results = QueryByNamedParam(inParams, returnedParameters); - return DataAccessUtils.RequiredUniqueResultSet(results); - } + public T QueryForObject(System.Collections.IDictionary inParams, System.Collections.IDictionary returnedParameters, System.Collections.IDictionary callingContext) + { + IList results = QueryByNamedParam(inParams, returnedParameters, callingContext); + return DataAccessUtils.RequiredUniqueResultSet(results); + } - public T QueryForObject(System.Collections.IDictionary inParams, System.Collections.IDictionary returnedParameters, System.Collections.IDictionary callingContext) - { - IList results = QueryByNamedParam(inParams, returnedParameters, callingContext); - return DataAccessUtils.RequiredUniqueResultSet(results); - } + protected abstract IRowMapper NewRowMapper(System.Collections.IDictionary inParams, System.Collections.IDictionary callingContext); - - protected abstract IRowMapper NewRowMapper(System.Collections.IDictionary inParams, System.Collections.IDictionary callingContext); - - #endregion - - } + #endregion } diff --git a/src/Spring/Spring.Data/Data/Objects/Generic/MappingAdoQuery.cs b/src/Spring/Spring.Data/Data/Objects/Generic/MappingAdoQuery.cs index 550d9724..03dec96e 100644 --- a/src/Spring/Spring.Data/Data/Objects/Generic/MappingAdoQuery.cs +++ b/src/Spring/Spring.Data/Data/Objects/Generic/MappingAdoQuery.cs @@ -22,46 +22,45 @@ using System.Collections; using System.Data; using Spring.Data.Common; -namespace Spring.Data.Objects.Generic +namespace Spring.Data.Objects.Generic; + +/// +/// Reusable query in which concrete subclasses must implement the +/// MapRow method to map each row of a single result set into an +/// object. +/// +/// +/// Simplifies MappingSqlQueryWithContext API by dropping parameters and +/// context. Most subclasses won't care about parameters. If you don't use +/// contextual information, subclass this instead of MappingSqlQueryWithContext. +/// +/// Mark Pollack (.NET) +public abstract class MappingAdoQuery : MappingAdoQueryWithContext { + #region Constructor (s) + /// - /// Reusable query in which concrete subclasses must implement the - /// MapRow method to map each row of a single result set into an - /// object. + /// Initializes a new instance of the class. /// - /// - /// Simplifies MappingSqlQueryWithContext API by dropping parameters and - /// context. Most subclasses won't care about parameters. If you don't use - /// contextual information, subclass this instead of MappingSqlQueryWithContext. - /// - /// Mark Pollack (.NET) - public abstract class MappingAdoQuery : MappingAdoQueryWithContext + public MappingAdoQuery() { - #region Constructor (s) - - /// - /// Initializes a new instance of the class. - /// - public MappingAdoQuery() - { - } - - public MappingAdoQuery(IDbProvider dbProvider, string sql) : base(dbProvider, sql) - { - } - - #endregion - - #region Methods - - protected override T MapRow(IDataReader reader, int rowNum, IDictionary inParams, - IDictionary callingContext) - { - return MapRow(reader, rowNum); - } - - protected abstract T MapRow(IDataReader reader, int num); - - #endregion } -} + + public MappingAdoQuery(IDbProvider dbProvider, string sql) : base(dbProvider, sql) + { + } + + #endregion + + #region Methods + + protected override T MapRow(IDataReader reader, int rowNum, IDictionary inParams, + IDictionary callingContext) + { + return MapRow(reader, rowNum); + } + + protected abstract T MapRow(IDataReader reader, int num); + + #endregion +} \ No newline at end of file diff --git a/src/Spring/Spring.Data/Data/Objects/Generic/MappingAdoQueryWithContext.cs b/src/Spring/Spring.Data/Data/Objects/Generic/MappingAdoQueryWithContext.cs index f299da13..687170a8 100644 --- a/src/Spring/Spring.Data/Data/Objects/Generic/MappingAdoQueryWithContext.cs +++ b/src/Spring/Spring.Data/Data/Objects/Generic/MappingAdoQueryWithContext.cs @@ -23,71 +23,68 @@ using System.Data; using Spring.Data.Common; using Spring.Data.Generic; -namespace Spring.Data.Objects.Generic +namespace Spring.Data.Objects.Generic; + +/// +/// Reusable query in which concrete subclasses must implement the +/// abstract MapRow method to map each row of a single result set into an +/// object. +/// +/// The MapRow method is also passed the input parameters and +/// a dictionary to provide the method with calling context information +/// (if necessary). If you do not need these additional parameters, use +/// the subclass MappingAdoQuery. +/// +/// Mark Pollack (.NET) +public abstract class MappingAdoQueryWithContext : AdoQuery { - /// - /// Reusable query in which concrete subclasses must implement the - /// abstract MapRow method to map each row of a single result set into an - /// object. - /// - /// The MapRow method is also passed the input parameters and - /// a dictionary to provide the method with calling context information - /// (if necessary). If you do not need these additional parameters, use - /// the subclass MappingAdoQuery. - /// - /// Mark Pollack (.NET) - public abstract class MappingAdoQueryWithContext : AdoQuery - { - #region Constructor (s) - /// - /// Initializes a new instance of the class. - /// - public MappingAdoQueryWithContext() - { + #region Constructor (s) - } + /// + /// Initializes a new instance of the class. + /// + public MappingAdoQueryWithContext() + { + } - public MappingAdoQueryWithContext(IDbProvider dbProvider, string sql) : base(dbProvider, sql) - { + public MappingAdoQueryWithContext(IDbProvider dbProvider, string sql) : base(dbProvider, sql) + { + } - } - #endregion + #endregion - #region Properties + #region Properties - #endregion + #endregion - #region Methods + #region Methods - protected override IRowMapper NewRowMapper(System.Collections.IDictionary inParams, - System.Collections.IDictionary callingContext) + protected override IRowMapper NewRowMapper(System.Collections.IDictionary inParams, + System.Collections.IDictionary callingContext) + { + return new RowMapperImpl(this, inParams, callingContext); + } + + protected abstract T MapRow(IDataReader reader, int rowNum, IDictionary inParams, IDictionary callingContext); + + #endregion + + private class RowMapperImpl : IRowMapper + { + private MappingAdoQueryWithContext outer; + private IDictionary inParams; + private IDictionary callingContext; + + public RowMapperImpl(MappingAdoQueryWithContext mappingAdoQueryWithContext, IDictionary inParams, IDictionary callingContext) { - return new RowMapperImpl(this, inParams, callingContext); + outer = mappingAdoQueryWithContext; + this.inParams = inParams; + this.callingContext = callingContext; } - protected abstract T MapRow(IDataReader reader, int rowNum, IDictionary inParams, IDictionary callingContext); - - - #endregion - - private class RowMapperImpl : IRowMapper + public T MapRow(IDataReader dataReader, int rowNum) { - private MappingAdoQueryWithContext outer; - private IDictionary inParams; - private IDictionary callingContext; - - public RowMapperImpl(MappingAdoQueryWithContext mappingAdoQueryWithContext, IDictionary inParams, IDictionary callingContext) - { - outer = mappingAdoQueryWithContext; - this.inParams = inParams; - this.callingContext = callingContext; - } - - public T MapRow(IDataReader dataReader, int rowNum) - { - return outer.MapRow(dataReader, rowNum, inParams, callingContext); - } + return outer.MapRow(dataReader, rowNum, inParams, callingContext); } - - } + } } diff --git a/src/Spring/Spring.Data/Data/Objects/Generic/StoredProcedure.cs b/src/Spring/Spring.Data/Data/Objects/Generic/StoredProcedure.cs index 41499294..2f9f3584 100644 --- a/src/Spring/Spring.Data/Data/Objects/Generic/StoredProcedure.cs +++ b/src/Spring/Spring.Data/Data/Objects/Generic/StoredProcedure.cs @@ -21,188 +21,187 @@ using Spring.Data.Common; using Spring.Data.Generic; using Spring.Data.Support; -namespace Spring.Data.Objects.Generic +namespace Spring.Data.Objects.Generic; + +/// +/// A superclass for object based abstractions of RDBMS stored procedures. +/// +/// Mark Pollack (.NET) +public abstract class StoredProcedure : AdoOperation { - /// - /// A superclass for object based abstractions of RDBMS stored procedures. - /// - /// Mark Pollack (.NET) - public abstract class StoredProcedure : AdoOperation - { - //A collection of NamedResultSetProcessor + //A collection of NamedResultSetProcessor - private List resultProcessors = new List(); - private bool usingDerivedParameters = false; + private List resultProcessors = new List(); + private bool usingDerivedParameters = false; - /// - /// Initializes a new instance of the class. - /// - public StoredProcedure() - { - CommandType = CommandType.StoredProcedure; - } + /// + /// Initializes a new instance of the class. + /// + public StoredProcedure() + { + CommandType = CommandType.StoredProcedure; + } - public StoredProcedure(IDbProvider dbProvider, string procedureName) : base(dbProvider, procedureName) + public StoredProcedure(IDbProvider dbProvider, string procedureName) : base(dbProvider, procedureName) + { + CommandType = CommandType.StoredProcedure; + } + + public void DeriveParameters() + { + DeriveParameters(false); + } + + public void DeriveParameters(bool includeReturnParameter) + { + //TODO does this account for offsets? + IDataParameter[] derivedParameters = AdoTemplate.DeriveParameters(Sql, includeReturnParameter); + for (int i = 0; i < derivedParameters.Length; i++) { - CommandType = CommandType.StoredProcedure; + IDataParameter parameter = derivedParameters[i]; + DeclaredParameters.AddParameter(parameter); } - public void DeriveParameters() - { - DeriveParameters(false); - } + usingDerivedParameters = true; + } - - public void DeriveParameters(bool includeReturnParameter) + public void AddResultSetExtractor(string name, IResultSetExtractor resultSetExtractor) + { + if (Compiled) { - //TODO does this account for offsets? - IDataParameter[] derivedParameters = AdoTemplate.DeriveParameters(Sql, includeReturnParameter); - for (int i = 0; i < derivedParameters.Length; i++) - { - IDataParameter parameter = derivedParameters[i]; - DeclaredParameters.AddParameter(parameter); - } - usingDerivedParameters = true; + throw new InvalidDataAccessApiUsageException("Cannot add ResultSetExtractors once operation is compiled"); } - public void AddResultSetExtractor(string name, IResultSetExtractor resultSetExtractor) + resultProcessors.Add(new NamedResultSetProcessor(name, resultSetExtractor)); + } + + public void AddRowCallback(string name, IRowCallback rowCallback) + { + if (Compiled) { - if (Compiled) - { - throw new InvalidDataAccessApiUsageException("Cannot add ResultSetExtractors once operation is compiled"); - } - resultProcessors.Add(new NamedResultSetProcessor(name, resultSetExtractor)); + throw new InvalidDataAccessApiUsageException("Cannot add RowCallbacks once operation is compiled"); } - public void AddRowCallback(string name, IRowCallback rowCallback) + resultProcessors.Add(new NamedResultSetProcessor(name, rowCallback)); + } + + public void AddRowMapper(string name, IRowMapper rowMapper) + { + if (Compiled) { - if (Compiled) - { - throw new InvalidDataAccessApiUsageException("Cannot add RowCallbacks once operation is compiled"); - } - resultProcessors.Add(new NamedResultSetProcessor(name, rowCallback)); + throw new InvalidDataAccessApiUsageException("Cannot add RowMappers once operation is compiled"); } - public void AddRowMapper(string name, IRowMapper rowMapper) + resultProcessors.Add(new NamedResultSetProcessor(name, rowMapper)); + } + + public void AddResultSetExtractor(string name, IResultSetExtractor resultSetExtractor) + { + if (Compiled) { - if (Compiled) - { - throw new InvalidDataAccessApiUsageException("Cannot add RowMappers once operation is compiled"); - } - resultProcessors.Add(new NamedResultSetProcessor(name, rowMapper)); + throw new InvalidDataAccessApiUsageException("Cannot add ResultSetExtractors once operation is compiled"); } - public void AddResultSetExtractor(string name, IResultSetExtractor resultSetExtractor) + resultProcessors.Add(new NamedResultSetProcessor(name, resultSetExtractor)); + } + + public void AddRowMapper(string name, IRowMapper rowMapper) + { + if (Compiled) { - if (Compiled) - { - throw new InvalidDataAccessApiUsageException("Cannot add ResultSetExtractors once operation is compiled"); - } - resultProcessors.Add(new NamedResultSetProcessor(name, resultSetExtractor)); + throw new InvalidDataAccessApiUsageException("Cannot add RowMappers once operation is compiled"); } + resultProcessors.Add(new NamedResultSetProcessor(name, rowMapper)); + } - public void AddRowMapper(string name, IRowMapper rowMapper) + protected virtual IDictionary ExecuteScalar(params object[] inParameterValues) + { + ValidateParameters(inParameterValues); + return AdoTemplate.ExecuteScalar(NewCommandCreatorWithParamValues(inParameterValues)); + } + + protected virtual IDictionary ExecuteNonQuery(params object[] inParameterValues) + { + ValidateParameters(inParameterValues); + return AdoTemplate.ExecuteNonQuery(NewCommandCreatorWithParamValues(inParameterValues)); + } + + public IList QueryWithRowMapper(params object[] inParameterValues) + { + ValidateParameters(inParameterValues); + if (resultProcessors.Count == 0) { - if (Compiled) - { - throw new InvalidDataAccessApiUsageException("Cannot add RowMappers once operation is compiled"); - } - resultProcessors.Add(new NamedResultSetProcessor(name,rowMapper)); + throw new InvalidDataAccessApiUsageException("No row mapper is specified."); } - protected virtual IDictionary ExecuteScalar(params object[] inParameterValues) - { - ValidateParameters(inParameterValues); - return AdoTemplate.ExecuteScalar(NewCommandCreatorWithParamValues(inParameterValues)); - } - - protected virtual IDictionary ExecuteNonQuery(params object[] inParameterValues) + NamedResultSetProcessor resultSetProcessor = resultProcessors[0] as NamedResultSetProcessor; + if (resultSetProcessor == null) { - ValidateParameters(inParameterValues); - return AdoTemplate.ExecuteNonQuery(NewCommandCreatorWithParamValues(inParameterValues)); + throw new InvalidDataAccessApiUsageException("No row mapper is specified."); } - - public IList QueryWithRowMapper(params object[] inParameterValues) + if (resultSetProcessor.RowMapper == null) { - ValidateParameters(inParameterValues); - if (resultProcessors.Count == 0) - { - throw new InvalidDataAccessApiUsageException("No row mapper is specified."); - } - - NamedResultSetProcessor resultSetProcessor = resultProcessors[0] as NamedResultSetProcessor; - if (resultSetProcessor == null) - { - throw new InvalidDataAccessApiUsageException("No row mapper is specified."); - } - - if (resultSetProcessor.RowMapper == null) - { - throw new InvalidDataAccessApiUsageException("No row mapper is specified as first result set processor."); - } - IDictionary outParams = Query(inParameterValues); - return outParams[resultSetProcessor.Name] as IList; - + throw new InvalidDataAccessApiUsageException("No row mapper is specified as first result set processor."); } - protected virtual IDictionary Query(params object[] inParameterValues) + IDictionary outParams = Query(inParameterValues); + return outParams[resultSetProcessor.Name] as IList; + } + + protected virtual IDictionary Query(params object[] inParameterValues) + { + ValidateParameters(inParameterValues); + return AdoTemplate.QueryWithCommandCreator(NewCommandCreatorWithParamValues(inParameterValues), resultProcessors); + } + + protected virtual IDictionary Query(params object[] inParameterValues) + { + ValidateParameters(inParameterValues); + return AdoTemplate.QueryWithCommandCreator(NewCommandCreatorWithParamValues(inParameterValues), resultProcessors); + } + + /// + /// Execute the stored procedure using 'ExecuteScalar' + /// + /// Value of input parameters. + /// Dictionary with any named output parameters and the value of the + /// scalar under the key "scalar". + protected virtual IDictionary ExecuteScalarByNamedParam(IDictionary inParams) + { + ValidateNamedParameters(inParams); + return AdoTemplate.ExecuteScalar(NewCommandCreator(inParams)); + } + + protected virtual IDictionary ExecuteNonQueryByNamedParam(IDictionary inParams) + { + ValidateNamedParameters(inParams); + return AdoTemplate.ExecuteNonQuery(NewCommandCreator(inParams)); + } + + protected virtual IDictionary QueryByNamedParam(IDictionary inParams) + { + ValidateNamedParameters(inParams); + return AdoTemplate.QueryWithCommandCreator(NewCommandCreator(inParams), resultProcessors); + } + + protected virtual IDictionary QueryByNamedParam(IDictionary inParams) + { + ValidateNamedParameters(inParams); + return AdoTemplate.QueryWithCommandCreator(NewCommandCreator(inParams), resultProcessors); + } + + protected override bool IsInputParameter(IDataParameter parameter) + { + if (usingDerivedParameters) { - ValidateParameters(inParameterValues); - return AdoTemplate.QueryWithCommandCreator(NewCommandCreatorWithParamValues(inParameterValues), resultProcessors); - + //Can only count Input, derived output parameters are incorrectly classified as input-output + return (parameter.Direction == ParameterDirection.Input); } - - protected virtual IDictionary Query(params object[] inParameterValues) + else { - ValidateParameters(inParameterValues); - return AdoTemplate.QueryWithCommandCreator(NewCommandCreatorWithParamValues(inParameterValues), resultProcessors); - + return base.IsInputParameter(parameter); } - - /// - /// Execute the stored procedure using 'ExecuteScalar' - /// - /// Value of input parameters. - /// Dictionary with any named output parameters and the value of the - /// scalar under the key "scalar". - protected virtual IDictionary ExecuteScalarByNamedParam(IDictionary inParams) - { - ValidateNamedParameters(inParams); - return AdoTemplate.ExecuteScalar(NewCommandCreator(inParams)); - } - - protected virtual IDictionary ExecuteNonQueryByNamedParam(IDictionary inParams) - { - ValidateNamedParameters(inParams); - return AdoTemplate.ExecuteNonQuery(NewCommandCreator(inParams)); - } - - - protected virtual IDictionary QueryByNamedParam(IDictionary inParams) - { - ValidateNamedParameters(inParams); - return AdoTemplate.QueryWithCommandCreator(NewCommandCreator(inParams), resultProcessors); - } - - protected virtual IDictionary QueryByNamedParam(IDictionary inParams) - { - ValidateNamedParameters(inParams); - return AdoTemplate.QueryWithCommandCreator(NewCommandCreator(inParams), resultProcessors); - } - - protected override bool IsInputParameter(IDataParameter parameter) - { - if (usingDerivedParameters) - { - //Can only count Input, derived output parameters are incorrectly classified as input-output - return (parameter.Direction == ParameterDirection.Input); - } - else - { - return base.IsInputParameter(parameter); - } - } - } + } } diff --git a/src/Spring/Spring.Data/Data/Objects/MappingAdoQuery.cs b/src/Spring/Spring.Data/Data/Objects/MappingAdoQuery.cs index c736f55f..aafb6dfe 100644 --- a/src/Spring/Spring.Data/Data/Objects/MappingAdoQuery.cs +++ b/src/Spring/Spring.Data/Data/Objects/MappingAdoQuery.cs @@ -22,49 +22,45 @@ using System.Collections; using System.Data; using Spring.Data.Common; -namespace Spring.Data.Objects +namespace Spring.Data.Objects; + +/// +/// Reusable query in which concrete subclasses must implement the +/// MapRow method to map each row of a single result set into an +/// object. +/// +/// +/// Simplifies MappingAdoQueryWithContext API by dropping parameters and +/// context. Most subclasses won't care about parameters. If you don't use +/// contextual information, subclass this instead of MappingSqlQueryWithContext. +/// +/// Mark Pollack (.NET) +public abstract class MappingAdoQuery : MappingAdoQueryWithContext { - /// - /// Reusable query in which concrete subclasses must implement the - /// MapRow method to map each row of a single result set into an - /// object. - /// - /// - /// Simplifies MappingAdoQueryWithContext API by dropping parameters and - /// context. Most subclasses won't care about parameters. If you don't use - /// contextual information, subclass this instead of MappingSqlQueryWithContext. - /// - /// Mark Pollack (.NET) - public abstract class MappingAdoQuery : MappingAdoQueryWithContext - { - #region Constructor (s) - /// - /// Initializes a new instance of the class. - /// - public MappingAdoQuery() - { + #region Constructor (s) - } + /// + /// Initializes a new instance of the class. + /// + public MappingAdoQuery() + { + } - public MappingAdoQuery(IDbProvider dbProvider, string sql) : base(dbProvider, sql) - { + public MappingAdoQuery(IDbProvider dbProvider, string sql) : base(dbProvider, sql) + { + } - } + #endregion - #endregion + #region Methods - #region Methods + protected override object MapRow(IDataReader reader, int rowNum, IDictionary inParams, + IDictionary callingContext) + { + return MapRow(reader, rowNum); + } - protected override object MapRow(IDataReader reader, int rowNum, IDictionary inParams, - IDictionary callingContext) - { - return MapRow(reader, rowNum); - } + protected abstract object MapRow(IDataReader reader, int num); - protected abstract object MapRow(IDataReader reader, int num); - - #endregion - - - } + #endregion } diff --git a/src/Spring/Spring.Data/Data/Objects/MappingAdoQueryWithContext.cs b/src/Spring/Spring.Data/Data/Objects/MappingAdoQueryWithContext.cs index 61f50264..de4bb8d7 100644 --- a/src/Spring/Spring.Data/Data/Objects/MappingAdoQueryWithContext.cs +++ b/src/Spring/Spring.Data/Data/Objects/MappingAdoQueryWithContext.cs @@ -22,70 +22,67 @@ using System.Collections; using System.Data; using Spring.Data.Common; -namespace Spring.Data.Objects +namespace Spring.Data.Objects; + +/// +/// Reusable query in which concrete subclasses must implement the +/// MapRow method to map each row of a single result set into an +/// object. +/// +/// The MapRow method is also passed the input parameters and +/// a dictionary to provide the method with calling context information +/// (if necessary). If you do not need these additional parameters, use +/// the subclass MappingAdoQuery. +/// +/// Mark Pollack (.NET) +public abstract class MappingAdoQueryWithContext : AdoQuery { - /// - /// Reusable query in which concrete subclasses must implement the - /// MapRow method to map each row of a single result set into an - /// object. - /// - /// The MapRow method is also passed the input parameters and - /// a dictionary to provide the method with calling context information - /// (if necessary). If you do not need these additional parameters, use - /// the subclass MappingAdoQuery. - /// - /// Mark Pollack (.NET) - public abstract class MappingAdoQueryWithContext : AdoQuery - { - #region Constructor (s) - /// - /// Initializes a new instance of the class. - /// - public MappingAdoQueryWithContext() - { + #region Constructor (s) - } + /// + /// Initializes a new instance of the class. + /// + public MappingAdoQueryWithContext() + { + } - public MappingAdoQueryWithContext(IDbProvider dbProvider, string sql) : base(dbProvider, sql) - { + public MappingAdoQueryWithContext(IDbProvider dbProvider, string sql) : base(dbProvider, sql) + { + } - } - #endregion + #endregion - #region Properties + #region Properties - #endregion + #endregion - #region Methods + #region Methods - protected override IRowMapper NewRowMapper(IDictionary inParams, IDictionary callingContext) + protected override IRowMapper NewRowMapper(IDictionary inParams, IDictionary callingContext) + { + return new RowMapperImpl(this, inParams, callingContext); + } + + protected abstract Object MapRow(IDataReader reader, int rowNum, IDictionary inParams, IDictionary callingContext); + + #endregion + + private class RowMapperImpl : IRowMapper + { + private MappingAdoQueryWithContext outer; + private IDictionary inParams; + private IDictionary callingContext; + + public RowMapperImpl(MappingAdoQueryWithContext mappingAdoQueryWithContext, IDictionary inParams, IDictionary callingContext) { - return new RowMapperImpl(this, inParams, callingContext); + outer = mappingAdoQueryWithContext; + this.inParams = inParams; + this.callingContext = callingContext; } - protected abstract Object MapRow(IDataReader reader, int rowNum, IDictionary inParams, IDictionary callingContext); - - - #endregion - - private class RowMapperImpl : IRowMapper + public object MapRow(IDataReader dataReader, int rowNum) { - private MappingAdoQueryWithContext outer; - private IDictionary inParams; - private IDictionary callingContext; - - public RowMapperImpl(MappingAdoQueryWithContext mappingAdoQueryWithContext, IDictionary inParams, IDictionary callingContext) - { - outer = mappingAdoQueryWithContext; - this.inParams = inParams; - this.callingContext = callingContext; - } - - public object MapRow(IDataReader dataReader, int rowNum) - { - return outer.MapRow(dataReader, rowNum, inParams, callingContext); - } + return outer.MapRow(dataReader, rowNum, inParams, callingContext); } - - } + } } diff --git a/src/Spring/Spring.Data/Data/Objects/StoredProcedure.cs b/src/Spring/Spring.Data/Data/Objects/StoredProcedure.cs index 267249f8..2679740a 100644 --- a/src/Spring/Spring.Data/Data/Objects/StoredProcedure.cs +++ b/src/Spring/Spring.Data/Data/Objects/StoredProcedure.cs @@ -20,137 +20,136 @@ using Spring.Dao; using Spring.Data.Common; using Spring.Data.Support; -namespace Spring.Data.Objects +namespace Spring.Data.Objects; + +/// +/// A superclass for object based abstractions of RDBMS stored procedures. +/// +/// Mark Pollack (.NET) +public abstract class StoredProcedure : AdoOperation { - /// - /// A superclass for object based abstractions of RDBMS stored procedures. - /// - /// Mark Pollack (.NET) - public abstract class StoredProcedure : AdoOperation - { - //A collection of NamedResultSetProcessor - private readonly List resultProcessors = new List(); - private bool usingDerivedParameters = false; + //A collection of NamedResultSetProcessor + private readonly List resultProcessors = new List(); + private bool usingDerivedParameters = false; - /// - /// Initializes a new instance of the class. - /// - public StoredProcedure() - { - CommandType = CommandType.StoredProcedure; - } + /// + /// Initializes a new instance of the class. + /// + public StoredProcedure() + { + CommandType = CommandType.StoredProcedure; + } - /// - /// Initializes a new instance of the class. - /// - /// The db provider. - /// Name of the stored procedure. - public StoredProcedure(IDbProvider dbProvider, string procedureName) : base(dbProvider, procedureName) + /// + /// Initializes a new instance of the class. + /// + /// The db provider. + /// Name of the stored procedure. + public StoredProcedure(IDbProvider dbProvider, string procedureName) : base(dbProvider, procedureName) + { + CommandType = CommandType.StoredProcedure; + } + + public void DeriveParameters() + { + DeriveParameters(false); + } + + public void DeriveParameters(bool includeReturnParameter) + { + //TODO does this account for offsets? + IDataParameter[] derivedParameters = AdoTemplate.DeriveParameters(Sql, includeReturnParameter); + for (int i = 0; i < derivedParameters.Length; i++) { - CommandType = CommandType.StoredProcedure; + IDataParameter parameter = derivedParameters[i]; + DeclaredParameters.AddParameter(parameter); } - public void DeriveParameters() - { - DeriveParameters(false); - } + usingDerivedParameters = true; + } - - public void DeriveParameters(bool includeReturnParameter) + public void AddResultSetExtractor(string name, IResultSetExtractor resultSetExtractor) + { + if (Compiled) { - //TODO does this account for offsets? - IDataParameter[] derivedParameters = AdoTemplate.DeriveParameters(Sql, includeReturnParameter); - for (int i = 0; i < derivedParameters.Length; i++) - { - IDataParameter parameter = derivedParameters[i]; - DeclaredParameters.AddParameter(parameter); - } - usingDerivedParameters = true; + throw new InvalidDataAccessApiUsageException("Cannot add ResultSetExtractors once operation is compiled"); } + resultProcessors.Add(new NamedResultSetProcessor(name, resultSetExtractor)); + } - public void AddResultSetExtractor(string name, IResultSetExtractor resultSetExtractor) + public void AddRowCallback(string name, IRowCallback rowCallback) + { + if (Compiled) { - if (Compiled) - { - throw new InvalidDataAccessApiUsageException("Cannot add ResultSetExtractors once operation is compiled"); - } - resultProcessors.Add(new NamedResultSetProcessor(name, resultSetExtractor)); + throw new InvalidDataAccessApiUsageException("Cannot add RowCallbacks once operation is compiled"); } - public void AddRowCallback(string name, IRowCallback rowCallback) + resultProcessors.Add(new NamedResultSetProcessor(name, rowCallback)); + } + + public void AddRowMapper(string name, IRowMapper rowMapper) + { + if (Compiled) { - if (Compiled) - { - throw new InvalidDataAccessApiUsageException("Cannot add RowCallbacks once operation is compiled"); - } - resultProcessors.Add(new NamedResultSetProcessor(name,rowCallback)); + throw new InvalidDataAccessApiUsageException("Cannot add RowMappers once operation is compiled"); } - public void AddRowMapper(string name, IRowMapper rowMapper) + resultProcessors.Add(new NamedResultSetProcessor(name, rowMapper)); + } + + protected virtual IDictionary ExecuteScalar(params object[] inParameterValues) + { + ValidateParameters(inParameterValues); + return AdoTemplate.ExecuteScalar(NewCommandCreatorWithParamValues(inParameterValues)); + } + + protected virtual IDictionary ExecuteNonQuery(params object[] inParameterValues) + { + ValidateParameters(inParameterValues); + return AdoTemplate.ExecuteNonQuery(NewCommandCreatorWithParamValues(inParameterValues)); + } + + protected virtual IDictionary Query(params object[] inParameterValues) + { + ValidateParameters(inParameterValues); + return AdoTemplate.QueryWithCommandCreator(NewCommandCreatorWithParamValues(inParameterValues), resultProcessors); + } + + /// + /// Execute the stored procedure using 'ExecuteScalar' + /// + /// Value of input parameters. + /// Dictionary with any named output parameters and the value of the + /// scalar under the key "scalar". + protected virtual IDictionary ExecuteScalarByNamedParam(IDictionary inParams) + { + ValidateNamedParameters(inParams); + return AdoTemplate.ExecuteScalar(NewCommandCreator(inParams)); + } + + protected virtual IDictionary ExecuteNonQueryByNamedParam(IDictionary inParams) + { + ValidateNamedParameters(inParams); + return AdoTemplate.ExecuteNonQuery(NewCommandCreator(inParams)); + } + + protected virtual IDictionary QueryByNamedParam(IDictionary inParams) + { + ValidateNamedParameters(inParams); + return AdoTemplate.QueryWithCommandCreator(NewCommandCreator(inParams), resultProcessors); + } + + protected override bool IsInputParameter(IDataParameter parameter) + { + if (usingDerivedParameters) { - if (Compiled) - { - throw new InvalidDataAccessApiUsageException("Cannot add RowMappers once operation is compiled"); - } - resultProcessors.Add(new NamedResultSetProcessor(name,rowMapper)); + //Can only count Input, derived output parameters are incorrectly classified as input-output + return (parameter.Direction == ParameterDirection.Input); } - - - protected virtual IDictionary ExecuteScalar(params object[] inParameterValues) - { - ValidateParameters(inParameterValues); - return AdoTemplate.ExecuteScalar(NewCommandCreatorWithParamValues(inParameterValues)); - } - - protected virtual IDictionary ExecuteNonQuery(params object[] inParameterValues) + else { - ValidateParameters(inParameterValues); - return AdoTemplate.ExecuteNonQuery(NewCommandCreatorWithParamValues(inParameterValues)); + return base.IsInputParameter(parameter); } - - protected virtual IDictionary Query(params object[] inParameterValues) - { - ValidateParameters(inParameterValues); - return AdoTemplate.QueryWithCommandCreator(NewCommandCreatorWithParamValues(inParameterValues), resultProcessors); - } - - /// - /// Execute the stored procedure using 'ExecuteScalar' - /// - /// Value of input parameters. - /// Dictionary with any named output parameters and the value of the - /// scalar under the key "scalar". - protected virtual IDictionary ExecuteScalarByNamedParam(IDictionary inParams) - { - ValidateNamedParameters(inParams); - return AdoTemplate.ExecuteScalar(NewCommandCreator(inParams)); - } - - protected virtual IDictionary ExecuteNonQueryByNamedParam(IDictionary inParams) - { - ValidateNamedParameters(inParams); - return AdoTemplate.ExecuteNonQuery(NewCommandCreator(inParams)); - } - - - protected virtual IDictionary QueryByNamedParam(IDictionary inParams) - { - ValidateNamedParameters(inParams); - return AdoTemplate.QueryWithCommandCreator(NewCommandCreator(inParams), resultProcessors); - } - - protected override bool IsInputParameter(IDataParameter parameter) - { - if (usingDerivedParameters) - { - //Can only count Input, derived output parameters are incorrectly classified as input-output - return (parameter.Direction == ParameterDirection.Input); - } - else - { - return base.IsInputParameter(parameter); - } - } - } + } } diff --git a/src/Spring/Spring.Data/Data/ResultSetExtractorDelegate.cs b/src/Spring/Spring.Data/Data/ResultSetExtractorDelegate.cs index fc9f4eda..73a754ad 100644 --- a/src/Spring/Spring.Data/Data/ResultSetExtractorDelegate.cs +++ b/src/Spring/Spring.Data/Data/ResultSetExtractorDelegate.cs @@ -1,14 +1,14 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. - * + * Copyright � 2002-2011 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. @@ -20,21 +20,19 @@ using System.Data; +namespace Spring.Data; -namespace Spring.Data -{ - /// - /// Callback delegate to process all result sets and row in an - /// AdoTemplate query method. - /// - /// - /// Implementations of this delegate perform the work - /// of extracting results but don't need worry about managing - /// ADO.NET resources, such as closing the reader, or transaction management. - /// - /// The IDataReader to extract data from. - /// Implementations should not close this: it will be closed - /// by the AdoTemplate. - /// An arbitrary result object or null if none. - public delegate object ResultSetExtractorDelegate(IDataReader reader); -} +/// +/// Callback delegate to process all result sets and row in an +/// AdoTemplate query method. +/// +/// +/// Implementations of this delegate perform the work +/// of extracting results but don't need worry about managing +/// ADO.NET resources, such as closing the reader, or transaction management. +/// +/// The IDataReader to extract data from. +/// Implementations should not close this: it will be closed +/// by the AdoTemplate. +/// An arbitrary result object or null if none. +public delegate object ResultSetExtractorDelegate(IDataReader reader); diff --git a/src/Spring/Spring.Data/Data/RowCallbackDelegate.cs b/src/Spring/Spring.Data/Data/RowCallbackDelegate.cs index a738162c..0d7688b2 100644 --- a/src/Spring/Spring.Data/Data/RowCallbackDelegate.cs +++ b/src/Spring/Spring.Data/Data/RowCallbackDelegate.cs @@ -1,8 +1,5 @@ - - using System.Data; -namespace Spring.Data -{ - public delegate void RowCallbackDelegate(IDataReader dataReader); -} +namespace Spring.Data; + +public delegate void RowCallbackDelegate(IDataReader dataReader); diff --git a/src/Spring/Spring.Data/Data/RowMapperDelegate.cs b/src/Spring/Spring.Data/Data/RowMapperDelegate.cs index bf314c69..cd300b4b 100644 --- a/src/Spring/Spring.Data/Data/RowMapperDelegate.cs +++ b/src/Spring/Spring.Data/Data/RowMapperDelegate.cs @@ -1,14 +1,14 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. - * + * Copyright � 2002-2011 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. @@ -18,18 +18,15 @@ #endregion - using System.Data; -namespace Spring.Data -{ - /// - /// Callback delegate to process each row of data in a result set to an object. - /// - /// The IDataReader to map - /// the number of the current row. - /// An abrirary object, typically derived from data - /// in the result set. - public delegate object RowMapperDelegate(IDataReader dataReader, int rowNum); +namespace Spring.Data; -} +/// +/// Callback delegate to process each row of data in a result set to an object. +/// +/// The IDataReader to map +/// the number of the current row. +/// An abrirary object, typically derived from data +/// in the result set. +public delegate object RowMapperDelegate(IDataReader dataReader, int rowNum); diff --git a/src/Spring/Spring.Data/Data/Support/AdoTransactionObjectSupport.cs b/src/Spring/Spring.Data/Data/Support/AdoTransactionObjectSupport.cs index 467d4a0c..2017c02c 100644 --- a/src/Spring/Spring.Data/Data/Support/AdoTransactionObjectSupport.cs +++ b/src/Spring/Spring.Data/Data/Support/AdoTransactionObjectSupport.cs @@ -22,132 +22,129 @@ using System.Data; using Spring.Transaction; using Spring.Transaction.Support; -namespace Spring.Data.Support +namespace Spring.Data.Support; + +/// +/// Convenient base class for ADO.NET transaction aware objects. +/// +/// +/// Can contain a ConnectionHolder object. +/// +/// Mark Pollack (.NET) +public abstract class AdoTransactionObjectSupport : ISavepointManager, ISmartTransactionObject { + #region Fields + + private ConnectionHolder connectionHolder; + + private IsolationLevel previousIsolationLevel; + + private bool savepointAllowed; + + #endregion + + #region Properties + + public ConnectionHolder ConnectionHolder + { + get { return connectionHolder; } + set { connectionHolder = value; } + } + + public bool HasConnectionHolder + { + get { return (connectionHolder != null); } + } + + public IsolationLevel PreviousIsolationLevel + { + get { return previousIsolationLevel; } + set { previousIsolationLevel = value; } + } + + public bool SavepointAllowed + { + get { return savepointAllowed; } + set { savepointAllowed = value; } + } + /// - /// Convenient base class for ADO.NET transaction aware objects. + /// Return whether the transaction is internally marked as rollback-only. + /// + /// + /// True of the transaction is marked as rollback-only. + public abstract bool RollbackOnly { get; } + + #endregion + + /// + /// Create a new savepoint. + /// + /// + /// The name of the savepoint to create. + /// + /// + /// You can roll back to a specific savepoint + /// via , + /// and explicitly release a savepoint that you don't need anymore via + /// . + ///

+ /// Note that most transaction managers will automatically release + /// savepoints at transaction completion. + ///

+ ///
+ /// + /// If the savepoint could not be created, + /// either because the backend does not support it or because the + /// transaction is not in an appropriate state. + /// + /// + /// A savepoint object, to be passed into + /// + /// or . + /// + public virtual void CreateSavepoint(string savepointName) + { + throw new NestedTransactionNotSupportedException( + "Cannot create a nested transaction because savepoints have not been implemented in the metadata for the DbProvider."); + } + + /// + /// Roll back to the given savepoint. /// /// - /// Can contain a ConnectionHolder object. + /// The savepoint will be automatically released afterwards. /// - /// Mark Pollack (.NET) - public abstract class AdoTransactionObjectSupport : ISavepointManager, ISmartTransactionObject + /// The savepoint to roll back to. + /// + /// If the rollback failed. + /// + public virtual void RollbackToSavepoint(string savepoint) { - #region Fields + throw new NestedTransactionNotSupportedException( + "Cannot rollback to a savepoint in a nested transaction because savepoints have not been implemented in the metadata for the DbProvider."); + } - private ConnectionHolder connectionHolder; - - private IsolationLevel previousIsolationLevel; - - private bool savepointAllowed; - - #endregion - - #region Properties - - public ConnectionHolder ConnectionHolder - { - get { return connectionHolder; } - set { connectionHolder = value; } - } - - public bool HasConnectionHolder - { - get { return (connectionHolder != null); } - } - - public IsolationLevel PreviousIsolationLevel - { - get { return previousIsolationLevel; } - set { previousIsolationLevel = value; } - } - - public bool SavepointAllowed - { - get { return savepointAllowed; } - set { savepointAllowed = value; } - } - - /// - /// Return whether the transaction is internally marked as rollback-only. - /// - /// - /// True of the transaction is marked as rollback-only. - public abstract bool RollbackOnly { get; } - - #endregion - - /// - /// Create a new savepoint. - /// - /// - /// The name of the savepoint to create. - /// - /// - /// You can roll back to a specific savepoint - /// via , - /// and explicitly release a savepoint that you don't need anymore via - /// . - ///

- /// Note that most transaction managers will automatically release - /// savepoints at transaction completion. - ///

- ///
- /// - /// If the savepoint could not be created, - /// either because the backend does not support it or because the - /// transaction is not in an appropriate state. - /// - /// - /// A savepoint object, to be passed into - /// - /// or . - /// - public virtual void CreateSavepoint(string savepointName) - { - throw new NestedTransactionNotSupportedException( - "Cannot create a nested transaction because savepoints have not been implemented in the metadata for the DbProvider."); - } - - /// - /// Roll back to the given savepoint. - /// - /// - /// The savepoint will be automatically released afterwards. - /// - /// The savepoint to roll back to. - /// - /// If the rollback failed. - /// - public virtual void RollbackToSavepoint(string savepoint) - { - throw new NestedTransactionNotSupportedException( - "Cannot rollback to a savepoint in a nested transaction because savepoints have not been implemented in the metadata for the DbProvider."); - - } - - /// - /// Explicitly release the given savepoint. - /// - /// - ///

- /// Note that most transaction managers will automatically release - /// savepoints at transaction completion. - ///

- ///

- /// Implementations should fail as silently as possible if - /// proper resource cleanup will still happen at transaction completion. - ///

- ///
- /// The savepoint to release. - /// - /// If the release failed. - /// - public virtual void ReleaseSavepoint(string savepoint) - { - throw new NestedTransactionNotSupportedException( - "Cannot release a savepoint in a nested transaction because savepoints have not been implemented in the metadata for the DbProvider."); - - } + /// + /// Explicitly release the given savepoint. + /// + /// + ///

+ /// Note that most transaction managers will automatically release + /// savepoints at transaction completion. + ///

+ ///

+ /// Implementations should fail as silently as possible if + /// proper resource cleanup will still happen at transaction completion. + ///

+ ///
+ /// The savepoint to release. + /// + /// If the release failed. + /// + public virtual void ReleaseSavepoint(string savepoint) + { + throw new NestedTransactionNotSupportedException( + "Cannot release a savepoint in a nested transaction because savepoints have not been implemented in the metadata for the DbProvider."); } } diff --git a/src/Spring/Spring.Data/Data/Support/AdoUtils.cs b/src/Spring/Spring.Data/Data/Support/AdoUtils.cs index 6e2c1e37..6c41c5cf 100644 --- a/src/Spring/Spring.Data/Data/Support/AdoUtils.cs +++ b/src/Spring/Spring.Data/Data/Support/AdoUtils.cs @@ -1,88 +1,88 @@ using System.Data; using Microsoft.Extensions.Logging; -namespace Spring.Data.Support +namespace Spring.Data.Support; + +/// +/// Summary description for AdoUtils. +/// +public abstract class AdoUtils { - /// - /// Summary description for AdoUtils. - /// - public abstract class AdoUtils + #region Logging + + private static readonly ILogger LOG = LogManager.GetLogger(typeof(AdoUtils)); + + #endregion + + #region Constants + + /// + /// Order value for TransactionSynchronization objects that clean up + /// ADO.NET Connections. + /// + public static readonly int CONNECTION_SYNCHRONIZATION_ORDER = 1000; + + #endregion + + /// + /// Property dispose of the command. Useful in finally or catch blocks. + /// + /// command to dispose + public static void DisposeCommand(IDbCommand command) { - #region Logging - - private static readonly ILogger LOG = LogManager.GetLogger(typeof (AdoUtils)); - - #endregion - - #region Constants - - /// - /// Order value for TransactionSynchronization objects that clean up - /// ADO.NET Connections. - /// - public static readonly int CONNECTION_SYNCHRONIZATION_ORDER = 1000; - - #endregion - /// - /// Property dispose of the command. Useful in finally or catch blocks. - /// - /// command to dispose - public static void DisposeCommand(IDbCommand command) + if (command != null) { - if (command != null) - { - DoDisposeCommand(command); - } + DoDisposeCommand(command); + } + } + + public static void DisposeDataAdapterCommands(IDbDataAdapter adapter) + { + if (adapter.SelectCommand != null) + { + DoDisposeCommand(adapter.SelectCommand); } - - public static void DisposeDataAdapterCommands(IDbDataAdapter adapter) + if (adapter.InsertCommand != null) { - if (adapter.SelectCommand != null) - { - DoDisposeCommand(adapter.SelectCommand); - } - if (adapter.InsertCommand != null) - { - DoDisposeCommand(adapter.InsertCommand); - } - if (adapter.UpdateCommand != null) - { - DoDisposeCommand(adapter.UpdateCommand); - } - if (adapter.DeleteCommand != null) - { - DoDisposeCommand(adapter.DeleteCommand); - } - - } - public static void CloseReader(IDataReader reader) - { - if (reader != null) - { - try - { - reader.Close(); - } - catch (Exception e) - { - LOG.LogWarning(e, "Could not close IDataRader"); - } - } + DoDisposeCommand(adapter.InsertCommand); } - private static void DoDisposeCommand(IDbCommand command) + if (adapter.UpdateCommand != null) + { + DoDisposeCommand(adapter.UpdateCommand); + } + + if (adapter.DeleteCommand != null) + { + DoDisposeCommand(adapter.DeleteCommand); + } + } + + public static void CloseReader(IDataReader reader) + { + if (reader != null) { try { - command.Dispose(); + reader.Close(); } catch (Exception e) { - LOG.LogWarning(e, "Could not dispose of command"); + LOG.LogWarning(e, "Could not close IDataRader"); } } - } + private static void DoDisposeCommand(IDbCommand command) + { + try + { + command.Dispose(); + } + catch (Exception e) + { + LOG.LogWarning(e, "Could not dispose of command"); + } + } } diff --git a/src/Spring/Spring.Data/Data/Support/ConnectionHolder.cs b/src/Spring/Spring.Data/Data/Support/ConnectionHolder.cs index e97a3fb5..c96dfc27 100644 --- a/src/Spring/Spring.Data/Data/Support/ConnectionHolder.cs +++ b/src/Spring/Spring.Data/Data/Support/ConnectionHolder.cs @@ -1,72 +1,70 @@ using System.Data; using Spring.Transaction.Support; -namespace Spring.Data.Support +namespace Spring.Data.Support; + +/// +/// Connection holder, wrapping a ADO.NET connection and transaction. +/// +/// AdoTransactionManager binds instances of this class to the +/// thread for a given DbProvider. +/// Jurgen Hoeller +/// Mark Pollack (.NET) +public class ConnectionHolder : ResourceHolderSupport { - /// - /// Connection holder, wrapping a ADO.NET connection and transaction. - /// - /// AdoTransactionManager binds instances of this class to the - /// thread for a given DbProvider. - /// Jurgen Hoeller - /// Mark Pollack (.NET) - public class ConnectionHolder : ResourceHolderSupport - { - private IDbConnection currentConnection; + private IDbConnection currentConnection; - private IDbTransaction currentTransaction; + private IDbTransaction currentTransaction; - private bool transactionActive = false; + private bool transactionActive = false; - /// - /// Create a new ConnectionHolder - /// - /// The connection to hold - /// The transaction to hold - public ConnectionHolder(IDbConnection conn, IDbTransaction transaction) - { - //TODO assert conn is not null. - currentConnection = conn; - currentTransaction = transaction; - } + /// + /// Create a new ConnectionHolder + /// + /// The connection to hold + /// The transaction to hold + public ConnectionHolder(IDbConnection conn, IDbTransaction transaction) + { + //TODO assert conn is not null. + currentConnection = conn; + currentTransaction = transaction; + } - public IDbConnection Connection + public IDbConnection Connection + { + get { - get - { - return currentConnection; - } - set - { - currentConnection = value; - } - + return currentConnection; } - - public IDbTransaction Transaction - { - get { return currentTransaction; } - set { currentTransaction = value; } - } - - public bool HasConnection + set { - get - { - return (currentConnection != null); - } + currentConnection = value; } + } - public bool TransactionActive - { - get { return transactionActive; } - set { transactionActive = value; } - } + public IDbTransaction Transaction + { + get { return currentTransaction; } + set { currentTransaction = value; } + } - public override void Clear() + public bool HasConnection + { + get { - base.Clear(); - transactionActive = false; + return (currentConnection != null); } - } + } + + public bool TransactionActive + { + get { return transactionActive; } + set { transactionActive = value; } + } + + public override void Clear() + { + base.Clear(); + transactionActive = false; + } } diff --git a/src/Spring/Spring.Data/Data/Support/ConnectionSynchronization.cs b/src/Spring/Spring.Data/Data/Support/ConnectionSynchronization.cs index 7cc36bff..78be6c07 100644 --- a/src/Spring/Spring.Data/Data/Support/ConnectionSynchronization.cs +++ b/src/Spring/Spring.Data/Data/Support/ConnectionSynchronization.cs @@ -1,129 +1,127 @@ using Spring.Data.Common; using Spring.Transaction.Support; -namespace Spring.Data.Support +namespace Spring.Data.Support; + +/// +/// Callback for resource cleanup at end of transaction. +/// +public class ConnectionSynchronization : TransactionSynchronizationAdapter { - /// - /// Callback for resource cleanup at end of transaction. - /// - public class ConnectionSynchronization : TransactionSynchronizationAdapter - { - - private ConnectionHolder connectionHolder; + private ConnectionHolder connectionHolder; - private IDbProvider dbProvider; + private IDbProvider dbProvider; - private bool holderActive = true; + private bool holderActive = true; - private int order; - /// - /// Create a new instance. - /// - /// - /// - public ConnectionSynchronization(ConnectionHolder connHolder, IDbProvider provider) - { - connectionHolder = connHolder; - dbProvider = provider; - order = ConnectionUtils.CONNECTION_SYNCHRONIZATION_ORDER; - } + private int order; + /// + /// Create a new instance. + /// + /// + /// + public ConnectionSynchronization(ConnectionHolder connHolder, IDbProvider provider) + { + connectionHolder = connHolder; + dbProvider = provider; + order = ConnectionUtils.CONNECTION_SYNCHRONIZATION_ORDER; + } - /// - /// Compares the current instance with another object of the same type. - /// - /// An object to compare with this instance. - /// - /// The value of the order property. - /// - public override int CompareTo(object obj) + /// + /// Compares the current instance with another object of the same type. + /// + /// An object to compare with this instance. + /// + /// The value of the order property. + /// + public override int CompareTo(object obj) + { + return order; + } + + /// + /// Suspend this synchronization. + /// + /// + ///

+ /// Supposed to unbind resources from + /// + /// if managing any. + ///

+ ///
+ public override void Suspend() + { + if (holderActive) { - return order; + TransactionSynchronizationManager.UnbindResource(dbProvider); + + //TODO do we need to reset the connection inside the conHolder to null? } - /// - /// Suspend this synchronization. - /// - /// - ///

- /// Supposed to unbind resources from - /// - /// if managing any. - ///

- ///
- public override void Suspend() + } + + /// + /// Resume this synchronization. + /// + /// + ///

+ /// Supposed to unbind resources from + /// + /// if managing any. + ///

+ ///
+ public override void Resume() + { + if (holderActive) { - if (holderActive) - { - TransactionSynchronizationManager.UnbindResource(dbProvider); - - //TODO do we need to reset the connection inside the conHolder to null? - } + TransactionSynchronizationManager.BindResource(dbProvider, connectionHolder); } + } - /// - /// Resume this synchronization. - /// - /// - ///

- /// Supposed to unbind resources from - /// - /// if managing any. - ///

- ///
- public override void Resume() + /// + /// Invoked before transaction commit/rollback (after + /// , + /// even if + /// + /// threw an exception). + /// + /// + ///

+ /// Can e.g. perform resource cleanup. + ///

+ ///

+ /// Note that exceptions will get propagated to the commit caller + /// and cause a rollback of the transaction. + ///

+ ///
+ public override void BeforeCompletion() + { + if (connectionHolder.IsOpen) { - if (holderActive) - { - TransactionSynchronizationManager.BindResource(dbProvider, connectionHolder); - } + TransactionSynchronizationManager.UnbindResource(dbProvider); + holderActive = false; + ConnectionUtils.DisposeConnection(connectionHolder.Connection, dbProvider); } + } - /// - /// Invoked before transaction commit/rollback (after - /// , - /// even if - /// - /// threw an exception). - /// - /// - ///

- /// Can e.g. perform resource cleanup. - ///

- ///

- /// Note that exceptions will get propagated to the commit caller - /// and cause a rollback of the transaction. - ///

- ///
- public override void BeforeCompletion() + /// + /// Invoked after transaction commit/rollback. + /// + /// Status according to + /// + /// Can e.g. perform resource cleanup, in this case after transaction completion. + ///

+ /// Note that exceptions will get propagated to the commit or rollback + /// caller, although they will not influence the outcome of the transaction. + ///

+ ///
+ public override void AfterCompletion(TransactionSynchronizationStatus status) + { + if (TransactionSynchronizationManager.HasResource(dbProvider)) { - if (connectionHolder.IsOpen ) - { - TransactionSynchronizationManager.UnbindResource(dbProvider); - holderActive= false; - ConnectionUtils.DisposeConnection(connectionHolder.Connection, dbProvider); - } + TransactionSynchronizationManager.UnbindResource(dbProvider); + holderActive = false; + ConnectionUtils.DisposeConnection(connectionHolder.Connection, dbProvider); } - - /// - /// Invoked after transaction commit/rollback. - /// - /// Status according to - /// - /// Can e.g. perform resource cleanup, in this case after transaction completion. - ///

- /// Note that exceptions will get propagated to the commit or rollback - /// caller, although they will not influence the outcome of the transaction. - ///

- ///
- public override void AfterCompletion(TransactionSynchronizationStatus status) - { - if (TransactionSynchronizationManager.HasResource(dbProvider)) - { - TransactionSynchronizationManager.UnbindResource(dbProvider); - holderActive = false; - ConnectionUtils.DisposeConnection(connectionHolder.Connection, dbProvider); - } - } - - } + } } diff --git a/src/Spring/Spring.Data/Data/Support/ConnectionTxPair.cs b/src/Spring/Spring.Data/Data/Support/ConnectionTxPair.cs index b8b31c30..59badbb6 100644 --- a/src/Spring/Spring.Data/Data/Support/ConnectionTxPair.cs +++ b/src/Spring/Spring.Data/Data/Support/ConnectionTxPair.cs @@ -20,45 +20,44 @@ using System.Data; -namespace Spring.Data.Support +namespace Spring.Data.Support; + +/// +/// A simple holder for the current Connection/Transaction objects +/// to use within a given AdoTemplate Execute operation. Used internally. +/// +public class ConnectionTxPair { + private IDbConnection connection; + private IDbTransaction transaction; + /// - /// A simple holder for the current Connection/Transaction objects - /// to use within a given AdoTemplate Execute operation. Used internally. + /// Initializes a new instance of the class. /// - public class ConnectionTxPair + /// The connection. + /// The transaction. + public ConnectionTxPair(IDbConnection connection, IDbTransaction transaction) { - private IDbConnection connection; - private IDbTransaction transaction; + this.connection = connection; + this.transaction = transaction; + } - /// - /// Initializes a new instance of the class. - /// - /// The connection. - /// The transaction. - public ConnectionTxPair(IDbConnection connection, IDbTransaction transaction) - { - this.connection = connection; - this.transaction = transaction; - } + /// + /// Gets the connection. + /// + /// The connection. + public IDbConnection Connection + { + get { return connection; } + set { connection = value; } + } - /// - /// Gets the connection. - /// - /// The connection. - public IDbConnection Connection - { - get { return connection; } - set { connection = value; } - } - - /// - /// Gets the transaction. - /// - /// The transaction. - public IDbTransaction Transaction - { - get { return transaction; } - } + /// + /// Gets the transaction. + /// + /// The transaction. + public IDbTransaction Transaction + { + get { return transaction; } } } diff --git a/src/Spring/Spring.Data/Data/Support/ConnectionUtils.cs b/src/Spring/Spring.Data/Data/Support/ConnectionUtils.cs index a10e3199..4f354746 100644 --- a/src/Spring/Spring.Data/Data/Support/ConnectionUtils.cs +++ b/src/Spring/Spring.Data/Data/Support/ConnectionUtils.cs @@ -24,222 +24,223 @@ using Spring.Data.Common; using Spring.Transaction.Support; using Spring.Util; -namespace Spring.Data.Support +namespace Spring.Data.Support; + +/// +/// Summary description for DbProviderUtils. +/// +public abstract class ConnectionUtils { + #region Logging + + private static readonly ILogger LOG = LogManager.GetLogger(); + + #endregion + + public static readonly int CONNECTION_SYNCHRONIZATION_ORDER = 1000; + /// - /// Summary description for DbProviderUtils. + /// Dispose of the given Connection, created via the given IDbProvider, + /// if it is not managed externally (that is, not bound to the thread). /// - public abstract class ConnectionUtils + /// The connection to close if necessary. If + /// this is null the call will be ignored. + /// The IDbProvider the connection came from + public static void DisposeConnection(IDbConnection conn, IDbProvider dbProvider) { - #region Logging - - private static readonly ILogger LOG = LogManager.GetLogger(); - - #endregion - - public static readonly int CONNECTION_SYNCHRONIZATION_ORDER = 1000; - /// - /// Dispose of the given Connection, created via the given IDbProvider, - /// if it is not managed externally (that is, not bound to the thread). - /// - /// The connection to close if necessary. If - /// this is null the call will be ignored. - /// The IDbProvider the connection came from - public static void DisposeConnection(IDbConnection conn, IDbProvider dbProvider) + try { - try - { - DoDisposeConnection(conn, dbProvider); - } - catch (Exception e) - { - LOG.LogWarning(e, "Could not close connection"); - } - + DoDisposeConnection(conn, dbProvider); } - private static void DoDisposeConnection(IDbConnection conn, IDbProvider dbProvider) + catch (Exception e) { - if (conn == null) + LOG.LogWarning(e, "Could not close connection"); + } + } + + private static void DoDisposeConnection(IDbConnection conn, IDbProvider dbProvider) + { + if (conn == null) + { + return; + } + + if (dbProvider != null) + { + ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.GetResource(dbProvider); + if (conHolder != null && ConnectionEquals(conHolder.Connection, conn)) { + // It's the transactional connection bound to the thread so don't close it. + conHolder.Released(); return; } - - if (dbProvider != null) - { - ConnectionHolder conHolder = (ConnectionHolder)TransactionSynchronizationManager.GetResource(dbProvider); - if (conHolder != null && ConnectionEquals(conHolder.Connection, conn)) - { - // It's the transactional connection bound to the thread so don't close it. - conHolder.Released(); - return; - } - } - if (LOG.IsEnabled(LogLevel.Debug)) - { - LOG.LogDebug("Disposing of IDbConnection with connection string = [" + dbProvider.ConnectionString + "]"); - } - conn.Dispose(); } - - /// - /// Get a ADO.NET Connection/Transaction Pair for the given IDbProvider. - /// Changes any exception into the Spring hierarchy of generic data access - /// exceptions, simplifying calling code and making any exception that is - /// thrown more meaningful. - /// - /// - /// Is aware of a corresponding Connection/Transaction bound to the current thread, for example - /// when using AdoPlatformTransactionManager. Will bind a IDbConnection to the thread - /// if transaction synchronization is active - /// - /// The provider. - /// A Connection/Transaction pair. - public static ConnectionTxPair GetConnectionTxPair(IDbProvider provider) + if (LOG.IsEnabled(LogLevel.Debug)) { - try - { - return DoGetConnection(provider); - } - catch (Exception e) - { - throw new CannotGetAdoConnectionException("Could not get ADO.NET connection.", e); - } - + LOG.LogDebug("Disposing of IDbConnection with connection string = [" + dbProvider.ConnectionString + "]"); } + conn.Dispose(); + } - /// - /// Get a ADO.NET Connection/Transaction Pair for the given IDbProvider. - /// Same as but throwing original provider - /// exception. - /// - /// - /// Is aware of a corresponding Connection/Transaction bound to the current thread, for example - /// when using AdoPlatformTransactionManager. Will bind a IDbConnection to the thread - /// if transaction synchronization is active - /// - /// The provider. - /// - public static ConnectionTxPair DoGetConnection(IDbProvider provider) + /// + /// Get a ADO.NET Connection/Transaction Pair for the given IDbProvider. + /// Changes any exception into the Spring hierarchy of generic data access + /// exceptions, simplifying calling code and making any exception that is + /// thrown more meaningful. + /// + /// + /// Is aware of a corresponding Connection/Transaction bound to the current thread, for example + /// when using AdoPlatformTransactionManager. Will bind a IDbConnection to the thread + /// if transaction synchronization is active + /// + /// The provider. + /// A Connection/Transaction pair. + public static ConnectionTxPair GetConnectionTxPair(IDbProvider provider) + { + try { - AssertUtils.ArgumentNotNull(provider, "provider"); - ConnectionHolder conHolder = (ConnectionHolder)TransactionSynchronizationManager.GetResource(provider); - if (conHolder != null && (conHolder.HasConnection || conHolder.SynchronizedWithTransaction)) + return DoGetConnection(provider); + } + catch (Exception e) + { + throw new CannotGetAdoConnectionException("Could not get ADO.NET connection.", e); + } + } + + /// + /// Get a ADO.NET Connection/Transaction Pair for the given IDbProvider. + /// Same as but throwing original provider + /// exception. + /// + /// + /// Is aware of a corresponding Connection/Transaction bound to the current thread, for example + /// when using AdoPlatformTransactionManager. Will bind a IDbConnection to the thread + /// if transaction synchronization is active + /// + /// The provider. + /// + public static ConnectionTxPair DoGetConnection(IDbProvider provider) + { + AssertUtils.ArgumentNotNull(provider, "provider"); + ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.GetResource(provider); + if (conHolder != null && (conHolder.HasConnection || conHolder.SynchronizedWithTransaction)) + { + conHolder.Requested(); + if (!conHolder.HasConnection) { - conHolder.Requested(); - if (!conHolder.HasConnection) + if (LOG.IsEnabled(LogLevel.Debug)) { - if (LOG.IsEnabled(LogLevel.Debug)) - { - LOG.LogDebug("Fetching resumed ADO.NET connection from DbProvider"); - } - conHolder.Connection = provider.CreateConnection(); + LOG.LogDebug("Fetching resumed ADO.NET connection from DbProvider"); } - return new ConnectionTxPair(conHolder.Connection, conHolder.Transaction); + + conHolder.Connection = provider.CreateConnection(); } - // Else we either got no holder or an empty thread-bound holder here. - if (LOG.IsEnabled(LogLevel.Debug)) - { - LOG.LogDebug("Fetching Connection from DbProvider"); - } - IDbConnection conn = provider.CreateConnection(); - conn.Open(); - - if (TransactionSynchronizationManager.SynchronizationActive) - { - LOG.LogDebug("Registering transaction synchronization for IDbConnection"); - //Use same connection for further ADO.NET actions with the transaction. - //Thread-bound object will get removed by manager at transaction completion. - - ConnectionHolder holderToUse = conHolder; - if (holderToUse == null) - { - holderToUse = new ConnectionHolder(conn, null); - } - else - { - holderToUse.Connection = conn; - } - holderToUse.Requested(); - TransactionSynchronizationManager.RegisterSynchronization( - new ConnectionSynchronization(holderToUse, provider)); - holderToUse.SynchronizedWithTransaction = true; - if (holderToUse != conHolder) - { - TransactionSynchronizationManager.BindResource(provider, holderToUse); - } - - } - return new ConnectionTxPair(conn, null); + return new ConnectionTxPair(conHolder.Connection, conHolder.Transaction); } - /// - /// Do the connection mgmt. - /// - /// - /// - public static IDbConnection GetConnection(IDbProvider provider) + // Else we either got no holder or an empty thread-bound holder here. + if (LOG.IsEnabled(LogLevel.Debug)) { - AssertUtils.ArgumentNotNull(provider, "provider"); - - return GetConnectionTxPair(provider).Connection; - + LOG.LogDebug("Fetching Connection from DbProvider"); } - private static bool ConnectionEquals(IDbConnection heldCon, IDbConnection passedInCon) + IDbConnection conn = provider.CreateConnection(); + conn.Open(); + + if (TransactionSynchronizationManager.SynchronizationActive) { - return (heldCon == passedInCon || heldCon.Equals(passedInCon) || + LOG.LogDebug("Registering transaction synchronization for IDbConnection"); + //Use same connection for further ADO.NET actions with the transaction. + //Thread-bound object will get removed by manager at transaction completion. + + ConnectionHolder holderToUse = conHolder; + if (holderToUse == null) + { + holderToUse = new ConnectionHolder(conn, null); + } + else + { + holderToUse.Connection = conn; + } + + holderToUse.Requested(); + TransactionSynchronizationManager.RegisterSynchronization( + new ConnectionSynchronization(holderToUse, provider)); + holderToUse.SynchronizedWithTransaction = true; + if (holderToUse != conHolder) + { + TransactionSynchronizationManager.BindResource(provider, holderToUse); + } + } + + return new ConnectionTxPair(conn, null); + } + + /// + /// Do the connection mgmt. + /// + /// + /// + public static IDbConnection GetConnection(IDbProvider provider) + { + AssertUtils.ArgumentNotNull(provider, "provider"); + + return GetConnectionTxPair(provider).Connection; + } + + private static bool ConnectionEquals(IDbConnection heldCon, IDbConnection passedInCon) + { + return (heldCon == passedInCon || heldCon.Equals(passedInCon) || getTargetConnection(heldCon).Equals(passedInCon)); - } + } - private static IDbConnection getTargetConnection(IDbConnection con) + private static IDbConnection getTargetConnection(IDbConnection con) + { + IDbConnection conToUse = con; + /* + while (conToUse is ConnectionProxy) { - IDbConnection conToUse = con; - /* - while (conToUse is ConnectionProxy) - { - conToUse = (ConnectionProxy)conToUse.getTargetConnection(); - } - */ - return conToUse; + conToUse = (ConnectionProxy)conToUse.getTargetConnection(); } + */ + return conToUse; + } - /// - /// Applies the current transaction timeout, if any, to the given ADO.NET IDbCommand object. - /// - /// The command. - /// The db provider. - public static void ApplyTransactionTimeout(IDbCommand command, IDbProvider dbProvider) + /// + /// Applies the current transaction timeout, if any, to the given ADO.NET IDbCommand object. + /// + /// The command. + /// The db provider. + public static void ApplyTransactionTimeout(IDbCommand command, IDbProvider dbProvider) + { + ApplyTransactionTimeout(command, dbProvider, 0); + } + + /// + /// Applies the specified timeout - overridden by the current transaction timeout, if any, to to the + /// given ADO.NET IDb command object. + /// + /// The command. + /// The db provider the command was obtained from. + /// The timeout to apply (or 0 for no timeout outside of a transaction. + public static void ApplyTransactionTimeout(IDbCommand command, IDbProvider dbProvider, int timeout) + { + AssertUtils.ArgumentNotNull(command, "command", "No IDbCommand specified."); + AssertUtils.ArgumentNotNull(dbProvider, "dbProvider", "No IDbProvider specified."); + + ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.GetResource(dbProvider); + if (conHolder != null && conHolder.HasTimeout) { - ApplyTransactionTimeout(command, dbProvider, 0); + // Remaining transaction timeout overrides specified value. + command.CommandTimeout = conHolder.TimeToLiveInSeconds; } - - /// - /// Applies the specified timeout - overridden by the current transaction timeout, if any, to to the - /// given ADO.NET IDb command object. - /// - /// The command. - /// The db provider the command was obtained from. - /// The timeout to apply (or 0 for no timeout outside of a transaction. - public static void ApplyTransactionTimeout(IDbCommand command, IDbProvider dbProvider, int timeout) + else if (timeout != -1) { - AssertUtils.ArgumentNotNull(command, "command", "No IDbCommand specified."); - AssertUtils.ArgumentNotNull(dbProvider, "dbProvider", "No IDbProvider specified."); - - ConnectionHolder conHolder = (ConnectionHolder)TransactionSynchronizationManager.GetResource(dbProvider); - if (conHolder != null && conHolder.HasTimeout) - { - // Remaining transaction timeout overrides specified value. - command.CommandTimeout = conHolder.TimeToLiveInSeconds; - } - else if (timeout != -1) - { - // No current transaction timeout -> apply specified value. 0 = infinite timeout in some drivers. - command.CommandTimeout = timeout; - } - + // No current transaction timeout -> apply specified value. 0 = infinite timeout in some drivers. + command.CommandTimeout = timeout; } } } diff --git a/src/Spring/Spring.Data/Data/Support/DefaultServiceDomainAdapter.cs b/src/Spring/Spring.Data/Data/Support/DefaultServiceDomainAdapter.cs index 3cd327fc..0ad4c54f 100644 --- a/src/Spring/Spring.Data/Data/Support/DefaultServiceDomainAdapter.cs +++ b/src/Spring/Spring.Data/Data/Support/DefaultServiceDomainAdapter.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -20,72 +20,70 @@ using System.EnterpriseServices; -namespace Spring.Data.Support +namespace Spring.Data.Support; + +/// +/// Implementation that delegates to ServiceDomain and ContextUtil for all functionality. +/// +/// Introduced for purposes of unit testing. +/// Mark Pollack (.NET) +public class DefaultServiceDomainAdapter : IServiceDomainAdapter { /// - /// Implementation that delegates to ServiceDomain and ContextUtil for all functionality. + /// Creates the context specified by the ServiceConfig object and pushes it onto the context stack to + /// become the current context. /// - /// Introduced for purposes of unit testing. - /// Mark Pollack (.NET) - public class DefaultServiceDomainAdapter : IServiceDomainAdapter + /// A ServiceConfig that contains the configuration information for the services to be used within the enclosed code. + public void Enter(SimpleServiceConfig config) { + ServiceConfig serviceConfig = config.CreateServiceConfig(); + ServiceDomain.Enter(serviceConfig); + } - /// - /// Creates the context specified by the ServiceConfig object and pushes it onto the context stack to - /// become the current context. - /// - /// A ServiceConfig that contains the configuration information for the services to be used within the enclosed code. - public void Enter(SimpleServiceConfig config) - { - ServiceConfig serviceConfig = config.CreateServiceConfig(); - ServiceDomain.Enter(serviceConfig); - } + /// + /// Leaves this ServiceDomain. The current context is then popped from the context stack, and the + /// context that was running when Enter was called becomes the current context. + /// + /// One of the TransactionStatus values + public TransactionStatus Leave() + { + return ServiceDomain.Leave(); + } - /// - /// Leaves this ServiceDomain. The current context is then popped from the context stack, and the - /// context that was running when Enter was called becomes the current context. - /// - /// One of the TransactionStatus values - public TransactionStatus Leave() - { - return ServiceDomain.Leave(); - } + /// + /// Sets the consistent bit and the done bit to true in the COM+ context + /// + public void SetComplete() + { + ContextUtil.SetComplete(); + } - /// - /// Sets the consistent bit and the done bit to true in the COM+ context - /// - public void SetComplete() - { - ContextUtil.SetComplete(); - } + /// + /// Sets the consistent bit to false and the done bit to true in the COM+ context. + /// + public void SetAbort() + { + ContextUtil.SetAbort(); + } - /// - /// Sets the consistent bit to false and the done bit to true in the COM+ context. - /// - public void SetAbort() - { - ContextUtil.SetAbort(); - } + /// + /// Gets or sets the consistent bit in the COM+ context. + /// + /// My transaction vote. + public TransactionVote MyTransactionVote + { + get { return ContextUtil.MyTransactionVote; } + set { ContextUtil.MyTransactionVote = value; } + } - /// - /// Gets or sets the consistent bit in the COM+ context. - /// - /// My transaction vote. - public TransactionVote MyTransactionVote - { - get { return ContextUtil.MyTransactionVote; } - set { ContextUtil.MyTransactionVote = value; } - } - - /// - /// Gets a value indicating whether the current context is transactional. - /// - /// - /// true if this instance is existing transaction; otherwise, false. - /// - public bool IsInTransaction - { - get { return ContextUtil.IsInTransaction; } - } + /// + /// Gets a value indicating whether the current context is transactional. + /// + /// + /// true if this instance is existing transaction; otherwise, false. + /// + public bool IsInTransaction + { + get { return ContextUtil.IsInTransaction; } } } diff --git a/src/Spring/Spring.Data/Data/Support/DefaultTransactionScopeAdapter.cs b/src/Spring/Spring.Data/Data/Support/DefaultTransactionScopeAdapter.cs index cb59a5a7..c5987b04 100644 --- a/src/Spring/Spring.Data/Data/Support/DefaultTransactionScopeAdapter.cs +++ b/src/Spring/Spring.Data/Data/Support/DefaultTransactionScopeAdapter.cs @@ -20,56 +20,55 @@ using System.Transactions; -namespace Spring.Data.Support +namespace Spring.Data.Support; + +/// +/// Uses and System.Transactions.Transaction.Current to provide +/// necessary state and operations to TxScopeTransactionManager. +/// +/// Mark Pollack (.NET) +public class DefaultTransactionScopeAdapter : ITransactionScopeAdapter { - /// - /// Uses and System.Transactions.Transaction.Current to provide - /// necessary state and operations to TxScopeTransactionManager. - /// - /// Mark Pollack (.NET) - public class DefaultTransactionScopeAdapter : ITransactionScopeAdapter + private TransactionScope txScope; + + /// + public void Complete() { - private TransactionScope txScope; + txScope.Complete(); + } - /// - public void Complete() + /// + public void Dispose() + { + txScope.Dispose(); + } + + /// + public bool IsExistingTransaction => System.Transactions.Transaction.Current != null; + + /// + public bool RollbackOnly + { + get { - txScope.Complete(); - } - - /// - public void Dispose() - { - txScope.Dispose(); - } - - /// - public bool IsExistingTransaction => System.Transactions.Transaction.Current != null; - - /// - public bool RollbackOnly - { - get + var transaction = System.Transactions.Transaction.Current; + if (transaction != null && + transaction.TransactionInformation != null && + transaction.TransactionInformation.Status == TransactionStatus.Aborted) { - var transaction = System.Transactions.Transaction.Current; - if (transaction != null && - transaction.TransactionInformation != null && - transaction.TransactionInformation.Status == TransactionStatus.Aborted) - { - return true; - } - - return false; + return true; } - } - /// - public void CreateTransactionScope( - TransactionScopeOption txScopeOption, - TransactionOptions txOptions, - TransactionScopeAsyncFlowOption asyncFlowOption) - { - txScope = new TransactionScope(txScopeOption, txOptions, asyncFlowOption); + return false; } } + + /// + public void CreateTransactionScope( + TransactionScopeOption txScopeOption, + TransactionOptions txOptions, + TransactionScopeAsyncFlowOption asyncFlowOption) + { + txScope = new TransactionScope(txScopeOption, txOptions, asyncFlowOption); + } } \ No newline at end of file diff --git a/src/Spring/Spring.Data/Data/Support/ErrorCodeExceptionTranslator.cs b/src/Spring/Spring.Data/Data/Support/ErrorCodeExceptionTranslator.cs index ec0599ff..d618a5d1 100644 --- a/src/Spring/Spring.Data/Data/Support/ErrorCodeExceptionTranslator.cs +++ b/src/Spring/Spring.Data/Data/Support/ErrorCodeExceptionTranslator.cs @@ -22,320 +22,313 @@ using Microsoft.Extensions.Logging; using Spring.Dao; using Spring.Data.Common; -namespace Spring.Data.Support +namespace Spring.Data.Support; + +/// +/// Implementation of IAdoExceptionTranslator that analyzes provider specific +/// error codes and translates into the DAO exception hierarchy. +/// +/// This class loads the obtains error codes from +/// the IDbProvider metadata property ErrorCodes +/// which defines error code mappings for various providers. +/// +/// Mark Pollack (.NET) +public class ErrorCodeExceptionTranslator : IAdoExceptionTranslator { - /// - /// Implementation of IAdoExceptionTranslator that analyzes provider specific - /// error codes and translates into the DAO exception hierarchy. - /// - /// This class loads the obtains error codes from - /// the IDbProvider metadata property ErrorCodes - /// which defines error code mappings for various providers. - /// - /// Mark Pollack (.NET) - public class ErrorCodeExceptionTranslator : IAdoExceptionTranslator - { - #region Fields + #region Fields - private ErrorCodes errorCodes; + private ErrorCodes errorCodes; - private IAdoExceptionTranslator fallbackTranslator; + private IAdoExceptionTranslator fallbackTranslator; - private IDbProvider dbProvider; + private IDbProvider dbProvider; - #endregion + #endregion - #region Constants + #region Constants - /// - /// The shared log instance for this class (and derived classes). - /// - protected static readonly ILogger log = LogManager.GetLogger(typeof (ErrorCodeExceptionTranslator)); + /// + /// The shared log instance for this class (and derived classes). + /// + protected static readonly ILogger log = LogManager.GetLogger(typeof(ErrorCodeExceptionTranslator)); - #endregion + #endregion - #region Constructor (s) + #region Constructor (s) - /// - /// Initializes a new instance of the class. - /// - /// The data provider. - public ErrorCodeExceptionTranslator(IDbProvider provider) - { - DbProvider = provider; - } + /// + /// Initializes a new instance of the class. + /// + /// The data provider. + public ErrorCodeExceptionTranslator(IDbProvider provider) + { + DbProvider = provider; + } + /// + /// Initializes a new instance of the class. + /// + /// The data provider. + /// The error code collection. + public ErrorCodeExceptionTranslator(IDbProvider provider, ErrorCodes ec) + { + DbProvider = provider; + errorCodes = ec; + } + #endregion - /// - /// Initializes a new instance of the class. - /// - /// The data provider. - /// The error code collection. - public ErrorCodeExceptionTranslator(IDbProvider provider, ErrorCodes ec) + #region Properties + + /// + /// Sets the db provider. + /// + /// The db provider. + public IDbProvider DbProvider + { + set { - DbProvider = provider; - errorCodes = ec; + dbProvider = value; + errorCodes = dbProvider.DbMetadata.ErrorCodes; } + } - - - #endregion - - #region Properties - - /// - /// Sets the db provider. - /// - /// The db provider. - public IDbProvider DbProvider - { - set - { - dbProvider = value; - errorCodes = dbProvider.DbMetadata.ErrorCodes; - - } - } - - /// - /// Gets the error codes for the provider - /// - /// The error codes. - public ErrorCodes ErrorCodes - { - get - { - return errorCodes; - } - } - - #endregion - - /// - /// Gets or sets the fallback translator to use in case error code based translation - /// fails. - /// - /// The fallback translator. - public IAdoExceptionTranslator FallbackTranslator - { - get - { - return fallbackTranslator; - } - set - { - fallbackTranslator = value; - } - } - - - #region Methods - - #endregion - - - /// - /// Translate the given into a generic data access exception. - /// - /// A readable string describing the task being attempted. - /// The SQL query or update that caused the problem. May be null. - /// - /// The encountered by the ADO.NET implementation. - /// - /// - /// A appropriate for the supplied - /// . - /// - public virtual DataAccessException Translate(string task, string sql, Exception exception) + /// + /// Gets the error codes for the provider + /// + /// The error codes. + public ErrorCodes ErrorCodes + { + get { - if (task == null) - { - task = ""; - } - if (sql == null) - { - sql = ""; - } - string errorCode = ExtractErrorCode(exception); + return errorCodes; + } + } - DataAccessException dex = DoTranslate(task, sql, errorCode, exception); - if (dex != null) - { - // Specific exception match found. - return dex; - } - // Looking for a fallback... - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug("Unable to translate exception with errorCode '" + errorCode + "', will use the fallback translator"); - } - IAdoExceptionTranslator fallback = FallbackTranslator; - if (fallback != null) - { - return FallbackTranslator.Translate(task, sql, exception); - } - // We couldn't identify it more precisely. - return new UncategorizedAdoException(task, sql, errorCode, exception); + #endregion + /// + /// Gets or sets the fallback translator to use in case error code based translation + /// fails. + /// + /// The fallback translator. + public IAdoExceptionTranslator FallbackTranslator + { + get + { + return fallbackTranslator; + } + set + { + fallbackTranslator = value; + } + } + #region Methods + + #endregion + + /// + /// Translate the given into a generic data access exception. + /// + /// A readable string describing the task being attempted. + /// The SQL query or update that caused the problem. May be null. + /// + /// The encountered by the ADO.NET implementation. + /// + /// + /// A appropriate for the supplied + /// . + /// + public virtual DataAccessException Translate(string task, string sql, Exception exception) + { + if (task == null) + { + task = ""; } - /// - /// Template method for actually translating the given exception. - /// given into a generic data access exception. - /// - /// A readable string describing the task being attempted. - /// The SQL query or update that caused the problem. May be null. - /// The error code. - /// The encountered by the ADO.NET implementation. - /// - /// A appropriate for the supplied - /// . - /// - /// - /// The passed-in arguments will have been pre-checked. furthermore, this method is allowed to - /// return null to indicate that no exception match has been found and that - /// fallback translation should kick in. - /// - protected virtual DataAccessException DoTranslate(string task, string sql, string errorCode, Exception exception) - { - // First, try custom translation from overridden method. - DataAccessException dex = TranslateException(task, sql, errorCode, exception); - if (dex != null) - { - return dex; - } - - - if (errorCodes != null) - { - - if (errorCode != null) - { - if (Array.IndexOf(errorCodes.BadSqlGrammarCodes, errorCode) >= 0) - { - LogTranslation(task, sql, errorCode, exception, false); - return new BadSqlGrammarException(task, sql, exception); - } - else if (Array.IndexOf(errorCodes.InvalidResultSetAccessCodes, errorCode) >= 0) - { - LogTranslation(task, sql, errorCode, exception, false); - return new InvalidResultSetAccessException(task, sql, exception); - } - else if (Array.IndexOf(errorCodes.DuplicateKeyCodes, errorCode) >= 0) - { - LogTranslation(task, sql, errorCode, exception, false); - return new DuplicateKeyException(task, sql, exception); - } - else if (Array.IndexOf(errorCodes.DataAccessResourceFailureCodes, errorCode) >= 0) - { - LogTranslation(task, sql, errorCode, exception, false); - return new DataAccessResourceFailureException(BuildMessage(task, sql, exception), exception); - } - else if (Array.IndexOf(errorCodes.TransientAccessResourceFailureCodes, errorCode) >= 0) - { - LogTranslation(task, sql, errorCode, exception, false); - return new TransientDataAccessResourceException(BuildMessage(task, sql, exception), exception); - } - else if (Array.IndexOf(errorCodes.PermissionDeniedCodes, errorCode) >= 0) - { - LogTranslation(task, sql, errorCode, exception, false); - return new PermissionDeniedDataAccessException(BuildMessage(task, sql, exception), exception); - } - else if (Array.IndexOf(errorCodes.DataIntegrityViolationCodes, errorCode) >= 0) - { - LogTranslation(task, sql, errorCode, exception, false); - return new DataIntegrityViolationException(BuildMessage(task, sql, exception), exception); - } - else if (Array.IndexOf(errorCodes.CannotAcquireLockCodes, errorCode) >= 0) - { - LogTranslation(task, sql, errorCode, exception, false); - return new CannotAcquireLockException(BuildMessage(task, sql, exception), exception); - } - else if (Array.IndexOf(errorCodes.DeadlockLoserCodes, errorCode) >= 0) - { - LogTranslation(task, sql, errorCode, exception, false); - return new DeadlockLoserDataAccessException(BuildMessage(task, sql, exception), exception); - } - else if (Array.IndexOf(errorCodes.CannotSerializeTransactionCodes, errorCode) >= 0) - { - LogTranslation(task, sql, errorCode, exception, false); - return new CannotSerializeTransactionException(BuildMessage(task, sql, exception), exception); - } - } - } - return null; - } - - /// - /// Subclasses can override this method to attempt a custom mapping from a data access Exception - /// to DataAccessException. - /// - /// Readable text describing the task being attempted. - /// SQL query or update that caused the problem. May be null. - /// The error code extracted from the generic data access exception for - /// a particular provider. - /// The exception thrown from a data access operation. - /// - /// null if no custom translation was possible, otherwise a DataAccessException - /// resulting from custom translation. This exception should include the exception parameter - /// as a nested root cause. This implementation always returns null, meaning that - /// the translator always falls back to the default error codes. - /// - protected virtual DataAccessException TranslateException(string task, string sql, string errorCode, Exception exception) - { - return null; - } - - - /// - /// Builds the message. - /// - /// The task. - /// The SQL. - /// The exception. - /// - protected virtual string BuildMessage(string task, string sql, Exception exception) - { - return task + "; SQL [" + sql + "]; " + exception.Message; - } - - /// - /// Determines whether the specified exception is valid data access exception. - /// - /// The exception. - /// - /// true if is valid data access exception; otherwise, false. - /// - public bool IsValidDataAccessException(Exception e) - { - return dbProvider.IsDataAccessException(e); + if (sql == null) + { + sql = ""; } - /// - /// Logs the translation. - /// - /// The task. - /// The SQL. - /// The error code. - /// The exception. - /// if set to true [b]. - private void LogTranslation(string task, string sql, string errorCode, Exception exception, bool b) - { - if (log.IsEnabled(LogLevel.Debug)) - { - String intro = "Translating"; - log.LogDebug(intro + " ADO exception with error code '" + errorCode - + "', message [" + exception.Message + - "]; SQL was [" + sql + "] for task [" + task + "]"); - } - } + string errorCode = ExtractErrorCode(exception); - private string ExtractErrorCode(Exception exception) - { - // Use provider specific reflection information to extract error code. - return dbProvider.ExtractError(exception); - } - } + DataAccessException dex = DoTranslate(task, sql, errorCode, exception); + if (dex != null) + { + // Specific exception match found. + return dex; + } + + // Looking for a fallback... + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug("Unable to translate exception with errorCode '" + errorCode + "', will use the fallback translator"); + } + + IAdoExceptionTranslator fallback = FallbackTranslator; + if (fallback != null) + { + return FallbackTranslator.Translate(task, sql, exception); + } + + // We couldn't identify it more precisely. + return new UncategorizedAdoException(task, sql, errorCode, exception); + } + + /// + /// Template method for actually translating the given exception. + /// given into a generic data access exception. + /// + /// A readable string describing the task being attempted. + /// The SQL query or update that caused the problem. May be null. + /// The error code. + /// The encountered by the ADO.NET implementation. + /// + /// A appropriate for the supplied + /// . + /// + /// + /// The passed-in arguments will have been pre-checked. furthermore, this method is allowed to + /// return null to indicate that no exception match has been found and that + /// fallback translation should kick in. + /// + protected virtual DataAccessException DoTranslate(string task, string sql, string errorCode, Exception exception) + { + // First, try custom translation from overridden method. + DataAccessException dex = TranslateException(task, sql, errorCode, exception); + if (dex != null) + { + return dex; + } + + if (errorCodes != null) + { + if (errorCode != null) + { + if (Array.IndexOf(errorCodes.BadSqlGrammarCodes, errorCode) >= 0) + { + LogTranslation(task, sql, errorCode, exception, false); + return new BadSqlGrammarException(task, sql, exception); + } + else if (Array.IndexOf(errorCodes.InvalidResultSetAccessCodes, errorCode) >= 0) + { + LogTranslation(task, sql, errorCode, exception, false); + return new InvalidResultSetAccessException(task, sql, exception); + } + else if (Array.IndexOf(errorCodes.DuplicateKeyCodes, errorCode) >= 0) + { + LogTranslation(task, sql, errorCode, exception, false); + return new DuplicateKeyException(task, sql, exception); + } + else if (Array.IndexOf(errorCodes.DataAccessResourceFailureCodes, errorCode) >= 0) + { + LogTranslation(task, sql, errorCode, exception, false); + return new DataAccessResourceFailureException(BuildMessage(task, sql, exception), exception); + } + else if (Array.IndexOf(errorCodes.TransientAccessResourceFailureCodes, errorCode) >= 0) + { + LogTranslation(task, sql, errorCode, exception, false); + return new TransientDataAccessResourceException(BuildMessage(task, sql, exception), exception); + } + else if (Array.IndexOf(errorCodes.PermissionDeniedCodes, errorCode) >= 0) + { + LogTranslation(task, sql, errorCode, exception, false); + return new PermissionDeniedDataAccessException(BuildMessage(task, sql, exception), exception); + } + else if (Array.IndexOf(errorCodes.DataIntegrityViolationCodes, errorCode) >= 0) + { + LogTranslation(task, sql, errorCode, exception, false); + return new DataIntegrityViolationException(BuildMessage(task, sql, exception), exception); + } + else if (Array.IndexOf(errorCodes.CannotAcquireLockCodes, errorCode) >= 0) + { + LogTranslation(task, sql, errorCode, exception, false); + return new CannotAcquireLockException(BuildMessage(task, sql, exception), exception); + } + else if (Array.IndexOf(errorCodes.DeadlockLoserCodes, errorCode) >= 0) + { + LogTranslation(task, sql, errorCode, exception, false); + return new DeadlockLoserDataAccessException(BuildMessage(task, sql, exception), exception); + } + else if (Array.IndexOf(errorCodes.CannotSerializeTransactionCodes, errorCode) >= 0) + { + LogTranslation(task, sql, errorCode, exception, false); + return new CannotSerializeTransactionException(BuildMessage(task, sql, exception), exception); + } + } + } + + return null; + } + + /// + /// Subclasses can override this method to attempt a custom mapping from a data access Exception + /// to DataAccessException. + /// + /// Readable text describing the task being attempted. + /// SQL query or update that caused the problem. May be null. + /// The error code extracted from the generic data access exception for + /// a particular provider. + /// The exception thrown from a data access operation. + /// + /// null if no custom translation was possible, otherwise a DataAccessException + /// resulting from custom translation. This exception should include the exception parameter + /// as a nested root cause. This implementation always returns null, meaning that + /// the translator always falls back to the default error codes. + /// + protected virtual DataAccessException TranslateException(string task, string sql, string errorCode, Exception exception) + { + return null; + } + + /// + /// Builds the message. + /// + /// The task. + /// The SQL. + /// The exception. + /// + protected virtual string BuildMessage(string task, string sql, Exception exception) + { + return task + "; SQL [" + sql + "]; " + exception.Message; + } + + /// + /// Determines whether the specified exception is valid data access exception. + /// + /// The exception. + /// + /// true if is valid data access exception; otherwise, false. + /// + public bool IsValidDataAccessException(Exception e) + { + return dbProvider.IsDataAccessException(e); + } + + /// + /// Logs the translation. + /// + /// The task. + /// The SQL. + /// The error code. + /// The exception. + /// if set to true [b]. + private void LogTranslation(string task, string sql, string errorCode, Exception exception, bool b) + { + if (log.IsEnabled(LogLevel.Debug)) + { + String intro = "Translating"; + log.LogDebug(intro + " ADO exception with error code '" + errorCode + + "', message [" + exception.Message + + "]; SQL was [" + sql + "] for task [" + task + "]"); + } + } + + private string ExtractErrorCode(Exception exception) + { + // Use provider specific reflection information to extract error code. + return dbProvider.ExtractError(exception); + } } diff --git a/src/Spring/Spring.Data/Data/Support/FallbackExceptionTranslator.cs b/src/Spring/Spring.Data/Data/Support/FallbackExceptionTranslator.cs index 458bc844..b173a80e 100644 --- a/src/Spring/Spring.Data/Data/Support/FallbackExceptionTranslator.cs +++ b/src/Spring/Spring.Data/Data/Support/FallbackExceptionTranslator.cs @@ -20,46 +20,43 @@ using Spring.Dao; -namespace Spring.Data.Support +namespace Spring.Data.Support; + +/// +/// Translates all exceptions to an UncategorizedAdoException. +/// +/// +/// This exception translator used when an exception is thrown using the +/// "primary" implementation of IAdoExceptionTranslator, i.e. AdoExceptionTranslator. +/// +/// Mark Pollack (.NET) +public class FallbackExceptionTranslator : IAdoExceptionTranslator { - /// - /// Translates all exceptions to an UncategorizedAdoException. + #region Constructor (s) + + /// + /// Initializes a new instance of the class. /// - /// - /// This exception translator used when an exception is thrown using the - /// "primary" implementation of IAdoExceptionTranslator, i.e. AdoExceptionTranslator. - /// - /// Mark Pollack (.NET) - public class FallbackExceptionTranslator : IAdoExceptionTranslator - { + public FallbackExceptionTranslator() + { + } + #endregion - #region Constructor (s) - /// - /// Initializes a new instance of the class. - /// - public FallbackExceptionTranslator() - { - } - - #endregion - - - /// - /// Translate the given into a generic data access exception. - /// - /// A readable string describing the task being attempted. - /// The SQL query or update that caused the problem. May be null. - /// - /// The encountered by the ADO.NET implementation. - /// - /// - /// A appropriate for the supplied - /// . - /// - public DataAccessException Translate(string task, string sql, Exception exception) - { - return new UncategorizedAdoException(task, sql, "", exception); - } - } + /// + /// Translate the given into a generic data access exception. + /// + /// A readable string describing the task being attempted. + /// The SQL query or update that caused the problem. May be null. + /// + /// The encountered by the ADO.NET implementation. + /// + /// + /// A appropriate for the supplied + /// . + /// + public DataAccessException Translate(string task, string sql, Exception exception) + { + return new UncategorizedAdoException(task, sql, "", exception); + } } diff --git a/src/Spring/Spring.Data/Data/Support/IAdoExceptionTranslator.cs b/src/Spring/Spring.Data/Data/Support/IAdoExceptionTranslator.cs index a7aeadd3..9078a2e0 100644 --- a/src/Spring/Spring.Data/Data/Support/IAdoExceptionTranslator.cs +++ b/src/Spring/Spring.Data/Data/Support/IAdoExceptionTranslator.cs @@ -20,35 +20,34 @@ using Spring.Dao; -namespace Spring.Data.Support +namespace Spring.Data.Support; + +/// +/// Interface to be implemented by classes that can translate between properietary SQL exceptions +/// and Spring.NET's data access strategy-agnostic . +/// +/// +///

+/// Implementations can be generic (for example, ADO.NET Exceptions) or proprietary (for example, +/// using SQL Server or Oracle error codes) for greater precision. +///

+///
+/// Rod Johnson +/// Griffin Caprio (.NET) +/// Mark Pollack +public interface IAdoExceptionTranslator { - /// - /// Interface to be implemented by classes that can translate between properietary SQL exceptions - /// and Spring.NET's data access strategy-agnostic . - /// - /// - ///

- /// Implementations can be generic (for example, ADO.NET Exceptions) or proprietary (for example, - /// using SQL Server or Oracle error codes) for greater precision. - ///

- ///
- /// Rod Johnson - /// Griffin Caprio (.NET) - /// Mark Pollack - public interface IAdoExceptionTranslator - { - /// - /// Translate the given into a generic data access exception. - /// - /// A readable string describing the task being attempted. - /// The SQL query or update that caused the problem. May be null. - /// - /// The encountered by the ADO.NET implementation. - /// - /// - /// A appropriate for the supplied - /// . - /// - DataAccessException Translate( string task, string sql, Exception exception ); - } + /// + /// Translate the given into a generic data access exception. + /// + /// A readable string describing the task being attempted. + /// The SQL query or update that caused the problem. May be null. + /// + /// The encountered by the ADO.NET implementation. + /// + /// + /// A appropriate for the supplied + /// . + /// + DataAccessException Translate(string task, string sql, Exception exception); } diff --git a/src/Spring/Spring.Data/Data/Support/IServiceDomainAdapter.cs b/src/Spring/Spring.Data/Data/Support/IServiceDomainAdapter.cs index 9f9228cd..35c6dbd4 100644 --- a/src/Spring/Spring.Data/Data/Support/IServiceDomainAdapter.cs +++ b/src/Spring/Spring.Data/Data/Support/IServiceDomainAdapter.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -20,53 +20,51 @@ using System.EnterpriseServices; -namespace Spring.Data.Support +namespace Spring.Data.Support; + +/// +/// Provides the necessary transactional state and operations for ServiceDomainTransactionManager to +/// work with ServiceDomain and ContextUtil. +/// +/// Introduced for purposes of unit testing. +/// Mark Pollack (.NET) +public interface IServiceDomainAdapter { /// - /// Provides the necessary transactional state and operations for ServiceDomainTransactionManager to - /// work with ServiceDomain and ContextUtil. + /// Creates the context specified by the ServiceConfig object and pushes it onto the context stack to + /// become the current context. /// - /// Introduced for purposes of unit testing. - /// Mark Pollack (.NET) - public interface IServiceDomainAdapter - { - /// - /// Creates the context specified by the ServiceConfig object and pushes it onto the context stack to - /// become the current context. - /// - /// A ServiceConfig that contains the configuration information for the services to be used within the enclosed code. - void Enter(SimpleServiceConfig config); + /// A ServiceConfig that contains the configuration information for the services to be used within the enclosed code. + void Enter(SimpleServiceConfig config); - /// - /// Leaves this ServiceDomain. The current context is then popped from the context stack, and the - /// context that was running when Enter was called becomes the current context. - /// - /// One of the TransactionStatus values - TransactionStatus Leave(); + /// + /// Leaves this ServiceDomain. The current context is then popped from the context stack, and the + /// context that was running when Enter was called becomes the current context. + /// + /// One of the TransactionStatus values + TransactionStatus Leave(); - /// - /// Sets the consistent bit and the done bit to true in the COM+ context - /// - void SetComplete(); + /// + /// Sets the consistent bit and the done bit to true in the COM+ context + /// + void SetComplete(); - /// - /// Sets the consistent bit to false and the done bit to true in the COM+ context. - /// - void SetAbort(); + /// + /// Sets the consistent bit to false and the done bit to true in the COM+ context. + /// + void SetAbort(); - /// - /// Gets or sets the consistent bit in the COM+ context. - /// - /// My transaction vote. - TransactionVote MyTransactionVote { get; set;} + /// + /// Gets or sets the consistent bit in the COM+ context. + /// + /// My transaction vote. + TransactionVote MyTransactionVote { get; set; } - /// - /// Gets a value indicating whether the current context is transactional. - /// - /// - /// true if this instance is existing transaction; otherwise, false. - /// - bool IsInTransaction { get; } - - } + /// + /// Gets a value indicating whether the current context is transactional. + /// + /// + /// true if this instance is existing transaction; otherwise, false. + /// + bool IsInTransaction { get; } } diff --git a/src/Spring/Spring.Data/Data/Support/ITransactionScopeAdapter.cs b/src/Spring/Spring.Data/Data/Support/ITransactionScopeAdapter.cs index 9e55a473..ff726248 100644 --- a/src/Spring/Spring.Data/Data/Support/ITransactionScopeAdapter.cs +++ b/src/Spring/Spring.Data/Data/Support/ITransactionScopeAdapter.cs @@ -20,50 +20,49 @@ using System.Transactions; -namespace Spring.Data.Support +namespace Spring.Data.Support; + +/// +/// Provides the necessary transactional state and operations for TxScopeTransactionManager to +/// work with TransactionScope and Transaction.Current. +/// +/// Introduced for purposes of unit testing. +/// Mark Pollack (.NET) +public interface ITransactionScopeAdapter { /// - /// Provides the necessary transactional state and operations for TxScopeTransactionManager to - /// work with TransactionScope and Transaction.Current. + /// Creates the transaction scope. /// - /// Introduced for purposes of unit testing. - /// Mark Pollack (.NET) - public interface ITransactionScopeAdapter - { - /// - /// Creates the transaction scope. - /// - /// The tx scope option. - /// The tx options. - /// The async flow option. - void CreateTransactionScope( - TransactionScopeOption txScopeOption, - TransactionOptions txOptions, - TransactionScopeAsyncFlowOption asyncFlowOption); + /// The tx scope option. + /// The tx options. + /// The async flow option. + void CreateTransactionScope( + TransactionScopeOption txScopeOption, + TransactionOptions txOptions, + TransactionScopeAsyncFlowOption asyncFlowOption); - /// - /// Call Complete() on the TransactionScope object created by this instance. - /// - void Complete(); + /// + /// Call Complete() on the TransactionScope object created by this instance. + /// + void Complete(); - /// - /// Call Dispose() on the TransactionScope object created by this instance. - /// - void Dispose(); + /// + /// Call Dispose() on the TransactionScope object created by this instance. + /// + void Dispose(); - /// - /// Gets a value indicating whether there is a new transaction or an existing transaction. - /// - /// - /// true if this instance is existing transaction; otherwise, false. - /// - bool IsExistingTransaction { get; } + /// + /// Gets a value indicating whether there is a new transaction or an existing transaction. + /// + /// + /// true if this instance is existing transaction; otherwise, false. + /// + bool IsExistingTransaction { get; } - /// - /// Gets a value indicating whether rollback only has been called (i.e. Rollback() on the - /// Transaction object) and therefore voting that the transaction will be aborted. - /// - /// true if rollback only; otherwise, false. - bool RollbackOnly { get; } - } -} \ No newline at end of file + /// + /// Gets a value indicating whether rollback only has been called (i.e. Rollback() on the + /// Transaction object) and therefore voting that the transaction will be aborted. + /// + /// true if rollback only; otherwise, false. + bool RollbackOnly { get; } +} diff --git a/src/Spring/Spring.Data/Data/Support/NamedResultSetProcessor.cs b/src/Spring/Spring.Data/Data/Support/NamedResultSetProcessor.cs index de57a4fa..6887065f 100644 --- a/src/Spring/Spring.Data/Data/Support/NamedResultSetProcessor.cs +++ b/src/Spring/Spring.Data/Data/Support/NamedResultSetProcessor.cs @@ -1,12 +1,12 @@ /* * Copyright © 2002-2011 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. @@ -14,69 +14,68 @@ * limitations under the License. */ -namespace Spring.Data.Support +namespace Spring.Data.Support; + +/// +/// Provides a name to a ResultSetProcessor for use with AdoOperation subclasses +/// such as StoredProcedure. +/// +/// Mark Pollack (.NET) +public class NamedResultSetProcessor { - /// - /// Provides a name to a ResultSetProcessor for use with AdoOperation subclasses - /// such as StoredProcedure. - /// - /// Mark Pollack (.NET) - public class NamedResultSetProcessor - { - private readonly object resultSetProcessor; - private readonly string name; + private readonly object resultSetProcessor; + private readonly string name; - /// - /// Initializes a new instance of the class with a - /// IRowCallback instance - /// - /// The name of the associated row callback for use with output - /// result set mappers. - /// A row callback instance. - public NamedResultSetProcessor(string name, IRowCallback rowcallback) - { - this.name = name; - resultSetProcessor = rowcallback; - } - - /// - /// Initializes a new instance of the class with a - /// IRowMapper instance - /// - /// The name of the associated row mapper. - /// A IRowMapper instance. - public NamedResultSetProcessor(string name, IRowMapper rowMapper) - { - this.name = name; - resultSetProcessor = rowMapper; - } - - /// - /// Initializes a new instance of the class with a - /// IResultSetExtractor instance - /// - /// The name of the associated result set extractor. - /// A IResultSetExtractor instance. - public NamedResultSetProcessor(string name, IResultSetExtractor resultSetExtractor) + /// + /// Initializes a new instance of the class with a + /// IRowCallback instance + /// + /// The name of the associated row callback for use with output + /// result set mappers. + /// A row callback instance. + public NamedResultSetProcessor(string name, IRowCallback rowcallback) + { + this.name = name; + resultSetProcessor = rowcallback; + } + + /// + /// Initializes a new instance of the class with a + /// IRowMapper instance + /// + /// The name of the associated row mapper. + /// A IRowMapper instance. + public NamedResultSetProcessor(string name, IRowMapper rowMapper) + { + this.name = name; + resultSetProcessor = rowMapper; + } + + /// + /// Initializes a new instance of the class with a + /// IResultSetExtractor instance + /// + /// The name of the associated result set extractor. + /// A IResultSetExtractor instance. + public NamedResultSetProcessor(string name, IResultSetExtractor resultSetExtractor) + { + this.name = name; + resultSetProcessor = resultSetExtractor; + } + + public string Name + { + get { - this.name = name; - resultSetProcessor = resultSetExtractor; + return name; } + } - public string Name - { - get - { - return name; - } - } - - public object ResultSetProcessor - { - get - { - return resultSetProcessor; - } - } - } + public object ResultSetProcessor + { + get + { + return resultSetProcessor; + } + } } diff --git a/src/Spring/Spring.Data/Data/Support/NullMappingDataReader.cs b/src/Spring/Spring.Data/Data/Support/NullMappingDataReader.cs index 2f4f74d5..e3147020 100644 --- a/src/Spring/Spring.Data/Data/Support/NullMappingDataReader.cs +++ b/src/Spring/Spring.Data/Data/Support/NullMappingDataReader.cs @@ -20,323 +20,323 @@ using System.Data; -namespace Spring.Data.Support +namespace Spring.Data.Support; + +/// +/// A data reader implementation that mapps DBNull values to sensible defaults. +/// +/// IDataRecord methods are virtual. +/// Mark Pollack (.NET) +public class NullMappingDataReader : IDataReaderWrapper { - /// - /// A data reader implementation that mapps DBNull values to sensible defaults. - /// - /// IDataRecord methods are virtual. - /// Mark Pollack (.NET) - public class NullMappingDataReader : IDataReaderWrapper - { - #region Fields + #region Fields - protected IDataReader dataReader; - private bool alreadyDisposed = false; + protected IDataReader dataReader; + private bool alreadyDisposed = false; - #endregion + #endregion - #region Constructor (s) - /// - /// Initializes a new instance of the class. - /// - public NullMappingDataReader() - { + #region Constructor (s) - } + /// + /// Initializes a new instance of the class. + /// + public NullMappingDataReader() + { + } - /// - /// Initializes a new instance of the class. - /// - /// The data reader to delegate operations to. - public NullMappingDataReader(IDataReader dataReader) - { - this.dataReader = dataReader; - } + /// + /// Initializes a new instance of the class. + /// + /// The data reader to delegate operations to. + public NullMappingDataReader(IDataReader dataReader) + { + this.dataReader = dataReader; + } - #endregion + #endregion - ~NullMappingDataReader() - { - Dispose(false); - } - #region Methods - protected virtual void Dispose(bool isDisposing) + ~NullMappingDataReader() + { + Dispose(false); + } + + #region Methods + + protected virtual void Dispose(bool isDisposing) + { + // Don't dispose more than once + if (alreadyDisposed) { - // Don't dispose more than once - if (alreadyDisposed) - { - return; - } - if (isDisposing) - { - //free managed resourced - dataReader.Dispose(); - } - alreadyDisposed = true; - } - #endregion - - #region IDataReaderWrapper Members - - public IDataReader WrappedReader - { - get - { - return dataReader; - } - set - { - dataReader = value; - } + return; } - #endregion - - #region IDataReader Members - - public int RecordsAffected + if (isDisposing) { - get - { - return this.dataReader.RecordsAffected; - } + //free managed resourced + dataReader.Dispose(); } - public bool IsClosed + alreadyDisposed = true; + } + + #endregion + + #region IDataReaderWrapper Members + + public IDataReader WrappedReader + { + get { - get - { - return this.dataReader.IsClosed; - } + return dataReader; } - - public bool NextResult() + set { - return dataReader.NextResult(); + dataReader = value; } + } - public void Close() + #endregion + + #region IDataReader Members + + public int RecordsAffected + { + get { - dataReader.Close(); + return this.dataReader.RecordsAffected; } + } - public bool Read() + public bool IsClosed + { + get { - return dataReader.Read(); + return this.dataReader.IsClosed; } + } - public int Depth + public bool NextResult() + { + return dataReader.NextResult(); + } + + public void Close() + { + dataReader.Close(); + } + + public bool Read() + { + return dataReader.Read(); + } + + public int Depth + { + get { - get - { - return dataReader.Depth; - } + return dataReader.Depth; } + } - public DataTable GetSchemaTable() + public DataTable GetSchemaTable() + { + return dataReader.GetSchemaTable(); + } + + #endregion + + #region IDisposable Members + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(true); + } + + #endregion + + #region IDataRecord Members + + /// + /// Gets the 32-bit signed integer value of the specified field. + /// + /// The index of the field to find. + /// + /// The 32-bit signed integer value of the specified field or 0 if null + /// + /// The index passed was outside the range of 0 through . + public virtual int GetInt32(int i) + { + if (dataReader.IsDBNull(i)) { - return dataReader.GetSchemaTable(); + return 0; } - - #endregion - - #region IDisposable Members - - public void Dispose() + else { - Dispose(true); - GC.SuppressFinalize(true); + return dataReader.GetInt32(i); } + } - #endregion - - #region IDataRecord Members - - /// - /// Gets the 32-bit signed integer value of the specified field. - /// - /// The index of the field to find. - /// - /// The 32-bit signed integer value of the specified field or 0 if null - /// - /// The index passed was outside the range of 0 through . - public virtual int GetInt32(int i) + /// + /// Gets the with the specified name. + /// Returns null if value equals DBNull.Value + /// + /// + public virtual object this[string name] + { + get { - if (dataReader.IsDBNull(i)) - { - return 0; - } - else - { - return dataReader.GetInt32(i); - } + object objectValue = dataReader[name]; + return DBNull.Value.Equals(objectValue) ? null : objectValue; } + } - - /// - /// Gets the with the specified name. - /// Returns null if value equals DBNull.Value - /// - /// - public virtual object this[string name] + /// + /// Gets the with the specified i. + /// Returns null if value equals DBNull.Value + /// + /// Return the object or null if the value equals DBNull.Value + public virtual object this[int i] + { + get { - get - { - object objectValue = dataReader[name]; - return DBNull.Value.Equals(objectValue) ? null : objectValue; - } + return dataReader.IsDBNull(i) ? null : dataReader[i]; } + } + /// + /// Return the value of the specified field, null if value equals DBNull.Value + /// + /// The index of the field to find. + /// + /// The which will contain the field value upon return. + /// Returns null if value equals DBNull.Value + /// + /// + /// The index passed was outside the range of 0 through . + /// + public virtual object GetValue(int i) + { + return dataReader.IsDBNull(i) ? null : dataReader.GetValue(i); + } - /// - /// Gets the with the specified i. - /// Returns null if value equals DBNull.Value - /// - /// Return the object or null if the value equals DBNull.Value - public virtual object this[int i] + /// + /// Return whether the specified field is set to null. + /// + /// The index of the field to find. + /// + /// if the specified field is set to null, otherwise + /// . + /// + /// The index passed was outside the range of 0 through . + public virtual bool IsDBNull(int i) + { + return dataReader.IsDBNull(i); + } + + public virtual long GetBytes(int i, long fieldOffset, byte[] buffer, int bufferoffset, int length) + { + return dataReader.IsDBNull(i) ? 0 : dataReader.GetBytes(i, fieldOffset, buffer, bufferoffset, length); + } + + public virtual byte GetByte(int i) + { + return dataReader.IsDBNull(i) ? (byte) 0 : dataReader.GetByte(i); + } + + public virtual Type GetFieldType(int i) + { + return dataReader.GetFieldType(i); + } + + public virtual decimal GetDecimal(int i) + { + return dataReader.IsDBNull(i) ? 0 : dataReader.GetDecimal(i); + } + + public virtual int GetValues(object[] values) + { + return dataReader.GetValues(values); + } + + public virtual string GetName(int i) + { + return dataReader.GetName(i); + } + + public virtual int FieldCount + { + get { - get - { - - return dataReader.IsDBNull(i) ? null : dataReader[i]; - } + return dataReader.FieldCount; } + } - /// - /// Return the value of the specified field, null if value equals DBNull.Value - /// - /// The index of the field to find. - /// - /// The which will contain the field value upon return. - /// Returns null if value equals DBNull.Value - /// - /// - /// The index passed was outside the range of 0 through . - /// - public virtual object GetValue(int i) - { - return dataReader.IsDBNull(i) ? null : dataReader.GetValue(i); - } + public virtual long GetInt64(int i) + { + return dataReader.IsDBNull(i) ? 0 : dataReader.GetInt64(i); + } - /// - /// Return whether the specified field is set to null. - /// - /// The index of the field to find. - /// - /// if the specified field is set to null, otherwise - /// . - /// - /// The index passed was outside the range of 0 through . - public virtual bool IsDBNull(int i) - { - return dataReader.IsDBNull(i); - } + public virtual double GetDouble(int i) + { + return dataReader.IsDBNull(i) ? 0 : dataReader.GetDouble(i); + } - public virtual long GetBytes(int i, long fieldOffset, byte[] buffer, int bufferoffset, int length) - { - return dataReader.IsDBNull(i) ? 0 : dataReader.GetBytes(i, fieldOffset, buffer, bufferoffset, length); - } + public virtual bool GetBoolean(int i) + { + return dataReader.IsDBNull(i) ? false : dataReader.GetBoolean(i); + } - public virtual byte GetByte(int i) - { - return dataReader.IsDBNull(i) ? (byte)0 : dataReader.GetByte(i); - } + public virtual Guid GetGuid(int i) + { + return dataReader.IsDBNull(i) ? Guid.Empty : dataReader.GetGuid(i); + } - public virtual Type GetFieldType(int i) - { - return dataReader.GetFieldType(i); - } + public virtual DateTime GetDateTime(int i) + { + return dataReader.IsDBNull(i) ? DateTime.MinValue : dataReader.GetDateTime(i); + } - public virtual decimal GetDecimal(int i) - { - return dataReader.IsDBNull(i) ? 0 : dataReader.GetDecimal(i); - } + public virtual int GetOrdinal(string name) + { + return dataReader.GetOrdinal(name); + } - public virtual int GetValues(object[] values) - { - return dataReader.GetValues(values); - } + public virtual string GetDataTypeName(int i) + { + return dataReader.GetDataTypeName(i); + } - public virtual string GetName(int i) - { - return dataReader.GetName(i); - } + public virtual float GetFloat(int i) + { + return dataReader.IsDBNull(i) ? 0 : dataReader.GetFloat(i); + } - public virtual int FieldCount - { - get - { - return dataReader.FieldCount; - } - } + public virtual IDataReader GetData(int i) + { + return dataReader.GetData(i); + } - public virtual long GetInt64(int i) - { - return dataReader.IsDBNull(i) ? 0 : dataReader.GetInt64(i); - } + public virtual long GetChars(int i, long fieldoffset, char[] buffer, int bufferoffset, int length) + { + return dataReader.IsDBNull(i) ? 0 : dataReader.GetChars(i, fieldoffset, buffer, bufferoffset, length); + } - public virtual double GetDouble(int i) - { - return dataReader.IsDBNull(i) ? 0 : dataReader.GetDouble(i); - } + public virtual string GetString(int i) + { + return dataReader.IsDBNull(i) ? string.Empty : dataReader.GetString(i); + } - public virtual bool GetBoolean(int i) - { - return dataReader.IsDBNull(i) ? false : dataReader.GetBoolean(i); - } + public virtual char GetChar(int i) + { + return dataReader.IsDBNull(i) ? char.MinValue : dataReader.GetChar(i); + } - public virtual Guid GetGuid(int i) - { - return dataReader.IsDBNull(i) ? Guid.Empty : dataReader.GetGuid(i); - } + public virtual short GetInt16(int i) + { + return dataReader.IsDBNull(i) ? (short) 0 : dataReader.GetInt16(i); + } - public virtual DateTime GetDateTime(int i) - { - return dataReader.IsDBNull(i) ? DateTime.MinValue : dataReader.GetDateTime(i); - } - - public virtual int GetOrdinal(string name) - { - return dataReader.GetOrdinal(name); - } - - public virtual string GetDataTypeName(int i) - { - return dataReader.GetDataTypeName(i); - } - - public virtual float GetFloat(int i) - { - return dataReader.IsDBNull(i) ? 0 : dataReader.GetFloat(i); - } - - public virtual IDataReader GetData(int i) - { - return dataReader.GetData(i); - } - - public virtual long GetChars(int i, long fieldoffset, char[] buffer, int bufferoffset, int length) - { - return dataReader.IsDBNull(i) ? 0 : dataReader.GetChars(i, fieldoffset, buffer, bufferoffset, length); - } - - public virtual string GetString(int i) - { - return dataReader.IsDBNull(i) ? string.Empty : dataReader.GetString(i); - } - - public virtual char GetChar(int i) - { - return dataReader.IsDBNull(i) ? char.MinValue : dataReader.GetChar(i); - } - - public virtual short GetInt16(int i) - { - return dataReader.IsDBNull(i) ? (short)0 : dataReader.GetInt16(i); - } - - #endregion - - } + #endregion } diff --git a/src/Spring/Spring.Data/Data/Support/ParameterUtils.cs b/src/Spring/Spring.Data/Data/Support/ParameterUtils.cs index 1fc74438..62d16e2f 100644 --- a/src/Spring/Spring.Data/Data/Support/ParameterUtils.cs +++ b/src/Spring/Spring.Data/Data/Support/ParameterUtils.cs @@ -23,145 +23,147 @@ using System.Data; using Microsoft.Extensions.Logging; using Spring.Data.Common; -namespace Spring.Data.Support +namespace Spring.Data.Support; + +/// +/// Miscellaneous utility methods for manipulating parameter objects. +/// +/// Mark Pollack (.NET) +public class ParameterUtils { - /// - /// Miscellaneous utility methods for manipulating parameter objects. - /// - /// Mark Pollack (.NET) - public class ParameterUtils - { - #region Fields + #region Fields - #endregion + #endregion - #region Constants + #region Constants - /// - /// The shared log instance for this class (and derived classes). - /// - protected static readonly ILogger log = LogManager.GetLogger(typeof (ParameterUtils)); + /// + /// The shared log instance for this class (and derived classes). + /// + protected static readonly ILogger log = LogManager.GetLogger(typeof(ParameterUtils)); - #endregion + #endregion - #region Constructor (s) - /// - /// Initializes a new instance of the class. - /// - public ParameterUtils() - { + #region Constructor (s) - } + /// + /// Initializes a new instance of the class. + /// + public ParameterUtils() + { + } - #endregion + #endregion - #region Properties + #region Properties - #endregion + #endregion - #region Methods + #region Methods - - /// - /// Copies the parameters from IDbParameters to the parameter collection in IDbCommand - /// - /// The command. - /// The spring param collection. - public static void CopyParameters(IDbCommand command, IDbParameters springParamCollection) + /// + /// Copies the parameters from IDbParameters to the parameter collection in IDbCommand + /// + /// The command. + /// The spring param collection. + public static void CopyParameters(IDbCommand command, IDbParameters springParamCollection) + { + if (springParamCollection != null) { - if (springParamCollection != null) - { - IDataParameterCollection collection = springParamCollection.DataParameterCollection; + IDataParameterCollection collection = springParamCollection.DataParameterCollection; - foreach (IDbDataParameter parameter in collection) - { - IDbDataParameter pClone = (IDbDataParameter)((ICloneable)parameter).Clone(); - command.Parameters.Add(pClone); - } + foreach (IDbDataParameter parameter in collection) + { + IDbDataParameter pClone = (IDbDataParameter) ((ICloneable) parameter).Clone(); + command.Parameters.Add(pClone); } } + } - public static IDataParameter[] CloneParameters(IDbCommand command) - { - IDataParameter[] returnParameters = new IDataParameter[command.Parameters.Count]; - for (int i = 0; i < command.Parameters.Count; i++) - { - IDbDataParameter pClone = (IDbDataParameter)((ICloneable)command.Parameters[i]).Clone(); - returnParameters[i] = pClone; - } - return returnParameters; - } - - - /// - /// Copies the parameters in IDbCommand to IDbParameters - /// - /// The spring param collection. - /// The command. - public static void CopyParameters(IDbParameters springParamCollection, - IDbCommand command) + public static IDataParameter[] CloneParameters(IDbCommand command) + { + IDataParameter[] returnParameters = new IDataParameter[command.Parameters.Count]; + for (int i = 0; i < command.Parameters.Count; i++) { - if (springParamCollection != null) - { - IDataParameterCollection cmdParameterCollection = command.Parameters; - //TODO investigate copying only the values over, not a full clone. - int count = 0; - foreach (IDbDataParameter dbDataParameter in cmdParameterCollection) - { - springParamCollection[count] = (IDbDataParameter)((ICloneable)dbDataParameter).Clone();; - count++; - } - } + IDbDataParameter pClone = (IDbDataParameter) ((ICloneable) command.Parameters[i]).Clone(); + returnParameters[i] = pClone; } - #endregion + return returnParameters; + } - public static void ExtractOutputParameters(IDictionary returnedParameters, IDbCommand command) - { - if (returnedParameters == null) - { - return; - } - IDataParameterCollection paramCollection = command.Parameters; - int count = 0; - foreach (IDbDataParameter dbDataParameter in paramCollection) - { - if (dbDataParameter.Direction == ParameterDirection.Output - || dbDataParameter.Direction == ParameterDirection.InputOutput) + /// + /// Copies the parameters in IDbCommand to IDbParameters + /// + /// The spring param collection. + /// The command. + public static void CopyParameters(IDbParameters springParamCollection, + IDbCommand command) + { + if (springParamCollection != null) + { + IDataParameterCollection cmdParameterCollection = command.Parameters; + //TODO investigate copying only the values over, not a full clone. + int count = 0; + foreach (IDbDataParameter dbDataParameter in cmdParameterCollection) + { + springParamCollection[count] = (IDbDataParameter) ((ICloneable) dbDataParameter).Clone(); + ; + count++; + } + } + } + + #endregion + + public static void ExtractOutputParameters(IDictionary returnedParameters, IDbCommand command) + { + if (returnedParameters == null) + { + return; + } + + IDataParameterCollection paramCollection = command.Parameters; + int count = 0; + foreach (IDbDataParameter dbDataParameter in paramCollection) + { + if (dbDataParameter.Direction == ParameterDirection.Output + || dbDataParameter.Direction == ParameterDirection.InputOutput) + { + if (dbDataParameter.ParameterName == null) { - if (dbDataParameter.ParameterName == null) - { - returnedParameters.Add("P" + count, dbDataParameter.Value); - } - else - { - returnedParameters.Add(dbDataParameter.ParameterName, dbDataParameter.Value); - } + returnedParameters.Add("P" + count, dbDataParameter.Value); } - if (dbDataParameter.Direction == ParameterDirection.ReturnValue) + else { - returnedParameters.Add("RETURN_VALUE", dbDataParameter.Value); + returnedParameters.Add(dbDataParameter.ParameterName, dbDataParameter.Value); } - count++; - } - /* - for (int i = 0; i < declaredParameters.Count; i++) - { - IDataParameter declaredParameter = declaredParameters[i]; - if (declaredParameter.Direction == ParameterDirection.Output - || declaredParameter.Direction == ParameterDirection.InputOutput) - { - IDataParameter outParameter = (IDataParameter)command.Parameters[i]; - if (declaredParameter.ParameterName == null) - { - returnedParameters.Add("P" + i, outParameter.Value); - } - else - { - returnedParameters.Add(outParameter.ParameterName, outParameter.Value); - } - } - }*/ - } - } + } + + if (dbDataParameter.Direction == ParameterDirection.ReturnValue) + { + returnedParameters.Add("RETURN_VALUE", dbDataParameter.Value); + } + + count++; + } + /* + for (int i = 0; i < declaredParameters.Count; i++) + { + IDataParameter declaredParameter = declaredParameters[i]; + if (declaredParameter.Direction == ParameterDirection.Output + || declaredParameter.Direction == ParameterDirection.InputOutput) + { + IDataParameter outParameter = (IDataParameter)command.Parameters[i]; + if (declaredParameter.ParameterName == null) + { + returnedParameters.Add("P" + i, outParameter.Value); + } + else + { + returnedParameters.Add(outParameter.ParameterName, outParameter.Value); + } + } + }*/ + } } diff --git a/src/Spring/Spring.Data/Data/Support/RowCallbackResultSetExtractor.cs b/src/Spring/Spring.Data/Data/Support/RowCallbackResultSetExtractor.cs index 8897a36c..d328e1b8 100644 --- a/src/Spring/Spring.Data/Data/Support/RowCallbackResultSetExtractor.cs +++ b/src/Spring/Spring.Data/Data/Support/RowCallbackResultSetExtractor.cs @@ -21,67 +21,66 @@ using System.Data; using Spring.Util; -namespace Spring.Data.Support +namespace Spring.Data.Support; + +/// +/// Adapter to enable use of a IRowCallback inside a ResultSetExtractor. +/// +/// We don't use it for navigating since this could lead to unpredictable consequences. +/// Mark Pollack +public class RowCallbackResultSetExtractor : IResultSetExtractor { + private IRowCallback rowCallback; + + private RowCallbackDelegate rowCallbackDelegate; + /// - /// Adapter to enable use of a IRowCallback inside a ResultSetExtractor. + /// Initializes a new instance of the class. /// - /// We don't use it for navigating since this could lead to unpredictable consequences. - /// Mark Pollack - public class RowCallbackResultSetExtractor : IResultSetExtractor + /// The row callback. + public RowCallbackResultSetExtractor(IRowCallback rowCallback) { - private IRowCallback rowCallback; - - private RowCallbackDelegate rowCallbackDelegate; - - /// - /// Initializes a new instance of the class. - /// - /// The row callback. - public RowCallbackResultSetExtractor(IRowCallback rowCallback) - { - AssertUtils.ArgumentNotNull(rowCallback, "rowCallback"); - this.rowCallback = rowCallback; - } - - /// - /// Initializes a new instance of the class. - /// - /// The row callback delegate. - public RowCallbackResultSetExtractor(RowCallbackDelegate rowCallbackDelegate) - { - AssertUtils.ArgumentNotNull(rowCallbackDelegate, "rowCallbackDelegate"); - this.rowCallbackDelegate = rowCallbackDelegate; - } - - /// - /// All rows of the data reader are passed to the IRowCallback - /// associated with this class. - /// - /// The IDataReader to extract data from. - /// Implementations should not close this: it will be closed - /// by the AdoTemplate. - /// - /// Null is returned since IRowCallback manages its own state. - /// - public object ExtractData(IDataReader reader) - { - if (rowCallback != null) - { - while (reader.Read()) - { - rowCallback.ProcessRow(reader); - } - } - else - { - while (reader.Read()) - { - rowCallbackDelegate(reader); - } - } - - return null; - } + AssertUtils.ArgumentNotNull(rowCallback, "rowCallback"); + this.rowCallback = rowCallback; } -} \ No newline at end of file + + /// + /// Initializes a new instance of the class. + /// + /// The row callback delegate. + public RowCallbackResultSetExtractor(RowCallbackDelegate rowCallbackDelegate) + { + AssertUtils.ArgumentNotNull(rowCallbackDelegate, "rowCallbackDelegate"); + this.rowCallbackDelegate = rowCallbackDelegate; + } + + /// + /// All rows of the data reader are passed to the IRowCallback + /// associated with this class. + /// + /// The IDataReader to extract data from. + /// Implementations should not close this: it will be closed + /// by the AdoTemplate. + /// + /// Null is returned since IRowCallback manages its own state. + /// + public object ExtractData(IDataReader reader) + { + if (rowCallback != null) + { + while (reader.Read()) + { + rowCallback.ProcessRow(reader); + } + } + else + { + while (reader.Read()) + { + rowCallbackDelegate(reader); + } + } + + return null; + } +} diff --git a/src/Spring/Spring.Data/Data/Support/SimpleServiceConfig.cs b/src/Spring/Spring.Data/Data/Support/SimpleServiceConfig.cs index b585de46..fb7d32e7 100644 --- a/src/Spring/Spring.Data/Data/Support/SimpleServiceConfig.cs +++ b/src/Spring/Spring.Data/Data/Support/SimpleServiceConfig.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -20,104 +20,102 @@ using System.EnterpriseServices; -namespace Spring.Data.Support +namespace Spring.Data.Support; + +/// +/// A class that contains the properties of ServiceConfig used by ServiceDomainPlatformTransactionManager. +/// +/// This is done to enhance testability of the transaction manager since ServiceConfig does not override Equals or Hashcode +/// Mark Pollack (.NET) +public class SimpleServiceConfig { - /// - /// A class that contains the properties of ServiceConfig used by ServiceDomainPlatformTransactionManager. - /// - /// This is done to enhance testability of the transaction manager since ServiceConfig does not override Equals or Hashcode - /// Mark Pollack (.NET) - public class SimpleServiceConfig + private string transactionDescription; + private bool trackingEnabled = true; + private string trackingAppName; + private string trackingComponentName; + private TransactionOption transactionOption; + private TransactionIsolationLevel isolationLevel; + private int transactionTimeout; + + public string TransactionDescription { - private string transactionDescription; - private bool trackingEnabled = true; - private string trackingAppName; - private string trackingComponentName; - private TransactionOption transactionOption; - private TransactionIsolationLevel isolationLevel; - private int transactionTimeout; + get { return transactionDescription; } + set { transactionDescription = value; } + } + public bool TrackingEnabled + { + get { return trackingEnabled; } + set { trackingEnabled = value; } + } - public string TransactionDescription - { - get { return transactionDescription; } - set { transactionDescription = value; } - } + public string TrackingAppName + { + get { return trackingAppName; } + set { trackingAppName = value; } + } - public bool TrackingEnabled - { - get { return trackingEnabled; } - set { trackingEnabled = value; } - } + public string TrackingComponentName + { + get { return trackingComponentName; } + set { trackingComponentName = value; } + } - public string TrackingAppName - { - get { return trackingAppName; } - set { trackingAppName = value; } - } + public TransactionOption TransactionOption + { + get { return transactionOption; } + set { transactionOption = value; } + } - public string TrackingComponentName - { - get { return trackingComponentName; } - set { trackingComponentName = value; } - } + public TransactionIsolationLevel IsolationLevel + { + get { return isolationLevel; } + set { isolationLevel = value; } + } - public TransactionOption TransactionOption - { - get { return transactionOption; } - set { transactionOption = value; } - } + public int TransactionTimeout + { + get { return transactionTimeout; } + set { transactionTimeout = value; } + } - public TransactionIsolationLevel IsolationLevel - { - get { return isolationLevel; } - set { isolationLevel = value; } - } + public ServiceConfig CreateServiceConfig() + { + ServiceConfig serviceConfig = new ServiceConfig(); + serviceConfig.TransactionDescription = this.transactionDescription; + serviceConfig.TrackingEnabled = this.trackingEnabled; + serviceConfig.TrackingAppName = this.trackingAppName; + serviceConfig.TrackingComponentName = this.trackingComponentName; + serviceConfig.Transaction = this.transactionOption; + serviceConfig.IsolationLevel = this.isolationLevel; + serviceConfig.TransactionTimeout = this.transactionTimeout; + return serviceConfig; + } - public int TransactionTimeout - { - get { return transactionTimeout; } - set { transactionTimeout = value; } - } + public override bool Equals(object obj) + { + if (this == obj) return true; + SimpleServiceConfig simpleServiceConfig = obj as SimpleServiceConfig; + if (simpleServiceConfig == null) return false; + if (!Equals(transactionDescription, simpleServiceConfig.transactionDescription)) return false; + if (!Equals(trackingEnabled, simpleServiceConfig.trackingEnabled)) return false; + if (!Equals(trackingAppName, simpleServiceConfig.trackingAppName)) return false; + if (!Equals(trackingComponentName, simpleServiceConfig.trackingComponentName)) return false; + if (!Equals(transactionOption, simpleServiceConfig.transactionOption)) return false; + if (!Equals(isolationLevel, simpleServiceConfig.isolationLevel)) return false; + if (transactionTimeout != simpleServiceConfig.transactionTimeout) return false; + return true; + } - public ServiceConfig CreateServiceConfig() - { - ServiceConfig serviceConfig = new ServiceConfig(); - serviceConfig.TransactionDescription = this.transactionDescription; - serviceConfig.TrackingEnabled = this.trackingEnabled; - serviceConfig.TrackingAppName = this.trackingAppName; - serviceConfig.TrackingComponentName = this.trackingComponentName; - serviceConfig.Transaction = this.transactionOption; - serviceConfig.IsolationLevel = this.isolationLevel; - serviceConfig.TransactionTimeout = this.transactionTimeout; - return serviceConfig; - } - - public override bool Equals(object obj) - { - if (this == obj) return true; - SimpleServiceConfig simpleServiceConfig = obj as SimpleServiceConfig; - if (simpleServiceConfig == null) return false; - if (!Equals(transactionDescription, simpleServiceConfig.transactionDescription)) return false; - if (!Equals(trackingEnabled, simpleServiceConfig.trackingEnabled)) return false; - if (!Equals(trackingAppName, simpleServiceConfig.trackingAppName)) return false; - if (!Equals(trackingComponentName, simpleServiceConfig.trackingComponentName)) return false; - if (!Equals(transactionOption, simpleServiceConfig.transactionOption)) return false; - if (!Equals(isolationLevel, simpleServiceConfig.isolationLevel)) return false; - if (transactionTimeout != simpleServiceConfig.transactionTimeout) return false; - return true; - } - - public override int GetHashCode() - { - int result = transactionDescription != null ? transactionDescription.GetHashCode() : 0; - result = 29*result + trackingEnabled.GetHashCode(); - result = 29*result + (trackingAppName != null ? trackingAppName.GetHashCode() : 0); - result = 29*result + (trackingComponentName != null ? trackingComponentName.GetHashCode() : 0); - result = 29*result + transactionOption.GetHashCode(); - result = 29*result + isolationLevel.GetHashCode(); - result = 29*result + transactionTimeout; - return result; - } + public override int GetHashCode() + { + int result = transactionDescription != null ? transactionDescription.GetHashCode() : 0; + result = 29 * result + trackingEnabled.GetHashCode(); + result = 29 * result + (trackingAppName != null ? trackingAppName.GetHashCode() : 0); + result = 29 * result + (trackingComponentName != null ? trackingComponentName.GetHashCode() : 0); + result = 29 * result + transactionOption.GetHashCode(); + result = 29 * result + isolationLevel.GetHashCode(); + result = 29 * result + transactionTimeout; + return result; } } diff --git a/src/Spring/Spring.Data/Data/Support/Sql/sqlconnectionstring.xsd b/src/Spring/Spring.Data/Data/Support/Sql/sqlconnectionstring.xsd index b36cd970..73db4fbc 100644 --- a/src/Spring/Spring.Data/Data/Support/Sql/sqlconnectionstring.xsd +++ b/src/Spring/Spring.Data/Data/Support/Sql/sqlconnectionstring.xsd @@ -1,64 +1,64 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Spring/Spring.Data/Data/Support/TypedDataSetUtils.cs b/src/Spring/Spring.Data/Data/Support/TypedDataSetUtils.cs index b20e8935..c74b4334 100644 --- a/src/Spring/Spring.Data/Data/Support/TypedDataSetUtils.cs +++ b/src/Spring/Spring.Data/Data/Support/TypedDataSetUtils.cs @@ -23,143 +23,135 @@ using System.Reflection; using Microsoft.Extensions.Logging; using Spring.Data.Common; -namespace Spring.Data.Support +namespace Spring.Data.Support; + +/// +/// Using reflection on VS.NET 2005 a generated typed dataset, apply the +/// connection/transaction pair associated with the current Spring based +/// transaction scope. +/// +/// This avoids the limitations of using System.Transaction +/// based transaction scope for multiple operation on typed datasets withone one +/// transaction. Reflection was used rather than partial classes to provide +/// a general solution that can be written and applied once. +/// Usage within a DAO method, FindAll() is shown below. Note: Convenience methods +/// to simplify calling syntax maybe provided in the future, it is a trade off on type +/// safety calling the typed adapter defined outside the anonymous method as +/// compared to casting inside a "DoInDbAdapter(object dbAdapter) method. +/// +/// public PrintGroupMappingDataSet FindAll() +/// { +/// +/// PrintGroupMappingTableAdapter adapter = new PrintGroupMappingTableAdapter(); +/// PrintGroupMappingDataSet printGroupMappingDataSet = new PrintGroupMappingDataSet(); +/// +/// +/// printGroupMappingDataSet = AdoTemplate.Execute(delegate(IDbCommand command) +/// { +/// TypedDataSetUtils.ApplyConnectionAndTx(adapter, command); +/// adapter.Fill(printGroupMappingDataSet.PrintGroupMapping); +/// return printGroupMappingDataSet; +/// }) +/// as PrintGroupMappingDataSet; +/// +/// return printGroupMappingDataSet; +/// } +/// +/// See http://www.code-magazine.com/articleprint.aspx?quickid=0605031 for a +/// more complete discussion. +/// +/// +public abstract class TypedDataSetUtils { + private static readonly ILogger LOG = LogManager.GetLogger(typeof(TypedDataSetUtils)); + /// - /// Using reflection on VS.NET 2005 a generated typed dataset, apply the - /// connection/transaction pair associated with the current Spring based - /// transaction scope. + /// Applies the connection and tx to the provided typed dataset. The connection and transaction + /// used are taken from the Spring's current transactional context. See ConnectionUtils.GetConnectionTxPair + /// for more information /// - /// This avoids the limitations of using System.Transaction - /// based transaction scope for multiple operation on typed datasets withone one - /// transaction. Reflection was used rather than partial classes to provide - /// a general solution that can be written and applied once. - /// Usage within a DAO method, FindAll() is shown below. Note: Convenience methods - /// to simplify calling syntax maybe provided in the future, it is a trade off on type - /// safety calling the typed adapter defined outside the anonymous method as - /// compared to casting inside a "DoInDbAdapter(object dbAdapter) method. - /// - /// public PrintGroupMappingDataSet FindAll() - /// { - /// - /// PrintGroupMappingTableAdapter adapter = new PrintGroupMappingTableAdapter(); - /// PrintGroupMappingDataSet printGroupMappingDataSet = new PrintGroupMappingDataSet(); - /// - /// - /// printGroupMappingDataSet = AdoTemplate.Execute(delegate(IDbCommand command) - /// { - /// TypedDataSetUtils.ApplyConnectionAndTx(adapter, command); - /// adapter.Fill(printGroupMappingDataSet.PrintGroupMapping); - /// return printGroupMappingDataSet; - /// }) - /// as PrintGroupMappingDataSet; - /// - /// return printGroupMappingDataSet; - /// } - /// - /// See http://www.code-magazine.com/articleprint.aspx?quickid=0605031 for a - /// more complete discussion. - /// - /// - public abstract class TypedDataSetUtils + /// The typed data set adapter. + /// The db provider. + public static void ApplyConnectionAndTx(object typedDataSetAdapter, IDbProvider dbProvider) { - private static readonly ILogger LOG = LogManager.GetLogger(typeof (TypedDataSetUtils)); + ConnectionTxPair connectionTxPairToUse = ConnectionUtils.GetConnectionTxPair(dbProvider); + ApplyConnectionAndTxToDataAdapter(typedDataSetAdapter, connectionTxPairToUse.Connection, connectionTxPairToUse.Transaction); + } - /// - /// Applies the connection and tx to the provided typed dataset. The connection and transaction - /// used are taken from the Spring's current transactional context. See ConnectionUtils.GetConnectionTxPair - /// for more information - /// - /// The typed data set adapter. - /// The db provider. - public static void ApplyConnectionAndTx(object typedDataSetAdapter, IDbProvider dbProvider) + /// + /// Applies the connection and tx to the provided typed dataset. + /// + /// Generated dataset to not inherit from a common base + /// class so that we must pass in the generic object type. + /// The typed data set adapter. + /// The IDbCommand managed by Spring and set with + /// the connection/transaction of the current Spring transaction scope. + public static void ApplyConnectionAndTx(object typedDataSetAdapter, IDbCommand sourceCommand) + { + if (sourceCommand != null) { - ConnectionTxPair connectionTxPairToUse = ConnectionUtils.GetConnectionTxPair(dbProvider); - ApplyConnectionAndTxToDataAdapter(typedDataSetAdapter, connectionTxPairToUse.Connection, connectionTxPairToUse.Transaction); + ApplyConnectionAndTxToDataAdapter(typedDataSetAdapter, sourceCommand.Connection, sourceCommand.Transaction); + } + } + + private static IDbCommand[] GetCommandCollection(object typedDataSetAdapter) + { + PropertyInfo pi = + typedDataSetAdapter.GetType().GetProperty("CommandCollection", + BindingFlags.NonPublic | BindingFlags.Instance); + MethodInfo mi = pi.GetGetMethod(true); + return mi.Invoke(typedDataSetAdapter, null) as IDbCommand[]; + } + + private static IDbDataAdapter GetDataAdapter(object typedDataSetAdapter) + { + PropertyInfo api = + typedDataSetAdapter.GetType().GetProperty("Adapter", + BindingFlags.NonPublic | BindingFlags.Instance); + MethodInfo ami = api.GetGetMethod(true); + return ami.Invoke(typedDataSetAdapter, null) as IDbDataAdapter; + } + + private static void ApplyConnectionAndTxToDataAdapter(object typedDataSetAdapter, IDbConnection connection, IDbTransaction transaction) + { + IDbDataAdapter dataAdapter = GetDataAdapter(typedDataSetAdapter); + if (dataAdapter != null) + { + ApplyConnectionAndTxToCommand(dataAdapter.SelectCommand, connection, transaction); + + ApplyConnectionAndTxToCommand(dataAdapter.InsertCommand, connection, transaction); + + ApplyConnectionAndTxToCommand(dataAdapter.UpdateCommand, connection, transaction); + + ApplyConnectionAndTxToCommand(dataAdapter.DeleteCommand, connection, transaction); + } + else + { + LOG.LogWarning("Could not extract IDbDataAdapter from TypedDataset."); } - /// - /// Applies the connection and tx to the provided typed dataset. - /// - /// Generated dataset to not inherit from a common base - /// class so that we must pass in the generic object type. - /// The typed data set adapter. - /// The IDbCommand managed by Spring and set with - /// the connection/transaction of the current Spring transaction scope. - public static void ApplyConnectionAndTx(object typedDataSetAdapter, IDbCommand sourceCommand) - { - if (sourceCommand != null) - { - ApplyConnectionAndTxToDataAdapter(typedDataSetAdapter, sourceCommand.Connection, sourceCommand.Transaction); - } - } - - private static IDbCommand[] GetCommandCollection(object typedDataSetAdapter) + IDbCommand[] commandCollection = GetCommandCollection(typedDataSetAdapter); + if (commandCollection != null) { - PropertyInfo pi = - typedDataSetAdapter.GetType().GetProperty("CommandCollection", - BindingFlags.NonPublic | BindingFlags.Instance); - MethodInfo mi = pi.GetGetMethod(true); - return mi.Invoke(typedDataSetAdapter, null) as IDbCommand[]; - } - - private static IDbDataAdapter GetDataAdapter(object typedDataSetAdapter) - { - PropertyInfo api = - typedDataSetAdapter.GetType().GetProperty("Adapter", - BindingFlags.NonPublic | BindingFlags.Instance); - MethodInfo ami = api.GetGetMethod(true); - return ami.Invoke(typedDataSetAdapter, null) as IDbDataAdapter; - } - - private static void ApplyConnectionAndTxToDataAdapter(object typedDataSetAdapter, IDbConnection connection, IDbTransaction transaction) - { - IDbDataAdapter dataAdapter = GetDataAdapter(typedDataSetAdapter); - if (dataAdapter != null) + //don't know which one to set, so set them all. + foreach (IDbCommand dbCommand in commandCollection) { - ApplyConnectionAndTxToCommand(dataAdapter.SelectCommand, connection, transaction); - - - ApplyConnectionAndTxToCommand(dataAdapter.InsertCommand, connection, transaction); - - - ApplyConnectionAndTxToCommand(dataAdapter.UpdateCommand, connection, transaction); - - - ApplyConnectionAndTxToCommand(dataAdapter.DeleteCommand, connection, transaction); - } - else - { - LOG.LogWarning("Could not extract IDbDataAdapter from TypedDataset."); - } - - - IDbCommand[] commandCollection = GetCommandCollection(typedDataSetAdapter); - if (commandCollection != null) - { - //don't know which one to set, so set them all. - foreach (IDbCommand dbCommand in commandCollection) - { - dbCommand.Connection = connection; - dbCommand.Transaction = transaction; - } - } - else - { - LOG.LogWarning("Could not extract IDbCommand collection from TypedDataset."); + dbCommand.Connection = connection; + dbCommand.Transaction = transaction; } } - - - private static void ApplyConnectionAndTxToCommand(IDbCommand targetDbCommand, IDbConnection connection, IDbTransaction transaction) + else { - if (targetDbCommand != null) - { - targetDbCommand.Connection = connection; - targetDbCommand.Transaction = transaction; - } + LOG.LogWarning("Could not extract IDbCommand collection from TypedDataset."); } + } - + private static void ApplyConnectionAndTxToCommand(IDbCommand targetDbCommand, IDbConnection connection, IDbTransaction transaction) + { + if (targetDbCommand != null) + { + targetDbCommand.Connection = connection; + targetDbCommand.Transaction = transaction; + } } } diff --git a/src/Spring/Spring.Data/Data/UncategorizedAdoException.cs b/src/Spring/Spring.Data/Data/UncategorizedAdoException.cs index 270cfa49..ebc879b4 100644 --- a/src/Spring/Spring.Data/Data/UncategorizedAdoException.cs +++ b/src/Spring/Spring.Data/Data/UncategorizedAdoException.cs @@ -21,114 +21,113 @@ using System.Runtime.Serialization; using Spring.Dao; -namespace Spring.Data +namespace Spring.Data; + +/// +/// Exception thrown when we can't classify a SQLException into +/// one of our generic data access exceptions. +/// +/// Mark Pollack (.NET) +[Serializable] +public class UncategorizedAdoException : UncategorizedDataAccessException, ISerializable { - /// - /// Exception thrown when we can't classify a SQLException into - /// one of our generic data access exceptions. - /// - /// Mark Pollack (.NET) - [Serializable] - public class UncategorizedAdoException : UncategorizedDataAccessException, ISerializable - { - #region Fields + #region Fields - /// - /// SQL that led to the problem - /// - private readonly string sql; + /// + /// SQL that led to the problem + /// + private readonly string sql; - /// - /// The error code, if available, that was unable to be categorized. - /// - private readonly string errorCode; + /// + /// The error code, if available, that was unable to be categorized. + /// + private readonly string errorCode; - #endregion + #endregion - #region Constructor (s) - /// - /// Initializes a new instance of the class. - /// - public UncategorizedAdoException() - { - } + #region Constructor (s) - /// - /// Initializes a new instance of the class. - /// - /// A message about the exception. - public UncategorizedAdoException(string message): base(message) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// A message about the exception. - /// The inner exception. - public UncategorizedAdoException(string message, Exception inner): base(message, inner) - { - } - - - /// - /// Initializes a new instance of the class. - /// - /// name of the current task. - /// the underlying error code that could not be translated - /// The offending SQL statment - /// The root cause. - public UncategorizedAdoException(string task, string sql, string errorCode, Exception ex) : base(task + "; uncategorized DataException for SQL [" + sql + "]; " + "ErrorCode [" + errorCode + "]; " + ex.Message, ex) - { - this.sql = sql; - this.errorCode = errorCode; - } - - /// - protected UncategorizedAdoException( SerializationInfo info, StreamingContext context ) : base( info, context ) {} - - #endregion - - #region Properties - - /// - /// Return the underlying error code if available from the underlying provider. - /// - public string ErrorCode - { - get { return errorCode; } - } - - /// - /// Return the SQL that resulted in this exception. - /// - public string Sql - { - get { return sql; } - } - - #endregion - - #region Methods - - #endregion - - #region ISerializable Members - - /// - /// When overridden in a derived class, sets the - /// with information about the exception. - /// - /// The that holds the serialized object data about the exception being thrown. - /// The that contains contextual information about the source or destination. - /// The parameter is a null reference ( in Visual Basic). - public override void GetObjectData(SerializationInfo info, StreamingContext context) - { - info.AddValue( "sql", sql ); - info.AddValue( "errorCode", errorCode); - base.GetObjectData( info, context ); - } - - #endregion + /// + /// Initializes a new instance of the class. + /// + public UncategorizedAdoException() + { } + + /// + /// Initializes a new instance of the class. + /// + /// A message about the exception. + public UncategorizedAdoException(string message) : base(message) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// A message about the exception. + /// The inner exception. + public UncategorizedAdoException(string message, Exception inner) : base(message, inner) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// name of the current task. + /// the underlying error code that could not be translated + /// The offending SQL statment + /// The root cause. + public UncategorizedAdoException(string task, string sql, string errorCode, Exception ex) : base(task + "; uncategorized DataException for SQL [" + sql + "]; " + "ErrorCode [" + errorCode + "]; " + ex.Message, ex) + { + this.sql = sql; + this.errorCode = errorCode; + } + + /// + protected UncategorizedAdoException(SerializationInfo info, StreamingContext context) : base(info, context) { } + + #endregion + + #region Properties + + /// + /// Return the underlying error code if available from the underlying provider. + /// + public string ErrorCode + { + get { return errorCode; } + } + + /// + /// Return the SQL that resulted in this exception. + /// + public string Sql + { + get { return sql; } + } + + #endregion + + #region Methods + + #endregion + + #region ISerializable Members + + /// + /// When overridden in a derived class, sets the + /// with information about the exception. + /// + /// The that holds the serialized object data about the exception being thrown. + /// The that contains contextual information about the source or destination. + /// The parameter is a null reference ( in Visual Basic). + public override void GetObjectData(SerializationInfo info, StreamingContext context) + { + info.AddValue("sql", sql); + info.AddValue("errorCode", errorCode); + base.GetObjectData(info, context); + } + + #endregion } diff --git a/src/Spring/Spring.Data/Transaction/CannotCreateTransactionException.cs b/src/Spring/Spring.Data/Transaction/CannotCreateTransactionException.cs index eace762e..44f75a86 100644 --- a/src/Spring/Spring.Data/Transaction/CannotCreateTransactionException.cs +++ b/src/Spring/Spring.Data/Transaction/CannotCreateTransactionException.cs @@ -20,47 +20,50 @@ using System.Runtime.Serialization; -namespace Spring.Transaction +namespace Spring.Transaction; + +/// +/// Exception thrown when a transaction can't be created using an +/// underlying transaction API such as COM+. +/// +/// Rod Johnson +/// Griffin Caprio (.NET) +[Serializable] +public class CannotCreateTransactionException : TransactionException { - /// - /// Exception thrown when a transaction can't be created using an - /// underlying transaction API such as COM+. - /// - /// Rod Johnson - /// Griffin Caprio (.NET) - [Serializable] - public class CannotCreateTransactionException : TransactionException - { - /// - /// Creates a new instance of the - /// class. - /// - public CannotCreateTransactionException() {} + /// + /// Creates a new instance of the + /// class. + /// + public CannotCreateTransactionException() { } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - public CannotCreateTransactionException( string message ) : base( message ) {} + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + public CannotCreateTransactionException(string message) : base(message) { } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception that is being wrapped. - /// - public CannotCreateTransactionException( string message, Exception rootCause) - : base( message , rootCause ) {} + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception that is being wrapped. + /// + public CannotCreateTransactionException(string message, Exception rootCause) + : base(message, rootCause) + { + } - /// - protected CannotCreateTransactionException( - SerializationInfo info, StreamingContext context ) : base( info, context ) {} - } + /// + protected CannotCreateTransactionException( + SerializationInfo info, StreamingContext context) : base(info, context) + { + } } diff --git a/src/Spring/Spring.Data/Transaction/Config/AttributeDrivenObjectDefinitionParser.cs b/src/Spring/Spring.Data/Transaction/Config/AttributeDrivenObjectDefinitionParser.cs index f4ae057c..58b0d9aa 100644 --- a/src/Spring/Spring.Data/Transaction/Config/AttributeDrivenObjectDefinitionParser.cs +++ b/src/Spring/Spring.Data/Transaction/Config/AttributeDrivenObjectDefinitionParser.cs @@ -25,103 +25,100 @@ using Spring.Objects.Factory.Support; using Spring.Objects.Factory.Xml; using Spring.Transaction.Interceptor; -namespace Spring.Transaction.Config +namespace Spring.Transaction.Config; + +/// +/// IObjectDefinitionParser implementation that allows users to easily configure all the +/// infrastructure objects required to enable attribute-driven transction demarcation. +/// +/// Rob Harrop +/// Juergen Hoeller +/// Mark Pollack (.NET) +public class AttributeDrivenObjectDefinitionParser : AbstractObjectDefinitionParser { /// - /// IObjectDefinitionParser implementation that allows users to easily configure all the - /// infrastructure objects required to enable attribute-driven transction demarcation. + /// The 'proxy-target-type' attribute /// - /// Rob Harrop - /// Juergen Hoeller - /// Mark Pollack (.NET) - public class AttributeDrivenObjectDefinitionParser : AbstractObjectDefinitionParser + private static readonly string PROXY_TARGET_TYPE = "proxy-target-type"; + + /// + /// The 'order' property/attribute + /// + private static readonly string ORDER = "order"; + + /// + /// Central template method to actually parse the supplied XmlElement + /// into one or more IObjectDefinitions. + /// + /// The element that is to be parsed into one or more s + /// The the object encapsulating the current state of the parsing process; + /// provides access to a + /// + /// The primary IObjectDefinition resulting from the parsing of the supplied XmlElement + /// + protected override AbstractObjectDefinition ParseInternal(XmlElement element, ParserContext parserContext) { - /// - /// The 'proxy-target-type' attribute - /// - private static readonly string PROXY_TARGET_TYPE = "proxy-target-type"; + ConfigureAutoProxyCreator(parserContext, element); - /// - /// The 'order' property/attribute - /// - private static readonly string ORDER = "order"; + //Create the TransactionAttributeSource + RootObjectDefinition sourceDef = new RootObjectDefinition(typeof(AttributesTransactionAttributeSource)); + sourceDef.Role = ObjectRole.ROLE_INFRASTRUCTURE; + string sourceName = parserContext.ReaderContext.RegisterWithGeneratedName(sourceDef); - /// - /// Central template method to actually parse the supplied XmlElement - /// into one or more IObjectDefinitions. - /// - /// The element that is to be parsed into one or more s - /// The the object encapsulating the current state of the parsing process; - /// provides access to a - /// - /// The primary IObjectDefinition resulting from the parsing of the supplied XmlElement - /// - protected override AbstractObjectDefinition ParseInternal(XmlElement element, ParserContext parserContext) + //Create the TransactionInterceptor definition. + RootObjectDefinition interceptorDefinition = new RootObjectDefinition(typeof(TransactionInterceptor)); + interceptorDefinition.Role = ObjectRole.ROLE_INFRASTRUCTURE; + RegisterTransactionManager(element, interceptorDefinition); + interceptorDefinition.PropertyValues.Add(TxNamespaceUtils.TRANSACTION_ATTRIBUTE_SOURCE, new RuntimeObjectReference(sourceName)); + String interceptorName = parserContext.ReaderContext.RegisterWithGeneratedName(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)) { - ConfigureAutoProxyCreator(parserContext, element); - - //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; - RegisterTransactionManager(element, interceptorDefinition); - interceptorDefinition.PropertyValues.Add(TxNamespaceUtils.TRANSACTION_ATTRIBUTE_SOURCE, new RuntimeObjectReference(sourceName)); - String interceptorName = parserContext.ReaderContext.RegisterWithGeneratedName(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)) - { - advisorDef.PropertyValues.Add(ORDER, GetAttributeValue(element, ORDER)); - } - - return advisorDef; + advisorDef.PropertyValues.Add(ORDER, GetAttributeValue(element, ORDER)); } - private void RegisterTransactionManager(XmlElement element, RootObjectDefinition interceptorDefinition) + 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)); + } + + /// + /// Configures the auto proxy creator. + /// + /// The parser context. + /// The element. + private static void ConfigureAutoProxyCreator(ParserContext parserContext, XmlElement element) + { + AopNamespaceUtils.RegisterAutoProxyCreatorIfNecessary(parserContext, element); + + bool proxyTargetClass = parserContext.ParserHelper.IsTrueStringValue(GetAttributeValue(element, PROXY_TARGET_TYPE)); + if (proxyTargetClass) { - string transactionManagerName = GetAttributeValue(element, TxNamespaceUtils.TRANSACTION_MANAGER_ATTRIBUTE); - interceptorDefinition.PropertyValues.Add(TxNamespaceUtils.TRANSACTION_MANAGER_PROPERTY, - new RuntimeObjectReference(transactionManagerName)); - - - } - - /// - /// Configures the auto proxy creator. - /// - /// The parser context. - /// The element. - private static void ConfigureAutoProxyCreator(ParserContext parserContext, XmlElement element) - { - AopNamespaceUtils.RegisterAutoProxyCreatorIfNecessary(parserContext, element); - - bool proxyTargetClass = parserContext.ParserHelper.IsTrueStringValue(GetAttributeValue(element, PROXY_TARGET_TYPE)); - if (proxyTargetClass) - { - AopNamespaceUtils.ForceAutoProxyCreatorToUseDecoratorProxy(parserContext.Registry); - } - } - - /// - /// Gets a value indicating whether an ID should be generated instead of read - /// from the passed in XmlElement. - /// - /// true if should generate id; otherwise, false. - /// Note that this flag is about always generating an ID; the parser - /// won't even check for an "id" attribute in this case. - /// - protected override bool ShouldGenerateId - { - get { return true; } + AopNamespaceUtils.ForceAutoProxyCreatorToUseDecoratorProxy(parserContext.Registry); } } + + /// + /// Gets a value indicating whether an ID should be generated instead of read + /// from the passed in XmlElement. + /// + /// true if should generate id; otherwise, false. + /// Note that this flag is about always generating an ID; the parser + /// won't even check for an "id" attribute in this case. + /// + protected override bool ShouldGenerateId + { + get { return true; } + } } diff --git a/src/Spring/Spring.Data/Transaction/Config/TxAdviceObjectDefinitionParser.cs b/src/Spring/Spring.Data/Transaction/Config/TxAdviceObjectDefinitionParser.cs index 196f1e86..6c7ede55 100644 --- a/src/Spring/Spring.Data/Transaction/Config/TxAdviceObjectDefinitionParser.cs +++ b/src/Spring/Spring.Data/Transaction/Config/TxAdviceObjectDefinitionParser.cs @@ -26,145 +26,146 @@ using Spring.Objects.Factory.Xml; using Spring.Transaction.Interceptor; using Spring.Util; -namespace Spring.Transaction.Config +namespace Spring.Transaction.Config; + +/// +/// The for the <tx:advice> tag. +/// +/// Rob Harrop +/// Juergen Hoeller +/// Adrian Colyer +/// Mark Pollack (.NET) +public class TxAdviceObjectDefinitionParser : AbstractSingleObjectDefinitionParser { - /// - /// The for the <tx:advice> tag. - /// - /// Rob Harrop - /// Juergen Hoeller - /// Adrian Colyer - /// Mark Pollack (.NET) - public class TxAdviceObjectDefinitionParser : AbstractSingleObjectDefinitionParser + private static string TIMEOUT = "timeout"; + + private static string READ_ONLY = "read-only"; + + private static string NAME_MAP = "nameMap"; + + private static string PROPAGATION = "propagation"; + + private static string ISOLATION = "isolation"; + + private static string ROLLBACK_FOR = "rollback-for"; + + private static string NO_ROLLBACK_FOR = "no-rollback-for"; + + protected override Type GetObjectType(XmlElement element) { - private static string TIMEOUT = "timeout"; + return typeof(TransactionInterceptor); + } - private static string READ_ONLY = "read-only"; - - private static string NAME_MAP = "nameMap"; - - private static string PROPAGATION = "propagation"; - - private static string ISOLATION = "isolation"; - - private static string ROLLBACK_FOR = "rollback-for"; - - private static string NO_ROLLBACK_FOR = "no-rollback-for"; - - protected override Type GetObjectType(XmlElement element) + protected override void DoParse(XmlElement element, ParserContext parserContext, ObjectDefinitionBuilder builder) + { + builder.AddPropertyReference(TxNamespaceUtils.TRANSACTION_MANAGER_PROPERTY, + GetAttributeValue(element, TxNamespaceUtils.TRANSACTION_MANAGER_ATTRIBUTE)); + XmlNodeList txAttributes = element.SelectNodes("*[local-name()='attributes' and namespace-uri()='" + element.NamespaceURI + "']"); + if (txAttributes.Count > 1) { - return typeof (TransactionInterceptor); + parserContext.ReaderContext.ReportException(element, "tx advice", "Element is allowed at most once inside element "); + } + else if (txAttributes.Count == 1) + { + //using xml defined source + XmlElement attributeSourceElement = txAttributes[0] as XmlElement; + AbstractObjectDefinition attributeSourceDefinition = + ParseAttributeSource(attributeSourceElement, parserContext); + builder.AddPropertyValue(TxNamespaceUtils.TRANSACTION_ATTRIBUTE_SOURCE, attributeSourceDefinition); + } + else + { + //Assume attibutes source + ObjectDefinitionBuilder txAttributeSourceBuilder = + parserContext.ParserHelper.CreateRootObjectDefinitionBuilder(typeof(AttributesTransactionAttributeSource)); + + builder.AddPropertyValue(TxNamespaceUtils.TRANSACTION_ATTRIBUTE_SOURCE, + txAttributeSourceBuilder.ObjectDefinition); + } + } + + private AbstractObjectDefinition ParseAttributeSource(XmlElement element, ParserContext parserContext) + { + XmlNodeList methods = element.SelectNodes("*[local-name()='method' and namespace-uri()='" + element.NamespaceURI + "']"); + ManagedDictionary transactionAttributeMap = new ManagedDictionary(); + foreach (XmlElement methodElement in methods) + { + string name = GetAttributeValue(methodElement, "name"); + TypedStringValue nameHolder = new TypedStringValue(name); + + RuleBasedTransactionAttribute attribute = new RuleBasedTransactionAttribute(); + string propagation = GetAttributeValue(methodElement, PROPAGATION); + string isolation = GetAttributeValue(methodElement, ISOLATION); + string timeout = GetAttributeValue(methodElement, TIMEOUT); + string readOnly = GetAttributeValue(methodElement, READ_ONLY); + if (StringUtils.HasText(propagation)) + { + attribute.PropagationBehavior = (TransactionPropagation) Enum.Parse(typeof(TransactionPropagation), propagation, true); + } + + if (StringUtils.HasText(isolation)) + { + attribute.TransactionIsolationLevel = + (IsolationLevel) Enum.Parse(typeof(IsolationLevel), isolation, true); + } + + if (StringUtils.HasText(timeout)) + { + try + { + attribute.TransactionTimeout = Int32.Parse(timeout); + } + catch (FormatException ex) + { + parserContext.ReaderContext.ReportException(methodElement, "tx advice", "timeout must be an integer value: [" + timeout + "]", ex); + } + } + + if (StringUtils.HasText(readOnly)) + { + attribute.ReadOnly = Boolean.Parse(GetAttributeValue(methodElement, READ_ONLY)); + } + + var rollbackRules = new List(); + if (methodElement.HasAttribute(ROLLBACK_FOR)) + { + string rollbackForValue = GetAttributeValue(methodElement, ROLLBACK_FOR); + AddRollbackRuleAttributesTo(rollbackRules, rollbackForValue); + } + + if (methodElement.HasAttribute(NO_ROLLBACK_FOR)) + { + string noRollbackForValue = GetAttributeValue(methodElement, NO_ROLLBACK_FOR); + AddNoRollbackRuleAttributesTo(rollbackRules, noRollbackForValue); + } + + attribute.RollbackRules = rollbackRules; + + transactionAttributeMap[nameHolder] = attribute; } - protected override void DoParse(XmlElement element, ParserContext parserContext, ObjectDefinitionBuilder builder) + ObjectDefinitionBuilder builder = parserContext + .ParserHelper + .CreateRootObjectDefinitionBuilder(typeof(NameMatchTransactionAttributeSource)); + builder.AddPropertyValue(NAME_MAP, transactionAttributeMap); + return builder.ObjectDefinition; + } + + private void AddRollbackRuleAttributesTo(List rollbackRules, string rollbackForValue) + { + string[] exceptionTypeNames = StringUtils.CommaDelimitedListToStringArray(rollbackForValue); + foreach (string exceptionTypeName in exceptionTypeNames) { - - builder.AddPropertyReference(TxNamespaceUtils.TRANSACTION_MANAGER_PROPERTY, - GetAttributeValue(element, TxNamespaceUtils.TRANSACTION_MANAGER_ATTRIBUTE)); - XmlNodeList txAttributes = element.SelectNodes("*[local-name()='attributes' and namespace-uri()='" + element.NamespaceURI + "']"); - if (txAttributes.Count > 1 ) - { - parserContext.ReaderContext.ReportException(element, "tx advice", "Element is allowed at most once inside element "); - } - else if (txAttributes.Count == 1) - { - //using xml defined source - XmlElement attributeSourceElement = txAttributes[0] as XmlElement; - AbstractObjectDefinition attributeSourceDefinition = - ParseAttributeSource(attributeSourceElement, parserContext); - builder.AddPropertyValue(TxNamespaceUtils.TRANSACTION_ATTRIBUTE_SOURCE, attributeSourceDefinition); - } - else - { - //Assume attibutes source - ObjectDefinitionBuilder txAttributeSourceBuilder = - parserContext.ParserHelper.CreateRootObjectDefinitionBuilder(typeof (AttributesTransactionAttributeSource)); - - builder.AddPropertyValue(TxNamespaceUtils.TRANSACTION_ATTRIBUTE_SOURCE, - txAttributeSourceBuilder.ObjectDefinition); - - } + rollbackRules.Add(new RollbackRuleAttribute(exceptionTypeName.Trim())); } + } - private AbstractObjectDefinition ParseAttributeSource(XmlElement element, ParserContext parserContext) + private void AddNoRollbackRuleAttributesTo(List rollbackRules, string noRollbackForValue) + { + string[] exceptionTypeNames = StringUtils.CommaDelimitedListToStringArray(noRollbackForValue); + foreach (string exceptionTypeName in exceptionTypeNames) { - XmlNodeList methods = element.SelectNodes("*[local-name()='method' and namespace-uri()='" + element.NamespaceURI + "']"); - ManagedDictionary transactionAttributeMap = new ManagedDictionary(); - foreach (XmlElement methodElement in methods) - { - string name = GetAttributeValue(methodElement, "name"); - TypedStringValue nameHolder = new TypedStringValue(name); - - RuleBasedTransactionAttribute attribute = new RuleBasedTransactionAttribute(); - string propagation = GetAttributeValue(methodElement, PROPAGATION); - string isolation = GetAttributeValue(methodElement, ISOLATION); - string timeout = GetAttributeValue(methodElement, TIMEOUT); - string readOnly = GetAttributeValue(methodElement, READ_ONLY); - if (StringUtils.HasText(propagation)) - { - attribute.PropagationBehavior = (TransactionPropagation) Enum.Parse(typeof (TransactionPropagation), propagation, true); - } - if (StringUtils.HasText(isolation)) - { - attribute.TransactionIsolationLevel = - (IsolationLevel) Enum.Parse(typeof (IsolationLevel), isolation, true); - } - if (StringUtils.HasText(timeout)) - { - try - { - attribute.TransactionTimeout = Int32.Parse(timeout); - } - catch (FormatException ex) - { - parserContext.ReaderContext.ReportException(methodElement,"tx advice","timeout must be an integer value: [" + timeout + "]", ex); - } - } - if (StringUtils.HasText(readOnly)) - { - attribute.ReadOnly = Boolean.Parse(GetAttributeValue(methodElement, READ_ONLY)); - } - - var rollbackRules = new List(); - if (methodElement.HasAttribute(ROLLBACK_FOR)) - { - string rollbackForValue = GetAttributeValue(methodElement, ROLLBACK_FOR); - AddRollbackRuleAttributesTo(rollbackRules, rollbackForValue); - } - if (methodElement.HasAttribute(NO_ROLLBACK_FOR)) - { - string noRollbackForValue = GetAttributeValue(methodElement, NO_ROLLBACK_FOR); - AddNoRollbackRuleAttributesTo(rollbackRules, noRollbackForValue); - } - attribute.RollbackRules = rollbackRules; - - transactionAttributeMap[nameHolder] = attribute; - } - - ObjectDefinitionBuilder builder = parserContext - .ParserHelper - .CreateRootObjectDefinitionBuilder(typeof (NameMatchTransactionAttributeSource)); - builder.AddPropertyValue(NAME_MAP, transactionAttributeMap); - return builder.ObjectDefinition; - - } - - private void AddRollbackRuleAttributesTo(List rollbackRules, string rollbackForValue) - { - string[] exceptionTypeNames = StringUtils.CommaDelimitedListToStringArray(rollbackForValue); - foreach (string exceptionTypeName in exceptionTypeNames) - { - rollbackRules.Add(new RollbackRuleAttribute(exceptionTypeName.Trim())); - } - } - - private void AddNoRollbackRuleAttributesTo(List rollbackRules, string noRollbackForValue) - { - string[] exceptionTypeNames = StringUtils.CommaDelimitedListToStringArray(noRollbackForValue); - foreach (string exceptionTypeName in exceptionTypeNames) - { - rollbackRules.Add(new NoRollbackRuleAttribute(exceptionTypeName.Trim())); - } + rollbackRules.Add(new NoRollbackRuleAttribute(exceptionTypeName.Trim())); } } } diff --git a/src/Spring/Spring.Data/Transaction/Config/TxNamespaceParser.cs b/src/Spring/Spring.Data/Transaction/Config/TxNamespaceParser.cs index f70c269b..84ed4bda 100644 --- a/src/Spring/Spring.Data/Transaction/Config/TxNamespaceParser.cs +++ b/src/Spring/Spring.Data/Transaction/Config/TxNamespaceParser.cs @@ -18,42 +18,39 @@ #endregion - using Spring.Objects.Factory.Xml; -namespace Spring.Transaction.Config +namespace Spring.Transaction.Config; + +/// +/// NamespaceParser allowing for the configuration of +/// declarative transaction management using either XML or using attributes. +/// +/// This namespace handler is the central piece of functionality in the +/// Spring transaction management facilities and offers two appraoches +/// to declaratively manage transactions. +/// +/// One approach uses transaction semantics defined in XML using the +/// <tx:advice> elements, the other uses attributes +/// in combination with the <tx:annotation-driven> element. +/// Both approached are detailed in the Spring reference manual. +/// +[ + NamespaceParser( + Namespace = "http://www.springframework.net/tx", + SchemaLocationAssemblyHint = typeof(TxNamespaceParser), + SchemaLocation = "/Spring.Transaction.Config/spring-tx-1.1.xsd" + ) +] +public class TxNamespaceParser : NamespaceParserSupport { /// - /// NamespaceParser allowing for the configuration of - /// declarative transaction management using either XML or using attributes. - /// - /// This namespace handler is the central piece of functionality in the - /// Spring transaction management facilities and offers two appraoches - /// to declaratively manage transactions. - /// - /// One approach uses transaction semantics defined in XML using the - /// <tx:advice> elements, the other uses attributes - /// in combination with the <tx:annotation-driven> element. - /// Both approached are detailed in the Spring reference manual. + /// Register the for the 'advice' and + /// 'attribute-driven' tags. /// - [ - NamespaceParser( - Namespace = "http://www.springframework.net/tx", - SchemaLocationAssemblyHint = typeof(TxNamespaceParser), - SchemaLocation = "/Spring.Transaction.Config/spring-tx-1.1.xsd" - ) - ] - public class TxNamespaceParser : NamespaceParserSupport + public override void Init() { - /// - /// Register the for the 'advice' and - /// 'attribute-driven' tags. - /// - public override void Init() - { - RegisterObjectDefinitionParser("advice", new TxAdviceObjectDefinitionParser()); - RegisterObjectDefinitionParser("attribute-driven", new AttributeDrivenObjectDefinitionParser()); - - } + RegisterObjectDefinitionParser("advice", new TxAdviceObjectDefinitionParser()); + RegisterObjectDefinitionParser("attribute-driven", new AttributeDrivenObjectDefinitionParser()); } } diff --git a/src/Spring/Spring.Data/Transaction/Config/TxNamespaceUtils.cs b/src/Spring/Spring.Data/Transaction/Config/TxNamespaceUtils.cs index 7da864f4..223133d0 100644 --- a/src/Spring/Spring.Data/Transaction/Config/TxNamespaceUtils.cs +++ b/src/Spring/Spring.Data/Transaction/Config/TxNamespaceUtils.cs @@ -20,30 +20,27 @@ using Spring.Core; -namespace Spring.Transaction.Config +namespace Spring.Transaction.Config; + +/// +/// This is a utility class to help in parsing the transaction namespace +/// +/// Mark Pollack +public sealed class TxNamespaceUtils { /// - /// This is a utility class to help in parsing the transaction namespace + /// The transaction manager attribute /// - /// Mark Pollack - public sealed class TxNamespaceUtils - { - /// - /// The transaction manager attribute - /// - public const string TRANSACTION_MANAGER_ATTRIBUTE = "transaction-manager"; + public const string TRANSACTION_MANAGER_ATTRIBUTE = "transaction-manager"; - /// - /// The source of transaction metadata - /// - public const string TRANSACTION_ATTRIBUTE_SOURCE = "transactionAttributeSource"; + /// + /// The source of transaction metadata + /// + public const string TRANSACTION_ATTRIBUTE_SOURCE = "transactionAttributeSource"; - /// - /// The property asociated with the transaction manager xml element - /// - public static readonly string TRANSACTION_MANAGER_PROPERTY = - Conventions.AttributeNameToPropertyName(TRANSACTION_MANAGER_ATTRIBUTE); - - - } + /// + /// The property asociated with the transaction manager xml element + /// + public static readonly string TRANSACTION_MANAGER_PROPERTY = + Conventions.AttributeNameToPropertyName(TRANSACTION_MANAGER_ATTRIBUTE); } \ No newline at end of file diff --git a/src/Spring/Spring.Data/Transaction/Config/spring-tx-1.1.xsd b/src/Spring/Spring.Data/Transaction/Config/spring-tx-1.1.xsd index 3759bad6..157d90c3 100644 --- a/src/Spring/Spring.Data/Transaction/Config/spring-tx-1.1.xsd +++ b/src/Spring/Spring.Data/Transaction/Config/spring-tx-1.1.xsd @@ -1,48 +1,48 @@ + xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:objects="http://www.springframework.net" + xmlns:tool="http://www.springframework.net/tool" + targetNamespace="http://www.springframework.net/tx" + elementFormDefault="qualified" + attributeFormDefault="unqualified"> - - + + - - - - + + + - - - - - - + + + + + - - - - + + + + - - + - + - - - - + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + - - - - + + + + - - - - + + + - - - - - - - - - - + + + + + + + + + - - - - - + + + + - - - - + + + + - - - - - - - + + + + + + - - - - - - + + + + + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - + + + + - - - - - + + + + - - - - - + + + + - - - - - - + + + + + + diff --git a/src/Spring/Spring.Data/Transaction/HeuristicCompletionException.cs b/src/Spring/Spring.Data/Transaction/HeuristicCompletionException.cs index a3108186..7e1a6be9 100644 --- a/src/Spring/Spring.Data/Transaction/HeuristicCompletionException.cs +++ b/src/Spring/Spring.Data/Transaction/HeuristicCompletionException.cs @@ -20,104 +20,105 @@ using System.Runtime.Serialization; -namespace Spring.Transaction +namespace Spring.Transaction; + +/// +/// Exception that represents a transaction failure caused by heuristics. +/// +/// Rod Johnson +/// Juergen Hoeller +/// Griffin Caprio (.NET) +[Serializable] +public class HeuristicCompletionException : TransactionException, ISerializable { - /// - /// Exception that represents a transaction failure caused by heuristics. - /// - /// Rod Johnson - /// Juergen Hoeller - /// Griffin Caprio (.NET) - [Serializable] - public class HeuristicCompletionException : TransactionException, ISerializable - { - /// - /// The outcome state of the transaction: have some or all resources been committed? - /// - private TransactionOutcomeState _outcomeState = TransactionOutcomeState.Unknown; + /// + /// The outcome state of the transaction: have some or all resources been committed? + /// + private TransactionOutcomeState _outcomeState = TransactionOutcomeState.Unknown; - /// - /// Returns the transaction's outcome state. - /// - public TransactionOutcomeState OutcomeState - { - get { return _outcomeState; } - } + /// + /// Returns the transaction's outcome state. + /// + public TransactionOutcomeState OutcomeState + { + get { return _outcomeState; } + } - /// - /// Returns a representation of the supplied - /// . - /// - /// - /// The value that - /// is to be stringified. - /// - /// A representation. - public static string GetStateString( TransactionOutcomeState outcomeState ) - { - return Enum.GetName (typeof (TransactionOutcomeState), outcomeState); - } - - /// - /// Creates a new instance of the - /// class. - /// - public HeuristicCompletionException( ) {} + /// + /// Returns a representation of the supplied + /// . + /// + /// + /// The value that + /// is to be stringified. + /// + /// A representation. + public static string GetStateString(TransactionOutcomeState outcomeState) + { + return Enum.GetName(typeof(TransactionOutcomeState), outcomeState); + } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - public HeuristicCompletionException( string message ) : base( message ) {} + /// + /// Creates a new instance of the + /// class. + /// + public HeuristicCompletionException() { } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception that is being wrapped. - /// - public HeuristicCompletionException( string message, Exception rootCause ) - : base( message, rootCause ) {} + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + public HeuristicCompletionException(string message) : base(message) { } - /// - /// Creates a new instance of the - /// class - /// with the specified - /// and inner exception. - /// - /// - /// The - /// for the transaction. - /// - /// - /// The inner exception that is being wrapped. - /// - public HeuristicCompletionException( - TransactionOutcomeState outcomeState, Exception innerException) - : base( "Heuristic completion: outcome state is " + GetStateString(outcomeState), innerException ) - { - _outcomeState = outcomeState; - } + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception that is being wrapped. + /// + public HeuristicCompletionException(string message, Exception rootCause) + : base(message, rootCause) + { + } - /// - protected HeuristicCompletionException( SerializationInfo info, StreamingContext context ) - : base( info, context ) - { - _outcomeState = ( TransactionOutcomeState ) info.GetInt32( "outcomeState" ); - } + /// + /// Creates a new instance of the + /// class + /// with the specified + /// and inner exception. + /// + /// + /// The + /// for the transaction. + /// + /// + /// The inner exception that is being wrapped. + /// + public HeuristicCompletionException( + TransactionOutcomeState outcomeState, Exception innerException) + : base("Heuristic completion: outcome state is " + GetStateString(outcomeState), innerException) + { + _outcomeState = outcomeState; + } - /// - public override void GetObjectData(SerializationInfo info, StreamingContext context) - { - info.AddValue( "outcomeState", _outcomeState ); - base.GetObjectData (info, context); - } - } + /// + protected HeuristicCompletionException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + _outcomeState = (TransactionOutcomeState) info.GetInt32("outcomeState"); + } + + /// + public override void GetObjectData(SerializationInfo info, StreamingContext context) + { + info.AddValue("outcomeState", _outcomeState); + base.GetObjectData(info, context); + } } diff --git a/src/Spring/Spring.Data/Transaction/IPlatformTransactionManager.cs b/src/Spring/Spring.Data/Transaction/IPlatformTransactionManager.cs index b6c260de..4ec9c756 100644 --- a/src/Spring/Spring.Data/Transaction/IPlatformTransactionManager.cs +++ b/src/Spring/Spring.Data/Transaction/IPlatformTransactionManager.cs @@ -18,90 +18,89 @@ #endregion -namespace Spring.Transaction +namespace Spring.Transaction; + +/// +/// This is the central interface in Spring.NET's transaction support. +/// +/// +///

+/// Applications can use this directly, but it is not primarily meant as an API. +/// Typically, applications will work with either +/// or the AOP transaction +/// interceptor. +///

+///

+/// For implementers, +/// is a good starting point. +///

+///
+/// Rod Johnson +/// Juergen Hoeller +/// Griffin Caprio (.NET) +public interface IPlatformTransactionManager { - /// - /// This is the central interface in Spring.NET's transaction support. - /// - /// - ///

- /// Applications can use this directly, but it is not primarily meant as an API. - /// Typically, applications will work with either - /// or the AOP transaction - /// interceptor. + ///

+ /// Return a currently active transaction or create a new one. + /// + /// + ///

+ /// Note that parameters like isolation level or timeout will only be applied + /// to new transactions, and thus be ignored when participating in active ones. + /// Furthermore, they aren't supported by every transaction manager: + /// a proper implementation should throw an exception when custom values + /// that it doesn't support are specified. + ///

+ ///
+ /// + /// instance (can be null for + /// defaults), describing propagation behavior, isolation level, timeout etc. + /// + /// + /// In case of lookup, creation, or system errors. + /// + /// + /// A representing the new or current transaction. + /// + ITransactionStatus GetTransaction(ITransactionDefinition definition); + + /// + /// Commit the given transaction, with regard to its status. + /// + /// + ///

+ /// If the transaction has been marked rollback-only programmatically, + /// perform a rollback. ///

///

- /// For implementers, - /// is a good starting point. + /// If the transaction wasn't a new one, omit the commit to take part + /// in the surrounding transaction properly. ///

- ///
- /// Rod Johnson - /// Juergen Hoeller - /// Griffin Caprio (.NET) - public interface IPlatformTransactionManager - { - /// - /// Return a currently active transaction or create a new one. - /// - /// - ///

- /// Note that parameters like isolation level or timeout will only be applied - /// to new transactions, and thus be ignored when participating in active ones. - /// Furthermore, they aren't supported by every transaction manager: - /// a proper implementation should throw an exception when custom values - /// that it doesn't support are specified. - ///

- ///
- /// - /// instance (can be null for - /// defaults), describing propagation behavior, isolation level, timeout etc. - /// - /// - /// In case of lookup, creation, or system errors. - /// - /// - /// A representing the new or current transaction. - /// - ITransactionStatus GetTransaction( ITransactionDefinition definition ); + ///
+ /// + /// The instance returned by the + /// () method. + /// + /// + /// In case of commit or system errors + /// + void Commit(ITransactionStatus transactionStatus); - /// - /// Commit the given transaction, with regard to its status. - /// - /// - ///

- /// If the transaction has been marked rollback-only programmatically, - /// perform a rollback. - ///

- ///

- /// If the transaction wasn't a new one, omit the commit to take part - /// in the surrounding transaction properly. - ///

- ///
- /// - /// The instance returned by the - /// () method. - /// - /// - /// In case of commit or system errors - /// - void Commit( ITransactionStatus transactionStatus ); - - /// - /// Roll back the given transaction, with regard to its status. - /// - /// - ///

- /// If the transaction wasn't a new one, just set it rollback-only - /// to take part in the surrounding transaction properly. - ///

- ///
- /// - /// The instance returned by the - /// () method. - /// - /// - /// In case of system errors. - /// - void Rollback( ITransactionStatus transactionStatus ); - } + /// + /// Roll back the given transaction, with regard to its status. + /// + /// + ///

+ /// If the transaction wasn't a new one, just set it rollback-only + /// to take part in the surrounding transaction properly. + ///

+ ///
+ /// + /// The instance returned by the + /// () method. + /// + /// + /// In case of system errors. + /// + void Rollback(ITransactionStatus transactionStatus); } diff --git a/src/Spring/Spring.Data/Transaction/ISavepointManager.cs b/src/Spring/Spring.Data/Transaction/ISavepointManager.cs index 6f5f38c7..dcebe210 100644 --- a/src/Spring/Spring.Data/Transaction/ISavepointManager.cs +++ b/src/Spring/Spring.Data/Transaction/ISavepointManager.cs @@ -1,4 +1,5 @@ #region License + /* * Copyright 2002-2010 the original author or authors. * @@ -14,83 +15,83 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + #endregion -namespace Spring.Transaction +namespace Spring.Transaction; + +/// +/// Interface that specifies means to programmatically manage +/// transaction savepoints in a generic fashion. +/// +/// +///

+/// Note that savepoints can only work within an active transaction. +/// Just use this programmatic savepoint handling for advanced needs; +/// else, a subtransaction with a value +/// of is preferable. +///

+///
+/// Juergen Hoeller +/// Griffin Caprio (.NET) +public interface ISavepointManager { - /// - /// Interface that specifies means to programmatically manage - /// transaction savepoints in a generic fashion. - /// - /// - ///

- /// Note that savepoints can only work within an active transaction. - /// Just use this programmatic savepoint handling for advanced needs; - /// else, a subtransaction with a value - /// of is preferable. - ///

- ///
- /// Juergen Hoeller - /// Griffin Caprio (.NET) - public interface ISavepointManager - { - /// - /// Create a new savepoint. - /// - /// - /// The name of the savepoint to create. - /// - /// - /// You can roll back to a specific savepoint - /// via , - /// and explicitly release a savepoint that you don't need anymore via - /// . - ///

- /// Note that most transaction managers will automatically release - /// savepoints at transaction completion. - ///

- ///
- /// - /// If the savepoint could not be created, - /// either because the backend does not support it or because the - /// transaction is not in an appropriate state. - /// - /// - /// A savepoint object, to be passed into - /// - /// or . - /// - void CreateSavepoint( string savepointName ); + /// + /// Create a new savepoint. + /// + /// + /// The name of the savepoint to create. + /// + /// + /// You can roll back to a specific savepoint + /// via , + /// and explicitly release a savepoint that you don't need anymore via + /// . + ///

+ /// Note that most transaction managers will automatically release + /// savepoints at transaction completion. + ///

+ ///
+ /// + /// If the savepoint could not be created, + /// either because the backend does not support it or because the + /// transaction is not in an appropriate state. + /// + /// + /// A savepoint object, to be passed into + /// + /// or . + /// + void CreateSavepoint(string savepointName); - /// - /// Roll back to the given savepoint. - /// - /// - /// The savepoint will be automatically released afterwards. - /// - /// The savepoint to roll back to. - /// - /// If the rollback failed. - /// - void RollbackToSavepoint( string savepoint ); + /// + /// Roll back to the given savepoint. + /// + /// + /// The savepoint will be automatically released afterwards. + /// + /// The savepoint to roll back to. + /// + /// If the rollback failed. + /// + void RollbackToSavepoint(string savepoint); - /// - /// Explicitly release the given savepoint. - /// - /// - ///

- /// Note that most transaction managers will automatically release - /// savepoints at transaction completion. - ///

- ///

- /// Implementations should fail as silently as possible if - /// proper resource cleanup will still happen at transaction completion. - ///

- ///
- /// The savepoint to release. - /// - /// If the release failed. - /// - void ReleaseSavepoint( string savepoint ); - } -} + /// + /// Explicitly release the given savepoint. + /// + /// + ///

+ /// Note that most transaction managers will automatically release + /// savepoints at transaction completion. + ///

+ ///

+ /// Implementations should fail as silently as possible if + /// proper resource cleanup will still happen at transaction completion. + ///

+ ///
+ /// The savepoint to release. + /// + /// If the release failed. + /// + void ReleaseSavepoint(string savepoint); +} \ No newline at end of file diff --git a/src/Spring/Spring.Data/Transaction/ITransactionDefinition.cs b/src/Spring/Spring.Data/Transaction/ITransactionDefinition.cs index ab35760a..f8993dc0 100644 --- a/src/Spring/Spring.Data/Transaction/ITransactionDefinition.cs +++ b/src/Spring/Spring.Data/Transaction/ITransactionDefinition.cs @@ -20,100 +20,99 @@ using System.Data; -namespace Spring.Transaction +namespace Spring.Transaction; + +/// +/// Interface for classes that define transaction properties. Base interface for +/// . +/// +/// +///

+/// Note that isolation level, timeout and read-only settings will only +/// get applied when starting a new transaction. As only +/// and +/// can actually cause that, it doesn't make sense +/// to specify any of those settings else. Furthermore, not all transaction +/// managers will support those features and thus throw respective exceptions +/// when given non-default values. +///

+///
+/// Griffin Caprio (.NET) +/// Mark Pollack (.NET) +public interface ITransactionDefinition { - /// - /// Interface for classes that define transaction properties. Base interface for - /// . + /// + /// Return the propagation behavior of type + /// . + /// + TransactionPropagation PropagationBehavior { get; } + + /// + /// Return the isolation level of type . /// /// ///

- /// Note that isolation level, timeout and read-only settings will only - /// get applied when starting a new transaction. As only + /// Only makes sense in combination with /// and - /// can actually cause that, it doesn't make sense - /// to specify any of those settings else. Furthermore, not all transaction - /// managers will support those features and thus throw respective exceptions - /// when given non-default values. + /// . + ///

+ ///

+ /// Note that a transaction manager that does not support custom isolation levels + /// will throw an exception when given any other level than + /// . ///

///
- /// Griffin Caprio (.NET) - /// Mark Pollack (.NET) - public interface ITransactionDefinition - { - /// - /// Return the propagation behavior of type - /// . - /// - TransactionPropagation PropagationBehavior { get; } + IsolationLevel TransactionIsolationLevel { get; } - /// - /// Return the isolation level of type . - /// - /// - ///

- /// Only makes sense in combination with - /// and - /// . - ///

- ///

- /// Note that a transaction manager that does not support custom isolation levels - /// will throw an exception when given any other level than - /// . - ///

- ///
- IsolationLevel TransactionIsolationLevel { get; } + /// + /// Return the transaction timeout. + /// + /// + ///

+ /// Must return a number of seconds, or -1. + /// Only makes sense in combination with + /// and + /// . + /// Note that a transaction manager that does not support timeouts will + /// throw an exception when given any other timeout than -1. + ///

+ ///
+ int TransactionTimeout { get; } - /// - /// Return the transaction timeout. - /// - /// - ///

- /// Must return a number of seconds, or -1. - /// Only makes sense in combination with - /// and - /// . - /// Note that a transaction manager that does not support timeouts will - /// throw an exception when given any other timeout than -1. - ///

- ///
- int TransactionTimeout { get; } + /// + /// Get whether to optimize as read-only transaction. + /// + /// + ///

+ /// This just serves as hint for the actual transaction subsystem, + /// it will not necessarily cause failure of write accesses. + ///

+ ///

+ /// Only makes sense in combination with + /// and + /// . + ///

+ ///

+ /// A transaction manager that cannot interpret the read-only hint + /// will not throw an exception when given ReadOnly=true. + ///

+ ///
+ bool ReadOnly { get; } - /// - /// Get whether to optimize as read-only transaction. - /// - /// - ///

- /// This just serves as hint for the actual transaction subsystem, - /// it will not necessarily cause failure of write accesses. - ///

- ///

- /// Only makes sense in combination with - /// and - /// . - ///

- ///

- /// A transaction manager that cannot interpret the read-only hint - /// will not throw an exception when given ReadOnly=true. - ///

- ///
- bool ReadOnly { get; } + /// + /// Return the name of this transaction. Can be null. + /// + /// + /// This will be used as a transaction name to be shown in a + /// transaction monitor, if applicable. In the case of Spring + /// declarative transactions, the exposed name will be the fully + /// qualified type name + "." method name + assembly (by default). + /// + string Name { get; } - /// - /// Return the name of this transaction. Can be null. - /// - /// - /// This will be used as a transaction name to be shown in a - /// transaction monitor, if applicable. In the case of Spring - /// declarative transactions, the exposed name will be the fully - /// qualified type name + "." method name + assembly (by default). - /// - string Name { get; } - - /// - /// Gets the async flow option. - /// - /// The async flow option. - System.Transactions.TransactionScopeAsyncFlowOption AsyncFlowOption { get;} - } + /// + /// Gets the async flow option. + /// + /// The async flow option. + System.Transactions.TransactionScopeAsyncFlowOption AsyncFlowOption { get; } } diff --git a/src/Spring/Spring.Data/Transaction/ITransactionStatus.cs b/src/Spring/Spring.Data/Transaction/ITransactionStatus.cs index 11f455c6..c77d3a4d 100644 --- a/src/Spring/Spring.Data/Transaction/ITransactionStatus.cs +++ b/src/Spring/Spring.Data/Transaction/ITransactionStatus.cs @@ -18,66 +18,65 @@ #endregion -namespace Spring.Transaction +namespace Spring.Transaction; + +/// +/// Representation of the status of a transaction, +/// consisting of a transaction object and some status flags. +/// +/// +///

+/// Transactional code can use this to retrieve status information, +/// and to programmatically request a rollback (instead of throwing +/// an exception that causes an implicit rollback). +///

+///

+/// Derives from the interface to provide access +/// to savepoint management facilities. Note that savepoint management +/// is just available if the actual transaction manager supports it. +///

+///
+/// Juergen Hoeller +/// Griffin Caprio (.NET) +/// Mark Pollack (.NET) +public interface ITransactionStatus : ISavepointManager { - /// - /// Representation of the status of a transaction, - /// consisting of a transaction object and some status flags. + /// + /// Returns true if the transaction is new, else false if participating + /// in an existing transaction. + /// + bool IsNewTransaction { get; } + + /// + /// Return whether the transaction has been marked as rollback-only, + /// (either by the application or by the transaction infrastructure). + /// + bool RollbackOnly { get; } + + /// + /// Set the transaction rollback-only. This instructs the transaction manager that the only possible outcome of + /// the transaction may be a rollback, proceeding with the normal application + /// workflow though (i.e. no exception). /// /// ///

- /// Transactional code can use this to retrieve status information, - /// and to programmatically request a rollback (instead of throwing - /// an exception that causes an implicit rollback). - ///

- ///

- /// Derives from the interface to provide access - /// to savepoint management facilities. Note that savepoint management - /// is just available if the actual transaction manager supports it. + /// For transactions managed by a or + /// . + /// An alternative way to trigger a rollback is throwing an transaction exception. ///

///
- /// Juergen Hoeller - /// Griffin Caprio (.NET) - /// Mark Pollack (.NET) - public interface ITransactionStatus : ISavepointManager - { - /// - /// Returns true if the transaction is new, else false if participating - /// in an existing transaction. - /// - bool IsNewTransaction { get; } + void SetRollbackOnly(); - /// - /// Return whether the transaction has been marked as rollback-only, - /// (either by the application or by the transaction infrastructure). - /// - bool RollbackOnly { get; } - - /// - /// Set the transaction rollback-only. This instructs the transaction manager that the only possible outcome of - /// the transaction may be a rollback, proceeding with the normal application - /// workflow though (i.e. no exception). - /// - /// - ///

- /// For transactions managed by a or - /// . - /// An alternative way to trigger a rollback is throwing an transaction exception. - ///

- ///
- void SetRollbackOnly(); + /// + /// Gets the current transaction object. + /// + /// + /// Returns the current transaction object for a given connection. + ///

+ /// Used to associate with the property. + ///

+ ///
+ object Transaction { get; } - /// - /// Gets the current transaction object. - /// - /// - /// Returns the current transaction object for a given connection. - ///

- /// Used to associate with the property. - ///

- ///
- object Transaction { get; } - - bool Completed { get; } - } + bool Completed { get; } } diff --git a/src/Spring/Spring.Data/Transaction/IllegalTransactionStateException.cs b/src/Spring/Spring.Data/Transaction/IllegalTransactionStateException.cs index ae3fcffe..77d15d17 100644 --- a/src/Spring/Spring.Data/Transaction/IllegalTransactionStateException.cs +++ b/src/Spring/Spring.Data/Transaction/IllegalTransactionStateException.cs @@ -20,48 +20,51 @@ using System.Runtime.Serialization; -namespace Spring.Transaction +namespace Spring.Transaction; + +/// +/// Exception thrown when the existence or non-existence of a transaction +/// amounts to an illegal state according to the transaction propagation +/// behavior that applies. +/// +/// Juergen Hoeller +/// Griffin Caprio (.NET) +[Serializable] +public class IllegalTransactionStateException : CannotCreateTransactionException { - /// - /// Exception thrown when the existence or non-existence of a transaction - /// amounts to an illegal state according to the transaction propagation - /// behavior that applies. - /// - /// Juergen Hoeller - /// Griffin Caprio (.NET) - [Serializable] - public class IllegalTransactionStateException : CannotCreateTransactionException - { - /// - /// Creates a new instance of the - /// class. - /// - public IllegalTransactionStateException( ) {} + /// + /// Creates a new instance of the + /// class. + /// + public IllegalTransactionStateException() { } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - public IllegalTransactionStateException( String message ) : base(message) {} + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + public IllegalTransactionStateException(String message) : base(message) { } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception that is being wrapped. - /// - public IllegalTransactionStateException(string message, Exception rootCause) - : base(message, rootCause) {} + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception that is being wrapped. + /// + public IllegalTransactionStateException(string message, Exception rootCause) + : base(message, rootCause) + { + } - /// - protected IllegalTransactionStateException( - SerializationInfo info, StreamingContext context ) : base( info, context ) {} - } -} + /// + protected IllegalTransactionStateException( + SerializationInfo info, StreamingContext context) : base(info, context) + { + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Data/Transaction/Interceptor/AbstractFallbackTransactionAttributeSource.cs b/src/Spring/Spring.Data/Transaction/Interceptor/AbstractFallbackTransactionAttributeSource.cs index 08ae4eec..04c2d5cd 100644 --- a/src/Spring/Spring.Data/Transaction/Interceptor/AbstractFallbackTransactionAttributeSource.cs +++ b/src/Spring/Spring.Data/Transaction/Interceptor/AbstractFallbackTransactionAttributeSource.cs @@ -19,257 +19,264 @@ using System.Reflection; using Spring.Util; using Spring.Core; -namespace Spring.Transaction.Interceptor +namespace Spring.Transaction.Interceptor; + +/// +/// Abstract implementation of +/// +/// that caches attributes for methods, and implements a default fallback policy. +/// +/// +///

+/// The default fallback policy applied by this class is: +/// +/// +/// most specific method +/// +/// +/// target class attribute +/// +/// +/// declaring method +/// +/// +/// declaring class +/// +/// +///

+///

+/// Defaults to using class's transaction attribute if none is associated +/// with the target method. Any transaction attribute associated with the +/// target method completely overrides a class transaction attribute. +///

+///

+/// This implementation caches attributes by method after they are first used. +/// If it's ever desirable to allow dynamic changing of transaction attributes +/// (unlikely) caching could be made configurable. Caching is desirable because +/// of the cost of evaluating rollback rules. +///

+///
+/// Rod Johnson +/// Griffin Caprio (.NET) +/// Mark Pollack (.NET) +public abstract class AbstractFallbackTransactionAttributeSource : ITransactionAttributeSource { - /// - /// Abstract implementation of - /// - /// that caches attributes for methods, and implements a default fallback policy. - /// - /// - ///

- /// The default fallback policy applied by this class is: - /// - /// - /// most specific method - /// - /// - /// target class attribute - /// - /// - /// declaring method - /// - /// - /// declaring class - /// - /// - ///

- ///

- /// Defaults to using class's transaction attribute if none is associated - /// with the target method. Any transaction attribute associated with the - /// target method completely overrides a class transaction attribute. - ///

- ///

- /// This implementation caches attributes by method after they are first used. - /// If it's ever desirable to allow dynamic changing of transaction attributes - /// (unlikely) caching could be made configurable. Caching is desirable because - /// of the cost of evaluating rollback rules. - ///

- ///
- /// Rod Johnson - /// Griffin Caprio (.NET) - /// Mark Pollack (.NET) - public abstract class AbstractFallbackTransactionAttributeSource : ITransactionAttributeSource - { - /// - /// Canonical value held in cache to indicate no transaction attibute was found - /// for this method, and we don't need to look again. - /// - private static readonly object NULL_TX_ATTIBUTE = new object(); + /// + /// Canonical value held in cache to indicate no transaction attibute was found + /// for this method, and we don't need to look again. + /// + private static readonly object NULL_TX_ATTIBUTE = new object(); - /// - /// Cache of s, keyed by method and target class. - /// - private readonly IDictionary _transactionAttibuteCache = new Hashtable(); + /// + /// Cache of s, keyed by method and target class. + /// + private readonly IDictionary _transactionAttibuteCache = new Hashtable(); - /// - /// Creates a new instance of the - /// - /// class. - /// - /// - ///

- /// This is an class, and as such exposes no public constructors. - ///

- ///
- protected AbstractFallbackTransactionAttributeSource() - { - } + /// + /// Creates a new instance of the + /// + /// class. + /// + /// + ///

+ /// This is an class, and as such exposes no public constructors. + ///

+ ///
+ protected AbstractFallbackTransactionAttributeSource() + { + } - /// - /// Subclasses should implement this to return all attributes for this method. - /// May return null. - /// - /// - /// We need all because of the need to analyze rollback rules. - /// - /// The method to retrieve attributes for. - /// The transactional attributes associated with the method. - protected abstract Attribute[] FindAllAttributes(MethodInfo method); + /// + /// Subclasses should implement this to return all attributes for this method. + /// May return null. + /// + /// + /// We need all because of the need to analyze rollback rules. + /// + /// The method to retrieve attributes for. + /// The transactional attributes associated with the method. + protected abstract Attribute[] FindAllAttributes(MethodInfo method); - /// - /// Subclasses should implement this to return all attributes for this class. - /// May return null. - /// - /// - /// The to retrieve attributes for. - /// - /// - /// All attributes associated with the supplied . - /// - protected abstract Attribute[] FindAllAttributes(Type targetType); + /// + /// Subclasses should implement this to return all attributes for this class. + /// May return null. + /// + /// + /// The to retrieve attributes for. + /// + /// + /// All attributes associated with the supplied . + /// + protected abstract Attribute[] FindAllAttributes(Type targetType); - /// - /// Return the transaction attribute for this method invocation. - /// - /// - /// Defaults to the class's transaction attribute if no method - /// attribute is found - /// - /// method for the current invocation. Can't be null - /// target class for this invocation. May be null. - /// for this method, or null if the method is non-transactional - public ITransactionAttribute ReturnTransactionAttribute(MethodInfo method, Type targetType) - { - object cacheKey = GetCacheKey(method, targetType); + /// + /// Return the transaction attribute for this method invocation. + /// + /// + /// Defaults to the class's transaction attribute if no method + /// attribute is found + /// + /// method for the current invocation. Can't be null + /// target class for this invocation. May be null. + /// for this method, or null if the method is non-transactional + public ITransactionAttribute ReturnTransactionAttribute(MethodInfo method, Type targetType) + { + object cacheKey = GetCacheKey(method, targetType); - lock (_transactionAttibuteCache) - { - object cached = _transactionAttibuteCache[cacheKey]; - - if (cached != null) - { - if (NULL_TX_ATTIBUTE == cached) - { - return null; - } - { - return (ITransactionAttribute)cached; - } - } - else - { - ITransactionAttribute transactionAttribute = ComputeTransactionAttribute(method, targetType); - if (null == transactionAttribute) - { - _transactionAttibuteCache.Add(cacheKey, NULL_TX_ATTIBUTE); - } - else - { - _transactionAttibuteCache.Add(cacheKey, transactionAttribute); - } - return transactionAttribute; - } - } - } - - /// - /// Return the transaction attribute, given this set of attributes - /// attached to a method or class. Return null if it's not transactional. - /// - /// - /// Protected rather than private as subclasses may want to customize - /// how this is done: for example, returning a - /// - /// affected by the values of other attributes. - /// This implementation takes into account - /// s, if - /// the TransactionAttribute is a RuleBasedTransactionAttribute. - /// - /// - /// Attributes attached to a method or class. May be null, in which case a null - /// will be returned. - /// - /// - /// The configured transaction attribute, or null - /// if none was found. - /// - protected virtual ITransactionAttribute FindTransactionAttribute(Attribute[] attributes) - { - if (null == attributes) - { - return null; - } - ITransactionAttribute transactionAttribute = null; - foreach (Attribute currentAttribute in attributes) - { - transactionAttribute = currentAttribute as ITransactionAttribute; - if (null != transactionAttribute) - { - break; - } - } - - if (transactionAttribute is RuleBasedTransactionAttribute ruleBasedTransactionAttribute) - { - var rollbackRules = new List(); - foreach (Attribute currentAttribute in attributes) - { - if (currentAttribute is RollbackRuleAttribute rollbackRuleAttribute) - { - rollbackRules.Add(rollbackRuleAttribute); - } - } - ruleBasedTransactionAttribute.RollbackRules = rollbackRules; - return ruleBasedTransactionAttribute; - } - return transactionAttribute; - } - - private static object GetCacheKey(MethodBase method, Type targetType) - { - return string.Intern(targetType.AssemblyQualifiedName + "." + method); - } - - private ITransactionAttribute ComputeTransactionAttribute(MethodInfo method, Type targetType) + lock (_transactionAttibuteCache) { - MethodInfo specificMethod; - if (targetType == null) + object cached = _transactionAttibuteCache[cacheKey]; + + if (cached != null) { - specificMethod = method; + if (NULL_TX_ATTIBUTE == cached) + { + return null; + } + + { + return (ITransactionAttribute) cached; + } } else { - ParameterInfo[] parameters = method.GetParameters(); - - ComposedCriteria searchCriteria = new ComposedCriteria(); - searchCriteria.Add(new MethodNameMatchCriteria(method.Name)); - searchCriteria.Add(new MethodParametersCountCriteria(parameters.Length)); - searchCriteria.Add(new MethodGenericArgumentsCountCriteria(method.GetGenericArguments().Length)); - searchCriteria.Add(new MethodParametersCriteria(ReflectionUtils.GetParameterTypes(parameters))); - - MemberInfo[] matchingMethods = targetType.FindMembers( - MemberTypes.Method, - BindingFlags.Instance | BindingFlags.Public, - new MemberFilter(new CriteriaMemberFilter().FilterMemberByCriteria), - searchCriteria); - - if (matchingMethods != null && matchingMethods.Length == 1) + ITransactionAttribute transactionAttribute = ComputeTransactionAttribute(method, targetType); + if (null == transactionAttribute) { - specificMethod = matchingMethods[0] as MethodInfo; + _transactionAttibuteCache.Add(cacheKey, NULL_TX_ATTIBUTE); } else { - specificMethod = method; + _transactionAttibuteCache.Add(cacheKey, transactionAttribute); } - } - ITransactionAttribute transactionAttribute = GetTransactionAttribute(specificMethod); - if (null != transactionAttribute) - { return transactionAttribute; } - else if (specificMethod != method) - { - transactionAttribute = GetTransactionAttribute(method); - } + } + } + + /// + /// Return the transaction attribute, given this set of attributes + /// attached to a method or class. Return null if it's not transactional. + /// + /// + /// Protected rather than private as subclasses may want to customize + /// how this is done: for example, returning a + /// + /// affected by the values of other attributes. + /// This implementation takes into account + /// s, if + /// the TransactionAttribute is a RuleBasedTransactionAttribute. + /// + /// + /// Attributes attached to a method or class. May be null, in which case a null + /// will be returned. + /// + /// + /// The configured transaction attribute, or null + /// if none was found. + /// + protected virtual ITransactionAttribute FindTransactionAttribute(Attribute[] attributes) + { + if (null == attributes) + { return null; } - private ITransactionAttribute GetTransactionAttribute(MethodInfo methodInfo) - { - ITransactionAttribute transactionAttribute = FindTransactionAttribute(FindAllAttributes(methodInfo)); + ITransactionAttribute transactionAttribute = null; + foreach (Attribute currentAttribute in attributes) + { + transactionAttribute = currentAttribute as ITransactionAttribute; + if (null != transactionAttribute) + { + break; + } + } - if (null != transactionAttribute) - { - return transactionAttribute; - } - transactionAttribute = FindTransactionAttribute(FindAllAttributes(methodInfo.DeclaringType)); - if (null != transactionAttribute) - { - return transactionAttribute; - } - return null; - } - } + if (transactionAttribute is RuleBasedTransactionAttribute ruleBasedTransactionAttribute) + { + var rollbackRules = new List(); + foreach (Attribute currentAttribute in attributes) + { + if (currentAttribute is RollbackRuleAttribute rollbackRuleAttribute) + { + rollbackRules.Add(rollbackRuleAttribute); + } + } + + ruleBasedTransactionAttribute.RollbackRules = rollbackRules; + return ruleBasedTransactionAttribute; + } + + return transactionAttribute; + } + + private static object GetCacheKey(MethodBase method, Type targetType) + { + return string.Intern(targetType.AssemblyQualifiedName + "." + method); + } + + private ITransactionAttribute ComputeTransactionAttribute(MethodInfo method, Type targetType) + { + MethodInfo specificMethod; + if (targetType == null) + { + specificMethod = method; + } + else + { + ParameterInfo[] parameters = method.GetParameters(); + + ComposedCriteria searchCriteria = new ComposedCriteria(); + searchCriteria.Add(new MethodNameMatchCriteria(method.Name)); + searchCriteria.Add(new MethodParametersCountCriteria(parameters.Length)); + searchCriteria.Add(new MethodGenericArgumentsCountCriteria(method.GetGenericArguments().Length)); + searchCriteria.Add(new MethodParametersCriteria(ReflectionUtils.GetParameterTypes(parameters))); + + MemberInfo[] matchingMethods = targetType.FindMembers( + MemberTypes.Method, + BindingFlags.Instance | BindingFlags.Public, + new MemberFilter(new CriteriaMemberFilter().FilterMemberByCriteria), + searchCriteria); + + if (matchingMethods != null && matchingMethods.Length == 1) + { + specificMethod = matchingMethods[0] as MethodInfo; + } + else + { + specificMethod = method; + } + } + + ITransactionAttribute transactionAttribute = GetTransactionAttribute(specificMethod); + if (null != transactionAttribute) + { + return transactionAttribute; + } + else if (specificMethod != method) + { + transactionAttribute = GetTransactionAttribute(method); + } + + return null; + } + + private ITransactionAttribute GetTransactionAttribute(MethodInfo methodInfo) + { + ITransactionAttribute transactionAttribute = FindTransactionAttribute(FindAllAttributes(methodInfo)); + + if (null != transactionAttribute) + { + return transactionAttribute; + } + + transactionAttribute = FindTransactionAttribute(FindAllAttributes(methodInfo.DeclaringType)); + if (null != transactionAttribute) + { + return transactionAttribute; + } + + return null; + } } diff --git a/src/Spring/Spring.Data/Transaction/Interceptor/AbstractTransactionAttributeSourcePointcut.cs b/src/Spring/Spring.Data/Transaction/Interceptor/AbstractTransactionAttributeSourcePointcut.cs index 26567582..d8ba4e24 100644 --- a/src/Spring/Spring.Data/Transaction/Interceptor/AbstractTransactionAttributeSourcePointcut.cs +++ b/src/Spring/Spring.Data/Transaction/Interceptor/AbstractTransactionAttributeSourcePointcut.cs @@ -21,38 +21,37 @@ using System.Reflection; using Spring.Aop.Support; -namespace Spring.Transaction.Interceptor +namespace Spring.Transaction.Interceptor; + +public abstract class AbstractTransactionAttributeSourcePointcut : StaticMethodMatcherPointcut { - 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) { - #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; } + ITransactionAttributeSource tas = TransactionAttributeSource; + return (tas == null || TransactionAttributeSource.ReturnTransactionAttribute(method, targetType) != null); } + + #endregion + + protected abstract ITransactionAttributeSource TransactionAttributeSource { get; } } diff --git a/src/Spring/Spring.Data/Transaction/Interceptor/AttributesTransactionAttributeSource.cs b/src/Spring/Spring.Data/Transaction/Interceptor/AttributesTransactionAttributeSource.cs index b124c427..817db7e6 100644 --- a/src/Spring/Spring.Data/Transaction/Interceptor/AttributesTransactionAttributeSource.cs +++ b/src/Spring/Spring.Data/Transaction/Interceptor/AttributesTransactionAttributeSource.cs @@ -20,108 +20,105 @@ using System.Reflection; -namespace Spring.Transaction.Interceptor +namespace Spring.Transaction.Interceptor; + +/// +/// Implementation of that uses +/// s. +/// +/// Rod Johnson +/// Griffin Caprio (.NET) +/// Mark Pollack (.NET) +public class AttributesTransactionAttributeSource : AbstractFallbackTransactionAttributeSource { - /// - /// Implementation of that uses - /// s. - /// - /// Rod Johnson - /// Griffin Caprio (.NET) - /// Mark Pollack (.NET) - public class AttributesTransactionAttributeSource : AbstractFallbackTransactionAttributeSource - { + /// + /// Initializes a new instance of the class. + /// + public AttributesTransactionAttributeSource() + { + } - /// - /// Initializes a new instance of the class. - /// - public AttributesTransactionAttributeSource( ) - { - } + /// + /// + /// implementation. + /// + /// + /// We need all because of the need to analyze rollback rules. + /// + /// The method to retrieve attributes for. + /// The transactional attributes associated with the method. + protected override Attribute[] FindAllAttributes(MethodInfo method) + { + return Attribute.GetCustomAttributes(method); + } - /// - /// - /// implementation. - /// - /// - /// We need all because of the need to analyze rollback rules. - /// - /// The method to retrieve attributes for. - /// The transactional attributes associated with the method. - protected override Attribute[] FindAllAttributes( MethodInfo method ) - { - return Attribute.GetCustomAttributes( method ); - } + /// + /// + /// implementation. + /// + /// + /// The to retrieve attributes for. + /// + /// + /// All attributes associated with the supplied . + /// + protected override Attribute[] FindAllAttributes(Type targetType) + { + return Attribute.GetCustomAttributes(targetType); + } - /// - /// - /// implementation. - /// - /// - /// The to retrieve attributes for. - /// - /// - /// All attributes associated with the supplied . - /// - protected override Attribute[] FindAllAttributes( Type targetType ) - { - return Attribute.GetCustomAttributes( targetType ); - } - - protected override ITransactionAttribute FindTransactionAttribute(Attribute[] attributes) + protected override ITransactionAttribute FindTransactionAttribute(Attribute[] attributes) + { + if (attributes == null) { - if (attributes == null) - { - return null; - } - foreach (Attribute attr in attributes) - { - if (attr is TransactionAttribute) - { - TransactionAttribute ta = (TransactionAttribute)attr; - RuleBasedTransactionAttribute rbta = - new RuleBasedTransactionAttribute(); - - //TODO another reminder to sync property names - rbta.PropagationBehavior = ta.TransactionPropagation; - rbta.TransactionIsolationLevel = ta.IsolationLevel; - rbta.ReadOnly = ta.ReadOnly; - rbta.TransactionTimeout = ta.Timeout; - rbta.AsyncFlowOption = ta.AsyncFlowOption; - - Type[] rbf = ta.RollbackFor; - - var rollBackRules = new List(); - - if (rbf != null) - { - foreach (Type t in rbf) - { - RollbackRuleAttribute rule = new RollbackRuleAttribute(t); - rollBackRules.Add(rule); - } - } - - - Type[] nrbfc = ta.NoRollbackFor; - - if (nrbfc != null) - { - foreach (Type t in nrbfc) - { - NoRollbackRuleAttribute rule = new NoRollbackRuleAttribute(t); - rollBackRules.Add(rule); - } - } - - rbta.RollbackRules = rollBackRules; - - return rbta; - - } - } return null; } - } + foreach (Attribute attr in attributes) + { + if (attr is TransactionAttribute) + { + TransactionAttribute ta = (TransactionAttribute) attr; + RuleBasedTransactionAttribute rbta = + new RuleBasedTransactionAttribute(); + + //TODO another reminder to sync property names + rbta.PropagationBehavior = ta.TransactionPropagation; + rbta.TransactionIsolationLevel = ta.IsolationLevel; + rbta.ReadOnly = ta.ReadOnly; + rbta.TransactionTimeout = ta.Timeout; + rbta.AsyncFlowOption = ta.AsyncFlowOption; + + Type[] rbf = ta.RollbackFor; + + var rollBackRules = new List(); + + if (rbf != null) + { + foreach (Type t in rbf) + { + RollbackRuleAttribute rule = new RollbackRuleAttribute(t); + rollBackRules.Add(rule); + } + } + + Type[] nrbfc = ta.NoRollbackFor; + + if (nrbfc != null) + { + foreach (Type t in nrbfc) + { + NoRollbackRuleAttribute rule = new NoRollbackRuleAttribute(t); + rollBackRules.Add(rule); + } + } + + rbta.RollbackRules = rollBackRules; + + return rbta; + } + } + + return null; + } } diff --git a/src/Spring/Spring.Data/Transaction/Interceptor/DefaultTransactionAttribute.cs b/src/Spring/Spring.Data/Transaction/Interceptor/DefaultTransactionAttribute.cs index aef1bdc3..51a74f90 100644 --- a/src/Spring/Spring.Data/Transaction/Interceptor/DefaultTransactionAttribute.cs +++ b/src/Spring/Spring.Data/Transaction/Interceptor/DefaultTransactionAttribute.cs @@ -16,80 +16,79 @@ using Spring.Transaction.Support; -namespace Spring.Transaction.Interceptor +namespace Spring.Transaction.Interceptor; + +/// +/// Transaction attribute approach to rolling back on all exceptions, no other +/// exceptions by default. +/// +/// Rod Johnson +/// Griffin Caprio (.NET) +public class DefaultTransactionAttribute : DefaultTransactionDefinition, ITransactionAttribute { /// - /// Transaction attribute approach to rolling back on all exceptions, no other - /// exceptions by default. + /// Prefix for rollback-on-exception rules in description strings. /// - /// Rod Johnson - /// Griffin Caprio (.NET) - public class DefaultTransactionAttribute : DefaultTransactionDefinition, ITransactionAttribute + public static readonly string ROLLBACK_RULE_PREFIX = "-"; + + /// + /// Prefix for commit-on-exception rules in description strings. + /// + public static readonly string COMMIT_RULE_PREFIX = "+"; + + /// + /// Creates a new instance of the + /// + /// class. + /// + public DefaultTransactionAttribute() { - /// - /// Prefix for rollback-on-exception rules in description strings. - /// - public static readonly string ROLLBACK_RULE_PREFIX = "-"; + } - /// - /// Prefix for commit-on-exception rules in description strings. - /// - public static readonly string COMMIT_RULE_PREFIX = "+"; + /// + /// Creates a new instance of the + /// + /// class, setting the propagation behavior to the supplied value. + /// + /// + /// The desired transaction propagation behaviour. + /// + public DefaultTransactionAttribute(TransactionPropagation propagationBehavior) + : base(propagationBehavior) + { + } - /// - /// Creates a new instance of the - /// - /// class. - /// - public DefaultTransactionAttribute() - { - } + /// + /// Decides if rollback is required for the supplied . + /// + /// + ///

+ /// The default behavior is to rollback on any exception. + /// Consistent with 's behavior. + ///

+ ///
+ /// The to evaluate. + /// True if the exception causes a rollback, false otherwise. + public virtual bool RollbackOn(Exception exception) + { + return (true); + } - /// - /// Creates a new instance of the - /// - /// class, setting the propagation behavior to the supplied value. - /// - /// - /// The desired transaction propagation behaviour. - /// - public DefaultTransactionAttribute(TransactionPropagation propagationBehavior) - : base(propagationBehavior) - { - } - - /// - /// Decides if rollback is required for the supplied . - /// - /// - ///

- /// The default behavior is to rollback on any exception. - /// Consistent with 's behavior. - ///

- ///
- /// The to evaluate. - /// True if the exception causes a rollback, false otherwise. - public virtual bool RollbackOn(Exception exception) - { - return (true); - } - - /// - /// Return a description of this transaction attribute. - /// - /// - ///

- /// The format matches the one used by the - /// , - /// to be able to feed any result into a - /// instance's properties. - ///

- ///
- public override string ToString() - { - string result = DefinitionDescription; - result += "," + ROLLBACK_RULE_PREFIX + "System.Exception"; - return result; - } + /// + /// Return a description of this transaction attribute. + /// + /// + ///

+ /// The format matches the one used by the + /// , + /// to be able to feed any result into a + /// instance's properties. + ///

+ ///
+ public override string ToString() + { + string result = DefinitionDescription; + result += "," + ROLLBACK_RULE_PREFIX + "System.Exception"; + return result; } } diff --git a/src/Spring/Spring.Data/Transaction/Interceptor/DefaultTransactionAttributeSourceAdvisor.cs b/src/Spring/Spring.Data/Transaction/Interceptor/DefaultTransactionAttributeSourceAdvisor.cs index 393311c8..3374c61a 100644 --- a/src/Spring/Spring.Data/Transaction/Interceptor/DefaultTransactionAttributeSourceAdvisor.cs +++ b/src/Spring/Spring.Data/Transaction/Interceptor/DefaultTransactionAttributeSourceAdvisor.cs @@ -23,57 +23,57 @@ using AopAlliance.Aop; using Spring.Aop.Framework; using Spring.Aop.Support; -namespace Spring.Transaction.Interceptor +namespace Spring.Transaction.Interceptor; + +/// +/// Advisor driven by a , +/// used to exclude a general advice from methods that +/// are non-transactional. +/// +/// +/// +/// To put it another way, use this advisor when you would like to associate other AOP +/// advice based on the pointcut specified by declarative transaction demarcation, +/// attibute based or otherwise. +/// +///

+/// Because the AOP framework caches advice calculations, this is normally +/// faster than just letting the +/// run and find out itself that it has no work to do. +///

+///
+/// Mark Pollack (.NET) +[Serializable] +public class DefaultTransactionAttributeSourceAdvisor : StaticMethodMatcherPointcutAdvisor { - /// - /// Advisor driven by a , - /// used to exclude a general advice from methods that - /// are non-transactional. - /// - /// - /// - /// To put it another way, use this advisor when you would like to associate other AOP - /// advice based on the pointcut specified by declarative transaction demarcation, - /// attibute based or otherwise. - /// - ///

- /// Because the AOP framework caches advice calculations, this is normally - /// faster than just letting the - /// run and find out itself that it has no work to do. - ///

- ///
- /// Mark Pollack (.NET) - [Serializable] - public class DefaultTransactionAttributeSourceAdvisor : StaticMethodMatcherPointcutAdvisor - { - private ITransactionAttributeSource _transactionAttributeSource; + private ITransactionAttributeSource _transactionAttributeSource; - /// - /// Creates a new instance of the - /// class. - /// - public DefaultTransactionAttributeSourceAdvisor(ITransactionAttributeSource transactionAttributeSource, IAdvice advice) - : base( advice ) - { - if (transactionAttributeSource == null) - { - throw new AopConfigException("Cannot construct a DefaultTransactionAttributeSourceAdvisor if " + - "TransactionAttributeSource is null."); - } - _transactionAttributeSource = transactionAttributeSource; - } + /// + /// Creates a new instance of the + /// class. + /// + public DefaultTransactionAttributeSourceAdvisor(ITransactionAttributeSource transactionAttributeSource, IAdvice advice) + : base(advice) + { + if (transactionAttributeSource == null) + { + throw new AopConfigException("Cannot construct a DefaultTransactionAttributeSourceAdvisor if " + + "TransactionAttributeSource is null."); + } - /// - /// Tests the input method to see if it's covered by the advisor. - /// - /// The method to match. - /// The to match against. - /// - /// True if the supplied is covered by the advisor. - /// - public override bool Matches(MethodInfo method, Type targetClass) - { - return ( _transactionAttributeSource.ReturnTransactionAttribute( (MethodInfo)method, targetClass ) != null); - } - } + _transactionAttributeSource = transactionAttributeSource; + } + + /// + /// Tests the input method to see if it's covered by the advisor. + /// + /// The method to match. + /// The to match against. + /// + /// True if the supplied is covered by the advisor. + /// + public override bool Matches(MethodInfo method, Type targetClass) + { + return (_transactionAttributeSource.ReturnTransactionAttribute((MethodInfo) method, targetClass) != null); + } } diff --git a/src/Spring/Spring.Data/Transaction/Interceptor/DelegatingTransactionAttributeWithName.cs b/src/Spring/Spring.Data/Transaction/Interceptor/DelegatingTransactionAttributeWithName.cs index 9d45060e..5f9f7649 100644 --- a/src/Spring/Spring.Data/Transaction/Interceptor/DelegatingTransactionAttributeWithName.cs +++ b/src/Spring/Spring.Data/Transaction/Interceptor/DelegatingTransactionAttributeWithName.cs @@ -19,93 +19,92 @@ #endregion using System.Transactions; -using IsolationLevel=System.Data.IsolationLevel; +using IsolationLevel = System.Data.IsolationLevel; -namespace Spring.Transaction.Interceptor +namespace Spring.Transaction.Interceptor; + +/// +/// ITransactionAttribute that delegates all calls to a give target attribute except for the +/// name, which is specified in the constructor. +/// +public class DelegatingTransactionAttributeWithName : ITransactionAttribute { + private readonly ITransactionAttribute targetAttribute; + private readonly string joinpointIdentification; + /// - /// ITransactionAttribute that delegates all calls to a give target attribute except for the - /// name, which is specified in the constructor. + /// Initializes a new instance of the class. /// - public class DelegatingTransactionAttributeWithName : ITransactionAttribute + /// The target attribute. + /// The identification. + public DelegatingTransactionAttributeWithName(ITransactionAttribute targetAttribute, string identification) { - private readonly ITransactionAttribute targetAttribute; - private readonly string joinpointIdentification; + this.targetAttribute = targetAttribute; + joinpointIdentification = identification; + } - /// - /// Initializes a new instance of the class. - /// - /// The target attribute. - /// The identification. - public DelegatingTransactionAttributeWithName(ITransactionAttribute targetAttribute, string identification) - { - this.targetAttribute = targetAttribute; - joinpointIdentification = identification; - } + /// + /// Decides if rollback is required for the supplied . + /// + /// The to evaluate. + /// + /// True if the exception causes a rollback, false otherwise. + /// + public bool RollbackOn(Exception exception) + { + return targetAttribute.RollbackOn(exception); + } - /// - /// Decides if rollback is required for the supplied . - /// - /// The to evaluate. - /// - /// True if the exception causes a rollback, false otherwise. - /// - public bool RollbackOn(Exception exception) - { - return targetAttribute.RollbackOn(exception); - } + /// + /// Return the propagation behavior of type + /// . + /// + /// + public TransactionPropagation PropagationBehavior => targetAttribute.PropagationBehavior; - /// - /// Return the propagation behavior of type - /// . - /// - /// - public TransactionPropagation PropagationBehavior => targetAttribute.PropagationBehavior; + /// + /// Return the isolation level of type . + /// + /// + /// + ///

+ /// Only makes sense in combination with + /// and + /// . + ///

+ ///

+ /// Note that a transaction manager that does not support custom isolation levels + /// will throw an exception when given any other level than + /// . + ///

+ ///
+ public IsolationLevel TransactionIsolationLevel => targetAttribute.TransactionIsolationLevel; - /// - /// Return the isolation level of type . - /// - /// - /// - ///

- /// Only makes sense in combination with - /// and - /// . - ///

- ///

- /// Note that a transaction manager that does not support custom isolation levels - /// will throw an exception when given any other level than - /// . - ///

- ///
- public IsolationLevel TransactionIsolationLevel => targetAttribute.TransactionIsolationLevel; + /// + public int TransactionTimeout => targetAttribute.TransactionTimeout; - /// - public int TransactionTimeout => targetAttribute.TransactionTimeout; + /// + public bool ReadOnly => targetAttribute.ReadOnly; - /// - public bool ReadOnly => targetAttribute.ReadOnly; + /// + public string Name => joinpointIdentification; - /// - public string Name => joinpointIdentification; + /// + public TransactionScopeAsyncFlowOption AsyncFlowOption => targetAttribute.AsyncFlowOption; - /// - public TransactionScopeAsyncFlowOption AsyncFlowOption => targetAttribute.AsyncFlowOption; - - /// - /// Return a description of this transaction attribute. - /// - /// - ///

- /// The format matches the one used by the - /// , - /// to be able to feed any result into a - /// instance's properties. - ///

- ///
- public override string ToString() - { - return targetAttribute.ToString(); - } + /// + /// Return a description of this transaction attribute. + /// + /// + ///

+ /// The format matches the one used by the + /// , + /// to be able to feed any result into a + /// instance's properties. + ///

+ ///
+ public override string ToString() + { + return targetAttribute.ToString(); } } diff --git a/src/Spring/Spring.Data/Transaction/Interceptor/ITransactionAttribute.cs b/src/Spring/Spring.Data/Transaction/Interceptor/ITransactionAttribute.cs index 961492e6..f2722b5f 100644 --- a/src/Spring/Spring.Data/Transaction/Interceptor/ITransactionAttribute.cs +++ b/src/Spring/Spring.Data/Transaction/Interceptor/ITransactionAttribute.cs @@ -20,22 +20,21 @@ using System.ComponentModel; -namespace Spring.Transaction.Interceptor +namespace Spring.Transaction.Interceptor; + +/// +/// This interface adds a +/// +/// specification to . +/// +/// Griffin Caprio (.NET) +[TypeConverter(typeof(TransactionAttributeConverter))] +public interface ITransactionAttribute : ITransactionDefinition { - /// - /// This interface adds a - /// - /// specification to . - /// - /// Griffin Caprio (.NET) - [TypeConverter(typeof(TransactionAttributeConverter))] - public interface ITransactionAttribute : ITransactionDefinition - { - /// - /// Decides if rollback is required for the supplied . - /// - /// The to evaluate. - /// True if the exception causes a rollback, false otherwise. - bool RollbackOn( Exception exception ); - } + /// + /// Decides if rollback is required for the supplied . + /// + /// The to evaluate. + /// True if the exception causes a rollback, false otherwise. + bool RollbackOn(Exception exception); } diff --git a/src/Spring/Spring.Data/Transaction/Interceptor/ITransactionAttributeSource.cs b/src/Spring/Spring.Data/Transaction/Interceptor/ITransactionAttributeSource.cs index a5658d36..ba77aac2 100644 --- a/src/Spring/Spring.Data/Transaction/Interceptor/ITransactionAttributeSource.cs +++ b/src/Spring/Spring.Data/Transaction/Interceptor/ITransactionAttributeSource.cs @@ -20,35 +20,34 @@ using System.Reflection; -namespace Spring.Transaction.Interceptor +namespace Spring.Transaction.Interceptor; + +/// +/// Interface used by +/// to source transaction attributes. +/// +/// +///

+/// Implementations know how to source transaction attributes, whether from configuration, +/// metadata attributes at source level, or anywhere else. +///

+///
+/// Rod Johnson +/// Griffin Caprio (.NET) +public interface ITransactionAttributeSource { - /// - /// Interface used by - /// to source transaction attributes. - /// - /// - ///

- /// Implementations know how to source transaction attributes, whether from configuration, - /// metadata attributes at source level, or anywhere else. - ///

- ///
- /// Rod Johnson - /// Griffin Caprio (.NET) - public interface ITransactionAttributeSource - { - /// - /// Return the for this - /// method. - /// - /// The method to check. - /// - /// The target . May be null, in which case the declaring - /// class of the supplied must be used. - /// - /// - /// A or - /// null if the method is non-transactional. - /// - ITransactionAttribute ReturnTransactionAttribute( MethodInfo method, Type targetType ); - } + /// + /// Return the for this + /// method. + /// + /// The method to check. + /// + /// The target . May be null, in which case the declaring + /// class of the supplied must be used. + /// + /// + /// A or + /// null if the method is non-transactional. + /// + ITransactionAttribute ReturnTransactionAttribute(MethodInfo method, Type targetType); } diff --git a/src/Spring/Spring.Data/Transaction/Interceptor/MatchAlwaysTransactionAttributeSource.cs b/src/Spring/Spring.Data/Transaction/Interceptor/MatchAlwaysTransactionAttributeSource.cs index e11437fa..969f683a 100644 --- a/src/Spring/Spring.Data/Transaction/Interceptor/MatchAlwaysTransactionAttributeSource.cs +++ b/src/Spring/Spring.Data/Transaction/Interceptor/MatchAlwaysTransactionAttributeSource.cs @@ -20,105 +20,105 @@ using System.Reflection; -namespace Spring.Transaction.Interceptor +namespace Spring.Transaction.Interceptor; + +/// +/// Very simple implementation of +/// which will always return the same +/// for all methods fed to it. +/// +/// +///

+/// The +/// may be specified, but will otherwise default to PROPAGATION_REQUIRED. This may be +/// used in the cases where you want to use the same transaction attribute with all +/// methods being handled by a transaction interceptor. +///

+///
+/// Colin Sampaleanu +/// Griffin Caprio (.NET) +[Serializable] +public class MatchAlwaysTransactionAttributeSource : ITransactionAttributeSource { - /// - /// Very simple implementation of - /// which will always return the same - /// for all methods fed to it. - /// - /// - ///

- /// The - /// may be specified, but will otherwise default to PROPAGATION_REQUIRED. This may be - /// used in the cases where you want to use the same transaction attribute with all - /// methods being handled by a transaction interceptor. - ///

- ///
- /// Colin Sampaleanu - /// Griffin Caprio (.NET) - [Serializable] - public class MatchAlwaysTransactionAttributeSource : ITransactionAttributeSource - { - private ITransactionAttribute _transactionAttribute; + private ITransactionAttribute _transactionAttribute; - /// - /// Creates a new instance of the - /// - /// class. - /// - public MatchAlwaysTransactionAttributeSource() - { - _transactionAttribute = new DefaultTransactionAttribute(); - } + /// + /// Creates a new instance of the + /// + /// class. + /// + public MatchAlwaysTransactionAttributeSource() + { + _transactionAttribute = new DefaultTransactionAttribute(); + } - /// - /// Allows a transaction attribute to be specified, using the - /// form, for example, "PROPAGATION_REQUIRED". - /// - public ITransactionAttribute TransactionAttribute - { - set { _transactionAttribute = value; } - } + /// + /// Allows a transaction attribute to be specified, using the + /// form, for example, "PROPAGATION_REQUIRED". + /// + public ITransactionAttribute TransactionAttribute + { + set { _transactionAttribute = value; } + } - #region ITransactionAttributeSource Members - /// - /// Return the for this - /// method. - /// - /// The method to check. - /// - /// The target . May be null, in which case the declaring - /// class of the supplied must be used. - /// - /// - /// A or - /// null if the method is non-transactional. - /// - public ITransactionAttribute ReturnTransactionAttribute(MethodInfo method, Type targetType) - { - return _transactionAttribute; - } - #endregion + #region ITransactionAttributeSource Members - /// - /// Determines whether the specified is equal to the current . - /// - /// The to compare with the current . - /// - /// true if the specified is equal to the current ; otherwise, false. - /// - public override bool Equals(object obj) - { - if (this == obj) return true; - MatchAlwaysTransactionAttributeSource matchAlwaysTransactionAttributeSource = obj as MatchAlwaysTransactionAttributeSource; - if (matchAlwaysTransactionAttributeSource == null) return false; - return Equals(_transactionAttribute, matchAlwaysTransactionAttributeSource._transactionAttribute); - } + /// + /// Return the for this + /// method. + /// + /// The method to check. + /// + /// The target . May be null, in which case the declaring + /// class of the supplied must be used. + /// + /// + /// A or + /// null if the method is non-transactional. + /// + public ITransactionAttribute ReturnTransactionAttribute(MethodInfo method, Type targetType) + { + return _transactionAttribute; + } - /// - /// Serves as a hash function for a particular type. is suitable for use in hashing algorithms and data structures like a hash table. - /// - /// - /// A hash code for the current . - /// - public override int GetHashCode() - { - return _transactionAttribute != null ? _transactionAttribute.GetHashCode() : 0; - } + #endregion + /// + /// Determines whether the specified is equal to the current . + /// + /// The to compare with the current . + /// + /// true if the specified is equal to the current ; otherwise, false. + /// + public override bool Equals(object obj) + { + if (this == obj) return true; + MatchAlwaysTransactionAttributeSource matchAlwaysTransactionAttributeSource = obj as MatchAlwaysTransactionAttributeSource; + if (matchAlwaysTransactionAttributeSource == null) return false; + return Equals(_transactionAttribute, matchAlwaysTransactionAttributeSource._transactionAttribute); + } - /// - ///Returns a that represents the current . - /// - /// - /// - ///A that represents the current . - /// - ///2 - public override string ToString() - { - return GetType().Name + ": " + _transactionAttribute; - } - } + /// + /// Serves as a hash function for a particular type. is suitable for use in hashing algorithms and data structures like a hash table. + /// + /// + /// A hash code for the current . + /// + public override int GetHashCode() + { + return _transactionAttribute != null ? _transactionAttribute.GetHashCode() : 0; + } + + /// + ///Returns a that represents the current . + /// + /// + /// + ///A that represents the current . + /// + ///2 + public override string ToString() + { + return GetType().Name + ": " + _transactionAttribute; + } } diff --git a/src/Spring/Spring.Data/Transaction/Interceptor/MethodMapTransactionAttributeSource.cs b/src/Spring/Spring.Data/Transaction/Interceptor/MethodMapTransactionAttributeSource.cs index 7bd707fc..e66daf3b 100644 --- a/src/Spring/Spring.Data/Transaction/Interceptor/MethodMapTransactionAttributeSource.cs +++ b/src/Spring/Spring.Data/Transaction/Interceptor/MethodMapTransactionAttributeSource.cs @@ -25,262 +25,267 @@ using Spring.Util; using Spring.Core.TypeResolution; using Spring.Core; -namespace Spring.Transaction.Interceptor +namespace Spring.Transaction.Interceptor; + +/// +/// Simple implementation of the +/// interface that allows attributes to be stored per method in a map. +/// +/// Rod Johnson +/// Juergen Hoeller +/// Griffin Caprio (.NET) +public class MethodMapTransactionAttributeSource : ITransactionAttributeSource { - /// - /// Simple implementation of the - /// interface that allows attributes to be stored per method in a map. - /// - /// Rod Johnson - /// Juergen Hoeller - /// Griffin Caprio (.NET) - public class MethodMapTransactionAttributeSource : ITransactionAttributeSource - { - private IDictionary _methodMap; - private IDictionary _nameMap; + private IDictionary _methodMap; + private IDictionary _nameMap; - #region Logging Definition + #region Logging Definition - private static readonly ILogger LOG = LogManager.GetLogger(typeof (MethodMapTransactionAttributeSource)); + private static readonly ILogger LOG = LogManager.GetLogger(typeof(MethodMapTransactionAttributeSource)); - #endregion + #endregion - /// - /// Creates a new instance of the - /// class. - /// - public MethodMapTransactionAttributeSource() - { - _methodMap = new Hashtable(); - _nameMap = new Hashtable(); - } + /// + /// Creates a new instance of the + /// class. + /// + public MethodMapTransactionAttributeSource() + { + _methodMap = new Hashtable(); + _nameMap = new Hashtable(); + } - /// - /// Set a name/attribute map, consisting of "FQCN.method, AssemblyName" method names - /// (e.g. "MyNameSpace.MyClass.MyMethod, MyAssembly") and ITransactionAttribute - /// instances (or Strings to be converted to instances). - /// - /// - ///

- /// The key values of the supplied - /// must adhere to the following form:
- /// FQCN.methodName, Assembly. - ///

- /// - /// MyNameSpace.MyClass.MyMethod, MyAssembly - /// - ///
- public IDictionary MethodMap - { - set - { - foreach (DictionaryEntry entry in value) - { - - string name = entry.Key as string; - ITransactionAttribute attribute = null; - //Check if we need to convert from a string to ITransactionAttribute - if (entry.Value is ITransactionAttribute) - { - attribute = entry.Value as ITransactionAttribute; - } - else - { - TransactionAttributeEditor editor = new TransactionAttributeEditor(); - editor.SetAsText(entry.Value.ToString()); - attribute = editor.Value; - } - AddTransactionalMethod( name, attribute ); - - } - - } - } - /// - /// Add an attribute for a transactional method. - /// - /// - /// Method names can end or start with "*" for matching multiple methods. - /// - /// The class and method name, separated by a dot. - /// The attribute to be associated with the method. - public void AddTransactionalMethod( string name, ITransactionAttribute attribute ) - { - AssertUtils.ArgumentNotNull(name, "name"); - int lastCommaIndex = name.LastIndexOf( "," ); - if (lastCommaIndex == -1) + /// + /// Set a name/attribute map, consisting of "FQCN.method, AssemblyName" method names + /// (e.g. "MyNameSpace.MyClass.MyMethod, MyAssembly") and ITransactionAttribute + /// instances (or Strings to be converted to instances). + /// + /// + ///

+ /// The key values of the supplied + /// must adhere to the following form:
+ /// FQCN.methodName, Assembly. + ///

+ /// + /// MyNameSpace.MyClass.MyMethod, MyAssembly + /// + ///
+ public IDictionary MethodMap + { + set + { + foreach (DictionaryEntry entry in value) { - throw new ArgumentException("'" + name + "'" + - " is not a valid method name, missing AssemblyName. Format is FQN.MethodName, AssemblyName."); - } - string fqnWithMethod = name.Substring(0, lastCommaIndex); - - int lastDotIndex = fqnWithMethod.LastIndexOf( "." ); - if ( lastDotIndex == -1 ) - { - throw new TransactionUsageException("'" + fqnWithMethod + "' is not a valid method name: format is FQN.methodName"); - } - string className = fqnWithMethod.Substring(0, lastDotIndex ); - string assemblyName = name.Substring(lastCommaIndex + 1); - string methodName = fqnWithMethod.Substring(lastDotIndex + 1 ); - string fqnClassName = className + ", " + assemblyName; - try - { - Type type = TypeResolutionUtils.ResolveType(fqnClassName); - AddTransactionalMethod( type, methodName, attribute ); - } catch ( TypeLoadException exception ) - { - throw new TransactionUsageException( "Type '" + fqnClassName + "' not found.", exception ); - } - } - - /// - /// Add an attribute for a transactional method. - /// - /// - /// Method names can end or start with "*" for matching multiple methods. - /// - /// The target interface or class. - /// The mapped method name. - /// - /// The attribute to be associated with the method. - /// - public void AddTransactionalMethod( - Type type, string mappedName, ITransactionAttribute transactionAttribute ) - { - // TODO address method overloading? At present this will - // simply match all methods that have the given name. - string name = type.Name + "." + mappedName; - MethodInfo[] methods = type.GetMethods(); - IList matchingMethods = new ArrayList(); - for ( int i = 0; i < methods.Length; i++ ) - { - if ( methods[i].Name.Equals( mappedName ) || IsMatch(methods[i].Name, mappedName )) - { - matchingMethods.Add( methods[i] ); - } - } - if ( matchingMethods.Count == 0 ) - { - throw new TransactionUsageException("Couldn't find method '" + mappedName + "' on Type [" + type.Name + "]"); - } - // register all matching methods - foreach ( MethodInfo currentMethod in matchingMethods ) - { - string regularMethodName = (string)_nameMap[currentMethod]; - if ( regularMethodName == null || ( !regularMethodName.Equals(name) && regularMethodName.Length <= name.Length)) - { - // No already registered method name, or more specific - // method name specification now -> (re-)register method. - if (LOG.IsEnabled(LogLevel.Debug) && regularMethodName != null) - { - LOG.LogDebug("Replacing attribute for transactional method [" + currentMethod + "]: current name '" + - name + "' is more specific than '" + regularMethodName + "'"); - } - _nameMap.Add( currentMethod, name ); - AddTransactionalMethod( currentMethod, transactionAttribute ); - } + string name = entry.Key as string; + ITransactionAttribute attribute = null; + //Check if we need to convert from a string to ITransactionAttribute + if (entry.Value is ITransactionAttribute) + { + attribute = entry.Value as ITransactionAttribute; + } else - { - if (LOG.IsEnabled(LogLevel.Debug) && regularMethodName != null) - { - LOG.LogDebug("Keeping attribute for transactional method [" + currentMethod + "]: current name '" + - name + "' is not more specific than '" + regularMethodName + "'"); - } - } - } - } + { + TransactionAttributeEditor editor = new TransactionAttributeEditor(); + editor.SetAsText(entry.Value.ToString()); + attribute = editor.Value; + } - /// - /// Add an attribute for a transactional method. - /// - /// The transactional method. - /// - /// The attribute to be associated with the method. - /// - public void AddTransactionalMethod( MethodInfo method, ITransactionAttribute transactionAttribute ) - { - _methodMap.Add( method, transactionAttribute ); - } + AddTransactionalMethod(name, attribute); + } + } + } - /// - /// Does the supplied match the supplied ? - /// - /// - /// The default implementation checks for "xxx*", "*xxx" and "*xxx*" matches, - /// as well as direct equality. This behaviour can (of course) be overridden in - /// derived classes. - /// - /// The method name of the class. - /// The name in the descriptor. - /// True if the names match. - protected virtual bool IsMatch( string methodName, string mappedName ) - { - return PatternMatchUtils.SimpleMatch(mappedName, methodName); - } + /// + /// Add an attribute for a transactional method. + /// + /// + /// Method names can end or start with "*" for matching multiple methods. + /// + /// The class and method name, separated by a dot. + /// The attribute to be associated with the method. + public void AddTransactionalMethod(string name, ITransactionAttribute attribute) + { + AssertUtils.ArgumentNotNull(name, "name"); + int lastCommaIndex = name.LastIndexOf(","); + if (lastCommaIndex == -1) + { + throw new ArgumentException("'" + name + "'" + + " is not a valid method name, missing AssemblyName. Format is FQN.MethodName, AssemblyName."); + } - #region ITransactionAttributeSource Members - /// - /// Return the for this - /// method. - /// - /// The method to check. - /// - /// The target . May be null, in which case the declaring - /// class of the supplied must be used. - /// - /// - /// A or - /// null if the method is non-transactional. - /// - public ITransactionAttribute ReturnTransactionAttribute(MethodInfo method, Type targetType) - { - //Might have registered MethodInfo objects whose declaring type is the interface, so 'downcast' - //to the most specific method which is typically what is passed in as the first method argument. - foreach (DictionaryEntry dictionaryEntry in _methodMap) + string fqnWithMethod = name.Substring(0, lastCommaIndex); + + int lastDotIndex = fqnWithMethod.LastIndexOf("."); + if (lastDotIndex == -1) + { + throw new TransactionUsageException("'" + fqnWithMethod + "' is not a valid method name: format is FQN.methodName"); + } + + string className = fqnWithMethod.Substring(0, lastDotIndex); + string assemblyName = name.Substring(lastCommaIndex + 1); + string methodName = fqnWithMethod.Substring(lastDotIndex + 1); + string fqnClassName = className + ", " + assemblyName; + try + { + Type type = TypeResolutionUtils.ResolveType(fqnClassName); + AddTransactionalMethod(type, methodName, attribute); + } + catch (TypeLoadException exception) + { + throw new TransactionUsageException("Type '" + fqnClassName + "' not found.", exception); + } + } + + /// + /// Add an attribute for a transactional method. + /// + /// + /// Method names can end or start with "*" for matching multiple methods. + /// + /// The target interface or class. + /// The mapped method name. + /// + /// The attribute to be associated with the method. + /// + public void AddTransactionalMethod( + Type type, string mappedName, ITransactionAttribute transactionAttribute) + { + // TODO address method overloading? At present this will + // simply match all methods that have the given name. + string name = type.Name + "." + mappedName; + MethodInfo[] methods = type.GetMethods(); + IList matchingMethods = new ArrayList(); + for (int i = 0; i < methods.Length; i++) + { + if (methods[i].Name.Equals(mappedName) || IsMatch(methods[i].Name, mappedName)) { - MethodInfo currentMethod = (MethodInfo)dictionaryEntry.Key; + matchingMethods.Add(methods[i]); + } + } - MethodInfo specificMethod; - if (targetType == null) + if (matchingMethods.Count == 0) + { + throw new TransactionUsageException("Couldn't find method '" + mappedName + "' on Type [" + type.Name + "]"); + } + + // register all matching methods + foreach (MethodInfo currentMethod in matchingMethods) + { + string regularMethodName = (string) _nameMap[currentMethod]; + if (regularMethodName == null || (!regularMethodName.Equals(name) && regularMethodName.Length <= name.Length)) + { + // No already registered method name, or more specific + // method name specification now -> (re-)register method. + if (LOG.IsEnabled(LogLevel.Debug) && regularMethodName != null) + { + LOG.LogDebug("Replacing attribute for transactional method [" + currentMethod + "]: current name '" + + name + "' is more specific than '" + regularMethodName + "'"); + } + + _nameMap.Add(currentMethod, name); + AddTransactionalMethod(currentMethod, transactionAttribute); + } + else + { + if (LOG.IsEnabled(LogLevel.Debug) && regularMethodName != null) + { + LOG.LogDebug("Keeping attribute for transactional method [" + currentMethod + "]: current name '" + + name + "' is not more specific than '" + regularMethodName + "'"); + } + } + } + } + + /// + /// Add an attribute for a transactional method. + /// + /// The transactional method. + /// + /// The attribute to be associated with the method. + /// + public void AddTransactionalMethod(MethodInfo method, ITransactionAttribute transactionAttribute) + { + _methodMap.Add(method, transactionAttribute); + } + + /// + /// Does the supplied match the supplied ? + /// + /// + /// The default implementation checks for "xxx*", "*xxx" and "*xxx*" matches, + /// as well as direct equality. This behaviour can (of course) be overridden in + /// derived classes. + /// + /// The method name of the class. + /// The name in the descriptor. + /// True if the names match. + protected virtual bool IsMatch(string methodName, string mappedName) + { + return PatternMatchUtils.SimpleMatch(mappedName, methodName); + } + + #region ITransactionAttributeSource Members + + /// + /// Return the for this + /// method. + /// + /// The method to check. + /// + /// The target . May be null, in which case the declaring + /// class of the supplied must be used. + /// + /// + /// A or + /// null if the method is non-transactional. + /// + public ITransactionAttribute ReturnTransactionAttribute(MethodInfo method, Type targetType) + { + //Might have registered MethodInfo objects whose declaring type is the interface, so 'downcast' + //to the most specific method which is typically what is passed in as the first method argument. + foreach (DictionaryEntry dictionaryEntry in _methodMap) + { + MethodInfo currentMethod = (MethodInfo) dictionaryEntry.Key; + + MethodInfo specificMethod; + if (targetType == null) + { + specificMethod = currentMethod; + } + else + { + ParameterInfo[] parameters = currentMethod.GetParameters(); + + ComposedCriteria searchCriteria = new ComposedCriteria(); + searchCriteria.Add(new MethodNameMatchCriteria(currentMethod.Name)); + searchCriteria.Add(new MethodParametersCountCriteria(parameters.Length)); + searchCriteria.Add(new MethodGenericArgumentsCountCriteria(currentMethod.GetGenericArguments().Length)); + searchCriteria.Add(new MethodParametersCriteria(ReflectionUtils.GetParameterTypes(parameters))); + + MemberInfo[] matchingMethods = targetType.FindMembers( + MemberTypes.Method, + BindingFlags.Instance | BindingFlags.Public, + new MemberFilter(new CriteriaMemberFilter().FilterMemberByCriteria), + searchCriteria); + + if (matchingMethods != null && matchingMethods.Length == 1) + { + specificMethod = matchingMethods[0] as MethodInfo; + } + else { specificMethod = currentMethod; } - else - { - ParameterInfo[] parameters = currentMethod.GetParameters(); - - ComposedCriteria searchCriteria = new ComposedCriteria(); - searchCriteria.Add(new MethodNameMatchCriteria(currentMethod.Name)); - searchCriteria.Add(new MethodParametersCountCriteria(parameters.Length)); - searchCriteria.Add(new MethodGenericArgumentsCountCriteria(currentMethod.GetGenericArguments().Length)); - searchCriteria.Add(new MethodParametersCriteria(ReflectionUtils.GetParameterTypes(parameters))); - - MemberInfo[] matchingMethods = targetType.FindMembers( - MemberTypes.Method, - BindingFlags.Instance | BindingFlags.Public, - new MemberFilter(new CriteriaMemberFilter().FilterMemberByCriteria), - searchCriteria); - - if (matchingMethods != null && matchingMethods.Length == 1) - { - specificMethod = matchingMethods[0] as MethodInfo; - } - else - { - specificMethod = currentMethod; - } - } - - if (method == specificMethod) - { - return (ITransactionAttribute)dictionaryEntry.Value; - } } - return (ITransactionAttribute)_methodMap[method]; - } - #endregion + if (method == specificMethod) + { + return (ITransactionAttribute) dictionaryEntry.Value; + } + } - } + return (ITransactionAttribute) _methodMap[method]; + } + + #endregion } diff --git a/src/Spring/Spring.Data/Transaction/Interceptor/NameMatchTransactionAttributeSource.cs b/src/Spring/Spring.Data/Transaction/Interceptor/NameMatchTransactionAttributeSource.cs index 4d043475..990032a3 100644 --- a/src/Spring/Spring.Data/Transaction/Interceptor/NameMatchTransactionAttributeSource.cs +++ b/src/Spring/Spring.Data/Transaction/Interceptor/NameMatchTransactionAttributeSource.cs @@ -24,205 +24,210 @@ using System.Reflection; using Microsoft.Extensions.Logging; using Spring.Util; -namespace Spring.Transaction.Interceptor +namespace Spring.Transaction.Interceptor; + +/// +/// Simple implementation of the +/// that allows attributes to be matched by registered name. +/// +/// Juergen Hoeller +/// Griffin Caprio (.NET) +[Serializable] +public class NameMatchTransactionAttributeSource : ITransactionAttributeSource, IEnumerable { - /// - /// Simple implementation of the - /// that allows attributes to be matched by registered name. - /// - /// Juergen Hoeller - /// Griffin Caprio (.NET) - [Serializable] - public class NameMatchTransactionAttributeSource : ITransactionAttributeSource, IEnumerable - { - /// - /// Logger available to subclasses, static for optimal serialization - /// - [NonSerialized()] - protected static readonly ILogger log = LogManager.GetLogger(); + /// + /// Logger available to subclasses, static for optimal serialization + /// + [NonSerialized()] protected static readonly ILogger log = LogManager.GetLogger(); - /// - /// Keys are method names; values are ITransactionAttributes - /// - private readonly IDictionary nameMap; + /// + /// Keys are method names; values are ITransactionAttributes + /// + private readonly IDictionary nameMap; - /// - /// Creates a new instance of the - /// class. - /// - public NameMatchTransactionAttributeSource() - { - nameMap = new Hashtable(); - } + /// + /// Creates a new instance of the + /// class. + /// + public NameMatchTransactionAttributeSource() + { + nameMap = new Hashtable(); + } - /// - /// Enumerate the string/ mapping entries. - /// - public IEnumerator GetEnumerator() - { - return nameMap.GetEnumerator(); - } + /// + /// Enumerate the string/ mapping entries. + /// + public IEnumerator GetEnumerator() + { + return nameMap.GetEnumerator(); + } - /// - /// Add a mapping. - /// - public void Add(string methodPattern, ITransactionAttribute txAttribute) + /// + /// Add a mapping. + /// + public void Add(string methodPattern, ITransactionAttribute txAttribute) + { + AddTransactionMethod(methodPattern, txAttribute); + } + + /// + /// Add a mapping. + /// + public void Add(string methodPattern, string txAttributeText) + { + TransactionAttributeEditor editor = new TransactionAttributeEditor(); + editor.SetAsText(txAttributeText); + ITransactionAttribute txAttribute = editor.Value; + AddTransactionMethod(methodPattern, txAttribute); + } + + /// + /// Set a name/attribute map, consisting of method names (e.g. "MyMethod") and + /// instances + /// (or Strings to be converted to ITransactionAttribute instances). + /// + public IDictionary NameMap + { + set { - AddTransactionMethod(methodPattern, txAttribute); - } - - /// - /// Add a mapping. - /// - public void Add(string methodPattern, string txAttributeText) - { - TransactionAttributeEditor editor = new TransactionAttributeEditor(); - editor.SetAsText(txAttributeText); - ITransactionAttribute txAttribute = editor.Value; - AddTransactionMethod(methodPattern, txAttribute); - } - - /// - /// Set a name/attribute map, consisting of method names (e.g. "MyMethod") and - /// instances - /// (or Strings to be converted to ITransactionAttribute instances). - /// - public IDictionary NameMap - { - set - { - foreach (DictionaryEntry entry in value) - { - string name = entry.Key as string; - ITransactionAttribute attribute = null; - if (entry.Value is ITransactionAttribute) - { - attribute = entry.Value as ITransactionAttribute; - } - else - { - TransactionAttributeEditor editor = new TransactionAttributeEditor(); - editor.SetAsText(entry.Value.ToString()); - attribute = editor.Value; - } - AddTransactionMethod(name, attribute); - } - } - } - - /// - /// Parses the given properties into a name/attribute map. - /// - /// - /// Expects method names as keys and string attributes definitions as values, - /// parsable into - /// instances via - /// . - /// - /// The properties of the transaction. - public NameValueCollection NameProperties - { - set - { - SetProperties(value); - } - } - - /// - /// Does the supplied match the supplied ? - /// - /// - /// The default implementation checks for "xxx*", "*xxx" and "*xxx*" matches, - /// as well as direct equality. Can be overridden in subclasses. - /// - /// The method name of the class. - /// The name in the descriptor. - /// True if the names match. - protected virtual bool IsMatch( string methodName, string mappedName ) - { - return PatternMatchUtils.SimpleMatch(mappedName, methodName); - } - - /// - /// Add an attribute for a transactional method. - /// - /// - ///

- /// Method names can end with "*" for matching multiple methods. - ///

- ///
- /// The transactional method name. - /// - /// The attribute to be associated with the method. - /// - public void AddTransactionMethod( string methodName, ITransactionAttribute attribute ) - { - #region Instrumentation - if (log.IsEnabled(LogLevel.Debug)) + foreach (DictionaryEntry entry in value) { - log.LogDebug("Adding transactional method [" + methodName + "] with attribute [" + attribute + "]"); + string name = entry.Key as string; + ITransactionAttribute attribute = null; + if (entry.Value is ITransactionAttribute) + { + attribute = entry.Value as ITransactionAttribute; + } + else + { + TransactionAttributeEditor editor = new TransactionAttributeEditor(); + editor.SetAsText(entry.Value.ToString()); + attribute = editor.Value; + } + + AddTransactionMethod(name, attribute); } - #endregion - nameMap.Add( methodName, attribute ); - } + } + } - /// - /// Parses the given properties into a name/attribute map. - /// - /// - /// Expects method names as keys and string attributes definitions as values, - /// parsable into - /// instances via - /// . - /// - /// The properties of the transaction. - public void SetProperties( NameValueCollection transactionAttributes ) - { - TransactionAttributeEditor editor = new TransactionAttributeEditor(); - foreach ( string methodName in transactionAttributes.Keys ) - { - string value = transactionAttributes[methodName]; - editor.SetAsText(value); - AddTransactionMethod(methodName, editor.Value); - } - } + /// + /// Parses the given properties into a name/attribute map. + /// + /// + /// Expects method names as keys and string attributes definitions as values, + /// parsable into + /// instances via + /// . + /// + /// The properties of the transaction. + public NameValueCollection NameProperties + { + set + { + SetProperties(value); + } + } - #region ITransactionAttributeSource Members - /// - /// Return the for this - /// method. - /// - /// The method to check. - /// - /// The target . May be null, in which case the declaring - /// class of the supplied must be used. - /// - /// - /// A or - /// null if the method is non-transactional. - /// - public ITransactionAttribute ReturnTransactionAttribute(MethodInfo method, Type targetType) - { - string methodName = method.Name; - ITransactionAttribute attribute = (ITransactionAttribute) nameMap[methodName]; - if ( attribute != null ) - { - return attribute; - } - else - { - string bestNameMatch = null; - foreach ( string mappedName in nameMap.Keys ) - { - if ( ( IsMatch( methodName, mappedName ) ) && ( bestNameMatch == null || bestNameMatch.Length <= mappedName.Length ) ) - { - attribute = (ITransactionAttribute) nameMap[mappedName]; - bestNameMatch = mappedName; - } - } - } - return attribute; - } - #endregion - } + /// + /// Does the supplied match the supplied ? + /// + /// + /// The default implementation checks for "xxx*", "*xxx" and "*xxx*" matches, + /// as well as direct equality. Can be overridden in subclasses. + /// + /// The method name of the class. + /// The name in the descriptor. + /// True if the names match. + protected virtual bool IsMatch(string methodName, string mappedName) + { + return PatternMatchUtils.SimpleMatch(mappedName, methodName); + } + + /// + /// Add an attribute for a transactional method. + /// + /// + ///

+ /// Method names can end with "*" for matching multiple methods. + ///

+ ///
+ /// The transactional method name. + /// + /// The attribute to be associated with the method. + /// + public void AddTransactionMethod(string methodName, ITransactionAttribute attribute) + { + #region Instrumentation + + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug("Adding transactional method [" + methodName + "] with attribute [" + attribute + "]"); + } + + #endregion + + nameMap.Add(methodName, attribute); + } + + /// + /// Parses the given properties into a name/attribute map. + /// + /// + /// Expects method names as keys and string attributes definitions as values, + /// parsable into + /// instances via + /// . + /// + /// The properties of the transaction. + public void SetProperties(NameValueCollection transactionAttributes) + { + TransactionAttributeEditor editor = new TransactionAttributeEditor(); + foreach (string methodName in transactionAttributes.Keys) + { + string value = transactionAttributes[methodName]; + editor.SetAsText(value); + AddTransactionMethod(methodName, editor.Value); + } + } + + #region ITransactionAttributeSource Members + + /// + /// Return the for this + /// method. + /// + /// The method to check. + /// + /// The target . May be null, in which case the declaring + /// class of the supplied must be used. + /// + /// + /// A or + /// null if the method is non-transactional. + /// + public ITransactionAttribute ReturnTransactionAttribute(MethodInfo method, Type targetType) + { + string methodName = method.Name; + ITransactionAttribute attribute = (ITransactionAttribute) nameMap[methodName]; + if (attribute != null) + { + return attribute; + } + else + { + string bestNameMatch = null; + foreach (string mappedName in nameMap.Keys) + { + if ((IsMatch(methodName, mappedName)) && (bestNameMatch == null || bestNameMatch.Length <= mappedName.Length)) + { + attribute = (ITransactionAttribute) nameMap[mappedName]; + bestNameMatch = mappedName; + } + } + } + + return attribute; + } + + #endregion } diff --git a/src/Spring/Spring.Data/Transaction/Interceptor/NoRollbackRuleAttribute.cs b/src/Spring/Spring.Data/Transaction/Interceptor/NoRollbackRuleAttribute.cs index abe457e9..fd9d9498 100644 --- a/src/Spring/Spring.Data/Transaction/Interceptor/NoRollbackRuleAttribute.cs +++ b/src/Spring/Spring.Data/Transaction/Interceptor/NoRollbackRuleAttribute.cs @@ -18,29 +18,28 @@ #endregion -namespace Spring.Transaction.Interceptor -{ - /// - /// Tag class. Its class means it has the opposite behaviour to the - /// superclass. - /// - /// Rod Johnson - /// Griffin Caprio (.NET) - public class NoRollbackRuleAttribute : RollbackRuleAttribute - { - /// - /// Creates a new instance of the - /// class. - /// - public NoRollbackRuleAttribute( string exceptionType ) : base( exceptionType ){} +namespace Spring.Transaction.Interceptor; - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The class that will trigger a rollback. - /// - public NoRollbackRuleAttribute( Type exceptionType ) : base( exceptionType ){} - } +/// +/// Tag class. Its class means it has the opposite behaviour to the +/// superclass. +/// +/// Rod Johnson +/// Griffin Caprio (.NET) +public class NoRollbackRuleAttribute : RollbackRuleAttribute +{ + /// + /// Creates a new instance of the + /// class. + /// + public NoRollbackRuleAttribute(string exceptionType) : base(exceptionType) { } + + /// + /// Creates a new instance of the + /// class. + /// + /// + /// The class that will trigger a rollback. + /// + public NoRollbackRuleAttribute(Type exceptionType) : base(exceptionType) { } } diff --git a/src/Spring/Spring.Data/Transaction/Interceptor/ObjectFactoryTransactionAttributeSourceAdvisor.cs b/src/Spring/Spring.Data/Transaction/Interceptor/ObjectFactoryTransactionAttributeSourceAdvisor.cs index 5f6fc392..68f93c19 100644 --- a/src/Spring/Spring.Data/Transaction/Interceptor/ObjectFactoryTransactionAttributeSourceAdvisor.cs +++ b/src/Spring/Spring.Data/Transaction/Interceptor/ObjectFactoryTransactionAttributeSourceAdvisor.cs @@ -1,74 +1,72 @@ -#region License - -/* - * Copyright 2002-2010 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 - +#region License + +/* + * Copyright 2002-2010 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 Spring.Aop; using Spring.Aop.Support; -namespace Spring.Transaction.Interceptor +namespace Spring.Transaction.Interceptor; + +public class ObjectFactoryTransactionAttributeSourceAdvisor : AbstractObjectFactoryPointcutAdvisor { - public class ObjectFactoryTransactionAttributeSourceAdvisor : AbstractObjectFactoryPointcutAdvisor + private ITransactionAttributeSource _transactionAttributeSource; + private IPointcut _pointcut; + + public ObjectFactoryTransactionAttributeSourceAdvisor() { + _pointcut = new TransactonAttributeSourcePointcut(this); + } - private ITransactionAttributeSource _transactionAttributeSource; - private IPointcut _pointcut; + private class TransactonAttributeSourcePointcut : AbstractTransactionAttributeSourcePointcut + { + private ObjectFactoryTransactionAttributeSourceAdvisor outer; - public ObjectFactoryTransactionAttributeSourceAdvisor() + public TransactonAttributeSourcePointcut(ObjectFactoryTransactionAttributeSourceAdvisor outer) { - _pointcut = new TransactonAttributeSourcePointcut(this); + this.outer = outer; } + #region Overrides of AbstractTransactionAttributeSourcePointcut - private class TransactonAttributeSourcePointcut : AbstractTransactionAttributeSourcePointcut + protected override ITransactionAttributeSource TransactionAttributeSource { - 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; } + 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/RollbackRuleAttribute.cs b/src/Spring/Spring.Data/Transaction/Interceptor/RollbackRuleAttribute.cs index 6710bea2..0d08a167 100644 --- a/src/Spring/Spring.Data/Transaction/Interceptor/RollbackRuleAttribute.cs +++ b/src/Spring/Spring.Data/Transaction/Interceptor/RollbackRuleAttribute.cs @@ -20,187 +20,189 @@ using Spring.Util; -namespace Spring.Transaction.Interceptor +namespace Spring.Transaction.Interceptor; + +/// +/// Rule determining whether or not a given exception (and any subclasses) should +/// cause a rollback. +/// +/// +///

+/// Multiple such rules can be applied to determine whether a transaction should commit +/// or rollback after an exception has been thrown. +///

+///
+/// Griffin Caprio (.NET) +[Serializable] +public class RollbackRuleAttribute : Attribute { - /// - /// Rule determining whether or not a given exception (and any subclasses) should - /// cause a rollback. - /// - /// - ///

- /// Multiple such rules can be applied to determine whether a transaction should commit - /// or rollback after an exception has been thrown. - ///

- ///
- /// Griffin Caprio (.NET) - [Serializable] - public class RollbackRuleAttribute : Attribute - { - /// - /// Could hold exception, resolving class name but would always require FQN. - /// This way does multiple string comparisons, but how often do we decide - /// whether to roll back a transaction following an exception? - /// - private string _exceptionName; + /// + /// Could hold exception, resolving class name but would always require FQN. + /// This way does multiple string comparisons, but how often do we decide + /// whether to roll back a transaction following an exception? + /// + private string _exceptionName; - /// - /// Canonical instance representing default behavior for rolling back on - /// all s. - /// - public static RollbackRuleAttribute RollbackOnSystemExceptions - = new RollbackRuleAttribute(typeof (Exception).Name); + /// + /// Canonical instance representing default behavior for rolling back on + /// all s. + /// + public static RollbackRuleAttribute RollbackOnSystemExceptions + = new RollbackRuleAttribute(typeof(Exception).Name); - /// - /// Creates a new instance of the - /// class - /// for the named . - /// - /// The exception name. - /// - ///

- /// As always, the should be the full - /// assembly qualified version. - ///

- ///
- public RollbackRuleAttribute( string exceptionName ) - { - AssertUtils.ArgumentHasText(exceptionName, "exceptionName"); - _exceptionName = exceptionName; - } + /// + /// Creates a new instance of the + /// class + /// for the named . + /// + /// The exception name. + /// + ///

+ /// As always, the should be the full + /// assembly qualified version. + ///

+ ///
+ public RollbackRuleAttribute(string exceptionName) + { + AssertUtils.ArgumentHasText(exceptionName, "exceptionName"); + _exceptionName = exceptionName; + } - /// - /// Creates a new instance of the - /// class - /// for the suplied . - /// - /// - ///

- /// The exception class must be or a subclass. - ///

- ///

- /// This is the preferred way to construct a - /// , - /// matching the exception class and subclasses. - ///

- ///
- /// - /// The class that will trigger a rollback. - /// - public RollbackRuleAttribute( Type exceptionType ) - { - AssertUtils.ArgumentNotNull(exceptionType, "exceptionType"); - if ( ! typeof(Exception).IsAssignableFrom( exceptionType ) ) - { - throw new ArgumentException("Cannot construct rollback rule from " + exceptionType + "; " + "It's not an Exception"); - } - _exceptionName = exceptionType.Name; - } + /// + /// Creates a new instance of the + /// class + /// for the suplied . + /// + /// + ///

+ /// The exception class must be or a subclass. + ///

+ ///

+ /// This is the preferred way to construct a + /// , + /// matching the exception class and subclasses. + ///

+ ///
+ /// + /// The class that will trigger a rollback. + /// + public RollbackRuleAttribute(Type exceptionType) + { + AssertUtils.ArgumentNotNull(exceptionType, "exceptionType"); + if (!typeof(Exception).IsAssignableFrom(exceptionType)) + { + throw new ArgumentException("Cannot construct rollback rule from " + exceptionType + "; " + "It's not an Exception"); + } - /// - /// Returns the name of the exception. - /// - public string ExceptionName - { - get { return _exceptionName; } - } + _exceptionName = exceptionType.Name; + } - /// - /// Return the depth to the matching superclass execption . - /// - /// - /// A return value of 0 means that the matches. - /// - /// - /// The of exception to find. - /// - /// - /// Return -1 if there's no match. Otherwise, return depth. Lowest depth wins. - /// - public int GetDepth( Type exceptionType ) - { - return getDepth( exceptionType, 0 ); - } + /// + /// Returns the name of the exception. + /// + public string ExceptionName + { + get { return _exceptionName; } + } - /// - /// Return the depth to the matching superclass execption . - /// - /// - /// A return value of 0 means that the s - /// matches. - /// - /// - /// The exception object to find. - /// - /// - /// Return -1 if there's no match. Otherwise, return depth. Lowest depth wins. - /// - public int GetDepth( object exception ) - { - return GetDepth( exception.GetType() ); - } + /// + /// Return the depth to the matching superclass execption . + /// + /// + /// A return value of 0 means that the matches. + /// + /// + /// The of exception to find. + /// + /// + /// Return -1 if there's no match. Otherwise, return depth. Lowest depth wins. + /// + public int GetDepth(Type exceptionType) + { + return getDepth(exceptionType, 0); + } - /// - /// Returns a representation of this instance. - /// - /// - /// A containing the exception covered by this instance. - /// - public override string ToString() - { - return "RollbackRule with pattern '" + ExceptionName + "'"; - } + /// + /// Return the depth to the matching superclass execption . + /// + /// + /// A return value of 0 means that the s + /// matches. + /// + /// + /// The exception object to find. + /// + /// + /// Return -1 if there's no match. Otherwise, return depth. Lowest depth wins. + /// + public int GetDepth(object exception) + { + return GetDepth(exception.GetType()); + } - /// - /// Override of . - /// - /// The hashcode of the exception name covered by this instance. - public override int GetHashCode() - { - return base.GetHashCode(); - } + /// + /// Returns a representation of this instance. + /// + /// + /// A containing the exception covered by this instance. + /// + public override string ToString() + { + return "RollbackRule with pattern '" + ExceptionName + "'"; + } + /// + /// Override of . + /// + /// The hashcode of the exception name covered by this instance. + public override int GetHashCode() + { + return base.GetHashCode(); + } - /// - /// Override of . - /// - /// The object to compare. - /// True if the input object is equal to this instance. - public override bool Equals(object obj) - { - if (ReferenceEquals(this, obj)) return true; - RollbackRuleAttribute rollbackRuleAttribute = obj as RollbackRuleAttribute; - if ( rollbackRuleAttribute == null ) - { - return false; - } - return Equals( rollbackRuleAttribute ); - } + /// + /// Override of . + /// + /// The object to compare. + /// True if the input object is equal to this instance. + public override bool Equals(object obj) + { + if (ReferenceEquals(this, obj)) return true; + RollbackRuleAttribute rollbackRuleAttribute = obj as RollbackRuleAttribute; + if (rollbackRuleAttribute == null) + { + return false; + } - /// - /// Strongly typed Equals() implementation. - /// - /// - /// The to compare. - /// - /// - /// True if the input object is equal to the supplied . - /// - public bool Equals( RollbackRuleAttribute rollbackRuleAttribute ) - { - return base.Equals(rollbackRuleAttribute); - } + return Equals(rollbackRuleAttribute); + } - private int getDepth( Type exceptionType, int depth ) - { - if ( ( exceptionType.Name.IndexOf( ExceptionName ) != -1 ) || ( exceptionType.FullName.IndexOf( ExceptionName ) != -1 ) ) - { - return depth; - } - if ( exceptionType == typeof(Exception)) - { - return -1; - } - return getDepth( exceptionType.BaseType, depth + 1 ); - } - } + /// + /// Strongly typed Equals() implementation. + /// + /// + /// The to compare. + /// + /// + /// True if the input object is equal to the supplied . + /// + public bool Equals(RollbackRuleAttribute rollbackRuleAttribute) + { + return base.Equals(rollbackRuleAttribute); + } + + private int getDepth(Type exceptionType, int depth) + { + if ((exceptionType.Name.IndexOf(ExceptionName) != -1) || (exceptionType.FullName.IndexOf(ExceptionName) != -1)) + { + return depth; + } + + if (exceptionType == typeof(Exception)) + { + return -1; + } + + return getDepth(exceptionType.BaseType, depth + 1); + } } diff --git a/src/Spring/Spring.Data/Transaction/Interceptor/RuleBasedTransactionAttribute.cs b/src/Spring/Spring.Data/Transaction/Interceptor/RuleBasedTransactionAttribute.cs index 69178108..d1b3eea4 100644 --- a/src/Spring/Spring.Data/Transaction/Interceptor/RuleBasedTransactionAttribute.cs +++ b/src/Spring/Spring.Data/Transaction/Interceptor/RuleBasedTransactionAttribute.cs @@ -19,139 +19,142 @@ #endregion using System.Text; - using Spring.Collections; -namespace Spring.Transaction.Interceptor +namespace Spring.Transaction.Interceptor; + +/// +/// implementation +/// that works out whether a given exception should cause transaction rollback by applying +/// a number of rollback rules, both positive and negative. +/// +/// +/// If no rules are relevant to the exception, it behaves like the +/// class +/// (rolling back on runtime exceptions).. +///

+/// The +/// creates objects of this class. +///

+///
+/// Rod Johnson +/// Griffin Caprio (.NET) +public class RuleBasedTransactionAttribute : DefaultTransactionAttribute { - /// - /// implementation - /// that works out whether a given exception should cause transaction rollback by applying - /// a number of rollback rules, both positive and negative. - /// - /// - /// If no rules are relevant to the exception, it behaves like the - /// class - /// (rolling back on runtime exceptions).. - ///

- /// The - /// creates objects of this class. - ///

- ///
- /// Rod Johnson - /// Griffin Caprio (.NET) - public class RuleBasedTransactionAttribute : DefaultTransactionAttribute - { - private IList _rollbackRules; + private IList _rollbackRules; - /// - /// Creates a new instance of the - /// - /// class. - /// - /// - /// The desired transaction propagation behaviour. - /// - /// - /// The rollback rules list for this transaction attribute. - /// - public RuleBasedTransactionAttribute( - TransactionPropagation transactionPropagation, - IList ruleList ) - : base(transactionPropagation) - { - _rollbackRules = ruleList; - } + /// + /// Creates a new instance of the + /// + /// class. + /// + /// + /// The desired transaction propagation behaviour. + /// + /// + /// The rollback rules list for this transaction attribute. + /// + public RuleBasedTransactionAttribute( + TransactionPropagation transactionPropagation, + IList ruleList) + : base(transactionPropagation) + { + _rollbackRules = ruleList; + } - /// - /// Creates a new instance of the - /// - /// class. - /// - public RuleBasedTransactionAttribute( ) - { - _rollbackRules = new List(); - } + /// + /// Creates a new instance of the + /// + /// class. + /// + public RuleBasedTransactionAttribute() + { + _rollbackRules = new List(); + } - /// - /// Sets the rollback rules list for this transaction attribute. - /// - public IList RollbackRules - { - set => _rollbackRules = value; - } + /// + /// Sets the rollback rules list for this transaction attribute. + /// + public IList RollbackRules + { + set => _rollbackRules = value; + } - /// - /// Will a transaction be rolled back if the supplied - /// is thrown during the lifecycle of a transaction to which this attribute is applied? - /// - /// The offending . - /// True if the exception should cause a rollback, false otherwise. - public override bool RollbackOn(Exception exception) - { - RollbackRuleAttribute finalAttribute = null; - int deepest = Int32.MaxValue; + /// + /// Will a transaction be rolled back if the supplied + /// is thrown during the lifecycle of a transaction to which this attribute is applied? + /// + /// The offending . + /// True if the exception should cause a rollback, false otherwise. + public override bool RollbackOn(Exception exception) + { + RollbackRuleAttribute finalAttribute = null; + int deepest = Int32.MaxValue; - if ( _rollbackRules != null ) - { - foreach ( RollbackRuleAttribute rule in _rollbackRules ) - { - int depth = rule.GetDepth( exception ); - if ( ( depth >= 0 ) && ( depth < deepest ) ) - { - deepest = depth; - finalAttribute = rule; - } - } - } - if ( null == finalAttribute ) - { - return base.RollbackOn( exception ); - } - return !( finalAttribute is NoRollbackRuleAttribute ); - } + if (_rollbackRules != null) + { + foreach (RollbackRuleAttribute rule in _rollbackRules) + { + int depth = rule.GetDepth(exception); + if ((depth >= 0) && (depth < deepest)) + { + deepest = depth; + finalAttribute = rule; + } + } + } - /// - /// Returns a representation of this instance. - /// - /// - /// A representation of this instance. - /// - public override string ToString() - { - StringBuilder result = new StringBuilder(); - result.Append(DefinitionDescription); - SortedSet rules = new SortedSet(); - foreach ( RollbackRuleAttribute rule in _rollbackRules ) - { - string sign = ( rule is NoRollbackRuleAttribute ) ? COMMIT_RULE_PREFIX : ROLLBACK_RULE_PREFIX; - rules.Add( sign + rule.ExceptionName ); - } - foreach ( string rule in rules ) - { - result.Append(','); - result.Append(rule); - } - return result.ToString( ); - } - /// - /// Adds a to this - /// attributes list of rollback rules. - /// - /// - /// The to add. - /// - public void AddRollbackRule( RollbackRuleAttribute rule ) - { - _rollbackRules.Add( rule ); - } + if (null == finalAttribute) + { + return base.RollbackOn(exception); + } - /// - /// Clears the rollback rules for this attribute. - /// - public void ClearRollbackRules() - { - _rollbackRules.Clear(); - } - } + return !(finalAttribute is NoRollbackRuleAttribute); + } + + /// + /// Returns a representation of this instance. + /// + /// + /// A representation of this instance. + /// + public override string ToString() + { + StringBuilder result = new StringBuilder(); + result.Append(DefinitionDescription); + SortedSet rules = new SortedSet(); + foreach (RollbackRuleAttribute rule in _rollbackRules) + { + string sign = (rule is NoRollbackRuleAttribute) ? COMMIT_RULE_PREFIX : ROLLBACK_RULE_PREFIX; + rules.Add(sign + rule.ExceptionName); + } + + foreach (string rule in rules) + { + result.Append(','); + result.Append(rule); + } + + return result.ToString(); + } + + /// + /// Adds a to this + /// attributes list of rollback rules. + /// + /// + /// The to add. + /// + public void AddRollbackRule(RollbackRuleAttribute rule) + { + _rollbackRules.Add(rule); + } + + /// + /// Clears the rollback rules for this attribute. + /// + public void ClearRollbackRules() + { + _rollbackRules.Clear(); + } } diff --git a/src/Spring/Spring.Data/Transaction/Interceptor/TransactionAspectSupport.cs b/src/Spring/Spring.Data/Transaction/Interceptor/TransactionAspectSupport.cs index eee81fcd..de0be6e9 100644 --- a/src/Spring/Spring.Data/Transaction/Interceptor/TransactionAspectSupport.cs +++ b/src/Spring/Spring.Data/Transaction/Interceptor/TransactionAspectSupport.cs @@ -25,470 +25,474 @@ using Spring.Objects.Factory; using Spring.Threading; using Spring.Util; -namespace Spring.Transaction.Interceptor +namespace Spring.Transaction.Interceptor; + +/// +/// Superclass for transaction aspects, such as the AOP Alliance-compatible +/// . +/// +/// +///

+/// This enables the underlying Spring transaction infrastructure to be used +/// to easily implement an aspect for any aspect system. +///

+///

+/// Subclasses are responsible for calling methods in this class in the correct order. +///

+///

+/// Uses the Strategy design pattern. A +/// implementation will perform the actual transaction management +///

+///

+/// A transaction aspect is serializable if its +/// and +/// are serializable. +///

+///
+/// Rod Johnson +/// Juergen Hoeller +/// Griffin Caprio (.NET) +/// Mark Pollack (.NET) +[Serializable] +public class TransactionAspectSupport : IInitializingObject { - /// - /// Superclass for transaction aspects, such as the AOP Alliance-compatible - /// . - /// - /// - ///

- /// This enables the underlying Spring transaction infrastructure to be used - /// to easily implement an aspect for any aspect system. - ///

- ///

- /// Subclasses are responsible for calling methods in this class in the correct order. - ///

- ///

- /// Uses the Strategy design pattern. A - /// implementation will perform the actual transaction management - ///

- ///

- /// A transaction aspect is serializable if its - /// and - /// are serializable. - ///

- ///
- /// Rod Johnson - /// Juergen Hoeller - /// Griffin Caprio (.NET) - /// Mark Pollack (.NET) - [Serializable] - public class TransactionAspectSupport : IInitializingObject - { - //TODO work on serialization support. + //TODO work on serialization support. - #region TransactionInfo Class - /// - /// Opaque object used to hold transaction information. - /// - /// - ///

- /// Subclasses must pass it back to method on this class, but not see its internals. - ///

- ///
- internal protected class TransactionInfo - { - - private ITransactionAttribute _transactionAttribute; - private string _joinpointIdentification; - private ITransactionStatus _transactionStatus; - private TransactionInfo _oldTransactionInfo; - - /// - /// Creates a new instance of the - /// - /// class for the supplied . - /// - /// The transaction attributes to associate with any transaction. - /// The info for diagnostic display of joinpoint - public TransactionInfo( ITransactionAttribute transactionAttribute, string joinpointIdentification) - { - _transactionAttribute = transactionAttribute; - _joinpointIdentification = joinpointIdentification; - } - - /// - /// Does this instance currently have a transaction? - /// - /// True if this instance has a transaction. - public bool HasTransaction - { - get { return _transactionStatus != null; } - } - - /// - /// Gets and sets the for this object. - /// - public ITransactionStatus TransactionStatus - { - set { _transactionStatus = value; } - get { return _transactionStatus; } - } - - /// - /// Binds this - /// - /// instance to the thread local storage variable for the current thread and - /// backs up the existing - /// - /// object for the current thread. - /// - public void BindToThread() - { - // Expose current TransactionStatus, preserving any existing TransactionStatus - // for restoration after this transaction is complete. - TransactionInfo currentTransactionInfo = LogicalThreadContext.GetData(CURRENT_TRANSACTIONINFO_SLOTNAME) as TransactionInfo; - _oldTransactionInfo = currentTransactionInfo; - LogicalThreadContext.SetData(CURRENT_TRANSACTIONINFO_SLOTNAME, this); - } - - /// - /// Restores the previous - /// - /// object to the current thread. - /// - public void RestoreThreadLocalStatus() - { - // Use stack to restore old transaction TransactionInfo. - // Will be null if none was set. - LogicalThreadContext.SetData(CURRENT_TRANSACTIONINFO_SLOTNAME, _oldTransactionInfo); - } - - /// - /// Gets the current - /// for this - /// - /// object. - /// - public ITransactionAttribute TransactionAttribute - { - get { return _transactionAttribute; } - } - - /// - /// Gets the joinpoint identification. - /// - /// The joinpoint identification. - public string JoinpointIdentification - { - get { return _joinpointIdentification; } - } - } - #endregion - - #region Logging Definition - - [NonSerialized] - protected ILogger log = LogManager.GetLogger(typeof (TransactionAspectSupport)); - - #endregion + #region TransactionInfo Class + /// + /// Opaque object used to hold transaction information. + /// + /// + ///

+ /// Subclasses must pass it back to method on this class, but not see its internals. + ///

+ ///
+ internal protected class TransactionInfo + { + private ITransactionAttribute _transactionAttribute; + private string _joinpointIdentification; + private ITransactionStatus _transactionStatus; + private TransactionInfo _oldTransactionInfo; /// - /// The name in thread local storage where the TransactionInfo object is located + /// Creates a new instance of the + /// + /// class for the supplied . /// - public const string CURRENT_TRANSACTIONINFO_SLOTNAME = "TransactionAspectSupport.CurrentTransactionInfoSlotName"; - - /// - /// The currently referenced by - /// this aspect - /// - private IPlatformTransactionManager _transactionManager; - - /// - /// The currently - /// referenced by this aspect. - /// - private ITransactionAttributeSource _transactionAttributeSource; - - /// - /// Creates a new instance of the - /// class. - /// - public TransactionAspectSupport() {} - - /// - /// Gets and sets the for - /// this aspect. - /// - public IPlatformTransactionManager TransactionManager - { - get { return _transactionManager; } - set { _transactionManager = value; } - } - - /// - /// Gets and sets the - /// for - /// this aspect. - /// - public ITransactionAttributeSource TransactionAttributeSource - { - get { return _transactionAttributeSource; } - set { _transactionAttributeSource = value; } - } - - /// - /// Returns the - /// of the current method invocation. - /// - /// - /// Mainly intended for code that wants to set the current transaction - /// rollback-only but not throw an application exception. - /// - /// - /// If the transaction info cannot be found, because the method was invoked - /// outside of an AOP invocation context. - /// - public static ITransactionStatus CurrentTransactionStatus - { - get { return CurrentTransactionInfo.TransactionStatus; } - } - - /// - /// Subclasses can use this to return the current - /// . - /// - /// - /// Only subclasses that cannot handle all operations in one method - /// need to use this mechanism to get at the current - /// . - /// An around advice such as an AOP Alliance - /// can hold a reference to the - /// - /// throughout the aspect method. - /// A - /// will be returned even if no transaction was created. The - /// - /// property can be used to query this. - /// - /// - /// If no transaction has been created by an aspect. - /// - protected static TransactionInfo CurrentTransactionInfo - { - get - { - TransactionInfo currentTransactionInfo = - LogicalThreadContext.GetData(CURRENT_TRANSACTIONINFO_SLOTNAME) as TransactionInfo; - if (currentTransactionInfo == null) - { - throw new NoTransactionException("No transaction aspect-managed ITransactionStatus in scope"); - } - return currentTransactionInfo; - } - } - /// - /// Set properties with method names as keys and transaction attribute - /// descriptors (parsed via ) as values: - /// e.g. key = "MyMethod", value = "PROPAGATION_REQUIRED,readOnly". - /// - /// - /// - /// Method names are always applied to the target class, no matter if defined in an - /// interface or the class itself. - /// - ///

- /// Internally, a - /// - /// will be created from the given properties. - ///

- ///
- public NameValueCollection TransactionAttributes - { - set - { - NameMatchTransactionAttributeSource attributeSource = new NameMatchTransactionAttributeSource(); - attributeSource.NameProperties = value; - _transactionAttributeSource = attributeSource; - } - } - - /// - /// Checks that the required properties are set. - /// - public void AfterPropertiesSet() - { - if ( null == _transactionManager) - { - throw new ArgumentException("IPlatformTransactionManager is required"); - } - if ( null == _transactionAttributeSource ) - { - throw new ArgumentException("Either 'TransactionAttributeSource' or 'TransactionAttribute' property is required: " + - "If there are no transactional methods, don't use a TransactionInterceptor " + - "or TransactionProxyFactoryObject." ); - } - } - - /// - /// Create a transaction if necessary - /// - /// Method about to execute - /// Type that the method is on - /// - /// A object, - /// whether or not a transaction was created. - ///

- /// The - /// - /// property on the - /// - /// class can be used to tell if there was a transaction created. - ///

- ///
- protected TransactionInfo CreateTransactionIfNecessary( MethodInfo method, Type targetType ) - { - // If the transaction attribute is null, the method is non-transactional. - ITransactionAttribute sourceAttr = _transactionAttributeSource.ReturnTransactionAttribute( method, targetType ); - - return CreateTransactionIfNecessary(sourceAttr, MethodIdentification(method)); - } - - /// - /// Creates the transaction if necessary. - /// - /// The source transaction attribute. - /// The joinpoint identification. - /// Transaction Info for declarative transaction management. - protected TransactionInfo CreateTransactionIfNecessary(ITransactionAttribute sourceAttr, string joinpointIdentification) - { - ITransactionAttribute txAttr = sourceAttr; - - // If no name specified, apply method identification as transaction name. - if (txAttr != null && txAttr.Name == null) - { - txAttr = new DelegatingTransactionAttributeWithName(txAttr, joinpointIdentification); - } - - TransactionInfo transactionInfo = new TransactionInfo(txAttr, joinpointIdentification); - if ( txAttr != null ) - { - // We need a transaction for this method - #region Instrumentation - - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug("Getting transaction for " + transactionInfo.JoinpointIdentification); - } - - #endregion - // The transaction manager will flag an error if an incompatible tx already exists - transactionInfo.TransactionStatus = _transactionManager.GetTransaction(txAttr); - } - else - { - // The TransactionInfo.HasTransaction property will return - // false. We created it only to preserve the integrity of - // the ThreadLocal stack maintained in this class. - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug("Skipping transactional joinpoint [" + joinpointIdentification + - "] because no transaction manager has been configured"); - } - } - - // We always bind the TransactionInfo to the thread, even if we didn't create - // a new transaction here. This guarantees that the TransactionInfo stack - // will be managed correctly even if no transaction was created by this aspect. - transactionInfo.BindToThread( ); - return transactionInfo; - } - - /// - /// Identifies the method by providing the qualfied method name. - /// - /// The method info. - /// qualified mehtod name. - protected string MethodIdentification(MethodInfo methodInfo) + /// The transaction attributes to associate with any transaction. + /// The info for diagnostic display of joinpoint + public TransactionInfo(ITransactionAttribute transactionAttribute, string joinpointIdentification) { - return ObjectUtils.GetQualifiedMethodName(methodInfo); + _transactionAttribute = transactionAttribute; + _joinpointIdentification = joinpointIdentification; } - /// - /// Execute after the successful completion of call, but not after an exception was handled. - /// - /// - ///

- /// Do nothing if we didn't create a transaction. - ///

- ///
- /// - /// The - /// - /// about the current transaction. - /// - protected void CommitTransactionAfterReturning( TransactionInfo transactionInfo ) - { - if ( transactionInfo != null && transactionInfo.HasTransaction ) - { - #region Instrumentation + /// + /// Does this instance currently have a transaction? + /// + /// True if this instance has a transaction. + public bool HasTransaction + { + get { return _transactionStatus != null; } + } - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug("Completing transaction for [" + transactionInfo.JoinpointIdentification + "]"); - } + /// + /// Gets and sets the for this object. + /// + public ITransactionStatus TransactionStatus + { + set { _transactionStatus = value; } + get { return _transactionStatus; } + } - #endregion + /// + /// Binds this + /// + /// instance to the thread local storage variable for the current thread and + /// backs up the existing + /// + /// object for the current thread. + /// + public void BindToThread() + { + // Expose current TransactionStatus, preserving any existing TransactionStatus + // for restoration after this transaction is complete. + TransactionInfo currentTransactionInfo = LogicalThreadContext.GetData(CURRENT_TRANSACTIONINFO_SLOTNAME) as TransactionInfo; + _oldTransactionInfo = currentTransactionInfo; + LogicalThreadContext.SetData(CURRENT_TRANSACTIONINFO_SLOTNAME, this); + } - _transactionManager.Commit( transactionInfo.TransactionStatus ); - } - } + /// + /// Restores the previous + /// + /// object to the current thread. + /// + public void RestoreThreadLocalStatus() + { + // Use stack to restore old transaction TransactionInfo. + // Will be null if none was set. + LogicalThreadContext.SetData(CURRENT_TRANSACTIONINFO_SLOTNAME, _oldTransactionInfo); + } - /// - /// Handle a exception, closing out the transaction. - /// - /// - ///

- /// We may commit or roll back, depending on our configuration. - ///

- ///
- /// - /// The - /// - /// about the current transaction. - /// - /// The encountered. - protected void CompleteTransactionAfterThrowing( - TransactionInfo transactionInfo, Exception exception ) - { - if ( transactionInfo != null && transactionInfo.HasTransaction ) - { - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug("Completing transaction for [" + transactionInfo.JoinpointIdentification + "] after exception: " + exception); + /// + /// Gets the current + /// for this + /// + /// object. + /// + public ITransactionAttribute TransactionAttribute + { + get { return _transactionAttribute; } + } + + /// + /// Gets the joinpoint identification. + /// + /// The joinpoint identification. + public string JoinpointIdentification + { + get { return _joinpointIdentification; } + } + } + + #endregion + + #region Logging Definition + + [NonSerialized] protected ILogger log = LogManager.GetLogger(typeof(TransactionAspectSupport)); + + #endregion + + /// + /// The name in thread local storage where the TransactionInfo object is located + /// + public const string CURRENT_TRANSACTIONINFO_SLOTNAME = "TransactionAspectSupport.CurrentTransactionInfoSlotName"; + + /// + /// The currently referenced by + /// this aspect + /// + private IPlatformTransactionManager _transactionManager; + + /// + /// The currently + /// referenced by this aspect. + /// + private ITransactionAttributeSource _transactionAttributeSource; + + /// + /// Creates a new instance of the + /// class. + /// + public TransactionAspectSupport() { } + + /// + /// Gets and sets the for + /// this aspect. + /// + public IPlatformTransactionManager TransactionManager + { + get { return _transactionManager; } + set { _transactionManager = value; } + } + + /// + /// Gets and sets the + /// for + /// this aspect. + /// + public ITransactionAttributeSource TransactionAttributeSource + { + get { return _transactionAttributeSource; } + set { _transactionAttributeSource = value; } + } + + /// + /// Returns the + /// of the current method invocation. + /// + /// + /// Mainly intended for code that wants to set the current transaction + /// rollback-only but not throw an application exception. + /// + /// + /// If the transaction info cannot be found, because the method was invoked + /// outside of an AOP invocation context. + /// + public static ITransactionStatus CurrentTransactionStatus + { + get { return CurrentTransactionInfo.TransactionStatus; } + } + + /// + /// Subclasses can use this to return the current + /// . + /// + /// + /// Only subclasses that cannot handle all operations in one method + /// need to use this mechanism to get at the current + /// . + /// An around advice such as an AOP Alliance + /// can hold a reference to the + /// + /// throughout the aspect method. + /// A + /// will be returned even if no transaction was created. The + /// + /// property can be used to query this. + /// + /// + /// If no transaction has been created by an aspect. + /// + protected static TransactionInfo CurrentTransactionInfo + { + get + { + TransactionInfo currentTransactionInfo = + LogicalThreadContext.GetData(CURRENT_TRANSACTIONINFO_SLOTNAME) as TransactionInfo; + if (currentTransactionInfo == null) + { + throw new NoTransactionException("No transaction aspect-managed ITransactionStatus in scope"); + } + + return currentTransactionInfo; + } + } + + /// + /// Set properties with method names as keys and transaction attribute + /// descriptors (parsed via ) as values: + /// e.g. key = "MyMethod", value = "PROPAGATION_REQUIRED,readOnly". + /// + /// + /// + /// Method names are always applied to the target class, no matter if defined in an + /// interface or the class itself. + /// + ///

+ /// Internally, a + /// + /// will be created from the given properties. + ///

+ ///
+ public NameValueCollection TransactionAttributes + { + set + { + NameMatchTransactionAttributeSource attributeSource = new NameMatchTransactionAttributeSource(); + attributeSource.NameProperties = value; + _transactionAttributeSource = attributeSource; + } + } + + /// + /// Checks that the required properties are set. + /// + public void AfterPropertiesSet() + { + if (null == _transactionManager) + { + throw new ArgumentException("IPlatformTransactionManager is required"); + } + + if (null == _transactionAttributeSource) + { + throw new ArgumentException("Either 'TransactionAttributeSource' or 'TransactionAttribute' property is required: " + + "If there are no transactional methods, don't use a TransactionInterceptor " + + "or TransactionProxyFactoryObject."); + } + } + + /// + /// Create a transaction if necessary + /// + /// Method about to execute + /// Type that the method is on + /// + /// A object, + /// whether or not a transaction was created. + ///

+ /// The + /// + /// property on the + /// + /// class can be used to tell if there was a transaction created. + ///

+ ///
+ protected TransactionInfo CreateTransactionIfNecessary(MethodInfo method, Type targetType) + { + // If the transaction attribute is null, the method is non-transactional. + ITransactionAttribute sourceAttr = _transactionAttributeSource.ReturnTransactionAttribute(method, targetType); + + return CreateTransactionIfNecessary(sourceAttr, MethodIdentification(method)); + } + + /// + /// Creates the transaction if necessary. + /// + /// The source transaction attribute. + /// The joinpoint identification. + /// Transaction Info for declarative transaction management. + protected TransactionInfo CreateTransactionIfNecessary(ITransactionAttribute sourceAttr, string joinpointIdentification) + { + ITransactionAttribute txAttr = sourceAttr; + + // If no name specified, apply method identification as transaction name. + if (txAttr != null && txAttr.Name == null) + { + txAttr = new DelegatingTransactionAttributeWithName(txAttr, joinpointIdentification); + } + + TransactionInfo transactionInfo = new TransactionInfo(txAttr, joinpointIdentification); + if (txAttr != null) + { + // We need a transaction for this method + + #region Instrumentation + + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug("Getting transaction for " + transactionInfo.JoinpointIdentification); + } + + #endregion + + // The transaction manager will flag an error if an incompatible tx already exists + transactionInfo.TransactionStatus = _transactionManager.GetTransaction(txAttr); + } + else + { + // The TransactionInfo.HasTransaction property will return + // false. We created it only to preserve the integrity of + // the ThreadLocal stack maintained in this class. + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug("Skipping transactional joinpoint [" + joinpointIdentification + + "] because no transaction manager has been configured"); + } + } + + // We always bind the TransactionInfo to the thread, even if we didn't create + // a new transaction here. This guarantees that the TransactionInfo stack + // will be managed correctly even if no transaction was created by this aspect. + transactionInfo.BindToThread(); + return transactionInfo; + } + + /// + /// Identifies the method by providing the qualfied method name. + /// + /// The method info. + /// qualified mehtod name. + protected string MethodIdentification(MethodInfo methodInfo) + { + return ObjectUtils.GetQualifiedMethodName(methodInfo); + } + + /// + /// Execute after the successful completion of call, but not after an exception was handled. + /// + /// + ///

+ /// Do nothing if we didn't create a transaction. + ///

+ ///
+ /// + /// The + /// + /// about the current transaction. + /// + protected void CommitTransactionAfterReturning(TransactionInfo transactionInfo) + { + if (transactionInfo != null && transactionInfo.HasTransaction) + { + #region Instrumentation + + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug("Completing transaction for [" + transactionInfo.JoinpointIdentification + "]"); + } + + #endregion + + _transactionManager.Commit(transactionInfo.TransactionStatus); + } + } + + /// + /// Handle a exception, closing out the transaction. + /// + /// + ///

+ /// We may commit or roll back, depending on our configuration. + ///

+ ///
+ /// + /// The + /// + /// about the current transaction. + /// + /// The encountered. + protected void CompleteTransactionAfterThrowing( + TransactionInfo transactionInfo, Exception exception) + { + if (transactionInfo != null && transactionInfo.HasTransaction) + { + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug("Completing transaction for [" + transactionInfo.JoinpointIdentification + "] after exception: " + exception); + } + + if (transactionInfo.TransactionAttribute.RollbackOn(exception)) + { + try + { + _transactionManager.Rollback(transactionInfo.TransactionStatus); } + catch (Exception e) + { + log.LogError(e, "Application exception overridden by rollback exception"); + throw; + } + } + else + { + // We don't roll back on this exception. + // Will still roll back if TransactionStatus.RollbackOnly is true. + try + { + _transactionManager.Commit(transactionInfo.TransactionStatus); + } + catch (Exception e) + { + log.LogError(e, "Application exception overriden by commit exception"); + throw; + } + } + } + } - if ( transactionInfo.TransactionAttribute.RollbackOn( exception )) - { - try - { - _transactionManager.Rollback( transactionInfo.TransactionStatus ); - } - catch (Exception e) - { - log.LogError(e, "Application exception overridden by rollback exception"); - throw; - } - } - else - { - // We don't roll back on this exception. - // Will still roll back if TransactionStatus.RollbackOnly is true. - try - { - _transactionManager.Commit(transactionInfo.TransactionStatus); - } catch (Exception e) - { - log.LogError(e, "Application exception overriden by commit exception"); - throw; - } - - } - } - } - /// - /// Resets the - /// - /// for this thread. - /// - /// - /// - /// Call this in all cases: exceptions or normal return. - /// - /// - /// - /// The - /// - /// about the current transaction. May be null. - /// - protected void CleanupTransactionInfo( TransactionInfo transactionInfo ) - { - if ( transactionInfo != null ) - { - transactionInfo.RestoreThreadLocalStatus( ); - } - } - } + /// + /// Resets the + /// + /// for this thread. + /// + /// + /// + /// Call this in all cases: exceptions or normal return. + /// + /// + /// + /// The + /// + /// about the current transaction. May be null. + /// + protected void CleanupTransactionInfo(TransactionInfo transactionInfo) + { + if (transactionInfo != null) + { + transactionInfo.RestoreThreadLocalStatus(); + } + } } diff --git a/src/Spring/Spring.Data/Transaction/Interceptor/TransactionAttribute.cs b/src/Spring/Spring.Data/Transaction/Interceptor/TransactionAttribute.cs index 91a99081..53e7254c 100644 --- a/src/Spring/Spring.Data/Transaction/Interceptor/TransactionAttribute.cs +++ b/src/Spring/Spring.Data/Transaction/Interceptor/TransactionAttribute.cs @@ -1,12 +1,12 @@ /* * Copyright � 2002-2011 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. @@ -17,149 +17,148 @@ using System.Data; using Spring.Transaction.Support; -namespace Spring.Transaction.Interceptor +namespace Spring.Transaction.Interceptor; + +/// +/// .NET Attribute for describing transactional behavior of methods in a class. +/// +/// This attribute type is generally directly comparable +/// to Spring's class and +/// in fact will +/// directly convert the data to a +/// so that Spring's transaction support code does not have to know about +/// attributes. If no rules are relevant to the exception it will be treaded +/// like DefaultTransactionAttribute, (rolling back on all exceptions). +/// +/// The default property values are TransactionPropagation.Required, IsolationLevel.ReadCommitted, +/// DefaultTransactionDefinition.TIMEOUT_DEFAULT (can be changed, by default is the default +/// value of the underlying transaction subsystem) +/// ReadOnly = false, and Type.EmtptyTypes specified for Rollbackfor and NoRollbackFor exception +/// types. +/// +/// +/// Mark Pollack (.NET) +[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, + Inherited = true)] +[Serializable] +public class TransactionAttribute : Attribute { + private TransactionPropagation _transactionPropagation = TransactionPropagation.Required; + private IsolationLevel _isolationLevel = IsolationLevel.ReadCommitted; + private int _timeout = DefaultTransactionDefinition.TIMEOUT_DEFAULT; + private bool _readOnly = false; + private Type[] _rollbackTypes = Type.EmptyTypes; + private Type[] _noRollbackTypes = Type.EmptyTypes; + + private System.Transactions.TransactionScopeAsyncFlowOption _asyncFlowOption = System.Transactions.TransactionScopeAsyncFlowOption.Enabled; + /// - /// .NET Attribute for describing transactional behavior of methods in a class. + /// Initializes a new instance of the class. /// - /// This attribute type is generally directly comparable - /// to Spring's class and - /// in fact will - /// directly convert the data to a - /// so that Spring's transaction support code does not have to know about - /// attributes. If no rules are relevant to the exception it will be treaded - /// like DefaultTransactionAttribute, (rolling back on all exceptions). - /// - /// The default property values are TransactionPropagation.Required, IsolationLevel.ReadCommitted, - /// DefaultTransactionDefinition.TIMEOUT_DEFAULT (can be changed, by default is the default - /// value of the underlying transaction subsystem) - /// ReadOnly = false, and Type.EmtptyTypes specified for Rollbackfor and NoRollbackFor exception - /// types. - /// - /// - /// Mark Pollack (.NET) - [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, - Inherited = true)] - [Serializable] - public class TransactionAttribute : Attribute + public TransactionAttribute() { - private TransactionPropagation _transactionPropagation = TransactionPropagation.Required; - private IsolationLevel _isolationLevel = IsolationLevel.ReadCommitted; - private int _timeout = DefaultTransactionDefinition.TIMEOUT_DEFAULT; - private bool _readOnly = false; - private Type[] _rollbackTypes = Type.EmptyTypes; - private Type[] _noRollbackTypes = Type.EmptyTypes; - - private System.Transactions.TransactionScopeAsyncFlowOption _asyncFlowOption = System.Transactions.TransactionScopeAsyncFlowOption.Enabled; - - /// - /// Initializes a new instance of the class. - /// - public TransactionAttribute() - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The transaction propagation. - public TransactionAttribute(TransactionPropagation transactionPropagation) : this() - { - _transactionPropagation = transactionPropagation; - } - - /// - /// Initializes a new instance of the class. - /// - /// The transaction propagation. - /// The isolation level. - public TransactionAttribute(TransactionPropagation transactionPropagation, - IsolationLevel isolationLevel) : this(transactionPropagation) - { - _isolationLevel = isolationLevel; - } - - /// - /// Initializes a new instance of the class. - /// - /// The isolation level. - public TransactionAttribute(IsolationLevel isolationLevel) - { - _isolationLevel = isolationLevel; - } - - /// - /// Gets the transaction propagation. - /// - /// Defaults to TransactionPropagation.Required - /// The transaction propagation. - public TransactionPropagation TransactionPropagation => _transactionPropagation; - - /// - /// Gets the isolation level. - /// - /// Defaults to IsolationLevel.Unspecified - /// The isolation level. - public IsolationLevel IsolationLevel => _isolationLevel; - - /// - /// Gets or sets the timeout. - /// - /// Defaults to the default timeout of the underlying transaction system. - /// The timeout. - public int Timeout - { - get => _timeout; - set => _timeout = value; - } - - /// - /// Gets or sets a value indicating whether the transaction is readonly. - /// - /// Defaults to false - /// true if read-only; otherwise, false. - public bool ReadOnly - { - get => _readOnly; - set => _readOnly = value; - } - - /// - /// Gets or sets the zero or more exception types which - /// indicating which exception types must cause a transaction - /// rollback. - /// - /// This is the preferred way to construct a rollback rule, - /// matching the exception class and subclasses. - /// The rollback types. - public Type[] RollbackFor - { - get => _rollbackTypes; - set => _rollbackTypes = value; - } - - /// - /// Gets or sets zero or more exceptions types which - /// indicationg which exception type must not - /// cause a transaction rollback. - /// - /// This is the preferred way to construct a rollback rule, - /// matching the exception type. - /// The no rollback for. - public Type[] NoRollbackFor - { - get => _noRollbackTypes; - set => _noRollbackTypes = value; - } - - /// - /// Gets the async flow option. - /// - /// The async flow option. - public System.Transactions.TransactionScopeAsyncFlowOption AsyncFlowOption - { - get => _asyncFlowOption; - set => _asyncFlowOption = value; - } } -} + + /// + /// Initializes a new instance of the class. + /// + /// The transaction propagation. + public TransactionAttribute(TransactionPropagation transactionPropagation) : this() + { + _transactionPropagation = transactionPropagation; + } + + /// + /// Initializes a new instance of the class. + /// + /// The transaction propagation. + /// The isolation level. + public TransactionAttribute(TransactionPropagation transactionPropagation, + IsolationLevel isolationLevel) : this(transactionPropagation) + { + _isolationLevel = isolationLevel; + } + + /// + /// Initializes a new instance of the class. + /// + /// The isolation level. + public TransactionAttribute(IsolationLevel isolationLevel) + { + _isolationLevel = isolationLevel; + } + + /// + /// Gets the transaction propagation. + /// + /// Defaults to TransactionPropagation.Required + /// The transaction propagation. + public TransactionPropagation TransactionPropagation => _transactionPropagation; + + /// + /// Gets the isolation level. + /// + /// Defaults to IsolationLevel.Unspecified + /// The isolation level. + public IsolationLevel IsolationLevel => _isolationLevel; + + /// + /// Gets or sets the timeout. + /// + /// Defaults to the default timeout of the underlying transaction system. + /// The timeout. + public int Timeout + { + get => _timeout; + set => _timeout = value; + } + + /// + /// Gets or sets a value indicating whether the transaction is readonly. + /// + /// Defaults to false + /// true if read-only; otherwise, false. + public bool ReadOnly + { + get => _readOnly; + set => _readOnly = value; + } + + /// + /// Gets or sets the zero or more exception types which + /// indicating which exception types must cause a transaction + /// rollback. + /// + /// This is the preferred way to construct a rollback rule, + /// matching the exception class and subclasses. + /// The rollback types. + public Type[] RollbackFor + { + get => _rollbackTypes; + set => _rollbackTypes = value; + } + + /// + /// Gets or sets zero or more exceptions types which + /// indicationg which exception type must not + /// cause a transaction rollback. + /// + /// This is the preferred way to construct a rollback rule, + /// matching the exception type. + /// The no rollback for. + public Type[] NoRollbackFor + { + get => _noRollbackTypes; + set => _noRollbackTypes = value; + } + + /// + /// Gets the async flow option. + /// + /// The async flow option. + public System.Transactions.TransactionScopeAsyncFlowOption AsyncFlowOption + { + get => _asyncFlowOption; + set => _asyncFlowOption = value; + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Data/Transaction/Interceptor/TransactionAttributeConverter.cs b/src/Spring/Spring.Data/Transaction/Interceptor/TransactionAttributeConverter.cs index ab46cab9..a7f85120 100644 --- a/src/Spring/Spring.Data/Transaction/Interceptor/TransactionAttributeConverter.cs +++ b/src/Spring/Spring.Data/Transaction/Interceptor/TransactionAttributeConverter.cs @@ -21,67 +21,68 @@ using System.ComponentModel; using System.Globalization; -namespace Spring.Transaction.Interceptor +namespace Spring.Transaction.Interceptor; + +/// +/// Type converter for +/// objects. +/// +/// +/// Takes s of the form +///

PROPAGATION_NAME,ISOLATION_NAME,readOnly,timeout_NNNN,+Exception1,-Exception2

+///

where only propagation code is required. For example:

+///

PROPAGATION_MANDATORY,ISOLATION_DEFAULT

+///

+/// The tokens can be in any order. Propagation and isolation codes +/// must use the names of the values in the +/// enumeration. Timeout values are in seconds. If no timeout is specified, the transaction +/// manager will apply a default timeout specific to the particular transaction manager. +///

+///

+/// A "+" before an exception name substring indicates that transactions should commit even +/// if this exception is thrown; a "-" that they should roll back. +///

+///
+/// Mark Pollack +public class TransactionAttributeConverter : TypeConverter { /// - /// Type converter for - /// objects. + /// Returns whether this converter can convert an object of the given type to an ITransactionAttribute, using the specified context. /// - /// - /// Takes s of the form - ///

PROPAGATION_NAME,ISOLATION_NAME,readOnly,timeout_NNNN,+Exception1,-Exception2

- ///

where only propagation code is required. For example:

- ///

PROPAGATION_MANDATORY,ISOLATION_DEFAULT

- ///

- /// The tokens can be in any order. Propagation and isolation codes - /// must use the names of the values in the - /// enumeration. Timeout values are in seconds. If no timeout is specified, the transaction - /// manager will apply a default timeout specific to the particular transaction manager. - ///

- ///

- /// A "+" before an exception name substring indicates that transactions should commit even - /// if this exception is thrown; a "-" that they should roll back. - ///

- ///
- /// Mark Pollack - public class TransactionAttributeConverter : TypeConverter + /// An that provides a format context. + /// A that represents the type you want to convert from. + /// + /// true if this converter can perform the conversion; otherwise, false. + /// + public override bool CanConvertFrom( + ITypeDescriptorContext context, Type sourceType) { - /// - /// Returns whether this converter can convert an object of the given type to an ITransactionAttribute, using the specified context. - /// - /// An that provides a format context. - /// A that represents the type you want to convert from. - /// - /// true if this converter can perform the conversion; otherwise, false. - /// - public override bool CanConvertFrom( - ITypeDescriptorContext context, Type sourceType) + if (sourceType == typeof(string)) { - if (sourceType == typeof (string)) - { - return true; - } - return base.CanConvertFrom(context, sourceType); + return true; } - /// - /// Converts from string to ITransactionAttribute - /// - /// The context. - /// The culture. - /// The string value to convert - /// An ITransactionAttribute instance - public override object ConvertFrom( - ITypeDescriptorContext context, CultureInfo culture, object val) + return base.CanConvertFrom(context, sourceType); + } + + /// + /// Converts from string to ITransactionAttribute + /// + /// The context. + /// The culture. + /// The string value to convert + /// An ITransactionAttribute instance + public override object ConvertFrom( + ITypeDescriptorContext context, CultureInfo culture, object val) + { + if (val is string) { - if (val is string) - { - string value = val as string; - TransactionAttributeEditor editor = new TransactionAttributeEditor(); - editor.SetAsText(value); - return editor.Value; - } - return base.ConvertFrom(context, culture, val); + string value = val as string; + TransactionAttributeEditor editor = new TransactionAttributeEditor(); + editor.SetAsText(value); + return editor.Value; } + + return base.ConvertFrom(context, culture, val); } } diff --git a/src/Spring/Spring.Data/Transaction/Interceptor/TransactionAttributeEditor.cs b/src/Spring/Spring.Data/Transaction/Interceptor/TransactionAttributeEditor.cs index 4b2716e7..d740425a 100644 --- a/src/Spring/Spring.Data/Transaction/Interceptor/TransactionAttributeEditor.cs +++ b/src/Spring/Spring.Data/Transaction/Interceptor/TransactionAttributeEditor.cs @@ -21,132 +21,138 @@ using System.Data; using Spring.Util; -namespace Spring.Transaction.Interceptor +namespace Spring.Transaction.Interceptor; + +/// +/// Type converter for +/// objects. +/// +/// +/// Takes s of the form +///

PROPAGATION_NAME,ISOLATION_NAME,readOnly,timeout_NNNN,+Exception1,-Exception2

+///

where only propagation code is required. For example:

+///

PROPAGATION_MANDATORY,ISOLATION_DEFAULT

+///

+/// The tokens can be in any order. Propagation and isolation codes +/// must use the names of the values in the +/// enumeration. Timeout values are in seconds. If no timeout is specified, the transaction +/// manager will apply a default timeout specific to the particular transaction manager. +///

+///

+/// A "+" before an exception name substring indicates that transactions should commit even +/// if this exception is thrown; a "-" that they should roll back. +///

+///
+/// Rod Johnson +/// Juergen Hoeller +/// Griffin Caprio (.NET) +public class TransactionAttributeEditor { - /// - /// Type converter for - /// objects. - /// - /// - /// Takes s of the form - ///

PROPAGATION_NAME,ISOLATION_NAME,readOnly,timeout_NNNN,+Exception1,-Exception2

- ///

where only propagation code is required. For example:

- ///

PROPAGATION_MANDATORY,ISOLATION_DEFAULT

- ///

- /// The tokens can be in any order. Propagation and isolation codes - /// must use the names of the values in the - /// enumeration. Timeout values are in seconds. If no timeout is specified, the transaction - /// manager will apply a default timeout specific to the particular transaction manager. - ///

- ///

- /// A "+" before an exception name substring indicates that transactions should commit even - /// if this exception is thrown; a "-" that they should roll back. - ///

- ///
- /// Rod Johnson - /// Juergen Hoeller - /// Griffin Caprio (.NET) - public class TransactionAttributeEditor - { - private RuleBasedTransactionAttribute _attribute; + private RuleBasedTransactionAttribute _attribute; - /// - /// Parses the input properties string into a valid - /// instance - /// - /// - /// The string defining the transactional properties. - /// - public void SetAsText( string transactionProperties ) - { - if (!StringUtils.HasText(transactionProperties)) - { - _attribute = null; - } - else - { - string[] tokens = StringUtils.CommaDelimitedListToStringArray( transactionProperties ); - RuleBasedTransactionAttribute attribute = new RuleBasedTransactionAttribute(); - for ( int i = 0; i < tokens.Length; i++ ) - { - string token = tokens[i].Trim(); - if ( token.StartsWith(DefaultTransactionAttribute.PROPAGATION_CONSTANT_PREFIX)) - { - attribute.PropagationBehavior = convertPropagationValue( token ); - } else if ( token.StartsWith(DefaultTransactionAttribute.ISOLATION_CONSTANT_PREFIX ) ) - { - attribute.TransactionIsolationLevel = convertIsolationValue( token ); - } else if ( token.StartsWith(DefaultTransactionAttribute.TIMEOUT_PREFIX ) ) - { - string value = token.Substring(DefaultTransactionAttribute.TIMEOUT_PREFIX.Length); - attribute.TransactionTimeout = Convert.ToInt32( value ); - } else if ( token.StartsWith( DefaultTransactionAttribute.READ_ONLY_MARKER ) ) - { - attribute.ReadOnly = true; - } else if ( token.StartsWith( DefaultTransactionAttribute.COMMIT_RULE_PREFIX ) ) - { - attribute.AddRollbackRule( new NoRollbackRuleAttribute(token.Substring( 1 ) ) ); - } else if ( token.StartsWith( DefaultTransactionAttribute.ROLLBACK_RULE_PREFIX ) ) - { - attribute.AddRollbackRule( new RollbackRuleAttribute( token.Substring( 1 ) ) ); - } else - { - throw new ArgumentException("Illegal transaction attribute token: [" + token + "]"); - } - } - _attribute = attribute; - } - } + /// + /// Parses the input properties string into a valid + /// instance + /// + /// + /// The string defining the transactional properties. + /// + public void SetAsText(string transactionProperties) + { + if (!StringUtils.HasText(transactionProperties)) + { + _attribute = null; + } + else + { + string[] tokens = StringUtils.CommaDelimitedListToStringArray(transactionProperties); + RuleBasedTransactionAttribute attribute = new RuleBasedTransactionAttribute(); + for (int i = 0; i < tokens.Length; i++) + { + string token = tokens[i].Trim(); + if (token.StartsWith(DefaultTransactionAttribute.PROPAGATION_CONSTANT_PREFIX)) + { + attribute.PropagationBehavior = convertPropagationValue(token); + } + else if (token.StartsWith(DefaultTransactionAttribute.ISOLATION_CONSTANT_PREFIX)) + { + attribute.TransactionIsolationLevel = convertIsolationValue(token); + } + else if (token.StartsWith(DefaultTransactionAttribute.TIMEOUT_PREFIX)) + { + string value = token.Substring(DefaultTransactionAttribute.TIMEOUT_PREFIX.Length); + attribute.TransactionTimeout = Convert.ToInt32(value); + } + else if (token.StartsWith(DefaultTransactionAttribute.READ_ONLY_MARKER)) + { + attribute.ReadOnly = true; + } + else if (token.StartsWith(DefaultTransactionAttribute.COMMIT_RULE_PREFIX)) + { + attribute.AddRollbackRule(new NoRollbackRuleAttribute(token.Substring(1))); + } + else if (token.StartsWith(DefaultTransactionAttribute.ROLLBACK_RULE_PREFIX)) + { + attribute.AddRollbackRule(new RollbackRuleAttribute(token.Substring(1))); + } + else + { + throw new ArgumentException("Illegal transaction attribute token: [" + token + "]"); + } + } - /// - /// Gets the - /// from this editor. - /// - public ITransactionAttribute Value - { - get { return _attribute; } - } + _attribute = attribute; + } + } - private TransactionPropagation convertPropagationValue( string transactionPropagation ) - { - switch ( transactionPropagation.ToUpper() ) - { - case "PROPAGATION_REQUIRED": - return TransactionPropagation.Required; - case "PROPAGATION_SUPPORTS": - return TransactionPropagation.Supports; - case "PROPAGATION_MANDATORY": - return TransactionPropagation.Mandatory; - case "PROPAGATION_REQUIRES_NEW": - return TransactionPropagation.RequiresNew; - case "PROPAGATION_NOT_SUPPORTED": - return TransactionPropagation.NotSupported; - case "PROPAGATION_NEVER": - return TransactionPropagation.Never; - case "PROPAGATION_NESTED": - return TransactionPropagation.Nested; - default: - throw new ArgumentException("Illegal transaction propagation token: [" + transactionPropagation + "]"); - } - } + /// + /// Gets the + /// from this editor. + /// + public ITransactionAttribute Value + { + get { return _attribute; } + } - private IsolationLevel convertIsolationValue( string isolationLevel ) - { - switch ( isolationLevel.ToUpper() ) - { - case "ISOLATION_DEFAULT": - return IsolationLevel.ReadCommitted; - case "ISOLATION_READUNCOMMITTED": - return IsolationLevel.ReadUncommitted; - case "ISOLATION_READCOMMITTED": - return IsolationLevel.ReadCommitted; - case "ISOLATION_REPEATABLEREAD": - return IsolationLevel.RepeatableRead; - case "ISOLATION_SERIALIZABLE": - return IsolationLevel.Serializable; - default: - return IsolationLevel.ReadCommitted; - } - } - } + private TransactionPropagation convertPropagationValue(string transactionPropagation) + { + switch (transactionPropagation.ToUpper()) + { + case "PROPAGATION_REQUIRED": + return TransactionPropagation.Required; + case "PROPAGATION_SUPPORTS": + return TransactionPropagation.Supports; + case "PROPAGATION_MANDATORY": + return TransactionPropagation.Mandatory; + case "PROPAGATION_REQUIRES_NEW": + return TransactionPropagation.RequiresNew; + case "PROPAGATION_NOT_SUPPORTED": + return TransactionPropagation.NotSupported; + case "PROPAGATION_NEVER": + return TransactionPropagation.Never; + case "PROPAGATION_NESTED": + return TransactionPropagation.Nested; + default: + throw new ArgumentException("Illegal transaction propagation token: [" + transactionPropagation + "]"); + } + } + + private IsolationLevel convertIsolationValue(string isolationLevel) + { + switch (isolationLevel.ToUpper()) + { + case "ISOLATION_DEFAULT": + return IsolationLevel.ReadCommitted; + case "ISOLATION_READUNCOMMITTED": + return IsolationLevel.ReadUncommitted; + case "ISOLATION_READCOMMITTED": + return IsolationLevel.ReadCommitted; + case "ISOLATION_REPEATABLEREAD": + return IsolationLevel.RepeatableRead; + case "ISOLATION_SERIALIZABLE": + return IsolationLevel.Serializable; + default: + return IsolationLevel.ReadCommitted; + } + } } diff --git a/src/Spring/Spring.Data/Transaction/Interceptor/TransactionAttributeSourceAdvisor.cs b/src/Spring/Spring.Data/Transaction/Interceptor/TransactionAttributeSourceAdvisor.cs index 0e5cb5d8..ef3157f4 100644 --- a/src/Spring/Spring.Data/Transaction/Interceptor/TransactionAttributeSourceAdvisor.cs +++ b/src/Spring/Spring.Data/Transaction/Interceptor/TransactionAttributeSourceAdvisor.cs @@ -22,108 +22,108 @@ using System.Reflection; using Spring.Aop.Framework; using Spring.Aop.Support; -namespace Spring.Transaction.Interceptor +namespace Spring.Transaction.Interceptor; + +/// +/// Advisor driven by a , used to include +/// a for methods that +/// are transactional. +/// +/// +///

+/// Because the AOP framework caches advice calculations, this is normally +/// faster than just letting the +/// run and find out itself that it has no work to do. +///

+///
+/// Rod Johnson +/// Griffin Caprio (.NET) +[Serializable] +public class TransactionAttributeSourceAdvisor : StaticMethodMatcherPointcutAdvisor { - /// - /// Advisor driven by a , used to include - /// a for methods that - /// are transactional. - /// - /// - ///

- /// Because the AOP framework caches advice calculations, this is normally - /// faster than just letting the - /// run and find out itself that it has no work to do. - ///

- ///
- /// Rod Johnson - /// Griffin Caprio (.NET) - [Serializable] - public class TransactionAttributeSourceAdvisor : StaticMethodMatcherPointcutAdvisor - { - #region Fields + #region Fields - private ITransactionAttributeSource _transactionAttributeSource; + private ITransactionAttributeSource _transactionAttributeSource; - #endregion + #endregion - #region Constructor(s) + #region Constructor(s) - /// - /// Initializes a new instance of the class. - /// - /// - ///

- /// This is an abstract class, and as such has no publicly - /// visible constructors. - ///

- ///
- public TransactionAttributeSourceAdvisor() - { - } + /// + /// Initializes a new instance of the class. + /// + /// + ///

+ /// This is an abstract class, and as such has no publicly + /// visible constructors. + ///

+ ///
+ public TransactionAttributeSourceAdvisor() + { + } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The pre-configured transaction interceptor. - /// - public TransactionAttributeSourceAdvisor( TransactionInterceptor transactionInterceptor ) - : base( transactionInterceptor ) - { - SetTxAttributeSource(transactionInterceptor); - } + /// + /// Creates a new instance of the + /// class. + /// + /// + /// The pre-configured transaction interceptor. + /// + public TransactionAttributeSourceAdvisor(TransactionInterceptor transactionInterceptor) + : base(transactionInterceptor) + { + SetTxAttributeSource(transactionInterceptor); + } - #endregion + #endregion - #region Properties + #region Properties - /// - /// Sets the transaction interceptor. - /// - /// The transaction interceptor. - public TransactionInterceptor TransactionInterceptor - { - set - { - //TODO refactor - Advice = value; - SetTxAttributeSource(value); - } - } - - #endregion - - #region Methods - - /// - /// Tests the input method to see if it's covered by the advisor. - /// - /// The method to match. - /// The to match against. - /// - /// True if the supplied is covered by the advisor. - /// - public override bool Matches(MethodInfo method, Type targetClass) + /// + /// Sets the transaction interceptor. + /// + /// The transaction interceptor. + public TransactionInterceptor TransactionInterceptor + { + set { - return (_transactionAttributeSource.ReturnTransactionAttribute(method, targetClass) != null); + //TODO refactor + Advice = value; + SetTxAttributeSource(value); + } + } + + #endregion + + #region Methods + + /// + /// Tests the input method to see if it's covered by the advisor. + /// + /// The method to match. + /// The to match against. + /// + /// True if the supplied is covered by the advisor. + /// + public override bool Matches(MethodInfo method, Type targetClass) + { + return (_transactionAttributeSource.ReturnTransactionAttribute(method, targetClass) != null); + } + + /// + /// Sets the tx attribute source. + /// + /// The transaction interceptor. + protected void SetTxAttributeSource(TransactionInterceptor transactionInterceptor) + { + if (transactionInterceptor.TransactionAttributeSource == null) + { + throw new AopConfigException("Cannot construct a TransactionAttributeSourceAdvisor using a " + + "TransactionInterceptor that has no TransactionAttributeSource configured."); } - /// - /// Sets the tx attribute source. - /// - /// The transaction interceptor. - protected void SetTxAttributeSource(TransactionInterceptor transactionInterceptor) - { - if (transactionInterceptor.TransactionAttributeSource == null) - { - throw new AopConfigException("Cannot construct a TransactionAttributeSourceAdvisor using a " + - "TransactionInterceptor that has no TransactionAttributeSource configured."); - } - _transactionAttributeSource = transactionInterceptor.TransactionAttributeSource; - } + _transactionAttributeSource = transactionInterceptor.TransactionAttributeSource; + } - #endregion - } -} + #endregion +} \ No newline at end of file diff --git a/src/Spring/Spring.Data/Transaction/Interceptor/TransactionAttributeSourceEditor.cs b/src/Spring/Spring.Data/Transaction/Interceptor/TransactionAttributeSourceEditor.cs index e091d526..fa20e6e7 100644 --- a/src/Spring/Spring.Data/Transaction/Interceptor/TransactionAttributeSourceEditor.cs +++ b/src/Spring/Spring.Data/Transaction/Interceptor/TransactionAttributeSourceEditor.cs @@ -21,127 +21,130 @@ using System.Collections; using Spring.Util; -namespace Spring.Transaction.Interceptor +namespace Spring.Transaction.Interceptor; + +/// +/// Editor that can convert values into +/// instances. +/// +/// +/// The transaction attribute string must be parseable by the +/// in this package. +///

+/// Strings must be specified in the following syntax:
+/// FQCN.methodName=<transaction attribute string> (sans <>). +///

+/// +/// ExampleNamespace.ExampleClass.MyMethod=PROPAGATION_MANDATORY,ISOLATION_DEFAULT +/// +/// +/// The specified class must be the one where the methods are defined; in the case of +/// implementing an interface, the interface class name must be specified. +/// +///

+/// This will register all overloaded methods for a given name. Does not support explicit +/// registration of certain overloaded methods. Supports wildcard style mappings (in +/// the form "xxx*"), e.g. "Notify*" for "Notify" and "NotifyAll". +///

+///
+/// Rod Johnson +/// Juergen Hoeller +/// Griffin Caprio (.NET) +public class TransactionAttributeSourceEditor { - /// - /// Editor that can convert values into - /// instances. - /// - /// - /// The transaction attribute string must be parseable by the - /// in this package. - ///

- /// Strings must be specified in the following syntax:
- /// FQCN.methodName=<transaction attribute string> (sans <>). - ///

- /// - /// ExampleNamespace.ExampleClass.MyMethod=PROPAGATION_MANDATORY,ISOLATION_DEFAULT - /// - /// - /// The specified class must be the one where the methods are defined; in the case of - /// implementing an interface, the interface class name must be specified. - /// - ///

- /// This will register all overloaded methods for a given name. Does not support explicit - /// registration of certain overloaded methods. Supports wildcard style mappings (in - /// the form "xxx*"), e.g. "Notify*" for "Notify" and "NotifyAll". - ///

- ///
- /// Rod Johnson - /// Juergen Hoeller - /// Griffin Caprio (.NET) - public class TransactionAttributeSourceEditor - { - #region PropertiesEditor Class - /// - /// Internal class to parse property values. - /// - protected internal class PropertiesEditor - { - private IDictionary _properties; + #region PropertiesEditor Class - /// - /// Creates a new instance of the - /// class. - /// - /// The property values to be parsed. - public PropertiesEditor( string properties ) - { - _properties = new Hashtable(); - parseProperties( properties ); - } + /// + /// Internal class to parse property values. + /// + protected internal class PropertiesEditor + { + private IDictionary _properties; - /// - /// Indexer to return values based on index value. - /// - public string this[ string index ] - { - get { return (string) _properties[index]; } - } + /// + /// Creates a new instance of the + /// class. + /// + /// The property values to be parsed. + public PropertiesEditor(string properties) + { + _properties = new Hashtable(); + parseProperties(properties); + } - /// - /// Returns the collection of keys for properties. - /// - public ICollection Keys - { - get { return _properties.Keys; } - } + /// + /// Indexer to return values based on index value. + /// + public string this[string index] + { + get { return (string) _properties[index]; } + } - private void parseProperties( string properties ) - { - string[] tokens = StringUtils.DelimitedListToStringArray( properties, "\n"); - foreach ( string token in tokens ) - { - string[] property = token.Split('='); - _properties.Add( property[0].Trim(), property[1].Trim()); - } - } - } - #endregion - - private ITransactionAttributeSource _attributeSource; + /// + /// Returns the collection of keys for properties. + /// + public ICollection Keys + { + get { return _properties.Keys; } + } - /// - /// Creates a new instance of the - /// class. - /// - public TransactionAttributeSourceEditor() {} + private void parseProperties(string properties) + { + string[] tokens = StringUtils.DelimitedListToStringArray(properties, "\n"); + foreach (string token in tokens) + { + string[] property = token.Split('='); + _properties.Add(property[0].Trim(), property[1].Trim()); + } + } + } - /// - /// Parses the input properties into a valid - /// - /// instance - /// - /// The properties string to be parsed. - public void SetAsText( string attributeSource ) - { - MethodMapTransactionAttributeSource source = new MethodMapTransactionAttributeSource(); - if ( attributeSource == null || attributeSource.Length == 0 ) - { - _attributeSource = null; - } else - { - PropertiesEditor editor = new PropertiesEditor(attributeSource); - TransactionAttributeEditor tae = new TransactionAttributeEditor(); + #endregion - foreach ( string name in editor.Keys ) - { - string value = editor[name]; - tae.SetAsText( value ); - ITransactionAttribute transactionAttribute = tae.Value; - source.AddTransactionalMethod( name, transactionAttribute ); - } - } - _attributeSource = source; - } + private ITransactionAttributeSource _attributeSource; - /// - /// Gets the - /// from this instance. - /// - public ITransactionAttributeSource Value - { - get { return _attributeSource; } - } - } -} + /// + /// Creates a new instance of the + /// class. + /// + public TransactionAttributeSourceEditor() { } + + /// + /// Parses the input properties into a valid + /// + /// instance + /// + /// The properties string to be parsed. + public void SetAsText(string attributeSource) + { + MethodMapTransactionAttributeSource source = new MethodMapTransactionAttributeSource(); + if (attributeSource == null || attributeSource.Length == 0) + { + _attributeSource = null; + } + else + { + PropertiesEditor editor = new PropertiesEditor(attributeSource); + TransactionAttributeEditor tae = new TransactionAttributeEditor(); + + foreach (string name in editor.Keys) + { + string value = editor[name]; + tae.SetAsText(value); + ITransactionAttribute transactionAttribute = tae.Value; + source.AddTransactionalMethod(name, transactionAttribute); + } + } + + _attributeSource = source; + } + + /// + /// Gets the + /// from this instance. + /// + public ITransactionAttributeSource Value + { + get { return _attributeSource; } + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Data/Transaction/Interceptor/TransactionInterceptor.cs b/src/Spring/Spring.Data/Transaction/Interceptor/TransactionInterceptor.cs index 7b2cd0ad..4cb722c4 100644 --- a/src/Spring/Spring.Data/Transaction/Interceptor/TransactionInterceptor.cs +++ b/src/Spring/Spring.Data/Transaction/Interceptor/TransactionInterceptor.cs @@ -21,68 +21,68 @@ using System.Reflection; using AopAlliance.Intercept; -namespace Spring.Transaction.Interceptor +namespace Spring.Transaction.Interceptor; + +/// +/// An AOP Alliance providing +/// declarative transaction management using the common Spring.NET transaction infrastructure. +/// +/// +///

+/// That class contains the necessary calls into Spring.NET's underlying +/// transaction API: subclasses such as this are responsible for calling +/// superclass methods such as +/// +/// in the correct order, in the event of normal invocation return or an exception. +///

+///

+/// s are thread-safe. +///

+///
+/// Rod Johnson +/// Juergen Hoeller +/// Griffin Caprio (.NET) +/// Mark Pollack (.NET) +[Serializable] +public class TransactionInterceptor : TransactionAspectSupport, IMethodInterceptor { - /// - /// An AOP Alliance providing - /// declarative transaction management using the common Spring.NET transaction infrastructure. - /// - /// - ///

- /// That class contains the necessary calls into Spring.NET's underlying - /// transaction API: subclasses such as this are responsible for calling - /// superclass methods such as - /// - /// in the correct order, in the event of normal invocation return or an exception. - ///

- ///

- /// s are thread-safe. - ///

- ///
- /// Rod Johnson - /// Juergen Hoeller - /// Griffin Caprio (.NET) - /// Mark Pollack (.NET) - [Serializable] - public class TransactionInterceptor : TransactionAspectSupport, IMethodInterceptor - { - /// - /// AOP Alliance invoke call that handles all transaction plumbing. - /// - /// - /// The method that is to execute in the context of a transaction. - /// - /// The return value from the method invocation. - public object Invoke(IMethodInvocation invocation) - { - // Work out the target class: may be null. - // The TransactionAttributeSource should be passed the target class - // as well as the method, which may be from an interface. - Type targetType = ( invocation.This != null ) ? invocation.This.GetType() : null; + /// + /// AOP Alliance invoke call that handles all transaction plumbing. + /// + /// + /// The method that is to execute in the context of a transaction. + /// + /// The return value from the method invocation. + public object Invoke(IMethodInvocation invocation) + { + // Work out the target class: may be null. + // The TransactionAttributeSource should be passed the target class + // as well as the method, which may be from an interface. + Type targetType = (invocation.This != null) ? invocation.This.GetType() : null; - // If the transaction attribute is null, the method is non-transactional. - TransactionInfo txnInfo = CreateTransactionIfNecessary( invocation.Method, targetType ); - object returnValue = null; + // If the transaction attribute is null, the method is non-transactional. + TransactionInfo txnInfo = CreateTransactionIfNecessary(invocation.Method, targetType); + object returnValue = null; - try - { - // This is an around advice. - // Invoke the next interceptor in the chain. - // This will normally result in a target object being invoked. - returnValue = invocation.Proceed(); - } - catch ( Exception ex ) - { - // target invocation exception - CompleteTransactionAfterThrowing( txnInfo, ex ); - throw; - } - finally - { - CleanupTransactionInfo( txnInfo ); - } - CommitTransactionAfterReturning( txnInfo ); - return returnValue; - } - } + try + { + // This is an around advice. + // Invoke the next interceptor in the chain. + // This will normally result in a target object being invoked. + returnValue = invocation.Proceed(); + } + catch (Exception ex) + { + // target invocation exception + CompleteTransactionAfterThrowing(txnInfo, ex); + throw; + } + finally + { + CleanupTransactionInfo(txnInfo); + } + + CommitTransactionAfterReturning(txnInfo); + return returnValue; + } } diff --git a/src/Spring/Spring.Data/Transaction/Interceptor/TransactionProxyFactoryObject.cs b/src/Spring/Spring.Data/Transaction/Interceptor/TransactionProxyFactoryObject.cs index 1d20a747..8acef24c 100644 --- a/src/Spring/Spring.Data/Transaction/Interceptor/TransactionProxyFactoryObject.cs +++ b/src/Spring/Spring.Data/Transaction/Interceptor/TransactionProxyFactoryObject.cs @@ -19,7 +19,6 @@ #endregion using System.Collections.Specialized; - using Spring.Aop; using Spring.Aop.Framework; using Spring.Aop.Framework.Adapter; @@ -28,319 +27,330 @@ using Spring.Aop.Target; using Spring.Core.TypeResolution; using Spring.Objects.Factory; -namespace Spring.Transaction.Interceptor +namespace Spring.Transaction.Interceptor; + +/// +/// Proxy factory object for simplified declarative transaction handling. +/// +/// +///

+/// Alternative to the standard AOP +/// with a . +///

+///

+/// This class is intended to cover the typical case of declarative +/// transaction demarcation: namely, wrapping a (singleton) target object with a +/// transactional proxy, proxying all the interfaces that the target implements. +///

+///

+/// Internally, a +/// instance is used, but the user of this class does not have to care. Optionally, an +/// can be specified to cause conditional invocation of +/// the underlying . +///

+///

+/// The +/// +/// and +/// +/// properties can be set to add additional interceptors to the mix. +///

+///
+/// Juergen Hoeller +/// Dmitriy Kopylenko +/// Rod Johnson +/// Griffin Caprio (.NET) +public class TransactionProxyFactoryObject : ProxyConfig, IFactoryObject, IInitializingObject { - /// - /// Proxy factory object for simplified declarative transaction handling. - /// - /// - ///

- /// Alternative to the standard AOP - /// with a . - ///

- ///

- /// This class is intended to cover the typical case of declarative - /// transaction demarcation: namely, wrapping a (singleton) target object with a - /// transactional proxy, proxying all the interfaces that the target implements. - ///

- ///

- /// Internally, a - /// instance is used, but the user of this class does not have to care. Optionally, an - /// can be specified to cause conditional invocation of - /// the underlying . - ///

- ///

- /// The - /// - /// and - /// - /// properties can be set to add additional interceptors to the mix. - ///

- ///
- /// Juergen Hoeller - /// Dmitriy Kopylenko - /// Rod Johnson - /// Griffin Caprio (.NET) - public class TransactionProxyFactoryObject : ProxyConfig, IFactoryObject, IInitializingObject - { - private TransactionInterceptor _transactionInterceptor; - private object _target; - private IList _proxyInterfaces; - private TruePointcut _pointcut; - private object[] _preInterceptors; - private object[] _postInterceptors; - private IAdvisorAdapterRegistry _advisorAdapterRegistry = GlobalAdvisorAdapterRegistry.Instance; - private object _proxy; + private TransactionInterceptor _transactionInterceptor; + private object _target; + private IList _proxyInterfaces; + private TruePointcut _pointcut; + private object[] _preInterceptors; + private object[] _postInterceptors; + private IAdvisorAdapterRegistry _advisorAdapterRegistry = GlobalAdvisorAdapterRegistry.Instance; + private object _proxy; - /// - /// Creates a new instance of the - /// class. - /// - public TransactionProxyFactoryObject() - { - _transactionInterceptor = new TransactionInterceptor(); - } + /// + /// Creates a new instance of the + /// class. + /// + public TransactionProxyFactoryObject() + { + _transactionInterceptor = new TransactionInterceptor(); + } - /// - /// Set the transaction manager for this factory. - /// - /// - /// It is this instance that will perform actual transaction management: this class is - /// just a way of invoking it. - /// - public IPlatformTransactionManager PlatformTransactionManager - { - set { _transactionInterceptor.TransactionManager = value; } - } + /// + /// Set the transaction manager for this factory. + /// + /// + /// It is this instance that will perform actual transaction management: this class is + /// just a way of invoking it. + /// + public IPlatformTransactionManager PlatformTransactionManager + { + set { _transactionInterceptor.TransactionManager = value; } + } - /// - /// Set the target object, i.e. the object to be wrapped with a transactional proxy. - /// - /// - ///

- /// The target may be any object, in which case a - /// will - /// be created. If it is a , no wrapper - /// is created: this enables the use of a pooling - /// or prototype . - ///

- ///
- public object Target - { - set { _target = value; } - } + /// + /// Set the target object, i.e. the object to be wrapped with a transactional proxy. + /// + /// + ///

+ /// The target may be any object, in which case a + /// will + /// be created. If it is a , no wrapper + /// is created: this enables the use of a pooling + /// or prototype . + ///

+ ///
+ public object Target + { + set { _target = value; } + } - /// - /// Specify the set of interfaces being proxied. - /// - /// - ///

- /// If left null (the default), the AOP infrastructure works - /// out which interfaces need proxying by analyzing the target, - /// proxying all of the interfaces that the target object implements. - ///

- ///
- public string[] ProxyInterfaces - { - set { _proxyInterfaces = TypeResolutionUtils.ResolveInterfaceArray( value ); } - } + /// + /// Specify the set of interfaces being proxied. + /// + /// + ///

+ /// If left null (the default), the AOP infrastructure works + /// out which interfaces need proxying by analyzing the target, + /// proxying all of the interfaces that the target object implements. + ///

+ ///
+ public string[] ProxyInterfaces + { + set { _proxyInterfaces = TypeResolutionUtils.ResolveInterfaceArray(value); } + } - /// - /// Set properties with method names as keys and transaction attribute - /// descriptors as values. - /// - /// - ///

- /// The various transaction attribute descriptors are parsed via - /// an instance of the - /// class. - ///

- /// - /// Method names are always applied to the target class, no matter if defined in an - /// interface or the class itself. - /// - ///

- /// Internally, a - /// - /// will be created from the given properties. - ///

- ///
- /// - ///

- /// An example string (method name and transaction attributes) might be: - ///

- ///

- /// key = "myMethod", value = "PROPAGATION_REQUIRED,readOnly". - ///

- ///
- public NameValueCollection TransactionAttributes - { - set { _transactionInterceptor.TransactionAttributes = value; } - } + /// + /// Set properties with method names as keys and transaction attribute + /// descriptors as values. + /// + /// + ///

+ /// The various transaction attribute descriptors are parsed via + /// an instance of the + /// class. + ///

+ /// + /// Method names are always applied to the target class, no matter if defined in an + /// interface or the class itself. + /// + ///

+ /// Internally, a + /// + /// will be created from the given properties. + ///

+ ///
+ /// + ///

+ /// An example string (method name and transaction attributes) might be: + ///

+ ///

+ /// key = "myMethod", value = "PROPAGATION_REQUIRED,readOnly". + ///

+ ///
+ public NameValueCollection TransactionAttributes + { + set { _transactionInterceptor.TransactionAttributes = value; } + } - /// - /// Set the transaction attribute source which is used to find transaction - /// attributes. - /// - /// - ///

- /// If specifying a property value, an - /// appropriate - /// implementation will create a - /// - /// from the value. - ///

- ///
- public ITransactionAttributeSource TransactionAttributeSource - { - set { _transactionInterceptor.TransactionAttributeSource = value; } - } + /// + /// Set the transaction attribute source which is used to find transaction + /// attributes. + /// + /// + ///

+ /// If specifying a property value, an + /// appropriate + /// implementation will create a + /// + /// from the value. + ///

+ ///
+ public ITransactionAttributeSource TransactionAttributeSource + { + set { _transactionInterceptor.TransactionAttributeSource = value; } + } - /// - /// Set a pointcut, i.e an object that can cause conditional invocation - /// of the - /// depending on method and attributes passed. - /// - /// - /// - /// Additional interceptors are always invoked. - /// - /// - public TruePointcut TruePointcut - { - set { _pointcut = value; } - } + /// + /// Set a pointcut, i.e an object that can cause conditional invocation + /// of the + /// depending on method and attributes passed. + /// + /// + /// + /// Additional interceptors are always invoked. + /// + /// + public TruePointcut TruePointcut + { + set { _pointcut = value; } + } - /// - /// Set additional interceptors (or advisors) to be applied before the - /// implicit transaction interceptor. - /// - public object[] PreInterceptors - { - set { _preInterceptors = value; } - } + /// + /// Set additional interceptors (or advisors) to be applied before the + /// implicit transaction interceptor. + /// + public object[] PreInterceptors + { + set { _preInterceptors = value; } + } - /// - /// Set additional interceptors (or advisors) to be applied after the - /// implicit transaction interceptor. - /// - /// - ///

- /// Note that this is just necessary if you rely on those interceptors in general. - ///

- ///
- public object[] PostInterceptors - { - set { _postInterceptors = value; } - } + /// + /// Set additional interceptors (or advisors) to be applied after the + /// implicit transaction interceptor. + /// + /// + ///

+ /// Note that this is just necessary if you rely on those interceptors in general. + ///

+ ///
+ public object[] PostInterceptors + { + set { _postInterceptors = value; } + } - /// - /// Specify the to use. - /// - /// The default instance is the global AdvisorAdapterRegistry. - public IAdvisorAdapterRegistry AdvisorAdapterRegistry - { - set { _advisorAdapterRegistry = value; } - } + /// + /// Specify the to use. + /// + /// The default instance is the global AdvisorAdapterRegistry. + public IAdvisorAdapterRegistry AdvisorAdapterRegistry + { + set { _advisorAdapterRegistry = value; } + } - #region IFactoryObject Members - /// - /// Returns the object for this proxy factory. - /// - public Type ObjectType - { - get - { - if ( _proxy != null ) - { - return _proxy.GetType(); - } - else if ( _target != null && _target is ITargetSource ) - { - return _target.GetType(); - } - else - { - return null; - } - } - } - /// - /// Returns the object wrapped by this proxy factory. - /// - /// The target object proxy. - public object GetObject() - { - return _proxy; - } + #region IFactoryObject Members - /// - /// Is this object a singleton? Always returns true in this implementation. - /// - public bool IsSingleton - { - get - { - return true; - } - } - #endregion + /// + /// Returns the object for this proxy factory. + /// + public Type ObjectType + { + get + { + if (_proxy != null) + { + return _proxy.GetType(); + } + else if (_target != null && _target is ITargetSource) + { + return _target.GetType(); + } + else + { + return null; + } + } + } - #region IInitializingObject Members - /// - /// Method run after all the properties have been set for this object. - /// Responsible for actual proxy creation. - /// - public void AfterPropertiesSet() - { - _transactionInterceptor.AfterPropertiesSet(); + /// + /// Returns the object wrapped by this proxy factory. + /// + /// The target object proxy. + public object GetObject() + { + return _proxy; + } - if ( _target == null ) - { - throw new ArgumentException("'target' is required."); - } - ProxyFactory proxyFactory = new ProxyFactory(); + /// + /// Is this object a singleton? Always returns true in this implementation. + /// + public bool IsSingleton + { + get + { + return true; + } + } - if ( _preInterceptors != null ) - { - for ( int i = 0; i < _preInterceptors.Length; i++ ) - { - proxyFactory.AddAdvisor(_advisorAdapterRegistry.Wrap(_preInterceptors[i])); - } - } - if ( _pointcut != null ) - { - IAdvisor advice = new DefaultPointcutAdvisor(_pointcut, _transactionInterceptor); - proxyFactory.AddAdvisor(advice); - } - else - { - proxyFactory.AddAdvisor( new TransactionAttributeSourceAdvisor( _transactionInterceptor ) ); - } - if ( _postInterceptors != null ) - { - for ( int i = 0; i < _postInterceptors.Length; i++ ) - { - proxyFactory.AddAdvisor(_advisorAdapterRegistry.Wrap(_postInterceptors[i])); - } - } - proxyFactory.CopyFrom(this); - proxyFactory.TargetSource = createTargetSource(_target); - if ( _proxyInterfaces != null ) - { - proxyFactory.Interfaces = _proxyInterfaces; - } - else if ( !ProxyTargetType ) - { - if ( _target is ITargetSource ) - { - throw new AopConfigException("Either 'ProxyInterfaces' or 'ProxyTargetType' is required " + - "when using an ITargetSource as 'target'"); - } - proxyFactory.Interfaces = AopUtils.GetAllInterfaces(_target); - } - _proxy = proxyFactory.GetProxy(); - } - #endregion + #endregion - /// - /// Set the target or . - /// - /// - /// The target. If this is an implementation of the - /// interface, it is used as our ; otherwise it is - /// wrapped in a . - /// - /// An for this object. - protected ITargetSource createTargetSource( object target ) - { - if ( target is ITargetSource ) - { - return (ITargetSource) target; - } else - { - return new SingletonTargetSource( target ); - } - } - } + #region IInitializingObject Members + + /// + /// Method run after all the properties have been set for this object. + /// Responsible for actual proxy creation. + /// + public void AfterPropertiesSet() + { + _transactionInterceptor.AfterPropertiesSet(); + + if (_target == null) + { + throw new ArgumentException("'target' is required."); + } + + ProxyFactory proxyFactory = new ProxyFactory(); + + if (_preInterceptors != null) + { + for (int i = 0; i < _preInterceptors.Length; i++) + { + proxyFactory.AddAdvisor(_advisorAdapterRegistry.Wrap(_preInterceptors[i])); + } + } + + if (_pointcut != null) + { + IAdvisor advice = new DefaultPointcutAdvisor(_pointcut, _transactionInterceptor); + proxyFactory.AddAdvisor(advice); + } + else + { + proxyFactory.AddAdvisor(new TransactionAttributeSourceAdvisor(_transactionInterceptor)); + } + + if (_postInterceptors != null) + { + for (int i = 0; i < _postInterceptors.Length; i++) + { + proxyFactory.AddAdvisor(_advisorAdapterRegistry.Wrap(_postInterceptors[i])); + } + } + + proxyFactory.CopyFrom(this); + proxyFactory.TargetSource = createTargetSource(_target); + if (_proxyInterfaces != null) + { + proxyFactory.Interfaces = _proxyInterfaces; + } + else if (!ProxyTargetType) + { + if (_target is ITargetSource) + { + throw new AopConfigException("Either 'ProxyInterfaces' or 'ProxyTargetType' is required " + + "when using an ITargetSource as 'target'"); + } + + proxyFactory.Interfaces = AopUtils.GetAllInterfaces(_target); + } + + _proxy = proxyFactory.GetProxy(); + } + + #endregion + + /// + /// Set the target or . + /// + /// + /// The target. If this is an implementation of the + /// interface, it is used as our ; otherwise it is + /// wrapped in a . + /// + /// An for this object. + protected ITargetSource createTargetSource(object target) + { + if (target is ITargetSource) + { + return (ITargetSource) target; + } + else + { + return new SingletonTargetSource(target); + } + } } diff --git a/src/Spring/Spring.Data/Transaction/InvalidIsolationLevelException.cs b/src/Spring/Spring.Data/Transaction/InvalidIsolationLevelException.cs index aa7809e1..09fa4bda 100644 --- a/src/Spring/Spring.Data/Transaction/InvalidIsolationLevelException.cs +++ b/src/Spring/Spring.Data/Transaction/InvalidIsolationLevelException.cs @@ -20,49 +20,51 @@ using System.Runtime.Serialization; -namespace Spring.Transaction +namespace Spring.Transaction; + +/// +/// Exception that gets thrown when an invalid isolation level is specified, +/// i.e. an isolation level that the transaction manager implementation +/// doesn't support. +/// +/// Juergen Hoeller +/// Griffin Caprio (.NET) +[Serializable] +public class InvalidIsolationLevelException : TransactionUsageException { + /// + /// Creates a new instance of the + /// class. + /// + public InvalidIsolationLevelException() { } - /// - /// Exception that gets thrown when an invalid isolation level is specified, - /// i.e. an isolation level that the transaction manager implementation - /// doesn't support. - /// - /// Juergen Hoeller - /// Griffin Caprio (.NET) - [Serializable] - public class InvalidIsolationLevelException : TransactionUsageException - { - /// - /// Creates a new instance of the - /// class. - /// - public InvalidIsolationLevelException( ) {} + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + public InvalidIsolationLevelException(String message) : base(message) { } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - public InvalidIsolationLevelException( String message ) : base(message) {} + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception that is being wrapped. + /// + public InvalidIsolationLevelException(string message, Exception rootCause) + : base(message, rootCause) + { + } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception that is being wrapped. - /// - public InvalidIsolationLevelException(string message, Exception rootCause) - : base(message, rootCause) {} - - /// - protected InvalidIsolationLevelException( - SerializationInfo info, StreamingContext context ) : base( info, context ) {} - } + /// + protected InvalidIsolationLevelException( + SerializationInfo info, StreamingContext context) : base(info, context) + { + } } diff --git a/src/Spring/Spring.Data/Transaction/InvalidTimeoutException.cs b/src/Spring/Spring.Data/Transaction/InvalidTimeoutException.cs index 18891ce6..08105d05 100644 --- a/src/Spring/Spring.Data/Transaction/InvalidTimeoutException.cs +++ b/src/Spring/Spring.Data/Transaction/InvalidTimeoutException.cs @@ -20,87 +20,88 @@ using System.Runtime.Serialization; -namespace Spring.Transaction +namespace Spring.Transaction; + +/// +/// Exception that gets thrown when an invalid timeout is specified, +/// for example when the transaction manager implementation doesn't support timeouts. +/// +/// Juergen Hoeller +/// Griffin Caprio (.NET) +[Serializable] +public class InvalidTimeoutException : TransactionUsageException, ISerializable { - /// - /// Exception that gets thrown when an invalid timeout is specified, - /// for example when the transaction manager implementation doesn't support timeouts. - /// - /// Juergen Hoeller - /// Griffin Caprio (.NET) - [Serializable] - public class InvalidTimeoutException : TransactionUsageException, ISerializable - { - /// - /// Invalid timeout value. - /// - private int _timeout = -1; + /// + /// Invalid timeout value. + /// + private int _timeout = -1; - /// - /// Returns the invalid timeout for this exception. - /// - public int Timeout - { - get - { - return _timeout; - } - } + /// + /// Returns the invalid timeout for this exception. + /// + public int Timeout + { + get + { + return _timeout; + } + } - /// - /// Creates a new instance of the - /// class - /// with the specified message and timeout value. - /// - /// - /// A message about the exception. - /// - /// The (possibly invalid) timeout value. - public InvalidTimeoutException(string message, int timeout):base(message) - { - _timeout = timeout; - } + /// + /// Creates a new instance of the + /// class + /// with the specified message and timeout value. + /// + /// + /// A message about the exception. + /// + /// The (possibly invalid) timeout value. + public InvalidTimeoutException(string message, int timeout) : base(message) + { + _timeout = timeout; + } - /// - /// Creates a new instance of the - /// class. - /// - public InvalidTimeoutException( ) {} + /// + /// Creates a new instance of the + /// class. + /// + public InvalidTimeoutException() { } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - public InvalidTimeoutException( String message ) : base(message) {} + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + public InvalidTimeoutException(String message) : base(message) { } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception that is being wrapped. - /// - public InvalidTimeoutException(string message, Exception rootCause) - : base(message, rootCause) {} + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception that is being wrapped. + /// + public InvalidTimeoutException(string message, Exception rootCause) + : base(message, rootCause) + { + } - /// - protected InvalidTimeoutException( - SerializationInfo info, StreamingContext context ) : base( info, context ) - { - _timeout = info.GetInt32( "timeout" ); - } + /// + protected InvalidTimeoutException( + SerializationInfo info, StreamingContext context) : base(info, context) + { + _timeout = info.GetInt32("timeout"); + } - /// - public override void GetObjectData(SerializationInfo info, StreamingContext context) - { - info.AddValue( "timeout", _timeout ); - base.GetObjectData( info, context ); - } - } + /// + public override void GetObjectData(SerializationInfo info, StreamingContext context) + { + info.AddValue("timeout", _timeout); + base.GetObjectData(info, context); + } } diff --git a/src/Spring/Spring.Data/Transaction/NestedTransactionNotSupportedException.cs b/src/Spring/Spring.Data/Transaction/NestedTransactionNotSupportedException.cs index ef220a39..920308a1 100644 --- a/src/Spring/Spring.Data/Transaction/NestedTransactionNotSupportedException.cs +++ b/src/Spring/Spring.Data/Transaction/NestedTransactionNotSupportedException.cs @@ -20,47 +20,50 @@ using System.Runtime.Serialization; -namespace Spring.Transaction +namespace Spring.Transaction; + +/// +/// Exception thrown when attempting to work with a nested transaction +/// but nested transactions are not supported by the underlying backend. +/// +/// Juergen Hoeller +/// Griffin Caprio (.NET) +[Serializable] +public class NestedTransactionNotSupportedException : CannotCreateTransactionException { - /// - /// Exception thrown when attempting to work with a nested transaction - /// but nested transactions are not supported by the underlying backend. - /// - /// Juergen Hoeller - /// Griffin Caprio (.NET) - [Serializable] - public class NestedTransactionNotSupportedException : CannotCreateTransactionException - { - /// - /// Creates a new instance of the - /// class. - /// - public NestedTransactionNotSupportedException( ) {} + /// + /// Creates a new instance of the + /// class. + /// + public NestedTransactionNotSupportedException() { } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - public NestedTransactionNotSupportedException( String message ) : base(message) {} + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + public NestedTransactionNotSupportedException(String message) : base(message) { } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception that is being wrapped. - /// - public NestedTransactionNotSupportedException(string message, Exception rootCause) - : base(message, rootCause) {} + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception that is being wrapped. + /// + public NestedTransactionNotSupportedException(string message, Exception rootCause) + : base(message, rootCause) + { + } - /// - protected NestedTransactionNotSupportedException( - SerializationInfo info, StreamingContext context ) : base( info, context ) {} - } + /// + protected NestedTransactionNotSupportedException( + SerializationInfo info, StreamingContext context) : base(info, context) + { + } } diff --git a/src/Spring/Spring.Data/Transaction/NoTransactionException.cs b/src/Spring/Spring.Data/Transaction/NoTransactionException.cs index 565ce8ea..11774071 100644 --- a/src/Spring/Spring.Data/Transaction/NoTransactionException.cs +++ b/src/Spring/Spring.Data/Transaction/NoTransactionException.cs @@ -20,48 +20,51 @@ using System.Runtime.Serialization; -namespace Spring.Transaction +namespace Spring.Transaction; + +/// +/// Exception thrown when an operation is attempted that relies on an existing +/// transaction (such as setting rollback status) and there is no existing transaction. +/// This represents an illegal usage of the transaction API. +/// +/// Rod Johnson +/// Griffin Caprio (.NET) +[Serializable] +public class NoTransactionException : TransactionUsageException { - /// - /// Exception thrown when an operation is attempted that relies on an existing - /// transaction (such as setting rollback status) and there is no existing transaction. - /// This represents an illegal usage of the transaction API. - /// - /// Rod Johnson - /// Griffin Caprio (.NET) - [Serializable] - public class NoTransactionException : TransactionUsageException - { - /// - /// Creates a new instance of the - /// class. - /// - public NoTransactionException( ) {} + /// + /// Creates a new instance of the + /// class. + /// + public NoTransactionException() { } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - public NoTransactionException( String message ) : base(message) {} + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + public NoTransactionException(String message) : base(message) { } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception that is being wrapped. - /// - public NoTransactionException(string message, Exception rootCause) - : base(message, rootCause) {} + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception that is being wrapped. + /// + public NoTransactionException(string message, Exception rootCause) + : base(message, rootCause) + { + } - /// - protected NoTransactionException( - SerializationInfo info, StreamingContext context ) : base( info, context ) {} - } + /// + protected NoTransactionException( + SerializationInfo info, StreamingContext context) : base(info, context) + { + } } diff --git a/src/Spring/Spring.Data/Transaction/Support/AbstractPlatformTransactionManager.cs b/src/Spring/Spring.Data/Transaction/Support/AbstractPlatformTransactionManager.cs index 0f0826cd..f88bb892 100644 --- a/src/Spring/Spring.Data/Transaction/Support/AbstractPlatformTransactionManager.cs +++ b/src/Spring/Spring.Data/Transaction/Support/AbstractPlatformTransactionManager.cs @@ -22,1254 +22,1269 @@ using System.Collections; using System.Data; using Microsoft.Extensions.Logging; -namespace Spring.Transaction.Support +namespace Spring.Transaction.Support; + +/// +/// Abstract base class that allows for easy implementation of concrete platform transaction managers. +/// +/// +///

Provides the following workflow handling: +///

    +///
  • Determines if there is an existing transaction
  • +///
  • Applies the appropriate propagation behavior
  • +///
  • Suspends and resumes transactions if necessary
  • +///
  • Checks the rollback-only flag on commit
  • +///
  • Applies the appropriate modification on rollback (actual rollback or setting rollback-only)
  • +///
  • Triggers registered synchronization callbacks (if transaction synchronization is active)
  • +///
+///

+///

+/// Transaction synchronization is a generic mechanism for registering +/// callbacks that get invoked at transaction completion time. The same mechanism +/// can also be used for custom synchronization efforts. +///

+///

+/// The state of this class is serializable. It's up to subclasses if +/// they wish to make their state to be serializable. +/// They should implement if they need +/// to restore any transient state. +///

+///
+/// Juergen Hoeller +/// Mark Pollack (.NET) +/// Griffin Caprio (.NET) +[Serializable] +public abstract class AbstractPlatformTransactionManager : IPlatformTransactionManager { + #region Private SuspendedResourcesHolder Helper class + + private class SuspendedResourcesHolder + { + private IList _suspendedSynchronizations; + private object _suspendedResources; + private string _name; + private bool _readOnly; + private IsolationLevel _isolationLevel; + private bool _wasActive; + + public SuspendedResourcesHolder(object suspendedResources) + { + _suspendedResources = suspendedResources; + } + + public SuspendedResourcesHolder(IList suspendedSynchronizations, object suspendedResources, + string name, bool readOnly, IsolationLevel isolationLevel, bool wasActive) + { + _suspendedSynchronizations = suspendedSynchronizations; + _suspendedResources = suspendedResources; + _name = name; + _readOnly = readOnly; + _isolationLevel = isolationLevel; + _wasActive = wasActive; + } + + public IList SuspendedSynchronizations + { + get { return _suspendedSynchronizations; } + } + + public object SuspendedResources + { + get { return _suspendedResources; } + } + + public string Name + { + get { return _name; } + } + + public bool ReadOnly + { + get { return _readOnly; } + } + + public IsolationLevel IsolationLevel + { + get { return _isolationLevel; } + } + + public bool WasActive + { + get { return _wasActive; } + } + } + + #endregion + + #region Private Variables + + private TransactionSynchronizationState _transactionSyncState = TransactionSynchronizationState.Never; + private bool _nestedTransactionsAllowed; + private bool _rollbackOnCommitFailure; + private bool _failEarlyOnGlobalRollbackOnly; + private int _defaultTimeout = DefaultTransactionDefinition.TIMEOUT_DEFAULT; + + #region Logging Definition + + [NonSerialized()] protected readonly ILogger log; + + #endregion + + protected AbstractPlatformTransactionManager() + { + log = LogManager.GetLogger(this.GetType()); + } + + #endregion + + #region Public Properties + /// - /// Abstract base class that allows for easy implementation of concrete platform transaction managers. + /// Sets and gets when this transaction manager should activate the thread-bound + /// transaction synchronization support. Default is "always". /// /// - ///

Provides the following workflow handling: - ///

    - ///
  • Determines if there is an existing transaction
  • - ///
  • Applies the appropriate propagation behavior
  • - ///
  • Suspends and resumes transactions if necessary
  • - ///
  • Checks the rollback-only flag on commit
  • - ///
  • Applies the appropriate modification on rollback (actual rollback or setting rollback-only)
  • - ///
  • Triggers registered synchronization callbacks (if transaction synchronization is active)
  • - ///
- ///

///

- /// Transaction synchronization is a generic mechanism for registering - /// callbacks that get invoked at transaction completion time. The same mechanism - /// can also be used for custom synchronization efforts. + /// Note that transaction synchronization isn't supported for + /// multiple concurrent transactions by different transaction managers. + /// Only one transaction manager is allowed to activate it at any time. ///

+ /// + ///
+ public TransactionSynchronizationState TransactionSynchronization + { + set { _transactionSyncState = value; } + get { return _transactionSyncState; } + } + + /// + /// Sets and gets whether nested transactions are allowed. Default is false. + /// + /// ///

- /// The state of this class is serializable. It's up to subclasses if - /// they wish to make their state to be serializable. - /// They should implement if they need - /// to restore any transient state. + /// Typically initialized with an appropriate default by the + /// concrete transaction manager subclass. ///

///
- /// Juergen Hoeller - /// Mark Pollack (.NET) - /// Griffin Caprio (.NET) - [Serializable] - public abstract class AbstractPlatformTransactionManager : IPlatformTransactionManager + public bool NestedTransactionsAllowed { - #region Private SuspendedResourcesHolder Helper class + get { return _nestedTransactionsAllowed; } + set { _nestedTransactionsAllowed = value; } + } - private class SuspendedResourcesHolder + /// + /// Sets and gets a flag that determines whether or not the + /// + /// method must be invoked if a call to the + /// + /// method fails. Default is false. + /// + /// + /// Typically not necessary and thus to be avoided as it can override the + /// commit exception with a subsequent rollback exception. + /// + public bool RollbackOnCommitFailure + { + get { return _rollbackOnCommitFailure; } + set { _rollbackOnCommitFailure = value; } + } + + /// + /// Gets or sets a value indicating whether to fail early in case of the transaction being + /// globally marked as rollback-only. + /// + /// + /// Default is "false", only causing an UnexpectedRollbackException at the + /// outermost transaction boundary. Switch this flag on to cause an + /// UnexpectedRollbackException as early as the global rollback-only marker + /// has been first detected, even from within an inner transaction boundary. + /// + /// + /// true if fail early on global rollback; otherwise, false. + /// + public bool FailEarlyOnGlobalRollbackOnly + { + get { return _failEarlyOnGlobalRollbackOnly; } + set { _failEarlyOnGlobalRollbackOnly = value; } + } + + /// + /// Gets or sets the default timeout that this transaction manager should apply if there + /// is no timeout specified at the transaction level, in seconds. + /// + /// Returns DefaultTransactionDefinition.TIMEOUT_DEFAULT to indicate the + /// underlying transaction infrastructure's default timeout. + /// The default timeout. + public int DefaultTimeout + { + get { - private IList _suspendedSynchronizations; - private object _suspendedResources; - private string _name; - private bool _readOnly; - private IsolationLevel _isolationLevel; - private bool _wasActive; - - - public SuspendedResourcesHolder(object suspendedResources) + return _defaultTimeout; + } + set + { + if (_defaultTimeout < DefaultTransactionDefinition.TIMEOUT_DEFAULT) { - _suspendedResources = suspendedResources; + throw new InvalidTimeoutException("Invalid default timeout", _defaultTimeout); } - public SuspendedResourcesHolder(IList suspendedSynchronizations, object suspendedResources, - string name, bool readOnly, IsolationLevel isolationLevel, bool wasActive) - { - _suspendedSynchronizations = suspendedSynchronizations; - _suspendedResources = suspendedResources; - _name = name; - _readOnly = readOnly; - _isolationLevel = isolationLevel; - _wasActive = wasActive; - } - - public IList SuspendedSynchronizations - { - get { return _suspendedSynchronizations; } - } - - public object SuspendedResources - { - get { return _suspendedResources; } - } - - - public string Name - { - get { return _name; } - } - - public bool ReadOnly - { - get { return _readOnly; } - } - - public IsolationLevel IsolationLevel - { - get { return _isolationLevel; } - } - - public bool WasActive - { - get { return _wasActive; } - } + _defaultTimeout = value; } + } - #endregion + #endregion - #region Private Variables + #region Protected Methods - private TransactionSynchronizationState _transactionSyncState = TransactionSynchronizationState.Never; - private bool _nestedTransactionsAllowed; - private bool _rollbackOnCommitFailure; - private bool _failEarlyOnGlobalRollbackOnly; - private int _defaultTimeout = DefaultTransactionDefinition.TIMEOUT_DEFAULT; + /// + /// Return the current transaction object. + /// + /// The current transaction object. + /// + /// If transaction support is not available. + /// + /// + /// In the case of lookup or system errors. + /// + protected abstract object DoGetTransaction(); - #region Logging Definition + /// + /// Check if the given transaction object indicates an existing transaction + /// (that is, a transaction which has already started). + /// + /// + /// The result will be evaluated according to the specified propagation + /// behavior for the new transaction. An existing transaction might get + /// suspended (in case of PROPAGATION_REQUIRES_NEW), or the new transaction + /// might participate in the existing one (in case of PROPAGATION_REQUIRED). + /// Default implementation returns false, assuming that detection of or + /// participating in existing transactions is generally not supported. + /// Subclasses are of course encouraged to provide such support. + /// + /// Transaction object returned by + /// . + /// + /// True if there is an existing transaction. + /// + /// In the case of system errors. + /// + protected virtual bool IsExistingTransaction(object transaction) + { + return false; + } - [NonSerialized()] - protected readonly ILogger log; + /// + /// Begin a new transaction with the given transaction definition. + /// + /// + /// Does not have to care about applying the propagation behavior, + /// as this has already been handled by this abstract manager. + /// + /// + /// Transaction object returned by + /// . + /// + /// + /// instance, describing + /// propagation behavior, isolation level, timeout etc. + /// + /// + /// In the case of creation or system errors. + /// + protected abstract void DoBegin(object transaction, ITransactionDefinition definition); - #endregion + /// + /// Suspend the resources of the current transaction. + /// + /// + /// Transaction synchronization will already have been suspended. + /// + /// Default implementation throws a TransactionSuspensionNotSupportedException, + /// assuming that transaction suspension is generally not supported. + /// + /// + /// + /// Transaction object returned by + /// . + /// + /// + /// An object that holds suspended resources (will be kept unexamined for passing it into + /// .) + /// + /// + /// If suspending is not supported by the transaction manager implementation. + /// + /// + /// in case of system errors. + /// + protected virtual object DoSuspend(object transaction) + { + throw new TransactionSuspensionNotSupportedException( + "Transaction manager [" + GetType().Name + "] does not support transaction suspension"); + } - protected AbstractPlatformTransactionManager() + /// + /// Resume the resources of the current transaction. + /// + /// Transaction synchronization will be resumed afterwards. + /// + /// Default implementation throws a TransactionSuspensionNotSupportedException, + /// assuming that transaction suspension is generally not supported. + /// + /// + /// + /// Transaction object returned by + /// . + /// + /// + /// The object that holds suspended resources as returned by + /// . + /// + /// + /// If suspending is not supported by the transaction manager implementation. + /// + /// + /// In the case of system errors. + /// + protected virtual void DoResume(object transaction, object suspendedResources) + { + throw new TransactionSuspensionNotSupportedException( + "Transaction manager [" + GetType().Name + "] does not support transaction suspension"); + } + + /// + /// Perform an actual commit on the given transaction. + /// + /// The status representation of the transaction. + /// + ///

+ /// An implementation does not need to check the rollback-only flag. + ///

+ ///
+ /// + /// In the case of system errors. + /// + protected abstract void DoCommit(DefaultTransactionStatus status); + + /// + /// Perform an actual rollback on the given transaction. + /// + /// The status representation of the transaction. + /// + /// An implementation does not need to check the new transaction flag. + /// + /// + /// In the case of system errors. + /// + protected abstract void DoRollback(DefaultTransactionStatus status); + + /// + /// Set the given transaction rollback-only. Only called on rollback + /// if the current transaction takes part in an existing one. + /// + /// Default implementation throws an IllegalTransactionStateException, + /// assuming that participating in existing transactions is generally not + /// supported. Subclasses are of course encouraged to provide such support. + /// + /// The status representation of the transaction. + /// + /// In the case of system errors. + /// + protected virtual void DoSetRollbackOnly(DefaultTransactionStatus status) + { + throw new IllegalTransactionStateException( + "Participating in existing transactions is not supported - when 'IsExistingTransaction' " + + "returns true, appropriate 'DoSetRollbackOnly' behavior must be provided"); + } + + /// + /// Return whether to use a savepoint for a nested transaction. Default is true, + /// which causes delegation to + /// for holding a savepoint. + /// + /// + /// + ///

+ /// Subclasses can override this to return false, causing a further + /// invocation of + /// + /// despite an already existing transaction. + ///

+ ///
+ protected virtual bool UseSavepointForNestedTransaction() + { + return true; + } + + /// + /// Register the given list of transaction synchronizations with the existing transaction. + /// + /// + /// Invoked when the control of the Spring transaction manager and thus all Spring + /// transaction synchronizations end, without the transaction being completed yet. This + /// is for example the case when participating in an existing System.Transactions or + /// EnterpriseServices transaction invoked via their APIs. + /// + /// The default implementation simply invokes the AfterCompletion methods + /// immediately, passing in TransactionSynchronizationStatus.Unknown. + /// This is the best we can do if there's no chance to determine the actual + /// outcome of the outer transaction. + /// + /// + /// The transaction transaction object returned by DoGetTransaction. + /// The lList of TransactionSynchronization objects. + /// In case of errors + /// + /// + /// + protected virtual void RegisterAfterCompletionWithExistingTransaction(Object transaction, IList synchronizations) + { + log.LogDebug("Cannot register Spring after-completion synchronization with existing transaction - " + + "processing Spring after-completion callbacks immediately, with outcome status 'unknown'"); + InvokeAfterCompletion(synchronizations, TransactionSynchronizationStatus.Unknown); + } + + /// + /// Cleanup resources after transaction completion. + /// + /// + /// Transaction object returned by + /// . + /// + /// + /// + /// Called after + /// and + /// + /// execution on any outcome. + /// + /// + /// Should not throw any exceptions but just issue warnings on errors. + /// + /// + /// Default implementation does nothing. + /// + /// + protected virtual void DoCleanupAfterCompletion(object transaction) + { + } + + #endregion + + #region IPlatformTransactionManager Members + + /// + /// Return a currently active transaction or create a new one. + /// + /// + ///

+ /// This implementation handles propagation behavior. + ///

+ ///

+ /// Delegates to + /// , + /// , + /// and + /// . + ///

+ ///

+ /// Note that parameters like isolation level or timeout will only be applied + /// to new transactions, and thus be ignored when participating in active ones. + /// Furthermore, they aren't supported by every transaction manager: + /// a proper implementation should throw an exception when custom values + /// that it doesn't support are specified. + ///

+ ///
+ /// + /// instance (can be null for + /// defaults), describing propagation behavior, isolation level, timeout etc. + /// + /// + /// In case of lookup, creation, or system errors. + /// + /// + /// representing the new or current transaction. + /// + public ITransactionStatus GetTransaction(ITransactionDefinition definition) + { + object transaction = DoGetTransaction(); + bool debugEnabled = log.IsEnabled(LogLevel.Debug); + + if (debugEnabled) { - log = LogManager.GetLogger(this.GetType()); + log.LogDebug("Using transaction object [" + transaction + "]"); } - #endregion - - #region Public Properties - - /// - /// Sets and gets when this transaction manager should activate the thread-bound - /// transaction synchronization support. Default is "always". - /// - /// - ///

- /// Note that transaction synchronization isn't supported for - /// multiple concurrent transactions by different transaction managers. - /// Only one transaction manager is allowed to activate it at any time. - ///

- /// - ///
- public TransactionSynchronizationState TransactionSynchronization + if (definition == null) { - set { _transactionSyncState = value; } - get { return _transactionSyncState; } + definition = new DefaultTransactionDefinition(); } - /// - /// Sets and gets whether nested transactions are allowed. Default is false. - /// - /// - ///

- /// Typically initialized with an appropriate default by the - /// concrete transaction manager subclass. - ///

- ///
- public bool NestedTransactionsAllowed + if (IsExistingTransaction(transaction)) { - get { return _nestedTransactionsAllowed; } - set { _nestedTransactionsAllowed = value; } + // Existing transaction found -> check propagation behavior to find out how to behave. + return HandleExistingTransaction(definition, transaction, debugEnabled); } - /// - /// Sets and gets a flag that determines whether or not the - /// - /// method must be invoked if a call to the - /// - /// method fails. Default is false. - /// - /// - /// Typically not necessary and thus to be avoided as it can override the - /// commit exception with a subsequent rollback exception. - /// - public bool RollbackOnCommitFailure + // Check definition settings for new transaction. + if (definition.TransactionTimeout < DefaultTransactionDefinition.TIMEOUT_DEFAULT) { - get { return _rollbackOnCommitFailure; } - set { _rollbackOnCommitFailure = value; } + throw new InvalidTimeoutException("Invalid transaction timeout", definition.TransactionTimeout); } - - /// - /// Gets or sets a value indicating whether to fail early in case of the transaction being - /// globally marked as rollback-only. - /// - /// - /// Default is "false", only causing an UnexpectedRollbackException at the - /// outermost transaction boundary. Switch this flag on to cause an - /// UnexpectedRollbackException as early as the global rollback-only marker - /// has been first detected, even from within an inner transaction boundary. - /// - /// - /// true if fail early on global rollback; otherwise, false. - /// - public bool FailEarlyOnGlobalRollbackOnly - { - get { return _failEarlyOnGlobalRollbackOnly; } - set { _failEarlyOnGlobalRollbackOnly = value; } - } - - /// - /// Gets or sets the default timeout that this transaction manager should apply if there - /// is no timeout specified at the transaction level, in seconds. - /// - /// Returns DefaultTransactionDefinition.TIMEOUT_DEFAULT to indicate the - /// underlying transaction infrastructure's default timeout. - /// The default timeout. - public int DefaultTimeout - { - get - { - return _defaultTimeout; - } - set - { - if (_defaultTimeout < DefaultTransactionDefinition.TIMEOUT_DEFAULT) - { - throw new InvalidTimeoutException("Invalid default timeout", _defaultTimeout); - } - _defaultTimeout = value; - } - } - - #endregion - - #region Protected Methods - - /// - /// Return the current transaction object. - /// - /// The current transaction object. - /// - /// If transaction support is not available. - /// - /// - /// In the case of lookup or system errors. - /// - protected abstract object DoGetTransaction(); - - /// - /// Check if the given transaction object indicates an existing transaction - /// (that is, a transaction which has already started). - /// - /// - /// The result will be evaluated according to the specified propagation - /// behavior for the new transaction. An existing transaction might get - /// suspended (in case of PROPAGATION_REQUIRES_NEW), or the new transaction - /// might participate in the existing one (in case of PROPAGATION_REQUIRED). - /// Default implementation returns false, assuming that detection of or - /// participating in existing transactions is generally not supported. - /// Subclasses are of course encouraged to provide such support. - /// - /// Transaction object returned by - /// . - /// - /// True if there is an existing transaction. - /// - /// In the case of system errors. - /// - protected virtual bool IsExistingTransaction(object transaction) - { - return false; - } - - /// - /// Begin a new transaction with the given transaction definition. - /// - /// - /// Does not have to care about applying the propagation behavior, - /// as this has already been handled by this abstract manager. - /// - /// - /// Transaction object returned by - /// . - /// - /// - /// instance, describing - /// propagation behavior, isolation level, timeout etc. - /// - /// - /// In the case of creation or system errors. - /// - protected abstract void DoBegin(object transaction, ITransactionDefinition definition); - - /// - /// Suspend the resources of the current transaction. - /// - /// - /// Transaction synchronization will already have been suspended. - /// - /// Default implementation throws a TransactionSuspensionNotSupportedException, - /// assuming that transaction suspension is generally not supported. - /// - /// - /// - /// Transaction object returned by - /// . - /// - /// - /// An object that holds suspended resources (will be kept unexamined for passing it into - /// .) - /// - /// - /// If suspending is not supported by the transaction manager implementation. - /// - /// - /// in case of system errors. - /// - protected virtual object DoSuspend(object transaction) - { - throw new TransactionSuspensionNotSupportedException( - "Transaction manager [" + GetType().Name + "] does not support transaction suspension"); - } - - /// - /// Resume the resources of the current transaction. - /// - /// Transaction synchronization will be resumed afterwards. - /// - /// Default implementation throws a TransactionSuspensionNotSupportedException, - /// assuming that transaction suspension is generally not supported. - /// - /// - /// - /// Transaction object returned by - /// . - /// - /// - /// The object that holds suspended resources as returned by - /// . - /// - /// - /// If suspending is not supported by the transaction manager implementation. - /// - /// - /// In the case of system errors. - /// - protected virtual void DoResume(object transaction, object suspendedResources) - { - throw new TransactionSuspensionNotSupportedException( - "Transaction manager [" + GetType().Name + "] does not support transaction suspension"); - } - - /// - /// Perform an actual commit on the given transaction. - /// - /// The status representation of the transaction. - /// - ///

- /// An implementation does not need to check the rollback-only flag. - ///

- ///
- /// - /// In the case of system errors. - /// - protected abstract void DoCommit(DefaultTransactionStatus status); - - /// - /// Perform an actual rollback on the given transaction. - /// - /// The status representation of the transaction. - /// - /// An implementation does not need to check the new transaction flag. - /// - /// - /// In the case of system errors. - /// - protected abstract void DoRollback(DefaultTransactionStatus status); - - /// - /// Set the given transaction rollback-only. Only called on rollback - /// if the current transaction takes part in an existing one. - /// - /// Default implementation throws an IllegalTransactionStateException, - /// assuming that participating in existing transactions is generally not - /// supported. Subclasses are of course encouraged to provide such support. - /// - /// The status representation of the transaction. - /// - /// In the case of system errors. - /// - protected virtual void DoSetRollbackOnly(DefaultTransactionStatus status) + // No existing transaction found -> check propagation behavior to find out how to proceed. + if (definition.PropagationBehavior == TransactionPropagation.Mandatory) { throw new IllegalTransactionStateException( - "Participating in existing transactions is not supported - when 'IsExistingTransaction' " + - "returns true, appropriate 'DoSetRollbackOnly' behavior must be provided"); + "Transaction propagation 'mandatory' but no existing transaction found"); + } + else if (definition.PropagationBehavior == TransactionPropagation.Required || + definition.PropagationBehavior == TransactionPropagation.RequiresNew || + definition.PropagationBehavior == TransactionPropagation.Nested) + { + object suspendedResources = Suspend(null); + if (debugEnabled) + { + log.LogDebug("Creating new transaction with name [" + definition.Name + "]:" + definition); + } + + try + { + bool newSynchronization = (_transactionSyncState != TransactionSynchronizationState.Never); + DefaultTransactionStatus status = NewTransactionStatus(definition, transaction, true, newSynchronization, debugEnabled, + suspendedResources); + DoBegin(transaction, definition); + PrepareSynchronization(status, definition); + return status; + } + catch (TransactionException) + { + Resume(null, suspendedResources); + throw; + } + } + else + { + // Create "empty" transaction: no actual transaction, but potentially synchronization. + bool newSynchronization = (_transactionSyncState == TransactionSynchronizationState.Always); + return PrepareTransactionStatus(definition, null, true, newSynchronization, debugEnabled, null); + } + } + + protected DefaultTransactionStatus PrepareTransactionStatus( + ITransactionDefinition definition, Object transaction, bool newTransaction, + bool newSynchronization, bool debug, Object suspendedResources) + { + DefaultTransactionStatus status = NewTransactionStatus( + definition, transaction, newTransaction, newSynchronization, debug, suspendedResources); + PrepareSynchronization(status, definition); + return status; + } + + protected void PrepareSynchronization(DefaultTransactionStatus status, ITransactionDefinition definition) + { + if (status.NewSynchronization) + { + TransactionSynchronizationManager.ActualTransactionActive = status.HasTransaction(); + TransactionSynchronizationManager.CurrentTransactionIsolationLevel = definition.TransactionIsolationLevel != System.Data.IsolationLevel.Unspecified ? definition.TransactionIsolationLevel : IsolationLevel.Unspecified; + TransactionSynchronizationManager.CurrentTransactionReadOnly = definition.ReadOnly; + TransactionSynchronizationManager.CurrentTransactionName = definition.Name; + TransactionSynchronizationManager.InitSynchronization(); + } + } + + private ITransactionStatus HandleExistingTransaction(ITransactionDefinition definition, object transaction, bool debugEnabled) + { + //bool newSynchronization; + if (definition.PropagationBehavior == TransactionPropagation.Never) + { + throw new IllegalTransactionStateException( + "Transaction propagation 'never' but existing transaction found."); } - /// - /// Return whether to use a savepoint for a nested transaction. Default is true, - /// which causes delegation to - /// for holding a savepoint. - /// - /// - /// - ///

- /// Subclasses can override this to return false, causing a further - /// invocation of - /// - /// despite an already existing transaction. - ///

- ///
- protected virtual bool UseSavepointForNestedTransaction() + if (definition.PropagationBehavior == TransactionPropagation.NotSupported) { - return true; + if (debugEnabled) + { + log.LogDebug("Suspending current transaction"); + } + + object suspendedResources = Suspend(transaction); + bool newSynchronization = (_transactionSyncState == TransactionSynchronizationState.Always); + return + PrepareTransactionStatus(definition, null, false, newSynchronization, debugEnabled, + suspendedResources); } - /// - /// Register the given list of transaction synchronizations with the existing transaction. - /// - /// - /// Invoked when the control of the Spring transaction manager and thus all Spring - /// transaction synchronizations end, without the transaction being completed yet. This - /// is for example the case when participating in an existing System.Transactions or - /// EnterpriseServices transaction invoked via their APIs. - /// - /// The default implementation simply invokes the AfterCompletion methods - /// immediately, passing in TransactionSynchronizationStatus.Unknown. - /// This is the best we can do if there's no chance to determine the actual - /// outcome of the outer transaction. - /// - /// - /// The transaction transaction object returned by DoGetTransaction. - /// The lList of TransactionSynchronization objects. - /// In case of errors - /// - /// - /// - protected virtual void RegisterAfterCompletionWithExistingTransaction(Object transaction, IList synchronizations) + if (definition.PropagationBehavior == TransactionPropagation.RequiresNew) { + if (debugEnabled) + { + log.LogDebug("Suspending current transaction, creating new transaction with name [" + + definition.Name + "]:" + definition); + } - log.LogDebug("Cannot register Spring after-completion synchronization with existing transaction - " + - "processing Spring after-completion callbacks immediately, with outcome status 'unknown'"); - InvokeAfterCompletion(synchronizations, TransactionSynchronizationStatus.Unknown); + object suspendedResources = Suspend(transaction); + try + { + bool newSynchronization = (_transactionSyncState != TransactionSynchronizationState.Never); + DefaultTransactionStatus status = NewTransactionStatus( + definition, transaction, true, newSynchronization, debugEnabled, suspendedResources); + PrepareSynchronization(status, definition); + DoBegin(transaction, definition); + return status; + } + catch (TransactionException beginEx) + { + try + { + Resume(transaction, suspendedResources); + //TODO: java code rethrows the ex here...should we do so as well? + //throw; + } + catch (TransactionException resumeEx) + { + log.LogError("Inner transaction begin exception overridden by outer transaction resume exception"); + log.LogError(beginEx, "Begin Transaction Exception"); + log.LogError(resumeEx, "Resume Transaction Exception"); + throw; + } + + throw; + } } - /// - /// Cleanup resources after transaction completion. - /// - /// - /// Transaction object returned by - /// . - /// - /// - /// - /// Called after - /// and - /// - /// execution on any outcome. - /// - /// - /// Should not throw any exceptions but just issue warnings on errors. - /// - /// - /// Default implementation does nothing. - /// - /// - protected virtual void DoCleanupAfterCompletion(object transaction) + if (definition.PropagationBehavior == TransactionPropagation.Nested) { - } - - #endregion - - #region IPlatformTransactionManager Members - - /// - /// Return a currently active transaction or create a new one. - /// - /// - ///

- /// This implementation handles propagation behavior. - ///

- ///

- /// Delegates to - /// , - /// , - /// and - /// . - ///

- ///

- /// Note that parameters like isolation level or timeout will only be applied - /// to new transactions, and thus be ignored when participating in active ones. - /// Furthermore, they aren't supported by every transaction manager: - /// a proper implementation should throw an exception when custom values - /// that it doesn't support are specified. - ///

- ///
- /// - /// instance (can be null for - /// defaults), describing propagation behavior, isolation level, timeout etc. - /// - /// - /// In case of lookup, creation, or system errors. - /// - /// - /// representing the new or current transaction. - /// - public ITransactionStatus GetTransaction(ITransactionDefinition definition) - { - object transaction = DoGetTransaction(); - bool debugEnabled = log.IsEnabled(LogLevel.Debug); + if (!NestedTransactionsAllowed) + { + throw new NestedTransactionNotSupportedException( + "Transaction manager does not allow nested transactions by default - " + + "specify 'NestedTransactionsAllowed' property with value 'true'"); + } if (debugEnabled) { - log.LogDebug("Using transaction object [" + transaction + "]"); + log.LogDebug("Creating nested transaction with name [" + definition.Name + "]:" + definition); } - if (definition == null) + if (UseSavepointForNestedTransaction()) { - definition = new DefaultTransactionDefinition(); - } - if (IsExistingTransaction(transaction)) - { - // Existing transaction found -> check propagation behavior to find out how to behave. - return HandleExistingTransaction(definition, transaction, debugEnabled); - } - - // Check definition settings for new transaction. - if (definition.TransactionTimeout < DefaultTransactionDefinition.TIMEOUT_DEFAULT) - { - throw new InvalidTimeoutException("Invalid transaction timeout", definition.TransactionTimeout); - } - - // No existing transaction found -> check propagation behavior to find out how to proceed. - if (definition.PropagationBehavior == TransactionPropagation.Mandatory) - { - throw new IllegalTransactionStateException( - "Transaction propagation 'mandatory' but no existing transaction found"); - } - else if (definition.PropagationBehavior == TransactionPropagation.Required || - definition.PropagationBehavior == TransactionPropagation.RequiresNew || - definition.PropagationBehavior == TransactionPropagation.Nested) - { - object suspendedResources = Suspend(null); - if (debugEnabled) - { - log.LogDebug("Creating new transaction with name [" + definition.Name + "]:" + definition); - } - try - { - bool newSynchronization = (_transactionSyncState != TransactionSynchronizationState.Never); - DefaultTransactionStatus status = NewTransactionStatus(definition, transaction, true, newSynchronization, debugEnabled, - suspendedResources); - DoBegin(transaction, definition); - PrepareSynchronization(status, definition); - return status; - } - catch (TransactionException) - { - Resume(null, suspendedResources); - throw; - } + DefaultTransactionStatus status = + PrepareTransactionStatus(definition, transaction, false, false, debugEnabled, null); + status.CreateAndHoldSavepoint(DateTime.Now.ToLongTimeString()); + return status; } else { - // Create "empty" transaction: no actual transaction, but potentially synchronization. - bool newSynchronization = (_transactionSyncState == TransactionSynchronizationState.Always); - return PrepareTransactionStatus(definition, null, true, newSynchronization, debugEnabled, null); - - } - - } - - protected DefaultTransactionStatus PrepareTransactionStatus( - ITransactionDefinition definition, Object transaction, bool newTransaction, - bool newSynchronization, bool debug, Object suspendedResources) - { - DefaultTransactionStatus status = NewTransactionStatus( - definition, transaction, newTransaction, newSynchronization, debug, suspendedResources); - PrepareSynchronization(status, definition); - return status; - } - - - protected void PrepareSynchronization(DefaultTransactionStatus status, ITransactionDefinition definition) - { - if (status.NewSynchronization) - { - TransactionSynchronizationManager.ActualTransactionActive = status.HasTransaction(); - TransactionSynchronizationManager.CurrentTransactionIsolationLevel = definition.TransactionIsolationLevel != System.Data.IsolationLevel.Unspecified ? definition.TransactionIsolationLevel : IsolationLevel.Unspecified; - TransactionSynchronizationManager.CurrentTransactionReadOnly = definition.ReadOnly; - TransactionSynchronizationManager.CurrentTransactionName = definition.Name; - TransactionSynchronizationManager.InitSynchronization(); + bool newSynchronization = (_transactionSyncState != TransactionSynchronizationState.Never); + DefaultTransactionStatus status = NewTransactionStatus(definition, transaction, true, newSynchronization, debugEnabled, null); + PrepareSynchronization(status, definition); + DoBegin(transaction, definition); + return status; } } - private ITransactionStatus HandleExistingTransaction(ITransactionDefinition definition, object transaction, bool debugEnabled) + // Assumably PROPAGATION_SUPPORTS. + if (debugEnabled) { - //bool newSynchronization; - if (definition.PropagationBehavior == TransactionPropagation.Never) + log.LogDebug("Participating in existing transaction"); + } + + //TODO: this block related to un-ported java feature permitting setting the ValidateExistingTransaction flag + // default is FALSE anyway so skipping this validation block should have no effect on code excecution path + /*if (isValidateExistingTransaction()) + { + if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) { - throw new IllegalTransactionStateException( - "Transaction propagation 'never' but existing transaction found."); - } - if (definition.PropagationBehavior == TransactionPropagation.NotSupported) - { - if (debugEnabled) + Integer currentIsolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel(); + if (currentIsolationLevel == null || currentIsolationLevel != definition.getIsolationLevel()) { - log.LogDebug("Suspending current transaction"); + Constants isoConstants = DefaultTransactionDefinition.constants; + throw new IllegalTransactionStateException("Participating transaction with definition [" + + definition + "] specifies isolation level which is incompatible with existing transaction: " + + (currentIsolationLevel != null ? + isoConstants.toCode(currentIsolationLevel, DefaultTransactionDefinition.PREFIX_ISOLATION) : + "(unknown)")); } - object suspendedResources = Suspend(transaction); - bool newSynchronization = (_transactionSyncState == TransactionSynchronizationState.Always); - return - PrepareTransactionStatus(definition, null, false, newSynchronization, debugEnabled, - suspendedResources); + }*/ + + if (!definition.ReadOnly) + { + if (TransactionSynchronizationManager.CurrentTransactionReadOnly) + { + throw new IllegalTransactionStateException("Participating transaction with definition [" + + definition + "] is not marked as read-only but existing transaction is"); + } + } + + bool newSynch = (_transactionSyncState != TransactionSynchronizationState.Never); + return PrepareTransactionStatus(definition, transaction, false, newSynch, debugEnabled, null); + } + + /// + /// This implementation of commit handles participating in existing transactions + /// and programmatic rollback requests. + /// + /// + /// + /// + /// ITransactionStatus object returned by the + /// () method. + /// + /// + /// In case of commit or system errors. + /// + public void Commit(ITransactionStatus transactionStatus) + { + if (transactionStatus.Completed) + { + throw new IllegalTransactionStateException( + "Transaction is already completed - do not call commit or rollback more than once per transaction"); + } + + DefaultTransactionStatus defaultStatus = (DefaultTransactionStatus) transactionStatus; + if (defaultStatus.LocalRollbackOnly) + { + if (defaultStatus.Debug) + { + log.LogDebug("Transaction code has requested rollback"); } - if (definition.PropagationBehavior == TransactionPropagation.RequiresNew) + ProcessRollback(defaultStatus); + return; + } + + if (!ShouldCommitOnGlobalRollbackOnly && defaultStatus.GlobalRollbackOnly) + { + if (defaultStatus.Debug) { - if (debugEnabled) - { - log.LogDebug("Suspending current transaction, creating new transaction with name [" + - definition.Name + "]:" + definition); - } - object suspendedResources = Suspend(transaction); - try - { - bool newSynchronization = (_transactionSyncState != TransactionSynchronizationState.Never); - DefaultTransactionStatus status = NewTransactionStatus( - definition, transaction, true, newSynchronization, debugEnabled, suspendedResources); - PrepareSynchronization(status, definition); - DoBegin(transaction, definition); - return status; - } - catch (TransactionException beginEx) - { - try - { - Resume(transaction, suspendedResources); - //TODO: java code rethrows the ex here...should we do so as well? - //throw; - } - catch (TransactionException resumeEx) - { - log.LogError("Inner transaction begin exception overridden by outer transaction resume exception"); - log.LogError(beginEx, "Begin Transaction Exception"); - log.LogError(resumeEx, "Resume Transaction Exception"); - throw; - } - throw; - } + log.LogDebug("Global transaction is marked as rollback-only but transactional code requested commit"); } - if (definition.PropagationBehavior == TransactionPropagation.Nested) + + ProcessRollback(defaultStatus); + // Throw UnexpectedRollbackException only at outermost transaction boundary + // or if explicitly asked to. + if (defaultStatus.IsNewTransaction || FailEarlyOnGlobalRollbackOnly) { - if (!NestedTransactionsAllowed) + throw new UnexpectedRollbackException( + "Transaction rolled back because it has been marked as rollback-only"); + } + + return; + } + + ProcessCommit(defaultStatus); + } + + protected virtual bool ShouldCommitOnGlobalRollbackOnly + { + get { return false; } + } + + private void ProcessCommit(DefaultTransactionStatus status) + { + try + { + bool beforeCompletionInvoked = false; + try + { + TriggerBeforeCommit(status); + TriggerBeforeCompletion(status); + beforeCompletionInvoked = true; + bool globalRollbackOnly = false; + if (status.IsNewTransaction || FailEarlyOnGlobalRollbackOnly) { - throw new NestedTransactionNotSupportedException( - "Transaction manager does not allow nested transactions by default - " + - "specify 'NestedTransactionsAllowed' property with value 'true'"); - } - if (debugEnabled) - { - log.LogDebug("Creating nested transaction with name [" + definition.Name + "]:" + definition); + globalRollbackOnly = status.GlobalRollbackOnly; } - if (UseSavepointForNestedTransaction()) + if (status.HasSavepoint) { - DefaultTransactionStatus status = - PrepareTransactionStatus(definition, transaction, false, false, debugEnabled, null); - status.CreateAndHoldSavepoint(DateTime.Now.ToLongTimeString()); - return status; + status.ReleaseHeldSavepoint(); + } + else if (status.IsNewTransaction) + { + DoCommit(status); + } + + // Throw UnexpectedRollbackException if we have a global rollback-only + // marker but still didn't get a corresponding exception from commit. + if (globalRollbackOnly) + { + throw new UnexpectedRollbackException( + "Transaction silently rolled back because it has been marked as rollback-only"); + } + } + catch (UnexpectedRollbackException) + { + TriggerAfterCompletion(status, TransactionSynchronizationStatus.Rolledback); + throw; + } + catch (TransactionException ex) + { + if (RollbackOnCommitFailure) + { + DoRollbackOnCommitException(status, ex); } else - { - bool newSynchronization = (_transactionSyncState != TransactionSynchronizationState.Never); - DefaultTransactionStatus status = NewTransactionStatus(definition, transaction, true, newSynchronization, debugEnabled, null); - PrepareSynchronization(status, definition); - DoBegin(transaction, definition); - return status; - - } - } - // Assumably PROPAGATION_SUPPORTS. - if (debugEnabled) - { - log.LogDebug("Participating in existing transaction"); - } - - //TODO: this block related to un-ported java feature permitting setting the ValidateExistingTransaction flag - // default is FALSE anyway so skipping this validation block should have no effect on code excecution path - /*if (isValidateExistingTransaction()) - { - if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) - { - Integer currentIsolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel(); - if (currentIsolationLevel == null || currentIsolationLevel != definition.getIsolationLevel()) - { - Constants isoConstants = DefaultTransactionDefinition.constants; - throw new IllegalTransactionStateException("Participating transaction with definition [" + - definition + "] specifies isolation level which is incompatible with existing transaction: " + - (currentIsolationLevel != null ? - isoConstants.toCode(currentIsolationLevel, DefaultTransactionDefinition.PREFIX_ISOLATION) : - "(unknown)")); - } - }*/ - - if (!definition.ReadOnly) - { - if (TransactionSynchronizationManager.CurrentTransactionReadOnly) - { - throw new IllegalTransactionStateException("Participating transaction with definition [" + - definition + "] is not marked as read-only but existing transaction is"); - } - } - - bool newSynch = (_transactionSyncState != TransactionSynchronizationState.Never); - return PrepareTransactionStatus(definition, transaction, false, newSynch, debugEnabled, null); - - } - - /// - /// This implementation of commit handles participating in existing transactions - /// and programmatic rollback requests. - /// - /// - /// - /// - /// ITransactionStatus object returned by the - /// () method. - /// - /// - /// In case of commit or system errors. - /// - public void Commit(ITransactionStatus transactionStatus) - { - if (transactionStatus.Completed) - { - throw new IllegalTransactionStateException( - "Transaction is already completed - do not call commit or rollback more than once per transaction"); - } - - DefaultTransactionStatus defaultStatus = (DefaultTransactionStatus)transactionStatus; - if (defaultStatus.LocalRollbackOnly) - { - if (defaultStatus.Debug) - { - log.LogDebug("Transaction code has requested rollback"); - } - ProcessRollback(defaultStatus); - return; - } - if (!ShouldCommitOnGlobalRollbackOnly && defaultStatus.GlobalRollbackOnly) - { - if (defaultStatus.Debug) - { - log.LogDebug("Global transaction is marked as rollback-only but transactional code requested commit"); - } - ProcessRollback(defaultStatus); - // Throw UnexpectedRollbackException only at outermost transaction boundary - // or if explicitly asked to. - if (defaultStatus.IsNewTransaction || FailEarlyOnGlobalRollbackOnly) - { - throw new UnexpectedRollbackException( - "Transaction rolled back because it has been marked as rollback-only"); - } - return; - } - ProcessCommit(defaultStatus); - - } - - protected virtual bool ShouldCommitOnGlobalRollbackOnly - { - get { return false; } - } - - private void ProcessCommit(DefaultTransactionStatus status) - { - try - { - bool beforeCompletionInvoked = false; - try - { - TriggerBeforeCommit(status); - TriggerBeforeCompletion(status); - beforeCompletionInvoked = true; - bool globalRollbackOnly = false; - if (status.IsNewTransaction || FailEarlyOnGlobalRollbackOnly) - { - globalRollbackOnly = status.GlobalRollbackOnly; - } - if (status.HasSavepoint) - { - status.ReleaseHeldSavepoint(); - } - else if (status.IsNewTransaction) - { - DoCommit(status); - } - // Throw UnexpectedRollbackException if we have a global rollback-only - // marker but still didn't get a corresponding exception from commit. - if (globalRollbackOnly) - { - throw new UnexpectedRollbackException( - "Transaction silently rolled back because it has been marked as rollback-only"); - } - } - catch (UnexpectedRollbackException) - { - TriggerAfterCompletion(status, TransactionSynchronizationStatus.Rolledback); - throw; - } - catch (TransactionException ex) - { - if (RollbackOnCommitFailure) - { - DoRollbackOnCommitException(status, ex); - } - else - { - TriggerAfterCompletion(status, TransactionSynchronizationStatus.Unknown); - } - throw; - } - catch (Exception ex) - { - if (!beforeCompletionInvoked) - { - TriggerBeforeCompletion(status); - } - DoRollbackOnCommitException(status, ex); - throw; - } - // Trigger AfterCommit callbacks, with an exception thrown there - // propagated to callers but the transaction still considered as commited. - try - { - TriggerAfterCommit(status); - } - finally - { - TriggerAfterCompletion(status, TransactionSynchronizationStatus.Committed); - } - } - finally - { - CleanupAfterCompletion(status); - } - } - - private void TriggerAfterCommit(DefaultTransactionStatus status) - { - if (status.NewSynchronization) - { - if (status.Debug) - { - log.LogDebug("Trigger AfterCommit Synchronization"); - } - IList synchronizations = TransactionSynchronizationManager.Synchronizations; - foreach (ITransactionSynchronization currentTxnSynchronization in synchronizations) - { - try - { - currentTxnSynchronization.AfterCommit(); - } - catch (Exception e) - { - log.LogError(e, "TransactionSynchronization.AfterCommit thew exception"); - } - } - } - } - - /// - /// Roll back the given transaction, with regard to its status. - /// - /// - ///

- /// This implementation handles participating in existing transactions. - ///

- ///

- /// Delegates to - /// , - /// and - /// . - ///

- ///

- /// If the transaction wasn't a new one, just set it rollback-only - /// to take part in the surrounding transaction properly. - ///

- ///
- /// - /// ITransactionStatusObject returned by the - /// () method. - /// - /// - /// In case of system errors. - /// - public void Rollback(ITransactionStatus transactionStatus) - { - if (transactionStatus.Completed) - { - throw new IllegalTransactionStateException( - "Transaction is already completed - do not call commit or rollback more than once per transaction"); - } - DefaultTransactionStatus defaultStatus = (DefaultTransactionStatus)transactionStatus; - ProcessRollback(defaultStatus); - } - - private void ProcessRollback(DefaultTransactionStatus status) - { - try - { - try - { - TriggerBeforeCompletion(status); - if (status.HasSavepoint) - { - if (status.Debug) - { - log.LogDebug("Rolling back transaction to savepoint."); - } - status.RollbackToHeldSavepoint(); - } - else if (status.IsNewTransaction) - { - if (status.Debug) - { - log.LogDebug("Initiating transaction rollback"); - } - DoRollback(status); - } - else if (status.HasTransaction()) - { - if (status.LocalRollbackOnly) - { - if (status.Debug) - { - log.LogDebug("Participating transaction failed - marking existing transaction as rollback-only"); - } - } - DoSetRollbackOnly(status); - } - else - { - log.LogDebug("Should roll back transaction but cannot - no transaction available."); - } - } - catch (Exception) { TriggerAfterCompletion(status, TransactionSynchronizationStatus.Unknown); - throw; } - TriggerAfterCompletion(status, TransactionSynchronizationStatus.Rolledback); + + throw; + } + catch (Exception ex) + { + if (!beforeCompletionInvoked) + { + TriggerBeforeCompletion(status); + } + + DoRollbackOnCommitException(status, ex); + throw; + } + + // Trigger AfterCommit callbacks, with an exception thrown there + // propagated to callers but the transaction still considered as commited. + try + { + TriggerAfterCommit(status); } finally { - CleanupAfterCompletion(status); + TriggerAfterCompletion(status, TransactionSynchronizationStatus.Committed); } } - - #endregion - - #region Protected Method - - private DefaultTransactionStatus NewTransactionStatus(ITransactionDefinition definition, - object transaction, bool newTransaction, - bool newSynchronization, bool debug, - object suspendedResources) + finally { - bool actualNewSynchronization = newSynchronization && - !TransactionSynchronizationManager.SynchronizationActive; - // if (actualNewSynchronization) - // { - // TransactionSynchronizationManager.ActualTransactionActive = (transaction != null); - // TransactionSynchronizationManager.CurrentTransactionIsolationLevel = - // definition.TransactionIsolationLevel; - // TransactionSynchronizationManager.CurrentTransactionReadOnly = definition.ReadOnly; - // TransactionSynchronizationManager.CurrentTransactionName = definition.Name; - // TransactionSynchronizationManager.InitSynchronization(); - // } - return - new DefaultTransactionStatus(transaction, newTransaction, actualNewSynchronization, definition.ReadOnly, debug, - suspendedResources); + CleanupAfterCompletion(status); } + } - /// - /// Determines the timeout to use for the given definition. Will fall back to this manager's default - /// timeout if the transaction definition doesn't specify a non-default value. - /// - /// The transaction definition. - /// the actual timeout to use. - protected int DetermineTimeout(ITransactionDefinition definition) + private void TriggerAfterCommit(DefaultTransactionStatus status) + { + if (status.NewSynchronization) { - if (definition.TransactionTimeout != DefaultTransactionDefinition.TIMEOUT_DEFAULT) + if (status.Debug) { - return definition.TransactionTimeout; + log.LogDebug("Trigger AfterCommit Synchronization"); } - return _defaultTimeout; - } - #endregion - - #region Private Methods - - - - - - /// - /// Suspend the given transaction. Suspends transaction synchronization first, - /// then delegates to the doSuspend template method. - /// - /// the current transaction object - /// an object that holds suspended resources - private object Suspend(object transaction) - { - if (TransactionSynchronizationManager.SynchronizationActive) + IList synchronizations = TransactionSynchronizationManager.Synchronizations; + foreach (ITransactionSynchronization currentTxnSynchronization in synchronizations) { - IList suspendedSynchronizations = DoSuspendSynchronization(); - try { - object suspendedResources = null; - if (transaction != null) - { - suspendedResources = DoSuspend(transaction); - } - - string name = TransactionSynchronizationManager.CurrentTransactionName; - TransactionSynchronizationManager.CurrentTransactionName = null; - bool readOnly = TransactionSynchronizationManager.CurrentTransactionReadOnly; - TransactionSynchronizationManager.CurrentTransactionReadOnly = false; - IsolationLevel isolationLevel = TransactionSynchronizationManager.CurrentTransactionIsolationLevel; - TransactionSynchronizationManager.CurrentTransactionIsolationLevel = IsolationLevel.Unspecified; - bool wasActive = TransactionSynchronizationManager.ActualTransactionActive; - TransactionSynchronizationManager.ActualTransactionActive = false; - - - return new SuspendedResourcesHolder(suspendedSynchronizations, suspendedResources, - name, readOnly, isolationLevel, wasActive); - + currentTxnSynchronization.AfterCommit(); } - catch (TransactionException) + catch (Exception e) { - // DoSuspend failed - original transaction is still active - DoResumeSynchronization(suspendedSynchronizations); - throw; + log.LogError(e, "TransactionSynchronization.AfterCommit thew exception"); } } - else if (transaction != null) - { - // Transaction active but no synchronization active. - object suspendedResources = DoSuspend(transaction); - return new SuspendedResourcesHolder(suspendedResources); - } - else - { - // Neither transaction nor synchronization active. - return null; - } - } + } - private IList DoSuspendSynchronization() + /// + /// Roll back the given transaction, with regard to its status. + /// + /// + ///

+ /// This implementation handles participating in existing transactions. + ///

+ ///

+ /// Delegates to + /// , + /// and + /// . + ///

+ ///

+ /// If the transaction wasn't a new one, just set it rollback-only + /// to take part in the surrounding transaction properly. + ///

+ ///
+ /// + /// ITransactionStatusObject returned by the + /// () method. + /// + /// + /// In case of system errors. + /// + public void Rollback(ITransactionStatus transactionStatus) + { + if (transactionStatus.Completed) { - IList suspendedSynchronizations = TransactionSynchronizationManager.Synchronizations; - foreach (ITransactionSynchronization currentTxnSynchronization in suspendedSynchronizations) - { - currentTxnSynchronization.Suspend(); - } - TransactionSynchronizationManager.ClearSynchronization(); - return suspendedSynchronizations; + throw new IllegalTransactionStateException( + "Transaction is already completed - do not call commit or rollback more than once per transaction"); } - private void DoResumeSynchronization(IList suspendedSynchronizations) - { - TransactionSynchronizationManager.InitSynchronization(); - foreach (ITransactionSynchronization currentTxnSynchronization in suspendedSynchronizations) - { - currentTxnSynchronization.Resume(); - TransactionSynchronizationManager.RegisterSynchronization(currentTxnSynchronization); - } - } + DefaultTransactionStatus defaultStatus = (DefaultTransactionStatus) transactionStatus; + ProcessRollback(defaultStatus); + } - /// - /// Resume the given transaction. Delegates to the doResume template method - /// first, then resuming transaction synchronization. - /// - /// the current transaction object - /// the object that holds suspended resources, as returned by suspend - private void Resume(object transaction, object suspendedResources) - { - SuspendedResourcesHolder resourcesHolder = (SuspendedResourcesHolder)suspendedResources; - if (resourcesHolder != null) - { - object suspendedResourcesObject = resourcesHolder.SuspendedResources; - if (suspendedResourcesObject != null) - { - DoResume(transaction, suspendedResourcesObject); - } - IList suspendedSynchronizations = resourcesHolder.SuspendedSynchronizations; - if (suspendedSynchronizations != null) - { - TransactionSynchronizationManager.ActualTransactionActive = resourcesHolder.WasActive; - TransactionSynchronizationManager.CurrentTransactionIsolationLevel = resourcesHolder.IsolationLevel; - TransactionSynchronizationManager.CurrentTransactionReadOnly = resourcesHolder.ReadOnly; - TransactionSynchronizationManager.CurrentTransactionName = resourcesHolder.Name; - DoResumeSynchronization(suspendedSynchronizations); - } - - } - } - - - - /// - /// Invoke doRollback, handling rollback exceptions properly. - /// - /// object representing the transaction - /// the thrown application exception or error - /// - /// in case of a rollback error - /// - private void DoRollbackOnCommitException(DefaultTransactionStatus status, Exception exception) + private void ProcessRollback(DefaultTransactionStatus status) + { + try { try { - if (status.IsNewTransaction) + TriggerBeforeCompletion(status); + if (status.HasSavepoint) { if (status.Debug) { - log.LogDebug("Initiating transaction rollback on commit exception."); + log.LogDebug("Rolling back transaction to savepoint."); } + + status.RollbackToHeldSavepoint(); + } + else if (status.IsNewTransaction) + { + if (status.Debug) + { + log.LogDebug("Initiating transaction rollback"); + } + DoRollback(status); } else if (status.HasTransaction()) { - if (status.Debug) + if (status.LocalRollbackOnly) { - log.LogDebug(exception, "Marking existing transaction as rollback-only after commit exception"); + if (status.Debug) + { + log.LogDebug("Participating transaction failed - marking existing transaction as rollback-only"); + } } + DoSetRollbackOnly(status); } + else + { + log.LogDebug("Should roll back transaction but cannot - no transaction available."); + } } catch (Exception) { - //TODO investigate rollback behavior... - log.LogError(exception, "Commit exception overridden by rollback exception"); TriggerAfterCompletion(status, TransactionSynchronizationStatus.Unknown); throw; } + TriggerAfterCompletion(status, TransactionSynchronizationStatus.Rolledback); } - - /// - /// Trigger beforeCommit callback. - /// - /// object representing the transaction - private void TriggerBeforeCommit(DefaultTransactionStatus status) + finally { - if (status.NewSynchronization) - { - IList synchronizations = TransactionSynchronizationManager.Synchronizations; - foreach (ITransactionSynchronization currentTxnSynchronization in synchronizations) - { - currentTxnSynchronization.BeforeCommit(status.ReadOnly); - } - } + CleanupAfterCompletion(status); + } + } + + #endregion + + #region Protected Method + + private DefaultTransactionStatus NewTransactionStatus(ITransactionDefinition definition, + object transaction, bool newTransaction, + bool newSynchronization, bool debug, + object suspendedResources) + { + bool actualNewSynchronization = newSynchronization && + !TransactionSynchronizationManager.SynchronizationActive; + // if (actualNewSynchronization) + // { + // TransactionSynchronizationManager.ActualTransactionActive = (transaction != null); + // TransactionSynchronizationManager.CurrentTransactionIsolationLevel = + // definition.TransactionIsolationLevel; + // TransactionSynchronizationManager.CurrentTransactionReadOnly = definition.ReadOnly; + // TransactionSynchronizationManager.CurrentTransactionName = definition.Name; + // TransactionSynchronizationManager.InitSynchronization(); + // } + return + new DefaultTransactionStatus(transaction, newTransaction, actualNewSynchronization, definition.ReadOnly, debug, + suspendedResources); + } + + /// + /// Determines the timeout to use for the given definition. Will fall back to this manager's default + /// timeout if the transaction definition doesn't specify a non-default value. + /// + /// The transaction definition. + /// the actual timeout to use. + protected int DetermineTimeout(ITransactionDefinition definition) + { + if (definition.TransactionTimeout != DefaultTransactionDefinition.TIMEOUT_DEFAULT) + { + return definition.TransactionTimeout; } - /// - /// Trigger beforeCompletion callback. - /// - /// object representing the transaction - private void TriggerBeforeCompletion(DefaultTransactionStatus status) + return _defaultTimeout; + } + + #endregion + + #region Private Methods + + /// + /// Suspend the given transaction. Suspends transaction synchronization first, + /// then delegates to the doSuspend template method. + /// + /// the current transaction object + /// an object that holds suspended resources + private object Suspend(object transaction) + { + if (TransactionSynchronizationManager.SynchronizationActive) { - if (status.NewSynchronization) + IList suspendedSynchronizations = DoSuspendSynchronization(); + + try + { + object suspendedResources = null; + if (transaction != null) + { + suspendedResources = DoSuspend(transaction); + } + + string name = TransactionSynchronizationManager.CurrentTransactionName; + TransactionSynchronizationManager.CurrentTransactionName = null; + bool readOnly = TransactionSynchronizationManager.CurrentTransactionReadOnly; + TransactionSynchronizationManager.CurrentTransactionReadOnly = false; + IsolationLevel isolationLevel = TransactionSynchronizationManager.CurrentTransactionIsolationLevel; + TransactionSynchronizationManager.CurrentTransactionIsolationLevel = IsolationLevel.Unspecified; + bool wasActive = TransactionSynchronizationManager.ActualTransactionActive; + TransactionSynchronizationManager.ActualTransactionActive = false; + + return new SuspendedResourcesHolder(suspendedSynchronizations, suspendedResources, + name, readOnly, isolationLevel, wasActive); + } + catch (TransactionException) + { + // DoSuspend failed - original transaction is still active + DoResumeSynchronization(suspendedSynchronizations); + throw; + } + } + else if (transaction != null) + { + // Transaction active but no synchronization active. + object suspendedResources = DoSuspend(transaction); + return new SuspendedResourcesHolder(suspendedResources); + } + else + { + // Neither transaction nor synchronization active. + return null; + } + } + + private IList DoSuspendSynchronization() + { + IList suspendedSynchronizations = TransactionSynchronizationManager.Synchronizations; + foreach (ITransactionSynchronization currentTxnSynchronization in suspendedSynchronizations) + { + currentTxnSynchronization.Suspend(); + } + + TransactionSynchronizationManager.ClearSynchronization(); + return suspendedSynchronizations; + } + + private void DoResumeSynchronization(IList suspendedSynchronizations) + { + TransactionSynchronizationManager.InitSynchronization(); + foreach (ITransactionSynchronization currentTxnSynchronization in suspendedSynchronizations) + { + currentTxnSynchronization.Resume(); + TransactionSynchronizationManager.RegisterSynchronization(currentTxnSynchronization); + } + } + + /// + /// Resume the given transaction. Delegates to the doResume template method + /// first, then resuming transaction synchronization. + /// + /// the current transaction object + /// the object that holds suspended resources, as returned by suspend + private void Resume(object transaction, object suspendedResources) + { + SuspendedResourcesHolder resourcesHolder = (SuspendedResourcesHolder) suspendedResources; + if (resourcesHolder != null) + { + object suspendedResourcesObject = resourcesHolder.SuspendedResources; + if (suspendedResourcesObject != null) + { + DoResume(transaction, suspendedResourcesObject); + } + + IList suspendedSynchronizations = resourcesHolder.SuspendedSynchronizations; + if (suspendedSynchronizations != null) + { + TransactionSynchronizationManager.ActualTransactionActive = resourcesHolder.WasActive; + TransactionSynchronizationManager.CurrentTransactionIsolationLevel = resourcesHolder.IsolationLevel; + TransactionSynchronizationManager.CurrentTransactionReadOnly = resourcesHolder.ReadOnly; + TransactionSynchronizationManager.CurrentTransactionName = resourcesHolder.Name; + DoResumeSynchronization(suspendedSynchronizations); + } + } + } + + /// + /// Invoke doRollback, handling rollback exceptions properly. + /// + /// object representing the transaction + /// the thrown application exception or error + /// + /// in case of a rollback error + /// + private void DoRollbackOnCommitException(DefaultTransactionStatus status, Exception exception) + { + try + { + if (status.IsNewTransaction) { if (status.Debug) { - log.LogDebug("Trigger BeforeCompletion Synchronization"); + log.LogDebug("Initiating transaction rollback on commit exception."); } - IList synchronizations = TransactionSynchronizationManager.Synchronizations; - foreach (ITransactionSynchronization synchronization in synchronizations) - { - try - { - synchronization.BeforeCompletion(); - } - catch (Exception e) - { - log.LogError(e, "TransactionSynchronization.BeforeCompletion threw exception"); - } - } - } - } - /// - /// Trigger afterCompletion callback, handling exceptions properly. - /// - /// object representing the transaction - /// - /// Completion status according to - /// - private void TriggerAfterCompletion(DefaultTransactionStatus status, TransactionSynchronizationStatus completionStatus) - { - if (status.NewSynchronization) + DoRollback(status); + } + else if (status.HasTransaction()) { - IList synchronizations = TransactionSynchronizationManager.Synchronizations; - if (!status.HasTransaction() || status.IsNewTransaction) + if (status.Debug) { - if (status.Debug) - { - log.LogDebug("Triggering afterCompletion synchronization"); - } - InvokeAfterCompletion(synchronizations, completionStatus); - } - else - { - //TODO investigate parallel of JTA/System.Txs - log.LogInformation("Transaction controlled outside of spring tx manager."); - RegisterAfterCompletionWithExistingTransaction(status.Transaction, synchronizations); + log.LogDebug(exception, "Marking existing transaction as rollback-only after commit exception"); } + + DoSetRollbackOnly(status); } } - - private void InvokeAfterCompletion(IList synchronizations, TransactionSynchronizationStatus status) + catch (Exception) { + //TODO investigate rollback behavior... + log.LogError(exception, "Commit exception overridden by rollback exception"); + TriggerAfterCompletion(status, TransactionSynchronizationStatus.Unknown); + throw; + } + + TriggerAfterCompletion(status, TransactionSynchronizationStatus.Rolledback); + } + + /// + /// Trigger beforeCommit callback. + /// + /// object representing the transaction + private void TriggerBeforeCommit(DefaultTransactionStatus status) + { + if (status.NewSynchronization) + { + IList synchronizations = TransactionSynchronizationManager.Synchronizations; + foreach (ITransactionSynchronization currentTxnSynchronization in synchronizations) + { + currentTxnSynchronization.BeforeCommit(status.ReadOnly); + } + } + } + + /// + /// Trigger beforeCompletion callback. + /// + /// object representing the transaction + private void TriggerBeforeCompletion(DefaultTransactionStatus status) + { + if (status.NewSynchronization) + { + if (status.Debug) + { + log.LogDebug("Trigger BeforeCompletion Synchronization"); + } + + IList synchronizations = TransactionSynchronizationManager.Synchronizations; foreach (ITransactionSynchronization synchronization in synchronizations) { try { - synchronization.AfterCompletion(status); + synchronization.BeforeCompletion(); } catch (Exception e) { - log.LogError(e, "TransactionSynchronization.AfterCompletion threw exception"); + log.LogError(e, "TransactionSynchronization.BeforeCompletion threw exception"); } } } + } - /// - /// Clean up after completion, clearing synchronization if necessary, - /// and invoking doCleanupAfterCompletion. - /// - /// object representing the transaction - private void CleanupAfterCompletion(DefaultTransactionStatus status) + /// + /// Trigger afterCompletion callback, handling exceptions properly. + /// + /// object representing the transaction + /// + /// Completion status according to + /// + private void TriggerAfterCompletion(DefaultTransactionStatus status, TransactionSynchronizationStatus completionStatus) + { + if (status.NewSynchronization) { - status.Completed = true; - if (status.NewSynchronization) - { - TransactionSynchronizationManager.Clear(); - } - if (status.IsNewTransaction) - { - DoCleanupAfterCompletion(status.Transaction); - } - if (status.SuspendedResources != null) + IList synchronizations = TransactionSynchronizationManager.Synchronizations; + if (!status.HasTransaction() || status.IsNewTransaction) { if (status.Debug) { - log.LogDebug("Resuming suspended transaction"); + log.LogDebug("Triggering afterCompletion synchronization"); } - Resume(status.Transaction, status.SuspendedResources); + + InvokeAfterCompletion(synchronizations, completionStatus); + } + else + { + //TODO investigate parallel of JTA/System.Txs + log.LogInformation("Transaction controlled outside of spring tx manager."); + RegisterAfterCompletionWithExistingTransaction(status.Transaction, synchronizations); } } - - #endregion } + + private void InvokeAfterCompletion(IList synchronizations, TransactionSynchronizationStatus status) + { + foreach (ITransactionSynchronization synchronization in synchronizations) + { + try + { + synchronization.AfterCompletion(status); + } + catch (Exception e) + { + log.LogError(e, "TransactionSynchronization.AfterCompletion threw exception"); + } + } + } + + /// + /// Clean up after completion, clearing synchronization if necessary, + /// and invoking doCleanupAfterCompletion. + /// + /// object representing the transaction + private void CleanupAfterCompletion(DefaultTransactionStatus status) + { + status.Completed = true; + if (status.NewSynchronization) + { + TransactionSynchronizationManager.Clear(); + } + + if (status.IsNewTransaction) + { + DoCleanupAfterCompletion(status.Transaction); + } + + if (status.SuspendedResources != null) + { + if (status.Debug) + { + log.LogDebug("Resuming suspended transaction"); + } + + Resume(status.Transaction, status.SuspendedResources); + } + } + + #endregion } diff --git a/src/Spring/Spring.Data/Transaction/Support/DefaultTransactionDefinition.cs b/src/Spring/Spring.Data/Transaction/Support/DefaultTransactionDefinition.cs index 00bfb8c9..cb5dc998 100644 --- a/src/Spring/Spring.Data/Transaction/Support/DefaultTransactionDefinition.cs +++ b/src/Spring/Spring.Data/Transaction/Support/DefaultTransactionDefinition.cs @@ -17,257 +17,256 @@ using System.Text; using System.Transactions; -namespace Spring.Transaction.Support +namespace Spring.Transaction.Support; + +/// +/// Default implementation of the +/// interface, offering object-style configuration and sensible default values. +/// +/// +///

+/// Base class for both and +/// . +///

+///
+/// Juergen Hoeller +/// Griffin Caprio (.NET) +/// Mark Pollack (.NET) +[Serializable] +public class DefaultTransactionDefinition : ITransactionDefinition { /// - /// Default implementation of the - /// interface, offering object-style configuration and sensible default values. + /// Prefix for Propagation settings. + /// + public static readonly string PROPAGATION_CONSTANT_PREFIX = "PROPAGATION"; + + /// + /// Prefix for IsolationLevel settings. + /// + public static readonly string ISOLATION_CONSTANT_PREFIX = "ISOLATION"; + + /// + /// Prefix for transaction timeout values in description strings. + /// + public static readonly string TIMEOUT_PREFIX = "timeout_"; + + /// + /// Marker for read-only transactions in description strings. + /// + public static readonly string READ_ONLY_MARKER = "readOnly"; + + /// + /// The default transaction timeout. + /// + public const int TIMEOUT_DEFAULT = -1; + + //TODO Refactoring to sync with Spring 2.0 for nt/enums for various default values. + + private TransactionPropagation _transactionPropagation = TransactionPropagation.Required; + private System.Data.IsolationLevel _transactionIsolationLevel = System.Data.IsolationLevel.ReadCommitted; + private int _timeout = TIMEOUT_DEFAULT; + private bool _readOnly = false; + private string _name = null; + private System.Transactions.TransactionScopeAsyncFlowOption _asyncFlowOption = TransactionScopeAsyncFlowOption.Enabled; + + /// + /// Creates a new instance of the + /// class. + /// + public DefaultTransactionDefinition() + { + } + + /// + /// Creates a new instance of the + /// class + /// with the supplied + /// behaviour. + /// + /// + /// The desired behavior. + /// + public DefaultTransactionDefinition(TransactionPropagation transactionPropagation) + { + _transactionPropagation = transactionPropagation; + } + + // TODO change method name to same as type returned (TransactionPropagation) + + /// + /// Gets / Sets the propagation + /// behavior. + /// + public TransactionPropagation PropagationBehavior + { + get => _transactionPropagation; + set => _transactionPropagation = value; + } + + // TODO change method name to same as type returned (TransactionPropagation) + + /// + /// Return the isolation level of type . /// /// ///

- /// Base class for both and - /// . + /// Only makes sense in combination with + /// and + /// . + ///

+ ///

+ /// Note that a transaction manager that does not support custom isolation levels + /// will throw an exception when given any other level than + /// . ///

///
- /// Juergen Hoeller - /// Griffin Caprio (.NET) - /// Mark Pollack (.NET) - [Serializable] - public class DefaultTransactionDefinition : ITransactionDefinition + public System.Data.IsolationLevel TransactionIsolationLevel { - /// - /// Prefix for Propagation settings. - /// - public static readonly string PROPAGATION_CONSTANT_PREFIX = "PROPAGATION"; + get => _transactionIsolationLevel; + set => _transactionIsolationLevel = value; + } - /// - /// Prefix for IsolationLevel settings. - /// - public static readonly string ISOLATION_CONSTANT_PREFIX = "ISOLATION"; - - /// - /// Prefix for transaction timeout values in description strings. - /// - public static readonly string TIMEOUT_PREFIX = "timeout_"; - - /// - /// Marker for read-only transactions in description strings. - /// - public static readonly string READ_ONLY_MARKER = "readOnly"; - - /// - /// The default transaction timeout. - /// - public const int TIMEOUT_DEFAULT = -1; - - //TODO Refactoring to sync with Spring 2.0 for nt/enums for various default values. - - private TransactionPropagation _transactionPropagation = TransactionPropagation.Required; - private System.Data.IsolationLevel _transactionIsolationLevel = System.Data.IsolationLevel.ReadCommitted; - private int _timeout = TIMEOUT_DEFAULT; - private bool _readOnly = false; - private string _name = null; - private System.Transactions.TransactionScopeAsyncFlowOption _asyncFlowOption = TransactionScopeAsyncFlowOption.Enabled; - - /// - /// Creates a new instance of the - /// class. - /// - public DefaultTransactionDefinition() + /// + /// Return the transaction timeout. + /// + /// + ///

+ /// Must return a number of seconds, or -1. + /// Only makes sense in combination with + /// and + /// . + /// Note that a transaction manager that does not support timeouts will + /// throw an exception when given any other timeout than -1. + ///

+ ///
+ public int TransactionTimeout + { + get => _timeout; + set { - } - - /// - /// Creates a new instance of the - /// class - /// with the supplied - /// behaviour. - /// - /// - /// The desired behavior. - /// - public DefaultTransactionDefinition(TransactionPropagation transactionPropagation) - { - _transactionPropagation = transactionPropagation; - } - - // TODO change method name to same as type returned (TransactionPropagation) - - /// - /// Gets / Sets the propagation - /// behavior. - /// - public TransactionPropagation PropagationBehavior - { - get => _transactionPropagation; - set => _transactionPropagation = value; - } - - // TODO change method name to same as type returned (TransactionPropagation) - - /// - /// Return the isolation level of type . - /// - /// - ///

- /// Only makes sense in combination with - /// and - /// . - ///

- ///

- /// Note that a transaction manager that does not support custom isolation levels - /// will throw an exception when given any other level than - /// . - ///

- ///
- public System.Data.IsolationLevel TransactionIsolationLevel - { - get => _transactionIsolationLevel; - set => _transactionIsolationLevel = value; - } - - /// - /// Return the transaction timeout. - /// - /// - ///

- /// Must return a number of seconds, or -1. - /// Only makes sense in combination with - /// and - /// . - /// Note that a transaction manager that does not support timeouts will - /// throw an exception when given any other timeout than -1. - ///

- ///
- public int TransactionTimeout - { - get => _timeout; - set + if (value < TIMEOUT_DEFAULT) { - if (value < TIMEOUT_DEFAULT) - { - throw new ArgumentException( - "Timeout must be a positive integer or DefaultTransactionDefinition.TIMEOUT_DEFAULT"); - } - - _timeout = value; + throw new ArgumentException( + "Timeout must be a positive integer or DefaultTransactionDefinition.TIMEOUT_DEFAULT"); } - } - /// - /// Get whether to optimize as read-only transaction. - /// - /// - ///

- /// This just serves as hint for the actual transaction subsystem, - /// it will not necessarily cause failure of write accesses. - ///

- ///

- /// Only makes sense in combination with - /// and - /// . - ///

- ///

- /// A transaction manager that cannot interpret the read-only hint - /// will not throw an exception when given ReadOnly=true. - ///

- ///
- public bool ReadOnly - { - get => _readOnly; - set => _readOnly = value; + _timeout = value; } + } - /// - /// Return the name of this transaction. Can be null. - /// - /// - /// - /// This will be used as a transaction name to be shown in a - /// transaction monitor, if applicable. In the case of Spring - /// declarative transactions, the exposed name will be the fully - /// qualified type name + "." method name + assembly (by default). - /// - public string Name - { - get => _name; - set => _name = value; - } + /// + /// Get whether to optimize as read-only transaction. + /// + /// + ///

+ /// This just serves as hint for the actual transaction subsystem, + /// it will not necessarily cause failure of write accesses. + ///

+ ///

+ /// Only makes sense in combination with + /// and + /// . + ///

+ ///

+ /// A transaction manager that cannot interpret the read-only hint + /// will not throw an exception when given ReadOnly=true. + ///

+ ///
+ public bool ReadOnly + { + get => _readOnly; + set => _readOnly = value; + } - /// - public System.Transactions.TransactionScopeAsyncFlowOption AsyncFlowOption - { - get => _asyncFlowOption; - set => _asyncFlowOption = value; - } + /// + /// Return the name of this transaction. Can be null. + /// + /// + /// + /// This will be used as a transaction name to be shown in a + /// transaction monitor, if applicable. In the case of Spring + /// declarative transactions, the exposed name will be the fully + /// qualified type name + "." method name + assembly (by default). + /// + public string Name + { + get => _name; + set => _name = value; + } - /// - /// An override of the default method. - /// - /// The to compare to. - /// True if the objects are equal. - public override bool Equals(object obj) - { - return (obj is ITransactionDefinition) && ToString().Equals(obj.ToString()); - } + /// + public System.Transactions.TransactionScopeAsyncFlowOption AsyncFlowOption + { + get => _asyncFlowOption; + set => _asyncFlowOption = value; + } - /// - /// An override of the default method that returns the - /// hashcode of the - /// - /// property. - /// - /// - /// The hashcode of the - /// - /// property. - /// - public override int GetHashCode() - { - return ToString().GetHashCode(); - } + /// + /// An override of the default method. + /// + /// The to compare to. + /// True if the objects are equal. + public override bool Equals(object obj) + { + return (obj is ITransactionDefinition) && ToString().Equals(obj.ToString()); + } - /// - /// An override of the default method that returns a string - /// representation of the - /// - /// property. - /// - /// - /// A string representation of the - /// - /// property. - /// - public override string ToString() - { - return DefinitionDescription; - } + /// + /// An override of the default method that returns the + /// hashcode of the + /// + /// property. + /// + /// + /// The hashcode of the + /// + /// property. + /// + public override int GetHashCode() + { + return ToString().GetHashCode(); + } - /// - /// Returns a representation of the - /// - /// property. - /// - protected string DefinitionDescription + /// + /// An override of the default method that returns a string + /// representation of the + /// + /// property. + /// + /// + /// A string representation of the + /// + /// property. + /// + public override string ToString() + { + return DefinitionDescription; + } + + /// + /// Returns a representation of the + /// + /// property. + /// + protected string DefinitionDescription + { + get { - get + StringBuilder builder = new StringBuilder(); + builder.Append(PROPAGATION_CONSTANT_PREFIX + "_" + PropagationBehavior); + builder.Append(","); + builder.Append(ISOLATION_CONSTANT_PREFIX + "_" + TransactionIsolationLevel); + if (TransactionTimeout != TIMEOUT_DEFAULT) { - StringBuilder builder = new StringBuilder(); - builder.Append(PROPAGATION_CONSTANT_PREFIX + "_" + PropagationBehavior); - builder.Append(","); - builder.Append(ISOLATION_CONSTANT_PREFIX + "_" + TransactionIsolationLevel); - if (TransactionTimeout != TIMEOUT_DEFAULT) - { - builder.Append(",timeout_" + _timeout); - } - - if (ReadOnly) - { - builder.Append(",readOnly"); - } - - return builder.ToString(); + builder.Append(",timeout_" + _timeout); } + + if (ReadOnly) + { + builder.Append(",readOnly"); + } + + return builder.ToString(); } } } diff --git a/src/Spring/Spring.Data/Transaction/Support/DefaultTransactionStatus.cs b/src/Spring/Spring.Data/Transaction/Support/DefaultTransactionStatus.cs index ac7e1464..8fd61c36 100644 --- a/src/Spring/Spring.Data/Transaction/Support/DefaultTransactionStatus.cs +++ b/src/Spring/Spring.Data/Transaction/Support/DefaultTransactionStatus.cs @@ -18,326 +18,333 @@ #endregion +namespace Spring.Transaction.Support; -namespace Spring.Transaction.Support +/// +/// Default implementation of the interface, +/// used by . +/// +/// +///

+/// Holds all status information that +/// +/// needs internally, including a generic transaction object determined by +/// the concrete transaction manager implementation. +///

+///

+/// Supports delegating savepoint-related methods to a transaction object +/// that implements the interface. +///

+///
+/// Juergen Hoeller +/// Griffin Caprio (.NET) +/// Mark Pollack (.NET) +public class DefaultTransactionStatus : ITransactionStatus { - /// - /// Default implementation of the interface, - /// used by . - /// - /// - ///

- /// Holds all status information that - /// - /// needs internally, including a generic transaction object determined by - /// the concrete transaction manager implementation. - ///

- ///

- /// Supports delegating savepoint-related methods to a transaction object - /// that implements the interface. - ///

- ///
- /// Juergen Hoeller - /// Griffin Caprio (.NET) - /// Mark Pollack (.NET) - public class DefaultTransactionStatus : ITransactionStatus - { - private object _transaction; - private bool _newTransaction; - private bool _newSynchronization; - private bool _readOnly; - private readonly bool _debug; - private object _suspendedResources; - - private string _savepoint; - private bool _rollbackOnly; - private bool _completed = false; + private object _transaction; + private bool _newTransaction; + private bool _newSynchronization; + private bool _readOnly; + private readonly bool _debug; + private object _suspendedResources; - /// - /// Creates a new instance of the - /// class. - /// - /// The underlying transaction object that can hold state for the internal - /// transaction implementation. - /// True if the transaction is new, else false if participating in an existing transaction. - /// True if a new transaction synchronization has been opened for the given - /// . - /// True if the transaction is read only. - /// if set to true, enable debug log in tx managers. - /// The suspended resources for the given . - public DefaultTransactionStatus( object transaction, - bool newTransaction, - bool newSynchronization, - bool readOnly, - bool debug, - object suspendedResources) - { - _transaction = transaction; - _newTransaction = newTransaction; - _newSynchronization = newSynchronization; - _readOnly = readOnly; - _debug = debug; - _suspendedResources = suspendedResources; - } + private string _savepoint; + private bool _rollbackOnly; + private bool _completed = false; - #region Properties + /// + /// Creates a new instance of the + /// class. + /// + /// The underlying transaction object that can hold state for the internal + /// transaction implementation. + /// True if the transaction is new, else false if participating in an existing transaction. + /// True if a new transaction synchronization has been opened for the given + /// . + /// True if the transaction is read only. + /// if set to true, enable debug log in tx managers. + /// The suspended resources for the given . + public DefaultTransactionStatus(object transaction, + bool newTransaction, + bool newSynchronization, + bool readOnly, + bool debug, + object suspendedResources) + { + _transaction = transaction; + _newTransaction = newTransaction; + _newSynchronization = newSynchronization; + _readOnly = readOnly; + _debug = debug; + _suspendedResources = suspendedResources; + } - /// - /// Gets a value indicating whether the progress of this transaction is debugged. - /// This is used by AbstractPlatformTransactionManager as an optimization, to prevent repeated - /// calls to log.IsDebug. Not really intended for client code. - /// true if debug; otherwise, false. - public bool Debug - { - get { return _debug; } - } + #region Properties - /// - /// Returns the underlying transaction object. - /// - public object Transaction - { - get { return _transaction; } - } + /// + /// Gets a value indicating whether the progress of this transaction is debugged. + /// This is used by AbstractPlatformTransactionManager as an optimization, to prevent repeated + /// calls to log.IsDebug. Not really intended for client code. + /// true if debug; otherwise, false. + public bool Debug + { + get { return _debug; } + } - /// - /// Gets or sets a value indicating whether the Transaction is completed, that is commited or rolled back. - /// - /// true if completed; otherwise, false. - public bool Completed - { - get { return _completed; } - set { _completed = value; } - } + /// + /// Returns the underlying transaction object. + /// + public object Transaction + { + get { return _transaction; } + } - /// - /// Returns true if the underlying transaction is read only. - /// - public bool ReadOnly - { - get { return _readOnly; } - } + /// + /// Gets or sets a value indicating whether the Transaction is completed, that is commited or rolled back. + /// + /// true if completed; otherwise, false. + public bool Completed + { + get { return _completed; } + set { _completed = value; } + } - /// - /// Flag indicating if a new transaction synchronization has been opened - /// for this transaction. - /// - public bool NewSynchronization - { - get { return _newSynchronization; } - } + /// + /// Returns true if the underlying transaction is read only. + /// + public bool ReadOnly + { + get { return _readOnly; } + } - /// - /// Returns suspended resources for this transaction. - /// - public object SuspendedResources - { - get { return _suspendedResources; } - } + /// + /// Flag indicating if a new transaction synchronization has been opened + /// for this transaction. + /// + public bool NewSynchronization + { + get { return _newSynchronization; } + } - /// - /// Gets and sets the savepoint for the current transaction, if any. - /// - public string Savepoint - { - get { return _savepoint; } - set { _savepoint = value; } - } + /// + /// Returns suspended resources for this transaction. + /// + public object SuspendedResources + { + get { return _suspendedResources; } + } - /// - /// Returns a flag indicating if the transaction has a savepoint. - /// - public bool HasSavepoint - { - get { return ( _savepoint != null ); } - } + /// + /// Gets and sets the savepoint for the current transaction, if any. + /// + public string Savepoint + { + get { return _savepoint; } + set { _savepoint = value; } + } - /// - /// Determines whether there is an actual transaction active. - /// - /// - /// true if there is an actual transaction active; otherwise, false. - /// - public bool HasTransaction() - { - return Transaction != null; - } + /// + /// Returns a flag indicating if the transaction has a savepoint. + /// + public bool HasSavepoint + { + get { return (_savepoint != null); } + } - /// - /// Return the underlying transaction as a - /// , if possible. - /// - /// - /// If the underlying transaction does not support savepoints. - /// - protected ISavepointManager SavepointManager - { - get - { - if ( ! IsTransactionSavepointManager ) - { - throw new NestedTransactionNotSupportedException( - "Transaction object [" + Transaction + "] does not support savepoints."); - } - return ( ISavepointManager) Transaction; - } - } - /// - /// Return true if the underlying transaction implements the - /// interface. - /// - public bool IsTransactionSavepointManager - { - get { return ( Transaction is ISavepointManager ); } - } - #endregion + /// + /// Determines whether there is an actual transaction active. + /// + /// + /// true if there is an actual transaction active; otherwise, false. + /// + public bool HasTransaction() + { + return Transaction != null; + } - #region ITransactionStatus Members - /// - /// Returns true if the transaction is new, else false if participating - /// in an existing transaction. - /// - public bool IsNewTransaction - { - get - { - return ( HasTransaction() && _newTransaction ); - } - } - - /// - /// Determine the rollbackOnly flag via checking both this - /// - /// and the transaction object, provided that the latter implements the - /// interface. - /// - /// The property can only be set to true. - public bool RollbackOnly - { - get { - return ( LocalRollbackOnly || GlobalRollbackOnly); - } - } - - /// - /// Set the transaction rollback-only. This instructs the transaction manager that the only possible outcome of - /// the transaction may be a rollback, proceeding with the normal application - /// workflow though (i.e. no exception). - /// - /// - ///

- /// For transactions managed by a or - /// . - /// An alternative way to trigger a rollback is throwing an transaction exception. - ///

- ///
- public void SetRollbackOnly() - { - _rollbackOnly = true; - } - - #endregion - - - /// - /// Determine the rollback-only flag via checking this TransactionStatus. Will only - /// return true if the application set the property RollbackOnly to true on this - /// TransactionStatus object. - /// - /// true if [local rollback only]; otherwise, false. - public bool LocalRollbackOnly - { - get + /// + /// Return the underlying transaction as a + /// , if possible. + /// + /// + /// If the underlying transaction does not support savepoints. + /// + protected ISavepointManager SavepointManager + { + get + { + if (!IsTransactionSavepointManager) { - return _rollbackOnly; + throw new NestedTransactionNotSupportedException( + "Transaction object [" + Transaction + "] does not support savepoints."); } + + return (ISavepointManager) Transaction; + } + } + + /// + /// Return true if the underlying transaction implements the + /// interface. + /// + public bool IsTransactionSavepointManager + { + get { return (Transaction is ISavepointManager); } + } + + #endregion + + #region ITransactionStatus Members + + /// + /// Returns true if the transaction is new, else false if participating + /// in an existing transaction. + /// + public bool IsNewTransaction + { + get + { + return (HasTransaction() && _newTransaction); + } + } + + /// + /// Determine the rollbackOnly flag via checking both this + /// + /// and the transaction object, provided that the latter implements the + /// interface. + /// + /// The property can only be set to true. + public bool RollbackOnly + { + get + { + return (LocalRollbackOnly || GlobalRollbackOnly); + } + } + + /// + /// Set the transaction rollback-only. This instructs the transaction manager that the only possible outcome of + /// the transaction may be a rollback, proceeding with the normal application + /// workflow though (i.e. no exception). + /// + /// + ///

+ /// For transactions managed by a or + /// . + /// An alternative way to trigger a rollback is throwing an transaction exception. + ///

+ ///
+ public void SetRollbackOnly() + { + _rollbackOnly = true; + } + + #endregion + + /// + /// Determine the rollback-only flag via checking this TransactionStatus. Will only + /// return true if the application set the property RollbackOnly to true on this + /// TransactionStatus object. + /// + /// true if [local rollback only]; otherwise, false. + public bool LocalRollbackOnly + { + get + { + return _rollbackOnly; + } + } + + public bool GlobalRollbackOnly + { + get + { + return ((_transaction is ISmartTransactionObject) && + ((ISmartTransactionObject) _transaction).RollbackOnly); + } + } + + #region ISavepointManager Members + + /// + /// This implementation delegates to the underlying transaction object + /// (if it implements the interface) + /// to create a savepoint. + /// + /// + /// If the underlying transaction does not support savepoints. + /// + public void CreateSavepoint(string savepoint) + { + SavepointManager.CreateSavepoint(savepoint); + } + + /// + /// This implementation delegates to the underlying transaction object + /// (if it implements the interface) + /// to rollback to the supplied . + /// + /// The savepoint to rollback to. + public void RollbackToSavepoint(string savepoint) + { + SavepointManager.RollbackToSavepoint(savepoint); + } + + /// + /// This implementation delegates to the underlying transaction object + /// (if it implements the interface) + /// to release the supplied . + /// + /// The savepoint to release. + public void ReleaseSavepoint(string savepoint) + { + SavepointManager.ReleaseSavepoint(savepoint); + } + + #endregion + + /// + /// Create a savepoint and hold it for the transaction. + /// + /// + /// If the underlying transaction does not support savepoints. + /// + public void CreateAndHoldSavepoint(string savepoint) + { + SavepointManager.CreateSavepoint(savepoint); + Savepoint = savepoint; + } + + /// + /// Roll back to the savepoint that is held for the transaction. + /// + /// + /// If no save point has been created. + /// + public void RollbackToHeldSavepoint() + { + if (!HasSavepoint) + { + throw new TransactionUsageException("No savepoint associated with current transaction"); } - public bool GlobalRollbackOnly - { - get - { - return ((_transaction is ISmartTransactionObject) && - ((ISmartTransactionObject) _transaction).RollbackOnly); - } - } - #region ISavepointManager Members - /// - /// This implementation delegates to the underlying transaction object - /// (if it implements the interface) - /// to create a savepoint. - /// - /// - /// If the underlying transaction does not support savepoints. - /// - public void CreateSavepoint( string savepoint ) - { - SavepointManager.CreateSavepoint( savepoint ); - } + SavepointManager.RollbackToSavepoint(Savepoint); + } - /// - /// This implementation delegates to the underlying transaction object - /// (if it implements the interface) - /// to rollback to the supplied . - /// - /// The savepoint to rollback to. - public void RollbackToSavepoint( string savepoint ) - { - SavepointManager.RollbackToSavepoint( savepoint ); - } + /// + /// Release the savepoint that is held for the transaction. + /// + /// + /// If no save point has been created. + /// + public void ReleaseHeldSavepoint() + { + if (!HasSavepoint) + { + throw new TransactionUsageException("No savepoint associated with current transaction"); + } - /// - /// This implementation delegates to the underlying transaction object - /// (if it implements the interface) - /// to release the supplied . - /// - /// The savepoint to release. - public void ReleaseSavepoint( string savepoint) - { - SavepointManager.ReleaseSavepoint( savepoint ); - } - - #endregion - /// - /// Create a savepoint and hold it for the transaction. - /// - /// - /// If the underlying transaction does not support savepoints. - /// - public void CreateAndHoldSavepoint( string savepoint ) - { - SavepointManager.CreateSavepoint( savepoint ); - Savepoint = savepoint; - } - - /// - /// Roll back to the savepoint that is held for the transaction. - /// - /// - /// If no save point has been created. - /// - public void RollbackToHeldSavepoint() - { - if ( ! HasSavepoint ) - { - throw new TransactionUsageException( "No savepoint associated with current transaction" ); - } - SavepointManager.RollbackToSavepoint( Savepoint ); - } - - /// - /// Release the savepoint that is held for the transaction. - /// - /// - /// If no save point has been created. - /// - public void ReleaseHeldSavepoint() - { - if ( ! HasSavepoint ) - { - throw new TransactionUsageException( "No savepoint associated with current transaction" ); - } - SavepointManager.ReleaseSavepoint( Savepoint ); - } - } + SavepointManager.ReleaseSavepoint(Savepoint); + } } diff --git a/src/Spring/Spring.Data/Transaction/Support/IResourceTransactionManager.cs b/src/Spring/Spring.Data/Transaction/Support/IResourceTransactionManager.cs index 47b10ab6..5e330bae 100644 --- a/src/Spring/Spring.Data/Transaction/Support/IResourceTransactionManager.cs +++ b/src/Spring/Spring.Data/Transaction/Support/IResourceTransactionManager.cs @@ -1,49 +1,48 @@ #region License -/* - * Copyright 2002-2010 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. +/* + * Copyright 2002-2010 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 +#endregion -namespace Spring.Transaction.Support +namespace Spring.Transaction.Support; + +/// +/// Extension of the +/// interface, indicating a native resource transaction manager, operating on a single +/// target resource. Such transaction managers differ from DTC based transaction managers in +/// that they do not use transaction enlistment for an open number of resources but +/// rather focus on leveraging the native power and simplicity of a single target resource. +/// +/// +/// This interface is mainly used for abstract introspection of a transaction manager, +/// giving clients a hint on what kind of transaction manager they have been given +/// and on what concrete resource the transaction manager is operating on. +/// +/// Juergen Hoeller +/// Mark Pollack +public interface IResourceTransactionManager : IPlatformTransactionManager { /// - /// Extension of the - /// interface, indicating a native resource transaction manager, operating on a single - /// target resource. Such transaction managers differ from DTC based transaction managers in - /// that they do not use transaction enlistment for an open number of resources but - /// rather focus on leveraging the native power and simplicity of a single target resource. + /// Gets the resource factory that this transaction manager operates on, + /// e.g. a IDbProvider or a Hibernate ISessionFactory. /// - /// - /// This interface is mainly used for abstract introspection of a transaction manager, - /// giving clients a hint on what kind of transaction manager they have been given - /// and on what concrete resource the transaction manager is operating on. - /// - /// Juergen Hoeller - /// Mark Pollack - public interface IResourceTransactionManager : IPlatformTransactionManager + /// The resource factory. + object ResourceFactory { - /// - /// Gets the resource factory that this transaction manager operates on, - /// e.g. a IDbProvider or a Hibernate ISessionFactory. - /// - /// The resource factory. - object ResourceFactory - { - get; - } + get; } -} \ No newline at end of file +} diff --git a/src/Spring/Spring.Data/Transaction/Support/ISmartTransactionObject.cs b/src/Spring/Spring.Data/Transaction/Support/ISmartTransactionObject.cs index 4b3b1a16..46cf4a01 100644 --- a/src/Spring/Spring.Data/Transaction/Support/ISmartTransactionObject.cs +++ b/src/Spring/Spring.Data/Transaction/Support/ISmartTransactionObject.cs @@ -18,31 +18,30 @@ #endregion -namespace Spring.Transaction.Support +namespace Spring.Transaction.Support; + +/// +/// Interface to be implemented by transaction objects that are able to +/// return an internal rollback-only marker, typically from a another +/// transaction that has participated and marked it as rollback-only. +/// +/// +///

+/// Autodetected by , +/// to always return a current rollbackOnly flag even if not resulting from the current +/// . +///

+///
+/// Juergen Hoeller +/// Griffin Caprio (.NET) +public interface ISmartTransactionObject { - /// - /// Interface to be implemented by transaction objects that are able to - /// return an internal rollback-only marker, typically from a another - /// transaction that has participated and marked it as rollback-only. - /// - /// - ///

- /// Autodetected by , - /// to always return a current rollbackOnly flag even if not resulting from the current - /// . - ///

- ///
- /// Juergen Hoeller - /// Griffin Caprio (.NET) - public interface ISmartTransactionObject - { - /// - /// Return whether the transaction is internally marked as rollback-only. - /// - /// True of the transaction is marked as rollback-only. - bool RollbackOnly - { - get; - } - } + /// + /// Return whether the transaction is internally marked as rollback-only. + /// + /// True of the transaction is marked as rollback-only. + bool RollbackOnly + { + get; + } } diff --git a/src/Spring/Spring.Data/Transaction/Support/ITransactionCallback.cs b/src/Spring/Spring.Data/Transaction/Support/ITransactionCallback.cs index 5d3466be..12768e1e 100644 --- a/src/Spring/Spring.Data/Transaction/Support/ITransactionCallback.cs +++ b/src/Spring/Spring.Data/Transaction/Support/ITransactionCallback.cs @@ -1,14 +1,14 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. - * + * Copyright � 2002-2011 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. @@ -18,32 +18,30 @@ #endregion +namespace Spring.Transaction.Support; -namespace Spring.Transaction.Support +/// +/// Callback interface for transactional code. +/// +/// +///

To be used with 's Execute +/// methods. +///

+///

+/// Typically used to gather various calls to transaction-unaware low-level +/// services into a higher-level method implementation with transaction +/// demarcation. +///

+///
+/// Juergen Hoeller +/// Mark Pollack (.NET) +public interface ITransactionCallback { /// - /// Callback interface for transactional code. + /// Gets called by TransactionTemplate.Execute within a + /// transaction context. /// - /// - ///

To be used with 's Execute - /// methods. - ///

- ///

- /// Typically used to gather various calls to transaction-unaware low-level - /// services into a higher-level method implementation with transaction - /// demarcation. - ///

- ///
- /// Juergen Hoeller - /// Mark Pollack (.NET) - public interface ITransactionCallback - { - /// - /// Gets called by TransactionTemplate.Execute within a - /// transaction context. - /// - /// The associated transaction status. - /// A result object or null. - object DoInTransaction(ITransactionStatus status); - } + /// The associated transaction status. + /// A result object or null. + object DoInTransaction(ITransactionStatus status); } diff --git a/src/Spring/Spring.Data/Transaction/Support/ITransactionOperations.cs b/src/Spring/Spring.Data/Transaction/Support/ITransactionOperations.cs index a4c4f979..39e70df1 100644 --- a/src/Spring/Spring.Data/Transaction/Support/ITransactionOperations.cs +++ b/src/Spring/Spring.Data/Transaction/Support/ITransactionOperations.cs @@ -18,47 +18,46 @@ #endregion -namespace Spring.Transaction.Support +namespace Spring.Transaction.Support; + +/// +/// Interface specifying basic transaction exectuion operations. +/// +/// +/// Implemented by . Not often used directly, +/// but a useful option to enhance testability, as it can easily be mocked or stubbed. +/// +/// Juergen Hoeller +/// Mark Pollac (.NET) +public interface ITransactionOperations { /// - /// Interface specifying basic transaction exectuion operations. + /// Executes the the action specified by the given delegate callback within a transaction. /// - /// - /// Implemented by . Not often used directly, - /// but a useful option to enhance testability, as it can easily be mocked or stubbed. + /// Allows for returning a result object created within the transaction, that is, + /// a domain object or a collection of domain objects. An exception thrown by the callback + /// is treated as a fatal exception that enforces a rollback. Such an exception gets + /// propagated to the caller of the template. /// - /// Juergen Hoeller - /// Mark Pollac (.NET) - public interface ITransactionOperations - { - /// - /// Executes the the action specified by the given delegate callback within a transaction. - /// - /// Allows for returning a result object created within the transaction, that is, - /// a domain object or a collection of domain objects. An exception thrown by the callback - /// is treated as a fatal exception that enforces a rollback. Such an exception gets - /// propagated to the caller of the template. - /// - /// The delegate that specifies the transactional action. - /// A result object returned by the callback, or null if one - /// - /// In case of initialization or system errors. - /// - object Execute(TransactionDelegate transactionMethod); + /// The delegate that specifies the transactional action. + /// A result object returned by the callback, or null if one + /// + /// In case of initialization or system errors. + /// + object Execute(TransactionDelegate transactionMethod); - /// - /// Executes the action specified by the given callback object within a transaction. - /// - /// Allows for returning a result object created within the transaction, that is, - /// a domain object or a collection of domain objects. An exception thrown by the callback - /// is treated as a fatal exception that enforces a rollback. Such an exception gets - /// propagated to the caller of the template. - /// - /// The callback object that specifies the transactional action. - /// A result object returned by the callback, or null if one - /// - /// In case of initialization or system errors. - /// - object Execute(ITransactionCallback action); - } -} \ No newline at end of file + /// + /// Executes the action specified by the given callback object within a transaction. + /// + /// Allows for returning a result object created within the transaction, that is, + /// a domain object or a collection of domain objects. An exception thrown by the callback + /// is treated as a fatal exception that enforces a rollback. Such an exception gets + /// propagated to the caller of the template. + /// + /// The callback object that specifies the transactional action. + /// A result object returned by the callback, or null if one + /// + /// In case of initialization or system errors. + /// + object Execute(ITransactionCallback action); +} diff --git a/src/Spring/Spring.Data/Transaction/Support/ITransactionSynchronization.cs b/src/Spring/Spring.Data/Transaction/Support/ITransactionSynchronization.cs index 9e2c1a3d..0b1398e6 100644 --- a/src/Spring/Spring.Data/Transaction/Support/ITransactionSynchronization.cs +++ b/src/Spring/Spring.Data/Transaction/Support/ITransactionSynchronization.cs @@ -18,110 +18,109 @@ #endregion -namespace Spring.Transaction.Support +namespace Spring.Transaction.Support; + +/// +/// Interface for transaction synchronization callbacks. +/// +/// +/// Supported by . +/// +/// Juergen Hoeller +/// Griffin Caprio (.NET) +/// Mark Pollack (.NET) +public interface ITransactionSynchronization { - /// - /// Interface for transaction synchronization callbacks. - /// - /// - /// Supported by . - /// - /// Juergen Hoeller - /// Griffin Caprio (.NET) - /// Mark Pollack (.NET) - public interface ITransactionSynchronization - { - /// - /// Suspend this synchronization. - /// - /// - ///

- /// Supposed to unbind resources from - /// - /// if managing any. - ///

- ///
- void Suspend(); + /// + /// Suspend this synchronization. + /// + /// + ///

+ /// Supposed to unbind resources from + /// + /// if managing any. + ///

+ ///
+ void Suspend(); - /// - /// Resume this synchronization. - /// - /// - ///

- /// Supposed to rebind resources from - /// - /// if managing any. - ///

- ///
- void Resume(); + /// + /// Resume this synchronization. + /// + /// + ///

+ /// Supposed to rebind resources from + /// + /// if managing any. + ///

+ ///
+ void Resume(); - /// - /// Invoked before transaction commit (before - /// ) - /// Can e.g. flush transactional O/R Mapping sessions to the database - /// - /// - /// - /// This callback does not mean that the transaction will actually be - /// commited. A rollback decision can still occur after this method - /// has been called. This callback is rather meant to perform work - /// that's only relevant if a commit still has a chance - /// to happen, such as flushing SQL statements to the database. - /// - /// - /// Note that exceptions will get propagated to the commit caller and cause a - /// rollback of the transaction. - /// - /// (note: do not throw TransactionException subclasses here!) - /// - /// - /// - /// If the transaction is defined as a read-only transaction. - /// - void BeforeCommit( bool readOnly ); + /// + /// Invoked before transaction commit (before + /// ) + /// Can e.g. flush transactional O/R Mapping sessions to the database + /// + /// + /// + /// This callback does not mean that the transaction will actually be + /// commited. A rollback decision can still occur after this method + /// has been called. This callback is rather meant to perform work + /// that's only relevant if a commit still has a chance + /// to happen, such as flushing SQL statements to the database. + /// + /// + /// Note that exceptions will get propagated to the commit caller and cause a + /// rollback of the transaction. + /// + /// (note: do not throw TransactionException subclasses here!) + /// + /// + /// + /// If the transaction is defined as a read-only transaction. + /// + void BeforeCommit(bool readOnly); - /// - /// Invoked after transaction commit. - /// - /// Can e.g. commit further operations that are supposed to follow on - /// a successful commit of the main transaction. - /// Throws exception in case of errors; will be propagated to the caller. - /// Note: To not throw TransactionExeption sbuclasses here! - /// - /// - void AfterCommit(); - - /// - /// Invoked before transaction commit/rollback (after - /// , - /// even if - /// - /// threw an exception). - /// - /// - ///

- /// Can e.g. perform resource cleanup. - ///

- ///

- /// Note that exceptions will get propagated to the commit caller - /// and cause a rollback of the transaction. - ///

- ///
- void BeforeCompletion(); + /// + /// Invoked after transaction commit. + /// + /// Can e.g. commit further operations that are supposed to follow on + /// a successful commit of the main transaction. + /// Throws exception in case of errors; will be propagated to the caller. + /// Note: To not throw TransactionExeption sbuclasses here! + /// + /// + void AfterCommit(); - /// - /// Invoked after transaction commit/rollback. - /// - /// - /// Status according to - /// - /// - /// Can e.g. perform resource cleanup, in this case after transaction completion. - ///

- /// Note that exceptions will get propagated to the commit or rollback - /// caller, although they will not influence the outcome of the transaction. - ///

- ///
- void AfterCompletion( TransactionSynchronizationStatus status ); - } + /// + /// Invoked before transaction commit/rollback (after + /// , + /// even if + /// + /// threw an exception). + /// + /// + ///

+ /// Can e.g. perform resource cleanup. + ///

+ ///

+ /// Note that exceptions will get propagated to the commit caller + /// and cause a rollback of the transaction. + ///

+ ///
+ void BeforeCompletion(); + + /// + /// Invoked after transaction commit/rollback. + /// + /// + /// Status according to + /// + /// + /// Can e.g. perform resource cleanup, in this case after transaction completion. + ///

+ /// Note that exceptions will get propagated to the commit or rollback + /// caller, although they will not influence the outcome of the transaction. + ///

+ ///
+ void AfterCompletion(TransactionSynchronizationStatus status); } diff --git a/src/Spring/Spring.Data/Transaction/Support/ResourceHolderSupport.cs b/src/Spring/Spring.Data/Transaction/Support/ResourceHolderSupport.cs index 196aa9eb..8ec4aed0 100644 --- a/src/Spring/Spring.Data/Transaction/Support/ResourceHolderSupport.cs +++ b/src/Spring/Spring.Data/Transaction/Support/ResourceHolderSupport.cs @@ -18,179 +18,177 @@ #endregion -namespace Spring.Transaction.Support +namespace Spring.Transaction.Support; + +/// +/// Convenient base class for resource holders. +/// +/// +///

+/// Features rollback-only support transactions. Can expire after a certain number of +/// seconds or milliseconds, to determine transactional timeouts. +///

+///
+/// Juergen Hoeller +/// Griffin Caprio (.NET) +public abstract class ResourceHolderSupport { - /// - /// Convenient base class for resource holders. - /// - /// - ///

- /// Features rollback-only support transactions. Can expire after a certain number of - /// seconds or milliseconds, to determine transactional timeouts. - ///

- ///
- /// Juergen Hoeller - /// Griffin Caprio (.NET) - public abstract class ResourceHolderSupport - { - private bool synchronizedWithTransaction = false; - private bool rollbackOnly = false; - private DateTime deadline; - private int referenceCount = 0; + private bool synchronizedWithTransaction = false; + private bool rollbackOnly = false; + private DateTime deadline; + private int referenceCount = 0; - /// - /// Mark the resource as synchronized with a transaction. - /// - public bool SynchronizedWithTransaction - { - get { return synchronizedWithTransaction; } - set { synchronizedWithTransaction = value; } - } + /// + /// Mark the resource as synchronized with a transaction. + /// + public bool SynchronizedWithTransaction + { + get { return synchronizedWithTransaction; } + set { synchronizedWithTransaction = value; } + } - /// - /// Get or set whether the resource is synchronized with a transaction. - /// - /// true if synchronized; otherwise, false. - public bool RollbackOnly - { - get { return rollbackOnly; } - set { rollbackOnly = value;} - } + /// + /// Get or set whether the resource is synchronized with a transaction. + /// + /// true if synchronized; otherwise, false. + public bool RollbackOnly + { + get { return rollbackOnly; } + set { rollbackOnly = value; } + } - /// - /// Return the expiration deadline of this object. - /// - public DateTime Deadline - { - get { return deadline; } - } + /// + /// Return the expiration deadline of this object. + /// + public DateTime Deadline + { + get { return deadline; } + } - /// - /// Return whether this object has an associated timeout. - /// - public bool HasTimeout - { - get { return ( deadline != DateTime.MinValue ); } - } + /// + /// Return whether this object has an associated timeout. + /// + public bool HasTimeout + { + get { return (deadline != DateTime.MinValue); } + } - /// - /// Return the time to live for this object in seconds. - /// - /// - ///

- /// Rounds up eagerly, e.g. '9.00001' to '10'. - ///

- ///
- /// - /// If no deadline has been set. - /// - public int TimeToLiveInSeconds - { - get - { - int secs = (int)Math.Ceiling( TimeToLiveInMilliseconds / 1000 ); - checkTransactionTimeout(secs <= 0); - return secs; - } - } - - /// - /// Return the time to live for this object in milliseconds. - /// - /// - /// If no deadline has been set. - /// - public double TimeToLiveInMilliseconds - { - get - { - if ( deadline == DateTime.MinValue ) - { - throw new ArgumentException( "No deadline specified for this resource holder."); - } - TimeSpan duration = deadline - DateTime.Now; - checkTransactionTimeout(duration.TotalMilliseconds <= 0); - if (duration.TotalMilliseconds > 0) - { - return duration.TotalMilliseconds; - } - else - { - return 0; - } - } - } - - /// - /// Sets the timeout for this object in milliseconds. - /// - /// Number of milliseconds until expiration. - public long TimeoutInMillis + /// + /// Return the time to live for this object in seconds. + /// + /// + ///

+ /// Rounds up eagerly, e.g. '9.00001' to '10'. + ///

+ ///
+ /// + /// If no deadline has been set. + /// + public int TimeToLiveInSeconds + { + get { - set + int secs = (int) Math.Ceiling(TimeToLiveInMilliseconds / 1000); + checkTransactionTimeout(secs <= 0); + return secs; + } + } + + /// + /// Return the time to live for this object in milliseconds. + /// + /// + /// If no deadline has been set. + /// + public double TimeToLiveInMilliseconds + { + get + { + if (deadline == DateTime.MinValue) { - deadline = DateTime.Now.AddMilliseconds(value); + throw new ArgumentException("No deadline specified for this resource holder."); + } + + TimeSpan duration = deadline - DateTime.Now; + checkTransactionTimeout(duration.TotalMilliseconds <= 0); + if (duration.TotalMilliseconds > 0) + { + return duration.TotalMilliseconds; + } + else + { + return 0; } } + } - /// - /// Sets the timeout for this object in seconds. - /// - /// Number of seconds until expiration. - public int TimeoutInSeconds + /// + /// Sets the timeout for this object in milliseconds. + /// + /// Number of milliseconds until expiration. + public long TimeoutInMillis + { + set { - set - { - TimeoutInMillis = value * 1000; - } + deadline = DateTime.Now.AddMilliseconds(value); } + } - private void checkTransactionTimeout(bool deadlineReached) + /// + /// Sets the timeout for this object in seconds. + /// + /// Number of seconds until expiration. + public int TimeoutInSeconds + { + set { - if (deadlineReached) - { - RollbackOnly = true; - throw new TransactionTimedOutException("Transaction timed out: deadline was " + Deadline); - } + TimeoutInMillis = value * 1000; } + } - - /// - /// Clear the transaction state of this resource holder. - /// - public virtual void Clear() - { - synchronizedWithTransaction = false; - rollbackOnly = false; - deadline = DateTime.MinValue; - } - - /// - /// Increase the reference count by one because the holder has been requested. - /// - public void Requested() + private void checkTransactionTimeout(bool deadlineReached) + { + if (deadlineReached) { - referenceCount++; + RollbackOnly = true; + throw new TransactionTimedOutException("Transaction timed out: deadline was " + Deadline); } + } - /// - /// Decrease the reference count by one because the holder has been released. - /// - public void Released() + /// + /// Clear the transaction state of this resource holder. + /// + public virtual void Clear() + { + synchronizedWithTransaction = false; + rollbackOnly = false; + deadline = DateTime.MinValue; + } + + /// + /// Increase the reference count by one because the holder has been requested. + /// + public void Requested() + { + referenceCount++; + } + + /// + /// Decrease the reference count by one because the holder has been released. + /// + public void Released() + { + referenceCount--; + } + + /// + /// Return wheterh there are still open references to this holder + /// + public bool IsOpen + { + get { - referenceCount--; + return (referenceCount > 0); } - - /// - /// Return wheterh there are still open references to this holder - /// - public bool IsOpen - { - get - { - return (referenceCount > 0); - } - } - - } + } } diff --git a/src/Spring/Spring.Data/Transaction/Support/TransactionCallbackWithoutResult.cs b/src/Spring/Spring.Data/Transaction/Support/TransactionCallbackWithoutResult.cs index 51e21453..70fe01b8 100644 --- a/src/Spring/Spring.Data/Transaction/Support/TransactionCallbackWithoutResult.cs +++ b/src/Spring/Spring.Data/Transaction/Support/TransactionCallbackWithoutResult.cs @@ -18,51 +18,48 @@ #endregion -namespace Spring.Transaction.Support +namespace Spring.Transaction.Support; + +/// +/// Simple convenience class for TransactionCallback implementation. +/// Allows for implementing a DoInTransaction version without result, +/// i.e. without the need for a return statement. +/// +/// Mark Pollack (.NET) +public abstract class TransactionCallbackWithoutResult : ITransactionCallback { - /// - /// Simple convenience class for TransactionCallback implementation. - /// Allows for implementing a DoInTransaction version without result, - /// i.e. without the need for a return statement. - /// - /// Mark Pollack (.NET) - public abstract class TransactionCallbackWithoutResult : ITransactionCallback - { - #region Methods + #region Methods - /// - /// Gets called by TransactionTemplate.execute within a transactional context - /// when no return value is required. - /// - /// The status. - /// - /// Does not need to care about transactions itself, although it can retrieve - /// and influence the status of the current transaction via the given status - /// object, e.g. setting rollback-only. - /// A RuntimeException thrown by the callback is treated as application - /// exception that enforces a rollback. An exception gets propagated to the - /// caller of the template. - /// - public abstract void DoInTransactionWithoutResult(ITransactionStatus status); + /// + /// Gets called by TransactionTemplate.execute within a transactional context + /// when no return value is required. + /// + /// The status. + /// + /// Does not need to care about transactions itself, although it can retrieve + /// and influence the status of the current transaction via the given status + /// object, e.g. setting rollback-only. + /// A RuntimeException thrown by the callback is treated as application + /// exception that enforces a rollback. An exception gets propagated to the + /// caller of the template. + /// + public abstract void DoInTransactionWithoutResult(ITransactionStatus status); - #endregion + #endregion - #region ITransactionCallback Members + #region ITransactionCallback Members - /// - /// Gets called by TransactionTemplate.Execute within a - /// transaction context. - /// - /// The associated transaction status. - /// a result object or null - public object DoInTransaction(ITransactionStatus status) - { - DoInTransactionWithoutResult(status); - return null; - } - - - - #endregion + /// + /// Gets called by TransactionTemplate.Execute within a + /// transaction context. + /// + /// The associated transaction status. + /// a result object or null + public object DoInTransaction(ITransactionStatus status) + { + DoInTransactionWithoutResult(status); + return null; } + + #endregion } diff --git a/src/Spring/Spring.Data/Transaction/Support/TransactionDelegate.cs b/src/Spring/Spring.Data/Transaction/Support/TransactionDelegate.cs index 05307ac9..3f63db28 100644 --- a/src/Spring/Spring.Data/Transaction/Support/TransactionDelegate.cs +++ b/src/Spring/Spring.Data/Transaction/Support/TransactionDelegate.cs @@ -18,25 +18,23 @@ #endregion -namespace Spring.Transaction.Support -{ +namespace Spring.Transaction.Support; - /// - /// Callback delegate for performing actions within a transactional context. - /// - /// - ///

To be used with 's Execute - /// methods. - ///

- ///

- /// Typically used to gather various calls to transaction-unaware low-level - /// services into a higher-level method implementation with transaction - /// demarcation. - ///

- ///
- /// The status of the transaction, can be used to - /// trigger a rollback the current transaction by settings its - /// RollbackOnly property to true. - /// A result object or null. - public delegate object TransactionDelegate(ITransactionStatus status); -} +/// +/// Callback delegate for performing actions within a transactional context. +/// +/// +///

To be used with 's Execute +/// methods. +///

+///

+/// Typically used to gather various calls to transaction-unaware low-level +/// services into a higher-level method implementation with transaction +/// demarcation. +///

+///
+/// The status of the transaction, can be used to +/// trigger a rollback the current transaction by settings its +/// RollbackOnly property to true. +/// A result object or null. +public delegate object TransactionDelegate(ITransactionStatus status); diff --git a/src/Spring/Spring.Data/Transaction/Support/TransactionSynchronizationAdapter.cs b/src/Spring/Spring.Data/Transaction/Support/TransactionSynchronizationAdapter.cs index b78ca318..ed5f4a65 100644 --- a/src/Spring/Spring.Data/Transaction/Support/TransactionSynchronizationAdapter.cs +++ b/src/Spring/Spring.Data/Transaction/Support/TransactionSynchronizationAdapter.cs @@ -18,126 +18,124 @@ #endregion -namespace Spring.Transaction.Support +namespace Spring.Transaction.Support; + +/// +/// Adapter for the +/// interface. +/// +/// +/// Contains empty implementations of all interface methods, for easy overriding of +/// single methods. +/// +/// Juergen Hoeller +/// Griffin Caprio (.NET) +/// Mark Pollack (.NET) +public abstract class TransactionSynchronizationAdapter : ITransactionSynchronization, IComparable { - /// - /// Adapter for the - /// interface. - /// - /// - /// Contains empty implementations of all interface methods, for easy overriding of - /// single methods. - /// - /// Juergen Hoeller - /// Griffin Caprio (.NET) - /// Mark Pollack (.NET) - public abstract class TransactionSynchronizationAdapter : ITransactionSynchronization, IComparable - { + #region ITransactionSynchronization Members + /// + /// Suspend this synchronization. + /// + /// + ///

+ /// Supposed to unbind resources from + /// + /// if managing any. + ///

+ ///
+ public virtual void Suspend() { } - #region ITransactionSynchronization Members - /// - /// Suspend this synchronization. - /// - /// - ///

- /// Supposed to unbind resources from - /// - /// if managing any. - ///

- ///
- public virtual void Suspend() {} + /// + /// Resume this synchronization. + /// + /// + ///

+ /// Supposed to unbind resources from + /// + /// if managing any. + ///

+ ///
+ public virtual void Resume() { } - /// - /// Resume this synchronization. - /// - /// - ///

- /// Supposed to unbind resources from - /// - /// if managing any. - ///

- ///
- public virtual void Resume() {} + /// + /// Invoked before transaction commit (before + /// ) + /// + /// + /// If the transaction is defined as a read-only transaction. + /// + /// + ///

+ /// Can flush transactional sessions to the database. + ///

+ ///

+ /// Note that exceptions will get propagated to the commit caller and + /// cause a rollback of the transaction. + ///

+ ///
+ public virtual void BeforeCommit(bool readOnly) { } - /// - /// Invoked before transaction commit (before - /// ) - /// - /// - /// If the transaction is defined as a read-only transaction. - /// - /// - ///

- /// Can flush transactional sessions to the database. - ///

- ///

- /// Note that exceptions will get propagated to the commit caller and - /// cause a rollback of the transaction. - ///

- ///
- public virtual void BeforeCommit( bool readOnly ) {} + /// + /// Invoked after transaction commit. + /// + /// Can e.g. commit further operations that are supposed to follow on + /// a successful commit of the main transaction. + /// Throws exception in case of errors; will be propagated to the caller. + /// Note: To not throw TransactionExeption sbuclasses here! + /// + public virtual void AfterCommit() + { + } + /// + /// Invoked before transaction commit/rollback (after + /// , + /// even if + /// + /// threw an exception). + /// + /// + ///

+ /// Can e.g. perform resource cleanup. + ///

+ ///

+ /// Note that exceptions will get propagated to the commit caller + /// and cause a rollback of the transaction. + ///

+ ///
+ public virtual void BeforeCompletion() { } - /// - /// Invoked after transaction commit. - /// - /// Can e.g. commit further operations that are supposed to follow on - /// a successful commit of the main transaction. - /// Throws exception in case of errors; will be propagated to the caller. - /// Note: To not throw TransactionExeption sbuclasses here! - /// - public virtual void AfterCommit() - { - } + /// + /// Invoked after transaction commit/rollback. + /// + /// + /// Status according to + /// + /// + /// Can e.g. perform resource cleanup, in this case after transaction completion. + ///

+ /// Note that exceptions will get propagated to the commit or rollback + /// caller, although they will not influence the outcome of the transaction. + ///

+ ///
+ public virtual void AfterCompletion(TransactionSynchronizationStatus status) { } - /// - /// Invoked before transaction commit/rollback (after - /// , - /// even if - /// - /// threw an exception). - /// - /// - ///

- /// Can e.g. perform resource cleanup. - ///

- ///

- /// Note that exceptions will get propagated to the commit caller - /// and cause a rollback of the transaction. - ///

- ///
- public virtual void BeforeCompletion() {} + #endregion - /// - /// Invoked after transaction commit/rollback. - /// - /// - /// Status according to - /// - /// - /// Can e.g. perform resource cleanup, in this case after transaction completion. - ///

- /// Note that exceptions will get propagated to the commit or rollback - /// caller, although they will not influence the outcome of the transaction. - ///

- ///
- public virtual void AfterCompletion( TransactionSynchronizationStatus status ) {} - #endregion - - /// - ///Compares the current instance with another object of the same type. - /// - /// - /// - ///A 32-bit signed integer that indicates the relative order of the objects being compared. The return value has these meanings: Value Meaning Less than zero This instance is less than obj. Zero This instance is equal to obj. Greater than zero This instance is greater than obj. - /// - /// - ///An object to compare with this instance. - ///obj is not the same type as this instance. 2 - public virtual int CompareTo(object obj) - { - return Int32.MinValue; - } - } + /// + ///Compares the current instance with another object of the same type. + /// + /// + /// + ///A 32-bit signed integer that indicates the relative order of the objects being compared. The return value has these meanings: Value Meaning Less than zero This instance is less than obj. Zero This instance is equal to obj. Greater than zero This instance is greater than obj. + /// + /// + ///An object to compare with this instance. + ///obj is not the same type as this instance. 2 + public virtual int CompareTo(object obj) + { + return Int32.MinValue; + } } diff --git a/src/Spring/Spring.Data/Transaction/Support/TransactionSynchronizationManager.cs b/src/Spring/Spring.Data/Transaction/Support/TransactionSynchronizationManager.cs index acf37a65..9d1ac987 100644 --- a/src/Spring/Spring.Data/Transaction/Support/TransactionSynchronizationManager.cs +++ b/src/Spring/Spring.Data/Transaction/Support/TransactionSynchronizationManager.cs @@ -25,466 +25,479 @@ using Spring.Core; using Spring.Threading; using Spring.Util; -namespace Spring.Transaction.Support +namespace Spring.Transaction.Support; + +/// +/// Internal class that manages resources and transaction synchronizations per thread. +/// +/// +/// Supports one resource per key without overwriting, i.e. a resource needs to +/// be removed before a new one can be set for the same key. +/// Supports a list of transaction synchronizations if synchronization is active. +///

+/// Resource management code should check for thread-bound resources via GetResource(). +/// It is normally not supposed +/// to bind resources to threads, as this is the responsiblity of transaction managers. +/// A further option is to lazily bind on first use if transaction synchronization +/// is active, for performing transactions that span an arbitrary number of resources. +///

+///

+/// Transaction synchronization must be activated and deactivated by a transaction +/// manager via +/// InitSynchronization +/// and +/// ClearSynchronization. +/// This is automatically supported by +/// . +///

+///

+/// Resource management code should only register synchronizations when this +/// manager is active, and perform resource cleanup immediately else. +/// If transaction synchronization isn't active, there is either no current +/// transaction, or the transaction manager doesn't support synchronizations. +///

+/// Note that this class uses following naming convention for the +/// named 'data slots' for storage of thread local data, 'Spring.Transaction:Name' +/// where Name is either +///
+/// Juergen Hoeller +/// Griffin Caprio (.NET) +/// Mark Pollack (.NET) +public sealed class TransactionSynchronizationManager { - /// - /// Internal class that manages resources and transaction synchronizations per thread. - /// - /// - /// Supports one resource per key without overwriting, i.e. a resource needs to - /// be removed before a new one can be set for the same key. - /// Supports a list of transaction synchronizations if synchronization is active. - ///

- /// Resource management code should check for thread-bound resources via GetResource(). - /// It is normally not supposed - /// to bind resources to threads, as this is the responsiblity of transaction managers. - /// A further option is to lazily bind on first use if transaction synchronization - /// is active, for performing transactions that span an arbitrary number of resources. - ///

- ///

- /// Transaction synchronization must be activated and deactivated by a transaction - /// manager via - /// InitSynchronization - /// and - /// ClearSynchronization. - /// This is automatically supported by - /// . - ///

- ///

- /// Resource management code should only register synchronizations when this - /// manager is active, and perform resource cleanup immediately else. - /// If transaction synchronization isn't active, there is either no current - /// transaction, or the transaction manager doesn't support synchronizations. - ///

- /// Note that this class uses following naming convention for the - /// named 'data slots' for storage of thread local data, 'Spring.Transaction:Name' - /// where Name is either - ///
- /// Juergen Hoeller - /// Griffin Caprio (.NET) - /// Mark Pollack (.NET) - public sealed class TransactionSynchronizationManager - { - #region Logging + #region Logging - private static readonly ILogger LOG = LogManager.GetLogger(typeof (TransactionSynchronizationManager)); + private static readonly ILogger LOG = LogManager.GetLogger(typeof(TransactionSynchronizationManager)); - #endregion + #endregion - #region Fields - private static readonly string syncsDataSlotName = "Spring.Transactions:syncList"; + #region Fields - private static readonly string resourcesDataSlotName = "Spring.Transactions:resources"; + private static readonly string syncsDataSlotName = "Spring.Transactions:syncList"; - private static readonly string currentTxReadOnlyDataSlotName = "Spring.Transactions:currentTxReadOnly"; + private static readonly string resourcesDataSlotName = "Spring.Transactions:resources"; - private static readonly string currentTxNameDataSlotName = "Spring.Transactions:currentTxName"; + private static readonly string currentTxReadOnlyDataSlotName = "Spring.Transactions:currentTxReadOnly"; - private static readonly string currentTxIsolationLevelDataSlotName = "Spring.Transactions:currentTxIsolationLevel"; + private static readonly string currentTxNameDataSlotName = "Spring.Transactions:currentTxName"; - private static readonly string actualTxActiveDataSlotName = "Spring.Transactions:actualTxActive"; + private static readonly string currentTxIsolationLevelDataSlotName = "Spring.Transactions:currentTxIsolationLevel"; - private static IComparer syncComparer = new OrderComparator(); + private static readonly string actualTxActiveDataSlotName = "Spring.Transactions:actualTxActive"; - #endregion + private static IComparer syncComparer = new OrderComparator(); - #region Management of transaction-associated resource handles - /// - /// Return all resources that are bound to the current thread. - /// - /// Main for debugging purposes. Resource manager should always - /// invoke HasResource for a specific resource key that they are interested in. - /// - /// IDictionary with resource keys and resource objects or empty - /// dictionary if none is bound. - public static IDictionary ResourceDictionary + #endregion + + #region Management of transaction-associated resource handles + + /// + /// Return all resources that are bound to the current thread. + /// + /// Main for debugging purposes. Resource manager should always + /// invoke HasResource for a specific resource key that they are interested in. + /// + /// IDictionary with resource keys and resource objects or empty + /// dictionary if none is bound. + public static IDictionary ResourceDictionary + { + get { - get - { - IDictionary resources = LogicalThreadContext.GetData(resourcesDataSlotName) as IDictionary; - if (resources != null) - { - //TODO add readonly wrapper in Spring.Collections. - return resources; - } - else - { - return new Hashtable(); - } - } - } - - /// - /// Check if there is a resource for the given key bound to the current thread. - /// - /// key to check - /// if there is a value bound to the current thread - public static bool HasResource(Object key) - { - AssertUtils.ArgumentNotNull(key, "Key must not be null"); - return ResourceDictionary.Contains(key); - } - - /// - /// Retrieve a resource for the given key that is bound to the current thread. - /// - /// key to check - /// a value bound to the current thread, or null if none. - public static object GetResource(Object key) - { - AssertUtils.ArgumentNotNull(key, "Key must not be null"); IDictionary resources = LogicalThreadContext.GetData(resourcesDataSlotName) as IDictionary; - if (resources == null) + if (resources != null) { - return null; + //TODO add readonly wrapper in Spring.Collections. + return resources; } - //Check for contains since indexer returning null behavior changes in 2.0 - if (!resources.Contains(key)) + else { - return null; + return new Hashtable(); } - object val = resources[key]; - - if (val != null && LOG.IsEnabled(LogLevel.Debug)) - { - LOG.LogDebug("Retrieved value [" + Describe(val) + "] for key [" + Describe(key) + "] bound to thread [" + - SystemUtils.ThreadId + "]"); - } - return val; } + } - /// - /// Bind the given resource for teh given key to the current thread - /// - /// key to bind the value to - /// value to bind - public static void BindResource(Object key, Object value) + /// + /// Check if there is a resource for the given key bound to the current thread. + /// + /// key to check + /// if there is a value bound to the current thread + public static bool HasResource(Object key) + { + AssertUtils.ArgumentNotNull(key, "Key must not be null"); + return ResourceDictionary.Contains(key); + } + + /// + /// Retrieve a resource for the given key that is bound to the current thread. + /// + /// key to check + /// a value bound to the current thread, or null if none. + public static object GetResource(Object key) + { + AssertUtils.ArgumentNotNull(key, "Key must not be null"); + IDictionary resources = LogicalThreadContext.GetData(resourcesDataSlotName) as IDictionary; + if (resources == null) { - AssertUtils.ArgumentNotNull(key, "Key value for thread local storage of transactional resources must not be null"); - AssertUtils.ArgumentNotNull(value, "Transactional resource to bind to thread local storage must not be null" ); - - IDictionary resources = LogicalThreadContext.GetData(resourcesDataSlotName) as IDictionary; - //Set thread local resource storage if not found - if (resources == null) - { - resources = new Hashtable(); - LogicalThreadContext.SetData(resourcesDataSlotName, resources); - } - if (resources.Contains(key)) - { - throw new InvalidOperationException("Already value [" + resources[key] + "] for key [" + key + - "] bound to thread [" + SystemUtils.ThreadId + "]"); - } - resources.Add(key, value); - if (LOG.IsEnabled(LogLevel.Debug)) - { - LOG.LogDebug("Bound value [" + Describe(value) + "] for key [" + Describe(key) + "] to thread [" + - SystemUtils.ThreadId + "]"); - } + return null; } - - /// - /// Unbind a resource for the given key from the current thread - /// - /// key to check - /// the previously bound value - /// if there is no value bound to the thread - public static object UnbindResource(Object key) + //Check for contains since indexer returning null behavior changes in 2.0 + if (!resources.Contains(key)) { - AssertUtils.ArgumentNotNull(key, "Key must not be null"); - - IDictionary resources = LogicalThreadContext.GetData(resourcesDataSlotName) as IDictionary; - if (resources == null || !resources.Contains(key)) - { - throw new InvalidOperationException("No value for key [" + key + "] bound to thread [" + - SystemUtils.ThreadId + "]"); - } - Object val = resources[key]; - resources.Remove(key); - if (resources.Count == 0) - { - LogicalThreadContext.FreeNamedDataSlot(resourcesDataSlotName); - } - if (LOG.IsEnabled(LogLevel.Debug)) - { - LOG.LogDebug("Removed value [" + Describe(val) + "] for key [" + Describe(key) + "] from thread [" + - SystemUtils.ThreadId + "]"); - } - return val; + return null; } - #endregion + object val = resources[key]; - /// - /// Activate transaction synchronization for the current thread. - /// - /// - /// Called by transaction manager at the beginning of a transaction. - /// - /// - /// If synchronization is already active. - /// - public static void InitSynchronization() - { - if ( SynchronizationActive ) - { - throw new InvalidOperationException( "Cannot activate transaction synchronization - already active" ); - } - if (LOG.IsEnabled(LogLevel.Debug)) - { - LOG.LogDebug("Initializing transaction synchronization"); - } - ArrayList syncs = new ArrayList(); - LogicalThreadContext.SetData(syncsDataSlotName, syncs); - } - - /// - /// Deactivate transaction synchronization for the current thread. - /// - /// - /// Called by transaction manager on transaction cleanup. - /// - /// - /// If synchronization is not active. - /// - public static void ClearSynchronization() - { - if ( !SynchronizationActive ) - { - throw new InvalidOperationException( "Cannot deactivate transaction synchronization - not active" ); - } - if (LOG.IsEnabled(LogLevel.Debug)) - { - LOG.LogDebug("Clearing transaction synchronization"); - } - LogicalThreadContext.FreeNamedDataSlot(syncsDataSlotName); - } - - /// - /// Clears the entire transaction synchronization state for the current thread, registered - /// synchronizations as well as the various transaction characteristics. - /// - public static void Clear() + if (val != null && LOG.IsEnabled(LogLevel.Debug)) { - ClearSynchronization(); - CurrentTransactionName = null; - CurrentTransactionReadOnly = false; - CurrentTransactionIsolationLevel = IsolationLevel.Unspecified; - ActualTransactionActive = false; + LOG.LogDebug("Retrieved value [" + Describe(val) + "] for key [" + Describe(key) + "] bound to thread [" + + SystemUtils.ThreadId + "]"); } - /// - /// Register a new transaction synchronization for the current thread. - /// - /// - /// Typically called by resource management code. - /// - /// - /// If synchronization is not active. - /// - public static void RegisterSynchronization( ITransactionSynchronization synchronization ) - { - AssertUtils.ArgumentNotNull(synchronization, "TransactionSynchronization must not be null"); - if ( !SynchronizationActive ) - { - throw new InvalidOperationException( "Transaction synchronization is not active" ); - } + return val; + } + + /// + /// Bind the given resource for teh given key to the current thread + /// + /// key to bind the value to + /// value to bind + public static void BindResource(Object key, Object value) + { + AssertUtils.ArgumentNotNull(key, "Key value for thread local storage of transactional resources must not be null"); + AssertUtils.ArgumentNotNull(value, "Transactional resource to bind to thread local storage must not be null"); + + IDictionary resources = LogicalThreadContext.GetData(resourcesDataSlotName) as IDictionary; + //Set thread local resource storage if not found + if (resources == null) + { + resources = new Hashtable(); + LogicalThreadContext.SetData(resourcesDataSlotName, resources); + } + + if (resources.Contains(key)) + { + throw new InvalidOperationException("Already value [" + resources[key] + "] for key [" + key + + "] bound to thread [" + SystemUtils.ThreadId + "]"); + } + + resources.Add(key, value); + if (LOG.IsEnabled(LogLevel.Debug)) + { + LOG.LogDebug("Bound value [" + Describe(value) + "] for key [" + Describe(key) + "] to thread [" + + SystemUtils.ThreadId + "]"); + } + } + + /// + /// Unbind a resource for the given key from the current thread + /// + /// key to check + /// the previously bound value + /// if there is no value bound to the thread + public static object UnbindResource(Object key) + { + AssertUtils.ArgumentNotNull(key, "Key must not be null"); + + IDictionary resources = LogicalThreadContext.GetData(resourcesDataSlotName) as IDictionary; + if (resources == null || !resources.Contains(key)) + { + throw new InvalidOperationException("No value for key [" + key + "] bound to thread [" + + SystemUtils.ThreadId + "]"); + } + + Object val = resources[key]; + resources.Remove(key); + if (resources.Count == 0) + { + LogicalThreadContext.FreeNamedDataSlot(resourcesDataSlotName); + } + + if (LOG.IsEnabled(LogLevel.Debug)) + { + LOG.LogDebug("Removed value [" + Describe(val) + "] for key [" + Describe(key) + "] from thread [" + + SystemUtils.ThreadId + "]"); + } + + return val; + } + + #endregion + + /// + /// Activate transaction synchronization for the current thread. + /// + /// + /// Called by transaction manager at the beginning of a transaction. + /// + /// + /// If synchronization is already active. + /// + public static void InitSynchronization() + { + if (SynchronizationActive) + { + throw new InvalidOperationException("Cannot activate transaction synchronization - already active"); + } + + if (LOG.IsEnabled(LogLevel.Debug)) + { + LOG.LogDebug("Initializing transaction synchronization"); + } + + ArrayList syncs = new ArrayList(); + LogicalThreadContext.SetData(syncsDataSlotName, syncs); + } + + /// + /// Deactivate transaction synchronization for the current thread. + /// + /// + /// Called by transaction manager on transaction cleanup. + /// + /// + /// If synchronization is not active. + /// + public static void ClearSynchronization() + { + if (!SynchronizationActive) + { + throw new InvalidOperationException("Cannot deactivate transaction synchronization - not active"); + } + + if (LOG.IsEnabled(LogLevel.Debug)) + { + LOG.LogDebug("Clearing transaction synchronization"); + } + + LogicalThreadContext.FreeNamedDataSlot(syncsDataSlotName); + } + + /// + /// Clears the entire transaction synchronization state for the current thread, registered + /// synchronizations as well as the various transaction characteristics. + /// + public static void Clear() + { + ClearSynchronization(); + CurrentTransactionName = null; + CurrentTransactionReadOnly = false; + CurrentTransactionIsolationLevel = IsolationLevel.Unspecified; + ActualTransactionActive = false; + } + + /// + /// Register a new transaction synchronization for the current thread. + /// + /// + /// Typically called by resource management code. + /// + /// + /// If synchronization is not active. + /// + public static void RegisterSynchronization(ITransactionSynchronization synchronization) + { + AssertUtils.ArgumentNotNull(synchronization, "TransactionSynchronization must not be null"); + if (!SynchronizationActive) + { + throw new InvalidOperationException("Transaction synchronization is not active"); + } + + ArrayList syncs = LogicalThreadContext.GetData(syncsDataSlotName) as ArrayList; + if (syncs != null) + { + object root = syncs.SyncRoot; + lock (root) + { + syncs.Add(synchronization); + } + } + } + + private static string Describe(object obj) + { + return obj == null ? "" : obj + "@" + obj.GetHashCode().ToString("X"); + } + + #region Properties + + /// + /// Return an unmodifiable list of all registered synchronizations + /// for the current thread. + /// + /// + /// A list of + /// instances. + /// + /// + /// If synchronization is not active. + /// + public static IList Synchronizations + { + get + { + if (!SynchronizationActive) + { + throw new InvalidOperationException("Transaction synchronization is not active"); + } + ArrayList syncs = LogicalThreadContext.GetData(syncsDataSlotName) as ArrayList; if (syncs != null) { + // Sort lazily here, not in registerSynchronization. object root = syncs.SyncRoot; lock (root) { - syncs.Add(synchronization); + // #SPRNET-1160, tx Ben Rowlands + CollectionUtils.StableSortInPlace(syncs, syncComparer); } + + // Return unmodifiable snapshot, to avoid exceptions + // while iterating and invoking synchronization callbacks that in turn + // might register further synchronizations. + return ArrayList.ReadOnly(syncs); + } + else + { + return ArrayList.ReadOnly(new ArrayList()); } } - - private static string Describe(object obj) - { - return obj == null ? "" : obj + "@" + obj.GetHashCode().ToString("X"); - } - - #region Properties - - /// - /// Return an unmodifiable list of all registered synchronizations - /// for the current thread. - /// - /// - /// A list of - /// instances. - /// - /// - /// If synchronization is not active. - /// - public static IList Synchronizations - { - get - { - if (!SynchronizationActive) - { - throw new InvalidOperationException("Transaction synchronization is not active"); - } - ArrayList syncs = LogicalThreadContext.GetData(syncsDataSlotName) as ArrayList; - if (syncs != null) - { - // Sort lazily here, not in registerSynchronization. - object root = syncs.SyncRoot; - lock (root) - { - // #SPRNET-1160, tx Ben Rowlands - CollectionUtils.StableSortInPlace(syncs, syncComparer); - } - - // Return unmodifiable snapshot, to avoid exceptions - // while iterating and invoking synchronization callbacks that in turn - // might register further synchronizations. - return ArrayList.ReadOnly(syncs); - } - else - { - return ArrayList.ReadOnly(new ArrayList()); - } - } - } - - /// - /// Return if transaction synchronization is active for the current thread. - /// - /// - /// Can be called before - /// InitSynchronization - /// to avoid unnecessary instance creation. - /// - public static bool SynchronizationActive - { - get - { - IList syncs = LogicalThreadContext.GetData(syncsDataSlotName) as IList; - return syncs != null; - } - } - - /// - /// Gets or sets a value indicating whether the - /// current transaction is read only. - /// - /// - /// Called by transaction manager on transaction begin and on cleanup. - /// Return whether the current transaction is marked as read-only. - /// To be called by resource management code when preparing a newly - /// created resource (for example, a Hibernate Session). - ///

Note that transaction synchronizations receive the read-only flag - /// as argument for the beforeCommit callback, to be able - /// to suppress change detection on commit. The present method is meant - /// to be used for earlier read-only checks, for example to set the - /// flush mode of a Hibernate Session to FlushMode.Never upfront. - ///

- ///
- /// - /// true if current transaction read only; otherwise, false. - /// - public static bool CurrentTransactionReadOnly - { - get - { - return LogicalThreadContext.GetData(currentTxReadOnlyDataSlotName) != null; - } - set - { - if (value) - { - LogicalThreadContext.SetData(currentTxReadOnlyDataSlotName, true); - } - else - { - LogicalThreadContext.FreeNamedDataSlot(currentTxReadOnlyDataSlotName); - } - - } - } - - /// - /// Gets or sets the name of the current transaction, if any. - /// - /// Called by the transaction manager on transaction begin and on cleanup. - /// To be called by resource management code for optimizations per use case, for - /// example to optimize fetch strategies for specific named transactions. - /// The name of the current transactio or null if none set. - public static string CurrentTransactionName - { - get - { - return LogicalThreadContext.GetData(currentTxNameDataSlotName) as string; - } - set - { - LogicalThreadContext.SetData(currentTxNameDataSlotName, value); - } - } - - /// - /// Gets or sets a value indicating whether there currently is an actual transaction - /// active. - /// - /// This indicates wheter the current thread is associated with an actual - /// transaction rather than just with active transaction synchronization. - /// Called by the transaction manager on transaction begin and on cleanup. - /// To be called by resource management code that wants to discriminate between - /// active transaction synchronization (with or without backing resource transaction; - /// also on PROPAGATION_SUPPORTS) and an actual transaction being active; on - /// PROPAGATION_REQUIRES, PROPAGATION_REQUIRES_NEW, etC) - /// - /// true if [actual transaction active]; otherwise, false. - /// - public static bool ActualTransactionActive - { - get - { - return LogicalThreadContext.GetData(actualTxActiveDataSlotName) != null; - } - set - { - if (value) - { - LogicalThreadContext.SetData(actualTxActiveDataSlotName, value); - } - else - { - LogicalThreadContext.FreeNamedDataSlot(actualTxActiveDataSlotName); - } - } - } - - - /// - /// Gets or sets the current transaction isolation level, if any. - /// - /// Called by the transaction manager on transaction begin and on cleanup. - /// The current transaction isolation level. If no current transaction is - /// active, retrun IsolationLevel.Unspecified - public static IsolationLevel CurrentTransactionIsolationLevel - { - get - { - object data = - LogicalThreadContext.GetData(currentTxIsolationLevelDataSlotName); - if (data != null) - { - return (IsolationLevel) data; - } - else - { - return IsolationLevel.Unspecified; - } - } - set - { - LogicalThreadContext.SetData(currentTxIsolationLevelDataSlotName, value); - } - } - #endregion } + + /// + /// Return if transaction synchronization is active for the current thread. + /// + /// + /// Can be called before + /// InitSynchronization + /// to avoid unnecessary instance creation. + /// + public static bool SynchronizationActive + { + get + { + IList syncs = LogicalThreadContext.GetData(syncsDataSlotName) as IList; + return syncs != null; + } + } + + /// + /// Gets or sets a value indicating whether the + /// current transaction is read only. + /// + /// + /// Called by transaction manager on transaction begin and on cleanup. + /// Return whether the current transaction is marked as read-only. + /// To be called by resource management code when preparing a newly + /// created resource (for example, a Hibernate Session). + ///

Note that transaction synchronizations receive the read-only flag + /// as argument for the beforeCommit callback, to be able + /// to suppress change detection on commit. The present method is meant + /// to be used for earlier read-only checks, for example to set the + /// flush mode of a Hibernate Session to FlushMode.Never upfront. + ///

+ ///
+ /// + /// true if current transaction read only; otherwise, false. + /// + public static bool CurrentTransactionReadOnly + { + get + { + return LogicalThreadContext.GetData(currentTxReadOnlyDataSlotName) != null; + } + set + { + if (value) + { + LogicalThreadContext.SetData(currentTxReadOnlyDataSlotName, true); + } + else + { + LogicalThreadContext.FreeNamedDataSlot(currentTxReadOnlyDataSlotName); + } + } + } + + /// + /// Gets or sets the name of the current transaction, if any. + /// + /// Called by the transaction manager on transaction begin and on cleanup. + /// To be called by resource management code for optimizations per use case, for + /// example to optimize fetch strategies for specific named transactions. + /// The name of the current transactio or null if none set. + public static string CurrentTransactionName + { + get + { + return LogicalThreadContext.GetData(currentTxNameDataSlotName) as string; + } + set + { + LogicalThreadContext.SetData(currentTxNameDataSlotName, value); + } + } + + /// + /// Gets or sets a value indicating whether there currently is an actual transaction + /// active. + /// + /// This indicates wheter the current thread is associated with an actual + /// transaction rather than just with active transaction synchronization. + /// Called by the transaction manager on transaction begin and on cleanup. + /// To be called by resource management code that wants to discriminate between + /// active transaction synchronization (with or without backing resource transaction; + /// also on PROPAGATION_SUPPORTS) and an actual transaction being active; on + /// PROPAGATION_REQUIRES, PROPAGATION_REQUIRES_NEW, etC) + /// + /// true if [actual transaction active]; otherwise, false. + /// + public static bool ActualTransactionActive + { + get + { + return LogicalThreadContext.GetData(actualTxActiveDataSlotName) != null; + } + set + { + if (value) + { + LogicalThreadContext.SetData(actualTxActiveDataSlotName, value); + } + else + { + LogicalThreadContext.FreeNamedDataSlot(actualTxActiveDataSlotName); + } + } + } + + /// + /// Gets or sets the current transaction isolation level, if any. + /// + /// Called by the transaction manager on transaction begin and on cleanup. + /// The current transaction isolation level. If no current transaction is + /// active, retrun IsolationLevel.Unspecified + public static IsolationLevel CurrentTransactionIsolationLevel + { + get + { + object data = + LogicalThreadContext.GetData(currentTxIsolationLevelDataSlotName); + if (data != null) + { + return (IsolationLevel) data; + } + else + { + return IsolationLevel.Unspecified; + } + } + set + { + LogicalThreadContext.SetData(currentTxIsolationLevelDataSlotName, value); + } + } + + #endregion } diff --git a/src/Spring/Spring.Data/Transaction/Support/TransactionSynchronizationState.cs b/src/Spring/Spring.Data/Transaction/Support/TransactionSynchronizationState.cs index 4bc1f35c..7d851201 100644 --- a/src/Spring/Spring.Data/Transaction/Support/TransactionSynchronizationState.cs +++ b/src/Spring/Spring.Data/Transaction/Support/TransactionSynchronizationState.cs @@ -18,30 +18,31 @@ #endregion -namespace Spring.Transaction.Support +namespace Spring.Transaction.Support; + +/// +/// Enumeration containing the state of transaction synchronization. +/// +/// Griffin Caprio (.NET) +public enum TransactionSynchronizationState { - /// - /// Enumeration containing the state of transaction synchronization. + /// + /// Always activate transaction synchronization, even for "empty" transactions + /// that result from . /// - /// Griffin Caprio (.NET) - public enum TransactionSynchronizationState - { - /// - /// Always activate transaction synchronization, even for "empty" transactions - /// that result from . - /// - /// with no existing backend transaction. - Always, - /// - /// Activate transaction synchronization only for actual transactions, - /// i.e. not for empty ones that result from . - /// - /// with no - /// existing backend transaction. - OnActualTransaction, - /// - /// Never active transaction synchronization. - /// - Never - } + /// with no existing backend transaction. + Always, + + /// + /// Activate transaction synchronization only for actual transactions, + /// i.e. not for empty ones that result from . + /// + /// with no + /// existing backend transaction. + OnActualTransaction, + + /// + /// Never active transaction synchronization. + /// + Never } diff --git a/src/Spring/Spring.Data/Transaction/Support/TransactionSynchronizationStatus.cs b/src/Spring/Spring.Data/Transaction/Support/TransactionSynchronizationStatus.cs index ccf8ca08..19180546 100644 --- a/src/Spring/Spring.Data/Transaction/Support/TransactionSynchronizationStatus.cs +++ b/src/Spring/Spring.Data/Transaction/Support/TransactionSynchronizationStatus.cs @@ -18,25 +18,26 @@ #endregion -namespace Spring.Transaction.Support +namespace Spring.Transaction.Support; + +/// +/// Enumeration of status values when synchronizing transactions. +/// +/// Griffin Caprio +public enum TransactionSynchronizationStatus { - /// - /// Enumeration of status values when synchronizing transactions. - /// - /// Griffin Caprio - public enum TransactionSynchronizationStatus - { - /// - /// Completion status in case of proper commit. - /// - Committed, - /// - /// Completion status in case of proper rollback. - /// - Rolledback, - /// - /// Completion status in case of heuristic mixed completion or system error. - /// - Unknown, - } + /// + /// Completion status in case of proper commit. + /// + Committed, + + /// + /// Completion status in case of proper rollback. + /// + Rolledback, + + /// + /// Completion status in case of heuristic mixed completion or system error. + /// + Unknown, } diff --git a/src/Spring/Spring.Data/Transaction/Support/TransactionTemplate.cs b/src/Spring/Spring.Data/Transaction/Support/TransactionTemplate.cs index 555a800d..70a7df0b 100644 --- a/src/Spring/Spring.Data/Transaction/Support/TransactionTemplate.cs +++ b/src/Spring/Spring.Data/Transaction/Support/TransactionTemplate.cs @@ -21,196 +21,199 @@ using Microsoft.Extensions.Logging; using Spring.Objects.Factory; -namespace Spring.Transaction.Support +namespace Spring.Transaction.Support; + +/// +/// Helper class that simplifies programmatic transaction demarcation and +/// transaction exception handling. +/// +/// +///

+/// The central methods are +/// +/// and +/// supporting transactional code wrapped in the delegate instance. It handles the +/// transaction lifecycle and possible exceptions such that neither the delegate +/// implementation nor the calling code needs to explicitly handle transactions. +///

+///

+/// Can be used within a service implementation via direct instantiation with +/// a transaction manager reference, or get prepared in an application context +/// and given to services as object reference. +///

+/// +/// The transaction manager should always be configured as an object in the application +/// context, in the first case given to the service directly, in the second case to the +/// prepared template. +/// +///

+/// Supports setting the propagation behavior and the isolation level by name, +/// for convenient configuration in context definitions. +///

+///
+/// Juergen Hoeller +/// Mark Pollack (.NET) +/// Griffin Caprio (.NET) +public class TransactionTemplate : DefaultTransactionDefinition, ITransactionOperations, IInitializingObject { + private IPlatformTransactionManager _platformTransactionManager; + + #region Logging Definition + + protected readonly ILogger log = LogManager.GetLogger(); + + #endregion + /// - /// Helper class that simplifies programmatic transaction demarcation and - /// transaction exception handling. + /// Creates a new instance of the + /// class. /// /// ///

- /// The central methods are - /// - /// and - /// supporting transactional code wrapped in the delegate instance. It handles the - /// transaction lifecycle and possible exceptions such that neither the delegate - /// implementation nor the calling code needs to explicitly handle transactions. - ///

- ///

- /// Can be used within a service implementation via direct instantiation with - /// a transaction manager reference, or get prepared in an application context - /// and given to services as object reference. + /// Mainly targeted at configuration by an object factory. ///

/// - /// The transaction manager should always be configured as an object in the application - /// context, in the first case given to the service directly, in the second case to the - /// prepared template. + /// The + /// + /// property must be set before any calls to the + /// + /// or + /// method. /// + ///
+ /// + public TransactionTemplate() { } + + /// + /// Creates a new instance of the + /// class. + /// + /// ///

- /// Supports setting the propagation behavior and the isolation level by name, - /// for convenient configuration in context definitions. + /// Mainly targeted at configuration by an object factory. ///

///
- /// Juergen Hoeller - /// Mark Pollack (.NET) - /// Griffin Caprio (.NET) - public class TransactionTemplate : DefaultTransactionDefinition, ITransactionOperations, IInitializingObject + /// + /// The transaction management strategy to be used. + /// + public TransactionTemplate(IPlatformTransactionManager platformTransactionManager) { - private IPlatformTransactionManager _platformTransactionManager; + _platformTransactionManager = platformTransactionManager; + } - #region Logging Definition + /// + /// Gets and sets the to + /// be used. + /// + public IPlatformTransactionManager PlatformTransactionManager + { + get { return _platformTransactionManager; } + set { _platformTransactionManager = value; } + } - protected readonly ILogger log = LogManager.GetLogger(); + #region IInitializingObject Members - #endregion - /// - /// Creates a new instance of the - /// class. - /// - /// - ///

- /// Mainly targeted at configuration by an object factory. - ///

- /// - /// The - /// - /// property must be set before any calls to the - /// - /// or - /// method. - /// - ///
- /// - public TransactionTemplate() {} - - /// - /// Creates a new instance of the - /// class. - /// - /// - ///

- /// Mainly targeted at configuration by an object factory. - ///

- ///
- /// - /// The transaction management strategy to be used. - /// - public TransactionTemplate( IPlatformTransactionManager platformTransactionManager ) + /// + /// Ensures that the + /// + /// has been set. + /// + public void AfterPropertiesSet() + { + if (_platformTransactionManager == null) { - _platformTransactionManager = platformTransactionManager; + throw new ArgumentException("IPlatformTransactionManager instance is required."); + } + } + + #endregion + + /// + /// Executes the the action specified by the given delegate callback within a transaction. + /// + /// The delegate that specifies the transactional action. + /// + /// A result object returned by the callback, or null if one + /// + /// Allows for returning a result object created within the transaction, that is, + /// a domain object or a collection of domain objects. An exception thrown by the callback + /// is treated as a fatal exception that enforces a rollback. Such an exception gets + /// propagated to the caller of the template. + /// + /// + /// In case of initialization or system errors. + /// + public object Execute(TransactionDelegate transactionMethod) + { + ITransactionStatus status = _platformTransactionManager.GetTransaction(this); + object result; + try + { + result = transactionMethod(status); + } + catch (Exception ex) + { + rollbackOnException(status, ex); + throw; } - /// - /// Gets and sets the to - /// be used. - /// - public IPlatformTransactionManager PlatformTransactionManager + _platformTransactionManager.Commit(status); + return result; + } + + /// + /// Executes the action specified by the given callback object within a transaction. + /// + /// The callback object that specifies the transactional action. + /// + /// A result object returned by the callback, or null if one + /// + /// Allows for returning a result object created within the transaction, that is, + /// a domain object or a collection of domain objects. An exception thrown by the callback + /// is treated as a fatal exception that enforces a rollback. Such an exception gets + /// propagated to the caller of the template. + /// + /// + /// In case of initialization or system errors. + /// + public object Execute(ITransactionCallback action) + { + ITransactionStatus status = _platformTransactionManager.GetTransaction(this); + object result; + try { - get { return _platformTransactionManager; } - set { _platformTransactionManager = value; } + result = action.DoInTransaction(status); + } + catch (Exception ex) + { + rollbackOnException(status, ex); + throw; } - #region IInitializingObject Members - /// - /// Ensures that the - /// - /// has been set. - /// - public void AfterPropertiesSet() - { - if ( _platformTransactionManager == null ) - { - throw new ArgumentException( "IPlatformTransactionManager instance is required." ); - } - } - #endregion + _platformTransactionManager.Commit(status); + return result; + } - - /// - /// Executes the the action specified by the given delegate callback within a transaction. - /// - /// The delegate that specifies the transactional action. - /// - /// A result object returned by the callback, or null if one - /// - /// Allows for returning a result object created within the transaction, that is, - /// a domain object or a collection of domain objects. An exception thrown by the callback - /// is treated as a fatal exception that enforces a rollback. Such an exception gets - /// propagated to the caller of the template. - /// - /// - /// In case of initialization or system errors. - /// - public object Execute( TransactionDelegate transactionMethod ) + /// + /// Perform a rollback, handling rollback exceptions properly. + /// + /// The object representing the transaction. + /// The thrown application exception or error. + private void rollbackOnException(ITransactionStatus status, Exception exception) + { + if (log.IsEnabled(LogLevel.Debug)) { - ITransactionStatus status = _platformTransactionManager.GetTransaction( this ); - object result; - try - { - result = transactionMethod( status ); - } - catch ( Exception ex ) - { - rollbackOnException( status, ex ); - throw; - } - _platformTransactionManager.Commit( status ); - return result; + log.LogDebug(exception, "Initiating transaction rollback on application exception"); } - - /// - /// Executes the action specified by the given callback object within a transaction. - /// - /// The callback object that specifies the transactional action. - /// - /// A result object returned by the callback, or null if one - /// - /// Allows for returning a result object created within the transaction, that is, - /// a domain object or a collection of domain objects. An exception thrown by the callback - /// is treated as a fatal exception that enforces a rollback. Such an exception gets - /// propagated to the caller of the template. - /// - /// - /// In case of initialization or system errors. - /// - public object Execute(ITransactionCallback action) + try { - ITransactionStatus status = _platformTransactionManager.GetTransaction( this ); - object result; - try - { - result = action.DoInTransaction(status); - } - catch ( Exception ex ) - { - rollbackOnException( status, ex ); - throw; - } - _platformTransactionManager.Commit( status ); - return result; + _platformTransactionManager.Rollback(status); } - - /// - /// Perform a rollback, handling rollback exceptions properly. - /// - /// The object representing the transaction. - /// The thrown application exception or error. - private void rollbackOnException( ITransactionStatus status, Exception exception ) + catch (Exception ex) { - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug(exception, "Initiating transaction rollback on application exception"); - } - try - { - _platformTransactionManager.Rollback( status ); - } - catch ( Exception ex ) - { - log.LogError(ex, "Application exception overridden by rollback exception"); - throw; - } + log.LogError(ex, "Application exception overridden by rollback exception"); + throw; } } } diff --git a/src/Spring/Spring.Data/Transaction/TransactionException.cs b/src/Spring/Spring.Data/Transaction/TransactionException.cs index 18eb05fd..4302a24a 100644 --- a/src/Spring/Spring.Data/Transaction/TransactionException.cs +++ b/src/Spring/Spring.Data/Transaction/TransactionException.cs @@ -20,53 +20,52 @@ using System.Runtime.Serialization; -namespace Spring.Transaction +namespace Spring.Transaction; + +/// +/// Base class for all transaction exceptions. +/// +/// Rod Johnson +/// Griffin Caprio (.NET) +[Serializable] +public abstract class TransactionException : ApplicationException { /// - /// Base class for all transaction exceptions. + /// Creates a new instance of the TransactionException class. /// - /// Rod Johnson - /// Griffin Caprio (.NET) - [Serializable] - public abstract class TransactionException : ApplicationException + protected TransactionException() { - /// - /// Creates a new instance of the TransactionException class. - /// - protected TransactionException() - { - } + } - /// - /// Creates a new instance of the TransactionException class, with the specified message. - /// - /// - /// A message about the exception. - /// - protected TransactionException (string message) : base(message) - { - } + /// + /// Creates a new instance of the TransactionException class, with the specified message. + /// + /// + /// A message about the exception. + /// + protected TransactionException(string message) : base(message) + { + } - /// - /// Creates a new instance of the TransactionException class with the specified message - /// and root cause. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception that is being wrapped. - /// - protected TransactionException (string message, Exception rootCause) - : base(message, rootCause) - { - } + /// + /// Creates a new instance of the TransactionException class with the specified message + /// and root cause. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception that is being wrapped. + /// + protected TransactionException(string message, Exception rootCause) + : base(message, rootCause) + { + } - /// - protected TransactionException ( - SerializationInfo info, StreamingContext context) - : base (info, context) - { - } + /// + protected TransactionException( + SerializationInfo info, StreamingContext context) + : base(info, context) + { } } diff --git a/src/Spring/Spring.Data/Transaction/TransactionOutcomeState.cs b/src/Spring/Spring.Data/Transaction/TransactionOutcomeState.cs index 41307617..d843c92c 100644 --- a/src/Spring/Spring.Data/Transaction/TransactionOutcomeState.cs +++ b/src/Spring/Spring.Data/Transaction/TransactionOutcomeState.cs @@ -2,29 +2,31 @@ #endregion -namespace Spring.Transaction +namespace Spring.Transaction; + +/// +/// Represents a transaction's current state. +/// +/// Griffin Caprio (.NET) +public enum TransactionOutcomeState { - /// - /// Represents a transaction's current state. - /// - /// Griffin Caprio (.NET) - public enum TransactionOutcomeState - { - /// - /// The transaction state is unknown. - /// - Unknown, - /// - /// The transaction has been committed. - /// - Committed, - /// - /// The transaction has been rolled back. - /// - Rolledback, - /// - /// The transaction is in an unknown, mixed state. - /// - Mixed - } + /// + /// The transaction state is unknown. + /// + Unknown, + + /// + /// The transaction has been committed. + /// + Committed, + + /// + /// The transaction has been rolled back. + /// + Rolledback, + + /// + /// The transaction is in an unknown, mixed state. + /// + Mixed } diff --git a/src/Spring/Spring.Data/Transaction/TransactionPropagation.cs b/src/Spring/Spring.Data/Transaction/TransactionPropagation.cs index 31787659..533e49d8 100644 --- a/src/Spring/Spring.Data/Transaction/TransactionPropagation.cs +++ b/src/Spring/Spring.Data/Transaction/TransactionPropagation.cs @@ -18,85 +18,84 @@ #endregion -namespace Spring.Transaction +namespace Spring.Transaction; + +/// +/// Enumeration describing Spring.NET's +/// transaction propagation settings. +/// +/// Griffin Caprio (.NET) +public enum TransactionPropagation { /// - /// Enumeration describing Spring.NET's - /// transaction propagation settings. + /// Support a current transaction, create a new one if none exists. /// - /// Griffin Caprio (.NET) - public enum TransactionPropagation - { - /// - /// Support a current transaction, create a new one if none exists. - /// - /// - ///

- /// Analogous to System.EnterpriseServices.TransactionOption value of the same name. - /// This is typically the default setting of a transaction definition. - ///

- ///
- Required, + /// + ///

+ /// Analogous to System.EnterpriseServices.TransactionOption value of the same name. + /// This is typically the default setting of a transaction definition. + ///

+ ///
+ Required, - /// - /// Support a current transaction, execute non-transactionally if none exists. - /// - /// - ///

- /// Analogous to System.EnterpriseServices.TransactionOption.Supported. - ///

- ///
- Supports, + /// + /// Support a current transaction, execute non-transactionally if none exists. + /// + /// + ///

+ /// Analogous to System.EnterpriseServices.TransactionOption.Supported. + ///

+ ///
+ Supports, - /// - /// Support a current transaction, throw an exception if none exists. - /// - /// - ///

- /// No corresponding System.EnterpriseServices.TransactionOption value. - ///

- ///
- Mandatory, + /// + /// Support a current transaction, throw an exception if none exists. + /// + /// + ///

+ /// No corresponding System.EnterpriseServices.TransactionOption value. + ///

+ ///
+ Mandatory, - /// - /// Create a new transaction, suspending the current transaction if one exists. - /// - /// - ///

- /// Analogous to System.EnterpriseServices.TransactionOption value of the same name. - ///

- ///
- RequiresNew, + /// + /// Create a new transaction, suspending the current transaction if one exists. + /// + /// + ///

+ /// Analogous to System.EnterpriseServices.TransactionOption value of the same name. + ///

+ ///
+ RequiresNew, - /// - /// Execute non-transactionally, suspending the current transaction if one exists. - /// - /// - ///

- /// Analogous to System.EnterpriseServices.TransactionOption value of the same name. - ///

- ///
- NotSupported, + /// + /// Execute non-transactionally, suspending the current transaction if one exists. + /// + /// + ///

+ /// Analogous to System.EnterpriseServices.TransactionOption value of the same name. + ///

+ ///
+ NotSupported, - /// - /// Execute non-transactionally, throw an exception if a transaction exists. - /// - /// - ///

- /// Analogous to System.EnterpriseServices.TransactionOption.Disabled. - ///

- ///
- Never, + /// + /// Execute non-transactionally, throw an exception if a transaction exists. + /// + /// + ///

+ /// Analogous to System.EnterpriseServices.TransactionOption.Disabled. + ///

+ ///
+ Never, - /// - /// Execute within a nested transaction if a current transaction exists, else - /// behave like . - /// - /// - ///

- /// There is no analogous feature in TransactionOption. - ///

- ///
- Nested - } + /// + /// Execute within a nested transaction if a current transaction exists, else + /// behave like . + /// + /// + ///

+ /// There is no analogous feature in TransactionOption. + ///

+ ///
+ Nested } diff --git a/src/Spring/Spring.Data/Transaction/TransactionSuspensionNotSupportedException.cs b/src/Spring/Spring.Data/Transaction/TransactionSuspensionNotSupportedException.cs index 10192847..5ec8cac1 100644 --- a/src/Spring/Spring.Data/Transaction/TransactionSuspensionNotSupportedException.cs +++ b/src/Spring/Spring.Data/Transaction/TransactionSuspensionNotSupportedException.cs @@ -20,47 +20,50 @@ using System.Runtime.Serialization; -namespace Spring.Transaction +namespace Spring.Transaction; + +/// +/// Exception thrown when attempting to suspend an existing transaction +/// but transaction suspension is not supported by the underlying backend. +/// +/// Juergen Hoeller +/// Griffin Caprio (.NET) +[Serializable] +public class TransactionSuspensionNotSupportedException : CannotCreateTransactionException { - /// - /// Exception thrown when attempting to suspend an existing transaction - /// but transaction suspension is not supported by the underlying backend. - /// - /// Juergen Hoeller - /// Griffin Caprio (.NET) - [Serializable] - public class TransactionSuspensionNotSupportedException : CannotCreateTransactionException - { - /// - /// Creates a new instance of the - /// class. - /// - public TransactionSuspensionNotSupportedException( ) {} + /// + /// Creates a new instance of the + /// class. + /// + public TransactionSuspensionNotSupportedException() { } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - public TransactionSuspensionNotSupportedException( String message ) : base(message) {} + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + public TransactionSuspensionNotSupportedException(String message) : base(message) { } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception that is being wrapped. - /// - public TransactionSuspensionNotSupportedException(string message, Exception rootCause) - : base(message, rootCause) {} + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception that is being wrapped. + /// + public TransactionSuspensionNotSupportedException(string message, Exception rootCause) + : base(message, rootCause) + { + } - /// - protected TransactionSuspensionNotSupportedException( - SerializationInfo info, StreamingContext context ) : base( info, context ) {} - } + /// + protected TransactionSuspensionNotSupportedException( + SerializationInfo info, StreamingContext context) : base(info, context) + { + } } diff --git a/src/Spring/Spring.Data/Transaction/TransactionSystemException.cs b/src/Spring/Spring.Data/Transaction/TransactionSystemException.cs index 8f930dd7..567d08a0 100644 --- a/src/Spring/Spring.Data/Transaction/TransactionSystemException.cs +++ b/src/Spring/Spring.Data/Transaction/TransactionSystemException.cs @@ -20,47 +20,50 @@ using System.Runtime.Serialization; -namespace Spring.Transaction +namespace Spring.Transaction; + +/// +/// Exception thrown when a general transaction system error is encountered, +/// for instance on commit or rollback. +/// +/// Juergen Hoeller +/// Griffin Caprio (.NET) +[Serializable] +public class TransactionSystemException : TransactionException { - /// - /// Exception thrown when a general transaction system error is encountered, - /// for instance on commit or rollback. - /// - /// Juergen Hoeller - /// Griffin Caprio (.NET) - [Serializable] - public class TransactionSystemException : TransactionException - { - /// - /// Creates a new instance of the - /// class. - /// - public TransactionSystemException( ) {} + /// + /// Creates a new instance of the + /// class. + /// + public TransactionSystemException() { } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - public TransactionSystemException( String message ) : base(message) {} + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + public TransactionSystemException(String message) : base(message) { } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception that is being wrapped. - /// - public TransactionSystemException(string message, Exception rootCause) - : base(message, rootCause) {} + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception that is being wrapped. + /// + public TransactionSystemException(string message, Exception rootCause) + : base(message, rootCause) + { + } - /// - protected TransactionSystemException( - SerializationInfo info, StreamingContext context ) : base( info, context ) {} - } + /// + protected TransactionSystemException( + SerializationInfo info, StreamingContext context) : base(info, context) + { + } } diff --git a/src/Spring/Spring.Data/Transaction/TransactionTimedOutException.cs b/src/Spring/Spring.Data/Transaction/TransactionTimedOutException.cs index 2146de21..ef55d1cb 100644 --- a/src/Spring/Spring.Data/Transaction/TransactionTimedOutException.cs +++ b/src/Spring/Spring.Data/Transaction/TransactionTimedOutException.cs @@ -1,44 +1,47 @@ using System.Runtime.Serialization; -namespace Spring.Transaction +namespace Spring.Transaction; + +/// +/// Exception to be thrown when a transaction has timed out. +/// +[Serializable] +public class TransactionTimedOutException : TransactionException { - /// - /// Exception to be thrown when a transaction has timed out. - /// - [Serializable] - public class TransactionTimedOutException : TransactionException - { - /// - /// Create a new instance - /// - public TransactionTimedOutException() : base() - { + /// + /// Create a new instance + /// + public TransactionTimedOutException() : base() + { + } - } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - public TransactionTimedOutException( String message ) : base(message) {} + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + public TransactionTimedOutException(String message) : base(message) { } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception that is being wrapped. - /// - public TransactionTimedOutException(string message, Exception rootCause) - : base(message, rootCause) {} + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception that is being wrapped. + /// + public TransactionTimedOutException(string message, Exception rootCause) + : base(message, rootCause) + { + } - /// - protected TransactionTimedOutException( - SerializationInfo info, StreamingContext context ) : base( info, context ) {} - } + /// + protected TransactionTimedOutException( + SerializationInfo info, StreamingContext context) : base(info, context) + { + } } diff --git a/src/Spring/Spring.Data/Transaction/TransactionUsageException.cs b/src/Spring/Spring.Data/Transaction/TransactionUsageException.cs index 220e2243..d8b417dc 100644 --- a/src/Spring/Spring.Data/Transaction/TransactionUsageException.cs +++ b/src/Spring/Spring.Data/Transaction/TransactionUsageException.cs @@ -20,47 +20,50 @@ using System.Runtime.Serialization; -namespace Spring.Transaction +namespace Spring.Transaction; + +/// +/// Superclass for exceptions caused by inappropriate usage of +/// a Spring.NET transaction API. +/// +/// Juergen Hoeller +/// Griffin Caprio (.NET) +[Serializable] +public class TransactionUsageException : TransactionException { - /// - /// Superclass for exceptions caused by inappropriate usage of - /// a Spring.NET transaction API. - /// - /// Juergen Hoeller - /// Griffin Caprio (.NET) - [Serializable] - public class TransactionUsageException : TransactionException - { - /// - /// Creates a new instance of the - /// class. - /// - public TransactionUsageException( ) {} + /// + /// Creates a new instance of the + /// class. + /// + public TransactionUsageException() { } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - public TransactionUsageException( String message ) : base(message) {} + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + public TransactionUsageException(String message) : base(message) { } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception that is being wrapped. - /// - public TransactionUsageException(string message, Exception rootCause) - : base(message, rootCause) {} + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception that is being wrapped. + /// + public TransactionUsageException(string message, Exception rootCause) + : base(message, rootCause) + { + } - /// - protected TransactionUsageException( - SerializationInfo info, StreamingContext context ) : base( info, context ) {} - } + /// + protected TransactionUsageException( + SerializationInfo info, StreamingContext context) : base(info, context) + { + } } diff --git a/src/Spring/Spring.Data/Transaction/UnexpectedRollbackException.cs b/src/Spring/Spring.Data/Transaction/UnexpectedRollbackException.cs index 0706ce82..857dcb43 100644 --- a/src/Spring/Spring.Data/Transaction/UnexpectedRollbackException.cs +++ b/src/Spring/Spring.Data/Transaction/UnexpectedRollbackException.cs @@ -20,46 +20,49 @@ using System.Runtime.Serialization; -namespace Spring.Transaction +namespace Spring.Transaction; + +/// +/// Thrown when an attempt to commit a transaction resulted in an unexpected rollback. +/// +/// Rod Johnson +/// Griffin Caprio (.NET) +[Serializable] +public class UnexpectedRollbackException : TransactionException { - /// - /// Thrown when an attempt to commit a transaction resulted in an unexpected rollback. - /// - /// Rod Johnson - /// Griffin Caprio (.NET) - [Serializable] - public class UnexpectedRollbackException : TransactionException - { - /// - /// Creates a new instance of the - /// class. - /// - public UnexpectedRollbackException( ) {} + /// + /// Creates a new instance of the + /// class. + /// + public UnexpectedRollbackException() { } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - public UnexpectedRollbackException( String message ) : base(message) {} + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + public UnexpectedRollbackException(String message) : base(message) { } - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception that is being wrapped. - /// - public UnexpectedRollbackException(string message, Exception rootCause) - : base(message, rootCause) {} + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception that is being wrapped. + /// + public UnexpectedRollbackException(string message, Exception rootCause) + : base(message, rootCause) + { + } - /// - protected UnexpectedRollbackException( - SerializationInfo info, StreamingContext context ) : base( info, context ) {} - } + /// + protected UnexpectedRollbackException( + SerializationInfo info, StreamingContext context) : base(info, context) + { + } } diff --git a/src/Spring/Spring.Messaging.Ems/AssemblyInfo.cs b/src/Spring/Spring.Messaging.Ems/AssemblyInfo.cs index fbbf4aab..14e5a087 100644 --- a/src/Spring/Spring.Messaging.Ems/AssemblyInfo.cs +++ b/src/Spring/Spring.Messaging.Ems/AssemblyInfo.cs @@ -1,4 +1,4 @@ using System.Reflection; [assembly: AssemblyTitle("Spring.Messaging.Ems")] -[assembly: AssemblyDescription("TIBCO EMS support")] \ No newline at end of file +[assembly: AssemblyDescription("TIBCO EMS support")] diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Common/EmsConnection.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Common/EmsConnection.cs index 64806c61..bb7f108c 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Common/EmsConnection.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Common/EmsConnection.cs @@ -20,184 +20,181 @@ using Microsoft.Extensions.Logging; -namespace Spring.Messaging.Ems.Common +namespace Spring.Messaging.Ems.Common; + +/// +/// A Connection object is a client's active connection to TIBCO EMS Server. +/// +public class EmsConnection : IConnection { + #region Logging + + private readonly ILogger logger = LogManager.GetLogger(); + + #endregion + + private Connection nativeConnection; + /// - /// A Connection object is a client's active connection to TIBCO EMS Server. + /// Initializes a new instance of the class. /// - public class EmsConnection : IConnection + /// The underlying TIBCO EMS connection. + public EmsConnection(Connection connection) { - #region Logging + this.nativeConnection = connection; + this.nativeConnection.ExceptionHandler += HandleEmsException; + } - private readonly ILogger logger = LogManager.GetLogger(); + #region Implementation of IConnection - #endregion + /// + /// Gets the native TIBCO EMS connection. + /// + /// The native connection. + public Connection NativeConnection + { + get { return this.nativeConnection; } + } - private Connection nativeConnection; + /// + /// Occurs when the client library detects a problem with the connection. + /// + public event EMSExceptionHandler EMSExceptionHandler; - /// - /// Initializes a new instance of the class. - /// - /// The underlying TIBCO EMS connection. - public EmsConnection(Connection connection) + /// + /// Gets the URL of the server this connection is currently connected to + /// + /// The active URL. + public string ActiveURL + { + get { return nativeConnection.ActiveURL; } + } + + /// + /// Gets or sets the client ID. + /// + /// The client ID. + public string ClientID + { + get { return nativeConnection.ClientID; } + set { nativeConnection.ClientID = value; } + } + + /// + /// Gets the connection ID. + /// + /// The connection ID. + public long ConnID + { + get { return nativeConnection.ConnID; } + } + + /// + /// Gets or sets the exception listener. + /// + /// The exception listener. + public IExceptionListener ExceptionListener + { + get { return nativeConnection.ExceptionListener; } + set { nativeConnection.ExceptionListener = value; } + } + + /// + /// Gets a value indicating whether the connection is closed. + /// + /// + /// true if the connection is closed; otherwise, false. + /// + public bool IsClosed + { + get { return nativeConnection.IsClosed; } + } + + /// + /// Gets a value indicating whether the connection communicates with a secure protocol + /// + /// + /// true if the connection communicates with a secure protocol; otherwise, false. + /// + public bool IsSecure + { + get { return nativeConnection.IsSecure; } + } + + /// + /// Gets the metadata for this connection + /// + /// The metadata for this connection. + public ConnectionMetaData MetaData + { + get { return nativeConnection.MetaData; } + } + + /// + /// Closes the connection and reclaims resources. + /// + public void Close() + { + nativeConnection.Close(); + } + + /// + /// Creates the session. + /// + /// if set to true the session has transaction semantics. + /// Indicates whether and how the consumer is to acknowledge received messages. + /// This version of CreateSession accepts an integer value associated with the acknowledge mode described by a Session member and should only be used for backward compatibility. + /// This parameter is ignored if the session is transacted. + /// A newly created session. + public ISession CreateSession(bool transacted, int acknowledgeMode) + { + Session nativeSession = nativeConnection.CreateSession(transacted, acknowledgeMode); + return new EmsSession(nativeSession); + } + + /// + /// Creates the session. + /// + /// if set to true [transacted]. + /// The acknowledge mode. + /// When true, the new session has transaction semantics. + /// Indicates whether and how the consumer is to acknowledge received messages. + /// Legal values are listed under SessionMode. + /// This parameter is ignored if the session is transacted. + /// A newly created session. + public ISession CreateSession(bool transacted, SessionMode acknowledgeMode) + { + Session nativeSession = nativeConnection.CreateSession(transacted, acknowledgeMode); + return new EmsSession(nativeSession); + } + + /// + /// Starts (or restarts) a connection's delivery of incoming messages. + /// + public void Start() + { + nativeConnection.Start(); + } + + /// + /// Temporarily stops a connection's delivery of incoming messages. + /// + public void Stop() + { + nativeConnection.Stop(); + } + + #endregion + + private void HandleEmsException(object sender, EMSExceptionEventArgs arg) + { + if (EMSExceptionHandler != null) { - this.nativeConnection = connection; - this.nativeConnection.ExceptionHandler += HandleEmsException; + EMSExceptionHandler(sender, arg); } - - - - #region Implementation of IConnection - - /// - /// Gets the native TIBCO EMS connection. - /// - /// The native connection. - public Connection NativeConnection + else { - get { return this.nativeConnection; } - } - - /// - /// Occurs when the client library detects a problem with the connection. - /// - public event EMSExceptionHandler EMSExceptionHandler; - - /// - /// Gets the URL of the server this connection is currently connected to - /// - /// The active URL. - public string ActiveURL - { - get { return nativeConnection.ActiveURL; } - } - - /// - /// Gets or sets the client ID. - /// - /// The client ID. - public string ClientID - { - get { return nativeConnection.ClientID; } - set { nativeConnection.ClientID = value; } - } - - /// - /// Gets the connection ID. - /// - /// The connection ID. - public long ConnID - { - get { return nativeConnection.ConnID; } - } - - /// - /// Gets or sets the exception listener. - /// - /// The exception listener. - public IExceptionListener ExceptionListener - { - get { return nativeConnection.ExceptionListener; } - set { nativeConnection.ExceptionListener = value; } - } - - /// - /// Gets a value indicating whether the connection is closed. - /// - /// - /// true if the connection is closed; otherwise, false. - /// - public bool IsClosed - { - get { return nativeConnection.IsClosed; } - } - - /// - /// Gets a value indicating whether the connection communicates with a secure protocol - /// - /// - /// true if the connection communicates with a secure protocol; otherwise, false. - /// - public bool IsSecure - { - get { return nativeConnection.IsSecure; } - } - - /// - /// Gets the metadata for this connection - /// - /// The metadata for this connection. - public ConnectionMetaData MetaData - { - get { return nativeConnection.MetaData; } - } - - /// - /// Closes the connection and reclaims resources. - /// - public void Close() - { - nativeConnection.Close(); - } - - /// - /// Creates the session. - /// - /// if set to true the session has transaction semantics. - /// Indicates whether and how the consumer is to acknowledge received messages. - /// This version of CreateSession accepts an integer value associated with the acknowledge mode described by a Session member and should only be used for backward compatibility. - /// This parameter is ignored if the session is transacted. - /// A newly created session. - public ISession CreateSession(bool transacted, int acknowledgeMode) - { - Session nativeSession = nativeConnection.CreateSession(transacted, acknowledgeMode); - return new EmsSession(nativeSession); - } - - /// - /// Creates the session. - /// - /// if set to true [transacted]. - /// The acknowledge mode. - /// When true, the new session has transaction semantics. - /// Indicates whether and how the consumer is to acknowledge received messages. - /// Legal values are listed under SessionMode. - /// This parameter is ignored if the session is transacted. - /// A newly created session. - public ISession CreateSession(bool transacted, SessionMode acknowledgeMode) - { - Session nativeSession = nativeConnection.CreateSession(transacted, acknowledgeMode); - return new EmsSession(nativeSession); - } - - /// - /// Starts (or restarts) a connection's delivery of incoming messages. - /// - public void Start() - { - nativeConnection.Start(); - } - - /// - /// Temporarily stops a connection's delivery of incoming messages. - /// - public void Stop() - { - nativeConnection.Stop(); - } - - #endregion - - private void HandleEmsException(object sender, EMSExceptionEventArgs arg) - { - if (EMSExceptionHandler != null) - { - EMSExceptionHandler(sender, arg); - } - else - { - logger.LogError((Exception) arg.Exception, "No exception handler registered with EmsConnection wrapper class."); - } + logger.LogError((Exception) arg.Exception, "No exception handler registered with EmsConnection wrapper class."); } } } diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Common/EmsConnectionFactory.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Common/EmsConnectionFactory.cs index 036dfd16..51740213 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Common/EmsConnectionFactory.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Common/EmsConnectionFactory.cs @@ -22,254 +22,255 @@ using System.Collections; using System.Runtime.Serialization; using Spring.Objects.Factory; -namespace Spring.Messaging.Ems.Common +namespace Spring.Messaging.Ems.Common; + +public class EmsConnectionFactory : IConnectionFactory, IInitializingObject { - public class EmsConnectionFactory : IConnectionFactory, IInitializingObject + private ConnectionFactory nativeConnectionFactory; + private string sslProxyAuthUsername; + private string sslProxyAuthPassword; + + private string sslProxyHost; + private int sslProxyPort; + + public EmsConnectionFactory() { - private ConnectionFactory nativeConnectionFactory; - private string sslProxyAuthUsername; - private string sslProxyAuthPassword; - - private string sslProxyHost; - private int sslProxyPort; - - public EmsConnectionFactory() - { - this.nativeConnectionFactory = new ConnectionFactory(); - } - - public EmsConnectionFactory(string serverUrl) : this(serverUrl, null, null) - { - } - - public EmsConnectionFactory(string serverUrl, string clientId) : this(serverUrl, clientId, null) - { - } - - public EmsConnectionFactory(string serverUrl, string clientId, Hashtable properties) - { - this.nativeConnectionFactory = new ConnectionFactory(serverUrl, clientId, properties); - } - - public EmsConnectionFactory(ConnectionFactory nativeConnectionFactory) - { - this.nativeConnectionFactory = nativeConnectionFactory; - } - - - #region Implementation of ISerializable - - public void GetObjectData(SerializationInfo info, StreamingContext context) - { - nativeConnectionFactory.GetObjectData(info, context); - } - - #endregion - - #region Implementation of ICloneable - - public object Clone() - { - return nativeConnectionFactory.Clone(); - } - - #endregion - - #region Implementation of IConnectionFactory - - public ConnectionFactory NativeConnectionFactory - { - get { return this.nativeConnectionFactory; } - } - - public IConnection CreateConnection() - { - Connection nativeConnection = nativeConnectionFactory.CreateConnection(); - return new EmsConnection(nativeConnection); - } - - public IConnection CreateConnection(string userName, string password) - { - Connection nativeConnection = nativeConnectionFactory.CreateConnection(userName, password); - return new EmsConnection(nativeConnection); - } - - public object CertificateStore - { - get { return nativeConnectionFactory.GetCertificateStore(); } - } - - public string SSLProxyHost - { - get { return this.sslProxyHost; } - set { this.sslProxyHost = value; } - } - - public string SSLProxyPassword - { - get { return nativeConnectionFactory.GetSSLProxyPassword(); } - } - - public int SSLProxyPort - { - get { return this.sslProxyPort; } - set { this.sslProxyPort = value; } - } - - public string SSLProxyUser - { - get { return nativeConnectionFactory.GetSSLProxyUser(); } - } - - public IEmsSSLStoreType CertificateStoreType - { - set - { - if (value is EmsSSLFileStoreInfo) - { - EmsSSLFileStoreInfo emsSslFileStoreInfo = (EmsSSLFileStoreInfo) value; - nativeConnectionFactory.SetCertificateStoreType(EMSSSLStoreType.EMSSSL_STORE_TYPE_FILE, emsSslFileStoreInfo.NativeEmsSslFileStoreInfo); - } else if (value is EmsSSLSystemStoreInfo) - { - EmsSSLSystemStoreInfo info = (EmsSSLSystemStoreInfo) value; - nativeConnectionFactory.SetCertificateStoreType(EMSSSLStoreType.EMSSSL_STORE_TYPE_SYSTEM, info.NativeEmssslSystemStoreInfo); - } else - { - throw new ArgumentException("IEmsSSLStoreType of type [" + value.GetType() + "], not supported."); - } - } - } - - public string ClientID - { - set { nativeConnectionFactory.SetClientID(value); } - } - - public StreamWriter ClientTracer - { - set { nativeConnectionFactory.SetClientTracer(value); } - } - - public int ConnAttemptCount - { - set { nativeConnectionFactory.SetConnAttemptCount(value); } - } - - public int ConnAttemptDelay - { - set { nativeConnectionFactory.SetConnAttemptDelay(value); } - } - - public int ConnAttemptTimeout - { - set { nativeConnectionFactory.SetConnAttemptTimeout(value); } - } - - public EMSSSLHostNameVerifier HostNameVerifier - { - set { nativeConnectionFactory.SetHostNameVerifier(value); } - } - - public int MetricAsInt - { - set { nativeConnectionFactory.SetMetric(value); } - } - - public string MulticastDaemon - { - set { nativeConnectionFactory.SetMulticastDaemon(value); } - } - - public bool MulticastEnabled - { - set { nativeConnectionFactory.SetMulticastEnabled(value); } - } - - public int ReconnAttemptCount - { - set { nativeConnectionFactory.SetReconnAttemptCount(value); } - } - - public int ReconnAttemptDelay - { - set { nativeConnectionFactory.SetReconnAttemptDelay(value); } - } - - public int ReconnAttemptTimeout - { - set { nativeConnectionFactory.SetReconnAttemptTimeout(value); } - } - - public string ServerUrl - { - set { nativeConnectionFactory.SetServerUrl(value); } - } - - public bool SSLAuthOnly - { - set { nativeConnectionFactory.SetSSLAuthOnly(value); } - } - - public string SSLProxyAuthUsername - { - set { this.sslProxyAuthUsername = value; } - get { return this.sslProxyAuthUsername; } - } - - public string SSLProxyAuthPassword - { - set { this.sslProxyAuthPassword = value; } - get { return this.sslProxyAuthPassword; } - } - - public bool SSLTrace - { - set { nativeConnectionFactory.SetSSLTrace(value); } - } - - public string TargetHostName - { - set { nativeConnectionFactory.SetTargetHostName(value); } - } - - public string UserName - { - set { nativeConnectionFactory.SetUserName(value); } - } - - public string UserPassword - { - set { nativeConnectionFactory.SetUserPassword(value); } - } - - public FactoryLoadBalanceMetric Metric - { - get - { - return nativeConnectionFactory.Metric; - } - set { - nativeConnectionFactory.Metric = value; - } - } - - #endregion - - #region Implementation of IInitializingObject - - public void AfterPropertiesSet() { - - if (this.sslProxyAuthUsername != null && sslProxyAuthPassword != null) - { - nativeConnectionFactory.SetSSLProxyAuth(this.sslProxyAuthUsername, this.sslProxyAuthPassword); - } - if (sslProxyHost != null && sslProxyPort != 0) - { - nativeConnectionFactory.SetSSLProxy(this.sslProxyHost, this.sslProxyPort); - } - - } - - #endregion + this.nativeConnectionFactory = new ConnectionFactory(); } + + public EmsConnectionFactory(string serverUrl) : this(serverUrl, null, null) + { + } + + public EmsConnectionFactory(string serverUrl, string clientId) : this(serverUrl, clientId, null) + { + } + + public EmsConnectionFactory(string serverUrl, string clientId, Hashtable properties) + { + this.nativeConnectionFactory = new ConnectionFactory(serverUrl, clientId, properties); + } + + public EmsConnectionFactory(ConnectionFactory nativeConnectionFactory) + { + this.nativeConnectionFactory = nativeConnectionFactory; + } + + #region Implementation of ISerializable + + public void GetObjectData(SerializationInfo info, StreamingContext context) + { + nativeConnectionFactory.GetObjectData(info, context); + } + + #endregion + + #region Implementation of ICloneable + + public object Clone() + { + return nativeConnectionFactory.Clone(); + } + + #endregion + + #region Implementation of IConnectionFactory + + public ConnectionFactory NativeConnectionFactory + { + get { return this.nativeConnectionFactory; } + } + + public IConnection CreateConnection() + { + Connection nativeConnection = nativeConnectionFactory.CreateConnection(); + return new EmsConnection(nativeConnection); + } + + public IConnection CreateConnection(string userName, string password) + { + Connection nativeConnection = nativeConnectionFactory.CreateConnection(userName, password); + return new EmsConnection(nativeConnection); + } + + public object CertificateStore + { + get { return nativeConnectionFactory.GetCertificateStore(); } + } + + public string SSLProxyHost + { + get { return this.sslProxyHost; } + set { this.sslProxyHost = value; } + } + + public string SSLProxyPassword + { + get { return nativeConnectionFactory.GetSSLProxyPassword(); } + } + + public int SSLProxyPort + { + get { return this.sslProxyPort; } + set { this.sslProxyPort = value; } + } + + public string SSLProxyUser + { + get { return nativeConnectionFactory.GetSSLProxyUser(); } + } + + public IEmsSSLStoreType CertificateStoreType + { + set + { + if (value is EmsSSLFileStoreInfo) + { + EmsSSLFileStoreInfo emsSslFileStoreInfo = (EmsSSLFileStoreInfo) value; + nativeConnectionFactory.SetCertificateStoreType(EMSSSLStoreType.EMSSSL_STORE_TYPE_FILE, emsSslFileStoreInfo.NativeEmsSslFileStoreInfo); + } + else if (value is EmsSSLSystemStoreInfo) + { + EmsSSLSystemStoreInfo info = (EmsSSLSystemStoreInfo) value; + nativeConnectionFactory.SetCertificateStoreType(EMSSSLStoreType.EMSSSL_STORE_TYPE_SYSTEM, info.NativeEmssslSystemStoreInfo); + } + else + { + throw new ArgumentException("IEmsSSLStoreType of type [" + value.GetType() + "], not supported."); + } + } + } + + public string ClientID + { + set { nativeConnectionFactory.SetClientID(value); } + } + + public StreamWriter ClientTracer + { + set { nativeConnectionFactory.SetClientTracer(value); } + } + + public int ConnAttemptCount + { + set { nativeConnectionFactory.SetConnAttemptCount(value); } + } + + public int ConnAttemptDelay + { + set { nativeConnectionFactory.SetConnAttemptDelay(value); } + } + + public int ConnAttemptTimeout + { + set { nativeConnectionFactory.SetConnAttemptTimeout(value); } + } + + public EMSSSLHostNameVerifier HostNameVerifier + { + set { nativeConnectionFactory.SetHostNameVerifier(value); } + } + + public int MetricAsInt + { + set { nativeConnectionFactory.SetMetric(value); } + } + + public string MulticastDaemon + { + set { nativeConnectionFactory.SetMulticastDaemon(value); } + } + + public bool MulticastEnabled + { + set { nativeConnectionFactory.SetMulticastEnabled(value); } + } + + public int ReconnAttemptCount + { + set { nativeConnectionFactory.SetReconnAttemptCount(value); } + } + + public int ReconnAttemptDelay + { + set { nativeConnectionFactory.SetReconnAttemptDelay(value); } + } + + public int ReconnAttemptTimeout + { + set { nativeConnectionFactory.SetReconnAttemptTimeout(value); } + } + + public string ServerUrl + { + set { nativeConnectionFactory.SetServerUrl(value); } + } + + public bool SSLAuthOnly + { + set { nativeConnectionFactory.SetSSLAuthOnly(value); } + } + + public string SSLProxyAuthUsername + { + set { this.sslProxyAuthUsername = value; } + get { return this.sslProxyAuthUsername; } + } + + public string SSLProxyAuthPassword + { + set { this.sslProxyAuthPassword = value; } + get { return this.sslProxyAuthPassword; } + } + + public bool SSLTrace + { + set { nativeConnectionFactory.SetSSLTrace(value); } + } + + public string TargetHostName + { + set { nativeConnectionFactory.SetTargetHostName(value); } + } + + public string UserName + { + set { nativeConnectionFactory.SetUserName(value); } + } + + public string UserPassword + { + set { nativeConnectionFactory.SetUserPassword(value); } + } + + public FactoryLoadBalanceMetric Metric + { + get + { + return nativeConnectionFactory.Metric; + } + set + { + nativeConnectionFactory.Metric = value; + } + } + + #endregion + + #region Implementation of IInitializingObject + + public void AfterPropertiesSet() + { + if (this.sslProxyAuthUsername != null && sslProxyAuthPassword != null) + { + nativeConnectionFactory.SetSSLProxyAuth(this.sslProxyAuthUsername, this.sslProxyAuthPassword); + } + + if (sslProxyHost != null && sslProxyPort != 0) + { + nativeConnectionFactory.SetSSLProxy(this.sslProxyHost, this.sslProxyPort); + } + } + + #endregion } diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Common/EmsMessageConsumer.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Common/EmsMessageConsumer.cs index 5556ed69..c86bd5aa 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Common/EmsMessageConsumer.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Common/EmsMessageConsumer.cs @@ -18,58 +18,57 @@ #endregion -namespace Spring.Messaging.Ems.Common +namespace Spring.Messaging.Ems.Common; + +public class EmsMessageConsumer : IMessageConsumer { - public class EmsMessageConsumer : IMessageConsumer + protected readonly MessageConsumer nativeMessageConsumer; + + public EmsMessageConsumer(MessageConsumer messageConsumer) { - protected readonly MessageConsumer nativeMessageConsumer; - - public EmsMessageConsumer(MessageConsumer messageConsumer) - { - nativeMessageConsumer = messageConsumer; - nativeMessageConsumer.MessageHandler += MessageHandler; - } - - #region Implementation of IMessageConsumer - - public MessageConsumer NativeMessageConsumer - { - get { return this.nativeMessageConsumer; } - } - - public event EMSMessageHandler MessageHandler; - - public IMessageListener MessageListener - { - get { return nativeMessageConsumer.MessageListener; } - set { nativeMessageConsumer.MessageListener = value; } - } - - public string MessageSelector - { - get { return nativeMessageConsumer.MessageSelector; } - } - - public void Close() - { - nativeMessageConsumer.Close(); - } - - public Message Receive() - { - return nativeMessageConsumer.Receive(); - } - - public Message Receive(long timeout) - { - return nativeMessageConsumer.Receive(timeout); - } - - public Message ReceiveNoWait() - { - return nativeMessageConsumer.ReceiveNoWait(); - } - - #endregion + nativeMessageConsumer = messageConsumer; + nativeMessageConsumer.MessageHandler += MessageHandler; } + + #region Implementation of IMessageConsumer + + public MessageConsumer NativeMessageConsumer + { + get { return this.nativeMessageConsumer; } + } + + public event EMSMessageHandler MessageHandler; + + public IMessageListener MessageListener + { + get { return nativeMessageConsumer.MessageListener; } + set { nativeMessageConsumer.MessageListener = value; } + } + + public string MessageSelector + { + get { return nativeMessageConsumer.MessageSelector; } + } + + public void Close() + { + nativeMessageConsumer.Close(); + } + + public Message Receive() + { + return nativeMessageConsumer.Receive(); + } + + public Message Receive(long timeout) + { + return nativeMessageConsumer.Receive(timeout); + } + + public Message ReceiveNoWait() + { + return nativeMessageConsumer.ReceiveNoWait(); + } + + #endregion } diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Common/EmsMessageProducer.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Common/EmsMessageProducer.cs index a855d669..2f08054f 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Common/EmsMessageProducer.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Common/EmsMessageProducer.cs @@ -18,100 +18,99 @@ #endregion -namespace Spring.Messaging.Ems.Common +namespace Spring.Messaging.Ems.Common; + +public class EmsMessageProducer : IMessageProducer { - public class EmsMessageProducer : IMessageProducer + private MessageProducer nativeMessageProducer; + + public EmsMessageProducer(MessageProducer messageProducer) { - private MessageProducer nativeMessageProducer; - - public EmsMessageProducer(MessageProducer messageProducer) - { - this.nativeMessageProducer = messageProducer; - } - - #region Implementation of IMessageProducer - - public MessageProducer NativeMessageProducer - { - get { return this.nativeMessageProducer; } - } - - public void Close() - { - nativeMessageProducer.Close(); - } - - public void Send(Message message) - { - nativeMessageProducer.Send(message); - } - - public void Send(Destination dest, Message message) - { - nativeMessageProducer.Send(dest, message); - } - - public void Send(Message message, int deliveryMode, int priority, long timeToLive) - { - nativeMessageProducer.Send(message, deliveryMode, priority, timeToLive); - } - - public void Send(Message message, MessageDeliveryMode deliveryMode, int priority, long timeToLive) - { - nativeMessageProducer.Send(message, deliveryMode, priority, timeToLive); - } - - public void Send(Destination dest, Message message, int deliveryMode, int priority, long timeToLive) - { - nativeMessageProducer.Send(dest, message, deliveryMode, priority, timeToLive); - } - - public void Send(Destination dest, Message message, MessageDeliveryMode deliveryMode, int priority, long timeToLive) - { - nativeMessageProducer.Send(dest, message, deliveryMode, priority, timeToLive); - } - - public int DeliveryMode - { - get { return nativeMessageProducer.DeliveryMode; } - set { nativeMessageProducer.DeliveryMode = value; } - } - - public Destination Destination - { - get { return nativeMessageProducer.Destination; } - } - - public bool DisableMessageID - { - get { return nativeMessageProducer.DisableMessageID; } - set { nativeMessageProducer.DisableMessageID = value; } - } - - public bool DisableMessageTimestamp - { - get { return nativeMessageProducer.DisableMessageTimestamp; } - set { nativeMessageProducer.DisableMessageTimestamp = value; } - } - - public MessageDeliveryMode MsgDeliveryMode - { - get { return nativeMessageProducer.MsgDeliveryMode; } - set { nativeMessageProducer.MsgDeliveryMode = value; } - } - - public int Priority - { - get { return nativeMessageProducer.Priority; } - set { nativeMessageProducer.Priority = value; } - } - - public long TimeToLive - { - get { return nativeMessageProducer.TimeToLive; } - set { nativeMessageProducer.TimeToLive = value; } - } - - #endregion + this.nativeMessageProducer = messageProducer; } + + #region Implementation of IMessageProducer + + public MessageProducer NativeMessageProducer + { + get { return this.nativeMessageProducer; } + } + + public void Close() + { + nativeMessageProducer.Close(); + } + + public void Send(Message message) + { + nativeMessageProducer.Send(message); + } + + public void Send(Destination dest, Message message) + { + nativeMessageProducer.Send(dest, message); + } + + public void Send(Message message, int deliveryMode, int priority, long timeToLive) + { + nativeMessageProducer.Send(message, deliveryMode, priority, timeToLive); + } + + public void Send(Message message, MessageDeliveryMode deliveryMode, int priority, long timeToLive) + { + nativeMessageProducer.Send(message, deliveryMode, priority, timeToLive); + } + + public void Send(Destination dest, Message message, int deliveryMode, int priority, long timeToLive) + { + nativeMessageProducer.Send(dest, message, deliveryMode, priority, timeToLive); + } + + public void Send(Destination dest, Message message, MessageDeliveryMode deliveryMode, int priority, long timeToLive) + { + nativeMessageProducer.Send(dest, message, deliveryMode, priority, timeToLive); + } + + public int DeliveryMode + { + get { return nativeMessageProducer.DeliveryMode; } + set { nativeMessageProducer.DeliveryMode = value; } + } + + public Destination Destination + { + get { return nativeMessageProducer.Destination; } + } + + public bool DisableMessageID + { + get { return nativeMessageProducer.DisableMessageID; } + set { nativeMessageProducer.DisableMessageID = value; } + } + + public bool DisableMessageTimestamp + { + get { return nativeMessageProducer.DisableMessageTimestamp; } + set { nativeMessageProducer.DisableMessageTimestamp = value; } + } + + public MessageDeliveryMode MsgDeliveryMode + { + get { return nativeMessageProducer.MsgDeliveryMode; } + set { nativeMessageProducer.MsgDeliveryMode = value; } + } + + public int Priority + { + get { return nativeMessageProducer.Priority; } + set { nativeMessageProducer.Priority = value; } + } + + public long TimeToLive + { + get { return nativeMessageProducer.TimeToLive; } + set { nativeMessageProducer.TimeToLive = value; } + } + + #endregion } diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Common/EmsSSLFileStoreInfo.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Common/EmsSSLFileStoreInfo.cs index c6df042e..b0b75c6b 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Common/EmsSSLFileStoreInfo.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Common/EmsSSLFileStoreInfo.cs @@ -20,42 +20,40 @@ using System.Security.Cryptography.X509Certificates; -namespace Spring.Messaging.Ems.Common +namespace Spring.Messaging.Ems.Common; + +public class EmsSSLFileStoreInfo : IEmsSSLStoreType { - public class EmsSSLFileStoreInfo : IEmsSSLStoreType + private EMSSSLFileStoreInfo nativeEmsSSLFileStoreInfo; + + public virtual EMSSSLFileStoreInfo NativeEmsSslFileStoreInfo { - private EMSSSLFileStoreInfo nativeEmsSSLFileStoreInfo; - - public virtual EMSSSLFileStoreInfo NativeEmsSslFileStoreInfo - { - get { return nativeEmsSSLFileStoreInfo; } - set { nativeEmsSSLFileStoreInfo = value; } - } - - public X509Certificate SslClientIdentity - { - set { NativeEmsSslFileStoreInfo.SetSSLClientIdentity(value); } - } - - public string SslClientIdentityAsString - { - set { NativeEmsSslFileStoreInfo.SetSSLClientIdentity(value); } - } - - public string SslPassword - { - set { NativeEmsSslFileStoreInfo.SetSSLPassword(value.ToCharArray()); } - } - - public X509Certificate SslTrustedCertificate - { - set { NativeEmsSslFileStoreInfo.SetSSLTrustedCertificate(value); } - } - - public string SslTrustedCertificateAsString - { - set { NativeEmsSslFileStoreInfo.SetSSLTrustedCertificate(value); } - } - + get { return nativeEmsSSLFileStoreInfo; } + set { nativeEmsSSLFileStoreInfo = value; } } -} + + public X509Certificate SslClientIdentity + { + set { NativeEmsSslFileStoreInfo.SetSSLClientIdentity(value); } + } + + public string SslClientIdentityAsString + { + set { NativeEmsSslFileStoreInfo.SetSSLClientIdentity(value); } + } + + public string SslPassword + { + set { NativeEmsSslFileStoreInfo.SetSSLPassword(value.ToCharArray()); } + } + + public X509Certificate SslTrustedCertificate + { + set { NativeEmsSslFileStoreInfo.SetSSLTrustedCertificate(value); } + } + + public string SslTrustedCertificateAsString + { + set { NativeEmsSslFileStoreInfo.SetSSLTrustedCertificate(value); } + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Common/EmsSSLSystemStoreInfo.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Common/EmsSSLSystemStoreInfo.cs index b5d7a238..205df886 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Common/EmsSSLSystemStoreInfo.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Common/EmsSSLSystemStoreInfo.cs @@ -20,38 +20,36 @@ using System.Security.Cryptography.X509Certificates; -namespace Spring.Messaging.Ems.Common +namespace Spring.Messaging.Ems.Common; + +public class EmsSSLSystemStoreInfo : IEmsSSLStoreType { - public class EmsSSLSystemStoreInfo : IEmsSSLStoreType + private EMSSSLSystemStoreInfo emssslSystemStoreInfo; + + public EMSSSLSystemStoreInfo NativeEmssslSystemStoreInfo { + get { return emssslSystemStoreInfo; } + set { emssslSystemStoreInfo = value; } + } - private EMSSSLSystemStoreInfo emssslSystemStoreInfo; + public virtual EMSSSLSystemStoreInfo EmssslSystemStoreInfo + { + get { return emssslSystemStoreInfo; } + set { emssslSystemStoreInfo = value; } + } - public EMSSSLSystemStoreInfo NativeEmssslSystemStoreInfo - { - get { return emssslSystemStoreInfo; } - set { emssslSystemStoreInfo = value; } - } + public string CertificateNameAsFullSubjectDn + { + set { EmssslSystemStoreInfo.SetCertificateNameAsFullSubjectDN(value); } + } - public virtual EMSSSLSystemStoreInfo EmssslSystemStoreInfo - { - get { return emssslSystemStoreInfo; } - set { emssslSystemStoreInfo = value; } - } + public StoreLocation CertificateStoreLocation + { + set { EmssslSystemStoreInfo.SetCertificateStoreLocation(value); } + } - public string CertificateNameAsFullSubjectDn - { - set { EmssslSystemStoreInfo.SetCertificateNameAsFullSubjectDN(value); } - } - - public StoreLocation CertificateStoreLocation { - - set { EmssslSystemStoreInfo.SetCertificateStoreLocation(value); } - } - - public string CertificateStoreName - { - set { EmssslSystemStoreInfo.SetCertificateStoreName(value); } - } + public string CertificateStoreName + { + set { EmssslSystemStoreInfo.SetCertificateStoreName(value); } } } diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Common/EmsSession.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Common/EmsSession.cs index 3498ee89..02ad668b 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Common/EmsSession.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Common/EmsSession.cs @@ -18,191 +18,189 @@ #endregion -namespace Spring.Messaging.Ems.Common +namespace Spring.Messaging.Ems.Common; + +public class EmsSession : ISession { - public class EmsSession : ISession + private Session nativeSession; + + public EmsSession(Session session) { - private Session nativeSession; - - public EmsSession(Session session) - { - this.nativeSession = session; - } - - #region Implementation of ISession - - public Session NativeSession - { - get { return this.nativeSession; } - } - - public void Close() - { - nativeSession.Close(); - } - - public void Commit() - { - nativeSession.Commit(); - } - - public QueueBrowser CreateBrowser(Queue queue) - { - return nativeSession.CreateBrowser(queue); - } - - public QueueBrowser CreateBrowser(Queue queue, string messageSelector) - { - return nativeSession.CreateBrowser(queue, messageSelector); - } - - public BytesMessage CreateBytesMessage() - { - return nativeSession.CreateBytesMessage(); - } - - public IMessageConsumer CreateConsumer(Destination dest) - { - return new EmsMessageConsumer(nativeSession.CreateConsumer(dest)); - - } - - public IMessageConsumer CreateConsumer(Destination dest, string messageSelector) - { - return new EmsMessageConsumer(nativeSession.CreateConsumer(dest, messageSelector)); - } - - public IMessageConsumer CreateConsumer(Destination dest, string messageSelector, bool noLocal) - { - return new EmsMessageConsumer(nativeSession.CreateConsumer(dest, messageSelector, noLocal)); - } - - public ITopicSubscriber CreateDurableSubscriber(Topic topic, string name) - { - return new EmsTopicSubscriber(nativeSession.CreateDurableSubscriber(topic, name)); - } - - public ITopicSubscriber CreateDurableSubscriber(Topic topic, string name, string messageSelector, bool noLocal) - { - return new EmsTopicSubscriber(nativeSession.CreateDurableSubscriber(topic, name, messageSelector, noLocal)); - } - - public MapMessage CreateMapMessage() - { - return nativeSession.CreateMapMessage(); - } - - public Message CreateMessage() - { - return nativeSession.CreateMessage(); - } - - public ObjectMessage CreateObjectMessage() - { - return nativeSession.CreateObjectMessage(); - } - - public ObjectMessage CreateObjectMessage(object obj) - { - return nativeSession.CreateObjectMessage(obj); - } - - public IMessageProducer CreateProducer(Destination dest) - { - return new EmsMessageProducer(nativeSession.CreateProducer(dest)); - } - - public Queue CreateQueue(string queueName) - { - return nativeSession.CreateQueue(queueName); - } - - public StreamMessage CreateStreamMessage() - { - return nativeSession.CreateStreamMessage(); - } - - public TemporaryQueue CreateTemporaryQueue() - { - return nativeSession.CreateTemporaryQueue(); - } - - public TemporaryTopic CreateTemporaryTopic() - { - return nativeSession.CreateTemporaryTopic(); - } - - public TextMessage CreateTextMessage() - { - return nativeSession.CreateTextMessage(); - } - - public TextMessage CreateTextMessage(string text) - { - return nativeSession.CreateTextMessage(text); - } - - public Topic CreateTopic(string topicName) - { - return nativeSession.CreateTopic(topicName); - } - - public void Recover() - { - nativeSession.Recover(); - } - - public void Rollback() - { - nativeSession.Rollback(); - } - - public void Run() - { - nativeSession.Run(); - } - - public void Unsubscribe(string name) - { - nativeSession.Unsubscribe(name); - } - - public int AcknowledgeMode - { - get { return nativeSession.AcknowledgeMode; } - } - - // TODO - public Connection Connection - { - get { return nativeSession.Connection; } - } - - public bool IsClosed - { - get { return nativeSession.IsClosed; } - } - - public bool IsTransacted - { - get { return nativeSession.IsTransacted; } - } - - public long SessID - { - get { return nativeSession.SessID; } - } - - public SessionMode SessionAcknowledgeMode - { - get { return nativeSession.SessionAcknowledgeMode; } - } - - public bool Transacted - { - get { return nativeSession.Transacted; } - } - - #endregion + this.nativeSession = session; } -} + + #region Implementation of ISession + + public Session NativeSession + { + get { return this.nativeSession; } + } + + public void Close() + { + nativeSession.Close(); + } + + public void Commit() + { + nativeSession.Commit(); + } + + public QueueBrowser CreateBrowser(Queue queue) + { + return nativeSession.CreateBrowser(queue); + } + + public QueueBrowser CreateBrowser(Queue queue, string messageSelector) + { + return nativeSession.CreateBrowser(queue, messageSelector); + } + + public BytesMessage CreateBytesMessage() + { + return nativeSession.CreateBytesMessage(); + } + + public IMessageConsumer CreateConsumer(Destination dest) + { + return new EmsMessageConsumer(nativeSession.CreateConsumer(dest)); + } + + public IMessageConsumer CreateConsumer(Destination dest, string messageSelector) + { + return new EmsMessageConsumer(nativeSession.CreateConsumer(dest, messageSelector)); + } + + public IMessageConsumer CreateConsumer(Destination dest, string messageSelector, bool noLocal) + { + return new EmsMessageConsumer(nativeSession.CreateConsumer(dest, messageSelector, noLocal)); + } + + public ITopicSubscriber CreateDurableSubscriber(Topic topic, string name) + { + return new EmsTopicSubscriber(nativeSession.CreateDurableSubscriber(topic, name)); + } + + public ITopicSubscriber CreateDurableSubscriber(Topic topic, string name, string messageSelector, bool noLocal) + { + return new EmsTopicSubscriber(nativeSession.CreateDurableSubscriber(topic, name, messageSelector, noLocal)); + } + + public MapMessage CreateMapMessage() + { + return nativeSession.CreateMapMessage(); + } + + public Message CreateMessage() + { + return nativeSession.CreateMessage(); + } + + public ObjectMessage CreateObjectMessage() + { + return nativeSession.CreateObjectMessage(); + } + + public ObjectMessage CreateObjectMessage(object obj) + { + return nativeSession.CreateObjectMessage(obj); + } + + public IMessageProducer CreateProducer(Destination dest) + { + return new EmsMessageProducer(nativeSession.CreateProducer(dest)); + } + + public Queue CreateQueue(string queueName) + { + return nativeSession.CreateQueue(queueName); + } + + public StreamMessage CreateStreamMessage() + { + return nativeSession.CreateStreamMessage(); + } + + public TemporaryQueue CreateTemporaryQueue() + { + return nativeSession.CreateTemporaryQueue(); + } + + public TemporaryTopic CreateTemporaryTopic() + { + return nativeSession.CreateTemporaryTopic(); + } + + public TextMessage CreateTextMessage() + { + return nativeSession.CreateTextMessage(); + } + + public TextMessage CreateTextMessage(string text) + { + return nativeSession.CreateTextMessage(text); + } + + public Topic CreateTopic(string topicName) + { + return nativeSession.CreateTopic(topicName); + } + + public void Recover() + { + nativeSession.Recover(); + } + + public void Rollback() + { + nativeSession.Rollback(); + } + + public void Run() + { + nativeSession.Run(); + } + + public void Unsubscribe(string name) + { + nativeSession.Unsubscribe(name); + } + + public int AcknowledgeMode + { + get { return nativeSession.AcknowledgeMode; } + } + + // TODO + public Connection Connection + { + get { return nativeSession.Connection; } + } + + public bool IsClosed + { + get { return nativeSession.IsClosed; } + } + + public bool IsTransacted + { + get { return nativeSession.IsTransacted; } + } + + public long SessID + { + get { return nativeSession.SessID; } + } + + public SessionMode SessionAcknowledgeMode + { + get { return nativeSession.SessionAcknowledgeMode; } + } + + public bool Transacted + { + get { return nativeSession.Transacted; } + } + + #endregion +} \ No newline at end of file diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Common/EmsTopicSubscriber.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Common/EmsTopicSubscriber.cs index 15b62dc4..0902dcb2 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Common/EmsTopicSubscriber.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Common/EmsTopicSubscriber.cs @@ -18,27 +18,26 @@ #endregion -namespace Spring.Messaging.Ems.Common +namespace Spring.Messaging.Ems.Common; + +public class EmsTopicSubscriber : EmsMessageConsumer, ITopicSubscriber { - public class EmsTopicSubscriber : EmsMessageConsumer, ITopicSubscriber + public EmsTopicSubscriber(TopicSubscriber topicSubscriber) + : base(topicSubscriber) { - public EmsTopicSubscriber(TopicSubscriber topicSubscriber) - : base(topicSubscriber) - { - } - - #region Implementation of ITopicSubscriber - - public bool NoLocal - { - get { return ((TopicSubscriber) nativeMessageConsumer).NoLocal; } - } - - public Topic Topic - { - get { return ((TopicSubscriber) nativeMessageConsumer).Topic; } - } - - #endregion } + + #region Implementation of ITopicSubscriber + + public bool NoLocal + { + get { return ((TopicSubscriber) nativeMessageConsumer).NoLocal; } + } + + public Topic Topic + { + get { return ((TopicSubscriber) nativeMessageConsumer).Topic; } + } + + #endregion } diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Common/IConnection.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Common/IConnection.cs index a3dd1f4c..9f6d4c4b 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Common/IConnection.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Common/IConnection.cs @@ -20,115 +20,113 @@ using System.ComponentModel; -namespace Spring.Messaging.Ems.Common +namespace Spring.Messaging.Ems.Common; + +/// +/// An interface containing all methods and properties on the TIBCO.EMS.Connection class. +/// Refer to the TIBCO EMS API documentation for more information. +/// +/// Mark Pollack +public interface IConnection { /// - /// An interface containing all methods and properties on the TIBCO.EMS.Connection class. - /// Refer to the TIBCO EMS API documentation for more information. + /// Gets the native TIBCO EMS connection. /// - /// Mark Pollack - public interface IConnection - { - /// - /// Gets the native TIBCO EMS connection. - /// - /// The native connection. - Connection NativeConnection { get; } + /// The native connection. + Connection NativeConnection { get; } - /// - /// Occurs when the client library detects a problem with the connection. - /// - event EMSExceptionHandler EMSExceptionHandler; + /// + /// Occurs when the client library detects a problem with the connection. + /// + event EMSExceptionHandler EMSExceptionHandler; - /// - /// Gets the URL of the server this connection is currently connected to - /// - /// The active URL. - string ActiveURL { get; } + /// + /// Gets the URL of the server this connection is currently connected to + /// + /// The active URL. + string ActiveURL { get; } + /// + /// Gets or sets the client ID. + /// + /// The client ID. + string ClientID { get; set; } - /// - /// Gets or sets the client ID. - /// - /// The client ID. - string ClientID { get; set; } + /// + /// Gets the connection ID. + /// + /// The connection ID. + [EditorBrowsable(EditorBrowsableState.Never)] + long ConnID { get; } - /// - /// Gets the connection ID. - /// - /// The connection ID. - [EditorBrowsable(EditorBrowsableState.Never)] - long ConnID { get; } + /// + /// Gets or sets the exception listener. + /// + /// The exception listener. + IExceptionListener ExceptionListener { get; set; } - /// - /// Gets or sets the exception listener. - /// - /// The exception listener. - IExceptionListener ExceptionListener { get; set; } + /// + /// Gets a value indicating whether the connection is closed. + /// + /// true if the connection is closed; otherwise, false. + bool IsClosed { get; } - /// - /// Gets a value indicating whether the connection is closed. - /// - /// true if the connection is closed; otherwise, false. - bool IsClosed { get; } + /// + /// Gets a value indicating whether the connection communicates with a secure protocol + /// + /// true if the connection communicates with a secure protocol; otherwise, false. + [EditorBrowsable(EditorBrowsableState.Never)] + bool IsSecure { get; } - /// - /// Gets a value indicating whether the connection communicates with a secure protocol - /// - /// true if the connection communicates with a secure protocol; otherwise, false. - [EditorBrowsable(EditorBrowsableState.Never)] - bool IsSecure { get; } + /// + /// Gets the metadata for this connection + /// + /// The metadata for this connection. + ConnectionMetaData MetaData { get; } - /// - /// Gets the metadata for this connection - /// - /// The metadata for this connection. - ConnectionMetaData MetaData { get; } + /// + /// Closes the connection and reclaims resources. + /// + void Close(); - /// - /// Closes the connection and reclaims resources. - /// - void Close(); + /// + /// Creates the session. + /// + /// if set to true the session has transaction semantcis. + /// Indicates whether and how the consumer is to acknowledge received messages. + /// This version of CreateSession accepts an integer value associated with the acknowledge mode described by a Session member and should only be used for backward compatibility. + /// This parameter is ignored if the session is transacted. + /// A newly created session. + ISession CreateSession(bool transacted, int acknowledgeMode); - /// - /// Creates the session. - /// - /// if set to true the session has transaction semantcis. - /// Indicates whether and how the consumer is to acknowledge received messages. - /// This version of CreateSession accepts an integer value associated with the acknowledge mode described by a Session member and should only be used for backward compatibility. - /// This parameter is ignored if the session is transacted. - /// A newly created session. - ISession CreateSession(bool transacted, int acknowledgeMode); + /// + /// Creates the session. + /// + /// if set to true [transacted]. + /// The acknowledge mode. + /// When true, the new session has transaction semantics. + /// Indicates whether and how the consumer is to acknowledge received messages. + /// Legal values are listed under SessionMode. + /// This parameter is ignored if the session is transacted. + /// + /// A newly created session. + ISession CreateSession(bool transacted, SessionMode acknowledgeMode); - /// - /// Creates the session. - /// - /// if set to true [transacted]. - /// The acknowledge mode. - /// When true, the new session has transaction semantics. - /// Indicates whether and how the consumer is to acknowledge received messages. - /// Legal values are listed under SessionMode. - /// This parameter is ignored if the session is transacted. - /// - /// A newly created session. - ISession CreateSession(bool transacted, SessionMode acknowledgeMode); + /// + /// Starts (or restarts) a connection's delivery of incoming messages. + /// + void Start(); - /// - /// Starts (or restarts) a connection's delivery of incoming messages. - /// - void Start(); + /// + /// Temporarily stops a connection's delivery of incoming messages. + /// + void Stop(); - /// - /// Temporarily stops a connection's delivery of incoming messages. - /// - void Stop(); - - /// - /// A String representation of the connection object - /// - /// - /// A that represents this instance. - /// - string ToString(); - } -} + /// + /// A String representation of the connection object + /// + /// + /// A that represents this instance. + /// + string ToString(); +} \ No newline at end of file diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Common/IConnectionFactory.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Common/IConnectionFactory.cs index d56c84d8..6a596e63 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Common/IConnectionFactory.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Common/IConnectionFactory.cs @@ -20,152 +20,151 @@ using System.Runtime.Serialization; -namespace Spring.Messaging.Ems.Common +namespace Spring.Messaging.Ems.Common; + +/// +/// An interface containing all methods and properties on the TIBCO.EMS.ConnectionFactory class. +/// Refer to the TIBCO EMS API documentation for more information. +/// +/// +/// All the 'GetXXX()' methods in the TIBCO.EMS.ConnectionFactory were translated to .NET properties +/// +/// Mark Pollack +public interface IConnectionFactory : ISerializable, ICloneable { /// - /// An interface containing all methods and properties on the TIBCO.EMS.ConnectionFactory class. - /// Refer to the TIBCO EMS API documentation for more information. + /// Gets the native TIBCO EMS connection factory. /// - /// - /// All the 'GetXXX()' methods in the TIBCO.EMS.ConnectionFactory were translated to .NET properties - /// - /// Mark Pollack - public interface IConnectionFactory : ISerializable, ICloneable - { - /// - /// Gets the native TIBCO EMS connection factory. - /// - /// The native connection factory. - ConnectionFactory NativeConnectionFactory { get; } + /// The native connection factory. + ConnectionFactory NativeConnectionFactory { get; } - /// - /// Creates the connection. - /// - /// The newly created connection - IConnection CreateConnection(); + /// + /// Creates the connection. + /// + /// The newly created connection + IConnection CreateConnection(); - /// - /// Creates the connection with the given username and password - /// - /// Name of the user. - /// The password. - /// - IConnection CreateConnection(string userName, string password); + /// + /// Creates the connection with the given username and password + /// + /// Name of the user. + /// The password. + /// + IConnection CreateConnection(string userName, string password); - /// - /// Gets the certificate store info object associated with this connection factory. - /// - /// The certificate store. - object CertificateStore { get; } + /// + /// Gets the certificate store info object associated with this connection factory. + /// + /// The certificate store. + object CertificateStore { get; } - /// - /// Gets or sets the SSL proxy host. - /// - /// The SSL proxy host. - string SSLProxyHost { set; get; } + /// + /// Gets or sets the SSL proxy host. + /// + /// The SSL proxy host. + string SSLProxyHost { set; get; } - /// - /// Gets or sets the SSL proxy port. - /// - /// The SSL proxy port. - int SSLProxyPort { set; get; } + /// + /// Gets or sets the SSL proxy port. + /// + /// The SSL proxy port. + int SSLProxyPort { set; get; } - /// - /// Gets the SSL proxy password. - /// - /// The SSL proxy password. - string SSLProxyPassword { get; } + /// + /// Gets the SSL proxy password. + /// + /// The SSL proxy password. + string SSLProxyPassword { get; } - /// - /// Gets the SSL proxy user. - /// - /// The SSL proxy user. - string SSLProxyUser { get; } + /// + /// Gets the SSL proxy user. + /// + /// The SSL proxy user. + string SSLProxyUser { get; } - /// - /// Sets the type of the certificate store. - /// - /// The type of the certificate store. - IEmsSSLStoreType CertificateStoreType { set; } + /// + /// Sets the type of the certificate store. + /// + /// The type of the certificate store. + IEmsSSLStoreType CertificateStoreType { set; } - /// - /// Sets the client ID. - /// - /// The client ID. - string ClientID { set; } + /// + /// Sets the client ID. + /// + /// The client ID. + string ClientID { set; } - /// - /// Sets the client tracer to a given output stream - /// - /// The client tracer. - StreamWriter ClientTracer { set; } + /// + /// Sets the client tracer to a given output stream + /// + /// The client tracer. + StreamWriter ClientTracer { set; } - /// - /// Sets the number of connection attempts - /// - /// The number of connection attempts. - int ConnAttemptCount { set; } + /// + /// Sets the number of connection attempts + /// + /// The number of connection attempts. + int ConnAttemptCount { set; } - /// - /// Sets delay between connection attempts - /// - /// The delay between connection attempts. - int ConnAttemptDelay { set; } + /// + /// Sets delay between connection attempts + /// + /// The delay between connection attempts. + int ConnAttemptDelay { set; } - /// - /// Sets the connection attempt timeout. - /// - /// The connection attempt timeout. - int ConnAttemptTimeout { set; } + /// + /// Sets the connection attempt timeout. + /// + /// The connection attempt timeout. + int ConnAttemptTimeout { set; } - /// - /// Sets the custom host name verifier. Set to null to remove custom host name verifier. - /// - /// The host name verifier. - EMSSSLHostNameVerifier HostNameVerifier { set; } + /// + /// Sets the custom host name verifier. Set to null to remove custom host name verifier. + /// + /// The host name verifier. + EMSSSLHostNameVerifier HostNameVerifier { set; } - /// - /// Sets the load balance metric as an integer. - /// - /// The load balance metric as int. - int MetricAsInt { set; } + /// + /// Sets the load balance metric as an integer. + /// + /// The load balance metric as int. + int MetricAsInt { set; } - /// - /// Sets the port on which the client will connect to the multicast daemon. - /// - /// The multicast daemon port. - string MulticastDaemon { set; } + /// + /// Sets the port on which the client will connect to the multicast daemon. + /// + /// The multicast daemon port. + string MulticastDaemon { set; } - /// - /// Sets whether MessageConsumers subscribed to a multicast-enabled topic will receive messages over multicast. - /// - /// true to enable multicast; false to disable. - bool MulticastEnabled { set; } + /// + /// Sets whether MessageConsumers subscribed to a multicast-enabled topic will receive messages over multicast. + /// + /// true to enable multicast; false to disable. + bool MulticastEnabled { set; } - int ReconnAttemptCount { set; } + int ReconnAttemptCount { set; } - int ReconnAttemptDelay { set; } + int ReconnAttemptDelay { set; } - int ReconnAttemptTimeout { set; } + int ReconnAttemptTimeout { set; } - string ServerUrl { set; } + string ServerUrl { set; } - bool SSLAuthOnly { set; } + bool SSLAuthOnly { set; } - string SSLProxyAuthUsername { set; get; } + string SSLProxyAuthUsername { set; get; } - string SSLProxyAuthPassword { set; get; } + string SSLProxyAuthPassword { set; get; } - bool SSLTrace { set; } + bool SSLTrace { set; } - string TargetHostName { set; } + string TargetHostName { set; } - string UserName { set; } + string UserName { set; } - string UserPassword { set; } + string UserPassword { set; } - string ToString(); + string ToString(); - FactoryLoadBalanceMetric Metric { get; set; } - } + FactoryLoadBalanceMetric Metric { get; set; } } diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Common/IEmsSSLStoreType.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Common/IEmsSSLStoreType.cs index bd2e4c62..46fa2c08 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Common/IEmsSSLStoreType.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Common/IEmsSSLStoreType.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2010 the original author or authors. + * Copyright � 2002-2010 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. @@ -18,13 +18,11 @@ #endregion -namespace Spring.Messaging.Ems.Common +namespace Spring.Messaging.Ems.Common; + +/// +/// Market interface for EMS SSL store types +/// +public interface IEmsSSLStoreType { - /// - /// Market interface for EMS SSL store types - /// - public interface IEmsSSLStoreType - { - - } -} \ No newline at end of file +} diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Common/IMessageConsumer.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Common/IMessageConsumer.cs index 739f1def..dd5d8310 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Common/IMessageConsumer.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Common/IMessageConsumer.cs @@ -18,18 +18,17 @@ #endregion -namespace Spring.Messaging.Ems.Common +namespace Spring.Messaging.Ems.Common; + +public interface IMessageConsumer { - public interface IMessageConsumer - { - MessageConsumer NativeMessageConsumer { get; } - event EMSMessageHandler MessageHandler; - IMessageListener MessageListener { get; set; } - string MessageSelector { get; } - void Close(); - Message Receive(); - Message Receive(long timeout); - Message ReceiveNoWait(); - string ToString(); - } + MessageConsumer NativeMessageConsumer { get; } + event EMSMessageHandler MessageHandler; + IMessageListener MessageListener { get; set; } + string MessageSelector { get; } + void Close(); + Message Receive(); + Message Receive(long timeout); + Message ReceiveNoWait(); + string ToString(); } diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Common/IMessageProducer.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Common/IMessageProducer.cs index 70eb58e4..56206121 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Common/IMessageProducer.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Common/IMessageProducer.cs @@ -18,33 +18,32 @@ #endregion -namespace Spring.Messaging.Ems.Common +namespace Spring.Messaging.Ems.Common; + +public interface IMessageProducer { - public interface IMessageProducer - { - MessageProducer NativeMessageProducer { get; } + MessageProducer NativeMessageProducer { get; } - void Close(); - void Send(Message message); - void Send(TIBCO.EMS.Destination dest, Message message); - void Send(Message message, int deliveryMode, int priority, long timeToLive); - void Send(Message message, MessageDeliveryMode deliveryMode, int priority, long timeToLive); - void Send(TIBCO.EMS.Destination dest, Message message, int deliveryMode, int priority, long timeToLive); - void Send(TIBCO.EMS.Destination dest, Message message, MessageDeliveryMode deliveryMode, int priority, long timeToLive); - string ToString(); - int DeliveryMode { get; set; } - TIBCO.EMS.Destination Destination { get; } - bool DisableMessageID { get; set; } - bool DisableMessageTimestamp { get; set; } - MessageDeliveryMode MsgDeliveryMode { get; set; } - int Priority { get; set; } + void Close(); + void Send(Message message); + void Send(TIBCO.EMS.Destination dest, Message message); + void Send(Message message, int deliveryMode, int priority, long timeToLive); + void Send(Message message, MessageDeliveryMode deliveryMode, int priority, long timeToLive); + void Send(TIBCO.EMS.Destination dest, Message message, int deliveryMode, int priority, long timeToLive); + void Send(TIBCO.EMS.Destination dest, Message message, MessageDeliveryMode deliveryMode, int priority, long timeToLive); + string ToString(); + int DeliveryMode { get; set; } + TIBCO.EMS.Destination Destination { get; } + bool DisableMessageID { get; set; } + bool DisableMessageTimestamp { get; set; } + MessageDeliveryMode MsgDeliveryMode { get; set; } + int Priority { get; set; } - /// - /// Gets or sets the the default length of time in milliseconds from its dispatch time - /// that a produced message should be retained by the message system. - /// - /// Time to live is set to zero by default. - /// The message time to live in milliseconds; zero is unlimited - long TimeToLive { get; set; } - } + /// + /// Gets or sets the the default length of time in milliseconds from its dispatch time + /// that a produced message should be retained by the message system. + /// + /// Time to live is set to zero by default. + /// The message time to live in milliseconds; zero is unlimited + long TimeToLive { get; set; } } diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Common/ISession.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Common/ISession.cs index eb519285..795237cf 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Common/ISession.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Common/ISession.cs @@ -20,72 +20,71 @@ using System.ComponentModel; -namespace Spring.Messaging.Ems.Common +namespace Spring.Messaging.Ems.Common; + +public interface ISession { - public interface ISession - { - Session NativeSession { get; } + Session NativeSession { get; } - void Close(); + void Close(); - void Commit(); + void Commit(); - QueueBrowser CreateBrowser(Queue queue); + QueueBrowser CreateBrowser(Queue queue); - QueueBrowser CreateBrowser(Queue queue, string messageSelector); + QueueBrowser CreateBrowser(Queue queue, string messageSelector); - IMessageConsumer CreateConsumer(Destination dest); + IMessageConsumer CreateConsumer(Destination dest); - IMessageConsumer CreateConsumer(Destination dest, string messageSelector); + IMessageConsumer CreateConsumer(Destination dest, string messageSelector); - IMessageConsumer CreateConsumer(Destination dest, string messageSelector, bool noLocal); + IMessageConsumer CreateConsumer(Destination dest, string messageSelector, bool noLocal); - ITopicSubscriber CreateDurableSubscriber(Topic topic, string name); + ITopicSubscriber CreateDurableSubscriber(Topic topic, string name); - ITopicSubscriber CreateDurableSubscriber(Topic topic, string name, string messageSelector, bool noLocal); + ITopicSubscriber CreateDurableSubscriber(Topic topic, string name, string messageSelector, bool noLocal); - IMessageProducer CreateProducer(Destination dest); + IMessageProducer CreateProducer(Destination dest); - Queue CreateQueue(string queueName); + Queue CreateQueue(string queueName); - Topic CreateTopic(string topicName); + Topic CreateTopic(string topicName); - TemporaryQueue CreateTemporaryQueue(); + TemporaryQueue CreateTemporaryQueue(); - TemporaryTopic CreateTemporaryTopic(); + TemporaryTopic CreateTemporaryTopic(); - Message CreateMessage(); + Message CreateMessage(); - TextMessage CreateTextMessage(); + TextMessage CreateTextMessage(); - TextMessage CreateTextMessage(string text); + TextMessage CreateTextMessage(string text); - MapMessage CreateMapMessage(); + MapMessage CreateMapMessage(); - BytesMessage CreateBytesMessage(); + BytesMessage CreateBytesMessage(); - ObjectMessage CreateObjectMessage(); + ObjectMessage CreateObjectMessage(); - ObjectMessage CreateObjectMessage(object obj); + ObjectMessage CreateObjectMessage(object obj); - StreamMessage CreateStreamMessage(); + StreamMessage CreateStreamMessage(); - void Recover(); + void Recover(); - void Rollback(); + void Rollback(); - [EditorBrowsable(EditorBrowsableState.Never), Obsolete("Ordinary JMS clients should not use this method.")] - void Run(); + [EditorBrowsable(EditorBrowsableState.Never), Obsolete("Ordinary JMS clients should not use this method.")] + void Run(); - void Unsubscribe(string name); + void Unsubscribe(string name); - int AcknowledgeMode { get; } - TIBCO.EMS.Connection Connection { get; } - bool IsClosed { get; } - bool IsTransacted { get; } + int AcknowledgeMode { get; } + TIBCO.EMS.Connection Connection { get; } + bool IsClosed { get; } + bool IsTransacted { get; } - long SessID { get; } - SessionMode SessionAcknowledgeMode { get; } - bool Transacted { get; } - } + long SessID { get; } + SessionMode SessionAcknowledgeMode { get; } + bool Transacted { get; } } diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Common/ITopicSubscriber.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Common/ITopicSubscriber.cs index b369d7db..716f91a9 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Common/ITopicSubscriber.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Common/ITopicSubscriber.cs @@ -18,11 +18,10 @@ #endregion -namespace Spring.Messaging.Ems.Common +namespace Spring.Messaging.Ems.Common; + +public interface ITopicSubscriber : IMessageConsumer { - public interface ITopicSubscriber : IMessageConsumer - { - bool NoLocal { get; } - Topic Topic { get; } - } + bool NoLocal { get; } + Topic Topic { get; } } diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Config/EmsNamespaceParser.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Config/EmsNamespaceParser.cs index 1462f68e..58a95f7f 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Config/EmsNamespaceParser.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Config/EmsNamespaceParser.cs @@ -20,29 +20,28 @@ using Spring.Objects.Factory.Xml; -namespace Spring.Messaging.Ems.Config +namespace Spring.Messaging.Ems.Config; + +/// +/// Namespace parser for the EMS namespace. +/// +/// Mark Fisher +/// Juergen Hoeller +/// Mark Pollack (.NET) +[ + NamespaceParser( + Namespace = "http://www.springframework.net/ems", + SchemaLocationAssemblyHint = typeof(EmsNamespaceParser), + SchemaLocation = "/Spring.Messaging.Ems.Config/spring-ems-1.3.xsd" + ) +] +public class EmsNamespaceParser : NamespaceParserSupport { /// - /// Namespace parser for the EMS namespace. + /// Register a MessageListenerContainer for the 'listener-container' tag. /// - /// Mark Fisher - /// Juergen Hoeller - /// Mark Pollack (.NET) - [ - NamespaceParser( - Namespace = "http://www.springframework.net/ems", - SchemaLocationAssemblyHint = typeof (EmsNamespaceParser), - SchemaLocation = "/Spring.Messaging.Ems.Config/spring-ems-1.3.xsd" - ) - ] - public class EmsNamespaceParser : NamespaceParserSupport + public override void Init() { - /// - /// Register a MessageListenerContainer for the 'listener-container' tag. - /// - public override void Init() - { - RegisterObjectDefinitionParser("listener-container", new MessageListenerContainerObjectDefinitionParser()); - } + RegisterObjectDefinitionParser("listener-container", new MessageListenerContainerObjectDefinitionParser()); } } diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Config/MessageListenerContainerObjectDefinitionParser.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Config/MessageListenerContainerObjectDefinitionParser.cs index d73b9cd9..6d3a0ce8 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Config/MessageListenerContainerObjectDefinitionParser.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Config/MessageListenerContainerObjectDefinitionParser.cs @@ -28,427 +28,434 @@ using Spring.Objects.Factory.Support; using Spring.Objects.Factory.Xml; using Spring.Util; -namespace Spring.Messaging.Ems.Config +namespace Spring.Messaging.Ems.Config; + +/// +/// Parser for the EMS <listener-container> element. +/// +/// Mark Fisher +/// Juergen Hoeller +/// Mark Pollack (.NET) +public class MessageListenerContainerObjectDefinitionParser : IObjectDefinitionParser { + #region Fields + + private readonly string LISTENER_ELEMENT = "listener"; + + private readonly string ID_ATTRIBUTE = "id"; + + private readonly string DESTINATION_ATTRIBUTE = "destination"; + + private readonly string SUBSCRIPTION_ATTRIBUTE = "subscription"; + + private readonly string SELECTOR_ATTRIBUTE = "selector"; + + private readonly string REF_ATTRIBUTE = "ref"; + + private readonly string METHOD_ATTRIBUTE = "method"; + + private readonly string DESTINATION_RESOLVER_ATTRIBUTE = "destination-resolver"; + + private readonly string MESSAGE_CONVERTER_ATTRIBUTE = "message-converter"; + + private readonly string RESPONSE_DESTINATION_ATTRIBUTE = "response-destination"; + + private readonly string DESTINATION_TYPE_ATTRIBUTE = "destination-type"; + + private readonly string DESTINATION_TYPE_QUEUE = "queue"; + + private readonly string DESTINATION_TYPE_TOPIC = "topic"; + + private readonly string DESTINATION_TYPE_DURABLE_TOPIC = "durableTopic"; + + private readonly string CLIENT_ID_ATTRIBUTE = "client-id"; + + private readonly string ACKNOWLEDGE_ATTRIBUTE = "acknowledge"; + + private readonly string ACKNOWLEDGE_AUTO = "auto"; + + private readonly string ACKNOWLEDGE_CLIENT = "client"; + + private readonly string ACKNOWLEDGE_DUPS_OK = "dups-ok"; + + private readonly string ACKNOWLEDGE_TRANSACTED = "transacted"; + + private readonly string CONCURRENCY_ATTRIBUTE = "concurrency"; + + private readonly string RECOVERY_INTERVAL_ATTRIBUTE = "recovery-interval"; + + private readonly string MAX_RECOVERY_TIME_ATTRIBUTE = "max-recovery-time"; + + private readonly string CONNECTION_FACTORY_ATTRIBUTE = "connection-factory"; + + private readonly string CONTAINER_CUSTOM_TYPE = "container-custom-type"; + + private readonly string PUBSUB_DOMAIN_ATTRIBUTE = "pubsub-domain"; + + private readonly string AUTO_STARTUP = "auto-startup"; + + private readonly string ERROR_HANDLER_ATTRIBUTE = "error-handler"; + + private readonly string EXCEPTION_LISTENER_ATTRIBUTE = "exception-listener"; + + #endregion + + #region IObjectDefinitionParser Members + /// - /// Parser for the EMS <listener-container> element. + /// Parse the specified XmlElement and register the resulting + /// ObjectDefinitions with the IObjectDefinitionRegistry + /// embedded in the supplied /// - /// Mark Fisher - /// Juergen Hoeller - /// Mark Pollack (.NET) - public class MessageListenerContainerObjectDefinitionParser : IObjectDefinitionParser + /// The element to be parsed. + /// The object encapsulating the current state of the parsing process. + /// Provides access to a IObjectDefinitionRegistry + /// The primary object definition. + /// + ///

+ /// This method is never invoked if the parser is namespace aware + /// and was called to process the root node. + ///

+ ///
+ public IObjectDefinition ParseElement(XmlElement element, ParserContext parserContext) { - #region Fields - - private readonly string LISTENER_ELEMENT = "listener"; - - private readonly string ID_ATTRIBUTE = "id"; - - private readonly string DESTINATION_ATTRIBUTE = "destination"; - - private readonly string SUBSCRIPTION_ATTRIBUTE = "subscription"; - - private readonly string SELECTOR_ATTRIBUTE = "selector"; - - private readonly string REF_ATTRIBUTE = "ref"; - - private readonly string METHOD_ATTRIBUTE = "method"; - - private readonly string DESTINATION_RESOLVER_ATTRIBUTE = "destination-resolver"; - - private readonly string MESSAGE_CONVERTER_ATTRIBUTE = "message-converter"; - - private readonly string RESPONSE_DESTINATION_ATTRIBUTE = "response-destination"; - - private readonly string DESTINATION_TYPE_ATTRIBUTE = "destination-type"; - - private readonly string DESTINATION_TYPE_QUEUE = "queue"; - - private readonly string DESTINATION_TYPE_TOPIC = "topic"; - - private readonly string DESTINATION_TYPE_DURABLE_TOPIC = "durableTopic"; - - private readonly string CLIENT_ID_ATTRIBUTE = "client-id"; - - private readonly string ACKNOWLEDGE_ATTRIBUTE = "acknowledge"; - - private readonly string ACKNOWLEDGE_AUTO = "auto"; - - private readonly string ACKNOWLEDGE_CLIENT = "client"; - - private readonly string ACKNOWLEDGE_DUPS_OK = "dups-ok"; - - private readonly string ACKNOWLEDGE_TRANSACTED = "transacted"; - - private readonly string CONCURRENCY_ATTRIBUTE = "concurrency"; - - private readonly string RECOVERY_INTERVAL_ATTRIBUTE = "recovery-interval"; - - private readonly string MAX_RECOVERY_TIME_ATTRIBUTE = "max-recovery-time"; - - private readonly string CONNECTION_FACTORY_ATTRIBUTE = "connection-factory"; - - private readonly string CONTAINER_CUSTOM_TYPE = "container-custom-type"; - - private readonly string PUBSUB_DOMAIN_ATTRIBUTE = "pubsub-domain"; - - private readonly string AUTO_STARTUP = "auto-startup"; - - private readonly string ERROR_HANDLER_ATTRIBUTE = "error-handler"; - - private readonly string EXCEPTION_LISTENER_ATTRIBUTE = "exception-listener"; - - #endregion - - #region IObjectDefinitionParser Members - - /// - /// Parse the specified XmlElement and register the resulting - /// ObjectDefinitions with the IObjectDefinitionRegistry - /// embedded in the supplied - /// - /// The element to be parsed. - /// The object encapsulating the current state of the parsing process. - /// Provides access to a IObjectDefinitionRegistry - /// The primary object definition. - /// - ///

- /// This method is never invoked if the parser is namespace aware - /// and was called to process the root node. - ///

- ///
- public IObjectDefinition ParseElement(XmlElement element, ParserContext parserContext) + XmlNodeList childNodes = element.ChildNodes; + foreach (XmlNode childNode in childNodes) { - - XmlNodeList childNodes = element.ChildNodes; - foreach (XmlNode childNode in childNodes) + if (childNode.NodeType == XmlNodeType.Element) { - if (childNode.NodeType == XmlNodeType.Element) + string localName = childNode.LocalName; + if (LISTENER_ELEMENT.Equals(localName)) { - string localName = childNode.LocalName; - if (LISTENER_ELEMENT.Equals(localName)) - { - ParseListener((XmlElement) childNode, element, parserContext); - } + ParseListener((XmlElement) childNode, element, parserContext); } } - return null; } - #endregion + return null; + } - private void ParseListener(XmlElement listenerElement, XmlElement containerElement, ParserContext parserContext) + #endregion + + private void ParseListener(XmlElement listenerElement, XmlElement containerElement, ParserContext parserContext) + { + ObjectDefinitionBuilder listenerDefBuilder = + parserContext.ParserHelper.CreateRootObjectDefinitionBuilder(typeof(MessageListenerAdapter)); + + string reference = listenerElement.GetAttribute(REF_ATTRIBUTE); + if (!StringUtils.HasText(reference)) { - ObjectDefinitionBuilder listenerDefBuilder = - parserContext.ParserHelper.CreateRootObjectDefinitionBuilder(typeof (MessageListenerAdapter)); - - string reference = listenerElement.GetAttribute(REF_ATTRIBUTE); - if (!StringUtils.HasText(reference)) - { - parserContext.ReaderContext.ReportException(listenerElement, LISTENER_ELEMENT, - "Listener '" + REF_ATTRIBUTE + - "' attribute contains empty value."); - } - listenerDefBuilder.AddPropertyValue("HandlerObject", new RuntimeObjectReference(reference)); - - string handlerMethod = null; - if (listenerElement.HasAttribute(METHOD_ATTRIBUTE)) - { - handlerMethod = listenerElement.GetAttribute(METHOD_ATTRIBUTE); - { - if (!StringUtils.HasText(handlerMethod)) - { - parserContext.ReaderContext.ReportException(listenerElement, LISTENER_ELEMENT, - "Listener '" + METHOD_ATTRIBUTE + - "' attribute contains empty value."); - } - } - } - listenerDefBuilder.AddPropertyValue("DefaultHandlerMethod", handlerMethod); - - if (containerElement.HasAttribute(MESSAGE_CONVERTER_ATTRIBUTE)) - { - string messageConverter = containerElement.GetAttribute(MESSAGE_CONVERTER_ATTRIBUTE); - listenerDefBuilder.AddPropertyValue("MessageConverter", new RuntimeObjectReference(messageConverter)); - } - - ObjectDefinitionBuilder containerDefBuilder = ParseContainer(listenerElement, containerElement, parserContext); - - if (listenerElement.HasAttribute(RESPONSE_DESTINATION_ATTRIBUTE)) - { - string responseDestination = listenerElement.GetAttribute(RESPONSE_DESTINATION_ATTRIBUTE); - bool pubSubDomain = IndicatesPubSub(containerDefBuilder.RawObjectDefinition); - listenerDefBuilder.AddPropertyValue(pubSubDomain ? "DefaultResponseTopicName" : "DefaultResponseQueueName", - responseDestination); - if (containerDefBuilder.RawObjectDefinition.PropertyValues.Contains("DestinationResolver")) - { - listenerDefBuilder.AddPropertyValue("DestinationResolver", - containerDefBuilder.RawObjectDefinition.PropertyValues.GetPropertyValue - ( - "DestinationResolver").Value); - } - } - - containerDefBuilder.AddPropertyValue("MessageListener", listenerDefBuilder.ObjectDefinition); - - string containerObjectName = listenerElement.GetAttribute(ID_ATTRIBUTE); - // If no object id is given auto generate one using the ReaderContext's ObjectNameGenerator - if (!StringUtils.HasText(containerObjectName)) - { - containerObjectName = - parserContext.ReaderContext.GenerateObjectName(containerDefBuilder.RawObjectDefinition); - } - - string pubsubDomain = listenerElement.GetAttribute(PUBSUB_DOMAIN_ATTRIBUTE); - containerDefBuilder.AddPropertyValue("PubSubDomain", pubsubDomain); - - parserContext.Registry.RegisterObjectDefinition(containerObjectName, containerDefBuilder.ObjectDefinition); + parserContext.ReaderContext.ReportException(listenerElement, LISTENER_ELEMENT, + "Listener '" + REF_ATTRIBUTE + + "' attribute contains empty value."); } - private ObjectDefinitionBuilder ParseContainer(XmlElement listenerElement, XmlElement containerElement, - ParserContext parserContext) + listenerDefBuilder.AddPropertyValue("HandlerObject", new RuntimeObjectReference(reference)); + + string handlerMethod = null; + if (listenerElement.HasAttribute(METHOD_ATTRIBUTE)) { - //Only support SimpleMessageListenerContainer or container-custom-type - - Type containerType = typeof(SimpleMessageListenerContainer); - if (containerElement.HasAttribute(CONTAINER_CUSTOM_TYPE)) + handlerMethod = listenerElement.GetAttribute(METHOD_ATTRIBUTE); { - string customType = containerElement.GetAttribute(CONTAINER_CUSTOM_TYPE); - if (!StringUtils.HasLength(customType)) - { - parserContext.ReaderContext.ReportException(containerElement, CONTAINER_CUSTOM_TYPE, - "Listener container '" + CONTAINER_CUSTOM_TYPE + - "' attribute contains empty value."); - } - try - { - containerType = TypeResolutionUtils.ResolveType(customType); - } - catch (Exception ex) - { - parserContext.ReaderContext.ReportException(containerElement, CONTAINER_CUSTOM_TYPE, - "Invalid container-custom-type value [" + customType + "]", ex); - } - } - //Only support SimpleMessageListenerContainer - ObjectDefinitionBuilder containerDef = - parserContext.ParserHelper.CreateRootObjectDefinitionBuilder(containerType); - - ParseListenerConfiguration(listenerElement, parserContext, containerDef); - ParseContainerConfiguration(containerElement, parserContext, containerDef); - - if (containerElement.HasAttribute(AUTO_STARTUP)) - { - string autoStartup = containerElement.GetAttribute(AUTO_STARTUP); - if (StringUtils.HasText(autoStartup)) - { - containerDef.AddPropertyValue("AutoStartup", autoStartup); - } - } - - string connectionFactoryObjectName = "connectionFactory"; - if (containerElement.HasAttribute(CONNECTION_FACTORY_ATTRIBUTE)) - { - connectionFactoryObjectName = containerElement.GetAttribute(CONNECTION_FACTORY_ATTRIBUTE); - if (!StringUtils.HasText(connectionFactoryObjectName)) + if (!StringUtils.HasText(handlerMethod)) { parserContext.ReaderContext.ReportException(listenerElement, LISTENER_ELEMENT, - "Listener container '" + CONNECTION_FACTORY_ATTRIBUTE + - "' attribute contains empty value."); + "Listener '" + METHOD_ATTRIBUTE + + "' attribute contains empty value."); } } - - containerDef.AddPropertyValue("ConnectionFactory", new RuntimeObjectReference(connectionFactoryObjectName)); - - - string errorHandlerObjectName = containerElement.GetAttribute(ERROR_HANDLER_ATTRIBUTE); - if (StringUtils.HasText(errorHandlerObjectName)) - { - containerDef.AddPropertyValue("ErrorHandler", - new RuntimeObjectReference(errorHandlerObjectName)); - } - - string exceptionListenerObjectName = containerElement.GetAttribute(EXCEPTION_LISTENER_ATTRIBUTE); - if (StringUtils.HasText(exceptionListenerObjectName)) - { - containerDef.AddPropertyValue("ExceptionListener", - new RuntimeObjectReference(exceptionListenerObjectName)); - } - - string destinationResolverObjectName = containerElement.GetAttribute(DESTINATION_RESOLVER_ATTRIBUTE); - if (StringUtils.HasText(destinationResolverObjectName)) - { - containerDef.AddPropertyValue("DestinationResolver", - new RuntimeObjectReference(destinationResolverObjectName)); - } - - string acknowledge = containerElement.GetAttribute(ACKNOWLEDGE_ATTRIBUTE); - if (StringUtils.HasText(acknowledge)) - { - int acknowledgementMode = ParseAcknowledgementMode(containerElement, parserContext); - containerDef.AddPropertyValue("SessionAcknowledgeMode", acknowledgementMode); - } - - string concurrency = ParseConcurrency(containerElement, parserContext); - if (concurrency != null) - { - containerDef.AddPropertyValue("ConcurrentConsumers", concurrency); - } - containerDef.AddPropertyValue("RecoveryInterval", ParseRecoveryInterval(containerElement, parserContext)); - - containerDef.AddPropertyValue("MaxRecoveryTime", ParseMaxRecoveryTime(containerElement, parserContext)); - - return containerDef; } - private bool IndicatesPubSub(AbstractObjectDefinition configDef) + listenerDefBuilder.AddPropertyValue("DefaultHandlerMethod", handlerMethod); + + if (containerElement.HasAttribute(MESSAGE_CONVERTER_ATTRIBUTE)) { - return (bool) configDef.PropertyValues.GetPropertyValue("PubSubDomain").Value; + string messageConverter = containerElement.GetAttribute(MESSAGE_CONVERTER_ATTRIBUTE); + listenerDefBuilder.AddPropertyValue("MessageConverter", new RuntimeObjectReference(messageConverter)); } - private void ParseListenerConfiguration(XmlElement ele, ParserContext parserContext, - ObjectDefinitionBuilder containerDef) + ObjectDefinitionBuilder containerDefBuilder = ParseContainer(listenerElement, containerElement, parserContext); + + if (listenerElement.HasAttribute(RESPONSE_DESTINATION_ATTRIBUTE)) { - string destination = ele.GetAttribute(DESTINATION_ATTRIBUTE); - if (!StringUtils.HasText(destination)) + string responseDestination = listenerElement.GetAttribute(RESPONSE_DESTINATION_ATTRIBUTE); + bool pubSubDomain = IndicatesPubSub(containerDefBuilder.RawObjectDefinition); + listenerDefBuilder.AddPropertyValue(pubSubDomain ? "DefaultResponseTopicName" : "DefaultResponseQueueName", + responseDestination); + if (containerDefBuilder.RawObjectDefinition.PropertyValues.Contains("DestinationResolver")) { - parserContext.ReaderContext.ReportException(ele, LISTENER_ELEMENT, - "Listener '" + DESTINATION_ATTRIBUTE + - "' attribute contains empty value."); - } - containerDef.AddPropertyValue("DestinationName", destination); - - if (ele.HasAttribute(SUBSCRIPTION_ATTRIBUTE)) - { - string subscription = ele.GetAttribute(SUBSCRIPTION_ATTRIBUTE); - if (!StringUtils.HasText(subscription)) - { - parserContext.ReaderContext.ReportException(ele, SUBSCRIPTION_ATTRIBUTE, - "Listener '" + SUBSCRIPTION_ATTRIBUTE + - "' attribute contains empty value."); - } - containerDef.AddPropertyValue("DurableSubscriptionName", subscription); - } - - if (ele.HasAttribute(SELECTOR_ATTRIBUTE)) - { - string selector = ele.GetAttribute(SELECTOR_ATTRIBUTE); - if (!StringUtils.HasText(selector)) - { - parserContext.ReaderContext.ReportException(ele, selector, - "Listener '" + SELECTOR_ATTRIBUTE + - "' attribute contains empty value."); - } - containerDef.AddPropertyValue("MessageSelector", selector); + listenerDefBuilder.AddPropertyValue("DestinationResolver", + containerDefBuilder.RawObjectDefinition.PropertyValues.GetPropertyValue + ( + "DestinationResolver").Value); } } - private void ParseContainerConfiguration(XmlElement ele, ParserContext parserContext, - ObjectDefinitionBuilder containerDef) + containerDefBuilder.AddPropertyValue("MessageListener", listenerDefBuilder.ObjectDefinition); + + string containerObjectName = listenerElement.GetAttribute(ID_ATTRIBUTE); + // If no object id is given auto generate one using the ReaderContext's ObjectNameGenerator + if (!StringUtils.HasText(containerObjectName)) { - string destinationType = ele.GetAttribute(DESTINATION_TYPE_ATTRIBUTE); - bool pubSubDomain = false; - bool subscriptionDurable = false; - if (DESTINATION_TYPE_DURABLE_TOPIC.Equals(destinationType)) + containerObjectName = + parserContext.ReaderContext.GenerateObjectName(containerDefBuilder.RawObjectDefinition); + } + + string pubsubDomain = listenerElement.GetAttribute(PUBSUB_DOMAIN_ATTRIBUTE); + containerDefBuilder.AddPropertyValue("PubSubDomain", pubsubDomain); + + parserContext.Registry.RegisterObjectDefinition(containerObjectName, containerDefBuilder.ObjectDefinition); + } + + private ObjectDefinitionBuilder ParseContainer(XmlElement listenerElement, XmlElement containerElement, + ParserContext parserContext) + { + //Only support SimpleMessageListenerContainer or container-custom-type + + Type containerType = typeof(SimpleMessageListenerContainer); + if (containerElement.HasAttribute(CONTAINER_CUSTOM_TYPE)) + { + string customType = containerElement.GetAttribute(CONTAINER_CUSTOM_TYPE); + if (!StringUtils.HasLength(customType)) { - pubSubDomain = true; - subscriptionDurable = true; - } - else if (DESTINATION_TYPE_TOPIC.Equals(destinationType)) - { - pubSubDomain = true; - } - else if ("".Equals(destinationType) || DESTINATION_TYPE_QUEUE.Equals(destinationType)) - { - // the default: queue - } - else - { - parserContext.ReaderContext.ReportException(ele, destinationType, - "Invalid listener container '" + DESTINATION_TYPE_ATTRIBUTE + - "': only 'queue', 'topic' and 'durableTopic' supported"); + parserContext.ReaderContext.ReportException(containerElement, CONTAINER_CUSTOM_TYPE, + "Listener container '" + CONTAINER_CUSTOM_TYPE + + "' attribute contains empty value."); } - containerDef.AddPropertyValue("PubSubDomain", pubSubDomain); - containerDef.AddPropertyValue("SubscriptionDurable", subscriptionDurable); - - if (ele.HasAttribute(CLIENT_ID_ATTRIBUTE)) + try { - string clientId = ele.GetAttribute(CLIENT_ID_ATTRIBUTE); - if (!StringUtils.HasText(clientId)) - { - parserContext.ReaderContext.ReportException(ele, clientId, - "Listener '" + CLIENT_ID_ATTRIBUTE + - "' attribute contains empty value."); - } - containerDef.AddPropertyValue("ClientId", clientId); + containerType = TypeResolutionUtils.ResolveType(customType); + } + catch (Exception ex) + { + parserContext.ReaderContext.ReportException(containerElement, CONTAINER_CUSTOM_TYPE, + "Invalid container-custom-type value [" + customType + "]", ex); } } - private int ParseAcknowledgementMode(XmlElement element, ParserContext parserContext) - { - string acknowledge = element.GetAttribute(ACKNOWLEDGE_ATTRIBUTE); - if (acknowledge.Equals(ACKNOWLEDGE_TRANSACTED)) - { - return TIBCO.EMS.Session.SESSION_TRANSACTED; - } - else if (acknowledge.Equals(ACKNOWLEDGE_DUPS_OK)) - { - return TIBCO.EMS.Session.DUPS_OK_ACKNOWLEDGE; - } - else if (acknowledge.Equals(ACKNOWLEDGE_CLIENT)) - { - return TIBCO.EMS.Session.CLIENT_ACKNOWLEDGE; - } - //TODO other ack modes. - else if (!acknowledge.Equals(ACKNOWLEDGE_AUTO)) - { - parserContext.ReaderContext.ReportException(element, ACKNOWLEDGE_ATTRIBUTE, - "Invalid listener container 'acknowledge' setting ['" + - acknowledge + - "]: only \"auto\", \"client\", \"dups-ok\" and \"transacted\" supported."); - } - return TIBCO.EMS.Session.AUTO_ACKNOWLEDGE; - } + //Only support SimpleMessageListenerContainer + ObjectDefinitionBuilder containerDef = + parserContext.ParserHelper.CreateRootObjectDefinitionBuilder(containerType); - private string ParseConcurrency(XmlElement ele, ParserContext parserContext) + ParseListenerConfiguration(listenerElement, parserContext, containerDef); + ParseContainerConfiguration(containerElement, parserContext, containerDef); + + if (containerElement.HasAttribute(AUTO_STARTUP)) { - string concurrency = ele.GetAttribute(CONCURRENCY_ATTRIBUTE); - if (!StringUtils.HasText(concurrency)) + string autoStartup = containerElement.GetAttribute(AUTO_STARTUP); + if (StringUtils.HasText(autoStartup)) { - return null; - } - else - { - return concurrency; + containerDef.AddPropertyValue("AutoStartup", autoStartup); } } - private string ParseRecoveryInterval(XmlElement ele, ParserContext parserContext) + string connectionFactoryObjectName = "connectionFactory"; + if (containerElement.HasAttribute(CONNECTION_FACTORY_ATTRIBUTE)) { - string recoveryInterval = ele.GetAttribute(RECOVERY_INTERVAL_ATTRIBUTE); - if (StringUtils.HasText(recoveryInterval)) + connectionFactoryObjectName = containerElement.GetAttribute(CONNECTION_FACTORY_ATTRIBUTE); + if (!StringUtils.HasText(connectionFactoryObjectName)) { - return recoveryInterval; - - } - else - { - return SimpleMessageListenerContainer.DEFAULT_RECOVERY_INTERVAL; + parserContext.ReaderContext.ReportException(listenerElement, LISTENER_ELEMENT, + "Listener container '" + CONNECTION_FACTORY_ATTRIBUTE + + "' attribute contains empty value."); } } - private string ParseMaxRecoveryTime(XmlElement ele, ParserContext parserContext) + containerDef.AddPropertyValue("ConnectionFactory", new RuntimeObjectReference(connectionFactoryObjectName)); + + string errorHandlerObjectName = containerElement.GetAttribute(ERROR_HANDLER_ATTRIBUTE); + if (StringUtils.HasText(errorHandlerObjectName)) { - string recoverTime = ele.GetAttribute(MAX_RECOVERY_TIME_ATTRIBUTE); - if (StringUtils.HasText(recoverTime)) + containerDef.AddPropertyValue("ErrorHandler", + new RuntimeObjectReference(errorHandlerObjectName)); + } + + string exceptionListenerObjectName = containerElement.GetAttribute(EXCEPTION_LISTENER_ATTRIBUTE); + if (StringUtils.HasText(exceptionListenerObjectName)) + { + containerDef.AddPropertyValue("ExceptionListener", + new RuntimeObjectReference(exceptionListenerObjectName)); + } + + string destinationResolverObjectName = containerElement.GetAttribute(DESTINATION_RESOLVER_ATTRIBUTE); + if (StringUtils.HasText(destinationResolverObjectName)) + { + containerDef.AddPropertyValue("DestinationResolver", + new RuntimeObjectReference(destinationResolverObjectName)); + } + + string acknowledge = containerElement.GetAttribute(ACKNOWLEDGE_ATTRIBUTE); + if (StringUtils.HasText(acknowledge)) + { + int acknowledgementMode = ParseAcknowledgementMode(containerElement, parserContext); + containerDef.AddPropertyValue("SessionAcknowledgeMode", acknowledgementMode); + } + + string concurrency = ParseConcurrency(containerElement, parserContext); + if (concurrency != null) + { + containerDef.AddPropertyValue("ConcurrentConsumers", concurrency); + } + + containerDef.AddPropertyValue("RecoveryInterval", ParseRecoveryInterval(containerElement, parserContext)); + + containerDef.AddPropertyValue("MaxRecoveryTime", ParseMaxRecoveryTime(containerElement, parserContext)); + + return containerDef; + } + + private bool IndicatesPubSub(AbstractObjectDefinition configDef) + { + return (bool) configDef.PropertyValues.GetPropertyValue("PubSubDomain").Value; + } + + private void ParseListenerConfiguration(XmlElement ele, ParserContext parserContext, + ObjectDefinitionBuilder containerDef) + { + string destination = ele.GetAttribute(DESTINATION_ATTRIBUTE); + if (!StringUtils.HasText(destination)) + { + parserContext.ReaderContext.ReportException(ele, LISTENER_ELEMENT, + "Listener '" + DESTINATION_ATTRIBUTE + + "' attribute contains empty value."); + } + + containerDef.AddPropertyValue("DestinationName", destination); + + if (ele.HasAttribute(SUBSCRIPTION_ATTRIBUTE)) + { + string subscription = ele.GetAttribute(SUBSCRIPTION_ATTRIBUTE); + if (!StringUtils.HasText(subscription)) { - return recoverTime; + parserContext.ReaderContext.ReportException(ele, SUBSCRIPTION_ATTRIBUTE, + "Listener '" + SUBSCRIPTION_ATTRIBUTE + + "' attribute contains empty value."); } - else + + containerDef.AddPropertyValue("DurableSubscriptionName", subscription); + } + + if (ele.HasAttribute(SELECTOR_ATTRIBUTE)) + { + string selector = ele.GetAttribute(SELECTOR_ATTRIBUTE); + if (!StringUtils.HasText(selector)) { - return SimpleMessageListenerContainer.DEFAULT_MAX_RECOVERY_TIME; + parserContext.ReaderContext.ReportException(ele, selector, + "Listener '" + SELECTOR_ATTRIBUTE + + "' attribute contains empty value."); } + + containerDef.AddPropertyValue("MessageSelector", selector); + } + } + + private void ParseContainerConfiguration(XmlElement ele, ParserContext parserContext, + ObjectDefinitionBuilder containerDef) + { + string destinationType = ele.GetAttribute(DESTINATION_TYPE_ATTRIBUTE); + bool pubSubDomain = false; + bool subscriptionDurable = false; + if (DESTINATION_TYPE_DURABLE_TOPIC.Equals(destinationType)) + { + pubSubDomain = true; + subscriptionDurable = true; + } + else if (DESTINATION_TYPE_TOPIC.Equals(destinationType)) + { + pubSubDomain = true; + } + else if ("".Equals(destinationType) || DESTINATION_TYPE_QUEUE.Equals(destinationType)) + { + // the default: queue + } + else + { + parserContext.ReaderContext.ReportException(ele, destinationType, + "Invalid listener container '" + DESTINATION_TYPE_ATTRIBUTE + + "': only 'queue', 'topic' and 'durableTopic' supported"); + } + + containerDef.AddPropertyValue("PubSubDomain", pubSubDomain); + containerDef.AddPropertyValue("SubscriptionDurable", subscriptionDurable); + + if (ele.HasAttribute(CLIENT_ID_ATTRIBUTE)) + { + string clientId = ele.GetAttribute(CLIENT_ID_ATTRIBUTE); + if (!StringUtils.HasText(clientId)) + { + parserContext.ReaderContext.ReportException(ele, clientId, + "Listener '" + CLIENT_ID_ATTRIBUTE + + "' attribute contains empty value."); + } + + containerDef.AddPropertyValue("ClientId", clientId); + } + } + + private int ParseAcknowledgementMode(XmlElement element, ParserContext parserContext) + { + string acknowledge = element.GetAttribute(ACKNOWLEDGE_ATTRIBUTE); + if (acknowledge.Equals(ACKNOWLEDGE_TRANSACTED)) + { + return TIBCO.EMS.Session.SESSION_TRANSACTED; + } + else if (acknowledge.Equals(ACKNOWLEDGE_DUPS_OK)) + { + return TIBCO.EMS.Session.DUPS_OK_ACKNOWLEDGE; + } + else if (acknowledge.Equals(ACKNOWLEDGE_CLIENT)) + { + return TIBCO.EMS.Session.CLIENT_ACKNOWLEDGE; + } + //TODO other ack modes. + else if (!acknowledge.Equals(ACKNOWLEDGE_AUTO)) + { + parserContext.ReaderContext.ReportException(element, ACKNOWLEDGE_ATTRIBUTE, + "Invalid listener container 'acknowledge' setting ['" + + acknowledge + + "]: only \"auto\", \"client\", \"dups-ok\" and \"transacted\" supported."); + } + + return TIBCO.EMS.Session.AUTO_ACKNOWLEDGE; + } + + private string ParseConcurrency(XmlElement ele, ParserContext parserContext) + { + string concurrency = ele.GetAttribute(CONCURRENCY_ATTRIBUTE); + if (!StringUtils.HasText(concurrency)) + { + return null; + } + else + { + return concurrency; + } + } + + private string ParseRecoveryInterval(XmlElement ele, ParserContext parserContext) + { + string recoveryInterval = ele.GetAttribute(RECOVERY_INTERVAL_ATTRIBUTE); + if (StringUtils.HasText(recoveryInterval)) + { + return recoveryInterval; + } + else + { + return SimpleMessageListenerContainer.DEFAULT_RECOVERY_INTERVAL; + } + } + + private string ParseMaxRecoveryTime(XmlElement ele, ParserContext parserContext) + { + string recoverTime = ele.GetAttribute(MAX_RECOVERY_TIME_ATTRIBUTE); + if (StringUtils.HasText(recoverTime)) + { + return recoverTime; + } + else + { + return SimpleMessageListenerContainer.DEFAULT_MAX_RECOVERY_TIME; } } } diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Config/spring-ems-1.3.xsd b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Config/spring-ems-1.3.xsd index 43c8b3b1..2d44648e 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Config/spring-ems-1.3.xsd +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Config/spring-ems-1.3.xsd @@ -1,231 +1,232 @@ + xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:vs="http://schemas.microsoft.com/Visual-Studio-Intellisense" + targetNamespace="http://www.springframework.net/ems" + elementFormDefault="qualified" + attributeFormDefault="unqualified" + vs:friendlyname="Spring.NET TIBCO EMS Configuration" vs:ishtmlschema="false" vs:iscasesensitive="true" + vs:requireattributequotes="true" vs:defaultnamespacequalifier="" vs:defaultnsprefix=""> - - + - + - - - + + - - - - - - - - + + + + + + + - - - - - - - - - - - + + + + + + + + + + - - - - - - - + + + + + + - - - - - - + + + + + - - - - - + + + + - - - - - + + + + - - - - - - + + + + + - - - - - - - + + + + + + - - - - - - + + + + + - - - - - - - - - - - - + + + + + + + + + + + - - - - - + + + + - - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - + + + + + - - - - - - - + + + + + + - - - - - - + + + + + - - - - + + + - - - - - + + + + - - - - - + + + + - - - - - + + + + - - - - - + + + + - - - - - + + + + - - - - - + + + + - - - - - - + + + + + - - - - - + + + + + diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Connections/CachedMessageConsumer .cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Connections/CachedMessageConsumer .cs index 2a3d96d9..d6357dc5 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Connections/CachedMessageConsumer .cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Connections/CachedMessageConsumer .cs @@ -20,115 +20,109 @@ using Spring.Messaging.Ems.Common; -namespace Spring.Messaging.Ems.Connections +namespace Spring.Messaging.Ems.Connections; + +/// +/// EMS MessageConsumer decorator that adapts all calls +/// to a shared MessageConsumer instance underneath. +/// +/// Juergen Hoeller +/// Mark Pollack (.NET) +public class CachedMessageConsumer : IMessageConsumer { + private IMessageConsumer target; + /// - /// EMS MessageConsumer decorator that adapts all calls - /// to a shared MessageConsumer instance underneath. + /// Initializes a new instance of the class. /// - /// Juergen Hoeller - /// Mark Pollack (.NET) - public class CachedMessageConsumer : IMessageConsumer + /// The target. + public CachedMessageConsumer(IMessageConsumer target) { - private IMessageConsumer target; + this.target = target; + } - /// - /// Initializes a new instance of the class. - /// - /// The target. - public CachedMessageConsumer(IMessageConsumer target) + /// + /// Gets the target MessageConsumer, the consumer we are 'wrapping' + /// + /// The target MessageConsumer. + public IMessageConsumer Target + { + get { return target; } + } + + /// + /// Occurs when a message is received. + /// + public event EMSMessageHandler MessageHandler + { + add { - this.target = target; + target.MessageHandler += value; } - - - /// - /// Gets the target MessageConsumer, the consumer we are 'wrapping' - /// - /// The target MessageConsumer. - public IMessageConsumer Target + remove { - get { return target; } - } - - /// - /// Occurs when a message is received. - /// - public event EMSMessageHandler MessageHandler - { - add - { - target.MessageHandler += value; - } - remove - { - target.MessageHandler -= value; - } - } - - - public MessageConsumer NativeMessageConsumer - { - get { return target.NativeMessageConsumer; } - } - - public IMessageListener MessageListener - { - get { return target.MessageListener; } - set { target.MessageListener = value; } - } - - public string MessageSelector - { - get { return target.MessageSelector; } - } - - /// - /// Receives the next message produced for this message consumer. - /// - /// the next message produced for this message consumer, , or null if this message consumer is concurrently closed - public Message Receive() - { - return this.target.Receive(); - } - - /// - /// Receives the next message that arrives within the specified timeout interval. - /// - /// The timeout value. - /// the next message produced for this message consumer, or null if the timeout expires or this message consumer is concurrently closed - public Message Receive(long timeout) - { - return this.target.Receive(timeout); - } - - /// - /// Receives the next message if one is immediately available. - /// - /// the next message produced for this message consumer, or null if one is not available - public Message ReceiveNoWait() - { - return this.target.ReceiveNoWait(); - } - - /// - /// No-op implementation since it is caching. - /// - public void Close() - { - // It's a cached MessageConsumer... - } - - - - - /// - /// Description that shows this is a cached MessageConsumer - /// - /// Description that shows this is a cached MessageConsumer - public override string ToString() - { - return "Cached EMS MessageConsumer: " + this.target; + target.MessageHandler -= value; } } + + public MessageConsumer NativeMessageConsumer + { + get { return target.NativeMessageConsumer; } + } + + public IMessageListener MessageListener + { + get { return target.MessageListener; } + set { target.MessageListener = value; } + } + + public string MessageSelector + { + get { return target.MessageSelector; } + } + + /// + /// Receives the next message produced for this message consumer. + /// + /// the next message produced for this message consumer, , or null if this message consumer is concurrently closed + public Message Receive() + { + return this.target.Receive(); + } + + /// + /// Receives the next message that arrives within the specified timeout interval. + /// + /// The timeout value. + /// the next message produced for this message consumer, or null if the timeout expires or this message consumer is concurrently closed + public Message Receive(long timeout) + { + return this.target.Receive(timeout); + } + + /// + /// Receives the next message if one is immediately available. + /// + /// the next message produced for this message consumer, or null if one is not available + public Message ReceiveNoWait() + { + return this.target.ReceiveNoWait(); + } + + /// + /// No-op implementation since it is caching. + /// + public void Close() + { + // It's a cached MessageConsumer... + } + + /// + /// Description that shows this is a cached MessageConsumer + /// + /// Description that shows this is a cached MessageConsumer + public override string ToString() + { + return "Cached EMS MessageConsumer: " + this.target; + } } diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Connections/CachedMessageProducer.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Connections/CachedMessageProducer.cs index 6ee060c8..21effaa5 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Connections/CachedMessageProducer.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Connections/CachedMessageProducer.cs @@ -20,215 +20,216 @@ using Spring.Messaging.Ems.Common; -namespace Spring.Messaging.Ems.Connections +namespace Spring.Messaging.Ems.Connections; + +/// +/// MessageProducer decorator that adapts calls to a shared MessageProducer +/// instance underneath, managing QoS settings locally within the decorator. +/// +/// Juergen Hoeller +/// Mark Pollack (.NET) +public class CachedMessageProducer : IMessageProducer { + private readonly IMessageProducer target; + + private object originalDisableMessageID; + + private object originalDisableMessageTimestamp; + + private MessageDeliveryMode deliveryMode; + + private int priority; + + private long timeToLive; + /// - /// MessageProducer decorator that adapts calls to a shared MessageProducer - /// instance underneath, managing QoS settings locally within the decorator. + /// Initializes a new instance of the class. /// - /// Juergen Hoeller - /// Mark Pollack (.NET) - public class CachedMessageProducer : IMessageProducer + /// The target. + public CachedMessageProducer(IMessageProducer target) { - private readonly IMessageProducer target; + this.target = target; + deliveryMode = target.MsgDeliveryMode; + priority = target.Priority; + timeToLive = target.TimeToLive; + } - private object originalDisableMessageID; - - private object originalDisableMessageTimestamp; - - private MessageDeliveryMode deliveryMode; - - private int priority; - - private long timeToLive; - - /// - /// Initializes a new instance of the class. - /// - /// The target. - public CachedMessageProducer(IMessageProducer target) + /// + /// Gets or sets a value indicating whether disable setting of the message ID property. + /// + /// true if disable message ID setting; otherwise, false. + public bool DisableMessageID + { + get { - this.target = target; - deliveryMode = target.MsgDeliveryMode; - priority = target.Priority; - timeToLive = target.TimeToLive; + return target.DisableMessageID; } - - - /// - /// Gets or sets a value indicating whether disable setting of the message ID property. - /// - /// true if disable message ID setting; otherwise, false. - public bool DisableMessageID + set { - get + if (originalDisableMessageID == null) { - return target.DisableMessageID; + originalDisableMessageID = target.DisableMessageID; } - set - { - if (originalDisableMessageID == null) - { - originalDisableMessageID = target.DisableMessageID; - } - target.DisableMessageID = value; - } - } - /// - /// Gets or sets a value indicating whether disable setting the message timestamp property. - /// - /// - /// true if disable message timestamp; otherwise, false. - /// - public bool DisableMessageTimestamp - { - get - { - return target.DisableMessageTimestamp; - } - set - { - if (originalDisableMessageTimestamp == null) - { - originalDisableMessageTimestamp = target.DisableMessageTimestamp; - } - target.DisableMessageTimestamp = value; - } - } - - /// - /// Gets or sets the producer's default delivery mode. - /// - /// The message delivery mode for this message producer - public int DeliveryMode - { - get { return (int)this.deliveryMode; } - set { this.deliveryMode = (MessageDeliveryMode) value; } - } - - /// - /// Gets or sets the MSG delivery mode. - /// - /// The MSG delivery mode. - public MessageDeliveryMode MsgDeliveryMode - { - get { return this.deliveryMode; } - set { this.deliveryMode = value; } - } - - /// - /// Gets or sets the priority of messages sent with this producer. - /// - /// The priority. - public int Priority - { - get { return priority; } - set { priority = value;} - } - - /// - /// Gets or sets the the default length of time in milliseconds from its dispatch time - /// that a produced message should be retained by the message system. - /// - /// Time to live is set to zero by default. - /// The message time to live in milliseconds; zero is unlimited - public long TimeToLive - { - get { return timeToLive; } - set { timeToLive = value; } - } - - public Destination Destination - { - get { return target.Destination; } - } - - /// - /// Gets the target MessageProducer, the producer we are 'wrapping' - /// - /// The target MessageProducer. - public IMessageProducer Target - { - get { return target; } - } - - /// - /// Sends the specified message. - /// - /// The message. - public void Send(Message message) - { - target.Send(message, this.deliveryMode, this.priority, this.timeToLive); - } - - /// - /// Sends the specified message. - /// - /// The message. - /// The delivery mode. - /// The priority. - /// The time to live. - public void Send(Message message, int deliveryMode, int priority, long timeToLive) - { - target.Send(message, deliveryMode, priority, timeToLive); - } - - /// - /// Sends a message to the specified destination. - /// - /// The destination. - /// The message. - public void Send(Destination destination, Message message) - { - target.Send(destination, message, this.deliveryMode, this.priority, this.timeToLive); - } - - public void Send(Message message, MessageDeliveryMode deliveryMode, int priority, long timeToLive) - { - target.Send(message, deliveryMode, priority, timeToLive); - } - - public void Send(Destination dest, Message message, int deliveryMode, int priority, long timeToLive) - { - target.Send(dest, message, deliveryMode, priority, timeToLive); - } - - public void Send(Destination dest, Message message, MessageDeliveryMode deliveryMode, int priority, long timeToLive) - { - target.Send(dest, message, deliveryMode, priority, timeToLive); - } - - /// - /// Reset properties. - /// - public void Close() - { - // It's a cached MessageProducer... reset properties only. - if (originalDisableMessageID != null) - { - target.DisableMessageID = (bool) originalDisableMessageID; - originalDisableMessageID = null; - } - if (originalDisableMessageTimestamp != null) - { - target.DisableMessageTimestamp = (bool) originalDisableMessageTimestamp; - originalDisableMessageTimestamp = null; - } - } - - public MessageProducer NativeMessageProducer - { - get { return target.NativeMessageProducer; } - } - - /// - /// Returns string indicated this is a wrapped MessageProducer - /// - /// - public override string ToString() - { - return "Cached EMS MessageProducer: " + this.target; + target.DisableMessageID = value; } } + + /// + /// Gets or sets a value indicating whether disable setting the message timestamp property. + /// + /// + /// true if disable message timestamp; otherwise, false. + /// + public bool DisableMessageTimestamp + { + get + { + return target.DisableMessageTimestamp; + } + set + { + if (originalDisableMessageTimestamp == null) + { + originalDisableMessageTimestamp = target.DisableMessageTimestamp; + } + + target.DisableMessageTimestamp = value; + } + } + + /// + /// Gets or sets the producer's default delivery mode. + /// + /// The message delivery mode for this message producer + public int DeliveryMode + { + get { return (int) this.deliveryMode; } + set { this.deliveryMode = (MessageDeliveryMode) value; } + } + + /// + /// Gets or sets the MSG delivery mode. + /// + /// The MSG delivery mode. + public MessageDeliveryMode MsgDeliveryMode + { + get { return this.deliveryMode; } + set { this.deliveryMode = value; } + } + + /// + /// Gets or sets the priority of messages sent with this producer. + /// + /// The priority. + public int Priority + { + get { return priority; } + set { priority = value; } + } + + /// + /// Gets or sets the the default length of time in milliseconds from its dispatch time + /// that a produced message should be retained by the message system. + /// + /// Time to live is set to zero by default. + /// The message time to live in milliseconds; zero is unlimited + public long TimeToLive + { + get { return timeToLive; } + set { timeToLive = value; } + } + + public Destination Destination + { + get { return target.Destination; } + } + + /// + /// Gets the target MessageProducer, the producer we are 'wrapping' + /// + /// The target MessageProducer. + public IMessageProducer Target + { + get { return target; } + } + + /// + /// Sends the specified message. + /// + /// The message. + public void Send(Message message) + { + target.Send(message, this.deliveryMode, this.priority, this.timeToLive); + } + + /// + /// Sends the specified message. + /// + /// The message. + /// The delivery mode. + /// The priority. + /// The time to live. + public void Send(Message message, int deliveryMode, int priority, long timeToLive) + { + target.Send(message, deliveryMode, priority, timeToLive); + } + + /// + /// Sends a message to the specified destination. + /// + /// The destination. + /// The message. + public void Send(Destination destination, Message message) + { + target.Send(destination, message, this.deliveryMode, this.priority, this.timeToLive); + } + + public void Send(Message message, MessageDeliveryMode deliveryMode, int priority, long timeToLive) + { + target.Send(message, deliveryMode, priority, timeToLive); + } + + public void Send(Destination dest, Message message, int deliveryMode, int priority, long timeToLive) + { + target.Send(dest, message, deliveryMode, priority, timeToLive); + } + + public void Send(Destination dest, Message message, MessageDeliveryMode deliveryMode, int priority, long timeToLive) + { + target.Send(dest, message, deliveryMode, priority, timeToLive); + } + + /// + /// Reset properties. + /// + public void Close() + { + // It's a cached MessageProducer... reset properties only. + if (originalDisableMessageID != null) + { + target.DisableMessageID = (bool) originalDisableMessageID; + originalDisableMessageID = null; + } + + if (originalDisableMessageTimestamp != null) + { + target.DisableMessageTimestamp = (bool) originalDisableMessageTimestamp; + originalDisableMessageTimestamp = null; + } + } + + public MessageProducer NativeMessageProducer + { + get { return target.NativeMessageProducer; } + } + + /// + /// Returns string indicated this is a wrapped MessageProducer + /// + /// + public override string ToString() + { + return "Cached EMS MessageProducer: " + this.target; + } } diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Connections/CachedSession.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Connections/CachedSession.cs index 85052aaf..da49aa17 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Connections/CachedSession.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Connections/CachedSession.cs @@ -23,626 +23,628 @@ using Microsoft.Extensions.Logging; using Spring.Messaging.Ems.Common; using Spring.Collections; using Spring.Util; -using Queue=TIBCO.EMS.Queue; +using Queue = TIBCO.EMS.Queue; -namespace Spring.Messaging.Ems.Connections +namespace Spring.Messaging.Ems.Connections; + +/// +/// Wrapper for Session that caches producers and registers itself as available +/// to the session cache when being closed. Generally used for testing purposes or +/// if need to get at the wrapped Session object via the TargetSession property (for +/// vendor specific methods). +/// +/// Juergen Hoeller +/// Mark Pollack +public class CachedSession : IDecoratorSession { + #region Logging Definition + + private static readonly ILogger LOG = LogManager.GetLogger(); + + #endregion + + private readonly ISession target; + private readonly LinkedList sessionList; + private readonly int sessionCacheSize; + private readonly IDictionary cachedProducers = new Hashtable(); + private readonly IDictionary cachedConsumers = new Hashtable(); + private readonly bool shouldCacheProducers; + private readonly bool shouldCacheConsumers; + private bool transactionOpen = false; + private readonly CachingConnectionFactory ccf; + /// - /// Wrapper for Session that caches producers and registers itself as available - /// to the session cache when being closed. Generally used for testing purposes or - /// if need to get at the wrapped Session object via the TargetSession property (for - /// vendor specific methods). + /// Initializes a new instance of the class. /// - /// Juergen Hoeller - /// Mark Pollack - public class CachedSession : IDecoratorSession + /// The target session. + /// The session list. + /// The CachingConnectionFactory. + public CachedSession(ISession targetSession, LinkedList sessionList, CachingConnectionFactory ccf) { - #region Logging Definition + target = targetSession; + this.sessionList = sessionList; + this.sessionCacheSize = ccf.SessionCacheSize; + shouldCacheProducers = ccf.CacheProducers; + shouldCacheConsumers = ccf.CacheConsumers; + this.ccf = ccf; + } - private static readonly ILogger LOG = LogManager.GetLogger(); + /// + /// Gets the target, for testing purposes. + /// + /// The target. + public ISession TargetSession + { + get { return target; } + } - #endregion - - private readonly ISession target; - private readonly LinkedList sessionList; - private readonly int sessionCacheSize; - private readonly IDictionary cachedProducers = new Hashtable(); - private readonly IDictionary cachedConsumers = new Hashtable(); - private readonly bool shouldCacheProducers; - private readonly bool shouldCacheConsumers; - private bool transactionOpen = false; - private readonly CachingConnectionFactory ccf; - - /// - /// Initializes a new instance of the class. - /// - /// The target session. - /// The session list. - /// The CachingConnectionFactory. - public CachedSession(ISession targetSession, LinkedList sessionList, CachingConnectionFactory ccf) + /// + /// Creates the producer, potentially returning a cached instance. + /// + /// The destination. + /// A message producer. + public IMessageProducer CreateProducer(Destination destination) + { + if (shouldCacheProducers) { - target = targetSession; - this.sessionList = sessionList; - this.sessionCacheSize = ccf.SessionCacheSize; - shouldCacheProducers = ccf.CacheProducers; - shouldCacheConsumers = ccf.CacheConsumers; - this.ccf = ccf; - } - - - /// - /// Gets the target, for testing purposes. - /// - /// The target. - public ISession TargetSession - { - get { return target; } - } - - /// - /// Creates the producer, potentially returning a cached instance. - /// - /// The destination. - /// A message producer. - public IMessageProducer CreateProducer(Destination destination) - { - if (shouldCacheProducers) - { - IMessageProducer producer = (IMessageProducer)cachedProducers[destination]; - if (producer != null) - { - #region Logging - - if (LOG.IsEnabled(LogLevel.Debug)) - { - LOG.LogDebug("Found cached MessageProducer for destination [" + destination + "]"); - } - - #endregion - } - else - { - producer = target.CreateProducer(destination); - #region Logging - - if (LOG.IsEnabled(LogLevel.Debug)) - { - LOG.LogDebug("Creating cached MessageProducer for destination [" + destination + "]"); - } - - #endregion - cachedProducers.Add(destination, producer); - - } - this.transactionOpen = true; - return new CachedMessageProducer(producer); - } - else - { - return target.CreateProducer(destination); - } - } - - - /// - /// If have not yet reached session cache size, cache the session, otherwise - /// dispose of all cached message producers and close the session. - /// - public void Close() - { - if (ccf.IsActive) - { - //don't pass the call to the underlying target. - lock (sessionList) - { - if (sessionList.Count < sessionCacheSize) - { - LogicalClose(); - // Remain open in the session list. - return; - } - } - } - // If we get here, we're supposed to shut down. - PhysicalClose(); - } - - private void LogicalClose() - { - // Preserve rollback-on-close semantics. - if (this.transactionOpen && this.target.Transacted) - { - this.transactionOpen = false; - this.target.Rollback(); - } - - // Physically close durable subscribers at time of Session close call. - IList ToRemove = new ArrayList(); - foreach (DictionaryEntry dictionaryEntry in cachedConsumers) - { - ConsumerCacheKey key = (ConsumerCacheKey) dictionaryEntry.Key; - if (key.Subscription != null) - { - ((IMessageConsumer) dictionaryEntry.Value).Close(); - ToRemove.Add(key); - } - } - foreach (ConsumerCacheKey key in ToRemove) - { - cachedConsumers.Remove(key); - } - - // Allow for multiple close calls... - if (!sessionList.Contains(this)) + IMessageProducer producer = (IMessageProducer) cachedProducers[destination]; + if (producer != null) { #region Logging if (LOG.IsEnabled(LogLevel.Debug)) { - LOG.LogDebug("Returning cached Session: " + target); + LOG.LogDebug("Found cached MessageProducer for destination [" + destination + "]"); + } + + #endregion + } + else + { + producer = target.CreateProducer(destination); + + #region Logging + + if (LOG.IsEnabled(LogLevel.Debug)) + { + LOG.LogDebug("Creating cached MessageProducer for destination [" + destination + "]"); } #endregion - sessionList.Add(this); //add to end of linked list. + cachedProducers.Add(destination, producer); + } + + this.transactionOpen = true; + return new CachedMessageProducer(producer); + } + else + { + return target.CreateProducer(destination); + } + } + + /// + /// If have not yet reached session cache size, cache the session, otherwise + /// dispose of all cached message producers and close the session. + /// + public void Close() + { + if (ccf.IsActive) + { + //don't pass the call to the underlying target. + lock (sessionList) + { + if (sessionList.Count < sessionCacheSize) + { + LogicalClose(); + // Remain open in the session list. + return; + } } } - private void PhysicalClose() + // If we get here, we're supposed to shut down. + PhysicalClose(); + } + + private void LogicalClose() + { + // Preserve rollback-on-close semantics. + if (this.transactionOpen && this.target.Transacted) + { + this.transactionOpen = false; + this.target.Rollback(); + } + + // Physically close durable subscribers at time of Session close call. + IList ToRemove = new ArrayList(); + foreach (DictionaryEntry dictionaryEntry in cachedConsumers) + { + ConsumerCacheKey key = (ConsumerCacheKey) dictionaryEntry.Key; + if (key.Subscription != null) + { + ((IMessageConsumer) dictionaryEntry.Value).Close(); + ToRemove.Add(key); + } + } + + foreach (ConsumerCacheKey key in ToRemove) + { + cachedConsumers.Remove(key); + } + + // Allow for multiple close calls... + if (!sessionList.Contains(this)) + { + #region Logging + + if (LOG.IsEnabled(LogLevel.Debug)) + { + LOG.LogDebug("Returning cached Session: " + target); + } + + #endregion + + sessionList.Add(this); //add to end of linked list. + } + } + + private void PhysicalClose() + { + if (LOG.IsEnabled(LogLevel.Debug)) + { + LOG.LogDebug("Closing cached Session: " + this.target); + } + + // Explicitly close all MessageProducers and MessageConsumers that + // this Session happens to cache... + try + { + foreach (DictionaryEntry entry in cachedProducers) + { + ((IMessageProducer) entry.Value).Close(); + } + + foreach (DictionaryEntry entry in cachedConsumers) + { + ((IMessageConsumer) entry.Value).Close(); + } + } + finally + { + // Now actually close the Session. + target.Close(); + } + } + + /// + /// Creates the consumer, potentially returning a cached instance. + /// + /// The destination. + /// A message consumer + public IMessageConsumer CreateConsumer(Destination destination) + { + return CreateConsumer(destination, null, false, null); + } + + /// + /// Creates the consumer, potentially returning a cached instance. + /// + /// The destination. + /// The selector. + /// A message consumer + public IMessageConsumer CreateConsumer(Destination destination, string selector) + { + return CreateConsumer(destination, selector, false, null); + } + + /// + /// Creates the consumer, potentially returning a cached instance. + /// + /// The destination. + /// The selector. + /// if set to true [no local]. + /// A message consumer. + public IMessageConsumer CreateConsumer(Destination destination, string selector, bool noLocal) + { + return CreateConsumer(destination, selector, noLocal, null); + } + + /// + /// Creates the durable consumer, potentially returning a cached instance. + /// + /// The destination. + /// The name of the durable subscription. + /// The selector. + /// if set to true [no local]. + /// A message consumer + public ITopicSubscriber CreateDurableSubscriber(Topic destination, string subscription, string selector, bool noLocal) + { + this.transactionOpen = true; + if (shouldCacheConsumers) + { + return (ITopicSubscriber) GetCachedConsumer(destination, selector, noLocal, subscription); + } + else + { + return target.CreateDurableSubscriber(destination, subscription, selector, noLocal); + } + } + + /// + /// Creates the durable consumer, potentially returning a cached instance. + /// + /// The destination. + /// The name of the durable subscription. + /// A message consumer + public ITopicSubscriber CreateDurableSubscriber(Topic destination, string subscription) + { + return CreateDurableSubscriber(destination, subscription, null, false); + } + + /// + /// Creates the consumer. + /// + /// The destination. + /// The selector. + /// if set to true [no local]. + /// The subscription. + /// + protected IMessageConsumer CreateConsumer(Destination destination, string selector, bool noLocal, string subscription) + { + this.transactionOpen = true; + if (shouldCacheConsumers) + { + return GetCachedConsumer(destination, selector, noLocal, subscription); + } + else + { + return target.CreateConsumer(destination, selector, noLocal); + } + } + + private IMessageConsumer GetCachedConsumer(Destination destination, string selector, bool noLocal, string subscription) + { + object cacheKey = new ConsumerCacheKey(destination, selector, noLocal, null); + IMessageConsumer consumer = (IMessageConsumer) cachedConsumers[cacheKey]; + if (consumer != null) { if (LOG.IsEnabled(LogLevel.Debug)) { - LOG.LogDebug("Closing cached Session: " + this.target); - } - // Explicitly close all MessageProducers and MessageConsumers that - // this Session happens to cache... - try - { - foreach (DictionaryEntry entry in cachedProducers) - { - ((IMessageProducer)entry.Value).Close(); - } - foreach (DictionaryEntry entry in cachedConsumers) - { - ((IMessageConsumer)entry.Value).Close(); - } - } - finally - { - // Now actually close the Session. - target.Close(); + LOG.LogDebug("Found cached EMS MessageConsumer for destination [" + destination + "]: " + consumer); } } - - /// - /// Creates the consumer, potentially returning a cached instance. - /// - /// The destination. - /// A message consumer - public IMessageConsumer CreateConsumer(Destination destination) + else { - return CreateConsumer(destination, null, false, null); - } - - - /// - /// Creates the consumer, potentially returning a cached instance. - /// - /// The destination. - /// The selector. - /// A message consumer - public IMessageConsumer CreateConsumer(Destination destination, string selector) - { - return CreateConsumer(destination, selector, false, null); - } - - /// - /// Creates the consumer, potentially returning a cached instance. - /// - /// The destination. - /// The selector. - /// if set to true [no local]. - /// A message consumer. - public IMessageConsumer CreateConsumer(Destination destination, string selector, bool noLocal) - { - return CreateConsumer(destination, selector, noLocal, null); - } - - - /// - /// Creates the durable consumer, potentially returning a cached instance. - /// - /// The destination. - /// The name of the durable subscription. - /// The selector. - /// if set to true [no local]. - /// A message consumer - public ITopicSubscriber CreateDurableSubscriber(Topic destination, string subscription, string selector, bool noLocal) - { - this.transactionOpen = true; - if (shouldCacheConsumers) + if (destination is Topic) { - return (ITopicSubscriber)GetCachedConsumer(destination, selector, noLocal, subscription); + consumer = (subscription != null + ? target.CreateDurableSubscriber((Topic) destination, subscription, selector, noLocal) + : target.CreateConsumer(destination, selector, noLocal)); } else { - return target.CreateDurableSubscriber(destination, subscription, selector, noLocal); + consumer = target.CreateConsumer(destination, selector); } - } - /// - /// Creates the durable consumer, potentially returning a cached instance. - /// - /// The destination. - /// The name of the durable subscription. - /// A message consumer - public ITopicSubscriber CreateDurableSubscriber(Topic destination, string subscription) - { - return CreateDurableSubscriber(destination, subscription, null, false); - } - - /// - /// Creates the consumer. - /// - /// The destination. - /// The selector. - /// if set to true [no local]. - /// The subscription. - /// - protected IMessageConsumer CreateConsumer(Destination destination, string selector, bool noLocal, string subscription) - { - this.transactionOpen = true; - if (shouldCacheConsumers) + if (LOG.IsEnabled(LogLevel.Debug)) { - return GetCachedConsumer(destination, selector, noLocal, subscription); - } - else - { - return target.CreateConsumer(destination, selector, noLocal); + LOG.LogDebug("Creating cached EMS MessageConsumer for destination [" + destination + "]: " + consumer); } + + cachedConsumers[cacheKey] = consumer; } - private IMessageConsumer GetCachedConsumer(Destination destination, string selector, bool noLocal, string subscription) - { - object cacheKey = new ConsumerCacheKey(destination, selector, noLocal, null); - IMessageConsumer consumer = (IMessageConsumer)cachedConsumers[cacheKey]; - if (consumer != null) - { - if (LOG.IsEnabled(LogLevel.Debug)) - { - LOG.LogDebug("Found cached EMS MessageConsumer for destination [" + destination + "]: " + consumer); - } - } - else - { - if (destination is Topic) - { - consumer = (subscription != null - ? target.CreateDurableSubscriber((Topic)destination, subscription, selector, noLocal) - : target.CreateConsumer(destination, selector, noLocal)); - } - else - { - consumer = target.CreateConsumer(destination, selector); - } - if (LOG.IsEnabled(LogLevel.Debug)) - { - LOG.LogDebug("Creating cached EMS MessageConsumer for destination [" + destination + "]: " + consumer); - } - cachedConsumers[cacheKey] = consumer; - } - return new CachedMessageConsumer(consumer); - } + return new CachedMessageConsumer(consumer); + } - #region Pass through implementations + #region Pass through implementations - /// - /// Gets the queue. - /// - /// The name. - /// - public TIBCO.EMS.Queue CreateQueue(string name) + /// + /// Gets the queue. + /// + /// The name. + /// + public TIBCO.EMS.Queue CreateQueue(string name) + { + this.transactionOpen = true; + return target.CreateQueue(name); + } + + /// + /// Gets the topic. + /// + /// The name. + /// + public Topic CreateTopic(string name) + { + this.transactionOpen = true; + return target.CreateTopic(name); + } + + /// + /// Creates the temporary queue. + /// + /// + public TemporaryQueue CreateTemporaryQueue() + { + this.transactionOpen = true; + return target.CreateTemporaryQueue(); + } + + /// + /// Creates the temporary topic. + /// + /// + public TemporaryTopic CreateTemporaryTopic() + { + this.transactionOpen = true; + return target.CreateTemporaryTopic(); + } + + /// + /// Creates the message. + /// + /// + public Message CreateMessage() + { + this.transactionOpen = true; + return target.CreateMessage(); + } + + /// + /// Creates the text message. + /// + /// + public TextMessage CreateTextMessage() + { + this.transactionOpen = true; + return target.CreateTextMessage(); + } + + /// + /// Creates the text message. + /// + /// The text. + /// + public TextMessage CreateTextMessage(string text) + { + this.transactionOpen = true; + return target.CreateTextMessage(text); + } + + /// + /// Creates the map message. + /// + /// + public MapMessage CreateMapMessage() + { + this.transactionOpen = true; + return target.CreateMapMessage(); + } + + /// + /// Creates the bytes message. + /// + /// + public BytesMessage CreateBytesMessage() + { + this.transactionOpen = true; + return target.CreateBytesMessage(); + } + + /// + /// Creates the object message. + /// + /// + public ObjectMessage CreateObjectMessage() + { + this.transactionOpen = true; + return target.CreateObjectMessage(); + } + + /// + /// Creates the object message. + /// + /// The body. + /// + public ObjectMessage CreateObjectMessage(object body) + { + this.transactionOpen = true; + return target.CreateObjectMessage(body); + } + + /// + /// Creates the stream message. + /// + /// + public StreamMessage CreateStreamMessage() + { + this.transactionOpen = true; + return target.CreateStreamMessage(); + } + + /// + /// Commits this instance. + /// + public void Commit() + { + this.transactionOpen = false; + target.Commit(); + } + + /// + /// Rollbacks this instance. + /// + public void Rollback() + { + this.transactionOpen = false; + target.Rollback(); + } + + public QueueBrowser CreateBrowser(Queue queue) + { + this.transactionOpen = true; + return target.CreateBrowser(queue); + } + + public QueueBrowser CreateBrowser(Queue queue, string messageSelector) + { + this.transactionOpen = true; + return target.CreateBrowser(queue, messageSelector); + } + + public void Recover() + { + this.transactionOpen = true; + target.Recover(); + } + + public void Run() + { + this.transactionOpen = true; + target.Run(); + } + + public void Unsubscribe(string name) + { + this.transactionOpen = true; + target.Unsubscribe(name); + } + + /// + /// Gets a value indicating whether this is transacted. + /// + /// true if transacted; otherwise, false. + public bool Transacted + { + get { this.transactionOpen = true; - return target.CreateQueue(name); - } - - /// - /// Gets the topic. - /// - /// The name. - /// - public Topic CreateTopic(string name) - { - this.transactionOpen = true; - return target.CreateTopic(name); - } - - /// - /// Creates the temporary queue. - /// - /// - public TemporaryQueue CreateTemporaryQueue() - { - this.transactionOpen = true; - return target.CreateTemporaryQueue(); - } - - /// - /// Creates the temporary topic. - /// - /// - public TemporaryTopic CreateTemporaryTopic() - { - this.transactionOpen = true; - return target.CreateTemporaryTopic(); - } - - /// - /// Creates the message. - /// - /// - public Message CreateMessage() - { - this.transactionOpen = true; - return target.CreateMessage(); - } - - /// - /// Creates the text message. - /// - /// - public TextMessage CreateTextMessage() - { - this.transactionOpen = true; - return target.CreateTextMessage(); - } - - /// - /// Creates the text message. - /// - /// The text. - /// - public TextMessage CreateTextMessage(string text) - { - this.transactionOpen = true; - return target.CreateTextMessage(text); - } - - /// - /// Creates the map message. - /// - /// - public MapMessage CreateMapMessage() - { - this.transactionOpen = true; - return target.CreateMapMessage(); - } - - /// - /// Creates the bytes message. - /// - /// - public BytesMessage CreateBytesMessage() - { - this.transactionOpen = true; - return target.CreateBytesMessage(); - } - - /// - /// Creates the object message. - /// - /// - public ObjectMessage CreateObjectMessage() - { - this.transactionOpen = true; - return target.CreateObjectMessage(); - } - - /// - /// Creates the object message. - /// - /// The body. - /// - public ObjectMessage CreateObjectMessage(object body) - { - this.transactionOpen = true; - return target.CreateObjectMessage(body); - } - - /// - /// Creates the stream message. - /// - /// - public StreamMessage CreateStreamMessage() - { - this.transactionOpen = true; - return target.CreateStreamMessage(); - } - - - /// - /// Commits this instance. - /// - public void Commit() - { - this.transactionOpen = false; - target.Commit(); - } - - /// - /// Rollbacks this instance. - /// - public void Rollback() - { - this.transactionOpen = false; - target.Rollback(); - } - - - public QueueBrowser CreateBrowser(Queue queue) - { - this.transactionOpen = true; - return target.CreateBrowser(queue); - } - - public QueueBrowser CreateBrowser(Queue queue, string messageSelector) - { - this.transactionOpen = true; - return target.CreateBrowser(queue, messageSelector); - } - - - public void Recover() - { - this.transactionOpen = true; - target.Recover(); - } - - public void Run() - { - this.transactionOpen = true; - target.Run(); - } - - public void Unsubscribe(string name) - { - this.transactionOpen = true; - target.Unsubscribe(name); - } - - /// - /// Gets a value indicating whether this is transacted. - /// - /// true if transacted; otherwise, false. - public bool Transacted - { - get - { - this.transactionOpen = true; - return target.Transacted; - } - } - - /// - /// Gets the acknowledgement mode. - /// - /// The acknowledgement mode. - public SessionMode SessionAcknowledgeMode - { - get - { - this.transactionOpen = true; - return target.SessionAcknowledgeMode; - } - } - - public long SessID - { - get - { - this.transactionOpen = true; - return target.SessID; - } - } - - public Session NativeSession - { - get - { - this.transactionOpen = true; - return target.NativeSession; - } - } - - public int AcknowledgeMode - { - get - { - this.transactionOpen = true; - return target.AcknowledgeMode; - } - } - - public Connection Connection - { - get - { - this.transactionOpen = true; - return target.Connection; - } - } - - public bool IsClosed - { - get { - this.transactionOpen = true; - return target.IsClosed; - } - } - - public bool IsTransacted - { - get - { - this.transactionOpen = true; - return target.IsTransacted; - } - } - - #endregion - - /// - /// Returns a that represents the current . - /// - /// - /// A that represents the current . - /// - public override string ToString() - { - return "Cached EMS Session: " + this.target; + return target.Transacted; } } - internal class ConsumerCacheKey + /// + /// Gets the acknowledgement mode. + /// + /// The acknowledgement mode. + public SessionMode SessionAcknowledgeMode { - private readonly Destination destination; - private readonly string selector; - private readonly bool noLocal; - private readonly string subscription; - - public ConsumerCacheKey(Destination destination, string selector, bool noLocal, string subscription) + get { - this.destination = destination; - this.selector = selector; - this.noLocal = noLocal; - this.subscription = subscription; + this.transactionOpen = true; + return target.SessionAcknowledgeMode; } + } - public string Subscription + public long SessID + { + get { - get { return subscription; } + this.transactionOpen = true; + return target.SessID; } + } - protected bool Equals(ConsumerCacheKey consumerCacheKey) + public Session NativeSession + { + get { - if (consumerCacheKey == null) return false; - if (!Equals(destination, consumerCacheKey.destination)) return false; - if (!ObjectUtils.NullSafeEquals(selector, consumerCacheKey.selector)) return false; - if (!Equals(noLocal, consumerCacheKey.noLocal)) return false; - if (!ObjectUtils.NullSafeEquals(subscription, consumerCacheKey.subscription)) return false; - return true; + this.transactionOpen = true; + return target.NativeSession; } + } - public override bool Equals(object obj) + public int AcknowledgeMode + { + get { - if (ReferenceEquals(this, obj)) return true; - return Equals(obj as ConsumerCacheKey); + this.transactionOpen = true; + return target.AcknowledgeMode; } + } - public override int GetHashCode() + public Connection Connection + { + get { - return destination.GetHashCode(); + this.transactionOpen = true; + return target.Connection; } } + + public bool IsClosed + { + get + { + this.transactionOpen = true; + return target.IsClosed; + } + } + + public bool IsTransacted + { + get + { + this.transactionOpen = true; + return target.IsTransacted; + } + } + + #endregion + + /// + /// Returns a that represents the current . + /// + /// + /// A that represents the current . + /// + public override string ToString() + { + return "Cached EMS Session: " + this.target; + } +} + +internal class ConsumerCacheKey +{ + private readonly Destination destination; + private readonly string selector; + private readonly bool noLocal; + private readonly string subscription; + + public ConsumerCacheKey(Destination destination, string selector, bool noLocal, string subscription) + { + this.destination = destination; + this.selector = selector; + this.noLocal = noLocal; + this.subscription = subscription; + } + + public string Subscription + { + get { return subscription; } + } + + protected bool Equals(ConsumerCacheKey consumerCacheKey) + { + if (consumerCacheKey == null) return false; + if (!Equals(destination, consumerCacheKey.destination)) return false; + if (!ObjectUtils.NullSafeEquals(selector, consumerCacheKey.selector)) return false; + if (!Equals(noLocal, consumerCacheKey.noLocal)) return false; + if (!ObjectUtils.NullSafeEquals(subscription, consumerCacheKey.subscription)) return false; + return true; + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(this, obj)) return true; + return Equals(obj as ConsumerCacheKey); + } + + public override int GetHashCode() + { + return destination.GetHashCode(); + } } diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Connections/CachingConnectionFactory.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Connections/CachingConnectionFactory.cs index 1e28bbf4..768bcfc9 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Connections/CachingConnectionFactory.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Connections/CachingConnectionFactory.cs @@ -21,251 +21,254 @@ using System.Collections; using Microsoft.Extensions.Logging; using Spring.Messaging.Ems.Common; - using Spring.Collections; using Spring.Util; -namespace Spring.Messaging.Ems.Connections +namespace Spring.Messaging.Ems.Connections; + +/// +/// subclass that adds +/// Session, MessageProducer, and MessageConsumer caching. This ConnectionFactory +/// also switches the ReconnectOnException property to true +/// by default, allowing for automatic recovery of the underlying +/// Connection. +/// +/// +/// By default, only one single Session will be cached, with further requested +/// Sessions being created and disposed on demand. Consider raising the +/// SessionCacheSize property in case of a high-concurrency environment. +/// +/// NOTE: This ConnectionFactory requires explicit closing of all Sessions +/// obtained from its shared Connection. This is the usual recommendation for +/// native EMS access code anyway. However, with this ConnectionFactory, its use +/// is mandatory in order to actually allow for Session reuse. +/// +/// +/// Note also that MessageConsumers obtained from a cached Session won't get +/// closed until the Session will eventually be removed from the pool. This may +/// lead to semantic side effects in some cases. For a durable subscriber, the +/// logical Session.Close() call will also close the subscription. +/// Re-registering a durable consumer for the same subscription on the same +/// Session handle is not supported; close and reobtain a cached Session first. +/// +/// +/// +/// Juergen Hoeller +/// Mark Pollack (.NET) +public class CachingConnectionFactory : SingleConnectionFactory { + #region Logging Definition + + private static readonly ILog LOG = LogManager.GetLogger(typeof(CachingConnectionFactory)); + + #endregion + + private int sessionCacheSize = 1; + + private bool cacheProducers = true; + + private bool cacheConsumers = true; + + private volatile bool active = true; + + private IDictionary cachedSessions = new Hashtable(); + /// - /// subclass that adds - /// Session, MessageProducer, and MessageConsumer caching. This ConnectionFactory - /// also switches the ReconnectOnException property to true - /// by default, allowing for automatic recovery of the underlying - /// Connection. + /// Initializes a new instance of the class. + /// and sets the ReconnectOnException to true + /// + public CachingConnectionFactory() + { + ReconnectOnException = true; + } + + /// + /// Initializes a new instance of the class for the given + /// IConnectionFactory + /// + /// The target connection factory. + public CachingConnectionFactory(IConnectionFactory targetConnectionFactory) : base(targetConnectionFactory) + { + ReconnectOnException = true; + } + + /// + /// Gets or sets the size of the session cache. /// /// - /// By default, only one single Session will be cached, with further requested - /// Sessions being created and disposed on demand. Consider raising the - /// SessionCacheSize property in case of a high-concurrency environment. + /// This cache size is the maximum limit for the number of cached Sessions + /// per session acknowledgement type (auto, client, dups_ok, transacted). + /// As a consequence, the actual number of cached Sessions may be up to + /// four times as high as the specified value - in the unlikely case + /// of mixing and matching different acknowledgement types. /// - /// NOTE: This ConnectionFactory requires explicit closing of all Sessions - /// obtained from its shared Connection. This is the usual recommendation for - /// native EMS access code anyway. However, with this ConnectionFactory, its use - /// is mandatory in order to actually allow for Session reuse. - /// - /// - /// Note also that MessageConsumers obtained from a cached Session won't get - /// closed until the Session will eventually be removed from the pool. This may - /// lead to semantic side effects in some cases. For a durable subscriber, the - /// logical Session.Close() call will also close the subscription. - /// Re-registering a durable consumer for the same subscription on the same - /// Session handle is not supported; close and reobtain a cached Session first. + /// Default is 1: caching a single Session, (re-)creating further ones on + /// demand. Specify a number like 10 if you'd like to raise the number of cached + /// Sessions; that said, 1 may be sufficient for low-concurrency scenarios. /// /// - /// - /// Juergen Hoeller - /// Mark Pollack (.NET) - public class CachingConnectionFactory : SingleConnectionFactory + /// The size of the session cache. + public int SessionCacheSize { - #region Logging Definition - - private static readonly ILog LOG = LogManager.GetLogger(typeof (CachingConnectionFactory)); - - #endregion - - private int sessionCacheSize = 1; - - private bool cacheProducers = true; - - private bool cacheConsumers = true; - - private volatile bool active = true; - - private IDictionary cachedSessions = new Hashtable(); - - /// - /// Initializes a new instance of the class. - /// and sets the ReconnectOnException to true - /// - public CachingConnectionFactory() + get { return sessionCacheSize; } + set { - ReconnectOnException = true; + AssertUtils.IsTrue(value >= 1, "Session cache size must be 1 or higher"); + sessionCacheSize = value; } + } - /// - /// Initializes a new instance of the class for the given - /// IConnectionFactory - /// - /// The target connection factory. - public CachingConnectionFactory(IConnectionFactory targetConnectionFactory) : base(targetConnectionFactory) - { - ReconnectOnException = true; - } + /// + /// Gets or sets a value indicating whether to cache MessageProducers per + /// Session instance. (more specifically: one MessageProducer per Destination + /// and Session). + /// + /// + /// Default is "true". Switch this to "false" in order to always, + /// recreate MessageProducers on demand. + /// + /// + /// true if should cache message producers; otherwise, false. + public bool CacheProducers + { + get { return cacheProducers; } + set { cacheProducers = value; } + } - /// - /// Gets or sets the size of the session cache. - /// - /// - /// This cache size is the maximum limit for the number of cached Sessions - /// per session acknowledgement type (auto, client, dups_ok, transacted). - /// As a consequence, the actual number of cached Sessions may be up to - /// four times as high as the specified value - in the unlikely case - /// of mixing and matching different acknowledgement types. - /// - /// Default is 1: caching a single Session, (re-)creating further ones on - /// demand. Specify a number like 10 if you'd like to raise the number of cached - /// Sessions; that said, 1 may be sufficient for low-concurrency scenarios. - /// - /// - /// The size of the session cache. - public int SessionCacheSize + /// + /// Gets or sets a value indicating whether o cache JMS MessageConsumers per + /// EMS Session instance. + /// + /// + /// Mmore specifically: one MessageConsumer per Destination, selector String + /// and Session. Note that durable subscribers will only be cached until + /// logical closing of the Session handle. + /// + /// Default is "true". Switch this to "false" in order to always + /// recreate MessageConsumers on demand. + /// + /// + /// true to cache consumers per session instance; otherwise, false. + public bool CacheConsumers + { + get { return cacheConsumers; } + set { cacheConsumers = value; } + } + + /// + /// Gets or sets a value indicating whether this instance is active. + /// + /// true if this instance is active; otherwise, false. + public bool IsActive + { + get { return active; } + set { active = value; } + } + + /// + /// Resets the Session cache as well as resetting the connection. + /// + public override void ResetConnection() + { + this.active = false; + lock (cachedSessions) { - get { return sessionCacheSize; } - set + foreach (DictionaryEntry dictionaryEntry in cachedSessions) { - AssertUtils.IsTrue(value >= 1, "Session cache size must be 1 or higher"); - sessionCacheSize = value; - } - } - - /// - /// Gets or sets a value indicating whether to cache MessageProducers per - /// Session instance. (more specifically: one MessageProducer per Destination - /// and Session). - /// - /// - /// Default is "true". Switch this to "false" in order to always, - /// recreate MessageProducers on demand. - /// - /// - /// true if should cache message producers; otherwise, false. - public bool CacheProducers - { - get { return cacheProducers; } - set { cacheProducers = value; } - } - - /// - /// Gets or sets a value indicating whether o cache JMS MessageConsumers per - /// EMS Session instance. - /// - /// - /// Mmore specifically: one MessageConsumer per Destination, selector String - /// and Session. Note that durable subscribers will only be cached until - /// logical closing of the Session handle. - /// - /// Default is "true". Switch this to "false" in order to always - /// recreate MessageConsumers on demand. - /// - /// - /// true to cache consumers per session instance; otherwise, false. - public bool CacheConsumers - { - get { return cacheConsumers; } - set { cacheConsumers = value; } - } - - /// - /// Gets or sets a value indicating whether this instance is active. - /// - /// true if this instance is active; otherwise, false. - public bool IsActive - { - get { return active; } - set { active = value; } - } - - /// - /// Resets the Session cache as well as resetting the connection. - /// - public override void ResetConnection() - { - this.active = false; - lock (cachedSessions) - { - foreach (DictionaryEntry dictionaryEntry in cachedSessions) + LinkedList sessionList = (LinkedList) dictionaryEntry.Value; + lock (sessionList) { - LinkedList sessionList = (LinkedList) dictionaryEntry.Value; - lock (sessionList) + foreach (ISession session in sessionList) { - foreach (ISession session in sessionList) + try { - try - { - session.Close(); - } - catch (Exception ex) - { - LOG.LogTrace(ex, "Could not close cached EMS Session"); - } + session.Close(); + } + catch (Exception ex) + { + LOG.LogTrace(ex, "Could not close cached EMS Session"); } } } - cachedSessions.Clear(); } - this.active = true; - // Now proceed with actual closing of the shared Connection... - base.ResetConnection(); + + cachedSessions.Clear(); } - /// - /// Obtaining a cached Session. - /// - /// The connection to operate on. - /// The session ack mode. - /// The Session to use - /// - public override ISession GetSession(IConnection con, SessionMode mode) + this.active = true; + // Now proceed with actual closing of the shared Connection... + base.ResetConnection(); + } + + /// + /// Obtaining a cached Session. + /// + /// The connection to operate on. + /// The session ack mode. + /// The Session to use + /// + public override ISession GetSession(IConnection con, SessionMode mode) + { + LinkedList sessionList; + lock (cachedSessions) { - LinkedList sessionList; - lock (cachedSessions) + sessionList = (LinkedList) cachedSessions[mode]; + if (sessionList == null) { - sessionList = (LinkedList) cachedSessions[mode]; - if (sessionList == null) - { - sessionList = new LinkedList(); - cachedSessions.Add(mode, sessionList); - } + sessionList = new LinkedList(); + cachedSessions.Add(mode, sessionList); } - - ISession session = null; - lock (sessionList) - { - if (sessionList.Count > 0) - { - session = (ISession) sessionList[0]; - sessionList.RemoveAt(0); - } - } - if (session != null) - { - if (LOG.IsEnabled(LogLevel.Debug)) - { - LOG.LogDebug("Found cached Session for mode " + mode + ": " - + (session is IDecoratorSession ? ((IDecoratorSession) session).TargetSession : session)); - } - } - else - { - ISession targetSession = CreateSession(con, mode); - if (LOG.IsEnabled(LogLevel.Debug)) - { - LOG.LogDebug("Creating cached Session for mode " + mode + ": " + targetSession); - } - session = GetCachedSessionWrapper(targetSession, sessionList); - } - return session; } - protected virtual ISession CreateSession(IConnection con, SessionMode mode) + ISession session = null; + lock (sessionList) { - bool transacted = (mode == SessionMode.SessionTransacted); - SessionMode ackMode = (transacted ? SessionMode.SessionTransacted : mode); - return con.CreateSession(transacted, ackMode); + if (sessionList.Count > 0) + { + session = (ISession) sessionList[0]; + sessionList.RemoveAt(0); + } } - /// - /// Wraps the given Session so that it delegates every method call to the target session but - /// adapts close calls. This is useful for allowing application code to - /// handle a special framework Session just like an ordinary Session. - /// - /// The original Session to wrap. - /// The List of cached Sessions that the given Session belongs to. - /// The wrapped Session - protected virtual ISession GetCachedSessionWrapper(ISession targetSession, LinkedList sessionList) + if (session != null) { - return new CachedSession(targetSession, sessionList, this); + if (LOG.IsEnabled(LogLevel.Debug)) + { + LOG.LogDebug("Found cached Session for mode " + mode + ": " + + (session is IDecoratorSession ? ((IDecoratorSession) session).TargetSession : session)); + } } + else + { + ISession targetSession = CreateSession(con, mode); + if (LOG.IsEnabled(LogLevel.Debug)) + { + LOG.LogDebug("Creating cached Session for mode " + mode + ": " + targetSession); + } + + session = GetCachedSessionWrapper(targetSession, sessionList); + } + + return session; + } + + protected virtual ISession CreateSession(IConnection con, SessionMode mode) + { + bool transacted = (mode == SessionMode.SessionTransacted); + SessionMode ackMode = (transacted ? SessionMode.SessionTransacted : mode); + return con.CreateSession(transacted, ackMode); + } + + /// + /// Wraps the given Session so that it delegates every method call to the target session but + /// adapts close calls. This is useful for allowing application code to + /// handle a special framework Session just like an ordinary Session. + /// + /// The original Session to wrap. + /// The List of cached Sessions that the given Session belongs to. + /// The wrapped Session + protected virtual ISession GetCachedSessionWrapper(ISession targetSession, LinkedList sessionList) + { + return new CachedSession(targetSession, sessionList, this); } } diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Connections/ChainedExceptionListener.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Connections/ChainedExceptionListener.cs index b75f16a8..32e066f8 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Connections/ChainedExceptionListener.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Connections/ChainedExceptionListener.cs @@ -21,50 +21,49 @@ using System.Collections; using Spring.Util; -namespace Spring.Messaging.Ems.Connections +namespace Spring.Messaging.Ems.Connections; + +/// +/// Implementation of Spring IExceptionListener interface that supports +/// chaining allowing the addition of multiple ExceptionListener instances in order. +/// +/// Juergen Hoeller +/// Mark Pollack (.NET) +public class ChainedExceptionListener : IExceptionListener { + private ArrayList listeners = new ArrayList(2); + /// - /// Implementation of Spring IExceptionListener interface that supports - /// chaining allowing the addition of multiple ExceptionListener instances in order. + /// Adds the exception listener to the chain /// - /// Juergen Hoeller - /// Mark Pollack (.NET) - public class ChainedExceptionListener : IExceptionListener + /// The listener. + public void AddListener(IExceptionListener listener) { - private ArrayList listeners = new ArrayList(2); + AssertUtils.ArgumentNotNull(listener, "listener", "ExceptionListener must not be null"); + listeners.Add(listener); + } - /// - /// Adds the exception listener to the chain - /// - /// The listener. - public void AddListener(IExceptionListener listener) + /// + /// Called when an exception occurs in message processing. + /// + /// The exception. + public void OnException(EMSException exception) + { + foreach (IExceptionListener listener in listeners) { - AssertUtils.ArgumentNotNull(listener, "listener", "ExceptionListener must not be null"); - listeners.Add(listener); + listener.OnException(exception); } + } - /// - /// Called when an exception occurs in message processing. - /// - /// The exception. - public void OnException(EMSException exception) + /// + /// Gets the exception listeners as an array. + /// + /// The exception listeners. + public IExceptionListener[] Listeners + { + get { - foreach (IExceptionListener listener in listeners) - { - listener.OnException(exception); - } - } - - /// - /// Gets the exception listeners as an array. - /// - /// The exception listeners. - public IExceptionListener[] Listeners - { - get - { - return (IExceptionListener[]) listeners.ToArray(typeof (IExceptionListener)); - } + return (IExceptionListener[]) listeners.ToArray(typeof(IExceptionListener)); } } } diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Connections/ConnectionFactoryUtils.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Connections/ConnectionFactoryUtils.cs index 3a52e86f..fa187989 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Connections/ConnectionFactoryUtils.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Connections/ConnectionFactoryUtils.cs @@ -24,388 +24,396 @@ using Spring.Messaging.Ems.Support; using Spring.Transaction.Support; using Spring.Util; -namespace Spring.Messaging.Ems.Connections +namespace Spring.Messaging.Ems.Connections; + +/// Helper class for obtaining transactional EMS resources +/// for a given ConnectionFactory. +/// +/// Juergen Hoeller +/// Mark Pollack (.NET) +public abstract class ConnectionFactoryUtils { - /// Helper class for obtaining transactional EMS resources - /// for a given ConnectionFactory. + #region Logging + + private static readonly ILogger LOG = LogManager.GetLogger(); + + #endregion + + /// + /// Releases the given connection, stopping it (if necessary) and eventually closing it. /// - /// Juergen Hoeller - /// Mark Pollack (.NET) - public abstract class ConnectionFactoryUtils + /// Checks , if available. + /// This is essentially a more sophisticated version of + /// + /// + /// The connection to release. (if this is null, the call will be ignored) + /// The ConnectionFactory that the Connection was obtained from. (may be null) + /// whether the Connection might have been started by the application. + public static void ReleaseConnection(IConnection connection, IConnectionFactory cf, bool started) { - #region Logging - - private static readonly ILogger LOG = LogManager.GetLogger(); - - #endregion - - /// - /// Releases the given connection, stopping it (if necessary) and eventually closing it. - /// - /// Checks , if available. - /// This is essentially a more sophisticated version of - /// - /// - /// The connection to release. (if this is null, the call will be ignored) - /// The ConnectionFactory that the Connection was obtained from. (may be null) - /// whether the Connection might have been started by the application. - public static void ReleaseConnection(IConnection connection, IConnectionFactory cf, bool started) + if (connection == null) { - if (connection == null) - { - return; - } + return; + } - if (started && cf is ISmartConnectionFactory && ((ISmartConnectionFactory)cf).ShouldStop(connection)) - { - try - { - connection.Stop(); - } - catch (Exception ex) - { - LOG.LogDebug(ex, "Could not stop EMS Connection before closing it"); - - } - } + if (started && cf is ISmartConnectionFactory && ((ISmartConnectionFactory) cf).ShouldStop(connection)) + { try { - connection.Close(); + connection.Stop(); } catch (Exception ex) { - LOG.LogDebug(ex, "Could not close EMS Connection"); + LOG.LogDebug(ex, "Could not stop EMS Connection before closing it"); } } - /// - /// Return the innermost target Session of the given Session. If the given - /// Session is a decorated session, it will be unwrapped until a non-decorated - /// Session is found. Otherwise, the passed-in Session will be returned as-is. - /// - /// The session to unwrap - /// The innermost target Session, or the passed-in one if no decorator - public static ISession GetTargetSession(ISession session) + try { - ISession sessionToUse = session; - while (sessionToUse is IDecoratorSession) - { - sessionToUse = ((IDecoratorSession)sessionToUse).TargetSession; - } - return sessionToUse; + connection.Close(); + } + catch (Exception ex) + { + LOG.LogDebug(ex, "Could not close EMS Connection"); + } + } + + /// + /// Return the innermost target Session of the given Session. If the given + /// Session is a decorated session, it will be unwrapped until a non-decorated + /// Session is found. Otherwise, the passed-in Session will be returned as-is. + /// + /// The session to unwrap + /// The innermost target Session, or the passed-in one if no decorator + public static ISession GetTargetSession(ISession session) + { + ISession sessionToUse = session; + while (sessionToUse is IDecoratorSession) + { + sessionToUse = ((IDecoratorSession) sessionToUse).TargetSession; } - /// - /// Determines whether the given JMS Session is transactional, that is, - /// bound to the current thread by Spring's transaction facilities. - /// - /// The session to check. - /// The ConnectionFactory that the Session originated from - /// - /// true if is session transactional, bound to current thread; otherwise, false. - /// - public static bool IsSessionTransactional(ISession session, IConnectionFactory cf) + return sessionToUse; + } + + /// + /// Determines whether the given JMS Session is transactional, that is, + /// bound to the current thread by Spring's transaction facilities. + /// + /// The session to check. + /// The ConnectionFactory that the Session originated from + /// + /// true if is session transactional, bound to current thread; otherwise, false. + /// + public static bool IsSessionTransactional(ISession session, IConnectionFactory cf) + { + if (session == null || cf == null) { - if (session == null || cf == null) - { - return false; - } - EmsResourceHolder resourceHolder = (EmsResourceHolder) TransactionSynchronizationManager.GetResource(cf); - return (resourceHolder != null && resourceHolder.ContainsSession(session)); + return false; } - /// Obtain a EMS Session that is synchronized with the current transaction, if any. - /// the ConnectionFactory to obtain a Session for - /// - /// the existing EMS Connection to obtain a Session for - /// (may be null) - /// - /// whether to allow for a local EMS transaction - /// that is synchronized with a Spring-managed transaction (where the main transaction - /// might be a ADO.NET-based one for a specific DataSource, for example), with the EMS - /// transaction committing right after the main transaction. If not allowed, the given - /// ConnectionFactory needs to handle transaction enlistment underneath the covers. - /// - /// the transactional Session, or null if none found - /// - /// EMSException in case of EMS failure - public static ISession GetTransactionalSession(IConnectionFactory cf, IConnection existingCon, - bool synchedLocalTransactionAllowed) + EmsResourceHolder resourceHolder = (EmsResourceHolder) TransactionSynchronizationManager.GetResource(cf); + return (resourceHolder != null && resourceHolder.ContainsSession(session)); + } + + /// Obtain a EMS Session that is synchronized with the current transaction, if any. + /// the ConnectionFactory to obtain a Session for + /// + /// the existing EMS Connection to obtain a Session for + /// (may be null) + /// + /// whether to allow for a local EMS transaction + /// that is synchronized with a Spring-managed transaction (where the main transaction + /// might be a ADO.NET-based one for a specific DataSource, for example), with the EMS + /// transaction committing right after the main transaction. If not allowed, the given + /// ConnectionFactory needs to handle transaction enlistment underneath the covers. + /// + /// the transactional Session, or null if none found + /// + /// EMSException in case of EMS failure + public static ISession GetTransactionalSession(IConnectionFactory cf, IConnection existingCon, + bool synchedLocalTransactionAllowed) + { + return + DoGetTransactionalSession(cf, + new AnonymousClassResourceFactory(existingCon, cf, + synchedLocalTransactionAllowed), true); + } + + /// + /// Obtain a EMS Session that is synchronized with the current transaction, if any. + /// + /// the TransactionSynchronizationManager key to bind to + /// (usually the ConnectionFactory) + /// the ResourceFactory to use for extracting or creating + /// EMS resources + /// whether the underlying Connection approach should be + /// started in order to allow for receiving messages. Note that a reused Connection + /// may already have been started before, even if this flag is false. + /// + /// the transactional Session, or null if none found + /// + /// EMSException in case of EMS failure + public static ISession DoGetTransactionalSession(Object resourceKey, ResourceFactory resourceFactory, bool startConnection) + { + AssertUtils.ArgumentNotNull(resourceKey, "Resource key must not be null"); + AssertUtils.ArgumentNotNull(resourceKey, "ResourceFactory must not be null"); + + EmsResourceHolder resourceHolder = + (EmsResourceHolder) TransactionSynchronizationManager.GetResource(resourceKey); + if (resourceHolder != null) { - return - DoGetTransactionalSession(cf, - new AnonymousClassResourceFactory(existingCon, cf, - synchedLocalTransactionAllowed), true); - } - - /// - /// Obtain a EMS Session that is synchronized with the current transaction, if any. - /// - /// the TransactionSynchronizationManager key to bind to - /// (usually the ConnectionFactory) - /// the ResourceFactory to use for extracting or creating - /// EMS resources - /// whether the underlying Connection approach should be - /// started in order to allow for receiving messages. Note that a reused Connection - /// may already have been started before, even if this flag is false. - /// - /// the transactional Session, or null if none found - /// - /// EMSException in case of EMS failure - public static ISession DoGetTransactionalSession(Object resourceKey, ResourceFactory resourceFactory, bool startConnection) - { - AssertUtils.ArgumentNotNull(resourceKey, "Resource key must not be null"); - AssertUtils.ArgumentNotNull(resourceKey, "ResourceFactory must not be null"); - - EmsResourceHolder resourceHolder = - (EmsResourceHolder)TransactionSynchronizationManager.GetResource(resourceKey); - if (resourceHolder != null) + ISession rhSession = resourceFactory.GetSession(resourceHolder); + if (rhSession != null) { - ISession rhSession = resourceFactory.GetSession(resourceHolder); - if (rhSession != null) - { - if (startConnection) - { - IConnection conn = resourceFactory.GetConnection(resourceHolder); - if (conn != null) - { - conn.Start(); - } - } - return rhSession; - } - } - if (!TransactionSynchronizationManager.SynchronizationActive) - { - return null; - } - EmsResourceHolder resourceHolderToUse = resourceHolder; - if (resourceHolderToUse == null) - { - resourceHolderToUse = new EmsResourceHolder(); - } - - IConnection con = resourceFactory.GetConnection(resourceHolderToUse); - ISession session = null; - try - { - bool isExistingCon = (con != null); - if (!isExistingCon) - { - con = resourceFactory.CreateConnection(); - resourceHolderToUse.AddConnection(con); - } - session = resourceFactory.CreateSession(con); - resourceHolderToUse.AddSession(session, con); if (startConnection) { - con.Start(); - } - } - catch (EMSException) - { - if (session != null) - { - try + IConnection conn = resourceFactory.GetConnection(resourceHolder); + if (conn != null) { - session.Close(); - } - catch (Exception) - { - // ignore + conn.Start(); } } - if (con != null) - { - try - { - con.Close(); - } - catch (Exception) - { - // ignore - } - } - throw; + + return rhSession; } - if (resourceHolderToUse != resourceHolder) - { - TransactionSynchronizationManager.RegisterSynchronization( - new EmsResourceSynchronization(resourceHolderToUse, - resourceKey, resourceFactory.SynchedLocalTransactionAllowed)); - resourceHolderToUse.SynchronizedWithTransaction = true; - TransactionSynchronizationManager.BindResource(resourceKey, resourceHolderToUse); - } - return session; } - #region ResourceFactory helper classes - - private class AnonymousClassResourceFactory : ResourceFactory + if (!TransactionSynchronizationManager.SynchronizationActive) { - private IConnection existingCon; - private IConnectionFactory cf; - private bool synchedLocalTransactionAllowed; - - public AnonymousClassResourceFactory(IConnection existingCon, IConnectionFactory cf, - bool synchedLocalTransactionAllowed) - { - InitBlock(existingCon, cf, synchedLocalTransactionAllowed); - } - - private void InitBlock(IConnection existingCon, IConnectionFactory cf, bool synchedLocalTransactionAllowed) - { - this.existingCon = existingCon; - this.cf = cf; - this.synchedLocalTransactionAllowed = synchedLocalTransactionAllowed; - } - - public virtual ISession GetSession(EmsResourceHolder holder) - { - return holder.GetSession(typeof(ISession), existingCon); - } - - public virtual IConnection GetConnection(EmsResourceHolder holder) - { - return (existingCon != null ? existingCon : holder.GetConnection()); - } - - public virtual IConnection CreateConnection() - { - return cf.CreateConnection(); - } - - public virtual ISession CreateSession(IConnection con) - { - return con.CreateSession(synchedLocalTransactionAllowed, Session.SESSION_TRANSACTED); - } - - public bool SynchedLocalTransactionAllowed - { - get { return synchedLocalTransactionAllowed; } - } + return null; } - #endregion + EmsResourceHolder resourceHolderToUse = resourceHolder; + if (resourceHolderToUse == null) + { + resourceHolderToUse = new EmsResourceHolder(); + } - #region Helper classes/interfaces + IConnection con = resourceFactory.GetConnection(resourceHolderToUse); + ISession session = null; + try + { + bool isExistingCon = (con != null); + if (!isExistingCon) + { + con = resourceFactory.CreateConnection(); + resourceHolderToUse.AddConnection(con); + } - /// Callback interface for resource creation. - /// Serving as argument for the DoGetTransactionalSession method. + session = resourceFactory.CreateSession(con); + resourceHolderToUse.AddSession(session, con); + if (startConnection) + { + con.Start(); + } + } + catch (EMSException) + { + if (session != null) + { + try + { + session.Close(); + } + catch (Exception) + { + // ignore + } + } + + if (con != null) + { + try + { + con.Close(); + } + catch (Exception) + { + // ignore + } + } + + throw; + } + + if (resourceHolderToUse != resourceHolder) + { + TransactionSynchronizationManager.RegisterSynchronization( + new EmsResourceSynchronization(resourceHolderToUse, + resourceKey, resourceFactory.SynchedLocalTransactionAllowed)); + resourceHolderToUse.SynchronizedWithTransaction = true; + TransactionSynchronizationManager.BindResource(resourceKey, resourceHolderToUse); + } + + return session; + } + + #region ResourceFactory helper classes + + private class AnonymousClassResourceFactory : ResourceFactory + { + private IConnection existingCon; + private IConnectionFactory cf; + private bool synchedLocalTransactionAllowed; + + public AnonymousClassResourceFactory(IConnection existingCon, IConnectionFactory cf, + bool synchedLocalTransactionAllowed) + { + InitBlock(existingCon, cf, synchedLocalTransactionAllowed); + } + + private void InitBlock(IConnection existingCon, IConnectionFactory cf, bool synchedLocalTransactionAllowed) + { + this.existingCon = existingCon; + this.cf = cf; + this.synchedLocalTransactionAllowed = synchedLocalTransactionAllowed; + } + + public virtual ISession GetSession(EmsResourceHolder holder) + { + return holder.GetSession(typeof(ISession), existingCon); + } + + public virtual IConnection GetConnection(EmsResourceHolder holder) + { + return (existingCon != null ? existingCon : holder.GetConnection()); + } + + public virtual IConnection CreateConnection() + { + return cf.CreateConnection(); + } + + public virtual ISession CreateSession(IConnection con) + { + return con.CreateSession(synchedLocalTransactionAllowed, Session.SESSION_TRANSACTED); + } + + public bool SynchedLocalTransactionAllowed + { + get { return synchedLocalTransactionAllowed; } + } + } + + #endregion + + #region Helper classes/interfaces + + /// Callback interface for resource creation. + /// Serving as argument for the DoGetTransactionalSession method. + /// + public interface ResourceFactory + { + /// Fetch an appropriate Session from the given EmsResourceHolder. + /// the EmsResourceHolder + /// + /// an appropriate Session fetched from the holder, + /// or null if none found + /// + ISession GetSession(EmsResourceHolder holder); + + /// Fetch an appropriate Connection from the given EmsResourceHolder. + /// the EmsResourceHolder + /// + /// an appropriate Connection fetched from the holder, + /// or null if none found + /// + IConnection GetConnection(EmsResourceHolder holder); + + /// Create a new EMS Connection for registration with a EmsResourceHolder. + /// the new EMS Connection + /// + /// EMSException if thrown by EMS API methods + IConnection CreateConnection(); + + /// Create a new EMS Session for registration with a EmsResourceHolder. + /// the EMS Connection to create a Session for + /// + /// the new EMS Session + /// + /// EMSException if thrown by EMS API methods + ISession CreateSession(IConnection con); + + /// + /// Return whether to allow for a local EMS transaction that is synchronized with + /// a Spring-managed transaction (where the main transaction might be a ADO.NET-based + /// one for a specific IDbProvider, for example), with the EMS transaction + /// committing right after the main transaction. + /// Returns whether to allow for synchronizing a local EMS transaction /// - public interface ResourceFactory + /// + bool SynchedLocalTransactionAllowed { get; } + } + + /// Callback for resource cleanup at the end of a non-native EMS transaction + /// + private class EmsResourceSynchronization : TransactionSynchronizationAdapter + { + private object resourceKey; + + private EmsResourceHolder resourceHolder; + + private bool transacted; + + private bool holderActive = true; + + public EmsResourceSynchronization(EmsResourceHolder resourceHolder, object resourceKey, bool transacted) { - /// Fetch an appropriate Session from the given EmsResourceHolder. - /// the EmsResourceHolder - /// - /// an appropriate Session fetched from the holder, - /// or null if none found - /// - ISession GetSession(EmsResourceHolder holder); - - /// Fetch an appropriate Connection from the given EmsResourceHolder. - /// the EmsResourceHolder - /// - /// an appropriate Connection fetched from the holder, - /// or null if none found - /// - IConnection GetConnection(EmsResourceHolder holder); - - /// Create a new EMS Connection for registration with a EmsResourceHolder. - /// the new EMS Connection - /// - /// EMSException if thrown by EMS API methods - IConnection CreateConnection(); - - /// Create a new EMS Session for registration with a EmsResourceHolder. - /// the EMS Connection to create a Session for - /// - /// the new EMS Session - /// - /// EMSException if thrown by EMS API methods - ISession CreateSession(IConnection con); - - - /// - /// Return whether to allow for a local EMS transaction that is synchronized with - /// a Spring-managed transaction (where the main transaction might be a ADO.NET-based - /// one for a specific IDbProvider, for example), with the EMS transaction - /// committing right after the main transaction. - /// Returns whether to allow for synchronizing a local EMS transaction - /// - /// - bool SynchedLocalTransactionAllowed { get; } + this.resourceKey = resourceKey; + this.resourceHolder = resourceHolder; + this.transacted = transacted; } - /// Callback for resource cleanup at the end of a non-native EMS transaction - /// - private class EmsResourceSynchronization : TransactionSynchronizationAdapter + public override void Suspend() { - private object resourceKey; - - private EmsResourceHolder resourceHolder; - - private bool transacted; - - private bool holderActive = true; - - public EmsResourceSynchronization(EmsResourceHolder resourceHolder, object resourceKey, bool transacted) - { - this.resourceKey = resourceKey; - this.resourceHolder = resourceHolder; - this.transacted = transacted; - } - - public override void Suspend() - { - if (holderActive) - { - TransactionSynchronizationManager.UnbindResource(resourceKey); - } - } - - public override void Resume() - { - if (holderActive) - { - TransactionSynchronizationManager.BindResource(resourceKey, resourceHolder); - } - } - - public override void BeforeCompletion() + if (holderActive) { TransactionSynchronizationManager.UnbindResource(resourceKey); - holderActive = false; - if (!transacted) - { - resourceHolder.CloseAll(); - } } + } - public override void AfterCommit() + public override void Resume() + { + if (holderActive) { - if (transacted) - { - try - { - resourceHolder.CommitAll(); - } - catch (EMSException ex) - { - throw new SynchedLocalTransactionFailedException("Local EMS transaction failed to commit", ex); - } - } + TransactionSynchronizationManager.BindResource(resourceKey, resourceHolder); } + } - public override void AfterCompletion(TransactionSynchronizationStatus status) + public override void BeforeCompletion() + { + TransactionSynchronizationManager.UnbindResource(resourceKey); + holderActive = false; + if (!transacted) { - if (transacted) + resourceHolder.CloseAll(); + } + } + + public override void AfterCommit() + { + if (transacted) + { + try { - resourceHolder.CloseAll(); + resourceHolder.CommitAll(); + } + catch (EMSException ex) + { + throw new SynchedLocalTransactionFailedException("Local EMS transaction failed to commit", ex); } } } - #endregion + public override void AfterCompletion(TransactionSynchronizationStatus status) + { + if (transacted) + { + resourceHolder.CloseAll(); + } + } } + + #endregion } diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Connections/EmsResourceHolder.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Connections/EmsResourceHolder.cs index 325b22e1..4c42ba99 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Connections/EmsResourceHolder.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Connections/EmsResourceHolder.cs @@ -25,270 +25,272 @@ using Spring.Messaging.Ems.Common; using Spring.Transaction.Support; using Spring.Util; -namespace Spring.Messaging.Ems.Connections +namespace Spring.Messaging.Ems.Connections; + +/// Connection holder, wrapping a EMS Connection and a EMS Session. +/// EmsTransactionManager binds instances of this class to the thread, +/// for a given EMS ConnectionFactory. +/// +///

Note: This is an SPI class, not intended to be used by applications.

+/// +///
+/// Juergen Hoeller +/// Mark Pollack (.NET) +public class EmsResourceHolder : ResourceHolderSupport { - /// Connection holder, wrapping a EMS Connection and a EMS Session. - /// EmsTransactionManager binds instances of this class to the thread, - /// for a given EMS ConnectionFactory. - /// - ///

Note: This is an SPI class, not intended to be used by applications.

- /// - ///
- /// Juergen Hoeller - /// Mark Pollack (.NET) - public class EmsResourceHolder : ResourceHolderSupport + #region Logging + + private static readonly ILogger logger = LogManager.GetLogger(); + + #endregion + + #region Fields + + private IConnectionFactory connectionFactory; + + private bool frozen = false; + + private IList connections = new LinkedList(); + + private IList sessions = new LinkedList(); + + private IDictionary sessionsPerConnection = new Hashtable(); + + #endregion + + #region Constructor (s) + + /// Create a new EmsResourceHolder that is open for resources to be added. + public EmsResourceHolder() { - #region Logging + } - private static readonly ILogger logger = LogManager.GetLogger(); + /// + /// Initializes a new instance of the class + /// at is open for resources to be added. + /// + /// The connection factory that this + /// resource holder is associated with (may be null) + /// + public EmsResourceHolder(IConnectionFactory connectionFactory) + { + this.connectionFactory = connectionFactory; + } - #endregion + /// + /// Initializes a new instance of the class for the + /// given Session. + /// + /// The session. + public EmsResourceHolder(ISession session) + { + AddSession(session); + frozen = true; + } - #region Fields + /// Create a new EmsResourceHolder for the given EMS resources. + /// the EMS Connection + /// + /// the EMS Session + /// + public EmsResourceHolder(IConnection connection, ISession session) + { + AddConnection(connection); + AddSession(session, connection); + this.frozen = true; + } - private IConnectionFactory connectionFactory; + /// + /// Initializes a new instance of the class. + /// + /// The connection factory. + /// The connection. + /// The session. + public EmsResourceHolder(IConnectionFactory connectionFactory, IConnection connection, ISession session) + { + this.connectionFactory = connectionFactory; + AddConnection(connection); + AddSession(session, connection); + this.frozen = true; + } - private bool frozen = false; + #endregion - private IList connections = new LinkedList(); + #region Properties - private IList sessions = new LinkedList(); - - private IDictionary sessionsPerConnection = new Hashtable(); - - #endregion - - - #region Constructor (s) - - /// Create a new EmsResourceHolder that is open for resources to be added. - public EmsResourceHolder() + /// + /// Gets a value indicating whether this is frozen, namely that + /// additional resources can be registered with the holder. If using any of the constructors with + /// a Session, the holder will be set to the frozen state. + /// + /// true if frozen; otherwise, false. + virtual public bool Frozen + { + get { + return frozen; } + } + #endregion - /// - /// Initializes a new instance of the class - /// at is open for resources to be added. - /// - /// The connection factory that this - /// resource holder is associated with (may be null) - /// - public EmsResourceHolder(IConnectionFactory connectionFactory) + #region Methods + + /// + /// Adds the connection to the list of resources managed by this holder. + /// + /// The connection. + public void AddConnection(IConnection connection) + { + AssertUtils.IsTrue(!frozen, "Cannot add Connection because EmsResourceHolder is frozen"); + AssertUtils.ArgumentNotNull(connection, "Connection must not be null"); + if (!connections.Contains(connection)) { - this.connectionFactory = connectionFactory; + connections.Add(connection); } + } - /// - /// Initializes a new instance of the class for the - /// given Session. - /// - /// The session. - public EmsResourceHolder(ISession session) + /// + /// Adds the session to the list of resources managed by this holder. + /// + /// The session. + public void AddSession(ISession session) + { + AddSession(session, null); + } + + /// + /// Adds the session and connection to the list of resources managed by this holder. + /// + /// The session. + /// The connection. + public void AddSession(ISession session, IConnection connection) + { + AssertUtils.IsTrue(!frozen, "Cannot add Session because EmsResourceHolder is frozen"); + AssertUtils.ArgumentNotNull(session, "Session must not be null"); + if (!sessions.Contains(session)) { - AddSession(session); - frozen = true; - } - - /// Create a new EmsResourceHolder for the given EMS resources. - /// the EMS Connection - /// - /// the EMS Session - /// - public EmsResourceHolder(IConnection connection, ISession session) - { - AddConnection(connection); - AddSession(session, connection); - this.frozen = true; - } - - /// - /// Initializes a new instance of the class. - /// - /// The connection factory. - /// The connection. - /// The session. - public EmsResourceHolder(IConnectionFactory connectionFactory, IConnection connection, ISession session) - { - this.connectionFactory = connectionFactory; - AddConnection(connection); - AddSession(session, connection); - this.frozen = true; - } - #endregion - - #region Properties - - /// - /// Gets a value indicating whether this is frozen, namely that - /// additional resources can be registered with the holder. If using any of the constructors with - /// a Session, the holder will be set to the frozen state. - /// - /// true if frozen; otherwise, false. - virtual public bool Frozen - { - get - { - return frozen; - } - - } - #endregion - - #region Methods - - /// - /// Adds the connection to the list of resources managed by this holder. - /// - /// The connection. - public void AddConnection(IConnection connection) - { - AssertUtils.IsTrue(!frozen, "Cannot add Connection because EmsResourceHolder is frozen"); - AssertUtils.ArgumentNotNull(connection, "Connection must not be null"); - if (!connections.Contains(connection)) - { - connections.Add(connection); - } - } - - /// - /// Adds the session to the list of resources managed by this holder. - /// - /// The session. - public void AddSession(ISession session) - { - AddSession(session, null); - } - - /// - /// Adds the session and connection to the list of resources managed by this holder. - /// - /// The session. - /// The connection. - public void AddSession(ISession session, IConnection connection) - { - AssertUtils.IsTrue(!frozen, "Cannot add Session because EmsResourceHolder is frozen"); - AssertUtils.ArgumentNotNull(session, "Session must not be null"); - if (!sessions.Contains(session)) - { - sessions.Add(session); - if (connection != null) - { - IList sessionsList = (IList)sessionsPerConnection[connection]; - if (sessionsList == null) - { - sessionsList = new LinkedList(); - sessionsPerConnection[connection] = sessionsList; - } - sessionsList.Add(session); - } - } - } - - /// - /// Gets the connection managed by this resource holder - /// - /// A Connection, or null if no managed connection. - public virtual IConnection GetConnection() - { - return (!(this.connections.Count == 0) ? (IConnection)this.connections[0] : null); - } - - /// - /// Gets the connection of a given type managed by this resource holder. This is used - /// when storing Queue or Topic Connections (from the older 1.0.2 API) as compared to the - /// 'unified domain' API , just Connection, in the newer 1.2 API. - /// - /// Type of the connection. - /// The connection, or null if not found. - public virtual IConnection GetConnection(Type connectionType) - { - return (IConnection)CollectionUtils.FindValueOfType(this.connections, connectionType); - } - - /// - /// Gets the first session manged by this holder or null if not available. - /// - /// The session or null if not available. - public virtual ISession GetSession() - { - return (!(this.sessions.Count == 0) ? (ISession)this.sessions[0] : null); - } - - /// - /// Gets the session managed by this holder by type. - /// - /// Type of the session. - /// The session or null if not available. - public virtual ISession GetSession(Type sessionType) - { - return GetSession(sessionType, null); - } - - /// - /// Gets the session of a given type associated with the given connection - /// - /// Type of the session. - /// The connection. - /// The sessin or null if not available. - public virtual ISession GetSession(Type sessionType, IConnection connection) - { - IList sessions = this.sessions; + sessions.Add(session); if (connection != null) { - sessions = (IList)sessionsPerConnection[connection]; - } - return (ISession)CollectionUtils.FindValueOfType(sessions, sessionType); - } - - /// - /// Commits all sessions. - /// - public virtual void CommitAll() - { - foreach (ISession session in sessions) - { - session.Commit(); - } - } - - /// - /// Closes all sessions then stops and closes all connections, in that order. - /// - public virtual void CloseAll() - { - foreach (ISession session in sessions) - { - try + IList sessionsList = (IList) sessionsPerConnection[connection]; + if (sessionsList == null) { - session.Close(); + sessionsList = new LinkedList(); + sessionsPerConnection[connection] = sessionsList; } - catch (Exception ex) - { - logger.LogDebug(ex, "Could not close EMS Session after transaction"); - } - } - foreach (IConnection connection in connections) - { - ConnectionFactoryUtils.ReleaseConnection(connection, connectionFactory, true); - } - this.connections.Clear(); - this.sessions.Clear(); - this.sessionsPerConnection.Clear(); - } - /// - /// Determines whether the holder contains the specified session. - /// - /// The session. - /// - /// true if the holder contains the specified session; otherwise, false. - /// - public bool ContainsSession(ISession session) - { - return this.sessions.Contains(session); + sessionsList.Add(session); + } } - - #endregion } -} + + /// + /// Gets the connection managed by this resource holder + /// + /// A Connection, or null if no managed connection. + public virtual IConnection GetConnection() + { + return (!(this.connections.Count == 0) ? (IConnection) this.connections[0] : null); + } + + /// + /// Gets the connection of a given type managed by this resource holder. This is used + /// when storing Queue or Topic Connections (from the older 1.0.2 API) as compared to the + /// 'unified domain' API , just Connection, in the newer 1.2 API. + /// + /// Type of the connection. + /// The connection, or null if not found. + public virtual IConnection GetConnection(Type connectionType) + { + return (IConnection) CollectionUtils.FindValueOfType(this.connections, connectionType); + } + + /// + /// Gets the first session manged by this holder or null if not available. + /// + /// The session or null if not available. + public virtual ISession GetSession() + { + return (!(this.sessions.Count == 0) ? (ISession) this.sessions[0] : null); + } + + /// + /// Gets the session managed by this holder by type. + /// + /// Type of the session. + /// The session or null if not available. + public virtual ISession GetSession(Type sessionType) + { + return GetSession(sessionType, null); + } + + /// + /// Gets the session of a given type associated with the given connection + /// + /// Type of the session. + /// The connection. + /// The sessin or null if not available. + public virtual ISession GetSession(Type sessionType, IConnection connection) + { + IList sessions = this.sessions; + if (connection != null) + { + sessions = (IList) sessionsPerConnection[connection]; + } + + return (ISession) CollectionUtils.FindValueOfType(sessions, sessionType); + } + + /// + /// Commits all sessions. + /// + public virtual void CommitAll() + { + foreach (ISession session in sessions) + { + session.Commit(); + } + } + + /// + /// Closes all sessions then stops and closes all connections, in that order. + /// + public virtual void CloseAll() + { + foreach (ISession session in sessions) + { + try + { + session.Close(); + } + catch (Exception ex) + { + logger.LogDebug(ex, "Could not close EMS Session after transaction"); + } + } + + foreach (IConnection connection in connections) + { + ConnectionFactoryUtils.ReleaseConnection(connection, connectionFactory, true); + } + + this.connections.Clear(); + this.sessions.Clear(); + this.sessionsPerConnection.Clear(); + } + + /// + /// Determines whether the holder contains the specified session. + /// + /// The session. + /// + /// true if the holder contains the specified session; otherwise, false. + /// + public bool ContainsSession(ISession session) + { + return this.sessions.Contains(session); + } + + #endregion +} \ No newline at end of file diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Connections/EmsTransactionManager.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Connections/EmsTransactionManager.cs index 3999cd6c..a2216859 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Connections/EmsTransactionManager.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Connections/EmsTransactionManager.cs @@ -26,392 +26,392 @@ using Spring.Objects.Factory; using Spring.Transaction; using Spring.Transaction.Support; -namespace Spring.Messaging.Ems.Connections +namespace Spring.Messaging.Ems.Connections; + +/// +/// A implementation +/// for a single EMS ConnectionFactory. Binds a +/// Connection/Session pair from the specified ConnecctionFactory to the thread, +/// potentially allowing for one thread-bound Session per ConnectionFactory. +/// +/// +/// +/// Application code is required to retrieve the transactional Session via +/// . Spring's +/// will autodetect a thread-bound Session and +/// automatically participate in it. +/// +/// +/// Transaction synchronization is turned off by default, as this manager might be used +/// alongside an IDbProvider based Spring transaction manager such as the +/// AdoPlatformTransactionManager, which has stronger needs for synchronization. +/// +/// +/// Juergen Hoeller +/// Mark Pollack (.NET) +public class EmsTransactionManager : AbstractPlatformTransactionManager, + IResourceTransactionManager, IInitializingObject { + #region Logging Definition + + private static readonly ILogger LOG = LogManager.GetLogger(); + + #endregion + + private IConnectionFactory connectionFactory; + /// - /// A implementation - /// for a single EMS ConnectionFactory. Binds a - /// Connection/Session pair from the specified ConnecctionFactory to the thread, - /// potentially allowing for one thread-bound Session per ConnectionFactory. + /// Initializes a new instance of the class. /// /// + /// The ConnectionFactory has to be set before using the instance. + /// This constructor can be used to prepare a EmsTemplate via a ApplicationContext, + /// typically setting the ConnectionFactory via ConnectionFactory property. /// - /// Application code is required to retrieve the transactional Session via - /// . Spring's - /// will autodetect a thread-bound Session and - /// automatically participate in it. - /// - /// - /// Transaction synchronization is turned off by default, as this manager might be used - /// alongside an IDbProvider based Spring transaction manager such as the + /// Turns off transaction synchronization by default, as this manager might + /// be used alongside a dbprovider-based Spring transaction manager like /// AdoPlatformTransactionManager, which has stronger needs for synchronization. + /// Only one manager is allowed to drive synchronization at any point of time. /// /// - /// Juergen Hoeller - /// Mark Pollack (.NET) - public class EmsTransactionManager : AbstractPlatformTransactionManager, - IResourceTransactionManager, IInitializingObject + public EmsTransactionManager() { + TransactionSynchronization = TransactionSynchronizationState.Never; + } - #region Logging Definition + /// + /// Initializes a new instance of the class + /// given a ConnectionFactory. + /// + /// The connection factory to obtain connections from. + public EmsTransactionManager(IConnectionFactory connectionFactory) : this() + { + ConnectionFactory = connectionFactory; + AfterPropertiesSet(); + } - private static readonly ILogger LOG = LogManager.GetLogger(); - - #endregion - - private IConnectionFactory connectionFactory; - - /// - /// Initializes a new instance of the class. - /// - /// - /// The ConnectionFactory has to be set before using the instance. - /// This constructor can be used to prepare a EmsTemplate via a ApplicationContext, - /// typically setting the ConnectionFactory via ConnectionFactory property. - /// - /// Turns off transaction synchronization by default, as this manager might - /// be used alongside a dbprovider-based Spring transaction manager like - /// AdoPlatformTransactionManager, which has stronger needs for synchronization. - /// Only one manager is allowed to drive synchronization at any point of time. - /// - /// - public EmsTransactionManager() + /// + /// Gets or sets the connection factory that this instance should manage transaction. + /// for. + /// + /// The connection factory. + public IConnectionFactory ConnectionFactory + { + get { return connectionFactory; } + set { - TransactionSynchronization = TransactionSynchronizationState.Never; - } - - /// - /// Initializes a new instance of the class - /// given a ConnectionFactory. - /// - /// The connection factory to obtain connections from. - public EmsTransactionManager(IConnectionFactory connectionFactory) : this() - { - ConnectionFactory = connectionFactory; - AfterPropertiesSet(); - } - - - /// - /// Gets or sets the connection factory that this instance should manage transaction. - /// for. - /// - /// The connection factory. - public IConnectionFactory ConnectionFactory - { - get { return connectionFactory; } - set - { - connectionFactory = value; - } - } - - #region IInitializingObject Members - - /// - /// Make sure the ConnectionFactory has been set. - /// - public void AfterPropertiesSet() - { - if (ConnectionFactory == null) - { - throw new ArgumentException("Property 'ConnectionFactory' is required."); - } - } - - #endregion - - #region IResourceTransactionManager Members - - /// - /// Gets the resource factory that this transaction manager operates on, - /// In tihs case the ConnectionFactory - /// - /// The ConnectionFactory. - public object ResourceFactory - { - get { return ConnectionFactory; } - } - - #endregion - - - /// - /// Get the EmsTransactionObject. - /// - /// he EmsTransactionObject. - protected override object DoGetTransaction() - { - EmsTransactionObject txObject = new EmsTransactionObject(); - - txObject.ResourceHolder = - (EmsResourceHolder) TransactionSynchronizationManager.GetResource(ConnectionFactory); - return txObject; - } - - - /// - /// Begin a new transaction with the given transaction definition. - /// - /// Transaction object returned by - /// . - /// instance, describing - /// propagation behavior, isolation level, timeout etc. - /// - /// Does not have to care about applying the propagation behavior, - /// as this has already been handled by this abstract manager. - /// - /// - /// In the case of creation or system errors. - /// - protected override void DoBegin(object transaction, ITransactionDefinition definition) - { - //This is the default value defined in DefaultTransactionDefinition - if (definition.TransactionIsolationLevel != IsolationLevel.ReadCommitted) - { - throw new InvalidIsolationLevelException("EMS does not support an isoliation level concept"); - } - EmsTransactionObject txObject = (EmsTransactionObject) transaction; - IConnection con = null; - ISession session = null; - try - { - con = CreateConnection(); - session = CreateSession(con); - if (LOG.IsEnabled(LogLevel.Debug)) - { - log.LogDebug("Created EMS transaction on Session [" + session + "] from Connection [" + con + "]"); - } - txObject.ResourceHolder = new EmsResourceHolder(ConnectionFactory, con, session); - txObject.ResourceHolder.SynchronizedWithTransaction = true; - int timeout = DetermineTimeout(definition); - if (timeout != DefaultTransactionDefinition.TIMEOUT_DEFAULT) - { - txObject.ResourceHolder.TimeoutInSeconds = timeout; - } - TransactionSynchronizationManager.BindResource(ConnectionFactory, txObject.ResourceHolder); - - - - } catch (EMSException ex) - { - if (session != null) - { - try - { - session.Close(); - } catch (Exception) - {} - } - if (con != null) - { - try - { - con.Close(); - } catch (Exception){} - } - throw new CannotCreateTransactionException("Could not create EMS Transaction", ex); - } - - } - - /// - /// Suspend the resources of the current transaction. - /// - /// Transaction object returned by - /// . - /// - /// An object that holds suspended resources (will be kept unexamined for passing it into - /// .) - /// - /// - /// Transaction synchronization will already have been suspended. - /// - /// - /// in case of system errors. - /// - protected override object DoSuspend(object transaction) - { - EmsTransactionObject txObject = (EmsTransactionObject) transaction; - txObject.ResourceHolder = null; - return TransactionSynchronizationManager.UnbindResource(ConnectionFactory); - } - - /// - /// Resume the resources of the current transaction. - /// - /// Transaction object returned by - /// . - /// The object that holds suspended resources as returned by - /// . - /// Transaction synchronization will be resumed afterwards. - /// - /// - /// In the case of system errors. - /// - protected override void DoResume(object transaction, object suspendedResources) - { - EmsResourceHolder conHolder = (EmsResourceHolder) suspendedResources; - TransactionSynchronizationManager.BindResource(ConnectionFactory, conHolder); - } - - /// - /// Perform an actual commit on the given transaction. - /// - /// The status representation of the transaction. - /// - /// In the case of system errors. - /// - protected override void DoCommit(DefaultTransactionStatus status) - { - EmsTransactionObject txObject = (EmsTransactionObject)status.Transaction; - ISession session = txObject.ResourceHolder.GetSession(); - try - { - if (status.Debug) - { - LOG.LogDebug("Committing EMS transaction on Session [" + session + "]"); - } - session.Commit(); - } - catch (TransactionRolledBackException ex) - { - throw new UnexpectedRollbackException("EMS transaction rolled back", ex); - } - catch (EMSException ex) - { - throw new TransactionSystemException("Could not commit EMS transaction.", ex); - } - } - - /// - /// Perform an actual rollback on the given transaction. - /// - /// The status representation of the transaction. - /// - /// In the case of system errors. - /// - protected override void DoRollback(DefaultTransactionStatus status) - { - EmsTransactionObject txObject = (EmsTransactionObject)status.Transaction; - ISession session = txObject.ResourceHolder.GetSession(); - try - { - if (status.Debug) - { - LOG.LogDebug("Rolling back EMS transaction on Session [" + session + "]"); - } - session.Rollback(); - } - catch (EMSException ex) - { - throw new TransactionSystemException("Could not roll back EMS transaction.", ex); - } - } - - - /// - /// Set the given transaction rollback-only. Only called on rollback - /// if the current transaction takes part in an existing one. - /// - /// The status representation of the transaction. - /// - /// In the case of system errors. - /// - protected override void DoSetRollbackOnly(DefaultTransactionStatus status) - { - EmsTransactionObject txObject = (EmsTransactionObject)status.Transaction; - txObject.ResourceHolder.RollbackOnly = true; - } - - /// - /// Cleanup resources after transaction completion. - /// - /// Transaction object returned by - /// . - /// - /// - /// Called after - /// and - /// - /// execution on any outcome. - /// - /// - protected override void DoCleanupAfterCompletion(object transaction) - { - EmsTransactionObject txObject = (EmsTransactionObject)transaction; - TransactionSynchronizationManager.UnbindResource(ConnectionFactory); - txObject.ResourceHolder.CloseAll(); - txObject.ResourceHolder.Clear(); - } - - /// - /// Check if the given transaction object indicates an existing transaction - /// (that is, a transaction which has already started). - /// - /// Transaction object returned by - /// . - /// - /// True if there is an existing transaction. - /// - /// - /// In the case of system errors. - /// - protected override bool IsExistingTransaction(object transaction) - { - EmsTransactionObject txObject = transaction as EmsTransactionObject; - if (txObject != null) - { - return txObject.ResourceHolder != null; - } - return false; - } - - /// - /// Creates the connection via thie manager's ConnectionFactory. - /// - /// The new Connection - /// If thrown by underlying messaging APIs - protected virtual IConnection CreateConnection() - { - return ConnectionFactory.CreateConnection(); - } - - /// - /// Creates the session for the given Connection - /// - /// The connection to create a Session for. - /// the new Session - /// If thrown by underlying messaging APIs - protected virtual ISession CreateSession(IConnection connection) - { - return connection.CreateSession(true, Session.SESSION_TRANSACTED); - } - - - /// - /// EMS Transaction object, representing a EmsResourceHolder. - /// Used as transaction object by EMSTransactionManager - /// - internal class EmsTransactionObject : ISmartTransactionObject - { - private EmsResourceHolder resourceHolder; - - - public EmsResourceHolder ResourceHolder - { - get { return resourceHolder; } - set { resourceHolder = value; } - } - - #region ISmartTransactionObject Members - - public bool RollbackOnly - { - get { return resourceHolder.RollbackOnly; } - } - - #endregion + connectionFactory = value; } } -} + + #region IInitializingObject Members + + /// + /// Make sure the ConnectionFactory has been set. + /// + public void AfterPropertiesSet() + { + if (ConnectionFactory == null) + { + throw new ArgumentException("Property 'ConnectionFactory' is required."); + } + } + + #endregion + + #region IResourceTransactionManager Members + + /// + /// Gets the resource factory that this transaction manager operates on, + /// In tihs case the ConnectionFactory + /// + /// The ConnectionFactory. + public object ResourceFactory + { + get { return ConnectionFactory; } + } + + #endregion + + /// + /// Get the EmsTransactionObject. + /// + /// he EmsTransactionObject. + protected override object DoGetTransaction() + { + EmsTransactionObject txObject = new EmsTransactionObject(); + + txObject.ResourceHolder = + (EmsResourceHolder) TransactionSynchronizationManager.GetResource(ConnectionFactory); + return txObject; + } + + /// + /// Begin a new transaction with the given transaction definition. + /// + /// Transaction object returned by + /// . + /// instance, describing + /// propagation behavior, isolation level, timeout etc. + /// + /// Does not have to care about applying the propagation behavior, + /// as this has already been handled by this abstract manager. + /// + /// + /// In the case of creation or system errors. + /// + protected override void DoBegin(object transaction, ITransactionDefinition definition) + { + //This is the default value defined in DefaultTransactionDefinition + if (definition.TransactionIsolationLevel != IsolationLevel.ReadCommitted) + { + throw new InvalidIsolationLevelException("EMS does not support an isoliation level concept"); + } + + EmsTransactionObject txObject = (EmsTransactionObject) transaction; + IConnection con = null; + ISession session = null; + try + { + con = CreateConnection(); + session = CreateSession(con); + if (LOG.IsEnabled(LogLevel.Debug)) + { + log.LogDebug("Created EMS transaction on Session [" + session + "] from Connection [" + con + "]"); + } + + txObject.ResourceHolder = new EmsResourceHolder(ConnectionFactory, con, session); + txObject.ResourceHolder.SynchronizedWithTransaction = true; + int timeout = DetermineTimeout(definition); + if (timeout != DefaultTransactionDefinition.TIMEOUT_DEFAULT) + { + txObject.ResourceHolder.TimeoutInSeconds = timeout; + } + + TransactionSynchronizationManager.BindResource(ConnectionFactory, txObject.ResourceHolder); + } + catch (EMSException ex) + { + if (session != null) + { + try + { + session.Close(); + } + catch (Exception) + { + } + } + + if (con != null) + { + try + { + con.Close(); + } + catch (Exception) { } + } + + throw new CannotCreateTransactionException("Could not create EMS Transaction", ex); + } + } + + /// + /// Suspend the resources of the current transaction. + /// + /// Transaction object returned by + /// . + /// + /// An object that holds suspended resources (will be kept unexamined for passing it into + /// .) + /// + /// + /// Transaction synchronization will already have been suspended. + /// + /// + /// in case of system errors. + /// + protected override object DoSuspend(object transaction) + { + EmsTransactionObject txObject = (EmsTransactionObject) transaction; + txObject.ResourceHolder = null; + return TransactionSynchronizationManager.UnbindResource(ConnectionFactory); + } + + /// + /// Resume the resources of the current transaction. + /// + /// Transaction object returned by + /// . + /// The object that holds suspended resources as returned by + /// . + /// Transaction synchronization will be resumed afterwards. + /// + /// + /// In the case of system errors. + /// + protected override void DoResume(object transaction, object suspendedResources) + { + EmsResourceHolder conHolder = (EmsResourceHolder) suspendedResources; + TransactionSynchronizationManager.BindResource(ConnectionFactory, conHolder); + } + + /// + /// Perform an actual commit on the given transaction. + /// + /// The status representation of the transaction. + /// + /// In the case of system errors. + /// + protected override void DoCommit(DefaultTransactionStatus status) + { + EmsTransactionObject txObject = (EmsTransactionObject) status.Transaction; + ISession session = txObject.ResourceHolder.GetSession(); + try + { + if (status.Debug) + { + LOG.LogDebug("Committing EMS transaction on Session [" + session + "]"); + } + + session.Commit(); + } + catch (TransactionRolledBackException ex) + { + throw new UnexpectedRollbackException("EMS transaction rolled back", ex); + } + catch (EMSException ex) + { + throw new TransactionSystemException("Could not commit EMS transaction.", ex); + } + } + + /// + /// Perform an actual rollback on the given transaction. + /// + /// The status representation of the transaction. + /// + /// In the case of system errors. + /// + protected override void DoRollback(DefaultTransactionStatus status) + { + EmsTransactionObject txObject = (EmsTransactionObject) status.Transaction; + ISession session = txObject.ResourceHolder.GetSession(); + try + { + if (status.Debug) + { + LOG.LogDebug("Rolling back EMS transaction on Session [" + session + "]"); + } + + session.Rollback(); + } + catch (EMSException ex) + { + throw new TransactionSystemException("Could not roll back EMS transaction.", ex); + } + } + + /// + /// Set the given transaction rollback-only. Only called on rollback + /// if the current transaction takes part in an existing one. + /// + /// The status representation of the transaction. + /// + /// In the case of system errors. + /// + protected override void DoSetRollbackOnly(DefaultTransactionStatus status) + { + EmsTransactionObject txObject = (EmsTransactionObject) status.Transaction; + txObject.ResourceHolder.RollbackOnly = true; + } + + /// + /// Cleanup resources after transaction completion. + /// + /// Transaction object returned by + /// . + /// + /// + /// Called after + /// and + /// + /// execution on any outcome. + /// + /// + protected override void DoCleanupAfterCompletion(object transaction) + { + EmsTransactionObject txObject = (EmsTransactionObject) transaction; + TransactionSynchronizationManager.UnbindResource(ConnectionFactory); + txObject.ResourceHolder.CloseAll(); + txObject.ResourceHolder.Clear(); + } + + /// + /// Check if the given transaction object indicates an existing transaction + /// (that is, a transaction which has already started). + /// + /// Transaction object returned by + /// . + /// + /// True if there is an existing transaction. + /// + /// + /// In the case of system errors. + /// + protected override bool IsExistingTransaction(object transaction) + { + EmsTransactionObject txObject = transaction as EmsTransactionObject; + if (txObject != null) + { + return txObject.ResourceHolder != null; + } + + return false; + } + + /// + /// Creates the connection via thie manager's ConnectionFactory. + /// + /// The new Connection + /// If thrown by underlying messaging APIs + protected virtual IConnection CreateConnection() + { + return ConnectionFactory.CreateConnection(); + } + + /// + /// Creates the session for the given Connection + /// + /// The connection to create a Session for. + /// the new Session + /// If thrown by underlying messaging APIs + protected virtual ISession CreateSession(IConnection connection) + { + return connection.CreateSession(true, Session.SESSION_TRANSACTED); + } + + /// + /// EMS Transaction object, representing a EmsResourceHolder. + /// Used as transaction object by EMSTransactionManager + /// + internal class EmsTransactionObject : ISmartTransactionObject + { + private EmsResourceHolder resourceHolder; + + public EmsResourceHolder ResourceHolder + { + get { return resourceHolder; } + set { resourceHolder = value; } + } + + #region ISmartTransactionObject Members + + public bool RollbackOnly + { + get { return resourceHolder.RollbackOnly; } + } + + #endregion + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Connections/IDecoratorSession.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Connections/IDecoratorSession.cs index 924d644c..c35d6f45 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Connections/IDecoratorSession.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Connections/IDecoratorSession.cs @@ -20,23 +20,22 @@ using Spring.Messaging.Ems.Common; -namespace Spring.Messaging.Ems.Connections +namespace Spring.Messaging.Ems.Connections; + +/// +/// Subinterface of Session to be implemented by +/// implementations that wrap an Session to provide added +/// functionality. Allows access to the the underlying target Session. +/// +/// Mark Pollack +/// +/// +public interface IDecoratorSession : ISession { /// - /// Subinterface of Session to be implemented by - /// implementations that wrap an Session to provide added - /// functionality. Allows access to the the underlying target Session. + /// Gets the target session of the decorator. + /// This will typically be the native provider Session or a wrapper from a session pool. /// - /// Mark Pollack - /// - /// - public interface IDecoratorSession : ISession - { - /// - /// Gets the target session of the decorator. - /// This will typically be the native provider Session or a wrapper from a session pool. - /// - /// The underlying session, never null - ISession TargetSession { get; } - } -} \ No newline at end of file + /// The underlying session, never null + ISession TargetSession { get; } +} diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Connections/ISmartConnectionFactory.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Connections/ISmartConnectionFactory.cs index ac64bbed..b2fdae84 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Connections/ISmartConnectionFactory.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Connections/ISmartConnectionFactory.cs @@ -1,5 +1,3 @@ - - #region License /* @@ -22,21 +20,20 @@ using Spring.Messaging.Ems.Common; -namespace Spring.Messaging.Ems.Connections +namespace Spring.Messaging.Ems.Connections; + +/// +/// Extension of the IConnectionFactory interface, +/// indicating how to release Connections obtained from it. +/// +/// Juergen Hoeller +/// Mark Pollack (.NET) +public interface ISmartConnectionFactory { /// - /// Extension of the IConnectionFactory interface, - /// indicating how to release Connections obtained from it. + /// Shoulds we stop the connection, obtained from this ConnectionFactory? /// - /// Juergen Hoeller - /// Mark Pollack (.NET) - public interface ISmartConnectionFactory - { - /// - /// Shoulds we stop the connection, obtained from this ConnectionFactory? - /// - /// The connection to check. - /// wheter a stop call is necessary - bool ShouldStop(IConnection con); - } + /// The connection to check. + /// wheter a stop call is necessary + bool ShouldStop(IConnection con); } diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Connections/SingleConnectionFactory.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Connections/SingleConnectionFactory.cs index d8dab7a3..030aa7d6 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Connections/SingleConnectionFactory.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Connections/SingleConnectionFactory.cs @@ -26,786 +26,785 @@ using Spring.Messaging.Ems.Common; using Spring.Objects.Factory; using Spring.Util; -namespace Spring.Messaging.Ems.Connections +namespace Spring.Messaging.Ems.Connections; + +/// +/// A ConnectionFactory adapter that returns the same Connection +/// from all CreateConnection() calls, and ignores calls to +/// Connection.Close(). According to the JMS Connection +/// model, this is perfectly thread-safe. The +/// shared Connection can be automatically recovered in case of an Exception. +/// +/// +/// +/// You can either pass in a specific Connection directly or let this +/// factory lazily create a Connection via a given target ConnectionFactory. +/// +/// +/// Useful for testing and in applications when you want to keep using the +/// same Connection for multiple +/// calls, without having a pooling ConnectionFactory underneath. This may span +/// any number of transactions, even concurrently executing transactions. +/// +/// +/// Note that Spring's message listener containers support the use of +/// a shared Connection within each listener container instance. Using +/// SingleConnectionFactory with a MessageListenerContainer only really makes sense for +/// sharing a single Connection across multiple listener containers. +/// +/// +/// Juergen Hoeller +/// Mark Pollack +/// Mark Pollack (.NET) +public class SingleConnectionFactory : IConnectionFactory, IExceptionListener, IInitializingObject, IDisposable { + #region Logging Definition + + private static readonly ILog LOG = LogManager.GetLogger(typeof(SingleConnectionFactory)); + + #endregion + + #region Fields + + private IConnectionFactory targetConnectionFactory; + + private string clientId; + + private IExceptionListener exceptionListener; + + private bool reconnectOnException = false; + /// - /// A ConnectionFactory adapter that returns the same Connection - /// from all CreateConnection() calls, and ignores calls to - /// Connection.Close(). According to the JMS Connection - /// model, this is perfectly thread-safe. The - /// shared Connection can be automatically recovered in case of an Exception. + /// Wrapped Connection + /// + private IConnection target; + + /// + /// Proxy Connection + /// + private IConnection connection; + + /// + /// Whether the shared Connection has been started + /// + private bool started = false; + + /// + /// Synchronization monitor for the shared Connection + /// + private object connectionMonitor = new object(); + + private bool sslProxyHostSet; + private bool sslProxyPortSet; + private bool sslProxyAuthPasswordSet; + private bool sslProxyAuthUsernameSet; + + #endregion + + #region Constructors + + /// + /// Initializes a new instance of the class. + /// + public SingleConnectionFactory() + { + } + + /// + /// Initializes a new instance of the class + /// that alwasy returns the given Connection. + /// + /// The single Connection. + public SingleConnectionFactory(IConnection target) + { + AssertUtils.ArgumentNotNull(target, "connection", "TargetSession Connection must not be null"); + this.target = target; + connection = GetSharedConnection(target); + } + + /// + /// Initializes a new instance of the class + /// that alwasy returns a single Connection. + /// + /// The target connection factory. + public SingleConnectionFactory(IConnectionFactory targetConnectionFactory) + { + AssertUtils.ArgumentNotNull(targetConnectionFactory, "targetConnectionFactory", + "TargetSession ConnectionFactory must not be null"); + this.targetConnectionFactory = targetConnectionFactory; + } + + #endregion + + #region Properties + + /// + /// Gets or sets the target connection factory which will be used to create a single + /// connection. + /// + /// The target connection factory. + public IConnectionFactory TargetConnectionFactory + { + get { return targetConnectionFactory; } + set { targetConnectionFactory = value; } + } + + /// + /// Sets the exception listener. + /// + /// The exception listener. + public IExceptionListener ExceptionListener + { + get { return exceptionListener; } + set { exceptionListener = value; } + } + + /// + /// Gets or sets a value indicating whether the single Connection + /// should be reset (to be subsequently renewed) when a EMSException + /// is reported by the underlying Connection. /// /// + /// Default is false. Switch this to true + /// to automatically trigger recover based on your messaging provider's + /// exception notifications. /// - /// You can either pass in a specific Connection directly or let this - /// factory lazily create a Connection via a given target ConnectionFactory. - /// - /// - /// Useful for testing and in applications when you want to keep using the - /// same Connection for multiple - /// calls, without having a pooling ConnectionFactory underneath. This may span - /// any number of transactions, even concurrently executing transactions. - /// - /// - /// Note that Spring's message listener containers support the use of - /// a shared Connection within each listener container instance. Using - /// SingleConnectionFactory with a MessageListenerContainer only really makes sense for - /// sharing a single Connection across multiple listener containers. + /// Internally, this will lead to a special ExceptionListener (this + /// SingleConnectionFactory itself) being registered with the underlying + /// Connection. This can also be combined with a user-specified + /// ExceptionListener, if desired. /// /// - /// Juergen Hoeller - /// Mark Pollack - /// Mark Pollack (.NET) - public class SingleConnectionFactory : IConnectionFactory, IExceptionListener, IInitializingObject, IDisposable + /// + /// true attempt to reconnect on exception during next access; otherwise, false. + /// + public bool ReconnectOnException { - #region Logging Definition + get { return reconnectOnException; } + set { reconnectOnException = value; } + } - private static readonly ILog LOG = LogManager.GetLogger(typeof (SingleConnectionFactory)); + /// + /// Gets the connection monitor. + /// + /// The connection monitor. + internal object ConnectionMonitor + { + get { return connectionMonitor; } + } - #endregion + /// + /// Gets a value indicating whether this instance is started. + /// + /// + /// true if this instance is started; otherwise, false. + /// + internal bool IsStarted + { + get { return started; } + set { started = value; } + } - #region Fields + /// + /// Gets the client id. + /// + /// The client id. + internal string ClientId + { + get { return clientId; } + } - private IConnectionFactory targetConnectionFactory; + #endregion - private string clientId; + #region Implementation of IConnectionFactory - private IExceptionListener exceptionListener; - - private bool reconnectOnException = false; - - /// - /// Wrapped Connection - /// - private IConnection target; - - /// - /// Proxy Connection - /// - private IConnection connection; - - - /// - /// Whether the shared Connection has been started - /// - private bool started = false; - - /// - /// Synchronization monitor for the shared Connection - /// - private object connectionMonitor = new object(); - - private bool sslProxyHostSet; - private bool sslProxyPortSet; - private bool sslProxyAuthPasswordSet; - private bool sslProxyAuthUsernameSet; - - #endregion - - #region Constructors - - /// - /// Initializes a new instance of the class. - /// - public SingleConnectionFactory() + /// + /// Creates the connection. + /// + /// A single shared connection + public IConnection CreateConnection() + { + lock (connectionMonitor) { - } - - - /// - /// Initializes a new instance of the class - /// that alwasy returns the given Connection. - /// - /// The single Connection. - public SingleConnectionFactory(IConnection target) - { - AssertUtils.ArgumentNotNull(target, "connection", "TargetSession Connection must not be null"); - this.target = target; - connection = GetSharedConnection(target); - } - - - /// - /// Initializes a new instance of the class - /// that alwasy returns a single Connection. - /// - /// The target connection factory. - public SingleConnectionFactory(IConnectionFactory targetConnectionFactory) - { - AssertUtils.ArgumentNotNull(targetConnectionFactory, "targetConnectionFactory", - "TargetSession ConnectionFactory must not be null"); - this.targetConnectionFactory = targetConnectionFactory; - } - - #endregion - - #region Properties - - /// - /// Gets or sets the target connection factory which will be used to create a single - /// connection. - /// - /// The target connection factory. - public IConnectionFactory TargetConnectionFactory - { - get { return targetConnectionFactory; } - set { targetConnectionFactory = value; } - } - - - /// - /// Sets the exception listener. - /// - /// The exception listener. - public IExceptionListener ExceptionListener - { - get { return exceptionListener; } - set { exceptionListener = value; } - } - - - /// - /// Gets or sets a value indicating whether the single Connection - /// should be reset (to be subsequently renewed) when a EMSException - /// is reported by the underlying Connection. - /// - /// - /// Default is false. Switch this to true - /// to automatically trigger recover based on your messaging provider's - /// exception notifications. - /// - /// Internally, this will lead to a special ExceptionListener (this - /// SingleConnectionFactory itself) being registered with the underlying - /// Connection. This can also be combined with a user-specified - /// ExceptionListener, if desired. - /// - /// - /// - /// true attempt to reconnect on exception during next access; otherwise, false. - /// - public bool ReconnectOnException - { - get { return reconnectOnException; } - set { reconnectOnException = value; } - } - - /// - /// Gets the connection monitor. - /// - /// The connection monitor. - internal object ConnectionMonitor - { - get { return connectionMonitor; } - } - - /// - /// Gets a value indicating whether this instance is started. - /// - /// - /// true if this instance is started; otherwise, false. - /// - internal bool IsStarted - { - get { return started;} - set { started = value; } - } - - /// - /// Gets the client id. - /// - /// The client id. - internal string ClientId - { - get { return clientId; } - } - - #endregion - - #region Implementation of IConnectionFactory - - /// - /// Creates the connection. - /// - /// A single shared connection - public IConnection CreateConnection() - { - lock (connectionMonitor) + if (connection == null) { - if (connection == null) - { - InitConnection(); - } - return connection; + InitConnection(); } - } - /// - /// Creates the connection. - /// - /// Name of the user. - /// The password. - /// - public IConnection CreateConnection(string userName, string password) - { - throw new InvalidOperationException("SingleConnectionFactory does not support custom username and password."); - } - - public ConnectionFactory NativeConnectionFactory - { - get { return targetConnectionFactory.NativeConnectionFactory; } - } - - public object CertificateStore - { - get { return TargetConnectionFactory.CertificateStore; } - } - - - public string SSLProxyPassword - { - get { return TargetConnectionFactory.SSLProxyPassword; } - } - - public string SSLProxyUser - { - get { return TargetConnectionFactory.SSLProxyUser; } - } - - public IEmsSSLStoreType CertificateStoreType - { - set { TargetConnectionFactory.CertificateStoreType = value; } - } - - public string ClientID - { - set - { - this.clientId = value; - TargetConnectionFactory.ClientID = value; - } - } - - public StreamWriter ClientTracer - { - set { TargetConnectionFactory.ClientTracer = value; } - } - - public int ConnAttemptCount - { - set { TargetConnectionFactory.ConnAttemptCount = value; } - } - - public int ConnAttemptDelay - { - set { TargetConnectionFactory.ConnAttemptDelay = value; } - } - - public int ConnAttemptTimeout - { - set { TargetConnectionFactory.ConnAttemptTimeout = value; } - } - - public EMSSSLHostNameVerifier HostNameVerifier - { - set { TargetConnectionFactory.HostNameVerifier = value; } - } - - public int MetricAsInt - { - set { TargetConnectionFactory.MetricAsInt = value; } - } - - public string MulticastDaemon - { - set { TargetConnectionFactory.MulticastDaemon = value; } - } - - public bool MulticastEnabled - { - set { TargetConnectionFactory.MulticastEnabled = value; } - } - - public int ReconnAttemptCount - { - set { TargetConnectionFactory.ReconnAttemptCount = value; } - } - - public int ReconnAttemptDelay - { - set { TargetConnectionFactory.ReconnAttemptDelay = value; } - } - - public int ReconnAttemptTimeout - { - set { TargetConnectionFactory.ReconnAttemptTimeout = value; } - } - - public string ServerUrl - { - set { TargetConnectionFactory.ServerUrl = value; } - } - - public bool SSLAuthOnly - { - set { TargetConnectionFactory.SSLAuthOnly = value; } - } - - public string SSLProxyHost - { - get - { - return TargetConnectionFactory.SSLProxyHost; - } - set - { - TargetConnectionFactory.SSLProxyHost = value; - sslProxyHostSet = true; - } - } - - public int SSLProxyPort - { - get { return TargetConnectionFactory.SSLProxyPort;} - set - { - TargetConnectionFactory.SSLProxyPort = value; - sslProxyPortSet = true; - } - } - - public string SSLProxyAuthUsername - { - set - { - TargetConnectionFactory.SSLProxyAuthUsername = value; - sslProxyAuthUsernameSet = true; - } - get { return TargetConnectionFactory.SSLProxyAuthUsername; } - } - - public string SSLProxyAuthPassword - { - set - { - TargetConnectionFactory.SSLProxyAuthPassword = value; - sslProxyAuthPasswordSet = true; - } - get { return TargetConnectionFactory.SSLProxyAuthPassword; } - } - - public bool SSLTrace - { - set { TargetConnectionFactory.SSLTrace = value; } - } - - public string TargetHostName - { - set { TargetConnectionFactory.TargetHostName = value; } - } - - public string UserName - { - set { TargetConnectionFactory.UserName = value; } - } - - public string UserPassword - { - set { TargetConnectionFactory.UserPassword = value; } - } - - public FactoryLoadBalanceMetric Metric - { - get { return TargetConnectionFactory.Metric; } - set { TargetConnectionFactory.Metric = value; } - } - - #endregion - - - - #region Implementation of ISerializable - - public void GetObjectData(SerializationInfo info, StreamingContext context) - { - TargetConnectionFactory.GetObjectData(info, context); - } - - #endregion - - #region Implementation of ICloneable - - public object Clone() - { - return TargetConnectionFactory.Clone(); - } - - #endregion - - /// - /// Initialize the underlying shared Connection. Closes and reinitializes the Connection if an underlying - /// Connection is present already. - /// - public void InitConnection() - { - if (TargetConnectionFactory == null) - { - throw new ArgumentException( - "'TargetConnectionFactory' is required for lazily initializing a Connection"); - } - lock (connectionMonitor) - { - if (this.target != null) - { - CloseConnection(this.target); - } - this.target = DoCreateConnection(); - PrepareConnection(this.target); - if (LOG.IsEnabled(LogLevel.Debug)) - { - LOG.LogInformation("Established shared EMS Connection: " + this.target); - } - this.connection = GetSharedConnection(target); - } - } - - /// - /// Exception listener callback that renews the underlying single Connection. - /// - /// The exception from the messaging infrastructure. - public void OnException(EMSException exception) - { - ResetConnection(); - } - - /// - /// Prepares the connection before it is exposed. - /// The default implementation applies ExceptionListener and client id. - /// Can be overridden in subclasses. - /// - /// The Connection to prepare. - /// if thrown by any EMS API methods. - protected virtual void PrepareConnection(IConnection con) - { - if (ClientId != null) - { - con.ClientID = ClientId; - } - if (this.exceptionListener != null || this.reconnectOnException) - { - IExceptionListener listenerToUse = this.exceptionListener; - if (reconnectOnException) - { - listenerToUse = new InternalChainedExceptionListener(this, listenerToUse); - } - con.ExceptionListener = listenerToUse; - } - } - - /// - /// Template method for obtaining a (potentially cached) Session. - /// - /// The connection to operate on. - /// The session ack mode. - /// the Session to use, or null to indicate - /// creation of a raw standard Session - public virtual ISession GetSession(IConnection con, SessionMode mode) - { - return null; - } - - - - /// - /// reate a JMS Connection via this template's ConnectionFactory. - /// - /// - protected virtual IConnection DoCreateConnection() - { - return TargetConnectionFactory.CreateConnection(); - } - - /// - /// Closes the given connection. - /// - /// The connection. - protected virtual void CloseConnection(IConnection con) - { - if (LOG.IsEnabled(LogLevel.Debug)) - { - LOG.LogDebug("Closing shared EMS Connection: " + this.target); - } - try - { - try - { - if (this.started) - { - this.started = false; - con.Stop(); - } - } finally - { - con.Close(); - } - } catch (Exception ex) - { - LOG.LogWarning(ex, "Could not close shared EMS connection."); - } - } - - #region IInitializingObject Members - - /// - /// Ensure that the connection or TargetConnectionFactory are specified. - /// - public void AfterPropertiesSet() - { - if (connection == null && TargetConnectionFactory == null) - { - throw new ArgumentException("Connection or 'TargetConnectionFactory' is required."); - } - // Note this is repeated in EmsConnectionFactory as this class only refers to IConnectionFactory and - // IConnectionFactory does not implement the spring specific lifecycle interface IInitializingObject - if (sslProxyAuthUsernameSet || sslProxyAuthPasswordSet) - { - TargetConnectionFactory.NativeConnectionFactory.SetSSLProxyAuth(SSLProxyAuthUsername, SSLProxyAuthPassword); - } - if (sslProxyHostSet || sslProxyPortSet) - { - TargetConnectionFactory.NativeConnectionFactory.SetSSLProxy(SSLProxyHost, SSLProxyPort); - } - } - - #endregion - - - /// - /// Close the underlying shared connection. The provider of this ConnectionFactory needs to care for proper shutdown. - /// As this object implements an application context will automatically - /// invoke this on distruction o - /// - public void Dispose() - { - ResetConnection(); - } - - /// - /// Resets the underlying shared Connection, to be reinitialized on next access. - /// - public virtual void ResetConnection() - { - lock (connectionMonitor) - { - if (this.target != null) - { - CloseConnection(this.target); - } - this.target = null; - this.connection = null; - } - } - - /// - /// Wrap the given Connection with a proxy that delegates every method call to it - /// but suppresses close calls. This is useful for allowing application code to - /// handle a special framework Connection just like an ordinary Connection from a - /// ConnectionFactory. - /// - /// The original connection to wrap. - /// the wrapped connection - protected virtual IConnection GetSharedConnection(IConnection target) - { - lock (connectionMonitor) - { - return new CloseSupressingConnection(this, target); - } + return connection; } } /// - /// Internal chained ExceptionListener for handling the internal recovery listener - /// in combination with a user-specified listener. + /// Creates the connection. /// - internal class InternalChainedExceptionListener : ChainedExceptionListener + /// Name of the user. + /// The password. + /// + public IConnection CreateConnection(string userName, string password) { - private IExceptionListener userListener; + throw new InvalidOperationException("SingleConnectionFactory does not support custom username and password."); + } - public InternalChainedExceptionListener(IExceptionListener internalListener, IExceptionListener userListener) - { - AddListener(internalListener); - if (userListener != null) - { - AddListener(userListener); - this.userListener = userListener; - } - } + public ConnectionFactory NativeConnectionFactory + { + get { return targetConnectionFactory.NativeConnectionFactory; } + } - public IExceptionListener UserListener + public object CertificateStore + { + get { return TargetConnectionFactory.CertificateStore; } + } + + public string SSLProxyPassword + { + get { return TargetConnectionFactory.SSLProxyPassword; } + } + + public string SSLProxyUser + { + get { return TargetConnectionFactory.SSLProxyUser; } + } + + public IEmsSSLStoreType CertificateStoreType + { + set { TargetConnectionFactory.CertificateStoreType = value; } + } + + public string ClientID + { + set { - get { return userListener; } + this.clientId = value; + TargetConnectionFactory.ClientID = value; } } - internal class CloseSupressingConnection : IConnection + + public StreamWriter ClientTracer { - private IConnection target; - private SingleConnectionFactory singleConnectionFactory; + set { TargetConnectionFactory.ClientTracer = value; } + } - public CloseSupressingConnection(SingleConnectionFactory singleConnectionFactory, IConnection target) + public int ConnAttemptCount + { + set { TargetConnectionFactory.ConnAttemptCount = value; } + } + + public int ConnAttemptDelay + { + set { TargetConnectionFactory.ConnAttemptDelay = value; } + } + + public int ConnAttemptTimeout + { + set { TargetConnectionFactory.ConnAttemptTimeout = value; } + } + + public EMSSSLHostNameVerifier HostNameVerifier + { + set { TargetConnectionFactory.HostNameVerifier = value; } + } + + public int MetricAsInt + { + set { TargetConnectionFactory.MetricAsInt = value; } + } + + public string MulticastDaemon + { + set { TargetConnectionFactory.MulticastDaemon = value; } + } + + public bool MulticastEnabled + { + set { TargetConnectionFactory.MulticastEnabled = value; } + } + + public int ReconnAttemptCount + { + set { TargetConnectionFactory.ReconnAttemptCount = value; } + } + + public int ReconnAttemptDelay + { + set { TargetConnectionFactory.ReconnAttemptDelay = value; } + } + + public int ReconnAttemptTimeout + { + set { TargetConnectionFactory.ReconnAttemptTimeout = value; } + } + + public string ServerUrl + { + set { TargetConnectionFactory.ServerUrl = value; } + } + + public bool SSLAuthOnly + { + set { TargetConnectionFactory.SSLAuthOnly = value; } + } + + public string SSLProxyHost + { + get { - this.target = target; - this.singleConnectionFactory = singleConnectionFactory; + return TargetConnectionFactory.SSLProxyHost; + } + set + { + TargetConnectionFactory.SSLProxyHost = value; + sslProxyHostSet = true; + } + } + + public int SSLProxyPort + { + get { return TargetConnectionFactory.SSLProxyPort; } + set + { + TargetConnectionFactory.SSLProxyPort = value; + sslProxyPortSet = true; + } + } + + public string SSLProxyAuthUsername + { + set + { + TargetConnectionFactory.SSLProxyAuthUsername = value; + sslProxyAuthUsernameSet = true; + } + get { return TargetConnectionFactory.SSLProxyAuthUsername; } + } + + public string SSLProxyAuthPassword + { + set + { + TargetConnectionFactory.SSLProxyAuthPassword = value; + sslProxyAuthPasswordSet = true; + } + get { return TargetConnectionFactory.SSLProxyAuthPassword; } + } + + public bool SSLTrace + { + set { TargetConnectionFactory.SSLTrace = value; } + } + + public string TargetHostName + { + set { TargetConnectionFactory.TargetHostName = value; } + } + + public string UserName + { + set { TargetConnectionFactory.UserName = value; } + } + + public string UserPassword + { + set { TargetConnectionFactory.UserPassword = value; } + } + + public FactoryLoadBalanceMetric Metric + { + get { return TargetConnectionFactory.Metric; } + set { TargetConnectionFactory.Metric = value; } + } + + #endregion + + #region Implementation of ISerializable + + public void GetObjectData(SerializationInfo info, StreamingContext context) + { + TargetConnectionFactory.GetObjectData(info, context); + } + + #endregion + + #region Implementation of ICloneable + + public object Clone() + { + return TargetConnectionFactory.Clone(); + } + + #endregion + + /// + /// Initialize the underlying shared Connection. Closes and reinitializes the Connection if an underlying + /// Connection is present already. + /// + public void InitConnection() + { + if (TargetConnectionFactory == null) + { + throw new ArgumentException( + "'TargetConnectionFactory' is required for lazily initializing a Connection"); } - /// - /// Add information to show this is a shared EMS connection - /// - /// Description of connection wrapper - public override string ToString() + lock (connectionMonitor) { - return "Shared EMS Connection: " + this.target; - } - - public string ClientID - { - get { return target.ClientID; } - set + if (this.target != null) { - // Handle set ClientID property: throw exception if not compatible. - string currentClientId = target.ClientID; - if (currentClientId != null && currentClientId.Equals(value)) - { - //ok, the values are consistent. - } - else - { - throw new IllegalStateException( - "Setting of 'ClientID' property not supported on wrapper for shared Connection since" + - "this is a shared connection that may serve any number of clients concurrently." + - "Set the 'ClientId' property on the SingleConnectionFactory instead."); - } - + CloseConnection(this.target); } - } - - public void Start() - { - // Handle start method: track started state. - target.Start(); - lock (singleConnectionFactory.ConnectionMonitor) + this.target = DoCreateConnection(); + PrepareConnection(this.target); + if (LOG.IsEnabled(LogLevel.Debug)) { - singleConnectionFactory.IsStarted = true; + LOG.LogInformation("Established shared EMS Connection: " + this.target); } + + this.connection = GetSharedConnection(target); + } + } + + /// + /// Exception listener callback that renews the underlying single Connection. + /// + /// The exception from the messaging infrastructure. + public void OnException(EMSException exception) + { + ResetConnection(); + } + + /// + /// Prepares the connection before it is exposed. + /// The default implementation applies ExceptionListener and client id. + /// Can be overridden in subclasses. + /// + /// The Connection to prepare. + /// if thrown by any EMS API methods. + protected virtual void PrepareConnection(IConnection con) + { + if (ClientId != null) + { + con.ClientID = ClientId; } - public void Stop() + if (this.exceptionListener != null || this.reconnectOnException) { - //don't pass the call to the target as it would stop receiving for all clients sharing this connection. - } - - public void Close() - { - // don't pass the call to the target. - } - - public ISession CreateSession(bool transacted, int acknowledgementMode) - { - ISession session = singleConnectionFactory.GetSession(target, EmsUtils.ConvertAcknowledgementMode(acknowledgementMode)); - if (session != null) + IExceptionListener listenerToUse = this.exceptionListener; + if (reconnectOnException) { - return session; + listenerToUse = new InternalChainedExceptionListener(this, listenerToUse); } - return target.CreateSession(transacted, acknowledgementMode); + + con.ExceptionListener = listenerToUse; + } + } + + /// + /// Template method for obtaining a (potentially cached) Session. + /// + /// The connection to operate on. + /// The session ack mode. + /// the Session to use, or null to indicate + /// creation of a raw standard Session + public virtual ISession GetSession(IConnection con, SessionMode mode) + { + return null; + } + + /// + /// reate a JMS Connection via this template's ConnectionFactory. + /// + /// + protected virtual IConnection DoCreateConnection() + { + return TargetConnectionFactory.CreateConnection(); + } + + /// + /// Closes the given connection. + /// + /// The connection. + protected virtual void CloseConnection(IConnection con) + { + if (LOG.IsEnabled(LogLevel.Debug)) + { + LOG.LogDebug("Closing shared EMS Connection: " + this.target); } - public ISession CreateSession(bool transacted, SessionMode acknowledgeMode) + try { - ISession session = singleConnectionFactory.GetSession(target, acknowledgeMode); - if (session != null) + try { - return session; - } - return target.CreateSession(transacted, acknowledgeMode); - } - - public IExceptionListener ExceptionListener - { - get - { - IExceptionListener currentExceptionListener = target.ExceptionListener; - if (currentExceptionListener is InternalChainedExceptionListener) + if (this.started) { - return ((InternalChainedExceptionListener) currentExceptionListener).UserListener; - } else - { - return currentExceptionListener; + this.started = false; + con.Stop(); } } - set + finally { - IExceptionListener currentExceptionListener = target.ExceptionListener; - if (value != null && currentExceptionListener is InternalChainedExceptionListener) - { - ((InternalChainedExceptionListener) currentExceptionListener).AddListener(value); - } else - { - throw new IllegalStateException( - "set ExceptionListener call not supported on proxy for shared Connection. " + - "Set the 'ExceptionListener' property on the SingleConnectionFactory instead. " + - "Alternatively, activate SingleConnectionFactory's 'reconnectOnException' feature, " + - "which will allow for registering further ExceptionListeners to the recovery chain."); - } + con.Close(); } } - - #region Pass through implementations to the target connection - - - public event EMSExceptionHandler EMSExceptionHandler + catch (Exception ex) { - add + LOG.LogWarning(ex, "Could not close shared EMS connection."); + } + } + + #region IInitializingObject Members + + /// + /// Ensure that the connection or TargetConnectionFactory are specified. + /// + public void AfterPropertiesSet() + { + if (connection == null && TargetConnectionFactory == null) + { + throw new ArgumentException("Connection or 'TargetConnectionFactory' is required."); + } + + // Note this is repeated in EmsConnectionFactory as this class only refers to IConnectionFactory and + // IConnectionFactory does not implement the spring specific lifecycle interface IInitializingObject + if (sslProxyAuthUsernameSet || sslProxyAuthPasswordSet) + { + TargetConnectionFactory.NativeConnectionFactory.SetSSLProxyAuth(SSLProxyAuthUsername, SSLProxyAuthPassword); + } + + if (sslProxyHostSet || sslProxyPortSet) + { + TargetConnectionFactory.NativeConnectionFactory.SetSSLProxy(SSLProxyHost, SSLProxyPort); + } + } + + #endregion + + /// + /// Close the underlying shared connection. The provider of this ConnectionFactory needs to care for proper shutdown. + /// As this object implements an application context will automatically + /// invoke this on distruction o + /// + public void Dispose() + { + ResetConnection(); + } + + /// + /// Resets the underlying shared Connection, to be reinitialized on next access. + /// + public virtual void ResetConnection() + { + lock (connectionMonitor) + { + if (this.target != null) { - target.EMSExceptionHandler += value; - } - remove - { - target.EMSExceptionHandler -= value; + CloseConnection(this.target); } + + this.target = null; + this.connection = null; } + } - - public Connection NativeConnection + /// + /// Wrap the given Connection with a proxy that delegates every method call to it + /// but suppresses close calls. This is useful for allowing application code to + /// handle a special framework Connection just like an ordinary Connection from a + /// ConnectionFactory. + /// + /// The original connection to wrap. + /// the wrapped connection + protected virtual IConnection GetSharedConnection(IConnection target) + { + lock (connectionMonitor) { - get { return target.NativeConnection; } + return new CloseSupressingConnection(this, target); } - - public string ActiveURL - { - get { return target.ActiveURL; } - } - - public long ConnID - { - get { return target.ConnID; } - } - - public bool IsClosed - { - get { return target.IsClosed; } - } - - public bool IsSecure - { - get { return target.IsSecure; } - } - - public ConnectionMetaData MetaData - { - get { return target.MetaData; } - } - - #endregion - - } } + +/// +/// Internal chained ExceptionListener for handling the internal recovery listener +/// in combination with a user-specified listener. +/// +internal class InternalChainedExceptionListener : ChainedExceptionListener +{ + private IExceptionListener userListener; + + public InternalChainedExceptionListener(IExceptionListener internalListener, IExceptionListener userListener) + { + AddListener(internalListener); + if (userListener != null) + { + AddListener(userListener); + this.userListener = userListener; + } + } + + public IExceptionListener UserListener + { + get { return userListener; } + } +} + +internal class CloseSupressingConnection : IConnection +{ + private IConnection target; + private SingleConnectionFactory singleConnectionFactory; + + public CloseSupressingConnection(SingleConnectionFactory singleConnectionFactory, IConnection target) + { + this.target = target; + this.singleConnectionFactory = singleConnectionFactory; + } + + /// + /// Add information to show this is a shared EMS connection + /// + /// Description of connection wrapper + public override string ToString() + { + return "Shared EMS Connection: " + this.target; + } + + public string ClientID + { + get { return target.ClientID; } + set + { + // Handle set ClientID property: throw exception if not compatible. + string currentClientId = target.ClientID; + if (currentClientId != null && currentClientId.Equals(value)) + { + //ok, the values are consistent. + } + else + { + throw new IllegalStateException( + "Setting of 'ClientID' property not supported on wrapper for shared Connection since" + + "this is a shared connection that may serve any number of clients concurrently." + + "Set the 'ClientId' property on the SingleConnectionFactory instead."); + } + } + } + + public void Start() + { + // Handle start method: track started state. + target.Start(); + lock (singleConnectionFactory.ConnectionMonitor) + { + singleConnectionFactory.IsStarted = true; + } + } + + public void Stop() + { + //don't pass the call to the target as it would stop receiving for all clients sharing this connection. + } + + public void Close() + { + // don't pass the call to the target. + } + + public ISession CreateSession(bool transacted, int acknowledgementMode) + { + ISession session = singleConnectionFactory.GetSession(target, EmsUtils.ConvertAcknowledgementMode(acknowledgementMode)); + if (session != null) + { + return session; + } + + return target.CreateSession(transacted, acknowledgementMode); + } + + public ISession CreateSession(bool transacted, SessionMode acknowledgeMode) + { + ISession session = singleConnectionFactory.GetSession(target, acknowledgeMode); + if (session != null) + { + return session; + } + + return target.CreateSession(transacted, acknowledgeMode); + } + + public IExceptionListener ExceptionListener + { + get + { + IExceptionListener currentExceptionListener = target.ExceptionListener; + if (currentExceptionListener is InternalChainedExceptionListener) + { + return ((InternalChainedExceptionListener) currentExceptionListener).UserListener; + } + else + { + return currentExceptionListener; + } + } + set + { + IExceptionListener currentExceptionListener = target.ExceptionListener; + if (value != null && currentExceptionListener is InternalChainedExceptionListener) + { + ((InternalChainedExceptionListener) currentExceptionListener).AddListener(value); + } + else + { + throw new IllegalStateException( + "set ExceptionListener call not supported on proxy for shared Connection. " + + "Set the 'ExceptionListener' property on the SingleConnectionFactory instead. " + + "Alternatively, activate SingleConnectionFactory's 'reconnectOnException' feature, " + + "which will allow for registering further ExceptionListeners to the recovery chain."); + } + } + } + + #region Pass through implementations to the target connection + + public event EMSExceptionHandler EMSExceptionHandler + { + add + { + target.EMSExceptionHandler += value; + } + remove + { + target.EMSExceptionHandler -= value; + } + } + + public Connection NativeConnection + { + get { return target.NativeConnection; } + } + + public string ActiveURL + { + get { return target.ActiveURL; } + } + + public long ConnID + { + get { return target.ConnID; } + } + + public bool IsClosed + { + get { return target.IsClosed; } + } + + public bool IsSecure + { + get { return target.IsSecure; } + } + + public ConnectionMetaData MetaData + { + get { return target.MetaData; } + } + + #endregion +} diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Connections/SynchedLocalTransactionFailedException.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Connections/SynchedLocalTransactionFailedException.cs index db2eb3cc..74397bf4 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Connections/SynchedLocalTransactionFailedException.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Connections/SynchedLocalTransactionFailedException.cs @@ -18,44 +18,43 @@ #endregion -namespace Spring.Messaging.Ems.Connections -{ - /// Exception thrown when a synchronized local transaction failed to complete - /// (after the main transaction has already completed). +namespace Spring.Messaging.Ems.Connections; + +/// Exception thrown when a synchronized local transaction failed to complete +/// (after the main transaction has already completed). +/// +/// Jergen Hoeller +/// Mark Pollack (.NET) +[Serializable] +public class SynchedLocalTransactionFailedException : EMSException +{ + #region Constructor (s) / Destructor + + /// + /// Creates a new instance of the SynchedLocalTransactionFailedException class. with the specified message. /// - /// Jergen Hoeller - /// Mark Pollack (.NET) - [Serializable] - public class SynchedLocalTransactionFailedException : EMSException + /// + /// A message about the exception. + /// + public SynchedLocalTransactionFailedException(string message) : base(message) { - #region Constructor (s) / Destructor - - /// - /// Creates a new instance of the SynchedLocalTransactionFailedException class. with the specified message. - /// - /// - /// A message about the exception. - /// - public SynchedLocalTransactionFailedException (string message) : base(message) - { - } - - /// - /// Creates a new instance of the SynchedLocalTransactionFailedException class with the specified message - /// and root cause. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception that is being wrapped. - /// - public SynchedLocalTransactionFailedException (string message, Exception rootCause) - : base(message) - { - LinkedException = rootCause; - } - - #endregion } + + /// + /// Creates a new instance of the SynchedLocalTransactionFailedException class with the specified message + /// and root cause. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception that is being wrapped. + /// + public SynchedLocalTransactionFailedException(string message, Exception rootCause) + : base(message) + { + LinkedException = rootCause; + } + + #endregion } diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Core/BrowserDelegate.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Core/BrowserDelegate.cs index 39edf505..4d931b7e 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Core/BrowserDelegate.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Core/BrowserDelegate.cs @@ -1,5 +1,3 @@ - - #region License /* @@ -22,10 +20,9 @@ using Spring.Messaging.Ems.Common; -namespace Spring.Messaging.Ems.Core -{ - /// - /// Delegate callback for browsing the messages in an EMS queue. - /// - public delegate object BrowserDelegate(ISession session, QueueBrowser browser); -} +namespace Spring.Messaging.Ems.Core; + +/// +/// Delegate callback for browsing the messages in an EMS queue. +/// +public delegate object BrowserDelegate(ISession session, QueueBrowser browser); diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Core/EmsGatewaySupport.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Core/EmsGatewaySupport.cs index 3c533632..2d11a8be 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Core/EmsGatewaySupport.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Core/EmsGatewaySupport.cs @@ -21,97 +21,94 @@ using Spring.Messaging.Ems.Common; using Spring.Objects.Factory; -namespace Spring.Messaging.Ems.Core +namespace Spring.Messaging.Ems.Core; + +/// +/// Convenient super class for application classes that need EMS access. +/// +/// +/// Requires a ConnectionFactory or a EmsTemplate instance to be set. +/// It will create its own EmsTemplate if a ConnectionFactory is passed in. +/// A custom EmsTemplate instance can be created for a given ConnectionFactory +/// through overriding the createEmsTemplate method. +/// +/// +public class EmsGatewaySupport : IInitializingObject { + #region Logging + + private readonly ILogger logger = LogManager.GetLogger(); + + #endregion + + private EmsTemplate emsTemplate; + /// - /// Convenient super class for application classes that need EMS access. + /// Gets or sets the EMS template for the gateway. /// - /// - /// Requires a ConnectionFactory or a EmsTemplate instance to be set. - /// It will create its own EmsTemplate if a ConnectionFactory is passed in. - /// A custom EmsTemplate instance can be created for a given ConnectionFactory - /// through overriding the createEmsTemplate method. - /// - /// - public class EmsGatewaySupport : IInitializingObject + /// The EMS template. + public EmsTemplate EmsTemplate { + get { return emsTemplate; } + set { emsTemplate = value; } + } - #region Logging - - private readonly ILogger logger = LogManager.GetLogger(); - - #endregion - - private EmsTemplate emsTemplate; - - - /// - /// Gets or sets the EMS template for the gateway. - /// - /// The EMS template. - public EmsTemplate EmsTemplate + /// + /// Gets or sets he EMS connection factory to be used by the gateway. + /// Will automatically create a EmsTemplate for the given ConnectionFactory. + /// + /// The connection factory. + public IConnectionFactory ConnectionFactory + { + get { - get { return emsTemplate; } - set { emsTemplate = value; } + return (emsTemplate != null ? this.emsTemplate.ConnectionFactory : null); } - - /// - /// Gets or sets he EMS connection factory to be used by the gateway. - /// Will automatically create a EmsTemplate for the given ConnectionFactory. - /// - /// The connection factory. - public IConnectionFactory ConnectionFactory + set { - get - { - return (emsTemplate != null ? this.emsTemplate.ConnectionFactory : null); - } - set - { - this.emsTemplate = CreateEmsTemplate(value); - } - } - - /// - /// Creates a EmsTemplate for the given ConnectionFactory. - /// - /// Only invoked if populating the gateway with a ConnectionFactory reference. - /// Can be overridden in subclasses to provide a different EmsTemplate instance - /// - /// - /// The connection factory. - /// - protected virtual EmsTemplate CreateEmsTemplate(IConnectionFactory connectionFactory) - { - return new EmsTemplate(connectionFactory); - } - - /// - /// Ensures that the JmsTemplate is specified and calls . - /// - public virtual void AfterPropertiesSet() - { - if (emsTemplate == null) - { - throw new ArgumentException("connectionFactory or jmsTemplate is required"); - } - try - { - InitGateway(); - } - catch (Exception e) - { - throw new ObjectInitializationException("Initialization of the EMS gateway failed: " + e.Message, e); - } - } - - /// - /// Subclasses can override this for custom initialization behavior. - /// Gets called after population of this instance's properties. - /// - protected virtual void InitGateway() - { - + this.emsTemplate = CreateEmsTemplate(value); } } -} + + /// + /// Creates a EmsTemplate for the given ConnectionFactory. + /// + /// Only invoked if populating the gateway with a ConnectionFactory reference. + /// Can be overridden in subclasses to provide a different EmsTemplate instance + /// + /// + /// The connection factory. + /// + protected virtual EmsTemplate CreateEmsTemplate(IConnectionFactory connectionFactory) + { + return new EmsTemplate(connectionFactory); + } + + /// + /// Ensures that the JmsTemplate is specified and calls . + /// + public virtual void AfterPropertiesSet() + { + if (emsTemplate == null) + { + throw new ArgumentException("connectionFactory or jmsTemplate is required"); + } + + try + { + InitGateway(); + } + catch (Exception e) + { + throw new ObjectInitializationException("Initialization of the EMS gateway failed: " + e.Message, e); + } + } + + /// + /// Subclasses can override this for custom initialization behavior. + /// Gets called after population of this instance's properties. + /// + protected virtual void InitGateway() + { + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Core/EmsTemplate.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Core/EmsTemplate.cs index 52efcc3d..277e3068 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Core/EmsTemplate.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Core/EmsTemplate.cs @@ -26,1766 +26,1752 @@ using Spring.Messaging.Ems.Support.Converter; using Spring.Messaging.Ems.Support.Destinations; using Spring.Transaction.Support; using Spring.Util; -using Queue=TIBCO.EMS.Queue; +using Queue = TIBCO.EMS.Queue; -namespace Spring.Messaging.Ems.Core +namespace Spring.Messaging.Ems.Core; + +/// Helper class that simplifies EMS access code. +/// +/// If you want to use dynamic destination creation, you must specify +/// the type of EMS destination to create, using the "pubSubDomain" property. +/// For other operations, this is not necessary. +/// Point-to-Point (Queues) is the default domain. +/// +/// Default settings for EMS Sessions is "auto-acknowledge". +/// +/// This template uses a DynamicDestinationResolver and a SimpleMessageConverter +/// as default strategies for resolving a destination name or converting a message, +/// respectively. +/// +/// +/// Mark Pollack +/// Juergen Hoeller +/// Mark Pollack (.NET) +public class EmsTemplate : EmsDestinationAccessor, IEmsOperations { - /// Helper class that simplifies EMS access code. + #region Logging + + private readonly ILogger logger = LogManager.GetLogger(); + + #endregion + + #region Fields + + /// + /// Timeout value indicating that a receive operation should + /// check if a message is immediately available without blocking. + /// + public static readonly long DEFAULT_RECEIVE_TIMEOUT = -1; + + private EmsTemplateResourceFactory transactionalResourceFactory; + + private object defaultDestination; + + private IMessageConverter messageConverter; + + private bool messageIdEnabled = true; + + private bool messageTimestampEnabled = true; + + private bool pubSubNoLocal = false; + + private long receiveTimeout = DEFAULT_RECEIVE_TIMEOUT; + + private bool explicitQosEnabled = false; + + private int priority = Message.DEFAULT_PRIORITY; + + private int deliveryMode = Message.DEFAULT_DELIVERY_MODE; + + private long timeToLive = Message.DEFAULT_TIME_TO_LIVE; + + #endregion + + #region Constructor (s) + + /// Create a new EmsTemplate. /// - /// If you want to use dynamic destination creation, you must specify - /// the type of EMS destination to create, using the "pubSubDomain" property. - /// For other operations, this is not necessary. - /// Point-to-Point (Queues) is the default domain. - /// - /// Default settings for EMS Sessions is "auto-acknowledge". - /// - /// This template uses a DynamicDestinationResolver and a SimpleMessageConverter - /// as default strategies for resolving a destination name or converting a message, - /// respectively. - /// + /// Note: The ConnectionFactory has to be set before using the instance. + /// This constructor can be used to prepare a EmsTemplate via an ObjectFactory, + /// typically setting the ConnectionFactory. /// - /// Mark Pollack - /// Juergen Hoeller - /// Mark Pollack (.NET) - public class EmsTemplate : EmsDestinationAccessor, IEmsOperations + public EmsTemplate() { - #region Logging + transactionalResourceFactory = new EmsTemplateResourceFactory(this); + InitDefaultStrategies(); + } - private readonly ILogger logger = LogManager.GetLogger(); + /// Create a new EmsTemplate, given a ConnectionFactory. + /// the ConnectionFactory to obtain Connections from + /// + public EmsTemplate(IConnectionFactory connectionFactory) + : this() + { + ConnectionFactory = connectionFactory; + AfterPropertiesSet(); + } + #endregion - #endregion - #region Fields + #region Methods - /// - /// Timeout value indicating that a receive operation should - /// check if a message is immediately available without blocking. - /// - public static readonly long DEFAULT_RECEIVE_TIMEOUT = -1; + /// Initialize the default implementations for the template's strategies: + /// DynamicDestinationResolver and SimpleMessageConverter. + /// + protected virtual void InitDefaultStrategies() + { + MessageConverter = new SimpleMessageConverter(); + } - private EmsTemplateResourceFactory transactionalResourceFactory; - - private object defaultDestination; - - private IMessageConverter messageConverter; - - - private bool messageIdEnabled = true; - - private bool messageTimestampEnabled = true; - - private bool pubSubNoLocal = false; - - private long receiveTimeout = DEFAULT_RECEIVE_TIMEOUT; - - private bool explicitQosEnabled = false; - - private int priority = Message.DEFAULT_PRIORITY; - - private int deliveryMode = Message.DEFAULT_DELIVERY_MODE; - - private long timeToLive = Message.DEFAULT_TIME_TO_LIVE; - - #endregion - - #region Constructor (s) - - /// Create a new EmsTemplate. - /// - /// Note: The ConnectionFactory has to be set before using the instance. - /// This constructor can be used to prepare a EmsTemplate via an ObjectFactory, - /// typically setting the ConnectionFactory. - /// - public EmsTemplate() + private void CheckDefaultDestination() + { + if (defaultDestination == null) { - transactionalResourceFactory = new EmsTemplateResourceFactory(this); - InitDefaultStrategies(); + throw new SystemException( + "No defaultDestination or defaultDestinationName specified. Check configuration of EmsTemplate."); } + } - - /// Create a new EmsTemplate, given a ConnectionFactory. - /// the ConnectionFactory to obtain Connections from - /// - public EmsTemplate(IConnectionFactory connectionFactory) - : this() + private void CheckMessageConverter() + { + if (MessageConverter == null) { - ConnectionFactory = connectionFactory; - AfterPropertiesSet(); + throw new SystemException("No messageConverter registered. Check configuration of EmsTemplate."); } + } - #endregion + /// Execute the action specified by the given action object within a + /// EMS Session. + /// + /// Generalized version of execute(SessionCallback), + /// allowing the EMS Connection to be started on the fly. + ///

Use execute(SessionCallback) for the general case. + /// Starting the EMS Connection is just necessary for receiving messages, + /// which is preferably achieved through the receive methods.

+ ///
+ /// callback object that exposes the session + /// + /// Start the connection before performing callback action. + /// + /// the result object from working with the session + /// + /// If there is any problem accessing the EMS API + public virtual object Execute(ISessionCallback action, bool startConnection) + { + return Execute(action.DoInEms, startConnection); + } - #region Methods + /// Execute the action specified by the given action object within a + /// EMS Session. + /// + /// Generalized version of execute(SessionCallback), + /// allowing the EMS Connection to be started on the fly. + ///

Use execute(SessionCallback) for the general case. + /// Starting the EMS Connection is just necessary for receiving messages, + /// which is preferably achieved through the receive methods.

+ ///
+ /// callback object that exposes the session + /// + /// Start the connection before performing callback action. + /// + /// the result object from working with the session + /// + /// If there is any problem accessing the EMS API + public virtual object Execute(SessionDelegate action, bool startConnection) + { + AssertUtils.ArgumentNotNull(action, "Callback object must not be null"); - /// Initialize the default implementations for the template's strategies: - /// DynamicDestinationResolver and SimpleMessageConverter. - /// - protected virtual void InitDefaultStrategies() + IConnection conToClose = null; + ISession sessionToClose = null; + // bool sessionInTLS = true; + + //NOTE: Not closing session or connection unless session is not returned from + // ConnectionFactoryUtils.DoGetTransactionalSession and CacheEmsResources is set to false + try { - MessageConverter = new SimpleMessageConverter(); - } - - private void CheckDefaultDestination() - { - if (defaultDestination == null) + ISession sessionToUse = + ConnectionFactoryUtils.DoGetTransactionalSession(ConnectionFactory, transactionalResourceFactory, + startConnection); + if (sessionToUse == null) { - throw new SystemException( - "No defaultDestination or defaultDestinationName specified. Check configuration of EmsTemplate."); - } - } - - - private void CheckMessageConverter() - { - if (MessageConverter == null) - { - throw new SystemException("No messageConverter registered. Check configuration of EmsTemplate."); - } - } - - /// Execute the action specified by the given action object within a - /// EMS Session. - /// - /// Generalized version of execute(SessionCallback), - /// allowing the EMS Connection to be started on the fly. - ///

Use execute(SessionCallback) for the general case. - /// Starting the EMS Connection is just necessary for receiving messages, - /// which is preferably achieved through the receive methods.

- ///
- /// callback object that exposes the session - /// - /// Start the connection before performing callback action. - /// - /// the result object from working with the session - /// - /// If there is any problem accessing the EMS API - public virtual object Execute(ISessionCallback action, bool startConnection) - { - return Execute(action.DoInEms, startConnection); - } - - - /// Execute the action specified by the given action object within a - /// EMS Session. - /// - /// Generalized version of execute(SessionCallback), - /// allowing the EMS Connection to be started on the fly. - ///

Use execute(SessionCallback) for the general case. - /// Starting the EMS Connection is just necessary for receiving messages, - /// which is preferably achieved through the receive methods.

- ///
- /// callback object that exposes the session - /// - /// Start the connection before performing callback action. - /// - /// the result object from working with the session - /// - /// If there is any problem accessing the EMS API - public virtual object Execute(SessionDelegate action, bool startConnection) - { - AssertUtils.ArgumentNotNull(action, "Callback object must not be null"); - - IConnection conToClose = null; - ISession sessionToClose = null; - // bool sessionInTLS = true; - - //NOTE: Not closing session or connection unless session is not returned from - // ConnectionFactoryUtils.DoGetTransactionalSession and CacheEmsResources is set to false - try - { - ISession sessionToUse = - ConnectionFactoryUtils.DoGetTransactionalSession(ConnectionFactory, transactionalResourceFactory, - startConnection); - if (sessionToUse == null) + //sessionInTLS = false; + conToClose = CreateConnection(); + sessionToClose = CreateSession(conToClose); + if (startConnection) { - //sessionInTLS = false; - conToClose = CreateConnection(); - sessionToClose = CreateSession(conToClose); - if (startConnection) - { - conToClose.Start(); - } - sessionToUse = sessionToClose; + conToClose.Start(); } - if (logger.IsEnabled(LogLevel.Debug)) - { - logger.LogDebug("Executing callback on EMS Session [" + sessionToUse + "]"); - } - return action(sessionToUse); + + sessionToUse = sessionToClose; } - finally + + if (logger.IsEnabled(LogLevel.Debug)) { - EmsUtils.CloseSession(sessionToClose); - ConnectionFactoryUtils.ReleaseConnection(conToClose, ConnectionFactory, startConnection); - /* - if (!sessionInTLS && !CacheEmsResources) - { - EmsUtils.CloseSession(session); - ConnectionFactoryUtils.ReleaseConnection(con, ConnectionFactory, startConnection); - }*/ + logger.LogDebug("Executing callback on EMS Session [" + sessionToUse + "]"); } + + return action(sessionToUse); } - - #endregion - - #region Properties - - /// - /// Gets or sets the default destination to be used on send/receive operations that do not - /// have a destination parameter. - /// - /// Alternatively, specify a "defaultDestinationName", to be - /// dynamically resolved via the DestinationResolver. - /// The default destination. - virtual public Destination DefaultDestination + finally { - get { return (defaultDestination as Destination); } - - set { defaultDestination = value; } + EmsUtils.CloseSession(sessionToClose); + ConnectionFactoryUtils.ReleaseConnection(conToClose, ConnectionFactory, startConnection); + /* + if (!sessionInTLS && !CacheEmsResources) + { + EmsUtils.CloseSession(session); + ConnectionFactoryUtils.ReleaseConnection(con, ConnectionFactory, startConnection); + }*/ } + } + #endregion - /// - /// Gets or sets the name of the default destination name - /// to be used on send/receive operations that - /// do not have a destination parameter. - /// - /// - /// Alternatively, specify a EMS Destination object as "DefaultDestination" - /// - /// The name of the default destination. - virtual public string DefaultDestinationName + #region Properties + + /// + /// Gets or sets the default destination to be used on send/receive operations that do not + /// have a destination parameter. + /// + /// Alternatively, specify a "defaultDestinationName", to be + /// dynamically resolved via the DestinationResolver. + /// The default destination. + virtual public Destination DefaultDestination + { + get { return (defaultDestination as Destination); } + + set { defaultDestination = value; } + } + + /// + /// Gets or sets the name of the default destination name + /// to be used on send/receive operations that + /// do not have a destination parameter. + /// + /// + /// Alternatively, specify a EMS Destination object as "DefaultDestination" + /// + /// The name of the default destination. + virtual public string DefaultDestinationName + { + get { return (defaultDestination as string); } + + set { defaultDestination = value; } + } + + /// + /// Gets or sets the message converter for this template. + /// + /// + /// Used to resolve + /// Object parameters to convertAndSend methods and Object results + /// from receiveAndConvert methods. + ///

The default converter is a SimpleMessageConverter, which is able + /// to handle BytesMessages, TextMessages and ObjectMessages.

+ ///
+ /// The message converter. + virtual public IMessageConverter MessageConverter + { + get { return messageConverter; } + + set { messageConverter = value; } + } + + /// + /// Gets or sets a value indicating whether Message Ids are enabled. + /// + /// true if message id enabled; otherwise, false. + virtual public bool MessageIdEnabled + { + get { return messageIdEnabled; } + + set { messageIdEnabled = value; } + } + + /// + /// Gets or sets a value indicating whether message timestamps are enabled. + /// + /// + /// true if [message timestamp enabled]; otherwise, false. + /// + virtual public bool MessageTimestampEnabled + { + get { return messageTimestampEnabled; } + + set { messageTimestampEnabled = value; } + } + + /// + /// Gets or sets a value indicating whether to inhibit the delivery of messages published by its own connection. + /// + /// + /// true if inhibit the delivery of messages published by its own connection; otherwise, false. + virtual public bool PubSubNoLocal + { + get { return pubSubNoLocal; } + + set { pubSubNoLocal = value; } + } + + /// + /// Gets or sets the receive timeout to use for recieve calls. + /// + /// The default is -1, which means no timeout. + /// The receive timeout. + virtual public long ReceiveTimeout + { + get { return receiveTimeout; } + + set { receiveTimeout = value; } + } + + /// + /// Gets or sets a value indicating whether to use explicit Quality of Service values. + /// + /// If "true", then the values of deliveryMode, priority, and timeToLive + /// will be used when sending a message. Otherwise, the default values, + /// that may be set administratively, will be used + /// true if use explicit QoS values; otherwise, false. + virtual public bool ExplicitQosEnabled + { + get { return explicitQosEnabled; } + + set { explicitQosEnabled = value; } + } + + /// + /// Sets a value indicating the delivery mode QOS + /// + /// + /// This will set the delivery to persistent, non-persistent, or reliable delivery. + /// Default value is Message.DEFAULT_DELIVERY_MODE (aka TIBCO.EMS.DeliveryMode.PERSISTENT) + /// + /// Integer value representing the delivery mode [delivery persistent]; otherwise, false. + virtual public int DeliveryMode + { + get { return deliveryMode; } + + set { deliveryMode = value; } + } + + /// + /// Gets or sets the priority when sending. + /// + /// Since a default value may be defined administratively, + /// this is only used when "isExplicitQosEnabled" equals "true". + /// The priority. + virtual public int Priority + { + get { return priority; } + + set { priority = value; } + } + + /// + /// Gets or sets the time to live when sending + /// + /// Since a default value may be defined administratively, + /// this is only used when "isExplicitQosEnabled" equals "true". + /// The time to live. + virtual public long TimeToLive + { + get { return timeToLive; } + + set { timeToLive = value; } + } + + /* + /// + /// Gets or sets a value indicating whether the EmsTemplate should itself + /// be responsible for caching EMS Connection/Session/MessageProducer as compared to + /// creating new instances per operation (unless such resources are already + /// present in Thread-Local storage either due to the use of EmsTransactionMananger or + /// SimpleMessageListenerContainer at an outer calling layer. + /// + /// Connection/Session/MessageProducer are thread-safe classes in TIBCO EMS. + /// true to locally cache ems resources; otherwise, false. + virtual public bool CacheEmsResources + { + get { return cacheEmsResources; } + set { cacheEmsResources = value; } + }*/ + + #endregion + + /// + /// Extract the content from the given JMS message. + /// + /// The Message to convert (can be null). + /// The content of the message, or null if none + protected virtual object DoConvertFromMessage(Message message) + { + if (message != null) { - get { return (defaultDestination as string); } - - set { defaultDestination = value; } + return MessageConverter.FromMessage(message); } - /// - /// Gets or sets the message converter for this template. - /// - /// - /// Used to resolve - /// Object parameters to convertAndSend methods and Object results - /// from receiveAndConvert methods. - ///

The default converter is a SimpleMessageConverter, which is able - /// to handle BytesMessages, TextMessages and ObjectMessages.

- ///
- /// The message converter. - virtual public IMessageConverter MessageConverter + return null; + } + + #region EMS Factory Methods + + /// Fetch an appropriate Connection from the given EmsResourceHolder. + /// + /// the EmsResourceHolder + /// + /// an appropriate Connection fetched from the holder, + /// or null if none found + /// + protected virtual IConnection GetConnection(EmsResourceHolder holder) + { + return holder.GetConnection(); + } + + /// Fetch an appropriate Session from the given EmsResourceHolder. + /// + /// the EmsResourceHolder + /// + /// an appropriate Session fetched from the holder, + /// or null if none found + /// + protected virtual ISession GetSession(EmsResourceHolder holder) + { + return holder.GetSession(); + } + + /// Create a EMS MessageProducer for the given Session and Destination, + /// configuring it to disable message ids and/or timestamps (if necessary). + ///

Delegates to doCreateProducer for creation of the raw + /// EMS MessageProducer

+ ///
+ /// the EMS Session to create a MessageProducer for + /// + /// the EMS Destination to create a MessageProducer for + /// + /// the new EMS MessageProducer + /// + /// If there is any problem accessing the EMS API + /// + /// + /// + /// + /// + /// + protected virtual IMessageProducer CreateProducer(ISession session, Destination destination) + { + IMessageProducer producer = DoCreateProducer(session, destination); + if (!MessageIdEnabled) { - get { return messageConverter; } - - set { messageConverter = value; } + producer.DisableMessageID = true; } - /// - /// Gets or sets a value indicating whether Message Ids are enabled. - /// - /// true if message id enabled; otherwise, false. - virtual public bool MessageIdEnabled + if (!MessageTimestampEnabled) { - get { return messageIdEnabled; } - - set { messageIdEnabled = value; } + producer.DisableMessageTimestamp = true; } - /// - /// Gets or sets a value indicating whether message timestamps are enabled. - /// - /// - /// true if [message timestamp enabled]; otherwise, false. - /// - virtual public bool MessageTimestampEnabled - { - get { return messageTimestampEnabled; } + return producer; + } - set { messageTimestampEnabled = value; } - } - - - /// - /// Gets or sets a value indicating whether to inhibit the delivery of messages published by its own connection. - /// - /// - /// true if inhibit the delivery of messages published by its own connection; otherwise, false. - virtual public bool PubSubNoLocal - { - get { return pubSubNoLocal; } - - set { pubSubNoLocal = value; } - } - - /// - /// Gets or sets the receive timeout to use for recieve calls. - /// - /// The default is -1, which means no timeout. - /// The receive timeout. - virtual public long ReceiveTimeout - { - get { return receiveTimeout; } - - set { receiveTimeout = value; } - } - - /// - /// Gets or sets a value indicating whether to use explicit Quality of Service values. - /// - /// If "true", then the values of deliveryMode, priority, and timeToLive - /// will be used when sending a message. Otherwise, the default values, - /// that may be set administratively, will be used - /// true if use explicit QoS values; otherwise, false. - virtual public bool ExplicitQosEnabled - { - get { return explicitQosEnabled; } - - set { explicitQosEnabled = value; } - } - - /// - /// Sets a value indicating the delivery mode QOS - /// - /// - /// This will set the delivery to persistent, non-persistent, or reliable delivery. - /// Default value is Message.DEFAULT_DELIVERY_MODE (aka TIBCO.EMS.DeliveryMode.PERSISTENT) - /// - /// Integer value representing the delivery mode [delivery persistent]; otherwise, false. - virtual public int DeliveryMode - { - get { return deliveryMode; } - - set { deliveryMode = value; } - } - - /// - /// Gets or sets the priority when sending. - /// - /// Since a default value may be defined administratively, - /// this is only used when "isExplicitQosEnabled" equals "true". - /// The priority. - virtual public int Priority - { - get { return priority; } - - set { priority = value; } - } - - /// - /// Gets or sets the time to live when sending - /// - /// Since a default value may be defined administratively, - /// this is only used when "isExplicitQosEnabled" equals "true". - /// The time to live. - virtual public long TimeToLive - { - get { return timeToLive; } - - set { timeToLive = value; } - } + /// + /// Determines whether the given Session is locally transacted, that is, whether + /// its transaction is managed by this template class's Session handling + /// and not by an external transaction coordinator. + /// + /// + /// The Session's own transacted flag will already have been checked + /// before. This method is about finding out whether the Session's transaction + /// is local or externally coordinated. + /// + /// The session to check. + /// + /// true if the session is locally transacted; otherwise, false. + /// + protected virtual bool IsSessionLocallyTransacted(ISession session) + { + return SessionTransacted && + !ConnectionFactoryUtils.IsSessionTransactional(session, ConnectionFactory); + } + /// Create a raw EMS MessageProducer for the given Session and Destination. + /// + /// If CacheJmsResource is true, then the producer + /// will be created upon the first invocation and will retrun the same + /// producer (per destination) on all subsequent calls. + /// + /// the EMS Session to create a MessageProducer for + /// + /// the EMS Destination to create a MessageProducer for + /// + /// the new EMS MessageProducer + /// + /// If there is any problem accessing the EMS API + protected virtual IMessageProducer DoCreateProducer(ISession session, Destination destination) + { + return session.CreateProducer(destination); /* - /// - /// Gets or sets a value indicating whether the EmsTemplate should itself - /// be responsible for caching EMS Connection/Session/MessageProducer as compared to - /// creating new instances per operation (unless such resources are already - /// present in Thread-Local storage either due to the use of EmsTransactionMananger or - /// SimpleMessageListenerContainer at an outer calling layer. - /// - /// Connection/Session/MessageProducer are thread-safe classes in TIBCO EMS. - /// true to locally cache ems resources; otherwise, false. - virtual public bool CacheEmsResources + if (CacheEmsResources) { - get { return cacheEmsResources; } - set { cacheEmsResources = value; } - }*/ - - - #endregion - - /// - /// Extract the content from the given JMS message. - /// - /// The Message to convert (can be null). - /// The content of the message, or null if none - protected virtual object DoConvertFromMessage(Message message) - { - if (message != null) + if (destination == null) { - return MessageConverter.FromMessage(message); + if (emsResources.UnspecifiedDestinationMessageProducer == null) + { + emsResources.UnspecifiedDestinationMessageProducer = session.CreateProducer(destination); + } + return emsResources.UnspecifiedDestinationMessageProducer; } - return null; - } - - #region EMS Factory Methods - - /// Fetch an appropriate Connection from the given EmsResourceHolder. - /// - /// the EmsResourceHolder - /// - /// an appropriate Connection fetched from the holder, - /// or null if none found - /// - protected virtual IConnection GetConnection(EmsResourceHolder holder) - { - return holder.GetConnection(); - } - - /// Fetch an appropriate Session from the given EmsResourceHolder. - /// - /// the EmsResourceHolder - /// - /// an appropriate Session fetched from the holder, - /// or null if none found - /// - protected virtual ISession GetSession(EmsResourceHolder holder) - { - return holder.GetSession(); - } - - /// Create a EMS MessageProducer for the given Session and Destination, - /// configuring it to disable message ids and/or timestamps (if necessary). - ///

Delegates to doCreateProducer for creation of the raw - /// EMS MessageProducer

- ///
- /// the EMS Session to create a MessageProducer for - /// - /// the EMS Destination to create a MessageProducer for - /// - /// the new EMS MessageProducer - /// - /// If there is any problem accessing the EMS API - /// - /// - /// - /// - /// - /// - protected virtual IMessageProducer CreateProducer(ISession session, Destination destination) - { - IMessageProducer producer = DoCreateProducer(session, destination); - if (!MessageIdEnabled) + IMessageProducer producer = (IMessageProducer)emsResources.Producers[destination]; + if (producer != null) { - producer.DisableMessageID = true; + #region Logging + + if (logger.IsDebugEnabled()) + { + logger.Debug("Found cached MessageProducer for destination [" + destination + "]"); + } + + #endregion } - if (!MessageTimestampEnabled) + else { - producer.DisableMessageTimestamp = true; + producer = session.CreateProducer(destination); + emsResources.Producers.Add(destination, producer); + #region Logging + + if (logger.IsDebugEnabled()) + { + logger.Debug("Created cached MessageProducer for destination [" + destination + "]"); + } + + #endregion } return producer; } - - - /// - /// Determines whether the given Session is locally transacted, that is, whether - /// its transaction is managed by this template class's Session handling - /// and not by an external transaction coordinator. - /// - /// - /// The Session's own transacted flag will already have been checked - /// before. This method is about finding out whether the Session's transaction - /// is local or externally coordinated. - /// - /// The session to check. - /// - /// true if the session is locally transacted; otherwise, false. - /// - protected virtual bool IsSessionLocallyTransacted(ISession session) - { - return SessionTransacted && - !ConnectionFactoryUtils.IsSessionTransactional(session, ConnectionFactory); - } - - /// Create a raw EMS MessageProducer for the given Session and Destination. - /// - /// If CacheJmsResource is true, then the producer - /// will be created upon the first invocation and will retrun the same - /// producer (per destination) on all subsequent calls. - /// - /// the EMS Session to create a MessageProducer for - /// - /// the EMS Destination to create a MessageProducer for - /// - /// the new EMS MessageProducer - /// - /// If there is any problem accessing the EMS API - protected virtual IMessageProducer DoCreateProducer(ISession session, Destination destination) + else { return session.CreateProducer(destination); - /* - if (CacheEmsResources) - { - if (destination == null) - { - if (emsResources.UnspecifiedDestinationMessageProducer == null) - { - emsResources.UnspecifiedDestinationMessageProducer = session.CreateProducer(destination); - } - return emsResources.UnspecifiedDestinationMessageProducer; - } - IMessageProducer producer = (IMessageProducer)emsResources.Producers[destination]; - if (producer != null) - { - #region Logging - - if (logger.IsDebugEnabled()) - { - logger.Debug("Found cached MessageProducer for destination [" + destination + "]"); - } - - #endregion - } - else - { - producer = session.CreateProducer(destination); - emsResources.Producers.Add(destination, producer); - #region Logging - - if (logger.IsDebugEnabled()) - { - logger.Debug("Created cached MessageProducer for destination [" + destination + "]"); - } - - #endregion - } - return producer; - } - else - { - return session.CreateProducer(destination); - }*/ - } - - /// Create a EMS MessageConsumer for the given Session and Destination. - /// - /// the EMS Session to create a MessageConsumer for - /// - /// the EMS Destination to create a MessageConsumer for - /// - /// the message selector for this consumer (can be null) - /// - /// the new EMS MessageConsumer - /// - /// If there is any problem accessing the EMS API - protected virtual IMessageConsumer CreateConsumer(ISession session, Destination destination, - string messageSelector) - { - // Only pass in the NoLocal flag in case of a Topic: - // Some EMS providers, such as WebSphere MQ 6.0, throw IllegalStateException - // in case of the NoLocal flag being specified for a Queue. - if (PubSubDomain) - { - return session.CreateConsumer(destination, messageSelector, PubSubNoLocal); - } - else - { - return session.CreateConsumer(destination, messageSelector); - } - } - /* - /// Create a EMS Connection via this template's ConnectionFactory. - /// - /// If CacheJmsResource is true, then the connection - /// will be created upon the first invocation and will retrun the same - /// connection on all subsequent calls. - /// - /// A EMS Connection - /// - /// If there is any problem accessing the EMS API - protected override IConnection CreateConnection() - { - if (CacheEmsResources) - { - if (emsResources.Connection == null) - { - emsResources.Connection = ConnectionFactory.CreateConnection(); - } - return emsResources.Connection; - - } - else - { - return ConnectionFactory.CreateConnection(); - } }*/ - /* - /// Create a EMS Session for the given Connection. - /// - /// If CacheJmsResource is true, then the session - /// will be created upon the first invocation and will retrun the same - /// session on all subsequent calls. - /// - /// the EMS Connection to create a Session for - /// - /// the new EMS Session - /// - /// If there is any problem accessing the EMS API - protected override ISession CreateSession(IConnection con) + } + + /// Create a EMS MessageConsumer for the given Session and Destination. + /// + /// the EMS Session to create a MessageConsumer for + /// + /// the EMS Destination to create a MessageConsumer for + /// + /// the message selector for this consumer (can be null) + /// + /// the new EMS MessageConsumer + /// + /// If there is any problem accessing the EMS API + protected virtual IMessageConsumer CreateConsumer(ISession session, Destination destination, + string messageSelector) + { + // Only pass in the NoLocal flag in case of a Topic: + // Some EMS providers, such as WebSphere MQ 6.0, throw IllegalStateException + // in case of the NoLocal flag being specified for a Queue. + if (PubSubDomain) { - if (CacheEmsResources) + return session.CreateConsumer(destination, messageSelector, PubSubNoLocal); + } + else + { + return session.CreateConsumer(destination, messageSelector); + } + } + /* + /// Create a EMS Connection via this template's ConnectionFactory. + /// + /// If CacheJmsResource is true, then the connection + /// will be created upon the first invocation and will retrun the same + /// connection on all subsequent calls. + /// + /// A EMS Connection + /// + /// If there is any problem accessing the EMS API + protected override IConnection CreateConnection() + { + if (CacheEmsResources) + { + if (emsResources.Connection == null) { - if (emsResources.Session == null) - { - emsResources.Session = emsResources.Connection.CreateSession(SessionTransacted, SessionAcknowledgeMode); - } - return emsResources.Session; + emsResources.Connection = ConnectionFactory.CreateConnection(); + } + return emsResources.Connection; + + } + else + { + return ConnectionFactory.CreateConnection(); + } + }*/ + /* + /// Create a EMS Session for the given Connection. + /// + /// If CacheJmsResource is true, then the session + /// will be created upon the first invocation and will retrun the same + /// session on all subsequent calls. + /// + /// the EMS Connection to create a Session for + /// + /// the new EMS Session + /// + /// If there is any problem accessing the EMS API + protected override ISession CreateSession(IConnection con) + { + if (CacheEmsResources) + { + if (emsResources.Session == null) + { + emsResources.Session = emsResources.Connection.CreateSession(SessionTransacted, SessionAcknowledgeMode); + } + return emsResources.Session; + } + else + { + return con.CreateSession(SessionTransacted, SessionAcknowledgeMode); + } + }*/ + + /// + /// Send the given message. + /// + /// The session to operate on. + /// The destination to send to. + /// The message creator delegate callback to create a Message. + protected internal virtual void DoSend(ISession session, Destination destination, MessageCreatorDelegate messageCreatorDelegate) + { + AssertUtils.ArgumentNotNull(messageCreatorDelegate, "IMessageCreatorDelegate must not be null"); + DoSend(session, destination, null, messageCreatorDelegate); + } + + /// + /// Send the given message. + /// + /// The session to operate on. + /// The destination to send to. + /// The message creator callback to create a Message. + protected internal virtual void DoSend(ISession session, Destination destination, IMessageCreator messageCreator) + { + AssertUtils.ArgumentNotNull(messageCreator, "IMessageCreator must not be null"); + DoSend(session, destination, messageCreator, null); + } + + /// Send the given EMS message. + /// the EMS Session to operate on + /// + /// the EMS Destination to send to + /// + /// callback to create a EMS Message + /// + /// delegate callback to create a EMS Message + /// + /// If there is any problem accessing the EMS API + protected internal virtual void DoSend(ISession session, Destination destination, IMessageCreator messageCreator, + MessageCreatorDelegate messageCreatorDelegate) + { + IMessageProducer producer = CreateProducer(session, destination); + try + { + Message message; + if (messageCreator != null) + { + message = messageCreator.CreateMessage(session); } else { - return con.CreateSession(SessionTransacted, SessionAcknowledgeMode); + message = messageCreatorDelegate(session); } - }*/ - /// - /// Send the given message. - /// - /// The session to operate on. - /// The destination to send to. - /// The message creator delegate callback to create a Message. - protected internal virtual void DoSend(ISession session, Destination destination, MessageCreatorDelegate messageCreatorDelegate) - { - AssertUtils.ArgumentNotNull(messageCreatorDelegate, "IMessageCreatorDelegate must not be null"); - DoSend(session, destination, null, messageCreatorDelegate); - } - - /// - /// Send the given message. - /// - /// The session to operate on. - /// The destination to send to. - /// The message creator callback to create a Message. - protected internal virtual void DoSend(ISession session, Destination destination, IMessageCreator messageCreator) - { - AssertUtils.ArgumentNotNull(messageCreator, "IMessageCreator must not be null"); - DoSend(session, destination, messageCreator, null); - } - - /// Send the given EMS message. - /// the EMS Session to operate on - /// - /// the EMS Destination to send to - /// - /// callback to create a EMS Message - /// - /// delegate callback to create a EMS Message - /// - /// If there is any problem accessing the EMS API - protected internal virtual void DoSend(ISession session, Destination destination, IMessageCreator messageCreator, - MessageCreatorDelegate messageCreatorDelegate) - { - - - IMessageProducer producer = CreateProducer(session, destination); - try + if (logger.IsEnabled(LogLevel.Debug)) { + logger.LogDebug("Sending created message [" + message + "]"); + } - Message message; - if (messageCreator != null) - { - message = messageCreator.CreateMessage(session) ; - } - else { - message = messageCreatorDelegate(session); - } - if (logger.IsEnabled(LogLevel.Debug)) - { - logger.LogDebug("Sending created message [" + message + "]"); - } - DoSend(producer, message); + DoSend(producer, message); - // Check commit, avoid commit call is Session transaction is externally coordinated. - if (session.Transacted && IsSessionLocallyTransacted(session)) + // Check commit, avoid commit call is Session transaction is externally coordinated. + if (session.Transacted && IsSessionLocallyTransacted(session)) + { + // Transacted session created by this template -> commit. + EmsUtils.CommitIfNecessary(session); + } + } + finally + { + EmsUtils.CloseMessageProducer(producer); + } + } + + /// Actually send the given EMS message. + /// the EMS MessageProducer to send with + /// + /// the EMS Message to send + /// + /// If there is any problem accessing the EMS API + protected virtual void DoSend(IMessageProducer producer, Message message) + { + if (ExplicitQosEnabled) + { + producer.Send(message, DeliveryMode, Priority, TimeToLive); + } + else + { + producer.Send(message); + } + } + + #endregion + + #region IEmsOperations Implementation + + /// + /// Execute the action specified by the given action object within + /// a EMS Session. + /// + /// delegate that exposes the session + /// + /// the result object from working with the session + /// + /// + /// Note that the value of PubSubDomain affects the behavior of this method. + /// If PubSubDomain equals true, then a Session is passed to the callback. + /// If false, then a Session is passed to the callback.b + /// + /// If there is any problem accessing the EMS API + public object Execute(SessionDelegate del) + { + return Execute(new ExecuteSessionCallbackUsingDelegate(del)); + } + + /// Execute the action specified by the given action object within + /// a EMS Session. + ///

Note: The value of PubSubDomain affects the behavior of this method. + /// If PubSubDomain equals true, then a Session is passed to the callback. + /// If false, then a Session is passed to the callback.

+ ///
+ /// callback object that exposes the session + /// + /// the result object from working with the session + /// + /// If there is any problem accessing the EMS API + public object Execute(ISessionCallback action) + { + return Execute(action, false); + } + + /// Send a message to a EMS destination. The callback gives access to + /// the EMS session and MessageProducer in order to do more complex + /// send operations. + /// + /// callback object that exposes the session/producer pair + /// + /// the result object from working with the session + /// + /// If there is any problem accessing the EMS API + public object Execute(IProducerCallback action) + { + return Execute(new ProducerCreatorCallback(this, action)); + } + + /// Send a message to a EMS destination. The callback gives access to + /// the EMS session and MessageProducer in order to do more complex + /// send operations. + /// + /// delegate that exposes the session/producer pair + /// + /// the result object from working with the session + /// + /// If there is any problem accessing the EMS API + public object Execute(ProducerDelegate del) + { + return Execute(new ProducerCreatorCallback(this, del)); + } + + /// Send a message to the default destination. + ///

This will only work with a default destination specified!

+ ///
+ /// delegate callback to create a message + /// + /// If there is any problem accessing the EMS API + public void SendWithDelegate(MessageCreatorDelegate messageCreatorDelegate) + { + CheckDefaultDestination(); + if (DefaultDestination != null) + { + SendWithDelegate(DefaultDestination, messageCreatorDelegate); + } + else + { + SendWithDelegate(DefaultDestinationName, messageCreatorDelegate); + } + } + + /// Send a message to the specified destination. + /// The MessageCreator callback creates the message given a Session. + /// + /// the destination to send this message to + /// + /// delegate callback to create a message + /// + /// If there is any problem accessing the EMS API + public void SendWithDelegate(Destination destination, MessageCreatorDelegate messageCreatorDelegate) + { + Execute(new SendDestinationCallback(this, destination, messageCreatorDelegate), false); + } + + /// Send a message to the specified destination. + /// The MessageCreator callback creates the message given a Session. + /// + /// the name of the destination to send this message to + /// (to be resolved to an actual destination by a DestinationResolver) + /// + /// delegate callback to create a message + /// + /// If there is any problem accessing the EMS API + public void SendWithDelegate(string destinationName, MessageCreatorDelegate messageCreatorDelegate) + { + Execute(new SendDestinationCallback(this, destinationName, messageCreatorDelegate), false); + } + + /// Send a message to the default destination. + ///

This will only work with a default destination specified!

+ ///
+ /// callback to create a message + /// + /// If there is any problem accessing the EMS API + public void Send(IMessageCreator messageCreator) + { + CheckDefaultDestination(); + if (DefaultDestination != null) + { + Send(DefaultDestination, messageCreator); + } + else + { + Send(DefaultDestinationName, messageCreator); + } + } + + /// Send a message to the specified destination. + /// The MessageCreator callback creates the message given a Session. + /// + /// the destination to send this message to + /// + /// callback to create a message + /// + /// If there is any problem accessing the EMS API + public void Send(Destination destination, IMessageCreator messageCreator) + { + Execute(new SendDestinationCallback(this, destination, messageCreator), false); + } + + /// Send a message to the specified destination. + /// The MessageCreator callback creates the message given a Session. + /// + /// the destination to send this message to + /// + /// callback to create a message + /// + /// If there is any problem accessing the EMS API + public void Send(string destinationName, IMessageCreator messageCreator) + { + Execute(new SendDestinationCallback(this, destinationName, messageCreator), false); + } + + /// Send the given object to the default destination, converting the object + /// to a EMS message with a configured IMessageConverter. + ///

This will only work with a default destination specified!

+ ///
+ /// the object to convert to a message + /// + /// If there is any problem accessing the EMS API + public void ConvertAndSend(object message) + { + CheckDefaultDestination(); + if (DefaultDestination != null) + { + ConvertAndSend(DefaultDestination, message); + } + else + { + ConvertAndSend(DefaultDestinationName, message); + } + } + + /// Send the given object to the specified destination, converting the object + /// to a EMS message with a configured IMessageConverter. + /// + /// the destination to send this message to + /// + /// the object to convert to a message + /// + /// If there is any problem accessing the EMS API + public void ConvertAndSend(Destination destination, object message) + { + CheckMessageConverter(); + Send(destination, new SimpleMessageCreator(this, message)); + } + + /// Send the given object to the specified destination, converting the object + /// to a EMS message with a configured IMessageConverter. + /// + /// the name of the destination to send this message to + /// (to be resolved to an actual destination by a DestinationResolver) + /// + /// the object to convert to a message + /// + /// If there is any problem accessing the EMS API + public void ConvertAndSend(string destinationName, object message) + { + Send(destinationName, new SimpleMessageCreator(this, message)); + } + + /// Send the given object to the default destination, converting the object + /// to a EMS message with a configured IMessageConverter. The IMessagePostProcessor + /// callback allows for modification of the message after conversion. + ///

This will only work with a default destination specified!

+ ///
+ /// the object to convert to a message + /// + /// the callback to modify the message + /// + /// If there is any problem accessing the EMS API + public void ConvertAndSend(object message, IMessagePostProcessor postProcessor) + { + CheckDefaultDestination(); + if (DefaultDestination != null) + { + ConvertAndSend(DefaultDestination, message, postProcessor); + } + else + { + ConvertAndSend(DefaultDestinationName, message, postProcessor); + } + } + + /// Send the given object to the specified destination, converting the object + /// to a EMS message with a configured IMessageConverter. The IMessagePostProcessor + /// callback allows for modification of the message after conversion. + /// + /// the destination to send this message to + /// + /// the object to convert to a message + /// + /// the callback to modify the message + /// + /// If there is any problem accessing the EMS API + public void ConvertAndSend(Destination destination, object message, IMessagePostProcessor postProcessor) + { + CheckMessageConverter(); + Send(destination, new ConvertAndSendMessageCreator(this, message, postProcessor)); + } + + /// Send the given object to the specified destination, converting the object + /// to a EMS message with a configured IMessageConverter. The IMessagePostProcessor + /// callback allows for modification of the message after conversion. + /// + /// the name of the destination to send this message to + /// (to be resolved to an actual destination by a DestinationResolver) + /// + /// the object to convert to a message. + /// + /// the callback to modify the message + /// + /// If there is any problem accessing the EMS API + public void ConvertAndSend(string destinationName, object message, IMessagePostProcessor postProcessor) + { + CheckMessageConverter(); + Send(destinationName, new ConvertAndSendMessageCreator(this, message, postProcessor)); + } + + /// + /// Send the given object to the default destination, converting the object + /// to a EMS message with a configured IMessageConverter. The IMessagePostProcessor + /// callback allows for modification of the message after conversion. + ///

This will only work with a default destination specified!

+ ///
+ /// the object to convert to a message + /// the callback to modify the message + /// If there is any problem accessing the EMS API + public void ConvertAndSendWithDelegate(object message, MessagePostProcessorDelegate postProcessor) + { + //Execute(new SendDestinationCallback(this, destination, messageCreatorDelegate), false); + CheckDefaultDestination(); + if (DefaultDestination != null) + { + ConvertAndSendWithDelegate(DefaultDestination, message, postProcessor); + } + else + { + ConvertAndSendWithDelegate(DefaultDestinationName, message, postProcessor); + } + } + + /// + /// Send the given object to the specified destination, converting the object + /// to a EMS message with a configured IMessageConverter. The IMessagePostProcessor + /// callback allows for modification of the message after conversion. + /// + /// the destination to send this message to + /// the object to convert to a message + /// the callback to modify the message + /// If there is any problem accessing the EMS API + public void ConvertAndSendWithDelegate(Destination destination, object message, + MessagePostProcessorDelegate postProcessor) + { + CheckMessageConverter(); + Send(destination, new ConvertAndSendMessageCreator(this, message, postProcessor)); + } + + /// + /// Send the given object to the specified destination, converting the object + /// to a EMS message with a configured IMessageConverter. The IMessagePostProcessor + /// callback allows for modification of the message after conversion. + /// + /// the name of the destination to send this message to + /// (to be resolved to an actual destination by a DestinationResolver) + /// the object to convert to a message. + /// the callback to modify the message + /// If there is any problem accessing the EMS API + public void ConvertAndSendWithDelegate(string destinationName, object message, + MessagePostProcessorDelegate postProcessor) + { + CheckMessageConverter(); + Send(destinationName, new ConvertAndSendMessageCreator(this, message, postProcessor)); + } + + /// Receive a message synchronously from the default destination, but only + /// wait up to a specified time for delivery. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///

This will only work with a default destination specified!

+ ///
+ /// the message received by the consumer, or null if the timeout expires + /// + /// If there is any problem accessing the EMS API + public Message Receive() + { + CheckDefaultDestination(); + if (DefaultDestination != null) + { + return Receive(DefaultDestination); + } + else + { + return Receive(DefaultDestinationName); + } + } + + /// Receive a message synchronously from the specified destination, but only + /// wait up to a specified time for delivery. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///
+ /// the destination to receive a message from + /// + /// the message received by the consumer, or null if the timeout expires + /// + /// If there is any problem accessing the EMS API + public Message Receive(Destination destination) + { + return Execute(new ReceiveCallback(this, destination)) as Message; + } + + /// Receive a message synchronously from the specified destination, but only + /// wait up to a specified time for delivery. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///
+ /// the name of the destination to send this message to + /// (to be resolved to an actual destination by a DestinationResolver) + /// + /// the message received by the consumer, or null if the timeout expires + /// + /// If there is any problem accessing the EMS API + public Message Receive(string destinationName) + { + return Execute(new ReceiveCallback(this, destinationName)) as Message; + } + + /// Receive a message synchronously from the default destination, but only + /// wait up to a specified time for delivery. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///

This will only work with a default destination specified!

+ ///
+ /// the EMS message selector expression (or null if none). + /// See the EMS specification for a detailed definition of selector expressions. + /// + /// the message received by the consumer, or null if the timeout expires + /// + /// If there is any problem accessing the EMS API + public Message ReceiveSelected(string messageSelector) + { + CheckDefaultDestination(); + if (DefaultDestination != null) + { + return ReceiveSelected(DefaultDestination, messageSelector); + } + else + { + return ReceiveSelected(DefaultDestinationName, messageSelector); + } + } + + /// Receive a message synchronously from the specified destination, but only + /// wait up to a specified time for delivery. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///
+ /// the destination to receive a message from + /// + /// the EMS message selector expression (or null if none). + /// See the EMS specification for a detailed definition of selector expressions. + /// + /// the message received by the consumer, or null if the timeout expires + /// + /// If there is any problem accessing the EMS API + public Message ReceiveSelected(Destination destination, string messageSelector) + { + return Execute(new ReceiveSelectedCallback(this, destination, messageSelector), true) as Message; + } + + /// Receive a message synchronously from the specified destination, but only + /// wait up to a specified time for delivery. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///
+ /// the name of the destination to send this message to + /// (to be resolved to an actual destination by a DestinationResolver) + /// + /// the EMS message selector expression (or null if none). + /// See the EMS specification for a detailed definition of selector expressions. + /// + /// the message received by the consumer, or null if the timeout expires + /// + /// If there is any problem accessing the EMS API + public Message ReceiveSelected(string destinationName, string messageSelector) + { + return Execute(new ReceiveSelectedCallback(this, destinationName, messageSelector), true) as Message; + } + + /// + /// Receive a message. + /// + /// The session to operate on. + /// The destination to receive from. + /// The message selector for this consumer (can be null + /// The Message received, or null if none. + protected virtual Message DoReceive(ISession session, Destination destination, string messageSelector) + { + return DoReceive(session, CreateConsumer(session, destination, messageSelector)); + } + + /// + /// Receive a message. + /// + /// The session to operate on. + /// The consumer to receive with. + /// The Message received, or null if none + protected virtual Message DoReceive(ISession session, IMessageConsumer consumer) + { + try + { + long timeout = ReceiveTimeout; + EmsResourceHolder resourceHolder = + (EmsResourceHolder) TransactionSynchronizationManager.GetResource(ConnectionFactory); + if (resourceHolder != null && resourceHolder.HasTimeout) + { + timeout = Convert.ToInt64(resourceHolder.TimeToLiveInMilliseconds); + } + + Message message = (timeout > 0) + ? consumer.Receive(timeout) + : consumer.Receive(); + if (session.Transacted) + { + // Commit necessary - but avoid commit call is Session transaction is externally coordinated. + if (IsSessionLocallyTransacted(session)) { // Transacted session created by this template -> commit. EmsUtils.CommitIfNecessary(session); } } + else if (IsClientAcknowledge(session)) + { + // Manually acknowledge message, if any. + if (message != null) + { + message.Acknowledge(); + } + } + + return message; + } + finally + { + EmsUtils.CloseMessageConsumer(consumer); + } + } + + /// Receive a message synchronously from the default destination, but only + /// wait up to a specified time for delivery. Convert the message into an + /// object with a configured IMessageConverter. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///

This will only work with a default destination specified!

+ ///
+ /// the message produced for the consumer or null if the timeout expires. + /// + /// If there is any problem accessing the EMS API + public object ReceiveAndConvert() + { + CheckMessageConverter(); + return DoConvertFromMessage(Receive()); + } + + /// Receive a message synchronously from the specified destination, but only + /// wait up to a specified time for delivery. Convert the message into an + /// object with a configured IMessageConverter. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///
+ /// the destination to receive a message from + /// + /// the message produced for the consumer or null if the timeout expires. + /// + /// If there is any problem accessing the EMS API + public object ReceiveAndConvert(Destination destination) + { + CheckMessageConverter(); + return DoConvertFromMessage(Receive(destination)); + } + + /// Receive a message synchronously from the specified destination, but only + /// wait up to a specified time for delivery. Convert the message into an + /// object with a configured IMessageConverter. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///
+ /// the name of the destination to send this message to + /// (to be resolved to an actual destination by a DestinationResolver) + /// + /// the message produced for the consumer or null if the timeout expires. + /// + /// If there is any problem accessing the EMS API + public object ReceiveAndConvert(string destinationName) + { + CheckMessageConverter(); + return DoConvertFromMessage(Receive(destinationName)); + } + + /// Receive a message synchronously from the default destination, but only + /// wait up to a specified time for delivery. Convert the message into an + /// object with a configured IMessageConverter. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///

This will only work with a default destination specified!

+ ///
+ /// the EMS message selector expression (or null if none). + /// See the EMS specification for a detailed definition of selector expressions. + /// + /// the message produced for the consumer or null if the timeout expires. + /// + /// If there is any problem accessing the EMS API + public object ReceiveSelectedAndConvert(string messageSelector) + { + CheckMessageConverter(); + return DoConvertFromMessage(ReceiveSelected(messageSelector)); + } + + /// Receive a message synchronously from the specified destination, but only + /// wait up to a specified time for delivery. Convert the message into an + /// object with a configured IMessageConverter. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///
+ /// the destination to receive a message from + /// + /// the EMS message selector expression (or null if none). + /// See the EMS specification for a detailed definition of selector expressions. + /// + /// the message produced for the consumer or null if the timeout expires. + /// + /// If there is any problem accessing the EMS API + public object ReceiveSelectedAndConvert(Destination destination, string messageSelector) + { + CheckMessageConverter(); + return DoConvertFromMessage(ReceiveSelected(destination, messageSelector)); + } + + /// Receive a message synchronously from the specified destination, but only + /// wait up to a specified time for delivery. Convert the message into an + /// object with a configured IMessageConverter. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///
+ /// the name of the destination to send this message to + /// (to be resolved to an actual destination by a DestinationResolver) + /// + /// the EMS message selector expression (or null if none). + /// See the EMS specification for a detailed definition of selector expressions. + /// + /// the message produced for the consumer or null if the timeout expires. + /// + /// If there is any problem accessing the EMS API + public object ReceiveSelectedAndConvert(string destinationName, string messageSelector) + { + CheckMessageConverter(); + return DoConvertFromMessage(ReceiveSelected(destinationName, messageSelector)); + } + + /// + /// Browses messages in the default EMS queue. The callback gives access to the EMS + /// Session and QueueBrowser in order to browse the queue and react to the contents. + /// + /// The action callback object that exposes the session/browser pair. + /// the result object from working with the session + /// If there is any problem accessing the EMS API + public object Browse(IBrowserCallback action) + { + AssertUtils.ArgumentNotNull(action, "action"); + return BrowseWithDelegate(action.DoInEms); + } + + /// + /// Browses messages in a EMS queue. The callback gives access to the EMS Session + /// and QueueBrowser in order to browse the queue and react to the contents. + /// + /// The queue to browse. + /// The action callback object that exposes the session/browser pair. + /// the result object from working with the session + /// If there is any problem accessing the EMS API + public object Browse(Queue queue, IBrowserCallback action) + { + AssertUtils.ArgumentNotNull(action, "action"); + return BrowseSelectedWithDelegate(queue, null, action.DoInEms); + } + + /// + /// Browses messages in a EMS queue. The callback gives access to the EMS Session + /// and QueueBrowser in order to browse the queue and react to the contents. + /// + /// Name of the queue to browse, + /// (to be resolved to an actual destination by a DestinationResolver) + /// The action callback object that exposes the session/browser pair. + /// If there is any problem accessing the EMS API + public object Browse(string queueName, IBrowserCallback action) + { + AssertUtils.ArgumentNotNull(action, "action"); + return BrowseSelectedWithDelegate(queueName, null, action.DoInEms); + } + + /// + /// Browses messages in a EMS queue. The callback gives access to the EMS Session + /// and QueueBrowser in order to browse the queue and react to the contents. + /// + /// The EMS message selector expression (or null if none). + /// The action callback object that exposes the session/browser pair. + /// If there is any problem accessing the EMS API + public object BrowseSelected(string messageSelector, IBrowserCallback action) + { + AssertUtils.ArgumentNotNull(action, "action"); + return BrowseSelectedWithDelegate(messageSelector, action.DoInEms); + } + + /// + /// Browses messages in a EMS queue. The callback gives access to the EMS Session + /// and QueueBrowser in order to browse the queue and react to the contents. + /// + /// The queue to browse. + /// The EMS message selector expression (or null if none). + /// The action callback object that exposes the session/browser pair. + /// + /// If there is any problem accessing the EMS API + public object BrowseSelected(Queue queue, string messageSelector, IBrowserCallback action) + { + AssertUtils.ArgumentNotNull(action, "action"); + return BrowseSelectedWithDelegate(queue, messageSelector, action.DoInEms); + } + + /// + /// Browses messages in a EMS queue. The callback gives access to the EMS Session + /// and QueueBrowser in order to browse the queue and react to the contents. + /// + /// Name of the queue to browse, + /// (to be resolved to an actual destination by a DestinationResolver) + /// The EMS message selector expression (or null if none). + /// The action callback object that exposes the session/browser pair. + /// + /// If there is any problem accessing the EMS API + public object BrowseSelected(string queueName, string messageSelector, IBrowserCallback action) + { + AssertUtils.ArgumentNotNull(action, "action"); + return BrowseSelectedWithDelegate(queueName, messageSelector, action.DoInEms); + } + + /// + /// Browses messages in the default EMS queue. The callback gives access to the EMS + /// Session and QueueBrowser in order to browse the queue and react to the contents. + /// + /// The action callback delegate that exposes the session/browser pair. + /// the result object from working with the session + public object BrowseWithDelegate(BrowserDelegate action) + { + if (DefaultDestinationName != null) + { + return BrowseSelectedWithDelegate(DefaultDestinationName, action); + } + else + { + Destination destination = DefaultDestination; + if (!(destination is Queue)) + { + throw new InvalidOperationException("defaultDestination does not correspond to a Queue. Check configuration of EmsTemplate."); + } + + return BrowseWithDelegate((Queue) destination, action); + } + } + + /// + /// Browses messages in a EMS queue. The callback gives access to the EMS Session + /// and QueueBrowser in order to browse the queue and react to the contents. + /// + /// The queue to browse. + /// The action callback delegate that exposes the session/browser pair. + /// the result object from working with the session + public object BrowseWithDelegate(Queue queue, BrowserDelegate action) + { + return BrowseSelectedWithDelegate(queue, null, action); + } + + /// + /// Browses messages in a EMS queue. The callback gives access to the EMS Session + /// and QueueBrowser in order to browse the queue and react to the contents. + /// + /// Name of the queue to browse, + /// (to be resolved to an actual destination by a DestinationResolver) + /// The action callback delegate that exposes the session/browser pair. + /// If there is any problem accessing the EMS API + public object BrowseWithDelegate(string queueName, BrowserDelegate action) + { + return BrowseSelectedWithDelegate(queueName, null, action); + } + + /// + /// Browses messages in a EMS queue. The callback gives access to the EMS Session + /// and QueueBrowser in order to browse the queue and react to the contents. + /// + /// The EMS message selector expression (or null if none). + /// The action callback delegate that exposes the session/browser pair. + /// If there is any problem accessing the EMS API + public object BrowseSelectedWithDelegate(string messageSelector, BrowserDelegate action) + { + if (DefaultDestinationName != null) + { + return BrowseSelectedWithDelegate(DefaultDestinationName, messageSelector, action); + } + else + { + Destination destination = DefaultDestination; + if (!(destination is Queue)) + { + throw new InvalidOperationException("defaultDestination does not correspond to a Queue. Check configuration of EmsTemplate."); + } + + return BrowseSelectedWithDelegate((Queue) destination, messageSelector, action); + } + } + + /// + /// Browses messages in a EMS queue. The callback gives access to the EMS Session + /// and QueueBrowser in order to browse the queue and react to the contents. + /// + /// The queue to browse. + /// The EMS message selector expression (or null if none). + /// The action callback delegate that exposes the session/browser pair. + /// + /// If there is any problem accessing the EMS API + public object BrowseSelectedWithDelegate(Queue queue, string messageSelector, BrowserDelegate action) + { + AssertUtils.ArgumentNotNull(action, "action"); + return Execute(session => + { + QueueBrowser browser = CreateBrowser(session, queue, messageSelector); + try + { + return action(session, browser); + } + finally + { + EmsUtils.CloseQueueBrowser(browser); + } + }, true); + } + + /// + /// Browses messages in a EMS queue. The callback gives access to the EMS Session + /// and QueueBrowser in order to browse the queue and react to the contents. + /// + /// Name of the queue to browse, + /// (to be resolved to an actual destination by a DestinationResolver) + /// The EMS message selector expression (or null if none). + /// The action callback delegate that exposes the session/browser pair. + /// + /// If there is any problem accessing the EMS API + public object BrowseSelectedWithDelegate(string queueName, string messageSelector, BrowserDelegate action) + { + AssertUtils.ArgumentNotNull(action, "action"); + return Execute(session => + { + Queue queue = (Queue) DestinationResolver.ResolveDestinationName(session, queueName, false); + QueueBrowser browser = CreateBrowser(session, queue, messageSelector); + try + { + return action(session, browser); + } + finally + { + EmsUtils.CloseQueueBrowser(browser); + } + }, true); + } + + #endregion + + /// + /// Creates the queue browser. + /// + /// The session. + /// The queue. + /// The selector. + /// A new queue browser + protected virtual QueueBrowser CreateBrowser(ISession session, Queue queue, string selector) + { + return session.CreateBrowser(queue, selector); + } + + #region Supporting Internal Classes + + /// + /// ResourceFactory implementation that delegates to this template's callback methods. + /// + private class EmsTemplateResourceFactory : ConnectionFactoryUtils.ResourceFactory + { + private EmsTemplate enclosingTemplateInstance; + + public EmsTemplateResourceFactory(EmsTemplate enclosingInstance) + { + InitBlock(enclosingInstance); + } + + private void InitBlock(EmsTemplate enclosingInstance) + { + enclosingTemplateInstance = enclosingInstance; + } + + public EmsTemplate EnclosingInstance + { + get { return enclosingTemplateInstance; } + } + + public virtual IConnection GetConnection(EmsResourceHolder holder) + { + return EnclosingInstance.GetConnection(holder); + } + + public virtual ISession GetSession(EmsResourceHolder holder) + { + return EnclosingInstance.GetSession(holder); + } + + public virtual IConnection CreateConnection() + { + return EnclosingInstance.CreateConnection(); + } + + public virtual ISession CreateSession(IConnection con) + { + return EnclosingInstance.CreateSession(con); + } + + public bool SynchedLocalTransactionAllowed + { + get { return EnclosingInstance.SessionTransacted; } + } + } + + private class ProducerCreatorCallback : ISessionCallback + { + private EmsTemplate jmsTemplate; + private IProducerCallback producerCallback; + private ProducerDelegate producerDelegate; + + public ProducerCreatorCallback(EmsTemplate jmsTemplate, IProducerCallback producerCallback) + { + this.jmsTemplate = jmsTemplate; + this.producerCallback = producerCallback; + } + + public ProducerCreatorCallback(EmsTemplate jmsTemplate, ProducerDelegate producerDelegate) + { + this.jmsTemplate = jmsTemplate; + this.producerDelegate = producerDelegate; + } + + public object DoInEms(ISession session) + { + IMessageProducer producer = jmsTemplate.CreateProducer(session, null); + try + { + if (producerCallback != null) + { + return producerCallback.DoInEms(session, producer); + } + else + { + return producerDelegate(session, producer); + } + } finally { EmsUtils.CloseMessageProducer(producer); } } - - - /// Actually send the given EMS message. - /// the EMS MessageProducer to send with - /// - /// the EMS Message to send - /// - /// If there is any problem accessing the EMS API - protected virtual void DoSend(IMessageProducer producer, Message message) - { - if (ExplicitQosEnabled) - { - producer.Send(message, DeliveryMode, Priority, TimeToLive); - } - else - { - producer.Send(message); - } - } - - - #endregion - - #region IEmsOperations Implementation - - /// - /// Execute the action specified by the given action object within - /// a EMS Session. - /// - /// delegate that exposes the session - /// - /// the result object from working with the session - /// - /// - /// Note that the value of PubSubDomain affects the behavior of this method. - /// If PubSubDomain equals true, then a Session is passed to the callback. - /// If false, then a Session is passed to the callback.b - /// - /// If there is any problem accessing the EMS API - public object Execute(SessionDelegate del) - { - return Execute(new ExecuteSessionCallbackUsingDelegate(del)); - } - - /// Execute the action specified by the given action object within - /// a EMS Session. - ///

Note: The value of PubSubDomain affects the behavior of this method. - /// If PubSubDomain equals true, then a Session is passed to the callback. - /// If false, then a Session is passed to the callback.

- ///
- /// callback object that exposes the session - /// - /// the result object from working with the session - /// - /// If there is any problem accessing the EMS API - public object Execute(ISessionCallback action) - { - return Execute(action, false); - } - - /// Send a message to a EMS destination. The callback gives access to - /// the EMS session and MessageProducer in order to do more complex - /// send operations. - /// - /// callback object that exposes the session/producer pair - /// - /// the result object from working with the session - /// - /// If there is any problem accessing the EMS API - public object Execute(IProducerCallback action) - { - return Execute(new ProducerCreatorCallback(this, action)); - } - - /// Send a message to a EMS destination. The callback gives access to - /// the EMS session and MessageProducer in order to do more complex - /// send operations. - /// - /// delegate that exposes the session/producer pair - /// - /// the result object from working with the session - /// - /// If there is any problem accessing the EMS API - public object Execute(ProducerDelegate del) - { - return Execute(new ProducerCreatorCallback(this, del)); - } - - /// Send a message to the default destination. - ///

This will only work with a default destination specified!

- ///
- /// delegate callback to create a message - /// - /// If there is any problem accessing the EMS API - public void SendWithDelegate(MessageCreatorDelegate messageCreatorDelegate) - { - CheckDefaultDestination(); - if (DefaultDestination != null) - { - SendWithDelegate(DefaultDestination, messageCreatorDelegate); - } - else - { - SendWithDelegate(DefaultDestinationName, messageCreatorDelegate); - } - } - - /// Send a message to the specified destination. - /// The MessageCreator callback creates the message given a Session. - /// - /// the destination to send this message to - /// - /// delegate callback to create a message - /// - /// If there is any problem accessing the EMS API - public void SendWithDelegate(Destination destination, MessageCreatorDelegate messageCreatorDelegate) - { - Execute(new SendDestinationCallback(this, destination, messageCreatorDelegate), false); - } - - /// Send a message to the specified destination. - /// The MessageCreator callback creates the message given a Session. - /// - /// the name of the destination to send this message to - /// (to be resolved to an actual destination by a DestinationResolver) - /// - /// delegate callback to create a message - /// - /// If there is any problem accessing the EMS API - public void SendWithDelegate(string destinationName, MessageCreatorDelegate messageCreatorDelegate) - { - Execute(new SendDestinationCallback(this, destinationName, messageCreatorDelegate), false); - } - - /// Send a message to the default destination. - ///

This will only work with a default destination specified!

- ///
- /// callback to create a message - /// - /// If there is any problem accessing the EMS API - public void Send(IMessageCreator messageCreator) - { - CheckDefaultDestination(); - if (DefaultDestination != null) - { - Send(DefaultDestination, messageCreator); - } - else - { - Send(DefaultDestinationName, messageCreator); - } - } - - /// Send a message to the specified destination. - /// The MessageCreator callback creates the message given a Session. - /// - /// the destination to send this message to - /// - /// callback to create a message - /// - /// If there is any problem accessing the EMS API - public void Send(Destination destination, IMessageCreator messageCreator) - { - - Execute(new SendDestinationCallback(this, destination, messageCreator), false); - } - - /// Send a message to the specified destination. - /// The MessageCreator callback creates the message given a Session. - /// - /// the destination to send this message to - /// - /// callback to create a message - /// - /// If there is any problem accessing the EMS API - public void Send(string destinationName, IMessageCreator messageCreator) - { - Execute(new SendDestinationCallback(this, destinationName, messageCreator), false); - } - /// Send the given object to the default destination, converting the object - /// to a EMS message with a configured IMessageConverter. - ///

This will only work with a default destination specified!

- ///
- /// the object to convert to a message - /// - /// If there is any problem accessing the EMS API - public void ConvertAndSend(object message) - { - CheckDefaultDestination(); - if (DefaultDestination != null) - { - ConvertAndSend(DefaultDestination, message); - } - else - { - ConvertAndSend(DefaultDestinationName, message); - } - } - - /// Send the given object to the specified destination, converting the object - /// to a EMS message with a configured IMessageConverter. - /// - /// the destination to send this message to - /// - /// the object to convert to a message - /// - /// If there is any problem accessing the EMS API - public void ConvertAndSend(Destination destination, object message) - { - CheckMessageConverter(); - Send(destination, new SimpleMessageCreator(this, message)); - } - - /// Send the given object to the specified destination, converting the object - /// to a EMS message with a configured IMessageConverter. - /// - /// the name of the destination to send this message to - /// (to be resolved to an actual destination by a DestinationResolver) - /// - /// the object to convert to a message - /// - /// If there is any problem accessing the EMS API - public void ConvertAndSend(string destinationName, object message) - { - Send(destinationName, new SimpleMessageCreator(this, message)); - } - - /// Send the given object to the default destination, converting the object - /// to a EMS message with a configured IMessageConverter. The IMessagePostProcessor - /// callback allows for modification of the message after conversion. - ///

This will only work with a default destination specified!

- ///
- /// the object to convert to a message - /// - /// the callback to modify the message - /// - /// If there is any problem accessing the EMS API - public void ConvertAndSend(object message, IMessagePostProcessor postProcessor) - { - CheckDefaultDestination(); - if (DefaultDestination != null) - { - ConvertAndSend(DefaultDestination, message, postProcessor); - } - else - { - ConvertAndSend(DefaultDestinationName, message, postProcessor); - } - } - - /// Send the given object to the specified destination, converting the object - /// to a EMS message with a configured IMessageConverter. The IMessagePostProcessor - /// callback allows for modification of the message after conversion. - /// - /// the destination to send this message to - /// - /// the object to convert to a message - /// - /// the callback to modify the message - /// - /// If there is any problem accessing the EMS API - public void ConvertAndSend(Destination destination, object message, IMessagePostProcessor postProcessor) - { - CheckMessageConverter(); - Send(destination, new ConvertAndSendMessageCreator(this, message, postProcessor)); - - } - - /// Send the given object to the specified destination, converting the object - /// to a EMS message with a configured IMessageConverter. The IMessagePostProcessor - /// callback allows for modification of the message after conversion. - /// - /// the name of the destination to send this message to - /// (to be resolved to an actual destination by a DestinationResolver) - /// - /// the object to convert to a message. - /// - /// the callback to modify the message - /// - /// If there is any problem accessing the EMS API - public void ConvertAndSend(string destinationName, object message, IMessagePostProcessor postProcessor) - { - CheckMessageConverter(); - Send(destinationName, new ConvertAndSendMessageCreator(this, message, postProcessor)); - } - /// - /// Send the given object to the default destination, converting the object - /// to a EMS message with a configured IMessageConverter. The IMessagePostProcessor - /// callback allows for modification of the message after conversion. - ///

This will only work with a default destination specified!

- ///
- /// the object to convert to a message - /// the callback to modify the message - /// If there is any problem accessing the EMS API - public void ConvertAndSendWithDelegate(object message, MessagePostProcessorDelegate postProcessor) - { - //Execute(new SendDestinationCallback(this, destination, messageCreatorDelegate), false); - CheckDefaultDestination(); - if (DefaultDestination != null) - { - ConvertAndSendWithDelegate(DefaultDestination, message, postProcessor); - } - else - { - ConvertAndSendWithDelegate(DefaultDestinationName, message, postProcessor); - } - } - - /// - /// Send the given object to the specified destination, converting the object - /// to a EMS message with a configured IMessageConverter. The IMessagePostProcessor - /// callback allows for modification of the message after conversion. - /// - /// the destination to send this message to - /// the object to convert to a message - /// the callback to modify the message - /// If there is any problem accessing the EMS API - public void ConvertAndSendWithDelegate(Destination destination, object message, - MessagePostProcessorDelegate postProcessor) - { - CheckMessageConverter(); - Send(destination, new ConvertAndSendMessageCreator(this, message, postProcessor)); - } - - /// - /// Send the given object to the specified destination, converting the object - /// to a EMS message with a configured IMessageConverter. The IMessagePostProcessor - /// callback allows for modification of the message after conversion. - /// - /// the name of the destination to send this message to - /// (to be resolved to an actual destination by a DestinationResolver) - /// the object to convert to a message. - /// the callback to modify the message - /// If there is any problem accessing the EMS API - public void ConvertAndSendWithDelegate(string destinationName, object message, - MessagePostProcessorDelegate postProcessor) - { - CheckMessageConverter(); - Send(destinationName, new ConvertAndSendMessageCreator(this, message, postProcessor)); - - } - - /// Receive a message synchronously from the default destination, but only - /// wait up to a specified time for delivery. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///

This will only work with a default destination specified!

- ///
- /// the message received by the consumer, or null if the timeout expires - /// - /// If there is any problem accessing the EMS API - public Message Receive() - { - CheckDefaultDestination(); - if (DefaultDestination != null) - { - return Receive(DefaultDestination); - } - else - { - return Receive(DefaultDestinationName); - } - } - - /// Receive a message synchronously from the specified destination, but only - /// wait up to a specified time for delivery. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///
- /// the destination to receive a message from - /// - /// the message received by the consumer, or null if the timeout expires - /// - /// If there is any problem accessing the EMS API - public Message Receive(Destination destination) - { - return Execute(new ReceiveCallback(this, destination)) as Message; - } - - - /// Receive a message synchronously from the specified destination, but only - /// wait up to a specified time for delivery. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///
- /// the name of the destination to send this message to - /// (to be resolved to an actual destination by a DestinationResolver) - /// - /// the message received by the consumer, or null if the timeout expires - /// - /// If there is any problem accessing the EMS API - public Message Receive(string destinationName) - { - return Execute(new ReceiveCallback(this, destinationName)) as Message; - } - - /// Receive a message synchronously from the default destination, but only - /// wait up to a specified time for delivery. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///

This will only work with a default destination specified!

- ///
- /// the EMS message selector expression (or null if none). - /// See the EMS specification for a detailed definition of selector expressions. - /// - /// the message received by the consumer, or null if the timeout expires - /// - /// If there is any problem accessing the EMS API - public Message ReceiveSelected(string messageSelector) - { - CheckDefaultDestination(); - if (DefaultDestination!= null) - { - return ReceiveSelected(DefaultDestination, messageSelector); - } - else - { - return ReceiveSelected(DefaultDestinationName, messageSelector); - } - } - - /// Receive a message synchronously from the specified destination, but only - /// wait up to a specified time for delivery. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///
- /// the destination to receive a message from - /// - /// the EMS message selector expression (or null if none). - /// See the EMS specification for a detailed definition of selector expressions. - /// - /// the message received by the consumer, or null if the timeout expires - /// - /// If there is any problem accessing the EMS API - public Message ReceiveSelected(Destination destination, string messageSelector) - { - return Execute(new ReceiveSelectedCallback(this, destination, messageSelector), true) as Message; - } - - /// Receive a message synchronously from the specified destination, but only - /// wait up to a specified time for delivery. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///
- /// the name of the destination to send this message to - /// (to be resolved to an actual destination by a DestinationResolver) - /// - /// the EMS message selector expression (or null if none). - /// See the EMS specification for a detailed definition of selector expressions. - /// - /// the message received by the consumer, or null if the timeout expires - /// - /// If there is any problem accessing the EMS API - public Message ReceiveSelected(string destinationName, string messageSelector) - { - return Execute(new ReceiveSelectedCallback(this, destinationName, messageSelector), true) as Message; - - } - - /// - /// Receive a message. - /// - /// The session to operate on. - /// The destination to receive from. - /// The message selector for this consumer (can be null - /// The Message received, or null if none. - protected virtual Message DoReceive(ISession session, Destination destination, string messageSelector) - { - return DoReceive(session, CreateConsumer(session, destination, messageSelector)); - } - - /// - /// Receive a message. - /// - /// The session to operate on. - /// The consumer to receive with. - /// The Message received, or null if none - protected virtual Message DoReceive(ISession session, IMessageConsumer consumer) - { - try - { - long timeout = ReceiveTimeout; - EmsResourceHolder resourceHolder = - (EmsResourceHolder)TransactionSynchronizationManager.GetResource(ConnectionFactory); - if (resourceHolder != null && resourceHolder.HasTimeout) - { - timeout = Convert.ToInt64(resourceHolder.TimeToLiveInMilliseconds); - } - Message message = (timeout > 0) - ? consumer.Receive(timeout) - : consumer.Receive(); - if (session.Transacted) - { - // Commit necessary - but avoid commit call is Session transaction is externally coordinated. - if (IsSessionLocallyTransacted(session)) - { - // Transacted session created by this template -> commit. - EmsUtils.CommitIfNecessary(session); - } - } - else if (IsClientAcknowledge(session)) - { - // Manually acknowledge message, if any. - if (message != null) - { - message.Acknowledge(); - } - } - return message; - } - finally - { - EmsUtils.CloseMessageConsumer(consumer); - } - } - - - /// Receive a message synchronously from the default destination, but only - /// wait up to a specified time for delivery. Convert the message into an - /// object with a configured IMessageConverter. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///

This will only work with a default destination specified!

- ///
- /// the message produced for the consumer or null if the timeout expires. - /// - /// If there is any problem accessing the EMS API - public object ReceiveAndConvert() - { - CheckMessageConverter(); - return DoConvertFromMessage(Receive()); - } - - /// Receive a message synchronously from the specified destination, but only - /// wait up to a specified time for delivery. Convert the message into an - /// object with a configured IMessageConverter. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///
- /// the destination to receive a message from - /// - /// the message produced for the consumer or null if the timeout expires. - /// - /// If there is any problem accessing the EMS API - public object ReceiveAndConvert(Destination destination) - { - CheckMessageConverter(); - return DoConvertFromMessage(Receive(destination)); - } - - - /// Receive a message synchronously from the specified destination, but only - /// wait up to a specified time for delivery. Convert the message into an - /// object with a configured IMessageConverter. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///
- /// the name of the destination to send this message to - /// (to be resolved to an actual destination by a DestinationResolver) - /// - /// the message produced for the consumer or null if the timeout expires. - /// - /// If there is any problem accessing the EMS API - public object ReceiveAndConvert(string destinationName) - { - CheckMessageConverter(); - return DoConvertFromMessage(Receive(destinationName)); - } - - /// Receive a message synchronously from the default destination, but only - /// wait up to a specified time for delivery. Convert the message into an - /// object with a configured IMessageConverter. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///

This will only work with a default destination specified!

- ///
- /// the EMS message selector expression (or null if none). - /// See the EMS specification for a detailed definition of selector expressions. - /// - /// the message produced for the consumer or null if the timeout expires. - /// - /// If there is any problem accessing the EMS API - public object ReceiveSelectedAndConvert(string messageSelector) - { - CheckMessageConverter(); - return DoConvertFromMessage(ReceiveSelected(messageSelector)); - } - - /// Receive a message synchronously from the specified destination, but only - /// wait up to a specified time for delivery. Convert the message into an - /// object with a configured IMessageConverter. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///
- /// the destination to receive a message from - /// - /// the EMS message selector expression (or null if none). - /// See the EMS specification for a detailed definition of selector expressions. - /// - /// the message produced for the consumer or null if the timeout expires. - /// - /// If there is any problem accessing the EMS API - public object ReceiveSelectedAndConvert(Destination destination, string messageSelector) - { - CheckMessageConverter(); - return DoConvertFromMessage(ReceiveSelected(destination, messageSelector)); - } - - /// Receive a message synchronously from the specified destination, but only - /// wait up to a specified time for delivery. Convert the message into an - /// object with a configured IMessageConverter. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///
- /// the name of the destination to send this message to - /// (to be resolved to an actual destination by a DestinationResolver) - /// - /// the EMS message selector expression (or null if none). - /// See the EMS specification for a detailed definition of selector expressions. - /// - /// the message produced for the consumer or null if the timeout expires. - /// - /// If there is any problem accessing the EMS API - public object ReceiveSelectedAndConvert(string destinationName, string messageSelector) - { - CheckMessageConverter(); - return DoConvertFromMessage(ReceiveSelected(destinationName, messageSelector)); - } - - - /// - /// Browses messages in the default EMS queue. The callback gives access to the EMS - /// Session and QueueBrowser in order to browse the queue and react to the contents. - /// - /// The action callback object that exposes the session/browser pair. - /// the result object from working with the session - /// If there is any problem accessing the EMS API - public object Browse(IBrowserCallback action) - { - AssertUtils.ArgumentNotNull(action, "action"); - return BrowseWithDelegate(action.DoInEms); - } - - /// - /// Browses messages in a EMS queue. The callback gives access to the EMS Session - /// and QueueBrowser in order to browse the queue and react to the contents. - /// - /// The queue to browse. - /// The action callback object that exposes the session/browser pair. - /// the result object from working with the session - /// If there is any problem accessing the EMS API - public object Browse(Queue queue, IBrowserCallback action) - { - AssertUtils.ArgumentNotNull(action, "action"); - return BrowseSelectedWithDelegate(queue, null, action.DoInEms); - } - - /// - /// Browses messages in a EMS queue. The callback gives access to the EMS Session - /// and QueueBrowser in order to browse the queue and react to the contents. - /// - /// Name of the queue to browse, - /// (to be resolved to an actual destination by a DestinationResolver) - /// The action callback object that exposes the session/browser pair. - /// If there is any problem accessing the EMS API - public object Browse(string queueName, IBrowserCallback action) - { - AssertUtils.ArgumentNotNull(action, "action"); - return BrowseSelectedWithDelegate(queueName, null, action.DoInEms); - } - - /// - /// Browses messages in a EMS queue. The callback gives access to the EMS Session - /// and QueueBrowser in order to browse the queue and react to the contents. - /// - /// The EMS message selector expression (or null if none). - /// The action callback object that exposes the session/browser pair. - /// If there is any problem accessing the EMS API - public object BrowseSelected(string messageSelector, IBrowserCallback action) - { - AssertUtils.ArgumentNotNull(action, "action"); - return BrowseSelectedWithDelegate(messageSelector, action.DoInEms); - } - - /// - /// Browses messages in a EMS queue. The callback gives access to the EMS Session - /// and QueueBrowser in order to browse the queue and react to the contents. - /// - /// The queue to browse. - /// The EMS message selector expression (or null if none). - /// The action callback object that exposes the session/browser pair. - /// - /// If there is any problem accessing the EMS API - public object BrowseSelected(Queue queue, string messageSelector, IBrowserCallback action) - { - AssertUtils.ArgumentNotNull(action, "action"); - return BrowseSelectedWithDelegate(queue, messageSelector, action.DoInEms); - } - - - /// - /// Browses messages in a EMS queue. The callback gives access to the EMS Session - /// and QueueBrowser in order to browse the queue and react to the contents. - /// - /// Name of the queue to browse, - /// (to be resolved to an actual destination by a DestinationResolver) - /// The EMS message selector expression (or null if none). - /// The action callback object that exposes the session/browser pair. - /// - /// If there is any problem accessing the EMS API - public object BrowseSelected(string queueName, string messageSelector, IBrowserCallback action) - { - AssertUtils.ArgumentNotNull(action, "action"); - return BrowseSelectedWithDelegate(queueName, messageSelector, action.DoInEms); - } - - - - /// - /// Browses messages in the default EMS queue. The callback gives access to the EMS - /// Session and QueueBrowser in order to browse the queue and react to the contents. - /// - /// The action callback delegate that exposes the session/browser pair. - /// the result object from working with the session - public object BrowseWithDelegate(BrowserDelegate action) - { - if (DefaultDestinationName != null) - { - return BrowseSelectedWithDelegate(DefaultDestinationName, action); - } - else - { - Destination destination = DefaultDestination; - if (!(destination is Queue)) - { - throw new InvalidOperationException("defaultDestination does not correspond to a Queue. Check configuration of EmsTemplate."); - } - return BrowseWithDelegate((Queue)destination, action); - } - } - - /// - /// Browses messages in a EMS queue. The callback gives access to the EMS Session - /// and QueueBrowser in order to browse the queue and react to the contents. - /// - /// The queue to browse. - /// The action callback delegate that exposes the session/browser pair. - /// the result object from working with the session - public object BrowseWithDelegate(Queue queue, BrowserDelegate action) - { - return BrowseSelectedWithDelegate(queue, null, action); - } - - /// - /// Browses messages in a EMS queue. The callback gives access to the EMS Session - /// and QueueBrowser in order to browse the queue and react to the contents. - /// - /// Name of the queue to browse, - /// (to be resolved to an actual destination by a DestinationResolver) - /// The action callback delegate that exposes the session/browser pair. - /// If there is any problem accessing the EMS API - public object BrowseWithDelegate(string queueName, BrowserDelegate action) - { - return BrowseSelectedWithDelegate(queueName, null, action); - } - - /// - /// Browses messages in a EMS queue. The callback gives access to the EMS Session - /// and QueueBrowser in order to browse the queue and react to the contents. - /// - /// The EMS message selector expression (or null if none). - /// The action callback delegate that exposes the session/browser pair. - /// If there is any problem accessing the EMS API - public object BrowseSelectedWithDelegate(string messageSelector, BrowserDelegate action) - { - if (DefaultDestinationName != null) - { - return BrowseSelectedWithDelegate(DefaultDestinationName, messageSelector, action); - } - else - { - Destination destination = DefaultDestination; - if (!(destination is Queue)) - { - throw new InvalidOperationException("defaultDestination does not correspond to a Queue. Check configuration of EmsTemplate."); - } - return BrowseSelectedWithDelegate((Queue)destination, messageSelector, action); - } - } - - /// - /// Browses messages in a EMS queue. The callback gives access to the EMS Session - /// and QueueBrowser in order to browse the queue and react to the contents. - /// - /// The queue to browse. - /// The EMS message selector expression (or null if none). - /// The action callback delegate that exposes the session/browser pair. - /// - /// If there is any problem accessing the EMS API - public object BrowseSelectedWithDelegate(Queue queue, string messageSelector, BrowserDelegate action) - { - AssertUtils.ArgumentNotNull(action, "action"); - return Execute(session => - { - QueueBrowser browser = CreateBrowser(session, queue, messageSelector); - try - { - return action(session, browser); - } - finally - { - EmsUtils.CloseQueueBrowser(browser); - } - }, true); - } - - /// - /// Browses messages in a EMS queue. The callback gives access to the EMS Session - /// and QueueBrowser in order to browse the queue and react to the contents. - /// - /// Name of the queue to browse, - /// (to be resolved to an actual destination by a DestinationResolver) - /// The EMS message selector expression (or null if none). - /// The action callback delegate that exposes the session/browser pair. - /// - /// If there is any problem accessing the EMS API - public object BrowseSelectedWithDelegate(string queueName, string messageSelector, BrowserDelegate action) - { - AssertUtils.ArgumentNotNull(action, "action"); - return Execute(session => - { - Queue queue = (Queue)DestinationResolver.ResolveDestinationName(session, queueName, false); - QueueBrowser browser = CreateBrowser(session, queue, messageSelector); - try - { - return action(session, browser); - } - finally - { - EmsUtils.CloseQueueBrowser(browser); - } - }, true); - } - - #endregion - - /// - /// Creates the queue browser. - /// - /// The session. - /// The queue. - /// The selector. - /// A new queue browser - protected virtual QueueBrowser CreateBrowser(ISession session, Queue queue, string selector) - { - return session.CreateBrowser(queue, selector); - } - - - #region Supporting Internal Classes - - /// - /// ResourceFactory implementation that delegates to this template's callback methods. - /// - private class EmsTemplateResourceFactory : ConnectionFactoryUtils.ResourceFactory - { - private EmsTemplate enclosingTemplateInstance; - - public EmsTemplateResourceFactory(EmsTemplate enclosingInstance) - { - InitBlock(enclosingInstance); - } - - private void InitBlock(EmsTemplate enclosingInstance) - { - enclosingTemplateInstance = enclosingInstance; - } - - public EmsTemplate EnclosingInstance - { - get { return enclosingTemplateInstance; } - } - - public virtual IConnection GetConnection(EmsResourceHolder holder) - { - return EnclosingInstance.GetConnection(holder); - } - - public virtual ISession GetSession(EmsResourceHolder holder) - { - return EnclosingInstance.GetSession(holder); - } - - public virtual IConnection CreateConnection() - { - return EnclosingInstance.CreateConnection(); - } - - public virtual ISession CreateSession(IConnection con) - { - return EnclosingInstance.CreateSession(con); - } - - public bool SynchedLocalTransactionAllowed - { - get { return EnclosingInstance.SessionTransacted; } - } - } - - private class ProducerCreatorCallback : ISessionCallback - { - private EmsTemplate jmsTemplate; - private IProducerCallback producerCallback; - private ProducerDelegate producerDelegate; - - public ProducerCreatorCallback(EmsTemplate jmsTemplate, IProducerCallback producerCallback) - { - this.jmsTemplate = jmsTemplate; - this.producerCallback = producerCallback; - } - - public ProducerCreatorCallback(EmsTemplate jmsTemplate, ProducerDelegate producerDelegate) - { - this.jmsTemplate = jmsTemplate; - this.producerDelegate = producerDelegate; - } - - - public object DoInEms(ISession session) - { - IMessageProducer producer = jmsTemplate.CreateProducer(session, null); - try - { - if (producerCallback != null) - { - return producerCallback.DoInEms(session, producer); - } - else - { - return producerDelegate(session, producer); - } - } - finally - { - EmsUtils.CloseMessageProducer(producer); - } - - } - } - - private class ReceiveCallback : ISessionCallback - { - private EmsTemplate jmsTemplate; - private Destination destination; - private string destinationName; - - - public ReceiveCallback(EmsTemplate jmsTemplate, string destinationName) - { - this.jmsTemplate = jmsTemplate; - this.destinationName = destinationName; - } - - public ReceiveCallback(EmsTemplate jmsTemplate, Destination destination) - { - this.jmsTemplate = jmsTemplate; - this.destination = destination; - } - - public object DoInEms(ISession session) - { - if (destination != null) - { - return jmsTemplate.DoReceive(session, destination, null); - } - else - { - return jmsTemplate.DoReceive(session, - jmsTemplate.ResolveDestinationName(session, destinationName), - null); - } - - } - } - - private class ConvertAndSendMessageCreator : IMessageCreator - { - private EmsTemplate jmsTemplate; - private object objectToConvert; - private IMessagePostProcessor messagePostProcessor; - private MessagePostProcessorDelegate messagePostProcessorDelegate; - - public ConvertAndSendMessageCreator(EmsTemplate jmsTemplate, object message, IMessagePostProcessor messagePostProcessor) - { - this.jmsTemplate = jmsTemplate; - objectToConvert = message; - this.messagePostProcessor = messagePostProcessor; - } - - public ConvertAndSendMessageCreator(EmsTemplate jmsTemplate, object message, MessagePostProcessorDelegate messagePostProcessorDelegate) - { - this.jmsTemplate = jmsTemplate; - objectToConvert = message; - this.messagePostProcessorDelegate = messagePostProcessorDelegate; - } - - public Message CreateMessage(ISession session) - { - Message msg = jmsTemplate.MessageConverter.ToMessage(objectToConvert, session); - if (messagePostProcessor != null) - { - return messagePostProcessor.PostProcessMessage(msg); - } - else - { - return messagePostProcessorDelegate(msg); - } - } - } - - private class ReceiveSelectedCallback : ISessionCallback - { - private EmsTemplate jmsTemplate; - private string messageSelector; - private string destinationName; - private Destination destination; - - public ReceiveSelectedCallback(EmsTemplate jmsTemplate, - Destination destination, - string messageSelector) - { - this.jmsTemplate = jmsTemplate; - this.destination = destination; - this.messageSelector = messageSelector; - } - public ReceiveSelectedCallback(EmsTemplate jmsTemplate, - string destinationName, - string messageSelector) - { - this.jmsTemplate = jmsTemplate; - this.destinationName = destinationName; - this.messageSelector = messageSelector; - } - - public object DoInEms(ISession session) - { - if (destination != null) - { - return jmsTemplate.DoReceive(session, destination, messageSelector); - } - else - { - return jmsTemplate.DoReceive(session, - jmsTemplate.ResolveDestinationName(session, destinationName), - messageSelector); - } - - } - - } - - private class ExecuteSessionCallbackUsingDelegate : ISessionCallback - { - private SessionDelegate del; - public ExecuteSessionCallbackUsingDelegate(SessionDelegate del) - { - this.del = del; - } - - public object DoInEms(ISession session) - { - return del(session); - } - } - - #endregion } - /// - /// This is a TIBCO specific class so that we can reuse connections, session, and - /// message producers instead of creating/destroying them on each operation. - /// + private class ReceiveCallback : ISessionCallback + { + private EmsTemplate jmsTemplate; + private Destination destination; + private string destinationName; + + public ReceiveCallback(EmsTemplate jmsTemplate, string destinationName) + { + this.jmsTemplate = jmsTemplate; + this.destinationName = destinationName; + } + + public ReceiveCallback(EmsTemplate jmsTemplate, Destination destination) + { + this.jmsTemplate = jmsTemplate; + this.destination = destination; + } + + public object DoInEms(ISession session) + { + if (destination != null) + { + return jmsTemplate.DoReceive(session, destination, null); + } + else + { + return jmsTemplate.DoReceive(session, + jmsTemplate.ResolveDestinationName(session, destinationName), + null); + } + } + } + + private class ConvertAndSendMessageCreator : IMessageCreator + { + private EmsTemplate jmsTemplate; + private object objectToConvert; + private IMessagePostProcessor messagePostProcessor; + private MessagePostProcessorDelegate messagePostProcessorDelegate; + + public ConvertAndSendMessageCreator(EmsTemplate jmsTemplate, object message, IMessagePostProcessor messagePostProcessor) + { + this.jmsTemplate = jmsTemplate; + objectToConvert = message; + this.messagePostProcessor = messagePostProcessor; + } + + public ConvertAndSendMessageCreator(EmsTemplate jmsTemplate, object message, MessagePostProcessorDelegate messagePostProcessorDelegate) + { + this.jmsTemplate = jmsTemplate; + objectToConvert = message; + this.messagePostProcessorDelegate = messagePostProcessorDelegate; + } + + public Message CreateMessage(ISession session) + { + Message msg = jmsTemplate.MessageConverter.ToMessage(objectToConvert, session); + if (messagePostProcessor != null) + { + return messagePostProcessor.PostProcessMessage(msg); + } + else + { + return messagePostProcessorDelegate(msg); + } + } + } + + private class ReceiveSelectedCallback : ISessionCallback + { + private EmsTemplate jmsTemplate; + private string messageSelector; + private string destinationName; + private Destination destination; + + public ReceiveSelectedCallback(EmsTemplate jmsTemplate, + Destination destination, + string messageSelector) + { + this.jmsTemplate = jmsTemplate; + this.destination = destination; + this.messageSelector = messageSelector; + } + + public ReceiveSelectedCallback(EmsTemplate jmsTemplate, + string destinationName, + string messageSelector) + { + this.jmsTemplate = jmsTemplate; + this.destinationName = destinationName; + this.messageSelector = messageSelector; + } + + public object DoInEms(ISession session) + { + if (destination != null) + { + return jmsTemplate.DoReceive(session, destination, messageSelector); + } + else + { + return jmsTemplate.DoReceive(session, + jmsTemplate.ResolveDestinationName(session, destinationName), + messageSelector); + } + } + } + + private class ExecuteSessionCallbackUsingDelegate : ISessionCallback + { + private SessionDelegate del; + + public ExecuteSessionCallbackUsingDelegate(SessionDelegate del) + { + this.del = del; + } + + public object DoInEms(ISession session) + { + return del(session); + } + } + + #endregion +} + +/// +/// This is a TIBCO specific class so that we can reuse connections, session, and +/// message producers instead of creating/destroying them on each operation. +/// /* internal class EmsResources { private IConnection connection; @@ -1819,81 +1805,75 @@ namespace Spring.Messaging.Ems.Core set { cachedProducers = value; } } }*/ +internal class SimpleMessageCreator : IMessageCreator +{ + private EmsTemplate jmsTemplate; + private object objectToConvert; - - internal class SimpleMessageCreator : IMessageCreator + public SimpleMessageCreator(EmsTemplate jmsTemplate, object objectToConvert) { - private EmsTemplate jmsTemplate; - private object objectToConvert; - - public SimpleMessageCreator(EmsTemplate jmsTemplate, object objectToConvert) - { - this.jmsTemplate = jmsTemplate; - this.objectToConvert = objectToConvert; - } - - public Message CreateMessage(ISession session) - { - return jmsTemplate.MessageConverter.ToMessage(objectToConvert, session); - } - - + this.jmsTemplate = jmsTemplate; + this.objectToConvert = objectToConvert; } - - - internal class SendDestinationCallback : ISessionCallback + public Message CreateMessage(ISession session) { - private string destinationName; - private Destination destination; - private EmsTemplate jmsTemplate; - private IMessageCreator messageCreator; - private MessageCreatorDelegate messageCreatorDelegate; - - public SendDestinationCallback(EmsTemplate jmsTemplate, string destinationName, IMessageCreator messageCreator) - { - this.jmsTemplate = jmsTemplate; - this.destinationName = destinationName; - this.messageCreator = messageCreator; - } - - public SendDestinationCallback(EmsTemplate jmsTemplate, Destination destination, IMessageCreator messageCreator) - { - this.jmsTemplate = jmsTemplate; - this.destination = destination; - this.messageCreator = messageCreator; - } - - public SendDestinationCallback(EmsTemplate jmsTemplate, string destinationName, MessageCreatorDelegate messageCreatorDelegate) - { - this.jmsTemplate = jmsTemplate; - this.destinationName = destinationName; - this.messageCreatorDelegate = messageCreatorDelegate; - } - - public SendDestinationCallback(EmsTemplate jmsTemplate, Destination destination, MessageCreatorDelegate messageCreatorDelegate) - { - this.jmsTemplate = jmsTemplate; - this.destination = destination; - this.messageCreatorDelegate = messageCreatorDelegate; - } - - - public object DoInEms(ISession session) - { - if (destination == null) - { - destination = jmsTemplate.ResolveDestinationName(session, destinationName); - } - if (messageCreator != null) - { - jmsTemplate.DoSend(session, destination, messageCreator); - } - else - { - jmsTemplate.DoSend(session, destination, messageCreatorDelegate); - } - return null; - } + return jmsTemplate.MessageConverter.ToMessage(objectToConvert, session); } } + +internal class SendDestinationCallback : ISessionCallback +{ + private string destinationName; + private Destination destination; + private EmsTemplate jmsTemplate; + private IMessageCreator messageCreator; + private MessageCreatorDelegate messageCreatorDelegate; + + public SendDestinationCallback(EmsTemplate jmsTemplate, string destinationName, IMessageCreator messageCreator) + { + this.jmsTemplate = jmsTemplate; + this.destinationName = destinationName; + this.messageCreator = messageCreator; + } + + public SendDestinationCallback(EmsTemplate jmsTemplate, Destination destination, IMessageCreator messageCreator) + { + this.jmsTemplate = jmsTemplate; + this.destination = destination; + this.messageCreator = messageCreator; + } + + public SendDestinationCallback(EmsTemplate jmsTemplate, string destinationName, MessageCreatorDelegate messageCreatorDelegate) + { + this.jmsTemplate = jmsTemplate; + this.destinationName = destinationName; + this.messageCreatorDelegate = messageCreatorDelegate; + } + + public SendDestinationCallback(EmsTemplate jmsTemplate, Destination destination, MessageCreatorDelegate messageCreatorDelegate) + { + this.jmsTemplate = jmsTemplate; + this.destination = destination; + this.messageCreatorDelegate = messageCreatorDelegate; + } + + public object DoInEms(ISession session) + { + if (destination == null) + { + destination = jmsTemplate.ResolveDestinationName(session, destinationName); + } + + if (messageCreator != null) + { + jmsTemplate.DoSend(session, destination, messageCreator); + } + else + { + jmsTemplate.DoSend(session, destination, messageCreatorDelegate); + } + + return null; + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Core/IBrowserCallback.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Core/IBrowserCallback.cs index 653e0ded..2195648b 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Core/IBrowserCallback.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Core/IBrowserCallback.cs @@ -1,5 +1,3 @@ - - #region License /* @@ -22,26 +20,24 @@ using Spring.Messaging.Ems.Common; -namespace Spring.Messaging.Ems.Core +namespace Spring.Messaging.Ems.Core; + +/// +/// Callback for browsing the messages in an EMS queue. +/// +/// +/// To be used with EmsTemplate's callback methods that take a IBrowserCallback argument +/// +/// Juergen Hoeller +/// Mark Pollack (.NET) +public interface IBrowserCallback { /// - /// Callback for browsing the messages in an EMS queue. + /// Perform operations on the given Session and QueueBrowser /// - /// - /// To be used with EmsTemplate's callback methods that take a IBrowserCallback argument - /// - /// Juergen Hoeller - /// Mark Pollack (.NET) - public interface IBrowserCallback - { - - /// - /// Perform operations on the given Session and QueueBrowser - /// - /// The session. - /// The browser. - /// The object from working with the Session and QueueBrowser, may be null - /// If there is any problem when accessing EMS API - object DoInEms(ISession session, QueueBrowser browser); - } + /// The session. + /// The browser. + /// The object from working with the Session and QueueBrowser, may be null + /// If there is any problem when accessing EMS API + object DoInEms(ISession session, QueueBrowser browser); } diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Core/IEmsOperations.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Core/IEmsOperations.cs index a55152ab..30bfd337 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Core/IEmsOperations.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Core/IEmsOperations.cs @@ -18,543 +18,531 @@ #endregion -namespace Spring.Messaging.Ems.Core +namespace Spring.Messaging.Ems.Core; + +/// Specifies a basic set of EMS operations. +/// +/// +///

Implemented by EmsTemplate. Not often used but a useful option +/// to enhance testability, as it can easily be mocked or stubbed.

+/// +///

Provides EmsTemplate's send(..) and +/// receive(..) methods that mirror various EMS API methods. +/// See the EMS specification and EMS API docs for details on those methods. +///

+///
+/// Mark Pollack +/// Juergen Hoeller +/// Mark Pollack (.NET) +public interface IEmsOperations { - /// Specifies a basic set of EMS operations. - /// - /// - ///

Implemented by EmsTemplate. Not often used but a useful option - /// to enhance testability, as it can easily be mocked or stubbed.

- /// - ///

Provides EmsTemplate's send(..) and - /// receive(..) methods that mirror various EMS API methods. - /// See the EMS specification and EMS API docs for details on those methods. - ///

- ///
- /// Mark Pollack - /// Juergen Hoeller - /// Mark Pollack (.NET) - public interface IEmsOperations - { - /// Execute the action specified by the given action object within - /// a EMS Session. - /// - /// delegate that exposes the session - /// the result object from working with the session - /// - /// If there is any problem accessing the EMS API - object Execute(SessionDelegate del); + /// Execute the action specified by the given action object within + /// a EMS Session. + /// + /// delegate that exposes the session + /// the result object from working with the session + /// + /// If there is any problem accessing the EMS API + object Execute(SessionDelegate del); - /// Execute the action specified by the given action object within - /// a EMS Session. - /// - /// callback object that exposes the session - /// - /// the result object from working with the session - /// - /// If there is any problem accessing the EMS API - object Execute(ISessionCallback action); + /// Execute the action specified by the given action object within + /// a EMS Session. + /// + /// callback object that exposes the session + /// + /// the result object from working with the session + /// + /// If there is any problem accessing the EMS API + object Execute(ISessionCallback action); - /// Send a message to a EMS destination. The callback gives access to - /// the EMS session and MessageProducer in order to do more complex - /// send operations. - /// - /// callback object that exposes the session/producer pair - /// - /// the result object from working with the session - /// - /// EMSException if there is any problem - object Execute(IProducerCallback action); + /// Send a message to a EMS destination. The callback gives access to + /// the EMS session and MessageProducer in order to do more complex + /// send operations. + /// + /// callback object that exposes the session/producer pair + /// + /// the result object from working with the session + /// + /// EMSException if there is any problem + object Execute(IProducerCallback action); - /// Send a message to a EMS destination. The callback gives access to - /// the EMS session and MessageProducer in order to do more complex - /// send operations. - /// - /// delegate that exposes the session/producer pair - /// - /// the result object from working with the session - /// - /// If there is any problem accessing the EMS API - object Execute(ProducerDelegate del); + /// Send a message to a EMS destination. The callback gives access to + /// the EMS session and MessageProducer in order to do more complex + /// send operations. + /// + /// delegate that exposes the session/producer pair + /// + /// the result object from working with the session + /// + /// If there is any problem accessing the EMS API + object Execute(ProducerDelegate del); + //------------------------------------------------------------------------- + // Convenience methods for sending messages + //------------------------------------------------------------------------- - //------------------------------------------------------------------------- - // Convenience methods for sending messages - //------------------------------------------------------------------------- + /// Send a message to the default destination. + ///

This will only work with a default destination specified!

+ ///
+ /// callback to create a message + /// + /// If there is any problem accessing the EMS API + void Send(IMessageCreator messageCreator); - /// Send a message to the default destination. - ///

This will only work with a default destination specified!

- ///
- /// callback to create a message - /// - /// If there is any problem accessing the EMS API - void Send(IMessageCreator messageCreator); + /// Send a message to the specified destination. + /// The IMessageCreator callback creates the message given a Session. + /// + /// the destination to send this message to + /// + /// callback to create a message + /// + /// If there is any problem accessing the EMS API + void Send(Destination destination, IMessageCreator messageCreator); - /// Send a message to the specified destination. - /// The IMessageCreator callback creates the message given a Session. - /// - /// the destination to send this message to - /// - /// callback to create a message - /// - /// If there is any problem accessing the EMS API - void Send(Destination destination, IMessageCreator messageCreator); + /// Send a message to the specified destination. + /// The IMessageCreator callback creates the message given a Session. + /// + /// the name of the destination to send this message to + /// (to be resolved to an actual destination by a DestinationResolver) + /// + /// callback to create a message + /// + /// If there is any problem accessing the EMS API + void Send(string destinationName, IMessageCreator messageCreator); - /// Send a message to the specified destination. - /// The IMessageCreator callback creates the message given a Session. - /// - /// the name of the destination to send this message to - /// (to be resolved to an actual destination by a DestinationResolver) - /// - /// callback to create a message - /// - /// If there is any problem accessing the EMS API - void Send(string destinationName, IMessageCreator messageCreator); + //------------------------------------------------------------------------- + // Convenience methods for sending messages + //------------------------------------------------------------------------- - //------------------------------------------------------------------------- - // Convenience methods for sending messages - //------------------------------------------------------------------------- + /// Send a message to the default destination. + ///

This will only work with a default destination specified!

+ ///
+ /// delegate callback to create a message + /// + /// If there is any problem accessing the EMS API + void SendWithDelegate(MessageCreatorDelegate messageCreatorDelegate); - /// Send a message to the default destination. - ///

This will only work with a default destination specified!

- ///
- /// delegate callback to create a message - /// - /// If there is any problem accessing the EMS API - void SendWithDelegate(MessageCreatorDelegate messageCreatorDelegate); + /// Send a message to the specified destination. + /// The IMessageCreator callback creates the message given a Session. + /// + /// the destination to send this message to + /// + /// delegate callback to create a message + /// + /// If there is any problem accessing the EMS API + void SendWithDelegate(Destination destination, MessageCreatorDelegate messageCreatorDelegate); - /// Send a message to the specified destination. - /// The IMessageCreator callback creates the message given a Session. - /// - /// the destination to send this message to - /// - /// delegate callback to create a message - /// - /// If there is any problem accessing the EMS API - void SendWithDelegate(Destination destination, MessageCreatorDelegate messageCreatorDelegate); + /// Send a message to the specified destination. + /// The IMessageCreator callback creates the message given a Session. + /// + /// the name of the destination to send this message to + /// (to be resolved to an actual destination by a DestinationResolver) + /// + /// delegate callback to create a message + /// + /// If there is any problem accessing the EMS API + void SendWithDelegate(string destinationName, MessageCreatorDelegate messageCreatorDelegate); - /// Send a message to the specified destination. - /// The IMessageCreator callback creates the message given a Session. - /// - /// the name of the destination to send this message to - /// (to be resolved to an actual destination by a DestinationResolver) - /// - /// delegate callback to create a message - /// - /// If there is any problem accessing the EMS API - void SendWithDelegate(string destinationName, MessageCreatorDelegate messageCreatorDelegate); + //------------------------------------------------------------------------- + // Convenience methods for sending auto-converted messages + //------------------------------------------------------------------------- - //------------------------------------------------------------------------- - // Convenience methods for sending auto-converted messages - //------------------------------------------------------------------------- + /// Send the given object to the default destination, converting the object + /// to a EMS message with a configured IMessageConverter. + ///

This will only work with a default destination specified!

+ ///
+ /// the object to convert to a message + /// + /// If there is any problem accessing the EMS API + void ConvertAndSend(object message); - /// Send the given object to the default destination, converting the object - /// to a EMS message with a configured IMessageConverter. - ///

This will only work with a default destination specified!

- ///
- /// the object to convert to a message - /// - /// If there is any problem accessing the EMS API - void ConvertAndSend(object message); + /// Send the given object to the specified destination, converting the object + /// to a EMS message with a configured IMessageConverter. + /// + /// the destination to send this message to + /// + /// the object to convert to a message + /// + /// If there is any problem accessing the EMS API + void ConvertAndSend(Destination destination, object message); - /// Send the given object to the specified destination, converting the object - /// to a EMS message with a configured IMessageConverter. - /// - /// the destination to send this message to - /// - /// the object to convert to a message - /// - /// If there is any problem accessing the EMS API - void ConvertAndSend(Destination destination, object message); + /// Send the given object to the specified destination, converting the object + /// to a EMS message with a configured IMessageConverter. + /// + /// the name of the destination to send this message to + /// (to be resolved to an actual destination by a DestinationResolver) + /// + /// the object to convert to a message + /// + /// If there is any problem accessing the EMS API + void ConvertAndSend(string destinationName, object message); - /// Send the given object to the specified destination, converting the object - /// to a EMS message with a configured IMessageConverter. - /// - /// the name of the destination to send this message to - /// (to be resolved to an actual destination by a DestinationResolver) - /// - /// the object to convert to a message - /// - /// If there is any problem accessing the EMS API - void ConvertAndSend(string destinationName, object message); + /// Send the given object to the default destination, converting the object + /// to a EMS message with a configured IMessageConverter. The IMessagePostProcessor + /// callback allows for modification of the message after conversion. + ///

This will only work with a default destination specified!

+ ///
+ /// the object to convert to a message + /// + /// the callback to modify the message + /// + /// If there is any problem accessing the EMS API + void ConvertAndSend(object message, IMessagePostProcessor postProcessor); - /// Send the given object to the default destination, converting the object - /// to a EMS message with a configured IMessageConverter. The IMessagePostProcessor - /// callback allows for modification of the message after conversion. - ///

This will only work with a default destination specified!

- ///
- /// the object to convert to a message - /// - /// the callback to modify the message - /// - /// If there is any problem accessing the EMS API - void ConvertAndSend(object message, IMessagePostProcessor postProcessor); + /// Send the given object to the specified destination, converting the object + /// to a EMS message with a configured IMessageConverter. The IMessagePostProcessor + /// callback allows for modification of the message after conversion. + /// + /// the destination to send this message to + /// + /// the object to convert to a message + /// + /// the callback to modify the message + /// + /// If there is any problem accessing the EMS API + void ConvertAndSend(Destination destination, object message, IMessagePostProcessor postProcessor); - /// Send the given object to the specified destination, converting the object - /// to a EMS message with a configured IMessageConverter. The IMessagePostProcessor - /// callback allows for modification of the message after conversion. - /// - /// the destination to send this message to - /// - /// the object to convert to a message - /// - /// the callback to modify the message - /// - /// If there is any problem accessing the EMS API - void ConvertAndSend(Destination destination, object message, IMessagePostProcessor postProcessor); + /// Send the given object to the specified destination, converting the object + /// to a EMS message with a configured IMessageConverter. The IMessagePostProcessor + /// callback allows for modification of the message after conversion. + /// + /// the name of the destination to send this message to + /// (to be resolved to an actual destination by a DestinationResolver) + /// + /// the object to convert to a message. + /// + /// the callback to modify the message + /// + /// If there is any problem accessing the EMS API + void ConvertAndSend(string destinationName, object message, IMessagePostProcessor postProcessor); - /// Send the given object to the specified destination, converting the object - /// to a EMS message with a configured IMessageConverter. The IMessagePostProcessor - /// callback allows for modification of the message after conversion. - /// - /// the name of the destination to send this message to - /// (to be resolved to an actual destination by a DestinationResolver) - /// - /// the object to convert to a message. - /// - /// the callback to modify the message - /// - /// If there is any problem accessing the EMS API - void ConvertAndSend(string destinationName, object message, IMessagePostProcessor postProcessor); + /// + /// Send the given object to the default destination, converting the object + /// to a EMS message with a configured IMessageConverter. The IMessagePostProcessor + /// callback allows for modification of the message after conversion. + ///

This will only work with a default destination specified!

+ ///
+ /// the object to convert to a message + /// the callback to modify the message + /// If there is any problem accessing the EMS API + void ConvertAndSendWithDelegate(object message, MessagePostProcessorDelegate postProcessor); + /// + /// Send the given object to the specified destination, converting the object + /// to a EMS message with a configured IMessageConverter. The IMessagePostProcessor + /// callback allows for modification of the message after conversion. + /// + /// the destination to send this message to + /// the object to convert to a message + /// the callback to modify the message + /// If there is any problem accessing the EMS API + void ConvertAndSendWithDelegate(Destination destination, object message, MessagePostProcessorDelegate postProcessor); - /// - /// Send the given object to the default destination, converting the object - /// to a EMS message with a configured IMessageConverter. The IMessagePostProcessor - /// callback allows for modification of the message after conversion. - ///

This will only work with a default destination specified!

- ///
- /// the object to convert to a message - /// the callback to modify the message - /// If there is any problem accessing the EMS API - void ConvertAndSendWithDelegate(object message, MessagePostProcessorDelegate postProcessor); + /// + /// Send the given object to the specified destination, converting the object + /// to a EMS message with a configured IMessageConverter. The IMessagePostProcessor + /// callback allows for modification of the message after conversion. + /// + /// the name of the destination to send this message to + /// (to be resolved to an actual destination by a DestinationResolver) + /// the object to convert to a message. + /// the callback to modify the message + /// If there is any problem accessing the EMS API + void ConvertAndSendWithDelegate(string destinationName, object message, MessagePostProcessorDelegate postProcessor); - /// - /// Send the given object to the specified destination, converting the object - /// to a EMS message with a configured IMessageConverter. The IMessagePostProcessor - /// callback allows for modification of the message after conversion. - /// - /// the destination to send this message to - /// the object to convert to a message - /// the callback to modify the message - /// If there is any problem accessing the EMS API - void ConvertAndSendWithDelegate(Destination destination, object message, MessagePostProcessorDelegate postProcessor); + //------------------------------------------------------------------------- + // Convenience methods for receiving messages + //------------------------------------------------------------------------- - /// - /// Send the given object to the specified destination, converting the object - /// to a EMS message with a configured IMessageConverter. The IMessagePostProcessor - /// callback allows for modification of the message after conversion. - /// - /// the name of the destination to send this message to - /// (to be resolved to an actual destination by a DestinationResolver) - /// the object to convert to a message. - /// the callback to modify the message - /// If there is any problem accessing the EMS API - void ConvertAndSendWithDelegate(string destinationName, object message, MessagePostProcessorDelegate postProcessor); + /// Receive a message synchronously from the default destination, but only + /// wait up to a specified time for delivery. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///

This will only work with a default destination specified!

+ ///
+ /// the message received by the consumer, or null if the timeout expires + /// + /// If there is any problem accessing the EMS API + Message Receive(); + /// Receive a message synchronously from the specified destination, but only + /// wait up to a specified time for delivery. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///
+ /// the destination to receive a message from + /// + /// the message received by the consumer, or null if the timeout expires + /// + /// If there is any problem accessing the EMS API + Message Receive(Destination destination); - //------------------------------------------------------------------------- - // Convenience methods for receiving messages - //------------------------------------------------------------------------- + /// Receive a message synchronously from the specified destination, but only + /// wait up to a specified time for delivery. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///
+ /// the name of the destination to send this message to + /// (to be resolved to an actual destination by a DestinationResolver) + /// + /// the message received by the consumer, or null if the timeout expires + /// + /// If there is any problem accessing the EMS API + Message Receive(string destinationName); - /// Receive a message synchronously from the default destination, but only - /// wait up to a specified time for delivery. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///

This will only work with a default destination specified!

- ///
- /// the message received by the consumer, or null if the timeout expires - /// - /// If there is any problem accessing the EMS API - Message Receive(); + /// Receive a message synchronously from the default destination, but only + /// wait up to a specified time for delivery. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///

This will only work with a default destination specified!

+ ///
+ /// the EMS message selector expression (or null if none). + /// See the EMS specification for a detailed definition of selector expressions. + /// + /// the message received by the consumer, or null if the timeout expires + /// + /// If there is any problem accessing the EMS API + Message ReceiveSelected(string messageSelector); - /// Receive a message synchronously from the specified destination, but only - /// wait up to a specified time for delivery. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///
- /// the destination to receive a message from - /// - /// the message received by the consumer, or null if the timeout expires - /// - /// If there is any problem accessing the EMS API - Message Receive(Destination destination); + /// Receive a message synchronously from the specified destination, but only + /// wait up to a specified time for delivery. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///
+ /// the destination to receive a message from + /// + /// the EMS message selector expression (or null if none). + /// See the EMS specification for a detailed definition of selector expressions. + /// + /// the message received by the consumer, or null if the timeout expires + /// + /// If there is any problem accessing the EMS API + Message ReceiveSelected(Destination destination, string messageSelector); - /// Receive a message synchronously from the specified destination, but only - /// wait up to a specified time for delivery. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///
- /// the name of the destination to send this message to - /// (to be resolved to an actual destination by a DestinationResolver) - /// - /// the message received by the consumer, or null if the timeout expires - /// - /// If there is any problem accessing the EMS API - Message Receive(string destinationName); + /// Receive a message synchronously from the specified destination, but only + /// wait up to a specified time for delivery. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///
+ /// the name of the destination to send this message to + /// (to be resolved to an actual destination by a DestinationResolver) + /// + /// the EMS message selector expression (or null if none). + /// See the EMS specification for a detailed definition of selector expressions. + /// + /// the message received by the consumer, or null if the timeout expires + /// + /// If there is any problem accessing the EMS API + Message ReceiveSelected(string destinationName, string messageSelector); - /// Receive a message synchronously from the default destination, but only - /// wait up to a specified time for delivery. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///

This will only work with a default destination specified!

- ///
- /// the EMS message selector expression (or null if none). - /// See the EMS specification for a detailed definition of selector expressions. - /// - /// the message received by the consumer, or null if the timeout expires - /// - /// If there is any problem accessing the EMS API - Message ReceiveSelected(string messageSelector); + //------------------------------------------------------------------------- + // Convenience methods for receiving auto-converted messages + //------------------------------------------------------------------------- - /// Receive a message synchronously from the specified destination, but only - /// wait up to a specified time for delivery. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///
- /// the destination to receive a message from - /// - /// the EMS message selector expression (or null if none). - /// See the EMS specification for a detailed definition of selector expressions. - /// - /// the message received by the consumer, or null if the timeout expires - /// - /// If there is any problem accessing the EMS API - Message ReceiveSelected(Destination destination, string messageSelector); + /// Receive a message synchronously from the default destination, but only + /// wait up to a specified time for delivery. Convert the message into an + /// object with a configured IMessageConverter. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///

This will only work with a default destination specified!

+ ///
+ /// the message produced for the consumer or null if the timeout expires. + /// + /// If there is any problem accessing the EMS API + object ReceiveAndConvert(); - /// Receive a message synchronously from the specified destination, but only - /// wait up to a specified time for delivery. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///
- /// the name of the destination to send this message to - /// (to be resolved to an actual destination by a DestinationResolver) - /// - /// the EMS message selector expression (or null if none). - /// See the EMS specification for a detailed definition of selector expressions. - /// - /// the message received by the consumer, or null if the timeout expires - /// - /// If there is any problem accessing the EMS API - Message ReceiveSelected(string destinationName, string messageSelector); + /// Receive a message synchronously from the specified destination, but only + /// wait up to a specified time for delivery. Convert the message into an + /// object with a configured IMessageConverter. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///
+ /// the destination to receive a message from + /// + /// the message produced for the consumer or null if the timeout expires. + /// + /// If there is any problem accessing the EMS API + object ReceiveAndConvert(Destination destination); + /// Receive a message synchronously from the specified destination, but only + /// wait up to a specified time for delivery. Convert the message into an + /// object with a configured IMessageConverter. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///
+ /// the name of the destination to send this message to + /// (to be resolved to an actual destination by a DestinationResolver) + /// + /// the message produced for the consumer or null if the timeout expires. + /// + /// If there is any problem accessing the EMS API + object ReceiveAndConvert(string destinationName); - //------------------------------------------------------------------------- - // Convenience methods for receiving auto-converted messages - //------------------------------------------------------------------------- + /// Receive a message synchronously from the default destination, but only + /// wait up to a specified time for delivery. Convert the message into an + /// object with a configured IMessageConverter. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///

This will only work with a default destination specified!

+ ///
+ /// the EMS message selector expression (or null if none). + /// See the EMS specification for a detailed definition of selector expressions. + /// + /// the message produced for the consumer or null if the timeout expires. + /// + /// If there is any problem accessing the EMS API + object ReceiveSelectedAndConvert(string messageSelector); - /// Receive a message synchronously from the default destination, but only - /// wait up to a specified time for delivery. Convert the message into an - /// object with a configured IMessageConverter. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///

This will only work with a default destination specified!

- ///
- /// the message produced for the consumer or null if the timeout expires. - /// - /// If there is any problem accessing the EMS API - object ReceiveAndConvert(); + /// Receive a message synchronously from the specified destination, but only + /// wait up to a specified time for delivery. Convert the message into an + /// object with a configured IMessageConverter. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///
+ /// the destination to receive a message from + /// + /// the EMS message selector expression (or null if none). + /// See the EMS specification for a detailed definition of selector expressions. + /// + /// the message produced for the consumer or null if the timeout expires. + /// + /// If there is any problem accessing the EMS API + object ReceiveSelectedAndConvert(Destination destination, string messageSelector); - /// Receive a message synchronously from the specified destination, but only - /// wait up to a specified time for delivery. Convert the message into an - /// object with a configured IMessageConverter. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///
- /// the destination to receive a message from - /// - /// the message produced for the consumer or null if the timeout expires. - /// - /// If there is any problem accessing the EMS API - object ReceiveAndConvert(Destination destination); + /// Receive a message synchronously from the specified destination, but only + /// wait up to a specified time for delivery. Convert the message into an + /// object with a configured IMessageConverter. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///
+ /// the name of the destination to send this message to + /// (to be resolved to an actual destination by a DestinationResolver) + /// + /// the EMS message selector expression (or null if none). + /// See the EMS specification for a detailed definition of selector expressions. + /// + /// the message produced for the consumer or null if the timeout expires. + /// + /// If there is any problem accessing the EMS API + object ReceiveSelectedAndConvert(string destinationName, string messageSelector); - /// Receive a message synchronously from the specified destination, but only - /// wait up to a specified time for delivery. Convert the message into an - /// object with a configured IMessageConverter. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///
- /// the name of the destination to send this message to - /// (to be resolved to an actual destination by a DestinationResolver) - /// - /// the message produced for the consumer or null if the timeout expires. - /// - /// If there is any problem accessing the EMS API - object ReceiveAndConvert(string destinationName); + /// + /// Browses messages in the default EMS queue. The callback gives access to the EMS + /// Session and QueueBrowser in order to browse the queue and react to the contents. + /// + /// The action callback object that exposes the session/browser pair. + /// the result object from working with the session + /// If there is any problem accessing the EMS API + object Browse(IBrowserCallback action); - /// Receive a message synchronously from the default destination, but only - /// wait up to a specified time for delivery. Convert the message into an - /// object with a configured IMessageConverter. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///

This will only work with a default destination specified!

- ///
- /// the EMS message selector expression (or null if none). - /// See the EMS specification for a detailed definition of selector expressions. - /// - /// the message produced for the consumer or null if the timeout expires. - /// - /// If there is any problem accessing the EMS API - object ReceiveSelectedAndConvert(string messageSelector); + /// + /// Browses messages in a EMS queue. The callback gives access to the EMS Session + /// and QueueBrowser in order to browse the queue and react to the contents. + /// + /// The queue to browse. + /// The action callback object that exposes the session/browser pair. + /// the result object from working with the session + /// If there is any problem accessing the EMS API + object Browse(Queue queue, IBrowserCallback action); - /// Receive a message synchronously from the specified destination, but only - /// wait up to a specified time for delivery. Convert the message into an - /// object with a configured IMessageConverter. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///
- /// the destination to receive a message from - /// - /// the EMS message selector expression (or null if none). - /// See the EMS specification for a detailed definition of selector expressions. - /// - /// the message produced for the consumer or null if the timeout expires. - /// - /// If there is any problem accessing the EMS API - object ReceiveSelectedAndConvert(Destination destination, string messageSelector); + /// + /// Browses messages in a EMS queue. The callback gives access to the EMS Session + /// and QueueBrowser in order to browse the queue and react to the contents. + /// + /// Name of the queue to browse, + /// (to be resolved to an actual destination by a DestinationResolver) + /// The action callback object that exposes the session/browser pair. + /// If there is any problem accessing the EMS API + object Browse(string queueName, IBrowserCallback action); - /// Receive a message synchronously from the specified destination, but only - /// wait up to a specified time for delivery. Convert the message into an - /// object with a configured IMessageConverter. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///
- /// the name of the destination to send this message to - /// (to be resolved to an actual destination by a DestinationResolver) - /// - /// the EMS message selector expression (or null if none). - /// See the EMS specification for a detailed definition of selector expressions. - /// - /// the message produced for the consumer or null if the timeout expires. - /// - /// If there is any problem accessing the EMS API - object ReceiveSelectedAndConvert(string destinationName, string messageSelector); + /// + /// Browses messages in a EMS queue. The callback gives access to the EMS Session + /// and QueueBrowser in order to browse the queue and react to the contents. + /// + /// The EMS message selector expression (or null if none). + /// The action callback object that exposes the session/browser pair. + /// If there is any problem accessing the EMS API + object BrowseSelected(string messageSelector, IBrowserCallback action); + /// + /// Browses messages in a EMS queue. The callback gives access to the EMS Session + /// and QueueBrowser in order to browse the queue and react to the contents. + /// + /// The queue to browse. + /// The EMS message selector expression (or null if none). + /// The action callback object that exposes the session/browser pair. + /// + /// If there is any problem accessing the EMS API + object BrowseSelected(Queue queue, string messageSelector, IBrowserCallback action); - /// - /// Browses messages in the default EMS queue. The callback gives access to the EMS - /// Session and QueueBrowser in order to browse the queue and react to the contents. - /// - /// The action callback object that exposes the session/browser pair. - /// the result object from working with the session - /// If there is any problem accessing the EMS API - object Browse(IBrowserCallback action); + /// + /// Browses messages in a EMS queue. The callback gives access to the EMS Session + /// and QueueBrowser in order to browse the queue and react to the contents. + /// + /// Name of the queue to browse, + /// (to be resolved to an actual destination by a DestinationResolver) + /// The EMS message selector expression (or null if none). + /// The action callback object that exposes the session/browser pair. + /// + /// If there is any problem accessing the EMS API + object BrowseSelected(string queueName, string messageSelector, IBrowserCallback action); + /// + /// Browses messages in the default EMS queue. The callback gives access to the EMS + /// Session and QueueBrowser in order to browse the queue and react to the contents. + /// + /// The action callback delegate that exposes the session/browser pair. + /// the result object from working with the session + object BrowseWithDelegate(BrowserDelegate action); - /// - /// Browses messages in a EMS queue. The callback gives access to the EMS Session - /// and QueueBrowser in order to browse the queue and react to the contents. - /// - /// The queue to browse. - /// The action callback object that exposes the session/browser pair. - /// the result object from working with the session - /// If there is any problem accessing the EMS API - object Browse(Queue queue, IBrowserCallback action); + /// + /// Browses messages in a EMS queue. The callback gives access to the EMS Session + /// and QueueBrowser in order to browse the queue and react to the contents. + /// + /// The queue to browse. + /// The action callback delegate that exposes the session/browser pair. + /// the result object from working with the session + object BrowseWithDelegate(Queue queue, BrowserDelegate action); - /// - /// Browses messages in a EMS queue. The callback gives access to the EMS Session - /// and QueueBrowser in order to browse the queue and react to the contents. - /// - /// Name of the queue to browse, - /// (to be resolved to an actual destination by a DestinationResolver) - /// The action callback object that exposes the session/browser pair. - /// If there is any problem accessing the EMS API - object Browse(string queueName, IBrowserCallback action); + /// + /// Browses messages in a EMS queue. The callback gives access to the EMS Session + /// and QueueBrowser in order to browse the queue and react to the contents. + /// + /// Name of the queue to browse, + /// (to be resolved to an actual destination by a DestinationResolver) + /// The action callback delegate that exposes the session/browser pair. + /// If there is any problem accessing the EMS API + object BrowseWithDelegate(string queueName, BrowserDelegate action); + /// + /// Browses messages in a EMS queue. The callback gives access to the EMS Session + /// and QueueBrowser in order to browse the queue and react to the contents. + /// + /// The EMS message selector expression (or null if none). + /// The action callback delegate that exposes the session/browser pair. + /// If there is any problem accessing the EMS API + object BrowseSelectedWithDelegate(string messageSelector, BrowserDelegate action); - /// - /// Browses messages in a EMS queue. The callback gives access to the EMS Session - /// and QueueBrowser in order to browse the queue and react to the contents. - /// - /// The EMS message selector expression (or null if none). - /// The action callback object that exposes the session/browser pair. - /// If there is any problem accessing the EMS API - object BrowseSelected(string messageSelector, IBrowserCallback action); + /// + /// Browses messages in a EMS queue. The callback gives access to the EMS Session + /// and QueueBrowser in order to browse the queue and react to the contents. + /// + /// The queue to browse. + /// The EMS message selector expression (or null if none). + /// The action callback delegate that exposes the session/browser pair. + /// + /// If there is any problem accessing the EMS API + object BrowseSelectedWithDelegate(Queue queue, string messageSelector, BrowserDelegate action); - - /// - /// Browses messages in a EMS queue. The callback gives access to the EMS Session - /// and QueueBrowser in order to browse the queue and react to the contents. - /// - /// The queue to browse. - /// The EMS message selector expression (or null if none). - /// The action callback object that exposes the session/browser pair. - /// - /// If there is any problem accessing the EMS API - object BrowseSelected(Queue queue, string messageSelector, IBrowserCallback action); - - /// - /// Browses messages in a EMS queue. The callback gives access to the EMS Session - /// and QueueBrowser in order to browse the queue and react to the contents. - /// - /// Name of the queue to browse, - /// (to be resolved to an actual destination by a DestinationResolver) - /// The EMS message selector expression (or null if none). - /// The action callback object that exposes the session/browser pair. - /// - /// If there is any problem accessing the EMS API - object BrowseSelected(string queueName, string messageSelector, IBrowserCallback action); - - /// - /// Browses messages in the default EMS queue. The callback gives access to the EMS - /// Session and QueueBrowser in order to browse the queue and react to the contents. - /// - /// The action callback delegate that exposes the session/browser pair. - /// the result object from working with the session - object BrowseWithDelegate(BrowserDelegate action); - - /// - /// Browses messages in a EMS queue. The callback gives access to the EMS Session - /// and QueueBrowser in order to browse the queue and react to the contents. - /// - /// The queue to browse. - /// The action callback delegate that exposes the session/browser pair. - /// the result object from working with the session - object BrowseWithDelegate(Queue queue, BrowserDelegate action); - - /// - /// Browses messages in a EMS queue. The callback gives access to the EMS Session - /// and QueueBrowser in order to browse the queue and react to the contents. - /// - /// Name of the queue to browse, - /// (to be resolved to an actual destination by a DestinationResolver) - /// The action callback delegate that exposes the session/browser pair. - /// If there is any problem accessing the EMS API - object BrowseWithDelegate(string queueName, BrowserDelegate action); - - - /// - /// Browses messages in a EMS queue. The callback gives access to the EMS Session - /// and QueueBrowser in order to browse the queue and react to the contents. - /// - /// The EMS message selector expression (or null if none). - /// The action callback delegate that exposes the session/browser pair. - /// If there is any problem accessing the EMS API - object BrowseSelectedWithDelegate(string messageSelector, BrowserDelegate action); - - /// - /// Browses messages in a EMS queue. The callback gives access to the EMS Session - /// and QueueBrowser in order to browse the queue and react to the contents. - /// - /// The queue to browse. - /// The EMS message selector expression (or null if none). - /// The action callback delegate that exposes the session/browser pair. - /// - /// If there is any problem accessing the EMS API - object BrowseSelectedWithDelegate(Queue queue, string messageSelector, BrowserDelegate action); - - - /// - /// Browses messages in a EMS queue. The callback gives access to the EMS Session - /// and QueueBrowser in order to browse the queue and react to the contents. - /// - /// Name of the queue to browse, - /// (to be resolved to an actual destination by a DestinationResolver) - /// The EMS message selector expression (or null if none). - /// The action callback delegate that exposes the session/browser pair. - /// - /// If there is any problem accessing the EMS API - object BrowseSelectedWithDelegate(string queueName, string messageSelector, BrowserDelegate action); - - } + /// + /// Browses messages in a EMS queue. The callback gives access to the EMS Session + /// and QueueBrowser in order to browse the queue and react to the contents. + /// + /// Name of the queue to browse, + /// (to be resolved to an actual destination by a DestinationResolver) + /// The EMS message selector expression (or null if none). + /// The action callback delegate that exposes the session/browser pair. + /// + /// If there is any problem accessing the EMS API + object BrowseSelectedWithDelegate(string queueName, string messageSelector, BrowserDelegate action); } diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Core/IMessageCreator.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Core/IMessageCreator.cs index cce43236..1cd62697 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Core/IMessageCreator.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Core/IMessageCreator.cs @@ -20,23 +20,22 @@ using Spring.Messaging.Ems.Common; -namespace Spring.Messaging.Ems.Core +namespace Spring.Messaging.Ems.Core; + +/// Creates a EMS message given a Session +/// +///

The Session typically is provided by an instance +/// of the EmsTemplate class.

+///
+/// Mark Pollack +public interface IMessageCreator { - /// Creates a EMS message given a Session - /// - ///

The Session typically is provided by an instance - /// of the EmsTemplate class.

- ///
- /// Mark Pollack - public interface IMessageCreator - { - /// Create a Message to be sent. - /// the EMS Session to be used to create the - /// Message (never null) - /// - /// the Message to be sent - /// - /// EMSException if thrown by EMS API methods - Message CreateMessage(ISession session); - } + /// Create a Message to be sent. + /// the EMS Session to be used to create the + /// Message (never null) + /// + /// the Message to be sent + /// + /// EMSException if thrown by EMS API methods + Message CreateMessage(ISession session); } diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Core/IMessagePostProcessor.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Core/IMessagePostProcessor.cs index a6b6b729..848991c0 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Core/IMessagePostProcessor.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Core/IMessagePostProcessor.cs @@ -18,27 +18,25 @@ #endregion -namespace Spring.Messaging.Ems.Core -{ - /// To be used with EmsTemplate's send method that - /// convert an object to a message. - /// - /// - /// It allows for further modification of the message after it has been processed - /// by the converter. This is useful for setting of EMS Header and Properties. - /// - /// Mark Pollack - public interface IMessagePostProcessor - { - /// Apply a IMessagePostProcessor to the message. The returned message is - /// typically a modified version of the original. - /// - /// the EMS message from the IMessageConverter - /// - /// the modified version of the Message - /// - /// EMSException if thrown by EMS API methods - Message PostProcessMessage(Message message); +namespace Spring.Messaging.Ems.Core; - } -} +/// To be used with EmsTemplate's send method that +/// convert an object to a message. +/// +/// +/// It allows for further modification of the message after it has been processed +/// by the converter. This is useful for setting of EMS Header and Properties. +/// +/// Mark Pollack +public interface IMessagePostProcessor +{ + /// Apply a IMessagePostProcessor to the message. The returned message is + /// typically a modified version of the original. + /// + /// the EMS message from the IMessageConverter + /// + /// the modified version of the Message + /// + /// EMSException if thrown by EMS API methods + Message PostProcessMessage(Message message); +} \ No newline at end of file diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Core/IProducerCallback.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Core/IProducerCallback.cs index 13f8f738..efa14ee1 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Core/IProducerCallback.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Core/IProducerCallback.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2010 the original author or authors. + * Copyright � 2002-2010 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. @@ -20,29 +20,27 @@ using Spring.Messaging.Ems.Common; -namespace Spring.Messaging.Ems.Core +namespace Spring.Messaging.Ems.Core; + +/// Callback for sending a message to a EMS destination. +/// +///

To be used with the EmsTemplate.Execute(IProducerCallback) +/// method, often implemented as an anonymous inner class.

+/// +///

The typical implementation will perform multiple operations on the +/// supplied EMS Session and MessageProducer.

+///
+/// Mark Pollack +public interface IProducerCallback { - /// Callback for sending a message to a EMS destination. - /// - ///

To be used with the EmsTemplate.Execute(IProducerCallback) - /// method, often implemented as an anonymous inner class.

- /// - ///

The typical implementation will perform multiple operations on the - /// supplied EMS Session and MessageProducer.

- ///
- /// Mark Pollack - public interface IProducerCallback - { - /// Perform operations on the given Session and MessageProducer. - /// The message producer is not associated with any destination. - /// - /// the EMS Session object to use - /// - /// the EMS MessageProducer object to use - /// - /// a result object from working with the Session, if any (can be null) - /// - object DoInEms(ISession session, IMessageProducer producer); - - } -} \ No newline at end of file + /// Perform operations on the given Session and MessageProducer. + /// The message producer is not associated with any destination. + /// + /// the EMS Session object to use + /// + /// the EMS MessageProducer object to use + /// + /// a result object from working with the Session, if any (can be null) + /// + object DoInEms(ISession session, IMessageProducer producer); +} diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Core/ISessionCallback.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Core/ISessionCallback.cs index 76d7eb6e..0554136d 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Core/ISessionCallback.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Core/ISessionCallback.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2010 the original author or authors. + * Copyright � 2002-2010 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. @@ -20,28 +20,27 @@ using Spring.Messaging.Ems.Common; -namespace Spring.Messaging.Ems.Core +namespace Spring.Messaging.Ems.Core; + +/// Callback for executing any number of operations on a provided +/// Session +/// +/// +///

To be used with the EmsTemplate.Execute(ISessionCallback)} +/// method, often implemented as an anonymous inner class.

+///
+/// Mark Pollack +/// +/// +public interface ISessionCallback { - /// Callback for executing any number of operations on a provided - /// Session + /// Execute any number of operations against the supplied EMS + /// Session, possibly returning a result. /// - /// - ///

To be used with the EmsTemplate.Execute(ISessionCallback)} - /// method, often implemented as an anonymous inner class.

- ///
- /// Mark Pollack - /// - /// - public interface ISessionCallback - { - /// Execute any number of operations against the supplied EMS - /// Session, possibly returning a result. - /// - /// the EMS Session - /// - /// a result object from working with the Session, if any (so can be null) - /// - /// EMSException if there is any problem - object DoInEms(ISession session); - } + /// the EMS Session + /// + /// a result object from working with the Session, if any (so can be null) + /// + /// EMSException if there is any problem + object DoInEms(ISession session); } diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Core/MessageCreatorDelegate.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Core/MessageCreatorDelegate.cs index 40357972..7d2a994c 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Core/MessageCreatorDelegate.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Core/MessageCreatorDelegate.cs @@ -20,16 +20,15 @@ using Spring.Messaging.Ems.Common; -namespace Spring.Messaging.Ems.Core -{ - /// - /// Delegate that creates a EMS message given a Session - /// - /// the EMS Session to be used to create the - /// Message (never null) - /// - /// the Message to be sent - /// - /// EMSException if thrown by EMS API methods - public delegate Message MessageCreatorDelegate(ISession session); -} +namespace Spring.Messaging.Ems.Core; + +/// +/// Delegate that creates a EMS message given a Session +/// +/// the EMS Session to be used to create the +/// Message (never null) +/// +/// the Message to be sent +/// +/// EMSException if thrown by EMS API methods +public delegate Message MessageCreatorDelegate(ISession session); diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Core/MessagePostProcessorDelegate.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Core/MessagePostProcessorDelegate.cs index acb5be52..4d3aec8d 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Core/MessagePostProcessorDelegate.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Core/MessagePostProcessorDelegate.cs @@ -18,17 +18,15 @@ #endregion -namespace Spring.Messaging.Ems.Core -{ +namespace Spring.Messaging.Ems.Core; - /// - /// Delegate that is used with EmsTemplate's ConvertAndSend method that converts - /// an object. - /// - /// - /// It allows for further modification of the message after it has been processed - /// by the converter. This is useful for setting of EMS Header and Properties. - /// - /// Mark Pollack - public delegate Message MessagePostProcessorDelegate(Message message); -} +/// +/// Delegate that is used with EmsTemplate's ConvertAndSend method that converts +/// an object. +/// +/// +/// It allows for further modification of the message after it has been processed +/// by the converter. This is useful for setting of EMS Header and Properties. +/// +/// Mark Pollack +public delegate Message MessagePostProcessorDelegate(Message message); diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Core/ProducerDelegate.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Core/ProducerDelegate.cs index dbc5e9a9..fdc9015f 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Core/ProducerDelegate.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Core/ProducerDelegate.cs @@ -1,5 +1,3 @@ - - #region License /* @@ -22,17 +20,15 @@ using Spring.Messaging.Ems.Common; -namespace Spring.Messaging.Ems.Core -{ - /// Perform operations on the given Session and MessageProducer. - /// The message producer is not associated with any destination. - /// - /// the EMS Session object to use - /// - /// the EMS MessageProducer object to use - /// - /// a result object from working with the Session, if any (can be null) - /// - public delegate object ProducerDelegate(ISession session, IMessageProducer producer); +namespace Spring.Messaging.Ems.Core; -} \ No newline at end of file +/// Perform operations on the given Session and MessageProducer. +/// The message producer is not associated with any destination. +/// +/// the EMS Session object to use +/// +/// the EMS MessageProducer object to use +/// +/// a result object from working with the Session, if any (can be null) +/// +public delegate object ProducerDelegate(ISession session, IMessageProducer producer); diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Core/SessionDelegate.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Core/SessionDelegate.cs index 92f56df4..173c7a7d 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Core/SessionDelegate.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Core/SessionDelegate.cs @@ -1,14 +1,14 @@ #region License /* - * Copyright © 2002-2010 the original author or authors. - * + * Copyright � 2002-2010 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. @@ -20,20 +20,19 @@ using Spring.Messaging.Ems.Common; -namespace Spring.Messaging.Ems.Core -{ - /// - /// Callback delegate for code that operates on a Session. - /// - /// The EMS Session object. - /// - /// Allows you to execute any number of operations - /// on a single ISession, possibly returning a result a result. - /// - /// - /// A result object from working with the Session, if any (so can be null) - /// - /// EMSException if there is any problem - /// Mark Pollack - public delegate object SessionDelegate(ISession session); -} +namespace Spring.Messaging.Ems.Core; + +/// +/// Callback delegate for code that operates on a Session. +/// +/// The EMS Session object. +/// +/// Allows you to execute any number of operations +/// on a single ISession, possibly returning a result a result. +/// +/// +/// A result object from working with the Session, if any (so can be null) +/// +/// EMSException if there is any problem +/// Mark Pollack +public delegate object SessionDelegate(ISession session); diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Jndi/JndiAccessor.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Jndi/JndiAccessor.cs index a02d79ca..1cd7b6a6 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Jndi/JndiAccessor.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Jndi/JndiAccessor.cs @@ -21,82 +21,80 @@ using System.Collections; using Spring.Objects.Factory; -namespace Spring.Messaging.Ems.Jndi +namespace Spring.Messaging.Ems.Jndi; + +/// +/// Convenient superclass to access JndiProperties, JndiContextType or alternatively set the ILookupContext directly. +/// +/// Juergen Hoeller +/// Mark Pollack +public class JndiAccessor : IInitializingObject { + private ILookupContext _jndiLookupContext; + + private Hashtable jndiProperties = new Hashtable(); + + private JndiContextType contextType = JndiContextType.JMS; + + protected ILog logger; + + LookupContextFactory contextFactoryObject = new LookupContextFactory(); + /// - /// Convenient superclass to access JndiProperties, JndiContextType or alternatively set the ILookupContext directly. + /// Gets or sets the lookup context. /// - /// Juergen Hoeller - /// Mark Pollack - public class JndiAccessor : IInitializingObject + /// The lookup context. + public ILookupContext JndiLookupContext { - private ILookupContext _jndiLookupContext; + get { return _jndiLookupContext; } + set { _jndiLookupContext = value; } + } - private Hashtable jndiProperties = new Hashtable(); - - private JndiContextType contextType = JndiContextType.JMS; - - protected ILog logger; - - LookupContextFactory contextFactoryObject = new LookupContextFactory(); - - /// - /// Gets or sets the lookup context. - /// - /// The lookup context. - public ILookupContext JndiLookupContext + /// + /// Gets or sets the JNDI environment properties. + /// + /// The jndi properties. + public IDictionary JndiProperties + { + get { - get { return _jndiLookupContext; } - set { _jndiLookupContext = value; } + return jndiProperties; } - - /// - /// Gets or sets the JNDI environment properties. - /// - /// The jndi properties. - public IDictionary JndiProperties + set { - get - { - return jndiProperties; - } - set - { - jndiProperties = new Hashtable(value); - } + jndiProperties = new Hashtable(value); } + } - /// - /// Gets or sets the type of the jndi context. The default is JndiContextType.JMS - /// - /// The type of the jndi context. - public JndiContextType JndiContextType + /// + /// Gets or sets the type of the jndi context. The default is JndiContextType.JMS + /// + /// The type of the jndi context. + public JndiContextType JndiContextType + { + get { return this.contextType; } + set { - get { return this.contextType; } - set - { - this.contextType = value; - } + this.contextType = value; } + } - - /// - /// Create the JndiLookupContext if it has not been explicitly set. - /// - public virtual void AfterPropertiesSet() + /// + /// Create the JndiLookupContext if it has not been explicitly set. + /// + public virtual void AfterPropertiesSet() + { + if (_jndiLookupContext == null) { - if (_jndiLookupContext == null) + if (JndiContextType == JndiContextType.JMS) { - if (JndiContextType == JndiContextType.JMS) - { - this._jndiLookupContext = contextFactoryObject.CreateContext(LookupContextFactory.TIBJMS_NAMING_CONTEXT, - jndiProperties); - } - else - { - this._jndiLookupContext = contextFactoryObject.CreateContext(LookupContextFactory.LDAP_CONTEXT, - jndiProperties); - } + this._jndiLookupContext = contextFactoryObject.CreateContext(LookupContextFactory.TIBJMS_NAMING_CONTEXT, + jndiProperties); + } + else + { + this._jndiLookupContext = contextFactoryObject.CreateContext(LookupContextFactory.LDAP_CONTEXT, + jndiProperties); } } } diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Jndi/JndiContextType.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Jndi/JndiContextType.cs index a56cffc0..e920bde0 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Jndi/JndiContextType.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Jndi/JndiContextType.cs @@ -1,19 +1,17 @@ -namespace Spring.Messaging.Ems.Jndi +namespace Spring.Messaging.Ems.Jndi; + +/// +/// The various JNDI Context types. +/// +public enum JndiContextType { + /// + /// Create a tibjmsnaming context to lookup administered object inside the tibjmsnaming server. + /// + JMS, /// - /// The various JNDI Context types. + /// Create a ldap context to lookup administered object in an ldap server. /// - public enum JndiContextType - { - /// - /// Create a tibjmsnaming context to lookup administered object inside the tibjmsnaming server. - /// - JMS, - - /// - /// Create a ldap context to lookup administered object in an ldap server. - /// - LDAP - } ; -} \ No newline at end of file + LDAP +}; diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Jndi/JndiLocatorSupport.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Jndi/JndiLocatorSupport.cs index 34a77e15..05ac7ee9 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Jndi/JndiLocatorSupport.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Jndi/JndiLocatorSupport.cs @@ -22,42 +22,38 @@ using Microsoft.Extensions.Logging; using Spring.Objects.Factory; using Spring.Util; -namespace Spring.Messaging.Ems.Jndi +namespace Spring.Messaging.Ems.Jndi; + +public abstract class JndiLocatorSupport : JndiAccessor { - public abstract class JndiLocatorSupport : JndiAccessor + protected virtual object Lookup(string jndiName) { - - - protected virtual object Lookup(string jndiName) + object jndiObject = Lookup(jndiName, null); + if (logger.IsEnabled(LogLevel.Debug)) { - object jndiObject = Lookup(jndiName, null); - if (logger.IsEnabled(LogLevel.Debug)) - { - logger.LogDebug("Located object with JNDI name [" + jndiName + "]"); - } - return jndiObject; + logger.LogDebug("Located object with JNDI name [" + jndiName + "]"); } - protected virtual object Lookup(string jndiName, Type requiredType) + return jndiObject; + } + + protected virtual object Lookup(string jndiName, Type requiredType) + { + AssertUtils.ArgumentNotNull(jndiName, "jndiName"); + + object jndiObject = JndiLookupContext.Lookup(jndiName); + + if (requiredType != null && !ObjectUtils.IsAssignable(requiredType, jndiObject)) { - AssertUtils.ArgumentNotNull(jndiName, "jndiName"); - - object jndiObject = JndiLookupContext.Lookup(jndiName); - - - if (requiredType != null && !ObjectUtils.IsAssignable(requiredType, jndiObject)) - { - throw new TypeMismatchNamingException( - jndiName, requiredType, (jndiObject != null ? jndiObject.GetType() : null)); - } - - if (logger.IsEnabled(LogLevel.Debug)) - { - logger.LogDebug("Located object with JNDI name [" + jndiName + "]"); - } - return jndiObject; + throw new TypeMismatchNamingException( + jndiName, requiredType, (jndiObject != null ? jndiObject.GetType() : null)); } + if (logger.IsEnabled(LogLevel.Debug)) + { + logger.LogDebug("Located object with JNDI name [" + jndiName + "]"); + } + return jndiObject; } } diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Jndi/JndiLookupFactoryObject.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Jndi/JndiLookupFactoryObject.cs index abf57261..a5cbdd7f 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Jndi/JndiLookupFactoryObject.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Jndi/JndiLookupFactoryObject.cs @@ -24,135 +24,136 @@ using Spring.Objects.Factory; using Spring.Objects.Factory.Config; using Spring.Util; -namespace Spring.Messaging.Ems.Jndi +namespace Spring.Messaging.Ems.Jndi; + +public class JndiLookupFactoryObject : JndiObjectLocator, IConfigurableFactoryObject { - public class JndiLookupFactoryObject : JndiObjectLocator, IConfigurableFactoryObject + static JndiLookupFactoryObject() { - static JndiLookupFactoryObject() + TypeRegistry.RegisterType("LookupContext", typeof(LookupContext)); + TypeRegistry.RegisterType("JndiContextType", typeof(JndiContextType)); + } + + private object defaultObject; + private Object jndiObject; + private IObjectDefinition productTemplate; + + public JndiLookupFactoryObject() + { + this.logger = LogManager.GetLogger(GetType()); + } + + /// + /// Sets the default object to fall back to if the JNDI lookup fails. + /// Default is none. + /// + /// + /// This can be an arbitrary bean reference or literal value. + /// It is typically used for literal values in scenarios where the JNDI environment + /// might define specific config settings but those are not required to be present. + /// + /// + /// The default object to use when lookup fails. + public object DefaultObject + { + set { defaultObject = value; } + } + + #region Implementation of IFactoryObject + + /// + /// Return the Jndi object + /// + /// The Jndi object + public object GetObject() + { + return this.jndiObject; + } + + /// + /// Return type of object retrieved from Jndi or the expected type if the Jndi retrieval + /// did not succeed. + /// + /// Return value of retrieved object + public Type ObjectType + { + get { - TypeRegistry.RegisterType("LookupContext", typeof(LookupContext)); - TypeRegistry.RegisterType("JndiContextType", typeof(JndiContextType)); - } - - private object defaultObject; - private Object jndiObject; - private IObjectDefinition productTemplate; - - public JndiLookupFactoryObject() - { - this.logger = LogManager.GetLogger(GetType()); - } - - /// - /// Sets the default object to fall back to if the JNDI lookup fails. - /// Default is none. - /// - /// - /// This can be an arbitrary bean reference or literal value. - /// It is typically used for literal values in scenarios where the JNDI environment - /// might define specific config settings but those are not required to be present. - /// - /// - /// The default object to use when lookup fails. - public object DefaultObject - { - set { defaultObject = value; } - } - - #region Implementation of IFactoryObject - - /// - /// Return the Jndi object - /// - /// The Jndi object - public object GetObject() - { - return this.jndiObject; - } - - - /// - /// Return type of object retrieved from Jndi or the expected type if the Jndi retrieval - /// did not succeed. - /// - /// Return value of retrieved object - public Type ObjectType - { - get + if (this.jndiObject != null) { - if (this.jndiObject != null) - { - return this.jndiObject.GetType(); - } - return ExpectedType; + return this.jndiObject.GetType(); } - } - - /// - /// Returns true - /// - public bool IsSingleton - { - get { return true; } - } - - #endregion - - public override void AfterPropertiesSet() - { - base.AfterPropertiesSet(); - TypeRegistry.RegisterType("LookupContext", typeof(LookupContext)); - if (this.defaultObject != null && ExpectedType != null && - !ObjectUtils.IsAssignable(ExpectedType, this.defaultObject)) - { - throw new ArgumentException("Default object [" + this.defaultObject + - "] of type [" + this.defaultObject.GetType().Name + - "] is not of expected type [" + ExpectedType.Name + "]"); - } - // Locate specified JNDI object. - this.jndiObject = LookupWithFallback(); - } - - protected virtual object LookupWithFallback() - { - try - { - return Lookup(); - } - catch (TypeMismatchNamingException) - { - // Always let TypeMismatchNamingException through - - // we don't want to fall back to the defaultObject in this case. - throw; - } - catch (NamingException ex) - { - if (this.defaultObject != null) - { - if (logger.IsEnabled(LogLevel.Debug)) - { - logger.LogDebug((Exception) ex, "JNDI lookup failed - returning specified default object instead"); - } - else if (logger.IsEnabled(LogLevel.Information)) - { - logger.LogInformation("JNDI lookup failed - returning specified default object instead: " + ex); - } - return this.defaultObject; - } - throw; - } - } - - /// - /// Gets the template object definition that should be used - /// to configure the instance of the object managed by this factory. - /// - /// - public IObjectDefinition ProductTemplate - { - get { return productTemplate; } - set { productTemplate = value; } + return ExpectedType; } } + + /// + /// Returns true + /// + public bool IsSingleton + { + get { return true; } + } + + #endregion + + public override void AfterPropertiesSet() + { + base.AfterPropertiesSet(); + TypeRegistry.RegisterType("LookupContext", typeof(LookupContext)); + if (this.defaultObject != null && ExpectedType != null && + !ObjectUtils.IsAssignable(ExpectedType, this.defaultObject)) + { + throw new ArgumentException("Default object [" + this.defaultObject + + "] of type [" + this.defaultObject.GetType().Name + + "] is not of expected type [" + ExpectedType.Name + "]"); + } + + // Locate specified JNDI object. + this.jndiObject = LookupWithFallback(); + } + + protected virtual object LookupWithFallback() + { + try + { + return Lookup(); + } + catch (TypeMismatchNamingException) + { + // Always let TypeMismatchNamingException through - + // we don't want to fall back to the defaultObject in this case. + throw; + } + catch (NamingException ex) + { + if (this.defaultObject != null) + { + if (logger.IsEnabled(LogLevel.Debug)) + { + logger.LogDebug((Exception) ex, "JNDI lookup failed - returning specified default object instead"); + } + else if (logger.IsEnabled(LogLevel.Information)) + { + logger.LogInformation("JNDI lookup failed - returning specified default object instead: " + ex); + } + + return this.defaultObject; + } + + throw; + } + } + + /// + /// Gets the template object definition that should be used + /// to configure the instance of the object managed by this factory. + /// + /// + public IObjectDefinition ProductTemplate + { + get { return productTemplate; } + set { productTemplate = value; } + } } diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Jndi/JndiObjectLocator.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Jndi/JndiObjectLocator.cs index c1a1d920..c941488b 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Jndi/JndiObjectLocator.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Jndi/JndiObjectLocator.cs @@ -20,73 +20,73 @@ using Spring.Util; -namespace Spring.Messaging.Ems.Jndi +namespace Spring.Messaging.Ems.Jndi; + +/// +/// Convenient superclass for JNDI-based service locators, +/// providing configurable lookup of a specific JNDI resource. +/// +/// +/// +/// Exposes a JndiName property. +/// +/// Subclasses may invoke the Lookup method whenever it is appropriate. +/// Some classes might do this on initialization, while others might do it +/// on demand. The latter strategy is more flexible in that it allows for +/// initialization of the locator before the JNDI object is available. +/// +/// +/// Juergen Hoeller +/// Mark Pollack (.NET) +public abstract class JndiObjectLocator : JndiLocatorSupport { + private string jndiName; + + private Type expectedType; + /// - /// Convenient superclass for JNDI-based service locators, - /// providing configurable lookup of a specific JNDI resource. + /// Gets or sets the Jndi name to lookup. /// - /// - /// - /// Exposes a JndiName property. - /// - /// Subclasses may invoke the Lookup method whenever it is appropriate. - /// Some classes might do this on initialization, while others might do it - /// on demand. The latter strategy is more flexible in that it allows for - /// initialization of the locator before the JNDI object is available. - /// - /// - /// Juergen Hoeller - /// Mark Pollack (.NET) - public abstract class JndiObjectLocator : JndiLocatorSupport + /// The name of the jndi. + public string JndiName { - private string jndiName; - - private Type expectedType; - - /// - /// Gets or sets the Jndi name to lookup. - /// - /// The name of the jndi. - public string JndiName - { - get { return jndiName; } - set { jndiName = value; } - } - - /// - /// Gets or sets the type that the located JNDI object is supposed - /// to be assignable to, if any. - /// - /// The expected type. - public Type ExpectedType - { - get { return expectedType; } - set { expectedType = value; } - } - - #region Implementation of IInitializingObject - - /// - /// Ensure that the JndiName property is set and create the TIBCO EMS ILookupContext instance. - /// - public override void AfterPropertiesSet() - { - base.AfterPropertiesSet(); - if (!StringUtils.HasLength(JndiName)) - { - throw new ArgumentException("Property 'JndiName' is required"); - } - } - - /// - /// Lookups this instance using the JndiName and ExpectedType properties - /// - /// The object retrieved from Jndi - protected virtual object Lookup() { - return Lookup(JndiName, ExpectedType); - } - - #endregion + get { return jndiName; } + set { jndiName = value; } } -} + + /// + /// Gets or sets the type that the located JNDI object is supposed + /// to be assignable to, if any. + /// + /// The expected type. + public Type ExpectedType + { + get { return expectedType; } + set { expectedType = value; } + } + + #region Implementation of IInitializingObject + + /// + /// Ensure that the JndiName property is set and create the TIBCO EMS ILookupContext instance. + /// + public override void AfterPropertiesSet() + { + base.AfterPropertiesSet(); + if (!StringUtils.HasLength(JndiName)) + { + throw new ArgumentException("Property 'JndiName' is required"); + } + } + + /// + /// Lookups this instance using the JndiName and ExpectedType properties + /// + /// The object retrieved from Jndi + protected virtual object Lookup() + { + return Lookup(JndiName, ExpectedType); + } + + #endregion +} \ No newline at end of file diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Jndi/LookupContextFactoryObject.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Jndi/LookupContextFactoryObject.cs index 74c48b7c..f3c92022 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Jndi/LookupContextFactoryObject.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Jndi/LookupContextFactoryObject.cs @@ -20,52 +20,50 @@ using Spring.Objects.Factory; -namespace Spring.Messaging.Ems.Jndi +namespace Spring.Messaging.Ems.Jndi; + +/// +/// A Spring FactoryObject that returns TIBCO.EMS.ILookupContext. Use the returned +/// ILookupContext to do you lookups at runtime. +/// +/// +/// +/// Important properties to set are JndiProperties and JndiContexType. JndiContextType is set to +/// LookupContextFactory.TIBJMS_NAMING_CONT by default. +/// +/// To lookup objects at startup time and cache their values, as well as provide a +/// default value if lookup fail, +/// +/// +/// Mark Pollack +public class LookupContextFactoryObject : JndiLocatorSupport, IFactoryObject { + #region Implementation of IFactoryObject + /// - /// A Spring FactoryObject that returns TIBCO.EMS.ILookupContext. Use the returned - /// ILookupContext to do you lookups at runtime. + /// Returns the TIBCO.EMS.ILookupContext /// - /// - /// - /// Important properties to set are JndiProperties and JndiContexType. JndiContextType is set to - /// LookupContextFactory.TIBJMS_NAMING_CONT by default. - /// - /// To lookup objects at startup time and cache their values, as well as provide a - /// default value if lookup fail, - /// - /// - /// Mark Pollack - public class LookupContextFactoryObject : JndiLocatorSupport, IFactoryObject + /// TIBCO.EMS.ILookupContext + public object GetObject() { - #region Implementation of IFactoryObject - - /// - /// Returns the TIBCO.EMS.ILookupContext - /// - /// TIBCO.EMS.ILookupContext - public object GetObject() - { - return this.JndiLookupContext; - } - - /// - /// Return typeof(TIBCO.EMS.ILookupContext) - /// - public Type ObjectType - { - get { return typeof (ILookupContext); } - } - - /// - /// Returns true - /// - public bool IsSingleton - { - get { return true; } - } - - #endregion - + return this.JndiLookupContext; } + + /// + /// Return typeof(TIBCO.EMS.ILookupContext) + /// + public Type ObjectType + { + get { return typeof(ILookupContext); } + } + + /// + /// Returns true + /// + public bool IsSingleton + { + get { return true; } + } + + #endregion } diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Jndi/TypeMismatchNamingException.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Jndi/TypeMismatchNamingException.cs index ce4dc70c..93553d06 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Jndi/TypeMismatchNamingException.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Jndi/TypeMismatchNamingException.cs @@ -18,64 +18,63 @@ #endregion -namespace Spring.Objects.Factory +namespace Spring.Objects.Factory; + +/// +/// Exception thrown if a type mismatch is encountered for an object +/// located in a JNDI environment. +/// +/// Juergen Hoeller +/// Mark Pollack (.NET) +[Serializable] +public class TypeMismatchNamingException : NamingException { - /// - /// Exception thrown if a type mismatch is encountered for an object - /// located in a JNDI environment. - /// - /// Juergen Hoeller - /// Mark Pollack (.NET) - [Serializable] - public class TypeMismatchNamingException : NamingException - { - private Type requiredType; + private Type requiredType; - private Type actualType; + private Type actualType; - /// - /// Creates a new instance of the - /// class. - /// - /// - /// A message about the exception. - /// - public TypeMismatchNamingException(string message) - : base(message) - { - } + /// + /// Creates a new instance of the + /// class. + /// + /// + /// A message about the exception. + /// + public TypeMismatchNamingException(string message) + : base(message) + { + } - /// - /// Initializes a new instance of the class - /// building an explanation text from the given arguments. - /// - /// The Jndi name. - /// Type required type of the lookup. - /// The actual type that the lookup returned. - public TypeMismatchNamingException(String jndiName, Type requiredType, Type actualType) : - base("Object of type [" + actualType + "] available at JNDI location [" + - jndiName + "] is not assignable to [" + requiredType.Name + "]") - { - this.requiredType = requiredType; - this.actualType = actualType; - } + /// + /// Initializes a new instance of the class + /// building an explanation text from the given arguments. + /// + /// The Jndi name. + /// Type required type of the lookup. + /// The actual type that the lookup returned. + public TypeMismatchNamingException(String jndiName, Type requiredType, Type actualType) : + base("Object of type [" + actualType + "] available at JNDI location [" + + jndiName + "] is not assignable to [" + requiredType.Name + "]") + { + this.requiredType = requiredType; + this.actualType = actualType; + } - /// - /// Gets the actual type that the lookup returned, if available. - /// - /// The actual type that the lookup. - public Type ActualType - { - get { return actualType; } - } + /// + /// Gets the actual type that the lookup returned, if available. + /// + /// The actual type that the lookup. + public Type ActualType + { + get { return actualType; } + } - /// - /// Gets the required type for the lookup, if available. - /// - /// The equired type for the lookup - public Type RequiredType - { - get { return requiredType; } - } - } + /// + /// Gets the required type for the lookup, if available. + /// + /// The equired type for the lookup + public Type RequiredType + { + get { return requiredType; } + } } diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Listener/AbstractListenerContainer.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Listener/AbstractListenerContainer.cs index fca04159..8438c8e5 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Listener/AbstractListenerContainer.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Listener/AbstractListenerContainer.cs @@ -26,520 +26,518 @@ using Spring.Messaging.Ems.Support; using Spring.Messaging.Ems.Support.Destinations; using Spring.Objects.Factory; -namespace Spring.Messaging.Ems.Listener +namespace Spring.Messaging.Ems.Listener; + +/// +/// Common base class for all containers which need to implement listening +/// based on a Connection (either shared or freshly obtained for each attempt). +/// Inherits basic Connection and Session configuration handling from the +/// base class. +/// +/// +/// This class provides basic lifecycle management, in particular management +/// of a shared Connection. Subclasses are supposed to plug into this +/// lifecycle, implementing the as well as +/// +/// +/// +/// +/// +/// Mark Pollack +public abstract class AbstractListenerContainer : EmsDestinationAccessor, ILifecycle, IObjectNameAware, IDisposable { + #region Logging + + private readonly ILogger logger = LogManager.GetLogger(); + + #endregion + + #region Fields + + private String clientId; + + private bool autoStartup = true; + + private string objectName; + + private IConnection sharedConnection; + + private bool sharedConnectionStarted = false; + /// - /// Common base class for all containers which need to implement listening - /// based on a Connection (either shared or freshly obtained for each attempt). - /// Inherits basic Connection and Session configuration handling from the - /// base class. + /// The monitor object to lock on when performing operations on the connection. + /// + protected object sharedConnectionMonitor = new object(); + + private volatile bool active = false; + + private bool running = false; + + /// + /// The monitor object to lock on when performing operations that update the lifecycle of the container. + /// + protected object lifecycleMonitor = new object(); + + #endregion + + /// + /// Gets or sets the client id for a shared Connection created and used by this container. /// - /// - /// This class provides basic lifecycle management, in particular management - /// of a shared Connection. Subclasses are supposed to plug into this - /// lifecycle, implementing the as well as - /// - /// /// - /// + /// Note that client ids need to be unique among all active Connections + /// of the underlying JMS provider. Furthermore, a client id can only be + /// assigned if the original ConnectionFactory hasn't already assigned one. /// - /// Mark Pollack - public abstract class AbstractListenerContainer : EmsDestinationAccessor, ILifecycle, IObjectNameAware, IDisposable + /// The client id. + public string ClientId { - #region Logging + set { clientId = value; } + get { return clientId; } + } - private readonly ILogger logger = LogManager.GetLogger(); + /// Set whether to automatically start the listener after initialization. + ///

Default is "true"; set this to "false" to allow for manual startup.

+ ///
+ public virtual bool AutoStartup + { + set { this.autoStartup = value; } + } - #endregion + /// + /// Set the name of the object in the object factory that created this object. + /// + /// The name of the object in the factory. + /// + ///

+ /// Invoked after population of normal object properties but before an init + /// callback like 's + /// + /// method or a custom init-method. + ///

+ ///
+ public string ObjectName + { + set { objectName = value; } + } - #region Fields - - private String clientId; - - private bool autoStartup = true; - - private string objectName; - - private IConnection sharedConnection; - - private bool sharedConnectionStarted = false; - - /// - /// The monitor object to lock on when performing operations on the connection. - /// - protected object sharedConnectionMonitor = new object(); - - private volatile bool active = false; - - private bool running = false; - - /// - /// The monitor object to lock on when performing operations that update the lifecycle of the container. - /// - protected object lifecycleMonitor = new object(); - - #endregion - - /// - /// Gets or sets the client id for a shared Connection created and used by this container. - /// - /// - /// Note that client ids need to be unique among all active Connections - /// of the underlying JMS provider. Furthermore, a client id can only be - /// assigned if the original ConnectionFactory hasn't already assigned one. - /// - /// The client id. - public string ClientId + /// + /// Gets a value indicating whether this container is currently running, + /// that is, whether it has been started and not stopped yet. + /// + /// + /// true if this container is running; otherwise, false. + /// + public bool IsRunning + { + get { - set { clientId = value; } - get { return clientId; } - } - - /// Set whether to automatically start the listener after initialization. - ///

Default is "true"; set this to "false" to allow for manual startup.

- ///
- public virtual bool AutoStartup - { - set { this.autoStartup = value; } - } - - /// - /// Set the name of the object in the object factory that created this object. - /// - /// The name of the object in the factory. - /// - ///

- /// Invoked after population of normal object properties but before an init - /// callback like 's - /// - /// method or a custom init-method. - ///

- ///
- public string ObjectName - { - set { objectName = value; } - } - - /// - /// Gets a value indicating whether this container is currently running, - /// that is, whether it has been started and not stopped yet. - /// - /// - /// true if this container is running; otherwise, false. - /// - public bool IsRunning - { - get + lock (lifecycleMonitor) { - lock (lifecycleMonitor) - { - return (running && RunningAllowed); - } + return (running && RunningAllowed); } } + } - /// - /// Gets a value indicating whether this container's listeners are generally allowed to run. - /// - /// - /// - /// >This implementation always returns true; the default 'running' - /// state is purely determined by /. - /// - /// - /// Subclasses may override this method to check against temporary - /// conditions that prevent listeners from actually running. In other words, - /// they may apply further restrictions to the 'running' state, returning - /// false if such a restriction prevents listeners from running. - /// - /// - /// true if running allowed; otherwise, false. - protected virtual bool RunningAllowed + /// + /// Gets a value indicating whether this container's listeners are generally allowed to run. + /// + /// + /// + /// >This implementation always returns true; the default 'running' + /// state is purely determined by /. + /// + /// + /// Subclasses may override this method to check against temporary + /// conditions that prevent listeners from actually running. In other words, + /// they may apply further restrictions to the 'running' state, returning + /// false if such a restriction prevents listeners from running. + /// + /// + /// true if running allowed; otherwise, false. + protected virtual bool RunningAllowed + { + get { - get { - return true; } + return true; } + } - /// - /// Gets a value indicating whether this container is currently active, - /// that is, whether it has been set up but not shut down yet. - /// - /// true if active; otherwise, false. - public virtual bool Active - { - get - { - lock (this.lifecycleMonitor) - { - return this.active; - } - } - - } - - /// Return whether a shared EMS Connection should be maintained - /// by this listener container base class. - /// - /// - protected abstract bool SharedConnectionEnabled { get; } - - /// - /// Gets the shared connection maintained by this container. - /// Available after initialization. - /// - /// The shared connection (never null) - /// if this container does not maintain a - /// shared Connection, or if the Connection hasn't been initialized yet. - /// - /// - protected IConnection SharedConnection - { - get - { - if (!SharedConnectionEnabled) - { - throw new InvalidOperationException("This listener container does not maintain a shared Connection"); - } - lock (this.sharedConnectionMonitor) - { - if (this.sharedConnection == null) - { - throw new SharedConnectionNotInitializedException("This listener container's shared Connection has not been initialized yet"); - } - return this.sharedConnection; - } - } - } - - /// - /// Call base class method, then and then - /// - public override void AfterPropertiesSet() - { - base.AfterPropertiesSet(); - ValidateConfiguration(); - Initialize(); - } - - /// - /// Validates the configuration of this container. The default implementation - /// is empty. To be overriden in subclasses. - /// - protected virtual void ValidateConfiguration() - { - - } - - /// - /// Calls when the application context destroys the container instance. - /// - public void Dispose() - { - Shutdown(); - } - - - /// - /// Initializes this container. Creates a Connection, starts the Connection - /// (if the property hasn't been turned off), and calls - /// . - /// - /// If startup failed - public virtual void Initialize() - { - try - { - lock (this.lifecycleMonitor) - { - this.active = true; - System.Threading.Monitor.PulseAll(this.lifecycleMonitor); - } - - if (this.autoStartup) - { - DoStart(); - } - - DoInitialize(); - - } - catch (Exception) - { - lock (this.sharedConnectionMonitor) - { - ConnectionFactoryUtils.ReleaseConnection(sharedConnection, ConnectionFactory, autoStartup); - } - throw; - } - } - - /// - /// Stop the shared connection, call , and close this container. - /// - public virtual void Shutdown() - { - logger.LogDebug("Shutting down message listener container"); - bool wasRunning = false; - lock (this.lifecycleMonitor) - { - wasRunning = this.running; - this.running = false; - this.active = false; - System.Threading.Monitor.PulseAll(this.lifecycleMonitor); - } - - if (wasRunning && SharedConnectionEnabled) - { - try - { - StopSharedConnection(); - } catch (Exception ex) - { - logger.LogDebug(ex, "Could not stop EMS Connection on shutdown"); - } - } - - // Shut down the invokers - try - { - DoShutdown(); - } - finally - { - lock (this.sharedConnectionMonitor) - { - ConnectionFactoryUtils.ReleaseConnection(this.sharedConnection, ConnectionFactory, false); - } - } - } - - /// - /// Starts this container. - /// - /// if starting failed. - public void Start() - { - DoStart(); - } - - /// - /// Start the shared Connection, if any, and notify all invoker tasks. - /// - protected virtual void DoStart() - { - // Lazily establish a shared Connection, if necessary. - if (SharedConnectionEnabled) - { - EstablishSharedConnection(); - } - - lock (this.lifecycleMonitor) - { - running = true; - System.Threading.Monitor.PulseAll(this.lifecycleMonitor); - } - - // Start the shared Connection, if any. - if (SharedConnectionEnabled) - { - StartSharedConnection(); - } - } - - /// - /// Stops this container. - /// - /// if stopping failed. - public void Stop() - { - DoStop(); - } - - /// - /// Notify all invoker tasks and stop the shared Connection, if any. - /// - /// if thrown by EMS API methods. - /// - protected virtual void DoStop() + /// + /// Gets a value indicating whether this container is currently active, + /// that is, whether it has been set up but not shut down yet. + /// + /// true if active; otherwise, false. + public virtual bool Active + { + get { lock (this.lifecycleMonitor) { - this.running = false; + return this.active; + } + } + } + + /// Return whether a shared EMS Connection should be maintained + /// by this listener container base class. + /// + /// + protected abstract bool SharedConnectionEnabled { get; } + + /// + /// Gets the shared connection maintained by this container. + /// Available after initialization. + /// + /// The shared connection (never null) + /// if this container does not maintain a + /// shared Connection, or if the Connection hasn't been initialized yet. + /// + /// + protected IConnection SharedConnection + { + get + { + if (!SharedConnectionEnabled) + { + throw new InvalidOperationException("This listener container does not maintain a shared Connection"); + } + + lock (this.sharedConnectionMonitor) + { + if (this.sharedConnection == null) + { + throw new SharedConnectionNotInitializedException("This listener container's shared Connection has not been initialized yet"); + } + + return this.sharedConnection; + } + } + } + + /// + /// Call base class method, then and then + /// + public override void AfterPropertiesSet() + { + base.AfterPropertiesSet(); + ValidateConfiguration(); + Initialize(); + } + + /// + /// Validates the configuration of this container. The default implementation + /// is empty. To be overriden in subclasses. + /// + protected virtual void ValidateConfiguration() + { + } + + /// + /// Calls when the application context destroys the container instance. + /// + public void Dispose() + { + Shutdown(); + } + + /// + /// Initializes this container. Creates a Connection, starts the Connection + /// (if the property hasn't been turned off), and calls + /// . + /// + /// If startup failed + public virtual void Initialize() + { + try + { + lock (this.lifecycleMonitor) + { + this.active = true; System.Threading.Monitor.PulseAll(this.lifecycleMonitor); } - if (SharedConnectionEnabled) + if (this.autoStartup) { - StopSharedConnection(); + DoStart(); } + + DoInitialize(); } - - /// - /// Register any invokers within this container. - /// Subclasses need to implement this method for their specific - /// invoker management process. A shared Connection, if any, will already have been - /// started at this point. - /// - protected abstract void DoInitialize(); - - - /// - /// Close the registered invokers. Subclasses need to implement this method - /// for their specific invoker management process. A shared Connection, if any, - /// will automatically be closed afterwards. - /// - protected abstract void DoShutdown(); - - - /// - /// Establishes a shared Connection for this container. - /// - /// - /// - /// The default implementation delegates to - /// which does one immediate attempt and throws an exception if it fails. - /// Can be overridden to have a recovery process in place, retrying - /// until a Connection can be successfully established. - /// - /// - /// If thrown by EMS API methods - protected virtual void EstablishSharedConnection() - { - lock (sharedConnectionMonitor) - { - if (sharedConnection == null) - { - sharedConnection = CreateSharedConnection(); - logger.LogDebug("Established shared EMS Connection"); - } - } - } - - /// - /// Refreshes the shared connection that this container holds. - /// - /// - /// Called on startup and also after an infrastructure exception - /// that occurred during invoker setup and/or execution. - /// - /// If thrown by EMS API methods - protected void RefreshSharedConnection() - { - lock (sharedConnectionMonitor) - { - ConnectionFactoryUtils.ReleaseConnection(sharedConnection, ConnectionFactory, sharedConnectionStarted); - sharedConnection = CreateSharedConnection(); - if (sharedConnectionStarted) - { - sharedConnection.Start(); - } - } - } - - /// - /// Creates the shared connection for this container. - /// - /// - /// The default implementation creates a standard Connection - /// and prepares it through - /// - /// the prepared Connection - /// if the creation failed. - protected virtual IConnection CreateSharedConnection() - { - IConnection con = CreateConnection(); - try - { - PrepareSharedConnection(con); - return con; - } catch (EMSException) - { - EmsUtils.CloseConnection(con); - throw; - } - } - - /// - /// Prepares the given connection, which is about to be registered - /// as shared Connection for this container. - /// - /// - /// The default implementation sets the specified client id, if any. - /// Subclasses can override this to apply further settings. - /// - /// The connection to prepare. - /// If the preparation efforts failed. - protected virtual void PrepareSharedConnection(IConnection connection) - { - if (ClientId != null) - { - connection.ClientID = ClientId; - } - } - - - /// - /// Starts the shared connection. - /// - /// If thrown by EMS API methods - /// - protected virtual void StartSharedConnection() - { - lock (sharedConnectionMonitor) - { - if (sharedConnection != null) - { - try - { - sharedConnectionStarted = true; - sharedConnection.Start(); - } - catch (Exception ex) - { - logger.LogWarning(ex, "Ignoring Connection start exception - assuming already started"); - } - } - } - } - - /// - /// Stops the shared connection. - /// - /// if thrown by EMS API methods. - protected virtual void StopSharedConnection() + catch (Exception) { lock (this.sharedConnectionMonitor) { - if (this.sharedConnection != null) - { - try - { - this.sharedConnectionStarted = false; - this.sharedConnection.Stop(); - } - catch (System.InvalidOperationException ex) - { - logger.LogWarning(ex, "Ignoring Connection stop exception - assuming already stopped"); - } - } + ConnectionFactoryUtils.ReleaseConnection(sharedConnection, ConnectionFactory, autoStartup); } - } + throw; + } } /// - /// Exception that indicates that the initial setup of this container's - /// shared Connection failed. This is indicating to invokers that they need - /// to establish the shared Connection themselves on first access. + /// Stop the shared connection, call , and close this container. /// - public class SharedConnectionNotInitializedException : EMSException + public virtual void Shutdown() { - /// - /// Initializes a new instance of the class. - /// - /// The message. - public SharedConnectionNotInitializedException(string message) : base(message) + logger.LogDebug("Shutting down message listener container"); + bool wasRunning = false; + lock (this.lifecycleMonitor) { + wasRunning = this.running; + this.running = false; + this.active = false; + System.Threading.Monitor.PulseAll(this.lifecycleMonitor); + } + + if (wasRunning && SharedConnectionEnabled) + { + try + { + StopSharedConnection(); + } + catch (Exception ex) + { + logger.LogDebug(ex, "Could not stop EMS Connection on shutdown"); + } + } + + // Shut down the invokers + try + { + DoShutdown(); + } + finally + { + lock (this.sharedConnectionMonitor) + { + ConnectionFactoryUtils.ReleaseConnection(this.sharedConnection, ConnectionFactory, false); + } + } + } + + /// + /// Starts this container. + /// + /// if starting failed. + public void Start() + { + DoStart(); + } + + /// + /// Start the shared Connection, if any, and notify all invoker tasks. + /// + protected virtual void DoStart() + { + // Lazily establish a shared Connection, if necessary. + if (SharedConnectionEnabled) + { + EstablishSharedConnection(); + } + + lock (this.lifecycleMonitor) + { + running = true; + System.Threading.Monitor.PulseAll(this.lifecycleMonitor); + } + + // Start the shared Connection, if any. + if (SharedConnectionEnabled) + { + StartSharedConnection(); + } + } + + /// + /// Stops this container. + /// + /// if stopping failed. + public void Stop() + { + DoStop(); + } + + /// + /// Notify all invoker tasks and stop the shared Connection, if any. + /// + /// if thrown by EMS API methods. + /// + protected virtual void DoStop() + { + lock (this.lifecycleMonitor) + { + this.running = false; + System.Threading.Monitor.PulseAll(this.lifecycleMonitor); + } + + if (SharedConnectionEnabled) + { + StopSharedConnection(); + } + } + + /// + /// Register any invokers within this container. + /// Subclasses need to implement this method for their specific + /// invoker management process. A shared Connection, if any, will already have been + /// started at this point. + /// + protected abstract void DoInitialize(); + + /// + /// Close the registered invokers. Subclasses need to implement this method + /// for their specific invoker management process. A shared Connection, if any, + /// will automatically be closed afterwards. + /// + protected abstract void DoShutdown(); + + /// + /// Establishes a shared Connection for this container. + /// + /// + /// + /// The default implementation delegates to + /// which does one immediate attempt and throws an exception if it fails. + /// Can be overridden to have a recovery process in place, retrying + /// until a Connection can be successfully established. + /// + /// + /// If thrown by EMS API methods + protected virtual void EstablishSharedConnection() + { + lock (sharedConnectionMonitor) + { + if (sharedConnection == null) + { + sharedConnection = CreateSharedConnection(); + logger.LogDebug("Established shared EMS Connection"); + } + } + } + + /// + /// Refreshes the shared connection that this container holds. + /// + /// + /// Called on startup and also after an infrastructure exception + /// that occurred during invoker setup and/or execution. + /// + /// If thrown by EMS API methods + protected void RefreshSharedConnection() + { + lock (sharedConnectionMonitor) + { + ConnectionFactoryUtils.ReleaseConnection(sharedConnection, ConnectionFactory, sharedConnectionStarted); + sharedConnection = CreateSharedConnection(); + if (sharedConnectionStarted) + { + sharedConnection.Start(); + } + } + } + + /// + /// Creates the shared connection for this container. + /// + /// + /// The default implementation creates a standard Connection + /// and prepares it through + /// + /// the prepared Connection + /// if the creation failed. + protected virtual IConnection CreateSharedConnection() + { + IConnection con = CreateConnection(); + try + { + PrepareSharedConnection(con); + return con; + } + catch (EMSException) + { + EmsUtils.CloseConnection(con); + throw; + } + } + + /// + /// Prepares the given connection, which is about to be registered + /// as shared Connection for this container. + /// + /// + /// The default implementation sets the specified client id, if any. + /// Subclasses can override this to apply further settings. + /// + /// The connection to prepare. + /// If the preparation efforts failed. + protected virtual void PrepareSharedConnection(IConnection connection) + { + if (ClientId != null) + { + connection.ClientID = ClientId; + } + } + + /// + /// Starts the shared connection. + /// + /// If thrown by EMS API methods + /// + protected virtual void StartSharedConnection() + { + lock (sharedConnectionMonitor) + { + if (sharedConnection != null) + { + try + { + sharedConnectionStarted = true; + sharedConnection.Start(); + } + catch (Exception ex) + { + logger.LogWarning(ex, "Ignoring Connection start exception - assuming already started"); + } + } + } + } + + /// + /// Stops the shared connection. + /// + /// if thrown by EMS API methods. + protected virtual void StopSharedConnection() + { + lock (this.sharedConnectionMonitor) + { + if (this.sharedConnection != null) + { + try + { + this.sharedConnectionStarted = false; + this.sharedConnection.Stop(); + } + catch (System.InvalidOperationException ex) + { + logger.LogWarning(ex, "Ignoring Connection stop exception - assuming already stopped"); + } + } } } } + +/// +/// Exception that indicates that the initial setup of this container's +/// shared Connection failed. This is indicating to invokers that they need +/// to establish the shared Connection themselves on first access. +/// +public class SharedConnectionNotInitializedException : EMSException +{ + /// + /// Initializes a new instance of the class. + /// + /// The message. + public SharedConnectionNotInitializedException(string message) : base(message) + { + } +} diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Listener/AbstractMessageListenerContainer.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Listener/AbstractMessageListenerContainer.cs index da87b9fd..11f0c7cf 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Listener/AbstractMessageListenerContainer.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Listener/AbstractMessageListenerContainer.cs @@ -24,484 +24,503 @@ using Spring.Messaging.Ems.Core; using Spring.Messaging.Ems.Support; using Spring.Util; -namespace Spring.Messaging.Ems.Listener +namespace Spring.Messaging.Ems.Listener; + +/// +/// Abstract base class for message listener containers. Can either host +/// a standard EMS MessageListener or a Spring-specific +/// +/// +public abstract class AbstractMessageListenerContainer : AbstractListenerContainer { + #region Logging + + private readonly ILogger logger = LogManager.GetLogger(); + + #endregion + + #region Fields + + private object destination; + + private String messageSelector; + + private object messageListener; + + private bool subscriptionDurable = false; + + private string durableSubscriptionName; + + private IExceptionListener exceptionListener; + + private IErrorHandler errorHandler; + + private bool exposeListenerSession = true; + + private bool acceptMessagesWhileStopping = false; + + #endregion + + #region Properties + /// - /// Abstract base class for message listener containers. Can either host - /// a standard EMS MessageListener or a Spring-specific - /// + /// Gets or sets the destination to receive messages from. Will be null + /// if the configured destination is not an actual Destination type; + /// c.f. when the destination is a String. /// - public abstract class AbstractMessageListenerContainer : AbstractListenerContainer + /// The destination. + public Destination Destination { - #region Logging - - private readonly ILogger logger = LogManager.GetLogger(); - - #endregion - - #region Fields - - private object destination; - - private String messageSelector; - - private object messageListener; - - private bool subscriptionDurable = false; - - private string durableSubscriptionName; - - private IExceptionListener exceptionListener; - - private IErrorHandler errorHandler; - - private bool exposeListenerSession = true; - - private bool acceptMessagesWhileStopping = false; - - #endregion - - #region Properties - - /// - /// Gets or sets the destination to receive messages from. Will be null - /// if the configured destination is not an actual Destination type; - /// c.f. when the destination is a String. - /// - /// The destination. - public Destination Destination + get { - get + return (this.destination is Destination ? (Destination) this.destination : null); + } + set + { + AssertUtils.ArgumentNotNull(value, "destination"); + destination = value; + if (destination is Topic && !(destination is Queue)) { - return (this.destination is Destination ? (Destination) this.destination : null); + PubSubDomain = true; } - set + } + } + + /// + /// Gets or sets the name of the destination to receive messages from. + /// Will be null if the configured destination is not a + /// string type; c.f. when it is an actual Destination object. + /// + /// The name of the destination. + public string DestinationName + { + get + { + return (this.destination is string ? (string) this.destination : null); + } + set + { + AssertUtils.ArgumentNotNull(value, "destinationName must not be null"); + this.destination = value; + } + } + + /// + /// Gets or sets the message selector. + /// + /// The message selector expression (or null if none).. + public string MessageSelector + { + get { return messageSelector; } + set { messageSelector = value; } + } + + /// + /// Gets or sets the message listener to register. + /// + /// + /// + /// + /// This can be either a standard EMS MessageListener object or a + /// Spring object. + /// + /// + /// The message listener. + public object MessageListener + { + set + { + CheckMessageListener(value); + if (durableSubscriptionName == null) { - AssertUtils.ArgumentNotNull(value, "destination"); - destination = value; - if (destination is Topic && !(destination is Queue)) + // Use message listener class name as default name for a durable subscription. + durableSubscriptionName = value.GetType().FullName; + } + + messageListener = value; + } + get + { + return messageListener; + } + } + + /// + /// Gets or sets a value indicating whether the subscription is durable. + /// + /// + /// Set whether to make the subscription durable. The durable subscription name + /// to be used can be specified through the "DurableSubscriptionName" property. + /// Default is "false". Set this to "true" to register a durable subscription, + /// typically in combination with a "DurableSubscriptionName" value (unless + /// your message listener class name is good enough as subscription name). + /// + /// Only makes sense when listening to a topic (pub-sub domain). + /// + /// true if the subscription is durable; otherwise, false. + public bool SubscriptionDurable + { + get { return subscriptionDurable; } + set { subscriptionDurable = value; } + } + + /// + /// Gets or sets the name of the durable subscription to create. + /// + /// + /// To be applied in case of a topic (pub-sub domain) with subscription durability activated. + /// The durable subscription name needs to be unique within this client's + /// client id. Default is the class name of the specified message listener. + /// Note: Only 1 concurrent consumer (which is the default of this + /// message listener container) is allowed for each durable subscription. + /// + /// + /// The name of the durable subscription. + public string DurableSubscriptionName + { + get + { + return durableSubscriptionName; + } + set + { + AssertUtils.ArgumentNotNull(value, "durableSubscriptionName must not be null"); + durableSubscriptionName = value; + } + } + + /// + /// Gets or sets the exception listener to notify in case of a EMSException thrown + /// by the registered message listener or the invocation infrastructure. + /// + /// The exception listener. + public IExceptionListener ExceptionListener + { + get { return exceptionListener; } + set { exceptionListener = value; } + } + + /// + /// Sets an ErrorHandler to be invoked in case of any uncaught exceptions thrown + /// while processing a Message. By default there will be no ErrorHandler + /// so that error-level logging is the only result. + /// + /// The error handler. + public IErrorHandler ErrorHandler + { + set { errorHandler = value; } + } + + /// + /// Gets or sets a value indicating whether to expose listener session to a registered + /// as well as to calls. + /// + /// + /// Default is "true", reusing the listener's Session. + /// Turn this off to expose a fresh Session fetched from the same + /// underlying Connection instead, which might be necessary + /// on some messaging providers. + /// Note that Sessions managed by an external transaction manager will + /// always get exposed to + /// calls. So in terms of EmsTemplate exposure, this setting only affects + /// locally transacted Sessions. + /// + /// + /// + /// true if expose listener session; otherwise, false. + /// + public bool ExposeListenerSession + { + get { return exposeListenerSession; } + set { exposeListenerSession = value; } + } + + /// + /// Gets or sets a value indicating whether to accept messages while + /// the listener container is in the process of stopping. + /// + /// + /// + /// Return whether to accept received messages while the listener container + /// receive attempt. Switch this flag on to fully process such messages + /// even in the stopping phase, with the drawback that even newly sent + /// messages might still get processed (if coming in before all receive + /// timeouts have expired). + /// + /// + /// Aborting receive attempts for such incoming messages + /// might lead to the provider's retry count decreasing for the affected + /// messages. If you have a high number of concurrent consumers, make sure + /// that the number of retries is higher than the number of consumers, + /// to be on the safe side for all potential stopping scenarios. + /// + /// + /// + /// true if accept messages while in the process of stopping; otherwise, false. + /// + public bool AcceptMessagesWhileStopping + { + get { return acceptMessagesWhileStopping; } + set { acceptMessagesWhileStopping = value; } + } + + #endregion + + /// + /// Validate that the destination is not null and that if the subscription is durable, then we are not + /// using the Pub/Sub domain. + /// + protected override void ValidateConfiguration() + { + if (this.destination == null) + { + throw new ArgumentException("Property 'destination' or 'DestinationName' is required"); + } + + if (SubscriptionDurable && !PubSubDomain) + { + throw new ArgumentException("A durable subscription requires a topic (pub-sub domain)"); + } + } + + #region Template methods for listeners + + /// + /// Executes the specified listener, + /// committing or rolling back the transaction afterwards (if necessary). + /// + /// The session to operate on. + /// The received message. + /// + /// + /// + /// + public virtual void ExecuteListener(ISession session, Message message) + { + try + { + DoExecuteListener(session, message); + } + catch (Exception ex) + { + HandleListenerException(ex); + } + } + + /// + /// Executes the specified listener, + /// committing or rolling back the transaction afterwards (if necessary). + /// + /// The session to operate on. + /// The received message. + /// If thrown by EMS API methods. + /// + /// + /// + protected virtual void DoExecuteListener(ISession session, Message message) + { + if (!AcceptMessagesWhileStopping && !IsRunning) + { + #region Logging + + if (logger.IsEnabled(LogLevel.Warning)) + { + logger.LogWarning("Rejecting received message because of the listener container " + + "having been stopped in the meantime: " + message); + } + + #endregion + + RollbackIfNecessary(session); + throw new MessageRejectedWhileStoppingException(); + } + + try + { + InvokeListener(session, message); + } + catch (Exception ex) + { + RollbackOnExceptionIfNecessary(session, ex); + throw; + } + + CommitIfNecessary(session, message); + } + + /// + /// Invokes the specified listener: either as standard EMS MessageListener + /// or (preferably) as Spring ISessionAwareMessageListener. + /// + /// The session to operate on. + /// The received message. + /// If thrown by EMS API methods. + /// + protected virtual void InvokeListener(ISession session, Message message) + { + object listener = MessageListener; + if (listener is ISessionAwareMessageListener) + { + DoInvokeListener((ISessionAwareMessageListener) listener, session, message); + } + + else if (listener is IMessageListener) + { + DoInvokeListener((IMessageListener) listener, message); + } + else if (listener != null) + { + throw new ArgumentException("Only MessageListener and ISessionAwareMessageListener supported"); + } + else + { + throw new InvalidOperationException("No message listener specified - see property MessageListener"); + } + } + + /// + /// Invoke the specified listener as Spring ISessionAwareMessageListener, + /// exposing a new EMS Session (potentially with its own transaction) + /// to the listener if demanded. + /// + /// The Spring ISessionAwareMessageListener to invoke. + /// The session to operate on. + /// The received message. + /// If thrown by EMS API methods. + /// + /// + protected virtual void DoInvokeListener(ISessionAwareMessageListener listener, ISession session, Message message) + { + IConnection conToClose = null; + ISession sessionToClose = null; + try + { + ISession sessionToUse = session; + if (!ExposeListenerSession) + { + //We need to expose a separate Session. + conToClose = CreateConnection(); + sessionToClose = CreateSession(conToClose); + sessionToUse = sessionToClose; + } + + // Actually invoke the message listener + if (logger.IsEnabled(LogLevel.Debug)) + { + logger.LogDebug("Invoking listener with message of type [" + message.GetType() + + "] and session [" + sessionToUse + "]"); + } + + listener.OnMessage(message, sessionToUse); + // Clean up specially exposed Session, if any + if (sessionToUse != session) + { + if (sessionToUse.Transacted && SessionTransacted) { - PubSubDomain = true; - } - - } - } - - - /// - /// Gets or sets the name of the destination to receive messages from. - /// Will be null if the configured destination is not a - /// string type; c.f. when it is an actual Destination object. - /// - /// The name of the destination. - public string DestinationName - { - get - { - return (this.destination is string ? (string) this.destination : null); - - } - set - { - AssertUtils.ArgumentNotNull(value, "destinationName must not be null"); - this.destination = value; - } - } - - - /// - /// Gets or sets the message selector. - /// - /// The message selector expression (or null if none).. - public string MessageSelector - { - get { return messageSelector; } - set { messageSelector = value; } - } - - - /// - /// Gets or sets the message listener to register. - /// - /// - /// - /// - /// This can be either a standard EMS MessageListener object or a - /// Spring object. - /// - /// - /// The message listener. - public object MessageListener - { - set - { - CheckMessageListener(value); - if (durableSubscriptionName == null) - { - // Use message listener class name as default name for a durable subscription. - durableSubscriptionName = value.GetType().FullName; - } - messageListener = value; - } - get - { - return messageListener; - } - } - - - /// - /// Gets or sets a value indicating whether the subscription is durable. - /// - /// - /// Set whether to make the subscription durable. The durable subscription name - /// to be used can be specified through the "DurableSubscriptionName" property. - /// Default is "false". Set this to "true" to register a durable subscription, - /// typically in combination with a "DurableSubscriptionName" value (unless - /// your message listener class name is good enough as subscription name). - /// - /// Only makes sense when listening to a topic (pub-sub domain). - /// - /// true if the subscription is durable; otherwise, false. - public bool SubscriptionDurable - { - get { return subscriptionDurable; } - set { subscriptionDurable = value; } - } - - - /// - /// Gets or sets the name of the durable subscription to create. - /// - /// - /// To be applied in case of a topic (pub-sub domain) with subscription durability activated. - /// The durable subscription name needs to be unique within this client's - /// client id. Default is the class name of the specified message listener. - /// Note: Only 1 concurrent consumer (which is the default of this - /// message listener container) is allowed for each durable subscription. - /// - /// - /// The name of the durable subscription. - public string DurableSubscriptionName - { - get - { - return durableSubscriptionName; - } - set - { - AssertUtils.ArgumentNotNull(value, "durableSubscriptionName must not be null"); - durableSubscriptionName = value; - } - } - - - /// - /// Gets or sets the exception listener to notify in case of a EMSException thrown - /// by the registered message listener or the invocation infrastructure. - /// - /// The exception listener. - public IExceptionListener ExceptionListener - { - get { return exceptionListener; } - set { exceptionListener = value; } - } - - /// - /// Sets an ErrorHandler to be invoked in case of any uncaught exceptions thrown - /// while processing a Message. By default there will be no ErrorHandler - /// so that error-level logging is the only result. - /// - /// The error handler. - public IErrorHandler ErrorHandler - { - set { errorHandler = value; } - } - - - /// - /// Gets or sets a value indicating whether to expose listener session to a registered - /// as well as to calls. - /// - /// - /// Default is "true", reusing the listener's Session. - /// Turn this off to expose a fresh Session fetched from the same - /// underlying Connection instead, which might be necessary - /// on some messaging providers. - /// Note that Sessions managed by an external transaction manager will - /// always get exposed to - /// calls. So in terms of EmsTemplate exposure, this setting only affects - /// locally transacted Sessions. - /// - /// - /// - /// true if expose listener session; otherwise, false. - /// - public bool ExposeListenerSession - { - get { return exposeListenerSession; } - set { exposeListenerSession = value; } - } - - - /// - /// Gets or sets a value indicating whether to accept messages while - /// the listener container is in the process of stopping. - /// - /// - /// - /// Return whether to accept received messages while the listener container - /// receive attempt. Switch this flag on to fully process such messages - /// even in the stopping phase, with the drawback that even newly sent - /// messages might still get processed (if coming in before all receive - /// timeouts have expired). - /// - /// - /// Aborting receive attempts for such incoming messages - /// might lead to the provider's retry count decreasing for the affected - /// messages. If you have a high number of concurrent consumers, make sure - /// that the number of retries is higher than the number of consumers, - /// to be on the safe side for all potential stopping scenarios. - /// - /// - /// - /// true if accept messages while in the process of stopping; otherwise, false. - /// - public bool AcceptMessagesWhileStopping - { - get { return acceptMessagesWhileStopping; } - set { acceptMessagesWhileStopping = value; } - } - - - #endregion - - - - /// - /// Validate that the destination is not null and that if the subscription is durable, then we are not - /// using the Pub/Sub domain. - /// - protected override void ValidateConfiguration() - { - if (this.destination == null) - { - throw new ArgumentException("Property 'destination' or 'DestinationName' is required"); - } - if (SubscriptionDurable && !PubSubDomain) - { - throw new ArgumentException("A durable subscription requires a topic (pub-sub domain)"); - } - } - - #region Template methods for listeners - - - - /// - /// Executes the specified listener, - /// committing or rolling back the transaction afterwards (if necessary). - /// - /// The session to operate on. - /// The received message. - /// - /// - /// - /// - public virtual void ExecuteListener(ISession session, Message message) - { - try - { - DoExecuteListener(session, message); - } - catch (Exception ex) - { - HandleListenerException(ex); - } - } - - /// - /// Executes the specified listener, - /// committing or rolling back the transaction afterwards (if necessary). - /// - /// The session to operate on. - /// The received message. - /// If thrown by EMS API methods. - /// - /// - /// - protected virtual void DoExecuteListener(ISession session, Message message) - { - if (!AcceptMessagesWhileStopping && !IsRunning) - { - #region Logging - if (logger.IsEnabled(LogLevel.Warning)) - { - logger.LogWarning("Rejecting received message because of the listener container " + - "having been stopped in the meantime: " + message); - } - #endregion - RollbackIfNecessary(session); - throw new MessageRejectedWhileStoppingException(); - } - - try - { - InvokeListener(session, message); - } - catch (Exception ex) - { - RollbackOnExceptionIfNecessary(session, ex); - throw; - } - CommitIfNecessary(session, message); - } - - /// - /// Invokes the specified listener: either as standard EMS MessageListener - /// or (preferably) as Spring ISessionAwareMessageListener. - /// - /// The session to operate on. - /// The received message. - /// If thrown by EMS API methods. - /// - protected virtual void InvokeListener(ISession session, Message message) - { - object listener = MessageListener; - if (listener is ISessionAwareMessageListener) - { - DoInvokeListener((ISessionAwareMessageListener) listener, session, message); - } - - else if (listener is IMessageListener) - { - DoInvokeListener((IMessageListener)listener, message); - } - else if (listener != null) - { - throw new ArgumentException("Only MessageListener and ISessionAwareMessageListener supported"); - } - else - { - throw new InvalidOperationException("No message listener specified - see property MessageListener"); - } - } - - /// - /// Invoke the specified listener as Spring ISessionAwareMessageListener, - /// exposing a new EMS Session (potentially with its own transaction) - /// to the listener if demanded. - /// - /// The Spring ISessionAwareMessageListener to invoke. - /// The session to operate on. - /// The received message. - /// If thrown by EMS API methods. - /// - /// - protected virtual void DoInvokeListener(ISessionAwareMessageListener listener, ISession session, Message message) - { - IConnection conToClose = null; - ISession sessionToClose = null; - try - { - ISession sessionToUse = session; - if (!ExposeListenerSession) - { - //We need to expose a separate Session. - conToClose = CreateConnection(); - sessionToClose = CreateSession(conToClose); - sessionToUse = sessionToClose; - } - // Actually invoke the message listener - if (logger.IsEnabled(LogLevel.Debug)) - { - logger.LogDebug("Invoking listener with message of type [" + message.GetType() + - "] and session [" + sessionToUse + "]"); - } - listener.OnMessage(message, sessionToUse); - // Clean up specially exposed Session, if any - if (sessionToUse != session) - { - if (sessionToUse.Transacted && SessionTransacted) - { - // Transacted session created by this container -> commit. - EmsUtils.CommitIfNecessary(sessionToUse); - } - } - } finally - { - EmsUtils.CloseSession(sessionToClose); - EmsUtils.CloseConnection(conToClose); - } - } - - /// - /// Invoke the specified listener as standard JMS MessageListener. - /// - /// Default implementation performs a plain invocation of the - /// OnMessage methods - /// The listener to invoke. - /// The received message. - /// if thrown by the EMS API methods - protected virtual void DoInvokeListener(IMessageListener listener, Message message) - { - listener.OnMessage(message); - } - - /// - /// Perform a commit or message acknowledgement, as appropriate - /// - /// The session to commit. - /// The message to acknowledge. - /// In case of commit failure - protected virtual void CommitIfNecessary(ISession session, Message message) - { - // Commit session or acknowledge message - if (session.Transacted) - { - // Commit necessary - but avoid commit call is Session transaction is externally coordinated. - if (IsSessionLocallyTransacted(session)) - { - EmsUtils.CommitIfNecessary(session); + // Transacted session created by this container -> commit. + EmsUtils.CommitIfNecessary(sessionToUse); } } - else if (IsClientAcknowledge(session)) + } + finally + { + EmsUtils.CloseSession(sessionToClose); + EmsUtils.CloseConnection(conToClose); + } + } + + /// + /// Invoke the specified listener as standard JMS MessageListener. + /// + /// Default implementation performs a plain invocation of the + /// OnMessage methods + /// The listener to invoke. + /// The received message. + /// if thrown by the EMS API methods + protected virtual void DoInvokeListener(IMessageListener listener, Message message) + { + listener.OnMessage(message); + } + + /// + /// Perform a commit or message acknowledgement, as appropriate + /// + /// The session to commit. + /// The message to acknowledge. + /// In case of commit failure + protected virtual void CommitIfNecessary(ISession session, Message message) + { + // Commit session or acknowledge message + if (session.Transacted) + { + // Commit necessary - but avoid commit call is Session transaction is externally coordinated. + if (IsSessionLocallyTransacted(session)) { - message.Acknowledge(); + EmsUtils.CommitIfNecessary(session); } } - - /// - /// Determines whether the given Session is locally transacted, that is, whether - /// its transaction is managed by this listener container's Session handling - /// and not by an external transaction coordinator. - /// - /// - /// The Session's own transacted flag will already have been checked - /// before. This method is about finding out whether the Session's transaction - /// is local or externally coordinated. - /// - /// The session to check. - /// - /// true if the is session locally transacted; otherwise, false. - /// - /// - protected virtual bool IsSessionLocallyTransacted(ISession session) + else if (IsClientAcknowledge(session)) { - return SessionTransacted; + message.Acknowledge(); } + } + /// + /// Determines whether the given Session is locally transacted, that is, whether + /// its transaction is managed by this listener container's Session handling + /// and not by an external transaction coordinator. + /// + /// + /// The Session's own transacted flag will already have been checked + /// before. This method is about finding out whether the Session's transaction + /// is local or externally coordinated. + /// + /// The session to check. + /// + /// true if the is session locally transacted; otherwise, false. + /// + /// + protected virtual bool IsSessionLocallyTransacted(ISession session) + { + return SessionTransacted; + } - /// - /// Perform a rollback, if appropriate. - /// - /// The session to rollback. - /// In case of a rollback error - protected virtual void RollbackIfNecessary(ISession session) + /// + /// Perform a rollback, if appropriate. + /// + /// The session to rollback. + /// In case of a rollback error + protected virtual void RollbackIfNecessary(ISession session) + { + if (session.Transacted && IsSessionLocallyTransacted(session)) + { + // Transacted session created by this container -> rollback + EmsUtils.RollbackIfNecessary(session); + } + else if (IsClientAcknowledge(session)) + { + session.Recover(); + } + } + + /// + /// Perform a rollback, handling rollback excepitons properly. + /// + /// The session to rollback. + /// The thrown application exception. + /// in case of a rollback error. + protected virtual void RollbackOnExceptionIfNecessary(ISession session, Exception ex) + { + try { if (session.Transacted && IsSessionLocallyTransacted(session)) { // Transacted session created by this container -> rollback + if (logger.IsEnabled(LogLevel.Debug)) + { + logger.LogDebug("Initiating transaction rollback on application exception"); + } + EmsUtils.RollbackIfNecessary(session); } else if (IsClientAcknowledge(session)) @@ -509,123 +528,99 @@ namespace Spring.Messaging.Ems.Listener session.Recover(); } } - /// - /// Perform a rollback, handling rollback excepitons properly. - /// - /// The session to rollback. - /// The thrown application exception. - /// in case of a rollback error. - protected virtual void RollbackOnExceptionIfNecessary(ISession session, Exception ex) + catch (EMSException) { - try - { - if (session.Transacted && IsSessionLocallyTransacted(session)) - { - // Transacted session created by this container -> rollback - if (logger.IsEnabled(LogLevel.Debug)) - { - logger.LogDebug("Initiating transaction rollback on application exception"); - } - EmsUtils.RollbackIfNecessary(session); - } - else if (IsClientAcknowledge(session)) - { - session.Recover(); - } - } - catch (EMSException) - { - logger.LogError(ex, "Application exception overriden by rollback exception"); - throw; - } - } - - - /// - /// Handle the given exception that arose during listener execution. - /// - /// - /// The default implementation logs the exception at error level, - /// not propagating it to the JMS provider - assuming that all handling of - /// acknowledgement and/or transactions is done by this listener container. - /// This can be overridden in subclasses. - /// - /// The exceptin to handle - protected virtual void HandleListenerException(Exception ex) - { - if (ex is MessageRejectedWhileStoppingException) - { - // Internal exception - has been handled before. - return; - } - if (ex is EMSException) - { - InvokeExceptionListener((EMSException)ex); - } - if (Active) - { - // Regular case: failed while active. - // Invoke ErrorHandler if available. - InvokeErrorHandler(ex); - } - else - { - // Rare case: listener thread failed after container shutdown. - // Log at debug level, to avoid spamming the shutdown log. - logger.LogDebug(ex, "Listener exception after container shutdown"); - } - } - - protected virtual void InvokeErrorHandler(Exception exception) - { - if (errorHandler != null) - { - errorHandler.HandleError(exception); - } - else if (logger.IsEnabled(LogLevel.Warning)) - { - logger.LogWarning(exception, "Execution of EMS message listener failed, and no ErrorHandler has been set."); - } - } - - /// - /// Invokes the registered exception listener, if any. - /// - /// The exception that arose during EMS processing. - /// - protected virtual void InvokeExceptionListener(EMSException ex) - { - IExceptionListener exListener = ExceptionListener; - if (exListener != null) - { - exListener.OnException(ex); - } - } - - #endregion - - /// - /// Checks the message listener, throwing an exception - /// if it does not correspond to a supported listener type. - /// By default, only a standard JMS MessageListener object or a - /// Spring object will be accepted. - /// - /// The message listener. - protected virtual void CheckMessageListener(object messageListener) - { - AssertUtils.ArgumentNotNull(messageListener, "Message Listener can not be null"); - if (!(messageListener is IMessageListener || messageListener is ISessionAwareMessageListener)) - { - throw new ArgumentException("messageListener needs to be of type [" + typeof(IMessageListener).FullName + "] or [" + typeof(ISessionAwareMessageListener).FullName + "]"); - } + logger.LogError(ex, "Application exception overriden by rollback exception"); + throw; } } /// - /// Internal exception class that indicates a rejected message on shutdown. - /// Used to trigger a rollback for an external transaction manager in that case. + /// Handle the given exception that arose during listener execution. /// - internal class MessageRejectedWhileStoppingException : ApplicationException + /// + /// The default implementation logs the exception at error level, + /// not propagating it to the JMS provider - assuming that all handling of + /// acknowledgement and/or transactions is done by this listener container. + /// This can be overridden in subclasses. + /// + /// The exceptin to handle + protected virtual void HandleListenerException(Exception ex) { + if (ex is MessageRejectedWhileStoppingException) + { + // Internal exception - has been handled before. + return; + } + + if (ex is EMSException) + { + InvokeExceptionListener((EMSException) ex); + } + + if (Active) + { + // Regular case: failed while active. + // Invoke ErrorHandler if available. + InvokeErrorHandler(ex); + } + else + { + // Rare case: listener thread failed after container shutdown. + // Log at debug level, to avoid spamming the shutdown log. + logger.LogDebug(ex, "Listener exception after container shutdown"); + } + } + + protected virtual void InvokeErrorHandler(Exception exception) + { + if (errorHandler != null) + { + errorHandler.HandleError(exception); + } + else if (logger.IsEnabled(LogLevel.Warning)) + { + logger.LogWarning(exception, "Execution of EMS message listener failed, and no ErrorHandler has been set."); + } + } + + /// + /// Invokes the registered exception listener, if any. + /// + /// The exception that arose during EMS processing. + /// + protected virtual void InvokeExceptionListener(EMSException ex) + { + IExceptionListener exListener = ExceptionListener; + if (exListener != null) + { + exListener.OnException(ex); + } + } + + #endregion + + /// + /// Checks the message listener, throwing an exception + /// if it does not correspond to a supported listener type. + /// By default, only a standard JMS MessageListener object or a + /// Spring object will be accepted. + /// + /// The message listener. + protected virtual void CheckMessageListener(object messageListener) + { + AssertUtils.ArgumentNotNull(messageListener, "Message Listener can not be null"); + if (!(messageListener is IMessageListener || messageListener is ISessionAwareMessageListener)) + { + throw new ArgumentException("messageListener needs to be of type [" + typeof(IMessageListener).FullName + "] or [" + typeof(ISessionAwareMessageListener).FullName + "]"); + } } } + +/// +/// Internal exception class that indicates a rejected message on shutdown. +/// Used to trigger a rollback for an external transaction manager in that case. +/// +internal class MessageRejectedWhileStoppingException : ApplicationException +{ +} diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Listener/Adapter/ListenerExecutionFailedException.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Listener/Adapter/ListenerExecutionFailedException.cs index f19707fc..09f02396 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Listener/Adapter/ListenerExecutionFailedException.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Listener/Adapter/ListenerExecutionFailedException.cs @@ -18,34 +18,32 @@ #endregion -namespace Spring.Messaging.Ems.Listener.Adapter +namespace Spring.Messaging.Ems.Listener.Adapter; + +/// +/// Exception to be thrown when the execution of a listener method failed. +/// +/// Juergen Hoeller +/// Mark Pollack (.NET) +public class ListenerExecutionFailedException : EMSException { /// - /// Exception to be thrown when the execution of a listener method failed. + /// Initializes a new instance of the class, with the specified message /// - /// Juergen Hoeller - /// Mark Pollack (.NET) - public class ListenerExecutionFailedException : EMSException + /// The message. + public ListenerExecutionFailedException(string message) : base(message) { + } - /// - /// Initializes a new instance of the class, with the specified message - /// - /// The message. - public ListenerExecutionFailedException(string message) : base(message) - { - } - - /// - /// Initializes a new instance of the class, with the specified message - /// and root cause exception - /// - /// The message. - /// The inner exception. - public ListenerExecutionFailedException(string message, Exception innerException) - : base(message) - { - LinkedException = innerException; - } + /// + /// Initializes a new instance of the class, with the specified message + /// and root cause exception + /// + /// The message. + /// The inner exception. + public ListenerExecutionFailedException(string message, Exception innerException) + : base(message) + { + LinkedException = innerException; } } diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Listener/Adapter/MessageListenerAdapter.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Listener/Adapter/MessageListenerAdapter.cs index ebfd901b..da830ed0 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Listener/Adapter/MessageListenerAdapter.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Listener/Adapter/MessageListenerAdapter.cs @@ -7,552 +7,550 @@ using Spring.Messaging.Ems.Support.Converter; using Spring.Messaging.Ems.Support.Destinations; using Spring.Util; -namespace Spring.Messaging.Ems.Listener.Adapter +namespace Spring.Messaging.Ems.Listener.Adapter; + +/// +/// Message listener adapter that delegates the handling of messages to target +/// listener methods via reflection, with flexible message type conversion. +/// Allows listener methods to operate on message content types, completely +/// independent from the EMS API. +/// +/// +/// By default, the content of incoming messages gets extracted before +/// being passed into the target listener method, to let the target method +/// operate on message content types such as String or byte array instead of +/// the raw Message. Message type conversion is delegated to a Spring +/// . By default, a +/// will be used. (If you do not want such automatic message conversion taking +/// place, then be sure to set the property +/// to null.) +/// +/// If a target listener method returns a non-null object (typically of a +/// message content type such as String or byte array), it will get +/// wrapped in a EMS Message and sent to the response destination +/// (either the EMS "reply-to" destination or the +/// specified. +/// +/// +/// The sending of response messages is only available when +/// using the entry point (typically through a +/// Spring message listener container). Usage as standard EMS MessageListener +/// does not support the generation of response messages. +/// +/// Consult the reference documentation for examples of method signatures compliant with this +/// adapter class. +/// +/// +/// Juergen Hoeller +/// Mark Pollack (.NET) +public class MessageListenerAdapter : IMessageListener, ISessionAwareMessageListener { + #region Logging + + private readonly ILog logger = LogManager.GetLogger(typeof(MessageListenerAdapter)); + + #endregion + /// - /// Message listener adapter that delegates the handling of messages to target - /// listener methods via reflection, with flexible message type conversion. - /// Allows listener methods to operate on message content types, completely - /// independent from the EMS API. + /// The default handler method name. + /// + public static string ORIGINAL_DEFAULT_HANDLER_METHOD = "HandleMessage"; + + #region Fields + + private object handlerObject; + + private string defaultHandlerMethod = ORIGINAL_DEFAULT_HANDLER_METHOD; + + private IExpression processingExpression; + + private object defaultResponseDestination; + + private IDestinationResolver destinationResolver = new DynamicDestinationResolver(); + + private IMessageConverter messageConverter; + + #endregion + + #region Constructors + + /// + /// Initializes a new instance of the class with default settings. + /// + public MessageListenerAdapter() + { + InitDefaultStrategies(); + handlerObject = this; + } + + /// + /// Initializes a new instance of the class for the given handler object + /// + /// The delegate object. + public MessageListenerAdapter(object handlerObject) + { + InitDefaultStrategies(); + this.handlerObject = handlerObject; + } + + #endregion + + #region Properties + + /// + /// Gets or sets the handler object to delegate message listening to. /// /// - /// By default, the content of incoming messages gets extracted before - /// being passed into the target listener method, to let the target method - /// operate on message content types such as String or byte array instead of - /// the raw Message. Message type conversion is delegated to a Spring - /// . By default, a - /// will be used. (If you do not want such automatic message conversion taking - /// place, then be sure to set the property - /// to null.) - /// - /// If a target listener method returns a non-null object (typically of a - /// message content type such as String or byte array), it will get - /// wrapped in a EMS Message and sent to the response destination - /// (either the EMS "reply-to" destination or the - /// specified. - /// - /// - /// The sending of response messages is only available when - /// using the entry point (typically through a - /// Spring message listener container). Usage as standard EMS MessageListener - /// does not support the generation of response messages. - /// - /// Consult the reference documentation for examples of method signatures compliant with this - /// adapter class. - /// + /// Specified listener methods have to be present on this target object. + /// If no explicit handler object has been specified, listener + /// methods are expected to present on this adapter instance, that is, + /// on a custom subclass of this adapter, defining listener methods. /// - /// Juergen Hoeller - /// Mark Pollack (.NET) - public class MessageListenerAdapter : IMessageListener, ISessionAwareMessageListener + /// The handler object. + public object HandlerObject { - #region Logging + get { return handlerObject; } + set { handlerObject = value; } + } - private readonly ILog logger = LogManager.GetLogger(typeof (MessageListenerAdapter)); - - #endregion - - /// - /// The default handler method name. - /// - public static string ORIGINAL_DEFAULT_HANDLER_METHOD = "HandleMessage"; - - #region Fields - - private object handlerObject; - - private string defaultHandlerMethod = ORIGINAL_DEFAULT_HANDLER_METHOD; - - private IExpression processingExpression; - - private object defaultResponseDestination; - - private IDestinationResolver destinationResolver = new DynamicDestinationResolver(); - - private IMessageConverter messageConverter; - - #endregion - - #region Constructors - - /// - /// Initializes a new instance of the class with default settings. - /// - public MessageListenerAdapter() + /// + /// Gets or sets the default handler method to delegate to, + /// for the case where no specific listener method has been determined. + /// Out-of-the-box value is ("HandleMessage"}. + /// + /// The default handler method. + public string DefaultHandlerMethod + { + get { return defaultHandlerMethod; } + set { - InitDefaultStrategies(); - handlerObject = this; - } - - /// - /// Initializes a new instance of the class for the given handler object - /// - /// The delegate object. - public MessageListenerAdapter(object handlerObject) - { - InitDefaultStrategies(); - this.handlerObject = handlerObject; - } - - #endregion - - #region Properties - - /// - /// Gets or sets the handler object to delegate message listening to. - /// - /// - /// Specified listener methods have to be present on this target object. - /// If no explicit handler object has been specified, listener - /// methods are expected to present on this adapter instance, that is, - /// on a custom subclass of this adapter, defining listener methods. - /// - /// The handler object. - public object HandlerObject - { - get { return handlerObject; } - set { handlerObject = value; } - } - - /// - /// Gets or sets the default handler method to delegate to, - /// for the case where no specific listener method has been determined. - /// Out-of-the-box value is ("HandleMessage"}. - /// - /// The default handler method. - public string DefaultHandlerMethod - { - get { return defaultHandlerMethod; } - set - { - defaultHandlerMethod = value; - processingExpression = Expression.Parse(defaultHandlerMethod + "(#convertedObject)"); - } - } - - - /// - /// Sets the default destination to send response messages to. This will be applied - /// in case of a request message that does not carry a "JMSReplyTo" field. - /// Response destinations are only relevant for listener methods that return - /// result objects, which will be wrapped in a response message and sent to a - /// response destination. - /// - /// Alternatively, specify a "DefaultResponseQueueName" or "DefaultResponseTopicName", - /// to be dynamically resolved via the DestinationResolver. - /// - /// - /// The default response destination. - public object DefaultResponseDestination - { - set { defaultResponseDestination = value; } - } - - /// - /// Sets the name of the default response queue to send response messages to. - /// This will be applied in case of a request message that does not carry a - /// "EMSReplyTo" field. - /// Alternatively, specify a JMS Destination object as "defaultResponseDestination". - /// - /// The name of the default response destination queue. - public string DefaultResponseQueueName - { - set { defaultResponseDestination = new DestinationNameHolder(value, false); } - } - - /// - /// Sets the name of the default response topic to send response messages to. - /// This will be applied in case of a request message that does not carry a - /// "ReplyTo" field. - /// Alternatively, specify a JMS Destination object as "defaultResponseDestination". - /// - /// The name of the default response destination topic. - public string DefaultResponseTopicName - { - set { defaultResponseDestination = new DestinationNameHolder(value, true); } - } - - - /// - /// Gets or sets the destination resolver that should be used to resolve response - /// destination names for this adapter. - /// The default resolver is a . - /// Specify another implementation, for other strategies, perhaps from a directory service. - /// - /// The destination resolver. - public IDestinationResolver DestinationResolver - { - get { return destinationResolver; } - set - { - AssertUtils.ArgumentNotNull(value, "DestinationResolver must not be null"); - destinationResolver = value; - } - } - - /// - /// Gets or sets the message converter that will convert incoming JMS messages to - /// listener method arguments, and objects returned from listener - /// methods back to EMS messages. - /// - /// - /// The default converter is a {@link SimpleMessageConverter}, which is able - /// to handle BytesMessages}, TextMessages, MapMessages, and ObjectMessages. - /// - /// - /// The message converter. - public IMessageConverter MessageConverter - { - get { return messageConverter; } - set { messageConverter = value; } - } - - #endregion - - - /// - /// Standard JMS {@link MessageListener} entry point. - /// Delegates the message to the target listener method, with appropriate - /// conversion of the message arguments - /// - /// - /// - /// In case of an exception, the method will be invoked. - /// Note - /// Does not support sending response messages based on - /// result objects returned from listener methods. Use the - /// entry point (typically through a Spring - /// message listener container) for handling result objects as well. - /// - /// The incoming message. - public void OnMessage(Message message) - { - try - { - OnMessage(message, null); - } - catch (Exception e) - { - HandleListenerException(e); - } - } - - /// - /// Spring entry point. - /// - /// Delegates the message to the target listener method, with appropriate - /// conversion of the message argument. If the target method returns a - /// non-null object, wrap in a EMS message and send it back. - /// - /// - /// The incoming message. - /// The session to operate on. - public void OnMessage(Message message, ISession session) - { - if (handlerObject != this) - { - if (typeof(ISessionAwareMessageListener).IsInstanceOfType(handlerObject)) - { - if (session != null) - { - ((ISessionAwareMessageListener)handlerObject).OnMessage(message, session); - return; - } - else if (!typeof(IMessageListener).IsInstanceOfType(handlerObject)) - { - throw new InvalidOperationException("MessageListenerAdapter cannot handle a " + - "ISessionAwareMessageListener delegate if it hasn't been invoked with a Session itself"); - } - } - if (typeof(IMessageListener).IsInstanceOfType(handlerObject)) - { - ((IMessageListener)handlerObject).OnMessage(message); - return; - } - } - - // Regular case: find a handler method reflectively. - object convertedMessage = ExtractMessage(message); - - - IDictionary vars = new Dictionary(); - vars["convertedObject"] = convertedMessage; - - //Invoke message handler method and get result. - object result; - try - { - result = processingExpression.GetValue(handlerObject, vars); - } - catch (EMSException) - { - throw; - } - // Will only happen if dynamic method invocation falls back to standard reflection. - catch (TargetInvocationException ex) - { - Exception targetEx = ex.InnerException; - if (ObjectUtils.IsAssignable(typeof(EMSException), targetEx)) - { - throw ReflectionUtils.UnwrapTargetInvocationException(ex); - } - else - { - throw new ListenerExecutionFailedException("Listener method '" + defaultHandlerMethod + "' threw exception", targetEx); - } - } - catch (Exception ex) - { - throw new ListenerExecutionFailedException("Failed to invoke target method '" + defaultHandlerMethod + - "' with argument " + convertedMessage, ex); - } - - if (result != null) - { - HandleResult(result, message, session); - } - else - { - logger.LogDebug("No result object given - no result to handle"); - } - } - - /// - /// Initialize the default implementations for the adapter's strategies. - /// - protected virtual void InitDefaultStrategies() - { - MessageConverter = new SimpleMessageConverter(); + defaultHandlerMethod = value; processingExpression = Expression.Parse(defaultHandlerMethod + "(#convertedObject)"); } - - /// - /// Handle the given exception that arose during listener execution. - /// The default implementation logs the exception at error level. - /// This method only applies when used as standard EMS MessageListener. - /// In case of the Spring mechanism, - /// exceptions get handled by the caller instead. - /// - /// - /// The exception to handle. - protected virtual void HandleListenerException(Exception ex) - { - logger.LogError(ex, "Listener execution failed"); - } - - /// - /// Extract the message body from the given message. - /// - /// The message. - /// the content of the message, to be passed into the - /// listener method as argument - /// if thrown by EMS API methods - private object ExtractMessage(Message message) - { - IMessageConverter converter = MessageConverter; - if (converter != null) - { - return converter.FromMessage(message); - } - return message; - } - - /// - /// Gets the name of the listener method that is supposed to - /// handle the given message. - /// The default implementation simply returns the configured - /// default listener method, if any. - /// - /// The EMS request message. - /// The converted JMS request message, - /// to be passed into the listener method as argument. - /// the name of the listener method (never null) - /// if thrown by EMS API methods - protected virtual string GetHandlerMethodName(Message originalMessage, object extractedMessage) - { - return DefaultHandlerMethod; - } - - /// - /// Handles the given result object returned from the listener method, sending a response message back. - /// - /// The result object to handle (never null). - /// The original request message. - /// The session to operate on (may be null). - protected virtual void HandleResult(object result, Message request, ISession session) - { - if (session != null) - { - if (logger.IsEnabled(LogLevel.Debug)) - { - logger.LogDebug("Listener method returned result [" + result + - "] - generating response message for it"); - } - Message response = BuildMessage(session, result); - PostProcessResponse(request, response); - Destination destination = GetResponseDestination(request, response, session); - SendResponse(session, destination, response); - } - else - { - if (logger.IsEnabled(LogLevel.Debug)) - { - logger.LogDebug("Listener method returned result [" + result + - "]: not generating response message for it because of no EMS Session given"); - } - } - } - - /// - /// Builds a JMS message to be sent as response based on the given result object. - /// - /// The JMS Session to operate on. - /// The content of the message, as returned from the listener method. - /// the JMS Message (never null) - /// If there was an error in message conversion - /// if thrown by EMS API methods - protected virtual Message BuildMessage(ISession session, Object result) - { - IMessageConverter converter = MessageConverter; - if (converter != null) - { - return converter.ToMessage(result, session); - } - else - { - Message msg = result as Message; - if (msg == null) - { - throw new MessageConversionException( - "No IMessageConverter specified - cannot handle message [" + result + "]"); - } - return msg; - } - } - - /// - /// Post-process the given response message before it will be sent. The default implementation - /// sets the response's correlation id to the request message's correlation id. - /// - /// The original incoming message. - /// The outgoing JMS message about to be sent. - /// if thrown by EMS API methods - protected virtual void PostProcessResponse(Message request, Message response) - { - response.CorrelationID = request.CorrelationID; - } - - /// - /// Determine a response destination for the given message. - /// - /// - /// The default implementation first checks the JMS Reply-To - /// Destination of the supplied request; if that is not null - /// it is returned; if it is null, then the configured - /// default response destination} - /// is returned; if this too is null, then an - /// is thrown. - /// - /// - /// The original incoming message. - /// The outgoing message about to be sent. - /// The session to operate on. - /// the response destination (never null) - /// if thrown by EMS API methods - /// if no destination can be determined. - protected virtual Destination GetResponseDestination(Message request, Message response, ISession session) - { - Destination replyTo = request.ReplyTo; - if (replyTo == null) - { - replyTo = ResolveDefaultResponseDestination(session); - if (replyTo == null) - { - throw new InvalidDestinationException("Cannot determine response destination: " + - "Request message does not contain reply-to destination, and no default response destination set."); - } - } - return replyTo; - } - - /// - /// Resolves the default response destination into a Destination, using this - /// accessor's in case of a destination name. - /// - /// The session to operate on. - /// The located destination - protected virtual Destination ResolveDefaultResponseDestination(ISession session) - { - Destination dest = defaultResponseDestination as Destination; - if (dest != null) - { - return dest; - } - - DestinationNameHolder destNameHolder = defaultResponseDestination as DestinationNameHolder; - if (destNameHolder != null) - { - return DestinationResolver.ResolveDestinationName(session, destNameHolder.Name, destNameHolder.IsTopic); - } - - return null; - } - - /// - /// Sends the given response message to the given destination. - /// - /// The session to operate on. - /// The destination to send to. - /// The outgoing message about to be sent. - protected virtual void SendResponse(ISession session, Destination destination, Message response) - { - IMessageProducer producer = session.CreateProducer(destination); - try - { - PostProcessProducer(producer, response); - producer.Send(response); - } - finally - { - EmsUtils.CloseMessageProducer(producer); - } - } - - /// - /// Post-process the given message producer before using it to send the response. - /// The default implementation is empty. - /// - /// The producer that will be used to send the message. - /// The outgoing message about to be sent. - protected virtual void PostProcessProducer(IMessageProducer producer, Message response) - { - - } } /// - /// Internal class combining a destination name and its target destination type (queue or topic). + /// Sets the default destination to send response messages to. This will be applied + /// in case of a request message that does not carry a "JMSReplyTo" field. + /// Response destinations are only relevant for listener methods that return + /// result objects, which will be wrapped in a response message and sent to a + /// response destination. + /// + /// Alternatively, specify a "DefaultResponseQueueName" or "DefaultResponseTopicName", + /// to be dynamically resolved via the DestinationResolver. + /// /// - internal class DestinationNameHolder + /// The default response destination. + public object DefaultResponseDestination { - private readonly string name; + set { defaultResponseDestination = value; } + } - private readonly bool isTopic; + /// + /// Sets the name of the default response queue to send response messages to. + /// This will be applied in case of a request message that does not carry a + /// "EMSReplyTo" field. + /// Alternatively, specify a JMS Destination object as "defaultResponseDestination". + /// + /// The name of the default response destination queue. + public string DefaultResponseQueueName + { + set { defaultResponseDestination = new DestinationNameHolder(value, false); } + } - public DestinationNameHolder(string name, bool isTopic) + /// + /// Sets the name of the default response topic to send response messages to. + /// This will be applied in case of a request message that does not carry a + /// "ReplyTo" field. + /// Alternatively, specify a JMS Destination object as "defaultResponseDestination". + /// + /// The name of the default response destination topic. + public string DefaultResponseTopicName + { + set { defaultResponseDestination = new DestinationNameHolder(value, true); } + } + + /// + /// Gets or sets the destination resolver that should be used to resolve response + /// destination names for this adapter. + /// The default resolver is a . + /// Specify another implementation, for other strategies, perhaps from a directory service. + /// + /// The destination resolver. + public IDestinationResolver DestinationResolver + { + get { return destinationResolver; } + set { - this.name = name; - this.isTopic = isTopic; - } - - - public string Name - { - get { return name; } - } - - public bool IsTopic - { - get { return isTopic; } + AssertUtils.ArgumentNotNull(value, "DestinationResolver must not be null"); + destinationResolver = value; } } + + /// + /// Gets or sets the message converter that will convert incoming JMS messages to + /// listener method arguments, and objects returned from listener + /// methods back to EMS messages. + /// + /// + /// The default converter is a {@link SimpleMessageConverter}, which is able + /// to handle BytesMessages}, TextMessages, MapMessages, and ObjectMessages. + /// + /// + /// The message converter. + public IMessageConverter MessageConverter + { + get { return messageConverter; } + set { messageConverter = value; } + } + + #endregion + + /// + /// Standard JMS {@link MessageListener} entry point. + /// Delegates the message to the target listener method, with appropriate + /// conversion of the message arguments + /// + /// + /// + /// In case of an exception, the method will be invoked. + /// Note + /// Does not support sending response messages based on + /// result objects returned from listener methods. Use the + /// entry point (typically through a Spring + /// message listener container) for handling result objects as well. + /// + /// The incoming message. + public void OnMessage(Message message) + { + try + { + OnMessage(message, null); + } + catch (Exception e) + { + HandleListenerException(e); + } + } + + /// + /// Spring entry point. + /// + /// Delegates the message to the target listener method, with appropriate + /// conversion of the message argument. If the target method returns a + /// non-null object, wrap in a EMS message and send it back. + /// + /// + /// The incoming message. + /// The session to operate on. + public void OnMessage(Message message, ISession session) + { + if (handlerObject != this) + { + if (typeof(ISessionAwareMessageListener).IsInstanceOfType(handlerObject)) + { + if (session != null) + { + ((ISessionAwareMessageListener) handlerObject).OnMessage(message, session); + return; + } + else if (!typeof(IMessageListener).IsInstanceOfType(handlerObject)) + { + throw new InvalidOperationException("MessageListenerAdapter cannot handle a " + + "ISessionAwareMessageListener delegate if it hasn't been invoked with a Session itself"); + } + } + + if (typeof(IMessageListener).IsInstanceOfType(handlerObject)) + { + ((IMessageListener) handlerObject).OnMessage(message); + return; + } + } + + // Regular case: find a handler method reflectively. + object convertedMessage = ExtractMessage(message); + + IDictionary vars = new Dictionary(); + vars["convertedObject"] = convertedMessage; + + //Invoke message handler method and get result. + object result; + try + { + result = processingExpression.GetValue(handlerObject, vars); + } + catch (EMSException) + { + throw; + } + // Will only happen if dynamic method invocation falls back to standard reflection. + catch (TargetInvocationException ex) + { + Exception targetEx = ex.InnerException; + if (ObjectUtils.IsAssignable(typeof(EMSException), targetEx)) + { + throw ReflectionUtils.UnwrapTargetInvocationException(ex); + } + else + { + throw new ListenerExecutionFailedException("Listener method '" + defaultHandlerMethod + "' threw exception", targetEx); + } + } + catch (Exception ex) + { + throw new ListenerExecutionFailedException("Failed to invoke target method '" + defaultHandlerMethod + + "' with argument " + convertedMessage, ex); + } + + if (result != null) + { + HandleResult(result, message, session); + } + else + { + logger.LogDebug("No result object given - no result to handle"); + } + } + + /// + /// Initialize the default implementations for the adapter's strategies. + /// + protected virtual void InitDefaultStrategies() + { + MessageConverter = new SimpleMessageConverter(); + processingExpression = Expression.Parse(defaultHandlerMethod + "(#convertedObject)"); + } + + /// + /// Handle the given exception that arose during listener execution. + /// The default implementation logs the exception at error level. + /// This method only applies when used as standard EMS MessageListener. + /// In case of the Spring mechanism, + /// exceptions get handled by the caller instead. + /// + /// + /// The exception to handle. + protected virtual void HandleListenerException(Exception ex) + { + logger.LogError(ex, "Listener execution failed"); + } + + /// + /// Extract the message body from the given message. + /// + /// The message. + /// the content of the message, to be passed into the + /// listener method as argument + /// if thrown by EMS API methods + private object ExtractMessage(Message message) + { + IMessageConverter converter = MessageConverter; + if (converter != null) + { + return converter.FromMessage(message); + } + + return message; + } + + /// + /// Gets the name of the listener method that is supposed to + /// handle the given message. + /// The default implementation simply returns the configured + /// default listener method, if any. + /// + /// The EMS request message. + /// The converted JMS request message, + /// to be passed into the listener method as argument. + /// the name of the listener method (never null) + /// if thrown by EMS API methods + protected virtual string GetHandlerMethodName(Message originalMessage, object extractedMessage) + { + return DefaultHandlerMethod; + } + + /// + /// Handles the given result object returned from the listener method, sending a response message back. + /// + /// The result object to handle (never null). + /// The original request message. + /// The session to operate on (may be null). + protected virtual void HandleResult(object result, Message request, ISession session) + { + if (session != null) + { + if (logger.IsEnabled(LogLevel.Debug)) + { + logger.LogDebug("Listener method returned result [" + result + + "] - generating response message for it"); + } + + Message response = BuildMessage(session, result); + PostProcessResponse(request, response); + Destination destination = GetResponseDestination(request, response, session); + SendResponse(session, destination, response); + } + else + { + if (logger.IsEnabled(LogLevel.Debug)) + { + logger.LogDebug("Listener method returned result [" + result + + "]: not generating response message for it because of no EMS Session given"); + } + } + } + + /// + /// Builds a JMS message to be sent as response based on the given result object. + /// + /// The JMS Session to operate on. + /// The content of the message, as returned from the listener method. + /// the JMS Message (never null) + /// If there was an error in message conversion + /// if thrown by EMS API methods + protected virtual Message BuildMessage(ISession session, Object result) + { + IMessageConverter converter = MessageConverter; + if (converter != null) + { + return converter.ToMessage(result, session); + } + else + { + Message msg = result as Message; + if (msg == null) + { + throw new MessageConversionException( + "No IMessageConverter specified - cannot handle message [" + result + "]"); + } + + return msg; + } + } + + /// + /// Post-process the given response message before it will be sent. The default implementation + /// sets the response's correlation id to the request message's correlation id. + /// + /// The original incoming message. + /// The outgoing JMS message about to be sent. + /// if thrown by EMS API methods + protected virtual void PostProcessResponse(Message request, Message response) + { + response.CorrelationID = request.CorrelationID; + } + + /// + /// Determine a response destination for the given message. + /// + /// + /// The default implementation first checks the JMS Reply-To + /// Destination of the supplied request; if that is not null + /// it is returned; if it is null, then the configured + /// default response destination} + /// is returned; if this too is null, then an + /// is thrown. + /// + /// + /// The original incoming message. + /// The outgoing message about to be sent. + /// The session to operate on. + /// the response destination (never null) + /// if thrown by EMS API methods + /// if no destination can be determined. + protected virtual Destination GetResponseDestination(Message request, Message response, ISession session) + { + Destination replyTo = request.ReplyTo; + if (replyTo == null) + { + replyTo = ResolveDefaultResponseDestination(session); + if (replyTo == null) + { + throw new InvalidDestinationException("Cannot determine response destination: " + + "Request message does not contain reply-to destination, and no default response destination set."); + } + } + + return replyTo; + } + + /// + /// Resolves the default response destination into a Destination, using this + /// accessor's in case of a destination name. + /// + /// The session to operate on. + /// The located destination + protected virtual Destination ResolveDefaultResponseDestination(ISession session) + { + Destination dest = defaultResponseDestination as Destination; + if (dest != null) + { + return dest; + } + + DestinationNameHolder destNameHolder = defaultResponseDestination as DestinationNameHolder; + if (destNameHolder != null) + { + return DestinationResolver.ResolveDestinationName(session, destNameHolder.Name, destNameHolder.IsTopic); + } + + return null; + } + + /// + /// Sends the given response message to the given destination. + /// + /// The session to operate on. + /// The destination to send to. + /// The outgoing message about to be sent. + protected virtual void SendResponse(ISession session, Destination destination, Message response) + { + IMessageProducer producer = session.CreateProducer(destination); + try + { + PostProcessProducer(producer, response); + producer.Send(response); + } + finally + { + EmsUtils.CloseMessageProducer(producer); + } + } + + /// + /// Post-process the given message producer before using it to send the response. + /// The default implementation is empty. + /// + /// The producer that will be used to send the message. + /// The outgoing message about to be sent. + protected virtual void PostProcessProducer(IMessageProducer producer, Message response) + { + } } + +/// +/// Internal class combining a destination name and its target destination type (queue or topic). +/// +internal class DestinationNameHolder +{ + private readonly string name; + + private readonly bool isTopic; + + public DestinationNameHolder(string name, bool isTopic) + { + this.name = name; + this.isTopic = isTopic; + } + + public string Name + { + get { return name; } + } + + public bool IsTopic + { + get { return isTopic; } + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Listener/ISessionAwareMessageListener.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Listener/ISessionAwareMessageListener.cs index cde5f96a..059dbc31 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Listener/ISessionAwareMessageListener.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Listener/ISessionAwareMessageListener.cs @@ -20,32 +20,31 @@ using Spring.Messaging.Ems.Common; -namespace Spring.Messaging.Ems.Listener +namespace Spring.Messaging.Ems.Listener; + +/// +/// Variant of the standard EMS MessageListener interface, +/// offering not only the received Message but also the underlying +/// Session object. The latter can be used to send reply messages, +/// without the need to access an external Connection/Session, +/// i.e. without the need to access the underlying ConnectionFactory. +/// +/// +/// Supported by Spring's +/// as direct alternative to the standard MessageListener interface. +/// +/// Juergen Hoeller +/// Mark Pollack (.NET) +public interface ISessionAwareMessageListener { - /// - /// Variant of the standard EMS MessageListener interface, - /// offering not only the received Message but also the underlying - /// Session object. The latter can be used to send reply messages, - /// without the need to access an external Connection/Session, - /// i.e. without the need to access the underlying ConnectionFactory. + /// Callback for processing a received EMS message. + /// Implementors are supposed to process the given Message, + /// typically sending reply messages through the given Session. /// - /// - /// Supported by Spring's - /// as direct alternative to the standard MessageListener interface. - /// - /// Juergen Hoeller - /// Mark Pollack (.NET) - public interface ISessionAwareMessageListener - { - /// Callback for processing a received EMS message. - /// Implementors are supposed to process the given Message, - /// typically sending reply messages through the given Session. - /// - /// the received EMS message - /// - /// the underlying EMS Session - /// - /// EMSException if thrown by EMS methods - void OnMessage(Message message, ISession session); - } + /// the received EMS message + /// + /// the underlying EMS Session + /// + /// EMSException if thrown by EMS methods + void OnMessage(Message message, ISession session); } diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Listener/LocallyExposedEmsResourceHolder.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Listener/LocallyExposedEmsResourceHolder.cs index 752da46f..ac471ffe 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Listener/LocallyExposedEmsResourceHolder.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Listener/LocallyExposedEmsResourceHolder.cs @@ -21,23 +21,21 @@ using Spring.Messaging.Ems.Common; using Spring.Messaging.Ems.Connections; -namespace Spring.Messaging.Ems.Listener +namespace Spring.Messaging.Ems.Listener; + +/// +/// EmsResourceHolder marker subclass that indicates local exposure, +/// i.e. that does not indicate an externally managed transaction. +/// +/// Juergen Hoeller +/// Mark Pollack (.NET) +public class LocallyExposedEmsResourceHolder : EmsResourceHolder { /// - /// EmsResourceHolder marker subclass that indicates local exposure, - /// i.e. that does not indicate an externally managed transaction. + /// Initializes a new instance of the class. /// - /// Juergen Hoeller - /// Mark Pollack (.NET) - public class LocallyExposedEmsResourceHolder : EmsResourceHolder + /// The session. + public LocallyExposedEmsResourceHolder(ISession session) : base(session) { - /// - /// Initializes a new instance of the class. - /// - /// The session. - public LocallyExposedEmsResourceHolder(ISession session) : base(session) - { - - } } } \ No newline at end of file diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Listener/RecoveryTimeExceededException.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Listener/RecoveryTimeExceededException.cs index d3f67382..c480990d 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Listener/RecoveryTimeExceededException.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Listener/RecoveryTimeExceededException.cs @@ -20,33 +20,31 @@ using Spring.Messaging.Ems.Listener.Adapter; -namespace Spring.Messaging.Ems.Listener +namespace Spring.Messaging.Ems.Listener; + +/// +/// Exception thrown when the maximum connection recovery time has been exceeded. +/// +/// Mark Pollack +public class RecoveryTimeExceededException : EMSException { /// - /// Exception thrown when the maximum connection recovery time has been exceeded. + /// Initializes a new instance of the class, with the specified message /// - /// Mark Pollack - public class RecoveryTimeExceededException : EMSException + /// The message. + public RecoveryTimeExceededException(string message) : base(message) { + } - /// - /// Initializes a new instance of the class, with the specified message - /// - /// The message. - public RecoveryTimeExceededException(string message) : base(message) - { - } - - /// - /// Initializes a new instance of the class, with the specified message - /// and root cause exception - /// - /// The message. - /// The inner exception. - public RecoveryTimeExceededException(string message, Exception innerException) - : base(message) - { - LinkedException = innerException; - } + /// + /// Initializes a new instance of the class, with the specified message + /// and root cause exception + /// + /// The message. + /// The inner exception. + public RecoveryTimeExceededException(string message, Exception innerException) + : base(message) + { + LinkedException = innerException; } } diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Listener/SimpleMessageListenerContainer.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Listener/SimpleMessageListenerContainer.cs index 749f0d74..e5830401 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Listener/SimpleMessageListenerContainer.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Listener/SimpleMessageListenerContainer.cs @@ -25,385 +25,388 @@ using Spring.Messaging.Ems.Support; using Spring.Transaction.Support; using Spring.Util; -namespace Spring.Messaging.Ems.Listener +namespace Spring.Messaging.Ems.Listener; + +/// +/// Message listener container that uses the plain EMS client API's +/// MessageConsumer.Listener method to create concurrent +/// MessageConsumers for the specified listeners. +/// +/// Juergen Hoeller +/// Mark Pollack (.NET) +public class SimpleMessageListenerContainer : AbstractMessageListenerContainer, IExceptionListener { + #region Logging + + private readonly ILogger logger = LogManager.GetLogger(); + + #endregion + + #region fields + /// - /// Message listener container that uses the plain EMS client API's - /// MessageConsumer.Listener method to create concurrent - /// MessageConsumers for the specified listeners. + /// The default recovery time interval between connection reconnection attempts /// - /// Juergen Hoeller - /// Mark Pollack (.NET) - public class SimpleMessageListenerContainer : AbstractMessageListenerContainer, IExceptionListener + public static string DEFAULT_RECOVERY_INTERVAL = "5s"; + + /// + /// The total time connection recovery will be attempted. + /// + public static string DEFAULT_MAX_RECOVERY_TIME = "10m"; + + private bool pubSubNoLocal = false; + + private int concurrentConsumers = 1; + + private ISet sessions; + + private ISet consumers; + + private object consumersMonitor = new object(); + + private TimeSpan recoveryInterval = new TimeSpan(0, 0, 0, 5, 0); + + private TimeSpan maxRecoveryTime = new TimeSpan(0, 0, 10, 0, 0); + + #endregion + + #region Properties + + /// + /// Gets or sets a value indicating whether to inhibit the delivery of messages published by its own connection. + /// Default is "false". + /// + /// true if should inhibit the delivery of messages published by its own connection; otherwise, false. + public bool PubSubNoLocal { - #region Logging + get { return pubSubNoLocal; } + set { pubSubNoLocal = value; } + } - private readonly ILogger logger = LogManager.GetLogger(); - - #endregion - - #region fields - - /// - /// The default recovery time interval between connection reconnection attempts - /// - public static string DEFAULT_RECOVERY_INTERVAL = "5s"; - - /// - /// The total time connection recovery will be attempted. - /// - public static string DEFAULT_MAX_RECOVERY_TIME = "10m"; - - private bool pubSubNoLocal = false; - - private int concurrentConsumers = 1; - - private ISet sessions; - - private ISet consumers; - - private object consumersMonitor = new object(); - - private TimeSpan recoveryInterval = new TimeSpan(0, 0, 0, 5, 0); - - private TimeSpan maxRecoveryTime = new TimeSpan(0, 0, 10, 0, 0); - - #endregion - - #region Properties - - /// - /// Gets or sets a value indicating whether to inhibit the delivery of messages published by its own connection. - /// Default is "false". - /// - /// true if should inhibit the delivery of messages published by its own connection; otherwise, false. - public bool PubSubNoLocal + /// + /// Specify the number of concurrent consumers to create. Default is 1. + /// + /// + /// Raising the number of concurrent consumers is recommendable in order + /// to scale the consumption of messages coming in from a queue. However, + /// note that any ordering guarantees are lost once multiple consumers are + /// registered. In general, stick with 1 consumer for low-volume queues. + /// Do not raise the number of concurrent consumers for a topic. + /// This would lead to concurrent consumption of the same message, + /// which is hardly ever desirable. + /// + /// + /// The concurrent consumers. + public int ConcurrentConsumers + { + set { - get { return pubSubNoLocal; } - set { pubSubNoLocal = value; } + AssertUtils.IsTrue(value > 0, "'ConcurrentConsumer' value must be at least 1 (one)"); + concurrentConsumers = value; + } + get + { + return concurrentConsumers; + } + } + + /// + /// Sets the time interval between connection recovery attempts. The default is 5 seconds. + /// + /// The recovery interval. + public TimeSpan RecoveryInterval + { + set { recoveryInterval = value; } + } + + /// + /// Sets the max recovery time to try reconnection attempts. The default is 10 minutes. + /// + /// The max recovery time. + public TimeSpan MaxRecoveryTime + { + set { maxRecoveryTime = value; } + } + + /// + /// Always use a shared EMS connection + /// + protected override bool SharedConnectionEnabled + { + get { return true; } + } + + #endregion + + /// + /// Call base class for valdation and then check that if the subscription is durable that the number of + /// concurrent consumers is equal to one. + /// + protected override void ValidateConfiguration() + { + base.ValidateConfiguration(); + if (SubscriptionDurable && concurrentConsumers != 1) + { + throw new ArgumentException("Only 1 concurrent consumer supported for durable subscription"); + } + } + + /// + /// Creates the specified number of concurrent consumers, + /// in the form of a JMS Session plus associated MessageConsumer + /// + /// + protected override void DoInitialize() + { + EstablishSharedConnection(); + InitializeConsumers(); + } + + /// + /// Re-initializes this container's EMS message consumers, + /// if not initialized already. + /// + protected override void DoStart() + { + base.DoStart(); + InitializeConsumers(); + } + + /// + /// Registers this listener container as EMS ExceptionListener on the shared connection. + /// + /// + protected override void PrepareSharedConnection(IConnection connection) + { + base.PrepareSharedConnection(connection); + connection.ExceptionListener = this; + } + + /// + /// implementation, invoked by the EMS provider in + /// case of connection failures. Re-initializes this listener container's + /// shared connection and its sessions and consumers. + /// + /// The reported connection exception. + public void OnException(EMSException exception) + { + // First invoke the user-specific ExceptionListener, if any. + InvokeExceptionListener(exception); + // now try to recover the shared Connection and all consumers... + if (logger.IsEnabled(LogLevel.Information)) + { + logger.LogInformation("Trying to recover from EMS Connection exception: " + exception); } - /// - /// Specify the number of concurrent consumers to create. Default is 1. - /// - /// - /// Raising the number of concurrent consumers is recommendable in order - /// to scale the consumption of messages coming in from a queue. However, - /// note that any ordering guarantees are lost once multiple consumers are - /// registered. In general, stick with 1 consumer for low-volume queues. - /// Do not raise the number of concurrent consumers for a topic. - /// This would lead to concurrent consumption of the same message, - /// which is hardly ever desirable. - /// - /// - /// The concurrent consumers. - public int ConcurrentConsumers + try { - set + lock (consumersMonitor) { - AssertUtils.IsTrue(value > 0, "'ConcurrentConsumer' value must be at least 1 (one)"); - concurrentConsumers = value; + sessions = null; + consumers = null; } - get - { - return concurrentConsumers; - } - } - /// - /// Sets the time interval between connection recovery attempts. The default is 5 seconds. - /// - /// The recovery interval. - public TimeSpan RecoveryInterval - { - set { recoveryInterval = value; } - } - - - /// - /// Sets the max recovery time to try reconnection attempts. The default is 10 minutes. - /// - /// The max recovery time. - public TimeSpan MaxRecoveryTime - { - set { maxRecoveryTime = value; } - } - - /// - /// Always use a shared EMS connection - /// - protected override bool SharedConnectionEnabled - { - get { return true; } - } - - #endregion - - /// - /// Call base class for valdation and then check that if the subscription is durable that the number of - /// concurrent consumers is equal to one. - /// - protected override void ValidateConfiguration() - { - base.ValidateConfiguration(); - if (SubscriptionDurable && concurrentConsumers !=1 ) - { - throw new ArgumentException("Only 1 concurrent consumer supported for durable subscription"); - } - } - - /// - /// Creates the specified number of concurrent consumers, - /// in the form of a JMS Session plus associated MessageConsumer - /// - /// - protected override void DoInitialize() - { - EstablishSharedConnection(); + RefreshConnectionUntilSuccessful(); InitializeConsumers(); + logger.LogInformation("Successfully refreshed EMS Connection"); } - - /// - /// Re-initializes this container's EMS message consumers, - /// if not initialized already. - /// - protected override void DoStart() + catch (RecoveryTimeExceededException) { - base.DoStart(); - InitializeConsumers(); + throw; } - - /// - /// Registers this listener container as EMS ExceptionListener on the shared connection. - /// - /// - protected override void PrepareSharedConnection(IConnection connection) + catch (EMSException recoverEx) { - base.PrepareSharedConnection(connection); - connection.ExceptionListener = this; + logger.LogDebug((Exception) recoverEx, "Failed to recover EMS Connection"); + logger.LogError((Exception) exception, "Encountered non-recoverable EMSException"); } + } - - /// - /// implementation, invoked by the EMS provider in - /// case of connection failures. Re-initializes this listener container's - /// shared connection and its sessions and consumers. - /// - /// The reported connection exception. - public void OnException(EMSException exception) + /// + /// Refresh the underlying Connection, not returning before an attempt has been + /// successful. Called in case of a shared Connection as well as without shared + /// Connection, so either needs to operate on the shared Connection or on a + /// temporary Connection that just gets established for validation purposes. + /// + /// + /// The default implementation retries until it successfully established a + /// Connection, for as long as this message listener container is active. + /// Applies the specified recovery interval between retries. + /// + protected virtual void RefreshConnectionUntilSuccessful() + { + TimeSpan totalTryTime = new TimeSpan(); + while (IsRunning) { - // First invoke the user-specific ExceptionListener, if any. - InvokeExceptionListener(exception); - // now try to recover the shared Connection and all consumers... - if (logger.IsEnabled(LogLevel.Information)) - { - logger.LogInformation("Trying to recover from EMS Connection exception: " + exception); - } try { - lock (consumersMonitor) + RefreshSharedConnection(); + break; + } + catch (Exception ex) + { + if (logger.IsEnabled(LogLevel.Information)) { - sessions = null; - consumers = null; + logger.LogInformation("Could not refresh Connection - retrying in " + recoveryInterval); } - RefreshConnectionUntilSuccessful(); - InitializeConsumers(); - logger.LogInformation("Successfully refreshed EMS Connection"); } - catch (RecoveryTimeExceededException) + + if (totalTryTime > maxRecoveryTime) { - throw; - } catch (EMSException recoverEx) - { - logger.LogDebug((Exception) recoverEx, "Failed to recover EMS Connection"); - logger.LogError((Exception) exception, "Encountered non-recoverable EMSException"); + logger.LogInformation("Could not refresh Connection after " + totalTryTime + ". Stopping reconnection attempts."); + throw new RecoveryTimeExceededException("Could not recover after " + totalTryTime); } + + DateTime startTime = DateTime.Now; + SleepInBetweenRecoveryAttempts(); + TimeSpan sleepTimeSpan = DateTime.Now - startTime; + totalTryTime += sleepTimeSpan; } + } - /// - /// Refresh the underlying Connection, not returning before an attempt has been - /// successful. Called in case of a shared Connection as well as without shared - /// Connection, so either needs to operate on the shared Connection or on a - /// temporary Connection that just gets established for validation purposes. - /// - /// - /// The default implementation retries until it successfully established a - /// Connection, for as long as this message listener container is active. - /// Applies the specified recovery interval between retries. - /// - protected virtual void RefreshConnectionUntilSuccessful() + /// + /// The amount of time to sleep in between recovery attempts. + /// + protected virtual void SleepInBetweenRecoveryAttempts() + { + Thread.Sleep(recoveryInterval); + } + + /// + /// Initialize the Sessions and MessageConsumers for this container. + /// + /// in case of setup failure. + protected virtual void InitializeConsumers() + { + // Register Sessions and MessageConsumers + lock (consumersMonitor) { - TimeSpan totalTryTime = new TimeSpan(); - while (IsRunning) + if (this.consumers == null) { - try + this.sessions = new HashedSet(); + this.consumers = new HashedSet(); + IConnection con = SharedConnection; + for (int i = 0; i < this.concurrentConsumers; i++) { - RefreshSharedConnection(); - break; + ISession session = CreateSession(SharedConnection); + IMessageConsumer consumer = CreateListenerConsumer(session); + this.sessions.Add(session); + this.consumers.Add(consumer); } - catch (Exception ex) - { - if (logger.IsEnabled(LogLevel.Information)) - { - logger.LogInformation("Could not refresh Connection - retrying in " + recoveryInterval); - } - } - - if (totalTryTime > maxRecoveryTime) - { - logger.LogInformation("Could not refresh Connection after " + totalTryTime + ". Stopping reconnection attempts."); - throw new RecoveryTimeExceededException("Could not recover after " + totalTryTime); - } - - DateTime startTime = DateTime.Now; - SleepInBetweenRecoveryAttempts(); - TimeSpan sleepTimeSpan = DateTime.Now - startTime; - totalTryTime += sleepTimeSpan; - } - } - - /// - /// The amount of time to sleep in between recovery attempts. - /// - protected virtual void SleepInBetweenRecoveryAttempts() - { - Thread.Sleep(recoveryInterval); - } - - - /// - /// Initialize the Sessions and MessageConsumers for this container. - /// - /// in case of setup failure. - protected virtual void InitializeConsumers() - { - // Register Sessions and MessageConsumers - lock (consumersMonitor) - { - if (this.consumers == null) - { - this.sessions = new HashedSet(); - this.consumers = new HashedSet(); - IConnection con = SharedConnection; - for (int i = 0; i < this.concurrentConsumers; i++) - { - ISession session = CreateSession(SharedConnection); - IMessageConsumer consumer = CreateListenerConsumer(session); - this.sessions.Add(session); - this.consumers.Add(consumer); - } - } - } - } - - /// - /// Creates a MessageConsumer for the given Session, - /// registering a MessageListener for the specified listener - /// - /// The session to work on. - /// the MessageConsumer"/> - /// if thrown by EMS methods - private IMessageConsumer CreateListenerConsumer(ISession session) - { - Destination destination = Destination; - if (destination == null) - { - destination = ResolveDestinationName(session, DestinationName); - } - IMessageConsumer consumer = CreateConsumer(session, destination); - - consumer.MessageListener = new SimpleMessageListener(this, session); - return consumer; - } - - /// - /// Close the message consumers and sessions. - /// - /// EMSException if destruction failed - protected override void DoShutdown() - { - lock (consumersMonitor) - { - if (consumers != null) - { - logger.LogDebug("Closing EMS MessageConsumers"); - foreach (IMessageConsumer messageConsumer in consumers) - { - EmsUtils.CloseMessageConsumer(messageConsumer); - } - } - if (sessions != null) - { - logger.LogDebug("Closing EMS Sessions"); - foreach (ISession session in sessions) - { - EmsUtils.CloseSession(session); - } - } - consumers = null; - sessions = null; - } - } - - - /// - /// Creates a MessageConsumer for the given Session and Destination. - /// - /// The session to create a MessageConsumer for. - /// The destination to create a MessageConsumer for. - /// The new MessageConsumer - protected IMessageConsumer CreateConsumer(ISession session, Destination destination) - { - // Only pass in the NoLocal flag in case of a Topic: - // Some EMS providers, such as WebSphere MQ 6.0, throw IllegalStateException - // in case of the NoLocal flag being specified for a Queue. - if (PubSubDomain) - { - if (SubscriptionDurable && destination is Topic) - { - return session.CreateDurableSubscriber( - (Topic) destination, DurableSubscriptionName, MessageSelector, PubSubNoLocal); - } - else - { - return session.CreateConsumer(destination, MessageSelector, PubSubNoLocal); - } - } - else - { - return session.CreateConsumer(destination, MessageSelector); } } } - internal class SimpleMessageListener : IMessageListener + /// + /// Creates a MessageConsumer for the given Session, + /// registering a MessageListener for the specified listener + /// + /// The session to work on. + /// the MessageConsumer"/> + /// if thrown by EMS methods + private IMessageConsumer CreateListenerConsumer(ISession session) { - private SimpleMessageListenerContainer container; - private ISession session; - - public SimpleMessageListener(SimpleMessageListenerContainer container, ISession session) + Destination destination = Destination; + if (destination == null) { - this.container = container; - this.session = session; + destination = ResolveDestinationName(session, DestinationName); } - public void OnMessage(Message message) + IMessageConsumer consumer = CreateConsumer(session, destination); + + consumer.MessageListener = new SimpleMessageListener(this, session); + return consumer; + } + + /// + /// Close the message consumers and sessions. + /// + /// EMSException if destruction failed + protected override void DoShutdown() + { + lock (consumersMonitor) + { + if (consumers != null) + { + logger.LogDebug("Closing EMS MessageConsumers"); + foreach (IMessageConsumer messageConsumer in consumers) + { + EmsUtils.CloseMessageConsumer(messageConsumer); + } + } + + if (sessions != null) + { + logger.LogDebug("Closing EMS Sessions"); + foreach (ISession session in sessions) + { + EmsUtils.CloseSession(session); + } + } + + consumers = null; + sessions = null; + } + } + + /// + /// Creates a MessageConsumer for the given Session and Destination. + /// + /// The session to create a MessageConsumer for. + /// The destination to create a MessageConsumer for. + /// The new MessageConsumer + protected IMessageConsumer CreateConsumer(ISession session, Destination destination) + { + // Only pass in the NoLocal flag in case of a Topic: + // Some EMS providers, such as WebSphere MQ 6.0, throw IllegalStateException + // in case of the NoLocal flag being specified for a Queue. + if (PubSubDomain) + { + if (SubscriptionDurable && destination is Topic) + { + return session.CreateDurableSubscriber( + (Topic) destination, DurableSubscriptionName, MessageSelector, PubSubNoLocal); + } + else + { + return session.CreateConsumer(destination, MessageSelector, PubSubNoLocal); + } + } + else + { + return session.CreateConsumer(destination, MessageSelector); + } + } +} + +internal class SimpleMessageListener : IMessageListener +{ + private SimpleMessageListenerContainer container; + private ISession session; + + public SimpleMessageListener(SimpleMessageListenerContainer container, ISession session) + { + this.container = container; + this.session = session; + } + + public void OnMessage(Message message) + { + bool exposeResource = container.ExposeListenerSession; + if (exposeResource) + { + TransactionSynchronizationManager.BindResource( + container.ConnectionFactory, new LocallyExposedEmsResourceHolder(session)); + } + + try + { + container.ExecuteListener(session, message); + } + finally { - bool exposeResource = container.ExposeListenerSession; if (exposeResource) { - TransactionSynchronizationManager.BindResource( - container.ConnectionFactory, new LocallyExposedEmsResourceHolder(session)); - } - try - { - container.ExecuteListener(session, message); - } finally - { - if (exposeResource) - { - TransactionSynchronizationManager.UnbindResource(container.ConnectionFactory); - } + TransactionSynchronizationManager.UnbindResource(container.ConnectionFactory); } } } diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Support/Converter/IMessageConverter.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Support/Converter/IMessageConverter.cs index fb15233c..55b633a5 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Support/Converter/IMessageConverter.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Support/Converter/IMessageConverter.cs @@ -20,36 +20,35 @@ using Spring.Messaging.Ems.Common; -namespace Spring.Messaging.Ems.Support.Converter -{ - /// Strategy interface that specifies a IMessageConverter - /// between .NET objects and EMS messages. - /// - /// - /// Mark Pollack - /// Juergen Hoeller - /// Mark Pollack (.NET) - public interface IMessageConverter - { - /// Convert a .NET object to a EMS Message using the supplied session - /// to create the message object. - /// - /// the object to convert - /// - /// the Session to use for creating a EMS Message - /// - /// the EMS Message - /// - /// EMSException if thrown by EMS API methods - /// MessageConversionException in case of conversion failure - Message ToMessage(object objectToConvert, ISession session); +namespace Spring.Messaging.Ems.Support.Converter; - /// Convert from a EMS Message to a .NET object. - /// the message to convert - /// - /// the converted .NET object - /// - /// MessageConversionException in case of conversion failure - object FromMessage(Message messageToConvert); - } +/// Strategy interface that specifies a IMessageConverter +/// between .NET objects and EMS messages. +/// +/// +/// Mark Pollack +/// Juergen Hoeller +/// Mark Pollack (.NET) +public interface IMessageConverter +{ + /// Convert a .NET object to a EMS Message using the supplied session + /// to create the message object. + /// + /// the object to convert + /// + /// the Session to use for creating a EMS Message + /// + /// the EMS Message + /// + /// EMSException if thrown by EMS API methods + /// MessageConversionException in case of conversion failure + Message ToMessage(object objectToConvert, ISession session); + + /// Convert from a EMS Message to a .NET object. + /// the message to convert + /// + /// the converted .NET object + /// + /// MessageConversionException in case of conversion failure + object FromMessage(Message messageToConvert); } diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Support/Converter/ITypeMapper.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Support/Converter/ITypeMapper.cs index 75ed03af..c59c0d6b 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Support/Converter/ITypeMapper.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Support/Converter/ITypeMapper.cs @@ -18,35 +18,34 @@ #endregion -namespace Spring.Messaging.Ems.Support.Converter +namespace Spring.Messaging.Ems.Support.Converter; + +/// +/// Provides a layer of indirection when adding the 'type' of the object as a message property. +/// +/// Mark Pollack +public interface ITypeMapper { /// - /// Provides a layer of indirection when adding the 'type' of the object as a message property. + /// Gets the name of the field in the message that has type information.. /// - /// Mark Pollack - public interface ITypeMapper + /// The name of the type id field. + string TypeIdFieldName { - /// - /// Gets the name of the field in the message that has type information.. - /// - /// The name of the type id field. - string TypeIdFieldName - { - get; - } - - /// - /// Convert from a type to a string. - /// - /// The type of object to convert. - /// - string FromType(Type typeOfObjectToConvert); - - /// - /// Convert from a string to a type - /// - /// The type id. - /// - Type ToType(string typeId); + get; } -} + + /// + /// Convert from a type to a string. + /// + /// The type of object to convert. + /// + string FromType(Type typeOfObjectToConvert); + + /// + /// Convert from a string to a type + /// + /// The type id. + /// + Type ToType(string typeId); +} \ No newline at end of file diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Support/Converter/MessageConversionException.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Support/Converter/MessageConversionException.cs index 324af2b0..398f953f 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Support/Converter/MessageConversionException.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Support/Converter/MessageConversionException.cs @@ -18,44 +18,42 @@ #endregion -namespace Spring.Messaging.Ems.Support.Converter +namespace Spring.Messaging.Ems.Support.Converter; + +/// Thrown by IMessageConverter implementations when the conversion +/// of an object to/from a Message fails. +/// +/// Mark Pollack +public class MessageConversionException : EMSException { - /// Thrown by IMessageConverter implementations when the conversion - /// of an object to/from a Message fails. + #region Constructor (s) / Destructor + + /// + /// Creates a new instance of the IMessageConverterException class. with the specified message. /// - /// Mark Pollack - public class MessageConversionException : EMSException + /// + /// A message about the exception. + /// + public MessageConversionException(string message) + : base(message) { - #region Constructor (s) / Destructor - - - /// - /// Creates a new instance of the IMessageConverterException class. with the specified message. - /// - /// - /// A message about the exception. - /// - public MessageConversionException(string message) - : base(message) - { - } - - /// - /// Creates a new instance of the IMessageConverterException class with the specified message - /// and root cause. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception that is being wrapped. - /// - public MessageConversionException(string message, Exception rootCause) - : base(message) - { - LinkedException = rootCause; - } - - #endregion } + + /// + /// Creates a new instance of the IMessageConverterException class with the specified message + /// and root cause. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception that is being wrapped. + /// + public MessageConversionException(string message, Exception rootCause) + : base(message) + { + LinkedException = rootCause; + } + + #endregion } diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Support/Converter/SimpleMessageConverter.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Support/Converter/SimpleMessageConverter.cs index b6f80c86..6fcdb382 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Support/Converter/SimpleMessageConverter.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Support/Converter/SimpleMessageConverter.cs @@ -21,211 +21,221 @@ using System.Collections; using Spring.Messaging.Ems.Common; -namespace Spring.Messaging.Ems.Support.Converter +namespace Spring.Messaging.Ems.Support.Converter; + +/// A simple message converter that can handle TextMessages, BytesMessages, +/// MapMessages, and ObjectMessages. Used as default by EmsTemplate, for +/// ConvertAndSend and ReceiveAndConvert operations. +/// +///

Converts a String to a EMS TextMessage, a byte array to a EMS BytesMessage, +/// a Map to a EMS MapMessage, and a Serializable object to a EMS ObjectMessage +/// (or vice versa).

+/// +/// +///
+/// Juergen Hoeller +/// Mark Pollack (.NET) +public class SimpleMessageConverter : IMessageConverter { - /// A simple message converter that can handle TextMessages, BytesMessages, - /// MapMessages, and ObjectMessages. Used as default by EmsTemplate, for - /// ConvertAndSend and ReceiveAndConvert operations. - /// - ///

Converts a String to a EMS TextMessage, a byte array to a EMS BytesMessage, - /// a Map to a EMS MapMessage, and a Serializable object to a EMS ObjectMessage - /// (or vice versa).

- /// - /// + /// Convert a .NET object to a EMS Message using the supplied session + /// to create the message object. /// - /// Juergen Hoeller - /// Mark Pollack (.NET) - public class SimpleMessageConverter : IMessageConverter + /// the object to convert + /// + /// the Session to use for creating a EMS Message + /// + /// the EMS Message + /// + /// EMSException if thrown by EMS API methods + /// MessageConversionException in case of conversion failure + public Message ToMessage(object objectToConvert, ISession session) { - /// Convert a .NET object to a EMS Message using the supplied session - /// to create the message object. - /// - /// the object to convert - /// - /// the Session to use for creating a EMS Message - /// - /// the EMS Message - /// - /// EMSException if thrown by EMS API methods - /// MessageConversionException in case of conversion failure - public Message ToMessage(object objectToConvert, ISession session) + if (objectToConvert is Message) { - if (objectToConvert is Message) - { - return (Message) objectToConvert; - } - if (objectToConvert is string) - { - return CreateMessageForString((string) objectToConvert, session); - } - if (objectToConvert is sbyte[]) - { - return CreateMessageForByteArray((byte[]) objectToConvert, session); - } - if (objectToConvert is IDictionary) - { - return CreateMessageForMap((IDictionary) objectToConvert, session); - } - if (objectToConvert != null && objectToConvert.GetType().IsSerializable) - { - return CreateMessageForSerializable(objectToConvert, session); - } - throw new MessageConversionException("Cannot convert object [" + objectToConvert + "] to EMS message"); + return (Message) objectToConvert; } - /// Convert from a EMS Message to a .NET object. - /// the message to convert - /// - /// the converted .NET object - /// - /// MessageConversionException in case of conversion failure - public object FromMessage(Message messageToConvert) + if (objectToConvert is string) { - if (messageToConvert is TextMessage) - { - return ExtractStringFromMessage((TextMessage) messageToConvert); - } - if (messageToConvert is BytesMessage) - { - return ExtractByteArrayFromMessage((BytesMessage) messageToConvert); - } - if (messageToConvert is MapMessage) - { - return ExtractMapFromMessage((MapMessage) messageToConvert); - } - if (messageToConvert is ObjectMessage) - { - return ExtractSerializableFromMessage((ObjectMessage) messageToConvert); - } - return messageToConvert; + return CreateMessageForString((string) objectToConvert, session); } - #region To Converter Methods - - /// Create a EMS TextMessage for the given String. - /// the String to convert - /// - /// current EMS session - /// - /// the resulting message - /// - /// EMSException if thrown by EMS methods - protected virtual TextMessage CreateMessageForString(string text, ISession session) + if (objectToConvert is sbyte[]) { - return session.CreateTextMessage((text)); + return CreateMessageForByteArray((byte[]) objectToConvert, session); } - /// Create a EMS BytesMessage for the given byte array. - /// the byyte array to convert - /// - /// current EMS session - /// - /// the resulting message - /// - /// EMSException if thrown by EMS methods - protected virtual BytesMessage CreateMessageForByteArray(byte[] bytes, ISession session) + if (objectToConvert is IDictionary) { - BytesMessage message = session.CreateBytesMessage(); - message.WriteBytes(bytes); - return message; + return CreateMessageForMap((IDictionary) objectToConvert, session); } - /// Create a EMS MapMessage for the given Map. - /// the Map to convert - /// - /// current EMS session - /// - /// the resulting message - /// - /// EMSException if thrown by EMS methods - protected virtual MapMessage CreateMessageForMap(IDictionary map, ISession session) + if (objectToConvert != null && objectToConvert.GetType().IsSerializable) { - MapMessage mapMessage = session.CreateMapMessage(); - foreach (DictionaryEntry entry in map) - { - if (!(entry.Key is string)) - { - throw new MessageConversionException("Cannot convert non-String key of type [" + - (entry.Key != null ? entry.Key.GetType().FullName : null) + - "] to MapMessage entry"); - } - mapMessage.SetObject(entry.Key.ToString(), entry.Value); - } - return mapMessage; + return CreateMessageForSerializable(objectToConvert, session); } - /// Create a EMS ObjectMessage for the given Serializable object. - /// the Serializable object to convert - /// - /// current EMS session - /// - /// the resulting message - /// - /// EMSException if thrown by EMS methods - protected virtual ObjectMessage CreateMessageForSerializable( - object objectToSend, ISession session) - { - return session.CreateObjectMessage(objectToSend); - } - - #endregion - - #region From Converter Mehtods - - /// Extract a String from the given TextMessage. - /// the message to convert - /// - /// the resulting String - /// - /// EMSException if thrown by EMS methods - protected virtual string ExtractStringFromMessage(TextMessage message) - { - return message.Text; - } - - /// Extract a byte array from the given BytesMessage. - /// the message to convert - /// - /// the resulting byte array - /// - /// EMSException if thrown by EMS methods - protected virtual byte[] ExtractByteArrayFromMessage(BytesMessage message) - { - byte[] bytes = new byte[(int)message.BodyLength]; - message.ReadBytes(bytes); - return bytes; - } - - /// Extract a IDictionary from the given MapMessage. - /// the message to convert - /// - /// the resulting Map - /// - /// EMSException if thrown by EMS methods - protected virtual IDictionary ExtractMapFromMessage(MapMessage message) - { - IDictionary dictionary = new Hashtable(); - IEnumerator e = message.MapNames; - while (e.MoveNext()) - { - String key = (String)e.Current; - dictionary.Add(key, message.GetObject(key)); - } - - return dictionary; - } - - /// - /// Extracts the serializable object from the given object message. - /// - /// The message to convert. - /// The resulting serializable object. - protected virtual object ExtractSerializableFromMessage( - ObjectMessage message) - { - return message.TheObject; - } - - #endregion + throw new MessageConversionException("Cannot convert object [" + objectToConvert + "] to EMS message"); } + + /// Convert from a EMS Message to a .NET object. + /// the message to convert + /// + /// the converted .NET object + /// + /// MessageConversionException in case of conversion failure + public object FromMessage(Message messageToConvert) + { + if (messageToConvert is TextMessage) + { + return ExtractStringFromMessage((TextMessage) messageToConvert); + } + + if (messageToConvert is BytesMessage) + { + return ExtractByteArrayFromMessage((BytesMessage) messageToConvert); + } + + if (messageToConvert is MapMessage) + { + return ExtractMapFromMessage((MapMessage) messageToConvert); + } + + if (messageToConvert is ObjectMessage) + { + return ExtractSerializableFromMessage((ObjectMessage) messageToConvert); + } + + return messageToConvert; + } + + #region To Converter Methods + + /// Create a EMS TextMessage for the given String. + /// the String to convert + /// + /// current EMS session + /// + /// the resulting message + /// + /// EMSException if thrown by EMS methods + protected virtual TextMessage CreateMessageForString(string text, ISession session) + { + return session.CreateTextMessage((text)); + } + + /// Create a EMS BytesMessage for the given byte array. + /// the byyte array to convert + /// + /// current EMS session + /// + /// the resulting message + /// + /// EMSException if thrown by EMS methods + protected virtual BytesMessage CreateMessageForByteArray(byte[] bytes, ISession session) + { + BytesMessage message = session.CreateBytesMessage(); + message.WriteBytes(bytes); + return message; + } + + /// Create a EMS MapMessage for the given Map. + /// the Map to convert + /// + /// current EMS session + /// + /// the resulting message + /// + /// EMSException if thrown by EMS methods + protected virtual MapMessage CreateMessageForMap(IDictionary map, ISession session) + { + MapMessage mapMessage = session.CreateMapMessage(); + foreach (DictionaryEntry entry in map) + { + if (!(entry.Key is string)) + { + throw new MessageConversionException("Cannot convert non-String key of type [" + + (entry.Key != null ? entry.Key.GetType().FullName : null) + + "] to MapMessage entry"); + } + + mapMessage.SetObject(entry.Key.ToString(), entry.Value); + } + + return mapMessage; + } + + /// Create a EMS ObjectMessage for the given Serializable object. + /// the Serializable object to convert + /// + /// current EMS session + /// + /// the resulting message + /// + /// EMSException if thrown by EMS methods + protected virtual ObjectMessage CreateMessageForSerializable( + object objectToSend, ISession session) + { + return session.CreateObjectMessage(objectToSend); + } + + #endregion + + #region From Converter Mehtods + + /// Extract a String from the given TextMessage. + /// the message to convert + /// + /// the resulting String + /// + /// EMSException if thrown by EMS methods + protected virtual string ExtractStringFromMessage(TextMessage message) + { + return message.Text; + } + + /// Extract a byte array from the given BytesMessage. + /// the message to convert + /// + /// the resulting byte array + /// + /// EMSException if thrown by EMS methods + protected virtual byte[] ExtractByteArrayFromMessage(BytesMessage message) + { + byte[] bytes = new byte[(int) message.BodyLength]; + message.ReadBytes(bytes); + return bytes; + } + + /// Extract a IDictionary from the given MapMessage. + /// the message to convert + /// + /// the resulting Map + /// + /// EMSException if thrown by EMS methods + protected virtual IDictionary ExtractMapFromMessage(MapMessage message) + { + IDictionary dictionary = new Hashtable(); + IEnumerator e = message.MapNames; + while (e.MoveNext()) + { + String key = (String) e.Current; + dictionary.Add(key, message.GetObject(key)); + } + + return dictionary; + } + + /// + /// Extracts the serializable object from the given object message. + /// + /// The message to convert. + /// The resulting serializable object. + protected virtual object ExtractSerializableFromMessage( + ObjectMessage message) + { + return message.TheObject; + } + + #endregion } diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Support/Converter/TypeMapper.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Support/Converter/TypeMapper.cs index 5acf29c7..a154dcbe 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Support/Converter/TypeMapper.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Support/Converter/TypeMapper.cs @@ -21,178 +21,175 @@ using System.Collections; using Spring.Core.TypeResolution; -namespace Spring.Messaging.Ems.Support.Converter +namespace Spring.Messaging.Ems.Support.Converter; + +/// +/// Provides a layer of indirection when adding the 'type' of the object as a message property. +/// +public class TypeMapper : ITypeMapper { + private string defaultNamespace; + private string defaultAssemblyName; + + //Generics not used to support both 1.1 and 2.0 + private IDictionary idTypeMapping; + private IDictionary typeIdMapping; + + private string defaultHashtableTypeId = "Hashtable"; + + private Type defaultHashtableClass = typeof(Hashtable); + /// - /// Provides a layer of indirection when adding the 'type' of the object as a message property. + /// Initializes a new instance of the /// - public class TypeMapper : ITypeMapper + public TypeMapper() { - private string defaultNamespace; - private string defaultAssemblyName; + idTypeMapping = new Hashtable(); + typeIdMapping = new Hashtable(); + } - //Generics not used to support both 1.1 and 2.0 - private IDictionary idTypeMapping; - private IDictionary typeIdMapping; + /// + /// Gets or sets the id type mapping. + /// + /// The id type mapping. + public IDictionary IdTypeMapping + { + get { return idTypeMapping; } + set { idTypeMapping = value; } + } - private string defaultHashtableTypeId = "Hashtable"; + /// + /// Gets the name of the field in the message that has type information.. + /// + /// The name of the type id field. + public string TypeIdFieldName + { + get { return "__TypeId__"; } + } - private Type defaultHashtableClass = typeof(Hashtable); + /// + /// Sets the default hashtable class. + /// + /// The default hashtable class. + public Type DefaultHashtableClass + { + set { defaultHashtableClass = value; } + } - /// - /// Initializes a new instance of the - /// - public TypeMapper() + /// + /// Convert from a type to a string. + /// + /// The type of object to convert. + /// + public string FromType(Type typeOfObjectToConvert) + { + if (typeIdMapping.Contains(typeOfObjectToConvert)) { - idTypeMapping = new Hashtable(); - typeIdMapping = new Hashtable(); + return typeIdMapping[typeOfObjectToConvert] as string; } - - - /// - /// Gets or sets the id type mapping. - /// - /// The id type mapping. - public IDictionary IdTypeMapping + else { - get { return idTypeMapping; } - set { idTypeMapping = value; } - } - - /// - /// Gets the name of the field in the message that has type information.. - /// - /// The name of the type id field. - public string TypeIdFieldName - { - get { return "__TypeId__"; } - } - - - /// - /// Sets the default hashtable class. - /// - /// The default hashtable class. - public Type DefaultHashtableClass - { - set { defaultHashtableClass = value; } - } - - /// - /// Convert from a type to a string. - /// - /// The type of object to convert. - /// - public string FromType(Type typeOfObjectToConvert) - { - - if (typeIdMapping.Contains(typeOfObjectToConvert)) + if (typeof(IDictionary).IsAssignableFrom(typeOfObjectToConvert)) { - return typeIdMapping[typeOfObjectToConvert] as string; - } - else - { - if ( typeof (IDictionary).IsAssignableFrom(typeOfObjectToConvert)) - { - return defaultHashtableTypeId; - } - return typeOfObjectToConvert.Name; - } - } - - /// - /// Convert from a string to a type - /// - /// The type id. - /// - public Type ToType(string typeId) - { - if (idTypeMapping.Contains(typeId)) - { - return idTypeMapping[typeId] as Type; - } - else - { - if (typeId.Equals(defaultHashtableTypeId)) - { - return defaultHashtableClass; - } - string fullyQualifiedTypeName = defaultNamespace + "." + - typeId + ", " + - DefaultAssemblyName; - return TypeResolutionUtils.ResolveType(fullyQualifiedTypeName); + return defaultHashtableTypeId; } - } - - /// - /// Gets or sets the default namespace. - /// - /// The default namespace. - public string DefaultNamespace - { - get - { - return defaultNamespace; - } - set - { - defaultNamespace = value; - } - - } - - /// - /// Gets or sets the default name of the assembly. - /// - /// The default name of the assembly. - public string DefaultAssemblyName - { - get - { - return defaultAssemblyName; - } - set - { - defaultAssemblyName = value; - } - } - - /// - /// Afters the properties set. - /// - public void AfterPropertiesSet() - { - ValidateIdTypeMapping(); - if (DefaultAssemblyName != null && DefaultNamespace == null) - { - throw new ArgumentException("Default Namespace required when DefaultAssemblyName is set."); - } - if (DefaultNamespace != null && DefaultAssemblyName == null) - { - throw new ArgumentException("Default Assembly Name required when DefaultNamespace is set."); - } - } - - - private void ValidateIdTypeMapping() - { - IDictionary finalIdTypeMapping = new Hashtable(); - foreach (DictionaryEntry entry in idTypeMapping) - { - string id = entry.Key.ToString(); - Type t = entry.Value as Type; - if (t == null) - { - //convert from string value. - string typeName = entry.Value.ToString(); - t = TypeResolutionUtils.ResolveType(typeName); - } - finalIdTypeMapping.Add(id,t); - typeIdMapping.Add(t,id); - - } - idTypeMapping = finalIdTypeMapping; + return typeOfObjectToConvert.Name; } } + + /// + /// Convert from a string to a type + /// + /// The type id. + /// + public Type ToType(string typeId) + { + if (idTypeMapping.Contains(typeId)) + { + return idTypeMapping[typeId] as Type; + } + else + { + if (typeId.Equals(defaultHashtableTypeId)) + { + return defaultHashtableClass; + } + + string fullyQualifiedTypeName = defaultNamespace + "." + + typeId + ", " + + DefaultAssemblyName; + return TypeResolutionUtils.ResolveType(fullyQualifiedTypeName); + } + } + + /// + /// Gets or sets the default namespace. + /// + /// The default namespace. + public string DefaultNamespace + { + get + { + return defaultNamespace; + } + set + { + defaultNamespace = value; + } + } + + /// + /// Gets or sets the default name of the assembly. + /// + /// The default name of the assembly. + public string DefaultAssemblyName + { + get + { + return defaultAssemblyName; + } + set + { + defaultAssemblyName = value; + } + } + + /// + /// Afters the properties set. + /// + public void AfterPropertiesSet() + { + ValidateIdTypeMapping(); + if (DefaultAssemblyName != null && DefaultNamespace == null) + { + throw new ArgumentException("Default Namespace required when DefaultAssemblyName is set."); + } + + if (DefaultNamespace != null && DefaultAssemblyName == null) + { + throw new ArgumentException("Default Assembly Name required when DefaultNamespace is set."); + } + } + + private void ValidateIdTypeMapping() + { + IDictionary finalIdTypeMapping = new Hashtable(); + foreach (DictionaryEntry entry in idTypeMapping) + { + string id = entry.Key.ToString(); + Type t = entry.Value as Type; + if (t == null) + { + //convert from string value. + string typeName = entry.Value.ToString(); + t = TypeResolutionUtils.ResolveType(typeName); + } + + finalIdTypeMapping.Add(id, t); + typeIdMapping.Add(t, id); + } + + idTypeMapping = finalIdTypeMapping; + } } diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Support/Converter/XmlMessageConverter.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Support/Converter/XmlMessageConverter.cs index b56047a9..79a1b870 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Support/Converter/XmlMessageConverter.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Support/Converter/XmlMessageConverter.cs @@ -4,194 +4,194 @@ using System.Xml; using System.Xml.Serialization; using Spring.Messaging.Ems.Common; -namespace Spring.Messaging.Ems.Support.Converter +namespace Spring.Messaging.Ems.Support.Converter; + +/// +/// Convert an object via XML serialization for sending via an ITextMessage +/// +/// Mark Pollack +public class XmlMessageConverter : IMessageConverter { + private IMessageConverter defaultMessageConverter = new SimpleMessageConverter(); + + private ITypeMapper typeMapper; + + private bool encoderShouldEmitUTF8Identifier = false; + + private bool throwOnInvalidBytes = true; + /// - /// Convert an object via XML serialization for sending via an ITextMessage + /// Sets the type mapper. /// - /// Mark Pollack - public class XmlMessageConverter : IMessageConverter + /// The type mapper. + public ITypeMapper TypeMapper { - private IMessageConverter defaultMessageConverter = new SimpleMessageConverter(); + set { typeMapper = value; } + } + /// + /// Gets or sets a value indicating whether encoder should emit UTF8 byte order mark. Default is false. + /// + /// + /// true to specify that a Unicode byte order mark is provided; otherwise, false. + /// + public bool EncoderShouldEmitUtf8Identifier + { + get { return encoderShouldEmitUTF8Identifier; } + set { encoderShouldEmitUTF8Identifier = value; } + } - private ITypeMapper typeMapper; + /// + /// Gets or sets a value indicating whether to throw an exception on invalid bytes. Default is true. + /// + /// true to specify that an exception be thrown when an invalid encoding is detected; otherwise, false. + /// + public bool ThrowOnInvalidBytes + { + get { return throwOnInvalidBytes; } + set { throwOnInvalidBytes = value; } + } - private bool encoderShouldEmitUTF8Identifier = false; - - private bool throwOnInvalidBytes = true; - - - /// - /// Sets the type mapper. - /// - /// The type mapper. - public ITypeMapper TypeMapper + /// + /// Convert a .NET object to a EMS Message using the supplied session + /// to create the message object. + /// + /// the object to convert + /// the Session to use for creating a EMS Message + /// the EMS Message + /// EMSException if thrown by EMS API methods + /// MessageConversionException in case of conversion failure + public Message ToMessage(object objectToConvert, ISession session) + { + if (objectToConvert == null) { - set { typeMapper = value; } + throw new MessageConversionException("Can't convert null object"); } - /// - /// Gets or sets a value indicating whether encoder should emit UTF8 byte order mark. Default is false. - /// - /// - /// true to specify that a Unicode byte order mark is provided; otherwise, false. - /// - public bool EncoderShouldEmitUtf8Identifier + try { - get { return encoderShouldEmitUTF8Identifier; } - set { encoderShouldEmitUTF8Identifier = value; } - } - - /// - /// Gets or sets a value indicating whether to throw an exception on invalid bytes. Default is true. - /// - /// true to specify that an exception be thrown when an invalid encoding is detected; otherwise, false. - /// - public bool ThrowOnInvalidBytes - { - get { return throwOnInvalidBytes; } - set { throwOnInvalidBytes = value; } - } - - /// - /// Convert a .NET object to a EMS Message using the supplied session - /// to create the message object. - /// - /// the object to convert - /// the Session to use for creating a EMS Message - /// the EMS Message - /// EMSException if thrown by EMS API methods - /// MessageConversionException in case of conversion failure - public Message ToMessage(object objectToConvert, ISession session) - { - if (objectToConvert == null) + if (objectToConvert.GetType().Equals(typeof(string)) || + typeof(IDictionary).IsAssignableFrom(objectToConvert.GetType()) || + objectToConvert.GetType().Equals(typeof(Byte[]))) { - throw new MessageConversionException("Can't convert null object"); - } - try - { - if (objectToConvert.GetType().Equals(typeof(string)) || - typeof(IDictionary).IsAssignableFrom(objectToConvert.GetType()) || - objectToConvert.GetType().Equals(typeof(Byte[]))) - { - return defaultMessageConverter.ToMessage(objectToConvert, session); - } - string xmlString = GetXmlString(objectToConvert); - Message msg = session.CreateTextMessage(xmlString); - msg.SetStringProperty(typeMapper.TypeIdFieldName, typeMapper.FromType(objectToConvert.GetType())); - return msg; - } - catch (Exception e) - { - throw new MessageConversionException("Can't convert object of type " + objectToConvert.GetType(), e); + return defaultMessageConverter.ToMessage(objectToConvert, session); } + + string xmlString = GetXmlString(objectToConvert); + Message msg = session.CreateTextMessage(xmlString); + msg.SetStringProperty(typeMapper.TypeIdFieldName, typeMapper.FromType(objectToConvert.GetType())); + return msg; } - - /// - /// Gets the XML string for an object - /// - /// The object to convert. - /// XML string - protected virtual string GetXmlString(object objectToConvert) + catch (Exception e) { - string xmlString; - try - { - using (MemoryStream memoryStream = new MemoryStream()) - { - using (XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, new UTF8Encoding(EncoderShouldEmitUtf8Identifier))) - { - XmlSerializer xs = new XmlSerializer(objectToConvert.GetType()); - xs.Serialize(xmlTextWriter, objectToConvert); - xmlString = UTF8ByteArrayToString(((MemoryStream) xmlTextWriter.BaseStream).ToArray()); - } - } - } catch (Exception e) - { - throw new MessageConversionException("Can't convert object of type " + objectToConvert.GetType(), e); - } - return xmlString; - } - - /// - /// Convert from a EMS Message to a .NET object. - /// - /// the message to convert - /// the converted .NET object - /// MessageConversionException in case of conversion failure - public object FromMessage(Message messageToConvert) - { - if (messageToConvert == null) - { - throw new MessageConversionException("Can't convert null message"); - } - try - { - string converterId = messageToConvert.GetStringProperty(typeMapper.TypeIdFieldName); - if (converterId == null) - { - return defaultMessageConverter.FromMessage(messageToConvert); - } - TextMessage textMessage = messageToConvert as TextMessage; - if (textMessage == null) - { - throw new MessageConversionException("Can't convert message of type " + - messageToConvert.GetType()); - } - - using (MemoryStream memoryStream = new MemoryStream(StringToUTF8ByteArray(textMessage.Text))) - { - - XmlSerializer xs = new XmlSerializer(GetTargetType(textMessage)); - XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.UTF8); - return xs.Deserialize(memoryStream); - } - } - catch (Exception e) - { - throw new MessageConversionException("Can't convert message of type " + messageToConvert.GetType(), e); - } - } - - /// - /// Gets the type of the target given the message. - /// - /// The message. - /// Type of the target - protected virtual Type GetTargetType(TextMessage message) - { - return typeMapper.ToType(message.GetStringProperty(typeMapper.TypeIdFieldName)); - } - - - /// - /// Converts a byte array to a UTF8 string. - /// - /// The characters. - /// UTF8 string - protected virtual String UTF8ByteArrayToString(Byte[] characters) - { - UTF8Encoding encoding = new UTF8Encoding(EncoderShouldEmitUtf8Identifier, ThrowOnInvalidBytes); - - String constructedString = encoding.GetString(characters); - - return (constructedString); - } - - - /// - /// Converts a UTF8 string to a byte array - /// - /// The p XML string. - /// - protected virtual Byte[] StringToUTF8ByteArray(String xmlString) - { - UTF8Encoding encoding = new UTF8Encoding(); - - Byte[] byteArray = encoding.GetBytes(xmlString); - - return byteArray; + throw new MessageConversionException("Can't convert object of type " + objectToConvert.GetType(), e); } } -} + + /// + /// Gets the XML string for an object + /// + /// The object to convert. + /// XML string + protected virtual string GetXmlString(object objectToConvert) + { + string xmlString; + try + { + using (MemoryStream memoryStream = new MemoryStream()) + { + using (XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, new UTF8Encoding(EncoderShouldEmitUtf8Identifier))) + { + XmlSerializer xs = new XmlSerializer(objectToConvert.GetType()); + xs.Serialize(xmlTextWriter, objectToConvert); + xmlString = UTF8ByteArrayToString(((MemoryStream) xmlTextWriter.BaseStream).ToArray()); + } + } + } + catch (Exception e) + { + throw new MessageConversionException("Can't convert object of type " + objectToConvert.GetType(), e); + } + + return xmlString; + } + + /// + /// Convert from a EMS Message to a .NET object. + /// + /// the message to convert + /// the converted .NET object + /// MessageConversionException in case of conversion failure + public object FromMessage(Message messageToConvert) + { + if (messageToConvert == null) + { + throw new MessageConversionException("Can't convert null message"); + } + + try + { + string converterId = messageToConvert.GetStringProperty(typeMapper.TypeIdFieldName); + if (converterId == null) + { + return defaultMessageConverter.FromMessage(messageToConvert); + } + + TextMessage textMessage = messageToConvert as TextMessage; + if (textMessage == null) + { + throw new MessageConversionException("Can't convert message of type " + + messageToConvert.GetType()); + } + + using (MemoryStream memoryStream = new MemoryStream(StringToUTF8ByteArray(textMessage.Text))) + { + XmlSerializer xs = new XmlSerializer(GetTargetType(textMessage)); + XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.UTF8); + return xs.Deserialize(memoryStream); + } + } + catch (Exception e) + { + throw new MessageConversionException("Can't convert message of type " + messageToConvert.GetType(), e); + } + } + + /// + /// Gets the type of the target given the message. + /// + /// The message. + /// Type of the target + protected virtual Type GetTargetType(TextMessage message) + { + return typeMapper.ToType(message.GetStringProperty(typeMapper.TypeIdFieldName)); + } + + /// + /// Converts a byte array to a UTF8 string. + /// + /// The characters. + /// UTF8 string + protected virtual String UTF8ByteArrayToString(Byte[] characters) + { + UTF8Encoding encoding = new UTF8Encoding(EncoderShouldEmitUtf8Identifier, ThrowOnInvalidBytes); + + String constructedString = encoding.GetString(characters); + + return (constructedString); + } + + /// + /// Converts a UTF8 string to a byte array + /// + /// The p XML string. + /// + protected virtual Byte[] StringToUTF8ByteArray(String xmlString) + { + UTF8Encoding encoding = new UTF8Encoding(); + + Byte[] byteArray = encoding.GetBytes(xmlString); + + return byteArray; + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Support/Destinations/DynamicDestinationResolver.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Support/Destinations/DynamicDestinationResolver.cs index 07a38345..fcea8aa1 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Support/Destinations/DynamicDestinationResolver.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Support/Destinations/DynamicDestinationResolver.cs @@ -21,63 +21,62 @@ using Spring.Messaging.Ems.Common; using Spring.Util; -namespace Spring.Messaging.Ems.Support.Destinations +namespace Spring.Messaging.Ems.Support.Destinations; + +/// Simple DestinationResolver implementation resolving destination names +/// as dynamic destinations. +/// +/// Juergen Hoeller +/// Mark Pollack (.NET) +public class DynamicDestinationResolver : IDestinationResolver { - /// Simple DestinationResolver implementation resolving destination names - /// as dynamic destinations. - /// - /// Juergen Hoeller - /// Mark Pollack (.NET) - public class DynamicDestinationResolver : IDestinationResolver + /// Resolve the given destination name, either as located resource + /// or as dynamic destination. + /// + /// the current EMS Session + /// + /// the name of the destination + /// + /// true if the domain is pub-sub, false if P2P + /// + /// the EMS destination (either a topic or a queue) + /// + /// EMSException if resolution failed + public Destination ResolveDestinationName(ISession session, string destinationName, bool pubSubDomain) { - /// Resolve the given destination name, either as located resource - /// or as dynamic destination. - /// - /// the current EMS Session - /// - /// the name of the destination - /// - /// true if the domain is pub-sub, false if P2P - /// - /// the EMS destination (either a topic or a queue) - /// - /// EMSException if resolution failed - public Destination ResolveDestinationName(ISession session, string destinationName, bool pubSubDomain) + AssertUtils.ArgumentNotNull(session, "Session must not be null"); + AssertUtils.ArgumentNotNull(destinationName, "Destination name must not be null"); + if (pubSubDomain) { - AssertUtils.ArgumentNotNull(session, "Session must not be null"); - AssertUtils.ArgumentNotNull(destinationName, "Destination name must not be null"); - if (pubSubDomain) - { - return ResolveTopic(session, destinationName); - } - return ResolveQueue(session, destinationName); + return ResolveTopic(session, destinationName); } - - /// Resolve the given destination name to a Topic. - /// the current EMS Session - /// - /// the name of the desired Topic. - /// - /// the EMS Topic name - /// - /// EMSException if resolution failed - protected internal virtual Destination ResolveTopic(ISession session, string topicName) - { - return session.CreateTopic(topicName); - } - - /// Resolve the given destination name to a Queue. - /// the current EMS Session - /// - /// the name of the desired Queue. - /// - /// the EMS Queue name - /// - /// EMSException if resolution failed - protected internal virtual Destination ResolveQueue(ISession session, string queueName) - { - return session.CreateQueue(queueName); - } + return ResolveQueue(session, destinationName); } -} + + /// Resolve the given destination name to a Topic. + /// the current EMS Session + /// + /// the name of the desired Topic. + /// + /// the EMS Topic name + /// + /// EMSException if resolution failed + protected internal virtual Destination ResolveTopic(ISession session, string topicName) + { + return session.CreateTopic(topicName); + } + + /// Resolve the given destination name to a Queue. + /// the current EMS Session + /// + /// the name of the desired Queue. + /// + /// the EMS Queue name + /// + /// EMSException if resolution failed + protected internal virtual Destination ResolveQueue(ISession session, string queueName) + { + return session.CreateQueue(queueName); + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Support/Destinations/EmsDestinationAccessor.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Support/Destinations/EmsDestinationAccessor.cs index 7d6eb12c..92697fef 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Support/Destinations/EmsDestinationAccessor.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Support/Destinations/EmsDestinationAccessor.cs @@ -21,90 +21,86 @@ using Spring.Messaging.Ems.Common; using Spring.Util; -namespace Spring.Messaging.Ems.Support.Destinations +namespace Spring.Messaging.Ems.Support.Destinations; + +/// Base class for EmsTemplate} and other +/// EMS-accessing gateway helpers, adding destination-related properties to +/// EmsAccessor's common properties. +/// +/// +///

Not intended to be used directly. See EmsTemplate.

+/// +///
+/// Juergen Hoeller +/// Mark Pollack (.NET) +public class EmsDestinationAccessor : EmsAccessor { - /// Base class for EmsTemplate} and other - /// EMS-accessing gateway helpers, adding destination-related properties to - /// EmsAccessor's common properties. + #region Fields + + private IDestinationResolver destinationResolver = new DynamicDestinationResolver(); + + private bool pubSubDomain = false; + + #endregion + + #region Properties + + /// + /// Gets or sets the destination resolver that is to be used to resolve + /// Destination references for this accessor. /// - /// - ///

Not intended to be used directly. See EmsTemplate.

- /// + /// The default resolver is a DynamicDestinationResolver. Specify a + /// JndDestinationResolver for resolving destination names as JNDI locations. /// - /// Juergen Hoeller - /// Mark Pollack (.NET) - public class EmsDestinationAccessor : EmsAccessor + /// The destination resolver. + virtual public IDestinationResolver DestinationResolver { - #region Fields - - private IDestinationResolver destinationResolver = new DynamicDestinationResolver(); - - private bool pubSubDomain = false; - - #endregion - - #region Properties - - /// - /// Gets or sets the destination resolver that is to be used to resolve - /// Destination references for this accessor. - /// - /// The default resolver is a DynamicDestinationResolver. Specify a - /// JndDestinationResolver for resolving destination names as JNDI locations. - /// - /// The destination resolver. - virtual public IDestinationResolver DestinationResolver + get { - get - { - return destinationResolver; - } - - set - { - AssertUtils.ArgumentNotNull(value, "DestinationResolver must not be null"); - this.destinationResolver = value; - } - + return destinationResolver; } - - /// - /// Gets or sets a value indicating whether Publish/Subscribe - /// domain (Topics) is used. Otherwise, the Point-to-Point domain - /// (Queues) is used. - /// - /// - /// this - /// setting tells what type of destination to create if dynamic destinations are enabled. - /// true if Publish/Subscribe domain; otherwise, false - /// for the Point-to-Point domain. - public virtual bool PubSubDomain + set { - get - { - return pubSubDomain; - } - - set - { - this.pubSubDomain = value; - } - - } - - #endregion - - /// - /// Resolves the given destination name to a EMS destination. - /// - /// The current session. - /// Name of the destination. - /// The located Destination - /// If resolution failed. - public virtual Destination ResolveDestinationName(ISession session, System.String destinationName) - { - return DestinationResolver.ResolveDestinationName(session, destinationName, PubSubDomain); + AssertUtils.ArgumentNotNull(value, "DestinationResolver must not be null"); + this.destinationResolver = value; } } + + /// + /// Gets or sets a value indicating whether Publish/Subscribe + /// domain (Topics) is used. Otherwise, the Point-to-Point domain + /// (Queues) is used. + /// + /// + /// this + /// setting tells what type of destination to create if dynamic destinations are enabled. + /// true if Publish/Subscribe domain; otherwise, false + /// for the Point-to-Point domain. + public virtual bool PubSubDomain + { + get + { + return pubSubDomain; + } + + set + { + this.pubSubDomain = value; + } + } + + #endregion + + /// + /// Resolves the given destination name to a EMS destination. + /// + /// The current session. + /// Name of the destination. + /// The located Destination + /// If resolution failed. + public virtual Destination ResolveDestinationName(ISession session, System.String destinationName) + { + return DestinationResolver.ResolveDestinationName(session, destinationName, PubSubDomain); + } } diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Support/Destinations/IDestinationResolver.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Support/Destinations/IDestinationResolver.cs index 8235bb39..342e4c8c 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Support/Destinations/IDestinationResolver.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Support/Destinations/IDestinationResolver.cs @@ -20,39 +20,37 @@ using Spring.Messaging.Ems.Common; -namespace Spring.Messaging.Ems.Support.Destinations -{ - /// Strategy interface for resolving EMS destinations. - /// - /// - /// Used by EmsTemplate for resolving - /// destination names from simple Strings to actual - /// Destination implementation instances. - /// - /// - /// The default DestinationResolver implementation used by - /// EmsTemplate instances is the - /// DynamicDestinationResolver class. Consider using the - /// JndDestinationResolver for more advanced scenarios. - /// - /// - /// Juergen Hoeller - /// Mark Pollack (.NET) - public interface IDestinationResolver - { - /// Resolve the given destination name, either as located resource - /// or as dynamic destination. - /// - /// the current EMS Session - /// - /// the name of the destination - /// - /// true if the domain is pub-sub, false if P2P - /// - /// the EMS destination (either a topic or a queue) - /// - /// EMSException if resolution failed - Destination ResolveDestinationName(ISession session, string destinationName, bool pubSubDomain); +namespace Spring.Messaging.Ems.Support.Destinations; - } +/// Strategy interface for resolving EMS destinations. +/// +/// +/// Used by EmsTemplate for resolving +/// destination names from simple Strings to actual +/// Destination implementation instances. +/// +/// +/// The default DestinationResolver implementation used by +/// EmsTemplate instances is the +/// DynamicDestinationResolver class. Consider using the +/// JndDestinationResolver for more advanced scenarios. +/// +/// +/// Juergen Hoeller +/// Mark Pollack (.NET) +public interface IDestinationResolver +{ + /// Resolve the given destination name, either as located resource + /// or as dynamic destination. + /// + /// the current EMS Session + /// + /// the name of the destination + /// + /// true if the domain is pub-sub, false if P2P + /// + /// the EMS destination (either a topic or a queue) + /// + /// EMSException if resolution failed + Destination ResolveDestinationName(ISession session, string destinationName, bool pubSubDomain); } diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Support/EmsAccessor.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Support/EmsAccessor.cs index 3a24ddf0..82e9a277 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Support/EmsAccessor.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Support/EmsAccessor.cs @@ -21,148 +21,143 @@ using Spring.Messaging.Ems.Common; using Spring.Objects.Factory; -namespace Spring.Messaging.Ems.Support +namespace Spring.Messaging.Ems.Support; + +/// Base class for EmsTemplate and other EMS-accessing gateway helpers +/// It defines common properties like the ConnectionFactory}. The subclass +/// EmsDestinationAccessor adds further, destination-related properties. +/// +/// Not intended to be used directly. See EmsTemplate. +/// +/// +/// Juergen Hoeller +/// Mark Pollack (.NET) +public class EmsAccessor : IInitializingObject { - /// Base class for EmsTemplate and other EMS-accessing gateway helpers - /// It defines common properties like the ConnectionFactory}. The subclass - /// EmsDestinationAccessor adds further, destination-related properties. - /// - /// Not intended to be used directly. See EmsTemplate. - /// - /// - /// Juergen Hoeller - /// Mark Pollack (.NET) - public class EmsAccessor : IInitializingObject + #region Logging + + private readonly ILogger logger = LogManager.GetLogger(); + + #endregion + + #region Fields + + private IConnectionFactory connectionFactory; + + private bool sessionTransacted = false; + + private int sessionAcknowledgeMode = Session.AUTO_ACKNOWLEDGE; + + #endregion + + #region Properties + + /// + /// Gets or sets the connection factory to use for obtaining EMS Connections. + /// + /// The connection factory. + virtual public IConnectionFactory ConnectionFactory { - #region Logging - - private readonly ILogger logger = LogManager.GetLogger(); - - #endregion - - #region Fields - - private IConnectionFactory connectionFactory; - - private bool sessionTransacted = false; - - private int sessionAcknowledgeMode = Session.AUTO_ACKNOWLEDGE; - - #endregion - - #region Properties - - - /// - /// Gets or sets the connection factory to use for obtaining EMS Connections. - /// - /// The connection factory. - virtual public IConnectionFactory ConnectionFactory + get { - get - { - return connectionFactory; - } - - set - { - this.connectionFactory = value; - } + return connectionFactory; } - - /// - /// Gets or sets the session acknowledge mode for EMS Sessions including whether or not the session is transacted - /// - /// - /// Set the EMS acknowledgement mode that is used when creating a EMS - /// Session to send a message. The default is AUTO_ACKNOWLEDGE. - /// - /// The session acknowledge mode. - virtual public int SessionAcknowledgeMode + set { - get - { - return sessionAcknowledgeMode; - } - - set - { - this.sessionAcknowledgeMode = value; - } - - } - - /// - /// Set the transaction mode that is used when creating a EMS Session. - /// Default is "false". - /// - /// - /// Setting this flag to "true" will use a short local EMS transaction - /// when running outside of a managed transaction, and a synchronized local - /// EMS transaction in case of a managed transaction being present. - /// The latter has the effect of a local EMS - /// transaction being managed alongside the main transaction (which might - /// be a native ADO.NET transaction), with the EMS transaction committing - /// right after the main transaction. - /// - /// - public bool SessionTransacted - { - get - { - return sessionTransacted; - } - set - { - if (value) - { - sessionTransacted = value; - } - } - } - - #endregion - - - /// - /// Verify that ConnectionFactory property has been set. - /// - public virtual void AfterPropertiesSet() - { - if (ConnectionFactory == null) - { - throw new ArgumentException("ConnectionFactory is required"); - } - } - - /// - /// Creates the connection via the ConnectionFactory. - /// - /// - protected virtual IConnection CreateConnection() - { - return ConnectionFactory.CreateConnection(); - } - - /// - /// Creates the session for the given Connection - /// - /// The connection to create a session for. - /// The new session - protected virtual ISession CreateSession(IConnection con) - { - return con.CreateSession(sessionTransacted, SessionAcknowledgeMode); - } - - /// - /// Returns whether the Session is in client acknowledgement mode. - /// - /// The session to check. - /// true if in client ack mode, false otherwise - protected virtual bool IsClientAcknowledge(ISession session) - { - return (session.AcknowledgeMode == Session.CLIENT_ACKNOWLEDGE); + this.connectionFactory = value; } } + + /// + /// Gets or sets the session acknowledge mode for EMS Sessions including whether or not the session is transacted + /// + /// + /// Set the EMS acknowledgement mode that is used when creating a EMS + /// Session to send a message. The default is AUTO_ACKNOWLEDGE. + /// + /// The session acknowledge mode. + virtual public int SessionAcknowledgeMode + { + get + { + return sessionAcknowledgeMode; + } + + set + { + this.sessionAcknowledgeMode = value; + } + } + + /// + /// Set the transaction mode that is used when creating a EMS Session. + /// Default is "false". + /// + /// + /// Setting this flag to "true" will use a short local EMS transaction + /// when running outside of a managed transaction, and a synchronized local + /// EMS transaction in case of a managed transaction being present. + /// The latter has the effect of a local EMS + /// transaction being managed alongside the main transaction (which might + /// be a native ADO.NET transaction), with the EMS transaction committing + /// right after the main transaction. + /// + /// + public bool SessionTransacted + { + get + { + return sessionTransacted; + } + set + { + if (value) + { + sessionTransacted = value; + } + } + } + + #endregion + + /// + /// Verify that ConnectionFactory property has been set. + /// + public virtual void AfterPropertiesSet() + { + if (ConnectionFactory == null) + { + throw new ArgumentException("ConnectionFactory is required"); + } + } + + /// + /// Creates the connection via the ConnectionFactory. + /// + /// + protected virtual IConnection CreateConnection() + { + return ConnectionFactory.CreateConnection(); + } + + /// + /// Creates the session for the given Connection + /// + /// The connection to create a session for. + /// The new session + protected virtual ISession CreateSession(IConnection con) + { + return con.CreateSession(sessionTransacted, SessionAcknowledgeMode); + } + + /// + /// Returns whether the Session is in client acknowledgement mode. + /// + /// The session to check. + /// true if in client ack mode, false otherwise + protected virtual bool IsClientAcknowledge(ISession session) + { + return (session.AcknowledgeMode == Session.CLIENT_ACKNOWLEDGE); + } } diff --git a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Support/EmsUtils.cs b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Support/EmsUtils.cs index 1d8a80b8..c6a53ecf 100644 --- a/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Support/EmsUtils.cs +++ b/src/Spring/Spring.Messaging.Ems/Messaging/Ems/Support/EmsUtils.cs @@ -22,145 +22,145 @@ using Microsoft.Extensions.Logging; using Spring.Messaging.Ems.Common; using Spring.Util; -namespace Spring.Messaging.Ems.Support +namespace Spring.Messaging.Ems.Support; + +/// +/// Generic utility methods for working with EMS. Mainly for internal use +/// within the framework, but also useful for custom EMS access code. +/// +public abstract class EmsUtils { - /// - /// Generic utility methods for working with EMS. Mainly for internal use - /// within the framework, but also useful for custom EMS access code. + #region Logging + + private static readonly ILogger logger = LogManager.GetLogger(); + + #endregion + + /// Close the given EMS Connection and ignore any thrown exception. + /// This is useful for typical finally blocks in manual EMS code. /// - public abstract class EmsUtils + /// the EMS Connection to close (may be null) + /// + public static void CloseConnection(IConnection con) { - #region Logging + CloseConnection(con, false); + } - private static readonly ILogger logger = LogManager.GetLogger(); - - #endregion - - /// Close the given EMS Connection and ignore any thrown exception. - /// This is useful for typical finally blocks in manual EMS code. - /// - /// the EMS Connection to close (may be null) - /// - public static void CloseConnection(IConnection con) + /// Close the given EMS Connection and ignore any thrown exception. + /// This is useful for typical finally blocks in manual EMS code. + /// + /// the EMS Connection to close (may be null) + /// + /// whether to call stop() before closing + /// + public static void CloseConnection(IConnection con, bool stop) + { + if (con != null) { - CloseConnection(con, false); - } - - /// Close the given EMS Connection and ignore any thrown exception. - /// This is useful for typical finally blocks in manual EMS code. - /// - /// the EMS Connection to close (may be null) - /// - /// whether to call stop() before closing - /// - public static void CloseConnection(IConnection con, bool stop) - { - if (con != null) + try { - try + if (stop) { - if (stop) + try { - try - { - con.Stop(); - } - finally - { - con.Close(); - } + con.Stop(); } - else + finally { con.Close(); } } - catch (EMSException ex) + else { - logger.LogDebug((Exception) ex, "Could not close EMS Connection"); - } - catch (Exception ex) - { - // We don't trust the EMS provider: It might throw another exception. - logger.LogDebug(ex, "Unexpected exception on closing EMS Connection"); + con.Close(); } } - } - - /// Close the given EMS Session and ignore any thrown exception. - /// This is useful for typical finally blocks in manual EMS code. - /// - /// the EMS Session to close (may be null) - /// - public static void CloseSession(ISession session) - { - if (session != null) + catch (EMSException ex) { - try - { - session.Close(); - } - catch (EMSException ex) - { - logger.LogDebug((Exception) ex, "Could not close EMS Session"); - } - catch (Exception ex) - { - // We don't trust the EMS provider: It might throw RuntimeException or Error. - logger.LogDebug(ex, "Unexpected exception on closing EMS Session"); - } + logger.LogDebug((Exception) ex, "Could not close EMS Connection"); } - } - - /// Close the given EMS MessageProducer and ignore any thrown exception. - /// This is useful for typical finally blocks in manual EMS code. - /// - /// the EMS MessageProducer to close (may be null) - /// - public static void CloseMessageProducer(IMessageProducer producer) - { - if (producer != null) + catch (Exception ex) { - try - { - producer.Close(); - } - catch (EMSException ex) - { - logger.LogDebug((Exception) ex, "Could not close EMS MessageProducer"); - } - catch (Exception ex) - { - // We don't trust the provider: It might throw an exception . - logger.LogDebug(ex, "Unexpected exception on closing EMS MessageProducer"); - } + // We don't trust the EMS provider: It might throw another exception. + logger.LogDebug(ex, "Unexpected exception on closing EMS Connection"); } } + } - /// Close the given EMS MessageConsumer and ignore any thrown exception. - /// This is useful for typical finally blocks in manual EMS code. - /// - /// the EMS MessageConsumer to close (may be null) - /// - public static void CloseMessageConsumer(IMessageConsumer consumer) + /// Close the given EMS Session and ignore any thrown exception. + /// This is useful for typical finally blocks in manual EMS code. + /// + /// the EMS Session to close (may be null) + /// + public static void CloseSession(ISession session) + { + if (session != null) { - if (consumer != null) + try { - try - { - consumer.Close(); - } - catch (EMSException ex) - { - logger.LogDebug((Exception) ex, "Could not close EMS MessageConsumer"); - } - catch (Exception ex) - { - // We don't trust the EMS provider: It might throw RuntimeException or Error. - logger.LogDebug(ex, "Unexpected exception on closing EMS MessageConsumer"); - } + session.Close(); + } + catch (EMSException ex) + { + logger.LogDebug((Exception) ex, "Could not close EMS Session"); + } + catch (Exception ex) + { + // We don't trust the EMS provider: It might throw RuntimeException or Error. + logger.LogDebug(ex, "Unexpected exception on closing EMS Session"); } } + } + + /// Close the given EMS MessageProducer and ignore any thrown exception. + /// This is useful for typical finally blocks in manual EMS code. + /// + /// the EMS MessageProducer to close (may be null) + /// + public static void CloseMessageProducer(IMessageProducer producer) + { + if (producer != null) + { + try + { + producer.Close(); + } + catch (EMSException ex) + { + logger.LogDebug((Exception) ex, "Could not close EMS MessageProducer"); + } + catch (Exception ex) + { + // We don't trust the provider: It might throw an exception . + logger.LogDebug(ex, "Unexpected exception on closing EMS MessageProducer"); + } + } + } + + /// Close the given EMS MessageConsumer and ignore any thrown exception. + /// This is useful for typical finally blocks in manual EMS code. + /// + /// the EMS MessageConsumer to close (may be null) + /// + public static void CloseMessageConsumer(IMessageConsumer consumer) + { + if (consumer != null) + { + try + { + consumer.Close(); + } + catch (EMSException ex) + { + logger.LogDebug((Exception) ex, "Could not close EMS MessageConsumer"); + } + catch (Exception ex) + { + // We don't trust the EMS provider: It might throw RuntimeException or Error. + logger.LogDebug(ex, "Unexpected exception on closing EMS MessageConsumer"); + } + } + } /* /// Close the given EMS QueueRequestor and ignore any thrown exception. /// This is useful for typical finally blocks in manual EMS code. @@ -188,19 +188,18 @@ namespace Spring.Messaging.Ems.Support // } // } + /// Commit the Session if not within a distributed transaction. + /// Needs investigation - no distributed tx in .NET messaging providers + /// the EMS Session to commit + /// + /// EMSException if committing failed + public static void CommitIfNecessary(ISession session) + { + AssertUtils.ArgumentNotNull(session, "Session must not be null"); - /// Commit the Session if not within a distributed transaction. - /// Needs investigation - no distributed tx in .NET messaging providers - /// the EMS Session to commit - /// - /// EMSException if committing failed - public static void CommitIfNecessary(ISession session) - { - AssertUtils.ArgumentNotNull(session, "Session must not be null"); + session.Commit(); - session.Commit(); - - // TODO Investigate + // TODO Investigate // try { // session.Commit(); @@ -213,19 +212,19 @@ namespace Spring.Messaging.Ems.Support // // TODO Investigate // // Ignore -> can only happen in case of a JTA transaction. // } - } + } - /// Rollback the Session if not within a distributed transaction. - /// Needs investigation - no distributed tx in EMS - /// the EMS Session to rollback - /// - /// EMSException if committing failed - public static void RollbackIfNecessary(ISession session) - { - AssertUtils.ArgumentNotNull(session, "Session must not be null"); - session.Rollback(); + /// Rollback the Session if not within a distributed transaction. + /// Needs investigation - no distributed tx in EMS + /// the EMS Session to rollback + /// + /// EMSException if committing failed + public static void RollbackIfNecessary(ISession session) + { + AssertUtils.ArgumentNotNull(session, "Session must not be null"); + session.Rollback(); - // TODO Investigate + // TODO Investigate // try { // session.Rollback(); @@ -236,58 +235,59 @@ namespace Spring.Messaging.Ems.Support // catch (IllegalStateException ex) { // // Ignore -> can only happen in case of a JTA transaction. // } - } + } - /// - /// Closes the given queue browser and ignore any thrown exception. - /// This is useful for typical finally blocks in manual EMS code. - /// - /// The queue browser to close (may be null. - public static void CloseQueueBrowser(QueueBrowser browser) + /// + /// Closes the given queue browser and ignore any thrown exception. + /// This is useful for typical finally blocks in manual EMS code. + /// + /// The queue browser to close (may be null. + public static void CloseQueueBrowser(QueueBrowser browser) + { + if (browser != null) { - if (browser != null) + try { - try - { - browser.Close(); - } catch (EMSException ex) - { - logger.LogDebug((Exception) ex, "Could not close EMS QueueBrowser"); - } catch (Exception ex) - { - logger.LogDebug(ex, "Unexpected exception on closing EMS QueueBrowser"); - } + browser.Close(); } - } - - /// - /// Converts the acknowledgement mode from an integer to an enumeration. If the integer - /// does not match a valid enumeration, the returned enumeration is SessionMode.AutoAcknowledge - /// - /// The ack mode. - /// The corresponding SessionMode enumeration - public static SessionMode ConvertAcknowledgementMode(int ackMode) - { - switch (ackMode) + catch (EMSException ex) { - case Session.AUTO_ACKNOWLEDGE: - return SessionMode.AutoAcknowledge; - case Session.CLIENT_ACKNOWLEDGE: - return SessionMode.ClientAcknowledge; - case Session.DUPS_OK_ACKNOWLEDGE: - return SessionMode.DupsOkAcknowledge; - case Session.EXPLICIT_CLIENT_ACKNOWLEDGE: - return SessionMode.ExplicitClientAcknowledge; - case Session.EXPLICIT_CLIENT_DUPS_OK_ACKNOWLEDGE: - return SessionMode.ExplicitClientDupsOkAcknowledge; - case Session.NO_ACKNOWLEDGE: - return SessionMode.NoAcknowledge; - case Session.SESSION_TRANSACTED: - return SessionMode.SessionTransacted; - default: - logger.LogWarning("Integer acknowledgement mode [" + ackMode + "] not valid. Defaulting to SessionMode.AutoAcknowledge"); - return SessionMode.AutoAcknowledge; + logger.LogDebug((Exception) ex, "Could not close EMS QueueBrowser"); + } + catch (Exception ex) + { + logger.LogDebug(ex, "Unexpected exception on closing EMS QueueBrowser"); } } } + + /// + /// Converts the acknowledgement mode from an integer to an enumeration. If the integer + /// does not match a valid enumeration, the returned enumeration is SessionMode.AutoAcknowledge + /// + /// The ack mode. + /// The corresponding SessionMode enumeration + public static SessionMode ConvertAcknowledgementMode(int ackMode) + { + switch (ackMode) + { + case Session.AUTO_ACKNOWLEDGE: + return SessionMode.AutoAcknowledge; + case Session.CLIENT_ACKNOWLEDGE: + return SessionMode.ClientAcknowledge; + case Session.DUPS_OK_ACKNOWLEDGE: + return SessionMode.DupsOkAcknowledge; + case Session.EXPLICIT_CLIENT_ACKNOWLEDGE: + return SessionMode.ExplicitClientAcknowledge; + case Session.EXPLICIT_CLIENT_DUPS_OK_ACKNOWLEDGE: + return SessionMode.ExplicitClientDupsOkAcknowledge; + case Session.NO_ACKNOWLEDGE: + return SessionMode.NoAcknowledge; + case Session.SESSION_TRANSACTED: + return SessionMode.SessionTransacted; + default: + logger.LogWarning("Integer acknowledgement mode [" + ackMode + "] not valid. Defaulting to SessionMode.AutoAcknowledge"); + return SessionMode.AutoAcknowledge; + } + } } diff --git a/src/Spring/Spring.Messaging.Nms/AssemblyInfo.cs b/src/Spring/Spring.Messaging.Nms/AssemblyInfo.cs index 0fb18931..6f4ecad1 100644 --- a/src/Spring/Spring.Messaging.Nms/AssemblyInfo.cs +++ b/src/Spring/Spring.Messaging.Nms/AssemblyInfo.cs @@ -1,4 +1,4 @@ using System.Reflection; [assembly: AssemblyTitle("Spring.Messaging.Nms")] -[assembly: AssemblyDescription("ActiveMQ support")] \ No newline at end of file +[assembly: AssemblyDescription("ActiveMQ support")] diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Config/MessageListenerContainerObjectDefinitionParser.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Config/MessageListenerContainerObjectDefinitionParser.cs index 57df1dac..3e7ace5e 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Config/MessageListenerContainerObjectDefinitionParser.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Config/MessageListenerContainerObjectDefinitionParser.cs @@ -28,426 +28,432 @@ using Spring.Objects.Factory.Support; using Spring.Objects.Factory.Xml; using Spring.Util; -namespace Spring.Messaging.Nms.Config +namespace Spring.Messaging.Nms.Config; + +/// +/// Parser for the NMS <listener-container> element. +/// +/// Mark Fisher +/// Juergen Hoeller +/// Mark Pollack (.NET) +public class MessageListenerContainerObjectDefinitionParser : IObjectDefinitionParser { + #region Fields + + private readonly string LISTENER_ELEMENT = "listener"; + + private readonly string ID_ATTRIBUTE = "id"; + + private readonly string DESTINATION_ATTRIBUTE = "destination"; + + private readonly string SUBSCRIPTION_ATTRIBUTE = "subscription"; + + private readonly string SELECTOR_ATTRIBUTE = "selector"; + + private readonly string REF_ATTRIBUTE = "ref"; + + private readonly string METHOD_ATTRIBUTE = "method"; + + private readonly string DESTINATION_RESOLVER_ATTRIBUTE = "destination-resolver"; + + private readonly string MESSAGE_CONVERTER_ATTRIBUTE = "message-converter"; + + private readonly string RESPONSE_DESTINATION_ATTRIBUTE = "response-destination"; + + private readonly string DESTINATION_TYPE_ATTRIBUTE = "destination-type"; + + private readonly string DESTINATION_TYPE_QUEUE = "queue"; + + private readonly string DESTINATION_TYPE_TOPIC = "topic"; + + private readonly string DESTINATION_TYPE_DURABLE_TOPIC = "durableTopic"; + + private readonly string CLIENT_ID_ATTRIBUTE = "client-id"; + + private readonly string ACKNOWLEDGE_ATTRIBUTE = "acknowledge"; + + private readonly string ACKNOWLEDGE_AUTO = "auto"; + + private readonly string ACKNOWLEDGE_CLIENT = "client"; + + private readonly string ACKNOWLEDGE_DUPS_OK = "dups-ok"; + + private readonly string ACKNOWLEDGE_TRANSACTED = "transacted"; + + private readonly string CONCURRENCY_ATTRIBUTE = "concurrency"; + + private readonly string RECOVERY_INTERVAL_ATTRIBUTE = "recovery-interval"; + + private readonly string MAX_RECOVERY_TIME_ATTRIBUTE = "max-recovery-time"; + + private readonly string CONNECTION_FACTORY_ATTRIBUTE = "connection-factory"; + + private readonly string CONTAINER_CUSTOM_TYPE = "container-custom-type"; + + private readonly string PUBSUB_DOMAIN_ATTRIBUTE = "pubsub-domain"; + + private readonly string AUTO_STARTUP = "auto-startup"; + + private readonly string ERROR_HANDLER_ATTRIBUTE = "error-handler"; + + private readonly string EXCEPTION_LISTENER_ATTRIBUTE = "exception-listener"; + + #endregion + + #region IObjectDefinitionParser Members + /// - /// Parser for the NMS <listener-container> element. + /// Parse the specified XmlElement and register the resulting + /// ObjectDefinitions with the IObjectDefinitionRegistry + /// embedded in the supplied /// - /// Mark Fisher - /// Juergen Hoeller - /// Mark Pollack (.NET) - public class MessageListenerContainerObjectDefinitionParser : IObjectDefinitionParser + /// The element to be parsed. + /// The object encapsulating the current state of the parsing process. + /// Provides access to a IObjectDefinitionRegistry + /// The primary object definition. + /// + ///

+ /// This method is never invoked if the parser is namespace aware + /// and was called to process the root node. + ///

+ ///
+ public IObjectDefinition ParseElement(XmlElement element, ParserContext parserContext) { - #region Fields - - private readonly string LISTENER_ELEMENT = "listener"; - - private readonly string ID_ATTRIBUTE = "id"; - - private readonly string DESTINATION_ATTRIBUTE = "destination"; - - private readonly string SUBSCRIPTION_ATTRIBUTE = "subscription"; - - private readonly string SELECTOR_ATTRIBUTE = "selector"; - - private readonly string REF_ATTRIBUTE = "ref"; - - private readonly string METHOD_ATTRIBUTE = "method"; - - private readonly string DESTINATION_RESOLVER_ATTRIBUTE = "destination-resolver"; - - private readonly string MESSAGE_CONVERTER_ATTRIBUTE = "message-converter"; - - private readonly string RESPONSE_DESTINATION_ATTRIBUTE = "response-destination"; - - private readonly string DESTINATION_TYPE_ATTRIBUTE = "destination-type"; - - private readonly string DESTINATION_TYPE_QUEUE = "queue"; - - private readonly string DESTINATION_TYPE_TOPIC = "topic"; - - private readonly string DESTINATION_TYPE_DURABLE_TOPIC = "durableTopic"; - - private readonly string CLIENT_ID_ATTRIBUTE = "client-id"; - - private readonly string ACKNOWLEDGE_ATTRIBUTE = "acknowledge"; - - private readonly string ACKNOWLEDGE_AUTO = "auto"; - - private readonly string ACKNOWLEDGE_CLIENT = "client"; - - private readonly string ACKNOWLEDGE_DUPS_OK = "dups-ok"; - - private readonly string ACKNOWLEDGE_TRANSACTED = "transacted"; - - private readonly string CONCURRENCY_ATTRIBUTE = "concurrency"; - - private readonly string RECOVERY_INTERVAL_ATTRIBUTE = "recovery-interval"; - - private readonly string MAX_RECOVERY_TIME_ATTRIBUTE = "max-recovery-time"; - - private readonly string CONNECTION_FACTORY_ATTRIBUTE = "connection-factory"; - - private readonly string CONTAINER_CUSTOM_TYPE = "container-custom-type"; - - private readonly string PUBSUB_DOMAIN_ATTRIBUTE = "pubsub-domain"; - - private readonly string AUTO_STARTUP = "auto-startup"; - - private readonly string ERROR_HANDLER_ATTRIBUTE = "error-handler"; - - private readonly string EXCEPTION_LISTENER_ATTRIBUTE = "exception-listener"; - - #endregion - - #region IObjectDefinitionParser Members - - /// - /// Parse the specified XmlElement and register the resulting - /// ObjectDefinitions with the IObjectDefinitionRegistry - /// embedded in the supplied - /// - /// The element to be parsed. - /// The object encapsulating the current state of the parsing process. - /// Provides access to a IObjectDefinitionRegistry - /// The primary object definition. - /// - ///

- /// This method is never invoked if the parser is namespace aware - /// and was called to process the root node. - ///

- ///
- public IObjectDefinition ParseElement(XmlElement element, ParserContext parserContext) + XmlNodeList childNodes = element.ChildNodes; + foreach (XmlNode childNode in childNodes) { - - XmlNodeList childNodes = element.ChildNodes; - foreach (XmlNode childNode in childNodes) + if (childNode.NodeType == XmlNodeType.Element) { - if (childNode.NodeType == XmlNodeType.Element) + string localName = childNode.LocalName; + if (LISTENER_ELEMENT.Equals(localName)) { - string localName = childNode.LocalName; - if (LISTENER_ELEMENT.Equals(localName)) - { - ParseListener((XmlElement) childNode, element, parserContext); - } + ParseListener((XmlElement) childNode, element, parserContext); } } - return null; } - #endregion + return null; + } - private void ParseListener(XmlElement listenerElement, XmlElement containerElement, ParserContext parserContext) + #endregion + + private void ParseListener(XmlElement listenerElement, XmlElement containerElement, ParserContext parserContext) + { + ObjectDefinitionBuilder listenerDefBuilder = + parserContext.ParserHelper.CreateRootObjectDefinitionBuilder(typeof(MessageListenerAdapter)); + + string reference = listenerElement.GetAttribute(REF_ATTRIBUTE); + if (!StringUtils.HasText(reference)) { - ObjectDefinitionBuilder listenerDefBuilder = - parserContext.ParserHelper.CreateRootObjectDefinitionBuilder(typeof (MessageListenerAdapter)); - - string reference = listenerElement.GetAttribute(REF_ATTRIBUTE); - if (!StringUtils.HasText(reference)) - { - parserContext.ReaderContext.ReportException(listenerElement, LISTENER_ELEMENT, - "Listener '" + REF_ATTRIBUTE + - "' attribute contains empty value."); - } - listenerDefBuilder.AddPropertyValue("HandlerObject", new RuntimeObjectReference(reference)); - - string handlerMethod = null; - if (listenerElement.HasAttribute(METHOD_ATTRIBUTE)) - { - handlerMethod = listenerElement.GetAttribute(METHOD_ATTRIBUTE); - { - if (!StringUtils.HasText(handlerMethod)) - { - parserContext.ReaderContext.ReportException(listenerElement, LISTENER_ELEMENT, - "Listener '" + METHOD_ATTRIBUTE + - "' attribute contains empty value."); - } - } - } - listenerDefBuilder.AddPropertyValue("DefaultHandlerMethod", handlerMethod); - - if (containerElement.HasAttribute(MESSAGE_CONVERTER_ATTRIBUTE)) - { - string messageConverter = containerElement.GetAttribute(MESSAGE_CONVERTER_ATTRIBUTE); - listenerDefBuilder.AddPropertyValue("MessageConverter", new RuntimeObjectReference(messageConverter)); - } - - ObjectDefinitionBuilder containerDefBuilder = ParseContainer(listenerElement, containerElement, parserContext); - - if (listenerElement.HasAttribute(RESPONSE_DESTINATION_ATTRIBUTE)) - { - string responseDestination = listenerElement.GetAttribute(RESPONSE_DESTINATION_ATTRIBUTE); - bool pubSubDomain = IndicatesPubSub(containerDefBuilder.RawObjectDefinition); - listenerDefBuilder.AddPropertyValue(pubSubDomain ? "DefaultResponseTopicName" : "DefaultResponseQueueName", - responseDestination); - if (containerDefBuilder.RawObjectDefinition.PropertyValues.Contains("DestinationResolver")) - { - listenerDefBuilder.AddPropertyValue("DestinationResolver", - containerDefBuilder.RawObjectDefinition.PropertyValues.GetPropertyValue - ( - "DestinationResolver").Value); - } - } - - containerDefBuilder.AddPropertyValue("MessageListener", listenerDefBuilder.ObjectDefinition); - - string containerObjectName = listenerElement.GetAttribute(ID_ATTRIBUTE); - // If no object id is given auto generate one using the ReaderContext's ObjectNameGenerator - if (!StringUtils.HasText(containerObjectName)) - { - containerObjectName = - parserContext.ReaderContext.GenerateObjectName(containerDefBuilder.RawObjectDefinition); - } - - string pubsubDomain = listenerElement.GetAttribute(PUBSUB_DOMAIN_ATTRIBUTE); - containerDefBuilder.AddPropertyValue("PubSubDomain", pubsubDomain); - - - parserContext.Registry.RegisterObjectDefinition(containerObjectName, containerDefBuilder.ObjectDefinition); + parserContext.ReaderContext.ReportException(listenerElement, LISTENER_ELEMENT, + "Listener '" + REF_ATTRIBUTE + + "' attribute contains empty value."); } - private ObjectDefinitionBuilder ParseContainer(XmlElement listenerElement, XmlElement containerElement, - ParserContext parserContext) + listenerDefBuilder.AddPropertyValue("HandlerObject", new RuntimeObjectReference(reference)); + + string handlerMethod = null; + if (listenerElement.HasAttribute(METHOD_ATTRIBUTE)) { - //Only support SimpleMessageListenerContainer or container-custom-type - - Type containerType = typeof (SimpleMessageListenerContainer); - if (containerElement.HasAttribute(CONTAINER_CUSTOM_TYPE)) + handlerMethod = listenerElement.GetAttribute(METHOD_ATTRIBUTE); { - string customType = containerElement.GetAttribute(CONTAINER_CUSTOM_TYPE); - if (!StringUtils.HasLength(customType)) - { - parserContext.ReaderContext.ReportException(containerElement, CONTAINER_CUSTOM_TYPE, - "Listener container '" + CONTAINER_CUSTOM_TYPE + - "' attribute contains empty value."); - } - try - { - containerType = TypeResolutionUtils.ResolveType(customType); - } catch (Exception ex) - { - parserContext.ReaderContext.ReportException(containerElement, CONTAINER_CUSTOM_TYPE, - "Invalid container-custom-type value [" + customType + "]", ex); - } - } - - ObjectDefinitionBuilder containerDef = - parserContext.ParserHelper.CreateRootObjectDefinitionBuilder(containerType); - - ParseListenerConfiguration(listenerElement, parserContext, containerDef); - ParseContainerConfiguration(containerElement, parserContext, containerDef); - - - if (containerElement.HasAttribute(AUTO_STARTUP)) - { - string autoStartup = containerElement.GetAttribute(AUTO_STARTUP); - if (StringUtils.HasText(autoStartup)) - { - containerDef.AddPropertyValue("AutoStartup", autoStartup); - } - } - - string connectionFactoryObjectName = "connectionFactory"; - if (containerElement.HasAttribute(CONNECTION_FACTORY_ATTRIBUTE)) - { - connectionFactoryObjectName = containerElement.GetAttribute(CONNECTION_FACTORY_ATTRIBUTE); - if (!StringUtils.HasText(connectionFactoryObjectName)) + if (!StringUtils.HasText(handlerMethod)) { parserContext.ReaderContext.ReportException(listenerElement, LISTENER_ELEMENT, - "Listener container '" + CONNECTION_FACTORY_ATTRIBUTE + - "' attribute contains empty value."); + "Listener '" + METHOD_ATTRIBUTE + + "' attribute contains empty value."); } - - } - - containerDef.AddPropertyValue("ConnectionFactory", new RuntimeObjectReference(connectionFactoryObjectName)); - - - string errorHandlerObjectName = containerElement.GetAttribute(ERROR_HANDLER_ATTRIBUTE); - if (StringUtils.HasText(errorHandlerObjectName)) - { - containerDef.AddPropertyValue("ErrorHandler", - new RuntimeObjectReference(errorHandlerObjectName)); - } - - string exceptionListenerObjectName = containerElement.GetAttribute(EXCEPTION_LISTENER_ATTRIBUTE); - if (StringUtils.HasText(exceptionListenerObjectName)) - { - containerDef.AddPropertyValue("ExceptionListener", - new RuntimeObjectReference(exceptionListenerObjectName)); - } - - string destinationResolverObjectName = containerElement.GetAttribute(DESTINATION_RESOLVER_ATTRIBUTE); - if (StringUtils.HasText(destinationResolverObjectName)) - { - containerDef.AddPropertyValue("DestinationResolver", - new RuntimeObjectReference(destinationResolverObjectName)); - } - - string acknowledge = containerElement.GetAttribute(ACKNOWLEDGE_ATTRIBUTE); - if (StringUtils.HasText(acknowledge)) - { - AcknowledgementMode acknowledgementMode = ParseAcknowledgementMode(containerElement, parserContext); - containerDef.AddPropertyValue("SessionAcknowledgeMode", acknowledgementMode); - } - - string concurrency = ParseConcurrency(containerElement, parserContext); - if (concurrency != null) - { - containerDef.AddPropertyValue("ConcurrentConsumers", concurrency); - } - containerDef.AddPropertyValue("RecoveryInterval", ParseRecoveryInterval(containerElement, parserContext)); - - containerDef.AddPropertyValue("MaxRecoveryTime", ParseMaxRecoveryTime(containerElement, parserContext)); - - return containerDef; - } - - private bool IndicatesPubSub(AbstractObjectDefinition configDef) - { - return (bool) configDef.PropertyValues.GetPropertyValue("PubSubDomain").Value; - } - - private void ParseListenerConfiguration(XmlElement ele, ParserContext parserContext, - ObjectDefinitionBuilder containerDef) - { - string destination = ele.GetAttribute(DESTINATION_ATTRIBUTE); - if (!StringUtils.HasText(destination)) - { - parserContext.ReaderContext.ReportException(ele, LISTENER_ELEMENT, - "Listener '" + DESTINATION_ATTRIBUTE + - "' attribute contains empty value."); - } - containerDef.AddPropertyValue("DestinationName", destination); - - if (ele.HasAttribute(SUBSCRIPTION_ATTRIBUTE)) - { - string subscription = ele.GetAttribute(SUBSCRIPTION_ATTRIBUTE); - if (!StringUtils.HasText(subscription)) - { - parserContext.ReaderContext.ReportException(ele, SUBSCRIPTION_ATTRIBUTE, - "Listener '" + SUBSCRIPTION_ATTRIBUTE + - "' attribute contains empty value."); - } - containerDef.AddPropertyValue("DurableSubscriptionName", subscription); - } - - if (ele.HasAttribute(SELECTOR_ATTRIBUTE)) - { - string selector = ele.GetAttribute(SELECTOR_ATTRIBUTE); - if (!StringUtils.HasText(selector)) - { - parserContext.ReaderContext.ReportException(ele, selector, - "Listener '" + SELECTOR_ATTRIBUTE + - "' attribute contains empty value."); - } - containerDef.AddPropertyValue("MessageSelector", selector); } } - private void ParseContainerConfiguration(XmlElement ele, ParserContext parserContext, - ObjectDefinitionBuilder containerDef) + listenerDefBuilder.AddPropertyValue("DefaultHandlerMethod", handlerMethod); + + if (containerElement.HasAttribute(MESSAGE_CONVERTER_ATTRIBUTE)) { - string destinationType = ele.GetAttribute(DESTINATION_TYPE_ATTRIBUTE); - bool pubSubDomain = false; - bool subscriptionDurable = false; - if (DESTINATION_TYPE_DURABLE_TOPIC.Equals(destinationType)) - { - pubSubDomain = true; - subscriptionDurable = true; - } - else if (DESTINATION_TYPE_TOPIC.Equals(destinationType)) - { - pubSubDomain = true; - } - else if ("".Equals(destinationType) || DESTINATION_TYPE_QUEUE.Equals(destinationType)) - { - // the default: queue - } - else - { - parserContext.ReaderContext.ReportException(ele, destinationType, - "Invalid listener container '" + DESTINATION_TYPE_ATTRIBUTE + - "': only 'queue', 'topic' and 'durableTopic' supported"); - } + string messageConverter = containerElement.GetAttribute(MESSAGE_CONVERTER_ATTRIBUTE); + listenerDefBuilder.AddPropertyValue("MessageConverter", new RuntimeObjectReference(messageConverter)); + } - containerDef.AddPropertyValue("PubSubDomain", pubSubDomain); - containerDef.AddPropertyValue("SubscriptionDurable", subscriptionDurable); + ObjectDefinitionBuilder containerDefBuilder = ParseContainer(listenerElement, containerElement, parserContext); - if (ele.HasAttribute(CLIENT_ID_ATTRIBUTE)) + if (listenerElement.HasAttribute(RESPONSE_DESTINATION_ATTRIBUTE)) + { + string responseDestination = listenerElement.GetAttribute(RESPONSE_DESTINATION_ATTRIBUTE); + bool pubSubDomain = IndicatesPubSub(containerDefBuilder.RawObjectDefinition); + listenerDefBuilder.AddPropertyValue(pubSubDomain ? "DefaultResponseTopicName" : "DefaultResponseQueueName", + responseDestination); + if (containerDefBuilder.RawObjectDefinition.PropertyValues.Contains("DestinationResolver")) { - string clientId = ele.GetAttribute(CLIENT_ID_ATTRIBUTE); - if (!StringUtils.HasText(clientId)) - { - parserContext.ReaderContext.ReportException(ele, clientId, - "Listener '" + CLIENT_ID_ATTRIBUTE + - "' attribute contains empty value."); - } - containerDef.AddPropertyValue("ClientId", clientId); + listenerDefBuilder.AddPropertyValue("DestinationResolver", + containerDefBuilder.RawObjectDefinition.PropertyValues.GetPropertyValue + ( + "DestinationResolver").Value); } } - private AcknowledgementMode ParseAcknowledgementMode(XmlElement element, ParserContext parserContext) + containerDefBuilder.AddPropertyValue("MessageListener", listenerDefBuilder.ObjectDefinition); + + string containerObjectName = listenerElement.GetAttribute(ID_ATTRIBUTE); + // If no object id is given auto generate one using the ReaderContext's ObjectNameGenerator + if (!StringUtils.HasText(containerObjectName)) { - string acknowledge = element.GetAttribute(ACKNOWLEDGE_ATTRIBUTE); - if (acknowledge.Equals(ACKNOWLEDGE_TRANSACTED)) - { - return AcknowledgementMode.Transactional; - } - else if (acknowledge.Equals(ACKNOWLEDGE_DUPS_OK)) - { - return AcknowledgementMode.DupsOkAcknowledge; - } - else if (acknowledge.Equals(ACKNOWLEDGE_CLIENT)) - { - return AcknowledgementMode.ClientAcknowledge; - } - else if (!acknowledge.Equals(ACKNOWLEDGE_AUTO)) - { - parserContext.ReaderContext.ReportException(element, ACKNOWLEDGE_ATTRIBUTE, - "Invalid listener container 'acknowledge' setting ['" + - acknowledge + - "]: only \"auto\", \"client\", \"dups-ok\" and \"transacted\" supported."); - } - return AcknowledgementMode.AutoAcknowledge; + containerObjectName = + parserContext.ReaderContext.GenerateObjectName(containerDefBuilder.RawObjectDefinition); } - private string ParseConcurrency(XmlElement ele, ParserContext parserContext) + string pubsubDomain = listenerElement.GetAttribute(PUBSUB_DOMAIN_ATTRIBUTE); + containerDefBuilder.AddPropertyValue("PubSubDomain", pubsubDomain); + + parserContext.Registry.RegisterObjectDefinition(containerObjectName, containerDefBuilder.ObjectDefinition); + } + + private ObjectDefinitionBuilder ParseContainer(XmlElement listenerElement, XmlElement containerElement, + ParserContext parserContext) + { + //Only support SimpleMessageListenerContainer or container-custom-type + + Type containerType = typeof(SimpleMessageListenerContainer); + if (containerElement.HasAttribute(CONTAINER_CUSTOM_TYPE)) { - string concurrency = ele.GetAttribute(CONCURRENCY_ATTRIBUTE); - if (!StringUtils.HasText(concurrency)) + string customType = containerElement.GetAttribute(CONTAINER_CUSTOM_TYPE); + if (!StringUtils.HasLength(customType)) { - return null; - } else + parserContext.ReaderContext.ReportException(containerElement, CONTAINER_CUSTOM_TYPE, + "Listener container '" + CONTAINER_CUSTOM_TYPE + + "' attribute contains empty value."); + } + + try { - return concurrency; + containerType = TypeResolutionUtils.ResolveType(customType); + } + catch (Exception ex) + { + parserContext.ReaderContext.ReportException(containerElement, CONTAINER_CUSTOM_TYPE, + "Invalid container-custom-type value [" + customType + "]", ex); } } - private string ParseRecoveryInterval(XmlElement ele, ParserContext parserContext) - { - string recoveryInterval = ele.GetAttribute(RECOVERY_INTERVAL_ATTRIBUTE); - if (StringUtils.HasText(recoveryInterval)) - { - return recoveryInterval; + ObjectDefinitionBuilder containerDef = + parserContext.ParserHelper.CreateRootObjectDefinitionBuilder(containerType); - } else + ParseListenerConfiguration(listenerElement, parserContext, containerDef); + ParseContainerConfiguration(containerElement, parserContext, containerDef); + + if (containerElement.HasAttribute(AUTO_STARTUP)) + { + string autoStartup = containerElement.GetAttribute(AUTO_STARTUP); + if (StringUtils.HasText(autoStartup)) { - return SimpleMessageListenerContainer.DEFAULT_RECOVERY_INTERVAL; + containerDef.AddPropertyValue("AutoStartup", autoStartup); } } - private string ParseMaxRecoveryTime(XmlElement ele, ParserContext parserContext) + string connectionFactoryObjectName = "connectionFactory"; + if (containerElement.HasAttribute(CONNECTION_FACTORY_ATTRIBUTE)) { - string recoverTime = ele.GetAttribute(MAX_RECOVERY_TIME_ATTRIBUTE); - if (StringUtils.HasText(recoverTime)) + connectionFactoryObjectName = containerElement.GetAttribute(CONNECTION_FACTORY_ATTRIBUTE); + if (!StringUtils.HasText(connectionFactoryObjectName)) { - return recoverTime; + parserContext.ReaderContext.ReportException(listenerElement, LISTENER_ELEMENT, + "Listener container '" + CONNECTION_FACTORY_ATTRIBUTE + + "' attribute contains empty value."); } - else + } + + containerDef.AddPropertyValue("ConnectionFactory", new RuntimeObjectReference(connectionFactoryObjectName)); + + string errorHandlerObjectName = containerElement.GetAttribute(ERROR_HANDLER_ATTRIBUTE); + if (StringUtils.HasText(errorHandlerObjectName)) + { + containerDef.AddPropertyValue("ErrorHandler", + new RuntimeObjectReference(errorHandlerObjectName)); + } + + string exceptionListenerObjectName = containerElement.GetAttribute(EXCEPTION_LISTENER_ATTRIBUTE); + if (StringUtils.HasText(exceptionListenerObjectName)) + { + containerDef.AddPropertyValue("ExceptionListener", + new RuntimeObjectReference(exceptionListenerObjectName)); + } + + string destinationResolverObjectName = containerElement.GetAttribute(DESTINATION_RESOLVER_ATTRIBUTE); + if (StringUtils.HasText(destinationResolverObjectName)) + { + containerDef.AddPropertyValue("DestinationResolver", + new RuntimeObjectReference(destinationResolverObjectName)); + } + + string acknowledge = containerElement.GetAttribute(ACKNOWLEDGE_ATTRIBUTE); + if (StringUtils.HasText(acknowledge)) + { + AcknowledgementMode acknowledgementMode = ParseAcknowledgementMode(containerElement, parserContext); + containerDef.AddPropertyValue("SessionAcknowledgeMode", acknowledgementMode); + } + + string concurrency = ParseConcurrency(containerElement, parserContext); + if (concurrency != null) + { + containerDef.AddPropertyValue("ConcurrentConsumers", concurrency); + } + + containerDef.AddPropertyValue("RecoveryInterval", ParseRecoveryInterval(containerElement, parserContext)); + + containerDef.AddPropertyValue("MaxRecoveryTime", ParseMaxRecoveryTime(containerElement, parserContext)); + + return containerDef; + } + + private bool IndicatesPubSub(AbstractObjectDefinition configDef) + { + return (bool) configDef.PropertyValues.GetPropertyValue("PubSubDomain").Value; + } + + private void ParseListenerConfiguration(XmlElement ele, ParserContext parserContext, + ObjectDefinitionBuilder containerDef) + { + string destination = ele.GetAttribute(DESTINATION_ATTRIBUTE); + if (!StringUtils.HasText(destination)) + { + parserContext.ReaderContext.ReportException(ele, LISTENER_ELEMENT, + "Listener '" + DESTINATION_ATTRIBUTE + + "' attribute contains empty value."); + } + + containerDef.AddPropertyValue("DestinationName", destination); + + if (ele.HasAttribute(SUBSCRIPTION_ATTRIBUTE)) + { + string subscription = ele.GetAttribute(SUBSCRIPTION_ATTRIBUTE); + if (!StringUtils.HasText(subscription)) { - return SimpleMessageListenerContainer.DEFAULT_MAX_RECOVERY_TIME; + parserContext.ReaderContext.ReportException(ele, SUBSCRIPTION_ATTRIBUTE, + "Listener '" + SUBSCRIPTION_ATTRIBUTE + + "' attribute contains empty value."); } + + containerDef.AddPropertyValue("DurableSubscriptionName", subscription); + } + + if (ele.HasAttribute(SELECTOR_ATTRIBUTE)) + { + string selector = ele.GetAttribute(SELECTOR_ATTRIBUTE); + if (!StringUtils.HasText(selector)) + { + parserContext.ReaderContext.ReportException(ele, selector, + "Listener '" + SELECTOR_ATTRIBUTE + + "' attribute contains empty value."); + } + + containerDef.AddPropertyValue("MessageSelector", selector); + } + } + + private void ParseContainerConfiguration(XmlElement ele, ParserContext parserContext, + ObjectDefinitionBuilder containerDef) + { + string destinationType = ele.GetAttribute(DESTINATION_TYPE_ATTRIBUTE); + bool pubSubDomain = false; + bool subscriptionDurable = false; + if (DESTINATION_TYPE_DURABLE_TOPIC.Equals(destinationType)) + { + pubSubDomain = true; + subscriptionDurable = true; + } + else if (DESTINATION_TYPE_TOPIC.Equals(destinationType)) + { + pubSubDomain = true; + } + else if ("".Equals(destinationType) || DESTINATION_TYPE_QUEUE.Equals(destinationType)) + { + // the default: queue + } + else + { + parserContext.ReaderContext.ReportException(ele, destinationType, + "Invalid listener container '" + DESTINATION_TYPE_ATTRIBUTE + + "': only 'queue', 'topic' and 'durableTopic' supported"); + } + + containerDef.AddPropertyValue("PubSubDomain", pubSubDomain); + containerDef.AddPropertyValue("SubscriptionDurable", subscriptionDurable); + + if (ele.HasAttribute(CLIENT_ID_ATTRIBUTE)) + { + string clientId = ele.GetAttribute(CLIENT_ID_ATTRIBUTE); + if (!StringUtils.HasText(clientId)) + { + parserContext.ReaderContext.ReportException(ele, clientId, + "Listener '" + CLIENT_ID_ATTRIBUTE + + "' attribute contains empty value."); + } + + containerDef.AddPropertyValue("ClientId", clientId); + } + } + + private AcknowledgementMode ParseAcknowledgementMode(XmlElement element, ParserContext parserContext) + { + string acknowledge = element.GetAttribute(ACKNOWLEDGE_ATTRIBUTE); + if (acknowledge.Equals(ACKNOWLEDGE_TRANSACTED)) + { + return AcknowledgementMode.Transactional; + } + else if (acknowledge.Equals(ACKNOWLEDGE_DUPS_OK)) + { + return AcknowledgementMode.DupsOkAcknowledge; + } + else if (acknowledge.Equals(ACKNOWLEDGE_CLIENT)) + { + return AcknowledgementMode.ClientAcknowledge; + } + else if (!acknowledge.Equals(ACKNOWLEDGE_AUTO)) + { + parserContext.ReaderContext.ReportException(element, ACKNOWLEDGE_ATTRIBUTE, + "Invalid listener container 'acknowledge' setting ['" + + acknowledge + + "]: only \"auto\", \"client\", \"dups-ok\" and \"transacted\" supported."); + } + + return AcknowledgementMode.AutoAcknowledge; + } + + private string ParseConcurrency(XmlElement ele, ParserContext parserContext) + { + string concurrency = ele.GetAttribute(CONCURRENCY_ATTRIBUTE); + if (!StringUtils.HasText(concurrency)) + { + return null; + } + else + { + return concurrency; + } + } + + private string ParseRecoveryInterval(XmlElement ele, ParserContext parserContext) + { + string recoveryInterval = ele.GetAttribute(RECOVERY_INTERVAL_ATTRIBUTE); + if (StringUtils.HasText(recoveryInterval)) + { + return recoveryInterval; + } + else + { + return SimpleMessageListenerContainer.DEFAULT_RECOVERY_INTERVAL; + } + } + + private string ParseMaxRecoveryTime(XmlElement ele, ParserContext parserContext) + { + string recoverTime = ele.GetAttribute(MAX_RECOVERY_TIME_ATTRIBUTE); + if (StringUtils.HasText(recoverTime)) + { + return recoverTime; + } + else + { + return SimpleMessageListenerContainer.DEFAULT_MAX_RECOVERY_TIME; } } } diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Config/NmsNamespaceParser.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Config/NmsNamespaceParser.cs index a166f912..19b2c687 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Config/NmsNamespaceParser.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Config/NmsNamespaceParser.cs @@ -20,29 +20,28 @@ using Spring.Objects.Factory.Xml; -namespace Spring.Messaging.Nms.Config +namespace Spring.Messaging.Nms.Config; + +/// +/// Namespace parser for the nms namespace. +/// +/// Mark Fisher +/// Juergen Hoeller +/// Mark Pollack (.NET) +[ + NamespaceParser( + Namespace = "http://www.springframework.net/nms", + SchemaLocationAssemblyHint = typeof(NmsNamespaceParser), + SchemaLocation = "/Spring.Messaging.Nms.Config/spring-nms-1.3.xsd" + ) +] +public class NmsNamespaceParser : NamespaceParserSupport { /// - /// Namespace parser for the nms namespace. + /// Register a MessageListenerContainer for the 'listener-container' tag. /// - /// Mark Fisher - /// Juergen Hoeller - /// Mark Pollack (.NET) - [ - NamespaceParser( - Namespace = "http://www.springframework.net/nms", - SchemaLocationAssemblyHint = typeof (NmsNamespaceParser), - SchemaLocation = "/Spring.Messaging.Nms.Config/spring-nms-1.3.xsd" - ) - ] - public class NmsNamespaceParser : NamespaceParserSupport + public override void Init() { - /// - /// Register a MessageListenerContainer for the 'listener-container' tag. - /// - public override void Init() - { - RegisterObjectDefinitionParser("listener-container", new MessageListenerContainerObjectDefinitionParser()); - } + RegisterObjectDefinitionParser("listener-container", new MessageListenerContainerObjectDefinitionParser()); } -} \ No newline at end of file +} diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Config/spring-nms-1.2.xsd b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Config/spring-nms-1.2.xsd index 88cf7d59..559f0ca1 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Config/spring-nms-1.2.xsd +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Config/spring-nms-1.2.xsd @@ -1,211 +1,212 @@ + xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:vs="http://schemas.microsoft.com/Visual-Studio-Intellisense" + targetNamespace="http://www.springframework.net/nms" + elementFormDefault="qualified" + attributeFormDefault="unqualified" + vs:friendlyname="Spring.NET NMS Configuration" vs:ishtmlschema="false" vs:iscasesensitive="true" + vs:requireattributequotes="true" vs:defaultnamespacequalifier="" vs:defaultnsprefix=""> - - + - + - - - + + - - - - - - - - + + + + + + + - - - - - - - - - - - + + + + + + + + + + - - - - - - - + + + + + + - - - - - - + + + + + - - - - - + + + + - - - - - + + + + - - - - - + + + + - - - - - - - - - - - - + + + + + + + + + + + - - - - - + + + + - - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - + + + + + - - - - - - - + + + + + + - - - - - - + + + + + - - - - + + + - - - - - + + + + - - - - - + + + + - - - - - + + + + - - - - - + + + + - - - - - + + + + - - - - - + + + + - - - - - - + + + + + - - - - - + + + + + diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Config/spring-nms-1.3.xsd b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Config/spring-nms-1.3.xsd index 92f502c4..b4f35942 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Config/spring-nms-1.3.xsd +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Config/spring-nms-1.3.xsd @@ -1,231 +1,232 @@ + xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:vs="http://schemas.microsoft.com/Visual-Studio-Intellisense" + targetNamespace="http://www.springframework.net/nms" + elementFormDefault="qualified" + attributeFormDefault="unqualified" + vs:friendlyname="Spring.NET NMS Configuration" vs:ishtmlschema="false" vs:iscasesensitive="true" + vs:requireattributequotes="true" vs:defaultnamespacequalifier="" vs:defaultnsprefix=""> - - + - + - - - + + - - - - - - - - + + + + + + + - - - - - - - - - - - + + + + + + + + + + - - - - - - - + + + + + + - - - - - - + + + + + - - - - - + + + + - - - - - + + + + - - - - - - + + + + + - - - - - - - + + + + + + - - - - - - + + + + + - - - - - - - - - - - - + + + + + + + + + + + - - - - - + + + + - - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - + + + + + - - - - - - - + + + + + + - - - - - - + + + + + - - - - + + + - - - - - + + + + - - - - - + + + + - - - - - + + + + - - - - - + + + + - - - - - + + + + - - - - - + + + + - - - - - - + + + + + - - - - - + + + + + diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/CachedMessageConsumer .cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/CachedMessageConsumer .cs index 7e17664a..b3909507 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/CachedMessageConsumer .cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/CachedMessageConsumer .cs @@ -20,139 +20,136 @@ using Apache.NMS; -namespace Spring.Messaging.Nms.Connections +namespace Spring.Messaging.Nms.Connections; + +/// +/// NMS MessageConsumer decorator that adapts all calls +/// to a shared MessageConsumer instance underneath. +/// +/// Juergen Hoeller +/// Mark Pollack (.NET) +public class CachedMessageConsumer : IMessageConsumer { + private IMessageConsumer target; + /// - /// NMS MessageConsumer decorator that adapts all calls - /// to a shared MessageConsumer instance underneath. + /// Initializes a new instance of the class. /// - /// Juergen Hoeller - /// Mark Pollack (.NET) - public class CachedMessageConsumer : IMessageConsumer + /// The target. + public CachedMessageConsumer(IMessageConsumer target) { - private IMessageConsumer target; + this.target = target; + } - /// - /// Initializes a new instance of the class. - /// - /// The target. - public CachedMessageConsumer(IMessageConsumer target) + /// + /// Gets the target MessageConsumer, the consumer we are 'wrapping' + /// + /// The target MessageConsumer. + public IMessageConsumer Target + { + get { return target; } + } + + public string MessageSelector + { + get { - this.target = target; - } - - - /// - /// Gets the target MessageConsumer, the consumer we are 'wrapping' - /// - /// The target MessageConsumer. - public IMessageConsumer Target - { - get { return target; } - } - - public string MessageSelector - { - get - { - return target.MessageSelector; - } - } - - /// - /// Register for message events. - /// - public event MessageListener Listener - { - add - { - target.Listener += value; - } - remove - { - target.Listener -= value; - } - } - - /// - /// Receives the next message produced for this message consumer. - /// - /// the next message produced for this message consumer, , or null if this message consumer is concurrently closed - public IMessage Receive() - { - return this.target.Receive(); - } - - public Task ReceiveAsync() - { - return this.target.ReceiveAsync(); - } - - /// - /// Receives the next message that arrives within the specified timeout interval. - /// - /// The timeout value. - /// the next message produced for this message consumer, or null if the timeout expires or this message consumer is concurrently closed - public IMessage Receive(TimeSpan timeout) - { - return this.target.Receive(timeout); - } - - public Task ReceiveAsync(TimeSpan timeout) - { - return this.target.ReceiveAsync(timeout); - } - - /// - /// Receives the next message if one is immediately available. - /// - /// the next message produced for this message consumer, or null if one is not available - public IMessage ReceiveNoWait() - { - return this.target.ReceiveNoWait(); - } - - /// - /// No-op implementation since it is caching. - /// - public void Close() - { - // It's a cached MessageConsumer... - } - - public Task CloseAsync() - { - // It's a cached MessageConsumer... - return Task.FromResult(true); - } - - /// - /// A Delegate that is called each time a Message is dispatched to allow the client to do - /// any necessary transformations on the received message before it is delivered. - /// - /// - public ConsumerTransformerDelegate ConsumerTransformer - { - get { return target.ConsumerTransformer; } - set { target.ConsumerTransformer = value; } - } - - /// - /// Dispose of wrapped MessageConsumer - /// - public void Dispose() - { - this.target.Dispose(); - } - - - /// - /// Description that shows this is a cached MessageConsumer - /// - /// Description that shows this is a cached MessageConsumer - public override string ToString() - { - return "Cached NMS MessageConsumer: " + this.target; + return target.MessageSelector; } } -} \ No newline at end of file + + /// + /// Register for message events. + /// + public event MessageListener Listener + { + add + { + target.Listener += value; + } + remove + { + target.Listener -= value; + } + } + + /// + /// Receives the next message produced for this message consumer. + /// + /// the next message produced for this message consumer, , or null if this message consumer is concurrently closed + public IMessage Receive() + { + return this.target.Receive(); + } + + public Task ReceiveAsync() + { + return this.target.ReceiveAsync(); + } + + /// + /// Receives the next message that arrives within the specified timeout interval. + /// + /// The timeout value. + /// the next message produced for this message consumer, or null if the timeout expires or this message consumer is concurrently closed + public IMessage Receive(TimeSpan timeout) + { + return this.target.Receive(timeout); + } + + public Task ReceiveAsync(TimeSpan timeout) + { + return this.target.ReceiveAsync(timeout); + } + + /// + /// Receives the next message if one is immediately available. + /// + /// the next message produced for this message consumer, or null if one is not available + public IMessage ReceiveNoWait() + { + return this.target.ReceiveNoWait(); + } + + /// + /// No-op implementation since it is caching. + /// + public void Close() + { + // It's a cached MessageConsumer... + } + + public Task CloseAsync() + { + // It's a cached MessageConsumer... + return Task.FromResult(true); + } + + /// + /// A Delegate that is called each time a Message is dispatched to allow the client to do + /// any necessary transformations on the received message before it is delivered. + /// + /// + public ConsumerTransformerDelegate ConsumerTransformer + { + get { return target.ConsumerTransformer; } + set { target.ConsumerTransformer = value; } + } + + /// + /// Dispose of wrapped MessageConsumer + /// + public void Dispose() + { + this.target.Dispose(); + } + + /// + /// Description that shows this is a cached MessageConsumer + /// + /// Description that shows this is a cached MessageConsumer + public override string ToString() + { + return "Cached NMS MessageConsumer: " + this.target; + } +} diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/CachedMessageProducer.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/CachedMessageProducer.cs index 34ff3bfc..3a6ec63f 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/CachedMessageProducer.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/CachedMessageProducer.cs @@ -20,378 +20,376 @@ using Apache.NMS; -namespace Spring.Messaging.Nms.Connections +namespace Spring.Messaging.Nms.Connections; + +/// +/// MessageProducer decorator that adapts calls to a shared MessageProducer +/// instance underneath, managing QoS settings locally within the decorator. +/// +/// Juergen Hoeller +/// Mark Pollack (.NET) +public class CachedMessageProducer : IMessageProducer { + private readonly IMessageProducer target; + + private object originalDisableMessageID = null; + + private object originalDisableMessageTimestamp = null; + + private MsgDeliveryMode msgDeliveryMode; + + private MsgPriority priority; + + private TimeSpan timeToLive; + + private TimeSpan requestTimeout; + /// - /// MessageProducer decorator that adapts calls to a shared MessageProducer - /// instance underneath, managing QoS settings locally within the decorator. + /// Initializes a new instance of the class. /// - /// Juergen Hoeller - /// Mark Pollack (.NET) - public class CachedMessageProducer : IMessageProducer + /// The target. + public CachedMessageProducer(IMessageProducer target) { - private readonly IMessageProducer target; + this.target = target; + this.msgDeliveryMode = target.DeliveryMode; + this.priority = target.Priority; + this.timeToLive = target.TimeToLive; + } - private object originalDisableMessageID = null; + /// + /// Gets the target MessageProducer, the producer we are 'wrapping' + /// + /// The target MessageProducer. + public IMessageProducer Target + { + get { return target; } + } - private object originalDisableMessageTimestamp = null; + /// + /// Sends the specified message. + /// + /// The message. + public void Send(IMessage message) + { + target.Send(message); + } - private MsgDeliveryMode msgDeliveryMode; + /// + /// Sends a message to the specified message. + /// + /// The message to send. + /// The QOS to use for sending . + /// The message priority. + /// The time to live. + public void Send(IMessage message, MsgDeliveryMode deliveryMode, MsgPriority priority, TimeSpan timeToLive) + { + target.Send(message, deliveryMode, priority, timeToLive); + } - private MsgPriority priority; + /// + /// Sends a message to the specified destination. + /// + /// The destination. + /// The message. + public void Send(IDestination destination, IMessage message) + { + target.Send(destination, message); + } - private TimeSpan timeToLive; + /// + /// Sends a message the specified destination. + /// + /// The destination. + /// The message to send. + /// The QOS to use for sending . + /// The priority. + /// The time to live. + public void Send(IDestination destination, IMessage message, MsgDeliveryMode deliveryMode, MsgPriority priority, TimeSpan timeToLive) + { + target.Send(destination, message, deliveryMode, priority, timeToLive); + } - private TimeSpan requestTimeout; + public TimeSpan DeliveryDelay + { + get { return target.DeliveryDelay; } + set { target.DeliveryDelay = value; } + } + public Task SendAsync(IMessage message) + { + return target.SendAsync(message); + } - /// - /// Initializes a new instance of the class. - /// - /// The target. - public CachedMessageProducer(IMessageProducer target) + public Task SendAsync(IMessage message, MsgDeliveryMode deliveryMode, MsgPriority priority, TimeSpan timeToLive) + { + return target.SendAsync(message, deliveryMode, priority, timeToLive); + } + + public Task SendAsync(IDestination destination, IMessage message) + { + return target.SendAsync(destination, message); + } + + public Task SendAsync(IDestination destination, IMessage message, MsgDeliveryMode deliveryMode, MsgPriority priority, TimeSpan timeToLive) + { + return target.SendAsync(destination, message, deliveryMode, priority, timeToLive); + } + + #region Odd Message Creationg Methods on IMessageProducer - not in-line with JMS APIs. + + /// + /// Creates the message. + /// + /// A new message + public IMessage CreateMessage() + { + return target.CreateMessage(); + } + + public Task CreateMessageAsync() + { + return target.CreateMessageAsync(); + } + + /// + /// Creates the text message. + /// + /// A new text message. + public ITextMessage CreateTextMessage() + { + return target.CreateTextMessage(); + } + + public Task CreateTextMessageAsync() + { + return target.CreateTextMessageAsync(); + } + + /// + /// Creates the text message. + /// + /// The text. + /// A texst message with the given text. + public ITextMessage CreateTextMessage(string text) + { + return target.CreateTextMessage(text); + } + + public Task CreateTextMessageAsync(string text) + { + return target.CreateTextMessageAsync(text); + } + + /// + /// Creates the map message. + /// + /// a new map message. + public IMapMessage CreateMapMessage() + { + return target.CreateMapMessage(); + } + + public Task CreateMapMessageAsync() + { + return target.CreateMapMessageAsync(); + } + + /// + /// Creates the object message. + /// + /// The body. + /// A new object message with the given body. + public IObjectMessage CreateObjectMessage(object body) + { + return target.CreateObjectMessage(body); + } + + public Task CreateObjectMessageAsync(object body) + { + return target.CreateObjectMessageAsync(body); + } + + /// + /// Creates the bytes message. + /// + /// A new bytes message. + public IBytesMessage CreateBytesMessage() + { + return target.CreateBytesMessage(); + } + + public Task CreateBytesMessageAsync() + { + return target.CreateBytesMessageAsync(); + } + + /// + /// Creates the bytes message. + /// + /// The body. + /// A new bytes message with the given body. + public IBytesMessage CreateBytesMessage(byte[] body) + { + return target.CreateBytesMessage(body); + } + + public Task CreateBytesMessageAsync(byte[] body) + { + return target.CreateBytesMessageAsync(body); + } + + /// + /// Creates the stream message. + /// + /// A new stream message. + public IStreamMessage CreateStreamMessage() + { + return target.CreateStreamMessage(); + } + + public Task CreateStreamMessageAsync() + { + return target.CreateStreamMessageAsync(); + } + + /// + /// A delegate that is called each time a Message is sent from this Producer which allows + /// the application to perform any needed transformations on the Message before it is sent. + /// The Session instance sets the delegate on each Producer it creates. + /// + /// + public ProducerTransformerDelegate ProducerTransformer + { + get { return target.ProducerTransformer; } + set { target.ProducerTransformer = value; } + } + + #endregion + + /// + /// Gets or sets a value indicating what DeliveryMode this + /// should use, for example a persistent QOS + /// + /// + public MsgDeliveryMode DeliveryMode + { + get { return msgDeliveryMode; } + set { msgDeliveryMode = value; } + } + + /// + /// Gets or sets the time to live value for messages sent with this producer. + /// + /// The time to live. + public TimeSpan TimeToLive + { + get { return timeToLive; } + set { timeToLive = value; } + } + + /// + /// Gets or sets the request timeout for the message producer. + /// + /// The request timeout. + public TimeSpan RequestTimeout + { + get { return requestTimeout; } + set { requestTimeout = value; } + } + + /// + /// Gets or sets the priority of messages sent with this producer. + /// + /// The priority. + public MsgPriority Priority + { + get { return priority; } + set { priority = value; } + } + + /// + /// Gets or sets a value indicating whether disable setting of the message ID property. + /// + /// true if disable message ID setting; otherwise, false. + public bool DisableMessageID + { + get { - this.target = target; - this.msgDeliveryMode = target.DeliveryMode; - this.priority = target.Priority; - this.timeToLive = target.TimeToLive; + return target.DisableMessageID; } - - - /// - /// Gets the target MessageProducer, the producer we are 'wrapping' - /// - /// The target MessageProducer. - public IMessageProducer Target + set { - get { return target; } - } - - /// - /// Sends the specified message. - /// - /// The message. - public void Send(IMessage message) - { - target.Send(message); - } - - /// - /// Sends a message to the specified message. - /// - /// The message to send. - /// The QOS to use for sending . - /// The message priority. - /// The time to live. - public void Send(IMessage message, MsgDeliveryMode deliveryMode, MsgPriority priority, TimeSpan timeToLive) - { - target.Send(message, deliveryMode, priority, timeToLive); - } - - /// - /// Sends a message to the specified destination. - /// - /// The destination. - /// The message. - public void Send(IDestination destination, IMessage message) - { - target.Send(destination, message); - } - - /// - /// Sends a message the specified destination. - /// - /// The destination. - /// The message to send. - /// The QOS to use for sending . - /// The priority. - /// The time to live. - public void Send(IDestination destination, IMessage message, MsgDeliveryMode deliveryMode, MsgPriority priority, TimeSpan timeToLive) - { - target.Send(destination, message, deliveryMode, priority, timeToLive); - } - - public TimeSpan DeliveryDelay - { - get { return target.DeliveryDelay; } - set { target.DeliveryDelay = value; } - } - - public Task SendAsync(IMessage message) - { - return target.SendAsync(message); - } - - public Task SendAsync(IMessage message, MsgDeliveryMode deliveryMode, MsgPriority priority, TimeSpan timeToLive) - { - return target.SendAsync(message, deliveryMode, priority, timeToLive); - } - - public Task SendAsync(IDestination destination, IMessage message) - { - return target.SendAsync(destination, message); - } - - public Task SendAsync(IDestination destination, IMessage message, MsgDeliveryMode deliveryMode, MsgPriority priority, TimeSpan timeToLive) - { - return target.SendAsync(destination, message, deliveryMode, priority, timeToLive); - } - - #region Odd Message Creationg Methods on IMessageProducer - not in-line with JMS APIs. - /// - /// Creates the message. - /// - /// A new message - public IMessage CreateMessage() - { - return target.CreateMessage(); - } - - public Task CreateMessageAsync() - { - return target.CreateMessageAsync(); - } - - /// - /// Creates the text message. - /// - /// A new text message. - public ITextMessage CreateTextMessage() - { - return target.CreateTextMessage(); - } - - public Task CreateTextMessageAsync() - { - return target.CreateTextMessageAsync(); - } - - /// - /// Creates the text message. - /// - /// The text. - /// A texst message with the given text. - public ITextMessage CreateTextMessage(string text) - { - return target.CreateTextMessage(text); - } - - public Task CreateTextMessageAsync(string text) - { - return target.CreateTextMessageAsync(text); - } - - /// - /// Creates the map message. - /// - /// a new map message. - public IMapMessage CreateMapMessage() - { - return target.CreateMapMessage(); - } - - public Task CreateMapMessageAsync() - { - return target.CreateMapMessageAsync(); - } - - /// - /// Creates the object message. - /// - /// The body. - /// A new object message with the given body. - public IObjectMessage CreateObjectMessage(object body) - { - return target.CreateObjectMessage(body); - } - - public Task CreateObjectMessageAsync(object body) - { - return target.CreateObjectMessageAsync(body); - } - - /// - /// Creates the bytes message. - /// - /// A new bytes message. - public IBytesMessage CreateBytesMessage() - { - return target.CreateBytesMessage(); - } - - public Task CreateBytesMessageAsync() - { - return target.CreateBytesMessageAsync(); - } - - /// - /// Creates the bytes message. - /// - /// The body. - /// A new bytes message with the given body. - public IBytesMessage CreateBytesMessage(byte[] body) - { - return target.CreateBytesMessage(body); - } - - public Task CreateBytesMessageAsync(byte[] body) - { - return target.CreateBytesMessageAsync(body); - } - - /// - /// Creates the stream message. - /// - /// A new stream message. - public IStreamMessage CreateStreamMessage() - { - return target.CreateStreamMessage(); - } - - public Task CreateStreamMessageAsync() - { - return target.CreateStreamMessageAsync(); - } - - - /// - /// A delegate that is called each time a Message is sent from this Producer which allows - /// the application to perform any needed transformations on the Message before it is sent. - /// The Session instance sets the delegate on each Producer it creates. - /// - /// - public ProducerTransformerDelegate ProducerTransformer - { - get { return target.ProducerTransformer; } - set { target.ProducerTransformer = value; } - } - - #endregion - - /// - /// Gets or sets a value indicating what DeliveryMode this - /// should use, for example a persistent QOS - /// - /// - public MsgDeliveryMode DeliveryMode - { - get { return msgDeliveryMode; } - set { msgDeliveryMode = value; } - } - - /// - /// Gets or sets the time to live value for messages sent with this producer. - /// - /// The time to live. - public TimeSpan TimeToLive - { - get { return timeToLive; } - set { timeToLive = value; } - } - - - /// - /// Gets or sets the request timeout for the message producer. - /// - /// The request timeout. - public TimeSpan RequestTimeout - { - get { return requestTimeout; } - set { requestTimeout = value; } - } - - /// - /// Gets or sets the priority of messages sent with this producer. - /// - /// The priority. - public MsgPriority Priority - { - get { return priority; } - set { priority = value;} - } - - /// - /// Gets or sets a value indicating whether disable setting of the message ID property. - /// - /// true if disable message ID setting; otherwise, false. - public bool DisableMessageID - { - get + if (originalDisableMessageID == null) { - return target.DisableMessageID; + originalDisableMessageID = target.DisableMessageID; } - set - { - if (originalDisableMessageID == null) - { - originalDisableMessageID = target.DisableMessageID; - } - target.DisableMessageID = value; - } - } - /// - /// Gets or sets a value indicating whether disable setting the message timestamp property. - /// - /// - /// true if disable message timestamp; otherwise, false. - /// - public bool DisableMessageTimestamp - { - get - { - return target.DisableMessageTimestamp; - } - set - { - if (originalDisableMessageTimestamp == null) - { - originalDisableMessageTimestamp = target.DisableMessageTimestamp; - } - target.DisableMessageTimestamp = value; - } - } - - /// - /// Reset properties. - /// - public void Close() - { - // It's a cached MessageProducer... reset properties only. - if (originalDisableMessageID != null) - { - target.DisableMessageID = (bool) originalDisableMessageID; - originalDisableMessageID = null; - } - if (originalDisableMessageTimestamp != null) - { - target.DisableMessageTimestamp = (bool) originalDisableMessageTimestamp; - originalDisableMessageTimestamp = null; - } - } - - public Task CloseAsync() - { - Close(); - return Task.FromResult(true); - } - - /// - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - /// - public void Dispose() - { - target.Dispose(); - } - - - /// - /// Returns string indicated this is a wrapped MessageProducer - /// - /// - public override string ToString() - { - return "Cached NMS MessageProducer: " + this.target; + target.DisableMessageID = value; } } -} \ No newline at end of file + + /// + /// Gets or sets a value indicating whether disable setting the message timestamp property. + /// + /// + /// true if disable message timestamp; otherwise, false. + /// + public bool DisableMessageTimestamp + { + get + { + return target.DisableMessageTimestamp; + } + set + { + if (originalDisableMessageTimestamp == null) + { + originalDisableMessageTimestamp = target.DisableMessageTimestamp; + } + + target.DisableMessageTimestamp = value; + } + } + + /// + /// Reset properties. + /// + public void Close() + { + // It's a cached MessageProducer... reset properties only. + if (originalDisableMessageID != null) + { + target.DisableMessageID = (bool) originalDisableMessageID; + originalDisableMessageID = null; + } + + if (originalDisableMessageTimestamp != null) + { + target.DisableMessageTimestamp = (bool) originalDisableMessageTimestamp; + originalDisableMessageTimestamp = null; + } + } + + public Task CloseAsync() + { + Close(); + return Task.FromResult(true); + } + + /// + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// + public void Dispose() + { + target.Dispose(); + } + + /// + /// Returns string indicated this is a wrapped MessageProducer + /// + /// + public override string ToString() + { + return "Cached NMS MessageProducer: " + this.target; + } +} diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/CachedSession.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/CachedSession.cs index 0853e1a1..d858ce64 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/CachedSession.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/CachedSession.cs @@ -18,926 +18,928 @@ using Apache.NMS; using Microsoft.Extensions.Logging; using Spring.Messaging.Nms.Support; using Spring.Util; -using IQueue=Apache.NMS.IQueue; +using IQueue = Apache.NMS.IQueue; -namespace Spring.Messaging.Nms.Connections +namespace Spring.Messaging.Nms.Connections; + +/// +/// Wrapper for Session that caches producers and registers itself as available +/// to the session cache when being closed. Generally used for testing purposes or +/// if need to get at the wrapped Session object via the TargetSession property (for +/// vendor specific methods). +/// +/// Juergen Hoeller +/// Mark Pollack +public class CachedSession : IDecoratorSession { + private static readonly ILogger Log = LogManager.GetLogger(); + + private readonly ISession target; + private readonly List sessionList; + private readonly SemaphoreSlim semaphoreSessionList = new SemaphoreSlim(1, 1); + private readonly int sessionCacheSize; + private readonly Dictionary cachedProducers = new Dictionary(); + private readonly Dictionary cachedConsumers = new Dictionary(); + private IMessageProducer cachedUnspecifiedDestinationMessageProducer; + private readonly bool shouldCacheProducers; + private readonly bool shouldCacheConsumers; + private bool transactionOpen = false; + private readonly CachingConnectionFactory ccf; + /// - /// Wrapper for Session that caches producers and registers itself as available - /// to the session cache when being closed. Generally used for testing purposes or - /// if need to get at the wrapped Session object via the TargetSession property (for - /// vendor specific methods). + /// Initializes a new instance of the class. /// - /// Juergen Hoeller - /// Mark Pollack - public class CachedSession : IDecoratorSession + /// The target session. + /// The session list. + /// The CachingConnectionFactory. + public CachedSession( + ISession targetSession, + List sessionList, + CachingConnectionFactory ccf) { - private static readonly ILogger Log = LogManager.GetLogger(); + target = targetSession; + this.sessionList = sessionList; + sessionCacheSize = ccf.SessionCacheSize; + shouldCacheProducers = ccf.CacheProducers; + shouldCacheConsumers = ccf.CacheConsumers; + this.ccf = ccf; + } - private readonly ISession target; - private readonly List sessionList; - private readonly SemaphoreSlim semaphoreSessionList = new SemaphoreSlim(1,1); - private readonly int sessionCacheSize; - private readonly Dictionary cachedProducers = new Dictionary(); - private readonly Dictionary cachedConsumers = new Dictionary(); - private IMessageProducer cachedUnspecifiedDestinationMessageProducer; - private readonly bool shouldCacheProducers; - private readonly bool shouldCacheConsumers; - private bool transactionOpen = false; - private readonly CachingConnectionFactory ccf; + /// + /// Gets the target, for testing purposes. + /// + /// The target. + public ISession TargetSession => target; - /// - /// Initializes a new instance of the class. - /// - /// The target session. - /// The session list. - /// The CachingConnectionFactory. - public CachedSession( - ISession targetSession, - List sessionList, - CachingConnectionFactory ccf) + /// + /// Creates the producer, potentially returning a cached instance. + /// + /// A message producer, potentially cached. + public IMessageProducer CreateProducer() + { + return CreateProducerAsync().GetAsyncResult(); + } + + public async Task CreateProducerAsync() + { + if (shouldCacheProducers) { - target = targetSession; - this.sessionList = sessionList; - sessionCacheSize = ccf.SessionCacheSize; - shouldCacheProducers = ccf.CacheProducers; - shouldCacheConsumers = ccf.CacheConsumers; - this.ccf = ccf; - } - - - /// - /// Gets the target, for testing purposes. - /// - /// The target. - public ISession TargetSession => target; - - /// - /// Creates the producer, potentially returning a cached instance. - /// - /// A message producer, potentially cached. - public IMessageProducer CreateProducer() - { - return CreateProducerAsync().GetAsyncResult(); - } - - public async Task CreateProducerAsync() - { - if (shouldCacheProducers) - { - if (cachedUnspecifiedDestinationMessageProducer != null) - { - if (Log.IsEnabled(LogLevel.Debug)) - { - Log.LogDebug("Found cached MessageProducer for unspecified destination"); - } - } - else - { - if (Log.IsEnabled(LogLevel.Debug)) - { - Log.LogDebug("Creating cached MessageProducer for unspecified destination"); - } - - cachedUnspecifiedDestinationMessageProducer = await target.CreateProducerAsync().Awaiter(); - - } - transactionOpen = true; - return new CachedMessageProducer(cachedUnspecifiedDestinationMessageProducer); - } - else - { - return await target.CreateProducerAsync().Awaiter(); - } - } - - /// - /// Creates the producer, potentially returning a cached instance. - /// - /// The destination. - /// A message producer. - public IMessageProducer CreateProducer(IDestination destination) - { - return CreateProducerAsync(destination).GetAsyncResult(); - } - - public async Task CreateProducerAsync(IDestination destination) - { - AssertUtils.ArgumentNotNull(destination,"destination"); - - if (shouldCacheProducers) - { - if (cachedProducers.TryGetValue(destination, out var producer)) - { - if (Log.IsEnabled(LogLevel.Debug)) - { - Log.LogDebug("Found cached MessageProducer for destination [" + destination + "]"); - } - } - else - { - producer = await target.CreateProducerAsync(destination).Awaiter(); - - if (Log.IsEnabled(LogLevel.Debug)) - { - Log.LogDebug("Creating cached MessageProducer for destination [" + destination + "]"); - } - - cachedProducers[destination] = producer; - - } - transactionOpen = true; - return new CachedMessageProducer(producer); - } - else - { - return await target.CreateProducerAsync(destination).Awaiter(); - } - } - - - /// - /// If have not yet reached session cache size, cache the session, otherwise - /// dispose of all cached message producers and close the session. - /// - public void Close() - { - CloseAsync().GetAsyncResult(); - } - - public async Task CloseAsync() - { - if (ccf.IsActive) - { - //don't pass the call to the underlying target. - await semaphoreSessionList.WaitAsync().Awaiter(); - try - { - if (sessionList.Count < sessionCacheSize) - { - await LogicalClose().Awaiter(); - // Remain open in the session list. - return; - } - } - finally - { - semaphoreSessionList.Release(); - } - } - // If we get here, we're supposed to shut down. - await PhysicalClose().Awaiter(); - } - - private async Task LogicalClose() - { - // Preserve rollback-on-close semantics. - if (transactionOpen && target.Transacted) - { - transactionOpen = false; - await target.RollbackAsync().Awaiter(); - } - - // Physically close durable subscribers at time of Session close call. - var toRemove = new List(); - foreach (var dictionaryEntry in cachedConsumers) - { - ConsumerCacheKey key = dictionaryEntry.Key; - if (key.Subscription != null) - { - await dictionaryEntry.Value.CloseAsync().Awaiter(); - toRemove.Add(key); - } - } - foreach (ConsumerCacheKey key in toRemove) - { - cachedConsumers.Remove(key); - } - - // Allow for multiple close calls... - if (!sessionList.Contains(this)) + if (cachedUnspecifiedDestinationMessageProducer != null) { if (Log.IsEnabled(LogLevel.Debug)) { - Log.LogDebug("Returning cached Session: " + target); + Log.LogDebug("Found cached MessageProducer for unspecified destination"); + } + } + else + { + if (Log.IsEnabled(LogLevel.Debug)) + { + Log.LogDebug("Creating cached MessageProducer for unspecified destination"); } - sessionList.Add(this); //add to end of linked list. + cachedUnspecifiedDestinationMessageProducer = await target.CreateProducerAsync().Awaiter(); } - } - private async Task PhysicalClose() + transactionOpen = true; + return new CachedMessageProducer(cachedUnspecifiedDestinationMessageProducer); + } + else { - if (Log.IsEnabled(LogLevel.Debug)) + return await target.CreateProducerAsync().Awaiter(); + } + } + + /// + /// Creates the producer, potentially returning a cached instance. + /// + /// The destination. + /// A message producer. + public IMessageProducer CreateProducer(IDestination destination) + { + return CreateProducerAsync(destination).GetAsyncResult(); + } + + public async Task CreateProducerAsync(IDestination destination) + { + AssertUtils.ArgumentNotNull(destination, "destination"); + + if (shouldCacheProducers) + { + if (cachedProducers.TryGetValue(destination, out var producer)) { - Log.LogDebug("Closing cached Session: " + target); + if (Log.IsEnabled(LogLevel.Debug)) + { + Log.LogDebug("Found cached MessageProducer for destination [" + destination + "]"); + } } - // Explicitly close all MessageProducers and MessageConsumers that - // this Session happens to cache... + else + { + producer = await target.CreateProducerAsync(destination).Awaiter(); + + if (Log.IsEnabled(LogLevel.Debug)) + { + Log.LogDebug("Creating cached MessageProducer for destination [" + destination + "]"); + } + + cachedProducers[destination] = producer; + } + + transactionOpen = true; + return new CachedMessageProducer(producer); + } + else + { + return await target.CreateProducerAsync(destination).Awaiter(); + } + } + + /// + /// If have not yet reached session cache size, cache the session, otherwise + /// dispose of all cached message producers and close the session. + /// + public void Close() + { + CloseAsync().GetAsyncResult(); + } + + public async Task CloseAsync() + { + if (ccf.IsActive) + { + //don't pass the call to the underlying target. + await semaphoreSessionList.WaitAsync().Awaiter(); try { - foreach (var entry in cachedProducers) + if (sessionList.Count < sessionCacheSize) { - await entry.Value.CloseAsync().Awaiter(); - } - foreach (var entry in cachedConsumers) - { - await entry.Value.CloseAsync().Awaiter(); + await LogicalClose().Awaiter(); + // Remain open in the session list. + return; } } finally { - // Now actually close the Session. - await target.CloseAsync().Awaiter(); + semaphoreSessionList.Release(); } } - /// - /// Creates the consumer, potentially returning a cached instance. - /// - /// The destination. - /// A message consumer - public IMessageConsumer CreateConsumer(IDestination destination) - { - return CreateConsumerInternalAsync(destination, null, false, null, false, false).GetAsyncResult(); - } + // If we get here, we're supposed to shut down. + await PhysicalClose().Awaiter(); + } - public Task CreateConsumerAsync(IDestination destination) - { - return CreateConsumerInternalAsync(destination, null, false, null, false, false); - } - - /// - /// Creates the consumer, potentially returning a cached instance. - /// - /// The destination. - /// The selector. - /// A message consumer - public IMessageConsumer CreateConsumer(IDestination destination, string selector) - { - return CreateConsumerInternalAsync(destination, selector, false, null, false, false).GetAsyncResult(); - } - - public Task CreateConsumerAsync(IDestination destination, string selector) - { - return CreateConsumerInternalAsync(destination, selector, false, null, false, false); - } - - /// - /// Creates the consumer, potentially returning a cached instance. - /// - /// The destination. - /// The selector. - /// if set to true [no local]. - /// A message consumer. - public IMessageConsumer CreateConsumer(IDestination destination, string selector, bool noLocal) - { - return CreateConsumerInternalAsync(destination, selector, noLocal, null, false, false).GetAsyncResult(); - } - - public Task CreateConsumerAsync(IDestination destination, string selector, bool noLocal) - { - return CreateConsumerInternalAsync(destination, selector, noLocal, null, false, false); - } - - public IMessageConsumer CreateDurableConsumer(ITopic destination, string name) - { - return CreateConsumerInternalAsync(destination, null, false, name, false, true).GetAsyncResult(); - } - - public Task CreateDurableConsumerAsync(ITopic destination, string name) - { - return CreateConsumerInternalAsync(destination, null, false, name, false, true); - } - - public IMessageConsumer CreateDurableConsumer(ITopic destination, string name, string selector) - { - return CreateConsumerInternalAsync(destination, selector, false, name, false, true).GetAsyncResult(); - } - - public Task CreateDurableConsumerAsync(ITopic destination, string name, string selector) - { - return CreateConsumerInternalAsync(destination, selector, false, name, false, true); - } - - /// - /// Creates the durable consumer, potentially returning a cached instance. - /// - /// The destination. - /// The name of the durable subscription. - /// The selector. - /// if set to true [no local]. - /// A message consumer - public IMessageConsumer CreateDurableConsumer(ITopic destination, string subscription, string selector, bool noLocal) - { - return CreateConsumerInternalAsync(destination, selector, noLocal, subscription, false, true).GetAsyncResult(); - } - - public Task CreateDurableConsumerAsync(ITopic destination, string name, string selector, bool noLocal) - { - return CreateConsumerInternalAsync(destination, selector, noLocal, name, false, true); - } - - public IMessageConsumer CreateSharedConsumer(ITopic destination, string name) - { - return CreateConsumerInternalAsync(destination, null, false, name, true, false).GetAsyncResult(); - } - - public Task CreateSharedConsumerAsync(ITopic destination, string name) - { - return CreateConsumerInternalAsync(destination, null, false, name, true, false); - } - - public IMessageConsumer CreateSharedConsumer(ITopic destination, string name, string selector) - { - return CreateConsumerInternalAsync(destination, selector, false, name, true, false).GetAsyncResult(); - } - - public Task CreateSharedConsumerAsync(ITopic destination, string name, string selector) - { - return CreateConsumerInternalAsync(destination, selector, false, name, true, false); - } - - public IMessageConsumer CreateSharedDurableConsumer(ITopic destination, string name) - { - return CreateConsumerInternalAsync(destination, null, false, name, true, true).GetAsyncResult(); - } - - public Task CreateSharedDurableConsumerAsync(ITopic destination, string name) - { - return CreateConsumerInternalAsync(destination, null, false, name, true, true); - } - - public IMessageConsumer CreateSharedDurableConsumer(ITopic destination, string name, string selector) - { - return CreateConsumerInternalAsync(destination, selector, false, name, true, true).GetAsyncResult(); - } - - public Task CreateSharedDurableConsumerAsync(ITopic destination, string name, string selector) - { - return CreateConsumerInternalAsync(destination, selector, false, name, true, true); - } - - /// - /// Deletes the durable consumer. - /// - /// The name of the durable subscription. - public void DeleteDurableConsumer(string durableSubscriptionName) - { - if (shouldCacheConsumers) - { - throw new InvalidOperationException("Deleting of durable consumers is not supported when caching of consumers is enabled"); - } - - target.Unsubscribe(durableSubscriptionName); //DeleteDurableConsumer(durableSubscriptionName); - } - - public void Unsubscribe(string name) - { - target.Unsubscribe(name); - } - - public Task UnsubscribeAsync(string name) - { - return target.UnsubscribeAsync(name); - } - - /// - /// Creates the consumer. - /// - /// The destination. - /// The selector. - /// if set to true [no local]. - /// The durable or shared subscription name. - /// - protected async Task CreateConsumerInternalAsync(IDestination destination, string selector, bool noLocal, string subscriptionName, bool shared, bool durable) - { - transactionOpen = true; - if (shouldCacheConsumers) - { - return await GetCachedConsumerAsync(destination, selector, noLocal, subscriptionName, shared, durable).Awaiter(); - } - else - { - if (shared && durable) - { - return await target.CreateSharedDurableConsumerAsync((ITopic) destination, subscriptionName, selector).Awaiter(); - } - else if (shared) - { - return await target.CreateSharedConsumerAsync((ITopic) destination, subscriptionName, selector).Awaiter(); - } - else if (durable) - { - return await target.CreateDurableConsumerAsync((ITopic) destination, subscriptionName, selector, noLocal).Awaiter(); - } - else - { - return await target.CreateConsumerAsync(destination, selector, noLocal).Awaiter(); - } - } - } - - private async Task GetCachedConsumerAsync(IDestination destination, string selector, bool noLocal, string subscriptionName, bool durable, bool shared) - { - if ((durable || shared) && subscriptionName == null) - { - throw new ArgumentException("Durable or shared subscriptions must have a name"); - } - - var cacheKey = new ConsumerCacheKey(destination, selector, noLocal, subscriptionName, durable, shared); - if (cachedConsumers.TryGetValue(cacheKey, out var consumer)) - { - if (Log.IsEnabled(LogLevel.Debug)) - { - Log.LogDebug("Found cached NMS MessageConsumer for destination [" + destination + "]: " + consumer); - } - } - else - { - if (shared && durable) - { - consumer = await target.CreateSharedDurableConsumerAsync((ITopic) destination, subscriptionName, selector).Awaiter(); - } - else if (shared) - { - consumer = await target.CreateSharedConsumerAsync((ITopic) destination, subscriptionName, selector).Awaiter(); - } - else if (durable) - { - consumer = await target.CreateDurableConsumerAsync((ITopic) destination, subscriptionName, selector, noLocal).Awaiter(); - } - else - { - consumer = await target.CreateConsumerAsync(destination, selector, noLocal).Awaiter(); - } - } - - if (Log.IsEnabled(LogLevel.Debug)) - { - Log.LogDebug("Creating cached NMS MessageConsumer for destination [" + destination + "]: " + consumer); - } - - cachedConsumers[cacheKey] = consumer; - - return new CachedMessageConsumer(consumer); - } - - public Task CreateBrowserAsync(IQueue queue, string selector) - { - transactionOpen = true; - return target.CreateBrowserAsync(queue, selector); - } - - /// - /// Gets the queue. - /// - /// The name. - /// - public IQueue GetQueue(string name) - { - return GetQueueAsync(name).GetAsyncResult(); - } - - public async Task GetQueueAsync(string name) - { - transactionOpen = true; - return await target.GetQueueAsync(name).Awaiter(); - } - - /// - /// Gets the topic. - /// - /// The name. - /// - public ITopic GetTopic(string name) - { - return GetTopicAsync(name).GetAsyncResult(); - } - - public async Task GetTopicAsync(string name) - { - transactionOpen = true; - return await target.GetTopicAsync(name).Awaiter(); - } - - /// - /// Creates the temporary queue. - /// - /// - public ITemporaryQueue CreateTemporaryQueue() - { - transactionOpen = true; - return target.CreateTemporaryQueue(); - } - - public async Task CreateTemporaryQueueAsync() - { - transactionOpen = true; - return await target.CreateTemporaryQueueAsync().Awaiter(); - } - - /// - /// Creates the temporary topic. - /// - /// - public ITemporaryTopic CreateTemporaryTopic() - { - transactionOpen = true; - return target.CreateTemporaryTopic(); - } - - public async Task CreateTemporaryTopicAsync() - { - transactionOpen = true; - return await target.CreateTemporaryTopicAsync().Awaiter(); - } - - /// - /// Deletes the destination. - /// - /// The destination. - public void DeleteDestination(IDestination destination) - { - transactionOpen = true; - target.DeleteDestination(destination); - } - - public async Task DeleteDestinationAsync(IDestination destination) - { - transactionOpen = true; - await target.DeleteDestinationAsync(destination).Awaiter(); - } - - /// - /// Creates the message. - /// - /// - public IMessage CreateMessage() - { - transactionOpen = true; - return target.CreateMessage(); - } - - public async Task CreateMessageAsync() - { - transactionOpen = true; - return await target.CreateMessageAsync().Awaiter(); - } - - /// - /// Creates the text message. - /// - /// - public ITextMessage CreateTextMessage() - { - transactionOpen = true; - return target.CreateTextMessage(); - } - - public async Task CreateTextMessageAsync() - { - transactionOpen = true; - return await target.CreateTextMessageAsync().Awaiter(); - } - - /// - /// Creates the text message. - /// - /// The text. - /// - public ITextMessage CreateTextMessage(string text) - { - transactionOpen = true; - return target.CreateTextMessage(text); - } - - public async Task CreateTextMessageAsync(string text) - { - transactionOpen = true; - return await target.CreateTextMessageAsync(text).Awaiter(); - } - - /// - /// Creates the map message. - /// - /// - public IMapMessage CreateMapMessage() - { - transactionOpen = true; - return target.CreateMapMessage(); - } - - public async Task CreateMapMessageAsync() - { - transactionOpen = true; - return await target.CreateMapMessageAsync().Awaiter(); - } - - /// - /// Creates the object message. - /// - /// The body. - /// - public IObjectMessage CreateObjectMessage(object body) - { - transactionOpen = true; - return target.CreateObjectMessage(body); - } - - public async Task CreateObjectMessageAsync(object body) - { - transactionOpen = true; - return await target.CreateObjectMessageAsync(body).Awaiter(); - } - - /// - /// Creates the bytes message. - /// - /// - public IBytesMessage CreateBytesMessage() - { - transactionOpen = true; - return target.CreateBytesMessage(); - } - - public async Task CreateBytesMessageAsync() - { - transactionOpen = true; - return await target.CreateBytesMessageAsync().Awaiter(); - } - - /// - /// Creates the bytes message. - /// - /// The body. - /// - public IBytesMessage CreateBytesMessage(byte[] body) - { - transactionOpen = true; - return target.CreateBytesMessage(body); - } - - public async Task CreateBytesMessageAsync(byte[] body) - { - transactionOpen = true; - return await target.CreateBytesMessageAsync(body).Awaiter(); - } - - /// - /// Creates the stream message. - /// - /// - public IStreamMessage CreateStreamMessage() - { - transactionOpen = true; - return target.CreateStreamMessage(); - } - - public async Task CreateStreamMessageAsync() - { - transactionOpen = true; - return await target.CreateStreamMessageAsync().Awaiter(); - } - - public void Acknowledge() - { - transactionOpen = true; - target.Acknowledge(); - } - - public async Task AcknowledgeAsync() - { - transactionOpen = true; - await target.AcknowledgeAsync().Awaiter(); - } - - /// - /// Commits this instance. - /// - public void Commit() - { - transactionOpen = false; - target.Commit(); - } - - public async Task CommitAsync() - { - transactionOpen = false; - await target.CommitAsync().Awaiter(); - } - - /// - /// Stops all Message delivery in this session and restarts it again with the oldest unacknowledged message. Messages that were delivered - /// but not acknowledged should have their redelivered property set. This is an optional method that may not by implemented by all NMS - /// providers, if not implemented an Exception will be thrown. Message redelivery is not requried to be performed in the original - /// order. It is not valid to call this method on a Transacted Session. - /// - public void Recover() - { - transactionOpen = true; - target.Recover(); - } - - public async Task RecoverAsync() - { - transactionOpen = true; - await target.RecoverAsync().Awaiter(); - } - - /// - /// Rollbacks this instance. - /// - public void Rollback() - { - transactionOpen = false; - target.Rollback(); - } - - public async Task RollbackAsync() + private async Task LogicalClose() + { + // Preserve rollback-on-close semantics. + if (transactionOpen && target.Transacted) { transactionOpen = false; await target.RollbackAsync().Awaiter(); } - /// - /// A Delegate that is called each time a Message is dispatched to allow the client to do - /// any necessary transformations on the received message before it is delivered. - /// The Session instance sets the delegate on each Consumer it creates. - /// - /// - public ConsumerTransformerDelegate ConsumerTransformer + // Physically close durable subscribers at time of Session close call. + var toRemove = new List(); + foreach (var dictionaryEntry in cachedConsumers) { - get => target.ConsumerTransformer; - set => target.ConsumerTransformer = value; - } - - /// - /// A delegate that is called each time a Message is sent from this Producer which allows - /// the application to perform any needed transformations on the Message before it is sent. - /// The Session instance sets the delegate on each Producer it creates. - /// - /// - public ProducerTransformerDelegate ProducerTransformer - { - get => target.ProducerTransformer; - set => target.ProducerTransformer = value; - } - /// - /// Gets or sets the request timeout. - /// - /// The request timeout. - public TimeSpan RequestTimeout - { - get => target.RequestTimeout; - set => target.RequestTimeout = value; - } - - /// - /// Gets a value indicating whether this is transacted. - /// - /// true if transacted; otherwise, false. - public bool Transacted - { - get + ConsumerCacheKey key = dictionaryEntry.Key; + if (key.Subscription != null) { - transactionOpen = true; - return target.Transacted; + await dictionaryEntry.Value.CloseAsync().Awaiter(); + toRemove.Add(key); } } - /// - /// Gets the acknowledgement mode. - /// - /// The acknowledgement mode. - public AcknowledgementMode AcknowledgementMode + foreach (ConsumerCacheKey key in toRemove) { - get + cachedConsumers.Remove(key); + } + + // Allow for multiple close calls... + if (!sessionList.Contains(this)) + { + if (Log.IsEnabled(LogLevel.Debug)) { - transactionOpen = true; - return target.AcknowledgementMode; + Log.LogDebug("Returning cached Session: " + target); } - } - /// - /// Occurs, when a transaction is started. - /// - public event SessionTxEventDelegate TransactionStartedListener - { - add => target.TransactionStartedListener += value; - remove => target.TransactionStartedListener -= value; - } - - /// - /// Occurs, when a transaction is commited. - /// - public event SessionTxEventDelegate TransactionCommittedListener - { - add => target.TransactionCommittedListener += value; - remove => target.TransactionCommittedListener -= value; - } - - /// - /// Occurs, when a transaction is rolled back. - /// - public event SessionTxEventDelegate TransactionRolledBackListener - { - add => target.TransactionRolledBackListener += value; - remove => target.TransactionRolledBackListener -= value; - } - - /// - /// Call dispose on the target. - /// - public void Dispose() - { - transactionOpen = true; - target.Dispose(); - } - - public async Task CreateBrowserAsync(IQueue queue) - { - transactionOpen = true; - return await target.CreateBrowserAsync(queue).Awaiter(); - } - - /// - /// Creates the queue browser with a specified selector - /// - /// The queue. - /// The selector. - /// The Queue browser - public IQueueBrowser CreateBrowser(IQueue queue, string selector) - { - transactionOpen = true; - return target.CreateBrowser(queue, selector); - } - - /// - /// Creates the queue browser. - /// - /// The queue. - /// The Queue browser - public IQueueBrowser CreateBrowser(IQueue queue) - { - transactionOpen = true; - return target.CreateBrowser(queue); - } - - /// - /// Returns a that represents the current . - /// - /// - /// A that represents the current . - /// - public override string ToString() - { - return "Cached NMS Session: " + target; + sessionList.Add(this); //add to end of linked list. } } - internal class ConsumerCacheKey + private async Task PhysicalClose() { - private readonly IDestination destination; - private readonly string selector; - private readonly bool noLocal; - private readonly string subscription; - private readonly bool shared; - private readonly bool durable; - - public ConsumerCacheKey(IDestination destination, string selector, bool noLocal, string subscription, bool durable, bool shared) + if (Log.IsEnabled(LogLevel.Debug)) { - this.destination = destination; - this.selector = selector; - this.noLocal = noLocal; - this.subscription = subscription; - this.shared = shared; - this.durable = durable; + Log.LogDebug("Closing cached Session: " + target); } - public string Subscription => subscription; - - protected bool Equals(ConsumerCacheKey consumerCacheKey) + // Explicitly close all MessageProducers and MessageConsumers that + // this Session happens to cache... + try { - if (consumerCacheKey == null) return false; - if (!Equals(destination, consumerCacheKey.destination)) return false; - if (!ObjectUtils.NullSafeEquals(selector, consumerCacheKey.selector)) return false; - if (!Equals(noLocal, consumerCacheKey.noLocal)) return false; - if (!ObjectUtils.NullSafeEquals(subscription, consumerCacheKey.subscription)) return false; - if (shared != consumerCacheKey.shared) return false; - if (durable != consumerCacheKey.durable) return false; - return true; + foreach (var entry in cachedProducers) + { + await entry.Value.CloseAsync().Awaiter(); + } + + foreach (var entry in cachedConsumers) + { + await entry.Value.CloseAsync().Awaiter(); + } + } + finally + { + // Now actually close the Session. + await target.CloseAsync().Awaiter(); + } + } + + /// + /// Creates the consumer, potentially returning a cached instance. + /// + /// The destination. + /// A message consumer + public IMessageConsumer CreateConsumer(IDestination destination) + { + return CreateConsumerInternalAsync(destination, null, false, null, false, false).GetAsyncResult(); + } + + public Task CreateConsumerAsync(IDestination destination) + { + return CreateConsumerInternalAsync(destination, null, false, null, false, false); + } + + /// + /// Creates the consumer, potentially returning a cached instance. + /// + /// The destination. + /// The selector. + /// A message consumer + public IMessageConsumer CreateConsumer(IDestination destination, string selector) + { + return CreateConsumerInternalAsync(destination, selector, false, null, false, false).GetAsyncResult(); + } + + public Task CreateConsumerAsync(IDestination destination, string selector) + { + return CreateConsumerInternalAsync(destination, selector, false, null, false, false); + } + + /// + /// Creates the consumer, potentially returning a cached instance. + /// + /// The destination. + /// The selector. + /// if set to true [no local]. + /// A message consumer. + public IMessageConsumer CreateConsumer(IDestination destination, string selector, bool noLocal) + { + return CreateConsumerInternalAsync(destination, selector, noLocal, null, false, false).GetAsyncResult(); + } + + public Task CreateConsumerAsync(IDestination destination, string selector, bool noLocal) + { + return CreateConsumerInternalAsync(destination, selector, noLocal, null, false, false); + } + + public IMessageConsumer CreateDurableConsumer(ITopic destination, string name) + { + return CreateConsumerInternalAsync(destination, null, false, name, false, true).GetAsyncResult(); + } + + public Task CreateDurableConsumerAsync(ITopic destination, string name) + { + return CreateConsumerInternalAsync(destination, null, false, name, false, true); + } + + public IMessageConsumer CreateDurableConsumer(ITopic destination, string name, string selector) + { + return CreateConsumerInternalAsync(destination, selector, false, name, false, true).GetAsyncResult(); + } + + public Task CreateDurableConsumerAsync(ITopic destination, string name, string selector) + { + return CreateConsumerInternalAsync(destination, selector, false, name, false, true); + } + + /// + /// Creates the durable consumer, potentially returning a cached instance. + /// + /// The destination. + /// The name of the durable subscription. + /// The selector. + /// if set to true [no local]. + /// A message consumer + public IMessageConsumer CreateDurableConsumer(ITopic destination, string subscription, string selector, bool noLocal) + { + return CreateConsumerInternalAsync(destination, selector, noLocal, subscription, false, true).GetAsyncResult(); + } + + public Task CreateDurableConsumerAsync(ITopic destination, string name, string selector, bool noLocal) + { + return CreateConsumerInternalAsync(destination, selector, noLocal, name, false, true); + } + + public IMessageConsumer CreateSharedConsumer(ITopic destination, string name) + { + return CreateConsumerInternalAsync(destination, null, false, name, true, false).GetAsyncResult(); + } + + public Task CreateSharedConsumerAsync(ITopic destination, string name) + { + return CreateConsumerInternalAsync(destination, null, false, name, true, false); + } + + public IMessageConsumer CreateSharedConsumer(ITopic destination, string name, string selector) + { + return CreateConsumerInternalAsync(destination, selector, false, name, true, false).GetAsyncResult(); + } + + public Task CreateSharedConsumerAsync(ITopic destination, string name, string selector) + { + return CreateConsumerInternalAsync(destination, selector, false, name, true, false); + } + + public IMessageConsumer CreateSharedDurableConsumer(ITopic destination, string name) + { + return CreateConsumerInternalAsync(destination, null, false, name, true, true).GetAsyncResult(); + } + + public Task CreateSharedDurableConsumerAsync(ITopic destination, string name) + { + return CreateConsumerInternalAsync(destination, null, false, name, true, true); + } + + public IMessageConsumer CreateSharedDurableConsumer(ITopic destination, string name, string selector) + { + return CreateConsumerInternalAsync(destination, selector, false, name, true, true).GetAsyncResult(); + } + + public Task CreateSharedDurableConsumerAsync(ITopic destination, string name, string selector) + { + return CreateConsumerInternalAsync(destination, selector, false, name, true, true); + } + + /// + /// Deletes the durable consumer. + /// + /// The name of the durable subscription. + public void DeleteDurableConsumer(string durableSubscriptionName) + { + if (shouldCacheConsumers) + { + throw new InvalidOperationException("Deleting of durable consumers is not supported when caching of consumers is enabled"); } - public override bool Equals(object obj) + target.Unsubscribe(durableSubscriptionName); //DeleteDurableConsumer(durableSubscriptionName); + } + + public void Unsubscribe(string name) + { + target.Unsubscribe(name); + } + + public Task UnsubscribeAsync(string name) + { + return target.UnsubscribeAsync(name); + } + + /// + /// Creates the consumer. + /// + /// The destination. + /// The selector. + /// if set to true [no local]. + /// The durable or shared subscription name. + /// + protected async Task CreateConsumerInternalAsync(IDestination destination, string selector, bool noLocal, string subscriptionName, bool shared, bool durable) + { + transactionOpen = true; + if (shouldCacheConsumers) { - if (ReferenceEquals(this, obj)) return true; - return Equals(obj as ConsumerCacheKey); + return await GetCachedConsumerAsync(destination, selector, noLocal, subscriptionName, shared, durable).Awaiter(); + } + else + { + if (shared && durable) + { + return await target.CreateSharedDurableConsumerAsync((ITopic) destination, subscriptionName, selector).Awaiter(); + } + else if (shared) + { + return await target.CreateSharedConsumerAsync((ITopic) destination, subscriptionName, selector).Awaiter(); + } + else if (durable) + { + return await target.CreateDurableConsumerAsync((ITopic) destination, subscriptionName, selector, noLocal).Awaiter(); + } + else + { + return await target.CreateConsumerAsync(destination, selector, noLocal).Awaiter(); + } + } + } + + private async Task GetCachedConsumerAsync(IDestination destination, string selector, bool noLocal, string subscriptionName, bool durable, bool shared) + { + if ((durable || shared) && subscriptionName == null) + { + throw new ArgumentException("Durable or shared subscriptions must have a name"); } - public override int GetHashCode() + var cacheKey = new ConsumerCacheKey(destination, selector, noLocal, subscriptionName, durable, shared); + if (cachedConsumers.TryGetValue(cacheKey, out var consumer)) { - return destination.GetHashCode(); + if (Log.IsEnabled(LogLevel.Debug)) + { + Log.LogDebug("Found cached NMS MessageConsumer for destination [" + destination + "]: " + consumer); + } } + else + { + if (shared && durable) + { + consumer = await target.CreateSharedDurableConsumerAsync((ITopic) destination, subscriptionName, selector).Awaiter(); + } + else if (shared) + { + consumer = await target.CreateSharedConsumerAsync((ITopic) destination, subscriptionName, selector).Awaiter(); + } + else if (durable) + { + consumer = await target.CreateDurableConsumerAsync((ITopic) destination, subscriptionName, selector, noLocal).Awaiter(); + } + else + { + consumer = await target.CreateConsumerAsync(destination, selector, noLocal).Awaiter(); + } + } + + if (Log.IsEnabled(LogLevel.Debug)) + { + Log.LogDebug("Creating cached NMS MessageConsumer for destination [" + destination + "]: " + consumer); + } + + cachedConsumers[cacheKey] = consumer; + + return new CachedMessageConsumer(consumer); + } + + public Task CreateBrowserAsync(IQueue queue, string selector) + { + transactionOpen = true; + return target.CreateBrowserAsync(queue, selector); + } + + /// + /// Gets the queue. + /// + /// The name. + /// + public IQueue GetQueue(string name) + { + return GetQueueAsync(name).GetAsyncResult(); + } + + public async Task GetQueueAsync(string name) + { + transactionOpen = true; + return await target.GetQueueAsync(name).Awaiter(); + } + + /// + /// Gets the topic. + /// + /// The name. + /// + public ITopic GetTopic(string name) + { + return GetTopicAsync(name).GetAsyncResult(); + } + + public async Task GetTopicAsync(string name) + { + transactionOpen = true; + return await target.GetTopicAsync(name).Awaiter(); + } + + /// + /// Creates the temporary queue. + /// + /// + public ITemporaryQueue CreateTemporaryQueue() + { + transactionOpen = true; + return target.CreateTemporaryQueue(); + } + + public async Task CreateTemporaryQueueAsync() + { + transactionOpen = true; + return await target.CreateTemporaryQueueAsync().Awaiter(); + } + + /// + /// Creates the temporary topic. + /// + /// + public ITemporaryTopic CreateTemporaryTopic() + { + transactionOpen = true; + return target.CreateTemporaryTopic(); + } + + public async Task CreateTemporaryTopicAsync() + { + transactionOpen = true; + return await target.CreateTemporaryTopicAsync().Awaiter(); + } + + /// + /// Deletes the destination. + /// + /// The destination. + public void DeleteDestination(IDestination destination) + { + transactionOpen = true; + target.DeleteDestination(destination); + } + + public async Task DeleteDestinationAsync(IDestination destination) + { + transactionOpen = true; + await target.DeleteDestinationAsync(destination).Awaiter(); + } + + /// + /// Creates the message. + /// + /// + public IMessage CreateMessage() + { + transactionOpen = true; + return target.CreateMessage(); + } + + public async Task CreateMessageAsync() + { + transactionOpen = true; + return await target.CreateMessageAsync().Awaiter(); + } + + /// + /// Creates the text message. + /// + /// + public ITextMessage CreateTextMessage() + { + transactionOpen = true; + return target.CreateTextMessage(); + } + + public async Task CreateTextMessageAsync() + { + transactionOpen = true; + return await target.CreateTextMessageAsync().Awaiter(); + } + + /// + /// Creates the text message. + /// + /// The text. + /// + public ITextMessage CreateTextMessage(string text) + { + transactionOpen = true; + return target.CreateTextMessage(text); + } + + public async Task CreateTextMessageAsync(string text) + { + transactionOpen = true; + return await target.CreateTextMessageAsync(text).Awaiter(); + } + + /// + /// Creates the map message. + /// + /// + public IMapMessage CreateMapMessage() + { + transactionOpen = true; + return target.CreateMapMessage(); + } + + public async Task CreateMapMessageAsync() + { + transactionOpen = true; + return await target.CreateMapMessageAsync().Awaiter(); + } + + /// + /// Creates the object message. + /// + /// The body. + /// + public IObjectMessage CreateObjectMessage(object body) + { + transactionOpen = true; + return target.CreateObjectMessage(body); + } + + public async Task CreateObjectMessageAsync(object body) + { + transactionOpen = true; + return await target.CreateObjectMessageAsync(body).Awaiter(); + } + + /// + /// Creates the bytes message. + /// + /// + public IBytesMessage CreateBytesMessage() + { + transactionOpen = true; + return target.CreateBytesMessage(); + } + + public async Task CreateBytesMessageAsync() + { + transactionOpen = true; + return await target.CreateBytesMessageAsync().Awaiter(); + } + + /// + /// Creates the bytes message. + /// + /// The body. + /// + public IBytesMessage CreateBytesMessage(byte[] body) + { + transactionOpen = true; + return target.CreateBytesMessage(body); + } + + public async Task CreateBytesMessageAsync(byte[] body) + { + transactionOpen = true; + return await target.CreateBytesMessageAsync(body).Awaiter(); + } + + /// + /// Creates the stream message. + /// + /// + public IStreamMessage CreateStreamMessage() + { + transactionOpen = true; + return target.CreateStreamMessage(); + } + + public async Task CreateStreamMessageAsync() + { + transactionOpen = true; + return await target.CreateStreamMessageAsync().Awaiter(); + } + + public void Acknowledge() + { + transactionOpen = true; + target.Acknowledge(); + } + + public async Task AcknowledgeAsync() + { + transactionOpen = true; + await target.AcknowledgeAsync().Awaiter(); + } + + /// + /// Commits this instance. + /// + public void Commit() + { + transactionOpen = false; + target.Commit(); + } + + public async Task CommitAsync() + { + transactionOpen = false; + await target.CommitAsync().Awaiter(); + } + + /// + /// Stops all Message delivery in this session and restarts it again with the oldest unacknowledged message. Messages that were delivered + /// but not acknowledged should have their redelivered property set. This is an optional method that may not by implemented by all NMS + /// providers, if not implemented an Exception will be thrown. Message redelivery is not requried to be performed in the original + /// order. It is not valid to call this method on a Transacted Session. + /// + public void Recover() + { + transactionOpen = true; + target.Recover(); + } + + public async Task RecoverAsync() + { + transactionOpen = true; + await target.RecoverAsync().Awaiter(); + } + + /// + /// Rollbacks this instance. + /// + public void Rollback() + { + transactionOpen = false; + target.Rollback(); + } + + public async Task RollbackAsync() + { + transactionOpen = false; + await target.RollbackAsync().Awaiter(); + } + + /// + /// A Delegate that is called each time a Message is dispatched to allow the client to do + /// any necessary transformations on the received message before it is delivered. + /// The Session instance sets the delegate on each Consumer it creates. + /// + /// + public ConsumerTransformerDelegate ConsumerTransformer + { + get => target.ConsumerTransformer; + set => target.ConsumerTransformer = value; + } + + /// + /// A delegate that is called each time a Message is sent from this Producer which allows + /// the application to perform any needed transformations on the Message before it is sent. + /// The Session instance sets the delegate on each Producer it creates. + /// + /// + public ProducerTransformerDelegate ProducerTransformer + { + get => target.ProducerTransformer; + set => target.ProducerTransformer = value; + } + + /// + /// Gets or sets the request timeout. + /// + /// The request timeout. + public TimeSpan RequestTimeout + { + get => target.RequestTimeout; + set => target.RequestTimeout = value; + } + + /// + /// Gets a value indicating whether this is transacted. + /// + /// true if transacted; otherwise, false. + public bool Transacted + { + get + { + transactionOpen = true; + return target.Transacted; + } + } + + /// + /// Gets the acknowledgement mode. + /// + /// The acknowledgement mode. + public AcknowledgementMode AcknowledgementMode + { + get + { + transactionOpen = true; + return target.AcknowledgementMode; + } + } + + /// + /// Occurs, when a transaction is started. + /// + public event SessionTxEventDelegate TransactionStartedListener + { + add => target.TransactionStartedListener += value; + remove => target.TransactionStartedListener -= value; + } + + /// + /// Occurs, when a transaction is commited. + /// + public event SessionTxEventDelegate TransactionCommittedListener + { + add => target.TransactionCommittedListener += value; + remove => target.TransactionCommittedListener -= value; + } + + /// + /// Occurs, when a transaction is rolled back. + /// + public event SessionTxEventDelegate TransactionRolledBackListener + { + add => target.TransactionRolledBackListener += value; + remove => target.TransactionRolledBackListener -= value; + } + + /// + /// Call dispose on the target. + /// + public void Dispose() + { + transactionOpen = true; + target.Dispose(); + } + + public async Task CreateBrowserAsync(IQueue queue) + { + transactionOpen = true; + return await target.CreateBrowserAsync(queue).Awaiter(); + } + + /// + /// Creates the queue browser with a specified selector + /// + /// The queue. + /// The selector. + /// The Queue browser + public IQueueBrowser CreateBrowser(IQueue queue, string selector) + { + transactionOpen = true; + return target.CreateBrowser(queue, selector); + } + + /// + /// Creates the queue browser. + /// + /// The queue. + /// The Queue browser + public IQueueBrowser CreateBrowser(IQueue queue) + { + transactionOpen = true; + return target.CreateBrowser(queue); + } + + /// + /// Returns a that represents the current . + /// + /// + /// A that represents the current . + /// + public override string ToString() + { + return "Cached NMS Session: " + target; + } +} + +internal class ConsumerCacheKey +{ + private readonly IDestination destination; + private readonly string selector; + private readonly bool noLocal; + private readonly string subscription; + private readonly bool shared; + private readonly bool durable; + + public ConsumerCacheKey(IDestination destination, string selector, bool noLocal, string subscription, bool durable, bool shared) + { + this.destination = destination; + this.selector = selector; + this.noLocal = noLocal; + this.subscription = subscription; + this.shared = shared; + this.durable = durable; + } + + public string Subscription => subscription; + + protected bool Equals(ConsumerCacheKey consumerCacheKey) + { + if (consumerCacheKey == null) return false; + if (!Equals(destination, consumerCacheKey.destination)) return false; + if (!ObjectUtils.NullSafeEquals(selector, consumerCacheKey.selector)) return false; + if (!Equals(noLocal, consumerCacheKey.noLocal)) return false; + if (!ObjectUtils.NullSafeEquals(subscription, consumerCacheKey.subscription)) return false; + if (shared != consumerCacheKey.shared) return false; + if (durable != consumerCacheKey.durable) return false; + return true; + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(this, obj)) return true; + return Equals(obj as ConsumerCacheKey); + } + + public override int GetHashCode() + { + return destination.GetHashCode(); } } diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/CachingConnectionFactory.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/CachingConnectionFactory.cs index c717b245..f9de8aed 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/CachingConnectionFactory.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/CachingConnectionFactory.cs @@ -19,235 +19,234 @@ using Microsoft.Extensions.Logging; using Spring.Messaging.Nms.Support; using Spring.Util; -namespace Spring.Messaging.Nms.Connections +namespace Spring.Messaging.Nms.Connections; + +/// +/// subclass that adds +/// Session, MessageProducer, and MessageConsumer caching. This ConnectionFactory +/// also switches the ReconnectOnException property to true +/// by default, allowing for automatic recovery of the underlying +/// Connection. +/// +/// +/// By default, only one single Session will be cached, with further requested +/// Sessions being created and disposed on demand. Consider raising the +/// SessionCacheSize property in case of a high-concurrency environment. +/// +/// NOTE: This ConnectionFactory requires explicit closing of all Sessions +/// obtained from its shared Connection. This is the usual recommendation for +/// native NMS access code anyway. However, with this ConnectionFactory, its use +/// is mandatory in order to actually allow for Session reuse. +/// +/// +/// Note also that MessageConsumers obtained from a cached Session won't get +/// closed until the Session will eventually be removed from the pool. This may +/// lead to semantic side effects in some cases. For a durable subscriber, the +/// logical Session.Close() call will also close the subscription. +/// Re-registering a durable consumer for the same subscription on the same +/// Session handle is not supported; close and reobtain a cached Session first. +/// +/// +/// +/// Juergen Hoeller +/// Mark Pollack (.NET) +public class CachingConnectionFactory : SingleConnectionFactory { + private static readonly ILogger Log = LogManager.GetLogger(); + + private int sessionCacheSize = 1; + + private volatile bool active = true; + + private readonly Dictionary> cachedSessions = + new Dictionary>(); + /// - /// subclass that adds - /// Session, MessageProducer, and MessageConsumer caching. This ConnectionFactory - /// also switches the ReconnectOnException property to true - /// by default, allowing for automatic recovery of the underlying - /// Connection. + /// Initializes a new instance of the class. + /// and sets the ReconnectOnException to true + /// + public CachingConnectionFactory() + { + ReconnectOnException = true; + } + + /// + /// Initializes a new instance of the class for the given + /// IConnectionFactory + /// + /// The target connection factory. + public CachingConnectionFactory(IConnectionFactory targetConnectionFactory) : base(targetConnectionFactory) + { + ReconnectOnException = true; + } + + /// + /// Gets or sets the size of the session cache. /// /// - /// By default, only one single Session will be cached, with further requested - /// Sessions being created and disposed on demand. Consider raising the - /// SessionCacheSize property in case of a high-concurrency environment. + /// This cache size is the maximum limit for the number of cached Sessions + /// per session acknowledgement type (auto, client, dups_ok, transacted). + /// As a consequence, the actual number of cached Sessions may be up to + /// four times as high as the specified value - in the unlikely case + /// of mixing and matching different acknowledgement types. /// - /// NOTE: This ConnectionFactory requires explicit closing of all Sessions - /// obtained from its shared Connection. This is the usual recommendation for - /// native NMS access code anyway. However, with this ConnectionFactory, its use - /// is mandatory in order to actually allow for Session reuse. - /// - /// - /// Note also that MessageConsumers obtained from a cached Session won't get - /// closed until the Session will eventually be removed from the pool. This may - /// lead to semantic side effects in some cases. For a durable subscriber, the - /// logical Session.Close() call will also close the subscription. - /// Re-registering a durable consumer for the same subscription on the same - /// Session handle is not supported; close and reobtain a cached Session first. + /// Default is 1: caching a single Session, (re-)creating further ones on + /// demand. Specify a number like 10 if you'd like to raise the number of cached + /// Sessions; that said, 1 may be sufficient for low-concurrency scenarios. /// /// - /// - /// Juergen Hoeller - /// Mark Pollack (.NET) - public class CachingConnectionFactory : SingleConnectionFactory + /// The size of the session cache. + public int SessionCacheSize { - private static readonly ILogger Log = LogManager.GetLogger(); - - private int sessionCacheSize = 1; - - private volatile bool active = true; - - private readonly Dictionary> cachedSessions = - new Dictionary>(); - - /// - /// Initializes a new instance of the class. - /// and sets the ReconnectOnException to true - /// - public CachingConnectionFactory() + get => sessionCacheSize; + set { - ReconnectOnException = true; + AssertUtils.IsTrue(value >= 1, "Session cache size must be 1 or higher"); + sessionCacheSize = value; } + } - /// - /// Initializes a new instance of the class for the given - /// IConnectionFactory - /// - /// The target connection factory. - public CachingConnectionFactory(IConnectionFactory targetConnectionFactory) : base(targetConnectionFactory) - { - ReconnectOnException = true; - } + /// + /// Gets or sets a value indicating whether to cache MessageProducers per + /// Session instance. (more specifically: one MessageProducer per Destination + /// and Session). + /// + /// + /// Default is "true". Switch this to "false" in order to always, + /// recreate MessageProducers on demand. + /// + /// + /// true if should cache message producers; otherwise, false. + public bool CacheProducers { get; set; } = true; - /// - /// Gets or sets the size of the session cache. - /// - /// - /// This cache size is the maximum limit for the number of cached Sessions - /// per session acknowledgement type (auto, client, dups_ok, transacted). - /// As a consequence, the actual number of cached Sessions may be up to - /// four times as high as the specified value - in the unlikely case - /// of mixing and matching different acknowledgement types. - /// - /// Default is 1: caching a single Session, (re-)creating further ones on - /// demand. Specify a number like 10 if you'd like to raise the number of cached - /// Sessions; that said, 1 may be sufficient for low-concurrency scenarios. - /// - /// - /// The size of the session cache. - public int SessionCacheSize + /// + /// Gets or sets a value indicating whether o cache JMS MessageConsumers per + /// NMS Session instance. + /// + /// + /// Mmore specifically: one MessageConsumer per Destination, selector String + /// and Session. Note that durable subscribers will only be cached until + /// logical closing of the Session handle. + /// + /// Default is "true". Switch this to "false" in order to always + /// recreate MessageConsumers on demand. + /// + /// + /// true to cache consumers per session instance; otherwise, false. + public bool CacheConsumers { get; set; } = true; + + /// + /// Gets or sets a value indicating whether this instance is active. + /// + /// true if this instance is active; otherwise, false. + public bool IsActive + { + get => active; + set => active = value; + } + + /// + /// Resets the Session cache as well as resetting the connection. + /// + public override void ResetConnection() + { + this.active = false; + lock (cachedSessions) { - get => sessionCacheSize; - set + foreach (var pair in cachedSessions) { - AssertUtils.IsTrue(value >= 1, "Session cache size must be 1 or higher"); - sessionCacheSize = value; - } - } - - /// - /// Gets or sets a value indicating whether to cache MessageProducers per - /// Session instance. (more specifically: one MessageProducer per Destination - /// and Session). - /// - /// - /// Default is "true". Switch this to "false" in order to always, - /// recreate MessageProducers on demand. - /// - /// - /// true if should cache message producers; otherwise, false. - public bool CacheProducers { get; set; } = true; - - /// - /// Gets or sets a value indicating whether o cache JMS MessageConsumers per - /// NMS Session instance. - /// - /// - /// Mmore specifically: one MessageConsumer per Destination, selector String - /// and Session. Note that durable subscribers will only be cached until - /// logical closing of the Session handle. - /// - /// Default is "true". Switch this to "false" in order to always - /// recreate MessageConsumers on demand. - /// - /// - /// true to cache consumers per session instance; otherwise, false. - public bool CacheConsumers { get; set; } = true; - - /// - /// Gets or sets a value indicating whether this instance is active. - /// - /// true if this instance is active; otherwise, false. - public bool IsActive - { - get => active; - set => active = value; - } - - /// - /// Resets the Session cache as well as resetting the connection. - /// - public override void ResetConnection() - { - this.active = false; - lock (cachedSessions) - { - foreach (var pair in cachedSessions) + var sessionList = pair.Value; + lock (sessionList) { - var sessionList = pair.Value; - lock (sessionList) + foreach (ISession session in sessionList) { - foreach (ISession session in sessionList) + try { - try - { - session.Close(); - } - catch (Exception ex) - { - Log.LogTrace(ex, "Could not close cached NMS Session"); - } + session.Close(); + } + catch (Exception ex) + { + Log.LogTrace(ex, "Could not close cached NMS Session"); } } } - - cachedSessions.Clear(); } - this.active = true; - // Now proceed with actual closing of the shared Connection... - base.ResetConnection(); + cachedSessions.Clear(); } - /// - /// Obtaining a cached Session. - /// - /// The connection to operate on. - /// The session ack mode. - /// The Session to use - /// - public override ISession GetSession(IConnection con, AcknowledgementMode mode) + this.active = true; + // Now proceed with actual closing of the shared Connection... + base.ResetConnection(); + } + + /// + /// Obtaining a cached Session. + /// + /// The connection to operate on. + /// The session ack mode. + /// The Session to use + /// + public override ISession GetSession(IConnection con, AcknowledgementMode mode) + { + return GetSessionAsync(con, mode).GetAsyncResult(); + } + + public override async Task GetSessionAsync(IConnection con, AcknowledgementMode mode) + { + List sessionList; + lock (cachedSessions) { - return GetSessionAsync(con, mode).GetAsyncResult(); + if (!cachedSessions.TryGetValue(mode, out sessionList)) + { + sessionList = new List(); + cachedSessions[mode] = sessionList; + } } - - public override async Task GetSessionAsync(IConnection con, AcknowledgementMode mode) + + ISession session = null; + lock (sessionList) { - List sessionList; - lock (cachedSessions) + if (sessionList.Count > 0) { - if (!cachedSessions.TryGetValue(mode, out sessionList)) - { - sessionList = new List(); - cachedSessions[mode] = sessionList; - } + session = sessionList[0]; + sessionList.RemoveAt(0); } - - ISession session = null; - lock (sessionList) - { - if (sessionList.Count > 0) - { - session = sessionList[0]; - sessionList.RemoveAt(0); - } - } - - if (session != null) - { - if (Log.IsEnabled(LogLevel.Debug)) - { - string message = "Found cached Session for mode " + mode + ": " - + (session is IDecoratorSession decoratorSession ? decoratorSession.TargetSession : session); - Log.LogDebug(message); - } - } - else - { - ISession targetSession = await con.CreateSessionAsync(mode).Awaiter(); - if (Log.IsEnabled(LogLevel.Debug)) - { - Log.LogDebug("Creating cached Session for mode " + mode + ": " + targetSession); - } - - session = GetCachedSessionWrapper(targetSession, sessionList); - } - - return session; } - /// - /// Wraps the given Session so that it delegates every method call to the target session but - /// adapts close calls. This is useful for allowing application code to - /// handle a special framework Session just like an ordinary Session. - /// - /// The original Session to wrap. - /// The List of cached Sessions that the given Session belongs to. - /// The wrapped Session - protected virtual ISession GetCachedSessionWrapper(ISession targetSession, List sessionList) + if (session != null) { - return new CachedSession(targetSession, sessionList, this); + if (Log.IsEnabled(LogLevel.Debug)) + { + string message = "Found cached Session for mode " + mode + ": " + + (session is IDecoratorSession decoratorSession ? decoratorSession.TargetSession : session); + Log.LogDebug(message); + } } + else + { + ISession targetSession = await con.CreateSessionAsync(mode).Awaiter(); + if (Log.IsEnabled(LogLevel.Debug)) + { + Log.LogDebug("Creating cached Session for mode " + mode + ": " + targetSession); + } + + session = GetCachedSessionWrapper(targetSession, sessionList); + } + + return session; + } + + /// + /// Wraps the given Session so that it delegates every method call to the target session but + /// adapts close calls. This is useful for allowing application code to + /// handle a special framework Session just like an ordinary Session. + /// + /// The original Session to wrap. + /// The List of cached Sessions that the given Session belongs to. + /// The wrapped Session + protected virtual ISession GetCachedSessionWrapper(ISession targetSession, List sessionList) + { + return new CachedSession(targetSession, sessionList, this); } } diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/ChainedExceptionListener.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/ChainedExceptionListener.cs index eb1d598e..7dc82a4f 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/ChainedExceptionListener.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/ChainedExceptionListener.cs @@ -21,47 +21,46 @@ using Spring.Messaging.Nms.Core; using Spring.Util; -namespace Spring.Messaging.Nms.Connections +namespace Spring.Messaging.Nms.Connections; + +/// +/// Implementation of Spring IExceptionListener interface that supports +/// chaining allowing the addition of multiple ExceptionListener instances in order. +/// +/// Juergen Hoeller +/// Mark Pollack (.NET) +public class ChainedExceptionListener : IExceptionListener { + private List listeners = new List(2); + /// - /// Implementation of Spring IExceptionListener interface that supports - /// chaining allowing the addition of multiple ExceptionListener instances in order. + /// Adds the exception listener to the chain /// - /// Juergen Hoeller - /// Mark Pollack (.NET) - public class ChainedExceptionListener : IExceptionListener + /// The listener. + public void AddListener(IExceptionListener listener) { - private List listeners = new List(2); + AssertUtils.ArgumentNotNull(listener, "listener", "ExceptionListener must not be null"); + listeners.Add(listener); + } - /// - /// Adds the exception listener to the chain - /// - /// The listener. - public void AddListener(IExceptionListener listener) + /// + /// Called when an exception occurs in message processing. + /// + /// The exception. + public void OnException(Exception exception) + { + foreach (IExceptionListener listener in listeners) { - AssertUtils.ArgumentNotNull(listener, "listener", "ExceptionListener must not be null"); - listeners.Add(listener); - } - - /// - /// Called when an exception occurs in message processing. - /// - /// The exception. - public void OnException(Exception exception) - { - foreach (IExceptionListener listener in listeners) - { - listener.OnException(exception); - } - } - - /// - /// Gets the exception listeners as an array. - /// - /// The exception listeners. - public IList Listeners - { - get { return listeners; } + listener.OnException(exception); } } + + /// + /// Gets the exception listeners as an array. + /// + /// The exception listeners. + public IList Listeners + { + get { return listeners; } + } } diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/ConnectionFactoryUtils.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/ConnectionFactoryUtils.cs index 1463e0bf..3176745c 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/ConnectionFactoryUtils.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/ConnectionFactoryUtils.cs @@ -24,467 +24,477 @@ using Spring.Messaging.Nms.Support; using Spring.Transaction.Support; using Spring.Util; -namespace Spring.Messaging.Nms.Connections +namespace Spring.Messaging.Nms.Connections; + +/// Helper class for obtaining transactional NMS resources +/// for a given ConnectionFactory. +/// +/// Juergen Hoeller +/// Mark Pollack (.NET) +public abstract class ConnectionFactoryUtils { - /// Helper class for obtaining transactional NMS resources - /// for a given ConnectionFactory. + #region Logging + + private static readonly ILogger LOG = LogManager.GetLogger(); + + #endregion + + /// + /// Releases the given connection, stopping it (if necessary) and eventually closing it. /// - /// Juergen Hoeller - /// Mark Pollack (.NET) - public abstract class ConnectionFactoryUtils + /// Checks , if available. + /// This is essentially a more sophisticated version of + /// + /// + /// The connection to release. (if this is null, the call will be ignored) + /// The ConnectionFactory that the Connection was obtained from. (may be null) + /// whether the Connection might have been started by the application. + public static void ReleaseConnection(IConnection connection, IConnectionFactory cf, bool started) { - #region Logging - - private static readonly ILogger LOG = LogManager.GetLogger(); - - #endregion - - /// - /// Releases the given connection, stopping it (if necessary) and eventually closing it. - /// - /// Checks , if available. - /// This is essentially a more sophisticated version of - /// - /// - /// The connection to release. (if this is null, the call will be ignored) - /// The ConnectionFactory that the Connection was obtained from. (may be null) - /// whether the Connection might have been started by the application. - public static void ReleaseConnection(IConnection connection, IConnectionFactory cf, bool started) + if (connection == null) { - if (connection == null) - { - return; - } + return; + } - if (started && cf is ISmartConnectionFactory && ((ISmartConnectionFactory)cf).ShouldStop(connection)) - { - try - { - connection.Stop(); - } - catch (Exception ex) - { - LOG.LogDebug(ex, "Could not stop NMS Connection before closing it"); - - } - } + if (started && cf is ISmartConnectionFactory && ((ISmartConnectionFactory) cf).ShouldStop(connection)) + { try { - connection.Close(); - } catch (Exception ex) + connection.Stop(); + } + catch (Exception ex) { - LOG.LogDebug(ex, "Could not close NMS Connection"); - } - } - - /// - /// Releases the given connection, stopping it (if necessary) and eventually closing it. - /// - /// Checks , if available. - /// This is essentially a more sophisticated version of - /// - /// - /// The connection to release. (if this is null, the call will be ignored) - /// The ConnectionFactory that the Connection was obtained from. (may be null) - /// whether the Connection might have been started by the application. - public static async Task ReleaseConnectionAsync(IConnection connection, IConnectionFactory cf, bool started) + LOG.LogDebug(ex, "Could not stop NMS Connection before closing it"); + } + } + + try { - if (connection == null) - { - return; - } + connection.Close(); + } + catch (Exception ex) + { + LOG.LogDebug(ex, "Could not close NMS Connection"); + } + } - if (started && cf is ISmartConnectionFactory && ((ISmartConnectionFactory)cf).ShouldStop(connection)) - { - try - { - await connection.StopAsync().Awaiter(); - } - catch (Exception ex) - { - LOG.LogDebug(ex, "Could not stop NMS Connection before closing it"); + /// + /// Releases the given connection, stopping it (if necessary) and eventually closing it. + /// + /// Checks , if available. + /// This is essentially a more sophisticated version of + /// + /// + /// The connection to release. (if this is null, the call will be ignored) + /// The ConnectionFactory that the Connection was obtained from. (may be null) + /// whether the Connection might have been started by the application. + public static async Task ReleaseConnectionAsync(IConnection connection, IConnectionFactory cf, bool started) + { + if (connection == null) + { + return; + } - } - } + if (started && cf is ISmartConnectionFactory && ((ISmartConnectionFactory) cf).ShouldStop(connection)) + { try { - await connection.CloseAsync().Awaiter(); - } catch (Exception ex) + await connection.StopAsync().Awaiter(); + } + catch (Exception ex) { - LOG.LogDebug(ex, "Could not close NMS Connection"); - } + LOG.LogDebug(ex, "Could not stop NMS Connection before closing it"); + } } - /// - /// Return the innermost target Session of the given Session. If the given - /// Session is a decorated session, it will be unwrapped until a non-decorated - /// Session is found. Otherwise, the passed-in Session will be returned as-is. - /// - /// The session to unwrap - /// The innermost target Session, or the passed-in one if no decorator - public static ISession GetTargetSession(ISession session) + try { - ISession sessionToUse = session; - while (sessionToUse is IDecoratorSession) - { - sessionToUse = ((IDecoratorSession) sessionToUse).TargetSession; - } - return sessionToUse; + await connection.CloseAsync().Awaiter(); + } + catch (Exception ex) + { + LOG.LogDebug(ex, "Could not close NMS Connection"); + } + } + + /// + /// Return the innermost target Session of the given Session. If the given + /// Session is a decorated session, it will be unwrapped until a non-decorated + /// Session is found. Otherwise, the passed-in Session will be returned as-is. + /// + /// The session to unwrap + /// The innermost target Session, or the passed-in one if no decorator + public static ISession GetTargetSession(ISession session) + { + ISession sessionToUse = session; + while (sessionToUse is IDecoratorSession) + { + sessionToUse = ((IDecoratorSession) sessionToUse).TargetSession; } - /// - /// Determines whether the given JMS Session is transactional, that is, - /// bound to the current thread by Spring's transaction facilities. - /// - /// The session to check. - /// The ConnectionFactory that the Session originated from - /// - /// true if is session transactional, bound to current thread; otherwise, false. - /// - public static bool IsSessionTransactional(ISession session, IConnectionFactory cf) + return sessionToUse; + } + + /// + /// Determines whether the given JMS Session is transactional, that is, + /// bound to the current thread by Spring's transaction facilities. + /// + /// The session to check. + /// The ConnectionFactory that the Session originated from + /// + /// true if is session transactional, bound to current thread; otherwise, false. + /// + public static bool IsSessionTransactional(ISession session, IConnectionFactory cf) + { + if (session == null || cf == null) { - if (session == null || cf == null) - { - return false; - } - NmsResourceHolder resourceHolder = (NmsResourceHolder) TransactionSynchronizationManager.GetResource(cf); - return (resourceHolder != null && resourceHolder.ContainsSession(session)); + return false; } - /// Obtain a NMS Session that is synchronized with the current transaction, if any. - /// the ConnectionFactory to obtain a Session for - /// - /// the existing NMS Connection to obtain a Session for - /// (may be null) - /// - /// whether to allow for a local NMS transaction - /// that is synchronized with a Spring-managed transaction (where the main transaction - /// might be a ADO.NET-based one for a specific DataSource, for example), with the NMS - /// transaction committing right after the main transaction. If not allowed, the given - /// ConnectionFactory needs to handle transaction enlistment underneath the covers. - /// - /// the transactional Session, or null if none found - /// - /// NMSException in case of NMS failure - public static ISession GetTransactionalSession(IConnectionFactory cf, IConnection existingCon, - bool synchedLocalTransactionAllowed) + NmsResourceHolder resourceHolder = (NmsResourceHolder) TransactionSynchronizationManager.GetResource(cf); + return (resourceHolder != null && resourceHolder.ContainsSession(session)); + } + + /// Obtain a NMS Session that is synchronized with the current transaction, if any. + /// the ConnectionFactory to obtain a Session for + /// + /// the existing NMS Connection to obtain a Session for + /// (may be null) + /// + /// whether to allow for a local NMS transaction + /// that is synchronized with a Spring-managed transaction (where the main transaction + /// might be a ADO.NET-based one for a specific DataSource, for example), with the NMS + /// transaction committing right after the main transaction. If not allowed, the given + /// ConnectionFactory needs to handle transaction enlistment underneath the covers. + /// + /// the transactional Session, or null if none found + /// + /// NMSException in case of NMS failure + public static ISession GetTransactionalSession(IConnectionFactory cf, IConnection existingCon, + bool synchedLocalTransactionAllowed) + { + return + DoGetTransactionalSession(cf, + new AnonymousClassResourceFactory(existingCon, cf, + synchedLocalTransactionAllowed), true, true).GetAsyncResult(); + } + + /// + /// Obtain a NMS Session that is synchronized with the current transaction, if any. + /// + /// the TransactionSynchronizationManager key to bind to + /// (usually the ConnectionFactory) + /// the ResourceFactory to use for extracting or creating + /// NMS resources + /// whether the underlying Connection approach should be + /// started in order to allow for receiving messages. Note that a reused Connection + /// may already have been started before, even if this flag is false. + /// + /// the transactional Session, or null if none found + /// + /// NMSException in case of NMS failure + public static async Task DoGetTransactionalSession(Object resourceKey, ResourceFactory resourceFactory, bool startConnection, bool sync = false) + { + AssertUtils.ArgumentNotNull(resourceKey, "Resource key must not be null"); + AssertUtils.ArgumentNotNull(resourceKey, "ResourceFactory must not be null"); + + NmsResourceHolder resourceHolder = + (NmsResourceHolder) TransactionSynchronizationManager.GetResource(resourceKey); + if (resourceHolder != null) { - return - DoGetTransactionalSession(cf, - new AnonymousClassResourceFactory(existingCon, cf, - synchedLocalTransactionAllowed), true, true).GetAsyncResult(); - } - - /// - /// Obtain a NMS Session that is synchronized with the current transaction, if any. - /// - /// the TransactionSynchronizationManager key to bind to - /// (usually the ConnectionFactory) - /// the ResourceFactory to use for extracting or creating - /// NMS resources - /// whether the underlying Connection approach should be - /// started in order to allow for receiving messages. Note that a reused Connection - /// may already have been started before, even if this flag is false. - /// - /// the transactional Session, or null if none found - /// - /// NMSException in case of NMS failure - public static async Task DoGetTransactionalSession(Object resourceKey, ResourceFactory resourceFactory, bool startConnection, bool sync = false) - { - AssertUtils.ArgumentNotNull(resourceKey, "Resource key must not be null"); - AssertUtils.ArgumentNotNull(resourceKey, "ResourceFactory must not be null"); - - NmsResourceHolder resourceHolder = - (NmsResourceHolder)TransactionSynchronizationManager.GetResource(resourceKey); - if (resourceHolder != null) + ISession rhSession = resourceFactory.GetSession(resourceHolder); + if (rhSession != null) { - ISession rhSession = resourceFactory.GetSession(resourceHolder); - if (rhSession != null) - { - if (startConnection) - { - IConnection conn = resourceFactory.GetConnection(resourceHolder); - if (conn != null) - { - if(sync) conn.Start(); - else await conn.StartAsync().Awaiter(); - } - } - return rhSession; - } - } - if (!TransactionSynchronizationManager.SynchronizationActive) - { - return null; - } - NmsResourceHolder resourceHolderToUse = resourceHolder; - if (resourceHolderToUse == null) - { - resourceHolderToUse = new NmsResourceHolder(); - } - - IConnection con = resourceFactory.GetConnection(resourceHolderToUse); - ISession session = null; - try - { - bool isExistingCon = (con != null); - if (!isExistingCon) - { - con = await resourceFactory.CreateConnectionAsync().Awaiter(); - resourceHolderToUse.AddConnection(con); - } - session = await resourceFactory.CreateSessionAsync(con).Awaiter(); - resourceHolderToUse.AddSession(session, con); if (startConnection) { - if (sync) con.Start(); - else await con.StartAsync().Awaiter(); - } - } - catch (NMSException) - { - if (session != null) - { - try + IConnection conn = resourceFactory.GetConnection(resourceHolder); + if (conn != null) { - if (sync) session.Close(); - else await session.CloseAsync().Awaiter(); - } - catch (Exception) - { - // ignore + if (sync) conn.Start(); + else await conn.StartAsync().Awaiter(); } } - if (con != null) - { - try - { - if (sync) con.Close(); - else await con.CloseAsync().Awaiter(); - } - catch (Exception) - { - // ignore - } - } - throw; + + return rhSession; } - if (resourceHolderToUse != resourceHolder) - { - TransactionSynchronizationManager.RegisterSynchronization( - new NmsResourceSynchronization(resourceHolderToUse, resourceKey, - resourceFactory.SynchedLocalTransactionAllowed)); - resourceHolderToUse.SynchronizedWithTransaction = true; - TransactionSynchronizationManager.BindResource(resourceKey, resourceHolderToUse); - } - return session; } - #region ResourceFactory helper classes - - private class AnonymousClassResourceFactory : ResourceFactory + if (!TransactionSynchronizationManager.SynchronizationActive) { - private IConnection existingCon; - private IConnectionFactory cf; - private bool synchedLocalTransactionAllowed; + return null; + } - public AnonymousClassResourceFactory(IConnection existingCon, IConnectionFactory cf, - bool synchedLocalTransactionAllowed) + NmsResourceHolder resourceHolderToUse = resourceHolder; + if (resourceHolderToUse == null) + { + resourceHolderToUse = new NmsResourceHolder(); + } + + IConnection con = resourceFactory.GetConnection(resourceHolderToUse); + ISession session = null; + try + { + bool isExistingCon = (con != null); + if (!isExistingCon) { - InitBlock(existingCon, cf, synchedLocalTransactionAllowed); + con = await resourceFactory.CreateConnectionAsync().Awaiter(); + resourceHolderToUse.AddConnection(con); } - private void InitBlock(IConnection existingCon, IConnectionFactory cf, bool synchedLocalTransactionAllowed) + session = await resourceFactory.CreateSessionAsync(con).Awaiter(); + resourceHolderToUse.AddSession(session, con); + if (startConnection) { - this.existingCon = existingCon; - this.cf = cf; - this.synchedLocalTransactionAllowed = synchedLocalTransactionAllowed; + if (sync) con.Start(); + else await con.StartAsync().Awaiter(); } - - public virtual ISession GetSession(NmsResourceHolder holder) + } + catch (NMSException) + { + if (session != null) { - return holder.GetSession(typeof(ISession), existingCon); - } - - public virtual IConnection GetConnection(NmsResourceHolder holder) - { - return (existingCon != null ? existingCon : holder.GetConnection()); - } - - public virtual IConnection CreateConnection() - { - return cf.CreateConnection(); - } - - public virtual ISession CreateSession(IConnection con) - { - if (synchedLocalTransactionAllowed) + try { - return con.CreateSession(AcknowledgementMode.Transactional); + if (sync) session.Close(); + else await session.CloseAsync().Awaiter(); } - else + catch (Exception) { - return con.CreateSession(AcknowledgementMode.AutoAcknowledge); + // ignore } } - public Task CreateConnectionAsync() + if (con != null) { - return cf.CreateConnectionAsync(); - } - - public async Task CreateSessionAsync(IConnection con) - { - if (synchedLocalTransactionAllowed) + try { - return await con.CreateSessionAsync(AcknowledgementMode.Transactional).Awaiter(); + if (sync) con.Close(); + else await con.CloseAsync().Awaiter(); } - else + catch (Exception) { - return await con.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge).Awaiter(); + // ignore } } - public bool SynchedLocalTransactionAllowed + throw; + } + + if (resourceHolderToUse != resourceHolder) + { + TransactionSynchronizationManager.RegisterSynchronization( + new NmsResourceSynchronization(resourceHolderToUse, resourceKey, + resourceFactory.SynchedLocalTransactionAllowed)); + resourceHolderToUse.SynchronizedWithTransaction = true; + TransactionSynchronizationManager.BindResource(resourceKey, resourceHolderToUse); + } + + return session; + } + + #region ResourceFactory helper classes + + private class AnonymousClassResourceFactory : ResourceFactory + { + private IConnection existingCon; + private IConnectionFactory cf; + private bool synchedLocalTransactionAllowed; + + public AnonymousClassResourceFactory(IConnection existingCon, IConnectionFactory cf, + bool synchedLocalTransactionAllowed) + { + InitBlock(existingCon, cf, synchedLocalTransactionAllowed); + } + + private void InitBlock(IConnection existingCon, IConnectionFactory cf, bool synchedLocalTransactionAllowed) + { + this.existingCon = existingCon; + this.cf = cf; + this.synchedLocalTransactionAllowed = synchedLocalTransactionAllowed; + } + + public virtual ISession GetSession(NmsResourceHolder holder) + { + return holder.GetSession(typeof(ISession), existingCon); + } + + public virtual IConnection GetConnection(NmsResourceHolder holder) + { + return (existingCon != null ? existingCon : holder.GetConnection()); + } + + public virtual IConnection CreateConnection() + { + return cf.CreateConnection(); + } + + public virtual ISession CreateSession(IConnection con) + { + if (synchedLocalTransactionAllowed) { - get { return synchedLocalTransactionAllowed; } + return con.CreateSession(AcknowledgementMode.Transactional); + } + else + { + return con.CreateSession(AcknowledgementMode.AutoAcknowledge); } } - #endregion + public Task CreateConnectionAsync() + { + return cf.CreateConnectionAsync(); + } - #region Helper classes/interfaces + public async Task CreateSessionAsync(IConnection con) + { + if (synchedLocalTransactionAllowed) + { + return await con.CreateSessionAsync(AcknowledgementMode.Transactional).Awaiter(); + } + else + { + return await con.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge).Awaiter(); + } + } - /// Callback interface for resource creation. - /// Serving as argument for the DoGetTransactionalSession method. + public bool SynchedLocalTransactionAllowed + { + get { return synchedLocalTransactionAllowed; } + } + } + + #endregion + + #region Helper classes/interfaces + + /// Callback interface for resource creation. + /// Serving as argument for the DoGetTransactionalSession method. + /// + public interface ResourceFactory + { + /// Fetch an appropriate Session from the given MessageResourceHolder. + /// the MessageResourceHolder + /// + /// an appropriate Session fetched from the holder, + /// or null if none found + /// + ISession GetSession(NmsResourceHolder holder); + + /// Fetch an appropriate Connection from the given MessageResourceHolder. + /// the MessageResourceHolder + /// + /// an appropriate Connection fetched from the holder, + /// or null if none found + /// + IConnection GetConnection(NmsResourceHolder holder); + + /// Create a new NMS Connection for registration with a MessageResourceHolder. + /// the new NMS Connection + /// + /// NMSException if thrown by NMS API methods + IConnection CreateConnection(); + + /// Create a new NMS ISession for registration with a MessageResourceHolder. + /// the NMS Connection to create a ISession for + /// + /// the new NMS Session + /// + /// NMSException if thrown by NMS API methods + ISession CreateSession(IConnection con); + + /// Create a new NMS Connection for registration with a MessageResourceHolder. + /// the new NMS Connection + /// + /// NMSException if thrown by NMS API methods + Task CreateConnectionAsync(); + + /// Create a new NMS ISession for registration with a MessageResourceHolder. + /// the NMS Connection to create a ISession for + /// + /// the new NMS Session + /// + /// NMSException if thrown by NMS API methods + Task CreateSessionAsync(IConnection con); + + /// + /// Return whether to allow for a local NMS transaction that is synchronized with + /// a Spring-managed transaction (where the main transaction might be a ADO.NET-based + /// one for a specific IDbProvider, for example), with the NMS transaction + /// committing right after the main transaction. + /// Returns whether to allow for synchronizing a local NMS transaction /// - public interface ResourceFactory + /// + bool SynchedLocalTransactionAllowed { get; } + } + + /// Callback for resource cleanup at the end of a non-native NMS transaction + /// + private class NmsResourceSynchronization : TransactionSynchronizationAdapter + { + private object resourceKey; + + private NmsResourceHolder resourceHolder; + + private bool transacted; + + private bool holderActive = true; + + public NmsResourceSynchronization(NmsResourceHolder resourceHolder, object resourceKey, bool transacted) { - /// Fetch an appropriate Session from the given MessageResourceHolder. - /// the MessageResourceHolder - /// - /// an appropriate Session fetched from the holder, - /// or null if none found - /// - ISession GetSession(NmsResourceHolder holder); - - /// Fetch an appropriate Connection from the given MessageResourceHolder. - /// the MessageResourceHolder - /// - /// an appropriate Connection fetched from the holder, - /// or null if none found - /// - IConnection GetConnection(NmsResourceHolder holder); - - /// Create a new NMS Connection for registration with a MessageResourceHolder. - /// the new NMS Connection - /// - /// NMSException if thrown by NMS API methods - IConnection CreateConnection(); - - /// Create a new NMS ISession for registration with a MessageResourceHolder. - /// the NMS Connection to create a ISession for - /// - /// the new NMS Session - /// - /// NMSException if thrown by NMS API methods - ISession CreateSession(IConnection con); - - /// Create a new NMS Connection for registration with a MessageResourceHolder. - /// the new NMS Connection - /// - /// NMSException if thrown by NMS API methods - Task CreateConnectionAsync(); - - /// Create a new NMS ISession for registration with a MessageResourceHolder. - /// the NMS Connection to create a ISession for - /// - /// the new NMS Session - /// - /// NMSException if thrown by NMS API methods - Task CreateSessionAsync(IConnection con); - - - /// - /// Return whether to allow for a local NMS transaction that is synchronized with - /// a Spring-managed transaction (where the main transaction might be a ADO.NET-based - /// one for a specific IDbProvider, for example), with the NMS transaction - /// committing right after the main transaction. - /// Returns whether to allow for synchronizing a local NMS transaction - /// - /// - bool SynchedLocalTransactionAllowed { get; } + this.resourceKey = resourceKey; + this.resourceHolder = resourceHolder; + this.transacted = transacted; } - /// Callback for resource cleanup at the end of a non-native NMS transaction - /// - private class NmsResourceSynchronization : TransactionSynchronizationAdapter + public override void Suspend() { - private object resourceKey; - - private NmsResourceHolder resourceHolder; - - private bool transacted; - - private bool holderActive = true; - - public NmsResourceSynchronization(NmsResourceHolder resourceHolder, object resourceKey, bool transacted) - { - this.resourceKey = resourceKey; - this.resourceHolder = resourceHolder; - this.transacted = transacted; - } - - public override void Suspend() - { - if (holderActive) - { - TransactionSynchronizationManager.UnbindResource(resourceKey); - } - } - - public override void Resume() - { - if (holderActive) - { - TransactionSynchronizationManager.BindResource(resourceKey, resourceHolder); - } - } - - public override void BeforeCompletion() + if (holderActive) { TransactionSynchronizationManager.UnbindResource(resourceKey); - holderActive = false; - if (!transacted) - { - resourceHolder.CloseAll(); - } } + } - public override void AfterCommit() + public override void Resume() + { + if (holderActive) { - if (transacted) - { - try - { - resourceHolder.CommitAll(); - } - catch (NMSException ex) - { - throw new SynchedLocalTransactionFailedException("Local NMS transaction failed to commit", ex); - } - } + TransactionSynchronizationManager.BindResource(resourceKey, resourceHolder); } + } - public override void AfterCompletion(TransactionSynchronizationStatus status) + public override void BeforeCompletion() + { + TransactionSynchronizationManager.UnbindResource(resourceKey); + holderActive = false; + if (!transacted) { - if (transacted) + resourceHolder.CloseAll(); + } + } + + public override void AfterCommit() + { + if (transacted) + { + try { - resourceHolder.CloseAll(); + resourceHolder.CommitAll(); + } + catch (NMSException ex) + { + throw new SynchedLocalTransactionFailedException("Local NMS transaction failed to commit", ex); } } } - #endregion + public override void AfterCompletion(TransactionSynchronizationStatus status) + { + if (transacted) + { + resourceHolder.CloseAll(); + } + } } + + #endregion } diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/IDecoratorSession.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/IDecoratorSession.cs index 41fd3aef..db422bd8 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/IDecoratorSession.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/IDecoratorSession.cs @@ -20,23 +20,22 @@ using Apache.NMS; -namespace Spring.Messaging.Nms.Connections +namespace Spring.Messaging.Nms.Connections; + +/// +/// Subinterface of Session to be implemented by +/// implementations that wrap an Session to provide added +/// functionality. Allows access to the the underlying target Session. +/// +/// Mark Pollack +/// +/// +public interface IDecoratorSession : ISession { /// - /// Subinterface of Session to be implemented by - /// implementations that wrap an Session to provide added - /// functionality. Allows access to the the underlying target Session. + /// Gets the target session of the decorator. + /// This will typically be the native provider Session or a wrapper from a session pool. /// - /// Mark Pollack - /// - /// - public interface IDecoratorSession : ISession - { - /// - /// Gets the target session of the decorator. - /// This will typically be the native provider Session or a wrapper from a session pool. - /// - /// The underlying session, never null - ISession TargetSession { get; } - } -} \ No newline at end of file + /// The underlying session, never null + ISession TargetSession { get; } +} diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/ISmartConnectionFactory.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/ISmartConnectionFactory.cs index 075eb0ca..bbce67b8 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/ISmartConnectionFactory.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/ISmartConnectionFactory.cs @@ -1,5 +1,3 @@ - - #region License /* @@ -22,21 +20,20 @@ using Apache.NMS; -namespace Spring.Messaging.Nms.Connections +namespace Spring.Messaging.Nms.Connections; + +/// +/// Extension of the ConnectionFactory interface, +/// indicating how to release Connections obtained from it. +/// +/// Juergen Hoeller +/// Mark Pollack (.NET) +public interface ISmartConnectionFactory { /// - /// Extension of the ConnectionFactory interface, - /// indicating how to release Connections obtained from it. + /// Shoulds we stop the connection, obtained from this ConnectionFactory? /// - /// Juergen Hoeller - /// Mark Pollack (.NET) - public interface ISmartConnectionFactory - { - /// - /// Shoulds we stop the connection, obtained from this ConnectionFactory? - /// - /// The connection to check. - /// wheter a stop call is necessary - bool ShouldStop(IConnection con); - } -} \ No newline at end of file + /// The connection to check. + /// wheter a stop call is necessary + bool ShouldStop(IConnection con); +} diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/NmsConsumer.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/NmsConsumer.cs index a085b407..40254bb0 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/NmsConsumer.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/NmsConsumer.cs @@ -1,4 +1,5 @@ #region License + // /* // * Copyright 2022 the original author or authors. // * @@ -14,112 +15,112 @@ // * See the License for the specific language governing permissions and // * limitations under the License. // */ + #endregion using Apache.NMS; using Spring.Messaging.Nms.Support; -namespace Spring.Messaging.Nms.Connections +namespace Spring.Messaging.Nms.Connections; + +public class NmsConsumer : INMSConsumer { - public class NmsConsumer : INMSConsumer + private readonly IMessageConsumer consumer; + + public NmsConsumer(IMessageConsumer consumer) { - private readonly IMessageConsumer consumer; + this.consumer = consumer; + } - public NmsConsumer(IMessageConsumer consumer) - { - this.consumer = consumer; - } - - public void Dispose() - { - consumer.Dispose(); - } + public void Dispose() + { + consumer.Dispose(); + } - public IMessage Receive() - { - return consumer.Receive(); - } + public IMessage Receive() + { + return consumer.Receive(); + } - public Task ReceiveAsync() - { - return consumer.ReceiveAsync(); - } + public Task ReceiveAsync() + { + return consumer.ReceiveAsync(); + } - public IMessage Receive(TimeSpan timeout) - { - return consumer.Receive(timeout); - } + public IMessage Receive(TimeSpan timeout) + { + return consumer.Receive(timeout); + } - public Task ReceiveAsync(TimeSpan timeout) - { - return consumer.ReceiveAsync(timeout); - } + public Task ReceiveAsync(TimeSpan timeout) + { + return consumer.ReceiveAsync(timeout); + } - public IMessage ReceiveNoWait() - { - return consumer.ReceiveNoWait(); - } + public IMessage ReceiveNoWait() + { + return consumer.ReceiveNoWait(); + } - public T ReceiveBody() - { - return ReceiveBodyInternal(() => Task.FromResult(consumer.Receive())).GetAsyncResult(); - } + public T ReceiveBody() + { + return ReceiveBodyInternal(() => Task.FromResult(consumer.Receive())).GetAsyncResult(); + } - public Task ReceiveBodyAsync() - { - return ReceiveBodyInternal(() => consumer.ReceiveAsync()); - } + public Task ReceiveBodyAsync() + { + return ReceiveBodyInternal(() => consumer.ReceiveAsync()); + } - public T ReceiveBody(TimeSpan timeout) - { - return ReceiveBodyInternal(() => Task.FromResult(consumer.Receive(timeout))).GetAsyncResult(); - } + public T ReceiveBody(TimeSpan timeout) + { + return ReceiveBodyInternal(() => Task.FromResult(consumer.Receive(timeout))).GetAsyncResult(); + } - public Task ReceiveBodyAsync(TimeSpan timeout) - { - return ReceiveBodyInternal(() => consumer.ReceiveAsync(timeout)); - } + public Task ReceiveBodyAsync(TimeSpan timeout) + { + return ReceiveBodyInternal(() => consumer.ReceiveAsync(timeout)); + } - public T ReceiveBodyNoWait() - { - return ReceiveBodyInternal( () => Task.FromResult( consumer.ReceiveNoWait())).GetAsyncResult(); - } + public T ReceiveBodyNoWait() + { + return ReceiveBodyInternal(() => Task.FromResult(consumer.ReceiveNoWait())).GetAsyncResult(); + } - private async Task ReceiveBodyInternal(Func> receiveMessageFunc) + private async Task ReceiveBodyInternal(Func> receiveMessageFunc) + { + var message = await receiveMessageFunc().Awaiter(); + if (message != null) { - var message = await receiveMessageFunc().Awaiter(); - if (message != null) - { - return message.Body(); - } - else - { - return default(T); - } + return message.Body(); } - - public void Close() + else { - consumer.Close(); - } - - public Task CloseAsync() - { - return consumer.CloseAsync(); - } - - public string MessageSelector => consumer.MessageSelector; - - public ConsumerTransformerDelegate ConsumerTransformer - { - get => consumer.ConsumerTransformer; - set => consumer.ConsumerTransformer = value; - } - - public event MessageListener Listener - { - add => consumer.Listener += value; - remove => consumer.Listener -= value; + return default(T); } } -} \ No newline at end of file + + public void Close() + { + consumer.Close(); + } + + public Task CloseAsync() + { + return consumer.CloseAsync(); + } + + public string MessageSelector => consumer.MessageSelector; + + public ConsumerTransformerDelegate ConsumerTransformer + { + get => consumer.ConsumerTransformer; + set => consumer.ConsumerTransformer = value; + } + + public event MessageListener Listener + { + add => consumer.Listener += value; + remove => consumer.Listener -= value; + } +} diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/NmsContext.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/NmsContext.cs index c44e1607..ce9f8725 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/NmsContext.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/NmsContext.cs @@ -1,4 +1,5 @@ #region License + // /* // * Copyright 2022 the original author or authors. // * @@ -14,479 +15,481 @@ // * See the License for the specific language governing permissions and // * limitations under the License. // */ + #endregion using Apache.NMS; using Spring.Messaging.Nms.Support; -namespace Spring.Messaging.Nms.Connections +namespace Spring.Messaging.Nms.Connections; + +internal class NmsContext : INMSContext { - internal class NmsContext: INMSContext + private readonly IConnection connection; + private ISession session; + private readonly SemaphoreSlimLock lockRoot = new SemaphoreSlimLock(); + private readonly AcknowledgementMode acknowledgementMode; + private bool autoStart = true; + + public NmsContext(IConnection connection, AcknowledgementMode acknowledgementMode) { - private readonly IConnection connection; - private ISession session; - private readonly SemaphoreSlimLock lockRoot = new SemaphoreSlimLock(); - private readonly AcknowledgementMode acknowledgementMode; - private bool autoStart = true; - - public NmsContext(IConnection connection, AcknowledgementMode acknowledgementMode) - { - this.connection = connection; - this.acknowledgementMode = acknowledgementMode; - } - - public void Dispose() - { - connection.Dispose(); - } - - public void Start() - { - StartAsync().GetAsyncResult(); - } - - public Task StartAsync() - { - return connection.StartAsync(); - } - - public bool IsStarted => connection.IsStarted; - - public void Stop() - { - StopAsync().GetAsyncResult(); - } - - public Task StopAsync() - { - return connection.StopAsync(); - } - - public INMSContext CreateContext(AcknowledgementMode ackMode) - { - return new NmsContext(connection, ackMode); - } - - public INMSProducer CreateProducer() - { - return CreateProducerAsync().GetAsyncResult(); - } - - public async Task CreateProducerAsync() - { - return new NmsProducer(await GetSessionAsync().Awaiter()); - } - - public INMSConsumer CreateConsumer(IDestination destination) - { - return PrepareConsumer(new NmsConsumer(session.CreateConsumer(destination))); - } - - public INMSConsumer CreateConsumer(IDestination destination, string selector) - { - return PrepareConsumer(new NmsConsumer(session.CreateConsumer(destination, selector))); - } - - public INMSConsumer CreateConsumer(IDestination destination, string selector, bool noLocal) - { - return PrepareConsumer(new NmsConsumer(session.CreateConsumer(destination, selector, noLocal))); - } - - public INMSConsumer CreateDurableConsumer(ITopic destination, string subscriptionName) - { - return PrepareConsumer(new NmsConsumer(session.CreateDurableConsumer(destination, subscriptionName))); - } - - public INMSConsumer CreateDurableConsumer(ITopic destination, string subscriptionName, string selector) - { - return PrepareConsumer(new NmsConsumer(session.CreateDurableConsumer(destination, subscriptionName, selector))); - } - - public INMSConsumer CreateDurableConsumer(ITopic destination, string subscriptionName, string selector, bool noLocal) - { - return PrepareConsumer(new NmsConsumer(session.CreateDurableConsumer(destination, subscriptionName, selector, noLocal))); - } - - public INMSConsumer CreateSharedConsumer(ITopic destination, string subscriptionName) - { - return PrepareConsumer(new NmsConsumer(session.CreateSharedConsumer(destination, subscriptionName))); - } - - public INMSConsumer CreateSharedConsumer(ITopic destination, string subscriptionName, string selector) - { - return PrepareConsumer(new NmsConsumer(session.CreateSharedConsumer(destination, subscriptionName, selector))); - } - - public INMSConsumer CreateSharedDurableConsumer(ITopic destination, string subscriptionName) - { - return PrepareConsumer(new NmsConsumer(session.CreateSharedDurableConsumer(destination, subscriptionName))); - } - - public INMSConsumer CreateSharedDurableConsumer(ITopic destination, string subscriptionName, string selector) - { - return PrepareConsumer(new NmsConsumer(session.CreateSharedDurableConsumer(destination, subscriptionName, selector))); - } - - public async Task CreateConsumerAsync(IDestination destination) - { - return await PrepareConsumerAsync(new NmsConsumer(await session.CreateConsumerAsync(destination).Awaiter())).Awaiter(); - } - - public async Task CreateConsumerAsync(IDestination destination, string selector) - { - return await PrepareConsumerAsync(new NmsConsumer(await session.CreateConsumerAsync(destination, selector).Awaiter())).Awaiter(); - } - - public async Task CreateConsumerAsync(IDestination destination, string selector, bool noLocal) - { - return await PrepareConsumerAsync(new NmsConsumer(await session.CreateConsumerAsync(destination, selector, noLocal).Awaiter())).Awaiter(); - } - - public async Task CreateDurableConsumerAsync(ITopic destination, string subscriptionName) - { - return await PrepareConsumerAsync(new NmsConsumer(await session.CreateDurableConsumerAsync(destination, subscriptionName).Awaiter())).Awaiter(); - } - - public async Task CreateDurableConsumerAsync(ITopic destination, string subscriptionName, string selector) - { - return await PrepareConsumerAsync(new NmsConsumer(await session.CreateDurableConsumerAsync(destination, subscriptionName, selector).Awaiter())).Awaiter(); - } - - public async Task CreateDurableConsumerAsync(ITopic destination, string subscriptionName, string selector, bool noLocal) - { - return await PrepareConsumerAsync(new NmsConsumer(await session.CreateDurableConsumerAsync(destination, subscriptionName, selector, noLocal).Awaiter())).Awaiter(); - } - - public async Task CreateSharedConsumerAsync(ITopic destination, string subscriptionName) - { - return await PrepareConsumerAsync(new NmsConsumer(await session.CreateSharedConsumerAsync(destination, subscriptionName).Awaiter())).Awaiter(); - } - - public async Task CreateSharedConsumerAsync(ITopic destination, string subscriptionName, string selector) - { - return await PrepareConsumerAsync(new NmsConsumer(await session.CreateSharedConsumerAsync(destination, subscriptionName, selector).Awaiter())).Awaiter(); - } - - public async Task CreateSharedDurableConsumerAsync(ITopic destination, string subscriptionName) - { - return await PrepareConsumerAsync(new NmsConsumer(await session.CreateSharedDurableConsumerAsync(destination, subscriptionName).Awaiter())).Awaiter(); - } - - public async Task CreateSharedDurableConsumerAsync(ITopic destination, string subscriptionName, string selector) - { - return await PrepareConsumerAsync(new NmsConsumer(await session.CreateSharedDurableConsumerAsync(destination, subscriptionName, selector).Awaiter())).Awaiter(); - } - - public void Unsubscribe(string name) - { - UnsubscribeAsync(name).GetAsyncResult(); - } - - public Task UnsubscribeAsync(string name) - { - return GetSession().UnsubscribeAsync(name); - } - - public IQueueBrowser CreateBrowser(IQueue queue) - { - return CreateBrowserAsync(queue).GetAsyncResult(); - } - - public Task CreateBrowserAsync(IQueue queue) - { - return GetSession().CreateBrowserAsync(queue); - } - - public IQueueBrowser CreateBrowser(IQueue queue, string selector) - { - return CreateBrowserAsync(queue, selector).GetAsyncResult(); - } - - public Task CreateBrowserAsync(IQueue queue, string selector) - { - return GetSession().CreateBrowserAsync(queue, selector); - } - - public IQueue GetQueue(string name) - { - return GetQueueAsync(name).GetAsyncResult(); - } - - public Task GetQueueAsync(string name) - { - return GetSession().GetQueueAsync(name); - } - - public ITopic GetTopic(string name) - { - return GetTopicAsync(name).GetAsyncResult(); - } - - public Task GetTopicAsync(string name) - { - return GetSession().GetTopicAsync(name); - } - - public ITemporaryQueue CreateTemporaryQueue() - { - return CreateTemporaryQueueAsync().GetAsyncResult(); - } - - public Task CreateTemporaryQueueAsync() - { - return GetSession().CreateTemporaryQueueAsync(); - } - - public ITemporaryTopic CreateTemporaryTopic() - { - return CreateTemporaryTopicAsync().GetAsyncResult(); - } - - public Task CreateTemporaryTopicAsync() - { - return GetSession().CreateTemporaryTopicAsync(); - } - - public IMessage CreateMessage() - { - return CreateMessageAsync().GetAsyncResult(); - } - - public Task CreateMessageAsync() - { - return GetSession().CreateMessageAsync(); - } - - public ITextMessage CreateTextMessage() - { - return CreateTextMessageAsync().GetAsyncResult(); - } - - public Task CreateTextMessageAsync() - { - return GetSession().CreateTextMessageAsync(); - } - - public ITextMessage CreateTextMessage(string text) - { - return CreateTextMessageAsync(text).GetAsyncResult(); - } - - public Task CreateTextMessageAsync(string text) - { - return GetSession().CreateTextMessageAsync(text); - } - - public IMapMessage CreateMapMessage() - { - return CreateMapMessageAsync().GetAsyncResult(); - } - - public Task CreateMapMessageAsync() - { - return GetSession().CreateMapMessageAsync(); - } - - public IObjectMessage CreateObjectMessage(object body) - { - return CreateObjectMessageAsync(body).GetAsyncResult(); - } - - public Task CreateObjectMessageAsync(object body) - { - return GetSession().CreateObjectMessageAsync(body); - } - - public IBytesMessage CreateBytesMessage() - { - return CreateBytesMessageAsync().GetAsyncResult(); - } - - public Task CreateBytesMessageAsync() - { - return GetSession().CreateBytesMessageAsync(); - } - - public IBytesMessage CreateBytesMessage(byte[] body) - { - return CreateBytesMessageAsync(body).GetAsyncResult(); - } - - public Task CreateBytesMessageAsync(byte[] body) - { - return GetSession().CreateBytesMessageAsync(body); - } - - public IStreamMessage CreateStreamMessage() - { - return CreateStreamMessageAsync().GetAsyncResult(); - } - - public Task CreateStreamMessageAsync() - { - return GetSession().CreateStreamMessageAsync(); - } - - public void Close() - { - session?.Close(); - } - - public async Task CloseAsync() - { - if (session != null) - { - await session.CloseAsync().Awaiter(); - } - } - - public void Recover() - { - RecoverAsync().GetAsyncResult(); - } - - public Task RecoverAsync() - { - return GetSession().RecoverAsync(); - } - - public void Acknowledge() - { - AcknowledgeAsync().GetAsyncResult(); - } - - public Task AcknowledgeAsync() - { - return GetSession().AcknowledgeAsync(); - } - - public void Commit() - { - CommitAsync().GetAsyncResult(); - } - - public Task CommitAsync() - { - return GetSession().CommitAsync(); - } - - public void Rollback() - { - RollbackAsync().GetAsyncResult(); - } - - public Task RollbackAsync() - { - return GetSession().RollbackAsync(); - } - - public void PurgeTempDestinations() - { - connection.PurgeTempDestinations(); - } - - public ConsumerTransformerDelegate ConsumerTransformer - { - get => GetSession().ConsumerTransformer; - set => GetSession().ConsumerTransformer = value; - } - - public ProducerTransformerDelegate ProducerTransformer - { - get => GetSession().ProducerTransformer; - set => GetSession().ProducerTransformer = value; - } - - public TimeSpan RequestTimeout - { - get => GetSession().RequestTimeout; - set => GetSession().RequestTimeout = value; - } - - public bool Transacted => GetSession().Transacted; - - public AcknowledgementMode AcknowledgementMode => acknowledgementMode; - - public string ClientId - { - get => connection.ClientId; - set => connection.ClientId = value; - } - - public bool AutoStart - { - get => autoStart; - set => autoStart = value; - } - - public event SessionTxEventDelegate TransactionStartedListener - { - add => GetSession().TransactionStartedListener += value; - remove => GetSession().TransactionStartedListener -= value; - } - - public event SessionTxEventDelegate TransactionCommittedListener - { - add => GetSession().TransactionCommittedListener += value; - remove => GetSession().TransactionCommittedListener -= value; - } - - public event SessionTxEventDelegate TransactionRolledBackListener - { - add => GetSession().TransactionRolledBackListener += value; - remove => GetSession().TransactionRolledBackListener -= value; - } - - public event ExceptionListener ExceptionListener - { - add => connection.ExceptionListener += value; - remove => connection.ExceptionListener -= value; - } - - public event ConnectionInterruptedListener ConnectionInterruptedListener - { - add => connection.ConnectionInterruptedListener += value; - remove => connection.ConnectionInterruptedListener -= value; - } - - public event ConnectionResumedListener ConnectionResumedListener - { - add => connection.ConnectionResumedListener += value; - remove => connection.ConnectionResumedListener -= value; - } - - private INMSConsumer PrepareConsumer(INMSConsumer consumer) - { - return PrepareConsumerAsync(consumer).GetAsyncResult(); - } - - private async Task PrepareConsumerAsync(INMSConsumer consumer) - { - if (autoStart) { - await connection.StartAsync().Awaiter(); - } - return consumer; - } - - private ISession GetSession() - { - return GetSessionAsync().GetAsyncResult(); - } - - private async Task GetSessionAsync() - { - if (session == null) - { - using (await lockRoot.LockAsync().Awaiter()) - { - if (session == null) - { - session = await connection.CreateSessionAsync(acknowledgementMode).Awaiter(); - } - } - } - - return session; + this.connection = connection; + this.acknowledgementMode = acknowledgementMode; + } + + public void Dispose() + { + connection.Dispose(); + } + + public void Start() + { + StartAsync().GetAsyncResult(); + } + + public Task StartAsync() + { + return connection.StartAsync(); + } + + public bool IsStarted => connection.IsStarted; + + public void Stop() + { + StopAsync().GetAsyncResult(); + } + + public Task StopAsync() + { + return connection.StopAsync(); + } + + public INMSContext CreateContext(AcknowledgementMode ackMode) + { + return new NmsContext(connection, ackMode); + } + + public INMSProducer CreateProducer() + { + return CreateProducerAsync().GetAsyncResult(); + } + + public async Task CreateProducerAsync() + { + return new NmsProducer(await GetSessionAsync().Awaiter()); + } + + public INMSConsumer CreateConsumer(IDestination destination) + { + return PrepareConsumer(new NmsConsumer(session.CreateConsumer(destination))); + } + + public INMSConsumer CreateConsumer(IDestination destination, string selector) + { + return PrepareConsumer(new NmsConsumer(session.CreateConsumer(destination, selector))); + } + + public INMSConsumer CreateConsumer(IDestination destination, string selector, bool noLocal) + { + return PrepareConsumer(new NmsConsumer(session.CreateConsumer(destination, selector, noLocal))); + } + + public INMSConsumer CreateDurableConsumer(ITopic destination, string subscriptionName) + { + return PrepareConsumer(new NmsConsumer(session.CreateDurableConsumer(destination, subscriptionName))); + } + + public INMSConsumer CreateDurableConsumer(ITopic destination, string subscriptionName, string selector) + { + return PrepareConsumer(new NmsConsumer(session.CreateDurableConsumer(destination, subscriptionName, selector))); + } + + public INMSConsumer CreateDurableConsumer(ITopic destination, string subscriptionName, string selector, bool noLocal) + { + return PrepareConsumer(new NmsConsumer(session.CreateDurableConsumer(destination, subscriptionName, selector, noLocal))); + } + + public INMSConsumer CreateSharedConsumer(ITopic destination, string subscriptionName) + { + return PrepareConsumer(new NmsConsumer(session.CreateSharedConsumer(destination, subscriptionName))); + } + + public INMSConsumer CreateSharedConsumer(ITopic destination, string subscriptionName, string selector) + { + return PrepareConsumer(new NmsConsumer(session.CreateSharedConsumer(destination, subscriptionName, selector))); + } + + public INMSConsumer CreateSharedDurableConsumer(ITopic destination, string subscriptionName) + { + return PrepareConsumer(new NmsConsumer(session.CreateSharedDurableConsumer(destination, subscriptionName))); + } + + public INMSConsumer CreateSharedDurableConsumer(ITopic destination, string subscriptionName, string selector) + { + return PrepareConsumer(new NmsConsumer(session.CreateSharedDurableConsumer(destination, subscriptionName, selector))); + } + + public async Task CreateConsumerAsync(IDestination destination) + { + return await PrepareConsumerAsync(new NmsConsumer(await session.CreateConsumerAsync(destination).Awaiter())).Awaiter(); + } + + public async Task CreateConsumerAsync(IDestination destination, string selector) + { + return await PrepareConsumerAsync(new NmsConsumer(await session.CreateConsumerAsync(destination, selector).Awaiter())).Awaiter(); + } + + public async Task CreateConsumerAsync(IDestination destination, string selector, bool noLocal) + { + return await PrepareConsumerAsync(new NmsConsumer(await session.CreateConsumerAsync(destination, selector, noLocal).Awaiter())).Awaiter(); + } + + public async Task CreateDurableConsumerAsync(ITopic destination, string subscriptionName) + { + return await PrepareConsumerAsync(new NmsConsumer(await session.CreateDurableConsumerAsync(destination, subscriptionName).Awaiter())).Awaiter(); + } + + public async Task CreateDurableConsumerAsync(ITopic destination, string subscriptionName, string selector) + { + return await PrepareConsumerAsync(new NmsConsumer(await session.CreateDurableConsumerAsync(destination, subscriptionName, selector).Awaiter())).Awaiter(); + } + + public async Task CreateDurableConsumerAsync(ITopic destination, string subscriptionName, string selector, bool noLocal) + { + return await PrepareConsumerAsync(new NmsConsumer(await session.CreateDurableConsumerAsync(destination, subscriptionName, selector, noLocal).Awaiter())).Awaiter(); + } + + public async Task CreateSharedConsumerAsync(ITopic destination, string subscriptionName) + { + return await PrepareConsumerAsync(new NmsConsumer(await session.CreateSharedConsumerAsync(destination, subscriptionName).Awaiter())).Awaiter(); + } + + public async Task CreateSharedConsumerAsync(ITopic destination, string subscriptionName, string selector) + { + return await PrepareConsumerAsync(new NmsConsumer(await session.CreateSharedConsumerAsync(destination, subscriptionName, selector).Awaiter())).Awaiter(); + } + + public async Task CreateSharedDurableConsumerAsync(ITopic destination, string subscriptionName) + { + return await PrepareConsumerAsync(new NmsConsumer(await session.CreateSharedDurableConsumerAsync(destination, subscriptionName).Awaiter())).Awaiter(); + } + + public async Task CreateSharedDurableConsumerAsync(ITopic destination, string subscriptionName, string selector) + { + return await PrepareConsumerAsync(new NmsConsumer(await session.CreateSharedDurableConsumerAsync(destination, subscriptionName, selector).Awaiter())).Awaiter(); + } + + public void Unsubscribe(string name) + { + UnsubscribeAsync(name).GetAsyncResult(); + } + + public Task UnsubscribeAsync(string name) + { + return GetSession().UnsubscribeAsync(name); + } + + public IQueueBrowser CreateBrowser(IQueue queue) + { + return CreateBrowserAsync(queue).GetAsyncResult(); + } + + public Task CreateBrowserAsync(IQueue queue) + { + return GetSession().CreateBrowserAsync(queue); + } + + public IQueueBrowser CreateBrowser(IQueue queue, string selector) + { + return CreateBrowserAsync(queue, selector).GetAsyncResult(); + } + + public Task CreateBrowserAsync(IQueue queue, string selector) + { + return GetSession().CreateBrowserAsync(queue, selector); + } + + public IQueue GetQueue(string name) + { + return GetQueueAsync(name).GetAsyncResult(); + } + + public Task GetQueueAsync(string name) + { + return GetSession().GetQueueAsync(name); + } + + public ITopic GetTopic(string name) + { + return GetTopicAsync(name).GetAsyncResult(); + } + + public Task GetTopicAsync(string name) + { + return GetSession().GetTopicAsync(name); + } + + public ITemporaryQueue CreateTemporaryQueue() + { + return CreateTemporaryQueueAsync().GetAsyncResult(); + } + + public Task CreateTemporaryQueueAsync() + { + return GetSession().CreateTemporaryQueueAsync(); + } + + public ITemporaryTopic CreateTemporaryTopic() + { + return CreateTemporaryTopicAsync().GetAsyncResult(); + } + + public Task CreateTemporaryTopicAsync() + { + return GetSession().CreateTemporaryTopicAsync(); + } + + public IMessage CreateMessage() + { + return CreateMessageAsync().GetAsyncResult(); + } + + public Task CreateMessageAsync() + { + return GetSession().CreateMessageAsync(); + } + + public ITextMessage CreateTextMessage() + { + return CreateTextMessageAsync().GetAsyncResult(); + } + + public Task CreateTextMessageAsync() + { + return GetSession().CreateTextMessageAsync(); + } + + public ITextMessage CreateTextMessage(string text) + { + return CreateTextMessageAsync(text).GetAsyncResult(); + } + + public Task CreateTextMessageAsync(string text) + { + return GetSession().CreateTextMessageAsync(text); + } + + public IMapMessage CreateMapMessage() + { + return CreateMapMessageAsync().GetAsyncResult(); + } + + public Task CreateMapMessageAsync() + { + return GetSession().CreateMapMessageAsync(); + } + + public IObjectMessage CreateObjectMessage(object body) + { + return CreateObjectMessageAsync(body).GetAsyncResult(); + } + + public Task CreateObjectMessageAsync(object body) + { + return GetSession().CreateObjectMessageAsync(body); + } + + public IBytesMessage CreateBytesMessage() + { + return CreateBytesMessageAsync().GetAsyncResult(); + } + + public Task CreateBytesMessageAsync() + { + return GetSession().CreateBytesMessageAsync(); + } + + public IBytesMessage CreateBytesMessage(byte[] body) + { + return CreateBytesMessageAsync(body).GetAsyncResult(); + } + + public Task CreateBytesMessageAsync(byte[] body) + { + return GetSession().CreateBytesMessageAsync(body); + } + + public IStreamMessage CreateStreamMessage() + { + return CreateStreamMessageAsync().GetAsyncResult(); + } + + public Task CreateStreamMessageAsync() + { + return GetSession().CreateStreamMessageAsync(); + } + + public void Close() + { + session?.Close(); + } + + public async Task CloseAsync() + { + if (session != null) + { + await session.CloseAsync().Awaiter(); } } -} \ No newline at end of file + + public void Recover() + { + RecoverAsync().GetAsyncResult(); + } + + public Task RecoverAsync() + { + return GetSession().RecoverAsync(); + } + + public void Acknowledge() + { + AcknowledgeAsync().GetAsyncResult(); + } + + public Task AcknowledgeAsync() + { + return GetSession().AcknowledgeAsync(); + } + + public void Commit() + { + CommitAsync().GetAsyncResult(); + } + + public Task CommitAsync() + { + return GetSession().CommitAsync(); + } + + public void Rollback() + { + RollbackAsync().GetAsyncResult(); + } + + public Task RollbackAsync() + { + return GetSession().RollbackAsync(); + } + + public void PurgeTempDestinations() + { + connection.PurgeTempDestinations(); + } + + public ConsumerTransformerDelegate ConsumerTransformer + { + get => GetSession().ConsumerTransformer; + set => GetSession().ConsumerTransformer = value; + } + + public ProducerTransformerDelegate ProducerTransformer + { + get => GetSession().ProducerTransformer; + set => GetSession().ProducerTransformer = value; + } + + public TimeSpan RequestTimeout + { + get => GetSession().RequestTimeout; + set => GetSession().RequestTimeout = value; + } + + public bool Transacted => GetSession().Transacted; + + public AcknowledgementMode AcknowledgementMode => acknowledgementMode; + + public string ClientId + { + get => connection.ClientId; + set => connection.ClientId = value; + } + + public bool AutoStart + { + get => autoStart; + set => autoStart = value; + } + + public event SessionTxEventDelegate TransactionStartedListener + { + add => GetSession().TransactionStartedListener += value; + remove => GetSession().TransactionStartedListener -= value; + } + + public event SessionTxEventDelegate TransactionCommittedListener + { + add => GetSession().TransactionCommittedListener += value; + remove => GetSession().TransactionCommittedListener -= value; + } + + public event SessionTxEventDelegate TransactionRolledBackListener + { + add => GetSession().TransactionRolledBackListener += value; + remove => GetSession().TransactionRolledBackListener -= value; + } + + public event ExceptionListener ExceptionListener + { + add => connection.ExceptionListener += value; + remove => connection.ExceptionListener -= value; + } + + public event ConnectionInterruptedListener ConnectionInterruptedListener + { + add => connection.ConnectionInterruptedListener += value; + remove => connection.ConnectionInterruptedListener -= value; + } + + public event ConnectionResumedListener ConnectionResumedListener + { + add => connection.ConnectionResumedListener += value; + remove => connection.ConnectionResumedListener -= value; + } + + private INMSConsumer PrepareConsumer(INMSConsumer consumer) + { + return PrepareConsumerAsync(consumer).GetAsyncResult(); + } + + private async Task PrepareConsumerAsync(INMSConsumer consumer) + { + if (autoStart) + { + await connection.StartAsync().Awaiter(); + } + + return consumer; + } + + private ISession GetSession() + { + return GetSessionAsync().GetAsyncResult(); + } + + private async Task GetSessionAsync() + { + if (session == null) + { + using (await lockRoot.LockAsync().Awaiter()) + { + if (session == null) + { + session = await connection.CreateSessionAsync(acknowledgementMode).Awaiter(); + } + } + } + + return session; + } +} diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/NmsProducer.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/NmsProducer.cs index 7b86860f..61b7c238 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/NmsProducer.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/NmsProducer.cs @@ -1,4 +1,5 @@ #region License + // /* // * Copyright 2022 the original author or authors. // * @@ -14,6 +15,7 @@ // * See the License for the specific language governing permissions and // * limitations under the License. // */ + #endregion using System.Collections; @@ -21,369 +23,378 @@ using Apache.NMS; using Apache.NMS.Util; using Spring.Messaging.Nms.Support; -namespace Spring.Messaging.Nms.Connections +namespace Spring.Messaging.Nms.Connections; + +public class NmsProducer : INMSProducer { - public class NmsProducer : INMSProducer + private readonly IMessageProducer producer; + private readonly ISession session; + private String correlationId; + private String type; + private IDestination replyTo; + private readonly IPrimitiveMap messageProperties = new PrimitiveMap(); + + public NmsProducer(ISession session) { - private readonly IMessageProducer producer; - private readonly ISession session; - private String correlationId; - private String type; - private IDestination replyTo; - private readonly IPrimitiveMap messageProperties = new PrimitiveMap(); + this.session = session; + this.producer = session.CreateProducer(); + } - public NmsProducer(ISession session) - { - this.session = session; - this.producer = session.CreateProducer(); - } + public void Dispose() + { + producer.Dispose(); + } - public void Dispose() - { - producer.Dispose(); - } + public INMSProducer Send(IDestination destination, IMessage message) + { + return SendAsync(destination, message).GetAsyncResult(); + } - public INMSProducer Send(IDestination destination, IMessage message) - { - return SendAsync(destination, message).GetAsyncResult(); - } + public INMSProducer Send(IDestination destination, string body) + { + return SendAsync(destination, body).GetAsyncResult(); + } - public INMSProducer Send(IDestination destination, string body) - { - return SendAsync(destination, body).GetAsyncResult(); - } + public INMSProducer Send(IDestination destination, IPrimitiveMap body) + { + return SendAsync(destination, body).GetAsyncResult(); + } - public INMSProducer Send(IDestination destination, IPrimitiveMap body) - { - return SendAsync(destination, body).GetAsyncResult(); - } + public INMSProducer Send(IDestination destination, byte[] body) + { + return SendAsync(destination, body).GetAsyncResult(); + } - public INMSProducer Send(IDestination destination, byte[] body) - { - return SendAsync(destination, body).GetAsyncResult(); - } + public INMSProducer Send(IDestination destination, object body) + { + return SendAsync(destination, body).GetAsyncResult(); + } - public INMSProducer Send(IDestination destination, object body) - { - return SendAsync(destination, body).GetAsyncResult(); - } + public async Task SendAsync(IDestination destination, IMessage message) + { + CopyMap(messageProperties, message.Properties); + await producer.SendAsync(destination, message).Awaiter(); + return this; + } - public async Task SendAsync(IDestination destination, IMessage message) - { - CopyMap(messageProperties, message.Properties); - await producer.SendAsync(destination, message).Awaiter(); - return this; - } + public async Task SendAsync(IDestination destination, string body) + { + var message = await CreateTextMessageAsync(body).Awaiter(); + return await SendAsync(destination, message).Awaiter(); + } - public async Task SendAsync(IDestination destination, string body) - { - var message = await CreateTextMessageAsync(body).Awaiter(); - return await SendAsync(destination, message).Awaiter(); - } + public async Task SendAsync(IDestination destination, IPrimitiveMap body) + { + var message = await CreateMapMessageAsync().Awaiter(); + CopyMap(body, message.Body); - public async Task SendAsync(IDestination destination, IPrimitiveMap body) - { - var message = await CreateMapMessageAsync().Awaiter(); - CopyMap(body, message.Body); + return await SendAsync(destination, message).Awaiter(); + } - return await SendAsync(destination, message).Awaiter(); - } + public async Task SendAsync(IDestination destination, byte[] body) + { + var message = await CreateBytesMessageAsync(body).Awaiter(); + return await SendAsync(destination, message).Awaiter(); + } - public async Task SendAsync(IDestination destination, byte[] body) - { - var message = await CreateBytesMessageAsync(body).Awaiter(); - return await SendAsync(destination, message).Awaiter(); - } + public async Task SendAsync(IDestination destination, object body) + { + var message = await CreateObjectMessageAsync(body).Awaiter(); + return await SendAsync(destination, message).Awaiter(); + } - public async Task SendAsync(IDestination destination, object body) - { - var message = await CreateObjectMessageAsync(body).Awaiter(); - return await SendAsync(destination, message).Awaiter(); - } + public INMSProducer ClearProperties() + { + messageProperties.Clear(); + return this; + } - public INMSProducer ClearProperties() - { - messageProperties.Clear(); - return this; - } + public INMSProducer SetDeliveryDelay(TimeSpan deliveryDelay) + { + DeliveryDelay = deliveryDelay; + return this; + } - public INMSProducer SetDeliveryDelay(TimeSpan deliveryDelay) - { - DeliveryDelay = deliveryDelay; - return this; - } + public INMSProducer SetTimeToLive(TimeSpan timeToLive) + { + TimeToLive = timeToLive; + return this; + } - public INMSProducer SetTimeToLive(TimeSpan timeToLive) - { - TimeToLive = timeToLive; - return this; - } + public INMSProducer SetDeliveryMode(MsgDeliveryMode deliveryMode) + { + DeliveryMode = deliveryMode; + return this; + } - public INMSProducer SetDeliveryMode(MsgDeliveryMode deliveryMode) - { - DeliveryMode = deliveryMode; - return this; - } + public INMSProducer SetDisableMessageID(bool value) + { + DisableMessageID = value; + return this; + } - public INMSProducer SetDisableMessageID(bool value) - { - DisableMessageID = value; - return this; - } + public INMSProducer SetDisableMessageTimestamp(bool value) + { + DisableMessageTimestamp = value; + return this; + } - public INMSProducer SetDisableMessageTimestamp(bool value) - { - DisableMessageTimestamp = value; - return this; - } + public INMSProducer SetNMSCorrelationID(string correlationID) + { + NMSCorrelationID = correlationID; + return this; + } - public INMSProducer SetNMSCorrelationID(string correlationID) - { - NMSCorrelationID = correlationID; - return this; - } + public INMSProducer SetNMSReplyTo(IDestination replyTo) + { + NMSReplyTo = replyTo; + return this; + } - public INMSProducer SetNMSReplyTo(IDestination replyTo) - { - NMSReplyTo = replyTo; - return this; - } + public INMSProducer SetNMSType(string type) + { + NMSType = type; + return this; + } - public INMSProducer SetNMSType(string type) - { - NMSType = type; - return this; - } + public INMSProducer SetPriority(MsgPriority priority) + { + Priority = priority; + return this; + } - public INMSProducer SetPriority(MsgPriority priority) - { - Priority = priority; - return this; - } + public INMSProducer SetProperty(string name, bool value) + { + messageProperties.SetBool(name, value); + return this; + } - public INMSProducer SetProperty(string name, bool value) - { - messageProperties.SetBool(name, value); - return this; - } + public INMSProducer SetProperty(string name, byte value) + { + messageProperties.SetByte(name, value); + return this; + } - public INMSProducer SetProperty(string name, byte value) - { - messageProperties.SetByte(name, value); - return this; - } + public INMSProducer SetProperty(string name, double value) + { + messageProperties.SetDouble(name, value); + return this; + } - public INMSProducer SetProperty(string name, double value) - { - messageProperties.SetDouble(name, value); - return this; - } + public INMSProducer SetProperty(string name, float value) + { + messageProperties.SetFloat(name, value); + return this; + } - public INMSProducer SetProperty(string name, float value) - { - messageProperties.SetFloat(name, value); - return this; - } + public INMSProducer SetProperty(string name, int value) + { + messageProperties.SetInt(name, value); + return this; + } - public INMSProducer SetProperty(string name, int value) - { - messageProperties.SetInt(name, value); - return this; - } + public INMSProducer SetProperty(string name, long value) + { + messageProperties.SetLong(name, value); + return this; + } - public INMSProducer SetProperty(string name, long value) - { - messageProperties.SetLong(name, value); - return this; - } + public INMSProducer SetProperty(string name, short value) + { + messageProperties.SetShort(name, value); + return this; + } - public INMSProducer SetProperty(string name, short value) - { - messageProperties.SetShort(name, value); - return this; - } + public INMSProducer SetProperty(string name, char value) + { + messageProperties.SetChar(name, value); + return this; + } - public INMSProducer SetProperty(string name, char value) - { - messageProperties.SetChar(name, value); - return this; - } + public INMSProducer SetProperty(string name, string value) + { + messageProperties.SetString(name, value); + return this; + } - public INMSProducer SetProperty(string name, string value) - { - messageProperties.SetString(name, value); - return this; - } + public INMSProducer SetProperty(string name, byte[] value) + { + messageProperties.SetBytes(name, value); + return this; + } - public INMSProducer SetProperty(string name, byte[] value) - { - messageProperties.SetBytes(name, value); - return this; - } + public INMSProducer SetProperty(string name, IList value) + { + messageProperties.SetList(name, value); + return this; + } - public INMSProducer SetProperty(string name, IList value) - { - messageProperties.SetList(name, value); - return this; - } + public INMSProducer SetProperty(string name, IDictionary value) + { + messageProperties.SetDictionary(name, value); + return this; + } - public INMSProducer SetProperty(string name, IDictionary value) - { - messageProperties.SetDictionary(name, value); - return this; - } + public IMessage CreateMessage() + { + return session.CreateMessage(); + } - public IMessage CreateMessage() - { - return session.CreateMessage(); - } + public Task CreateMessageAsync() + { + return session.CreateMessageAsync(); + } - public Task CreateMessageAsync() - { - return session.CreateMessageAsync(); - } + public ITextMessage CreateTextMessage() + { + return session.CreateTextMessage(); + } - public ITextMessage CreateTextMessage() - { - return session.CreateTextMessage(); - } + public Task CreateTextMessageAsync() + { + return session.CreateTextMessageAsync(); + } - public Task CreateTextMessageAsync() - { - return session.CreateTextMessageAsync(); - } + public ITextMessage CreateTextMessage(string text) + { + return session.CreateTextMessage(text); + } - public ITextMessage CreateTextMessage(string text) - { - return session.CreateTextMessage(text); - } + public Task CreateTextMessageAsync(string text) + { + return session.CreateTextMessageAsync(text); + } - public Task CreateTextMessageAsync(string text) - { - return session.CreateTextMessageAsync(text); - } + public IMapMessage CreateMapMessage() + { + return session.CreateMapMessage(); + } - public IMapMessage CreateMapMessage() - { - return session.CreateMapMessage(); - } + public Task CreateMapMessageAsync() + { + return session.CreateMapMessageAsync(); + } - public Task CreateMapMessageAsync() - { - return session.CreateMapMessageAsync(); - } + public IObjectMessage CreateObjectMessage(object body) + { + return session.CreateObjectMessage(body); + } - public IObjectMessage CreateObjectMessage(object body) - { - return session.CreateObjectMessage(body); - } + public Task CreateObjectMessageAsync(object body) + { + return session.CreateObjectMessageAsync(body); + } - public Task CreateObjectMessageAsync(object body) - { - return session.CreateObjectMessageAsync(body); - } + public IBytesMessage CreateBytesMessage() + { + return session.CreateBytesMessage(); + } - public IBytesMessage CreateBytesMessage() - { - return session.CreateBytesMessage(); - } + public Task CreateBytesMessageAsync() + { + return session.CreateBytesMessageAsync(); + } - public Task CreateBytesMessageAsync() - { - return session.CreateBytesMessageAsync(); - } + public IBytesMessage CreateBytesMessage(byte[] body) + { + return session.CreateBytesMessage(body); + } - public IBytesMessage CreateBytesMessage(byte[] body) - { - return session.CreateBytesMessage(body); - } + public Task CreateBytesMessageAsync(byte[] body) + { + return session.CreateBytesMessageAsync(body); + } - public Task CreateBytesMessageAsync(byte[] body) - { - return session.CreateBytesMessageAsync(body); - } + public IStreamMessage CreateStreamMessage() + { + return session.CreateStreamMessage(); + } - public IStreamMessage CreateStreamMessage() - { - return session.CreateStreamMessage(); - } + public Task CreateStreamMessageAsync() + { + return session.CreateStreamMessageAsync(); + } - public Task CreateStreamMessageAsync() - { - return session.CreateStreamMessageAsync(); - } + public void Close() + { + producer.Close(); + } - public void Close() - { - producer.Close(); - } + public Task CloseAsync() + { + return producer.CloseAsync(); + } - public Task CloseAsync() - { - return producer.CloseAsync(); - } + public IPrimitiveMap Properties => messageProperties; - public IPrimitiveMap Properties => messageProperties; - public string NMSCorrelationID - { - get => correlationId; - set => correlationId = value; - } - public IDestination NMSReplyTo - { - get => replyTo; - set => replyTo = value; - } - public string NMSType - { - get => type; - set => type = value; - } + public string NMSCorrelationID + { + get => correlationId; + set => correlationId = value; + } + public IDestination NMSReplyTo + { + get => replyTo; + set => replyTo = value; + } - public ProducerTransformerDelegate ProducerTransformer { - get => producer.ProducerTransformer; - set => producer.ProducerTransformer = value; - } - public MsgDeliveryMode DeliveryMode { get => producer.DeliveryMode; set => producer.DeliveryMode = value; } - public TimeSpan DeliveryDelay { get => producer.DeliveryDelay; - set => producer.DeliveryDelay = value; - } - public TimeSpan TimeToLive - { - get => producer.TimeToLive; - set => producer.TimeToLive = value; - } + public string NMSType + { + get => type; + set => type = value; + } - public TimeSpan RequestTimeout - { - get => producer.RequestTimeout; - set => producer.RequestTimeout = value; - } - public MsgPriority Priority - { - get => producer.Priority; - set => producer.Priority = value; - } - public bool DisableMessageID - { - get => producer.DisableMessageID; - set => producer.DisableMessageID = value; - } - public bool DisableMessageTimestamp - { - get => producer.DisableMessageTimestamp; - set => producer.DisableMessageTimestamp = value; - } + public ProducerTransformerDelegate ProducerTransformer + { + get => producer.ProducerTransformer; + set => producer.ProducerTransformer = value; + } - private void CopyMap(IPrimitiveMap source, IPrimitiveMap target) - { - foreach (object key in source.Keys) - { - string name = key.ToString(); - target[name] = source[name]; - } - } + public MsgDeliveryMode DeliveryMode { get => producer.DeliveryMode; set => producer.DeliveryMode = value; } + public TimeSpan DeliveryDelay + { + get => producer.DeliveryDelay; + set => producer.DeliveryDelay = value; + } + + public TimeSpan TimeToLive + { + get => producer.TimeToLive; + set => producer.TimeToLive = value; + } + + public TimeSpan RequestTimeout + { + get => producer.RequestTimeout; + set => producer.RequestTimeout = value; + } + + public MsgPriority Priority + { + get => producer.Priority; + set => producer.Priority = value; + } + + public bool DisableMessageID + { + get => producer.DisableMessageID; + set => producer.DisableMessageID = value; + } + + public bool DisableMessageTimestamp + { + get => producer.DisableMessageTimestamp; + set => producer.DisableMessageTimestamp = value; + } + + private void CopyMap(IPrimitiveMap source, IPrimitiveMap target) + { + foreach (object key in source.Keys) + { + string name = key.ToString(); + target[name] = source[name]; + } } } diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/NmsResourceHolder.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/NmsResourceHolder.cs index f93c91c7..a5ee2d91 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/NmsResourceHolder.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/NmsResourceHolder.cs @@ -20,276 +20,279 @@ using Apache.NMS; using Microsoft.Extensions.Logging; using Spring.Messaging.Nms.Support; -namespace Spring.Messaging.Nms.Connections +namespace Spring.Messaging.Nms.Connections; + +/// Connection holder, wrapping a NMS Connection and a NMS Session. +/// MessageTransactionManager binds instances of this class to the thread, +/// for a given NMS ConnectionFactory. +/// +///

Note: This is an SPI class, not intended to be used by applications.

+/// +///
+/// Juergen Hoeller +/// Mark Pollack (.NET) +public class NmsResourceHolder : ResourceHolderSupport { - /// Connection holder, wrapping a NMS Connection and a NMS Session. - /// MessageTransactionManager binds instances of this class to the thread, - /// for a given NMS ConnectionFactory. - /// - ///

Note: This is an SPI class, not intended to be used by applications.

- /// - ///
- /// Juergen Hoeller - /// Mark Pollack (.NET) - public class NmsResourceHolder : ResourceHolderSupport + private static readonly ILogger logger = LogManager.GetLogger(); + + private readonly IConnectionFactory connectionFactory; + private readonly bool frozen = false; + private readonly List connections = new List(); + private readonly List sessions = new List(); + private readonly Dictionary> sessionsPerIConnection = new Dictionary>(); + + /// Create a new MessageResourceHolder that is open for resources to be added. + public NmsResourceHolder() { - private static readonly ILogger logger = LogManager.GetLogger(); + } - private readonly IConnectionFactory connectionFactory; - private readonly bool frozen = false; - private readonly List connections = new List(); - private readonly List sessions = new List(); - private readonly Dictionary> sessionsPerIConnection = new Dictionary>(); + /// + /// Initializes a new instance of the class + /// at is open for resources to be added. + /// + /// The connection factory that this + /// resource holder is associated with (may be null) + /// + public NmsResourceHolder(IConnectionFactory connectionFactory) + { + this.connectionFactory = connectionFactory; + } - /// Create a new MessageResourceHolder that is open for resources to be added. - public NmsResourceHolder() + /// + /// Initializes a new instance of the class for the + /// given Session. + /// + /// The session. + public NmsResourceHolder(ISession session) + { + AddSession(session); + frozen = true; + } + + /// Create a new MessageResourceHolder for the given NMS resources. + /// the NMS Connection + /// + /// the NMS Session + /// + public NmsResourceHolder(IConnection connection, ISession session) + { + AddConnection(connection); + AddSession(session, connection); + frozen = true; + } + + /// + /// Initializes a new instance of the class. + /// + /// The connection factory. + /// The connection. + /// The session. + public NmsResourceHolder(IConnectionFactory connectionFactory, IConnection connection, ISession session) + { + this.connectionFactory = connectionFactory; + AddConnection(connection); + AddSession(session, connection); + frozen = true; + } + + /// + /// Gets a value indicating whether this is frozen, namely that + /// additional resources can be registered with the holder. If using any of the constructors with + /// a Session, the holder will be set to the frozen state. + /// + /// true if frozen; otherwise, false. + public virtual bool Frozen => frozen; + + /// + /// Adds the connection to the list of resources managed by this holder. + /// + /// The connection. + public void AddConnection(IConnection connection) + { + AssertUtils.IsTrue(!frozen, "Cannot add IConnection because MessageResourceHolder is frozen"); + AssertUtils.ArgumentNotNull(connection, "IConnection must not be null"); + if (!connections.Contains(connection)) { - } - - - /// - /// Initializes a new instance of the class - /// at is open for resources to be added. - /// - /// The connection factory that this - /// resource holder is associated with (may be null) - /// - public NmsResourceHolder(IConnectionFactory connectionFactory) - { - this.connectionFactory = connectionFactory; - } - - /// - /// Initializes a new instance of the class for the - /// given Session. - /// - /// The session. - public NmsResourceHolder(ISession session) - { - AddSession(session); - frozen = true; - } - - /// Create a new MessageResourceHolder for the given NMS resources. - /// the NMS Connection - /// - /// the NMS Session - /// - public NmsResourceHolder(IConnection connection, ISession session) - { - AddConnection(connection); - AddSession(session, connection); - frozen = true; - } - - /// - /// Initializes a new instance of the class. - /// - /// The connection factory. - /// The connection. - /// The session. - public NmsResourceHolder(IConnectionFactory connectionFactory, IConnection connection, ISession session) - { - this.connectionFactory = connectionFactory; - AddConnection(connection); - AddSession(session, connection); - frozen = true; - } - - /// - /// Gets a value indicating whether this is frozen, namely that - /// additional resources can be registered with the holder. If using any of the constructors with - /// a Session, the holder will be set to the frozen state. - /// - /// true if frozen; otherwise, false. - public virtual bool Frozen => frozen; - - /// - /// Adds the connection to the list of resources managed by this holder. - /// - /// The connection. - public void AddConnection(IConnection connection) - { - AssertUtils.IsTrue(!frozen, "Cannot add IConnection because MessageResourceHolder is frozen"); - AssertUtils.ArgumentNotNull(connection, "IConnection must not be null"); - if (!connections.Contains(connection)) - { - connections.Add(connection); - } - } - - /// - /// Adds the session to the list of resources managed by this holder. - /// - /// The session. - public void AddSession(ISession session) - { - AddSession(session, null); - } - - /// - /// Adds the session and connection to the list of resources managed by this holder. - /// - /// The session. - /// The connection. - public void AddSession(ISession session, IConnection connection) - { - AssertUtils.IsTrue(!frozen, "Cannot add ISession because MessageResourceHolder is frozen"); - AssertUtils.ArgumentNotNull(session, "ISession must not be null"); - if (!sessions.Contains(session)) - { - sessions.Add(session); - if (connection != null) - { - if (!sessionsPerIConnection.TryGetValue(connection, out var sessionsList)) - { - sessionsList = new List(); - sessionsPerIConnection[connection] = sessionsList; - } - sessionsList.Add(session); - } - } - } - - /// - /// Gets the connection managed by this resource holder - /// - /// A Connection, or null if no managed connection. - public virtual IConnection GetConnection() - { - return (connections.Count != 0 ? connections[0] : null); - } - - /// - /// Gets the connection of a given type managed by this resource holder. This is used - /// when storing Queue or Topic Connections (from the older 1.0.2 API) as compared to the - /// 'unified domain' API , just Connection, in the newer 1.2 API. - /// - /// Type of the connection. - /// The connection, or null if not found. - public virtual IConnection GetConnection(Type connectionType) - { - return (IConnection)CollectionUtils.FindValueOfType(connections, connectionType); - } - - /// - /// Gets the first session manged by this holder or null if not available. - /// - /// The session or null if not available. - public virtual ISession GetSession() - { - return sessions.Count != 0 ? sessions[0] : null; - } - - /// - /// Gets the session managed by this holder by type. - /// - /// Type of the session. - /// The session or null if not available. - public virtual ISession GetSession(Type sessionType) - { - return GetSession(sessionType, null); - } - - /// - /// Gets the session of a given type associated with the given connection - /// - /// Type of the session. - /// The connection. - /// The sessin or null if not available. - public virtual ISession GetSession(Type sessionType, IConnection connection) - { - var sessions = this.sessions; - if (connection != null) - { - sessionsPerIConnection.TryGetValue(connection, out sessions); - } - - return (ISession) CollectionUtils.FindValueOfType(sessions, sessionType); - } - - /// - /// Commits all sessions. - /// - public virtual void CommitAll() - { - foreach (ISession session in sessions) - { - session.Commit(); - } - } - - /// - /// Closes all sessions then stops and closes all connections, in that order. - /// - public virtual void CloseAll() - { - foreach (ISession session in sessions) - { - try - { - session.Close(); - } - catch (Exception ex) - { - logger.LogDebug(ex, "Could not close NMS ISession after transaction"); - } - } - foreach (IConnection connection in connections) - { - ConnectionFactoryUtils.ReleaseConnection(connection, connectionFactory, true); - } - connections.Clear(); - sessions.Clear(); - sessionsPerIConnection.Clear(); - } - - /// - /// Commits all sessions. - /// - public virtual async Task CommitAllAsync() - { - foreach (ISession session in sessions) - { - await session.CommitAsync().Awaiter(); - } - } - - /// - /// Closes all sessions then stops and closes all connections, in that order. - /// - public virtual async Task CloseAllAsync() - { - foreach (ISession session in sessions) - { - try - { - await session.CloseAsync().Awaiter(); - } - catch (Exception ex) - { - logger.LogDebug(ex, "Could not close NMS ISession after transaction"); - } - } - foreach (IConnection connection in connections) - { - await ConnectionFactoryUtils.ReleaseConnectionAsync(connection, connectionFactory, true).Awaiter(); - } - connections.Clear(); - sessions.Clear(); - sessionsPerIConnection.Clear(); - } - - /// - /// Determines whether the holder contains the specified session. - /// - /// The session. - /// - /// true if the holder contains the specified session; otherwise, false. - /// - public bool ContainsSession(ISession session) - { - return sessions.Contains(session); + connections.Add(connection); } } + + /// + /// Adds the session to the list of resources managed by this holder. + /// + /// The session. + public void AddSession(ISession session) + { + AddSession(session, null); + } + + /// + /// Adds the session and connection to the list of resources managed by this holder. + /// + /// The session. + /// The connection. + public void AddSession(ISession session, IConnection connection) + { + AssertUtils.IsTrue(!frozen, "Cannot add ISession because MessageResourceHolder is frozen"); + AssertUtils.ArgumentNotNull(session, "ISession must not be null"); + if (!sessions.Contains(session)) + { + sessions.Add(session); + if (connection != null) + { + if (!sessionsPerIConnection.TryGetValue(connection, out var sessionsList)) + { + sessionsList = new List(); + sessionsPerIConnection[connection] = sessionsList; + } + + sessionsList.Add(session); + } + } + } + + /// + /// Gets the connection managed by this resource holder + /// + /// A Connection, or null if no managed connection. + public virtual IConnection GetConnection() + { + return (connections.Count != 0 ? connections[0] : null); + } + + /// + /// Gets the connection of a given type managed by this resource holder. This is used + /// when storing Queue or Topic Connections (from the older 1.0.2 API) as compared to the + /// 'unified domain' API , just Connection, in the newer 1.2 API. + /// + /// Type of the connection. + /// The connection, or null if not found. + public virtual IConnection GetConnection(Type connectionType) + { + return (IConnection) CollectionUtils.FindValueOfType(connections, connectionType); + } + + /// + /// Gets the first session manged by this holder or null if not available. + /// + /// The session or null if not available. + public virtual ISession GetSession() + { + return sessions.Count != 0 ? sessions[0] : null; + } + + /// + /// Gets the session managed by this holder by type. + /// + /// Type of the session. + /// The session or null if not available. + public virtual ISession GetSession(Type sessionType) + { + return GetSession(sessionType, null); + } + + /// + /// Gets the session of a given type associated with the given connection + /// + /// Type of the session. + /// The connection. + /// The sessin or null if not available. + public virtual ISession GetSession(Type sessionType, IConnection connection) + { + var sessions = this.sessions; + if (connection != null) + { + sessionsPerIConnection.TryGetValue(connection, out sessions); + } + + return (ISession) CollectionUtils.FindValueOfType(sessions, sessionType); + } + + /// + /// Commits all sessions. + /// + public virtual void CommitAll() + { + foreach (ISession session in sessions) + { + session.Commit(); + } + } + + /// + /// Closes all sessions then stops and closes all connections, in that order. + /// + public virtual void CloseAll() + { + foreach (ISession session in sessions) + { + try + { + session.Close(); + } + catch (Exception ex) + { + logger.LogDebug(ex, "Could not close NMS ISession after transaction"); + } + } + + foreach (IConnection connection in connections) + { + ConnectionFactoryUtils.ReleaseConnection(connection, connectionFactory, true); + } + + connections.Clear(); + sessions.Clear(); + sessionsPerIConnection.Clear(); + } + + /// + /// Commits all sessions. + /// + public virtual async Task CommitAllAsync() + { + foreach (ISession session in sessions) + { + await session.CommitAsync().Awaiter(); + } + } + + /// + /// Closes all sessions then stops and closes all connections, in that order. + /// + public virtual async Task CloseAllAsync() + { + foreach (ISession session in sessions) + { + try + { + await session.CloseAsync().Awaiter(); + } + catch (Exception ex) + { + logger.LogDebug(ex, "Could not close NMS ISession after transaction"); + } + } + + foreach (IConnection connection in connections) + { + await ConnectionFactoryUtils.ReleaseConnectionAsync(connection, connectionFactory, true).Awaiter(); + } + + connections.Clear(); + sessions.Clear(); + sessionsPerIConnection.Clear(); + } + + /// + /// Determines whether the holder contains the specified session. + /// + /// The session. + /// + /// true if the holder contains the specified session; otherwise, false. + /// + public bool ContainsSession(ISession session) + { + return sessions.Contains(session); + } } diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/NmsTransactionManager.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/NmsTransactionManager.cs index a6306c8e..3a83be5e 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/NmsTransactionManager.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/NmsTransactionManager.cs @@ -26,407 +26,407 @@ using Spring.Objects.Factory; using Spring.Transaction; using Spring.Transaction.Support; -namespace Spring.Messaging.Nms.Connections +namespace Spring.Messaging.Nms.Connections; + +/// +/// A implementation +/// for a single NMS ConnectionFactory. Binds a +/// Connection/Session pair from the specified ConnecctionFactory to the thread, +/// potentially allowing for one thread-bound Session per ConnectionFactory. +/// +/// +/// +/// Application code is required to retrieve the transactional Session via +/// . Spring's +/// will autodetect a thread-bound Session and +/// automatically participate in it. +/// +/// +/// The use of as a target for this +/// transaction manager is strongly recommended. CachingConnectionFactory +/// uses a single NMS Connection for all NMS access in order to avoid the overhead +/// of repeated Connection creation, as well as maintaining a cache of Sessions. +/// Each transaction will then share the same NMS Connection, while still using +/// its own individual NMS Session. +/// +/// The use of a raw target ConnectionFactory would not only be inefficient +/// because of the lack of resource reuse. It might also lead to strange effects +/// when your NMS provider doesn't accept MessageProducer.close() calls +/// and/or MessageConsumer.close() calls before Session.commit(), +/// with the latter supposed to commit all the messages that have been sent through the +/// producer handle and received through the consumer handle. As a safe general solution, +/// always pass in a into this transaction manager's +/// ConnectionFactory property. +/// +/// +/// Transaction synchronization is turned off by default, as this manager might be used +/// alongside an IDbProvider based Spring transaction manager such as the +/// AdoPlatformTransactionManager, which has stronger needs for synchronization. +/// +/// +/// Juergen Hoeller +/// Mark Pollack (.NET) +public class NmsTransactionManager : AbstractPlatformTransactionManager, + IResourceTransactionManager, IInitializingObject { + #region Logging Definition + + private static readonly ILogger LOG = LogManager.GetLogger(); + + #endregion + + private IConnectionFactory connectionFactory; + /// - /// A implementation - /// for a single NMS ConnectionFactory. Binds a - /// Connection/Session pair from the specified ConnecctionFactory to the thread, - /// potentially allowing for one thread-bound Session per ConnectionFactory. + /// Initializes a new instance of the class. /// /// + /// The ConnectionFactory has to be set before using the instance. + /// This constructor can be used to prepare a NmsTemplate via a ApplicationContext, + /// typically setting the ConnectionFactory via ConnectionFactory property. /// - /// Application code is required to retrieve the transactional Session via - /// . Spring's - /// will autodetect a thread-bound Session and - /// automatically participate in it. - /// - /// - /// The use of as a target for this - /// transaction manager is strongly recommended. CachingConnectionFactory - /// uses a single NMS Connection for all NMS access in order to avoid the overhead - /// of repeated Connection creation, as well as maintaining a cache of Sessions. - /// Each transaction will then share the same NMS Connection, while still using - /// its own individual NMS Session. - /// - /// The use of a raw target ConnectionFactory would not only be inefficient - /// because of the lack of resource reuse. It might also lead to strange effects - /// when your NMS provider doesn't accept MessageProducer.close() calls - /// and/or MessageConsumer.close() calls before Session.commit(), - /// with the latter supposed to commit all the messages that have been sent through the - /// producer handle and received through the consumer handle. As a safe general solution, - /// always pass in a into this transaction manager's - /// ConnectionFactory property. - /// - /// - /// Transaction synchronization is turned off by default, as this manager might be used - /// alongside an IDbProvider based Spring transaction manager such as the + /// Turns off transaction synchronization by default, as this manager might + /// be used alongside a dbprovider-based Spring transaction manager like /// AdoPlatformTransactionManager, which has stronger needs for synchronization. + /// Only one manager is allowed to drive synchronization at any point of time. /// /// - /// Juergen Hoeller - /// Mark Pollack (.NET) - public class NmsTransactionManager : AbstractPlatformTransactionManager, - IResourceTransactionManager, IInitializingObject + public NmsTransactionManager() { + TransactionSynchronization = TransactionSynchronizationState.Never; + } - #region Logging Definition + /// + /// Initializes a new instance of the class + /// given a ConnectionFactory. + /// + /// The connection factory to obtain connections from. + public NmsTransactionManager(IConnectionFactory connectionFactory) : this() + { + ConnectionFactory = connectionFactory; + AfterPropertiesSet(); + } - private static readonly ILogger LOG = LogManager.GetLogger(); - - #endregion - - private IConnectionFactory connectionFactory; - - /// - /// Initializes a new instance of the class. - /// - /// - /// The ConnectionFactory has to be set before using the instance. - /// This constructor can be used to prepare a NmsTemplate via a ApplicationContext, - /// typically setting the ConnectionFactory via ConnectionFactory property. - /// - /// Turns off transaction synchronization by default, as this manager might - /// be used alongside a dbprovider-based Spring transaction manager like - /// AdoPlatformTransactionManager, which has stronger needs for synchronization. - /// Only one manager is allowed to drive synchronization at any point of time. - /// - /// - public NmsTransactionManager() + /// + /// Gets or sets the connection factory that this instance should manage transaction. + /// for. + /// + /// The connection factory. + public IConnectionFactory ConnectionFactory + { + get { return connectionFactory; } + set { - TransactionSynchronization = TransactionSynchronizationState.Never; - } - - /// - /// Initializes a new instance of the class - /// given a ConnectionFactory. - /// - /// The connection factory to obtain connections from. - public NmsTransactionManager(IConnectionFactory connectionFactory) : this() - { - ConnectionFactory = connectionFactory; - AfterPropertiesSet(); - } - - - /// - /// Gets or sets the connection factory that this instance should manage transaction. - /// for. - /// - /// The connection factory. - public IConnectionFactory ConnectionFactory - { - get { return connectionFactory; } - set - { - connectionFactory = value; - } - } - - #region IInitializingObject Members - - /// - /// Make sure the ConnectionFactory has been set. - /// - public void AfterPropertiesSet() - { - if (ConnectionFactory == null) - { - throw new ArgumentException("Property 'ConnectionFactory' is required."); - } - } - - #endregion - - #region IResourceTransactionManager Members - - /// - /// Gets the resource factory that this transaction manager operates on, - /// In tihs case the ConnectionFactory - /// - /// The ConnectionFactory. - public object ResourceFactory - { - get { return ConnectionFactory; } - } - - #endregion - - - /// - /// Get the MessageTransactionObject. - /// - /// he MessageTransactionObject. - protected override object DoGetTransaction() - { - MessageTransactionObject txObject = new MessageTransactionObject(); - - txObject.ResourceHolder = - (NmsResourceHolder) TransactionSynchronizationManager.GetResource(ConnectionFactory); - return txObject; - } - - - /// - /// Begin a new transaction with the given transaction definition. - /// - /// Transaction object returned by - /// . - /// instance, describing - /// propagation behavior, isolation level, timeout etc. - /// - /// Does not have to care about applying the propagation behavior, - /// as this has already been handled by this abstract manager. - /// - /// - /// In the case of creation or system errors. - /// - protected override void DoBegin(object transaction, ITransactionDefinition definition) - { - //This is the default value defined in DefaultTransactionDefinition - if (definition.TransactionIsolationLevel != IsolationLevel.ReadCommitted) - { - throw new InvalidIsolationLevelException("NMS does not support an isoliation level concept"); - } - MessageTransactionObject txObject = (MessageTransactionObject) transaction; - IConnection con = null; - ISession session = null; - try - { - con = CreateConnection(); - session = CreateSession(con); - if (LOG.IsEnabled(LogLevel.Debug)) - { - log.LogDebug("Created NMS transaction on Session [" + session + "] from Connection [" + con + "]"); - } - txObject.ResourceHolder = new NmsResourceHolder(ConnectionFactory, con, session); - txObject.ResourceHolder.SynchronizedWithTransaction = true; - int timeout = DetermineTimeout(definition); - if (timeout != DefaultTransactionDefinition.TIMEOUT_DEFAULT) - { - txObject.ResourceHolder.TimeoutInSeconds = timeout; - } - TransactionSynchronizationManager.BindResource(ConnectionFactory, txObject.ResourceHolder); - - - - } catch (NMSException ex) - { - if (session != null) - { - try - { - session.Close(); - } catch (Exception) - {} - } - if (con != null) - { - try - { - con.Close(); - } catch (Exception){} - } - throw new CannotCreateTransactionException("Could not create NMS Transaction", ex); - } - - } - - /// - /// Suspend the resources of the current transaction. - /// - /// Transaction object returned by - /// . - /// - /// An object that holds suspended resources (will be kept unexamined for passing it into - /// .) - /// - /// - /// Transaction synchronization will already have been suspended. - /// - /// - /// in case of system errors. - /// - protected override object DoSuspend(object transaction) - { - MessageTransactionObject txObject = (MessageTransactionObject) transaction; - txObject.ResourceHolder = null; - return TransactionSynchronizationManager.UnbindResource(ConnectionFactory); - } - - /// - /// Resume the resources of the current transaction. - /// - /// Transaction object returned by - /// . - /// The object that holds suspended resources as returned by - /// . - /// Transaction synchronization will be resumed afterwards. - /// - /// - /// In the case of system errors. - /// - protected override void DoResume(object transaction, object suspendedResources) - { - NmsResourceHolder conHolder = (NmsResourceHolder) suspendedResources; - TransactionSynchronizationManager.BindResource(ConnectionFactory, conHolder); - } - - /// - /// Perform an actual commit on the given transaction. - /// - /// The status representation of the transaction. - /// - /// In the case of system errors. - /// - protected override void DoCommit(DefaultTransactionStatus status) - { - MessageTransactionObject txObject = (MessageTransactionObject)status.Transaction; - ISession session = txObject.ResourceHolder.GetSession(); - try - { - if (status.Debug) - { - LOG.LogDebug("Committing NMS transaction on Session [" + session + "]"); - } - session.Commit(); - //Note that NMS does not have, TransactionRolledBackException - //See https://issues.apache.org/activemq/browse/AMQNET-93 - } - catch (NMSException ex) - { - throw new TransactionSystemException("Could not commit NMS transaction.", ex); - } - } - - /// - /// Perform an actual rollback on the given transaction. - /// - /// The status representation of the transaction. - /// - /// In the case of system errors. - /// - protected override void DoRollback(DefaultTransactionStatus status) - { - MessageTransactionObject txObject = (MessageTransactionObject)status.Transaction; - ISession session = txObject.ResourceHolder.GetSession(); - try - { - if (status.Debug) - { - LOG.LogDebug("Rolling back NMS transaction on Session [" + session + "]"); - } - session.Rollback(); - } - catch (NMSException ex) - { - throw new TransactionSystemException("Could not roll back NMS transaction.", ex); - } - } - - - /// - /// Set the given transaction rollback-only. Only called on rollback - /// if the current transaction takes part in an existing one. - /// - /// The status representation of the transaction. - /// - /// In the case of system errors. - /// - protected override void DoSetRollbackOnly(DefaultTransactionStatus status) - { - MessageTransactionObject txObject = (MessageTransactionObject)status.Transaction; - txObject.ResourceHolder.RollbackOnly = true; - } - - /// - /// Cleanup resources after transaction completion. - /// - /// Transaction object returned by - /// . - /// - /// - /// Called after - /// and - /// - /// execution on any outcome. - /// - /// - protected override void DoCleanupAfterCompletion(object transaction) - { - MessageTransactionObject txObject = (MessageTransactionObject)transaction; - TransactionSynchronizationManager.UnbindResource(ConnectionFactory); - txObject.ResourceHolder.CloseAll(); - txObject.ResourceHolder.Clear(); - } - - /// - /// Check if the given transaction object indicates an existing transaction - /// (that is, a transaction which has already started). - /// - /// Transaction object returned by - /// . - /// - /// True if there is an existing transaction. - /// - /// - /// In the case of system errors. - /// - protected override bool IsExistingTransaction(object transaction) - { - MessageTransactionObject txObject = transaction as MessageTransactionObject; - if (txObject != null) - { - return txObject.ResourceHolder != null; - } - return false; - } - - /// - /// Creates the connection via thie manager's ConnectionFactory. - /// - /// The new Connection - /// If thrown by underlying messaging APIs - protected virtual IConnection CreateConnection() - { - return ConnectionFactory.CreateConnection(); - } - - /// - /// Creates the session for the given Connection - /// - /// The connection to create a Session for. - /// the new Session - /// If thrown by underlying messaging APIs - protected virtual ISession CreateSession(IConnection connection) - { - return connection.CreateSession(AcknowledgementMode.Transactional); - } - - - /// - /// NMS Transaction object, representing a MessageResourceHolder. - /// Used as transaction object by MessageTransactionManager - /// - internal class MessageTransactionObject : ISmartTransactionObject - { - private NmsResourceHolder resourceHolder; - - - public NmsResourceHolder ResourceHolder - { - get { return resourceHolder; } - set { resourceHolder = value; } - } - - #region ISmartTransactionObject Members - - public bool RollbackOnly - { - get { return resourceHolder.RollbackOnly; } - } - - #endregion + connectionFactory = value; } } + + #region IInitializingObject Members + + /// + /// Make sure the ConnectionFactory has been set. + /// + public void AfterPropertiesSet() + { + if (ConnectionFactory == null) + { + throw new ArgumentException("Property 'ConnectionFactory' is required."); + } + } + + #endregion + + #region IResourceTransactionManager Members + + /// + /// Gets the resource factory that this transaction manager operates on, + /// In tihs case the ConnectionFactory + /// + /// The ConnectionFactory. + public object ResourceFactory + { + get { return ConnectionFactory; } + } + + #endregion + + /// + /// Get the MessageTransactionObject. + /// + /// he MessageTransactionObject. + protected override object DoGetTransaction() + { + MessageTransactionObject txObject = new MessageTransactionObject(); + + txObject.ResourceHolder = + (NmsResourceHolder) TransactionSynchronizationManager.GetResource(ConnectionFactory); + return txObject; + } + + /// + /// Begin a new transaction with the given transaction definition. + /// + /// Transaction object returned by + /// . + /// instance, describing + /// propagation behavior, isolation level, timeout etc. + /// + /// Does not have to care about applying the propagation behavior, + /// as this has already been handled by this abstract manager. + /// + /// + /// In the case of creation or system errors. + /// + protected override void DoBegin(object transaction, ITransactionDefinition definition) + { + //This is the default value defined in DefaultTransactionDefinition + if (definition.TransactionIsolationLevel != IsolationLevel.ReadCommitted) + { + throw new InvalidIsolationLevelException("NMS does not support an isoliation level concept"); + } + + MessageTransactionObject txObject = (MessageTransactionObject) transaction; + IConnection con = null; + ISession session = null; + try + { + con = CreateConnection(); + session = CreateSession(con); + if (LOG.IsEnabled(LogLevel.Debug)) + { + log.LogDebug("Created NMS transaction on Session [" + session + "] from Connection [" + con + "]"); + } + + txObject.ResourceHolder = new NmsResourceHolder(ConnectionFactory, con, session); + txObject.ResourceHolder.SynchronizedWithTransaction = true; + int timeout = DetermineTimeout(definition); + if (timeout != DefaultTransactionDefinition.TIMEOUT_DEFAULT) + { + txObject.ResourceHolder.TimeoutInSeconds = timeout; + } + + TransactionSynchronizationManager.BindResource(ConnectionFactory, txObject.ResourceHolder); + } + catch (NMSException ex) + { + if (session != null) + { + try + { + session.Close(); + } + catch (Exception) + { + } + } + + if (con != null) + { + try + { + con.Close(); + } + catch (Exception) { } + } + + throw new CannotCreateTransactionException("Could not create NMS Transaction", ex); + } + } + + /// + /// Suspend the resources of the current transaction. + /// + /// Transaction object returned by + /// . + /// + /// An object that holds suspended resources (will be kept unexamined for passing it into + /// .) + /// + /// + /// Transaction synchronization will already have been suspended. + /// + /// + /// in case of system errors. + /// + protected override object DoSuspend(object transaction) + { + MessageTransactionObject txObject = (MessageTransactionObject) transaction; + txObject.ResourceHolder = null; + return TransactionSynchronizationManager.UnbindResource(ConnectionFactory); + } + + /// + /// Resume the resources of the current transaction. + /// + /// Transaction object returned by + /// . + /// The object that holds suspended resources as returned by + /// . + /// Transaction synchronization will be resumed afterwards. + /// + /// + /// In the case of system errors. + /// + protected override void DoResume(object transaction, object suspendedResources) + { + NmsResourceHolder conHolder = (NmsResourceHolder) suspendedResources; + TransactionSynchronizationManager.BindResource(ConnectionFactory, conHolder); + } + + /// + /// Perform an actual commit on the given transaction. + /// + /// The status representation of the transaction. + /// + /// In the case of system errors. + /// + protected override void DoCommit(DefaultTransactionStatus status) + { + MessageTransactionObject txObject = (MessageTransactionObject) status.Transaction; + ISession session = txObject.ResourceHolder.GetSession(); + try + { + if (status.Debug) + { + LOG.LogDebug("Committing NMS transaction on Session [" + session + "]"); + } + + session.Commit(); + //Note that NMS does not have, TransactionRolledBackException + //See https://issues.apache.org/activemq/browse/AMQNET-93 + } + catch (NMSException ex) + { + throw new TransactionSystemException("Could not commit NMS transaction.", ex); + } + } + + /// + /// Perform an actual rollback on the given transaction. + /// + /// The status representation of the transaction. + /// + /// In the case of system errors. + /// + protected override void DoRollback(DefaultTransactionStatus status) + { + MessageTransactionObject txObject = (MessageTransactionObject) status.Transaction; + ISession session = txObject.ResourceHolder.GetSession(); + try + { + if (status.Debug) + { + LOG.LogDebug("Rolling back NMS transaction on Session [" + session + "]"); + } + + session.Rollback(); + } + catch (NMSException ex) + { + throw new TransactionSystemException("Could not roll back NMS transaction.", ex); + } + } + + /// + /// Set the given transaction rollback-only. Only called on rollback + /// if the current transaction takes part in an existing one. + /// + /// The status representation of the transaction. + /// + /// In the case of system errors. + /// + protected override void DoSetRollbackOnly(DefaultTransactionStatus status) + { + MessageTransactionObject txObject = (MessageTransactionObject) status.Transaction; + txObject.ResourceHolder.RollbackOnly = true; + } + + /// + /// Cleanup resources after transaction completion. + /// + /// Transaction object returned by + /// . + /// + /// + /// Called after + /// and + /// + /// execution on any outcome. + /// + /// + protected override void DoCleanupAfterCompletion(object transaction) + { + MessageTransactionObject txObject = (MessageTransactionObject) transaction; + TransactionSynchronizationManager.UnbindResource(ConnectionFactory); + txObject.ResourceHolder.CloseAll(); + txObject.ResourceHolder.Clear(); + } + + /// + /// Check if the given transaction object indicates an existing transaction + /// (that is, a transaction which has already started). + /// + /// Transaction object returned by + /// . + /// + /// True if there is an existing transaction. + /// + /// + /// In the case of system errors. + /// + protected override bool IsExistingTransaction(object transaction) + { + MessageTransactionObject txObject = transaction as MessageTransactionObject; + if (txObject != null) + { + return txObject.ResourceHolder != null; + } + + return false; + } + + /// + /// Creates the connection via thie manager's ConnectionFactory. + /// + /// The new Connection + /// If thrown by underlying messaging APIs + protected virtual IConnection CreateConnection() + { + return ConnectionFactory.CreateConnection(); + } + + /// + /// Creates the session for the given Connection + /// + /// The connection to create a Session for. + /// the new Session + /// If thrown by underlying messaging APIs + protected virtual ISession CreateSession(IConnection connection) + { + return connection.CreateSession(AcknowledgementMode.Transactional); + } + + /// + /// NMS Transaction object, representing a MessageResourceHolder. + /// Used as transaction object by MessageTransactionManager + /// + internal class MessageTransactionObject : ISmartTransactionObject + { + private NmsResourceHolder resourceHolder; + + public NmsResourceHolder ResourceHolder + { + get { return resourceHolder; } + set { resourceHolder = value; } + } + + #region ISmartTransactionObject Members + + public bool RollbackOnly + { + get { return resourceHolder.RollbackOnly; } + } + + #endregion + } } diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/SingleConnectionFactory.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/SingleConnectionFactory.cs index 62b16588..c054e3d7 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/SingleConnectionFactory.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/SingleConnectionFactory.cs @@ -25,704 +25,690 @@ using Spring.Messaging.Nms.Support; using Spring.Objects.Factory; using Spring.Util; -namespace Spring.Messaging.Nms.Connections +namespace Spring.Messaging.Nms.Connections; + +/// +/// A ConnectionFactory adapter that returns the same Connection +/// from all CreateConnection() calls, and ignores calls to +/// Connection.Close(). According to the JMS Connection +/// model, this is perfectly thread-safe. The +/// shared Connection can be automatically recovered in case of an Exception. +/// +/// +/// +/// You can either pass in a specific Connection directly or let this +/// factory lazily create a Connection via a given target ConnectionFactory. +/// +/// +/// Useful for testing and in applications when you want to keep using the +/// same Connection for multiple +/// calls, without having a pooling ConnectionFactory underneath. This may span +/// any number of transactions, even concurrently executing transactions. +/// +/// +/// Note that Spring's message listener containers support the use of +/// a shared Connection within each listener container instance. Using +/// SingleConnectionFactory with a MessageListenerContainer only really makes sense for +/// sharing a single Connection across multiple listener containers. +/// +/// +/// Juergen Hoeller +/// Mark Pollack +/// Mark Pollack (.NET) +public class SingleConnectionFactory : IConnectionFactory, IExceptionListener, IInitializingObject, IDisposable { + #region Logging Definition + + private static readonly ILogger LOG = LogManager.GetLogger(); + + #endregion + + #region Fields + + private IConnectionFactory targetConnectionFactory; + + private string clientId; + + private IExceptionListener exceptionListener; + + private bool reconnectOnException = false; + /// - /// A ConnectionFactory adapter that returns the same Connection - /// from all CreateConnection() calls, and ignores calls to - /// Connection.Close(). According to the JMS Connection - /// model, this is perfectly thread-safe. The - /// shared Connection can be automatically recovered in case of an Exception. + /// Wrapped Connection + /// + private IConnection target; + + /// + /// Proxy Connection + /// + private IConnection connection; + + /// + /// Whether the shared Connection has been started + /// + private bool started = false; + + /// + /// Synchronization monitor for the shared Connection + /// + private SemaphoreSlimLock connectionMonitor = new SemaphoreSlimLock(); + + #endregion + + #region Constructors + + /// + /// Initializes a new instance of the class. + /// + public SingleConnectionFactory() + { + } + + /// + /// Initializes a new instance of the class + /// that alwasy returns the given Connection. + /// + /// The single Connection. + public SingleConnectionFactory(IConnection target) + { + AssertUtils.ArgumentNotNull(target, "connection", "TargetSession Connection must not be null"); + this.target = target; + connection = GetSharedConnection(target); + } + + /// + /// Initializes a new instance of the class + /// that alwasy returns a single Connection. + /// + /// The target connection factory. + public SingleConnectionFactory(IConnectionFactory targetConnectionFactory) + { + AssertUtils.ArgumentNotNull(targetConnectionFactory, "targetConnectionFactory", + "TargetSession ConnectionFactory must not be null"); + this.targetConnectionFactory = targetConnectionFactory; + } + + #endregion + + #region Properties + + /// + /// Gets or sets the target connection factory which will be used to create a single + /// connection. + /// + /// The target connection factory. + public IConnectionFactory TargetConnectionFactory + { + get { return targetConnectionFactory; } + set { targetConnectionFactory = value; } + } + + /// + /// Gets or sets the client id for the single Connection created and exposed by + /// this ConnectionFactory. + /// + /// Note that the client IDs need to be unique among all active + /// Connections of teh underlying provider. Furthermore, a client ID can only + /// be assigned if the original ConnectionFactory hasn't already assigned one. + /// The client id. + public string ClientId + { + get { return clientId; } + set { clientId = value; } + } + + /// + /// Gets or sets the exception listener implementation that should be registered + /// with with the single Connection created by this factory, if any. + /// + /// The exception listener. + public IExceptionListener ExceptionListener + { + get { return exceptionListener; } + set { exceptionListener = value; } + } + + /// + /// Gets or sets a value indicating whether the single Connection + /// should be reset (to be subsequently renewed) when a NMSException + /// is reported by the underlying Connection. /// /// + /// Default is false. Switch this to true + /// to automatically trigger recover based on your messaging provider's + /// exception notifications. /// - /// You can either pass in a specific Connection directly or let this - /// factory lazily create a Connection via a given target ConnectionFactory. - /// - /// - /// Useful for testing and in applications when you want to keep using the - /// same Connection for multiple - /// calls, without having a pooling ConnectionFactory underneath. This may span - /// any number of transactions, even concurrently executing transactions. - /// - /// - /// Note that Spring's message listener containers support the use of - /// a shared Connection within each listener container instance. Using - /// SingleConnectionFactory with a MessageListenerContainer only really makes sense for - /// sharing a single Connection across multiple listener containers. + /// Internally, this will lead to a special ExceptionListener (this + /// SingleConnectionFactory itself) being registered with the underlying + /// Connection. This can also be combined with a user-specified + /// ExceptionListener, if desired. /// /// - /// Juergen Hoeller - /// Mark Pollack - /// Mark Pollack (.NET) - public class SingleConnectionFactory : IConnectionFactory, IExceptionListener, IInitializingObject, IDisposable + /// + /// true attempt to reconnect on exception during next access; otherwise, false. + /// + public bool ReconnectOnException { - #region Logging Definition + get { return reconnectOnException; } + set { reconnectOnException = value; } + } - private static readonly ILogger LOG = LogManager.GetLogger(); + public INMSContext CreateContext(string userName, string password, AcknowledgementMode acknowledgementMode) + { + throw new InvalidOperationException("SingleConnectionFactory does not support custom username and password."); + } - #endregion + public Task CreateContextAsync() + { + return CreateContextAsync(AcknowledgementMode.AutoAcknowledge); + } - #region Fields + public async Task CreateContextAsync(AcknowledgementMode acknowledgementMode) + { + var conn = await CreateConnectionAsync().Awaiter(); + return new NmsContext(conn, acknowledgementMode); + } - private IConnectionFactory targetConnectionFactory; + public Task CreateContextAsync(string userName, string password) + { + throw new InvalidOperationException("SingleConnectionFactory does not support custom username and password."); + } - private string clientId; + public Task CreateContextAsync(string userName, string password, AcknowledgementMode acknowledgementMode) + { + throw new InvalidOperationException("SingleConnectionFactory does not support custom username and password."); + } - private IExceptionListener exceptionListener; + /// + /// Get/or set the broker Uri. + /// + public Uri BrokerUri + { + get { return targetConnectionFactory.BrokerUri; } + set { targetConnectionFactory.BrokerUri = value; } + } - private bool reconnectOnException = false; + /// + /// Get/or set the redelivery policy that new IConnection objects are + /// assigned upon creation. + /// + public IRedeliveryPolicy RedeliveryPolicy + { + get { return targetConnectionFactory.RedeliveryPolicy; } + set { targetConnectionFactory.RedeliveryPolicy = value; } + } - /// - /// Wrapped Connection - /// - private IConnection target; + /// + /// A Delegate that is called each time a Message is dispatched to allow the client to do + /// any necessary transformations on the received message before it is delivered. The + /// ConnectionFactory sets the provided delegate instance on each Connection instance that + /// is created from this factory, each connection in turn passes the delegate along to each + /// Session it creates which then passes that along to the Consumers it creates. + /// + /// + public ConsumerTransformerDelegate ConsumerTransformer + { + get { return targetConnectionFactory.ConsumerTransformer; } + set { targetConnectionFactory.ConsumerTransformer = value; } + } - /// - /// Proxy Connection - /// - private IConnection connection; + /// + /// A delegate that is called each time a Message is sent from this Producer which allows + /// the application to perform any needed transformations on the Message before it is sent. + /// The ConnectionFactory sets the provided delegate instance on each Connection instance that + /// is created from this factory, each connection in turn passes the delegate along to each + /// Session it creates which then passes that along to the Producers it creates. + /// + /// + public ProducerTransformerDelegate ProducerTransformer + { + get { return targetConnectionFactory.ProducerTransformer; } + set { targetConnectionFactory.ProducerTransformer = value; } + } + /// + /// Gets the connection monitor. + /// + /// The connection monitor. + internal SemaphoreSlimLock ConnectionMonitor + { + get { return connectionMonitor; } + } - /// - /// Whether the shared Connection has been started - /// - private bool started = false; + /// + /// Gets a value indicating whether this instance is started. + /// + /// + /// true if this instance is started; otherwise, false. + /// + internal bool IsStarted + { + get { return started; } + set { started = value; } + } - /// - /// Synchronization monitor for the shared Connection - /// - private SemaphoreSlimLock connectionMonitor = new SemaphoreSlimLock(); + #endregion - #endregion + #region IConnectionFactory Members - #region Constructors + /// + /// Creates the connection. + /// + /// A single shared connection + public IConnection CreateConnection() + { + return CreateConnectionAsync().GetAsyncResult(); + } - /// - /// Initializes a new instance of the class. - /// - public SingleConnectionFactory() + /// + /// Creates the connection. + /// + /// Name of the user. + /// The password. + /// + public IConnection CreateConnection(string userName, string password) + { + throw new InvalidOperationException("SingleConnectionFactory does not support custom username and password."); + } + + public async Task CreateConnectionAsync() + { + using (await connectionMonitor.LockAsync().Awaiter()) { - } - - - /// - /// Initializes a new instance of the class - /// that alwasy returns the given Connection. - /// - /// The single Connection. - public SingleConnectionFactory(IConnection target) - { - AssertUtils.ArgumentNotNull(target, "connection", "TargetSession Connection must not be null"); - this.target = target; - connection = GetSharedConnection(target); - } - - - /// - /// Initializes a new instance of the class - /// that alwasy returns a single Connection. - /// - /// The target connection factory. - public SingleConnectionFactory(IConnectionFactory targetConnectionFactory) - { - AssertUtils.ArgumentNotNull(targetConnectionFactory, "targetConnectionFactory", - "TargetSession ConnectionFactory must not be null"); - this.targetConnectionFactory = targetConnectionFactory; - } - - #endregion - - #region Properties - - /// - /// Gets or sets the target connection factory which will be used to create a single - /// connection. - /// - /// The target connection factory. - public IConnectionFactory TargetConnectionFactory - { - get { return targetConnectionFactory; } - set { targetConnectionFactory = value; } - } - - - /// - /// Gets or sets the client id for the single Connection created and exposed by - /// this ConnectionFactory. - /// - /// Note that the client IDs need to be unique among all active - /// Connections of teh underlying provider. Furthermore, a client ID can only - /// be assigned if the original ConnectionFactory hasn't already assigned one. - /// The client id. - public string ClientId - { - get { return clientId; } - set { clientId = value; } - } - - - /// - /// Gets or sets the exception listener implementation that should be registered - /// with with the single Connection created by this factory, if any. - /// - /// The exception listener. - public IExceptionListener ExceptionListener - { - get { return exceptionListener; } - set { exceptionListener = value; } - } - - /// - /// Gets or sets a value indicating whether the single Connection - /// should be reset (to be subsequently renewed) when a NMSException - /// is reported by the underlying Connection. - /// - /// - /// Default is false. Switch this to true - /// to automatically trigger recover based on your messaging provider's - /// exception notifications. - /// - /// Internally, this will lead to a special ExceptionListener (this - /// SingleConnectionFactory itself) being registered with the underlying - /// Connection. This can also be combined with a user-specified - /// ExceptionListener, if desired. - /// - /// - /// - /// true attempt to reconnect on exception during next access; otherwise, false. - /// - public bool ReconnectOnException - { - get { return reconnectOnException; } - set { reconnectOnException = value; } - } - - public INMSContext CreateContext(string userName, string password, AcknowledgementMode acknowledgementMode) - { - throw new InvalidOperationException("SingleConnectionFactory does not support custom username and password."); - } - - public Task CreateContextAsync() - { - return CreateContextAsync(AcknowledgementMode.AutoAcknowledge); - } - - public async Task CreateContextAsync(AcknowledgementMode acknowledgementMode) - { - var conn = await CreateConnectionAsync().Awaiter(); - return new NmsContext(conn, acknowledgementMode); - } - - public Task CreateContextAsync(string userName, string password) - { - throw new InvalidOperationException("SingleConnectionFactory does not support custom username and password."); - } - - public Task CreateContextAsync(string userName, string password, AcknowledgementMode acknowledgementMode) - { - throw new InvalidOperationException("SingleConnectionFactory does not support custom username and password."); - } - - /// - /// Get/or set the broker Uri. - /// - public Uri BrokerUri - { - get { return targetConnectionFactory.BrokerUri; } - set { targetConnectionFactory.BrokerUri = value; } - } - - /// - /// Get/or set the redelivery policy that new IConnection objects are - /// assigned upon creation. - /// - public IRedeliveryPolicy RedeliveryPolicy - { - get { return targetConnectionFactory.RedeliveryPolicy; } - set { targetConnectionFactory.RedeliveryPolicy = value; } - } - - /// - /// A Delegate that is called each time a Message is dispatched to allow the client to do - /// any necessary transformations on the received message before it is delivered. The - /// ConnectionFactory sets the provided delegate instance on each Connection instance that - /// is created from this factory, each connection in turn passes the delegate along to each - /// Session it creates which then passes that along to the Consumers it creates. - /// - /// - public ConsumerTransformerDelegate ConsumerTransformer - { - get { return targetConnectionFactory.ConsumerTransformer; } - set { targetConnectionFactory.ConsumerTransformer = value; } - } - - /// - /// A delegate that is called each time a Message is sent from this Producer which allows - /// the application to perform any needed transformations on the Message before it is sent. - /// The ConnectionFactory sets the provided delegate instance on each Connection instance that - /// is created from this factory, each connection in turn passes the delegate along to each - /// Session it creates which then passes that along to the Producers it creates. - /// - /// - public ProducerTransformerDelegate ProducerTransformer - { - get { return targetConnectionFactory.ProducerTransformer; } - set { targetConnectionFactory.ProducerTransformer = value; } - } - - /// - /// Gets the connection monitor. - /// - /// The connection monitor. - internal SemaphoreSlimLock ConnectionMonitor - { - get { return connectionMonitor; } - } - - /// - /// Gets a value indicating whether this instance is started. - /// - /// - /// true if this instance is started; otherwise, false. - /// - internal bool IsStarted - { - get { return started; } - set { started = value; } - } - - #endregion - - #region IConnectionFactory Members - - /// - /// Creates the connection. - /// - /// A single shared connection - public IConnection CreateConnection() - { - return CreateConnectionAsync().GetAsyncResult(); - } - - - - /// - /// Creates the connection. - /// - /// Name of the user. - /// The password. - /// - public IConnection CreateConnection(string userName, string password) - { - throw new InvalidOperationException("SingleConnectionFactory does not support custom username and password."); - } - - public async Task CreateConnectionAsync() - { - using(await connectionMonitor.LockAsync().Awaiter()) + if (connection == null) { - if (connection == null) - { - await InitConnectionAsync(false).Awaiter(); - } - - return connection; - } - } - - public Task CreateConnectionAsync(string userName, string password) - { - throw new InvalidOperationException("SingleConnectionFactory does not support custom username and password."); - } - - public INMSContext CreateContext() - { - return CreateContext(AcknowledgementMode.AutoAcknowledge); - } - - public INMSContext CreateContext(AcknowledgementMode acknowledgementMode) - { - return CreateContextAsync(acknowledgementMode).GetAsyncResult(); - } - - public INMSContext CreateContext(string userName, string password) - { - throw new InvalidOperationException("SingleConnectionFactory does not support custom username and password."); - } - - #endregion - - /// - /// Initialize the underlying shared Connection. Closes and reinitializes the Connection if an underlying - /// Connection is present already. - /// - public async Task InitConnectionAsync(bool acquireLock = true) - { - if (TargetConnectionFactory == null) - { - throw new ArgumentException( - "'TargetConnectionFactory' is required for lazily initializing a Connection"); + await InitConnectionAsync(false).Awaiter(); } - using (await connectionMonitor.LockAsync(acquireLock).Awaiter()) - { - if (this.target != null) - { - CloseConnection(this.target); - } - - this.target = DoCreateConnection(); - PrepareConnection(this.target); - if (LOG.IsEnabled(LogLevel.Debug)) - { - LOG.LogInformation("Established shared NMS Connection: " + this.target); - } - - this.connection = GetSharedConnection(target, acquireLock); - } - } - - /// - /// Exception listener callback that renews the underlying single Connection. - /// - /// The exception from the messaging infrastructure. - public void OnException(Exception exception) - { - ResetConnection(); - } - - /// - /// Prepares the connection before it is exposed. - /// The default implementation applies ExceptionListener and client id. - /// Can be overridden in subclasses. - /// - /// The Connection to prepare. - /// if thrown by any NMS API methods. - protected virtual void PrepareConnection(IConnection con) - { - if (ClientId != null) - { - con.ClientId = ClientId; - } - - if (reconnectOnException) - { - //add reconnect exception handler first to exception chain. - con.ExceptionListener += this.OnException; - } - - if (ExceptionListener != null) - { - con.ExceptionListener += ExceptionListener.OnException; - } - } - - /// - /// Template method for obtaining a (potentially cached) Session. - /// - /// The connection to operate on. - /// The session ack mode. - /// the Session to use, or null to indicate - /// creation of a raw standard Session - public virtual ISession GetSession(IConnection con, AcknowledgementMode mode) - { - return null; - } - - public virtual Task GetSessionAsync(IConnection con, AcknowledgementMode mode) - { - return Task.FromResult((ISession) null); - } - - /// - /// reate a JMS Connection via this template's ConnectionFactory. - /// - /// - protected virtual IConnection DoCreateConnection() - { - return TargetConnectionFactory.CreateConnection(); - } - - /// - /// Closes the given connection. - /// - /// The connection. - protected virtual void CloseConnection(IConnection con) - { - if (LOG.IsEnabled(LogLevel.Debug)) - { - LOG.LogDebug("Closing shared NMS Connection: " + this.target); - } - - try - { - try - { - if (this.started) - { - this.started = false; - con.Stop(); - } - } - finally - { - con.Close(); - } - } - catch (Exception ex) - { - LOG.LogWarning(ex, "Could not close shared NMS connection."); - } - } - - #region IInitializingObject Members - - /// - /// Ensure that the connection or TargetConnectionFactory are specified. - /// - public void AfterPropertiesSet() - { - if (connection == null && TargetConnectionFactory == null) - { - throw new ArgumentException("Connection or 'TargetConnectionFactory' is required."); - } - } - - #endregion - - - /// - /// Close the underlying shared connection. The provider of this ConnectionFactory needs to care for proper shutdown. - /// As this object implements an application context will automatically - /// invoke this on distruction o - /// - public void Dispose() - { - ResetConnection(); - } - - /// - /// Resets the underlying shared Connection, to be reinitialized on next access. - /// - public virtual void ResetConnection() - { - using(connectionMonitor.Lock()) - { - if (this.target != null) - { - CloseConnection(this.target); - } - - this.target = null; - this.connection = null; - } - } - - /// - /// Wrap the given Connection with a proxy that delegates every method call to it - /// but suppresses close calls. This is useful for allowing application code to - /// handle a special framework Connection just like an ordinary Connection from a - /// ConnectionFactory. - /// - /// The original connection to wrap. - /// the wrapped connection - protected virtual IConnection GetSharedConnection(IConnection target, bool acquireLock = true) - { - using(connectionMonitor.Lock(acquireLock)) - { - return new CloseSupressingConnection(this, target); - } + return connection; } } - - internal class CloseSupressingConnection : IConnection + + public Task CreateConnectionAsync(string userName, string password) { - private IConnection target; - private SingleConnectionFactory singleConnectionFactory; + throw new InvalidOperationException("SingleConnectionFactory does not support custom username and password."); + } - public CloseSupressingConnection(SingleConnectionFactory singleConnectionFactory, IConnection target) + public INMSContext CreateContext() + { + return CreateContext(AcknowledgementMode.AutoAcknowledge); + } + + public INMSContext CreateContext(AcknowledgementMode acknowledgementMode) + { + return CreateContextAsync(acknowledgementMode).GetAsyncResult(); + } + + public INMSContext CreateContext(string userName, string password) + { + throw new InvalidOperationException("SingleConnectionFactory does not support custom username and password."); + } + + #endregion + + /// + /// Initialize the underlying shared Connection. Closes and reinitializes the Connection if an underlying + /// Connection is present already. + /// + public async Task InitConnectionAsync(bool acquireLock = true) + { + if (TargetConnectionFactory == null) { - this.target = target; - this.singleConnectionFactory = singleConnectionFactory; + throw new ArgumentException( + "'TargetConnectionFactory' is required for lazily initializing a Connection"); } - public string ClientId + using (await connectionMonitor.LockAsync(acquireLock).Awaiter()) { - get { return target.ClientId; } - set + if (this.target != null) { - string currentClientId = target.ClientId; - if (currentClientId != null && currentClientId.Equals(value)) + CloseConnection(this.target); + } + + this.target = DoCreateConnection(); + PrepareConnection(this.target); + if (LOG.IsEnabled(LogLevel.Debug)) + { + LOG.LogInformation("Established shared NMS Connection: " + this.target); + } + + this.connection = GetSharedConnection(target, acquireLock); + } + } + + /// + /// Exception listener callback that renews the underlying single Connection. + /// + /// The exception from the messaging infrastructure. + public void OnException(Exception exception) + { + ResetConnection(); + } + + /// + /// Prepares the connection before it is exposed. + /// The default implementation applies ExceptionListener and client id. + /// Can be overridden in subclasses. + /// + /// The Connection to prepare. + /// if thrown by any NMS API methods. + protected virtual void PrepareConnection(IConnection con) + { + if (ClientId != null) + { + con.ClientId = ClientId; + } + + if (reconnectOnException) + { + //add reconnect exception handler first to exception chain. + con.ExceptionListener += this.OnException; + } + + if (ExceptionListener != null) + { + con.ExceptionListener += ExceptionListener.OnException; + } + } + + /// + /// Template method for obtaining a (potentially cached) Session. + /// + /// The connection to operate on. + /// The session ack mode. + /// the Session to use, or null to indicate + /// creation of a raw standard Session + public virtual ISession GetSession(IConnection con, AcknowledgementMode mode) + { + return null; + } + + public virtual Task GetSessionAsync(IConnection con, AcknowledgementMode mode) + { + return Task.FromResult((ISession) null); + } + + /// + /// reate a JMS Connection via this template's ConnectionFactory. + /// + /// + protected virtual IConnection DoCreateConnection() + { + return TargetConnectionFactory.CreateConnection(); + } + + /// + /// Closes the given connection. + /// + /// The connection. + protected virtual void CloseConnection(IConnection con) + { + if (LOG.IsEnabled(LogLevel.Debug)) + { + LOG.LogDebug("Closing shared NMS Connection: " + this.target); + } + + try + { + try + { + if (this.started) { - //ok, the values are consistent. - } - else - { - throw new ArgumentException( - "Setting of 'ClientID' property not supported on wrapper for shared Connection since" + - "this is a shared connection that may serve any number of clients concurrently." + - "Set the 'ClientId' property on the SingleConnectionFactory instead."); + this.started = false; + con.Stop(); } } - } - - - public void Close() - { - // don't pass the call to the target. - } - - public Task CloseAsync() - { - return Task.FromResult(true); // no CompletedTask available - } - - public ConsumerTransformerDelegate ConsumerTransformer - { - get { return target.ConsumerTransformer; } - set { target.ConsumerTransformer = value; } - } - - public ProducerTransformerDelegate ProducerTransformer - { - get { return target.ProducerTransformer; } - set { target.ProducerTransformer = value; } - } - - public TimeSpan RequestTimeout - { - get { return target.RequestTimeout; } - set { target.RequestTimeout = value; } - } - - public void Start() - { - // Handle start method: track started state. - target.Start(); - using(singleConnectionFactory.ConnectionMonitor.Lock()) + finally { - singleConnectionFactory.IsStarted = true; + con.Close(); } } - - public async Task StartAsync() + catch (Exception ex) { - await target.StartAsync().Awaiter(); - using(await singleConnectionFactory.ConnectionMonitor.LockAsync().Awaiter()) + LOG.LogWarning(ex, "Could not close shared NMS connection."); + } + } + + #region IInitializingObject Members + + /// + /// Ensure that the connection or TargetConnectionFactory are specified. + /// + public void AfterPropertiesSet() + { + if (connection == null && TargetConnectionFactory == null) + { + throw new ArgumentException("Connection or 'TargetConnectionFactory' is required."); + } + } + + #endregion + + /// + /// Close the underlying shared connection. The provider of this ConnectionFactory needs to care for proper shutdown. + /// As this object implements an application context will automatically + /// invoke this on distruction o + /// + public void Dispose() + { + ResetConnection(); + } + + /// + /// Resets the underlying shared Connection, to be reinitialized on next access. + /// + public virtual void ResetConnection() + { + using (connectionMonitor.Lock()) + { + if (this.target != null) { - singleConnectionFactory.IsStarted = true; - } - } - - public void Stop() - { - //don't pass the call to the target as it would stop receiving for all clients sharing this connection. - } - - public Task StopAsync() - { - //don't pass the call to the target as it would stop receiving for all clients sharing this connection. - return Task.FromResult(true); - } - - public ISession CreateSession() - { - return CreateSession(AcknowledgementMode.AutoAcknowledge); - } - - public ISession CreateSession(AcknowledgementMode acknowledgementMode) - { - ISession session = singleConnectionFactory.GetSession(target, acknowledgementMode); - if (session != null) - { - return session; + CloseConnection(this.target); } - return target.CreateSession(acknowledgementMode); + this.target = null; + this.connection = null; } + } - public Task CreateSessionAsync() + /// + /// Wrap the given Connection with a proxy that delegates every method call to it + /// but suppresses close calls. This is useful for allowing application code to + /// handle a special framework Connection just like an ordinary Connection from a + /// ConnectionFactory. + /// + /// The original connection to wrap. + /// the wrapped connection + protected virtual IConnection GetSharedConnection(IConnection target, bool acquireLock = true) + { + using (connectionMonitor.Lock(acquireLock)) { - return CreateSessionAsync(AcknowledgementMode.AutoAcknowledge); - } - - public async Task CreateSessionAsync(AcknowledgementMode acknowledgementMode) - { - ISession session = await singleConnectionFactory.GetSessionAsync(target, acknowledgementMode).Awaiter(); - if (session != null) - { - return session; - } - - return await target.CreateSessionAsync(acknowledgementMode).Awaiter(); - } - - - #region Pass through implementations to the target connection - - public void PurgeTempDestinations() - { - target.PurgeTempDestinations(); - } - - public event ExceptionListener ExceptionListener - { - add { target.ExceptionListener += value; } - remove { target.ExceptionListener -= value; } - } - - public event ConnectionInterruptedListener ConnectionInterruptedListener - { - add { target.ConnectionInterruptedListener += value; } - remove { target.ConnectionInterruptedListener -= value; } - } - - public event ConnectionResumedListener ConnectionResumedListener - { - add { target.ConnectionResumedListener += value; } - remove { target.ConnectionResumedListener -= value; } - } - - - public AcknowledgementMode AcknowledgementMode - { - get { return target.AcknowledgementMode; } - set { target.AcknowledgementMode = value; } - } - - public void Dispose() - { - target.Dispose(); - } - - - public bool IsStarted - { - get { return target.IsStarted; } - } - - - public IConnectionMetaData MetaData - { - get { return target.MetaData; } - } - - - public IRedeliveryPolicy RedeliveryPolicy - { - get { return target.RedeliveryPolicy; } - set { target.RedeliveryPolicy = value; } - } - #endregion - - /// - /// Add information to show this is a shared NMS connection - /// - /// Description of connection wrapper - public override string ToString() - { - return "Shared NMS Connection: " + this.target; + return new CloseSupressingConnection(this, target); } } } + +internal class CloseSupressingConnection : IConnection +{ + private IConnection target; + private SingleConnectionFactory singleConnectionFactory; + + public CloseSupressingConnection(SingleConnectionFactory singleConnectionFactory, IConnection target) + { + this.target = target; + this.singleConnectionFactory = singleConnectionFactory; + } + + public string ClientId + { + get { return target.ClientId; } + set + { + string currentClientId = target.ClientId; + if (currentClientId != null && currentClientId.Equals(value)) + { + //ok, the values are consistent. + } + else + { + throw new ArgumentException( + "Setting of 'ClientID' property not supported on wrapper for shared Connection since" + + "this is a shared connection that may serve any number of clients concurrently." + + "Set the 'ClientId' property on the SingleConnectionFactory instead."); + } + } + } + + public void Close() + { + // don't pass the call to the target. + } + + public Task CloseAsync() + { + return Task.FromResult(true); // no CompletedTask available + } + + public ConsumerTransformerDelegate ConsumerTransformer + { + get { return target.ConsumerTransformer; } + set { target.ConsumerTransformer = value; } + } + + public ProducerTransformerDelegate ProducerTransformer + { + get { return target.ProducerTransformer; } + set { target.ProducerTransformer = value; } + } + + public TimeSpan RequestTimeout + { + get { return target.RequestTimeout; } + set { target.RequestTimeout = value; } + } + + public void Start() + { + // Handle start method: track started state. + target.Start(); + using (singleConnectionFactory.ConnectionMonitor.Lock()) + { + singleConnectionFactory.IsStarted = true; + } + } + + public async Task StartAsync() + { + await target.StartAsync().Awaiter(); + using (await singleConnectionFactory.ConnectionMonitor.LockAsync().Awaiter()) + { + singleConnectionFactory.IsStarted = true; + } + } + + public void Stop() + { + //don't pass the call to the target as it would stop receiving for all clients sharing this connection. + } + + public Task StopAsync() + { + //don't pass the call to the target as it would stop receiving for all clients sharing this connection. + return Task.FromResult(true); + } + + public ISession CreateSession() + { + return CreateSession(AcknowledgementMode.AutoAcknowledge); + } + + public ISession CreateSession(AcknowledgementMode acknowledgementMode) + { + ISession session = singleConnectionFactory.GetSession(target, acknowledgementMode); + if (session != null) + { + return session; + } + + return target.CreateSession(acknowledgementMode); + } + + public Task CreateSessionAsync() + { + return CreateSessionAsync(AcknowledgementMode.AutoAcknowledge); + } + + public async Task CreateSessionAsync(AcknowledgementMode acknowledgementMode) + { + ISession session = await singleConnectionFactory.GetSessionAsync(target, acknowledgementMode).Awaiter(); + if (session != null) + { + return session; + } + + return await target.CreateSessionAsync(acknowledgementMode).Awaiter(); + } + + #region Pass through implementations to the target connection + + public void PurgeTempDestinations() + { + target.PurgeTempDestinations(); + } + + public event ExceptionListener ExceptionListener + { + add { target.ExceptionListener += value; } + remove { target.ExceptionListener -= value; } + } + + public event ConnectionInterruptedListener ConnectionInterruptedListener + { + add { target.ConnectionInterruptedListener += value; } + remove { target.ConnectionInterruptedListener -= value; } + } + + public event ConnectionResumedListener ConnectionResumedListener + { + add { target.ConnectionResumedListener += value; } + remove { target.ConnectionResumedListener -= value; } + } + + public AcknowledgementMode AcknowledgementMode + { + get { return target.AcknowledgementMode; } + set { target.AcknowledgementMode = value; } + } + + public void Dispose() + { + target.Dispose(); + } + + public bool IsStarted + { + get { return target.IsStarted; } + } + + public IConnectionMetaData MetaData + { + get { return target.MetaData; } + } + + public IRedeliveryPolicy RedeliveryPolicy + { + get { return target.RedeliveryPolicy; } + set { target.RedeliveryPolicy = value; } + } + + #endregion + + /// + /// Add information to show this is a shared NMS connection + /// + /// Description of connection wrapper + public override string ToString() + { + return "Shared NMS Connection: " + this.target; + } +} diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/SynchedLocalTransactionFailedException.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/SynchedLocalTransactionFailedException.cs index 023151a8..c3cfaf37 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/SynchedLocalTransactionFailedException.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/SynchedLocalTransactionFailedException.cs @@ -21,60 +21,59 @@ using System.Runtime.Serialization; using Apache.NMS; -namespace Spring.Messaging.Nms.Connections +namespace Spring.Messaging.Nms.Connections; + +/// Exception thrown when a synchronized local transaction failed to complete +/// (after the main transaction has already completed). +/// +/// Jergen Hoeller +/// Mark Pollack (.NET) +[Serializable] +public class SynchedLocalTransactionFailedException : NMSException { - /// Exception thrown when a synchronized local transaction failed to complete - /// (after the main transaction has already completed). + #region Constructor (s) / Destructor + + /// + /// Initializes a new instance of the class. /// - /// Jergen Hoeller - /// Mark Pollack (.NET) - [Serializable] - public class SynchedLocalTransactionFailedException : NMSException + public SynchedLocalTransactionFailedException() { - #region Constructor (s) / Destructor - - /// - /// Initializes a new instance of the class. - /// - public SynchedLocalTransactionFailedException() - { - } - - /// - /// Creates a new instance of the SynchedLocalTransactionFailedException class. with the specified message. - /// - /// - /// A message about the exception. - /// - public SynchedLocalTransactionFailedException (string message) : base(message) - { - } - - /// - /// Creates a new instance of the SynchedLocalTransactionFailedException class with the specified message - /// and root cause. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception that is being wrapped. - /// - public SynchedLocalTransactionFailedException (string message, Exception rootCause) - : base(message, rootCause) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The SerializationInfo that holds the serialized object data about the exception being thrown. - /// The StreamingContext that contains contextual information about the source or destination. - protected SynchedLocalTransactionFailedException(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } - - #endregion } + + /// + /// Creates a new instance of the SynchedLocalTransactionFailedException class. with the specified message. + /// + /// + /// A message about the exception. + /// + public SynchedLocalTransactionFailedException(string message) : base(message) + { + } + + /// + /// Creates a new instance of the SynchedLocalTransactionFailedException class with the specified message + /// and root cause. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception that is being wrapped. + /// + public SynchedLocalTransactionFailedException(string message, Exception rootCause) + : base(message, rootCause) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The SerializationInfo that holds the serialized object data about the exception being thrown. + /// The StreamingContext that contains contextual information about the source or destination. + protected SynchedLocalTransactionFailedException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + + #endregion } diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/UserCredentialsConnectionFactoryAdapter.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/UserCredentialsConnectionFactoryAdapter.cs index a3b630e3..4c930a60 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/UserCredentialsConnectionFactoryAdapter.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/UserCredentialsConnectionFactoryAdapter.cs @@ -15,193 +15,190 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + #endregion using Apache.NMS; -namespace Spring.Messaging.Nms.Connections +namespace Spring.Messaging.Nms.Connections; + +/// +/// An adapter for a target JMS {@link javax.jms.ConnectionFactory}, applying the +/// given user credentials to every standard CreateConnection() call, +/// that is, implicitly invoking CreateConnection(username, password) +/// on the target.All other methods simply delegate to the corresponding methods +/// of the target ConnectionFactory. +/// +/// +/// Can be used to proxy a target NMS ConnectionFactory that does not have user +/// credentials configured. Client code can work with the ConnectionFactory without +/// passing in username and password on every CreateConnection() call. +/// If the "Username" is empty, this proxy will simply delegate to the standard +/// CreateConnection() method of the target ConnectionFactory. +/// This can be used to keep a UserCredentialsConnectionFactoryAdapter +/// definition just for the option of implicitly passing in user credentials +/// if the particular target ConnectionFactory requires it. +/// +public class UserCredentialsConnectionFactoryAdapter : IConnectionFactory { - /// - /// An adapter for a target JMS {@link javax.jms.ConnectionFactory}, applying the - /// given user credentials to every standard CreateConnection() call, - /// that is, implicitly invoking CreateConnection(username, password) - /// on the target.All other methods simply delegate to the corresponding methods - /// of the target ConnectionFactory. - /// - /// - /// Can be used to proxy a target NMS ConnectionFactory that does not have user - /// credentials configured. Client code can work with the ConnectionFactory without - /// passing in username and password on every CreateConnection() call. - /// If the "Username" is empty, this proxy will simply delegate to the standard - /// CreateConnection() method of the target ConnectionFactory. - /// This can be used to keep a UserCredentialsConnectionFactoryAdapter - /// definition just for the option of implicitly passing in user credentials - /// if the particular target ConnectionFactory requires it. - /// - public class UserCredentialsConnectionFactoryAdapter:IConnectionFactory + private readonly IConnectionFactory _wrappedConnectionFactory; + + private readonly ThreadLocal threadLocalCredentials = new ThreadLocal(); + + public UserCredentialsConnectionFactoryAdapter(IConnectionFactory wrappedConnectionFactory) { - private readonly IConnectionFactory _wrappedConnectionFactory; + this._wrappedConnectionFactory = wrappedConnectionFactory; + } - private readonly ThreadLocal threadLocalCredentials = new ThreadLocal(); + /// + /// Set user credentials for this proxy and the current thread. + /// The given username and password will be applied to all subsequent + /// CreateConnection() calls on this ConnectionFactory proxy. + /// This will override any statically specified user credentials, + /// that is, values of the "username" and "password" properties. + /// + public void SetCredentialsForCurrentThread(string userName, string password) + { + this.threadLocalCredentials.Value = new NmsUserCredentials(userName, password); + } - public UserCredentialsConnectionFactoryAdapter(IConnectionFactory wrappedConnectionFactory) + /// + /// Remove any user credentials for this proxy from the current thread. + /// Statically specified user credentials apply again afterwards. + /// + public void RemoveCredentialsFromCurrentThread() + { + this.threadLocalCredentials.Value = null; + } + + private string _userName; + + /// + /// Set the username that this adapter should use for retrieving Connections. + /// + public string UserName + { + get => _userName; + set => _userName = string.IsNullOrWhiteSpace(value) ? null : value; + } + + private string UserNameInternal => threadLocalCredentials.Value != null ? threadLocalCredentials.Value.UserName : UserName; + private string PasswordInternal => threadLocalCredentials.Value != null ? threadLocalCredentials.Value.Password : Password; + + private string _password; + + /// + /// Set the password that this adapter should use for retrieving Connections. + /// + public string Password + { + get => _password; + set => _password = string.IsNullOrEmpty(value) ? null : value; + } + + public IConnection CreateConnection() + { + return CreateConnectionForSpecificCredentials(UserNameInternal, PasswordInternal); + } + + private IConnection CreateConnectionForSpecificCredentials(string userName, string password) + { + if (string.IsNullOrWhiteSpace(userName) == false) { - this._wrappedConnectionFactory = wrappedConnectionFactory; + return CreateConnection(userName, password); } + return _wrappedConnectionFactory.CreateConnection(); + } - /// - /// Set user credentials for this proxy and the current thread. - /// The given username and password will be applied to all subsequent - /// CreateConnection() calls on this ConnectionFactory proxy. - /// This will override any statically specified user credentials, - /// that is, values of the "username" and "password" properties. - /// - public void SetCredentialsForCurrentThread(string userName, string password) + public IConnection CreateConnection(string userName, string password) + { + return _wrappedConnectionFactory.CreateConnection(userName, password); + } + + public Task CreateConnectionAsync() + { + return _wrappedConnectionFactory.CreateConnectionAsync(UserNameInternal, PasswordInternal); + } + + public Task CreateConnectionAsync(string userName, string password) + { + return _wrappedConnectionFactory.CreateConnectionAsync(userName, password); + } + + public INMSContext CreateContext() + { + return _wrappedConnectionFactory.CreateContext(UserNameInternal, PasswordInternal); + } + + public INMSContext CreateContext(AcknowledgementMode acknowledgementMode) + { + return _wrappedConnectionFactory.CreateContext(UserNameInternal, PasswordInternal, acknowledgementMode); + } + + public INMSContext CreateContext(string userName, string password) + { + return _wrappedConnectionFactory.CreateContext(userName, password); + } + + public INMSContext CreateContext(string userName, string password, AcknowledgementMode acknowledgementMode) + { + return _wrappedConnectionFactory.CreateContext(userName, password, acknowledgementMode); + } + + public Task CreateContextAsync() + { + return _wrappedConnectionFactory.CreateContextAsync(UserNameInternal, PasswordInternal); + } + + public Task CreateContextAsync(AcknowledgementMode acknowledgementMode) + { + return _wrappedConnectionFactory.CreateContextAsync(UserNameInternal, PasswordInternal, acknowledgementMode); + } + + public Task CreateContextAsync(string userName, string password) + { + return _wrappedConnectionFactory.CreateContextAsync(userName, password); + } + + public Task CreateContextAsync(string userName, string password, AcknowledgementMode acknowledgementMode) + { + return _wrappedConnectionFactory.CreateContextAsync(userName, password, acknowledgementMode); + } + + public Uri BrokerUri + { + get => _wrappedConnectionFactory.BrokerUri; + set => _wrappedConnectionFactory.BrokerUri = value; + } + + public IRedeliveryPolicy RedeliveryPolicy + { + get => _wrappedConnectionFactory.RedeliveryPolicy; + set => _wrappedConnectionFactory.RedeliveryPolicy = value; + } + + public ConsumerTransformerDelegate ConsumerTransformer + { + get => _wrappedConnectionFactory.ConsumerTransformer; + set => _wrappedConnectionFactory.ConsumerTransformer = value; + } + + public ProducerTransformerDelegate ProducerTransformer + { + get => _wrappedConnectionFactory.ProducerTransformer; + set => _wrappedConnectionFactory.ProducerTransformer = value; + } + + private class NmsUserCredentials + { + public string UserName { get; } + public string Password { get; } + + public NmsUserCredentials(string userName, string password) { - this.threadLocalCredentials.Value = new NmsUserCredentials(userName, password); - } - - /// - /// Remove any user credentials for this proxy from the current thread. - /// Statically specified user credentials apply again afterwards. - /// - public void RemoveCredentialsFromCurrentThread() - { - this.threadLocalCredentials.Value = null; - } - - - private string _userName; - - /// - /// Set the username that this adapter should use for retrieving Connections. - /// - public string UserName - { - get => _userName; - set => _userName = string.IsNullOrWhiteSpace(value) ? null : value; - } - - private string UserNameInternal => threadLocalCredentials.Value != null ? threadLocalCredentials.Value.UserName : UserName; - private string PasswordInternal => threadLocalCredentials.Value != null ? threadLocalCredentials.Value.Password : Password; - - - private string _password; - - /// - /// Set the password that this adapter should use for retrieving Connections. - /// - public string Password - { - get => _password; - set => _password = string.IsNullOrEmpty(value) ? null : value; - } - - public IConnection CreateConnection() - { - return CreateConnectionForSpecificCredentials(UserNameInternal, PasswordInternal); - } - - private IConnection CreateConnectionForSpecificCredentials(string userName, string password) - { - if (string.IsNullOrWhiteSpace(userName) == false) - { - return CreateConnection(userName, password); - } - - return _wrappedConnectionFactory.CreateConnection(); - } - - public IConnection CreateConnection(string userName, string password) - { - return _wrappedConnectionFactory.CreateConnection(userName, password); - } - - public Task CreateConnectionAsync() - { - return _wrappedConnectionFactory.CreateConnectionAsync(UserNameInternal, PasswordInternal); - } - - public Task CreateConnectionAsync(string userName, string password) - { - return _wrappedConnectionFactory.CreateConnectionAsync(userName, password); - } - - public INMSContext CreateContext() - { - return _wrappedConnectionFactory.CreateContext(UserNameInternal, PasswordInternal); - } - - public INMSContext CreateContext(AcknowledgementMode acknowledgementMode) - { - return _wrappedConnectionFactory.CreateContext(UserNameInternal, PasswordInternal, acknowledgementMode); - } - - public INMSContext CreateContext(string userName, string password) - { - return _wrappedConnectionFactory.CreateContext(userName, password); - } - - public INMSContext CreateContext(string userName, string password, AcknowledgementMode acknowledgementMode) - { - return _wrappedConnectionFactory.CreateContext(userName, password, acknowledgementMode); - } - - public Task CreateContextAsync() - { - return _wrappedConnectionFactory.CreateContextAsync(UserNameInternal, PasswordInternal); - } - - public Task CreateContextAsync(AcknowledgementMode acknowledgementMode) - { - return _wrappedConnectionFactory.CreateContextAsync(UserNameInternal, PasswordInternal, acknowledgementMode); - } - - public Task CreateContextAsync(string userName, string password) - { - return _wrappedConnectionFactory.CreateContextAsync(userName, password); - } - - public Task CreateContextAsync(string userName, string password, AcknowledgementMode acknowledgementMode) - { - return _wrappedConnectionFactory.CreateContextAsync(userName, password, acknowledgementMode); - } - - public Uri BrokerUri - { - get => _wrappedConnectionFactory.BrokerUri; - set => _wrappedConnectionFactory.BrokerUri = value; - } - - public IRedeliveryPolicy RedeliveryPolicy - { - get => _wrappedConnectionFactory.RedeliveryPolicy; - set => _wrappedConnectionFactory.RedeliveryPolicy = value; - } - - public ConsumerTransformerDelegate ConsumerTransformer - { - get => _wrappedConnectionFactory.ConsumerTransformer; - set => _wrappedConnectionFactory.ConsumerTransformer = value; - } - - public ProducerTransformerDelegate ProducerTransformer - { - get => _wrappedConnectionFactory.ProducerTransformer; - set => _wrappedConnectionFactory.ProducerTransformer = value; - } - - private class NmsUserCredentials - { - public string UserName { get; } - public string Password { get; } - - public NmsUserCredentials(string userName, string password) - { - UserName = userName; - Password = password; - } + UserName = userName; + Password = password; } } } diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/IExceptionListener.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/IExceptionListener.cs index 2d6e9601..5b73e9d3 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/IExceptionListener.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/IExceptionListener.cs @@ -18,18 +18,17 @@ #endregion -namespace Spring.Messaging.Nms.Core +namespace Spring.Messaging.Nms.Core; + +/// +/// Exception handler for exceptions from the messaging infrastrcture. +/// +/// Mark Pollack +public interface IExceptionListener { /// - /// Exception handler for exceptions from the messaging infrastrcture. + /// Called when there is an exception in message processing. /// - /// Mark Pollack - public interface IExceptionListener - { - /// - /// Called when there is an exception in message processing. - /// - /// The exception. - void OnException(Exception exception); - } + /// The exception. + void OnException(Exception exception); } diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/IMessageCreator.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/IMessageCreator.cs index fc1b274f..3b4a0190 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/IMessageCreator.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/IMessageCreator.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -20,23 +20,22 @@ using Apache.NMS; -namespace Spring.Messaging.Nms.Core +namespace Spring.Messaging.Nms.Core; + +/// Creates a NMS message given a Session +/// +///

The Session typically is provided by an instance +/// of the MessageTemplate class.

+///
+/// Mark Pollack +public interface IMessageCreator { - /// Creates a NMS message given a Session - /// - ///

The Session typically is provided by an instance - /// of the MessageTemplate class.

- ///
- /// Mark Pollack - public interface IMessageCreator - { - /// Create a Message to be sent. - /// the NMS Session to be used to create the - /// IMessage (never null) - /// - /// the Message to be sent - /// - /// NMSException if thrown by NMS API methods - IMessage CreateMessage(ISession session); - } + /// Create a Message to be sent. + /// the NMS Session to be used to create the + /// IMessage (never null) + /// + /// the Message to be sent + /// + /// NMSException if thrown by NMS API methods + IMessage CreateMessage(ISession session); } diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/IMessageListener.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/IMessageListener.cs index 14450fbd..1540b974 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/IMessageListener.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/IMessageListener.cs @@ -20,17 +20,16 @@ using Apache.NMS; -namespace Spring.Messaging.Nms.Core +namespace Spring.Messaging.Nms.Core; + +/// +/// Interfaced based approach to listen to messaging events. +/// +public interface IMessageListener { /// - /// Interfaced based approach to listen to messaging events. + /// Called when a message is delivered. /// - public interface IMessageListener - { - /// - /// Called when a message is delivered. - /// - /// The message. - void OnMessage(IMessage message); - } -} \ No newline at end of file + /// The message. + void OnMessage(IMessage message); +} diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/IMessagePostProcessor.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/IMessagePostProcessor.cs index 79f1d70f..766df3be 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/IMessagePostProcessor.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/IMessagePostProcessor.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -20,27 +20,25 @@ using Apache.NMS; -namespace Spring.Messaging.Nms.Core +namespace Spring.Messaging.Nms.Core; + +/// To be used with NmsTemplate's send method that +/// convert an object to a message. +/// +/// +/// It allows for further modification of the message after it has been processed +/// by the converter. This is useful for setting of NMS Header and Properties. +/// +/// Mark Pollack +public interface IMessagePostProcessor { - /// To be used with NmsTemplate's send method that - /// convert an object to a message. + /// Apply a IMessagePostProcessor to the message. The returned message is + /// typically a modified version of the original. /// - /// - /// It allows for further modification of the message after it has been processed - /// by the converter. This is useful for setting of NMS Header and Properties. - /// - /// Mark Pollack - public interface IMessagePostProcessor - { - /// Apply a IMessagePostProcessor to the message. The returned message is - /// typically a modified version of the original. - /// - /// the NMS message from the IMessageConverter - /// - /// the modified version of the Message - /// - /// NMSException if thrown by NMS API methods - IMessage PostProcessMessage(IMessage message); - - } + /// the NMS message from the IMessageConverter + /// + /// the modified version of the Message + /// + /// NMSException if thrown by NMS API methods + IMessage PostProcessMessage(IMessage message); } diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/INmsOperations.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/INmsOperations.cs index ec14e316..0854f1de 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/INmsOperations.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/INmsOperations.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -20,417 +20,415 @@ using Apache.NMS; -namespace Spring.Messaging.Nms.Core +namespace Spring.Messaging.Nms.Core; + +/// +/// Specifies a basic set of NMS operations. +/// +/// +///

Implemented by NmsTemplate. Not often used but a useful option +/// to enhance testability, as it can easily be mocked or stubbed.

+///

Provides NmsTemplate's +/// send(..) and +/// receive(..) methods that mirror various NMS API methods. +/// See the NMS specification and NMS API docs for details on those methods. +///

+///
+/// Mark Pollack +/// Juergen Hoeller +/// Mark Pollack (.NET) +public interface INmsOperations { /// - /// Specifies a basic set of NMS operations. + /// Execute the action specified by the given action object within + /// a NMS Session. /// - /// - ///

Implemented by NmsTemplate. Not often used but a useful option - /// to enhance testability, as it can easily be mocked or stubbed.

- ///

Provides NmsTemplate's - /// send(..) and - /// receive(..) methods that mirror various NMS API methods. - /// See the NMS specification and NMS API docs for details on those methods. - ///

- ///
- /// Mark Pollack - /// Juergen Hoeller - /// Mark Pollack (.NET) - public interface INmsOperations - { - /// - /// Execute the action specified by the given action object within - /// a NMS Session. - /// - /// callback object that exposes the session - /// - /// the result object from working with the session - /// - /// NMSException if there is any problem - object Execute(ISessionCallback action); + /// callback object that exposes the session + /// + /// the result object from working with the session + /// + /// NMSException if there is any problem + object Execute(ISessionCallback action); - /// - /// Execute the action specified by the given action object within - /// a NMS Session. - /// - /// delegate that exposes the session - /// - /// the result object from working with the session - /// - /// NMSException if there is any problem - object Execute(SessionDelegate del); - - /// Send a message to a NMS destination. The callback gives access to - /// the NMS session and MessageProducer in order to do more complex - /// send operations. - /// - /// delegate that exposes the session/producer pair - /// - /// the result object from working with the session - /// - /// NMSException if there is any problem - object Execute(ProducerDelegate del); + /// + /// Execute the action specified by the given action object within + /// a NMS Session. + /// + /// delegate that exposes the session + /// + /// the result object from working with the session + /// + /// NMSException if there is any problem + object Execute(SessionDelegate del); - /// Send a message to a NMS destination. The callback gives access to - /// the NMS session and MessageProducer in order to do more complex - /// send operations. - /// - /// callback object that exposes the session/producer pair - /// - /// the result object from working with the session - /// - /// NMSException if there is any problem - object Execute(IProducerCallback action); - - //------------------------------------------------------------------------- - // Convenience methods for sending messages - //------------------------------------------------------------------------- - - /// Send a message to the default destination. - ///

This will only work with a default destination specified!

- ///
- /// callback to create a message - /// - /// NMSException if there is any problem - void Send(IMessageCreator messageCreator); - - /// Send a message to the specified destination. - /// The IMessageCreator callback creates the message given a Session. - /// - /// the destination to send this message to - /// - /// callback to create a message - /// - /// NMSException if there is any problem - void Send(IDestination destination, IMessageCreator messageCreator); - - /// Send a message to the specified destination. - /// The IMessageCreator callback creates the message given a Session. - /// - /// the name of the destination to send this message to - /// (to be resolved to an actual destination by a DestinationResolver) - /// - /// callback to create a message - /// - /// NMSException if there is any problem - void Send(string destinationName, IMessageCreator messageCreator); + /// Send a message to a NMS destination. The callback gives access to + /// the NMS session and MessageProducer in order to do more complex + /// send operations. + /// + /// delegate that exposes the session/producer pair + /// + /// the result object from working with the session + /// + /// NMSException if there is any problem + object Execute(ProducerDelegate del); - //------------------------------------------------------------------------- - // Convenience methods for sending messages - //------------------------------------------------------------------------- + /// Send a message to a NMS destination. The callback gives access to + /// the NMS session and MessageProducer in order to do more complex + /// send operations. + /// + /// callback object that exposes the session/producer pair + /// + /// the result object from working with the session + /// + /// NMSException if there is any problem + object Execute(IProducerCallback action); - /// Send a message to the default destination. - ///

This will only work with a default destination specified!

- ///
- /// delegate callback to create a message - /// - /// NMSException if there is any problem - void SendWithDelegate(MessageCreatorDelegate messageCreatorDelegate); + //------------------------------------------------------------------------- + // Convenience methods for sending messages + //------------------------------------------------------------------------- - /// Send a message to the specified destination. - /// The IMessageCreator callback creates the message given a Session. - /// - /// the destination to send this message to - /// - /// delegate callback to create a message - /// - /// NMSException if there is any problem - void SendWithDelegate(IDestination destination, MessageCreatorDelegate messageCreatorDelegate); + /// Send a message to the default destination. + ///

This will only work with a default destination specified!

+ ///
+ /// callback to create a message + /// + /// NMSException if there is any problem + void Send(IMessageCreator messageCreator); - /// Send a message to the specified destination. - /// The IMessageCreator callback creates the message given a Session. - /// - /// the name of the destination to send this message to - /// (to be resolved to an actual destination by a DestinationResolver) - /// - /// delegate callback to create a message - /// - /// NMSException if there is any problem - void SendWithDelegate(string destinationName, MessageCreatorDelegate messageCreatorDelegate); - - //------------------------------------------------------------------------- - // Convenience methods for sending auto-converted messages - //------------------------------------------------------------------------- - - /// Send the given object to the default destination, converting the object - /// to a NMS message with a configured IMessageConverter. - ///

This will only work with a default destination specified!

- ///
- /// the object to convert to a message - /// - /// NMSException if there is any problem - void ConvertAndSend(object message); - - /// Send the given object to the specified destination, converting the object - /// to a NMS message with a configured IMessageConverter. - /// - /// the destination to send this message to - /// - /// the object to convert to a message - /// - /// NMSException if there is any problem - void ConvertAndSend(IDestination destination, object message); - - /// Send the given object to the specified destination, converting the object - /// to a NMS message with a configured IMessageConverter. - /// - /// the name of the destination to send this message to - /// (to be resolved to an actual destination by a DestinationResolver) - /// - /// the object to convert to a message - /// - /// NMSException if there is any problem - void ConvertAndSend(string destinationName, object message); - - /// Send the given object to the default destination, converting the object - /// to a NMS message with a configured IMessageConverter. The IMessagePostProcessor - /// callback allows for modification of the message after conversion. - ///

This will only work with a default destination specified!

- ///
- /// the object to convert to a message - /// - /// the callback to modify the message - /// - /// NMSException if there is any problem - void ConvertAndSend(object message, IMessagePostProcessor postProcessor); - - /// Send the given object to the specified destination, converting the object - /// to a NMS message with a configured IMessageConverter. The IMessagePostProcessor - /// callback allows for modification of the message after conversion. - /// - /// the destination to send this message to - /// - /// the object to convert to a message - /// - /// the callback to modify the message - /// - /// NMSException if there is any problem - void ConvertAndSend(IDestination destination, object message, IMessagePostProcessor postProcessor); - - /// Send the given object to the specified destination, converting the object - /// to a NMS message with a configured IMessageConverter. The IMessagePostProcessor - /// callback allows for modification of the message after conversion. - /// - /// the name of the destination to send this message to - /// (to be resolved to an actual destination by a DestinationResolver) - /// - /// the object to convert to a message. - /// - /// the callback to modify the message - /// - /// NMSException if there is any problem - void ConvertAndSend(string destinationName, object message, IMessagePostProcessor postProcessor); + /// Send a message to the specified destination. + /// The IMessageCreator callback creates the message given a Session. + /// + /// the destination to send this message to + /// + /// callback to create a message + /// + /// NMSException if there is any problem + void Send(IDestination destination, IMessageCreator messageCreator); - /// - /// Send the given object to the default destination, converting the object - /// to a NMS message with a configured IMessageConverter. The IMessagePostProcessor - /// callback allows for modification of the message after conversion. - ///

This will only work with a default destination specified!

- ///
- /// the object to convert to a message - /// the callback to modify the message - /// NMSException if there is any problem - void ConvertAndSendWithDelegate(object message, MessagePostProcessorDelegate postProcessor); + /// Send a message to the specified destination. + /// The IMessageCreator callback creates the message given a Session. + /// + /// the name of the destination to send this message to + /// (to be resolved to an actual destination by a DestinationResolver) + /// + /// callback to create a message + /// + /// NMSException if there is any problem + void Send(string destinationName, IMessageCreator messageCreator); - /// - /// Send the given object to the specified destination, converting the object - /// to a NMS message with a configured IMessageConverter. The IMessagePostProcessor - /// callback allows for modification of the message after conversion. - /// - /// the destination to send this message to - /// the object to convert to a message - /// the callback to modify the message - /// NMSException if there is any problem - void ConvertAndSendWithDelegate(IDestination destination, object message, MessagePostProcessorDelegate postProcessor); + //------------------------------------------------------------------------- + // Convenience methods for sending messages + //------------------------------------------------------------------------- - /// - /// Send the given object to the specified destination, converting the object - /// to a NMS message with a configured IMessageConverter. The IMessagePostProcessor - /// callback allows for modification of the message after conversion. - /// - /// the name of the destination to send this message to - /// (to be resolved to an actual destination by a DestinationResolver) - /// the object to convert to a message. - /// the callback to modify the message - /// NMSException if there is any problem - void ConvertAndSendWithDelegate(string destinationName, object message, MessagePostProcessorDelegate postProcessor); - - //------------------------------------------------------------------------- - // Convenience methods for receiving messages - //------------------------------------------------------------------------- - - /// Receive a message synchronously from the default destination, but only - /// wait up to a specified time for delivery. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///

This will only work with a default destination specified!

- ///
- /// the message received by the consumer, or null if the timeout expires - /// - /// NMSException if there is any problem - IMessage Receive(); - - /// Receive a message synchronously from the specified destination, but only - /// wait up to a specified time for delivery. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///
- /// the destination to receive a message from - /// - /// the message received by the consumer, or null if the timeout expires - /// - /// NMSException if there is any problem - IMessage Receive(IDestination destination); - - /// Receive a message synchronously from the specified destination, but only - /// wait up to a specified time for delivery. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///
- /// the name of the destination to send this message to - /// (to be resolved to an actual destination by a DestinationResolver) - /// - /// the message received by the consumer, or null if the timeout expires - /// - /// NMSException if there is any problem - IMessage Receive(string destinationName); - - /// Receive a message synchronously from the default destination, but only - /// wait up to a specified time for delivery. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///

This will only work with a default destination specified!

- ///
- /// the NMS message selector expression (or null if none). - /// See the NMS specification for a detailed definition of selector expressions. - /// - /// the message received by the consumer, or null if the timeout expires - /// - /// NMSException if there is any problem - IMessage ReceiveSelected(string messageSelector); - - /// Receive a message synchronously from the specified destination, but only - /// wait up to a specified time for delivery. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///
- /// the destination to receive a message from - /// - /// the NMS message selector expression (or null if none). - /// See the NMS specification for a detailed definition of selector expressions. - /// - /// the message received by the consumer, or null if the timeout expires - /// - /// NMSException if there is any problem - IMessage ReceiveSelected(IDestination destination, string messageSelector); - - /// Receive a message synchronously from the specified destination, but only - /// wait up to a specified time for delivery. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///
- /// the name of the destination to send this message to - /// (to be resolved to an actual destination by a DestinationResolver) - /// - /// the NMS message selector expression (or null if none). - /// See the NMS specification for a detailed definition of selector expressions. - /// - /// the message received by the consumer, or null if the timeout expires - /// - /// NMSException if there is any problem - IMessage ReceiveSelected(string destinationName, string messageSelector); - - - //------------------------------------------------------------------------- - // Convenience methods for receiving auto-converted messages - //------------------------------------------------------------------------- - - /// Receive a message synchronously from the default destination, but only - /// wait up to a specified time for delivery. Convert the message into an - /// object with a configured IMessageConverter. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///

This will only work with a default destination specified!

- ///
- /// the message produced for the consumer or null if the timeout expires. - /// - /// NMSException if there is any problem - object ReceiveAndConvert(); - - /// Receive a message synchronously from the specified destination, but only - /// wait up to a specified time for delivery. Convert the message into an - /// object with a configured IMessageConverter. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///
- /// the destination to receive a message from - /// - /// the message produced for the consumer or null if the timeout expires. - /// - /// NMSException if there is any problem - object ReceiveAndConvert(IDestination destination); - - /// Receive a message synchronously from the specified destination, but only - /// wait up to a specified time for delivery. Convert the message into an - /// object with a configured IMessageConverter. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///
- /// the name of the destination to send this message to - /// (to be resolved to an actual destination by a DestinationResolver) - /// - /// the message produced for the consumer or null if the timeout expires. - /// - /// NMSException if there is any problem - object ReceiveAndConvert(string destinationName); - - /// Receive a message synchronously from the default destination, but only - /// wait up to a specified time for delivery. Convert the message into an - /// object with a configured IMessageConverter. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///

This will only work with a default destination specified!

- ///
- /// the NMS message selector expression (or null if none). - /// See the NMS specification for a detailed definition of selector expressions. - /// - /// the message produced for the consumer or null if the timeout expires. - /// - /// NMSException if there is any problem - object ReceiveSelectedAndConvert(string messageSelector); - - /// Receive a message synchronously from the specified destination, but only - /// wait up to a specified time for delivery. Convert the message into an - /// object with a configured IMessageConverter. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///
- /// the destination to receive a message from - /// - /// the NMS message selector expression (or null if none). - /// See the NMS specification for a detailed definition of selector expressions. - /// - /// the message produced for the consumer or null if the timeout expires. - /// - /// NMSException if there is any problem - object ReceiveSelectedAndConvert(IDestination destination, string messageSelector); - - /// Receive a message synchronously from the specified destination, but only - /// wait up to a specified time for delivery. Convert the message into an - /// object with a configured IMessageConverter. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///
- /// the name of the destination to send this message to - /// (to be resolved to an actual destination by a DestinationResolver) - /// - /// the NMS message selector expression (or null if none). - /// See the NMS specification for a detailed definition of selector expressions. - /// - /// the message produced for the consumer or null if the timeout expires. - /// - /// NMSException if there is any problem - object ReceiveSelectedAndConvert(string destinationName, string messageSelector); - } + /// Send a message to the default destination. + ///

This will only work with a default destination specified!

+ ///
+ /// delegate callback to create a message + /// + /// NMSException if there is any problem + void SendWithDelegate(MessageCreatorDelegate messageCreatorDelegate); + + /// Send a message to the specified destination. + /// The IMessageCreator callback creates the message given a Session. + /// + /// the destination to send this message to + /// + /// delegate callback to create a message + /// + /// NMSException if there is any problem + void SendWithDelegate(IDestination destination, MessageCreatorDelegate messageCreatorDelegate); + + /// Send a message to the specified destination. + /// The IMessageCreator callback creates the message given a Session. + /// + /// the name of the destination to send this message to + /// (to be resolved to an actual destination by a DestinationResolver) + /// + /// delegate callback to create a message + /// + /// NMSException if there is any problem + void SendWithDelegate(string destinationName, MessageCreatorDelegate messageCreatorDelegate); + + //------------------------------------------------------------------------- + // Convenience methods for sending auto-converted messages + //------------------------------------------------------------------------- + + /// Send the given object to the default destination, converting the object + /// to a NMS message with a configured IMessageConverter. + ///

This will only work with a default destination specified!

+ ///
+ /// the object to convert to a message + /// + /// NMSException if there is any problem + void ConvertAndSend(object message); + + /// Send the given object to the specified destination, converting the object + /// to a NMS message with a configured IMessageConverter. + /// + /// the destination to send this message to + /// + /// the object to convert to a message + /// + /// NMSException if there is any problem + void ConvertAndSend(IDestination destination, object message); + + /// Send the given object to the specified destination, converting the object + /// to a NMS message with a configured IMessageConverter. + /// + /// the name of the destination to send this message to + /// (to be resolved to an actual destination by a DestinationResolver) + /// + /// the object to convert to a message + /// + /// NMSException if there is any problem + void ConvertAndSend(string destinationName, object message); + + /// Send the given object to the default destination, converting the object + /// to a NMS message with a configured IMessageConverter. The IMessagePostProcessor + /// callback allows for modification of the message after conversion. + ///

This will only work with a default destination specified!

+ ///
+ /// the object to convert to a message + /// + /// the callback to modify the message + /// + /// NMSException if there is any problem + void ConvertAndSend(object message, IMessagePostProcessor postProcessor); + + /// Send the given object to the specified destination, converting the object + /// to a NMS message with a configured IMessageConverter. The IMessagePostProcessor + /// callback allows for modification of the message after conversion. + /// + /// the destination to send this message to + /// + /// the object to convert to a message + /// + /// the callback to modify the message + /// + /// NMSException if there is any problem + void ConvertAndSend(IDestination destination, object message, IMessagePostProcessor postProcessor); + + /// Send the given object to the specified destination, converting the object + /// to a NMS message with a configured IMessageConverter. The IMessagePostProcessor + /// callback allows for modification of the message after conversion. + /// + /// the name of the destination to send this message to + /// (to be resolved to an actual destination by a DestinationResolver) + /// + /// the object to convert to a message. + /// + /// the callback to modify the message + /// + /// NMSException if there is any problem + void ConvertAndSend(string destinationName, object message, IMessagePostProcessor postProcessor); + + /// + /// Send the given object to the default destination, converting the object + /// to a NMS message with a configured IMessageConverter. The IMessagePostProcessor + /// callback allows for modification of the message after conversion. + ///

This will only work with a default destination specified!

+ ///
+ /// the object to convert to a message + /// the callback to modify the message + /// NMSException if there is any problem + void ConvertAndSendWithDelegate(object message, MessagePostProcessorDelegate postProcessor); + + /// + /// Send the given object to the specified destination, converting the object + /// to a NMS message with a configured IMessageConverter. The IMessagePostProcessor + /// callback allows for modification of the message after conversion. + /// + /// the destination to send this message to + /// the object to convert to a message + /// the callback to modify the message + /// NMSException if there is any problem + void ConvertAndSendWithDelegate(IDestination destination, object message, MessagePostProcessorDelegate postProcessor); + + /// + /// Send the given object to the specified destination, converting the object + /// to a NMS message with a configured IMessageConverter. The IMessagePostProcessor + /// callback allows for modification of the message after conversion. + /// + /// the name of the destination to send this message to + /// (to be resolved to an actual destination by a DestinationResolver) + /// the object to convert to a message. + /// the callback to modify the message + /// NMSException if there is any problem + void ConvertAndSendWithDelegate(string destinationName, object message, MessagePostProcessorDelegate postProcessor); + + //------------------------------------------------------------------------- + // Convenience methods for receiving messages + //------------------------------------------------------------------------- + + /// Receive a message synchronously from the default destination, but only + /// wait up to a specified time for delivery. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///

This will only work with a default destination specified!

+ ///
+ /// the message received by the consumer, or null if the timeout expires + /// + /// NMSException if there is any problem + IMessage Receive(); + + /// Receive a message synchronously from the specified destination, but only + /// wait up to a specified time for delivery. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///
+ /// the destination to receive a message from + /// + /// the message received by the consumer, or null if the timeout expires + /// + /// NMSException if there is any problem + IMessage Receive(IDestination destination); + + /// Receive a message synchronously from the specified destination, but only + /// wait up to a specified time for delivery. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///
+ /// the name of the destination to send this message to + /// (to be resolved to an actual destination by a DestinationResolver) + /// + /// the message received by the consumer, or null if the timeout expires + /// + /// NMSException if there is any problem + IMessage Receive(string destinationName); + + /// Receive a message synchronously from the default destination, but only + /// wait up to a specified time for delivery. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///

This will only work with a default destination specified!

+ ///
+ /// the NMS message selector expression (or null if none). + /// See the NMS specification for a detailed definition of selector expressions. + /// + /// the message received by the consumer, or null if the timeout expires + /// + /// NMSException if there is any problem + IMessage ReceiveSelected(string messageSelector); + + /// Receive a message synchronously from the specified destination, but only + /// wait up to a specified time for delivery. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///
+ /// the destination to receive a message from + /// + /// the NMS message selector expression (or null if none). + /// See the NMS specification for a detailed definition of selector expressions. + /// + /// the message received by the consumer, or null if the timeout expires + /// + /// NMSException if there is any problem + IMessage ReceiveSelected(IDestination destination, string messageSelector); + + /// Receive a message synchronously from the specified destination, but only + /// wait up to a specified time for delivery. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///
+ /// the name of the destination to send this message to + /// (to be resolved to an actual destination by a DestinationResolver) + /// + /// the NMS message selector expression (or null if none). + /// See the NMS specification for a detailed definition of selector expressions. + /// + /// the message received by the consumer, or null if the timeout expires + /// + /// NMSException if there is any problem + IMessage ReceiveSelected(string destinationName, string messageSelector); + + //------------------------------------------------------------------------- + // Convenience methods for receiving auto-converted messages + //------------------------------------------------------------------------- + + /// Receive a message synchronously from the default destination, but only + /// wait up to a specified time for delivery. Convert the message into an + /// object with a configured IMessageConverter. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///

This will only work with a default destination specified!

+ ///
+ /// the message produced for the consumer or null if the timeout expires. + /// + /// NMSException if there is any problem + object ReceiveAndConvert(); + + /// Receive a message synchronously from the specified destination, but only + /// wait up to a specified time for delivery. Convert the message into an + /// object with a configured IMessageConverter. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///
+ /// the destination to receive a message from + /// + /// the message produced for the consumer or null if the timeout expires. + /// + /// NMSException if there is any problem + object ReceiveAndConvert(IDestination destination); + + /// Receive a message synchronously from the specified destination, but only + /// wait up to a specified time for delivery. Convert the message into an + /// object with a configured IMessageConverter. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///
+ /// the name of the destination to send this message to + /// (to be resolved to an actual destination by a DestinationResolver) + /// + /// the message produced for the consumer or null if the timeout expires. + /// + /// NMSException if there is any problem + object ReceiveAndConvert(string destinationName); + + /// Receive a message synchronously from the default destination, but only + /// wait up to a specified time for delivery. Convert the message into an + /// object with a configured IMessageConverter. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///

This will only work with a default destination specified!

+ ///
+ /// the NMS message selector expression (or null if none). + /// See the NMS specification for a detailed definition of selector expressions. + /// + /// the message produced for the consumer or null if the timeout expires. + /// + /// NMSException if there is any problem + object ReceiveSelectedAndConvert(string messageSelector); + + /// Receive a message synchronously from the specified destination, but only + /// wait up to a specified time for delivery. Convert the message into an + /// object with a configured IMessageConverter. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///
+ /// the destination to receive a message from + /// + /// the NMS message selector expression (or null if none). + /// See the NMS specification for a detailed definition of selector expressions. + /// + /// the message produced for the consumer or null if the timeout expires. + /// + /// NMSException if there is any problem + object ReceiveSelectedAndConvert(IDestination destination, string messageSelector); + + /// Receive a message synchronously from the specified destination, but only + /// wait up to a specified time for delivery. Convert the message into an + /// object with a configured IMessageConverter. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///
+ /// the name of the destination to send this message to + /// (to be resolved to an actual destination by a DestinationResolver) + /// + /// the NMS message selector expression (or null if none). + /// See the NMS specification for a detailed definition of selector expressions. + /// + /// the message produced for the consumer or null if the timeout expires. + /// + /// NMSException if there is any problem + object ReceiveSelectedAndConvert(string destinationName, string messageSelector); } diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/INmsOperationsAsync.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/INmsOperationsAsync.cs index 9d97e3ee..d9f84ac4 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/INmsOperationsAsync.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/INmsOperationsAsync.cs @@ -20,405 +20,404 @@ using Apache.NMS; -namespace Spring.Messaging.Nms.Core +namespace Spring.Messaging.Nms.Core; + +/// +/// Async version of INmsOperations +/// +/// +public interface INmsOperationsAsync { /// - /// Async version of INmsOperations + /// Execute the action specified by the given action object within + /// a NMS Session. /// - /// - public interface INmsOperationsAsync - { - /// - /// Execute the action specified by the given action object within - /// a NMS Session. - /// - /// callback object that exposes the session - /// - /// the result object from working with the session - /// - /// NMSException if there is any problem - Task Execute(ISessionCallbackAsync action); + /// callback object that exposes the session + /// + /// the result object from working with the session + /// + /// NMSException if there is any problem + Task Execute(ISessionCallbackAsync action); - /// - /// Execute the action specified by the given action object within - /// a NMS Session. - /// - /// delegate that exposes the session - /// - /// the result object from working with the session - /// - /// NMSException if there is any problem - Task Execute(SessionDelegateAsync del); + /// + /// Execute the action specified by the given action object within + /// a NMS Session. + /// + /// delegate that exposes the session + /// + /// the result object from working with the session + /// + /// NMSException if there is any problem + Task Execute(SessionDelegateAsync del); - /// Send a message to a NMS destination. The callback gives access to - /// the NMS session and MessageProducer in order to do more complex - /// send operations. - /// - /// delegate that exposes the session/producer pair - /// - /// the result object from working with the session - /// - /// NMSException if there is any problem - Task Execute(ProducerDelegate del); + /// Send a message to a NMS destination. The callback gives access to + /// the NMS session and MessageProducer in order to do more complex + /// send operations. + /// + /// delegate that exposes the session/producer pair + /// + /// the result object from working with the session + /// + /// NMSException if there is any problem + Task Execute(ProducerDelegate del); - /// Send a message to a NMS destination. The callback gives access to - /// the NMS session and MessageProducer in order to do more complex - /// send operations. - /// - /// callback object that exposes the session/producer pair - /// - /// the result object from working with the session - /// - /// NMSException if there is any problem - Task Execute(IProducerCallbackAsync action); + /// Send a message to a NMS destination. The callback gives access to + /// the NMS session and MessageProducer in order to do more complex + /// send operations. + /// + /// callback object that exposes the session/producer pair + /// + /// the result object from working with the session + /// + /// NMSException if there is any problem + Task Execute(IProducerCallbackAsync action); - //------------------------------------------------------------------------- - // Convenience methods for sending messages - //------------------------------------------------------------------------- + //------------------------------------------------------------------------- + // Convenience methods for sending messages + //------------------------------------------------------------------------- - /// Send a message to the default destination. - ///

This will only work with a default destination specified!

- ///
- /// callback to create a message - /// - /// NMSException if there is any problem - Task Send(IMessageCreator messageCreator); + /// Send a message to the default destination. + ///

This will only work with a default destination specified!

+ ///
+ /// callback to create a message + /// + /// NMSException if there is any problem + Task Send(IMessageCreator messageCreator); - /// Send a message to the specified destination. - /// The IMessageCreator callback creates the message given a Session. - /// - /// the destination to send this message to - /// - /// callback to create a message - /// - /// NMSException if there is any problem - Task Send(IDestination destination, IMessageCreator messageCreator); + /// Send a message to the specified destination. + /// The IMessageCreator callback creates the message given a Session. + /// + /// the destination to send this message to + /// + /// callback to create a message + /// + /// NMSException if there is any problem + Task Send(IDestination destination, IMessageCreator messageCreator); - /// Send a message to the specified destination. - /// The IMessageCreator callback creates the message given a Session. - /// - /// the name of the destination to send this message to - /// (to be resolved to an actual destination by a DestinationResolver) - /// - /// callback to create a message - /// - /// NMSException if there is any problem - Task Send(string destinationName, IMessageCreator messageCreator); + /// Send a message to the specified destination. + /// The IMessageCreator callback creates the message given a Session. + /// + /// the name of the destination to send this message to + /// (to be resolved to an actual destination by a DestinationResolver) + /// + /// callback to create a message + /// + /// NMSException if there is any problem + Task Send(string destinationName, IMessageCreator messageCreator); - //------------------------------------------------------------------------- - // Convenience methods for sending messages - //------------------------------------------------------------------------- + //------------------------------------------------------------------------- + // Convenience methods for sending messages + //------------------------------------------------------------------------- - /// Send a message to the default destination. - ///

This will only work with a default destination specified!

- ///
- /// delegate callback to create a message - /// - /// NMSException if there is any problem - Task SendWithDelegate(MessageCreatorDelegate messageCreatorDelegate); + /// Send a message to the default destination. + ///

This will only work with a default destination specified!

+ ///
+ /// delegate callback to create a message + /// + /// NMSException if there is any problem + Task SendWithDelegate(MessageCreatorDelegate messageCreatorDelegate); - /// Send a message to the specified destination. - /// The IMessageCreator callback creates the message given a Session. - /// - /// the destination to send this message to - /// - /// delegate callback to create a message - /// - /// NMSException if there is any problem - Task SendWithDelegate(IDestination destination, MessageCreatorDelegate messageCreatorDelegate); + /// Send a message to the specified destination. + /// The IMessageCreator callback creates the message given a Session. + /// + /// the destination to send this message to + /// + /// delegate callback to create a message + /// + /// NMSException if there is any problem + Task SendWithDelegate(IDestination destination, MessageCreatorDelegate messageCreatorDelegate); - /// Send a message to the specified destination. - /// The IMessageCreator callback creates the message given a Session. - /// - /// the name of the destination to send this message to - /// (to be resolved to an actual destination by a DestinationResolver) - /// - /// delegate callback to create a message - /// - /// NMSException if there is any problem - Task SendWithDelegate(string destinationName, MessageCreatorDelegate messageCreatorDelegate); + /// Send a message to the specified destination. + /// The IMessageCreator callback creates the message given a Session. + /// + /// the name of the destination to send this message to + /// (to be resolved to an actual destination by a DestinationResolver) + /// + /// delegate callback to create a message + /// + /// NMSException if there is any problem + Task SendWithDelegate(string destinationName, MessageCreatorDelegate messageCreatorDelegate); - //------------------------------------------------------------------------- - // Convenience methods for sending auto-converted messages - //------------------------------------------------------------------------- + //------------------------------------------------------------------------- + // Convenience methods for sending auto-converted messages + //------------------------------------------------------------------------- - /// Send the given object to the default destination, converting the object - /// to a NMS message with a configured IMessageConverter. - ///

This will only work with a default destination specified!

- ///
- /// the object to convert to a message - /// - /// NMSException if there is any problem - Task ConvertAndSend(object message); + /// Send the given object to the default destination, converting the object + /// to a NMS message with a configured IMessageConverter. + ///

This will only work with a default destination specified!

+ ///
+ /// the object to convert to a message + /// + /// NMSException if there is any problem + Task ConvertAndSend(object message); - /// Send the given object to the specified destination, converting the object - /// to a NMS message with a configured IMessageConverter. - /// - /// the destination to send this message to - /// - /// the object to convert to a message - /// - /// NMSException if there is any problem - Task ConvertAndSend(IDestination destination, object message); + /// Send the given object to the specified destination, converting the object + /// to a NMS message with a configured IMessageConverter. + /// + /// the destination to send this message to + /// + /// the object to convert to a message + /// + /// NMSException if there is any problem + Task ConvertAndSend(IDestination destination, object message); - /// Send the given object to the specified destination, converting the object - /// to a NMS message with a configured IMessageConverter. - /// - /// the name of the destination to send this message to - /// (to be resolved to an actual destination by a DestinationResolver) - /// - /// the object to convert to a message - /// - /// NMSException if there is any problem - Task ConvertAndSend(string destinationName, object message); + /// Send the given object to the specified destination, converting the object + /// to a NMS message with a configured IMessageConverter. + /// + /// the name of the destination to send this message to + /// (to be resolved to an actual destination by a DestinationResolver) + /// + /// the object to convert to a message + /// + /// NMSException if there is any problem + Task ConvertAndSend(string destinationName, object message); - /// Send the given object to the default destination, converting the object - /// to a NMS message with a configured IMessageConverter. The IMessagePostProcessor - /// callback allows for modification of the message after conversion. - ///

This will only work with a default destination specified!

- ///
- /// the object to convert to a message - /// - /// the callback to modify the message - /// - /// NMSException if there is any problem - Task ConvertAndSend(object message, IMessagePostProcessor postProcessor); + /// Send the given object to the default destination, converting the object + /// to a NMS message with a configured IMessageConverter. The IMessagePostProcessor + /// callback allows for modification of the message after conversion. + ///

This will only work with a default destination specified!

+ ///
+ /// the object to convert to a message + /// + /// the callback to modify the message + /// + /// NMSException if there is any problem + Task ConvertAndSend(object message, IMessagePostProcessor postProcessor); - /// Send the given object to the specified destination, converting the object - /// to a NMS message with a configured IMessageConverter. The IMessagePostProcessor - /// callback allows for modification of the message after conversion. - /// - /// the destination to send this message to - /// - /// the object to convert to a message - /// - /// the callback to modify the message - /// - /// NMSException if there is any problem - Task ConvertAndSend(IDestination destination, object message, IMessagePostProcessor postProcessor); + /// Send the given object to the specified destination, converting the object + /// to a NMS message with a configured IMessageConverter. The IMessagePostProcessor + /// callback allows for modification of the message after conversion. + /// + /// the destination to send this message to + /// + /// the object to convert to a message + /// + /// the callback to modify the message + /// + /// NMSException if there is any problem + Task ConvertAndSend(IDestination destination, object message, IMessagePostProcessor postProcessor); - /// Send the given object to the specified destination, converting the object - /// to a NMS message with a configured IMessageConverter. The IMessagePostProcessor - /// callback allows for modification of the message after conversion. - /// - /// the name of the destination to send this message to - /// (to be resolved to an actual destination by a DestinationResolver) - /// - /// the object to convert to a message. - /// - /// the callback to modify the message - /// - /// NMSException if there is any problem - Task ConvertAndSend(string destinationName, object message, IMessagePostProcessor postProcessor); + /// Send the given object to the specified destination, converting the object + /// to a NMS message with a configured IMessageConverter. The IMessagePostProcessor + /// callback allows for modification of the message after conversion. + /// + /// the name of the destination to send this message to + /// (to be resolved to an actual destination by a DestinationResolver) + /// + /// the object to convert to a message. + /// + /// the callback to modify the message + /// + /// NMSException if there is any problem + Task ConvertAndSend(string destinationName, object message, IMessagePostProcessor postProcessor); - /// - /// Send the given object to the default destination, converting the object - /// to a NMS message with a configured IMessageConverter. The IMessagePostProcessor - /// callback allows for modification of the message after conversion. - ///

This will only work with a default destination specified!

- ///
- /// the object to convert to a message - /// the callback to modify the message - /// NMSException if there is any problem - Task ConvertAndSendWithDelegate(object message, MessagePostProcessorDelegate postProcessor); + /// + /// Send the given object to the default destination, converting the object + /// to a NMS message with a configured IMessageConverter. The IMessagePostProcessor + /// callback allows for modification of the message after conversion. + ///

This will only work with a default destination specified!

+ ///
+ /// the object to convert to a message + /// the callback to modify the message + /// NMSException if there is any problem + Task ConvertAndSendWithDelegate(object message, MessagePostProcessorDelegate postProcessor); - /// - /// Send the given object to the specified destination, converting the object - /// to a NMS message with a configured IMessageConverter. The IMessagePostProcessor - /// callback allows for modification of the message after conversion. - /// - /// the destination to send this message to - /// the object to convert to a message - /// the callback to modify the message - /// NMSException if there is any problem - Task ConvertAndSendWithDelegate(IDestination destination, object message, MessagePostProcessorDelegate postProcessor); + /// + /// Send the given object to the specified destination, converting the object + /// to a NMS message with a configured IMessageConverter. The IMessagePostProcessor + /// callback allows for modification of the message after conversion. + /// + /// the destination to send this message to + /// the object to convert to a message + /// the callback to modify the message + /// NMSException if there is any problem + Task ConvertAndSendWithDelegate(IDestination destination, object message, MessagePostProcessorDelegate postProcessor); - /// - /// Send the given object to the specified destination, converting the object - /// to a NMS message with a configured IMessageConverter. The IMessagePostProcessor - /// callback allows for modification of the message after conversion. - /// - /// the name of the destination to send this message to - /// (to be resolved to an actual destination by a DestinationResolver) - /// the object to convert to a message. - /// the callback to modify the message - /// NMSException if there is any problem - Task ConvertAndSendWithDelegate(string destinationName, object message, MessagePostProcessorDelegate postProcessor); + /// + /// Send the given object to the specified destination, converting the object + /// to a NMS message with a configured IMessageConverter. The IMessagePostProcessor + /// callback allows for modification of the message after conversion. + /// + /// the name of the destination to send this message to + /// (to be resolved to an actual destination by a DestinationResolver) + /// the object to convert to a message. + /// the callback to modify the message + /// NMSException if there is any problem + Task ConvertAndSendWithDelegate(string destinationName, object message, MessagePostProcessorDelegate postProcessor); - //------------------------------------------------------------------------- - // Convenience methods for receiving messages - //------------------------------------------------------------------------- + //------------------------------------------------------------------------- + // Convenience methods for receiving messages + //------------------------------------------------------------------------- - /// Receive a message synchronously from the default destination, but only - /// wait up to a specified time for delivery. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///

This will only work with a default destination specified!

- ///
- /// the message received by the consumer, or null if the timeout expires - /// - /// NMSException if there is any problem - Task Receive(); + /// Receive a message synchronously from the default destination, but only + /// wait up to a specified time for delivery. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///

This will only work with a default destination specified!

+ ///
+ /// the message received by the consumer, or null if the timeout expires + /// + /// NMSException if there is any problem + Task Receive(); - /// Receive a message synchronously from the specified destination, but only - /// wait up to a specified time for delivery. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///
- /// the destination to receive a message from - /// - /// the message received by the consumer, or null if the timeout expires - /// - /// NMSException if there is any problem - Task Receive(IDestination destination); + /// Receive a message synchronously from the specified destination, but only + /// wait up to a specified time for delivery. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///
+ /// the destination to receive a message from + /// + /// the message received by the consumer, or null if the timeout expires + /// + /// NMSException if there is any problem + Task Receive(IDestination destination); - /// Receive a message synchronously from the specified destination, but only - /// wait up to a specified time for delivery. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///
- /// the name of the destination to send this message to - /// (to be resolved to an actual destination by a DestinationResolver) - /// - /// the message received by the consumer, or null if the timeout expires - /// - /// NMSException if there is any problem - Task Receive(string destinationName); + /// Receive a message synchronously from the specified destination, but only + /// wait up to a specified time for delivery. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///
+ /// the name of the destination to send this message to + /// (to be resolved to an actual destination by a DestinationResolver) + /// + /// the message received by the consumer, or null if the timeout expires + /// + /// NMSException if there is any problem + Task Receive(string destinationName); - /// Receive a message synchronously from the default destination, but only - /// wait up to a specified time for delivery. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///

This will only work with a default destination specified!

- ///
- /// the NMS message selector expression (or null if none). - /// See the NMS specification for a detailed definition of selector expressions. - /// - /// the message received by the consumer, or null if the timeout expires - /// - /// NMSException if there is any problem - Task ReceiveSelected(string messageSelector); + /// Receive a message synchronously from the default destination, but only + /// wait up to a specified time for delivery. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///

This will only work with a default destination specified!

+ ///
+ /// the NMS message selector expression (or null if none). + /// See the NMS specification for a detailed definition of selector expressions. + /// + /// the message received by the consumer, or null if the timeout expires + /// + /// NMSException if there is any problem + Task ReceiveSelected(string messageSelector); - /// Receive a message synchronously from the specified destination, but only - /// wait up to a specified time for delivery. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///
- /// the destination to receive a message from - /// - /// the NMS message selector expression (or null if none). - /// See the NMS specification for a detailed definition of selector expressions. - /// - /// the message received by the consumer, or null if the timeout expires - /// - /// NMSException if there is any problem - Task ReceiveSelected(IDestination destination, string messageSelector); + /// Receive a message synchronously from the specified destination, but only + /// wait up to a specified time for delivery. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///
+ /// the destination to receive a message from + /// + /// the NMS message selector expression (or null if none). + /// See the NMS specification for a detailed definition of selector expressions. + /// + /// the message received by the consumer, or null if the timeout expires + /// + /// NMSException if there is any problem + Task ReceiveSelected(IDestination destination, string messageSelector); - /// Receive a message synchronously from the specified destination, but only - /// wait up to a specified time for delivery. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///
- /// the name of the destination to send this message to - /// (to be resolved to an actual destination by a DestinationResolver) - /// - /// the NMS message selector expression (or null if none). - /// See the NMS specification for a detailed definition of selector expressions. - /// - /// the message received by the consumer, or null if the timeout expires - /// - /// NMSException if there is any problem - Task ReceiveSelected(string destinationName, string messageSelector); + /// Receive a message synchronously from the specified destination, but only + /// wait up to a specified time for delivery. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///
+ /// the name of the destination to send this message to + /// (to be resolved to an actual destination by a DestinationResolver) + /// + /// the NMS message selector expression (or null if none). + /// See the NMS specification for a detailed definition of selector expressions. + /// + /// the message received by the consumer, or null if the timeout expires + /// + /// NMSException if there is any problem + Task ReceiveSelected(string destinationName, string messageSelector); - //------------------------------------------------------------------------- - // Convenience methods for receiving auto-converted messages - //------------------------------------------------------------------------- + //------------------------------------------------------------------------- + // Convenience methods for receiving auto-converted messages + //------------------------------------------------------------------------- - /// Receive a message synchronously from the default destination, but only - /// wait up to a specified time for delivery. Convert the message into an - /// object with a configured IMessageConverter. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///

This will only work with a default destination specified!

- ///
- /// the message produced for the consumer or null if the timeout expires. - /// - /// NMSException if there is any problem - Task ReceiveAndConvert(); + /// Receive a message synchronously from the default destination, but only + /// wait up to a specified time for delivery. Convert the message into an + /// object with a configured IMessageConverter. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///

This will only work with a default destination specified!

+ ///
+ /// the message produced for the consumer or null if the timeout expires. + /// + /// NMSException if there is any problem + Task ReceiveAndConvert(); - /// Receive a message synchronously from the specified destination, but only - /// wait up to a specified time for delivery. Convert the message into an - /// object with a configured IMessageConverter. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///
- /// the destination to receive a message from - /// - /// the message produced for the consumer or null if the timeout expires. - /// - /// NMSException if there is any problem - Task ReceiveAndConvert(IDestination destination); + /// Receive a message synchronously from the specified destination, but only + /// wait up to a specified time for delivery. Convert the message into an + /// object with a configured IMessageConverter. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///
+ /// the destination to receive a message from + /// + /// the message produced for the consumer or null if the timeout expires. + /// + /// NMSException if there is any problem + Task ReceiveAndConvert(IDestination destination); - /// Receive a message synchronously from the specified destination, but only - /// wait up to a specified time for delivery. Convert the message into an - /// object with a configured IMessageConverter. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///
- /// the name of the destination to send this message to - /// (to be resolved to an actual destination by a DestinationResolver) - /// - /// the message produced for the consumer or null if the timeout expires. - /// - /// NMSException if there is any problem - Task ReceiveAndConvert(string destinationName); + /// Receive a message synchronously from the specified destination, but only + /// wait up to a specified time for delivery. Convert the message into an + /// object with a configured IMessageConverter. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///
+ /// the name of the destination to send this message to + /// (to be resolved to an actual destination by a DestinationResolver) + /// + /// the message produced for the consumer or null if the timeout expires. + /// + /// NMSException if there is any problem + Task ReceiveAndConvert(string destinationName); - /// Receive a message synchronously from the default destination, but only - /// wait up to a specified time for delivery. Convert the message into an - /// object with a configured IMessageConverter. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///

This will only work with a default destination specified!

- ///
- /// the NMS message selector expression (or null if none). - /// See the NMS specification for a detailed definition of selector expressions. - /// - /// the message produced for the consumer or null if the timeout expires. - /// - /// NMSException if there is any problem - Task ReceiveSelectedAndConvert(string messageSelector); + /// Receive a message synchronously from the default destination, but only + /// wait up to a specified time for delivery. Convert the message into an + /// object with a configured IMessageConverter. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///

This will only work with a default destination specified!

+ ///
+ /// the NMS message selector expression (or null if none). + /// See the NMS specification for a detailed definition of selector expressions. + /// + /// the message produced for the consumer or null if the timeout expires. + /// + /// NMSException if there is any problem + Task ReceiveSelectedAndConvert(string messageSelector); - /// Receive a message synchronously from the specified destination, but only - /// wait up to a specified time for delivery. Convert the message into an - /// object with a configured IMessageConverter. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///
- /// the destination to receive a message from - /// - /// the NMS message selector expression (or null if none). - /// See the NMS specification for a detailed definition of selector expressions. - /// - /// the message produced for the consumer or null if the timeout expires. - /// - /// NMSException if there is any problem - Task ReceiveSelectedAndConvert(IDestination destination, string messageSelector); + /// Receive a message synchronously from the specified destination, but only + /// wait up to a specified time for delivery. Convert the message into an + /// object with a configured IMessageConverter. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///
+ /// the destination to receive a message from + /// + /// the NMS message selector expression (or null if none). + /// See the NMS specification for a detailed definition of selector expressions. + /// + /// the message produced for the consumer or null if the timeout expires. + /// + /// NMSException if there is any problem + Task ReceiveSelectedAndConvert(IDestination destination, string messageSelector); - /// Receive a message synchronously from the specified destination, but only - /// wait up to a specified time for delivery. Convert the message into an - /// object with a configured IMessageConverter. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///
- /// the name of the destination to send this message to - /// (to be resolved to an actual destination by a DestinationResolver) - /// - /// the NMS message selector expression (or null if none). - /// See the NMS specification for a detailed definition of selector expressions. - /// - /// the message produced for the consumer or null if the timeout expires. - /// - /// NMSException if there is any problem - Task ReceiveSelectedAndConvert(string destinationName, string messageSelector); - } + /// Receive a message synchronously from the specified destination, but only + /// wait up to a specified time for delivery. Convert the message into an + /// object with a configured IMessageConverter. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///
+ /// the name of the destination to send this message to + /// (to be resolved to an actual destination by a DestinationResolver) + /// + /// the NMS message selector expression (or null if none). + /// See the NMS specification for a detailed definition of selector expressions. + /// + /// the message produced for the consumer or null if the timeout expires. + /// + /// NMSException if there is any problem + Task ReceiveSelectedAndConvert(string destinationName, string messageSelector); } diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/IProducerCallback.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/IProducerCallback.cs index 78ca5789..2de47bcc 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/IProducerCallback.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/IProducerCallback.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -20,29 +20,27 @@ using Apache.NMS; -namespace Spring.Messaging.Nms.Core +namespace Spring.Messaging.Nms.Core; + +/// Callback for sending a message to a NMS destination. +/// +///

To be used with the MessageTemplate.Execute(IProducerCallback) +/// method, often implemented as an anonymous inner class.

+/// +///

The typical implementation will perform multiple operations on the +/// supplied NMS Session and MessageProducer.

+///
+/// Mark Pollack +public interface IProducerCallback { - /// Callback for sending a message to a NMS destination. - /// - ///

To be used with the MessageTemplate.Execute(IProducerCallback) - /// method, often implemented as an anonymous inner class.

- /// - ///

The typical implementation will perform multiple operations on the - /// supplied NMS Session and MessageProducer.

- ///
- /// Mark Pollack - public interface IProducerCallback - { - /// Perform operations on the given Session and MessageProducer. - /// The message producer is not associated with any destination. - /// - /// the NMS Session object to use - /// - /// the NMS MessageProducer object to use - /// - /// a result object from working with the Session, if any (can be null) - /// - object DoInNms(ISession session, IMessageProducer producer); - - } -} \ No newline at end of file + /// Perform operations on the given Session and MessageProducer. + /// The message producer is not associated with any destination. + /// + /// the NMS Session object to use + /// + /// the NMS MessageProducer object to use + /// + /// a result object from working with the Session, if any (can be null) + /// + object DoInNms(ISession session, IMessageProducer producer); +} diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/IProducerCallbackAsync.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/IProducerCallbackAsync.cs index 3dd963bf..e1ad21fe 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/IProducerCallbackAsync.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/IProducerCallbackAsync.cs @@ -1,4 +1,5 @@ #region License + // /* // * Copyright 2022 the original author or authors. // * @@ -14,28 +15,27 @@ // * See the License for the specific language governing permissions and // * limitations under the License. // */ + #endregion using Apache.NMS; -namespace Spring.Messaging.Nms.Core +namespace Spring.Messaging.Nms.Core; + +/// +/// Async version of IProducerCallback +/// +/// +public interface IProducerCallbackAsync { - /// - /// Async version of IProducerCallback + /// Perform operations on the given Session and MessageProducer. + /// The message producer is not associated with any destination. /// - /// - public interface IProducerCallbackAsync - { - /// Perform operations on the given Session and MessageProducer. - /// The message producer is not associated with any destination. - /// - /// the NMS Session object to use - /// - /// the NMS MessageProducer object to use - /// - /// a result object from working with the Session, if any (can be null) - /// - Task DoInNms(ISession session, IMessageProducer producer); - - } -} \ No newline at end of file + /// the NMS Session object to use + /// + /// the NMS MessageProducer object to use + /// + /// a result object from working with the Session, if any (can be null) + /// + Task DoInNms(ISession session, IMessageProducer producer); +} diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/ISessionCallback.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/ISessionCallback.cs index 13f4db65..49e60b4f 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/ISessionCallback.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/ISessionCallback.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -20,29 +20,28 @@ using Apache.NMS; -namespace Spring.Messaging.Nms.Core +namespace Spring.Messaging.Nms.Core; + +/// Callback for executing any number of operations on a provided +/// Session +/// +/// +/// To be used with the NmsTemplate.Execute(ISessionCallback)} +/// method. See for the equivalent callback +/// that can be used as a (anonymous) delegate. +/// +/// Mark Pollack +/// +/// +public interface ISessionCallback { - /// Callback for executing any number of operations on a provided - /// Session + /// Execute any number of operations against the supplied NMS + /// Session, possibly returning a result. /// - /// - /// To be used with the NmsTemplate.Execute(ISessionCallback)} - /// method. See for the equivalent callback - /// that can be used as a (anonymous) delegate. - /// - /// Mark Pollack - /// - /// - public interface ISessionCallback - { - /// Execute any number of operations against the supplied NMS - /// Session, possibly returning a result. - /// - /// the NMS Session - /// - /// a result object from working with the Session, if any (so can be null) - /// - /// NMSException if there is any problem - object DoInNms(ISession session); - } + /// the NMS Session + /// + /// a result object from working with the Session, if any (so can be null) + /// + /// NMSException if there is any problem + object DoInNms(ISession session); } diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/ISessionCallbackAsync.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/ISessionCallbackAsync.cs index d67cf1db..eb6ab269 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/ISessionCallbackAsync.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/ISessionCallbackAsync.cs @@ -1,4 +1,5 @@ #region License + // /* // * Copyright 2022 the original author or authors. // * @@ -14,28 +15,26 @@ // * See the License for the specific language governing permissions and // * limitations under the License. // */ + #endregion using Apache.NMS; -namespace Spring.Messaging.Nms.Core +namespace Spring.Messaging.Nms.Core; + +/// +/// Async version of ISessionCallback +/// +/// +public interface ISessionCallbackAsync { - /// - /// Async version of ISessionCallback + /// Execute any number of operations against the supplied NMS + /// Session, possibly returning a result. /// - /// - public interface ISessionCallbackAsync - { - /// Execute any number of operations against the supplied NMS - /// Session, possibly returning a result. - /// - /// the NMS Session - /// - /// a result object from working with the Session, if any (so can be null) - /// - /// NMSException if there is any problem - Task DoInNms(ISession session); - - - } -} + /// the NMS Session + /// + /// a result object from working with the Session, if any (so can be null) + /// + /// NMSException if there is any problem + Task DoInNms(ISession session); +} \ No newline at end of file diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/MessageCreatorDelegate.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/MessageCreatorDelegate.cs index e4a6397e..a22c83bc 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/MessageCreatorDelegate.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/MessageCreatorDelegate.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -20,16 +20,15 @@ using Apache.NMS; -namespace Spring.Messaging.Nms.Core -{ - /// - /// Delegate that creates a NMS message given a ISession - /// - /// the NMS Session to be used to create the - /// Message (never null) - /// - /// the Message to be sent - /// - /// NMSException if thrown by NMS API methods - public delegate IMessage MessageCreatorDelegate(ISession session); -} +namespace Spring.Messaging.Nms.Core; + +/// +/// Delegate that creates a NMS message given a ISession +/// +/// the NMS Session to be used to create the +/// Message (never null) +/// +/// the Message to be sent +/// +/// NMSException if thrown by NMS API methods +public delegate IMessage MessageCreatorDelegate(ISession session); diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/MessagePostProcessorDelegate.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/MessagePostProcessorDelegate.cs index 294950b1..4f5677f2 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/MessagePostProcessorDelegate.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/MessagePostProcessorDelegate.cs @@ -20,17 +20,15 @@ using Apache.NMS; -namespace Spring.Messaging.Nms.Core -{ +namespace Spring.Messaging.Nms.Core; - /// - /// Delegate that is used with NmsTemplate's ConvertAndSend method that converts - /// an object. - /// - /// - /// It allows for further modification of the message after it has been processed - /// by the converter. This is useful for setting of NMS Header and Properties. - /// - /// Mark Pollack - public delegate IMessage MessagePostProcessorDelegate(IMessage message); -} \ No newline at end of file +/// +/// Delegate that is used with NmsTemplate's ConvertAndSend method that converts +/// an object. +/// +/// +/// It allows for further modification of the message after it has been processed +/// by the converter. This is useful for setting of NMS Header and Properties. +/// +/// Mark Pollack +public delegate IMessage MessagePostProcessorDelegate(IMessage message); diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/NmsGatewaySupport.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/NmsGatewaySupport.cs index 2dcee77d..90f4d55d 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/NmsGatewaySupport.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/NmsGatewaySupport.cs @@ -22,96 +22,93 @@ using Spring.Objects.Factory; using Apache.NMS; using Microsoft.Extensions.Logging; -namespace Spring.Messaging.Nms.Core +namespace Spring.Messaging.Nms.Core; + +/// +/// Convenient super class for application classes that need NMS access. +/// +/// +/// Requires a ConnectionFactory or a NmsTemplate instance to be set. +/// It will create its own NmsTemplate if a ConnectionFactory is passed in. +/// A custom NmsTemplate instance can be created for a given ConnectionFactory +/// through overriding the createNmsTemplate method. +/// +public class NmsGatewaySupport : IInitializingObject { + #region Logging + + private readonly ILogger logger = LogManager.GetLogger(); + + #endregion + + private NmsTemplate nmsTemplate; + /// - /// Convenient super class for application classes that need NMS access. + /// Gets or sets the NMS template for the gateway. /// - /// - /// Requires a ConnectionFactory or a NmsTemplate instance to be set. - /// It will create its own NmsTemplate if a ConnectionFactory is passed in. - /// A custom NmsTemplate instance can be created for a given ConnectionFactory - /// through overriding the createNmsTemplate method. - /// - public class NmsGatewaySupport : IInitializingObject + /// The NMS template. + public NmsTemplate NmsTemplate { + get { return nmsTemplate; } + set { nmsTemplate = value; } + } - #region Logging - - private readonly ILogger logger = LogManager.GetLogger(); - - #endregion - - private NmsTemplate nmsTemplate; - - - /// - /// Gets or sets the NMS template for the gateway. - /// - /// The NMS template. - public NmsTemplate NmsTemplate + /// + /// Gets or sets he NMS connection factory to be used by the gateway. + /// Will automatically create a NmsTemplate for the given ConnectionFactory. + /// + /// The connection factory. + public IConnectionFactory ConnectionFactory + { + get { - get { return nmsTemplate; } - set { nmsTemplate = value; } + return (nmsTemplate != null ? this.nmsTemplate.ConnectionFactory : null); } - - /// - /// Gets or sets he NMS connection factory to be used by the gateway. - /// Will automatically create a NmsTemplate for the given ConnectionFactory. - /// - /// The connection factory. - public IConnectionFactory ConnectionFactory + set { - get - { - return (nmsTemplate != null ? this.nmsTemplate.ConnectionFactory : null); - } - set - { - this.nmsTemplate = CreateNmsTemplate(value); - } - } - - /// - /// Creates a NmsTemplate for the given ConnectionFactory. - /// - /// Only invoked if populating the gateway with a ConnectionFactory reference. - /// Can be overridden in subclasses to provide a different NmsTemplate instance - /// - /// - /// The connection factory. - /// - protected virtual NmsTemplate CreateNmsTemplate(IConnectionFactory connectionFactory) - { - return new NmsTemplate(connectionFactory); - } - - /// - /// Ensures that the JmsTemplate is specified and calls . - /// - public virtual void AfterPropertiesSet() - { - if (nmsTemplate == null) - { - throw new ArgumentException("connectionFactory or jmsTemplate is required"); - } - try - { - InitGateway(); - } - catch (Exception e) - { - throw new ObjectInitializationException("Initialization of the NMS gateway failed: " + e.Message, e); - } - } - - /// - /// Subclasses can override this for custom initialization behavior. - /// Gets called after population of this instance's properties. - /// - protected virtual void InitGateway() - { - + this.nmsTemplate = CreateNmsTemplate(value); } } + + /// + /// Creates a NmsTemplate for the given ConnectionFactory. + /// + /// Only invoked if populating the gateway with a ConnectionFactory reference. + /// Can be overridden in subclasses to provide a different NmsTemplate instance + /// + /// + /// The connection factory. + /// + protected virtual NmsTemplate CreateNmsTemplate(IConnectionFactory connectionFactory) + { + return new NmsTemplate(connectionFactory); + } + + /// + /// Ensures that the JmsTemplate is specified and calls . + /// + public virtual void AfterPropertiesSet() + { + if (nmsTemplate == null) + { + throw new ArgumentException("connectionFactory or jmsTemplate is required"); + } + + try + { + InitGateway(); + } + catch (Exception e) + { + throw new ObjectInitializationException("Initialization of the NMS gateway failed: " + e.Message, e); + } + } + + /// + /// Subclasses can override this for custom initialization behavior. + /// Gets called after population of this instance's properties. + /// + protected virtual void InitGateway() + { + } } diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/NmsTemplate.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/NmsTemplate.cs index ed2d0ff4..0a9a8922 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/NmsTemplate.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/NmsTemplate.cs @@ -27,1494 +27,1479 @@ using Spring.Util; using Apache.NMS; using Microsoft.Extensions.Logging; -namespace Spring.Messaging.Nms.Core +namespace Spring.Messaging.Nms.Core; + +/// Helper class that simplifies NMS access code. +/// +/// If you want to use dynamic destination creation, you must specify +/// the type of NMS destination to create, using the "pubSubDomain" property. +/// For other operations, this is not necessary. +/// Point-to-Point (Queues) is the default domain. +/// +/// Default settings for NMS Sessions is "auto-acknowledge". +/// +/// This template uses a DynamicDestinationResolver and a SimpleMessageConverter +/// as default strategies for resolving a destination name or converting a message, +/// respectively. +/// +/// +/// Mark Pollack +/// Juergen Hoeller +/// Mark Pollack (.NET) +public class NmsTemplate : NmsDestinationAccessor, INmsOperations { - /// Helper class that simplifies NMS access code. + #region Logging + + private readonly ILogger logger = LogManager.GetLogger(); + + #endregion + + #region Fields + + /// + /// Timeout value indicating that a receive operation should + /// check if a message is immediately available without blocking. + /// + public static readonly long RECEIVE_TIMEOUT_NO_WAIT = -1; + + /// + /// Timeout value indicating a blocking receive without timeout. + /// + public static readonly long RECEIVE_TIMEOUT_INDEFINITE_WAIT = 0; + + private NmsTemplateResourceFactory transactionalResourceFactory; + + private object defaultDestination; + + private IMessageConverter messageConverter; + + private bool messageIdEnabled = true; + + private bool messageTimestampEnabled = true; + + private bool pubSubNoLocal = false; + + private long receiveTimeout = RECEIVE_TIMEOUT_NO_WAIT; + + private bool explicitQosEnabled = false; + + private MsgPriority priority = NMSConstants.defaultPriority; + + private TimeSpan timeToLive; + + private MsgDeliveryMode deliveryMode = NMSConstants.defaultDeliveryMode; + + #endregion + + #region Constructor (s) + + /// Create a new NmsTemplate. /// - /// If you want to use dynamic destination creation, you must specify - /// the type of NMS destination to create, using the "pubSubDomain" property. - /// For other operations, this is not necessary. - /// Point-to-Point (Queues) is the default domain. - /// - /// Default settings for NMS Sessions is "auto-acknowledge". - /// - /// This template uses a DynamicDestinationResolver and a SimpleMessageConverter - /// as default strategies for resolving a destination name or converting a message, - /// respectively. - /// + /// Note: The ConnectionFactory has to be set before using the instance. + /// This constructor can be used to prepare a NmsTemplate via an ObjectFactory, + /// typically setting the ConnectionFactory. /// - /// Mark Pollack - /// Juergen Hoeller - /// Mark Pollack (.NET) - public class NmsTemplate : NmsDestinationAccessor, INmsOperations + public NmsTemplate() { - #region Logging + transactionalResourceFactory = new NmsTemplateResourceFactory(this); + InitDefaultStrategies(); + } - private readonly ILogger logger = LogManager.GetLogger(); + /// Create a new NmsTemplate, given a ConnectionFactory. + /// the ConnectionFactory to obtain IConnections from + /// + public NmsTemplate(IConnectionFactory connectionFactory) + : this() + { + ConnectionFactory = connectionFactory; + AfterPropertiesSet(); + } + #endregion - #endregion + #region Methods - #region Fields + /// Initialize the default implementations for the template's strategies: + /// DynamicDestinationResolver and SimpleMessageConverter. + /// + protected virtual void InitDefaultStrategies() + { + MessageConverter = new SimpleMessageConverter(); + } - /// - /// Timeout value indicating that a receive operation should - /// check if a message is immediately available without blocking. - /// - public static readonly long RECEIVE_TIMEOUT_NO_WAIT = -1; - - /// - /// Timeout value indicating a blocking receive without timeout. - /// - public static readonly long RECEIVE_TIMEOUT_INDEFINITE_WAIT = 0; - - private NmsTemplateResourceFactory transactionalResourceFactory; - - private object defaultDestination; - - private IMessageConverter messageConverter; - - - private bool messageIdEnabled = true; - - private bool messageTimestampEnabled = true; - - private bool pubSubNoLocal = false; - - private long receiveTimeout = RECEIVE_TIMEOUT_NO_WAIT; - - private bool explicitQosEnabled = false; - - private MsgPriority priority = NMSConstants.defaultPriority; - - private TimeSpan timeToLive; - - private MsgDeliveryMode deliveryMode = NMSConstants.defaultDeliveryMode; - - #endregion - - #region Constructor (s) - - /// Create a new NmsTemplate. - /// - /// Note: The ConnectionFactory has to be set before using the instance. - /// This constructor can be used to prepare a NmsTemplate via an ObjectFactory, - /// typically setting the ConnectionFactory. - /// - public NmsTemplate() + private void CheckDefaultDestination() + { + if (defaultDestination == null) { - transactionalResourceFactory = new NmsTemplateResourceFactory(this); - InitDefaultStrategies(); + throw new SystemException( + "No defaultDestination or defaultDestinationName specified. Check configuration of NmsTemplate."); } + } - - /// Create a new NmsTemplate, given a ConnectionFactory. - /// the ConnectionFactory to obtain IConnections from - /// - public NmsTemplate(IConnectionFactory connectionFactory) - : this() + private void CheckMessageConverter() + { + if (MessageConverter == null) { - ConnectionFactory = connectionFactory; - AfterPropertiesSet(); + throw new SystemException("No messageConverter registered. Check configuration of NmsTemplate."); } + } - #endregion + /// Execute the action specified by the given action object within a + /// NMS Session. + /// + /// Generalized version of execute(ISessionCallback), + /// allowing the NMS Connection to be started on the fly. + ///

Use execute(ISessionCallback) for the general case. + /// Starting the NMS Connection is just necessary for receiving messages, + /// which is preferably achieved through the receive methods.

+ ///
+ /// callback object that exposes the session + /// + /// Start the connection before performing callback action. + /// + /// the result object from working with the session + /// + /// NMSException if there is any problem + public virtual object Execute(ISessionCallback action, bool startConnection) + { + AssertUtils.ArgumentNotNull(action, "Callback object must not be null"); - #region Methods - - /// Initialize the default implementations for the template's strategies: - /// DynamicDestinationResolver and SimpleMessageConverter. - /// - protected virtual void InitDefaultStrategies() + IConnection conToClose = null; + ISession sessionToClose = null; + try { - MessageConverter = new SimpleMessageConverter(); - } - - private void CheckDefaultDestination() - { - if (defaultDestination == null) + ISession sessionToUse = + ConnectionFactoryUtils.DoGetTransactionalSession(ConnectionFactory, transactionalResourceFactory, + startConnection, true).GetAsyncResult(); + if (sessionToUse == null) { - throw new SystemException( - "No defaultDestination or defaultDestinationName specified. Check configuration of NmsTemplate."); - } - } - - - private void CheckMessageConverter() - { - if (MessageConverter == null) - { - throw new SystemException("No messageConverter registered. Check configuration of NmsTemplate."); - } - } - - /// Execute the action specified by the given action object within a - /// NMS Session. - /// - /// Generalized version of execute(ISessionCallback), - /// allowing the NMS Connection to be started on the fly. - ///

Use execute(ISessionCallback) for the general case. - /// Starting the NMS Connection is just necessary for receiving messages, - /// which is preferably achieved through the receive methods.

- ///
- /// callback object that exposes the session - /// - /// Start the connection before performing callback action. - /// - /// the result object from working with the session - /// - /// NMSException if there is any problem - public virtual object Execute(ISessionCallback action, bool startConnection) - { - AssertUtils.ArgumentNotNull(action, "Callback object must not be null"); - - IConnection conToClose = null; - ISession sessionToClose = null; - try - { - ISession sessionToUse = - ConnectionFactoryUtils.DoGetTransactionalSession(ConnectionFactory, transactionalResourceFactory, - startConnection, true).GetAsyncResult(); - if (sessionToUse == null) + conToClose = CreateConnection(); + sessionToClose = CreateSession(conToClose); + if (startConnection) { - conToClose = CreateConnection(); - sessionToClose = CreateSession(conToClose); - if (startConnection) - { - conToClose.Start(); - } - sessionToUse = sessionToClose; + conToClose.Start(); } - if (logger.IsEnabled(LogLevel.Debug)) - { - logger.LogDebug("Executing callback on NMS ISession [" + sessionToUse + "]"); - } - return action.DoInNms(sessionToUse); + + sessionToUse = sessionToClose; } - finally + + if (logger.IsEnabled(LogLevel.Debug)) { - NmsUtils.CloseSession(sessionToClose); - ConnectionFactoryUtils.ReleaseConnection(conToClose, ConnectionFactory, startConnection); + logger.LogDebug("Executing callback on NMS ISession [" + sessionToUse + "]"); } + + return action.DoInNms(sessionToUse); } - - #endregion - - #region Properties - - /// - /// Gets or sets the default destination to be used on send/receive operations that do not - /// have a destination parameter. - /// - /// Alternatively, specify a "defaultDestinationName", to be - /// dynamically resolved via the DestinationResolver. - /// The default destination. - virtual public IDestination DefaultDestination + finally { - get { return (defaultDestination as IDestination); } - - set { defaultDestination = value; } + NmsUtils.CloseSession(sessionToClose); + ConnectionFactoryUtils.ReleaseConnection(conToClose, ConnectionFactory, startConnection); } + } + #endregion - /// - /// Gets or sets the name of the default destination name - /// to be used on send/receive operations that - /// do not have a destination parameter. - /// - /// - /// Alternatively, specify a NMS IDestination object as "DefaultDestination" - /// - /// The name of the default destination. - virtual public string DefaultDestinationName + #region Properties + + /// + /// Gets or sets the default destination to be used on send/receive operations that do not + /// have a destination parameter. + /// + /// Alternatively, specify a "defaultDestinationName", to be + /// dynamically resolved via the DestinationResolver. + /// The default destination. + virtual public IDestination DefaultDestination + { + get { return (defaultDestination as IDestination); } + + set { defaultDestination = value; } + } + + /// + /// Gets or sets the name of the default destination name + /// to be used on send/receive operations that + /// do not have a destination parameter. + /// + /// + /// Alternatively, specify a NMS IDestination object as "DefaultDestination" + /// + /// The name of the default destination. + virtual public string DefaultDestinationName + { + get { return (defaultDestination as string); } + + set { defaultDestination = value; } + } + + /// + /// Gets or sets the message converter for this template. + /// + /// + /// Used to resolve + /// Object parameters to convertAndSend methods and Object results + /// from receiveAndConvert methods. + ///

The default converter is a SimpleMessageConverter, which is able + /// to handle IBytesMessages, ITextMessages and IObjectMessages.

+ ///
+ /// The message converter. + virtual public IMessageConverter MessageConverter + { + get { return messageConverter; } + + set { messageConverter = value; } + } + + /// + /// Gets or sets a value indicating whether Message Ids are enabled. + /// + /// true if message id enabled; otherwise, false. + virtual public bool MessageIdEnabled + { + get { return messageIdEnabled; } + + set { messageIdEnabled = value; } + } + + /// + /// Gets or sets a value indicating whether message timestamps are enabled. + /// + /// + /// true if [message timestamp enabled]; otherwise, false. + /// + virtual public bool MessageTimestampEnabled + { + get { return messageTimestampEnabled; } + + set { messageTimestampEnabled = value; } + } + + /// + /// Gets or sets a value indicating whether to inhibit the delivery of messages published by its own connection. + /// + /// + /// true if inhibit the delivery of messages published by its own connection; otherwise, false. + virtual public bool PubSubNoLocal + { + get { return pubSubNoLocal; } + + set { pubSubNoLocal = value; } + } + + /// + /// Gets or sets the receive timeout to use for recieve calls (in milliseconds) + /// + /// The default is -1, which means no timeout. + /// The receive timeout. + virtual public long ReceiveTimeout + { + get { return receiveTimeout; } + + set { receiveTimeout = value; } + } + + /// + /// Gets or sets a value indicating whether to use explicit Quality of Service values. + /// + /// If "true", then the values of deliveryMode, priority, and timeToLive + /// will be used when sending a message. Otherwise, the default values, + /// that may be set administratively, will be used + /// true if use explicit QoS values; otherwise, false. + virtual public bool ExplicitQosEnabled + { + get { return explicitQosEnabled; } + + set { explicitQosEnabled = value; } + } + + /// + /// Sets a value indicating whether message delivery should be persistent or non-persistent + /// + /// + /// This will set the delivery to persistent or non-persistent + ///

Default it "true" aka delivery mode "PERSISTENT".

+ ///
+ /// true if [delivery persistent]; otherwise, false. + virtual public bool Persistent + { + get { return (deliveryMode == MsgDeliveryMode.Persistent); } + + set { - get { return (defaultDestination as string); } - - set { defaultDestination = value; } - } - - /// - /// Gets or sets the message converter for this template. - /// - /// - /// Used to resolve - /// Object parameters to convertAndSend methods and Object results - /// from receiveAndConvert methods. - ///

The default converter is a SimpleMessageConverter, which is able - /// to handle IBytesMessages, ITextMessages and IObjectMessages.

- ///
- /// The message converter. - virtual public IMessageConverter MessageConverter - { - get { return messageConverter; } - - set { messageConverter = value; } - } - - /// - /// Gets or sets a value indicating whether Message Ids are enabled. - /// - /// true if message id enabled; otherwise, false. - virtual public bool MessageIdEnabled - { - get { return messageIdEnabled; } - - set { messageIdEnabled = value; } - } - - /// - /// Gets or sets a value indicating whether message timestamps are enabled. - /// - /// - /// true if [message timestamp enabled]; otherwise, false. - /// - virtual public bool MessageTimestampEnabled - { - get { return messageTimestampEnabled; } - - set { messageTimestampEnabled = value; } - } - - - /// - /// Gets or sets a value indicating whether to inhibit the delivery of messages published by its own connection. - /// - /// - /// true if inhibit the delivery of messages published by its own connection; otherwise, false. - virtual public bool PubSubNoLocal - { - get { return pubSubNoLocal; } - - set { pubSubNoLocal = value; } - } - - /// - /// Gets or sets the receive timeout to use for recieve calls (in milliseconds) - /// - /// The default is -1, which means no timeout. - /// The receive timeout. - virtual public long ReceiveTimeout - { - get { return receiveTimeout; } - - set { receiveTimeout = value; } - } - - /// - /// Gets or sets a value indicating whether to use explicit Quality of Service values. - /// - /// If "true", then the values of deliveryMode, priority, and timeToLive - /// will be used when sending a message. Otherwise, the default values, - /// that may be set administratively, will be used - /// true if use explicit QoS values; otherwise, false. - virtual public bool ExplicitQosEnabled - { - get { return explicitQosEnabled; } - - set { explicitQosEnabled = value; } - } - - /// - /// Sets a value indicating whether message delivery should be persistent or non-persistent - /// - /// - /// This will set the delivery to persistent or non-persistent - ///

Default it "true" aka delivery mode "PERSISTENT".

- ///
- /// true if [delivery persistent]; otherwise, false. - virtual public bool Persistent - { - get { return (deliveryMode == MsgDeliveryMode.Persistent); } - - set + if (value) { - if (value) { - deliveryMode = MsgDeliveryMode.Persistent; - } else { - deliveryMode = MsgDeliveryMode.NonPersistent; - } - } - } - - /// - /// Gets or sets a value indicating what DeliveryMode this - /// should use, for example a persistent QOS - /// - /// - virtual public MsgDeliveryMode DeliveryMode - { - get { return deliveryMode; } - set { deliveryMode = value; } - } - - /// - /// Gets or sets the priority when sending. - /// - /// Since a default value may be defined administratively, - /// this is only used when "isExplicitQosEnabled" equals "true". - /// The priority. - virtual public MsgPriority Priority - { - get { return priority; } - - set { priority = value; } - } - - /// - /// Gets or sets the time to live when sending - /// - /// Since a default value may be defined administratively, - /// this is only used when "isExplicitQosEnabled" equals "true". - /// The time to live. - virtual public TimeSpan TimeToLive - { - get { return timeToLive; } - - set { timeToLive = value; } - } - - - #endregion - - /// - /// Extract the content from the given JMS message. - /// - /// The Message to convert (can be null). - /// The content of the message, or null if none - protected virtual object DoConvertFromMessage(IMessage message) - { - if (message != null) - { - return MessageConverter.FromMessage(message); - } - return null; - } - - #region NMS Factory Methods - - /// Fetch an appropriate Connection from the given MessageResourceHolder. - /// - /// the MessageResourceHolder - /// - /// an appropriate IConnection fetched from the holder, - /// or null if none found - /// - protected virtual IConnection GetConnection(NmsResourceHolder holder) - { - return holder.GetConnection(); - } - - /// Fetch an appropriate Session from the given MessageResourceHolder. - /// - /// the MessageResourceHolder - /// - /// an appropriate ISession fetched from the holder, - /// or null if none found - /// - protected virtual ISession GetSession(NmsResourceHolder holder) - { - return holder.GetSession(); - } - - /// Create a NMS MessageProducer for the given Session and Destination, - /// configuring it to disable message ids and/or timestamps (if necessary). - ///

Delegates to doCreateProducer for creation of the raw - /// NMS MessageProducer

- ///
- /// the NMS Session to create a MessageProducer for - /// - /// the NMS Destination to create a MessageProducer for - /// - /// the new NMS MessageProducer - /// - /// NMSException if thrown by NMS API methods - /// - /// - /// - /// - /// - /// - protected virtual IMessageProducer CreateProducer(ISession session, IDestination destination) - { - IMessageProducer producer = DoCreateProducer(session, destination); - if (!MessageIdEnabled) - { - producer.DisableMessageID = true; - } - if (!MessageTimestampEnabled) - { - producer.DisableMessageTimestamp = true; - } - return producer; - } - - - /// - /// Determines whether the given Session is locally transacted, that is, whether - /// its transaction is managed by this template class's Session handling - /// and not by an external transaction coordinator. - /// - /// - /// The Session's own transacted flag will already have been checked - /// before. This method is about finding out whether the Session's transaction - /// is local or externally coordinated. - /// - /// The session to check. - /// - /// true if the session is locally transacted; otherwise, false. - /// - protected virtual bool IsSessionLocallyTransacted(ISession session) - { - return SessionTransacted && - !ConnectionFactoryUtils.IsSessionTransactional(session, ConnectionFactory); - } - - /// Create a raw NMS MessageProducer for the given Session and Destination. - /// - /// the NMS Session to create a MessageProducer for - /// - /// the NMS IDestination to create a MessageProducer for - /// - /// the new NMS MessageProducer - /// - /// NMSException if thrown by NMS API methods - protected virtual IMessageProducer DoCreateProducer(ISession session, IDestination destination) - { - return session.CreateProducer(destination); - } - - /// Create a NMS MessageConsumer for the given Session and Destination. - /// - /// the NMS Session to create a MessageConsumer for - /// - /// the NMS Destination to create a MessageConsumer for - /// - /// the message selector for this consumer (can be null) - /// - /// the new NMS IMessageConsumer - /// - /// NMSException if thrown by NMS API methods - protected virtual IMessageConsumer CreateConsumer(ISession session, IDestination destination, - string messageSelector) - { - // Only pass in the NoLocal flag in case of a Topic: - // Some NMS providers, such as WebSphere MQ 6.0, throw IllegalStateException - // in case of the NoLocal flag being specified for a Queue. - if (PubSubDomain) - { - return session.CreateConsumer(destination, messageSelector, PubSubNoLocal); + deliveryMode = MsgDeliveryMode.Persistent; } else { - return session.CreateConsumer(destination, messageSelector); + deliveryMode = MsgDeliveryMode.NonPersistent; } } + } - /// - /// Send the given message. - /// - /// The session to operate on. - /// The destination to send to. - /// The message creator delegate callback to create a Message. - protected internal virtual void DoSend(ISession session, IDestination destination, MessageCreatorDelegate messageCreatorDelegate) + /// + /// Gets or sets a value indicating what DeliveryMode this + /// should use, for example a persistent QOS + /// + /// + virtual public MsgDeliveryMode DeliveryMode + { + get { return deliveryMode; } + set { deliveryMode = value; } + } + + /// + /// Gets or sets the priority when sending. + /// + /// Since a default value may be defined administratively, + /// this is only used when "isExplicitQosEnabled" equals "true". + /// The priority. + virtual public MsgPriority Priority + { + get { return priority; } + + set { priority = value; } + } + + /// + /// Gets or sets the time to live when sending + /// + /// Since a default value may be defined administratively, + /// this is only used when "isExplicitQosEnabled" equals "true". + /// The time to live. + virtual public TimeSpan TimeToLive + { + get { return timeToLive; } + + set { timeToLive = value; } + } + + #endregion + + /// + /// Extract the content from the given JMS message. + /// + /// The Message to convert (can be null). + /// The content of the message, or null if none + protected virtual object DoConvertFromMessage(IMessage message) + { + if (message != null) { - AssertUtils.ArgumentNotNull(messageCreatorDelegate, "IMessageCreatorDelegate must not be null"); - DoSend(session, destination, null, messageCreatorDelegate); + return MessageConverter.FromMessage(message); } - /// - /// Send the given message. - /// - /// The session to operate on. - /// The destination to send to. - /// The message creator callback to create a Message. - protected internal virtual void DoSend(ISession session, IDestination destination, IMessageCreator messageCreator) + return null; + } + + #region NMS Factory Methods + + /// Fetch an appropriate Connection from the given MessageResourceHolder. + /// + /// the MessageResourceHolder + /// + /// an appropriate IConnection fetched from the holder, + /// or null if none found + /// + protected virtual IConnection GetConnection(NmsResourceHolder holder) + { + return holder.GetConnection(); + } + + /// Fetch an appropriate Session from the given MessageResourceHolder. + /// + /// the MessageResourceHolder + /// + /// an appropriate ISession fetched from the holder, + /// or null if none found + /// + protected virtual ISession GetSession(NmsResourceHolder holder) + { + return holder.GetSession(); + } + + /// Create a NMS MessageProducer for the given Session and Destination, + /// configuring it to disable message ids and/or timestamps (if necessary). + ///

Delegates to doCreateProducer for creation of the raw + /// NMS MessageProducer

+ ///
+ /// the NMS Session to create a MessageProducer for + /// + /// the NMS Destination to create a MessageProducer for + /// + /// the new NMS MessageProducer + /// + /// NMSException if thrown by NMS API methods + /// + /// + /// + /// + /// + /// + protected virtual IMessageProducer CreateProducer(ISession session, IDestination destination) + { + IMessageProducer producer = DoCreateProducer(session, destination); + if (!MessageIdEnabled) { - AssertUtils.ArgumentNotNull(messageCreator, "IMessageCreator must not be null"); - DoSend(session, destination, messageCreator, null); + producer.DisableMessageID = true; } - /// Send the given NMS message. - /// the NMS Session to operate on - /// - /// the NMS Destination to send to - /// - /// callback to create a NMS Message - /// - /// delegate callback to create a NMS Message - /// - /// NMSException if thrown by NMS API methods - protected internal virtual void DoSend(ISession session, IDestination destination, IMessageCreator messageCreator, - MessageCreatorDelegate messageCreatorDelegate) + if (!MessageTimestampEnabled) { + producer.DisableMessageTimestamp = true; + } + return producer; + } - IMessageProducer producer = CreateProducer(session, destination); - try + /// + /// Determines whether the given Session is locally transacted, that is, whether + /// its transaction is managed by this template class's Session handling + /// and not by an external transaction coordinator. + /// + /// + /// The Session's own transacted flag will already have been checked + /// before. This method is about finding out whether the Session's transaction + /// is local or externally coordinated. + /// + /// The session to check. + /// + /// true if the session is locally transacted; otherwise, false. + /// + protected virtual bool IsSessionLocallyTransacted(ISession session) + { + return SessionTransacted && + !ConnectionFactoryUtils.IsSessionTransactional(session, ConnectionFactory); + } + + /// Create a raw NMS MessageProducer for the given Session and Destination. + /// + /// the NMS Session to create a MessageProducer for + /// + /// the NMS IDestination to create a MessageProducer for + /// + /// the new NMS MessageProducer + /// + /// NMSException if thrown by NMS API methods + protected virtual IMessageProducer DoCreateProducer(ISession session, IDestination destination) + { + return session.CreateProducer(destination); + } + + /// Create a NMS MessageConsumer for the given Session and Destination. + /// + /// the NMS Session to create a MessageConsumer for + /// + /// the NMS Destination to create a MessageConsumer for + /// + /// the message selector for this consumer (can be null) + /// + /// the new NMS IMessageConsumer + /// + /// NMSException if thrown by NMS API methods + protected virtual IMessageConsumer CreateConsumer(ISession session, IDestination destination, + string messageSelector) + { + // Only pass in the NoLocal flag in case of a Topic: + // Some NMS providers, such as WebSphere MQ 6.0, throw IllegalStateException + // in case of the NoLocal flag being specified for a Queue. + if (PubSubDomain) + { + return session.CreateConsumer(destination, messageSelector, PubSubNoLocal); + } + else + { + return session.CreateConsumer(destination, messageSelector); + } + } + + /// + /// Send the given message. + /// + /// The session to operate on. + /// The destination to send to. + /// The message creator delegate callback to create a Message. + protected internal virtual void DoSend(ISession session, IDestination destination, MessageCreatorDelegate messageCreatorDelegate) + { + AssertUtils.ArgumentNotNull(messageCreatorDelegate, "IMessageCreatorDelegate must not be null"); + DoSend(session, destination, null, messageCreatorDelegate); + } + + /// + /// Send the given message. + /// + /// The session to operate on. + /// The destination to send to. + /// The message creator callback to create a Message. + protected internal virtual void DoSend(ISession session, IDestination destination, IMessageCreator messageCreator) + { + AssertUtils.ArgumentNotNull(messageCreator, "IMessageCreator must not be null"); + DoSend(session, destination, messageCreator, null); + } + + /// Send the given NMS message. + /// the NMS Session to operate on + /// + /// the NMS Destination to send to + /// + /// callback to create a NMS Message + /// + /// delegate callback to create a NMS Message + /// + /// NMSException if thrown by NMS API methods + protected internal virtual void DoSend(ISession session, IDestination destination, IMessageCreator messageCreator, + MessageCreatorDelegate messageCreatorDelegate) + { + IMessageProducer producer = CreateProducer(session, destination); + try + { + IMessage message = null; + if (messageCreator != null) { - - IMessage message = null; - if (messageCreator != null) - { - message = messageCreator.CreateMessage(session) ; - } - else { - message = messageCreatorDelegate(session); - } - if (logger.IsEnabled(LogLevel.Debug)) - { - logger.LogDebug("Sending created message [" + message + "]"); - } - DoSend(producer, message); + message = messageCreator.CreateMessage(session); + } + else + { + message = messageCreatorDelegate(session); + } - // Check commit, avoid commit call is Session transaction is externally coordinated. - if (session.Transacted && IsSessionLocallyTransacted(session)) + if (logger.IsEnabled(LogLevel.Debug)) + { + logger.LogDebug("Sending created message [" + message + "]"); + } + + DoSend(producer, message); + + // Check commit, avoid commit call is Session transaction is externally coordinated. + if (session.Transacted && IsSessionLocallyTransacted(session)) + { + // Transacted session created by this template -> commit. + NmsUtils.CommitIfNecessary(session); + } + } + finally + { + NmsUtils.CloseMessageProducer(producer); + } + } + + /// Actually send the given NMS message. + /// the NMS MessageProducer to send with + /// + /// the NMS Message to send + /// + /// NMSException if thrown by NMS API methods + protected virtual void DoSend(IMessageProducer producer, IMessage message) + { + if (ExplicitQosEnabled) + { + producer.Send(message, DeliveryMode, Priority, TimeToLive); + } + else + { + producer.Send(message); + } + } + + #endregion + + #region IMessageOperations Implementation + + /// + /// Execute the action specified by the given action object within + /// a NMS Session. + /// + /// delegate that exposes the session + /// + /// the result object from working with the session + /// + /// + /// Note that the value of PubSubDomain affects the behavior of this method. + /// If PubSubDomain equals true, then a Session is passed to the callback. + /// If false, then a ISession is passed to the callback.b + /// + /// NMSException if there is any problem + public object Execute(SessionDelegate del) + { + return Execute(new ExecuteSessionCallbackUsingDelegate(del)); + } + + /// Execute the action specified by the given action object within + /// a NMS Session. + ///

Note: The value of PubSubDomain affects the behavior of this method. + /// If PubSubDomain equals true, then a Session is passed to the callback. + /// If false, then a Session is passed to the callback.

+ ///
+ /// callback object that exposes the session + /// + /// the result object from working with the session + /// + /// NMSException if there is any problem + public object Execute(ISessionCallback action) + { + return Execute(action, false); + } + + /// Send a message to a NMS destination. The callback gives access to + /// the NMS session and MessageProducer in order to do more complex + /// send operations. + /// + /// callback object that exposes the session/producer pair + /// + /// the result object from working with the session + /// + /// NMSException if there is any problem + public object Execute(IProducerCallback action) + { + return Execute(new ProducerCreatorCallback(this, action)); + } + + /// Send a message to a NMS destination. The callback gives access to + /// the NMS session and MessageProducer in order to do more complex + /// send operations. + /// + /// delegate that exposes the session/producer pair + /// + /// the result object from working with the session + /// + /// NMSException if there is any problem + public object Execute(ProducerDelegate del) + { + return Execute(new ProducerCreatorCallback(this, del)); + } + + /// Send a message to the default destination. + ///

This will only work with a default destination specified!

+ ///
+ /// delegate callback to create a message + /// + /// NMSException if there is any problem + public void SendWithDelegate(MessageCreatorDelegate messageCreatorDelegate) + { + CheckDefaultDestination(); + if (DefaultDestination != null) + { + SendWithDelegate(DefaultDestination, messageCreatorDelegate); + } + else + { + SendWithDelegate(DefaultDestinationName, messageCreatorDelegate); + } + } + + /// Send a message to the specified destination. + /// The MessageCreator callback creates the message given a Session. + /// + /// the destination to send this message to + /// + /// delegate callback to create a message + /// + /// NMSException if there is any problem + public void SendWithDelegate(IDestination destination, MessageCreatorDelegate messageCreatorDelegate) + { + Execute(new SendDestinationCallback(this, destination, messageCreatorDelegate), false); + } + + /// Send a message to the specified destination. + /// The MessageCreator callback creates the message given a Session. + /// + /// the name of the destination to send this message to + /// (to be resolved to an actual destination by a DestinationResolver) + /// + /// delegate callback to create a message + /// + /// NMSException if there is any problem + public void SendWithDelegate(string destinationName, MessageCreatorDelegate messageCreatorDelegate) + { + Execute(new SendDestinationCallback(this, destinationName, messageCreatorDelegate), false); + } + + /// Send a message to the default destination. + ///

This will only work with a default destination specified!

+ ///
+ /// callback to create a message + /// + /// NMSException if there is any problem + public void Send(IMessageCreator messageCreator) + { + CheckDefaultDestination(); + if (DefaultDestination != null) + { + Send(DefaultDestination, messageCreator); + } + else + { + Send(DefaultDestinationName, messageCreator); + } + } + + /// Send a message to the specified destination. + /// The MessageCreator callback creates the message given a Session. + /// + /// the destination to send this message to + /// + /// callback to create a message + /// + /// NMSException if there is any problem + public void Send(IDestination destination, IMessageCreator messageCreator) + { + Execute(new SendDestinationCallback(this, destination, messageCreator), false); + } + + /// Send a message to the specified destination. + /// The MessageCreator callback creates the message given a Session. + /// + /// the destination to send this message to + /// + /// callback to create a message + /// + /// NMSException if there is any problem + public void Send(string destinationName, IMessageCreator messageCreator) + { + Execute(new SendDestinationCallback(this, destinationName, messageCreator), false); + } + + /// Send the given object to the default destination, converting the object + /// to a NMS message with a configured IMessageConverter. + ///

This will only work with a default destination specified!

+ ///
+ /// the object to convert to a message + /// + /// NMSException if there is any problem + public void ConvertAndSend(object message) + { + CheckDefaultDestination(); + if (DefaultDestination != null) + { + ConvertAndSend(DefaultDestination, message); + } + else + { + ConvertAndSend(DefaultDestinationName, message); + } + } + + /// Send the given object to the specified destination, converting the object + /// to a NMS message with a configured IMessageConverter. + /// + /// the destination to send this message to + /// + /// the object to convert to a message + /// + /// NMSException if there is any problem + public void ConvertAndSend(IDestination destination, object message) + { + CheckMessageConverter(); + Send(destination, new SimpleMessageCreator(this, message)); + } + + /// Send the given object to the specified destination, converting the object + /// to a NMS message with a configured IMessageConverter. + /// + /// the name of the destination to send this message to + /// (to be resolved to an actual destination by a DestinationResolver) + /// + /// the object to convert to a message + /// + /// NMSException if there is any problem + public void ConvertAndSend(string destinationName, object message) + { + Send(destinationName, new SimpleMessageCreator(this, message)); + } + + /// Send the given object to the default destination, converting the object + /// to a NMS message with a configured IMessageConverter. The IMessagePostProcessor + /// callback allows for modification of the message after conversion. + ///

This will only work with a default destination specified!

+ ///
+ /// the object to convert to a message + /// + /// the callback to modify the message + /// + /// NMSException if there is any problem + public void ConvertAndSend(object message, IMessagePostProcessor postProcessor) + { + CheckDefaultDestination(); + if (DefaultDestination != null) + { + ConvertAndSend(DefaultDestination, message, postProcessor); + } + else + { + ConvertAndSend(DefaultDestinationName, message, postProcessor); + } + } + + /// Send the given object to the specified destination, converting the object + /// to a NMS message with a configured IMessageConverter. The IMessagePostProcessor + /// callback allows for modification of the message after conversion. + /// + /// the destination to send this message to + /// + /// the object to convert to a message + /// + /// the callback to modify the message + /// + /// NMSException if there is any problem + public void ConvertAndSend(IDestination destination, object message, IMessagePostProcessor postProcessor) + { + CheckMessageConverter(); + Send(destination, new ConvertAndSendMessageCreator(this, message, postProcessor)); + } + + /// Send the given object to the specified destination, converting the object + /// to a NMS message with a configured IMessageConverter. The IMessagePostProcessor + /// callback allows for modification of the message after conversion. + /// + /// the name of the destination to send this message to + /// (to be resolved to an actual destination by a DestinationResolver) + /// + /// the object to convert to a message. + /// + /// the callback to modify the message + /// + /// NMSException if there is any problem + public void ConvertAndSend(string destinationName, object message, IMessagePostProcessor postProcessor) + { + CheckMessageConverter(); + Send(destinationName, new ConvertAndSendMessageCreator(this, message, postProcessor)); + } + + /// + /// Send the given object to the default destination, converting the object + /// to a NMS message with a configured IMessageConverter. The IMessagePostProcessor + /// callback allows for modification of the message after conversion. + ///

This will only work with a default destination specified!

+ ///
+ /// the object to convert to a message + /// the callback to modify the message + /// NMSException if there is any problem + public void ConvertAndSendWithDelegate(object message, MessagePostProcessorDelegate postProcessor) + { + //Execute(new SendDestinationCallback(this, destination, messageCreatorDelegate), false); + CheckDefaultDestination(); + if (DefaultDestination != null) + { + ConvertAndSendWithDelegate(DefaultDestination, message, postProcessor); + } + else + { + ConvertAndSendWithDelegate(DefaultDestinationName, message, postProcessor); + } + } + + /// + /// Send the given object to the specified destination, converting the object + /// to a NMS message with a configured IMessageConverter. The IMessagePostProcessor + /// callback allows for modification of the message after conversion. + /// + /// the destination to send this message to + /// the object to convert to a message + /// the callback to modify the message + /// NMSException if there is any problem + public void ConvertAndSendWithDelegate(IDestination destination, object message, + MessagePostProcessorDelegate postProcessor) + { + CheckMessageConverter(); + Send(destination, new ConvertAndSendMessageCreator(this, message, postProcessor)); + } + + /// + /// Send the given object to the specified destination, converting the object + /// to a NMS message with a configured IMessageConverter. The IMessagePostProcessor + /// callback allows for modification of the message after conversion. + /// + /// the name of the destination to send this message to + /// (to be resolved to an actual destination by a DestinationResolver) + /// the object to convert to a message. + /// the callback to modify the message + /// NMSException if there is any problem + public void ConvertAndSendWithDelegate(string destinationName, object message, + MessagePostProcessorDelegate postProcessor) + { + CheckMessageConverter(); + Send(destinationName, new ConvertAndSendMessageCreator(this, message, postProcessor)); + } + + /// Receive a message synchronously from the default destination, but only + /// wait up to a specified time for delivery. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///

This will only work with a default destination specified!

+ ///
+ /// the message received by the consumer, or null if the timeout expires + /// + /// NMSException if there is any problem + public IMessage Receive() + { + CheckDefaultDestination(); + if (DefaultDestination != null) + { + return Receive(DefaultDestination); + } + else + { + return Receive(DefaultDestinationName); + } + } + + /// Receive a message synchronously from the specified destination, but only + /// wait up to a specified time for delivery. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///
+ /// the destination to receive a message from + /// + /// the message received by the consumer, or null if the timeout expires + /// + /// NMSException if there is any problem + public IMessage Receive(IDestination destination) + { + return ReceiveSelected(destination, null); + } + + /// Receive a message synchronously from the specified destination, but only + /// wait up to a specified time for delivery. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///
+ /// the name of the destination to send this message to + /// (to be resolved to an actual destination by a DestinationResolver) + /// + /// the message received by the consumer, or null if the timeout expires + /// + /// NMSException if there is any problem + public IMessage Receive(string destinationName) + { + return ReceiveSelected(destinationName, null); + } + + /// Receive a message synchronously from the default destination, but only + /// wait up to a specified time for delivery. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///

This will only work with a default destination specified!

+ ///
+ /// the NMS message selector expression (or null if none). + /// See the NMS specification for a detailed definition of selector expressions. + /// + /// the message received by the consumer, or null if the timeout expires + /// + /// NMSException if there is any problem + public IMessage ReceiveSelected(string messageSelector) + { + CheckDefaultDestination(); + if (DefaultDestination != null) + { + return ReceiveSelected(DefaultDestination, messageSelector); + } + else + { + return ReceiveSelected(DefaultDestinationName, messageSelector); + } + } + + /// Receive a message synchronously from the specified destination, but only + /// wait up to a specified time for delivery. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///
+ /// the destination to receive a message from + /// + /// the NMS message selector expression (or null if none). + /// See the NMS specification for a detailed definition of selector expressions. + /// + /// the message received by the consumer, or null if the timeout expires + /// + /// NMSException if there is any problem + public IMessage ReceiveSelected(IDestination destination, string messageSelector) + { + return Execute(new ReceiveSelectedCallback(this, destination, messageSelector), true) as IMessage; + } + + /// Receive a message synchronously from the specified destination, but only + /// wait up to a specified time for delivery. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///
+ /// the name of the destination to send this message to + /// (to be resolved to an actual destination by a DestinationResolver) + /// + /// the NMS message selector expression (or null if none). + /// See the NMS specification for a detailed definition of selector expressions. + /// + /// the message received by the consumer, or null if the timeout expires + /// + /// NMSException if there is any problem + public IMessage ReceiveSelected(string destinationName, string messageSelector) + { + return Execute(new ReceiveSelectedCallback(this, destinationName, messageSelector), true) as IMessage; + } + + /// + /// Receive a message. + /// + /// The session to operate on. + /// The destination to receive from. + /// The message selector for this consumer (can be null + /// The Message received, or null if none. + protected virtual IMessage DoReceive(ISession session, IDestination destination, string messageSelector) + { + return DoReceive(session, CreateConsumer(session, destination, messageSelector)); + } + + /// + /// Receive a message. + /// + /// The session to operate on. + /// The consumer to receive with. + /// The Message received, or null if none + protected virtual IMessage DoReceive(ISession session, IMessageConsumer consumer) + { + try + { + long timeout = ReceiveTimeout; + NmsResourceHolder resourceHolder = + (NmsResourceHolder) TransactionSynchronizationManager.GetResource(ConnectionFactory); + if (resourceHolder != null && resourceHolder.HasTimeout) + { + timeout = Convert.ToInt64(resourceHolder.TimeToLiveInMilliseconds); + } + + IMessage message = (timeout > 0) + ? consumer.Receive(TimeSpan.FromMilliseconds(timeout)) + : consumer.Receive(); + if (session.Transacted) + { + // Commit necessary - but avoid commit call is Session transaction is externally coordinated. + if (IsSessionLocallyTransacted(session)) { // Transacted session created by this template -> commit. NmsUtils.CommitIfNecessary(session); } } + else if (IsClientAcknowledge(session)) + { + // Manually acknowledge message, if any. + if (message != null) + { + message.Acknowledge(); + } + } + + return message; + } + finally + { + NmsUtils.CloseMessageConsumer(consumer); + } + } + + /// Receive a message synchronously from the default destination, but only + /// wait up to a specified time for delivery. Convert the message into an + /// object with a configured IMessageConverter. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///

This will only work with a default destination specified!

+ ///
+ /// the message produced for the consumer or null if the timeout expires. + /// + /// NMSException if there is any problem + public object ReceiveAndConvert() + { + CheckMessageConverter(); + return DoConvertFromMessage(Receive()); + } + + /// Receive a message synchronously from the specified destination, but only + /// wait up to a specified time for delivery. Convert the message into an + /// object with a configured IMessageConverter. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///
+ /// the destination to receive a message from + /// + /// the message produced for the consumer or null if the timeout expires. + /// + /// NMSException if there is any problem + public object ReceiveAndConvert(IDestination destination) + { + CheckMessageConverter(); + return DoConvertFromMessage(Receive(destination)); + } + + /// Receive a message synchronously from the specified destination, but only + /// wait up to a specified time for delivery. Convert the message into an + /// object with a configured IMessageConverter. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///
+ /// the name of the destination to send this message to + /// (to be resolved to an actual destination by a DestinationResolver) + /// + /// the message produced for the consumer or null if the timeout expires. + /// + /// NMSException if there is any problem + public object ReceiveAndConvert(string destinationName) + { + CheckMessageConverter(); + return DoConvertFromMessage(Receive(destinationName)); + } + + /// Receive a message synchronously from the default destination, but only + /// wait up to a specified time for delivery. Convert the message into an + /// object with a configured IMessageConverter. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///

This will only work with a default destination specified!

+ ///
+ /// the NMS message selector expression (or null if none). + /// See the NMS specification for a detailed definition of selector expressions. + /// + /// the message produced for the consumer or null if the timeout expires. + /// + /// NMSException if there is any problem + public object ReceiveSelectedAndConvert(string messageSelector) + { + CheckMessageConverter(); + return DoConvertFromMessage(ReceiveSelected(messageSelector)); + } + + /// Receive a message synchronously from the specified destination, but only + /// wait up to a specified time for delivery. Convert the message into an + /// object with a configured IMessageConverter. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///
+ /// the destination to receive a message from + /// + /// the NMS message selector expression (or null if none). + /// See the NMS specification for a detailed definition of selector expressions. + /// + /// the message produced for the consumer or null if the timeout expires. + /// + /// NMSException if there is any problem + public object ReceiveSelectedAndConvert(IDestination destination, string messageSelector) + { + CheckMessageConverter(); + return DoConvertFromMessage(ReceiveSelected(destination, messageSelector)); + } + + /// Receive a message synchronously from the specified destination, but only + /// wait up to a specified time for delivery. Convert the message into an + /// object with a configured IMessageConverter. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///
+ /// the name of the destination to send this message to + /// (to be resolved to an actual destination by a DestinationResolver) + /// + /// the NMS message selector expression (or null if none). + /// See the NMS specification for a detailed definition of selector expressions. + /// + /// the message produced for the consumer or null if the timeout expires. + /// + /// NMSException if there is any problem + public object ReceiveSelectedAndConvert(string destinationName, string messageSelector) + { + CheckMessageConverter(); + return DoConvertFromMessage(ReceiveSelected(destinationName, messageSelector)); + } + + #endregion + + #region Supporting Internal Classes + + /// + /// ResourceFactory implementation that delegates to this template's callback methods. + /// + private class NmsTemplateResourceFactory : ConnectionFactoryUtils.ResourceFactory + { + private NmsTemplate enclosingTemplateInstance; + + public NmsTemplateResourceFactory(NmsTemplate enclosingInstance) + { + InitBlock(enclosingInstance); + } + + private void InitBlock(NmsTemplate enclosingInstance) + { + enclosingTemplateInstance = enclosingInstance; + } + + public NmsTemplate EnclosingInstance + { + get { return enclosingTemplateInstance; } + } + + public virtual IConnection GetConnection(NmsResourceHolder holder) + { + return EnclosingInstance.GetConnection(holder); + } + + public virtual ISession GetSession(NmsResourceHolder holder) + { + return EnclosingInstance.GetSession(holder); + } + + public virtual IConnection CreateConnection() + { + return EnclosingInstance.CreateConnection(); + } + + public virtual ISession CreateSession(IConnection con) + { + return EnclosingInstance.CreateSession(con); + } + + public Task CreateConnectionAsync() + { + return Task.FromResult(CreateConnection()); + } + + public Task CreateSessionAsync(IConnection con) + { + return Task.FromResult(CreateSession(con)); + } + + public bool SynchedLocalTransactionAllowed + { + get { return EnclosingInstance.SessionTransacted; } + } + } + + private class ProducerCreatorCallback : ISessionCallback + { + private NmsTemplate jmsTemplate; + private IProducerCallback producerCallback; + private ProducerDelegate producerDelegate; + + public ProducerCreatorCallback(NmsTemplate jmsTemplate, IProducerCallback producerCallback) + { + this.jmsTemplate = jmsTemplate; + this.producerCallback = producerCallback; + } + + public ProducerCreatorCallback(NmsTemplate jmsTemplate, ProducerDelegate producerDelegate) + { + this.jmsTemplate = jmsTemplate; + this.producerDelegate = producerDelegate; + } + + public object DoInNms(ISession session) + { + IMessageProducer producer = jmsTemplate.CreateProducer(session, null); + try + { + if (producerCallback != null) + { + return producerCallback.DoInNms(session, producer); + } + else + { + return producerDelegate(session, producer); + } + } finally { NmsUtils.CloseMessageProducer(producer); } } + } + private class ReceiveCallback : ISessionCallback + { + private NmsTemplate jmsTemplate; + private IDestination destination; + private string destinationName; - /// Actually send the given NMS message. - /// the NMS MessageProducer to send with - /// - /// the NMS Message to send - /// - /// NMSException if thrown by NMS API methods - protected virtual void DoSend(IMessageProducer producer, IMessage message) + public ReceiveCallback(NmsTemplate jmsTemplate, string destinationName) { - if (ExplicitQosEnabled) + this.jmsTemplate = jmsTemplate; + this.destinationName = destinationName; + } + + public ReceiveCallback(NmsTemplate jmsTemplate, IDestination destination) + { + this.jmsTemplate = jmsTemplate; + this.destination = destination; + } + + public object DoInNms(ISession session) + { + if (destination != null) { - producer.Send(message, DeliveryMode, Priority, TimeToLive); + return jmsTemplate.DoReceive(session, destination, null); } else { - producer.Send(message); - } - } - - - #endregion - - #region IMessageOperations Implementation - - /// - /// Execute the action specified by the given action object within - /// a NMS Session. - /// - /// delegate that exposes the session - /// - /// the result object from working with the session - /// - /// - /// Note that the value of PubSubDomain affects the behavior of this method. - /// If PubSubDomain equals true, then a Session is passed to the callback. - /// If false, then a ISession is passed to the callback.b - /// - /// NMSException if there is any problem - public object Execute(SessionDelegate del) - { - return Execute(new ExecuteSessionCallbackUsingDelegate(del)); - } - - /// Execute the action specified by the given action object within - /// a NMS Session. - ///

Note: The value of PubSubDomain affects the behavior of this method. - /// If PubSubDomain equals true, then a Session is passed to the callback. - /// If false, then a Session is passed to the callback.

- ///
- /// callback object that exposes the session - /// - /// the result object from working with the session - /// - /// NMSException if there is any problem - public object Execute(ISessionCallback action) - { - return Execute(action, false); - } - - /// Send a message to a NMS destination. The callback gives access to - /// the NMS session and MessageProducer in order to do more complex - /// send operations. - /// - /// callback object that exposes the session/producer pair - /// - /// the result object from working with the session - /// - /// NMSException if there is any problem - public object Execute(IProducerCallback action) - { - return Execute(new ProducerCreatorCallback(this, action)); - } - - /// Send a message to a NMS destination. The callback gives access to - /// the NMS session and MessageProducer in order to do more complex - /// send operations. - /// - /// delegate that exposes the session/producer pair - /// - /// the result object from working with the session - /// - /// NMSException if there is any problem - public object Execute(ProducerDelegate del) - { - return Execute(new ProducerCreatorCallback(this, del)); - } - - /// Send a message to the default destination. - ///

This will only work with a default destination specified!

- ///
- /// delegate callback to create a message - /// - /// NMSException if there is any problem - public void SendWithDelegate(MessageCreatorDelegate messageCreatorDelegate) - { - CheckDefaultDestination(); - if (DefaultDestination != null) - { - SendWithDelegate(DefaultDestination, messageCreatorDelegate); - } - else - { - SendWithDelegate(DefaultDestinationName, messageCreatorDelegate); - } - } - - /// Send a message to the specified destination. - /// The MessageCreator callback creates the message given a Session. - /// - /// the destination to send this message to - /// - /// delegate callback to create a message - /// - /// NMSException if there is any problem - public void SendWithDelegate(IDestination destination, MessageCreatorDelegate messageCreatorDelegate) - { - Execute(new SendDestinationCallback(this, destination, messageCreatorDelegate), false); - } - - /// Send a message to the specified destination. - /// The MessageCreator callback creates the message given a Session. - /// - /// the name of the destination to send this message to - /// (to be resolved to an actual destination by a DestinationResolver) - /// - /// delegate callback to create a message - /// - /// NMSException if there is any problem - public void SendWithDelegate(string destinationName, MessageCreatorDelegate messageCreatorDelegate) - { - Execute(new SendDestinationCallback(this, destinationName, messageCreatorDelegate), false); - } - - /// Send a message to the default destination. - ///

This will only work with a default destination specified!

- ///
- /// callback to create a message - /// - /// NMSException if there is any problem - public void Send(IMessageCreator messageCreator) - { - CheckDefaultDestination(); - if (DefaultDestination != null) - { - Send(DefaultDestination, messageCreator); - } - else - { - Send(DefaultDestinationName, messageCreator); - } - } - - /// Send a message to the specified destination. - /// The MessageCreator callback creates the message given a Session. - /// - /// the destination to send this message to - /// - /// callback to create a message - /// - /// NMSException if there is any problem - public void Send(IDestination destination, IMessageCreator messageCreator) - { - - Execute(new SendDestinationCallback(this, destination, messageCreator), false); - } - - /// Send a message to the specified destination. - /// The MessageCreator callback creates the message given a Session. - /// - /// the destination to send this message to - /// - /// callback to create a message - /// - /// NMSException if there is any problem - public void Send(string destinationName, IMessageCreator messageCreator) - { - Execute(new SendDestinationCallback(this, destinationName, messageCreator), false); - } - /// Send the given object to the default destination, converting the object - /// to a NMS message with a configured IMessageConverter. - ///

This will only work with a default destination specified!

- ///
- /// the object to convert to a message - /// - /// NMSException if there is any problem - public void ConvertAndSend(object message) - { - CheckDefaultDestination(); - if (DefaultDestination != null) - { - ConvertAndSend(DefaultDestination, message); - } - else - { - ConvertAndSend(DefaultDestinationName, message); - } - } - - /// Send the given object to the specified destination, converting the object - /// to a NMS message with a configured IMessageConverter. - /// - /// the destination to send this message to - /// - /// the object to convert to a message - /// - /// NMSException if there is any problem - public void ConvertAndSend(IDestination destination, object message) - { - CheckMessageConverter(); - Send(destination, new SimpleMessageCreator(this, message)); - } - - /// Send the given object to the specified destination, converting the object - /// to a NMS message with a configured IMessageConverter. - /// - /// the name of the destination to send this message to - /// (to be resolved to an actual destination by a DestinationResolver) - /// - /// the object to convert to a message - /// - /// NMSException if there is any problem - public void ConvertAndSend(string destinationName, object message) - { - Send(destinationName, new SimpleMessageCreator(this, message)); - } - - /// Send the given object to the default destination, converting the object - /// to a NMS message with a configured IMessageConverter. The IMessagePostProcessor - /// callback allows for modification of the message after conversion. - ///

This will only work with a default destination specified!

- ///
- /// the object to convert to a message - /// - /// the callback to modify the message - /// - /// NMSException if there is any problem - public void ConvertAndSend(object message, IMessagePostProcessor postProcessor) - { - CheckDefaultDestination(); - if (DefaultDestination != null) - { - ConvertAndSend(DefaultDestination, message, postProcessor); - } - else - { - ConvertAndSend(DefaultDestinationName, message, postProcessor); - } - } - - /// Send the given object to the specified destination, converting the object - /// to a NMS message with a configured IMessageConverter. The IMessagePostProcessor - /// callback allows for modification of the message after conversion. - /// - /// the destination to send this message to - /// - /// the object to convert to a message - /// - /// the callback to modify the message - /// - /// NMSException if there is any problem - public void ConvertAndSend(IDestination destination, object message, IMessagePostProcessor postProcessor) - { - CheckMessageConverter(); - Send(destination, new ConvertAndSendMessageCreator(this, message, postProcessor)); - - } - - /// Send the given object to the specified destination, converting the object - /// to a NMS message with a configured IMessageConverter. The IMessagePostProcessor - /// callback allows for modification of the message after conversion. - /// - /// the name of the destination to send this message to - /// (to be resolved to an actual destination by a DestinationResolver) - /// - /// the object to convert to a message. - /// - /// the callback to modify the message - /// - /// NMSException if there is any problem - public void ConvertAndSend(string destinationName, object message, IMessagePostProcessor postProcessor) - { - CheckMessageConverter(); - Send(destinationName, new ConvertAndSendMessageCreator(this, message, postProcessor)); - - } - - - /// - /// Send the given object to the default destination, converting the object - /// to a NMS message with a configured IMessageConverter. The IMessagePostProcessor - /// callback allows for modification of the message after conversion. - ///

This will only work with a default destination specified!

- ///
- /// the object to convert to a message - /// the callback to modify the message - /// NMSException if there is any problem - public void ConvertAndSendWithDelegate(object message, MessagePostProcessorDelegate postProcessor) - { - //Execute(new SendDestinationCallback(this, destination, messageCreatorDelegate), false); - CheckDefaultDestination(); - if (DefaultDestination != null) - { - ConvertAndSendWithDelegate(DefaultDestination, message, postProcessor); - } - else - { - ConvertAndSendWithDelegate(DefaultDestinationName, message, postProcessor); - } - } - - /// - /// Send the given object to the specified destination, converting the object - /// to a NMS message with a configured IMessageConverter. The IMessagePostProcessor - /// callback allows for modification of the message after conversion. - /// - /// the destination to send this message to - /// the object to convert to a message - /// the callback to modify the message - /// NMSException if there is any problem - public void ConvertAndSendWithDelegate(IDestination destination, object message, - MessagePostProcessorDelegate postProcessor) - { - CheckMessageConverter(); - Send(destination, new ConvertAndSendMessageCreator(this, message, postProcessor)); - } - - /// - /// Send the given object to the specified destination, converting the object - /// to a NMS message with a configured IMessageConverter. The IMessagePostProcessor - /// callback allows for modification of the message after conversion. - /// - /// the name of the destination to send this message to - /// (to be resolved to an actual destination by a DestinationResolver) - /// the object to convert to a message. - /// the callback to modify the message - /// NMSException if there is any problem - public void ConvertAndSendWithDelegate(string destinationName, object message, - MessagePostProcessorDelegate postProcessor) - { - CheckMessageConverter(); - Send(destinationName, new ConvertAndSendMessageCreator(this, message, postProcessor)); - - } - - /// Receive a message synchronously from the default destination, but only - /// wait up to a specified time for delivery. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///

This will only work with a default destination specified!

- ///
- /// the message received by the consumer, or null if the timeout expires - /// - /// NMSException if there is any problem - public IMessage Receive() - { - CheckDefaultDestination(); - if (DefaultDestination != null) - { - return Receive(DefaultDestination); - } - else - { - return Receive(DefaultDestinationName); - } - } - - /// Receive a message synchronously from the specified destination, but only - /// wait up to a specified time for delivery. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///
- /// the destination to receive a message from - /// - /// the message received by the consumer, or null if the timeout expires - /// - /// NMSException if there is any problem - public IMessage Receive(IDestination destination) - { - return ReceiveSelected(destination, null); - } - - - /// Receive a message synchronously from the specified destination, but only - /// wait up to a specified time for delivery. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///
- /// the name of the destination to send this message to - /// (to be resolved to an actual destination by a DestinationResolver) - /// - /// the message received by the consumer, or null if the timeout expires - /// - /// NMSException if there is any problem - public IMessage Receive(string destinationName) - { - return ReceiveSelected(destinationName, null); - } - - /// Receive a message synchronously from the default destination, but only - /// wait up to a specified time for delivery. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///

This will only work with a default destination specified!

- ///
- /// the NMS message selector expression (or null if none). - /// See the NMS specification for a detailed definition of selector expressions. - /// - /// the message received by the consumer, or null if the timeout expires - /// - /// NMSException if there is any problem - public IMessage ReceiveSelected(string messageSelector) - { - CheckDefaultDestination(); - if (DefaultDestination!= null) - { - return ReceiveSelected(DefaultDestination, messageSelector); - } - else - { - return ReceiveSelected(DefaultDestinationName, messageSelector); - } - } - - /// Receive a message synchronously from the specified destination, but only - /// wait up to a specified time for delivery. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///
- /// the destination to receive a message from - /// - /// the NMS message selector expression (or null if none). - /// See the NMS specification for a detailed definition of selector expressions. - /// - /// the message received by the consumer, or null if the timeout expires - /// - /// NMSException if there is any problem - public IMessage ReceiveSelected(IDestination destination, string messageSelector) - { - return Execute(new ReceiveSelectedCallback(this, destination, messageSelector), true) as IMessage; - } - - /// Receive a message synchronously from the specified destination, but only - /// wait up to a specified time for delivery. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///
- /// the name of the destination to send this message to - /// (to be resolved to an actual destination by a DestinationResolver) - /// - /// the NMS message selector expression (or null if none). - /// See the NMS specification for a detailed definition of selector expressions. - /// - /// the message received by the consumer, or null if the timeout expires - /// - /// NMSException if there is any problem - public IMessage ReceiveSelected(string destinationName, string messageSelector) - { - return Execute(new ReceiveSelectedCallback(this, destinationName, messageSelector), true) as IMessage; - } - - /// - /// Receive a message. - /// - /// The session to operate on. - /// The destination to receive from. - /// The message selector for this consumer (can be null - /// The Message received, or null if none. - protected virtual IMessage DoReceive(ISession session, IDestination destination, string messageSelector) - { - return DoReceive(session, CreateConsumer(session, destination, messageSelector)); - } - - /// - /// Receive a message. - /// - /// The session to operate on. - /// The consumer to receive with. - /// The Message received, or null if none - protected virtual IMessage DoReceive(ISession session, IMessageConsumer consumer) - { - try - { - long timeout = ReceiveTimeout; - NmsResourceHolder resourceHolder = - (NmsResourceHolder)TransactionSynchronizationManager.GetResource(ConnectionFactory); - if (resourceHolder != null && resourceHolder.HasTimeout) - { - timeout = Convert.ToInt64(resourceHolder.TimeToLiveInMilliseconds); - } - IMessage message = (timeout > 0) - ? consumer.Receive(TimeSpan.FromMilliseconds(timeout)) - : consumer.Receive(); - if (session.Transacted) - { - // Commit necessary - but avoid commit call is Session transaction is externally coordinated. - if (IsSessionLocallyTransacted(session)) - { - // Transacted session created by this template -> commit. - NmsUtils.CommitIfNecessary(session); - } - } - else if (IsClientAcknowledge(session)) - { - // Manually acknowledge message, if any. - if (message != null) - { - message.Acknowledge(); - } - } - return message; - } - finally - { - NmsUtils.CloseMessageConsumer(consumer); - } - } - - - /// Receive a message synchronously from the default destination, but only - /// wait up to a specified time for delivery. Convert the message into an - /// object with a configured IMessageConverter. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///

This will only work with a default destination specified!

- ///
- /// the message produced for the consumer or null if the timeout expires. - /// - /// NMSException if there is any problem - public object ReceiveAndConvert() - { - CheckMessageConverter(); - return DoConvertFromMessage(Receive()); - } - - /// Receive a message synchronously from the specified destination, but only - /// wait up to a specified time for delivery. Convert the message into an - /// object with a configured IMessageConverter. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///
- /// the destination to receive a message from - /// - /// the message produced for the consumer or null if the timeout expires. - /// - /// NMSException if there is any problem - public object ReceiveAndConvert(IDestination destination) - { - CheckMessageConverter(); - return DoConvertFromMessage(Receive(destination)); - } - - - /// Receive a message synchronously from the specified destination, but only - /// wait up to a specified time for delivery. Convert the message into an - /// object with a configured IMessageConverter. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///
- /// the name of the destination to send this message to - /// (to be resolved to an actual destination by a DestinationResolver) - /// - /// the message produced for the consumer or null if the timeout expires. - /// - /// NMSException if there is any problem - public object ReceiveAndConvert(string destinationName) - { - CheckMessageConverter(); - return DoConvertFromMessage(Receive(destinationName)); - } - - /// Receive a message synchronously from the default destination, but only - /// wait up to a specified time for delivery. Convert the message into an - /// object with a configured IMessageConverter. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///

This will only work with a default destination specified!

- ///
- /// the NMS message selector expression (or null if none). - /// See the NMS specification for a detailed definition of selector expressions. - /// - /// the message produced for the consumer or null if the timeout expires. - /// - /// NMSException if there is any problem - public object ReceiveSelectedAndConvert(string messageSelector) - { - CheckMessageConverter(); - return DoConvertFromMessage(ReceiveSelected(messageSelector)); - } - - /// Receive a message synchronously from the specified destination, but only - /// wait up to a specified time for delivery. Convert the message into an - /// object with a configured IMessageConverter. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///
- /// the destination to receive a message from - /// - /// the NMS message selector expression (or null if none). - /// See the NMS specification for a detailed definition of selector expressions. - /// - /// the message produced for the consumer or null if the timeout expires. - /// - /// NMSException if there is any problem - public object ReceiveSelectedAndConvert(IDestination destination, string messageSelector) - { - CheckMessageConverter(); - return DoConvertFromMessage(ReceiveSelected(destination, messageSelector)); - } - - /// Receive a message synchronously from the specified destination, but only - /// wait up to a specified time for delivery. Convert the message into an - /// object with a configured IMessageConverter. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///
- /// the name of the destination to send this message to - /// (to be resolved to an actual destination by a DestinationResolver) - /// - /// the NMS message selector expression (or null if none). - /// See the NMS specification for a detailed definition of selector expressions. - /// - /// the message produced for the consumer or null if the timeout expires. - /// - /// NMSException if there is any problem - public object ReceiveSelectedAndConvert(string destinationName, string messageSelector) - { - CheckMessageConverter(); - return DoConvertFromMessage(ReceiveSelected(destinationName, messageSelector)); - } - - #endregion - - #region Supporting Internal Classes - - /// - /// ResourceFactory implementation that delegates to this template's callback methods. - /// - private class NmsTemplateResourceFactory : ConnectionFactoryUtils.ResourceFactory - { - private NmsTemplate enclosingTemplateInstance; - - public NmsTemplateResourceFactory(NmsTemplate enclosingInstance) - { - InitBlock(enclosingInstance); - } - - private void InitBlock(NmsTemplate enclosingInstance) - { - enclosingTemplateInstance = enclosingInstance; - } - - public NmsTemplate EnclosingInstance - { - get { return enclosingTemplateInstance; } - } - - public virtual IConnection GetConnection(NmsResourceHolder holder) - { - return EnclosingInstance.GetConnection(holder); - } - - public virtual ISession GetSession(NmsResourceHolder holder) - { - return EnclosingInstance.GetSession(holder); - } - - public virtual IConnection CreateConnection() - { - return EnclosingInstance.CreateConnection(); - } - - public virtual ISession CreateSession(IConnection con) - { - return EnclosingInstance.CreateSession(con); - } - - public Task CreateConnectionAsync() - { - return Task.FromResult(CreateConnection()); - } - - public Task CreateSessionAsync(IConnection con) - { - return Task.FromResult(CreateSession(con)); - } - - public bool SynchedLocalTransactionAllowed - { - get { return EnclosingInstance.SessionTransacted; } - } - } - - private class ProducerCreatorCallback : ISessionCallback - { - private NmsTemplate jmsTemplate; - private IProducerCallback producerCallback; - private ProducerDelegate producerDelegate; - - public ProducerCreatorCallback(NmsTemplate jmsTemplate, IProducerCallback producerCallback) - { - this.jmsTemplate = jmsTemplate; - this.producerCallback = producerCallback; - } - - public ProducerCreatorCallback(NmsTemplate jmsTemplate, ProducerDelegate producerDelegate) - { - this.jmsTemplate = jmsTemplate; - this.producerDelegate = producerDelegate; - } - - public object DoInNms(ISession session) - { - IMessageProducer producer = jmsTemplate.CreateProducer(session, null); - try - { - if (producerCallback != null) - { - return producerCallback.DoInNms(session, producer); - } - else - { - return producerDelegate(session, producer); - } - } - finally - { - NmsUtils.CloseMessageProducer(producer); - } - - } - } - - private class ReceiveCallback : ISessionCallback - { - private NmsTemplate jmsTemplate; - private IDestination destination; - private string destinationName; - - - public ReceiveCallback(NmsTemplate jmsTemplate, string destinationName) - { - this.jmsTemplate = jmsTemplate; - this.destinationName = destinationName; - } - - public ReceiveCallback(NmsTemplate jmsTemplate, IDestination destination) - { - this.jmsTemplate = jmsTemplate; - this.destination = destination; - } - - public object DoInNms(ISession session) - { - if (destination != null) - { - return jmsTemplate.DoReceive(session, destination, null); - } - else - { - return jmsTemplate.DoReceive(session, - jmsTemplate.ResolveDestinationName(session, destinationName), - null); - } - - } - } - - private class ConvertAndSendMessageCreator : IMessageCreator - { - private NmsTemplate jmsTemplate; - private object objectToConvert; - private IMessagePostProcessor messagePostProcessor; - private MessagePostProcessorDelegate messagePostProcessorDelegate; - - public ConvertAndSendMessageCreator(NmsTemplate jmsTemplate, object message, IMessagePostProcessor messagePostProcessor) - { - this.jmsTemplate = jmsTemplate; - objectToConvert = message; - this.messagePostProcessor = messagePostProcessor; - } - - public ConvertAndSendMessageCreator(NmsTemplate jmsTemplate, object message, MessagePostProcessorDelegate messagePostProcessorDelegate) - { - this.jmsTemplate = jmsTemplate; - objectToConvert = message; - this.messagePostProcessorDelegate = messagePostProcessorDelegate; - } - - public IMessage CreateMessage(ISession session) - { - IMessage msg = jmsTemplate.MessageConverter.ToMessage(objectToConvert, session); - if (messagePostProcessor != null) - { - return messagePostProcessor.PostProcessMessage(msg); - } else - { - return messagePostProcessorDelegate(msg); - } - } - - } - - private class ReceiveSelectedCallback : ISessionCallback - { - private NmsTemplate jmsTemplate; - private string messageSelector; - private string destinationName; - private IDestination destination; - - public ReceiveSelectedCallback(NmsTemplate jmsTemplate, - IDestination destination, - string messageSelector) - { - this.jmsTemplate = jmsTemplate; - this.destination = destination; - this.messageSelector = messageSelector; - } - public ReceiveSelectedCallback(NmsTemplate jmsTemplate, - string destinationName, - string messageSelector) - { - this.jmsTemplate = jmsTemplate; - this.destinationName = destinationName; - this.messageSelector = messageSelector; - } - - public object DoInNms(ISession session) - { - if (destination != null) - { - return jmsTemplate.DoReceive(session, destination, messageSelector); - } - else - { - return jmsTemplate.DoReceive(session, - jmsTemplate.ResolveDestinationName(session, destinationName), - messageSelector); - } - - } - - } - - #endregion - - private class ExecuteSessionCallbackUsingDelegate : ISessionCallback - { - private readonly SessionDelegate del; - public ExecuteSessionCallbackUsingDelegate(SessionDelegate del) - { - this.del = del; - } - - public object DoInNms(ISession session) - { - return del(session); + return jmsTemplate.DoReceive(session, + jmsTemplate.ResolveDestinationName(session, destinationName), + null); } } } - - - internal class SimpleMessageCreator : IMessageCreator + private class ConvertAndSendMessageCreator : IMessageCreator { private NmsTemplate jmsTemplate; private object objectToConvert; - - public SimpleMessageCreator(NmsTemplate jmsTemplate, object objectToConvert) + private IMessagePostProcessor messagePostProcessor; + private MessagePostProcessorDelegate messagePostProcessorDelegate; + + public ConvertAndSendMessageCreator(NmsTemplate jmsTemplate, object message, IMessagePostProcessor messagePostProcessor) { this.jmsTemplate = jmsTemplate; - this.objectToConvert = objectToConvert; + objectToConvert = message; + this.messagePostProcessor = messagePostProcessor; + } + + public ConvertAndSendMessageCreator(NmsTemplate jmsTemplate, object message, MessagePostProcessorDelegate messagePostProcessorDelegate) + { + this.jmsTemplate = jmsTemplate; + objectToConvert = message; + this.messagePostProcessorDelegate = messagePostProcessorDelegate; } public IMessage CreateMessage(ISession session) { - return jmsTemplate.MessageConverter.ToMessage(objectToConvert, session); - } - - - } - - - - internal class SendDestinationCallback : ISessionCallback - { - private string destinationName; - private IDestination destination; - private NmsTemplate jmsTemplate; - private IMessageCreator messageCreator; - private MessageCreatorDelegate messageCreatorDelegate; - - public SendDestinationCallback(NmsTemplate jmsTemplate, string destinationName, IMessageCreator messageCreator) - { - this.jmsTemplate = jmsTemplate; - this.destinationName = destinationName; - this.messageCreator = messageCreator; - } - - public SendDestinationCallback(NmsTemplate jmsTemplate, IDestination destination, IMessageCreator messageCreator) - { - this.jmsTemplate = jmsTemplate; - this.destination = destination; - this.messageCreator = messageCreator; - } - - public SendDestinationCallback(NmsTemplate jmsTemplate, string destinationName, MessageCreatorDelegate messageCreatorDelegate) - { - this.jmsTemplate = jmsTemplate; - this.destinationName = destinationName; - this.messageCreatorDelegate = messageCreatorDelegate; - } - - public SendDestinationCallback(NmsTemplate jmsTemplate, IDestination destination, MessageCreatorDelegate messageCreatorDelegate) - { - this.jmsTemplate = jmsTemplate; - this.destination = destination; - this.messageCreatorDelegate = messageCreatorDelegate; - } - - - public object DoInNms(ISession session) - { - if (destination == null) + IMessage msg = jmsTemplate.MessageConverter.ToMessage(objectToConvert, session); + if (messagePostProcessor != null) { - destination = jmsTemplate.ResolveDestinationName(session, destinationName); - } - if (messageCreator != null) - { - jmsTemplate.DoSend(session, destination, messageCreator); + return messagePostProcessor.PostProcessMessage(msg); } else { - jmsTemplate.DoSend(session, destination, messageCreatorDelegate); + return messagePostProcessorDelegate(msg); } - return null; + } + } + + private class ReceiveSelectedCallback : ISessionCallback + { + private NmsTemplate jmsTemplate; + private string messageSelector; + private string destinationName; + private IDestination destination; + + public ReceiveSelectedCallback(NmsTemplate jmsTemplate, + IDestination destination, + string messageSelector) + { + this.jmsTemplate = jmsTemplate; + this.destination = destination; + this.messageSelector = messageSelector; + } + + public ReceiveSelectedCallback(NmsTemplate jmsTemplate, + string destinationName, + string messageSelector) + { + this.jmsTemplate = jmsTemplate; + this.destinationName = destinationName; + this.messageSelector = messageSelector; + } + + public object DoInNms(ISession session) + { + if (destination != null) + { + return jmsTemplate.DoReceive(session, destination, messageSelector); + } + else + { + return jmsTemplate.DoReceive(session, + jmsTemplate.ResolveDestinationName(session, destinationName), + messageSelector); + } + } + } + + #endregion + + private class ExecuteSessionCallbackUsingDelegate : ISessionCallback + { + private readonly SessionDelegate del; + + public ExecuteSessionCallbackUsingDelegate(SessionDelegate del) + { + this.del = del; + } + + public object DoInNms(ISession session) + { + return del(session); } } } + +internal class SimpleMessageCreator : IMessageCreator +{ + private NmsTemplate jmsTemplate; + private object objectToConvert; + + public SimpleMessageCreator(NmsTemplate jmsTemplate, object objectToConvert) + { + this.jmsTemplate = jmsTemplate; + this.objectToConvert = objectToConvert; + } + + public IMessage CreateMessage(ISession session) + { + return jmsTemplate.MessageConverter.ToMessage(objectToConvert, session); + } +} + +internal class SendDestinationCallback : ISessionCallback +{ + private string destinationName; + private IDestination destination; + private NmsTemplate jmsTemplate; + private IMessageCreator messageCreator; + private MessageCreatorDelegate messageCreatorDelegate; + + public SendDestinationCallback(NmsTemplate jmsTemplate, string destinationName, IMessageCreator messageCreator) + { + this.jmsTemplate = jmsTemplate; + this.destinationName = destinationName; + this.messageCreator = messageCreator; + } + + public SendDestinationCallback(NmsTemplate jmsTemplate, IDestination destination, IMessageCreator messageCreator) + { + this.jmsTemplate = jmsTemplate; + this.destination = destination; + this.messageCreator = messageCreator; + } + + public SendDestinationCallback(NmsTemplate jmsTemplate, string destinationName, MessageCreatorDelegate messageCreatorDelegate) + { + this.jmsTemplate = jmsTemplate; + this.destinationName = destinationName; + this.messageCreatorDelegate = messageCreatorDelegate; + } + + public SendDestinationCallback(NmsTemplate jmsTemplate, IDestination destination, MessageCreatorDelegate messageCreatorDelegate) + { + this.jmsTemplate = jmsTemplate; + this.destination = destination; + this.messageCreatorDelegate = messageCreatorDelegate; + } + + public object DoInNms(ISession session) + { + if (destination == null) + { + destination = jmsTemplate.ResolveDestinationName(session, destinationName); + } + + if (messageCreator != null) + { + jmsTemplate.DoSend(session, destination, messageCreator); + } + else + { + jmsTemplate.DoSend(session, destination, messageCreatorDelegate); + } + + return null; + } +} diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/NmsTemplateAsync.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/NmsTemplateAsync.cs index 9e4eb3ef..f7a1e4be 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/NmsTemplateAsync.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/NmsTemplateAsync.cs @@ -1,4 +1,5 @@ #region License + // /* // * Copyright 2022 the original author or authors. // * @@ -14,6 +15,7 @@ // * See the License for the specific language governing permissions and // * limitations under the License. // */ + #endregion using Spring.Messaging.Nms.Connections; @@ -25,1481 +27,1467 @@ using Spring.Util; using Apache.NMS; using Microsoft.Extensions.Logging; -namespace Spring.Messaging.Nms.Core +namespace Spring.Messaging.Nms.Core; + +/// +/// Async version of NmsTemplate +/// +/// +public class NmsTemplateAsync : NmsDestinationAccessorAsync, INmsOperationsAsync { + #region Logging + + private readonly ILogger logger = LogManager.GetLogger(); + + #endregion + + #region Fields + /// - /// Async version of NmsTemplate + /// Timeout value indicating that a receive operation should + /// check if a message is immediately available without blocking. /// - /// - public class NmsTemplateAsync : NmsDestinationAccessorAsync, INmsOperationsAsync + public static readonly long RECEIVE_TIMEOUT_NO_WAIT = -1; + + /// + /// Timeout value indicating a blocking receive without timeout. + /// + public static readonly long RECEIVE_TIMEOUT_INDEFINITE_WAIT = 0; + + private readonly NmsTemplateResourceFactoryAsync transactionalResourceFactory; + + private object defaultDestination; + + private IMessageConverter messageConverter; + + private bool messageIdEnabled = true; + + private bool messageTimestampEnabled = true; + + private bool pubSubNoLocal = false; + + private long receiveTimeout = RECEIVE_TIMEOUT_NO_WAIT; + + private bool explicitQosEnabled = false; + + private MsgPriority priority = NMSConstants.defaultPriority; + + private TimeSpan timeToLive; + + private MsgDeliveryMode deliveryMode = NMSConstants.defaultDeliveryMode; + + #endregion + + #region Constructor (s) + + /// Create a new NmsTemplate. + /// + /// Note: The ConnectionFactory has to be set before using the instance. + /// This constructor can be used to prepare a NmsTemplate via an ObjectFactory, + /// typically setting the ConnectionFactory. + /// + public NmsTemplateAsync() { - #region Logging + transactionalResourceFactory = new NmsTemplateResourceFactoryAsync(this); + InitDefaultStrategies(); + } - private readonly ILogger logger = LogManager.GetLogger(); + /// Create a new NmsTemplate, given a ConnectionFactory. + /// the ConnectionFactory to obtain IConnections from + /// + public NmsTemplateAsync(IConnectionFactory connectionFactory) + : this() + { + ConnectionFactory = connectionFactory; + AfterPropertiesSet(); + } + #endregion - #endregion + #region Methods - #region Fields + /// Initialize the default implementations for the template's strategies: + /// DynamicDestinationResolver and SimpleMessageConverter. + /// + protected virtual void InitDefaultStrategies() + { + MessageConverter = new SimpleMessageConverter(); + } - /// - /// Timeout value indicating that a receive operation should - /// check if a message is immediately available without blocking. - /// - public static readonly long RECEIVE_TIMEOUT_NO_WAIT = -1; - - /// - /// Timeout value indicating a blocking receive without timeout. - /// - public static readonly long RECEIVE_TIMEOUT_INDEFINITE_WAIT = 0; - - private readonly NmsTemplateResourceFactoryAsync transactionalResourceFactory; - - private object defaultDestination; - - private IMessageConverter messageConverter; - - - private bool messageIdEnabled = true; - - private bool messageTimestampEnabled = true; - - private bool pubSubNoLocal = false; - - private long receiveTimeout = RECEIVE_TIMEOUT_NO_WAIT; - - private bool explicitQosEnabled = false; - - private MsgPriority priority = NMSConstants.defaultPriority; - - private TimeSpan timeToLive; - - private MsgDeliveryMode deliveryMode = NMSConstants.defaultDeliveryMode; - - #endregion - - #region Constructor (s) - - /// Create a new NmsTemplate. - /// - /// Note: The ConnectionFactory has to be set before using the instance. - /// This constructor can be used to prepare a NmsTemplate via an ObjectFactory, - /// typically setting the ConnectionFactory. - /// - public NmsTemplateAsync() + private void CheckDefaultDestination() + { + if (defaultDestination == null) { - transactionalResourceFactory = new NmsTemplateResourceFactoryAsync(this); - InitDefaultStrategies(); + throw new SystemException( + "No defaultDestination or defaultDestinationName specified. Check configuration of NmsTemplate."); } + } - - /// Create a new NmsTemplate, given a ConnectionFactory. - /// the ConnectionFactory to obtain IConnections from - /// - public NmsTemplateAsync(IConnectionFactory connectionFactory) - : this() + private void CheckMessageConverter() + { + if (MessageConverter == null) { - ConnectionFactory = connectionFactory; - AfterPropertiesSet(); + throw new SystemException("No messageConverter registered. Check configuration of NmsTemplate."); } + } - #endregion + /// Execute the action specified by the given action object within a + /// NMS Session. + /// + /// Generalized version of execute(ISessionCallback), + /// allowing the NMS Connection to be started on the fly. + ///

Use execute(ISessionCallback) for the general case. + /// Starting the NMS Connection is just necessary for receiving messages, + /// which is preferably achieved through the receive methods.

+ ///
+ /// callback object that exposes the session + /// + /// Start the connection before performing callback action. + /// + /// the result object from working with the session + /// + /// NMSException if there is any problem + public virtual async Task Execute(ISessionCallbackAsync action, bool startConnection) + { + AssertUtils.ArgumentNotNull(action, "Callback object must not be null"); - #region Methods - - /// Initialize the default implementations for the template's strategies: - /// DynamicDestinationResolver and SimpleMessageConverter. - /// - protected virtual void InitDefaultStrategies() + IConnection conToClose = null; + ISession sessionToClose = null; + try { - MessageConverter = new SimpleMessageConverter(); - } - - private void CheckDefaultDestination() - { - if (defaultDestination == null) + ISession sessionToUse = + await ConnectionFactoryUtils.DoGetTransactionalSession(ConnectionFactory, transactionalResourceFactory, + startConnection).Awaiter(); + if (sessionToUse == null) { - throw new SystemException( - "No defaultDestination or defaultDestinationName specified. Check configuration of NmsTemplate."); - } - } - - - private void CheckMessageConverter() - { - if (MessageConverter == null) - { - throw new SystemException("No messageConverter registered. Check configuration of NmsTemplate."); - } - } - - /// Execute the action specified by the given action object within a - /// NMS Session. - /// - /// Generalized version of execute(ISessionCallback), - /// allowing the NMS Connection to be started on the fly. - ///

Use execute(ISessionCallback) for the general case. - /// Starting the NMS Connection is just necessary for receiving messages, - /// which is preferably achieved through the receive methods.

- ///
- /// callback object that exposes the session - /// - /// Start the connection before performing callback action. - /// - /// the result object from working with the session - /// - /// NMSException if there is any problem - public virtual async Task Execute(ISessionCallbackAsync action, bool startConnection) - { - AssertUtils.ArgumentNotNull(action, "Callback object must not be null"); - - IConnection conToClose = null; - ISession sessionToClose = null; - try - { - ISession sessionToUse = - await ConnectionFactoryUtils.DoGetTransactionalSession(ConnectionFactory, transactionalResourceFactory, - startConnection).Awaiter(); - if (sessionToUse == null) + conToClose = await CreateConnection().Awaiter(); + sessionToClose = await CreateSession(conToClose).Awaiter(); + if (startConnection) { - conToClose = await CreateConnection().Awaiter(); - sessionToClose = await CreateSession(conToClose).Awaiter(); - if (startConnection) - { - await conToClose.StartAsync().Awaiter(); - } - sessionToUse = sessionToClose; + await conToClose.StartAsync().Awaiter(); } - if (logger.IsEnabled(LogLevel.Debug)) - { - logger.LogDebug("Executing callback on NMS ISession [" + sessionToUse + "]"); - } - return await action.DoInNms(sessionToUse).Awaiter(); + + sessionToUse = sessionToClose; } - finally + + if (logger.IsEnabled(LogLevel.Debug)) { - await NmsUtilsAsync.CloseSession(sessionToClose).Awaiter(); - await ConnectionFactoryUtils.ReleaseConnectionAsync(conToClose, ConnectionFactory, startConnection).Awaiter(); + logger.LogDebug("Executing callback on NMS ISession [" + sessionToUse + "]"); } + + return await action.DoInNms(sessionToUse).Awaiter(); } - - #endregion - - #region Properties - - /// - /// Gets or sets the default destination to be used on send/receive operations that do not - /// have a destination parameter. - /// - /// Alternatively, specify a "defaultDestinationName", to be - /// dynamically resolved via the DestinationResolver. - /// The default destination. - virtual public IDestination DefaultDestination + finally { - get { return (defaultDestination as IDestination); } - - set { defaultDestination = value; } + await NmsUtilsAsync.CloseSession(sessionToClose).Awaiter(); + await ConnectionFactoryUtils.ReleaseConnectionAsync(conToClose, ConnectionFactory, startConnection).Awaiter(); } + } + #endregion - /// - /// Gets or sets the name of the default destination name - /// to be used on send/receive operations that - /// do not have a destination parameter. - /// - /// - /// Alternatively, specify a NMS IDestination object as "DefaultDestination" - /// - /// The name of the default destination. - virtual public string DefaultDestinationName + #region Properties + + /// + /// Gets or sets the default destination to be used on send/receive operations that do not + /// have a destination parameter. + /// + /// Alternatively, specify a "defaultDestinationName", to be + /// dynamically resolved via the DestinationResolver. + /// The default destination. + virtual public IDestination DefaultDestination + { + get { return (defaultDestination as IDestination); } + + set { defaultDestination = value; } + } + + /// + /// Gets or sets the name of the default destination name + /// to be used on send/receive operations that + /// do not have a destination parameter. + /// + /// + /// Alternatively, specify a NMS IDestination object as "DefaultDestination" + /// + /// The name of the default destination. + virtual public string DefaultDestinationName + { + get { return (defaultDestination as string); } + + set { defaultDestination = value; } + } + + /// + /// Gets or sets the message converter for this template. + /// + /// + /// Used to resolve + /// Object parameters to convertAndSend methods and Object results + /// from receiveAndConvert methods. + ///

The default converter is a SimpleMessageConverter, which is able + /// to handle IBytesMessages, ITextMessages and IObjectMessages.

+ ///
+ /// The message converter. + virtual public IMessageConverter MessageConverter + { + get { return messageConverter; } + + set { messageConverter = value; } + } + + /// + /// Gets or sets a value indicating whether Message Ids are enabled. + /// + /// true if message id enabled; otherwise, false. + virtual public bool MessageIdEnabled + { + get { return messageIdEnabled; } + + set { messageIdEnabled = value; } + } + + /// + /// Gets or sets a value indicating whether message timestamps are enabled. + /// + /// + /// true if [message timestamp enabled]; otherwise, false. + /// + virtual public bool MessageTimestampEnabled + { + get { return messageTimestampEnabled; } + + set { messageTimestampEnabled = value; } + } + + /// + /// Gets or sets a value indicating whether to inhibit the delivery of messages published by its own connection. + /// + /// + /// true if inhibit the delivery of messages published by its own connection; otherwise, false. + virtual public bool PubSubNoLocal + { + get { return pubSubNoLocal; } + + set { pubSubNoLocal = value; } + } + + /// + /// Gets or sets the receive timeout to use for recieve calls (in milliseconds) + /// + /// The default is -1, which means no timeout. + /// The receive timeout. + virtual public long ReceiveTimeout + { + get { return receiveTimeout; } + + set { receiveTimeout = value; } + } + + /// + /// Gets or sets a value indicating whether to use explicit Quality of Service values. + /// + /// If "true", then the values of deliveryMode, priority, and timeToLive + /// will be used when sending a message. Otherwise, the default values, + /// that may be set administratively, will be used + /// true if use explicit QoS values; otherwise, false. + virtual public bool ExplicitQosEnabled + { + get { return explicitQosEnabled; } + + set { explicitQosEnabled = value; } + } + + /// + /// Sets a value indicating whether message delivery should be persistent or non-persistent + /// + /// + /// This will set the delivery to persistent or non-persistent + ///

Default it "true" aka delivery mode "PERSISTENT".

+ ///
+ /// true if [delivery persistent]; otherwise, false. + virtual public bool Persistent + { + get { return (deliveryMode == MsgDeliveryMode.Persistent); } + + set { - get { return (defaultDestination as string); } - - set { defaultDestination = value; } - } - - /// - /// Gets or sets the message converter for this template. - /// - /// - /// Used to resolve - /// Object parameters to convertAndSend methods and Object results - /// from receiveAndConvert methods. - ///

The default converter is a SimpleMessageConverter, which is able - /// to handle IBytesMessages, ITextMessages and IObjectMessages.

- ///
- /// The message converter. - virtual public IMessageConverter MessageConverter - { - get { return messageConverter; } - - set { messageConverter = value; } - } - - /// - /// Gets or sets a value indicating whether Message Ids are enabled. - /// - /// true if message id enabled; otherwise, false. - virtual public bool MessageIdEnabled - { - get { return messageIdEnabled; } - - set { messageIdEnabled = value; } - } - - /// - /// Gets or sets a value indicating whether message timestamps are enabled. - /// - /// - /// true if [message timestamp enabled]; otherwise, false. - /// - virtual public bool MessageTimestampEnabled - { - get { return messageTimestampEnabled; } - - set { messageTimestampEnabled = value; } - } - - - /// - /// Gets or sets a value indicating whether to inhibit the delivery of messages published by its own connection. - /// - /// - /// true if inhibit the delivery of messages published by its own connection; otherwise, false. - virtual public bool PubSubNoLocal - { - get { return pubSubNoLocal; } - - set { pubSubNoLocal = value; } - } - - /// - /// Gets or sets the receive timeout to use for recieve calls (in milliseconds) - /// - /// The default is -1, which means no timeout. - /// The receive timeout. - virtual public long ReceiveTimeout - { - get { return receiveTimeout; } - - set { receiveTimeout = value; } - } - - /// - /// Gets or sets a value indicating whether to use explicit Quality of Service values. - /// - /// If "true", then the values of deliveryMode, priority, and timeToLive - /// will be used when sending a message. Otherwise, the default values, - /// that may be set administratively, will be used - /// true if use explicit QoS values; otherwise, false. - virtual public bool ExplicitQosEnabled - { - get { return explicitQosEnabled; } - - set { explicitQosEnabled = value; } - } - - /// - /// Sets a value indicating whether message delivery should be persistent or non-persistent - /// - /// - /// This will set the delivery to persistent or non-persistent - ///

Default it "true" aka delivery mode "PERSISTENT".

- ///
- /// true if [delivery persistent]; otherwise, false. - virtual public bool Persistent - { - get { return (deliveryMode == MsgDeliveryMode.Persistent); } - - set + if (value) { - if (value) { - deliveryMode = MsgDeliveryMode.Persistent; - } else { - deliveryMode = MsgDeliveryMode.NonPersistent; - } - } - } - - /// - /// Gets or sets a value indicating what DeliveryMode this - /// should use, for example a persistent QOS - /// - /// - virtual public MsgDeliveryMode DeliveryMode - { - get { return deliveryMode; } - set { deliveryMode = value; } - } - - /// - /// Gets or sets the priority when sending. - /// - /// Since a default value may be defined administratively, - /// this is only used when "isExplicitQosEnabled" equals "true". - /// The priority. - virtual public MsgPriority Priority - { - get { return priority; } - - set { priority = value; } - } - - /// - /// Gets or sets the time to live when sending - /// - /// Since a default value may be defined administratively, - /// this is only used when "isExplicitQosEnabled" equals "true". - /// The time to live. - virtual public TimeSpan TimeToLive - { - get { return timeToLive; } - - set { timeToLive = value; } - } - - - #endregion - - /// - /// Extract the content from the given JMS message. - /// - /// The Message to convert (can be null). - /// The content of the message, or null if none - protected virtual object DoConvertFromMessage(IMessage message) - { - if (message != null) - { - return MessageConverter.FromMessage(message); - } - return null; - } - - #region NMS Factory Methods - - /// Fetch an appropriate Connection from the given MessageResourceHolder. - /// - /// the MessageResourceHolder - /// - /// an appropriate IConnection fetched from the holder, - /// or null if none found - /// - protected virtual IConnection GetConnection(NmsResourceHolder holder) - { - return holder.GetConnection(); // TODO - } - - /// Fetch an appropriate Session from the given MessageResourceHolder. - /// - /// the MessageResourceHolder - /// - /// an appropriate ISession fetched from the holder, - /// or null if none found - /// - protected virtual ISession GetSession(NmsResourceHolder holder) - { - return holder.GetSession(); // TODO - } - - /// Create a NMS MessageProducer for the given Session and Destination, - /// configuring it to disable message ids and/or timestamps (if necessary). - ///

Delegates to doCreateProducer for creation of the raw - /// NMS MessageProducer

- ///
- /// the NMS Session to create a MessageProducer for - /// - /// the NMS Destination to create a MessageProducer for - /// - /// the new NMS MessageProducer - /// - /// NMSException if thrown by NMS API methods - /// - /// - /// - /// - /// - /// - protected virtual async Task CreateProducer(ISession session, IDestination destination) - { - IMessageProducer producer = await DoCreateProducer(session, destination).Awaiter(); - if (!MessageIdEnabled) - { - producer.DisableMessageID = true; - } - if (!MessageTimestampEnabled) - { - producer.DisableMessageTimestamp = true; - } - return producer; - } - - - /// - /// Determines whether the given Session is locally transacted, that is, whether - /// its transaction is managed by this template class's Session handling - /// and not by an external transaction coordinator. - /// - /// - /// The Session's own transacted flag will already have been checked - /// before. This method is about finding out whether the Session's transaction - /// is local or externally coordinated. - /// - /// The session to check. - /// - /// true if the session is locally transacted; otherwise, false. - /// - protected virtual bool IsSessionLocallyTransacted(ISession session) - { - return SessionTransacted && - !ConnectionFactoryUtils.IsSessionTransactional(session, ConnectionFactory); - } - - /// Create a raw NMS MessageProducer for the given Session and Destination. - /// - /// the NMS Session to create a MessageProducer for - /// - /// the NMS IDestination to create a MessageProducer for - /// - /// the new NMS MessageProducer - /// - /// NMSException if thrown by NMS API methods - protected virtual Task DoCreateProducer(ISession session, IDestination destination) - { - return session.CreateProducerAsync(destination); - } - - /// Create a NMS MessageConsumer for the given Session and Destination. - /// - /// the NMS Session to create a MessageConsumer for - /// - /// the NMS Destination to create a MessageConsumer for - /// - /// the message selector for this consumer (can be null) - /// - /// the new NMS IMessageConsumer - /// - /// NMSException if thrown by NMS API methods - protected virtual Task CreateConsumer(ISession session, IDestination destination, - string messageSelector) - { - // Only pass in the NoLocal flag in case of a Topic: - // Some NMS providers, such as WebSphere MQ 6.0, throw IllegalStateException - // in case of the NoLocal flag being specified for a Queue. - if (PubSubDomain) - { - return session.CreateConsumerAsync(destination, messageSelector, PubSubNoLocal); + deliveryMode = MsgDeliveryMode.Persistent; } else { - return session.CreateConsumerAsync(destination, messageSelector); + deliveryMode = MsgDeliveryMode.NonPersistent; } } + } - /// - /// Send the given message. - /// - /// The session to operate on. - /// The destination to send to. - /// The message creator delegate callback to create a Message. - protected internal virtual async Task DoSend(ISession session, IDestination destination, MessageCreatorDelegate messageCreatorDelegate) + /// + /// Gets or sets a value indicating what DeliveryMode this + /// should use, for example a persistent QOS + /// + /// + virtual public MsgDeliveryMode DeliveryMode + { + get { return deliveryMode; } + set { deliveryMode = value; } + } + + /// + /// Gets or sets the priority when sending. + /// + /// Since a default value may be defined administratively, + /// this is only used when "isExplicitQosEnabled" equals "true". + /// The priority. + virtual public MsgPriority Priority + { + get { return priority; } + + set { priority = value; } + } + + /// + /// Gets or sets the time to live when sending + /// + /// Since a default value may be defined administratively, + /// this is only used when "isExplicitQosEnabled" equals "true". + /// The time to live. + virtual public TimeSpan TimeToLive + { + get { return timeToLive; } + + set { timeToLive = value; } + } + + #endregion + + /// + /// Extract the content from the given JMS message. + /// + /// The Message to convert (can be null). + /// The content of the message, or null if none + protected virtual object DoConvertFromMessage(IMessage message) + { + if (message != null) { - AssertUtils.ArgumentNotNull(messageCreatorDelegate, "IMessageCreatorDelegate must not be null"); - await DoSend(session, destination, null, messageCreatorDelegate).Awaiter(); + return MessageConverter.FromMessage(message); } - /// - /// Send the given message. - /// - /// The session to operate on. - /// The destination to send to. - /// The message creator callback to create a Message. - protected internal virtual async Task DoSend(ISession session, IDestination destination, IMessageCreator messageCreator) + return null; + } + + #region NMS Factory Methods + + /// Fetch an appropriate Connection from the given MessageResourceHolder. + /// + /// the MessageResourceHolder + /// + /// an appropriate IConnection fetched from the holder, + /// or null if none found + /// + protected virtual IConnection GetConnection(NmsResourceHolder holder) + { + return holder.GetConnection(); // TODO + } + + /// Fetch an appropriate Session from the given MessageResourceHolder. + /// + /// the MessageResourceHolder + /// + /// an appropriate ISession fetched from the holder, + /// or null if none found + /// + protected virtual ISession GetSession(NmsResourceHolder holder) + { + return holder.GetSession(); // TODO + } + + /// Create a NMS MessageProducer for the given Session and Destination, + /// configuring it to disable message ids and/or timestamps (if necessary). + ///

Delegates to doCreateProducer for creation of the raw + /// NMS MessageProducer

+ ///
+ /// the NMS Session to create a MessageProducer for + /// + /// the NMS Destination to create a MessageProducer for + /// + /// the new NMS MessageProducer + /// + /// NMSException if thrown by NMS API methods + /// + /// + /// + /// + /// + /// + protected virtual async Task CreateProducer(ISession session, IDestination destination) + { + IMessageProducer producer = await DoCreateProducer(session, destination).Awaiter(); + if (!MessageIdEnabled) { - AssertUtils.ArgumentNotNull(messageCreator, "IMessageCreator must not be null"); - await DoSend(session, destination, messageCreator, null).Awaiter(); + producer.DisableMessageID = true; } - /// Send the given NMS message. - /// the NMS Session to operate on - /// - /// the NMS Destination to send to - /// - /// callback to create a NMS Message - /// - /// delegate callback to create a NMS Message - /// - /// NMSException if thrown by NMS API methods - protected internal virtual async Task DoSend(ISession session, IDestination destination, IMessageCreator messageCreator, - MessageCreatorDelegate messageCreatorDelegate) + if (!MessageTimestampEnabled) { - IMessageProducer producer = await CreateProducer(session, destination).Awaiter(); - try + producer.DisableMessageTimestamp = true; + } + + return producer; + } + + /// + /// Determines whether the given Session is locally transacted, that is, whether + /// its transaction is managed by this template class's Session handling + /// and not by an external transaction coordinator. + /// + /// + /// The Session's own transacted flag will already have been checked + /// before. This method is about finding out whether the Session's transaction + /// is local or externally coordinated. + /// + /// The session to check. + /// + /// true if the session is locally transacted; otherwise, false. + /// + protected virtual bool IsSessionLocallyTransacted(ISession session) + { + return SessionTransacted && + !ConnectionFactoryUtils.IsSessionTransactional(session, ConnectionFactory); + } + + /// Create a raw NMS MessageProducer for the given Session and Destination. + /// + /// the NMS Session to create a MessageProducer for + /// + /// the NMS IDestination to create a MessageProducer for + /// + /// the new NMS MessageProducer + /// + /// NMSException if thrown by NMS API methods + protected virtual Task DoCreateProducer(ISession session, IDestination destination) + { + return session.CreateProducerAsync(destination); + } + + /// Create a NMS MessageConsumer for the given Session and Destination. + /// + /// the NMS Session to create a MessageConsumer for + /// + /// the NMS Destination to create a MessageConsumer for + /// + /// the message selector for this consumer (can be null) + /// + /// the new NMS IMessageConsumer + /// + /// NMSException if thrown by NMS API methods + protected virtual Task CreateConsumer(ISession session, IDestination destination, + string messageSelector) + { + // Only pass in the NoLocal flag in case of a Topic: + // Some NMS providers, such as WebSphere MQ 6.0, throw IllegalStateException + // in case of the NoLocal flag being specified for a Queue. + if (PubSubDomain) + { + return session.CreateConsumerAsync(destination, messageSelector, PubSubNoLocal); + } + else + { + return session.CreateConsumerAsync(destination, messageSelector); + } + } + + /// + /// Send the given message. + /// + /// The session to operate on. + /// The destination to send to. + /// The message creator delegate callback to create a Message. + protected internal virtual async Task DoSend(ISession session, IDestination destination, MessageCreatorDelegate messageCreatorDelegate) + { + AssertUtils.ArgumentNotNull(messageCreatorDelegate, "IMessageCreatorDelegate must not be null"); + await DoSend(session, destination, null, messageCreatorDelegate).Awaiter(); + } + + /// + /// Send the given message. + /// + /// The session to operate on. + /// The destination to send to. + /// The message creator callback to create a Message. + protected internal virtual async Task DoSend(ISession session, IDestination destination, IMessageCreator messageCreator) + { + AssertUtils.ArgumentNotNull(messageCreator, "IMessageCreator must not be null"); + await DoSend(session, destination, messageCreator, null).Awaiter(); + } + + /// Send the given NMS message. + /// the NMS Session to operate on + /// + /// the NMS Destination to send to + /// + /// callback to create a NMS Message + /// + /// delegate callback to create a NMS Message + /// + /// NMSException if thrown by NMS API methods + protected internal virtual async Task DoSend(ISession session, IDestination destination, IMessageCreator messageCreator, + MessageCreatorDelegate messageCreatorDelegate) + { + IMessageProducer producer = await CreateProducer(session, destination).Awaiter(); + try + { + IMessage message = null; + if (messageCreator != null) { - - IMessage message = null; - if (messageCreator != null) - { - message = messageCreator.CreateMessage(session) ; - } - else { - message = messageCreatorDelegate(session); - } - if (logger.IsEnabled(LogLevel.Debug)) - { - logger.LogDebug("Sending created message [" + message + "]"); - } - await DoSend(producer, message).Awaiter(); + message = messageCreator.CreateMessage(session); + } + else + { + message = messageCreatorDelegate(session); + } - // Check commit, avoid commit call is Session transaction is externally coordinated. - if (session.Transacted && IsSessionLocallyTransacted(session)) + if (logger.IsEnabled(LogLevel.Debug)) + { + logger.LogDebug("Sending created message [" + message + "]"); + } + + await DoSend(producer, message).Awaiter(); + + // Check commit, avoid commit call is Session transaction is externally coordinated. + if (session.Transacted && IsSessionLocallyTransacted(session)) + { + // Transacted session created by this template -> commit. + await NmsUtilsAsync.CommitIfNecessary(session).Awaiter(); + } + } + finally + { + await NmsUtilsAsync.CloseMessageProducer(producer).Awaiter(); + } + } + + /// Actually send the given NMS message. + /// the NMS MessageProducer to send with + /// + /// the NMS Message to send + /// + /// NMSException if thrown by NMS API methods + protected virtual async Task DoSend(IMessageProducer producer, IMessage message) + { + if (ExplicitQosEnabled) + { + await producer.SendAsync(message, DeliveryMode, Priority, TimeToLive).Awaiter(); + } + else + { + await producer.SendAsync(message).Awaiter(); + } + } + + #endregion + + #region IMessageOperations Implementation + + /// + /// Execute the action specified by the given action object within + /// a NMS Session. + /// + /// delegate that exposes the session + /// + /// the result object from working with the session + /// + /// + /// Note that the value of PubSubDomain affects the behavior of this method. + /// If PubSubDomain equals true, then a Session is passed to the callback. + /// If false, then a ISession is passed to the callback.b + /// + /// NMSException if there is any problem + public Task Execute(SessionDelegateAsync del) + { + return Execute(new ExecuteSessionCallbackUsingDelegateAsync(del)); + } + + /// Execute the action specified by the given action object within + /// a NMS Session. + ///

Note: The value of PubSubDomain affects the behavior of this method. + /// If PubSubDomain equals true, then a Session is passed to the callback. + /// If false, then a Session is passed to the callback.

+ ///
+ /// callback object that exposes the session + /// + /// the result object from working with the session + /// + /// NMSException if there is any problem + public Task Execute(ISessionCallbackAsync action) + { + return Execute(action, false); + } + + /// Send a message to a NMS destination. The callback gives access to + /// the NMS session and MessageProducer in order to do more complex + /// send operations. + /// + /// callback object that exposes the session/producer pair + /// + /// the result object from working with the session + /// + /// NMSException if there is any problem + public Task Execute(IProducerCallbackAsync action) + { + return Execute(new ProducerCreatorCallbackAsync(this, action)); + } + + /// Send a message to a NMS destination. The callback gives access to + /// the NMS session and MessageProducer in order to do more complex + /// send operations. + /// + /// delegate that exposes the session/producer pair + /// + /// the result object from working with the session + /// + /// NMSException if there is any problem + public Task Execute(ProducerDelegate del) + { + return Execute(new ProducerCreatorCallbackAsync(this, del)); + } + + /// Send a message to the default destination. + ///

This will only work with a default destination specified!

+ ///
+ /// delegate callback to create a message + /// + /// NMSException if there is any problem + public async Task SendWithDelegate(MessageCreatorDelegate messageCreatorDelegate) + { + CheckDefaultDestination(); + if (DefaultDestination != null) + { + await SendWithDelegate(DefaultDestination, messageCreatorDelegate).Awaiter(); + } + else + { + await SendWithDelegate(DefaultDestinationName, messageCreatorDelegate).Awaiter(); + } + } + + /// Send a message to the specified destination. + /// The MessageCreator callback creates the message given a Session. + /// + /// the destination to send this message to + /// + /// delegate callback to create a message + /// + /// NMSException if there is any problem + public Task SendWithDelegate(IDestination destination, MessageCreatorDelegate messageCreatorDelegate) + { + return Execute(new SendDestinationCallbackAsync(this, destination, messageCreatorDelegate), false); + } + + /// Send a message to the specified destination. + /// The MessageCreator callback creates the message given a Session. + /// + /// the name of the destination to send this message to + /// (to be resolved to an actual destination by a DestinationResolver) + /// + /// delegate callback to create a message + /// + /// NMSException if there is any problem + public Task SendWithDelegate(string destinationName, MessageCreatorDelegate messageCreatorDelegate) + { + return Execute(new SendDestinationCallbackAsync(this, destinationName, messageCreatorDelegate), false); + } + + /// Send a message to the default destination. + ///

This will only work with a default destination specified!

+ ///
+ /// callback to create a message + /// + /// NMSException if there is any problem + public async Task Send(IMessageCreator messageCreator) + { + CheckDefaultDestination(); + if (DefaultDestination != null) + { + await Send(DefaultDestination, messageCreator).Awaiter(); + } + else + { + await Send(DefaultDestinationName, messageCreator).Awaiter(); + } + } + + /// Send a message to the specified destination. + /// The MessageCreator callback creates the message given a Session. + /// + /// the destination to send this message to + /// + /// callback to create a message + /// + /// NMSException if there is any problem + public Task Send(IDestination destination, IMessageCreator messageCreator) + { + return Execute(new SendDestinationCallbackAsync(this, destination, messageCreator), false); + } + + /// Send a message to the specified destination. + /// The MessageCreator callback creates the message given a Session. + /// + /// the destination to send this message to + /// + /// callback to create a message + /// + /// NMSException if there is any problem + public Task Send(string destinationName, IMessageCreator messageCreator) + { + return Execute(new SendDestinationCallbackAsync(this, destinationName, messageCreator), false); + } + + /// Send the given object to the default destination, converting the object + /// to a NMS message with a configured IMessageConverter. + ///

This will only work with a default destination specified!

+ ///
+ /// the object to convert to a message + /// + /// NMSException if there is any problem + public async Task ConvertAndSend(object message) + { + CheckDefaultDestination(); + if (DefaultDestination != null) + { + await ConvertAndSend(DefaultDestination, message).Awaiter(); + } + else + { + await ConvertAndSend(DefaultDestinationName, message).Awaiter(); + } + } + + /// Send the given object to the specified destination, converting the object + /// to a NMS message with a configured IMessageConverter. + /// + /// the destination to send this message to + /// + /// the object to convert to a message + /// + /// NMSException if there is any problem + public Task ConvertAndSend(IDestination destination, object message) + { + CheckMessageConverter(); + return Send(destination, new SimpleMessageCreatorAsync(this, message)); + } + + /// Send the given object to the specified destination, converting the object + /// to a NMS message with a configured IMessageConverter. + /// + /// the name of the destination to send this message to + /// (to be resolved to an actual destination by a DestinationResolver) + /// + /// the object to convert to a message + /// + /// NMSException if there is any problem + public Task ConvertAndSend(string destinationName, object message) + { + return Send(destinationName, new SimpleMessageCreatorAsync(this, message)); + } + + /// Send the given object to the default destination, converting the object + /// to a NMS message with a configured IMessageConverter. The IMessagePostProcessor + /// callback allows for modification of the message after conversion. + ///

This will only work with a default destination specified!

+ ///
+ /// the object to convert to a message + /// + /// the callback to modify the message + /// + /// NMSException if there is any problem + public async Task ConvertAndSend(object message, IMessagePostProcessor postProcessor) + { + CheckDefaultDestination(); + if (DefaultDestination != null) + { + await ConvertAndSend(DefaultDestination, message, postProcessor).Awaiter(); + } + else + { + await ConvertAndSend(DefaultDestinationName, message, postProcessor).Awaiter(); + } + } + + /// Send the given object to the specified destination, converting the object + /// to a NMS message with a configured IMessageConverter. The IMessagePostProcessor + /// callback allows for modification of the message after conversion. + /// + /// the destination to send this message to + /// + /// the object to convert to a message + /// + /// the callback to modify the message + /// + /// NMSException if there is any problem + public Task ConvertAndSend(IDestination destination, object message, IMessagePostProcessor postProcessor) + { + CheckMessageConverter(); + return Send(destination, new ConvertAndSendMessageCreatorAsync(this, message, postProcessor)); + } + + /// Send the given object to the specified destination, converting the object + /// to a NMS message with a configured IMessageConverter. The IMessagePostProcessor + /// callback allows for modification of the message after conversion. + /// + /// the name of the destination to send this message to + /// (to be resolved to an actual destination by a DestinationResolver) + /// + /// the object to convert to a message. + /// + /// the callback to modify the message + /// + /// NMSException if there is any problem + public Task ConvertAndSend(string destinationName, object message, IMessagePostProcessor postProcessor) + { + CheckMessageConverter(); + return Send(destinationName, new ConvertAndSendMessageCreatorAsync(this, message, postProcessor)); + } + + /// + /// Send the given object to the default destination, converting the object + /// to a NMS message with a configured IMessageConverter. The IMessagePostProcessor + /// callback allows for modification of the message after conversion. + ///

This will only work with a default destination specified!

+ ///
+ /// the object to convert to a message + /// the callback to modify the message + /// NMSException if there is any problem + public async Task ConvertAndSendWithDelegate(object message, MessagePostProcessorDelegate postProcessor) + { + //Execute(new SendDestinationCallback(this, destination, messageCreatorDelegate), false); + CheckDefaultDestination(); + if (DefaultDestination != null) + { + await ConvertAndSendWithDelegate(DefaultDestination, message, postProcessor).Awaiter(); + } + else + { + await ConvertAndSendWithDelegate(DefaultDestinationName, message, postProcessor).Awaiter(); + } + } + + /// + /// Send the given object to the specified destination, converting the object + /// to a NMS message with a configured IMessageConverter. The IMessagePostProcessor + /// callback allows for modification of the message after conversion. + /// + /// the destination to send this message to + /// the object to convert to a message + /// the callback to modify the message + /// NMSException if there is any problem + public Task ConvertAndSendWithDelegate(IDestination destination, object message, + MessagePostProcessorDelegate postProcessor) + { + CheckMessageConverter(); + return Send(destination, new ConvertAndSendMessageCreatorAsync(this, message, postProcessor)); + } + + /// + /// Send the given object to the specified destination, converting the object + /// to a NMS message with a configured IMessageConverter. The IMessagePostProcessor + /// callback allows for modification of the message after conversion. + /// + /// the name of the destination to send this message to + /// (to be resolved to an actual destination by a DestinationResolver) + /// the object to convert to a message. + /// the callback to modify the message + /// NMSException if there is any problem + public Task ConvertAndSendWithDelegate(string destinationName, object message, + MessagePostProcessorDelegate postProcessor) + { + CheckMessageConverter(); + return Send(destinationName, new ConvertAndSendMessageCreatorAsync(this, message, postProcessor)); + } + + /// Receive a message synchronously from the default destination, but only + /// wait up to a specified time for delivery. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///

This will only work with a default destination specified!

+ ///
+ /// the message received by the consumer, or null if the timeout expires + /// + /// NMSException if there is any problem + public async Task Receive() + { + CheckDefaultDestination(); + if (DefaultDestination != null) + { + return await Receive(DefaultDestination).Awaiter(); + } + else + { + return await Receive(DefaultDestinationName).Awaiter(); + } + } + + /// Receive a message synchronously from the specified destination, but only + /// wait up to a specified time for delivery. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///
+ /// the destination to receive a message from + /// + /// the message received by the consumer, or null if the timeout expires + /// + /// NMSException if there is any problem + public Task Receive(IDestination destination) + { + return ReceiveSelected(destination, null); + } + + /// Receive a message synchronously from the specified destination, but only + /// wait up to a specified time for delivery. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///
+ /// the name of the destination to send this message to + /// (to be resolved to an actual destination by a DestinationResolver) + /// + /// the message received by the consumer, or null if the timeout expires + /// + /// NMSException if there is any problem + public Task Receive(string destinationName) + { + return ReceiveSelected(destinationName, null); + } + + /// Receive a message synchronously from the default destination, but only + /// wait up to a specified time for delivery. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///

This will only work with a default destination specified!

+ ///
+ /// the NMS message selector expression (or null if none). + /// See the NMS specification for a detailed definition of selector expressions. + /// + /// the message received by the consumer, or null if the timeout expires + /// + /// NMSException if there is any problem + public async Task ReceiveSelected(string messageSelector) + { + CheckDefaultDestination(); + if (DefaultDestination != null) + { + return await ReceiveSelected(DefaultDestination, messageSelector).Awaiter(); + } + else + { + return await ReceiveSelected(DefaultDestinationName, messageSelector).Awaiter(); + } + } + + /// Receive a message synchronously from the specified destination, but only + /// wait up to a specified time for delivery. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///
+ /// the destination to receive a message from + /// + /// the NMS message selector expression (or null if none). + /// See the NMS specification for a detailed definition of selector expressions. + /// + /// the message received by the consumer, or null if the timeout expires + /// + /// NMSException if there is any problem + public async Task ReceiveSelected(IDestination destination, string messageSelector) + { + return (await Execute(new ReceiveSelectedCallbackAsync(this, destination, messageSelector), true).Awaiter()) as IMessage; + } + + /// Receive a message synchronously from the specified destination, but only + /// wait up to a specified time for delivery. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///
+ /// the name of the destination to send this message to + /// (to be resolved to an actual destination by a DestinationResolver) + /// + /// the NMS message selector expression (or null if none). + /// See the NMS specification for a detailed definition of selector expressions. + /// + /// the message received by the consumer, or null if the timeout expires + /// + /// NMSException if there is any problem + public async Task ReceiveSelected(string destinationName, string messageSelector) + { + return (await Execute(new ReceiveSelectedCallbackAsync(this, destinationName, messageSelector), true).Awaiter()) as IMessage; + } + + /// + /// Receive a message. + /// + /// The session to operate on. + /// The destination to receive from. + /// The message selector for this consumer (can be null + /// The Message received, or null if none. + protected virtual async Task DoReceive(ISession session, IDestination destination, string messageSelector) + { + return await DoReceive(session, await CreateConsumer(session, destination, messageSelector).Awaiter()).Awaiter(); + } + + /// + /// Receive a message. + /// + /// The session to operate on. + /// The consumer to receive with. + /// The Message received, or null if none + protected virtual async Task DoReceive(ISession session, IMessageConsumer consumer) + { + try + { + long timeout = ReceiveTimeout; + NmsResourceHolder resourceHolder = + (NmsResourceHolder) TransactionSynchronizationManager.GetResource(ConnectionFactory); + if (resourceHolder != null && resourceHolder.HasTimeout) + { + timeout = Convert.ToInt64(resourceHolder.TimeToLiveInMilliseconds); + } + + IMessage message = (timeout > 0) + ? await consumer.ReceiveAsync(TimeSpan.FromMilliseconds(timeout)).Awaiter() + : await consumer.ReceiveAsync().Awaiter(); + if (session.Transacted) + { + // Commit necessary - but avoid commit call is Session transaction is externally coordinated. + if (IsSessionLocallyTransacted(session)) { // Transacted session created by this template -> commit. await NmsUtilsAsync.CommitIfNecessary(session).Awaiter(); } } + else if (IsClientAcknowledge(session)) + { + // Manually acknowledge message, if any. + if (message != null) + { + await message.AcknowledgeAsync().Awaiter(); + } + } + + return message; + // return message; + } + finally + { + await NmsUtilsAsync.CloseMessageConsumer(consumer).Awaiter(); + } + } + + /// Receive a message synchronously from the default destination, but only + /// wait up to a specified time for delivery. Convert the message into an + /// object with a configured IMessageConverter. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///

This will only work with a default destination specified!

+ ///
+ /// the message produced for the consumer or null if the timeout expires. + /// + /// NMSException if there is any problem + public async Task ReceiveAndConvert() + { + CheckMessageConverter(); + return DoConvertFromMessage(await Receive().Awaiter()); + } + + /// Receive a message synchronously from the specified destination, but only + /// wait up to a specified time for delivery. Convert the message into an + /// object with a configured IMessageConverter. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///
+ /// the destination to receive a message from + /// + /// the message produced for the consumer or null if the timeout expires. + /// + /// NMSException if there is any problem + public async Task ReceiveAndConvert(IDestination destination) + { + CheckMessageConverter(); + return DoConvertFromMessage(await Receive(destination).Awaiter()); + } + + /// Receive a message synchronously from the specified destination, but only + /// wait up to a specified time for delivery. Convert the message into an + /// object with a configured IMessageConverter. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///
+ /// the name of the destination to send this message to + /// (to be resolved to an actual destination by a DestinationResolver) + /// + /// the message produced for the consumer or null if the timeout expires. + /// + /// NMSException if there is any problem + public async Task ReceiveAndConvert(string destinationName) + { + CheckMessageConverter(); + return DoConvertFromMessage(await Receive(destinationName).Awaiter()); + } + + /// Receive a message synchronously from the default destination, but only + /// wait up to a specified time for delivery. Convert the message into an + /// object with a configured IMessageConverter. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///

This will only work with a default destination specified!

+ ///
+ /// the NMS message selector expression (or null if none). + /// See the NMS specification for a detailed definition of selector expressions. + /// + /// the message produced for the consumer or null if the timeout expires. + /// + /// NMSException if there is any problem + public async Task ReceiveSelectedAndConvert(string messageSelector) + { + CheckMessageConverter(); + return DoConvertFromMessage(await ReceiveSelected(messageSelector).Awaiter()); + } + + /// Receive a message synchronously from the specified destination, but only + /// wait up to a specified time for delivery. Convert the message into an + /// object with a configured IMessageConverter. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///
+ /// the destination to receive a message from + /// + /// the NMS message selector expression (or null if none). + /// See the NMS specification for a detailed definition of selector expressions. + /// + /// the message produced for the consumer or null if the timeout expires. + /// + /// NMSException if there is any problem + public async Task ReceiveSelectedAndConvert(IDestination destination, string messageSelector) + { + CheckMessageConverter(); + return DoConvertFromMessage(await ReceiveSelected(destination, messageSelector).Awaiter()); + } + + /// Receive a message synchronously from the specified destination, but only + /// wait up to a specified time for delivery. Convert the message into an + /// object with a configured IMessageConverter. + ///

This method should be used carefully, since it will block the thread + /// until the message becomes available or until the timeout value is exceeded.

+ ///
+ /// the name of the destination to send this message to + /// (to be resolved to an actual destination by a DestinationResolver) + /// + /// the NMS message selector expression (or null if none). + /// See the NMS specification for a detailed definition of selector expressions. + /// + /// the message produced for the consumer or null if the timeout expires. + /// + /// NMSException if there is any problem + public async Task ReceiveSelectedAndConvert(string destinationName, string messageSelector) + { + CheckMessageConverter(); + return DoConvertFromMessage(await ReceiveSelected(destinationName, messageSelector).Awaiter()); + } + + #endregion + + #region Supporting Internal Classes + + /// + /// ResourceFactory implementation that delegates to this template's callback methods. + /// + private class NmsTemplateResourceFactoryAsync : ConnectionFactoryUtils.ResourceFactory + { + private NmsTemplateAsync enclosingTemplateInstance; + + public NmsTemplateResourceFactoryAsync(NmsTemplateAsync enclosingInstance) + { + InitBlock(enclosingInstance); + } + + private void InitBlock(NmsTemplateAsync enclosingInstance) + { + enclosingTemplateInstance = enclosingInstance; + } + + public NmsTemplateAsync EnclosingInstance + { + get { return enclosingTemplateInstance; } + } + + public virtual IConnection GetConnection(NmsResourceHolder holder) + { + return EnclosingInstance.GetConnection(holder); + } + + public virtual ISession GetSession(NmsResourceHolder holder) + { + return EnclosingInstance.GetSession(holder); + } + + public virtual IConnection CreateConnection() + { + return EnclosingInstance.CreateConnection().GetAsyncResult(); + } + + public virtual ISession CreateSession(IConnection con) + { + return EnclosingInstance.CreateSession(con).GetAsyncResult(); + } + + public virtual Task CreateConnectionAsync() + { + return EnclosingInstance.CreateConnection(); + } + + public virtual Task CreateSessionAsync(IConnection con) + { + return EnclosingInstance.CreateSession(con); + } + + public bool SynchedLocalTransactionAllowed + { + get { return EnclosingInstance.SessionTransacted; } + } + } + + private class ProducerCreatorCallbackAsync : ISessionCallbackAsync + { + private readonly NmsTemplateAsync jmsTemplate; + private readonly IProducerCallbackAsync producerCallback; + private readonly ProducerDelegate producerDelegate; + + public ProducerCreatorCallbackAsync(NmsTemplateAsync jmsTemplate, IProducerCallbackAsync producerCallback) + { + this.jmsTemplate = jmsTemplate; + this.producerCallback = producerCallback; + } + + public ProducerCreatorCallbackAsync(NmsTemplateAsync jmsTemplate, ProducerDelegate producerDelegate) + { + this.jmsTemplate = jmsTemplate; + this.producerDelegate = producerDelegate; + } + + public async Task DoInNms(ISession session) + { + IMessageProducer producer = await jmsTemplate.CreateProducer(session, null).Awaiter(); + try + { + if (producerCallback != null) + { + return await producerCallback.DoInNms(session, producer).Awaiter(); + } + else + { + return producerDelegate(session, producer); + } + } finally { await NmsUtilsAsync.CloseMessageProducer(producer).Awaiter(); } } + } + private class ReceiveCallbackAsync : ISessionCallbackAsync + { + private readonly NmsTemplateAsync jmsTemplate; + private readonly IDestination destination; + private readonly string destinationName; - /// Actually send the given NMS message. - /// the NMS MessageProducer to send with - /// - /// the NMS Message to send - /// - /// NMSException if thrown by NMS API methods - protected virtual async Task DoSend(IMessageProducer producer, IMessage message) + public ReceiveCallbackAsync(NmsTemplateAsync jmsTemplate, string destinationName) { - if (ExplicitQosEnabled) + this.jmsTemplate = jmsTemplate; + this.destinationName = destinationName; + } + + public ReceiveCallbackAsync(NmsTemplateAsync jmsTemplate, IDestination destination) + { + this.jmsTemplate = jmsTemplate; + this.destination = destination; + } + + public async Task DoInNms(ISession session) + { + if (destination != null) { - await producer.SendAsync(message, DeliveryMode, Priority, TimeToLive).Awaiter(); + return await jmsTemplate.DoReceive(session, destination, null).Awaiter(); } else { - await producer.SendAsync(message).Awaiter(); - } - } - - #endregion - - #region IMessageOperations Implementation - - /// - /// Execute the action specified by the given action object within - /// a NMS Session. - /// - /// delegate that exposes the session - /// - /// the result object from working with the session - /// - /// - /// Note that the value of PubSubDomain affects the behavior of this method. - /// If PubSubDomain equals true, then a Session is passed to the callback. - /// If false, then a ISession is passed to the callback.b - /// - /// NMSException if there is any problem - public Task Execute(SessionDelegateAsync del) - { - return Execute(new ExecuteSessionCallbackUsingDelegateAsync(del)); - } - - /// Execute the action specified by the given action object within - /// a NMS Session. - ///

Note: The value of PubSubDomain affects the behavior of this method. - /// If PubSubDomain equals true, then a Session is passed to the callback. - /// If false, then a Session is passed to the callback.

- ///
- /// callback object that exposes the session - /// - /// the result object from working with the session - /// - /// NMSException if there is any problem - public Task Execute(ISessionCallbackAsync action) - { - return Execute(action, false); - } - - - - /// Send a message to a NMS destination. The callback gives access to - /// the NMS session and MessageProducer in order to do more complex - /// send operations. - /// - /// callback object that exposes the session/producer pair - /// - /// the result object from working with the session - /// - /// NMSException if there is any problem - public Task Execute(IProducerCallbackAsync action) - { - return Execute(new ProducerCreatorCallbackAsync(this, action)); - } - - /// Send a message to a NMS destination. The callback gives access to - /// the NMS session and MessageProducer in order to do more complex - /// send operations. - /// - /// delegate that exposes the session/producer pair - /// - /// the result object from working with the session - /// - /// NMSException if there is any problem - public Task Execute(ProducerDelegate del) - { - return Execute(new ProducerCreatorCallbackAsync(this, del)); - } - - /// Send a message to the default destination. - ///

This will only work with a default destination specified!

- ///
- /// delegate callback to create a message - /// - /// NMSException if there is any problem - public async Task SendWithDelegate(MessageCreatorDelegate messageCreatorDelegate) - { - CheckDefaultDestination(); - if (DefaultDestination != null) - { - await SendWithDelegate(DefaultDestination, messageCreatorDelegate).Awaiter(); - } - else - { - await SendWithDelegate(DefaultDestinationName, messageCreatorDelegate).Awaiter(); - } - } - - - - /// Send a message to the specified destination. - /// The MessageCreator callback creates the message given a Session. - /// - /// the destination to send this message to - /// - /// delegate callback to create a message - /// - /// NMSException if there is any problem - public Task SendWithDelegate(IDestination destination, MessageCreatorDelegate messageCreatorDelegate) - { - return Execute(new SendDestinationCallbackAsync(this, destination, messageCreatorDelegate), false); - } - - /// Send a message to the specified destination. - /// The MessageCreator callback creates the message given a Session. - /// - /// the name of the destination to send this message to - /// (to be resolved to an actual destination by a DestinationResolver) - /// - /// delegate callback to create a message - /// - /// NMSException if there is any problem - public Task SendWithDelegate(string destinationName, MessageCreatorDelegate messageCreatorDelegate) - { - return Execute(new SendDestinationCallbackAsync(this, destinationName, messageCreatorDelegate), false); - } - - - /// Send a message to the default destination. - ///

This will only work with a default destination specified!

- ///
- /// callback to create a message - /// - /// NMSException if there is any problem - public async Task Send(IMessageCreator messageCreator) - { - CheckDefaultDestination(); - if (DefaultDestination != null) - { - await Send(DefaultDestination, messageCreator).Awaiter(); - } - else - { - await Send(DefaultDestinationName, messageCreator).Awaiter(); - } - } - - /// Send a message to the specified destination. - /// The MessageCreator callback creates the message given a Session. - /// - /// the destination to send this message to - /// - /// callback to create a message - /// - /// NMSException if there is any problem - public Task Send(IDestination destination, IMessageCreator messageCreator) - { - return Execute(new SendDestinationCallbackAsync(this, destination, messageCreator), false); - } - - /// Send a message to the specified destination. - /// The MessageCreator callback creates the message given a Session. - /// - /// the destination to send this message to - /// - /// callback to create a message - /// - /// NMSException if there is any problem - public Task Send(string destinationName, IMessageCreator messageCreator) - { - return Execute(new SendDestinationCallbackAsync(this, destinationName, messageCreator), false); - } - /// Send the given object to the default destination, converting the object - /// to a NMS message with a configured IMessageConverter. - ///

This will only work with a default destination specified!

- ///
- /// the object to convert to a message - /// - /// NMSException if there is any problem - public async Task ConvertAndSend(object message) - { - CheckDefaultDestination(); - if (DefaultDestination != null) - { - await ConvertAndSend(DefaultDestination, message).Awaiter(); - } - else - { - await ConvertAndSend(DefaultDestinationName, message).Awaiter(); - } - } - - /// Send the given object to the specified destination, converting the object - /// to a NMS message with a configured IMessageConverter. - /// - /// the destination to send this message to - /// - /// the object to convert to a message - /// - /// NMSException if there is any problem - public Task ConvertAndSend(IDestination destination, object message) - { - CheckMessageConverter(); - return Send(destination, new SimpleMessageCreatorAsync(this, message)); - } - - /// Send the given object to the specified destination, converting the object - /// to a NMS message with a configured IMessageConverter. - /// - /// the name of the destination to send this message to - /// (to be resolved to an actual destination by a DestinationResolver) - /// - /// the object to convert to a message - /// - /// NMSException if there is any problem - public Task ConvertAndSend(string destinationName, object message) - { - return Send(destinationName, new SimpleMessageCreatorAsync(this, message)); - } - - /// Send the given object to the default destination, converting the object - /// to a NMS message with a configured IMessageConverter. The IMessagePostProcessor - /// callback allows for modification of the message after conversion. - ///

This will only work with a default destination specified!

- ///
- /// the object to convert to a message - /// - /// the callback to modify the message - /// - /// NMSException if there is any problem - public async Task ConvertAndSend(object message, IMessagePostProcessor postProcessor) - { - CheckDefaultDestination(); - if (DefaultDestination != null) - { - await ConvertAndSend(DefaultDestination, message, postProcessor).Awaiter(); - } - else - { - await ConvertAndSend(DefaultDestinationName, message, postProcessor).Awaiter(); - } - } - - /// Send the given object to the specified destination, converting the object - /// to a NMS message with a configured IMessageConverter. The IMessagePostProcessor - /// callback allows for modification of the message after conversion. - /// - /// the destination to send this message to - /// - /// the object to convert to a message - /// - /// the callback to modify the message - /// - /// NMSException if there is any problem - public Task ConvertAndSend(IDestination destination, object message, IMessagePostProcessor postProcessor) - { - CheckMessageConverter(); - return Send(destination, new ConvertAndSendMessageCreatorAsync(this, message, postProcessor)); - } - - /// Send the given object to the specified destination, converting the object - /// to a NMS message with a configured IMessageConverter. The IMessagePostProcessor - /// callback allows for modification of the message after conversion. - /// - /// the name of the destination to send this message to - /// (to be resolved to an actual destination by a DestinationResolver) - /// - /// the object to convert to a message. - /// - /// the callback to modify the message - /// - /// NMSException if there is any problem - public Task ConvertAndSend(string destinationName, object message, IMessagePostProcessor postProcessor) - { - CheckMessageConverter(); - return Send(destinationName, new ConvertAndSendMessageCreatorAsync(this, message, postProcessor)); - } - - - /// - /// Send the given object to the default destination, converting the object - /// to a NMS message with a configured IMessageConverter. The IMessagePostProcessor - /// callback allows for modification of the message after conversion. - ///

This will only work with a default destination specified!

- ///
- /// the object to convert to a message - /// the callback to modify the message - /// NMSException if there is any problem - public async Task ConvertAndSendWithDelegate(object message, MessagePostProcessorDelegate postProcessor) - { - //Execute(new SendDestinationCallback(this, destination, messageCreatorDelegate), false); - CheckDefaultDestination(); - if (DefaultDestination != null) - { - await ConvertAndSendWithDelegate(DefaultDestination, message, postProcessor).Awaiter(); - } - else - { - await ConvertAndSendWithDelegate(DefaultDestinationName, message, postProcessor).Awaiter(); - } - } - - /// - /// Send the given object to the specified destination, converting the object - /// to a NMS message with a configured IMessageConverter. The IMessagePostProcessor - /// callback allows for modification of the message after conversion. - /// - /// the destination to send this message to - /// the object to convert to a message - /// the callback to modify the message - /// NMSException if there is any problem - public Task ConvertAndSendWithDelegate(IDestination destination, object message, - MessagePostProcessorDelegate postProcessor) - { - CheckMessageConverter(); - return Send(destination, new ConvertAndSendMessageCreatorAsync(this, message, postProcessor)); - } - - /// - /// Send the given object to the specified destination, converting the object - /// to a NMS message with a configured IMessageConverter. The IMessagePostProcessor - /// callback allows for modification of the message after conversion. - /// - /// the name of the destination to send this message to - /// (to be resolved to an actual destination by a DestinationResolver) - /// the object to convert to a message. - /// the callback to modify the message - /// NMSException if there is any problem - public Task ConvertAndSendWithDelegate(string destinationName, object message, - MessagePostProcessorDelegate postProcessor) - { - CheckMessageConverter(); - return Send(destinationName, new ConvertAndSendMessageCreatorAsync(this, message, postProcessor)); - } - - /// Receive a message synchronously from the default destination, but only - /// wait up to a specified time for delivery. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///

This will only work with a default destination specified!

- ///
- /// the message received by the consumer, or null if the timeout expires - /// - /// NMSException if there is any problem - public async Task Receive() - { - CheckDefaultDestination(); - if (DefaultDestination != null) - { - return await Receive(DefaultDestination).Awaiter(); - } - else - { - return await Receive(DefaultDestinationName).Awaiter(); - } - } - - /// Receive a message synchronously from the specified destination, but only - /// wait up to a specified time for delivery. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///
- /// the destination to receive a message from - /// - /// the message received by the consumer, or null if the timeout expires - /// - /// NMSException if there is any problem - public Task Receive(IDestination destination) - { - return ReceiveSelected(destination, null); - } - - - /// Receive a message synchronously from the specified destination, but only - /// wait up to a specified time for delivery. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///
- /// the name of the destination to send this message to - /// (to be resolved to an actual destination by a DestinationResolver) - /// - /// the message received by the consumer, or null if the timeout expires - /// - /// NMSException if there is any problem - public Task Receive(string destinationName) - { - return ReceiveSelected(destinationName, null); - } - - /// Receive a message synchronously from the default destination, but only - /// wait up to a specified time for delivery. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///

This will only work with a default destination specified!

- ///
- /// the NMS message selector expression (or null if none). - /// See the NMS specification for a detailed definition of selector expressions. - /// - /// the message received by the consumer, or null if the timeout expires - /// - /// NMSException if there is any problem - public async Task ReceiveSelected(string messageSelector) - { - CheckDefaultDestination(); - if (DefaultDestination!= null) - { - return await ReceiveSelected(DefaultDestination, messageSelector).Awaiter(); - } - else - { - return await ReceiveSelected(DefaultDestinationName, messageSelector).Awaiter(); - } - } - - /// Receive a message synchronously from the specified destination, but only - /// wait up to a specified time for delivery. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///
- /// the destination to receive a message from - /// - /// the NMS message selector expression (or null if none). - /// See the NMS specification for a detailed definition of selector expressions. - /// - /// the message received by the consumer, or null if the timeout expires - /// - /// NMSException if there is any problem - public async Task ReceiveSelected(IDestination destination, string messageSelector) - { - return (await Execute(new ReceiveSelectedCallbackAsync(this, destination, messageSelector), true).Awaiter()) as IMessage; - } - - /// Receive a message synchronously from the specified destination, but only - /// wait up to a specified time for delivery. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///
- /// the name of the destination to send this message to - /// (to be resolved to an actual destination by a DestinationResolver) - /// - /// the NMS message selector expression (or null if none). - /// See the NMS specification for a detailed definition of selector expressions. - /// - /// the message received by the consumer, or null if the timeout expires - /// - /// NMSException if there is any problem - public async Task ReceiveSelected(string destinationName, string messageSelector) - { - return (await Execute(new ReceiveSelectedCallbackAsync(this, destinationName, messageSelector), true).Awaiter()) as IMessage; - } - - /// - /// Receive a message. - /// - /// The session to operate on. - /// The destination to receive from. - /// The message selector for this consumer (can be null - /// The Message received, or null if none. - protected virtual async Task DoReceive(ISession session, IDestination destination, string messageSelector) - { - return await DoReceive(session, await CreateConsumer(session, destination, messageSelector).Awaiter()).Awaiter(); - } - - /// - /// Receive a message. - /// - /// The session to operate on. - /// The consumer to receive with. - /// The Message received, or null if none - protected virtual async Task DoReceive(ISession session, IMessageConsumer consumer) - { - try - { - long timeout = ReceiveTimeout; - NmsResourceHolder resourceHolder = - (NmsResourceHolder)TransactionSynchronizationManager.GetResource(ConnectionFactory); - if (resourceHolder != null && resourceHolder.HasTimeout) - { - timeout = Convert.ToInt64(resourceHolder.TimeToLiveInMilliseconds); - } - IMessage message = (timeout > 0) - ? await consumer.ReceiveAsync(TimeSpan.FromMilliseconds(timeout)).Awaiter() - : await consumer.ReceiveAsync().Awaiter(); - if (session.Transacted) - { - // Commit necessary - but avoid commit call is Session transaction is externally coordinated. - if (IsSessionLocallyTransacted(session)) - { - // Transacted session created by this template -> commit. - await NmsUtilsAsync.CommitIfNecessary(session).Awaiter(); - } - } - else if (IsClientAcknowledge(session)) - { - // Manually acknowledge message, if any. - if (message != null) - { - await message.AcknowledgeAsync().Awaiter(); - } - } - - return message; - // return message; - } - finally - { - await NmsUtilsAsync.CloseMessageConsumer(consumer).Awaiter(); - } - } - - - /// Receive a message synchronously from the default destination, but only - /// wait up to a specified time for delivery. Convert the message into an - /// object with a configured IMessageConverter. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///

This will only work with a default destination specified!

- ///
- /// the message produced for the consumer or null if the timeout expires. - /// - /// NMSException if there is any problem - public async Task ReceiveAndConvert() - { - CheckMessageConverter(); - return DoConvertFromMessage(await Receive().Awaiter()); - } - - /// Receive a message synchronously from the specified destination, but only - /// wait up to a specified time for delivery. Convert the message into an - /// object with a configured IMessageConverter. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///
- /// the destination to receive a message from - /// - /// the message produced for the consumer or null if the timeout expires. - /// - /// NMSException if there is any problem - public async Task ReceiveAndConvert(IDestination destination) - { - CheckMessageConverter(); - return DoConvertFromMessage(await Receive(destination).Awaiter()); - } - - - /// Receive a message synchronously from the specified destination, but only - /// wait up to a specified time for delivery. Convert the message into an - /// object with a configured IMessageConverter. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///
- /// the name of the destination to send this message to - /// (to be resolved to an actual destination by a DestinationResolver) - /// - /// the message produced for the consumer or null if the timeout expires. - /// - /// NMSException if there is any problem - public async Task ReceiveAndConvert(string destinationName) - { - CheckMessageConverter(); - return DoConvertFromMessage(await Receive(destinationName).Awaiter()); - } - - /// Receive a message synchronously from the default destination, but only - /// wait up to a specified time for delivery. Convert the message into an - /// object with a configured IMessageConverter. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///

This will only work with a default destination specified!

- ///
- /// the NMS message selector expression (or null if none). - /// See the NMS specification for a detailed definition of selector expressions. - /// - /// the message produced for the consumer or null if the timeout expires. - /// - /// NMSException if there is any problem - public async Task ReceiveSelectedAndConvert(string messageSelector) - { - CheckMessageConverter(); - return DoConvertFromMessage(await ReceiveSelected(messageSelector).Awaiter()); - } - - /// Receive a message synchronously from the specified destination, but only - /// wait up to a specified time for delivery. Convert the message into an - /// object with a configured IMessageConverter. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///
- /// the destination to receive a message from - /// - /// the NMS message selector expression (or null if none). - /// See the NMS specification for a detailed definition of selector expressions. - /// - /// the message produced for the consumer or null if the timeout expires. - /// - /// NMSException if there is any problem - public async Task ReceiveSelectedAndConvert(IDestination destination, string messageSelector) - { - CheckMessageConverter(); - return DoConvertFromMessage(await ReceiveSelected(destination, messageSelector).Awaiter()); - } - - /// Receive a message synchronously from the specified destination, but only - /// wait up to a specified time for delivery. Convert the message into an - /// object with a configured IMessageConverter. - ///

This method should be used carefully, since it will block the thread - /// until the message becomes available or until the timeout value is exceeded.

- ///
- /// the name of the destination to send this message to - /// (to be resolved to an actual destination by a DestinationResolver) - /// - /// the NMS message selector expression (or null if none). - /// See the NMS specification for a detailed definition of selector expressions. - /// - /// the message produced for the consumer or null if the timeout expires. - /// - /// NMSException if there is any problem - public async Task ReceiveSelectedAndConvert(string destinationName, string messageSelector) - { - CheckMessageConverter(); - return DoConvertFromMessage(await ReceiveSelected(destinationName, messageSelector).Awaiter()); - } - - #endregion - - #region Supporting Internal Classes - - /// - /// ResourceFactory implementation that delegates to this template's callback methods. - /// - private class NmsTemplateResourceFactoryAsync : ConnectionFactoryUtils.ResourceFactory - { - private NmsTemplateAsync enclosingTemplateInstance; - - public NmsTemplateResourceFactoryAsync(NmsTemplateAsync enclosingInstance) - { - InitBlock(enclosingInstance); - } - - private void InitBlock(NmsTemplateAsync enclosingInstance) - { - enclosingTemplateInstance = enclosingInstance; - } - - public NmsTemplateAsync EnclosingInstance - { - get { return enclosingTemplateInstance; } - } - - public virtual IConnection GetConnection(NmsResourceHolder holder) - { - return EnclosingInstance.GetConnection(holder); - } - - public virtual ISession GetSession(NmsResourceHolder holder) - { - return EnclosingInstance.GetSession(holder); - } - - public virtual IConnection CreateConnection() - { - return EnclosingInstance.CreateConnection().GetAsyncResult(); - } - - public virtual ISession CreateSession(IConnection con) - { - return EnclosingInstance.CreateSession(con).GetAsyncResult(); - } - - public virtual Task CreateConnectionAsync() - { - return EnclosingInstance.CreateConnection(); - } - - public virtual Task CreateSessionAsync(IConnection con) - { - return EnclosingInstance.CreateSession(con); - } - - public bool SynchedLocalTransactionAllowed - { - get { return EnclosingInstance.SessionTransacted; } - } - } - - private class ProducerCreatorCallbackAsync : ISessionCallbackAsync - { - private readonly NmsTemplateAsync jmsTemplate; - private readonly IProducerCallbackAsync producerCallback; - private readonly ProducerDelegate producerDelegate; - - public ProducerCreatorCallbackAsync(NmsTemplateAsync jmsTemplate, IProducerCallbackAsync producerCallback) - { - this.jmsTemplate = jmsTemplate; - this.producerCallback = producerCallback; - } - - public ProducerCreatorCallbackAsync(NmsTemplateAsync jmsTemplate, ProducerDelegate producerDelegate) - { - this.jmsTemplate = jmsTemplate; - this.producerDelegate = producerDelegate; - } - - public async Task DoInNms(ISession session) - { - IMessageProducer producer = await jmsTemplate.CreateProducer(session, null).Awaiter(); - try - { - if (producerCallback != null) - { - return await producerCallback.DoInNms(session, producer).Awaiter(); - } - else - { - return producerDelegate(session, producer); - } - } - finally - { - await NmsUtilsAsync.CloseMessageProducer(producer).Awaiter(); - } - - } - } - - private class ReceiveCallbackAsync : ISessionCallbackAsync - { - private readonly NmsTemplateAsync jmsTemplate; - private readonly IDestination destination; - private readonly string destinationName; - - - public ReceiveCallbackAsync(NmsTemplateAsync jmsTemplate, string destinationName) - { - this.jmsTemplate = jmsTemplate; - this.destinationName = destinationName; - } - - public ReceiveCallbackAsync(NmsTemplateAsync jmsTemplate, IDestination destination) - { - this.jmsTemplate = jmsTemplate; - this.destination = destination; - } - - public async Task DoInNms(ISession session) - { - if (destination != null) - { - return await jmsTemplate.DoReceive(session, destination, null).Awaiter(); - } - else - { - return await jmsTemplate.DoReceive(session,await - jmsTemplate.ResolveDestinationName(session, destinationName).Awaiter(), - null).Awaiter(); - } - - } - } - - private class ConvertAndSendMessageCreatorAsync : IMessageCreator - { - private readonly NmsTemplateAsync jmsTemplate; - private readonly object objectToConvert; - private readonly IMessagePostProcessor messagePostProcessor; - private readonly MessagePostProcessorDelegate messagePostProcessorDelegate; - - public ConvertAndSendMessageCreatorAsync(NmsTemplateAsync jmsTemplate, object message, IMessagePostProcessor messagePostProcessor) - { - this.jmsTemplate = jmsTemplate; - objectToConvert = message; - this.messagePostProcessor = messagePostProcessor; - } - - public ConvertAndSendMessageCreatorAsync(NmsTemplateAsync jmsTemplate, object message, MessagePostProcessorDelegate messagePostProcessorDelegate) - { - this.jmsTemplate = jmsTemplate; - objectToConvert = message; - this.messagePostProcessorDelegate = messagePostProcessorDelegate; - } - - public IMessage CreateMessage(ISession session) - { - IMessage msg = jmsTemplate.MessageConverter.ToMessage(objectToConvert, session); - if (messagePostProcessor != null) - { - return messagePostProcessor.PostProcessMessage(msg); - } else - { - return messagePostProcessorDelegate(msg); - } - } - - } - - private class ReceiveSelectedCallbackAsync : ISessionCallbackAsync - { - private readonly NmsTemplateAsync jmsTemplate; - private readonly string messageSelector; - private readonly string destinationName; - private readonly IDestination destination; - - public ReceiveSelectedCallbackAsync(NmsTemplateAsync jmsTemplate, - IDestination destination, - string messageSelector) - { - this.jmsTemplate = jmsTemplate; - this.destination = destination; - this.messageSelector = messageSelector; - } - public ReceiveSelectedCallbackAsync(NmsTemplateAsync jmsTemplate, - string destinationName, - string messageSelector) - { - this.jmsTemplate = jmsTemplate; - this.destinationName = destinationName; - this.messageSelector = messageSelector; - } - - public async Task DoInNms(ISession session) - { - if (destination != null) - { - return await jmsTemplate.DoReceive(session, destination, messageSelector).Awaiter(); - } - else - { - return await jmsTemplate.DoReceive(session,await - jmsTemplate.ResolveDestinationName(session, destinationName).Awaiter(), - messageSelector).Awaiter(); - } - - } - - } - - #endregion - - private class ExecuteSessionCallbackUsingDelegateAsync : ISessionCallbackAsync - { - private readonly SessionDelegateAsync del; - public ExecuteSessionCallbackUsingDelegateAsync(SessionDelegateAsync del) - { - this.del = del; - } - - public Task DoInNms(ISession session) - { - return del(session); + return await jmsTemplate.DoReceive(session, await + jmsTemplate.ResolveDestinationName(session, destinationName).Awaiter(), + null).Awaiter(); } } } - - - internal class SimpleMessageCreatorAsync : IMessageCreator + private class ConvertAndSendMessageCreatorAsync : IMessageCreator { private readonly NmsTemplateAsync jmsTemplate; private readonly object objectToConvert; - - public SimpleMessageCreatorAsync(NmsTemplateAsync jmsTemplate, object objectToConvert) + private readonly IMessagePostProcessor messagePostProcessor; + private readonly MessagePostProcessorDelegate messagePostProcessorDelegate; + + public ConvertAndSendMessageCreatorAsync(NmsTemplateAsync jmsTemplate, object message, IMessagePostProcessor messagePostProcessor) { this.jmsTemplate = jmsTemplate; - this.objectToConvert = objectToConvert; + objectToConvert = message; + this.messagePostProcessor = messagePostProcessor; + } + + public ConvertAndSendMessageCreatorAsync(NmsTemplateAsync jmsTemplate, object message, MessagePostProcessorDelegate messagePostProcessorDelegate) + { + this.jmsTemplate = jmsTemplate; + objectToConvert = message; + this.messagePostProcessorDelegate = messagePostProcessorDelegate; } public IMessage CreateMessage(ISession session) { - return jmsTemplate.MessageConverter.ToMessage(objectToConvert, session); - } - - - } - - - - internal class SendDestinationCallbackAsync : ISessionCallbackAsync - { - private readonly string destinationName; - private IDestination destination; - private readonly NmsTemplateAsync jmsTemplate; - private readonly IMessageCreator messageCreator; - private readonly MessageCreatorDelegate messageCreatorDelegate; - - public SendDestinationCallbackAsync(NmsTemplateAsync jmsTemplate, string destinationName, IMessageCreator messageCreator) - { - this.jmsTemplate = jmsTemplate; - this.destinationName = destinationName; - this.messageCreator = messageCreator; - } - - public SendDestinationCallbackAsync(NmsTemplateAsync jmsTemplate, IDestination destination, IMessageCreator messageCreator) - { - this.jmsTemplate = jmsTemplate; - this.destination = destination; - this.messageCreator = messageCreator; - } - - public SendDestinationCallbackAsync(NmsTemplateAsync jmsTemplate, string destinationName, MessageCreatorDelegate messageCreatorDelegate) - { - this.jmsTemplate = jmsTemplate; - this.destinationName = destinationName; - this.messageCreatorDelegate = messageCreatorDelegate; - } - - public SendDestinationCallbackAsync(NmsTemplateAsync jmsTemplate, IDestination destination, MessageCreatorDelegate messageCreatorDelegate) - { - this.jmsTemplate = jmsTemplate; - this.destination = destination; - this.messageCreatorDelegate = messageCreatorDelegate; - } - - - public async Task DoInNms(ISession session) - { - if (destination == null) + IMessage msg = jmsTemplate.MessageConverter.ToMessage(objectToConvert, session); + if (messagePostProcessor != null) { - destination =await jmsTemplate.ResolveDestinationName(session, destinationName).Awaiter(); - } - if (messageCreator != null) - { - await jmsTemplate.DoSend(session, destination, messageCreator).Awaiter(); + return messagePostProcessor.PostProcessMessage(msg); } else { - await jmsTemplate.DoSend(session, destination, messageCreatorDelegate).Awaiter(); + return messagePostProcessorDelegate(msg); } - return null; + } + } + + private class ReceiveSelectedCallbackAsync : ISessionCallbackAsync + { + private readonly NmsTemplateAsync jmsTemplate; + private readonly string messageSelector; + private readonly string destinationName; + private readonly IDestination destination; + + public ReceiveSelectedCallbackAsync(NmsTemplateAsync jmsTemplate, + IDestination destination, + string messageSelector) + { + this.jmsTemplate = jmsTemplate; + this.destination = destination; + this.messageSelector = messageSelector; + } + + public ReceiveSelectedCallbackAsync(NmsTemplateAsync jmsTemplate, + string destinationName, + string messageSelector) + { + this.jmsTemplate = jmsTemplate; + this.destinationName = destinationName; + this.messageSelector = messageSelector; + } + + public async Task DoInNms(ISession session) + { + if (destination != null) + { + return await jmsTemplate.DoReceive(session, destination, messageSelector).Awaiter(); + } + else + { + return await jmsTemplate.DoReceive(session, await + jmsTemplate.ResolveDestinationName(session, destinationName).Awaiter(), + messageSelector).Awaiter(); + } + } + } + + #endregion + + private class ExecuteSessionCallbackUsingDelegateAsync : ISessionCallbackAsync + { + private readonly SessionDelegateAsync del; + + public ExecuteSessionCallbackUsingDelegateAsync(SessionDelegateAsync del) + { + this.del = del; + } + + public Task DoInNms(ISession session) + { + return del(session); } } } + +internal class SimpleMessageCreatorAsync : IMessageCreator +{ + private readonly NmsTemplateAsync jmsTemplate; + private readonly object objectToConvert; + + public SimpleMessageCreatorAsync(NmsTemplateAsync jmsTemplate, object objectToConvert) + { + this.jmsTemplate = jmsTemplate; + this.objectToConvert = objectToConvert; + } + + public IMessage CreateMessage(ISession session) + { + return jmsTemplate.MessageConverter.ToMessage(objectToConvert, session); + } +} + +internal class SendDestinationCallbackAsync : ISessionCallbackAsync +{ + private readonly string destinationName; + private IDestination destination; + private readonly NmsTemplateAsync jmsTemplate; + private readonly IMessageCreator messageCreator; + private readonly MessageCreatorDelegate messageCreatorDelegate; + + public SendDestinationCallbackAsync(NmsTemplateAsync jmsTemplate, string destinationName, IMessageCreator messageCreator) + { + this.jmsTemplate = jmsTemplate; + this.destinationName = destinationName; + this.messageCreator = messageCreator; + } + + public SendDestinationCallbackAsync(NmsTemplateAsync jmsTemplate, IDestination destination, IMessageCreator messageCreator) + { + this.jmsTemplate = jmsTemplate; + this.destination = destination; + this.messageCreator = messageCreator; + } + + public SendDestinationCallbackAsync(NmsTemplateAsync jmsTemplate, string destinationName, MessageCreatorDelegate messageCreatorDelegate) + { + this.jmsTemplate = jmsTemplate; + this.destinationName = destinationName; + this.messageCreatorDelegate = messageCreatorDelegate; + } + + public SendDestinationCallbackAsync(NmsTemplateAsync jmsTemplate, IDestination destination, MessageCreatorDelegate messageCreatorDelegate) + { + this.jmsTemplate = jmsTemplate; + this.destination = destination; + this.messageCreatorDelegate = messageCreatorDelegate; + } + + public async Task DoInNms(ISession session) + { + if (destination == null) + { + destination = await jmsTemplate.ResolveDestinationName(session, destinationName).Awaiter(); + } + + if (messageCreator != null) + { + await jmsTemplate.DoSend(session, destination, messageCreator).Awaiter(); + } + else + { + await jmsTemplate.DoSend(session, destination, messageCreatorDelegate).Awaiter(); + } + + return null; + } +} diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/NmsTrace.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/NmsTrace.cs index 8d7ad9b2..0b0bfb12 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/NmsTrace.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/NmsTrace.cs @@ -21,140 +21,137 @@ using Apache.NMS; using Microsoft.Extensions.Logging; -namespace Spring.Messaging.Nms.Core +namespace Spring.Messaging.Nms.Core; + +/// +/// Implemention of NMS ITrace interface that will log NMS messages to Common.Logging. +/// +/// Registering of this class is done by default in NmsTemplate and SimpleMessageListenerContainer if the value +/// of Apache.NMS.Tracer.Trace is null, indicating it was not set. +/// +/// Mark Pollack +public class NmsTrace : ITrace { + #region Logging Definition + + private readonly ILogger log; + + #endregion + /// - /// Implemention of NMS ITrace interface that will log NMS messages to Common.Logging. + /// Initializes a new instance of the class. The log name used is typeof(NmsTrace). /// - /// Registering of this class is done by default in NmsTemplate and SimpleMessageListenerContainer if the value - /// of Apache.NMS.Tracer.Trace is null, indicating it was not set. - /// - /// Mark Pollack - public class NmsTrace : ITrace + public NmsTrace() { - #region Logging Definition - - private readonly ILogger log; - - #endregion - - /// - /// Initializes a new instance of the class. The log name used is typeof(NmsTrace). - /// - public NmsTrace() - { - log = LogManager.GetLogger(typeof(NmsTrace)); - } - - - /// - /// Initializes a new instance of the class. - /// - /// The log instance to use for logging. - public NmsTrace(ILogger log) - { - this.log = log; - } - - /// - /// Logs message at Debug Level. - /// - /// The message. - public void Debug(string message) - { - log.LogDebug(message); - } - - /// - /// Logs message at Info Level. - /// - /// The message. - public void Info(string message) - { - log.LogInformation(message); - } - - /// - /// Logs message at Warn Level. - /// - /// The message. - public void Warn(string message) - { - log.LogWarning(message); - } - - /// - /// Logs message at Error Level. - /// - /// The message. - public void Error(string message) - { - log.LogError(message); - } - - /// - /// Logs message at Fatal Level. - /// - /// The message. - public void Fatal(string message) - { - log.LogCritical(message); - } - - /// - /// Gets a value indicating whether the debug log level is enabled. - /// - /// - /// true if this instance is debug enabled; otherwise, false. - /// - public bool IsDebugEnabled - { - get { return log.IsEnabled(LogLevel.Debug); } - } - - /// - /// Gets a value indicating whether the info log level is enabled. - /// - /// - /// true if this instance is info enabled; otherwise, false. - /// - public bool IsInfoEnabled - { - get { return log.IsEnabled(LogLevel.Information); } - } - - /// - /// Gets a value indicating whether the warn log level is enabled. - /// - /// - /// true if this instance is warn enabled; otherwise, false. - /// - public bool IsWarnEnabled - { - get { return log.IsEnabled(LogLevel.Warning); } - } - - /// - /// Gets a value indicating whether the error log level is enabled. - /// - /// - /// true if this instance is error enabled; otherwise, false. - /// - public bool IsErrorEnabled - { - get { return log.IsEnabled(LogLevel.Error); } - } - - /// - /// Gets a value indicating whether the fatal log level is enabled. - /// - /// - /// true if this instance is fatal enabled; otherwise, false. - /// - public bool IsFatalEnabled - { - get { return log.IsEnabled(LogLevel.Critical); } - } + log = LogManager.GetLogger(typeof(NmsTrace)); } + /// + /// Initializes a new instance of the class. + /// + /// The log instance to use for logging. + public NmsTrace(ILogger log) + { + this.log = log; + } + + /// + /// Logs message at Debug Level. + /// + /// The message. + public void Debug(string message) + { + log.LogDebug(message); + } + + /// + /// Logs message at Info Level. + /// + /// The message. + public void Info(string message) + { + log.LogInformation(message); + } + + /// + /// Logs message at Warn Level. + /// + /// The message. + public void Warn(string message) + { + log.LogWarning(message); + } + + /// + /// Logs message at Error Level. + /// + /// The message. + public void Error(string message) + { + log.LogError(message); + } + + /// + /// Logs message at Fatal Level. + /// + /// The message. + public void Fatal(string message) + { + log.LogCritical(message); + } + + /// + /// Gets a value indicating whether the debug log level is enabled. + /// + /// + /// true if this instance is debug enabled; otherwise, false. + /// + public bool IsDebugEnabled + { + get { return log.IsEnabled(LogLevel.Debug); } + } + + /// + /// Gets a value indicating whether the info log level is enabled. + /// + /// + /// true if this instance is info enabled; otherwise, false. + /// + public bool IsInfoEnabled + { + get { return log.IsEnabled(LogLevel.Information); } + } + + /// + /// Gets a value indicating whether the warn log level is enabled. + /// + /// + /// true if this instance is warn enabled; otherwise, false. + /// + public bool IsWarnEnabled + { + get { return log.IsEnabled(LogLevel.Warning); } + } + + /// + /// Gets a value indicating whether the error log level is enabled. + /// + /// + /// true if this instance is error enabled; otherwise, false. + /// + public bool IsErrorEnabled + { + get { return log.IsEnabled(LogLevel.Error); } + } + + /// + /// Gets a value indicating whether the fatal log level is enabled. + /// + /// + /// true if this instance is fatal enabled; otherwise, false. + /// + public bool IsFatalEnabled + { + get { return log.IsEnabled(LogLevel.Critical); } + } } diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/ProducerDelegate.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/ProducerDelegate.cs index 0f0d88d4..b4c3ac14 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/ProducerDelegate.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/ProducerDelegate.cs @@ -1,5 +1,3 @@ - - #region License /* @@ -22,17 +20,15 @@ using Apache.NMS; -namespace Spring.Messaging.Nms.Core -{ - /// Perform operations on the given Session and MessageProducer. - /// The message producer is not associated with any destination. - /// - /// the NMS Session object to use - /// - /// the NMS MessageProducer object to use - /// - /// a result object from working with the Session, if any (can be null) - /// - public delegate object ProducerDelegate(ISession session, IMessageProducer producer); +namespace Spring.Messaging.Nms.Core; -} \ No newline at end of file +/// Perform operations on the given Session and MessageProducer. +/// The message producer is not associated with any destination. +/// +/// the NMS Session object to use +/// +/// the NMS MessageProducer object to use +/// +/// a result object from working with the Session, if any (can be null) +/// +public delegate object ProducerDelegate(ISession session, IMessageProducer producer); diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/SessionDelegate.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/SessionDelegate.cs index 7f7e371a..782d3e90 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/SessionDelegate.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Core/SessionDelegate.cs @@ -2,13 +2,13 @@ /* * Copyright © 2002-2011 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. @@ -20,23 +20,22 @@ using Apache.NMS; -namespace Spring.Messaging.Nms.Core -{ - /// - /// Callback delegate for code that operates on a Session. - /// - /// The NMS ISession object. - /// - /// Allows you to execute any number of operations - /// on a single ISession, possibly returning a result a result. - /// - /// - /// A result object from working with the Session, if any (so can be null) - /// - /// NMSException if there is any problem - /// Mark Pollack - public delegate object SessionDelegate(ISession session); - - // async version - public delegate Task SessionDelegateAsync(ISession session); -} +namespace Spring.Messaging.Nms.Core; + +/// +/// Callback delegate for code that operates on a Session. +/// +/// The NMS ISession object. +/// +/// Allows you to execute any number of operations +/// on a single ISession, possibly returning a result a result. +/// +/// +/// A result object from working with the Session, if any (so can be null) +/// +/// NMSException if there is any problem +/// Mark Pollack +public delegate object SessionDelegate(ISession session); + +// async version +public delegate Task SessionDelegateAsync(ISession session); diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Listener/AbstractListenerContainer.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Listener/AbstractListenerContainer.cs index ce15f5fd..ecb94365 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Listener/AbstractListenerContainer.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Listener/AbstractListenerContainer.cs @@ -27,547 +27,545 @@ using Spring.Messaging.Nms.Support; using Spring.Messaging.Nms.Support.Destinations; using Spring.Objects.Factory; -namespace Spring.Messaging.Nms.Listener +namespace Spring.Messaging.Nms.Listener; + +/// +/// Common base class for all containers which need to implement listening +/// based on a Connection (either shared or freshly obtained for each attempt). +/// Inherits basic Connection and Session configuration handling from the +/// base class. +/// +/// +/// +/// This class provides basic lifecycle management, in particular management +/// of a shared Connection. Subclasses are supposed to plug into this +/// lifecycle, implementing the as well as +/// +/// +/// Juergen Hoeller +/// Mark Pollack(.NET) +public abstract class AbstractListenerContainer : NmsDestinationAccessor, ILifecycle, IObjectNameAware, IDisposable { + #region Logging + + private readonly ILogger logger = LogManager.GetLogger(); + + #endregion + + #region Fields + + private String clientId; + + private bool autoStartup = true; + + private string objectName; + + private IConnection sharedConnection; + + private bool sharedConnectionStarted = false; + /// - /// Common base class for all containers which need to implement listening - /// based on a Connection (either shared or freshly obtained for each attempt). - /// Inherits basic Connection and Session configuration handling from the - /// base class. + /// The monitor object to lock on when performing operations on the connection. + /// + protected object sharedConnectionMonitor = new object(); + + private volatile bool active = false; + + private bool running = false; + + /// + /// The monitor object to lock on when performing operations that update the lifecycle of the container. + /// + protected object lifecycleMonitor = new object(); + + #endregion + + /// + /// Gets or sets the client id for a shared Connection created and used by this container. + /// + /// + /// Note that client ids need to be unique among all active Connections + /// of the underlying JMS provider. Furthermore, a client id can only be + /// assigned if the original ConnectionFactory hasn't already assigned one. + /// + /// The client id. + public string ClientId + { + set { clientId = value; } + get { return clientId; } + } + + /// Set whether to automatically start the listener after initialization. + ///

Default is "true"; set this to "false" to allow for manual startup.

+ ///
+ public virtual bool AutoStartup + { + set { this.autoStartup = value; } + } + + /// + /// Set the name of the object in the object factory that created this object. + /// + /// The name of the object in the factory. + /// + ///

+ /// Invoked after population of normal object properties but before an init + /// callback like 's + /// + /// method or a custom init-method. + ///

+ ///
+ public string ObjectName + { + set { objectName = value; } + } + + /// + /// Gets a value indicating whether this container is currently running, + /// that is, whether it has been started and not stopped yet. + /// + /// + /// true if this container is running; otherwise, false. + /// + public bool IsRunning + { + get + { + lock (lifecycleMonitor) + { + return (running && RunningAllowed); + } + } + } + + /// + /// Gets a value indicating whether this container's listeners are generally allowed to run. /// /// /// - /// This class provides basic lifecycle management, in particular management - /// of a shared Connection. Subclasses are supposed to plug into this - /// lifecycle, implementing the as well as + /// >This implementation always returns true; the default 'running' + /// state is purely determined by /. + /// + /// + /// Subclasses may override this method to check against temporary + /// conditions that prevent listeners from actually running. In other words, + /// they may apply further restrictions to the 'running' state, returning + /// false if such a restriction prevents listeners from running. /// /// - /// Juergen Hoeller - /// Mark Pollack(.NET) - public abstract class AbstractListenerContainer : NmsDestinationAccessor, ILifecycle, IObjectNameAware, IDisposable + /// true if running allowed; otherwise, false. + protected virtual bool RunningAllowed { - #region Logging - - private readonly ILogger logger = LogManager.GetLogger(); - - #endregion - - #region Fields - - private String clientId; - - private bool autoStartup = true; - - private string objectName; - - private IConnection sharedConnection; - - private bool sharedConnectionStarted = false; - - /// - /// The monitor object to lock on when performing operations on the connection. - /// - protected object sharedConnectionMonitor = new object(); - - private volatile bool active = false; - - private bool running = false; - - /// - /// The monitor object to lock on when performing operations that update the lifecycle of the container. - /// - protected object lifecycleMonitor = new object(); - - #endregion - - /// - /// Gets or sets the client id for a shared Connection created and used by this container. - /// - /// - /// Note that client ids need to be unique among all active Connections - /// of the underlying JMS provider. Furthermore, a client id can only be - /// assigned if the original ConnectionFactory hasn't already assigned one. - /// - /// The client id. - public string ClientId + get { - set { clientId = value; } - get { return clientId; } + return true; } - - /// Set whether to automatically start the listener after initialization. - ///

Default is "true"; set this to "false" to allow for manual startup.

- ///
- public virtual bool AutoStartup - { - set { this.autoStartup = value; } - } - - /// - /// Set the name of the object in the object factory that created this object. - /// - /// The name of the object in the factory. - /// - ///

- /// Invoked after population of normal object properties but before an init - /// callback like 's - /// - /// method or a custom init-method. - ///

- ///
- public string ObjectName - { - set { objectName = value; } - } - - /// - /// Gets a value indicating whether this container is currently running, - /// that is, whether it has been started and not stopped yet. - /// - /// - /// true if this container is running; otherwise, false. - /// - public bool IsRunning - { - get - { - lock (lifecycleMonitor) - { - return (running && RunningAllowed); - } - } - } - - /// - /// Gets a value indicating whether this container's listeners are generally allowed to run. - /// - /// - /// - /// >This implementation always returns true; the default 'running' - /// state is purely determined by /. - /// - /// - /// Subclasses may override this method to check against temporary - /// conditions that prevent listeners from actually running. In other words, - /// they may apply further restrictions to the 'running' state, returning - /// false if such a restriction prevents listeners from running. - /// - /// - /// true if running allowed; otherwise, false. - protected virtual bool RunningAllowed - { - get { - return true; } - } - - /// - /// Gets a value indicating whether this container is currently active, - /// that is, whether it has been set up but not shut down yet. - /// - /// true if active; otherwise, false. - public virtual bool Active - { - get - { - lock (this.lifecycleMonitor) - { - return this.active; - } - } - - } - - /// Return whether a shared NMS Connection should be maintained - /// by this listener container base class. - /// - /// - protected abstract bool SharedConnectionEnabled { get; } - - /// - /// Gets the shared connection maintained by this container. - /// Available after initialization. - /// - /// The shared connection (never null) - /// if this container does not maintain a - /// shared Connection, or if the Connection hasn't been initialized yet. - /// - /// - protected IConnection SharedConnection - { - get - { - if (!SharedConnectionEnabled) - { - throw new InvalidOperationException("This listener container does not maintain a shared IConnection"); - } - lock (this.sharedConnectionMonitor) - { - if (this.sharedConnection == null) - { - throw new SharedConnectionNotInitializedException("This listener container's shared Connection has not been initialized yet"); - } - return this.sharedConnection; - } - } - } - - /// - /// Call base class method, then and then - /// - public override void AfterPropertiesSet() - { - base.AfterPropertiesSet(); - ValidateConfiguration(); - Initialize(); - } - - /// - /// Validates the configuration of this container. The default implementation - /// is empty. To be overriden in subclasses. - /// - protected virtual void ValidateConfiguration() - { - - } - - /// - /// Calls when the application context destroys the container instance. - /// - public void Dispose() - { - Shutdown(); - } - - - /// - /// Initializes this container. Creates a Connection, starts the Connection - /// (if the property hasn't been turned off), and calls - /// . - /// - /// If startup failed - public virtual void Initialize() - { - try - { - lock (this.lifecycleMonitor) - { - this.active = true; - System.Threading.Monitor.PulseAll(this.lifecycleMonitor); - } - - if (this.autoStartup) - { - DoStart(); - } - - DoInitialize(); - - } - catch (Exception) - { - lock (this.sharedConnectionMonitor) - { - ConnectionFactoryUtils.ReleaseConnection(sharedConnection, ConnectionFactory, autoStartup); - } - throw; - } - } - - /// - /// Stop the shared connection, call , and close this container. - /// - public virtual void Shutdown() - { - logger.LogDebug("Shutting down message listener container"); - bool wasRunning = false; - lock (this.lifecycleMonitor) - { - wasRunning = this.running; - this.running = false; - this.active = false; - System.Threading.Monitor.PulseAll(this.lifecycleMonitor); - } - - if (wasRunning && SharedConnectionEnabled) - { - try - { - StopSharedConnection(); - } catch (Exception ex) - { - logger.LogDebug(ex, "Could not stop NMS Connection on shutdown"); - } - } - - // Shut down the invokers - try - { - DoShutdown(); - } - finally - { - lock (this.sharedConnectionMonitor) - { - ConnectionFactoryUtils.ReleaseConnection(this.sharedConnection, ConnectionFactory, false); - } - } - } - - /// - /// Starts this container. - /// - /// if starting failed. - public void Start() - { - DoStart(); - } - - /// - /// Start the shared Connection, if any, and notify all invoker tasks. - /// - protected virtual void DoStart() - { - // Lazily establish a shared Connection, if necessary. - if (SharedConnectionEnabled) - { - EstablishSharedConnection(); - } - - lock (this.lifecycleMonitor) - { - running = true; - System.Threading.Monitor.PulseAll(this.lifecycleMonitor); - } - - // Start the shared Connection, if any. - if (SharedConnectionEnabled) - { - StartSharedConnection(); - } - } - - /// - /// Stops this container. - /// - /// if stopping failed. - public void Stop() - { - DoStop(); - } - - /// - /// Notify all invoker tasks and stop the shared Connection, if any. - /// - /// if thrown by NMS API methods. - /// - protected virtual void DoStop() - { - lock (this.lifecycleMonitor) - { - this.running = false; - System.Threading.Monitor.PulseAll(this.lifecycleMonitor); - } - - if (SharedConnectionEnabled) - { - StopSharedConnection(); - } - } - - /// - /// Register any invokers within this container. - /// Subclasses need to implement this method for their specific - /// invoker management process. A shared Connection, if any, will already have been - /// started at this point. - /// - protected abstract void DoInitialize(); - - - /// - /// Close the registered invokers. Subclasses need to implement this method - /// for their specific invoker management process. A shared Connection, if any, - /// will automatically be closed afterwards. - /// - protected abstract void DoShutdown(); - - - /// - /// Establishes a shared Connection for this container. - /// - /// - /// - /// The default implementation delegates to - /// which does one immediate attempt and throws an exception if it fails. - /// Can be overridden to have a recovery process in place, retrying - /// until a Connection can be successfully established. - /// - /// - /// If thrown by NMS API methods - protected virtual void EstablishSharedConnection() - { - lock (sharedConnectionMonitor) - { - if (sharedConnection == null) - { - sharedConnection = CreateSharedConnection(); - logger.LogDebug("Established shared NMS Connection"); - } - } - } - - /// - /// Refreshes the shared connection that this container holds. - /// - /// - /// Called on startup and also after an infrastructure exception - /// that occurred during invoker setup and/or execution. - /// - /// If thrown by NMS API methods - protected void RefreshSharedConnection() - { - lock (sharedConnectionMonitor) - { - ConnectionFactoryUtils.ReleaseConnection(sharedConnection, ConnectionFactory, sharedConnectionStarted); - sharedConnection = CreateSharedConnection(); - if (sharedConnectionStarted) - { - sharedConnection.Start(); - } - } - } - - /// - /// Creates the shared connection for this container. - /// - /// - /// The default implementation creates a standard Connection - /// and prepares it through - /// - /// the prepared Connection - /// if the creation failed. - protected virtual IConnection CreateSharedConnection() - { - IConnection con = CreateConnection(); - try - { - PrepareSharedConnection(con); - return con; - } catch (Exception) - { - NmsUtils.CloseConnection(con); - throw; - } - } - - /// - /// Prepares the given connection, which is about to be registered - /// as shared Connection for this container. - /// - /// - /// The default implementation sets the specified client id, if any. - /// Subclasses can override this to apply further settings. - /// - /// The connection to prepare. - /// If the preparation efforts failed. - protected virtual void PrepareSharedConnection(IConnection connection) - { - if (ClientId != null) - { - connection.ClientId = ClientId; - } - } - - - /// - /// Starts the shared connection. - /// - /// If thrown by NMS API methods - /// - protected virtual void StartSharedConnection() - { - lock (sharedConnectionMonitor) - { - if (sharedConnection != null) - { - try - { - sharedConnectionStarted = true; - sharedConnection.Start(); - } - catch (Exception ex) - { - logger.LogWarning(ex, "Ignoring Connection start exception - assuming already started"); - } - } - } - } - - /// - /// Stops the shared connection. - /// - /// if thrown by NMS API methods. - protected virtual void StopSharedConnection() - { - lock (this.sharedConnectionMonitor) - { - if (this.sharedConnection != null) - { - try - { - this.sharedConnectionStarted = false; - this.sharedConnection.Stop(); - } - catch (System.InvalidOperationException ex) - { - logger.LogWarning(ex, "Ignoring Connection stop exception - assuming already stopped"); - } - } - } - } - } /// - /// Exception that indicates that the initial setup of this container's - /// shared Connection failed. This is indicating to invokers that they need - /// to establish the shared Connection themselves on first access. + /// Gets a value indicating whether this container is currently active, + /// that is, whether it has been set up but not shut down yet. /// - [Serializable] - public class SharedConnectionNotInitializedException : NMSException + /// true if active; otherwise, false. + public virtual bool Active { - /// - /// Initializes a new instance of the class. - /// - public SharedConnectionNotInitializedException() + get { + lock (this.lifecycleMonitor) + { + return this.active; + } + } + } + + /// Return whether a shared NMS Connection should be maintained + /// by this listener container base class. + /// + /// + protected abstract bool SharedConnectionEnabled { get; } + + /// + /// Gets the shared connection maintained by this container. + /// Available after initialization. + /// + /// The shared connection (never null) + /// if this container does not maintain a + /// shared Connection, or if the Connection hasn't been initialized yet. + /// + /// + protected IConnection SharedConnection + { + get + { + if (!SharedConnectionEnabled) + { + throw new InvalidOperationException("This listener container does not maintain a shared IConnection"); + } + + lock (this.sharedConnectionMonitor) + { + if (this.sharedConnection == null) + { + throw new SharedConnectionNotInitializedException("This listener container's shared Connection has not been initialized yet"); + } + + return this.sharedConnection; + } + } + } + + /// + /// Call base class method, then and then + /// + public override void AfterPropertiesSet() + { + base.AfterPropertiesSet(); + ValidateConfiguration(); + Initialize(); + } + + /// + /// Validates the configuration of this container. The default implementation + /// is empty. To be overriden in subclasses. + /// + protected virtual void ValidateConfiguration() + { + } + + /// + /// Calls when the application context destroys the container instance. + /// + public void Dispose() + { + Shutdown(); + } + + /// + /// Initializes this container. Creates a Connection, starts the Connection + /// (if the property hasn't been turned off), and calls + /// . + /// + /// If startup failed + public virtual void Initialize() + { + try + { + lock (this.lifecycleMonitor) + { + this.active = true; + System.Threading.Monitor.PulseAll(this.lifecycleMonitor); + } + + if (this.autoStartup) + { + DoStart(); + } + + DoInitialize(); + } + catch (Exception) + { + lock (this.sharedConnectionMonitor) + { + ConnectionFactoryUtils.ReleaseConnection(sharedConnection, ConnectionFactory, autoStartup); + } + + throw; + } + } + + /// + /// Stop the shared connection, call , and close this container. + /// + public virtual void Shutdown() + { + logger.LogDebug("Shutting down message listener container"); + bool wasRunning = false; + lock (this.lifecycleMonitor) + { + wasRunning = this.running; + this.running = false; + this.active = false; + System.Threading.Monitor.PulseAll(this.lifecycleMonitor); } - /// - /// Initializes a new instance of the class. - /// - /// The message. - public SharedConnectionNotInitializedException(string message) : base(message) + if (wasRunning && SharedConnectionEnabled) { + try + { + StopSharedConnection(); + } + catch (Exception ex) + { + logger.LogDebug(ex, "Could not stop NMS Connection on shutdown"); + } } - /// - /// Initializes a new instance of the class, with the specified message - /// and root cause exception - /// - /// The message. - /// The inner exception. - public SharedConnectionNotInitializedException(string message, Exception innerException) - : base(message, innerException) + // Shut down the invokers + try { + DoShutdown(); + } + finally + { + lock (this.sharedConnectionMonitor) + { + ConnectionFactoryUtils.ReleaseConnection(this.sharedConnection, ConnectionFactory, false); + } + } + } + + /// + /// Starts this container. + /// + /// if starting failed. + public void Start() + { + DoStart(); + } + + /// + /// Start the shared Connection, if any, and notify all invoker tasks. + /// + protected virtual void DoStart() + { + // Lazily establish a shared Connection, if necessary. + if (SharedConnectionEnabled) + { + EstablishSharedConnection(); } - /// - /// Initializes a new instance of the class. - /// - /// The SerializationInfo that holds the serialized object data about the exception being thrown. - /// The StreamingContext that contains contextual information about the source or destination. - protected SharedConnectionNotInitializedException(SerializationInfo info, StreamingContext context) : base(info, context) + lock (this.lifecycleMonitor) { + running = true; + System.Threading.Monitor.PulseAll(this.lifecycleMonitor); + } + + // Start the shared Connection, if any. + if (SharedConnectionEnabled) + { + StartSharedConnection(); + } + } + + /// + /// Stops this container. + /// + /// if stopping failed. + public void Stop() + { + DoStop(); + } + + /// + /// Notify all invoker tasks and stop the shared Connection, if any. + /// + /// if thrown by NMS API methods. + /// + protected virtual void DoStop() + { + lock (this.lifecycleMonitor) + { + this.running = false; + System.Threading.Monitor.PulseAll(this.lifecycleMonitor); + } + + if (SharedConnectionEnabled) + { + StopSharedConnection(); + } + } + + /// + /// Register any invokers within this container. + /// Subclasses need to implement this method for their specific + /// invoker management process. A shared Connection, if any, will already have been + /// started at this point. + /// + protected abstract void DoInitialize(); + + /// + /// Close the registered invokers. Subclasses need to implement this method + /// for their specific invoker management process. A shared Connection, if any, + /// will automatically be closed afterwards. + /// + protected abstract void DoShutdown(); + + /// + /// Establishes a shared Connection for this container. + /// + /// + /// + /// The default implementation delegates to + /// which does one immediate attempt and throws an exception if it fails. + /// Can be overridden to have a recovery process in place, retrying + /// until a Connection can be successfully established. + /// + /// + /// If thrown by NMS API methods + protected virtual void EstablishSharedConnection() + { + lock (sharedConnectionMonitor) + { + if (sharedConnection == null) + { + sharedConnection = CreateSharedConnection(); + logger.LogDebug("Established shared NMS Connection"); + } + } + } + + /// + /// Refreshes the shared connection that this container holds. + /// + /// + /// Called on startup and also after an infrastructure exception + /// that occurred during invoker setup and/or execution. + /// + /// If thrown by NMS API methods + protected void RefreshSharedConnection() + { + lock (sharedConnectionMonitor) + { + ConnectionFactoryUtils.ReleaseConnection(sharedConnection, ConnectionFactory, sharedConnectionStarted); + sharedConnection = CreateSharedConnection(); + if (sharedConnectionStarted) + { + sharedConnection.Start(); + } + } + } + + /// + /// Creates the shared connection for this container. + /// + /// + /// The default implementation creates a standard Connection + /// and prepares it through + /// + /// the prepared Connection + /// if the creation failed. + protected virtual IConnection CreateSharedConnection() + { + IConnection con = CreateConnection(); + try + { + PrepareSharedConnection(con); + return con; + } + catch (Exception) + { + NmsUtils.CloseConnection(con); + throw; + } + } + + /// + /// Prepares the given connection, which is about to be registered + /// as shared Connection for this container. + /// + /// + /// The default implementation sets the specified client id, if any. + /// Subclasses can override this to apply further settings. + /// + /// The connection to prepare. + /// If the preparation efforts failed. + protected virtual void PrepareSharedConnection(IConnection connection) + { + if (ClientId != null) + { + connection.ClientId = ClientId; + } + } + + /// + /// Starts the shared connection. + /// + /// If thrown by NMS API methods + /// + protected virtual void StartSharedConnection() + { + lock (sharedConnectionMonitor) + { + if (sharedConnection != null) + { + try + { + sharedConnectionStarted = true; + sharedConnection.Start(); + } + catch (Exception ex) + { + logger.LogWarning(ex, "Ignoring Connection start exception - assuming already started"); + } + } + } + } + + /// + /// Stops the shared connection. + /// + /// if thrown by NMS API methods. + protected virtual void StopSharedConnection() + { + lock (this.sharedConnectionMonitor) + { + if (this.sharedConnection != null) + { + try + { + this.sharedConnectionStarted = false; + this.sharedConnection.Stop(); + } + catch (System.InvalidOperationException ex) + { + logger.LogWarning(ex, "Ignoring Connection stop exception - assuming already stopped"); + } + } } } } + +/// +/// Exception that indicates that the initial setup of this container's +/// shared Connection failed. This is indicating to invokers that they need +/// to establish the shared Connection themselves on first access. +/// +[Serializable] +public class SharedConnectionNotInitializedException : NMSException +{ + /// + /// Initializes a new instance of the class. + /// + public SharedConnectionNotInitializedException() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The message. + public SharedConnectionNotInitializedException(string message) : base(message) + { + } + + /// + /// Initializes a new instance of the class, with the specified message + /// and root cause exception + /// + /// The message. + /// The inner exception. + public SharedConnectionNotInitializedException(string message, Exception innerException) + : base(message, innerException) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The SerializationInfo that holds the serialized object data about the exception being thrown. + /// The StreamingContext that contains contextual information about the source or destination. + protected SharedConnectionNotInitializedException(SerializationInfo info, StreamingContext context) : base(info, context) + { + } +} diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Listener/AbstractMessageListenerContainer.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Listener/AbstractMessageListenerContainer.cs index 484622c4..831ee5e2 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Listener/AbstractMessageListenerContainer.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Listener/AbstractMessageListenerContainer.cs @@ -24,487 +24,506 @@ using Spring.Util; using Apache.NMS; using Microsoft.Extensions.Logging; -namespace Spring.Messaging.Nms.Listener +namespace Spring.Messaging.Nms.Listener; + +/// +/// Abstract base class for message listener containers. Can either host +/// a standard NMS MessageListener or a Spring-specific +/// +/// +public abstract class AbstractMessageListenerContainer : AbstractListenerContainer { + #region Logging + + private readonly ILogger logger = LogManager.GetLogger(); + + #endregion + + #region Fields + + private object destination; + + private String messageSelector; + + private object messageListener; + + private bool subscriptionDurable = false; + + private string durableSubscriptionName; + + private IExceptionListener exceptionListener; + + private IErrorHandler errorHandler; + + private bool exposeListenerISession = true; + + private bool acceptMessagesWhileStopping = false; + + #endregion + + #region Properties + /// - /// Abstract base class for message listener containers. Can either host - /// a standard NMS MessageListener or a Spring-specific - /// + /// Gets or sets the destination to receive messages from. Will be null + /// if the configured destination is not an actual Destination type; + /// c.f. when the destination is a String. /// - public abstract class AbstractMessageListenerContainer : AbstractListenerContainer + /// The destination. + public IDestination Destination { - #region Logging - - private readonly ILogger logger = LogManager.GetLogger(); - - #endregion - - #region Fields - - private object destination; - - private String messageSelector; - - private object messageListener; - - private bool subscriptionDurable = false; - - private string durableSubscriptionName; - - private IExceptionListener exceptionListener; - - private IErrorHandler errorHandler; - - private bool exposeListenerISession = true; - - private bool acceptMessagesWhileStopping = false; - - #endregion - - #region Properties - - /// - /// Gets or sets the destination to receive messages from. Will be null - /// if the configured destination is not an actual Destination type; - /// c.f. when the destination is a String. - /// - /// The destination. - public IDestination Destination + get { - get + return (this.destination is IDestination ? (IDestination) this.destination : null); + } + set + { + AssertUtils.ArgumentNotNull(value, "destination"); + destination = value; + if (destination is ITopic && !(destination is IQueue)) { - return (this.destination is IDestination ? (IDestination) this.destination : null); + PubSubDomain = true; } - set + } + } + + /// + /// Gets or sets the name of the destination to receive messages from. + /// Will be null if the configured destination is not a + /// string type; c.f. when it is an actual Destination object. + /// + /// The name of the destination. + public string DestinationName + { + get + { + return (this.destination is string ? (string) this.destination : null); + } + set + { + AssertUtils.ArgumentNotNull(value, "destinationName must not be null"); + this.destination = value; + } + } + + /// + /// Gets or sets the message selector. + /// + /// The message selector expression (or null if none).. + public string MessageSelector + { + get { return messageSelector; } + set { messageSelector = value; } + } + + /// + /// Gets or sets the message listener to register. + /// + /// + /// + /// + /// This can be either a standard NMS MessageListener object or a + /// Spring object. + /// + /// + /// The message listener. + public object MessageListener + { + set + { + CheckMessageListener(value); + if (durableSubscriptionName == null) { - AssertUtils.ArgumentNotNull(value, "destination"); - destination = value; - if (destination is ITopic && !(destination is IQueue)) + // Use message listener class name as default name for a durable subscription. + durableSubscriptionName = value.GetType().FullName; + } + + messageListener = value; + } + get + { + return messageListener; + } + } + + /// + /// Gets or sets a value indicating whether the subscription is durable. + /// + /// + /// Set whether to make the subscription durable. The durable subscription name + /// to be used can be specified through the "DurableSubscriptionName" property. + /// Default is "false". Set this to "true" to register a durable subscription, + /// typically in combination with a "DurableSubscriptionName" value (unless + /// your message listener class name is good enough as subscription name). + /// + /// Only makes sense when listening to a topic (pub-sub domain). + /// + /// true if the subscription is durable; otherwise, false. + public bool SubscriptionDurable + { + get { return subscriptionDurable; } + set { subscriptionDurable = value; } + } + + public bool SubscriptionShared { get; set; } + + public string SubscriptionName { get; set; } + + /// + /// Gets or sets the name of the durable subscription to create. + /// + /// + /// To be applied in case of a topic (pub-sub domain) with subscription durability activated. + /// The durable subscription name needs to be unique within this client's + /// client id. Default is the class name of the specified message listener. + /// Note: Only 1 concurrent consumer (which is the default of this + /// message listener container) is allowed for each durable subscription. + /// + /// + /// The name of the durable subscription. + public string DurableSubscriptionName + { + get + { + return durableSubscriptionName; + } + set + { + AssertUtils.ArgumentNotNull(value, "durableSubscriptionName must not be null"); + durableSubscriptionName = value; + } + } + + /// + /// Gets or sets the exception listener to notify in case of a NMSException thrown + /// by the registered message listener or the invocation infrastructure. + /// + /// The exception listener. + public IExceptionListener ExceptionListener + { + get { return exceptionListener; } + set { exceptionListener = value; } + } + + /// + /// Sets an ErrorHandler to be invoked in case of any uncaught exceptions thrown + /// while processing a Message. By default there will be no ErrorHandler + /// so that error-level logging is the only result. + /// + /// The error handler. + public IErrorHandler ErrorHandler + { + set { errorHandler = value; } + } + + /// + /// Gets or sets a value indicating whether to expose listener session to a registered + /// as well as to calls. + /// + /// + /// Default is "true", reusing the listener's Session. + /// Turn this off to expose a fresh Session fetched from the same + /// underlying Connection instead, which might be necessary + /// on some messaging providers. + /// Note that Sessions managed by an external transaction manager will + /// always get exposed to + /// calls. So in terms of NmsTemplate exposure, this setting only affects + /// locally transacted Sessions. + /// + /// + /// + /// true if expose listener session; otherwise, false. + /// + public bool ExposeListenerSession + { + get { return exposeListenerISession; } + set { exposeListenerISession = value; } + } + + /// + /// Gets or sets a value indicating whether to accept messages while + /// the listener container is in the process of stopping. + /// + /// + /// + /// Return whether to accept received messages while the listener container + /// receive attempt. Switch this flag on to fully process such messages + /// even in the stopping phase, with the drawback that even newly sent + /// messages might still get processed (if coming in before all receive + /// timeouts have expired). + /// + /// + /// Aborting receive attempts for such incoming messages + /// might lead to the provider's retry count decreasing for the affected + /// messages. If you have a high number of concurrent consumers, make sure + /// that the number of retries is higher than the number of consumers, + /// to be on the safe side for all potential stopping scenarios. + /// + /// + /// + /// true if accept messages while in the process of stopping; otherwise, false. + /// + public bool AcceptMessagesWhileStopping + { + get { return acceptMessagesWhileStopping; } + set { acceptMessagesWhileStopping = value; } + } + + #endregion + + /// + /// Validate that the destination is not null and that if the subscription is durable, then we are not + /// using the Pub/Sub domain. + /// + protected override void ValidateConfiguration() + { + if (this.destination == null) + { + throw new ArgumentException("Property 'destination' or 'DestinationName' is required"); + } + + if (SubscriptionDurable && !PubSubDomain) + { + throw new ArgumentException("A durable subscription requires a topic (pub-sub domain)"); + } + } + + #region Template methods for listeners + + /// + /// Executes the specified listener, + /// committing or rolling back the transaction afterwards (if necessary). + /// + /// The session to operate on. + /// The received message. + /// + /// + /// + /// + public virtual void ExecuteListener(ISession session, IMessage message) + { + try + { + DoExecuteListener(session, message); + } + catch (Exception ex) + { + HandleListenerException(ex); + } + } + + /// + /// Executes the specified listener, + /// committing or rolling back the transaction afterwards (if necessary). + /// + /// The session to operate on. + /// The received message. + /// If thrown by NMS API methods. + /// + /// + /// + protected virtual void DoExecuteListener(ISession session, IMessage message) + { + if (!AcceptMessagesWhileStopping && !IsRunning) + { + #region Logging + + if (logger.IsEnabled(LogLevel.Warning)) + { + logger.LogWarning("Rejecting received message because of the listener container " + + "having been stopped in the meantime: " + message); + } + + #endregion + + RollbackIfNecessary(session); + throw new MessageRejectedWhileStoppingException(); + } + + try + { + InvokeListener(session, message); + } + catch (Exception ex) + { + RollbackOnExceptionIfNecessary(session, ex); + throw; + } + + CommitIfNecessary(session, message); + } + + /// + /// Invokes the specified listener: either as standard NMS MessageListener + /// or (preferably) as Spring SessionAwareMessageListener. + /// + /// The session to operate on. + /// The received message. + /// If thrown by NMS API methods. + /// + protected virtual void InvokeListener(ISession session, IMessage message) + { + object listener = MessageListener; + if (listener is ISessionAwareMessageListener) + { + DoInvokeListener((ISessionAwareMessageListener) listener, session, message); + } + else if (listener is IMessageListener) + { + DoInvokeListener((IMessageListener) listener, message); + } + else if (listener != null) + { + throw new ArgumentException("Only IMessageListener and ISessionAwareMessageListener supported"); + } + else + { + throw new InvalidOperationException("No message listener specified - see property MessageListener"); + } + } + + /// + /// Invoke the specified listener as Spring SessionAwareMessageListener, + /// exposing a new NMS Session (potentially with its own transaction) + /// to the listener if demanded. + /// + /// The Spring ISessionAwareMessageListener to invoke. + /// The session to operate on. + /// The received message. + /// If thrown by NMS API methods. + /// + /// + protected virtual void DoInvokeListener(ISessionAwareMessageListener listener, ISession session, IMessage message) + { + IConnection conToClose = null; + ISession sessionToClose = null; + try + { + ISession sessionToUse = session; + if (!ExposeListenerSession) + { + //We need to expose a separate Session. + conToClose = CreateConnection(); + sessionToClose = CreateSession(conToClose); + sessionToUse = sessionToClose; + } + + // Actually invoke the message listener + if (logger.IsEnabled(LogLevel.Debug)) + { + logger.LogDebug("Invoking listener with message of type [" + message.GetType() + + "] and session [" + sessionToUse + "]"); + } + + listener.OnMessage(message, sessionToUse); + // Clean up specially exposed Session, if any + if (sessionToUse != session) + { + if (sessionToUse.Transacted && SessionTransacted) { - PubSubDomain = true; - } - - } - } - - - /// - /// Gets or sets the name of the destination to receive messages from. - /// Will be null if the configured destination is not a - /// string type; c.f. when it is an actual Destination object. - /// - /// The name of the destination. - public string DestinationName - { - get - { - return (this.destination is string ? (string) this.destination : null); - - } - set - { - AssertUtils.ArgumentNotNull(value, "destinationName must not be null"); - this.destination = value; - } - } - - - /// - /// Gets or sets the message selector. - /// - /// The message selector expression (or null if none).. - public string MessageSelector - { - get { return messageSelector; } - set { messageSelector = value; } - } - - - /// - /// Gets or sets the message listener to register. - /// - /// - /// - /// - /// This can be either a standard NMS MessageListener object or a - /// Spring object. - /// - /// - /// The message listener. - public object MessageListener - { - set - { - CheckMessageListener(value); - if (durableSubscriptionName == null) - { - // Use message listener class name as default name for a durable subscription. - durableSubscriptionName = value.GetType().FullName; - } - messageListener = value; - } - get - { - return messageListener; - } - } - - - /// - /// Gets or sets a value indicating whether the subscription is durable. - /// - /// - /// Set whether to make the subscription durable. The durable subscription name - /// to be used can be specified through the "DurableSubscriptionName" property. - /// Default is "false". Set this to "true" to register a durable subscription, - /// typically in combination with a "DurableSubscriptionName" value (unless - /// your message listener class name is good enough as subscription name). - /// - /// Only makes sense when listening to a topic (pub-sub domain). - /// - /// true if the subscription is durable; otherwise, false. - public bool SubscriptionDurable - { - get { return subscriptionDurable; } - set { subscriptionDurable = value; } - } - - - public bool SubscriptionShared { get; set; } - - public string SubscriptionName { get; set; } - - - /// - /// Gets or sets the name of the durable subscription to create. - /// - /// - /// To be applied in case of a topic (pub-sub domain) with subscription durability activated. - /// The durable subscription name needs to be unique within this client's - /// client id. Default is the class name of the specified message listener. - /// Note: Only 1 concurrent consumer (which is the default of this - /// message listener container) is allowed for each durable subscription. - /// - /// - /// The name of the durable subscription. - public string DurableSubscriptionName - { - get - { - return durableSubscriptionName; - } - set - { - AssertUtils.ArgumentNotNull(value, "durableSubscriptionName must not be null"); - durableSubscriptionName = value; - } - } - - - /// - /// Gets or sets the exception listener to notify in case of a NMSException thrown - /// by the registered message listener or the invocation infrastructure. - /// - /// The exception listener. - public IExceptionListener ExceptionListener - { - get { return exceptionListener; } - set { exceptionListener = value; } - } - - /// - /// Sets an ErrorHandler to be invoked in case of any uncaught exceptions thrown - /// while processing a Message. By default there will be no ErrorHandler - /// so that error-level logging is the only result. - /// - /// The error handler. - public IErrorHandler ErrorHandler - { - set { errorHandler = value; } - } - - - /// - /// Gets or sets a value indicating whether to expose listener session to a registered - /// as well as to calls. - /// - /// - /// Default is "true", reusing the listener's Session. - /// Turn this off to expose a fresh Session fetched from the same - /// underlying Connection instead, which might be necessary - /// on some messaging providers. - /// Note that Sessions managed by an external transaction manager will - /// always get exposed to - /// calls. So in terms of NmsTemplate exposure, this setting only affects - /// locally transacted Sessions. - /// - /// - /// - /// true if expose listener session; otherwise, false. - /// - public bool ExposeListenerSession - { - get { return exposeListenerISession; } - set { exposeListenerISession = value; } - } - - - /// - /// Gets or sets a value indicating whether to accept messages while - /// the listener container is in the process of stopping. - /// - /// - /// - /// Return whether to accept received messages while the listener container - /// receive attempt. Switch this flag on to fully process such messages - /// even in the stopping phase, with the drawback that even newly sent - /// messages might still get processed (if coming in before all receive - /// timeouts have expired). - /// - /// - /// Aborting receive attempts for such incoming messages - /// might lead to the provider's retry count decreasing for the affected - /// messages. If you have a high number of concurrent consumers, make sure - /// that the number of retries is higher than the number of consumers, - /// to be on the safe side for all potential stopping scenarios. - /// - /// - /// - /// true if accept messages while in the process of stopping; otherwise, false. - /// - public bool AcceptMessagesWhileStopping - { - get { return acceptMessagesWhileStopping; } - set { acceptMessagesWhileStopping = value; } - } - - #endregion - - - - /// - /// Validate that the destination is not null and that if the subscription is durable, then we are not - /// using the Pub/Sub domain. - /// - protected override void ValidateConfiguration() - { - if (this.destination == null) - { - throw new ArgumentException("Property 'destination' or 'DestinationName' is required"); - } - if (SubscriptionDurable && !PubSubDomain) - { - throw new ArgumentException("A durable subscription requires a topic (pub-sub domain)"); - } - } - - #region Template methods for listeners - - - - /// - /// Executes the specified listener, - /// committing or rolling back the transaction afterwards (if necessary). - /// - /// The session to operate on. - /// The received message. - /// - /// - /// - /// - public virtual void ExecuteListener(ISession session, IMessage message) - { - try - { - DoExecuteListener(session, message); - } - catch (Exception ex) - { - HandleListenerException(ex); - } - } - - /// - /// Executes the specified listener, - /// committing or rolling back the transaction afterwards (if necessary). - /// - /// The session to operate on. - /// The received message. - /// If thrown by NMS API methods. - /// - /// - /// - protected virtual void DoExecuteListener(ISession session, IMessage message) - { - if (!AcceptMessagesWhileStopping && !IsRunning) - { - #region Logging - if (logger.IsEnabled(LogLevel.Warning)) - { - logger.LogWarning("Rejecting received message because of the listener container " + - "having been stopped in the meantime: " + message); - } - #endregion - RollbackIfNecessary(session); - throw new MessageRejectedWhileStoppingException(); - } - - try - { - InvokeListener(session, message); - } - catch (Exception ex) - { - RollbackOnExceptionIfNecessary(session, ex); - throw; - } - CommitIfNecessary(session, message); - } - - /// - /// Invokes the specified listener: either as standard NMS MessageListener - /// or (preferably) as Spring SessionAwareMessageListener. - /// - /// The session to operate on. - /// The received message. - /// If thrown by NMS API methods. - /// - protected virtual void InvokeListener(ISession session, IMessage message) - { - object listener = MessageListener; - if (listener is ISessionAwareMessageListener) - { - DoInvokeListener((ISessionAwareMessageListener) listener, session, message); - } - else if (listener is IMessageListener) - { - DoInvokeListener((IMessageListener) listener, message); - } - else if (listener != null) - { - throw new ArgumentException("Only IMessageListener and ISessionAwareMessageListener supported"); - } - else - { - throw new InvalidOperationException("No message listener specified - see property MessageListener"); - } - } - - /// - /// Invoke the specified listener as Spring SessionAwareMessageListener, - /// exposing a new NMS Session (potentially with its own transaction) - /// to the listener if demanded. - /// - /// The Spring ISessionAwareMessageListener to invoke. - /// The session to operate on. - /// The received message. - /// If thrown by NMS API methods. - /// - /// - protected virtual void DoInvokeListener(ISessionAwareMessageListener listener, ISession session, IMessage message) - { - IConnection conToClose = null; - ISession sessionToClose = null; - try - { - ISession sessionToUse = session; - if (!ExposeListenerSession) - { - //We need to expose a separate Session. - conToClose = CreateConnection(); - sessionToClose = CreateSession(conToClose); - sessionToUse = sessionToClose; - } - // Actually invoke the message listener - if (logger.IsEnabled(LogLevel.Debug)) - { - logger.LogDebug("Invoking listener with message of type [" + message.GetType() + - "] and session [" + sessionToUse + "]"); - } - listener.OnMessage(message, sessionToUse); - // Clean up specially exposed Session, if any - if (sessionToUse != session) - { - if (sessionToUse.Transacted && SessionTransacted) - { - // Transacted session created by this container -> commit. - NmsUtils.CommitIfNecessary(sessionToUse); - } - } - } finally - { - NmsUtils.CloseSession(sessionToClose); - NmsUtils.CloseConnection(conToClose); - } - } - - /// - /// Invoke the specified listener as standard JMS MessageListener. - /// - /// Default implementation performs a plain invocation of the - /// OnMessage methods - /// The listener to invoke. - /// The received message. - /// if thrown by the NMS API methods - protected virtual void DoInvokeListener(IMessageListener listener, IMessage message) - { - listener.OnMessage(message); - } - - /// - /// Perform a commit or message acknowledgement, as appropriate - /// - /// The session to commit. - /// The message to acknowledge. - /// In case of commit failure - protected virtual void CommitIfNecessary(ISession session, IMessage message) - { - // Commit session or acknowledge message - if (session.Transacted) - { - // Commit necessary - but avoid commit call is Session transaction is externally coordinated. - if (IsSessionLocallyTransacted(session)) - { - NmsUtils.CommitIfNecessary(session); + // Transacted session created by this container -> commit. + NmsUtils.CommitIfNecessary(sessionToUse); } } - else if (IsClientAcknowledge(session)) + } + finally + { + NmsUtils.CloseSession(sessionToClose); + NmsUtils.CloseConnection(conToClose); + } + } + + /// + /// Invoke the specified listener as standard JMS MessageListener. + /// + /// Default implementation performs a plain invocation of the + /// OnMessage methods + /// The listener to invoke. + /// The received message. + /// if thrown by the NMS API methods + protected virtual void DoInvokeListener(IMessageListener listener, IMessage message) + { + listener.OnMessage(message); + } + + /// + /// Perform a commit or message acknowledgement, as appropriate + /// + /// The session to commit. + /// The message to acknowledge. + /// In case of commit failure + protected virtual void CommitIfNecessary(ISession session, IMessage message) + { + // Commit session or acknowledge message + if (session.Transacted) + { + // Commit necessary - but avoid commit call is Session transaction is externally coordinated. + if (IsSessionLocallyTransacted(session)) { - message.Acknowledge(); + NmsUtils.CommitIfNecessary(session); } } - - /// - /// Determines whether the given Session is locally transacted, that is, whether - /// its transaction is managed by this listener container's Session handling - /// and not by an external transaction coordinator. - /// - /// - /// The Session's own transacted flag will already have been checked - /// before. This method is about finding out whether the Session's transaction - /// is local or externally coordinated. - /// - /// The session to check. - /// - /// true if the is session locally transacted; otherwise, false. - /// - /// - protected virtual bool IsSessionLocallyTransacted(ISession session) + else if (IsClientAcknowledge(session)) { - return SessionTransacted; + message.Acknowledge(); } + } + /// + /// Determines whether the given Session is locally transacted, that is, whether + /// its transaction is managed by this listener container's Session handling + /// and not by an external transaction coordinator. + /// + /// + /// The Session's own transacted flag will already have been checked + /// before. This method is about finding out whether the Session's transaction + /// is local or externally coordinated. + /// + /// The session to check. + /// + /// true if the is session locally transacted; otherwise, false. + /// + /// + protected virtual bool IsSessionLocallyTransacted(ISession session) + { + return SessionTransacted; + } - /// - /// Perform a rollback, if appropriate. - /// - /// The session to rollback. - /// In case of a rollback error - protected virtual void RollbackIfNecessary(ISession session) + /// + /// Perform a rollback, if appropriate. + /// + /// The session to rollback. + /// In case of a rollback error + protected virtual void RollbackIfNecessary(ISession session) + { + if (session.Transacted && IsSessionLocallyTransacted(session)) + { + // Transacted session created by this container -> rollback + NmsUtils.RollbackIfNecessary(session); + } + else if (IsClientAcknowledge(session)) + { + session.Recover(); + } + } + + /// + /// Perform a rollback, handling rollback excepitons properly. + /// + /// The session to rollback. + /// The thrown application exception. + /// in case of a rollback error. + protected virtual void RollbackOnExceptionIfNecessary(ISession session, Exception ex) + { + try { if (session.Transacted && IsSessionLocallyTransacted(session)) { // Transacted session created by this container -> rollback + if (logger.IsEnabled(LogLevel.Debug)) + { + logger.LogDebug("Initiating transaction rollback on application exception"); + } + NmsUtils.RollbackIfNecessary(session); } else if (IsClientAcknowledge(session)) @@ -512,129 +531,103 @@ namespace Spring.Messaging.Nms.Listener session.Recover(); } } - /// - /// Perform a rollback, handling rollback excepitons properly. - /// - /// The session to rollback. - /// The thrown application exception. - /// in case of a rollback error. - protected virtual void RollbackOnExceptionIfNecessary(ISession session, Exception ex) + catch (NMSException) { - try - { - if (session.Transacted && IsSessionLocallyTransacted(session)) - { - // Transacted session created by this container -> rollback - if (logger.IsEnabled(LogLevel.Debug)) - { - logger.LogDebug("Initiating transaction rollback on application exception"); - } - NmsUtils.RollbackIfNecessary(session); - } - else if (IsClientAcknowledge(session)) - { - session.Recover(); - } - } - catch (NMSException) - { - logger.LogError(ex, "Application exception overriden by rollback exception"); - throw; - } - } - - - /// - /// Handle the given exception that arose during listener execution. - /// - /// - /// The default implementation logs the exception at error level, - /// not propagating it to the JMS provider - assuming that all handling of - /// acknowledgement and/or transactions is done by this listener container. - /// This can be overridden in subclasses. - /// - /// The exceptin to handle - protected virtual void HandleListenerException(Exception ex) - { - if (ex is MessageRejectedWhileStoppingException) - { - // Internal exception - has been handled before. - return; - } - if (ex is NMSException) - { - InvokeExceptionListener(ex); - } - if (Active) - { - // Regular case: failed while active. - // Invoke ErrorHandler if available. - InvokeErrorHandler(ex); - } - else - { - // Rare case: listener thread failed after container shutdown. - // Log at debug level, to avoid spamming the shutdown log. - logger.LogDebug(ex, "Listener exception after container shutdown"); - } - } - - /// - /// Invokes the error handler. - /// - /// The exception. - protected virtual void InvokeErrorHandler(Exception exception) - { - if (errorHandler != null) - { - errorHandler.HandleError(exception); - } - else if(logger.IsEnabled(LogLevel.Warning)) - { - logger.LogWarning(exception, "Execution of NMS message listener failed, and no ErrorHandler has been set."); - } - } - - /// - /// Invokes the registered exception listener, if any. - /// - /// The exception that arose during NMS processing. - /// - protected virtual void InvokeExceptionListener(Exception ex) - { - IExceptionListener exListener = ExceptionListener; - if (exListener != null) - { - exListener.OnException(ex); - } - } - - - - #endregion - - /// - /// Checks the message listener, throwing an exception - /// if it does not correspond to a supported listener type. - /// By default, only a standard JMS MessageListener object or a - /// Spring object will be accepted. - /// - /// The message listener. - protected virtual void CheckMessageListener(object messageListener) - { - AssertUtils.ArgumentNotNull(messageListener, "IMessage Listener can not be null"); - if (!(messageListener is IMessageListener || messageListener is ISessionAwareMessageListener)) - { - throw new ArgumentException("messageListener needs to be of type [" + typeof(IMessageListener).FullName + "] or [" + typeof(ISessionAwareMessageListener).FullName + "]"); - } + logger.LogError(ex, "Application exception overriden by rollback exception"); + throw; } } /// - /// Internal exception class that indicates a rejected message on shutdown. - /// Used to trigger a rollback for an external transaction manager in that case. + /// Handle the given exception that arose during listener execution. /// - internal class MessageRejectedWhileStoppingException : ApplicationException + /// + /// The default implementation logs the exception at error level, + /// not propagating it to the JMS provider - assuming that all handling of + /// acknowledgement and/or transactions is done by this listener container. + /// This can be overridden in subclasses. + /// + /// The exceptin to handle + protected virtual void HandleListenerException(Exception ex) { + if (ex is MessageRejectedWhileStoppingException) + { + // Internal exception - has been handled before. + return; + } + + if (ex is NMSException) + { + InvokeExceptionListener(ex); + } + + if (Active) + { + // Regular case: failed while active. + // Invoke ErrorHandler if available. + InvokeErrorHandler(ex); + } + else + { + // Rare case: listener thread failed after container shutdown. + // Log at debug level, to avoid spamming the shutdown log. + logger.LogDebug(ex, "Listener exception after container shutdown"); + } + } + + /// + /// Invokes the error handler. + /// + /// The exception. + protected virtual void InvokeErrorHandler(Exception exception) + { + if (errorHandler != null) + { + errorHandler.HandleError(exception); + } + else if (logger.IsEnabled(LogLevel.Warning)) + { + logger.LogWarning(exception, "Execution of NMS message listener failed, and no ErrorHandler has been set."); + } + } + + /// + /// Invokes the registered exception listener, if any. + /// + /// The exception that arose during NMS processing. + /// + protected virtual void InvokeExceptionListener(Exception ex) + { + IExceptionListener exListener = ExceptionListener; + if (exListener != null) + { + exListener.OnException(ex); + } + } + + #endregion + + /// + /// Checks the message listener, throwing an exception + /// if it does not correspond to a supported listener type. + /// By default, only a standard JMS MessageListener object or a + /// Spring object will be accepted. + /// + /// The message listener. + protected virtual void CheckMessageListener(object messageListener) + { + AssertUtils.ArgumentNotNull(messageListener, "IMessage Listener can not be null"); + if (!(messageListener is IMessageListener || messageListener is ISessionAwareMessageListener)) + { + throw new ArgumentException("messageListener needs to be of type [" + typeof(IMessageListener).FullName + "] or [" + typeof(ISessionAwareMessageListener).FullName + "]"); + } } } + +/// +/// Internal exception class that indicates a rejected message on shutdown. +/// Used to trigger a rollback for an external transaction manager in that case. +/// +internal class MessageRejectedWhileStoppingException : ApplicationException +{ +} diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Listener/Adapter/ListenerExecutionFailedException.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Listener/Adapter/ListenerExecutionFailedException.cs index 3cb64c99..490ee582 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Listener/Adapter/ListenerExecutionFailedException.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Listener/Adapter/ListenerExecutionFailedException.cs @@ -21,50 +21,49 @@ using System.Runtime.Serialization; using Apache.NMS; -namespace Spring.Messaging.Nms.Listener.Adapter +namespace Spring.Messaging.Nms.Listener.Adapter; + +/// +/// Exception to be thrown when the execution of a listener method failed. +/// +/// Juergen Hoeller +/// Mark Pollack (.NET) +[Serializable] +public class ListenerExecutionFailedException : NMSException { /// - /// Exception to be thrown when the execution of a listener method failed. + /// Initializes a new instance of the class. /// - /// Juergen Hoeller - /// Mark Pollack (.NET) - [Serializable] - public class ListenerExecutionFailedException : NMSException + public ListenerExecutionFailedException() { - /// - /// Initializes a new instance of the class. - /// - public ListenerExecutionFailedException() - { - } + } - /// - /// Initializes a new instance of the class, with the specified message - /// - /// The message. - public ListenerExecutionFailedException(string message) : base(message) - { - } + /// + /// Initializes a new instance of the class, with the specified message + /// + /// The message. + public ListenerExecutionFailedException(string message) : base(message) + { + } - /// - /// Initializes a new instance of the class, with the specified message - /// and root cause exception - /// - /// The message. - /// The inner exception. - public ListenerExecutionFailedException(string message, Exception innerException) - : base(message, innerException) - { - } + /// + /// Initializes a new instance of the class, with the specified message + /// and root cause exception + /// + /// The message. + /// The inner exception. + public ListenerExecutionFailedException(string message, Exception innerException) + : base(message, innerException) + { + } - /// - /// Initializes a new instance of the class. - /// - /// The SerializationInfo that holds the serialized object data about the exception being thrown. - /// The StreamingContext that contains contextual information about the source or destination. - protected ListenerExecutionFailedException(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } + /// + /// Initializes a new instance of the class. + /// + /// The SerializationInfo that holds the serialized object data about the exception being thrown. + /// The StreamingContext that contains contextual information about the source or destination. + protected ListenerExecutionFailedException(SerializationInfo info, StreamingContext context) + : base(info, context) + { } } diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Listener/Adapter/MessageListenerAdapter.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Listener/Adapter/MessageListenerAdapter.cs index bdd2d33b..0d0f9162 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Listener/Adapter/MessageListenerAdapter.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Listener/Adapter/MessageListenerAdapter.cs @@ -28,553 +28,551 @@ using Spring.Util; using Apache.NMS; using Microsoft.Extensions.Logging; -namespace Spring.Messaging.Nms.Listener.Adapter +namespace Spring.Messaging.Nms.Listener.Adapter; + +/// +/// Message listener adapter that delegates the handling of messages to target +/// listener methods via reflection, with flexible message type conversion. +/// Allows listener methods to operate on message content types, completely +/// independent from the NMS API. +/// +/// +/// By default, the content of incoming messages gets extracted before +/// being passed into the target listener method, to let the target method +/// operate on message content types such as String or byte array instead of +/// the raw Message. Message type conversion is delegated to a Spring +/// . By default, a +/// will be used. (If you do not want such automatic message conversion taking +/// place, then be sure to set the property +/// to null.) +/// +/// If a target listener method returns a non-null object (typically of a +/// message content type such as String or byte array), it will get +/// wrapped in a NMS Message and sent to the response destination +/// (either the NMS "reply-to" destination or the +/// specified. +/// +/// +/// The sending of response messages is only available when +/// using the entry point (typically through a +/// Spring message listener container). Usage as standard NMS MessageListener +/// does not support the generation of response messages. +/// +/// Consult the reference documentation for examples of method signatures compliant with this +/// adapter class. +/// +/// +/// Juergen Hoeller +/// Mark Pollack (.NET) +public class MessageListenerAdapter : IMessageListener, ISessionAwareMessageListener { + #region Logging + + private readonly ILogger logger = LogManager.GetLogger(typeof(MessageListenerAdapter)); + + #endregion + + #region Fields + /// - /// Message listener adapter that delegates the handling of messages to target - /// listener methods via reflection, with flexible message type conversion. - /// Allows listener methods to operate on message content types, completely - /// independent from the NMS API. + /// The default handler method name. + /// + public static string ORIGINAL_DEFAULT_HANDLER_METHOD = "HandleMessage"; + + private object handlerObject; + + private string defaultHandlerMethod = ORIGINAL_DEFAULT_HANDLER_METHOD; + + private IExpression processingExpression; + + private object defaultResponseDestination; + + private IDestinationResolver destinationResolver = new DynamicDestinationResolver(); + + private IMessageConverter messageConverter; + + #endregion + + #region Constructors + + /// + /// Initializes a new instance of the class with default settings. + /// + public MessageListenerAdapter() + { + InitDefaultStrategies(); + handlerObject = this; + } + + /// + /// Initializes a new instance of the class for the given handler object + /// + /// The delegate object. + public MessageListenerAdapter(object handlerObject) + { + InitDefaultStrategies(); + this.handlerObject = handlerObject; + } + + #endregion + + /// + /// Gets or sets the handler object to delegate message listening to. /// /// - /// By default, the content of incoming messages gets extracted before - /// being passed into the target listener method, to let the target method - /// operate on message content types such as String or byte array instead of - /// the raw Message. Message type conversion is delegated to a Spring - /// . By default, a - /// will be used. (If you do not want such automatic message conversion taking - /// place, then be sure to set the property - /// to null.) - /// - /// If a target listener method returns a non-null object (typically of a - /// message content type such as String or byte array), it will get - /// wrapped in a NMS Message and sent to the response destination - /// (either the NMS "reply-to" destination or the - /// specified. - /// - /// - /// The sending of response messages is only available when - /// using the entry point (typically through a - /// Spring message listener container). Usage as standard NMS MessageListener - /// does not support the generation of response messages. - /// - /// Consult the reference documentation for examples of method signatures compliant with this - /// adapter class. - /// + /// Specified listener methods have to be present on this target object. + /// If no explicit handler object has been specified, listener + /// methods are expected to present on this adapter instance, that is, + /// on a custom subclass of this adapter, defining listener methods. /// - /// Juergen Hoeller - /// Mark Pollack (.NET) - public class MessageListenerAdapter : IMessageListener, ISessionAwareMessageListener + /// The handler object. + public object HandlerObject { - #region Logging + get { return handlerObject; } + set { handlerObject = value; } + } - private readonly ILogger logger = LogManager.GetLogger(typeof (MessageListenerAdapter)); - - #endregion - - #region Fields - - /// - /// The default handler method name. - /// - public static string ORIGINAL_DEFAULT_HANDLER_METHOD = "HandleMessage"; - - private object handlerObject; - - private string defaultHandlerMethod = ORIGINAL_DEFAULT_HANDLER_METHOD; - - private IExpression processingExpression; - - private object defaultResponseDestination; - - private IDestinationResolver destinationResolver = new DynamicDestinationResolver(); - - private IMessageConverter messageConverter; - - #endregion - - #region Constructors - - /// - /// Initializes a new instance of the class with default settings. - /// - public MessageListenerAdapter() + /// + /// Gets or sets the default handler method to delegate to, + /// for the case where no specific listener method has been determined. + /// Out-of-the-box value is ("HandleMessage"}. + /// + /// The default handler method. + public string DefaultHandlerMethod + { + get { return defaultHandlerMethod; } + set { - InitDefaultStrategies(); - handlerObject = this; - } - - /// - /// Initializes a new instance of the class for the given handler object - /// - /// The delegate object. - public MessageListenerAdapter(object handlerObject) - { - InitDefaultStrategies(); - this.handlerObject = handlerObject; - } - - #endregion - - /// - /// Gets or sets the handler object to delegate message listening to. - /// - /// - /// Specified listener methods have to be present on this target object. - /// If no explicit handler object has been specified, listener - /// methods are expected to present on this adapter instance, that is, - /// on a custom subclass of this adapter, defining listener methods. - /// - /// The handler object. - public object HandlerObject - { - get { return handlerObject; } - set { handlerObject = value; } - } - - /// - /// Gets or sets the default handler method to delegate to, - /// for the case where no specific listener method has been determined. - /// Out-of-the-box value is ("HandleMessage"}. - /// - /// The default handler method. - public string DefaultHandlerMethod - { - get { return defaultHandlerMethod; } - set - { - defaultHandlerMethod = value; - processingExpression = Expression.Parse(defaultHandlerMethod + "(#convertedObject)"); - } - } - - - /// - /// Sets the default destination to send response messages to. This will be applied - /// in case of a request message that does not carry a "JMSReplyTo" field. - /// Response destinations are only relevant for listener methods that return - /// result objects, which will be wrapped in a response message and sent to a - /// response destination. - /// - /// Alternatively, specify a "DefaultResponseQueueName" or "DefaultResponseTopicName", - /// to be dynamically resolved via the DestinationResolver. - /// - /// - /// The default response destination. - public object DefaultResponseDestination - { - set { defaultResponseDestination = value; } - } - - /// - /// Sets the name of the default response queue to send response messages to. - /// This will be applied in case of a request message that does not carry a - /// "NMSReplyTo" field. - /// Alternatively, specify a JMS Destination object as "defaultResponseDestination". - /// - /// The name of the default response destination queue. - public string DefaultResponseQueueName - { - set { defaultResponseDestination = new DestinationNameHolder(value, false); } - } - - /// - /// Sets the name of the default response topic to send response messages to. - /// This will be applied in case of a request message that does not carry a - /// "NMSReplyTo" field. - /// Alternatively, specify a JMS Destination object as "defaultResponseDestination". - /// - /// The name of the default response destination topic. - public string DefaultResponseTopicName - { - set { defaultResponseDestination = new DestinationNameHolder(value, true); } - } - - - /// - /// Gets or sets the destination resolver that should be used to resolve response - /// destination names for this adapter. - /// The default resolver is a . - /// Specify another implementation, for other strategies, perhaps from a directory service. - /// - /// The destination resolver. - public IDestinationResolver DestinationResolver - { - get { return destinationResolver; } - set - { - AssertUtils.ArgumentNotNull(value, "DestinationResolver must not be null"); - destinationResolver = value; - } - } - - /// - /// Gets or sets the message converter that will convert incoming JMS messages to - /// listener method arguments, and objects returned from listener - /// methods back to NMS messages. - /// - /// - /// The default converter is a {@link SimpleMessageConverter}, which is able - /// to handle BytesMessages}, TextMessages, MapMessages, and ObjectMessages. - /// - /// - /// The message converter. - public IMessageConverter MessageConverter - { - get { return messageConverter; } - set { messageConverter = value; } - } - - - /// - /// Standard JMS {@link MessageListener} entry point. - /// Delegates the message to the target listener method, with appropriate - /// conversion of the message arguments - /// - /// - /// - /// In case of an exception, the method will be invoked. - /// Note - /// Does not support sending response messages based on - /// result objects returned from listener methods. Use the - /// entry point (typically through a Spring - /// message listener container) for handling result objects as well. - /// - /// The incoming message. - public void OnMessage(IMessage message) - { - try - { - OnMessage(message, null); - } - catch (Exception e) - { - HandleListenerException(e); - } - } - - /// - /// Spring entry point. - /// - /// Delegates the message to the target listener method, with appropriate - /// conversion of the message argument. If the target method returns a - /// non-null object, wrap in a NMS message and send it back. - /// - /// - /// The incoming message. - /// The session to operate on. - public void OnMessage(IMessage message, ISession session) - { - if (handlerObject != this) - { - if (typeof(ISessionAwareMessageListener).IsInstanceOfType(handlerObject)) - { - if (session != null) - { - ((ISessionAwareMessageListener) handlerObject).OnMessage(message, session); - return; - } - else if (!typeof(IMessageListener).IsInstanceOfType(handlerObject)) - { - throw new InvalidOperationException("MessageListenerAdapter cannot handle a " + - "SessionAwareMessageListener delegate if it hasn't been invoked with a Session itself"); - } - } - if (typeof(IMessageListener).IsInstanceOfType(handlerObject)) - { - ((IMessageListener)handlerObject).OnMessage(message); - return; - } - } - - // Regular case: find a handler method reflectively. - object convertedMessage = ExtractMessage(message); - - - IDictionary vars = new Dictionary(); - vars["convertedObject"] = convertedMessage; - - //Need to parse each time since have overloaded methods and - //expression processor caches target of first invocation. - //TODO - check JIRA as I believe this has been fixed, otherwise, use regular reflection. -MLP - //processingExpression = Expression.Parse(defaultHandlerMethod + "(#convertedObject)"); - - //Invoke message handler method and get result. - object result; - try - { - result = processingExpression.GetValue(handlerObject, vars); - } - catch (NMSException) - { - throw; - } - // Will only happen if dynamic method invocation falls back to standard reflection. - catch (TargetInvocationException ex) - { - Exception targetEx = ex.InnerException; - if (ObjectUtils.IsAssignable(typeof(NMSException), targetEx)) - { - throw ReflectionUtils.UnwrapTargetInvocationException(ex); - } - else - { - throw new ListenerExecutionFailedException("Listener method '" + defaultHandlerMethod + "' threw exception", targetEx); - } - } - catch (Exception ex) - { - throw new ListenerExecutionFailedException("Failed to invoke target method '" + defaultHandlerMethod + - "' with argument " + convertedMessage, ex); - } - - if (result != null) - { - HandleResult(result, message, session); - } - else - { - logger.LogDebug("No result object given - no result to handle"); - } - } - - /// - /// Initialize the default implementations for the adapter's strategies. - /// - protected virtual void InitDefaultStrategies() - { - MessageConverter = new SimpleMessageConverter(); + defaultHandlerMethod = value; processingExpression = Expression.Parse(defaultHandlerMethod + "(#convertedObject)"); } - - /// - /// Handle the given exception that arose during listener execution. - /// The default implementation logs the exception at error level. - /// This method only applies when used as standard NMS MessageListener. - /// In case of the Spring mechanism, - /// exceptions get handled by the caller instead. - /// - /// - /// The exception to handle. - protected virtual void HandleListenerException(Exception ex) - { - logger.LogError(ex, "Listener execution failed"); - } - - /// - /// Extract the message body from the given message. - /// - /// The message. - /// the content of the message, to be passed into the - /// listener method as argument - /// if thrown by NMS API methods - private object ExtractMessage(IMessage message) - { - IMessageConverter converter = MessageConverter; - if (converter != null) - { - return converter.FromMessage(message); - } - return message; - } - - /// - /// Gets the name of the listener method that is supposed to - /// handle the given message. - /// The default implementation simply returns the configured - /// default listener method, if any. - /// - /// The NMS request message. - /// The converted JMS request message, - /// to be passed into the listener method as argument. - /// the name of the listener method (never null) - /// if thrown by NMS API methods - protected virtual string GetHandlerMethodName(IMessage originalIMessage, object extractedMessage) - { - return DefaultHandlerMethod; - } - - /// - /// Handles the given result object returned from the listener method, sending a response message back. - /// - /// The result object to handle (never null). - /// The original request message. - /// The session to operate on (may be null). - protected virtual void HandleResult(object result, IMessage request, ISession session) - { - if (session != null) - { - if (logger.IsEnabled(LogLevel.Debug)) - { - logger.LogDebug("Listener method returned result [" + result + - "] - generating response message for it"); - } - IMessage response = BuildMessage(session, result); - PostProcessResponse(request, response); - IDestination destination = GetResponseDestination(request, response, session); - SendResponse(session, destination, response); - } - else - { - if (logger.IsEnabled(LogLevel.Debug)) - { - logger.LogDebug("Listener method returned result [" + result + - "]: not generating response message for it because of no NMS ISession given"); - } - } - } - - /// - /// Builds a JMS message to be sent as response based on the given result object. - /// - /// The JMS Session to operate on. - /// The content of the message, as returned from the listener method. - /// the JMS Message (never null) - /// If there was an error in message conversion - /// if thrown by NMS API methods - protected virtual IMessage BuildMessage(ISession session, Object result) - { - IMessageConverter converter = MessageConverter; - if (converter != null) - { - return converter.ToMessage(result, session); - } - else - { - IMessage msg = result as IMessage; - if (msg == null) - { - throw new MessageConversionException( - "No IMessageConverter specified - cannot handle message [" + result + "]"); - } - return msg; - } - } - - /// - /// Post-process the given response message before it will be sent. The default implementation - /// sets the response's correlation id to the request message's correlation id. - /// - /// The original incoming message. - /// The outgoing JMS message about to be sent. - /// if thrown by NMS API methods - protected virtual void PostProcessResponse(IMessage request, IMessage response) - { - response.NMSCorrelationID = request.NMSCorrelationID; - } - - /// - /// Determine a response destination for the given message. - /// - /// - /// The default implementation first checks the JMS Reply-To - /// Destination of the supplied request; if that is not null - /// it is returned; if it is null, then the configured - /// default response destination - /// is returned; if this too is null, then an - /// is thrown. - /// - /// - /// The original incoming message. - /// The outgoing message about to be sent. - /// The session to operate on. - /// the response destination (never null) - /// if thrown by NMS API methods - /// if no destination can be determined. - protected virtual IDestination GetResponseDestination(IMessage request, IMessage response, ISession session) - { - IDestination replyTo = request.NMSReplyTo; - if (replyTo == null) - { - replyTo = ResolveDefaultResponseDestination(session); - if (replyTo == null) - { - throw new InvalidDestinationException("Cannot determine response destination: " + - "Request message does not contain reply-to destination, and no default response destination set."); - } - } - return replyTo; - } - - /// - /// Resolves the default response destination into a Destination, using this - /// accessor's in case of a destination name. - /// - /// The session to operate on. - /// The located destination - protected virtual IDestination ResolveDefaultResponseDestination(ISession session) - { - IDestination dest = defaultResponseDestination as IDestination; - if (dest != null) - { - return dest; - } - - DestinationNameHolder destNameHolder = defaultResponseDestination as DestinationNameHolder; - if (destNameHolder != null) - { - return DestinationResolver.ResolveDestinationName(session, destNameHolder.Name, destNameHolder.IsTopic); - } - - return null; - } - - /// - /// Sends the given response message to the given destination. - /// - /// The session to operate on. - /// The destination to send to. - /// The outgoing message about to be sent. - protected virtual void SendResponse(ISession session, IDestination destination, IMessage response) - { - IMessageProducer producer = session.CreateProducer(destination); - try - { - PostProcessProducer(producer, response); - producer.Send(response); - } - finally - { - NmsUtils.CloseMessageProducer(producer); - } - } - - /// - /// Post-process the given message producer before using it to send the response. - /// The default implementation is empty. - /// - /// The producer that will be used to send the message. - /// The outgoing message about to be sent. - protected virtual void PostProcessProducer(IMessageProducer producer, IMessage response) - { - - } } /// - /// Internal class combining a destination name and its target destination type (queue or topic). + /// Sets the default destination to send response messages to. This will be applied + /// in case of a request message that does not carry a "JMSReplyTo" field. + /// Response destinations are only relevant for listener methods that return + /// result objects, which will be wrapped in a response message and sent to a + /// response destination. + /// + /// Alternatively, specify a "DefaultResponseQueueName" or "DefaultResponseTopicName", + /// to be dynamically resolved via the DestinationResolver. + /// /// - internal class DestinationNameHolder + /// The default response destination. + public object DefaultResponseDestination { - private readonly string name; + set { defaultResponseDestination = value; } + } - private readonly bool isTopic; + /// + /// Sets the name of the default response queue to send response messages to. + /// This will be applied in case of a request message that does not carry a + /// "NMSReplyTo" field. + /// Alternatively, specify a JMS Destination object as "defaultResponseDestination". + /// + /// The name of the default response destination queue. + public string DefaultResponseQueueName + { + set { defaultResponseDestination = new DestinationNameHolder(value, false); } + } - public DestinationNameHolder(string name, bool isTopic) + /// + /// Sets the name of the default response topic to send response messages to. + /// This will be applied in case of a request message that does not carry a + /// "NMSReplyTo" field. + /// Alternatively, specify a JMS Destination object as "defaultResponseDestination". + /// + /// The name of the default response destination topic. + public string DefaultResponseTopicName + { + set { defaultResponseDestination = new DestinationNameHolder(value, true); } + } + + /// + /// Gets or sets the destination resolver that should be used to resolve response + /// destination names for this adapter. + /// The default resolver is a . + /// Specify another implementation, for other strategies, perhaps from a directory service. + /// + /// The destination resolver. + public IDestinationResolver DestinationResolver + { + get { return destinationResolver; } + set { - this.name = name; - this.isTopic = isTopic; - } - - - public string Name - { - get { return name; } - } - - public bool IsTopic - { - get { return isTopic; } + AssertUtils.ArgumentNotNull(value, "DestinationResolver must not be null"); + destinationResolver = value; } } + + /// + /// Gets or sets the message converter that will convert incoming JMS messages to + /// listener method arguments, and objects returned from listener + /// methods back to NMS messages. + /// + /// + /// The default converter is a {@link SimpleMessageConverter}, which is able + /// to handle BytesMessages}, TextMessages, MapMessages, and ObjectMessages. + /// + /// + /// The message converter. + public IMessageConverter MessageConverter + { + get { return messageConverter; } + set { messageConverter = value; } + } + + /// + /// Standard JMS {@link MessageListener} entry point. + /// Delegates the message to the target listener method, with appropriate + /// conversion of the message arguments + /// + /// + /// + /// In case of an exception, the method will be invoked. + /// Note + /// Does not support sending response messages based on + /// result objects returned from listener methods. Use the + /// entry point (typically through a Spring + /// message listener container) for handling result objects as well. + /// + /// The incoming message. + public void OnMessage(IMessage message) + { + try + { + OnMessage(message, null); + } + catch (Exception e) + { + HandleListenerException(e); + } + } + + /// + /// Spring entry point. + /// + /// Delegates the message to the target listener method, with appropriate + /// conversion of the message argument. If the target method returns a + /// non-null object, wrap in a NMS message and send it back. + /// + /// + /// The incoming message. + /// The session to operate on. + public void OnMessage(IMessage message, ISession session) + { + if (handlerObject != this) + { + if (typeof(ISessionAwareMessageListener).IsInstanceOfType(handlerObject)) + { + if (session != null) + { + ((ISessionAwareMessageListener) handlerObject).OnMessage(message, session); + return; + } + else if (!typeof(IMessageListener).IsInstanceOfType(handlerObject)) + { + throw new InvalidOperationException("MessageListenerAdapter cannot handle a " + + "SessionAwareMessageListener delegate if it hasn't been invoked with a Session itself"); + } + } + + if (typeof(IMessageListener).IsInstanceOfType(handlerObject)) + { + ((IMessageListener) handlerObject).OnMessage(message); + return; + } + } + + // Regular case: find a handler method reflectively. + object convertedMessage = ExtractMessage(message); + + IDictionary vars = new Dictionary(); + vars["convertedObject"] = convertedMessage; + + //Need to parse each time since have overloaded methods and + //expression processor caches target of first invocation. + //TODO - check JIRA as I believe this has been fixed, otherwise, use regular reflection. -MLP + //processingExpression = Expression.Parse(defaultHandlerMethod + "(#convertedObject)"); + + //Invoke message handler method and get result. + object result; + try + { + result = processingExpression.GetValue(handlerObject, vars); + } + catch (NMSException) + { + throw; + } + // Will only happen if dynamic method invocation falls back to standard reflection. + catch (TargetInvocationException ex) + { + Exception targetEx = ex.InnerException; + if (ObjectUtils.IsAssignable(typeof(NMSException), targetEx)) + { + throw ReflectionUtils.UnwrapTargetInvocationException(ex); + } + else + { + throw new ListenerExecutionFailedException("Listener method '" + defaultHandlerMethod + "' threw exception", targetEx); + } + } + catch (Exception ex) + { + throw new ListenerExecutionFailedException("Failed to invoke target method '" + defaultHandlerMethod + + "' with argument " + convertedMessage, ex); + } + + if (result != null) + { + HandleResult(result, message, session); + } + else + { + logger.LogDebug("No result object given - no result to handle"); + } + } + + /// + /// Initialize the default implementations for the adapter's strategies. + /// + protected virtual void InitDefaultStrategies() + { + MessageConverter = new SimpleMessageConverter(); + processingExpression = Expression.Parse(defaultHandlerMethod + "(#convertedObject)"); + } + + /// + /// Handle the given exception that arose during listener execution. + /// The default implementation logs the exception at error level. + /// This method only applies when used as standard NMS MessageListener. + /// In case of the Spring mechanism, + /// exceptions get handled by the caller instead. + /// + /// + /// The exception to handle. + protected virtual void HandleListenerException(Exception ex) + { + logger.LogError(ex, "Listener execution failed"); + } + + /// + /// Extract the message body from the given message. + /// + /// The message. + /// the content of the message, to be passed into the + /// listener method as argument + /// if thrown by NMS API methods + private object ExtractMessage(IMessage message) + { + IMessageConverter converter = MessageConverter; + if (converter != null) + { + return converter.FromMessage(message); + } + + return message; + } + + /// + /// Gets the name of the listener method that is supposed to + /// handle the given message. + /// The default implementation simply returns the configured + /// default listener method, if any. + /// + /// The NMS request message. + /// The converted JMS request message, + /// to be passed into the listener method as argument. + /// the name of the listener method (never null) + /// if thrown by NMS API methods + protected virtual string GetHandlerMethodName(IMessage originalIMessage, object extractedMessage) + { + return DefaultHandlerMethod; + } + + /// + /// Handles the given result object returned from the listener method, sending a response message back. + /// + /// The result object to handle (never null). + /// The original request message. + /// The session to operate on (may be null). + protected virtual void HandleResult(object result, IMessage request, ISession session) + { + if (session != null) + { + if (logger.IsEnabled(LogLevel.Debug)) + { + logger.LogDebug("Listener method returned result [" + result + + "] - generating response message for it"); + } + + IMessage response = BuildMessage(session, result); + PostProcessResponse(request, response); + IDestination destination = GetResponseDestination(request, response, session); + SendResponse(session, destination, response); + } + else + { + if (logger.IsEnabled(LogLevel.Debug)) + { + logger.LogDebug("Listener method returned result [" + result + + "]: not generating response message for it because of no NMS ISession given"); + } + } + } + + /// + /// Builds a JMS message to be sent as response based on the given result object. + /// + /// The JMS Session to operate on. + /// The content of the message, as returned from the listener method. + /// the JMS Message (never null) + /// If there was an error in message conversion + /// if thrown by NMS API methods + protected virtual IMessage BuildMessage(ISession session, Object result) + { + IMessageConverter converter = MessageConverter; + if (converter != null) + { + return converter.ToMessage(result, session); + } + else + { + IMessage msg = result as IMessage; + if (msg == null) + { + throw new MessageConversionException( + "No IMessageConverter specified - cannot handle message [" + result + "]"); + } + + return msg; + } + } + + /// + /// Post-process the given response message before it will be sent. The default implementation + /// sets the response's correlation id to the request message's correlation id. + /// + /// The original incoming message. + /// The outgoing JMS message about to be sent. + /// if thrown by NMS API methods + protected virtual void PostProcessResponse(IMessage request, IMessage response) + { + response.NMSCorrelationID = request.NMSCorrelationID; + } + + /// + /// Determine a response destination for the given message. + /// + /// + /// The default implementation first checks the JMS Reply-To + /// Destination of the supplied request; if that is not null + /// it is returned; if it is null, then the configured + /// default response destination + /// is returned; if this too is null, then an + /// is thrown. + /// + /// + /// The original incoming message. + /// The outgoing message about to be sent. + /// The session to operate on. + /// the response destination (never null) + /// if thrown by NMS API methods + /// if no destination can be determined. + protected virtual IDestination GetResponseDestination(IMessage request, IMessage response, ISession session) + { + IDestination replyTo = request.NMSReplyTo; + if (replyTo == null) + { + replyTo = ResolveDefaultResponseDestination(session); + if (replyTo == null) + { + throw new InvalidDestinationException("Cannot determine response destination: " + + "Request message does not contain reply-to destination, and no default response destination set."); + } + } + + return replyTo; + } + + /// + /// Resolves the default response destination into a Destination, using this + /// accessor's in case of a destination name. + /// + /// The session to operate on. + /// The located destination + protected virtual IDestination ResolveDefaultResponseDestination(ISession session) + { + IDestination dest = defaultResponseDestination as IDestination; + if (dest != null) + { + return dest; + } + + DestinationNameHolder destNameHolder = defaultResponseDestination as DestinationNameHolder; + if (destNameHolder != null) + { + return DestinationResolver.ResolveDestinationName(session, destNameHolder.Name, destNameHolder.IsTopic); + } + + return null; + } + + /// + /// Sends the given response message to the given destination. + /// + /// The session to operate on. + /// The destination to send to. + /// The outgoing message about to be sent. + protected virtual void SendResponse(ISession session, IDestination destination, IMessage response) + { + IMessageProducer producer = session.CreateProducer(destination); + try + { + PostProcessProducer(producer, response); + producer.Send(response); + } + finally + { + NmsUtils.CloseMessageProducer(producer); + } + } + + /// + /// Post-process the given message producer before using it to send the response. + /// The default implementation is empty. + /// + /// The producer that will be used to send the message. + /// The outgoing message about to be sent. + protected virtual void PostProcessProducer(IMessageProducer producer, IMessage response) + { + } +} + +/// +/// Internal class combining a destination name and its target destination type (queue or topic). +/// +internal class DestinationNameHolder +{ + private readonly string name; + + private readonly bool isTopic; + + public DestinationNameHolder(string name, bool isTopic) + { + this.name = name; + this.isTopic = isTopic; + } + + public string Name + { + get { return name; } + } + + public bool IsTopic + { + get { return isTopic; } + } } diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Listener/ISessionAwareMessageListener.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Listener/ISessionAwareMessageListener.cs index 0840eb52..e1ad16d0 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Listener/ISessionAwareMessageListener.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Listener/ISessionAwareMessageListener.cs @@ -20,32 +20,31 @@ using Apache.NMS; -namespace Spring.Messaging.Nms.Listener +namespace Spring.Messaging.Nms.Listener; + +/// +/// Variant of the standard NMS MessageListener interface, +/// offering not only the received Message but also the underlying +/// Session object. The latter can be used to send reply messages, +/// without the need to access an external Connection/Session, +/// i.e. without the need to access the underlying ConnectionFactory. +/// +/// +/// Supported by Spring's +/// as direct alternative to the standard MessageListener interface. +/// +/// Juergen Hoeller +/// Mark Pollack (.NET) +public interface ISessionAwareMessageListener { - /// - /// Variant of the standard NMS MessageListener interface, - /// offering not only the received Message but also the underlying - /// Session object. The latter can be used to send reply messages, - /// without the need to access an external Connection/Session, - /// i.e. without the need to access the underlying ConnectionFactory. + /// Callback for processing a received NMS message. + /// Implementors are supposed to process the given Message, + /// typically sending reply messages through the given Session. /// - /// - /// Supported by Spring's - /// as direct alternative to the standard MessageListener interface. - /// - /// Juergen Hoeller - /// Mark Pollack (.NET) - public interface ISessionAwareMessageListener - { - /// Callback for processing a received NMS message. - /// Implementors are supposed to process the given Message, - /// typically sending reply messages through the given Session. - /// - /// the received NMS message - /// - /// the underlying NMS Session - /// - /// NMSException if thrown by NMS methods - void OnMessage(IMessage message, ISession session); - } + /// the received NMS message + /// + /// the underlying NMS Session + /// + /// NMSException if thrown by NMS methods + void OnMessage(IMessage message, ISession session); } diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Listener/LocallyExposedNmsResourceHolder.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Listener/LocallyExposedNmsResourceHolder.cs index a9f2258f..3fc5d67b 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Listener/LocallyExposedNmsResourceHolder.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Listener/LocallyExposedNmsResourceHolder.cs @@ -21,23 +21,21 @@ using Apache.NMS; using Spring.Messaging.Nms.Connections; -namespace Spring.Messaging.Nms.Listener +namespace Spring.Messaging.Nms.Listener; + +/// +/// MessageResourceHolder marker subclass that indicates local exposure, +/// i.e. that does not indicate an externally managed transaction. +/// +/// Juergen Hoeller +/// Mark Pollack (.NET) +public class LocallyExposedNmsResourceHolder : NmsResourceHolder { /// - /// MessageResourceHolder marker subclass that indicates local exposure, - /// i.e. that does not indicate an externally managed transaction. + /// Initializes a new instance of the class. /// - /// Juergen Hoeller - /// Mark Pollack (.NET) - public class LocallyExposedNmsResourceHolder : NmsResourceHolder + /// The session. + public LocallyExposedNmsResourceHolder(ISession session) : base(session) { - /// - /// Initializes a new instance of the class. - /// - /// The session. - public LocallyExposedNmsResourceHolder(ISession session) : base(session) - { - - } } -} \ No newline at end of file +} diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Listener/RecoveryTimeExceededException.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Listener/RecoveryTimeExceededException.cs index 0458ff38..99ac13af 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Listener/RecoveryTimeExceededException.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Listener/RecoveryTimeExceededException.cs @@ -25,49 +25,48 @@ using Apache.NMS; #endregion -namespace Spring.Messaging.Nms.Listener +namespace Spring.Messaging.Nms.Listener; + +/// +/// Exception thrown when the maximum connection recovery time has been exceeded. +/// +/// Mark Pollack +[Serializable] +public class RecoveryTimeExceededException : NMSException { /// - /// Exception thrown when the maximum connection recovery time has been exceeded. + /// Initializes a new instance of the class. /// - /// Mark Pollack - [Serializable] - public class RecoveryTimeExceededException : NMSException + public RecoveryTimeExceededException() { - /// - /// Initializes a new instance of the class. - /// - public RecoveryTimeExceededException() - { - } + } - /// - /// Initializes a new instance of the class, with the specified message - /// - /// The message. - public RecoveryTimeExceededException(string message) - : base(message) - { - } + /// + /// Initializes a new instance of the class, with the specified message + /// + /// The message. + public RecoveryTimeExceededException(string message) + : base(message) + { + } - /// - /// Initializes a new instance of the class, with the specified message - /// and root cause exception - /// - /// The message. - /// The inner exception. - public RecoveryTimeExceededException(string message, Exception innerException) - : base(message, innerException) - { - } + /// + /// Initializes a new instance of the class, with the specified message + /// and root cause exception + /// + /// The message. + /// The inner exception. + public RecoveryTimeExceededException(string message, Exception innerException) + : base(message, innerException) + { + } - /// - /// Initializes a new instance of the class. - /// - /// The SerializationInfo that holds the serialized object data about the exception being thrown. - /// The StreamingContext that contains contextual information about the source or destination. - protected RecoveryTimeExceededException(SerializationInfo info, StreamingContext context) : base(info, context) - { - } + /// + /// Initializes a new instance of the class. + /// + /// The SerializationInfo that holds the serialized object data about the exception being thrown. + /// The StreamingContext that contains contextual information about the source or destination. + protected RecoveryTimeExceededException(SerializationInfo info, StreamingContext context) : base(info, context) + { } } diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Listener/SimpleMessageListenerContainer.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Listener/SimpleMessageListenerContainer.cs index 8b4196c1..afb8bc6d 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Listener/SimpleMessageListenerContainer.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Listener/SimpleMessageListenerContainer.cs @@ -26,390 +26,393 @@ using Microsoft.Extensions.Logging; using Spring.Transaction.Support; using Spring.Util; -namespace Spring.Messaging.Nms.Listener +namespace Spring.Messaging.Nms.Listener; + +/// +/// Message listener container that uses the plain NMS client API's +/// MessageConsumer.Listener method to create concurrent +/// MessageConsumers for the specified listeners. +/// +/// Mark Pollack +public class SimpleMessageListenerContainer : AbstractMessageListenerContainer, IExceptionListener { + #region Logging + + private readonly ILogger logger = LogManager.GetLogger(); + + #endregion + + #region fields + /// - /// Message listener container that uses the plain NMS client API's - /// MessageConsumer.Listener method to create concurrent - /// MessageConsumers for the specified listeners. + /// The default recovery time interval between connection reconnection attempts /// - /// Mark Pollack - public class SimpleMessageListenerContainer : AbstractMessageListenerContainer, IExceptionListener + public static string DEFAULT_RECOVERY_INTERVAL = "5s"; + + /// + /// The total time connection recovery will be attempted. + /// + public static string DEFAULT_MAX_RECOVERY_TIME = "10m"; + + private bool pubSubNoLocal = false; + + private int concurrentConsumers = 1; + + private ISet sessions; + + private ISet consumers; + + private object consumersMonitor = new object(); + + private TimeSpan recoveryInterval = new TimeSpan(0, 0, 0, 5, 0); + + private TimeSpan maxRecoveryTime = new TimeSpan(0, 0, 10, 0, 0); + + #endregion + + #region Properties + + /// + /// Gets or sets a value indicating whether to inhibit the delivery of messages published by its own connection. + /// Default is "false". + /// + /// true if should inhibit the delivery of messages published by its own connection; otherwise, false. + public bool PubSubNoLocal { - #region Logging + get { return pubSubNoLocal; } + set { pubSubNoLocal = value; } + } - private readonly ILogger logger = LogManager.GetLogger(); - - #endregion - - #region fields - - /// - /// The default recovery time interval between connection reconnection attempts - /// - public static string DEFAULT_RECOVERY_INTERVAL = "5s"; - - /// - /// The total time connection recovery will be attempted. - /// - public static string DEFAULT_MAX_RECOVERY_TIME = "10m"; - - private bool pubSubNoLocal = false; - - private int concurrentConsumers = 1; - - private ISet sessions; - - private ISet consumers; - - private object consumersMonitor = new object(); - - private TimeSpan recoveryInterval = new TimeSpan(0, 0, 0, 5, 0); - - private TimeSpan maxRecoveryTime = new TimeSpan(0, 0, 10, 0, 0); - - - #endregion - - #region Properties - - /// - /// Gets or sets a value indicating whether to inhibit the delivery of messages published by its own connection. - /// Default is "false". - /// - /// true if should inhibit the delivery of messages published by its own connection; otherwise, false. - public bool PubSubNoLocal + /// + /// Specify the number of concurrent consumers to create. Default is 1. + /// + /// + /// Raising the number of concurrent consumers is recommendable in order + /// to scale the consumption of messages coming in from a queue. However, + /// note that any ordering guarantees are lost once multiple consumers are + /// registered. In general, stick with 1 consumer for low-volume queues. + /// Do not raise the number of concurrent consumers for a topic. + /// This would lead to concurrent consumption of the same message, + /// which is hardly ever desirable. + /// + /// + /// The concurrent consumers. + public int ConcurrentConsumers + { + set { - get { return pubSubNoLocal; } - set { pubSubNoLocal = value; } - } - - /// - /// Specify the number of concurrent consumers to create. Default is 1. - /// - /// - /// Raising the number of concurrent consumers is recommendable in order - /// to scale the consumption of messages coming in from a queue. However, - /// note that any ordering guarantees are lost once multiple consumers are - /// registered. In general, stick with 1 consumer for low-volume queues. - /// Do not raise the number of concurrent consumers for a topic. - /// This would lead to concurrent consumption of the same message, - /// which is hardly ever desirable. - /// - /// - /// The concurrent consumers. - public int ConcurrentConsumers - { - set - { - AssertUtils.IsTrue(value > 0, "'ConcurrentConsumer' value must be at least 1 (one)"); - concurrentConsumers = value; - } - } - - - /// - /// Sets the time interval between connection recovery attempts. The default is 5 seconds. - /// - /// The recovery interval. - public TimeSpan RecoveryInterval - { - set { recoveryInterval = value; } - } - - - /// - /// Sets the max recovery time to try reconnection attempts. The default is 10 minutes. - /// - /// The max recovery time. - public TimeSpan MaxRecoveryTime - { - set { maxRecoveryTime = value; } - } - - /// - /// Always use a shared NMS connection - /// - protected override bool SharedConnectionEnabled - { - get { return true; } - } - - #endregion - - /// - /// Call base class for valdation and then check that if the subscription is durable that the number of - /// concurrent consumers is equal to one. - /// - protected override void ValidateConfiguration() - { - base.ValidateConfiguration(); - if (SubscriptionDurable && concurrentConsumers !=1 ) - { - throw new ArgumentException("Only 1 concurrent consumer supported for durable subscription"); - } - } - - /// - /// Creates the specified number of concurrent consumers, - /// in the form of a JMS Session plus associated MessageConsumer - /// - /// - protected override void DoInitialize() - { - EstablishSharedConnection(); - InitializeConsumers(); - } - - /// - /// Re-initializes this container's NMS message consumers, - /// if not initialized already. - /// - protected override void DoStart() - { - base.DoStart(); - InitializeConsumers(); - } - - /// - /// Registers this listener container as NMS ExceptionListener on the shared connection. - /// - /// - protected override void PrepareSharedConnection(IConnection connection) - { - base.PrepareSharedConnection(connection); - connection.ExceptionListener += OnException; - } - - - /// - /// implementation, invoked by the NMS provider in - /// case of connection failures. Re-initializes this listener container's - /// shared connection and its sessions and consumers. - /// - /// The reported connection exception. - public void OnException(Exception exception) - { - // First invoke the user-specific ExceptionListener, if any. - InvokeExceptionListener(exception); - // now try to recover the shared Connection and all consumers... - if (logger.IsEnabled(LogLevel.Information)) - { - logger.LogInformation("Trying to recover from NMS Connection exception: " + exception); - } - try - { - lock (consumersMonitor) - { - sessions = null; - consumers = null; - } - RefreshConnectionUntilSuccessful(); - InitializeConsumers(); - logger.LogInformation("Successfully refreshed NMS Connection"); - } catch (RecoveryTimeExceededException) - { - throw; - } catch (Exception recoverEx) - { - logger.LogDebug(recoverEx, "Failed to recover NMS Connection"); - logger.LogError(exception, "Encountered non-recoverable Exception"); - throw; - } - } - - /// - /// Refresh the underlying Connection, not returning before an attempt has been - /// successful. Called in case of a shared Connection as well as without shared - /// Connection, so either needs to operate on the shared Connection or on a - /// temporary Connection that just gets established for validation purposes. - /// - /// - /// The default implementation retries until it successfully established a - /// Connection, for as long as this message listener container is active. - /// Applies the specified recovery interval between retries. - /// - protected virtual void RefreshConnectionUntilSuccessful() - { - TimeSpan totalTryTime = new TimeSpan(); - while (IsRunning) - { - try - { - RefreshSharedConnection(); - break; - } catch (Exception ex) - { - if (logger.IsEnabled(LogLevel.Information)) - { - logger.LogInformation(ex, "Could not refresh Connection - retrying in {RecoveryInterval}", recoveryInterval); - } - } - - if (totalTryTime > maxRecoveryTime) - { - logger.LogInformation("Could not refresh Connection after " + totalTryTime + ". Stopping reconnection attempts."); - throw new RecoveryTimeExceededException("Could not recover after " + totalTryTime); - } - - DateTime startTime = DateTime.Now; - SleepInBetweenRecoveryAttempts(); - TimeSpan sleepTimeSpan = DateTime.Now - startTime; - totalTryTime += sleepTimeSpan; - } - } - - /// - /// The amount of time to sleep in between recovery attempts. - /// - protected virtual void SleepInBetweenRecoveryAttempts() - { - Thread.Sleep(recoveryInterval); - } - - /// - /// Initialize the Sessions and MessageConsumers for this container. - /// - /// in case of setup failure. - protected virtual void InitializeConsumers() - { - // Register Sessions and MessageConsumers - lock (consumersMonitor) - { - if (this.consumers == null) - { - this.sessions = new HashedSet(); - this.consumers = new HashedSet(); - IConnection con = SharedConnection; - for (int i = 0; i < this.concurrentConsumers; i++) - { - ISession session = CreateSession(SharedConnection); - IMessageConsumer consumer = CreateListenerConsumer(session); - this.sessions.Add(session); - this.consumers.Add(consumer); - } - } - } - } - - /// - /// Creates a MessageConsumer for the given Session, - /// registering a MessageListener for the specified listener - /// - /// The session to work on. - /// the MessageConsumer"/> - /// if thrown by NMS methods - private IMessageConsumer CreateListenerConsumer(ISession session) - { - IDestination destination = Destination; - if (destination == null) - { - destination = ResolveDestinationName(session, DestinationName); - } - IMessageConsumer consumer = CreateConsumer(session, destination); - - - SimpleMessageListener listener = new SimpleMessageListener(this, session); - // put in explicit registration with 'new' for compilation on .NET 1.1 - consumer.Listener += listener.OnMessage; - return consumer; - } - - /// - /// Close the message consumers and sessions. - /// - /// NMSException if destruction failed - protected override void DoShutdown() - { - lock (consumersMonitor) - { - if (consumers != null) - { - logger.LogDebug("Closing NMS MessageConsumers"); - foreach (IMessageConsumer messageConsumer in consumers) - { - NmsUtils.CloseMessageConsumer(messageConsumer); - } - } - if (sessions != null) - { - logger.LogDebug("Closing NMS Sessions"); - foreach (ISession session in sessions) - { - NmsUtils.CloseSession(session); - } - } - consumers = null; - sessions = null; - } - } - - - /// - /// Creates a MessageConsumer for the given Session and Destination. - /// - /// The session to create a MessageConsumer for. - /// The destination to create a MessageConsumer for. - /// The new MessageConsumer - protected virtual IMessageConsumer CreateConsumer(ISession session, IDestination destination) - { - // Only pass in the NoLocal flag in case of a Topic: - // Some NMS providers, such as WebSphere MQ 6.0, throw IllegalStateException - // in case of the NoLocal flag being specified for a Queue. - - if (PubSubDomain && destination is ITopic) - { - if (SubscriptionShared) - { - if (SubscriptionDurable) - { - return session.CreateSharedDurableConsumer((ITopic) destination, SubscriptionName, MessageSelector); - } - - return session.CreateSharedConsumer((ITopic) destination, SubscriptionName, MessageSelector); - } - - if (SubscriptionDurable) - { - return session.CreateDurableConsumer((ITopic) destination, SubscriptionName, MessageSelector, PubSubNoLocal); - } - - return session.CreateConsumer(destination, MessageSelector, PubSubNoLocal); - } - - return session.CreateConsumer(destination, MessageSelector); + AssertUtils.IsTrue(value > 0, "'ConcurrentConsumer' value must be at least 1 (one)"); + concurrentConsumers = value; } } - internal class SimpleMessageListener : IMessageListener + /// + /// Sets the time interval between connection recovery attempts. The default is 5 seconds. + /// + /// The recovery interval. + public TimeSpan RecoveryInterval { - private SimpleMessageListenerContainer container; - private ISession session; + set { recoveryInterval = value; } + } - public SimpleMessageListener(SimpleMessageListenerContainer container, ISession session) + /// + /// Sets the max recovery time to try reconnection attempts. The default is 10 minutes. + /// + /// The max recovery time. + public TimeSpan MaxRecoveryTime + { + set { maxRecoveryTime = value; } + } + + /// + /// Always use a shared NMS connection + /// + protected override bool SharedConnectionEnabled + { + get { return true; } + } + + #endregion + + /// + /// Call base class for valdation and then check that if the subscription is durable that the number of + /// concurrent consumers is equal to one. + /// + protected override void ValidateConfiguration() + { + base.ValidateConfiguration(); + if (SubscriptionDurable && concurrentConsumers != 1) { - this.container = container; - this.session = session; + throw new ArgumentException("Only 1 concurrent consumer supported for durable subscription"); + } + } + + /// + /// Creates the specified number of concurrent consumers, + /// in the form of a JMS Session plus associated MessageConsumer + /// + /// + protected override void DoInitialize() + { + EstablishSharedConnection(); + InitializeConsumers(); + } + + /// + /// Re-initializes this container's NMS message consumers, + /// if not initialized already. + /// + protected override void DoStart() + { + base.DoStart(); + InitializeConsumers(); + } + + /// + /// Registers this listener container as NMS ExceptionListener on the shared connection. + /// + /// + protected override void PrepareSharedConnection(IConnection connection) + { + base.PrepareSharedConnection(connection); + connection.ExceptionListener += OnException; + } + + /// + /// implementation, invoked by the NMS provider in + /// case of connection failures. Re-initializes this listener container's + /// shared connection and its sessions and consumers. + /// + /// The reported connection exception. + public void OnException(Exception exception) + { + // First invoke the user-specific ExceptionListener, if any. + InvokeExceptionListener(exception); + // now try to recover the shared Connection and all consumers... + if (logger.IsEnabled(LogLevel.Information)) + { + logger.LogInformation("Trying to recover from NMS Connection exception: " + exception); } - public void OnMessage(IMessage message) + try { - bool exposeResource = container.ExposeListenerSession; - if (exposeResource) + lock (consumersMonitor) { - TransactionSynchronizationManager.BindResource( - container.ConnectionFactory, new LocallyExposedNmsResourceHolder(session)); + sessions = null; + consumers = null; } + + RefreshConnectionUntilSuccessful(); + InitializeConsumers(); + logger.LogInformation("Successfully refreshed NMS Connection"); + } + catch (RecoveryTimeExceededException) + { + throw; + } + catch (Exception recoverEx) + { + logger.LogDebug(recoverEx, "Failed to recover NMS Connection"); + logger.LogError(exception, "Encountered non-recoverable Exception"); + throw; + } + } + + /// + /// Refresh the underlying Connection, not returning before an attempt has been + /// successful. Called in case of a shared Connection as well as without shared + /// Connection, so either needs to operate on the shared Connection or on a + /// temporary Connection that just gets established for validation purposes. + /// + /// + /// The default implementation retries until it successfully established a + /// Connection, for as long as this message listener container is active. + /// Applies the specified recovery interval between retries. + /// + protected virtual void RefreshConnectionUntilSuccessful() + { + TimeSpan totalTryTime = new TimeSpan(); + while (IsRunning) + { try { - container.ExecuteListener(session, message); - } finally + RefreshSharedConnection(); + break; + } + catch (Exception ex) { - if (exposeResource) + if (logger.IsEnabled(LogLevel.Information)) { - TransactionSynchronizationManager.UnbindResource(container.ConnectionFactory); + logger.LogInformation(ex, "Could not refresh Connection - retrying in {RecoveryInterval}", recoveryInterval); } } + + if (totalTryTime > maxRecoveryTime) + { + logger.LogInformation("Could not refresh Connection after " + totalTryTime + ". Stopping reconnection attempts."); + throw new RecoveryTimeExceededException("Could not recover after " + totalTryTime); + } + + DateTime startTime = DateTime.Now; + SleepInBetweenRecoveryAttempts(); + TimeSpan sleepTimeSpan = DateTime.Now - startTime; + totalTryTime += sleepTimeSpan; + } + } + + /// + /// The amount of time to sleep in between recovery attempts. + /// + protected virtual void SleepInBetweenRecoveryAttempts() + { + Thread.Sleep(recoveryInterval); + } + + /// + /// Initialize the Sessions and MessageConsumers for this container. + /// + /// in case of setup failure. + protected virtual void InitializeConsumers() + { + // Register Sessions and MessageConsumers + lock (consumersMonitor) + { + if (this.consumers == null) + { + this.sessions = new HashedSet(); + this.consumers = new HashedSet(); + IConnection con = SharedConnection; + for (int i = 0; i < this.concurrentConsumers; i++) + { + ISession session = CreateSession(SharedConnection); + IMessageConsumer consumer = CreateListenerConsumer(session); + this.sessions.Add(session); + this.consumers.Add(consumer); + } + } + } + } + + /// + /// Creates a MessageConsumer for the given Session, + /// registering a MessageListener for the specified listener + /// + /// The session to work on. + /// the MessageConsumer"/> + /// if thrown by NMS methods + private IMessageConsumer CreateListenerConsumer(ISession session) + { + IDestination destination = Destination; + if (destination == null) + { + destination = ResolveDestinationName(session, DestinationName); + } + + IMessageConsumer consumer = CreateConsumer(session, destination); + + SimpleMessageListener listener = new SimpleMessageListener(this, session); + // put in explicit registration with 'new' for compilation on .NET 1.1 + consumer.Listener += listener.OnMessage; + return consumer; + } + + /// + /// Close the message consumers and sessions. + /// + /// NMSException if destruction failed + protected override void DoShutdown() + { + lock (consumersMonitor) + { + if (consumers != null) + { + logger.LogDebug("Closing NMS MessageConsumers"); + foreach (IMessageConsumer messageConsumer in consumers) + { + NmsUtils.CloseMessageConsumer(messageConsumer); + } + } + + if (sessions != null) + { + logger.LogDebug("Closing NMS Sessions"); + foreach (ISession session in sessions) + { + NmsUtils.CloseSession(session); + } + } + + consumers = null; + sessions = null; + } + } + + /// + /// Creates a MessageConsumer for the given Session and Destination. + /// + /// The session to create a MessageConsumer for. + /// The destination to create a MessageConsumer for. + /// The new MessageConsumer + protected virtual IMessageConsumer CreateConsumer(ISession session, IDestination destination) + { + // Only pass in the NoLocal flag in case of a Topic: + // Some NMS providers, such as WebSphere MQ 6.0, throw IllegalStateException + // in case of the NoLocal flag being specified for a Queue. + + if (PubSubDomain && destination is ITopic) + { + if (SubscriptionShared) + { + if (SubscriptionDurable) + { + return session.CreateSharedDurableConsumer((ITopic) destination, SubscriptionName, MessageSelector); + } + + return session.CreateSharedConsumer((ITopic) destination, SubscriptionName, MessageSelector); + } + + if (SubscriptionDurable) + { + return session.CreateDurableConsumer((ITopic) destination, SubscriptionName, MessageSelector, PubSubNoLocal); + } + + return session.CreateConsumer(destination, MessageSelector, PubSubNoLocal); + } + + return session.CreateConsumer(destination, MessageSelector); + } +} + +internal class SimpleMessageListener : IMessageListener +{ + private SimpleMessageListenerContainer container; + private ISession session; + + public SimpleMessageListener(SimpleMessageListenerContainer container, ISession session) + { + this.container = container; + this.session = session; + } + + public void OnMessage(IMessage message) + { + bool exposeResource = container.ExposeListenerSession; + if (exposeResource) + { + TransactionSynchronizationManager.BindResource( + container.ConnectionFactory, new LocallyExposedNmsResourceHolder(session)); + } + + try + { + container.ExecuteListener(session, message); + } + finally + { + if (exposeResource) + { + TransactionSynchronizationManager.UnbindResource(container.ConnectionFactory); + } } } } diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/Converter/IMessageConverter.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/Converter/IMessageConverter.cs index 89afa771..c3c3228d 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/Converter/IMessageConverter.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/Converter/IMessageConverter.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -20,36 +20,35 @@ using Apache.NMS; -namespace Spring.Messaging.Nms.Support.Converter -{ - /// Strategy interface that specifies a IMessageConverter - /// between .NET objects and NMS messages. - /// - /// - /// Mark Pollack - /// Juergen Hoeller - /// Mark Pollack (.NET) - public interface IMessageConverter - { - /// Convert a .NET object to a NMS Message using the supplied session - /// to create the message object. - /// - /// the object to convert - /// - /// the Session to use for creating a NMS Message - /// - /// the NMS Message - /// - /// NMSException if thrown by NMS API methods - /// MessageConversionException in case of conversion failure - IMessage ToMessage(object objectToConvert, ISession session); +namespace Spring.Messaging.Nms.Support.Converter; - /// Convert from a NMS Message to a .NET object. - /// the message to convert - /// - /// the converted .NET object - /// - /// MessageConversionException in case of conversion failure - object FromMessage(IMessage messageToConvert); - } +/// Strategy interface that specifies a IMessageConverter +/// between .NET objects and NMS messages. +/// +/// +/// Mark Pollack +/// Juergen Hoeller +/// Mark Pollack (.NET) +public interface IMessageConverter +{ + /// Convert a .NET object to a NMS Message using the supplied session + /// to create the message object. + /// + /// the object to convert + /// + /// the Session to use for creating a NMS Message + /// + /// the NMS Message + /// + /// NMSException if thrown by NMS API methods + /// MessageConversionException in case of conversion failure + IMessage ToMessage(object objectToConvert, ISession session); + + /// Convert from a NMS Message to a .NET object. + /// the message to convert + /// + /// the converted .NET object + /// + /// MessageConversionException in case of conversion failure + object FromMessage(IMessage messageToConvert); } diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/Converter/ITypeMapper.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/Converter/ITypeMapper.cs index b95674a3..3eba6dd0 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/Converter/ITypeMapper.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/Converter/ITypeMapper.cs @@ -1,5 +1,3 @@ - - #region License /* @@ -20,35 +18,34 @@ #endregion -namespace Spring.Messaging.Nms.Support.Converter +namespace Spring.Messaging.Nms.Support.Converter; + +/// +/// Provides a layer of indirection when adding the 'type' of the object as a message property. +/// +/// Mark Pollack +public interface ITypeMapper { /// - /// Provides a layer of indirection when adding the 'type' of the object as a message property. + /// Gets the name of the field in the message that has type information.. /// - /// Mark Pollack - public interface ITypeMapper + /// The name of the type id field. + string TypeIdFieldName { - /// - /// Gets the name of the field in the message that has type information.. - /// - /// The name of the type id field. - string TypeIdFieldName - { - get; - } - - /// - /// Convert from a type to a string. - /// - /// The type of object to convert. - /// - string FromType(Type typeOfObjectToConvert); - - /// - /// Convert from a string to a type - /// - /// The type id. - /// - Type ToType(string typeId); + get; } + + /// + /// Convert from a type to a string. + /// + /// The type of object to convert. + /// + string FromType(Type typeOfObjectToConvert); + + /// + /// Convert from a string to a type + /// + /// The type id. + /// + Type ToType(string typeId); } diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/Converter/MessageConversionException.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/Converter/MessageConversionException.cs index 329e92be..83d5ce21 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/Converter/MessageConversionException.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/Converter/MessageConversionException.cs @@ -21,59 +21,58 @@ using System.Runtime.Serialization; using Apache.NMS; -namespace Spring.Messaging.Nms.Support.Converter +namespace Spring.Messaging.Nms.Support.Converter; + +/// Thrown by IMessageConverter implementations when the conversion +/// of an object to/from a Message fails. +/// +/// Mark Pollack +[Serializable] +public class MessageConversionException : NMSException { - /// Thrown by IMessageConverter implementations when the conversion - /// of an object to/from a Message fails. + #region Constructor (s) / Destructor + + /// + /// Initializes a new instance of the class. /// - /// Mark Pollack - [Serializable] - public class MessageConversionException : NMSException + public MessageConversionException() { - #region Constructor (s) / Destructor - - /// - /// Initializes a new instance of the class. - /// - public MessageConversionException() - { - } - - /// - /// Creates a new instance of the IMessageConverterException class. with the specified message. - /// - /// - /// A message about the exception. - /// - public MessageConversionException(string message) - : base(message) - { - } - - /// - /// Creates a new instance of the IMessageConverterException class with the specified message - /// and root cause. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception that is being wrapped. - /// - public MessageConversionException(string message, Exception rootCause) - : base(message, rootCause) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The SerializationInfo that holds the serialized object data about the exception being thrown. - /// The StreamingContext that contains contextual information about the source or destination. - protected MessageConversionException(SerializationInfo info, StreamingContext context) : base(info, context) - { - } - - #endregion } + + /// + /// Creates a new instance of the IMessageConverterException class. with the specified message. + /// + /// + /// A message about the exception. + /// + public MessageConversionException(string message) + : base(message) + { + } + + /// + /// Creates a new instance of the IMessageConverterException class with the specified message + /// and root cause. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception that is being wrapped. + /// + public MessageConversionException(string message, Exception rootCause) + : base(message, rootCause) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The SerializationInfo that holds the serialized object data about the exception being thrown. + /// The StreamingContext that contains contextual information about the source or destination. + protected MessageConversionException(SerializationInfo info, StreamingContext context) : base(info, context) + { + } + + #endregion } diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/Converter/SimpleMessageConverter.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/Converter/SimpleMessageConverter.cs index 318dfbd3..ac907076 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/Converter/SimpleMessageConverter.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/Converter/SimpleMessageConverter.cs @@ -19,219 +19,220 @@ #endregion using System.Collections; - using Apache.NMS; -namespace Spring.Messaging.Nms.Support.Converter +namespace Spring.Messaging.Nms.Support.Converter; + +/// A simple message converter that can handle ITextMessages, IBytesMessages, +/// IMapMessages, and IObjectMessages. Used as default by NmsTemplate, for +/// ConvertAndSend and ReceiveAndConvert operations. +/// +///

Converts a String to a NMS ITextMessage, a byte array to a NMS IBytesMessage, +/// a Map to a NMS IMapMessage, and a Serializable object to a NMS IObjectMessage +/// (or vice versa).

+/// +/// +///
+/// Juergen Hoeller +/// Mark Pollack (.NET) +public class SimpleMessageConverter : IMessageConverter { - /// A simple message converter that can handle ITextMessages, IBytesMessages, - /// IMapMessages, and IObjectMessages. Used as default by NmsTemplate, for - /// ConvertAndSend and ReceiveAndConvert operations. - /// - ///

Converts a String to a NMS ITextMessage, a byte array to a NMS IBytesMessage, - /// a Map to a NMS IMapMessage, and a Serializable object to a NMS IObjectMessage - /// (or vice versa).

- /// - /// + /// Convert a .NET object to a NMS Message using the supplied session + /// to create the message object. /// - /// Juergen Hoeller - /// Mark Pollack (.NET) - public class SimpleMessageConverter : IMessageConverter + /// the object to convert + /// + /// the Session to use for creating a NMS Message + /// + /// the NMS Message + /// + /// NMSException if thrown by NMS API methods + /// MessageConversionException in case of conversion failure + public IMessage ToMessage(object objectToConvert, ISession session) { - /// Convert a .NET object to a NMS Message using the supplied session - /// to create the message object. - /// - /// the object to convert - /// - /// the Session to use for creating a NMS Message - /// - /// the NMS Message - /// - /// NMSException if thrown by NMS API methods - /// MessageConversionException in case of conversion failure - public IMessage ToMessage(object objectToConvert, ISession session) + if (objectToConvert is IMessage) { - if (objectToConvert is IMessage) - { - return (IMessage) objectToConvert; - } - else if (objectToConvert is string) - { - return CreateMessageForString((string) objectToConvert, session); - } - else if (objectToConvert is sbyte[]) - { - return CreateMessageForByteArray((byte[]) objectToConvert, session); - } - else if (objectToConvert is IDictionary) - { - return CreateMessageForMap((IDictionary) objectToConvert, session); - } - else if (objectToConvert != null && objectToConvert.GetType().IsSerializable) - { - return - CreateMessageForSerializable(objectToConvert, session); - } - else - { - throw new MessageConversionException("Cannot convert object [" + objectToConvert + "] to NMS message"); - } + return (IMessage) objectToConvert; } - - /// Convert from a NMS Message to a .NET object. - /// the message to convert - /// - /// the converted .NET object - /// - /// MessageConversionException in case of conversion failure - public object FromMessage(IMessage messageToConvert) + else if (objectToConvert is string) { - if (messageToConvert is ITextMessage) - { - return ExtractStringFromMessage((ITextMessage) messageToConvert); - } - else if (messageToConvert is IBytesMessage) - { - return ExtractByteArrayFromMessage((IBytesMessage) messageToConvert); - } - else if (messageToConvert is IMapMessage) - { - return ExtractMapFromMessage((IMapMessage) messageToConvert); - } - else if (messageToConvert is IObjectMessage) - { - return ExtractSerializableFromMessage((IObjectMessage) messageToConvert); - } - else - { - return messageToConvert; - } + return CreateMessageForString((string) objectToConvert, session); } - - #region To Converter Methods - - /// Create a NMS ITextMessage for the given String. - /// the String to convert - /// - /// current NMS session - /// - /// the resulting message - /// - /// NMSException if thrown by NMS methods - protected virtual ITextMessage CreateMessageForString(string text, ISession session) + else if (objectToConvert is sbyte[]) { - return session.CreateTextMessage((text)); + return CreateMessageForByteArray((byte[]) objectToConvert, session); } - - /// Create a NMS IBytesMessage for the given byte array. - /// the byyte array to convert - /// - /// current NMS session - /// - /// the resulting message - /// - /// NMSException if thrown by NMS methods - protected virtual IBytesMessage CreateMessageForByteArray(byte[] bytes, ISession session) + else if (objectToConvert is IDictionary) { - IBytesMessage message = session.CreateBytesMessage(); - message.Content = bytes; - return message; + return CreateMessageForMap((IDictionary) objectToConvert, session); } - - /// Create a NMS IMapMessage for the given Map. - /// the Map to convert - /// - /// current NMS session - /// - /// the resulting message - /// - /// NMSException if thrown by NMS methods - protected virtual IMapMessage CreateMessageForMap(IDictionary map, ISession session) + else if (objectToConvert != null && objectToConvert.GetType().IsSerializable) { - IMapMessage mapMessage = session.CreateMapMessage(); - foreach (DictionaryEntry entry in map) - { - if (!(entry.Key is string)) - { - //UPGRADE_TODO: The equivalent in .NET for method 'java.lang.Class.getName' may return a different value. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1043'" - throw new MessageConversionException("Cannot convert non-String key of type [" + - (entry.Key != null ? entry.Key.GetType().FullName : null) + - "] to IMapMessage entry"); - } - mapMessage.Body[entry.Key.ToString()] = entry.Value; - } - return mapMessage; + return + CreateMessageForSerializable(objectToConvert, session); } - - /// Create a NMS IObjectMessage for the given Serializable object. - /// the Serializable object to convert - /// - /// current NMS session - /// - /// the resulting message - /// - /// NMSException if thrown by NMS methods - protected virtual IObjectMessage CreateMessageForSerializable( - object objectToSend, ISession session) + else { - return session.CreateObjectMessage(objectToSend); + throw new MessageConversionException("Cannot convert object [" + objectToConvert + "] to NMS message"); } - - #endregion - - #region From Converter Mehtods - - /// Extract a String from the given ITextMessage. - /// the message to convert - /// - /// the resulting String - /// - /// NMSException if thrown by NMS methods - protected virtual string ExtractStringFromMessage(ITextMessage message) - { - return message.Text; - } - - /// Extract a byte array from the given IBytesMessage. - /// the message to convert - /// - /// the resulting byte array - /// - /// NMSException if thrown by NMS methods - protected virtual byte[] ExtractByteArrayFromMessage(IBytesMessage message) - { - return message.Content; - } - - /// Extract a IDictionary from the given IMapMessage. - /// the message to convert - /// - /// the resulting Map - /// - /// NMSException if thrown by NMS methods - protected virtual IDictionary ExtractMapFromMessage(IMapMessage message) - { - IDictionary dictionary = new Hashtable(); - IEnumerator e = message.Body.Keys.GetEnumerator(); - while (e.MoveNext()) - { - String key = (String) e.Current; - dictionary.Add(key, message.Body[key]); - } - return dictionary; - } - - /// - /// Extracts the serializable object from the given object message. - /// - /// The message to convert. - /// The resulting serializable object. - protected virtual object ExtractSerializableFromMessage( - IObjectMessage message) - { - return message.Body; - } - - #endregion } -} + + /// Convert from a NMS Message to a .NET object. + /// the message to convert + /// + /// the converted .NET object + /// + /// MessageConversionException in case of conversion failure + public object FromMessage(IMessage messageToConvert) + { + if (messageToConvert is ITextMessage) + { + return ExtractStringFromMessage((ITextMessage) messageToConvert); + } + else if (messageToConvert is IBytesMessage) + { + return ExtractByteArrayFromMessage((IBytesMessage) messageToConvert); + } + else if (messageToConvert is IMapMessage) + { + return ExtractMapFromMessage((IMapMessage) messageToConvert); + } + else if (messageToConvert is IObjectMessage) + { + return ExtractSerializableFromMessage((IObjectMessage) messageToConvert); + } + else + { + return messageToConvert; + } + } + + #region To Converter Methods + + /// Create a NMS ITextMessage for the given String. + /// the String to convert + /// + /// current NMS session + /// + /// the resulting message + /// + /// NMSException if thrown by NMS methods + protected virtual ITextMessage CreateMessageForString(string text, ISession session) + { + return session.CreateTextMessage((text)); + } + + /// Create a NMS IBytesMessage for the given byte array. + /// the byyte array to convert + /// + /// current NMS session + /// + /// the resulting message + /// + /// NMSException if thrown by NMS methods + protected virtual IBytesMessage CreateMessageForByteArray(byte[] bytes, ISession session) + { + IBytesMessage message = session.CreateBytesMessage(); + message.Content = bytes; + return message; + } + + /// Create a NMS IMapMessage for the given Map. + /// the Map to convert + /// + /// current NMS session + /// + /// the resulting message + /// + /// NMSException if thrown by NMS methods + protected virtual IMapMessage CreateMessageForMap(IDictionary map, ISession session) + { + IMapMessage mapMessage = session.CreateMapMessage(); + foreach (DictionaryEntry entry in map) + { + if (!(entry.Key is string)) + { + //UPGRADE_TODO: The equivalent in .NET for method 'java.lang.Class.getName' may return a different value. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1043'" + throw new MessageConversionException("Cannot convert non-String key of type [" + + (entry.Key != null ? entry.Key.GetType().FullName : null) + + "] to IMapMessage entry"); + } + + mapMessage.Body[entry.Key.ToString()] = entry.Value; + } + + return mapMessage; + } + + /// Create a NMS IObjectMessage for the given Serializable object. + /// the Serializable object to convert + /// + /// current NMS session + /// + /// the resulting message + /// + /// NMSException if thrown by NMS methods + protected virtual IObjectMessage CreateMessageForSerializable( + object objectToSend, ISession session) + { + return session.CreateObjectMessage(objectToSend); + } + + #endregion + + #region From Converter Mehtods + + /// Extract a String from the given ITextMessage. + /// the message to convert + /// + /// the resulting String + /// + /// NMSException if thrown by NMS methods + protected virtual string ExtractStringFromMessage(ITextMessage message) + { + return message.Text; + } + + /// Extract a byte array from the given IBytesMessage. + /// the message to convert + /// + /// the resulting byte array + /// + /// NMSException if thrown by NMS methods + protected virtual byte[] ExtractByteArrayFromMessage(IBytesMessage message) + { + return message.Content; + } + + /// Extract a IDictionary from the given IMapMessage. + /// the message to convert + /// + /// the resulting Map + /// + /// NMSException if thrown by NMS methods + protected virtual IDictionary ExtractMapFromMessage(IMapMessage message) + { + IDictionary dictionary = new Hashtable(); + IEnumerator e = message.Body.Keys.GetEnumerator(); + while (e.MoveNext()) + { + String key = (String) e.Current; + dictionary.Add(key, message.Body[key]); + } + + return dictionary; + } + + /// + /// Extracts the serializable object from the given object message. + /// + /// The message to convert. + /// The resulting serializable object. + protected virtual object ExtractSerializableFromMessage( + IObjectMessage message) + { + return message.Body; + } + + #endregion +} \ No newline at end of file diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/Converter/TypeMapper.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/Converter/TypeMapper.cs index bed1788b..7efb4ca1 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/Converter/TypeMapper.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/Converter/TypeMapper.cs @@ -21,215 +21,214 @@ using System.Collections; using Spring.Core.TypeResolution; -namespace Spring.Messaging.Nms.Support.Converter +namespace Spring.Messaging.Nms.Support.Converter; + +/// +/// Provides a layer of indirection when adding the 'type' of the object as a message property. +/// +public class TypeMapper : ITypeMapper { + private string defaultNamespace; + private string defaultAssemblyName; + + //Generics not used to support both 1.1 and 2.0 + private IDictionary idTypeMapping; + private IDictionary typeIdMapping; + + private string defaultHashtableTypeId = "Hashtable"; + + private Type defaultHashtableClass = typeof(Hashtable); + private bool useAssemblyQualifiedName; + /// - /// Provides a layer of indirection when adding the 'type' of the object as a message property. + /// Initializes a new instance of the [ERROR: invalid expression DeclaringTypeKind]. /// - public class TypeMapper : ITypeMapper + public TypeMapper() { - private string defaultNamespace; - private string defaultAssemblyName; + idTypeMapping = new Hashtable(); + typeIdMapping = new Hashtable(); + } - //Generics not used to support both 1.1 and 2.0 - private IDictionary idTypeMapping; - private IDictionary typeIdMapping; + /// + /// Gets or sets the id type mapping. + /// + /// The id type mapping. + public IDictionary IdTypeMapping + { + get { return idTypeMapping; } + set { idTypeMapping = value; } + } - private string defaultHashtableTypeId = "Hashtable"; + /// + /// Gets the name of the field in the message that has type information.. + /// + /// The name of the type id field. + public string TypeIdFieldName + { + get { return "__TypeId__"; } + } - private Type defaultHashtableClass = typeof(Hashtable); - private bool useAssemblyQualifiedName; + /// + /// Sets the default hashtable class. + /// + /// The default hashtable class. + public Type DefaultHashtableClass + { + set { defaultHashtableClass = value; } + } - /// - /// Initializes a new instance of the [ERROR: invalid expression DeclaringTypeKind]. - /// - public TypeMapper() + /// + /// Convert from a type to a string. + /// + /// The type of object to convert. + /// + public string FromType(Type typeOfObjectToConvert) + { + if (typeIdMapping.Contains(typeOfObjectToConvert)) { - idTypeMapping = new Hashtable(); - typeIdMapping = new Hashtable(); + return typeIdMapping[typeOfObjectToConvert] as string; } - - - /// - /// Gets or sets the id type mapping. - /// - /// The id type mapping. - public IDictionary IdTypeMapping + else { - get { return idTypeMapping; } - set { idTypeMapping = value; } - } - - /// - /// Gets the name of the field in the message that has type information.. - /// - /// The name of the type id field. - public string TypeIdFieldName - { - get { return "__TypeId__"; } - } - - - /// - /// Sets the default hashtable class. - /// - /// The default hashtable class. - public Type DefaultHashtableClass - { - set { defaultHashtableClass = value; } - } - - /// - /// Convert from a type to a string. - /// - /// The type of object to convert. - /// - public string FromType(Type typeOfObjectToConvert) - { - - if (typeIdMapping.Contains(typeOfObjectToConvert)) + if (typeof(IDictionary).IsAssignableFrom(typeOfObjectToConvert)) { - return typeIdMapping[typeOfObjectToConvert] as string; + return defaultHashtableTypeId; + } + + if (UseAssemblyQualifiedName) + { + return typeOfObjectToConvert.AssemblyQualifiedName; } else { - if ( typeof (IDictionary).IsAssignableFrom(typeOfObjectToConvert)) - { - return defaultHashtableTypeId; - } - if (UseAssemblyQualifiedName) - { - return typeOfObjectToConvert.AssemblyQualifiedName; - } - else - { - return typeOfObjectToConvert.Name; - } + return typeOfObjectToConvert.Name; } } - - /// - /// Gets or sets a value indicating whether use the assembly qualified name when creating a string from a type reference. - /// - /// - /// By setting this property to true you will be able to easily share types that are available on both the publisher and - /// consumer with minimal configuration. However, this means that the publishers and subscribers would be tightly coupled - /// despite the use of loosely coupled messaging middleware. - /// - /// - /// true if to the assembly qualified name; otherwise, false. - /// - public bool UseAssemblyQualifiedName - { - get { - return useAssemblyQualifiedName; - } - set { - useAssemblyQualifiedName = value; - } - } - - /// - /// Convert from a string to a type. Will look into the IdTypeMapping dictionary first to resolve the - /// type, then check if it is the well known typeId of 'Hashtable' followed by a strategy to resolve a fully qualfied - /// name from a simple type name. This strategy requires that - /// - /// The type id. - /// The type associated with the string. - /// If the type can not be resolved. - public Type ToType(string typeId) - { - if (idTypeMapping.Contains(typeId)) - { - return idTypeMapping[typeId] as Type; - } - else - { - if (typeId.Equals(defaultHashtableTypeId)) - { - return defaultHashtableClass; - } - if (defaultNamespace != null) - { - string fullyQualifiedTypeName = defaultNamespace + "." + - typeId + ", " + - DefaultAssemblyName; - return TypeResolutionUtils.ResolveType(fullyQualifiedTypeName); - } - - return TypeResolutionUtils.ResolveType(typeId); - } - - } - - /// - /// Gets or sets the default namespace. - /// - /// The default namespace. - public string DefaultNamespace - { - get - { - return defaultNamespace; - } - set - { - defaultNamespace = value; - } - - } - - /// - /// Gets or sets the default name of the assembly. - /// - /// The default name of the assembly. - public string DefaultAssemblyName - { - get - { - return defaultAssemblyName; - } - set - { - defaultAssemblyName = value; - } - } - - /// - /// Afters the properties set. - /// - public void AfterPropertiesSet() - { - ValidateIdTypeMapping(); - if (DefaultAssemblyName != null && DefaultNamespace == null) - { - throw new ArgumentException("Default Namespace required when DefaultAssemblyName is set."); - } - if (DefaultNamespace != null && DefaultAssemblyName == null) - { - throw new ArgumentException("Default Assembly Name required when DefaultNamespace is set."); - } - } - - - private void ValidateIdTypeMapping() - { - IDictionary finalIdTypeMapping = new Hashtable(); - foreach (DictionaryEntry entry in idTypeMapping) - { - string id = entry.Key.ToString(); - Type t = entry.Value as Type; - if (t == null) - { - //convert from string value. - string typeName = entry.Value.ToString(); - t = TypeResolutionUtils.ResolveType(typeName); - } - finalIdTypeMapping.Add(id,t); - typeIdMapping.Add(t,id); - - } - idTypeMapping = finalIdTypeMapping; - } + } + + /// + /// Gets or sets a value indicating whether use the assembly qualified name when creating a string from a type reference. + /// + /// + /// By setting this property to true you will be able to easily share types that are available on both the publisher and + /// consumer with minimal configuration. However, this means that the publishers and subscribers would be tightly coupled + /// despite the use of loosely coupled messaging middleware. + /// + /// + /// true if to the assembly qualified name; otherwise, false. + /// + public bool UseAssemblyQualifiedName + { + get + { + return useAssemblyQualifiedName; + } + set + { + useAssemblyQualifiedName = value; + } + } + + /// + /// Convert from a string to a type. Will look into the IdTypeMapping dictionary first to resolve the + /// type, then check if it is the well known typeId of 'Hashtable' followed by a strategy to resolve a fully qualfied + /// name from a simple type name. This strategy requires that + /// + /// The type id. + /// The type associated with the string. + /// If the type can not be resolved. + public Type ToType(string typeId) + { + if (idTypeMapping.Contains(typeId)) + { + return idTypeMapping[typeId] as Type; + } + else + { + if (typeId.Equals(defaultHashtableTypeId)) + { + return defaultHashtableClass; + } + + if (defaultNamespace != null) + { + string fullyQualifiedTypeName = defaultNamespace + "." + + typeId + ", " + + DefaultAssemblyName; + return TypeResolutionUtils.ResolveType(fullyQualifiedTypeName); + } + + return TypeResolutionUtils.ResolveType(typeId); + } + } + + /// + /// Gets or sets the default namespace. + /// + /// The default namespace. + public string DefaultNamespace + { + get + { + return defaultNamespace; + } + set + { + defaultNamespace = value; + } + } + + /// + /// Gets or sets the default name of the assembly. + /// + /// The default name of the assembly. + public string DefaultAssemblyName + { + get + { + return defaultAssemblyName; + } + set + { + defaultAssemblyName = value; + } + } + + /// + /// Afters the properties set. + /// + public void AfterPropertiesSet() + { + ValidateIdTypeMapping(); + if (DefaultAssemblyName != null && DefaultNamespace == null) + { + throw new ArgumentException("Default Namespace required when DefaultAssemblyName is set."); + } + + if (DefaultNamespace != null && DefaultAssemblyName == null) + { + throw new ArgumentException("Default Assembly Name required when DefaultNamespace is set."); + } + } + + private void ValidateIdTypeMapping() + { + IDictionary finalIdTypeMapping = new Hashtable(); + foreach (DictionaryEntry entry in idTypeMapping) + { + string id = entry.Key.ToString(); + Type t = entry.Value as Type; + if (t == null) + { + //convert from string value. + string typeName = entry.Value.ToString(); + t = TypeResolutionUtils.ResolveType(typeName); + } + + finalIdTypeMapping.Add(id, t); + typeIdMapping.Add(t, id); + } + + idTypeMapping = finalIdTypeMapping; } } diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/Converter/XmlMessageConverter.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/Converter/XmlMessageConverter.cs index 87864e7f..7e77a5a7 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/Converter/XmlMessageConverter.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/Converter/XmlMessageConverter.cs @@ -4,193 +4,194 @@ using System.Xml; using System.Xml.Serialization; using Apache.NMS; -namespace Spring.Messaging.Nms.Support.Converter +namespace Spring.Messaging.Nms.Support.Converter; + +/// +/// Convert an object via XML serialization for sending via an ITextMessage +/// +/// Mark Pollack +public class XmlMessageConverter : IMessageConverter { + private IMessageConverter defaultMessageConverter = new SimpleMessageConverter(); + + private ITypeMapper typeMapper = new TypeMapper(); + + private bool encoderShouldEmitUTF8Identifier = false; + + private bool throwOnInvalidBytes = true; + /// - /// Convert an object via XML serialization for sending via an ITextMessage + /// Sets the type mapper. /// - /// Mark Pollack - public class XmlMessageConverter : IMessageConverter + /// The type mapper. + public ITypeMapper TypeMapper { - private IMessageConverter defaultMessageConverter = new SimpleMessageConverter(); + set { typeMapper = value; } + } + /// + /// Gets or sets a value indicating whether encoder should emit UTF8 byte order mark. Default is false. + /// + /// + /// true to specify that a Unicode byte order mark is provided; otherwise, false. + /// + public bool EncoderShouldEmitUtf8Identifier + { + get { return encoderShouldEmitUTF8Identifier; } + set { encoderShouldEmitUTF8Identifier = value; } + } - private ITypeMapper typeMapper = new TypeMapper(); + /// + /// Gets or sets a value indicating whether to throw an exception on invalid bytes. Default is true. + /// + /// true to specify that an exception be thrown when an invalid encoding is detected; otherwise, false. + /// + public bool ThrowOnInvalidBytes + { + get { return throwOnInvalidBytes; } + set { throwOnInvalidBytes = value; } + } - private bool encoderShouldEmitUTF8Identifier = false; - - private bool throwOnInvalidBytes = true; - - - /// - /// Sets the type mapper. - /// - /// The type mapper. - public ITypeMapper TypeMapper + /// + /// Convert a .NET object to a NMS Message using the supplied session + /// to create the message object. + /// + /// the object to convert + /// the Session to use for creating a NMS Message + /// the NMS Message + /// NMSException if thrown by NMS API methods + /// MessageConversionException in case of conversion failure + public IMessage ToMessage(object objectToConvert, ISession session) + { + if (objectToConvert == null) { - set { typeMapper = value; } + throw new MessageConversionException("Can't convert null object"); } - /// - /// Gets or sets a value indicating whether encoder should emit UTF8 byte order mark. Default is false. - /// - /// - /// true to specify that a Unicode byte order mark is provided; otherwise, false. - /// - public bool EncoderShouldEmitUtf8Identifier + try { - get { return encoderShouldEmitUTF8Identifier; } - set { encoderShouldEmitUTF8Identifier = value; } - } - - /// - /// Gets or sets a value indicating whether to throw an exception on invalid bytes. Default is true. - /// - /// true to specify that an exception be thrown when an invalid encoding is detected; otherwise, false. - /// - public bool ThrowOnInvalidBytes - { - get { return throwOnInvalidBytes; } - set { throwOnInvalidBytes = value; } - } - - /// - /// Convert a .NET object to a NMS Message using the supplied session - /// to create the message object. - /// - /// the object to convert - /// the Session to use for creating a NMS Message - /// the NMS Message - /// NMSException if thrown by NMS API methods - /// MessageConversionException in case of conversion failure - public IMessage ToMessage(object objectToConvert, ISession session) - { - if (objectToConvert == null) + if (objectToConvert.GetType().Equals(typeof(string)) || + typeof(IDictionary).IsAssignableFrom(objectToConvert.GetType()) || + objectToConvert.GetType().Equals(typeof(Byte[]))) { - throw new MessageConversionException("Can't convert null object"); - } - try - { - if (objectToConvert.GetType().Equals(typeof (string)) || - typeof (IDictionary).IsAssignableFrom(objectToConvert.GetType()) || - objectToConvert.GetType().Equals(typeof (Byte[]))) - { - return defaultMessageConverter.ToMessage(objectToConvert, session); - } - string xmlString = GetXmlString(objectToConvert); - IMessage msg = session.CreateTextMessage(xmlString); - msg.Properties.SetString(typeMapper.TypeIdFieldName, typeMapper.FromType(objectToConvert.GetType())); - return msg; - } catch (Exception e) - { - throw new MessageConversionException("Can't convert object of type " + objectToConvert.GetType(), e); + return defaultMessageConverter.ToMessage(objectToConvert, session); } + + string xmlString = GetXmlString(objectToConvert); + IMessage msg = session.CreateTextMessage(xmlString); + msg.Properties.SetString(typeMapper.TypeIdFieldName, typeMapper.FromType(objectToConvert.GetType())); + return msg; } - - /// - /// Gets the XML string for an object - /// - /// The object to convert. - /// XML string - protected virtual string GetXmlString(object objectToConvert) + catch (Exception e) { - string xmlString; - try - { - using (MemoryStream memoryStream = new MemoryStream()) - { - using (XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, new UTF8Encoding(EncoderShouldEmitUtf8Identifier))) - { - XmlSerializer xs = new XmlSerializer(objectToConvert.GetType()); - xs.Serialize(xmlTextWriter, objectToConvert); - xmlString = UTF8ByteArrayToString(((MemoryStream)xmlTextWriter.BaseStream).ToArray()); - } - } - } - catch (Exception e) - { - throw new MessageConversionException("Can't convert object of type " + objectToConvert.GetType(), e); - } - return xmlString; - } - - /// - /// Convert from a NMS Message to a .NET object. - /// - /// the message to convert - /// the converted .NET object - /// MessageConversionException in case of conversion failure - public object FromMessage(IMessage messageToConvert) - { - if (messageToConvert == null) - { - throw new MessageConversionException("Can't convert null message"); - } - try - { - string converterId = messageToConvert.Properties.GetString(typeMapper.TypeIdFieldName); - if (converterId == null) - { - return defaultMessageConverter.FromMessage(messageToConvert); - } - ITextMessage textMessage = messageToConvert as ITextMessage; - if (textMessage == null) - { - throw new MessageConversionException("Can't convert message of type " + - messageToConvert.GetType()); - } - - using (MemoryStream memoryStream = new MemoryStream(StringToUTF8ByteArray(textMessage.Text))) - { - - XmlSerializer xs = new XmlSerializer(GetTargetType(textMessage)); - XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.UTF8); - return xs.Deserialize(memoryStream); - } - } catch (Exception e) - { - throw new MessageConversionException("Can't convert message of type " + messageToConvert.GetType(), e); - } - } - - /// - /// Gets the type of the target given the message. - /// - /// The message. - /// Type of the target - protected virtual Type GetTargetType(ITextMessage message) - { - return typeMapper.ToType(message.Properties.GetString(typeMapper.TypeIdFieldName)); - } - - - /// - /// Converts a byte array to a UTF8 string. - /// - /// The characters. - /// UTF8 string - protected virtual String UTF8ByteArrayToString(Byte[] characters) - { - UTF8Encoding encoding = new UTF8Encoding(EncoderShouldEmitUtf8Identifier, ThrowOnInvalidBytes); - - String constructedString = encoding.GetString(characters); - - return (constructedString); - } - - - /// - /// Converts a UTF8 string to a byte array - /// - /// The p XML string. - /// - protected virtual Byte[] StringToUTF8ByteArray(String xmlString) - { - UTF8Encoding encoding = new UTF8Encoding(); - - Byte[] byteArray = encoding.GetBytes(xmlString); - - return byteArray; + throw new MessageConversionException("Can't convert object of type " + objectToConvert.GetType(), e); } } + + /// + /// Gets the XML string for an object + /// + /// The object to convert. + /// XML string + protected virtual string GetXmlString(object objectToConvert) + { + string xmlString; + try + { + using (MemoryStream memoryStream = new MemoryStream()) + { + using (XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, new UTF8Encoding(EncoderShouldEmitUtf8Identifier))) + { + XmlSerializer xs = new XmlSerializer(objectToConvert.GetType()); + xs.Serialize(xmlTextWriter, objectToConvert); + xmlString = UTF8ByteArrayToString(((MemoryStream) xmlTextWriter.BaseStream).ToArray()); + } + } + } + catch (Exception e) + { + throw new MessageConversionException("Can't convert object of type " + objectToConvert.GetType(), e); + } + + return xmlString; + } + + /// + /// Convert from a NMS Message to a .NET object. + /// + /// the message to convert + /// the converted .NET object + /// MessageConversionException in case of conversion failure + public object FromMessage(IMessage messageToConvert) + { + if (messageToConvert == null) + { + throw new MessageConversionException("Can't convert null message"); + } + + try + { + string converterId = messageToConvert.Properties.GetString(typeMapper.TypeIdFieldName); + if (converterId == null) + { + return defaultMessageConverter.FromMessage(messageToConvert); + } + + ITextMessage textMessage = messageToConvert as ITextMessage; + if (textMessage == null) + { + throw new MessageConversionException("Can't convert message of type " + + messageToConvert.GetType()); + } + + using (MemoryStream memoryStream = new MemoryStream(StringToUTF8ByteArray(textMessage.Text))) + { + XmlSerializer xs = new XmlSerializer(GetTargetType(textMessage)); + XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.UTF8); + return xs.Deserialize(memoryStream); + } + } + catch (Exception e) + { + throw new MessageConversionException("Can't convert message of type " + messageToConvert.GetType(), e); + } + } + + /// + /// Gets the type of the target given the message. + /// + /// The message. + /// Type of the target + protected virtual Type GetTargetType(ITextMessage message) + { + return typeMapper.ToType(message.Properties.GetString(typeMapper.TypeIdFieldName)); + } + + /// + /// Converts a byte array to a UTF8 string. + /// + /// The characters. + /// UTF8 string + protected virtual String UTF8ByteArrayToString(Byte[] characters) + { + UTF8Encoding encoding = new UTF8Encoding(EncoderShouldEmitUtf8Identifier, ThrowOnInvalidBytes); + + String constructedString = encoding.GetString(characters); + + return (constructedString); + } + + /// + /// Converts a UTF8 string to a byte array + /// + /// The p XML string. + /// + protected virtual Byte[] StringToUTF8ByteArray(String xmlString) + { + UTF8Encoding encoding = new UTF8Encoding(); + + Byte[] byteArray = encoding.GetBytes(xmlString); + + return byteArray; + } } diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/Destinations/DynamicDestinationResolver.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/Destinations/DynamicDestinationResolver.cs index 6f2d44e0..005b0066 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/Destinations/DynamicDestinationResolver.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/Destinations/DynamicDestinationResolver.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -21,66 +21,64 @@ using Spring.Util; using Apache.NMS; -namespace Spring.Messaging.Nms.Support.Destinations +namespace Spring.Messaging.Nms.Support.Destinations; + +/// Simple DestinationResolver implementation resolving destination names +/// as dynamic destinations. +/// +/// Juergen Hoeller +/// Mark Pollack (.NET) +public class DynamicDestinationResolver : IDestinationResolver { - /// Simple DestinationResolver implementation resolving destination names - /// as dynamic destinations. - /// - /// Juergen Hoeller - /// Mark Pollack (.NET) - public class DynamicDestinationResolver : IDestinationResolver + /// Resolve the given destination name, either as located resource + /// or as dynamic destination. + /// + /// the current NMS Session + /// + /// the name of the destination + /// + /// true if the domain is pub-sub, false if P2P + /// + /// the NMS destination (either a topic or a queue) + /// + /// NMSException if resolution failed + public IDestination ResolveDestinationName(ISession session, string destinationName, bool pubSubDomain) { - /// Resolve the given destination name, either as located resource - /// or as dynamic destination. - /// - /// the current NMS Session - /// - /// the name of the destination - /// - /// true if the domain is pub-sub, false if P2P - /// - /// the NMS destination (either a topic or a queue) - /// - /// NMSException if resolution failed - public IDestination ResolveDestinationName(ISession session, string destinationName, bool pubSubDomain) + AssertUtils.ArgumentNotNull(session, "ISession must not be null"); + AssertUtils.ArgumentNotNull(destinationName, "IDestination name must not be null"); + if (pubSubDomain) { - AssertUtils.ArgumentNotNull(session, "ISession must not be null"); - AssertUtils.ArgumentNotNull(destinationName, "IDestination name must not be null"); - if (pubSubDomain) - { - return ResolveTopic(session, destinationName); - } - else - { - return ResolveQueue(session, destinationName); - } + return ResolveTopic(session, destinationName); } - - - /// Resolve the given destination name to a Topic. - /// the current NMS Session - /// - /// the name of the desired Topic. - /// - /// the NMS Topic name - /// - /// NMSException if resolution failed - protected internal virtual IDestination ResolveTopic(ISession session, System.String topicName) + else { - return session.GetTopic(topicName); - } - - /// Resolve the given destination name to a Queue. - /// the current NMS Session - /// - /// the name of the desired Queue. - /// - /// the NMS Queue name - /// - /// NMSException if resolution failed - protected internal virtual IDestination ResolveQueue(ISession session, string queueName) - { - return session.GetQueue(queueName); + return ResolveQueue(session, destinationName); } } + + /// Resolve the given destination name to a Topic. + /// the current NMS Session + /// + /// the name of the desired Topic. + /// + /// the NMS Topic name + /// + /// NMSException if resolution failed + protected internal virtual IDestination ResolveTopic(ISession session, System.String topicName) + { + return session.GetTopic(topicName); + } + + /// Resolve the given destination name to a Queue. + /// the current NMS Session + /// + /// the name of the desired Queue. + /// + /// the NMS Queue name + /// + /// NMSException if resolution failed + protected internal virtual IDestination ResolveQueue(ISession session, string queueName) + { + return session.GetQueue(queueName); + } } diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/Destinations/IDestinationResolver.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/Destinations/IDestinationResolver.cs index 61226255..5b129be6 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/Destinations/IDestinationResolver.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/Destinations/IDestinationResolver.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -20,39 +20,37 @@ using Apache.NMS; -namespace Spring.Messaging.Nms.Support.Destinations +namespace Spring.Messaging.Nms.Support.Destinations; + +/// Strategy interface for resolving NMS destinations. +/// +/// +/// Used by MessageTemplate for resolving +/// destination names from simple Strings to actual +/// IDestination implementation instances. +/// +/// +/// The default DestinationResolver implementation used by +/// MessageTemplate instances is the +/// DynamicDestinationResolver class. Consider using the +/// JndiDestinationResolver for more advanced scenarios. +/// +/// +/// Juergen Hoeller +/// Mark Pollack (.NET) +public interface IDestinationResolver { - /// Strategy interface for resolving NMS destinations. + /// Resolve the given destination name, either as located resource + /// or as dynamic destination. /// - /// - /// Used by MessageTemplate for resolving - /// destination names from simple Strings to actual - /// IDestination implementation instances. - /// - /// - /// The default DestinationResolver implementation used by - /// MessageTemplate instances is the - /// DynamicDestinationResolver class. Consider using the - /// JndiDestinationResolver for more advanced scenarios. - /// - /// - /// Juergen Hoeller - /// Mark Pollack (.NET) - public interface IDestinationResolver - { - /// Resolve the given destination name, either as located resource - /// or as dynamic destination. - /// - /// the current NMS Session - /// - /// the name of the destination - /// - /// true if the domain is pub-sub, false if P2P - /// - /// the NMS destination (either a topic or a queue) - /// - /// NMSException if resolution failed - IDestination ResolveDestinationName(ISession session, string destinationName, bool pubSubDomain); - - } + /// the current NMS Session + /// + /// the name of the destination + /// + /// true if the domain is pub-sub, false if P2P + /// + /// the NMS destination (either a topic or a queue) + /// + /// NMSException if resolution failed + IDestination ResolveDestinationName(ISession session, string destinationName, bool pubSubDomain); } diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/Destinations/NmsDestinationAccessor.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/Destinations/NmsDestinationAccessor.cs index bbfbdc75..c08ac6d8 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/Destinations/NmsDestinationAccessor.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/Destinations/NmsDestinationAccessor.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -21,90 +21,86 @@ using Spring.Util; using Apache.NMS; -namespace Spring.Messaging.Nms.Support.Destinations +namespace Spring.Messaging.Nms.Support.Destinations; + +/// Base class for NmsTemplate} and other +/// NMS-accessing gateway helpers, adding destination-related properties to +/// MessagingAccessor's common properties. +/// +/// +///

Not intended to be used directly. See NmsTemplate.

+/// +///
+/// Juergen Hoeller +/// Mark Pollack (.NET) +public class NmsDestinationAccessor : NmsAccessor { - /// Base class for NmsTemplate} and other - /// NMS-accessing gateway helpers, adding destination-related properties to - /// MessagingAccessor's common properties. + #region Fields + + private IDestinationResolver destinationResolver = new DynamicDestinationResolver(); + + private bool pubSubDomain = false; + + #endregion + + #region Properties + + /// + /// Gets or sets the destination resolver that is to be used to resolve + /// IDestination references for this accessor. /// - /// - ///

Not intended to be used directly. See NmsTemplate.

- /// + /// The default resolver is a DynamicDestinationResolver. Specify a + /// JndiDestinationResolver for resolving destination names as JNDI locations. /// - /// Juergen Hoeller - /// Mark Pollack (.NET) - public class NmsDestinationAccessor : NmsAccessor + /// The destination resolver. + virtual public IDestinationResolver DestinationResolver { - #region Fields - - private IDestinationResolver destinationResolver = new DynamicDestinationResolver(); - - private bool pubSubDomain = false; - - #endregion - - #region Properties - - /// - /// Gets or sets the destination resolver that is to be used to resolve - /// IDestination references for this accessor. - /// - /// The default resolver is a DynamicDestinationResolver. Specify a - /// JndiDestinationResolver for resolving destination names as JNDI locations. - /// - /// The destination resolver. - virtual public IDestinationResolver DestinationResolver + get { - get - { - return destinationResolver; - } - - set - { - AssertUtils.ArgumentNotNull(value, "DestinationResolver must not be null"); - this.destinationResolver = value; - } - + return destinationResolver; } - - /// - /// Gets or sets a value indicating whether Publish/Subscribe - /// domain (Topics) is used. Otherwise, the Point-to-Point domain - /// (Queues) is used. - /// - /// - /// this - /// setting tells what type of destination to create if dynamic destinations are enabled. - /// true if Publish/Subscribe domain; otherwise, false - /// for the Point-to-Point domain. - public virtual bool PubSubDomain + set { - get - { - return pubSubDomain; - } - - set - { - this.pubSubDomain = value; - } - - } - - #endregion - - /// - /// Resolves the given destination name to a NMS destination. - /// - /// The current session. - /// Name of the destination. - /// The located IDestination - /// If resolution failed. - public virtual IDestination ResolveDestinationName(ISession session, System.String destinationName) - { - return DestinationResolver.ResolveDestinationName(session, destinationName, PubSubDomain); + AssertUtils.ArgumentNotNull(value, "DestinationResolver must not be null"); + this.destinationResolver = value; } } + + /// + /// Gets or sets a value indicating whether Publish/Subscribe + /// domain (Topics) is used. Otherwise, the Point-to-Point domain + /// (Queues) is used. + /// + /// + /// this + /// setting tells what type of destination to create if dynamic destinations are enabled. + /// true if Publish/Subscribe domain; otherwise, false + /// for the Point-to-Point domain. + public virtual bool PubSubDomain + { + get + { + return pubSubDomain; + } + + set + { + this.pubSubDomain = value; + } + } + + #endregion + + /// + /// Resolves the given destination name to a NMS destination. + /// + /// The current session. + /// Name of the destination. + /// The located IDestination + /// If resolution failed. + public virtual IDestination ResolveDestinationName(ISession session, System.String destinationName) + { + return DestinationResolver.ResolveDestinationName(session, destinationName, PubSubDomain); + } } diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/Destinations/NmsDestinationAccessorAsync.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/Destinations/NmsDestinationAccessorAsync.cs index 7a3844e3..410a8bec 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/Destinations/NmsDestinationAccessorAsync.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/Destinations/NmsDestinationAccessorAsync.cs @@ -1,4 +1,5 @@ #region License + // /* // * Copyright 2022 the original author or authors. // * @@ -14,89 +15,86 @@ // * See the License for the specific language governing permissions and // * limitations under the License. // */ + #endregion using Apache.NMS; using Spring.Util; -namespace Spring.Messaging.Nms.Support.Destinations +namespace Spring.Messaging.Nms.Support.Destinations; + +/// +/// Async version of NmsDestinationAccessor +/// +/// +public class NmsDestinationAccessorAsync : NmsAccessorAsync { + #region Fields + + private IDestinationResolver destinationResolver = new DynamicDestinationResolver(); + + private bool pubSubDomain = false; + + #endregion + + #region Properties + /// - /// Async version of NmsDestinationAccessor + /// Gets or sets the destination resolver that is to be used to resolve + /// IDestination references for this accessor. /// - /// - public class NmsDestinationAccessorAsync : NmsAccessorAsync + /// The default resolver is a DynamicDestinationResolver. Specify a + /// JndiDestinationResolver for resolving destination names as JNDI locations. + /// + /// The destination resolver. + virtual public IDestinationResolver DestinationResolver { - #region Fields - - private IDestinationResolver destinationResolver = new DynamicDestinationResolver(); - - private bool pubSubDomain = false; - - #endregion - - #region Properties - - /// - /// Gets or sets the destination resolver that is to be used to resolve - /// IDestination references for this accessor. - /// - /// The default resolver is a DynamicDestinationResolver. Specify a - /// JndiDestinationResolver for resolving destination names as JNDI locations. - /// - /// The destination resolver. - virtual public IDestinationResolver DestinationResolver + get { - get - { - return destinationResolver; - } - - set - { - AssertUtils.ArgumentNotNull(value, "DestinationResolver must not be null"); - this.destinationResolver = value; - } - + return destinationResolver; } - - /// - /// Gets or sets a value indicating whether Publish/Subscribe - /// domain (Topics) is used. Otherwise, the Point-to-Point domain - /// (Queues) is used. - /// - /// - /// this - /// setting tells what type of destination to create if dynamic destinations are enabled. - /// true if Publish/Subscribe domain; otherwise, false - /// for the Point-to-Point domain. - public virtual bool PubSubDomain + set { - get - { - return pubSubDomain; - } - - set - { - this.pubSubDomain = value; - } - - } - - #endregion - - /// - /// Resolves the given destination name to a NMS destination. - /// - /// The current session. - /// Name of the destination. - /// The located IDestination - /// If resolution failed. - public virtual Task ResolveDestinationName(ISession session, System.String destinationName) - { - return Task.FromResult(DestinationResolver.ResolveDestinationName(session, destinationName, PubSubDomain)); + AssertUtils.ArgumentNotNull(value, "DestinationResolver must not be null"); + this.destinationResolver = value; } } -} \ No newline at end of file + + /// + /// Gets or sets a value indicating whether Publish/Subscribe + /// domain (Topics) is used. Otherwise, the Point-to-Point domain + /// (Queues) is used. + /// + /// + /// this + /// setting tells what type of destination to create if dynamic destinations are enabled. + /// true if Publish/Subscribe domain; otherwise, false + /// for the Point-to-Point domain. + public virtual bool PubSubDomain + { + get + { + return pubSubDomain; + } + + set + { + this.pubSubDomain = value; + } + } + + #endregion + + /// + /// Resolves the given destination name to a NMS destination. + /// + /// The current session. + /// Name of the destination. + /// The located IDestination + /// If resolution failed. + public virtual Task ResolveDestinationName(ISession session, System.String destinationName) + { + return Task.FromResult(DestinationResolver.ResolveDestinationName(session, destinationName, PubSubDomain)); + } +} diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/MessageUtils.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/MessageUtils.cs index 040f934e..e3a2d680 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/MessageUtils.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/MessageUtils.cs @@ -22,145 +22,145 @@ using Spring.Util; using Apache.NMS; using Microsoft.Extensions.Logging; -namespace Spring.Messaging.Nms.Support +namespace Spring.Messaging.Nms.Support; + +/// +/// Generic utility methods for working with NMS. Mainly for internal use +/// within the framework, but also useful for custom NMS access code. +/// +public abstract class NmsUtils { - /// - /// Generic utility methods for working with NMS. Mainly for internal use - /// within the framework, but also useful for custom NMS access code. + #region Logging + + private static readonly ILogger logger = LogManager.GetLogger(); + + #endregion + + /// Close the given NMS Connection and ignore any thrown exception. + /// This is useful for typical finally blocks in manual NMS code. /// - public abstract class NmsUtils + /// the NMS Connection to close (may be null) + /// + public static void CloseConnection(IConnection con) { - #region Logging + CloseConnection(con, false); + } - private static readonly ILogger logger = LogManager.GetLogger(); - - #endregion - - /// Close the given NMS Connection and ignore any thrown exception. - /// This is useful for typical finally blocks in manual NMS code. - /// - /// the NMS Connection to close (may be null) - /// - public static void CloseConnection(IConnection con) + /// Close the given NMS Connection and ignore any thrown exception. + /// This is useful for typical finally blocks in manual NMS code. + /// + /// the NMS Connection to close (may be null) + /// + /// whether to call stop() before closing + /// + public static void CloseConnection(IConnection con, bool stop) + { + if (con != null) { - CloseConnection(con, false); - } - - /// Close the given NMS Connection and ignore any thrown exception. - /// This is useful for typical finally blocks in manual NMS code. - /// - /// the NMS Connection to close (may be null) - /// - /// whether to call stop() before closing - /// - public static void CloseConnection(IConnection con, bool stop) - { - if (con != null) + try { - try + if (stop) { - if (stop) + try { - try - { - con.Stop(); - } - finally - { - con.Close(); - } + con.Stop(); } - else + finally { con.Close(); } } - catch (NMSException ex) + else { - logger.LogDebug(ex, "Could not close NMS Connection"); - } - catch (Exception ex) - { - // We don't trust the NMS provider: It might throw another exception. - logger.LogDebug(ex, "Unexpected exception on closing NMS Connection"); + con.Close(); } } - } - - /// Close the given NMS Session and ignore any thrown exception. - /// This is useful for typical finally blocks in manual NMS code. - /// - /// the NMS Session to close (may be null) - /// - public static void CloseSession(ISession session) - { - if (session != null) + catch (NMSException ex) { - try - { - session.Close(); - } - catch (NMSException ex) - { - logger.LogDebug(ex, "Could not close NMS ISession"); - } - catch (Exception ex) - { - // We don't trust the NMS provider: It might throw RuntimeException or Error. - logger.LogDebug(ex, "Unexpected exception on closing NMS ISession"); - } + logger.LogDebug(ex, "Could not close NMS Connection"); } - } - - /// Close the given NMS MessageProducer and ignore any thrown exception. - /// This is useful for typical finally blocks in manual NMS code. - /// - /// the NMS MessageProducer to close (may be null) - /// - public static void CloseMessageProducer(IMessageProducer producer) - { - if (producer != null) + catch (Exception ex) { - try - { - producer.Close(); - } - catch (NMSException ex) - { - logger.LogDebug(ex, "Could not close NMS MessageProducer"); - } - catch (Exception ex) - { - // We don't trust the NMS provider: It might throw RuntimeException or Error. - logger.LogDebug(ex, "Unexpected exception on closing NMS MessageProducer"); - } + // We don't trust the NMS provider: It might throw another exception. + logger.LogDebug(ex, "Unexpected exception on closing NMS Connection"); } } + } - /// Close the given NMS MessageConsumer and ignore any thrown exception. - /// This is useful for typical finally blocks in manual NMS code. - /// - /// the NMS MessageConsumer to close (may be null) - /// - public static void CloseMessageConsumer(IMessageConsumer consumer) + /// Close the given NMS Session and ignore any thrown exception. + /// This is useful for typical finally blocks in manual NMS code. + /// + /// the NMS Session to close (may be null) + /// + public static void CloseSession(ISession session) + { + if (session != null) { - if (consumer != null) + try { - try - { - consumer.Close(); - } - catch (NMSException ex) - { - logger.LogDebug(ex, "Could not close NMS MessageConsumer"); - } - catch (Exception ex) - { - // We don't trust the NMS provider: It might throw RuntimeException or Error. - logger.LogDebug(ex, "Unexpected exception on closing NMS MessageConsumer"); - } + session.Close(); + } + catch (NMSException ex) + { + logger.LogDebug(ex, "Could not close NMS ISession"); + } + catch (Exception ex) + { + // We don't trust the NMS provider: It might throw RuntimeException or Error. + logger.LogDebug(ex, "Unexpected exception on closing NMS ISession"); } } + } + + /// Close the given NMS MessageProducer and ignore any thrown exception. + /// This is useful for typical finally blocks in manual NMS code. + /// + /// the NMS MessageProducer to close (may be null) + /// + public static void CloseMessageProducer(IMessageProducer producer) + { + if (producer != null) + { + try + { + producer.Close(); + } + catch (NMSException ex) + { + logger.LogDebug(ex, "Could not close NMS MessageProducer"); + } + catch (Exception ex) + { + // We don't trust the NMS provider: It might throw RuntimeException or Error. + logger.LogDebug(ex, "Unexpected exception on closing NMS MessageProducer"); + } + } + } + + /// Close the given NMS MessageConsumer and ignore any thrown exception. + /// This is useful for typical finally blocks in manual NMS code. + /// + /// the NMS MessageConsumer to close (may be null) + /// + public static void CloseMessageConsumer(IMessageConsumer consumer) + { + if (consumer != null) + { + try + { + consumer.Close(); + } + catch (NMSException ex) + { + logger.LogDebug(ex, "Could not close NMS MessageConsumer"); + } + catch (Exception ex) + { + // We don't trust the NMS provider: It might throw RuntimeException or Error. + logger.LogDebug(ex, "Unexpected exception on closing NMS MessageConsumer"); + } + } + } /* /// Close the given NMS QueueRequestor and ignore any thrown exception. /// This is useful for typical finally blocks in manual NMS code. @@ -188,20 +188,19 @@ namespace Spring.Messaging.Nms.Support // } // } + /// Commit the Session if not within a distributed transaction. + /// Needs investigation - no distributed tx in .NET messaging providers + /// the NMS Session to commit + /// + /// NMSException if committing failed + public static void CommitIfNecessary(ISession session) + { + AssertUtils.ArgumentNotNull(session, "ISession must not be null"); - /// Commit the Session if not within a distributed transaction. - /// Needs investigation - no distributed tx in .NET messaging providers - /// the NMS Session to commit - /// - /// NMSException if committing failed - public static void CommitIfNecessary(ISession session) - { - AssertUtils.ArgumentNotNull(session, "ISession must not be null"); - - session.Commit(); + session.Commit(); + + // TODO Investigate - // TODO Investigate - // try { // session.Commit(); // } @@ -213,19 +212,19 @@ namespace Spring.Messaging.Nms.Support // // TODO Investigate // // Ignore -> can only happen in case of a JTA transaction. // } - } + } - /// Rollback the Session if not within a distributed transaction. - /// Needs investigation - no distributed tx in EMS - /// the NMS Session to rollback - /// - /// NMSException if committing failed - public static void RollbackIfNecessary(ISession session) - { - AssertUtils.ArgumentNotNull(session, "ISession must not be null"); - session.Rollback(); + /// Rollback the Session if not within a distributed transaction. + /// Needs investigation - no distributed tx in EMS + /// the NMS Session to rollback + /// + /// NMSException if committing failed + public static void RollbackIfNecessary(ISession session) + { + AssertUtils.ArgumentNotNull(session, "ISession must not be null"); + session.Rollback(); - // TODO Investigate + // TODO Investigate // try { // session.Rollback(); @@ -236,7 +235,5 @@ namespace Spring.Messaging.Nms.Support // catch (IllegalStateException ex) { // // Ignore -> can only happen in case of a JTA transaction. // } - } - } } diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/MessageUtilsAsync.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/MessageUtilsAsync.cs index 21c4cbe9..480b8a76 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/MessageUtilsAsync.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/MessageUtilsAsync.cs @@ -1,4 +1,5 @@ #region License + // /* // * Copyright 2022 the original author or authors. // * @@ -14,178 +15,174 @@ // * See the License for the specific language governing permissions and // * limitations under the License. // */ + #endregion using Spring.Util; using Apache.NMS; using Microsoft.Extensions.Logging; -namespace Spring.Messaging.Nms.Support +namespace Spring.Messaging.Nms.Support; + +/// +/// Async version of NmsUtils +/// +/// +public abstract class NmsUtilsAsync { - /// - /// Async version of NmsUtils + #region Logging + + private static readonly ILogger logger = LogManager.GetLogger(); + + #endregion + + /// Close the given NMS Connection and ignore any thrown exception. + /// This is useful for typical finally blocks in manual NMS code. /// - /// - public abstract class NmsUtilsAsync + /// the NMS Connection to close (may be null) + /// + public static Task CloseConnection(IConnection con) { - #region Logging + return CloseConnection(con, false); + } - private static readonly ILogger logger = LogManager.GetLogger(); - - #endregion - - /// Close the given NMS Connection and ignore any thrown exception. - /// This is useful for typical finally blocks in manual NMS code. - /// - /// the NMS Connection to close (may be null) - /// - public static Task CloseConnection(IConnection con) + /// Close the given NMS Connection and ignore any thrown exception. + /// This is useful for typical finally blocks in manual NMS code. + /// + /// the NMS Connection to close (may be null) + /// + /// whether to call stop() before closing + /// + public static async Task CloseConnection(IConnection con, bool stop) + { + if (con != null) { - return CloseConnection(con, false); - } - - /// Close the given NMS Connection and ignore any thrown exception. - /// This is useful for typical finally blocks in manual NMS code. - /// - /// the NMS Connection to close (may be null) - /// - /// whether to call stop() before closing - /// - public static async Task CloseConnection(IConnection con, bool stop) - { - if (con != null) + try { - try + if (stop) { - if (stop) + try { - try - { - await con.StopAsync().Awaiter(); - } - finally - { - await con.CloseAsync().Awaiter(); - } + await con.StopAsync().Awaiter(); } - else + finally { await con.CloseAsync().Awaiter(); } } - catch (NMSException ex) + else { - logger.LogDebug(ex, "Could not close NMS Connection"); - } - catch (Exception ex) - { - // We don't trust the NMS provider: It might throw another exception. - logger.LogDebug(ex, "Unexpected exception on closing NMS Connection"); + await con.CloseAsync().Awaiter(); } } - } - - /// Close the given NMS Session and ignore any thrown exception. - /// This is useful for typical finally blocks in manual NMS code. - /// - /// the NMS Session to close (may be null) - /// - public static async Task CloseSession(ISession session) - { - if (session != null) + catch (NMSException ex) { - try - { - await session.CloseAsync().Awaiter(); - } - catch (NMSException ex) - { - logger.LogDebug(ex, "Could not close NMS ISession"); - } - catch (Exception ex) - { - // We don't trust the NMS provider: It might throw RuntimeException or Error. - logger.LogDebug(ex, "Unexpected exception on closing NMS ISession"); - } + logger.LogDebug(ex, "Could not close NMS Connection"); } - } - - /// Close the given NMS MessageProducer and ignore any thrown exception. - /// This is useful for typical finally blocks in manual NMS code. - /// - /// the NMS MessageProducer to close (may be null) - /// - public static async Task CloseMessageProducer(IMessageProducer producer) - { - if (producer != null) + catch (Exception ex) { - try - { - await producer.CloseAsync().Awaiter(); - } - catch (NMSException ex) - { - logger.LogDebug(ex, "Could not close NMS MessageProducer"); - } - catch (Exception ex) - { - // We don't trust the NMS provider: It might throw RuntimeException or Error. - logger.LogDebug(ex, "Unexpected exception on closing NMS MessageProducer"); - } + // We don't trust the NMS provider: It might throw another exception. + logger.LogDebug(ex, "Unexpected exception on closing NMS Connection"); } } - - + } - /// Close the given NMS MessageConsumer and ignore any thrown exception. - /// This is useful for typical finally blocks in manual NMS code. - /// - /// the NMS MessageConsumer to close (may be null) - /// - public static async Task CloseMessageConsumer(IMessageConsumer consumer) + /// Close the given NMS Session and ignore any thrown exception. + /// This is useful for typical finally blocks in manual NMS code. + /// + /// the NMS Session to close (may be null) + /// + public static async Task CloseSession(ISession session) + { + if (session != null) { - if (consumer != null) + try { - try - { - await consumer.CloseAsync().Awaiter(); - } - catch (NMSException ex) - { - logger.LogDebug(ex, "Could not close NMS MessageConsumer"); - } - catch (Exception ex) - { - // We don't trust the NMS provider: It might throw RuntimeException or Error. - logger.LogDebug(ex, "Unexpected exception on closing NMS MessageConsumer"); - } + await session.CloseAsync().Awaiter(); + } + catch (NMSException ex) + { + logger.LogDebug(ex, "Could not close NMS ISession"); + } + catch (Exception ex) + { + // We don't trust the NMS provider: It might throw RuntimeException or Error. + logger.LogDebug(ex, "Unexpected exception on closing NMS ISession"); } } + } - - /// Commit the Session if not within a distributed transaction. - /// Needs investigation - no distributed tx in .NET messaging providers - /// the NMS Session to commit - /// - /// NMSException if committing failed - public static async Task CommitIfNecessary(ISession session) + /// Close the given NMS MessageProducer and ignore any thrown exception. + /// This is useful for typical finally blocks in manual NMS code. + /// + /// the NMS MessageProducer to close (may be null) + /// + public static async Task CloseMessageProducer(IMessageProducer producer) + { + if (producer != null) { - AssertUtils.ArgumentNotNull(session, "ISession must not be null"); - - await session.CommitAsync().Awaiter(); - } + try + { + await producer.CloseAsync().Awaiter(); + } + catch (NMSException ex) + { + logger.LogDebug(ex, "Could not close NMS MessageProducer"); + } + catch (Exception ex) + { + // We don't trust the NMS provider: It might throw RuntimeException or Error. + logger.LogDebug(ex, "Unexpected exception on closing NMS MessageProducer"); + } + } + } - /// Rollback the Session if not within a distributed transaction. - /// Needs investigation - no distributed tx in EMS - /// the NMS Session to rollback - /// - /// NMSException if committing failed - public static async Task RollbackIfNecessary(ISession session) + /// Close the given NMS MessageConsumer and ignore any thrown exception. + /// This is useful for typical finally blocks in manual NMS code. + /// + /// the NMS MessageConsumer to close (may be null) + /// + public static async Task CloseMessageConsumer(IMessageConsumer consumer) + { + if (consumer != null) { - AssertUtils.ArgumentNotNull(session, "ISession must not be null"); + try + { + await consumer.CloseAsync().Awaiter(); + } + catch (NMSException ex) + { + logger.LogDebug(ex, "Could not close NMS MessageConsumer"); + } + catch (Exception ex) + { + // We don't trust the NMS provider: It might throw RuntimeException or Error. + logger.LogDebug(ex, "Unexpected exception on closing NMS MessageConsumer"); + } + } + } - await session.RollbackAsync().Awaiter(); - } - + /// Commit the Session if not within a distributed transaction. + /// Needs investigation - no distributed tx in .NET messaging providers + /// the NMS Session to commit + /// + /// NMSException if committing failed + public static async Task CommitIfNecessary(ISession session) + { + AssertUtils.ArgumentNotNull(session, "ISession must not be null"); + + await session.CommitAsync().Awaiter(); + } + + /// Rollback the Session if not within a distributed transaction. + /// Needs investigation - no distributed tx in EMS + /// the NMS Session to rollback + /// + /// NMSException if committing failed + public static async Task RollbackIfNecessary(ISession session) + { + AssertUtils.ArgumentNotNull(session, "ISession must not be null"); + + await session.RollbackAsync().Awaiter(); } } diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/NmsAccessor.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/NmsAccessor.cs index 944c4e49..d6cc64aa 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/NmsAccessor.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/NmsAccessor.cs @@ -23,154 +23,151 @@ using Spring.Objects.Factory; using Apache.NMS; using Microsoft.Extensions.Logging; -namespace Spring.Messaging.Nms.Support +namespace Spring.Messaging.Nms.Support; + +/// Base class for NmsTemplate and other NMS-accessing gateway helpers +/// It defines common properties like the ConnectionFactory}. The subclass +/// NmsIDestinationAccessor adds further, destination-related properties. +/// +/// Not intended to be used directly. See NmsTemplate. +/// +/// +/// Juergen Hoeller +/// Mark Pollack (.NET) +public class NmsAccessor : IInitializingObject { - /// Base class for NmsTemplate and other NMS-accessing gateway helpers - /// It defines common properties like the ConnectionFactory}. The subclass - /// NmsIDestinationAccessor adds further, destination-related properties. - /// - /// Not intended to be used directly. See NmsTemplate. - /// - /// - /// Juergen Hoeller - /// Mark Pollack (.NET) - public class NmsAccessor : IInitializingObject + #region Logging + + private readonly ILogger logger = LogManager.GetLogger(); + + #endregion + + #region Fields + + private IConnectionFactory connectionFactory; + + private AcknowledgementMode sessionAcknowledgeMode = AcknowledgementMode.AutoAcknowledge; + + #endregion + + #region Properties + + /// + /// Gets or sets the connection factory to use for obtaining NMS Connections. + /// + /// The connection factory. + virtual public IConnectionFactory ConnectionFactory { - #region Logging - - private readonly ILogger logger = LogManager.GetLogger(); - - #endregion - - #region Fields - - private IConnectionFactory connectionFactory; - - private AcknowledgementMode sessionAcknowledgeMode = AcknowledgementMode.AutoAcknowledge; - - #endregion - - #region Properties - - - /// - /// Gets or sets the connection factory to use for obtaining NMS Connections. - /// - /// The connection factory. - virtual public IConnectionFactory ConnectionFactory + get { - get - { - return connectionFactory; - } - - set - { - this.connectionFactory = value; - } + return connectionFactory; } - - /// - /// Gets or sets the session acknowledge mode for NMS Sessions including whether or not the session is transacted - /// - /// - /// Set the NMS acknowledgement mode that is used when creating a NMS - /// Session to send a message. The default is AUTO_ACKNOWLEDGE. - /// - /// The session acknowledge mode. - virtual public AcknowledgementMode SessionAcknowledgeMode + set { - get - { - return sessionAcknowledgeMode; - } - - set - { - this.sessionAcknowledgeMode = value; - } - - } - - /// - /// Set the transaction mode that is used when creating a NMS Session. - /// Default is "false". - /// - /// - /// Setting this flag to "true" will use a short local NMS transaction - /// when running outside of a managed transaction, and a synchronized local - /// NMS transaction in case of a managed transaction being present. - /// The latter has the effect of a local NMS - /// transaction being managed alongside the main transaction (which might - /// be a native ADO.NET transaction), with the NMS transaction committing - /// right after the main transaction. - /// - /// - public bool SessionTransacted - { - get - { - return SessionAcknowledgeMode == AcknowledgementMode.Transactional; - } - set - { - if (value) - { - sessionAcknowledgeMode = AcknowledgementMode.Transactional; - } - } - } - - #endregion - - - /// - /// Verify that ConnectionFactory property has been set. - /// - public virtual void AfterPropertiesSet() - { - if (ConnectionFactory == null) - { - throw new ArgumentException("ConnectionFactory is required"); - } - if (Tracer.Trace == null) - { - if (logger.IsEnabled(LogLevel.Trace)) - { - logger.LogTrace("Setting Apache.NMS.Tracer.Trace to default implementation that directs output to Common.Logging"); - } - Tracer.Trace = new NmsTrace(); - } - } - - /// - /// Creates the connection via the ConnectionFactory. - /// - /// - protected virtual IConnection CreateConnection() - { - return ConnectionFactory.CreateConnection(); - } - - /// - /// Creates the session for the given Connection - /// - /// The connection to create a session for. - /// The new session - protected virtual ISession CreateSession(IConnection con) - { - return con.CreateSession(SessionAcknowledgeMode); - } - - /// - /// Returns whether the ISession is in client acknowledgement mode. - /// - /// The session to check. - /// true if in client ack mode, false otherwise - protected virtual bool IsClientAcknowledge(ISession session) - { - return (session.AcknowledgementMode == AcknowledgementMode.ClientAcknowledge); + this.connectionFactory = value; } } + + /// + /// Gets or sets the session acknowledge mode for NMS Sessions including whether or not the session is transacted + /// + /// + /// Set the NMS acknowledgement mode that is used when creating a NMS + /// Session to send a message. The default is AUTO_ACKNOWLEDGE. + /// + /// The session acknowledge mode. + virtual public AcknowledgementMode SessionAcknowledgeMode + { + get + { + return sessionAcknowledgeMode; + } + + set + { + this.sessionAcknowledgeMode = value; + } + } + + /// + /// Set the transaction mode that is used when creating a NMS Session. + /// Default is "false". + /// + /// + /// Setting this flag to "true" will use a short local NMS transaction + /// when running outside of a managed transaction, and a synchronized local + /// NMS transaction in case of a managed transaction being present. + /// The latter has the effect of a local NMS + /// transaction being managed alongside the main transaction (which might + /// be a native ADO.NET transaction), with the NMS transaction committing + /// right after the main transaction. + /// + /// + public bool SessionTransacted + { + get + { + return SessionAcknowledgeMode == AcknowledgementMode.Transactional; + } + set + { + if (value) + { + sessionAcknowledgeMode = AcknowledgementMode.Transactional; + } + } + } + + #endregion + + /// + /// Verify that ConnectionFactory property has been set. + /// + public virtual void AfterPropertiesSet() + { + if (ConnectionFactory == null) + { + throw new ArgumentException("ConnectionFactory is required"); + } + + if (Tracer.Trace == null) + { + if (logger.IsEnabled(LogLevel.Trace)) + { + logger.LogTrace("Setting Apache.NMS.Tracer.Trace to default implementation that directs output to Common.Logging"); + } + + Tracer.Trace = new NmsTrace(); + } + } + + /// + /// Creates the connection via the ConnectionFactory. + /// + /// + protected virtual IConnection CreateConnection() + { + return ConnectionFactory.CreateConnection(); + } + + /// + /// Creates the session for the given Connection + /// + /// The connection to create a session for. + /// The new session + protected virtual ISession CreateSession(IConnection con) + { + return con.CreateSession(SessionAcknowledgeMode); + } + + /// + /// Returns whether the ISession is in client acknowledgement mode. + /// + /// The session to check. + /// true if in client ack mode, false otherwise + protected virtual bool IsClientAcknowledge(ISession session) + { + return (session.AcknowledgementMode == AcknowledgementMode.ClientAcknowledge); + } } diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/NmsAccessorAsync.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/NmsAccessorAsync.cs index 82a2dd25..e76ab631 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/NmsAccessorAsync.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/NmsAccessorAsync.cs @@ -1,4 +1,5 @@ #region License + // /* // * Copyright 2022 the original author or authors. // * @@ -14,6 +15,7 @@ // * See the License for the specific language governing permissions and // * limitations under the License. // */ + #endregion using Spring.Messaging.Nms.Core; @@ -21,149 +23,146 @@ using Spring.Objects.Factory; using Apache.NMS; using Microsoft.Extensions.Logging; -namespace Spring.Messaging.Nms.Support +namespace Spring.Messaging.Nms.Support; + +/// +/// Async version of NmsAccessor +/// +/// +public class NmsAccessorAsync : IInitializingObject { + #region Logging + + private readonly ILogger logger = LogManager.GetLogger(); + + #endregion + + #region Fields + + private IConnectionFactory connectionFactory; + + private AcknowledgementMode sessionAcknowledgeMode = AcknowledgementMode.AutoAcknowledge; + + #endregion + + #region Properties + /// - /// Async version of NmsAccessor + /// Gets or sets the connection factory to use for obtaining NMS Connections. /// - /// - public class NmsAccessorAsync : IInitializingObject + /// The connection factory. + public virtual IConnectionFactory ConnectionFactory { - #region Logging - - private readonly ILogger logger = LogManager.GetLogger(); - - #endregion - - #region Fields - - private IConnectionFactory connectionFactory; - - private AcknowledgementMode sessionAcknowledgeMode = AcknowledgementMode.AutoAcknowledge; - - #endregion - - #region Properties - - - /// - /// Gets or sets the connection factory to use for obtaining NMS Connections. - /// - /// The connection factory. - public virtual IConnectionFactory ConnectionFactory + get { - get - { - return connectionFactory; - } - - set - { - this.connectionFactory = value; - } + return connectionFactory; } - - /// - /// Gets or sets the session acknowledge mode for NMS Sessions including whether or not the session is transacted - /// - /// - /// Set the NMS acknowledgement mode that is used when creating a NMS - /// Session to send a message. The default is AUTO_ACKNOWLEDGE. - /// - /// The session acknowledge mode. - virtual public AcknowledgementMode SessionAcknowledgeMode + set { - get - { - return sessionAcknowledgeMode; - } - - set - { - this.sessionAcknowledgeMode = value; - } - - } - - /// - /// Set the transaction mode that is used when creating a NMS Session. - /// Default is "false". - /// - /// - /// Setting this flag to "true" will use a short local NMS transaction - /// when running outside of a managed transaction, and a synchronized local - /// NMS transaction in case of a managed transaction being present. - /// The latter has the effect of a local NMS - /// transaction being managed alongside the main transaction (which might - /// be a native ADO.NET transaction), with the NMS transaction committing - /// right after the main transaction. - /// - /// - public bool SessionTransacted - { - get - { - return SessionAcknowledgeMode == AcknowledgementMode.Transactional; - } - set - { - if (value) - { - sessionAcknowledgeMode = AcknowledgementMode.Transactional; - } - } - } - - #endregion - - - /// - /// Verify that ConnectionFactory property has been set. - /// - public virtual void AfterPropertiesSet() - { - if (ConnectionFactory == null) - { - throw new ArgumentException("ConnectionFactory is required"); - } - if (Tracer.Trace == null) - { - if (logger.IsEnabled(LogLevel.Trace)) - { - logger.LogTrace("Setting Apache.NMS.Tracer.Trace to default implementation that directs output to Common.Logging"); - } - Tracer.Trace = new NmsTrace(); - } - } - - /// - /// Creates the connection via the ConnectionFactory. - /// - /// - protected virtual async Task CreateConnection() - { - return await ConnectionFactory.CreateConnectionAsync().Awaiter(); - } - - /// - /// Creates the session for the given Connection - /// - /// The connection to create a session for. - /// The new session - protected virtual async Task CreateSession(IConnection con) - { - return await con.CreateSessionAsync(SessionAcknowledgeMode).Awaiter(); - } - - /// - /// Returns whether the ISession is in client acknowledgement mode. - /// - /// The session to check. - /// true if in client ack mode, false otherwise - protected virtual bool IsClientAcknowledge(ISession session) - { - return (session.AcknowledgementMode == AcknowledgementMode.ClientAcknowledge); + this.connectionFactory = value; } } -} + + /// + /// Gets or sets the session acknowledge mode for NMS Sessions including whether or not the session is transacted + /// + /// + /// Set the NMS acknowledgement mode that is used when creating a NMS + /// Session to send a message. The default is AUTO_ACKNOWLEDGE. + /// + /// The session acknowledge mode. + virtual public AcknowledgementMode SessionAcknowledgeMode + { + get + { + return sessionAcknowledgeMode; + } + + set + { + this.sessionAcknowledgeMode = value; + } + } + + /// + /// Set the transaction mode that is used when creating a NMS Session. + /// Default is "false". + /// + /// + /// Setting this flag to "true" will use a short local NMS transaction + /// when running outside of a managed transaction, and a synchronized local + /// NMS transaction in case of a managed transaction being present. + /// The latter has the effect of a local NMS + /// transaction being managed alongside the main transaction (which might + /// be a native ADO.NET transaction), with the NMS transaction committing + /// right after the main transaction. + /// + /// + public bool SessionTransacted + { + get + { + return SessionAcknowledgeMode == AcknowledgementMode.Transactional; + } + set + { + if (value) + { + sessionAcknowledgeMode = AcknowledgementMode.Transactional; + } + } + } + + #endregion + + /// + /// Verify that ConnectionFactory property has been set. + /// + public virtual void AfterPropertiesSet() + { + if (ConnectionFactory == null) + { + throw new ArgumentException("ConnectionFactory is required"); + } + + if (Tracer.Trace == null) + { + if (logger.IsEnabled(LogLevel.Trace)) + { + logger.LogTrace("Setting Apache.NMS.Tracer.Trace to default implementation that directs output to Common.Logging"); + } + + Tracer.Trace = new NmsTrace(); + } + } + + /// + /// Creates the connection via the ConnectionFactory. + /// + /// + protected virtual async Task CreateConnection() + { + return await ConnectionFactory.CreateConnectionAsync().Awaiter(); + } + + /// + /// Creates the session for the given Connection + /// + /// The connection to create a session for. + /// The new session + protected virtual async Task CreateSession(IConnection con) + { + return await con.CreateSessionAsync(SessionAcknowledgeMode).Awaiter(); + } + + /// + /// Returns whether the ISession is in client acknowledgement mode. + /// + /// The session to check. + /// true if in client ack mode, false otherwise + protected virtual bool IsClientAcknowledge(ISession session) + { + return (session.AcknowledgementMode == AcknowledgementMode.ClientAcknowledge); + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/SemaphoreSlimLock.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/SemaphoreSlimLock.cs index 5e0bceef..5cc0cdac 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/SemaphoreSlimLock.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/SemaphoreSlimLock.cs @@ -1,4 +1,5 @@ #region License + // /* // * Copyright 2022 the original author or authors. // * @@ -14,59 +15,57 @@ // * See the License for the specific language governing permissions and // * limitations under the License. // */ + #endregion -namespace Spring.Messaging.Nms.Support +namespace Spring.Messaging.Nms.Support; + +/// +/// Lock that can be used in sync and async code +/// its non reentrant but there is a parameter acquireLock that can be passed from outer context to tell that lock is already taken for current execution flow +/// +public class SemaphoreSlimLock { - /// - /// Lock that can be used in sync and async code - /// its non reentrant but there is a parameter acquireLock that can be passed from outer context to tell that lock is already taken for current execution flow - /// - public class SemaphoreSlimLock + private readonly SemaphoreSlim _semaphoreSlim = new SemaphoreSlim(1, 1); + + public IDisposable Lock(bool acquireLock = true) { - private readonly SemaphoreSlim _semaphoreSlim = new SemaphoreSlim(1, 1); - - public IDisposable Lock(bool acquireLock = true) + if (acquireLock) { - if (acquireLock) - { - _semaphoreSlim.Wait(); - return new DisposableLock(_semaphoreSlim); - } - else - { - return new DisposableLock(null); - } + _semaphoreSlim.Wait(); + return new DisposableLock(_semaphoreSlim); } - - public async Task LockAsync(bool acquireLock = true) + else { - if (acquireLock) - { - await _semaphoreSlim.WaitAsync().Awaiter(); - return new DisposableLock(_semaphoreSlim); - } - else - { - return new DisposableLock(null); - } + return new DisposableLock(null); } - - - private class DisposableLock : IDisposable - { - private readonly SemaphoreSlim _semaphoreToUnlock; - - public DisposableLock(SemaphoreSlim semaphoreSlim) - { - this._semaphoreToUnlock = semaphoreSlim; - } - - public void Dispose() - { - _semaphoreToUnlock?.Release(); - } - } - } -} \ No newline at end of file + + public async Task LockAsync(bool acquireLock = true) + { + if (acquireLock) + { + await _semaphoreSlim.WaitAsync().Awaiter(); + return new DisposableLock(_semaphoreSlim); + } + else + { + return new DisposableLock(null); + } + } + + private class DisposableLock : IDisposable + { + private readonly SemaphoreSlim _semaphoreToUnlock; + + public DisposableLock(SemaphoreSlim semaphoreSlim) + { + this._semaphoreToUnlock = semaphoreSlim; + } + + public void Dispose() + { + _semaphoreToUnlock?.Release(); + } + } +} diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/TaskExtensions.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/TaskExtensions.cs index 1f904401..bebb5bb3 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/TaskExtensions.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/TaskExtensions.cs @@ -1,4 +1,5 @@ #region License + // /* // * Copyright 2022 the original author or authors. // * @@ -14,34 +15,34 @@ // * See the License for the specific language governing permissions and // * limitations under the License. // */ + #endregion using System.Runtime.CompilerServices; -namespace Spring.Messaging.Nms.Support -{ - public static class TaskExtensions - { - public static T GetAsyncResult(this Task task) - { - return task.ConfigureAwait(ContinueOnCapturedContext).GetAwaiter().GetResult(); - } - - public static void GetAsyncResult(this Task task) - { - task.ConfigureAwait(ContinueOnCapturedContext).GetAwaiter().GetResult(); - } - - public static ConfiguredTaskAwaitable Awaiter(this Task task) - { - return task.ConfigureAwait(ContinueOnCapturedContext); - } - - public static ConfiguredTaskAwaitable Awaiter(this Task task) - { - return task.ConfigureAwait(ContinueOnCapturedContext); - } +namespace Spring.Messaging.Nms.Support; - public static bool ContinueOnCapturedContext { get; set; } = false; +public static class TaskExtensions +{ + public static T GetAsyncResult(this Task task) + { + return task.ConfigureAwait(ContinueOnCapturedContext).GetAwaiter().GetResult(); } -} \ No newline at end of file + + public static void GetAsyncResult(this Task task) + { + task.ConfigureAwait(ContinueOnCapturedContext).GetAwaiter().GetResult(); + } + + public static ConfiguredTaskAwaitable Awaiter(this Task task) + { + return task.ConfigureAwait(ContinueOnCapturedContext); + } + + public static ConfiguredTaskAwaitable Awaiter(this Task task) + { + return task.ConfigureAwait(ContinueOnCapturedContext); + } + + public static bool ContinueOnCapturedContext { get; set; } = false; +} diff --git a/src/Spring/Spring.Messaging/AssemblyInfo.cs b/src/Spring/Spring.Messaging/AssemblyInfo.cs index a46da0d6..8581f9d7 100644 --- a/src/Spring/Spring.Messaging/AssemblyInfo.cs +++ b/src/Spring/Spring.Messaging/AssemblyInfo.cs @@ -1,4 +1,4 @@ using System.Reflection; [assembly: AssemblyTitle("Spring.Messaging")] -[assembly: AssemblyDescription("Interfaces and classes that provide MSMQ 3.0 support in Spring.Net")] \ No newline at end of file +[assembly: AssemblyDescription("Interfaces and classes that provide MSMQ 3.0 support in Spring.Net")] diff --git a/src/Spring/Spring.Messaging/Messaging/Core/DefaultMessageQueueFactory.cs b/src/Spring/Spring.Messaging/Messaging/Core/DefaultMessageQueueFactory.cs index 4fe1829d..35532067 100644 --- a/src/Spring/Spring.Messaging/Messaging/Core/DefaultMessageQueueFactory.cs +++ b/src/Spring/Spring.Messaging/Messaging/Core/DefaultMessageQueueFactory.cs @@ -28,198 +28,200 @@ using Spring.Util; #if NETSTANDARD using Experimental.System.Messaging; + #else using System.Messaging; #endif -namespace Spring.Messaging.Core +namespace Spring.Messaging.Core; + +/// +/// A implementation that caches MessageQueue and IMessageConverter +/// instances. The MessageQueue objects are created by retrieving them by-name from the +/// ApplicationContext. +/// +/// Mark Pollack +public class DefaultMessageQueueFactory : IMessageQueueFactory, IApplicationContextAware { /// - /// A implementation that caches MessageQueue and IMessageConverter - /// instances. The MessageQueue objects are created by retrieving them by-name from the - /// ApplicationContext. + /// The instance for this class. /// - /// Mark Pollack - public class DefaultMessageQueueFactory : IMessageQueueFactory, IApplicationContextAware + private readonly ILogger log = LogManager.GetLogger(); + + private static readonly string QUEUE_DICTIONARY_SLOTNAME = + UniqueKey.GetTypeScopedString(typeof(DefaultMessageQueueFactory), "Queue"); + + private static readonly string CONVERTER_DICTIONARY_SLOTNAME = + UniqueKey.GetTypeScopedString(typeof(DefaultMessageQueueFactory), "Converter"); + + private IConfigurableApplicationContext applicationContext; + + #region IMessageQueueFactory Members + + /// + /// Registers the message queue, its creation specified via the factory method + /// MessageQueueCreatorDelegate, with the provided name in the application context + /// + /// Name of the message queue object. + /// The message queue creator delegate. + public void RegisterMessageQueue(string messageQueueObjectName, + MessageQueueCreatorDelegate messageQueueCreatorDelegate) { - /// - /// The instance for this class. - /// - private readonly ILogger log = LogManager.GetLogger(); - - - private static readonly string QUEUE_DICTIONARY_SLOTNAME = - UniqueKey.GetTypeScopedString(typeof (DefaultMessageQueueFactory), "Queue"); - - private static readonly string CONVERTER_DICTIONARY_SLOTNAME = - UniqueKey.GetTypeScopedString(typeof (DefaultMessageQueueFactory), "Converter"); - - private IConfigurableApplicationContext applicationContext; - - #region IMessageQueueFactory Members - - /// - /// Registers the message queue, its creation specified via the factory method - /// MessageQueueCreatorDelegate, with the provided name in the application context - /// - /// Name of the message queue object. - /// The message queue creator delegate. - public void RegisterMessageQueue(string messageQueueObjectName, - MessageQueueCreatorDelegate messageQueueCreatorDelegate) + MessageQueueFactoryObject mqfo = new MessageQueueFactoryObject(); + mqfo.MessageCreatorDelegate = messageQueueCreatorDelegate; + applicationContext.ObjectFactory.RegisterSingleton(messageQueueObjectName, mqfo); + var caches = applicationContext.GetObjects(); + foreach (KeyValuePair entry in caches) { - MessageQueueFactoryObject mqfo = new MessageQueueFactoryObject(); - mqfo.MessageCreatorDelegate = messageQueueCreatorDelegate; - applicationContext.ObjectFactory.RegisterSingleton(messageQueueObjectName, mqfo); - var caches = applicationContext.GetObjects(); - foreach (KeyValuePair entry in caches) - { - entry.Value.Insert(mqfo.Path, new MessageQueueMetadata(mqfo.RemoteQueue, mqfo.RemoteQueueIsTransactional)); - } + entry.Value.Insert(mqfo.Path, new MessageQueueMetadata(mqfo.RemoteQueue, mqfo.RemoteQueueIsTransactional)); } - - /// - /// Creates the message queue given its name in the application context. - /// - /// Name of the message queue object. - /// - /// A MessageQueue instance configured via the application context - /// - public MessageQueue CreateMessageQueue(string messageQueueObjectName) - { - AssertUtils.ArgumentHasText(messageQueueObjectName, "DefaultMessageQueueObjectName"); - IDictionary queues = LogicalThreadContext.GetData(QUEUE_DICTIONARY_SLOTNAME) as IDictionary; - if (queues == null) - { - queues = new Hashtable(); - LogicalThreadContext.SetData(QUEUE_DICTIONARY_SLOTNAME, queues); - } - if (!queues.Contains(messageQueueObjectName)) - { - MessageQueue mq = applicationContext.GetObject(messageQueueObjectName) as MessageQueue; - queues.Add(messageQueueObjectName, mq); - } - return queues[messageQueueObjectName] as MessageQueue; - } - - /// - /// Determines whether the application context contains the message queue object definition. - /// - /// Name of the message queue object. - /// - /// true if the application context contains the specified message queue object name; otherwise, false. - /// - public bool ContainsMessageQueue(string messageQueueObjectName) - { - return applicationContext.ContainsObject(messageQueueObjectName); - } - - /// - /// Registers the message converter. - /// - /// Name of the message converter. - /// The message converter creator delegate. - public void RegisterMessageConverter(string messageConverterName, - MessageConverterCreatorDelegate messageConverterCreatorDelegate) - { - MessageConverterFactoryObject mcfo = new MessageConverterFactoryObject(); - mcfo.MessageConverterCreatorDelegate = messageConverterCreatorDelegate; - applicationContext.ObjectFactory.RegisterSingleton(messageConverterName, mcfo); - } - - /// - /// Creates the message converter given its name in the application context. - /// - /// Name of the message converter object. - /// - /// A IMessageConverter instance configured via the application context - /// - public IMessageConverter CreateMessageConverter(string messageConverterObjectName) - { - AssertUtils.ArgumentHasText(messageConverterObjectName, "MessgaeFormatterObjectName"); - IDictionary converters = LogicalThreadContext.GetData(CONVERTER_DICTIONARY_SLOTNAME) as IDictionary; - if (converters == null) - { - converters = new Hashtable(); - LogicalThreadContext.SetData(CONVERTER_DICTIONARY_SLOTNAME, converters); - } - if (!converters.Contains(messageConverterObjectName)) - { - IMessageConverter mc = - (IMessageConverter) - applicationContext.GetObject(messageConverterObjectName, typeof (IMessageConverter)); - if (applicationContext.ObjectFactory.GetObjectDefinition(messageConverterObjectName).IsSingleton) - { - log.LogWarning("MessageConverter with name = [" + messageConverterObjectName + "] should be declared with singleton=false. Using Clone() to create independent instance for thread local storage"); - converters.Add(messageConverterObjectName, mc.Clone()); - } - else - { - converters.Add(messageConverterObjectName, mc); - } - } - return converters[messageConverterObjectName] as IMessageConverter; - } - - - /// - /// Determines whether the application context contains the message queue object definition. - /// - /// Name of the message converter object. - /// - /// true if the application context contains the specified message message converter object name; otherwise, false. - /// - public bool ContainsMessageConverter(string messageConverterObjectName) - { - return applicationContext.ContainsObject(messageConverterObjectName); - } - - #endregion - - #region IApplicationContextAware Members - - /// - /// Gets or sets the that this - /// object runs in. - /// - /// - ///

- /// Normally this call will be used to initialize the object. - ///

- ///

- /// Invoked after population of normal object properties but before an - /// init callback such as - /// 's - /// - /// or a custom init-method. Invoked after the setting of any - /// 's - /// - /// property. - ///

- ///
- /// - /// In the case of application context initialization errors. - /// - /// - /// If thrown by any application context methods. - /// - /// - public IApplicationContext ApplicationContext - { - get { return applicationContext; } - set - { - AssertUtils.ArgumentNotNull(value, "An ApplicationContext instance is required"); - IConfigurableApplicationContext ctx = value as IConfigurableApplicationContext; - if (ctx == null) - { - throw new InvalidOperationException( - "Implementations of IApplicationContext must also implement IConfigurableApplicationContext"); - } - - applicationContext = ctx; - } - } - - #endregion } + + /// + /// Creates the message queue given its name in the application context. + /// + /// Name of the message queue object. + /// + /// A MessageQueue instance configured via the application context + /// + public MessageQueue CreateMessageQueue(string messageQueueObjectName) + { + AssertUtils.ArgumentHasText(messageQueueObjectName, "DefaultMessageQueueObjectName"); + IDictionary queues = LogicalThreadContext.GetData(QUEUE_DICTIONARY_SLOTNAME) as IDictionary; + if (queues == null) + { + queues = new Hashtable(); + LogicalThreadContext.SetData(QUEUE_DICTIONARY_SLOTNAME, queues); + } + + if (!queues.Contains(messageQueueObjectName)) + { + MessageQueue mq = applicationContext.GetObject(messageQueueObjectName) as MessageQueue; + queues.Add(messageQueueObjectName, mq); + } + + return queues[messageQueueObjectName] as MessageQueue; + } + + /// + /// Determines whether the application context contains the message queue object definition. + /// + /// Name of the message queue object. + /// + /// true if the application context contains the specified message queue object name; otherwise, false. + /// + public bool ContainsMessageQueue(string messageQueueObjectName) + { + return applicationContext.ContainsObject(messageQueueObjectName); + } + + /// + /// Registers the message converter. + /// + /// Name of the message converter. + /// The message converter creator delegate. + public void RegisterMessageConverter(string messageConverterName, + MessageConverterCreatorDelegate messageConverterCreatorDelegate) + { + MessageConverterFactoryObject mcfo = new MessageConverterFactoryObject(); + mcfo.MessageConverterCreatorDelegate = messageConverterCreatorDelegate; + applicationContext.ObjectFactory.RegisterSingleton(messageConverterName, mcfo); + } + + /// + /// Creates the message converter given its name in the application context. + /// + /// Name of the message converter object. + /// + /// A IMessageConverter instance configured via the application context + /// + public IMessageConverter CreateMessageConverter(string messageConverterObjectName) + { + AssertUtils.ArgumentHasText(messageConverterObjectName, "MessgaeFormatterObjectName"); + IDictionary converters = LogicalThreadContext.GetData(CONVERTER_DICTIONARY_SLOTNAME) as IDictionary; + if (converters == null) + { + converters = new Hashtable(); + LogicalThreadContext.SetData(CONVERTER_DICTIONARY_SLOTNAME, converters); + } + + if (!converters.Contains(messageConverterObjectName)) + { + IMessageConverter mc = + (IMessageConverter) + applicationContext.GetObject(messageConverterObjectName, typeof(IMessageConverter)); + if (applicationContext.ObjectFactory.GetObjectDefinition(messageConverterObjectName).IsSingleton) + { + log.LogWarning("MessageConverter with name = [" + messageConverterObjectName + "] should be declared with singleton=false. Using Clone() to create independent instance for thread local storage"); + converters.Add(messageConverterObjectName, mc.Clone()); + } + else + { + converters.Add(messageConverterObjectName, mc); + } + } + + return converters[messageConverterObjectName] as IMessageConverter; + } + + /// + /// Determines whether the application context contains the message queue object definition. + /// + /// Name of the message converter object. + /// + /// true if the application context contains the specified message message converter object name; otherwise, false. + /// + public bool ContainsMessageConverter(string messageConverterObjectName) + { + return applicationContext.ContainsObject(messageConverterObjectName); + } + + #endregion + + #region IApplicationContextAware Members + + /// + /// Gets or sets the that this + /// object runs in. + /// + /// + ///

+ /// Normally this call will be used to initialize the object. + ///

+ ///

+ /// Invoked after population of normal object properties but before an + /// init callback such as + /// 's + /// + /// or a custom init-method. Invoked after the setting of any + /// 's + /// + /// property. + ///

+ ///
+ /// + /// In the case of application context initialization errors. + /// + /// + /// If thrown by any application context methods. + /// + /// + public IApplicationContext ApplicationContext + { + get { return applicationContext; } + set + { + AssertUtils.ArgumentNotNull(value, "An ApplicationContext instance is required"); + IConfigurableApplicationContext ctx = value as IConfigurableApplicationContext; + if (ctx == null) + { + throw new InvalidOperationException( + "Implementations of IApplicationContext must also implement IConfigurableApplicationContext"); + } + + applicationContext = ctx; + } + } + + #endregion } diff --git a/src/Spring/Spring.Messaging/Messaging/Core/IMessageQueueFactory.cs b/src/Spring/Spring.Messaging/Messaging/Core/IMessageQueueFactory.cs index 66d2165a..41dd63b6 100644 --- a/src/Spring/Spring.Messaging/Messaging/Core/IMessageQueueFactory.cs +++ b/src/Spring/Spring.Messaging/Messaging/Core/IMessageQueueFactory.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -23,79 +23,73 @@ using Spring.Messaging.Support.Converters; #if NETSTANDARD using Experimental.System.Messaging; + #else using System.Messaging; #endif -namespace Spring.Messaging.Core +namespace Spring.Messaging.Core; + +/// +/// An interface for creating MessageQueue and IMessageConverter objects from object definitions +/// defined in the application context. +/// +/// +/// MessageQueue and IMessageConverter objects have methods that are generally not thread safe, +/// (IMessageConverter classes rely on IMessageFormatter objects that are not thread safe). +/// As such, a major reason to for this interface is to provide thread-local instances such that +/// appliation code need not be concerned with these resource management issues. +/// +/// Mark Pollack +public interface IMessageQueueFactory { /// - /// An interface for creating MessageQueue and IMessageConverter objects from object definitions - /// defined in the application context. + /// Registers the message queue, its creation specified via the factory method + /// MessageQueueCreatorDelegate, with the provided name in the application context /// - /// - /// MessageQueue and IMessageConverter objects have methods that are generally not thread safe, - /// (IMessageConverter classes rely on IMessageFormatter objects that are not thread safe). - /// As such, a major reason to for this interface is to provide thread-local instances such that - /// appliation code need not be concerned with these resource management issues. - /// - /// Mark Pollack - public interface IMessageQueueFactory - { - /// - /// Registers the message queue, its creation specified via the factory method - /// MessageQueueCreatorDelegate, with the provided name in the application context - /// - /// Name of the message queue object. - /// The message queue creator delegate. - void RegisterMessageQueue(string messageQueueObjectName, - MessageQueueCreatorDelegate messageQueueCreatorDelegate); + /// Name of the message queue object. + /// The message queue creator delegate. + void RegisterMessageQueue(string messageQueueObjectName, + MessageQueueCreatorDelegate messageQueueCreatorDelegate); - /// - /// Creates the message queue given its name in the application context. - /// - /// Name of the message queue object. - /// A MessageQueue instance configured via the application context - MessageQueue CreateMessageQueue(string messageQueueObjectName); + /// + /// Creates the message queue given its name in the application context. + /// + /// Name of the message queue object. + /// A MessageQueue instance configured via the application context + MessageQueue CreateMessageQueue(string messageQueueObjectName); - /// - /// Determines whether the application context contains the message queue object definition. - /// - /// Name of the message queue object. - /// - /// true if the application context contains the specified message queue object name; otherwise, false. - /// - bool ContainsMessageQueue(string messageQueueObjectName); + /// + /// Determines whether the application context contains the message queue object definition. + /// + /// Name of the message queue object. + /// + /// true if the application context contains the specified message queue object name; otherwise, false. + /// + bool ContainsMessageQueue(string messageQueueObjectName); + /// + /// Registers the message converter, its creation specified via the factory method + /// MessageConverterCreatorDelegate, with the provided name in the application context. + /// + /// Name of the message converter. + /// The message converter creator delegate. + void RegisterMessageConverter(string messageConverterName, + MessageConverterCreatorDelegate MessageConverterCreatorDelegate); + /// + /// Creates the message converter given its name in the application context. + /// + /// Name of the message converter object. + /// A IMessageConverter instance configured via the application context + IMessageConverter CreateMessageConverter(string messageConverterObjectName); - /// - /// Registers the message converter, its creation specified via the factory method - /// MessageConverterCreatorDelegate, with the provided name in the application context. - /// - /// Name of the message converter. - /// The message converter creator delegate. - void RegisterMessageConverter(string messageConverterName, - MessageConverterCreatorDelegate MessageConverterCreatorDelegate); - - - /// - /// Creates the message converter given its name in the application context. - /// - /// Name of the message converter object. - /// A IMessageConverter instance configured via the application context - IMessageConverter CreateMessageConverter(string messageConverterObjectName); - - /// - /// Determines whether the application context contains the message queue object definition. - /// - /// Name of the message converter object. - /// - /// true if the application context contains the specified message message converter object name; otherwise, false. - /// - bool ContainsMessageConverter(string messageConverterObjectName); - - - - } -} \ No newline at end of file + /// + /// Determines whether the application context contains the message queue object definition. + /// + /// Name of the message converter object. + /// + /// true if the application context contains the specified message message converter object name; otherwise, false. + /// + bool ContainsMessageConverter(string messageConverterObjectName); +} diff --git a/src/Spring/Spring.Messaging/Messaging/Core/IMessageQueueOperations.cs b/src/Spring/Spring.Messaging/Messaging/Core/IMessageQueueOperations.cs index 18e167cd..18d08061 100644 --- a/src/Spring/Spring.Messaging/Messaging/Core/IMessageQueueOperations.cs +++ b/src/Spring/Spring.Messaging/Messaging/Core/IMessageQueueOperations.cs @@ -22,149 +22,147 @@ using Spring.Messaging.Support.Converters; #if NETSTANDARD using Experimental.System.Messaging; + #else using System.Messaging; #endif -namespace Spring.Messaging.Core +namespace Spring.Messaging.Core; + +/// +/// Specifies a basic set of helper MSMQ opertions. +/// +/// +/// Implemented by . Not often used but a useful option +/// to enhance testability, as it can easily be mocked or stubbed. +/// +/// +/// Provides MessageQueueTemplate's +/// Send(..) and receive(..) methods that mirror various MSMQ MessageQueue +/// API methods. +/// +/// +/// Mark Pollack +public interface IMessageQueueOperations { /// - /// Specifies a basic set of helper MSMQ opertions. + /// Send the given object to the default destination, converting the object + /// to a MSMQ message with a configured IMessageConverter. + /// + /// This will only work with a default destination queue specified! + /// The obj. + void ConvertAndSend(object obj); + + /// Send the given object to the default destination, converting the object + /// to a MSMQ message with a configured IMessageConverter. The IMessagePostProcessor + /// callback allows for modification of the message after conversion. + ///

This will only work with a default destination specified!

+ ///
+ /// the object to convert to a message + /// + /// the callback to modify the message + /// + /// if thrown by MSMQ API methods + void ConvertAndSend(object obj, MessagePostProcessorDelegate messagePostProcessorDelegate); + + /// Send the given object to the specified destination, converting the object + /// to a MSMQ message with a configured and resolving the + /// destination name to a using a + /// + /// the name of the destination queue + /// to send this message to (to be resolved to an actual MessageQueue + /// by a IMessageQueueFactory) + /// + /// the object to convert to a message + /// + /// NMSException if there is any problem + void ConvertAndSend(string messageQueueObjectName, object obj); + + /// Send the given object to the specified destination, converting the object + /// to a MSMQ message with a configured and resolving the + /// destination name to a with an + /// The callback allows for modification of the message after conversion. + /// + /// the name of the destination queue + /// to send this message to (to be resolved to an actual MessageQueue + /// by a IMessageQueueFactory) + /// + /// the object to convert to a message + /// + /// the callback to modify the message + /// + /// if thrown by MSMQ API methods + void ConvertAndSend(string messageQueueObjectName, object obj, MessagePostProcessorDelegate messagePostProcessorDelegate); + + /* + void ConvertAndSend(QueueIdentifierType queueIdentifierType, string destinationValue, string messageQueueObjectName, object obj); + + void ConvertAndSend(QueueIdentifierType queueIdentifierType, string destinationValue, string messageQueueObjectName, object obj, MessagePostProcessorDelegate messagePostProcessorDelegate); + */ + /// + /// Receive and convert a message synchronously from the default message queue. + /// + /// The converted object + /// if thrown by MSMQ API methods. Note an + /// exception will be thrown if the timeout of the syncrhonous recieve operation expires. + /// + object ReceiveAndConvert(); + + /// + /// Receives and convert a message synchronously from the specified message queue. + /// + /// Name of the message queue object. + /// the converted object + /// if thrown by MSMQ API methods. Note an + /// exception will be thrown if the timeout of the syncrhonous recieve operation expires. + /// + object ReceiveAndConvert(string messageQueueObjectName); + + /// + /// Receives a message on the default message queue using the transactional settings as dicted by MessageQueue's Transactional property and + /// the current Spring managed ambient transaction. + /// + /// A message. + Message Receive(); + + /// + /// Receives a message on the specified queue using the transactional settings as dicted by MessageQueue's Transactional property and + /// the current Spring managed ambient transaction. + /// + /// Name of the message queue object. + /// + Message Receive(string messageQueueObjectName); + + /// + /// Sends the specified message to the default message queue using the + /// transactional settings as dicted by MessageQueue's Transactional property and + /// the current Spring managed ambient transaction. + /// + /// The message to send + void Send(Message message); + + /// + /// Sends the specified message to the message queue using the + /// transactional settings as dicted by MessageQueue's Transactional property and + /// the current Spring managed ambient transaction. + /// + /// Name of the message queue object. + /// The message. + void Send(string messageQueueObjectName, Message message); + + /// + /// Sends the specified message on the provided MessageQueue using the + /// transactional settings as dicted by MessageQueue's Transactional property and + /// the current Spring managed ambient transaction. /// - /// - /// Implemented by . Not often used but a useful option - /// to enhance testability, as it can easily be mocked or stubbed. - /// /// - /// Provides MessageQueueTemplate's - /// Send(..) and receive(..) methods that mirror various MSMQ MessageQueue - /// API methods. + /// Note that it is the callers responsibility to ensure that the MessageQueue instance + /// passed into this not being access simultaneously by other threads. /// - /// - /// Mark Pollack - public interface IMessageQueueOperations - { - /// - /// Send the given object to the default destination, converting the object - /// to a MSMQ message with a configured IMessageConverter. - /// - /// This will only work with a default destination queue specified! - /// The obj. - void ConvertAndSend(object obj); - - /// Send the given object to the default destination, converting the object - /// to a MSMQ message with a configured IMessageConverter. The IMessagePostProcessor - /// callback allows for modification of the message after conversion. - ///

This will only work with a default destination specified!

- ///
- /// the object to convert to a message - /// - /// the callback to modify the message - /// - /// if thrown by MSMQ API methods - void ConvertAndSend(object obj, MessagePostProcessorDelegate messagePostProcessorDelegate); - - /// Send the given object to the specified destination, converting the object - /// to a MSMQ message with a configured and resolving the - /// destination name to a using a - /// - /// the name of the destination queue - /// to send this message to (to be resolved to an actual MessageQueue - /// by a IMessageQueueFactory) - /// - /// the object to convert to a message - /// - /// NMSException if there is any problem - void ConvertAndSend(string messageQueueObjectName, object obj); - - /// Send the given object to the specified destination, converting the object - /// to a MSMQ message with a configured and resolving the - /// destination name to a with an - /// The callback allows for modification of the message after conversion. - /// - /// the name of the destination queue - /// to send this message to (to be resolved to an actual MessageQueue - /// by a IMessageQueueFactory) - /// - /// the object to convert to a message - /// - /// the callback to modify the message - /// - /// if thrown by MSMQ API methods - void ConvertAndSend(string messageQueueObjectName, object obj, MessagePostProcessorDelegate messagePostProcessorDelegate); - - /* - void ConvertAndSend(QueueIdentifierType queueIdentifierType, string destinationValue, string messageQueueObjectName, object obj); - - void ConvertAndSend(QueueIdentifierType queueIdentifierType, string destinationValue, string messageQueueObjectName, object obj, MessagePostProcessorDelegate messagePostProcessorDelegate); - */ - /// - /// Receive and convert a message synchronously from the default message queue. - /// - /// The converted object - /// if thrown by MSMQ API methods. Note an - /// exception will be thrown if the timeout of the syncrhonous recieve operation expires. - /// - object ReceiveAndConvert(); - - - /// - /// Receives and convert a message synchronously from the specified message queue. - /// - /// Name of the message queue object. - /// the converted object - /// if thrown by MSMQ API methods. Note an - /// exception will be thrown if the timeout of the syncrhonous recieve operation expires. - /// - object ReceiveAndConvert(string messageQueueObjectName); - - /// - /// Receives a message on the default message queue using the transactional settings as dicted by MessageQueue's Transactional property and - /// the current Spring managed ambient transaction. - /// - /// A message. - Message Receive(); - - /// - /// Receives a message on the specified queue using the transactional settings as dicted by MessageQueue's Transactional property and - /// the current Spring managed ambient transaction. - /// - /// Name of the message queue object. - /// - Message Receive(string messageQueueObjectName); - - /// - /// Sends the specified message to the default message queue using the - /// transactional settings as dicted by MessageQueue's Transactional property and - /// the current Spring managed ambient transaction. - /// - /// The message to send - void Send(Message message); - - - /// - /// Sends the specified message to the message queue using the - /// transactional settings as dicted by MessageQueue's Transactional property and - /// the current Spring managed ambient transaction. - /// - /// Name of the message queue object. - /// The message. - void Send(string messageQueueObjectName, Message message); - - /// - /// Sends the specified message on the provided MessageQueue using the - /// transactional settings as dicted by MessageQueue's Transactional property and - /// the current Spring managed ambient transaction. - /// - /// - /// Note that it is the callers responsibility to ensure that the MessageQueue instance - /// passed into this not being access simultaneously by other threads. - /// - /// A transactional send (either local or DTC transaction) will be - /// attempted for a transacitonal queue, falling back to a single-transaction send - /// to a transactional queue if there is not ambient Spring managed transaction. - /// The DefaultMessageQueue to send a message to. - /// The message to send - void Send(MessageQueue messageQueue, Message message); - } -} \ No newline at end of file + /// A transactional send (either local or DTC transaction) will be + /// attempted for a transacitonal queue, falling back to a single-transaction send + /// to a transactional queue if there is not ambient Spring managed transaction. + /// The DefaultMessageQueue to send a message to. + /// The message to send + void Send(MessageQueue messageQueue, Message message); +} diff --git a/src/Spring/Spring.Messaging/Messaging/Core/LocallyExposedMessageQueueResourceHolder.cs b/src/Spring/Spring.Messaging/Messaging/Core/LocallyExposedMessageQueueResourceHolder.cs index 648579dc..2e2a0a6b 100644 --- a/src/Spring/Spring.Messaging/Messaging/Core/LocallyExposedMessageQueueResourceHolder.cs +++ b/src/Spring/Spring.Messaging/Messaging/Core/LocallyExposedMessageQueueResourceHolder.cs @@ -20,26 +20,26 @@ #if NETSTANDARD using Experimental.System.Messaging; + #else using System.Messaging; #endif -namespace Spring.Messaging.Core +namespace Spring.Messaging.Core; + +/// +/// MessageQueueResourceHolder marker subclass that indicates local exposure, +/// i.e. that does not indicate an externally managed transaction. +/// +/// Mark Pollack +public class LocallyExposedMessageQueueResourceHolder : MessageQueueResourceHolder { /// - /// MessageQueueResourceHolder marker subclass that indicates local exposure, - /// i.e. that does not indicate an externally managed transaction. + /// Initializes a new instance of the class. /// - /// Mark Pollack - public class LocallyExposedMessageQueueResourceHolder : MessageQueueResourceHolder + /// The message queue transaction. + public LocallyExposedMessageQueueResourceHolder(MessageQueueTransaction messageQueueTransaction) + : base(messageQueueTransaction) { - /// - /// Initializes a new instance of the class. - /// - /// The message queue transaction. - public LocallyExposedMessageQueueResourceHolder(MessageQueueTransaction messageQueueTransaction) - : base(messageQueueTransaction) - { - } } -} \ No newline at end of file +} diff --git a/src/Spring/Spring.Messaging/Messaging/Core/MessagePostProcessorDelegate.cs b/src/Spring/Spring.Messaging/Messaging/Core/MessagePostProcessorDelegate.cs index d6a2196a..cfbd8c79 100644 --- a/src/Spring/Spring.Messaging/Messaging/Core/MessagePostProcessorDelegate.cs +++ b/src/Spring/Spring.Messaging/Messaging/Core/MessagePostProcessorDelegate.cs @@ -18,24 +18,23 @@ #endregion - #if NETSTANDARD using Experimental.System.Messaging; + #else using System.Messaging; #endif -namespace Spring.Messaging.Core -{ - /// - /// To be used with MessageQueueTemplate's send method that - /// convert an object to a message. - /// - /// - /// It allows for further modification of the message after it has been processed - /// by the converter. This is useful for setting of Message properties (e.g. - /// CorrelationId, AppSpecific, TimeToReachQueue). - /// - /// Mark Pollack - public delegate Message MessagePostProcessorDelegate(Message message); -} \ No newline at end of file +namespace Spring.Messaging.Core; + +/// +/// To be used with MessageQueueTemplate's send method that +/// convert an object to a message. +/// +/// +/// It allows for further modification of the message after it has been processed +/// by the converter. This is useful for setting of Message properties (e.g. +/// CorrelationId, AppSpecific, TimeToReachQueue). +/// +/// Mark Pollack +public delegate Message MessagePostProcessorDelegate(Message message); diff --git a/src/Spring/Spring.Messaging/Messaging/Core/MessageQueueGatewaySupport.cs b/src/Spring/Spring.Messaging/Messaging/Core/MessageQueueGatewaySupport.cs index cfb77f93..628a5a2b 100644 --- a/src/Spring/Spring.Messaging/Messaging/Core/MessageQueueGatewaySupport.cs +++ b/src/Spring/Spring.Messaging/Messaging/Core/MessageQueueGatewaySupport.cs @@ -20,68 +20,64 @@ using Spring.Objects.Factory; -namespace Spring.Messaging.Core +namespace Spring.Messaging.Core; + +/// +/// Convenient super class for application classes that need MSMQ access. +/// +/// +/// Override the InitGateway method to perform custom startup tasks. +/// +/// Mark Pollack +public class MessageQueueGatewaySupport : IInitializingObject { + private MessageQueueTemplate messageQueueTemplate; + /// - /// Convenient super class for application classes that need MSMQ access. + /// Gets or sets the message queue template. . /// - /// - /// Override the InitGateway method to perform custom startup tasks. - /// - /// Mark Pollack - public class MessageQueueGatewaySupport : IInitializingObject + /// The message queue template. + public MessageQueueTemplate MessageQueueTemplate { - private MessageQueueTemplate messageQueueTemplate; + get { return messageQueueTemplate; } + set { messageQueueTemplate = value; } + } + /// + /// Gets the message queue factory, a convenience method. + /// + /// The message queue factory. + protected IMessageQueueFactory MessageQueueFactory + { + get { return MessageQueueTemplate.MessageQueueFactory; } + } - /// - /// Gets or sets the message queue template. . - /// - /// The message queue template. - public MessageQueueTemplate MessageQueueTemplate + /// + /// Invoked by an + /// after it has injected all of an object's dependencies. + /// + public void AfterPropertiesSet() + { + if (this.MessageQueueTemplate == null) { - get { return messageQueueTemplate; } - set { messageQueueTemplate = value; } + throw new ArgumentException("MessageQueueTemplate is required"); } - /// - /// Gets the message queue factory, a convenience method. - /// - /// The message queue factory. - protected IMessageQueueFactory MessageQueueFactory + try { - get { return MessageQueueTemplate.MessageQueueFactory; } + InitGateway(); } - - - /// - /// Invoked by an - /// after it has injected all of an object's dependencies. - /// - public void AfterPropertiesSet() + catch (Exception e) { - if (this.MessageQueueTemplate == null) - { - throw new ArgumentException("MessageQueueTemplate is required"); - } - try - { - InitGateway(); - } - catch (Exception e) - { - throw new ObjectInitializationException("Initialization of the MessageQueue gateway failed: " + e.Message, e); - } - } - - - /// - /// Subclasses can override this for custom initialization behavior. - /// Gets called after population of this instance's properties. - /// - protected virtual void InitGateway() - { - + throw new ObjectInitializationException("Initialization of the MessageQueue gateway failed: " + e.Message, e); } } -} + + /// + /// Subclasses can override this for custom initialization behavior. + /// Gets called after population of this instance's properties. + /// + protected virtual void InitGateway() + { + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Messaging/Messaging/Core/MessageQueueMetadata.cs b/src/Spring/Spring.Messaging/Messaging/Core/MessageQueueMetadata.cs index b7fc694d..310f798e 100644 --- a/src/Spring/Spring.Messaging/Messaging/Core/MessageQueueMetadata.cs +++ b/src/Spring/Spring.Messaging/Messaging/Core/MessageQueueMetadata.cs @@ -18,53 +18,52 @@ #endregion -namespace Spring.Messaging.Core +namespace Spring.Messaging.Core; + +/// +/// Encapsulates additional metadata information about the MessageQueue that can not be easily obtained +/// from the MessageQueue itself. +/// +public class MessageQueueMetadata { + private bool remoteQueue; + + private bool remoteQueueIsTransactional; + /// - /// Encapsulates additional metadata information about the MessageQueue that can not be easily obtained - /// from the MessageQueue itself. + /// Initializes a new instance of the class. /// - public class MessageQueueMetadata + /// if set to true [remote queue]. + /// if set to true [remote queue is transactional]. + public MessageQueueMetadata(bool remoteQueue, bool remoteQueueIsTransactional) { - private bool remoteQueue; - - private bool remoteQueueIsTransactional; - - /// - /// Initializes a new instance of the class. - /// - /// if set to true [remote queue]. - /// if set to true [remote queue is transactional]. - public MessageQueueMetadata(bool remoteQueue, bool remoteQueueIsTransactional) - { - this.remoteQueue = remoteQueue; - this.remoteQueueIsTransactional = remoteQueueIsTransactional; - } - - /// - /// Gets or sets a value indicating whether the queue is a remote queue. - /// - /// - /// The operations that one can perform on the MessageQueue depend on if it is local or remote, for - /// example checking if it is transactional. This is very difficult to determine programmatically. - /// The property was made virtual so it can be overridden to take into account custom heuristics you - /// may want to use to determine this programmatically. - /// - /// true if remote queue; otherwise, false. - public virtual bool RemoteQueue - { - get { return remoteQueue; } - } - - /// - /// Gets or sets a value indicating whether the remote queue is transactional. - /// - /// - /// true if the remote queue is transactional; otherwise, false. - /// - public virtual bool RemoteQueueIsTransactional - { - get { return remoteQueueIsTransactional; } - } + this.remoteQueue = remoteQueue; + this.remoteQueueIsTransactional = remoteQueueIsTransactional; } -} \ No newline at end of file + + /// + /// Gets or sets a value indicating whether the queue is a remote queue. + /// + /// + /// The operations that one can perform on the MessageQueue depend on if it is local or remote, for + /// example checking if it is transactional. This is very difficult to determine programmatically. + /// The property was made virtual so it can be overridden to take into account custom heuristics you + /// may want to use to determine this programmatically. + /// + /// true if remote queue; otherwise, false. + public virtual bool RemoteQueue + { + get { return remoteQueue; } + } + + /// + /// Gets or sets a value indicating whether the remote queue is transactional. + /// + /// + /// true if the remote queue is transactional; otherwise, false. + /// + public virtual bool RemoteQueueIsTransactional + { + get { return remoteQueueIsTransactional; } + } +} diff --git a/src/Spring/Spring.Messaging/Messaging/Core/MessageQueueMetadataCache.cs b/src/Spring/Spring.Messaging/Messaging/Core/MessageQueueMetadataCache.cs index 788ea956..e627fb26 100644 --- a/src/Spring/Spring.Messaging/Messaging/Core/MessageQueueMetadataCache.cs +++ b/src/Spring/Spring.Messaging/Messaging/Core/MessageQueueMetadataCache.cs @@ -4,215 +4,221 @@ using Spring.Context; using Spring.Messaging.Support; using Spring.Objects.Factory; -namespace Spring.Messaging.Core +namespace Spring.Messaging.Core; + +/// +/// Hold cached data for queue's metadata. +/// +public class MessageQueueMetadataCache : IApplicationContextAware, IInitializingObject { + #region Logging Definition + + private static readonly ILogger LOG = LogManager.GetLogger(); + + #endregion + + private readonly IDictionary itemStore = new Hashtable(); + + private IConfigurableApplicationContext configurableApplicationContext; + private IApplicationContext applicationContext; + + private bool isInitialized; + /// - /// Hold cached data for queue's metadata. + /// Constructs a new instance of . /// - public class MessageQueueMetadataCache : IApplicationContextAware, IInitializingObject + public MessageQueueMetadataCache() { - #region Logging Definition + } - private static readonly ILogger LOG = LogManager.GetLogger(); + /// + /// Constructs a new instance of . + /// + public MessageQueueMetadataCache(IConfigurableApplicationContext configurableApplicationContext) + { + this.configurableApplicationContext = configurableApplicationContext; + } - #endregion + /// + /// Sets the that this + /// object runs in. + /// + public IApplicationContext ApplicationContext + { + set { applicationContext = value; } + } - private readonly IDictionary itemStore = new Hashtable(); - - private IConfigurableApplicationContext configurableApplicationContext; - private IApplicationContext applicationContext; - - - private bool isInitialized; - - /// - /// Constructs a new instance of . - /// - public MessageQueueMetadataCache() + /// + /// Initializes the cache. + /// + public void Initialize() + { + var messageQueueDictionary = configurableApplicationContext.GetObjects(); + lock (itemStore.SyncRoot) { - } - - /// - /// Constructs a new instance of . - /// - public MessageQueueMetadataCache(IConfigurableApplicationContext configurableApplicationContext) - { - this.configurableApplicationContext = configurableApplicationContext; - } - - /// - /// Sets the that this - /// object runs in. - /// - public IApplicationContext ApplicationContext - { - set { applicationContext = value; } - } - - /// - /// Initializes the cache. - /// - public void Initialize() - { - var messageQueueDictionary = configurableApplicationContext.GetObjects(); - lock (itemStore.SyncRoot) + foreach (KeyValuePair entry in messageQueueDictionary) { - foreach (KeyValuePair entry in messageQueueDictionary) + MessageQueueFactoryObject mqfo = entry.Value; + if (mqfo != null) { - MessageQueueFactoryObject mqfo = entry.Value; - if (mqfo != null) + if (mqfo.Path != null) { - if (mqfo.Path != null) + Insert(mqfo.Path, + new MessageQueueMetadata(mqfo.RemoteQueue, mqfo.RemoteQueueIsTransactional)); + } + else + { + #region Logging + + if (LOG.IsEnabled(LogLevel.Warning)) { - Insert(mqfo.Path, - new MessageQueueMetadata(mqfo.RemoteQueue, mqfo.RemoteQueueIsTransactional)); - } else - { - #region Logging - if (LOG.IsEnabled(LogLevel.Warning)) - { - LOG.LogWarning("Path for MessageQueueFactoryObject named [" + - mqfo.ObjectName + "] is null, so can't cache its metadata."); - } - #endregion + LOG.LogWarning("Path for MessageQueueFactoryObject named [" + + mqfo.ObjectName + "] is null, so can't cache its metadata."); } - } else - { - // This would indicate some bug in GetObjectsOfType - LOG.LogError("Unexpected type of " + entry.Value.GetType() + " was given as candidate for caching MessageQueueMetadata."); + + #endregion } } - isInitialized = true; - } - } - - /// - /// Invoked by an - /// after it has injected all of an object's dependencies. - /// - public void AfterPropertiesSet() - { - IConfigurableApplicationContext ctx = applicationContext as IConfigurableApplicationContext; - if (ctx == null) - { - throw new InvalidOperationException( - "Implementations of IApplicationContext must also implement IConfigurableApplicationContext"); - } - configurableApplicationContext = ctx; - } - - /// - /// Gets the number of items in the cache. - /// - public int Count - { - get - { - lock (itemStore.SyncRoot) + else { - return itemStore.Count; + // This would indicate some bug in GetObjectsOfType + LOG.LogError("Unexpected type of " + entry.Value.GetType() + " was given as candidate for caching MessageQueueMetadata."); } } + + isInitialized = true; + } + } + + /// + /// Invoked by an + /// after it has injected all of an object's dependencies. + /// + public void AfterPropertiesSet() + { + IConfigurableApplicationContext ctx = applicationContext as IConfigurableApplicationContext; + if (ctx == null) + { + throw new InvalidOperationException( + "Implementations of IApplicationContext must also implement IConfigurableApplicationContext"); } - /// - /// Returns whether this cache has been initialized yet. - /// - public bool Initalized - { - get - { - lock (itemStore.SyncRoot) - { - return isInitialized; - } - } - } - /// - /// Gets a collection of all cache queue paths. - /// - public string[] Paths - { - get - { - lock (itemStore.SyncRoot) - { - string[] paths = new string[itemStore.Count]; - int count = 0; - foreach (object path in itemStore.Keys) - { - paths[count] = (string) path; - count++; - } - return paths; - } - } - } + configurableApplicationContext = ctx; + } - /// - /// Retrieves MessageQueueMetadata from the cache. - /// - /// The queue path. - /// - /// Item for the specified , or null. - /// - public MessageQueueMetadata Get(string queuePath) + /// + /// Gets the number of items in the cache. + /// + public int Count + { + get { lock (itemStore.SyncRoot) { - return (MessageQueueMetadata) itemStore[queuePath]; + return itemStore.Count; } } + } - /// - /// Removes the specified queue path from the cache - /// - /// The queue path. - public void Remove(string queuePath) + /// + /// Returns whether this cache has been initialized yet. + /// + public bool Initalized + { + get { lock (itemStore.SyncRoot) + { + return isInitialized; + } + } + } + + /// + /// Gets a collection of all cache queue paths. + /// + public string[] Paths + { + get + { + lock (itemStore.SyncRoot) + { + string[] paths = new string[itemStore.Count]; + int count = 0; + foreach (object path in itemStore.Keys) + { + paths[count] = (string) path; + count++; + } + + return paths; + } + } + } + + /// + /// Retrieves MessageQueueMetadata from the cache. + /// + /// The queue path. + /// + /// Item for the specified , or null. + /// + public MessageQueueMetadata Get(string queuePath) + { + lock (itemStore.SyncRoot) + { + return (MessageQueueMetadata) itemStore[queuePath]; + } + } + + /// + /// Removes the specified queue path from the cache + /// + /// The queue path. + public void Remove(string queuePath) + { + lock (itemStore.SyncRoot) + { + itemStore.Remove(queuePath); + } + } + + /// + /// Removes collection of MessageQueueMetaCache from the cache. + /// + /// + /// Array of MessageQueue paths to remove. + /// + public void RemoveAll(string[] queuePaths) + { + lock (itemStore.SyncRoot) + { + foreach (string queuePath in queuePaths) { itemStore.Remove(queuePath); } } + } - /// - /// Removes collection of MessageQueueMetaCache from the cache. - /// - /// - /// Array of MessageQueue paths to remove. - /// - public void RemoveAll(string[] queuePaths) + /// + /// Removes all MessageQueueMetadata from the cache. + /// + public void Clear() + { + lock (itemStore.SyncRoot) { - lock (itemStore.SyncRoot) - { - foreach (string queuePath in queuePaths) - { - itemStore.Remove(queuePath); - } - } + itemStore.Clear(); } + } - /// - /// Removes all MessageQueueMetadata from the cache. - /// - public void Clear() + /// + /// Inserts metadata to the cache. + /// + public void Insert(string path, MessageQueueMetadata messageQueueMetadata) + { + lock (itemStore.SyncRoot) { - lock (itemStore.SyncRoot) - { - itemStore.Clear(); - } - } - - /// - /// Inserts metadata to the cache. - /// - public void Insert(string path, MessageQueueMetadata messageQueueMetadata) - { - lock (itemStore.SyncRoot) - { - itemStore[path] = messageQueueMetadata; - } + itemStore[path] = messageQueueMetadata; } } } diff --git a/src/Spring/Spring.Messaging/Messaging/Core/MessageQueueResourceHolder.cs b/src/Spring/Spring.Messaging/Messaging/Core/MessageQueueResourceHolder.cs index 32e85680..c2404364 100644 --- a/src/Spring/Spring.Messaging/Messaging/Core/MessageQueueResourceHolder.cs +++ b/src/Spring/Spring.Messaging/Messaging/Core/MessageQueueResourceHolder.cs @@ -20,46 +20,43 @@ using Spring.Transaction.Support; - #if NETSTANDARD using Experimental.System.Messaging; + #else using System.Messaging; #endif -namespace Spring.Messaging.Core +namespace Spring.Messaging.Core; + +/// +/// MessageQueue resource holder, wrapping a MessageQueueTransaction. +/// MessageQueueTransactionManager binds instances of this class to the thread. +/// +/// +/// This is an SPI class, not intended to be used by applications. +/// +/// Mark Pollack +public class MessageQueueResourceHolder : ResourceHolderSupport { + private MessageQueueTransaction messageQueueTransaction; + /// - /// MessageQueue resource holder, wrapping a MessageQueueTransaction. - /// MessageQueueTransactionManager binds instances of this class to the thread. + /// Initializes a new instance of the class. /// - /// - /// This is an SPI class, not intended to be used by applications. - /// - /// Mark Pollack - public class MessageQueueResourceHolder : ResourceHolderSupport + /// The message queue transaction. + public MessageQueueResourceHolder(MessageQueueTransaction messageQueueTransaction) { - private MessageQueueTransaction messageQueueTransaction; - - - /// - /// Initializes a new instance of the class. - /// - /// The message queue transaction. - public MessageQueueResourceHolder(MessageQueueTransaction messageQueueTransaction) - { - this.messageQueueTransaction = messageQueueTransaction; - } - - - /// - /// Gets or sets the message queue transaction. - /// - /// The message queue transaction. - public MessageQueueTransaction MessageQueueTransaction - { - get { return messageQueueTransaction; } - set { messageQueueTransaction = value; } - } + this.messageQueueTransaction = messageQueueTransaction; } -} \ No newline at end of file + + /// + /// Gets or sets the message queue transaction. + /// + /// The message queue transaction. + public MessageQueueTransaction MessageQueueTransaction + { + get { return messageQueueTransaction; } + set { messageQueueTransaction = value; } + } +} diff --git a/src/Spring/Spring.Messaging/Messaging/Core/MessageQueueTemplate.cs b/src/Spring/Spring.Messaging/Messaging/Core/MessageQueueTemplate.cs index 5d9d4b59..a3a02302 100644 --- a/src/Spring/Spring.Messaging/Messaging/Core/MessageQueueTemplate.cs +++ b/src/Spring/Spring.Messaging/Messaging/Core/MessageQueueTemplate.cs @@ -24,664 +24,665 @@ using Spring.Messaging.Support.Converters; using Spring.Objects.Factory; using Spring.Util; - #if NETSTANDARD using Experimental.System.Messaging; + #else using System.Messaging; #endif +namespace Spring.Messaging.Core; -namespace Spring.Messaging.Core +/// +/// Helper class that simplifies MSMQ access code. +/// +/// +/// +/// Using the System.Messaging.MessageQueue class directly in application code has a number of +/// shortcomings, namely that most operations are not thread safe (in particular Send) and +/// IMessageFormatter classes are not thread safe either. +/// +/// +/// The MessageQueueTemplate class overcomes these limitations letting you use a single instance +/// of MessageQueueTemplate across multiple threads to perform standard MessageQueue opertations. +/// Classes that are not thread safe are obtained and cached in thread local storage via an +/// implementation of the interface, specifically +/// . +/// +/// +/// You can access the thread local instance of the MessageQueue associated with this template +/// via the Property DefaultMessageQueue. +/// +/// +/// The template's Send methods will select an appropriate transaction delivery settings so +/// calling code does not need to explicitly manage this responsibility themselves and thus +/// allowing for greater portability of code across different, but common, transactional usage scenarios. +/// +/// A transactional send (either local or DTC transaction) will be +/// attempted for a transacitonal queue, falling back to a single-transaction send +/// to a transactional queue if there is not ambient Spring managed transaction. +/// +/// The overloaded ConvertAndSend and ReceiveAndConvert methods inherit the transactional +/// semantics of the previously described Send method but more importantly, they help to ensure +/// that thread safe access to instances are +/// used as well as providing additional central location to put programmic logic that translates +/// between the MSMQ Message object and the your business objects. This for example is useful if you +/// need to perform additional translation operations after calling a IMessageFormatter instance or +/// want to directly extract and process the Message body contents. +/// +/// +public class MessageQueueTemplate : IMessageQueueOperations, IInitializingObject, IApplicationContextAware { + #region Logging Definition + + private static readonly ILogger LOG = LogManager.GetLogger(typeof(MessageQueueTemplate)); + + #endregion + + #region Fields + + private string defaultMessageQueueObjectName; + private string messageConverterObjectName; + + private IMessageQueueFactory messageQueueFactory; + private IConfigurableApplicationContext applicationContext; + + private TimeSpan timeout = MessageQueue.InfiniteTimeout; + + private MessageQueueMetadataCache metadataCache; + /// - /// Helper class that simplifies MSMQ access code. + /// The name that is used from cache registration inside the application context. + /// + public const string METADATA_CACHE_NAME = "__MessageQueueMetadataCache__"; + + #endregion + + #region Constructors + + /// + /// Initializes a new instance of the class. + /// + public MessageQueueTemplate() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// Name of the message queue as registered in the Spring container. + public MessageQueueTemplate(string messageQueueName) + { + defaultMessageQueueObjectName = messageQueueName; + } + + #endregion + + #region Properties + + /// + /// Gets or sets the message queue factory to use for creating MessageQueue and IMessageConverters. + /// Default value is one that support thread local instances. + /// + /// The message queue factory. + public IMessageQueueFactory MessageQueueFactory + { + get { return messageQueueFactory; } + set { messageQueueFactory = value; } + } + + /// + /// Gets or sets the name of the default message queue as identified in the Spring container. + /// + /// The name of the message queue as identified in the Spring container. + public string DefaultMessageQueueObjectName + { + get { return defaultMessageQueueObjectName; } + set { defaultMessageQueueObjectName = value; } + } + + /// + /// Gets or sets the name of the message converter object. The name will be passed to + /// the class to resolve it to an actual MessageQueue + /// instance. + /// + /// The default name is internally generated and will register an XmlMessageConverter + /// that uses an and a simple System.String as its TargetType. + /// The name of the message converter object. + public string MessageConverterObjectName + { + get { return messageConverterObjectName; } + set { messageConverterObjectName = value; } + } + + /// + /// Gets the default message queue to be used on send/receive operations that do not + /// have a destination parameter. The MessageQueue instance is resolved using + /// the template's , the default implementaion + /// will return an unique instance per thread. + /// + /// The default message queue. + public MessageQueue DefaultMessageQueue + { + get + { + return MessageQueueFactory.CreateMessageQueue(DefaultMessageQueueObjectName); + } + } + + /// + /// Gets the message converter to use for this template. Used to resolve + /// object parameters to ConvertAndSend methods and object results + /// from ReceiveAndConvert methods. /// /// - /// - /// Using the System.Messaging.MessageQueue class directly in application code has a number of - /// shortcomings, namely that most operations are not thread safe (in particular Send) and - /// IMessageFormatter classes are not thread safe either. - /// - /// - /// The MessageQueueTemplate class overcomes these limitations letting you use a single instance - /// of MessageQueueTemplate across multiple threads to perform standard MessageQueue opertations. - /// Classes that are not thread safe are obtained and cached in thread local storage via an - /// implementation of the interface, specifically - /// . - /// - /// - /// You can access the thread local instance of the MessageQueue associated with this template - /// via the Property DefaultMessageQueue. - /// - /// - /// The template's Send methods will select an appropriate transaction delivery settings so - /// calling code does not need to explicitly manage this responsibility themselves and thus - /// allowing for greater portability of code across different, but common, transactional usage scenarios. - /// - /// A transactional send (either local or DTC transaction) will be - /// attempted for a transacitonal queue, falling back to a single-transaction send - /// to a transactional queue if there is not ambient Spring managed transaction. - /// - /// The overloaded ConvertAndSend and ReceiveAndConvert methods inherit the transactional - /// semantics of the previously described Send method but more importantly, they help to ensure - /// that thread safe access to instances are - /// used as well as providing additional central location to put programmic logic that translates - /// between the MSMQ Message object and the your business objects. This for example is useful if you - /// need to perform additional translation operations after calling a IMessageFormatter instance or - /// want to directly extract and process the Message body contents. - /// + /// The default /// - public class MessageQueueTemplate : IMessageQueueOperations, IInitializingObject, IApplicationContextAware + /// The message converter. + public IMessageConverter MessageConverter { - #region Logging Definition - - private static readonly ILogger LOG = LogManager.GetLogger(typeof (MessageQueueTemplate)); - - #endregion - - #region Fields - - private string defaultMessageQueueObjectName; - private string messageConverterObjectName; - - private IMessageQueueFactory messageQueueFactory; - private IConfigurableApplicationContext applicationContext; - - private TimeSpan timeout = MessageQueue.InfiniteTimeout; - - private MessageQueueMetadataCache metadataCache; - - /// - /// The name that is used from cache registration inside the application context. - /// - public const string METADATA_CACHE_NAME = "__MessageQueueMetadataCache__"; - - #endregion - - #region Constructors - - /// - /// Initializes a new instance of the class. - /// - public MessageQueueTemplate() + get { - } - - - /// - /// Initializes a new instance of the class. - /// - /// Name of the message queue as registered in the Spring container. - public MessageQueueTemplate(string messageQueueName) - { - defaultMessageQueueObjectName = messageQueueName; - } - - #endregion - - #region Properties - - /// - /// Gets or sets the message queue factory to use for creating MessageQueue and IMessageConverters. - /// Default value is one that support thread local instances. - /// - /// The message queue factory. - public IMessageQueueFactory MessageQueueFactory - { - get { return messageQueueFactory; } - set { messageQueueFactory = value; } - } - - /// - /// Gets or sets the name of the default message queue as identified in the Spring container. - /// - /// The name of the message queue as identified in the Spring container. - public string DefaultMessageQueueObjectName - { - get { return defaultMessageQueueObjectName; } - set { defaultMessageQueueObjectName = value; } - } - - /// - /// Gets or sets the name of the message converter object. The name will be passed to - /// the class to resolve it to an actual MessageQueue - /// instance. - /// - /// The default name is internally generated and will register an XmlMessageConverter - /// that uses an and a simple System.String as its TargetType. - /// The name of the message converter object. - public string MessageConverterObjectName - { - get { return messageConverterObjectName; } - set { messageConverterObjectName = value; } - } - - /// - /// Gets the default message queue to be used on send/receive operations that do not - /// have a destination parameter. The MessageQueue instance is resolved using - /// the template's , the default implementaion - /// will return an unique instance per thread. - /// - /// The default message queue. - public MessageQueue DefaultMessageQueue - { - get - { - return MessageQueueFactory.CreateMessageQueue(DefaultMessageQueueObjectName); - } - } - - - /// - /// Gets the message converter to use for this template. Used to resolve - /// object parameters to ConvertAndSend methods and object results - /// from ReceiveAndConvert methods. - /// - /// - /// The default - /// - /// The message converter. - public IMessageConverter MessageConverter - { - get - { - if (messageConverterObjectName == null) - { - throw new InvalidOperationException( - "No MessageConverter registered. Check configuration of MessageQueueTemplate."); - } - return messageQueueFactory.CreateMessageConverter(MessageConverterObjectName); - } - } - - - /// - /// Gets or sets the receive timeout to be used on recieve operations. Default value is - /// MessageQueue.InfiniteTimeout (which is actually ~3 months). - /// - /// The receive timeout. - public TimeSpan ReceiveTimeout - { - get { return timeout; } - set { timeout = value; } - } - - /// - /// Gets or sets the metadata cache. - /// - /// The metadata cache. - public MessageQueueMetadataCache MetadataCache - { - get { return metadataCache; } - set { metadataCache = value; } - } - - #endregion - - #region IApplicationContextAware Members - - /// - /// Gets or sets the that this - /// object runs in. - /// - /// - ///

- /// Normally this call will be used to initialize the object. - ///

- ///

- /// Invoked after population of normal object properties but before an - /// init callback such as - /// 's - /// - /// or a custom init-method. Invoked after the setting of any - /// 's - /// - /// property. - ///

- ///
- /// - /// In the case of application context initialization errors. - /// - /// - /// If thrown by any application context methods. - /// - /// - public IApplicationContext ApplicationContext - { - get { return applicationContext; } - set { - AssertUtils.ArgumentNotNull(value, "An ApplicationContext instance is required"); - var ctx = value as IConfigurableApplicationContext; - if (ctx == null) - { - throw new InvalidOperationException( - "Implementations of IApplicationContext must also implement IConfigurableApplicationContext"); - } - - applicationContext = ctx; - } - } - - #endregion - - #region IInitializingObject Members - - - /// - /// Invoked by an - /// after it has injected all of an object's dependencies. - /// - /// - /// Ensure that the DefaultMessageQueueObjectName property is set, creates - /// a default implementation of the interface - /// () that retrieves instances on a per-thread - /// basis, and registers in the Spring container a default implementation of - /// () with a - /// simple System.String as its TargetType. - /// - public void AfterPropertiesSet() - { - if (MessageQueueFactory == null) - { - AssertUtils.ArgumentNotNull(applicationContext, "MessageQueueTemplate requires the ApplicationContext property to be set if the MessageQueueFactory property is not set for automatic create of the DefaultMessageQueueFactory"); - - DefaultMessageQueueFactory mqf = new DefaultMessageQueueFactory(); - mqf.ApplicationContext = applicationContext; - messageQueueFactory = mqf; - } if (messageConverterObjectName == null) { - messageConverterObjectName = QueueUtils.RegisterDefaultMessageConverter(applicationContext); + throw new InvalidOperationException( + "No MessageConverter registered. Check configuration of MessageQueueTemplate."); } - //If it has not been set by the user explicitly, then initialize. - CreateDefaultMetadataCache(); + + return messageQueueFactory.CreateMessageConverter(MessageConverterObjectName); + } + } + + /// + /// Gets or sets the receive timeout to be used on recieve operations. Default value is + /// MessageQueue.InfiniteTimeout (which is actually ~3 months). + /// + /// The receive timeout. + public TimeSpan ReceiveTimeout + { + get { return timeout; } + set { timeout = value; } + } + + /// + /// Gets or sets the metadata cache. + /// + /// The metadata cache. + public MessageQueueMetadataCache MetadataCache + { + get { return metadataCache; } + set { metadataCache = value; } + } + + #endregion + + #region IApplicationContextAware Members + + /// + /// Gets or sets the that this + /// object runs in. + /// + /// + ///

+ /// Normally this call will be used to initialize the object. + ///

+ ///

+ /// Invoked after population of normal object properties but before an + /// init callback such as + /// 's + /// + /// or a custom init-method. Invoked after the setting of any + /// 's + /// + /// property. + ///

+ ///
+ /// + /// In the case of application context initialization errors. + /// + /// + /// If thrown by any application context methods. + /// + /// + public IApplicationContext ApplicationContext + { + get { return applicationContext; } + set + { + AssertUtils.ArgumentNotNull(value, "An ApplicationContext instance is required"); + var ctx = value as IConfigurableApplicationContext; + if (ctx == null) + { + throw new InvalidOperationException( + "Implementations of IApplicationContext must also implement IConfigurableApplicationContext"); + } + + applicationContext = ctx; + } + } + + #endregion + + #region IInitializingObject Members + + /// + /// Invoked by an + /// after it has injected all of an object's dependencies. + /// + /// + /// Ensure that the DefaultMessageQueueObjectName property is set, creates + /// a default implementation of the interface + /// () that retrieves instances on a per-thread + /// basis, and registers in the Spring container a default implementation of + /// () with a + /// simple System.String as its TargetType. + /// + public void AfterPropertiesSet() + { + if (MessageQueueFactory == null) + { + AssertUtils.ArgumentNotNull(applicationContext, "MessageQueueTemplate requires the ApplicationContext property to be set if the MessageQueueFactory property is not set for automatic create of the DefaultMessageQueueFactory"); + + DefaultMessageQueueFactory mqf = new DefaultMessageQueueFactory(); + mqf.ApplicationContext = applicationContext; + messageQueueFactory = mqf; } - /// - /// Constructs the metadata cache with default options. - /// - protected virtual void CreateDefaultMetadataCache() + if (messageConverterObjectName == null) { - if (metadataCache == null) + messageConverterObjectName = QueueUtils.RegisterDefaultMessageConverter(applicationContext); + } + + //If it has not been set by the user explicitly, then initialize. + CreateDefaultMetadataCache(); + } + + /// + /// Constructs the metadata cache with default options. + /// + protected virtual void CreateDefaultMetadataCache() + { + if (metadataCache == null) + { + if (applicationContext.ContainsObject(METADATA_CACHE_NAME)) { - if (applicationContext.ContainsObject(METADATA_CACHE_NAME)) + metadataCache = applicationContext.GetObject(METADATA_CACHE_NAME) as MessageQueueMetadataCache; + } + else + { + metadataCache = new MessageQueueMetadataCache(); + if (ApplicationContext != null) { - metadataCache = applicationContext.GetObject(METADATA_CACHE_NAME) as MessageQueueMetadataCache; + metadataCache.ApplicationContext = ApplicationContext; + metadataCache.AfterPropertiesSet(); + metadataCache.Initialize(); + applicationContext.ObjectFactory.RegisterSingleton("__MessageQueueMetadataCache__", + metadataCache); } else { - metadataCache = new MessageQueueMetadataCache(); - if (ApplicationContext != null) - { - metadataCache.ApplicationContext = ApplicationContext; - metadataCache.AfterPropertiesSet(); - metadataCache.Initialize(); - applicationContext.ObjectFactory.RegisterSingleton("__MessageQueueMetadataCache__", - metadataCache); - } - else - { - #region Logging + #region Logging - if (LOG.IsEnabled(LogLevel.Warning)) - { - LOG.LogWarning("The ApplicationContext property has not been set, so the MessageQueueMetadataCache can not be automatically generated. " + - "Please explictly set the MessageQueueMetadataCache using the property MetadataCache or set the ApplicationContext property. " + - "This will only effect the use of MessageQueueTemplate when publishing to remote queues."); - } - - #endregion + if (LOG.IsEnabled(LogLevel.Warning)) + { + LOG.LogWarning("The ApplicationContext property has not been set, so the MessageQueueMetadataCache can not be automatically generated. " + + "Please explictly set the MessageQueueMetadataCache using the property MetadataCache or set the ApplicationContext property. " + + "This will only effect the use of MessageQueueTemplate when publishing to remote queues."); } + + #endregion } } } + } - #endregion + #endregion - #region IMessageQueueOperations Members + #region IMessageQueueOperations Members - /// - /// Send the given object to the default destination, converting the object - /// to a MSMQ message with a configured IMessageConverter. - /// - /// The obj. - /// This will only work with a default destination queue specified! - public void ConvertAndSend(object obj) + /// + /// Send the given object to the default destination, converting the object + /// to a MSMQ message with a configured IMessageConverter. + /// + /// The obj. + /// This will only work with a default destination queue specified! + public void ConvertAndSend(object obj) + { + CheckDefaultMessageQueue(); + ConvertAndSend(DefaultMessageQueueObjectName, obj); + } + + /// + /// Send the given object to the default destination, converting the object + /// to a MSMQ message with a configured IMessageConverter. The IMessagePostProcessor + /// callback allows for modification of the message after conversion. + ///

This will only work with a default destination specified!

+ ///
+ /// the object to convert to a message + /// the callback to modify the message + /// if thrown by MSMQ API methods + public void ConvertAndSend(object obj, MessagePostProcessorDelegate messagePostProcessorDelegate) + { + CheckDefaultMessageQueue(); + ConvertAndSend(DefaultMessageQueueObjectName, obj, messagePostProcessorDelegate); + } + + /// + /// Send the given object to the specified destination, converting the object + /// to a MSMQ message with a configured and resolving the + /// destination name to a using a + /// + /// the name of the destination queue + /// to send this message to (to be resolved to an actual MessageQueue + /// by a IMessageQueueFactory) + /// the object to convert to a message + /// NMSException if there is any problem + public void ConvertAndSend(string messageQueueObjectName, object obj) + { + Message msg = MessageConverter.ToMessage(obj); + Send(MessageQueueFactory.CreateMessageQueue(messageQueueObjectName), msg); + } + + /// + /// Send the given object to the specified destination, converting the object + /// to a MSMQ message with a configured and resolving the + /// destination name to a with an + /// The callback allows for modification of the message after conversion. + /// + /// the name of the destination queue + /// to send this message to (to be resolved to an actual MessageQueue + /// by a IMessageQueueFactory) + /// the object to convert to a message + /// the callback to modify the message + /// if thrown by MSMQ API methods + public void ConvertAndSend(string messageQueueObjectName, object obj, + MessagePostProcessorDelegate messagePostProcessorDelegate) + { + Message msg = MessageConverter.ToMessage(obj); + Message msgToSend = messagePostProcessorDelegate(msg); + Send(MessageQueueFactory.CreateMessageQueue(messageQueueObjectName), msgToSend); + } + + /// + /// Receive and convert a message synchronously from the default message queue. + /// + /// The converted object + /// if thrown by MSMQ API methods. Note an + /// exception will be thrown if the timeout of the syncrhonous recieve operation expires. + /// + public object ReceiveAndConvert() + { + MessageQueue mq = DefaultMessageQueue; + Message m = mq.Receive(ReceiveTimeout); + return DoConvertMessage(m); + } + + /// + /// Receives and convert a message synchronously from the specified message queue. + /// + /// Name of the message queue object. + /// the converted object + /// if thrown by MSMQ API methods. Note an + /// exception will be thrown if the timeout of the syncrhonous recieve operation expires. + /// + public object ReceiveAndConvert(string messageQueueObjectName) + { + MessageQueue mq = MessageQueueFactory.CreateMessageQueue(messageQueueObjectName); + Message m = mq.Receive(ReceiveTimeout); + return DoConvertMessage(m); + } + + /// + /// Receives a message on the default message queue using the transactional settings as dicted by MessageQueue's Transactional property and + /// the current Spring managed ambient transaction. + /// + /// A message. + public Message Receive() + { + return DefaultMessageQueue.Receive(ReceiveTimeout); + } + + /// + /// Receives a message on the specified queue using the transactional settings as dicted by MessageQueue's Transactional property and + /// the current Spring managed ambient transaction. + /// + /// Name of the message queue object. + /// + public Message Receive(string messageQueueObjectName) + { + return MessageQueueFactory.CreateMessageQueue(messageQueueObjectName).Receive(ReceiveTimeout); + } + + /// + /// Sends the specified message to the default message queue using the + /// transactional settings as dicted by MessageQueue's Transactional property and + /// the current Spring managed ambient transaction. + /// + /// The message to send + public void Send(Message message) + { + Send(DefaultMessageQueue, message); + } + + /// + /// Sends the specified message to the message queue using the + /// transactional settings as dicted by MessageQueue's Transactional property and + /// the current Spring managed ambient transaction. + /// + /// Name of the message queue object. + /// The message. + public void Send(string messageQueueObjectName, Message message) + { + Send(MessageQueueFactory.CreateMessageQueue(messageQueueObjectName), message); + } + + /// + /// Sends the specified message on the provided MessageQueue using the + /// transactional settings as dicted by MessageQueue's Transactional property and + /// the current Spring managed ambient transaction. + /// + /// The DefaultMessageQueue to send a message to. + /// The message to send + /// + /// Note that it is the callers responsibility to ensure that the MessageQueue instance + /// passed into this not being access simultaneously by other threads. + /// + /// A transactional send (either local or DTC transaction) will be + /// attempted for a transacitonal queue, falling back to a single-transaction send + /// to a transactional queue if there is not ambient Spring managed transaction. + public virtual void Send(MessageQueue messageQueue, Message message) + { + DoSend(messageQueue, message); + } + + #endregion + + #region Protected Methods + + /// + /// Sends the message to the given message queue. + /// + /// If System.Transactions.Transaction.Current is null, then send based on + /// the transaction semantics of the queue definition. See + /// The message queue. + /// The message. + protected virtual void DoSend(MessageQueue messageQueue, Message message) + { + if (System.Transactions.Transaction.Current == null) { - CheckDefaultMessageQueue(); - ConvertAndSend(DefaultMessageQueueObjectName, obj); + DoSendMessageQueue(messageQueue, message); } - - /// - /// Send the given object to the default destination, converting the object - /// to a MSMQ message with a configured IMessageConverter. The IMessagePostProcessor - /// callback allows for modification of the message after conversion. - ///

This will only work with a default destination specified!

- ///
- /// the object to convert to a message - /// the callback to modify the message - /// if thrown by MSMQ API methods - public void ConvertAndSend(object obj, MessagePostProcessorDelegate messagePostProcessorDelegate) + else { - CheckDefaultMessageQueue(); - ConvertAndSend(DefaultMessageQueueObjectName, obj, messagePostProcessorDelegate); + DoSendTxScope(messageQueue, message); } + } - /// - /// Send the given object to the specified destination, converting the object - /// to a MSMQ message with a configured and resolving the - /// destination name to a using a - /// - /// the name of the destination queue - /// to send this message to (to be resolved to an actual MessageQueue - /// by a IMessageQueueFactory) - /// the object to convert to a message - /// NMSException if there is any problem - public void ConvertAndSend(string messageQueueObjectName, object obj) + /// + /// Send the message queue selecting the appropriate transactional delivery options. + /// + /// + /// + /// If the message queue is transactional and there is an ambient MessageQueueTransaction + /// in thread local storage (put there via the use of Spring's MessageQueueTransactionManager + /// or TransactionalMessageListenerContainer), the message will be sent transactionally using the + /// MessageQueueTransaction object in thread local storage. This lets you group together multiple + /// messaging operations within the same transaction without having to explicitly pass around the + /// MessageQueueTransaction object. + /// + /// + /// If the message queue is transactional but there is no ambient MessageQueueTransaction, + /// then a single message transaction is created on each messaging operation. + /// (MessageQueueTransactionType = Single). + /// + /// + /// If there is an ambient System.Transactions transaction then that transaction will + /// be used (MessageQueueTransactionType = Automatic). + /// + /// + /// If the queue is not transactional, then a non-transactional send + /// (MessageQueueTransactionType = None) is used. + /// + /// + /// The mq. + /// The MSG. + protected virtual void DoSendMessageQueue(MessageQueue mq, Message msg) + { + MessageQueueTransaction transactionToUse = QueueUtils.GetMessageQueueTransaction(null); + if (metadataCache != null) { - Message msg = MessageConverter.ToMessage(obj); - Send(MessageQueueFactory.CreateMessageQueue(messageQueueObjectName), msg); - } - - /// - /// Send the given object to the specified destination, converting the object - /// to a MSMQ message with a configured and resolving the - /// destination name to a with an - /// The callback allows for modification of the message after conversion. - /// - /// the name of the destination queue - /// to send this message to (to be resolved to an actual MessageQueue - /// by a IMessageQueueFactory) - /// the object to convert to a message - /// the callback to modify the message - /// if thrown by MSMQ API methods - public void ConvertAndSend(string messageQueueObjectName, object obj, - MessagePostProcessorDelegate messagePostProcessorDelegate) - { - Message msg = MessageConverter.ToMessage(obj); - Message msgToSend = messagePostProcessorDelegate(msg); - Send(MessageQueueFactory.CreateMessageQueue(messageQueueObjectName), msgToSend); - } - - /// - /// Receive and convert a message synchronously from the default message queue. - /// - /// The converted object - /// if thrown by MSMQ API methods. Note an - /// exception will be thrown if the timeout of the syncrhonous recieve operation expires. - /// - public object ReceiveAndConvert() - { - MessageQueue mq = DefaultMessageQueue; - Message m = mq.Receive(ReceiveTimeout); - return DoConvertMessage(m); - } - - /// - /// Receives and convert a message synchronously from the specified message queue. - /// - /// Name of the message queue object. - /// the converted object - /// if thrown by MSMQ API methods. Note an - /// exception will be thrown if the timeout of the syncrhonous recieve operation expires. - /// - public object ReceiveAndConvert(string messageQueueObjectName) - { - MessageQueue mq = MessageQueueFactory.CreateMessageQueue(messageQueueObjectName); - Message m = mq.Receive(ReceiveTimeout); - return DoConvertMessage(m); - } - - /// - /// Receives a message on the default message queue using the transactional settings as dicted by MessageQueue's Transactional property and - /// the current Spring managed ambient transaction. - /// - /// A message. - public Message Receive() - { - return DefaultMessageQueue.Receive(ReceiveTimeout); - } - - /// - /// Receives a message on the specified queue using the transactional settings as dicted by MessageQueue's Transactional property and - /// the current Spring managed ambient transaction. - /// - /// Name of the message queue object. - /// - public Message Receive(string messageQueueObjectName) - { - return MessageQueueFactory.CreateMessageQueue(messageQueueObjectName).Receive(ReceiveTimeout); - } - - /// - /// Sends the specified message to the default message queue using the - /// transactional settings as dicted by MessageQueue's Transactional property and - /// the current Spring managed ambient transaction. - /// - /// The message to send - public void Send(Message message) - { - Send(DefaultMessageQueue, message); - } - - /// - /// Sends the specified message to the message queue using the - /// transactional settings as dicted by MessageQueue's Transactional property and - /// the current Spring managed ambient transaction. - /// - /// Name of the message queue object. - /// The message. - public void Send(string messageQueueObjectName, Message message) - { - Send(MessageQueueFactory.CreateMessageQueue(messageQueueObjectName), message); - } - - /// - /// Sends the specified message on the provided MessageQueue using the - /// transactional settings as dicted by MessageQueue's Transactional property and - /// the current Spring managed ambient transaction. - /// - /// The DefaultMessageQueue to send a message to. - /// The message to send - /// - /// Note that it is the callers responsibility to ensure that the MessageQueue instance - /// passed into this not being access simultaneously by other threads. - /// - /// A transactional send (either local or DTC transaction) will be - /// attempted for a transacitonal queue, falling back to a single-transaction send - /// to a transactional queue if there is not ambient Spring managed transaction. - public virtual void Send(MessageQueue messageQueue, Message message) - { - DoSend(messageQueue, message); - } - - #endregion - - #region Protected Methods - - /// - /// Sends the message to the given message queue. - /// - /// If System.Transactions.Transaction.Current is null, then send based on - /// the transaction semantics of the queue definition. See - /// The message queue. - /// The message. - protected virtual void DoSend(MessageQueue messageQueue, Message message) - { - if (System.Transactions.Transaction.Current == null) + MessageQueueMetadata mqMetadata = metadataCache.Get(mq.Path); + if (mqMetadata != null) { - DoSendMessageQueue(messageQueue, message); - } - else - { - DoSendTxScope(messageQueue, message); - } - } - - /// - /// Send the message queue selecting the appropriate transactional delivery options. - /// - /// - /// - /// If the message queue is transactional and there is an ambient MessageQueueTransaction - /// in thread local storage (put there via the use of Spring's MessageQueueTransactionManager - /// or TransactionalMessageListenerContainer), the message will be sent transactionally using the - /// MessageQueueTransaction object in thread local storage. This lets you group together multiple - /// messaging operations within the same transaction without having to explicitly pass around the - /// MessageQueueTransaction object. - /// - /// - /// If the message queue is transactional but there is no ambient MessageQueueTransaction, - /// then a single message transaction is created on each messaging operation. - /// (MessageQueueTransactionType = Single). - /// - /// - /// If there is an ambient System.Transactions transaction then that transaction will - /// be used (MessageQueueTransactionType = Automatic). - /// - /// - /// If the queue is not transactional, then a non-transactional send - /// (MessageQueueTransactionType = None) is used. - /// - /// - /// The mq. - /// The MSG. - protected virtual void DoSendMessageQueue(MessageQueue mq, Message msg) - { - MessageQueueTransaction transactionToUse = QueueUtils.GetMessageQueueTransaction(null); - if (metadataCache != null) - { - MessageQueueMetadata mqMetadata = metadataCache.Get(mq.Path); - if (mqMetadata != null) + if (mqMetadata.RemoteQueue) { - if (mqMetadata.RemoteQueue) + if (mqMetadata.RemoteQueueIsTransactional) { - if (mqMetadata.RemoteQueueIsTransactional) - { - // DefaultMessageQueue transaction is externally managed. - DoSendMessageTransaction(mq, transactionToUse, msg); - return; - } - DoSendMessageQueueNonTransactional(mq, transactionToUse, msg); + // DefaultMessageQueue transaction is externally managed. + DoSendMessageTransaction(mq, transactionToUse, msg); return; } - } - } else - { - if (LOG.IsEnabled(LogLevel.Warning)) - { - LOG.LogWarning("MetadataCache has not been initialized. Set the MetadataCache explicitly in standalone usage and/or " + - "configure the MessageQueueTemplate in an ApplicationContext. If deployed in an ApplicationContext by default " + - "the MetadataCache will automaticaly populated."); + + DoSendMessageQueueNonTransactional(mq, transactionToUse, msg); + return; } } - // Handle assuming these are local queues. - - if (mq.Transactional) - { - // DefaultMessageQueue transaction is externally managed. - DoSendMessageTransaction(mq, transactionToUse, msg); - } - else - { - DoSendMessageQueueNonTransactional(mq, transactionToUse, msg); - } } - - /// - /// Does the send message transaction. - /// - /// The mq. - /// The transaction to use. - /// The MSG. - protected virtual void DoSendMessageTransaction(MessageQueue mq, MessageQueueTransaction transactionToUse, Message msg) + else { - if (transactionToUse != null) + if (LOG.IsEnabled(LogLevel.Warning)) { - if (LOG.IsEnabled(LogLevel.Debug)) - { - LOG.LogDebug("Sending messsage using externally managed MessageQueueTransction to transactional queue with path [" + mq.Path + "]."); - } - mq.Send(msg, transactionToUse); - } - else - { - /* From MSDN documentation - * If a non-transactional message is sent to a transactional queue, - * this component creates a single-message transaction for it, - * except in the case of referencing a queue on a remote computer - * using a direct format name. In this situation, if you do not specify a - * transaction context when sending a message, one is not created for you - * and the message will be sent to the dead-letter queue.*/ - LOG.LogWarning("Sending message using implicit single-message transaction to transactional queue queue with path [" + mq.Path + "]."); - mq.Send(msg, MessageQueueTransactionType.Single); + LOG.LogWarning("MetadataCache has not been initialized. Set the MetadataCache explicitly in standalone usage and/or " + + "configure the MessageQueueTemplate in an ApplicationContext. If deployed in an ApplicationContext by default " + + "the MetadataCache will automaticaly populated."); } } + // Handle assuming these are local queues. - /// - /// Does the send message queue non transactional. - /// - /// The mq. - /// The transaction to use. - /// The MSG. - protected virtual void DoSendMessageQueueNonTransactional(MessageQueue mq, MessageQueueTransaction transactionToUse, Message msg) + if (mq.Transactional) { - if (transactionToUse != null) - { - LOG.LogWarning("Thread local message transaction ignored for sending to non-transactional queue with path [" + mq.Path + "]."); - mq.Send(msg); - } - else - { - if (LOG.IsEnabled(LogLevel.Debug)) - { - LOG.LogDebug("Sending messsage without MSMQ transaction to non-transactional queue with path [" + mq.Path + "]."); - } - //Typical case, non TLS transaction, non-tx queue. - mq.Send(msg); - } + // DefaultMessageQueue transaction is externally managed. + DoSendMessageTransaction(mq, transactionToUse, msg); } - - - /// - /// Sends using MessageQueueTransactionType.Automatic transaction type - /// - /// The message queue. - /// The message. - protected virtual void DoSendTxScope(MessageQueue mq, Message msg) + else { - mq.Send(msg, MessageQueueTransactionType.Automatic); + DoSendMessageQueueNonTransactional(mq, transactionToUse, msg); } - - /// - /// Template method to convert the message if it is not null. - /// - /// The message. - /// The converted message ,or null if no message converter is set. - protected virtual object DoConvertMessage(Message m) - { - if (m != null) - { - return MessageConverter.FromMessage(m); - } - else - { - return null; - } - } - - /// - /// Checks if the default message queue if defined. - /// - protected virtual void CheckDefaultMessageQueue() - { - if (DefaultMessageQueueObjectName == null) - { - throw new SystemException("No DefaultMessageQueueObjectName specified. Check configuration of MessageQueueTemplate."); - } - } - - #endregion } + + /// + /// Does the send message transaction. + /// + /// The mq. + /// The transaction to use. + /// The MSG. + protected virtual void DoSendMessageTransaction(MessageQueue mq, MessageQueueTransaction transactionToUse, Message msg) + { + if (transactionToUse != null) + { + if (LOG.IsEnabled(LogLevel.Debug)) + { + LOG.LogDebug("Sending messsage using externally managed MessageQueueTransction to transactional queue with path [" + mq.Path + "]."); + } + + mq.Send(msg, transactionToUse); + } + else + { + /* From MSDN documentation + * If a non-transactional message is sent to a transactional queue, + * this component creates a single-message transaction for it, + * except in the case of referencing a queue on a remote computer + * using a direct format name. In this situation, if you do not specify a + * transaction context when sending a message, one is not created for you + * and the message will be sent to the dead-letter queue.*/ + LOG.LogWarning("Sending message using implicit single-message transaction to transactional queue queue with path [" + mq.Path + "]."); + mq.Send(msg, MessageQueueTransactionType.Single); + } + } + + /// + /// Does the send message queue non transactional. + /// + /// The mq. + /// The transaction to use. + /// The MSG. + protected virtual void DoSendMessageQueueNonTransactional(MessageQueue mq, MessageQueueTransaction transactionToUse, Message msg) + { + if (transactionToUse != null) + { + LOG.LogWarning("Thread local message transaction ignored for sending to non-transactional queue with path [" + mq.Path + "]."); + mq.Send(msg); + } + else + { + if (LOG.IsEnabled(LogLevel.Debug)) + { + LOG.LogDebug("Sending messsage without MSMQ transaction to non-transactional queue with path [" + mq.Path + "]."); + } + + //Typical case, non TLS transaction, non-tx queue. + mq.Send(msg); + } + } + + /// + /// Sends using MessageQueueTransactionType.Automatic transaction type + /// + /// The message queue. + /// The message. + protected virtual void DoSendTxScope(MessageQueue mq, Message msg) + { + mq.Send(msg, MessageQueueTransactionType.Automatic); + } + + /// + /// Template method to convert the message if it is not null. + /// + /// The message. + /// The converted message ,or null if no message converter is set. + protected virtual object DoConvertMessage(Message m) + { + if (m != null) + { + return MessageConverter.FromMessage(m); + } + else + { + return null; + } + } + + /// + /// Checks if the default message queue if defined. + /// + protected virtual void CheckDefaultMessageQueue() + { + if (DefaultMessageQueueObjectName == null) + { + throw new SystemException("No DefaultMessageQueueObjectName specified. Check configuration of MessageQueueTemplate."); + } + } + + #endregion } diff --git a/src/Spring/Spring.Messaging/Messaging/Core/MessageQueueTransactionManager.cs b/src/Spring/Spring.Messaging/Messaging/Core/MessageQueueTransactionManager.cs index 8d5469d6..4540f020 100644 --- a/src/Spring/Spring.Messaging/Messaging/Core/MessageQueueTransactionManager.cs +++ b/src/Spring/Spring.Messaging/Messaging/Core/MessageQueueTransactionManager.cs @@ -26,258 +26,259 @@ using Spring.Util; #if NETSTANDARD using Experimental.System.Messaging; + #else using System.Messaging; #endif -namespace Spring.Messaging.Core +namespace Spring.Messaging.Core; + +/// +/// implementation for MSMQ. Binds a +/// MessageQueueTransaction to the thread. +/// +/// +/// +/// This local strategy is an alternative to executing MSMQ operations within +/// DTC transactions. Its advantage is that multiple MSMQ operations can +/// easily participate within the same local MessagingTransaction transparently when +/// using the class for send and recieve operations +/// and not pay the overhead of a DTC transaction. +/// +/// Transaction synchronization is turned off by default, as this manager might +/// be used alongside a IDbProvider-based Spring transaction manager such as the +/// ADO.NET . +/// which has stronger needs for synchronization. +/// +/// Mark Pollack +public class MessageQueueTransactionManager : AbstractPlatformTransactionManager { /// - /// implementation for MSMQ. Binds a - /// MessageQueueTransaction to the thread. + /// Location where the message transaction is stored in thread local storage. + /// + public static readonly string CURRENT_TRANSACTION_SLOTNAME = + UniqueKey.GetTypeScopedString(typeof(MessageQueueTransaction), "Current"); + + #region Logging Definition + + private static readonly ILogger LOG = LogManager.GetLogger(typeof(MessageQueueTransactionManager)); + + #endregion + + /// + /// Initializes a new instance of the class. /// /// - /// - /// This local strategy is an alternative to executing MSMQ operations within - /// DTC transactions. Its advantage is that multiple MSMQ operations can - /// easily participate within the same local MessagingTransaction transparently when - /// using the class for send and recieve operations - /// and not pay the overhead of a DTC transaction. - /// - /// Transaction synchronization is turned off by default, as this manager might - /// be used alongside a IDbProvider-based Spring transaction manager such as the - /// ADO.NET . - /// which has stronger needs for synchronization. + /// Turns off transaction synchronization by default, as this manager might + /// be used alongside a DbProvider-based Spring transaction manager like + /// AdoPlatformTransactionManager, which has stronger needs for synchronization. + /// Only one manager is allowed to drive synchronization at any point of time. /// - /// Mark Pollack - public class MessageQueueTransactionManager : AbstractPlatformTransactionManager + public MessageQueueTransactionManager() { - /// - /// Location where the message transaction is stored in thread local storage. - /// - public static readonly string CURRENT_TRANSACTION_SLOTNAME = - UniqueKey.GetTypeScopedString(typeof (MessageQueueTransaction), "Current"); + TransactionSynchronization = TransactionSynchronizationState.Never; + } - #region Logging Definition + /// + /// Return the current transaction object. + /// + /// The current transaction object. + /// + /// If transaction support is not available. + /// + /// + /// In the case of lookup or system errors. + /// + protected override object DoGetTransaction() + { + MessageQueueTransactionObject txObject = new MessageQueueTransactionObject(); + txObject.ResourceHolder = + (MessageQueueResourceHolder) TransactionSynchronizationManager.GetResource(CURRENT_TRANSACTION_SLOTNAME); + return txObject; + } - private static readonly ILogger LOG = LogManager.GetLogger(typeof (MessageQueueTransactionManager)); + /// + /// Check if the given transaction object indicates an existing transaction + /// (that is, a transaction which has already started). + /// + /// MessageQueueTransactionObject object returned by + /// . + /// + /// True if there is an existing transaction. + /// + protected override bool IsExistingTransaction(object transaction) + { + MessageQueueTransactionObject txObject = (MessageQueueTransactionObject) transaction; + return (txObject.ResourceHolder != null); + } - #endregion + /// + /// Begin a new transaction with the given transaction definition. + /// + /// Transaction object returned by + /// . + /// instance, describing + /// propagation behavior, isolation level, timeout etc. + /// + /// In the case of creation or system errors. + /// + protected override void DoBegin(object transaction, ITransactionDefinition definition) + { + MessageQueueTransactionObject txObject = (MessageQueueTransactionObject) transaction; - /// - /// Initializes a new instance of the class. - /// - /// - /// Turns off transaction synchronization by default, as this manager might - /// be used alongside a DbProvider-based Spring transaction manager like - /// AdoPlatformTransactionManager, which has stronger needs for synchronization. - /// Only one manager is allowed to drive synchronization at any point of time. - /// - public MessageQueueTransactionManager() + MessageQueueTransaction mqt = new MessageQueueTransaction(); + mqt.Begin(); + + txObject.ResourceHolder = new MessageQueueResourceHolder(mqt); + txObject.ResourceHolder.SynchronizedWithTransaction = true; + + int timeout = DetermineTimeout(definition); + if (timeout != DefaultTransactionDefinition.TIMEOUT_DEFAULT) { - TransactionSynchronization = TransactionSynchronizationState.Never; + txObject.ResourceHolder.TimeoutInSeconds = timeout; } - /// - /// Return the current transaction object. - /// - /// The current transaction object. - /// - /// If transaction support is not available. - /// - /// - /// In the case of lookup or system errors. - /// - protected override object DoGetTransaction() + TransactionSynchronizationManager.BindResource(CURRENT_TRANSACTION_SLOTNAME, txObject.ResourceHolder); + } + + /// + /// Suspend the resources of the current transaction. + /// + /// Transaction object returned by + /// . + /// + /// An object that holds suspended resources (will be kept unexamined for passing it into + /// .) + /// + protected override object DoSuspend(object transaction) + { + MessageQueueTransactionObject txObject = (MessageQueueTransactionObject) transaction; + txObject.ResourceHolder = null; + return TransactionSynchronizationManager.UnbindResource(CURRENT_TRANSACTION_SLOTNAME); + } + + /// + /// Resume the resources of the current transaction. + /// + /// Transaction object returned by + /// . + /// The object that holds suspended resources as returned by + /// . + protected override void DoResume(object transaction, object suspendedResources) + { + MessageQueueResourceHolder queueHolder = (MessageQueueResourceHolder) suspendedResources; + TransactionSynchronizationManager.BindResource(CURRENT_TRANSACTION_SLOTNAME, queueHolder); + } + + /// + /// Perform an actual commit on the given transaction. + /// + /// The status representation of the transaction. + /// + ///

+ /// An implementation does not need to check the rollback-only flag. + ///

+ ///
+ protected override void DoCommit(DefaultTransactionStatus status) + { + MessageQueueTransactionObject txObject = (MessageQueueTransactionObject) status.Transaction; + MessageQueueTransaction transaction = txObject.ResourceHolder.MessageQueueTransaction; + try { - MessageQueueTransactionObject txObject = new MessageQueueTransactionObject(); - txObject.ResourceHolder = - (MessageQueueResourceHolder) TransactionSynchronizationManager.GetResource(CURRENT_TRANSACTION_SLOTNAME); - return txObject; - } - - /// - /// Check if the given transaction object indicates an existing transaction - /// (that is, a transaction which has already started). - /// - /// MessageQueueTransactionObject object returned by - /// . - /// - /// True if there is an existing transaction. - /// - protected override bool IsExistingTransaction(object transaction) - { - MessageQueueTransactionObject txObject = (MessageQueueTransactionObject) transaction; - return (txObject.ResourceHolder != null); - } - - /// - /// Begin a new transaction with the given transaction definition. - /// - /// Transaction object returned by - /// . - /// instance, describing - /// propagation behavior, isolation level, timeout etc. - /// - /// In the case of creation or system errors. - /// - protected override void DoBegin(object transaction, ITransactionDefinition definition) - { - MessageQueueTransactionObject txObject = (MessageQueueTransactionObject) transaction; - - MessageQueueTransaction mqt = new MessageQueueTransaction(); - mqt.Begin(); - - txObject.ResourceHolder = new MessageQueueResourceHolder(mqt); - txObject.ResourceHolder.SynchronizedWithTransaction = true; - - int timeout = DetermineTimeout(definition); - if (timeout != DefaultTransactionDefinition.TIMEOUT_DEFAULT) + if (LOG.IsEnabled(LogLevel.Debug)) { - txObject.ResourceHolder.TimeoutInSeconds = timeout; - } - TransactionSynchronizationManager.BindResource(CURRENT_TRANSACTION_SLOTNAME, txObject.ResourceHolder); - } - - /// - /// Suspend the resources of the current transaction. - /// - /// Transaction object returned by - /// . - /// - /// An object that holds suspended resources (will be kept unexamined for passing it into - /// .) - /// - protected override object DoSuspend(object transaction) - { - MessageQueueTransactionObject txObject = (MessageQueueTransactionObject) transaction; - txObject.ResourceHolder = null; - return TransactionSynchronizationManager.UnbindResource(CURRENT_TRANSACTION_SLOTNAME); - } - - /// - /// Resume the resources of the current transaction. - /// - /// Transaction object returned by - /// . - /// The object that holds suspended resources as returned by - /// . - protected override void DoResume(object transaction, object suspendedResources) - { - MessageQueueResourceHolder queueHolder = (MessageQueueResourceHolder) suspendedResources; - TransactionSynchronizationManager.BindResource(CURRENT_TRANSACTION_SLOTNAME, queueHolder); - } - - /// - /// Perform an actual commit on the given transaction. - /// - /// The status representation of the transaction. - /// - ///

- /// An implementation does not need to check the rollback-only flag. - ///

- ///
- protected override void DoCommit(DefaultTransactionStatus status) - { - MessageQueueTransactionObject txObject = (MessageQueueTransactionObject) status.Transaction; - MessageQueueTransaction transaction = txObject.ResourceHolder.MessageQueueTransaction; - try - { - if (LOG.IsEnabled(LogLevel.Debug)) - { - LOG.LogDebug("Committing MessageQueueTransaction"); - } - transaction.Commit(); - } - catch (MessageQueueException ex) - { - throw new TransactionSystemException("Could not commit DefaultMessageQueue transaction", ex); - } - } - - /// - /// Perform an actual rollback on the given transaction, calls Transaction.Abort(). - /// - /// The status representation of the transaction. - /// - /// An implementation does not need to check the new transaction flag. - /// - protected override void DoRollback(DefaultTransactionStatus status) - { - MessageQueueTransactionObject txObject = (MessageQueueTransactionObject) status.Transaction; - MessageQueueTransaction transaction = txObject.ResourceHolder.MessageQueueTransaction; - try - { - if (LOG.IsEnabled(LogLevel.Debug)) - { - LOG.LogDebug("Committing MessageQueueTransaction"); - } - transaction.Abort(); - } - catch (MessageQueueException ex) - { - throw new TransactionSystemException("Could not roll back DefaultMessageQueue transaction", ex); - } - } - - /// - /// Set the given transaction rollback-only. Only called on rollback - /// if the current transaction takes part in an existing one. - /// - /// The status representation of the transaction. - /// Default implementation throws an IllegalTransactionStateException, - /// assuming that participating in existing transactions is generally not - /// supported. Subclasses are of course encouraged to provide such support. - /// - /// - /// In the case of system errors. - /// - protected override void DoSetRollbackOnly(DefaultTransactionStatus status) - { - MessageQueueTransactionObject txObject = (MessageQueueTransactionObject) status.Transaction; - txObject.ResourceHolder.RollbackOnly = true; - } - - /// - /// Cleanup resources after transaction completion. - /// - /// Transaction object returned by - /// . - /// - /// - /// Called after - /// and - /// - /// execution on any outcome. - /// - /// - protected override void DoCleanupAfterCompletion(object transaction) - { - MessageQueueTransactionObject txObject = (MessageQueueTransactionObject) transaction; - TransactionSynchronizationManager.UnbindResource(CURRENT_TRANSACTION_SLOTNAME); - txObject.ResourceHolder.Clear(); - } - - - private class MessageQueueTransactionObject : ISmartTransactionObject - { - private MessageQueueResourceHolder resourceHolder; - - - public MessageQueueResourceHolder ResourceHolder - { - get { return resourceHolder; } - set { resourceHolder = value; } + LOG.LogDebug("Committing MessageQueueTransaction"); } - #region ISmartTransactionObject Members - - public bool RollbackOnly - { - get { return resourceHolder.RollbackOnly; } - } - - #endregion + transaction.Commit(); + } + catch (MessageQueueException ex) + { + throw new TransactionSystemException("Could not commit DefaultMessageQueue transaction", ex); } } -} + + /// + /// Perform an actual rollback on the given transaction, calls Transaction.Abort(). + /// + /// The status representation of the transaction. + /// + /// An implementation does not need to check the new transaction flag. + /// + protected override void DoRollback(DefaultTransactionStatus status) + { + MessageQueueTransactionObject txObject = (MessageQueueTransactionObject) status.Transaction; + MessageQueueTransaction transaction = txObject.ResourceHolder.MessageQueueTransaction; + try + { + if (LOG.IsEnabled(LogLevel.Debug)) + { + LOG.LogDebug("Committing MessageQueueTransaction"); + } + + transaction.Abort(); + } + catch (MessageQueueException ex) + { + throw new TransactionSystemException("Could not roll back DefaultMessageQueue transaction", ex); + } + } + + /// + /// Set the given transaction rollback-only. Only called on rollback + /// if the current transaction takes part in an existing one. + /// + /// The status representation of the transaction. + /// Default implementation throws an IllegalTransactionStateException, + /// assuming that participating in existing transactions is generally not + /// supported. Subclasses are of course encouraged to provide such support. + /// + /// + /// In the case of system errors. + /// + protected override void DoSetRollbackOnly(DefaultTransactionStatus status) + { + MessageQueueTransactionObject txObject = (MessageQueueTransactionObject) status.Transaction; + txObject.ResourceHolder.RollbackOnly = true; + } + + /// + /// Cleanup resources after transaction completion. + /// + /// Transaction object returned by + /// . + /// + /// + /// Called after + /// and + /// + /// execution on any outcome. + /// + /// + protected override void DoCleanupAfterCompletion(object transaction) + { + MessageQueueTransactionObject txObject = (MessageQueueTransactionObject) transaction; + TransactionSynchronizationManager.UnbindResource(CURRENT_TRANSACTION_SLOTNAME); + txObject.ResourceHolder.Clear(); + } + + private class MessageQueueTransactionObject : ISmartTransactionObject + { + private MessageQueueResourceHolder resourceHolder; + + public MessageQueueResourceHolder ResourceHolder + { + get { return resourceHolder; } + set { resourceHolder = value; } + } + + #region ISmartTransactionObject Members + + public bool RollbackOnly + { + get { return resourceHolder.RollbackOnly; } + } + + #endregion + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Messaging/Messaging/Core/QueueUtils.cs b/src/Spring/Spring.Messaging/Messaging/Core/QueueUtils.cs index c4e300be..dd1c37c9 100644 --- a/src/Spring/Spring.Messaging/Messaging/Core/QueueUtils.cs +++ b/src/Spring/Spring.Messaging/Messaging/Core/QueueUtils.cs @@ -25,134 +25,131 @@ using Spring.Transaction.Support; #if NETSTANDARD using Experimental.System.Messaging; + #else using System.Messaging; #endif -namespace Spring.Messaging.Core +namespace Spring.Messaging.Core; + +/// +/// Utility methods to support Spring's MSMQ functionality +/// +public class QueueUtils { /// - /// Utility methods to support Spring's MSMQ functionality + /// Registers the default message converter with the application context. /// - public class QueueUtils + /// The application context. + /// The name of the message converter to use for lookups with + /// . + /// + public static string RegisterDefaultMessageConverter(IApplicationContext applicationContext) { - - /// - /// Registers the default message converter with the application context. - /// - /// The application context. - /// The name of the message converter to use for lookups with - /// . - /// - public static string RegisterDefaultMessageConverter(IApplicationContext applicationContext) + //Create a default message converter to use. + RootObjectDefinition rod = new RootObjectDefinition(typeof(XmlMessageConverter)); + rod.PropertyValues.Add("TargetTypes", new Type[] { typeof(String) }); + rod.IsSingleton = false; + IConfigurableApplicationContext ctx = (IConfigurableApplicationContext) applicationContext; + DefaultListableObjectFactory of = (DefaultListableObjectFactory) ctx.ObjectFactory; + string messageConverterObjectName = "__XmlMessageConverter__"; + if (!applicationContext.ContainsObjectDefinition(messageConverterObjectName)) { - //Create a default message converter to use. - RootObjectDefinition rod = new RootObjectDefinition(typeof(XmlMessageConverter)); - rod.PropertyValues.Add("TargetTypes", new Type[] { typeof(String) }); - rod.IsSingleton = false; - IConfigurableApplicationContext ctx = (IConfigurableApplicationContext)applicationContext; - DefaultListableObjectFactory of = (DefaultListableObjectFactory)ctx.ObjectFactory; - string messageConverterObjectName = "__XmlMessageConverter__"; - if (!applicationContext.ContainsObjectDefinition(messageConverterObjectName)) - { - of.RegisterObjectDefinition(messageConverterObjectName, rod); - } - return messageConverterObjectName; - - } - - /// - /// Gets the message queue transaction from thread local storage - /// - /// The resource factory. - /// null if not found in thread local storage - public static MessageQueueTransaction GetMessageQueueTransaction(IResourceFactory resourceFactory) - { - MessageQueueResourceHolder resourceHolder = - (MessageQueueResourceHolder) - TransactionSynchronizationManager.GetResource( - MessageQueueTransactionManager.CURRENT_TRANSACTION_SLOTNAME); - if (resourceHolder != null) - { - return resourceHolder.MessageQueueTransaction; - } - else - { - return null; - } + of.RegisterObjectDefinition(messageConverterObjectName, rod); } + return messageConverterObjectName; } - internal class MessageQueueResourceSynchronization : ITransactionSynchronization - { - private object resourceKey; - - private MessageQueueResourceHolder resourceHolder; - - private bool holderActive = true; - - public MessageQueueResourceSynchronization(MessageQueueResourceHolder resourceHolder, object resourceKey) - { - this.resourceHolder = resourceHolder; - this.resourceKey = resourceKey; - } - - #region ITransactionSynchronization Members - - public void Suspend() - { - if (holderActive) - { - TransactionSynchronizationManager.UnbindResource(resourceKey); - } - } - - public void Resume() - { - if (holderActive) - { - TransactionSynchronizationManager.BindResource(resourceKey, resourceHolder); - } - } - - public void BeforeCompletion() - { - TransactionSynchronizationManager.UnbindResource(resourceKey); - holderActive = false; - //this.resourceHolder.closeAll(); - //TODO SPRNET-1244 - } - - public void BeforeCommit(bool readOnly) - { - - } - - public void AfterCommit() - { - } - - public void AfterCompletion(TransactionSynchronizationStatus status) - { - //TODO SPRNET-1244 - } - - #endregion - } - - /// Callback interface for resource creation. - /// Serving as argument for the GetMessageQueueTransaction method. + /// + /// Gets the message queue transaction from thread local storage /// - public interface IResourceFactory + /// The resource factory. + /// null if not found in thread local storage + public static MessageQueueTransaction GetMessageQueueTransaction(IResourceFactory resourceFactory) { - /// - /// Return whether to allow for a local transaction that is synchronized with - /// a Spring-managed transaction (where the main transaction might be a ADO.NET-based - /// one for a specific IDbProvider, for example), with the MSMQ transaction - /// committing right after the main transaction. - /// Returns whether to allow for synchronizing a local MSMQ transaction - /// - bool SynchedLocalTransactionAllowed { get; } + MessageQueueResourceHolder resourceHolder = + (MessageQueueResourceHolder) + TransactionSynchronizationManager.GetResource( + MessageQueueTransactionManager.CURRENT_TRANSACTION_SLOTNAME); + if (resourceHolder != null) + { + return resourceHolder.MessageQueueTransaction; + } + else + { + return null; + } } } + +internal class MessageQueueResourceSynchronization : ITransactionSynchronization +{ + private object resourceKey; + + private MessageQueueResourceHolder resourceHolder; + + private bool holderActive = true; + + public MessageQueueResourceSynchronization(MessageQueueResourceHolder resourceHolder, object resourceKey) + { + this.resourceHolder = resourceHolder; + this.resourceKey = resourceKey; + } + + #region ITransactionSynchronization Members + + public void Suspend() + { + if (holderActive) + { + TransactionSynchronizationManager.UnbindResource(resourceKey); + } + } + + public void Resume() + { + if (holderActive) + { + TransactionSynchronizationManager.BindResource(resourceKey, resourceHolder); + } + } + + public void BeforeCompletion() + { + TransactionSynchronizationManager.UnbindResource(resourceKey); + holderActive = false; + //this.resourceHolder.closeAll(); + //TODO SPRNET-1244 + } + + public void BeforeCommit(bool readOnly) + { + } + + public void AfterCommit() + { + } + + public void AfterCompletion(TransactionSynchronizationStatus status) + { + //TODO SPRNET-1244 + } + + #endregion +} + +/// Callback interface for resource creation. +/// Serving as argument for the GetMessageQueueTransaction method. +/// +public interface IResourceFactory +{ + /// + /// Return whether to allow for a local transaction that is synchronized with + /// a Spring-managed transaction (where the main transaction might be a ADO.NET-based + /// one for a specific IDbProvider, for example), with the MSMQ transaction + /// committing right after the main transaction. + /// Returns whether to allow for synchronizing a local MSMQ transaction + /// + bool SynchedLocalTransactionAllowed { get; } +} diff --git a/src/Spring/Spring.Messaging/Messaging/Listener/AbstractListenerContainer.cs b/src/Spring/Spring.Messaging/Messaging/Listener/AbstractListenerContainer.cs index c78ca491..465665b2 100644 --- a/src/Spring/Spring.Messaging/Messaging/Listener/AbstractListenerContainer.cs +++ b/src/Spring/Spring.Messaging/Messaging/Listener/AbstractListenerContainer.cs @@ -21,244 +21,243 @@ using Microsoft.Extensions.Logging; using Spring.Objects.Factory; -namespace Spring.Messaging.Listener +namespace Spring.Messaging.Listener; + +/// +/// Provides basic lifecyle management methods for implementing a message listener container. +/// +/// +/// This base class does not assume any specific listener programming model +/// or listener invoker mechanism. It just provides the general runtime +/// lifecycle management needed for any kind of message-based listening mechanism. +/// +/// For a concrete listener programming model, check out the +/// subclass. For a concrete listener +/// invoker mechanism, check out the , +/// , or +/// classes. +/// +/// +/// Mark Pollack +public abstract class AbstractListenerContainer : IInitializingObject, IObjectNameAware, IDisposable { + #region Logging Definition + + private static readonly ILogger LOG = LogManager.GetLogger(typeof(AbstractListenerContainer)); + + #endregion + + private bool autoStartup = true; + + private string objectName; + private bool active; + private bool running; + private object lifecycleMonitor = new object(); + + #region Properties + /// - /// Provides basic lifecyle management methods for implementing a message listener container. + /// Sets a value indicating whether to automatically start the container after initialization. + /// Default is "true"; set this to "false" to allow for manual startup though the + /// method. /// - /// - /// This base class does not assume any specific listener programming model - /// or listener invoker mechanism. It just provides the general runtime - /// lifecycle management needed for any kind of message-based listening mechanism. - /// - /// For a concrete listener programming model, check out the - /// subclass. For a concrete listener - /// invoker mechanism, check out the , - /// , or - /// classes. - /// - /// - /// Mark Pollack - public abstract class AbstractListenerContainer : IInitializingObject, IObjectNameAware, IDisposable + /// true if autostartup; otherwise, false. + public bool AutoStartup { - #region Logging Definition + set { autoStartup = value; } + } - private static readonly ILogger LOG = LogManager.GetLogger(typeof (AbstractListenerContainer)); - - #endregion - - private bool autoStartup = true; - - private string objectName; - private bool active; - private bool running; - private object lifecycleMonitor = new object(); - - #region Properties - - /// - /// Sets a value indicating whether to automatically start the container after initialization. - /// Default is "true"; set this to "false" to allow for manual startup though the - /// method. - /// - /// true if autostartup; otherwise, false. - public bool AutoStartup - { - set { autoStartup = value; } - } - - /// - /// Gets a value indicating whether this Container is active, - /// that is, whether it has been set up but not shut down yet. - /// - /// true if active; otherwise, false. - public bool Active - { - get - { - lock (lifecycleMonitor) - { - return active; - } - } - } - - - /// - /// Gets a value indicating whether this Container is running, - /// that is whether it has been started and not stopped yet. - /// - /// true if running; otherwise, false. - public bool Running - { - get - { - lock (lifecycleMonitor) - { - return (running && RunningAllowed()); - } - } - } - - #region IObjectNameAware Members - - /// - /// Return the object name that this listener container has been assigned - /// in its containing object factory, if any. - /// - public string ObjectName - { - set { objectName = value; } - get { return objectName; } - } - - #endregion - - #endregion - - #region IInitializingObject Members - - /// - /// Delegates to and - /// - public void AfterPropertiesSet() - { - ValidateConfiguration(); - Initialize(); - } - - #endregion - - #region IDisposable Members - - /// - /// Calls when the application context destroys the container instance. - /// - public void Dispose() - { - Shutdown(); - } - - #endregion - - /// - /// Validates the configuration of this container - /// The default implementation is empty. To be overridden in subclasses. - /// - protected virtual void ValidateConfiguration() - { - } - - /// - /// Initializes this container. Calls the abstract method to - /// initialize the listening infrastructure (i.e. subclasses will typically - /// resolve a MessageQueue instance from a MessageQueueObjectName) and then calls - /// the abstract method DoStart if the property is set to true, - /// - public virtual void Initialize() + /// + /// Gets a value indicating whether this Container is active, + /// that is, whether it has been set up but not shut down yet. + /// + /// true if active; otherwise, false. + public bool Active + { + get { lock (lifecycleMonitor) { - active = true; - Monitor.PulseAll(lifecycleMonitor); + return active; } - DoInitialize(); - if (autoStartup) - { - DoStart(); - } - } + } - /// - /// Sets the container state to inactive and not running, calls template method - /// - /// - public virtual void Shutdown() + /// + /// Gets a value indicating whether this Container is running, + /// that is whether it has been started and not stopped yet. + /// + /// true if running; otherwise, false. + public bool Running + { + get { - LOG.LogDebug("Shutting down MessageListenerContainer"); lock (lifecycleMonitor) { - running = false; - active = false; - Monitor.PulseAll(lifecycleMonitor); + return (running && RunningAllowed()); } - DoShutdown(); + } + } + + #region IObjectNameAware Members + + /// + /// Return the object name that this listener container has been assigned + /// in its containing object factory, if any. + /// + public string ObjectName + { + set { objectName = value; } + get { return objectName; } + } + + #endregion + + #endregion + + #region IInitializingObject Members + + /// + /// Delegates to and + /// + public void AfterPropertiesSet() + { + ValidateConfiguration(); + Initialize(); + } + + #endregion + + #region IDisposable Members + + /// + /// Calls when the application context destroys the container instance. + /// + public void Dispose() + { + Shutdown(); + } + + #endregion + + /// + /// Validates the configuration of this container + /// The default implementation is empty. To be overridden in subclasses. + /// + protected virtual void ValidateConfiguration() + { + } + + /// + /// Initializes this container. Calls the abstract method to + /// initialize the listening infrastructure (i.e. subclasses will typically + /// resolve a MessageQueue instance from a MessageQueueObjectName) and then calls + /// the abstract method DoStart if the property is set to true, + /// + public virtual void Initialize() + { + lock (lifecycleMonitor) + { + active = true; + Monitor.PulseAll(lifecycleMonitor); } - /// - /// Starts this container. - /// - public virtual void Start() + DoInitialize(); + if (autoStartup) { DoStart(); } - - /// - /// Sets the state to running, can be overridden in subclasses. - /// - protected virtual void DoStart() - { - lock (lifecycleMonitor) - { - running = true; - Monitor.PulseAll(lifecycleMonitor); - } - } - - /// - /// Stops this instance. - /// - public virtual void Stop() - { - DoStop(); - } - - /// - /// Template method suitable for overriding that stops the container. - /// - protected virtual void DoStop() - { - lock (lifecycleMonitor) - { - running = false; - Monitor.PulseAll(lifecycleMonitor); - } - } - - /// - /// Check whether this container's listeners are generally allowed to run. - /// - /// - /// This implementation always returns true; the default 'running' - /// state is purely determined by and - /// - /// Subclasses may override this method to check against temporary - /// conditions that prevent listeners from actually running. In other words, - /// they may apply further restrictions to the 'running' state, returning - /// false if such a restriction prevents listeners from running. - /// - /// - /// false if such a restriction prevents listeners from running. - protected virtual bool RunningAllowed() - { - return true; - } - - #region Abstract Methods - - /// - /// Subclasses need to implement this method for their specific - /// listener management process. - /// - protected abstract void DoInitialize(); - - /// - /// Subclasses need to implement this method for their specific - /// listener management process. - /// - protected abstract void DoShutdown(); - - #endregion } + + /// + /// Sets the container state to inactive and not running, calls template method + /// + /// + public virtual void Shutdown() + { + LOG.LogDebug("Shutting down MessageListenerContainer"); + lock (lifecycleMonitor) + { + running = false; + active = false; + Monitor.PulseAll(lifecycleMonitor); + } + + DoShutdown(); + } + + /// + /// Starts this container. + /// + public virtual void Start() + { + DoStart(); + } + + /// + /// Sets the state to running, can be overridden in subclasses. + /// + protected virtual void DoStart() + { + lock (lifecycleMonitor) + { + running = true; + Monitor.PulseAll(lifecycleMonitor); + } + } + + /// + /// Stops this instance. + /// + public virtual void Stop() + { + DoStop(); + } + + /// + /// Template method suitable for overriding that stops the container. + /// + protected virtual void DoStop() + { + lock (lifecycleMonitor) + { + running = false; + Monitor.PulseAll(lifecycleMonitor); + } + } + + /// + /// Check whether this container's listeners are generally allowed to run. + /// + /// + /// This implementation always returns true; the default 'running' + /// state is purely determined by and + /// + /// Subclasses may override this method to check against temporary + /// conditions that prevent listeners from actually running. In other words, + /// they may apply further restrictions to the 'running' state, returning + /// false if such a restriction prevents listeners from running. + /// + /// + /// false if such a restriction prevents listeners from running. + protected virtual bool RunningAllowed() + { + return true; + } + + #region Abstract Methods + + /// + /// Subclasses need to implement this method for their specific + /// listener management process. + /// + protected abstract void DoInitialize(); + + /// + /// Subclasses need to implement this method for their specific + /// listener management process. + /// + protected abstract void DoShutdown(); + + #endregion } diff --git a/src/Spring/Spring.Messaging/Messaging/Listener/AbstractMessageListenerContainer.cs b/src/Spring/Spring.Messaging/Messaging/Listener/AbstractMessageListenerContainer.cs index 5aca4769..ea4f1cf0 100644 --- a/src/Spring/Spring.Messaging/Messaging/Listener/AbstractMessageListenerContainer.cs +++ b/src/Spring/Spring.Messaging/Messaging/Listener/AbstractMessageListenerContainer.cs @@ -26,224 +26,224 @@ using Spring.Util; #if NETSTANDARD using Experimental.System.Messaging; + #else using System.Messaging; #endif -namespace Spring.Messaging.Listener +namespace Spring.Messaging.Listener; + +/// +/// Defines a minimal programming model for message listener containers. They are expected to +/// invoke a upon asynchronous receives of a MSMQ message. Access to +/// obtain MessageQueue and instances is available through the +/// property, the default implementation +/// provides per-thread instances of these classes. +/// +/// Mark Pollack +public abstract class AbstractMessageListenerContainer : AbstractListenerContainer, IApplicationContextAware { + #region Logging Definition + + private static readonly ILogger LOG = LogManager.GetLogger(typeof(AbstractMessageListenerContainer)); + + #endregion + + #region Fields + + private string messageQueueObjectName; + + private IMessageQueueFactory messageQueueFactory; + private IApplicationContext applicationContext; + /// - /// Defines a minimal programming model for message listener containers. They are expected to - /// invoke a upon asynchronous receives of a MSMQ message. Access to - /// obtain MessageQueue and instances is available through the - /// property, the default implementation - /// provides per-thread instances of these classes. + /// Most operations within the MessageListener container hierarchy use methods on the + /// MessageQueue instance which are thread safe (BeginPeek, BeginReceive, + /// EndPeek, EndReceive, GetAllMessages, Peek, and Receive). When using another + /// method on the shared MessageQueue instance, wrap calls with a lock on this object. /// - /// Mark Pollack - public abstract class AbstractMessageListenerContainer : AbstractListenerContainer, IApplicationContextAware + protected object messageQueueMonitor = new object(); + + private IMessageListener messageListener; + + private TimeSpan recoveryTimeSpan = new TimeSpan(0, 0, 0, 1, 0); + + #endregion + + #region Properties + + /// + /// Gets or sets the message queue factory. + /// + /// The message queue factory. + public IMessageQueueFactory MessageQueueFactory { - #region Logging Definition - - private static readonly ILogger LOG = LogManager.GetLogger(typeof (AbstractMessageListenerContainer)); - - #endregion - - #region Fields - - private string messageQueueObjectName; - - private IMessageQueueFactory messageQueueFactory; - private IApplicationContext applicationContext; - - /// - /// Most operations within the MessageListener container hierarchy use methods on the - /// MessageQueue instance which are thread safe (BeginPeek, BeginReceive, - /// EndPeek, EndReceive, GetAllMessages, Peek, and Receive). When using another - /// method on the shared MessageQueue instance, wrap calls with a lock on this object. - /// - protected object messageQueueMonitor = new object(); - - private IMessageListener messageListener; - - private TimeSpan recoveryTimeSpan = new TimeSpan(0, 0, 0, 1, 0); - - #endregion - - #region Properties - - /// - /// Gets or sets the message queue factory. - /// - /// The message queue factory. - public IMessageQueueFactory MessageQueueFactory - { - get { return messageQueueFactory; } - set { messageQueueFactory = value; } - } - - /// - /// Gets or sets the name of the message queue object, as refered to in the - /// Spring configuration, that will be used to create a DefaultMessageQueue instance - /// for consuming messages in the container. - /// - /// The name of the message queue object. - public string MessageQueueObjectName - { - get { return messageQueueObjectName; } - set - { - AssertUtils.ArgumentNotNull(value, "MessageQueueObjectName"); - messageQueueObjectName = value; - } - } - - /// - /// Gets or sets the message listener. - /// - /// The message listener. - public IMessageListener MessageListener - { - get { return messageListener; } - set - { - AssertUtils.ArgumentNotNull(value, "MessageListener"); - messageListener = value; - } - } - - /// - /// Gets or sets the recovery time span, how long to sleep after an exception in processing occured - /// to avoid excessive redelivery attempts. Default value is 1 second. - /// - /// The recovery time span. - public TimeSpan RecoveryTimeSpan - { - get { return recoveryTimeSpan; } - set { recoveryTimeSpan = value; } - } - - #endregion - - #region IApplicationContextAware Members - - /// - /// Gets or sets the that this - /// object runs in. - /// - /// - ///

- /// Normally this call will be used to initialize the object. - ///

- ///

- /// Invoked after population of normal object properties but before an - /// init callback such as - /// 's - /// - /// or a custom init-method. Invoked after the setting of any - /// 's - /// - /// property. - ///

- ///
- /// - /// In the case of application context initialization errors. - /// - /// - /// If thrown by any application context methods. - /// - /// - public IApplicationContext ApplicationContext - { - get { return applicationContext; } - set { applicationContext = value; } - } - - #endregion - - #region Protected Methods - - /// - /// Validates that the is not null. If - /// is null, a is created. Can be be overridden in subclasses. - /// - protected override void ValidateConfiguration() - { - if (MessageQueueObjectName == null) - { - throw new ArgumentException("Property 'MessageQueueObjectName' is required"); - } - if (MessageQueueFactory == null) - { - DefaultMessageQueueFactory qf = new DefaultMessageQueueFactory(); - qf.ApplicationContext = applicationContext; - MessageQueueFactory = qf; - } - } - - - /// - /// Template method that execute listener with the provided message if - /// is true. Subclasses will call - /// this method at the appropriate point in their processing lifecycle, for example - /// committing or rolling back a transaction if needed. - /// - /// Calls the template method - /// The message. - protected virtual void DoExecuteListener(Message message) - { - if (!Running) - { - if (LOG.IsEnabled(LogLevel.Warning)) - { - LOG.LogWarning("Not processing recieved message because of the listener container " + - "having been stopped in the meantime: " + message); - } - } - - InvokeListener(message); - } - - /// - /// Invokes the listener if it is not null. Invokes the method . - /// Can be overridden in subclasses. - /// - /// The message. - protected virtual void InvokeListener(Message message) - { - if (MessageListener != null) - { - DoInvokeListener(MessageListener, message); - } - else - { - throw new InvalidOperationException("No message listener specified - see property 'MessageListener'"); - } - } - - /// - /// Invokes the listener. Can be overriden in subclasses. - /// - /// The listener. - /// The message. - protected virtual void DoInvokeListener(IMessageListener listener, Message message) - { - listener.OnMessage(message); - } - - /// - /// Closes the queue handle. Cancel pending receive operation by closing the queue handle - /// To properly dispose of the queue handle, ensure that EnableConnectionCache=false on the - /// MessageQueue that this listener is configured to use. - /// - protected void CloseQueueHandle(MessageQueue mq) - { - lock (messageQueueMonitor) - { - mq.Close(); - mq.Dispose(); - } - } - - #endregion + get { return messageQueueFactory; } + set { messageQueueFactory = value; } } -} + + /// + /// Gets or sets the name of the message queue object, as refered to in the + /// Spring configuration, that will be used to create a DefaultMessageQueue instance + /// for consuming messages in the container. + /// + /// The name of the message queue object. + public string MessageQueueObjectName + { + get { return messageQueueObjectName; } + set + { + AssertUtils.ArgumentNotNull(value, "MessageQueueObjectName"); + messageQueueObjectName = value; + } + } + + /// + /// Gets or sets the message listener. + /// + /// The message listener. + public IMessageListener MessageListener + { + get { return messageListener; } + set + { + AssertUtils.ArgumentNotNull(value, "MessageListener"); + messageListener = value; + } + } + + /// + /// Gets or sets the recovery time span, how long to sleep after an exception in processing occured + /// to avoid excessive redelivery attempts. Default value is 1 second. + /// + /// The recovery time span. + public TimeSpan RecoveryTimeSpan + { + get { return recoveryTimeSpan; } + set { recoveryTimeSpan = value; } + } + + #endregion + + #region IApplicationContextAware Members + + /// + /// Gets or sets the that this + /// object runs in. + /// + /// + ///

+ /// Normally this call will be used to initialize the object. + ///

+ ///

+ /// Invoked after population of normal object properties but before an + /// init callback such as + /// 's + /// + /// or a custom init-method. Invoked after the setting of any + /// 's + /// + /// property. + ///

+ ///
+ /// + /// In the case of application context initialization errors. + /// + /// + /// If thrown by any application context methods. + /// + /// + public IApplicationContext ApplicationContext + { + get { return applicationContext; } + set { applicationContext = value; } + } + + #endregion + + #region Protected Methods + + /// + /// Validates that the is not null. If + /// is null, a is created. Can be be overridden in subclasses. + /// + protected override void ValidateConfiguration() + { + if (MessageQueueObjectName == null) + { + throw new ArgumentException("Property 'MessageQueueObjectName' is required"); + } + + if (MessageQueueFactory == null) + { + DefaultMessageQueueFactory qf = new DefaultMessageQueueFactory(); + qf.ApplicationContext = applicationContext; + MessageQueueFactory = qf; + } + } + + /// + /// Template method that execute listener with the provided message if + /// is true. Subclasses will call + /// this method at the appropriate point in their processing lifecycle, for example + /// committing or rolling back a transaction if needed. + /// + /// Calls the template method + /// The message. + protected virtual void DoExecuteListener(Message message) + { + if (!Running) + { + if (LOG.IsEnabled(LogLevel.Warning)) + { + LOG.LogWarning("Not processing recieved message because of the listener container " + + "having been stopped in the meantime: " + message); + } + } + + InvokeListener(message); + } + + /// + /// Invokes the listener if it is not null. Invokes the method . + /// Can be overridden in subclasses. + /// + /// The message. + protected virtual void InvokeListener(Message message) + { + if (MessageListener != null) + { + DoInvokeListener(MessageListener, message); + } + else + { + throw new InvalidOperationException("No message listener specified - see property 'MessageListener'"); + } + } + + /// + /// Invokes the listener. Can be overriden in subclasses. + /// + /// The listener. + /// The message. + protected virtual void DoInvokeListener(IMessageListener listener, Message message) + { + listener.OnMessage(message); + } + + /// + /// Closes the queue handle. Cancel pending receive operation by closing the queue handle + /// To properly dispose of the queue handle, ensure that EnableConnectionCache=false on the + /// MessageQueue that this listener is configured to use. + /// + protected void CloseQueueHandle(MessageQueue mq) + { + lock (messageQueueMonitor) + { + mq.Close(); + mq.Dispose(); + } + } + + #endregion +} \ No newline at end of file diff --git a/src/Spring/Spring.Messaging/Messaging/Listener/AbstractPeekingMessageListenerContainer.cs b/src/Spring/Spring.Messaging/Messaging/Listener/AbstractPeekingMessageListenerContainer.cs index dddb607f..6df7e433 100644 --- a/src/Spring/Spring.Messaging/Messaging/Listener/AbstractPeekingMessageListenerContainer.cs +++ b/src/Spring/Spring.Messaging/Messaging/Listener/AbstractPeekingMessageListenerContainer.cs @@ -18,7 +18,6 @@ #endregion - #if NETSTANDARD using Experimental.System.Messaging; #else @@ -26,433 +25,431 @@ using System.Messaging; #endif using Microsoft.Extensions.Logging; -namespace Spring.Messaging.Listener +namespace Spring.Messaging.Listener; + +/// +/// Base class for listener container implementations which are based on Peeking for messages on +/// a MessageQueue. Peeking is the only resource efficient approach that can be used in +/// order to have MessageQueue receipt in conjunction with transactions, either local MSMQ transactions, +/// local ADO.NET based transactions, or DTC transactions. See SimpleMessageListenerContainer for +/// an implementation based on a synchronous receives and you do not require transactional support. +/// +/// +/// The number of threads that will be created for processing messages after the Peek occurs +/// is set via the property MaxConcurrentListeners. Each processing thread will continue to listen +/// for messages up until the the timeout value specified by ListenerTimeLimit or until +/// there are no more messages on the queue (which ver comes first). +/// +/// The default value of +/// ListenerTimeLimit is TimeSpan.Zero, meaning that only one attempt to recieve a message from the +/// queue will be performed by each listener thread. +/// +/// +/// The current implementation uses the standard .NET thread pool. Future implementations will +/// use a custom (and pluggable) thread pool. +/// +/// +public abstract class AbstractPeekingMessageListenerContainer : AbstractMessageListenerContainer { + #region Logging Definition + + private static readonly ILogger LOG = LogManager.GetLogger(typeof(AbstractPeekingMessageListenerContainer)); + + #endregion + + #region Fields + + private Thread dispatcherThread; + + private ManualResetEvent stopEvent = new ManualResetEvent(false); + + private MessageQueue messageQueue; + + private int maxConcurrentListeners = 1; + private bool setMaxConcurrentListenersCalled = false; + + private int activeListenerCount; + private int scheduledListenerCount; + private object activeListenerMonitor = new object(); + + private TimeSpan listenerTimeLimit = TimeSpan.Zero; + + #endregion + + #region Properties + /// - /// Base class for listener container implementations which are based on Peeking for messages on - /// a MessageQueue. Peeking is the only resource efficient approach that can be used in - /// order to have MessageQueue receipt in conjunction with transactions, either local MSMQ transactions, - /// local ADO.NET based transactions, or DTC transactions. See SimpleMessageListenerContainer for - /// an implementation based on a synchronous receives and you do not require transactional support. + /// Gets or sets the listener time limit to continuously receive messages. + /// The value is specified in milliseconds. The default value is TimeSpan.Zero, + /// indicating to only perform one Receive operation per Peek trigger. /// - /// - /// The number of threads that will be created for processing messages after the Peek occurs - /// is set via the property MaxConcurrentListeners. Each processing thread will continue to listen - /// for messages up until the the timeout value specified by ListenerTimeLimit or until - /// there are no more messages on the queue (which ver comes first). - /// - /// The default value of - /// ListenerTimeLimit is TimeSpan.Zero, meaning that only one attempt to recieve a message from the - /// queue will be performed by each listener thread. - /// - /// - /// The current implementation uses the standard .NET thread pool. Future implementations will - /// use a custom (and pluggable) thread pool. - /// - /// - public abstract class AbstractPeekingMessageListenerContainer : AbstractMessageListenerContainer + /// The listener time limit in millis. + public TimeSpan ListenerTimeLimit { - #region Logging Definition + get { return listenerTimeLimit; } + set { listenerTimeLimit = value; } + } - private static readonly ILogger LOG = LogManager.GetLogger(typeof (AbstractPeekingMessageListenerContainer)); - - #endregion - - #region Fields - - private Thread dispatcherThread; - - private ManualResetEvent stopEvent = new ManualResetEvent(false); - - private MessageQueue messageQueue; - - private int maxConcurrentListeners = 1; - private bool setMaxConcurrentListenersCalled = false; - - private int activeListenerCount; - private int scheduledListenerCount; - private object activeListenerMonitor = new object(); - - private TimeSpan listenerTimeLimit = TimeSpan.Zero; - - #endregion - - #region Properties - - /// - /// Gets or sets the listener time limit to continuously receive messages. - /// The value is specified in milliseconds. The default value is TimeSpan.Zero, - /// indicating to only perform one Receive operation per Peek trigger. - /// - /// The listener time limit in millis. - public TimeSpan ListenerTimeLimit + /// + /// Gets or sets the max concurrent listeners to receive messages. + /// + /// The max concurrent listeners. + public int MaxConcurrentListeners + { + get { return maxConcurrentListeners; } + set { - get { return listenerTimeLimit; } - set { listenerTimeLimit = value; } - } - - /// - /// Gets or sets the max concurrent listeners to receive messages. - /// - /// The max concurrent listeners. - public int MaxConcurrentListeners - { - get { return maxConcurrentListeners; } - set + if (!setMaxConcurrentListenersCalled) { - if (!setMaxConcurrentListenersCalled) + setMaxConcurrentListenersCalled = true; + maxConcurrentListeners = value; + } + else + { + LOG.LogInformation("Ignoring resetting of MaxConcurrentListeners. Using previous value of " + + maxConcurrentListeners); + } + } + } + + /// + /// Gets or sets the message queue used for Peeking. + /// + /// The message queue. + public MessageQueue MessageQueue + { + get { return messageQueue; } + } + + #endregion + + #region Protected Container Lifecycle Methods + + /// + /// Retrieves a MessageQueue instance given the MessageQueueObjectName + /// + protected override void DoInitialize() + { + messageQueue = MessageQueueFactory.CreateMessageQueue(MessageQueueObjectName); + //TODO would initialize resources for a seperate thread pool here. + } + + /// + /// Wait for all listener threads to exit and closes the DefaultMessageQueue. + /// + protected override void DoShutdown() + { + stopEvent.Set(); + WaitForListenerThreadsToExit(); + CloseQueueHandle(MessageQueue); + if (dispatcherThread != null) + { + LOG.LogDebug("Waiting to join dispatcher thread."); + dispatcherThread.Join(); + dispatcherThread = null; + LOG.LogDebug("Dispatcher thread terminated."); + } + } + + /// + /// Starts peeking on the DefaultMessageQueue. + /// + protected override void DoStart() + { + base.DoStart(); + stopEvent = new ManualResetEvent(false); + dispatcherThread = new Thread(new ThreadStart(StartPeeking)); + ConfigureInitialPeekThread(dispatcherThread); + dispatcherThread.Start(); + } + + /// + /// Stops peeking on the message queue. + /// + protected override void DoStop() + { + base.DoStop(); + stopEvent.Set(); + CloseQueueHandle(MessageQueue); + if (dispatcherThread != null) + { + LOG.LogDebug("Waiting to join dispatcher thread."); + dispatcherThread.Join(); + dispatcherThread = null; + LOG.LogDebug("Dispatcher thread terminated."); + } + } + + #endregion + + #region Protected Methods + + /// + /// Starts peeking on the DefaultMessageQueue. This is the method that must be called + /// again at the end of message procesing to continue the peeking process. + /// + protected virtual void StartPeeking() + { + if (Running) + { + try + { + IAsyncResult asynchResult = MessageQueue.BeginPeek(); + LOG.LogDebug("Waiting on Peek AsyncWaitHandle"); + int firedWaitHandle = WaitHandle.WaitAny(new WaitHandle[] { asynchResult.AsyncWaitHandle, stopEvent }); + if (firedWaitHandle == 0) { - setMaxConcurrentListenersCalled = true; - maxConcurrentListeners = value; + PeekCompleted(asynchResult); } else { - LOG.LogInformation("Ignoring resetting of MaxConcurrentListeners. Using previous value of " + - maxConcurrentListeners); - } - } - } - - /// - /// Gets or sets the message queue used for Peeking. - /// - /// The message queue. - public MessageQueue MessageQueue - { - get { return messageQueue; } - } - - #endregion - - #region Protected Container Lifecycle Methods - - /// - /// Retrieves a MessageQueue instance given the MessageQueueObjectName - /// - protected override void DoInitialize() - { - messageQueue = MessageQueueFactory.CreateMessageQueue(MessageQueueObjectName); - //TODO would initialize resources for a seperate thread pool here. - } - - /// - /// Wait for all listener threads to exit and closes the DefaultMessageQueue. - /// - protected override void DoShutdown() - { - stopEvent.Set(); - WaitForListenerThreadsToExit(); - CloseQueueHandle(MessageQueue); - if (dispatcherThread != null) - { - LOG.LogDebug("Waiting to join dispatcher thread."); - dispatcherThread.Join(); - dispatcherThread = null; - LOG.LogDebug("Dispatcher thread terminated."); - } - } - - /// - /// Starts peeking on the DefaultMessageQueue. - /// - protected override void DoStart() - { - base.DoStart(); - stopEvent = new ManualResetEvent(false); - dispatcherThread = new Thread(new ThreadStart(StartPeeking)); - ConfigureInitialPeekThread(dispatcherThread); - dispatcherThread.Start(); - } - - /// - /// Stops peeking on the message queue. - /// - protected override void DoStop() - { - base.DoStop(); - stopEvent.Set(); - CloseQueueHandle(MessageQueue); - if (dispatcherThread != null) - { - LOG.LogDebug("Waiting to join dispatcher thread."); - dispatcherThread.Join(); - dispatcherThread = null; - LOG.LogDebug("Dispatcher thread terminated."); - } - } - - #endregion - - #region Protected Methods - - /// - /// Starts peeking on the DefaultMessageQueue. This is the method that must be called - /// again at the end of message procesing to continue the peeking process. - /// - protected virtual void StartPeeking() - { - if (Running) - { - try - { - IAsyncResult asynchResult = MessageQueue.BeginPeek(); - LOG.LogDebug("Waiting on Peek AsyncWaitHandle"); - int firedWaitHandle = WaitHandle.WaitAny(new WaitHandle[] {asynchResult.AsyncWaitHandle, stopEvent}); - if (firedWaitHandle == 0) - { - PeekCompleted(asynchResult); - } - else - { - //Stopping processing. - return; - } - } - catch (Exception ex) - { - string message = "Exception executing DefaultMessageQueue.BeginPeek. Reinvoking after recovery interval [" + - RecoveryTimeSpan + "]"; - LOG.LogError(ex, message); - Thread.Sleep(RecoveryTimeSpan); - StartPeeking(); - } - } - } - - /// - /// The callback when the peek has completed. Schedule up to the maximum number of - /// concurrent listeners to receive messages off the queue. Delegates to the abstract - /// method DoReceiveAndExecute so that subclasses may customize the receiving process, - /// for example to surround the receive operation with transactional semantics. - /// - /// The async result. - protected virtual void PeekCompleted(IAsyncResult asyncResult) - { - bool listenerThreadWillCallStartPeek = false; - try - { - LOG.LogDebug("Peek Completed called."); - - MessageQueue.EndPeek(asyncResult); - - int numberOfListenersToSchedule = 0; - - // lock also prevents listeners that are about to exit from invoking - // StartPeeking while new listeners are being scheduled. - lock (activeListenerMonitor) - { - numberOfListenersToSchedule = maxConcurrentListeners - - (activeListenerCount + scheduledListenerCount); - - LOG.LogDebug("Submitting " + numberOfListenersToSchedule + " listener work items"); - - #region Submit to thread pool up to max number of concurrent listeners - - for (int i = 1; i <= numberOfListenersToSchedule; i++) - { - bool wasQueued = ThreadPool.QueueUserWorkItem(new WaitCallback(ReceiveAndExecute), MessageQueue); - if (wasQueued) - { - scheduledListenerCount++; - listenerThreadWillCallStartPeek = true; - LOG.LogDebug("Queued ReceiveAndExecute listener # " + i); - } - else - { - LOG.LogError("Could not submit ReceiveAndExecute work item for listener # " + i); - } - } - Monitor.PulseAll(activeListenerMonitor); - } - - #endregion - } - catch (MessageQueueException mex) - { - switch ((int) mex.MessageQueueErrorCode) - { - case -1073741536: // = 0xc0000120 "STATUS_CANCELLED". - LOG.LogInformation("Asynchronous Peek Thread sent STATUS_CANCELLED."); - break; - default: - LOG.LogError(mex, "MessageQueueException Peeking Message"); - break; - } - } - catch (Exception e) - { - LOG.LogError(e, "Exception Peeking Message"); - } - finally - { - if (listenerThreadWillCallStartPeek == false && Running) - { - LOG.LogWarning("Could not queue any listeners onto the thread pool. Calling BeginPeek again after delay of " + - RecoveryTimeSpan); - Thread.Sleep(RecoveryTimeSpan); - StartPeeking(); - } - } - } - - /// - /// Execute the listener for a message received from the given queue - /// wrapping the entire operation in an external transaction if demanded. - /// - /// The DefaultMessageQueue upon which the call to receive should be - /// called. - protected virtual void ReceiveAndExecute(object state) - { - bool messageReceived = true; - bool listenerTimeOut = false; - - MessageQueue mq = state as MessageQueue; - if (mq == null) - { - throw new ArgumentException("Expected asynchronous state object to be of the type DefaultMessageQueue"); - } - - try - { - LOG.LogDebug("Executing ReceiveAndExecute"); - - #region Increment Active Listener Count - - lock (activeListenerMonitor) - { - activeListenerCount++; - scheduledListenerCount--; - LOG.LogDebug("ActiveListenerCount = " + activeListenerCount); - LOG.LogDebug("ScheduledListenerCount = " + scheduledListenerCount); - Monitor.PulseAll(activeListenerMonitor); - } - - #endregion - - DateTime expirationTime = DateTime.Now.Add(ListenerTimeLimit); - while (!listenerTimeOut && messageReceived) - { - //Subclasses to perform receive operation - messageReceived = DoReceiveAndExecute(mq); - - if (ListenerTimeLimit == TimeSpan.Zero) - { - listenerTimeOut = true; - LOG.LogTrace("No listener timelimit specified, exiting recieve loop after one iteration."); - } - else if (DateTime.Now >= expirationTime) - { - listenerTimeOut = true; - LOG.LogTrace("Listener timeout, exiting receive loop."); - } - else - { - LOG.LogTrace("Continuing receive loop."); - } + //Stopping processing. + return; } } catch (Exception ex) { - messageReceived = false; - string message = "Error receiving message from DefaultMessageQueue = [" + mq.Path + "]"; + string message = "Exception executing DefaultMessageQueue.BeginPeek. Reinvoking after recovery interval [" + + RecoveryTimeSpan + "]"; LOG.LogError(ex, message); - } - finally - { - LOG.LogDebug("Exiting ReceiveAndExecute"); - - #region Decrementing Listener Count and call StartPeeking if last listener or there are still messages to process - - lock (activeListenerMonitor) - { - activeListenerCount--; - LOG.LogDebug("ActiveListenerCount = " + activeListenerCount); - LOG.LogTrace("ListenerTimeout = " + listenerTimeOut + ", MessageRecieved = " + messageReceived); - if (activeListenerCount == 0) - { - LOG.LogDebug("All processing threads ended - calling StartPeek again."); - //last active worker thread needs to restart the peeking process - StartPeeking(); - } - else if (listenerTimeOut && messageReceived) - { - LOG.LogDebug("Processing thread ended due to timeout and last recieve operation was successfull, calling StartPeek again."); - StartPeeking(); - } - Monitor.PulseAll(activeListenerMonitor); - } - - #endregion + Thread.Sleep(RecoveryTimeSpan); + StartPeeking(); } } - - /// - /// Subclasses perform a receive opertion on the message queue and execute the - /// message listener - /// - /// The DefaultMessageQueue. - /// true if received a message, false otherwise - protected abstract bool DoReceiveAndExecute(MessageQueue mq); - - - /// - /// Waits for listener threads to exit. - /// - protected virtual void WaitForListenerThreadsToExit() - { - try - { - lock (activeListenerMonitor) - { - if (activeListenerCount > 0) - { - while (activeListenerCount > 0) - { - LOG.LogDebug("Waiting for termination of " + activeListenerCount + " listener threads."); - Monitor.Wait(activeListenerMonitor); - } - } - } - } - catch (ThreadInterruptedException) - { - Thread.CurrentThread.Interrupt(); - } - } - - - /// - /// Configures the initial peek thread, setting it to be a background thread. - /// Can be overridden in subclasses. - /// - /// The peek thread. - protected virtual void ConfigureInitialPeekThread(Thread thread) - { - thread.IsBackground = true; - } - - - /// - /// Template method that gets called right when a new message has been received, - /// before attempting to process it. Allows subclasses to react to the event - /// of an actual incoming message, for example adapting their consumer count. - /// - /// The message. - protected virtual void MessageReceived(Message message) - { - } - - /// - /// Template method that gets called right before a new message is received, i.e. - /// messageQueue.Receive(). - /// - /// It allows subclasses to modify the state of the MessageQueue - /// before receiving which maybe required when using remote queues - /// - protected virtual void BeforeMessageReceived(MessageQueue messageQueue) - { - } - - #endregion } + + /// + /// The callback when the peek has completed. Schedule up to the maximum number of + /// concurrent listeners to receive messages off the queue. Delegates to the abstract + /// method DoReceiveAndExecute so that subclasses may customize the receiving process, + /// for example to surround the receive operation with transactional semantics. + /// + /// The async result. + protected virtual void PeekCompleted(IAsyncResult asyncResult) + { + bool listenerThreadWillCallStartPeek = false; + try + { + LOG.LogDebug("Peek Completed called."); + + MessageQueue.EndPeek(asyncResult); + + int numberOfListenersToSchedule = 0; + + // lock also prevents listeners that are about to exit from invoking + // StartPeeking while new listeners are being scheduled. + lock (activeListenerMonitor) + { + numberOfListenersToSchedule = maxConcurrentListeners - + (activeListenerCount + scheduledListenerCount); + + LOG.LogDebug("Submitting " + numberOfListenersToSchedule + " listener work items"); + + #region Submit to thread pool up to max number of concurrent listeners + + for (int i = 1; i <= numberOfListenersToSchedule; i++) + { + bool wasQueued = ThreadPool.QueueUserWorkItem(new WaitCallback(ReceiveAndExecute), MessageQueue); + if (wasQueued) + { + scheduledListenerCount++; + listenerThreadWillCallStartPeek = true; + LOG.LogDebug("Queued ReceiveAndExecute listener # " + i); + } + else + { + LOG.LogError("Could not submit ReceiveAndExecute work item for listener # " + i); + } + } + + Monitor.PulseAll(activeListenerMonitor); + } + + #endregion + } + catch (MessageQueueException mex) + { + switch ((int) mex.MessageQueueErrorCode) + { + case -1073741536: // = 0xc0000120 "STATUS_CANCELLED". + LOG.LogInformation("Asynchronous Peek Thread sent STATUS_CANCELLED."); + break; + default: + LOG.LogError(mex, "MessageQueueException Peeking Message"); + break; + } + } + catch (Exception e) + { + LOG.LogError(e, "Exception Peeking Message"); + } + finally + { + if (listenerThreadWillCallStartPeek == false && Running) + { + LOG.LogWarning("Could not queue any listeners onto the thread pool. Calling BeginPeek again after delay of " + + RecoveryTimeSpan); + Thread.Sleep(RecoveryTimeSpan); + StartPeeking(); + } + } + } + + /// + /// Execute the listener for a message received from the given queue + /// wrapping the entire operation in an external transaction if demanded. + /// + /// The DefaultMessageQueue upon which the call to receive should be + /// called. + protected virtual void ReceiveAndExecute(object state) + { + bool messageReceived = true; + bool listenerTimeOut = false; + + MessageQueue mq = state as MessageQueue; + if (mq == null) + { + throw new ArgumentException("Expected asynchronous state object to be of the type DefaultMessageQueue"); + } + + try + { + LOG.LogDebug("Executing ReceiveAndExecute"); + + #region Increment Active Listener Count + + lock (activeListenerMonitor) + { + activeListenerCount++; + scheduledListenerCount--; + LOG.LogDebug("ActiveListenerCount = " + activeListenerCount); + LOG.LogDebug("ScheduledListenerCount = " + scheduledListenerCount); + Monitor.PulseAll(activeListenerMonitor); + } + + #endregion + + DateTime expirationTime = DateTime.Now.Add(ListenerTimeLimit); + while (!listenerTimeOut && messageReceived) + { + //Subclasses to perform receive operation + messageReceived = DoReceiveAndExecute(mq); + + if (ListenerTimeLimit == TimeSpan.Zero) + { + listenerTimeOut = true; + LOG.LogTrace("No listener timelimit specified, exiting recieve loop after one iteration."); + } + else if (DateTime.Now >= expirationTime) + { + listenerTimeOut = true; + LOG.LogTrace("Listener timeout, exiting receive loop."); + } + else + { + LOG.LogTrace("Continuing receive loop."); + } + } + } + catch (Exception ex) + { + messageReceived = false; + string message = "Error receiving message from DefaultMessageQueue = [" + mq.Path + "]"; + LOG.LogError(ex, message); + } + finally + { + LOG.LogDebug("Exiting ReceiveAndExecute"); + + #region Decrementing Listener Count and call StartPeeking if last listener or there are still messages to process + + lock (activeListenerMonitor) + { + activeListenerCount--; + LOG.LogDebug("ActiveListenerCount = " + activeListenerCount); + LOG.LogTrace("ListenerTimeout = " + listenerTimeOut + ", MessageRecieved = " + messageReceived); + if (activeListenerCount == 0) + { + LOG.LogDebug("All processing threads ended - calling StartPeek again."); + //last active worker thread needs to restart the peeking process + StartPeeking(); + } + else if (listenerTimeOut && messageReceived) + { + LOG.LogDebug("Processing thread ended due to timeout and last recieve operation was successfull, calling StartPeek again."); + StartPeeking(); + } + + Monitor.PulseAll(activeListenerMonitor); + } + + #endregion + } + } + + /// + /// Subclasses perform a receive opertion on the message queue and execute the + /// message listener + /// + /// The DefaultMessageQueue. + /// true if received a message, false otherwise + protected abstract bool DoReceiveAndExecute(MessageQueue mq); + + /// + /// Waits for listener threads to exit. + /// + protected virtual void WaitForListenerThreadsToExit() + { + try + { + lock (activeListenerMonitor) + { + if (activeListenerCount > 0) + { + while (activeListenerCount > 0) + { + LOG.LogDebug("Waiting for termination of " + activeListenerCount + " listener threads."); + Monitor.Wait(activeListenerMonitor); + } + } + } + } + catch (ThreadInterruptedException) + { + Thread.CurrentThread.Interrupt(); + } + } + + /// + /// Configures the initial peek thread, setting it to be a background thread. + /// Can be overridden in subclasses. + /// + /// The peek thread. + protected virtual void ConfigureInitialPeekThread(Thread thread) + { + thread.IsBackground = true; + } + + /// + /// Template method that gets called right when a new message has been received, + /// before attempting to process it. Allows subclasses to react to the event + /// of an actual incoming message, for example adapting their consumer count. + /// + /// The message. + protected virtual void MessageReceived(Message message) + { + } + + /// + /// Template method that gets called right before a new message is received, i.e. + /// messageQueue.Receive(). + /// + /// It allows subclasses to modify the state of the MessageQueue + /// before receiving which maybe required when using remote queues + /// + protected virtual void BeforeMessageReceived(MessageQueue messageQueue) + { + } + + #endregion } diff --git a/src/Spring/Spring.Messaging/Messaging/Listener/AbstractSendToQueueExceptionHandler.cs b/src/Spring/Spring.Messaging/Messaging/Listener/AbstractSendToQueueExceptionHandler.cs index b990a8ae..f5244273 100644 --- a/src/Spring/Spring.Messaging/Messaging/Listener/AbstractSendToQueueExceptionHandler.cs +++ b/src/Spring/Spring.Messaging/Messaging/Listener/AbstractSendToQueueExceptionHandler.cs @@ -5,136 +5,137 @@ using Spring.Objects.Factory; #if NETSTANDARD using Experimental.System.Messaging; + #else using System.Messaging; #endif -namespace Spring.Messaging.Listener +namespace Spring.Messaging.Listener; + +/// +/// Provides common functionality to exception handlers that will send the exceptional message to +/// another queue. +/// +/// Allows for setting of MaxRetry limit and contains an internal dictionary to keep track +/// of the Message Ids of messages. +/// +/// Mark Pollack +public abstract class AbstractSendToQueueExceptionHandler : IInitializingObject, IApplicationContextAware { + private int maxRetry = 5; + + private IMessageQueueFactory messageQueueFactory; + private string messageQueueObjectName; + private IApplicationContext applicationContext; + /// - /// Provides common functionality to exception handlers that will send the exceptional message to - /// another queue. + /// Synchronization object for access to messageMap protected variable /// - /// Allows for setting of MaxRetry limit and contains an internal dictionary to keep track - /// of the Message Ids of messages. - /// - /// Mark Pollack - public abstract class AbstractSendToQueueExceptionHandler : IInitializingObject, IApplicationContextAware + protected object messageMapMonitor = new object(); + + /// + /// In-memory storage to keep track of Message Ids that have been already processed. + /// + protected IDictionary messageMap = new Hashtable(); + + /// + /// Gets or sets the maximum retry count to reattempt processing of a message that has thrown + /// an exception + /// + /// The max retry count. + public int MaxRetry { - private int maxRetry = 5; - - private IMessageQueueFactory messageQueueFactory; - private string messageQueueObjectName; - private IApplicationContext applicationContext; - - /// - /// Synchronization object for access to messageMap protected variable - /// - protected object messageMapMonitor = new object(); - - - /// - /// In-memory storage to keep track of Message Ids that have been already processed. - /// - protected IDictionary messageMap = new Hashtable(); - - /// - /// Gets or sets the maximum retry count to reattempt processing of a message that has thrown - /// an exception - /// - /// The max retry count. - public int MaxRetry - { - get { return maxRetry; } - set { maxRetry = value; } - } - - /// - /// Gets or sets the message queue factory. - /// - /// The message queue factory. - public IMessageQueueFactory MessageQueueFactory - { - get { return messageQueueFactory; } - set { messageQueueFactory = value; } - } - - /// - /// Gets or sets the name of the message queue object to send the message that cannot be - /// processed successfully after MaxRetry delivery attempts. - /// - /// The name of the message queue object. - public string MessageQueueObjectName - { - get { return messageQueueObjectName; } - set { messageQueueObjectName = value; } - } - - #region IApplicationContextAware Members - - /// - /// Gets or sets the that this - /// object runs in. - /// - /// - ///

- /// Normally this call will be used to initialize the object. - ///

- ///

- /// Invoked after population of normal object properties but before an - /// init callback such as - /// 's - /// - /// or a custom init-method. Invoked after the setting of any - /// 's - /// - /// property. - ///

- ///
- /// - /// In the case of application context initialization errors. - /// - /// - /// If thrown by any application context methods. - /// - /// - public IApplicationContext ApplicationContext - { - get { return applicationContext; } - set { applicationContext = value; } - } - - #endregion - - #region IInitializingObject Members - - /// - /// Ensure that the MessageQueueObject name is set and creates a - /// if no - /// is specified. - /// - /// Will attempt to create an instance of the DefaultMessageQueue to detect early - /// any configuraiton errors. - /// - /// In the event of misconfiguration (such as the failure to set a - /// required property) or if initialization fails. - /// - public virtual void AfterPropertiesSet() - { - if (MessageQueueObjectName == null) - { - throw new ArgumentException("The DefaultMessageQueueObjectName property has not been set."); - } - if (messageQueueFactory == null) - { - DefaultMessageQueueFactory mqf = new DefaultMessageQueueFactory(); - mqf.ApplicationContext = applicationContext; - messageQueueFactory = mqf; - } - //Create an instance so we can 'fail-fast' if there isn't an DefaultMessageQueue unde - MessageQueue mq = MessageQueueFactory.CreateMessageQueue(messageQueueObjectName); - } - - #endregion + get { return maxRetry; } + set { maxRetry = value; } } + + /// + /// Gets or sets the message queue factory. + /// + /// The message queue factory. + public IMessageQueueFactory MessageQueueFactory + { + get { return messageQueueFactory; } + set { messageQueueFactory = value; } + } + + /// + /// Gets or sets the name of the message queue object to send the message that cannot be + /// processed successfully after MaxRetry delivery attempts. + /// + /// The name of the message queue object. + public string MessageQueueObjectName + { + get { return messageQueueObjectName; } + set { messageQueueObjectName = value; } + } + + #region IApplicationContextAware Members + + /// + /// Gets or sets the that this + /// object runs in. + /// + /// + ///

+ /// Normally this call will be used to initialize the object. + ///

+ ///

+ /// Invoked after population of normal object properties but before an + /// init callback such as + /// 's + /// + /// or a custom init-method. Invoked after the setting of any + /// 's + /// + /// property. + ///

+ ///
+ /// + /// In the case of application context initialization errors. + /// + /// + /// If thrown by any application context methods. + /// + /// + public IApplicationContext ApplicationContext + { + get { return applicationContext; } + set { applicationContext = value; } + } + + #endregion + + #region IInitializingObject Members + + /// + /// Ensure that the MessageQueueObject name is set and creates a + /// if no + /// is specified. + /// + /// Will attempt to create an instance of the DefaultMessageQueue to detect early + /// any configuraiton errors. + /// + /// In the event of misconfiguration (such as the failure to set a + /// required property) or if initialization fails. + /// + public virtual void AfterPropertiesSet() + { + if (MessageQueueObjectName == null) + { + throw new ArgumentException("The DefaultMessageQueueObjectName property has not been set."); + } + + if (messageQueueFactory == null) + { + DefaultMessageQueueFactory mqf = new DefaultMessageQueueFactory(); + mqf.ApplicationContext = applicationContext; + messageQueueFactory = mqf; + } + + //Create an instance so we can 'fail-fast' if there isn't an DefaultMessageQueue unde + MessageQueue mq = MessageQueueFactory.CreateMessageQueue(messageQueueObjectName); + } + + #endregion } diff --git a/src/Spring/Spring.Messaging/Messaging/Listener/AbstractTransactionalMessageListenerContainer.cs b/src/Spring/Spring.Messaging/Messaging/Listener/AbstractTransactionalMessageListenerContainer.cs index 1056a210..2d02c445 100644 --- a/src/Spring/Spring.Messaging/Messaging/Listener/AbstractTransactionalMessageListenerContainer.cs +++ b/src/Spring/Spring.Messaging/Messaging/Listener/AbstractTransactionalMessageListenerContainer.cs @@ -26,125 +26,125 @@ using Spring.Transaction.Support; #if NETSTANDARD using Experimental.System.Messaging; + #else using System.Messaging; #endif -namespace Spring.Messaging.Listener +namespace Spring.Messaging.Listener; + +/// +/// An implementation of a Peeking based MessageListener container that starts a transaction +/// before recieving a message. The implementation determines +/// the type of transaction that will be started. An exception while processing the message will +/// result in a rollback, otherwise a transaction commit will be performed. +/// +/// +/// The type of transaction that can be started can either be local transaction, +/// (e.g. , a local messaging transaction +/// (e.g. or a DTC based transaction, +/// (eg. . +/// +/// Transaction properties can be set using the property +/// and the transaction timeout via the property . +/// +/// +public abstract class AbstractTransactionalMessageListenerContainer : AbstractPeekingMessageListenerContainer { + #region Logging Definition + + private static readonly ILogger LOG = LogManager.GetLogger(typeof(AbstractTransactionalMessageListenerContainer)); + + #endregion + + private IPlatformTransactionManager platformTransactionManager; + + private DefaultTransactionDefinition transactionDefinition = new DefaultTransactionDefinition(); + /// - /// An implementation of a Peeking based MessageListener container that starts a transaction - /// before recieving a message. The implementation determines - /// the type of transaction that will be started. An exception while processing the message will - /// result in a rollback, otherwise a transaction commit will be performed. + /// Gets or sets the platform transaction manager. /// - /// - /// The type of transaction that can be started can either be local transaction, - /// (e.g. , a local messaging transaction - /// (e.g. or a DTC based transaction, - /// (eg. . - /// - /// Transaction properties can be set using the property - /// and the transaction timeout via the property . - /// - /// - public abstract class AbstractTransactionalMessageListenerContainer : AbstractPeekingMessageListenerContainer + /// The platform transaction manager. + public IPlatformTransactionManager PlatformTransactionManager { - #region Logging Definition + get { return platformTransactionManager; } + set { platformTransactionManager = value; } + } - private static readonly ILogger LOG = LogManager.GetLogger(typeof (AbstractTransactionalMessageListenerContainer)); + /// + /// Gets or sets the transaction definition. + /// + /// The transaction definition. + public DefaultTransactionDefinition TransactionDefinition + { + get { return transactionDefinition; } + set { transactionDefinition = value; } + } - #endregion + /// + /// Sets the transaction timeout to use for transactional wrapping, in seconds. + /// Default is none, using the transaction manager's default timeout. + /// + /// The transaction timeout. + public int TransactionTimeout + { + set { transactionDefinition.TransactionTimeout = value; } + } - private IPlatformTransactionManager platformTransactionManager; - - private DefaultTransactionDefinition transactionDefinition = new DefaultTransactionDefinition(); - - - /// - /// Gets or sets the platform transaction manager. - /// - /// The platform transaction manager. - public IPlatformTransactionManager PlatformTransactionManager + /// + /// Subclasses perform a receive opertion on the message queue and execute the + /// message listener + /// + /// The DefaultMessageQueue. + /// + /// true if received a message, false otherwise + /// + protected override bool DoReceiveAndExecute(MessageQueue mq) + { + bool messageReceived = false; + // Execute receive within transaction. + ITransactionStatus status = PlatformTransactionManager.GetTransaction(TransactionDefinition); + try { - get { return platformTransactionManager; } - set { platformTransactionManager = value; } + messageReceived = DoReceiveAndExecuteUsingPlatformTransactionManager(mq, status); + } + catch (Exception ex) + { + RollbackOnException(status, ex); + Thread.Sleep(RecoveryTimeSpan); + throw; } - /// - /// Gets or sets the transaction definition. - /// - /// The transaction definition. - public DefaultTransactionDefinition TransactionDefinition + //if status has indicated rollback only, will rollback. + PlatformTransactionManager.Commit(status); + return messageReceived; + } + + /// + /// Does the receive and execute using platform transaction manager. + /// + /// The message queue. + /// The transactional status. + /// true if should continue peeking, false otherwise. + protected abstract bool DoReceiveAndExecuteUsingPlatformTransactionManager(MessageQueue mq, + ITransactionStatus status); + + /// + /// Rollback the transaction on exception. + /// + /// The transactional status. + /// The exception. + protected void RollbackOnException(ITransactionStatus status, Exception ex) + { + LOG.LogDebug(ex, "Initiating transaction rollback on listener exception"); + try { - get { return transactionDefinition; } - set { transactionDefinition = value; } + PlatformTransactionManager.Rollback(status); } - - /// - /// Sets the transaction timeout to use for transactional wrapping, in seconds. - /// Default is none, using the transaction manager's default timeout. - /// - /// The transaction timeout. - public int TransactionTimeout + catch (Exception ex2) { - set { transactionDefinition.TransactionTimeout = value; } - } - - /// - /// Subclasses perform a receive opertion on the message queue and execute the - /// message listener - /// - /// The DefaultMessageQueue. - /// - /// true if received a message, false otherwise - /// - protected override bool DoReceiveAndExecute(MessageQueue mq) - { - bool messageReceived = false; - // Execute receive within transaction. - ITransactionStatus status = PlatformTransactionManager.GetTransaction(TransactionDefinition); - try - { - messageReceived = DoReceiveAndExecuteUsingPlatformTransactionManager(mq, status); - } - catch (Exception ex) - { - RollbackOnException(status, ex); - Thread.Sleep(RecoveryTimeSpan); - throw; - } - //if status has indicated rollback only, will rollback. - PlatformTransactionManager.Commit(status); - return messageReceived; - } - - /// - /// Does the receive and execute using platform transaction manager. - /// - /// The message queue. - /// The transactional status. - /// true if should continue peeking, false otherwise. - protected abstract bool DoReceiveAndExecuteUsingPlatformTransactionManager(MessageQueue mq, - ITransactionStatus status); - - /// - /// Rollback the transaction on exception. - /// - /// The transactional status. - /// The exception. - protected void RollbackOnException(ITransactionStatus status, Exception ex) - { - LOG.LogDebug(ex, "Initiating transaction rollback on listener exception"); - try - { - PlatformTransactionManager.Rollback(status); - } - catch (Exception ex2) - { - LOG.LogError(ex2, "Listener exception overridden by rollback error"); - throw; - } + LOG.LogError(ex2, "Listener exception overridden by rollback error"); + throw; } } } diff --git a/src/Spring/Spring.Messaging/Messaging/Listener/DistributedTxMessageListenerContainer.cs b/src/Spring/Spring.Messaging/Messaging/Listener/DistributedTxMessageListenerContainer.cs index 2a4a2700..f11b67ef 100644 --- a/src/Spring/Spring.Messaging/Messaging/Listener/DistributedTxMessageListenerContainer.cs +++ b/src/Spring/Spring.Messaging/Messaging/Listener/DistributedTxMessageListenerContainer.cs @@ -24,137 +24,111 @@ using Spring.Transaction; #if NETSTANDARD using Experimental.System.Messaging; + #else using System.Messaging; #endif -namespace Spring.Messaging.Listener +namespace Spring.Messaging.Listener; + +/// +/// A MessageListenerContainer that uses distributed (DTC) based transactions. Exceptions are +/// handled by instances of . +/// +/// +/// +/// Starts a DTC based transaction before receiving the message. The transaction is +/// automaticaly promoted to 2PC to avoid the default behaivor of transactional promotion. +/// Database and messaging operations will commit or rollback together. +/// +/// +/// If you only want local message based transactions use the +/// . With some simple programming +/// you may also achieve 'exactly once' processing using the +/// . +/// +/// +/// Poison messages can be detected and sent to another queue using Spring's +/// . +/// +/// +public class DistributedTxMessageListenerContainer : AbstractTransactionalMessageListenerContainer { + #region Logging Definition + + private static readonly ILogger LOG = LogManager.GetLogger(typeof(DistributedTxMessageListenerContainer)); + + #endregion + + private IDistributedTransactionExceptionHandler distributedTransactionExceptionHandler; + /// - /// A MessageListenerContainer that uses distributed (DTC) based transactions. Exceptions are - /// handled by instances of . + /// Gets or sets the distributed transaction exception handler. /// - /// - /// - /// Starts a DTC based transaction before receiving the message. The transaction is - /// automaticaly promoted to 2PC to avoid the default behaivor of transactional promotion. - /// Database and messaging operations will commit or rollback together. - /// - /// - /// If you only want local message based transactions use the - /// . With some simple programming - /// you may also achieve 'exactly once' processing using the - /// . - /// - /// - /// Poison messages can be detected and sent to another queue using Spring's - /// . - /// - /// - public class DistributedTxMessageListenerContainer : AbstractTransactionalMessageListenerContainer + /// The distributed transaction exception handler. + public IDistributedTransactionExceptionHandler DistributedTransactionExceptionHandler { - #region Logging Definition + get { return distributedTransactionExceptionHandler; } + set { distributedTransactionExceptionHandler = value; } + } - private static readonly ILogger LOG = LogManager.GetLogger(typeof (DistributedTxMessageListenerContainer)); - - #endregion - - private IDistributedTransactionExceptionHandler distributedTransactionExceptionHandler; - - - /// - /// Gets or sets the distributed transaction exception handler. - /// - /// The distributed transaction exception handler. - public IDistributedTransactionExceptionHandler DistributedTransactionExceptionHandler + /// + /// Set the transaction name to be the spring object name. + /// Call base class Initialize() functionality. + /// + public override void Initialize() + { + // Use object name as default transaction name. + if (TransactionDefinition.Name == null) { - get { return distributedTransactionExceptionHandler; } - set { distributedTransactionExceptionHandler = value; } + TransactionDefinition.Name = ObjectName; } - /// - /// Set the transaction name to be the spring object name. - /// Call base class Initialize() functionality. - /// - public override void Initialize() - { - // Use object name as default transaction name. - if (TransactionDefinition.Name == null) - { - TransactionDefinition.Name = ObjectName; - } + // Proceed with superclass initialization. + base.Initialize(); + } - // Proceed with superclass initialization. - base.Initialize(); + /// + /// Does the receive and execute using TxPlatformTransactionManager. Starts a distributed + /// transaction before calling Receive. + /// + /// The message queue. + /// The transactional status. + /// + /// true if should continue peeking, false otherwise. + /// + protected override bool DoReceiveAndExecuteUsingPlatformTransactionManager(MessageQueue mq, + ITransactionStatus status) + { + #region Logging + + if (LOG.IsEnabled(LogLevel.Debug)) + { + LOG.LogDebug("Executing DoReceiveAndExecuteUsingTxScopeTransactionManager"); } - /// - /// Does the receive and execute using TxPlatformTransactionManager. Starts a distributed - /// transaction before calling Receive. - /// - /// The message queue. - /// The transactional status. - /// - /// true if should continue peeking, false otherwise. - /// - protected override bool DoReceiveAndExecuteUsingPlatformTransactionManager(MessageQueue mq, - ITransactionStatus status) + #endregion Logging + + //We are sure to be talking to a second resource manager, so avoid going through + //the promotable transaction and force a distributed transaction right from the start. + TransactionInterop.GetTransmitterPropagationToken(System.Transactions.Transaction.Current); + + Message message; + try { - #region Logging - - if (LOG.IsEnabled(LogLevel.Debug)) + message = mq.Receive(TimeSpan.Zero, MessageQueueTransactionType.Automatic); + } + catch (MessageQueueException ex) + { + if (ex.MessageQueueErrorCode == MessageQueueErrorCode.IOTimeout) { - LOG.LogDebug("Executing DoReceiveAndExecuteUsingTxScopeTransactionManager"); - } + //expected to occur occasionally - #endregion Logging - - //We are sure to be talking to a second resource manager, so avoid going through - //the promotable transaction and force a distributed transaction right from the start. - TransactionInterop.GetTransmitterPropagationToken(System.Transactions.Transaction.Current); - - Message message; - try - { - message = mq.Receive(TimeSpan.Zero, MessageQueueTransactionType.Automatic); - } - catch (MessageQueueException ex) - { - if (ex.MessageQueueErrorCode == MessageQueueErrorCode.IOTimeout) - { - //expected to occur occasionally - - #region Logging - - if (LOG.IsEnabled(LogLevel.Trace)) - { - LOG.LogTrace("MessageQueueErrorCode.IOTimeout: No message available to receive. May have been processed by another thread."); - } - - #endregion - - status.SetRollbackOnly(); - return false; // no more peeking unless this is the last listener thread - } - else - { - // A real issue in receiving the message - lock (messageQueueMonitor) - { - mq.Close(); - MessageQueue.ClearConnectionCache(); - } - throw; // will cause rollback in surrounding platform transaction manager and log exception - } - } - - if (message == null) - { #region Logging if (LOG.IsEnabled(LogLevel.Trace)) { - LOG.LogTrace("Message recieved is null from Queue = [" + mq.Path + "]"); + LOG.LogTrace("MessageQueueErrorCode.IOTimeout: No message available to receive. May have been processed by another thread."); } #endregion @@ -162,55 +136,82 @@ namespace Spring.Messaging.Listener status.SetRollbackOnly(); return false; // no more peeking unless this is the last listener thread } - - - try + else { - #region Logging - - if (LOG.IsEnabled(LogLevel.Debug)) + // A real issue in receiving the message + lock (messageQueueMonitor) { - LOG.LogDebug("Received message [" + message.Id + "] on queue [" + mq.Path + "]"); + mq.Close(); + MessageQueue.ClearConnectionCache(); } - #endregion - - MessageReceived(message); - if (DistributedTransactionExceptionHandler != null) - { - if (DistributedTransactionExceptionHandler.IsPoisonMessage(message)) - { - DistributedTransactionExceptionHandler.HandlePoisonMessage(message); - return true; // will remove from queue and continue receive loop. - } - } - DoExecuteListener(message); + throw; // will cause rollback in surrounding platform transaction manager and log exception } - catch (Exception ex) - { - HandleDistributedTransactionListenerException(ex, message); - throw; // will rollback and keep message on the queue. - } - finally - { - message.Dispose(); - } - return true; } - /// - /// Handles the distributed transaction listener exception by calling the - /// if not null. - /// - /// The exception. - /// The message. - protected virtual void HandleDistributedTransactionListenerException(Exception exception, Message message) + if (message == null) { - IDistributedTransactionExceptionHandler exceptionHandler = DistributedTransactionExceptionHandler; - if (exceptionHandler != null) + #region Logging + + if (LOG.IsEnabled(LogLevel.Trace)) { - exceptionHandler.OnException(exception, message); + LOG.LogTrace("Message recieved is null from Queue = [" + mq.Path + "]"); } + + #endregion + + status.SetRollbackOnly(); + return false; // no more peeking unless this is the last listener thread + } + + try + { + #region Logging + + if (LOG.IsEnabled(LogLevel.Debug)) + { + LOG.LogDebug("Received message [" + message.Id + "] on queue [" + mq.Path + "]"); + } + + #endregion + + MessageReceived(message); + if (DistributedTransactionExceptionHandler != null) + { + if (DistributedTransactionExceptionHandler.IsPoisonMessage(message)) + { + DistributedTransactionExceptionHandler.HandlePoisonMessage(message); + return true; // will remove from queue and continue receive loop. + } + } + + DoExecuteListener(message); + } + catch (Exception ex) + { + HandleDistributedTransactionListenerException(ex, message); + throw; // will rollback and keep message on the queue. + } + finally + { + message.Dispose(); + } + + return true; + } + + /// + /// Handles the distributed transaction listener exception by calling the + /// if not null. + /// + /// The exception. + /// The message. + protected virtual void HandleDistributedTransactionListenerException(Exception exception, Message message) + { + IDistributedTransactionExceptionHandler exceptionHandler = DistributedTransactionExceptionHandler; + if (exceptionHandler != null) + { + exceptionHandler.OnException(exception, message); } } -} +} \ No newline at end of file diff --git a/src/Spring/Spring.Messaging/Messaging/Listener/IDistributedTransactionExceptionHandler.cs b/src/Spring/Spring.Messaging/Messaging/Listener/IDistributedTransactionExceptionHandler.cs index 584b1f6f..d1438f53 100644 --- a/src/Spring/Spring.Messaging/Messaging/Listener/IDistributedTransactionExceptionHandler.cs +++ b/src/Spring/Spring.Messaging/Messaging/Listener/IDistributedTransactionExceptionHandler.cs @@ -20,50 +20,50 @@ #if NETSTANDARD using Experimental.System.Messaging; + #else using System.Messaging; #endif -namespace Spring.Messaging.Listener +namespace Spring.Messaging.Listener; + +/// +/// Exception handler for use with DTC based message listener container. +/// such as . +/// See for +/// an implementation that detects poison messages and send them to another queue. +/// +public interface IDistributedTransactionExceptionHandler { /// - /// Exception handler for use with DTC based message listener container. - /// such as . - /// See for - /// an implementation that detects poison messages and send them to another queue. + /// Determines whether the incoming message is a poison message. This method is + /// called before the is invoked. /// - public interface IDistributedTransactionExceptionHandler - { - /// - /// Determines whether the incoming message is a poison message. This method is - /// called before the is invoked. - /// - /// - /// The will call - /// if this method returns true and will - /// then commit the distibuted transaction (removing the message from the queue). - /// - /// The incoming message. - /// - /// true if it is a poison message; otherwise, false. - /// - bool IsPoisonMessage(Message message); + /// + /// The will call + /// if this method returns true and will + /// then commit the distibuted transaction (removing the message from the queue). + /// + /// The incoming message. + /// + /// true if it is a poison message; otherwise, false. + /// + bool IsPoisonMessage(Message message); - /// - /// Handles the poison message. - /// - /// Typical implementations will move the message to another queue. - /// The will call this - /// method while still within a DTC-based transaction. - /// - /// The poison message. - void HandlePoisonMessage(Message poisonMessage); + /// + /// Handles the poison message. + /// + /// Typical implementations will move the message to another queue. + /// The will call this + /// method while still within a DTC-based transaction. + /// + /// The poison message. + void HandlePoisonMessage(Message poisonMessage); - /// - /// Called when an exception is thrown in listener processing. - /// - /// The exception. - /// The message. - void OnException(Exception exception, Message message); - } + /// + /// Called when an exception is thrown in listener processing. + /// + /// The exception. + /// The message. + void OnException(Exception exception, Message message); } diff --git a/src/Spring/Spring.Messaging/Messaging/Listener/IExceptionHandler.cs b/src/Spring/Spring.Messaging/Messaging/Listener/IExceptionHandler.cs index 5cdee42d..ee66de48 100644 --- a/src/Spring/Spring.Messaging/Messaging/Listener/IExceptionHandler.cs +++ b/src/Spring/Spring.Messaging/Messaging/Listener/IExceptionHandler.cs @@ -20,31 +20,31 @@ #if NETSTANDARD using Experimental.System.Messaging; + #else using System.Messaging; #endif -namespace Spring.Messaging.Listener +namespace Spring.Messaging.Listener; + +/// +/// Exception handler called when an exception occurs during +/// non-transactional receive processing. +/// +/// +/// A non-transactional receive will remove the message from the queue. Non-transactional +/// receivers do not suffer from poison messages since there is no redelivery by MSMQ. +/// Typical actions to perform are to log the message or place it in another queue. +/// If placed in another queue, another message listener container can be used to +/// process the message later, assuming the root cause of the original exception is +/// transient in nature. +/// +public interface IExceptionHandler { /// - /// Exception handler called when an exception occurs during - /// non-transactional receive processing. + /// Called when an exception is thrown in listener processing. /// - /// - /// A non-transactional receive will remove the message from the queue. Non-transactional - /// receivers do not suffer from poison messages since there is no redelivery by MSMQ. - /// Typical actions to perform are to log the message or place it in another queue. - /// If placed in another queue, another message listener container can be used to - /// process the message later, assuming the root cause of the original exception is - /// transient in nature. - /// - public interface IExceptionHandler - { - /// - /// Called when an exception is thrown in listener processing. - /// - /// The exception. - /// The message. - void OnException(Exception exception, Message message); - } + /// The exception. + /// The message. + void OnException(Exception exception, Message message); } diff --git a/src/Spring/Spring.Messaging/Messaging/Listener/IMessageListener.cs b/src/Spring/Spring.Messaging/Messaging/Listener/IMessageListener.cs index 20875fbf..403072ea 100644 --- a/src/Spring/Spring.Messaging/Messaging/Listener/IMessageListener.cs +++ b/src/Spring/Spring.Messaging/Messaging/Listener/IMessageListener.cs @@ -20,23 +20,22 @@ #if NETSTANDARD using Experimental.System.Messaging; + #else using System.Messaging; #endif +namespace Spring.Messaging.Listener; -namespace Spring.Messaging.Listener +/// +/// The callback invoked when a message is received. +/// +/// Mark Pollack +public interface IMessageListener { /// - /// The callback invoked when a message is received. + /// Called when message is received. /// - /// Mark Pollack - public interface IMessageListener - { - /// - /// Called when message is received. - /// - /// The message. - void OnMessage(Message message); - } -} \ No newline at end of file + /// The message. + void OnMessage(Message message); +} diff --git a/src/Spring/Spring.Messaging/Messaging/Listener/IMessageTransactionExceptionHandler.cs b/src/Spring/Spring.Messaging/Messaging/Listener/IMessageTransactionExceptionHandler.cs index 8560c8dd..35af6803 100644 --- a/src/Spring/Spring.Messaging/Messaging/Listener/IMessageTransactionExceptionHandler.cs +++ b/src/Spring/Spring.Messaging/Messaging/Listener/IMessageTransactionExceptionHandler.cs @@ -20,36 +20,36 @@ #if NETSTANDARD using Experimental.System.Messaging; + #else using System.Messaging; #endif -namespace Spring.Messaging.Listener +namespace Spring.Messaging.Listener; + +/// +/// The exception handler within a transactional context. +/// +/// +/// The return value indicates to the invoker (typically a +/// ) whether the +/// MessageTransaction that is associated with the delivery of this message +/// should be rolled back (placing the message back on the transactional queue +/// for redelivery) or commited (removing the message from the transactional queue) +/// +/// Mark Pollack +public interface IMessageTransactionExceptionHandler { /// - /// The exception handler within a transactional context. + /// Called when an exception is thrown during listener processing under the + /// scope of a . /// - /// - /// The return value indicates to the invoker (typically a - /// ) whether the - /// MessageTransaction that is associated with the delivery of this message - /// should be rolled back (placing the message back on the transactional queue - /// for redelivery) or commited (removing the message from the transactional queue) - /// - /// Mark Pollack - public interface IMessageTransactionExceptionHandler - { - /// - /// Called when an exception is thrown during listener processing under the - /// scope of a . - /// - /// The exception. - /// The message. - /// The message queue transaction. - /// An action indicating if the caller should commit or rollback the - /// - /// - TransactionAction OnException(Exception exception, Message message, - MessageQueueTransaction messageQueueTransaction); - } + /// The exception. + /// The message. + /// The message queue transaction. + /// An action indicating if the caller should commit or rollback the + /// + /// + TransactionAction OnException(Exception exception, Message message, + MessageQueueTransaction messageQueueTransaction); } diff --git a/src/Spring/Spring.Messaging/Messaging/Listener/ListenerExecutionFailedException.cs b/src/Spring/Spring.Messaging/Messaging/Listener/ListenerExecutionFailedException.cs index 7f7d3231..c268ced1 100644 --- a/src/Spring/Spring.Messaging/Messaging/Listener/ListenerExecutionFailedException.cs +++ b/src/Spring/Spring.Messaging/Messaging/Listener/ListenerExecutionFailedException.cs @@ -20,45 +20,44 @@ using System.Runtime.Serialization; -namespace Spring.Messaging.Listener +namespace Spring.Messaging.Listener; + +/// +/// Exception to be thrown when the execution of a listener method failed. +/// +/// Juergen Hoeller +/// Mark Pollack (.NET) +[Serializable] +public class ListenerExecutionFailedException : MessagingException { /// - /// Exception to be thrown when the execution of a listener method failed. + /// Initializes a new instance of the class. /// - /// Juergen Hoeller - /// Mark Pollack (.NET) - [Serializable] - public class ListenerExecutionFailedException : MessagingException + public ListenerExecutionFailedException() { - /// - /// Initializes a new instance of the class. - /// - public ListenerExecutionFailedException() - { - } + } - /// - /// Initializes a new instance of the class, with the specified message - /// - /// The message. - public ListenerExecutionFailedException(string message) : base(message) - { - } + /// + /// Initializes a new instance of the class, with the specified message + /// + /// The message. + public ListenerExecutionFailedException(string message) : base(message) + { + } - /// - /// Initializes a new instance of the class, with the specified message - /// and root cause exception - /// - /// The message. - /// The inner exception. - public ListenerExecutionFailedException(string message, Exception innerException) - : base(message, innerException) - { - } + /// + /// Initializes a new instance of the class, with the specified message + /// and root cause exception + /// + /// The message. + /// The inner exception. + public ListenerExecutionFailedException(string message, Exception innerException) + : base(message, innerException) + { + } - /// - protected ListenerExecutionFailedException(SerializationInfo info, StreamingContext context) : base(info, context) - { - } + /// + protected ListenerExecutionFailedException(SerializationInfo info, StreamingContext context) : base(info, context) + { } } diff --git a/src/Spring/Spring.Messaging/Messaging/Listener/MessageListenerAdapter.cs b/src/Spring/Spring.Messaging/Messaging/Listener/MessageListenerAdapter.cs index 58fea742..505378d9 100644 --- a/src/Spring/Spring.Messaging/Messaging/Listener/MessageListenerAdapter.cs +++ b/src/Spring/Spring.Messaging/Messaging/Listener/MessageListenerAdapter.cs @@ -28,582 +28,589 @@ using Spring.Reflection.Dynamic; #if NETSTANDARD using Experimental.System.Messaging; + #else using System.Messaging; #endif -namespace Spring.Messaging.Listener +namespace Spring.Messaging.Listener; + +/// +/// Message listener adapter that delegates the handling of messages to target +/// listener methods via reflection , +/// with flexible message type conversion. +/// Allows listener methods to operate on message content types, completely +/// independent from the MSMQ API. +/// +/// +/// +/// By default, the content of incoming MSMQ messages gets extracted before +/// being passed into the target handler method, to let the target method +/// operate on message content types such as String or business object instead of +/// . Message type conversion is delegated to a Spring +/// By default, an +/// with TargetType set to System.String is used. If you do not want such automatic +/// message conversion taking place, then be sure to set the +/// MessageConverter property to null. +/// +/// +/// If a target handler method returns a non-null object (for example, with a +/// message content type such as String), it will get +/// wrapped in a MSMQ Message and sent to the response destination +/// (either using the MSMQ Message.ResponseQueue property or +/// ) specified default response queue +/// destination). +/// +/// +/// Find below some examples of method signatures compliant with this adapter class. +/// This first example uses the default that can +/// marhsall/unmarshall string values from the MSMQ Message. +/// +/// +/// public interface IMyHandler +/// { +/// void HandleMessage(string text); +/// } +/// +/// +/// The next example indicates a similar method signature but the name of the +/// handler method name has been changed to "DoWork", using the property +/// +/// +/// +/// public interface IMyHandler +/// { +/// void DoWork(string text); +/// } +/// +/// If your implementation will return multiple object +/// types, overloading the handler method is perfectly acceptible, the most specific matching +/// method will be used. A method with an object signature would be consider a +/// 'catch-all' method +/// +/// +/// public interface IMyHandler +/// { +/// void DoWork(string text); +/// void DoWork(OrderRequest orderRequest); +/// void DoWork(InvoiceRequest invoiceRequest); +/// void DoWork(object obj); +/// } +/// +/// +/// The last example shows how to send a message to the ResponseQueue for those +/// methods that do not return void. +/// +/// public interface MyHandler +/// { +/// string DoWork(string text); +/// OrderResponse DoWork(OrderRequest orderRequest); +/// InvoiceResponse DoWork(InvoiceRequest invoiceRequest); +/// void DoWork(object obj); +/// } +/// +/// +/// +/// Mark Pollack +public class MessageListenerAdapter : IMessageListener, IApplicationContextAware, IInitializingObject { + #region Logging + + private static readonly ILogger logger = LogManager.GetLogger(typeof(MessageListenerAdapter)); + + #endregion + /// - /// Message listener adapter that delegates the handling of messages to target - /// listener methods via reflection , - /// with flexible message type conversion. - /// Allows listener methods to operate on message content types, completely - /// independent from the MSMQ API. + /// Out-of-the-box value for the default listener method: "HandleMessage" + /// + public static readonly string ORIGINAL_DEFAULT_LISTENER_METHOD = "HandleMessage"; + + #region Fields + + private IApplicationContext applicationContext; + + private object handlerObject; + + private string defaultHandlerMethod = ORIGINAL_DEFAULT_LISTENER_METHOD; + + private IExpression processingExpression; + + private string defaultResponseQueueName; + + private string messageConverterObjectName; + + private MessageQueueTemplate messageQueueTemplate; + + private IMessageQueueFactory messageQueueFactory; + + #endregion + + #region Constructors + + /// + /// Initializes a new instance of the class. + /// + public MessageListenerAdapter() + { + InitDefaultStrategies(); + handlerObject = this; + } + + /// + /// Initializes a new instance of the class. + /// + /// The handler object. + public MessageListenerAdapter(object handlerObject) + { + InitDefaultStrategies(); + this.handlerObject = handlerObject; + } + + #endregion + + /// + /// Gets or sets the handler object to delegate message listening to. /// /// - /// - /// By default, the content of incoming MSMQ messages gets extracted before - /// being passed into the target handler method, to let the target method - /// operate on message content types such as String or business object instead of - /// . Message type conversion is delegated to a Spring - /// By default, an - /// with TargetType set to System.String is used. If you do not want such automatic - /// message conversion taking place, then be sure to set the - /// MessageConverter property to null. - /// - /// - /// If a target handler method returns a non-null object (for example, with a - /// message content type such as String), it will get - /// wrapped in a MSMQ Message and sent to the response destination - /// (either using the MSMQ Message.ResponseQueue property or - /// ) specified default response queue - /// destination). - /// - /// - /// Find below some examples of method signatures compliant with this adapter class. - /// This first example uses the default that can - /// marhsall/unmarshall string values from the MSMQ Message. - /// - /// - /// public interface IMyHandler - /// { - /// void HandleMessage(string text); - /// } - /// - /// - /// The next example indicates a similar method signature but the name of the - /// handler method name has been changed to "DoWork", using the property - /// - /// - /// - /// public interface IMyHandler - /// { - /// void DoWork(string text); - /// } - /// - /// If your implementation will return multiple object - /// types, overloading the handler method is perfectly acceptible, the most specific matching - /// method will be used. A method with an object signature would be consider a - /// 'catch-all' method - /// - /// - /// public interface IMyHandler - /// { - /// void DoWork(string text); - /// void DoWork(OrderRequest orderRequest); - /// void DoWork(InvoiceRequest invoiceRequest); - /// void DoWork(object obj); - /// } - /// - /// - /// The last example shows how to send a message to the ResponseQueue for those - /// methods that do not return void. - /// - /// public interface MyHandler - /// { - /// string DoWork(string text); - /// OrderResponse DoWork(OrderRequest orderRequest); - /// InvoiceResponse DoWork(InvoiceRequest invoiceRequest); - /// void DoWork(object obj); - /// } - /// - /// + /// Specified listener methods have to be present on this target object. + /// If no explicit handler object has been specified, listener + /// methods are expected to present on this adapter instance, that is, + /// on a custom subclass of this adapter, defining listener methods. /// - /// Mark Pollack - public class MessageListenerAdapter : IMessageListener, IApplicationContextAware, IInitializingObject + /// The handler object. + public object HandlerObject { - #region Logging + get { return handlerObject; } + set { handlerObject = value; } + } - private static readonly ILogger logger = LogManager.GetLogger(typeof (MessageListenerAdapter)); - - #endregion - - /// - /// Out-of-the-box value for the default listener method: "HandleMessage" - /// - public static readonly string ORIGINAL_DEFAULT_LISTENER_METHOD = "HandleMessage"; - - #region Fields - - private IApplicationContext applicationContext; - - private object handlerObject; - - private string defaultHandlerMethod = ORIGINAL_DEFAULT_LISTENER_METHOD; - - private IExpression processingExpression; - - private string defaultResponseQueueName; - - private string messageConverterObjectName; - - private MessageQueueTemplate messageQueueTemplate; - - private IMessageQueueFactory messageQueueFactory; - - #endregion - - #region Constructors - - /// - /// Initializes a new instance of the class. - /// - public MessageListenerAdapter() - { - InitDefaultStrategies(); - handlerObject = this; - } - - /// - /// Initializes a new instance of the class. - /// - /// The handler object. - public MessageListenerAdapter(object handlerObject) - { - InitDefaultStrategies(); - this.handlerObject = handlerObject; - } - - #endregion - - /// - /// Gets or sets the handler object to delegate message listening to. - /// - /// - /// Specified listener methods have to be present on this target object. - /// If no explicit handler object has been specified, listener - /// methods are expected to present on this adapter instance, that is, - /// on a custom subclass of this adapter, defining listener methods. - /// - /// The handler object. - public object HandlerObject - { - get { return handlerObject; } - set { handlerObject = value; } - } - - /// - /// Gets or sets the default handler method to delegate to, - /// for the case where no specific listener method has been determined. - /// Out-of-the-box value is "HandleMessage". - /// - /// The default handler method. - public string DefaultHandlerMethod - { - get { return defaultHandlerMethod; } - set { - defaultHandlerMethod = value; - ProcessingExpression = Expression.Parse(defaultHandlerMethod + "(#convertedObject)"); - } - } - - /// - /// Gets or sets the processing expression for use in custom subclasses - /// - /// The processing expression. - protected IExpression ProcessingExpression - { - get { return processingExpression; } - set { processingExpression = value; } - } - - #region IInitializingObject Members - - /// - /// Invoked by an - /// after it has injected all of an object's dependencies. - /// - /// - ///

- /// This method allows the object instance to perform the kind of - /// initialization only possible when all of it's dependencies have - /// been injected (set), and to throw an appropriate exception in the - /// event of misconfiguration. - ///

- ///

- /// Please do consult the class level documentation for the - /// interface for a - /// description of exactly when this method is invoked. In - /// particular, it is worth noting that the - /// - /// and - /// callbacks will have been invoked prior to this method being - /// called. - ///

- ///
- /// - /// In the event of misconfiguration (such as the failure to set a - /// required property) or if initialization fails. - /// - public void AfterPropertiesSet() - { - if (messageQueueFactory == null) - { - DefaultMessageQueueFactory mqf = new DefaultMessageQueueFactory(); - mqf.ApplicationContext = applicationContext; - messageQueueFactory = mqf; - } - if (messageConverterObjectName == null) - { - messageConverterObjectName = QueueUtils.RegisterDefaultMessageConverter(applicationContext); - } - if (messageQueueTemplate == null) - { - messageQueueTemplate = new MessageQueueTemplate(); - messageQueueTemplate.ApplicationContext = ApplicationContext; - messageQueueTemplate.AfterPropertiesSet(); - } - } - - #endregion - - #region IApplicationContextAware Members - - /// - /// Gets or sets the that this - /// object runs in. - /// - /// - ///

- /// Normally this call will be used to initialize the object. - ///

- ///

- /// Invoked after population of normal object properties but before an - /// init callback such as - /// 's - /// - /// or a custom init-method. Invoked after the setting of any - /// 's - /// - /// property. - ///

- ///
- /// - /// In the case of application context initialization errors. - /// - /// - /// If thrown by any application context methods. - /// - /// - public IApplicationContext ApplicationContext - { - get { return applicationContext; } - set { applicationContext = value; } - } - - #endregion - - /// - /// Gets or sets the message queue factory. - /// - /// The message queue factory. - public IMessageQueueFactory MessageQueueFactory - { - get { return messageQueueFactory; } - set { messageQueueFactory = value; } - } - - /// - /// Sets the name of the default response queue to send response messages to. - /// This will be applied in case of a request message that does not carry a - /// "ResponseQueue" value. - /// Alternatively, specify a response queue via the property - /// . - /// - /// The name of the default response destination queue. - public string DefaultResponseQueueName - { - get { return defaultResponseQueueName; } - set { defaultResponseQueueName = value; } - } - - /// - /// Sets the default destination to send response messages to. This will be applied - /// in case of a request message that does not carry a "ResponseQueue" property - /// Response destinations are only relevant for listener methods that return - /// result objects, which will be wrapped in a response message and sent to a - /// response destination. - /// - /// Alternatively, specify a "DefaultResponseQueueName" - /// to be dynamically resolved via the MessageQueueFactory. - /// - /// - /// The default response destination. - public MessageQueue DefaultResponseQueue - { - get - { - if (DefaultResponseQueueName != null) - { - return messageQueueFactory.CreateMessageQueue(DefaultResponseQueueName); - } - else - { - return null; - } - } - } - - - /// - /// Gets or sets the name of the message converter object used to resolved a - /// instance. - /// - /// The name of the message converter object. - public string MessageConverterObjectName - { - get { return messageConverterObjectName; } - set { messageConverterObjectName = value; } - } - - /// - /// Gets message converter that will convert incoming MSMQ messages to - /// listener method arguments, and objects returned from listener - /// methods back to MSMQ messages. - /// - /// - /// The converter used is the one returned by CreateMessageConverter on MessageQueueFactory. - /// - /// - /// The message converter. - public IMessageConverter MessageConverter - { - get - { - return messageQueueFactory.CreateMessageConverter(MessageConverterObjectName); - } - } - - /// - /// Sets the message queue template. - /// - /// If not set, will create one for it own internal use whne MessageListenerAdapter is constructed. - /// It maybe useful to share an existing instance if you have an extensively configured MessageQueueTemplate. - /// - /// The message queue template. - public MessageQueueTemplate MessageQueueTemplate - { - set { messageQueueTemplate = value; } - } - - #region IMessageListener Members - - /// - /// Called when message is received. - /// - /// The message. - public virtual void OnMessage(Message message) - { - object convertedMessage = ExtractMessage(message); - - //IDictionary vars = new Hashtable(); - //vars["convertedObject"] = convertedMessage; - - string methodName = GetHandlerMethodName(message, convertedMessage); - object[] listenerArguments = BuildListenerArguments(convertedMessage); - object result = InvokeListenerMethod(methodName, listenerArguments); - - - //Invoke message handler method and get result. - //object result = processingExpression.GetValue(handlerObject, vars); - if (result != null) - { - HandleResult(result, message); - } - else - { - logger.LogDebug("No result object given - no result to handle"); - } - } - - #endregion - - /// - /// Gets the name of the handler method. - /// - /// The original message. - /// The extracted message. - /// The name of the handler method. - protected virtual string GetHandlerMethodName(Message originalMessage, object extractedMessage) - { - return DefaultHandlerMethod; - } - - /// - /// Builds an array of arguments to be passed into the taret listener method. - /// - /// - /// Allows for multiple method arguments to be built from a single message object. - ///

The default implementation builds an array with the given message object - /// as sole element. This means that the extracted message will always be passed - /// into a single method argument, even if it is an array, with the target - /// method having a corresponding single argument of the array's type declared.

- ///

This can be overridden to treat special message content such as arrays - /// differently, for example passing in each element of the message array - /// as distinct method argument.

- ///
- /// The converted message. - /// the array of arguments to be passed into the - /// listener method (each element of the array corresponding - /// to a distinct method argument) - protected virtual object[] BuildListenerArguments(object convertedMessage) - { - return new object[] { convertedMessage }; - } - - /// - /// Invokes the specified listener method. This default implementation can only handle invoking a - /// single argument method. - /// - /// Name of the listener method. - /// The arguments to be passed in. Only the first argument in the list is currently - /// supported in this implementation. - /// The result returned from the listener method - protected virtual object InvokeListenerMethod(string methodName, object[] arguments) - { - IDictionary vars = new Dictionary(); - vars["convertedObject"] = arguments[0]; - if (methodName.CompareTo(DefaultHandlerMethod) != 0) - { - //This is just to handle the case of overriding GetHandlerMethodName in a subclass and nothing else. - return ExpressionEvaluator.GetValue(handlerObject, methodName + "(#convertedObject)", vars); - } - // the normal case of using the cached expression. - return processingExpression.GetValue(handlerObject, vars); - } - - /// - /// Initialize the default implementations for the adapter's strategies. - /// - protected virtual void InitDefaultStrategies() + /// + /// Gets or sets the default handler method to delegate to, + /// for the case where no specific listener method has been determined. + /// Out-of-the-box value is "HandleMessage". + /// + /// The default handler method. + public string DefaultHandlerMethod + { + get { return defaultHandlerMethod; } + set { + defaultHandlerMethod = value; ProcessingExpression = Expression.Parse(defaultHandlerMethod + "(#convertedObject)"); } + } - /// - /// Extracts the message body from the given message. - /// - /// The message. - /// the content of the message, to be passed into the - /// listener method as argument - protected virtual object ExtractMessage(Message message) + /// + /// Gets or sets the processing expression for use in custom subclasses + /// + /// The processing expression. + protected IExpression ProcessingExpression + { + get { return processingExpression; } + set { processingExpression = value; } + } + + #region IInitializingObject Members + + /// + /// Invoked by an + /// after it has injected all of an object's dependencies. + /// + /// + ///

+ /// This method allows the object instance to perform the kind of + /// initialization only possible when all of it's dependencies have + /// been injected (set), and to throw an appropriate exception in the + /// event of misconfiguration. + ///

+ ///

+ /// Please do consult the class level documentation for the + /// interface for a + /// description of exactly when this method is invoked. In + /// particular, it is worth noting that the + /// + /// and + /// callbacks will have been invoked prior to this method being + /// called. + ///

+ ///
+ /// + /// In the event of misconfiguration (such as the failure to set a + /// required property) or if initialization fails. + /// + public void AfterPropertiesSet() + { + if (messageQueueFactory == null) { - IMessageConverter converter = MessageConverter; - if (converter != null) - { - return converter.FromMessage(message); - } - return message; + DefaultMessageQueueFactory mqf = new DefaultMessageQueueFactory(); + mqf.ApplicationContext = applicationContext; + messageQueueFactory = mqf; } - /// - /// Handles the result of a listener method. - /// - /// The result that was returned from listener. - /// The original request. - protected virtual void HandleResult(object result, Message request) + if (messageConverterObjectName == null) { - if (logger.IsEnabled(LogLevel.Debug)) - { - logger.LogDebug("Listener method returned result [" + result + - "] - generating response message for it"); - } - Message response = BuildMessage(result); - PostProcessResponse(request, response); - MessageQueue destination = GetResponseDestination(request, response); - SendResponse(destination, response); + messageConverterObjectName = QueueUtils.RegisterDefaultMessageConverter(applicationContext); } - /// - /// Sends the given response message to the given destination. - /// - /// The destination to send to. - /// The outgoing message about to be sent. - protected virtual void SendResponse(MessageQueue destination, Message response) + if (messageQueueTemplate == null) { - //Will send with appropriate transaction semantics - if (logger.IsEnabled(LogLevel.Debug)) - { - logger.LogDebug("Sending response message to path = [" + destination.Path + "]"); - } - messageQueueTemplate.Send(destination, response); + messageQueueTemplate = new MessageQueueTemplate(); + messageQueueTemplate.ApplicationContext = ApplicationContext; + messageQueueTemplate.AfterPropertiesSet(); } + } - /// - /// Builds a MSMQ message to be sent as response based on the given result object. - /// - /// The result. - /// the MSMQ Message (never null) - /// If no messgae converter is specified. - protected virtual Message BuildMessage(object result) + #endregion + + #region IApplicationContextAware Members + + /// + /// Gets or sets the that this + /// object runs in. + /// + /// + ///

+ /// Normally this call will be used to initialize the object. + ///

+ ///

+ /// Invoked after population of normal object properties but before an + /// init callback such as + /// 's + /// + /// or a custom init-method. Invoked after the setting of any + /// 's + /// + /// property. + ///

+ ///
+ /// + /// In the case of application context initialization errors. + /// + /// + /// If thrown by any application context methods. + /// + /// + public IApplicationContext ApplicationContext + { + get { return applicationContext; } + set { applicationContext = value; } + } + + #endregion + + /// + /// Gets or sets the message queue factory. + /// + /// The message queue factory. + public IMessageQueueFactory MessageQueueFactory + { + get { return messageQueueFactory; } + set { messageQueueFactory = value; } + } + + /// + /// Sets the name of the default response queue to send response messages to. + /// This will be applied in case of a request message that does not carry a + /// "ResponseQueue" value. + /// Alternatively, specify a response queue via the property + /// . + /// + /// The name of the default response destination queue. + public string DefaultResponseQueueName + { + get { return defaultResponseQueueName; } + set { defaultResponseQueueName = value; } + } + + /// + /// Sets the default destination to send response messages to. This will be applied + /// in case of a request message that does not carry a "ResponseQueue" property + /// Response destinations are only relevant for listener methods that return + /// result objects, which will be wrapped in a response message and sent to a + /// response destination. + /// + /// Alternatively, specify a "DefaultResponseQueueName" + /// to be dynamically resolved via the MessageQueueFactory. + /// + /// + /// The default response destination. + public MessageQueue DefaultResponseQueue + { + get { - IMessageConverter converter = MessageConverter; - if (converter != null) + if (DefaultResponseQueueName != null) { - // This is the default Message converter registered in QueueUtils.RegisterDefaultMessageConverter - // and used by MessageQueueTemplate and the MessageListenerAdapter if no other Message converage is - // set via the property MessageConverteryObjectName. - if (messageConverterObjectName.Equals("__XmlMessageConverter__")) - { - return converter.ToMessage(result.ToString()); - } - else - { - return converter.ToMessage(result); - } + return messageQueueFactory.CreateMessageQueue(DefaultResponseQueueName); } else { - Message msg = result as Message; - if (msg == null) - { - throw new MessagingException("No MessageConverter specified - cannot handle message [" + result + - "]"); - } - return msg; + return null; } } - - /// - /// Post-process the given response message before it will be sent. The default implementation - /// sets the response's correlation id to the request message's correlation id. - /// - /// The original incoming message. - /// The outgoing MSMQ message about to be sent. - protected virtual void PostProcessResponse(Message request, Message response) - { - response.CorrelationId = request.CorrelationId; - } - - /// - /// Determine a response destination for the given message. - /// - /// - /// The default implementation first checks the MSMQ ResponseQueue - /// of the supplied request; if that is not null - /// it is returned; if it is null, then the configured - /// default response destination} - /// is returned; if this too is null, then an - /// is thrown. - /// - /// - /// The request. - /// The response. - /// - protected virtual MessageQueue GetResponseDestination(Message request, Message response) - { - MessageQueue replyTo = request.ResponseQueue; - if (replyTo == null) - { - replyTo = DefaultResponseQueue; - if (replyTo == null) - { - throw new MessagingException("Cannot determine response destination: " + - "Request message does not contain ResponseQueue destination, and no default response queue set."); - } - } - return replyTo; - } + } + + /// + /// Gets or sets the name of the message converter object used to resolved a + /// instance. + /// + /// The name of the message converter object. + public string MessageConverterObjectName + { + get { return messageConverterObjectName; } + set { messageConverterObjectName = value; } + } + + /// + /// Gets message converter that will convert incoming MSMQ messages to + /// listener method arguments, and objects returned from listener + /// methods back to MSMQ messages. + /// + /// + /// The converter used is the one returned by CreateMessageConverter on MessageQueueFactory. + /// + /// + /// The message converter. + public IMessageConverter MessageConverter + { + get + { + return messageQueueFactory.CreateMessageConverter(MessageConverterObjectName); + } + } + + /// + /// Sets the message queue template. + /// + /// If not set, will create one for it own internal use whne MessageListenerAdapter is constructed. + /// It maybe useful to share an existing instance if you have an extensively configured MessageQueueTemplate. + /// + /// The message queue template. + public MessageQueueTemplate MessageQueueTemplate + { + set { messageQueueTemplate = value; } + } + + #region IMessageListener Members + + /// + /// Called when message is received. + /// + /// The message. + public virtual void OnMessage(Message message) + { + object convertedMessage = ExtractMessage(message); + + //IDictionary vars = new Hashtable(); + //vars["convertedObject"] = convertedMessage; + + string methodName = GetHandlerMethodName(message, convertedMessage); + object[] listenerArguments = BuildListenerArguments(convertedMessage); + object result = InvokeListenerMethod(methodName, listenerArguments); + + //Invoke message handler method and get result. + //object result = processingExpression.GetValue(handlerObject, vars); + if (result != null) + { + HandleResult(result, message); + } + else + { + logger.LogDebug("No result object given - no result to handle"); + } + } + + #endregion + + /// + /// Gets the name of the handler method. + /// + /// The original message. + /// The extracted message. + /// The name of the handler method. + protected virtual string GetHandlerMethodName(Message originalMessage, object extractedMessage) + { + return DefaultHandlerMethod; + } + + /// + /// Builds an array of arguments to be passed into the taret listener method. + /// + /// + /// Allows for multiple method arguments to be built from a single message object. + ///

The default implementation builds an array with the given message object + /// as sole element. This means that the extracted message will always be passed + /// into a single method argument, even if it is an array, with the target + /// method having a corresponding single argument of the array's type declared.

+ ///

This can be overridden to treat special message content such as arrays + /// differently, for example passing in each element of the message array + /// as distinct method argument.

+ ///
+ /// The converted message. + /// the array of arguments to be passed into the + /// listener method (each element of the array corresponding + /// to a distinct method argument) + protected virtual object[] BuildListenerArguments(object convertedMessage) + { + return new object[] { convertedMessage }; + } + + /// + /// Invokes the specified listener method. This default implementation can only handle invoking a + /// single argument method. + /// + /// Name of the listener method. + /// The arguments to be passed in. Only the first argument in the list is currently + /// supported in this implementation. + /// The result returned from the listener method + protected virtual object InvokeListenerMethod(string methodName, object[] arguments) + { + IDictionary vars = new Dictionary(); + vars["convertedObject"] = arguments[0]; + if (methodName.CompareTo(DefaultHandlerMethod) != 0) + { + //This is just to handle the case of overriding GetHandlerMethodName in a subclass and nothing else. + return ExpressionEvaluator.GetValue(handlerObject, methodName + "(#convertedObject)", vars); + } + + // the normal case of using the cached expression. + return processingExpression.GetValue(handlerObject, vars); + } + + /// + /// Initialize the default implementations for the adapter's strategies. + /// + protected virtual void InitDefaultStrategies() + { + ProcessingExpression = Expression.Parse(defaultHandlerMethod + "(#convertedObject)"); + } + + /// + /// Extracts the message body from the given message. + /// + /// The message. + /// the content of the message, to be passed into the + /// listener method as argument + protected virtual object ExtractMessage(Message message) + { + IMessageConverter converter = MessageConverter; + if (converter != null) + { + return converter.FromMessage(message); + } + + return message; + } + + /// + /// Handles the result of a listener method. + /// + /// The result that was returned from listener. + /// The original request. + protected virtual void HandleResult(object result, Message request) + { + if (logger.IsEnabled(LogLevel.Debug)) + { + logger.LogDebug("Listener method returned result [" + result + + "] - generating response message for it"); + } + + Message response = BuildMessage(result); + PostProcessResponse(request, response); + MessageQueue destination = GetResponseDestination(request, response); + SendResponse(destination, response); + } + + /// + /// Sends the given response message to the given destination. + /// + /// The destination to send to. + /// The outgoing message about to be sent. + protected virtual void SendResponse(MessageQueue destination, Message response) + { + //Will send with appropriate transaction semantics + if (logger.IsEnabled(LogLevel.Debug)) + { + logger.LogDebug("Sending response message to path = [" + destination.Path + "]"); + } + + messageQueueTemplate.Send(destination, response); + } + + /// + /// Builds a MSMQ message to be sent as response based on the given result object. + /// + /// The result. + /// the MSMQ Message (never null) + /// If no messgae converter is specified. + protected virtual Message BuildMessage(object result) + { + IMessageConverter converter = MessageConverter; + if (converter != null) + { + // This is the default Message converter registered in QueueUtils.RegisterDefaultMessageConverter + // and used by MessageQueueTemplate and the MessageListenerAdapter if no other Message converage is + // set via the property MessageConverteryObjectName. + if (messageConverterObjectName.Equals("__XmlMessageConverter__")) + { + return converter.ToMessage(result.ToString()); + } + else + { + return converter.ToMessage(result); + } + } + else + { + Message msg = result as Message; + if (msg == null) + { + throw new MessagingException("No MessageConverter specified - cannot handle message [" + result + + "]"); + } + + return msg; + } + } + + /// + /// Post-process the given response message before it will be sent. The default implementation + /// sets the response's correlation id to the request message's correlation id. + /// + /// The original incoming message. + /// The outgoing MSMQ message about to be sent. + protected virtual void PostProcessResponse(Message request, Message response) + { + response.CorrelationId = request.CorrelationId; + } + + /// + /// Determine a response destination for the given message. + /// + /// + /// The default implementation first checks the MSMQ ResponseQueue + /// of the supplied request; if that is not null + /// it is returned; if it is null, then the configured + /// default response destination} + /// is returned; if this too is null, then an + /// is thrown. + /// + /// + /// The request. + /// The response. + /// + protected virtual MessageQueue GetResponseDestination(Message request, Message response) + { + MessageQueue replyTo = request.ResponseQueue; + if (replyTo == null) + { + replyTo = DefaultResponseQueue; + if (replyTo == null) + { + throw new MessagingException("Cannot determine response destination: " + + "Request message does not contain ResponseQueue destination, and no default response queue set."); + } + } + + return replyTo; } } diff --git a/src/Spring/Spring.Messaging/Messaging/Listener/NonTransactionalMessageListenerContainer.cs b/src/Spring/Spring.Messaging/Messaging/Listener/NonTransactionalMessageListenerContainer.cs index dbf069b6..84b1958b 100644 --- a/src/Spring/Spring.Messaging/Messaging/Listener/NonTransactionalMessageListenerContainer.cs +++ b/src/Spring/Spring.Messaging/Messaging/Listener/NonTransactionalMessageListenerContainer.cs @@ -18,7 +18,6 @@ #endregion - #if NETSTANDARD using Experimental.System.Messaging; #else @@ -26,154 +25,154 @@ using System.Messaging; #endif using Microsoft.Extensions.Logging; -namespace Spring.Messaging.Listener +namespace Spring.Messaging.Listener; + +/// +/// An implementation of a Peeking based MessageListener container that does not surround the +/// receive operation with a transaction. +/// +/// +/// Exceptions that occur during message processing are handled by an instance +/// of . +/// +/// Mark Pollack +public class NonTransactionalMessageListenerContainer : AbstractPeekingMessageListenerContainer { + #region Logging Definition + + private static readonly ILogger LOG = LogManager.GetLogger(typeof(NonTransactionalMessageListenerContainer)); + + #endregion + + private IExceptionHandler exceptionHandler; + /// - /// An implementation of a Peeking based MessageListener container that does not surround the - /// receive operation with a transaction. + /// Gets or sets the exception handler. /// - /// - /// Exceptions that occur during message processing are handled by an instance - /// of . - /// - /// Mark Pollack - public class NonTransactionalMessageListenerContainer : AbstractPeekingMessageListenerContainer + /// The exception handler. + public IExceptionHandler ExceptionHandler { - #region Logging Definition + get { return exceptionHandler; } + set { exceptionHandler = value; } + } - private static readonly ILogger LOG = LogManager.GetLogger(typeof (NonTransactionalMessageListenerContainer)); - - #endregion - - private IExceptionHandler exceptionHandler; - - - /// - /// Gets or sets the exception handler. - /// - /// The exception handler. - public IExceptionHandler ExceptionHandler + /// + /// Handles the listener exception. + /// + /// The exception. + /// The message delivered that resultd in an processing exception. + protected virtual void HandleListenerException(Exception e, Message message) + { + IExceptionHandler exceptionHandler = ExceptionHandler; + if (exceptionHandler != null) { - get { return exceptionHandler; } - set { exceptionHandler = value; } + exceptionHandler.OnException(e, message); } + } - - /// - /// Handles the listener exception. - /// - /// The exception. - /// The message delivered that resultd in an processing exception. - protected virtual void HandleListenerException(Exception e, Message message) + /// + /// Perform a receive opertion on the message queue and execute the + /// message listener + /// + /// The MessageQueue. + /// + /// true if received a message, false otherwise + /// + protected override bool DoReceiveAndExecute(MessageQueue mq) + { + Message message = null; + try { - IExceptionHandler exceptionHandler = ExceptionHandler; - if (exceptionHandler != null) + #region Logging + + if (LOG.IsEnabled(LogLevel.Trace)) { - exceptionHandler.OnException(e, message); + LOG.LogTrace("Receiving message with zero timeout for queue = [" + mq.Path + "]"); } - } - /// - /// Perform a receive opertion on the message queue and execute the - /// message listener - /// - /// The MessageQueue. - /// - /// true if received a message, false otherwise - /// - protected override bool DoReceiveAndExecute(MessageQueue mq) + #endregion + + BeforeMessageReceived(mq); + message = mq.Receive(TimeSpan.Zero); + } + catch (MessageQueueException ex) { - Message message = null; - try + if (ex.MessageQueueErrorCode == MessageQueueErrorCode.IOTimeout) { + //expected to occur occasionally + #region Logging if (LOG.IsEnabled(LogLevel.Trace)) { - LOG.LogTrace("Receiving message with zero timeout for queue = [" + mq.Path + "]"); - } - - #endregion - BeforeMessageReceived(mq); - message = mq.Receive(TimeSpan.Zero); - } - catch (MessageQueueException ex) - { - if (ex.MessageQueueErrorCode == MessageQueueErrorCode.IOTimeout) - { - //expected to occur occasionally - - #region Logging - - if (LOG.IsEnabled(LogLevel.Trace)) - { - LOG.LogTrace("MessageQueueErrorCode.IOTimeout: No message available to receive. May have been processed by another thread."); - } - - #endregion - - return false; // no more peeking unless this is the last listener thread - } - else - { - // A real issue in receiving the message - - #region Logging - - if (LOG.IsEnabled(LogLevel.Error)) - { - LOG.LogError("Error receiving message from MessageQueue [" + mq.Path + - "], closing queue and clearing connection cache."); - } - - #endregion - - lock (messageQueueMonitor) - { - mq.Close(); - MessageQueue.ClearConnectionCache(); - } - throw; // will log exception. - } - } - - if (message == null) - { - #region Logging - - if (LOG.IsEnabled(LogLevel.Trace)) - { - LOG.LogTrace("Message recieved is null from Queue = [" + mq.Path + "]"); + LOG.LogTrace("MessageQueueErrorCode.IOTimeout: No message available to receive. May have been processed by another thread."); } #endregion return false; // no more peeking unless this is the last listener thread } - - try + else { + // A real issue in receiving the message + #region Logging - if (LOG.IsEnabled(LogLevel.Debug)) + if (LOG.IsEnabled(LogLevel.Error)) { - LOG.LogDebug("Received message [" + message.Id + "] on queue [" + mq.Path + "]"); + LOG.LogError("Error receiving message from MessageQueue [" + mq.Path + + "], closing queue and clearing connection cache."); } #endregion - MessageReceived(message); - DoExecuteListener(message); + lock (messageQueueMonitor) + { + mq.Close(); + MessageQueue.ClearConnectionCache(); + } + + throw; // will log exception. } - catch (Exception ex) - { - HandleListenerException(ex, message); - } - finally - { - message.Dispose(); - } - return true; } + + if (message == null) + { + #region Logging + + if (LOG.IsEnabled(LogLevel.Trace)) + { + LOG.LogTrace("Message recieved is null from Queue = [" + mq.Path + "]"); + } + + #endregion + + return false; // no more peeking unless this is the last listener thread + } + + try + { + #region Logging + + if (LOG.IsEnabled(LogLevel.Debug)) + { + LOG.LogDebug("Received message [" + message.Id + "] on queue [" + mq.Path + "]"); + } + + #endregion + + MessageReceived(message); + DoExecuteListener(message); + } + catch (Exception ex) + { + HandleListenerException(ex, message); + } + finally + { + message.Dispose(); + } + + return true; } } diff --git a/src/Spring/Spring.Messaging/Messaging/Listener/SendToQueueDistributedTransactionExceptionHandler.cs b/src/Spring/Spring.Messaging/Messaging/Listener/SendToQueueDistributedTransactionExceptionHandler.cs index 686c559c..f4ba057a 100644 --- a/src/Spring/Spring.Messaging/Messaging/Listener/SendToQueueDistributedTransactionExceptionHandler.cs +++ b/src/Spring/Spring.Messaging/Messaging/Listener/SendToQueueDistributedTransactionExceptionHandler.cs @@ -18,7 +18,6 @@ #endregion - #if NETSTANDARD using Experimental.System.Messaging; #else @@ -26,128 +25,129 @@ using System.Messaging; #endif using Microsoft.Extensions.Logging; -namespace Spring.Messaging.Listener +namespace Spring.Messaging.Listener; + +/// +/// detects poison messages by tracking the Message Id property in memory with a count of how many +/// times an exception has occurred. If that count is greater than the handler's MaxRetry count it +/// will be sent to another queue. The queue to send the message to is specified via the property M +/// essageQueueObjectName. +/// +/// Exception handler when using DistributedTxMessageListenerContainer +public class SendToQueueDistributedTransactionExceptionHandler : AbstractSendToQueueExceptionHandler, + IDistributedTransactionExceptionHandler { + #region Logging Definition + + private static readonly ILogger LOG = LogManager.GetLogger(typeof(SendToQueueDistributedTransactionExceptionHandler)); + + #endregion + + #region IDistributedTransactionExceptionHandler Members + /// - /// detects poison messages by tracking the Message Id property in memory with a count of how many - /// times an exception has occurred. If that count is greater than the handler's MaxRetry count it - /// will be sent to another queue. The queue to send the message to is specified via the property M - /// essageQueueObjectName. + /// Determines whether the incoming message is a poison message. This method is + /// called before the is invoked. /// - /// Exception handler when using DistributedTxMessageListenerContainer - public class SendToQueueDistributedTransactionExceptionHandler : AbstractSendToQueueExceptionHandler, - IDistributedTransactionExceptionHandler + /// The incoming message. + /// + /// true if it is a poison message; otherwise, false. + /// + /// + /// The will call + /// if this method returns true and will + /// then commit the distibuted transaction (removing the message from the queue). + /// + public bool IsPoisonMessage(Message message) { - #region Logging Definition - - private static readonly ILogger LOG = LogManager.GetLogger(typeof (SendToQueueDistributedTransactionExceptionHandler)); - - #endregion - - #region IDistributedTransactionExceptionHandler Members - - /// - /// Determines whether the incoming message is a poison message. This method is - /// called before the is invoked. - /// - /// The incoming message. - /// - /// true if it is a poison message; otherwise, false. - /// - /// - /// The will call - /// if this method returns true and will - /// then commit the distibuted transaction (removing the message from the queue). - /// - public bool IsPoisonMessage(Message message) + string messageId = message.Id; + lock (messageMapMonitor) { - string messageId = message.Id; - lock (messageMapMonitor) + MessageStats messageStats = null; + if (messageMap.Contains(messageId)) { - MessageStats messageStats = null; - if (messageMap.Contains(messageId)) + messageStats = (MessageStats) messageMap[messageId]; + if (messageStats.Count > MaxRetry) { - messageStats = (MessageStats) messageMap[messageId]; - if (messageStats.Count > MaxRetry) - { - LOG.LogWarning("Message with id = [" + message.Id + "] detected as poison message."); - return true; - } + LOG.LogWarning("Message with id = [" + message.Id + "] detected as poison message."); + return true; } - return false; } + + return false; } + } - /// - /// Handles the poison message. - /// - /// The message. - public void HandlePoisonMessage(Message message) + /// + /// Handles the poison message. + /// + /// The message. + public void HandlePoisonMessage(Message message) + { + SendMessageToQueue(message); + } + + /// + /// Called when an exception is thrown in listener processing. + /// + /// The exception. + /// The message. + public void OnException(Exception exception, Message message) + { + string messageId = message.Id; + lock (messageMapMonitor) { - SendMessageToQueue(message); + MessageStats messageStats = null; + if (messageMap.Contains(messageId)) + { + messageStats = (MessageStats) messageMap[messageId]; + } + else + { + messageStats = new MessageStats(); + messageMap[messageId] = messageStats; + } + + messageStats.Count++; + LOG.LogWarning("Message Error Count = [" + messageStats.Count + "] for message id = [" + messageId + + "]"); } + } - /// - /// Called when an exception is thrown in listener processing. - /// - /// The exception. - /// The message. - public void OnException(Exception exception, Message message) + #endregion + + /// + /// Sends the message to queue. + /// + /// The message. + protected virtual void SendMessageToQueue(Message message) + { + MessageQueue mq = MessageQueueFactory.CreateMessageQueue(MessageQueueObjectName); + try { - string messageId = message.Id; - lock (messageMapMonitor) + #region Logging + + if (LOG.IsEnabled(LogLevel.Information)) { - MessageStats messageStats = null; - if (messageMap.Contains(messageId)) - { - messageStats = (MessageStats) messageMap[messageId]; - } - else - { - messageStats = new MessageStats(); - messageMap[messageId] = messageStats; - } - messageStats.Count++; - LOG.LogWarning("Message Error Count = [" + messageStats.Count + "] for message id = [" + messageId + - "]"); + LOG.LogInformation("Sending message with id = [" + message.Id + "] to queue [" + mq.Path + "]."); } + + #endregion + + mq.Send(message, MessageQueueTransactionType.Automatic); } - - #endregion - - /// - /// Sends the message to queue. - /// - /// The message. - protected virtual void SendMessageToQueue(Message message) + catch (Exception e) { - MessageQueue mq = MessageQueueFactory.CreateMessageQueue(MessageQueueObjectName); - try + #region Logging + + if (LOG.IsEnabled(LogLevel.Error)) { - #region Logging - - if (LOG.IsEnabled(LogLevel.Information)) - { - LOG.LogInformation("Sending message with id = [" + message.Id + "] to queue [" + mq.Path + "]."); - } - - #endregion - - mq.Send(message, MessageQueueTransactionType.Automatic); + string message1 = "Could not send message with id = [" + message.Id + "] to queue [" + mq.Path + "]."; + LOG.LogError(e, message1); + LOG.LogError("Message will not be processed. Message Body = " + message.Body); } - catch (Exception e) - { - #region Logging - if (LOG.IsEnabled(LogLevel.Error)) - { - string message1 = "Could not send message with id = [" + message.Id + "] to queue [" + mq.Path + "]."; - LOG.LogError(e, message1); - LOG.LogError("Message will not be processed. Message Body = " + message.Body); - } - - #endregion - } + #endregion } } } diff --git a/src/Spring/Spring.Messaging/Messaging/Listener/SendToQueueExceptionHandler.cs b/src/Spring/Spring.Messaging/Messaging/Listener/SendToQueueExceptionHandler.cs index 6dbea674..aecabb58 100644 --- a/src/Spring/Spring.Messaging/Messaging/Listener/SendToQueueExceptionHandler.cs +++ b/src/Spring/Spring.Messaging/Messaging/Listener/SendToQueueExceptionHandler.cs @@ -18,7 +18,6 @@ #endregion - #if NETSTANDARD using Experimental.System.Messaging; #else @@ -26,191 +25,192 @@ using System.Messaging; #endif using Microsoft.Extensions.Logging; -namespace Spring.Messaging.Listener +namespace Spring.Messaging.Listener; + +/// +/// Keeps track of the Message's Id property in memory with a count of how many times an +/// exception has occurred. If that count is greater than the handler's MaxRetry count it +/// will be sent to another queue using the provided MessageQueueTransaction. The queue to +/// send the message to is specified via the property MessageQueueObjectName. +/// +public class SendToQueueExceptionHandler : AbstractSendToQueueExceptionHandler, IMessageTransactionExceptionHandler { + #region Logging Definition + + private static readonly ILogger LOG = LogManager.GetLogger(typeof(SendToQueueExceptionHandler)); + + #endregion + + #region Fields + + private string[] messageAlreadyProcessedExceptionNames; + + #endregion + + #region Properties + /// - /// Keeps track of the Message's Id property in memory with a count of how many times an - /// exception has occurred. If that count is greater than the handler's MaxRetry count it - /// will be sent to another queue using the provided MessageQueueTransaction. The queue to - /// send the message to is specified via the property MessageQueueObjectName. + /// Gets or sets the exception anmes that indicate the message has already + /// been processed. If the exception thrown matches one of these names then + /// the returned TransactionAction is Commit to remove it from the queue. /// - public class SendToQueueExceptionHandler : AbstractSendToQueueExceptionHandler, IMessageTransactionExceptionHandler + /// The name test is thrownException.GetType().Name.IndexOf(exceptionName) >= 0 + /// The message already processed exception types. + public string[] MessageAlreadyProcessedExceptionNames { - #region Logging Definition + set { messageAlreadyProcessedExceptionNames = value; } + get { return messageAlreadyProcessedExceptionNames; } + } - private static readonly ILogger LOG = LogManager.GetLogger(typeof (SendToQueueExceptionHandler)); + #endregion - #endregion + #region IMessageTransactionExceptionHandler Members - #region Fields - - private string[] messageAlreadyProcessedExceptionNames; - - #endregion - - #region Properties - - /// - /// Gets or sets the exception anmes that indicate the message has already - /// been processed. If the exception thrown matches one of these names then - /// the returned TransactionAction is Commit to remove it from the queue. - /// - /// The name test is thrownException.GetType().Name.IndexOf(exceptionName) >= 0 - /// The message already processed exception types. - public string[] MessageAlreadyProcessedExceptionNames + /// + /// Called when an exception is thrown during listener processing under the + /// scope of a . + /// + /// The exception. + /// The message. + /// The message queue transaction. + /// + /// An action indicating if the caller should commit or rollback the + /// + /// + public TransactionAction OnException(Exception exception, Message message, + MessageQueueTransaction messageQueueTransaction) + { + if (IsMessageAlreadyProcessedException(exception)) { - set { messageAlreadyProcessedExceptionNames = value; } - get { return messageAlreadyProcessedExceptionNames; } - } - - #endregion - - #region IMessageTransactionExceptionHandler Members - - /// - /// Called when an exception is thrown during listener processing under the - /// scope of a . - /// - /// The exception. - /// The message. - /// The message queue transaction. - /// - /// An action indicating if the caller should commit or rollback the - /// - /// - public TransactionAction OnException(Exception exception, Message message, - MessageQueueTransaction messageQueueTransaction) - { - if (IsMessageAlreadyProcessedException(exception)) - { - return TransactionAction.Commit; - } - - string messageId = message.Id; - lock (messageMapMonitor) - { - MessageStats messageStats = null; - if (messageMap.Contains(messageId)) - { - messageStats = (MessageStats) messageMap[messageId]; - } - else - { - messageStats = new MessageStats(); - messageMap[messageId] = messageStats; - } - messageStats.Count++; - LOG.LogWarning("Message Error Count = [" + messageStats.Count + "] for message id = [" + messageId + "]"); - - if (messageStats.Count > MaxRetry) - { - LOG.LogInformation("Maximum number of redelivery attempts exceeded for message id = [" + messageId + "]"); - messageMap.Remove(messageId); - return SendMessageToQueue(message, messageQueueTransaction); - } - else - { - LOG.LogWarning("Rolling back delivery of message id [" + messageId + "]"); - return TransactionAction.Rollback; - } - } - } - - #endregion - - #region Protected Methods - - /// - /// Determines whether this exception was already processed. - /// - /// The exception. - /// - /// true if the exception was already processed; otherwise, false. - /// - protected virtual bool IsMessageAlreadyProcessedException(Exception exception) - { - if (MessageAlreadyProcessedExceptionNames != null) - { - foreach (string exceptionName in MessageAlreadyProcessedExceptionNames) - { - if (exception.GetType().Name.IndexOf(exceptionName) >= 0) - { - return true; - } - } - } - return false; - } - - /// - /// Sends the message to queue. - /// - /// The message. - /// The message queue transaction. - /// TransactionAction.Commit - protected virtual TransactionAction SendMessageToQueue(Message message, - MessageQueueTransaction messageQueueTransaction) - { - MessageQueue mq = MessageQueueFactory.CreateMessageQueue(MessageQueueObjectName); - try - { - #region Logging - - if (LOG.IsEnabled(LogLevel.Information)) - { - LOG.LogInformation("Sending message with id = [" + message.Id + "] to queue [" + mq.Path + "]."); - } - - #endregion - - ProcessExceptionalMessage(message); - mq.Send(message, messageQueueTransaction); - } - catch (Exception e) - { - #region Logging - - if (LOG.IsEnabled(LogLevel.Error)) - { - string message1 = "Could not send message with id = [" + message.Id + "] to queue [" + mq.Path + "]."; - LOG.LogError(e, message1); - LOG.LogError("Message will not be processed. Message Body = " + message.Body); - } - - #endregion - } return TransactionAction.Commit; } - /// - /// Template method called before the message that caused the exception is - /// send to another queue. The default behavior is to set the CorrelationId - /// to the current message's Id value for tracking purposes. Subclasses - /// can use other means, perhaps using the AppSpecific field or modifying the - /// body of the message to a known shared format that keeps track of - /// the full 'lifecycle' of the message as it goes from queue-to-queue. - /// - /// The message. - protected virtual void ProcessExceptionalMessage(Message message) + string messageId = message.Id; + lock (messageMapMonitor) { - if (message.CorrelationId == null) + MessageStats messageStats = null; + if (messageMap.Contains(messageId)) { - message.CorrelationId = message.Id; + messageStats = (MessageStats) messageMap[messageId]; + } + else + { + messageStats = new MessageStats(); + messageMap[messageId] = messageStats; + } + + messageStats.Count++; + LOG.LogWarning("Message Error Count = [" + messageStats.Count + "] for message id = [" + messageId + "]"); + + if (messageStats.Count > MaxRetry) + { + LOG.LogInformation("Maximum number of redelivery attempts exceeded for message id = [" + messageId + "]"); + messageMap.Remove(messageId); + return SendMessageToQueue(message, messageQueueTransaction); + } + else + { + LOG.LogWarning("Rolling back delivery of message id [" + messageId + "]"); + return TransactionAction.Rollback; + } + } + } + + #endregion + + #region Protected Methods + + /// + /// Determines whether this exception was already processed. + /// + /// The exception. + /// + /// true if the exception was already processed; otherwise, false. + /// + protected virtual bool IsMessageAlreadyProcessedException(Exception exception) + { + if (MessageAlreadyProcessedExceptionNames != null) + { + foreach (string exceptionName in MessageAlreadyProcessedExceptionNames) + { + if (exception.GetType().Name.IndexOf(exceptionName) >= 0) + { + return true; + } } } - #endregion + return false; } - - internal class MessageStats + /// + /// Sends the message to queue. + /// + /// The message. + /// The message queue transaction. + /// TransactionAction.Commit + protected virtual TransactionAction SendMessageToQueue(Message message, + MessageQueueTransaction messageQueueTransaction) { - private int count; - - public int Count + MessageQueue mq = MessageQueueFactory.CreateMessageQueue(MessageQueueObjectName); + try { - get { return count; } - set { count = value; } + #region Logging + + if (LOG.IsEnabled(LogLevel.Information)) + { + LOG.LogInformation("Sending message with id = [" + message.Id + "] to queue [" + mq.Path + "]."); + } + + #endregion + + ProcessExceptionalMessage(message); + mq.Send(message, messageQueueTransaction); + } + catch (Exception e) + { + #region Logging + + if (LOG.IsEnabled(LogLevel.Error)) + { + string message1 = "Could not send message with id = [" + message.Id + "] to queue [" + mq.Path + "]."; + LOG.LogError(e, message1); + LOG.LogError("Message will not be processed. Message Body = " + message.Body); + } + + #endregion + } + + return TransactionAction.Commit; + } + + /// + /// Template method called before the message that caused the exception is + /// send to another queue. The default behavior is to set the CorrelationId + /// to the current message's Id value for tracking purposes. Subclasses + /// can use other means, perhaps using the AppSpecific field or modifying the + /// body of the message to a known shared format that keeps track of + /// the full 'lifecycle' of the message as it goes from queue-to-queue. + /// + /// The message. + protected virtual void ProcessExceptionalMessage(Message message) + { + if (message.CorrelationId == null) + { + message.CorrelationId = message.Id; } } + + #endregion +} + +internal class MessageStats +{ + private int count; + + public int Count + { + get { return count; } + set { count = value; } + } } diff --git a/src/Spring/Spring.Messaging/Messaging/Listener/TransactionAction.cs b/src/Spring/Spring.Messaging/Messaging/Listener/TransactionAction.cs index 4b326fe6..35a582de 100644 --- a/src/Spring/Spring.Messaging/Messaging/Listener/TransactionAction.cs +++ b/src/Spring/Spring.Messaging/Messaging/Listener/TransactionAction.cs @@ -18,21 +18,20 @@ #endregion +namespace Spring.Messaging.Listener; -namespace Spring.Messaging.Listener +/// +/// Action to perform on the MessageQueueTransaction when handling message listener exceptions. +/// +public enum TransactionAction { /// - /// Action to perform on the MessageQueueTransaction when handling message listener exceptions. + /// Rollback the MessageQueueTransaction, returning the recieved message back onto the queue. /// - public enum TransactionAction - { - /// - /// Rollback the MessageQueueTransaction, returning the recieved message back onto the queue. - /// - Rollback, - /// - /// Commit the MessageQueueTransaction, removing the message from the queue. - /// - Commit - } ; -} \ No newline at end of file + Rollback, + + /// + /// Commit the MessageQueueTransaction, removing the message from the queue. + /// + Commit +}; diff --git a/src/Spring/Spring.Messaging/Messaging/Listener/TransactionalMessageListenerContainer.cs b/src/Spring/Spring.Messaging/Messaging/Listener/TransactionalMessageListenerContainer.cs index 4e239e2f..1b918180 100644 --- a/src/Spring/Spring.Messaging/Messaging/Listener/TransactionalMessageListenerContainer.cs +++ b/src/Spring/Spring.Messaging/Messaging/Listener/TransactionalMessageListenerContainer.cs @@ -26,299 +26,466 @@ using Spring.Transaction.Support; #if NETSTANDARD using Experimental.System.Messaging; + #else using System.Messaging; #endif -namespace Spring.Messaging.Listener +namespace Spring.Messaging.Listener; + +/// +/// A MessageListenerContainer that uses local (non-DTC) based transactions. Exceptions are +/// handled by instances of . +/// +/// +/// +/// This container distinguishes between two types of +/// implementations. +/// +/// If you specify a then +/// a MSMQ will be started +/// before receiving the message and used as part of the container's recieve operation. The +/// binds the +/// to thread local storage and as such will implicitly be used by +/// send and receive operations to a transactional queue. +/// +/// +/// Service layer operations that are called inside the message listener will typically +/// be transactional based on using standard Spring declarative transaction management +/// functionality. In case of exceptions in the service layer, the database operation +/// will have been rolled back and the +/// that is later invoked should decide to either commit the surrounding local +/// MSMQ based transaction (removing the message from the queue) or to rollback +/// (placing the message back on the queue for redelivery). +/// +/// +/// The use of a transactional service layer in combination with +/// a container managed is a powerful combination +/// that can be used to achieve "exactly one" transaction message processing with +/// database operations that are commonly associated with using transactional messaging and +/// distributed transactions (i.e. both the messaging and database operation commit or rollback +/// together). +/// +/// +/// The additional programming logic needed to achieve this is to keep track of the Message.Id +/// that has been processed successfully within the transactional service layer. +/// This is needed as there may be a system failure (e.g. power goes off) +/// between the 'inner' database commit and the 'outer' messaging commit, resulting +/// in message redelivery. The transactional service layer needs logic to detect if incoming +/// message was processed successfully. It can do this by checking the database for an +/// indication of successfull processing, perhaps by recording the Message.Id itself in a +/// status table. If the transactional service layer determines that the message has +/// already been processed, it can throw a specific exception for thise case. The +/// container's exception handler will recognize this exception type and vote to commit +/// (remove from the queue) the 'outer' messaging transaction. +/// Spring provides an exception handler with this functionality, +/// see for more information. +/// +/// If you specify an implementation of +/// (e.g. or HibernateTransactionManager) then +/// an local database transaction will be started before receiving the message. By default, +/// the container will also start a local +/// after the local database transaction has started, but before the receiving the message. +/// The will be used to receive the message. +/// If you do not want his behavior set +/// to false. Also by default, the +/// will be bound to thread local storage such that any +/// send or recieve operations will participate transparently in the same +/// . If you do not want this behavior +/// set the property to false. +/// +/// In case of exceptions during processing +/// when using an implementation of +/// (e.g. and starting a container managed +/// ) the container's +/// will determine if the +/// should commit (removing it from the queue) +/// or rollback (placing it back on the queue for redelivery). The listener +/// exception will always +/// trigger a rollback in the 'outer' (e.g. +/// or HibernateTransactionManager) based transaction. +/// +/// +/// PoisonMessage handing, that is endless redelivery of a message due to exceptions +/// during processing, can be detected using implementatons of the +/// interface. A specific implementation +/// is provided that will move the poison message to another queue after a maximum number +/// of redelivery attempts. See for more information. +/// +/// +public class TransactionalMessageListenerContainer : AbstractTransactionalMessageListenerContainer { + #region Logging Definition + + private static readonly ILogger LOG = LogManager.GetLogger(typeof(TransactionalMessageListenerContainer)); + + #endregion + + #region Fields + + private bool useContainerManagedMessageQueueTransaction = false; + + private bool useMessageQueueTransactionManagerCalled = false; + + private bool exposeContainerManagedMessageQueueTransaction = true; + + private IMessageTransactionExceptionHandler messageTransactionExceptionHandler; + + #endregion + + #region Properties + /// - /// A MessageListenerContainer that uses local (non-DTC) based transactions. Exceptions are - /// handled by instances of . + /// Gets or sets a value indicating whether the MessageListenerContainer should be + /// responsible for creating a MessageQueueTransaction + /// when receiving a message. /// /// /// - /// This container distinguishes between two types of - /// implementations. - /// - /// If you specify a then - /// a MSMQ will be started - /// before receiving the message and used as part of the container's recieve operation. The - /// binds the - /// to thread local storage and as such will implicitly be used by - /// send and receive operations to a transactional queue. + /// Creating MessageQueueTransactions is usually the responsibility of the + /// IPlatformTransactionManager, e.g. TxScopePlatformTransactionManager (when using DTC) + /// or MessageQueueTransactionManager (when using local messaging transactions). /// /// - /// Service layer operations that are called inside the message listener will typically - /// be transactional based on using standard Spring declarative transaction management - /// functionality. In case of exceptions in the service layer, the database operation - /// will have been rolled back and the - /// that is later invoked should decide to either commit the surrounding local - /// MSMQ based transaction (removing the message from the queue) or to rollback - /// (placing the message back on the queue for redelivery). + /// For all other IPlatformTransactionManager implementations, including when none is + /// specified, the MessageListenerContainer will itself create a MessageQueueTransaction + /// (assuming the container is consuming from a transactional queue). /// /// - /// The use of a transactional service layer in combination with - /// a container managed is a powerful combination - /// that can be used to achieve "exactly one" transaction message processing with - /// database operations that are commonly associated with using transactional messaging and - /// distributed transactions (i.e. both the messaging and database operation commit or rollback - /// together). - /// - /// - /// The additional programming logic needed to achieve this is to keep track of the Message.Id - /// that has been processed successfully within the transactional service layer. - /// This is needed as there may be a system failure (e.g. power goes off) - /// between the 'inner' database commit and the 'outer' messaging commit, resulting - /// in message redelivery. The transactional service layer needs logic to detect if incoming - /// message was processed successfully. It can do this by checking the database for an - /// indication of successfull processing, perhaps by recording the Message.Id itself in a - /// status table. If the transactional service layer determines that the message has - /// already been processed, it can throw a specific exception for thise case. The - /// container's exception handler will recognize this exception type and vote to commit - /// (remove from the queue) the 'outer' messaging transaction. - /// Spring provides an exception handler with this functionality, - /// see for more information. - /// - /// If you specify an implementation of - /// (e.g. or HibernateTransactionManager) then - /// an local database transaction will be started before receiving the message. By default, - /// the container will also start a local - /// after the local database transaction has started, but before the receiving the message. - /// The will be used to receive the message. - /// If you do not want his behavior set - /// to false. Also by default, the - /// will be bound to thread local storage such that any - /// send or recieve operations will participate transparently in the same - /// . If you do not want this behavior - /// set the property to false. - /// - /// In case of exceptions during processing - /// when using an implementation of - /// (e.g. and starting a container managed - /// ) the container's - /// will determine if the - /// should commit (removing it from the queue) - /// or rollback (placing it back on the queue for redelivery). The listener - /// exception will always - /// trigger a rollback in the 'outer' (e.g. - /// or HibernateTransactionManager) based transaction. - /// - /// - /// PoisonMessage handing, that is endless redelivery of a message due to exceptions - /// during processing, can be detected using implementatons of the - /// interface. A specific implementation - /// is provided that will move the poison message to another queue after a maximum number - /// of redelivery attempts. See for more information. + /// Set the ExposeContainerManagedMessageQueueTransaction property to true if you want + /// the MessageQueueTransaction to be exposed to Spring's MessageQueueTemplate class /// /// - public class TransactionalMessageListenerContainer : AbstractTransactionalMessageListenerContainer + /// + /// true to use a container managed MessageQueueTransaction; otherwise, false. + /// + public bool UseContainerManagedMessageQueueTransaction { - #region Logging Definition - - private static readonly ILogger LOG = LogManager.GetLogger(typeof (TransactionalMessageListenerContainer)); - - #endregion - - #region Fields - - private bool useContainerManagedMessageQueueTransaction = false; - - private bool useMessageQueueTransactionManagerCalled = false; - - private bool exposeContainerManagedMessageQueueTransaction = true; - - private IMessageTransactionExceptionHandler messageTransactionExceptionHandler; - - #endregion - - #region Properties - - /// - /// Gets or sets a value indicating whether the MessageListenerContainer should be - /// responsible for creating a MessageQueueTransaction - /// when receiving a message. - /// - /// - /// - /// Creating MessageQueueTransactions is usually the responsibility of the - /// IPlatformTransactionManager, e.g. TxScopePlatformTransactionManager (when using DTC) - /// or MessageQueueTransactionManager (when using local messaging transactions). - /// - /// - /// For all other IPlatformTransactionManager implementations, including when none is - /// specified, the MessageListenerContainer will itself create a MessageQueueTransaction - /// (assuming the container is consuming from a transactional queue). - /// - /// - /// Set the ExposeContainerManagedMessageQueueTransaction property to true if you want - /// the MessageQueueTransaction to be exposed to Spring's MessageQueueTemplate class - /// - /// - /// - /// true to use a container managed MessageQueueTransaction; otherwise, false. - /// - public bool UseContainerManagedMessageQueueTransaction + get { return useContainerManagedMessageQueueTransaction; } + set { - get { return useContainerManagedMessageQueueTransaction; } - set + useContainerManagedMessageQueueTransaction = value; + useMessageQueueTransactionManagerCalled = true; + } + } + + /// + /// Gets or sets a value indicating whether expose the + /// container managed to thread local storage + /// where it will be automatically used by send + /// and receive operations. + /// + /// + /// Using an will always exposes a + /// to thread local storage. This property + /// only has effect when using a non-DTC based + /// + /// + /// true if [expose container managed message queue transaction]; otherwise, false. + /// + public bool ExposeContainerManagedMessageQueueTransaction + { + get { return exposeContainerManagedMessageQueueTransaction; } + set { exposeContainerManagedMessageQueueTransaction = value; } + } + + /// + /// Gets or sets the message transaction exception handler. + /// + /// The message transaction exception handler. + public IMessageTransactionExceptionHandler MessageTransactionExceptionHandler + { + get { return messageTransactionExceptionHandler; } + set { messageTransactionExceptionHandler = value; } + } + + #endregion + + #region Public Methods + + /// + /// Determine if the container should create its own + /// MessageQueueTransaction when a IResourceTransactionManager is specified. + /// Set the transaction name to the name of the spring object. + /// Call base class Initialize() funtionality + /// + public override void Initialize() + { + //using non-DTC based transaction manager? + bool isRtm = PlatformTransactionManager is IResourceTransactionManager; + //using MessageQueueTransactionManager? + bool isQtm = PlatformTransactionManager is MessageQueueTransactionManager; + + if (!isRtm && !isQtm) + { + throw new ArgumentException("Can not use the provied IPlatformTransactionManager of type " + + PlatformTransactionManager.GetType() + + ". It must implement IResourceTransactionManager or be a MessageQueueTransactionManager."); + } + + //Set useContainerManagedMessageQueueTransaction = true when using + // 1. non-DTC based transaction manager + // 2. not the MessageQueueTransactionManager. + if (!useMessageQueueTransactionManagerCalled && isRtm && !isQtm) + { + useContainerManagedMessageQueueTransaction = true; + } + + // Use object name as default transaction name. + if (TransactionDefinition.Name == null) + { + TransactionDefinition.Name = ObjectName; + } + + // Proceed with superclass initialization. + base.Initialize(); + } + + #endregion + + #region Protected Methods + + /// + /// Does the receive and execute using platform transaction manager. + /// + /// The message queue. + /// The transactional status. + /// + /// true if should continue peeking, false otherwise. + /// + protected override bool DoReceiveAndExecuteUsingPlatformTransactionManager(MessageQueue mq, + ITransactionStatus status) + { + if (PlatformTransactionManager is MessageQueueTransactionManager) + { + return DoRecieveAndExecuteUsingMessageQueueTransactionManager(mq, status); + } + else if (PlatformTransactionManager is IResourceTransactionManager) + { + if (UseContainerManagedMessageQueueTransaction) { - useContainerManagedMessageQueueTransaction = value; - useMessageQueueTransactionManagerCalled = true; + return DoRecieveAndExecuteUsingResourceTransactionManagerWithTxQueue(mq, status); + } + else + { + //recieve non-transactionally from transactional queue but + //use ResourceBasedTransactionManagement. + DoRecieveAndExecuteUsingResourceTransactionManager(); } } - /// - /// Gets or sets a value indicating whether expose the - /// container managed to thread local storage - /// where it will be automatically used by send - /// and receive operations. - /// - /// - /// Using an will always exposes a - /// to thread local storage. This property - /// only has effect when using a non-DTC based - /// - /// - /// true if [expose container managed message queue transaction]; otherwise, false. - /// - public bool ExposeContainerManagedMessageQueueTransaction + return false; + } + + private void DoRecieveAndExecuteUsingResourceTransactionManager() + { + //This is a bit of an odd case since really one is better off using + //NonTransactionalMessageListenerContainer and having the database + //transaction done in the service tier. + + throw new NotSupportedException("Try using NonTransactionalMessageListenerContainer instead."); + } + + /// + /// Does the recieve and execute using message queue transaction manager. + /// + /// The message queue. + /// The transactional status. + /// true if should continue peeking, false otherise + protected virtual bool DoRecieveAndExecuteUsingMessageQueueTransactionManager(MessageQueue mq, + ITransactionStatus status) + { + #region Logging + + if (LOG.IsEnabled(LogLevel.Debug)) { - get { return exposeContainerManagedMessageQueueTransaction; } - set { exposeContainerManagedMessageQueueTransaction = value; } + LOG.LogDebug("Executing DoRecieveAndExecuteUsingMessageQueueTransactionManager"); } - /// - /// Gets or sets the message transaction exception handler. - /// - /// The message transaction exception handler. - public IMessageTransactionExceptionHandler MessageTransactionExceptionHandler + #endregion Logging + + Message message; + + #region Receive message + + try { - get { return messageTransactionExceptionHandler; } - set { messageTransactionExceptionHandler = value; } + message = mq.Receive(TimeSpan.Zero, QueueUtils.GetMessageQueueTransaction(null)); } - - #endregion - - #region Public Methods - - /// - /// Determine if the container should create its own - /// MessageQueueTransaction when a IResourceTransactionManager is specified. - /// Set the transaction name to the name of the spring object. - /// Call base class Initialize() funtionality - /// - public override void Initialize() + catch (MessageQueueException ex) { - //using non-DTC based transaction manager? - bool isRtm = PlatformTransactionManager is IResourceTransactionManager; - //using MessageQueueTransactionManager? - bool isQtm = PlatformTransactionManager is MessageQueueTransactionManager; - - if (!isRtm && !isQtm) + if (ex.MessageQueueErrorCode == MessageQueueErrorCode.IOTimeout) { - throw new ArgumentException("Can not use the provied IPlatformTransactionManager of type " - + PlatformTransactionManager.GetType() - + ". It must implement IResourceTransactionManager or be a MessageQueueTransactionManager."); - } - - //Set useContainerManagedMessageQueueTransaction = true when using - // 1. non-DTC based transaction manager - // 2. not the MessageQueueTransactionManager. - if (!useMessageQueueTransactionManagerCalled && isRtm && !isQtm) - { - useContainerManagedMessageQueueTransaction = true; - } - - // Use object name as default transaction name. - if (TransactionDefinition.Name == null) - { - TransactionDefinition.Name = ObjectName; - } - - // Proceed with superclass initialization. - base.Initialize(); - } - - #endregion - - #region Protected Methods - - /// - /// Does the receive and execute using platform transaction manager. - /// - /// The message queue. - /// The transactional status. - /// - /// true if should continue peeking, false otherwise. - /// - protected override bool DoReceiveAndExecuteUsingPlatformTransactionManager(MessageQueue mq, - ITransactionStatus status) - { - if (PlatformTransactionManager is MessageQueueTransactionManager) - { - return DoRecieveAndExecuteUsingMessageQueueTransactionManager(mq, status); - } - else if (PlatformTransactionManager is IResourceTransactionManager) - { - if (UseContainerManagedMessageQueueTransaction) + //expected to occur occasionally + if (LOG.IsEnabled(LogLevel.Trace)) { - return DoRecieveAndExecuteUsingResourceTransactionManagerWithTxQueue(mq, status); - } - else - { - //recieve non-transactionally from transactional queue but - //use ResourceBasedTransactionManagement. - DoRecieveAndExecuteUsingResourceTransactionManager(); + LOG.LogTrace("IOTimeout: Message to receive was already processed by another thread."); } + + status.SetRollbackOnly(); + return false; // no more peeking unless this is the last listener thread + } + else + { + // A real issue in receiving the message + + #region Logging + + if (LOG.IsEnabled(LogLevel.Error)) + { + LOG.LogError("Error receiving message from DefaultMessageQueue [" + mq.Path + + "], closing queue and clearing connection cache."); + } + + #endregion + + lock (messageQueueMonitor) + { + mq.Close(); + MessageQueue.ClearConnectionCache(); + } + + throw; // will cause rollback in MessageQueueTransactionManager and log exception } - return false; } - private void DoRecieveAndExecuteUsingResourceTransactionManager() + #endregion + + if (message == null) { - //This is a bit of an odd case since really one is better off using - //NonTransactionalMessageListenerContainer and having the database - //transaction done in the service tier. + #region Logging - throw new NotSupportedException("Try using NonTransactionalMessageListenerContainer instead."); + if (LOG.IsEnabled(LogLevel.Trace)) + { + LOG.LogTrace("Message recieved is null from Queue = [" + mq.Path + "]"); + } + + #endregion + + status.SetRollbackOnly(); + return false; // no more peeking unless this is the last listener thread } - /// - /// Does the recieve and execute using message queue transaction manager. - /// - /// The message queue. - /// The transactional status. - /// true if should continue peeking, false otherise - protected virtual bool DoRecieveAndExecuteUsingMessageQueueTransactionManager(MessageQueue mq, - ITransactionStatus status) + try { #region Logging if (LOG.IsEnabled(LogLevel.Debug)) { - LOG.LogDebug("Executing DoRecieveAndExecuteUsingMessageQueueTransactionManager"); + LOG.LogDebug("Received message [" + message.Id + "] on queue [" + mq.Path + "]"); } - #endregion Logging + #endregion + + MessageReceived(message); + DoExecuteListener(message); + + #region Logging + + if (LOG.IsEnabled(LogLevel.Trace)) + { + LOG.LogTrace("MessageListener executed"); + } + + #endregion + } + catch (Exception ex) + { + //Exception may indicate rollback of database transaction in service layer. + //Let the handler determine if the message should be removed from the queue. + TransactionAction action = + HandleTransactionalListenerException(ex, message, QueueUtils.GetMessageQueueTransaction(null)); + if (action == TransactionAction.Rollback) + { + #region Logging + + if (LOG.IsEnabled(LogLevel.Debug)) + { + LOG.LogDebug("Exception handler's TransactionAction has rolled back MessageQueueTransaction for queue [" + + mq.Path + "]"); + } + + #endregion + + status.SetRollbackOnly(); + return false; // no more peeking unless this is the last listener thread + } + else + { + LOG.LogInformation("Committing MessageQueueTransaction due to explicit commit request by exception handler."); + } + } + finally + { + message.Dispose(); + } + + return true; + } + + /// + /// Does the recieve and execute using a local MessageQueueTransaction. + /// + /// The mqessage queue. + /// The transactional status. + /// true if should continue peeking, false otherwise. + protected virtual bool DoRecieveAndExecuteUsingResourceTransactionManagerWithTxQueue(MessageQueue mq, + ITransactionStatus status) + { + #region Logging + + if (LOG.IsEnabled(LogLevel.Debug)) + { + LOG.LogDebug("Executing DoRecieveAndExecuteUsingResourceTransactionManagerWithTxQueue"); + } + + #endregion Logging + + using (MessageQueueTransaction messageQueueTransaction = new MessageQueueTransaction()) + { + messageQueueTransaction.Begin(); + + #region Logging + + if (LOG.IsEnabled(LogLevel.Trace)) + { + LOG.LogTrace("Started MessageQueueTransaction for queue = [" + mq.Path + "]"); + } + + #endregion Message message; - #region Receive message + #region ReceiveMessage try { - message = mq.Receive(TimeSpan.Zero, QueueUtils.GetMessageQueueTransaction(null)); + #region Logging + + if (LOG.IsEnabled(LogLevel.Trace)) + { + LOG.LogTrace("Receiving message with zero timeout for queue = [" + mq.Path + "]"); + } + + #endregion + + message = mq.Receive(TimeSpan.Zero, messageQueueTransaction); } catch (MessageQueueException ex) { if (ex.MessageQueueErrorCode == MessageQueueErrorCode.IOTimeout) { //expected to occur occasionally + + #region Logging + if (LOG.IsEnabled(LogLevel.Trace)) { - LOG.LogTrace("IOTimeout: Message to receive was already processed by another thread."); + LOG.LogTrace("MessageQueueErrorCode.IOTimeout: No message available to receive. May have been processed by another thread."); } + + #endregion + status.SetRollbackOnly(); return false; // no more peeking unless this is the last listener thread } @@ -341,7 +508,8 @@ namespace Spring.Messaging.Listener mq.Close(); MessageQueue.ClearConnectionCache(); } - throw; // will cause rollback in MessageQueueTransactionManager and log exception + + throw; // will cause rollback in surrounding platform transaction manager and log exception } } @@ -374,6 +542,14 @@ namespace Spring.Messaging.Listener #endregion MessageReceived(message); + + if (ExposeContainerManagedMessageQueueTransaction) + { + TransactionSynchronizationManager.BindResource( + MessageQueueTransactionManager.CURRENT_TRANSACTION_SLOTNAME, + new LocallyExposedMessageQueueResourceHolder(messageQueueTransaction)); + } + DoExecuteListener(message); #region Logging @@ -384,15 +560,26 @@ namespace Spring.Messaging.Listener } #endregion + + messageQueueTransaction.Commit(); + + #region Logging + + if (LOG.IsEnabled(LogLevel.Trace)) + { + LOG.LogTrace("Committed MessageQueueTransaction for queue [" + mq.Path + "]"); + } + + #endregion } catch (Exception ex) { - //Exception may indicate rollback of database transaction in service layer. - //Let the handler determine if the message should be removed from the queue. TransactionAction action = - HandleTransactionalListenerException(ex, message, QueueUtils.GetMessageQueueTransaction(null)); + HandleTransactionalListenerException(ex, message, messageQueueTransaction); if (action == TransactionAction.Rollback) { + messageQueueTransaction.Abort(); + #region Logging if (LOG.IsEnabled(LogLevel.Debug)) @@ -402,281 +589,101 @@ namespace Spring.Messaging.Listener } #endregion - - status.SetRollbackOnly(); - return false; // no more peeking unless this is the last listener thread } else { - LOG.LogInformation("Committing MessageQueueTransaction due to explicit commit request by exception handler."); - } - } - finally - { - message.Dispose(); - } - return true; - } - - /// - /// Does the recieve and execute using a local MessageQueueTransaction. - /// - /// The mqessage queue. - /// The transactional status. - /// true if should continue peeking, false otherwise. - protected virtual bool DoRecieveAndExecuteUsingResourceTransactionManagerWithTxQueue(MessageQueue mq, - ITransactionStatus status) - { - #region Logging - - if (LOG.IsEnabled(LogLevel.Debug)) - { - LOG.LogDebug("Executing DoRecieveAndExecuteUsingResourceTransactionManagerWithTxQueue"); - } - - #endregion Logging - - using (MessageQueueTransaction messageQueueTransaction = new MessageQueueTransaction()) - { - messageQueueTransaction.Begin(); - - #region Logging - - if (LOG.IsEnabled(LogLevel.Trace)) - { - LOG.LogTrace("Started MessageQueueTransaction for queue = [" + mq.Path + "]"); - } - - #endregion - - Message message; - - #region ReceiveMessage - - try - { - #region Logging - - if (LOG.IsEnabled(LogLevel.Trace)) - { - LOG.LogTrace("Receiving message with zero timeout for queue = [" + mq.Path + "]"); - } - - #endregion - - message = mq.Receive(TimeSpan.Zero, messageQueueTransaction); - } - catch (MessageQueueException ex) - { - if (ex.MessageQueueErrorCode == MessageQueueErrorCode.IOTimeout) - { - //expected to occur occasionally - - #region Logging - - if (LOG.IsEnabled(LogLevel.Trace)) - { - LOG.LogTrace("MessageQueueErrorCode.IOTimeout: No message available to receive. May have been processed by another thread."); - } - - #endregion - - status.SetRollbackOnly(); - return false; // no more peeking unless this is the last listener thread - } - else - { - // A real issue in receiving the message - - #region Logging - - if (LOG.IsEnabled(LogLevel.Error)) - { - LOG.LogError("Error receiving message from DefaultMessageQueue [" + mq.Path + - "], closing queue and clearing connection cache."); - } - - #endregion - - lock (messageQueueMonitor) - { - mq.Close(); - MessageQueue.ClearConnectionCache(); - } - throw; // will cause rollback in surrounding platform transaction manager and log exception - } - } - - #endregion - - if (message == null) - { - #region Logging - - if (LOG.IsEnabled(LogLevel.Trace)) - { - LOG.LogTrace("Message recieved is null from Queue = [" + mq.Path + "]"); - } - - #endregion - - status.SetRollbackOnly(); - return false; // no more peeking unless this is the last listener thread - } - - try - { - #region Logging - - if (LOG.IsEnabled(LogLevel.Debug)) - { - LOG.LogDebug("Received message [" + message.Id + "] on queue [" + mq.Path + "]"); - } - - #endregion - - MessageReceived(message); - - if (ExposeContainerManagedMessageQueueTransaction) - { - TransactionSynchronizationManager.BindResource( - MessageQueueTransactionManager.CURRENT_TRANSACTION_SLOTNAME, - new LocallyExposedMessageQueueResourceHolder(messageQueueTransaction)); - } - - DoExecuteListener(message); - - #region Logging - - if (LOG.IsEnabled(LogLevel.Trace)) - { - LOG.LogTrace("MessageListener executed"); - } - - #endregion - + // Will remove from the message queue messageQueueTransaction.Commit(); #region Logging - if (LOG.IsEnabled(LogLevel.Trace)) + if (LOG.IsEnabled(LogLevel.Debug)) { - LOG.LogTrace("Committed MessageQueueTransaction for queue [" + mq.Path + "]"); + LOG.LogDebug("Exception handler's TransactionAction has committed MessageQueueTransaction for queue [" + + mq.Path + "]"); } #endregion } - catch (Exception ex) - { - TransactionAction action = - HandleTransactionalListenerException(ex, message, messageQueueTransaction); - if (action == TransactionAction.Rollback) - { - messageQueueTransaction.Abort(); - #region Logging - - if (LOG.IsEnabled(LogLevel.Debug)) - { - LOG.LogDebug("Exception handler's TransactionAction has rolled back MessageQueueTransaction for queue [" + - mq.Path + "]"); - } - - #endregion - } - else - { - // Will remove from the message queue - messageQueueTransaction.Commit(); - - #region Logging - - if (LOG.IsEnabled(LogLevel.Debug)) - { - LOG.LogDebug("Exception handler's TransactionAction has committed MessageQueueTransaction for queue [" + - mq.Path + "]"); - } - - #endregion - } - //Outer db-tx will rollback - throw; - } - finally - { - if (ExposeContainerManagedMessageQueueTransaction) - { - TransactionSynchronizationManager.UnbindResource( - MessageQueueTransactionManager.CURRENT_TRANSACTION_SLOTNAME); - } - message.Dispose(); - } - return true; + //Outer db-tx will rollback + throw; } + finally + { + if (ExposeContainerManagedMessageQueueTransaction) + { + TransactionSynchronizationManager.UnbindResource( + MessageQueueTransactionManager.CURRENT_TRANSACTION_SLOTNAME); + } + + message.Dispose(); + } + + return true; } + } - - /// - /// Handles the transactional listener exception. - /// - /// The exception thrown while processing the message. - /// The message. - /// The message queue transaction. - /// The TransactionAction retruned by the TransactionalExceptionListener - protected virtual TransactionAction HandleTransactionalListenerException(Exception e, Message message, - MessageQueueTransaction - messageQueueTransaction) + /// + /// Handles the transactional listener exception. + /// + /// The exception thrown while processing the message. + /// The message. + /// The message queue transaction. + /// The TransactionAction retruned by the TransactionalExceptionListener + protected virtual TransactionAction HandleTransactionalListenerException(Exception e, Message message, + MessageQueueTransaction + messageQueueTransaction) + { + try { - try + TransactionAction transactionAction = + InvokeTransactionalExceptionListener(e, message, messageQueueTransaction); + if (Active) { - TransactionAction transactionAction = - InvokeTransactionalExceptionListener(e, message, messageQueueTransaction); - if (Active) - { - // Regular case: failed while active. - // Log at error level. - LOG.LogError(e, "Execution of message listener failed"); - } - else - { - // Rare case: listener thread failed after container shutdown. - // Log at debug level, to avoid spamming the shutdown log. - LOG.LogDebug(e, "Listener exception after container shutdown"); - } - return transactionAction; - } - catch (Exception ex) - { - LOG.LogError(ex, "Exception invoking MessageTransactionExceptionHandler. Rolling back transaction."); - return TransactionAction.Rollback; - } - } - - - /// - /// Invokes the transactional exception listener. - /// - /// The exception thrown during message processing. - /// The message. - /// The message queue transaction. - /// TransactionAction.Rollback if no exception handler is defined, otherwise the - /// TransactionAction returned by the exception handler - protected virtual TransactionAction InvokeTransactionalExceptionListener(Exception e, Message message, - MessageQueueTransaction - messageQueueTransaction) - { - IMessageTransactionExceptionHandler exceptionHandler = MessageTransactionExceptionHandler; - if (exceptionHandler != null) - { - return exceptionHandler.OnException(e, message, messageQueueTransaction); + // Regular case: failed while active. + // Log at error level. + LOG.LogError(e, "Execution of message listener failed"); } else { - LOG.LogWarning("No MessageTransactionExceptionHandler defined. Defaulting to TransactionAction.Rollback."); - return TransactionAction.Rollback; + // Rare case: listener thread failed after container shutdown. + // Log at debug level, to avoid spamming the shutdown log. + LOG.LogDebug(e, "Listener exception after container shutdown"); } - } - #endregion + return transactionAction; + } + catch (Exception ex) + { + LOG.LogError(ex, "Exception invoking MessageTransactionExceptionHandler. Rolling back transaction."); + return TransactionAction.Rollback; + } } + + /// + /// Invokes the transactional exception listener. + /// + /// The exception thrown during message processing. + /// The message. + /// The message queue transaction. + /// TransactionAction.Rollback if no exception handler is defined, otherwise the + /// TransactionAction returned by the exception handler + protected virtual TransactionAction InvokeTransactionalExceptionListener(Exception e, Message message, + MessageQueueTransaction + messageQueueTransaction) + { + IMessageTransactionExceptionHandler exceptionHandler = MessageTransactionExceptionHandler; + if (exceptionHandler != null) + { + return exceptionHandler.OnException(e, message, messageQueueTransaction); + } + else + { + LOG.LogWarning("No MessageTransactionExceptionHandler defined. Defaulting to TransactionAction.Rollback."); + return TransactionAction.Rollback; + } + } + + #endregion } diff --git a/src/Spring/Spring.Messaging/Messaging/MessagingException.cs b/src/Spring/Spring.Messaging/Messaging/MessagingException.cs index ad261557..b9bf6319 100644 --- a/src/Spring/Spring.Messaging/Messaging/MessagingException.cs +++ b/src/Spring/Spring.Messaging/Messaging/MessagingException.cs @@ -1,53 +1,52 @@ using System.Runtime.Serialization; -namespace Spring.Messaging +namespace Spring.Messaging; + +/// +/// Base exception class for exceptions thrown by Spring in Spring.Messaging +/// +/// Mark Pollack +[Serializable] +public class MessagingException : ApplicationException { - /// - /// Base exception class for exceptions thrown by Spring in Spring.Messaging - /// - /// Mark Pollack - [Serializable] - public class MessagingException : ApplicationException + #region Constructor (s) / Destructor + + /// Creates a new instance of the MessagingException class. + public MessagingException() { - #region Constructor (s) / Destructor - - /// Creates a new instance of the MessagingException class. - public MessagingException() - { - } - - /// - /// Creates a new instance of the MessagingException class. with the specified message. - /// - /// - /// A message about the exception. - /// - public MessagingException(string message) : base(message) - { - } - - /// - /// Creates a new instance of the MessagingException class with the specified message - /// and root cause. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception that is being wrapped. - /// - public MessagingException(string message, Exception rootCause) - : base(message, rootCause) - { - } - - /// - protected MessagingException( - SerializationInfo info, StreamingContext context) - : base(info, context) - { - } - - #endregion } + + /// + /// Creates a new instance of the MessagingException class. with the specified message. + /// + /// + /// A message about the exception. + /// + public MessagingException(string message) : base(message) + { + } + + /// + /// Creates a new instance of the MessagingException class with the specified message + /// and root cause. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception that is being wrapped. + /// + public MessagingException(string message, Exception rootCause) + : base(message, rootCause) + { + } + + /// + protected MessagingException( + SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + + #endregion } diff --git a/src/Spring/Spring.Messaging/Messaging/Support/Converters/ActiveXMessageConverter.cs b/src/Spring/Spring.Messaging/Messaging/Support/Converters/ActiveXMessageConverter.cs index dadb1b3a..0703df67 100644 --- a/src/Spring/Spring.Messaging/Messaging/Support/Converters/ActiveXMessageConverter.cs +++ b/src/Spring/Spring.Messaging/Messaging/Support/Converters/ActiveXMessageConverter.cs @@ -20,81 +20,80 @@ #if NETSTANDARD using Experimental.System.Messaging; + #else using System.Messaging; #endif -namespace Spring.Messaging.Support.Converters +namespace Spring.Messaging.Support.Converters; + +/// +/// An implementation that delegates to an instance of +/// to convert messages. +/// +/// Mark Pollack +public class ActiveXMessageConverter : IMessageConverter { + private readonly ActiveXMessageFormatter messageFormatter; + /// - /// An implementation that delegates to an instance of - /// to convert messages. + /// Initializes a new instance of the class. /// - /// Mark Pollack - public class ActiveXMessageConverter : IMessageConverter + public ActiveXMessageConverter() { - private readonly ActiveXMessageFormatter messageFormatter; - - - /// - /// Initializes a new instance of the class. - /// - public ActiveXMessageConverter() - { - messageFormatter = new ActiveXMessageFormatter(); - } - - /// - /// Initializes a new instance of the class. - /// - /// The message formatter. - public ActiveXMessageConverter(ActiveXMessageFormatter messageFormatter) - { - this.messageFormatter = messageFormatter; - } - - #region IMessageConverter Members - - /// - /// Convert the given object to a Message. - /// - /// The object to send. - /// Message to send - public Message ToMessage(object obj) - { - Message m = new Message(); - m.Body = obj; - m.Formatter = messageFormatter; - return m; - } - - /// - /// Convert the given message to a object. - /// - /// The message. - /// the object - public object FromMessage(Message message) - { - message.Formatter = messageFormatter; - return message.Body; - } - - #endregion - - #region ICloneable Members - - /// - /// Creates a new object that is a copy of the current instance. - /// - /// - /// A new object that is a copy of this instance. - /// - public object Clone() - { - ActiveXMessageConverter mc = new ActiveXMessageConverter(messageFormatter.Clone() as ActiveXMessageFormatter); - return mc; - } - - #endregion + messageFormatter = new ActiveXMessageFormatter(); } -} \ No newline at end of file + + /// + /// Initializes a new instance of the class. + /// + /// The message formatter. + public ActiveXMessageConverter(ActiveXMessageFormatter messageFormatter) + { + this.messageFormatter = messageFormatter; + } + + #region IMessageConverter Members + + /// + /// Convert the given object to a Message. + /// + /// The object to send. + /// Message to send + public Message ToMessage(object obj) + { + Message m = new Message(); + m.Body = obj; + m.Formatter = messageFormatter; + return m; + } + + /// + /// Convert the given message to a object. + /// + /// The message. + /// the object + public object FromMessage(Message message) + { + message.Formatter = messageFormatter; + return message.Body; + } + + #endregion + + #region ICloneable Members + + /// + /// Creates a new object that is a copy of the current instance. + /// + /// + /// A new object that is a copy of this instance. + /// + public object Clone() + { + ActiveXMessageConverter mc = new ActiveXMessageConverter(messageFormatter.Clone() as ActiveXMessageFormatter); + return mc; + } + + #endregion +} diff --git a/src/Spring/Spring.Messaging/Messaging/Support/Converters/BinaryMessageConverter.cs b/src/Spring/Spring.Messaging/Messaging/Support/Converters/BinaryMessageConverter.cs index 788284bc..f4a48139 100644 --- a/src/Spring/Spring.Messaging/Messaging/Support/Converters/BinaryMessageConverter.cs +++ b/src/Spring/Spring.Messaging/Messaging/Support/Converters/BinaryMessageConverter.cs @@ -22,110 +22,110 @@ using System.Runtime.Serialization.Formatters; #if NETSTANDARD using Experimental.System.Messaging; + #else using System.Messaging; #endif -namespace Spring.Messaging.Support.Converters +namespace Spring.Messaging.Support.Converters; + +/// +/// An implementation that delegates to an instance of +/// to convert messages. +/// +/// Mark Pollack +public class BinaryMessageConverter : IMessageConverter { + private readonly BinaryMessageFormatter binaryMessageFormatter; + /// - /// An implementation that delegates to an instance of - /// to convert messages. + /// Initializes a new instance of the class. /// - /// Mark Pollack - public class BinaryMessageConverter : IMessageConverter + public BinaryMessageConverter() { - private readonly BinaryMessageFormatter binaryMessageFormatter; - - /// - /// Initializes a new instance of the class. - /// - public BinaryMessageConverter() - { - binaryMessageFormatter = new BinaryMessageFormatter(); - } - - - /// - /// Initializes a new instance of the class. - /// - /// The binary message formatter. - public BinaryMessageConverter(BinaryMessageFormatter binaryMessageFormatter) - { - this.binaryMessageFormatter = binaryMessageFormatter; - } - - /// - /// Gets or sets the type format used in the - /// - /// The type format. - public FormatterTypeStyle TypeFormat - { - get - { - return binaryMessageFormatter.TypeFormat; - } - set { - binaryMessageFormatter.TypeFormat = value; - } - } - - /// - /// Gets or sets the top object format used in the - /// - /// The top object format. - public FormatterAssemblyStyle TopObjectFormat - { - get { return binaryMessageFormatter.TopObjectFormat; } - set - { - binaryMessageFormatter.TopObjectFormat = value; - } - } - - #region IMessageConverter Members - - /// - /// Convert the given object to a Message using the - /// - /// The object to send. - /// Message to send - public Message ToMessage(object obj) - { - Message m = new Message(); - m.Body = obj; - m.Formatter = binaryMessageFormatter; - return m; - } - - /// - /// Convert the given message to a object using the - /// - /// The message. - /// the object - public object FromMessage(Message message) - { - message.Formatter = binaryMessageFormatter; - return message.Body; - } - - #endregion - - #region ICloneable Members - - /// - /// Creates a new object that is a copy of the current instance. - /// - /// - /// A new object that is a copy of this instance. - /// - public object Clone() - { - //takes into account TypeFormat and TypeObjectFormat - BinaryMessageConverter mc = new BinaryMessageConverter(binaryMessageFormatter.Clone() as BinaryMessageFormatter); - return mc; - } - - #endregion + binaryMessageFormatter = new BinaryMessageFormatter(); } + + /// + /// Initializes a new instance of the class. + /// + /// The binary message formatter. + public BinaryMessageConverter(BinaryMessageFormatter binaryMessageFormatter) + { + this.binaryMessageFormatter = binaryMessageFormatter; + } + + /// + /// Gets or sets the type format used in the + /// + /// The type format. + public FormatterTypeStyle TypeFormat + { + get + { + return binaryMessageFormatter.TypeFormat; + } + set + { + binaryMessageFormatter.TypeFormat = value; + } + } + + /// + /// Gets or sets the top object format used in the + /// + /// The top object format. + public FormatterAssemblyStyle TopObjectFormat + { + get { return binaryMessageFormatter.TopObjectFormat; } + set + { + binaryMessageFormatter.TopObjectFormat = value; + } + } + + #region IMessageConverter Members + + /// + /// Convert the given object to a Message using the + /// + /// The object to send. + /// Message to send + public Message ToMessage(object obj) + { + Message m = new Message(); + m.Body = obj; + m.Formatter = binaryMessageFormatter; + return m; + } + + /// + /// Convert the given message to a object using the + /// + /// The message. + /// the object + public object FromMessage(Message message) + { + message.Formatter = binaryMessageFormatter; + return message.Body; + } + + #endregion + + #region ICloneable Members + + /// + /// Creates a new object that is a copy of the current instance. + /// + /// + /// A new object that is a copy of this instance. + /// + public object Clone() + { + //takes into account TypeFormat and TypeObjectFormat + BinaryMessageConverter mc = new BinaryMessageConverter(binaryMessageFormatter.Clone() as BinaryMessageFormatter); + return mc; + } + + #endregion } \ No newline at end of file diff --git a/src/Spring/Spring.Messaging/Messaging/Support/Converters/IMessageConverter.cs b/src/Spring/Spring.Messaging/Messaging/Support/Converters/IMessageConverter.cs index 1652f5f6..2d2cac2c 100644 --- a/src/Spring/Spring.Messaging/Messaging/Support/Converters/IMessageConverter.cs +++ b/src/Spring/Spring.Messaging/Messaging/Support/Converters/IMessageConverter.cs @@ -20,29 +20,29 @@ #if NETSTANDARD using Experimental.System.Messaging; + #else using System.Messaging; #endif -namespace Spring.Messaging.Support.Converters +namespace Spring.Messaging.Support.Converters; + +/// +/// An interface specifying the contract to convert to and from objects. +/// +public interface IMessageConverter : ICloneable { /// - /// An interface specifying the contract to convert to and from objects. + /// Convert the given object to a Message. /// - public interface IMessageConverter : ICloneable - { - /// - /// Convert the given object to a Message. - /// - /// The object to send. - /// Message to send - Message ToMessage(object obj); + /// The object to send. + /// Message to send + Message ToMessage(object obj); - /// - /// Convert the given message to a object. - /// - /// The message. - /// the object - object FromMessage(Message message); - } + /// + /// Convert the given message to a object. + /// + /// The message. + /// the object + object FromMessage(Message message); } diff --git a/src/Spring/Spring.Messaging/Messaging/Support/Converters/MessageConverterCreatorDelegate.cs b/src/Spring/Spring.Messaging/Messaging/Support/Converters/MessageConverterCreatorDelegate.cs index 49e93398..369787ba 100644 --- a/src/Spring/Spring.Messaging/Messaging/Support/Converters/MessageConverterCreatorDelegate.cs +++ b/src/Spring/Spring.Messaging/Messaging/Support/Converters/MessageConverterCreatorDelegate.cs @@ -20,11 +20,10 @@ using Spring.Messaging.Core; -namespace Spring.Messaging.Support.Converters -{ - /// - /// Delegate for creating IMessageConverter instance. Used by - /// to register a creation function with a given name. - /// - public delegate IMessageConverter MessageConverterCreatorDelegate(); -} \ No newline at end of file +namespace Spring.Messaging.Support.Converters; + +/// +/// Delegate for creating IMessageConverter instance. Used by +/// to register a creation function with a given name. +/// +public delegate IMessageConverter MessageConverterCreatorDelegate(); diff --git a/src/Spring/Spring.Messaging/Messaging/Support/Converters/MessageConverterFactoryObject.cs b/src/Spring/Spring.Messaging/Messaging/Support/Converters/MessageConverterFactoryObject.cs index 5580f8c9..5d8b62d4 100644 --- a/src/Spring/Spring.Messaging/Messaging/Support/Converters/MessageConverterFactoryObject.cs +++ b/src/Spring/Spring.Messaging/Messaging/Support/Converters/MessageConverterFactoryObject.cs @@ -20,59 +20,56 @@ using Spring.Objects.Factory.Config; -namespace Spring.Messaging.Support.Converters +namespace Spring.Messaging.Support.Converters; + +/// +/// Internal class to that users can specify a delegate function to register with the application context that +/// will create a IMessageConverter instance easily at runtime. +/// +/// Mark Pollack +internal class MessageConverterFactoryObject : IConfigurableFactoryObject { - /// - /// Internal class to that users can specify a delegate function to register with the application context that - /// will create a IMessageConverter instance easily at runtime. - /// - /// Mark Pollack - internal class MessageConverterFactoryObject : IConfigurableFactoryObject + private IObjectDefinition productTemplate; + + private MessageConverterCreatorDelegate messageConverterCreatorDelegate; + + public MessageConverterCreatorDelegate MessageConverterCreatorDelegate { - private IObjectDefinition productTemplate; - - private MessageConverterCreatorDelegate messageConverterCreatorDelegate; - - - public MessageConverterCreatorDelegate MessageConverterCreatorDelegate - { - get { return messageConverterCreatorDelegate; } - set { messageConverterCreatorDelegate = value; } - } - - #region IConfigurableFactoryObject Members - - - /// - /// Gets the template object definition that should be used - /// to configure the instance of the object managed by this factory. - /// - /// The object definition to configure the factory's product - public IObjectDefinition ProductTemplate - { - get { return productTemplate; } - set { productTemplate = value; } - } - - #endregion - - #region IFactoryObject Members - - public object GetObject() - { - return MessageConverterCreatorDelegate(); - } - - public Type ObjectType - { - get { return typeof(IMessageConverter); } - } - - public bool IsSingleton - { - get { return false; } - } - - #endregion + get { return messageConverterCreatorDelegate; } + set { messageConverterCreatorDelegate = value; } } + + #region IConfigurableFactoryObject Members + + /// + /// Gets the template object definition that should be used + /// to configure the instance of the object managed by this factory. + /// + /// The object definition to configure the factory's product + public IObjectDefinition ProductTemplate + { + get { return productTemplate; } + set { productTemplate = value; } + } + + #endregion + + #region IFactoryObject Members + + public object GetObject() + { + return MessageConverterCreatorDelegate(); + } + + public Type ObjectType + { + get { return typeof(IMessageConverter); } + } + + public bool IsSingleton + { + get { return false; } + } + + #endregion } diff --git a/src/Spring/Spring.Messaging/Messaging/Support/Converters/XmlDocumentConverter.cs b/src/Spring/Spring.Messaging/Messaging/Support/Converters/XmlDocumentConverter.cs index 37ccc31a..8a8dbec4 100644 --- a/src/Spring/Spring.Messaging/Messaging/Support/Converters/XmlDocumentConverter.cs +++ b/src/Spring/Spring.Messaging/Messaging/Support/Converters/XmlDocumentConverter.cs @@ -22,68 +22,68 @@ using System.Xml; #if NETSTANDARD using Experimental.System.Messaging; + #else using System.Messaging; #endif -namespace Spring.Messaging.Support.Converters +namespace Spring.Messaging.Support.Converters; + +/// +/// Converts an to a Message and vice-versa by using the message's +/// body stream. +/// +/// Mark Pollack +public class XmlDocumentConverter : IMessageConverter { + #region IMessageConverter Members + /// - /// Converts an to a Message and vice-versa by using the message's - /// body stream. + /// Convert the given object to a Message. /// - /// Mark Pollack - public class XmlDocumentConverter : IMessageConverter + /// The object to send. + /// Message to send + public Message ToMessage(object obj) { - #region IMessageConverter Members - - /// - /// Convert the given object to a Message. - /// - /// The object to send. - /// Message to send - public Message ToMessage(object obj) + XmlDocument doc = obj as XmlDocument; + if (doc != null) { - XmlDocument doc = obj as XmlDocument; - if (doc != null) - { - Message m = new Message(); - doc.Save(m.BodyStream); - return m; - } - else - { - throw new MessagingException("Expected object to be of type System.Xml.XmlDocument"); - } + Message m = new Message(); + doc.Save(m.BodyStream); + return m; } - - /// - /// Convert the given message to a object. - /// - /// The message. - /// the object - public object FromMessage(Message message) + else { - XmlDocument doc = new XmlDocument(); - doc.Load(message.BodyStream); - return doc; + throw new MessagingException("Expected object to be of type System.Xml.XmlDocument"); } - - #endregion - - #region ICloneable Members - - /// - /// Creates a new object that is a copy of the current instance. - /// - /// - /// A new object that is a copy of this instance. - /// - public object Clone() - { - return new XmlDocumentConverter(); - } - - #endregion } + + /// + /// Convert the given message to a object. + /// + /// The message. + /// the object + public object FromMessage(Message message) + { + XmlDocument doc = new XmlDocument(); + doc.Load(message.BodyStream); + return doc; + } + + #endregion + + #region ICloneable Members + + /// + /// Creates a new object that is a copy of the current instance. + /// + /// + /// A new object that is a copy of this instance. + /// + public object Clone() + { + return new XmlDocumentConverter(); + } + + #endregion } \ No newline at end of file diff --git a/src/Spring/Spring.Messaging/Messaging/Support/Converters/XmlMessageConverter.cs b/src/Spring/Spring.Messaging/Messaging/Support/Converters/XmlMessageConverter.cs index 7fb3b744..875d0c4c 100644 --- a/src/Spring/Spring.Messaging/Messaging/Support/Converters/XmlMessageConverter.cs +++ b/src/Spring/Spring.Messaging/Messaging/Support/Converters/XmlMessageConverter.cs @@ -22,108 +22,108 @@ using Spring.Util; #if NETSTANDARD using Experimental.System.Messaging; + #else using System.Messaging; #endif -namespace Spring.Messaging.Support.Converters +namespace Spring.Messaging.Support.Converters; + +/// +/// An implementation that delegates to an instance of +/// to convert messages. +/// +/// Mark Pollack +public class XmlMessageConverter : IMessageConverter { + private XmlMessageFormatter messageFormatter; + /// - /// An implementation that delegates to an instance of - /// to convert messages. + /// Initializes a new instance of the class. /// - /// Mark Pollack - public class XmlMessageConverter : IMessageConverter + public XmlMessageConverter() { - private XmlMessageFormatter messageFormatter; - - /// - /// Initializes a new instance of the class. - /// - public XmlMessageConverter() - { - messageFormatter = new XmlMessageFormatter(); - } - - /// - /// Initializes a new instance of the class. - /// - /// The message formatter. - public XmlMessageConverter(XmlMessageFormatter messageFormatter) - { - this.messageFormatter = messageFormatter; - } - - /// - /// Gets or sets the target types used by the - /// - /// The target types. - public Type[] TargetTypes - { - set - { - AssertUtils.ArgumentNotNull(value, "TargetTypes"); - messageFormatter.TargetTypes = value; - } - get { return messageFormatter.TargetTypes; } - } - - /// - /// Gets or sets the target type names used by the - /// - /// The target type names. - public string[] TargetTypeNames - { - set - { - AssertUtils.ArgumentNotNull(value, "TargetTypeNames"); - messageFormatter.TargetTypeNames = value; - } - get { return messageFormatter.TargetTypeNames; } - } - - #region IMessageConverter Members - - /// - /// Convert the given object to a Message. - /// - /// The object to send. - /// Message to send - public Message ToMessage(object obj) - { - Message m = new Message(); - m.Body = obj; - m.Formatter = messageFormatter; - return m; - } - - /// - /// Convert the given message to a object. - /// - /// The message. - /// the object - public object FromMessage(Message message) - { - message.Formatter = messageFormatter; - return message.Body; - } - - #endregion - - #region ICloneable Members - - /// - /// Creates a new object that is a copy of the current instance. - /// - /// - /// A new object that is a copy of this instance. - /// - public object Clone() - { - XmlMessageConverter mc = new XmlMessageConverter(messageFormatter.Clone() as XmlMessageFormatter); - return mc; - } - - #endregion + messageFormatter = new XmlMessageFormatter(); } + + /// + /// Initializes a new instance of the class. + /// + /// The message formatter. + public XmlMessageConverter(XmlMessageFormatter messageFormatter) + { + this.messageFormatter = messageFormatter; + } + + /// + /// Gets or sets the target types used by the + /// + /// The target types. + public Type[] TargetTypes + { + set + { + AssertUtils.ArgumentNotNull(value, "TargetTypes"); + messageFormatter.TargetTypes = value; + } + get { return messageFormatter.TargetTypes; } + } + + /// + /// Gets or sets the target type names used by the + /// + /// The target type names. + public string[] TargetTypeNames + { + set + { + AssertUtils.ArgumentNotNull(value, "TargetTypeNames"); + messageFormatter.TargetTypeNames = value; + } + get { return messageFormatter.TargetTypeNames; } + } + + #region IMessageConverter Members + + /// + /// Convert the given object to a Message. + /// + /// The object to send. + /// Message to send + public Message ToMessage(object obj) + { + Message m = new Message(); + m.Body = obj; + m.Formatter = messageFormatter; + return m; + } + + /// + /// Convert the given message to a object. + /// + /// The message. + /// the object + public object FromMessage(Message message) + { + message.Formatter = messageFormatter; + return message.Body; + } + + #endregion + + #region ICloneable Members + + /// + /// Creates a new object that is a copy of the current instance. + /// + /// + /// A new object that is a copy of this instance. + /// + public object Clone() + { + XmlMessageConverter mc = new XmlMessageConverter(messageFormatter.Clone() as XmlMessageFormatter); + return mc; + } + + #endregion } diff --git a/src/Spring/Spring.Messaging/Messaging/Support/MessageQueueCreatorDelegate.cs b/src/Spring/Spring.Messaging/Messaging/Support/MessageQueueCreatorDelegate.cs index bb13ca55..9da81626 100644 --- a/src/Spring/Spring.Messaging/Messaging/Support/MessageQueueCreatorDelegate.cs +++ b/src/Spring/Spring.Messaging/Messaging/Support/MessageQueueCreatorDelegate.cs @@ -1,18 +1,16 @@ - - using Spring.Messaging.Core; #if NETSTANDARD using Experimental.System.Messaging; + #else using System.Messaging; #endif -namespace Spring.Messaging.Support -{ - /// - /// Delegate for creating MessageQueue instance. Used by - /// to register a creation function with a given name. - /// - public delegate MessageQueue MessageQueueCreatorDelegate(); -} \ No newline at end of file +namespace Spring.Messaging.Support; + +/// +/// Delegate for creating MessageQueue instance. Used by +/// to register a creation function with a given name. +/// +public delegate MessageQueue MessageQueueCreatorDelegate(); diff --git a/src/Spring/Spring.Messaging/Messaging/Support/MessageQueueFactoryObject.cs b/src/Spring/Spring.Messaging/Messaging/Support/MessageQueueFactoryObject.cs index 7cf08ec0..5f3bc8b8 100644 --- a/src/Spring/Spring.Messaging/Messaging/Support/MessageQueueFactoryObject.cs +++ b/src/Spring/Spring.Messaging/Messaging/Support/MessageQueueFactoryObject.cs @@ -23,255 +23,251 @@ using Spring.Objects.Factory.Config; #if NETSTANDARD using Experimental.System.Messaging; + #else using System.Messaging; #endif -namespace Spring.Messaging.Support +namespace Spring.Messaging.Support; + +/// +/// Factory for creating MessageQueues. This factory will create prototype instances, i.e. every call to GetObject +/// will return a new MessageQueue object. +/// +/// All MessageQueue constructor arguments are exposed as properties of the factory object. As this +/// is a use the PropertyTemplate property to specify additional +/// configuration of the MessageQueue. +/// +/// Mark Pollack +public class MessageQueueFactoryObject : IConfigurableFactoryObject, IObjectNameAware { + // fields used in constructor + private string path = string.Empty; + private bool modeDenySharedReceive; + private bool enableCache; + private QueueAccessMode accessMode = QueueAccessMode.SendAndReceive; + + // To avoid stale handles when MSMQ restarts and when stopping async recieve/peek operations + private bool enableConnectionCache = false; + + private IObjectDefinition productTemplate; + + private bool messageReadPropertyFilterSetAll = true; + + private bool messageReadPropertyFilterSetDefaults = false; + + private MessageQueueCreatorDelegate messageCreatorDelegate; + + private bool remoteQueue = false; + + private bool remoteQueueIsTransactional = false; + private string objectName; + /// - /// Factory for creating MessageQueues. This factory will create prototype instances, i.e. every call to GetObject - /// will return a new MessageQueue object. + /// Gets or sets an instance of the MessageQueueCreator delegate that will be used to create the + /// MessageQueue object, instead of using the various public properties on this class such + /// as Path, AccessMode, etc. Not intended for end-users but rather as a means to help + /// register MessageQueueFactoryObject at runtime using convenience method on the IMessageQueueFactory. /// - /// All MessageQueue constructor arguments are exposed as properties of the factory object. As this - /// is a use the PropertyTemplate property to specify additional - /// configuration of the MessageQueue. + /// + /// Can also be specifed using an instance of MessageCreatorDelegate. If both are specifed, the + /// Interface implementation has priority. /// - /// Mark Pollack - public class MessageQueueFactoryObject : IConfigurableFactoryObject, IObjectNameAware + /// The function that is responsbile for creating a message queue. + public MessageQueueCreatorDelegate MessageCreatorDelegate { - // fields used in constructor - private string path = string.Empty; - private bool modeDenySharedReceive; - private bool enableCache; - private QueueAccessMode accessMode = QueueAccessMode.SendAndReceive; + get { return messageCreatorDelegate; } + set { messageCreatorDelegate = value; } + } - // To avoid stale handles when MSMQ restarts and when stopping async recieve/peek operations - private bool enableConnectionCache = false; + /// + /// Gets or sets the path used to create a MessageQueue instance. + /// + /// The location of the queue. + public string Path + { + get { return path; } + set { path = value; } + } - private IObjectDefinition productTemplate; + /// + /// Gets or sets a value indicating whether to create the MessageQueue instance with + /// exclusive read access to the first application that accesses the queue + /// + /// + /// true to grant exclusive read access to the first application that accesses the queue; otherwise, false. + /// + public bool DenySharedReceive + { + get { return modeDenySharedReceive; } + set { modeDenySharedReceive = value; } + } - private bool messageReadPropertyFilterSetAll = true; + /// + /// Gets or sets the queue access mode. + /// + /// The queue access mode. + /// + public QueueAccessMode AccessMode + { + get { return accessMode; } + set { accessMode = value; } + } - private bool messageReadPropertyFilterSetDefaults = false; + /// + /// Gets or sets a value indicating whether [enable cache]. + /// + /// true to create and use a connection cache; otherwise false. + public bool EnableCache + { + get { return enableCache; } + set { enableCache = value; } + } - private MessageQueueCreatorDelegate messageCreatorDelegate; + /// + /// Sets a value indicating whether to enable connection cache. The default is false, which + /// is different than the default value when creating a System.Messaging.MessageQueue object. + /// + /// + /// true if enable connection cache; otherwise, false. + /// + public bool EnableConnectionCache + { + set { enableConnectionCache = value; } + } - private bool remoteQueue = false; + /// + /// Sets a value indicating whether to retrieve all message properties when receiving a message. + /// + /// + /// true if should etrieve all message properties when receiving a message; otherwise, false. + /// + public bool MessageReadPropertyFilterSetAll + { + set { messageReadPropertyFilterSetAll = value; } + } - private bool remoteQueueIsTransactional = false; - private string objectName; + /// + /// Sets a value indicating whether to set the filter values of common Message Queuing properties + /// to true and the integer-valued properties to their default values.. + /// + /// + /// true if should set the filter values of common Message Queuing properties; otherwise, false. + /// + public bool MessageReadPropertyFilterSetDefaults + { + set { messageReadPropertyFilterSetDefaults = value; } + } + /// + /// Gets or sets a value indicating whether the queue is a remote queue. + /// + /// + /// The operations that one can perform on the MessageQueue depend on if it is local or remote, for + /// example checking if it is transactional. This is very difficult to determine programmatically. + /// The property was made virtual so it can be overridden to take into account custom heuristics you + /// may want to use to determine this programmatically. + /// + /// true if remote queue; otherwise, false. + public virtual bool RemoteQueue + { + get { return remoteQueue; } + set { remoteQueue = value; } + } - /// - /// Gets or sets an instance of the MessageQueueCreator delegate that will be used to create the - /// MessageQueue object, instead of using the various public properties on this class such - /// as Path, AccessMode, etc. Not intended for end-users but rather as a means to help - /// register MessageQueueFactoryObject at runtime using convenience method on the IMessageQueueFactory. - /// - /// - /// Can also be specifed using an instance of MessageCreatorDelegate. If both are specifed, the - /// Interface implementation has priority. - /// - /// The function that is responsbile for creating a message queue. - public MessageQueueCreatorDelegate MessageCreatorDelegate + /// + /// Gets or sets a value indicating whether the remote queue is transactional. + /// + /// + /// true if the remote queue is transactional; otherwise, false. + /// + public virtual bool RemoteQueueIsTransactional + { + get { return remoteQueueIsTransactional; } + set { remoteQueueIsTransactional = value; } + } + + #region IFactoryObject Members + + /// + /// Retrun a configured MessageQueue object. + /// + /// A newly configured MessageQueue object + public object GetObject() + { + if (MessageCreatorDelegate != null) { - get { return messageCreatorDelegate; } - set { messageCreatorDelegate = value; } + return MessageCreatorDelegate(); } - - /// - /// Gets or sets the path used to create a MessageQueue instance. - /// - /// The location of the queue. - public string Path + else { - get { return path; } - set { path = value; } - } - - - /// - /// Gets or sets a value indicating whether to create the MessageQueue instance with - /// exclusive read access to the first application that accesses the queue - /// - /// - /// true to grant exclusive read access to the first application that accesses the queue; otherwise, false. - /// - public bool DenySharedReceive - { - get { return modeDenySharedReceive; } - set { modeDenySharedReceive = value; } - } - - - /// - /// Gets or sets the queue access mode. - /// - /// The queue access mode. - /// - public QueueAccessMode AccessMode - { - get { return accessMode; } - set { accessMode = value; } - } - - - /// - /// Gets or sets a value indicating whether [enable cache]. - /// - /// true to create and use a connection cache; otherwise false. - public bool EnableCache - { - get { return enableCache; } - set { enableCache = value; } - } - - /// - /// Sets a value indicating whether to enable connection cache. The default is false, which - /// is different than the default value when creating a System.Messaging.MessageQueue object. - /// - /// - /// true if enable connection cache; otherwise, false. - /// - public bool EnableConnectionCache - { - set { enableConnectionCache = value; } - } - - - /// - /// Sets a value indicating whether to retrieve all message properties when receiving a message. - /// - /// - /// true if should etrieve all message properties when receiving a message; otherwise, false. - /// - public bool MessageReadPropertyFilterSetAll - { - set { messageReadPropertyFilterSetAll = value; } - } - - - /// - /// Sets a value indicating whether to set the filter values of common Message Queuing properties - /// to true and the integer-valued properties to their default values.. - /// - /// - /// true if should set the filter values of common Message Queuing properties; otherwise, false. - /// - public bool MessageReadPropertyFilterSetDefaults - { - set { messageReadPropertyFilterSetDefaults = value; } - } - - /// - /// Gets or sets a value indicating whether the queue is a remote queue. - /// - /// - /// The operations that one can perform on the MessageQueue depend on if it is local or remote, for - /// example checking if it is transactional. This is very difficult to determine programmatically. - /// The property was made virtual so it can be overridden to take into account custom heuristics you - /// may want to use to determine this programmatically. - /// - /// true if remote queue; otherwise, false. - public virtual bool RemoteQueue - { - get { return remoteQueue; } - set { remoteQueue = value; } - } - - /// - /// Gets or sets a value indicating whether the remote queue is transactional. - /// - /// - /// true if the remote queue is transactional; otherwise, false. - /// - public virtual bool RemoteQueueIsTransactional - { - get { return remoteQueueIsTransactional; } - set { remoteQueueIsTransactional = value; } - } - - #region IFactoryObject Members - - /// - /// Retrun a configured MessageQueue object. - /// - /// A newly configured MessageQueue object - public object GetObject() - { - if (MessageCreatorDelegate != null) + MessageQueue mq = new MessageQueue(Path, DenySharedReceive, EnableCache, AccessMode); + if (messageReadPropertyFilterSetDefaults) { - return MessageCreatorDelegate(); + mq.MessageReadPropertyFilter.SetDefaults(); } - else + + if (messageReadPropertyFilterSetAll) { - MessageQueue mq = new MessageQueue(Path, DenySharedReceive, EnableCache, AccessMode); - if (messageReadPropertyFilterSetDefaults) - { - mq.MessageReadPropertyFilter.SetDefaults(); - } - if (messageReadPropertyFilterSetAll) - { - mq.MessageReadPropertyFilter.SetAll(); - } - return mq; + mq.MessageReadPropertyFilter.SetAll(); } - } - /// - /// Return the of object that this - /// creates, or - /// if not known in advance. - /// - /// The type System.Messaging.MessageQueue - public Type ObjectType - { - get { return typeof (MessageQueue); } - } - - /// - /// Is the object managed by this factory a singleton or a prototype? - /// - /// return false, a new object will be created for each request of the object - public bool IsSingleton - { - get { return false; } - } - - #region IConfigurableFactoryObject Members - - /// - /// Gets the template object definition that should be used - /// to configure the instance of the object managed by this factory. - /// - /// The object definition to configure the factory's product - public IObjectDefinition ProductTemplate - { - get { return productTemplate; } - set { productTemplate = value; } - } - - #endregion - - #endregion - - /// - /// Set the name of the object in the object factory that created this object. - /// - /// The name of the object in the factory. - /// - ///

- /// Invoked after population of normal object properties but before an init - /// callback like 's - /// - /// method or a custom init-method. - ///

- ///
- public string ObjectName - { - set { objectName = value; } - get { return ObjectName; } + return mq; } } + + /// + /// Return the of object that this + /// creates, or + /// if not known in advance. + /// + /// The type System.Messaging.MessageQueue + public Type ObjectType + { + get { return typeof(MessageQueue); } + } + + /// + /// Is the object managed by this factory a singleton or a prototype? + /// + /// return false, a new object will be created for each request of the object + public bool IsSingleton + { + get { return false; } + } + + #region IConfigurableFactoryObject Members + + /// + /// Gets the template object definition that should be used + /// to configure the instance of the object managed by this factory. + /// + /// The object definition to configure the factory's product + public IObjectDefinition ProductTemplate + { + get { return productTemplate; } + set { productTemplate = value; } + } + + #endregion + + #endregion + + /// + /// Set the name of the object in the object factory that created this object. + /// + /// The name of the object in the factory. + /// + ///

+ /// Invoked after population of normal object properties but before an init + /// callback like 's + /// + /// method or a custom init-method. + ///

+ ///
+ public string ObjectName + { + set { objectName = value; } + get { return ObjectName; } + } } diff --git a/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/AdaptableJobFactory.cs b/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/AdaptableJobFactory.cs index 14a5268f..e96dd4ac 100644 --- a/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/AdaptableJobFactory.cs +++ b/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/AdaptableJobFactory.cs @@ -1,126 +1,125 @@ /* -* Copyright 2002-2010 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. -*/ + * Copyright 2002-2010 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. + */ using Quartz; using Quartz.Spi; using Quartz.Util; -namespace Spring.Scheduling.Quartz +namespace Spring.Scheduling.Quartz; + +/// +/// JobFactory implementation that supports +/// objects as well as standard Quartz instances. +/// +/// Juergen Hoeller +/// Marko Lahma (.NET) +/// +/// +public class AdaptableJobFactory : IJobFactory { /// - /// JobFactory implementation that supports - /// objects as well as standard Quartz instances. + /// Called by the scheduler at the time of the trigger firing, in order to + /// produce a instance on which to call Execute. /// - /// Juergen Hoeller - /// Marko Lahma (.NET) - /// - /// - public class AdaptableJobFactory : IJobFactory + /// + /// It should be extremely rare for this method to throw an exception - + /// basically only the the case where there is no way at all to instantiate + /// and prepare the Job for execution. When the exception is thrown, the + /// Scheduler will move all triggers associated with the Job into the + /// state, which will require human + /// intervention (e.g. an application restart after fixing whatever + /// configuration problem led to the issue wih instantiating the Job. + /// + /// The TriggerFiredBundle from which the + /// and other info relating to the trigger firing can be obtained. + /// The scheduler instance. + /// the newly instantiated Job + /// SchedulerException if there is a problem instantiating the Job. + public virtual IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler) { - /// - /// Called by the scheduler at the time of the trigger firing, in order to - /// produce a instance on which to call Execute. - /// - /// - /// It should be extremely rare for this method to throw an exception - - /// basically only the the case where there is no way at all to instantiate - /// and prepare the Job for execution. When the exception is thrown, the - /// Scheduler will move all triggers associated with the Job into the - /// state, which will require human - /// intervention (e.g. an application restart after fixing whatever - /// configuration problem led to the issue wih instantiating the Job. - /// - /// The TriggerFiredBundle from which the - /// and other info relating to the trigger firing can be obtained. - /// The scheduler instance. - /// the newly instantiated Job - /// SchedulerException if there is a problem instantiating the Job. - public virtual IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler) + try { - try - { - object jobObject = CreateJobInstance(bundle); - return AdaptJob(jobObject); - } - catch (Exception ex) - { - throw new SchedulerException("Job instantiation failed", ex); - } + object jobObject = CreateJobInstance(bundle); + return AdaptJob(jobObject); } - - /// - /// Allows the the job factory to destroy/cleanup the job if needed. - /// - public virtual void ReturnJob(IJob job) + catch (Exception ex) { - } - - /// - /// Create an instance of the specified job class. - ///

- /// Can be overridden to post-process the job instance. - ///

- ///
- /// - /// The TriggerFiredBundle from which the JobDetail - /// and other info relating to the trigger firing can be obtained. - /// - /// The job instance. - protected virtual object CreateJobInstance(TriggerFiredBundle bundle) - { - return ObjectUtils.InstantiateType(bundle.JobDetail.JobType); - } - - /// - /// Adapt the given job object to the Quartz Job interface. - /// - /// - /// The default implementation supports straight Quartz Jobs - /// as well as Runnables, which get wrapped in a DelegatingJob. - /// - /// - /// The original instance of the specified job class. - /// - /// The adapted Quartz Job instance. - /// - protected virtual IJob AdaptJob(object jobObject) - { - if (jobObject is IJob job) - { - return job; - } - - if (jobObject is ThreadStart start) - { - return new DelegatingJob(start); - } - - if (jobObject is IThreadRunnable threadRunnable) - { - return new DelegatingJob(() => threadRunnable.Run().ConfigureAwait(false).GetAwaiter().GetResult()); - } - - if (jobObject is Func func) - { - return new DelegatingJob(() => func().ConfigureAwait(false).GetAwaiter().GetResult()); - } - - string message = - $"Unable to execute job class [{jobObject.GetType().FullName}]: only [IJob] and [ThreadStart] supported."; - throw new ArgumentException(message); + throw new SchedulerException("Job instantiation failed", ex); } } + + /// + /// Allows the the job factory to destroy/cleanup the job if needed. + /// + public virtual void ReturnJob(IJob job) + { + } + + /// + /// Create an instance of the specified job class. + ///

+ /// Can be overridden to post-process the job instance. + ///

+ ///
+ /// + /// The TriggerFiredBundle from which the JobDetail + /// and other info relating to the trigger firing can be obtained. + /// + /// The job instance. + protected virtual object CreateJobInstance(TriggerFiredBundle bundle) + { + return ObjectUtils.InstantiateType(bundle.JobDetail.JobType); + } + + /// + /// Adapt the given job object to the Quartz Job interface. + /// + /// + /// The default implementation supports straight Quartz Jobs + /// as well as Runnables, which get wrapped in a DelegatingJob. + /// + /// + /// The original instance of the specified job class. + /// + /// The adapted Quartz Job instance. + /// + protected virtual IJob AdaptJob(object jobObject) + { + if (jobObject is IJob job) + { + return job; + } + + if (jobObject is ThreadStart start) + { + return new DelegatingJob(start); + } + + if (jobObject is IThreadRunnable threadRunnable) + { + return new DelegatingJob(() => threadRunnable.Run().ConfigureAwait(false).GetAwaiter().GetResult()); + } + + if (jobObject is Func func) + { + return new DelegatingJob(() => func().ConfigureAwait(false).GetAwaiter().GetResult()); + } + + string message = + $"Unable to execute job class [{jobObject.GetType().FullName}]: only [IJob] and [ThreadStart] supported."; + throw new ArgumentException(message); + } } diff --git a/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/CronTriggerObject.cs b/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/CronTriggerObject.cs index 6a439dd2..53b78079 100644 --- a/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/CronTriggerObject.cs +++ b/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/CronTriggerObject.cs @@ -1,18 +1,18 @@ /* -* Copyright 2002-2010 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. -*/ + * Copyright 2002-2010 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. + */ using System.Collections; using System.Reflection; @@ -21,214 +21,213 @@ using Quartz.Impl.Triggers; using Spring.Objects.Factory; using Spring.Util; -namespace Spring.Scheduling.Quartz +namespace Spring.Scheduling.Quartz; + +/// +/// Convenience subclass of Quartz's CronTrigger type, making property based +/// usage easier. +/// +/// +///

+/// CronTrigger itself is already property based but lacks sensible defaults. +/// This class uses the Spring object name as job name, the Quartz default group +/// ("DEFAULT") as job group, the current time as start time, and indefinite +/// repetition, if not specified. +///

+///

+/// This class will also register the trigger with the job name and group of +/// a given . This allows +/// to automatically register a trigger for the corresponding JobDetail, +/// instead of registering the JobDetail separately. +///

+///
+/// Juergen Hoeller +/// +/// +/// +/// +/// +/// +public class CronTriggerObject : CronTriggerImpl, IJobDetailAwareTrigger, IObjectNameAware, IInitializingObject { + private readonly Constants constants = new Constants( + typeof(MisfireInstruction.CronTrigger), + typeof(MisfireInstruction) + ); + + private IJobDetail jobDetail; + private string objectName; + private TimeSpan startDelay; + /// - /// Convenience subclass of Quartz's CronTrigger type, making property based - /// usage easier. + /// Register objects in the JobDataMap via a given Map. + /// + /// + /// These objects will be available to this Trigger only, + /// in contrast to objects in the JobDetail's data map. + /// + /// + public virtual IDictionary JobDataAsMap + { + set + { + foreach (DictionaryEntry entry in value) + { + JobDataMap.Put((string) entry.Key, entry.Value); + } + } + } + + /// + /// Set the misfire instruction via the name of the corresponding + /// constant in the CronTrigger class. + /// Default is . + /// + /// + /// + /// + public virtual string MisfireInstructionName + { + set => MisfireInstruction = constants.AsNumber(value); + } + + /// + /// Set the name of the object in the object factory that created this object. + /// + /// The name of the object in the factory. + /// + ///

+ /// Invoked after population of normal object properties but before an init + /// callback like 's + /// + /// method or a custom init-method. + ///

+ ///
+ public virtual string ObjectName + { + set => objectName = value; + } + + /// + /// Set the JobDetail that this trigger should be associated with. + /// + /// + /// This is typically used with a object reference if the JobDetail + /// is a Spring-managed object. Alternatively, the trigger can also + /// be associated with a job by name and group. + /// + /// + public virtual IJobDetail JobDetail + { + get => jobDetail; + set => jobDetail = value; + } + + /// + /// Set the start delay as . + /// + /// + /// + /// The start delay is added to the current system UTC time + /// (when the object starts) to control the + /// of the trigger. + /// + /// + /// If the start delay is non-zero it will always + /// take precedence over start time. + /// + /// + /// the start delay, as object. + public TimeSpan StartDelay + { + set + { + AssertUtils.State(value >= TimeSpan.Zero, "Start delay cannot be negative."); + startDelay = value; + } + get => startDelay; + } + + /// + /// Invoked by an + /// after it has injected all of an object's dependencies. /// /// ///

- /// CronTrigger itself is already property based but lacks sensible defaults. - /// This class uses the Spring object name as job name, the Quartz default group - /// ("DEFAULT") as job group, the current time as start time, and indefinite - /// repetition, if not specified. + /// This method allows the object instance to perform the kind of + /// initialization only possible when all of it's dependencies have + /// been injected (set), and to throw an appropriate exception in the + /// event of misconfiguration. ///

///

- /// This class will also register the trigger with the job name and group of - /// a given . This allows - /// to automatically register a trigger for the corresponding JobDetail, - /// instead of registering the JobDetail separately. + /// Please do consult the class level documentation for the + /// interface for a + /// description of exactly when this method is invoked. In + /// particular, it is worth noting that the + /// + /// and + /// callbacks will have been invoked prior to this method being + /// called. ///

///
- /// Juergen Hoeller - /// - /// - /// - /// - /// - /// - public class CronTriggerObject : CronTriggerImpl, IJobDetailAwareTrigger, IObjectNameAware, IInitializingObject + /// + /// In the event of misconfiguration (such as the failure to set a + /// required property) or if initialization fails. + /// + public virtual void AfterPropertiesSet() { - private readonly Constants constants = new Constants( - typeof(MisfireInstruction.CronTrigger), - typeof(MisfireInstruction) - ); - - private IJobDetail jobDetail; - private string objectName; - private TimeSpan startDelay; - - /// - /// Register objects in the JobDataMap via a given Map. - /// - /// - /// These objects will be available to this Trigger only, - /// in contrast to objects in the JobDetail's data map. - /// - /// - public virtual IDictionary JobDataAsMap + if (StartTimeUtc == DateTimeOffset.MinValue) { - set - { - foreach (DictionaryEntry entry in value) - { - JobDataMap.Put((string) entry.Key, entry.Value); - } - } + StartTimeUtc = DateTimeOffset.UtcNow; } - /// - /// Set the misfire instruction via the name of the corresponding - /// constant in the CronTrigger class. - /// Default is . - /// - /// - /// - /// - public virtual string MisfireInstructionName + if (StartDelay > TimeSpan.Zero) { - set => MisfireInstruction = constants.AsNumber(value); + StartTimeUtc = DateTime.UtcNow.Add(startDelay); } - /// - /// Set the name of the object in the object factory that created this object. - /// - /// The name of the object in the factory. - /// - ///

- /// Invoked after population of normal object properties but before an init - /// callback like 's - /// - /// method or a custom init-method. - ///

- ///
- public virtual string ObjectName + if (Name == null) { - set => objectName = value; + Name = objectName; } - /// - /// Set the JobDetail that this trigger should be associated with. - /// - /// - /// This is typically used with a object reference if the JobDetail - /// is a Spring-managed object. Alternatively, the trigger can also - /// be associated with a job by name and group. - /// - /// - public virtual IJobDetail JobDetail + if (Group == null) { - get => jobDetail; - set => jobDetail = value; + Group = SchedulerConstants.DefaultGroup; } - /// - /// Set the start delay as . - /// - /// - /// - /// The start delay is added to the current system UTC time - /// (when the object starts) to control the - /// of the trigger. - /// - /// - /// If the start delay is non-zero it will always - /// take precedence over start time. - /// - /// - /// the start delay, as object. - public TimeSpan StartDelay + if (jobDetail != null) { - set - { - AssertUtils.State(value >= TimeSpan.Zero, "Start delay cannot be negative."); - startDelay = value; - } - get => startDelay; - } - - /// - /// Invoked by an - /// after it has injected all of an object's dependencies. - /// - /// - ///

- /// This method allows the object instance to perform the kind of - /// initialization only possible when all of it's dependencies have - /// been injected (set), and to throw an appropriate exception in the - /// event of misconfiguration. - ///

- ///

- /// Please do consult the class level documentation for the - /// interface for a - /// description of exactly when this method is invoked. In - /// particular, it is worth noting that the - /// - /// and - /// callbacks will have been invoked prior to this method being - /// called. - ///

- ///
- /// - /// In the event of misconfiguration (such as the failure to set a - /// required property) or if initialization fails. - /// - public virtual void AfterPropertiesSet() - { - if (StartTimeUtc == DateTimeOffset.MinValue) - { - StartTimeUtc = DateTimeOffset.UtcNow; - } - - if (StartDelay > TimeSpan.Zero) - { - StartTimeUtc = DateTime.UtcNow.Add(startDelay); - } - - if (Name == null) - { - Name = objectName; - } - - if (Group == null) - { - Group = SchedulerConstants.DefaultGroup; - } - - if (jobDetail != null) - { - JobName = jobDetail.Key.Name; - JobGroup = jobDetail.Key.Group; - } - } - } - - /// - /// Helper class to map constant names to their values. - /// - internal class Constants - { - private readonly Type[] types; - - public Constants(params Type[] reflectedTypes) - { - types = reflectedTypes; - } - - public int AsNumber(string field) - { - foreach (Type type in types) - { - FieldInfo fi = type.GetField(field); - if (fi != null) - { - return Convert.ToInt32(fi.GetValue(null)); - } - } - - // not found - throw new Exception($"Unknown field '{field}'"); + JobName = jobDetail.Key.Name; + JobGroup = jobDetail.Key.Group; } } } + +/// +/// Helper class to map constant names to their values. +/// +internal class Constants +{ + private readonly Type[] types; + + public Constants(params Type[] reflectedTypes) + { + types = reflectedTypes; + } + + public int AsNumber(string field) + { + foreach (Type type in types) + { + FieldInfo fi = type.GetField(field); + if (fi != null) + { + return Convert.ToInt32(fi.GetValue(null)); + } + } + + // not found + throw new Exception($"Unknown field '{field}'"); + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/DelegatingJob.cs b/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/DelegatingJob.cs index e41896ca..8bf855a5 100644 --- a/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/DelegatingJob.cs +++ b/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/DelegatingJob.cs @@ -1,60 +1,59 @@ /* -* Copyright 2002-2010 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. -*/ + * Copyright 2002-2010 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. + */ using Quartz; using Spring.Util; -namespace Spring.Scheduling.Quartz +namespace Spring.Scheduling.Quartz; + +/// +/// Simple Quartz IJob adapter that delegates to a +/// given instance. +/// +/// +/// Typically used in combination with property injection on the +/// Runnable instance, receiving parameters from the Quartz JobDataMap +/// that way instead of via the JobExecutionContext. +/// +/// Juergen Hoeller +/// Marko Lahma (.NET) +/// +/// +public class DelegatingJob : IJob { + private readonly ThreadStart delegateInstance; + /// - /// Simple Quartz IJob adapter that delegates to a - /// given instance. + /// Create a new DelegatingJob. /// - /// - /// Typically used in combination with property injection on the - /// Runnable instance, receiving parameters from the Quartz JobDataMap - /// that way instead of via the JobExecutionContext. - /// - /// Juergen Hoeller - /// Marko Lahma (.NET) - /// - /// - public class DelegatingJob : IJob + /// + /// The Runnable implementation to delegate to. + /// + public DelegatingJob(ThreadStart delegateInstance) { - private readonly ThreadStart delegateInstance; + AssertUtils.ArgumentNotNull(delegateInstance, "delegateInstance", "Delegate must not be null"); + this.delegateInstance = delegateInstance; + } - /// - /// Create a new DelegatingJob. - /// - /// - /// The Runnable implementation to delegate to. - /// - public DelegatingJob(ThreadStart delegateInstance) - { - AssertUtils.ArgumentNotNull(delegateInstance, "delegateInstance", "Delegate must not be null"); - this.delegateInstance = delegateInstance; - } - - /// - /// Delegates execution to the underlying ThreadStart. - /// - public virtual Task Execute(IJobExecutionContext context) - { - delegateInstance.Invoke(); - return Task.FromResult(true); - } + /// + /// Delegates execution to the underlying ThreadStart. + /// + public virtual Task Execute(IJobExecutionContext context) + { + delegateInstance.Invoke(); + return Task.FromResult(true); } } diff --git a/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/IJobDetailAwareTrigger.cs b/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/IJobDetailAwareTrigger.cs index f083085d..54e0b521 100644 --- a/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/IJobDetailAwareTrigger.cs +++ b/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/IJobDetailAwareTrigger.cs @@ -1,48 +1,47 @@ /* -* Copyright 2002-2010 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. -*/ + * Copyright 2002-2010 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. + */ using Quartz; -namespace Spring.Scheduling.Quartz +namespace Spring.Scheduling.Quartz; + +/// +/// Interface to be implemented by Quartz Triggers that are aware +/// of the JobDetail object that they are associated with. +/// +/// +///

+/// SchedulerFactoryObject will auto-detect Triggers that implement this +/// interface and register them for the respective JobDetail accordingly. +///

+/// +///

+/// The alternative is to configure a Trigger for a Job name and group: +/// This involves the need to register the JobDetail object separately +/// with SchedulerFactoryObject. +///

+///
+/// Juergen Hoeller +/// +/// +public interface IJobDetailAwareTrigger { - /// - /// Interface to be implemented by Quartz Triggers that are aware - /// of the JobDetail object that they are associated with. + /// + /// Return the JobDetail that this Trigger is associated with. /// - /// - ///

- /// SchedulerFactoryObject will auto-detect Triggers that implement this - /// interface and register them for the respective JobDetail accordingly. - ///

- /// - ///

- /// The alternative is to configure a Trigger for a Job name and group: - /// This involves the need to register the JobDetail object separately - /// with SchedulerFactoryObject. - ///

- ///
- /// Juergen Hoeller - /// - /// - public interface IJobDetailAwareTrigger - { - /// - /// Return the JobDetail that this Trigger is associated with. - /// - /// The associated JobDetail, or null if none - IJobDetail JobDetail { get; } - } -} \ No newline at end of file + /// The associated JobDetail, or null if none + IJobDetail JobDetail { get; } +} diff --git a/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/ISchedulerContextAware.cs b/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/ISchedulerContextAware.cs index fa4742d6..901b0393 100644 --- a/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/ISchedulerContextAware.cs +++ b/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/ISchedulerContextAware.cs @@ -1,42 +1,41 @@ /* -* Copyright 2002-2010 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. -*/ + * Copyright 2002-2010 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. + */ using Quartz; using Quartz.Spi; -namespace Spring.Scheduling.Quartz +namespace Spring.Scheduling.Quartz; + +/// +/// Callback interface to be implemented by Spring-managed +/// Quartz artifacts that need access to the SchedulerContext +/// (without having natural access to it). +/// +/// +/// Currently only supported for custom JobFactory implementations +/// that are passed in via Spring's SchedulerFactoryObject. +/// +/// Juergen Hoeller +/// +/// +public interface ISchedulerContextAware { - /// - /// Callback interface to be implemented by Spring-managed - /// Quartz artifacts that need access to the SchedulerContext - /// (without having natural access to it). + /// + /// Set the SchedulerContext of the current Quartz Scheduler. /// - /// - /// Currently only supported for custom JobFactory implementations - /// that are passed in via Spring's SchedulerFactoryObject. - /// - /// Juergen Hoeller - /// - /// - public interface ISchedulerContextAware - { - /// - /// Set the SchedulerContext of the current Quartz Scheduler. - /// - /// - SchedulerContext SchedulerContext { set; } - } -} \ No newline at end of file + /// + SchedulerContext SchedulerContext { set; } +} diff --git a/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/ISchedulingTaskExecutor.cs b/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/ISchedulingTaskExecutor.cs index 4cbd1c1d..125576ee 100644 --- a/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/ISchedulingTaskExecutor.cs +++ b/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/ISchedulingTaskExecutor.cs @@ -1,32 +1,31 @@ /* -* Copyright 2002-2010 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. -*/ + * Copyright 2002-2010 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. + */ -namespace Spring.Scheduling +namespace Spring.Scheduling; + +/// +/// +/// +public interface ISchedulingTaskExecutor : ITaskExecutor { /// - /// + /// Gets a value indicating whether�this instance prefers short lived tasks. /// - public interface ISchedulingTaskExecutor : ITaskExecutor - { - /// - /// Gets a value indicating whether´this instance prefers short lived tasks. - /// - /// - /// true if prefers short lived tasks; otherwise, false. - /// - bool PrefersShortLivedTasks { get; } - } -} \ No newline at end of file + /// + /// true if prefers short lived tasks; otherwise, false. + /// + bool PrefersShortLivedTasks { get; } +} diff --git a/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/ITaskExecutor.cs b/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/ITaskExecutor.cs index d8acdca1..81d7e1eb 100644 --- a/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/ITaskExecutor.cs +++ b/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/ITaskExecutor.cs @@ -1,29 +1,28 @@ /* -* Copyright 2002-2010 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. -*/ + * Copyright 2002-2010 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. + */ -namespace Spring.Scheduling +namespace Spring.Scheduling; + +/// +/// +/// +public interface ITaskExecutor { /// - /// + /// Executes this instance. /// - public interface ITaskExecutor - { - /// - /// Executes this instance. - /// - void Execute(ThreadStart runnable); - } + void Execute(ThreadStart runnable); } diff --git a/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/IThreadRunnable.cs b/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/IThreadRunnable.cs index 6a872c7e..ed576aaa 100644 --- a/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/IThreadRunnable.cs +++ b/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/IThreadRunnable.cs @@ -1,4 +1,5 @@ #region License + // /* // * Copyright 2018 the original author or authors. // * @@ -14,18 +15,18 @@ // * See the License for the specific language governing permissions and // * limitations under the License. // */ + #endregion -namespace Spring.Scheduling.Quartz +namespace Spring.Scheduling.Quartz; + +/// +/// Adapter interface as Quartz no longer has this interface. +/// +public interface IThreadRunnable { /// - /// Adapter interface as Quartz no longer has this interface. + /// Runs thread runnable. /// - public interface IThreadRunnable - { - /// - /// Runs thread runnable. - /// - Task Run(); - } + Task Run(); } diff --git a/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/JobDetailObject.cs b/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/JobDetailObject.cs index bb8b5028..98dcd085 100644 --- a/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/JobDetailObject.cs +++ b/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/JobDetailObject.cs @@ -1,18 +1,18 @@ /* -* Copyright 2002-2010 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. -*/ + * Copyright 2002-2010 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. + */ using System.Collections; using Quartz; @@ -20,204 +20,203 @@ using Quartz.Impl; using Spring.Context; using Spring.Objects.Factory; -namespace Spring.Scheduling.Quartz +namespace Spring.Scheduling.Quartz; + +/// +/// Convenience subclass of Quartz' JobDetail class that eases properties based +/// usage. +/// +/// +/// itself is already a object but lacks +/// sensible defaults. This class uses the Spring object name as job name, +/// and the Quartz default group ("DEFAULT") as job group if not specified. +/// +/// Juergen Hoeller +/// +/// +public class JobDetailObject : JobDetailImpl, IObjectNameAware, IApplicationContextAware, IInitializingObject { + private Type actualJobType; + private string objectName; + private IApplicationContext applicationContext; + private string applicationContextJobDataKey; + /// - /// Convenience subclass of Quartz' JobDetail class that eases properties based - /// usage. + /// Overridden to support any job class, to allow a custom JobFactory + /// to adapt the given job class to the Quartz Job interface. /// - /// - /// itself is already a object but lacks - /// sensible defaults. This class uses the Spring object name as job name, - /// and the Quartz default group ("DEFAULT") as job group if not specified. - /// - /// Juergen Hoeller - /// - /// - public class JobDetailObject : JobDetailImpl, IObjectNameAware, IApplicationContextAware, IInitializingObject + /// + public override Type JobType { - private Type actualJobType; - private string objectName; - private IApplicationContext applicationContext; - private string applicationContextJobDataKey; + get => actualJobType ?? base.JobType; - /// - /// Overridden to support any job class, to allow a custom JobFactory - /// to adapt the given job class to the Quartz Job interface. - /// - /// - public override Type JobType + set { - get => actualJobType ?? base.JobType; - - set + if (value != null && !typeof(IJob).IsAssignableFrom(value)) { - if (value != null && !typeof(IJob).IsAssignableFrom(value)) - { - base.JobType = typeof(DelegatingJob); - actualJobType = value; - } - else - { - base.JobType = value; - } + base.JobType = typeof(DelegatingJob); + actualJobType = value; } - } - - /// - /// Register objects in the JobDataMap via a given Map. - /// - /// - /// These objects will be available to this Job only, - /// in contrast to objects in the SchedulerContext. - ///

- /// Note: When using persistent Jobs whose JobDetail will be kept in the - /// database, do not put Spring-managed objects or an ApplicationContext - /// reference into the JobDataMap but rather into the SchedulerContext. - ///

- ///
- /// - public virtual IDictionary JobDataAsMap - { - set + else { - if (value == null) - { - throw new ArgumentException("Value cannot be null", "value"); - } - - foreach (DictionaryEntry entry in value) - { - JobDataMap.Put((string) entry.Key, entry.Value); - } - } - } - - /// - /// Set the name of the object in the object factory that created this object. - /// - /// The name of the object in the factory. - /// - /// Invoked after population of normal object properties but before an init - /// callback like 's - /// - /// method or a custom init-method. - /// - public virtual string ObjectName - { - set => objectName = value; - } - - /// - /// Gets or sets the that this - /// object runs in. - /// - /// - /// - ///

- /// Normally this call will be used to initialize the object. - ///

- ///

- /// Invoked after population of normal object properties but before an - /// init callback such as - /// 's - /// - /// or a custom init-method. Invoked after the setting of any - /// 's - /// - /// property. - ///

- ///
- /// - /// In the case of application context initialization errors. - /// - /// - /// If thrown by any application context methods. - /// - /// - public virtual IApplicationContext ApplicationContext - { - set => applicationContext = value; - get => applicationContext; - } - - /// - /// Set the key of an IApplicationContext reference to expose in the JobDataMap, - /// for example "applicationContext". Default is none. - /// Only applicable when running in a Spring ApplicationContext. - /// - /// - ///

- /// In case of a QuartzJobObject, the reference will be applied to the Job - /// instance as object property. An "applicationContext" attribute will correspond - /// to a "setApplicationContext" method in that scenario. - ///

- ///

- /// Note that ObjectFactory callback interfaces like IApplicationContextAware - /// are not automatically applied to Quartz Job instances, because Quartz - /// itself is responsible for the lifecycle of its Jobs. - ///

- ///

- /// Note: When using persistent job stores where JobDetail contents will - /// be kept in the database, do not put an IApplicationContext reference into - /// the JobDataMap but rather into the SchedulerContext. - ///

- ///
- /// - /// - public virtual string ApplicationContextJobDataKey - { - set => applicationContextJobDataKey = value; - } - - /// - /// Invoked by an - /// after it has injected all of an object's dependencies. - /// - /// - ///

- /// This method allows the object instance to perform the kind of - /// initialization only possible when all of it's dependencies have - /// been injected (set), and to throw an appropriate exception in the - /// event of misconfiguration. - ///

- ///

- /// Please do consult the class level documentation for the - /// interface for a - /// description of exactly when this method is invoked. In - /// particular, it is worth noting that the - /// - /// and - /// callbacks will have been invoked prior to this method being - /// called. - ///

- ///
- /// - /// In the event of misconfiguration (such as the failure to set a - /// required property) or if initialization fails. - /// - public virtual void AfterPropertiesSet() - { - if (Name == null) - { - Name = objectName; - } - - if (Group == null) - { - Group = SchedulerConstants.DefaultGroup; - } - - if (applicationContextJobDataKey != null) - { - if (applicationContext == null) - { - throw new ArgumentException("JobDetailObject needs to be set up in an IApplicationContext " + - "to be able to handle an 'applicationContextJobDataKey'"); - } - - JobDataMap.Put(applicationContextJobDataKey, applicationContext); + base.JobType = value; } } } + + /// + /// Register objects in the JobDataMap via a given Map. + /// + /// + /// These objects will be available to this Job only, + /// in contrast to objects in the SchedulerContext. + ///

+ /// Note: When using persistent Jobs whose JobDetail will be kept in the + /// database, do not put Spring-managed objects or an ApplicationContext + /// reference into the JobDataMap but rather into the SchedulerContext. + ///

+ ///
+ /// + public virtual IDictionary JobDataAsMap + { + set + { + if (value == null) + { + throw new ArgumentException("Value cannot be null", "value"); + } + + foreach (DictionaryEntry entry in value) + { + JobDataMap.Put((string) entry.Key, entry.Value); + } + } + } + + /// + /// Set the name of the object in the object factory that created this object. + /// + /// The name of the object in the factory. + /// + /// Invoked after population of normal object properties but before an init + /// callback like 's + /// + /// method or a custom init-method. + /// + public virtual string ObjectName + { + set => objectName = value; + } + + /// + /// Gets or sets the that this + /// object runs in. + /// + /// + /// + ///

+ /// Normally this call will be used to initialize the object. + ///

+ ///

+ /// Invoked after population of normal object properties but before an + /// init callback such as + /// 's + /// + /// or a custom init-method. Invoked after the setting of any + /// 's + /// + /// property. + ///

+ ///
+ /// + /// In the case of application context initialization errors. + /// + /// + /// If thrown by any application context methods. + /// + /// + public virtual IApplicationContext ApplicationContext + { + set => applicationContext = value; + get => applicationContext; + } + + /// + /// Set the key of an IApplicationContext reference to expose in the JobDataMap, + /// for example "applicationContext". Default is none. + /// Only applicable when running in a Spring ApplicationContext. + /// + /// + ///

+ /// In case of a QuartzJobObject, the reference will be applied to the Job + /// instance as object property. An "applicationContext" attribute will correspond + /// to a "setApplicationContext" method in that scenario. + ///

+ ///

+ /// Note that ObjectFactory callback interfaces like IApplicationContextAware + /// are not automatically applied to Quartz Job instances, because Quartz + /// itself is responsible for the lifecycle of its Jobs. + ///

+ ///

+ /// Note: When using persistent job stores where JobDetail contents will + /// be kept in the database, do not put an IApplicationContext reference into + /// the JobDataMap but rather into the SchedulerContext. + ///

+ ///
+ /// + /// + public virtual string ApplicationContextJobDataKey + { + set => applicationContextJobDataKey = value; + } + + /// + /// Invoked by an + /// after it has injected all of an object's dependencies. + /// + /// + ///

+ /// This method allows the object instance to perform the kind of + /// initialization only possible when all of it's dependencies have + /// been injected (set), and to throw an appropriate exception in the + /// event of misconfiguration. + ///

+ ///

+ /// Please do consult the class level documentation for the + /// interface for a + /// description of exactly when this method is invoked. In + /// particular, it is worth noting that the + /// + /// and + /// callbacks will have been invoked prior to this method being + /// called. + ///

+ ///
+ /// + /// In the event of misconfiguration (such as the failure to set a + /// required property) or if initialization fails. + /// + public virtual void AfterPropertiesSet() + { + if (Name == null) + { + Name = objectName; + } + + if (Group == null) + { + Group = SchedulerConstants.DefaultGroup; + } + + if (applicationContextJobDataKey != null) + { + if (applicationContext == null) + { + throw new ArgumentException("JobDetailObject needs to be set up in an IApplicationContext " + + "to be able to handle an 'applicationContextJobDataKey'"); + } + + JobDataMap.Put(applicationContextJobDataKey, applicationContext); + } + } } diff --git a/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/JobMethodInvocationFailedException.cs b/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/JobMethodInvocationFailedException.cs index 36837525..e831d411 100644 --- a/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/JobMethodInvocationFailedException.cs +++ b/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/JobMethodInvocationFailedException.cs @@ -16,26 +16,25 @@ using Spring.Objects.Support; -namespace Spring.Scheduling.Quartz +namespace Spring.Scheduling.Quartz; + +/// +/// Exception that wraps an exception thrown from a target method. +/// Propagated to the Quartz scheduler from a Job that reflectively invokes +/// an arbitrary target method. +/// +/// Juergen Hoeller +/// +public class JobMethodInvocationFailedException : Exception // TODO, in Java NestedRuntimeException { /// - /// Exception that wraps an exception thrown from a target method. - /// Propagated to the Quartz scheduler from a Job that reflectively invokes - /// an arbitrary target method. + /// Constructor for JobMethodInvocationFailedException. /// - /// Juergen Hoeller - /// - public class JobMethodInvocationFailedException : Exception // TODO, in Java NestedRuntimeException + /// the MethodInvoker used for reflective invocation + /// the root cause (as thrown from the target method) + public JobMethodInvocationFailedException(MethodInvoker methodInvoker, Exception cause) : + base("Invocation of method '" + methodInvoker.TargetMethod + + "' on target class [" + methodInvoker.TargetType + "] failed", cause) { - /// - /// Constructor for JobMethodInvocationFailedException. - /// - /// the MethodInvoker used for reflective invocation - /// the root cause (as thrown from the target method) - public JobMethodInvocationFailedException(MethodInvoker methodInvoker, Exception cause) : - base("Invocation of method '" + methodInvoker.TargetMethod + - "' on target class [" + methodInvoker.TargetType + "] failed", cause) - { - } } } diff --git a/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/LocalDataSourceJobStore.cs b/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/LocalDataSourceJobStore.cs index c3cd83bf..10a6dcc0 100644 --- a/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/LocalDataSourceJobStore.cs +++ b/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/LocalDataSourceJobStore.cs @@ -20,83 +20,82 @@ using Quartz.Impl.AdoJobStore; using Quartz.Util; using Spring.Data.Support; -namespace Spring.Scheduling.Quartz +namespace Spring.Scheduling.Quartz; + +/// +/// Subclass of Quartz's JobStoreCMT class that delegates to a Spring-managed +/// DataSource instead of using a Quartz-managed connection pool. This JobStore +/// will be used if SchedulerFactoryObject's "dbProvider" property is set. +/// +/// +///

Operations performed by this JobStore will properly participate in any +/// kind of Spring-managed transaction, as it uses Spring's DataSourceUtils +/// connection handling methods that are aware of a current transaction.

+/// +///

Note that all Quartz Scheduler operations that affect the persistent +/// job store should usually be performed within active transactions, +/// as they assume to get proper locks etc.

+///
+/// Juergen Hoeller +/// Marko Lahma (.NET) +/// +/// +public class LocalDataSourceJobStore : JobStoreCMT { /// - /// Subclass of Quartz's JobStoreCMT class that delegates to a Spring-managed - /// DataSource instead of using a Quartz-managed connection pool. This JobStore - /// will be used if SchedulerFactoryObject's "dbProvider" property is set. - /// - /// - ///

Operations performed by this JobStore will properly participate in any - /// kind of Spring-managed transaction, as it uses Spring's DataSourceUtils - /// connection handling methods that are aware of a current transaction.

- /// - ///

Note that all Quartz Scheduler operations that affect the persistent - /// job store should usually be performed within active transactions, - /// as they assume to get proper locks etc.

- ///
- /// Juergen Hoeller - /// Marko Lahma (.NET) - /// - /// - public class LocalDataSourceJobStore : JobStoreCMT + /// Name used for the transactional ConnectionProvider for Quartz. + /// This provider will delegate to the local Spring-managed DataSource. + /// + /// + ///
+ public const string TxDataSourcePrefix = "springTxDataSource."; + + private Data.Common.IDbProvider dbProvider; + + /// + /// Gets or sets the name of the instance. + /// + /// The name of the instance. + public override string InstanceName { - /// - /// Name used for the transactional ConnectionProvider for Quartz. - /// This provider will delegate to the local Spring-managed DataSource. - /// - /// - /// - public const string TxDataSourcePrefix = "springTxDataSource."; - - private Data.Common.IDbProvider dbProvider; - - /// - /// Gets or sets the name of the instance. - /// - /// The name of the instance. - public override string InstanceName + get => base.InstanceName; + set { - get => base.InstanceName; - set + // use to catch property setting + base.InstanceName = value; + DataSource = TxDataSourcePrefix + InstanceName; + // Register transactional ConnectionProvider for Quartz. + // Absolutely needs thread-bound DataSource to initialize. + dbProvider = SchedulerFactoryObject.ConfigTimeDbProvider; + if (dbProvider == null) { - // use to catch property setting - base.InstanceName = value; - DataSource = TxDataSourcePrefix + InstanceName; - // Register transactional ConnectionProvider for Quartz. - // Absolutely needs thread-bound DataSource to initialize. - dbProvider = SchedulerFactoryObject.ConfigTimeDbProvider; - if (dbProvider == null) - { - throw new SchedulerConfigException( - "No db provider found for configuration - " + - "'DbProvider' property must be set on SchedulerFactoryObject"); - } - - DBConnectionManager.Instance.AddConnectionProvider( - TxDataSourcePrefix + InstanceName, new SpringDbProviderAdapter(dbProvider)); + throw new SchedulerConfigException( + "No db provider found for configuration - " + + "'DbProvider' property must be set on SchedulerFactoryObject"); } - } - /// - /// Gets the non managed TX connection. - /// - /// - protected override ConnectionAndTransactionHolder GetNonManagedTXConnection() - { - ConnectionTxPair pair = ConnectionUtils.DoGetConnection(dbProvider); - return new ConnectionAndTransactionHolder((DbConnection) pair.Connection, (DbTransaction) pair.Transaction); - } - - /// - /// Closes the connection. - /// - /// The connection and transaction holder. - protected override void CloseConnection(ConnectionAndTransactionHolder connectionAndTransactionHolder) - { - // Will work for transactional and non-transactional connections. - ConnectionUtils.DisposeConnection(connectionAndTransactionHolder.Connection, dbProvider); + DBConnectionManager.Instance.AddConnectionProvider( + TxDataSourcePrefix + InstanceName, new SpringDbProviderAdapter(dbProvider)); } } -} \ No newline at end of file + + /// + /// Gets the non managed TX connection. + /// + /// + protected override ConnectionAndTransactionHolder GetNonManagedTXConnection() + { + ConnectionTxPair pair = ConnectionUtils.DoGetConnection(dbProvider); + return new ConnectionAndTransactionHolder((DbConnection) pair.Connection, (DbTransaction) pair.Transaction); + } + + /// + /// Closes the connection. + /// + /// The connection and transaction holder. + protected override void CloseConnection(ConnectionAndTransactionHolder connectionAndTransactionHolder) + { + // Will work for transactional and non-transactional connections. + ConnectionUtils.DisposeConnection(connectionAndTransactionHolder.Connection, dbProvider); + } +} diff --git a/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/LocalTaskExecutorThreadPool.cs b/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/LocalTaskExecutorThreadPool.cs index bc65c99c..75631e2b 100644 --- a/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/LocalTaskExecutorThreadPool.cs +++ b/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/LocalTaskExecutorThreadPool.cs @@ -1,109 +1,108 @@ /* -* Copyright 2002-2010 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. -*/ + * Copyright 2002-2010 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. + */ using Microsoft.Extensions.Logging; using Quartz; using Quartz.Spi; -namespace Spring.Scheduling.Quartz +namespace Spring.Scheduling.Quartz; + +/// +/// Quartz ThreadPool adapter that delegates to a Spring-managed +/// TaskExecutor instance, specified on SchedulerFactoryObject. +/// +/// Juergen Hoeller +/// +public class LocalTaskExecutorThreadPool : IThreadPool { + private ITaskExecutor taskExecutor; + /// - /// Quartz ThreadPool adapter that delegates to a Spring-managed - /// TaskExecutor instance, specified on SchedulerFactoryObject. + /// Initializes a new instance of the class. /// - /// Juergen Hoeller - /// - public class LocalTaskExecutorThreadPool : IThreadPool + public LocalTaskExecutorThreadPool() { - private ITaskExecutor taskExecutor; + Logger = LogManager.GetLogger(GetType()); + } - /// - /// Initializes a new instance of the class. - /// - public LocalTaskExecutorThreadPool() + /// + /// Logger instance. + /// + protected ILogger Logger { get; } + + /// + public virtual int PoolSize => -1; + + /// + public string InstanceId + { + set { } + } + + /// + public string InstanceName + { + set { } + } + + /// + public virtual void Initialize() + { + // Absolutely needs thread-bound TaskExecutor to Initialize. + taskExecutor = SchedulerFactoryObject.ConfigTimeTaskExecutor; + if (taskExecutor == null) { - Logger = LogManager.GetLogger(GetType()); - } - - /// - /// Logger instance. - /// - protected ILogger Logger { get; } - - /// - public virtual int PoolSize => -1; - - /// - public string InstanceId - { - set { } - } - - /// - public string InstanceName - { - set { } - } - - /// - public virtual void Initialize() - { - // Absolutely needs thread-bound TaskExecutor to Initialize. - taskExecutor = SchedulerFactoryObject.ConfigTimeTaskExecutor; - if (taskExecutor == null) - { - throw new SchedulerConfigException("No local TaskExecutor found for configuration - " + - "'taskExecutor' property must be set on SchedulerFactoryObject"); - } - } - - /// - public virtual void Shutdown(bool waitForJobsToComplete) - { - } - - /// - public virtual bool RunInThread(Func runnable) - { - if (runnable == null) - { - return false; - } - - try - { - taskExecutor.Execute(() => runnable().ConfigureAwait(false).GetAwaiter().GetResult()); - return true; - } - catch (TaskRejectedException ex) - { - Logger.LogError(ex, "Task has been rejected by TaskExecutor"); - return false; - } - } - - /// - public virtual int BlockForAvailableThreads() - { - // The present implementation always returns 1, making Quartz (1.6) - // always schedule any tasks that it feels like scheduling. - // This could be made smarter for specific TaskExecutors, - // for example calling getMaximumPoolSize() - getActiveCount() - // on a java.util.concurrent.ThreadPoolExecutor. - return 1; + throw new SchedulerConfigException("No local TaskExecutor found for configuration - " + + "'taskExecutor' property must be set on SchedulerFactoryObject"); } } + + /// + public virtual void Shutdown(bool waitForJobsToComplete) + { + } + + /// + public virtual bool RunInThread(Func runnable) + { + if (runnable == null) + { + return false; + } + + try + { + taskExecutor.Execute(() => runnable().ConfigureAwait(false).GetAwaiter().GetResult()); + return true; + } + catch (TaskRejectedException ex) + { + Logger.LogError(ex, "Task has been rejected by TaskExecutor"); + return false; + } + } + + /// + public virtual int BlockForAvailableThreads() + { + // The present implementation always returns 1, making Quartz (1.6) + // always schedule any tasks that it feels like scheduling. + // This could be made smarter for specific TaskExecutors, + // for example calling getMaximumPoolSize() - getActiveCount() + // on a java.util.concurrent.ThreadPoolExecutor. + return 1; + } } diff --git a/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/MethodInvokingJob.cs b/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/MethodInvokingJob.cs index f0124d7c..d6ce29cd 100644 --- a/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/MethodInvokingJob.cs +++ b/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/MethodInvokingJob.cs @@ -1,83 +1,82 @@ /* -* Copyright 2002-2010 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. -*/ + * Copyright 2002-2010 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. + */ using System.Reflection; using Microsoft.Extensions.Logging; using Quartz; using Spring.Objects.Support; -namespace Spring.Scheduling.Quartz +namespace Spring.Scheduling.Quartz; + +/// +/// Quartz Job implementation that invokes a specified method. +/// Automatically applied by MethodInvokingJobDetailFactoryObject. +/// +public class MethodInvokingJob : QuartzJobObject { - /// - /// Quartz Job implementation that invokes a specified method. - /// Automatically applied by MethodInvokingJobDetailFactoryObject. + private static readonly ILogger logger = LogManager.GetLogger(); + private MethodInvoker methodInvoker; + private string errorMessage; + + /// + /// Set the MethodInvoker to use. /// - public class MethodInvokingJob : QuartzJobObject + public virtual MethodInvoker MethodInvoker { - private static readonly ILogger logger = LogManager.GetLogger(); - private MethodInvoker methodInvoker; - private string errorMessage; - - /// - /// Set the MethodInvoker to use. - /// - public virtual MethodInvoker MethodInvoker + set { - set - { - methodInvoker = value ?? throw new ArgumentException("Method invoker cannot be null", nameof(value)); - errorMessage = - $"Could not invoke method '{methodInvoker.TargetMethod}' on target object [{methodInvoker.TargetObject}]"; - } - } - - /// - /// Invoke the method via the MethodInvoker. - /// - /// - protected override Task ExecuteInternal(IJobExecutionContext context) - { - if (methodInvoker == null) - { - throw new JobExecutionException("Could not execute job when method invoker is null"); - } - - try - { - context.Result = methodInvoker.Invoke(); - } - catch (TargetInvocationException ex) - { - logger.LogError(ex.GetBaseException(), errorMessage); - if (ex.GetBaseException() is JobExecutionException) - { - // -> JobExecutionException, to be logged at info level by Quartz - throw ex.GetBaseException(); - } - - // -> "unhandled exception", to be logged at error level by Quartz - throw new JobMethodInvocationFailedException(methodInvoker, ex.GetBaseException()); - } - catch (Exception ex) - { - // -> "unhandled exception", to be logged at error level by Quartz - throw new JobMethodInvocationFailedException(methodInvoker, ex.GetBaseException()); - } - - return Task.FromResult(true); + methodInvoker = value ?? throw new ArgumentException("Method invoker cannot be null", nameof(value)); + errorMessage = + $"Could not invoke method '{methodInvoker.TargetMethod}' on target object [{methodInvoker.TargetObject}]"; } } + + /// + /// Invoke the method via the MethodInvoker. + /// + /// + protected override Task ExecuteInternal(IJobExecutionContext context) + { + if (methodInvoker == null) + { + throw new JobExecutionException("Could not execute job when method invoker is null"); + } + + try + { + context.Result = methodInvoker.Invoke(); + } + catch (TargetInvocationException ex) + { + logger.LogError(ex.GetBaseException(), errorMessage); + if (ex.GetBaseException() is JobExecutionException) + { + // -> JobExecutionException, to be logged at info level by Quartz + throw ex.GetBaseException(); + } + + // -> "unhandled exception", to be logged at error level by Quartz + throw new JobMethodInvocationFailedException(methodInvoker, ex.GetBaseException()); + } + catch (Exception ex) + { + // -> "unhandled exception", to be logged at error level by Quartz + throw new JobMethodInvocationFailedException(methodInvoker, ex.GetBaseException()); + } + + return Task.FromResult(true); + } } diff --git a/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/MethodInvokingJobDetailFactoryObject.cs b/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/MethodInvokingJobDetailFactoryObject.cs index 6277980e..04be8291 100644 --- a/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/MethodInvokingJobDetailFactoryObject.cs +++ b/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/MethodInvokingJobDetailFactoryObject.cs @@ -1,18 +1,18 @@ /* -* Copyright 2002-2010 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. -*/ + * Copyright 2002-2010 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. + */ using Quartz; using Quartz.Impl; @@ -20,264 +20,263 @@ using Spring.Objects.Factory; using Spring.Objects.Factory.Config; using Spring.Objects.Support; -namespace Spring.Scheduling.Quartz +namespace Spring.Scheduling.Quartz; + +/// +/// IFactoryObject that exposes a JobDetail object that delegates job execution +/// to a specified (static or non-static) method. Avoids the need to implement +/// a one-line Quartz Job that just invokes an existing service method. +/// +/// +///

+/// Derived from ArgumentConverting MethodInvoker to share common properties and behavior +/// with MethodInvokingFactoryObject. +///

+///

+/// Supports both concurrently running jobs and non-currently running +/// ones through the "concurrent" property. Jobs created by this +/// MethodInvokingJobDetailFactoryObject are by default volatile and durable +/// (according to Quartz terminology). +///

+///

NOTE: JobDetails created via this FactoryObject are not +/// serializable and thus not suitable for persistent job stores. +/// You need to implement your own Quartz Job as a thin wrapper for each case +/// where you want a persistent job to delegate to a specific service method. +///

+///
+/// Juergen Hoeller +/// Alef Arendsen +/// +/// +public class MethodInvokingJobDetailFactoryObject : ArgumentConvertingMethodInvoker, + IObjectFactoryAware, + IFactoryObject, + IObjectNameAware, + IInitializingObject { + private string name; + private string group; + private bool concurrent = true; + private string[] jobListenerNames; + private string targetObjectName; + private string objectName; + private JobDetailImpl jobDetail; + private IObjectFactory objectFactory; + /// - /// IFactoryObject that exposes a JobDetail object that delegates job execution - /// to a specified (static or non-static) method. Avoids the need to implement - /// a one-line Quartz Job that just invokes an existing service method. + /// Initializes a new instance of the class. + /// + public MethodInvokingJobDetailFactoryObject() + { + group = SchedulerConstants.DefaultGroup; + } + + /// + /// Set the name of the job. + /// Default is the object name of this FactoryObject. + /// + /// + public virtual string Name + { + set => name = value; + } + + /// + /// Set the group of the job. + /// Default is the default group of the Scheduler. + /// + /// + /// + public virtual string Group + { + set => group = value; + } + + /// + /// Specify whether or not multiple jobs should be run in a concurrent + /// fashion. The behavior when one does not want concurrent jobs to be + /// executed is realized through adding the attribute. + /// More information on stateful versus stateless jobs can be found + /// here. + ///

+ /// The default setting is to run jobs concurrently. + ///

+ ///
+ public virtual bool Concurrent + { + set => concurrent = value; + } + + /// + /// Gets the job detail. + /// + /// The job detail. + protected IJobDetail JobDetail => jobDetail; + + /// + /// Set a list of JobListener names for this job, referring to + /// non-global JobListeners registered with the Scheduler. + /// + /// + /// A JobListener name always refers to the name returned + /// by the JobListener implementation. + /// + /// + /// + public virtual string[] JobListenerNames + { + set => jobListenerNames = value; + } + + /// + /// Set the name of the object in the object factory that created this object. + /// + /// The name of the object in the factory. + /// + /// Invoked after population of normal object properties but before an init + /// callback like 's + /// + /// method or a custom init-method. + /// + public virtual string ObjectName + { + set => objectName = value; + } + + /// + /// Set the name of the target object in the Spring object factory. + /// + /// + /// This is an alternative to specifying TargetObject + /// allowing for non-singleton objects to be invoked. Note that specified + /// "TargetObject" and "TargetType" values will + /// override the corresponding effect of this "TargetObjectName" setting + ///(i.e. statically pre-define the object type or even the target object). + /// + public string TargetObjectName + { + set => targetObjectName = value; + } + + /// + /// Sets the object factory. + /// + /// The object factory. + public IObjectFactory ObjectFactory + { + set => objectFactory = value; + } + + /// + /// Return an instance (possibly shared or independent) of the object + /// managed by this factory. + /// + /// + /// An instance (possibly shared or independent) of the object managed by + /// this factory. + /// + /// + /// + /// If this method is being called in the context of an enclosing IoC container and + /// returns , the IoC container will consider this factory + /// object as not being fully initialized and throw a corresponding (and most + /// probably fatal) exception. + /// + /// + public virtual object GetObject() + { + return jobDetail; + } + + /// + /// Return the of object that this + /// creates, or + /// if not known in advance. + /// + /// + public virtual Type ObjectType + { + get + { + if (targetObjectName != null) + { + if (objectFactory == null) + { + throw new InvalidOperationException("ObjectFactory must be set when using 'TargetObjectName'"); + } + + return objectFactory.GetType(targetObjectName); + } + + return typeof(IJobDetail); + } + } + + /// + /// Is the object managed by this factory a singleton or a prototype? + /// + /// + public virtual bool IsSingleton => true; + + /// + /// Invoked by an + /// after it has injected all of an object's dependencies. /// /// ///

- /// Derived from ArgumentConverting MethodInvoker to share common properties and behavior - /// with MethodInvokingFactoryObject. + /// This method allows the object instance to perform the kind of + /// initialization only possible when all of it's dependencies have + /// been injected (set), and to throw an appropriate exception in the + /// event of misconfiguration. ///

- ///

- /// Supports both concurrently running jobs and non-currently running - /// ones through the "concurrent" property. Jobs created by this - /// MethodInvokingJobDetailFactoryObject are by default volatile and durable - /// (according to Quartz terminology). - ///

- ///

NOTE: JobDetails created via this FactoryObject are not - /// serializable and thus not suitable for persistent job stores. - /// You need to implement your own Quartz Job as a thin wrapper for each case - /// where you want a persistent job to delegate to a specific service method. + ///

+ /// Please do consult the class level documentation for the + /// interface for a + /// description of exactly when this method is invoked. In + /// particular, it is worth noting that the + /// + /// and + /// callbacks will have been invoked prior to this method being + /// called. ///

///
- /// Juergen Hoeller - /// Alef Arendsen - /// - /// - public class MethodInvokingJobDetailFactoryObject : ArgumentConvertingMethodInvoker, - IObjectFactoryAware, - IFactoryObject, - IObjectNameAware, - IInitializingObject + /// + /// In the event of misconfiguration (such as the failure to set a + /// required property) or if initialization fails. + /// + public virtual void AfterPropertiesSet() { - private string name; - private string group; - private bool concurrent = true; - private string[] jobListenerNames; - private string targetObjectName; - private string objectName; - private JobDetailImpl jobDetail; - private IObjectFactory objectFactory; + Prepare(); - /// - /// Initializes a new instance of the class. - /// - public MethodInvokingJobDetailFactoryObject() + // Use specific name if given, else fall back to object name. + string jobDetailName = name ?? objectName; + + // Consider the concurrent flag to choose between stateful and stateless job. + Type jobType = (concurrent ? typeof(MethodInvokingJob) : typeof(StatefulMethodInvokingJob)); + + // Build JobDetail instance. + jobDetail = new JobDetailImpl(jobDetailName, group, jobType); + jobDetail.JobDataMap.Put("methodInvoker", this); + jobDetail.Durable = true; + + // job listeners through configuration are no longer supported + if (jobListenerNames != null && jobListenerNames.Length > 0) { - group = SchedulerConstants.DefaultGroup; + throw new InvalidOperationException("Non-global IJobListeners not supported on Quartz 2 - " + + "manually register a Matcher against the Quartz ListenerManager instead"); } - /// - /// Set the name of the job. - /// Default is the object name of this FactoryObject. - /// - /// - public virtual string Name - { - set => name = value; - } - - /// - /// Set the group of the job. - /// Default is the default group of the Scheduler. - /// - /// - /// - public virtual string Group - { - set => group = value; - } - - /// - /// Specify whether or not multiple jobs should be run in a concurrent - /// fashion. The behavior when one does not want concurrent jobs to be - /// executed is realized through adding the attribute. - /// More information on stateful versus stateless jobs can be found - /// here. - ///

- /// The default setting is to run jobs concurrently. - ///

- ///
- public virtual bool Concurrent - { - set => concurrent = value; - } - - /// - /// Gets the job detail. - /// - /// The job detail. - protected IJobDetail JobDetail => jobDetail; - - /// - /// Set a list of JobListener names for this job, referring to - /// non-global JobListeners registered with the Scheduler. - /// - /// - /// A JobListener name always refers to the name returned - /// by the JobListener implementation. - /// - /// - /// - public virtual string[] JobListenerNames - { - set => jobListenerNames = value; - } - - /// - /// Set the name of the object in the object factory that created this object. - /// - /// The name of the object in the factory. - /// - /// Invoked after population of normal object properties but before an init - /// callback like 's - /// - /// method or a custom init-method. - /// - public virtual string ObjectName - { - set => objectName = value; - } - - /// - /// Set the name of the target object in the Spring object factory. - /// - /// - /// This is an alternative to specifying TargetObject - /// allowing for non-singleton objects to be invoked. Note that specified - /// "TargetObject" and "TargetType" values will - /// override the corresponding effect of this "TargetObjectName" setting - ///(i.e. statically pre-define the object type or even the target object). - /// - public string TargetObjectName - { - set => targetObjectName = value; - } - - /// - /// Sets the object factory. - /// - /// The object factory. - public IObjectFactory ObjectFactory - { - set => objectFactory = value; - } - - /// - /// Return an instance (possibly shared or independent) of the object - /// managed by this factory. - /// - /// - /// An instance (possibly shared or independent) of the object managed by - /// this factory. - /// - /// - /// - /// If this method is being called in the context of an enclosing IoC container and - /// returns , the IoC container will consider this factory - /// object as not being fully initialized and throw a corresponding (and most - /// probably fatal) exception. - /// - /// - public virtual object GetObject() - { - return jobDetail; - } - - /// - /// Return the of object that this - /// creates, or - /// if not known in advance. - /// - /// - public virtual Type ObjectType - { - get - { - if (targetObjectName != null) - { - if (objectFactory == null) - { - throw new InvalidOperationException("ObjectFactory must be set when using 'TargetObjectName'"); - } - - return objectFactory.GetType(targetObjectName); - } - - return typeof(IJobDetail); - } - } - - /// - /// Is the object managed by this factory a singleton or a prototype? - /// - /// - public virtual bool IsSingleton => true; - - /// - /// Invoked by an - /// after it has injected all of an object's dependencies. - /// - /// - ///

- /// This method allows the object instance to perform the kind of - /// initialization only possible when all of it's dependencies have - /// been injected (set), and to throw an appropriate exception in the - /// event of misconfiguration. - ///

- ///

- /// Please do consult the class level documentation for the - /// interface for a - /// description of exactly when this method is invoked. In - /// particular, it is worth noting that the - /// - /// and - /// callbacks will have been invoked prior to this method being - /// called. - ///

- ///
- /// - /// In the event of misconfiguration (such as the failure to set a - /// required property) or if initialization fails. - /// - public virtual void AfterPropertiesSet() - { - Prepare(); - - // Use specific name if given, else fall back to object name. - string jobDetailName = name ?? objectName; - - // Consider the concurrent flag to choose between stateful and stateless job. - Type jobType = (concurrent ? typeof(MethodInvokingJob) : typeof(StatefulMethodInvokingJob)); - - // Build JobDetail instance. - jobDetail = new JobDetailImpl(jobDetailName, group, jobType); - jobDetail.JobDataMap.Put("methodInvoker", this); - jobDetail.Durable = true; - - // job listeners through configuration are no longer supported - if (jobListenerNames != null && jobListenerNames.Length > 0) - { - throw new InvalidOperationException("Non-global IJobListeners not supported on Quartz 2 - " + - "manually register a Matcher against the Quartz ListenerManager instead"); - } - - PostProcessJobDetail(jobDetail); - } - - /// - /// Callback for post-processing the JobDetail to be exposed by this FactoryObject. - ///

- /// The default implementation is empty. Can be overridden in subclasses. - ///

- ///
- /// the JobDetail prepared by this FactoryObject - protected virtual void PostProcessJobDetail(IJobDetail detail) - { - } + PostProcessJobDetail(jobDetail); } -} + + /// + /// Callback for post-processing the JobDetail to be exposed by this FactoryObject. + ///

+ /// The default implementation is empty. Can be overridden in subclasses. + ///

+ ///
+ /// the JobDetail prepared by this FactoryObject + protected virtual void PostProcessJobDetail(IJobDetail detail) + { + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/MethodInvokingRunnable.cs b/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/MethodInvokingRunnable.cs index 0f46f07c..57b99eaa 100644 --- a/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/MethodInvokingRunnable.cs +++ b/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/MethodInvokingRunnable.cs @@ -1,119 +1,118 @@ /* -* Copyright 2002-2010 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. -*/ + * Copyright 2002-2010 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. + */ using System.Reflection; using Microsoft.Extensions.Logging; using Spring.Objects.Factory; using Spring.Objects.Support; -namespace Spring.Scheduling.Quartz +namespace Spring.Scheduling.Quartz; + +/// +/// Adapter that implements the Runnable interface as a configurable +/// method invocation based on Spring's MethodInvoker. +/// +/// +///

+/// Derives from ArgumentConvertingMethodInvoker, inheriting common +/// configuration properties from MethodInvoker. +///

+///
+/// Juergen Hoeller +/// +/// +public class MethodInvokingRunnable : ArgumentConvertingMethodInvoker, IInitializingObject, IThreadRunnable { - /// - /// Adapter that implements the Runnable interface as a configurable - /// method invocation based on Spring's MethodInvoker. + /// + /// Logger instance shared by this instance and its sub-class instances. + /// + private readonly ILogger logger; + + /// + /// Initializes a new instance of the class. + /// + public MethodInvokingRunnable() + { + logger = LogManager.GetLogger(GetType()); + } + + /// + /// Logger instance. + /// + protected ILogger Logger => logger; + + /// + /// Gets the invocation failure message. + /// + /// The invocation failure message. + protected virtual string InvocationFailureMessage => + $"Invocation of method '{TargetMethod}' on target object [{TargetObject}] failed"; + + /// + /// Invoked by an + /// after it has injected all of an object's dependencies. /// /// - ///

- /// Derives from ArgumentConvertingMethodInvoker, inheriting common - /// configuration properties from MethodInvoker. + ///

+ /// This method allows the object instance to perform the kind of + /// initialization only possible when all of it's dependencies have + /// been injected (set), and to throw an appropriate exception in the + /// event of misconfiguration. + ///

+ ///

+ /// Please do consult the class level documentation for the + /// interface for a + /// description of exactly when this method is invoked. In + /// particular, it is worth noting that the + /// + /// and + /// callbacks will have been invoked prior to this method being + /// called. ///

///
- /// Juergen Hoeller - /// - /// - public class MethodInvokingRunnable : ArgumentConvertingMethodInvoker, IInitializingObject, IThreadRunnable + /// + /// In the event of misconfiguration (such as the failure to set a + /// required property) or if initialization fails. + /// + public virtual void AfterPropertiesSet() { - /// - /// Logger instance shared by this instance and its sub-class instances. - /// - private readonly ILogger logger; + Prepare(); + } - /// - /// Initializes a new instance of the class. - /// - public MethodInvokingRunnable() + /// + /// This method has to be implemented in order that starting of the thread causes the object's + /// run method to be called in that separately executing thread. + /// + public virtual Task Run() + { + try { - logger = LogManager.GetLogger(GetType()); + Invoke(); + } + catch (TargetInvocationException ex) + { + logger.LogError(ex, InvocationFailureMessage); + // Do not throw exception, else the main loop of the Timer will stop! + } + catch (Exception ex) + { + logger.LogError(ex, InvocationFailureMessage); + // Do not throw exception, else the main loop of the Timer will stop! } - /// - /// Logger instance. - /// - protected ILogger Logger => logger; - - /// - /// Gets the invocation failure message. - /// - /// The invocation failure message. - protected virtual string InvocationFailureMessage => - $"Invocation of method '{TargetMethod}' on target object [{TargetObject}] failed"; - - /// - /// Invoked by an - /// after it has injected all of an object's dependencies. - /// - /// - ///

- /// This method allows the object instance to perform the kind of - /// initialization only possible when all of it's dependencies have - /// been injected (set), and to throw an appropriate exception in the - /// event of misconfiguration. - ///

- ///

- /// Please do consult the class level documentation for the - /// interface for a - /// description of exactly when this method is invoked. In - /// particular, it is worth noting that the - /// - /// and - /// callbacks will have been invoked prior to this method being - /// called. - ///

- ///
- /// - /// In the event of misconfiguration (such as the failure to set a - /// required property) or if initialization fails. - /// - public virtual void AfterPropertiesSet() - { - Prepare(); - } - - /// - /// This method has to be implemented in order that starting of the thread causes the object's - /// run method to be called in that separately executing thread. - /// - public virtual Task Run() - { - try - { - Invoke(); - } - catch (TargetInvocationException ex) - { - logger.LogError(ex, InvocationFailureMessage); - // Do not throw exception, else the main loop of the Timer will stop! - } - catch (Exception ex) - { - logger.LogError(ex, InvocationFailureMessage); - // Do not throw exception, else the main loop of the Timer will stop! - } - - return Task.FromResult(true); - } + return Task.FromResult(true); } } diff --git a/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/QuartzJobObject.cs b/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/QuartzJobObject.cs index 369bceac..173383ce 100644 --- a/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/QuartzJobObject.cs +++ b/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/QuartzJobObject.cs @@ -1,85 +1,84 @@ /* -* Copyright 2002-2010 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. -*/ + * Copyright 2002-2010 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. + */ using Quartz; using Spring.Objects; -namespace Spring.Scheduling.Quartz -{ - /// - /// Simple implementation of the Quartz Job interface, applying the - /// passed-in JobDataMap and also the SchedulerContext as object property - /// values. This is appropriate because a new Job instance will be created - /// for each execution. JobDataMap entries will override SchedulerContext - /// entries with the same keys. - /// - /// - ///

- /// For example, let's assume that the JobDataMap contains a key - /// "myParam" with value "5": The Job implementation can then expose - /// a object property "myParam" of type int to receive such a value, - /// i.e. a method "setMyParam(int)". This will also work for complex - /// types like business objects etc. - ///

- /// - ///

- /// Note: The QuartzJobObject class itself only implements the standard - /// Quartz IJob interface. Let your subclass explicitly implement the - /// Quartz IStatefulJob interface to mark your concrete job object as stateful. - ///

- ///
- /// Juergen Hoeller - /// - /// - /// - /// - /// - /// - /// - public abstract class QuartzJobObject : IJob - { - /// - /// This implementation applies the passed-in job data map as object property - /// values, and delegates to ExecuteInternal afterwards. - /// - /// - public Task Execute(IJobExecutionContext context) - { - try - { - ObjectWrapper bw = new ObjectWrapper(this); - MutablePropertyValues pvs = new MutablePropertyValues(); - pvs.AddAll(context.Scheduler.Context); - pvs.AddAll(context.MergedJobDataMap); - bw.SetPropertyValues(pvs, true); - } - catch (SchedulerException ex) - { - throw new JobExecutionException(ex); - } +namespace Spring.Scheduling.Quartz; - return ExecuteInternal(context); +/// +/// Simple implementation of the Quartz Job interface, applying the +/// passed-in JobDataMap and also the SchedulerContext as object property +/// values. This is appropriate because a new Job instance will be created +/// for each execution. JobDataMap entries will override SchedulerContext +/// entries with the same keys. +/// +/// +///

+/// For example, let's assume that the JobDataMap contains a key +/// "myParam" with value "5": The Job implementation can then expose +/// a object property "myParam" of type int to receive such a value, +/// i.e. a method "setMyParam(int)". This will also work for complex +/// types like business objects etc. +///

+/// +///

+/// Note: The QuartzJobObject class itself only implements the standard +/// Quartz IJob interface. Let your subclass explicitly implement the +/// Quartz IStatefulJob interface to mark your concrete job object as stateful. +///

+///
+/// Juergen Hoeller +/// +/// +/// +/// +/// +/// +/// +public abstract class QuartzJobObject : IJob +{ + /// + /// This implementation applies the passed-in job data map as object property + /// values, and delegates to ExecuteInternal afterwards. + /// + /// + public Task Execute(IJobExecutionContext context) + { + try + { + ObjectWrapper bw = new ObjectWrapper(this); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.AddAll(context.Scheduler.Context); + pvs.AddAll(context.MergedJobDataMap); + bw.SetPropertyValues(pvs, true); + } + catch (SchedulerException ex) + { + throw new JobExecutionException(ex); } - /// - /// Execute the actual job. The job data map will already have been - /// applied as object property values by execute. The contract is - /// exactly the same as for the standard Quartz execute method. - /// - /// - protected abstract Task ExecuteInternal(IJobExecutionContext context); + return ExecuteInternal(context); } + + /// + /// Execute the actual job. The job data map will already have been + /// applied as object property values by execute. The contract is + /// exactly the same as for the standard Quartz execute method. + /// + /// + protected abstract Task ExecuteInternal(IJobExecutionContext context); } diff --git a/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/SchedulerAccessor.cs b/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/SchedulerAccessor.cs index 12d89ecf..dfcffebc 100644 --- a/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/SchedulerAccessor.cs +++ b/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/SchedulerAccessor.cs @@ -24,427 +24,426 @@ using Spring.Core.IO; using Spring.Transaction; using Spring.Transaction.Support; -namespace Spring.Scheduling.Quartz +namespace Spring.Scheduling.Quartz; + +/// +/// Common base class for accessing a Quartz Scheduler, i.e. for registering jobs, +/// triggers and listeners on a instance. +/// +/// +/// For concrete usage, check out the and +/// classes. +/// +/// Juergen Hoeller +/// Marko Lahma (.NET) +public abstract class SchedulerAccessor : IResourceLoaderAware { /// - /// Common base class for accessing a Quartz Scheduler, i.e. for registering jobs, - /// triggers and listeners on a instance. + /// Logger instance. + /// + private readonly ILogger logger; + + private bool overwriteExistingJobs; + + private string[] jobSchedulingDataLocations; + + private IList jobDetails; + private IDictionary calendars; + private IList triggers; + + private ISchedulerListener[] schedulerListeners; + private IJobListener[] globalJobListeners; + private IJobListener[] jobListeners; + private ITriggerListener[] globalTriggerListeners; + private ITriggerListener[] triggerListeners; + + private IPlatformTransactionManager transactionManager; + + /// + /// Resource loader instance for sub-classes + /// + private IResourceLoader resourceLoader; + + /// + /// Initializes a new instance of the class. + /// + protected SchedulerAccessor() + { + logger = LogManager.GetLogger(GetType()); + } + + /// + /// Set whether any jobs defined on this SchedulerFactoryObject should overwrite + /// existing job definitions. Default is "false", to not overwrite already + /// registered jobs that have been read in from a persistent job store. + /// + public virtual bool OverwriteExistingJobs + { + set => overwriteExistingJobs = value; + } + + /// + /// Set the locations of Quartz job definition XML files that follow the + /// "job_scheduling_data_1_5" XSD. Can be specified to automatically + /// register jobs that are defined in such files, possibly in addition + /// to jobs defined directly on this SchedulerFactoryObject. + /// + /// + public virtual string[] JobSchedulingDataLocations + { + set => jobSchedulingDataLocations = value; + } + + /// + /// Set the location of a Quartz job definition XML file that follows the + /// "job_scheduling_data" XSD. Can be specified to automatically + /// register jobs that are defined in such a file, possibly in addition + /// to jobs defined directly on this SchedulerFactoryObject. + /// + /// + public virtual string JobSchedulingDataLocation + { + set => jobSchedulingDataLocations = new string[] { value }; + } + + /// + /// Register a list of JobDetail objects with the Scheduler that + /// this FactoryObject creates, to be referenced by Triggers. + /// This is not necessary when a Trigger determines the JobDetail + /// itself: In this case, the JobDetail will be implicitly registered + /// in combination with the Trigger. + /// + /// + /// + /// + /// + /// + public virtual IJobDetail[] JobDetails + { + set => jobDetails = new List(value); + } + + /// + /// Register a list of Quartz ICalendar objects with the Scheduler + /// that this FactoryObject creates, to be referenced by Triggers. + /// + /// Map with calendar names as keys as Calendar objects as values + /// + /// + public virtual IDictionary Calendars + { + set => calendars = value; + } + + /// + /// Register a list of Trigger objects with the Scheduler that + /// this FactoryObject creates. /// /// - /// For concrete usage, check out the and - /// classes. - /// - /// Juergen Hoeller - /// Marko Lahma (.NET) - public abstract class SchedulerAccessor : IResourceLoaderAware + /// If the Trigger determines the corresponding JobDetail itself, + /// the job will be automatically registered with the Scheduler. + /// Else, the respective JobDetail needs to be registered via the + /// "jobDetails" property of this FactoryObject. + /// + /// + /// + /// + /// + /// + public virtual ITrigger[] Triggers { - /// - /// Logger instance. - /// - private readonly ILogger logger; + set => triggers = new ArrayList(value); + } - private bool overwriteExistingJobs; + /// + /// Specify Quartz SchedulerListeners to be registered with the Scheduler. + /// + public virtual ISchedulerListener[] SchedulerListeners + { + set => schedulerListeners = value; + } - private string[] jobSchedulingDataLocations; + /// + /// Specify global Quartz JobListeners to be registered with the Scheduler. + /// Such JobListeners will apply to all Jobs in the Scheduler. + /// + public virtual IJobListener[] GlobalJobListeners + { + set => globalJobListeners = value; + } - private IList jobDetails; - private IDictionary calendars; - private IList triggers; + /// + /// Specify named Quartz JobListeners to be registered with the Scheduler. + /// Such JobListeners will only apply to Jobs that explicitly activate + /// them via their name. + /// + /// + public virtual IJobListener[] JobListeners + { + set => jobListeners = value; + } - private ISchedulerListener[] schedulerListeners; - private IJobListener[] globalJobListeners; - private IJobListener[] jobListeners; - private ITriggerListener[] globalTriggerListeners; - private ITriggerListener[] triggerListeners; + /// + /// Specify global Quartz TriggerListeners to be registered with the Scheduler. + /// Such TriggerListeners will apply to all Triggers in the Scheduler. + /// + public virtual ITriggerListener[] GlobalTriggerListeners + { + set => globalTriggerListeners = value; + } - private IPlatformTransactionManager transactionManager; + /// + /// Specify named Quartz TriggerListeners to be registered with the Scheduler. + /// Such TriggerListeners will only apply to Triggers that explicitly activate + /// them via their name. + /// + /// + public virtual ITriggerListener[] TriggerListeners + { + set => triggerListeners = value; + } - /// - /// Resource loader instance for sub-classes - /// - private IResourceLoader resourceLoader; + /// + /// Set the transaction manager to be used for registering jobs and triggers + /// that are defined by this SchedulerFactoryObject. Default is none; setting + /// this only makes sense when specifying a DataSource for the Scheduler. + /// + public virtual IPlatformTransactionManager TransactionManager + { + set => transactionManager = value; + } - /// - /// Initializes a new instance of the class. - /// - protected SchedulerAccessor() + /// + /// Sets the + /// that this object runs in. + /// + /// + /// + /// Invoked after population of normal objects properties but + /// before an init callback such as + /// 's + /// + /// or a custom init-method. Invoked before setting + /// 's + /// + /// property. + /// + public virtual IResourceLoader ResourceLoader + { + set { resourceLoader = value; } + protected get { return resourceLoader; } + } + + /// + /// Logger instance. + /// + protected ILogger Logger => logger; + + /// + /// Register jobs and triggers (within a transaction, if possible). + /// + protected virtual async Task RegisterJobsAndTriggers() + { + ITransactionStatus transactionStatus = null; + if (transactionManager != null) { - logger = LogManager.GetLogger(GetType()); + transactionStatus = transactionManager.GetTransaction(new DefaultTransactionDefinition()); } - /// - /// Set whether any jobs defined on this SchedulerFactoryObject should overwrite - /// existing job definitions. Default is "false", to not overwrite already - /// registered jobs that have been read in from a persistent job store. - /// - public virtual bool OverwriteExistingJobs + try { - set => overwriteExistingJobs = value; - } - - /// - /// Set the locations of Quartz job definition XML files that follow the - /// "job_scheduling_data_1_5" XSD. Can be specified to automatically - /// register jobs that are defined in such files, possibly in addition - /// to jobs defined directly on this SchedulerFactoryObject. - /// - /// - public virtual string[] JobSchedulingDataLocations - { - set => jobSchedulingDataLocations = value; - } - - /// - /// Set the location of a Quartz job definition XML file that follows the - /// "job_scheduling_data" XSD. Can be specified to automatically - /// register jobs that are defined in such a file, possibly in addition - /// to jobs defined directly on this SchedulerFactoryObject. - /// - /// - public virtual string JobSchedulingDataLocation - { - set => jobSchedulingDataLocations = new string[] {value}; - } - - /// - /// Register a list of JobDetail objects with the Scheduler that - /// this FactoryObject creates, to be referenced by Triggers. - /// This is not necessary when a Trigger determines the JobDetail - /// itself: In this case, the JobDetail will be implicitly registered - /// in combination with the Trigger. - /// - /// - /// - /// - /// - /// - public virtual IJobDetail[] JobDetails - { - set => jobDetails = new List(value); - } - - /// - /// Register a list of Quartz ICalendar objects with the Scheduler - /// that this FactoryObject creates, to be referenced by Triggers. - /// - /// Map with calendar names as keys as Calendar objects as values - /// - /// - public virtual IDictionary Calendars - { - set => calendars = value; - } - - /// - /// Register a list of Trigger objects with the Scheduler that - /// this FactoryObject creates. - /// - /// - /// If the Trigger determines the corresponding JobDetail itself, - /// the job will be automatically registered with the Scheduler. - /// Else, the respective JobDetail needs to be registered via the - /// "jobDetails" property of this FactoryObject. - /// - /// - /// - /// - /// - /// - public virtual ITrigger[] Triggers - { - set => triggers = new ArrayList(value); - } - - /// - /// Specify Quartz SchedulerListeners to be registered with the Scheduler. - /// - public virtual ISchedulerListener[] SchedulerListeners - { - set => schedulerListeners = value; - } - - /// - /// Specify global Quartz JobListeners to be registered with the Scheduler. - /// Such JobListeners will apply to all Jobs in the Scheduler. - /// - public virtual IJobListener[] GlobalJobListeners - { - set => globalJobListeners = value; - } - - /// - /// Specify named Quartz JobListeners to be registered with the Scheduler. - /// Such JobListeners will only apply to Jobs that explicitly activate - /// them via their name. - /// - /// - public virtual IJobListener[] JobListeners - { - set => jobListeners = value; - } - - /// - /// Specify global Quartz TriggerListeners to be registered with the Scheduler. - /// Such TriggerListeners will apply to all Triggers in the Scheduler. - /// - public virtual ITriggerListener[] GlobalTriggerListeners - { - set => globalTriggerListeners = value; - } - - /// - /// Specify named Quartz TriggerListeners to be registered with the Scheduler. - /// Such TriggerListeners will only apply to Triggers that explicitly activate - /// them via their name. - /// - /// - public virtual ITriggerListener[] TriggerListeners - { - set => triggerListeners = value; - } - - /// - /// Set the transaction manager to be used for registering jobs and triggers - /// that are defined by this SchedulerFactoryObject. Default is none; setting - /// this only makes sense when specifying a DataSource for the Scheduler. - /// - public virtual IPlatformTransactionManager TransactionManager - { - set => transactionManager = value; - } - - /// - /// Sets the - /// that this object runs in. - /// - /// - /// - /// Invoked after population of normal objects properties but - /// before an init callback such as - /// 's - /// - /// or a custom init-method. Invoked before setting - /// 's - /// - /// property. - /// - public virtual IResourceLoader ResourceLoader - { - set { resourceLoader = value; } - protected get { return resourceLoader; } - } - - /// - /// Logger instance. - /// - protected ILogger Logger => logger; - - /// - /// Register jobs and triggers (within a transaction, if possible). - /// - protected virtual async Task RegisterJobsAndTriggers() - { - ITransactionStatus transactionStatus = null; - if (transactionManager != null) + if (jobSchedulingDataLocations != null) { - transactionStatus = transactionManager.GetTransaction(new DefaultTransactionDefinition()); + var dataProcessor = new XMLSchedulingDataProcessor(new SimpleTypeLoadHelper()); + dataProcessor.OverWriteExistingData = overwriteExistingJobs; + foreach (string location in jobSchedulingDataLocations) + { + await dataProcessor.ProcessFileAndScheduleJobs(location, GetScheduler()).ConfigureAwait(false); + } } - try + // Register JobDetails. + if (jobDetails != null) { - if (jobSchedulingDataLocations != null) + foreach (IJobDetail jobDetail in jobDetails) { - var dataProcessor = new XMLSchedulingDataProcessor(new SimpleTypeLoadHelper()); - dataProcessor.OverWriteExistingData = overwriteExistingJobs; - foreach (string location in jobSchedulingDataLocations) - { - await dataProcessor.ProcessFileAndScheduleJobs(location, GetScheduler()).ConfigureAwait(false); - } + await AddJobToScheduler(jobDetail).ConfigureAwait(false); } - - // Register JobDetails. - if (jobDetails != null) - { - foreach (IJobDetail jobDetail in jobDetails) - { - await AddJobToScheduler(jobDetail).ConfigureAwait(false); - } - } - else - { - // Create empty list for easier checks when registering triggers. - jobDetails = new List(); - } - - // Register Calendars. - if (calendars != null) - { - foreach (DictionaryEntry entry in calendars) - { - string calendarName = (string) entry.Key; - ICalendar calendar = (ICalendar) entry.Value; - await GetScheduler().AddCalendar(calendarName, calendar, true, true).ConfigureAwait(false); - } - } - - // Register Triggers. - if (triggers != null) - { - foreach (ITrigger trigger in triggers) - { - await AddTriggerToScheduler(trigger).ConfigureAwait(false); - } - } - } - catch (Exception ex) - { - if (transactionStatus != null) - { - try - { - transactionManager.Rollback(transactionStatus); - } - catch (TransactionException) - { - logger.LogError(ex, "Job registration exception overridden by rollback exception"); - throw; - } - } - - if (ex is SchedulerException) - { - throw; - } - - throw new SchedulerException("Registration of jobs and triggers failed: " + ex.Message); - } - - if (transactionStatus != null) - { - transactionManager.Commit(transactionStatus); - } - } - - /// - /// Add the given job to the Scheduler, if it doesn't already exist. - /// Overwrites the job in any case if "overwriteExistingJobs" is set. - /// - /// the job to add - /// true if the job was actually added, false if it already existed before - private async Task AddJobToScheduler(IJobDetail jobDetail) - { - if (overwriteExistingJobs - || await GetScheduler().GetJobDetail(jobDetail.Key).ConfigureAwait(false) == null) - { - await GetScheduler().AddJob(jobDetail, true, true).ConfigureAwait(false); - return true; - } - - return false; - } - - /// - /// Add the given trigger to the Scheduler, if it doesn't already exist. - /// Overwrites the trigger in any case if "overwriteExistingJobs" is set. - /// - /// the trigger to add - /// true if the trigger was actually added, false if it already existed before - private async Task AddTriggerToScheduler(ITrigger trigger) - { - bool triggerExists = await GetScheduler().GetTrigger(trigger.Key).ConfigureAwait(false) != null; - if (!triggerExists || overwriteExistingJobs) - { - // Check if the Trigger is aware of an associated JobDetail. - if (trigger is IJobDetailAwareTrigger awareTrigger) - { - IJobDetail jobDetail = awareTrigger.JobDetail; - // Automatically register the JobDetail too. - if (!jobDetails.Contains(jobDetail) - && await AddJobToScheduler(jobDetail).ConfigureAwait(false)) - { - jobDetails.Add(jobDetail); - } - } - - if (!triggerExists) - { - try - { - await GetScheduler().ScheduleJob(trigger).ConfigureAwait(false); - } - catch (ObjectAlreadyExistsException ex) - { - if (logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug)) - { - logger.LogDebug($"Unexpectedly found existing trigger, assumably due to cluster race condition: {ex.Message} - can safely be ignored"); - } - - if (overwriteExistingJobs) - { - await GetScheduler().RescheduleJob(trigger.Key, trigger).ConfigureAwait(false); - } - } - } - else - { - await GetScheduler().RescheduleJob(trigger.Key, trigger).ConfigureAwait(false); - } - - return true; } else { - return false; + // Create empty list for easier checks when registering triggers. + jobDetails = new List(); + } + + // Register Calendars. + if (calendars != null) + { + foreach (DictionaryEntry entry in calendars) + { + string calendarName = (string) entry.Key; + ICalendar calendar = (ICalendar) entry.Value; + await GetScheduler().AddCalendar(calendarName, calendar, true, true).ConfigureAwait(false); + } + } + + // Register Triggers. + if (triggers != null) + { + foreach (ITrigger trigger in triggers) + { + await AddTriggerToScheduler(trigger).ConfigureAwait(false); + } } } - - /// - /// Register all specified listeners with the Scheduler. - /// - protected virtual void RegisterListeners() + catch (Exception ex) { - if (schedulerListeners != null) + if (transactionStatus != null) { - for (int i = 0; i < schedulerListeners.Length; i++) + try { - GetScheduler().ListenerManager.AddSchedulerListener(schedulerListeners[i]); + transactionManager.Rollback(transactionStatus); + } + catch (TransactionException) + { + logger.LogError(ex, "Job registration exception overridden by rollback exception"); + throw; } } - if (globalJobListeners != null) + if (ex is SchedulerException) { - foreach (IJobListener jobListener in globalJobListeners) + throw; + } + + throw new SchedulerException("Registration of jobs and triggers failed: " + ex.Message); + } + + if (transactionStatus != null) + { + transactionManager.Commit(transactionStatus); + } + } + + /// + /// Add the given job to the Scheduler, if it doesn't already exist. + /// Overwrites the job in any case if "overwriteExistingJobs" is set. + /// + /// the job to add + /// true if the job was actually added, false if it already existed before + private async Task AddJobToScheduler(IJobDetail jobDetail) + { + if (overwriteExistingJobs + || await GetScheduler().GetJobDetail(jobDetail.Key).ConfigureAwait(false) == null) + { + await GetScheduler().AddJob(jobDetail, true, true).ConfigureAwait(false); + return true; + } + + return false; + } + + /// + /// Add the given trigger to the Scheduler, if it doesn't already exist. + /// Overwrites the trigger in any case if "overwriteExistingJobs" is set. + /// + /// the trigger to add + /// true if the trigger was actually added, false if it already existed before + private async Task AddTriggerToScheduler(ITrigger trigger) + { + bool triggerExists = await GetScheduler().GetTrigger(trigger.Key).ConfigureAwait(false) != null; + if (!triggerExists || overwriteExistingJobs) + { + // Check if the Trigger is aware of an associated JobDetail. + if (trigger is IJobDetailAwareTrigger awareTrigger) + { + IJobDetail jobDetail = awareTrigger.JobDetail; + // Automatically register the JobDetail too. + if (!jobDetails.Contains(jobDetail) + && await AddJobToScheduler(jobDetail).ConfigureAwait(false)) { - GetScheduler().ListenerManager.AddJobListener(jobListener); + jobDetails.Add(jobDetail); } } - if (jobListeners != null && jobListeners.Length > 0) + if (!triggerExists) { - throw new InvalidOperationException("Non-global JobListeners not supported on Quartz 2 - " + - "manually register a Matcher against the Quartz ListenerManager instead"); - } - - if (globalTriggerListeners != null) - { - foreach (ITriggerListener triggerListener in globalTriggerListeners) + try { - GetScheduler().ListenerManager.AddTriggerListener(triggerListener); + await GetScheduler().ScheduleJob(trigger).ConfigureAwait(false); + } + catch (ObjectAlreadyExistsException ex) + { + if (logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug)) + { + logger.LogDebug($"Unexpectedly found existing trigger, assumably due to cluster race condition: {ex.Message} - can safely be ignored"); + } + + if (overwriteExistingJobs) + { + await GetScheduler().RescheduleJob(trigger.Key, trigger).ConfigureAwait(false); + } } } - - if (triggerListeners != null && triggerListeners.Length > 0) + else { - throw new InvalidOperationException("Non-global TriggerListeners not supported on Quartz 2 - " + - "manually register a Matcher against the Quartz ListenerManager instead"); + await GetScheduler().RescheduleJob(trigger.Key, trigger).ConfigureAwait(false); + } + + return true; + } + else + { + return false; + } + } + + /// + /// Register all specified listeners with the Scheduler. + /// + protected virtual void RegisterListeners() + { + if (schedulerListeners != null) + { + for (int i = 0; i < schedulerListeners.Length; i++) + { + GetScheduler().ListenerManager.AddSchedulerListener(schedulerListeners[i]); } } - /// - /// Template method that determines the Scheduler to operate on. - /// To be implemented by subclasses. - /// - /// - protected abstract IScheduler GetScheduler(); + if (globalJobListeners != null) + { + foreach (IJobListener jobListener in globalJobListeners) + { + GetScheduler().ListenerManager.AddJobListener(jobListener); + } + } + + if (jobListeners != null && jobListeners.Length > 0) + { + throw new InvalidOperationException("Non-global JobListeners not supported on Quartz 2 - " + + "manually register a Matcher against the Quartz ListenerManager instead"); + } + + if (globalTriggerListeners != null) + { + foreach (ITriggerListener triggerListener in globalTriggerListeners) + { + GetScheduler().ListenerManager.AddTriggerListener(triggerListener); + } + } + + if (triggerListeners != null && triggerListeners.Length > 0) + { + throw new InvalidOperationException("Non-global TriggerListeners not supported on Quartz 2 - " + + "manually register a Matcher against the Quartz ListenerManager instead"); + } } + + /// + /// Template method that determines the Scheduler to operate on. + /// To be implemented by subclasses. + /// + /// + protected abstract IScheduler GetScheduler(); } diff --git a/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/SchedulerAccessorObject.cs b/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/SchedulerAccessorObject.cs index b0166f7d..87851520 100644 --- a/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/SchedulerAccessorObject.cs +++ b/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/SchedulerAccessorObject.cs @@ -18,135 +18,134 @@ using Quartz; using Quartz.Impl; using Spring.Objects.Factory; -namespace Spring.Scheduling.Quartz +namespace Spring.Scheduling.Quartz; + +/// +/// Spring class for accessing a Quartz Scheduler, i.e. for registering jobs, +/// triggers and listeners on a given instance. +/// +/// Juergen Hoeller +/// Marko Lahma (.NET) +/// +/// +public class SchedulerAccessorObject : SchedulerAccessor, IObjectFactoryAware, IInitializingObject { + private string schedulerName; + private IScheduler scheduler; + private IObjectFactory objectFactory; + /// - /// Spring class for accessing a Quartz Scheduler, i.e. for registering jobs, - /// triggers and listeners on a given instance. + /// Specify the Quartz Scheduler to operate on via its scheduler name in the Spring + /// application context or also in the Quartz {@link org.quartz.impl.SchedulerRepository}. /// - /// Juergen Hoeller - /// Marko Lahma (.NET) - /// - /// - public class SchedulerAccessorObject : SchedulerAccessor, IObjectFactoryAware, IInitializingObject + /// + /// Schedulers can be registered in the repository through custom bootstrapping, + /// e.g. via the or + /// factory classes. + /// However, in general, it's preferable to use Spring's + /// which includes the job/trigger/listener capabilities of this accessor as well. + /// + public string SchedulerName { - private string schedulerName; - private IScheduler scheduler; - private IObjectFactory objectFactory; + set => schedulerName = value; + } - /// - /// Specify the Quartz Scheduler to operate on via its scheduler name in the Spring - /// application context or also in the Quartz {@link org.quartz.impl.SchedulerRepository}. - /// - /// - /// Schedulers can be registered in the repository through custom bootstrapping, - /// e.g. via the or - /// factory classes. - /// However, in general, it's preferable to use Spring's - /// which includes the job/trigger/listener capabilities of this accessor as well. - /// - public string SchedulerName - { - set => schedulerName = value; - } + /// + /// Return the Quartz Scheduler instance that this accessor operates on. + /// + protected IScheduler Scheduler + { + set => scheduler = value; + } - /// - /// Return the Quartz Scheduler instance that this accessor operates on. - /// - protected IScheduler Scheduler - { - set => scheduler = value; - } + /// + /// Template method that determines the Scheduler to operate on. + /// + /// + protected override IScheduler GetScheduler() + { + return scheduler; + } - /// - /// Template method that determines the Scheduler to operate on. - /// - /// - protected override IScheduler GetScheduler() - { - return scheduler; - } + /// + /// Return the Quartz Scheduler instance that this accessor operates on. + /// + public IObjectFactory ObjectFactory + { + set => objectFactory = value; + } - /// - /// Return the Quartz Scheduler instance that this accessor operates on. - /// - public IObjectFactory ObjectFactory + /// + /// Invoked by an + /// after it has injected all of an object's dependencies. + /// + /// + ///

+ /// This method allows the object instance to perform the kind of + /// initialization only possible when all of it's dependencies have + /// been injected (set), and to throw an appropriate exception in the + /// event of misconfiguration. + ///

+ ///

+ /// Please do consult the class level documentation for the + /// interface for a + /// description of exactly when this method is invoked. In + /// particular, it is worth noting that the + /// + /// and + /// callbacks will have been invoked prior to this method being + /// called. + ///

+ ///
+ /// + /// In the event of misconfiguration (such as the failure to set a + /// required property) or if initialization fails. + /// + public void AfterPropertiesSet() + { + if (scheduler == null) { - set => objectFactory = value; - } - - /// - /// Invoked by an - /// after it has injected all of an object's dependencies. - /// - /// - ///

- /// This method allows the object instance to perform the kind of - /// initialization only possible when all of it's dependencies have - /// been injected (set), and to throw an appropriate exception in the - /// event of misconfiguration. - ///

- ///

- /// Please do consult the class level documentation for the - /// interface for a - /// description of exactly when this method is invoked. In - /// particular, it is worth noting that the - /// - /// and - /// callbacks will have been invoked prior to this method being - /// called. - ///

- ///
- /// - /// In the event of misconfiguration (such as the failure to set a - /// required property) or if initialization fails. - /// - public void AfterPropertiesSet() - { - if (scheduler == null) + if (schedulerName != null) { - if (schedulerName != null) + scheduler = FindScheduler(schedulerName); + } + else + { + throw new InvalidOperationException("No Scheduler specified"); + } + } + + RegisterListeners(); + RegisterJobsAndTriggers().ConfigureAwait(false).GetAwaiter().GetResult(); + } + + /// + /// Finds the scheduler. + /// + /// Name of the scheduler. + /// + protected virtual IScheduler FindScheduler(string schedulerName) + { + if (objectFactory is IListableObjectFactory lbf) + { + var objectNames = lbf.GetObjectNamesForType(typeof(IScheduler)); + foreach (string objectName in objectNames) + { + IScheduler schedulerObject = (IScheduler) lbf.GetObject(objectName); + if (schedulerName.Equals(schedulerObject.SchedulerName)) { - scheduler = FindScheduler(schedulerName); - } - else - { - throw new InvalidOperationException("No Scheduler specified"); + return schedulerObject; } } - - RegisterListeners(); - RegisterJobsAndTriggers().ConfigureAwait(false).GetAwaiter().GetResult(); } - /// - /// Finds the scheduler. - /// - /// Name of the scheduler. - /// - protected virtual IScheduler FindScheduler(string schedulerName) + IScheduler schedulerInRepo = SchedulerRepository.Instance.Lookup(schedulerName) + .ConfigureAwait(false).GetAwaiter().GetResult(); + if (schedulerInRepo == null) { - if (objectFactory is IListableObjectFactory lbf) - { - var objectNames = lbf.GetObjectNamesForType(typeof(IScheduler)); - foreach (string objectName in objectNames) - { - IScheduler schedulerObject = (IScheduler) lbf.GetObject(objectName); - if (schedulerName.Equals(schedulerObject.SchedulerName)) - { - return schedulerObject; - } - } - } - - IScheduler schedulerInRepo = SchedulerRepository.Instance.Lookup(schedulerName) - .ConfigureAwait(false).GetAwaiter().GetResult(); - if (schedulerInRepo == null) - { - throw new InvalidOperationException("No Scheduler named '" + schedulerName + "' found"); - } - - return schedulerInRepo; + throw new InvalidOperationException("No Scheduler named '" + schedulerName + "' found"); } + + return schedulerInRepo; } } diff --git a/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/SchedulerFactoryObject.cs b/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/SchedulerFactoryObject.cs index e0be9794..f63c802c 100644 --- a/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/SchedulerFactoryObject.cs +++ b/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/SchedulerFactoryObject.cs @@ -1,18 +1,18 @@ /* -* Copyright 2002-2010 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. -*/ + * Copyright 2002-2010 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. + */ using System.Collections; using System.Collections.Specialized; @@ -28,809 +28,808 @@ using Spring.Core.IO; using Spring.Data.Common; using Spring.Objects.Factory; -namespace Spring.Scheduling.Quartz +namespace Spring.Scheduling.Quartz; + +/// +/// FactoryObject that sets up a Quartz Scheduler and exposes it for object references. +/// +/// +///

+/// Allows registration of JobDetails, Calendars and Triggers, automatically +/// starting the scheduler on initialization and shutting it down on destruction. +/// In scenarios that just require static registration of jobs at startup, there +/// is no need to access the Scheduler instance itself in application code. +///

+/// +///

+/// For dynamic registration of jobs at runtime, use a object reference to +/// this SchedulerFactoryObject to get direct access to the Quartz Scheduler +/// (). This allows you to create new jobs +/// and triggers, and also to control and monitor the entire Scheduler. +///

+/// +///

+/// Note that Quartz instantiates a new Job for each execution, in +/// contrast to Timer which uses a TimerTask instance that is shared +/// between repeated executions. Just JobDetail descriptors are shared. +///

+/// +///

+/// When using persistent jobs, it is strongly recommended to perform all +/// operations on the Scheduler within Spring-managed transactions. +/// Else, database locking will not properly work and might even break. +///

+///

+/// The preferred way to achieve transactional execution is to demarcate +/// declarative transactions at the business facade level, which will +/// automatically apply to Scheduler operations performed within those scopes. +/// Alternatively, define a TransactionProxyFactoryObject for the Scheduler itself. +///

+///
+/// Juergen Hoeller +/// Marko Lahma (.NET) +/// +/// +/// +public class SchedulerFactoryObject : SchedulerAccessor, IFactoryObject, IObjectNameAware, + IApplicationContextAware, IApplicationEventListener, IInitializingObject, IDisposable { - /// - /// FactoryObject that sets up a Quartz Scheduler and exposes it for object references. + /// + /// Default thread count to be set to thread pool. + /// + public const int DefaultThreadCount = 10; + + /// + /// Property name for thread count in thread pool. + /// + public const string PropThreadCount = "quartz.threadPool.threadCount"; + + [ThreadStatic] private static IDbProvider configTimeDbProvider; + + [ThreadStatic] private static ITaskExecutor configTimeTaskExecutor; + + /// + /// Return the IDbProvider for the currently configured Quartz Scheduler, + /// to be used by LocalDataSourceJobStore. + /// + /// + /// This instance will be set before initialization of the corresponding + /// Scheduler, and reset immediately afterwards. It is thus only available + /// during configuration. + /// + /// + /// + public static IDbProvider ConfigTimeDbProvider => configTimeDbProvider; + + /// + /// Return the TaskExecutor for the currently configured Quartz Scheduler, + /// to be used by LocalTaskExecutorThreadPool. + /// + /// + /// This instance will be set before initialization of the corresponding + /// Scheduler, and reset immediately afterwards. It is thus only available + /// during configuration. + /// + public static ITaskExecutor ConfigTimeTaskExecutor => configTimeTaskExecutor; + + private IApplicationContext applicationContext; + private string applicationContextSchedulerContextKey; + private bool autoStartup = true; + private IResource configLocation; + private IJobFactory jobFactory; + private bool jobFactorySet; + private IDictionary quartzProperties; + private IScheduler scheduler; + private IDictionary schedulerContextMap; + private Type schedulerFactoryType; + private string schedulerName; + private TimeSpan startupDelay = TimeSpan.Zero; + private ITaskExecutor taskExecutor; + private bool exposeSchedulerInRepository; + private bool waitForJobsToCompleteOnShutdown; + private IDbProvider dbProvider; + + /// + /// Initializes a new instance of the class. + /// + public SchedulerFactoryObject() + { + schedulerFactoryType = typeof(StdSchedulerFactory); + } + + /// + /// Set the Quartz SchedulerFactory implementation to use. + /// + /// + /// Default is StdSchedulerFactory, reading in the standard + /// quartz.properties from Quartz' dll. To use custom Quartz + /// properties, specify "configLocation" or "quartzProperties". + /// + /// The scheduler factory class. + /// + /// + /// + public virtual Type SchedulerFactoryType + { + set + { + if (value == null || !typeof(ISchedulerFactory).IsAssignableFrom(value)) + { + throw new ArgumentException("schedulerFactoryType must implement [Quartz.ISchedulerFactory]"); + } + + schedulerFactoryType = value; + } + } + + /// + /// Set the name of the Scheduler to fetch from the SchedulerFactory. + /// If not specified, the default Scheduler will be used. + /// + /// The name of the scheduler. + /// + /// + public virtual string SchedulerName + { + set => schedulerName = value; + } + + /// + /// Set the location of the Quartz properties config file, for example + /// as assembly resource "assembly:quartz.properties". + /// + /// + /// Note: Can be omitted when all necessary properties are specified + /// locally via this object, or when relying on Quartz' default configuration. + /// + /// + public virtual IResource ConfigLocation + { + set => configLocation = value; + } + + /// + /// Set Quartz properties, like "quartz.threadPool.type". + /// + /// + /// Can be used to override values in a Quartz properties config file, + /// or to specify all necessary properties locally. + /// + /// + public virtual IDictionary QuartzProperties + { + set => quartzProperties = value; + } + + /// + /// Set the Spring TaskExecutor to use as Quartz backend. + /// Exposed as thread pool through the Quartz SPI. + /// + /// + /// By default, a Quartz SimpleThreadPool will be used, configured through + /// the corresponding Quartz properties. + /// + /// The task executor. + /// + /// + public virtual ITaskExecutor TaskExecutor + { + set => taskExecutor = value; + } + + /// + /// Register objects in the Scheduler context via a given Map. + /// These objects will be available to any Job that runs in this Scheduler. + /// + /// + /// Note: When using persistent Jobs whose JobDetail will be kept in the + /// database, do not put Spring-managed object or an ApplicationContext + /// reference into the JobDataMap but rather into the SchedulerContext. + /// + /// + /// Map with string keys and any objects as + /// values (for example Spring-managed objects) + /// + /// + public virtual IDictionary SchedulerContextAsMap + { + set => schedulerContextMap = value; + } + + /// + /// Set the key of an IApplicationContext reference to expose in the + /// SchedulerContext, for example "applicationContext". Default is none. + /// Only applicable when running in a Spring ApplicationContext. /// /// ///

- /// Allows registration of JobDetails, Calendars and Triggers, automatically - /// starting the scheduler on initialization and shutting it down on destruction. - /// In scenarios that just require static registration of jobs at startup, there - /// is no need to access the Scheduler instance itself in application code. + /// Note: When using persistent Jobs whose JobDetail will be kept in the + /// database, do not put an IApplicationContext reference into the JobDataMap + /// but rather into the SchedulerContext. ///

- /// + /// ///

- /// For dynamic registration of jobs at runtime, use a object reference to - /// this SchedulerFactoryObject to get direct access to the Quartz Scheduler - /// (). This allows you to create new jobs - /// and triggers, and also to control and monitor the entire Scheduler. + /// In case of a QuartzJobObject, the reference will be applied to the Job + /// instance as object property. An "applicationContext" attribute will + /// correspond to a "setApplicationContext" method in that scenario. ///

- /// + /// ///

- /// Note that Quartz instantiates a new Job for each execution, in - /// contrast to Timer which uses a TimerTask instance that is shared - /// between repeated executions. Just JobDetail descriptors are shared. - ///

- /// - ///

- /// When using persistent jobs, it is strongly recommended to perform all - /// operations on the Scheduler within Spring-managed transactions. - /// Else, database locking will not properly work and might even break. - ///

- ///

- /// The preferred way to achieve transactional execution is to demarcate - /// declarative transactions at the business facade level, which will - /// automatically apply to Scheduler operations performed within those scopes. - /// Alternatively, define a TransactionProxyFactoryObject for the Scheduler itself. + /// Note that ObjectFactory callback interfaces like IApplicationContextAware + /// are not automatically applied to Quartz Job instances, because Quartz + /// itself is reponsible for the lifecycle of its Jobs. ///

///
- /// Juergen Hoeller - /// Marko Lahma (.NET) - /// - /// - /// - public class SchedulerFactoryObject : SchedulerAccessor, IFactoryObject, IObjectNameAware, - IApplicationContextAware, IApplicationEventListener, IInitializingObject, IDisposable + /// The application context scheduler context key. + /// + public virtual string ApplicationContextSchedulerContextKey { - /// - /// Default thread count to be set to thread pool. - /// - public const int DefaultThreadCount = 10; + set => applicationContextSchedulerContextKey = value; + } - /// - /// Property name for thread count in thread pool. - /// - public const string PropThreadCount = "quartz.threadPool.threadCount"; - - [ThreadStatic] private static IDbProvider configTimeDbProvider; - - [ThreadStatic] private static ITaskExecutor configTimeTaskExecutor; - - /// - /// Return the IDbProvider for the currently configured Quartz Scheduler, - /// to be used by LocalDataSourceJobStore. - /// - /// - /// This instance will be set before initialization of the corresponding - /// Scheduler, and reset immediately afterwards. It is thus only available - /// during configuration. - /// - /// - /// - public static IDbProvider ConfigTimeDbProvider => configTimeDbProvider; - - /// - /// Return the TaskExecutor for the currently configured Quartz Scheduler, - /// to be used by LocalTaskExecutorThreadPool. - /// - /// - /// This instance will be set before initialization of the corresponding - /// Scheduler, and reset immediately afterwards. It is thus only available - /// during configuration. - /// - public static ITaskExecutor ConfigTimeTaskExecutor => configTimeTaskExecutor; - - private IApplicationContext applicationContext; - private string applicationContextSchedulerContextKey; - private bool autoStartup = true; - private IResource configLocation; - private IJobFactory jobFactory; - private bool jobFactorySet; - private IDictionary quartzProperties; - private IScheduler scheduler; - private IDictionary schedulerContextMap; - private Type schedulerFactoryType; - private string schedulerName; - private TimeSpan startupDelay = TimeSpan.Zero; - private ITaskExecutor taskExecutor; - private bool exposeSchedulerInRepository; - private bool waitForJobsToCompleteOnShutdown; - private IDbProvider dbProvider; - - /// - /// Initializes a new instance of the class. - /// - public SchedulerFactoryObject() + /// + /// Set the Quartz JobFactory to use for this Scheduler. + /// + /// + ///

+ /// Default is Spring's , which supports + /// standard Quartz instances. Note that this default only applies + /// to a local Scheduler, not to a RemoteScheduler (where setting + /// a custom JobFactory is not supported by Quartz). + ///

+ ///

+ /// Specify an instance of Spring's here + /// (typically as an inner object definition) to automatically populate a job's + /// object properties from the specified job data map and scheduler context. + ///

+ ///
+ /// + /// + public virtual IJobFactory JobFactory + { + set { - schedulerFactoryType = typeof(StdSchedulerFactory); + jobFactory = value; + jobFactorySet = true; } + } - /// - /// Set the Quartz SchedulerFactory implementation to use. - /// - /// - /// Default is StdSchedulerFactory, reading in the standard - /// quartz.properties from Quartz' dll. To use custom Quartz - /// properties, specify "configLocation" or "quartzProperties". - /// - /// The scheduler factory class. - /// - /// - /// - public virtual Type SchedulerFactoryType + /// + /// Set whether to expose the Spring-managed instance in the + /// Quartz . Default is "false", since the Spring-managed + /// Scheduler is usually exclusively intended for access within the Spring context. + /// + /// + /// Switch this flag to "true" in order to expose the Scheduler globally. + /// This is not recommended unless you have an existing Spring application that + /// relies on this behavior. + /// + public virtual bool ExposeSchedulerInRepository + { + set => exposeSchedulerInRepository = value; + } + + /// + /// Set whether to automatically start the scheduler after initialization. + /// Default is "true"; set this to "false" to allow for manual startup. + /// + public virtual bool AutoStartup + { + set => autoStartup = value; + } + + /// + /// Set the time span to wait after initialization before + /// starting the scheduler asynchronously. Default is 0, meaning + /// immediate synchronous startup on initialization of this object. + /// + /// + /// Setting this to 10 or 20 seconds makes sense if no jobs + /// should be run before the entire application has started up. + /// + public virtual TimeSpan StartupDelay + { + set => startupDelay = value; + } + + /// + /// Set whether to wait for running jobs to complete on Shutdown. + /// Default is "false". + /// + /// + /// true if [wait for jobs to complete on Shutdown]; otherwise, false. + /// + /// + public virtual bool WaitForJobsToCompleteOnShutdown + { + set => waitForJobsToCompleteOnShutdown = value; + } + + /// + /// Set the default DbProvider to be used by the Scheduler. If set, + /// this will override corresponding settings in Quartz properties. + /// + /// + ///

+ /// Note: If this is set, the Quartz settings should not define + /// a job store "dataSource" to avoid meaningless double configuration. + ///

+ ///

+ /// A Spring-specific subclass of Quartz' JobStoreSupport will be used. + /// It is therefore strongly recommended to perform all operations on + /// the Scheduler within Spring-managed transactions. + /// Else, database locking will not properly work and might even break + /// (e.g. if trying to obtain a lock on Oracle without a transaction). + ///

+ ///
+ /// + /// + public IDbProvider DbProvider + { + set => dbProvider = value; + } + + /// + /// Set the name of the object in the object factory that created this object. + /// + /// The name of the object in the factory. + /// + ///

+ /// Invoked after population of normal object properties but before an init + /// callback like 's + /// + /// method or a custom init-method. + ///

+ ///
+ public string ObjectName + { + set { - set + if (schedulerName == null) { - if (value == null || !typeof(ISchedulerFactory).IsAssignableFrom(value)) + schedulerName = value; + } + } + } + + /// + /// Gets a value indicating whether this is running. + /// + /// true if running; otherwise, false. + public virtual bool Running + { + get + { + if (scheduler != null) + { + try { - throw new ArgumentException("schedulerFactoryType must implement [Quartz.ISchedulerFactory]"); + return !scheduler.InStandbyMode; } - - schedulerFactoryType = value; - } - } - - /// - /// Set the name of the Scheduler to fetch from the SchedulerFactory. - /// If not specified, the default Scheduler will be used. - /// - /// The name of the scheduler. - /// - /// - public virtual string SchedulerName - { - set => schedulerName = value; - } - - /// - /// Set the location of the Quartz properties config file, for example - /// as assembly resource "assembly:quartz.properties". - /// - /// - /// Note: Can be omitted when all necessary properties are specified - /// locally via this object, or when relying on Quartz' default configuration. - /// - /// - public virtual IResource ConfigLocation - { - set => configLocation = value; - } - - /// - /// Set Quartz properties, like "quartz.threadPool.type". - /// - /// - /// Can be used to override values in a Quartz properties config file, - /// or to specify all necessary properties locally. - /// - /// - public virtual IDictionary QuartzProperties - { - set => quartzProperties = value; - } - - /// - /// Set the Spring TaskExecutor to use as Quartz backend. - /// Exposed as thread pool through the Quartz SPI. - /// - /// - /// By default, a Quartz SimpleThreadPool will be used, configured through - /// the corresponding Quartz properties. - /// - /// The task executor. - /// - /// - public virtual ITaskExecutor TaskExecutor - { - set => taskExecutor = value; - } - - /// - /// Register objects in the Scheduler context via a given Map. - /// These objects will be available to any Job that runs in this Scheduler. - /// - /// - /// Note: When using persistent Jobs whose JobDetail will be kept in the - /// database, do not put Spring-managed object or an ApplicationContext - /// reference into the JobDataMap but rather into the SchedulerContext. - /// - /// - /// Map with string keys and any objects as - /// values (for example Spring-managed objects) - /// - /// - public virtual IDictionary SchedulerContextAsMap - { - set => schedulerContextMap = value; - } - - /// - /// Set the key of an IApplicationContext reference to expose in the - /// SchedulerContext, for example "applicationContext". Default is none. - /// Only applicable when running in a Spring ApplicationContext. - /// - /// - ///

- /// Note: When using persistent Jobs whose JobDetail will be kept in the - /// database, do not put an IApplicationContext reference into the JobDataMap - /// but rather into the SchedulerContext. - ///

- /// - ///

- /// In case of a QuartzJobObject, the reference will be applied to the Job - /// instance as object property. An "applicationContext" attribute will - /// correspond to a "setApplicationContext" method in that scenario. - ///

- /// - ///

- /// Note that ObjectFactory callback interfaces like IApplicationContextAware - /// are not automatically applied to Quartz Job instances, because Quartz - /// itself is reponsible for the lifecycle of its Jobs. - ///

- ///
- /// The application context scheduler context key. - /// - public virtual string ApplicationContextSchedulerContextKey - { - set => applicationContextSchedulerContextKey = value; - } - - /// - /// Set the Quartz JobFactory to use for this Scheduler. - /// - /// - ///

- /// Default is Spring's , which supports - /// standard Quartz instances. Note that this default only applies - /// to a local Scheduler, not to a RemoteScheduler (where setting - /// a custom JobFactory is not supported by Quartz). - ///

- ///

- /// Specify an instance of Spring's here - /// (typically as an inner object definition) to automatically populate a job's - /// object properties from the specified job data map and scheduler context. - ///

- ///
- /// - /// - public virtual IJobFactory JobFactory - { - set - { - jobFactory = value; - jobFactorySet = true; - } - } - - /// - /// Set whether to expose the Spring-managed instance in the - /// Quartz . Default is "false", since the Spring-managed - /// Scheduler is usually exclusively intended for access within the Spring context. - /// - /// - /// Switch this flag to "true" in order to expose the Scheduler globally. - /// This is not recommended unless you have an existing Spring application that - /// relies on this behavior. - /// - public virtual bool ExposeSchedulerInRepository - { - set => exposeSchedulerInRepository = value; - } - - /// - /// Set whether to automatically start the scheduler after initialization. - /// Default is "true"; set this to "false" to allow for manual startup. - /// - public virtual bool AutoStartup - { - set => autoStartup = value; - } - - /// - /// Set the time span to wait after initialization before - /// starting the scheduler asynchronously. Default is 0, meaning - /// immediate synchronous startup on initialization of this object. - /// - /// - /// Setting this to 10 or 20 seconds makes sense if no jobs - /// should be run before the entire application has started up. - /// - public virtual TimeSpan StartupDelay - { - set => startupDelay = value; - } - - /// - /// Set whether to wait for running jobs to complete on Shutdown. - /// Default is "false". - /// - /// - /// true if [wait for jobs to complete on Shutdown]; otherwise, false. - /// - /// - public virtual bool WaitForJobsToCompleteOnShutdown - { - set => waitForJobsToCompleteOnShutdown = value; - } - - /// - /// Set the default DbProvider to be used by the Scheduler. If set, - /// this will override corresponding settings in Quartz properties. - /// - /// - ///

- /// Note: If this is set, the Quartz settings should not define - /// a job store "dataSource" to avoid meaningless double configuration. - ///

- ///

- /// A Spring-specific subclass of Quartz' JobStoreSupport will be used. - /// It is therefore strongly recommended to perform all operations on - /// the Scheduler within Spring-managed transactions. - /// Else, database locking will not properly work and might even break - /// (e.g. if trying to obtain a lock on Oracle without a transaction). - ///

- ///
- /// - /// - public IDbProvider DbProvider - { - set => dbProvider = value; - } - - /// - /// Set the name of the object in the object factory that created this object. - /// - /// The name of the object in the factory. - /// - ///

- /// Invoked after population of normal object properties but before an init - /// callback like 's - /// - /// method or a custom init-method. - ///

- ///
- public string ObjectName - { - set - { - if (schedulerName == null) + catch (SchedulerException) { - schedulerName = value; + return false; } } + + return false; + } + } + + /// + /// Sets the that this + /// object runs in. + /// + /// + /// + ///

+ /// Normally this call will be used to initialize the object. + ///

+ ///

+ /// Invoked after population of normal object properties but before an + /// init callback such as + /// 's + /// + /// or a custom init-method. Invoked after the setting of any + /// 's + /// + /// property. + ///

+ ///
+ /// + /// In the case of application context initialization errors. + /// + /// + /// If thrown by any application context methods. + /// + /// + public virtual IApplicationContext ApplicationContext + { + set => applicationContext = value; + } + + /// + /// Shut down the Quartz scheduler on object factory Shutdown, + /// stopping all scheduled jobs. + /// + public virtual void Dispose() + { + Logger.LogInformation("Shutting down Quartz Scheduler"); + scheduler.Shutdown(waitForJobsToCompleteOnShutdown).ConfigureAwait(false).GetAwaiter().GetResult(); + } + + /// + /// Template method that determines the Scheduler to operate on. + /// To be implemented by subclasses. + /// + /// + protected override IScheduler GetScheduler() + { + return scheduler; + } + + /// + /// Return an instance (possibly shared or independent) of the object + /// managed by this factory. + /// + /// + /// An instance (possibly shared or independent) of the object managed by + /// this factory. + /// + /// + /// + /// If this method is being called in the context of an enclosing IoC container and + /// returns , the IoC container will consider this factory + /// object as not being fully initialized and throw a corresponding (and most + /// probably fatal) exception. + /// + /// + public virtual object GetObject() + { + return scheduler; + } + + /// + /// Return the of object that this + /// creates, or + /// if not known in advance. + /// + /// + public virtual Type ObjectType => (scheduler != null) ? scheduler.GetType() : typeof(IScheduler); + + /// + /// Is the object managed by this factory a singleton or a prototype? + /// + /// + public virtual bool IsSingleton => true; + + //--------------------------------------------------------------------- + // Implementation of IInitializingObject interface + //--------------------------------------------------------------------- + + /// + /// Invoked by an + /// after it has injected all of an object's dependencies. + /// + /// + ///

+ /// This method allows the object instance to perform the kind of + /// initialization only possible when all of it's dependencies have + /// been injected (set), and to throw an appropriate exception in the + /// event of misconfiguration. + ///

+ ///

+ /// Please do consult the class level documentation for the + /// interface for a + /// description of exactly when this method is invoked. In + /// particular, it is worth noting that the + /// + /// and + /// callbacks will have been invoked prior to this method being + /// called. + ///

+ ///
+ /// + /// In the event of misconfiguration (such as the failure to set a + /// required property) or if initialization fails. + /// + public virtual void AfterPropertiesSet() + { + // Create SchedulerFactory instance. + ISchedulerFactory schedulerFactory = ObjectUtils.InstantiateType(schedulerFactoryType); + + InitSchedulerFactory(schedulerFactory); + + if (taskExecutor != null) + { + // Make given TaskExecutor available for SchedulerFactory configuration. + configTimeTaskExecutor = taskExecutor; } - /// - /// Gets a value indicating whether this is running. - /// - /// true if running; otherwise, false. - public virtual bool Running + if (dbProvider != null) { - get + // Make given db provider available for SchedulerFactory configuration. + configTimeDbProvider = dbProvider; + } + + try + { + // Get Scheduler instance from SchedulerFactory. + scheduler = CreateScheduler(schedulerFactory, schedulerName); + PopulateSchedulerContext(); + + if (!jobFactorySet && !(scheduler is RemoteScheduler)) { - if (scheduler != null) + // Use AdaptableJobFactory as default for a local Scheduler, unless when + // explicitly given a null value through the "jobFactory" object property. + jobFactory = new AdaptableJobFactory(); + } + + if (jobFactory != null) + { + if (jobFactory is ISchedulerContextAware) { - try - { - return !scheduler.InStandbyMode; - } - catch (SchedulerException) - { - return false; - } + ((ISchedulerContextAware) jobFactory).SchedulerContext = scheduler.Context; } - return false; + scheduler.JobFactory = jobFactory; } } - - /// - /// Sets the that this - /// object runs in. - /// - /// - /// - ///

- /// Normally this call will be used to initialize the object. - ///

- ///

- /// Invoked after population of normal object properties but before an - /// init callback such as - /// 's - /// - /// or a custom init-method. Invoked after the setting of any - /// 's - /// - /// property. - ///

- ///
- /// - /// In the case of application context initialization errors. - /// - /// - /// If thrown by any application context methods. - /// - /// - public virtual IApplicationContext ApplicationContext + finally { - set => applicationContext = value; - } - - /// - /// Shut down the Quartz scheduler on object factory Shutdown, - /// stopping all scheduled jobs. - /// - public virtual void Dispose() - { - Logger.LogInformation("Shutting down Quartz Scheduler"); - scheduler.Shutdown(waitForJobsToCompleteOnShutdown).ConfigureAwait(false).GetAwaiter().GetResult(); - } - - /// - /// Template method that determines the Scheduler to operate on. - /// To be implemented by subclasses. - /// - /// - protected override IScheduler GetScheduler() - { - return scheduler; - } - - /// - /// Return an instance (possibly shared or independent) of the object - /// managed by this factory. - /// - /// - /// An instance (possibly shared or independent) of the object managed by - /// this factory. - /// - /// - /// - /// If this method is being called in the context of an enclosing IoC container and - /// returns , the IoC container will consider this factory - /// object as not being fully initialized and throw a corresponding (and most - /// probably fatal) exception. - /// - /// - public virtual object GetObject() - { - return scheduler; - } - - /// - /// Return the of object that this - /// creates, or - /// if not known in advance. - /// - /// - public virtual Type ObjectType => (scheduler != null) ? scheduler.GetType() : typeof(IScheduler); - - /// - /// Is the object managed by this factory a singleton or a prototype? - /// - /// - public virtual bool IsSingleton => true; - - //--------------------------------------------------------------------- - // Implementation of IInitializingObject interface - //--------------------------------------------------------------------- - - /// - /// Invoked by an - /// after it has injected all of an object's dependencies. - /// - /// - ///

- /// This method allows the object instance to perform the kind of - /// initialization only possible when all of it's dependencies have - /// been injected (set), and to throw an appropriate exception in the - /// event of misconfiguration. - ///

- ///

- /// Please do consult the class level documentation for the - /// interface for a - /// description of exactly when this method is invoked. In - /// particular, it is worth noting that the - /// - /// and - /// callbacks will have been invoked prior to this method being - /// called. - ///

- ///
- /// - /// In the event of misconfiguration (such as the failure to set a - /// required property) or if initialization fails. - /// - public virtual void AfterPropertiesSet() - { - // Create SchedulerFactory instance. - ISchedulerFactory schedulerFactory = ObjectUtils.InstantiateType(schedulerFactoryType); - - InitSchedulerFactory(schedulerFactory); - if (taskExecutor != null) { - // Make given TaskExecutor available for SchedulerFactory configuration. - configTimeTaskExecutor = taskExecutor; + configTimeTaskExecutor = null; } if (dbProvider != null) { - // Make given db provider available for SchedulerFactory configuration. - configTimeDbProvider = dbProvider; + configTimeDbProvider = null; + } + } + + RegisterListeners(); + RegisterJobsAndTriggers().ConfigureAwait(false).GetAwaiter().GetResult(); + } + + /// + /// Load and/or apply Quartz properties to the given SchedulerFactory. + /// + /// the SchedulerFactory to Initialize + private void InitSchedulerFactory(ISchedulerFactory schedulerFactory) + { + if (!(schedulerFactory is StdSchedulerFactory)) + { + if (configLocation != null || quartzProperties != null || schedulerName != null || + taskExecutor != null || dbProvider != null) + { + throw new ArgumentException("StdSchedulerFactory required for applying Quartz properties: " + + schedulerFactory); } + // Otherwise assume that no initialization is necessary... + return; + } + + NameValueCollection mergedProps = new NameValueCollection(); + + // Set necessary default properties here, as Quartz will not apply + // its default configuration when explicitly given properties. + if (taskExecutor != null) + { + mergedProps[StdSchedulerFactory.PropertyThreadPoolType] = + typeof(LocalTaskExecutorThreadPool).AssemblyQualifiedName; + } + else + { + mergedProps.Set(StdSchedulerFactory.PropertyThreadPoolType, + typeof(DefaultThreadPool).AssemblyQualifiedName); + mergedProps[PropThreadCount] = Convert.ToString(DefaultThreadCount); + } + + if (configLocation != null) + { + if (Logger.IsEnabled(LogLevel.Information)) + { + Logger.LogInformation("Loading Quartz config from [" + configLocation + "]"); + } + + using (StreamReader sr = new StreamReader(configLocation.InputStream)) + { + string line; + while ((line = sr.ReadLine()) != null) + { + string[] lineItems = line.Split(new char[] { '=' }, 2); + if (lineItems.Length == 2) + { + mergedProps[lineItems[0].Trim()] = lineItems[1].Trim(); + } + } + } + } + + if (quartzProperties != null) + { + // if given quartz properties, merge to them to configuration + MergePropertiesIntoMap(quartzProperties, mergedProps); + } + + if (dbProvider != null) + { + mergedProps[StdSchedulerFactory.PropertyJobStoreType] = + typeof(LocalDataSourceJobStore).AssemblyQualifiedName; + } + + // Make sure to set the scheduler name as configured in the Spring configuration. + if (schedulerName != null) + { + mergedProps[StdSchedulerFactory.PropertySchedulerInstanceName] = schedulerName; + } + + ((StdSchedulerFactory) schedulerFactory).Initialize(mergedProps); + } + + /// + /// Merges the properties into map. This effectively also + /// overwrites existing properties with same key in map. + /// + /// The properties to merge into given map. + /// The map to merge to. + protected virtual void MergePropertiesIntoMap(IDictionary properties, NameValueCollection map) + { + foreach (string key in properties.Keys) + { + map[key] = (string) properties[key]; + } + } + + /// + /// Create the Scheduler instance for the given factory and scheduler name. + /// Called by afterPropertiesSet. + /// + /// + /// Default implementation invokes SchedulerFactory's GetScheduler + /// method. Can be overridden for custom Scheduler creation. + /// + /// the factory to create the Scheduler with + /// the name of the scheduler to create + /// the Scheduler instance + /// + /// + protected virtual IScheduler CreateScheduler(ISchedulerFactory schedulerFactory, string schedName) + { + SchedulerRepository repository = SchedulerRepository.Instance; + lock (repository) + { + IScheduler existingScheduler = schedulerName != null + ? repository.Lookup(schedulerName).ConfigureAwait(false).GetAwaiter().GetResult() + : null; + + IScheduler newScheduler = + schedulerFactory.GetScheduler().ConfigureAwait(false).GetAwaiter().GetResult(); + if (newScheduler == existingScheduler) + { + throw new InvalidOperationException( + $"Active Scheduler of name '{schedulerName}' already registered in Quartz SchedulerRepository. Cannot create a new Spring-managed Scheduler of the same name!"); + } + + if (!exposeSchedulerInRepository) + { + // Need to explicitly remove it if not intended for exposure, + // since Quartz shares the Scheduler instance by default! + SchedulerRepository.Instance.Remove(newScheduler.SchedulerName); + } + + return newScheduler; + } + } + + /// + /// Expose the specified context attributes and/or the current + /// IApplicationContext in the Quartz SchedulerContext. + /// + private void PopulateSchedulerContext() + { + // Put specified objects into Scheduler context. + if (schedulerContextMap != null) + { + var dictionary = schedulerContextMap.Cast() + .ToDictionary(entry => entry.Key.ToString(), entry => entry.Value); + scheduler.Context.PutAll(dictionary); + } + + // Register IApplicationContext in Scheduler context. + if (applicationContextSchedulerContextKey != null) + { + if (applicationContext == null) + { + throw new SystemException("SchedulerFactoryObject needs to be set up in an IApplicationContext " + + "to be able to handle an 'applicationContextSchedulerContextKey'"); + } + + scheduler.Context.Put(applicationContextSchedulerContextKey, applicationContext); + } + } + + /// + /// Start the Quartz Scheduler, respecting the "startDelay" setting. + /// + /// the Scheduler to start + /// the time span to wait before starting + /// the Scheduler asynchronously + protected virtual async Task StartScheduler(IScheduler sched, TimeSpan startDelay) + { + if (startDelay.TotalSeconds <= 0) + { + Logger.LogInformation("Starting Quartz Scheduler now"); + await sched.Start().ConfigureAwait(false); + } + else + { + if (Logger.IsEnabled(LogLevel.Information)) + { + Logger.LogInformation("Will start Quartz Scheduler [{SchedulerName}] in {StartDelaySeconds} seconds", sched.SchedulerName, startDelay); + } + + await sched.StartDelayed(startDelay).ConfigureAwait(false); + } + } + + //--------------------------------------------------------------------- + // Implementation of Lifecycle interface + //--------------------------------------------------------------------- + + /// + /// Starts this instance. + /// + public virtual async Task Start() + { + if (scheduler != null) + { try { - // Get Scheduler instance from SchedulerFactory. - scheduler = CreateScheduler(schedulerFactory, schedulerName); - PopulateSchedulerContext(); - - if (!jobFactorySet && !(scheduler is RemoteScheduler)) - { - // Use AdaptableJobFactory as default for a local Scheduler, unless when - // explicitly given a null value through the "jobFactory" object property. - jobFactory = new AdaptableJobFactory(); - } - - if (jobFactory != null) - { - if (jobFactory is ISchedulerContextAware) - { - ((ISchedulerContextAware) jobFactory).SchedulerContext = scheduler.Context; - } - - scheduler.JobFactory = jobFactory; - } + await scheduler.Start().ConfigureAwait(false); } - finally + catch (SchedulerException ex) { - if (taskExecutor != null) - { - configTimeTaskExecutor = null; - } - - if (dbProvider != null) - { - configTimeDbProvider = null; - } - } - - RegisterListeners(); - RegisterJobsAndTriggers().ConfigureAwait(false).GetAwaiter().GetResult(); - } - - /// - /// Load and/or apply Quartz properties to the given SchedulerFactory. - /// - /// the SchedulerFactory to Initialize - private void InitSchedulerFactory(ISchedulerFactory schedulerFactory) - { - if (!(schedulerFactory is StdSchedulerFactory)) - { - if (configLocation != null || quartzProperties != null || schedulerName != null || - taskExecutor != null || dbProvider != null) - { - throw new ArgumentException("StdSchedulerFactory required for applying Quartz properties: " + - schedulerFactory); - } - - // Otherwise assume that no initialization is necessary... - return; - } - - NameValueCollection mergedProps = new NameValueCollection(); - - // Set necessary default properties here, as Quartz will not apply - // its default configuration when explicitly given properties. - if (taskExecutor != null) - { - mergedProps[StdSchedulerFactory.PropertyThreadPoolType] = - typeof(LocalTaskExecutorThreadPool).AssemblyQualifiedName; - } - else - { - mergedProps.Set(StdSchedulerFactory.PropertyThreadPoolType, - typeof(DefaultThreadPool).AssemblyQualifiedName); - mergedProps[PropThreadCount] = Convert.ToString(DefaultThreadCount); - } - - if (configLocation != null) - { - if (Logger.IsEnabled(LogLevel.Information)) - { - Logger.LogInformation("Loading Quartz config from [" + configLocation + "]"); - } - - using (StreamReader sr = new StreamReader(configLocation.InputStream)) - { - string line; - while ((line = sr.ReadLine()) != null) - { - string[] lineItems = line.Split(new char[] {'='}, 2); - if (lineItems.Length == 2) - { - mergedProps[lineItems[0].Trim()] = lineItems[1].Trim(); - } - } - } - } - - if (quartzProperties != null) - { - // if given quartz properties, merge to them to configuration - MergePropertiesIntoMap(quartzProperties, mergedProps); - } - - if (dbProvider != null) - { - mergedProps[StdSchedulerFactory.PropertyJobStoreType] = - typeof(LocalDataSourceJobStore).AssemblyQualifiedName; - } - - // Make sure to set the scheduler name as configured in the Spring configuration. - if (schedulerName != null) - { - mergedProps[StdSchedulerFactory.PropertySchedulerInstanceName] = schedulerName; - } - - ((StdSchedulerFactory) schedulerFactory).Initialize(mergedProps); - } - - /// - /// Merges the properties into map. This effectively also - /// overwrites existing properties with same key in map. - /// - /// The properties to merge into given map. - /// The map to merge to. - protected virtual void MergePropertiesIntoMap(IDictionary properties, NameValueCollection map) - { - foreach (string key in properties.Keys) - { - map[key] = (string) properties[key]; + throw new SchedulingException("Could not start Quartz Scheduler", ex); } } + } - /// - /// Create the Scheduler instance for the given factory and scheduler name. - /// Called by afterPropertiesSet. - /// - /// - /// Default implementation invokes SchedulerFactory's GetScheduler - /// method. Can be overridden for custom Scheduler creation. - /// - /// the factory to create the Scheduler with - /// the name of the scheduler to create - /// the Scheduler instance - /// - /// - protected virtual IScheduler CreateScheduler(ISchedulerFactory schedulerFactory, string schedName) + /// + /// Stops this instance. + /// + public virtual async Task Stop() + { + if (scheduler != null) { - SchedulerRepository repository = SchedulerRepository.Instance; - lock (repository) + try { - IScheduler existingScheduler = schedulerName != null - ? repository.Lookup(schedulerName).ConfigureAwait(false).GetAwaiter().GetResult() - : null; - - IScheduler newScheduler = - schedulerFactory.GetScheduler().ConfigureAwait(false).GetAwaiter().GetResult(); - if (newScheduler == existingScheduler) - { - throw new InvalidOperationException( - $"Active Scheduler of name '{schedulerName}' already registered in Quartz SchedulerRepository. Cannot create a new Spring-managed Scheduler of the same name!"); - } - - if (!exposeSchedulerInRepository) - { - // Need to explicitly remove it if not intended for exposure, - // since Quartz shares the Scheduler instance by default! - SchedulerRepository.Instance.Remove(newScheduler.SchedulerName); - } - - return newScheduler; + await scheduler.Standby().ConfigureAwait(false); + } + catch (SchedulerException ex) + { + throw new SchedulingException("Could not stop Quartz Scheduler", ex); } } + } - /// - /// Expose the specified context attributes and/or the current - /// IApplicationContext in the Quartz SchedulerContext. - /// - private void PopulateSchedulerContext() + /// + /// Handles the application context's refresh event and starts the scheduler. + /// + public void HandleApplicationEvent(object sender, ApplicationEventArgs e) + { + // auto-start Scheduler if demanded + if (e is ContextRefreshedEventArgs && autoStartup) { - // Put specified objects into Scheduler context. - if (schedulerContextMap != null) + try { - var dictionary = schedulerContextMap.Cast() - .ToDictionary(entry => entry.Key.ToString(), entry => entry.Value); - scheduler.Context.PutAll(dictionary); + StartScheduler(scheduler, startupDelay).ConfigureAwait(false).GetAwaiter().GetResult(); } - - // Register IApplicationContext in Scheduler context. - if (applicationContextSchedulerContextKey != null) + catch (SchedulerException ex) { - if (applicationContext == null) - { - throw new SystemException("SchedulerFactoryObject needs to be set up in an IApplicationContext " + - "to be able to handle an 'applicationContextSchedulerContextKey'"); - } - - scheduler.Context.Put(applicationContextSchedulerContextKey, applicationContext); - } - } - - /// - /// Start the Quartz Scheduler, respecting the "startDelay" setting. - /// - /// the Scheduler to start - /// the time span to wait before starting - /// the Scheduler asynchronously - protected virtual async Task StartScheduler(IScheduler sched, TimeSpan startDelay) - { - if (startDelay.TotalSeconds <= 0) - { - Logger.LogInformation("Starting Quartz Scheduler now"); - await sched.Start().ConfigureAwait(false); - } - else - { - if (Logger.IsEnabled(LogLevel.Information)) - { - Logger.LogInformation("Will start Quartz Scheduler [{SchedulerName}] in {StartDelaySeconds} seconds", sched.SchedulerName, startDelay); - } - - await sched.StartDelayed(startDelay).ConfigureAwait(false); - } - } - - //--------------------------------------------------------------------- - // Implementation of Lifecycle interface - //--------------------------------------------------------------------- - - /// - /// Starts this instance. - /// - public virtual async Task Start() - { - if (scheduler != null) - { - try - { - await scheduler.Start().ConfigureAwait(false); - } - catch (SchedulerException ex) - { - throw new SchedulingException("Could not start Quartz Scheduler", ex); - } - } - } - - /// - /// Stops this instance. - /// - public virtual async Task Stop() - { - if (scheduler != null) - { - try - { - await scheduler.Standby().ConfigureAwait(false); - } - catch (SchedulerException ex) - { - throw new SchedulingException("Could not stop Quartz Scheduler", ex); - } - } - } - - /// - /// Handles the application context's refresh event and starts the scheduler. - /// - public void HandleApplicationEvent(object sender, ApplicationEventArgs e) - { - // auto-start Scheduler if demanded - if (e is ContextRefreshedEventArgs && autoStartup) - { - try - { - StartScheduler(scheduler, startupDelay).ConfigureAwait(false).GetAwaiter().GetResult(); - } - catch (SchedulerException ex) - { - throw new ObjectInitializationException("failed to auto-start scheduler", ex); - } + throw new ObjectInitializationException("failed to auto-start scheduler", ex); } } } diff --git a/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/SchedulingException.cs b/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/SchedulingException.cs index 5e43c466..0acbd574 100644 --- a/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/SchedulingException.cs +++ b/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/SchedulingException.cs @@ -1,25 +1,24 @@ -namespace Spring.Scheduling.Quartz +namespace Spring.Scheduling.Quartz; + +/// +/// Generic scheduling exception. +/// +public class SchedulingException : Exception { /// - /// Generic scheduling exception. + /// Initializes a new instance of the class. /// - public class SchedulingException : Exception + /// The message. + public SchedulingException(string message) : base(message) { - /// - /// Initializes a new instance of the class. - /// - /// The message. - public SchedulingException(string message) : base(message) - { - } + } - /// - /// Initializes a new instance of the class. - /// - /// The message. - /// The original exception. - public SchedulingException(string message, Exception ex) : base(message, ex) - { - } + /// + /// Initializes a new instance of the class. + /// + /// The message. + /// The original exception. + public SchedulingException(string message, Exception ex) : base(message, ex) + { } } diff --git a/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/SimpleTriggerObject.cs b/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/SimpleTriggerObject.cs index 4d1b631c..9e8795da 100644 --- a/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/SimpleTriggerObject.cs +++ b/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/SimpleTriggerObject.cs @@ -1,18 +1,18 @@ /* -* Copyright 2002-2010 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. -*/ + * Copyright 2002-2010 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. + */ using System.Collections; using Quartz; @@ -20,193 +20,192 @@ using Quartz.Impl.Triggers; using Spring.Objects.Factory; using Spring.Util; -namespace Spring.Scheduling.Quartz +namespace Spring.Scheduling.Quartz; + +/// +/// Convenience subclass of Quartz's +/// class, making properties based usage easier. +/// +/// +///

+/// SimpleTrigger itself is already a PONO but lacks sensible defaults. +/// This class uses the Spring object name as job name, the Quartz default group +/// ("DEFAULT") as job group, the current time as start time, and indefinite +/// repetition, if not specified. +///

+/// +///

+/// This class will also register the trigger with the job name and group of +/// a given . This allows +/// to automatically register a trigger for the corresponding JobDetail, +/// instead of registering the JobDetail separately. +///

+///
+/// Juergen Hoeller +/// +/// +/// +/// +/// +/// +/// +public class SimpleTriggerObject : SimpleTriggerImpl, IJobDetailAwareTrigger, IObjectNameAware, IInitializingObject { - /// - /// Convenience subclass of Quartz's - /// class, making properties based usage easier. + private TimeSpan startDelay = TimeSpan.Zero; + private IJobDetail jobDetail; + private string objectName; + + private readonly Constants constants = + new Constants(typeof(MisfireInstruction.SimpleTrigger), typeof(MisfireInstruction)); + + /// + /// Initializes a new instance of the class. /// - /// - ///

- /// SimpleTrigger itself is already a PONO but lacks sensible defaults. - /// This class uses the Spring object name as job name, the Quartz default group - /// ("DEFAULT") as job group, the current time as start time, and indefinite - /// repetition, if not specified. - ///

- /// - ///

- /// This class will also register the trigger with the job name and group of - /// a given . This allows - /// to automatically register a trigger for the corresponding JobDetail, - /// instead of registering the JobDetail separately. - ///

- ///
- /// Juergen Hoeller - /// - /// - /// - /// - /// - /// - /// - public class SimpleTriggerObject : SimpleTriggerImpl, IJobDetailAwareTrigger, IObjectNameAware, IInitializingObject + public SimpleTriggerObject() { - private TimeSpan startDelay = TimeSpan.Zero; - private IJobDetail jobDetail; - private string objectName; + RepeatCount = RepeatIndefinitely; + } - private readonly Constants constants = - new Constants(typeof(MisfireInstruction.SimpleTrigger), typeof(MisfireInstruction)); - - /// - /// Initializes a new instance of the class. - /// - public SimpleTriggerObject() + /// + /// Register objects in the JobDataMap via a given Map. + ///

+ /// These objects will be available to this Trigger only, + /// in contrast to objects in the JobDetail's data map. + ///

+ ///
+ /// + public virtual IDictionary JobDataAsMap + { + set { - RepeatCount = RepeatIndefinitely; - } - - /// - /// Register objects in the JobDataMap via a given Map. - ///

- /// These objects will be available to this Trigger only, - /// in contrast to objects in the JobDetail's data map. - ///

- ///
- /// - public virtual IDictionary JobDataAsMap - { - set + foreach (DictionaryEntry entry in value) { - foreach (DictionaryEntry entry in value) - { - JobDataMap.Put((string) entry.Key, entry.Value); - } - } - } - - /// - /// Set the misfire instruction via the name of the corresponding - /// constant in the SimpleTrigger class. - /// Default is . - /// - /// - /// - /// - /// - /// - /// - public virtual string MisfireInstructionName - { - set => MisfireInstruction = constants.AsNumber(value); - } - - /// - /// Set the delay before starting the job for the first time. - /// The given time span will be added to the current - /// time to calculate the start time. Default is . - /// - /// - /// This delay will just be applied if no custom start time was - /// specified. However, in typical usage within a Spring context, - /// the start time will be the container startup time anyway. - /// Specifying a relative delay is appropriate in that case. - /// - /// - public virtual TimeSpan StartDelay - { - set - { - AssertUtils.State(value >= TimeSpan.Zero, "Start delay cannot be negative."); - startDelay = value; - } - get => startDelay; - } - - /// - /// Set the name of the object in the object factory that created this object. - /// - /// The name of the object in the factory. - /// - ///

- /// Invoked after population of normal object properties but before an init - /// callback like 's - /// - /// method or a custom init-method. - ///

- ///
- public virtual string ObjectName - { - set => objectName = value; - } - - /// - /// Set the JobDetail that this trigger should be associated with. - ///

- /// This is typically used with a object reference if the JobDetail - /// is a Spring-managed object. Alternatively, the trigger can also - /// be associated with a job by name and group. - ///

- ///
- public virtual IJobDetail JobDetail - { - get => jobDetail; - set => jobDetail = value; - } - - /// - /// Invoked by an - /// after it has injected all of an object's dependencies. - /// - /// - ///

- /// This method allows the object instance to perform the kind of - /// initialization only possible when all of it's dependencies have - /// been injected (set), and to throw an appropriate exception in the - /// event of misconfiguration. - ///

- ///

- /// Please do consult the class level documentation for the - /// interface for a - /// description of exactly when this method is invoked. In - /// particular, it is worth noting that the - /// - /// and - /// callbacks will have been invoked prior to this method being - /// called. - ///

- ///
- /// - /// In the event of misconfiguration (such as the failure to set a - /// required property) or if initialization fails. - /// - public virtual void AfterPropertiesSet() - { - if (StartTimeUtc == DateTimeOffset.MinValue) - { - StartTimeUtc = DateTimeOffset.UtcNow; - } - - if (StartDelay > TimeSpan.Zero) - { - StartTimeUtc = DateTime.UtcNow.Add(startDelay); - } - - if (Name == null) - { - Name = objectName; - } - - if (Group == null) - { - Group = SchedulerConstants.DefaultGroup; - } - - if (jobDetail != null) - { - JobName = jobDetail.Key.Name; - JobGroup = jobDetail.Key.Group; + JobDataMap.Put((string) entry.Key, entry.Value); } } } + + /// + /// Set the misfire instruction via the name of the corresponding + /// constant in the SimpleTrigger class. + /// Default is . + /// + /// + /// + /// + /// + /// + /// + public virtual string MisfireInstructionName + { + set => MisfireInstruction = constants.AsNumber(value); + } + + /// + /// Set the delay before starting the job for the first time. + /// The given time span will be added to the current + /// time to calculate the start time. Default is . + /// + /// + /// This delay will just be applied if no custom start time was + /// specified. However, in typical usage within a Spring context, + /// the start time will be the container startup time anyway. + /// Specifying a relative delay is appropriate in that case. + /// + /// + public virtual TimeSpan StartDelay + { + set + { + AssertUtils.State(value >= TimeSpan.Zero, "Start delay cannot be negative."); + startDelay = value; + } + get => startDelay; + } + + /// + /// Set the name of the object in the object factory that created this object. + /// + /// The name of the object in the factory. + /// + ///

+ /// Invoked after population of normal object properties but before an init + /// callback like 's + /// + /// method or a custom init-method. + ///

+ ///
+ public virtual string ObjectName + { + set => objectName = value; + } + + /// + /// Set the JobDetail that this trigger should be associated with. + ///

+ /// This is typically used with a object reference if the JobDetail + /// is a Spring-managed object. Alternatively, the trigger can also + /// be associated with a job by name and group. + ///

+ ///
+ public virtual IJobDetail JobDetail + { + get => jobDetail; + set => jobDetail = value; + } + + /// + /// Invoked by an + /// after it has injected all of an object's dependencies. + /// + /// + ///

+ /// This method allows the object instance to perform the kind of + /// initialization only possible when all of it's dependencies have + /// been injected (set), and to throw an appropriate exception in the + /// event of misconfiguration. + ///

+ ///

+ /// Please do consult the class level documentation for the + /// interface for a + /// description of exactly when this method is invoked. In + /// particular, it is worth noting that the + /// + /// and + /// callbacks will have been invoked prior to this method being + /// called. + ///

+ ///
+ /// + /// In the event of misconfiguration (such as the failure to set a + /// required property) or if initialization fails. + /// + public virtual void AfterPropertiesSet() + { + if (StartTimeUtc == DateTimeOffset.MinValue) + { + StartTimeUtc = DateTimeOffset.UtcNow; + } + + if (StartDelay > TimeSpan.Zero) + { + StartTimeUtc = DateTime.UtcNow.Add(startDelay); + } + + if (Name == null) + { + Name = objectName; + } + + if (Group == null) + { + Group = SchedulerConstants.DefaultGroup; + } + + if (jobDetail != null) + { + JobName = jobDetail.Key.Name; + JobGroup = jobDetail.Key.Group; + } + } } diff --git a/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/SpringDbProviderAdapter.cs b/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/SpringDbProviderAdapter.cs index 09238e9e..a6bcd887 100644 --- a/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/SpringDbProviderAdapter.cs +++ b/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/SpringDbProviderAdapter.cs @@ -20,247 +20,246 @@ using System.Reflection; using Quartz.Impl.AdoJobStore.Common; using IDbMetadata = Spring.Data.Common.IDbMetadata; -namespace Spring.Scheduling.Quartz +namespace Spring.Scheduling.Quartz; + +/// +/// Adapts Spring's to Quartz's +/// . +/// +public class SpringDbProviderAdapter : IDbProvider { + private readonly Data.Common.IDbProvider dbProvider; + private readonly DbMetadata metadata; + /// - /// Adapts Spring's to Quartz's - /// . + /// Initializes a new instance of the class. /// - public class SpringDbProviderAdapter : IDbProvider + /// The Spring db provider. + public SpringDbProviderAdapter(Data.Common.IDbProvider dbProvider) { - private readonly Data.Common.IDbProvider dbProvider; - private readonly DbMetadata metadata; - - /// - /// Initializes a new instance of the class. - /// - /// The Spring db provider. - public SpringDbProviderAdapter(Data.Common.IDbProvider dbProvider) - { - this.dbProvider = dbProvider; - metadata = new SpringMetadataAdapter(dbProvider.DbMetadata); - } - - /// - /// Initializes the db provider implementation. - /// - public void Initialize() - { - } - - /// - /// Creates the command. - /// - /// - public DbCommand CreateCommand() - { - return (DbCommand) dbProvider.CreateCommand(); - } - - /// - /// Creates the command builder. - /// - /// - public object CreateCommandBuilder() - { - return dbProvider.CreateCommandBuilder(); - } - - /// - /// Creates the connection. - /// - /// - public DbConnection CreateConnection() - { - return (DbConnection) dbProvider.CreateConnection(); - } - - /// - /// Creates the parameter. - /// - /// - public IDbDataParameter CreateParameter() - { - return dbProvider.CreateParameter(); - } - - /// - /// Shutdowns this instance. - /// - public void Shutdown() - { - // no-op - } - - /// - /// Gets or sets the connection string. - /// - /// The connection string. - public string ConnectionString - { - get => dbProvider.ConnectionString; - set => dbProvider.ConnectionString = value; - } - - /// - /// Gets the metadata. - /// - /// The metadata. - public DbMetadata Metadata => metadata; + this.dbProvider = dbProvider; + metadata = new SpringMetadataAdapter(dbProvider.DbMetadata); } /// - /// Helper class to map between Quartz and Spring DB metadata. + /// Initializes the db provider implementation. /// - public class SpringMetadataAdapter : DbMetadata + public void Initialize() { - private readonly IDbMetadata metadata; - private readonly Enum dbTypeBinary; + } - /// - /// Initializes a new instance of the class. - /// - /// The metadata to wrap and adapt. - public SpringMetadataAdapter(IDbMetadata metadata) + /// + /// Creates the command. + /// + /// + public DbCommand CreateCommand() + { + return (DbCommand) dbProvider.CreateCommand(); + } + + /// + /// Creates the command builder. + /// + /// + public object CreateCommandBuilder() + { + return dbProvider.CreateCommandBuilder(); + } + + /// + /// Creates the connection. + /// + /// + public DbConnection CreateConnection() + { + return (DbConnection) dbProvider.CreateConnection(); + } + + /// + /// Creates the parameter. + /// + /// + public IDbDataParameter CreateParameter() + { + return dbProvider.CreateParameter(); + } + + /// + /// Shutdowns this instance. + /// + public void Shutdown() + { + // no-op + } + + /// + /// Gets or sets the connection string. + /// + /// The connection string. + public string ConnectionString + { + get => dbProvider.ConnectionString; + set => dbProvider.ConnectionString = value; + } + + /// + /// Gets the metadata. + /// + /// The metadata. + public DbMetadata Metadata => metadata; +} + +/// +/// Helper class to map between Quartz and Spring DB metadata. +/// +public class SpringMetadataAdapter : DbMetadata +{ + private readonly IDbMetadata metadata; + private readonly Enum dbTypeBinary; + + /// + /// Initializes a new instance of the class. + /// + /// The metadata to wrap and adapt. + public SpringMetadataAdapter(IDbMetadata metadata) + { + this.metadata = metadata; + // determine correct binary enum type + Type parameterType = metadata.ParameterDbType; + FieldInfo blobField = parameterType.GetField("Blob"); + FieldInfo imageField = parameterType.GetField("Image"); + if (blobField != null) { - this.metadata = metadata; - // determine correct binary enum type - Type parameterType = metadata.ParameterDbType; - FieldInfo blobField = parameterType.GetField("Blob"); - FieldInfo imageField = parameterType.GetField("Image"); - if (blobField != null) - { - // uses Blob, for example Oracle - dbTypeBinary = (Enum) blobField.GetValue(Activator.CreateInstance(parameterType)); - } - else if (imageField != null) - { - // uses Image, SQL Server - dbTypeBinary = (Enum) imageField.GetValue(Activator.CreateInstance(parameterType)); - } - else - { - // use standard binary type - dbTypeBinary = DbType.Binary; - } + // uses Blob, for example Oracle + dbTypeBinary = (Enum) blobField.GetValue(Activator.CreateInstance(parameterType)); } - - /// - /// Gets or sets the name of the product. - /// - /// The name of the product. - public override string ProductName + else if (imageField != null) { - get => metadata.ProductName; - set => throw new NotSupportedException(); + // uses Image, SQL Server + dbTypeBinary = (Enum) imageField.GetValue(Activator.CreateInstance(parameterType)); } - - /// - /// Gets or sets the type of the connection. - /// - /// The type of the connection. - public override Type ConnectionType + else { - get => metadata.ConnectionType; - set => throw new NotSupportedException(); + // use standard binary type + dbTypeBinary = DbType.Binary; } + } - /// - /// Gets or sets the type of the command. - /// - /// The type of the command. - public override Type CommandType - { - get => metadata.CommandType; - set => throw new NotSupportedException(); - } + /// + /// Gets or sets the name of the product. + /// + /// The name of the product. + public override string ProductName + { + get => metadata.ProductName; + set => throw new NotSupportedException(); + } - /// - /// Gets or sets the type of the parameter. - /// - /// The type of the parameter. - public override Type ParameterType - { - get => metadata.ParameterType; - set => throw new NotSupportedException(); - } + /// + /// Gets or sets the type of the connection. + /// + /// The type of the connection. + public override Type ConnectionType + { + get => metadata.ConnectionType; + set => throw new NotSupportedException(); + } - /// - /// Gets or sets the parameter name prefix. - /// - /// The parameter name prefix. - public override string ParameterNamePrefix - { - get => metadata.ParameterNamePrefix; - set => throw new NotSupportedException(); - } + /// + /// Gets or sets the type of the command. + /// + /// The type of the command. + public override Type CommandType + { + get => metadata.CommandType; + set => throw new NotSupportedException(); + } - /// - /// Gets or sets the type of the exception. - /// - /// The type of the exception. - public override Type ExceptionType - { - get => metadata.ExceptionType; - set => throw new NotSupportedException(); - } + /// + /// Gets or sets the type of the parameter. + /// + /// The type of the parameter. + public override Type ParameterType + { + get => metadata.ParameterType; + set => throw new NotSupportedException(); + } - /// - /// Gets or sets a value indicating whether [bind by name]. - /// - /// true if [bind by name]; otherwise, false. - public override bool BindByName - { - get => metadata.BindByName; - set => throw new NotSupportedException(); - } + /// + /// Gets or sets the parameter name prefix. + /// + /// The parameter name prefix. + public override string ParameterNamePrefix + { + get => metadata.ParameterNamePrefix; + set => throw new NotSupportedException(); + } - /// - /// Gets or sets the type of the parameter db. - /// - /// The type of the parameter db. - public override Type ParameterDbType - { - get => metadata.ParameterDbType; - set => throw new NotSupportedException(); - } + /// + /// Gets or sets the type of the exception. + /// + /// The type of the exception. + public override Type ExceptionType + { + get => metadata.ExceptionType; + set => throw new NotSupportedException(); + } - /// - /// Gets or sets the parameter db type property. - /// - /// The parameter db type property. - public override PropertyInfo ParameterDbTypeProperty - { - get => metadata.ParameterDbTypeProperty; - set => throw new NotSupportedException(); - } + /// + /// Gets or sets a value indicating whether [bind by name]. + /// + /// true if [bind by name]; otherwise, false. + public override bool BindByName + { + get => metadata.BindByName; + set => throw new NotSupportedException(); + } - /// - /// Gets or sets the parameter is nullable property. - /// - /// The parameter is nullable property. - public override PropertyInfo ParameterIsNullableProperty - { - get => metadata.ParameterIsNullableProperty; - set => throw new NotSupportedException(); - } + /// + /// Gets or sets the type of the parameter db. + /// + /// The type of the parameter db. + public override Type ParameterDbType + { + get => metadata.ParameterDbType; + set => throw new NotSupportedException(); + } - /// - /// Gets the type of the db binary. - /// - /// The type of the db binary. - public override Enum DbBinaryType => dbTypeBinary; + /// + /// Gets or sets the parameter db type property. + /// + /// The parameter db type property. + public override PropertyInfo ParameterDbTypeProperty + { + get => metadata.ParameterDbTypeProperty; + set => throw new NotSupportedException(); + } - /// - /// Gets or sets a value indicating whether [use parameter name prefix in parameter collection]. - /// - /// - /// true if [use parameter name prefix in parameter collection]; otherwise, false. - /// - public override bool UseParameterNamePrefixInParameterCollection - { - get => metadata.UseParameterNamePrefixInParameterCollection; - set => throw new NotSupportedException(); - } + /// + /// Gets or sets the parameter is nullable property. + /// + /// The parameter is nullable property. + public override PropertyInfo ParameterIsNullableProperty + { + get => metadata.ParameterIsNullableProperty; + set => throw new NotSupportedException(); + } + + /// + /// Gets the type of the db binary. + /// + /// The type of the db binary. + public override Enum DbBinaryType => dbTypeBinary; + + /// + /// Gets or sets a value indicating whether [use parameter name prefix in parameter collection]. + /// + /// + /// true if [use parameter name prefix in parameter collection]; otherwise, false. + /// + public override bool UseParameterNamePrefixInParameterCollection + { + get => metadata.UseParameterNamePrefixInParameterCollection; + set => throw new NotSupportedException(); } } diff --git a/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/SpringObjectJobFactory.cs b/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/SpringObjectJobFactory.cs index b30174d5..fc57330c 100644 --- a/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/SpringObjectJobFactory.cs +++ b/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/SpringObjectJobFactory.cs @@ -1,123 +1,122 @@ /* -* Copyright 2002-2010 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. -*/ + * Copyright 2002-2010 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. + */ using Quartz; using Quartz.Spi; using Spring.Objects; -namespace Spring.Scheduling.Quartz +namespace Spring.Scheduling.Quartz; + +/// +/// Subclass of AdaptableJobFactory that also supports Spring-style +/// dependency injection on object properties. This is essentially the direct +/// equivalent of Spring's QuartzJobObject in the shape of a +/// Quartz JobFactory. +/// +/// +/// Applies scheduler context, job data map and trigger data map entries +/// as object property values. If no matching object property is found, the entry +/// is by default simply ignored. This is analogous to QuartzJobObject's behavior. +/// +/// Juergen Hoeller +/// +/// +public class SpringObjectJobFactory : AdaptableJobFactory, ISchedulerContextAware { - /// - /// Subclass of AdaptableJobFactory that also supports Spring-style - /// dependency injection on object properties. This is essentially the direct - /// equivalent of Spring's QuartzJobObject in the shape of a - /// Quartz JobFactory. + private string[] ignoredUnknownProperties; + private SchedulerContext schedulerContext; + + /// + /// Specify the unknown properties (not found in the object) that should be ignored. /// /// - /// Applies scheduler context, job data map and trigger data map entries - /// as object property values. If no matching object property is found, the entry - /// is by default simply ignored. This is analogous to QuartzJobObject's behavior. + /// Default is null, indicating that all unknown properties + /// should be ignored. Specify an empty array to throw an exception in case + /// of any unknown properties, or a list of property names that should be + /// ignored if there is no corresponding property found on the particular + /// job class (all other unknown properties will still trigger an exception). /// - /// Juergen Hoeller - /// - /// - public class SpringObjectJobFactory : AdaptableJobFactory, ISchedulerContextAware + public virtual string[] IgnoredUnknownProperties { - private string[] ignoredUnknownProperties; - private SchedulerContext schedulerContext; + set => ignoredUnknownProperties = value; + } - /// - /// Specify the unknown properties (not found in the object) that should be ignored. - /// - /// - /// Default is null, indicating that all unknown properties - /// should be ignored. Specify an empty array to throw an exception in case - /// of any unknown properties, or a list of property names that should be - /// ignored if there is no corresponding property found on the particular - /// job class (all other unknown properties will still trigger an exception). - /// - public virtual string[] IgnoredUnknownProperties - { - set => ignoredUnknownProperties = value; - } + /// + /// Set the SchedulerContext of the current Quartz Scheduler. + /// + /// + /// + public virtual SchedulerContext SchedulerContext + { + set => schedulerContext = value; + } - /// - /// Set the SchedulerContext of the current Quartz Scheduler. - /// - /// - /// - public virtual SchedulerContext SchedulerContext + /// + /// Create the job instance, populating it with property values taken + /// from the scheduler context, job data map and trigger data map. + /// + protected override object CreateJobInstance(TriggerFiredBundle bundle) + { + ObjectWrapper ow = new ObjectWrapper(bundle.JobDetail.JobType); + if (IsEligibleForPropertyPopulation(ow.WrappedInstance)) { - set => schedulerContext = value; - } - - /// - /// Create the job instance, populating it with property values taken - /// from the scheduler context, job data map and trigger data map. - /// - protected override object CreateJobInstance(TriggerFiredBundle bundle) - { - ObjectWrapper ow = new ObjectWrapper(bundle.JobDetail.JobType); - if (IsEligibleForPropertyPopulation(ow.WrappedInstance)) + MutablePropertyValues pvs = new MutablePropertyValues(); + if (schedulerContext != null) { - MutablePropertyValues pvs = new MutablePropertyValues(); - if (schedulerContext != null) - { - pvs.AddAll(schedulerContext); - } - - pvs.AddAll(bundle.JobDetail.JobDataMap); - pvs.AddAll(bundle.Trigger.JobDataMap); - if (ignoredUnknownProperties != null) - { - for (int i = 0; i < ignoredUnknownProperties.Length; i++) - { - string propName = ignoredUnknownProperties[i]; - if (pvs.Contains(propName)) - { - pvs.Remove(propName); - } - } - - ow.SetPropertyValues(pvs); - } - else - { - ow.SetPropertyValues(pvs, true); - } + pvs.AddAll(schedulerContext); } - return ow.WrappedInstance; + pvs.AddAll(bundle.JobDetail.JobDataMap); + pvs.AddAll(bundle.Trigger.JobDataMap); + if (ignoredUnknownProperties != null) + { + for (int i = 0; i < ignoredUnknownProperties.Length; i++) + { + string propName = ignoredUnknownProperties[i]; + if (pvs.Contains(propName)) + { + pvs.Remove(propName); + } + } + + ow.SetPropertyValues(pvs); + } + else + { + ow.SetPropertyValues(pvs, true); + } } - /// - /// Return whether the given job object is eligible for having - /// its object properties populated. - ///

- /// The default implementation ignores QuartzJobObject instances, - /// which will inject object properties themselves. - ///

- ///
- /// - /// The job object to introspect. - /// - /// - protected virtual bool IsEligibleForPropertyPopulation(object jobObject) - { - return (!(jobObject is QuartzJobObject)); - } + return ow.WrappedInstance; } -} \ No newline at end of file + + /// + /// Return whether the given job object is eligible for having + /// its object properties populated. + ///

+ /// The default implementation ignores QuartzJobObject instances, + /// which will inject object properties themselves. + ///

+ ///
+ /// + /// The job object to introspect. + /// + /// + protected virtual bool IsEligibleForPropertyPopulation(object jobObject) + { + return (!(jobObject is QuartzJobObject)); + } +} diff --git a/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/StatefulMethodInvokingJob.cs b/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/StatefulMethodInvokingJob.cs index c39842b5..a0504945 100644 --- a/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/StatefulMethodInvokingJob.cs +++ b/src/Spring/Spring.Scheduling.Quartz3/Scheduling/Quartz/StatefulMethodInvokingJob.cs @@ -1,33 +1,32 @@ /* -* Copyright 2002-2010 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. -*/ + * Copyright 2002-2010 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. + */ using Quartz; -namespace Spring.Scheduling.Quartz +namespace Spring.Scheduling.Quartz; + +/// +/// Extension of the MethodInvokingJob, implementing the StatefulJob interface. +/// Quartz checks whether or not jobs are stateful and if so, +/// won't let jobs interfere with each other. +/// +[DisallowConcurrentExecution] +[PersistJobDataAfterExecution] +public class StatefulMethodInvokingJob : MethodInvokingJob { - /// - /// Extension of the MethodInvokingJob, implementing the StatefulJob interface. - /// Quartz checks whether or not jobs are stateful and if so, - /// won't let jobs interfere with each other. - /// - [DisallowConcurrentExecution] - [PersistJobDataAfterExecution] - public class StatefulMethodInvokingJob : MethodInvokingJob - { - // No implementation, just an addition of the tag interface StatefulJob - // in order to allow stateful method invoking jobs. - } -} \ No newline at end of file + // No implementation, just an addition of the tag interface StatefulJob + // in order to allow stateful method invoking jobs. +} diff --git a/src/Spring/Spring.Scheduling.Quartz3/Scheduling/TaskRejectedException.cs b/src/Spring/Spring.Scheduling.Quartz3/Scheduling/TaskRejectedException.cs index 70fcaf12..476dfb6e 100644 --- a/src/Spring/Spring.Scheduling.Quartz3/Scheduling/TaskRejectedException.cs +++ b/src/Spring/Spring.Scheduling.Quartz3/Scheduling/TaskRejectedException.cs @@ -1,9 +1,8 @@ -namespace Spring.Scheduling +namespace Spring.Scheduling; + +/// +/// Summary description for TaskRejectedException. +/// +public class TaskRejectedException : ApplicationException { - /// - /// Summary description for TaskRejectedException. - /// - public class TaskRejectedException : ApplicationException - { - } } diff --git a/src/Spring/Spring.Services/AssemblyInfo.cs b/src/Spring/Spring.Services/AssemblyInfo.cs index 252512d8..6fe793f1 100644 --- a/src/Spring/Spring.Services/AssemblyInfo.cs +++ b/src/Spring/Spring.Services/AssemblyInfo.cs @@ -1,4 +1,4 @@ using System.Reflection; [assembly: AssemblyTitle("Spring.Services")] -[assembly: AssemblyDescription("Interfaces and classes that provide portable service abstractions in Spring.Net")] \ No newline at end of file +[assembly: AssemblyDescription("Interfaces and classes that provide portable service abstractions in Spring.Net")] diff --git a/src/Spring/Spring.Services/EnterpriseServices/EnterpriseServicesExporter.cs b/src/Spring/Spring.Services/EnterpriseServices/EnterpriseServicesExporter.cs index 68c03c34..512803b4 100644 --- a/src/Spring/Spring.Services/EnterpriseServices/EnterpriseServicesExporter.cs +++ b/src/Spring/Spring.Services/EnterpriseServices/EnterpriseServicesExporter.cs @@ -23,585 +23,589 @@ using System.Diagnostics; using System.EnterpriseServices; using System.Reflection; using System.Reflection.Emit; - using Spring.Objects.Factory; using Spring.Util; -namespace Spring.EnterpriseServices +namespace Spring.EnterpriseServices; + +/// +/// Exports components as ServicedComponents using the specified s. +/// +/// +/// +/// This class will create ServicedComponent wrapper for each of the +/// specified components and register them with the Component Services. +/// +/// +/// First you need to generate and register your components. This is done by writing a simple e.g. console application using a configuration as shown below: +/// +/// <!-- actual objects 'calculatorService' and 'simpleCalculatorService' are defined elsewhere --> +/// +/// <!-- Define the component for exporting 'calculatorService' --> +/// <object id="calculatorComponent" type="Spring.EnterpriseServices.ServicedComponentExporter, +/// Spring.Services"> +/// <property name="TargetName" value="calculatorService" /> +/// <property name="TypeAttributes"> +/// <list> +/// <object type="System.EnterpriseServices.TransactionAttribute, System.EnterpriseServices" /> +/// </list> +/// </property> +/// <property name="MemberAttributes"> +/// <dictionary> +/// <entry key="*"> +/// <list> +/// <object type="System.EnterpriseServices.AutoCompleteAttribute, System.EnterpriseServices" /> +/// </list> +/// </entry> +/// </dictionary> +/// </property> +/// </object> +/// +/// <!-- Define the component for exporting 'simpleCalculatorService' --> +/// <object id="simpleCalculatorComponent" type="Spring.EnterpriseServices.ServicedComponentExporter, +/// Spring.Services"> +/// <property name="TargetName" value="simpleCalculatorService" /> +/// </object> +/// +/// <!-- Export components into assembly and autoregister with COM+ --> +/// <object type="Spring.EnterpriseServices.EnterpriseServicesExporter, Spring.Services"> +/// <!-- assembly name to generated - will generate 'Spring.Calculator.EnterpriseServices.dll' --> +/// <property name="Assembly" value="Spring.Calculator.EnterpriseServices" /> +/// +/// <!-- +/// use Spring's ContextRegistry for managing services. If true, requires a file +/// 'Spring.Calculator.EnterpriseServices.dll.spring-context.xml' containing a +/// <spring/context /> section placed next to the generated assembly. +/// --> +/// <property name="UseSpring" value="true" /> +/// +/// <property name="ApplicationName" value="Spring Calculator Application" /> +/// <property name="ActivationMode" value="Library" /> +/// <property name="Description" value="Spring Calculator application" /> +/// <property name="Components"> +/// <list> +/// <ref object="calculatorComponent" /> +/// <ref object="simpleCalculatorComponent" /> +/// </list> +/// </property> +/// </object> +/// +/// +/// +/// To load your objectdefinitions at runtime of the components, place a configuration file next to the assembly +/// generated by the exporter, using the filename of the exported assembly, postfixing it with '.spring-context.config'. +/// Taking the example above, the file must be named 'Spring.Calculator.EnterpriseServices.dll.spring-context.xml' and look like: +/// +/// <-- --> +/// <spring> +/// <context> +/// <resource uri="Config/services.xml" /> +/// </context> +/// </spring> +/// +/// This file should point to the service object definitions you exported using with a +/// configuration as shown above. +/// +/// +/// +/// Aleksandar Seovic +/// Erich Eichinger +public class EnterpriseServicesExporter : IInitializingObject, IObjectFactoryAware { + #region Fields + + private IObjectFactory objectFactory; + + private IList components = new ArrayList(); + private string applicationName; + private string applicationId; + private ActivationOption activationMode = ActivationOption.Library; + private string description; + private ApplicationAccessControlAttribute accessControl; + private ApplicationQueuingAttribute applicationQueuing; + private IList roles; + private string assemblyName; + private bool useSpring; + + #endregion + + #region Constructor(s) / Destructor + /// - /// Exports components as ServicedComponents using the specified s. + /// Creates new enterprise services exporter. /// - /// - /// - /// This class will create ServicedComponent wrapper for each of the - /// specified components and register them with the Component Services. - /// - /// - /// First you need to generate and register your components. This is done by writing a simple e.g. console application using a configuration as shown below: - /// - /// <!-- actual objects 'calculatorService' and 'simpleCalculatorService' are defined elsewhere --> - /// - /// <!-- Define the component for exporting 'calculatorService' --> - /// <object id="calculatorComponent" type="Spring.EnterpriseServices.ServicedComponentExporter, - /// Spring.Services"> - /// <property name="TargetName" value="calculatorService" /> - /// <property name="TypeAttributes"> - /// <list> - /// <object type="System.EnterpriseServices.TransactionAttribute, System.EnterpriseServices" /> - /// </list> - /// </property> - /// <property name="MemberAttributes"> - /// <dictionary> - /// <entry key="*"> - /// <list> - /// <object type="System.EnterpriseServices.AutoCompleteAttribute, System.EnterpriseServices" /> - /// </list> - /// </entry> - /// </dictionary> - /// </property> - /// </object> - /// - /// <!-- Define the component for exporting 'simpleCalculatorService' --> - /// <object id="simpleCalculatorComponent" type="Spring.EnterpriseServices.ServicedComponentExporter, - /// Spring.Services"> - /// <property name="TargetName" value="simpleCalculatorService" /> - /// </object> - /// - /// <!-- Export components into assembly and autoregister with COM+ --> - /// <object type="Spring.EnterpriseServices.EnterpriseServicesExporter, Spring.Services"> - /// <!-- assembly name to generated - will generate 'Spring.Calculator.EnterpriseServices.dll' --> - /// <property name="Assembly" value="Spring.Calculator.EnterpriseServices" /> - /// - /// <!-- - /// use Spring's ContextRegistry for managing services. If true, requires a file - /// 'Spring.Calculator.EnterpriseServices.dll.spring-context.xml' containing a - /// <spring/context /> section placed next to the generated assembly. - /// --> - /// <property name="UseSpring" value="true" /> - /// - /// <property name="ApplicationName" value="Spring Calculator Application" /> - /// <property name="ActivationMode" value="Library" /> - /// <property name="Description" value="Spring Calculator application" /> - /// <property name="Components"> - /// <list> - /// <ref object="calculatorComponent" /> - /// <ref object="simpleCalculatorComponent" /> - /// </list> - /// </property> - /// </object> - /// - /// - /// - /// To load your objectdefinitions at runtime of the components, place a configuration file next to the assembly - /// generated by the exporter, using the filename of the exported assembly, postfixing it with '.spring-context.config'. - /// Taking the example above, the file must be named 'Spring.Calculator.EnterpriseServices.dll.spring-context.xml' and look like: - /// - /// <-- --> - /// <spring> - /// <context> - /// <resource uri="Config/services.xml" /> - /// </context> - /// </spring> - /// - /// This file should point to the service object definitions you exported using with a - /// configuration as shown above. - /// - /// - /// - /// Aleksandar Seovic - /// Erich Eichinger - public class EnterpriseServicesExporter : IInitializingObject, IObjectFactoryAware + public EnterpriseServicesExporter() { - #region Fields - - private IObjectFactory objectFactory; - - private IList components = new ArrayList(); - private string applicationName; - private string applicationId; - private ActivationOption activationMode = ActivationOption.Library; - private string description; - private ApplicationAccessControlAttribute accessControl; - private ApplicationQueuingAttribute applicationQueuing; - private IList roles; - private string assemblyName; - private bool useSpring; - - #endregion - - #region Constructor(s) / Destructor - - /// - /// Creates new enterprise services exporter. - /// - public EnterpriseServicesExporter() - { - } - - #endregion - - #region Properties - - /// - /// Gets or sets list of components to export. - /// - public IList Components - { - get { return components; } - set { components = value; } - } - - /// - /// Gets or sets COM+ application name. - /// - public string ApplicationName - { - get { return applicationName; } - set { applicationName = value; } - } - - /// - /// Gets or sets application identifier (GUID). Defaults to generated GUID if not specified. - /// - public string ApplicationId - { - get { return applicationId; } - set { applicationId = value; } - } - - /// - /// Gets or sets application activation mode, which can be either Server or Library (default). - /// - public ActivationOption ActivationMode - { - get { return activationMode; } - set { activationMode = value; } - } - - /// - /// Gets or sets application description. - /// - public string Description - { - get { return description; } - set { description = value; } - } - - /// - /// Gets or sets access control attribute. - /// - public ApplicationAccessControlAttribute AccessControl - { - get { return accessControl; } - set { accessControl = value; } - } - - /// - /// Gets or sets application queuing attribute. - /// - public ApplicationQueuingAttribute ApplicationQueuing - { - get { return applicationQueuing; } - set { applicationQueuing = value; } - } - - /// - /// Gets or sets application roles. - /// - public IList Roles - { - get { return roles; } - set { roles = value; } - } - - /// - /// Gets or sets name of the generated assembly that will contain serviced components. - /// - public string Assembly - { - get { return assemblyName; } - set { assemblyName = value; } - } - - /// - /// Use Spring context to configure the serviced components within COM. - /// - public bool UseSpring - { - get { return useSpring; } - set { useSpring = value; } - } - - #endregion - - #region IInitializingObject Members - - /// - /// Called by Spring container after object is configured in order to initialize it. - /// - public void AfterPropertiesSet() - { - if (roles != null && roles.Count > 0) - { - RefreshRoles(); - } - Export(); - } - - #endregion - - #region IObjectFactoryAware Members - - /// - /// Sets object factory instance. - /// - public IObjectFactory ObjectFactory - { - set { objectFactory = value; } - } - - #endregion - - #region Public Methods - - /// - /// Creates ServicedComponent wrappers for the specified components and registers - /// them with COM+ Component Services. - /// - public virtual void Export() - { - string ext = (ActivationMode == ActivationOption.Library) ? ".dll" : ".exe"; - string moduleName = assemblyName + ext; - string basePath = !StringUtils.IsNullOrEmpty(AppDomain.CurrentDomain.DynamicDirectory) ? AppDomain.CurrentDomain.DynamicDirectory : AppDomain.CurrentDomain.BaseDirectory; - string assemblyFileName = String.Format("{0}\\{1}", basePath.Trim('\\', '/'), moduleName); - FileInfo assemblyFile = new FileInfo(assemblyFileName); - - GenerateComponentAssembly(assemblyFile); - RegisterServicedComponents(assemblyFile); - } - - /// - /// Generates all configured to the given assembly. - /// - public Assembly GenerateComponentAssembly(FileInfo assemblyFile) - { - AssemblyName an = new AssemblyName(); - an.Name = Path.GetFileNameWithoutExtension(assemblyFile.Name); - an.Version = new Version("1.0.0.0"); - an.KeyPair = new StrongNameKeyPair(GetKeyPair()); - - AssemblyBuilder proxyAssembly = DefineProxyAssembly(an, assemblyFile); - ModuleBuilder module = proxyAssembly.DefineDynamicModule(an.Name, assemblyFile.Name, true); - GenerateComponentTypes(module, objectFactory, components, UseSpring); - - // Assembly.Save() does not allow paths... - string dynamicFileName = assemblyFile.Name; - proxyAssembly.Save(dynamicFileName); - Assembly resultAssembly = System.Reflection.Assembly.LoadFrom(assemblyFile.FullName); - return resultAssembly; - } - - /// - /// Generates service types from the list of instances - /// into the given assembly. - /// - /// the module to export types to - /// the object factory to resolve target types - /// the list of instances. - /// whether to generate context lookups, - private static void GenerateComponentTypes(ModuleBuilder module, IObjectFactory objectFactory, IList components, bool springManaged) - { - Type baseType = typeof(ServicedComponent); - if (springManaged) - { - baseType = CreateSpringServicedComponentType(module, baseType); - } - - foreach (ServicedComponentExporter definition in components) - { - definition.CreateWrapperType(module, baseType, objectFactory.GetType(definition.TargetName), springManaged); - } - } - - private AssemblyBuilder DefineProxyAssembly(AssemblyName an, FileInfo assemblyFile) - { - AssemblyBuilder proxyAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.RunAndSave, assemblyFile.DirectoryName); - ApplyAssemblyAttributes(proxyAssembly); - return proxyAssembly; - } - - /// - /// - /// - /// - public void RegisterServicedComponents(FileInfo assemblyFile) - { - RegistrationConfig config = new RegistrationConfig(); - config.Application = applicationName; - config.AssemblyFile = assemblyFile.FullName; - config.InstallationFlags = InstallationFlags.ReportWarningsToConsole | InstallationFlags.FindOrCreateTargetApplication | InstallationFlags.ReconfigureExistingApplication; - - RegistrationHelper regHelper = new RegistrationHelper(); - regHelper.InstallAssemblyFromConfig(ref config); - } - - /// - /// - /// - /// - public void UnregisterServicedComponents(FileInfo assemblyFile) - { - RegistrationConfig config = new RegistrationConfig(); - config.Application = applicationName; - config.AssemblyFile = assemblyFile.FullName; - config.InstallationFlags = InstallationFlags.ReportWarningsToConsole | InstallationFlags.FindOrCreateTargetApplication | InstallationFlags.ReconfigureExistingApplication; - - RegistrationHelper regHelper = new RegistrationHelper(); - regHelper.UninstallAssemblyFromConfig(ref config); - } - - #endregion - - #region Private Methods - - /// - /// Reads key pair from embedded resource. - /// - /// Key pair as a byte array. - private byte[] GetKeyPair() - { - using (Stream keys = GetType().Assembly.GetManifestResourceStream("Spring.EnterpriseServices.EnterpriseServices.keys")) - { - byte[] bytes = new byte[keys.Length]; - keys.Read(bytes, 0, (int)keys.Length); - return bytes; - } - } - - /// - /// Applies custom attributes to generated assembly. - /// - /// Dynamic assembly to apply attributes to. - private void ApplyAssemblyAttributes(AssemblyBuilder assembly) - { - assembly.SetCustomAttribute(ReflectionUtils.CreateCustomAttribute(typeof(ApplicationNameAttribute), applicationName)); - assembly.SetCustomAttribute(ReflectionUtils.CreateCustomAttribute(typeof(ApplicationActivationAttribute), activationMode)); - if (applicationId != null) - { - assembly.SetCustomAttribute(ReflectionUtils.CreateCustomAttribute(typeof(ApplicationIDAttribute), applicationId)); - } - if (description != null) - { - assembly.SetCustomAttribute(ReflectionUtils.CreateCustomAttribute(typeof(DescriptionAttribute), description)); - assembly.SetCustomAttribute(ReflectionUtils.CreateCustomAttribute(typeof(AssemblyDescriptionAttribute), description)); - } - if (accessControl != null) - { - assembly.SetCustomAttribute(ReflectionUtils.CreateCustomAttribute(accessControl)); - } - if (applicationQueuing != null) - { - assembly.SetCustomAttribute(ReflectionUtils.CreateCustomAttribute(applicationQueuing)); - } - if (roles != null) - { - foreach (SecurityRoleAttribute role in roles) - { - assembly.SetCustomAttribute(ReflectionUtils.CreateCustomAttribute(typeof(SecurityRoleAttribute), - new object[] { role.Role }, role)); - } - } - } - - /// - /// Replaces roles expressed using string with appropriate SecurityRoleAttribute instance. - /// - private void RefreshRoles() - { - for (int i = 0; i < roles.Count; i++) - { - object role = roles[i]; - if (role is string) - { - roles[i] = ParseRole((string)role); - } - } - } - - /// - /// Parses string representation of SecurityRoleAttribute. - /// - /// Role definition string. - /// Configured SecurityRoleAttribute instance. - private SecurityRoleAttribute ParseRole(string roleString) - { - string[] parts = roleString.Split(':'); - SecurityRoleAttribute role = new SecurityRoleAttribute(parts[0].Trim()); - if (parts.Length > 1) - { - role.Description = parts[1].Trim(); - } - if (parts.Length > 2) - { - role.SetEveryoneAccess = bool.Parse(parts[2].Trim()); - } - - return role; - } - - #endregion - - #region SpringServicedComponent generation - - /// - /// Creates the SpringServicedComponent base class to derive all s from. - /// - /// - /// - /// internal class SpringServicedComponent: BaseType - /// { - /// protected delegate object GetObjectHandler(ServicedComponent servicedComponent, string targetName); - /// - /// protected static readonly GetObjectHandler getObjectRef; - /// - /// static SpringServicedComponent() - /// { - /// // first look for a local copy - /// System.Reflection.Assembly servicesAssembly; - /// string servicesAssemblyPath = Path.Combine( - /// new FileInfo(System.Reflection.Assembly.GetExecutingAssembly().Location).DirectoryName - /// , "Spring.Services.dll" ); - /// servicesAssembly = System.Reflection.Assembly.LoadFrom(servicesAssemblyPath); - /// if (servicesAssembly == null) - /// { - /// // then let the normal loader handle the typeload - /// servicesAssembly = System.Reflection.Assembly.Load("Spring.Services, culture=neutral, version=x.x.x.x, publicKey=xxxxxxxx"); - /// } - /// - /// Type componentHelperType = servicesAssembly.GetType("Spring.EnterpriseServices.ServicedComponentHelper"); - /// getObjectRef = (GetObjectHandler) Delegate.CreateDelegate(typeof(GetObjectHandler) - /// , componentHelperType.GetMethod("GetObject")); - /// } - /// } - /// - /// - public static Type CreateSpringServicedComponentType(ModuleBuilder module, Type baseType) - { - if (!typeof(ServicedComponent).IsAssignableFrom(baseType)) - { - throw new ArgumentException(string.Format("baseType must derive from {0}, was {1}", typeof(ServicedComponent).FullName, baseType), "baseType"); - } - - Type delegateType = DefineDelegate(module); - - TypeBuilder typeBuilder = module.DefineType("SpringServicedComponent", System.Reflection.TypeAttributes.Public, baseType); - ILGenerator il = null; - FieldBuilder getObjectRef = typeBuilder.DefineField("getObject", delegateType, FieldAttributes.Family | FieldAttributes.Static); - - ConstructorBuilder typeCtor = typeBuilder.DefineTypeInitializer(); - il = typeCtor.GetILGenerator(); - Label methodEnd = il.DefineLabel(); - Label loadType = il.DefineLabel(); - Label tryBegin = il.BeginExceptionBlock(); - LocalBuilder fldAssembly = il.DeclareLocal(typeof(Assembly)); - LocalBuilder fldType = il.DeclareLocal(typeof(Type)); - LocalBuilder fldArgs = il.DeclareLocal(typeof (object[])); - LocalBuilder fldMethod = il.DeclareLocal(typeof (MethodBase)); - - il.Emit(OpCodes.Call, typeof(Assembly).GetMethod("GetExecutingAssembly")); - il.Emit(OpCodes.Callvirt, typeof(Assembly).GetProperty("Location").GetGetMethod()); - il.Emit(OpCodes.Newobj, typeof(FileInfo).GetConstructor(new Type[] {typeof(string)})); - il.Emit(OpCodes.Call, typeof(FileInfo).GetProperty("DirectoryName").GetGetMethod()); - il.Emit(OpCodes.Ldstr, new FileInfo(typeof(ServicedComponentHelper).Assembly.Location).Name); - - il.Emit(OpCodes.Call, typeof(Path).GetMethod("Combine", new Type[] { typeof(string), typeof(string) })); - il.Emit(OpCodes.Call, typeof(Assembly).GetMethod("LoadFrom", new Type[] { typeof(string)})); - il.Emit(OpCodes.Stloc, fldAssembly); - il.Emit(OpCodes.Ldloc, fldAssembly); - il.Emit(OpCodes.Ldnull); - il.Emit(OpCodes.Ceq); - il.Emit(OpCodes.Ldc_I4_0); - il.Emit(OpCodes.Ceq); - il.Emit(OpCodes.Brtrue_S, loadType); - - il.Emit(OpCodes.Ldstr, typeof(ServicedComponentHelper).Assembly.FullName); - il.Emit(OpCodes.Call, typeof(Assembly).GetMethod("Load", new Type[] { typeof(string) })); - il.Emit(OpCodes.Stloc, fldAssembly); - - il.MarkLabel(loadType); - il.Emit(OpCodes.Ldloc, fldAssembly); - il.Emit(OpCodes.Ldstr, typeof(ServicedComponentHelper).FullName); - il.Emit(OpCodes.Ldc_I4_1); - il.Emit(OpCodes.Call, typeof(Assembly).GetMethod("GetType", new Type[] { typeof(string), typeof(bool) })); - il.Emit(OpCodes.Stloc, fldType); - - il.Emit(OpCodes.Ldtoken, delegateType); - il.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle")); - il.Emit(OpCodes.Ldloc, fldType); - il.Emit(OpCodes.Ldstr, "GetObject"); - il.Emit(OpCodes.Callvirt, typeof(Type).GetMethod("GetMethod", new Type[] { typeof(string) })); - il.Emit(OpCodes.Call, typeof(Delegate).GetMethod("CreateDelegate", new Type[] { typeof(Type), typeof(MethodInfo) })); - il.Emit(OpCodes.Castclass, delegateType); - il.Emit(OpCodes.Stsfld, getObjectRef); - - il.Emit(OpCodes.Ldc_I4_1); - il.Emit(OpCodes.Newarr, typeof(object)); - il.Emit(OpCodes.Stloc, fldArgs); - - il.Emit(OpCodes.Ldloc, fldArgs); - il.Emit(OpCodes.Ldc_I4_0); - il.Emit(OpCodes.Ldtoken, typeBuilder); - il.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle")); - il.Emit(OpCodes.Stelem_Ref); - il.Emit(OpCodes.Ldloc, fldType); - il.Emit(OpCodes.Ldstr, "EnsureComponentContextRegistryInitialized"); - il.Emit(OpCodes.Callvirt, typeof(Type).GetMethod("GetMethod", new Type[] { typeof(string) })); - il.Emit(OpCodes.Ldnull); - il.Emit(OpCodes.Ldloc, fldArgs); - il.Emit(OpCodes.Call, typeof(MethodBase).GetMethod("Invoke", new Type[] { typeof(object), typeof(object[]) })); - il.Emit(OpCodes.Pop); - - il.Emit(OpCodes.Leave_S, methodEnd); - - il.BeginCatchBlock(typeof(Exception)); - il.Emit(OpCodes.Call, typeof(Trace).GetMethod("WriteLine", new Type[] { typeof(object) })); - il.EndExceptionBlock(); - il.MarkLabel(methodEnd); - il.Emit(OpCodes.Ret); - return typeBuilder.CreateType(); - } - - private static readonly MethodAttributes ConstructorAttributes = MethodAttributes.Public | - MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName; - - private void InvokeBal() - { - Type type = typeof (Assembly); - object[] args = new object[] { typeof(EnterpriseServicesExporter) }; - type.GetMethod("MethodName").Invoke(null, args); - } - - private static Type DefineDelegate(ModuleBuilder module) - { - MethodAttributes methodAtts = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual; - - TypeBuilder typeBuilder = module.DefineType("GetObjectHandler", TypeAttributes.Public | TypeAttributes.Sealed, typeof(MulticastDelegate)); - ConstructorBuilder cb = typeBuilder.DefineConstructor(ConstructorAttributes, CallingConventions.Standard, new Type[] { typeof(object), typeof(IntPtr) }); - cb.SetImplementationFlags(MethodImplAttributes.Managed | MethodImplAttributes.Runtime); - - MethodBuilder mb1 = typeBuilder.DefineMethod("BeginInvoke", methodAtts, CallingConventions.Standard, typeof(IAsyncResult) - , new Type[] { typeof(ServicedComponent), typeof(string), typeof(AsyncCallback), typeof(object) }); - mb1.SetImplementationFlags(MethodImplAttributes.Managed | MethodImplAttributes.Runtime); - MethodBuilder mb2 = typeBuilder.DefineMethod("EndInvoke", methodAtts, CallingConventions.Standard, typeof(object) - , new Type[] { typeof(IAsyncResult) }); - mb2.SetImplementationFlags(MethodImplAttributes.Managed | MethodImplAttributes.Runtime); - MethodBuilder mb3 = typeBuilder.DefineMethod("Invoke", methodAtts, CallingConventions.Standard, typeof(object) - , new Type[] { typeof(ServicedComponent), typeof(string) }); - mb3.SetImplementationFlags(MethodImplAttributes.Managed | MethodImplAttributes.Runtime); - return typeBuilder.CreateType(); - } - - #endregion } + + #endregion + + #region Properties + + /// + /// Gets or sets list of components to export. + /// + public IList Components + { + get { return components; } + set { components = value; } + } + + /// + /// Gets or sets COM+ application name. + /// + public string ApplicationName + { + get { return applicationName; } + set { applicationName = value; } + } + + /// + /// Gets or sets application identifier (GUID). Defaults to generated GUID if not specified. + /// + public string ApplicationId + { + get { return applicationId; } + set { applicationId = value; } + } + + /// + /// Gets or sets application activation mode, which can be either Server or Library (default). + /// + public ActivationOption ActivationMode + { + get { return activationMode; } + set { activationMode = value; } + } + + /// + /// Gets or sets application description. + /// + public string Description + { + get { return description; } + set { description = value; } + } + + /// + /// Gets or sets access control attribute. + /// + public ApplicationAccessControlAttribute AccessControl + { + get { return accessControl; } + set { accessControl = value; } + } + + /// + /// Gets or sets application queuing attribute. + /// + public ApplicationQueuingAttribute ApplicationQueuing + { + get { return applicationQueuing; } + set { applicationQueuing = value; } + } + + /// + /// Gets or sets application roles. + /// + public IList Roles + { + get { return roles; } + set { roles = value; } + } + + /// + /// Gets or sets name of the generated assembly that will contain serviced components. + /// + public string Assembly + { + get { return assemblyName; } + set { assemblyName = value; } + } + + /// + /// Use Spring context to configure the serviced components within COM. + /// + public bool UseSpring + { + get { return useSpring; } + set { useSpring = value; } + } + + #endregion + + #region IInitializingObject Members + + /// + /// Called by Spring container after object is configured in order to initialize it. + /// + public void AfterPropertiesSet() + { + if (roles != null && roles.Count > 0) + { + RefreshRoles(); + } + + Export(); + } + + #endregion + + #region IObjectFactoryAware Members + + /// + /// Sets object factory instance. + /// + public IObjectFactory ObjectFactory + { + set { objectFactory = value; } + } + + #endregion + + #region Public Methods + + /// + /// Creates ServicedComponent wrappers for the specified components and registers + /// them with COM+ Component Services. + /// + public virtual void Export() + { + string ext = (ActivationMode == ActivationOption.Library) ? ".dll" : ".exe"; + string moduleName = assemblyName + ext; + string basePath = !StringUtils.IsNullOrEmpty(AppDomain.CurrentDomain.DynamicDirectory) ? AppDomain.CurrentDomain.DynamicDirectory : AppDomain.CurrentDomain.BaseDirectory; + string assemblyFileName = String.Format("{0}\\{1}", basePath.Trim('\\', '/'), moduleName); + FileInfo assemblyFile = new FileInfo(assemblyFileName); + + GenerateComponentAssembly(assemblyFile); + RegisterServicedComponents(assemblyFile); + } + + /// + /// Generates all configured to the given assembly. + /// + public Assembly GenerateComponentAssembly(FileInfo assemblyFile) + { + AssemblyName an = new AssemblyName(); + an.Name = Path.GetFileNameWithoutExtension(assemblyFile.Name); + an.Version = new Version("1.0.0.0"); + an.KeyPair = new StrongNameKeyPair(GetKeyPair()); + + AssemblyBuilder proxyAssembly = DefineProxyAssembly(an, assemblyFile); + ModuleBuilder module = proxyAssembly.DefineDynamicModule(an.Name, assemblyFile.Name, true); + GenerateComponentTypes(module, objectFactory, components, UseSpring); + + // Assembly.Save() does not allow paths... + string dynamicFileName = assemblyFile.Name; + proxyAssembly.Save(dynamicFileName); + Assembly resultAssembly = System.Reflection.Assembly.LoadFrom(assemblyFile.FullName); + return resultAssembly; + } + + /// + /// Generates service types from the list of instances + /// into the given assembly. + /// + /// the module to export types to + /// the object factory to resolve target types + /// the list of instances. + /// whether to generate context lookups, + private static void GenerateComponentTypes(ModuleBuilder module, IObjectFactory objectFactory, IList components, bool springManaged) + { + Type baseType = typeof(ServicedComponent); + if (springManaged) + { + baseType = CreateSpringServicedComponentType(module, baseType); + } + + foreach (ServicedComponentExporter definition in components) + { + definition.CreateWrapperType(module, baseType, objectFactory.GetType(definition.TargetName), springManaged); + } + } + + private AssemblyBuilder DefineProxyAssembly(AssemblyName an, FileInfo assemblyFile) + { + AssemblyBuilder proxyAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.RunAndSave, assemblyFile.DirectoryName); + ApplyAssemblyAttributes(proxyAssembly); + return proxyAssembly; + } + + /// + /// + /// + /// + public void RegisterServicedComponents(FileInfo assemblyFile) + { + RegistrationConfig config = new RegistrationConfig(); + config.Application = applicationName; + config.AssemblyFile = assemblyFile.FullName; + config.InstallationFlags = InstallationFlags.ReportWarningsToConsole | InstallationFlags.FindOrCreateTargetApplication | InstallationFlags.ReconfigureExistingApplication; + + RegistrationHelper regHelper = new RegistrationHelper(); + regHelper.InstallAssemblyFromConfig(ref config); + } + + /// + /// + /// + /// + public void UnregisterServicedComponents(FileInfo assemblyFile) + { + RegistrationConfig config = new RegistrationConfig(); + config.Application = applicationName; + config.AssemblyFile = assemblyFile.FullName; + config.InstallationFlags = InstallationFlags.ReportWarningsToConsole | InstallationFlags.FindOrCreateTargetApplication | InstallationFlags.ReconfigureExistingApplication; + + RegistrationHelper regHelper = new RegistrationHelper(); + regHelper.UninstallAssemblyFromConfig(ref config); + } + + #endregion + + #region Private Methods + + /// + /// Reads key pair from embedded resource. + /// + /// Key pair as a byte array. + private byte[] GetKeyPair() + { + using (Stream keys = GetType().Assembly.GetManifestResourceStream("Spring.EnterpriseServices.EnterpriseServices.keys")) + { + byte[] bytes = new byte[keys.Length]; + keys.Read(bytes, 0, (int) keys.Length); + return bytes; + } + } + + /// + /// Applies custom attributes to generated assembly. + /// + /// Dynamic assembly to apply attributes to. + private void ApplyAssemblyAttributes(AssemblyBuilder assembly) + { + assembly.SetCustomAttribute(ReflectionUtils.CreateCustomAttribute(typeof(ApplicationNameAttribute), applicationName)); + assembly.SetCustomAttribute(ReflectionUtils.CreateCustomAttribute(typeof(ApplicationActivationAttribute), activationMode)); + if (applicationId != null) + { + assembly.SetCustomAttribute(ReflectionUtils.CreateCustomAttribute(typeof(ApplicationIDAttribute), applicationId)); + } + + if (description != null) + { + assembly.SetCustomAttribute(ReflectionUtils.CreateCustomAttribute(typeof(DescriptionAttribute), description)); + assembly.SetCustomAttribute(ReflectionUtils.CreateCustomAttribute(typeof(AssemblyDescriptionAttribute), description)); + } + + if (accessControl != null) + { + assembly.SetCustomAttribute(ReflectionUtils.CreateCustomAttribute(accessControl)); + } + + if (applicationQueuing != null) + { + assembly.SetCustomAttribute(ReflectionUtils.CreateCustomAttribute(applicationQueuing)); + } + + if (roles != null) + { + foreach (SecurityRoleAttribute role in roles) + { + assembly.SetCustomAttribute(ReflectionUtils.CreateCustomAttribute(typeof(SecurityRoleAttribute), + new object[] { role.Role }, role)); + } + } + } + + /// + /// Replaces roles expressed using string with appropriate SecurityRoleAttribute instance. + /// + private void RefreshRoles() + { + for (int i = 0; i < roles.Count; i++) + { + object role = roles[i]; + if (role is string) + { + roles[i] = ParseRole((string) role); + } + } + } + + /// + /// Parses string representation of SecurityRoleAttribute. + /// + /// Role definition string. + /// Configured SecurityRoleAttribute instance. + private SecurityRoleAttribute ParseRole(string roleString) + { + string[] parts = roleString.Split(':'); + SecurityRoleAttribute role = new SecurityRoleAttribute(parts[0].Trim()); + if (parts.Length > 1) + { + role.Description = parts[1].Trim(); + } + + if (parts.Length > 2) + { + role.SetEveryoneAccess = bool.Parse(parts[2].Trim()); + } + + return role; + } + + #endregion + + #region SpringServicedComponent generation + + /// + /// Creates the SpringServicedComponent base class to derive all s from. + /// + /// + /// + /// internal class SpringServicedComponent: BaseType + /// { + /// protected delegate object GetObjectHandler(ServicedComponent servicedComponent, string targetName); + /// + /// protected static readonly GetObjectHandler getObjectRef; + /// + /// static SpringServicedComponent() + /// { + /// // first look for a local copy + /// System.Reflection.Assembly servicesAssembly; + /// string servicesAssemblyPath = Path.Combine( + /// new FileInfo(System.Reflection.Assembly.GetExecutingAssembly().Location).DirectoryName + /// , "Spring.Services.dll" ); + /// servicesAssembly = System.Reflection.Assembly.LoadFrom(servicesAssemblyPath); + /// if (servicesAssembly == null) + /// { + /// // then let the normal loader handle the typeload + /// servicesAssembly = System.Reflection.Assembly.Load("Spring.Services, culture=neutral, version=x.x.x.x, publicKey=xxxxxxxx"); + /// } + /// + /// Type componentHelperType = servicesAssembly.GetType("Spring.EnterpriseServices.ServicedComponentHelper"); + /// getObjectRef = (GetObjectHandler) Delegate.CreateDelegate(typeof(GetObjectHandler) + /// , componentHelperType.GetMethod("GetObject")); + /// } + /// } + /// + /// + public static Type CreateSpringServicedComponentType(ModuleBuilder module, Type baseType) + { + if (!typeof(ServicedComponent).IsAssignableFrom(baseType)) + { + throw new ArgumentException(string.Format("baseType must derive from {0}, was {1}", typeof(ServicedComponent).FullName, baseType), "baseType"); + } + + Type delegateType = DefineDelegate(module); + + TypeBuilder typeBuilder = module.DefineType("SpringServicedComponent", System.Reflection.TypeAttributes.Public, baseType); + ILGenerator il = null; + FieldBuilder getObjectRef = typeBuilder.DefineField("getObject", delegateType, FieldAttributes.Family | FieldAttributes.Static); + + ConstructorBuilder typeCtor = typeBuilder.DefineTypeInitializer(); + il = typeCtor.GetILGenerator(); + Label methodEnd = il.DefineLabel(); + Label loadType = il.DefineLabel(); + Label tryBegin = il.BeginExceptionBlock(); + LocalBuilder fldAssembly = il.DeclareLocal(typeof(Assembly)); + LocalBuilder fldType = il.DeclareLocal(typeof(Type)); + LocalBuilder fldArgs = il.DeclareLocal(typeof(object[])); + LocalBuilder fldMethod = il.DeclareLocal(typeof(MethodBase)); + + il.Emit(OpCodes.Call, typeof(Assembly).GetMethod("GetExecutingAssembly")); + il.Emit(OpCodes.Callvirt, typeof(Assembly).GetProperty("Location").GetGetMethod()); + il.Emit(OpCodes.Newobj, typeof(FileInfo).GetConstructor(new Type[] { typeof(string) })); + il.Emit(OpCodes.Call, typeof(FileInfo).GetProperty("DirectoryName").GetGetMethod()); + il.Emit(OpCodes.Ldstr, new FileInfo(typeof(ServicedComponentHelper).Assembly.Location).Name); + + il.Emit(OpCodes.Call, typeof(Path).GetMethod("Combine", new Type[] { typeof(string), typeof(string) })); + il.Emit(OpCodes.Call, typeof(Assembly).GetMethod("LoadFrom", new Type[] { typeof(string) })); + il.Emit(OpCodes.Stloc, fldAssembly); + il.Emit(OpCodes.Ldloc, fldAssembly); + il.Emit(OpCodes.Ldnull); + il.Emit(OpCodes.Ceq); + il.Emit(OpCodes.Ldc_I4_0); + il.Emit(OpCodes.Ceq); + il.Emit(OpCodes.Brtrue_S, loadType); + + il.Emit(OpCodes.Ldstr, typeof(ServicedComponentHelper).Assembly.FullName); + il.Emit(OpCodes.Call, typeof(Assembly).GetMethod("Load", new Type[] { typeof(string) })); + il.Emit(OpCodes.Stloc, fldAssembly); + + il.MarkLabel(loadType); + il.Emit(OpCodes.Ldloc, fldAssembly); + il.Emit(OpCodes.Ldstr, typeof(ServicedComponentHelper).FullName); + il.Emit(OpCodes.Ldc_I4_1); + il.Emit(OpCodes.Call, typeof(Assembly).GetMethod("GetType", new Type[] { typeof(string), typeof(bool) })); + il.Emit(OpCodes.Stloc, fldType); + + il.Emit(OpCodes.Ldtoken, delegateType); + il.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle")); + il.Emit(OpCodes.Ldloc, fldType); + il.Emit(OpCodes.Ldstr, "GetObject"); + il.Emit(OpCodes.Callvirt, typeof(Type).GetMethod("GetMethod", new Type[] { typeof(string) })); + il.Emit(OpCodes.Call, typeof(Delegate).GetMethod("CreateDelegate", new Type[] { typeof(Type), typeof(MethodInfo) })); + il.Emit(OpCodes.Castclass, delegateType); + il.Emit(OpCodes.Stsfld, getObjectRef); + + il.Emit(OpCodes.Ldc_I4_1); + il.Emit(OpCodes.Newarr, typeof(object)); + il.Emit(OpCodes.Stloc, fldArgs); + + il.Emit(OpCodes.Ldloc, fldArgs); + il.Emit(OpCodes.Ldc_I4_0); + il.Emit(OpCodes.Ldtoken, typeBuilder); + il.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle")); + il.Emit(OpCodes.Stelem_Ref); + il.Emit(OpCodes.Ldloc, fldType); + il.Emit(OpCodes.Ldstr, "EnsureComponentContextRegistryInitialized"); + il.Emit(OpCodes.Callvirt, typeof(Type).GetMethod("GetMethod", new Type[] { typeof(string) })); + il.Emit(OpCodes.Ldnull); + il.Emit(OpCodes.Ldloc, fldArgs); + il.Emit(OpCodes.Call, typeof(MethodBase).GetMethod("Invoke", new Type[] { typeof(object), typeof(object[]) })); + il.Emit(OpCodes.Pop); + + il.Emit(OpCodes.Leave_S, methodEnd); + + il.BeginCatchBlock(typeof(Exception)); + il.Emit(OpCodes.Call, typeof(Trace).GetMethod("WriteLine", new Type[] { typeof(object) })); + il.EndExceptionBlock(); + il.MarkLabel(methodEnd); + il.Emit(OpCodes.Ret); + return typeBuilder.CreateType(); + } + + private static readonly MethodAttributes ConstructorAttributes = MethodAttributes.Public | + MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName; + + private void InvokeBal() + { + Type type = typeof(Assembly); + object[] args = new object[] { typeof(EnterpriseServicesExporter) }; + type.GetMethod("MethodName").Invoke(null, args); + } + + private static Type DefineDelegate(ModuleBuilder module) + { + MethodAttributes methodAtts = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual; + + TypeBuilder typeBuilder = module.DefineType("GetObjectHandler", TypeAttributes.Public | TypeAttributes.Sealed, typeof(MulticastDelegate)); + ConstructorBuilder cb = typeBuilder.DefineConstructor(ConstructorAttributes, CallingConventions.Standard, new Type[] { typeof(object), typeof(IntPtr) }); + cb.SetImplementationFlags(MethodImplAttributes.Managed | MethodImplAttributes.Runtime); + + MethodBuilder mb1 = typeBuilder.DefineMethod("BeginInvoke", methodAtts, CallingConventions.Standard, typeof(IAsyncResult) + , new Type[] { typeof(ServicedComponent), typeof(string), typeof(AsyncCallback), typeof(object) }); + mb1.SetImplementationFlags(MethodImplAttributes.Managed | MethodImplAttributes.Runtime); + MethodBuilder mb2 = typeBuilder.DefineMethod("EndInvoke", methodAtts, CallingConventions.Standard, typeof(object) + , new Type[] { typeof(IAsyncResult) }); + mb2.SetImplementationFlags(MethodImplAttributes.Managed | MethodImplAttributes.Runtime); + MethodBuilder mb3 = typeBuilder.DefineMethod("Invoke", methodAtts, CallingConventions.Standard, typeof(object) + , new Type[] { typeof(ServicedComponent), typeof(string) }); + mb3.SetImplementationFlags(MethodImplAttributes.Managed | MethodImplAttributes.Runtime); + return typeBuilder.CreateType(); + } + + #endregion } diff --git a/src/Spring/Spring.Services/EnterpriseServices/ExeConfigurationSystem.cs b/src/Spring/Spring.Services/EnterpriseServices/ExeConfigurationSystem.cs index 73a91ab2..0467c827 100644 --- a/src/Spring/Spring.Services/EnterpriseServices/ExeConfigurationSystem.cs +++ b/src/Spring/Spring.Services/EnterpriseServices/ExeConfigurationSystem.cs @@ -18,137 +18,140 @@ #endregion -namespace Spring.EnterpriseServices -{ - using System; - using System.Configuration; - using System.Reflection; - using System.Xml; - using Spring.Core.TypeResolution; - using Spring.Util; +namespace Spring.EnterpriseServices; - using System.Configuration.Internal; +using System; +using System.Configuration; +using System.Reflection; +using System.Xml; +using Spring.Core.TypeResolution; +using Spring.Util; +using System.Configuration.Internal; + +/// +/// SUBJECT TO CHANGE -FOR INTERNAL USE ONLY!
+/// Holds configuration information from a given configuration file, obtained by . +/// You may use to replace the active configuration system. +///
+/// +/// +public class ExeConfigurationSystem : IChainableConfigSystem +{ + private string _configPath; + private Configuration _configuration; + private IInternalConfigSystem _next; /// - /// SUBJECT TO CHANGE -FOR INTERNAL USE ONLY!
- /// Holds configuration information from a given configuration file, obtained by . - /// You may use to replace the active configuration system. + /// initializes this instance with a path to be passed into ///
- /// - /// - public class ExeConfigurationSystem : IChainableConfigSystem + /// + public ExeConfigurationSystem(string configPath) { - private string _configPath; - private Configuration _configuration; - private IInternalConfigSystem _next; + _configPath = configPath; + } - /// - /// initializes this instance with a path to be passed into - /// - /// - public ExeConfigurationSystem(string configPath) + /// + /// Purges cached configuration + /// + public void RefreshConfig(string sectionName) + { + if (_next != null) { - _configPath = configPath; + _next.RefreshConfig(sectionName); } - /// - /// Purges cached configuration - /// - public void RefreshConfig(string sectionName) - { - if (_next != null) - { - _next.RefreshConfig(sectionName); - } - _configuration = null; - } + _configuration = null; + } - /// - /// Only true if the underlying config system supports this. - /// - public bool SupportsUserConfig - { - get - { - EnsureInit(); - if (_next != null) - { - return _next.SupportsUserConfig; - } - return false; - } - } - - /// - /// Set the nested configuration system to delegate calls in case we can't resolve a config section ourselves - /// - public void SetInnerConfigurationSystem(IInternalConfigSystem innerConfigSystem) - { - _next = innerConfigSystem; - } - - private void EnsureInit() - { - if (_configuration == null) - { - lock (this) - { - if (_configuration == null) - { - _configuration = ConfigurationManager.OpenExeConfiguration(_configPath); - } - } - } - } - - private delegate object ResolveSectionRuntimeObject(ConfigurationSection section); - - private static ResolveSectionRuntimeObject resolveSectionRuntimeObject = - (ResolveSectionRuntimeObject)Delegate.CreateDelegate(typeof(ResolveSectionRuntimeObject), - typeof (ConfigurationSection).GetMethod("GetRuntimeObject", - BindingFlags.Instance | - BindingFlags.NonPublic)); - - /// - /// Get the specified section - /// - /// - /// - public object GetSection(string sectionName) + /// + /// Only true if the underlying config system supports this. + /// + public bool SupportsUserConfig + { + get { EnsureInit(); - ConfigurationSection thisSection = _configuration.GetSection(sectionName); - - object parent = null; if (_next != null) { - parent = _next.GetSection(sectionName); - } - if (thisSection == null) - { - return parent; + return _next.SupportsUserConfig; } - object result = resolveSectionRuntimeObject(thisSection); - if (result is DefaultSection) - { - string rawXml = thisSection.SectionInformation.GetRawXml(); - if (string.IsNullOrEmpty(rawXml)) - { - return null; - } - - Type t = TypeResolutionUtils.ResolveType(thisSection.SectionInformation.Type); - if (typeof(IConfigurationSectionHandler).IsAssignableFrom(t)) - { - XmlDocument xmlDoc = new XmlDocument(); - xmlDoc.LoadXml(thisSection.SectionInformation.GetRawXml()); - IConfigurationSectionHandler handler = (IConfigurationSectionHandler) Activator.CreateInstance(t); - return handler.Create(parent, null, xmlDoc.DocumentElement ); - } - throw new ConfigurationErrorsException(string.Format("missing
declaration for section '{0}'", sectionName)); - } - return result; + return false; } } + + /// + /// Set the nested configuration system to delegate calls in case we can't resolve a config section ourselves + /// + public void SetInnerConfigurationSystem(IInternalConfigSystem innerConfigSystem) + { + _next = innerConfigSystem; + } + + private void EnsureInit() + { + if (_configuration == null) + { + lock (this) + { + if (_configuration == null) + { + _configuration = ConfigurationManager.OpenExeConfiguration(_configPath); + } + } + } + } + + private delegate object ResolveSectionRuntimeObject(ConfigurationSection section); + + private static ResolveSectionRuntimeObject resolveSectionRuntimeObject = + (ResolveSectionRuntimeObject) Delegate.CreateDelegate(typeof(ResolveSectionRuntimeObject), + typeof(ConfigurationSection).GetMethod("GetRuntimeObject", + BindingFlags.Instance | + BindingFlags.NonPublic)); + + /// + /// Get the specified section + /// + /// + /// + public object GetSection(string sectionName) + { + EnsureInit(); + ConfigurationSection thisSection = _configuration.GetSection(sectionName); + + object parent = null; + if (_next != null) + { + parent = _next.GetSection(sectionName); + } + + if (thisSection == null) + { + return parent; + } + + object result = resolveSectionRuntimeObject(thisSection); + if (result is DefaultSection) + { + string rawXml = thisSection.SectionInformation.GetRawXml(); + if (string.IsNullOrEmpty(rawXml)) + { + return null; + } + + Type t = TypeResolutionUtils.ResolveType(thisSection.SectionInformation.Type); + if (typeof(IConfigurationSectionHandler).IsAssignableFrom(t)) + { + XmlDocument xmlDoc = new XmlDocument(); + xmlDoc.LoadXml(thisSection.SectionInformation.GetRawXml()); + IConfigurationSectionHandler handler = (IConfigurationSectionHandler) Activator.CreateInstance(t); + return handler.Create(parent, null, xmlDoc.DocumentElement); + } + + throw new ConfigurationErrorsException(string.Format("missing
declaration for section '{0}'", sectionName)); + } + + return result; + } } diff --git a/src/Spring/Spring.Services/EnterpriseServices/ServicedComponentExporter.cs b/src/Spring/Spring.Services/EnterpriseServices/ServicedComponentExporter.cs index 184fe7e9..a353fa07 100644 --- a/src/Spring/Spring.Services/EnterpriseServices/ServicedComponentExporter.cs +++ b/src/Spring/Spring.Services/EnterpriseServices/ServicedComponentExporter.cs @@ -26,322 +26,325 @@ using Spring.Core.TypeResolution; using Spring.Objects.Factory; using Spring.Proxy; -namespace Spring.EnterpriseServices +namespace Spring.EnterpriseServices; + +/// +/// Encapsulates information necessary to create ServicedComponent +/// wrapper around target class. +/// +/// +/// +/// Instances of this class should be used as elements in the Components +/// list of the class, which will +/// register them with COM+ Services. For a full description on how to export +/// and use services with COM+, see the reference. +/// +/// +/// +/// Aleksandar Seovic +/// Erich Eichinger +public class ServicedComponentExporter : IInitializingObject, IObjectNameAware { + #region Fields + + private string _objectName; + private string _targetName; + private string[] _interfaces; + private IList _typeAttributes = new ArrayList(); + private IDictionary _memberAttributes = new Hashtable(); + + #endregion + + #region Constructor(s) / Destructor + /// - /// Encapsulates information necessary to create ServicedComponent - /// wrapper around target class. + /// Creates a new instance of the + /// class. + /// + public ServicedComponentExporter() + { + } + + #endregion + + #region Properties + + /// + /// Gets or sets name of the target object that should be exposed as a serviced component. + /// + public string TargetName + { + get { return _targetName; } + set { _targetName = value; } + } + + /// + /// Gets or sets the list of interfaces whose methods should be exported. /// /// - /// - /// Instances of this class should be used as elements in the Components - /// list of the class, which will - /// register them with COM+ Services. For a full description on how to export - /// and use services with COM+, see the reference. - /// + /// The default value of this property is all the interfaces + /// implemented or inherited by the target type. /// - /// - /// Aleksandar Seovic - /// Erich Eichinger - public class ServicedComponentExporter : IInitializingObject, IObjectNameAware + /// The interfaces to export. + public string[] Interfaces + { + get { return _interfaces; } + set { _interfaces = value; } + } + + /// + /// Gets or sets a list of custom attributes + /// that should be applied to a proxy class. + /// + public IList TypeAttributes + { + get { return _typeAttributes; } + set { _typeAttributes = value; } + } + + /// + /// Gets or sets a dictionary of custom attributes + /// that should be applied to proxy members. + /// + /// + /// Map key is an expression that members can be matched against. Value is a list + /// of attributes that should be applied to each member that matches expression. + /// + public IDictionary MemberAttributes + { + get { return _memberAttributes; } + set { _memberAttributes = value; } + } + + #endregion + + #region IInitializingObject Members + + /// + /// Validate configuration. + /// + public void AfterPropertiesSet() + { + ValidateConfiguration(); + } + + #endregion + + #region IObjectNameAware Members + + /// + /// Set the name of the object in the object factory + /// that created this object. + /// + public string ObjectName + { + set { _objectName = value; } + } + + #endregion + + #region Methods + + private void ValidateConfiguration() + { + if (TargetName == null) + { + throw new ArgumentException("The TargetName property is required."); + } + } + + /// + /// Creates ServicedComponent wrapper around target class. + /// + /// Dynamic module builder to use + /// + /// Type of the exported object. + /// whether to generate lookups in ContextRegistry for each service method call or use a 'new'ed target instance + /// + /// if is true, each ServicedComponent method call will look similar to + /// + /// class MyServicedComponent { + /// void MethodX() { + /// ContextRegistry.GetContext().GetObject("TargetName").MethodX(); + /// } + /// } + /// + ///
+ /// if is false, the instance will be simply created at component activation using 'new': + /// + /// class MyServicedComponent { + /// TargetType target = new TargetType(); + /// + /// void MethodX() { + /// target.MethodX(); + /// } + /// } + /// + ///
+ /// The differences are of course that in the former case, the target lifecycle is entirely managed by Spring, thus avoiding + /// issues with ServiceComponent activation/deactivation as well as removing the need for default constructors. + ///
+ public Type CreateWrapperType(ModuleBuilder module, Type baseType, Type targetType, bool springManagedLifecycle) + { + ValidateConfiguration(); + + // create wrapper using appropriate proxy builder + IProxyTypeBuilder proxyBuilder; + if (springManagedLifecycle) + { + proxyBuilder = new SpringManagedServicedComponentProxyTypeBuilder(module, baseType, this); + } + else + { + proxyBuilder = new SimpleServicedComponentProxyTypeBuilder(module, baseType); + } + + proxyBuilder.Name = _objectName; + proxyBuilder.TargetType = targetType; + if (_interfaces != null && _interfaces.Length > 0) + { + proxyBuilder.Interfaces = TypeResolutionUtils.ResolveInterfaceArray(_interfaces); + } + + proxyBuilder.TypeAttributes = TypeAttributes; + proxyBuilder.MemberAttributes = MemberAttributes; + + Type componentType = proxyBuilder.BuildProxyType(); + + // create and register client-side proxy factory for component + + return componentType; + } + + #endregion + + #region ServicedComponentProxyTypeBuilder inner class definition + + private class ServicedComponentTargetProxyMethodBuilder : TargetProxyMethodBuilder + { + public ServicedComponentTargetProxyMethodBuilder(TypeBuilder typeBuilder, IProxyTypeGenerator proxyGenerator, bool explicitImplementation) : base(typeBuilder, proxyGenerator, explicitImplementation) + { + } + + /// + /// Suppress output to avoid Spring.Core dependency + /// + protected override void CallAssertUnderstands(ILGenerator il, MethodInfo method, string targetName) + { +// base.CallAssertUnderstands(il, method, targetRef, targetName); + } + } + + private class ServicedComponentProxyTypeBuilder : CompositionProxyTypeBuilder + { + /// + /// Implements default constructor for the proxy class. + /// + protected override void ImplementConstructors(TypeBuilder builder) + { + MethodAttributes attributes = MethodAttributes.Public | + MethodAttributes.HideBySig | MethodAttributes.SpecialName | + MethodAttributes.RTSpecialName; + ConstructorBuilder cb = builder.DefineConstructor(attributes, + CallingConventions.Standard, Type.EmptyTypes); + + ILGenerator il = cb.GetILGenerator(); + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Call, builder.BaseType.GetConstructor(Type.EmptyTypes)); + il.Emit(OpCodes.Ret); + } + + protected override IProxyMethodBuilder CreateTargetProxyMethodBuilder(TypeBuilder typeBuilder) + { + return new ServicedComponentTargetProxyMethodBuilder(typeBuilder, this, + this.ExplicitInterfaceImplementation); + } + } + + private sealed class SimpleServicedComponentProxyTypeBuilder : ServicedComponentProxyTypeBuilder + { + private readonly ModuleBuilder module; + + #region Constructor(s) / Destructor + + public SimpleServicedComponentProxyTypeBuilder(ModuleBuilder module, Type baseType) + { + this.module = module; + BaseType = baseType; + } + + #endregion + + #region Protected Methods + + protected override TypeBuilder CreateTypeBuilder(string name, Type baseType) + { + return module.DefineType(name, System.Reflection.TypeAttributes.Public, baseType); + } + + #endregion + } + + private sealed class SpringManagedServicedComponentProxyTypeBuilder : ServicedComponentProxyTypeBuilder { #region Fields - private string _objectName; - private string _targetName; - private string[] _interfaces; - private IList _typeAttributes = new ArrayList(); - private IDictionary _memberAttributes = new Hashtable(); + private delegate object GetTargetDelegate(ServicedComponent component, string name); + + private static readonly MethodInfo ServicedComponentExporter_GetTarget = new GetTargetDelegate(ServicedComponentHelper.GetObject).Method; + + #endregion + + #region Fields + + private readonly ServicedComponentExporter exporter; + private readonly ModuleBuilder module; #endregion #region Constructor(s) / Destructor - /// - /// Creates a new instance of the - /// class. - /// - public ServicedComponentExporter() - {} - - #endregion - - #region Properties - - /// - /// Gets or sets name of the target object that should be exposed as a serviced component. - /// - public string TargetName + public SpringManagedServicedComponentProxyTypeBuilder(ModuleBuilder module, Type baseType, ServicedComponentExporter exporter) { - get { return _targetName; } - set { _targetName = value; } - } - - /// - /// Gets or sets the list of interfaces whose methods should be exported. - /// - /// - /// The default value of this property is all the interfaces - /// implemented or inherited by the target type. - /// - /// The interfaces to export. - public string[] Interfaces - { - get { return _interfaces; } - set { _interfaces = value; } - } - - /// - /// Gets or sets a list of custom attributes - /// that should be applied to a proxy class. - /// - public IList TypeAttributes - { - get { return _typeAttributes; } - set { _typeAttributes = value; } - } - - /// - /// Gets or sets a dictionary of custom attributes - /// that should be applied to proxy members. - /// - /// - /// Map key is an expression that members can be matched against. Value is a list - /// of attributes that should be applied to each member that matches expression. - /// - public IDictionary MemberAttributes - { - get { return _memberAttributes; } - set { _memberAttributes = value; } + this.module = module; + this.exporter = exporter; + BaseType = baseType; } #endregion - #region IInitializingObject Members + #region Protected Methods - /// - /// Validate configuration. - /// - public void AfterPropertiesSet() + protected override TypeBuilder CreateTypeBuilder(string name, Type baseType) { - ValidateConfiguration(); + return module.DefineType(name, System.Reflection.TypeAttributes.Public, baseType); + } + + protected override void DeclareTargetInstanceField(TypeBuilder builder) + { + //base.DeclareTargetInstanceField(builder); } #endregion - #region IObjectNameAware Members + #region IProxyTypeGenerator Members /// - /// Set the name of the object in the object factory - /// that created this object. + /// Generates the IL instructions that pushes + /// the target instance on which calls should be delegated to. /// - public string ObjectName + /// The IL generator to use. + public override void PushTarget(ILGenerator il) { - set { _objectName = value; } - } - - #endregion - - #region Methods - - private void ValidateConfiguration() - { - if (TargetName == null) - { - throw new ArgumentException("The TargetName property is required."); - } - } - - /// - /// Creates ServicedComponent wrapper around target class. - /// - /// Dynamic module builder to use - /// - /// Type of the exported object. - /// whether to generate lookups in ContextRegistry for each service method call or use a 'new'ed target instance - /// - /// if is true, each ServicedComponent method call will look similar to - /// - /// class MyServicedComponent { - /// void MethodX() { - /// ContextRegistry.GetContext().GetObject("TargetName").MethodX(); - /// } - /// } - /// - ///
- /// if is false, the instance will be simply created at component activation using 'new': - /// - /// class MyServicedComponent { - /// TargetType target = new TargetType(); - /// - /// void MethodX() { - /// target.MethodX(); - /// } - /// } - /// - ///
- /// The differences are of course that in the former case, the target lifecycle is entirely managed by Spring, thus avoiding - /// issues with ServiceComponent activation/deactivation as well as removing the need for default constructors. - ///
- public Type CreateWrapperType(ModuleBuilder module, Type baseType, Type targetType, bool springManagedLifecycle) - { - ValidateConfiguration(); - - // create wrapper using appropriate proxy builder - IProxyTypeBuilder proxyBuilder; - if (springManagedLifecycle) - { - proxyBuilder = new SpringManagedServicedComponentProxyTypeBuilder(module, baseType, this); - } - else - { - proxyBuilder = new SimpleServicedComponentProxyTypeBuilder(module, baseType); - } - - proxyBuilder.Name = _objectName; - proxyBuilder.TargetType = targetType; - if (_interfaces != null && _interfaces.Length > 0) - { - proxyBuilder.Interfaces = TypeResolutionUtils.ResolveInterfaceArray(_interfaces); - } - proxyBuilder.TypeAttributes = TypeAttributes; - proxyBuilder.MemberAttributes = MemberAttributes; - - Type componentType = proxyBuilder.BuildProxyType(); - - // create and register client-side proxy factory for component - - return componentType; - } - - #endregion - - #region ServicedComponentProxyTypeBuilder inner class definition - - private class ServicedComponentTargetProxyMethodBuilder : TargetProxyMethodBuilder - { - public ServicedComponentTargetProxyMethodBuilder(TypeBuilder typeBuilder, IProxyTypeGenerator proxyGenerator, bool explicitImplementation) : base(typeBuilder, proxyGenerator, explicitImplementation) - {} - - /// - /// Suppress output to avoid Spring.Core dependency - /// - protected override void CallAssertUnderstands(ILGenerator il, MethodInfo method, string targetName) - { -// base.CallAssertUnderstands(il, method, targetRef, targetName); - } - } - - private class ServicedComponentProxyTypeBuilder : CompositionProxyTypeBuilder - { - /// - /// Implements default constructor for the proxy class. - /// - protected override void ImplementConstructors(TypeBuilder builder) - { - MethodAttributes attributes = MethodAttributes.Public | - MethodAttributes.HideBySig | MethodAttributes.SpecialName | - MethodAttributes.RTSpecialName; - ConstructorBuilder cb = builder.DefineConstructor(attributes, - CallingConventions.Standard, Type.EmptyTypes); - - ILGenerator il = cb.GetILGenerator(); - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Call, builder.BaseType.GetConstructor(Type.EmptyTypes)); - il.Emit(OpCodes.Ret); - } - - protected override IProxyMethodBuilder CreateTargetProxyMethodBuilder(TypeBuilder typeBuilder) - { - return new ServicedComponentTargetProxyMethodBuilder(typeBuilder, this, - this.ExplicitInterfaceImplementation); - } - } - - private sealed class SimpleServicedComponentProxyTypeBuilder : ServicedComponentProxyTypeBuilder - { - private readonly ModuleBuilder module; - - #region Constructor(s) / Destructor - - public SimpleServicedComponentProxyTypeBuilder(ModuleBuilder module, Type baseType) - { - this.module = module; - BaseType = baseType; - } - - #endregion - - #region Protected Methods - - protected override TypeBuilder CreateTypeBuilder(string name, Type baseType) - { - return module.DefineType(name, System.Reflection.TypeAttributes.Public, baseType); - } - - #endregion - } - - private sealed class SpringManagedServicedComponentProxyTypeBuilder : ServicedComponentProxyTypeBuilder - { - #region Fields - - private delegate object GetTargetDelegate(ServicedComponent component, string name); - private static readonly MethodInfo ServicedComponentExporter_GetTarget = new GetTargetDelegate(ServicedComponentHelper.GetObject).Method; - - #endregion - - #region Fields - - private readonly ServicedComponentExporter exporter; - private readonly ModuleBuilder module; - - #endregion - - #region Constructor(s) / Destructor - - public SpringManagedServicedComponentProxyTypeBuilder(ModuleBuilder module, Type baseType, ServicedComponentExporter exporter) - { - this.module = module; - this.exporter = exporter; - BaseType = baseType; - } - - #endregion - - #region Protected Methods - - protected override TypeBuilder CreateTypeBuilder(string name, Type baseType) - { - return module.DefineType(name, System.Reflection.TypeAttributes.Public, baseType); - } - - protected override void DeclareTargetInstanceField(TypeBuilder builder) - { - //base.DeclareTargetInstanceField(builder); - } - - #endregion - - #region IProxyTypeGenerator Members - - /// - /// Generates the IL instructions that pushes - /// the target instance on which calls should be delegated to. - /// - /// The IL generator to use. - public override void PushTarget( ILGenerator il ) - { - FieldInfo getObjectRef = BaseType.GetField("getObject", BindingFlags.NonPublic|BindingFlags.Static); - il.Emit(OpCodes.Ldsfld, getObjectRef); - il.Emit(OpCodes.Ldarg_0); - il.Emit( OpCodes.Ldstr, this.exporter.TargetName ); - il.Emit( OpCodes.Callvirt, getObjectRef.FieldType.GetMethod("Invoke")); - } - #endregion - + FieldInfo getObjectRef = BaseType.GetField("getObject", BindingFlags.NonPublic | BindingFlags.Static); + il.Emit(OpCodes.Ldsfld, getObjectRef); + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldstr, this.exporter.TargetName); + il.Emit(OpCodes.Callvirt, getObjectRef.FieldType.GetMethod("Invoke")); } #endregion } + + #endregion } diff --git a/src/Spring/Spring.Services/EnterpriseServices/ServicedComponentFactory.cs b/src/Spring/Spring.Services/EnterpriseServices/ServicedComponentFactory.cs index ebb902ef..b64d2c19 100644 --- a/src/Spring/Spring.Services/EnterpriseServices/ServicedComponentFactory.cs +++ b/src/Spring/Spring.Services/EnterpriseServices/ServicedComponentFactory.cs @@ -24,158 +24,158 @@ using System.Reflection; using Spring.Objects.Factory; using Spring.Objects.Factory.Config; -namespace Spring.EnterpriseServices +namespace Spring.EnterpriseServices; + +/// +/// Factory Object that instantiates and configures ServicedComponent. +/// +/// +///

+/// This factory object should be used to instantiate and configure +/// serviced components created by . +///

+///
+/// Aleksandar Seovic +public class ServicedComponentFactory : IConfigurableFactoryObject, IInitializingObject { + #region Fields + + private string name; + private string server; + + private bool isSingleton; + private IObjectDefinition productTemplate; + + private Type componentType; + private object singletonInstance; + + #endregion + + #region Constructor(s) / Destructor + /// - /// Factory Object that instantiates and configures ServicedComponent. + /// Creates new instance of serviced component factory. /// - /// - ///

- /// This factory object should be used to instantiate and configure - /// serviced components created by . - ///

- ///
- /// Aleksandar Seovic - public class ServicedComponentFactory : IConfigurableFactoryObject, IInitializingObject + public ServicedComponentFactory() { - #region Fields - - private string name; - private string server; - - private bool isSingleton; - private IObjectDefinition productTemplate; - - private Type componentType; - private object singletonInstance; - - #endregion - - #region Constructor(s) / Destructor - - /// - /// Creates new instance of serviced component factory. - /// - public ServicedComponentFactory() - { - this.isSingleton = false; - } - - #endregion - - #region Properties - - /// - /// Gets or sets component name, as registered with COM+ Services. - /// - public string Name - { - get { return name; } - set { name = value; } - } - - /// - /// Gets or sets name of the remote server that COM+ component is registered with. - /// - public string Server - { - get { return server; } - set { server = value; } - } - - #endregion - - #region IConfigurableFactoryObject Members - - /// - /// Returns configured instance of the serviced component. - /// - /// Configured instance of the serviced component. - public object GetObject() - { - if (IsSingleton) - { - if (singletonInstance == null) - { - singletonInstance = CreateInstance(); - } - return singletonInstance; - } - else - { - return CreateInstance(); - } - } - - /// - /// Returns type of serviced component. - /// - public Type ObjectType - { - get { return componentType; } - } - - /// - /// Gets or sets whether serviced component should be treated as singleton. Default is false. - /// - public bool IsSingleton - { - get { return isSingleton; } - set { isSingleton = value; } - } - - /// - /// Gets or sets the template object definition - /// that should be used to configure proxy instance. - /// - public IObjectDefinition ProductTemplate - { - get { return productTemplate; } - set { productTemplate = value; } - } - - #endregion - - #region IInitializingObject Members - - /// - /// Initializes factory object. - /// - public void AfterPropertiesSet() - { - ValidateConfiguration(); - componentType = Type.GetTypeFromProgID(Name, Server); - AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve; - } - - #endregion - - #region Private Methods - - private void ValidateConfiguration() - { - if (Name == null) - { - throw new ArgumentException("The Name property is required."); - } - } - - /// - /// Creates new instance of serviced component. - /// - /// New instance of serviced component. - private object CreateInstance() - { - return Activator.CreateInstance(componentType); - } - - private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) - { - return Assembly.LoadFrom(componentType.Assembly.CodeBase); - } - - #endregion + this.isSingleton = false; } + + #endregion + + #region Properties + + /// + /// Gets or sets component name, as registered with COM+ Services. + /// + public string Name + { + get { return name; } + set { name = value; } + } + + /// + /// Gets or sets name of the remote server that COM+ component is registered with. + /// + public string Server + { + get { return server; } + set { server = value; } + } + + #endregion + + #region IConfigurableFactoryObject Members + + /// + /// Returns configured instance of the serviced component. + /// + /// Configured instance of the serviced component. + public object GetObject() + { + if (IsSingleton) + { + if (singletonInstance == null) + { + singletonInstance = CreateInstance(); + } + + return singletonInstance; + } + else + { + return CreateInstance(); + } + } + + /// + /// Returns type of serviced component. + /// + public Type ObjectType + { + get { return componentType; } + } + + /// + /// Gets or sets whether serviced component should be treated as singleton. Default is false. + /// + public bool IsSingleton + { + get { return isSingleton; } + set { isSingleton = value; } + } + + /// + /// Gets or sets the template object definition + /// that should be used to configure proxy instance. + /// + public IObjectDefinition ProductTemplate + { + get { return productTemplate; } + set { productTemplate = value; } + } + + #endregion + + #region IInitializingObject Members + + /// + /// Initializes factory object. + /// + public void AfterPropertiesSet() + { + ValidateConfiguration(); + componentType = Type.GetTypeFromProgID(Name, Server); + AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve; + } + + #endregion + + #region Private Methods + + private void ValidateConfiguration() + { + if (Name == null) + { + throw new ArgumentException("The Name property is required."); + } + } + + /// + /// Creates new instance of serviced component. + /// + /// New instance of serviced component. + private object CreateInstance() + { + return Activator.CreateInstance(componentType); + } + + private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) + { + return Assembly.LoadFrom(componentType.Assembly.CodeBase); + } + + #endregion } #endif // !MONO diff --git a/src/Spring/Spring.Services/EnterpriseServices/ServicedComponentHelper.cs b/src/Spring/Spring.Services/EnterpriseServices/ServicedComponentHelper.cs index c746139b..4e66c8dd 100644 --- a/src/Spring/Spring.Services/EnterpriseServices/ServicedComponentHelper.cs +++ b/src/Spring/Spring.Services/EnterpriseServices/ServicedComponentHelper.cs @@ -27,138 +27,140 @@ using Spring.Core.IO; using Spring.Objects.Factory.Config; using Spring.Util; -namespace Spring.EnterpriseServices +namespace Spring.EnterpriseServices; + +/// +/// This class supports s exported using . +/// and must never be used directly. +/// +/// Erich Eichinger +public class ServicedComponentHelper { - /// - /// This class supports s exported using . - /// and must never be used directly. - /// - /// Erich Eichinger - public class ServicedComponentHelper + private static bool isInitialized; + private static string componentDirectory; + private static IApplicationContext _appContext; + + static ServicedComponentHelper() { - private static bool isInitialized; - private static string componentDirectory; - private static IApplicationContext _appContext; + isInitialized = false; + } - static ServicedComponentHelper() - { - isInitialized = false; - } + /// + /// Reads in the 'xxx.spring-context.xml' configuration file associated with the specified . + /// See for an in-depth description on how to export and configure COM+ components. + /// + public static void EnsureComponentContextRegistryInitialized(Type componentType) + { + if (isInitialized) return; - /// - /// Reads in the 'xxx.spring-context.xml' configuration file associated with the specified . - /// See for an in-depth description on how to export and configure COM+ components. - /// - public static void EnsureComponentContextRegistryInitialized(Type componentType) + lock (typeof(ServicedComponentHelper)) { if (isInitialized) return; - lock (typeof(ServicedComponentHelper)) - { - if (isInitialized) return; - - try - { - Initialize(componentType); - } - catch (Exception e) - { - Trace.WriteLine("Error configuring application context for COM component of type " + componentType + ": " + e); - throw; - } - - isInitialized = true; - } - } - - private static void Initialize(Type componentType) - { - // this is to ensure, that assemblies placed next to the component assembly can be loaded - // even when they are not strong named. - AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve; - FileInfo componentAssemblyFile = new FileInfo(componentType.Assembly.Location); - FileInfo assemblyFile = new FileInfo(componentAssemblyFile.FullName); - - bool isRunningOutOfProcess = IsRunningOutOfProcess(); - FileInfo configFile = new FileInfo(componentAssemblyFile.FullName + ".config"); - - // no config file and in-proc -> reuse app's context, error otherwise - if (!configFile.Exists) - { - if (!isRunningOutOfProcess) - { - // check for context with component's name - if (ContextRegistry.IsContextRegistered(componentType.Name)) - { - Trace.WriteLine(string.Format("configuring COM InProc Server '{0}' using section from app.config", componentAssemblyFile.FullName, componentType.Name)); - _appContext = ContextRegistry.GetContext(componentType.Name); - } - else - { - Trace.WriteLine(string.Format("configuring COM InProc Server '{0}' using section from file '{1}'", componentAssemblyFile.FullName, configFile.FullName)); - _appContext = ContextRegistry.GetContext(); - } - return; - } - throw ConfigurationUtils.CreateConfigurationException("Spring-exported COM components require section in configuration file '" + configFile.FullName + "'"); - } - - // set and switch to component assembly's directory (affects resolving relative paths during context instantiation!) - componentDirectory = componentAssemblyFile.Directory.FullName; - Environment.CurrentDirectory = componentDirectory; - - if (isRunningOutOfProcess) - { - Trace.WriteLine(string.Format("configuring COM OutProc Server '{0}' using '{1}'", componentAssemblyFile.FullName, configFile.FullName)); - // read in config file - ExeConfigurationSystem comConfig = new ExeConfigurationSystem(assemblyFile.FullName); - // make the config "global" for this process, replacing any - // existing configuration that might already have been loaded - ConfigurationUtils.SetConfigurationSystem(comConfig, true); - _appContext = ContextRegistry.GetContext(); - } - else - { - Trace.WriteLine(string.Format("configuring COM InProc Server '{0}' using section from file '{1}'", componentAssemblyFile.FullName, configFile.FullName)); - _appContext = (IApplicationContext)ConfigurationReader.GetSection(new FileSystemResource(configFile.FullName), "spring/context"); - } - if (_appContext == null) - { - throw ConfigurationUtils.CreateConfigurationException("Spring-exported COM components require section in configuration file"); - } - Trace.WriteLine(string.Format("completed configuring COM Component '{0}' using '{1}'", componentAssemblyFile.FullName, configFile.FullName)); - } - - private static bool IsRunningOutOfProcess() - { - // TODO: checkout a prob. better way to find out, whether we are executing as a com server or library - return AppDomain.CurrentDomain.SetupInformation.ApplicationName == "dllhost.exe"; - } - - private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) - { - string name = args.Name.Split(',')[0]; - Assembly assembly = Assembly.LoadFrom(Path.Combine(componentDirectory, name + ".dll")); - return assembly; - } - - /// - /// Called by a exported by - /// to obtain a reference to the service it proxies. - /// - public static object GetObject(ServicedComponent sender, string targetName) - { - EnsureComponentContextRegistryInitialized(sender.GetType()); try { - return _appContext.GetObject(targetName); - + Initialize(componentType); } catch (Exception e) { - Trace.WriteLine("Error configuring application context for COM component of type " + sender.GetType() + ": " + e); + Trace.WriteLine("Error configuring application context for COM component of type " + componentType + ": " + e); throw; } + + isInitialized = true; + } + } + + private static void Initialize(Type componentType) + { + // this is to ensure, that assemblies placed next to the component assembly can be loaded + // even when they are not strong named. + AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve; + FileInfo componentAssemblyFile = new FileInfo(componentType.Assembly.Location); + FileInfo assemblyFile = new FileInfo(componentAssemblyFile.FullName); + + bool isRunningOutOfProcess = IsRunningOutOfProcess(); + FileInfo configFile = new FileInfo(componentAssemblyFile.FullName + ".config"); + + // no config file and in-proc -> reuse app's context, error otherwise + if (!configFile.Exists) + { + if (!isRunningOutOfProcess) + { + // check for context with component's name + if (ContextRegistry.IsContextRegistered(componentType.Name)) + { + Trace.WriteLine(string.Format("configuring COM InProc Server '{0}' using section from app.config", componentAssemblyFile.FullName, componentType.Name)); + _appContext = ContextRegistry.GetContext(componentType.Name); + } + else + { + Trace.WriteLine(string.Format("configuring COM InProc Server '{0}' using section from file '{1}'", componentAssemblyFile.FullName, configFile.FullName)); + _appContext = ContextRegistry.GetContext(); + } + + return; + } + + throw ConfigurationUtils.CreateConfigurationException("Spring-exported COM components require section in configuration file '" + configFile.FullName + "'"); + } + + // set and switch to component assembly's directory (affects resolving relative paths during context instantiation!) + componentDirectory = componentAssemblyFile.Directory.FullName; + Environment.CurrentDirectory = componentDirectory; + + if (isRunningOutOfProcess) + { + Trace.WriteLine(string.Format("configuring COM OutProc Server '{0}' using '{1}'", componentAssemblyFile.FullName, configFile.FullName)); + // read in config file + ExeConfigurationSystem comConfig = new ExeConfigurationSystem(assemblyFile.FullName); + // make the config "global" for this process, replacing any + // existing configuration that might already have been loaded + ConfigurationUtils.SetConfigurationSystem(comConfig, true); + _appContext = ContextRegistry.GetContext(); + } + else + { + Trace.WriteLine(string.Format("configuring COM InProc Server '{0}' using section from file '{1}'", componentAssemblyFile.FullName, configFile.FullName)); + _appContext = (IApplicationContext) ConfigurationReader.GetSection(new FileSystemResource(configFile.FullName), "spring/context"); + } + + if (_appContext == null) + { + throw ConfigurationUtils.CreateConfigurationException("Spring-exported COM components require section in configuration file"); + } + + Trace.WriteLine(string.Format("completed configuring COM Component '{0}' using '{1}'", componentAssemblyFile.FullName, configFile.FullName)); + } + + private static bool IsRunningOutOfProcess() + { + // TODO: checkout a prob. better way to find out, whether we are executing as a com server or library + return AppDomain.CurrentDomain.SetupInformation.ApplicationName == "dllhost.exe"; + } + + private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) + { + string name = args.Name.Split(',')[0]; + Assembly assembly = Assembly.LoadFrom(Path.Combine(componentDirectory, name + ".dll")); + return assembly; + } + + /// + /// Called by a exported by + /// to obtain a reference to the service it proxies. + /// + public static object GetObject(ServicedComponent sender, string targetName) + { + EnsureComponentContextRegistryInitialized(sender.GetType()); + try + { + return _appContext.GetObject(targetName); + } + catch (Exception e) + { + Trace.WriteLine("Error configuring application context for COM component of type " + sender.GetType() + ": " + e); + throw; } } } diff --git a/src/Spring/Spring.Services/Remoting/CaoExporter.cs b/src/Spring/Spring.Services/Remoting/CaoExporter.cs index f9371b72..f9ee7069 100644 --- a/src/Spring/Spring.Services/Remoting/CaoExporter.cs +++ b/src/Spring/Spring.Services/Remoting/CaoExporter.cs @@ -25,283 +25,282 @@ using Spring.Objects.Factory; using Spring.Objects.Factory.Support; using Spring.Remoting.Support; -namespace Spring.Remoting +namespace Spring.Remoting; + +/// +/// Registers an object type on the server +/// as a Client Activated Object (CAO). +/// +/// Aleksandar Seovic +/// Mark Pollack +/// Bruno Baia +public class CaoExporter : ConfigurableLifetime, IApplicationContextAware, IObjectFactoryAware, IInitializingObject, IDisposable { - /// - /// Registers an object type on the server - /// as a Client Activated Object (CAO). - /// - /// Aleksandar Seovic - /// Mark Pollack - /// Bruno Baia - public class CaoExporter : ConfigurableLifetime, IApplicationContextAware, IObjectFactoryAware, IInitializingObject, IDisposable - { - #region Logging + #region Logging - private static readonly ILogger LOG = LogManager.GetLogger(); + private static readonly ILogger LOG = LogManager.GetLogger(); - #endregion + #endregion - #region Fields + #region Fields - private string targetName; - private string[] interfaces; + private string targetName; + private string[] interfaces; - private IApplicationContext applicationContext; - private AbstractObjectFactory objectFactory; + private IApplicationContext applicationContext; + private AbstractObjectFactory objectFactory; - private CaoRemoteFactory remoteFactory; + private CaoRemoteFactory remoteFactory; - #endregion + #endregion - #region Constructor(s) / Destructor + #region Constructor(s) / Destructor - /// - /// Creates a new instance of the class. - /// - public CaoExporter() - { - } + /// + /// Creates a new instance of the class. + /// + public CaoExporter() + { + } - #endregion + #endregion - #region Properties + #region Properties - /// - /// Gets or sets the name of the target object definition. - /// - public string TargetName - { - get { return targetName; } - set { targetName = value; } - } + /// + /// Gets or sets the name of the target object definition. + /// + public string TargetName + { + get { return targetName; } + set { targetName = value; } + } - /// - /// Gets or sets the list of interfaces whose methods should be exported. - /// - /// - /// The default value of this property is all the interfaces - /// implemented or inherited by the target type. - /// - /// The interfaces to export. - public string[] Interfaces + /// + /// Gets or sets the list of interfaces whose methods should be exported. + /// + /// + /// The default value of this property is all the interfaces + /// implemented or inherited by the target type. + /// + /// The interfaces to export. + public string[] Interfaces + { + get { return interfaces; } + set { interfaces = value; } + } + + #endregion + + #region IApplicationContextAware Members + + /// + /// Sets the that this + /// object runs in. + /// + /// + /// + ///

+ /// Normally this call will be used to initialize the object. + ///

+ ///

+ /// Invoked after population of normal object properties but before an + /// init callback such as + /// 's + /// + /// or a custom init-method. Invoked after the setting of any + /// 's + /// + /// property. + ///

+ ///
+ /// + /// In the case of application context initialization errors. + /// + /// + /// If thrown by any application context methods. + /// + /// + public IApplicationContext ApplicationContext + { + set { applicationContext = value; } + } + + #endregion + + #region IObjectFactoryAware Members + + /// + /// Sets object factory to use. + /// + public IObjectFactory ObjectFactory + { + set { objectFactory = (AbstractObjectFactory) value; } + } + + #endregion + + #region IInitializingObject Members + + /// + /// Publish the object + /// + public void AfterPropertiesSet() + { + ValidateConfiguration(); + Export(); + } + + #endregion + + #region IDisposable Members + + /// + /// Disconnect the remote object from the registered remoting channels. + /// + public void Dispose() + { + RemotingServices.Disconnect(remoteFactory); + } + + #endregion + + #region Private Methods + + private void ValidateConfiguration() + { + if (TargetName == null) { - get { return interfaces; } - set { interfaces = value; } + throw new ArgumentException("The TargetName property is required."); + } + } + + private void Export() + { + remoteFactory = new CaoRemoteFactory(this, targetName, interfaces, objectFactory); + + RemotingServices.Marshal(remoteFactory, targetName); + + #region Instrumentation + + if (LOG.IsEnabled(LogLevel.Debug)) + { + LOG.LogDebug(String.Format("Target '{0}' registered.", targetName)); } - #endregion + #endregion + } - #region IApplicationContextAware Members + #endregion - /// - /// Sets the that this - /// object runs in. - /// - /// - /// - ///

- /// Normally this call will be used to initialize the object. - ///

- ///

- /// Invoked after population of normal object properties but before an - /// init callback such as - /// 's - /// - /// or a custom init-method. Invoked after the setting of any - /// 's - /// - /// property. - ///

- ///
- /// - /// In the case of application context initialization errors. - /// - /// - /// If thrown by any application context methods. - /// - /// - public IApplicationContext ApplicationContext - { - set { applicationContext = value; } - } + #region BaseCao inner class definition - #endregion + /// + /// This class extends to allow CAOs + /// to be disconnect from the client. + /// + public abstract class BaseCao : BaseRemoteObject, IDisposable + { + #region IDisposable Members - #region IObjectFactoryAware Members - - /// - /// Sets object factory to use. - /// - public IObjectFactory ObjectFactory - { - set { objectFactory = (AbstractObjectFactory) value; } - } - - #endregion - - #region IInitializingObject Members - - /// - /// Publish the object - /// - public void AfterPropertiesSet() - { - ValidateConfiguration(); - Export(); - } - - #endregion - - #region IDisposable Members - - /// - /// Disconnect the remote object from the registered remoting channels. - /// - public void Dispose() - { - RemotingServices.Disconnect(remoteFactory); - } - - #endregion - - #region Private Methods - - private void ValidateConfiguration() - { - if (TargetName == null) - { - throw new ArgumentException("The TargetName property is required."); - } - } - - private void Export() - { - remoteFactory = new CaoRemoteFactory(this, targetName, interfaces, objectFactory); - - RemotingServices.Marshal(remoteFactory, targetName); - - #region Instrumentation - - if (LOG.IsEnabled(LogLevel.Debug)) - { - LOG.LogDebug(String.Format("Target '{0}' registered.", targetName)); - } - - #endregion - } - - #endregion - - #region BaseCao inner class definition - - /// - /// This class extends to allow CAOs - /// to be disconnect from the client. - /// - public abstract class BaseCao : BaseRemoteObject, IDisposable + void IDisposable.Dispose() { - #region IDisposable Members + RemotingServices.Disconnect(this); + } - void IDisposable.Dispose() - { - RemotingServices.Disconnect(this); - } + #endregion + } - #endregion + #endregion + + #region CaoRemoteFactory inner class definition + + private sealed class CaoRemoteFactory : MarshalByRefObject, ICaoRemoteFactory + { + #region Fields + + private AbstractObjectFactory objectFactory; + private string targetName; + private RemoteObjectFactory remoteObjectFactory; + + #endregion + + #region Constructor(s) / Destructor + + /// + /// Create a new instance of the RemoteFactory. + /// + public CaoRemoteFactory(ILifetime lifetime, string targetName, + string[] interfaces, AbstractObjectFactory objectFactory) + { + this.targetName = targetName; + this.objectFactory = objectFactory; + + this.remoteObjectFactory = new RemoteObjectFactory(); + this.remoteObjectFactory.BaseType = typeof(BaseCao); + this.remoteObjectFactory.Interfaces = interfaces; + this.remoteObjectFactory.Infinite = lifetime.Infinite; + this.remoteObjectFactory.InitialLeaseTime = lifetime.InitialLeaseTime; + this.remoteObjectFactory.RenewOnCallTime = lifetime.RenewOnCallTime; + this.remoteObjectFactory.SponsorshipTimeout = lifetime.SponsorshipTimeout; } #endregion - #region CaoRemoteFactory inner class definition + #region Membres de ICaoRemoteFactory - private sealed class CaoRemoteFactory : MarshalByRefObject, ICaoRemoteFactory - { - #region Fields + /// + /// Returns the CAO proxy. + /// + /// The remote object. + public object GetObject() + { + remoteObjectFactory.Target = objectFactory.GetObject(targetName); - private AbstractObjectFactory objectFactory; - private string targetName; - private RemoteObjectFactory remoteObjectFactory; - - #endregion - - #region Constructor(s) / Destructor - - /// - /// Create a new instance of the RemoteFactory. - /// - public CaoRemoteFactory(ILifetime lifetime, string targetName, - string[] interfaces, AbstractObjectFactory objectFactory) - { - this.targetName = targetName; - this.objectFactory = objectFactory; - - this.remoteObjectFactory = new RemoteObjectFactory(); - this.remoteObjectFactory.BaseType = typeof(BaseCao); - this.remoteObjectFactory.Interfaces = interfaces; - this.remoteObjectFactory.Infinite = lifetime.Infinite; - this.remoteObjectFactory.InitialLeaseTime = lifetime.InitialLeaseTime; - this.remoteObjectFactory.RenewOnCallTime = lifetime.RenewOnCallTime; - this.remoteObjectFactory.SponsorshipTimeout = lifetime.SponsorshipTimeout; - } - - #endregion - - #region Membres de ICaoRemoteFactory - - /// - /// Returns the CAO proxy. - /// - /// The remote object. - public object GetObject() - { - remoteObjectFactory.Target = objectFactory.GetObject(targetName); - - return remoteObjectFactory.GetObject(); - } - - /// - /// Returns the CAO proxy using the - /// argument list to call the constructor. - /// - /// - /// The matching of arguments to call the constructor is done - /// by type. The alternative ways, by index and by constructor - /// name are not supported. - /// - /// Constructor - /// arguments used to create the object. - /// The remote object. - public object GetObject(object[] constructorArguments) - { - RootObjectDefinition mergedObjectDefinition = objectFactory.GetMergedObjectDefinition(targetName, false); - - if (typeof(IFactoryObject).IsAssignableFrom(mergedObjectDefinition.ObjectType)) - { - throw new NotSupportedException( - "Client activated objects with constructor arguments is not supported with IFactoryObject implementations."); - } - - remoteObjectFactory.Target = objectFactory.GetObject(targetName, constructorArguments); - - return remoteObjectFactory.GetObject(); - } - - #endregion - - #region Overrided Methods - - /// - /// Set infinite lifetime. - /// - public override object InitializeLifetimeService() - { - return null; - } - - #endregion + return remoteObjectFactory.GetObject(); } - #endregion - } + /// + /// Returns the CAO proxy using the + /// argument list to call the constructor. + /// + /// + /// The matching of arguments to call the constructor is done + /// by type. The alternative ways, by index and by constructor + /// name are not supported. + /// + /// Constructor + /// arguments used to create the object. + /// The remote object. + public object GetObject(object[] constructorArguments) + { + RootObjectDefinition mergedObjectDefinition = objectFactory.GetMergedObjectDefinition(targetName, false); + + if (typeof(IFactoryObject).IsAssignableFrom(mergedObjectDefinition.ObjectType)) + { + throw new NotSupportedException( + "Client activated objects with constructor arguments is not supported with IFactoryObject implementations."); + } + + remoteObjectFactory.Target = objectFactory.GetObject(targetName, constructorArguments); + + return remoteObjectFactory.GetObject(); + } + + #endregion + + #region Overrided Methods + + /// + /// Set infinite lifetime. + /// + public override object InitializeLifetimeService() + { + return null; + } + + #endregion + } + + #endregion } diff --git a/src/Spring/Spring.Services/Remoting/CaoFactoryObject.cs b/src/Spring/Spring.Services/Remoting/CaoFactoryObject.cs index ea7b1840..5a4b1103 100644 --- a/src/Spring/Spring.Services/Remoting/CaoFactoryObject.cs +++ b/src/Spring/Spring.Services/Remoting/CaoFactoryObject.cs @@ -22,135 +22,135 @@ using Microsoft.Extensions.Logging; using Spring.Objects.Factory; using Spring.Remoting.Support; -namespace Spring.Remoting +namespace Spring.Remoting; + +/// +/// Factory for creating a reference to a +/// client activated object (CAO). +/// +/// Aleksandar Seovic +/// Mark Pollack +/// Bruno Baia +public class CaoFactoryObject : IFactoryObject, IInitializingObject { + #region Logging + + private static readonly ILogger LOG = LogManager.GetLogger(); + + #endregion + + #region Fields + + private string remoteTargetName; + private string serviceUrl; + private object[] constructorArguments; + + #endregion + + #region Properties + /// - /// Factory for creating a reference to a - /// client activated object (CAO). + /// The remote target name to activate. /// - /// Aleksandar Seovic - /// Mark Pollack - /// Bruno Baia - public class CaoFactoryObject : IFactoryObject, IInitializingObject + public string RemoteTargetName { - #region Logging - - private static readonly ILogger LOG = LogManager.GetLogger(); - - #endregion - - #region Fields - - private string remoteTargetName; - private string serviceUrl; - private object[] constructorArguments; - - #endregion - - #region Properties - - /// - /// The remote target name to activate. - /// - public string RemoteTargetName - { - get { return remoteTargetName; } - set { remoteTargetName = value; } - } - - /// - /// The Uri of the remote type. - /// - public string ServiceUrl - { - get { return serviceUrl; } - set { serviceUrl = value; } - } - - /// - /// Argument list used to call the CAO constructor. - /// - public object[] ConstructorArguments - { - get { return constructorArguments; } - set { constructorArguments = value; } - } - - #endregion - - #region Constructor(s) / Destructor - - /// - /// Creates a new instance of the class. - /// - public CaoFactoryObject() - { - } - - #endregion - - #region IInitializingObject Members - - /// - /// Callback method called once all factory properties have been set. - /// - /// if an error occured - public void AfterPropertiesSet() - { - if (RemoteTargetName == null) - { - throw new ArgumentException("The RemoteTargetName property is required."); - } - - if (ServiceUrl == null) - { - throw new ArgumentException("The ServiceUrl property is required."); - } - } - - #endregion - - #region IFactoryObject Members - - /// - /// Always return false. - /// - public bool IsSingleton - { - get { return false; } - } - - /// - /// The type of object to be created. - /// - public Type ObjectType - { - get { return typeof(MarshalByRefObject); } - } - - /// - /// Return the CAO proxy. - /// - /// the CAO proxy - public object GetObject() - { - string url = serviceUrl.TrimEnd('/') + '/' + remoteTargetName; - if (LOG.IsEnabled(LogLevel.Debug)) - { - LOG.LogDebug("Accessing CAO object of type ICaoRemoteFactory object at url = [" + url + "]"); - } - ICaoRemoteFactory remoteFactory = (ICaoRemoteFactory) Activator.GetObject(typeof(ICaoRemoteFactory), url); - - if (constructorArguments != null) - { - return remoteFactory.GetObject(constructorArguments); - } - else - { - return remoteFactory.GetObject(); - } - } - - #endregion + get { return remoteTargetName; } + set { remoteTargetName = value; } } + + /// + /// The Uri of the remote type. + /// + public string ServiceUrl + { + get { return serviceUrl; } + set { serviceUrl = value; } + } + + /// + /// Argument list used to call the CAO constructor. + /// + public object[] ConstructorArguments + { + get { return constructorArguments; } + set { constructorArguments = value; } + } + + #endregion + + #region Constructor(s) / Destructor + + /// + /// Creates a new instance of the class. + /// + public CaoFactoryObject() + { + } + + #endregion + + #region IInitializingObject Members + + /// + /// Callback method called once all factory properties have been set. + /// + /// if an error occured + public void AfterPropertiesSet() + { + if (RemoteTargetName == null) + { + throw new ArgumentException("The RemoteTargetName property is required."); + } + + if (ServiceUrl == null) + { + throw new ArgumentException("The ServiceUrl property is required."); + } + } + + #endregion + + #region IFactoryObject Members + + /// + /// Always return false. + /// + public bool IsSingleton + { + get { return false; } + } + + /// + /// The type of object to be created. + /// + public Type ObjectType + { + get { return typeof(MarshalByRefObject); } + } + + /// + /// Return the CAO proxy. + /// + /// the CAO proxy + public object GetObject() + { + string url = serviceUrl.TrimEnd('/') + '/' + remoteTargetName; + if (LOG.IsEnabled(LogLevel.Debug)) + { + LOG.LogDebug("Accessing CAO object of type ICaoRemoteFactory object at url = [" + url + "]"); + } + + ICaoRemoteFactory remoteFactory = (ICaoRemoteFactory) Activator.GetObject(typeof(ICaoRemoteFactory), url); + + if (constructorArguments != null) + { + return remoteFactory.GetObject(constructorArguments); + } + else + { + return remoteFactory.GetObject(); + } + } + + #endregion } diff --git a/src/Spring/Spring.Services/Remoting/Config/RemotingNamespaceParser.cs b/src/Spring/Spring.Services/Remoting/Config/RemotingNamespaceParser.cs index 20b2f4f0..0fa93917 100644 --- a/src/Spring/Spring.Services/Remoting/Config/RemotingNamespaceParser.cs +++ b/src/Spring/Spring.Services/Remoting/Config/RemotingNamespaceParser.cs @@ -19,7 +19,6 @@ #endregion using System.Xml; - using Spring.Core.TypeResolution; using Spring.Objects; using Spring.Objects.Factory.Support; @@ -27,459 +26,470 @@ using Spring.Objects.Factory.Config; using Spring.Objects.Factory.Xml; using Spring.Util; -namespace Spring.Remoting.Config +namespace Spring.Remoting.Config; + +/// +/// Implementation of the custom configuration parser for remoting definitions. +/// +/// Bruno Baia +[ + NamespaceParser( + Namespace = "http://www.springframework.net/remoting", + SchemaLocationAssemblyHint = typeof(RemotingNamespaceParser), + SchemaLocation = "/Spring.Remoting.Config/spring-remoting-1.1.xsd") +] +public sealed class RemotingNamespaceParser : ObjectsNamespaceParser { - /// - /// Implementation of the custom configuration parser for remoting definitions. - /// - /// Bruno Baia - [ - NamespaceParser( - Namespace = "http://www.springframework.net/remoting", - SchemaLocationAssemblyHint = typeof(RemotingNamespaceParser), - SchemaLocation = "/Spring.Remoting.Config/spring-remoting-1.1.xsd") - ] - public sealed class RemotingNamespaceParser : ObjectsNamespaceParser + private const string RemotingTypePrefix = "remoting: "; + + static RemotingNamespaceParser() { - private const string RemotingTypePrefix = "remoting: "; - - static RemotingNamespaceParser() - { - TypeRegistry.RegisterType( - RemotingTypePrefix + RemotingConfigurerConstants.RemotingConfigurerElement, - typeof(RemotingConfigurer)); - TypeRegistry.RegisterType( - RemotingTypePrefix + SaoFactoryObjectConstants.SaoFactoryObjectElement, - typeof(SaoFactoryObject)); - TypeRegistry.RegisterType( - RemotingTypePrefix + CaoFactoryObjectConstants.CaoFactoryObjectElement, - typeof(CaoFactoryObject)); - TypeRegistry.RegisterType( - RemotingTypePrefix + RemoteObjectFactoryConstants.RemoteObjectFactoryElement, - typeof(RemoteObjectFactory)); - TypeRegistry.RegisterType( - RemotingTypePrefix + SaoExporterConstants.SaoExporterElement, - typeof(SaoExporter)); - TypeRegistry.RegisterType( - RemotingTypePrefix + CaoExporterConstants.CaoExporterElement, - typeof(CaoExporter)); - } - - /// - /// Initializes a new instance of the class. - /// - public RemotingNamespaceParser() - {} - - - /// - /// Parse the specified element and register any resulting - /// IObjectDefinitions with the IObjectDefinitionRegistry that is - /// embedded in the supplied ParserContext. - /// - /// The element to be parsed into one or more IObjectDefinitions - /// The object encapsulating the current state of the parsing - /// process. - /// - /// The primary IObjectDefinition (can be null as explained above) - /// - /// - /// Implementations should return the primary IObjectDefinition - /// that results from the parse phase if they wish to used nested - /// inside (for example) a <property> tag. - /// Implementations may return null if they will not - /// be used in a nested scenario. - /// - /// - public override IObjectDefinition ParseElement(XmlElement element, ParserContext parserContext) - { - string name = element.GetAttribute(ObjectDefinitionConstants.IdAttribute); - IConfigurableObjectDefinition remotingDefinition = ParseRemotingDefinition(element, name, parserContext); - if (!StringUtils.HasText(name)) - { - name = ObjectDefinitionReaderUtils.GenerateObjectName(remotingDefinition, parserContext.Registry); - } - parserContext.Registry.RegisterObjectDefinition(name, remotingDefinition); - - return null; - } - - - - /// - /// Parses remoting definitions. - /// - /// Validator XML element. - /// The name of the object definition. - /// The parser context. - /// A remoting object definition. - private IConfigurableObjectDefinition ParseRemotingDefinition( - XmlElement element, string name, ParserContext parserContext) - { - switch (element.LocalName) - { - case RemotingConfigurerConstants.RemotingConfigurerElement: - return ParseRemotingConfigurer(element, name, parserContext); - case SaoFactoryObjectConstants.SaoFactoryObjectElement: - return ParseSaoFactoryObject(element, name, parserContext); - case CaoFactoryObjectConstants.CaoFactoryObjectElement: - return ParseCaoFactoryObject(element, name, parserContext); - case RemoteObjectFactoryConstants.RemoteObjectFactoryElement: - return ParseRemoteObjectFactory(element, name, parserContext); - case SaoExporterConstants.SaoExporterElement: - return ParseSaoExporter(element, name, parserContext); - case CaoExporterConstants.CaoExporterElement: - return ParseCaoExporter(element, name, parserContext); - } - - return null; - } - - /// - /// Parses the RemotingConfigurer definition. - /// - /// The element to parse. - /// The name of the object definition. - /// The parser context. - /// RemotingConfigurer object definition. - private IConfigurableObjectDefinition ParseRemotingConfigurer( - XmlElement element, string name, ParserContext parserContext) - { - string typeName = GetTypeName(element); - string filename = element.GetAttribute(RemotingConfigurerConstants.FilenameAttribute); - string useConfigFile = element.GetAttribute(RemotingConfigurerConstants.UseConfigFileAttribute); - string ensureSecurity = element.GetAttribute(RemotingConfigurerConstants.EnsureSecurityAttribute); - - MutablePropertyValues properties = new MutablePropertyValues(); - if (StringUtils.HasText(filename)) - { - properties.Add("Filename", filename); - } - if (StringUtils.HasText(useConfigFile)) - { - properties.Add("UseConfigFile", useConfigFile); - } - if (StringUtils.HasText(ensureSecurity)) - { - properties.Add("EnsureSecurity", ensureSecurity); - } - - IConfigurableObjectDefinition cod = parserContext.ReaderContext.ObjectDefinitionFactory.CreateObjectDefinition( - typeName, null, parserContext.ReaderContext.Reader.Domain); - cod.PropertyValues = properties; - return cod; - } - - /// - /// Parses the SaoFactoryObject definition. - /// - /// The element to parse. - /// The name of the object definition. - /// The parser context. - /// SaoFactoryObject object definition. - private IConfigurableObjectDefinition ParseSaoFactoryObject( - XmlElement element, string name, ParserContext parserContext) - { - string typeName = GetTypeName(element); - string serviceInterface = element.GetAttribute(SaoFactoryObjectConstants.ServiceInterfaceAttribute); - string serviceUrl = element.GetAttribute(SaoFactoryObjectConstants.ServiceUrlAttribute); - - MutablePropertyValues properties = new MutablePropertyValues(); - if (StringUtils.HasText(serviceInterface)) - { - properties.Add("ServiceInterface", serviceInterface); - } - if (StringUtils.HasText(serviceUrl)) - { - properties.Add("ServiceUrl", serviceUrl); - } - IConfigurableObjectDefinition cod = parserContext.ReaderContext.ObjectDefinitionFactory.CreateObjectDefinition( - typeName, null, parserContext.ReaderContext.Reader.Domain); - cod.PropertyValues = properties; - return cod; - } - - /// - /// Parses the CaoFactoryObject definition. - /// - /// The element to parse. - /// The name of the object definition. - /// The parser context. - /// CaoFactoryObject object definition. - private IConfigurableObjectDefinition ParseCaoFactoryObject( - XmlElement element, string name, ParserContext parserContext) - { - string typeName = GetTypeName(element); - string remoteTargetName = element.GetAttribute(CaoFactoryObjectConstants.RemoteTargetNameAttribute); - string serviceUrl = element.GetAttribute(CaoFactoryObjectConstants.ServiceUrlAttribute); - - MutablePropertyValues properties = new MutablePropertyValues(); - if (StringUtils.HasText(remoteTargetName)) - { - properties.Add("RemoteTargetName", remoteTargetName); - } - if (StringUtils.HasText(serviceUrl)) - { - properties.Add("ServiceUrl", serviceUrl); - } - - foreach (XmlElement child in element.ChildNodes) - { - switch (child.LocalName) - { - case CaoFactoryObjectConstants.ConstructorArgumentsElement: - properties.Add("ConstructorArguments", base.ParseListElement(child, name, parserContext)); - break; - } - } - - IConfigurableObjectDefinition cod = parserContext.ReaderContext.ObjectDefinitionFactory.CreateObjectDefinition( - typeName, null, parserContext.ReaderContext.Reader.Domain); - cod.PropertyValues = properties; - - return cod; - } - - /// - /// Parses the RemoteObjectFactory definition. - /// - /// The element to parse. - /// The name of the object definition. - /// The parser context. - /// RemoteObjectFactory object definition. - private IConfigurableObjectDefinition ParseRemoteObjectFactory( - XmlElement element, string name, ParserContext parserContext) - { - string typeName = GetTypeName(element); - string targetName = element.GetAttribute(RemoteObjectFactoryConstants.TargetNameAttribute); - string infinite = element.GetAttribute(RemoteObjectFactoryConstants.InfiniteAttribute); - - MutablePropertyValues properties = new MutablePropertyValues(); - if (StringUtils.HasText(targetName)) - { - properties.Add("Target", targetName); - } - if (StringUtils.HasText(infinite)) - { - properties.Add("Infinite", infinite); - } - - foreach (XmlElement child in element.ChildNodes) - { - switch (child.LocalName) - { - case LifeTimeConstants.LifeTimeElement: - ParseLifeTime(properties, child, parserContext); - break; - case InterfacesConstants.InterfacesElement: - properties.Add("Interfaces", base.ParseListElement(child, name, parserContext)); - break; - } - } - - IConfigurableObjectDefinition cod = parserContext.ReaderContext.ObjectDefinitionFactory.CreateObjectDefinition( - typeName, null, parserContext.ReaderContext.Reader.Domain); - cod.PropertyValues = properties; - - return cod; - } - - /// - /// Parses the SaoExporter definition. - /// - /// The element to parse. - /// The name of the object definition. - /// The parser context. - /// SaoExporter object definition. - private IConfigurableObjectDefinition ParseSaoExporter( - XmlElement element, string name, ParserContext parserContext) - { - string typeName = GetTypeName(element); - string targetName = element.GetAttribute(SaoExporterConstants.TargetNameAttribute); - string applicationName = element.GetAttribute(SaoExporterConstants.ApplicationNameAttribute); - string serviceName = element.GetAttribute(SaoExporterConstants.ServiceNameAttribute); - string infinite = element.GetAttribute(SaoExporterConstants.InfiniteAttribute); - - MutablePropertyValues properties = new MutablePropertyValues(); - if (StringUtils.HasText(targetName)) - { - properties.Add("TargetName", targetName); - } - if (StringUtils.HasText(applicationName)) - { - properties.Add("ApplicationName", applicationName); - } - if (StringUtils.HasText(serviceName)) - { - properties.Add("ServiceName", serviceName); - } - if (StringUtils.HasText(infinite)) - { - properties.Add("Infinite", infinite); - } - - foreach (XmlElement child in element.ChildNodes) - { - switch (child.LocalName) - { - case LifeTimeConstants.LifeTimeElement: - ParseLifeTime(properties, child, parserContext); - break; - case InterfacesConstants.InterfacesElement: - properties.Add("Interfaces", base.ParseListElement(child, name, parserContext)); - break; - } - } - - IConfigurableObjectDefinition cod = parserContext.ReaderContext.ObjectDefinitionFactory.CreateObjectDefinition( - typeName, null, parserContext.ReaderContext.Reader.Domain); - cod.PropertyValues = properties; - return cod; - } - - /// - /// Parses the CaoExporter definition. - /// - /// The element to parse. - /// The name of the object definition. - /// The parser context. - /// CaoExporter object definition. - private IConfigurableObjectDefinition ParseCaoExporter( - XmlElement element, string name, ParserContext parserContext) - { - string typeName = GetTypeName(element); - string targetName = element.GetAttribute(CaoExporterConstants.TargetNameAttribute); - string infinite = element.GetAttribute(CaoExporterConstants.InfiniteAttribute); - - MutablePropertyValues properties = new MutablePropertyValues(); - if (StringUtils.HasText(targetName)) - { - properties.Add("TargetName", targetName); - } - if (StringUtils.HasText(infinite)) - { - properties.Add("Infinite", infinite); - } - - foreach (XmlElement child in element.ChildNodes) - { - switch (child.LocalName) - { - case LifeTimeConstants.LifeTimeElement: - ParseLifeTime(properties, child, parserContext); - break; - case InterfacesConstants.InterfacesElement: - properties.Add("Interfaces", base.ParseListElement(child, name, parserContext)); - break; - } - } - - IConfigurableObjectDefinition cod = parserContext.ReaderContext.ObjectDefinitionFactory.CreateObjectDefinition( - typeName, null, parserContext.ReaderContext.Reader.Domain); - cod.PropertyValues = properties; - - return cod; - } - - /// - /// Parses the LifeTime definition. - /// - private void ParseLifeTime(MutablePropertyValues properties, XmlElement child, ParserContext parserContext) - { - string initialLeaseTime = child.GetAttribute(LifeTimeConstants.InitialLeaseTimeAttribute); - string renewOnCallTime = child.GetAttribute(LifeTimeConstants.RenewOnCallTimeAttribute); - string sponsorshipTimeout = child.GetAttribute(LifeTimeConstants.SponsorshipTimeoutAttribute); - - if (StringUtils.HasText(initialLeaseTime)) - { - properties.Add("InitialLeaseTime", initialLeaseTime); - } - if (StringUtils.HasText(renewOnCallTime)) - { - properties.Add("RenewOnCallTime", renewOnCallTime); - } - if (StringUtils.HasText(sponsorshipTimeout)) - { - properties.Add("SponsorshipTimeout", sponsorshipTimeout); - } - } - - /// - /// Gets the name of the object type for the specified element. - /// - /// The element. - /// The name of the object type. - private string GetTypeName(XmlElement element) - { - string typeName = element.GetAttribute(ObjectDefinitionConstants.TypeAttribute); - if (StringUtils.IsNullOrEmpty(typeName)) - { - return RemotingTypePrefix + element.LocalName; - } - return typeName; - } - - #region Element & Attribute Name Constants - - private class RemotingConfigurerConstants - { - public const string RemotingConfigurerElement = "configurer"; - public const string FilenameAttribute = "filename"; - public const string UseConfigFileAttribute = "useConfigFile"; - public const string EnsureSecurityAttribute = "ensureSecurity"; - } - - private class SaoFactoryObjectConstants - { - public const string SaoFactoryObjectElement = "saoFactory"; - public const string ServiceInterfaceAttribute = "serviceInterface"; - public const string ServiceUrlAttribute = "serviceUrl"; - } - - private class CaoFactoryObjectConstants - { - public const string CaoFactoryObjectElement = "caoFactory"; - public const string ConstructorArgumentsElement = "constructor-args"; - public const string RemoteTargetNameAttribute = "remoteTargetName"; - public const string ServiceUrlAttribute = "serviceUrl"; - } - - private class LifeTimeConstants - { - public const string LifeTimeElement = "lifeTime"; - public const string InitialLeaseTimeAttribute = "initialLeaseTime"; - public const string RenewOnCallTimeAttribute = "renewOnCallTime"; - public const string SponsorshipTimeoutAttribute = "sponsorshipTimeout"; - } - - private class InterfacesConstants - { - public const string InterfacesElement = "interfaces"; - } - - private class RemoteObjectFactoryConstants - { - public const string RemoteObjectFactoryElement = "remoteObjectFactory"; - public const string TargetNameAttribute = "targetName"; - public const string InfiniteAttribute = "infinite"; - } - - private class SaoExporterConstants - { - public const string SaoExporterElement = "saoExporter"; - public const string TargetNameAttribute = "targetName"; - public const string ApplicationNameAttribute = "applicationName"; - public const string ServiceNameAttribute = "serviceName"; - public const string InfiniteAttribute = "infinite"; - } - - private class CaoExporterConstants - { - public const string CaoExporterElement = "caoExporter"; - public const string TargetNameAttribute = "targetName"; - public const string InfiniteAttribute = "infinite"; - } - - #endregion + TypeRegistry.RegisterType( + RemotingTypePrefix + RemotingConfigurerConstants.RemotingConfigurerElement, + typeof(RemotingConfigurer)); + TypeRegistry.RegisterType( + RemotingTypePrefix + SaoFactoryObjectConstants.SaoFactoryObjectElement, + typeof(SaoFactoryObject)); + TypeRegistry.RegisterType( + RemotingTypePrefix + CaoFactoryObjectConstants.CaoFactoryObjectElement, + typeof(CaoFactoryObject)); + TypeRegistry.RegisterType( + RemotingTypePrefix + RemoteObjectFactoryConstants.RemoteObjectFactoryElement, + typeof(RemoteObjectFactory)); + TypeRegistry.RegisterType( + RemotingTypePrefix + SaoExporterConstants.SaoExporterElement, + typeof(SaoExporter)); + TypeRegistry.RegisterType( + RemotingTypePrefix + CaoExporterConstants.CaoExporterElement, + typeof(CaoExporter)); } -} + + /// + /// Initializes a new instance of the class. + /// + public RemotingNamespaceParser() + { + } + + /// + /// Parse the specified element and register any resulting + /// IObjectDefinitions with the IObjectDefinitionRegistry that is + /// embedded in the supplied ParserContext. + /// + /// The element to be parsed into one or more IObjectDefinitions + /// The object encapsulating the current state of the parsing + /// process. + /// + /// The primary IObjectDefinition (can be null as explained above) + /// + /// + /// Implementations should return the primary IObjectDefinition + /// that results from the parse phase if they wish to used nested + /// inside (for example) a <property> tag. + /// Implementations may return null if they will not + /// be used in a nested scenario. + /// + /// + public override IObjectDefinition ParseElement(XmlElement element, ParserContext parserContext) + { + string name = element.GetAttribute(ObjectDefinitionConstants.IdAttribute); + IConfigurableObjectDefinition remotingDefinition = ParseRemotingDefinition(element, name, parserContext); + if (!StringUtils.HasText(name)) + { + name = ObjectDefinitionReaderUtils.GenerateObjectName(remotingDefinition, parserContext.Registry); + } + + parserContext.Registry.RegisterObjectDefinition(name, remotingDefinition); + + return null; + } + + /// + /// Parses remoting definitions. + /// + /// Validator XML element. + /// The name of the object definition. + /// The parser context. + /// A remoting object definition. + private IConfigurableObjectDefinition ParseRemotingDefinition( + XmlElement element, string name, ParserContext parserContext) + { + switch (element.LocalName) + { + case RemotingConfigurerConstants.RemotingConfigurerElement: + return ParseRemotingConfigurer(element, name, parserContext); + case SaoFactoryObjectConstants.SaoFactoryObjectElement: + return ParseSaoFactoryObject(element, name, parserContext); + case CaoFactoryObjectConstants.CaoFactoryObjectElement: + return ParseCaoFactoryObject(element, name, parserContext); + case RemoteObjectFactoryConstants.RemoteObjectFactoryElement: + return ParseRemoteObjectFactory(element, name, parserContext); + case SaoExporterConstants.SaoExporterElement: + return ParseSaoExporter(element, name, parserContext); + case CaoExporterConstants.CaoExporterElement: + return ParseCaoExporter(element, name, parserContext); + } + + return null; + } + + /// + /// Parses the RemotingConfigurer definition. + /// + /// The element to parse. + /// The name of the object definition. + /// The parser context. + /// RemotingConfigurer object definition. + private IConfigurableObjectDefinition ParseRemotingConfigurer( + XmlElement element, string name, ParserContext parserContext) + { + string typeName = GetTypeName(element); + string filename = element.GetAttribute(RemotingConfigurerConstants.FilenameAttribute); + string useConfigFile = element.GetAttribute(RemotingConfigurerConstants.UseConfigFileAttribute); + string ensureSecurity = element.GetAttribute(RemotingConfigurerConstants.EnsureSecurityAttribute); + + MutablePropertyValues properties = new MutablePropertyValues(); + if (StringUtils.HasText(filename)) + { + properties.Add("Filename", filename); + } + + if (StringUtils.HasText(useConfigFile)) + { + properties.Add("UseConfigFile", useConfigFile); + } + + if (StringUtils.HasText(ensureSecurity)) + { + properties.Add("EnsureSecurity", ensureSecurity); + } + + IConfigurableObjectDefinition cod = parserContext.ReaderContext.ObjectDefinitionFactory.CreateObjectDefinition( + typeName, null, parserContext.ReaderContext.Reader.Domain); + cod.PropertyValues = properties; + return cod; + } + + /// + /// Parses the SaoFactoryObject definition. + /// + /// The element to parse. + /// The name of the object definition. + /// The parser context. + /// SaoFactoryObject object definition. + private IConfigurableObjectDefinition ParseSaoFactoryObject( + XmlElement element, string name, ParserContext parserContext) + { + string typeName = GetTypeName(element); + string serviceInterface = element.GetAttribute(SaoFactoryObjectConstants.ServiceInterfaceAttribute); + string serviceUrl = element.GetAttribute(SaoFactoryObjectConstants.ServiceUrlAttribute); + + MutablePropertyValues properties = new MutablePropertyValues(); + if (StringUtils.HasText(serviceInterface)) + { + properties.Add("ServiceInterface", serviceInterface); + } + + if (StringUtils.HasText(serviceUrl)) + { + properties.Add("ServiceUrl", serviceUrl); + } + + IConfigurableObjectDefinition cod = parserContext.ReaderContext.ObjectDefinitionFactory.CreateObjectDefinition( + typeName, null, parserContext.ReaderContext.Reader.Domain); + cod.PropertyValues = properties; + return cod; + } + + /// + /// Parses the CaoFactoryObject definition. + /// + /// The element to parse. + /// The name of the object definition. + /// The parser context. + /// CaoFactoryObject object definition. + private IConfigurableObjectDefinition ParseCaoFactoryObject( + XmlElement element, string name, ParserContext parserContext) + { + string typeName = GetTypeName(element); + string remoteTargetName = element.GetAttribute(CaoFactoryObjectConstants.RemoteTargetNameAttribute); + string serviceUrl = element.GetAttribute(CaoFactoryObjectConstants.ServiceUrlAttribute); + + MutablePropertyValues properties = new MutablePropertyValues(); + if (StringUtils.HasText(remoteTargetName)) + { + properties.Add("RemoteTargetName", remoteTargetName); + } + + if (StringUtils.HasText(serviceUrl)) + { + properties.Add("ServiceUrl", serviceUrl); + } + + foreach (XmlElement child in element.ChildNodes) + { + switch (child.LocalName) + { + case CaoFactoryObjectConstants.ConstructorArgumentsElement: + properties.Add("ConstructorArguments", base.ParseListElement(child, name, parserContext)); + break; + } + } + + IConfigurableObjectDefinition cod = parserContext.ReaderContext.ObjectDefinitionFactory.CreateObjectDefinition( + typeName, null, parserContext.ReaderContext.Reader.Domain); + cod.PropertyValues = properties; + + return cod; + } + + /// + /// Parses the RemoteObjectFactory definition. + /// + /// The element to parse. + /// The name of the object definition. + /// The parser context. + /// RemoteObjectFactory object definition. + private IConfigurableObjectDefinition ParseRemoteObjectFactory( + XmlElement element, string name, ParserContext parserContext) + { + string typeName = GetTypeName(element); + string targetName = element.GetAttribute(RemoteObjectFactoryConstants.TargetNameAttribute); + string infinite = element.GetAttribute(RemoteObjectFactoryConstants.InfiniteAttribute); + + MutablePropertyValues properties = new MutablePropertyValues(); + if (StringUtils.HasText(targetName)) + { + properties.Add("Target", targetName); + } + + if (StringUtils.HasText(infinite)) + { + properties.Add("Infinite", infinite); + } + + foreach (XmlElement child in element.ChildNodes) + { + switch (child.LocalName) + { + case LifeTimeConstants.LifeTimeElement: + ParseLifeTime(properties, child, parserContext); + break; + case InterfacesConstants.InterfacesElement: + properties.Add("Interfaces", base.ParseListElement(child, name, parserContext)); + break; + } + } + + IConfigurableObjectDefinition cod = parserContext.ReaderContext.ObjectDefinitionFactory.CreateObjectDefinition( + typeName, null, parserContext.ReaderContext.Reader.Domain); + cod.PropertyValues = properties; + + return cod; + } + + /// + /// Parses the SaoExporter definition. + /// + /// The element to parse. + /// The name of the object definition. + /// The parser context. + /// SaoExporter object definition. + private IConfigurableObjectDefinition ParseSaoExporter( + XmlElement element, string name, ParserContext parserContext) + { + string typeName = GetTypeName(element); + string targetName = element.GetAttribute(SaoExporterConstants.TargetNameAttribute); + string applicationName = element.GetAttribute(SaoExporterConstants.ApplicationNameAttribute); + string serviceName = element.GetAttribute(SaoExporterConstants.ServiceNameAttribute); + string infinite = element.GetAttribute(SaoExporterConstants.InfiniteAttribute); + + MutablePropertyValues properties = new MutablePropertyValues(); + if (StringUtils.HasText(targetName)) + { + properties.Add("TargetName", targetName); + } + + if (StringUtils.HasText(applicationName)) + { + properties.Add("ApplicationName", applicationName); + } + + if (StringUtils.HasText(serviceName)) + { + properties.Add("ServiceName", serviceName); + } + + if (StringUtils.HasText(infinite)) + { + properties.Add("Infinite", infinite); + } + + foreach (XmlElement child in element.ChildNodes) + { + switch (child.LocalName) + { + case LifeTimeConstants.LifeTimeElement: + ParseLifeTime(properties, child, parserContext); + break; + case InterfacesConstants.InterfacesElement: + properties.Add("Interfaces", base.ParseListElement(child, name, parserContext)); + break; + } + } + + IConfigurableObjectDefinition cod = parserContext.ReaderContext.ObjectDefinitionFactory.CreateObjectDefinition( + typeName, null, parserContext.ReaderContext.Reader.Domain); + cod.PropertyValues = properties; + return cod; + } + + /// + /// Parses the CaoExporter definition. + /// + /// The element to parse. + /// The name of the object definition. + /// The parser context. + /// CaoExporter object definition. + private IConfigurableObjectDefinition ParseCaoExporter( + XmlElement element, string name, ParserContext parserContext) + { + string typeName = GetTypeName(element); + string targetName = element.GetAttribute(CaoExporterConstants.TargetNameAttribute); + string infinite = element.GetAttribute(CaoExporterConstants.InfiniteAttribute); + + MutablePropertyValues properties = new MutablePropertyValues(); + if (StringUtils.HasText(targetName)) + { + properties.Add("TargetName", targetName); + } + + if (StringUtils.HasText(infinite)) + { + properties.Add("Infinite", infinite); + } + + foreach (XmlElement child in element.ChildNodes) + { + switch (child.LocalName) + { + case LifeTimeConstants.LifeTimeElement: + ParseLifeTime(properties, child, parserContext); + break; + case InterfacesConstants.InterfacesElement: + properties.Add("Interfaces", base.ParseListElement(child, name, parserContext)); + break; + } + } + + IConfigurableObjectDefinition cod = parserContext.ReaderContext.ObjectDefinitionFactory.CreateObjectDefinition( + typeName, null, parserContext.ReaderContext.Reader.Domain); + cod.PropertyValues = properties; + + return cod; + } + + /// + /// Parses the LifeTime definition. + /// + private void ParseLifeTime(MutablePropertyValues properties, XmlElement child, ParserContext parserContext) + { + string initialLeaseTime = child.GetAttribute(LifeTimeConstants.InitialLeaseTimeAttribute); + string renewOnCallTime = child.GetAttribute(LifeTimeConstants.RenewOnCallTimeAttribute); + string sponsorshipTimeout = child.GetAttribute(LifeTimeConstants.SponsorshipTimeoutAttribute); + + if (StringUtils.HasText(initialLeaseTime)) + { + properties.Add("InitialLeaseTime", initialLeaseTime); + } + + if (StringUtils.HasText(renewOnCallTime)) + { + properties.Add("RenewOnCallTime", renewOnCallTime); + } + + if (StringUtils.HasText(sponsorshipTimeout)) + { + properties.Add("SponsorshipTimeout", sponsorshipTimeout); + } + } + + /// + /// Gets the name of the object type for the specified element. + /// + /// The element. + /// The name of the object type. + private string GetTypeName(XmlElement element) + { + string typeName = element.GetAttribute(ObjectDefinitionConstants.TypeAttribute); + if (StringUtils.IsNullOrEmpty(typeName)) + { + return RemotingTypePrefix + element.LocalName; + } + + return typeName; + } + + #region Element & Attribute Name Constants + + private class RemotingConfigurerConstants + { + public const string RemotingConfigurerElement = "configurer"; + public const string FilenameAttribute = "filename"; + public const string UseConfigFileAttribute = "useConfigFile"; + public const string EnsureSecurityAttribute = "ensureSecurity"; + } + + private class SaoFactoryObjectConstants + { + public const string SaoFactoryObjectElement = "saoFactory"; + public const string ServiceInterfaceAttribute = "serviceInterface"; + public const string ServiceUrlAttribute = "serviceUrl"; + } + + private class CaoFactoryObjectConstants + { + public const string CaoFactoryObjectElement = "caoFactory"; + public const string ConstructorArgumentsElement = "constructor-args"; + public const string RemoteTargetNameAttribute = "remoteTargetName"; + public const string ServiceUrlAttribute = "serviceUrl"; + } + + private class LifeTimeConstants + { + public const string LifeTimeElement = "lifeTime"; + public const string InitialLeaseTimeAttribute = "initialLeaseTime"; + public const string RenewOnCallTimeAttribute = "renewOnCallTime"; + public const string SponsorshipTimeoutAttribute = "sponsorshipTimeout"; + } + + private class InterfacesConstants + { + public const string InterfacesElement = "interfaces"; + } + + private class RemoteObjectFactoryConstants + { + public const string RemoteObjectFactoryElement = "remoteObjectFactory"; + public const string TargetNameAttribute = "targetName"; + public const string InfiniteAttribute = "infinite"; + } + + private class SaoExporterConstants + { + public const string SaoExporterElement = "saoExporter"; + public const string TargetNameAttribute = "targetName"; + public const string ApplicationNameAttribute = "applicationName"; + public const string ServiceNameAttribute = "serviceName"; + public const string InfiniteAttribute = "infinite"; + } + + private class CaoExporterConstants + { + public const string CaoExporterElement = "caoExporter"; + public const string TargetNameAttribute = "targetName"; + public const string InfiniteAttribute = "infinite"; + } + + #endregion +} \ No newline at end of file diff --git a/src/Spring/Spring.Services/Remoting/Config/spring-remoting-1.1.xsd b/src/Spring/Spring.Services/Remoting/Config/spring-remoting-1.1.xsd index 16878986..b951f044 100644 --- a/src/Spring/Spring.Services/Remoting/Config/spring-remoting-1.1.xsd +++ b/src/Spring/Spring.Services/Remoting/Config/spring-remoting-1.1.xsd @@ -1,231 +1,235 @@ + xmlns:objects="http://www.springframework.net" + xmlns:xs="http://www.w3.org/2001/XMLSchema" + xmlns:vs="http://schemas.microsoft.com/Visual-Studio-Intellisense" + targetNamespace="http://www.springframework.net/remoting" + elementFormDefault="qualified" attributeFormDefault="unqualified" + vs:friendlyname="Spring.NET Remoting Framework Configuration" vs:ishtmlschema="false" + vs:iscasesensitive="true" vs:requireattributequotes="true" vs:defaultnamespacequalifier="" + vs:defaultnsprefix=""> - + - - - Spring.NET Remoting Framework Config Schema Definition - - Author: Bruno Baia - - This file defines a configuration schema for the remoting framework - object definitions. Using elements from this schema instead of the - standard object definitions can greatly simplify remoting configuration. - - - - - Configures the remoting infrastructure. - - - - The name of the remoting configurationn file. - - - - - Indicates whether a configuration file is used. Default is true. - - - - - Indicates whether the security is enabled. Default is false. - - - + + Spring.NET Remoting Framework Config Schema Definition - - - Creates a reference to a server activated object (SAO). - - - - The id of the created object. - - - - - The remote service interface. - - - - - The URI of the well known object. - - - + Author: Bruno Baia - - - Creates a reference to a client activated object (CAO). + This file defines a configuration schema for the remoting framework + object definitions. Using elements from this schema instead of the + standard object definitions can greatly simplify remoting configuration. + - - + + - The arguments used to call the CAO constructor. + Configures the remoting infrastructure. - - - - - - - - The id of the created object. - - - - - The remote target name to activate. - - - - - The Uri of the remote type. - - - + + + The name of the remoting configurationn file. + + + + + Indicates whether a configuration file is used. Default is true. + + + + + Indicates whether the security is enabled. Default is false. + + + - - - Defines the lifetime policy of the remoteobject. - - - - The initial time for the lease. - - - - - The amount of time to add to the current lease time after each call. - - - - - The amount of time to wait for a sponsor to respond with a lease renewal time. - - - - - - - Creates a MarshalByRefObject wrapper around target class. - - - - + - The list of interfaces to wrap. + Creates a reference to a server activated object (SAO). - - - - - - - - The id of the created remote object to be referenced. - - - - - The target object. - - - - - Indicates whether the remote object has infinite lifetime. - - - + + + The id of the created object. + + + + + The remote service interface. + + + + + The URI of the well known object. + + + - - - Registers an object as a Server Activated Object (SAO). - - - - + - The list of interfaces whose methods should be exported. + Creates a reference to a client activated object (CAO). - - - - - - - - The id of the exporter to be referenced. - - - - - The target object to export. - - - - - The name of the remote application. - - - - - The name of the exported remote service. - - - - - Indicates whether the remote object has infinite lifetime. - - - + + + + The arguments used to call the CAO constructor. + + + + + + + + + The id of the created object. + + + + + The remote target name to activate. + + + + + The Uri of the remote type. + + + - - - Registers an object as a Client Activated Object (CAO). - - - - + - The list of interfaces whose methods should be exported. + Defines the lifetime policy of the remoteobject. - - - - - - - - The id of the exporter to be referenced. - - - - - The target object to export. - - - - - Indicates whether the remote object has infinite lifetime. - - - + + + The initial time for the lease. + + + + + The amount of time to add to the current lease time after each call. + + + + + + The amount of time to wait for a sponsor to respond with a lease renewal time. + + + + - - - - - - + + + Creates a MarshalByRefObject wrapper around target class. + + + + + + The list of interfaces to wrap. + + + + + + + + + The id of the created remote object to be referenced. + + + + + The target object. + + + + + Indicates whether the remote object has infinite lifetime. + + + + + + + Registers an object as a Server Activated Object (SAO). + + + + + + The list of interfaces whose methods should be exported. + + + + + + + + + The id of the exporter to be referenced. + + + + + The target object to export. + + + + + The name of the remote application. + + + + + The name of the exported remote service. + + + + + Indicates whether the remote object has infinite lifetime. + + + + + + + Registers an object as a Client Activated Object (CAO). + + + + + + The list of interfaces whose methods should be exported. + + + + + + + + + The id of the exporter to be referenced. + + + + + The target object to export. + + + + + Indicates whether the remote object has infinite lifetime. + + + + + + + + + + diff --git a/src/Spring/Spring.Services/Remoting/RemoteObjectFactory.cs b/src/Spring/Spring.Services/Remoting/RemoteObjectFactory.cs index a8ab2820..1eb98a6d 100644 --- a/src/Spring/Spring.Services/Remoting/RemoteObjectFactory.cs +++ b/src/Spring/Spring.Services/Remoting/RemoteObjectFactory.cs @@ -19,158 +19,157 @@ #endregion using System.Reflection; - using Spring.Proxy; using Spring.Objects.Factory; using Spring.Remoting.Support; using Spring.Core.TypeResolution; -namespace Spring.Remoting +namespace Spring.Remoting; + +/// +/// Factory for creating MarshalByRefObject wrapper around target class. +/// +/// Bruno Baia +public class RemoteObjectFactory : ConfigurableLifetime, IInitializingObject, IFactoryObject { - /// - /// Factory for creating MarshalByRefObject wrapper around target class. - /// - /// Bruno Baia - public class RemoteObjectFactory : ConfigurableLifetime, IInitializingObject, IFactoryObject - { - #region Fields + #region Fields - private object target; - private Type baseType = typeof(BaseRemoteObject); - private string[] interfaces; + private object target; + private Type baseType = typeof(BaseRemoteObject); + private string[] interfaces; - private ConstructorInfo proxyConstructor; + private ConstructorInfo proxyConstructor; - #endregion + #endregion - #region Constructor(s) / Destructor + #region Constructor(s) / Destructor - /// - /// Creates a new instance of the MarshalByRefObjectFactory. - /// - public RemoteObjectFactory() - { - } + /// + /// Creates a new instance of the MarshalByRefObjectFactory. + /// + public RemoteObjectFactory() + { + } - #endregion + #endregion - #region Properties + #region Properties - /// - /// Gets or sets the target object. - /// - public object Target - { - get { return target; } - set { target = value; } - } + /// + /// Gets or sets the target object. + /// + public object Target + { + get { return target; } + set { target = value; } + } - /// - /// Gets or sets the class or subclass - /// that the proxy must inherit from. - /// - public Type BaseType + /// + /// Gets or sets the class or subclass + /// that the proxy must inherit from. + /// + public Type BaseType + { + get { return baseType; } + set { baseType = value; } + } + + /// + /// Gets or sets the list of interfaces to wrap. + /// + /// + /// The default value of this property is all the interfaces + /// implemented or inherited by the target type. + /// + /// The interfaces to export. + public string[] Interfaces + { + get { return interfaces; } + set { interfaces = value; } + } + + #endregion + + #region IInitializingObject Members + + /// + /// Initializes factory object. + /// + public void AfterPropertiesSet() + { + ValidateConfiguration(); + GenerateProxy(); + } + + #endregion + + #region IFactoryObject Members + + /// + /// Returns type of the remotable target proxy. + /// + public Type ObjectType + { + get { - get { return baseType; } - set { baseType = value; } + return (proxyConstructor != null) ? proxyConstructor.DeclaringType : target.GetType(); } + } - /// - /// Gets or sets the list of interfaces to wrap. - /// - /// - /// The default value of this property is all the interfaces - /// implemented or inherited by the target type. - /// - /// The interfaces to export. - public string[] Interfaces - { - get { return interfaces; } - set { interfaces = value; } - } - - #endregion - - #region IInitializingObject Members - - /// - /// Initializes factory object. - /// - public void AfterPropertiesSet() - { - ValidateConfiguration(); + /// + /// Creates new instance of the remotable target proxy. + /// + /// New instance of the remotable target proxy. + public object GetObject() + { + if (proxyConstructor == null) GenerateProxy(); - } - #endregion + return proxyConstructor.Invoke(new object[1] { target }); + } - #region IFactoryObject Members + /// + /// Always returns false. + /// + public bool IsSingleton + { + get + { + return false; + } + } - /// - /// Returns type of the remotable target proxy. - /// - public Type ObjectType - { - get - { - return (proxyConstructor != null) ? proxyConstructor.DeclaringType : target.GetType(); - } - } + #endregion - /// - /// Creates new instance of the remotable target proxy. - /// - /// New instance of the remotable target proxy. - public object GetObject() - { - if (proxyConstructor == null) - GenerateProxy(); + #region Private Methods - return proxyConstructor.Invoke(new object[1]{ target }); - } + private void ValidateConfiguration() + { + if (Target == null) + { + throw new ArgumentException("The Target property is required."); + } - /// - /// Always returns false. - /// - public bool IsSingleton - { - get - { - return false; - } - } + if (!typeof(BaseRemoteObject).IsAssignableFrom(BaseType)) + { + throw new ArgumentException("The type BaseRemoteObject cannot be assigned from BaseType."); + } + } - #endregion + private void GenerateProxy() + { + IProxyTypeBuilder builder = new RemoteObjectProxyTypeBuilder(this); + builder.TargetType = target.GetType(); + builder.BaseType = baseType; + if (interfaces != null && interfaces.Length > 0) + { + builder.Interfaces = TypeResolutionUtils.ResolveInterfaceArray(interfaces); + } - #region Private Methods + Type remotableObjectType = builder.BuildProxyType(); - private void ValidateConfiguration() - { - if (Target == null) - { - throw new ArgumentException("The Target property is required."); - } - if (!typeof(BaseRemoteObject).IsAssignableFrom(BaseType)) - { - throw new ArgumentException("The type BaseRemoteObject cannot be assigned from BaseType."); - } - } + proxyConstructor = remotableObjectType.GetConstructor(new Type[1] { builder.TargetType }); + } - private void GenerateProxy() - { - IProxyTypeBuilder builder = new RemoteObjectProxyTypeBuilder(this); - builder.TargetType = target.GetType(); - builder.BaseType = baseType; - if (interfaces != null && interfaces.Length > 0) - { - builder.Interfaces = TypeResolutionUtils.ResolveInterfaceArray(interfaces); - } - - Type remotableObjectType = builder.BuildProxyType(); - - proxyConstructor = remotableObjectType.GetConstructor(new Type[1] { builder.TargetType }); - } - - #endregion - } + #endregion } diff --git a/src/Spring/Spring.Services/Remoting/RemotingConfigurer.cs b/src/Spring/Spring.Services/Remoting/RemotingConfigurer.cs index 02d5acea..59ef04de 100644 --- a/src/Spring/Spring.Services/Remoting/RemotingConfigurer.cs +++ b/src/Spring/Spring.Services/Remoting/RemotingConfigurer.cs @@ -24,130 +24,130 @@ using Spring.Core; using Spring.Core.IO; using Spring.Objects.Factory.Config; -namespace Spring.Remoting +namespace Spring.Remoting; + +/// +/// Convenience class to configure remoting infrastructure from the IoC container. +/// +/// Bruno Baia +public class RemotingConfigurer : IObjectFactoryPostProcessor, IOrdered { + #region Fields + + private static readonly ILogger log = LogManager.GetLogger(); + + private int _order = Int32.MinValue; + + private IResource _filename; + private bool _useConfigFile = true; + private bool _ensureSecurity = false; + + #endregion + + #region Constructor(s) / Destructor + /// - /// Convenience class to configure remoting infrastructure from the IoC container. + /// Initializes a new instance of the class. /// - /// Bruno Baia - public class RemotingConfigurer : IObjectFactoryPostProcessor, IOrdered + public RemotingConfigurer() { - #region Fields + } - private static readonly ILogger log = LogManager.GetLogger(); + #endregion - private int _order = Int32.MinValue; + #region Properties - private IResource _filename; - private bool _useConfigFile = true; - private bool _ensureSecurity = false; + /// + /// Gets or sets the name of the remoting configuration file. + /// + /// + /// If filename is or not set, + /// current AppDomain's configuration file will be used. + /// + public IResource Filename + { + get { return _filename; } + set { _filename = value; } + } - #endregion + /// + /// Indicates whether a configuration file is used. + /// Default value is . + /// + /// + /// If , default remoting configuration will be used. + /// + public bool UseConfigFile + { + get { return _useConfigFile; } + set { _useConfigFile = value; } + } - #region Constructor(s) / Destructor + /// + /// Gets or sets if security is enabled. + /// + /// + /// This property is only available since .NET Framework 2.0. + /// + public bool EnsureSecurity + { + get { return _ensureSecurity; } + set { _ensureSecurity = value; } + } - /// - /// Initializes a new instance of the class. - /// - public RemotingConfigurer() - {} + #endregion - #endregion + #region IObjectFactoryPostProcessor Members - #region Properties - - /// - /// Gets or sets the name of the remoting configuration file. - /// - /// - /// If filename is or not set, - /// current AppDomain's configuration file will be used. - /// - public IResource Filename + /// + /// Modify the application context's internal object factory after its + /// standard initialization. + /// + /// + /// The object factory used by the application context. + /// + /// + public void PostProcessObjectFactory(IConfigurableListableObjectFactory factory) + { + string filename = null; + if (UseConfigFile) { - get { return _filename; } - set { _filename = value; } + filename = (Filename == null) + ? AppDomain.CurrentDomain.SetupInformation.ConfigurationFile + : Filename.File.FullName; } - /// - /// Indicates whether a configuration file is used. - /// Default value is . - /// - /// - /// If , default remoting configuration will be used. - /// - public bool UseConfigFile + RemotingConfiguration.Configure(filename, EnsureSecurity); + + #region Instrumentation + + if (log.IsEnabled(LogLevel.Debug)) { - get { return _useConfigFile; } - set { _useConfigFile = value; } - } - - /// - /// Gets or sets if security is enabled. - /// - /// - /// This property is only available since .NET Framework 2.0. - /// - public bool EnsureSecurity - { - get { return _ensureSecurity; } - set { _ensureSecurity = value; } - } - - #endregion - - #region IObjectFactoryPostProcessor Members - - /// - /// Modify the application context's internal object factory after its - /// standard initialization. - /// - /// - /// The object factory used by the application context. - /// - /// - public void PostProcessObjectFactory(IConfigurableListableObjectFactory factory) - { - string filename = null; - if (UseConfigFile) + if (filename == null) { - filename = (Filename == null) - ? AppDomain.CurrentDomain.SetupInformation.ConfigurationFile - : Filename.File.FullName; + log.LogDebug("Default remoting infrastructure loaded."); } - - RemotingConfiguration.Configure(filename, EnsureSecurity); - - #region Instrumentation - - if (log.IsEnabled(LogLevel.Debug)) + else { - if (filename == null) - { - log.LogDebug("Default remoting infrastructure loaded."); - } - else - { - log.LogDebug(String.Format("Remoting infrastructure configured using file '{0}'.", filename)); - } + log.LogDebug(String.Format("Remoting infrastructure configured using file '{0}'.", filename)); } - - #endregion - } - - #endregion - - #region IOrdered Members - - /// - /// Return the order value of this object, - /// where a higher value means greater in terms of sorting. - /// - public int Order - { - get { return _order; } } #endregion } + + #endregion + + #region IOrdered Members + + /// + /// Return the order value of this object, + /// where a higher value means greater in terms of sorting. + /// + public int Order + { + get { return _order; } + } + + #endregion } diff --git a/src/Spring/Spring.Services/Remoting/SaoExporter.cs b/src/Spring/Spring.Services/Remoting/SaoExporter.cs index ac245d81..19ff08b0 100644 --- a/src/Spring/Spring.Services/Remoting/SaoExporter.cs +++ b/src/Spring/Spring.Services/Remoting/SaoExporter.cs @@ -29,352 +29,354 @@ using Spring.Objects.Factory; using Spring.Remoting.Support; using Spring.Util; -namespace Spring.Remoting +namespace Spring.Remoting; + +/// +/// Publishes an instance of an object under +/// a given url as a Server Activated Object (SAO). +/// +/// +/// Remoting servers exported by always correspond to . +/// Objects can be exported either as SingleCall or Singleton by marking the exported object identified by +/// as either singleton or prototype. +/// +/// Aleksandar Seovic +/// Mark Pollack +/// Bruno Baia +/// Erich Eichinger +public class SaoExporter : ConfigurableLifetime, IObjectFactoryAware, IInitializingObject, IDisposable { + #region Logging + + private static readonly ILogger LOG = LogManager.GetLogger(typeof(SaoExporter)); + + #endregion + /// - /// Publishes an instance of an object under - /// a given url as a Server Activated Object (SAO). + /// Holds EXPORTER_ID to SaoExporter instance mappings. /// - /// - /// Remoting servers exported by always correspond to . - /// Objects can be exported either as SingleCall or Singleton by marking the exported object identified by - /// as either singleton or prototype. - /// - /// Aleksandar Seovic - /// Mark Pollack - /// Bruno Baia - /// Erich Eichinger - public class SaoExporter : ConfigurableLifetime, IObjectFactoryAware, IInitializingObject, IDisposable + private static readonly IDictionary s_activeExporters = new Hashtable(); + + /// + /// Returns the target object instance exported by the SaoExporter identified by . + /// + /// + /// + public static object GetTarget(string exporterId) { - #region Logging - - private static readonly ILogger LOG = LogManager.GetLogger( typeof( SaoExporter ) ); - - #endregion - - /// - /// Holds EXPORTER_ID to SaoExporter instance mappings. - /// - private static readonly IDictionary s_activeExporters = new Hashtable(); - - /// - /// Returns the target object instance exported by the SaoExporter identified by . - /// - /// - /// - public static object GetTarget( string exporterId ) + SaoExporter exporterInstance; + lock (s_activeExporters.SyncRoot) { - SaoExporter exporterInstance; - lock (s_activeExporters.SyncRoot) - { - exporterInstance = (SaoExporter)s_activeExporters[exporterId]; - } - AssertUtils.ArgumentNotNull( exporterInstance, "exporterId", "Remoting Server object is not associated with any active SaoExporter" ); - object target = exporterInstance.GetTargetInstance(); - AssertUtils.ArgumentNotNull( target, "exporterId", string.Format( "Failed retrieving target object for SaoExporter ID {0}", exporterId ) ); - return target; + exporterInstance = (SaoExporter) s_activeExporters[exporterId]; } + AssertUtils.ArgumentNotNull(exporterInstance, "exporterId", "Remoting Server object is not associated with any active SaoExporter"); + object target = exporterInstance.GetTargetInstance(); + AssertUtils.ArgumentNotNull(target, "exporterId", string.Format("Failed retrieving target object for SaoExporter ID {0}", exporterId)); + return target; + } + + #region Fields + + private readonly string EXPORTER_ID = Guid.NewGuid().ToString(); + private string targetName; + private string applicationName; + private string serviceName; + private string[] interfaces; + + private IObjectFactory objectFactory; + private MarshalByRefObject remoteObject; + + #endregion + + #region Constructor(s) / Destructor + + /// + /// Creates a new instance of the class. + /// + public SaoExporter() + { + lock (s_activeExporters.SyncRoot) + { + s_activeExporters[EXPORTER_ID] = this; + } + } + + /// + /// Cleanup before GC + /// + ~SaoExporter() + { + Dispose(false); + } + + #endregion + + #region Properties + + /// + /// Gets or sets the name of the target object definition. + /// + public string TargetName + { + get { return targetName; } + set { targetName = value; } + } + + /// + /// Gets or sets the name of the remote application. + /// + public string ApplicationName + { + get { return applicationName; } + set { applicationName = value; } + } + + /// + /// Gets or sets the name of the exported remote service. + /// + /// The name that will be used in the URI to refer to this service. + /// This will be of the form, tcp://host:port/ServiceName or + /// tcp://host:port/ApplicationName/ServiceName + /// + /// + public string ServiceName + { + get { return serviceName; } + set { serviceName = value; } + } + + /// + /// Gets or sets the list of interfaces whose methods should be exported. + /// + /// + /// The default value of this property is all the interfaces + /// implemented or inherited by the target type. + /// + /// The interfaces to export. + public string[] Interfaces + { + get { return interfaces; } + set { interfaces = value; } + } + + #endregion + + #region IObjectFactoryAware Members + + /// + /// Sets object factory to use. + /// + public IObjectFactory ObjectFactory + { + set { objectFactory = value; } + } + + #endregion + + #region IInitializingObject Members + + /// + /// Publish the object + /// + public void AfterPropertiesSet() + { + ValidateConfiguration(); + Export(); + } + + #endregion + + #region IDisposable Members + + /// + /// Disconnect the remote object from the registered remoting channels. + /// + public void Dispose() + { + GC.SuppressFinalize(this); + Dispose(true); + } + + /// + /// Stops exporting the object identified by . + /// + /// true to release both managed and unmanaged resources; false to release only unmanaged resources. + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + RemotingServices.Disconnect(remoteObject); + lock (s_activeExporters.SyncRoot) + { + s_activeExporters.Remove(this.EXPORTER_ID); + } + + remoteObject = null; + objectFactory = null; + } + } + + #endregion + + #region Private Methods + + private object GetTargetInstance() + { + return objectFactory.GetObject(targetName); + } + + private void ValidateConfiguration() + { + if (TargetName == null) + { + throw new ArgumentException("The TargetName property is required."); + } + + if (ServiceName == null) + { + throw new ArgumentException("The ServiceName property is required."); + } + } + + private void Export() + { + if (remoteObject != null) + { + throw new InvalidOperationException("object is already exported"); + } + + IProxyTypeBuilder builder = new SaoRemoteObjectProxyTypeBuilder(this); + Type targetType = this.objectFactory.GetType(targetName); + if (targetType == null) + { + // perform full object retrieval if type cannot be predicted - this will + // also cause any object creation exceptions to be thrown + targetType = this.objectFactory.GetObject(targetName).GetType(); + } + + if (targetType.IsInterface) + { + builder.Interfaces = new Type[] { targetType }; + builder.TargetType = typeof(object); + } + else + { + if (interfaces != null && interfaces.Length > 0) + { + builder.Interfaces = TypeResolutionUtils.ResolveInterfaceArray(interfaces); + } + + builder.TargetType = targetType; + } + + Type proxyType = builder.BuildProxyType(); + string objectUri = (applicationName != null ? applicationName + "/" + serviceName : serviceName); + + ConstructorInfo proxyConstructor = proxyType.GetConstructor(Type.EmptyTypes); + remoteObject = (MarshalByRefObject) proxyConstructor.Invoke(ObjectUtils.EmptyObjects); + + RemotingServices.Marshal(remoteObject, objectUri); + + #region Instrumentation + + if (LOG.IsEnabled(LogLevel.Debug)) + { + LOG.LogDebug(String.Format("Target '{0}' exported as '{1}'.", targetName, objectUri)); + } + + #endregion + } + + #endregion + + #region SaoRemoteObjectProxyTypeBuilder inner class definition + + /// + /// Builds a proxy type based on to wrap a target object + /// that is intended to be remotable. + /// + /// + /// The wrapped target object is retrieved by name from the IoC container. + /// + private sealed class SaoRemoteObjectProxyTypeBuilder : RemoteObjectProxyTypeBuilder + { #region Fields - private readonly string EXPORTER_ID = Guid.NewGuid().ToString(); - private string targetName; - private string applicationName; - private string serviceName; - private string[] interfaces; + private static readonly MethodInfo SaoExporter_GetTargetInstance = typeof(SaoExporter).GetMethod("GetTarget", new Type[] { typeof(string) }); - private IObjectFactory objectFactory; - private MarshalByRefObject remoteObject; + private SaoExporter _saoExporter; #endregion #region Constructor(s) / Destructor /// - /// Creates a new instance of the class. + /// Creates a new instance of the + /// class. /// - public SaoExporter() + /// + /// The exporter to be associated with the proxy. + /// + public SaoRemoteObjectProxyTypeBuilder(SaoExporter saoExporter) + : base(saoExporter) { - lock (s_activeExporters.SyncRoot) - { - s_activeExporters[EXPORTER_ID] = this; - } - } + this._saoExporter = saoExporter; - /// - /// Cleanup before GC - /// - ~SaoExporter() - { - Dispose( false ); + Name = "SaoRemoteObjectProxy"; + BaseType = typeof(BaseRemoteObject); } #endregion - #region Properties + #region IProxyTypeGenerator Members /// - /// Gets or sets the name of the target object definition. + /// Generates the IL instructions that pushes + /// the target instance on which calls should be delegated to. /// - public string TargetName + /// The IL generator to use. + public override void PushTarget(ILGenerator il) { - get { return targetName; } - set { targetName = value; } - } - - /// - /// Gets or sets the name of the remote application. - /// - public string ApplicationName - { - get { return applicationName; } - set { applicationName = value; } - } - - /// - /// Gets or sets the name of the exported remote service. - /// - /// The name that will be used in the URI to refer to this service. - /// This will be of the form, tcp://host:port/ServiceName or - /// tcp://host:port/ApplicationName/ServiceName - /// - /// - public string ServiceName - { - get { return serviceName; } - set { serviceName = value; } - } - - /// - /// Gets or sets the list of interfaces whose methods should be exported. - /// - /// - /// The default value of this property is all the interfaces - /// implemented or inherited by the target type. - /// - /// The interfaces to export. - public string[] Interfaces - { - get { return interfaces; } - set { interfaces = value; } + il.Emit(OpCodes.Ldstr, this._saoExporter.EXPORTER_ID); + il.Emit(OpCodes.Call, SaoExporter_GetTargetInstance); } #endregion - #region IObjectFactoryAware Members + #region Protected Methods /// - /// Sets object factory to use. + /// Implements constructors for the proxy class. /// - public IObjectFactory ObjectFactory + /// + /// The to use. + /// + protected override void ImplementConstructors(TypeBuilder builder) { - set { objectFactory = value; } - } + MethodAttributes attributes = MethodAttributes.Public | + MethodAttributes.HideBySig | MethodAttributes.SpecialName | + MethodAttributes.RTSpecialName; + ConstructorBuilder cb = builder.DefineConstructor(attributes, + CallingConventions.Standard, Type.EmptyTypes); - #endregion - - #region IInitializingObject Members - - /// - /// Publish the object - /// - public void AfterPropertiesSet() - { - ValidateConfiguration(); - Export(); - } - - #endregion - - #region IDisposable Members - - /// - /// Disconnect the remote object from the registered remoting channels. - /// - public void Dispose() - { - GC.SuppressFinalize( this ); - Dispose( true ); + ILGenerator il = cb.GetILGenerator(); + GenerateRemoteObjectLifetimeInitialization(il); + il.Emit(OpCodes.Ret); } /// - /// Stops exporting the object identified by . + /// Deaclares a field that holds the target object instance. /// - /// true to release both managed and unmanaged resources; false to release only unmanaged resources. - protected virtual void Dispose( bool disposing ) + /// + /// The builder to use for code generation. + /// + protected override void DeclareTargetInstanceField(TypeBuilder builder) { - if (disposing) - { - RemotingServices.Disconnect( remoteObject ); - lock (s_activeExporters.SyncRoot) - { - s_activeExporters.Remove( this.EXPORTER_ID ); - } - remoteObject = null; - objectFactory = null; - } - } - - #endregion - - #region Private Methods - - private object GetTargetInstance() - { - return objectFactory.GetObject( targetName ); - } - - private void ValidateConfiguration() - { - if (TargetName == null) - { - throw new ArgumentException( "The TargetName property is required." ); - } - - if (ServiceName == null) - { - throw new ArgumentException( "The ServiceName property is required." ); - } - } - - private void Export() - { - if (remoteObject != null) - { - throw new InvalidOperationException("object is already exported"); - } - - IProxyTypeBuilder builder = new SaoRemoteObjectProxyTypeBuilder( this ); - Type targetType = this.objectFactory.GetType( targetName ); - if (targetType == null) - { - // perform full object retrieval if type cannot be predicted - this will - // also cause any object creation exceptions to be thrown - targetType = this.objectFactory.GetObject(targetName).GetType(); - } - - if (targetType.IsInterface) - { - builder.Interfaces = new Type[] { targetType }; - builder.TargetType = typeof(object); - } - else - { - if (interfaces != null && interfaces.Length > 0) - { - builder.Interfaces = TypeResolutionUtils.ResolveInterfaceArray(interfaces); - } - builder.TargetType = targetType; - } - - Type proxyType = builder.BuildProxyType(); - string objectUri = (applicationName != null ? applicationName + "/" + serviceName : serviceName); - - ConstructorInfo proxyConstructor = proxyType.GetConstructor( Type.EmptyTypes ); - remoteObject = (MarshalByRefObject)proxyConstructor.Invoke( ObjectUtils.EmptyObjects ); - - RemotingServices.Marshal( remoteObject, objectUri ); - - #region Instrumentation - - if (LOG.IsEnabled(LogLevel.Debug)) - { - LOG.LogDebug(String.Format( "Target '{0}' exported as '{1}'.", targetName, objectUri )); - } - - #endregion - } - - #endregion - - #region SaoRemoteObjectProxyTypeBuilder inner class definition - - /// - /// Builds a proxy type based on to wrap a target object - /// that is intended to be remotable. - /// - /// - /// The wrapped target object is retrieved by name from the IoC container. - /// - private sealed class SaoRemoteObjectProxyTypeBuilder : RemoteObjectProxyTypeBuilder - { - #region Fields - - private static readonly MethodInfo SaoExporter_GetTargetInstance = typeof( SaoExporter ).GetMethod( "GetTarget", new Type[] { typeof( string ) } ); - - private SaoExporter _saoExporter; - - #endregion - - #region Constructor(s) / Destructor - - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The exporter to be associated with the proxy. - /// - public SaoRemoteObjectProxyTypeBuilder( SaoExporter saoExporter ) - : base( saoExporter ) - { - this._saoExporter = saoExporter; - - Name = "SaoRemoteObjectProxy"; - BaseType = typeof( BaseRemoteObject ); - } - - #endregion - - #region IProxyTypeGenerator Members - - /// - /// Generates the IL instructions that pushes - /// the target instance on which calls should be delegated to. - /// - /// The IL generator to use. - public override void PushTarget( ILGenerator il ) - { - il.Emit( OpCodes.Ldstr, this._saoExporter.EXPORTER_ID ); - il.Emit( OpCodes.Call, SaoExporter_GetTargetInstance ); - } - - #endregion - - #region Protected Methods - - /// - /// Implements constructors for the proxy class. - /// - /// - /// The to use. - /// - protected override void ImplementConstructors( TypeBuilder builder ) - { - MethodAttributes attributes = MethodAttributes.Public | - MethodAttributes.HideBySig | MethodAttributes.SpecialName | - MethodAttributes.RTSpecialName; - ConstructorBuilder cb = builder.DefineConstructor( attributes, - CallingConventions.Standard, Type.EmptyTypes ); - - ILGenerator il = cb.GetILGenerator(); - GenerateRemoteObjectLifetimeInitialization( il ); - il.Emit( OpCodes.Ret ); - } - - /// - /// Deaclares a field that holds the target object instance. - /// - /// - /// The builder to use for code generation. - /// - protected override void DeclareTargetInstanceField( TypeBuilder builder ) - { - } - - #endregion } #endregion } + + #endregion } diff --git a/src/Spring/Spring.Services/Remoting/SaoFactoryObject.cs b/src/Spring/Spring.Services/Remoting/SaoFactoryObject.cs index c85fc3ab..0b7c09d9 100644 --- a/src/Spring/Spring.Services/Remoting/SaoFactoryObject.cs +++ b/src/Spring/Spring.Services/Remoting/SaoFactoryObject.cs @@ -20,116 +20,115 @@ using Spring.Objects.Factory; -namespace Spring.Remoting +namespace Spring.Remoting; + +/// +/// Factory for creating a reference to a +/// remote server activated object (SAO). +/// +/// +/// This is useful alternative to adminstrative type registration on +/// the client when you would like the client to have only +/// a reference to the interface that an SAO implements and not the +/// actual SAO implentation. +/// +/// Aleksandar Seovic +/// Mark Pollack +/// Bruno Baia +public class SaoFactoryObject : IFactoryObject, IInitializingObject { + #region Fields + + private Type serviceInterface; + private string serviceUrl; + + #endregion + + #region Properties + /// - /// Factory for creating a reference to a - /// remote server activated object (SAO). + /// The remote service interface. /// - /// - /// This is useful alternative to adminstrative type registration on - /// the client when you would like the client to have only - /// a reference to the interface that an SAO implements and not the - /// actual SAO implentation. - /// - /// Aleksandar Seovic - /// Mark Pollack - /// Bruno Baia - public class SaoFactoryObject : IFactoryObject, IInitializingObject + public Type ServiceInterface { - #region Fields - - private Type serviceInterface; - private string serviceUrl; - - #endregion - - #region Properties - - /// - /// The remote service interface. - /// - public Type ServiceInterface - { - get { return serviceInterface; } - set { serviceInterface = value; } - } - - /// - /// The URI of the well known object - /// - public string ServiceUrl - { - get { return serviceUrl; } - set { serviceUrl = value; } - } - - #endregion - - #region Constructor(s) / Destructor - - /// - /// Creates a new instance of the SaoFactoryObject class. - /// - public SaoFactoryObject() - { - } - - #endregion - - #region IInitializingObject Members - - /// - /// Callback method called once all factory properties have been set. - /// - /// if an error occured - public void AfterPropertiesSet() - { - if (ServiceUrl == null) - { - throw new ArgumentException("The ServiceUrl property is required."); - } - - if (ServiceInterface == null) - { - throw new ArgumentException("The ServiceInterface property is required."); - } - - if (!ServiceInterface.IsInterface) - { - throw new ArgumentException("ServiceInterface must be an interface"); - } - } - - #endregion - - #region IFactoryObject Members - - /// - /// Is the object managed by this factory a singleton or a prototype? - /// - public bool IsSingleton - { - get { return false; } - } - - /// - /// The type of object to be created. - /// - public Type ObjectType - { - get { return serviceInterface; } - } - - /// - /// Return the SAO proxy. - /// - /// the SAO proxy - public object GetObject() - { - return Activator.GetObject(serviceInterface, serviceUrl); - } - - #endregion + get { return serviceInterface; } + set { serviceInterface = value; } } -} + + /// + /// The URI of the well known object + /// + public string ServiceUrl + { + get { return serviceUrl; } + set { serviceUrl = value; } + } + + #endregion + + #region Constructor(s) / Destructor + + /// + /// Creates a new instance of the SaoFactoryObject class. + /// + public SaoFactoryObject() + { + } + + #endregion + + #region IInitializingObject Members + + /// + /// Callback method called once all factory properties have been set. + /// + /// if an error occured + public void AfterPropertiesSet() + { + if (ServiceUrl == null) + { + throw new ArgumentException("The ServiceUrl property is required."); + } + + if (ServiceInterface == null) + { + throw new ArgumentException("The ServiceInterface property is required."); + } + + if (!ServiceInterface.IsInterface) + { + throw new ArgumentException("ServiceInterface must be an interface"); + } + } + + #endregion + + #region IFactoryObject Members + + /// + /// Is the object managed by this factory a singleton or a prototype? + /// + public bool IsSingleton + { + get { return false; } + } + + /// + /// The type of object to be created. + /// + public Type ObjectType + { + get { return serviceInterface; } + } + + /// + /// Return the SAO proxy. + /// + /// the SAO proxy + public object GetObject() + { + return Activator.GetObject(serviceInterface, serviceUrl); + } + + #endregion +} \ No newline at end of file diff --git a/src/Spring/Spring.Services/Remoting/Support/BaseRemoteObject.cs b/src/Spring/Spring.Services/Remoting/Support/BaseRemoteObject.cs index f7580c93..5372dc82 100644 --- a/src/Spring/Spring.Services/Remoting/Support/BaseRemoteObject.cs +++ b/src/Spring/Spring.Services/Remoting/Support/BaseRemoteObject.cs @@ -20,139 +20,141 @@ using System.Runtime.Remoting.Lifetime; -namespace Spring.Remoting.Support +namespace Spring.Remoting.Support; + +/// +/// This class extends to allow users +/// to define object lifecycle details by simply setting its properties. +/// +/// +///

+/// Remoting exporters uses this class as a base proxy class +/// in order to support lifecycle configuration when exporting +/// a remote object. +///

+///
+/// Aleksandar Seovic +public abstract class BaseRemoteObject : MarshalByRefObject { + #region Fields + + private bool isInfinite = false; + private TimeSpan initialLeaseTime = TimeSpan.Zero; + private TimeSpan renewOnCallTime = TimeSpan.Zero; + private TimeSpan sponsorshipTimeout = TimeSpan.Zero; + + #endregion + + #region Constructor(s) / Destructor + /// - /// This class extends to allow users - /// to define object lifecycle details by simply setting its properties. + /// Initializes a new instance of the class. + /// + public BaseRemoteObject() + { + } + + #endregion + + #region Properties + + /// + /// Gets or sets a value indicating whether this instance has infinite lifetime. + /// + /// + /// if this instance has infinite lifetime; + /// otherwise, . + /// + public bool IsInfinite + { + get { return isInfinite; } + set { isInfinite = value; } + } + + /// + /// Gets or sets the initial lease time. + /// + /// The initial lease time. + public TimeSpan InitialLeaseTime + { + get { return initialLeaseTime; } + set { initialLeaseTime = value; } + } + + /// + /// Gets or sets the amount of time lease should be + /// extended for on each call to this object. + /// + /// The amount of time lease should be + /// extended for on each call to this object. + public TimeSpan RenewOnCallTime + { + get { return renewOnCallTime; } + set { renewOnCallTime = value; } + } + + /// + /// Gets or sets the amount of time lease manager will for this object's + /// sponsors to respond. + /// + /// The amount of time lease manager will for this object's + /// sponsors to respond. + public TimeSpan SponsorshipTimeout + { + get { return sponsorshipTimeout; } + set { sponsorshipTimeout = value; } + } + + #endregion + + #region Methods + + /// + /// Obtains a lifetime service object to control the lifetime policy for this instance. /// /// ///

- /// Remoting exporters uses this class as a base proxy class - /// in order to support lifecycle configuration when exporting - /// a remote object. + /// This method uses property values to configure for this object. + ///

+ ///

+ /// It is very much inspired by Ingo Rammer's example in Chapter 6 of "Advanced .NET Remoting", + /// but is modified slightly to make it more "Spring-friendly". Basically, the main difference is that + /// instead of pulling lease configuration from the .NET config file, this implementation relies + /// on Spring DI to get appropriate values injected, which makes it much more flexible. ///

///
- /// Aleksandar Seovic - public abstract class BaseRemoteObject : MarshalByRefObject + /// + /// An object of type used to control the + /// lifetime policy for this instance. This is the current lifetime service object for + /// this instance if one exists; otherwise, a new lifetime service object initialized to the value + /// of the property. + /// + /// The immediate caller does not have infrastructure permission. + public override object InitializeLifetimeService() { - #region Fields - - private bool isInfinite = false; - private TimeSpan initialLeaseTime = TimeSpan.Zero; - private TimeSpan renewOnCallTime = TimeSpan.Zero; - private TimeSpan sponsorshipTimeout = TimeSpan.Zero; - - #endregion - - #region Constructor(s) / Destructor - - /// - /// Initializes a new instance of the class. - /// - public BaseRemoteObject() - {} - - #endregion - - #region Properties - - /// - /// Gets or sets a value indicating whether this instance has infinite lifetime. - /// - /// - /// if this instance has infinite lifetime; - /// otherwise, . - /// - public bool IsInfinite + if (this.isInfinite) { - get { return isInfinite; } - set { isInfinite = value; } + return null; } - /// - /// Gets or sets the initial lease time. - /// - /// The initial lease time. - public TimeSpan InitialLeaseTime + ILease lease = (ILease) base.InitializeLifetimeService(); + if (this.initialLeaseTime != TimeSpan.Zero) { - get { return initialLeaseTime; } - set { initialLeaseTime = value; } + lease.InitialLeaseTime = this.initialLeaseTime; } - /// - /// Gets or sets the amount of time lease should be - /// extended for on each call to this object. - /// - /// The amount of time lease should be - /// extended for on each call to this object. - public TimeSpan RenewOnCallTime + if (this.renewOnCallTime != TimeSpan.Zero) { - get { return renewOnCallTime; } - set { renewOnCallTime = value; } + lease.RenewOnCallTime = this.renewOnCallTime; } - /// - /// Gets or sets the amount of time lease manager will for this object's - /// sponsors to respond. - /// - /// The amount of time lease manager will for this object's - /// sponsors to respond. - public TimeSpan SponsorshipTimeout + if (this.sponsorshipTimeout != TimeSpan.Zero) { - get { return sponsorshipTimeout; } - set { sponsorshipTimeout = value; } + lease.SponsorshipTimeout = this.sponsorshipTimeout; } - #endregion - - #region Methods - - /// - /// Obtains a lifetime service object to control the lifetime policy for this instance. - /// - /// - ///

- /// This method uses property values to configure for this object. - ///

- ///

- /// It is very much inspired by Ingo Rammer's example in Chapter 6 of "Advanced .NET Remoting", - /// but is modified slightly to make it more "Spring-friendly". Basically, the main difference is that - /// instead of pulling lease configuration from the .NET config file, this implementation relies - /// on Spring DI to get appropriate values injected, which makes it much more flexible. - ///

- ///
- /// - /// An object of type used to control the - /// lifetime policy for this instance. This is the current lifetime service object for - /// this instance if one exists; otherwise, a new lifetime service object initialized to the value - /// of the property. - /// - /// The immediate caller does not have infrastructure permission. - public override object InitializeLifetimeService() - { - if (this.isInfinite) - { - return null; - } - - ILease lease = (ILease) base.InitializeLifetimeService(); - if (this.initialLeaseTime != TimeSpan.Zero) - { - lease.InitialLeaseTime = this.initialLeaseTime; - } - if (this.renewOnCallTime != TimeSpan.Zero) - { - lease.RenewOnCallTime = this.renewOnCallTime; - } - if (this.sponsorshipTimeout != TimeSpan.Zero) - { - lease.SponsorshipTimeout = this.sponsorshipTimeout; - } - - return lease; - } - - #endregion + return lease; } + + #endregion } diff --git a/src/Spring/Spring.Services/Remoting/Support/ConfigurableLifetime.cs b/src/Spring/Spring.Services/Remoting/Support/ConfigurableLifetime.cs index 7d4aff89..51e0fc67 100644 --- a/src/Spring/Spring.Services/Remoting/Support/ConfigurableLifetime.cs +++ b/src/Spring/Spring.Services/Remoting/Support/ConfigurableLifetime.cs @@ -18,71 +18,70 @@ #endregion -namespace Spring.Remoting.Support +namespace Spring.Remoting.Support; + +/// +/// Configurable implementation of the interface. +/// +/// Bruno Baia +public class ConfigurableLifetime : ILifetime { + #region Fields + + private bool infinite = true; + private TimeSpan initialLeaseTime = TimeSpan.Zero; + private TimeSpan renewOnCallTime = TimeSpan.Zero; + private TimeSpan sponsorshipTimeout = TimeSpan.Zero; + + #endregion + + #region ILifetime Members + /// - /// Configurable implementation of the interface. + /// Gets or sets a value indicating whether this instance has infinite lifetime. /// - /// Bruno Baia - public class ConfigurableLifetime : ILifetime + /// + /// true if this instance has infinite lifetime; otherwise, false. + /// + public bool Infinite { - #region Fields - - private bool infinite = true; - private TimeSpan initialLeaseTime = TimeSpan.Zero; - private TimeSpan renewOnCallTime = TimeSpan.Zero; - private TimeSpan sponsorshipTimeout = TimeSpan.Zero; - - #endregion - - #region ILifetime Members - - /// - /// Gets or sets a value indicating whether this instance has infinite lifetime. - /// - /// - /// true if this instance has infinite lifetime; otherwise, false. - /// - public bool Infinite - { - get { return infinite; } - set { infinite = value; } - } - - /// - /// Gets or sets the initial lease time. - /// - /// The initial lease time. - public TimeSpan InitialLeaseTime - { - get { return initialLeaseTime; } - set { initialLeaseTime = value; } - } - - /// - /// Gets or sets the amount of time lease - /// should be extended for on each call to this object. - /// - /// The amount of time lease should be - /// extended for on each call to this object. - public TimeSpan RenewOnCallTime - { - get { return renewOnCallTime; } - set { renewOnCallTime = value; } - } - - /// - /// Gets or sets the amount of time lease manager - /// will for this object's sponsors to respond. - /// - /// The amount of time lease manager will for this object's - /// sponsors to respond. - public TimeSpan SponsorshipTimeout - { - get { return sponsorshipTimeout; } - set { sponsorshipTimeout = value; } - } - - #endregion + get { return infinite; } + set { infinite = value; } } + + /// + /// Gets or sets the initial lease time. + /// + /// The initial lease time. + public TimeSpan InitialLeaseTime + { + get { return initialLeaseTime; } + set { initialLeaseTime = value; } + } + + /// + /// Gets or sets the amount of time lease + /// should be extended for on each call to this object. + /// + /// The amount of time lease should be + /// extended for on each call to this object. + public TimeSpan RenewOnCallTime + { + get { return renewOnCallTime; } + set { renewOnCallTime = value; } + } + + /// + /// Gets or sets the amount of time lease manager + /// will for this object's sponsors to respond. + /// + /// The amount of time lease manager will for this object's + /// sponsors to respond. + public TimeSpan SponsorshipTimeout + { + get { return sponsorshipTimeout; } + set { sponsorshipTimeout = value; } + } + + #endregion } diff --git a/src/Spring/Spring.Services/Remoting/Support/ICaoRemoteFactory.cs b/src/Spring/Spring.Services/Remoting/Support/ICaoRemoteFactory.cs index 4e31db74..f0d6f373 100644 --- a/src/Spring/Spring.Services/Remoting/Support/ICaoRemoteFactory.cs +++ b/src/Spring/Spring.Services/Remoting/Support/ICaoRemoteFactory.cs @@ -18,40 +18,39 @@ #endregion -namespace Spring.Remoting.Support -{ - /// - /// Interface for a CAO based object factory. - /// - /// - ///

- /// Provides a well known location for clients to retrieve - /// references to CAO references. - ///

- ///
- /// Aleksandar Seovic - /// Mark Pollack - /// Bruno Baia - public interface ICaoRemoteFactory - { - /// - /// Returns the CAO proxy. - /// - /// The remote object. - object GetObject(); +namespace Spring.Remoting.Support; - /// - /// Returns the CAO proxy using the - /// argument list to call the constructor. - /// - /// - /// The matching of arguments to call the constructor is done - /// by type. The alternative ways, by index and by constructor - /// name are not supported. - /// - /// Constructor - /// arguments used to create the object. - /// The remote object. - object GetObject(object[] constructorArguments); - } +/// +/// Interface for a CAO based object factory. +/// +/// +///

+/// Provides a well known location for clients to retrieve +/// references to CAO references. +///

+///
+/// Aleksandar Seovic +/// Mark Pollack +/// Bruno Baia +public interface ICaoRemoteFactory +{ + /// + /// Returns the CAO proxy. + /// + /// The remote object. + object GetObject(); + + /// + /// Returns the CAO proxy using the + /// argument list to call the constructor. + /// + /// + /// The matching of arguments to call the constructor is done + /// by type. The alternative ways, by index and by constructor + /// name are not supported. + /// + /// Constructor + /// arguments used to create the object. + /// The remote object. + object GetObject(object[] constructorArguments); } diff --git a/src/Spring/Spring.Services/Remoting/Support/ILifetime.cs b/src/Spring/Spring.Services/Remoting/Support/ILifetime.cs index 5d1b0b20..f7414ac4 100644 --- a/src/Spring/Spring.Services/Remoting/Support/ILifetime.cs +++ b/src/Spring/Spring.Services/Remoting/Support/ILifetime.cs @@ -18,42 +18,41 @@ #endregion -namespace Spring.Remoting.Support +namespace Spring.Remoting.Support; + +/// +/// Defines lifetime's properties of remote objects that is used by Spring. +/// +/// Bruno Baia +public interface ILifetime { /// - /// Defines lifetime's properties of remote objects that is used by Spring. + /// Gets or sets a value indicating whether this instance has infinite lifetime. /// - /// Bruno Baia - public interface ILifetime - { - /// - /// Gets or sets a value indicating whether this instance has infinite lifetime. - /// - /// - /// true if this instance has infinite lifetime; otherwise, false. - /// - bool Infinite { get; } + /// + /// true if this instance has infinite lifetime; otherwise, false. + /// + bool Infinite { get; } - /// - /// Gets the initial lease time. - /// - /// The initial lease time. - TimeSpan InitialLeaseTime { get; } + /// + /// Gets the initial lease time. + /// + /// The initial lease time. + TimeSpan InitialLeaseTime { get; } - /// - /// Gets the amount of time lease - /// should be extended for on each call to this object. - /// - /// The amount of time lease should be - /// extended for on each call to this object. - TimeSpan RenewOnCallTime { get; } + /// + /// Gets the amount of time lease + /// should be extended for on each call to this object. + /// + /// The amount of time lease should be + /// extended for on each call to this object. + TimeSpan RenewOnCallTime { get; } - /// - /// Gets the amount of time lease manager - /// will for this object's sponsors to respond. - /// - /// The amount of time lease manager will for this object's - /// sponsors to respond. - TimeSpan SponsorshipTimeout { get; } - } + /// + /// Gets the amount of time lease manager + /// will for this object's sponsors to respond. + /// + /// The amount of time lease manager will for this object's + /// sponsors to respond. + TimeSpan SponsorshipTimeout { get; } } diff --git a/src/Spring/Spring.Services/Remoting/Support/RemoteObjectProxyTypeBuilder.cs b/src/Spring/Spring.Services/Remoting/Support/RemoteObjectProxyTypeBuilder.cs index dd7b697e..327f25d3 100644 --- a/src/Spring/Spring.Services/Remoting/Support/RemoteObjectProxyTypeBuilder.cs +++ b/src/Spring/Spring.Services/Remoting/Support/RemoteObjectProxyTypeBuilder.cs @@ -20,152 +20,150 @@ using System.Reflection; using System.Reflection.Emit; - using Spring.Proxy; -namespace Spring.Remoting.Support +namespace Spring.Remoting.Support; + +/// +/// Builds a proxy type based on to wrap a target object +/// that is intended to be remotable. +/// +/// Bruno Baia +internal class RemoteObjectProxyTypeBuilder : CompositionProxyTypeBuilder { + #region Fields + + private static readonly MethodInfo TimeSpan_FromTicks = + typeof(TimeSpan).GetMethod("FromTicks", BindingFlags.Public | BindingFlags.Static); + + private static readonly MethodInfo BaseRemoteObject_IsInfinite = + typeof(BaseRemoteObject).GetMethod("set_IsInfinite", BindingFlags.Public | BindingFlags.Instance); + + private static readonly MethodInfo BaseRemoteObject_InitialLeaseTime = + typeof(BaseRemoteObject).GetMethod("set_InitialLeaseTime", BindingFlags.Public | BindingFlags.Instance); + + private static readonly MethodInfo BaseRemoteObject_RenewOnCallTime = + typeof(BaseRemoteObject).GetMethod("set_RenewOnCallTime", BindingFlags.Public | BindingFlags.Instance); + + private static readonly MethodInfo BaseRemoteObject_SponsorshipTimeout = + typeof(BaseRemoteObject).GetMethod("set_SponsorshipTimeout", BindingFlags.Public | BindingFlags.Instance); + + private ILifetime lifetime; + + #endregion + + #region Constructor(s) / Destructor + /// - /// Builds a proxy type based on to wrap a target object - /// that is intended to be remotable. + /// Creates a new instance of the + /// class. /// - /// Bruno Baia - internal class RemoteObjectProxyTypeBuilder : CompositionProxyTypeBuilder + /// + /// The lifetime properties to be applied to the target object. + /// + public RemoteObjectProxyTypeBuilder(ILifetime lifetime) { - #region Fields + this.lifetime = lifetime; - private static readonly MethodInfo TimeSpan_FromTicks = - typeof(TimeSpan).GetMethod("FromTicks", BindingFlags.Public | BindingFlags.Static); + Name = "RemoteObjectProxy"; + } - private static readonly MethodInfo BaseRemoteObject_IsInfinite = - typeof(BaseRemoteObject).GetMethod("set_IsInfinite", BindingFlags.Public | BindingFlags.Instance); + #endregion - private static readonly MethodInfo BaseRemoteObject_InitialLeaseTime = - typeof(BaseRemoteObject).GetMethod("set_InitialLeaseTime", BindingFlags.Public | BindingFlags.Instance); + #region IProxyTypeBuilder Members - private static readonly MethodInfo BaseRemoteObject_RenewOnCallTime = - typeof(BaseRemoteObject).GetMethod("set_RenewOnCallTime", BindingFlags.Public | BindingFlags.Instance); - - private static readonly MethodInfo BaseRemoteObject_SponsorshipTimeout = - typeof(BaseRemoteObject).GetMethod("set_SponsorshipTimeout", BindingFlags.Public | BindingFlags.Instance); - - private ILifetime lifetime; - - #endregion - - #region Constructor(s) / Destructor - - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The lifetime properties to be applied to the target object. - /// - public RemoteObjectProxyTypeBuilder(ILifetime lifetime) + /// + /// Creates a remotable proxy type based on . + /// + /// The generated proxy class. + /// + /// If the is not + /// an instance of . + /// + public override Type BuildProxyType() + { + if (!typeof(BaseRemoteObject).IsAssignableFrom(this.BaseType)) { - this.lifetime = lifetime; - - Name = "RemoteObjectProxy"; + throw new ArgumentException( + "BaseRemoteObject cannot be assigned from BaseType.", "BaseType"); } - #endregion + return base.BuildProxyType(); + } - #region IProxyTypeBuilder Members + #endregion - /// - /// Creates a remotable proxy type based on . - /// - /// The generated proxy class. - /// - /// If the is not - /// an instance of . - /// - public override Type BuildProxyType() + #region Protected Methods + + /// + /// Implements constructors for the proxy class. + /// + /// + /// The to use. + /// + protected override void ImplementConstructors(TypeBuilder builder) + { + MethodAttributes attributes = MethodAttributes.Public | + MethodAttributes.HideBySig | MethodAttributes.SpecialName | + MethodAttributes.RTSpecialName; + ConstructorBuilder cb = builder.DefineConstructor(attributes, + CallingConventions.Standard, + new Type[1] { TargetType }); + + ILGenerator il = cb.GetILGenerator(); + + GenerateRemoteObjectLifetimeInitialization(il); + + PushProxy(il); + il.Emit(OpCodes.Ldarg_1); + il.Emit(OpCodes.Stfld, targetInstance); + + il.Emit(OpCodes.Ret); + } + + /// + /// Generate initialization code for 's lifetime properties. + /// + /// ILGenerator + protected void GenerateRemoteObjectLifetimeInitialization(ILGenerator il) + { + // Set IsInfinite Property + if (this.lifetime.Infinite) { - if (!typeof(BaseRemoteObject).IsAssignableFrom(this.BaseType)) - { - throw new ArgumentException( - "BaseRemoteObject cannot be assigned from BaseType.", "BaseType"); - } - - return base.BuildProxyType(); - } - - #endregion - - #region Protected Methods - - /// - /// Implements constructors for the proxy class. - /// - /// - /// The to use. - /// - protected override void ImplementConstructors(TypeBuilder builder) - { - MethodAttributes attributes = MethodAttributes.Public | - MethodAttributes.HideBySig | MethodAttributes.SpecialName | - MethodAttributes.RTSpecialName; - ConstructorBuilder cb = builder.DefineConstructor(attributes, - CallingConventions.Standard, - new Type[1] { TargetType }); - - ILGenerator il = cb.GetILGenerator(); - - GenerateRemoteObjectLifetimeInitialization(il); - PushProxy(il); - il.Emit(OpCodes.Ldarg_1); - il.Emit(OpCodes.Stfld, targetInstance); - - il.Emit(OpCodes.Ret); + il.Emit(OpCodes.Ldc_I4_1); // true + il.Emit(OpCodes.Call, BaseRemoteObject_IsInfinite); } - - /// - /// Generate initialization code for 's lifetime properties. - /// - /// ILGenerator - protected void GenerateRemoteObjectLifetimeInitialization(ILGenerator il) + else { - // Set IsInfinite Property - if (this.lifetime.Infinite) + // Set InitialLeaseTime Property + if (this.lifetime.InitialLeaseTime != TimeSpan.Zero) { PushProxy(il); - il.Emit(OpCodes.Ldc_I4_1); // true - il.Emit(OpCodes.Call, BaseRemoteObject_IsInfinite); + il.Emit(OpCodes.Ldc_I8, this.lifetime.InitialLeaseTime.Ticks); + il.Emit(OpCodes.Call, TimeSpan_FromTicks); + il.Emit(OpCodes.Call, BaseRemoteObject_InitialLeaseTime); } - else + + // Set RenewOnCallTime Property + if (this.lifetime.RenewOnCallTime != TimeSpan.Zero) { - // Set InitialLeaseTime Property - if (this.lifetime.InitialLeaseTime != TimeSpan.Zero) - { - PushProxy(il); - il.Emit(OpCodes.Ldc_I8, this.lifetime.InitialLeaseTime.Ticks); - il.Emit(OpCodes.Call, TimeSpan_FromTicks); - il.Emit(OpCodes.Call, BaseRemoteObject_InitialLeaseTime); - } + PushProxy(il); + il.Emit(OpCodes.Ldc_I8, this.lifetime.RenewOnCallTime.Ticks); + il.Emit(OpCodes.Call, TimeSpan_FromTicks); + il.Emit(OpCodes.Call, BaseRemoteObject_RenewOnCallTime); + } - // Set RenewOnCallTime Property - if (this.lifetime.RenewOnCallTime != TimeSpan.Zero) - { - PushProxy(il); - il.Emit(OpCodes.Ldc_I8, this.lifetime.RenewOnCallTime.Ticks); - il.Emit(OpCodes.Call, TimeSpan_FromTicks); - il.Emit(OpCodes.Call, BaseRemoteObject_RenewOnCallTime); - } - - // Set SponsorshipTimeout Property - if (this.lifetime.SponsorshipTimeout != TimeSpan.Zero) - { - PushProxy(il); - il.Emit(OpCodes.Ldc_I8, this.lifetime.SponsorshipTimeout.Ticks); - il.Emit(OpCodes.Call, TimeSpan_FromTicks); - il.Emit(OpCodes.Call, BaseRemoteObject_SponsorshipTimeout); - } + // Set SponsorshipTimeout Property + if (this.lifetime.SponsorshipTimeout != TimeSpan.Zero) + { + PushProxy(il); + il.Emit(OpCodes.Ldc_I8, this.lifetime.SponsorshipTimeout.Ticks); + il.Emit(OpCodes.Call, TimeSpan_FromTicks); + il.Emit(OpCodes.Call, BaseRemoteObject_SponsorshipTimeout); } } - - #endregion } + + #endregion } diff --git a/src/Spring/Spring.Services/ServiceModel/Activation/ServiceHostFactory.cs b/src/Spring/Spring.Services/ServiceModel/Activation/ServiceHostFactory.cs index 746871d6..1794361b 100644 --- a/src/Spring/Spring.Services/ServiceModel/Activation/ServiceHostFactory.cs +++ b/src/Spring/Spring.Services/ServiceModel/Activation/ServiceHostFactory.cs @@ -19,51 +19,49 @@ #endregion using System.ServiceModel; - using Spring.Util; using Spring.Context.Support; using Spring.Context; -namespace Spring.ServiceModel.Activation +namespace Spring.ServiceModel.Activation; + +/// +/// Factory that provides instances of +/// to host objects created by Spring's IoC container. +/// +/// Bruno Baia +public class ServiceHostFactory : System.ServiceModel.Activation.ServiceHostFactory { /// - /// Factory that provides instances of - /// to host objects created by Spring's IoC container. + /// Creates a for + /// a specified Spring-managed object with a specific base address. /// - /// Bruno Baia - public class ServiceHostFactory : System.ServiceModel.Activation.ServiceHostFactory + /// + /// A reference to a Spring-managed object or to a service type. + /// + /// + /// The of type that contains + /// the base addresses for the service hosted. + /// + /// + /// A for the Spring-managed object. + /// + /// + /// If the Service attribute in the ServiceHost directive was not provided. + /// + public override ServiceHostBase CreateServiceHost(string reference, Uri[] baseAddresses) { - /// - /// Creates a for - /// a specified Spring-managed object with a specific base address. - /// - /// - /// A reference to a Spring-managed object or to a service type. - /// - /// - /// The of type that contains - /// the base addresses for the service hosted. - /// - /// - /// A for the Spring-managed object. - /// - /// - /// If the Service attribute in the ServiceHost directive was not provided. - /// - public override ServiceHostBase CreateServiceHost(string reference, Uri[] baseAddresses) + if (StringUtils.IsNullOrEmpty(reference)) { - if (StringUtils.IsNullOrEmpty(reference)) - { - return base.CreateServiceHost(reference, baseAddresses); - } - - IApplicationContext applicationContext = ContextRegistry.GetContext(); - if (applicationContext.ContainsObject(reference)) - { - return new SpringServiceHost(reference, applicationContext, baseAddresses); - } - return base.CreateServiceHost(reference, baseAddresses); } + + IApplicationContext applicationContext = ContextRegistry.GetContext(); + if (applicationContext.ContainsObject(reference)) + { + return new SpringServiceHost(reference, applicationContext, baseAddresses); + } + + return base.CreateServiceHost(reference, baseAddresses); } -} +} \ No newline at end of file diff --git a/src/Spring/Spring.Services/ServiceModel/Activation/ServiceHostFactoryObject.cs b/src/Spring/Spring.Services/ServiceModel/Activation/ServiceHostFactoryObject.cs index 2ae2d95c..3fadf41f 100644 --- a/src/Spring/Spring.Services/ServiceModel/Activation/ServiceHostFactoryObject.cs +++ b/src/Spring/Spring.Services/ServiceModel/Activation/ServiceHostFactoryObject.cs @@ -22,205 +22,204 @@ using System.ServiceModel; using Microsoft.Extensions.Logging; using Spring.Objects.Factory; -namespace Spring.ServiceModel.Activation +namespace Spring.ServiceModel.Activation; + +/// +/// Factory that provides instances of +/// to host objects created with Spring's IoC container. +/// +/// Bruno Baia +public class ServiceHostFactoryObject : IFactoryObject, IInitializingObject, IObjectFactoryAware, IDisposable { + #region Logging + + private static readonly ILogger LOG = LogManager.GetLogger(); + + #endregion + + #region Fields + + private string _targetName; + private bool _useServiceProxyTypeCache = true; + private Uri[] _baseAddresses = new Uri[] { }; + /// - /// Factory that provides instances of - /// to host objects created with Spring's IoC container. + /// The owning factory. /// - /// Bruno Baia - public class ServiceHostFactoryObject : IFactoryObject, IInitializingObject, IObjectFactoryAware, IDisposable + private IObjectFactory objectFactory; + + /// + /// The instance managed by this factory. + /// + protected SpringServiceHost springServiceHost; + + #endregion + + #region Properties + + /// + /// Gets or sets the name of the target object that should be exposed as a service. + /// + /// + /// The name of the target object that should be exposed as a service. + /// + public string TargetName { - #region Logging + get { return _targetName; } + set { _targetName = value; } + } - private static readonly ILogger LOG = LogManager.GetLogger(); + /// + /// Gets or sets the base addresses for the hosted service. + /// + /// + /// The base addresses for the hosted service. + /// + public Uri[] BaseAddresses + { + get { return _baseAddresses; } + set { _baseAddresses = value; } + } - #endregion + /// + /// Controls, whether the underlying should cache + /// the generated proxy types. Defaults to true. + /// + public bool UseServiceProxyTypeCache + { + get { return _useServiceProxyTypeCache; } + set { _useServiceProxyTypeCache = value; } + } - #region Fields + #endregion - private string _targetName; - private bool _useServiceProxyTypeCache = true; - private Uri[] _baseAddresses = new Uri[] { }; + #region Constructor(s) / Destructor - /// - /// The owning factory. - /// - private IObjectFactory objectFactory; + /// + /// Creates a new instance of the + /// class. + /// + public ServiceHostFactoryObject() + { + } - /// - /// The instance managed by this factory. - /// - protected SpringServiceHost springServiceHost; + #endregion - #endregion + #region IObjectFactoryAware Members - #region Properties + /// + /// Callback that supplies the owning factory to an object instance. + /// + /// + /// Owning + /// (may not be ). The object can immediately + /// call methods on the factory. + /// + /// + ///

+ /// Invoked after population of normal object properties but before an init + /// callback like 's + /// + /// method or a custom init-method. + ///

+ ///
+ /// + /// In case of initialization errors. + /// + public virtual IObjectFactory ObjectFactory + { + protected get { return this.objectFactory; } + set { this.objectFactory = value; } + } - /// - /// Gets or sets the name of the target object that should be exposed as a service. - /// - /// - /// The name of the target object that should be exposed as a service. - /// - public string TargetName + #endregion + + #region IFactoryObject Members + + /// + /// Return a instance + /// managed by this factory. + /// + /// + /// An instance of + /// managed by this factory. + /// + public virtual object GetObject() + { + return springServiceHost; + } + + /// + /// Return the of object that this + /// creates. + /// + public virtual Type ObjectType + { + get { return typeof(SpringServiceHost); } + } + + /// + /// Always returns + /// + public virtual bool IsSingleton + { + get { return false; } + } + + #endregion + + #region IInitializingObject Members + + /// + /// Publish the object. + /// + public virtual void AfterPropertiesSet() + { + ValidateConfiguration(); + + springServiceHost = new SpringServiceHost(TargetName, objectFactory, UseServiceProxyTypeCache, BaseAddresses); + + springServiceHost.Open(); + + #region Instrumentation + + if (LOG.IsEnabled(LogLevel.Information)) { - get { return _targetName; } - set { _targetName = value; } - } - - /// - /// Gets or sets the base addresses for the hosted service. - /// - /// - /// The base addresses for the hosted service. - /// - public Uri[] BaseAddresses - { - get { return _baseAddresses; } - set { _baseAddresses = value; } - } - - /// - /// Controls, whether the underlying should cache - /// the generated proxy types. Defaults to true. - /// - public bool UseServiceProxyTypeCache - { - get { return _useServiceProxyTypeCache; } - set { _useServiceProxyTypeCache = value; } - } - - #endregion - - #region Constructor(s) / Destructor - - /// - /// Creates a new instance of the - /// class. - /// - public ServiceHostFactoryObject() - { - } - - #endregion - - #region IObjectFactoryAware Members - - /// - /// Callback that supplies the owning factory to an object instance. - /// - /// - /// Owning - /// (may not be ). The object can immediately - /// call methods on the factory. - /// - /// - ///

- /// Invoked after population of normal object properties but before an init - /// callback like 's - /// - /// method or a custom init-method. - ///

- ///
- /// - /// In case of initialization errors. - /// - public virtual IObjectFactory ObjectFactory - { - protected get { return this.objectFactory; } - set { this.objectFactory = value; } - } - - #endregion - - #region IFactoryObject Members - - /// - /// Return a instance - /// managed by this factory. - /// - /// - /// An instance of - /// managed by this factory. - /// - public virtual object GetObject() - { - return springServiceHost; - } - - /// - /// Return the of object that this - /// creates. - /// - public virtual Type ObjectType - { - get { return typeof(SpringServiceHost); } - } - - /// - /// Always returns - /// - public virtual bool IsSingleton - { - get { return false; } - } - - #endregion - - #region IInitializingObject Members - - /// - /// Publish the object. - /// - public virtual void AfterPropertiesSet() - { - ValidateConfiguration(); - - springServiceHost = new SpringServiceHost(TargetName, objectFactory, UseServiceProxyTypeCache, BaseAddresses); - - springServiceHost.Open(); - - #region Instrumentation - - if (LOG.IsEnabled(LogLevel.Information)) - { - LOG.LogInformation(String.Format("The service '{0}' is ready and can now be accessed.", TargetName)); - } - - #endregion - } - - #endregion - - #region IDisposable Members - - /// - /// Close the SpringServiceHost - /// - public void Dispose() - { - if (springServiceHost != null) - { - springServiceHost.Close(); - } - } - - #endregion - - #region Protected Methods - - /// - /// Validates the configuration. - /// - protected virtual void ValidateConfiguration() - { - if (TargetName == null) - { - throw new ArgumentException("The TargetName property is required."); - } + LOG.LogInformation(String.Format("The service '{0}' is ready and can now be accessed.", TargetName)); } #endregion } + + #endregion + + #region IDisposable Members + + /// + /// Close the SpringServiceHost + /// + public void Dispose() + { + if (springServiceHost != null) + { + springServiceHost.Close(); + } + } + + #endregion + + #region Protected Methods + + /// + /// Validates the configuration. + /// + protected virtual void ValidateConfiguration() + { + if (TargetName == null) + { + throw new ArgumentException("The TargetName property is required."); + } + } + + #endregion } diff --git a/src/Spring/Spring.Services/ServiceModel/Activation/WebServiceHostFactory.cs b/src/Spring/Spring.Services/ServiceModel/Activation/WebServiceHostFactory.cs index 4e6fe1f1..8348c9c4 100644 --- a/src/Spring/Spring.Services/ServiceModel/Activation/WebServiceHostFactory.cs +++ b/src/Spring/Spring.Services/ServiceModel/Activation/WebServiceHostFactory.cs @@ -19,51 +19,49 @@ #endregion using System.ServiceModel; - using Spring.Util; using Spring.Context.Support; using Spring.Context; -namespace Spring.ServiceModel.Activation +namespace Spring.ServiceModel.Activation; + +/// +/// Factory that provides instances of +/// to host objects created by Spring's IoC container. +/// +/// Steve Bohlen +public class WebServiceHostFactory : System.ServiceModel.Activation.WebServiceHostFactory { /// - /// Factory that provides instances of - /// to host objects created by Spring's IoC container. + /// Creates a for + /// a specified Spring-managed object with a specific base address. /// - /// Steve Bohlen - public class WebServiceHostFactory : System.ServiceModel.Activation.WebServiceHostFactory + /// + /// A reference to a Spring-managed object or to a service type. + /// + /// + /// The of type that contains + /// the base addresses for the service hosted. + /// + /// + /// A for the Spring-managed object. + /// + /// + /// If the Service attribute in the ServiceHost directive was not provided. + /// + public override ServiceHostBase CreateServiceHost(string reference, Uri[] baseAddresses) { - /// - /// Creates a for - /// a specified Spring-managed object with a specific base address. - /// - /// - /// A reference to a Spring-managed object or to a service type. - /// - /// - /// The of type that contains - /// the base addresses for the service hosted. - /// - /// - /// A for the Spring-managed object. - /// - /// - /// If the Service attribute in the ServiceHost directive was not provided. - /// - public override ServiceHostBase CreateServiceHost(string reference, Uri[] baseAddresses) + if (StringUtils.IsNullOrEmpty(reference)) { - if (StringUtils.IsNullOrEmpty(reference)) - { - return base.CreateServiceHost(reference, baseAddresses); - } - - IApplicationContext applicationContext = ContextRegistry.GetContext(); - if (applicationContext.ContainsObject(reference)) - { - return new SpringWebServiceHost(reference, applicationContext, baseAddresses); - } - return base.CreateServiceHost(reference, baseAddresses); } + + IApplicationContext applicationContext = ContextRegistry.GetContext(); + if (applicationContext.ContainsObject(reference)) + { + return new SpringWebServiceHost(reference, applicationContext, baseAddresses); + } + + return base.CreateServiceHost(reference, baseAddresses); } } diff --git a/src/Spring/Spring.Services/ServiceModel/ChannelFactoryObject.cs b/src/Spring/Spring.Services/ServiceModel/ChannelFactoryObject.cs index 365e79a7..8dc19631 100644 --- a/src/Spring/Spring.Services/ServiceModel/ChannelFactoryObject.cs +++ b/src/Spring/Spring.Services/ServiceModel/ChannelFactoryObject.cs @@ -22,92 +22,91 @@ using System.ServiceModel; using Microsoft.Extensions.Logging; using Spring.Objects.Factory; -namespace Spring.ServiceModel +namespace Spring.ServiceModel; + +/// +/// that creates a channel that is used by clients +/// to send messages to a specified endpoint address. +/// +/// The type of channel produced by the channel factory. +/// Bruno Baia +public class ChannelFactoryObject : ChannelFactory, IFactoryObject { + #region Logging + + private static readonly ILogger Log = LogManager.GetLogger(typeof(ChannelFactoryObject<>)); + + #endregion + + private bool _isSingleton = true; + private string _endpointConfigurationName; + /// - /// that creates a channel that is used by clients - /// to send messages to a specified endpoint address. + /// Creates a new instance of the class. /// - /// The type of channel produced by the channel factory. - /// Bruno Baia - public class ChannelFactoryObject : ChannelFactory, IFactoryObject + /// + /// The configuration name used for the endpoint. + /// + public ChannelFactoryObject(string endpointConfigurationName) + : base(endpointConfigurationName) { - #region Logging - - private static readonly ILogger Log = LogManager.GetLogger(typeof(ChannelFactoryObject<>)); - - #endregion - - private bool _isSingleton = true; - private string _endpointConfigurationName; - - /// - /// Creates a new instance of the class. - /// - /// - /// The configuration name used for the endpoint. - /// - public ChannelFactoryObject(string endpointConfigurationName) - : base(endpointConfigurationName) - { - this._endpointConfigurationName = endpointConfigurationName; - } - - /// - /// Gets the configuration name used for the endpoint. - /// - public string EndpointConfigurationName - { - get { return this._endpointConfigurationName; } - } - - #region IFactoryObject Membres - - /// - /// Return an instance (possibly shared or independent) of the channel - /// managed by this factory. - /// - /// - /// An instance (possibly shared or independent) of the channel managed by - /// this factory. - /// - public object GetObject() - { - #region Instrumentation - - if (Log.IsEnabled(LogLevel.Debug)) - { - Log.LogDebug(String.Format( - "Creating channel of type '{0}' for the specified endpoint '{1}'...", - typeof(T).FullName, this._endpointConfigurationName)); - } - - #endregion - - return this.CreateChannel(); - } - - /// - /// Return the of channel that this - /// creates. - /// - public Type ObjectType - { - get { return typeof(T); } - } - - /// - /// Is the object managed by this factory a singleton or a prototype ? - /// - /// - /// Default value is . - /// - public bool IsSingleton - { - get { return this._isSingleton; } - set { this._isSingleton = value; } - } - - #endregion + this._endpointConfigurationName = endpointConfigurationName; } -} + + /// + /// Gets the configuration name used for the endpoint. + /// + public string EndpointConfigurationName + { + get { return this._endpointConfigurationName; } + } + + #region IFactoryObject Membres + + /// + /// Return an instance (possibly shared or independent) of the channel + /// managed by this factory. + /// + /// + /// An instance (possibly shared or independent) of the channel managed by + /// this factory. + /// + public object GetObject() + { + #region Instrumentation + + if (Log.IsEnabled(LogLevel.Debug)) + { + Log.LogDebug(String.Format( + "Creating channel of type '{0}' for the specified endpoint '{1}'...", + typeof(T).FullName, this._endpointConfigurationName)); + } + + #endregion + + return this.CreateChannel(); + } + + /// + /// Return the of channel that this + /// creates. + /// + public Type ObjectType + { + get { return typeof(T); } + } + + /// + /// Is the object managed by this factory a singleton or a prototype ? + /// + /// + /// Default value is . + /// + public bool IsSingleton + { + get { return this._isSingleton; } + set { this._isSingleton = value; } + } + + #endregion +} \ No newline at end of file diff --git a/src/Spring/Spring.Services/ServiceModel/Config/ChannelFactoryObjectDefinitionParser.cs b/src/Spring/Spring.Services/ServiceModel/Config/ChannelFactoryObjectDefinitionParser.cs index 3287ec0b..e375bc02 100644 --- a/src/Spring/Spring.Services/ServiceModel/Config/ChannelFactoryObjectDefinitionParser.cs +++ b/src/Spring/Spring.Services/ServiceModel/Config/ChannelFactoryObjectDefinitionParser.cs @@ -19,7 +19,6 @@ #endregion using System.Xml; - using Spring.Util; using Spring.Objects.Factory.Xml; using Spring.Objects.Factory.Config; @@ -27,75 +26,74 @@ using Spring.Objects.Factory.Support; using Spring.Core.TypeResolution; using Spring.Objects; -namespace Spring.ServiceModel.Config +namespace Spring.ServiceModel.Config; + +/// +/// The for the <wcf:channelFactory> tag. +/// +/// Bruno Baia +public class ChannelFactoryObjectDefinitionParser : ObjectsNamespaceParser, IObjectDefinitionParser { + private static readonly string ChannelTypeAttribute = "channelType"; + private static readonly string EndpointConfigurationNameAttribute = "endpointConfigurationName"; + + #region IObjectDefinitionParser Members + /// - /// The for the <wcf:channelFactory> tag. + /// Parse the specified XmlElement and register the resulting + /// ObjectDefinitions with the IObjectDefinitionRegistry + /// embedded in the supplied /// - /// Bruno Baia - public class ChannelFactoryObjectDefinitionParser : ObjectsNamespaceParser, IObjectDefinitionParser + /// The element to be parsed. + /// The object encapsulating the current state of the parsing process. + /// Provides access to a IObjectDefinitionRegistry + /// The primary object definition. + /// + ///

+ /// This method is never invoked if the parser is namespace aware + /// and was called to process the root node. + ///

+ ///
+ IObjectDefinition IObjectDefinitionParser.ParseElement(XmlElement element, ParserContext parserContext) { - private static readonly string ChannelTypeAttribute = "channelType"; - private static readonly string EndpointConfigurationNameAttribute = "endpointConfigurationName"; + AssertUtils.ArgumentNotNull(parserContext, "parserContext"); - #region IObjectDefinitionParser Members + string id = element.GetAttribute(ObjectDefinitionConstants.IdAttribute); + string unresolvedChannelType = element.GetAttribute(ChannelTypeAttribute); + string endpointConfigurationName = element.GetAttribute(EndpointConfigurationNameAttribute); - /// - /// Parse the specified XmlElement and register the resulting - /// ObjectDefinitions with the IObjectDefinitionRegistry - /// embedded in the supplied - /// - /// The element to be parsed. - /// The object encapsulating the current state of the parsing process. - /// Provides access to a IObjectDefinitionRegistry - /// The primary object definition. - /// - ///

- /// This method is never invoked if the parser is namespace aware - /// and was called to process the root node. - ///

- ///
- IObjectDefinition IObjectDefinitionParser.ParseElement(XmlElement element, ParserContext parserContext) + IObjectDefinition channelFactoryDefinition; + try { - AssertUtils.ArgumentNotNull(parserContext, "parserContext"); - - string id = element.GetAttribute(ObjectDefinitionConstants.IdAttribute); - string unresolvedChannelType = element.GetAttribute(ChannelTypeAttribute); - string endpointConfigurationName = element.GetAttribute(EndpointConfigurationNameAttribute); - - IObjectDefinition channelFactoryDefinition; - try - { - Type channelType = TypeResolutionUtils.ResolveType(unresolvedChannelType); - Type channelFactoryType = typeof(ChannelFactoryObject<>).MakeGenericType(new Type[1] { channelType }); - channelFactoryDefinition = new RootObjectDefinition(channelFactoryType); - } - catch - { - // Try to resolve type later (Can be a type alias) - channelFactoryDefinition = new RootObjectDefinition( - String.Format("Spring.ServiceModel.ChannelFactoryObject<{0}>, Spring.Services", unresolvedChannelType), - new ConstructorArgumentValues(), - new MutablePropertyValues()); - } - - if (!StringUtils.HasText(id)) - { - id = parserContext.ReaderContext.GenerateObjectName(channelFactoryDefinition); - } - - channelFactoryDefinition.ConstructorArgumentValues.AddNamedArgumentValue("endpointConfigurationName", endpointConfigurationName); - - foreach (PropertyValue pv in base.ParsePropertyElements(id, element, parserContext)) - { - channelFactoryDefinition.PropertyValues.Add(pv); - } - - parserContext.Registry.RegisterObjectDefinition(id, channelFactoryDefinition); - - return null; + Type channelType = TypeResolutionUtils.ResolveType(unresolvedChannelType); + Type channelFactoryType = typeof(ChannelFactoryObject<>).MakeGenericType(new Type[1] { channelType }); + channelFactoryDefinition = new RootObjectDefinition(channelFactoryType); + } + catch + { + // Try to resolve type later (Can be a type alias) + channelFactoryDefinition = new RootObjectDefinition( + String.Format("Spring.ServiceModel.ChannelFactoryObject<{0}>, Spring.Services", unresolvedChannelType), + new ConstructorArgumentValues(), + new MutablePropertyValues()); } - #endregion + if (!StringUtils.HasText(id)) + { + id = parserContext.ReaderContext.GenerateObjectName(channelFactoryDefinition); + } + + channelFactoryDefinition.ConstructorArgumentValues.AddNamedArgumentValue("endpointConfigurationName", endpointConfigurationName); + + foreach (PropertyValue pv in base.ParsePropertyElements(id, element, parserContext)) + { + channelFactoryDefinition.PropertyValues.Add(pv); + } + + parserContext.Registry.RegisterObjectDefinition(id, channelFactoryDefinition); + + return null; } + + #endregion } diff --git a/src/Spring/Spring.Services/ServiceModel/Config/WcfNamespaceParser.cs b/src/Spring/Spring.Services/ServiceModel/Config/WcfNamespaceParser.cs index 4aa163a3..bc5c4345 100644 --- a/src/Spring/Spring.Services/ServiceModel/Config/WcfNamespaceParser.cs +++ b/src/Spring/Spring.Services/ServiceModel/Config/WcfNamespaceParser.cs @@ -20,30 +20,29 @@ using Spring.Objects.Factory.Xml; -namespace Spring.ServiceModel.Config -{ - /// - /// Namespace parser for the WCF namespace. - /// - /// Bruno Baia - [ - NamespaceParser( - Namespace = "http://www.springframework.net/wcf", - SchemaLocationAssemblyHint = typeof(WcfNamespaceParser), - SchemaLocation = "/Spring.ServiceModel.Config/spring-wcf-1.3.xsd") - ] - public sealed class WcfNamespaceParser : NamespaceParserSupport - { - private const string ChannelFactoryElement = "channelFactory"; - private const string ServiceHostElement = "serviceHost"; - private const string ServiceExporterElement = "serviceExporter"; +namespace Spring.ServiceModel.Config; - /// - /// Register the for the WCF tags. - /// - public override void Init() - { - RegisterObjectDefinitionParser(ChannelFactoryElement, new ChannelFactoryObjectDefinitionParser()); - } +/// +/// Namespace parser for the WCF namespace. +/// +/// Bruno Baia +[ + NamespaceParser( + Namespace = "http://www.springframework.net/wcf", + SchemaLocationAssemblyHint = typeof(WcfNamespaceParser), + SchemaLocation = "/Spring.ServiceModel.Config/spring-wcf-1.3.xsd") +] +public sealed class WcfNamespaceParser : NamespaceParserSupport +{ + private const string ChannelFactoryElement = "channelFactory"; + private const string ServiceHostElement = "serviceHost"; + private const string ServiceExporterElement = "serviceExporter"; + + /// + /// Register the for the WCF tags. + /// + public override void Init() + { + RegisterObjectDefinitionParser(ChannelFactoryElement, new ChannelFactoryObjectDefinitionParser()); } } diff --git a/src/Spring/Spring.Services/ServiceModel/Config/spring-wcf-1.3.xsd b/src/Spring/Spring.Services/ServiceModel/Config/spring-wcf-1.3.xsd index d9ea47a0..2ec7cecb 100644 --- a/src/Spring/Spring.Services/ServiceModel/Config/spring-wcf-1.3.xsd +++ b/src/Spring/Spring.Services/ServiceModel/Config/spring-wcf-1.3.xsd @@ -1,70 +1,71 @@ + xmlns:objects="http://www.springframework.net" + xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:vs="http://schemas.microsoft.com/Visual-Studio-Intellisense" + targetNamespace="http://www.springframework.net/wcf" + elementFormDefault="qualified" attributeFormDefault="unqualified" + vs:friendlyname="Spring.NET WCF Framework Configuration" vs:ishtmlschema="false" vs:iscasesensitive="true" + vs:requireattributequotes="true" vs:defaultnamespacequalifier="" vs:defaultnsprefix=""> - + - - - + + - - + + - - - - + + + - - - - - - - + + + + + + - - - - - - - - + + + + + + + - - - - - - - + + + + + + - - - - - - - + + + + + + - - - - + + + + - + diff --git a/src/Spring/Spring.Services/ServiceModel/ServiceExporter.cs b/src/Spring/Spring.Services/ServiceModel/ServiceExporter.cs index 5f98ff85..e17e6567 100644 --- a/src/Spring/Spring.Services/ServiceModel/ServiceExporter.cs +++ b/src/Spring/Spring.Services/ServiceModel/ServiceExporter.cs @@ -31,559 +31,563 @@ using Spring.Objects.Factory.Support; using Spring.Proxy; using Spring.ServiceModel.Support; -namespace Spring.ServiceModel +namespace Spring.ServiceModel; + +/// +/// Exports an object as a WCF service. +/// +/// Bruno Baia +public class ServiceExporter : IFactoryObject, IInitializingObject, IObjectFactoryAware, IObjectNameAware { + #region Logging + + //private static readonly ILogger LOG = LogManager.GetLogger(); + + #endregion + + #region Fields + + private string _targetName; + private Type _contractInterface; + private IList _typeAttributes = new ArrayList(); + private IDictionary _memberAttributes = new Hashtable(); + private bool _useServiceProxyTypeCache = true; + + private string _name; + private string _namespace; + private string _configurationName; + private Type _callbackContract; + private ProtectionLevel _protectionLevel; + private SessionMode _sessionMode; + /// - /// Exports an object as a WCF service. + /// The name of the object in the factory. /// - /// Bruno Baia - public class ServiceExporter : IFactoryObject, IInitializingObject, IObjectFactoryAware, IObjectNameAware + private string objectName; + + /// + /// The owning factory. + /// + private DefaultListableObjectFactory objectFactory; + + /// + /// The generated WCF service wrapper type. + /// + private Type proxyType; + + #endregion + + #region Constructor(s) / Destructor + + /// + /// Creates a new instance of the class. + /// + public ServiceExporter() { - #region Logging + } - //private static readonly ILogger LOG = LogManager.GetLogger(); + #endregion - #endregion + #region Properties - #region Fields + /// + /// Gets or sets the name of the target object definition. + /// + public string TargetName + { + get { return _targetName; } + set { _targetName = value; } + } - private string _targetName; - private Type _contractInterface; - private IList _typeAttributes = new ArrayList(); - private IDictionary _memberAttributes = new Hashtable(); - private bool _useServiceProxyTypeCache = true; + /// + /// Gets or sets the service contract interface type. + /// + /// + /// If not set, uses the unique interface implemented or inherited by the target type. + /// An error will be thrown if the target type implements more than one interface. + /// + /// The service contract interface type. + public Type ContractInterface + { + get { return _contractInterface; } + set { _contractInterface = value; } + } - private string _name; - private string _namespace; - private string _configurationName; - private Type _callbackContract; - private ProtectionLevel _protectionLevel; - private SessionMode _sessionMode; + /// + /// Gets or sets a list of custom attributes + /// that should be applied to the WCF service class. + /// + public IList TypeAttributes + { + get { return _typeAttributes; } + set { _typeAttributes = value; } + } - /// - /// The name of the object in the factory. - /// - private string objectName; + /// + /// Gets or sets a dictionary of custom attributes + /// that should be applied to the WCF service members. + /// + /// + /// Dictionary key is an expression that members can be matched against. + /// Value is a list of attributes that should be applied + /// to each member that matches expression. + /// + public IDictionary MemberAttributes + { + get { return _memberAttributes; } + set { _memberAttributes = value; } + } - /// - /// The owning factory. - /// + /// + /// Controls, whether the underlying should cache + /// the generated proxy types. Defaults to true. + /// + public bool UseServiceProxyTypeCache + { + get { return _useServiceProxyTypeCache; } + set { _useServiceProxyTypeCache = value; } + } + + /// + /// Gets or sets the name for the <portType> element in + /// Web Services Description Language (WSDL). + /// + /// + /// The default value is the name of the class or interface to which the + /// System.ServiceModel.ServiceContractAttribute is applied. + /// + public string Name + { + get { return _name; } + set { _name = value; } + } + + /// + /// Gets or sets the namespace of the <portType> element in + /// Web Services Description Language (WSDL). + /// + /// + /// The WSDL namespace of the <portType> element. The default value is "http://tempuri.org". + /// + public string Namespace + { + get { return _namespace; } + set { _namespace = value; } + } + + /// + /// Gets or sets the name used to locate the service in an application configuration file. + /// + /// + /// The name used to locate the service element in an application configuration file. + /// The default is the name of the service implementation class. + /// + public string ConfigurationName + { + get { return _configurationName; } + set { _configurationName = value; } + } + + /// + /// Gets or sets the type of callback contract when the contract is a duplex contract. + /// + /// + /// A that indicates the callback contract. The default is null. + /// + public Type CallbackContract + { + get { return _callbackContract; } + set { _callbackContract = value; } + } + + /// + /// Specifies whether the binding for the contract must support the value of + /// the ProtectionLevel property. + /// + /// + /// One of the values. + /// The default is . + /// + public ProtectionLevel ProtectionLevel + { + get { return _protectionLevel; } + set { _protectionLevel = value; } + } + + /// + /// Gets or sets whether sessions are allowed, not allowed or required. + /// + /// + /// A that indicates whether sessions are allowed, + /// not allowed, or required. + /// + public SessionMode SessionMode + { + get { return _sessionMode; } + set { _sessionMode = value; } + } + + #endregion + + #region IObjectFactoryAware Members + + /// + /// Callback that supplies the owning factory to an object instance. + /// + /// + /// Owning + /// (may not be ). The object can immediately + /// call methods on the factory. + /// + /// + ///

+ /// Invoked after population of normal object properties but before an init + /// callback like 's + /// + /// method or a custom init-method. + ///

+ ///
+ /// + /// In case of initialization errors. + /// + public virtual IObjectFactory ObjectFactory + { + protected get { return objectFactory; } + set + { + if (value is DefaultListableObjectFactory) + { + this.objectFactory = (DefaultListableObjectFactory) value; + } + else + { + //TODO verify type of exception thrown + throw new ArgumentException("ObjectFactory must of type DefaultListableObjectFactory"); + } + } + } + + #endregion + + #region IInitializingObject Members + + /// + /// Publish the object + /// + public void AfterPropertiesSet() + { + ValidateConfiguration(); + GenerateProxy(); + } + + #endregion + + #region IFactoryObject Members + + /// + /// Return an instance (possibly shared or independent) of the object + /// managed by this factory. + /// + /// + /// + /// If this method is being called in the context of an enclosing IoC container and + /// returns , the IoC container will consider this factory + /// object as not being fully initialized and throw a corresponding (and most + /// probably fatal) exception. + /// + /// + /// + /// An instance (possibly shared or independent) of the object managed by + /// this factory. + /// + public object GetObject() + { + return proxyType; + } + + /// + /// Return the of object that this + /// creates, or + /// if not known in advance. + /// + public Type ObjectType + { + get { return typeof(Type); } + } + + /// + /// Is the object managed by this factory a singleton or a prototype? + /// + public bool IsSingleton + { + get { return false; } + } + + #endregion + + #region IObjectNameAware Members + + /// + /// Set the name of the object in the object factory that created this object. + /// + /// + /// The name of the object in the factory. + /// + /// + ///

+ /// Invoked after population of normal object properties but before an init + /// callback like 's + /// + /// method or a custom init-method. + ///

+ ///
+ public string ObjectName + { + protected get { return this.objectName; } + set { this.objectName = value; } + } + + #endregion + + #region Protected Methods + + /// + /// Validates the configuration. + /// + protected virtual void ValidateConfiguration() + { + if (TargetName == null) + { + throw new ArgumentException("The TargetName property is required."); + } + + if (ContractInterface != null && !ContractInterface.IsInterface) + { + throw new ArgumentException("ContractInterface must be an interface."); + } + } + + /// + /// Generates the WCF service wrapper type. + /// + protected virtual void GenerateProxy() + { + IProxyTypeBuilder builder = new ConfigurableServiceProxyTypeBuilder( + TargetName, this.objectName, this.objectFactory, _useServiceProxyTypeCache, ContractInterface, + Name, Namespace, ConfigurationName, CallbackContract, ProtectionLevel, SessionMode); + + builder.TypeAttributes = TypeAttributes; + builder.MemberAttributes = MemberAttributes; + + proxyType = builder.BuildProxyType(); + } + + #endregion + + #region ConfigurableServiceProxyTypeBuilder inner class implementation + + /// + /// Builds a WCF service type. + /// + private sealed class ConfigurableServiceProxyTypeBuilder : ServiceProxyTypeBuilder + { + private Type contractInterface; + private CustomAttributeBuilder serviceContractAttribute; private DefaultListableObjectFactory objectFactory; - /// - /// The generated WCF service wrapper type. - /// - private Type proxyType; - - #endregion - - #region Constructor(s) / Destructor - - /// - /// Creates a new instance of the class. - /// - public ServiceExporter() + public ConfigurableServiceProxyTypeBuilder(string targetName, string objectName, DefaultListableObjectFactory objectFactory, bool useServiceProxyTypeCache, Type contractInterface, string name, string ns, string configurationName, Type callbackContract, ProtectionLevel protectionLevel, SessionMode sessionMode) + : base(targetName, objectName, objectFactory, useServiceProxyTypeCache) { - } - - #endregion - - #region Properties - - /// - /// Gets or sets the name of the target object definition. - /// - public string TargetName - { - get { return _targetName; } - set { _targetName = value; } - } - - /// - /// Gets or sets the service contract interface type. - /// - /// - /// If not set, uses the unique interface implemented or inherited by the target type. - /// An error will be thrown if the target type implements more than one interface. - /// - /// The service contract interface type. - public Type ContractInterface - { - get { return _contractInterface; } - set { _contractInterface = value; } - } - - /// - /// Gets or sets a list of custom attributes - /// that should be applied to the WCF service class. - /// - public IList TypeAttributes - { - get { return _typeAttributes; } - set { _typeAttributes = value; } - } - - /// - /// Gets or sets a dictionary of custom attributes - /// that should be applied to the WCF service members. - /// - /// - /// Dictionary key is an expression that members can be matched against. - /// Value is a list of attributes that should be applied - /// to each member that matches expression. - /// - public IDictionary MemberAttributes - { - get { return _memberAttributes; } - set { _memberAttributes = value; } - } - - /// - /// Controls, whether the underlying should cache - /// the generated proxy types. Defaults to true. - /// - public bool UseServiceProxyTypeCache - { - get { return _useServiceProxyTypeCache; } - set { _useServiceProxyTypeCache = value; } - } - - /// - /// Gets or sets the name for the <portType> element in - /// Web Services Description Language (WSDL). - /// - /// - /// The default value is the name of the class or interface to which the - /// System.ServiceModel.ServiceContractAttribute is applied. - /// - public string Name - { - get { return _name; } - set { _name = value; } - } - - /// - /// Gets or sets the namespace of the <portType> element in - /// Web Services Description Language (WSDL). - /// - /// - /// The WSDL namespace of the <portType> element. The default value is "http://tempuri.org". - /// - public string Namespace - { - get { return _namespace; } - set { _namespace = value; } - } - - /// - /// Gets or sets the name used to locate the service in an application configuration file. - /// - /// - /// The name used to locate the service element in an application configuration file. - /// The default is the name of the service implementation class. - /// - public string ConfigurationName - { - get { return _configurationName; } - set { _configurationName = value; } - } - - /// - /// Gets or sets the type of callback contract when the contract is a duplex contract. - /// - /// - /// A that indicates the callback contract. The default is null. - /// - public Type CallbackContract - { - get { return _callbackContract; } - set { _callbackContract = value; } - } - - /// - /// Specifies whether the binding for the contract must support the value of - /// the ProtectionLevel property. - /// - /// - /// One of the values. - /// The default is . - /// - public ProtectionLevel ProtectionLevel - { - get { return _protectionLevel; } - set { _protectionLevel = value; } - } - - /// - /// Gets or sets whether sessions are allowed, not allowed or required. - /// - /// - /// A that indicates whether sessions are allowed, - /// not allowed, or required. - /// - public SessionMode SessionMode - { - get { return _sessionMode; } - set { _sessionMode = value; } - } - - #endregion - - #region IObjectFactoryAware Members - - /// - /// Callback that supplies the owning factory to an object instance. - /// - /// - /// Owning - /// (may not be ). The object can immediately - /// call methods on the factory. - /// - /// - ///

- /// Invoked after population of normal object properties but before an init - /// callback like 's - /// - /// method or a custom init-method. - ///

- ///
- /// - /// In case of initialization errors. - /// - public virtual IObjectFactory ObjectFactory - { - protected get { return objectFactory; } - set + this.objectFactory = objectFactory; + this.contractInterface = contractInterface; + if (!StringUtils.HasText(configurationName)) { - if (value is DefaultListableObjectFactory) + name = this.Interfaces[0].Name; + configurationName = this.Interfaces[0].FullName; + } + + // Creates a ServiceContractAttribute from configuration info + this.serviceContractAttribute = CreateServiceContractAttribute(name, ns, configurationName, callbackContract, protectionLevel, sessionMode); + } + + private static CustomAttributeBuilder CreateServiceContractAttribute(string name, string ns, string configurationName, + Type callbackContract, ProtectionLevel protectionLevel, SessionMode sessionMode) + { + ReflectionUtils.CustomAttributeBuilderBuilder scbb = + new ReflectionUtils.CustomAttributeBuilderBuilder(typeof(ServiceContractAttribute)); + if (StringUtils.HasText(name)) + { + scbb.AddPropertyValue("Name", name); + } + + if (StringUtils.HasText(ns)) + { + scbb.AddPropertyValue("Namespace", ns); + } + + if (StringUtils.HasText(configurationName)) + { + scbb.AddPropertyValue("ConfigurationName", configurationName); + } + + if (callbackContract != null) + { + scbb.AddPropertyValue("CallbackContract", callbackContract); + } + + if (protectionLevel != ProtectionLevel.None) + { + scbb.AddPropertyValue("ProtectionLevel", protectionLevel); + } + + if (sessionMode != SessionMode.Allowed) + { + scbb.AddPropertyValue("SessionMode", sessionMode); + } + + return scbb.Build(); + } + + protected override IList GetTypeAttributes(Type type) + { + IList attrs = base.GetTypeAttributes(type); + + bool containsServiceContractAttribute = false; + + for (int i = 0; i < attrs.Count; i++) + { + if (IsAttributeMatchingType(attrs[i], typeof(ServiceContractAttribute))) { - this.objectFactory = (DefaultListableObjectFactory)value; - } else - { - //TODO verify type of exception thrown - throw new ArgumentException("ObjectFactory must of type DefaultListableObjectFactory"); + // Override existing ServiceContractAttribute + containsServiceContractAttribute = true; + attrs[i] = serviceContractAttribute; } } - } - #endregion - - #region IInitializingObject Members - - /// - /// Publish the object - /// - public void AfterPropertiesSet() - { - ValidateConfiguration(); - GenerateProxy(); - } - - #endregion - - #region IFactoryObject Members - - /// - /// Return an instance (possibly shared or independent) of the object - /// managed by this factory. - /// - /// - /// - /// If this method is being called in the context of an enclosing IoC container and - /// returns , the IoC container will consider this factory - /// object as not being fully initialized and throw a corresponding (and most - /// probably fatal) exception. - /// - /// - /// - /// An instance (possibly shared or independent) of the object managed by - /// this factory. - /// - public object GetObject() - { - return proxyType; - } - - /// - /// Return the of object that this - /// creates, or - /// if not known in advance. - /// - public Type ObjectType - { - get { return typeof(Type); } - } - - /// - /// Is the object managed by this factory a singleton or a prototype? - /// - public bool IsSingleton - { - get { return false; } - } - - #endregion - - #region IObjectNameAware Members - - /// - /// Set the name of the object in the object factory that created this object. - /// - /// - /// The name of the object in the factory. - /// - /// - ///

- /// Invoked after population of normal object properties but before an init - /// callback like 's - /// - /// method or a custom init-method. - ///

- ///
- public string ObjectName - { - protected get { return this.objectName; } - set { this.objectName = value; } - } - - #endregion - - #region Protected Methods - - /// - /// Validates the configuration. - /// - protected virtual void ValidateConfiguration() - { - if (TargetName == null) + // Add missing ServiceContractAttribute + if (!containsServiceContractAttribute) { - throw new ArgumentException("The TargetName property is required."); + attrs.Add(serviceContractAttribute); } - if (ContractInterface != null && !ContractInterface.IsInterface) + + return attrs; + } + + protected override IList GetMethodAttributes(MethodInfo method) + { + IList attrs = base.GetMethodAttributes(method); + + bool containsOperationContractAttribute = false; + foreach (object attr in attrs) { - throw new ArgumentException("ContractInterface must be an interface."); + if (IsAttributeMatchingType(attr, typeof(OperationContractAttribute))) + { + containsOperationContractAttribute = true; + break; + } + } + + // Creates default OperationContractAttribute if not set yet + if (!containsOperationContractAttribute) + { + attrs.Add(ReflectionUtils.CreateCustomAttribute(typeof(OperationContractAttribute))); + } + + return attrs; + } + + protected override IList GetProxiableInterfaces(IList interfaces) + { + if (contractInterface == null) + { + IList proxiableInterfaces = base.GetProxiableInterfaces(interfaces); + if (proxiableInterfaces.Count > 1) + { + throw new ArgumentException(String.Format( + "ServiceExporter cannot export service type '{0}' as a WCF service because it implements multiple interfaces. Specify the contract interface to expose via the ContractInterface property.", + this.TargetType)); + } + + return proxiableInterfaces; + } + else + { + return base.GetProxiableInterfaces(new Type[] { this.contractInterface }); } } /// - /// Generates the WCF service wrapper type. + /// Applies attributes to the proxy class. /// - protected virtual void GenerateProxy() + /// The type builder to use. + /// The proxied class. + /// + /// + protected override void ApplyTypeAttributes(TypeBuilder typeBuilder, Type targetType) { - IProxyTypeBuilder builder = new ConfigurableServiceProxyTypeBuilder( - TargetName, this.objectName, this.objectFactory, _useServiceProxyTypeCache, ContractInterface, - Name, Namespace, ConfigurationName, CallbackContract, ProtectionLevel, SessionMode); - - builder.TypeAttributes = TypeAttributes; - builder.MemberAttributes = MemberAttributes; - - proxyType = builder.BuildProxyType(); - } - - #endregion - - #region ConfigurableServiceProxyTypeBuilder inner class implementation - - /// - /// Builds a WCF service type. - /// - private sealed class ConfigurableServiceProxyTypeBuilder : ServiceProxyTypeBuilder - { - private Type contractInterface; - private CustomAttributeBuilder serviceContractAttribute; - private DefaultListableObjectFactory objectFactory; - - public ConfigurableServiceProxyTypeBuilder(string targetName, string objectName, DefaultListableObjectFactory objectFactory, bool useServiceProxyTypeCache, Type contractInterface, string name, string ns, string configurationName, Type callbackContract, ProtectionLevel protectionLevel, SessionMode sessionMode) - : base(targetName, objectName, objectFactory, useServiceProxyTypeCache) + foreach (object attr in GetTypeAttributes(targetType)) { - this.objectFactory = objectFactory; - this.contractInterface = contractInterface; - if (!StringUtils.HasText(configurationName)) + if (attr is CustomAttributeBuilder) { - name = this.Interfaces[0].Name; - configurationName = this.Interfaces[0].FullName; + typeBuilder.SetCustomAttribute((CustomAttributeBuilder) attr); } + else if (attr is CustomAttributeData) + { + typeBuilder.SetCustomAttribute( + ReflectionUtils.CreateCustomAttribute((CustomAttributeData) attr)); + } + else if (attr is Attribute) + { + typeBuilder.SetCustomAttribute( + ReflectionUtils.CreateCustomAttribute((Attribute) attr)); + } + else if (attr is IObjectDefinition) + { + RootObjectDefinition objectDefinition = (RootObjectDefinition) attr; - // Creates a ServiceContractAttribute from configuration info - this.serviceContractAttribute = CreateServiceContractAttribute(name, ns, configurationName, callbackContract, protectionLevel, sessionMode); - } + //TODO check that object definition is for an Attribute type. - private static CustomAttributeBuilder CreateServiceContractAttribute(string name, string ns, string configurationName, - Type callbackContract, ProtectionLevel protectionLevel, SessionMode sessionMode) - { - ReflectionUtils.CustomAttributeBuilderBuilder scbb = - new ReflectionUtils.CustomAttributeBuilderBuilder(typeof(ServiceContractAttribute)); - if (StringUtils.HasText(name)) - { - scbb.AddPropertyValue("Name", name); - } - if (StringUtils.HasText(ns)) - { - scbb.AddPropertyValue("Namespace", ns); - } - if (StringUtils.HasText(configurationName)) - { - scbb.AddPropertyValue("ConfigurationName", configurationName); - } - if (callbackContract != null) - { - scbb.AddPropertyValue("CallbackContract", callbackContract); - } - if (protectionLevel != ProtectionLevel.None) - { - scbb.AddPropertyValue("ProtectionLevel", protectionLevel); - } - if (sessionMode != SessionMode.Allowed) - { - scbb.AddPropertyValue("SessionMode", sessionMode); - } - return scbb.Build(); - } + //Change object definition so it can be instantiated and make prototype scope. + objectDefinition.IsAbstract = false; + objectDefinition.IsSingleton = false; + string objectName = ObjectDefinitionReaderUtils.GenerateObjectName(objectDefinition, objectFactory); + objectFactory.RegisterObjectDefinition(objectName, objectDefinition); - protected override IList GetTypeAttributes(Type type) - { - IList attrs = base.GetTypeAttributes(type); + //find constructor and constructor arg values to create this attribute. + ConstructorResolver constructorResolver = new ConstructorResolver(objectFactory, objectFactory, + new SimpleInstantiationStrategy(), + new ObjectDefinitionValueResolver(objectFactory)); - bool containsServiceContractAttribute = false; + ConstructorInstantiationInfo ci = constructorResolver.GetConstructorInstantiationInfo(objectName, + objectDefinition, + null, null); - for (int i = 0; i < attrs.Count; i++) - { - if (IsAttributeMatchingType(attrs[i], typeof(ServiceContractAttribute))) + if (objectDefinition.PropertyValues.PropertyValues.Count == 0) { - // Override existing ServiceContractAttribute - containsServiceContractAttribute = true; - attrs[i] = serviceContractAttribute; + CustomAttributeBuilder cab = new CustomAttributeBuilder(ci.ConstructorInfo, + ci.ArgInstances); + typeBuilder.SetCustomAttribute(cab); } - } - - // Add missing ServiceContractAttribute - if (!containsServiceContractAttribute) - { - attrs.Add(serviceContractAttribute); - } - - return attrs; - } - - protected override IList GetMethodAttributes(MethodInfo method) - { - IList attrs = base.GetMethodAttributes(method); - - bool containsOperationContractAttribute = false; - foreach (object attr in attrs) - { - if (IsAttributeMatchingType(attr, typeof(OperationContractAttribute))) + else { - containsOperationContractAttribute = true; - break; - } - } - - // Creates default OperationContractAttribute if not set yet - if (!containsOperationContractAttribute) - { - attrs.Add(ReflectionUtils.CreateCustomAttribute(typeof(OperationContractAttribute))); - } - - return attrs; - } - - protected override IList GetProxiableInterfaces(IList interfaces) - { - if (contractInterface == null) - { - IList proxiableInterfaces = base.GetProxiableInterfaces(interfaces); - if (proxiableInterfaces.Count > 1) - { - throw new ArgumentException(String.Format( - "ServiceExporter cannot export service type '{0}' as a WCF service because it implements multiple interfaces. Specify the contract interface to expose via the ContractInterface property.", - this.TargetType)); - } - return proxiableInterfaces; - } - else - { - return base.GetProxiableInterfaces(new Type[] { this.contractInterface }); - } - } - - /// - /// Applies attributes to the proxy class. - /// - /// The type builder to use. - /// The proxied class. - /// - /// - protected override void ApplyTypeAttributes(TypeBuilder typeBuilder, Type targetType) - { - foreach (object attr in GetTypeAttributes(targetType)) - { - if (attr is CustomAttributeBuilder) - { - typeBuilder.SetCustomAttribute((CustomAttributeBuilder)attr); - } - else if (attr is CustomAttributeData) - { - typeBuilder.SetCustomAttribute( - ReflectionUtils.CreateCustomAttribute((CustomAttributeData)attr)); - } - else if (attr is Attribute) - { - typeBuilder.SetCustomAttribute( - ReflectionUtils.CreateCustomAttribute((Attribute)attr)); - } - else if (attr is IObjectDefinition) - { - RootObjectDefinition objectDefinition = (RootObjectDefinition) attr; - - //TODO check that object definition is for an Attribute type. - - //Change object definition so it can be instantiated and make prototype scope. - objectDefinition.IsAbstract = false; - objectDefinition.IsSingleton = false; - string objectName = ObjectDefinitionReaderUtils.GenerateObjectName(objectDefinition, objectFactory); - objectFactory.RegisterObjectDefinition(objectName, objectDefinition); - - - //find constructor and constructor arg values to create this attribute. - ConstructorResolver constructorResolver = new ConstructorResolver(objectFactory, objectFactory, - new SimpleInstantiationStrategy(), - new ObjectDefinitionValueResolver(objectFactory)); - - - ConstructorInstantiationInfo ci = constructorResolver.GetConstructorInstantiationInfo(objectName, - objectDefinition, - null, null); - - if (objectDefinition.PropertyValues.PropertyValues.Count == 0) + object attributeInstance = objectFactory.GetObject(objectName); + IObjectWrapper wrappedAttributeInstance = new ObjectWrapper(attributeInstance); + PropertyInfo[] namedProperties = wrappedAttributeInstance.GetPropertyInfos(); + object[] propertyValues = new object[namedProperties.Length]; + for (int i = 0; i < namedProperties.Length; i++) { - CustomAttributeBuilder cab = new CustomAttributeBuilder(ci.ConstructorInfo, - ci.ArgInstances); - typeBuilder.SetCustomAttribute(cab); - } - else - { - object attributeInstance = objectFactory.GetObject(objectName); - IObjectWrapper wrappedAttributeInstance = new ObjectWrapper(attributeInstance); - PropertyInfo[] namedProperties = wrappedAttributeInstance.GetPropertyInfos(); - object[] propertyValues = new object[namedProperties.Length]; - for (int i = 0; i < namedProperties.Length; i++) - { - propertyValues[i] = - wrappedAttributeInstance.GetPropertyValue(namedProperties[i].Name); - } - CustomAttributeBuilder cab = new CustomAttributeBuilder(ci.ConstructorInfo, ci.ArgInstances, - namedProperties, propertyValues); - typeBuilder.SetCustomAttribute(cab); + propertyValues[i] = + wrappedAttributeInstance.GetPropertyValue(namedProperties[i].Name); } - + CustomAttributeBuilder cab = new CustomAttributeBuilder(ci.ConstructorInfo, ci.ArgInstances, + namedProperties, propertyValues); + typeBuilder.SetCustomAttribute(cab); } - } } } - - #endregion } + + #endregion } diff --git a/src/Spring/Spring.Services/ServiceModel/SpringServiceHost.cs b/src/Spring/Spring.Services/ServiceModel/SpringServiceHost.cs index fcf09067..fec489a5 100644 --- a/src/Spring/Spring.Services/ServiceModel/SpringServiceHost.cs +++ b/src/Spring/Spring.Services/ServiceModel/SpringServiceHost.cs @@ -24,88 +24,87 @@ using Spring.Context.Support; using Spring.ServiceModel.Support; using Spring.Objects.Factory; -namespace Spring.ServiceModel +namespace Spring.ServiceModel; + +/// +/// Provides a host for Spring-managed services. +/// +/// Bruno Baia +public class SpringServiceHost : System.ServiceModel.ServiceHost { + #region Constructor(s) / Destructor + /// - /// Provides a host for Spring-managed services. + /// Creates a new instance of the class. /// - /// Bruno Baia - public class SpringServiceHost : System.ServiceModel.ServiceHost + /// The name of the service within Spring's IoC container. + /// The base addresses for the hosted service. + public SpringServiceHost(string serviceName, params Uri[] baseAddresses) + : this(serviceName, GetApplicationContext(null), baseAddresses) { - #region Constructor(s) / Destructor - - /// - /// Creates a new instance of the class. - /// - /// The name of the service within Spring's IoC container. - /// The base addresses for the hosted service. - public SpringServiceHost(string serviceName, params Uri[] baseAddresses) - : this(serviceName, GetApplicationContext(null), baseAddresses) - { - } - - /// - /// Creates a new instance of the class. - /// - /// The name of the service within Spring's IoC container. - /// The name of the Spring context to use. - /// The base addresses for the hosted service. - public SpringServiceHost(string serviceName, string contextName, params Uri[] baseAddresses) - : this(serviceName, GetApplicationContext(contextName), baseAddresses) - { - } - - /// - /// Creates a new instance of the class. - /// - /// The name of the service within Spring's IoC container. - /// The to use. - /// The base addresses for the hosted service. - public SpringServiceHost(string serviceName, IObjectFactory objectFactory, params Uri[] baseAddresses) - : this(serviceName, objectFactory, true, baseAddresses) - { - } - - /// - /// Creates a new instance of the class. - /// - /// The name of the service within Spring's IoC container. - /// The to use. - /// Whether to cache the generated service proxy type. - /// The base addresses for the hosted service. - public SpringServiceHost(string serviceName, IObjectFactory objectFactory, bool useServiceProxyTypeCache, params Uri[] baseAddresses) - : base(CreateServiceType(serviceName, objectFactory, useServiceProxyTypeCache), baseAddresses) - { - } - - private static IApplicationContext GetApplicationContext(string contextName) - { - if (StringUtils.IsNullOrEmpty(contextName)) - { - return ContextRegistry.GetContext(); - } - else - { - return ContextRegistry.GetContext(contextName); - } - } - - private static Type CreateServiceType(string serviceName, IObjectFactory objectFactory, bool useServiceProxyTypeCache) - { - if (StringUtils.IsNullOrEmpty(serviceName)) - { - throw new ArgumentException("The service name cannot be null or an empty string.", "serviceName"); - } - - if (objectFactory.IsTypeMatch(serviceName, typeof(Type))) - { - return objectFactory.GetObject(serviceName) as Type; - } - - return new ServiceProxyTypeBuilder(serviceName, objectFactory, useServiceProxyTypeCache) - .BuildProxyType(); - } - - #endregion } + + /// + /// Creates a new instance of the class. + /// + /// The name of the service within Spring's IoC container. + /// The name of the Spring context to use. + /// The base addresses for the hosted service. + public SpringServiceHost(string serviceName, string contextName, params Uri[] baseAddresses) + : this(serviceName, GetApplicationContext(contextName), baseAddresses) + { + } + + /// + /// Creates a new instance of the class. + /// + /// The name of the service within Spring's IoC container. + /// The to use. + /// The base addresses for the hosted service. + public SpringServiceHost(string serviceName, IObjectFactory objectFactory, params Uri[] baseAddresses) + : this(serviceName, objectFactory, true, baseAddresses) + { + } + + /// + /// Creates a new instance of the class. + /// + /// The name of the service within Spring's IoC container. + /// The to use. + /// Whether to cache the generated service proxy type. + /// The base addresses for the hosted service. + public SpringServiceHost(string serviceName, IObjectFactory objectFactory, bool useServiceProxyTypeCache, params Uri[] baseAddresses) + : base(CreateServiceType(serviceName, objectFactory, useServiceProxyTypeCache), baseAddresses) + { + } + + private static IApplicationContext GetApplicationContext(string contextName) + { + if (StringUtils.IsNullOrEmpty(contextName)) + { + return ContextRegistry.GetContext(); + } + else + { + return ContextRegistry.GetContext(contextName); + } + } + + private static Type CreateServiceType(string serviceName, IObjectFactory objectFactory, bool useServiceProxyTypeCache) + { + if (StringUtils.IsNullOrEmpty(serviceName)) + { + throw new ArgumentException("The service name cannot be null or an empty string.", "serviceName"); + } + + if (objectFactory.IsTypeMatch(serviceName, typeof(Type))) + { + return objectFactory.GetObject(serviceName) as Type; + } + + return new ServiceProxyTypeBuilder(serviceName, objectFactory, useServiceProxyTypeCache) + .BuildProxyType(); + } + + #endregion } diff --git a/src/Spring/Spring.Services/ServiceModel/SpringWebServiceHost.cs b/src/Spring/Spring.Services/ServiceModel/SpringWebServiceHost.cs index 73a2a3ef..9623ec0a 100644 --- a/src/Spring/Spring.Services/ServiceModel/SpringWebServiceHost.cs +++ b/src/Spring/Spring.Services/ServiceModel/SpringWebServiceHost.cs @@ -25,88 +25,87 @@ using Spring.ServiceModel.Support; using Spring.Objects.Factory; using System.ServiceModel.Web; -namespace Spring.ServiceModel +namespace Spring.ServiceModel; + +/// +/// Provides a host for Spring-managed services. +/// +/// Bruno Baia +public class SpringWebServiceHost : WebServiceHost { + #region Constructor(s) / Destructor + /// - /// Provides a host for Spring-managed services. + /// Creates a new instance of the class. /// - /// Bruno Baia - public class SpringWebServiceHost : WebServiceHost + /// The name of the service within Spring's IoC container. + /// The base addresses for the hosted service. + public SpringWebServiceHost(string serviceName, params Uri[] baseAddresses) + : this(serviceName, GetApplicationContext(null), baseAddresses) { - #region Constructor(s) / Destructor - - /// - /// Creates a new instance of the class. - /// - /// The name of the service within Spring's IoC container. - /// The base addresses for the hosted service. - public SpringWebServiceHost(string serviceName, params Uri[] baseAddresses) - : this(serviceName, GetApplicationContext(null), baseAddresses) - { - } - - /// - /// Creates a new instance of the class. - /// - /// The name of the service within Spring's IoC container. - /// The name of the Spring context to use. - /// The base addresses for the hosted service. - public SpringWebServiceHost(string serviceName, string contextName, params Uri[] baseAddresses) - : this(serviceName, GetApplicationContext(contextName), baseAddresses) - { - } - - /// - /// Creates a new instance of the class. - /// - /// The name of the service within Spring's IoC container. - /// The to use. - /// The base addresses for the hosted service. - public SpringWebServiceHost(string serviceName, IObjectFactory objectFactory, params Uri[] baseAddresses) - : this(serviceName, objectFactory, true, baseAddresses) - { - } - - /// - /// Creates a new instance of the class. - /// - /// The name of the service within Spring's IoC container. - /// The to use. - /// Whether to cache the generated service proxy type. - /// The base addresses for the hosted service. - public SpringWebServiceHost(string serviceName, IObjectFactory objectFactory, bool useServiceProxyTypeCache, params Uri[] baseAddresses) - : base(CreateServiceType(serviceName, objectFactory, useServiceProxyTypeCache), baseAddresses) - { - } - - private static IApplicationContext GetApplicationContext(string contextName) - { - if (StringUtils.IsNullOrEmpty(contextName)) - { - return ContextRegistry.GetContext(); - } - else - { - return ContextRegistry.GetContext(contextName); - } - } - - private static Type CreateServiceType(string serviceName, IObjectFactory objectFactory, bool useServiceProxyTypeCache) - { - if (StringUtils.IsNullOrEmpty(serviceName)) - { - throw new ArgumentException("The service name cannot be null or an empty string.", "serviceName"); - } - - if (objectFactory.IsTypeMatch(serviceName, typeof(Type))) - { - return objectFactory.GetObject(serviceName) as Type; - } - - return new ServiceProxyTypeBuilder(serviceName, objectFactory, useServiceProxyTypeCache) - .BuildProxyType(); - } - - #endregion } + + /// + /// Creates a new instance of the class. + /// + /// The name of the service within Spring's IoC container. + /// The name of the Spring context to use. + /// The base addresses for the hosted service. + public SpringWebServiceHost(string serviceName, string contextName, params Uri[] baseAddresses) + : this(serviceName, GetApplicationContext(contextName), baseAddresses) + { + } + + /// + /// Creates a new instance of the class. + /// + /// The name of the service within Spring's IoC container. + /// The to use. + /// The base addresses for the hosted service. + public SpringWebServiceHost(string serviceName, IObjectFactory objectFactory, params Uri[] baseAddresses) + : this(serviceName, objectFactory, true, baseAddresses) + { + } + + /// + /// Creates a new instance of the class. + /// + /// The name of the service within Spring's IoC container. + /// The to use. + /// Whether to cache the generated service proxy type. + /// The base addresses for the hosted service. + public SpringWebServiceHost(string serviceName, IObjectFactory objectFactory, bool useServiceProxyTypeCache, params Uri[] baseAddresses) + : base(CreateServiceType(serviceName, objectFactory, useServiceProxyTypeCache), baseAddresses) + { + } + + private static IApplicationContext GetApplicationContext(string contextName) + { + if (StringUtils.IsNullOrEmpty(contextName)) + { + return ContextRegistry.GetContext(); + } + else + { + return ContextRegistry.GetContext(contextName); + } + } + + private static Type CreateServiceType(string serviceName, IObjectFactory objectFactory, bool useServiceProxyTypeCache) + { + if (StringUtils.IsNullOrEmpty(serviceName)) + { + throw new ArgumentException("The service name cannot be null or an empty string.", "serviceName"); + } + + if (objectFactory.IsTypeMatch(serviceName, typeof(Type))) + { + return objectFactory.GetObject(serviceName) as Type; + } + + return new ServiceProxyTypeBuilder(serviceName, objectFactory, useServiceProxyTypeCache) + .BuildProxyType(); + } + + #endregion } diff --git a/src/Spring/Spring.Services/ServiceModel/Support/ServiceProxyTypeBuilder.cs b/src/Spring/Spring.Services/ServiceModel/Support/ServiceProxyTypeBuilder.cs index e0c8f894..9c09f198 100644 --- a/src/Spring/Spring.Services/ServiceModel/Support/ServiceProxyTypeBuilder.cs +++ b/src/Spring/Spring.Services/ServiceModel/Support/ServiceProxyTypeBuilder.cs @@ -21,157 +21,154 @@ using System.Collections; using System.Reflection; using System.Reflection.Emit; - using Spring.Objects.Factory; using Spring.Proxy; using Spring.Util; -namespace Spring.ServiceModel.Support +namespace Spring.ServiceModel.Support; + +/// +/// Builds a WCF service type. +/// +/// Bruno Baia +public class ServiceProxyTypeBuilder : CompositionProxyTypeBuilder { + #region Fields + + private static readonly MethodInfo GetObject = + //typeof(IObjectFactory).GetMethod("GetObject", new Type[] { typeof(string) }); + ReflectionUtils.GetMethod(typeof(IObjectFactory), "GetObject", new Type[] { typeof(string) }); + + private IObjectFactory objectFactory; + private static Hashtable s_serviceTypeCache = new Hashtable(); + + private string targetName; + private bool useServiceProxyTypeCache; + /// - /// Builds a WCF service type. + /// Target instance calls should be delegated to. /// - /// Bruno Baia - public class ServiceProxyTypeBuilder : CompositionProxyTypeBuilder + protected FieldBuilder objectFactoryField; + + #endregion + + #region Constructor(s) / Destructor + + /// + /// Creates a new instance of the + /// class. + /// + /// The name of the service within Spring's IoC container. + /// The to use. + /// Whether to cache the generated service proxy type. + public ServiceProxyTypeBuilder(string targetName, IObjectFactory objectFactory, bool useServiceProxyTypeCache) + : this(targetName, targetName, objectFactory, useServiceProxyTypeCache) { - #region Fields + } - private static readonly MethodInfo GetObject = - //typeof(IObjectFactory).GetMethod("GetObject", new Type[] { typeof(string) }); - ReflectionUtils.GetMethod(typeof (IObjectFactory), "GetObject", new Type[] {typeof (string)}); + /// + /// Creates a new instance of the + /// class. + /// + /// The name of the service within Spring's IoC container. + /// The name of the generated WCF service . + /// The to use. + /// Whether to cache the generated service proxy type. + public ServiceProxyTypeBuilder(string targetName, string serviceTypeName, IObjectFactory objectFactory, bool useServiceProxyTypeCache) + { + this.targetName = targetName; + this.objectFactory = objectFactory; + this.useServiceProxyTypeCache = useServiceProxyTypeCache; - private IObjectFactory objectFactory; - private static Hashtable s_serviceTypeCache = new Hashtable(); + this.Name = serviceTypeName; + this.TargetType = objectFactory.GetType(targetName); + } - private string targetName; - private bool useServiceProxyTypeCache; + #endregion - /// - /// Target instance calls should be delegated to. - /// - protected FieldBuilder objectFactoryField; + #region Protected Methods - #endregion - - #region Constructor(s) / Destructor - - /// - /// Creates a new instance of the - /// class. - /// - /// The name of the service within Spring's IoC container. - /// The to use. - /// Whether to cache the generated service proxy type. - public ServiceProxyTypeBuilder(string targetName, IObjectFactory objectFactory, bool useServiceProxyTypeCache) - : this(targetName, targetName, objectFactory, useServiceProxyTypeCache) + /// + /// Creates a proxy that delegates calls to an instance of the target object. + /// This overriden implementation caches the generated proxy type + /// and sets the '__objectFactory' field. + /// + /// + /// If the + /// does not implement any interfaces. + /// + public override Type BuildProxyType() + { + Type proxyType = null; + if (useServiceProxyTypeCache) { - } - - - /// - /// Creates a new instance of the - /// class. - /// - /// The name of the service within Spring's IoC container. - /// The name of the generated WCF service . - /// The to use. - /// Whether to cache the generated service proxy type. - public ServiceProxyTypeBuilder(string targetName, string serviceTypeName, IObjectFactory objectFactory, bool useServiceProxyTypeCache) - { - this.targetName = targetName; - this.objectFactory = objectFactory; - this.useServiceProxyTypeCache = useServiceProxyTypeCache; - - this.Name = serviceTypeName; - this.TargetType = objectFactory.GetType(targetName); - } - - #endregion - - #region Protected Methods - - /// - /// Creates a proxy that delegates calls to an instance of the target object. - /// This overriden implementation caches the generated proxy type - /// and sets the '__objectFactory' field. - /// - /// - /// If the - /// does not implement any interfaces. - /// - public override Type BuildProxyType() - { - Type proxyType = null; - if (useServiceProxyTypeCache) + lock (s_serviceTypeCache) { - lock (s_serviceTypeCache) + proxyType = (Type) s_serviceTypeCache[this.Name]; + if (proxyType == null) { - proxyType = (Type)s_serviceTypeCache[this.Name]; - if (proxyType == null) - { - proxyType = base.BuildProxyType(); - s_serviceTypeCache[this.Name] = proxyType; - } + proxyType = base.BuildProxyType(); + s_serviceTypeCache[this.Name] = proxyType; } } - else - { - proxyType = base.BuildProxyType(); - } - - FieldInfo field = proxyType.GetField("__objectFactory", BindingFlags.NonPublic | BindingFlags.Static); - field.SetValue(proxyType, this.objectFactory); - - return proxyType; } - - /// - /// Implements constructors for the proxy class. - /// - /// - /// This implementation generates a constructor - /// that gets instance of the target object using - /// . - /// - /// - /// The builder to use. - /// - protected override void ImplementConstructors(TypeBuilder builder) + else { - MethodAttributes attributes = MethodAttributes.Public | - MethodAttributes.HideBySig | MethodAttributes.SpecialName | - MethodAttributes.RTSpecialName; - - ConstructorBuilder cb = builder.DefineConstructor( - attributes, CallingConventions.Standard, Type.EmptyTypes); - - ILGenerator il = cb.GetILGenerator(); - - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Ldsfld, objectFactoryField); - il.Emit(OpCodes.Ldstr, targetName); - il.EmitCall(OpCodes.Callvirt, GetObject, null); - il.Emit(OpCodes.Stfld, targetInstance); - - il.Emit(OpCodes.Ret); + proxyType = base.BuildProxyType(); } - /// - /// Creates an appropriate type builder. Add a field to hold a reference to the application context. - /// - /// The name to use for the proxy type name. - /// The type to extends if provided. - /// The type builder to use. - protected override TypeBuilder CreateTypeBuilder(string name, Type baseType) - { - TypeBuilder typeBuilder = DynamicProxyManager.CreateTypeBuilder(name, baseType); + FieldInfo field = proxyType.GetField("__objectFactory", BindingFlags.NonPublic | BindingFlags.Static); + field.SetValue(proxyType, this.objectFactory); - objectFactoryField = typeBuilder.DefineField("__objectFactory", typeof(IObjectFactory), - FieldAttributes.Private | FieldAttributes.Static | FieldAttributes.InitOnly); - - return typeBuilder; - } - - #endregion + return proxyType; } + + /// + /// Implements constructors for the proxy class. + /// + /// + /// This implementation generates a constructor + /// that gets instance of the target object using + /// . + /// + /// + /// The builder to use. + /// + protected override void ImplementConstructors(TypeBuilder builder) + { + MethodAttributes attributes = MethodAttributes.Public | + MethodAttributes.HideBySig | MethodAttributes.SpecialName | + MethodAttributes.RTSpecialName; + + ConstructorBuilder cb = builder.DefineConstructor( + attributes, CallingConventions.Standard, Type.EmptyTypes); + + ILGenerator il = cb.GetILGenerator(); + + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldsfld, objectFactoryField); + il.Emit(OpCodes.Ldstr, targetName); + il.EmitCall(OpCodes.Callvirt, GetObject, null); + il.Emit(OpCodes.Stfld, targetInstance); + + il.Emit(OpCodes.Ret); + } + + /// + /// Creates an appropriate type builder. Add a field to hold a reference to the application context. + /// + /// The name to use for the proxy type name. + /// The type to extends if provided. + /// The type builder to use. + protected override TypeBuilder CreateTypeBuilder(string name, Type baseType) + { + TypeBuilder typeBuilder = DynamicProxyManager.CreateTypeBuilder(name, baseType); + + objectFactoryField = typeBuilder.DefineField("__objectFactory", typeof(IObjectFactory), + FieldAttributes.Private | FieldAttributes.Static | FieldAttributes.InitOnly); + + return typeBuilder; + } + + #endregion } diff --git a/src/Spring/Spring.Services/Web/Services/WebServiceProxyFactory.cs b/src/Spring/Spring.Services/Web/Services/WebServiceProxyFactory.cs index 9c674e7e..38822afb 100644 --- a/src/Spring/Spring.Services/Web/Services/WebServiceProxyFactory.cs +++ b/src/Spring/Spring.Services/Web/Services/WebServiceProxyFactory.cs @@ -35,49 +35,424 @@ using Spring.Proxy; using Spring.Util; using Spring.Core.IO; -namespace Spring.Web.Services +namespace Spring.Web.Services; + +/// +/// Factory Object that dynamically implements service interface for web service. +/// +/// +///

+/// This factory object should be used to obtain reference to a web service +/// that can be safely cast to a service interface, which allows client code to code +/// against interface, and not directly against the web service. +///

+///

+/// The WSDL contract needs to conform to WS-I Basic Profiles. +///

+///
+/// Bruno Baia +/// Aleksandar Seovic +public class WebServiceProxyFactory : IConfigurableFactoryObject, IInitializingObject { + #region Logging + + private static readonly ILogger LOG = LogManager.GetLogger(); + + #endregion + + #region Fields + + private IObjectDefinition _productTemplate; + private Type _webServiceProxyBaseType = typeof(SoapHttpClientProtocol); + private IResource _serviceUri; + private Type _proxyType; + private Type _serviceInterface; + private NetworkCredential _credential; + private string _proxyUrl; + private NetworkCredential _proxyCredential; + private string _bindingName; + private IList _typeAttributes = new ArrayList(); + private IDictionary _memberAttributes = new Hashtable(); + /// - /// Factory Object that dynamically implements service interface for web service. + /// The web service proxy default constructor. + /// + protected ConstructorInfo proxyConstructor; + + #endregion + + #region Constructor(s) / Destructor + + /// + /// Creates a new instance of the + /// class. + /// + public WebServiceProxyFactory() + { + } + + #endregion + + #region Properties + + /// + /// Gets or sets the base type that web service proxy should inherit. + /// + /// + /// Default is + /// + public Type WebServiceProxyBaseType + { + get { return _webServiceProxyBaseType; } + set { _webServiceProxyBaseType = value; } + } + + /// + /// Gets or sets the URI for an + /// that contains the web service description (WSDL). + /// + public IResource ServiceUri + { + get { return _serviceUri; } + set { _serviceUri = value; } + } + + /// + /// Gets or sets type of the proxy class to wrap. + /// + public Type ProxyType + { + get { return _proxyType; } + set { _proxyType = value; } + } + + /// + /// Gets or sets service interface that proxy should implement. + /// + public Type ServiceInterface + { + get { return _serviceInterface; } + set { _serviceInterface = value; } + } + + /// + /// Gets or sets the instance + /// to use when connecting to a server that requires authentication. + /// + public NetworkCredential Credential + { + get { return _credential; } + set { _credential = value; } + } + + /// + /// Gets or sets the url of the proxy server to use for retrieving the WSDL. /// /// ///

- /// This factory object should be used to obtain reference to a web service - /// that can be safely cast to a service interface, which allows client code to code - /// against interface, and not directly against the web service. + /// This only applies when using an as uri. ///

///

- /// The WSDL contract needs to conform to WS-I Basic Profiles. + /// The default is to use the system proxy setting. ///

///
- /// Bruno Baia - /// Aleksandar Seovic - public class WebServiceProxyFactory : IConfigurableFactoryObject, IInitializingObject + public string ProxyUrl + { + get { return _proxyUrl; } + set { _proxyUrl = value; } + } + + /// + /// Gets or sets the instance + /// to use when connecting to a proxy server that requires authentication. + /// + /// + ///

+ /// This only applies when using an as uri. + ///

+ ///
+ public NetworkCredential ProxyCredential + { + get { return _proxyCredential; } + set { _proxyCredential = value; } + } + + /// + /// Gets or sets the web service binding name to use for the proxy. + /// + public string BindingName + { + get { return _bindingName; } + set { _bindingName = value; } + } + + /// + /// Gets or sets a list of custom attributes + /// that should be applied to a proxy class. + /// + public IList TypeAttributes + { + get { return _typeAttributes; } + set { _typeAttributes = value; } + } + + /// + /// Gets or sets a dictionary of custom attributes + /// that should be applied to web service members. + /// + /// + /// Dictionary key is an expression that members can be matched against. + /// Value is a list of attributes that should be applied + /// to each member that matches expression. + /// + public IDictionary MemberAttributes + { + get { return _memberAttributes; } + set { _memberAttributes = value; } + } + + #endregion + + #region IConfigurableFactoryObject Members + + /// + /// Returns type of the web service proxy. + /// + public virtual Type ObjectType + { + get { return (proxyConstructor != null ? proxyConstructor.DeclaringType : ServiceInterface); } + } + + /// + /// Creates new instance of the web service proxy. + /// + /// New instance of the web service proxy. + public virtual object GetObject() + { + if (proxyConstructor == null) + { + GenerateProxy(); + } + + return ObjectUtils.InstantiateType(proxyConstructor, ObjectUtils.EmptyObjects); + } + + /// + /// Always returns false. + /// + public virtual bool IsSingleton + { + get { return false; } + } + + /// + /// Gets or sets the template object definition + /// that should be used to configure proxy instance. + /// + public virtual IObjectDefinition ProductTemplate + { + get { return _productTemplate; } + set { _productTemplate = value; } + } + + #endregion + + #region IInitializingObject Members + + /// + /// Initializes factory object. + /// + public virtual void AfterPropertiesSet() + { + ValidateConfiguration(); + } + + #endregion + + #region Protected Methods + + /// + /// Validates the configuration. + /// + protected virtual void ValidateConfiguration() + { + if (ServiceUri == null && ProxyType == null) + { + throw new ArgumentException("ServiceUri or ProxyType property is required."); + } + + if (ServiceInterface == null) + { + throw new ArgumentException("The ServiceInterface property is required."); + } + + if (!ServiceInterface.IsInterface) + { + throw new ArgumentException("ServiceInterface must be an interface"); + } + + if (WebServiceProxyBaseType.IsSealed) + { + throw new ArgumentException("Web service client proxy cannot be created for a sealed class [" + WebServiceProxyBaseType.FullName + "]"); + } + } + + /// + /// Generates the web service proxy type. + /// + protected virtual void GenerateProxy() + { + IProxyTypeBuilder builder; + if (ProxyType != null) + { + // Wrap .NET generated proxy class or another + builder = new WebServiceProxyProxyTypeBuilder(); + builder.TargetType = ProxyType; + } + else + { + // Dynamically generates proxy class from WSDL + builder = new SoapHttpClientProxyTypeBuilder( + ServiceUri, GetWsDocuments(ServiceUri), BindingName); + builder.BaseType = WebServiceProxyBaseType; + } + + builder.Interfaces = ReflectionUtils.ToInterfaceArray(ServiceInterface); + builder.TypeAttributes = TypeAttributes; + builder.MemberAttributes = MemberAttributes; + + Type wrapper = builder.BuildProxyType(); + + proxyConstructor = wrapper.GetConstructor(Type.EmptyTypes); + + #region Instrumentation + + if (LOG.IsEnabled(LogLevel.Debug)) + { + if (ServiceUri != null) + { + LOG.LogDebug(String.Format("Generated client proxy type [{0}] for web service [{1}]", wrapper.FullName, + ServiceUri.Description)); + } + else if (ProxyType != null) + { + LOG.LogDebug(String.Format("Generated client proxy type [{0}] for web service based on provided proxy type [{1}]", wrapper.FullName, + ProxyType.FullName)); + } + } + + #endregion + } + + #endregion + + #region Private Methods + + /// + /// Gets XML Web Services documents from a Spring resource. + /// + private DiscoveryClientDocumentCollection GetWsDocuments(IResource resource) + { + try + { + if (ServiceUri is UrlResource || + ServiceUri is FileSystemResource) + { + DiscoveryClientProtocol dcProtocol = new DiscoveryClientProtocol(); + dcProtocol.AllowAutoRedirect = true; + dcProtocol.Credentials = CreateCredentials(); + dcProtocol.Proxy = ConfigureProxy(); + dcProtocol.DiscoverAny(resource.Uri.AbsoluteUri); + dcProtocol.ResolveAll(); + + return dcProtocol.Documents; + } + else + { + DiscoveryClientDocumentCollection dcdc = new DiscoveryClientDocumentCollection(); + dcdc[resource.Description] = ServiceDescription.Read(resource.InputStream); + return dcdc; + } + } + catch (Exception ex) + { + throw new ArgumentException(String.Format("Couldn't retrieve the description of the web service located at '{0}'.", resource.Description), ex); + } + } + + private IWebProxy ConfigureProxy() + { + IWebProxy webProxy = null; + if (ProxyUrl != null) + { + webProxy = new WebProxy(ProxyUrl); + } + + if (ProxyCredential != null) + { + if (webProxy == null) + { + webProxy = WebRequest.DefaultWebProxy; + } + + webProxy.Credentials = ProxyCredential; + } + + return webProxy; + } + + private ICredentials CreateCredentials() + { + if (Credential != null) + { + CredentialCache credentialCache = new CredentialCache(); + + Uri wsUri = new Uri(ServiceUri.Uri.AbsoluteUri.Substring(0, ServiceUri.Uri.AbsoluteUri.Length - ServiceUri.Uri.AbsolutePath.Length)); + IEnumerator enumerator = AuthenticationManager.RegisteredModules; + while (enumerator.MoveNext()) + { + credentialCache.Add(wsUri, ((IAuthenticationModule) enumerator.Current).AuthenticationType, Credential); + } + + return credentialCache; + } + else + { + return CredentialCache.DefaultCredentials; + } + } + + #endregion + + #region SoapHttpClientProxyTypeBuilder inner class implementation + + /// + /// Proxy type builder that can be used to create a proxy for + /// derived classes. + /// + private sealed class SoapHttpClientProxyTypeBuilder : AbstractProxyTypeBuilder { #region Logging - private static readonly ILogger LOG = LogManager.GetLogger(); + private static readonly ILogger LOG = LogManager.GetLogger(); #endregion #region Fields - private IObjectDefinition _productTemplate; - private Type _webServiceProxyBaseType = typeof(SoapHttpClientProtocol); - private IResource _serviceUri; - private Type _proxyType; - private Type _serviceInterface; - private NetworkCredential _credential; - private string _proxyUrl; - private NetworkCredential _proxyCredential; - private string _bindingName; - private IList _typeAttributes = new ArrayList(); - private IDictionary _memberAttributes = new Hashtable(); + // Binding/Type related + private IResource serviceUri; + private ServiceDescriptionCollection wsDescriptions; + private XmlSchemaImporter schemaImporter; + private Binding wsBinding; + private string wsUrl; - /// - /// The web service proxy default constructor. - /// - protected ConstructorInfo proxyConstructor; + // Operation/Method related + private Operation operation; + private OperationBinding operationBinding; + private SoapOperationBinding soapOperationBinding; + private XmlMembersMapping inputMembersMapping; + private XmlMembersMapping outputMembersMapping; #endregion @@ -85,186 +460,69 @@ namespace Spring.Web.Services /// /// Creates a new instance of the - /// class. + /// class. /// - public WebServiceProxyFactory() + /// The URI that contains the Web Service meta info (WSDL). + /// The XML Web Service documents to use to create the proxy. + /// The name of the Web Service binding to use. + public SoapHttpClientProxyTypeBuilder(IResource serviceUri, + DiscoveryClientDocumentCollection wsDocuments, string bindingName) { + this.serviceUri = serviceUri; + + Name = "SoapHttpClientProxy"; + ProxyTargetAttributes = false; + + Initialize(wsDocuments, bindingName); } #endregion - #region Properties + #region IProxyTypeBuilder Members /// - /// Gets or sets the base type that web service proxy should inherit. + /// Creates the proxy type. /// - /// - /// Default is - /// - public Type WebServiceProxyBaseType + /// The generated proxy class. + public override Type BuildProxyType() { - get { return _webServiceProxyBaseType; } - set { _webServiceProxyBaseType = value; } - } - - /// - /// Gets or sets the URI for an - /// that contains the web service description (WSDL). - /// - public IResource ServiceUri - { - get { return _serviceUri; } - set { _serviceUri = value; } - } - - /// - /// Gets or sets type of the proxy class to wrap. - /// - public Type ProxyType - { - get { return _proxyType; } - set { _proxyType = value; } - } - - /// - /// Gets or sets service interface that proxy should implement. - /// - public Type ServiceInterface - { - get { return _serviceInterface; } - set { _serviceInterface = value; } - } - - /// - /// Gets or sets the instance - /// to use when connecting to a server that requires authentication. - /// - public NetworkCredential Credential - { - get { return _credential; } - set { _credential = value; } - } - - /// - /// Gets or sets the url of the proxy server to use for retrieving the WSDL. - /// - /// - ///

- /// This only applies when using an as uri. - ///

- ///

- /// The default is to use the system proxy setting. - ///

- ///
- public string ProxyUrl - { - get { return _proxyUrl; } - set { _proxyUrl = value; } - } - - /// - /// Gets or sets the instance - /// to use when connecting to a proxy server that requires authentication. - /// - /// - ///

- /// This only applies when using an as uri. - ///

- ///
- public NetworkCredential ProxyCredential - { - get { return _proxyCredential; } - set { _proxyCredential = value; } - } - - /// - /// Gets or sets the web service binding name to use for the proxy. - /// - public string BindingName - { - get { return _bindingName; } - set { _bindingName = value; } - } - - /// - /// Gets or sets a list of custom attributes - /// that should be applied to a proxy class. - /// - public IList TypeAttributes - { - get { return _typeAttributes; } - set { _typeAttributes = value; } - } - - /// - /// Gets or sets a dictionary of custom attributes - /// that should be applied to web service members. - /// - /// - /// Dictionary key is an expression that members can be matched against. - /// Value is a list of attributes that should be applied - /// to each member that matches expression. - /// - public IDictionary MemberAttributes - { - get { return _memberAttributes; } - set { _memberAttributes = value; } - } - - #endregion - - #region IConfigurableFactoryObject Members - - /// - /// Returns type of the web service proxy. - /// - public virtual Type ObjectType - { - get { return (proxyConstructor != null ? proxyConstructor.DeclaringType : ServiceInterface); } - } - - /// - /// Creates new instance of the web service proxy. - /// - /// New instance of the web service proxy. - public virtual object GetObject() - { - if (proxyConstructor == null) + if (Interfaces == null || Interfaces.Count == 0) { - GenerateProxy(); + throw new ArgumentException( + "Web service client proxy must implement at least one interface."); } - return ObjectUtils.InstantiateType(proxyConstructor, ObjectUtils.EmptyObjects); - } + TypeBuilder typeBuilder = CreateTypeBuilder(Name, BaseType); - /// - /// Always returns false. - /// - public virtual bool IsSingleton - { - get { return false; } - } + // apply custom attributes to the proxy type. + ApplyTypeAttributes(typeBuilder, TargetType); - /// - /// Gets or sets the template object definition - /// that should be used to configure proxy instance. - /// - public virtual IObjectDefinition ProductTemplate - { - get { return _productTemplate; } - set { _productTemplate = value; } + // create constructors + ImplementConstructors(typeBuilder); + + // implement service interfaces + foreach (Type intf in Interfaces) + { + ImplementInterface(typeBuilder, + new SoapHttpClientProxyMethodBuilder(typeBuilder, this), + intf, TargetType); + } + + return typeBuilder.CreateType(); } #endregion - #region IInitializingObject Members + #region IProxyTypeGenerator Members /// - /// Initializes factory object. + /// Generates the IL instructions that pushes + /// the target instance on which calls should be delegated to. /// - public virtual void AfterPropertiesSet() + /// The IL generator to use. + public override void PushTarget(ILGenerator il) { - ValidateConfiguration(); + PushProxy(il); } #endregion @@ -272,381 +530,133 @@ namespace Spring.Web.Services #region Protected Methods /// - /// Validates the configuration. + /// Implements constructors for the proxy class. /// - protected virtual void ValidateConfiguration() + /// + /// The to use. + /// + protected override void ImplementConstructors(TypeBuilder builder) { - if (ServiceUri == null && ProxyType == null) - { - throw new ArgumentException("ServiceUri or ProxyType property is required."); - } - if (ServiceInterface == null) - { - throw new ArgumentException("The ServiceInterface property is required."); - } - if (!ServiceInterface.IsInterface) - { - throw new ArgumentException("ServiceInterface must be an interface"); - } - if (WebServiceProxyBaseType.IsSealed) - { - throw new ArgumentException("Web service client proxy cannot be created for a sealed class [" + WebServiceProxyBaseType.FullName + "]"); - } + MethodAttributes attributes = MethodAttributes.Public | + MethodAttributes.HideBySig | MethodAttributes.SpecialName | + MethodAttributes.RTSpecialName; + ConstructorBuilder cb = builder.DefineConstructor(attributes, + CallingConventions.Standard, Type.EmptyTypes); + + ILGenerator il = cb.GetILGenerator(); + + PushProxy(il); + il.Emit(OpCodes.Call, this.BaseType.GetConstructor(Type.EmptyTypes)); + + // Set Url Property + PushProxy(il); + il.Emit(OpCodes.Ldstr, this.wsUrl); + il.Emit(OpCodes.Call, this.BaseType.GetMethod("set_Url", BindingFlags.Public | BindingFlags.Instance)); + + il.Emit(OpCodes.Ret); } - /// - /// Generates the web service proxy type. - /// - protected virtual void GenerateProxy() + protected override void ApplyMethodAttributes( + MethodBuilder methodBuilder, MethodInfo targetMethod) { - IProxyTypeBuilder builder; - if (ProxyType != null) - { - // Wrap .NET generated proxy class or another - builder = new WebServiceProxyProxyTypeBuilder(); - builder.TargetType = ProxyType; - } - else - { - // Dynamically generates proxy class from WSDL - builder = new SoapHttpClientProxyTypeBuilder( - ServiceUri, GetWsDocuments(ServiceUri), BindingName); - builder.BaseType = WebServiceProxyBaseType; - } + MoveToMethod(targetMethod); - builder.Interfaces = ReflectionUtils.ToInterfaceArray(ServiceInterface); - builder.TypeAttributes = TypeAttributes; - builder.MemberAttributes = MemberAttributes; - - Type wrapper = builder.BuildProxyType(); - - proxyConstructor = wrapper.GetConstructor(Type.EmptyTypes); - - #region Instrumentation - - if (LOG.IsEnabled(LogLevel.Debug)) - { - if (ServiceUri != null) - { - LOG.LogDebug(String.Format("Generated client proxy type [{0}] for web service [{1}]", wrapper.FullName, - ServiceUri.Description)); - } - else if (ProxyType != null) - { - LOG.LogDebug(String.Format("Generated client proxy type [{0}] for web service based on provided proxy type [{1}]", wrapper.FullName, - ProxyType.FullName)); - } - } - - #endregion + base.ApplyMethodAttributes(methodBuilder, targetMethod); } - #endregion - - #region Private Methods - - /// - /// Gets XML Web Services documents from a Spring resource. - /// - private DiscoveryClientDocumentCollection GetWsDocuments(IResource resource) + protected override IList GetTypeAttributes(Type type) { - try - { - if (ServiceUri is UrlResource || - ServiceUri is FileSystemResource) - { - DiscoveryClientProtocol dcProtocol = new DiscoveryClientProtocol(); - dcProtocol.AllowAutoRedirect = true; - dcProtocol.Credentials = CreateCredentials(); - dcProtocol.Proxy = ConfigureProxy(); - dcProtocol.DiscoverAny(resource.Uri.AbsoluteUri); - dcProtocol.ResolveAll(); + IList attrs = base.GetTypeAttributes(type); - return dcProtocol.Documents; - } - else - { - DiscoveryClientDocumentCollection dcdc = new DiscoveryClientDocumentCollection(); - dcdc[resource.Description] = ServiceDescription.Read(resource.InputStream); - return dcdc; - } - } - catch (Exception ex) - { - throw new ArgumentException(String.Format("Couldn't retrieve the description of the web service located at '{0}'.", resource.Description), ex); - } + // Add the WebServiceBindingAttribute + attrs.Add(CreateWebServiceBindingAttribute(this.wsBinding)); + + return attrs; } - private IWebProxy ConfigureProxy() + protected override IList GetMethodAttributes(MethodInfo method) { - IWebProxy webProxy = null; - if (ProxyUrl != null) - { - webProxy = new WebProxy(ProxyUrl); - } - if (ProxyCredential != null) - { - if (webProxy == null) - { - webProxy = WebRequest.DefaultWebProxy; - } - webProxy.Credentials = ProxyCredential; - } + IList attrs = base.GetMethodAttributes(method); - return webProxy; + // Add the SoapMethodAttribute + attrs.Add(CreateSoapMethodAttribute( + operation, operationBinding, soapOperationBinding, inputMembersMapping, outputMembersMapping)); + + return attrs; } - private ICredentials CreateCredentials() + protected override IList GetMethodReturnTypeAttributes(MethodInfo method) { - if (Credential != null) - { - CredentialCache credentialCache = new CredentialCache(); + IList attrs = base.GetMethodReturnTypeAttributes(method); - Uri wsUri = new Uri(ServiceUri.Uri.AbsoluteUri.Substring(0, ServiceUri.Uri.AbsoluteUri.Length - ServiceUri.Uri.AbsolutePath.Length)); - IEnumerator enumerator = AuthenticationManager.RegisteredModules; - while (enumerator.MoveNext()) + // Add the XmlElementAttribute if needed + if (operation.Messages.Output != null) + { + if (method.ReturnType != typeof(void)) { - credentialCache.Add(wsUri, ((IAuthenticationModule)enumerator.Current).AuthenticationType, Credential); - } - - return credentialCache; - } - else - { - return CredentialCache.DefaultCredentials; - } - } - - #endregion - - #region SoapHttpClientProxyTypeBuilder inner class implementation - - /// - /// Proxy type builder that can be used to create a proxy for - /// derived classes. - /// - private sealed class SoapHttpClientProxyTypeBuilder : AbstractProxyTypeBuilder - { - #region Logging - - private static readonly ILogger LOG = LogManager.GetLogger(); - - #endregion - - #region Fields - - // Binding/Type related - private IResource serviceUri; - private ServiceDescriptionCollection wsDescriptions; - private XmlSchemaImporter schemaImporter; - private Binding wsBinding; - private string wsUrl; - - // Operation/Method related - private Operation operation; - private OperationBinding operationBinding; - private SoapOperationBinding soapOperationBinding; - private XmlMembersMapping inputMembersMapping; - private XmlMembersMapping outputMembersMapping; - - #endregion - - #region Constructor(s) / Destructor - - /// - /// Creates a new instance of the - /// class. - /// - /// The URI that contains the Web Service meta info (WSDL). - /// The XML Web Service documents to use to create the proxy. - /// The name of the Web Service binding to use. - public SoapHttpClientProxyTypeBuilder(IResource serviceUri, - DiscoveryClientDocumentCollection wsDocuments, string bindingName) - { - this.serviceUri = serviceUri; - - Name = "SoapHttpClientProxy"; - ProxyTargetAttributes = false; - - Initialize(wsDocuments, bindingName); - } - - #endregion - - #region IProxyTypeBuilder Members - - /// - /// Creates the proxy type. - /// - /// The generated proxy class. - public override Type BuildProxyType() - { - if (Interfaces == null || Interfaces.Count == 0) - { - throw new ArgumentException( - "Web service client proxy must implement at least one interface."); - } - - TypeBuilder typeBuilder = CreateTypeBuilder(Name, BaseType); - - // apply custom attributes to the proxy type. - ApplyTypeAttributes(typeBuilder, TargetType); - - // create constructors - ImplementConstructors(typeBuilder); - - // implement service interfaces - foreach (Type intf in Interfaces) - { - ImplementInterface(typeBuilder, - new SoapHttpClientProxyMethodBuilder(typeBuilder, this), - intf, TargetType); - } - - return typeBuilder.CreateType(); - } - - #endregion - - #region IProxyTypeGenerator Members - - /// - /// Generates the IL instructions that pushes - /// the target instance on which calls should be delegated to. - /// - /// The IL generator to use. - public override void PushTarget(ILGenerator il) - { - PushProxy(il); - } - - #endregion - - #region Protected Methods - - /// - /// Implements constructors for the proxy class. - /// - /// - /// The to use. - /// - protected override void ImplementConstructors(TypeBuilder builder) - { - MethodAttributes attributes = MethodAttributes.Public | - MethodAttributes.HideBySig | MethodAttributes.SpecialName | - MethodAttributes.RTSpecialName; - ConstructorBuilder cb = builder.DefineConstructor(attributes, - CallingConventions.Standard, Type.EmptyTypes); - - ILGenerator il = cb.GetILGenerator(); - - PushProxy(il); - il.Emit(OpCodes.Call, this.BaseType.GetConstructor(Type.EmptyTypes)); - - // Set Url Property - PushProxy(il); - il.Emit(OpCodes.Ldstr, this.wsUrl); - il.Emit(OpCodes.Call, this.BaseType.GetMethod("set_Url", BindingFlags.Public | BindingFlags.Instance)); - - il.Emit(OpCodes.Ret); - } - - protected override void ApplyMethodAttributes( - MethodBuilder methodBuilder, MethodInfo targetMethod) - { - MoveToMethod(targetMethod); - - base.ApplyMethodAttributes(methodBuilder, targetMethod); - } - - protected override IList GetTypeAttributes(Type type) - { - IList attrs = base.GetTypeAttributes(type); - - // Add the WebServiceBindingAttribute - attrs.Add(CreateWebServiceBindingAttribute(this.wsBinding)); - - return attrs; - } - - protected override IList GetMethodAttributes(MethodInfo method) - { - IList attrs = base.GetMethodAttributes(method); - - // Add the SoapMethodAttribute - attrs.Add(CreateSoapMethodAttribute( - operation, operationBinding, soapOperationBinding, inputMembersMapping, outputMembersMapping)); - - return attrs; - } - - protected override IList GetMethodReturnTypeAttributes(MethodInfo method) - { - IList attrs = base.GetMethodReturnTypeAttributes(method); - - // Add the XmlElementAttribute if needed - if (operation.Messages.Output != null) - { - if (method.ReturnType != typeof(void)) + if (outputMembersMapping.Count > 0) { - if (outputMembersMapping.Count > 0) + XmlMemberMapping outMemberMapping = outputMembersMapping[0]; + bool useMemberName = (outMemberMapping.MemberName != operation.Name + "Result"); + bool useNamespace = outMemberMapping.Namespace != outputMembersMapping.Namespace; + bool useTypeNamespace = outMemberMapping.TypeNamespace != XmlSchema.Namespace && + outMemberMapping.TypeNamespace != outputMembersMapping.Namespace; + if (useMemberName || useNamespace || useTypeNamespace) { - XmlMemberMapping outMemberMapping = outputMembersMapping[0]; - bool useMemberName = (outMemberMapping.MemberName != operation.Name + "Result"); - bool useNamespace = outMemberMapping.Namespace != outputMembersMapping.Namespace; - bool useTypeNamespace = outMemberMapping.TypeNamespace != XmlSchema.Namespace && - outMemberMapping.TypeNamespace != outputMembersMapping.Namespace; - if (useMemberName || useNamespace || useTypeNamespace) + if (outMemberMapping.TypeName.StartsWith("ArrayOf", StringComparison.Ordinal)) { - if (outMemberMapping.TypeName.StartsWith ("ArrayOf", StringComparison.Ordinal)) + if (useMemberName || useNamespace) { - if (useMemberName || useNamespace) + ReflectionUtils.CustomAttributeBuilderBuilder cabb = + new ReflectionUtils.CustomAttributeBuilderBuilder(typeof(XmlArrayAttribute)); + if (useMemberName) { - ReflectionUtils.CustomAttributeBuilderBuilder cabb = - new ReflectionUtils.CustomAttributeBuilderBuilder(typeof(XmlArrayAttribute)); - if (useMemberName) - { - cabb.AddPropertyValue("ElementName", outMemberMapping.MemberName); - } - if (useNamespace) - { - cabb.AddPropertyValue("Namespace", outMemberMapping.Namespace); - } - attrs.Add(cabb.Build()); + cabb.AddPropertyValue("ElementName", outMemberMapping.MemberName); } - if (useTypeNamespace) + + if (useNamespace) { - ReflectionUtils.CustomAttributeBuilderBuilder cabb = - new ReflectionUtils.CustomAttributeBuilderBuilder(typeof(XmlArrayItemAttribute)); - cabb.AddPropertyValue("Namespace", outMemberMapping.TypeNamespace); - attrs.Add(cabb.Build()); + cabb.AddPropertyValue("Namespace", outMemberMapping.Namespace); } + + attrs.Add(cabb.Build()); } - else + + if (useTypeNamespace) { - if (useMemberName || useNamespace) + ReflectionUtils.CustomAttributeBuilderBuilder cabb = + new ReflectionUtils.CustomAttributeBuilderBuilder(typeof(XmlArrayItemAttribute)); + cabb.AddPropertyValue("Namespace", outMemberMapping.TypeNamespace); + attrs.Add(cabb.Build()); + } + } + else + { + if (useMemberName || useNamespace) + { + ReflectionUtils.CustomAttributeBuilderBuilder cabb = + new ReflectionUtils.CustomAttributeBuilderBuilder(typeof(XmlElementAttribute)); + if (useMemberName) { - ReflectionUtils.CustomAttributeBuilderBuilder cabb = - new ReflectionUtils.CustomAttributeBuilderBuilder(typeof(XmlElementAttribute)); - if (useMemberName) - { - cabb.AddPropertyValue("ElementName", outMemberMapping.MemberName); - } - if (useNamespace) - { - cabb.AddPropertyValue("Namespace", outMemberMapping.Namespace); - } - attrs.Add(cabb.Build()); + cabb.AddPropertyValue("ElementName", outMemberMapping.MemberName); } + + if (useNamespace) + { + cabb.AddPropertyValue("Namespace", outMemberMapping.Namespace); + } + + attrs.Add(cabb.Build()); } } } } } - - return attrs; } + return attrs; + } + /* protected override IList GetMethodParameterAttributes(MethodInfo method, ParameterInfo paramInfo) { @@ -667,434 +677,304 @@ namespace Spring.Web.Services } */ - #endregion + #endregion - #region Private Methods + #region Private Methods - private void Initialize(DiscoveryClientDocumentCollection wsDocuments, string bindingName) + private void Initialize(DiscoveryClientDocumentCollection wsDocuments, string bindingName) + { + // Service descriptions + this.wsDescriptions = new ServiceDescriptionCollection(); + XmlSchemas schemas = new XmlSchemas(); + foreach (DictionaryEntry entry in wsDocuments) { - // Service descriptions - this.wsDescriptions = new ServiceDescriptionCollection(); - XmlSchemas schemas = new XmlSchemas(); - foreach (DictionaryEntry entry in wsDocuments) + if (entry.Value is ServiceDescription) { - if (entry.Value is ServiceDescription) - { - this.wsDescriptions.Add((ServiceDescription)entry.Value); - } - if (entry.Value is XmlSchema) - { - schemas.Add((XmlSchema)entry.Value); - } + this.wsDescriptions.Add((ServiceDescription) entry.Value); } - // XmlSchemaImporter - foreach (ServiceDescription serviceDescription in this.wsDescriptions) + if (entry.Value is XmlSchema) { - foreach (XmlSchema schema in serviceDescription.Types.Schemas) - { - if (schemas[schema.TargetNamespace] == null) - { - schemas.Add(schema); - } - } + schemas.Add((XmlSchema) entry.Value); } - this.schemaImporter = new XmlSchemaImporter(schemas); - - this.wsBinding = GetWsBinding(this.wsDescriptions, bindingName); - this.wsUrl = GetWsUrl(this.wsDescriptions, this.wsBinding); } - /// - /// Search and returns the binding for the specified name. - /// - private Binding GetWsBinding(ServiceDescriptionCollection serviceDescriptions, string bindingName) + // XmlSchemaImporter + foreach (ServiceDescription serviceDescription in this.wsDescriptions) { - if (bindingName != null) + foreach (XmlSchema schema in serviceDescription.Types.Schemas) { - // Search for a specific binding - foreach (ServiceDescription description in serviceDescriptions) + if (schemas[schema.TargetNamespace] == null) { - foreach (Binding binding in description.Bindings) - { - if (binding.Name == bindingName) - { - return binding; - } - } + schemas.Add(schema); } - throw new ApplicationException(String.Format("Binding '{0}' does not exist in the WSDL document located at '{1}'", bindingName, this.serviceUri.Description)); } - else + } + + this.schemaImporter = new XmlSchemaImporter(schemas); + + this.wsBinding = GetWsBinding(this.wsDescriptions, bindingName); + this.wsUrl = GetWsUrl(this.wsDescriptions, this.wsBinding); + } + + /// + /// Search and returns the binding for the specified name. + /// + private Binding GetWsBinding(ServiceDescriptionCollection serviceDescriptions, string bindingName) + { + if (bindingName != null) + { + // Search for a specific binding + foreach (ServiceDescription description in serviceDescriptions) { - // Use the first one - foreach (ServiceDescription description in serviceDescriptions) + foreach (Binding binding in description.Bindings) { - foreach (Binding binding in description.Bindings) + if (binding.Name == bindingName) { - #region Instrumentation - - if (LOG.IsEnabled(LogLevel.Information)) - { - LOG.LogInformation(String.Format("The binding '{0}', found in the WSDL document located at '{1}', will be use.", binding.Name, this.serviceUri.Description)); - } - - #endregion - return binding; } } - throw new ApplicationException(String.Format("No bindings exists in the WSDL document located at '{0}'", this.serviceUri.Description)); } - } - /// - /// Search and returns the url for the specified binding. - /// - private string GetWsUrl(ServiceDescriptionCollection serviceDescriptions, Binding binding) + throw new ApplicationException(String.Format("Binding '{0}' does not exist in the WSDL document located at '{1}'", bindingName, this.serviceUri.Description)); + } + else { + // Use the first one foreach (ServiceDescription description in serviceDescriptions) { - foreach (Service service in description.Services) + foreach (Binding binding in description.Bindings) { - foreach (Port port in service.Ports) + #region Instrumentation + + if (LOG.IsEnabled(LogLevel.Information)) { - if (port.Binding.Name == binding.Name) - { - SoapAddressBinding soapAddress = (SoapAddressBinding)port.Extensions.Find(typeof(SoapAddressBinding)); - return soapAddress.Location; - } + LOG.LogInformation(String.Format("The binding '{0}', found in the WSDL document located at '{1}', will be use.", binding.Name, this.serviceUri.Description)); } + + #endregion + + return binding; } } - throw new ApplicationException(String.Format("No SoapAddressBinding has been found for binding '{0}' in the WSDL document located at '{1}'.", binding.Name, serviceUri)); - } - /// - /// Search and returns the operation that matches the specified method. - /// - private Operation GetOperation(ServiceDescriptionCollection descriptions, Binding binding, MethodInfo method) + throw new ApplicationException(String.Format("No bindings exists in the WSDL document located at '{0}'", this.serviceUri.Description)); + } + } + + /// + /// Search and returns the url for the specified binding. + /// + private string GetWsUrl(ServiceDescriptionCollection serviceDescriptions, Binding binding) + { + foreach (ServiceDescription description in serviceDescriptions) { - PortType portType = descriptions.GetPortType(binding.Type); - foreach (Operation operation in portType.Operations) + foreach (Service service in description.Services) { - if (operation.Name == method.Name) + foreach (Port port in service.Ports) { - return operation; + if (port.Binding.Name == binding.Name) + { + SoapAddressBinding soapAddress = (SoapAddressBinding) port.Extensions.Find(typeof(SoapAddressBinding)); + return soapAddress.Location; + } } } - throw new ApplicationException(String.Format("No Operation has been found for the method '{0}' in the WSDL document located at '{1}'.", method.Name, serviceUri.Description)); } - /// - /// Search and returns the OperationBinding that matches the specified Operation. - /// - private OperationBinding GetOperationBinding(Operation operation, Binding binding) + throw new ApplicationException(String.Format("No SoapAddressBinding has been found for binding '{0}' in the WSDL document located at '{1}'.", binding.Name, serviceUri)); + } + + /// + /// Search and returns the operation that matches the specified method. + /// + private Operation GetOperation(ServiceDescriptionCollection descriptions, Binding binding, MethodInfo method) + { + PortType portType = descriptions.GetPortType(binding.Type); + foreach (Operation operation in portType.Operations) { - foreach (OperationBinding operationBinding in binding.Operations) + if (operation.Name == method.Name) { - if (operation.IsBoundBy(operationBinding)) - { - return operationBinding; - } + return operation; } - throw new ApplicationException(String.Format("No OperationBinding matches the Operation '{0}' in the WSDL document located at '{2}'.", operation.Name, this.serviceUri.Description)); } - /// - /// Search and returns the type mapping between method parameters/return value - /// and the element parts of a literal-use SOAP message. - /// - private XmlMembersMapping GetMembersMapping(string messageName, MessagePartCollection messageParts, SoapBodyBinding soapBodyBinding, SoapBindingStyle soapBindingStyle) + throw new ApplicationException(String.Format("No Operation has been found for the method '{0}' in the WSDL document located at '{1}'.", method.Name, serviceUri.Description)); + } + + /// + /// Search and returns the OperationBinding that matches the specified Operation. + /// + private OperationBinding GetOperationBinding(Operation operation, Binding binding) + { + foreach (OperationBinding operationBinding in binding.Operations) { - if (soapBindingStyle == SoapBindingStyle.Rpc) + if (operation.IsBoundBy(operationBinding)) { - SoapSchemaMember[] soapSchemaMembers = new SoapSchemaMember[messageParts.Count]; - for (int i = 0; i < messageParts.Count; i++) - { - SoapSchemaMember ssm = new SoapSchemaMember(); - ssm.MemberName = messageParts[i].Name; - ssm.MemberType = messageParts[i].Type; - soapSchemaMembers[i] = ssm; - } - return this.schemaImporter.ImportMembersMapping(messageName, soapBodyBinding.Namespace, soapSchemaMembers); - } - else - { - return this.schemaImporter.ImportMembersMapping(messageParts[0].Element); + return operationBinding; } } - private void MoveToMethod(MethodInfo targetMethod) + throw new ApplicationException(String.Format("No OperationBinding matches the Operation '{0}' in the WSDL document located at '{2}'.", operation.Name, this.serviceUri.Description)); + } + + /// + /// Search and returns the type mapping between method parameters/return value + /// and the element parts of a literal-use SOAP message. + /// + private XmlMembersMapping GetMembersMapping(string messageName, MessagePartCollection messageParts, SoapBodyBinding soapBodyBinding, SoapBindingStyle soapBindingStyle) + { + if (soapBindingStyle == SoapBindingStyle.Rpc) { - operation = GetOperation(this.wsDescriptions, this.wsBinding, targetMethod); - operationBinding = GetOperationBinding(operation, this.wsBinding); - soapOperationBinding = (SoapOperationBinding)operationBinding.Extensions.Find(typeof(SoapOperationBinding)); - - string inputMessageName = (!StringUtils.IsNullOrEmpty(operationBinding.Input.Name) && (soapOperationBinding.Style != SoapBindingStyle.Rpc)) ? operationBinding.Input.Name : operation.Name; - SoapBodyBinding inputSoapBodyBinding = (SoapBodyBinding)operationBinding.Input.Extensions.Find(typeof(SoapBodyBinding)); - - if (inputSoapBodyBinding.Use != SoapBindingUse.Literal) + SoapSchemaMember[] soapSchemaMembers = new SoapSchemaMember[messageParts.Count]; + for (int i = 0; i < messageParts.Count; i++) { - throw new NotSupportedException("WebServiceProxyFactory only supports document-literal and rpc-literal SOAP messages to conform to WS-I Basic Profiles."); + SoapSchemaMember ssm = new SoapSchemaMember(); + ssm.MemberName = messageParts[i].Name; + ssm.MemberType = messageParts[i].Type; + soapSchemaMembers[i] = ssm; } - Message inputMessage = this.wsDescriptions.GetMessage(operation.Messages.Input.Message); - inputMembersMapping = GetMembersMapping(inputMessageName, inputMessage.Parts, inputSoapBodyBinding, soapOperationBinding.Style); - - outputMembersMapping = null; - if (operation.Messages.Output != null) - { - string outputMessageName = (!StringUtils.IsNullOrEmpty(operationBinding.Output.Name) && (soapOperationBinding.Style != SoapBindingStyle.Rpc)) ? operationBinding.Output.Name : (operation.Name + "Response"); - SoapBodyBinding outputSoapBodyBinding = (SoapBodyBinding)operationBinding.Output.Extensions.Find(typeof(SoapBodyBinding)); - Message outputMessage = this.wsDescriptions.GetMessage(operation.Messages.Output.Message); - outputMembersMapping = GetMembersMapping(outputMessageName, outputMessage.Parts, outputSoapBodyBinding, soapOperationBinding.Style); - } + return this.schemaImporter.ImportMembersMapping(messageName, soapBodyBinding.Namespace, soapSchemaMembers); } - - /// - /// Creates a that should be applied to proxy type. - /// - private CustomAttributeBuilder CreateWebServiceBindingAttribute(Binding wsBinding) + else { - ReflectionUtils.CustomAttributeBuilderBuilder cabb = - new ReflectionUtils.CustomAttributeBuilderBuilder(typeof(WebServiceBindingAttribute)); - - cabb.AddContructorArgument(this.wsBinding.Name); - cabb.AddPropertyValue("Namespace", this.wsBinding.ServiceDescription.TargetNamespace); - - return cabb.Build(); + return this.schemaImporter.ImportMembersMapping(messageParts[0].Element); } + } - /// - /// Creates a or a - /// that should be applied to proxy method. - /// - private static CustomAttributeBuilder CreateSoapMethodAttribute(Operation operation, - OperationBinding operationBinding, SoapOperationBinding soapOperationBinding, - XmlMembersMapping inputMembersMapping, XmlMembersMapping outputMembersMapping) + private void MoveToMethod(MethodInfo targetMethod) + { + operation = GetOperation(this.wsDescriptions, this.wsBinding, targetMethod); + operationBinding = GetOperationBinding(operation, this.wsBinding); + soapOperationBinding = (SoapOperationBinding) operationBinding.Extensions.Find(typeof(SoapOperationBinding)); + + string inputMessageName = (!StringUtils.IsNullOrEmpty(operationBinding.Input.Name) && (soapOperationBinding.Style != SoapBindingStyle.Rpc)) ? operationBinding.Input.Name : operation.Name; + SoapBodyBinding inputSoapBodyBinding = (SoapBodyBinding) operationBinding.Input.Extensions.Find(typeof(SoapBodyBinding)); + + if (inputSoapBodyBinding.Use != SoapBindingUse.Literal) { - ReflectionUtils.CustomAttributeBuilderBuilder cabb; - - string inputMembersMappingElementName = inputMembersMapping.ElementName; - string inputMembersMappingNamespace = inputMembersMapping.Namespace; - - if (soapOperationBinding.Style == SoapBindingStyle.Rpc) - { - cabb = new ReflectionUtils.CustomAttributeBuilderBuilder(typeof(SoapRpcMethodAttribute)); - } - else - { - cabb = new ReflectionUtils.CustomAttributeBuilderBuilder(typeof(SoapDocumentMethodAttribute)); - cabb.AddPropertyValue("ParameterStyle", SoapParameterStyle.Wrapped); - } - - cabb.AddContructorArgument(soapOperationBinding.SoapAction); - cabb.AddPropertyValue("Use", SoapBindingUse.Literal); - - if (inputMembersMappingElementName.Length > 0 && - inputMembersMappingElementName != operation.Name) - { - cabb.AddPropertyValue("RequestElementName", inputMembersMappingElementName); - } - - if (inputMembersMappingNamespace != null) - { - cabb.AddPropertyValue("RequestNamespace", inputMembersMappingNamespace); - } - - if (outputMembersMapping == null) - { - cabb.AddPropertyValue("OneWay", true); - } - else - { - string outputMembersMappingElementName = outputMembersMapping.ElementName; - string outputMembersMappingNamespace = outputMembersMapping.Namespace; - - if (outputMembersMappingElementName.Length > 0 && - outputMembersMappingElementName != (operation.Name + "Response")) - { - cabb.AddPropertyValue("ResponseElementName", outputMembersMappingElementName); - } - - if (outputMembersMappingNamespace != null) - { - cabb.AddPropertyValue("ResponseNamespace", outputMembersMappingNamespace); - } - } - - return cabb.Build(); + throw new NotSupportedException("WebServiceProxyFactory only supports document-literal and rpc-literal SOAP messages to conform to WS-I Basic Profiles."); } - #endregion + Message inputMessage = this.wsDescriptions.GetMessage(operation.Messages.Input.Message); + inputMembersMapping = GetMembersMapping(inputMessageName, inputMessage.Parts, inputSoapBodyBinding, soapOperationBinding.Style); - #region SoapHttpClientProxyMethodBuilder inner class implementation - - /// - /// Proxy method builder that can be used to create a proxy method - /// for web services operation invocation. - /// - private sealed class SoapHttpClientProxyMethodBuilder : AbstractProxyMethodBuilder + outputMembersMapping = null; + if (operation.Messages.Output != null) { - #region Fields + string outputMessageName = (!StringUtils.IsNullOrEmpty(operationBinding.Output.Name) && (soapOperationBinding.Style != SoapBindingStyle.Rpc)) ? operationBinding.Output.Name : (operation.Name + "Response"); + SoapBodyBinding outputSoapBodyBinding = (SoapBodyBinding) operationBinding.Output.Extensions.Find(typeof(SoapBodyBinding)); + Message outputMessage = this.wsDescriptions.GetMessage(operation.Messages.Output.Message); + outputMembersMapping = GetMembersMapping(outputMessageName, outputMessage.Parts, outputSoapBodyBinding, soapOperationBinding.Style); + } + } - private static readonly MethodInfo Invoke = - typeof(SoapHttpClientProtocol).GetMethod("Invoke", BindingFlags.NonPublic | BindingFlags.Instance); + /// + /// Creates a that should be applied to proxy type. + /// + private CustomAttributeBuilder CreateWebServiceBindingAttribute(Binding wsBinding) + { + ReflectionUtils.CustomAttributeBuilderBuilder cabb = + new ReflectionUtils.CustomAttributeBuilderBuilder(typeof(WebServiceBindingAttribute)); - #endregion + cabb.AddContructorArgument(this.wsBinding.Name); + cabb.AddPropertyValue("Namespace", this.wsBinding.ServiceDescription.TargetNamespace); - #region Constructor(s) / Destructor + return cabb.Build(); + } - /// - /// Creates a new instance of the method builder. - /// - /// The type builder to use. - /// - /// The implementation to use. - /// - public SoapHttpClientProxyMethodBuilder( - TypeBuilder typeBuilder, IProxyTypeGenerator proxyGenerator) - : base(typeBuilder, proxyGenerator, false) - { - } + /// + /// Creates a or a + /// that should be applied to proxy method. + /// + private static CustomAttributeBuilder CreateSoapMethodAttribute(Operation operation, + OperationBinding operationBinding, SoapOperationBinding soapOperationBinding, + XmlMembersMapping inputMembersMapping, XmlMembersMapping outputMembersMapping) + { + ReflectionUtils.CustomAttributeBuilderBuilder cabb; - #endregion + string inputMembersMappingElementName = inputMembersMapping.ElementName; + string inputMembersMappingNamespace = inputMembersMapping.Namespace; - #region Protected Methods - - /// - /// Generates the proxy method. - /// - /// The IL generator to use. - /// The method to proxy. - /// - /// The interface definition of the method, if applicable. - /// - protected override void GenerateMethod( - ILGenerator il, MethodInfo method, MethodInfo interfaceMethod) - { - // In Parameters - ArrayList inParams = new ArrayList(); - // Ref or Out Parameters - ArrayList refOutParams = new ArrayList(); - - foreach (ParameterInfo paramInfo in interfaceMethod.GetParameters()) - { - if (paramInfo.IsRetval || paramInfo.IsOut) - { - refOutParams.Add(paramInfo); - } - else - { - inParams.Add(paramInfo); - } - } - - proxyGenerator.PushTarget(il); - - // Parameter #1 - il.Emit(OpCodes.Ldstr, interfaceMethod.Name); - - // Parameter #2 - LocalBuilder parameters = il.DeclareLocal(typeof(Object[])); - il.Emit(OpCodes.Ldc_I4, inParams.Count); - il.Emit(OpCodes.Newarr, typeof(Object)); - il.Emit(OpCodes.Stloc, parameters); - - int paramIndex = 0; - foreach (ParameterInfo paramInfo in inParams) - { - il.Emit(OpCodes.Ldloc, parameters); - il.Emit(OpCodes.Ldc_I4, paramIndex); - il.Emit(OpCodes.Ldarg, paramInfo.Position + 1); - if (paramInfo.ParameterType.IsValueType) - { - il.Emit(OpCodes.Box, paramInfo.ParameterType); - } - il.Emit(OpCodes.Stelem_Ref); - - paramIndex++; - } - - il.Emit(OpCodes.Ldloc, parameters); - - // Call Invoke method and save result - LocalBuilder results = il.DeclareLocal(typeof(Object[])); - il.EmitCall(OpCodes.Callvirt, Invoke, null); - il.Emit(OpCodes.Stloc, results); - - int resultIndex = (interfaceMethod.ReturnType == typeof(void) ? 0 : 1); - foreach (ParameterInfo paramInfo in refOutParams) - { - il.Emit(OpCodes.Ldarg, paramInfo.Position + 1); - il.Emit(OpCodes.Ldloc, results); - - // Cast / Unbox the return value - il.Emit(OpCodes.Ldc_I4, resultIndex); - il.Emit(OpCodes.Ldelem_Ref); - - Type elementType = paramInfo.ParameterType.GetElementType(); - if (elementType.IsValueType) - { - il.Emit(OpCodes.Unbox, elementType); - il.Emit(OpCodes.Ldobj, elementType); - il.Emit(OpCodes.Stobj, elementType); - } - else - { - il.Emit(OpCodes.Castclass, elementType); - il.Emit(OpCodes.Stind_Ref); - } - - resultIndex++; - } - - if (interfaceMethod.ReturnType != typeof(void)) - { - il.Emit(OpCodes.Ldloc, results); - - // Cast / Unbox the return value - il.Emit(OpCodes.Ldc_I4_0); - il.Emit(OpCodes.Ldelem_Ref); - if (interfaceMethod.ReturnType.IsValueType) - { - il.Emit(OpCodes.Unbox, interfaceMethod.ReturnType); - il.Emit(OpCodes.Ldobj, interfaceMethod.ReturnType); - } - else - { - il.Emit(OpCodes.Castclass, interfaceMethod.ReturnType); - } - } - } - - #endregion + if (soapOperationBinding.Style == SoapBindingStyle.Rpc) + { + cabb = new ReflectionUtils.CustomAttributeBuilderBuilder(typeof(SoapRpcMethodAttribute)); + } + else + { + cabb = new ReflectionUtils.CustomAttributeBuilderBuilder(typeof(SoapDocumentMethodAttribute)); + cabb.AddPropertyValue("ParameterStyle", SoapParameterStyle.Wrapped); } - #endregion + cabb.AddContructorArgument(soapOperationBinding.SoapAction); + cabb.AddPropertyValue("Use", SoapBindingUse.Literal); + + if (inputMembersMappingElementName.Length > 0 && + inputMembersMappingElementName != operation.Name) + { + cabb.AddPropertyValue("RequestElementName", inputMembersMappingElementName); + } + + if (inputMembersMappingNamespace != null) + { + cabb.AddPropertyValue("RequestNamespace", inputMembersMappingNamespace); + } + + if (outputMembersMapping == null) + { + cabb.AddPropertyValue("OneWay", true); + } + else + { + string outputMembersMappingElementName = outputMembersMapping.ElementName; + string outputMembersMappingNamespace = outputMembersMapping.Namespace; + + if (outputMembersMappingElementName.Length > 0 && + outputMembersMappingElementName != (operation.Name + "Response")) + { + cabb.AddPropertyValue("ResponseElementName", outputMembersMappingElementName); + } + + if (outputMembersMappingNamespace != null) + { + cabb.AddPropertyValue("ResponseNamespace", outputMembersMappingNamespace); + } + } + + return cabb.Build(); } #endregion - #region WebServiceProxyProxyTypeBuilder inner class implementation + #region SoapHttpClientProxyMethodBuilder inner class implementation /// - /// Proxy type builder that can be used to create a proxy for - /// .Net-generated proxy class that can be safely cast to a service interface. + /// Proxy method builder that can be used to create a proxy method + /// for web services operation invocation. /// - private sealed class WebServiceProxyProxyTypeBuilder : InheritanceProxyTypeBuilder + private sealed class SoapHttpClientProxyMethodBuilder : AbstractProxyMethodBuilder { + #region Fields + + private static readonly MethodInfo Invoke = + typeof(SoapHttpClientProtocol).GetMethod("Invoke", BindingFlags.NonPublic | BindingFlags.Instance); + + #endregion + #region Constructor(s) / Destructor /// - /// Creates a new instance of the - /// class. + /// Creates a new instance of the method builder. /// - public WebServiceProxyProxyTypeBuilder() + /// The type builder to use. + /// + /// The implementation to use. + /// + public SoapHttpClientProxyMethodBuilder( + TypeBuilder typeBuilder, IProxyTypeGenerator proxyGenerator) + : base(typeBuilder, proxyGenerator, false) { - this.Name = "WebServiceProxyProxy"; - this.DeclaredMembersOnly = true; } #endregion @@ -1102,35 +982,110 @@ namespace Spring.Web.Services #region Protected Methods /// - /// Gets the mapping of the interface to proxy - /// into the actual methods on the target type - /// that does not need to implement that interface. + /// Generates the proxy method. /// - /// - ///

- /// As the proxy type does not implement the interface, - /// we try to find matching methods. - ///

- ///
- /// - /// The of the target object. + /// The IL generator to use. + /// The method to proxy. + /// + /// The interface definition of the method, if applicable. /// - /// The interface to implement. - /// - /// An interface mapping for the interface to proxy. - /// - protected override InterfaceMapping GetInterfaceMapping( - Type targetType, Type intf) + protected override void GenerateMethod( + ILGenerator il, MethodInfo method, MethodInfo interfaceMethod) { - InterfaceMapping mapping; + // In Parameters + ArrayList inParams = new ArrayList(); + // Ref or Out Parameters + ArrayList refOutParams = new ArrayList(); - mapping.TargetType = targetType; - mapping.InterfaceType = intf; - mapping.InterfaceMethods = intf.GetMethods(); - mapping.TargetMethods = ReflectionUtils.GetMatchingMethods( - targetType, mapping.InterfaceMethods, true); + foreach (ParameterInfo paramInfo in interfaceMethod.GetParameters()) + { + if (paramInfo.IsRetval || paramInfo.IsOut) + { + refOutParams.Add(paramInfo); + } + else + { + inParams.Add(paramInfo); + } + } - return mapping; + proxyGenerator.PushTarget(il); + + // Parameter #1 + il.Emit(OpCodes.Ldstr, interfaceMethod.Name); + + // Parameter #2 + LocalBuilder parameters = il.DeclareLocal(typeof(Object[])); + il.Emit(OpCodes.Ldc_I4, inParams.Count); + il.Emit(OpCodes.Newarr, typeof(Object)); + il.Emit(OpCodes.Stloc, parameters); + + int paramIndex = 0; + foreach (ParameterInfo paramInfo in inParams) + { + il.Emit(OpCodes.Ldloc, parameters); + il.Emit(OpCodes.Ldc_I4, paramIndex); + il.Emit(OpCodes.Ldarg, paramInfo.Position + 1); + if (paramInfo.ParameterType.IsValueType) + { + il.Emit(OpCodes.Box, paramInfo.ParameterType); + } + + il.Emit(OpCodes.Stelem_Ref); + + paramIndex++; + } + + il.Emit(OpCodes.Ldloc, parameters); + + // Call Invoke method and save result + LocalBuilder results = il.DeclareLocal(typeof(Object[])); + il.EmitCall(OpCodes.Callvirt, Invoke, null); + il.Emit(OpCodes.Stloc, results); + + int resultIndex = (interfaceMethod.ReturnType == typeof(void) ? 0 : 1); + foreach (ParameterInfo paramInfo in refOutParams) + { + il.Emit(OpCodes.Ldarg, paramInfo.Position + 1); + il.Emit(OpCodes.Ldloc, results); + + // Cast / Unbox the return value + il.Emit(OpCodes.Ldc_I4, resultIndex); + il.Emit(OpCodes.Ldelem_Ref); + + Type elementType = paramInfo.ParameterType.GetElementType(); + if (elementType.IsValueType) + { + il.Emit(OpCodes.Unbox, elementType); + il.Emit(OpCodes.Ldobj, elementType); + il.Emit(OpCodes.Stobj, elementType); + } + else + { + il.Emit(OpCodes.Castclass, elementType); + il.Emit(OpCodes.Stind_Ref); + } + + resultIndex++; + } + + if (interfaceMethod.ReturnType != typeof(void)) + { + il.Emit(OpCodes.Ldloc, results); + + // Cast / Unbox the return value + il.Emit(OpCodes.Ldc_I4_0); + il.Emit(OpCodes.Ldelem_Ref); + if (interfaceMethod.ReturnType.IsValueType) + { + il.Emit(OpCodes.Unbox, interfaceMethod.ReturnType); + il.Emit(OpCodes.Ldobj, interfaceMethod.ReturnType); + } + else + { + il.Emit(OpCodes.Castclass, interfaceMethod.ReturnType); + } + } } #endregion @@ -1138,4 +1093,67 @@ namespace Spring.Web.Services #endregion } + + #endregion + + #region WebServiceProxyProxyTypeBuilder inner class implementation + + /// + /// Proxy type builder that can be used to create a proxy for + /// .Net-generated proxy class that can be safely cast to a service interface. + /// + private sealed class WebServiceProxyProxyTypeBuilder : InheritanceProxyTypeBuilder + { + #region Constructor(s) / Destructor + + /// + /// Creates a new instance of the + /// class. + /// + public WebServiceProxyProxyTypeBuilder() + { + this.Name = "WebServiceProxyProxy"; + this.DeclaredMembersOnly = true; + } + + #endregion + + #region Protected Methods + + /// + /// Gets the mapping of the interface to proxy + /// into the actual methods on the target type + /// that does not need to implement that interface. + /// + /// + ///

+ /// As the proxy type does not implement the interface, + /// we try to find matching methods. + ///

+ ///
+ /// + /// The of the target object. + /// + /// The interface to implement. + /// + /// An interface mapping for the interface to proxy. + /// + protected override InterfaceMapping GetInterfaceMapping( + Type targetType, Type intf) + { + InterfaceMapping mapping; + + mapping.TargetType = targetType; + mapping.InterfaceType = intf; + mapping.InterfaceMethods = intf.GetMethods(); + mapping.TargetMethods = ReflectionUtils.GetMatchingMethods( + targetType, mapping.InterfaceMethods, true); + + return mapping; + } + + #endregion + } + + #endregion } diff --git a/src/Spring/Spring.Template.Velocity.Castle/Template/Velocity/Config/TemplateNamespaceParser.cs b/src/Spring/Spring.Template.Velocity.Castle/Template/Velocity/Config/TemplateNamespaceParser.cs index d09f23af..9390152a 100644 --- a/src/Spring/Spring.Template.Velocity.Castle/Template/Velocity/Config/TemplateNamespaceParser.cs +++ b/src/Spring/Spring.Template.Velocity.Castle/Template/Velocity/Config/TemplateNamespaceParser.cs @@ -22,9 +22,7 @@ using System.Collections; using System.Xml; - using NVelocity.Runtime; - using Spring.Core.TypeResolution; using Spring.Objects; using Spring.Objects.Factory.Config; @@ -34,438 +32,478 @@ using Spring.Util; #endregion -namespace Spring.Template.Velocity.Config { +namespace Spring.Template.Velocity.Config; + +/// +/// Implementation of the custom configuration parser for template configurations +/// based on +/// +/// +/// Erez Mazor +/// +[ + NamespaceParser( + Namespace = "http://www.springframework.net/nvelocity", + SchemaLocationAssemblyHint = typeof(TemplateNamespaceParser), + SchemaLocation = "/Spring.Template.Velocity.Config/spring-nvelocity-1.3.xsd") +] +public class TemplateNamespaceParser : ObjectsNamespaceParser +{ + private const string TemplateTypePrefix = "template: "; + + static TemplateNamespaceParser() + { + TypeRegistry.RegisterType(TemplateTypePrefix + TemplateDefinitionConstants.NVelocityElement, typeof(VelocityEngineFactoryObject)); + } + /// - /// Implementation of the custom configuration parser for template configurations - /// based on - /// + /// Initializes a new instance of the class. /// - /// Erez Mazor - /// - [ - NamespaceParser( - Namespace = "http://www.springframework.net/nvelocity", - SchemaLocationAssemblyHint = typeof(TemplateNamespaceParser), - SchemaLocation = "/Spring.Template.Velocity.Config/spring-nvelocity-1.3.xsd") - ] - public class TemplateNamespaceParser : ObjectsNamespaceParser { - private const string TemplateTypePrefix = "template: "; + public TemplateNamespaceParser() + { + } - static TemplateNamespaceParser() { - TypeRegistry.RegisterType(TemplateTypePrefix + TemplateDefinitionConstants.NVelocityElement, typeof(VelocityEngineFactoryObject)); + /// + public override IObjectDefinition ParseElement(XmlElement element, ParserContext parserContext) + { + string name = element.GetAttribute(ObjectDefinitionConstants.IdAttribute); + IConfigurableObjectDefinition templateDefinition = ParseTemplateDefinition(element, parserContext); + if (!StringUtils.HasText(name)) + { + name = ObjectDefinitionReaderUtils.GenerateObjectName(templateDefinition, parserContext.Registry); } - /// - /// Initializes a new instance of the class. - /// - public TemplateNamespaceParser() { + parserContext.Registry.RegisterObjectDefinition(name, templateDefinition); + return null; + } + + /// + /// Parse a template definition from the templating namespace + /// + /// the root element defining the templating object + /// the parser context + /// + private IConfigurableObjectDefinition ParseTemplateDefinition(XmlElement element, ParserContext parserContext) + { + switch (element.LocalName) + { + case TemplateDefinitionConstants.NVelocityElement: + return ParseNVelocityEngine(element, parserContext); + default: + throw new ArgumentException(string.Format("undefined element for templating namespace: {0}", element.LocalName)); + } + } + + /// + /// Parses the object definition for the engine object, configures a single NVelocity template engine based + /// on the element definitions. + /// + /// the root element defining the velocity engine + /// the parser context + private IConfigurableObjectDefinition ParseNVelocityEngine(XmlElement element, ParserContext parserContext) + { + string typeName = GetTypeName(element); + IConfigurableObjectDefinition configurableObjectDefinition = parserContext.ReaderContext.ObjectDefinitionFactory.CreateObjectDefinition( + typeName, null, parserContext.ReaderContext.Reader.Domain); + + string preferFileSystemAccess = GetAttributeValue(element, TemplateDefinitionConstants.AttributePreferFileSystemAccess); + string overrideLogging = GetAttributeValue(element, TemplateDefinitionConstants.AttributeOverrideLogging); + string configFile = GetAttributeValue(element, TemplateDefinitionConstants.AttributeConfigFile); + + MutablePropertyValues objectDefinitionProperties = new MutablePropertyValues(); + if (StringUtils.HasText(preferFileSystemAccess)) + { + objectDefinitionProperties.Add(TemplateDefinitionConstants.PropertyPreferFileSystemAccess, preferFileSystemAccess); } - /// - public override IObjectDefinition ParseElement(XmlElement element, ParserContext parserContext) { - string name = element.GetAttribute(ObjectDefinitionConstants.IdAttribute); - IConfigurableObjectDefinition templateDefinition = ParseTemplateDefinition(element, parserContext); - if (!StringUtils.HasText(name)) { - name = ObjectDefinitionReaderUtils.GenerateObjectName(templateDefinition, parserContext.Registry); - } - parserContext.Registry.RegisterObjectDefinition(name, templateDefinition); - return null; + if (StringUtils.HasText(overrideLogging)) + { + objectDefinitionProperties.Add(TemplateDefinitionConstants.PropertyOverrideLogging, overrideLogging); } - /// - /// Parse a template definition from the templating namespace - /// - /// the root element defining the templating object - /// the parser context - /// - private IConfigurableObjectDefinition ParseTemplateDefinition(XmlElement element, ParserContext parserContext) { - switch (element.LocalName) { - case TemplateDefinitionConstants.NVelocityElement: - return ParseNVelocityEngine(element, parserContext); - default: - throw new ArgumentException(string.Format("undefined element for templating namespace: {0}", element.LocalName)); - } + if (StringUtils.HasText(configFile)) + { + objectDefinitionProperties.Add(TemplateDefinitionConstants.PropertyConfigFile, configFile); } - /// - /// Parses the object definition for the engine object, configures a single NVelocity template engine based - /// on the element definitions. - /// - /// the root element defining the velocity engine - /// the parser context - private IConfigurableObjectDefinition ParseNVelocityEngine(XmlElement element, ParserContext parserContext) { - string typeName = GetTypeName(element); - IConfigurableObjectDefinition configurableObjectDefinition = parserContext.ReaderContext.ObjectDefinitionFactory.CreateObjectDefinition( - typeName, null, parserContext.ReaderContext.Reader.Domain); - - string preferFileSystemAccess = GetAttributeValue(element, TemplateDefinitionConstants.AttributePreferFileSystemAccess); - string overrideLogging = GetAttributeValue(element, TemplateDefinitionConstants.AttributeOverrideLogging); - string configFile = GetAttributeValue(element, TemplateDefinitionConstants.AttributeConfigFile); - - MutablePropertyValues objectDefinitionProperties = new MutablePropertyValues(); - if (StringUtils.HasText(preferFileSystemAccess)) { - objectDefinitionProperties.Add(TemplateDefinitionConstants.PropertyPreferFileSystemAccess, preferFileSystemAccess); - } - - if (StringUtils.HasText(overrideLogging)) { - objectDefinitionProperties.Add(TemplateDefinitionConstants.PropertyOverrideLogging, overrideLogging); - } - - if (StringUtils.HasText(configFile)) { - objectDefinitionProperties.Add(TemplateDefinitionConstants.PropertyConfigFile, configFile); - } - - XmlNodeList childElements = element.ChildNodes; - if (childElements.Count > 0) { - ParseChildDefinitions(childElements, parserContext, objectDefinitionProperties); - } - configurableObjectDefinition.PropertyValues = objectDefinitionProperties; - return configurableObjectDefinition; + XmlNodeList childElements = element.ChildNodes; + if (childElements.Count > 0) + { + ParseChildDefinitions(childElements, parserContext, objectDefinitionProperties); } - /// - /// Parses child element definitions for the NVelocity engine. Typically resource loaders and locally defined properties are parsed here - /// - /// the XmlNodeList representing the child configuration of the root NVelocity engine element - /// the parser context - /// the MutablePropertyValues used to configure this object - private void ParseChildDefinitions(XmlNodeList childElements, ParserContext parserContext, MutablePropertyValues objectDefinitionProperties) { - IDictionary properties = new Dictionary(); + configurableObjectDefinition.PropertyValues = objectDefinitionProperties; + return configurableObjectDefinition; + } - foreach (XmlElement element in childElements) { - switch (element.LocalName) { - case TemplateDefinitionConstants.ElementResourceLoader: - ParseResourceLoader(element, objectDefinitionProperties, properties); - break; - case TemplateDefinitionConstants.ElementNVelocityProperties: - ParseNVelocityProperties(element, parserContext, properties); - break; - } - } + /// + /// Parses child element definitions for the NVelocity engine. Typically resource loaders and locally defined properties are parsed here + /// + /// the XmlNodeList representing the child configuration of the root NVelocity engine element + /// the parser context + /// the MutablePropertyValues used to configure this object + private void ParseChildDefinitions(XmlNodeList childElements, ParserContext parserContext, MutablePropertyValues objectDefinitionProperties) + { + IDictionary properties = new Dictionary(); - if (properties.Count > 0) { - objectDefinitionProperties.Add(TemplateDefinitionConstants.PropertyVelocityProperties, properties); - } - } - - /// - /// Configures the NVelocity resource loader definitions from the xml definition - /// - /// the root resource loader element - /// the MutablePropertyValues used to configure this object - /// the properties used to initialize the velocity engine - private void ParseResourceLoader(XmlElement element, MutablePropertyValues objectDefinitionProperties, IDictionary properties) { - string caching = GetAttributeValue(element, TemplateDefinitionConstants.AttributeTemplateCaching); - string defaultCacheSize = GetAttributeValue(element, TemplateDefinitionConstants.AttributeDefaultCacheSize); - string modificationCheckInterval = GetAttributeValue(element, TemplateDefinitionConstants.AttributeModificationCheckInterval); - - if (!string.IsNullOrEmpty(defaultCacheSize)) { - properties.Add(RuntimeConstants.RESOURCE_MANAGER_DEFAULTCACHE_SIZE, defaultCacheSize); - } - - XmlNodeList loaderElements = element.ChildNodes; - switch (loaderElements[0].LocalName) { - case VelocityConstants.File: - AppendFileLoaderProperties(loaderElements, properties); - AppendResourceLoaderGlobalProperties(properties, VelocityConstants.File, caching, - modificationCheckInterval); - break; - case VelocityConstants.Assembly: - AppendAssemblyLoaderProperties(loaderElements, properties); - AppendResourceLoaderGlobalProperties(properties, VelocityConstants.Assembly, caching, null); - break; - case TemplateDefinitionConstants.Spring: - AppendResourceLoaderPaths(loaderElements, objectDefinitionProperties); - AppendResourceLoaderGlobalProperties(properties, TemplateDefinitionConstants.Spring, caching, null); - break; - case TemplateDefinitionConstants.Custom: - XmlElement firstElement = (XmlElement)loaderElements.Item(0); - AppendCustomLoaderProperties(firstElement, properties); - AppendResourceLoaderGlobalProperties(properties, firstElement.LocalName, caching, modificationCheckInterval); - break; - default: - throw new ArgumentException(string.Format("undefined element for resource loadre type: {0}", element.LocalName)); - } - } - - - /// - /// Set the caching and modification interval checking properties of a resource loader of a given type - /// - /// the properties used to initialize the velocity engine - /// type of the resource loader - /// caching flag - /// modification interval value - private void AppendResourceLoaderGlobalProperties(IDictionary properties, string type, string caching, string modificationInterval) { - AppendResourceLoaderGlobalProperty(properties, type, - TemplateDefinitionConstants.PropertyResourceLoaderCaching, - Convert.ToBoolean(caching)); - AppendResourceLoaderGlobalProperty - (properties, type, TemplateDefinitionConstants.PropertyResourceLoaderModificationCheckInterval, Convert.ToInt64(modificationInterval)); - } - - /// - /// Set global velocity resource loader properties (caching, modification interval etc.) - /// - /// the properties used to initialize the velocity engine - /// the type of resource loader - /// the suffix property - /// the value of the property - private void AppendResourceLoaderGlobalProperty(IDictionary properties, string type, string property, object value) { - if (null != value) { - properties.Add(type + VelocityConstants.Separator + property, value); - } - } - - /// - /// Creates a nvelocity file based resource loader by setting the required properties - /// - /// a list of nv:file elements defining the paths to template files - /// the properties used to initialize the velocity engine - private void AppendFileLoaderProperties(XmlNodeList elements, IDictionary properties) { - IList paths = new List(elements.Count); - foreach (XmlElement element in elements) + foreach (XmlElement element in childElements) + { + switch (element.LocalName) { - paths.Add(GetAttributeValue(element, VelocityConstants.Path)); - } - properties.Add(RuntimeConstants.RESOURCE_LOADER, VelocityConstants.File); - properties.Add(getResourceLoaderProperty(VelocityConstants.File, VelocityConstants.Class), TemplateDefinitionConstants.FileResourceLoaderClass); - properties.Add(getResourceLoaderProperty(VelocityConstants.File, VelocityConstants.Path), StringUtils.CollectionToCommaDelimitedString(paths)); - } - - /// - /// Creates a nvelocity assembly based resource loader by setting the required properties - /// - /// a list of nv:assembly elements defining the assemblies - /// the properties used to initialize the velocity engine - private void AppendAssemblyLoaderProperties(XmlNodeList elements, IDictionary properties) { - IList assemblies = new List(elements.Count); - foreach (XmlElement element in elements) { - assemblies.Add(GetAttributeValue(element, VelocityConstants.Name)); - } - properties.Add(RuntimeConstants.RESOURCE_LOADER, VelocityConstants.Assembly); - properties.Add(getResourceLoaderProperty(VelocityConstants.Assembly, VelocityConstants.Class), TemplateDefinitionConstants.AssemblyResourceLoaderClass); - properties.Add(getResourceLoaderProperty(VelocityConstants.Assembly, VelocityConstants.Assembly), StringUtils.CollectionToCommaDelimitedString(assemblies)); - } - - /// - /// Creates a spring resource loader by setting the ResourceLoaderPaths of the - /// engine factory (the resource loader itself will be created internally either as - /// spring or as file resource loader based on the value of prefer-file-system-access - /// attribute). - /// - /// list of resource loader path elements - /// the MutablePropertyValues to set the property for the engine factory - private void AppendResourceLoaderPaths(XmlNodeList elements, MutablePropertyValues objectDefinitionProperties) { - IList paths = new List(); - foreach (XmlElement element in elements) { - string path = GetAttributeValue(element, TemplateDefinitionConstants.AttributeUri); - paths.Add(path); - } - objectDefinitionProperties.Add(TemplateDefinitionConstants.PropertyResourceLoaderPaths, paths); - } - - /// - /// Create a custom resource loader from an nv:custom element - /// generates the 4 required nvelocity props for a resource loader (name, description, class and path). - /// - /// the nv:custom xml definition element - /// the properties used to initialize the velocity engine - private void AppendCustomLoaderProperties(XmlElement element, IDictionary properties) { - string name = GetAttributeValue(element, VelocityConstants.Name); - string description = GetAttributeValue(element, VelocityConstants.Description); - string type = GetAttributeValue(element, VelocityConstants.Type); - string path = GetAttributeValue(element, VelocityConstants.Path); - properties.Add(RuntimeConstants.RESOURCE_LOADER, name); - properties.Add(getResourceLoaderProperty(name, VelocityConstants.Description), description); - properties.Add(getResourceLoaderProperty(name, VelocityConstants.Class), type.Replace(',', ';')); - properties.Add(getResourceLoaderProperty(name, VelocityConstants.Path), path); - } - - /// - /// Parses the nvelocity properties map using ObjectNamespaceParserHelper - /// and appends it to the properties dictionary - /// - /// root element of the map element - /// the parser context - /// the properties used to initialize the velocity engine - private void ParseNVelocityProperties(XmlElement element, ParserContext parserContext, IDictionary properties) { - IDictionary parsedProperties = ParseDictionaryElement(element, - TemplateDefinitionConstants.ElementNVelocityProperties, parserContext); - foreach (DictionaryEntry entry in parsedProperties) { - properties.Add(Convert.ToString(entry.Key), entry.Value); + case TemplateDefinitionConstants.ElementResourceLoader: + ParseResourceLoader(element, objectDefinitionProperties, properties); + break; + case TemplateDefinitionConstants.ElementNVelocityProperties: + ParseNVelocityProperties(element, parserContext, properties); + break; } } - /// - /// Gets the name of the object type for the specified element. - /// - /// The element. - /// The name of the object type. - private string GetTypeName(XmlElement element) { - string typeName = element.GetAttribute(ObjectDefinitionConstants.TypeAttribute); - if (StringUtils.IsNullOrEmpty(typeName)) { - return TemplateTypePrefix + element.LocalName; - } - return typeName; - } - - /// - /// constructs an nvelocity style resource loader property in the format: - /// prefix.resource.loader.suffix - /// - /// the prefix - /// the suffix - /// a concatenated string like: prefix.resource.loader.suffix - public static string getResourceLoaderProperty(string type, string suffix) { - return type + VelocityConstants.Separator + RuntimeConstants.RESOURCE_LOADER + VelocityConstants.Separator + - suffix; - } - - /// - /// This method is overriden from ObjectsNamespaceParser since when invoked on - /// sub-elements from the objets namespace (e.g., objects:objectMap for nvelocity - /// property map) the element.SelectNodes fails because it is in - /// the nvelocity custom namespace and not the object's namespace (http://www.springframwork.net) - /// to amend this the object's namespace is added to the provided XmlNamespaceManager - /// - /// The element to be searched in. - /// The name of the child nodes to look for. - /// - /// The child s of the supplied - /// with the supplied . - /// - /// - [Obsolete("not used anymore - ObjectsNamespaceParser will be dropped with 2.x, use ObjectDefinitionParserHelper instead")] - protected override XmlNodeList SelectNodes(XmlElement element, string childElementName) { - XmlNamespaceManager nsManager = new XmlNamespaceManager(new NameTable()); - nsManager.AddNamespace(GetNamespacePrefix(element), element.NamespaceURI); - nsManager.AddNamespace(GetNamespacePrefix(element), Namespace); - return element.SelectNodes(GetNamespacePrefix(element) + ":" + childElementName, nsManager); - } - - private string GetNamespacePrefix(XmlElement element) { - return StringUtils.HasText(element.Prefix) ? element.Prefix : "spring"; + if (properties.Count > 0) + { + objectDefinitionProperties.Add(TemplateDefinitionConstants.PropertyVelocityProperties, properties); } } - - - #region Element & Attribute Name Constants - /// - /// Template definition constants + /// Configures the NVelocity resource loader definitions from the xml definition /// - public class TemplateDefinitionConstants { - /// - /// Engine element definition - /// - public const string NVelocityElement = "engine"; + /// the root resource loader element + /// the MutablePropertyValues used to configure this object + /// the properties used to initialize the velocity engine + private void ParseResourceLoader(XmlElement element, MutablePropertyValues objectDefinitionProperties, IDictionary properties) + { + string caching = GetAttributeValue(element, TemplateDefinitionConstants.AttributeTemplateCaching); + string defaultCacheSize = GetAttributeValue(element, TemplateDefinitionConstants.AttributeDefaultCacheSize); + string modificationCheckInterval = GetAttributeValue(element, TemplateDefinitionConstants.AttributeModificationCheckInterval); - /// - /// Spring resource loader element definition - /// - public const string Spring = "spring"; + if (!string.IsNullOrEmpty(defaultCacheSize)) + { + properties.Add(RuntimeConstants.RESOURCE_MANAGER_DEFAULTCACHE_SIZE, defaultCacheSize); + } - /// - /// Custom resource loader element definition - /// - public const string Custom = "custom"; - - /// - /// uri attribute of the spring element - /// - public const string AttributeUri = "uri"; - - /// - /// prefer-file-system-access attribute of the engine factory - /// - public const string AttributePreferFileSystemAccess = "prefer-file-system-access"; - - /// - /// config-file attribute of the engine factory - /// - public const string AttributeConfigFile = "config-file"; - - /// - /// override-logging attribute of the engine factory - /// - public const string AttributeOverrideLogging = "override-logging"; - - /// - /// template-caching attribute of the nvelocity engine - /// - public const string AttributeTemplateCaching = "template-caching"; - - /// - /// default-cache-size attribute of the nvelocity engine resource manager - /// - public const string AttributeDefaultCacheSize = "default-cache-size"; - - /// - /// modification-check-interval attribute of the nvelocity engine resource loader - /// - public const string AttributeModificationCheckInterval = "modification-check-interval"; - - /// - /// resource loader element - /// - public const string ElementResourceLoader = "resource-loader"; - - /// - /// nvelocity propeties element (map) - /// - public const string ElementNVelocityProperties = "nvelocity-properties"; - - /// - /// PreferFileSystemAccess property of the engine factory - /// - public const string PropertyPreferFileSystemAccess = "PreferFileSystemAccess"; - - /// - /// OverrideLogging property of the engine factory - /// - public const string PropertyOverrideLogging = "OverrideLogging"; - - /// - /// ConfigLocation property of the engine factory - /// - public const string PropertyConfigFile = "ConfigLocation"; - - /// - /// ResourceLoaderPaths property of the engine factory - /// - public const string PropertyResourceLoaderPaths = "ResourceLoaderPaths"; - - /// - /// VelocityProperties property of the engine factory - /// - public const string PropertyVelocityProperties = "VelocityProperties"; - - /// - /// resource.loader.cache property of the resource loader configuration - /// - public const string PropertyResourceLoaderCaching = "resource.loader.cache"; - - /// - /// resource.loader.modificationCheckInterval property of the resource loader configuration - /// - public const string PropertyResourceLoaderModificationCheckInterval = "resource.loader.modificationCheckInterval"; - - /// - /// the type used for file resource loader - /// - public const string FileResourceLoaderClass = "NVelocity.Runtime.Resource.Loader.FileResourceLoader; NVelocity"; - - /// - /// the type used for assembly resource loader - /// - public const string AssemblyResourceLoaderClass = "NVelocity.Runtime.Resource.Loader.AssemblyResourceLoader; NVelocity"; - - /// - /// the type used for spring resource loader - /// - public const string SpringResourceLoaderClass = "Spring.Template.Velocity.SpringResourceLoader; Spring.Template.Velocity.Castle"; + XmlNodeList loaderElements = element.ChildNodes; + switch (loaderElements[0].LocalName) + { + case VelocityConstants.File: + AppendFileLoaderProperties(loaderElements, properties); + AppendResourceLoaderGlobalProperties(properties, VelocityConstants.File, caching, + modificationCheckInterval); + break; + case VelocityConstants.Assembly: + AppendAssemblyLoaderProperties(loaderElements, properties); + AppendResourceLoaderGlobalProperties(properties, VelocityConstants.Assembly, caching, null); + break; + case TemplateDefinitionConstants.Spring: + AppendResourceLoaderPaths(loaderElements, objectDefinitionProperties); + AppendResourceLoaderGlobalProperties(properties, TemplateDefinitionConstants.Spring, caching, null); + break; + case TemplateDefinitionConstants.Custom: + XmlElement firstElement = (XmlElement) loaderElements.Item(0); + AppendCustomLoaderProperties(firstElement, properties); + AppendResourceLoaderGlobalProperties(properties, firstElement.LocalName, caching, modificationCheckInterval); + break; + default: + throw new ArgumentException(string.Format("undefined element for resource loadre type: {0}", element.LocalName)); + } + } + + /// + /// Set the caching and modification interval checking properties of a resource loader of a given type + /// + /// the properties used to initialize the velocity engine + /// type of the resource loader + /// caching flag + /// modification interval value + private void AppendResourceLoaderGlobalProperties(IDictionary properties, string type, string caching, string modificationInterval) + { + AppendResourceLoaderGlobalProperty(properties, type, + TemplateDefinitionConstants.PropertyResourceLoaderCaching, + Convert.ToBoolean(caching)); + AppendResourceLoaderGlobalProperty + (properties, type, TemplateDefinitionConstants.PropertyResourceLoaderModificationCheckInterval, Convert.ToInt64(modificationInterval)); + } + + /// + /// Set global velocity resource loader properties (caching, modification interval etc.) + /// + /// the properties used to initialize the velocity engine + /// the type of resource loader + /// the suffix property + /// the value of the property + private void AppendResourceLoaderGlobalProperty(IDictionary properties, string type, string property, object value) + { + if (null != value) + { + properties.Add(type + VelocityConstants.Separator + property, value); + } + } + + /// + /// Creates a nvelocity file based resource loader by setting the required properties + /// + /// a list of nv:file elements defining the paths to template files + /// the properties used to initialize the velocity engine + private void AppendFileLoaderProperties(XmlNodeList elements, IDictionary properties) + { + IList paths = new List(elements.Count); + foreach (XmlElement element in elements) + { + paths.Add(GetAttributeValue(element, VelocityConstants.Path)); + } + + properties.Add(RuntimeConstants.RESOURCE_LOADER, VelocityConstants.File); + properties.Add(getResourceLoaderProperty(VelocityConstants.File, VelocityConstants.Class), TemplateDefinitionConstants.FileResourceLoaderClass); + properties.Add(getResourceLoaderProperty(VelocityConstants.File, VelocityConstants.Path), StringUtils.CollectionToCommaDelimitedString(paths)); + } + + /// + /// Creates a nvelocity assembly based resource loader by setting the required properties + /// + /// a list of nv:assembly elements defining the assemblies + /// the properties used to initialize the velocity engine + private void AppendAssemblyLoaderProperties(XmlNodeList elements, IDictionary properties) + { + IList assemblies = new List(elements.Count); + foreach (XmlElement element in elements) + { + assemblies.Add(GetAttributeValue(element, VelocityConstants.Name)); + } + + properties.Add(RuntimeConstants.RESOURCE_LOADER, VelocityConstants.Assembly); + properties.Add(getResourceLoaderProperty(VelocityConstants.Assembly, VelocityConstants.Class), TemplateDefinitionConstants.AssemblyResourceLoaderClass); + properties.Add(getResourceLoaderProperty(VelocityConstants.Assembly, VelocityConstants.Assembly), StringUtils.CollectionToCommaDelimitedString(assemblies)); + } + + /// + /// Creates a spring resource loader by setting the ResourceLoaderPaths of the + /// engine factory (the resource loader itself will be created internally either as + /// spring or as file resource loader based on the value of prefer-file-system-access + /// attribute). + /// + /// list of resource loader path elements + /// the MutablePropertyValues to set the property for the engine factory + private void AppendResourceLoaderPaths(XmlNodeList elements, MutablePropertyValues objectDefinitionProperties) + { + IList paths = new List(); + foreach (XmlElement element in elements) + { + string path = GetAttributeValue(element, TemplateDefinitionConstants.AttributeUri); + paths.Add(path); + } + + objectDefinitionProperties.Add(TemplateDefinitionConstants.PropertyResourceLoaderPaths, paths); + } + + /// + /// Create a custom resource loader from an nv:custom element + /// generates the 4 required nvelocity props for a resource loader (name, description, class and path). + /// + /// the nv:custom xml definition element + /// the properties used to initialize the velocity engine + private void AppendCustomLoaderProperties(XmlElement element, IDictionary properties) + { + string name = GetAttributeValue(element, VelocityConstants.Name); + string description = GetAttributeValue(element, VelocityConstants.Description); + string type = GetAttributeValue(element, VelocityConstants.Type); + string path = GetAttributeValue(element, VelocityConstants.Path); + properties.Add(RuntimeConstants.RESOURCE_LOADER, name); + properties.Add(getResourceLoaderProperty(name, VelocityConstants.Description), description); + properties.Add(getResourceLoaderProperty(name, VelocityConstants.Class), type.Replace(',', ';')); + properties.Add(getResourceLoaderProperty(name, VelocityConstants.Path), path); + } + + /// + /// Parses the nvelocity properties map using ObjectNamespaceParserHelper + /// and appends it to the properties dictionary + /// + /// root element of the map element + /// the parser context + /// the properties used to initialize the velocity engine + private void ParseNVelocityProperties(XmlElement element, ParserContext parserContext, IDictionary properties) + { + IDictionary parsedProperties = ParseDictionaryElement(element, + TemplateDefinitionConstants.ElementNVelocityProperties, parserContext); + foreach (DictionaryEntry entry in parsedProperties) + { + properties.Add(Convert.ToString(entry.Key), entry.Value); + } + } + + /// + /// Gets the name of the object type for the specified element. + /// + /// The element. + /// The name of the object type. + private string GetTypeName(XmlElement element) + { + string typeName = element.GetAttribute(ObjectDefinitionConstants.TypeAttribute); + if (StringUtils.IsNullOrEmpty(typeName)) + { + return TemplateTypePrefix + element.LocalName; + } + + return typeName; + } + + /// + /// constructs an nvelocity style resource loader property in the format: + /// prefix.resource.loader.suffix + /// + /// the prefix + /// the suffix + /// a concatenated string like: prefix.resource.loader.suffix + public static string getResourceLoaderProperty(string type, string suffix) + { + return type + VelocityConstants.Separator + RuntimeConstants.RESOURCE_LOADER + VelocityConstants.Separator + + suffix; + } + + /// + /// This method is overriden from ObjectsNamespaceParser since when invoked on + /// sub-elements from the objets namespace (e.g., objects:objectMap for nvelocity + /// property map) the element.SelectNodes fails because it is in + /// the nvelocity custom namespace and not the object's namespace (http://www.springframwork.net) + /// to amend this the object's namespace is added to the provided XmlNamespaceManager + /// + /// The element to be searched in. + /// The name of the child nodes to look for. + /// + /// The child s of the supplied + /// with the supplied . + /// + /// + [Obsolete("not used anymore - ObjectsNamespaceParser will be dropped with 2.x, use ObjectDefinitionParserHelper instead")] + protected override XmlNodeList SelectNodes(XmlElement element, string childElementName) + { + XmlNamespaceManager nsManager = new XmlNamespaceManager(new NameTable()); + nsManager.AddNamespace(GetNamespacePrefix(element), element.NamespaceURI); + nsManager.AddNamespace(GetNamespacePrefix(element), Namespace); + return element.SelectNodes(GetNamespacePrefix(element) + ":" + childElementName, nsManager); + } + + private string GetNamespacePrefix(XmlElement element) + { + return StringUtils.HasText(element.Prefix) ? element.Prefix : "spring"; } - #endregion } + +#region Element & Attribute Name Constants + +/// +/// Template definition constants +/// +public class TemplateDefinitionConstants +{ + /// + /// Engine element definition + /// + public const string NVelocityElement = "engine"; + + /// + /// Spring resource loader element definition + /// + public const string Spring = "spring"; + + /// + /// Custom resource loader element definition + /// + public const string Custom = "custom"; + + /// + /// uri attribute of the spring element + /// + public const string AttributeUri = "uri"; + + /// + /// prefer-file-system-access attribute of the engine factory + /// + public const string AttributePreferFileSystemAccess = "prefer-file-system-access"; + + /// + /// config-file attribute of the engine factory + /// + public const string AttributeConfigFile = "config-file"; + + /// + /// override-logging attribute of the engine factory + /// + public const string AttributeOverrideLogging = "override-logging"; + + /// + /// template-caching attribute of the nvelocity engine + /// + public const string AttributeTemplateCaching = "template-caching"; + + /// + /// default-cache-size attribute of the nvelocity engine resource manager + /// + public const string AttributeDefaultCacheSize = "default-cache-size"; + + /// + /// modification-check-interval attribute of the nvelocity engine resource loader + /// + public const string AttributeModificationCheckInterval = "modification-check-interval"; + + /// + /// resource loader element + /// + public const string ElementResourceLoader = "resource-loader"; + + /// + /// nvelocity propeties element (map) + /// + public const string ElementNVelocityProperties = "nvelocity-properties"; + + /// + /// PreferFileSystemAccess property of the engine factory + /// + public const string PropertyPreferFileSystemAccess = "PreferFileSystemAccess"; + + /// + /// OverrideLogging property of the engine factory + /// + public const string PropertyOverrideLogging = "OverrideLogging"; + + /// + /// ConfigLocation property of the engine factory + /// + public const string PropertyConfigFile = "ConfigLocation"; + + /// + /// ResourceLoaderPaths property of the engine factory + /// + public const string PropertyResourceLoaderPaths = "ResourceLoaderPaths"; + + /// + /// VelocityProperties property of the engine factory + /// + public const string PropertyVelocityProperties = "VelocityProperties"; + + /// + /// resource.loader.cache property of the resource loader configuration + /// + public const string PropertyResourceLoaderCaching = "resource.loader.cache"; + + /// + /// resource.loader.modificationCheckInterval property of the resource loader configuration + /// + public const string PropertyResourceLoaderModificationCheckInterval = "resource.loader.modificationCheckInterval"; + + /// + /// the type used for file resource loader + /// + public const string FileResourceLoaderClass = "NVelocity.Runtime.Resource.Loader.FileResourceLoader; NVelocity"; + + /// + /// the type used for assembly resource loader + /// + public const string AssemblyResourceLoaderClass = "NVelocity.Runtime.Resource.Loader.AssemblyResourceLoader; NVelocity"; + + /// + /// the type used for spring resource loader + /// + public const string SpringResourceLoaderClass = "Spring.Template.Velocity.SpringResourceLoader; Spring.Template.Velocity.Castle"; +} + +#endregion \ No newline at end of file diff --git a/src/Spring/Spring.Template.Velocity.Castle/Template/Velocity/SpringResourceLoader.cs b/src/Spring/Spring.Template.Velocity.Castle/Template/Velocity/SpringResourceLoader.cs index ed8d61c2..ee9e4f83 100644 --- a/src/Spring/Spring.Template.Velocity.Castle/Template/Velocity/SpringResourceLoader.cs +++ b/src/Spring/Spring.Template.Velocity.Castle/Template/Velocity/SpringResourceLoader.cs @@ -24,153 +24,155 @@ using NVelocity.Runtime.Resource; using NVelocity.Runtime.Resource.Loader; using Spring.Core.IO; -namespace Spring.Template.Velocity +namespace Spring.Template.Velocity; + +/// +/// NVelocity's abstract ResourceLoader extension which serves +/// as an adapter that loads templates via a Spring IResourceLoader. +/// +///
+/// Used by VelocityEngineFactory for any resource loader path that +/// cannot be resolved to a File or an Assembly or for +/// implementations which rely on spring's IResourceLoader +/// mechanism. +/// +///
+/// Important: this loader does not allow for modification detection. +///
+/// Expects "spring.resource.loader" (IResourceLoader implementations) +/// and "spring.resource.loader.path" application attributes in the +/// NVelocity runtime. +///
+/// +/// +/// +/// +/// +/// Erez Mazor (.NET) +public class SpringResourceLoader : ResourceLoader { + /// + /// Prefix used for the NVelocity Configuration + /// + public const string NAME = "spring"; + /// - /// NVelocity's abstract ResourceLoader extension which serves - /// as an adapter that loads templates via a Spring IResourceLoader. - /// - ///
- /// Used by VelocityEngineFactory for any resource loader path that - /// cannot be resolved to a File or an Assembly or for - /// implementations which rely on spring's IResourceLoader - /// mechanism. - /// - ///
- /// Important: this loader does not allow for modification detection. - ///
- /// Expects "spring.resource.loader" (IResourceLoader implementations) - /// and "spring.resource.loader.path" application attributes in the - /// NVelocity runtime. + /// The IResourceLoader implementation type ///
- /// - /// - /// - /// - /// - /// Erez Mazor (.NET) - public class SpringResourceLoader : ResourceLoader + public const string SPRING_RESOURCE_LOADER_CLASS = "spring.resource.loader.class"; + + /// + /// A flag indicating weather a template cache is used + /// + public const string SPRING_RESOURCE_LOADER_CACHE = "spring.resource.loader.cache"; + + /// + /// Fully qualified name of the IResourceLoader implementation class + /// + public const string SPRING_RESOURCE_LOADER = "spring.resource.loader"; + + /// + /// A comma delimited list of paths used by the spring IResourceLoader implementation + /// + public const string SPRING_RESOURCE_LOADER_PATH = "spring.resource.loader.path"; + + /// + /// Shared logger instance. + /// + protected static readonly ILogger log = LogManager.GetLogger(); + + private IResourceLoader resourceLoader; + + private string[] resourceLoaderPaths; + + /// + /// Initialize the template loader with a resources class. + /// + /// The ExtendedProperties representing the Velocity configuration. + public override void Init(ExtendedProperties configuration) { - /// - /// Prefix used for the NVelocity Configuration - /// - public const string NAME = "spring"; - - /// - /// The IResourceLoader implementation type - /// - public const string SPRING_RESOURCE_LOADER_CLASS = "spring.resource.loader.class"; - - /// - /// A flag indicating weather a template cache is used - /// - public const string SPRING_RESOURCE_LOADER_CACHE = "spring.resource.loader.cache"; - - /// - /// Fully qualified name of the IResourceLoader implementation class - /// - public const string SPRING_RESOURCE_LOADER = "spring.resource.loader"; - - /// - /// A comma delimited list of paths used by the spring IResourceLoader implementation - /// - public const string SPRING_RESOURCE_LOADER_PATH = "spring.resource.loader.path"; - - /// - /// Shared logger instance. - /// - protected static readonly ILogger log = LogManager.GetLogger(); - - private IResourceLoader resourceLoader; - - private string[] resourceLoaderPaths; - - - /// - /// Initialize the template loader with a resources class. - /// - /// The ExtendedProperties representing the Velocity configuration. - public override void Init(ExtendedProperties configuration) + resourceLoader = (IResourceLoader) runtimeServices.GetApplicationAttribute(SPRING_RESOURCE_LOADER); + string resourceLoaderPath = (string) runtimeServices.GetApplicationAttribute(SPRING_RESOURCE_LOADER_PATH); + if (resourceLoader == null) { - resourceLoader = (IResourceLoader)runtimeServices.GetApplicationAttribute(SPRING_RESOURCE_LOADER); - string resourceLoaderPath = (string)runtimeServices.GetApplicationAttribute(SPRING_RESOURCE_LOADER_PATH); - if (resourceLoader == null) + throw new ArgumentException("'resourceLoader' application attribute must be present for SpringResourceLoader"); + } + + if (null == resourceLoaderPath) + { + throw new ArgumentException("'resourceLoaderPath' application attribute must be present for SpringResourceLoader"); + } + + resourceLoaderPaths = resourceLoaderPath.Split(','); + for (int i = 0; i < resourceLoaderPaths.Length; i++) + { + string path = resourceLoaderPaths[i]; + if (!path.EndsWith("/")) { - throw new ArgumentException("'resourceLoader' application attribute must be present for SpringResourceLoader"); - } - if (null == resourceLoaderPath) - { - throw new ArgumentException("'resourceLoaderPath' application attribute must be present for SpringResourceLoader"); - } - resourceLoaderPaths = resourceLoaderPath.Split(','); - for (int i = 0; i < resourceLoaderPaths.Length; i++) - { - string path = resourceLoaderPaths[i]; - if (!path.EndsWith("/")) - { - resourceLoaderPaths[i] = path + "/"; - } - } - if (log.IsEnabled(LogLevel.Information)) - { - log.LogInformation(string.Format("SpringResourceLoader for Velocity: using resource loader [{0}] and resource loader paths {1}", resourceLoader, resourceLoaderPaths)); + resourceLoaderPaths[i] = path + "/"; } } - /// - /// Get the System.IO.Stream that the Runtime will parse to create a template. - /// - /// the source template name - /// a System.IO.Stream representation of the resource - public override Stream GetResourceStream(string source) + if (log.IsEnabled(LogLevel.Information)) { - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug(string.Format("Looking for Velocity resource with name [{0}]", source)); - } - - foreach (string resourceLoaderPath in resourceLoaderPaths) - { - IResource resource = resourceLoader.GetResource(resourceLoaderPath + source); - try - { - return resource.InputStream; - } - catch (IOException ex) - { - if (log.IsEnabled(LogLevel.Error)) - { - string message = string.Format("Could not find Velocity resource: {0}", resource); - log.LogError(ex, message); - } - } - } - throw new ArgumentException(string.Format("Could not find resource [{0}] in Spring resource loader path", source)); - } - - /// - /// Given a template, check to see if the source of InputStream has been modified. - /// - /// The resource. - /// - /// true if the source of the InputStream has been modified; otherwise, false. - /// - public override bool IsSourceModified(Resource resource) - { - return false; - } - - /// - /// Get the last modified time of the InputStream source - /// that was used to create the template. We need the template - /// here because we have to extract the name of the template - /// in order to locate the InputStream source. - /// - /// The resource. - /// - public override long GetLastModified(Resource resource) - { - return 0; + log.LogInformation(string.Format("SpringResourceLoader for Velocity: using resource loader [{0}] and resource loader paths {1}", resourceLoader, resourceLoaderPaths)); } } + + /// + /// Get the System.IO.Stream that the Runtime will parse to create a template. + /// + /// the source template name + /// a System.IO.Stream representation of the resource + public override Stream GetResourceStream(string source) + { + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug(string.Format("Looking for Velocity resource with name [{0}]", source)); + } + + foreach (string resourceLoaderPath in resourceLoaderPaths) + { + IResource resource = resourceLoader.GetResource(resourceLoaderPath + source); + try + { + return resource.InputStream; + } + catch (IOException ex) + { + if (log.IsEnabled(LogLevel.Error)) + { + string message = string.Format("Could not find Velocity resource: {0}", resource); + log.LogError(ex, message); + } + } + } + + throw new ArgumentException(string.Format("Could not find resource [{0}] in Spring resource loader path", source)); + } + + /// + /// Given a template, check to see if the source of InputStream has been modified. + /// + /// The resource. + /// + /// true if the source of the InputStream has been modified; otherwise, false. + /// + public override bool IsSourceModified(Resource resource) + { + return false; + } + + /// + /// Get the last modified time of the InputStream source + /// that was used to create the template. We need the template + /// here because we have to extract the name of the template + /// in order to locate the InputStream source. + /// + /// The resource. + /// + public override long GetLastModified(Resource resource) + { + return 0; + } } diff --git a/src/Spring/Spring.Template.Velocity/Template/Velocity/CommonsLoggingLogSystem.cs b/src/Spring/Spring.Template.Velocity/Template/Velocity/CommonsLoggingLogSystem.cs index 252c8ca0..22bd82b8 100644 --- a/src/Spring/Spring.Template.Velocity/Template/Velocity/CommonsLoggingLogSystem.cs +++ b/src/Spring/Spring.Template.Velocity/Template/Velocity/CommonsLoggingLogSystem.cs @@ -21,50 +21,50 @@ using Microsoft.Extensions.Logging; using NVelocity.Runtime; using NVelocity.Runtime.Log; -using LogLevel=NVelocity.Runtime.Log.LogLevel; +using LogLevel = NVelocity.Runtime.Log.LogLevel; -namespace Spring.Template.Velocity +namespace Spring.Template.Velocity; + +/// +/// NVelocity LogSystem implementation for Commons Logging. +/// +/// Erez Mazor +public class CommonsLoggingLogSystem : ILogSystem { /// - /// NVelocity LogSystem implementation for Commons Logging. + /// Shared logger instance. /// - /// Erez Mazor - public class CommonsLoggingLogSystem : ILogSystem { + protected static readonly ILogger log = LogManager.GetLogger(); - /// - /// Shared logger instance. - /// - protected static readonly ILogger log = LogManager.GetLogger(); + /// + /// Initializes the specified runtime services. No-op in current implementatin + /// + /// the runtime services. + public void Init(IRuntimeServices runtimeServices) + { + } - /// - /// Initializes the specified runtime services. No-op in current implementatin - /// - /// the runtime services. - public void Init(IRuntimeServices runtimeServices) + /// + /// Log a NVelocity message using the commons logging system + /// + /// LogLevel to match + /// message to log + public void LogVelocityMessage(LogLevel level, string message) + { + switch (level) { - } - - /// - /// Log a NVelocity message using the commons logging system - /// - /// LogLevel to match - /// message to log - public void LogVelocityMessage(LogLevel level, string message) - { - switch (level) { - case LogLevel.Error: - log.LogError(message); - break; - case LogLevel.Warn: - log.LogWarning(message); - break; - case LogLevel.Info: - log.LogInformation(message); - break; - case LogLevel.Debug: - log.LogDebug(message); - break; - } + case LogLevel.Error: + log.LogError(message); + break; + case LogLevel.Warn: + log.LogWarning(message); + break; + case LogLevel.Info: + log.LogInformation(message); + break; + case LogLevel.Debug: + log.LogDebug(message); + break; } } } diff --git a/src/Spring/Spring.Template.Velocity/Template/Velocity/Config/TemplateNamespaceParser.cs b/src/Spring/Spring.Template.Velocity/Template/Velocity/Config/TemplateNamespaceParser.cs index f060584e..2d14b9de 100644 --- a/src/Spring/Spring.Template.Velocity/Template/Velocity/Config/TemplateNamespaceParser.cs +++ b/src/Spring/Spring.Template.Velocity/Template/Velocity/Config/TemplateNamespaceParser.cs @@ -22,9 +22,7 @@ using System.Collections; using System.Xml; - using NVelocity.Runtime; - using Spring.Core.TypeResolution; using Spring.Objects; using Spring.Objects.Factory.Config; @@ -34,438 +32,478 @@ using Spring.Util; #endregion -namespace Spring.Template.Velocity.Config { +namespace Spring.Template.Velocity.Config; + +/// +/// Implementation of the custom configuration parser for template configurations +/// based on +/// +/// +/// Erez Mazor +/// +[ + NamespaceParser( + Namespace = "http://www.springframework.net/nvelocity", + SchemaLocationAssemblyHint = typeof(TemplateNamespaceParser), + SchemaLocation = "/Spring.Template.Velocity.Config/spring-nvelocity-1.3.xsd") +] +public class TemplateNamespaceParser : ObjectsNamespaceParser +{ + private const string TemplateTypePrefix = "template: "; + + static TemplateNamespaceParser() + { + TypeRegistry.RegisterType(TemplateTypePrefix + TemplateDefinitionConstants.NVelocityElement, typeof(VelocityEngineFactoryObject)); + } + /// - /// Implementation of the custom configuration parser for template configurations - /// based on - /// + /// Initializes a new instance of the class. /// - /// Erez Mazor - /// - [ - NamespaceParser( - Namespace = "http://www.springframework.net/nvelocity", - SchemaLocationAssemblyHint = typeof(TemplateNamespaceParser), - SchemaLocation = "/Spring.Template.Velocity.Config/spring-nvelocity-1.3.xsd") - ] - public class TemplateNamespaceParser : ObjectsNamespaceParser { - private const string TemplateTypePrefix = "template: "; + public TemplateNamespaceParser() + { + } - static TemplateNamespaceParser() { - TypeRegistry.RegisterType(TemplateTypePrefix + TemplateDefinitionConstants.NVelocityElement, typeof(VelocityEngineFactoryObject)); + /// + public override IObjectDefinition ParseElement(XmlElement element, ParserContext parserContext) + { + string name = element.GetAttribute(ObjectDefinitionConstants.IdAttribute); + IConfigurableObjectDefinition templateDefinition = ParseTemplateDefinition(element, parserContext); + if (!StringUtils.HasText(name)) + { + name = ObjectDefinitionReaderUtils.GenerateObjectName(templateDefinition, parserContext.Registry); } - /// - /// Initializes a new instance of the class. - /// - public TemplateNamespaceParser() { + parserContext.Registry.RegisterObjectDefinition(name, templateDefinition); + return null; + } + + /// + /// Parse a template definition from the templating namespace + /// + /// the root element defining the templating object + /// the parser context + /// + private IConfigurableObjectDefinition ParseTemplateDefinition(XmlElement element, ParserContext parserContext) + { + switch (element.LocalName) + { + case TemplateDefinitionConstants.NVelocityElement: + return ParseNVelocityEngine(element, parserContext); + default: + throw new ArgumentException(string.Format("undefined element for templating namespace: {0}", element.LocalName)); + } + } + + /// + /// Parses the object definition for the engine object, configures a single NVelocity template engine based + /// on the element definitions. + /// + /// the root element defining the velocity engine + /// the parser context + private IConfigurableObjectDefinition ParseNVelocityEngine(XmlElement element, ParserContext parserContext) + { + string typeName = GetTypeName(element); + IConfigurableObjectDefinition configurableObjectDefinition = parserContext.ReaderContext.ObjectDefinitionFactory.CreateObjectDefinition( + typeName, null, parserContext.ReaderContext.Reader.Domain); + + string preferFileSystemAccess = GetAttributeValue(element, TemplateDefinitionConstants.AttributePreferFileSystemAccess); + string overrideLogging = GetAttributeValue(element, TemplateDefinitionConstants.AttributeOverrideLogging); + string configFile = GetAttributeValue(element, TemplateDefinitionConstants.AttributeConfigFile); + + MutablePropertyValues objectDefinitionProperties = new MutablePropertyValues(); + if (StringUtils.HasText(preferFileSystemAccess)) + { + objectDefinitionProperties.Add(TemplateDefinitionConstants.PropertyPreferFileSystemAccess, preferFileSystemAccess); } - /// - public override IObjectDefinition ParseElement(XmlElement element, ParserContext parserContext) { - string name = element.GetAttribute(ObjectDefinitionConstants.IdAttribute); - IConfigurableObjectDefinition templateDefinition = ParseTemplateDefinition(element, parserContext); - if (!StringUtils.HasText(name)) { - name = ObjectDefinitionReaderUtils.GenerateObjectName(templateDefinition, parserContext.Registry); - } - parserContext.Registry.RegisterObjectDefinition(name, templateDefinition); - return null; + if (StringUtils.HasText(overrideLogging)) + { + objectDefinitionProperties.Add(TemplateDefinitionConstants.PropertyOverrideLogging, overrideLogging); } - /// - /// Parse a template definition from the templating namespace - /// - /// the root element defining the templating object - /// the parser context - /// - private IConfigurableObjectDefinition ParseTemplateDefinition(XmlElement element, ParserContext parserContext) { - switch (element.LocalName) { - case TemplateDefinitionConstants.NVelocityElement: - return ParseNVelocityEngine(element, parserContext); - default: - throw new ArgumentException(string.Format("undefined element for templating namespace: {0}", element.LocalName)); - } + if (StringUtils.HasText(configFile)) + { + objectDefinitionProperties.Add(TemplateDefinitionConstants.PropertyConfigFile, configFile); } - /// - /// Parses the object definition for the engine object, configures a single NVelocity template engine based - /// on the element definitions. - /// - /// the root element defining the velocity engine - /// the parser context - private IConfigurableObjectDefinition ParseNVelocityEngine(XmlElement element, ParserContext parserContext) { - string typeName = GetTypeName(element); - IConfigurableObjectDefinition configurableObjectDefinition = parserContext.ReaderContext.ObjectDefinitionFactory.CreateObjectDefinition( - typeName, null, parserContext.ReaderContext.Reader.Domain); - - string preferFileSystemAccess = GetAttributeValue(element, TemplateDefinitionConstants.AttributePreferFileSystemAccess); - string overrideLogging = GetAttributeValue(element, TemplateDefinitionConstants.AttributeOverrideLogging); - string configFile = GetAttributeValue(element, TemplateDefinitionConstants.AttributeConfigFile); - - MutablePropertyValues objectDefinitionProperties = new MutablePropertyValues(); - if (StringUtils.HasText(preferFileSystemAccess)) { - objectDefinitionProperties.Add(TemplateDefinitionConstants.PropertyPreferFileSystemAccess, preferFileSystemAccess); - } - - if (StringUtils.HasText(overrideLogging)) { - objectDefinitionProperties.Add(TemplateDefinitionConstants.PropertyOverrideLogging, overrideLogging); - } - - if (StringUtils.HasText(configFile)) { - objectDefinitionProperties.Add(TemplateDefinitionConstants.PropertyConfigFile, configFile); - } - - XmlNodeList childElements = element.ChildNodes; - if (childElements.Count > 0) { - ParseChildDefinitions(childElements, parserContext, objectDefinitionProperties); - } - configurableObjectDefinition.PropertyValues = objectDefinitionProperties; - return configurableObjectDefinition; + XmlNodeList childElements = element.ChildNodes; + if (childElements.Count > 0) + { + ParseChildDefinitions(childElements, parserContext, objectDefinitionProperties); } - /// - /// Parses child element definitions for the NVelocity engine. Typically resource loaders and locally defined properties are parsed here - /// - /// the XmlNodeList representing the child configuration of the root NVelocity engine element - /// the parser context - /// the MutablePropertyValues used to configure this object - private void ParseChildDefinitions(XmlNodeList childElements, ParserContext parserContext, MutablePropertyValues objectDefinitionProperties) { - IDictionary properties = new Dictionary(); + configurableObjectDefinition.PropertyValues = objectDefinitionProperties; + return configurableObjectDefinition; + } - foreach (XmlElement element in childElements) { - switch (element.LocalName) { - case TemplateDefinitionConstants.ElementResourceLoader: - ParseResourceLoader(element, objectDefinitionProperties, properties); - break; - case TemplateDefinitionConstants.ElementNVelocityProperties: - ParseNVelocityProperties(element, parserContext, properties); - break; - } - } + /// + /// Parses child element definitions for the NVelocity engine. Typically resource loaders and locally defined properties are parsed here + /// + /// the XmlNodeList representing the child configuration of the root NVelocity engine element + /// the parser context + /// the MutablePropertyValues used to configure this object + private void ParseChildDefinitions(XmlNodeList childElements, ParserContext parserContext, MutablePropertyValues objectDefinitionProperties) + { + IDictionary properties = new Dictionary(); - if (properties.Count > 0) { - objectDefinitionProperties.Add(TemplateDefinitionConstants.PropertyVelocityProperties, properties); - } - } - - /// - /// Configures the NVelocity resource loader definitions from the xml definition - /// - /// the root resource loader element - /// the MutablePropertyValues used to configure this object - /// the properties used to initialize the velocity engine - private void ParseResourceLoader(XmlElement element, MutablePropertyValues objectDefinitionProperties, IDictionary properties) { - string caching = GetAttributeValue(element, TemplateDefinitionConstants.AttributeTemplateCaching); - string defaultCacheSize = GetAttributeValue(element, TemplateDefinitionConstants.AttributeDefaultCacheSize); - string modificationCheckInterval = GetAttributeValue(element, TemplateDefinitionConstants.AttributeModificationCheckInterval); - - if (!string.IsNullOrEmpty(defaultCacheSize)) { - properties.Add(RuntimeConstants.RESOURCE_MANAGER_DEFAULTCACHE_SIZE, defaultCacheSize); - } - - XmlNodeList loaderElements = element.ChildNodes; - switch (loaderElements[0].LocalName) { - case VelocityConstants.File: - AppendFileLoaderProperties(loaderElements, properties); - AppendResourceLoaderGlobalProperties(properties, VelocityConstants.File, caching, - modificationCheckInterval); - break; - case VelocityConstants.Assembly: - AppendAssemblyLoaderProperties(loaderElements, properties); - AppendResourceLoaderGlobalProperties(properties, VelocityConstants.Assembly, caching, null); - break; - case TemplateDefinitionConstants.Spring: - AppendResourceLoaderPaths(loaderElements, objectDefinitionProperties); - AppendResourceLoaderGlobalProperties(properties, TemplateDefinitionConstants.Spring, caching, null); - break; - case TemplateDefinitionConstants.Custom: - XmlElement firstElement = (XmlElement)loaderElements.Item(0); - AppendCustomLoaderProperties(firstElement, properties); - AppendResourceLoaderGlobalProperties(properties, firstElement.LocalName, caching, modificationCheckInterval); - break; - default: - throw new ArgumentException(string.Format("undefined element for resource loadre type: {0}", element.LocalName)); - } - } - - - /// - /// Set the caching and modification interval checking properties of a resource loader of a given type - /// - /// the properties used to initialize the velocity engine - /// type of the resource loader - /// caching flag - /// modification interval value - private void AppendResourceLoaderGlobalProperties(IDictionary properties, string type, string caching, string modificationInterval) { - AppendResourceLoaderGlobalProperty(properties, type, - TemplateDefinitionConstants.PropertyResourceLoaderCaching, - Convert.ToBoolean(caching)); - AppendResourceLoaderGlobalProperty - (properties, type, TemplateDefinitionConstants.PropertyResourceLoaderModificationCheckInterval, Convert.ToInt64(modificationInterval)); - } - - /// - /// Set global velocity resource loader properties (caching, modification interval etc.) - /// - /// the properties used to initialize the velocity engine - /// the type of resource loader - /// the suffix property - /// the value of the property - private void AppendResourceLoaderGlobalProperty(IDictionary properties, string type, string property, object value) { - if (null != value) { - properties.Add(type + VelocityConstants.Separator + property, value); - } - } - - /// - /// Creates a nvelocity file based resource loader by setting the required properties - /// - /// a list of nv:file elements defining the paths to template files - /// the properties used to initialize the velocity engine - private void AppendFileLoaderProperties(XmlNodeList elements, IDictionary properties) { - IList paths = new List(elements.Count); - foreach (XmlElement element in elements) + foreach (XmlElement element in childElements) + { + switch (element.LocalName) { - paths.Add(GetAttributeValue(element, VelocityConstants.Path)); - } - properties.Add(RuntimeConstants.RESOURCE_LOADER, VelocityConstants.File); - properties.Add(getResourceLoaderProperty(VelocityConstants.File, VelocityConstants.Class), TemplateDefinitionConstants.FileResourceLoaderClass); - properties.Add(getResourceLoaderProperty(VelocityConstants.File, VelocityConstants.Path), StringUtils.CollectionToCommaDelimitedString(paths)); - } - - /// - /// Creates a nvelocity assembly based resource loader by setting the required properties - /// - /// a list of nv:assembly elements defining the assemblies - /// the properties used to initialize the velocity engine - private void AppendAssemblyLoaderProperties(XmlNodeList elements, IDictionary properties) { - IList assemblies = new List(elements.Count); - foreach (XmlElement element in elements) { - assemblies.Add(GetAttributeValue(element, VelocityConstants.Name)); - } - properties.Add(RuntimeConstants.RESOURCE_LOADER, VelocityConstants.Assembly); - properties.Add(getResourceLoaderProperty(VelocityConstants.Assembly, VelocityConstants.Class), TemplateDefinitionConstants.AssemblyResourceLoaderClass); - properties.Add(getResourceLoaderProperty(VelocityConstants.Assembly, VelocityConstants.Assembly), StringUtils.CollectionToCommaDelimitedString(assemblies)); - } - - /// - /// Creates a spring resource loader by setting the ResourceLoaderPaths of the - /// engine factory (the resource loader itself will be created internally either as - /// spring or as file resource loader based on the value of prefer-file-system-access - /// attribute). - /// - /// list of resource loader path elements - /// the MutablePropertyValues to set the property for the engine factory - private void AppendResourceLoaderPaths(XmlNodeList elements, MutablePropertyValues objectDefinitionProperties) { - IList paths = new List(); - foreach (XmlElement element in elements) { - string path = GetAttributeValue(element, TemplateDefinitionConstants.AttributeUri); - paths.Add(path); - } - objectDefinitionProperties.Add(TemplateDefinitionConstants.PropertyResourceLoaderPaths, paths); - } - - /// - /// Create a custom resource loader from an nv:custom element - /// generates the 4 required nvelocity props for a resource loader (name, description, class and path). - /// - /// the nv:custom xml definition element - /// the properties used to initialize the velocity engine - private void AppendCustomLoaderProperties(XmlElement element, IDictionary properties) { - string name = GetAttributeValue(element, VelocityConstants.Name); - string description = GetAttributeValue(element, VelocityConstants.Description); - string type = GetAttributeValue(element, VelocityConstants.Type); - string path = GetAttributeValue(element, VelocityConstants.Path); - properties.Add(RuntimeConstants.RESOURCE_LOADER, name); - properties.Add(getResourceLoaderProperty(name, VelocityConstants.Description), description); - properties.Add(getResourceLoaderProperty(name, VelocityConstants.Class), type.Replace(',', ';')); - properties.Add(getResourceLoaderProperty(name, VelocityConstants.Path), path); - } - - /// - /// Parses the nvelocity properties map using ObjectNamespaceParserHelper - /// and appends it to the properties dictionary - /// - /// root element of the map element - /// the parser context - /// the properties used to initialize the velocity engine - private void ParseNVelocityProperties(XmlElement element, ParserContext parserContext, IDictionary properties) { - IDictionary parsedProperties = ParseDictionaryElement(element, - TemplateDefinitionConstants.ElementNVelocityProperties, parserContext); - foreach (DictionaryEntry entry in parsedProperties) { - properties.Add(Convert.ToString(entry.Key), entry.Value); + case TemplateDefinitionConstants.ElementResourceLoader: + ParseResourceLoader(element, objectDefinitionProperties, properties); + break; + case TemplateDefinitionConstants.ElementNVelocityProperties: + ParseNVelocityProperties(element, parserContext, properties); + break; } } - /// - /// Gets the name of the object type for the specified element. - /// - /// The element. - /// The name of the object type. - private string GetTypeName(XmlElement element) { - string typeName = element.GetAttribute(ObjectDefinitionConstants.TypeAttribute); - if (StringUtils.IsNullOrEmpty(typeName)) { - return TemplateTypePrefix + element.LocalName; - } - return typeName; - } - - /// - /// constructs an nvelocity style resource loader property in the format: - /// prefix.resource.loader.suffix - /// - /// the prefix - /// the suffix - /// a concatenated string like: prefix.resource.loader.suffix - public static string getResourceLoaderProperty(string type, string suffix) { - return type + VelocityConstants.Separator + RuntimeConstants.RESOURCE_LOADER + VelocityConstants.Separator + - suffix; - } - - /// - /// This method is overriden from ObjectsNamespaceParser since when invoked on - /// sub-elements from the objets namespace (e.g., objects:objectMap for nvelocity - /// property map) the element.SelectNodes fails because it is in - /// the nvelocity custom namespace and not the object's namespace (http://www.springframwork.net) - /// to amend this the object's namespace is added to the provided XmlNamespaceManager - /// - /// The element to be searched in. - /// The name of the child nodes to look for. - /// - /// The child s of the supplied - /// with the supplied . - /// - /// - [Obsolete("not used anymore - ObjectsNamespaceParser will be dropped with 2.x, use ObjectDefinitionParserHelper instead")] - protected override XmlNodeList SelectNodes(XmlElement element, string childElementName) { - XmlNamespaceManager nsManager = new XmlNamespaceManager(new NameTable()); - nsManager.AddNamespace(GetNamespacePrefix(element), element.NamespaceURI); - nsManager.AddNamespace(GetNamespacePrefix(element), Namespace); - return element.SelectNodes(GetNamespacePrefix(element) + ":" + childElementName, nsManager); - } - - private string GetNamespacePrefix(XmlElement element) { - return StringUtils.HasText(element.Prefix) ? element.Prefix : "spring"; + if (properties.Count > 0) + { + objectDefinitionProperties.Add(TemplateDefinitionConstants.PropertyVelocityProperties, properties); } } - - - #region Element & Attribute Name Constants - /// - /// Template definition constants + /// Configures the NVelocity resource loader definitions from the xml definition /// - public class TemplateDefinitionConstants { - /// - /// Engine element definition - /// - public const string NVelocityElement = "engine"; + /// the root resource loader element + /// the MutablePropertyValues used to configure this object + /// the properties used to initialize the velocity engine + private void ParseResourceLoader(XmlElement element, MutablePropertyValues objectDefinitionProperties, IDictionary properties) + { + string caching = GetAttributeValue(element, TemplateDefinitionConstants.AttributeTemplateCaching); + string defaultCacheSize = GetAttributeValue(element, TemplateDefinitionConstants.AttributeDefaultCacheSize); + string modificationCheckInterval = GetAttributeValue(element, TemplateDefinitionConstants.AttributeModificationCheckInterval); - /// - /// Spring resource loader element definition - /// - public const string Spring = "spring"; + if (!string.IsNullOrEmpty(defaultCacheSize)) + { + properties.Add(RuntimeConstants.RESOURCE_MANAGER_DEFAULTCACHE_SIZE, defaultCacheSize); + } - /// - /// Custom resource loader element definition - /// - public const string Custom = "custom"; - - /// - /// uri attribute of the spring element - /// - public const string AttributeUri = "uri"; - - /// - /// prefer-file-system-access attribute of the engine factory - /// - public const string AttributePreferFileSystemAccess = "prefer-file-system-access"; - - /// - /// config-file attribute of the engine factory - /// - public const string AttributeConfigFile = "config-file"; - - /// - /// override-logging attribute of the engine factory - /// - public const string AttributeOverrideLogging = "override-logging"; - - /// - /// template-caching attribute of the nvelocity engine - /// - public const string AttributeTemplateCaching = "template-caching"; - - /// - /// default-cache-size attribute of the nvelocity engine resource manager - /// - public const string AttributeDefaultCacheSize = "default-cache-size"; - - /// - /// modification-check-interval attribute of the nvelocity engine resource loader - /// - public const string AttributeModificationCheckInterval = "modification-check-interval"; - - /// - /// resource loader element - /// - public const string ElementResourceLoader = "resource-loader"; - - /// - /// nvelocity propeties element (map) - /// - public const string ElementNVelocityProperties = "nvelocity-properties"; - - /// - /// PreferFileSystemAccess property of the engine factory - /// - public const string PropertyPreferFileSystemAccess = "PreferFileSystemAccess"; - - /// - /// OverrideLogging property of the engine factory - /// - public const string PropertyOverrideLogging = "OverrideLogging"; - - /// - /// ConfigLocation property of the engine factory - /// - public const string PropertyConfigFile = "ConfigLocation"; - - /// - /// ResourceLoaderPaths property of the engine factory - /// - public const string PropertyResourceLoaderPaths = "ResourceLoaderPaths"; - - /// - /// VelocityProperties property of the engine factory - /// - public const string PropertyVelocityProperties = "VelocityProperties"; - - /// - /// resource.loader.cache property of the resource loader configuration - /// - public const string PropertyResourceLoaderCaching = "resource.loader.cache"; - - /// - /// resource.loader.modificationCheckInterval property of the resource loader configuration - /// - public const string PropertyResourceLoaderModificationCheckInterval = "resource.loader.modificationCheckInterval"; - - /// - /// the type used for file resource loader - /// - public const string FileResourceLoaderClass = "NVelocity.Runtime.Resource.Loader.FileResourceLoader; NVelocity"; - - /// - /// the type used for assembly resource loader - /// - public const string AssemblyResourceLoaderClass = "NVelocity.Runtime.Resource.Loader.AssemblyResourceLoader; NVelocity"; - - /// - /// the type used for spring resource loader - /// - public const string SpringResourceLoaderClass = "Spring.Template.Velocity.SpringResourceLoader; Spring.Template.Velocity"; + XmlNodeList loaderElements = element.ChildNodes; + switch (loaderElements[0].LocalName) + { + case VelocityConstants.File: + AppendFileLoaderProperties(loaderElements, properties); + AppendResourceLoaderGlobalProperties(properties, VelocityConstants.File, caching, + modificationCheckInterval); + break; + case VelocityConstants.Assembly: + AppendAssemblyLoaderProperties(loaderElements, properties); + AppendResourceLoaderGlobalProperties(properties, VelocityConstants.Assembly, caching, null); + break; + case TemplateDefinitionConstants.Spring: + AppendResourceLoaderPaths(loaderElements, objectDefinitionProperties); + AppendResourceLoaderGlobalProperties(properties, TemplateDefinitionConstants.Spring, caching, null); + break; + case TemplateDefinitionConstants.Custom: + XmlElement firstElement = (XmlElement) loaderElements.Item(0); + AppendCustomLoaderProperties(firstElement, properties); + AppendResourceLoaderGlobalProperties(properties, firstElement.LocalName, caching, modificationCheckInterval); + break; + default: + throw new ArgumentException(string.Format("undefined element for resource loadre type: {0}", element.LocalName)); + } + } + + /// + /// Set the caching and modification interval checking properties of a resource loader of a given type + /// + /// the properties used to initialize the velocity engine + /// type of the resource loader + /// caching flag + /// modification interval value + private void AppendResourceLoaderGlobalProperties(IDictionary properties, string type, string caching, string modificationInterval) + { + AppendResourceLoaderGlobalProperty(properties, type, + TemplateDefinitionConstants.PropertyResourceLoaderCaching, + Convert.ToBoolean(caching)); + AppendResourceLoaderGlobalProperty + (properties, type, TemplateDefinitionConstants.PropertyResourceLoaderModificationCheckInterval, Convert.ToInt64(modificationInterval)); + } + + /// + /// Set global velocity resource loader properties (caching, modification interval etc.) + /// + /// the properties used to initialize the velocity engine + /// the type of resource loader + /// the suffix property + /// the value of the property + private void AppendResourceLoaderGlobalProperty(IDictionary properties, string type, string property, object value) + { + if (null != value) + { + properties.Add(type + VelocityConstants.Separator + property, value); + } + } + + /// + /// Creates a nvelocity file based resource loader by setting the required properties + /// + /// a list of nv:file elements defining the paths to template files + /// the properties used to initialize the velocity engine + private void AppendFileLoaderProperties(XmlNodeList elements, IDictionary properties) + { + IList paths = new List(elements.Count); + foreach (XmlElement element in elements) + { + paths.Add(GetAttributeValue(element, VelocityConstants.Path)); + } + + properties.Add(RuntimeConstants.RESOURCE_LOADER, VelocityConstants.File); + properties.Add(getResourceLoaderProperty(VelocityConstants.File, VelocityConstants.Class), TemplateDefinitionConstants.FileResourceLoaderClass); + properties.Add(getResourceLoaderProperty(VelocityConstants.File, VelocityConstants.Path), StringUtils.CollectionToCommaDelimitedString(paths)); + } + + /// + /// Creates a nvelocity assembly based resource loader by setting the required properties + /// + /// a list of nv:assembly elements defining the assemblies + /// the properties used to initialize the velocity engine + private void AppendAssemblyLoaderProperties(XmlNodeList elements, IDictionary properties) + { + IList assemblies = new List(elements.Count); + foreach (XmlElement element in elements) + { + assemblies.Add(GetAttributeValue(element, VelocityConstants.Name)); + } + + properties.Add(RuntimeConstants.RESOURCE_LOADER, VelocityConstants.Assembly); + properties.Add(getResourceLoaderProperty(VelocityConstants.Assembly, VelocityConstants.Class), TemplateDefinitionConstants.AssemblyResourceLoaderClass); + properties.Add(getResourceLoaderProperty(VelocityConstants.Assembly, VelocityConstants.Assembly), StringUtils.CollectionToCommaDelimitedString(assemblies)); + } + + /// + /// Creates a spring resource loader by setting the ResourceLoaderPaths of the + /// engine factory (the resource loader itself will be created internally either as + /// spring or as file resource loader based on the value of prefer-file-system-access + /// attribute). + /// + /// list of resource loader path elements + /// the MutablePropertyValues to set the property for the engine factory + private void AppendResourceLoaderPaths(XmlNodeList elements, MutablePropertyValues objectDefinitionProperties) + { + IList paths = new List(); + foreach (XmlElement element in elements) + { + string path = GetAttributeValue(element, TemplateDefinitionConstants.AttributeUri); + paths.Add(path); + } + + objectDefinitionProperties.Add(TemplateDefinitionConstants.PropertyResourceLoaderPaths, paths); + } + + /// + /// Create a custom resource loader from an nv:custom element + /// generates the 4 required nvelocity props for a resource loader (name, description, class and path). + /// + /// the nv:custom xml definition element + /// the properties used to initialize the velocity engine + private void AppendCustomLoaderProperties(XmlElement element, IDictionary properties) + { + string name = GetAttributeValue(element, VelocityConstants.Name); + string description = GetAttributeValue(element, VelocityConstants.Description); + string type = GetAttributeValue(element, VelocityConstants.Type); + string path = GetAttributeValue(element, VelocityConstants.Path); + properties.Add(RuntimeConstants.RESOURCE_LOADER, name); + properties.Add(getResourceLoaderProperty(name, VelocityConstants.Description), description); + properties.Add(getResourceLoaderProperty(name, VelocityConstants.Class), type.Replace(',', ';')); + properties.Add(getResourceLoaderProperty(name, VelocityConstants.Path), path); + } + + /// + /// Parses the nvelocity properties map using ObjectNamespaceParserHelper + /// and appends it to the properties dictionary + /// + /// root element of the map element + /// the parser context + /// the properties used to initialize the velocity engine + private void ParseNVelocityProperties(XmlElement element, ParserContext parserContext, IDictionary properties) + { + IDictionary parsedProperties = ParseDictionaryElement(element, + TemplateDefinitionConstants.ElementNVelocityProperties, parserContext); + foreach (DictionaryEntry entry in parsedProperties) + { + properties.Add(Convert.ToString(entry.Key), entry.Value); + } + } + + /// + /// Gets the name of the object type for the specified element. + /// + /// The element. + /// The name of the object type. + private string GetTypeName(XmlElement element) + { + string typeName = element.GetAttribute(ObjectDefinitionConstants.TypeAttribute); + if (StringUtils.IsNullOrEmpty(typeName)) + { + return TemplateTypePrefix + element.LocalName; + } + + return typeName; + } + + /// + /// constructs an nvelocity style resource loader property in the format: + /// prefix.resource.loader.suffix + /// + /// the prefix + /// the suffix + /// a concatenated string like: prefix.resource.loader.suffix + public static string getResourceLoaderProperty(string type, string suffix) + { + return type + VelocityConstants.Separator + RuntimeConstants.RESOURCE_LOADER + VelocityConstants.Separator + + suffix; + } + + /// + /// This method is overriden from ObjectsNamespaceParser since when invoked on + /// sub-elements from the objets namespace (e.g., objects:objectMap for nvelocity + /// property map) the element.SelectNodes fails because it is in + /// the nvelocity custom namespace and not the object's namespace (http://www.springframwork.net) + /// to amend this the object's namespace is added to the provided XmlNamespaceManager + /// + /// The element to be searched in. + /// The name of the child nodes to look for. + /// + /// The child s of the supplied + /// with the supplied . + /// + /// + [Obsolete("not used anymore - ObjectsNamespaceParser will be dropped with 2.x, use ObjectDefinitionParserHelper instead")] + protected override XmlNodeList SelectNodes(XmlElement element, string childElementName) + { + XmlNamespaceManager nsManager = new XmlNamespaceManager(new NameTable()); + nsManager.AddNamespace(GetNamespacePrefix(element), element.NamespaceURI); + nsManager.AddNamespace(GetNamespacePrefix(element), Namespace); + return element.SelectNodes(GetNamespacePrefix(element) + ":" + childElementName, nsManager); + } + + private string GetNamespacePrefix(XmlElement element) + { + return StringUtils.HasText(element.Prefix) ? element.Prefix : "spring"; } - #endregion } + +#region Element & Attribute Name Constants + +/// +/// Template definition constants +/// +public class TemplateDefinitionConstants +{ + /// + /// Engine element definition + /// + public const string NVelocityElement = "engine"; + + /// + /// Spring resource loader element definition + /// + public const string Spring = "spring"; + + /// + /// Custom resource loader element definition + /// + public const string Custom = "custom"; + + /// + /// uri attribute of the spring element + /// + public const string AttributeUri = "uri"; + + /// + /// prefer-file-system-access attribute of the engine factory + /// + public const string AttributePreferFileSystemAccess = "prefer-file-system-access"; + + /// + /// config-file attribute of the engine factory + /// + public const string AttributeConfigFile = "config-file"; + + /// + /// override-logging attribute of the engine factory + /// + public const string AttributeOverrideLogging = "override-logging"; + + /// + /// template-caching attribute of the nvelocity engine + /// + public const string AttributeTemplateCaching = "template-caching"; + + /// + /// default-cache-size attribute of the nvelocity engine resource manager + /// + public const string AttributeDefaultCacheSize = "default-cache-size"; + + /// + /// modification-check-interval attribute of the nvelocity engine resource loader + /// + public const string AttributeModificationCheckInterval = "modification-check-interval"; + + /// + /// resource loader element + /// + public const string ElementResourceLoader = "resource-loader"; + + /// + /// nvelocity propeties element (map) + /// + public const string ElementNVelocityProperties = "nvelocity-properties"; + + /// + /// PreferFileSystemAccess property of the engine factory + /// + public const string PropertyPreferFileSystemAccess = "PreferFileSystemAccess"; + + /// + /// OverrideLogging property of the engine factory + /// + public const string PropertyOverrideLogging = "OverrideLogging"; + + /// + /// ConfigLocation property of the engine factory + /// + public const string PropertyConfigFile = "ConfigLocation"; + + /// + /// ResourceLoaderPaths property of the engine factory + /// + public const string PropertyResourceLoaderPaths = "ResourceLoaderPaths"; + + /// + /// VelocityProperties property of the engine factory + /// + public const string PropertyVelocityProperties = "VelocityProperties"; + + /// + /// resource.loader.cache property of the resource loader configuration + /// + public const string PropertyResourceLoaderCaching = "resource.loader.cache"; + + /// + /// resource.loader.modificationCheckInterval property of the resource loader configuration + /// + public const string PropertyResourceLoaderModificationCheckInterval = "resource.loader.modificationCheckInterval"; + + /// + /// the type used for file resource loader + /// + public const string FileResourceLoaderClass = "NVelocity.Runtime.Resource.Loader.FileResourceLoader; NVelocity"; + + /// + /// the type used for assembly resource loader + /// + public const string AssemblyResourceLoaderClass = "NVelocity.Runtime.Resource.Loader.AssemblyResourceLoader; NVelocity"; + + /// + /// the type used for spring resource loader + /// + public const string SpringResourceLoaderClass = "Spring.Template.Velocity.SpringResourceLoader; Spring.Template.Velocity"; +} + +#endregion diff --git a/src/Spring/Spring.Template.Velocity/Template/Velocity/Config/spring-nvelocity-1.3.xsd b/src/Spring/Spring.Template.Velocity/Template/Velocity/Config/spring-nvelocity-1.3.xsd index 951d33cb..6d9ba755 100644 --- a/src/Spring/Spring.Template.Velocity/Template/Velocity/Config/spring-nvelocity-1.3.xsd +++ b/src/Spring/Spring.Template.Velocity/Template/Velocity/Config/spring-nvelocity-1.3.xsd @@ -1,21 +1,21 @@  + xmlns:objects="http://www.springframework.net" + xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:vs="http://schemas.microsoft.com/Visual-Studio-Intellisense" + targetNamespace="http://www.springframework.net/nvelocity" + elementFormDefault="qualified" + attributeFormDefault="unqualified" + vs:friendlyname="Spring.NET NVelocity Templating Framework Configuration" + vs:ishtmlschema="false" + vs:iscasesensitive="true" + vs:requireattributequotes="true" + vs:defaultnamespacequalifier="" + vs:defaultnsprefix=""> - - + + @@ -37,7 +37,7 @@ - + @@ -53,7 +53,7 @@ - + @@ -62,7 +62,7 @@ - + @@ -71,7 +71,7 @@ - + @@ -104,7 +104,8 @@ - + + @@ -136,17 +137,20 @@ - .loader.description property) of the resource loader]]> + + .loader.description property) of the resource loader]]> - .resource.loader.class property) of the resource loader]]> + + .resource.loader.class property) of the resource loader]]> - .resource.loader.path property) of the resource loader]]> + + .resource.loader.path property) of the resource loader]]> diff --git a/src/Spring/Spring.Template.Velocity/Template/Velocity/SpringResourceLoader.cs b/src/Spring/Spring.Template.Velocity/Template/Velocity/SpringResourceLoader.cs index 830da70e..ea6a999c 100644 --- a/src/Spring/Spring.Template.Velocity/Template/Velocity/SpringResourceLoader.cs +++ b/src/Spring/Spring.Template.Velocity/Template/Velocity/SpringResourceLoader.cs @@ -24,137 +24,155 @@ using NVelocity.Runtime.Resource; using NVelocity.Runtime.Resource.Loader; using Spring.Core.IO; -namespace Spring.Template.Velocity { +namespace Spring.Template.Velocity; + +/// +/// NVelocity's abstract ResourceLoader extension which serves +/// as an adapter that loads templates via a Spring IResourceLoader. +/// +///
+/// Used by VelocityEngineFactory for any resource loader path that +/// cannot be resolved to a File or an Assembly or for +/// implementations which rely on spring's IResourceLoader +/// mechanism. +/// +///
+/// Important: this loader does not allow for modification detection. +///
+/// Expects "spring.resource.loader" (IResourceLoader implementations) +/// and "spring.resource.loader.path" application attributes in the +/// NVelocity runtime. +///
+/// +/// +/// +/// +/// +/// Erez Mazor (.NET) +public class SpringResourceLoader : ResourceLoader +{ + /// + /// Prefix used for the NVelocity Configuration + /// + public const string NAME = "spring"; + /// - /// NVelocity's abstract ResourceLoader extension which serves - /// as an adapter that loads templates via a Spring IResourceLoader. - /// - ///
- /// Used by VelocityEngineFactory for any resource loader path that - /// cannot be resolved to a File or an Assembly or for - /// implementations which rely on spring's IResourceLoader - /// mechanism. - /// - ///
- /// Important: this loader does not allow for modification detection. - ///
- /// Expects "spring.resource.loader" (IResourceLoader implementations) - /// and "spring.resource.loader.path" application attributes in the - /// NVelocity runtime. + /// The IResourceLoader implementation type ///
- /// - /// - /// - /// - /// - /// Erez Mazor (.NET) - public class SpringResourceLoader : ResourceLoader { - /// - /// Prefix used for the NVelocity Configuration - /// - public const string NAME = "spring"; + public const string SPRING_RESOURCE_LOADER_CLASS = "spring.resource.loader.class"; - /// - /// The IResourceLoader implementation type - /// - public const string SPRING_RESOURCE_LOADER_CLASS = "spring.resource.loader.class"; + /// + /// A flag indicating weather a template cache is used + /// + public const string SPRING_RESOURCE_LOADER_CACHE = "spring.resource.loader.cache"; - /// - /// A flag indicating weather a template cache is used - /// - public const string SPRING_RESOURCE_LOADER_CACHE = "spring.resource.loader.cache"; + /// + /// Fully qualified name of the IResourceLoader implementation class + /// + public const string SPRING_RESOURCE_LOADER = "spring.resource.loader"; - /// - /// Fully qualified name of the IResourceLoader implementation class - /// - public const string SPRING_RESOURCE_LOADER = "spring.resource.loader"; + /// + /// A comma delimited list of paths used by the spring IResourceLoader implementation + /// + public const string SPRING_RESOURCE_LOADER_PATH = "spring.resource.loader.path"; - /// - /// A comma delimited list of paths used by the spring IResourceLoader implementation - /// - public const string SPRING_RESOURCE_LOADER_PATH = "spring.resource.loader.path"; + /// + /// Shared logger instance. + /// + protected static readonly ILogger log = LogManager.GetLogger(); - /// - /// Shared logger instance. - /// - protected static readonly ILogger log = LogManager.GetLogger(); + private IResourceLoader resourceLoader; - private IResourceLoader resourceLoader; + private string[] resourceLoaderPaths; - private string[] resourceLoaderPaths; + /// + /// Initialize the template loader with a resources class. + /// + /// The ExtendedProperties representing the Velocity configuration. + public override void Init(ExtendedProperties configuration) + { + resourceLoader = (IResourceLoader) runtimeServices.GetApplicationAttribute(SPRING_RESOURCE_LOADER); + string resourceLoaderPath = (string) runtimeServices.GetApplicationAttribute(SPRING_RESOURCE_LOADER_PATH); + if (resourceLoader == null) + { + throw new ArgumentException("'resourceLoader' application attribute must be present for SpringResourceLoader"); + } + if (null == resourceLoaderPath) + { + throw new ArgumentException("'resourceLoaderPath' application attribute must be present for SpringResourceLoader"); + } - /// - /// Initialize the template loader with a resources class. - /// - /// The ExtendedProperties representing the Velocity configuration. - public override void Init(ExtendedProperties configuration) { - resourceLoader = (IResourceLoader)runtimeServices.GetApplicationAttribute(SPRING_RESOURCE_LOADER); - string resourceLoaderPath = (string)runtimeServices.GetApplicationAttribute(SPRING_RESOURCE_LOADER_PATH); - if (resourceLoader == null) { - throw new ArgumentException("'resourceLoader' application attribute must be present for SpringResourceLoader"); - } - if (null == resourceLoaderPath) { - throw new ArgumentException("'resourceLoaderPath' application attribute must be present for SpringResourceLoader"); - } - resourceLoaderPaths = resourceLoaderPath.Split(','); - for (int i = 0; i < resourceLoaderPaths.Length; i++) { - string path = resourceLoaderPaths[i]; - if (!path.EndsWith("/")) { - resourceLoaderPaths[i] = path + "/"; - } - } - if (log.IsEnabled(LogLevel.Information)) { - log.LogInformation(string.Format("SpringResourceLoader for Velocity: using resource loader [{0}] and resource loader paths {1}", resourceLoader, resourceLoaderPaths)); + resourceLoaderPaths = resourceLoaderPath.Split(','); + for (int i = 0; i < resourceLoaderPaths.Length; i++) + { + string path = resourceLoaderPaths[i]; + if (!path.EndsWith("/")) + { + resourceLoaderPaths[i] = path + "/"; } } - /// - /// Get the System.IO.Stream that the Runtime will parse to create a template. - /// - /// the source template name - /// a System.IO.Stream representation of the resource - public override Stream GetResourceStream(string source) { - if (log.IsEnabled(LogLevel.Debug)) { - log.LogDebug(string.Format("Looking for Velocity resource with name [{0}]", source)); - } - - foreach (string resourceLoaderPath in resourceLoaderPaths){ - IResource resource = resourceLoader.GetResource(resourceLoaderPath + source); - try { - return resource.InputStream; - } catch (IOException ex) { - if (log.IsEnabled(LogLevel.Error)) - { - string message = string.Format("Could not find Velocity resource: {0}", resource); - log.LogError(ex, message); - } - } - } - throw new ArgumentException(string.Format("Could not find resource [{0}] in Spring resource loader path", source)); - } - - /// - /// Given a template, check to see if the source of InputStream has been modified. - /// - /// The resource. - /// - /// true if the source of the InputStream has been modified; otherwise, false. - /// - public override bool IsSourceModified(Resource resource) { - return false; - } - - /// - /// Get the last modified time of the InputStream source - /// that was used to create the template. We need the template - /// here because we have to extract the name of the template - /// in order to locate the InputStream source. - /// - /// The resource. - /// - public override long GetLastModified(Resource resource) { - return 0; + if (log.IsEnabled(LogLevel.Information)) + { + log.LogInformation(string.Format("SpringResourceLoader for Velocity: using resource loader [{0}] and resource loader paths {1}", resourceLoader, resourceLoaderPaths)); } } + + /// + /// Get the System.IO.Stream that the Runtime will parse to create a template. + /// + /// the source template name + /// a System.IO.Stream representation of the resource + public override Stream GetResourceStream(string source) + { + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug(string.Format("Looking for Velocity resource with name [{0}]", source)); + } + + foreach (string resourceLoaderPath in resourceLoaderPaths) + { + IResource resource = resourceLoader.GetResource(resourceLoaderPath + source); + try + { + return resource.InputStream; + } + catch (IOException ex) + { + if (log.IsEnabled(LogLevel.Error)) + { + string message = string.Format("Could not find Velocity resource: {0}", resource); + log.LogError(ex, message); + } + } + } + + throw new ArgumentException(string.Format("Could not find resource [{0}] in Spring resource loader path", source)); + } + + /// + /// Given a template, check to see if the source of InputStream has been modified. + /// + /// The resource. + /// + /// true if the source of the InputStream has been modified; otherwise, false. + /// + public override bool IsSourceModified(Resource resource) + { + return false; + } + + /// + /// Get the last modified time of the InputStream source + /// that was used to create the template. We need the template + /// here because we have to extract the name of the template + /// in order to locate the InputStream source. + /// + /// The resource. + /// + public override long GetLastModified(Resource resource) + { + return 0; + } } diff --git a/src/Spring/Spring.Template.Velocity/Template/Velocity/VelocityConstants.cs b/src/Spring/Spring.Template.Velocity/Template/Velocity/VelocityConstants.cs index 93893a87..746aad78 100644 --- a/src/Spring/Spring.Template.Velocity/Template/Velocity/VelocityConstants.cs +++ b/src/Spring/Spring.Template.Velocity/Template/Velocity/VelocityConstants.cs @@ -1,47 +1,47 @@ -namespace Spring.Template.Velocity{ - /// - /// Common Velocity constants. - /// - public class VelocityConstants{ - - /// - /// File. - /// - public const string File = "file"; - - /// - /// Type. - /// - public const string Type = "type"; - - /// - /// Assembly. - /// - public const string Assembly = "assembly"; +namespace Spring.Template.Velocity; - /// - /// Class. - /// - public const string Class = "class"; - - /// - /// Name. - /// - public const string Name = "name"; - - /// - /// Description. - /// - public const string Description = "description"; - - /// - /// Path. - /// - public const string Path = "path"; - - /// - /// Separator. - /// - public const string Separator = "."; - } -} \ No newline at end of file +/// +/// Common Velocity constants. +/// +public class VelocityConstants +{ + /// + /// File. + /// + public const string File = "file"; + + /// + /// Type. + /// + public const string Type = "type"; + + /// + /// Assembly. + /// + public const string Assembly = "assembly"; + + /// + /// Class. + /// + public const string Class = "class"; + + /// + /// Name. + /// + public const string Name = "name"; + + /// + /// Description. + /// + public const string Description = "description"; + + /// + /// Path. + /// + public const string Path = "path"; + + /// + /// Separator. + /// + public const string Separator = "."; +} diff --git a/src/Spring/Spring.Template.Velocity/Template/Velocity/VelocityEngineFactory.cs b/src/Spring/Spring.Template.Velocity/Template/Velocity/VelocityEngineFactory.cs index 84fd5cdc..27c4fc98 100644 --- a/src/Spring/Spring.Template.Velocity/Template/Velocity/VelocityEngineFactory.cs +++ b/src/Spring/Spring.Template.Velocity/Template/Velocity/VelocityEngineFactory.cs @@ -29,359 +29,391 @@ using Spring.Context.Support; using Spring.Core.IO; using Spring.Util; -namespace Spring.Template.Velocity { +namespace Spring.Template.Velocity; + +/// +/// Factory that configures a VelocityEngine. Can be used standalone, +/// but typically you will use VelocityEngineFactoryObject +/// for preparing a VelocityEngine as bean reference. +/// +///
+/// The optional "ConfigLocation" property sets the location of the Velocity +/// properties file, within the current application. Velocity properties can be +/// overridden via "VelocityProperties", or even completely specified locally, +/// avoiding the need for an external properties file. +/// +///
+/// The "ResourceLoaderPath" property can be used to specify the Velocity +/// resource loader path via Spring's IResource abstraction, possibly relative +/// to the Spring application context. +/// +///
+/// If "OverrideLogging" is true (the default), the VelocityEngine will be +/// configured to log via Commons Logging, that is, using the Spring-provided +/// CommonsLoggingLogSystem as log system. +/// +///
+/// The simplest way to use this class is to specify a ResourceLoaderPath +/// property. the VelocityEngine typically then does not need any further +/// configuration. +/// +///
+/// +/// +/// +/// Erez Mazor +public class VelocityEngineFactory +{ /// - /// Factory that configures a VelocityEngine. Can be used standalone, - /// but typically you will use VelocityEngineFactoryObject - /// for preparing a VelocityEngine as bean reference. - /// + /// Shared logger instance. + /// + protected static readonly ILogger log = LogManager.GetLogger(); + + private IResource configLocation; + + private IDictionary velocityProperties = new Dictionary(); + + private IList resourceLoaderPaths = new List(); + + private IResourceLoader resourceLoader = new ConfigurableResourceLoader(); + + private bool preferFileSystemAccess = true; + + private bool overrideLogging = true; + + /// + /// Set the location of the Velocity config file. Alternatively, you can specify all properties locally. + /// + /// + /// + public IResource ConfigLocation + { + set { configLocation = value; } + } + + /// + /// Set local NVelocity properties. + /// + /// + public IDictionary VelocityProperties + { + set { velocityProperties = value; } + } + + /// + /// Single ResourceLoaderPath + /// + /// + public string ResourceLoaderPath + { + set { resourceLoaderPaths.Add(value); } + } + + /// + /// Set the Velocity resource loader path via a Spring resource location. + /// Accepts multiple locations in Velocity's comma-separated path style. ///
- /// The optional "ConfigLocation" property sets the location of the Velocity - /// properties file, within the current application. Velocity properties can be - /// overridden via "VelocityProperties", or even completely specified locally, - /// avoiding the need for an external properties file. - /// + /// When populated via a String, standard URLs like "file:" and "assembly:" + /// pseudo URLs are supported, as understood by IResourceLoader. Allows for + /// relative paths when running in an ApplicationContext. ///
- /// The "ResourceLoaderPath" property can be used to specify the Velocity - /// resource loader path via Spring's IResource abstraction, possibly relative - /// to the Spring application context. - /// + /// Will define a path for the default Velocity resource loader with the name + /// "file". If the specified resource cannot be resolved to a File, + /// a generic SpringResourceLoader will be used under the name "spring", without + /// modification detection. ///
- /// If "OverrideLogging" is true (the default), the VelocityEngine will be - /// configured to log via Commons Logging, that is, using the Spring-provided - /// CommonsLoggingLogSystem as log system. - /// + /// Take notice that resource caching will be enabled in any case. With the file + /// resource loader, the last-modified timestamp will be checked on access to + /// detect changes. With SpringResourceLoader, the resource will be throughout + /// the life time of the application context (for example for class path resources). ///
- /// The simplest way to use this class is to specify a ResourceLoaderPath - /// property. the VelocityEngine typically then does not need any further - /// configuration. + /// To specify a modification check interval for files, use Velocity's + /// standard "file.resource.loader.modificationCheckInterval" property. By default, + /// the file timestamp is checked on every access (which is surprisingly fast). + /// Of course, this just applies when loading resources from the file system. + ///
+ /// To enforce the use of SpringResourceLoader, i.e. to not resolve a path + /// as file system resource in any case, turn off the "preferFileSystemAccess" + /// flag. See the latter's documentation for details. + ///
+ /// + /// + /// + /// + /// + public IList ResourceLoaderPaths + { + set { resourceLoaderPaths = value; } + } + + /// + /// Set the Spring ResourceLoader to use for loading Velocity template files. + /// The default is DefaultResourceLoader. Will get overridden by the + /// ApplicationContext if running in a context. /// /// - /// - /// - /// - /// Erez Mazor - public class VelocityEngineFactory + /// + /// + /// + public IResourceLoader ResourceLoader { + get { return resourceLoader; } + set { resourceLoader = value; } + } - /// - /// Shared logger instance. - /// - protected static readonly ILogger log = LogManager.GetLogger(); + /// + /// Set whether to prefer file system access for template loading. + /// File system access enables hot detection of template changes. + ///
+ /// If this is enabled, VelocityEngineFactory will try to resolve the + /// specified "resourceLoaderPath" as file system resource. + ///
+ /// Default is "true". Turn this off to always load via SpringResourceLoader + /// (i.e. as stream, without hot detection of template changes), which might + /// be necessary if some of your templates reside in a directory while + /// others reside in assembly files. + ///
+ /// + public bool PreferFileSystemAccess + { + get { return preferFileSystemAccess; } + set { preferFileSystemAccess = value; } + } - private IResource configLocation; + /// + /// Set whether Velocity should log via Commons Logging, i.e. whether Velocity's + /// log system should be set to CommonsLoggingLogSystem. Default value is true + /// + /// + public bool OverrideLogging + { + get { return overrideLogging; } + set { overrideLogging = value; } + } - private IDictionary velocityProperties = new Dictionary(); + /// + /// Create and initialize the VelocityEngine instance and return it + /// + /// VelocityEngine + /// + /// + /// + /// + /// + public VelocityEngine CreateVelocityEngine() + { + ExtendedProperties extendedProperties = new ExtendedProperties(); + VelocityEngine velocityEngine = NewVelocityEngine(); - private IList resourceLoaderPaths = new List(); + LoadDefaultProperties(extendedProperties); - private IResourceLoader resourceLoader = new ConfigurableResourceLoader(); - - private bool preferFileSystemAccess = true; - - private bool overrideLogging = true; - - /// - /// Set the location of the Velocity config file. Alternatively, you can specify all properties locally. - /// - /// - /// - public IResource ConfigLocation { - set { configLocation = value; } - } - - /// - /// Set local NVelocity properties. - /// - /// - public IDictionary VelocityProperties { - set { velocityProperties = value; } - } - - /// - /// Single ResourceLoaderPath - /// - /// - public string ResourceLoaderPath { - set { resourceLoaderPaths.Add(value); } - } - - /// - /// Set the Velocity resource loader path via a Spring resource location. - /// Accepts multiple locations in Velocity's comma-separated path style. - ///
- /// When populated via a String, standard URLs like "file:" and "assembly:" - /// pseudo URLs are supported, as understood by IResourceLoader. Allows for - /// relative paths when running in an ApplicationContext. - ///
- /// Will define a path for the default Velocity resource loader with the name - /// "file". If the specified resource cannot be resolved to a File, - /// a generic SpringResourceLoader will be used under the name "spring", without - /// modification detection. - ///
- /// Take notice that resource caching will be enabled in any case. With the file - /// resource loader, the last-modified timestamp will be checked on access to - /// detect changes. With SpringResourceLoader, the resource will be throughout - /// the life time of the application context (for example for class path resources). - ///
- /// To specify a modification check interval for files, use Velocity's - /// standard "file.resource.loader.modificationCheckInterval" property. By default, - /// the file timestamp is checked on every access (which is surprisingly fast). - /// Of course, this just applies when loading resources from the file system. - ///
- /// To enforce the use of SpringResourceLoader, i.e. to not resolve a path - /// as file system resource in any case, turn off the "preferFileSystemAccess" - /// flag. See the latter's documentation for details. - ///
- /// - /// - /// - /// - /// - public IList ResourceLoaderPaths + // Load config file if set. + if (configLocation != null) { - set { resourceLoaderPaths = value; } + if (log.IsEnabled(LogLevel.Information)) + { + log.LogInformation(string.Format("Loading Velocity config from [{0}]", configLocation)); + } + + FillProperties(extendedProperties, configLocation, false); } - /// - /// Set the Spring ResourceLoader to use for loading Velocity template files. - /// The default is DefaultResourceLoader. Will get overridden by the - /// ApplicationContext if running in a context. - /// - /// - /// - /// - /// - public IResourceLoader ResourceLoader { - get { return resourceLoader; } - set { resourceLoader = value; } - } - - /// - /// Set whether to prefer file system access for template loading. - /// File system access enables hot detection of template changes. - ///
- /// If this is enabled, VelocityEngineFactory will try to resolve the - /// specified "resourceLoaderPath" as file system resource. - ///
- /// Default is "true". Turn this off to always load via SpringResourceLoader - /// (i.e. as stream, without hot detection of template changes), which might - /// be necessary if some of your templates reside in a directory while - /// others reside in assembly files. - ///
- /// - public bool PreferFileSystemAccess { - get { return preferFileSystemAccess; } - set { preferFileSystemAccess = value; } - } - - /// - /// Set whether Velocity should log via Commons Logging, i.e. whether Velocity's - /// log system should be set to CommonsLoggingLogSystem. Default value is true - /// - /// - public bool OverrideLogging { - get { return overrideLogging; } - set { overrideLogging = value; } - } - - - /// - /// Create and initialize the VelocityEngine instance and return it - /// - /// VelocityEngine - /// - /// - /// - /// - /// - public VelocityEngine CreateVelocityEngine() + // merge local properties if set. + if (velocityProperties.Count > 0) { - ExtendedProperties extendedProperties = new ExtendedProperties(); - VelocityEngine velocityEngine = NewVelocityEngine(); + foreach (KeyValuePair pair in velocityProperties) + { + extendedProperties.SetProperty(pair.Key, pair.Value); + } + } - LoadDefaultProperties(extendedProperties); + // Set a resource loader path, if required. + if (!preferFileSystemAccess && resourceLoaderPaths.Count == 0) + { + throw new ArgumentException("When using SpringResourceLoader you must provide a path using the ResourceLoaderPath property"); + } - // Load config file if set. - if (configLocation != null) { - if (log.IsEnabled(LogLevel.Information)) { - log.LogInformation(string.Format("Loading Velocity config from [{0}]", configLocation)); + if (resourceLoaderPaths.Count > 0) + { + InitVelocityResourceLoader(velocityEngine, extendedProperties, resourceLoaderPaths); + } + + // Log via Commons Logging? + if (overrideLogging) + { + velocityEngine.SetProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM, new CommonsLoggingLogSystem()); + } + + PostProcessVelocityEngine(velocityEngine); + + try + { + velocityEngine.Init(extendedProperties); + } + catch (Exception ex) + { + throw new VelocityException(ex.ToString(), ex); + } + + return velocityEngine; + } + + /// + /// This is to overcome an issue with the current NVelocity library, it seems the + /// default runetime properties/directives (nvelocity.properties and directive.properties + /// files) are not being properly located in the library at load time. A jira should + /// be filed but for now we attempt to do this on our own. Particularly our + /// concern here is with several required properties which I don't want + /// to require users to re-defined. e.g.,: + ///
+ /// + /// Pre-requisites:
+ /// resource.manager.class=NVelocity.Runtime.Resource.ResourceManagerImpl
+ /// directive.manager=NVelocity.Runtime.Directive.DirectiveManager
+ /// runtime.introspector.uberspect=NVelocity.Util.Introspection.UberspectImpl
+ ///
+ private static void LoadDefaultProperties(ExtendedProperties extendedProperties) + { + IResource defaultRuntimeProperties = new AssemblyResource("assembly://NVelocity/NVelocity.Runtime.Defaults/nvelocity.properties"); + IResource defaultRuntimeDirectives = new AssemblyResource("assembly://NVelocity/NVelocity.Runtime.Defaults/directive.properties"); + FillProperties(extendedProperties, defaultRuntimeProperties, true); + FillProperties(extendedProperties, defaultRuntimeDirectives, true); + } + + /// + /// Return a new VelocityEngine. Subclasses can override this for + /// custom initialization, or for using a mock object for testing.
+ /// Called by CreateVelocityEngine() + ///
+ /// VelocityEngine instance (non-configured) + /// + protected static VelocityEngine NewVelocityEngine() + { + return new VelocityEngine(); + } + + /// + /// Initialize a Velocity resource loader for the given VelocityEngine: + /// either a standard Velocity FileResourceLoader or a SpringResourceLoader. + ///
Called by CreateVelocityEngine(). + ///
+ /// velocityEngine the VelocityEngine to configure + /// + /// paths the path list to load Velocity resources from + /// + /// + /// + /// + protected void InitVelocityResourceLoader(VelocityEngine velocityEngine, ExtendedProperties extendedProperties, IList paths) + { + if (PreferFileSystemAccess) + { + // Try to load via the file system, fall back to SpringResourceLoader + // (for hot detection of template changes, if possible). + IList resolvedPaths = new List(); + try + { + foreach (string path in paths) + { + IResource resource = ResourceLoader.GetResource(path); + resolvedPaths.Add(resource.File.FullName); } - FillProperties(extendedProperties, configLocation, false); + + extendedProperties.SetProperty(RuntimeConstants.RESOURCE_LOADER, VelocityConstants.File); + extendedProperties.SetProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH, + StringUtils.CollectionToCommaDelimitedString(resolvedPaths)); } - - // merge local properties if set. - if (velocityProperties.Count > 0) { - foreach (KeyValuePair pair in velocityProperties) { - extendedProperties.SetProperty(pair.Key, pair.Value); - } - } - - // Set a resource loader path, if required. - if (!preferFileSystemAccess && resourceLoaderPaths.Count == 0) { - throw new ArgumentException("When using SpringResourceLoader you must provide a path using the ResourceLoaderPath property"); - } - - if (resourceLoaderPaths.Count > 0) { - InitVelocityResourceLoader(velocityEngine, extendedProperties, resourceLoaderPaths); - } - - // Log via Commons Logging? - if (overrideLogging) { - velocityEngine.SetProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM, new CommonsLoggingLogSystem()); - } - - PostProcessVelocityEngine(velocityEngine); - - try { - velocityEngine.Init(extendedProperties); - } catch (Exception ex) { - throw new VelocityException(ex.ToString(), ex); - } - - return velocityEngine; - } - - /// - /// This is to overcome an issue with the current NVelocity library, it seems the - /// default runetime properties/directives (nvelocity.properties and directive.properties - /// files) are not being properly located in the library at load time. A jira should - /// be filed but for now we attempt to do this on our own. Particularly our - /// concern here is with several required properties which I don't want - /// to require users to re-defined. e.g.,: - ///
- /// - /// Pre-requisites:
- /// resource.manager.class=NVelocity.Runtime.Resource.ResourceManagerImpl
- /// directive.manager=NVelocity.Runtime.Directive.DirectiveManager
- /// runtime.introspector.uberspect=NVelocity.Util.Introspection.UberspectImpl
- ///
- private static void LoadDefaultProperties(ExtendedProperties extendedProperties) { - IResource defaultRuntimeProperties = new AssemblyResource("assembly://NVelocity/NVelocity.Runtime.Defaults/nvelocity.properties"); - IResource defaultRuntimeDirectives = new AssemblyResource("assembly://NVelocity/NVelocity.Runtime.Defaults/directive.properties"); - FillProperties(extendedProperties, defaultRuntimeProperties, true); - FillProperties(extendedProperties, defaultRuntimeDirectives, true); - } - - /// - /// Return a new VelocityEngine. Subclasses can override this for - /// custom initialization, or for using a mock object for testing.
- /// Called by CreateVelocityEngine() - ///
- /// VelocityEngine instance (non-configured) - /// - protected static VelocityEngine NewVelocityEngine() - { - return new VelocityEngine(); - } - - /// - /// Initialize a Velocity resource loader for the given VelocityEngine: - /// either a standard Velocity FileResourceLoader or a SpringResourceLoader. - ///
Called by CreateVelocityEngine(). - ///
- /// velocityEngine the VelocityEngine to configure - /// - /// paths the path list to load Velocity resources from - /// - /// - /// - /// - protected void InitVelocityResourceLoader(VelocityEngine velocityEngine, ExtendedProperties extendedProperties, IList paths) - { - - if (PreferFileSystemAccess) { - // Try to load via the file system, fall back to SpringResourceLoader - // (for hot detection of template changes, if possible). - IList resolvedPaths = new List(); - try { - foreach (string path in paths) { - IResource resource = ResourceLoader.GetResource(path); - resolvedPaths.Add(resource.File.FullName); - } - - extendedProperties.SetProperty(RuntimeConstants.RESOURCE_LOADER, VelocityConstants.File); - extendedProperties.SetProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH, + catch (IOException ex) + { + if (log.IsEnabled(LogLevel.Debug)) + { + string message = string.Format("Cannot resolve resource loader path [{0}] to [File]: using SpringResourceLoader", StringUtils.CollectionToCommaDelimitedString(resolvedPaths)); - } catch (IOException ex) { - if (log.IsEnabled(LogLevel.Debug)) - { - string message = string.Format("Cannot resolve resource loader path [{0}] to [File]: using SpringResourceLoader", - StringUtils.CollectionToCommaDelimitedString(resolvedPaths)); - log.LogError(ex, message); - } + log.LogError(ex, message); + } - InitSpringResourceLoader(velocityEngine, extendedProperties, StringUtils.CollectionToCommaDelimitedString(paths)); - } - } else { - // Always load via SpringResourceLoader (without hot detection of template changes). - if (log.IsEnabled(LogLevel.Debug)) { - log.LogDebug("File system access not preferred: using SpringResourceLoader"); - } InitSpringResourceLoader(velocityEngine, extendedProperties, StringUtils.CollectionToCommaDelimitedString(paths)); } } - - /// - /// Initialize a SpringResourceLoader for the given VelocityEngine. - ///
Called by InitVelocityResourceLoader. - /// - /// Important: the NVeloctity ResourceLoaderFactory.getLoader - /// method replaces ';' with ',' when attempting to construct our resource - /// loader. The name on the SPRING_RESOURCE_LOADER_CLASS property - /// has to be in the form of "ClassFullName; AssemblyName" in replacement - /// of the tranditional "ClassFullName, AssemblyName" to work. - ///
- /// velocityEngine the VelocityEngine to configure - /// - /// resourceLoaderPath the path to load Velocity resources from - /// - /// - protected void InitSpringResourceLoader(VelocityEngine velocityEngine, ExtendedProperties extendedProperties, string resourceLoaderPathString) + else { - extendedProperties.SetProperty(RuntimeConstants.RESOURCE_LOADER, SpringResourceLoader.NAME); - Type springResourceLoaderType = typeof(SpringResourceLoader); - string springResourceLoaderTypeName = springResourceLoaderType.FullName + "; " + springResourceLoaderType.Assembly.GetName().Name; - extendedProperties.SetProperty(SpringResourceLoader.SPRING_RESOURCE_LOADER_CLASS, springResourceLoaderTypeName); - velocityEngine.SetApplicationAttribute(SpringResourceLoader.SPRING_RESOURCE_LOADER, ResourceLoader); - velocityEngine.SetApplicationAttribute(SpringResourceLoader.SPRING_RESOURCE_LOADER_PATH, resourceLoaderPathString); - } - - /// - /// To be implemented by subclasses that want to to perform custom - /// post-processing of the VelocityEngine after this FactoryObject - /// performed its default configuration (but before VelocityEngine.init) - ///
- /// Called by CreateVelocityEngine - ///
- /// velocityEngine the current VelocityEngine - /// - /// - /// - protected virtual void PostProcessVelocityEngine(VelocityEngine velocityEngine) - { - } - - /// - /// Populates the velocity properties from the given resource - /// - /// ExtendedProperties instance to populate - /// The resource from which to load the properties - /// A flag indicated weather the properties loaded from the resource should be appended or replaced in the extendedProperties - private static void FillProperties(ExtendedProperties extendedProperties, IInputStreamSource resource, bool append) { - try { - if (append) { - extendedProperties.Load(resource.InputStream); - } else { - ExtendedProperties overrides = new ExtendedProperties(); - overrides.Load(resource.InputStream); - foreach (DictionaryEntry entry in overrides) { - extendedProperties.SetProperty(Convert.ToString(entry.Key), entry.Value); - } - } - } finally { - resource.InputStream.Close(); + // Always load via SpringResourceLoader (without hot detection of template changes). + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug("File system access not preferred: using SpringResourceLoader"); } + + InitSpringResourceLoader(velocityEngine, extendedProperties, StringUtils.CollectionToCommaDelimitedString(paths)); + } + } + + /// + /// Initialize a SpringResourceLoader for the given VelocityEngine. + ///
Called by InitVelocityResourceLoader. + /// + /// Important: the NVeloctity ResourceLoaderFactory.getLoader + /// method replaces ';' with ',' when attempting to construct our resource + /// loader. The name on the SPRING_RESOURCE_LOADER_CLASS property + /// has to be in the form of "ClassFullName; AssemblyName" in replacement + /// of the tranditional "ClassFullName, AssemblyName" to work. + ///
+ /// velocityEngine the VelocityEngine to configure + /// + /// resourceLoaderPath the path to load Velocity resources from + /// + /// + protected void InitSpringResourceLoader(VelocityEngine velocityEngine, ExtendedProperties extendedProperties, string resourceLoaderPathString) + { + extendedProperties.SetProperty(RuntimeConstants.RESOURCE_LOADER, SpringResourceLoader.NAME); + Type springResourceLoaderType = typeof(SpringResourceLoader); + string springResourceLoaderTypeName = springResourceLoaderType.FullName + "; " + springResourceLoaderType.Assembly.GetName().Name; + extendedProperties.SetProperty(SpringResourceLoader.SPRING_RESOURCE_LOADER_CLASS, springResourceLoaderTypeName); + velocityEngine.SetApplicationAttribute(SpringResourceLoader.SPRING_RESOURCE_LOADER, ResourceLoader); + velocityEngine.SetApplicationAttribute(SpringResourceLoader.SPRING_RESOURCE_LOADER_PATH, resourceLoaderPathString); + } + + /// + /// To be implemented by subclasses that want to to perform custom + /// post-processing of the VelocityEngine after this FactoryObject + /// performed its default configuration (but before VelocityEngine.init) + ///
+ /// Called by CreateVelocityEngine + ///
+ /// velocityEngine the current VelocityEngine + /// + /// + /// + protected virtual void PostProcessVelocityEngine(VelocityEngine velocityEngine) + { + } + + /// + /// Populates the velocity properties from the given resource + /// + /// ExtendedProperties instance to populate + /// The resource from which to load the properties + /// A flag indicated weather the properties loaded from the resource should be appended or replaced in the extendedProperties + private static void FillProperties(ExtendedProperties extendedProperties, IInputStreamSource resource, bool append) + { + try + { + if (append) + { + extendedProperties.Load(resource.InputStream); + } + else + { + ExtendedProperties overrides = new ExtendedProperties(); + overrides.Load(resource.InputStream); + foreach (DictionaryEntry entry in overrides) + { + extendedProperties.SetProperty(Convert.ToString(entry.Key), entry.Value); + } + } + } + finally + { + resource.InputStream.Close(); } } } diff --git a/src/Spring/Spring.Template.Velocity/Template/Velocity/VelocityEngineFactoryObject.cs b/src/Spring/Spring.Template.Velocity/Template/Velocity/VelocityEngineFactoryObject.cs index 21eab4f1..f7c90645 100644 --- a/src/Spring/Spring.Template.Velocity/Template/Velocity/VelocityEngineFactoryObject.cs +++ b/src/Spring/Spring.Template.Velocity/Template/Velocity/VelocityEngineFactoryObject.cs @@ -22,48 +22,52 @@ using NVelocity.App; using Spring.Context; using Spring.Objects.Factory; -namespace Spring.Template.Velocity +namespace Spring.Template.Velocity; + +/// +/// FactoryObject implementation that configures a VelocityEngine and provides it +/// as an object reference. This object is intended for any kind of usage of Velocity in +/// application code, e.g. for generating email content. +/// +/// See the base class VelocityEngineFactory for configuration details. +/// +/// +/// Erez Mazor +public class VelocityEngineFactoryObject : VelocityEngineFactory, IFactoryObject, IInitializingObject, IResourceLoaderAware { + private VelocityEngine velocityEngine; + /// - /// FactoryObject implementation that configures a VelocityEngine and provides it - /// as an object reference. This object is intended for any kind of usage of Velocity in - /// application code, e.g. for generating email content. - /// - /// See the base class VelocityEngineFactory for configuration details. + /// Get the velocity engine underlying object /// - /// - /// Erez Mazor - public class VelocityEngineFactoryObject : VelocityEngineFactory, IFactoryObject, IInitializingObject, IResourceLoaderAware + /// An instance of a configured VelocityEngine + /// + public object GetObject() { - private VelocityEngine velocityEngine; - /// - /// Get the velocity engine underlying object - /// - /// An instance of a configured VelocityEngine - /// - public object GetObject() { - return velocityEngine; - } + return velocityEngine; + } - /// - /// Get the type of the velocity engine - /// - public Type ObjectType { - get { return velocityEngine.GetType(); } - } + /// + /// Get the type of the velocity engine + /// + public Type ObjectType + { + get { return velocityEngine.GetType(); } + } - /// - /// Singleton - /// - public bool IsSingleton { - get { return true; } - } + /// + /// Singleton + /// + public bool IsSingleton + { + get { return true; } + } - /// - /// Facilitate the creation of the velocity engine object - /// - public void AfterPropertiesSet() { - velocityEngine = CreateVelocityEngine(); - } + /// + /// Facilitate the creation of the velocity engine object + /// + public void AfterPropertiesSet() + { + velocityEngine = CreateVelocityEngine(); } } diff --git a/src/Spring/Spring.Template.Velocity/Template/Velocity/VelocityEngineUtils.cs b/src/Spring/Spring.Template.Velocity/Template/Velocity/VelocityEngineUtils.cs index e3eb233e..e803031f 100644 --- a/src/Spring/Spring.Template.Velocity/Template/Velocity/VelocityEngineUtils.cs +++ b/src/Spring/Spring.Template.Velocity/Template/Velocity/VelocityEngineUtils.cs @@ -23,51 +23,56 @@ using NVelocity; using NVelocity.App; using NVelocity.Exception; -namespace Spring.Template.Velocity{ +namespace Spring.Template.Velocity; + +/// +/// Generalized Utility class for merging velocity templates into a text writer or return the result as a string +/// +/// Erez Mazor +public class VelocityEngineUtils +{ /// - /// Generalized Utility class for merging velocity templates into a text writer or return the result as a string + /// Merge the specified Velocity template with the given model and write + /// the result to the given Writer. /// - /// Erez Mazor - public class VelocityEngineUtils + /// VelocityEngine to work with + /// the location of template, relative to Velocity's resource loader path + /// encoding the encoding of the template file + /// the Hashtable that contains model names as keys and model objects + /// writer the TextWriter to write the result to + /// thrown if any exception is thrown by the velocity engine + public static void MergeTemplate( + VelocityEngine velocityEngine, string templateLocation, string encoding, Hashtable model, TextWriter writer) { - /// - /// Merge the specified Velocity template with the given model and write - /// the result to the given Writer. - /// - /// VelocityEngine to work with - /// the location of template, relative to Velocity's resource loader path - /// encoding the encoding of the template file - /// the Hashtable that contains model names as keys and model objects - /// writer the TextWriter to write the result to - /// thrown if any exception is thrown by the velocity engine - public static void MergeTemplate( - VelocityEngine velocityEngine, string templateLocation, string encoding, Hashtable model, TextWriter writer) { - - try { - VelocityContext velocityContext = new VelocityContext(model); - velocityEngine.MergeTemplate(templateLocation, encoding, velocityContext, writer); - } catch (VelocityException) { - throw; - } catch (Exception ex) { - throw new VelocityException(ex.ToString(), ex); - } + try + { + VelocityContext velocityContext = new VelocityContext(model); + velocityEngine.MergeTemplate(templateLocation, encoding, velocityContext, writer); } - - /// - /// Merge the specified Velocity template with the given model into a string. - /// - /// VelocityEngine to work with - /// the location of template, relative to Velocity's resource loader path - /// the encoding string to use for the merge - /// the Hashtable that contains model names as keys and model objects - /// the result as string - /// thrown if any exception is thrown by the velocity engine - public static string MergeTemplateIntoString( - VelocityEngine velocityEngine, string templateLocation, string encoding, Hashtable model) { - - StringWriter result = new StringWriter(); - MergeTemplate(velocityEngine, templateLocation, encoding, model, result); - return result.ToString(); + catch (VelocityException) + { + throw; + } + catch (Exception ex) + { + throw new VelocityException(ex.ToString(), ex); } } + + /// + /// Merge the specified Velocity template with the given model into a string. + /// + /// VelocityEngine to work with + /// the location of template, relative to Velocity's resource loader path + /// the encoding string to use for the merge + /// the Hashtable that contains model names as keys and model objects + /// the result as string + /// thrown if any exception is thrown by the velocity engine + public static string MergeTemplateIntoString( + VelocityEngine velocityEngine, string templateLocation, string encoding, Hashtable model) + { + StringWriter result = new StringWriter(); + MergeTemplate(velocityEngine, templateLocation, encoding, model, result); + return result.ToString(); + } } diff --git a/src/Spring/Spring.Testing.Microsoft/AssemblyInfo.cs b/src/Spring/Spring.Testing.Microsoft/AssemblyInfo.cs index 48788a27..984b0293 100644 --- a/src/Spring/Spring.Testing.Microsoft/AssemblyInfo.cs +++ b/src/Spring/Spring.Testing.Microsoft/AssemblyInfo.cs @@ -1,4 +1,4 @@ using System.Reflection; [assembly: AssemblyTitle("Spring.Testing.Microsoft")] -[assembly: AssemblyDescription("Interfaces and classes that provide Microsoft Unit Testing integration in Spring.Net")] \ No newline at end of file +[assembly: AssemblyDescription("Interfaces and classes that provide Microsoft Unit Testing integration in Spring.Net")] diff --git a/src/Spring/Spring.Testing.Microsoft/Testing/Microsoft/AbstractDependencyInjectionSpringContextTests.cs b/src/Spring/Spring.Testing.Microsoft/Testing/Microsoft/AbstractDependencyInjectionSpringContextTests.cs index c391d551..58393ccd 100644 --- a/src/Spring/Spring.Testing.Microsoft/Testing/Microsoft/AbstractDependencyInjectionSpringContextTests.cs +++ b/src/Spring/Spring.Testing.Microsoft/Testing/Microsoft/AbstractDependencyInjectionSpringContextTests.cs @@ -21,347 +21,350 @@ using System.Reflection; using Microsoft.Extensions.Logging; using Microsoft.VisualStudio.TestTools.UnitTesting; - using Spring.Context; using Spring.Objects.Factory; using Spring.Objects.Factory.Config; using Spring.Objects.Factory.Support; -namespace Spring.Testing.Microsoft +namespace Spring.Testing.Microsoft; + +/// +/// Convenient superclass for tests depending on a Spring context. +/// The test instance itself is populated by Dependency Injection. +/// +/// +/// +///

Really for integration testing, not unit testing. +/// You should not normally use the Spring container +/// for unit tests: simply populate your objects in plain NUnit tests!

+/// +///

This supports two modes of populating the test: +///

    +///
  • Via Property Dependency Injection. Simply express dependencies on objects +/// in the test fixture, and they will be satisfied by autowiring by type.
  • +///
  • Via Field Injection. Declare protected variables of the required type +/// which match named beans in the context. This is autowire by name, +/// rather than type. This approach is based on an approach originated by +/// Ara Abrahmian. Property Dependency Injection is the default: set the +/// "populateProtectedVariables" property to true in the constructor to switch +/// on Field Injection.
  • +///

+/// +///

This class will normally cache contexts based on a context key: +/// normally the config locations String array describing the Spring resource +/// descriptors making up the context. Unless the SetDirty() method +/// is called by a test, the context will not be reloaded, even across different +/// subclasses of this test. This is particularly beneficial if your context is +/// slow to construct, for example if you are using Hibernate and the time taken +/// to load the mappings is an issue.

+/// +///

If you don't want this behavior, you can override the ContextKey +/// property, most likely to return the test class. In conjunction with this you would +/// probably override the GetContext method, which by default loads +/// the locations specified by the ConfigLocations property.

+/// +///

WARNING: When doing integration tests from within VS.NET, only use +/// assembly resource URLs. Else, you may see misleading failures when changing +/// context locations.

+///
+/// +/// Rod Johnson +/// Rob Harrop +/// Rick Evans +/// Aleksandar Seovic (.NET) +public abstract class AbstractDependencyInjectionSpringContextTests : AbstractSpringContextTests { + private bool populateProtectedVariables = false; + private AutoWiringMode autowireMode = AutoWiringMode.ByType; + private bool dependencyCheck = true; + /// - /// Convenient superclass for tests depending on a Spring context. - /// The test instance itself is populated by Dependency Injection. + /// Application context this test will run against. /// - /// - /// - ///

Really for integration testing, not unit testing. - /// You should not normally use the Spring container - /// for unit tests: simply populate your objects in plain NUnit tests!

- /// - ///

This supports two modes of populating the test: - ///

    - ///
  • Via Property Dependency Injection. Simply express dependencies on objects - /// in the test fixture, and they will be satisfied by autowiring by type.
  • - ///
  • Via Field Injection. Declare protected variables of the required type - /// which match named beans in the context. This is autowire by name, - /// rather than type. This approach is based on an approach originated by - /// Ara Abrahmian. Property Dependency Injection is the default: set the - /// "populateProtectedVariables" property to true in the constructor to switch - /// on Field Injection.
  • - ///

- /// - ///

This class will normally cache contexts based on a context key: - /// normally the config locations String array describing the Spring resource - /// descriptors making up the context. Unless the SetDirty() method - /// is called by a test, the context will not be reloaded, even across different - /// subclasses of this test. This is particularly beneficial if your context is - /// slow to construct, for example if you are using Hibernate and the time taken - /// to load the mappings is an issue.

- /// - ///

If you don't want this behavior, you can override the ContextKey - /// property, most likely to return the test class. In conjunction with this you would - /// probably override the GetContext method, which by default loads - /// the locations specified by the ConfigLocations property.

- /// - ///

WARNING: When doing integration tests from within VS.NET, only use - /// assembly resource URLs. Else, you may see misleading failures when changing - /// context locations.

- ///
- /// - /// Rod Johnson - /// Rob Harrop - /// Rick Evans - /// Aleksandar Seovic (.NET) - public abstract class AbstractDependencyInjectionSpringContextTests : AbstractSpringContextTests + protected IConfigurableApplicationContext applicationContext; + + /// + /// Holds names of the fields that should be used for field injection. + /// + protected string[] managedVariableNames; + + private int loadCount = 0; + + /// + /// Default constructor for AbstractDependencyInjectionSpringContextTests. + /// + public AbstractDependencyInjectionSpringContextTests() { - private bool populateProtectedVariables = false; - private AutoWiringMode autowireMode = AutoWiringMode.ByType; - private bool dependencyCheck = true; + } - /// - /// Application context this test will run against. - /// - protected IConfigurableApplicationContext applicationContext; + /// + /// Gets or sets a flag specifying whether to populate protected + /// variables of this test case. + /// + /// + /// A flag specifying whether to populate protected variables of this test case. + /// Default is false. + /// + public bool PopulateProtectedVariables + { + get { return populateProtectedVariables; } + set { populateProtectedVariables = value; } + } - /// - /// Holds names of the fields that should be used for field injection. - /// - protected string[] managedVariableNames; - private int loadCount = 0; + /// + /// Gets or sets the autowire mode for test properties set by Dependency Injection. + /// + /// + /// The autowire mode for test properties set by Dependency Injection. + /// The default is . + /// + public AutoWiringMode AutowireMode + { + get { return autowireMode; } + set { autowireMode = value; } + } - /// - /// Default constructor for AbstractDependencyInjectionSpringContextTests. - /// - public AbstractDependencyInjectionSpringContextTests() - {} + /// + /// Gets or sets a flag specifying whether or not dependency checking + /// should be performed for test properties set by Dependency Injection. + /// + /// + ///

A flag specifying whether or not dependency checking + /// should be performed for test properties set by Dependency Injection.

+ ///

The default is true, meaning that tests cannot be run + /// unless all properties are populated.

+ ///
+ public bool DependencyCheck + { + get { return dependencyCheck; } + set { dependencyCheck = value; } + } - /// - /// Gets or sets a flag specifying whether to populate protected - /// variables of this test case. - /// - /// - /// A flag specifying whether to populate protected variables of this test case. - /// Default is false. - /// - public bool PopulateProtectedVariables + /// + /// Gets the current number of context load attempts. + /// + public int LoadCount + { + get { return loadCount; } + } + + /// + /// Called to say that the "applicationContext" instance variable is dirty and + /// should be reloaded. We need to do this if a test has modified the context + /// (for example, by replacing an object definition). + /// + public void SetDirty() + { + SetDirty(ConfigLocations); + } + + /// + /// Test setup method. + /// + [TestInitialize] + public virtual void TestInitialize() + { + this.applicationContext = GetContext(ContextKey); + InjectDependencies(); + try { - get { return populateProtectedVariables; } - set { populateProtectedVariables = value; } + OnTestInitialize(); } - - /// - /// Gets or sets the autowire mode for test properties set by Dependency Injection. - /// - /// - /// The autowire mode for test properties set by Dependency Injection. - /// The default is . - /// - public AutoWiringMode AutowireMode + catch (Exception ex) { - get { return autowireMode; } - set { autowireMode = value; } + logger.LogError(ex, "Setup error"); + throw; } + } - /// - /// Gets or sets a flag specifying whether or not dependency checking - /// should be performed for test properties set by Dependency Injection. - /// - /// - ///

A flag specifying whether or not dependency checking - /// should be performed for test properties set by Dependency Injection.

- ///

The default is true, meaning that tests cannot be run - /// unless all properties are populated.

- ///
- public bool DependencyCheck + /// + /// Inject dependencies into 'this' instance (that is, this test instance). + /// + /// + ///

The default implementation populates protected variables if the + /// property is set, else + /// uses autowiring if autowiring is switched on (which it is by default).

+ ///

You can certainly override this method if you want to totally control + /// how dependencies are injected into 'this' instance.

+ ///
+ protected virtual void InjectDependencies() + { + if (PopulateProtectedVariables) { - get { return dependencyCheck; } - set { dependencyCheck = value; } - } - - /// - /// Gets the current number of context load attempts. - /// - public int LoadCount - { - get { return loadCount; } - } - - /// - /// Called to say that the "applicationContext" instance variable is dirty and - /// should be reloaded. We need to do this if a test has modified the context - /// (for example, by replacing an object definition). - /// - public void SetDirty() - { - SetDirty(ConfigLocations); - } - - /// - /// Test setup method. - /// - [TestInitialize] - public virtual void TestInitialize() - { - this.applicationContext = GetContext(ContextKey); - InjectDependencies(); - try + if (this.managedVariableNames == null) { - OnTestInitialize(); + InitManagedVariableNames(); } - catch (Exception ex) + + InjectProtectedVariables(); + } + else if (AutowireMode != AutoWiringMode.No) + { + IConfigurableListableObjectFactory factory = this.applicationContext.ObjectFactory; + ((AbstractObjectFactory) factory).IgnoreDependencyType(typeof(AutoWiringMode)); + factory.AutowireObjectProperties(this, AutowireMode, DependencyCheck); + } + } + + /// + /// Gets a key for this context. Usually based on config locations, but + /// a subclass overriding buildContext() might want to return its class. + /// + protected virtual object ContextKey + { + get { return ConfigLocations; } + } + + /// + /// Loads application context from the specified resource locations. + /// + /// Resources to load object definitions from. + protected override IConfigurableApplicationContext LoadContextLocations(string[] locations) + { + ++this.loadCount; + return base.LoadContextLocations(locations); + } + + /// + /// Retrieves the names of the fields that should be used for field injection. + /// + protected virtual void InitManagedVariableNames() + { + List managedVarNames = new List(); + Type type = GetType(); + + do + { + FieldInfo[] fields = + type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Instance); + if (logger.IsEnabled(LogLevel.Debug)) { - logger.LogError(ex, "Setup error"); - throw; + logger.LogDebug("Found " + fields.Length + " fields on " + type); } - } - /// - /// Inject dependencies into 'this' instance (that is, this test instance). - /// - /// - ///

The default implementation populates protected variables if the - /// property is set, else - /// uses autowiring if autowiring is switched on (which it is by default).

- ///

You can certainly override this method if you want to totally control - /// how dependencies are injected into 'this' instance.

- ///
- protected virtual void InjectDependencies() - { - if (PopulateProtectedVariables) + for (int i = 0; i < fields.Length; i++) { - if (this.managedVariableNames == null) - { - InitManagedVariableNames(); - } - InjectProtectedVariables(); - } - else if (AutowireMode != AutoWiringMode.No) - { - IConfigurableListableObjectFactory factory = this.applicationContext.ObjectFactory; - ((AbstractObjectFactory) factory).IgnoreDependencyType(typeof(AutoWiringMode)); - factory.AutowireObjectProperties(this, AutowireMode, DependencyCheck); - } - } - - /// - /// Gets a key for this context. Usually based on config locations, but - /// a subclass overriding buildContext() might want to return its class. - /// - protected virtual object ContextKey - { - get { return ConfigLocations; } - } - - /// - /// Loads application context from the specified resource locations. - /// - /// Resources to load object definitions from. - protected override IConfigurableApplicationContext LoadContextLocations(string[] locations) - { - ++this.loadCount; - return base.LoadContextLocations(locations); - } - - /// - /// Retrieves the names of the fields that should be used for field injection. - /// - protected virtual void InitManagedVariableNames() - { - List managedVarNames = new List(); - Type type = GetType(); - - do - { - FieldInfo[] fields = - type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Instance); + FieldInfo field = fields[i]; if (logger.IsEnabled(LogLevel.Debug)) { - logger.LogDebug("Found " + fields.Length + " fields on " + type); + logger.LogDebug("Candidate field: " + field); } - for (int i = 0; i < fields.Length; i++) + if (IsProtectedInstanceField(field)) { - FieldInfo field = fields[i]; - if (logger.IsEnabled(LogLevel.Debug)) + object oldValue = field.GetValue(this); + if (oldValue == null) { - logger.LogDebug("Candidate field: " + field); - } - if (IsProtectedInstanceField(field)) - { - object oldValue = field.GetValue(this); - if (oldValue == null) - { - managedVarNames.Add(field.Name); - if (logger.IsEnabled(LogLevel.Debug)) - { - logger.LogDebug("Added managed variable '" + field.Name + "'"); - } - } - else - { - if (logger.IsEnabled(LogLevel.Debug)) - { - logger.LogDebug("Rejected managed variable '" + field.Name + "'"); - } - } - } - } - type = type.BaseType; - } while (type != typeof (AbstractDependencyInjectionSpringContextTests)); - - this.managedVariableNames = managedVarNames.ToArray(); - } - - private static bool IsProtectedInstanceField(FieldInfo field) - { - return field.IsFamily; - } - - /// - /// Injects protected fields using Field Injection. - /// - protected virtual void InjectProtectedVariables() - { - for (int i = 0; i < this.managedVariableNames.Length; i++) - { - string fieldName = this.managedVariableNames[i]; - Object obj = null; - try - { - FieldInfo field = GetType().GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Instance); - if (field != null) - { - BeforeProtectedVariableInjection(field); - obj = this.applicationContext.GetObject(fieldName, field.FieldType); - field.SetValue(this, obj); + managedVarNames.Add(field.Name); if (logger.IsEnabled(LogLevel.Debug)) { - logger.LogDebug("Populated field: " + field); + logger.LogDebug("Added managed variable '" + field.Name + "'"); } } else { - if (logger.IsEnabled(LogLevel.Warning)) + if (logger.IsEnabled(LogLevel.Debug)) { - logger.LogWarning("No field with name '" + fieldName + "'"); + logger.LogDebug("Rejected managed variable '" + field.Name + "'"); } } } - catch (NoSuchObjectDefinitionException) + } + + type = type.BaseType; + } while (type != typeof(AbstractDependencyInjectionSpringContextTests)); + + this.managedVariableNames = managedVarNames.ToArray(); + } + + private static bool IsProtectedInstanceField(FieldInfo field) + { + return field.IsFamily; + } + + /// + /// Injects protected fields using Field Injection. + /// + protected virtual void InjectProtectedVariables() + { + for (int i = 0; i < this.managedVariableNames.Length; i++) + { + string fieldName = this.managedVariableNames[i]; + Object obj = null; + try + { + FieldInfo field = GetType().GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Instance); + if (field != null) + { + BeforeProtectedVariableInjection(field); + obj = this.applicationContext.GetObject(fieldName, field.FieldType); + field.SetValue(this, obj); + if (logger.IsEnabled(LogLevel.Debug)) + { + logger.LogDebug("Populated field: " + field); + } + } + else { if (logger.IsEnabled(LogLevel.Warning)) { - logger.LogWarning("No object definition with name '" + fieldName + "'"); + logger.LogWarning("No field with name '" + fieldName + "'"); } } } - } - - /// - /// Called right before a field is being injected - /// - protected virtual void BeforeProtectedVariableInjection(FieldInfo fieldInfo) - { - - } - - /// - /// Subclasses can override this method in order to - /// add custom test setup logic. - /// - protected virtual void OnTestInitialize() - {} - - /// - /// Test teardown method. - /// - [TestCleanup] - public void TestCleanup() - { - try + catch (NoSuchObjectDefinitionException) { - OnTestCleanup(); - } - catch (Exception ex) - { - logger.LogError(ex, "OnTearDown error"); + if (logger.IsEnabled(LogLevel.Warning)) + { + logger.LogWarning("No object definition with name '" + fieldName + "'"); + } } } - - /// - /// Subclasses can override this method in order to - /// add custom test teardown logic. - /// - protected virtual void OnTestCleanup() - {} - - - /// - /// Subclasses must implement this property to return the locations of their - /// config files. A plain path will be treated as a file system location. - /// - /// An array of config locations - protected abstract string[] ConfigLocations { get; } } + + /// + /// Called right before a field is being injected + /// + protected virtual void BeforeProtectedVariableInjection(FieldInfo fieldInfo) + { + } + + /// + /// Subclasses can override this method in order to + /// add custom test setup logic. + /// + protected virtual void OnTestInitialize() + { + } + + /// + /// Test teardown method. + /// + [TestCleanup] + public void TestCleanup() + { + try + { + OnTestCleanup(); + } + catch (Exception ex) + { + logger.LogError(ex, "OnTearDown error"); + } + } + + /// + /// Subclasses can override this method in order to + /// add custom test teardown logic. + /// + protected virtual void OnTestCleanup() + { + } + + /// + /// Subclasses must implement this property to return the locations of their + /// config files. A plain path will be treated as a file system location. + /// + /// An array of config locations + protected abstract string[] ConfigLocations { get; } } diff --git a/src/Spring/Spring.Testing.Microsoft/Testing/Microsoft/AbstractSpringContextTests.cs b/src/Spring/Spring.Testing.Microsoft/Testing/Microsoft/AbstractSpringContextTests.cs index ada73c83..a3d2934c 100644 --- a/src/Spring/Spring.Testing.Microsoft/Testing/Microsoft/AbstractSpringContextTests.cs +++ b/src/Spring/Spring.Testing.Microsoft/Testing/Microsoft/AbstractSpringContextTests.cs @@ -24,214 +24,216 @@ using Spring.Context; using Spring.Context.Support; using Spring.Util; -namespace Spring.Testing.Microsoft +namespace Spring.Testing.Microsoft; + +/// +/// Superclass for NUnit test cases using a Spring context. +/// +/// +///

Maintains a cache of contexts by key. This has significant performance +/// benefit if initializing the context would take time. While initializing a +/// Spring context itself is very quick, some objects in a context, such as +/// a LocalSessionFactoryObject for working with NHibernate, may take time to +/// initialize. Hence it often makes sense to do that initializing once.

+///

Normally you won't extend this class directly but rather extend one +/// of its subclasses.

+///
+/// Rod Johnson +/// Aleksandar Seovic (.NET) +public abstract class AbstractSpringContextTests { /// - /// Superclass for NUnit test cases using a Spring context. + /// Map of context keys returned by subclasses of this class, to + /// Spring contexts. + /// + private static readonly IDictionary contextKeyToContextMap; + + /// + /// Static ctor to avoid "beforeFieldInit" problem. + /// + static AbstractSpringContextTests() + { + contextKeyToContextMap = new Hashtable(); + } + + /// + /// Disposes any cached context instance and removes it from cache. + /// + public static void ClearContextCache() + { + foreach (IApplicationContext ctx in contextKeyToContextMap.Values) + { + ctx.Dispose(); + } + + contextKeyToContextMap.Clear(); + } + + /// + /// Indicates, whether context instances should be automatically registered with the global . + /// + private bool registerContextWithContextRegistry = true; + + /// + /// Logger available to subclasses. + /// + protected readonly ILogger logger; + + /// + /// Default constructor for AbstractSpringContextTests. + /// + protected AbstractSpringContextTests() + { + logger = LogManager.GetLogger(GetType()); + } + + /// + /// Controls, whether application context instances will + /// be registered/unregistered with the global . + /// Defaults to true. + /// + public bool RegisterContextWithContextRegistry + { + get { return registerContextWithContextRegistry; } + set { registerContextWithContextRegistry = value; } + } + + /// + /// Set custom locations dirty. This will cause them to be reloaded + /// from the cache before the next test case is executed. /// /// - ///

Maintains a cache of contexts by key. This has significant performance - /// benefit if initializing the context would take time. While initializing a - /// Spring context itself is very quick, some objects in a context, such as - /// a LocalSessionFactoryObject for working with NHibernate, may take time to - /// initialize. Hence it often makes sense to do that initializing once.

- ///

Normally you won't extend this class directly but rather extend one - /// of its subclasses.

+ /// Call this method only if you change the state of a singleton + /// object, potentially affecting future tests. ///
- /// Rod Johnson - /// Aleksandar Seovic (.NET) - public abstract class AbstractSpringContextTests + /// Locations + protected void SetDirty(string[] locations) { - /// - /// Map of context keys returned by subclasses of this class, to - /// Spring contexts. - /// - private static readonly IDictionary contextKeyToContextMap; + String keyString = ContextKeyString(locations); + IConfigurableApplicationContext ctx = + (IConfigurableApplicationContext) contextKeyToContextMap[keyString]; + contextKeyToContextMap.Remove(keyString); - /// - /// Static ctor to avoid "beforeFieldInit" problem. - /// - static AbstractSpringContextTests() + if (ctx != null) { - contextKeyToContextMap = new Hashtable(); + ctx.Dispose(); + } + } + + /// + /// Returns true if context for the specified + /// is cached. + /// + /// Context key to check. + /// + /// true if context for the specified + /// is cached, + /// false otherwise. + /// + protected bool HasCachedContext(object contextKey) + { + string keyString = ContextKeyString(contextKey); + return contextKeyToContextMap.Contains(keyString); + } + + /// + /// Converts context key to string. + /// + /// + /// Subclasses can override this to return a string representation of + /// their contextKey for use in logging. + /// + /// Context key to convert. + /// + /// String representation of the specified . Null if + /// contextKey is null. + /// + protected virtual string ContextKeyString(object contextKey) + { + if (contextKey == null) + { + return null; } - /// - /// Disposes any cached context instance and removes it from cache. - /// - public static void ClearContextCache() + if (contextKey is string[]) { - foreach(IApplicationContext ctx in contextKeyToContextMap.Values) + return StringUtils.CollectionToCommaDelimitedString((string[]) contextKey); + } + else + { + return contextKey.ToString(); + } + } + + /// + /// Caches application context. + /// + /// Key to use. + /// Context to cache. + public void AddContext(object key, IConfigurableApplicationContext context) + { + AssertUtils.ArgumentNotNull(context, "context", "ApplicationContext must not be null"); + string keyString = ContextKeyString(key); + contextKeyToContextMap.Add(keyString, context); + + if (RegisterContextWithContextRegistry + && !ContextRegistry.IsContextRegistered(context.Name)) + { + ContextRegistry.RegisterContext(context); + } + } + + /// + /// Returns cached context if present, or loads it if not. + /// + /// Context key. + /// Spring application context associated with the specified key. + protected IConfigurableApplicationContext GetContext(object key) + { + string keyString = ContextKeyString(key); + IConfigurableApplicationContext ctx = + (IConfigurableApplicationContext) contextKeyToContextMap[keyString]; + if (ctx == null) + { + if (key is string[]) { - ctx.Dispose(); + ctx = LoadContextLocations((string[]) key); } - contextKeyToContextMap.Clear(); - } - - /// - /// Indicates, whether context instances should be automatically registered with the global . - /// - private bool registerContextWithContextRegistry = true; - - /// - /// Logger available to subclasses. - /// - protected readonly ILogger logger; - - /// - /// Default constructor for AbstractSpringContextTests. - /// - protected AbstractSpringContextTests() - { - logger = LogManager.GetLogger(GetType()); - } - - /// - /// Controls, whether application context instances will - /// be registered/unregistered with the global . - /// Defaults to true. - /// - public bool RegisterContextWithContextRegistry - { - get { return registerContextWithContextRegistry; } - set { registerContextWithContextRegistry = value; } - } - - /// - /// Set custom locations dirty. This will cause them to be reloaded - /// from the cache before the next test case is executed. - /// - /// - /// Call this method only if you change the state of a singleton - /// object, potentially affecting future tests. - /// - /// Locations - protected void SetDirty(string[] locations) - { - String keyString = ContextKeyString(locations); - IConfigurableApplicationContext ctx = - (IConfigurableApplicationContext) contextKeyToContextMap[keyString]; - contextKeyToContextMap.Remove(keyString); - - if (ctx != null) + else { - ctx.Dispose(); - } - } - - /// - /// Returns true if context for the specified - /// is cached. - /// - /// Context key to check. - /// - /// true if context for the specified - /// is cached, - /// false otherwise. - /// - protected bool HasCachedContext(object contextKey) - { - string keyString = ContextKeyString(contextKey); - return contextKeyToContextMap.Contains(keyString); - } - - /// - /// Converts context key to string. - /// - /// - /// Subclasses can override this to return a string representation of - /// their contextKey for use in logging. - /// - /// Context key to convert. - /// - /// String representation of the specified . Null if - /// contextKey is null. - /// - protected virtual string ContextKeyString(object contextKey) - { - if (contextKey == null) - { - return null; + ctx = LoadContext(key); } - if (contextKey is string[]) - { - return StringUtils.CollectionToCommaDelimitedString((string[])contextKey); - } - else - { - return contextKey.ToString(); - } - } - /// - /// Caches application context. - /// - /// Key to use. - /// Context to cache. - public void AddContext(object key, IConfigurableApplicationContext context) + AddContext(key, ctx); + } + + return ctx; + } + + /// + /// Loads application context from the specified resource locations. + /// + /// Resources to load object definitions from. + protected virtual IConfigurableApplicationContext LoadContextLocations(string[] locations) + { + if (logger.IsEnabled(LogLevel.Information)) { - AssertUtils.ArgumentNotNull(context, "context", "ApplicationContext must not be null"); - string keyString = ContextKeyString(key); - contextKeyToContextMap.Add(keyString, context); + logger.LogInformation("Loading config for: " + StringUtils.CollectionToCommaDelimitedString(locations)); + } - if (RegisterContextWithContextRegistry - && !ContextRegistry.IsContextRegistered(context.Name)) - { - ContextRegistry.RegisterContext(context); - } - } - - /// - /// Returns cached context if present, or loads it if not. - /// - /// Context key. - /// Spring application context associated with the specified key. - protected IConfigurableApplicationContext GetContext(object key) - { - string keyString = ContextKeyString(key); - IConfigurableApplicationContext ctx = - (IConfigurableApplicationContext) contextKeyToContextMap[keyString]; - if (ctx == null) - { - if (key is string[]) - { - ctx = LoadContextLocations((string[]) key); - } - else - { - ctx = LoadContext(key); - } - AddContext(key, ctx); - } - return ctx; - } - - - /// - /// Loads application context from the specified resource locations. - /// - /// Resources to load object definitions from. - protected virtual IConfigurableApplicationContext LoadContextLocations(string[] locations) - { - if (logger.IsEnabled(LogLevel.Information)) - { - logger.LogInformation("Loading config for: " + StringUtils.CollectionToCommaDelimitedString(locations)); - } - return new XmlApplicationContext(locations); - } - - /// - /// Loads application context based on user-defined key. - /// - /// - /// Unless overriden by the user, this method will alway throw - /// a . - /// - /// User-defined key. - protected virtual IConfigurableApplicationContext LoadContext(object key) - { - throw new NotSupportedException("Subclasses may override this"); - } + return new XmlApplicationContext(locations); + } + /// + /// Loads application context based on user-defined key. + /// + /// + /// Unless overriden by the user, this method will alway throw + /// a . + /// + /// User-defined key. + protected virtual IConfigurableApplicationContext LoadContext(object key) + { + throw new NotSupportedException("Subclasses may override this"); } } diff --git a/src/Spring/Spring.Testing.Microsoft/Testing/Microsoft/AbstractTransactionalDbProviderSpringContextTests.cs b/src/Spring/Spring.Testing.Microsoft/Testing/Microsoft/AbstractTransactionalDbProviderSpringContextTests.cs index 9394cbde..0095998b 100644 --- a/src/Spring/Spring.Testing.Microsoft/Testing/Microsoft/AbstractTransactionalDbProviderSpringContextTests.cs +++ b/src/Spring/Spring.Testing.Microsoft/Testing/Microsoft/AbstractTransactionalDbProviderSpringContextTests.cs @@ -23,120 +23,119 @@ using Microsoft.Extensions.Logging; using Spring.Data.Common; using Spring.Data.Core; -namespace Spring.Testing.Microsoft +namespace Spring.Testing.Microsoft; + +/// +/// Subclass of AbstractTransactionalSpringContextTests that adds some convenience +/// functionality for ADO.NET access. Expects a IDbProvider object +/// to be defined in the Spring application context. +/// +/// +/// This class exposes a AdoTemplate and provides an easy way to delete from the +/// database in a new transaction. +/// +/// Rod Johnson +/// Juergen Hoeller +/// Mark Pollack (.NET) +public abstract class AbstractTransactionalDbProviderSpringContextTests : AbstractTransactionalSpringContextTests { /// - /// Subclass of AbstractTransactionalSpringContextTests that adds some convenience - /// functionality for ADO.NET access. Expects a IDbProvider object - /// to be defined in the Spring application context. + /// Holds the that this base class manages + /// + private AdoTemplate adoTemplate; + + /// + /// Did this test delete any tables? If so, we forbid transaction completion, + /// and only allow rollback. + /// + private bool zappedTables; + + /// + /// Initializes a new instance of the class. + /// + public AbstractTransactionalDbProviderSpringContextTests() + { + } + + /// + /// Sets the DbProvider, via Dependency Injection. + /// + /// The IDbProvider. + public IDbProvider DbProvider + { + set { adoTemplate = new AdoTemplate(value); } + } + + /// + /// Gets or sets the AdoTemplate that this base class manages. + /// + /// The ADO template. + public AdoTemplate AdoTemplate + { + get { return adoTemplate; } + protected set { adoTemplate = value; } + } + + /// + /// Inject dependencies into 'this' instance (that is, this test instance). /// /// - /// This class exposes a AdoTemplate and provides an easy way to delete from the - /// database in a new transaction. + ///

The default implementation populates protected variables if the + /// property is set, else + /// uses autowiring if autowiring is switched on (which it is by default).

+ ///

You can certainly override this method if you want to totally control + /// how dependencies are injected into 'this' instance.

+ ///

AdoTemplate autowiring is Ignored

///
- /// Rod Johnson - /// Juergen Hoeller - /// Mark Pollack (.NET) - public abstract class AbstractTransactionalDbProviderSpringContextTests : AbstractTransactionalSpringContextTests + protected override void InjectDependencies() { - /// - /// Holds the that this base class manages - /// - private AdoTemplate adoTemplate; - - /// - /// Did this test delete any tables? If so, we forbid transaction completion, - /// and only allow rollback. - /// - private bool zappedTables; - - /// - /// Initializes a new instance of the class. - /// - public AbstractTransactionalDbProviderSpringContextTests() - { - } - - /// - /// Sets the DbProvider, via Dependency Injection. - /// - /// The IDbProvider. - public IDbProvider DbProvider - { - set { adoTemplate = new AdoTemplate(value); } - } - - /// - /// Gets or sets the AdoTemplate that this base class manages. - /// - /// The ADO template. - public AdoTemplate AdoTemplate - { - get { return adoTemplate; } - protected set { adoTemplate = value; } - } - - /// - /// Inject dependencies into 'this' instance (that is, this test instance). - /// - /// - ///

The default implementation populates protected variables if the - /// property is set, else - /// uses autowiring if autowiring is switched on (which it is by default).

- ///

You can certainly override this method if you want to totally control - /// how dependencies are injected into 'this' instance.

- ///

AdoTemplate autowiring is Ignored

- ///
- protected override void InjectDependencies() - { - applicationContext.ObjectFactory.IgnoreDependencyType(typeof(AdoTemplate)); - base.InjectDependencies(); - } - - /// - /// Convenient method to delete all rows from these tables. - /// Calling this method will make avoidance of rollback by calling - /// SetComplete() impossible. - /// - /// - protected void DeleteFromTables(String[] names) - { - for (int i = 0; i < names.Length; i++) - { - int rowCount = this.adoTemplate.ExecuteNonQuery(CommandType.Text, "DELETE FROM " + names[i]); - if (logger.IsEnabled(LogLevel.Information)) - { - logger.LogInformation("Deleted " + rowCount + " rows from table " + names[i]); - } - } - this.zappedTables = true; - } - - /// - /// Overridden to prevent the transaction committing if a number of tables have been - /// cleared, as a defensive measure against accidental permanent wiping of a database. - /// - protected override void SetComplete() - { - if (this.zappedTables) - { - throw new InvalidOperationException("Cannot set complete after deleting tables"); - } - base.SetComplete(); - } - - /// - /// Counts the rows in given table. - /// - /// Name of the table to count rows in. - /// The number of rows in the table - protected int CountRowsInTable(String tableName) - { - return (int) adoTemplate.ExecuteScalar(CommandType.Text, "SELECT COUNT(0) FROM " + tableName); - - } - - //TODO ExecuteScript... - + applicationContext.ObjectFactory.IgnoreDependencyType(typeof(AdoTemplate)); + base.InjectDependencies(); } -} + + /// + /// Convenient method to delete all rows from these tables. + /// Calling this method will make avoidance of rollback by calling + /// SetComplete() impossible. + /// + /// + protected void DeleteFromTables(String[] names) + { + for (int i = 0; i < names.Length; i++) + { + int rowCount = this.adoTemplate.ExecuteNonQuery(CommandType.Text, "DELETE FROM " + names[i]); + if (logger.IsEnabled(LogLevel.Information)) + { + logger.LogInformation("Deleted " + rowCount + " rows from table " + names[i]); + } + } + + this.zappedTables = true; + } + + /// + /// Overridden to prevent the transaction committing if a number of tables have been + /// cleared, as a defensive measure against accidental permanent wiping of a database. + /// + protected override void SetComplete() + { + if (this.zappedTables) + { + throw new InvalidOperationException("Cannot set complete after deleting tables"); + } + + base.SetComplete(); + } + + /// + /// Counts the rows in given table. + /// + /// Name of the table to count rows in. + /// The number of rows in the table + protected int CountRowsInTable(String tableName) + { + return (int) adoTemplate.ExecuteScalar(CommandType.Text, "SELECT COUNT(0) FROM " + tableName); + } + + //TODO ExecuteScript... +} \ No newline at end of file diff --git a/src/Spring/Spring.Testing.Microsoft/Testing/Microsoft/AbstractTransactionalSpringContextTests.cs b/src/Spring/Spring.Testing.Microsoft/Testing/Microsoft/AbstractTransactionalSpringContextTests.cs index 932a558c..53553d93 100644 --- a/src/Spring/Spring.Testing.Microsoft/Testing/Microsoft/AbstractTransactionalSpringContextTests.cs +++ b/src/Spring/Spring.Testing.Microsoft/Testing/Microsoft/AbstractTransactionalSpringContextTests.cs @@ -22,294 +22,293 @@ using Microsoft.Extensions.Logging; using Spring.Transaction; using Spring.Transaction.Support; -namespace Spring.Testing.Microsoft +namespace Spring.Testing.Microsoft; + +/// +/// Convenient superclass for tests that should occur in a transaction, but normally +/// will roll the transaction back on the completion of each test. +/// +/// +///

This is useful in a range of circumstances, allowing the following benefits:

+///
    +///
  • Ability to delete or insert any data in the database, without affecting other tests
  • +///
  • Providing a transactional context for any code requiring a transaction
  • +///
  • Ability to write anything to the database without any need to clean up.
  • +///
+/// +///

This class is typically very fast, compared to traditional setup/teardown scripts.

+/// +///

If data should be left in the database, call the SetComplete() +/// method in each test. The "DefaultRollback" property, which defaults to "true", +/// determines whether transactions will complete by default.

+/// +///

It is even possible to end the transaction early; for example, to verify lazy +/// loading behavior of an O/R mapping tool. (This is a valuable away to avoid +/// unexpected errors when testing a web UI, for example.) Simply call the +/// endTransaction() method. Execution will then occur without a +/// transactional context.

+/// +///

The StartNewTransaction() method may be called after a call to +/// EndTransaction() if you wish to create a new transaction, quite +/// independent of the old transaction. The new transaction's default fate will be to +/// roll back, unless setComplete() is called again during the scope of the +/// new transaction. Any number of transactions may be created and ended in this way. +/// The final transaction will automatically be rolled back when the test case is +/// torn down.

+/// +///

Transactional behavior requires a single object in the context implementing the +/// IPlatformTransactionManager interface. This will be set by the superclass's +/// Dependency Injection mechanism. If using the superclass's Field Injection mechanism, +/// the implementation should be named "transactionManager". This mechanism allows the +/// use of this superclass even when there's more than one transaction manager in the context.

+/// +///

This superclass can also be used without transaction management, if no +/// IPlatformTransactionManager object is found in the context provided. Be careful about +/// using this mode, as it allows the potential to permanently modify data. +/// This mode is available only if dependency checking is turned off in +/// the AbstractDependencyInjectionSpringContextTests superclass. The non-transactional +/// capability is provided to enable use of the same subclass in different environments.

+/// +///
+/// +/// Rod Johnson +/// Juergen Hoeller +/// Rick Evans +/// Mark Pollack (.NET) +public abstract class AbstractTransactionalSpringContextTests : AbstractDependencyInjectionSpringContextTests { /// - /// Convenient superclass for tests that should occur in a transaction, but normally - /// will roll the transaction back on the completion of each test. + /// The transaction manager to use + /// + private IPlatformTransactionManager transactionManager; + + /// + /// Should we roll back by default? + /// + private bool defaultRollback = true; + + /// + /// Should we commit the current transaction? + /// + private bool complete = false; + + /// + /// Number of transactions started + /// + private int transactionsStarted = 0; + + /// + /// Default transaction definition is used. + /// Subclasses can change this to cause different behaviour. + /// + private ITransactionDefinition transactionDefinition = new DefaultTransactionDefinition(); + + /// + /// TransactionStatus for this test. Typical subclasses won't need to use it. + /// + private ITransactionStatus transactionStatus; + + /// + /// Initializes a new instance of the class. + /// + public AbstractTransactionalSpringContextTests() + { + } + + /// + /// Sets the transaction manager to use. + /// + public IPlatformTransactionManager TransactionManager + { + protected get { return transactionManager; } + set { transactionManager = value; } + } + + /// + /// Sets the default rollback flag. + /// + public bool DefaultRollback + { + set { defaultRollback = value; } + } + + /// + /// Set the to be used /// /// - ///

This is useful in a range of circumstances, allowing the following benefits:

- ///
    - ///
  • Ability to delete or insert any data in the database, without affecting other tests
  • - ///
  • Providing a transactional context for any code requiring a transaction
  • - ///
  • Ability to write anything to the database without any need to clean up.
  • - ///
- /// - ///

This class is typically very fast, compared to traditional setup/teardown scripts.

- /// - ///

If data should be left in the database, call the SetComplete() - /// method in each test. The "DefaultRollback" property, which defaults to "true", - /// determines whether transactions will complete by default.

- /// - ///

It is even possible to end the transaction early; for example, to verify lazy - /// loading behavior of an O/R mapping tool. (This is a valuable away to avoid - /// unexpected errors when testing a web UI, for example.) Simply call the - /// endTransaction() method. Execution will then occur without a - /// transactional context.

- /// - ///

The StartNewTransaction() method may be called after a call to - /// EndTransaction() if you wish to create a new transaction, quite - /// independent of the old transaction. The new transaction's default fate will be to - /// roll back, unless setComplete() is called again during the scope of the - /// new transaction. Any number of transactions may be created and ended in this way. - /// The final transaction will automatically be rolled back when the test case is - /// torn down.

- /// - ///

Transactional behavior requires a single object in the context implementing the - /// IPlatformTransactionManager interface. This will be set by the superclass's - /// Dependency Injection mechanism. If using the superclass's Field Injection mechanism, - /// the implementation should be named "transactionManager". This mechanism allows the - /// use of this superclass even when there's more than one transaction manager in the context.

- /// - ///

This superclass can also be used without transaction management, if no - /// IPlatformTransactionManager object is found in the context provided. Be careful about - /// using this mode, as it allows the potential to permanently modify data. - /// This mode is available only if dependency checking is turned off in - /// the AbstractDependencyInjectionSpringContextTests superclass. The non-transactional - /// capability is provided to enable use of the same subclass in different environments.

- /// + /// Defaults to ///
- /// - /// Rod Johnson - /// Juergen Hoeller - /// Rick Evans - /// Mark Pollack (.NET) - public abstract class AbstractTransactionalSpringContextTests : AbstractDependencyInjectionSpringContextTests + protected ITransactionDefinition TransactionDefinition { - /// - /// The transaction manager to use - /// - private IPlatformTransactionManager transactionManager; + set { transactionDefinition = value; } + } - /// - /// Should we roll back by default? - /// - private bool defaultRollback = true; + /// + /// TransactionStatus for this test. Typical subclasses won't need to use it. + /// + protected ITransactionStatus TransactionStatus + { + get { return transactionStatus; } + set { transactionStatus = value; } + } - /// - /// Should we commit the current transaction? - /// - private bool complete = false; + /// + /// Prevents the transaction. + /// + protected virtual void PreventTransaction() + { + this.transactionDefinition = null; + } - /// - /// Number of transactions started - /// - private int transactionsStarted = 0; + /// + /// Creates a transaction + /// + protected override void OnTestInitialize() + { + this.complete = !this.defaultRollback; - /// - /// Default transaction definition is used. - /// Subclasses can change this to cause different behaviour. - /// - private ITransactionDefinition transactionDefinition = new DefaultTransactionDefinition(); - - /// - /// TransactionStatus for this test. Typical subclasses won't need to use it. - /// - private ITransactionStatus transactionStatus; - - - /// - /// Initializes a new instance of the class. - /// - public AbstractTransactionalSpringContextTests() + if (this.transactionManager == null) { + logger.LogInformation("No transaction manager set: test will NOT run within a transaction"); } - - /// - /// Sets the transaction manager to use. - /// - public IPlatformTransactionManager TransactionManager + else if (this.transactionDefinition == null) { - protected get { return transactionManager; } - set { transactionManager = value; } + logger.LogInformation("No transaction definition set: test will NOT run within a transaction"); } - - /// - /// Sets the default rollback flag. - /// - public bool DefaultRollback + else { - set { defaultRollback = value; } - } - - /// - /// Set the to be used - /// - /// - /// Defaults to - /// - protected ITransactionDefinition TransactionDefinition - { - set { transactionDefinition = value; } - } - - /// - /// TransactionStatus for this test. Typical subclasses won't need to use it. - /// - protected ITransactionStatus TransactionStatus - { - get { return transactionStatus; } - set { transactionStatus = value; } - } - - /// - /// Prevents the transaction. - /// - protected virtual void PreventTransaction() - { - this.transactionDefinition = null; - } - - - /// - /// Creates a transaction - /// - protected override void OnTestInitialize() - { - this.complete = !this.defaultRollback; - - if (this.transactionManager == null) + OnSetUpBeforeTransaction(); + StartNewTransaction(); + try { - logger.LogInformation("No transaction manager set: test will NOT run within a transaction"); + OnSetUpInTransaction(); } - else if (this.transactionDefinition == null) + catch (Exception) { - logger.LogInformation("No transaction definition set: test will NOT run within a transaction"); - } - else - { - OnSetUpBeforeTransaction(); - StartNewTransaction(); - try - { - OnSetUpInTransaction(); - } - catch (Exception) - { - EndTransaction(); - throw; - } - } - } - - - /// - /// Callback method called before transaction is setup. - /// - protected virtual void OnSetUpBeforeTransaction() - { - } - - /// - /// Callback method called after transaction is setup. - /// - protected virtual void OnSetUpInTransaction() - { - } - - /// - /// rollback the transaction. - /// - protected override void OnTestCleanup() - { - // Call onTearDownInTransaction and end transaction if the transaction is still active. - if (this.transactionStatus != null && !this.transactionStatus.Completed) - { - try - { - OnTearDownInTransaction(); - } - finally - { - EndTransaction(); - } - } - // Call onTearDownAfterTransaction if there was at least one transaction, - // even if it has been completed early through an endTransaction() call. - if (this.transactionsStarted > 0) - { - OnTearDownAfterTransaction(); - } - } - - /// - /// Callback before rolling back the transaction. - /// - protected virtual void OnTearDownInTransaction() - { - } - - /// - /// Callback after rolling back the transaction. - /// - protected virtual void OnTearDownAfterTransaction() - { - } - - /// - /// Set the complete flag.. - /// - protected virtual void SetComplete() - { - if (this.transactionManager == null) - { - throw new InvalidOperationException("No transaction manager set"); - } - this.complete = true; - } - - /// - /// Ends the transaction. - /// - protected virtual void EndTransaction() - { - if (this.transactionStatus != null) - { - try - { - if (!this.complete) - { - this.transactionManager.Rollback(this.transactionStatus); - logger.LogInformation("Rolled back transaction after test execution"); - } - else - { - this.transactionManager.Commit(this.transactionStatus); - logger.LogInformation("Committed transaction after test execution"); - } - } - finally - { - this.transactionStatus = null; - } - } - } - - /// - /// Starts the new transaction. - /// - protected void StartNewTransaction() - { - if (this.transactionStatus != null) - { - throw new InvalidOperationException("Cannot start new transaction without ending existing transaction: " + - "Invoke endTransaction() before startNewTransaction()"); - } - if (this.transactionManager == null) - { - throw new InvalidOperationException("No transaction manager set"); - } - - this.transactionStatus = this.transactionManager.GetTransaction(this.transactionDefinition); - ++this.transactionsStarted; - this.complete = !this.defaultRollback; - - if (logger.IsEnabled(LogLevel.Information)) - { - logger.LogInformation("Began transaction (" + this.transactionsStarted + "): transaction manager [" + - this.transactionManager + "]; default rollback = " + this.defaultRollback); + EndTransaction(); + throw; } } } + + /// + /// Callback method called before transaction is setup. + /// + protected virtual void OnSetUpBeforeTransaction() + { + } + + /// + /// Callback method called after transaction is setup. + /// + protected virtual void OnSetUpInTransaction() + { + } + + /// + /// rollback the transaction. + /// + protected override void OnTestCleanup() + { + // Call onTearDownInTransaction and end transaction if the transaction is still active. + if (this.transactionStatus != null && !this.transactionStatus.Completed) + { + try + { + OnTearDownInTransaction(); + } + finally + { + EndTransaction(); + } + } + + // Call onTearDownAfterTransaction if there was at least one transaction, + // even if it has been completed early through an endTransaction() call. + if (this.transactionsStarted > 0) + { + OnTearDownAfterTransaction(); + } + } + + /// + /// Callback before rolling back the transaction. + /// + protected virtual void OnTearDownInTransaction() + { + } + + /// + /// Callback after rolling back the transaction. + /// + protected virtual void OnTearDownAfterTransaction() + { + } + + /// + /// Set the complete flag.. + /// + protected virtual void SetComplete() + { + if (this.transactionManager == null) + { + throw new InvalidOperationException("No transaction manager set"); + } + + this.complete = true; + } + + /// + /// Ends the transaction. + /// + protected virtual void EndTransaction() + { + if (this.transactionStatus != null) + { + try + { + if (!this.complete) + { + this.transactionManager.Rollback(this.transactionStatus); + logger.LogInformation("Rolled back transaction after test execution"); + } + else + { + this.transactionManager.Commit(this.transactionStatus); + logger.LogInformation("Committed transaction after test execution"); + } + } + finally + { + this.transactionStatus = null; + } + } + } + + /// + /// Starts the new transaction. + /// + protected void StartNewTransaction() + { + if (this.transactionStatus != null) + { + throw new InvalidOperationException("Cannot start new transaction without ending existing transaction: " + + "Invoke endTransaction() before startNewTransaction()"); + } + + if (this.transactionManager == null) + { + throw new InvalidOperationException("No transaction manager set"); + } + + this.transactionStatus = this.transactionManager.GetTransaction(this.transactionDefinition); + ++this.transactionsStarted; + this.complete = !this.defaultRollback; + + if (logger.IsEnabled(LogLevel.Information)) + { + logger.LogInformation("Began transaction (" + this.transactionsStarted + "): transaction manager [" + + this.transactionManager + "]; default rollback = " + this.defaultRollback); + } + } } diff --git a/src/Spring/Spring.Testing.NUnit/AssemblyInfo.cs b/src/Spring/Spring.Testing.NUnit/AssemblyInfo.cs index 01dade9d..b3a8cdec 100644 --- a/src/Spring/Spring.Testing.NUnit/AssemblyInfo.cs +++ b/src/Spring/Spring.Testing.NUnit/AssemblyInfo.cs @@ -1,4 +1,4 @@ using System.Reflection; [assembly: AssemblyTitle("Spring.Testing.NUnit")] -[assembly: AssemblyDescription("Interfaces and classes that provide NUnit integration in Spring.Net")] \ No newline at end of file +[assembly: AssemblyDescription("Interfaces and classes that provide NUnit integration in Spring.Net")] diff --git a/src/Spring/Spring.Testing.NUnit/Testing/Ado/IPlatformTransaction.cs b/src/Spring/Spring.Testing.NUnit/Testing/Ado/IPlatformTransaction.cs index 07e207a1..12770089 100644 --- a/src/Spring/Spring.Testing.NUnit/Testing/Ado/IPlatformTransaction.cs +++ b/src/Spring/Spring.Testing.NUnit/Testing/Ado/IPlatformTransaction.cs @@ -1,25 +1,25 @@ -namespace Spring.Testing.Ado +namespace Spring.Testing.Ado; + +/// +/// Holds status for an active transaction. You *must* dispose this object! +/// +/// +/// +/// Usage Pattern: +/// +/// TBD +/// +/// +/// +public interface IPlatformTransaction : IDisposable { /// - /// Holds status for an active transaction. You *must* dispose this object! + /// Mark transaction for commit on disposal /// - /// - /// - /// Usage Pattern: - /// - /// TBD - /// - /// - /// - public interface IPlatformTransaction : IDisposable - { - /// - /// Mark transaction for commit on disposal - /// - void Commit(); - /// - /// Throw exception and rollback any uncommitted commands - /// - void Rollback(); - } + void Commit(); + + /// + /// Throw exception and rollback any uncommitted commands + /// + void Rollback(); } diff --git a/src/Spring/Spring.Testing.NUnit/Testing/Ado/SimpleAdoTestUtils.cs b/src/Spring/Spring.Testing.NUnit/Testing/Ado/SimpleAdoTestUtils.cs index d756da8b..462420ac 100644 --- a/src/Spring/Spring.Testing.NUnit/Testing/Ado/SimpleAdoTestUtils.cs +++ b/src/Spring/Spring.Testing.NUnit/Testing/Ado/SimpleAdoTestUtils.cs @@ -30,306 +30,312 @@ using Spring.Data.Core; using Spring.Transaction; using Spring.Util; -namespace Spring.Testing.Ado +namespace Spring.Testing.Ado; + +/// +/// TBD +/// +/// Erich Eichinger +public class SimpleAdoTestUtils { + private static readonly ILogger Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private static readonly RegexOptions REGEX_OPTIONS = RegexOptions.Multiline | RegexOptions.ECMAScript | RegexOptions.Compiled | RegexOptions.CultureInvariant | RegexOptions.IgnoreCase; + /// /// TBD /// - /// Erich Eichinger - public class SimpleAdoTestUtils + public static readonly string BLOCKDELIM_GO = @"^[\s\n\r]*GO[\s\n\r]*$"; + + /// + /// TBD + /// + public static readonly Regex BLOCKDELIM_GO_EXP = new Regex(BLOCKDELIM_GO, REGEX_OPTIONS); + + /// + /// TBD + /// + public static readonly string BLOCKDELIM_SEMICOLON = @";"; + + /// + /// TBD + /// + public static readonly Regex BLOCKDELIM_SEMICOLON_EXP = new Regex(BLOCKDELIM_SEMICOLON, REGEX_OPTIONS); + + /// + /// TBD + /// + public static readonly string BLOCKDELIM_NEWLINE = @"\n"; + + /// + /// TBD + /// + public static readonly Regex BLOCKDELIM_NEWLINE_EXP = new Regex(BLOCKDELIM_NEWLINE, REGEX_OPTIONS); + + /// + /// TBD + /// + public static Regex BLOCKDELIM_DEFAULT_EXP = BLOCKDELIM_GO_EXP; + + /// + /// TBD + /// + public static Regex[] BLOCKDELIM_ALL_EXP = { BLOCKDELIM_GO_EXP, BLOCKDELIM_SEMICOLON_EXP, BLOCKDELIM_NEWLINE_EXP }; + + static SimpleAdoTestUtils() { - private static readonly ILogger Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - private static readonly RegexOptions REGEX_OPTIONS = RegexOptions.Multiline | RegexOptions.ECMAScript | RegexOptions.Compiled | RegexOptions.CultureInvariant | RegexOptions.IgnoreCase; + } - /// - /// TBD - /// - public static readonly string BLOCKDELIM_GO = @"^[\s\n\r]*GO[\s\n\r]*$"; - /// - /// TBD - /// - public static readonly Regex BLOCKDELIM_GO_EXP = new Regex(BLOCKDELIM_GO, REGEX_OPTIONS); - /// - /// TBD - /// - public static readonly string BLOCKDELIM_SEMICOLON = @";"; - /// - /// TBD - /// - public static readonly Regex BLOCKDELIM_SEMICOLON_EXP = new Regex(BLOCKDELIM_SEMICOLON, REGEX_OPTIONS); - /// - /// TBD - /// - public static readonly string BLOCKDELIM_NEWLINE = @"\n"; - /// - /// TBD - /// - public static readonly Regex BLOCKDELIM_NEWLINE_EXP = new Regex(BLOCKDELIM_NEWLINE, REGEX_OPTIONS); + /// + /// TBD + /// + public static IPlatformTransaction CreateTransaction(IDbProvider dbProvider, ITransactionDefinition txDefinition) + { + AdoPlatformTransactionManager txMgr = new AdoPlatformTransactionManager(dbProvider); + ITransactionStatus txStatus = txMgr.GetTransaction(txDefinition); + return new PlatformTransactionHolder(txStatus, txMgr); + } - /// - /// TBD - /// - public static Regex BLOCKDELIM_DEFAULT_EXP = BLOCKDELIM_GO_EXP; + /// + /// Execute the given script + /// + public static void ExecuteSqlScript(IAdoOperations adoTemplate, string script, params Regex[] blockDelimiter) + { + ExecuteSqlScriptInternal(adoTemplate, new EncodedResource(new StringResource(script)), false, blockDelimiter); + } - /// - /// TBD - /// - public static Regex[] BLOCKDELIM_ALL_EXP = { BLOCKDELIM_GO_EXP, BLOCKDELIM_SEMICOLON_EXP, BLOCKDELIM_NEWLINE_EXP }; + /// + /// Execute the given script + /// + public static void ExecuteSqlScript(IAdoOperations adoTemplate, string script, bool continueOnError, params Regex[] blockDelimiter) + { + ExecuteSqlScriptInternal(adoTemplate, new EncodedResource(new StringResource(script)), continueOnError, blockDelimiter); + } - static SimpleAdoTestUtils() - { } + /// + /// Execute the given script + /// + public static void ExecuteSqlScript(IAdoOperations adoTemplate, IResourceLoader resourceLoader, string scriptResourcePath, bool continueOnError, params Regex[] blockDelimiter) + { + ExecuteSqlScriptInternal(adoTemplate, new EncodedResource(resourceLoader.GetResource(scriptResourcePath)), continueOnError, blockDelimiter); + } - /// - /// TBD - /// - public static IPlatformTransaction CreateTransaction(IDbProvider dbProvider, ITransactionDefinition txDefinition) + /// + /// Execute the given script + /// + public static void ExecuteSqlScript(IAdoOperations adoTemplate, IResource resource, params Regex[] blockDelimiter) + { + ExecuteSqlScriptInternal(adoTemplate, new EncodedResource(resource), false, blockDelimiter); + } + + /// + /// Execute the given script + /// + public static void ExecuteSqlScript(IAdoOperations adoTemplate, IResource resource, bool continueOnError, params Regex[] blockDelimiter) + { + ExecuteSqlScriptInternal(adoTemplate, new EncodedResource(resource), continueOnError, blockDelimiter); + } + + /// + /// Execute the given script + /// + public static void ExecuteSqlScript(IAdoOperations adoTemplate, EncodedResource resource, bool continueOnError, params Regex[] blockDelimiter) + { + ExecuteSqlScriptInternal(adoTemplate, resource, continueOnError, blockDelimiter); + } + + /// + /// Execute the given script + /// + private static void ExecuteSqlScriptInternal(IAdoOperations adoTemplate, EncodedResource resource, bool continueOnError, params Regex[] blockDelimiter) + { + AssertUtils.ArgumentNotNull(adoTemplate, "adoTemplate"); + AssertUtils.ArgumentNotNull(resource, "resource"); + + if (!CollectionUtils.HasElements(blockDelimiter)) { - AdoPlatformTransactionManager txMgr = new AdoPlatformTransactionManager(dbProvider); - ITransactionStatus txStatus = txMgr.GetTransaction(txDefinition); - return new PlatformTransactionHolder(txStatus, txMgr); + blockDelimiter = BLOCKDELIM_ALL_EXP; } - /// - /// Execute the given script - /// - public static void ExecuteSqlScript(IAdoOperations adoTemplate, string script, params Regex[] blockDelimiter) + List statements = new List(); + try { - ExecuteSqlScriptInternal(adoTemplate, new EncodedResource(new StringResource(script)), false, blockDelimiter); + GetScriptBlocks(resource, statements, blockDelimiter); + } + catch (Exception ex) + { + throw new DataAccessResourceFailureException("Failed to open SQL script from " + resource, ex); } - /// - /// Execute the given script - /// - public static void ExecuteSqlScript(IAdoOperations adoTemplate, string script, bool continueOnError, params Regex[] blockDelimiter) + foreach (string statement in statements) { - ExecuteSqlScriptInternal(adoTemplate, new EncodedResource(new StringResource(script)), continueOnError, blockDelimiter); - } - - /// - /// Execute the given script - /// - public static void ExecuteSqlScript(IAdoOperations adoTemplate, IResourceLoader resourceLoader, string scriptResourcePath, bool continueOnError, params Regex[] blockDelimiter) - { - ExecuteSqlScriptInternal(adoTemplate, new EncodedResource(resourceLoader.GetResource(scriptResourcePath)), continueOnError, blockDelimiter); - } - - /// - /// Execute the given script - /// - public static void ExecuteSqlScript(IAdoOperations adoTemplate, IResource resource, params Regex[] blockDelimiter) - { - ExecuteSqlScriptInternal(adoTemplate, new EncodedResource(resource), false, blockDelimiter); - } - - /// - /// Execute the given script - /// - public static void ExecuteSqlScript(IAdoOperations adoTemplate, IResource resource, bool continueOnError, params Regex[] blockDelimiter) - { - ExecuteSqlScriptInternal(adoTemplate, new EncodedResource(resource), continueOnError, blockDelimiter); - } - - /// - /// Execute the given script - /// - public static void ExecuteSqlScript(IAdoOperations adoTemplate, EncodedResource resource, bool continueOnError, params Regex[] blockDelimiter) - { - ExecuteSqlScriptInternal(adoTemplate, resource, continueOnError, blockDelimiter); - } - - /// - /// Execute the given script - /// - private static void ExecuteSqlScriptInternal(IAdoOperations adoTemplate, EncodedResource resource, bool continueOnError, params Regex[] blockDelimiter) - { - AssertUtils.ArgumentNotNull(adoTemplate, "adoTemplate"); - AssertUtils.ArgumentNotNull(resource, "resource"); - - if (!CollectionUtils.HasElements(blockDelimiter)) - { - blockDelimiter = BLOCKDELIM_ALL_EXP; - } - - List statements = new List(); try { - GetScriptBlocks(resource, statements, blockDelimiter); + adoTemplate.ExecuteNonQuery(CommandType.Text, statement); } - catch (Exception ex) + catch (DataAccessException dae) { - throw new DataAccessResourceFailureException("Failed to open SQL script from " + resource, ex); - } - - foreach (string statement in statements) - { - try + if (!continueOnError) { - adoTemplate.ExecuteNonQuery(CommandType.Text, statement); + throw; } - catch (DataAccessException dae) - { - if (!continueOnError) - { - throw; - } - string message = string.Format("SQL statement failed:{0}", statement); - Log.LogWarning(dae, message); - } + string message = string.Format("SQL statement failed:{0}", statement); + Log.LogWarning(dae, message); } } + } - /// - /// TBD - /// - public static void GetScriptBlocks(EncodedResource encodedResource, IList blockCollector, params Regex[] blockDelimiterPatterns) + /// + /// TBD + /// + public static void GetScriptBlocks(EncodedResource encodedResource, IList blockCollector, params Regex[] blockDelimiterPatterns) + { + AssertUtils.ArgumentNotNull(blockCollector, "blockCollector"); + + using (TextReader sr = encodedResource.OpenReader()) { - AssertUtils.ArgumentNotNull(blockCollector, "blockCollector"); + string script = sr.ReadToEnd(); - using (TextReader sr = encodedResource.OpenReader()) + // the first pattern that finds a match will be used, if any + Regex patternToUse = BLOCKDELIM_DEFAULT_EXP; + if (blockDelimiterPatterns != null) { - string script = sr.ReadToEnd(); - - // the first pattern that finds a match will be used, if any - Regex patternToUse = BLOCKDELIM_DEFAULT_EXP; - if (blockDelimiterPatterns != null) + foreach (Regex pattern in blockDelimiterPatterns) { - foreach (Regex pattern in blockDelimiterPatterns) + if (pattern.IsMatch(script)) { - if (pattern.IsMatch(script)) - { - patternToUse = pattern; - break; - } + patternToUse = pattern; + break; } } - - Split(script, patternToUse, blockCollector); } + + Split(script, patternToUse, blockCollector); } + } - private static void Split(string text, Regex exp, IList blockCollector) + private static void Split(string text, Regex exp, IList blockCollector) + { + // string[] blocks = exp.Split(text); + // foreach(string block in blocks) + // { + // if (StringUtils.HasText(block)) + // { + // blockCollector.Add(block); + // } + // } + MatchCollection matches = exp.Matches(text); + int curIndexStart = 0; + string tmp; + for (int i = 0; i < matches.Count; i++) { - // string[] blocks = exp.Split(text); - // foreach(string block in blocks) - // { - // if (StringUtils.HasText(block)) - // { - // blockCollector.Add(block); - // } - // } - MatchCollection matches = exp.Matches(text); - int curIndexStart = 0; - string tmp; - for (int i = 0; i < matches.Count; i++) - { - Match match = matches[i]; - Group group = match.Groups[0]; - // Capture cap = group.Captures[0]; - tmp = text.Substring(curIndexStart, match.Index - curIndexStart); - if (tmp.Trim().Length > 0) - blockCollector.Add(tmp); - curIndexStart = match.Index + match.Length; - } - - tmp = text.Substring(curIndexStart); + Match match = matches[i]; + Group group = match.Groups[0]; + // Capture cap = group.Captures[0]; + tmp = text.Substring(curIndexStart, match.Index - curIndexStart); if (tmp.Trim().Length > 0) blockCollector.Add(tmp); + curIndexStart = match.Index + match.Length; } - #region To be probably added in a future version + tmp = text.Substring(curIndexStart); + if (tmp.Trim().Length > 0) + blockCollector.Add(tmp); + } - // public static void ExecuteSqlScript( AdoTemplate adoTemplate, IResource scriptResource, string blockDelimiter, bool continueOnError ) - // { - // ExecuteSqlScript( adoTemplate, new EncodedResource(scriptResource), new Regex( Regex.Escape(blockDelimiter), REGEX_OPTIONS ), continueOnError ); - // } - // - // public static void ExecuteSqlScript( AdoTemplate adoTemplate, EncodedResource resource, string blockDelimiter, bool continueOnError ) - // { - // ExecuteSqlScript( adoTemplate, resource, new Regex( Regex.Escape(blockDelimiter), REGEX_OPTIONS ), continueOnError ); - // } + #region To be probably added in a future version - // /// - // /// Execute the given script - // /// - // public static void ExecuteSqlScript(AdoTemplate adoTemplate, string script, params string[] blockDelimiter) - // { - // Regex[] exps = CreateRegexpsFromStrings(blockDelimiter); - // ExecuteSqlScriptInternal(adoTemplate, new EncodedResource(new StringResource(script)), false, exps); - // } + // public static void ExecuteSqlScript( AdoTemplate adoTemplate, IResource scriptResource, string blockDelimiter, bool continueOnError ) + // { + // ExecuteSqlScript( adoTemplate, new EncodedResource(scriptResource), new Regex( Regex.Escape(blockDelimiter), REGEX_OPTIONS ), continueOnError ); + // } + // + // public static void ExecuteSqlScript( AdoTemplate adoTemplate, EncodedResource resource, string blockDelimiter, bool continueOnError ) + // { + // ExecuteSqlScript( adoTemplate, resource, new Regex( Regex.Escape(blockDelimiter), REGEX_OPTIONS ), continueOnError ); + // } - // /// - // /// Creates an array of from the given - // /// - // private static Regex[] CreateRegexpsFromStrings(string[] blockDelimiter) - // { - // Regex[] exps = null; - // if (!CollectionUtils.IsEmpty(blockDelimiter)) - // { - // ArrayList expsList = new ArrayList(); - // foreach (string delim in blockDelimiter) - // { - // expsList.Add(new Regex(Regex.Escape(delim), REGEX_OPTIONS)); - // } - // exps = (Regex[])expsList.ToArray(typeof(Regex)); - // } - // return exps; - // } - // + // /// + // /// Execute the given script + // /// + // public static void ExecuteSqlScript(AdoTemplate adoTemplate, string script, params string[] blockDelimiter) + // { + // Regex[] exps = CreateRegexpsFromStrings(blockDelimiter); + // ExecuteSqlScriptInternal(adoTemplate, new EncodedResource(new StringResource(script)), false, exps); + // } - #endregion + // /// + // /// Creates an array of from the given + // /// + // private static Regex[] CreateRegexpsFromStrings(string[] blockDelimiter) + // { + // Regex[] exps = null; + // if (!CollectionUtils.IsEmpty(blockDelimiter)) + // { + // ArrayList expsList = new ArrayList(); + // foreach (string delim in blockDelimiter) + // { + // expsList.Add(new Regex(Regex.Escape(delim), REGEX_OPTIONS)); + // } + // exps = (Regex[])expsList.ToArray(typeof(Regex)); + // } + // return exps; + // } + // - private class PlatformTransactionHolder : IPlatformTransaction + #endregion + + private class PlatformTransactionHolder : IPlatformTransaction + { + private ITransactionStatus txStatus; + private IPlatformTransactionManager txMgr; + private bool commit; + + public PlatformTransactionHolder(ITransactionStatus txStatus, IPlatformTransactionManager txMgr) { - private ITransactionStatus txStatus; - private IPlatformTransactionManager txMgr; - private bool commit; + AssertUtils.ArgumentNotNull(txStatus, "txStatus"); + AssertUtils.ArgumentNotNull(txMgr, "txMgr"); + this.txStatus = txStatus; + this.txMgr = txMgr; + this.commit = false; + } - public PlatformTransactionHolder(ITransactionStatus txStatus, IPlatformTransactionManager txMgr) + public void Dispose() + { + try { - AssertUtils.ArgumentNotNull(txStatus, "txStatus"); - AssertUtils.ArgumentNotNull(txMgr, "txMgr"); - this.txStatus = txStatus; - this.txMgr = txMgr; - this.commit = false; + if (txStatus == null) + return; + + if (commit) + { + txMgr.Commit(txStatus); + return; + } + + txMgr.Rollback(txStatus); } - - public void Dispose() + finally { - try - { - if (txStatus == null) - return; - - if (commit) - { - txMgr.Commit(txStatus); - return; - } - txMgr.Rollback(txStatus); - } - finally - { - txMgr = null; - txStatus = null; - } + txMgr = null; + txStatus = null; } + } - public void Commit() + public void Commit() + { + commit = true; + } + + public void Rollback() + { + try { - commit = true; + txMgr.Rollback(txStatus); } - - public void Rollback() + finally { - try - { - txMgr.Rollback(txStatus); - } - finally - { - txStatus = null; - } + txStatus = null; } } } diff --git a/src/Spring/Spring.Testing.NUnit/Testing/NUnit/AbstractDependencyInjectionSpringContextTests.cs b/src/Spring/Spring.Testing.NUnit/Testing/NUnit/AbstractDependencyInjectionSpringContextTests.cs index 34222ddb..ee4c2b5c 100644 --- a/src/Spring/Spring.Testing.NUnit/Testing/NUnit/AbstractDependencyInjectionSpringContextTests.cs +++ b/src/Spring/Spring.Testing.NUnit/Testing/NUnit/AbstractDependencyInjectionSpringContextTests.cs @@ -21,349 +21,352 @@ using System.Reflection; using Microsoft.Extensions.Logging; using NUnit.Framework; - using Spring.Context; using Spring.Objects.Factory; using Spring.Objects.Factory.Config; using Spring.Objects.Factory.Support; -namespace Spring.Testing.NUnit +namespace Spring.Testing.NUnit; + +/// +/// Convenient superclass for tests depending on a Spring context. +/// The test instance itself is populated by Dependency Injection. +/// +/// +/// +///

Really for integration testing, not unit testing. +/// You should not normally use the Spring container +/// for unit tests: simply populate your objects in plain NUnit tests!

+/// +///

This supports two modes of populating the test: +///

    +///
  • Via Property Dependency Injection. Simply express dependencies on objects +/// in the test fixture, and they will be satisfied by autowiring by type.
  • +///
  • Via Field Injection. Declare protected variables of the required type +/// which match named beans in the context. This is autowire by name, +/// rather than type. This approach is based on an approach originated by +/// Ara Abrahmian. Property Dependency Injection is the default: set the +/// "populateProtectedVariables" property to true in the constructor to switch +/// on Field Injection.
  • +///

+/// +///

This class will normally cache contexts based on a context key: +/// normally the config locations String array describing the Spring resource +/// descriptors making up the context. Unless the SetDirty() method +/// is called by a test, the context will not be reloaded, even across different +/// subclasses of this test. This is particularly beneficial if your context is +/// slow to construct, for example if you are using Hibernate and the time taken +/// to load the mappings is an issue.

+/// +///

If you don't want this behavior, you can override the ContextKey +/// property, most likely to return the test class. In conjunction with this you would +/// probably override the GetContext method, which by default loads +/// the locations specified by the ConfigLocations property.

+/// +///

WARNING: When doing integration tests from within VS.NET, only use +/// assembly resource URLs. Else, you may see misleading failures when changing +/// context locations.

+///
+/// +/// Rod Johnson +/// Rob Harrop +/// Rick Evans +/// Aleksandar Seovic (.NET) +public abstract class AbstractDependencyInjectionSpringContextTests : AbstractSpringContextTests { + private bool populateProtectedVariables = false; + private AutoWiringMode autowireMode = AutoWiringMode.ByType; + private bool dependencyCheck = true; + /// - /// Convenient superclass for tests depending on a Spring context. - /// The test instance itself is populated by Dependency Injection. + /// Application context this test will run against. /// - /// - /// - ///

Really for integration testing, not unit testing. - /// You should not normally use the Spring container - /// for unit tests: simply populate your objects in plain NUnit tests!

- /// - ///

This supports two modes of populating the test: - ///

    - ///
  • Via Property Dependency Injection. Simply express dependencies on objects - /// in the test fixture, and they will be satisfied by autowiring by type.
  • - ///
  • Via Field Injection. Declare protected variables of the required type - /// which match named beans in the context. This is autowire by name, - /// rather than type. This approach is based on an approach originated by - /// Ara Abrahmian. Property Dependency Injection is the default: set the - /// "populateProtectedVariables" property to true in the constructor to switch - /// on Field Injection.
  • - ///

- /// - ///

This class will normally cache contexts based on a context key: - /// normally the config locations String array describing the Spring resource - /// descriptors making up the context. Unless the SetDirty() method - /// is called by a test, the context will not be reloaded, even across different - /// subclasses of this test. This is particularly beneficial if your context is - /// slow to construct, for example if you are using Hibernate and the time taken - /// to load the mappings is an issue.

- /// - ///

If you don't want this behavior, you can override the ContextKey - /// property, most likely to return the test class. In conjunction with this you would - /// probably override the GetContext method, which by default loads - /// the locations specified by the ConfigLocations property.

- /// - ///

WARNING: When doing integration tests from within VS.NET, only use - /// assembly resource URLs. Else, you may see misleading failures when changing - /// context locations.

- ///
- /// - /// Rod Johnson - /// Rob Harrop - /// Rick Evans - /// Aleksandar Seovic (.NET) - public abstract class AbstractDependencyInjectionSpringContextTests : AbstractSpringContextTests + protected IConfigurableApplicationContext applicationContext; + + /// + /// Holds names of the fields that should be used for field injection. + /// + protected IList managedVariableNames; + + private int loadCount = 0; + + /// + /// Default constructor for AbstractDependencyInjectionSpringContextTests. + /// + public AbstractDependencyInjectionSpringContextTests() { - private bool populateProtectedVariables = false; - private AutoWiringMode autowireMode = AutoWiringMode.ByType; - private bool dependencyCheck = true; + } - /// - /// Application context this test will run against. - /// - protected IConfigurableApplicationContext applicationContext; + /// + /// Gets or sets a flag specifying whether to populate protected + /// variables of this test case. + /// + /// + /// A flag specifying whether to populate protected variables of this test case. + /// Default is false. + /// + public bool PopulateProtectedVariables + { + get { return populateProtectedVariables; } + set { populateProtectedVariables = value; } + } - /// - /// Holds names of the fields that should be used for field injection. - /// - protected IList managedVariableNames; - private int loadCount = 0; + /// + /// Gets or sets the autowire mode for test properties set by Dependency Injection. + /// + /// + /// The autowire mode for test properties set by Dependency Injection. + /// The default is . + /// + public AutoWiringMode AutowireMode + { + get { return autowireMode; } + set { autowireMode = value; } + } - /// - /// Default constructor for AbstractDependencyInjectionSpringContextTests. - /// - public AbstractDependencyInjectionSpringContextTests() - {} + /// + /// Gets or sets a flag specifying whether or not dependency checking + /// should be performed for test properties set by Dependency Injection. + /// + /// + ///

A flag specifying whether or not dependency checking + /// should be performed for test properties set by Dependency Injection.

+ ///

The default is true, meaning that tests cannot be run + /// unless all properties are populated.

+ ///
+ public bool DependencyCheck + { + get { return dependencyCheck; } + set { dependencyCheck = value; } + } - /// - /// Gets or sets a flag specifying whether to populate protected - /// variables of this test case. - /// - /// - /// A flag specifying whether to populate protected variables of this test case. - /// Default is false. - /// - public bool PopulateProtectedVariables + /// + /// Gets the current number of context load attempts. + /// + public int LoadCount + { + get { return loadCount; } + } + + /// + /// Called to say that the "applicationContext" instance variable is dirty and + /// should be reloaded. We need to do this if a test has modified the context + /// (for example, by replacing an object definition). + /// + public void SetDirty() + { + SetDirty(ConfigLocations); + } + + /// + /// Test setup method. + /// + [SetUp] + public virtual void SetUp() + { + this.applicationContext = GetContext(ContextKey); + InjectDependencies(); + try { - get { return populateProtectedVariables; } - set { populateProtectedVariables = value; } + OnSetUp(); } - - /// - /// Gets or sets the autowire mode for test properties set by Dependency Injection. - /// - /// - /// The autowire mode for test properties set by Dependency Injection. - /// The default is . - /// - public AutoWiringMode AutowireMode + catch (Exception ex) { - get { return autowireMode; } - set { autowireMode = value; } + logger.LogError(ex, "Setup error"); + throw; } + } - /// - /// Gets or sets a flag specifying whether or not dependency checking - /// should be performed for test properties set by Dependency Injection. - /// - /// - ///

A flag specifying whether or not dependency checking - /// should be performed for test properties set by Dependency Injection.

- ///

The default is true, meaning that tests cannot be run - /// unless all properties are populated.

- ///
- public bool DependencyCheck + /// + /// Inject dependencies into 'this' instance (that is, this test instance). + /// + /// + ///

The default implementation populates protected variables if the + /// property is set, else + /// uses autowiring if autowiring is switched on (which it is by default).

+ ///

You can certainly override this method if you want to totally control + /// how dependencies are injected into 'this' instance.

+ ///
+ protected virtual void InjectDependencies() + { + if (PopulateProtectedVariables) { - get { return dependencyCheck; } - set { dependencyCheck = value; } - } - - /// - /// Gets the current number of context load attempts. - /// - public int LoadCount - { - get { return loadCount; } - } - - /// - /// Called to say that the "applicationContext" instance variable is dirty and - /// should be reloaded. We need to do this if a test has modified the context - /// (for example, by replacing an object definition). - /// - public void SetDirty() - { - SetDirty(ConfigLocations); - } - - /// - /// Test setup method. - /// - [SetUp] - public virtual void SetUp() - { - this.applicationContext = GetContext(ContextKey); - InjectDependencies(); - try + if (this.managedVariableNames == null) { - OnSetUp(); + InitManagedVariableNames(); } - catch (Exception ex) + + InjectProtectedVariables(); + } + else if (AutowireMode != AutoWiringMode.No) + { + IConfigurableListableObjectFactory factory = this.applicationContext.ObjectFactory; + ((AbstractObjectFactory) factory).IgnoreDependencyType(typeof(AutoWiringMode)); + factory.AutowireObjectProperties(this, AutowireMode, DependencyCheck); + } + } + + /// + /// Gets a key for this context. Usually based on config locations, but + /// a subclass overriding buildContext() might want to return its class. + /// + protected virtual object ContextKey + { + get { return ConfigLocations; } + } + + /// + /// Loads application context from the specified resource locations. + /// + /// Resources to load object definitions from. + protected override IConfigurableApplicationContext LoadContextLocations(string[] locations) + { + ++this.loadCount; + return base.LoadContextLocations(locations); + } + + /// + /// Retrieves the names of the fields that should be used for field injection. + /// + protected virtual void InitManagedVariableNames() + { + List managedVarNames = new List(); + Type type = GetType(); + + do + { + FieldInfo[] fields = + type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Instance); + if (logger.IsEnabled(LogLevel.Debug)) { - logger.LogError(ex, "Setup error"); - throw; + logger.LogDebug("Found " + fields.Length + " fields on " + type); } - } - /// - /// Inject dependencies into 'this' instance (that is, this test instance). - /// - /// - ///

The default implementation populates protected variables if the - /// property is set, else - /// uses autowiring if autowiring is switched on (which it is by default).

- ///

You can certainly override this method if you want to totally control - /// how dependencies are injected into 'this' instance.

- ///
- protected virtual void InjectDependencies() - { - if (PopulateProtectedVariables) + for (int i = 0; i < fields.Length; i++) { - if (this.managedVariableNames == null) - { - InitManagedVariableNames(); - } - InjectProtectedVariables(); - } - else if (AutowireMode != AutoWiringMode.No) - { - IConfigurableListableObjectFactory factory = this.applicationContext.ObjectFactory; - ((AbstractObjectFactory) factory).IgnoreDependencyType(typeof(AutoWiringMode)); - factory.AutowireObjectProperties(this, AutowireMode, DependencyCheck); - } - } - - /// - /// Gets a key for this context. Usually based on config locations, but - /// a subclass overriding buildContext() might want to return its class. - /// - protected virtual object ContextKey - { - get { return ConfigLocations; } - } - - /// - /// Loads application context from the specified resource locations. - /// - /// Resources to load object definitions from. - protected override IConfigurableApplicationContext LoadContextLocations(string[] locations) - { - ++this.loadCount; - return base.LoadContextLocations(locations); - } - - /// - /// Retrieves the names of the fields that should be used for field injection. - /// - protected virtual void InitManagedVariableNames() - { - List managedVarNames = new List(); - Type type = GetType(); - - do - { - FieldInfo[] fields = - type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Instance); + FieldInfo field = fields[i]; if (logger.IsEnabled(LogLevel.Debug)) { - logger.LogDebug("Found " + fields.Length + " fields on " + type); + logger.LogDebug("Candidate field: " + field); } - for (int i = 0; i < fields.Length; i++) + if (IsProtectedInstanceField(field)) { - FieldInfo field = fields[i]; - if (logger.IsEnabled(LogLevel.Debug)) + object oldValue = field.GetValue(this); + if (oldValue == null) { - logger.LogDebug("Candidate field: " + field); - } - if (IsProtectedInstanceField(field)) - { - object oldValue = field.GetValue(this); - if (oldValue == null) - { - managedVarNames.Add(field.Name); - if (logger.IsEnabled(LogLevel.Debug)) - { - logger.LogDebug("Added managed variable '" + field.Name + "'"); - } - } - else - { - if (logger.IsEnabled(LogLevel.Debug)) - { - logger.LogDebug("Rejected managed variable '" + field.Name + "'"); - } - } - } - } - type = type.BaseType; - } while (type != typeof (AbstractDependencyInjectionSpringContextTests)); - - this.managedVariableNames = managedVarNames; - } - - private static bool IsProtectedInstanceField(FieldInfo field) - { - return field.IsFamily; - } - - /// - /// Injects protected fields using Field Injection. - /// - protected virtual void InjectProtectedVariables() - { - for (int i = 0; i < this.managedVariableNames.Count; i++) - { - string fieldName = this.managedVariableNames[i]; - Object obj = null; - try - { - FieldInfo field = GetType().GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Instance); - if (field != null) - { - BeforeProtectedVariableInjection(field); - obj = this.applicationContext.GetObject(fieldName, field.FieldType); - field.SetValue(this, obj); + managedVarNames.Add(field.Name); if (logger.IsEnabled(LogLevel.Debug)) { - logger.LogDebug("Populated field: " + field); + logger.LogDebug("Added managed variable '" + field.Name + "'"); } } else { - if (logger.IsEnabled(LogLevel.Warning)) + if (logger.IsEnabled(LogLevel.Debug)) { - logger.LogWarning("No field with name '" + fieldName + "'"); + logger.LogDebug("Rejected managed variable '" + field.Name + "'"); } } } - catch (NoSuchObjectDefinitionException) + } + + type = type.BaseType; + } while (type != typeof(AbstractDependencyInjectionSpringContextTests)); + + this.managedVariableNames = managedVarNames; + } + + private static bool IsProtectedInstanceField(FieldInfo field) + { + return field.IsFamily; + } + + /// + /// Injects protected fields using Field Injection. + /// + protected virtual void InjectProtectedVariables() + { + for (int i = 0; i < this.managedVariableNames.Count; i++) + { + string fieldName = this.managedVariableNames[i]; + Object obj = null; + try + { + FieldInfo field = GetType().GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Instance); + if (field != null) + { + BeforeProtectedVariableInjection(field); + obj = this.applicationContext.GetObject(fieldName, field.FieldType); + field.SetValue(this, obj); + if (logger.IsEnabled(LogLevel.Debug)) + { + logger.LogDebug("Populated field: " + field); + } + } + else { if (logger.IsEnabled(LogLevel.Warning)) { - logger.LogWarning("No object definition with name '" + fieldName + "'"); + logger.LogWarning("No field with name '" + fieldName + "'"); } } } - } - - /// - /// Called right before a field is being injected - /// - protected virtual void BeforeProtectedVariableInjection(FieldInfo fieldInfo) - { - - } - - /// - /// Subclasses can override this method in order to - /// add custom test setup logic after the context has been created and dependencies injected. - /// Called from this class's [SetUp] method. - /// - protected virtual void OnSetUp() - {} - - /// - /// Test teardown method. - /// - [TearDown] - public void TearDown() - { - try + catch (NoSuchObjectDefinitionException) { - OnTearDown(); - } - catch (Exception ex) - { - logger.LogError(ex, "OnTearDown error"); - throw; + if (logger.IsEnabled(LogLevel.Warning)) + { + logger.LogWarning("No object definition with name '" + fieldName + "'"); + } } } - - /// - /// Subclasses can override this method in order to - /// add custom test teardown logic. Called from this class's [TearDown] method. - /// - protected virtual void OnTearDown() - {} - - - /// - /// Subclasses must implement this property to return the locations of their - /// config files. A plain path will be treated as a file system location. - /// - /// An array of config locations - protected abstract string[] ConfigLocations { get; } } -} + + /// + /// Called right before a field is being injected + /// + protected virtual void BeforeProtectedVariableInjection(FieldInfo fieldInfo) + { + } + + /// + /// Subclasses can override this method in order to + /// add custom test setup logic after the context has been created and dependencies injected. + /// Called from this class's [SetUp] method. + /// + protected virtual void OnSetUp() + { + } + + /// + /// Test teardown method. + /// + [TearDown] + public void TearDown() + { + try + { + OnTearDown(); + } + catch (Exception ex) + { + logger.LogError(ex, "OnTearDown error"); + throw; + } + } + + /// + /// Subclasses can override this method in order to + /// add custom test teardown logic. Called from this class's [TearDown] method. + /// + protected virtual void OnTearDown() + { + } + + /// + /// Subclasses must implement this property to return the locations of their + /// config files. A plain path will be treated as a file system location. + /// + /// An array of config locations + protected abstract string[] ConfigLocations { get; } +} \ No newline at end of file diff --git a/src/Spring/Spring.Testing.NUnit/Testing/NUnit/AbstractSpringContextTests.cs b/src/Spring/Spring.Testing.NUnit/Testing/NUnit/AbstractSpringContextTests.cs index 3b9a31b9..ebd0bee8 100644 --- a/src/Spring/Spring.Testing.NUnit/Testing/NUnit/AbstractSpringContextTests.cs +++ b/src/Spring/Spring.Testing.NUnit/Testing/NUnit/AbstractSpringContextTests.cs @@ -20,230 +20,230 @@ using Spring.Context; using Spring.Context.Support; using Spring.Util; -namespace Spring.Testing.NUnit +namespace Spring.Testing.NUnit; + +/// +/// Superclass for NUnit test cases using a Spring context. +/// +/// +///

Maintains a cache of contexts by key. This has significant performance +/// benefit if initializing the context would take time. While initializing a +/// Spring context itself is very quick, some objects in a context, such as +/// a LocalSessionFactoryObject for working with NHibernate, may take time to +/// initialize. Hence it often makes sense to do that initializing once.

+///

Normally you won't extend this class directly but rather extend one +/// of its subclasses.

+///
+/// Rod Johnson +/// Aleksandar Seovic (.NET) +public abstract class AbstractSpringContextTests { /// - /// Superclass for NUnit test cases using a Spring context. + /// Map of context keys returned by subclasses of this class, to + /// Spring contexts. + /// + private static readonly IDictionary contextKeyToContextMap; + + /// + /// Static ctor to avoid "beforeFieldInit" problem. + /// + static AbstractSpringContextTests() + { + contextKeyToContextMap = new Hashtable(); + } + + /// + /// Disposes any cached context instance and removes it from cache. + /// + public static void ClearContextCache() + { + foreach (IApplicationContext ctx in contextKeyToContextMap.Values) + { + ctx.Dispose(); + } + + contextKeyToContextMap.Clear(); + } + + /// + /// Indicates, whether context instances should be automatically registered with the global . + /// + private bool registerContextWithContextRegistry = true; + + /// + /// Logger available to subclasses. + /// + protected readonly ILogger logger; + + /// + /// Default constructor for AbstractSpringContextTests. + /// + protected AbstractSpringContextTests() + { + logger = LogManager.GetLogger(GetType()); + } + + /// + /// Controls, whether application context instances will + /// be registered/unregistered with the global . + /// Defaults to true. + /// + public bool RegisterContextWithContextRegistry + { + get { return registerContextWithContextRegistry; } + set { registerContextWithContextRegistry = value; } + } + + /// + /// Set custom locations dirty. This will cause them to be reloaded + /// from the cache before the next test case is executed. /// /// - ///

Maintains a cache of contexts by key. This has significant performance - /// benefit if initializing the context would take time. While initializing a - /// Spring context itself is very quick, some objects in a context, such as - /// a LocalSessionFactoryObject for working with NHibernate, may take time to - /// initialize. Hence it often makes sense to do that initializing once.

- ///

Normally you won't extend this class directly but rather extend one - /// of its subclasses.

+ /// Call this method only if you change the state of a singleton + /// object, potentially affecting future tests. ///
- /// Rod Johnson - /// Aleksandar Seovic (.NET) - public abstract class AbstractSpringContextTests + /// Locations + protected void SetDirty(string[] locations) { - /// - /// Map of context keys returned by subclasses of this class, to - /// Spring contexts. - /// - private static readonly IDictionary contextKeyToContextMap; + SetDirty((object) locations); + } - /// - /// Static ctor to avoid "beforeFieldInit" problem. - /// - static AbstractSpringContextTests() + /// + /// Set context with dirty. This will cause + /// it to be reloaded from the cache before the next test case is executed. + /// + /// + /// Call this method only if you change the state of a singleton + /// object, potentially affecting future tests. + /// + /// Locations + protected void SetDirty(object contextKey) + { + String keyString = ContextKeyString(contextKey); + IConfigurableApplicationContext ctx = + (IConfigurableApplicationContext) contextKeyToContextMap[keyString]; + contextKeyToContextMap.Remove(keyString); + + if (ctx != null) { - contextKeyToContextMap = new Hashtable(); + ctx.Dispose(); + } + } + + /// + /// Returns true if context for the specified + /// is cached. + /// + /// Context key to check. + /// + /// true if context for the specified + /// is cached, + /// false otherwise. + /// + protected bool HasCachedContext(object contextKey) + { + string keyString = ContextKeyString(contextKey); + return contextKeyToContextMap.Contains(keyString); + } + + /// + /// Converts context key to string. + /// + /// + /// Subclasses can override this to return a string representation of + /// their contextKey for use in logging. + /// + /// Context key to convert. + /// + /// String representation of the specified . Null if + /// contextKey is null. + /// + protected virtual string ContextKeyString(object contextKey) + { + if (contextKey == null) + { + return null; } - /// - /// Disposes any cached context instance and removes it from cache. - /// - public static void ClearContextCache() + if (contextKey is string[]) { - foreach(IApplicationContext ctx in contextKeyToContextMap.Values) + return StringUtils.CollectionToCommaDelimitedString((string[]) contextKey); + } + else + { + return contextKey.ToString(); + } + } + + /// + /// Caches application context. + /// + /// Key to use. + /// Context to cache. + public void AddContext(object key, IConfigurableApplicationContext context) + { + AssertUtils.ArgumentNotNull(context, "context", "ApplicationContext must not be null"); + string keyString = ContextKeyString(key); + contextKeyToContextMap.Add(keyString, context); + + if (RegisterContextWithContextRegistry + && !ContextRegistry.IsContextRegistered(context.Name)) + { + ContextRegistry.RegisterContext(context); + } + } + + /// + /// Returns cached context if present, or loads it if not. + /// + /// Context key. + /// Spring application context associated with the specified key. + protected IConfigurableApplicationContext GetContext(object key) + { + string keyString = ContextKeyString(key); + IConfigurableApplicationContext ctx = + (IConfigurableApplicationContext) contextKeyToContextMap[keyString]; + if (ctx == null) + { + if (key is string[]) { - ctx.Dispose(); + ctx = LoadContextLocations((string[]) key); } - contextKeyToContextMap.Clear(); - } - - /// - /// Indicates, whether context instances should be automatically registered with the global . - /// - private bool registerContextWithContextRegistry = true; - - /// - /// Logger available to subclasses. - /// - protected readonly ILogger logger; - - /// - /// Default constructor for AbstractSpringContextTests. - /// - protected AbstractSpringContextTests() - { - logger = LogManager.GetLogger(GetType()); - } - - /// - /// Controls, whether application context instances will - /// be registered/unregistered with the global . - /// Defaults to true. - /// - public bool RegisterContextWithContextRegistry - { - get { return registerContextWithContextRegistry; } - set { registerContextWithContextRegistry = value; } - } - - /// - /// Set custom locations dirty. This will cause them to be reloaded - /// from the cache before the next test case is executed. - /// - /// - /// Call this method only if you change the state of a singleton - /// object, potentially affecting future tests. - /// - /// Locations - protected void SetDirty(string[] locations) - { - SetDirty((object)locations); - } - - /// - /// Set context with dirty. This will cause - /// it to be reloaded from the cache before the next test case is executed. - /// - /// - /// Call this method only if you change the state of a singleton - /// object, potentially affecting future tests. - /// - /// Locations - protected void SetDirty(object contextKey) - { - String keyString = ContextKeyString(contextKey); - IConfigurableApplicationContext ctx = - (IConfigurableApplicationContext) contextKeyToContextMap[keyString]; - contextKeyToContextMap.Remove(keyString); - - if (ctx != null) + else { - ctx.Dispose(); - } - } - - /// - /// Returns true if context for the specified - /// is cached. - /// - /// Context key to check. - /// - /// true if context for the specified - /// is cached, - /// false otherwise. - /// - protected bool HasCachedContext(object contextKey) - { - string keyString = ContextKeyString(contextKey); - return contextKeyToContextMap.Contains(keyString); - } - - /// - /// Converts context key to string. - /// - /// - /// Subclasses can override this to return a string representation of - /// their contextKey for use in logging. - /// - /// Context key to convert. - /// - /// String representation of the specified . Null if - /// contextKey is null. - /// - protected virtual string ContextKeyString(object contextKey) - { - if (contextKey == null) - { - return null; + ctx = LoadContext(key); } - if (contextKey is string[]) - { - return StringUtils.CollectionToCommaDelimitedString((string[])contextKey); - } - else - { - return contextKey.ToString(); - } - } - /// - /// Caches application context. - /// - /// Key to use. - /// Context to cache. - public void AddContext(object key, IConfigurableApplicationContext context) + AddContext(key, ctx); + } + + return ctx; + } + + /// + /// Loads application context from the specified resource locations. + /// + /// Resources to load object definitions from. + protected virtual IConfigurableApplicationContext LoadContextLocations(string[] locations) + { + if (logger.IsEnabled(LogLevel.Information)) { - AssertUtils.ArgumentNotNull(context, "context", "ApplicationContext must not be null"); - string keyString = ContextKeyString(key); - contextKeyToContextMap.Add(keyString, context); + logger.LogInformation("Loading config for: " + StringUtils.CollectionToCommaDelimitedString(locations)); + } - if (RegisterContextWithContextRegistry - && !ContextRegistry.IsContextRegistered(context.Name)) - { - ContextRegistry.RegisterContext(context); - } - } - - /// - /// Returns cached context if present, or loads it if not. - /// - /// Context key. - /// Spring application context associated with the specified key. - protected IConfigurableApplicationContext GetContext(object key) - { - string keyString = ContextKeyString(key); - IConfigurableApplicationContext ctx = - (IConfigurableApplicationContext) contextKeyToContextMap[keyString]; - if (ctx == null) - { - if (key is string[]) - { - ctx = LoadContextLocations((string[]) key); - } - else - { - ctx = LoadContext(key); - } - AddContext(key, ctx); - } - return ctx; - } - - - - - /// - /// Loads application context from the specified resource locations. - /// - /// Resources to load object definitions from. - protected virtual IConfigurableApplicationContext LoadContextLocations(string[] locations) - { - if (logger.IsEnabled(LogLevel.Information)) - { - logger.LogInformation("Loading config for: " + StringUtils.CollectionToCommaDelimitedString(locations)); - } - return new XmlApplicationContext(locations); - } - - /// - /// Loads application context based on user-defined key. - /// - /// - /// Unless overriden by the user, this method will alway throw - /// a . - /// - /// User-defined key. - protected virtual IConfigurableApplicationContext LoadContext(object key) - { - throw new NotSupportedException("Subclasses may override this"); - } + return new XmlApplicationContext(locations); + } + /// + /// Loads application context based on user-defined key. + /// + /// + /// Unless overriden by the user, this method will alway throw + /// a . + /// + /// User-defined key. + protected virtual IConfigurableApplicationContext LoadContext(object key) + { + throw new NotSupportedException("Subclasses may override this"); } } diff --git a/src/Spring/Spring.Testing.NUnit/Testing/NUnit/AbstractTransactionalDbProviderSpringContextTests.cs b/src/Spring/Spring.Testing.NUnit/Testing/NUnit/AbstractTransactionalDbProviderSpringContextTests.cs index e012be79..8748159f 100644 --- a/src/Spring/Spring.Testing.NUnit/Testing/NUnit/AbstractTransactionalDbProviderSpringContextTests.cs +++ b/src/Spring/Spring.Testing.NUnit/Testing/NUnit/AbstractTransactionalDbProviderSpringContextTests.cs @@ -4,128 +4,128 @@ using Spring.Data.Common; using Spring.Data.Core; using Spring.Testing.Ado; -namespace Spring.Testing.NUnit +namespace Spring.Testing.NUnit; + +/// +/// Subclass of AbstractTransactionalSpringContextTests that adds some convenience +/// functionality for ADO.NET access. Expects a IDbProvider object +/// to be defined in the Spring application context. +/// +/// +/// This class exposes a AdoTemplate and provides an easy way to delete from the +/// database in a new transaction. +/// +/// Rod Johnson +/// Juergen Hoeller +/// Mark Pollack (.NET) +public abstract class AbstractTransactionalDbProviderSpringContextTests : AbstractTransactionalSpringContextTests { /// - /// Subclass of AbstractTransactionalSpringContextTests that adds some convenience - /// functionality for ADO.NET access. Expects a IDbProvider object - /// to be defined in the Spring application context. + /// Holds the that this base class manages + /// + private AdoTemplate adoTemplate; + + /// + /// Did this test delete any tables? If so, we forbid transaction completion, + /// and only allow rollback. + /// + private bool zappedTables; + + /// + /// Initializes a new instance of the class. + /// + public AbstractTransactionalDbProviderSpringContextTests() + { + } + + /// + /// Sets the DbProvider, via Dependency Injection. + /// + /// The IDbProvider. + public IDbProvider DbProvider + { + set { adoTemplate = new AdoTemplate(value); } + } + + /// + /// Gets or sets the AdoTemplate that this base class manages. + /// + /// The ADO template. + public AdoTemplate AdoTemplate + { + get { return adoTemplate; } + protected set { adoTemplate = value; } + } + + /// + /// Inject dependencies into 'this' instance (that is, this test instance). /// /// - /// This class exposes a AdoTemplate and provides an easy way to delete from the - /// database in a new transaction. + ///

The default implementation populates protected variables if the + /// property is set, else + /// uses autowiring if autowiring is switched on (which it is by default).

+ ///

You can certainly override this method if you want to totally control + /// how dependencies are injected into 'this' instance.

+ ///

AdoTemplate autowiring is Ignored

///
- /// Rod Johnson - /// Juergen Hoeller - /// Mark Pollack (.NET) - public abstract class AbstractTransactionalDbProviderSpringContextTests : AbstractTransactionalSpringContextTests + protected override void InjectDependencies() { - /// - /// Holds the that this base class manages - /// - private AdoTemplate adoTemplate; + applicationContext.ObjectFactory.IgnoreDependencyType(typeof(AdoTemplate)); + base.InjectDependencies(); + } - /// - /// Did this test delete any tables? If so, we forbid transaction completion, - /// and only allow rollback. - /// - private bool zappedTables; - - /// - /// Initializes a new instance of the class. - /// - public AbstractTransactionalDbProviderSpringContextTests() + /// + /// Convenient method to delete all rows from these tables. + /// Calling this method will make avoidance of rollback by calling + /// SetComplete() impossible. + /// + /// + protected void DeleteFromTables(String[] names) + { + for (int i = 0; i < names.Length; i++) { - } - - /// - /// Sets the DbProvider, via Dependency Injection. - /// - /// The IDbProvider. - public IDbProvider DbProvider - { - set { adoTemplate = new AdoTemplate(value); } - } - - /// - /// Gets or sets the AdoTemplate that this base class manages. - /// - /// The ADO template. - public AdoTemplate AdoTemplate - { - get { return adoTemplate; } - protected set { adoTemplate = value; } - } - - /// - /// Inject dependencies into 'this' instance (that is, this test instance). - /// - /// - ///

The default implementation populates protected variables if the - /// property is set, else - /// uses autowiring if autowiring is switched on (which it is by default).

- ///

You can certainly override this method if you want to totally control - /// how dependencies are injected into 'this' instance.

- ///

AdoTemplate autowiring is Ignored

- ///
- protected override void InjectDependencies() - { - applicationContext.ObjectFactory.IgnoreDependencyType(typeof(AdoTemplate)); - base.InjectDependencies(); - } - - /// - /// Convenient method to delete all rows from these tables. - /// Calling this method will make avoidance of rollback by calling - /// SetComplete() impossible. - /// - /// - protected void DeleteFromTables(String[] names) - { - for (int i = 0; i < names.Length; i++) + int rowCount = this.adoTemplate.ExecuteNonQuery(CommandType.Text, "DELETE FROM " + names[i]); + if (logger.IsEnabled(LogLevel.Information)) { - int rowCount = this.adoTemplate.ExecuteNonQuery(CommandType.Text, "DELETE FROM " + names[i]); - if (logger.IsEnabled(LogLevel.Information)) - { - logger.LogInformation("Deleted " + rowCount + " rows from table " + names[i]); - } + logger.LogInformation("Deleted " + rowCount + " rows from table " + names[i]); } - this.zappedTables = true; } - /// - /// Overridden to prevent the transaction committing if a number of tables have been - /// cleared, as a defensive measure against accidental permanent wiping of a database. - /// - protected override void SetComplete() + this.zappedTables = true; + } + + /// + /// Overridden to prevent the transaction committing if a number of tables have been + /// cleared, as a defensive measure against accidental permanent wiping of a database. + /// + protected override void SetComplete() + { + if (this.zappedTables) { - if (this.zappedTables) - { - throw new InvalidOperationException("Cannot set complete after deleting tables"); - } - base.SetComplete(); + throw new InvalidOperationException("Cannot set complete after deleting tables"); } - /// - /// Counts the rows in given table. - /// - /// Name of the table to count rows in. - /// The number of rows in the table - protected int CountRowsInTable(String tableName) - { - return (int) adoTemplate.ExecuteScalar(CommandType.Text, "SELECT COUNT(0) FROM " + tableName); + base.SetComplete(); + } - } + /// + /// Counts the rows in given table. + /// + /// Name of the table to count rows in. + /// The number of rows in the table + protected int CountRowsInTable(String tableName) + { + return (int) adoTemplate.ExecuteScalar(CommandType.Text, "SELECT COUNT(0) FROM " + tableName); + } - /// - /// Execute the given SQL script using - /// - /// - /// - /// - protected void ExecuteSqlScript(string scriptResourcePath, bool continueOnError) - { - SimpleAdoTestUtils.ExecuteSqlScript( this.AdoTemplate, this.applicationContext, scriptResourcePath, continueOnError); - } + /// + /// Execute the given SQL script using + /// + /// + /// + /// + protected void ExecuteSqlScript(string scriptResourcePath, bool continueOnError) + { + SimpleAdoTestUtils.ExecuteSqlScript(this.AdoTemplate, this.applicationContext, scriptResourcePath, continueOnError); } } diff --git a/src/Spring/Spring.Testing.NUnit/Testing/NUnit/AbstractTransactionalSpringContextTests.cs b/src/Spring/Spring.Testing.NUnit/Testing/NUnit/AbstractTransactionalSpringContextTests.cs index 18ac60ec..025ffa7c 100644 --- a/src/Spring/Spring.Testing.NUnit/Testing/NUnit/AbstractTransactionalSpringContextTests.cs +++ b/src/Spring/Spring.Testing.NUnit/Testing/NUnit/AbstractTransactionalSpringContextTests.cs @@ -2,286 +2,286 @@ using Microsoft.Extensions.Logging; using Spring.Transaction; using Spring.Transaction.Support; -namespace Spring.Testing.NUnit +namespace Spring.Testing.NUnit; + +/// +/// Convenient superclass for tests that should occur in a transaction, but normally +/// will roll the transaction back on the completion of each test. +/// +/// +///

This is useful in a range of circumstances, allowing the following benefits:

+///
    +///
  • Ability to delete or insert any data in the database, without affecting other tests
  • +///
  • Providing a transactional context for any code requiring a transaction
  • +///
  • Ability to write anything to the database without any need to clean up.
  • +///
+/// +///

This class is typically very fast, compared to traditional setup/teardown scripts.

+/// +///

If data should be left in the database, call the SetComplete() +/// method in each test. The "DefaultRollback" property, which defaults to "true", +/// determines whether transactions will complete by default.

+/// +///

It is even possible to end the transaction early; for example, to verify lazy +/// loading behavior of an O/R mapping tool. (This is a valuable away to avoid +/// unexpected errors when testing a web UI, for example.) Simply call the +/// endTransaction() method. Execution will then occur without a +/// transactional context.

+/// +///

The StartNewTransaction() method may be called after a call to +/// EndTransaction() if you wish to create a new transaction, quite +/// independent of the old transaction. The new transaction's default fate will be to +/// roll back, unless setComplete() is called again during the scope of the +/// new transaction. Any number of transactions may be created and ended in this way. +/// The final transaction will automatically be rolled back when the test case is +/// torn down.

+/// +///

Transactional behavior requires a single object in the context implementing the +/// IPlatformTransactionManager interface. This will be set by the superclass's +/// Dependency Injection mechanism. If using the superclass's Field Injection mechanism, +/// the implementation should be named "transactionManager". This mechanism allows the +/// use of this superclass even when there's more than one transaction manager in the context.

+/// +///

This superclass can also be used without transaction management, if no +/// IPlatformTransactionManager object is found in the context provided. Be careful about +/// using this mode, as it allows the potential to permanently modify data. +/// This mode is available only if dependency checking is turned off in +/// the AbstractDependencyInjectionSpringContextTests superclass. The non-transactional +/// capability is provided to enable use of the same subclass in different environments.

+/// +///
+/// +/// Rod Johnson +/// Juergen Hoeller +/// Rick Evans +/// Mark Pollack (.NET) +public abstract class AbstractTransactionalSpringContextTests : AbstractDependencyInjectionSpringContextTests { /// - /// Convenient superclass for tests that should occur in a transaction, but normally - /// will roll the transaction back on the completion of each test. + /// The transaction manager to use + /// + private IPlatformTransactionManager transactionManager; + + /// + /// Should we roll back by default? + /// + private bool defaultRollback = true; + + /// + /// Should we commit the current transaction? + /// + private bool complete = false; + + /// + /// Number of transactions started + /// + private int transactionsStarted = 0; + + /// + /// Default transaction definition is used. + /// Subclasses can change this to cause different behaviour. + /// + private ITransactionDefinition transactionDefinition = new DefaultTransactionDefinition(); + + /// + /// TransactionStatus for this test. Typical subclasses won't need to use it. + /// + private ITransactionStatus transactionStatus; + + /// + /// Sets the transaction manager to use. + /// + public IPlatformTransactionManager TransactionManager + { + protected get { return transactionManager; } + set { transactionManager = value; } + } + + /// + /// Sets the default rollback flag. + /// + public bool DefaultRollback + { + set { defaultRollback = value; } + } + + /// + /// Set the to be used /// /// - ///

This is useful in a range of circumstances, allowing the following benefits:

- ///
    - ///
  • Ability to delete or insert any data in the database, without affecting other tests
  • - ///
  • Providing a transactional context for any code requiring a transaction
  • - ///
  • Ability to write anything to the database without any need to clean up.
  • - ///
- /// - ///

This class is typically very fast, compared to traditional setup/teardown scripts.

- /// - ///

If data should be left in the database, call the SetComplete() - /// method in each test. The "DefaultRollback" property, which defaults to "true", - /// determines whether transactions will complete by default.

- /// - ///

It is even possible to end the transaction early; for example, to verify lazy - /// loading behavior of an O/R mapping tool. (This is a valuable away to avoid - /// unexpected errors when testing a web UI, for example.) Simply call the - /// endTransaction() method. Execution will then occur without a - /// transactional context.

- /// - ///

The StartNewTransaction() method may be called after a call to - /// EndTransaction() if you wish to create a new transaction, quite - /// independent of the old transaction. The new transaction's default fate will be to - /// roll back, unless setComplete() is called again during the scope of the - /// new transaction. Any number of transactions may be created and ended in this way. - /// The final transaction will automatically be rolled back when the test case is - /// torn down.

- /// - ///

Transactional behavior requires a single object in the context implementing the - /// IPlatformTransactionManager interface. This will be set by the superclass's - /// Dependency Injection mechanism. If using the superclass's Field Injection mechanism, - /// the implementation should be named "transactionManager". This mechanism allows the - /// use of this superclass even when there's more than one transaction manager in the context.

- /// - ///

This superclass can also be used without transaction management, if no - /// IPlatformTransactionManager object is found in the context provided. Be careful about - /// using this mode, as it allows the potential to permanently modify data. - /// This mode is available only if dependency checking is turned off in - /// the AbstractDependencyInjectionSpringContextTests superclass. The non-transactional - /// capability is provided to enable use of the same subclass in different environments.

- /// + /// Defaults to ///
- /// - /// Rod Johnson - /// Juergen Hoeller - /// Rick Evans - /// Mark Pollack (.NET) - public abstract class AbstractTransactionalSpringContextTests : AbstractDependencyInjectionSpringContextTests + protected ITransactionDefinition TransactionDefinition { - /// - /// The transaction manager to use - /// - private IPlatformTransactionManager transactionManager; + set { transactionDefinition = value; } + } - /// - /// Should we roll back by default? - /// - private bool defaultRollback = true; + /// + /// TransactionStatus for this test. Typical subclasses won't need to use it. + /// + protected ITransactionStatus TransactionStatus + { + get { return transactionStatus; } + set { transactionStatus = value; } + } - /// - /// Should we commit the current transaction? - /// - private bool complete = false; + /// + /// Prevents the transaction. + /// + protected virtual void PreventTransaction() + { + this.transactionDefinition = null; + } - /// - /// Number of transactions started - /// - private int transactionsStarted = 0; + /// + /// Creates a transaction + /// + protected override void OnSetUp() + { + this.complete = !this.defaultRollback; - /// - /// Default transaction definition is used. - /// Subclasses can change this to cause different behaviour. - /// - private ITransactionDefinition transactionDefinition = new DefaultTransactionDefinition(); - - /// - /// TransactionStatus for this test. Typical subclasses won't need to use it. - /// - private ITransactionStatus transactionStatus; - - /// - /// Sets the transaction manager to use. - /// - public IPlatformTransactionManager TransactionManager + if (this.transactionManager == null) { - protected get { return transactionManager; } - set { transactionManager = value; } + logger.LogInformation("No transaction manager set: test will NOT run within a transaction"); } - - /// - /// Sets the default rollback flag. - /// - public bool DefaultRollback + else if (this.transactionDefinition == null) { - set { defaultRollback = value; } + logger.LogInformation("No transaction definition set: test will NOT run within a transaction"); } - - /// - /// Set the to be used - /// - /// - /// Defaults to - /// - protected ITransactionDefinition TransactionDefinition + else { - set { transactionDefinition = value; } - } - - /// - /// TransactionStatus for this test. Typical subclasses won't need to use it. - /// - protected ITransactionStatus TransactionStatus - { - get { return transactionStatus; } - set { transactionStatus = value; } - } - - /// - /// Prevents the transaction. - /// - protected virtual void PreventTransaction() - { - this.transactionDefinition = null; - } - - - /// - /// Creates a transaction - /// - protected override void OnSetUp() - { - this.complete = !this.defaultRollback; - - if (this.transactionManager == null) + OnSetUpBeforeTransaction(); + StartNewTransaction(); + try { - logger.LogInformation("No transaction manager set: test will NOT run within a transaction"); + OnSetUpInTransaction(); } - else if (this.transactionDefinition == null) + catch (Exception) { - logger.LogInformation("No transaction definition set: test will NOT run within a transaction"); - } - else - { - OnSetUpBeforeTransaction(); - StartNewTransaction(); - try - { - OnSetUpInTransaction(); - } - catch (Exception) - { - EndTransaction(); - throw; - } - } - } - - - /// - /// Callback method called before transaction is setup. - /// - protected virtual void OnSetUpBeforeTransaction() - { - } - - /// - /// Callback method called after transaction is setup. - /// - protected virtual void OnSetUpInTransaction() - { - } - - /// - /// rollback the transaction. - /// - protected override void OnTearDown() - { - // Call onTearDownInTransaction and end transaction if the transaction is still active. - if (this.transactionStatus != null && !this.transactionStatus.Completed) - { - try - { - OnTearDownInTransaction(); - } - finally - { - EndTransaction(); - } - } - // Call onTearDownAfterTransaction if there was at least one transaction, - // even if it has been completed early through an endTransaction() call. - if (this.transactionsStarted > 0) - { - OnTearDownAfterTransaction(); - } - } - - /// - /// Callback before rolling back the transaction. - /// - protected virtual void OnTearDownInTransaction() - { - } - - /// - /// Callback after rolling back the transaction. - /// - protected virtual void OnTearDownAfterTransaction() - { - } - - /// - /// Set the complete flag.. - /// - protected virtual void SetComplete() - { - if (this.transactionManager == null) - { - throw new InvalidOperationException("No transaction manager set"); - } - this.complete = true; - } - - /// - /// Ends the transaction. - /// - protected virtual void EndTransaction() - { - if (this.transactionStatus != null) - { - try - { - if (!this.complete) - { - this.transactionManager.Rollback(this.transactionStatus); - logger.LogInformation("Rolled back transaction after test execution"); - } - else - { - this.transactionManager.Commit(this.transactionStatus); - logger.LogInformation("Committed transaction after test execution"); - } - } - finally - { - this.transactionStatus = null; - } - } - } - - /// - /// Starts the new transaction. - /// - protected void StartNewTransaction() - { - if (this.transactionStatus != null) - { - throw new InvalidOperationException("Cannot start new transaction without ending existing transaction: " + - "Invoke endTransaction() before startNewTransaction()"); - } - if (this.transactionManager == null) - { - throw new InvalidOperationException("No transaction manager set"); - } - - this.transactionStatus = this.transactionManager.GetTransaction(this.transactionDefinition); - ++this.transactionsStarted; - this.complete = !this.defaultRollback; - - if (logger.IsEnabled(LogLevel.Information)) - { - logger.LogInformation("Began transaction (" + this.transactionsStarted + "): transaction manager [" + - this.transactionManager + "]; default rollback = " + this.defaultRollback); + EndTransaction(); + throw; } } } + + /// + /// Callback method called before transaction is setup. + /// + protected virtual void OnSetUpBeforeTransaction() + { + } + + /// + /// Callback method called after transaction is setup. + /// + protected virtual void OnSetUpInTransaction() + { + } + + /// + /// rollback the transaction. + /// + protected override void OnTearDown() + { + // Call onTearDownInTransaction and end transaction if the transaction is still active. + if (this.transactionStatus != null && !this.transactionStatus.Completed) + { + try + { + OnTearDownInTransaction(); + } + finally + { + EndTransaction(); + } + } + + // Call onTearDownAfterTransaction if there was at least one transaction, + // even if it has been completed early through an endTransaction() call. + if (this.transactionsStarted > 0) + { + OnTearDownAfterTransaction(); + } + } + + /// + /// Callback before rolling back the transaction. + /// + protected virtual void OnTearDownInTransaction() + { + } + + /// + /// Callback after rolling back the transaction. + /// + protected virtual void OnTearDownAfterTransaction() + { + } + + /// + /// Set the complete flag.. + /// + protected virtual void SetComplete() + { + if (this.transactionManager == null) + { + throw new InvalidOperationException("No transaction manager set"); + } + + this.complete = true; + } + + /// + /// Ends the transaction. + /// + protected virtual void EndTransaction() + { + if (this.transactionStatus != null) + { + try + { + if (!this.complete) + { + this.transactionManager.Rollback(this.transactionStatus); + logger.LogInformation("Rolled back transaction after test execution"); + } + else + { + this.transactionManager.Commit(this.transactionStatus); + logger.LogInformation("Committed transaction after test execution"); + } + } + finally + { + this.transactionStatus = null; + } + } + } + + /// + /// Starts the new transaction. + /// + protected void StartNewTransaction() + { + if (this.transactionStatus != null) + { + throw new InvalidOperationException("Cannot start new transaction without ending existing transaction: " + + "Invoke endTransaction() before startNewTransaction()"); + } + + if (this.transactionManager == null) + { + throw new InvalidOperationException("No transaction manager set"); + } + + this.transactionStatus = this.transactionManager.GetTransaction(this.transactionDefinition); + ++this.transactionsStarted; + this.complete = !this.defaultRollback; + + if (logger.IsEnabled(LogLevel.Information)) + { + logger.LogInformation("Began transaction (" + this.transactionsStarted + "): transaction manager [" + + this.transactionManager + "]; default rollback = " + this.defaultRollback); + } + } } diff --git a/src/Spring/Spring.Web.Conversation.NHibernate5/AssemblyInfo.cs b/src/Spring/Spring.Web.Conversation.NHibernate5/AssemblyInfo.cs index 3a3bec04..b99e51f8 100644 --- a/src/Spring/Spring.Web.Conversation.NHibernate5/AssemblyInfo.cs +++ b/src/Spring/Spring.Web.Conversation.NHibernate5/AssemblyInfo.cs @@ -1,4 +1,4 @@ using System.Reflection; [assembly: AssemblyTitle("Spring.Web.Conversation.NHibernate5. NHibernate 3.3 support.")] -[assembly: AssemblyDescription("Interfaces and classes that provide 'Long-Running Conversation' support in Spring.Net")] \ No newline at end of file +[assembly: AssemblyDescription("Interfaces and classes that provide 'Long-Running Conversation' support in Spring.Net")] diff --git a/src/Spring/Spring.Web.Conversation.NHibernate5/Data/NHibernate/Support/SessionPerConversationScope.cs b/src/Spring/Spring.Web.Conversation.NHibernate5/Data/NHibernate/Support/SessionPerConversationScope.cs index 280ed99f..0347c568 100644 --- a/src/Spring/Spring.Web.Conversation.NHibernate5/Data/NHibernate/Support/SessionPerConversationScope.cs +++ b/src/Spring/Spring.Web.Conversation.NHibernate5/Data/NHibernate/Support/SessionPerConversationScope.cs @@ -15,7 +15,6 @@ */ using System.Reflection; - using NHibernate; using Spring.Threading; using Spring.Transaction.Support; @@ -25,442 +24,448 @@ using System.Data.Common; using Microsoft.Extensions.Logging; using Spring.Web.Conversation; -namespace Spring.Data.NHibernate.Support +namespace Spring.Data.NHibernate.Support; + +/// +///Based on +/// for support of 'session-per-conversation' pattern. +/// +///Hailton de Castro +[Serializable] +public class SessionPerConversationScope : IDisposable { - /// - ///Based on - /// for support of 'session-per-conversation' pattern. - /// - ///Hailton de Castro - [Serializable] - public class SessionPerConversationScope : IDisposable + /// + /// The logging instance. + /// + protected readonly ILogger log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private readonly SessionPerConversationScopeSettings settings; + + // Keys into LogicalThreadContext for runtime values. + private readonly string ISOPEN_KEY; + private readonly string OPENER_CONVERSATION_ID_KEY; + + /// + /// Initializes a new instance of the class. + /// Uses default values for + /// + public SessionPerConversationScope() + : this(new SessionPerConversationScopeSettings()) { - /// - /// The logging instance. - /// - protected readonly ILogger log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + // noop + } - private readonly SessionPerConversationScopeSettings settings; + /// + /// Initializes a new instance of the class. + /// + /// Specify the to be set on each session provided by this instance. + /// Specify the flushmode to be applied on each session provided by this instance. + /// + public SessionPerConversationScope(IInterceptor entityInterceptor, FlushMode defaultFlushMode) + : this(new SessionPerConversationScopeSettings(entityInterceptor, defaultFlushMode)) + { + // noop + } - // Keys into LogicalThreadContext for runtime values. - private readonly string ISOPEN_KEY; - private readonly string OPENER_CONVERSATION_ID_KEY; + /// + /// Initializes a new instance of the class. + /// + /// An instance holding the scope configuration + public SessionPerConversationScope(SessionPerConversationScopeSettings settings) + { + log = LogManager.GetLogger(GetType()); + this.settings = settings; - /// - /// Initializes a new instance of the class. - /// Uses default values for - /// - public SessionPerConversationScope() - : this(new SessionPerConversationScopeSettings()) + ISOPEN_KEY = UniqueKey.GetInstanceScopedString(this, "IsOpen"); + OPENER_CONVERSATION_ID_KEY = UniqueKey.GetInstanceScopedString(this, "OpenerConversationId"); + } + + /// + /// Gets the flushmode to be applied on each newly created session. + /// + /// + /// This property defaults to to ensure that modifying objects outside the boundaries + /// of a transaction will not be persisted. It is recommended to not change this value but wrap any modifying operation + /// within a transaction. + /// + public FlushMode DefaultFlushMode + { + get { return settings.DefaultFlushMode; } + } + + /// + /// Get the configured EntityInterceptor + /// + public IInterceptor EntityInterceptor + { + get { - // noop + return settings.EntityInterceptor; } + } - /// - /// Initializes a new instance of the class. - /// - /// Specify the to be set on each session provided by this instance. - /// Specify the flushmode to be applied on each session provided by this instance. - /// - public SessionPerConversationScope(IInterceptor entityInterceptor, FlushMode defaultFlushMode) - : this(new SessionPerConversationScopeSettings(entityInterceptor, defaultFlushMode)) + /// + /// Id for conversation that open the Session. + /// + public String OpenerConversationId + { + get { - // noop + return (String) LogicalThreadContext.GetData(OPENER_CONVERSATION_ID_KEY); } - - /// - /// Initializes a new instance of the class. - /// - /// An instance holding the scope configuration - public SessionPerConversationScope(SessionPerConversationScopeSettings settings) + set { - log = LogManager.GetLogger(GetType()); - this.settings = settings; - - ISOPEN_KEY = UniqueKey.GetInstanceScopedString(this, "IsOpen"); - OPENER_CONVERSATION_ID_KEY = UniqueKey.GetInstanceScopedString(this, "OpenerConversationId"); + LogicalThreadContext.SetData(OPENER_CONVERSATION_ID_KEY, value); } + } - /// - /// Gets the flushmode to be applied on each newly created session. - /// - /// - /// This property defaults to to ensure that modifying objects outside the boundaries - /// of a transaction will not be persisted. It is recommended to not change this value but wrap any modifying operation - /// within a transaction. - /// - public FlushMode DefaultFlushMode + /// + /// Gets a flag, whether this scope is in "open" state on the current logical thread. + /// + public bool IsOpen + { + get { - get { return settings.DefaultFlushMode; } + return (null != LogicalThreadContext.GetData(ISOPEN_KEY)); } + } - /// - /// Get the configured EntityInterceptor - /// - public IInterceptor EntityInterceptor + /// + /// Sets a flag, whether this scope is in "open" state on the current logical thread. + /// + /// + private void SetOpen(bool isOpen) + { + if (isOpen) { - get + LogicalThreadContext.SetData(ISOPEN_KEY, ISOPEN_KEY); + } + else + { + LogicalThreadContext.FreeNamedDataSlot(ISOPEN_KEY); + } + } + + /// + /// NOOP. + /// + public virtual void Dispose() + { + //no OP + } + + /// + /// Open a new session or reconect the + /// in . + /// Participating in an existing session registed with + /// is not alowed. + /// + /// + /// + /// + /// + /// If there is another conversation with a with opened + /// . + /// If attempting to participate in an existing NHibernate + /// managed by . + /// + /// + /// + public void Open(IConversationState activeConversation, ICollection allManagedConversation) + { + bool isDebugEnabled = log.IsEnabled(LogLevel.Debug); + + if (IsOpen) + { + if (activeConversation.Id != OpenerConversationId) { - return settings.EntityInterceptor; - } - } - - /// - /// Id for conversation that open the Session. - /// - public String OpenerConversationId - { - get - { - return (String)LogicalThreadContext.GetData(OPENER_CONVERSATION_ID_KEY); - } - set - { - LogicalThreadContext.SetData(OPENER_CONVERSATION_ID_KEY, value); - } - } - - /// - /// Gets a flag, whether this scope is in "open" state on the current logical thread. - /// - public bool IsOpen - { - get - { - return (null != LogicalThreadContext.GetData(ISOPEN_KEY)); - } - } - - /// - /// Sets a flag, whether this scope is in "open" state on the current logical thread. - /// - /// - private void SetOpen(bool isOpen) - { - if (isOpen) - { - LogicalThreadContext.SetData(ISOPEN_KEY, ISOPEN_KEY); + throw new InvalidOperationException("There is another conversation with a ISession with opened IDbConnection."); } else { - LogicalThreadContext.FreeNamedDataSlot(ISOPEN_KEY); + if (isDebugEnabled) + { + log.LogDebug($"SessionPerConversationScope is already open for this conversation: Id:'{activeConversation.Id}'."); + } } } - - /// - /// NOOP. - /// - public virtual void Dispose() + else { - //no OP - } - - /// - /// Open a new session or reconect the - /// in . - /// Participating in an existing session registed with - /// is not alowed. - /// - /// - /// - /// - /// - /// If there is another conversation with a with opened - /// . - /// If attempting to participate in an existing NHibernate - /// managed by . - /// - /// - /// - public void Open(IConversationState activeConversation, ICollection allManagedConversation) - { - bool isDebugEnabled = log.IsEnabled(LogLevel.Debug); - - if (IsOpen) + if (activeConversation.SessionFactory != null) { - if (activeConversation.Id != OpenerConversationId) + if (isDebugEnabled) { - throw new InvalidOperationException("There is another conversation with a ISession with opened IDbConnection."); + log.LogDebug($"activeConversation with 'session-per-conversation': Id:'{activeConversation.Id}'."); + } + + // single session mode + if (TransactionSynchronizationManager.HasResource(activeConversation.SessionFactory)) + { + // Do not modify the Session: just set the participate flag. + if (isDebugEnabled) + { + log.LogDebug("Participating in existing NHibernate SessionFactory IS NOT ALLOWED."); + } + + throw new InvalidOperationException("Participating in existing NHibernate SessionFactory IS NOT ALLOWED."); } else { if (isDebugEnabled) { - log.LogDebug($"SessionPerConversationScope is already open for this conversation: Id:'{activeConversation.Id}'."); + log.LogDebug("Opening single NHibernate Session in SessionPerConversationScope"); } + + TransactionSynchronizationManager.BindResource(activeConversation.SessionFactory, new LazySessionPerConversationHolder(this, activeConversation, allManagedConversation)); + + SetOpen(true); + OpenerConversationId = activeConversation.Id; } } else { - if (activeConversation.SessionFactory != null) + if (isDebugEnabled) { - if (isDebugEnabled) - { - log.LogDebug($"activeConversation with 'session-per-conversation': Id:'{activeConversation.Id}'."); - } - - // single session mode - if (TransactionSynchronizationManager.HasResource(activeConversation.SessionFactory)) - { - // Do not modify the Session: just set the participate flag. - if (isDebugEnabled) - { - log.LogDebug("Participating in existing NHibernate SessionFactory IS NOT ALLOWED."); - } - throw new InvalidOperationException("Participating in existing NHibernate SessionFactory IS NOT ALLOWED."); - } - else - { - if (isDebugEnabled) - { - log.LogDebug("Opening single NHibernate Session in SessionPerConversationScope"); - } - - TransactionSynchronizationManager.BindResource(activeConversation.SessionFactory, new LazySessionPerConversationHolder(this, activeConversation, allManagedConversation)); - - SetOpen(true); - OpenerConversationId = activeConversation.Id; - } - } - else - { - if (isDebugEnabled) - { - log.LogDebug($"activeConversation with NO 'session-per-conversation': Id:'{activeConversation.Id}'."); - } - } - } - } - - /// - /// Close the current view's session and unregisters - /// from . - /// - /// The session factory that on use - /// A list of conversations which the session can be closed or disconnected - /// - /// - /// If start/resume a conversation from a - /// when exists a different - /// with open registered on - /// - /// If the holder on , is not a . - /// - /// - public void Close(ISessionFactory sessionFactory, ICollection allManagedConversation) - { - bool isDebugEnabled = log.IsEnabled(LogLevel.Debug); - if (isDebugEnabled) log.LogDebug("Trying to close SessionPerConversationScope"); - - if (IsOpen) - { - try - { - DoClose(sessionFactory, allManagedConversation, isDebugEnabled); - } - finally - { - SetOpen(false); - OpenerConversationId = null; - } - } - else - { - if (isDebugEnabled) log.LogDebug("No open conversation - doing nothing"); - } - } - - private void DoClose(ISessionFactory sessionFactory, ICollection allManagedConversation, bool isLogDebugEnabled) - { - // single session mode - if (isLogDebugEnabled) log.LogDebug("DoClose: Closing SessionPerConversationScope"); - Object holderObj = TransactionSynchronizationManager.UnbindResource(sessionFactory); - if (holderObj != null) - { - if (holderObj is LazySessionPerConversationHolder holder) - { - if (holder.Owner == this) - { - holder.CloseAll(); - } - else - { - throw new InvalidOperationException( - "Can not close session beacause 'holder owner' is not 'this'." + - " You are trying to start/resume a conversation from a" + - " IConversationManager when exists a diferent IConversationManager " + - " with open ISession registered on TransactionSynchronizationManager."); - } - } - else - { - throw new InvalidOperationException("Can not close session beacause holder, on TransactionSynchronizationManager, is not a LazySessionPerConversationHolder."); - } - } - else - { - if (isLogDebugEnabled) - { - log.LogWarning("DoClose: TransactionSynchronizationManager.UnbindResource(sessionFactory) has no SessionHolder. Should I throw error?"); - } - } - } - - private void DoOpenSession(IConversationState conversation) - { - lock (this) - { - ISession session = null; - if (conversation.RootSessionPerConversation == null) - { - //new session - session = (EntityInterceptor != null) - ? conversation.SessionFactory.WithOptions().Interceptor(EntityInterceptor).OpenSession() - : conversation.SessionFactory.OpenSession(); - conversation.RootSessionPerConversation = session; - } - else - { - //reconnect existing one. - if (conversation.DbProvider != null) - { - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug($"DoOpenSession: Conversation has a DbProvider: Id='{conversation.Id}'"); - } - if (!conversation.RootSessionPerConversation.IsConnected) - { - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug($"DoOpenSession: Conversation is not Connected: Id='{conversation.Id}'"); - } - - DbConnection connection = (DbConnection) conversation.DbProvider.CreateConnection(); - connection.Open(); - - conversation.RootSessionPerConversation.Reconnect(connection); - } - else - { - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug($"DoOpenSession: Conversation is already Connected: Id='{conversation.Id}'"); - } - } - } - else - { - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug($"DoOpenSession: Conversation has NO DbProvider: Id='{conversation.Id}'"); - } - conversation.RootSessionPerConversation.Reconnect(); - } - session = conversation.RootSessionPerConversation; - } - session.FlushMode = DefaultFlushMode; - } - } - - - /// - /// This sessionHolder creates a session for the active conversation only if it is - /// needed (). - /// - /// - /// Although a NHibernateSession defers creation of db-connections until they are really - /// needed, instantiation a session is still more expensive than using LazySessionHolder. - /// - private class LazySessionPerConversationHolder : SessionHolder - { - private readonly ILogger log = LogManager.GetLogger(); - private SessionPerConversationScope owner; - - IConversationState activeConversation; - ICollection allManagedConversation; - - /// - /// Initialize a new instance. - /// - public LazySessionPerConversationHolder(SessionPerConversationScope owner, IConversationState activeConversation, ICollection allManagedConversation) - { - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug("Created LazyReconnectableSessionHolder"); - } - - this.owner = owner; - this.activeConversation = activeConversation; - this.allManagedConversation = allManagedConversation; - } - - public SessionPerConversationScope Owner => owner; - - /// - /// Create a new session on demand - /// - protected override void EnsureInitialized() - { - if (activeConversation.RootSessionPerConversation == null - || !activeConversation.RootSessionPerConversation.IsConnected) - { - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug("EnsureInitialized: 'session-per-conversation' instance requested - opening new session"); - } - - owner.DoOpenSession(activeConversation); - AddSession(activeConversation.RootSessionPerConversation); - } - } - - public void CloseAll() - { - foreach (IConversationState conversation in allManagedConversation) - { - CloseConversation(conversation); - } - owner = null; - activeConversation = null; - allManagedConversation = null; - - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug("CloseAll LazySessionPerConversationHolder"); - } - } - - private void CloseConversation(IConversationState conversation) - { - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug($"CloseConversation: Id='{conversation.Id}'"); - } - - if (conversation.RootSessionPerConversation != null) - { - ISession tmpSession = conversation.RootSessionPerConversation; - if (conversation.Ended) - { - SessionFactoryUtils.CloseSession(tmpSession); - conversation.RootSessionPerConversation = null; - } - else - { - if (tmpSession.IsConnected) - { - IDbConnection conn = tmpSession.Disconnect(); - if (conn != null && conn.State == ConnectionState.Open) - conn.Close(); - } - } - RemoveSession(tmpSession); - } - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug("Closed LazySessionPerConversationHolder"); + log.LogDebug($"activeConversation with NO 'session-per-conversation': Id:'{activeConversation.Id}'."); } } } } -} + + /// + /// Close the current view's session and unregisters + /// from . + /// + /// The session factory that on use + /// A list of conversations which the session can be closed or disconnected + /// + /// + /// If start/resume a conversation from a + /// when exists a different + /// with open registered on + /// + /// If the holder on , is not a . + /// + /// + public void Close(ISessionFactory sessionFactory, ICollection allManagedConversation) + { + bool isDebugEnabled = log.IsEnabled(LogLevel.Debug); + if (isDebugEnabled) log.LogDebug("Trying to close SessionPerConversationScope"); + + if (IsOpen) + { + try + { + DoClose(sessionFactory, allManagedConversation, isDebugEnabled); + } + finally + { + SetOpen(false); + OpenerConversationId = null; + } + } + else + { + if (isDebugEnabled) log.LogDebug("No open conversation - doing nothing"); + } + } + + private void DoClose(ISessionFactory sessionFactory, ICollection allManagedConversation, bool isLogDebugEnabled) + { + // single session mode + if (isLogDebugEnabled) log.LogDebug("DoClose: Closing SessionPerConversationScope"); + Object holderObj = TransactionSynchronizationManager.UnbindResource(sessionFactory); + if (holderObj != null) + { + if (holderObj is LazySessionPerConversationHolder holder) + { + if (holder.Owner == this) + { + holder.CloseAll(); + } + else + { + throw new InvalidOperationException( + "Can not close session beacause 'holder owner' is not 'this'." + + " You are trying to start/resume a conversation from a" + + " IConversationManager when exists a diferent IConversationManager " + + " with open ISession registered on TransactionSynchronizationManager."); + } + } + else + { + throw new InvalidOperationException("Can not close session beacause holder, on TransactionSynchronizationManager, is not a LazySessionPerConversationHolder."); + } + } + else + { + if (isLogDebugEnabled) + { + log.LogWarning("DoClose: TransactionSynchronizationManager.UnbindResource(sessionFactory) has no SessionHolder. Should I throw error?"); + } + } + } + + private void DoOpenSession(IConversationState conversation) + { + lock (this) + { + ISession session = null; + if (conversation.RootSessionPerConversation == null) + { + //new session + session = (EntityInterceptor != null) + ? conversation.SessionFactory.WithOptions().Interceptor(EntityInterceptor).OpenSession() + : conversation.SessionFactory.OpenSession(); + conversation.RootSessionPerConversation = session; + } + else + { + //reconnect existing one. + if (conversation.DbProvider != null) + { + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug($"DoOpenSession: Conversation has a DbProvider: Id='{conversation.Id}'"); + } + + if (!conversation.RootSessionPerConversation.IsConnected) + { + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug($"DoOpenSession: Conversation is not Connected: Id='{conversation.Id}'"); + } + + DbConnection connection = (DbConnection) conversation.DbProvider.CreateConnection(); + connection.Open(); + + conversation.RootSessionPerConversation.Reconnect(connection); + } + else + { + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug($"DoOpenSession: Conversation is already Connected: Id='{conversation.Id}'"); + } + } + } + else + { + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug($"DoOpenSession: Conversation has NO DbProvider: Id='{conversation.Id}'"); + } + + conversation.RootSessionPerConversation.Reconnect(); + } + + session = conversation.RootSessionPerConversation; + } + + session.FlushMode = DefaultFlushMode; + } + } + + /// + /// This sessionHolder creates a session for the active conversation only if it is + /// needed (). + /// + /// + /// Although a NHibernateSession defers creation of db-connections until they are really + /// needed, instantiation a session is still more expensive than using LazySessionHolder. + /// + private class LazySessionPerConversationHolder : SessionHolder + { + private readonly ILogger log = LogManager.GetLogger(); + private SessionPerConversationScope owner; + + IConversationState activeConversation; + ICollection allManagedConversation; + + /// + /// Initialize a new instance. + /// + public LazySessionPerConversationHolder(SessionPerConversationScope owner, IConversationState activeConversation, ICollection allManagedConversation) + { + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug("Created LazyReconnectableSessionHolder"); + } + + this.owner = owner; + this.activeConversation = activeConversation; + this.allManagedConversation = allManagedConversation; + } + + public SessionPerConversationScope Owner => owner; + + /// + /// Create a new session on demand + /// + protected override void EnsureInitialized() + { + if (activeConversation.RootSessionPerConversation == null + || !activeConversation.RootSessionPerConversation.IsConnected) + { + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug("EnsureInitialized: 'session-per-conversation' instance requested - opening new session"); + } + + owner.DoOpenSession(activeConversation); + AddSession(activeConversation.RootSessionPerConversation); + } + } + + public void CloseAll() + { + foreach (IConversationState conversation in allManagedConversation) + { + CloseConversation(conversation); + } + + owner = null; + activeConversation = null; + allManagedConversation = null; + + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug("CloseAll LazySessionPerConversationHolder"); + } + } + + private void CloseConversation(IConversationState conversation) + { + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug($"CloseConversation: Id='{conversation.Id}'"); + } + + if (conversation.RootSessionPerConversation != null) + { + ISession tmpSession = conversation.RootSessionPerConversation; + if (conversation.Ended) + { + SessionFactoryUtils.CloseSession(tmpSession); + conversation.RootSessionPerConversation = null; + } + else + { + if (tmpSession.IsConnected) + { + IDbConnection conn = tmpSession.Disconnect(); + if (conn != null && conn.State == ConnectionState.Open) + conn.Close(); + } + } + + RemoveSession(tmpSession); + } + + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug("Closed LazySessionPerConversationHolder"); + } + } + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Web.Conversation.NHibernate5/Data/NHibernate/Support/SessionPerConversationSettings.cs b/src/Spring/Spring.Web.Conversation.NHibernate5/Data/NHibernate/Support/SessionPerConversationSettings.cs index c075f3f7..e819876f 100644 --- a/src/Spring/Spring.Web.Conversation.NHibernate5/Data/NHibernate/Support/SessionPerConversationSettings.cs +++ b/src/Spring/Spring.Web.Conversation.NHibernate5/Data/NHibernate/Support/SessionPerConversationSettings.cs @@ -20,95 +20,94 @@ using NHibernate; -namespace Spring.Data.NHibernate.Support +namespace Spring.Data.NHibernate.Support; + +/// +/// Setting for +/// +/// Hailton de Castro +[Serializable] +public class SessionPerConversationScopeSettings { /// - /// Setting for + /// Default value for property. /// - /// Hailton de Castro - [Serializable] - public class SessionPerConversationScopeSettings + public static readonly FlushMode FLUSHMODE_DEFAULT = FlushMode.Manual; + + private IInterceptor entityInterceptor; + private FlushMode defaultFlushMode; + + /// + /// Initialize a new instance of with default values. + /// + /// + /// Calling this constructor from your derived class leaves + /// uninitialized. See for more. + /// + public SessionPerConversationScopeSettings() { - /// - /// Default value for property. - /// - public static readonly FlushMode FLUSHMODE_DEFAULT = FlushMode.Manual; + this.entityInterceptor = null; + this.defaultFlushMode = FLUSHMODE_DEFAULT; + } - private IInterceptor entityInterceptor; - private FlushMode defaultFlushMode; + /// + /// Initialize a new instance of with the given values and references. + /// + /// + /// Specify the to be set on each session provided by the instance. + /// + /// + /// Specify the flushmode to be applied on each session provided by the instance. + /// + /// + /// Calling this constructor marks all properties initialized. + /// + public SessionPerConversationScopeSettings(IInterceptor entityInterceptor, FlushMode defaultFlushMode) + { + this.entityInterceptor = entityInterceptor; + this.defaultFlushMode = defaultFlushMode; + } - /// - /// Initialize a new instance of with default values. - /// - /// - /// Calling this constructor from your derived class leaves - /// uninitialized. See for more. - /// - public SessionPerConversationScopeSettings() + #region Properties + + /// + /// Gets the configured instance to be used. + /// + /// + /// + public virtual IInterceptor EntityInterceptor + { + get { - this.entityInterceptor = null; - this.defaultFlushMode = FLUSHMODE_DEFAULT; + return entityInterceptor; } - - /// - /// Initialize a new instance of with the given values and references. - /// - /// - /// Specify the to be set on each session provided by the instance. - /// - /// - /// Specify the flushmode to be applied on each session provided by the instance. - /// - /// - /// Calling this constructor marks all properties initialized. - /// - public SessionPerConversationScopeSettings(IInterceptor entityInterceptor, FlushMode defaultFlushMode) + set { - this.entityInterceptor = entityInterceptor; - this.defaultFlushMode = defaultFlushMode; - } - - #region Properties - - /// - /// Gets the configured instance to be used. - /// - /// - /// - public virtual IInterceptor EntityInterceptor - { - get - { - return entityInterceptor; - } - set - { - entityInterceptor = value; - } - } - - /// - /// Gets or Sets the flushmode to be applied on each newly created session. - /// - /// - /// This property defaults to to ensure that modifying objects outside the boundaries - /// of a transaction will not be persisted. It is recommended to not change this value but wrap any modifying operation - /// within a transaction. - /// - public FlushMode DefaultFlushMode - { - get { return defaultFlushMode; } - set { defaultFlushMode = value; } - } - - #endregion - - /// - /// Override this method to resolve an instance according to your chosen strategy. - /// - protected virtual IInterceptor ResolveEntityInterceptor() - { - return null; + entityInterceptor = value; } } + + /// + /// Gets or Sets the flushmode to be applied on each newly created session. + /// + /// + /// This property defaults to to ensure that modifying objects outside the boundaries + /// of a transaction will not be persisted. It is recommended to not change this value but wrap any modifying operation + /// within a transaction. + /// + public FlushMode DefaultFlushMode + { + get { return defaultFlushMode; } + set { defaultFlushMode = value; } + } + + #endregion + + /// + /// Override this method to resolve an instance according to your chosen strategy. + /// + protected virtual IInterceptor ResolveEntityInterceptor() + { + return null; + } } diff --git a/src/Spring/Spring.Web.Conversation.NHibernate5/Spring.Web.Conversation.NHibernate5.xml b/src/Spring/Spring.Web.Conversation.NHibernate5/Spring.Web.Conversation.NHibernate5.xml index 641f386a..eeb6300e 100644 --- a/src/Spring/Spring.Web.Conversation.NHibernate5/Spring.Web.Conversation.NHibernate5.xml +++ b/src/Spring/Spring.Web.Conversation.NHibernate5/Spring.Web.Conversation.NHibernate5.xml @@ -6,867 +6,989 @@ - Based on - for support of 'session-per-conversation' pattern. + Based on + + for support of 'session-per-conversation' pattern. Hailton de Castro - The logging instance. - + The logging instance. +
- Initializes a new instance of the class. - Uses default values for + Initializes a new instance of the + + class. + Uses default values for + - Initializes a new instance of the class. + Initializes a new instance of the + + class. - Specify the to be set on each session provided by this instance. - Specify the flushmode to be applied on each session provided by this instance. + Specify the + + to be set on each session provided by this + + instance. + + Specify the flushmode to be applied on each session provided by this + + instance. - Initializes a new instance of the class. + Initializes a new instance of the + + class. - An instance holding the scope configuration + An + + instance holding the scope configuration + - Gets the flushmode to be applied on each newly created session. + Gets the flushmode to be applied on each newly created session. - This property defaults to to ensure that modifying objects outside the boundaries - of a transaction will not be persisted. It is recommended to not change this value but wrap any modifying operation - within a transaction. + This property defaults to + + to ensure that modifying objects outside the boundaries + of a transaction will not be persisted. It is recommended to not change this value but wrap any + modifying operation + within a transaction. - Get the configured EntityInterceptor + Get the configured EntityInterceptor - Id for conversation that open the Session. + Id for conversation that open the Session. - Gets a flag, whether this scope is in "open" state on the current logical thread. + Gets a flag, whether this scope is in "open" state on the current logical thread. - Sets a flag, whether this scope is in "open" state on the current logical thread. + Sets a flag, whether this scope is in "open" state on the current logical thread. - NOOP. + NOOP. - Open a new session or reconect the - in . - Participating in an existing session registed with - is not alowed. + Open a new session or reconect the + + in. + Participating in an existing session registed with + + is not alowed. - - If there is another conversation with a with opened - . - If attempting to participate in an existing NHibernate - managed by . - - + + If there is another conversation with a + + with opened + . + + If attempting to participate in an existing NHibernate + + managed by. + + - Close the current view's session and unregisters - from . + Close the current view's session and unregisters + from. - The session factory that on use - A list of conversations which the session can be closed or disconnected + The session factory that + + on + + use + + A list of conversations which the session can be closed or + disconnected + - - If start/resume a conversation from a - when exists a different - with open registered on - - If the holder on , is not a . - + + If start/resume a conversation from a + + when exists a different + + with open + + registered on + + + If the holder on, + is not a + . + + - This sessionHolder creates a session for the active conversation only if it is - needed (). + This sessionHolder creates a session for the active conversation only if it is + needed (). - Although a NHibernateSession defers creation of db-connections until they are really - needed, instantiation a session is still more expensive than using LazySessionHolder. + Although a NHibernateSession defers creation of db-connections until they are really + needed, instantiation a session is still more expensive than using LazySessionHolder. - Initialize a new instance. + Initialize a new instance. - Create a new session on demand + Create a new session on demand - Setting for + Setting for + Hailton de Castro - Default value for property. + Default value for + + property. - Initialize a new instance of with default values. + Initialize a new instance of + + with default values. - Calling this constructor from your derived class leaves - uninitialized. See for more. + Calling this constructor from your derived class leaves + + uninitialized. See + + for more. - Initialize a new instance of with the given values and references. + Initialize a new instance of + + with the given values and references. - Specify the to be set on each session provided by the instance. + Specify the + + to be set on each session provided by the + + instance. - Specify the flushmode to be applied on each session provided by the instance. + Specify the flushmode to be applied on each session provided by the + + instance. - Calling this constructor marks all properties initialized. + Calling this constructor marks all properties initialized. - Gets the configured instance to be used. + Gets the configured + + instance to be used. - Gets or Sets the flushmode to be applied on each newly created session. + Gets or Sets the flushmode to be applied on each newly created session. - This property defaults to to ensure that modifying objects outside the boundaries - of a transaction will not be persisted. It is recommended to not change this value but wrap any modifying operation - within a transaction. + This property defaults to + + to ensure that modifying objects outside the boundaries + of a transaction will not be persisted. It is recommended to not change this value but wrap any + modifying operation + within a transaction. - Override this method to resolve an instance according to your chosen strategy. + Override this method to resolve an + + instance according to your chosen strategy. - HttpModule for ending Conversations with Timeout exceeded. + HttpModule for ending Conversations with Timeout exceeded. Hailton de Castro - The Names of the s in the + The Names of thes in the + - Add PostRequestHandlerExecute event to clear conversations with timeout exceeded. + Add PostRequestHandlerExecute event to clear conversations with timeout exceeded. - Disposes of the resources (other than memory) used by the module that implements . + Disposes of the resources (other than memory) used by the module that implements. - Handles the Unload event of the page control. + Handles the Unload event of the page control. The source of the event. - The instance containing the event data. + The + + instance containing the event data. + - Necessary for Redirect or Abort for any reason. + Necessary for Redirect or Abort for any reason. - Sets the that this - object runs in. + Sets the + + that this + object runs in. -

- Used to obtain the instances of -

-

- Invoked after population of normal object properties but before an - init callback such as - 's - - or a custom init-method. Invoked after the setting of any - 's - - property. -

+

+ Used to obtain the instances of + +

+

+ Invoked after population of normal object properties but before an + init callback such as + 's + + or a custom init-method. Invoked after the setting of any + 's + + property. +

- In the case of application context initialization errors. + In the case of application context initialization errors. - If thrown by any application context methods. + If thrown by any application context methods. - +
- manager for Conversations. + manager for Conversations. Hailton de Castro - Returns the conversation if it is still alive, otherwise it returns null. + Returns the conversation if it is still alive, otherwise it returns null. - Ends all conversations with the timeout exceeded. + Ends all conversations with the timeout exceeded. - Close IDbConnections for that - use 'session-per-conversation'. It calls - in all conversations. + Close IDbConnections for + + that + use 'session-per-conversation'. It calls + + in all conversations. - Release the ended conversations And removes them. - If the conversation supports 'session-per-conversation', also close the session. + Release the ended conversations And removes them. + If the conversation supports 'session-per-conversation', also close the session. - Add conversation. If is null - it resolves to 'this'. + Add conversation. If + + is null + it resolves to 'this'. - If already has another manager. + If + + already has another manager. - Makes the 'root conversation' of - the current active conversation and open/reopen the - if - the conversation supports 'session-per-conversation'. Close all - the connection for all session before. - If is true will end all - paused conversations. + Makes the 'root conversation' of + + the current active conversation and open/reopen the + + if + the conversation supports 'session-per-conversation'. Close all + the connection for all session before. + If + + is true will end all + paused conversations. - Returns the active conversation if exists, otherwise returns null. - It depends on + Returns the active conversation if exists, otherwise returns null. + It depends on + - If this is non-null run pattern 'session-per-conversation'. - Must be the same SessionFactory of the managed conversations. - + If this is non-null run pattern 'session-per-conversation'. + Must be the same SessionFactory of the managed conversations. + - Ends the "paused conversations" in call to . - Important: Unexpected behavior may occur if there are nested conversations, - as in only the current conversation and its parents - are started, the 'conversations children' remain paused, so these will be ended. - Defaul value: false. + Ends the "paused conversations" in call to. + Important: Unexpected behavior may occur if there are nested conversations, + as in + + only the current conversation and its parents + are started, the 'conversations children' remain paused, so these will be ended. + Defaul value: false. - When it is true, "start/resume a conversation" will cause the other to be - ended and cleaned up. - - This is useful to avoid memory leak where there are many conversations. - This leak can be very considerable, as the conversation may keep a "NHibernate session" - that can contain many objects in its cache from the database queries. - + When it is true, "start/resume a conversation" will cause the other to be + ended and cleaned up. + + This is useful to avoid memory leak where there are many conversations. + This leak can be very considerable, as the conversation may keep a "NHibernate session" + that can contain many objects in its cache from the database queries. + - Port to conversation. If the object is not found in the current - conversation, will be tried on the parent if the parent is - not null. + Port to conversation. If the object is not found in the current + conversation, will be tried on the parent if the parent is + not null. - If is different from spring name for this instance. + If + + is different from spring name for this instance. Hailton de Castro - Conversation id. + Conversation id. - Starts or resumes the conversation and the . - If is not null, so - is called to - Raise SessionHolder for make the reconnection. - - Make return false. - - Update the . - + Starts or resumes the conversation and the. + If + + is not null, so + + is called to + Raise SessionHolder for make the reconnection. + + Make + + return false. + + Update the. + - - If this conversation is ended. - - If is not null and - different from - - - + + If this conversation is ended. + + If + + is not null and + + different from + + + - Return true until is called. + Return true until + + is called. - Ends the conversation. End each of the 'inner conversations' in - . Returns false if the - conversation and all of - has already been ended. + Ends the conversation. End each of the 'inner conversations' in + . Returns false if the + conversation and all + + of + + has already been ended. - - If . - Session["spring.objects"] - is null. - - The 'spring session scopes' are not located in the key - 'spring.objects' of HttpSessionState. - - + + If. + Session["spring.objects"] + is null. + + The 'spring session scopes' are not located in the key + 'spring.objects' of HttpSessionState. + + - Return true if this conversation is ended. + Return true if this conversation is ended. - Inner conversation. After added if the - is null it will resolve to 'this'. + Inner conversation. After added if the + + is null it will resolve to 'this'. - at - , - , - - if Circular Dependency is detected. + at + , + , + + if Circular Dependency is detected. + - Conversation parent. + Conversation parent. - - If this conversation already has a different parent. - - If this Conversation is not new. - - If Circular Dependency is detected. - - The Parent conversation is not new. - - + + If this conversation already has a different parent. + + If this Conversation is not new. + + If Circular Dependency is detected. + + The Parent conversation is not new. + + - TimeOut for the conversation in milliseconds. - If 0 TimeOut will be ignored. + TimeOut for the conversation in milliseconds. + If 0 TimeOut will be ignored. - Last acces for a value into this Conversation or Inner Conversation. - Reset to DateTime.Now each time - is called. + Last acces for a value into this Conversation or Inner Conversation. + Reset to DateTime.Now each time + + is called. - Conversation Manager. When this is setted if - - returns null so AddConversation is called. + Conversation Manager. When this is setted if + + returns null so AddConversation is called. - that is stored in the root conversation. - - - must support 'session-per-conversation'. - + + + that is stored in the root conversation. + + + + must support 'session-per-conversation'. + - If this is non-null run pattern 'session-per-conversation'. - It also depends on and . - must support ConversationManager. - + If this is non-null run pattern 'session-per-conversation'. + It also depends on + + and. + + must support ConversationManager. + - If this is non-null run pattern 'session-per-conversation'. - It also depends on and . - must support ConversationManager. - + If this is non-null run pattern 'session-per-conversation'. + It also depends on + + and. + + must support ConversationManager. + - Indicates that the conversation is paused. + Indicates that the conversation is paused. - Starts or resumes the conversation and each 'inner conversation' in - . - It is not about 'Session-per-conversation' because it is done by - . + Starts or resumes the conversation and each 'inner conversation' in + . + It is not about 'Session-per-conversation' because it is done by + . - List that make validation for Circular Dependency for + List that make validation for Circular Dependency for + Hailton de Castro - Contructor. + Contructor. - The that owns this . + The + + that owns this. + - Common Helper to be run before insert. + Common Helper to be run before insert. - Common Helper to be run after insert. + Common Helper to be run after insert. - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - This was made to stay under session scope. + This was made to stay under session scope. Hailton de Castro - Semaphore to synchronize writes to the dictionary. + Semaphore to synchronize writes to the dictionary. - + - + - + - + - + - + - + - "SessionFactory" name in the current context. - This approach is required to support serialization. + "SessionFactory" name in the current context. + This approach is required to support serialization. - + - + - Ends all conversations and Closes all their Session. + Ends all conversations and Closes all their Session. - Remove conversation. + Remove conversation. - Returns the current context. Supports serialization and deserialization. + Returns the current context. Supports serialization and deserialization. - Implementation of conversation in the infrastructure of Spring. - It avoid Circular Dependencies. + Implementation of conversation in the infrastructure of Spring. + It avoid Circular Dependencies. Hailton de Castro - Default message for "CONVERSATION ALREADY HAS A PARENT" error. + Default message for "CONVERSATION ALREADY HAS A PARENT" error. - + - + - + - Default 180000. + Default 180000. - + - + - . + . - + - + - + - "SessionFactory" name in the current context. - This approach is required to support serialization. + "SessionFactory" name in the current context. + This approach is required to support serialization. - + - "DbProvider" name in the current context. - This approach is required to support serialization. + "DbProvider" name in the current context. + This approach is required to support serialization. - + - + - + - + - . It is used to valddate + . It is used to valddate + - + - + - + - + - + @@ -874,79 +996,79 @@ - + - + - + - + - + - + - + - + - + - + - + - A String representation from conversation. + A String representation from conversation. - Returns the current context. Supports serialization and deserialization. + Returns the current context. Supports serialization and deserialization. diff --git a/src/Spring/Spring.Web.Conversation.NHibernate5/Web/Conversation/HttpModule/ConversationModule.cs b/src/Spring/Spring.Web.Conversation.NHibernate5/Web/Conversation/HttpModule/ConversationModule.cs index d2e8579a..c756c036 100644 --- a/src/Spring/Spring.Web.Conversation.NHibernate5/Web/Conversation/HttpModule/ConversationModule.cs +++ b/src/Spring/Spring.Web.Conversation.NHibernate5/Web/Conversation/HttpModule/ConversationModule.cs @@ -23,146 +23,144 @@ using System.Web.UI; using Microsoft.Extensions.Logging; using Spring.Context; -namespace Spring.Web.Conversation.HttpModule +namespace Spring.Web.Conversation.HttpModule; + +/// +/// HttpModule for ending Conversations with Timeout exceeded. +/// +/// Hailton de Castro +public class ConversationModule : IHttpModule, IApplicationContextAware { + private static readonly ILogger LOG = LogManager.GetLogger(); + + private IList conversationManagerName; + /// - /// HttpModule for ending Conversations with Timeout exceeded. + /// The Names of the s in the /// - /// Hailton de Castro - public class ConversationModule : IHttpModule, IApplicationContextAware + public IList ConversationManagerNameList { - private static readonly ILogger LOG = LogManager.GetLogger(); + get { return conversationManagerName; } + set { conversationManagerName = value; } + } - private IList conversationManagerName; + #region IHttpModule Members - /// - /// The Names of the s in the - /// - public IList ConversationManagerNameList + /// + /// Add PostRequestHandlerExecute event to clear conversations with timeout exceeded. + /// + /// + public void Init(HttpApplication context) + { + context.PreRequestHandlerExecute += context_PreRequestHandlerExecute; + context.PostRequestHandlerExecute += context_PostRequestHandlerExecute; + context.EndRequest += context_EndRequest; + } + + /// + /// Disposes of the resources (other than memory) used by the module that implements . + /// + public void Dispose() + { + //noop + } + + void context_PreRequestHandlerExecute(object sender, EventArgs e) + { + if (HttpContext.Current.Handler is Page) { - get { return conversationManagerName; } - set { conversationManagerName = value; } - } + Page page = (Page) HttpContext.Current.Handler; + page.Unload += page_Unload; - #region IHttpModule Members - - /// - /// Add PostRequestHandlerExecute event to clear conversations with timeout exceeded. - /// - /// - public void Init(HttpApplication context) - { - context.PreRequestHandlerExecute += context_PreRequestHandlerExecute; - context.PostRequestHandlerExecute += context_PostRequestHandlerExecute; - context.EndRequest += context_EndRequest; - } - - - /// - /// Disposes of the resources (other than memory) used by the module that implements . - /// - public void Dispose() - { - //noop - } - - void context_PreRequestHandlerExecute(object sender, EventArgs e) - { - if (HttpContext.Current.Handler is Page) - { - Page page = (Page)HttpContext.Current.Handler; - page.Unload += page_Unload; - - if (HttpContext.Current.Session != null) - { - if (LOG.IsEnabled(LogLevel.Debug)) LOG.LogDebug("context_PreRequestHandlerExecute: Processing HttpContext.Current.Session"); - foreach (String convMngName in this.ConversationManagerNameList) - { - if (LOG.IsEnabled(LogLevel.Debug)) LOG.LogDebug(string.Format("context_PreRequestHandlerExecute: Processing ConversationManager: {0}", convMngName)); - IConversationManager convMng = (IConversationManager)this.applicationContext.GetObject(convMngName); - convMng.EndOnTimeOut(); - convMng.FreeEnded(); - } - } - else - { - if (LOG.IsEnabled(LogLevel.Debug)) LOG.LogDebug("context_PreRequestHandlerExecute: no HttpContext.Current.Session found."); - } - } - } - - - /// - /// Handles the Unload event of the page control. - /// - /// The source of the event. - /// The instance containing the event data. - /// - /// Necessary for Redirect or Abort for any reason. - /// - void page_Unload(object sender, EventArgs e) - { - if (LOG.IsEnabled(LogLevel.Debug)) LOG.LogDebug("page_Unload HttpContext.Current.Session is null: " + (HttpContext.Current.Session == null)); - foreach (String convMngName in this.ConversationManagerNameList) - { - if (LOG.IsEnabled(LogLevel.Debug)) LOG.LogDebug(string.Format("page_Unload: Processing ConversationManager: {0}", convMngName)); - IConversationManager convMng = (IConversationManager)this.applicationContext.GetObject(convMngName); - convMng.EndOnTimeOut(); - convMng.FreeEnded(); - convMng.PauseConversations(); - } - } - - void context_EndRequest(object sender, EventArgs e) - { - if (LOG.IsEnabled(LogLevel.Debug)) LOG.LogDebug("context_EndRequest HttpContext.Current.Session is null: " + (HttpContext.Current.Session == null)); - } - - void context_PostRequestHandlerExecute(object sender, EventArgs e) - { - if (LOG.IsEnabled(LogLevel.Debug)) LOG.LogDebug("context_PostRequestHandlerExecute HttpContext.Current.Session is null: " + (HttpContext.Current.Session == null)); if (HttpContext.Current.Session != null) { + if (LOG.IsEnabled(LogLevel.Debug)) LOG.LogDebug("context_PreRequestHandlerExecute: Processing HttpContext.Current.Session"); + foreach (String convMngName in this.ConversationManagerNameList) + { + if (LOG.IsEnabled(LogLevel.Debug)) LOG.LogDebug(string.Format("context_PreRequestHandlerExecute: Processing ConversationManager: {0}", convMngName)); + IConversationManager convMng = (IConversationManager) this.applicationContext.GetObject(convMngName); + convMng.EndOnTimeOut(); + convMng.FreeEnded(); + } + } + else + { + if (LOG.IsEnabled(LogLevel.Debug)) LOG.LogDebug("context_PreRequestHandlerExecute: no HttpContext.Current.Session found."); } } - - #endregion - - #region IApplicationContextAware Members - private IApplicationContext applicationContext; - - /// - /// Sets the that this - /// object runs in. - /// - /// - /// - ///

- /// Used to obtain the instances of - ///

- ///

- /// Invoked after population of normal object properties but before an - /// init callback such as - /// 's - /// - /// or a custom init-method. Invoked after the setting of any - /// 's - /// - /// property. - ///

- ///
- /// - /// In the case of application context initialization errors. - /// - /// - /// If thrown by any application context methods. - /// - /// - public IApplicationContext ApplicationContext - { - set { this.applicationContext = value; } - } - - #endregion } + + /// + /// Handles the Unload event of the page control. + /// + /// The source of the event. + /// The instance containing the event data. + /// + /// Necessary for Redirect or Abort for any reason. + /// + void page_Unload(object sender, EventArgs e) + { + if (LOG.IsEnabled(LogLevel.Debug)) LOG.LogDebug("page_Unload HttpContext.Current.Session is null: " + (HttpContext.Current.Session == null)); + foreach (String convMngName in this.ConversationManagerNameList) + { + if (LOG.IsEnabled(LogLevel.Debug)) LOG.LogDebug(string.Format("page_Unload: Processing ConversationManager: {0}", convMngName)); + IConversationManager convMng = (IConversationManager) this.applicationContext.GetObject(convMngName); + convMng.EndOnTimeOut(); + convMng.FreeEnded(); + convMng.PauseConversations(); + } + } + + void context_EndRequest(object sender, EventArgs e) + { + if (LOG.IsEnabled(LogLevel.Debug)) LOG.LogDebug("context_EndRequest HttpContext.Current.Session is null: " + (HttpContext.Current.Session == null)); + } + + void context_PostRequestHandlerExecute(object sender, EventArgs e) + { + if (LOG.IsEnabled(LogLevel.Debug)) LOG.LogDebug("context_PostRequestHandlerExecute HttpContext.Current.Session is null: " + (HttpContext.Current.Session == null)); + if (HttpContext.Current.Session != null) + { + } + } + + #endregion + + #region IApplicationContextAware Members + + private IApplicationContext applicationContext; + + /// + /// Sets the that this + /// object runs in. + /// + /// + /// + ///

+ /// Used to obtain the instances of + ///

+ ///

+ /// Invoked after population of normal object properties but before an + /// init callback such as + /// 's + /// + /// or a custom init-method. Invoked after the setting of any + /// 's + /// + /// property. + ///

+ ///
+ /// + /// In the case of application context initialization errors. + /// + /// + /// If thrown by any application context methods. + /// + /// + public IApplicationContext ApplicationContext + { + set { this.applicationContext = value; } + } + + #endregion } diff --git a/src/Spring/Spring.Web.Conversation.NHibernate5/Web/Conversation/IConversationManager.cs b/src/Spring/Spring.Web.Conversation.NHibernate5/Web/Conversation/IConversationManager.cs index 743585e2..3bfeedd2 100644 --- a/src/Spring/Spring.Web.Conversation.NHibernate5/Web/Conversation/IConversationManager.cs +++ b/src/Spring/Spring.Web.Conversation.NHibernate5/Web/Conversation/IConversationManager.cs @@ -20,90 +20,89 @@ using NHibernate; -namespace Spring.Web.Conversation +namespace Spring.Web.Conversation; + +/// +/// manager for Conversations. +/// +/// Hailton de Castro +public interface IConversationManager { /// - /// manager for Conversations. + /// Returns the conversation if it is still alive, otherwise it returns null. /// - /// Hailton de Castro - public interface IConversationManager - { - /// - /// Returns the conversation if it is still alive, otherwise it returns null. - /// - /// - /// - IConversationState GetConversationById(String id); + /// + /// + IConversationState GetConversationById(String id); - /// - /// Ends all conversations with the timeout exceeded. - /// - void EndOnTimeOut(); + /// + /// Ends all conversations with the timeout exceeded. + /// + void EndOnTimeOut(); - /// - /// Close IDbConnections for that - /// use 'session-per-conversation'. It calls - /// in all conversations. - /// - void PauseConversations(); + /// + /// Close IDbConnections for that + /// use 'session-per-conversation'. It calls + /// in all conversations. + /// + void PauseConversations(); - /// - /// Release the ended conversations And removes them. - /// If the conversation supports 'session-per-conversation', also close the session. - /// - void FreeEnded(); + /// + /// Release the ended conversations And removes them. + /// If the conversation supports 'session-per-conversation', also close the session. + /// + void FreeEnded(); - /// - /// Add conversation. If is null - /// it resolves to 'this'. - /// - /// - /// - /// If already has another manager. - /// - void AddConversation(IConversationState conversation); + /// + /// Add conversation. If is null + /// it resolves to 'this'. + /// + /// + /// + /// If already has another manager. + /// + void AddConversation(IConversationState conversation); - /// - /// Makes the 'root conversation' of - /// the current active conversation and open/reopen the - /// if - /// the conversation supports 'session-per-conversation'. Close all - /// the connection for all session before. - /// If is true will end all - /// paused conversations. - /// - void SetActiveConversation(IConversationState conversation); + /// + /// Makes the 'root conversation' of + /// the current active conversation and open/reopen the + /// if + /// the conversation supports 'session-per-conversation'. Close all + /// the connection for all session before. + /// If is true will end all + /// paused conversations. + /// + void SetActiveConversation(IConversationState conversation); - /// - /// Returns the active conversation if exists, otherwise returns null. - /// It depends on - /// - /// - IConversationState ActiveConversation{ get; } + /// + /// Returns the active conversation if exists, otherwise returns null. + /// It depends on + /// + /// + IConversationState ActiveConversation { get; } - /// - /// If this is non-null run pattern 'session-per-conversation'. - /// Must be the same SessionFactory of the managed conversations. - /// - /// - ISessionFactory SessionFactory { get; } + /// + /// If this is non-null run pattern 'session-per-conversation'. + /// Must be the same SessionFactory of the managed conversations. + /// + /// + ISessionFactory SessionFactory { get; } - /// - /// Ends the "paused conversations" in call to . - /// Important: Unexpected behavior may occur if there are nested conversations, - /// as in only the current conversation and its parents - /// are started, the 'conversations children' remain paused, so these will be ended. - /// Defaul value: false. - /// - /// - /// When it is true, "start/resume a conversation" will cause the other to be - /// ended and cleaned up. - /// - /// This is useful to avoid memory leak where there are many conversations. - /// This leak can be very considerable, as the conversation may keep a "NHibernate session" - /// that can contain many objects in its cache from the database queries. - /// - /// - bool EndPaused { get; set; } - } -} + /// + /// Ends the "paused conversations" in call to . + /// Important: Unexpected behavior may occur if there are nested conversations, + /// as in only the current conversation and its parents + /// are started, the 'conversations children' remain paused, so these will be ended. + /// Defaul value: false. + /// + /// + /// When it is true, "start/resume a conversation" will cause the other to be + /// ended and cleaned up. + /// + /// This is useful to avoid memory leak where there are many conversations. + /// This leak can be very considerable, as the conversation may keep a "NHibernate session" + /// that can contain many objects in its cache from the database queries. + /// + /// + bool EndPaused { get; set; } +} \ No newline at end of file diff --git a/src/Spring/Spring.Web.Conversation.NHibernate5/Web/Conversation/IConversationState.cs b/src/Spring/Spring.Web.Conversation.NHibernate5/Web/Conversation/IConversationState.cs index b773d2d4..21c8c35d 100644 --- a/src/Spring/Spring.Web.Conversation.NHibernate5/Web/Conversation/IConversationState.cs +++ b/src/Spring/Spring.Web.Conversation.NHibernate5/Web/Conversation/IConversationState.cs @@ -21,161 +21,160 @@ using NHibernate; using Spring.Data.Common; -namespace Spring.Web.Conversation +namespace Spring.Web.Conversation; + +/// +/// Port to conversation. If the object is not found in the current +/// conversation, will be tried on the parent if the parent is +/// not null. +/// +/// +/// If is different from spring name for this instance. +/// +/// Hailton de Castro +public interface IConversationState : IDictionary { /// - /// Port to conversation. If the object is not found in the current - /// conversation, will be tried on the parent if the parent is - /// not null. + /// Conversation id. + /// + String Id { get; set; } + + /// + /// Starts or resumes the conversation and the . + /// If is not null, so + /// is called to + /// Raise SessionHolder for make the reconnection. + /// + /// Make return false. + /// + /// Update the . + /// /// /// - /// If is different from spring name for this instance. + /// + /// If this conversation is ended. + /// + /// If is not null and + /// different from + /// + /// + /// /// - /// Hailton de Castro - public interface IConversationState: IDictionary - { - /// - /// Conversation id. - /// - String Id { get; set; } + void StartResumeConversation(); - /// - /// Starts or resumes the conversation and the . - /// If is not null, so - /// is called to - /// Raise SessionHolder for make the reconnection. - /// - /// Make return false. - /// - /// Update the . - /// - /// - /// - /// - /// If this conversation is ended. - /// - /// If is not null and - /// different from - /// - /// - /// - /// - void StartResumeConversation(); + /// + /// Return true until is called. + /// + bool IsNew { get; } - /// - /// Return true until is called. - /// - bool IsNew { get; } + /// + /// Ends the conversation. End each of the 'inner conversations' in + /// . Returns false if the + /// conversation and all of + /// has already been ended. + /// + /// + /// + /// + /// If . + /// Session["spring.objects"] + /// is null. + /// + /// The 'spring session scopes' are not located in the key + /// 'spring.objects' of HttpSessionState. + /// + /// + /// + void EndConversation(); - /// - /// Ends the conversation. End each of the 'inner conversations' in - /// . Returns false if the - /// conversation and all of - /// has already been ended. - /// - /// - /// - /// - /// If . - /// Session["spring.objects"] - /// is null. - /// - /// The 'spring session scopes' are not located in the key - /// 'spring.objects' of HttpSessionState. - /// - /// - /// - void EndConversation(); + /// + /// Return true if this conversation is ended. + /// + bool Ended { get; } - /// - /// Return true if this conversation is ended. - /// - bool Ended { get; } + /// + /// Inner conversation. After added if the + /// is null it will resolve to 'this'. + /// + /// at + /// , + /// , + /// + /// if Circular Dependency is detected. + IList InnerConversations { get; } - /// - /// Inner conversation. After added if the - /// is null it will resolve to 'this'. - /// - /// at - /// , - /// , - /// - /// if Circular Dependency is detected. - IList InnerConversations { get; } + /// + /// Conversation parent. + /// + /// + /// + /// If this conversation already has a different parent. + /// + /// If this Conversation is not new. + /// + /// If Circular Dependency is detected. + /// + /// The Parent conversation is not new. + /// + /// + /// + IConversationState ParentConversation { get; set; } - /// - /// Conversation parent. - /// - /// - /// - /// If this conversation already has a different parent. - /// - /// If this Conversation is not new. - /// - /// If Circular Dependency is detected. - /// - /// The Parent conversation is not new. - /// - /// - /// - IConversationState ParentConversation { get; set;} + /// + /// TimeOut for the conversation in milliseconds. + /// If 0 TimeOut will be ignored. + /// + Int32 TimeOut { get; set; } - /// - /// TimeOut for the conversation in milliseconds. - /// If 0 TimeOut will be ignored. - /// - Int32 TimeOut { get; set; } + /// + /// Last acces for a value into this Conversation or Inner Conversation. + /// Reset to DateTime.Now each time + /// is called. + /// + DateTime LastAccess { get; set; } - /// - /// Last acces for a value into this Conversation or Inner Conversation. - /// Reset to DateTime.Now each time - /// is called. - /// - DateTime LastAccess { get; set; } + /// + /// Conversation Manager. When this is setted if + /// + /// returns null so AddConversation is called. + /// + IConversationManager ConversationManager { get; set; } - /// - /// Conversation Manager. When this is setted if - /// - /// returns null so AddConversation is called. - /// - IConversationManager ConversationManager { get; set; } + /// + /// that is stored in the root conversation. + /// + /// + /// must support 'session-per-conversation'. + /// + /// + ISession RootSessionPerConversation { get; set; } - /// - /// that is stored in the root conversation. - /// - /// - /// must support 'session-per-conversation'. - /// - /// - ISession RootSessionPerConversation { get; set; } + /// + /// If this is non-null run pattern 'session-per-conversation'. + /// It also depends on and . + /// must support ConversationManager. + /// + /// + ISessionFactory SessionFactory { get; } - /// - /// If this is non-null run pattern 'session-per-conversation'. - /// It also depends on and . - /// must support ConversationManager. - /// - /// - ISessionFactory SessionFactory { get; } + /// + /// If this is non-null run pattern 'session-per-conversation'. + /// It also depends on and . + /// must support ConversationManager. + /// + /// + IDbProvider DbProvider { get; } - /// - /// If this is non-null run pattern 'session-per-conversation'. - /// It also depends on and . - /// must support ConversationManager. - /// - /// - IDbProvider DbProvider { get; } + /// + /// Indicates that the conversation is paused. + /// + bool IsPaused { get; } - /// - /// Indicates that the conversation is paused. - /// - bool IsPaused { get; } - - /// - /// Starts or resumes the conversation and each 'inner conversation' in - /// . - /// It is not about 'Session-per-conversation' because it is done by - /// . - /// - void PauseConversation(); - } + /// + /// Starts or resumes the conversation and each 'inner conversation' in + /// . + /// It is not about 'Session-per-conversation' because it is done by + /// . + /// + void PauseConversation(); } diff --git a/src/Spring/Spring.Web.Conversation.NHibernate5/Web/Conversation/InnerConversationList.cs b/src/Spring/Spring.Web.Conversation.NHibernate5/Web/Conversation/InnerConversationList.cs index ce4d39a8..bbbbf62d 100644 --- a/src/Spring/Spring.Web.Conversation.NHibernate5/Web/Conversation/InnerConversationList.cs +++ b/src/Spring/Spring.Web.Conversation.NHibernate5/Web/Conversation/InnerConversationList.cs @@ -22,353 +22,357 @@ using System.Collections; using Microsoft.Extensions.Logging; using Spring.Collections.Generic; -namespace Spring.Web.Conversation +namespace Spring.Web.Conversation; + +/// +/// List that make validation for Circular Dependency for +/// +/// Hailton de Castro +[Serializable] +public class InnerConversationList : IList, IList { + private static readonly ILogger LOG = LogManager.GetLogger(); + + private IConversationState conversationOwner; + + private IList innerList = new List(); + /// - /// List that make validation for Circular Dependency for + /// Contructor. /// - /// Hailton de Castro - [Serializable] - public class InnerConversationList: IList, IList + /// The that owns this . + public InnerConversationList(IConversationState conversationOwner) { - private static readonly ILogger LOG = LogManager.GetLogger(); - - private IConversationState conversationOwner; - - private IList innerList = new List(); - - /// - /// Contructor. - /// - /// The that owns this . - public InnerConversationList(IConversationState conversationOwner) + if (conversationOwner == null) { - if (conversationOwner == null) - { - String message = "'conversationOwner' can not be null"; + String message = "'conversationOwner' can not be null"; - LOG.LogError(message); - throw new InvalidOperationException(message); - } - if (LOG.IsEnabled(LogLevel.Debug)) LOG.LogError(String.Format("Creating InnerConversationList for '{0}'", conversationOwner.Id)); - this.conversationOwner = conversationOwner; + LOG.LogError(message); + throw new InvalidOperationException(message); } - /// - /// Common Helper to be run before insert. - /// - /// - private void PreAddProcessor(IConversationState itemAdded) - { - if (LOG.IsEnabled(LogLevel.Debug)) LOG.LogDebug(String.Format("PreAddProcessor: added={0} into {1}", itemAdded, this.conversationOwner)); - this.ValidateCircularDependency(itemAdded); - if (itemAdded.ParentConversation != null && itemAdded.ParentConversation != this.conversationOwner) - { - throw new InvalidOperationException( - String.Format(WebConversationSpringState.MSG_CONVERSATION_ALREADY_HAS_PARENT, itemAdded.ParentConversation.Id, this.conversationOwner.Id)); - } - } - - /// - /// Common Helper to be run after insert. - /// - private void PostAddProcessor(IConversationState itemAdded) - { - if (LOG.IsEnabled(LogLevel.Debug)) LOG.LogDebug(String.Format("PostAddProcessor: added={0} into {1}", itemAdded, this.conversationOwner)); - if (itemAdded.ParentConversation == null) - { - itemAdded.ParentConversation = this.conversationOwner; - } - } - - private void ValidateCircularDependency(IConversationState itemAdded) - { - if (LOG.IsEnabled(LogLevel.Debug)) LOG.LogDebug(String.Format("Validating Circular Dependency: added={0} into {1}", itemAdded, this.conversationOwner)); - - ICollection visitedColl = new HashedSet(); - visitedColl.Add(conversationOwner); - - IConversationState parentAncestor = this.conversationOwner; - String path = this.conversationOwner.Id; - //string conectorPath = ""; - - this.ValidateCircularDependencyRecursive(itemAdded, visitedColl, path + "->" + itemAdded.Id); - } - - private void ValidateCircularDependencyRecursive(IConversationState currentConv, ICollection visitedColl, String path) - { - foreach (IConversationState convItem in currentConv.InnerConversations) - { - if (visitedColl.Contains(convItem)) - { - String exMsgStr = - "ConversationState Circular Dependency detected: " + - path + "->" + convItem.Id; - - LOG.LogError(exMsgStr); - throw new InvalidOperationException(exMsgStr); - } - - visitedColl.Add(convItem); - - this.ValidateCircularDependencyRecursive(convItem, visitedColl, path + "->" + convItem.Id); - } - } - - #region IList Members - - /// - /// - /// - /// - /// - public int IndexOf(IConversationState item) - { - return this.innerList.IndexOf(item); - } - - /// - /// - /// - /// - /// - public void Insert(int index, IConversationState item) - { - this.PreAddProcessor(item); - this.innerList.Insert(index, item); - this.PostAddProcessor(item); - } - - /// - /// - /// - /// - public void RemoveAt(int index) - { - this.innerList.RemoveAt(index); - } - - /// - /// - /// - /// - /// - public IConversationState this[int index] - { - get - { - return this.innerList[index]; - } - set - { - this.PreAddProcessor(value); - this.innerList[index] = value; - this.PostAddProcessor(value); - } - } - - #endregion - - #region ICollection Members - /// - /// - /// - /// - public void Add(IConversationState item) - { - this.PreAddProcessor(item); - this.innerList.Add(item); - this.PostAddProcessor(item); - } - - /// - /// - /// - public void Clear() - { - this.innerList.Clear(); - } - - /// - /// - /// - /// - /// - public bool Contains(IConversationState item) - { - return this.innerList.Contains(item); - } - - /// - /// - /// - /// - /// - public void CopyTo(IConversationState[] array, int arrayIndex) - { - this.innerList.CopyTo(array, arrayIndex); - } - - /// - /// - /// - public int Count - { - get { return this.innerList.Count; } - } - - /// - /// - /// - public bool IsReadOnly - { - get { return this.innerList.IsReadOnly; } - } - - /// - /// - /// - /// - /// - public bool Remove(IConversationState item) - { - return this.innerList.Remove(item); - } - - #endregion - - #region IEnumerable Members - /// - /// - /// - /// - public IEnumerator GetEnumerator() - { - return this.innerList.GetEnumerator(); - } - - #endregion - - #region IEnumerable Members - - /// - /// - /// - /// - System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() - { - return this.innerList.GetEnumerator(); - } - - #endregion - - #region IList Members - /// - /// - /// - /// - /// - public int Add(object value) - { - ((IList)this).Add((IConversationState)value); - return this.innerList.Count - 1; - } - - /// - /// - /// - /// - /// - public bool Contains(object value) - { - return ((IList)this).Contains((IConversationState)value); - } - - /// - /// - /// - /// - /// - public int IndexOf(object value) - { - return ((IList)this).IndexOf((IConversationState)value); - } - - /// - /// - /// - /// - /// - public void Insert(int index, object value) - { - ((IList)this).Insert(index, (IConversationState)value); - } - - /// - /// - /// - public bool IsFixedSize - { - get { return false; } - } - - /// - /// - /// - /// - public void Remove(object value) - { - ((IList)this).Add((IConversationState)value); - } - - /// - /// - /// - /// - /// - object IList.this[int index] - { - get - { - return ((IList)this)[index]; - } - set - { - ((IList)this)[index] = (IConversationState)value; - } - } - - #endregion - - #region ICollection Members - /// - /// - /// - /// - /// - public void CopyTo(Array array, int index) - { - IConversationState[] convArr = new IConversationState[array.Length]; - ((IList)this).CopyTo(convArr, index); - convArr.CopyTo(array, index); - } - - /// - /// - /// - public bool IsSynchronized - { - get { return false; } - } - - /// - /// - /// - public object SyncRoot - { - get { return this; } - } - - #endregion + if (LOG.IsEnabled(LogLevel.Debug)) LOG.LogError(String.Format("Creating InnerConversationList for '{0}'", conversationOwner.Id)); + this.conversationOwner = conversationOwner; } + + /// + /// Common Helper to be run before insert. + /// + /// + private void PreAddProcessor(IConversationState itemAdded) + { + if (LOG.IsEnabled(LogLevel.Debug)) LOG.LogDebug(String.Format("PreAddProcessor: added={0} into {1}", itemAdded, this.conversationOwner)); + this.ValidateCircularDependency(itemAdded); + if (itemAdded.ParentConversation != null && itemAdded.ParentConversation != this.conversationOwner) + { + throw new InvalidOperationException( + String.Format(WebConversationSpringState.MSG_CONVERSATION_ALREADY_HAS_PARENT, itemAdded.ParentConversation.Id, this.conversationOwner.Id)); + } + } + + /// + /// Common Helper to be run after insert. + /// + private void PostAddProcessor(IConversationState itemAdded) + { + if (LOG.IsEnabled(LogLevel.Debug)) LOG.LogDebug(String.Format("PostAddProcessor: added={0} into {1}", itemAdded, this.conversationOwner)); + if (itemAdded.ParentConversation == null) + { + itemAdded.ParentConversation = this.conversationOwner; + } + } + + private void ValidateCircularDependency(IConversationState itemAdded) + { + if (LOG.IsEnabled(LogLevel.Debug)) LOG.LogDebug(String.Format("Validating Circular Dependency: added={0} into {1}", itemAdded, this.conversationOwner)); + + ICollection visitedColl = new HashedSet(); + visitedColl.Add(conversationOwner); + + IConversationState parentAncestor = this.conversationOwner; + String path = this.conversationOwner.Id; + //string conectorPath = ""; + + this.ValidateCircularDependencyRecursive(itemAdded, visitedColl, path + "->" + itemAdded.Id); + } + + private void ValidateCircularDependencyRecursive(IConversationState currentConv, ICollection visitedColl, String path) + { + foreach (IConversationState convItem in currentConv.InnerConversations) + { + if (visitedColl.Contains(convItem)) + { + String exMsgStr = + "ConversationState Circular Dependency detected: " + + path + "->" + convItem.Id; + + LOG.LogError(exMsgStr); + throw new InvalidOperationException(exMsgStr); + } + + visitedColl.Add(convItem); + + this.ValidateCircularDependencyRecursive(convItem, visitedColl, path + "->" + convItem.Id); + } + } + + #region IList Members + + /// + /// + /// + /// + /// + public int IndexOf(IConversationState item) + { + return this.innerList.IndexOf(item); + } + + /// + /// + /// + /// + /// + public void Insert(int index, IConversationState item) + { + this.PreAddProcessor(item); + this.innerList.Insert(index, item); + this.PostAddProcessor(item); + } + + /// + /// + /// + /// + public void RemoveAt(int index) + { + this.innerList.RemoveAt(index); + } + + /// + /// + /// + /// + /// + public IConversationState this[int index] + { + get + { + return this.innerList[index]; + } + set + { + this.PreAddProcessor(value); + this.innerList[index] = value; + this.PostAddProcessor(value); + } + } + + #endregion + + #region ICollection Members + + /// + /// + /// + /// + public void Add(IConversationState item) + { + this.PreAddProcessor(item); + this.innerList.Add(item); + this.PostAddProcessor(item); + } + + /// + /// + /// + public void Clear() + { + this.innerList.Clear(); + } + + /// + /// + /// + /// + /// + public bool Contains(IConversationState item) + { + return this.innerList.Contains(item); + } + + /// + /// + /// + /// + /// + public void CopyTo(IConversationState[] array, int arrayIndex) + { + this.innerList.CopyTo(array, arrayIndex); + } + + /// + /// + /// + public int Count + { + get { return this.innerList.Count; } + } + + /// + /// + /// + public bool IsReadOnly + { + get { return this.innerList.IsReadOnly; } + } + + /// + /// + /// + /// + /// + public bool Remove(IConversationState item) + { + return this.innerList.Remove(item); + } + + #endregion + + #region IEnumerable Members + + /// + /// + /// + /// + public IEnumerator GetEnumerator() + { + return this.innerList.GetEnumerator(); + } + + #endregion + + #region IEnumerable Members + + /// + /// + /// + /// + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return this.innerList.GetEnumerator(); + } + + #endregion + + #region IList Members + + /// + /// + /// + /// + /// + public int Add(object value) + { + ((IList) this).Add((IConversationState) value); + return this.innerList.Count - 1; + } + + /// + /// + /// + /// + /// + public bool Contains(object value) + { + return ((IList) this).Contains((IConversationState) value); + } + + /// + /// + /// + /// + /// + public int IndexOf(object value) + { + return ((IList) this).IndexOf((IConversationState) value); + } + + /// + /// + /// + /// + /// + public void Insert(int index, object value) + { + ((IList) this).Insert(index, (IConversationState) value); + } + + /// + /// + /// + public bool IsFixedSize + { + get { return false; } + } + + /// + /// + /// + /// + public void Remove(object value) + { + ((IList) this).Add((IConversationState) value); + } + + /// + /// + /// + /// + /// + object IList.this[int index] + { + get + { + return ((IList) this)[index]; + } + set + { + ((IList) this)[index] = (IConversationState) value; + } + } + + #endregion + + #region ICollection Members + + /// + /// + /// + /// + /// + public void CopyTo(Array array, int index) + { + IConversationState[] convArr = new IConversationState[array.Length]; + ((IList) this).CopyTo(convArr, index); + convArr.CopyTo(array, index); + } + + /// + /// + /// + public bool IsSynchronized + { + get { return false; } + } + + /// + /// + /// + public object SyncRoot + { + get { return this; } + } + + #endregion } diff --git a/src/Spring/Spring.Web.Conversation.NHibernate5/Web/Conversation/WebConversationManager.cs b/src/Spring/Spring.Web.Conversation.NHibernate5/Web/Conversation/WebConversationManager.cs index f6dd8dda..e154c844 100644 --- a/src/Spring/Spring.Web.Conversation.NHibernate5/Web/Conversation/WebConversationManager.cs +++ b/src/Spring/Spring.Web.Conversation.NHibernate5/Web/Conversation/WebConversationManager.cs @@ -24,306 +24,312 @@ using Spring.Context; using Spring.Context.Support; using Spring.Data.NHibernate.Support; -namespace Spring.Web.Conversation +namespace Spring.Web.Conversation; + +/// +/// This was made to stay under session scope. +/// +/// Hailton de Castro +[Serializable] +public class WebConversationManager : SessionPerConversationScope, IConversationManager, IApplicationContextAware { + private static readonly ILogger LOG = LogManager.GetLogger(); + /// - /// This was made to stay under session scope. + /// Semaphore to synchronize writes to the dictionary. /// - /// Hailton de Castro - [Serializable] - public class WebConversationManager : SessionPerConversationScope, IConversationManager, IApplicationContextAware + [NonSerialized] private Mutex mutexEditDic = new Mutex(); + + private Mutex MutexEditDic { - private static readonly ILogger LOG = LogManager.GetLogger(); - - /// - /// Semaphore to synchronize writes to the dictionary. - /// - [NonSerialized] - private Mutex mutexEditDic = new Mutex(); - - private Mutex MutexEditDic + get { - get - { - if (this.mutexEditDic == null) - this.mutexEditDic = new Mutex(); - return this.mutexEditDic; - } + if (this.mutexEditDic == null) + this.mutexEditDic = new Mutex(); + return this.mutexEditDic; } + } - private readonly IDictionary conversations = new Dictionary(); - private IConversationState activeConversation = null; + private readonly IDictionary conversations = new Dictionary(); + private IConversationState activeConversation = null; - #region IConversationManager Members + #region IConversationManager Members - /// - /// - /// - /// - /// - public IConversationState GetConversationById(string id) + /// + /// + /// + /// + /// + public IConversationState GetConversationById(string id) + { + if (this.conversations.ContainsKey(id)) { - if (this.conversations.ContainsKey(id)) - { - return this.conversations[id]; - } - else - { - return null; - } + return this.conversations[id]; } - - /// - /// - /// - public void EndOnTimeOut() + else { - try + return null; + } + } + + /// + /// + /// + public void EndOnTimeOut() + { + try + { + if (LOG.IsEnabled(LogLevel.Debug)) LOG.LogDebug("EndOnTimeOut"); + this.MutexEditDic.WaitOne(5000); + foreach (String keyItem in this.conversations.Keys) { - if (LOG.IsEnabled(LogLevel.Debug)) LOG.LogDebug("EndOnTimeOut"); - this.MutexEditDic.WaitOne(5000); - foreach (String keyItem in this.conversations.Keys) + IConversationState conversationItem = this.conversations[keyItem]; + if (conversationItem.TimeOut > 0) { - IConversationState conversationItem = this.conversations[keyItem]; - if (conversationItem.TimeOut > 0) + if (DateTime.Now.Subtract(conversationItem.LastAccess).TotalMilliseconds > conversationItem.TimeOut) { - if (DateTime.Now.Subtract(conversationItem.LastAccess).TotalMilliseconds > conversationItem.TimeOut) - { - if (LOG.IsEnabled(LogLevel.Debug)) LOG.LogDebug(String.Format("Timeout for conversation '{0}'", conversationItem.Id)); - conversationItem.EndConversation(); - } + if (LOG.IsEnabled(LogLevel.Debug)) LOG.LogDebug(String.Format("Timeout for conversation '{0}'", conversationItem.Id)); + conversationItem.EndConversation(); } } } - finally - { - this.MutexEditDic.ReleaseMutex(); - } + } + finally + { + this.MutexEditDic.ReleaseMutex(); + } + } + + /// + /// + /// + public void PauseConversations() + { + foreach (IConversationState convItem in this.conversations.Values) + { + convItem.PauseConversation(); } - /// - /// - /// - public void PauseConversations() + this.Close(this.SessionFactory, this.conversations.Values); + } + + /// + /// + /// + public void FreeEnded() + { + try + { + if (LOG.IsEnabled(LogLevel.Debug)) LOG.LogDebug("EndOnTimeOut"); + this.MutexEditDic.WaitOne(5000); + List removeList = new List(); + foreach (String keyItem in this.conversations.Keys) + { + IConversationState conversationItem = this.conversations[keyItem]; + if (conversationItem.Ended) + { + if (LOG.IsEnabled(LogLevel.Debug)) LOG.LogDebug(String.Format("FreeEnded: Release conversation '{0}'", conversationItem.Id)); + removeList.Add(conversationItem); + } + } + + if (removeList.Count > 0) + { + this.Close(this.SessionFactory, removeList); + } + + foreach (IConversationState conversationItem in removeList) + { + if (LOG.IsEnabled(LogLevel.Debug)) LOG.LogDebug(String.Format("FreeEnded: Remove conversation '{0}'", conversationItem.Id)); + conversationItem.EndConversation(); + this.RemoveConversation(conversationItem); + } + } + finally + { + this.MutexEditDic.ReleaseMutex(); + } + } + + /// + /// + /// + /// + public void AddConversation(IConversationState conversation) + { + try + { + this.MutexEditDic.WaitOne(5000); + this.conversations.Add(conversation.Id, conversation); + } + finally + { + this.MutexEditDic.ReleaseMutex(); + } + + if (conversation.ConversationManager != null && conversation.ConversationManager != this) + { + throw new InvalidOperationException(String.Format("Conversation already has another manager. conversation='{0}'", conversation.Id)); + } + + if (conversation.ConversationManager == null) + { + conversation.ConversationManager = this; + } + } + + /// + /// + /// + /// + public void SetActiveConversation(IConversationState conversation) + { + if (LOG.IsEnabled(LogLevel.Debug)) LOG.LogDebug(String.Format("SetActiveConversation('{0}')", conversation.Id)); + + //Close connection for the last conversation, if it is open. + if (this.activeConversation != null && this.activeConversation != conversation) + { + this.Close(this.SessionFactory, this.conversations.Values); + } + + this.Open(conversation, this.conversations.Values); + + this.activeConversation = conversation; + + //Ending the paused conversations. + if (this.EndPaused) { foreach (IConversationState convItem in this.conversations.Values) { - convItem.PauseConversation(); - } - this.Close(this.SessionFactory, this.conversations.Values); - } - - /// - /// - /// - public void FreeEnded() - { - try - { - if (LOG.IsEnabled(LogLevel.Debug)) LOG.LogDebug("EndOnTimeOut"); - this.MutexEditDic.WaitOne(5000); - List removeList = new List(); - foreach (String keyItem in this.conversations.Keys) + if (convItem.IsPaused) { - IConversationState conversationItem = this.conversations[keyItem]; - if (conversationItem.Ended) - { - if (LOG.IsEnabled(LogLevel.Debug)) LOG.LogDebug(String.Format("FreeEnded: Release conversation '{0}'", conversationItem.Id)); - removeList.Add(conversationItem); - } - } - - if (removeList.Count > 0) - { - this.Close(this.SessionFactory, removeList); - } - - foreach (IConversationState conversationItem in removeList) - { - if (LOG.IsEnabled(LogLevel.Debug)) LOG.LogDebug(String.Format("FreeEnded: Remove conversation '{0}'", conversationItem.Id)); - conversationItem.EndConversation(); - this.RemoveConversation(conversationItem); - } - } - finally - { - this.MutexEditDic.ReleaseMutex(); - } - } - - /// - /// - /// - /// - public void AddConversation(IConversationState conversation) - { - try - { - this.MutexEditDic.WaitOne(5000); - this.conversations.Add(conversation.Id, conversation); - } - finally - { - this.MutexEditDic.ReleaseMutex(); - } - - if (conversation.ConversationManager != null && conversation.ConversationManager != this) - { - throw new InvalidOperationException(String.Format("Conversation already has another manager. conversation='{0}'", conversation.Id)); - } - - if (conversation.ConversationManager == null) - { - conversation.ConversationManager = this; - } - } - - /// - /// - /// - /// - public void SetActiveConversation(IConversationState conversation) - { - if (LOG.IsEnabled(LogLevel.Debug)) LOG.LogDebug(String.Format("SetActiveConversation('{0}')", conversation.Id)); - - //Close connection for the last conversation, if it is open. - if (this.activeConversation != null && this.activeConversation != conversation) - { - this.Close(this.SessionFactory, this.conversations.Values); - } - this.Open(conversation, this.conversations.Values); - - this.activeConversation = conversation; - - //Ending the paused conversations. - if (this.EndPaused) - { - foreach (IConversationState convItem in this.conversations.Values) - { - if (convItem.IsPaused) - { - convItem.EndConversation(); - } + convItem.EndConversation(); } } } - - /// - /// - /// - public IConversationState ActiveConversation - { - get - { - return this.activeConversation; - } - } - - private String sessionFactoryName; - /// - /// "SessionFactory" name in the current context. - /// This approach is required to support serialization. - /// - public String SessionFactoryName - { - get { return sessionFactoryName; } - set { sessionFactoryName = value; } - } - - [NonSerialized] - private ISessionFactory sessionFactory; - /// - /// - /// - public ISessionFactory SessionFactory - { - get - { - if (this.sessionFactory == null && this.sessionFactoryName != null) - { - this.sessionFactory = this.ApplicationContext.GetObject(this.sessionFactoryName); - } - return sessionFactory; - } - } - - private bool endPaused = false; - - /// - /// - /// - public bool EndPaused - { - get { return endPaused; } - set { endPaused = value; } - } - #endregion - - #region SessionPerConversationScope Members - /// - /// Ends all conversations and Closes all their Session. - /// - public override void Dispose() - { - if (LOG.IsEnabled(LogLevel.Debug)) LOG.LogDebug("Dispose. End all Conversations"); - foreach (String conversationId in this.conversations.Keys) - { - if (LOG.IsEnabled(LogLevel.Debug)) LOG.LogDebug(string.Format("Ending Conversation for Conversation Id: {0}", conversationId)); - this.conversations[conversationId].EndConversation(); - } - - this.Close(this.SessionFactory, this.conversations.Values); - - this.conversations.Clear(); - this.sessionFactory = null; - } - #endregion - - /// - /// Remove conversation. - /// - /// - private void RemoveConversation(IConversationState conversation) - { - try - { - this.MutexEditDic.WaitOne(5000); - if (!this.conversations.Remove(conversation.Id)) - { - throw new InvalidOperationException(String.Format("Conversation '{0}' does not exist on this manager.", conversation.Id)); - } - } - finally - { - this.MutexEditDic.ReleaseMutex(); - } - } - - #region IApplicationContextAware Members - private String applicationContextName; - [NonSerialized] - private IApplicationContext applicationContext = null; - /// - /// Returns the current context. Supports serialization and deserialization. - /// - public IApplicationContext ApplicationContext - { - set - { - this.applicationContext = value; - this.applicationContextName = this.applicationContext.Name; - } - get - { - if (this.applicationContext == null) - { - this.applicationContext = ContextRegistry.GetContext(this.applicationContextName); - } - return this.applicationContext; - } - } - - #endregion - } + + /// + /// + /// + public IConversationState ActiveConversation + { + get + { + return this.activeConversation; + } + } + + private String sessionFactoryName; + + /// + /// "SessionFactory" name in the current context. + /// This approach is required to support serialization. + /// + public String SessionFactoryName + { + get { return sessionFactoryName; } + set { sessionFactoryName = value; } + } + + [NonSerialized] private ISessionFactory sessionFactory; + + /// + /// + /// + public ISessionFactory SessionFactory + { + get + { + if (this.sessionFactory == null && this.sessionFactoryName != null) + { + this.sessionFactory = this.ApplicationContext.GetObject(this.sessionFactoryName); + } + + return sessionFactory; + } + } + + private bool endPaused = false; + + /// + /// + /// + public bool EndPaused + { + get { return endPaused; } + set { endPaused = value; } + } + + #endregion + + #region SessionPerConversationScope Members + + /// + /// Ends all conversations and Closes all their Session. + /// + public override void Dispose() + { + if (LOG.IsEnabled(LogLevel.Debug)) LOG.LogDebug("Dispose. End all Conversations"); + foreach (String conversationId in this.conversations.Keys) + { + if (LOG.IsEnabled(LogLevel.Debug)) LOG.LogDebug(string.Format("Ending Conversation for Conversation Id: {0}", conversationId)); + this.conversations[conversationId].EndConversation(); + } + + this.Close(this.SessionFactory, this.conversations.Values); + + this.conversations.Clear(); + this.sessionFactory = null; + } + + #endregion + + /// + /// Remove conversation. + /// + /// + private void RemoveConversation(IConversationState conversation) + { + try + { + this.MutexEditDic.WaitOne(5000); + if (!this.conversations.Remove(conversation.Id)) + { + throw new InvalidOperationException(String.Format("Conversation '{0}' does not exist on this manager.", conversation.Id)); + } + } + finally + { + this.MutexEditDic.ReleaseMutex(); + } + } + + #region IApplicationContextAware Members + + private String applicationContextName; + [NonSerialized] private IApplicationContext applicationContext = null; + + /// + /// Returns the current context. Supports serialization and deserialization. + /// + public IApplicationContext ApplicationContext + { + set + { + this.applicationContext = value; + this.applicationContextName = this.applicationContext.Name; + } + get + { + if (this.applicationContext == null) + { + this.applicationContext = ContextRegistry.GetContext(this.applicationContextName); + } + + return this.applicationContext; + } + } + + #endregion } diff --git a/src/Spring/Spring.Web.Conversation.NHibernate5/Web/Conversation/WebConversationSpringState.cs b/src/Spring/Spring.Web.Conversation.NHibernate5/Web/Conversation/WebConversationSpringState.cs index 9790f5d1..60e8fecd 100644 --- a/src/Spring/Spring.Web.Conversation.NHibernate5/Web/Conversation/WebConversationSpringState.cs +++ b/src/Spring/Spring.Web.Conversation.NHibernate5/Web/Conversation/WebConversationSpringState.cs @@ -27,641 +27,666 @@ using Spring.Context.Support; using Spring.Data.Common; using Spring.Objects.Factory; -namespace Spring.Web.Conversation +namespace Spring.Web.Conversation; + +/// +/// Implementation of conversation in the infrastructure of Spring. +/// It avoid Circular Dependencies. +/// +/// Hailton de Castro +[Serializable] +public class WebConversationSpringState : IConversationState, IObjectNameAware, IApplicationContextAware { + private const string SPRING_SESSSION_SCOPE_KEY = "spring.objects"; + private static readonly ILogger LOG = LogManager.GetLogger(); + /// - /// Implementation of conversation in the infrastructure of Spring. - /// It avoid Circular Dependencies. + /// Default message for "CONVERSATION ALREADY HAS A PARENT" error. /// - /// Hailton de Castro - [Serializable] - public class WebConversationSpringState : IConversationState, IObjectNameAware, IApplicationContextAware + public static readonly String MSG_CONVERSATION_ALREADY_HAS_PARENT = + "This conversation already has a different parent." + + " Current: '{0}'. Tried: '{1}'"; + + private IDictionary state = new Dictionary(); + + #region IConversationState Members + + private String id; + + /// + /// + /// + public string Id { - private const string SPRING_SESSSION_SCOPE_KEY = "spring.objects"; - private static readonly ILogger LOG = LogManager.GetLogger(); - - /// - /// Default message for "CONVERSATION ALREADY HAS A PARENT" error. - /// - public static readonly String MSG_CONVERSATION_ALREADY_HAS_PARENT = - "This conversation already has a different parent." + - " Current: '{0}'. Tried: '{1}'"; - - private IDictionary state = new Dictionary(); - - #region IConversationState Members - - private String id; - /// - /// - /// - public string Id + get { - get - { - return this.id; - } - set - { - this.id = value; - } + return this.id; + } + set + { + this.id = value; + } + } + + /// + /// + /// + /// + public void EndConversation() + { + if (LOG.IsEnabled(LogLevel.Debug)) LOG.LogDebug(String.Format("End of Conversation '{0}'", this.id)); + + IDictionary springSessionScope = (IDictionary) HttpContext.Current.Session[SPRING_SESSSION_SCOPE_KEY]; + if (springSessionScope == null) + { + throw new InvalidOperationException(string.Format("The 'spring session scope' is not located in the key {0} of HttpSessionState.", SPRING_SESSSION_SCOPE_KEY)); } - /// - /// - /// - /// - public void EndConversation() + if (springSessionScope.Contains(this.Id)) { - if (LOG.IsEnabled(LogLevel.Debug)) LOG.LogDebug(String.Format("End of Conversation '{0}'", this.id)); + if (LOG.IsEnabled(LogLevel.Debug)) LOG.LogDebug(String.Format("EndConversation: Id='{0}' Was Found on 'spring session scope'!", this.id)); + springSessionScope.Remove(this.id); + } + else + { + if (LOG.IsEnabled(LogLevel.Debug)) LOG.LogDebug(String.Format("EndConversation: Id='{0}' Was NOT Found on 'spring session scope!", this.id)); + } - IDictionary springSessionScope = (IDictionary)HttpContext.Current.Session[SPRING_SESSSION_SCOPE_KEY]; - if (springSessionScope == null) + List innerConversationsListTemp = new List(this.InnerConversations); + foreach (IConversationState innerConversationItem in innerConversationsListTemp) + { + innerConversationItem.EndConversation(); + } + + if (this.parentConversation != null) + { + this.parentConversation.InnerConversations.Remove(this); + } + + this.ended = true; + } + + private bool ended = false; + + /// + /// + /// + public bool Ended + { + get { return ended; } + } + + private int timeOut = 180000; + + /// + /// Default 180000. + /// + public int TimeOut + { + get { return timeOut; } + set { timeOut = value; } + } + + private IList innerConversations; + + /// + /// + /// + public IList InnerConversations + { + get + { + if (this.innerConversations == null) { - throw new InvalidOperationException(string.Format("The 'spring session scope' is not located in the key {0} of HttpSessionState.", SPRING_SESSSION_SCOPE_KEY)); + this.innerConversations = new InnerConversationList(this); } - if (springSessionScope.Contains(this.Id)) + return this.innerConversations; + } + } + + private IConversationState parentConversation; + + /// + /// + /// + public IConversationState ParentConversation + { + get + { + return this.parentConversation; + } + set + { + if (this.parentConversation != null && this.parentConversation != value) { - if (LOG.IsEnabled(LogLevel.Debug)) LOG.LogDebug(String.Format("EndConversation: Id='{0}' Was Found on 'spring session scope'!", this.id)); - springSessionScope.Remove(this.id); + throw new InvalidOperationException( + String.Format(MSG_CONVERSATION_ALREADY_HAS_PARENT, this.parentConversation.Id, value.Id)); + } + + if (!this.IsNew) + { + throw new InvalidOperationException( + String.Format("This Conversation is not new." + + " Conversation.Id: '{0}'. Parent Tried: '{1}'", this.Id, value.Id)); + } + //Perhaps the father need not be new, only the child needs to be. + //if (!value.IsNew) + //{ + // throw new InvalidOperationException( + // String.Format("The Parent conversation is not new." + + // " Conversation.Id: '{0}'. Parent Tried: '{1}'", this.Id, value.Id)); + //} + + this.parentConversation = value; + if (!this.parentConversation.InnerConversations.Contains(this)) + { + this.parentConversation.InnerConversations.Add(this); + } + } + } + + private DateTime lastAccess = DateTime.Now; + + /// + /// . + /// + public DateTime LastAccess + { + get { return lastAccess; } + set { lastAccess = value; } + } + + private IConversationManager conversationManager; + + /// + /// + /// + public IConversationManager ConversationManager + { + get + { + return conversationManager; + } + set + { + conversationManager = value; + if (this.conversationManager.GetConversationById(this.Id) == null) + { + this.conversationManager.AddConversation(this); + } + } + } + + /// + /// + /// + public void StartResumeConversation() + { + this.isNew = false; + this.isPaused = false; + this.lastAccess = DateTime.Now; + + if (this.Ended) + { + throw new InvalidOperationException( + String.Format( + "StartResumeConversation: this conversation is ended." + + " Conversation.Id '{0}'", this.Id)); + } + + if (this.ConversationManager != null) + { + if (LOG.IsEnabled(LogLevel.Debug)) LOG.LogDebug(String.Format("StartResumeConversation('{0}'): ConversationManager is not null.", this.Id)); + //if this is the root conversation. + if (this.ParentConversation == null) + { + if (LOG.IsEnabled(LogLevel.Debug)) LOG.LogDebug(String.Format("SetActiveConversation('{0}'): ConversationManager is not null.", this.Id)); + //if this is the root conversation. + this.ConversationManager.SetActiveConversation(this); + + //makes SessionHolder to reopen this session + if (this.RootSessionPerConversation != null) + { + ISession session = this.SessionFactory.GetCurrentSession(); + if (this.RootSessionPerConversation != session) + { + //How it is implemented it will never happen, because of the sequence of previous calls: + // ConversationManager.SetActiveConversation -> SessionPerConversationScope.Open + // 'new InvalidOperationException("Participating in existing Hibernate SessionFactory IS NOT ALOWED.")' happen first. + throw new InvalidOperationException( + String.Format( + "StartResumeConversation: this.SessionFactory.GetCurrentSession()" + + " have a different instance than 'RootSessionPerConversation'" + + " from conversation '{0}'", this.Id)); + } + } } else { - if (LOG.IsEnabled(LogLevel.Debug)) LOG.LogDebug(String.Format("EndConversation: Id='{0}' Was NOT Found on 'spring session scope!", this.id)); + this.ParentConversation.StartResumeConversation(); } + } + } - List innerConversationsListTemp = new List(this.InnerConversations); - foreach (IConversationState innerConversationItem in innerConversationsListTemp) + private ISession rootSessionPerConversation; + + /// + /// + /// + public ISession RootSessionPerConversation + { + get + { + if (this.ParentConversation != null) { - innerConversationItem.EndConversation(); + return this.ParentConversation.RootSessionPerConversation; } - - if (this.parentConversation != null) + else { - this.parentConversation.InnerConversations.Remove(this); + return rootSessionPerConversation; } - - this.ended = true; } - - private bool ended = false; - /// - /// - /// - public bool Ended + set { - get { return ended; } - } - - private int timeOut = 180000; - /// - /// Default 180000. - /// - public int TimeOut - { - get { return timeOut; } - set { timeOut = value; } - } - - private IList innerConversations; - /// - /// - /// - public IList InnerConversations - { - get + if (this.ParentConversation != null) { - if (this.innerConversations == null) - { - this.innerConversations = new InnerConversationList(this); - } - return this.innerConversations; + this.ParentConversation.RootSessionPerConversation = value; } - } - - private IConversationState parentConversation; - /// - /// - /// - public IConversationState ParentConversation - { - get + else { - return this.parentConversation; + rootSessionPerConversation = value; } - set + } + } + + private String sessionFactoryName; + + /// + /// "SessionFactory" name in the current context. + /// This approach is required to support serialization. + /// + public String SessionFactoryName + { + get { return sessionFactoryName; } + set { sessionFactoryName = value; } + } + + [NonSerialized] private ISessionFactory sessionFactory; + + /// + /// + /// + public ISessionFactory SessionFactory + { + get + { + if (this.sessionFactory == null && this.sessionFactoryName != null) { - if (this.parentConversation != null && this.parentConversation != value) - { - throw new InvalidOperationException( - String.Format(MSG_CONVERSATION_ALREADY_HAS_PARENT, this.parentConversation.Id, value.Id)); - } - if (!this.IsNew) - { - throw new InvalidOperationException( - String.Format("This Conversation is not new." + - " Conversation.Id: '{0}'. Parent Tried: '{1}'", this.Id, value.Id)); - } - //Perhaps the father need not be new, only the child needs to be. - //if (!value.IsNew) - //{ - // throw new InvalidOperationException( - // String.Format("The Parent conversation is not new." + - // " Conversation.Id: '{0}'. Parent Tried: '{1}'", this.Id, value.Id)); - //} - - this.parentConversation = value; - if (!this.parentConversation.InnerConversations.Contains(this)) - { - this.parentConversation.InnerConversations.Add(this); - } + this.sessionFactory = this.ApplicationContext.GetObject(this.sessionFactoryName); } - } - private DateTime lastAccess = DateTime.Now; - /// - /// . - /// - public DateTime LastAccess - { - get { return lastAccess; } - set { lastAccess = value; } + return sessionFactory; } + } - private IConversationManager conversationManager; - /// - /// - /// - public IConversationManager ConversationManager + private String dbProviderName; + + /// + /// "DbProvider" name in the current context. + /// This approach is required to support serialization. + /// + public String DbProviderName + { + get { return dbProviderName; } + set { dbProviderName = value; } + } + + [NonSerialized] private IDbProvider dbProvider; + + /// + /// + /// + public IDbProvider DbProvider + { + get { - get + if (this.dbProvider == null && this.dbProviderName != null) { - return conversationManager; - } - set - { - conversationManager = value; - if (this.conversationManager.GetConversationById(this.Id) == null) - { - this.conversationManager.AddConversation(this); - } + this.dbProvider = this.ApplicationContext.GetObject(this.dbProviderName); } + + return dbProvider; } + } - /// - /// - /// - public void StartResumeConversation() + private bool isNew = true; + + /// + /// + /// + public bool IsNew + { + get { return this.isNew; } + } + + private bool isPaused = true; + + /// + /// + /// + public bool IsPaused + { + get { return isPaused; } + } + + /// + /// + /// + public void PauseConversation() + { + this.isPaused = true; + foreach (IConversationState conversation in this.InnerConversations) { - this.isNew = false; - this.isPaused = false; - this.lastAccess = DateTime.Now; + conversation.PauseConversation(); + } + } - if (this.Ended) + #endregion + + #region IObjectNameAware Members + + /// + /// . It is used to valddate + /// + public string ObjectName + { + set + { + if (this.id != value) { - throw new InvalidOperationException( - String.Format( - "StartResumeConversation: this conversation is ended." + - " Conversation.Id '{0}'", this.Id)); + throw new InvalidOperationException(String.Format("Id is different from spring name for this instance.. Currents='{0}', springName='{1}'", this.id, value)); } - if (this.ConversationManager != null) - { - if (LOG.IsEnabled(LogLevel.Debug)) LOG.LogDebug(String.Format("StartResumeConversation('{0}'): ConversationManager is not null.", this.Id)); - //if this is the root conversation. - if (this.ParentConversation == null) - { - if (LOG.IsEnabled(LogLevel.Debug)) LOG.LogDebug(String.Format("SetActiveConversation('{0}'): ConversationManager is not null.", this.Id)); - //if this is the root conversation. - this.ConversationManager.SetActiveConversation(this); - //makes SessionHolder to reopen this session - if (this.RootSessionPerConversation != null) - { - ISession session = this.SessionFactory.GetCurrentSession(); - if (this.RootSessionPerConversation != session) - { - //How it is implemented it will never happen, because of the sequence of previous calls: - // ConversationManager.SetActiveConversation -> SessionPerConversationScope.Open - // 'new InvalidOperationException("Participating in existing Hibernate SessionFactory IS NOT ALOWED.")' happen first. - throw new InvalidOperationException( - String.Format( - "StartResumeConversation: this.SessionFactory.GetCurrentSession()" + - " have a different instance than 'RootSessionPerConversation'" + - " from conversation '{0}'", this.Id)); - } - } - } - else - { - this.ParentConversation.StartResumeConversation(); - } - } + if (LOG.IsEnabled(LogLevel.Debug)) LOG.LogDebug(String.Format("Begin of Conversation '{0}'", this.id)); } + } - private ISession rootSessionPerConversation; - /// - /// - /// - public ISession RootSessionPerConversation + #endregion + + #region IDictionary Members + + /// + /// + /// + /// + /// + public void Add(string key, object value) + { + this.state.Add(key, value); + } + + /// + /// + /// + /// + /// + public bool ContainsKey(string key) + { + if (this.state.ContainsKey(key)) { - get - { - if (this.ParentConversation != null) - { - return this.ParentConversation.RootSessionPerConversation; - } - else - { - return rootSessionPerConversation; - } - } - set - { - if (this.ParentConversation != null) - { - this.ParentConversation.RootSessionPerConversation = value; - } - else - { - rootSessionPerConversation = value; - } - } + return this.state.ContainsKey(key); } - - private String sessionFactoryName; - /// - /// "SessionFactory" name in the current context. - /// This approach is required to support serialization. - /// - public String SessionFactoryName + else if (this.parentConversation != null) { - get { return sessionFactoryName; } - set { sessionFactoryName = value; } + return this.parentConversation.ContainsKey(key); } - - [NonSerialized] - private ISessionFactory sessionFactory; - /// - /// - /// - public ISessionFactory SessionFactory + else { - get - { - if (this.sessionFactory == null && this.sessionFactoryName != null) - { - this.sessionFactory = this.ApplicationContext.GetObject(this.sessionFactoryName); - } - return sessionFactory; - } + return false; } + } - private String dbProviderName; - /// - /// "DbProvider" name in the current context. - /// This approach is required to support serialization. - /// - public String DbProviderName + /// + /// + /// + public ICollection Keys + { + get { - get { return dbProviderName; } - set { dbProviderName = value; } + return this.state.Keys; } + } - [NonSerialized] - private IDbProvider dbProvider; - /// - /// - /// - public IDbProvider DbProvider + /// + /// + /// + /// + /// + public bool Remove(string key) + { + return this.state.Remove(key); + } + + /// + /// + /// + /// + /// + /// + public bool TryGetValue(string key, out object value) + { + if (this.state.TryGetValue(key, out value)) { - get - { - if (this.dbProvider == null && this.dbProviderName != null) - { - this.dbProvider = this.ApplicationContext.GetObject(this.dbProviderName); - } - return dbProvider; - } + return true; } - - private bool isNew = true; - /// - /// - /// - public bool IsNew + else if (this.parentConversation != null && this.parentConversation.TryGetValue(key, out value)) { - get { return this.isNew; } + return true; } - - private bool isPaused = true; - /// - /// - /// - public bool IsPaused + else { - get { return isPaused; } + return false; } + } - /// - /// - /// - public void PauseConversation() + /// + /// + /// + public ICollection Values + { + get { - this.isPaused = true; - foreach (IConversationState conversation in this.InnerConversations) - { - conversation.PauseConversation(); - } + return this.state.Values; } - #endregion + } - #region IObjectNameAware Members - /// - /// . It is used to valddate - /// - public string ObjectName - { - set - { - if (this.id != value) - { - throw new InvalidOperationException(String.Format("Id is different from spring name for this instance.. Currents='{0}', springName='{1}'", this.id, value)); - } - if (LOG.IsEnabled(LogLevel.Debug)) LOG.LogDebug(String.Format("Begin of Conversation '{0}'", this.id)); - } - } - - #endregion - - #region IDictionary Members - /// - /// - /// - /// - /// - public void Add(string key, object value) - { - this.state.Add(key, value); - } - - /// - /// - /// - /// - /// - public bool ContainsKey(string key) + /// + /// + /// + /// + /// + public object this[string key] + { + get { if (this.state.ContainsKey(key)) { - return this.state.ContainsKey(key); + return this.state[key]; } else if (this.parentConversation != null) { - return this.parentConversation.ContainsKey(key); + return this.parentConversation[key]; } else { - return false; + return null; } } - - /// - /// - /// - public ICollection Keys + set { - get - { - return this.state.Keys; - } + this.state[key] = value; } - - /// - /// - /// - /// - /// - public bool Remove(string key) - { - return this.state.Remove(key); - } - - /// - /// - /// - /// - /// - /// - public bool TryGetValue(string key, out object value) - { - if (this.state.TryGetValue(key, out value)) - { - return true; - } - else if (this.parentConversation != null && this.parentConversation.TryGetValue(key, out value)) - { - return true; - } - else - { - return false; - } - } - - /// - /// - /// - public ICollection Values - { - get - { - return this.state.Values; - } - } - - /// - /// - /// - /// - /// - public object this[string key] - { - get - { - if (this.state.ContainsKey(key)) - { - return this.state[key]; - } - else if (this.parentConversation != null) - { - return this.parentConversation[key]; - } - else - { - return null; - } - } - set - { - this.state[key] = value; - } - } - - #endregion - - #region ICollection> Members - /// - /// - /// - /// - public void Add(KeyValuePair item) - { - this.state.Add(item); - } - - /// - /// - /// - public void Clear() - { - this.state.Clear(); - } - - /// - /// - /// - /// - /// - public bool Contains(KeyValuePair item) - { - if (this.state.Contains(item)) - { - return this.state.Contains(item); - } - else if (this.parentConversation != null) - { - return this.parentConversation.Contains(item); - } - else - { - return false; - } - } - - /// - /// - /// - /// - /// - public void CopyTo(KeyValuePair[] array, int arrayIndex) - { - this.state.CopyTo(array, arrayIndex); - } - - /// - /// - /// - public int Count - { - get - { - return this.state.Count; - } - } - - /// - /// - /// - public bool IsReadOnly - { - get - { - return this.state.IsReadOnly; - } - } - - /// - /// - /// - /// - /// - public bool Remove(KeyValuePair item) - { - return this.state.Remove(item); - } - - #endregion - - #region IEnumerable> Members - /// - /// - /// - /// - public IEnumerator> GetEnumerator() - { - return this.state.GetEnumerator(); - } - - #endregion - - #region IEnumerable Members - /// - /// - /// - /// - IEnumerator IEnumerable.GetEnumerator() - { - return this.state.GetEnumerator(); - } - - #endregion - - /// - /// A String representation from conversation. - /// - /// - public override string ToString() - { - String innerConsversationsStr = ""; - - String conector = ""; - foreach (IConversationState convItem in this.InnerConversations) - { - innerConsversationsStr += conector + convItem; - } - - return String.Format("{{Id='{0}'; this.ParentConversation.Id={1}; InnerConversations=[{2}]}}", - this.id, - this.ParentConversation != null ? this.ParentConversation.Id : "", - innerConsversationsStr - ); - } - - #region IApplicationContextAware Members - private String applicationContextName; - [NonSerialized] - private IApplicationContext applicationContext = null; - /// - /// Returns the current context. Supports serialization and deserialization. - /// - public IApplicationContext ApplicationContext - { - set - { - this.applicationContext = value; - this.applicationContextName = this.applicationContext.Name; - } - get - { - if (this.applicationContext == null) - { - this.applicationContext = ContextRegistry.GetContext(this.applicationContextName); - } - return this.applicationContext; - } - } - - #endregion } + + #endregion + + #region ICollection> Members + + /// + /// + /// + /// + public void Add(KeyValuePair item) + { + this.state.Add(item); + } + + /// + /// + /// + public void Clear() + { + this.state.Clear(); + } + + /// + /// + /// + /// + /// + public bool Contains(KeyValuePair item) + { + if (this.state.Contains(item)) + { + return this.state.Contains(item); + } + else if (this.parentConversation != null) + { + return this.parentConversation.Contains(item); + } + else + { + return false; + } + } + + /// + /// + /// + /// + /// + public void CopyTo(KeyValuePair[] array, int arrayIndex) + { + this.state.CopyTo(array, arrayIndex); + } + + /// + /// + /// + public int Count + { + get + { + return this.state.Count; + } + } + + /// + /// + /// + public bool IsReadOnly + { + get + { + return this.state.IsReadOnly; + } + } + + /// + /// + /// + /// + /// + public bool Remove(KeyValuePair item) + { + return this.state.Remove(item); + } + + #endregion + + #region IEnumerable> Members + + /// + /// + /// + /// + public IEnumerator> GetEnumerator() + { + return this.state.GetEnumerator(); + } + + #endregion + + #region IEnumerable Members + + /// + /// + /// + /// + IEnumerator IEnumerable.GetEnumerator() + { + return this.state.GetEnumerator(); + } + + #endregion + + /// + /// A String representation from conversation. + /// + /// + public override string ToString() + { + String innerConsversationsStr = ""; + + String conector = ""; + foreach (IConversationState convItem in this.InnerConversations) + { + innerConsversationsStr += conector + convItem; + } + + return String.Format("{{Id='{0}'; this.ParentConversation.Id={1}; InnerConversations=[{2}]}}", + this.id, + this.ParentConversation != null ? this.ParentConversation.Id : "", + innerConsversationsStr + ); + } + + #region IApplicationContextAware Members + + private String applicationContextName; + [NonSerialized] private IApplicationContext applicationContext = null; + + /// + /// Returns the current context. Supports serialization and deserialization. + /// + public IApplicationContext ApplicationContext + { + set + { + this.applicationContext = value; + this.applicationContextName = this.applicationContext.Name; + } + get + { + if (this.applicationContext == null) + { + this.applicationContext = ContextRegistry.GetContext(this.applicationContextName); + } + + return this.applicationContext; + } + } + + #endregion } diff --git a/src/Spring/Spring.Web.Conversation.NHibernate5/app.config b/src/Spring/Spring.Web.Conversation.NHibernate5/app.config index 0df7832f..f9c38c49 100644 --- a/src/Spring/Spring.Web.Conversation.NHibernate5/app.config +++ b/src/Spring/Spring.Web.Conversation.NHibernate5/app.config @@ -1,3 +1,4 @@ - + + diff --git a/src/Spring/Spring.Web.Extensions/AssemblyInfo.cs b/src/Spring/Spring.Web.Extensions/AssemblyInfo.cs index 089232b1..6eba0528 100644 --- a/src/Spring/Spring.Web.Extensions/AssemblyInfo.cs +++ b/src/Spring/Spring.Web.Extensions/AssemblyInfo.cs @@ -1,4 +1,4 @@ using System.Reflection; [assembly: AssemblyTitle("Spring.Web.Extensions")] -[assembly: AssemblyDescription("Interfaces and classes that provide ASP.NET AJAX 1.0 support in Spring.Net")] \ No newline at end of file +[assembly: AssemblyDescription("Interfaces and classes that provide ASP.NET AJAX 1.0 support in Spring.Net")] diff --git a/src/Spring/Spring.Web.Extensions/Web/Script/Services/ScriptHandlerFactory.cs b/src/Spring/Spring.Web.Extensions/Web/Script/Services/ScriptHandlerFactory.cs index 877b7619..5f5ce357 100644 --- a/src/Spring/Spring.Web.Extensions/Web/Script/Services/ScriptHandlerFactory.cs +++ b/src/Spring/Spring.Web.Extensions/Web/Script/Services/ScriptHandlerFactory.cs @@ -21,119 +21,116 @@ using System.Reflection; using System.Web; using System.Web.Script.Services; - using Spring.Context; using Spring.Util; using Spring.Web.Services; using Spring.Web.Support; -namespace Spring.Web.Script.Services +namespace Spring.Web.Script.Services; + +/// +/// An implementation that +/// creates a handler object for either ASP.NET AJAX 1.0 or Spring web services. +/// +/// Bruno Baia +/// Thomas Broyer +public class ScriptHandlerFactory : AbstractHandlerFactory, IHttpHandlerFactory { + private static readonly Type scriptHandlerFactoryType = + typeof(ScriptServiceAttribute).Assembly.GetType("System.Web.Script.Services.ScriptHandlerFactory"); + + private static readonly FieldInfo scriptHandlerFactory_webServiceHandlerFactory = + scriptHandlerFactoryType.GetField("_webServiceHandlerFactory", BindingFlags.NonPublic | BindingFlags.Instance); + + private static readonly Type webServiceDataType = + typeof(ScriptServiceAttribute).Assembly.GetType("System.Web.Script.Services.WebServiceData"); + + private static readonly ConstructorInfo webServiceData_ctor = + webServiceDataType.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(Type), typeof(bool) }, null); + + private static readonly MethodInfo webServiceData_GetCacheKey = + webServiceDataType.GetMethod("GetCacheKey", BindingFlags.NonPublic | BindingFlags.Static, null, new Type[] { typeof(string) }, null); + + private readonly IHttpHandlerFactory scriptHandlerFactory = + (IHttpHandlerFactory) Activator.CreateInstance(scriptHandlerFactoryType, true); + /// - /// An implementation that - /// creates a handler object for either ASP.NET AJAX 1.0 or Spring web services. + /// Creates a new instance of the class. /// - /// Bruno Baia - /// Thomas Broyer - public class ScriptHandlerFactory : AbstractHandlerFactory, IHttpHandlerFactory + public ScriptHandlerFactory() + : base() { - private static readonly Type scriptHandlerFactoryType = - typeof(ScriptServiceAttribute).Assembly.GetType("System.Web.Script.Services.ScriptHandlerFactory"); + scriptHandlerFactory_webServiceHandlerFactory.SetValue( + this.scriptHandlerFactory, + new WebServiceHandlerFactory()); + } - private static readonly FieldInfo scriptHandlerFactory_webServiceHandlerFactory = - scriptHandlerFactoryType.GetField("_webServiceHandlerFactory", BindingFlags.NonPublic | BindingFlags.Instance); - - private static readonly Type webServiceDataType = - typeof(ScriptServiceAttribute).Assembly.GetType("System.Web.Script.Services.WebServiceData"); - - private static readonly ConstructorInfo webServiceData_ctor = - webServiceDataType.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(Type), typeof(bool) }, null); - - private static readonly MethodInfo webServiceData_GetCacheKey = - webServiceDataType.GetMethod("GetCacheKey", BindingFlags.NonPublic | BindingFlags.Static, null, new Type[] { typeof(string) }, null); - - - private readonly IHttpHandlerFactory scriptHandlerFactory = - (IHttpHandlerFactory)Activator.CreateInstance(scriptHandlerFactoryType, true); - - /// - /// Creates a new instance of the class. - /// - public ScriptHandlerFactory() - : base() + /// + /// Retrieves an instance of the + /// implementation for handling web service requests + /// for both Spring and ASP.NET AJAX 1.0 web services. + /// + /// The current HTTP context. + /// The type of HTTP request (GET or POST). + /// The url of the web service. + /// The physical application path for the web service. + /// The web service handler object. + public override IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated) + { + string filename = VirtualPathUtility.ToAbsolute(context.Request.FilePath); + string cacheKey = (string) webServiceData_GetCacheKey.Invoke(null, new object[] { filename }); + object webServiceData = context.Cache.Get(cacheKey); + if (webServiceData == null) { - scriptHandlerFactory_webServiceHandlerFactory.SetValue( - this.scriptHandlerFactory, - new WebServiceHandlerFactory()); - } + IConfigurableApplicationContext appContext = base.GetCheckedApplicationContext(url); + string appRelativeVirtualPath = WebUtils.GetAppRelativePath(url); + NamedObjectDefinition nod = FindWebObjectDefinition(appRelativeVirtualPath, appContext.ObjectFactory); - /// - /// Retrieves an instance of the - /// implementation for handling web service requests - /// for both Spring and ASP.NET AJAX 1.0 web services. - /// - /// The current HTTP context. - /// The type of HTTP request (GET or POST). - /// The url of the web service. - /// The physical application path for the web service. - /// The web service handler object. - public override IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated) - { - string filename = VirtualPathUtility.ToAbsolute(context.Request.FilePath); - string cacheKey = (string)webServiceData_GetCacheKey.Invoke(null, new object[] { filename }); - object webServiceData = context.Cache.Get(cacheKey); - if (webServiceData == null) + if (nod != null) { - IConfigurableApplicationContext appContext = base.GetCheckedApplicationContext(url); - string appRelativeVirtualPath = WebUtils.GetAppRelativePath(url); - NamedObjectDefinition nod = FindWebObjectDefinition(appRelativeVirtualPath, appContext.ObjectFactory); - - if (nod != null) + Type serviceType = null; + if (appContext.IsTypeMatch(nod.Name, typeof(WebServiceExporter))) { - Type serviceType = null; - if (appContext.IsTypeMatch(nod.Name, typeof(WebServiceExporter))) - { - WebServiceExporter wse = (WebServiceExporter)appContext.GetObject(nod.Name); - serviceType = wse.GetExportedType(); - } - else - { - serviceType = appContext.GetType(nod.Name); - } + WebServiceExporter wse = (WebServiceExporter) appContext.GetObject(nod.Name); + serviceType = wse.GetExportedType(); + } + else + { + serviceType = appContext.GetType(nod.Name); + } - object[] attrs = serviceType.GetCustomAttributes(typeof(ScriptServiceAttribute), false); - if (attrs.Length > 0) - { - webServiceData = webServiceData_ctor.Invoke(new object[] { serviceType, false }); - context.Cache.Insert(cacheKey, webServiceData); - } + object[] attrs = serviceType.GetCustomAttributes(typeof(ScriptServiceAttribute), false); + if (attrs.Length > 0) + { + webServiceData = webServiceData_ctor.Invoke(new object[] { serviceType, false }); + context.Cache.Insert(cacheKey, webServiceData); } } - - return this.scriptHandlerFactory.GetHandler(context, requestType, url, pathTranslated); } - /// - /// Enables a factory to reuse an existing handler instance. - /// - /// The object to reuse. - public override void ReleaseHandler(IHttpHandler handler) - { - this.scriptHandlerFactory.ReleaseHandler(handler); - } - - /// - /// Create a handler instance for the given URL. - /// - /// the application context corresponding to the current request - /// The instance for this request. - /// The HTTP data transfer method (GET, POST, ...) - /// The requested . - /// The physical path of the requested resource. - /// A handler instance for the current request. - protected override IHttpHandler CreateHandlerInstance( IConfigurableApplicationContext appContext, HttpContext context, string requestType, string rawUrl, string physicalPath ) - { - throw new NotSupportedException(); - } + return this.scriptHandlerFactory.GetHandler(context, requestType, url, pathTranslated); } -} + + /// + /// Enables a factory to reuse an existing handler instance. + /// + /// The object to reuse. + public override void ReleaseHandler(IHttpHandler handler) + { + this.scriptHandlerFactory.ReleaseHandler(handler); + } + + /// + /// Create a handler instance for the given URL. + /// + /// the application context corresponding to the current request + /// The instance for this request. + /// The HTTP data transfer method (GET, POST, ...) + /// The requested . + /// The physical path of the requested resource. + /// A handler instance for the current request. + protected override IHttpHandler CreateHandlerInstance(IConfigurableApplicationContext appContext, HttpContext context, string requestType, string rawUrl, string physicalPath) + { + throw new NotSupportedException(); + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Web.Mvc5/Context/Support/MvcApplicationContext.cs b/src/Spring/Spring.Web.Mvc5/Context/Support/MvcApplicationContext.cs index 202750ea..67a4c51b 100644 --- a/src/Spring/Spring.Web.Mvc5/Context/Support/MvcApplicationContext.cs +++ b/src/Spring/Spring.Web.Mvc5/Context/Support/MvcApplicationContext.cs @@ -21,123 +21,122 @@ using Microsoft.Extensions.Logging; using Spring.Core.IO; -namespace Spring.Context.Support +namespace Spring.Context.Support; + +/// +/// Application Context for ASP.NET MVC Applications +/// +public class MvcApplicationContext : AbstractXmlApplicationContext { + private readonly string[] _configurationLocations; + + private readonly IResource[] _configurationResources; + /// - /// Application Context for ASP.NET MVC Applications + /// Create a new MvcApplicationContext, loading the definitions + /// from the given XML resource. /// - public class MvcApplicationContext : AbstractXmlApplicationContext + /// The application context name. + /// Flag specifying whether to make this context case sensitive or not. + /// Names of configuration resources. + public MvcApplicationContext(string name, bool caseSensitive, params string[] configurationLocations) + : this(new MvcApplicationContextArgs(name, null, configurationLocations, null, caseSensitive)) { - private readonly string[] _configurationLocations; + } - private readonly IResource[] _configurationResources; + /// + /// Create a new MvcApplicationContext with the given parent, + /// loading the definitions from the given XML resources. + /// + /// The application context name. + /// Flag specifying whether to make this context case sensitive or not. + /// The parent context. + /// Names of configuration resources. + public MvcApplicationContext(string name, bool caseSensitive, IApplicationContext parentContext, + params string[] configurationLocations) + : this(new MvcApplicationContextArgs(name, parentContext, configurationLocations, null, caseSensitive)) + { + } - /// - /// Create a new MvcApplicationContext, loading the definitions - /// from the given XML resource. - /// - /// The application context name. - /// Flag specifying whether to make this context case sensitive or not. - /// Names of configuration resources. - public MvcApplicationContext(string name, bool caseSensitive, params string[] configurationLocations) - : this(new MvcApplicationContextArgs(name, null, configurationLocations, null, caseSensitive)) + /// + /// Initializes a new instance of the class. + /// + /// The args. + public MvcApplicationContext(MvcApplicationContextArgs args) + : base(args.Name, args.CaseSensitive, args.ParentContext) + { + _configurationLocations = args.ConfigurationLocations; + _configurationResources = args.ConfigurationResources; + + Refresh(); + + if (log.IsEnabled(LogLevel.Debug)) { + log.LogDebug("created instance " + this); } + } - /// - /// Create a new MvcApplicationContext with the given parent, - /// loading the definitions from the given XML resources. - /// - /// The application context name. - /// Flag specifying whether to make this context case sensitive or not. - /// The parent context. - /// Names of configuration resources. - public MvcApplicationContext(string name, bool caseSensitive, IApplicationContext parentContext, - params string[] configurationLocations) - : this(new MvcApplicationContextArgs(name, parentContext, configurationLocations, null, caseSensitive)) - { } + /// + /// Create a new MvcApplicationContext, loading the definitions + /// from the given XML resource. + /// + /// The application context name. + /// Flag specifying whether to make this context case sensitive or not. + /// Names of configuration resources. + /// Configuration resources. + public MvcApplicationContext(string name, bool caseSensitive, string[] configurationLocations, IResource[] configurationResources) + : this(new MvcApplicationContextArgs(name, null, configurationLocations, configurationResources, caseSensitive)) + { + } - /// - /// Initializes a new instance of the class. - /// - /// The args. - public MvcApplicationContext(MvcApplicationContextArgs args) - : base(args.Name, args.CaseSensitive, args.ParentContext) - { - _configurationLocations = args.ConfigurationLocations; - _configurationResources = args.ConfigurationResources; + /// + /// Create a new MvcApplicationContext, loading the definitions + /// from the given XML resource. + /// + /// Names of configuration resources. + public MvcApplicationContext(params string[] configurationLocations) + : this(new MvcApplicationContextArgs(string.Empty, null, configurationLocations, null, false)) + { + } - Refresh(); - - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug("created instance " + this); - } - } - - /// - /// Create a new MvcApplicationContext, loading the definitions - /// from the given XML resource. - /// - /// The application context name. - /// Flag specifying whether to make this context case sensitive or not. - /// Names of configuration resources. - /// Configuration resources. - public MvcApplicationContext(string name, bool caseSensitive, string[] configurationLocations, IResource[] configurationResources) - : this(new MvcApplicationContextArgs(name, null, configurationLocations, configurationResources, caseSensitive)) - { - } - - /// - /// Create a new MvcApplicationContext, loading the definitions - /// from the given XML resource. - /// - /// Names of configuration resources. - public MvcApplicationContext(params string[] configurationLocations) - : this(new MvcApplicationContextArgs(string.Empty, null, configurationLocations, null, false)) - { - } - - /// - /// An array of resource locations, referring to the XML object - /// definition files that this context is to be built with. - /// - /// - /// - ///

- /// Examples of the format of the various strings that would be - /// returned by accessing this property can be found in the overview - /// documentation of with the - /// class. - ///

- ///
- /// - /// An array of resource locations, or if none. - /// - protected override string[] ConfigurationLocations - { - get { return _configurationLocations; } - } - - /// - /// An array of resources that this context is to be built with. - /// - /// - /// - ///

- /// Examples of the format of the various strings that would be - /// returned by accessing this property can be found in the overview - /// documentation of with the - /// class. - ///

- ///
- /// - /// An array of s, or if none. - /// - protected override IResource[] ConfigurationResources - { - get { return _configurationResources; } - } + /// + /// An array of resource locations, referring to the XML object + /// definition files that this context is to be built with. + /// + /// + /// + ///

+ /// Examples of the format of the various strings that would be + /// returned by accessing this property can be found in the overview + /// documentation of with the + /// class. + ///

+ ///
+ /// + /// An array of resource locations, or if none. + /// + protected override string[] ConfigurationLocations + { + get { return _configurationLocations; } + } + /// + /// An array of resources that this context is to be built with. + /// + /// + /// + ///

+ /// Examples of the format of the various strings that would be + /// returned by accessing this property can be found in the overview + /// documentation of with the + /// class. + ///

+ ///
+ /// + /// An array of s, or if none. + /// + protected override IResource[] ConfigurationResources + { + get { return _configurationResources; } } } diff --git a/src/Spring/Spring.Web.Mvc5/Context/Support/MvcApplicationContextArgs.cs b/src/Spring/Spring.Web.Mvc5/Context/Support/MvcApplicationContextArgs.cs index 7bfb58f6..c0254f54 100644 --- a/src/Spring/Spring.Web.Mvc5/Context/Support/MvcApplicationContextArgs.cs +++ b/src/Spring/Spring.Web.Mvc5/Context/Support/MvcApplicationContextArgs.cs @@ -20,55 +20,51 @@ using Spring.Core.IO; -namespace Spring.Context.Support +namespace Spring.Context.Support; + +/// +/// Encapsulates arguments to the class. +/// +public class MvcApplicationContextArgs : AbstractXmlApplicationContextArgs { + private const bool DEFAULT_CASESENSITIVE = false; + private const bool DEFAULT_REFRESH = false; + /// - /// Encapsulates arguments to the class. + /// Initializes a new instance of the MvcApplicationContextArgs class. /// - public class MvcApplicationContextArgs : AbstractXmlApplicationContextArgs + public MvcApplicationContextArgs() { + CaseSensitive = DEFAULT_CASESENSITIVE; + } - private const bool DEFAULT_CASESENSITIVE = false; - private const bool DEFAULT_REFRESH = false; - - /// - /// Initializes a new instance of the MvcApplicationContextArgs class. - /// - public MvcApplicationContextArgs() - { - CaseSensitive = DEFAULT_CASESENSITIVE; - } - - /// - /// Initializes a new instance of the MvcApplicationContextArgs class. - /// - /// The name. - /// The parent context. - /// The configuration locations. - /// The configuration resources. - public MvcApplicationContextArgs(string name, IApplicationContext parentContext, string[] configurationLocations, IResource[] configurationResources) - : this(name, parentContext, configurationLocations, configurationResources, DEFAULT_CASESENSITIVE) - { } - - - /// - /// Initializes a new instance of the MvcApplicationContextArgs class. - /// - /// The name. - /// The parent context. - /// The configuration locations. - /// The configuration resources. - /// if set to true [case sensitive]. - public MvcApplicationContextArgs(string name, IApplicationContext parentContext, string[] configurationLocations, IResource[] configurationResources, bool caseSensitive) - { - Name = name; - ParentContext = parentContext; - ConfigurationLocations = configurationLocations; - ConfigurationResources = configurationResources; - CaseSensitive = caseSensitive; - Refresh = DEFAULT_REFRESH; - } - + /// + /// Initializes a new instance of the MvcApplicationContextArgs class. + /// + /// The name. + /// The parent context. + /// The configuration locations. + /// The configuration resources. + public MvcApplicationContextArgs(string name, IApplicationContext parentContext, string[] configurationLocations, IResource[] configurationResources) + : this(name, parentContext, configurationLocations, configurationResources, DEFAULT_CASESENSITIVE) + { + } + /// + /// Initializes a new instance of the MvcApplicationContextArgs class. + /// + /// The name. + /// The parent context. + /// The configuration locations. + /// The configuration resources. + /// if set to true [case sensitive]. + public MvcApplicationContextArgs(string name, IApplicationContext parentContext, string[] configurationLocations, IResource[] configurationResources, bool caseSensitive) + { + Name = name; + ParentContext = parentContext; + ConfigurationLocations = configurationLocations; + ConfigurationResources = configurationResources; + CaseSensitive = caseSensitive; + Refresh = DEFAULT_REFRESH; } } diff --git a/src/Spring/Spring.Web.Mvc5/Context/Support/MvcContextHandler.cs b/src/Spring/Spring.Web.Mvc5/Context/Support/MvcContextHandler.cs index c2e444f0..449d6848 100644 --- a/src/Spring/Spring.Web.Mvc5/Context/Support/MvcContextHandler.cs +++ b/src/Spring/Spring.Web.Mvc5/Context/Support/MvcContextHandler.cs @@ -18,13 +18,11 @@ #endregion -namespace Spring.Context.Support -{ - /// - /// Context Handler for ASP.NET MVC Applications - /// - public class MvcContextHandler : WebContextHandler - { +namespace Spring.Context.Support; - } -} +/// +/// Context Handler for ASP.NET MVC Applications +/// +public class MvcContextHandler : WebContextHandler +{ +} \ No newline at end of file diff --git a/src/Spring/Spring.Web.Mvc5/SpringActionInvoker.cs b/src/Spring/Spring.Web.Mvc5/SpringActionInvoker.cs index dae47cd8..56ae1e89 100644 --- a/src/Spring/Spring.Web.Mvc5/SpringActionInvoker.cs +++ b/src/Spring/Spring.Web.Mvc5/SpringActionInvoker.cs @@ -21,59 +21,56 @@ using System.Web.Mvc; using Spring.Context; -namespace Spring.Web.Mvc +namespace Spring.Web.Mvc; + +/// +/// ActionInvoker implementation that enables the to satisfy dependencies on ActionFilter attributes. +/// +public class SpringActionInvoker : ControllerActionInvoker { + private readonly IApplicationContext _context; + /// - /// ActionInvoker implementation that enables the to satisfy dependencies on ActionFilter attributes. + /// Initializes a new instance of the class. /// - public class SpringActionInvoker : ControllerActionInvoker + /// The IApplicationContext. + public SpringActionInvoker(IApplicationContext context) { - private readonly IApplicationContext _context; - - /// - /// Initializes a new instance of the class. - /// - /// The IApplicationContext. - public SpringActionInvoker(IApplicationContext context) - { - _context = context; - } - - /// - /// Retrieves information about the action filters. - /// - /// The controller context. - /// The action descriptor. - /// Information about the action filters. - protected override FilterInfo GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor) - { - //let the base class do the actual work as usual - var filterInfo = base.GetFilters(controllerContext, actionDescriptor); - - //configure each collection of filters using the IApplicationContext - foreach (IActionFilter filter in filterInfo.ActionFilters.Where(f => f != null)) - { - _context.ConfigureObject(filter, filter.GetType().FullName); - } - - foreach (IAuthorizationFilter filter in filterInfo.AuthorizationFilters.Where(f => f != null)) - { - _context.ConfigureObject(filter, filter.GetType().FullName); - } - - foreach (IExceptionFilter filter in filterInfo.ExceptionFilters.Where(f => f != null)) - { - _context.ConfigureObject(filter, filter.GetType().FullName); - } - - foreach (IResultFilter filter in filterInfo.ResultFilters.Where(f => f != null)) - { - _context.ConfigureObject(filter, filter.GetType().FullName); - } - - return filterInfo; - } - + _context = context; } -} + /// + /// Retrieves information about the action filters. + /// + /// The controller context. + /// The action descriptor. + /// Information about the action filters. + protected override FilterInfo GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor) + { + //let the base class do the actual work as usual + var filterInfo = base.GetFilters(controllerContext, actionDescriptor); + + //configure each collection of filters using the IApplicationContext + foreach (IActionFilter filter in filterInfo.ActionFilters.Where(f => f != null)) + { + _context.ConfigureObject(filter, filter.GetType().FullName); + } + + foreach (IAuthorizationFilter filter in filterInfo.AuthorizationFilters.Where(f => f != null)) + { + _context.ConfigureObject(filter, filter.GetType().FullName); + } + + foreach (IExceptionFilter filter in filterInfo.ExceptionFilters.Where(f => f != null)) + { + _context.ConfigureObject(filter, filter.GetType().FullName); + } + + foreach (IResultFilter filter in filterInfo.ResultFilters.Where(f => f != null)) + { + _context.ConfigureObject(filter, filter.GetType().FullName); + } + + return filterInfo; + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Web.Mvc5/SpringControllerFactory.cs b/src/Spring/Spring.Web.Mvc5/SpringControllerFactory.cs index 7ae9aa35..618a3912 100644 --- a/src/Spring/Spring.Web.Mvc5/SpringControllerFactory.cs +++ b/src/Spring/Spring.Web.Mvc5/SpringControllerFactory.cs @@ -20,127 +20,124 @@ using System.Web.Mvc; using System.Web.Routing; - using Spring.Context; using Spring.Context.Support; -namespace Spring.Web.Mvc +namespace Spring.Web.Mvc; + +/// +/// Controller Factory for ASP.NET MVC +/// +public class SpringControllerFactory : DefaultControllerFactory { + private static IApplicationContext _context; + /// - /// Controller Factory for ASP.NET MVC + /// Gets the application context. /// - public class SpringControllerFactory : DefaultControllerFactory + /// The application context. + public static IApplicationContext ApplicationContext { - private static IApplicationContext _context; - - /// - /// Gets the application context. - /// - /// The application context. - public static IApplicationContext ApplicationContext + get { - get + if (_context == null || _context.Name != ApplicationContextName) { - if (_context == null || _context.Name != ApplicationContextName) + if (string.IsNullOrEmpty(ApplicationContextName)) { - if (string.IsNullOrEmpty(ApplicationContextName)) - { - _context = ContextRegistry.GetContext(); - } - else - { - _context = ContextRegistry.GetContext(ApplicationContextName); - } + _context = ContextRegistry.GetContext(); } - - return _context; - } - } - - /// - /// Gets or sets the name of the application context. - /// - /// - /// Defaults to using the root (default) Application Context. - /// - /// The name of the application context. - public static string ApplicationContextName { get; set; } - - /// - /// Creates the specified controller by using the specified request context. - /// - /// The context of the HTTP request, which includes the HTTP context and route data. - /// The name of the controller. - /// A reference to the controller. - /// The parameter is null. - /// The parameter is null or empty. - public override IController CreateController(RequestContext requestContext, string controllerName) - { - IController controller; - - if (ApplicationContext.ContainsObjectDefinition(controllerName)) - { - controller = ApplicationContext.GetObject(controllerName) as IController; - } - else - { - controller = base.CreateController(requestContext, controllerName); - } - - AddActionInvokerTo(controller); - - return controller; - } - - /// - /// Retrieves the controller instance for the specified request context and controller type. - /// - /// The context of the HTTP request, which includes the HTTP context and route data. - /// The type of the controller. - /// The controller instance. - /// - /// is null. - /// - /// cannot be assigned. - /// An instance of cannot be created. - protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType) - { - IController controller = null; - - if (controllerType != null) - { - var controllers = ApplicationContext.GetObjectsOfType(controllerType); - if (controllers.Count > 0) + else { - controller = (IController)controllers.First().Value; + _context = ContextRegistry.GetContext(ApplicationContextName); } } - if (controller == null) - { - //pass to base class for remainder of handling if can't find it in the context - controller = base.GetControllerInstance(requestContext, controllerType); - } - - AddActionInvokerTo(controller); - - return controller; + return _context; } + } - /// - /// Adds the action invoker to the controller instance. - /// - /// The controller. - protected virtual void AddActionInvokerTo(IController controller) + /// + /// Gets or sets the name of the application context. + /// + /// + /// Defaults to using the root (default) Application Context. + /// + /// The name of the application context. + public static string ApplicationContextName { get; set; } + + /// + /// Creates the specified controller by using the specified request context. + /// + /// The context of the HTTP request, which includes the HTTP context and route data. + /// The name of the controller. + /// A reference to the controller. + /// The parameter is null. + /// The parameter is null or empty. + public override IController CreateController(RequestContext requestContext, string controllerName) + { + IController controller; + + if (ApplicationContext.ContainsObjectDefinition(controllerName)) { - if (controller == null) - return; + controller = ApplicationContext.GetObject(controllerName) as IController; + } + else + { + controller = base.CreateController(requestContext, controllerName); + } - if (typeof(Controller).IsAssignableFrom(controller.GetType())) + AddActionInvokerTo(controller); + + return controller; + } + + /// + /// Retrieves the controller instance for the specified request context and controller type. + /// + /// The context of the HTTP request, which includes the HTTP context and route data. + /// The type of the controller. + /// The controller instance. + /// + /// is null. + /// + /// cannot be assigned. + /// An instance of cannot be created. + protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType) + { + IController controller = null; + + if (controllerType != null) + { + var controllers = ApplicationContext.GetObjectsOfType(controllerType); + if (controllers.Count > 0) { - ((Controller)controller).ActionInvoker = new SpringActionInvoker(ApplicationContext); + controller = (IController) controllers.First().Value; } } + if (controller == null) + { + //pass to base class for remainder of handling if can't find it in the context + controller = base.GetControllerInstance(requestContext, controllerType); + } + + AddActionInvokerTo(controller); + + return controller; + } + + /// + /// Adds the action invoker to the controller instance. + /// + /// The controller. + protected virtual void AddActionInvokerTo(IController controller) + { + if (controller == null) + return; + + if (typeof(Controller).IsAssignableFrom(controller.GetType())) + { + ((Controller) controller).ActionInvoker = new SpringActionInvoker(ApplicationContext); + } } } diff --git a/src/Spring/Spring.Web.Mvc5/SpringMvcApplication.cs b/src/Spring/Spring.Web.Mvc5/SpringMvcApplication.cs index 4eb3b28a..45883f9c 100644 --- a/src/Spring/Spring.Web.Mvc5/SpringMvcApplication.cs +++ b/src/Spring/Spring.Web.Mvc5/SpringMvcApplication.cs @@ -20,158 +20,152 @@ using System.Web; using System.Web.Mvc; - using Spring.Context.Support; -namespace Spring.Web.Mvc +namespace Spring.Web.Mvc; + +/// +/// Spring.NET-specific HttpApplication for ASP.NET MVC integration. +/// +public abstract class SpringMvcApplication : HttpApplication { /// - /// Spring.NET-specific HttpApplication for ASP.NET MVC integration. + /// Executes custom initialization code after all event handler modules have been added. /// - public abstract class SpringMvcApplication : HttpApplication + public override void Init() { - /// - /// Executes custom initialization code after all event handler modules have been added. - /// - public override void Init() - { - base.Init(); + base.Init(); - //the Spring HTTP Module won't have built the context for us until now so we have to delay until the init - ConfigureApplicationContext(); - } + //the Spring HTTP Module won't have built the context for us until now so we have to delay until the init + ConfigureApplicationContext(); + } + + /// + /// Handles the BeginRequest event of the Application control. + /// + /// The source of the event. + /// The instance containing the event data. + protected virtual void Application_BeginRequest(object sender, EventArgs e) + { + var resolver = BuildDependencyResolver(); + RegisterDependencyResolver(resolver); + + var webApiResolver = BuildWebApiDependencyResolver(); + RegisterDependencyResolver(webApiResolver); + } + + /// + /// Builds the dependency resolver. + /// + /// The instance. + /// You must override this method in a derived class to control the manner in which the + /// is created. + protected virtual System.Web.Mvc.IDependencyResolver BuildDependencyResolver() + { + return new SpringMvcDependencyResolver(ContextRegistry.GetContext()); + } + + /// + /// Builds the dependency resolver. + /// + /// The instance. + /// You must override this method in a derived class to control the manner in which the + /// is created. + protected virtual System.Web.Http.Dependencies.IDependencyResolver BuildWebApiDependencyResolver() + { + return new SpringWebApiDependencyResolver(ContextRegistry.GetContext()); + } + + /// + /// Configures the instance. + /// + /// + /// You must override this method in a derived class to control the manner in which the + /// is configured. + /// + protected virtual void ConfigureApplicationContext() + { + } + + /// + /// Registers the DependencyResolver implementation with the MVC runtime. + /// + /// You must override this method in a derived class to control the manner in which the + /// is registered. + /// + /// + public virtual void RegisterDependencyResolver(System.Web.Mvc.IDependencyResolver resolver) + { + ThreadSafeDependencyResolverRegistrar.Register(resolver); + } + + /// + /// Registers the DependencyResolver implementation with the MVC runtime. + /// + /// You must override this method in a derived class to control the manner in which the + /// is registered. + /// + /// + public virtual void RegisterDependencyResolver(System.Web.Http.Dependencies.IDependencyResolver resolver) + { + ThreadSafeDependencyResolverRegistrar.Register(resolver); + } + + /// + /// Thread-safe class that ensures that the is registered only once. + /// + protected static class ThreadSafeDependencyResolverRegistrar + { + private static bool isMvcResolverRegistered; + private static bool isWebApiResolverRegistered; + private static readonly object Lock = new object(); /// - /// Handles the BeginRequest event of the Application control. + /// Registers the specified . /// - /// The source of the event. - /// The instance containing the event data. - protected virtual void Application_BeginRequest(object sender, EventArgs e) + /// The resolver. + public static void Register(IDependencyResolver resolver) { - var resolver = BuildDependencyResolver(); - RegisterDependencyResolver(resolver); + if (isMvcResolverRegistered) + { + return; + } - var webApiResolver = BuildWebApiDependencyResolver(); - RegisterDependencyResolver(webApiResolver); - } - - - /// - /// Builds the dependency resolver. - /// - /// The instance. - /// You must override this method in a derived class to control the manner in which the - /// is created. - protected virtual System.Web.Mvc.IDependencyResolver BuildDependencyResolver() - { - return new SpringMvcDependencyResolver(ContextRegistry.GetContext()); - } - - /// - /// Builds the dependency resolver. - /// - /// The instance. - /// You must override this method in a derived class to control the manner in which the - /// is created. - protected virtual System.Web.Http.Dependencies.IDependencyResolver BuildWebApiDependencyResolver() - { - return new SpringWebApiDependencyResolver(ContextRegistry.GetContext()); - } - - - /// - /// Configures the instance. - /// - /// - /// You must override this method in a derived class to control the manner in which the - /// is configured. - /// - protected virtual void ConfigureApplicationContext() - { - - } - - /// - /// Registers the DependencyResolver implementation with the MVC runtime. - /// - /// You must override this method in a derived class to control the manner in which the - /// is registered. - /// - /// - public virtual void RegisterDependencyResolver(System.Web.Mvc.IDependencyResolver resolver) - { - ThreadSafeDependencyResolverRegistrar.Register(resolver); - } - - /// - /// Registers the DependencyResolver implementation with the MVC runtime. - /// - /// You must override this method in a derived class to control the manner in which the - /// is registered. - /// - /// - public virtual void RegisterDependencyResolver(System.Web.Http.Dependencies.IDependencyResolver resolver) - { - ThreadSafeDependencyResolverRegistrar.Register(resolver); - } - - /// - /// Thread-safe class that ensures that the is registered only once. - /// - protected static class ThreadSafeDependencyResolverRegistrar - { - private static bool isMvcResolverRegistered; - private static bool isWebApiResolverRegistered; - private static readonly object Lock = new object(); - - /// - /// Registers the specified . - /// - /// The resolver. - public static void Register(IDependencyResolver resolver) + lock (Lock) { if (isMvcResolverRegistered) { return; } - lock (Lock) - { - if (isMvcResolverRegistered) - { - return; - } + DependencyResolver.SetResolver(resolver); - DependencyResolver.SetResolver(resolver); + isMvcResolverRegistered = true; + } + } - isMvcResolverRegistered = true; - } + /// + /// Registers the specified . + /// + /// The resolver. + public static void Register(System.Web.Http.Dependencies.IDependencyResolver resolver) + { + if (isWebApiResolverRegistered) + { + return; } - /// - /// Registers the specified . - /// - /// The resolver. - public static void Register(System.Web.Http.Dependencies.IDependencyResolver resolver) + lock (Lock) { if (isWebApiResolverRegistered) { return; } - lock (Lock) - { - if (isWebApiResolverRegistered) - { - return; - } + System.Web.Http.GlobalConfiguration.Configuration.DependencyResolver = resolver; - System.Web.Http.GlobalConfiguration.Configuration.DependencyResolver = resolver; - - isWebApiResolverRegistered = true; - } + isWebApiResolverRegistered = true; } } - } } diff --git a/src/Spring/Spring.Web.Mvc5/SpringMvcDependencyResolver.cs b/src/Spring/Spring.Web.Mvc5/SpringMvcDependencyResolver.cs index e613dd68..8107541b 100644 --- a/src/Spring/Spring.Web.Mvc5/SpringMvcDependencyResolver.cs +++ b/src/Spring/Spring.Web.Mvc5/SpringMvcDependencyResolver.cs @@ -4,137 +4,135 @@ using Microsoft.Extensions.Logging; using Spring.Context; using Spring.Context.Support; -namespace Spring.Web.Mvc +namespace Spring.Web.Mvc; + +/// +/// Spring-based implementation of the interface for ASP.NET MVC. +/// +public class SpringMvcDependencyResolver : IDependencyResolver { + private static readonly string IgnoreViewNamespace = "ASP."; + /// - /// Spring-based implementation of the interface for ASP.NET MVC. + /// The to be used by the resolver /// - public class SpringMvcDependencyResolver : IDependencyResolver + private IApplicationContext _context; + + private static readonly ILogger logger = LogManager.GetLogger(); + private readonly ConcurrentBag _nonResolvableTypes = new ConcurrentBag(); + private readonly ConcurrentDictionary _resolvedNames = new ConcurrentDictionary(); + + /// + /// Initializes a new instance of the class. + /// + /// The to be used by the resolver + public SpringMvcDependencyResolver(IApplicationContext context) { - private static readonly string IgnoreViewNamespace = "ASP."; + _context = context; + } - /// - /// The to be used by the resolver - /// - private IApplicationContext _context; - - private static readonly ILogger logger = LogManager.GetLogger(); - private readonly ConcurrentBag _nonResolvableTypes = new ConcurrentBag(); - private readonly ConcurrentDictionary _resolvedNames = new ConcurrentDictionary(); - - /// - /// Initializes a new instance of the class. - /// - /// The to be used by the resolver - public SpringMvcDependencyResolver(IApplicationContext context) + /// + /// Gets the application context. + /// + /// The application context. + public IApplicationContext ApplicationContext + { + get { - _context = context; - } - - - /// - /// Gets the application context. - /// - /// The application context. - public IApplicationContext ApplicationContext - { - get + if (_context == null || _context.Name != ApplicationContextName) { - if (_context == null || _context.Name != ApplicationContextName) + if (string.IsNullOrEmpty(ApplicationContextName)) { - if (string.IsNullOrEmpty(ApplicationContextName)) - { - _context = ContextRegistry.GetContext(); - } - else - { - _context = ContextRegistry.GetContext(ApplicationContextName); - } - } - - return _context; - } - protected set { _context = value; } - } - - /// - /// Gets or sets the name of the application context. - /// - /// - /// Defaults to using the root (default) Application Context. - /// - /// The name of the application context. - public string ApplicationContextName { get; set; } - - - /// - /// Resolves singly registered services that support arbitrary object creation. - /// - /// The type of the requested service or object. - /// The requested service or object. - public object GetService(Type serviceType) - { - object service = null; - - if (serviceType != null) - { - //if its an MVC auto-generated View Class... - if (serviceType.FullName.StartsWith(IgnoreViewNamespace)) - { - return null; - } - - //if we already know the container has tried and failed to resolve the type prior... - if (_nonResolvableTypes.Contains(serviceType)) - { - return null; - } - - // fastest lookup is if we have direct name match - if (ApplicationContext.ContainsObjectDefinition(serviceType.Name)) - { - service = ApplicationContext.GetObject(serviceType.Name); + _context = ContextRegistry.GetContext(); } else { - string resolvedName; - if (_resolvedNames.TryGetValue(serviceType, out resolvedName)) - { - service = ApplicationContext.GetObject(resolvedName); - } - else - { - // fall back to more expensive searching with type - var matchingServices = ApplicationContext.GetObjectNamesForType(serviceType); - if (matchingServices.Count > 0) - { - _resolvedNames.TryAdd(serviceType, matchingServices[0]); - service = ApplicationContext.GetObject(matchingServices[0]); - } - } + _context = ContextRegistry.GetContext(ApplicationContextName); } + } - if (service == null) + return _context; + } + protected set { _context = value; } + } + + /// + /// Gets or sets the name of the application context. + /// + /// + /// Defaults to using the root (default) Application Context. + /// + /// The name of the application context. + public string ApplicationContextName { get; set; } + + /// + /// Resolves singly registered services that support arbitrary object creation. + /// + /// The type of the requested service or object. + /// The requested service or object. + public object GetService(Type serviceType) + { + object service = null; + + if (serviceType != null) + { + //if its an MVC auto-generated View Class... + if (serviceType.FullName.StartsWith(IgnoreViewNamespace)) + { + return null; + } + + //if we already know the container has tried and failed to resolve the type prior... + if (_nonResolvableTypes.Contains(serviceType)) + { + return null; + } + + // fastest lookup is if we have direct name match + if (ApplicationContext.ContainsObjectDefinition(serviceType.Name)) + { + service = ApplicationContext.GetObject(serviceType.Name); + } + else + { + string resolvedName; + if (_resolvedNames.TryGetValue(serviceType, out resolvedName)) { - _nonResolvableTypes.Add(serviceType); - - if (logger.IsEnabled(LogLevel.Debug)) + service = ApplicationContext.GetObject(resolvedName); + } + else + { + // fall back to more expensive searching with type + var matchingServices = ApplicationContext.GetObjectNamesForType(serviceType); + if (matchingServices.Count > 0) { - logger.LogDebug("Could not find service from Spring container with type: {ServiceType}", serviceType); + _resolvedNames.TryAdd(serviceType, matchingServices[0]); + service = ApplicationContext.GetObject(matchingServices[0]); } } } - return service; + + if (service == null) + { + _nonResolvableTypes.Add(serviceType); + + if (logger.IsEnabled(LogLevel.Debug)) + { + logger.LogDebug("Could not find service from Spring container with type: {ServiceType}", serviceType); + } + } } - /// - /// Resolves multiply registered services. - /// - /// The type of the requested services. - /// The requested services. - public IEnumerable GetServices(Type serviceType) - { - return ApplicationContext.GetObjectsOfType(serviceType).Values; - } + return service; } -} + + /// + /// Resolves multiply registered services. + /// + /// The type of the requested services. + /// The requested services. + public IEnumerable GetServices(Type serviceType) + { + return ApplicationContext.GetObjectsOfType(serviceType).Values; + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Web.Mvc5/SpringWebApiDependencyResolver.cs b/src/Spring/Spring.Web.Mvc5/SpringWebApiDependencyResolver.cs index 52f03a07..5d970803 100644 --- a/src/Spring/Spring.Web.Mvc5/SpringWebApiDependencyResolver.cs +++ b/src/Spring/Spring.Web.Mvc5/SpringWebApiDependencyResolver.cs @@ -1,141 +1,137 @@ using System.Web.Http.Dependencies; - using Spring.Context; using Spring.Context.Support; using Spring.Core.IO; +namespace Spring.Web.Mvc; -namespace Spring.Web.Mvc +/// +/// Spring-based implementation of the interface for ASP.NET MVC Web API. +/// +public class SpringWebApiDependencyResolver : SpringMvcDependencyResolver, System.Web.Http.Dependencies.IDependencyResolver { /// - /// Spring-based implementation of the interface for ASP.NET MVC Web API. + /// Initializes a new instance of the class. /// - public class SpringWebApiDependencyResolver : SpringMvcDependencyResolver, System.Web.Http.Dependencies.IDependencyResolver + /// The to be used by the resolver + public SpringWebApiDependencyResolver(IApplicationContext context) + : base(context) { - /// - /// Initializes a new instance of the class. - /// - /// The to be used by the resolver - public SpringWebApiDependencyResolver(IApplicationContext context) - : base(context) - { - } + } + /// + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// + public virtual void Dispose() + { + //no unmanaged resources to dispose + } - /// - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - /// - public virtual void Dispose() + /// + /// + /// + /// The initialized instance. + /// + public virtual IDependencyScope BeginScope() + { + if (HasApplicationContext && (HasChildApplicationContextConfigurationLocations || HasChildApplicationContextConfigurationResources)) { - //no unmanaged resources to dispose - } - - /// - /// - /// - /// The initialized instance. - /// - public virtual IDependencyScope BeginScope() - { - if (HasApplicationContext && (HasChildApplicationContextConfigurationLocations || HasChildApplicationContextConfigurationResources)) + string[] configurationLocations = null; + if (HasChildApplicationContextConfigurationLocations) { - string[] configurationLocations = null; - if (HasChildApplicationContextConfigurationLocations) - { - configurationLocations = ChildApplicationContextConfigurationLocations.ToArray(); - } - - IResource[] configurationResources = null; - if (HasChildApplicationContextConfigurationResources) - { - configurationResources = ChildApplicationContextConfigurationResources.ToArray(); - } - - var childContextName = string.Format("child_of_{0}", ApplicationContext.Name); - var args = new MvcApplicationContextArgs(childContextName, ApplicationContext, configurationLocations, configurationResources, false); - - var childContext = new MvcApplicationContext(args); - var newResolver = new SpringWebApiDependencyResolver(childContext) { ApplicationContextName = childContextName }; - - RegisterContextIfNeeded(childContext); - - return newResolver; - } - else - { - return this; - } - } - - private void RegisterContextIfNeeded(IApplicationContext childContext) - { - if (!ContextRegistry.IsContextRegistered(childContext.Name)) - { - ContextRegistry.RegisterContext(childContext); - } - } - - private bool HasChildApplicationContextConfigurationResources - { - get - { - return ChildApplicationContextConfigurationResources != null && - ChildApplicationContextConfigurationResources.Count > 0; - } - } - - private bool HasChildApplicationContextConfigurationLocations - { - get - { - return ChildApplicationContextConfigurationLocations != null && - ChildApplicationContextConfigurationLocations.Count > 0; - } - } - - private bool HasApplicationContext - { - get { return ApplicationContext != null; } - } - - /// - /// Gets or sets the child configuration locations. - /// - /// The child configuration locations. - public virtual IList ChildApplicationContextConfigurationLocations { protected get; set; } - - /// - /// Gets or sets the child configuration resources. - /// - /// The child configuration resources. - public virtual IList ChildApplicationContextConfigurationResources { protected get; set; } - - /// - /// Adds the child configuration resource. - /// - /// The resource. - public virtual void AddChildApplicationContextConfigurationResource(IResource resource) - { - if (null == ChildApplicationContextConfigurationResources) - { - ChildApplicationContextConfigurationResources = new List(); + configurationLocations = ChildApplicationContextConfigurationLocations.ToArray(); } - ChildApplicationContextConfigurationResources.Add(resource); - } - - /// - /// Adds the child configuration location. - /// - /// The location. - public virtual void AddChildApplicationContextConfigurationLocation(string location) - { - if (null == ChildApplicationContextConfigurationLocations) + IResource[] configurationResources = null; + if (HasChildApplicationContextConfigurationResources) { - ChildApplicationContextConfigurationLocations = new List(); + configurationResources = ChildApplicationContextConfigurationResources.ToArray(); } - ChildApplicationContextConfigurationLocations.Add(location); + var childContextName = string.Format("child_of_{0}", ApplicationContext.Name); + var args = new MvcApplicationContextArgs(childContextName, ApplicationContext, configurationLocations, configurationResources, false); + + var childContext = new MvcApplicationContext(args); + var newResolver = new SpringWebApiDependencyResolver(childContext) { ApplicationContextName = childContextName }; + + RegisterContextIfNeeded(childContext); + + return newResolver; + } + else + { + return this; } } + + private void RegisterContextIfNeeded(IApplicationContext childContext) + { + if (!ContextRegistry.IsContextRegistered(childContext.Name)) + { + ContextRegistry.RegisterContext(childContext); + } + } + + private bool HasChildApplicationContextConfigurationResources + { + get + { + return ChildApplicationContextConfigurationResources != null && + ChildApplicationContextConfigurationResources.Count > 0; + } + } + + private bool HasChildApplicationContextConfigurationLocations + { + get + { + return ChildApplicationContextConfigurationLocations != null && + ChildApplicationContextConfigurationLocations.Count > 0; + } + } + + private bool HasApplicationContext + { + get { return ApplicationContext != null; } + } + + /// + /// Gets or sets the child configuration locations. + /// + /// The child configuration locations. + public virtual IList ChildApplicationContextConfigurationLocations { protected get; set; } + + /// + /// Gets or sets the child configuration resources. + /// + /// The child configuration resources. + public virtual IList ChildApplicationContextConfigurationResources { protected get; set; } + + /// + /// Adds the child configuration resource. + /// + /// The resource. + public virtual void AddChildApplicationContextConfigurationResource(IResource resource) + { + if (null == ChildApplicationContextConfigurationResources) + { + ChildApplicationContextConfigurationResources = new List(); + } + + ChildApplicationContextConfigurationResources.Add(resource); + } + + /// + /// Adds the child configuration location. + /// + /// The location. + public virtual void AddChildApplicationContextConfigurationLocation(string location) + { + if (null == ChildApplicationContextConfigurationLocations) + { + ChildApplicationContextConfigurationLocations = new List(); + } + + ChildApplicationContextConfigurationLocations.Add(location); + } } diff --git a/src/Spring/Spring.Web/Caching/AspNetCache.cs b/src/Spring/Spring.Web/Caching/AspNetCache.cs index 5a7fea65..afa8ffeb 100644 --- a/src/Spring/Spring.Web/Caching/AspNetCache.cs +++ b/src/Spring/Spring.Web/Caching/AspNetCache.cs @@ -24,285 +24,286 @@ using System.Web.Caching; using Microsoft.Extensions.Logging; using Spring.Util; -namespace Spring.Caching +namespace Spring.Caching; + +/// +/// An implementation backed by ASP.NET Cache (see ). +/// +/// +/// +/// Because ASP.NET Cache uses strings as cache keys, you need to ensure +/// that the key object type has properly implemented ToString method. +/// +/// +/// Despite the shared underlying , it is possible to use more than +/// one instance of without interfering each other. +/// +/// +/// Aleksandar Seovic +/// Erich Eichinger +public class AspNetCache : AbstractCache { + #region Internal Abstractions + /// - /// An implementation backed by ASP.NET Cache (see ). + /// Abstracts the underlying runtime cache /// - /// - /// - /// Because ASP.NET Cache uses strings as cache keys, you need to ensure - /// that the key object type has properly implemented ToString method. - /// - /// - /// Despite the shared underlying , it is possible to use more than - /// one instance of without interfering each other. - /// - /// - /// Aleksandar Seovic - /// Erich Eichinger - public class AspNetCache : AbstractCache + public interface IRuntimeCache : IEnumerable { - #region Internal Abstractions - /// - /// Abstracts the underlying runtime cache + /// Insert an item into the cache. /// - public interface IRuntimeCache : IEnumerable - { - /// - /// Insert an item into the cache. - /// - void Insert(string key, object value, CacheDependency dependencies, DateTime absoluteExpiration, - TimeSpan slidingExpiration, CacheItemPriority priority, CacheItemRemovedCallback onRemoveCallback); - - /// - /// Removes an item from the cache. - /// - /// The key of the item to remove - /// The object that has been removed from the cache - object Remove(string key); - - /// - /// Retrieve an item with the specified key from the cache. - /// - /// The key of the item to be retrieved - /// The item, if found. null otherwise - object Get(string key); - } - - /// - /// Actually delegates all calls to the underlying - /// - private class RuntimeCache : IRuntimeCache - { - private readonly Cache _runtimeCache = HttpRuntime.Cache; - - public object Remove(string key) - { - return _runtimeCache.Remove(key); - } - - public void Insert(string key, object value, CacheDependency dependencies, DateTime absoluteExpiration, TimeSpan slidingExpiration, CacheItemPriority priority, CacheItemRemovedCallback onRemoveCallback ) - { - _runtimeCache.Insert(key, value, dependencies, absoluteExpiration, slidingExpiration, priority, onRemoveCallback); - } - - public object Get(string key) - { - return _runtimeCache.Get(key); - } - - public IEnumerator GetEnumerator() - { - return _runtimeCache.GetEnumerator(); - } - } - - #endregion - - #region Fields - - // logger instance for this class - private static readonly ILogger Log = LogManager.GetLogger(); - // the concrete cache implementation - private readonly IRuntimeCache _cache; - // the (unique!) name of this particular cache instance. - private readonly string _cacheName; - - // hold default values for this cache instance. - private CacheItemPriority _priority = CacheItemPriority.Default; - private bool _slidingExpiration = false; - - #endregion - - /// - /// Initializes a new instance of - /// - public AspNetCache() - :this(new RuntimeCache()) - { - } - - /// - /// Initializes a new instance of - /// with the specified implementation. - /// - /// - public AspNetCache(IRuntimeCache runtimeCache) - { - _cache = runtimeCache; - // noop - _cacheName = typeof(AspNetCache).FullName + "[" + this.GetHashCode() + "]."; - } - - #region Configurable Properties - - /// - /// Gets/Sets a flag, whether to use sliding expiration policy. - /// - public bool SlidingExpiration - { - get { return _slidingExpiration; } - set { _slidingExpiration = value; } - } - - /// - /// Gets/Sets a default priority to be applied to all items inserted into this cache. - /// - public CacheItemPriority Priority - { - get { return _priority; } - set { _priority = value; } - } - - #endregion - - /// - /// Gets a collection of all cache item keys. - /// - public override ICollection Keys - { - get - { - List keys = new List(); - - foreach (DictionaryEntry entry in _cache) - { - string key = (string) entry.Key; - if (key.StartsWith(_cacheName)) - { - keys.Add(key.Substring(_cacheName.Length)); - } - } - - return keys; - } - } - - /// - /// Retrieves an item from the cache. - /// - /// - /// Item key. - /// - /// - /// Item for the specified , or null. - /// - public override object Get(object key) - { - return key == null ? null : _cache.Get(GenerateKey(key)); - } + void Insert(string key, object value, CacheDependency dependencies, DateTime absoluteExpiration, + TimeSpan slidingExpiration, CacheItemPriority priority, CacheItemRemovedCallback onRemoveCallback); /// /// Removes an item from the cache. /// - /// - /// Item key. - /// - public override void Remove(object key) + /// The key of the item to remove + /// The object that has been removed from the cache + object Remove(string key); + + /// + /// Retrieve an item with the specified key from the cache. + /// + /// The key of the item to be retrieved + /// The item, if found. null otherwise + object Get(string key); + } + + /// + /// Actually delegates all calls to the underlying + /// + private class RuntimeCache : IRuntimeCache + { + private readonly Cache _runtimeCache = HttpRuntime.Cache; + + public object Remove(string key) { - if (key != null) + return _runtimeCache.Remove(key); + } + + public void Insert(string key, object value, CacheDependency dependencies, DateTime absoluteExpiration, TimeSpan slidingExpiration, CacheItemPriority priority, CacheItemRemovedCallback onRemoveCallback) + { + _runtimeCache.Insert(key, value, dependencies, absoluteExpiration, slidingExpiration, priority, onRemoveCallback); + } + + public object Get(string key) + { + return _runtimeCache.Get(key); + } + + public IEnumerator GetEnumerator() + { + return _runtimeCache.GetEnumerator(); + } + } + + #endregion + + #region Fields + + // logger instance for this class + private static readonly ILogger Log = LogManager.GetLogger(); + + // the concrete cache implementation + private readonly IRuntimeCache _cache; + + // the (unique!) name of this particular cache instance. + private readonly string _cacheName; + + // hold default values for this cache instance. + private CacheItemPriority _priority = CacheItemPriority.Default; + private bool _slidingExpiration = false; + + #endregion + + /// + /// Initializes a new instance of + /// + public AspNetCache() + : this(new RuntimeCache()) + { + } + + /// + /// Initializes a new instance of + /// with the specified implementation. + /// + /// + public AspNetCache(IRuntimeCache runtimeCache) + { + _cache = runtimeCache; + // noop + _cacheName = typeof(AspNetCache).FullName + "[" + this.GetHashCode() + "]."; + } + + #region Configurable Properties + + /// + /// Gets/Sets a flag, whether to use sliding expiration policy. + /// + public bool SlidingExpiration + { + get { return _slidingExpiration; } + set { _slidingExpiration = value; } + } + + /// + /// Gets/Sets a default priority to be applied to all items inserted into this cache. + /// + public CacheItemPriority Priority + { + get { return _priority; } + set { _priority = value; } + } + + #endregion + + /// + /// Gets a collection of all cache item keys. + /// + public override ICollection Keys + { + get + { + List keys = new List(); + + foreach (DictionaryEntry entry in _cache) { - if (Log.IsEnabled(LogLevel.Debug)) Log.LogDebug(string.Format("removing item '{0}' from cache '{1}'", key, this._cacheName)); - _cache.Remove(GenerateKey(key)); + string key = (string) entry.Key; + if (key.StartsWith(_cacheName)) + { + keys.Add(key.Substring(_cacheName.Length)); + } } + + return keys; } + } - /// - /// Inserts an item into the cache. - /// - /// - /// Items inserted using this method have default and default - /// - /// - /// Item key. - /// - /// - /// Item value. - /// - /// - /// Item's time-to-live (TTL). - /// - protected override void DoInsert(object key, object value, TimeSpan timeToLive) + /// + /// Retrieves an item from the cache. + /// + /// + /// Item key. + /// + /// + /// Item for the specified , or null. + /// + public override object Get(object key) + { + return key == null ? null : _cache.Get(GenerateKey(key)); + } + + /// + /// Removes an item from the cache. + /// + /// + /// Item key. + /// + public override void Remove(object key) + { + if (key != null) { - this.Insert( key, value, timeToLive, _slidingExpiration, _priority ); + if (Log.IsEnabled(LogLevel.Debug)) Log.LogDebug(string.Format("removing item '{0}' from cache '{1}'", key, this._cacheName)); + _cache.Remove(GenerateKey(key)); } + } - /// - /// Inserts an item into the cache. - /// - /// - /// Item key. - /// - /// - /// Item value. - /// - /// - /// Item's time-to-live. - /// - /// - /// Flag specifying whether the item's time-to-live should be reset - /// when the item is accessed. - /// - public void Insert(object key, object value, TimeSpan timeToLive, bool slidingExpiration) + /// + /// Inserts an item into the cache. + /// + /// + /// Items inserted using this method have default and default + /// + /// + /// Item key. + /// + /// + /// Item value. + /// + /// + /// Item's time-to-live (TTL). + /// + protected override void DoInsert(object key, object value, TimeSpan timeToLive) + { + this.Insert(key, value, timeToLive, _slidingExpiration, _priority); + } + + /// + /// Inserts an item into the cache. + /// + /// + /// Item key. + /// + /// + /// Item value. + /// + /// + /// Item's time-to-live. + /// + /// + /// Flag specifying whether the item's time-to-live should be reset + /// when the item is accessed. + /// + public void Insert(object key, object value, TimeSpan timeToLive, bool slidingExpiration) + { + this.Insert(key, value, timeToLive, slidingExpiration, _priority); + } + + /// + /// Inserts an item into the cache. + /// + /// + /// Item key. + /// + /// + /// Item value. + /// + /// + /// Item's time-to-live. + /// + /// + /// Flag specifying whether the item's time-to-live should be reset + /// when the item is accessed. + /// + /// + /// Item priority. + /// + public void Insert(object key, object value, TimeSpan timeToLive, bool slidingExpiration, CacheItemPriority itemPriority) + { + AssertUtils.ArgumentNotNull(key, "key"); + AssertUtils.State(TimeSpan.Zero <= timeToLive, "timeToLive"); + + if (Log.IsEnabled(LogLevel.Debug)) Log.LogDebug(string.Format("adding item '{0}' to cache '{1}'", key, this._cacheName)); + + if (TimeSpan.Zero < timeToLive) { - this.Insert(key, value, timeToLive, slidingExpiration, _priority); - } - - /// - /// Inserts an item into the cache. - /// - /// - /// Item key. - /// - /// - /// Item value. - /// - /// - /// Item's time-to-live. - /// - /// - /// Flag specifying whether the item's time-to-live should be reset - /// when the item is accessed. - /// - /// - /// Item priority. - /// - public void Insert(object key, object value, TimeSpan timeToLive, bool slidingExpiration, CacheItemPriority itemPriority) - { - AssertUtils.ArgumentNotNull(key, "key"); - AssertUtils.State( TimeSpan.Zero <= timeToLive, "timeToLive" ); - - if (Log.IsEnabled(LogLevel.Debug)) Log.LogDebug(string.Format("adding item '{0}' to cache '{1}'", key, this._cacheName)); - - if (TimeSpan.Zero < timeToLive) + if (slidingExpiration) { - if (slidingExpiration) - { - TimeSpan slidingExpirationSpan = timeToLive; - _cache.Insert(GenerateKey(key), value, null, Cache.NoAbsoluteExpiration, slidingExpirationSpan, itemPriority, null); - } - else - { - DateTime absoluteExpiration = DateTime.UtcNow.Add(timeToLive); - _cache.Insert(GenerateKey(key), value, null, absoluteExpiration, Cache.NoSlidingExpiration, itemPriority, null); - } + TimeSpan slidingExpirationSpan = timeToLive; + _cache.Insert(GenerateKey(key), value, null, Cache.NoAbsoluteExpiration, slidingExpirationSpan, itemPriority, null); } else { - _cache.Insert(GenerateKey(key), value, null, Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, itemPriority, null); + DateTime absoluteExpiration = DateTime.UtcNow.Add(timeToLive); + _cache.Insert(GenerateKey(key), value, null, absoluteExpiration, Cache.NoSlidingExpiration, itemPriority, null); } } - - /// - /// Generate a key to be used for the underlying implementation. - /// - /// - /// - public string GenerateKey( object key ) + else { - return _cacheName + key; + _cache.Insert(GenerateKey(key), value, null, Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, itemPriority, null); } } -} + + /// + /// Generate a key to be used for the underlying implementation. + /// + /// + /// + public string GenerateKey(object key) + { + return _cacheName + key; + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Web/Context/Support/HttpApplicationConfigurer.cs b/src/Spring/Spring.Web/Context/Support/HttpApplicationConfigurer.cs index 49992549..fbbd9101 100644 --- a/src/Spring/Spring.Web/Context/Support/HttpApplicationConfigurer.cs +++ b/src/Spring/Spring.Web/Context/Support/HttpApplicationConfigurer.cs @@ -28,121 +28,121 @@ using Spring.Util; #endregion -namespace Spring.Context.Support +namespace Spring.Context.Support; + +/// +/// +/// +/// Erich Eichinger +public class HttpApplicationConfigurer { - /// - /// - /// - /// Erich Eichinger - public class HttpApplicationConfigurer + private static readonly ILogger Log = LogManager.GetLogger(); + + #region ModuleDefinitionsTable class + + private class ModuleDefinitionsTable : Hashtable { - private static readonly ILogger Log = LogManager.GetLogger(); - - #region ModuleDefinitionsTable class - - private class ModuleDefinitionsTable : Hashtable + public void Add(string key, IObjectDefinition value) { - public void Add(string key, IObjectDefinition value) + lock (SyncRoot) { - lock(SyncRoot) - { - base[key] = value; - } + base[key] = value; } + } - public IObjectDefinition this[string key] + public IObjectDefinition this[string key] + { + get { - get + lock (SyncRoot) { - lock (SyncRoot) - { - return (IObjectDefinition) base[key]; - } - } - } - - public override void Add(object key, object value) - { - AssertUtils.AssertArgumentType(key, "key", typeof(string), "Key must be a string"); - AssertUtils.AssertArgumentType(value, "value", typeof(IObjectDefinition), "Key must be a string"); - this.Add((string)key, (IObjectDefinition)value); - } - - public override object this[object key] - { - get - { - return this[(string)key]; + return (IObjectDefinition) base[key]; } } } - #endregion - - /// - /// Holds shared application Template - /// - private static volatile IObjectDefinition s_applicationDefinition = null; - /// - /// Holds shared modules Templates - /// - private static readonly ModuleDefinitionsTable s_moduleDefinitions = new ModuleDefinitionsTable(); - - /// - /// Gets or Sets the shared application template - /// - public IObjectDefinition ApplicationTemplate + public override void Add(object key, object value) { - // no need for lock because of "volatile" - get { return s_applicationDefinition; } - set { s_applicationDefinition = value; } + AssertUtils.AssertArgumentType(key, "key", typeof(string), "Key must be a string"); + AssertUtils.AssertArgumentType(value, "value", typeof(IObjectDefinition), "Key must be a string"); + this.Add((string) key, (IObjectDefinition) value); } - /// - /// Gets the dictionary of shared module templates - /// - /// - /// to synchronize access to the dictionary, use property. - /// - public IDictionary ModuleTemplates + public override object this[object key] { - get { return s_moduleDefinitions; } - } - - /// - /// Configures the instance and its modules. - /// - /// - /// When called, configures using the instance - /// provided in and the templates available in - /// and . - /// - /// the application context instance to be used for resolving object references. - /// the instance to be configured. - public static void Configure(IConfigurableApplicationContext appContext, HttpApplication app) - { - IObjectDefinition applicationDefinition = s_applicationDefinition; - if (s_applicationDefinition != null) - { - appContext.ObjectFactory.ConfigureObject(app, "ApplicationTemplate", applicationDefinition); - } - - lock(s_moduleDefinitions.SyncRoot) + get { - HttpModuleCollection modules = app.Modules; - foreach(DictionaryEntry moduleEntry in s_moduleDefinitions) + return this[(string) key]; + } + } + } + + #endregion + + /// + /// Holds shared application Template + /// + private static volatile IObjectDefinition s_applicationDefinition = null; + + /// + /// Holds shared modules Templates + /// + private static readonly ModuleDefinitionsTable s_moduleDefinitions = new ModuleDefinitionsTable(); + + /// + /// Gets or Sets the shared application template + /// + public IObjectDefinition ApplicationTemplate + { + // no need for lock because of "volatile" + get { return s_applicationDefinition; } + set { s_applicationDefinition = value; } + } + + /// + /// Gets the dictionary of shared module templates + /// + /// + /// to synchronize access to the dictionary, use property. + /// + public IDictionary ModuleTemplates + { + get { return s_moduleDefinitions; } + } + + /// + /// Configures the instance and its modules. + /// + /// + /// When called, configures using the instance + /// provided in and the templates available in + /// and . + /// + /// the application context instance to be used for resolving object references. + /// the instance to be configured. + public static void Configure(IConfigurableApplicationContext appContext, HttpApplication app) + { + IObjectDefinition applicationDefinition = s_applicationDefinition; + if (s_applicationDefinition != null) + { + appContext.ObjectFactory.ConfigureObject(app, "ApplicationTemplate", applicationDefinition); + } + + lock (s_moduleDefinitions.SyncRoot) + { + HttpModuleCollection modules = app.Modules; + foreach (DictionaryEntry moduleEntry in s_moduleDefinitions) + { + string moduleName = (string) moduleEntry.Key; + IObjectDefinition od = s_moduleDefinitions[moduleName]; + IHttpModule module = modules[moduleName]; + if (module != null) { - string moduleName = (string) moduleEntry.Key; - IObjectDefinition od = s_moduleDefinitions[moduleName]; - IHttpModule module = modules[moduleName]; - if (module != null) - { - appContext.ObjectFactory.ConfigureObject(module, moduleName, od); - } - else - { - throw ConfigurationUtils.CreateConfigurationException(string.Format("failed applying module template '{0}' - no matching module found", moduleName)); - } + appContext.ObjectFactory.ConfigureObject(module, moduleName, od); + } + else + { + throw ConfigurationUtils.CreateConfigurationException(string.Format("failed applying module template '{0}' - no matching module found", moduleName)); } } } diff --git a/src/Spring/Spring.Web/Context/Support/WebApplicationContext.cs b/src/Spring/Spring.Web/Context/Support/WebApplicationContext.cs index b2d54c1e..242e7ee1 100644 --- a/src/Spring/Spring.Web/Context/Support/WebApplicationContext.cs +++ b/src/Spring/Spring.Web/Context/Support/WebApplicationContext.cs @@ -32,395 +32,398 @@ using Spring.Reflection.Dynamic; using Spring.Util; using Spring.Core.IO; -namespace Spring.Context.Support +namespace Spring.Context.Support; + +/// +/// Web application context, taking the context definition files +/// from the file system or from URLs. +/// +/// Treats resource paths as web resources, when using +/// IApplicationContext.GetResource. Resource paths are considered relative +/// to the virtual directory. +/// +/// Note: In case of multiple config locations, later object definitions will +/// override ones defined in earlier loaded files. This can be leveraged to +/// deliberately override certain object definitions via an extra XML file. +/// +/// Aleksandar Seovic +public class WebApplicationContext : AbstractXmlApplicationContext { + // holds construction info for debugging output + private DateTime _constructionTimeStamp; + private string _constructionUrl; + + private readonly string[] _configurationLocations; + private readonly IResource[] _configurationResources; + /// - /// Web application context, taking the context definition files - /// from the file system or from URLs. - /// - /// Treats resource paths as web resources, when using - /// IApplicationContext.GetResource. Resource paths are considered relative - /// to the virtual directory. - /// - /// Note: In case of multiple config locations, later object definitions will - /// override ones defined in earlier loaded files. This can be leveraged to - /// deliberately override certain object definitions via an extra XML file. + /// Create a new WebApplicationContext, loading the definitions + /// from the given XML resource. /// - /// Aleksandar Seovic - public class WebApplicationContext : AbstractXmlApplicationContext + /// Names of configuration resources. + public WebApplicationContext(params string[] configurationLocations) + : this(new WebApplicationContextArgs(string.Empty, null, configurationLocations, null, false)) { - // holds construction info for debugging output - private DateTime _constructionTimeStamp; - private string _constructionUrl; + } - private readonly string[] _configurationLocations; - private readonly IResource[] _configurationResources; + /// + /// Create a new WebApplicationContext, loading the definitions + /// from the given XML resource. + /// + /// The application context name. + /// Flag specifying whether to make this context case sensitive or not. + /// Names of configuration resources. + public WebApplicationContext(string name, bool caseSensitive, params string[] configurationLocations) + : this(new WebApplicationContextArgs(name, null, configurationLocations, null, caseSensitive)) + { + } - /// - /// Create a new WebApplicationContext, loading the definitions - /// from the given XML resource. - /// - /// Names of configuration resources. - public WebApplicationContext(params string[] configurationLocations) - : this(new WebApplicationContextArgs(string.Empty, null, configurationLocations, null, false)) + /// + /// Create a new WebApplicationContext, loading the definitions + /// from the given XML resource. + /// + /// The application context name. + /// Flag specifying whether to make this context case sensitive or not. + /// Names of configuration resources. + /// Configuration resources. + public WebApplicationContext(string name, bool caseSensitive, string[] configurationLocations, IResource[] configurationResources) + : this(new WebApplicationContextArgs(name, null, configurationLocations, configurationResources, caseSensitive)) + { + } + + /// + /// Create a new WebApplicationContext with the given parent, + /// loading the definitions from the given XML resources. + /// + /// The application context name. + /// Flag specifying whether to make this context case sensitive or not. + /// The parent context. + /// Names of configuration resources. + public WebApplicationContext(string name, bool caseSensitive, IApplicationContext parentContext, + params string[] configurationLocations) + : this(new WebApplicationContextArgs(name, parentContext, configurationLocations, null, caseSensitive)) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The args. + public WebApplicationContext(WebApplicationContextArgs args) + : base(args.Name, args.CaseSensitive, args.ParentContext) + { + _configurationLocations = args.ConfigurationLocations; + _configurationResources = args.ConfigurationResources; + + DefaultResourceProtocol = WebUtils.DEFAULT_RESOURCE_PROTOCOL; + Refresh(); + + // remember creation info for debug output + this._constructionTimeStamp = DateTime.Now; + this._constructionUrl = VirtualEnvironment.CurrentVirtualPathAndQuery; + if (log.IsEnabled(LogLevel.Debug)) { + log.LogDebug("created instance " + this.ToString()); } + } - /// - /// Create a new WebApplicationContext, loading the definitions - /// from the given XML resource. - /// - /// The application context name. - /// Flag specifying whether to make this context case sensitive or not. - /// Names of configuration resources. - public WebApplicationContext(string name, bool caseSensitive, params string[] configurationLocations) - : this(new WebApplicationContextArgs(name, null, configurationLocations, null, caseSensitive)) - { - } + /// + /// returns detailed instance information for debugging + /// + /// + public override string ToString() + { + //return base.ToString() + " - created on " + _constructionTimeStamp + "\n\ncreated by:" + _constructionUrl + "\n" + _constructionStackTrace.ToString(); + return string.Format("[{0}]:{1}({2})", this.Name, this.GetType().Name, base.GetHashCode().ToString()); + } - /// - /// Create a new WebApplicationContext, loading the definitions - /// from the given XML resource. - /// - /// The application context name. - /// Flag specifying whether to make this context case sensitive or not. - /// Names of configuration resources. - /// Configuration resources. - public WebApplicationContext(string name, bool caseSensitive, string[] configurationLocations, IResource[] configurationResources) - : this(new WebApplicationContextArgs(name, null, configurationLocations, configurationResources, caseSensitive)) - { - } + /// + /// Since the HttpRuntime discards it's configurationsection cache, we maintain our own context cache. + /// Despite it really speeds up context-lookup, since we don't have to go through the whole HttpConfigurationSystem + /// + private static readonly Hashtable s_webContextCache = new CaseInsensitiveHashtable(); - /// - /// Create a new WebApplicationContext with the given parent, - /// loading the definitions from the given XML resources. - /// - /// The application context name. - /// Flag specifying whether to make this context case sensitive or not. - /// The parent context. - /// Names of configuration resources. - public WebApplicationContext(string name, bool caseSensitive, IApplicationContext parentContext, - params string[] configurationLocations) - : this(new WebApplicationContextArgs(name, parentContext, configurationLocations, null, caseSensitive)) - { } + static WebApplicationContext() + { + ILogger s_weblog = LogManager.GetLogger(); - - /// - /// Initializes a new instance of the class. - /// - /// The args. - public WebApplicationContext(WebApplicationContextArgs args) - : base(args.Name, args.CaseSensitive, args.ParentContext) - { - _configurationLocations = args.ConfigurationLocations; - _configurationResources = args.ConfigurationResources; - - DefaultResourceProtocol = WebUtils.DEFAULT_RESOURCE_PROTOCOL; - Refresh(); - - // remember creation info for debug output - this._constructionTimeStamp = DateTime.Now; - this._constructionUrl = VirtualEnvironment.CurrentVirtualPathAndQuery; - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug("created instance " + this.ToString()); - } - } - - - /// - /// returns detailed instance information for debugging - /// - /// - public override string ToString() - { - //return base.ToString() + " - created on " + _constructionTimeStamp + "\n\ncreated by:" + _constructionUrl + "\n" + _constructionStackTrace.ToString(); - return string.Format("[{0}]:{1}({2})", this.Name, this.GetType().Name, base.GetHashCode().ToString()); - } - - - /// - /// Since the HttpRuntime discards it's configurationsection cache, we maintain our own context cache. - /// Despite it really speeds up context-lookup, since we don't have to go through the whole HttpConfigurationSystem - /// - private static readonly Hashtable s_webContextCache = new CaseInsensitiveHashtable(); - - static WebApplicationContext() - { - ILogger s_weblog = LogManager.GetLogger(); - - // register for ContextRegistry.Cleared event - we need to discard our cache in this case - ContextRegistry.Cleared += OnContextRegistryCleared; + // register for ContextRegistry.Cleared event - we need to discard our cache in this case + ContextRegistry.Cleared += OnContextRegistryCleared; #if !MONO_2_0 - if (HttpRuntime.AppDomainAppVirtualPath != null) // check if we're within an ASP.NET AppDomain! - { - // ensure HttpRuntime has been fully initialized! - // this is a problem,.if ASP.NET Web Administration Application is used. This app does not fully set up the AppDomain... - HttpRuntime runtime = - (HttpRuntime) - typeof(HttpRuntime).GetField("_theRuntime", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null); + if (HttpRuntime.AppDomainAppVirtualPath != null) // check if we're within an ASP.NET AppDomain! + { + // ensure HttpRuntime has been fully initialized! + // this is a problem,.if ASP.NET Web Administration Application is used. This app does not fully set up the AppDomain... + HttpRuntime runtime = + (HttpRuntime) + typeof(HttpRuntime).GetField("_theRuntime", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null); - bool beforeFirstRequest = false; - lock (runtime) + bool beforeFirstRequest = false; + lock (runtime) + { + beforeFirstRequest = + (bool) + typeof(HttpRuntime).GetField("_beforeFirstRequest", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(runtime); + } + + s_weblog.LogDebug("BeforeFirstRequest:" + beforeFirstRequest); + if (beforeFirstRequest) + { + try { - beforeFirstRequest = - (bool) - typeof(HttpRuntime).GetField("_beforeFirstRequest", BindingFlags.Instance | BindingFlags.NonPublic). - GetValue(runtime); + string firstRequestPath = HttpRuntime.AppDomainAppVirtualPath.TrimEnd('/') + "/dummy.context"; + s_weblog.LogInformation("Forcing first request " + firstRequestPath); + SafeMethod fnProcessRequestNow = new SafeMethod(typeof(HttpRuntime).GetMethod("ProcessRequestNow", BindingFlags.Static | BindingFlags.NonPublic)); + SimpleWorkerRequest wr = new SimpleWorkerRequest(firstRequestPath, string.Empty, new StringWriter()); + fnProcessRequestNow.Invoke(null, new object[] { wr }); + // HttpRuntime.ProcessRequest( + // wr); + s_weblog.LogInformation("Successfully processed first request!"); } - s_weblog.LogDebug("BeforeFirstRequest:" + beforeFirstRequest); - if (beforeFirstRequest) + catch (Exception ex) { + s_weblog.LogError(ex, "Failed processing first request"); + throw; + } + } + } +#endif + } + + /// + /// EventHandler for ContextRegistry.Cleared event. Discards webContextCache. + /// + private static void OnContextRegistryCleared(object sender, EventArgs ev) + { + lock (s_webContextCache) + { + ILogger s_weblog = LogManager.GetLogger(); + if (s_weblog.IsEnabled(LogLevel.Debug)) + { + s_weblog.LogDebug("received ContextRegistry.Cleared event - clearing webContextCache"); + } + + s_webContextCache.Clear(); + } + } + + /// + /// Returns the root context of this web application + /// + public static IApplicationContext GetRootContext() + { + return GetContextInternal(("" + HttpRuntime.AppDomainAppVirtualPath).TrimEnd('/') + "/dummy.context"); + } + + /// + /// Returns the web application context for the given (absolute!) virtual path + /// + public static IApplicationContext GetContext(string virtualPath) + { + return GetContextInternal(virtualPath); + } + + /// + /// Returns the web application context for the current request's filepath + /// + public static IApplicationContext Current + { + get + { + string requestUrl = VirtualEnvironment.CurrentVirtualFilePath; + return GetContextInternal(requestUrl); + } + } + + private static IApplicationContext GetContextInternal(string virtualPath) + { + string virtualDirectory = WebUtils.GetVirtualDirectory(virtualPath); + string contextName = virtualDirectory; + if (0 == string.Compare(contextName, ("" + HttpRuntime.AppDomainAppVirtualPath).TrimEnd('/') + "/", true)) + { + contextName = DefaultRootContextName; + } + + ILogger s_weblog = LogManager.GetLogger(); + bool isLogDebugEnabled = s_weblog.IsEnabled(LogLevel.Debug); + + lock (s_webContextCache) + { + if (isLogDebugEnabled) + { + s_weblog.LogDebug(string.Format("looking up web context '{0}' in WebContextCache", contextName)); + } + + // first lookup in our own cache + IApplicationContext context = (IApplicationContext) s_webContextCache[contextName]; + if (context != null) + { + // found - nothing to do anymore + if (isLogDebugEnabled) + { + s_weblog.LogDebug(string.Format("returning WebContextCache hit '{0}' for vpath '{1}' ", context, contextName)); + } + + return context; + } + + // lookup ContextRegistry + lock (ContextRegistry.SyncRoot) + { + if (isLogDebugEnabled) + { + s_weblog.LogDebug(string.Format("looking up web context '{0}' in ContextRegistry", contextName)); + } + + if (ContextRegistry.IsContextRegistered(contextName)) + { + context = ContextRegistry.GetContext(contextName); + } + + if (context == null) + { + // finally ask HttpConfigurationSystem for the requested context try { - string firstRequestPath = HttpRuntime.AppDomainAppVirtualPath.TrimEnd('/') + "/dummy.context"; - s_weblog.LogInformation("Forcing first request " + firstRequestPath); - SafeMethod fnProcessRequestNow = new SafeMethod(typeof(HttpRuntime).GetMethod("ProcessRequestNow", BindingFlags.Static | BindingFlags.NonPublic)); - SimpleWorkerRequest wr = new SimpleWorkerRequest(firstRequestPath, string.Empty, new StringWriter()); - fnProcessRequestNow.Invoke(null, new object[] { wr }); - // HttpRuntime.ProcessRequest( - // wr); - s_weblog.LogInformation("Successfully processed first request!"); + if (isLogDebugEnabled) + { + s_weblog.LogDebug(string.Format( + "web context for vpath '{0}' not found. Force creation using filepath '{1}'", + contextName, virtualPath)); + } + + // assure context is resolved to the given virtualDirectory + using (new HttpContextSwitch(virtualDirectory)) + { + context = (IApplicationContext) ConfigurationUtils.GetSection(ContextSectionName); + } + + if (context != null) + { + if (isLogDebugEnabled) + s_weblog.LogDebug(string.Format("got context '{0}' for vpath '{1}'", context, contextName)); + } + else + { + if (isLogDebugEnabled) + s_weblog.LogDebug(string.Format("no context defined for vpath '{0}'", contextName)); + } } catch (Exception ex) { - s_weblog.LogError(ex, "Failed processing first request"); + if (s_weblog.IsEnabled(LogLevel.Error)) + { + string message = string.Format("failed creating context '{0}', Stacktrace:\n{1}", contextName, new StackTrace()); + s_weblog.LogError(ex, message); + } + throw; } } } -#endif - } - /// - /// EventHandler for ContextRegistry.Cleared event. Discards webContextCache. - /// - private static void OnContextRegistryCleared(object sender, EventArgs ev) - { - lock (s_webContextCache) + // add it to the cache + // Note: use 'contextName' not 'context.Name' here - the same context may be used for different paths! + s_webContextCache.Add(contextName, context); + if (isLogDebugEnabled) { - ILogger s_weblog = LogManager.GetLogger(); - if (s_weblog.IsEnabled(LogLevel.Debug)) - { - s_weblog.LogDebug("received ContextRegistry.Cleared event - clearing webContextCache"); - } - s_webContextCache.Clear(); - } - } - - /// - /// Returns the root context of this web application - /// - public static IApplicationContext GetRootContext() - { - return GetContextInternal(("" + HttpRuntime.AppDomainAppVirtualPath).TrimEnd('/') + "/dummy.context"); - } - - /// - /// Returns the web application context for the given (absolute!) virtual path - /// - public static IApplicationContext GetContext(string virtualPath) - { - return GetContextInternal(virtualPath); - } - - /// - /// Returns the web application context for the current request's filepath - /// - public static IApplicationContext Current - { - get - { - string requestUrl = VirtualEnvironment.CurrentVirtualFilePath; - return GetContextInternal(requestUrl); - } - } - - private static IApplicationContext GetContextInternal(string virtualPath) - { - string virtualDirectory = WebUtils.GetVirtualDirectory(virtualPath); - string contextName = virtualDirectory; - if (0 == string.Compare(contextName, ("" + HttpRuntime.AppDomainAppVirtualPath).TrimEnd('/') + "/", true)) - { - contextName = DefaultRootContextName; + s_weblog.LogDebug(string.Format("added context '{0}' to WebContextCache for vpath '{1}'", context, contextName)); } - ILogger s_weblog = LogManager.GetLogger(); - bool isLogDebugEnabled = s_weblog.IsEnabled(LogLevel.Debug); - - lock (s_webContextCache) + if (context != null) { - if (isLogDebugEnabled) + // register this context and all ParentContexts by their name - parent contexts may be additionally created by the HttpRuntime + IApplicationContext parentContext = context; + while (parentContext != null) { - s_weblog.LogDebug(string.Format("looking up web context '{0}' in WebContextCache", contextName)); - } - // first lookup in our own cache - IApplicationContext context = (IApplicationContext)s_webContextCache[contextName]; - if (context != null) - { - // found - nothing to do anymore - if (isLogDebugEnabled) + if (!s_webContextCache.ContainsKey(parentContext.Name)) { - s_weblog.LogDebug(string.Format("returning WebContextCache hit '{0}' for vpath '{1}' ", context, contextName)); - } - return context; - } - - // lookup ContextRegistry - lock (ContextRegistry.SyncRoot) - { - if (isLogDebugEnabled) - { - s_weblog.LogDebug(string.Format("looking up web context '{0}' in ContextRegistry", contextName)); - } - - if (ContextRegistry.IsContextRegistered(contextName)) - { - context = ContextRegistry.GetContext(contextName); - } - - if (context == null) - { - // finally ask HttpConfigurationSystem for the requested context - try + s_webContextCache.Add(parentContext.Name, parentContext); + if (isLogDebugEnabled) { - if (isLogDebugEnabled) - { - s_weblog.LogDebug(string.Format( - "web context for vpath '{0}' not found. Force creation using filepath '{1}'", - contextName, virtualPath)); - } - - // assure context is resolved to the given virtualDirectory - using (new HttpContextSwitch(virtualDirectory)) - { - context = (IApplicationContext)ConfigurationUtils.GetSection(ContextSectionName); - } - - if (context != null) - { - if (isLogDebugEnabled) - s_weblog.LogDebug(string.Format("got context '{0}' for vpath '{1}'", context, contextName)); - } - else - { - if (isLogDebugEnabled) - s_weblog.LogDebug(string.Format("no context defined for vpath '{0}'", contextName)); - } - } - catch (Exception ex) - { - if (s_weblog.IsEnabled(LogLevel.Error)) - { - string message = string.Format("failed creating context '{0}', Stacktrace:\n{1}", contextName, new StackTrace()); - s_weblog.LogError(ex, message); - } - - throw; + s_weblog.LogDebug(string.Format("added parent context '{0}' to WebContextCache for vpath '{1}'", + parentContext, parentContext.Name)); } } + + parentContext = parentContext.ParentContext; } - - // add it to the cache - // Note: use 'contextName' not 'context.Name' here - the same context may be used for different paths! - s_webContextCache.Add(contextName, context); - if (isLogDebugEnabled) - { - s_weblog.LogDebug(string.Format("added context '{0}' to WebContextCache for vpath '{1}'", context, contextName)); - } - - if (context != null) - { - // register this context and all ParentContexts by their name - parent contexts may be additionally created by the HttpRuntime - IApplicationContext parentContext = context; - while (parentContext != null) - { - if (!s_webContextCache.ContainsKey(parentContext.Name)) - { - s_webContextCache.Add(parentContext.Name, parentContext); - if (isLogDebugEnabled) - { - s_weblog.LogDebug(string.Format("added parent context '{0}' to WebContextCache for vpath '{1}'", - parentContext, parentContext.Name)); - } - } - parentContext = parentContext.ParentContext; - } - } - return context; - } // lock(s_webContextCache) - } - - /// - /// Initializes object definition reader. - /// - /// Reader to initialize. - protected override void InitObjectDefinitionReader(XmlObjectDefinitionReader objectDefinitionReader) - { - // NamespaceParserRegistry.RegisterParser(typeof(WebObjectsNamespaceParser)); - } - - /// - /// An array of resource locations, referring to the XML object - /// definition files with which this context is to be built. - /// - /// - /// An array of resource locations, or if none. - /// - /// - protected override string[] ConfigurationLocations - { - get { return _configurationLocations; } - } - - /// - /// An array of resources instances with which this context is to be built. - /// - /// - /// An array of s, or if none. - /// - /// - protected override IResource[] ConfigurationResources - { - get { return _configurationResources; } - } - - /// - /// Creates web object factory for this context using parent context's factory as a parent. - /// - /// Web object factory to use. - protected override DefaultListableObjectFactory CreateObjectFactory() - { - string contextPath = GetContextPathWithTrailingSlash(); - return new WebObjectFactory(contextPath, this.IsCaseSensitive, GetInternalParentObjectFactory()); - } - - /// - /// Returns the application-relative virtual path of this context (without leading '~'!). - /// - /// - private string GetContextPathWithTrailingSlash() - { - string contextPath = this.Name; - if (contextPath == DefaultRootContextName) - { - contextPath = "/"; } - else - { - contextPath = contextPath + "/"; - } - return contextPath; + + return context; + } // lock(s_webContextCache) + } + + /// + /// Initializes object definition reader. + /// + /// Reader to initialize. + protected override void InitObjectDefinitionReader(XmlObjectDefinitionReader objectDefinitionReader) + { + // NamespaceParserRegistry.RegisterParser(typeof(WebObjectsNamespaceParser)); + } + + /// + /// An array of resource locations, referring to the XML object + /// definition files with which this context is to be built. + /// + /// + /// An array of resource locations, or if none. + /// + /// + protected override string[] ConfigurationLocations + { + get { return _configurationLocations; } + } + + /// + /// An array of resources instances with which this context is to be built. + /// + /// + /// An array of s, or if none. + /// + /// + protected override IResource[] ConfigurationResources + { + get { return _configurationResources; } + } + + /// + /// Creates web object factory for this context using parent context's factory as a parent. + /// + /// Web object factory to use. + protected override DefaultListableObjectFactory CreateObjectFactory() + { + string contextPath = GetContextPathWithTrailingSlash(); + return new WebObjectFactory(contextPath, this.IsCaseSensitive, GetInternalParentObjectFactory()); + } + + /// + /// Returns the application-relative virtual path of this context (without leading '~'!). + /// + /// + private string GetContextPathWithTrailingSlash() + { + string contextPath = this.Name; + if (contextPath == DefaultRootContextName) + { + contextPath = "/"; + } + else + { + contextPath = contextPath + "/"; } - /// - /// Create a reader instance capable of handling web objects (Pages,Controls) for importing o - /// bject definitions into the specified . - /// - protected override XmlObjectDefinitionReader CreateXmlObjectDefinitionReader(DefaultListableObjectFactory objectFactory) - { - return new WebObjectDefinitionReader(GetContextPathWithTrailingSlash(), objectFactory, new XmlUrlResolver()); - } + return contextPath; + } + + /// + /// Create a reader instance capable of handling web objects (Pages,Controls) for importing o + /// bject definitions into the specified . + /// + protected override XmlObjectDefinitionReader CreateXmlObjectDefinitionReader(DefaultListableObjectFactory objectFactory) + { + return new WebObjectDefinitionReader(GetContextPathWithTrailingSlash(), objectFactory, new XmlUrlResolver()); } } diff --git a/src/Spring/Spring.Web/Context/Support/WebApplicationContextArgs.cs b/src/Spring/Spring.Web/Context/Support/WebApplicationContextArgs.cs index 126b94bc..0d9c3e48 100644 --- a/src/Spring/Spring.Web/Context/Support/WebApplicationContextArgs.cs +++ b/src/Spring/Spring.Web/Context/Support/WebApplicationContextArgs.cs @@ -20,55 +20,51 @@ using Spring.Core.IO; -namespace Spring.Context.Support +namespace Spring.Context.Support; + +/// +/// Encapsulates arguments to the class. +/// +public class WebApplicationContextArgs : AbstractXmlApplicationContextArgs { + private const bool DEFAULT_CASESENSITIVE = false; + private const bool DEFAULT_REFRESH = false; + /// - /// Encapsulates arguments to the class. + /// Initializes a new instance of the WebApplicationContextArgs class. /// - public class WebApplicationContextArgs : AbstractXmlApplicationContextArgs + public WebApplicationContextArgs() { + CaseSensitive = DEFAULT_CASESENSITIVE; + } - private const bool DEFAULT_CASESENSITIVE = false; - private const bool DEFAULT_REFRESH = false; - - /// - /// Initializes a new instance of the WebApplicationContextArgs class. - /// - public WebApplicationContextArgs() - { - CaseSensitive = DEFAULT_CASESENSITIVE; - } - - /// - /// Initializes a new instance of the WebApplicationContextArgs class. - /// - /// The name. - /// The parent context. - /// The configuration locations. - /// The configuration resources. - public WebApplicationContextArgs(string name, IApplicationContext parentContext, string[] configurationLocations, IResource[] configurationResources) - : this(name, parentContext, configurationLocations, configurationResources, DEFAULT_CASESENSITIVE) - { } - - - /// - /// Initializes a new instance of the WebApplicationContextArgs class. - /// - /// The name. - /// The parent context. - /// The configuration locations. - /// The configuration resources. - /// if set to true [case sensitive]. - public WebApplicationContextArgs(string name, IApplicationContext parentContext, string[] configurationLocations, IResource[] configurationResources, bool caseSensitive) - { - Name = name; - ParentContext = parentContext; - ConfigurationLocations = configurationLocations; - ConfigurationResources = configurationResources; - CaseSensitive = caseSensitive; - Refresh = DEFAULT_REFRESH; - } - + /// + /// Initializes a new instance of the WebApplicationContextArgs class. + /// + /// The name. + /// The parent context. + /// The configuration locations. + /// The configuration resources. + public WebApplicationContextArgs(string name, IApplicationContext parentContext, string[] configurationLocations, IResource[] configurationResources) + : this(name, parentContext, configurationLocations, configurationResources, DEFAULT_CASESENSITIVE) + { + } + /// + /// Initializes a new instance of the WebApplicationContextArgs class. + /// + /// The name. + /// The parent context. + /// The configuration locations. + /// The configuration resources. + /// if set to true [case sensitive]. + public WebApplicationContextArgs(string name, IApplicationContext parentContext, string[] configurationLocations, IResource[] configurationResources, bool caseSensitive) + { + Name = name; + ParentContext = parentContext; + ConfigurationLocations = configurationLocations; + ConfigurationResources = configurationResources; + CaseSensitive = caseSensitive; + Refresh = DEFAULT_REFRESH; } } diff --git a/src/Spring/Spring.Web/Context/Support/WebContextHandler.cs b/src/Spring/Spring.Web/Context/Support/WebContextHandler.cs index c6c972d0..70b3ce63 100644 --- a/src/Spring/Spring.Web/Context/Support/WebContextHandler.cs +++ b/src/Spring/Spring.Web/Context/Support/WebContextHandler.cs @@ -27,106 +27,108 @@ using Spring.Util; #endregion -namespace Spring.Context.Support +namespace Spring.Context.Support; + +/// +/// Creates an instance +/// using context definitions supplied in a custom configuration and +/// configures the with that instance. +/// +/// +/// This class extends ContextHandler with +/// web specific behaviour. It uses WebApplicationContext +/// as default Context-Type. +/// +/// Erich Eichinger +public class WebContextHandler : ContextHandler { + private static readonly ILogger Log = LogManager.GetLogger(); + /// - /// Creates an instance - /// using context definitions supplied in a custom configuration and - /// configures the with that instance. + /// Sets default context type to + /// + protected override Type DefaultApplicationContextType + { + get { return typeof(WebApplicationContext); } + } + + /// + /// Sets default case-sensitivity to 'false' for web-applications + /// + protected override bool DefaultCaseSensitivity + { + get { return false; } + } + + /// + /// Gets the context name from the given + /// + protected override string GetContextName(object configContext, XmlElement contextElement) + { + string contextName = GetVirtualPath(configContext); + // NET 2.0 returns "/" for root path + if (contextName == "/") + { + contextName = String.Empty; + } + + return contextName; + } + + /// + /// Throws a configuration exception, if child contexts are specified. /// /// - /// This class extends ContextHandler with - /// web specific behaviour. It uses WebApplicationContext - /// as default Context-Type. + /// Nesting contexts in webapplications is done by explicitly declaring + /// spring context sections for each directory. /// - /// Erich Eichinger - public class WebContextHandler : ContextHandler + protected override void CreateChildContexts(IApplicationContext parentContext, object configContext, IList childContexts) { - private static readonly ILogger Log = LogManager.GetLogger(); - - /// - /// Sets default context type to - /// - protected override Type DefaultApplicationContextType + // disable child contexts in webapps + if (childContexts.Count > 0) { - get { return typeof(WebApplicationContext); } - } - - /// - /// Sets default case-sensitivity to 'false' for web-applications - /// - protected override bool DefaultCaseSensitivity - { - get { return false; } - } - - /// - /// Gets the context name from the given - /// - protected override string GetContextName(object configContext, XmlElement contextElement) - { - string contextName = GetVirtualPath(configContext); - // NET 2.0 returns "/" for root path - if (contextName == "/") - { - contextName = String.Empty; - } - return contextName; - } - - /// - /// Throws a configuration exception, if child contexts are specified. - /// - /// - /// Nesting contexts in webapplications is done by explicitly declaring - /// spring context sections for each directory. - /// - protected override void CreateChildContexts(IApplicationContext parentContext, object configContext, IList childContexts) - { - // disable child contexts in webapps - if (childContexts.Count > 0) - { - throw ConfigurationUtils.CreateConfigurationException( - String.Format("Nested Child Contexts are not allowed in Web Applications. Use Web.config hierarchy instead."), childContexts[0]); - } - } - - /// - /// Handles web specific details of context instantiation. - /// - protected override IApplicationContext InstantiateContext(IApplicationContext parent, object configContext, string contextName, Type contextType, bool caseSensitive, IList resources) - { - // ASP.NET may scavenge it's configuration section cache if memory usage is too high. - // Thus a handler may be called more than once for the same context. - // Return registered context in this case. - if (ContextRegistry.IsContextRegistered(contextName)) - { - IApplicationContext ctx = ContextRegistry.GetContext(contextName); - if (Log.IsEnabled(LogLevel.Debug)) - { - Log.LogDebug(string.Format("web context '{0}' already registered - returning existing instance {1}", - contextName, ctx)); - } - return ctx; - } - - // for rewriting path during context instantiation - string vpath = GetVirtualPath(configContext); - if (!vpath.EndsWith("/")) vpath = vpath + "/"; - using (new HttpContextSwitch(vpath)) - { - return base.InstantiateContext(parent, configContext, contextName, contextType, caseSensitive, resources); - } - } - - private String GetVirtualPath(Object configContext) - { - HttpConfigurationContext httpConfigurationContext = (HttpConfigurationContext)configContext; - if (httpConfigurationContext != null) - { - return httpConfigurationContext.VirtualPath; - } - return String.Empty; + throw ConfigurationUtils.CreateConfigurationException( + String.Format("Nested Child Contexts are not allowed in Web Applications. Use Web.config hierarchy instead."), childContexts[0]); } } + + /// + /// Handles web specific details of context instantiation. + /// + protected override IApplicationContext InstantiateContext(IApplicationContext parent, object configContext, string contextName, Type contextType, bool caseSensitive, IList resources) + { + // ASP.NET may scavenge it's configuration section cache if memory usage is too high. + // Thus a handler may be called more than once for the same context. + // Return registered context in this case. + if (ContextRegistry.IsContextRegistered(contextName)) + { + IApplicationContext ctx = ContextRegistry.GetContext(contextName); + if (Log.IsEnabled(LogLevel.Debug)) + { + Log.LogDebug(string.Format("web context '{0}' already registered - returning existing instance {1}", + contextName, ctx)); + } + + return ctx; + } + + // for rewriting path during context instantiation + string vpath = GetVirtualPath(configContext); + if (!vpath.EndsWith("/")) vpath = vpath + "/"; + using (new HttpContextSwitch(vpath)) + { + return base.InstantiateContext(parent, configContext, contextName, contextType, caseSensitive, resources); + } + } + + private String GetVirtualPath(Object configContext) + { + HttpConfigurationContext httpConfigurationContext = (HttpConfigurationContext) configContext; + if (httpConfigurationContext != null) + { + return httpConfigurationContext.VirtualPath; + } + + return String.Empty; + } } diff --git a/src/Spring/Spring.Web/Context/Support/WebSupportModule.cs b/src/Spring/Spring.Web/Context/Support/WebSupportModule.cs index 35919782..6f17711e 100644 --- a/src/Spring/Spring.Web/Context/Support/WebSupportModule.cs +++ b/src/Spring/Spring.Web/Context/Support/WebSupportModule.cs @@ -36,342 +36,343 @@ using Spring.Threading; using Spring.Util; using Spring.Web.Support; -namespace Spring.Context.Support +namespace Spring.Context.Support; + +/// +/// Provides various support for proper handling requests. +/// +/// Erich Eichinger +public class WebSupportModule : IHttpModule { /// - /// Provides various support for proper handling requests. + /// Identifies the Objectdefinition used for the current IHttpHandler instance in TLS /// - /// Erich Eichinger - public class WebSupportModule : IHttpModule + private static readonly string CURRENTHANDLER_OBJECTDEFINITION = "__spring.web" + new Guid().ToString(); + + /// + /// Holds the handler configuration information. + /// + private class HandlerConfigurationMetaData { - /// - /// Identifies the Objectdefinition used for the current IHttpHandler instance in TLS - /// - private static readonly string CURRENTHANDLER_OBJECTDEFINITION = "__spring.web" + new Guid().ToString(); + public readonly IConfigurableApplicationContext ApplicationContext; + public readonly string ObjectDefinitionName; + public readonly bool IsContainerManaged; - /// - /// Holds the handler configuration information. - /// - private class HandlerConfigurationMetaData + public HandlerConfigurationMetaData(IConfigurableApplicationContext applicationContext, string objectDefinitionName, bool isContainerManaged) { - public readonly IConfigurableApplicationContext ApplicationContext; - public readonly string ObjectDefinitionName; - public readonly bool IsContainerManaged; - - public HandlerConfigurationMetaData(IConfigurableApplicationContext applicationContext, string objectDefinitionName, bool isContainerManaged) - { - ApplicationContext = applicationContext; - ObjectDefinitionName = objectDefinitionName; - IsContainerManaged = isContainerManaged; - } + ApplicationContext = applicationContext; + ObjectDefinitionName = objectDefinitionName; + IsContainerManaged = isContainerManaged; } + } - private static readonly ILogger s_log; + private static readonly ILogger s_log; - private static bool s_isInitialized = false; + private static bool s_isInitialized = false; - // Required for Session End event handling - private static int CACHEKEYPREFIXLENGTH = 0; - private static CacheItemRemovedCallback s_originalCallback; + // Required for Session End event handling + private static int CACHEKEYPREFIXLENGTH = 0; + private static CacheItemRemovedCallback s_originalCallback; + + // required to enable accessing HttpContext.Request during IHttpModule.Init() in integrated mode + private static readonly FieldInfo fiHideRequestResponse; + private static readonly SafeField ContextHideRequestResponse; + + /// + /// For webapplications always + ///
    + ///
  • convert IResources using the current context.
  • + ///
  • use "web" as default resource protocol
  • + ///
  • use as default threading storage
  • + ///
+ ///
+ static WebSupportModule() + { + s_log = LogManager.GetLogger(typeof(WebSupportModule)); // required to enable accessing HttpContext.Request during IHttpModule.Init() in integrated mode - private static readonly FieldInfo fiHideRequestResponse; - private static readonly SafeField ContextHideRequestResponse; - - /// - /// For webapplications always - ///
    - ///
  • convert IResources using the current context.
  • - ///
  • use "web" as default resource protocol
  • - ///
  • use as default threading storage
  • - ///
- ///
- static WebSupportModule() + ContextHideRequestResponse = null; + try { - s_log = LogManager.GetLogger(typeof(WebSupportModule)); - - // required to enable accessing HttpContext.Request during IHttpModule.Init() in integrated mode - ContextHideRequestResponse = null; - try - { - fiHideRequestResponse = typeof(HttpContext).GetField("HideRequestResponse", BindingFlags.Instance|BindingFlags.NonPublic); + fiHideRequestResponse = typeof(HttpContext).GetField("HideRequestResponse", BindingFlags.Instance | BindingFlags.NonPublic); // fiHideRequestResponse.SetValue(HttpContext.Current, false); - ContextHideRequestResponse = (fiHideRequestResponse!=null)?new SafeField(fiHideRequestResponse):null; - } - catch(SecurityException sec) - { - s_log.LogWarning(string.Format("failed reflecting field HttpContext.HideRequestResponse due to security restrictions {0}", sec)); - } - - // register additional resource handler - ResourceHandlerRegistry.RegisterResourceHandler(WebUtils.DEFAULT_RESOURCE_PROTOCOL, typeof(WebResource)); - // replace default IResource converter - TypeConverterRegistry.RegisterConverter(typeof(IResource), - new ResourceConverter( - new ConfigurableResourceLoader(WebUtils.DEFAULT_RESOURCE_PROTOCOL))); - // default to hybrid thread storage implementation - LogicalThreadContext.SetStorage(new HybridContextStorage()); - - s_log.LogDebug("Set default resource protocol to 'web' and installed HttpContext-aware HybridContextStorage"); + ContextHideRequestResponse = (fiHideRequestResponse != null) ? new SafeField(fiHideRequestResponse) : null; + } + catch (SecurityException sec) + { + s_log.LogWarning(string.Format("failed reflecting field HttpContext.HideRequestResponse due to security restrictions {0}", sec)); } - /// - /// Registers this module for all events required by the Spring.Web framework - /// - public virtual void Init(HttpApplication app) + // register additional resource handler + ResourceHandlerRegistry.RegisterResourceHandler(WebUtils.DEFAULT_RESOURCE_PROTOCOL, typeof(WebResource)); + // replace default IResource converter + TypeConverterRegistry.RegisterConverter(typeof(IResource), + new ResourceConverter( + new ConfigurableResourceLoader(WebUtils.DEFAULT_RESOURCE_PROTOCOL))); + // default to hybrid thread storage implementation + LogicalThreadContext.SetStorage(new HybridContextStorage()); + + s_log.LogDebug("Set default resource protocol to 'web' and installed HttpContext-aware HybridContextStorage"); + } + + /// + /// Registers this module for all events required by the Spring.Web framework + /// + public virtual void Init(HttpApplication app) + { + lock (typeof(WebSupportModule)) { - lock (typeof(WebSupportModule)) + s_log.LogDebug("Initializing Application instance"); + if (!s_isInitialized) { - s_log.LogDebug("Initializing Application instance"); - if (!s_isInitialized) + HttpModuleCollection modules = app.Modules; + foreach (string moduleKey in modules.AllKeys) { - HttpModuleCollection modules = app.Modules; - foreach (string moduleKey in modules.AllKeys) + if (modules[moduleKey] is SessionStateModule) { - if (modules[moduleKey] is SessionStateModule) - { - HookSessionEvent((SessionStateModule)modules[moduleKey]); - } + HookSessionEvent((SessionStateModule) modules[moduleKey]); } } - s_isInitialized = true; - - // signal, that VirtualEnvironment is ready to accept - // handler registrations for EndRequest and EndSession events - VirtualEnvironment.SetInitialized(); } - app.PreRequestHandlerExecute += OnConfigureHandler; - app.EndRequest += VirtualEnvironment.RaiseEndRequest; + s_isInitialized = true; - // TODO: this is only a workaround to get us up & running in IIS7/integrated mode - // We must review all code for relative virtual paths - they must be resolved to application-relative paths - // during parsing of the object definitions - bool hideRequestResponse = false; - if (ContextHideRequestResponse != null) - { - hideRequestResponse = (bool)ContextHideRequestResponse.GetValue(app.Context); - ContextHideRequestResponse.SetValue(app.Context, false); - } - - try - { - // ensure context is instantiated - IConfigurableApplicationContext appContext = WebApplicationContext.GetRootContext() as IConfigurableApplicationContext; - // configure this app + it's module instances - if (appContext == null) - { - throw new InvalidOperationException("Implementations of IApplicationContext must also implement IConfigurableApplicationContext"); - } - - HttpApplicationConfigurer.Configure(appContext, app); - } - finally - { - if (ContextHideRequestResponse!=null) ContextHideRequestResponse.SetValue(app.Context, hideRequestResponse); - } + // signal, that VirtualEnvironment is ready to accept + // handler registrations for EndRequest and EndSession events + VirtualEnvironment.SetInitialized(); } - #region IHttpHandler configuration + app.PreRequestHandlerExecute += OnConfigureHandler; + app.EndRequest += VirtualEnvironment.RaiseEndRequest; - /// - /// Configures the current IHttpHandler as specified by . If the - /// is not executed for the current request and an instance of - /// is served revalidate if the instance should be configured. - /// - private void OnConfigureHandler(object sender, EventArgs e) + // TODO: this is only a workaround to get us up & running in IIS7/integrated mode + // We must review all code for relative virtual paths - they must be resolved to application-relative paths + // during parsing of the object definitions + bool hideRequestResponse = false; + if (ContextHideRequestResponse != null) { - HttpApplication app = (HttpApplication)sender; - HandlerConfigurationMetaData hCfg = (HandlerConfigurationMetaData)LogicalThreadContext.GetData(CURRENTHANDLER_OBJECTDEFINITION); - if (hCfg != null) - { - // app.Context.Handler = // TODO: check, if this makes sense (EE) - ConfigureHandlerNow(app.Context.Handler, hCfg.ApplicationContext, hCfg.ObjectDefinitionName, hCfg.IsContainerManaged); - } - else - { - Page page = app.Context.Handler as Page; - if (!IsPageWithRouteHandler(page)) - { - return; - } - - // In case of Routing pages are not handled by the PageHandlerFactory therefore no HandlerConfigurationMetaData - // is set. - IConfigurableApplicationContext applicationContext = (IConfigurableApplicationContext)WebApplicationContext.Current; - string normalizedVirtualPath = WebUtils.GetNormalizedVirtualPath(page.AppRelativeVirtualPath); - - ControlInterceptor.EnsureControlIntercepted(applicationContext, page); - ConfigureHandlerNow(page, applicationContext, normalizedVirtualPath, true); - } + hideRequestResponse = (bool) ContextHideRequestResponse.GetValue(app.Context); + ContextHideRequestResponse.SetValue(app.Context, false); } - /// - /// Determines whether the specified page is processed by a . - /// - /// the page. - /// whether the page has a page route assigned - private static bool IsPageWithRouteHandler(Page page) + try { - return page != null && page.RouteData != null && page.RouteData.RouteHandler != null; + // ensure context is instantiated + IConfigurableApplicationContext appContext = WebApplicationContext.GetRootContext() as IConfigurableApplicationContext; + // configure this app + it's module instances + if (appContext == null) + { + throw new InvalidOperationException("Implementations of IApplicationContext must also implement IConfigurableApplicationContext"); + } + + HttpApplicationConfigurer.Configure(appContext, app); } - - /// - /// Configures the specified handler instance using the object definition . - /// - /// - /// TODO - /// - /// - /// - /// - /// - /// - /// - public static IHttpHandler ConfigureHandler(HttpContext context, IHttpHandler handler, IConfigurableApplicationContext applicationContext, string name, bool isContainerManaged) + finally { - if (context.Handler != null) - { - s_log.LogDebug(string.Format("previous handler is present - configuring handler now using application context '{0}' and name '{1}'", applicationContext, name)); - // this is a Server.Execute() or Server.Transfer() request -> configure immediately - return ConfigureHandlerNow(handler, applicationContext, name, isContainerManaged); - } - else - { - // remember the resolved object definition name for applying it during PreRequestHandlerExecute - s_log.LogDebug(string.Format("no previous handler is present - defer handler configuration using application context '{0}' and name '{1}'", applicationContext, name)); - SetCurrentHandlerConfiguration(applicationContext, name, isContainerManaged); - return handler; - } + if (ContextHideRequestResponse != null) ContextHideRequestResponse.SetValue(app.Context, hideRequestResponse); } + } - /// - /// TODO - /// - /// - /// - /// - private static void SetCurrentHandlerConfiguration(IConfigurableApplicationContext applicationContext, string name, bool isContainerManaged) + #region IHttpHandler configuration + + /// + /// Configures the current IHttpHandler as specified by . If the + /// is not executed for the current request and an instance of + /// is served revalidate if the instance should be configured. + /// + private void OnConfigureHandler(object sender, EventArgs e) + { + HttpApplication app = (HttpApplication) sender; + HandlerConfigurationMetaData hCfg = (HandlerConfigurationMetaData) LogicalThreadContext.GetData(CURRENTHANDLER_OBJECTDEFINITION); + if (hCfg != null) { - LogicalThreadContext.SetData(CURRENTHANDLER_OBJECTDEFINITION, new HandlerConfigurationMetaData(applicationContext, name, isContainerManaged)); + // app.Context.Handler = // TODO: check, if this makes sense (EE) + ConfigureHandlerNow(app.Context.Handler, hCfg.ApplicationContext, hCfg.ObjectDefinitionName, hCfg.IsContainerManaged); } - - /// - /// TODO - /// - /// - /// - /// - /// - private static IHttpHandler ConfigureHandlerNow(IHttpHandler handler, IConfigurableApplicationContext applicationContext, string name, bool isContainerManaged) + else { - if (isContainerManaged) + Page page = app.Context.Handler as Page; + if (!IsPageWithRouteHandler(page)) { - s_log.LogDebug(string.Format("configuring managed handler using application context '{0}' and name '{1}'", applicationContext, name)); - handler = (IHttpHandler)applicationContext.ObjectFactory.ConfigureObject(handler, name); - } - else - { - s_log.LogDebug(string.Format("configuring unmanaged handler using application context '{0}' and name '{1}'", applicationContext, name)); - // at a minimum we'll apply ObjectPostProcessors - handler = (IHttpHandler)applicationContext.ObjectFactory.ApplyObjectPostProcessorsBeforeInitialization(handler, name); - handler = (IHttpHandler)applicationContext.ObjectFactory.ApplyObjectPostProcessorsAfterInitialization(handler, name); + return; } + // In case of Routing pages are not handled by the PageHandlerFactory therefore no HandlerConfigurationMetaData + // is set. + IConfigurableApplicationContext applicationContext = (IConfigurableApplicationContext) WebApplicationContext.Current; + string normalizedVirtualPath = WebUtils.GetNormalizedVirtualPath(page.AppRelativeVirtualPath); + + ControlInterceptor.EnsureControlIntercepted(applicationContext, page); + ConfigureHandlerNow(page, applicationContext, normalizedVirtualPath, true); + } + } + + /// + /// Determines whether the specified page is processed by a . + /// + /// the page. + /// whether the page has a page route assigned + private static bool IsPageWithRouteHandler(Page page) + { + return page != null && page.RouteData != null && page.RouteData.RouteHandler != null; + } + + /// + /// Configures the specified handler instance using the object definition . + /// + /// + /// TODO + /// + /// + /// + /// + /// + /// + /// + public static IHttpHandler ConfigureHandler(HttpContext context, IHttpHandler handler, IConfigurableApplicationContext applicationContext, string name, bool isContainerManaged) + { + if (context.Handler != null) + { + s_log.LogDebug(string.Format("previous handler is present - configuring handler now using application context '{0}' and name '{1}'", applicationContext, name)); + // this is a Server.Execute() or Server.Transfer() request -> configure immediately + return ConfigureHandlerNow(handler, applicationContext, name, isContainerManaged); + } + else + { + // remember the resolved object definition name for applying it during PreRequestHandlerExecute + s_log.LogDebug(string.Format("no previous handler is present - defer handler configuration using application context '{0}' and name '{1}'", applicationContext, name)); + SetCurrentHandlerConfiguration(applicationContext, name, isContainerManaged); return handler; } - - #endregion - - /// - /// Disposes this instance - /// - public virtual void Dispose() - { - // noop - } - - #region Session Handling Stuff - - private static void OnCacheItemRemoved(string key, object value, CacheItemRemovedReason reason) - { - s_log.LogDebug("end session " + key + " because of " + reason); - - try - { - HttpSessionState ss = CreateSessionState(key, value); - - VirtualEnvironment.RaiseEndSession(ss, reason); - } - catch (Exception ex) - { - string msg = "Failure during EndSession event handling"; - // are we on a current request? - if (HttpContext.Current != null) - { - s_log.LogError(ex, msg); - } - else - { - // this is an async session timeout - log as fatal since this is the thread's exit point! - s_log.LogCritical(ex, msg); - } - } - finally - { - if (s_originalCallback != null) - { - s_originalCallback(key, value, reason); - } - } - } - - private static void HookSessionEvent(SessionStateModule sessionStateModule) - { - // Hook only into InProcState - all others ignore SessionEnd anyway - object store = ExpressionEvaluator.GetValue(sessionStateModule, "_store"); - if ((store != null) && store.GetType().Name == "InProcSessionStateStore") - { - s_log.LogDebug("attaching to InProcSessionStateStore"); - s_originalCallback = (CacheItemRemovedCallback)ExpressionEvaluator.GetValue(store, "_callback"); - ExpressionEvaluator.SetValue(store, "_callback", new CacheItemRemovedCallback(OnCacheItemRemoved)); - - CACHEKEYPREFIXLENGTH = (int)ExpressionEvaluator.GetValue(store, "CACHEKEYPREFIXLENGTH"); - } - } - - private static HttpSessionState CreateSessionState(string key, object state) - { - string id = key.Substring(CACHEKEYPREFIXLENGTH); - ISessionStateItemCollection sessionItems = - (ISessionStateItemCollection)ExpressionEvaluator.GetValue(state, "_sessionItems"); - HttpStaticObjectsCollection staticObjects = - (HttpStaticObjectsCollection)ExpressionEvaluator.GetValue(state, "_staticObjects"); - int timeout = (int)ExpressionEvaluator.GetValue(state, "_timeout"); - TypeRegistry.RegisterType("SessionStateModule", typeof(SessionStateModule)); - HttpCookieMode cookieMode = - (HttpCookieMode)ExpressionEvaluator.GetValue(null, "SessionStateModule.s_configCookieless"); - SessionStateMode stateMode = - (SessionStateMode)ExpressionEvaluator.GetValue(null, "SessionStateModule.s_configMode"); - HttpSessionStateContainer container = new HttpSessionStateContainer( - id - , sessionItems - , staticObjects - , timeout - , false - , cookieMode - , stateMode - , true - ); - - return (HttpSessionState)Activator.CreateInstance( - typeof(HttpSessionState) - , BindingFlags.Instance | BindingFlags.NonPublic - , null - , new object[] { container } - , CultureInfo.InvariantCulture - ); - } - #endregion Session Handling Stuff } + + /// + /// TODO + /// + /// + /// + /// + private static void SetCurrentHandlerConfiguration(IConfigurableApplicationContext applicationContext, string name, bool isContainerManaged) + { + LogicalThreadContext.SetData(CURRENTHANDLER_OBJECTDEFINITION, new HandlerConfigurationMetaData(applicationContext, name, isContainerManaged)); + } + + /// + /// TODO + /// + /// + /// + /// + /// + private static IHttpHandler ConfigureHandlerNow(IHttpHandler handler, IConfigurableApplicationContext applicationContext, string name, bool isContainerManaged) + { + if (isContainerManaged) + { + s_log.LogDebug(string.Format("configuring managed handler using application context '{0}' and name '{1}'", applicationContext, name)); + handler = (IHttpHandler) applicationContext.ObjectFactory.ConfigureObject(handler, name); + } + else + { + s_log.LogDebug(string.Format("configuring unmanaged handler using application context '{0}' and name '{1}'", applicationContext, name)); + // at a minimum we'll apply ObjectPostProcessors + handler = (IHttpHandler) applicationContext.ObjectFactory.ApplyObjectPostProcessorsBeforeInitialization(handler, name); + handler = (IHttpHandler) applicationContext.ObjectFactory.ApplyObjectPostProcessorsAfterInitialization(handler, name); + } + + return handler; + } + + #endregion + + /// + /// Disposes this instance + /// + public virtual void Dispose() + { + // noop + } + + #region Session Handling Stuff + + private static void OnCacheItemRemoved(string key, object value, CacheItemRemovedReason reason) + { + s_log.LogDebug("end session " + key + " because of " + reason); + + try + { + HttpSessionState ss = CreateSessionState(key, value); + + VirtualEnvironment.RaiseEndSession(ss, reason); + } + catch (Exception ex) + { + string msg = "Failure during EndSession event handling"; + // are we on a current request? + if (HttpContext.Current != null) + { + s_log.LogError(ex, msg); + } + else + { + // this is an async session timeout - log as fatal since this is the thread's exit point! + s_log.LogCritical(ex, msg); + } + } + finally + { + if (s_originalCallback != null) + { + s_originalCallback(key, value, reason); + } + } + } + + private static void HookSessionEvent(SessionStateModule sessionStateModule) + { + // Hook only into InProcState - all others ignore SessionEnd anyway + object store = ExpressionEvaluator.GetValue(sessionStateModule, "_store"); + if ((store != null) && store.GetType().Name == "InProcSessionStateStore") + { + s_log.LogDebug("attaching to InProcSessionStateStore"); + s_originalCallback = (CacheItemRemovedCallback) ExpressionEvaluator.GetValue(store, "_callback"); + ExpressionEvaluator.SetValue(store, "_callback", new CacheItemRemovedCallback(OnCacheItemRemoved)); + + CACHEKEYPREFIXLENGTH = (int) ExpressionEvaluator.GetValue(store, "CACHEKEYPREFIXLENGTH"); + } + } + + private static HttpSessionState CreateSessionState(string key, object state) + { + string id = key.Substring(CACHEKEYPREFIXLENGTH); + ISessionStateItemCollection sessionItems = + (ISessionStateItemCollection) ExpressionEvaluator.GetValue(state, "_sessionItems"); + HttpStaticObjectsCollection staticObjects = + (HttpStaticObjectsCollection) ExpressionEvaluator.GetValue(state, "_staticObjects"); + int timeout = (int) ExpressionEvaluator.GetValue(state, "_timeout"); + TypeRegistry.RegisterType("SessionStateModule", typeof(SessionStateModule)); + HttpCookieMode cookieMode = + (HttpCookieMode) ExpressionEvaluator.GetValue(null, "SessionStateModule.s_configCookieless"); + SessionStateMode stateMode = + (SessionStateMode) ExpressionEvaluator.GetValue(null, "SessionStateModule.s_configMode"); + HttpSessionStateContainer container = new HttpSessionStateContainer( + id + , sessionItems + , staticObjects + , timeout + , false + , cookieMode + , stateMode + , true + ); + + return (HttpSessionState) Activator.CreateInstance( + typeof(HttpSessionState) + , BindingFlags.Instance | BindingFlags.NonPublic + , null + , new object[] { container } + , CultureInfo.InvariantCulture + ); + } + + #endregion Session Handling Stuff } diff --git a/src/Spring/Spring.Web/Core/IO/WebResource.cs b/src/Spring/Spring.Web/Core/IO/WebResource.cs index 5ed584b0..20a60977 100644 --- a/src/Spring/Spring.Web/Core/IO/WebResource.cs +++ b/src/Spring/Spring.Web/Core/IO/WebResource.cs @@ -24,171 +24,172 @@ using Spring.Util; #endregion -namespace Spring.Core.IO +namespace Spring.Core.IO; + +/// +/// implementation specifically +/// for resources served up from a web server. +/// +/// +///

+/// Uses the System.Web.HttpContext.Current.Server.MapPath +/// method to resolve the file name for a given resource. +///

+///
+/// Aleksandar Seovic +public class WebResource : FileSystemResource { + private string absolutePath; + /// - /// implementation specifically - /// for resources served up from a web server. + /// Creates a new instance of the class. /// - /// - ///

- /// Uses the System.Web.HttpContext.Current.Server.MapPath - /// method to resolve the file name for a given resource. - ///

- ///
- /// Aleksandar Seovic - public class WebResource : FileSystemResource + /// + /// The name of the file system resource (on the server). + /// + public WebResource(string resourceName) + : base(resourceName) { - private string absolutePath; + } - /// - /// Creates a new instance of the class. - /// - /// - /// The name of the file system resource (on the server). - /// - public WebResource(string resourceName) - : base(resourceName) - { - } + /// + /// Gets those characters that are valid path separators for the + /// resource type. + /// + /// + /// Those characters that are valid path separators for the resource + /// type. + /// + /// + protected override char[] PathSeparatorChars + { + get { return new char[] { '/' }; } + } - /// - /// Gets those characters that are valid path separators for the - /// resource type. - /// - /// - /// Those characters that are valid path separators for the resource - /// type. - /// - /// - protected override char[] PathSeparatorChars + /// + /// Resolves the handle + /// for the supplied . + /// + /// + /// The name of the file system resource. + /// + /// + /// The handle for this resource. + /// + protected override FileInfo ResolveFileHandle(string resourceName) + { + this.absolutePath = ResolveResourceNameWithoutProtocol(resourceName); + if (!this.absolutePath.StartsWith("/")) { - get { return new char[] {'/'}; } - } - - /// - /// Resolves the handle - /// for the supplied . - /// - /// - /// The name of the file system resource. - /// - /// - /// The handle for this resource. - /// - protected override FileInfo ResolveFileHandle(string resourceName) - { - this.absolutePath = ResolveResourceNameWithoutProtocol(resourceName); - if(!this.absolutePath.StartsWith("/")) + string currentPath = VirtualEnvironment.CurrentVirtualFilePath; + int n = currentPath.LastIndexOfAny(new char[] { '/', '\\' }); + if (n >= 0) { - string currentPath = VirtualEnvironment.CurrentVirtualFilePath; - int n = currentPath.LastIndexOfAny(new char[] {'/', '\\'}); - if(n >= 0) - { - currentPath = currentPath.Substring(0, n); - } - this.absolutePath = currentPath + '/' + this.absolutePath; + currentPath = currentPath.Substring(0, n); } - return new FileInfo(VirtualEnvironment.MapPath(this.absolutePath)); + this.absolutePath = currentPath + '/' + this.absolutePath; } - /// - /// Resolves the root location for the supplied . - /// - /// - /// The name of the file system resource. - /// - /// - /// The root location of the resource. - /// - protected override string ResolveRootLocation(string resourceName) + return new FileInfo(VirtualEnvironment.MapPath(this.absolutePath)); + } + + /// + /// Resolves the root location for the supplied . + /// + /// + /// The name of the file system resource. + /// + /// + /// The root location of the resource. + /// + protected override string ResolveRootLocation(string resourceName) + { + return string.Empty; + } + + /// + /// Resolves the path for the supplied . + /// + /// + /// The name of the file system resource. + /// + /// + /// The current path of the resource. + /// + protected override string ResolveResourcePath(string resourceName) + { + string path = this.absolutePath.TrimStart(PathSeparatorChars); + int n = path.LastIndexOfAny(PathSeparatorChars); + if (n > 0) { - return string.Empty; + path = path.Substring(0, n); } - - /// - /// Resolves the path for the supplied . - /// - /// - /// The name of the file system resource. - /// - /// - /// The current path of the resource. - /// - protected override string ResolveResourcePath(string resourceName) + else { - string path = this.absolutePath.TrimStart(PathSeparatorChars); - int n = path.LastIndexOfAny(PathSeparatorChars); - if(n > 0) - { - path = path.Substring(0, n); - } - else - { - path = string.Empty; - } - - return path; + path = string.Empty; } - /// - /// Resolves the presence of the - /// value - /// in the supplied into a path. - /// - /// - /// The name of the resource. - /// - /// - /// The string that is a placeholder for a base path. - /// - /// - /// The name of the resource with any - /// value having been resolved into an actual path. - /// - protected override string ResolveBasePathPlaceHolder( - string resourceName, string basePathPlaceHolder) + return path; + } + + /// + /// Resolves the presence of the + /// value + /// in the supplied into a path. + /// + /// + /// The name of the resource. + /// + /// + /// The string that is a placeholder for a base path. + /// + /// + /// The name of the resource with any + /// value having been resolved into an actual path. + /// + protected override string ResolveBasePathPlaceHolder( + string resourceName, string basePathPlaceHolder) + { + if (StringUtils.HasText(resourceName) + && resourceName.TrimStart().StartsWith(basePathPlaceHolder)) { - if(StringUtils.HasText(resourceName) - && resourceName.TrimStart().StartsWith(basePathPlaceHolder)) - { - return resourceName.Replace(basePathPlaceHolder, VirtualEnvironment.ApplicationVirtualPath.TrimEnd('/')); - } - return resourceName; + return resourceName.Replace(basePathPlaceHolder, VirtualEnvironment.ApplicationVirtualPath.TrimEnd('/')); } - /// - /// Does the supplied relative ? - /// - /// - /// The name of the resource to test. - /// - /// - /// if resource name is relative; - /// otherwise . - /// - protected override bool IsRelativeResource(string resourceName) - { - return (! - (resourceName.StartsWith("/") || - resourceName.StartsWith(BasePathPlaceHolder))); - } + return resourceName; + } - /// - /// Factory Method. Create a new instance of the current resource type using the given resourceName - /// - protected override IResource CreateResourceInstance(string resourceName) - { - return new WebResource(resourceName); - } + /// + /// Does the supplied relative ? + /// + /// + /// The name of the resource to test. + /// + /// + /// if resource name is relative; + /// otherwise . + /// + protected override bool IsRelativeResource(string resourceName) + { + return (! + (resourceName.StartsWith("/") || + resourceName.StartsWith(BasePathPlaceHolder))); + } - /// - /// The ResourceLoader to be used for resolving relative resources - /// - protected override IResourceLoader GetResourceLoader() - { - return new ConfigurableResourceLoader(WebUtils.DEFAULT_RESOURCE_PROTOCOL); - } + /// + /// Factory Method. Create a new instance of the current resource type using the given resourceName + /// + protected override IResource CreateResourceInstance(string resourceName) + { + return new WebResource(resourceName); + } + + /// + /// The ResourceLoader to be used for resolving relative resources + /// + protected override IResourceLoader GetResourceLoader() + { + return new ConfigurableResourceLoader(WebUtils.DEFAULT_RESOURCE_PROTOCOL); } } diff --git a/src/Spring/Spring.Web/DataBinding/DataSourceItemFormatter.cs b/src/Spring/Spring.Web/DataBinding/DataSourceItemFormatter.cs index a3291356..c1959138 100644 --- a/src/Spring/Spring.Web/DataBinding/DataSourceItemFormatter.cs +++ b/src/Spring/Spring.Web/DataBinding/DataSourceItemFormatter.cs @@ -1,120 +1,119 @@ using System.Collections; using System.Web.UI; -namespace Spring.DataBinding +namespace Spring.DataBinding; + +/// +/// This formatter acts as an adapter to a datasource. It parses a given datasource into +/// a table to allow converting back and forth between objects and their keys during formatting. +/// +/// +/// +/// The DataSourceItemFormatter expects the "source" to have 2 properties named "DataSourceField" and "DataValueField". +/// +/// +public class DataSourceItemFormatter : IBindingAwareFormatter { + private string _dataSourceFieldName; + private string _dataValueFieldName; + + [ThreadStatic] private Hashtable _dataItemsByKey; + [ThreadStatic] private string _dataItemKeyField; + /// - /// This formatter acts as an adapter to a datasource. It parses a given datasource into - /// a table to allow converting back and forth between objects and their keys during formatting. + /// Initialize this instance. /// - /// - /// - /// The DataSourceItemFormatter expects the "source" to have 2 properties named "DataSourceField" and "DataValueField". - /// - /// - public class DataSourceItemFormatter : IBindingAwareFormatter + /// The name of the "source"s property containing the dataSource + /// The name of the "source"s property containing the name of the key property + public DataSourceItemFormatter(string dataSourceField, string dataValueField) { - private string _dataSourceFieldName; - private string _dataValueFieldName; - - [ThreadStatic] - private Hashtable _dataItemsByKey; - [ThreadStatic] - private string _dataItemKeyField; - - /// - /// Initialize this instance. - /// - /// The name of the "source"s property containing the dataSource - /// The name of the "source"s property containing the name of the key property - public DataSourceItemFormatter(string dataSourceField, string dataValueField) + this._dataSourceFieldName = dataSourceField; + if (dataValueField == null) { - this._dataSourceFieldName = dataSourceField; - if(dataValueField == null) + throw new ArgumentNullException("DataValueField must not be null."); + } + + this._dataValueFieldName = dataValueField; + } + + /// + /// Sets the bindingContext for the current thread. + /// + /// The source object + /// The target object + /// Variables to be used during binding + /// The current binding's direction + public void SetBindingContext(object source, object target, IDictionary variables, BindingDirection direction) + { + // Extract dataSource from source object + IEnumerable dataSource = DataBinder.GetPropertyValue(source, this._dataSourceFieldName) as IEnumerable; + // Extract dataItemKeyField from source object + string dataItemKeyField = DataBinder.GetPropertyValue(source, this._dataValueFieldName) as String; + + Initialize(dataSource, dataItemKeyField, direction); + } + + /// + /// Reset the current thread's binding context. + /// + public void ClearBindingContext() + { + _dataItemsByKey = null; + _dataItemKeyField = null; + } + + /// + /// Initialize a new instance. + /// + /// The datasource containing list items + /// The name of the listitem's property that evaluates to the item's key + /// The direction of the current binding + private void Initialize(IEnumerable dataSource, string dataItemKeyField, BindingDirection direction) + { + _dataItemKeyField = dataItemKeyField; + + // if we are binding from target to source only, we can save some performance + // here because only Format() will be called. + if (direction != (direction & BindingDirection.TargetToSource)) + { + if (dataSource == null) { - throw new ArgumentNullException("DataValueField must not be null."); + throw new ArgumentNullException( + string.Format("DataSource must not be null.")); } - this._dataValueFieldName = dataValueField; - } - /// - /// Sets the bindingContext for the current thread. - /// - /// The source object - /// The target object - /// Variables to be used during binding - /// The current binding's direction - public void SetBindingContext(object source, object target, IDictionary variables, BindingDirection direction) - { - // Extract dataSource from source object - IEnumerable dataSource = DataBinder.GetPropertyValue(source, this._dataSourceFieldName) as IEnumerable; - // Extract dataItemKeyField from source object - string dataItemKeyField = DataBinder.GetPropertyValue(source, this._dataValueFieldName) as String; - - Initialize(dataSource, dataItemKeyField, direction); - } - - /// - /// Reset the current thread's binding context. - /// - public void ClearBindingContext() - { - _dataItemsByKey = null; - _dataItemKeyField = null; - } - - /// - /// Initialize a new instance. - /// - /// The datasource containing list items - /// The name of the listitem's property that evaluates to the item's key - /// The direction of the current binding - private void Initialize(IEnumerable dataSource, string dataItemKeyField, BindingDirection direction) - { - _dataItemKeyField = dataItemKeyField; - - // if we are binding from target to source only, we can save some performance - // here because only Format() will be called. - if (direction != (direction&BindingDirection.TargetToSource)) + _dataItemsByKey = new Hashtable(); + foreach (object dataItem in dataSource) { - if(dataSource == null) - { - throw new ArgumentNullException( - string.Format("DataSource must not be null.")); - } - - _dataItemsByKey = new Hashtable(); - foreach(object dataItem in dataSource) - { - string key = Format(dataItem); - this._dataItemsByKey.Add(key, dataItem); - } + string key = Format(dataItem); + this._dataItemsByKey.Add(key, dataItem); } } - - /// - /// Returns the key of the specified value object. - /// - /// The value to extract the key from. - /// Key extracted from . - public string Format(object value) - { - return DataBinder.GetPropertyValue(value, this._dataItemKeyField, null); - } - - /// - /// Return the object with the specified key from the datasource. - /// - /// The key of the object. - /// Parsed . - public object Parse(string key) - { - object item = this._dataItemsByKey[key]; - if (item==null) - { - throw new ArgumentOutOfRangeException("key", key, string.Format("Item with key {0} does not exist", key)); - } - return item; - } + } + + /// + /// Returns the key of the specified value object. + /// + /// The value to extract the key from. + /// Key extracted from . + public string Format(object value) + { + return DataBinder.GetPropertyValue(value, this._dataItemKeyField, null); + } + + /// + /// Return the object with the specified key from the datasource. + /// + /// The key of the object. + /// Parsed . + public object Parse(string key) + { + object item = this._dataItemsByKey[key]; + if (item == null) + { + throw new ArgumentOutOfRangeException("key", key, string.Format("Item with key {0} does not exist", key)); + } + + return item; } } diff --git a/src/Spring/Spring.Web/DataBinding/HttpRequestBindingContainer.cs b/src/Spring/Spring.Web/DataBinding/HttpRequestBindingContainer.cs index 92045b26..255afb76 100644 --- a/src/Spring/Spring.Web/DataBinding/HttpRequestBindingContainer.cs +++ b/src/Spring/Spring.Web/DataBinding/HttpRequestBindingContainer.cs @@ -1,162 +1,160 @@ using System.Collections; using System.Collections.Specialized; using System.Reflection; - using Spring.Expressions; using Spring.Globalization; using Spring.Util; using Spring.Validation; -namespace Spring.DataBinding +namespace Spring.DataBinding; + +/// +/// Binds agroup of HTTP request multi-valued items to the data model. +/// +/// +/// Due to the fact, that browsers don't send the values of unchecked checkboxes, you +/// can't use for binding to checkboxes. +/// +/// Aleksandar Seovic +public class HttpRequestListBindingContainer : BaseBindingContainer { + private string[] requestParams; + private ConstructorInfo itemCtor; + private IExpression targetExpression; + /// - /// Binds agroup of HTTP request multi-valued items to the data model. + /// Creates a new instance of . + /// + /// + /// Comma separated list of multi-valued request parameters that + /// should be used to create a target item. + /// + /// + /// Expression that identifies a target list items should be added to. + /// + /// + /// The type of the target item. + /// + public HttpRequestListBindingContainer(string requestParams, string targetList, Type itemType) + { + this.requestParams = requestParams.Split(','); + this.targetExpression = Expression.Parse(targetList); + this.itemCtor = itemType.GetConstructor(Type.EmptyTypes); + if (this.itemCtor == null) + { + throw new ArgumentException("Type [{0}] does not have a default constructor. " + + "A default constructor for the item type is required for collection data binding.", + itemType.FullName); + } + } + + /// + /// Adds the binding. /// /// - /// Due to the fact, that browsers don't send the values of unchecked checkboxes, you - /// can't use for binding to checkboxes. + /// This is a convinience method for adding SimpleExpressionBinding, + /// one of the most often used binding types, to the bindings list. /// - /// Aleksandar Seovic - public class HttpRequestListBindingContainer : BaseBindingContainer + /// + /// The source expression. + /// + /// + /// The target expression. + /// + /// + /// Binding direction. + /// + /// + /// to use for value formatting and parsing. + /// + /// + /// Added instance. + /// + public override IBinding AddBinding(string sourceExpression, string targetExpression, BindingDirection direction, + IFormatter formatter) { - private string[] requestParams; - private ConstructorInfo itemCtor; - private IExpression targetExpression; + // setup variable for each HTTP request parameter + return base.AddBinding("#" + sourceExpression, targetExpression, direction, formatter); + } - /// - /// Creates a new instance of . - /// - /// - /// Comma separated list of multi-valued request parameters that - /// should be used to create a target item. - /// - /// - /// Expression that identifies a target list items should be added to. - /// - /// - /// The type of the target item. - /// - public HttpRequestListBindingContainer(string requestParams, string targetList, Type itemType) + /// + /// Binds source object to target object. + /// + /// + /// The source object. + /// + /// + /// The target object. + /// + /// + /// Validation errors collection that type conversion errors should be added to. + /// + /// + /// Variables that should be used during expression evaluation. + /// + public override void BindSourceToTarget(object source, object target, IValidationErrors validationErrors, IDictionary variables) + { + NameValueCollection parameters = VirtualEnvironment.RequestParams; + IList targetList = targetExpression.GetValue(target) as IList; + if (targetList == null) { - this.requestParams = requestParams.Split(','); - this.targetExpression = Expression.Parse(targetList); - this.itemCtor = itemType.GetConstructor(Type.EmptyTypes); - if (this.itemCtor == null) - { - throw new ArgumentException("Type [{0}] does not have a default constructor. " + - "A default constructor for the item type is required for collection data binding.", - itemType.FullName); - } + throw new ArgumentException("Target property has to be initialized to an instance of IList interface."); } - /// - /// Adds the binding. - /// - /// - /// This is a convinience method for adding SimpleExpressionBinding, - /// one of the most often used binding types, to the bindings list. - /// - /// - /// The source expression. - /// - /// - /// The target expression. - /// - /// - /// Binding direction. - /// - /// - /// to use for value formatting and parsing. - /// - /// - /// Added instance. - /// - public override IBinding AddBinding(string sourceExpression, string targetExpression, BindingDirection direction, - IFormatter formatter) + if (parameters.GetValues(requestParams[0]) != null) { - // setup variable for each HTTP request parameter - return base.AddBinding("#" + sourceExpression, targetExpression, direction, formatter); - } - - /// - /// Binds source object to target object. - /// - /// - /// The source object. - /// - /// - /// The target object. - /// - /// - /// Validation errors collection that type conversion errors should be added to. - /// - /// - /// Variables that should be used during expression evaluation. - /// - public override void BindSourceToTarget(object source, object target, IValidationErrors validationErrors, IDictionary variables) - { - NameValueCollection parameters = VirtualEnvironment.RequestParams; - IList targetList = targetExpression.GetValue(target) as IList; - if (targetList == null) + int valueCount = parameters.GetValues(requestParams[0]).Length; + for (int i = 0; i < valueCount; i++) { - throw new ArgumentException("Target property has to be initialized to an instance of IList interface."); - } - - if (parameters.GetValues(requestParams[0]) != null) - { - int valueCount = parameters.GetValues(requestParams[0]).Length; - for (int i = 0; i < valueCount; i++) + IDictionary vars = new Dictionary(); + foreach (string paramName in requestParams) { - IDictionary vars = new Dictionary(); - foreach (string paramName in requestParams) - { - vars[paramName] = parameters.GetValues(paramName)[i]; - } + vars[paramName] = parameters.GetValues(paramName)[i]; + } - object targetItem; - bool addToList; - if (i < targetList.Count) - { - targetItem = targetList[i]; - addToList = false; - } - else - { - targetItem = itemCtor.Invoke(ObjectUtils.EmptyObjects); - addToList = true; - } + object targetItem; + bool addToList; + if (i < targetList.Count) + { + targetItem = targetList[i]; + addToList = false; + } + else + { + targetItem = itemCtor.Invoke(ObjectUtils.EmptyObjects); + addToList = true; + } - foreach (IBinding binding in Bindings) - { - binding.BindSourceToTarget(null, targetItem, validationErrors, vars); - } + foreach (IBinding binding in Bindings) + { + binding.BindSourceToTarget(null, targetItem, validationErrors, vars); + } - if (addToList) - { - targetList.Add(targetItem); - } + if (addToList) + { + targetList.Add(targetItem); } } } + } - /// - /// Binds target object to source object. - /// - /// - /// The source object. - /// - /// - /// The target object. - /// - /// - /// Validation errors collection that type conversion errors should be added to. - /// - /// - /// Variables that should be used during expression evaluation. - /// - public override void BindTargetToSource(object source, object target, IValidationErrors validationErrors, IDictionary variables) - { - // can't bind to a read-only Request object... - } + /// + /// Binds target object to source object. + /// + /// + /// The source object. + /// + /// + /// The target object. + /// + /// + /// Validation errors collection that type conversion errors should be added to. + /// + /// + /// Variables that should be used during expression evaluation. + /// + public override void BindTargetToSource(object source, object target, IValidationErrors validationErrors, IDictionary variables) + { + // can't bind to a read-only Request object... } } diff --git a/src/Spring/Spring.Web/DataBinding/IBindingAwareFormatter.cs b/src/Spring/Spring.Web/DataBinding/IBindingAwareFormatter.cs index 5c27f3a8..c8615978 100644 --- a/src/Spring/Spring.Web/DataBinding/IBindingAwareFormatter.cs +++ b/src/Spring/Spring.Web/DataBinding/IBindingAwareFormatter.cs @@ -1,23 +1,23 @@ using Spring.Globalization; -namespace Spring.DataBinding +namespace Spring.DataBinding; + +/// +/// +/// +public interface IBindingAwareFormatter : IFormatter { /// - /// + /// Sets the binding context of this formatter. /// - public interface IBindingAwareFormatter : IFormatter - { - /// - /// Sets the binding context of this formatter. - /// - /// - /// - /// - /// - void SetBindingContext(object source, object target, IDictionary variables, BindingDirection direction); - /// - /// Clears the binding context of this formatter. - /// - void ClearBindingContext(); - } + /// + /// + /// + /// + void SetBindingContext(object source, object target, IDictionary variables, BindingDirection direction); + + /// + /// Clears the binding context of this formatter. + /// + void ClearBindingContext(); } diff --git a/src/Spring/Spring.Web/DataBinding/IWebDataBound.cs b/src/Spring/Spring.Web/DataBinding/IWebDataBound.cs index 66f76fc5..23fa6aea 100644 --- a/src/Spring/Spring.Web/DataBinding/IWebDataBound.cs +++ b/src/Spring/Spring.Web/DataBinding/IWebDataBound.cs @@ -1,30 +1,31 @@ using Spring.Context; using Spring.Globalization; -namespace Spring.DataBinding +namespace Spring.DataBinding; + +/// +/// A page or control must implement this interface to support spring's databinding infrastructure. +/// +/// +/// +/// +/// +/// +public interface IWebDataBound : IDataBound { - /// - /// A page or control must implement this interface to support spring's databinding infrastructure. - /// - /// - /// - /// - /// - /// - public interface IWebDataBound : IDataBound - { - /// - /// Return the UniqueID of this page or control. - /// - string UniqueID { get; } - /// - /// Return the where - /// instances should be optained from. - /// - IApplicationContext ApplicationContext { get; } - /// - /// This event is raised to initialize bindings for . - /// - event EventHandler DataBindingsInitialized; - } + /// + /// Return the UniqueID of this page or control. + /// + string UniqueID { get; } + + /// + /// Return the where + /// instances should be optained from. + /// + IApplicationContext ApplicationContext { get; } + + /// + /// This event is raised to initialize bindings for . + /// + event EventHandler DataBindingsInitialized; } diff --git a/src/Spring/Spring.Web/DataBinding/MultipleSelectionListControlBinding.cs b/src/Spring/Spring.Web/DataBinding/MultipleSelectionListControlBinding.cs index 788ec6d0..93ea7f37 100644 --- a/src/Spring/Spring.Web/DataBinding/MultipleSelectionListControlBinding.cs +++ b/src/Spring/Spring.Web/DataBinding/MultipleSelectionListControlBinding.cs @@ -1,162 +1,160 @@ using System.Collections; using System.Web.UI.WebControls; - using Spring.Globalization; -namespace Spring.DataBinding +namespace Spring.DataBinding; + +/// +/// Handles binding of a multiple selection ListControl to a target's IList property. +/// +public class MultipleSelectionListControlBinding : SimpleExpressionBinding { /// - /// Handles binding of a multiple selection ListControl to a target's IList property. + /// Creates a new instance of this binding. /// - public class MultipleSelectionListControlBinding : SimpleExpressionBinding + ///The expression that will evaluate to the acting as the source + ///The expression that will evaluate to an property acting as the target + /// Binding's direction + ///An optional formatter converting target items into and back + /// + /// If no formatter is specified, a will be used. + /// + public MultipleSelectionListControlBinding(string sourceExpression, string targetExpression, BindingDirection direction, + IFormatter itemFormatter) + : base(sourceExpression, targetExpression, itemFormatter) { - /// - /// Creates a new instance of this binding. - /// - ///The expression that will evaluate to the acting as the source - ///The expression that will evaluate to an property acting as the target - /// Binding's direction - ///An optional formatter converting target items into and back - /// - /// If no formatter is specified, a will be used. - /// - public MultipleSelectionListControlBinding(string sourceExpression, string targetExpression, BindingDirection direction, - IFormatter itemFormatter) - :base(sourceExpression, targetExpression, itemFormatter) + this.Direction = direction; + if (itemFormatter == null) { - this.Direction = direction; - if (itemFormatter == null) - { - this.Formatter = new DataSourceItemFormatter("DataSource", "DataValueField"); - } - } - - /// - /// Actually performs unbinding the ListControl's selected values into the target's - /// - protected override void DoBindSourceToTarget(object source, object target, IDictionary variables) - { - // retrieve targetlist - IList targetList = this.GetTargetValue(target,variables) as IList; - if(targetList == null) - { - throw new ArgumentException(string.Format("Target property must evaluate to an instance of {0}.", typeof(IList).FullName)); - } - - // retrieve ListControl to be unbound - source = this.GetSourceValue(source, variables); - ListControl listControl = source as ListControl; - if(listControl == null) - { - throw new ArgumentException(string.Format("Source property must evaluate to an instance of {0}.", typeof(ListControl).FullName)); - } - - // reset target list - targetList.Clear(); - - // set binding context if applicable - IBindingAwareFormatter bindingAwareFormatter = this.Formatter as IBindingAwareFormatter; - if (bindingAwareFormatter != null) - { - bindingAwareFormatter.SetBindingContext(source, target, variables, BindingDirection.SourceToTarget); - } - - // (re-)add selected items to the target list - try - { - IFormatter formatter = this.Formatter; - ListItemCollection listItems = listControl.Items; - foreach(ListItem listItem in listControl.Items) - { - if (listItem.Selected) - { - // formatter must return an object applicable to the targetlist. - object item = formatter.Parse(listItem.Value); - targetList.Add(item); - } - } - } - finally - { - if(bindingAwareFormatter != null) - { - bindingAwareFormatter.ClearBindingContext(); - } - } - } - - /// - /// Actually performs binding the targetlist to the ListControl. - /// - protected override void DoBindTargetToSource(object source, object target, IDictionary variables) - { - // retrieve targetlist - IList targetList = this.GetTargetValue(target, variables) as IList; - if (targetList == null) - { - throw new ArgumentException("Target property has to be initialized to an instance of IList interface."); - } - - // retrieve ListControl to be bound - source = this.GetSourceValue(source, variables); - ListControl listControl = source as ListControl; - if(listControl == null) - { - throw new ArgumentException(string.Format("Source property has to be initialized to an instance of {0}.", typeof(ListControl).FullName)); - } - - // clear control's selection - listControl.ClearSelection(); - ListItemCollection listItems = listControl.Items; - - // set binding context if applicable - IBindingAwareFormatter bindingAwareFormatter = this.Formatter as IBindingAwareFormatter; - if(bindingAwareFormatter != null) - { - bindingAwareFormatter.SetBindingContext(source, target, variables, BindingDirection.TargetToSource); - } - - // select all items in ListControl matching keys in targetlist - try - { - IFormatter formatter = this.Formatter; - foreach(object objectItem in targetList) - { - string key = formatter.Format(objectItem); - ListItem item = listItems.FindByValue(key); - if (item != null) - { - item.Selected = true; - } - else - { - throw new ArgumentOutOfRangeException("value", key, string.Format("Value '{0}' does not exist", key )); - } - } - } - finally - { - if(bindingAwareFormatter != null) - { - bindingAwareFormatter.ClearBindingContext(); - } - } - } - - /// - /// Setting source value is not allowed in this bindingType. - /// - protected override void SetSourceValue(object source, object value, IDictionary variables) - { - throw new InvalidOperationException(string.Format("Setting source value in '{0}' is not allowed.",this.GetType().FullName)); - } - - /// - /// Setting target value is not allowed in this bindingType. - /// - protected override void SetTargetValue(object target, object value, IDictionary variables) - { - throw new InvalidOperationException(string.Format("Setting target value in '{0}' is not allowed.", this.GetType().FullName)); + this.Formatter = new DataSourceItemFormatter("DataSource", "DataValueField"); } } + + /// + /// Actually performs unbinding the ListControl's selected values into the target's + /// + protected override void DoBindSourceToTarget(object source, object target, IDictionary variables) + { + // retrieve targetlist + IList targetList = this.GetTargetValue(target, variables) as IList; + if (targetList == null) + { + throw new ArgumentException(string.Format("Target property must evaluate to an instance of {0}.", typeof(IList).FullName)); + } + + // retrieve ListControl to be unbound + source = this.GetSourceValue(source, variables); + ListControl listControl = source as ListControl; + if (listControl == null) + { + throw new ArgumentException(string.Format("Source property must evaluate to an instance of {0}.", typeof(ListControl).FullName)); + } + + // reset target list + targetList.Clear(); + + // set binding context if applicable + IBindingAwareFormatter bindingAwareFormatter = this.Formatter as IBindingAwareFormatter; + if (bindingAwareFormatter != null) + { + bindingAwareFormatter.SetBindingContext(source, target, variables, BindingDirection.SourceToTarget); + } + + // (re-)add selected items to the target list + try + { + IFormatter formatter = this.Formatter; + ListItemCollection listItems = listControl.Items; + foreach (ListItem listItem in listControl.Items) + { + if (listItem.Selected) + { + // formatter must return an object applicable to the targetlist. + object item = formatter.Parse(listItem.Value); + targetList.Add(item); + } + } + } + finally + { + if (bindingAwareFormatter != null) + { + bindingAwareFormatter.ClearBindingContext(); + } + } + } + + /// + /// Actually performs binding the targetlist to the ListControl. + /// + protected override void DoBindTargetToSource(object source, object target, IDictionary variables) + { + // retrieve targetlist + IList targetList = this.GetTargetValue(target, variables) as IList; + if (targetList == null) + { + throw new ArgumentException("Target property has to be initialized to an instance of IList interface."); + } + + // retrieve ListControl to be bound + source = this.GetSourceValue(source, variables); + ListControl listControl = source as ListControl; + if (listControl == null) + { + throw new ArgumentException(string.Format("Source property has to be initialized to an instance of {0}.", typeof(ListControl).FullName)); + } + + // clear control's selection + listControl.ClearSelection(); + ListItemCollection listItems = listControl.Items; + + // set binding context if applicable + IBindingAwareFormatter bindingAwareFormatter = this.Formatter as IBindingAwareFormatter; + if (bindingAwareFormatter != null) + { + bindingAwareFormatter.SetBindingContext(source, target, variables, BindingDirection.TargetToSource); + } + + // select all items in ListControl matching keys in targetlist + try + { + IFormatter formatter = this.Formatter; + foreach (object objectItem in targetList) + { + string key = formatter.Format(objectItem); + ListItem item = listItems.FindByValue(key); + if (item != null) + { + item.Selected = true; + } + else + { + throw new ArgumentOutOfRangeException("value", key, string.Format("Value '{0}' does not exist", key)); + } + } + } + finally + { + if (bindingAwareFormatter != null) + { + bindingAwareFormatter.ClearBindingContext(); + } + } + } + + /// + /// Setting source value is not allowed in this bindingType. + /// + protected override void SetSourceValue(object source, object value, IDictionary variables) + { + throw new InvalidOperationException(string.Format("Setting source value in '{0}' is not allowed.", this.GetType().FullName)); + } + + /// + /// Setting target value is not allowed in this bindingType. + /// + protected override void SetTargetValue(object target, object value, IDictionary variables) + { + throw new InvalidOperationException(string.Format("Setting target value in '{0}' is not allowed.", this.GetType().FullName)); + } } diff --git a/src/Spring/Spring.Web/Globalization/AspNetResourceCache.cs b/src/Spring/Spring.Web/Globalization/AspNetResourceCache.cs index 677146ee..afefe605 100644 --- a/src/Spring/Spring.Web/Globalization/AspNetResourceCache.cs +++ b/src/Spring/Spring.Web/Globalization/AspNetResourceCache.cs @@ -21,32 +21,31 @@ using System.Web; using System.Web.Caching; -namespace Spring.Globalization +namespace Spring.Globalization; + +/// +/// Resource cache implementation that uses ASP.NET to cache resources. +/// +/// Aleksandar Seovic +internal class AspNetResourceCache : AbstractResourceCache { /// - /// Resource cache implementation that uses ASP.NET to cache resources. + /// Gets the list of resources from cache. /// - /// Aleksandar Seovic - internal class AspNetResourceCache : AbstractResourceCache + /// Cache key to use for lookup. + /// A list of cached resources for the specified target object and culture. + protected override IList GetResources(string cacheKey) { - /// - /// Gets the list of resources from cache. - /// - /// Cache key to use for lookup. - /// A list of cached resources for the specified target object and culture. - protected override IList GetResources(string cacheKey) - { - return (IList)HttpRuntime.Cache[cacheKey]; - } + return (IList) HttpRuntime.Cache[cacheKey]; + } - /// - /// Puts the list of resources in the cache. - /// - /// Cache key to use for the specified resources. - /// A list of resources to cache. - protected override void PutResources(string cacheKey, IList resources) - { - HttpRuntime.Cache[cacheKey] = resources; - } + /// + /// Puts the list of resources in the cache. + /// + /// Cache key to use for the specified resources. + /// A list of resources to cache. + protected override void PutResources(string cacheKey, IList resources) + { + HttpRuntime.Cache[cacheKey] = resources; } } diff --git a/src/Spring/Spring.Web/Globalization/Resolvers/CookieCultureResolver.cs b/src/Spring/Spring.Web/Globalization/Resolvers/CookieCultureResolver.cs index 9d743def..074d1f7f 100644 --- a/src/Spring/Spring.Web/Globalization/Resolvers/CookieCultureResolver.cs +++ b/src/Spring/Spring.Web/Globalization/Resolvers/CookieCultureResolver.cs @@ -21,63 +21,62 @@ using System.Globalization; using System.Web; -namespace Spring.Globalization.Resolvers +namespace Spring.Globalization.Resolvers; + +/// +/// Culture resolver that uses cookie to store culture information. +/// +/// Aleksandar Seovic +public class CookieCultureResolver : DefaultWebCultureResolver { + private const string CultureKey = "Spring.UserLocale"; + /// - /// Culture resolver that uses cookie to store culture information. + /// Resolves the culture from the request. /// - /// Aleksandar Seovic - public class CookieCultureResolver : DefaultWebCultureResolver + /// + /// If the culture cookie doesn't exist, this method will return + /// the value of the 'Accept-Language' request header, or if no + /// headers are specified, the culture of the current server thread. + /// + /// Culture that should be used to render view. + public override CultureInfo ResolveCulture() { - private const string CultureKey = "Spring.UserLocale"; + HttpCookie cookie = HttpContext.Current.Request.Cookies[CultureKey]; - /// - /// Resolves the culture from the request. - /// - /// - /// If the culture cookie doesn't exist, this method will return - /// the value of the 'Accept-Language' request header, or if no - /// headers are specified, the culture of the current server thread. - /// - /// Culture that should be used to render view. - public override CultureInfo ResolveCulture() + if (cookie != null) { - HttpCookie cookie = HttpContext.Current.Request.Cookies[CultureKey]; - - if (cookie != null) - { - return base.GetCulture(cookie.Value); - } - else - { - return base.GetDefaultLocale(); - } + return base.GetCulture(cookie.Value); } - - /// - /// Sets the culture. - /// - /// The new culture or null to clear the culture. - public override void SetCulture(CultureInfo culture) + else { - HttpCookie cookie = CreateCookie(culture); - HttpContext.Current.Request.Cookies.Set(cookie); - HttpContext.Current.Response.Cookies.Add(cookie); - } - - /// - /// Creates cookie for the specified culture. - /// - /// Culture to store in a cookie. - /// Created cookie. - private HttpCookie CreateCookie(CultureInfo culture) - { - HttpCookie cookie = new HttpCookie(CultureKey); - cookie.Domain = HttpContext.Current.Request.Url.Host; - cookie.Expires = DateTime.MaxValue; - cookie.Value = culture.Name; - - return cookie; + return base.GetDefaultLocale(); } } + + /// + /// Sets the culture. + /// + /// The new culture or null to clear the culture. + public override void SetCulture(CultureInfo culture) + { + HttpCookie cookie = CreateCookie(culture); + HttpContext.Current.Request.Cookies.Set(cookie); + HttpContext.Current.Response.Cookies.Add(cookie); + } + + /// + /// Creates cookie for the specified culture. + /// + /// Culture to store in a cookie. + /// Created cookie. + private HttpCookie CreateCookie(CultureInfo culture) + { + HttpCookie cookie = new HttpCookie(CultureKey); + cookie.Domain = HttpContext.Current.Request.Url.Host; + cookie.Expires = DateTime.MaxValue; + cookie.Value = culture.Name; + + return cookie; + } } diff --git a/src/Spring/Spring.Web/Globalization/Resolvers/DefaultWebCultureResolver.cs b/src/Spring/Spring.Web/Globalization/Resolvers/DefaultWebCultureResolver.cs index b3b6730d..e2e1d7a6 100644 --- a/src/Spring/Spring.Web/Globalization/Resolvers/DefaultWebCultureResolver.cs +++ b/src/Spring/Spring.Web/Globalization/Resolvers/DefaultWebCultureResolver.cs @@ -22,77 +22,79 @@ using System.Globalization; using System.Web; using Spring.Util; -namespace Spring.Globalization.Resolvers +namespace Spring.Globalization.Resolvers; + +/// +/// Default culture resolver for web applications. Contains some common utility methods for web culture resolvers. +/// +/// Aleksandar Seovic +public class DefaultWebCultureResolver : DefaultCultureResolver { /// - /// Default culture resolver for web applications. Contains some common utility methods for web culture resolvers. + /// Returns default culture. If property is not set, + /// it tries to get culture from the request headers + /// and falls back to a current thread's culture if no headers are available. /// - /// Aleksandar Seovic - public class DefaultWebCultureResolver : DefaultCultureResolver + /// Default culture to use. + protected override CultureInfo GetDefaultLocale() { - /// - /// Returns default culture. If property is not set, - /// it tries to get culture from the request headers - /// and falls back to a current thread's culture if no headers are available. - /// - /// Default culture to use. - protected override CultureInfo GetDefaultLocale() + if (DefaultCulture != null) { - if (DefaultCulture != null) - { - return base.DefaultCulture; - } - - CultureInfo culture = GetCulture(GetRequestLanguage()); - if (culture != null) - { - return culture; - } - - return Thread.CurrentThread.CurrentUICulture; + return base.DefaultCulture; } - /// - /// Extracts the users favorite language from "accept-language" header of the current request. - /// - /// a language string if any or null, if no languages have been sent with the request - protected virtual string GetRequestLanguage() + CultureInfo culture = GetCulture(GetRequestLanguage()); + if (culture != null) { - HttpContext context = HttpContext.Current; - if (context != null && context.Request != null && ArrayUtils.HasLength(context.Request.UserLanguages)) - { - return context.Request.UserLanguages[0]; - } - return null; + return culture; } - /// - /// Resolves a culture by name. - /// - /// the name of the culture to get - /// a (possible neutral!) or null, if culture could not be resolved - public CultureInfo GetCulture(string cultureName) - { - try { return new CultureInfo(cultureName.Split(';')[0]); } catch { } - return null; - } - - /// - /// Resolves the culture from the context. - /// - /// Culture that should be used to render view. - public override CultureInfo ResolveCulture() - { - return GetDefaultLocale(); - } - - /// - /// Not supported for this implementation. - /// - /// The new culture or null to clear the culture. - public override void SetCulture(CultureInfo culture) - { - throw new NotSupportedException("Cannot change a default culture in a web application - use a different culture resolution strategy."); - } + return Thread.CurrentThread.CurrentUICulture; } -} + + /// + /// Extracts the users favorite language from "accept-language" header of the current request. + /// + /// a language string if any or null, if no languages have been sent with the request + protected virtual string GetRequestLanguage() + { + HttpContext context = HttpContext.Current; + if (context != null && context.Request != null && ArrayUtils.HasLength(context.Request.UserLanguages)) + { + return context.Request.UserLanguages[0]; + } + + return null; + } + + /// + /// Resolves a culture by name. + /// + /// the name of the culture to get + /// a (possible neutral!) or null, if culture could not be resolved + public CultureInfo GetCulture(string cultureName) + { + try { return new CultureInfo(cultureName.Split(';')[0]); } + catch { } + + return null; + } + + /// + /// Resolves the culture from the context. + /// + /// Culture that should be used to render view. + public override CultureInfo ResolveCulture() + { + return GetDefaultLocale(); + } + + /// + /// Not supported for this implementation. + /// + /// The new culture or null to clear the culture. + public override void SetCulture(CultureInfo culture) + { + throw new NotSupportedException("Cannot change a default culture in a web application - use a different culture resolution strategy."); + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Web/Globalization/Resolvers/RequestCultureResolver.cs b/src/Spring/Spring.Web/Globalization/Resolvers/RequestCultureResolver.cs index d9cf32bb..f0718564 100644 --- a/src/Spring/Spring.Web/Globalization/Resolvers/RequestCultureResolver.cs +++ b/src/Spring/Spring.Web/Globalization/Resolvers/RequestCultureResolver.cs @@ -21,55 +21,54 @@ using System.Globalization; using System.Web; -namespace Spring.Globalization.Resolvers +namespace Spring.Globalization.Resolvers; + +/// +/// Culture resolver that uses request headers to determine culture. If no languages +/// are specified in the request headers, it returns default culture specifed, and +/// if no default culture was specifed it returns current culture for the executing +/// server thread. +/// +/// +/// Note: This culture resolver cannot be used to change the culture +/// because request headers cannot be modified. In order to change the culture +/// when using this culture resolver user has to change language settings in +/// the web browser. +/// +/// Aleksandar Seovic +public class RequestCultureResolver : DefaultWebCultureResolver { /// - /// Culture resolver that uses request headers to determine culture. If no languages + /// Tries to determine culture from the request headers. If no languages /// are specified in the request headers, it returns default culture specifed, and /// if no default culture was specifed it returns current culture for the executing /// server thread. /// - /// - /// Note: This culture resolver cannot be used to change the culture - /// because request headers cannot be modified. In order to change the culture - /// when using this culture resolver user has to change language settings in - /// the web browser. - /// - /// Aleksandar Seovic - public class RequestCultureResolver : DefaultWebCultureResolver + /// Culture that should be used to render view. + public override CultureInfo ResolveCulture() { - /// - /// Tries to determine culture from the request headers. If no languages - /// are specified in the request headers, it returns default culture specifed, and - /// if no default culture was specifed it returns current culture for the executing - /// server thread. - /// - /// Culture that should be used to render view. - public override CultureInfo ResolveCulture() + HttpContext context = HttpContext.Current; + + CultureInfo culture = GetCulture(GetRequestLanguage()); + if (culture != null) { - HttpContext context = HttpContext.Current; - - CultureInfo culture = GetCulture(GetRequestLanguage()); - if (culture != null) - { - return culture; - } - - if (DefaultCulture != null) - { - return base.DefaultCulture; - } - - return Thread.CurrentThread.CurrentUICulture; + return culture; } - /// - /// Not supported for this resolver implementation - /// - /// The new culture or null to clear the culture. - public override void SetCulture(CultureInfo culture) + if (DefaultCulture != null) { - throw new NotSupportedException("Cannot change HTTP request headers - use a different culture resolution strategy."); + return base.DefaultCulture; } + + return Thread.CurrentThread.CurrentUICulture; + } + + /// + /// Not supported for this resolver implementation + /// + /// The new culture or null to clear the culture. + public override void SetCulture(CultureInfo culture) + { + throw new NotSupportedException("Cannot change HTTP request headers - use a different culture resolution strategy."); } } diff --git a/src/Spring/Spring.Web/Globalization/Resolvers/SessionCultureResolver.cs b/src/Spring/Spring.Web/Globalization/Resolvers/SessionCultureResolver.cs index 7ae7c9de..6a18cd17 100644 --- a/src/Spring/Spring.Web/Globalization/Resolvers/SessionCultureResolver.cs +++ b/src/Spring/Spring.Web/Globalization/Resolvers/SessionCultureResolver.cs @@ -22,62 +22,61 @@ using System.Globalization; using System.Web; using Spring.Util; -namespace Spring.Globalization.Resolvers +namespace Spring.Globalization.Resolvers; + +/// +/// Culture resolver that uses HTTP session to store culture information. +/// +/// Aleksandar Seovic +public class SessionCultureResolver : DefaultWebCultureResolver { + private const string CultureKey = "Spring.UserLocale"; + /// - /// Culture resolver that uses HTTP session to store culture information. + /// Resolves the culture from the request. /// - /// Aleksandar Seovic - public class SessionCultureResolver : DefaultWebCultureResolver + /// + /// If culture information doesn't exist in the session, it will be created and its value will + /// be set to the value of the 'Accept-Language' request header, or if no + /// headers are specified to the culture of the current server thread. + /// + /// Culture that should be used to render view. + public override CultureInfo ResolveCulture() { - private const string CultureKey = "Spring.UserLocale"; - - /// - /// Resolves the culture from the request. - /// - /// - /// If culture information doesn't exist in the session, it will be created and its value will - /// be set to the value of the 'Accept-Language' request header, or if no - /// headers are specified to the culture of the current server thread. - /// - /// Culture that should be used to render view. - public override CultureInfo ResolveCulture() + CultureInfo culture = SessionCulture; + if (culture != null) { - CultureInfo culture = SessionCulture; - if (culture != null) - { - return culture; - } - else - { - return base.GetDefaultLocale(); - } + return culture; } - - /// - /// Sets the culture. - /// - /// The new culture or null to clear the culture. - public override void SetCulture(CultureInfo culture) + else { - SessionCulture = culture; - } - - /// - /// Gets/Sets the current session's culture. - /// - protected virtual CultureInfo SessionCulture - { - set - { - AssertUtils.ArgumentNotNull(value, "SessionCulture"); - HttpContext.Current.Session[CultureKey] = value; - } - get - { - CultureInfo culture = HttpContext.Current.Session[CultureKey] as CultureInfo; - return culture; - } + return base.GetDefaultLocale(); } } -} \ No newline at end of file + + /// + /// Sets the culture. + /// + /// The new culture or null to clear the culture. + public override void SetCulture(CultureInfo culture) + { + SessionCulture = culture; + } + + /// + /// Gets/Sets the current session's culture. + /// + protected virtual CultureInfo SessionCulture + { + set + { + AssertUtils.ArgumentNotNull(value, "SessionCulture"); + HttpContext.Current.Session[CultureKey] = value; + } + get + { + CultureInfo culture = HttpContext.Current.Session[CultureKey] as CultureInfo; + return culture; + } + } +} diff --git a/src/Spring/Spring.Web/Objects/Factory/Support/ChildWebObjectDefinition.cs b/src/Spring/Spring.Web/Objects/Factory/Support/ChildWebObjectDefinition.cs index c727fcce..c64081ad 100644 --- a/src/Spring/Spring.Web/Objects/Factory/Support/ChildWebObjectDefinition.cs +++ b/src/Spring/Spring.Web/Objects/Factory/Support/ChildWebObjectDefinition.cs @@ -19,166 +19,165 @@ #endregion using System.Globalization; - using Spring.Objects.Factory.Config; using Spring.Util; -namespace Spring.Objects.Factory.Support +namespace Spring.Objects.Factory.Support; + +/// +/// Web object definitions extend +/// by adding scope property. +/// +/// +///

+/// This is the most common type of object definition in ASP.Net web applications +///

+///
+/// Aleksandar Seovic +public class ChildWebObjectDefinition : ChildObjectDefinition, IWebObjectDefinition { - /// - /// Web object definitions extend - /// by adding scope property. - /// - /// - ///

- /// This is the most common type of object definition in ASP.Net web applications - ///

- ///
- /// Aleksandar Seovic - public class ChildWebObjectDefinition : ChildObjectDefinition, IWebObjectDefinition - { // private ObjectScope _scope = ObjectScope.Default; - private string _pageName; + private string _pageName; - #region Constructors + #region Constructors - /// - /// Creates a new instance of the - /// class - /// for a singleton, providing property values and constructor arguments. - /// - /// Name of the parent object definition. - /// The class of the object to instantiate. - /// - /// The - /// to be applied to a new instance of the object. - /// - /// - /// The to be applied to - /// a new instance of the object. - /// - public ChildWebObjectDefinition(string parentName, Type type, ConstructorArgumentValues arguments, MutablePropertyValues properties) - : base(parentName, type, arguments, properties) - {} + /// + /// Creates a new instance of the + /// class + /// for a singleton, providing property values and constructor arguments. + /// + /// Name of the parent object definition. + /// The class of the object to instantiate. + /// + /// The + /// to be applied to a new instance of the object. + /// + /// + /// The to be applied to + /// a new instance of the object. + /// + public ChildWebObjectDefinition(string parentName, Type type, ConstructorArgumentValues arguments, MutablePropertyValues properties) + : base(parentName, type, arguments, properties) + { + } - /// - /// Creates a new instance of the - /// class - /// for a singleton, providing property values and constructor arguments. - /// - /// Name of the parent object definition. - /// The class name of the object to instantiate. - /// - /// The - /// to be applied to a new instance of the object. - /// - /// - /// The to be applied to - /// a new instance of the object. - /// - public ChildWebObjectDefinition(string parentName, string typeName, ConstructorArgumentValues arguments, MutablePropertyValues properties) - : base(parentName, typeName, arguments, properties) - {} + /// + /// Creates a new instance of the + /// class + /// for a singleton, providing property values and constructor arguments. + /// + /// Name of the parent object definition. + /// The class name of the object to instantiate. + /// + /// The + /// to be applied to a new instance of the object. + /// + /// + /// The to be applied to + /// a new instance of the object. + /// + public ChildWebObjectDefinition(string parentName, string typeName, ConstructorArgumentValues arguments, MutablePropertyValues properties) + : base(parentName, typeName, arguments, properties) + { + } - /// - /// Creates a new instance of the - /// class - /// for an .aspx page, providing property values. - /// - /// Name of the parent object definition. - /// Name of the .aspx page to instantiate. - /// - /// The to be applied to - /// a new instance of the object. - /// - public ChildWebObjectDefinition(string parentName, string pageName, MutablePropertyValues properties) - : base(parentName, WebObjectUtils.GetPageType(pageName), null, properties) + /// + /// Creates a new instance of the + /// class + /// for an .aspx page, providing property values. + /// + /// Name of the parent object definition. + /// Name of the .aspx page to instantiate. + /// + /// The to be applied to + /// a new instance of the object. + /// + public ChildWebObjectDefinition(string parentName, string pageName, MutablePropertyValues properties) + : base(parentName, WebObjectUtils.GetPageType(pageName), null, properties) + { + _pageName = WebUtils.CombineVirtualPaths(VirtualEnvironment.CurrentExecutionFilePath, pageName); + } + + #endregion + + /// + /// Object scope. + /// + ObjectScope IWebObjectDefinition.Scope + { + get { return (ObjectScope) Enum.Parse(typeof(ObjectScope), this.Scope, true); } + set { this.Scope = value.ToString(); } + } + + /// + /// Returns true if web object is .aspx page. + /// + public bool IsPage + { + get { return _pageName != null; } + } + + /// + /// Gets the rooted url of the .aspx page, if object definition represents page. + /// + public string PageName + { + get { return _pageName; } + } + + /// + /// Forces ASP pages to be treated as prototypes all the time inorder to comply with ASP.Net requirements. + /// + public override bool IsSingleton + { + get { - _pageName = WebUtils.CombineVirtualPaths(VirtualEnvironment.CurrentExecutionFilePath, pageName); - } - - #endregion - - /// - /// Object scope. - /// - ObjectScope IWebObjectDefinition.Scope - { - get { return (ObjectScope)Enum.Parse(typeof(ObjectScope), this.Scope, true); } - set { this.Scope = value.ToString(); } - } - - /// - /// Returns true if web object is .aspx page. - /// - public bool IsPage - { - get { return _pageName != null; } - } - - /// - /// Gets the rooted url of the .aspx page, if object definition represents page. - /// - public string PageName - { - get { return _pageName; } - } - - /// - /// Forces ASP pages to be treated as prototypes all the time inorder to comply with ASP.Net requirements. - /// - public override bool IsSingleton - { - get + if (IsPage) { - if (IsPage) - { - return false; - } - else if (0 == string.Compare("application", this.Scope, true) - || 0 == string.Compare("session", this.Scope, true) - || 0 == string.Compare("request", this.Scope, true)) - { - return true; - } - else - { - return base.IsSingleton; - } + return false; } - set { base.IsSingleton = value; } - } - - /// - /// Overrides this object's values using values from other argument. - /// - /// The object to copy values from. - public override void OverrideFrom(IObjectDefinition other) - { - base.OverrideFrom(other); - if (other is IWebObjectDefinition) + else if (0 == string.Compare("application", this.Scope, true) + || 0 == string.Compare("session", this.Scope, true) + || 0 == string.Compare("request", this.Scope, true)) { - // this._scope = ((IWebObjectDefinition) other).Scope; - this._pageName = ((IWebObjectDefinition)other).PageName; + return true; + } + else + { + return base.IsSingleton; } } + set { base.IsSingleton = value; } + } - /// - /// A that represents the current - /// . - /// - /// - /// A that represents the current - /// . - /// - public override string ToString() + /// + /// Overrides this object's values using values from other argument. + /// + /// The object to copy values from. + public override void OverrideFrom(IObjectDefinition other) + { + base.OverrideFrom(other); + if (other is IWebObjectDefinition) { - return string.Format( - CultureInfo.InvariantCulture, - "Child web object with class [{0}] defined in {1}", - (IsPage ? PageName : ObjectTypeName), - ResourceDescription); + // this._scope = ((IWebObjectDefinition) other).Scope; + this._pageName = ((IWebObjectDefinition) other).PageName; } + } + /// + /// A that represents the current + /// . + /// + /// + /// A that represents the current + /// . + /// + public override string ToString() + { + return string.Format( + CultureInfo.InvariantCulture, + "Child web object with class [{0}] defined in {1}", + (IsPage ? PageName : ObjectTypeName), + ResourceDescription); } } diff --git a/src/Spring/Spring.Web/Objects/Factory/Support/IWebObjectDefinition.cs b/src/Spring/Spring.Web/Objects/Factory/Support/IWebObjectDefinition.cs index 5f06f587..817228d8 100644 --- a/src/Spring/Spring.Web/Objects/Factory/Support/IWebObjectDefinition.cs +++ b/src/Spring/Spring.Web/Objects/Factory/Support/IWebObjectDefinition.cs @@ -18,27 +18,26 @@ #endregion -namespace Spring.Objects.Factory.Support +namespace Spring.Objects.Factory.Support; + +/// +/// Defines additional members web object definitions need to implement. +/// +/// Aleksandar Seovic +public interface IWebObjectDefinition { /// - /// Defines additional members web object definitions need to implement. + /// Gets or sets scope for the web object (application, session or request) /// - /// Aleksandar Seovic - public interface IWebObjectDefinition - { - /// - /// Gets or sets scope for the web object (application, session or request) - /// - ObjectScope Scope { get; set; } + ObjectScope Scope { get; set; } - /// - /// Returns true if web object is .aspx page. - /// - bool IsPage { get; } + /// + /// Returns true if web object is .aspx page. + /// + bool IsPage { get; } - /// - /// Gets the rooted url of the .aspx page, if object definition represents page. - /// - string PageName { get; } - } -} \ No newline at end of file + /// + /// Gets the rooted url of the .aspx page, if object definition represents page. + /// + string PageName { get; } +} diff --git a/src/Spring/Spring.Web/Objects/Factory/Support/IWebObjectNameGenerator.cs b/src/Spring/Spring.Web/Objects/Factory/Support/IWebObjectNameGenerator.cs index ba4e8c3a..66498607 100644 --- a/src/Spring/Spring.Web/Objects/Factory/Support/IWebObjectNameGenerator.cs +++ b/src/Spring/Spring.Web/Objects/Factory/Support/IWebObjectNameGenerator.cs @@ -1,31 +1,30 @@ #region License -/* - * Copyright 2002-2010 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. +/* + * Copyright 2002-2010 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 -namespace Spring.Objects.Factory.Support +namespace Spring.Objects.Factory.Support; + +/// +/// +/// Erich Eichinger +internal interface IWebObjectNameGenerator { - /// - /// - /// Erich Eichinger - internal interface IWebObjectNameGenerator - { - string CreatePageDefinitionName(string virtualPath); - string CreateControlDefinitionName(string virtualPath); - } -} \ No newline at end of file + string CreatePageDefinitionName(string virtualPath); + string CreateControlDefinitionName(string virtualPath); +} diff --git a/src/Spring/Spring.Web/Objects/Factory/Support/RootWebObjectDefinition.cs b/src/Spring/Spring.Web/Objects/Factory/Support/RootWebObjectDefinition.cs index 375d24a1..150ad0f4 100644 --- a/src/Spring/Spring.Web/Objects/Factory/Support/RootWebObjectDefinition.cs +++ b/src/Spring/Spring.Web/Objects/Factory/Support/RootWebObjectDefinition.cs @@ -21,205 +21,204 @@ #region Imports using System.Globalization; - using Spring.Objects.Factory.Config; using Spring.Util; #endregion -namespace Spring.Objects.Factory.Support +namespace Spring.Objects.Factory.Support; + +/// +/// Web object definitions extend +/// by adding scope property. +/// +/// +///

+/// This is the most common type of object definition in ASP.Net web applications +///

+///
+/// Aleksandar Seovic +public class RootWebObjectDefinition : RootObjectDefinition, IWebObjectDefinition { +// private ObjectScope _scope = ObjectScope.Default; + private string _pageName; + + #region Constructors + /// - /// Web object definitions extend - /// by adding scope property. + /// Creates a new instance of the + /// class + /// for a singleton, providing property values and constructor arguments. /// + /// + /// The type of the object to instantiate. + /// + /// + /// The to be applied to + /// a new instance of the object. + /// + /// + /// The + /// to be applied to a new instance of the object. + /// + public RootWebObjectDefinition( + Type type, + ConstructorArgumentValues arguments, + MutablePropertyValues properties) + : base(type, arguments, properties) + { + } + + /// + /// Creates a new instance of the + /// class + /// for a singleton, providing property values and constructor arguments. + /// + /// + /// The assembly qualified of the object to instantiate. + /// + /// + /// The to be applied to + /// a new instance of the object. + /// + /// + /// The + /// to be applied to a new instance of the object. + /// /// - ///

- /// This is the most common type of object definition in ASP.Net web applications + ///

+ /// Takes an object class name to avoid eager loading of the object class. ///

///
- /// Aleksandar Seovic - public class RootWebObjectDefinition : RootObjectDefinition, IWebObjectDefinition + public RootWebObjectDefinition( + string typeName, + ConstructorArgumentValues arguments, + MutablePropertyValues properties) + : base(typeName, arguments, properties) { -// private ObjectScope _scope = ObjectScope.Default; - private string _pageName; + } - #region Constructors + /// + /// Creates a new instance of the + /// class + /// for an .aspx page, providing property values. + /// + /// + /// Name of the .aspx page to instantiate. + /// + /// + /// The to be applied to + /// a new instance of the object. + /// + public RootWebObjectDefinition( + string pageName, + MutablePropertyValues properties) + : base(WebObjectUtils.GetPageType(pageName), null, properties) + { + _pageName = WebUtils.CombineVirtualPaths(VirtualEnvironment.CurrentExecutionFilePath, pageName); + } - - /// - /// Creates a new instance of the - /// class - /// for a singleton, providing property values and constructor arguments. - /// - /// - /// The type of the object to instantiate. - /// - /// - /// The to be applied to - /// a new instance of the object. - /// - /// - /// The - /// to be applied to a new instance of the object. - /// - public RootWebObjectDefinition( - Type type, - ConstructorArgumentValues arguments, - MutablePropertyValues properties) - : base(type, arguments, properties) - {} - - /// - /// Creates a new instance of the - /// class - /// for a singleton, providing property values and constructor arguments. - /// - /// - /// The assembly qualified of the object to instantiate. - /// - /// - /// The to be applied to - /// a new instance of the object. - /// - /// - /// The - /// to be applied to a new instance of the object. - /// - /// - ///

- /// Takes an object class name to avoid eager loading of the object class. - ///

- ///
- public RootWebObjectDefinition( - string typeName, - ConstructorArgumentValues arguments, - MutablePropertyValues properties) - : base(typeName, arguments, properties) - {} - - /// - /// Creates a new instance of the - /// class - /// for an .aspx page, providing property values. - /// - /// - /// Name of the .aspx page to instantiate. - /// - /// - /// The to be applied to - /// a new instance of the object. - /// - public RootWebObjectDefinition( - string pageName, - MutablePropertyValues properties) - : base(WebObjectUtils.GetPageType(pageName), null, properties) + /// + /// Creates a new instance of the + /// class + /// + /// + /// The definition that is to be copied. + /// + /// + ///

+ /// Deep copy constructor. + ///

+ ///
+ public RootWebObjectDefinition(IObjectDefinition other) : base(other) + { + if (other is IWebObjectDefinition) { - _pageName = WebUtils.CombineVirtualPaths(VirtualEnvironment.CurrentExecutionFilePath, pageName); - } - - /// - /// Creates a new instance of the - /// class - /// - /// - /// The definition that is to be copied. - /// - /// - ///

- /// Deep copy constructor. - ///

- ///
- public RootWebObjectDefinition(IObjectDefinition other) : base(other) - { - if (other is IWebObjectDefinition) - { // this._scope = ((IWebObjectDefinition) other).Scope; - this._pageName = ((IWebObjectDefinition) other).PageName; - } - } - - #endregion - - /// - /// Object scope. - /// - ObjectScope IWebObjectDefinition.Scope - { - get { return (ObjectScope) Enum.Parse(typeof(ObjectScope), base.Scope, true); } - set { base.Scope = value.ToString(); } - } - - /// - /// Returns true if web object is .aspx page. - /// - public bool IsPage - { - get { return _pageName != null; } - } - - /// - /// Gets the rooted url of the .aspx page, if object definition represents page. - /// - public string PageName - { - get { return _pageName; } - } - - /// - /// Forces ASP pages to be treated as prototypes all the time inorder to comply with ASP.Net requirements. - /// - public override bool IsSingleton - { - get - { - if (IsPage) - { - return false; - } - else if (0 == string.Compare("application", this.Scope, true) - || 0 == string.Compare("session", this.Scope, true) - || 0 == string.Compare("request", this.Scope, true)) - { - return true; - } - else - { - return base.IsSingleton; - } - } - set { base.IsSingleton = value; } - } - - /// - /// Overrides this object's values using values from other argument. - /// - /// The object to copy values from. - public override void OverrideFrom(IObjectDefinition other) - { - base.OverrideFrom(other); - if (other is IWebObjectDefinition definition) - { -// this._scope = ((IWebObjectDefinition) other).Scope; - this._pageName = definition.PageName; - } - } - - /// - /// A that represents the current - /// . - /// - /// - /// A that represents the current - /// . - /// - public override string ToString() - { - return string.Format( - CultureInfo.InvariantCulture, - "Root web object with class [{0}] defined in {1}", - (IsPage ? PageName : ObjectTypeName), - ResourceDescription); + this._pageName = ((IWebObjectDefinition) other).PageName; } } + + #endregion + + /// + /// Object scope. + /// + ObjectScope IWebObjectDefinition.Scope + { + get { return (ObjectScope) Enum.Parse(typeof(ObjectScope), base.Scope, true); } + set { base.Scope = value.ToString(); } + } + + /// + /// Returns true if web object is .aspx page. + /// + public bool IsPage + { + get { return _pageName != null; } + } + + /// + /// Gets the rooted url of the .aspx page, if object definition represents page. + /// + public string PageName + { + get { return _pageName; } + } + + /// + /// Forces ASP pages to be treated as prototypes all the time inorder to comply with ASP.Net requirements. + /// + public override bool IsSingleton + { + get + { + if (IsPage) + { + return false; + } + else if (0 == string.Compare("application", this.Scope, true) + || 0 == string.Compare("session", this.Scope, true) + || 0 == string.Compare("request", this.Scope, true)) + { + return true; + } + else + { + return base.IsSingleton; + } + } + set { base.IsSingleton = value; } + } + + /// + /// Overrides this object's values using values from other argument. + /// + /// The object to copy values from. + public override void OverrideFrom(IObjectDefinition other) + { + base.OverrideFrom(other); + if (other is IWebObjectDefinition definition) + { +// this._scope = ((IWebObjectDefinition) other).Scope; + this._pageName = definition.PageName; + } + } + + /// + /// A that represents the current + /// . + /// + /// + /// A that represents the current + /// . + /// + public override string ToString() + { + return string.Format( + CultureInfo.InvariantCulture, + "Root web object with class [{0}] defined in {1}", + (IsPage ? PageName : ObjectTypeName), + ResourceDescription); + } } diff --git a/src/Spring/Spring.Web/Objects/Factory/Support/WebInstantiationStrategy.cs b/src/Spring/Spring.Web/Objects/Factory/Support/WebInstantiationStrategy.cs index 0d5e32c7..80f822c4 100644 --- a/src/Spring/Spring.Web/Objects/Factory/Support/WebInstantiationStrategy.cs +++ b/src/Spring/Spring.Web/Objects/Factory/Support/WebInstantiationStrategy.cs @@ -22,61 +22,60 @@ #endregion -namespace Spring.Objects.Factory.Support +namespace Spring.Objects.Factory.Support; + +/// +/// Object instantiation strategy for use in +/// . +/// +/// +///

+/// This strategy checks if objects id ASP.Net page and if it is uses +/// PageParser to compile and instantiate page instance. Otherwise it +/// delagates call to its parent. +///

+///
+/// Aleksandar Seovic +[Serializable] +public class WebInstantiationStrategy : MethodInjectingInstantiationStrategy { /// - /// Object instantiation strategy for use in - /// . + /// Creates a new instance of the + /// class. /// - /// - ///

- /// This strategy checks if objects id ASP.Net page and if it is uses - /// PageParser to compile and instantiate page instance. Otherwise it - /// delagates call to its parent. - ///

- ///
- /// Aleksandar Seovic - [Serializable] - public class WebInstantiationStrategy : MethodInjectingInstantiationStrategy + public WebInstantiationStrategy() { - /// - /// Creates a new instance of the - /// class. - /// - public WebInstantiationStrategy() - {} + } - /// - /// Instantiate an instance of the object described by the supplied - /// from the supplied . - /// - /// - /// The definition of the object that is to be instantiated. - /// - /// - /// The name associated with the object definition. The name can be the null - /// or zero length string if we're autowiring an object that doesn't belong - /// to the supplied . - /// - /// - /// The owning - /// - /// - /// An instance of the object described by the supplied - /// from the supplied . - /// - public override object Instantiate( - RootObjectDefinition definition, string name, IObjectFactory factory) + /// + /// Instantiate an instance of the object described by the supplied + /// from the supplied . + /// + /// + /// The definition of the object that is to be instantiated. + /// + /// + /// The name associated with the object definition. The name can be the null + /// or zero length string if we're autowiring an object that doesn't belong + /// to the supplied . + /// + /// + /// The owning + /// + /// + /// An instance of the object described by the supplied + /// from the supplied . + /// + public override object Instantiate( + RootObjectDefinition definition, string name, IObjectFactory factory) + { + if (definition is IWebObjectDefinition && ((IWebObjectDefinition) definition).IsPage) { - if (definition is IWebObjectDefinition && ((IWebObjectDefinition) definition).IsPage) - { - return WebObjectUtils.CreatePageInstance(((IWebObjectDefinition) definition).PageName); - } - else - { - return base.Instantiate(definition, name, factory); - } + return WebObjectUtils.CreatePageInstance(((IWebObjectDefinition) definition).PageName); + } + else + { + return base.Instantiate(definition, name, factory); } - } } diff --git a/src/Spring/Spring.Web/Objects/Factory/Support/WebObjectDefinitionFactory.cs b/src/Spring/Spring.Web/Objects/Factory/Support/WebObjectDefinitionFactory.cs index 8d49728f..9191d66e 100644 --- a/src/Spring/Spring.Web/Objects/Factory/Support/WebObjectDefinitionFactory.cs +++ b/src/Spring/Spring.Web/Objects/Factory/Support/WebObjectDefinitionFactory.cs @@ -26,85 +26,82 @@ using Spring.Util; #endregion -namespace Spring.Objects.Factory.Support +namespace Spring.Objects.Factory.Support; + +/// +/// Custom implementation of +/// for web applications. +/// +/// +///

+/// This implementation adds support for .aspx pages and scoped objects. +///

+///
+/// Aleksandar Seovic +public class WebObjectDefinitionFactory : DefaultObjectDefinitionFactory { /// - /// Custom implementation of - /// for web applications. + /// Factory style method for getting concrete + /// + /// instances. /// - /// - ///

- /// This implementation adds support for .aspx pages and scoped objects. - ///

- ///
- /// Aleksandar Seovic - public class WebObjectDefinitionFactory : DefaultObjectDefinitionFactory + /// If no parent is specified, a RootWebObjectDefinition is created, otherwise a + /// ChildWebObjectDefinition. + /// The of the defined object. + /// The name of the parent object definition (if any). + /// The against which any class names + /// will be resolved into instances. + /// + /// An + /// + /// instance. + /// + public override AbstractObjectDefinition CreateObjectDefinition(string typeName, string parent, AppDomain domain) { + Type objectType = null; + bool isPage = StringUtils.HasText(typeName) && typeName.ToLower().EndsWith(".aspx"); + bool isControl = StringUtils.HasText(typeName) && + (typeName.ToLower().EndsWith(".ascx") || typeName.ToLower().EndsWith(".master")); - /// - /// Factory style method for getting concrete - /// - /// instances. - /// - /// If no parent is specified, a RootWebObjectDefinition is created, otherwise a - /// ChildWebObjectDefinition. - /// The of the defined object. - /// The name of the parent object definition (if any). - /// The against which any class names - /// will be resolved into instances. - /// - /// An - /// - /// instance. - /// - public override AbstractObjectDefinition CreateObjectDefinition(string typeName, string parent, AppDomain domain) + if (!(isPage || isControl) && StringUtils.HasText(typeName) && domain != null) { - Type objectType = null; - bool isPage = StringUtils.HasText(typeName) && typeName.ToLower().EndsWith(".aspx"); - bool isControl = StringUtils.HasText(typeName) && - (typeName.ToLower().EndsWith(".ascx") || typeName.ToLower().EndsWith(".master")); - - if (!(isPage || isControl) && StringUtils.HasText(typeName) && domain != null) + try { - try - { - objectType = TypeResolutionUtils.ResolveType(typeName); - } - // try later.... - catch { } + objectType = TypeResolutionUtils.ResolveType(typeName); } + // try later.... + catch { } + } - if (StringUtils.IsNullOrEmpty(parent)) + if (StringUtils.IsNullOrEmpty(parent)) + { + if (objectType != null) { - if (objectType != null) - { - return new RootWebObjectDefinition(objectType, new ConstructorArgumentValues(), new MutablePropertyValues()); - } - else if (isPage) - { - return new RootWebObjectDefinition(typeName, new MutablePropertyValues()); - } - else - { - return new RootWebObjectDefinition(typeName, new ConstructorArgumentValues(), new MutablePropertyValues()); - } + return new RootWebObjectDefinition(objectType, new ConstructorArgumentValues(), new MutablePropertyValues()); + } + else if (isPage) + { + return new RootWebObjectDefinition(typeName, new MutablePropertyValues()); } else { - if (objectType != null) - { - return new ChildWebObjectDefinition(parent, objectType, new ConstructorArgumentValues(), new MutablePropertyValues()); - } - else if (isPage) - { - return new ChildWebObjectDefinition(parent, typeName, new MutablePropertyValues()); - } - else - { - return new ChildWebObjectDefinition(parent, typeName, new ConstructorArgumentValues(), new MutablePropertyValues()); - } - } + return new RootWebObjectDefinition(typeName, new ConstructorArgumentValues(), new MutablePropertyValues()); + } + } + else + { + if (objectType != null) + { + return new ChildWebObjectDefinition(parent, objectType, new ConstructorArgumentValues(), new MutablePropertyValues()); + } + else if (isPage) + { + return new ChildWebObjectDefinition(parent, typeName, new MutablePropertyValues()); + } + else + { + return new ChildWebObjectDefinition(parent, typeName, new ConstructorArgumentValues(), new MutablePropertyValues()); + } } - } } diff --git a/src/Spring/Spring.Web/Objects/Factory/Support/WebObjectFactory.cs b/src/Spring/Spring.Web/Objects/Factory/Support/WebObjectFactory.cs index 2a0c147e..aad36199 100644 --- a/src/Spring/Spring.Web/Objects/Factory/Support/WebObjectFactory.cs +++ b/src/Spring/Spring.Web/Objects/Factory/Support/WebObjectFactory.cs @@ -33,523 +33,529 @@ using Spring.Util; #endregion -namespace Spring.Objects.Factory.Support +namespace Spring.Objects.Factory.Support; + +/// +/// Concrete implementation of +/// that knows +/// how to handle s. +/// +/// +///

+/// This class should only be used within the context of an ASP.NET web application. +///

+///
+/// Aleksandar Seovic +public class WebObjectFactory : DefaultListableObjectFactory { + private static bool s_eventHandlersRegistered = false; + private readonly static string OBJECTTABLEKEY = "spring.objects"; + + private delegate IDictionary ObjectDictionaryCreationHandler(); + /// - /// Concrete implementation of - /// that knows - /// how to handle s. + /// Holds the virtual path this factory has been created from. + /// + private readonly string contextPath; + + /// + /// Holds the handler reference for creating an object dictionary + /// matching this factory's case-sensitivity + /// + private readonly ObjectDictionaryCreationHandler createObjectDictionary; + + #region Constructor (s) / Destructor + + static WebObjectFactory() + { + //EnsureEventHandlersRegistered(); + } + + /// + /// Registers events handlers with to ensure + /// proper disposal of 'request'- and 'session'-scoped objects + /// + private void EnsureEventHandlersRegistered() + { + if (!s_eventHandlersRegistered) + { + lock (typeof(WebObjectFactory)) + { + if (s_eventHandlersRegistered) return; + + if (log.IsEnabled(LogLevel.Debug)) log.LogDebug("hooking up event handlers"); + VirtualEnvironment.EndRequest += OnEndRequest; + VirtualEnvironment.EndSession += OnEndSession; + + s_eventHandlersRegistered = true; + } + } + } + + /// + /// Creates a new instance of the + /// class. + /// + /// The virtual path resources will be relative resolved to. + /// Flag specifying whether to make this object factory case sensitive or not. + public WebObjectFactory(string contextPath, bool caseSensitive) + : this(contextPath, caseSensitive, null) + { + } + + /// + /// Creates a new instance of the + /// class. + /// + /// The virtual path resources will be relative resolved to. + /// Flag specifying whether to make this object factory case sensitive or not. + /// + /// The parent object factory. + /// + public WebObjectFactory(string contextPath, bool caseSensitive, IObjectFactory parentFactory) + : base(caseSensitive, parentFactory) + { + this.contextPath = contextPath; + this.createObjectDictionary = (caseSensitive) + ? new ObjectDictionaryCreationHandler(CreateCaseSensitiveDictionary) + : new ObjectDictionaryCreationHandler(CreateCaseInsensitiveDictionary); + + InstantiationStrategy = new WebInstantiationStrategy(); + } + + #endregion + + /// + /// Returns the virtual path this object factory is associated with. + /// + public string ContextPath + { + get { return contextPath; } + } + + #region Convenience accessors for Http* objects + + /// + /// Convinience accessor for HttpContext + /// + private HttpContext Context + { + get { return HttpContext.Current; } + } + + /// + /// Get the table of 'request'-scoped objects. + /// + protected virtual IDictionary Request + { + get + { + IDictionary objecttable = null; + if (this.Context != null) + { + objecttable = this.Context.Items[OBJECTTABLEKEY] as IDictionary; + if (objecttable == null) + { + this.Context.Items[OBJECTTABLEKEY] = CreateObjectDictionary(); + } + } + + return objecttable; + } + } + + /// + /// Get the table of 'session'-scoped objects. Returns null, if Session is disabled. + /// + protected virtual IDictionary Session + { + get + { + IDictionary objecttable = null; + if ((Context != null) && (Context.Session != null)) + { + objecttable = Context.Session[OBJECTTABLEKEY] as IDictionary; + if (objecttable == null) + { + Context.Session[OBJECTTABLEKEY] = CreateObjectDictionary(); + } + } + + return objecttable; + } + } + + #endregion + + /// + /// Creates a dictionary matching this factory's case sensitivity behaviour. + /// + protected IDictionary CreateObjectDictionary() + { + return createObjectDictionary(); + } + + /// + /// Creates the root object definition. + /// + /// The template definition. + /// Root object definition. + protected override RootObjectDefinition CreateRootObjectDefinition(IObjectDefinition templateDefinition) + { + return new RootWebObjectDefinition(templateDefinition); + } + + /// + /// Tries to find cached object for the specified name. /// /// - ///

- /// This class should only be used within the context of an ASP.NET web application. - ///

+ /// This implementation tries to find object first in the Request scope, + /// then in the Session scope and finally in the Application scope. ///
- /// Aleksandar Seovic - public class WebObjectFactory : DefaultListableObjectFactory + /// Object name to look for. + /// Cached object if found, null otherwise. + public override object GetSingleton(string objectName) { - private static bool s_eventHandlersRegistered = false; - private readonly static string OBJECTTABLEKEY = "spring.objects"; + object instance = null; - private delegate IDictionary ObjectDictionaryCreationHandler(); + instance = GetScopedSingleton(objectName, this.Request); + if (instance != null) return instance; - /// - /// Holds the virtual path this factory has been created from. - /// - private readonly string contextPath; - /// - /// Holds the handler reference for creating an object dictionary - /// matching this factory's case-sensitivity - /// - private readonly ObjectDictionaryCreationHandler createObjectDictionary; + instance = GetScopedSingleton(objectName, this.Session); + if (instance != null) return instance; - #region Constructor (s) / Destructor + instance = base.GetSingleton(objectName); + return instance; + } - static WebObjectFactory() + /// + /// Looks up an in the specified cache dictionary. + /// + /// the name to lookup. + /// the cache dictionary to search + /// the found instance. null otherwise + protected object GetScopedSingleton(string objectName, IDictionary scopedSingletonCache) + { + if (scopedSingletonCache == null) return null; + + lock (scopedSingletonCache.SyncRoot) { - //EnsureEventHandlersRegistered(); - } - - /// - /// Registers events handlers with to ensure - /// proper disposal of 'request'- and 'session'-scoped objects - /// - private void EnsureEventHandlersRegistered() - { - if (!s_eventHandlersRegistered) + object instance = scopedSingletonCache[objectName]; + if (instance == TemporarySingletonPlaceHolder) { - lock(typeof(WebObjectFactory)) - { - if (s_eventHandlersRegistered) return; - - if (log.IsEnabled(LogLevel.Debug)) log.LogDebug("hooking up event handlers"); - VirtualEnvironment.EndRequest += OnEndRequest; - VirtualEnvironment.EndSession += OnEndSession; - - s_eventHandlersRegistered = true; - } + throw new ObjectCurrentlyInCreationException(objectName); } - } - /// - /// Creates a new instance of the - /// class. - /// - /// The virtual path resources will be relative resolved to. - /// Flag specifying whether to make this object factory case sensitive or not. - public WebObjectFactory(string contextPath, bool caseSensitive) - : this(contextPath, caseSensitive, null) - { - } - - /// - /// Creates a new instance of the - /// class. - /// - /// The virtual path resources will be relative resolved to. - /// Flag specifying whether to make this object factory case sensitive or not. - /// - /// The parent object factory. - /// - public WebObjectFactory(string contextPath, bool caseSensitive, IObjectFactory parentFactory) - : base(caseSensitive, parentFactory) - { - this.contextPath = contextPath; - this.createObjectDictionary = (caseSensitive) - ? new ObjectDictionaryCreationHandler(CreateCaseSensitiveDictionary) - : new ObjectDictionaryCreationHandler(CreateCaseInsensitiveDictionary); - - InstantiationStrategy = new WebInstantiationStrategy(); - } - - #endregion - - /// - /// Returns the virtual path this object factory is associated with. - /// - public string ContextPath - { - get { return contextPath; } - } - - #region Convenience accessors for Http* objects - - /// - /// Convinience accessor for HttpContext - /// - private HttpContext Context - { - get { return HttpContext.Current; } - } - - /// - /// Get the table of 'request'-scoped objects. - /// - protected virtual IDictionary Request - { - get - { - IDictionary objecttable = null; - if (this.Context != null) - { - objecttable = this.Context.Items[OBJECTTABLEKEY] as IDictionary; - if (objecttable == null) - { - this.Context.Items[OBJECTTABLEKEY] = CreateObjectDictionary(); - } - } - return objecttable; - } - } - - /// - /// Get the table of 'session'-scoped objects. Returns null, if Session is disabled. - /// - protected virtual IDictionary Session - { - get - { - IDictionary objecttable = null; - if ((Context != null) && (Context.Session != null)) - { - objecttable = Context.Session[OBJECTTABLEKEY] as IDictionary; - if (objecttable == null) - { - Context.Session[OBJECTTABLEKEY] = CreateObjectDictionary(); - } - } - return objecttable; - } - } - - #endregion - - /// - /// Creates a dictionary matching this factory's case sensitivity behaviour. - /// - protected IDictionary CreateObjectDictionary() - { - return createObjectDictionary(); - } - - /// - /// Creates the root object definition. - /// - /// The template definition. - /// Root object definition. - protected override RootObjectDefinition CreateRootObjectDefinition(IObjectDefinition templateDefinition) - { - return new RootWebObjectDefinition(templateDefinition); - } - - /// - /// Tries to find cached object for the specified name. - /// - /// - /// This implementation tries to find object first in the Request scope, - /// then in the Session scope and finally in the Application scope. - /// - /// Object name to look for. - /// Cached object if found, null otherwise. - public override object GetSingleton(string objectName) - { - object instance = null; - - instance = GetScopedSingleton(objectName, this.Request); - if (instance != null) return instance; - - instance = GetScopedSingleton(objectName, this.Session); - if (instance != null) return instance; - - instance = base.GetSingleton(objectName); return instance; } + } - /// - /// Looks up an in the specified cache dictionary. - /// - /// the name to lookup. - /// the cache dictionary to search - /// the found instance. null otherwise - protected object GetScopedSingleton(string objectName, IDictionary scopedSingletonCache) + /// + /// Creates a singleton instance for the specified object name and definition. + /// + /// + /// The object name (will be used as the key in the singleton cache key). + /// + /// The object definition. + /// + /// The arguments to use if creating a prototype using explicit arguments to + /// a static factory method. It is invalid to use a non-null arguments value + /// in any other case. + /// + /// The created object instance. + protected override object CreateAndCacheSingletonInstance( + string objectName, RootObjectDefinition objectDefinition, object[] arguments) + { + if (IsWebScopedSingleton(objectDefinition)) { - if (scopedSingletonCache == null) return null; + ObjectScope scope = GetObjectScope(objectDefinition); - lock (scopedSingletonCache.SyncRoot) + if (scope == ObjectScope.Request) { - object instance = scopedSingletonCache[objectName]; - if (instance == TemporarySingletonPlaceHolder) + IDictionary requestCache = this.Request; + if (requestCache == null) { - throw new ObjectCurrentlyInCreationException(objectName); + throw new ObjectCreationException(string.Format("'request' scoped web singleton object '{0}' requires a valid Request.", objectName)); } + object instance = CreateAndCacheScopedSingletonInstance(objectName, objectDefinition, arguments, requestCache); return instance; } + else if (scope == ObjectScope.Session) + { + IDictionary sessionCache = this.Session; + if (sessionCache == null) + { + throw new ObjectCreationException(string.Format("'session' scoped web singleton object '{0}' requires a valid Session.", objectName)); + } + + object instance = CreateAndCacheScopedSingletonInstance(objectName, objectDefinition, arguments, sessionCache); + return instance; + } + + throw new ObjectDefinitionException("Web singleton objects must be either request, session or application scoped."); } - /// - /// Creates a singleton instance for the specified object name and definition. - /// - /// - /// The object name (will be used as the key in the singleton cache key). - /// - /// The object definition. - /// - /// The arguments to use if creating a prototype using explicit arguments to - /// a static factory method. It is invalid to use a non-null arguments value - /// in any other case. - /// - /// The created object instance. - protected override object CreateAndCacheSingletonInstance( - string objectName, RootObjectDefinition objectDefinition, object[] arguments) + return base.CreateAndCacheSingletonInstance(objectName, objectDefinition, arguments); + } + + /// + /// Creates a singleton instance for the specified object name and definition + /// and caches the instance in the specified dictionary + /// + /// + /// The object name (will be used as the key in the singleton cache key). + /// + /// The object definition. + /// + /// The arguments to use if creating a prototype using explicit arguments to + /// a static factory method. It is invalid to use a non-null arguments value + /// in any other case. + /// + /// the dictionary to be used for caching singleton instances + /// The created object instance. + /// + /// If the object is successfully created, + /// contains the cached instance with the key . + /// + protected virtual object CreateAndCacheScopedSingletonInstance(string objectName, RootObjectDefinition objectDefinition, object[] arguments, IDictionary scopedSingletonCache) + { + object instance; + lock (scopedSingletonCache.SyncRoot) { - if (IsWebScopedSingleton(objectDefinition)) + EnsureEventHandlersRegistered(); + + instance = scopedSingletonCache[objectName]; + if (instance == TemporarySingletonPlaceHolder) { - ObjectScope scope = GetObjectScope(objectDefinition); - - if (scope == ObjectScope.Request) + throw new ObjectCurrentlyInCreationException(objectName); + } + else if (instance == null) + { + scopedSingletonCache.Add(objectName, TemporarySingletonPlaceHolder); + try { - IDictionary requestCache = this.Request; - if (requestCache == null) - { - throw new ObjectCreationException(string.Format("'request' scoped web singleton object '{0}' requires a valid Request.", objectName)); - } - - object instance = CreateAndCacheScopedSingletonInstance(objectName, objectDefinition, arguments, requestCache); - return instance; + instance = InstantiateObject(objectName, objectDefinition, arguments, true, false); + AssertUtils.ArgumentNotNull(instance, "instance"); + scopedSingletonCache[objectName] = instance; } - else if (scope == ObjectScope.Session) + catch { - IDictionary sessionCache = this.Session; - if (sessionCache == null) - { - throw new ObjectCreationException(string.Format("'session' scoped web singleton object '{0}' requires a valid Session.", objectName)); - } - object instance = CreateAndCacheScopedSingletonInstance(objectName, objectDefinition, arguments, sessionCache); - return instance; + scopedSingletonCache.Remove(objectName); + throw; } + } + } + return instance; + } + + /// + /// We need this override so that Web Scoped Singletons are not registered in general + /// DisposalObjectRegister + /// + /// + /// + /// + protected override void RegisterDisposableObjectIfNecessary(string name, object instance, + RootObjectDefinition objectDefinition) + { + if (!IsWebScopedSingleton(objectDefinition)) + { + base.RegisterDisposableObjectIfNecessary(name, instance, objectDefinition); + } + } + + /// + /// Add the created, but yet unpopulated singleton to the singleton cache + /// to be able to resolve circular references + /// + /// the name of the object to add to the cache. + /// the definition used to create and populated the object. + /// the raw object instance. + /// + /// Derived classes may override this method to select the right cache based on the object definition. + /// + protected override void AddEagerlyCachedSingleton(string objectName, IObjectDefinition objectDefinition, object rawSingletonInstance) + { + if (IsWebScopedSingleton(objectDefinition)) + { + ObjectScope scope = GetObjectScope(objectDefinition); + if (scope == ObjectScope.Request) + { + this.Request[objectName] = rawSingletonInstance; + } + else if (scope == ObjectScope.Session) + { + this.Session[objectName] = rawSingletonInstance; + } + else + { throw new ObjectDefinitionException("Web singleton objects must be either request, session or application scoped."); } - - return base.CreateAndCacheSingletonInstance(objectName, objectDefinition, arguments); } - - /// - /// Creates a singleton instance for the specified object name and definition - /// and caches the instance in the specified dictionary - /// - /// - /// The object name (will be used as the key in the singleton cache key). - /// - /// The object definition. - /// - /// The arguments to use if creating a prototype using explicit arguments to - /// a static factory method. It is invalid to use a non-null arguments value - /// in any other case. - /// - /// the dictionary to be used for caching singleton instances - /// The created object instance. - /// - /// If the object is successfully created, - /// contains the cached instance with the key . - /// - protected virtual object CreateAndCacheScopedSingletonInstance(string objectName, RootObjectDefinition objectDefinition, object[] arguments, IDictionary scopedSingletonCache) + else { - object instance; - lock (scopedSingletonCache.SyncRoot) - { - EnsureEventHandlersRegistered(); + base.AddEagerlyCachedSingleton(objectName, objectDefinition, rawSingletonInstance); + } + } - instance = scopedSingletonCache[objectName]; - if (instance == TemporarySingletonPlaceHolder) - { - throw new ObjectCurrentlyInCreationException(objectName); - } - else if (instance == null) - { - scopedSingletonCache.Add(objectName, TemporarySingletonPlaceHolder); - try - { - instance = InstantiateObject(objectName, objectDefinition, arguments, true, false); - AssertUtils.ArgumentNotNull(instance, "instance"); - scopedSingletonCache[objectName] = instance; - } - catch - { - scopedSingletonCache.Remove(objectName); - throw; - } - } + /// + /// Remove the specified singleton from the singleton cache that has + /// been added before by a call to + /// + /// the name of the object to remove from the cache. + /// the definition used to create and populated the object. + /// + /// Derived classes may override this method to select the right cache based on the object definition. + /// + protected override void RemoveEagerlyCachedSingleton(string objectName, IObjectDefinition objectDefinition) + { + if (IsWebScopedSingleton(objectDefinition)) + { + ObjectScope scope = GetObjectScope(objectDefinition); + if (scope == ObjectScope.Request) + { + this.Request.Remove(objectName); } - return instance; - } - - /// - /// We need this override so that Web Scoped Singletons are not registered in general - /// DisposalObjectRegister - /// - /// - /// - /// - protected override void RegisterDisposableObjectIfNecessary(string name, object instance, - RootObjectDefinition objectDefinition) - { - if (!IsWebScopedSingleton(objectDefinition)) + else if (scope == ObjectScope.Session) { - base.RegisterDisposableObjectIfNecessary(name, instance, objectDefinition); - } - } - - /// - /// Add the created, but yet unpopulated singleton to the singleton cache - /// to be able to resolve circular references - /// - /// the name of the object to add to the cache. - /// the definition used to create and populated the object. - /// the raw object instance. - /// - /// Derived classes may override this method to select the right cache based on the object definition. - /// - protected override void AddEagerlyCachedSingleton(string objectName, IObjectDefinition objectDefinition, object rawSingletonInstance) - { - if (IsWebScopedSingleton(objectDefinition)) - { - ObjectScope scope = GetObjectScope(objectDefinition); - if (scope == ObjectScope.Request) - { - this.Request[objectName] = rawSingletonInstance; - } - else if (scope == ObjectScope.Session) - { - this.Session[objectName] = rawSingletonInstance; - } - else - { - throw new ObjectDefinitionException("Web singleton objects must be either request, session or application scoped."); - } + this.Session.Remove(objectName); } else { - base.AddEagerlyCachedSingleton(objectName, objectDefinition, rawSingletonInstance); + throw new ObjectDefinitionException("Web singleton objects must be either 'request' or 'session' scoped."); } } - - /// - /// Remove the specified singleton from the singleton cache that has - /// been added before by a call to - /// - /// the name of the object to remove from the cache. - /// the definition used to create and populated the object. - /// - /// Derived classes may override this method to select the right cache based on the object definition. - /// - protected override void RemoveEagerlyCachedSingleton(string objectName, IObjectDefinition objectDefinition) + else { - if (IsWebScopedSingleton(objectDefinition)) + base.RemoveEagerlyCachedSingleton(objectName, objectDefinition); + } + } + + private bool IsWebScopedSingleton(IObjectDefinition objectDefinition) + { + if (objectDefinition.IsSingleton && + (objectDefinition is IWebObjectDefinition || objectDefinition is ScannedGenericObjectDefinition)) + { + ObjectScope scope = GetObjectScope(objectDefinition); + return (scope == ObjectScope.Request) || (scope == ObjectScope.Session); + } + + return false; + } + + private ObjectScope GetObjectScope(IObjectDefinition objectDefinition) + { + if (objectDefinition is IWebObjectDefinition) + { + return ((IWebObjectDefinition) objectDefinition).Scope; + } + + ObjectScope scope = (ObjectScope) Enum.Parse(typeof(ObjectScope), objectDefinition.Scope, true); + + return scope; + } + + /// + /// Configures object instance by injecting dependencies, satisfying Spring lifecycle + /// interfaces and applying object post-processors. + /// + /// + /// The name of the object definition expressing the dependencies that are to + /// be injected into the supplied instance. + /// + /// + /// An object definition that should be used to configure object. + /// + /// + /// A wrapped object instance that is to be so configured. + /// + /// + protected override object ConfigureObject(string name, RootObjectDefinition definition, IObjectWrapper wrapper) + { + // always configure object relative to contextPath + using (new HttpContextSwitch(contextPath)) + { + return base.ConfigureObject(name, definition, wrapper); + } + } + + /// + /// Disposes all 'request'-scoped objects at the end of each Request + /// + private void OnEndRequest(HttpContext context) + { + IDictionary items = context.Items[OBJECTTABLEKEY] as IDictionary; + + if (items != null) + { + log.LogDebug("disposing 'request'-scoped item cache"); + ArrayList keys = new ArrayList(items.Keys); + for (int i = 0; i < keys.Count; i++) { - ObjectScope scope = GetObjectScope(objectDefinition); - if (scope == ObjectScope.Request) + IDisposable d = items[keys[i]] as IDisposable; + if (d != null) { - this.Request.Remove(objectName); - } - else if (scope == ObjectScope.Session) - { - this.Session.Remove(objectName); - } - else - { - throw new ObjectDefinitionException("Web singleton objects must be either 'request' or 'session' scoped."); + d.Dispose(); } } - else - { - base.RemoveEagerlyCachedSingleton(objectName, objectDefinition); - } + } + } + + /// + /// Disposes all 'session'-scoped objects at the end of a session + /// + private void OnEndSession(HttpSessionState session, CacheItemRemovedReason reason) + { + IDictionary items = null; + try + { + items = session[OBJECTTABLEKEY] as IDictionary; + } + catch + { + // ignore exceptions while accessing session } - private bool IsWebScopedSingleton(IObjectDefinition objectDefinition) + if (items != null) { - if (objectDefinition.IsSingleton && - (objectDefinition is IWebObjectDefinition || objectDefinition is ScannedGenericObjectDefinition)) + log.LogDebug("disposing 'session'-scoped item cache"); + object key = null; + try { - ObjectScope scope = GetObjectScope(objectDefinition); - return (scope == ObjectScope.Request) || (scope == ObjectScope.Session); - } - return false; - } - - private ObjectScope GetObjectScope(IObjectDefinition objectDefinition) - { - if (objectDefinition is IWebObjectDefinition) - { - return ((IWebObjectDefinition) objectDefinition).Scope; - } - - ObjectScope scope = (ObjectScope) Enum.Parse(typeof (ObjectScope), objectDefinition.Scope, true); - - return scope; - } - - /// - /// Configures object instance by injecting dependencies, satisfying Spring lifecycle - /// interfaces and applying object post-processors. - /// - /// - /// The name of the object definition expressing the dependencies that are to - /// be injected into the supplied instance. - /// - /// - /// An object definition that should be used to configure object. - /// - /// - /// A wrapped object instance that is to be so configured. - /// - /// - protected override object ConfigureObject(string name, RootObjectDefinition definition, IObjectWrapper wrapper) - { - // always configure object relative to contextPath - using (new HttpContextSwitch(contextPath)) - { - return base.ConfigureObject(name, definition, wrapper); - } - } - - /// - /// Disposes all 'request'-scoped objects at the end of each Request - /// - private void OnEndRequest(HttpContext context) - { - IDictionary items = context.Items[OBJECTTABLEKEY] as IDictionary; - - if (items != null) - { - log.LogDebug("disposing 'request'-scoped item cache"); ArrayList keys = new ArrayList(items.Keys); for (int i = 0; i < keys.Count; i++) { - IDisposable d = items[keys[i]] as IDisposable; + key = keys[i]; + IDisposable d = items[key] as IDisposable; if (d != null) { d.Dispose(); } } } - } - - /// - /// Disposes all 'session'-scoped objects at the end of a session - /// - private void OnEndSession(HttpSessionState session, CacheItemRemovedReason reason) - { - IDictionary items = null; - try + catch (Exception ex) { - items = session[OBJECTTABLEKEY] as IDictionary; + string message = string.Format("error during disposing session item with key '{0}'", key); + log.LogCritical(ex, message); } - catch - { - // ignore exceptions while accessing session - } - if (items != null) - { - log.LogDebug("disposing 'session'-scoped item cache"); - object key = null; - try - { - ArrayList keys = new ArrayList(items.Keys); - for (int i = 0; i < keys.Count; i++) - { - key = keys[i]; - IDisposable d = items[key] as IDisposable; - if (d != null) - { - d.Dispose(); - } - } - } - catch (Exception ex) - { - string message = string.Format("error during disposing session item with key '{0}'", key); - log.LogCritical(ex, message); - } - } - } - - /// - /// Creates a case insensitive hashtable instance - /// - private static IDictionary CreateCaseInsensitiveDictionary() - { - return new CaseInsensitiveHashtable(); //CollectionsUtil.CreateCaseInsensitiveHashtable(); - } - - /// - /// Creates a case sensitive hashtable instance - /// - private static IDictionary CreateCaseSensitiveDictionary() - { - return new Hashtable(); } } + + /// + /// Creates a case insensitive hashtable instance + /// + private static IDictionary CreateCaseInsensitiveDictionary() + { + return new CaseInsensitiveHashtable(); //CollectionsUtil.CreateCaseInsensitiveHashtable(); + } + + /// + /// Creates a case sensitive hashtable instance + /// + private static IDictionary CreateCaseSensitiveDictionary() + { + return new Hashtable(); + } } diff --git a/src/Spring/Spring.Web/Objects/Factory/Support/WebObjectUtils.cs b/src/Spring/Spring.Web/Objects/Factory/Support/WebObjectUtils.cs index 8e92eb1c..297cac6d 100644 --- a/src/Spring/Spring.Web/Objects/Factory/Support/WebObjectUtils.cs +++ b/src/Spring/Spring.Web/Objects/Factory/Support/WebObjectUtils.cs @@ -23,129 +23,131 @@ using Spring.Util; using IHttpHandler = System.Web.IHttpHandler; using HttpException = System.Web.HttpException; -namespace Spring.Objects.Factory.Support +namespace Spring.Objects.Factory.Support; + +/// +/// Miscellaneous utility methods to support web functionality within Spring.Objects +/// +/// Aleksandar Seovic +public sealed class WebObjectUtils { + private static ILogger s_log = LogManager.GetLogger(typeof(WebObjectUtils)); + + // CLOVER:OFF + /// - /// Miscellaneous utility methods to support web functionality within Spring.Objects + /// Creates a new instance of the class. /// - /// Aleksandar Seovic - public sealed class WebObjectUtils + /// + ///

+ /// This is a utility class, and as such exposes no public constructors. + ///

+ ///
+ private WebObjectUtils() { - private static ILogger s_log = LogManager.GetLogger( typeof( WebObjectUtils ) ); + } - // CLOVER:OFF + // CLOVER:ON - /// - /// Creates a new instance of the class. - /// - /// - ///

- /// This is a utility class, and as such exposes no public constructors. - ///

- ///
- private WebObjectUtils() - { } - - // CLOVER:ON - - - /// - /// Creates an instance of the ASPX page - /// referred to by the supplied . - /// - /// - /// The URL of the ASPX page. - /// - /// Page instance. - /// - /// If this method is not called in the scope of an active web session - /// (i.e. the implementation this method depends on this code executing - /// in the environs of a running web server such as IIS); or if the - /// page could not be instantiated (for whatever reason, such as the - /// ASPX not actually existing). - /// - public static IHttpHandler CreatePageInstance( string pageUrl ) + /// + /// Creates an instance of the ASPX page + /// referred to by the supplied . + /// + /// + /// The URL of the ASPX page. + /// + /// Page instance. + /// + /// If this method is not called in the scope of an active web session + /// (i.e. the implementation this method depends on this code executing + /// in the environs of a running web server such as IIS); or if the + /// page could not be instantiated (for whatever reason, such as the + /// ASPX not actually existing). + /// + public static IHttpHandler CreatePageInstance(string pageUrl) + { + if (s_log.IsEnabled(LogLevel.Debug)) { - if (s_log.IsEnabled(LogLevel.Debug)) - { - s_log.LogDebug("creating page instance '" + pageUrl + "'"); - } - - IHttpHandler page; - try - { - page = CreateHandler( pageUrl ); - } - catch (HttpException httpEx) - { - string msg = String.Format( "Unable to instantiate page [{0}]: {1}", pageUrl, httpEx.Message ); - if (httpEx.GetHttpCode() == 404) - { - throw new FileNotFoundException( msg ); - } - s_log.LogError(httpEx, msg); - throw new ObjectCreationException( msg, httpEx ); - } - catch (Exception ex) - { - // in case of FileNotFound recreate the exception for clarity - FileNotFoundException fnfe = ex as FileNotFoundException; - if (fnfe != null) - { - string fmsg = String.Format( "Unable to instantiate page [{0}]: The file '{1}' does not exist.", pageUrl, fnfe.Message ); - throw new FileNotFoundException( fmsg ); - } - - string msg = String.Format( "Unable to instantiate page [{0}]", pageUrl ); - s_log.LogError(ex, msg); - throw new ObjectCreationException( msg, ex ); - } - return page; + s_log.LogDebug("creating page instance '" + pageUrl + "'"); } - /// - /// Creates the raw handler instance without any exception handling - /// - /// - /// - internal static IHttpHandler CreateHandler( string pageUrl ) + IHttpHandler page; + try { - return VirtualEnvironment.CreateInstanceFromVirtualPath(pageUrl, typeof(IHttpHandler)) as IHttpHandler; + page = CreateHandler(pageUrl); + } + catch (HttpException httpEx) + { + string msg = String.Format("Unable to instantiate page [{0}]: {1}", pageUrl, httpEx.Message); + if (httpEx.GetHttpCode() == 404) + { + throw new FileNotFoundException(msg); + } + + s_log.LogError(httpEx, msg); + throw new ObjectCreationException(msg, httpEx); + } + catch (Exception ex) + { + // in case of FileNotFound recreate the exception for clarity + FileNotFoundException fnfe = ex as FileNotFoundException; + if (fnfe != null) + { + string fmsg = String.Format("Unable to instantiate page [{0}]: The file '{1}' does not exist.", pageUrl, fnfe.Message); + throw new FileNotFoundException(fmsg); + } + + string msg = String.Format("Unable to instantiate page [{0}]", pageUrl); + s_log.LogError(ex, msg); + throw new ObjectCreationException(msg, ex); } - /// - /// Returns the of the ASPX page - /// referred to by the supplied . - /// - /// - ///

- /// As indicated by the exception that can be thrown by this method, - /// the ASPX page referred to by the supplied - /// does have to be instantiated in order to determine its - /// see cref="System.Type"/> - ///

- ///
- /// - /// The filename of the ASPX page. - /// - /// - /// The of the ASPX page - /// referred to by the supplied . - /// - /// - /// If the supplied is or - /// contains only whitespace character(s). - /// - /// - /// If this method is not called in the scope of an active web session - /// (i.e. the implementation this method depends on this code executing - /// in the environs of a running web server such as IIS); or if the - /// page could not be instantiated (for whatever reason, such as the - /// ASPX not actually existing). - /// - public static Type GetPageType( string pageUrl ) - { - AssertUtils.ArgumentHasText( pageUrl, "pageUrl" ); + return page; + } + + /// + /// Creates the raw handler instance without any exception handling + /// + /// + /// + internal static IHttpHandler CreateHandler(string pageUrl) + { + return VirtualEnvironment.CreateInstanceFromVirtualPath(pageUrl, typeof(IHttpHandler)) as IHttpHandler; + } + + /// + /// Returns the of the ASPX page + /// referred to by the supplied . + /// + /// + ///

+ /// As indicated by the exception that can be thrown by this method, + /// the ASPX page referred to by the supplied + /// does have to be instantiated in order to determine its + /// see cref="System.Type"/> + ///

+ ///
+ /// + /// The filename of the ASPX page. + /// + /// + /// The of the ASPX page + /// referred to by the supplied . + /// + /// + /// If the supplied is or + /// contains only whitespace character(s). + /// + /// + /// If this method is not called in the scope of an active web session + /// (i.e. the implementation this method depends on this code executing + /// in the environs of a running web server such as IIS); or if the + /// page could not be instantiated (for whatever reason, such as the + /// ASPX not actually existing). + /// + public static Type GetPageType(string pageUrl) + { + AssertUtils.ArgumentHasText(pageUrl, "pageUrl"); // HttpContext ctx = HttpContext.Current; // if (ctx == null) @@ -153,62 +155,62 @@ namespace Spring.Objects.Factory.Support // throw new ObjectCreationException( "Unable to get page type. HttpContext is not defined." ); // } - try - { - Type pageType = GetCompiledPageType( pageUrl ); - return pageType; - } - catch (Exception ex) - { - string msg = String.Format( "Unable to get page type for url [{0}]", pageUrl ); - s_log.LogError(ex, msg); - throw new ObjectCreationException( msg, ex ); - } - } - - /// - /// Calls the underlying ASP.NET infrastructure to obtain the compiled page type - /// relative to the current . - /// - /// - /// The filename of the ASPX page relative to the current - /// - /// - /// The of the ASPX page - /// referred to by the supplied . - /// - public static Type GetCompiledPageType( string pageUrl ) + try { - if (s_log.IsEnabled(LogLevel.Debug)) - { - s_log.LogDebug("getting page type for " + pageUrl); - } - - string rootedVPath = WebUtils.CombineVirtualPaths( VirtualEnvironment.CurrentExecutionFilePath, pageUrl ); - if (s_log.IsEnabled(LogLevel.Debug)) - { - s_log.LogDebug("page vpath is " + rootedVPath); - } - - Type pageType = VirtualEnvironment.GetCompiledType(rootedVPath); - if (s_log.IsEnabled(LogLevel.Debug)) - { - s_log.LogDebug(string.Format( "got page type '{0}' for vpath '{1}'", pageType.FullName, rootedVPath )); - } + Type pageType = GetCompiledPageType(pageUrl); return pageType; } - - - /// - /// Gets the controls type from a given filename - /// - public static Type GetControlType( string controlName ) + catch (Exception ex) { - AssertUtils.ArgumentHasText( controlName, "controlName" ); - if (s_log.IsEnabled(LogLevel.Debug)) - { - s_log.LogDebug("getting control type for " + controlName); - } + string msg = String.Format("Unable to get page type for url [{0}]", pageUrl); + s_log.LogError(ex, msg); + throw new ObjectCreationException(msg, ex); + } + } + + /// + /// Calls the underlying ASP.NET infrastructure to obtain the compiled page type + /// relative to the current . + /// + /// + /// The filename of the ASPX page relative to the current + /// + /// + /// The of the ASPX page + /// referred to by the supplied . + /// + public static Type GetCompiledPageType(string pageUrl) + { + if (s_log.IsEnabled(LogLevel.Debug)) + { + s_log.LogDebug("getting page type for " + pageUrl); + } + + string rootedVPath = WebUtils.CombineVirtualPaths(VirtualEnvironment.CurrentExecutionFilePath, pageUrl); + if (s_log.IsEnabled(LogLevel.Debug)) + { + s_log.LogDebug("page vpath is " + rootedVPath); + } + + Type pageType = VirtualEnvironment.GetCompiledType(rootedVPath); + if (s_log.IsEnabled(LogLevel.Debug)) + { + s_log.LogDebug(string.Format("got page type '{0}' for vpath '{1}'", pageType.FullName, rootedVPath)); + } + + return pageType; + } + + /// + /// Gets the controls type from a given filename + /// + public static Type GetControlType(string controlName) + { + AssertUtils.ArgumentHasText(controlName, "controlName"); + if (s_log.IsEnabled(LogLevel.Debug)) + { + s_log.LogDebug("getting control type for " + controlName); + } // HttpContext ctx = HttpContext.Current; // if (ctx == null) @@ -216,33 +218,34 @@ namespace Spring.Objects.Factory.Support // throw new ObjectCreationException( "Unable to get control type. HttpContext is not defined." ); // } - string rootedVPath = WebUtils.CombineVirtualPaths( VirtualEnvironment.CurrentExecutionFilePath, controlName ); + string rootedVPath = WebUtils.CombineVirtualPaths(VirtualEnvironment.CurrentExecutionFilePath, controlName); - if (s_log.IsEnabled(LogLevel.Debug)) - { - s_log.LogDebug("control vpath is " + rootedVPath); - } - - Type controlType; - try - { - controlType = VirtualEnvironment.GetCompiledType(rootedVPath); - } - catch (HttpException httpEx) - { - // for better error-handling suppress 404 HttpExceptions here - if (httpEx.GetHttpCode() == 404) - { - throw new FileNotFoundException( string.Format( "Control '{0}' does not exist", rootedVPath ) ); - } - throw; - } - - if (s_log.IsEnabled(LogLevel.Debug)) - { - s_log.LogDebug(string.Format( "got control type '{0}' for vpath '{1}'", controlType.FullName, rootedVPath )); - } - return controlType; + if (s_log.IsEnabled(LogLevel.Debug)) + { + s_log.LogDebug("control vpath is " + rootedVPath); } + + Type controlType; + try + { + controlType = VirtualEnvironment.GetCompiledType(rootedVPath); + } + catch (HttpException httpEx) + { + // for better error-handling suppress 404 HttpExceptions here + if (httpEx.GetHttpCode() == 404) + { + throw new FileNotFoundException(string.Format("Control '{0}' does not exist", rootedVPath)); + } + + throw; + } + + if (s_log.IsEnabled(LogLevel.Debug)) + { + s_log.LogDebug(string.Format("got control type '{0}' for vpath '{1}'", controlType.FullName, rootedVPath)); + } + + return controlType; } } diff --git a/src/Spring/Spring.Web/Objects/Factory/Xml/WebObjectDefinitionDocumentReader.cs b/src/Spring/Spring.Web/Objects/Factory/Xml/WebObjectDefinitionDocumentReader.cs index 8c71e808..6de3aee1 100644 --- a/src/Spring/Spring.Web/Objects/Factory/Xml/WebObjectDefinitionDocumentReader.cs +++ b/src/Spring/Spring.Web/Objects/Factory/Xml/WebObjectDefinitionDocumentReader.cs @@ -1,19 +1,19 @@ #region License -/* - * Copyright 2002-2010 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. +/* + * Copyright 2002-2010 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 @@ -21,29 +21,28 @@ using Spring.Objects.Factory.Support; using Spring.Util; -namespace Spring.Objects.Factory.Xml +namespace Spring.Objects.Factory.Xml; + +/// +/// An capable of handling web objects (Pages,Controls). +/// +/// Erich Eichinger +internal class WebObjectDefinitionDocumentReader : DefaultObjectDefinitionDocumentReader { - /// - /// An capable of handling web objects (Pages,Controls). - /// - /// Erich Eichinger - internal class WebObjectDefinitionDocumentReader : DefaultObjectDefinitionDocumentReader + private readonly IWebObjectNameGenerator webObjectNameGenerator; + + public WebObjectDefinitionDocumentReader(IWebObjectNameGenerator webObjectNameGenerator) { - private readonly IWebObjectNameGenerator webObjectNameGenerator; - - public WebObjectDefinitionDocumentReader(IWebObjectNameGenerator webObjectNameGenerator) - { - AssertUtils.ArgumentNotNull(webObjectNameGenerator, "webObjectNameGenerator"); - this.webObjectNameGenerator = webObjectNameGenerator; - } - - /// - /// Creates an instance for the given - /// and element. - /// - protected override ObjectDefinitionParserHelper CreateHelper(XmlReaderContext readerContext, System.Xml.XmlElement root) - { - return new WebObjectDefinitionParserHelper(webObjectNameGenerator, readerContext, root); - } + AssertUtils.ArgumentNotNull(webObjectNameGenerator, "webObjectNameGenerator"); + this.webObjectNameGenerator = webObjectNameGenerator; } -} \ No newline at end of file + + /// + /// Creates an instance for the given + /// and element. + /// + protected override ObjectDefinitionParserHelper CreateHelper(XmlReaderContext readerContext, System.Xml.XmlElement root) + { + return new WebObjectDefinitionParserHelper(webObjectNameGenerator, readerContext, root); + } +} diff --git a/src/Spring/Spring.Web/Objects/Factory/Xml/WebObjectDefinitionParserHelper.cs b/src/Spring/Spring.Web/Objects/Factory/Xml/WebObjectDefinitionParserHelper.cs index 1019dd2c..545d1ea8 100644 --- a/src/Spring/Spring.Web/Objects/Factory/Xml/WebObjectDefinitionParserHelper.cs +++ b/src/Spring/Spring.Web/Objects/Factory/Xml/WebObjectDefinitionParserHelper.cs @@ -24,141 +24,141 @@ using Spring.Objects.Factory.Config; using Spring.Objects.Factory.Support; using Spring.Util; -namespace Spring.Objects.Factory.Xml +namespace Spring.Objects.Factory.Xml; + +/// +/// An capable of handling web objects (Pages,Controls) +/// +/// Erich Eichinger +internal class WebObjectDefinitionParserHelper : ObjectDefinitionParserHelper { + private readonly IWebObjectNameGenerator webObjectNameGenerator; + /// - /// An capable of handling web objects (Pages,Controls) + /// Initializes a new instance of the class. /// - /// Erich Eichinger - internal class WebObjectDefinitionParserHelper : ObjectDefinitionParserHelper + /// used for generating object definition names from web object types (page, control) + /// The reader context. + /// The root element of the xml document to parse + public WebObjectDefinitionParserHelper(IWebObjectNameGenerator webObjectNameGenerator, XmlReaderContext readerContext, XmlElement root) + : base(readerContext, root) { - private readonly IWebObjectNameGenerator webObjectNameGenerator; + AssertUtils.ArgumentNotNull(webObjectNameGenerator, "webObjectNameGenerator"); + this.webObjectNameGenerator = webObjectNameGenerator; + } - /// - /// Initializes a new instance of the class. - /// - /// used for generating object definition names from web object types (page, control) - /// The reader context. - /// The root element of the xml document to parse - public WebObjectDefinitionParserHelper(IWebObjectNameGenerator webObjectNameGenerator, XmlReaderContext readerContext, XmlElement root) - : base(readerContext, root) + protected override string PostProcessObjectNameAndAliases(string objectName, List aliases, XmlElement element, IObjectDefinition containingDefinition) + { + string url = element.GetAttribute(ObjectDefinitionConstants.TypeAttribute); + string strTypeName = url.ToLower(); + if (strTypeName.EndsWith(".aspx")) { - AssertUtils.ArgumentNotNull(webObjectNameGenerator, "webObjectNameGenerator"); - this.webObjectNameGenerator = webObjectNameGenerator; - } - - protected override string PostProcessObjectNameAndAliases(string objectName, List aliases, XmlElement element, IObjectDefinition containingDefinition) - { - string url = element.GetAttribute(ObjectDefinitionConstants.TypeAttribute); - string strTypeName = url.ToLower(); - if (strTypeName.EndsWith(".aspx")) + if (!StringUtils.HasText(objectName)) { - if (!StringUtils.HasText(objectName)) - { - objectName = webObjectNameGenerator.CreatePageDefinitionName(url); - } - - // strip leading homepath symbol ('~') from aliases if necessary - for (int ai = 0; ai < aliases.Count; ai++) - { - string alias = (string)aliases[ai]; - if (alias != null && alias.Length > 0 && alias[0] == '~') - { - aliases[ai] = "/" + alias.Substring(1).TrimStart('/', '\\'); - } - } - } - else if (strTypeName.EndsWith(".ascx") || strTypeName.EndsWith(".master")) - { - string controlName = webObjectNameGenerator.CreateControlDefinitionName(url); - if (!StringUtils.HasText(objectName)) - { - objectName = controlName; - } - else - { - aliases.Add(controlName); - } + objectName = webObjectNameGenerator.CreatePageDefinitionName(url); } - return objectName; + // strip leading homepath symbol ('~') from aliases if necessary + for (int ai = 0; ai < aliases.Count; ai++) + { + string alias = (string) aliases[ai]; + if (alias != null && alias.Length > 0 && alias[0] == '~') + { + aliases[ai] = "/" + alias.Substring(1).TrimStart('/', '\\'); + } + } + } + else if (strTypeName.EndsWith(".ascx") || strTypeName.EndsWith(".master")) + { + string controlName = webObjectNameGenerator.CreateControlDefinitionName(url); + if (!StringUtils.HasText(objectName)) + { + objectName = controlName; + } + else + { + aliases.Add(controlName); + } } - protected override ObjectDefinitionHolder CreateObjectDefinitionHolder( - XmlElement element, - IConfigurableObjectDefinition definition, - string objectName, - IReadOnlyList aliasesArray) - { - if (definition is IWebObjectDefinition webDefinition) - { - if (definition.IsSingleton - && element.HasAttribute(ObjectDefinitionConstants.ScopeAttribute)) - { - webDefinition.Scope = GetScope(element.GetAttribute(ObjectDefinitionConstants.ScopeAttribute)); - } + return objectName; + } - // force request and session scoped objects to be lazily initialized... - if (webDefinition.Scope == ObjectScope.Request - || webDefinition.Scope == ObjectScope.Session) - { - definition.IsLazyInit = true; - } + protected override ObjectDefinitionHolder CreateObjectDefinitionHolder( + XmlElement element, + IConfigurableObjectDefinition definition, + string objectName, + IReadOnlyList aliasesArray) + { + if (definition is IWebObjectDefinition webDefinition) + { + if (definition.IsSingleton + && element.HasAttribute(ObjectDefinitionConstants.ScopeAttribute)) + { + webDefinition.Scope = GetScope(element.GetAttribute(ObjectDefinitionConstants.ScopeAttribute)); + } + + // force request and session scoped objects to be lazily initialized... + if (webDefinition.Scope == ObjectScope.Request + || webDefinition.Scope == ObjectScope.Session) + { + definition.IsLazyInit = true; + } // string typeName = element.GetAttribute(ObjectDefinitionConstants.TypeAttribute); - string typeName = definition.ObjectTypeName; - if (typeName != null - && (typeName.EndsWith(".ascx") || typeName.EndsWith(".master"))) - { - definition.IsAbstract = true; - } - } - - ObjectDefinitionHolder holder = base.CreateObjectDefinitionHolder(element, definition, objectName, aliasesArray); - return holder; - } - - /// - /// Gets the scope out of the supplied . - /// - /// - ///

- /// If the supplied is invalid - /// (i.e. it does not resolve to one of the - /// values), - /// then the return value of this method call will be - /// ; - /// no exception will be raised (although the value of the invalid - /// scope will be logged). - ///

- ///
- /// The string containing the scope name. - /// The scope. - /// - private ObjectScope GetScope(string value) - { - ObjectScope scope = ObjectScope.Default; - if (StringUtils.HasText(value)) + string typeName = definition.ObjectTypeName; + if (typeName != null + && (typeName.EndsWith(".ascx") || typeName.EndsWith(".master"))) { - try - { - scope = (ObjectScope)Enum.Parse(typeof(ObjectScope), value, true); - } - catch (ArgumentException ex) - { - #region Instrumentation - - if (log.IsEnabled(LogLevel.Debug)) - { - string message = string.Format("Error while parsing object scope : '{0}' is an invalid value.", - value); - log.LogDebug(ex, message); - } - - #endregion - } + definition.IsAbstract = true; } - return scope; } + + ObjectDefinitionHolder holder = base.CreateObjectDefinitionHolder(element, definition, objectName, aliasesArray); + return holder; + } + + /// + /// Gets the scope out of the supplied . + /// + /// + ///

+ /// If the supplied is invalid + /// (i.e. it does not resolve to one of the + /// values), + /// then the return value of this method call will be + /// ; + /// no exception will be raised (although the value of the invalid + /// scope will be logged). + ///

+ ///
+ /// The string containing the scope name. + /// The scope. + /// + private ObjectScope GetScope(string value) + { + ObjectScope scope = ObjectScope.Default; + if (StringUtils.HasText(value)) + { + try + { + scope = (ObjectScope) Enum.Parse(typeof(ObjectScope), value, true); + } + catch (ArgumentException ex) + { + #region Instrumentation + + if (log.IsEnabled(LogLevel.Debug)) + { + string message = string.Format("Error while parsing object scope : '{0}' is an invalid value.", + value); + log.LogDebug(ex, message); + } + + #endregion + } + } + + return scope; } } diff --git a/src/Spring/Spring.Web/Objects/Factory/Xml/WebObjectDefinitionReader.cs b/src/Spring/Spring.Web/Objects/Factory/Xml/WebObjectDefinitionReader.cs index c5c8ff35..ca39e09d 100644 --- a/src/Spring/Spring.Web/Objects/Factory/Xml/WebObjectDefinitionReader.cs +++ b/src/Spring/Spring.Web/Objects/Factory/Xml/WebObjectDefinitionReader.cs @@ -22,75 +22,74 @@ using System.Xml; using Spring.Objects.Factory.Support; using Spring.Util; -namespace Spring.Objects.Factory.Xml +namespace Spring.Objects.Factory.Xml; + +/// +/// An capable of handling web object definitions (Pages, Controls) +/// +/// Erich Eichinger +public class WebObjectDefinitionReader : XmlObjectDefinitionReader, IWebObjectNameGenerator { + private readonly string contextVirtualPath; + /// - /// An capable of handling web object definitions (Pages, Controls) + /// Creates a new instance of the + /// class. /// - /// Erich Eichinger - public class WebObjectDefinitionReader : XmlObjectDefinitionReader, IWebObjectNameGenerator + /// the (rooted) virtual path to resolve relative virtual paths. + /// + /// The + /// instance that this reader works on. + /// + /// the to use for resolving entities. + public WebObjectDefinitionReader(string contextVirtualPath, IObjectDefinitionRegistry registry, XmlResolver resolver) + : base(registry, resolver, new WebObjectDefinitionFactory()) { - private readonly string contextVirtualPath; - - /// - /// Creates a new instance of the - /// class. - /// - /// the (rooted) virtual path to resolve relative virtual paths. - /// - /// The - /// instance that this reader works on. - /// - /// the to use for resolving entities. - public WebObjectDefinitionReader(string contextVirtualPath, IObjectDefinitionRegistry registry, XmlResolver resolver) - : base(registry, resolver, new WebObjectDefinitionFactory()) - { - this.contextVirtualPath = contextVirtualPath; - } - - /// - /// Creates the to use for actually - /// reading object definitions from an XML document. - /// - protected override IObjectDefinitionDocumentReader CreateObjectDefinitionDocumentReader() - { - return new WebObjectDefinitionDocumentReader(this); - } - - string IWebObjectNameGenerator.CreatePageDefinitionName(string virtualPath) - { - return CreatePageDefinitionName(virtualPath); - } - - string IWebObjectNameGenerator.CreateControlDefinitionName(string virtualPath) - { - return CreateControlDefinitionName(virtualPath); - } - - /// - /// Create an object definition name for the given control path - /// - protected virtual string CreateControlDefinitionName(string virtualPath) - { - string objectName; - objectName = WebObjectUtils.GetControlType(virtualPath).FullName; - return objectName; - } - - /// - /// Create an object definition name for the given page path - /// - protected virtual string CreatePageDefinitionName(string url) - { - string objectName; - objectName = WebUtils.CombineVirtualPaths(VirtualEnvironment.CurrentExecutionFilePath, url); - string appPath = VirtualEnvironment.ApplicationVirtualPath; - if (objectName.ToLower().StartsWith(appPath.ToLower())) - { - objectName = objectName.Substring(appPath.Length-1); - } - - return objectName; - } + this.contextVirtualPath = contextVirtualPath; } -} \ No newline at end of file + + /// + /// Creates the to use for actually + /// reading object definitions from an XML document. + /// + protected override IObjectDefinitionDocumentReader CreateObjectDefinitionDocumentReader() + { + return new WebObjectDefinitionDocumentReader(this); + } + + string IWebObjectNameGenerator.CreatePageDefinitionName(string virtualPath) + { + return CreatePageDefinitionName(virtualPath); + } + + string IWebObjectNameGenerator.CreateControlDefinitionName(string virtualPath) + { + return CreateControlDefinitionName(virtualPath); + } + + /// + /// Create an object definition name for the given control path + /// + protected virtual string CreateControlDefinitionName(string virtualPath) + { + string objectName; + objectName = WebObjectUtils.GetControlType(virtualPath).FullName; + return objectName; + } + + /// + /// Create an object definition name for the given page path + /// + protected virtual string CreatePageDefinitionName(string url) + { + string objectName; + objectName = WebUtils.CombineVirtualPaths(VirtualEnvironment.CurrentExecutionFilePath, url); + string appPath = VirtualEnvironment.ApplicationVirtualPath; + if (objectName.ToLower().StartsWith(appPath.ToLower())) + { + objectName = objectName.Substring(appPath.Length - 1); + } + + return objectName; + } +} diff --git a/src/Spring/Spring.Web/Threading/HttpContextStorage.cs b/src/Spring/Spring.Web/Threading/HttpContextStorage.cs index ae70c40e..25c8b328 100644 --- a/src/Spring/Spring.Web/Threading/HttpContextStorage.cs +++ b/src/Spring/Spring.Web/Threading/HttpContextStorage.cs @@ -1,40 +1,39 @@ using System.Web; -namespace Spring.Threading +namespace Spring.Threading; + +/// +/// Implements by using . +/// +/// Erich Eichinger +public class HttpContextStorage : IThreadStorage { /// - /// Implements by using . + /// Retrieves an object with the specified name. /// - /// Erich Eichinger - public class HttpContextStorage : IThreadStorage + /// The name of the item. + /// The object in the context associated with the specified name or null if no object has been stored previously + public object GetData(string name) { - /// - /// Retrieves an object with the specified name. - /// - /// The name of the item. - /// The object in the context associated with the specified name or null if no object has been stored previously - public object GetData(string name) - { - return HttpContext.Current.Items[name]; - } + return HttpContext.Current.Items[name]; + } - /// - /// Stores a given object and associates it with the specified name. - /// - /// The name with which to associate the new item. - /// The object to store in the call context. - public void SetData(string name, object value) - { - HttpContext.Current.Items[name] = value; - } + /// + /// Stores a given object and associates it with the specified name. + /// + /// The name with which to associate the new item. + /// The object to store in the call context. + public void SetData(string name, object value) + { + HttpContext.Current.Items[name] = value; + } - /// - /// Empties a data slot with the specified name. - /// - /// The name of the data slot to empty. - public void FreeNamedDataSlot(string name) - { - HttpContext.Current.Items.Remove(name); - } + /// + /// Empties a data slot with the specified name. + /// + /// The name of the data slot to empty. + public void FreeNamedDataSlot(string name) + { + HttpContext.Current.Items.Remove(name); } } \ No newline at end of file diff --git a/src/Spring/Spring.Web/Threading/HybridContextStorage.cs b/src/Spring/Spring.Web/Threading/HybridContextStorage.cs index 0004f916..b0fd5509 100644 --- a/src/Spring/Spring.Web/Threading/HybridContextStorage.cs +++ b/src/Spring/Spring.Web/Threading/HybridContextStorage.cs @@ -1,70 +1,69 @@ using System.Runtime.Remoting.Messaging; using System.Web; -namespace Spring.Threading +namespace Spring.Threading; + +/// +/// Implements by using both and and choosing dynamically between them. +/// +/// +/// In web applications a single Request may be executed on different threads. In this case HttpContext.Current is the only invariant.
+/// This implementation dynamically chooses between System.Runtime.Remoting.Messaging.CallContext +/// and System.Web.HttpContext to store data. +///
+/// Erich Eichinger +public class HybridContextStorage : IThreadStorage { /// - /// Implements by using both and and choosing dynamically between them. + /// Retrieves an object with the specified name. /// - /// - /// In web applications a single Request may be executed on different threads. In this case HttpContext.Current is the only invariant.
- /// This implementation dynamically chooses between System.Runtime.Remoting.Messaging.CallContext - /// and System.Web.HttpContext to store data. - ///
- /// Erich Eichinger - public class HybridContextStorage : IThreadStorage + /// The name of the item. + /// The object in the context associated with the specified name or null if no object has been stored previously + public object GetData(string name) { - /// - /// Retrieves an object with the specified name. - /// - /// The name of the item. - /// The object in the context associated with the specified name or null if no object has been stored previously - public object GetData(string name) + HttpContext ctx = HttpContext.Current; + if (ctx == null) { - HttpContext ctx = HttpContext.Current; - if(ctx == null) - { - return CallContext.GetData(name); - } - else - { - return ctx.Items[name]; - } + return CallContext.GetData(name); } - - /// - /// Stores a given object and associates it with the specified name. - /// - /// The name with which to associate the new item. - /// The object to store in the call context. - public void SetData(string name, object value) + else { - HttpContext ctx = HttpContext.Current; - if(ctx == null) - { - CallContext.SetData(name, value); - } - else - { - ctx.Items[name] = value; - } + return ctx.Items[name]; } + } - /// - /// Empties a data slot with the specified name. - /// - /// The name of the data slot to empty. - public void FreeNamedDataSlot(string name) + /// + /// Stores a given object and associates it with the specified name. + /// + /// The name with which to associate the new item. + /// The object to store in the call context. + public void SetData(string name, object value) + { + HttpContext ctx = HttpContext.Current; + if (ctx == null) { - HttpContext ctx = HttpContext.Current; - if(ctx == null) - { - CallContext.FreeNamedDataSlot(name); - } - else - { - ctx.Items.Remove(name); - } + CallContext.SetData(name, value); + } + else + { + ctx.Items[name] = value; + } + } + + /// + /// Empties a data slot with the specified name. + /// + /// The name of the data slot to empty. + public void FreeNamedDataSlot(string name) + { + HttpContext ctx = HttpContext.Current; + if (ctx == null) + { + CallContext.FreeNamedDataSlot(name); + } + else + { + ctx.Items.Remove(name); } } } \ No newline at end of file diff --git a/src/Spring/Spring.Web/Util/HttpContextSwitch.cs b/src/Spring/Spring.Web/Util/HttpContextSwitch.cs index 490023af..b7a8a857 100644 --- a/src/Spring/Spring.Web/Util/HttpContextSwitch.cs +++ b/src/Spring/Spring.Web/Util/HttpContextSwitch.cs @@ -25,46 +25,45 @@ using Microsoft.Extensions.Logging; #endregion -namespace Spring.Util +namespace Spring.Util; + +/// +/// Performs a . Original path will be restored on +/// +/// +/// Rewrites the current HttpContext's filepath to <directory>/currentcontext.dummy.
+/// This affects resolving resources by calls to and
+/// Original path is restored during . +///
+/// +/// +/// using( new HttpContextSwitch( "/path" ) ) +/// { +/// Response.Write( Request.FilePath ); // writes "/path/currentcontext.dummy" to response. +/// } +/// // Request.FilePath has been reset to original url here +/// +/// +/// Erich Eichinger +public class HttpContextSwitch : IDisposable { + private readonly IDisposable rewriteContext; + private static readonly ILogger log = LogManager.GetLogger(); + /// - /// Performs a . Original path will be restored on + /// Performs an immediate call to /// - /// - /// Rewrites the current HttpContext's filepath to <directory>/currentcontext.dummy.
- /// This affects resolving resources by calls to and
- /// Original path is restored during . - ///
- /// - /// - /// using( new HttpContextSwitch( "/path" ) ) - /// { - /// Response.Write( Request.FilePath ); // writes "/path/currentcontext.dummy" to response. - /// } - /// // Request.FilePath has been reset to original url here - /// - /// - /// Erich Eichinger - public class HttpContextSwitch : IDisposable + /// a directory path (without trailing filename!) + public HttpContextSwitch(string virtualDirectory) { - private readonly IDisposable rewriteContext; - private static readonly ILogger log = LogManager.GetLogger(); + rewriteContext = VirtualEnvironment.RewritePath(virtualDirectory, false); + } - /// - /// Performs an immediate call to - /// - /// a directory path (without trailing filename!) - public HttpContextSwitch(string virtualDirectory) - { - rewriteContext = VirtualEnvironment.RewritePath(virtualDirectory, false); - } - - /// - /// Restores original path if necessary - /// - public void Dispose() - { - rewriteContext.Dispose(); - } + /// + /// Restores original path if necessary + /// + public void Dispose() + { + rewriteContext.Dispose(); } } diff --git a/src/Spring/Spring.Web/Util/ISessionState.cs b/src/Spring/Spring.Web/Util/ISessionState.cs index de01d46b..8bfcbdcb 100644 --- a/src/Spring/Spring.Web/Util/ISessionState.cs +++ b/src/Spring/Spring.Web/Util/ISessionState.cs @@ -2,47 +2,52 @@ using System.Collections; using System.Web; using System.Web.SessionState; -namespace Spring.Util +namespace Spring.Util; + +/// +/// Abstracts HttpSession +/// +public interface ISessionState : IDictionary { /// - /// Abstracts HttpSession + /// /// - public interface ISessionState : IDictionary - { - /// - /// - /// - void Abandon(); - /// - /// - /// - bool IsCookieless { get; } - /// - /// - /// - bool IsNewSession { get; } - /// - /// - /// - int LCID { get; set; } - /// - /// - /// - SessionStateMode Mode { get; } - /// - /// - /// - string SessionID { get; } - /// - /// - /// - int CodePage { get; set; } + void Abandon(); -#if !MONO - /// - /// - /// - HttpCookieMode CookieMode { get; } + /// + /// + /// + bool IsCookieless { get; } + + /// + /// + /// + bool IsNewSession { get; } + + /// + /// + /// + int LCID { get; set; } + + /// + /// + /// + SessionStateMode Mode { get; } + + /// + /// + /// + string SessionID { get; } + + /// + /// + /// + int CodePage { get; set; } + +#if !MONO + /// + /// + /// + HttpCookieMode CookieMode { get; } #endif - } -} \ No newline at end of file +} diff --git a/src/Spring/Spring.Web/Util/IVirtualEnvironment.cs b/src/Spring/Spring.Web/Util/IVirtualEnvironment.cs index c7807be4..79394fa2 100644 --- a/src/Spring/Spring.Web/Util/IVirtualEnvironment.cs +++ b/src/Spring/Spring.Web/Util/IVirtualEnvironment.cs @@ -26,72 +26,82 @@ using System.Web; #endregion -namespace Spring.Util +namespace Spring.Util; + +/// +/// Abstracts the underlying infrastructure of a HttpRequest +/// +public interface IVirtualEnvironment { /// - /// Abstracts the underlying infrastructure of a HttpRequest + /// The virtual (rooted) path of the current Application with trailing slash /// - public interface IVirtualEnvironment - { - /// - /// The virtual (rooted) path of the current Application with trailing slash - /// - /// - /// For the site rooted applications, "/" will be returned, for all others "/..someappdir../" - /// - string ApplicationVirtualPath { get; } - /// - /// The virtual (rooted) path of the current Request including - /// - string CurrentVirtualPath { get; } - /// - /// The virtual (rooted) path of the current Request without trailing - /// - string CurrentVirtualFilePath { get; } - /// - /// The virtual (rooted) path of the currently executing script - /// - /// - /// Normally this property is the same as . - /// In case of , this property returns the current script - /// whereas CurrentVirtualPath returns the original script path. - /// - string CurrentExecutionFilePath { get; } - /// - /// The query parameters - /// - NameValueCollection QueryString { get; } - /// - /// Maps a virtual path to it's physical location - /// - string MapPath( string virtualPath ); - /// - /// Rewrites the , thus also affecting - /// - IDisposable RewritePath(string newVirtualPath, bool rebaseClientPath); - /// - /// Returns the current Session's variable dictionary - /// - ISessionState Session { get; } - /// - /// Returns the current Request's variable dictionary - /// - IDictionary RequestVariables { get; } - /// - /// Returns the current Request's parameter dictionary - /// - NameValueCollection RequestParams { get; } - /// - /// Get the compiled type for the given virtual path - /// - /// the absolute (=rooted) virtual path - /// - Type GetCompiledType(string absoluteVirtualPath); - /// - /// Creates an instance from the given virtual path - /// - /// the absolute (=rooted) virtual path - /// the required base type - object CreateInstanceFromVirtualPath(string absoluteVirtualPath, Type requiredBaseType); - } -} + /// + /// For the site rooted applications, "/" will be returned, for all others "/..someappdir../" + /// + string ApplicationVirtualPath { get; } + + /// + /// The virtual (rooted) path of the current Request including + /// + string CurrentVirtualPath { get; } + + /// + /// The virtual (rooted) path of the current Request without trailing + /// + string CurrentVirtualFilePath { get; } + + /// + /// The virtual (rooted) path of the currently executing script + /// + /// + /// Normally this property is the same as . + /// In case of , this property returns the current script + /// whereas CurrentVirtualPath returns the original script path. + /// + string CurrentExecutionFilePath { get; } + + /// + /// The query parameters + /// + NameValueCollection QueryString { get; } + + /// + /// Maps a virtual path to it's physical location + /// + string MapPath(string virtualPath); + + /// + /// Rewrites the , thus also affecting + /// + IDisposable RewritePath(string newVirtualPath, bool rebaseClientPath); + + /// + /// Returns the current Session's variable dictionary + /// + ISessionState Session { get; } + + /// + /// Returns the current Request's variable dictionary + /// + IDictionary RequestVariables { get; } + + /// + /// Returns the current Request's parameter dictionary + /// + NameValueCollection RequestParams { get; } + + /// + /// Get the compiled type for the given virtual path + /// + /// the absolute (=rooted) virtual path + /// + Type GetCompiledType(string absoluteVirtualPath); + + /// + /// Creates an instance from the given virtual path + /// + /// the absolute (=rooted) virtual path + /// the required base type + object CreateInstanceFromVirtualPath(string absoluteVirtualPath, Type requiredBaseType); +} \ No newline at end of file diff --git a/src/Spring/Spring.Web/Util/SecurityCritical.cs b/src/Spring/Spring.Web/Util/SecurityCritical.cs index 5d6157fb..83b16ee9 100644 --- a/src/Spring/Spring.Web/Util/SecurityCritical.cs +++ b/src/Spring/Spring.Web/Util/SecurityCritical.cs @@ -21,48 +21,47 @@ using System.Runtime.CompilerServices; using System.Security; -namespace Spring.Util +namespace Spring.Util; + +/// +/// Utility class to be used from within this assembly for executing security critical code +/// NEVER EVER MAKE THIS PUBLIC! +/// +/// Erich Eichinger +internal class SecurityCritical { - /// - /// Utility class to be used from within this assembly for executing security critical code - /// NEVER EVER MAKE THIS PUBLIC! - /// - /// Erich Eichinger - internal class SecurityCritical - { - internal delegate void PrivilegedCallback(); + internal delegate void PrivilegedCallback(); #pragma warning disable 618 - [SecurityCritical, SecurityTreatAsSafe] + [SecurityCritical, SecurityTreatAsSafe] #pragma warning restore 618 - [MethodImpl(MethodImplOptions.NoInlining)] - internal static void ExecutePrivileged(IStackWalk permission, PrivilegedCallback callback) + [MethodImpl(MethodImplOptions.NoInlining)] + internal static void ExecutePrivileged(IStackWalk permission, PrivilegedCallback callback) + { + permission.Assert(); + try { - permission.Assert(); - try - { - callback(); - } - finally - { - CodeAccessPermission.RevertAssert(); - } + callback(); + } + finally + { + CodeAccessPermission.RevertAssert(); } - - // internal delegate TResult PrivilegedCallback(); - // - // [SecurityCritical, SecurityTreatAsSafe] - // internal static TResult ExecutePrivileged(IStackWalk permission, PrivilegedCallback callback) - // { - // permission.Assert(); - // try - // { - // return callback(); - // } - // finally - // { - // CodeAccessPermission.RevertAssert(); - // } - // } } + + // internal delegate TResult PrivilegedCallback(); + // + // [SecurityCritical, SecurityTreatAsSafe] + // internal static TResult ExecutePrivileged(IStackWalk permission, PrivilegedCallback callback) + // { + // permission.Assert(); + // try + // { + // return callback(); + // } + // finally + // { + // CodeAccessPermission.RevertAssert(); + // } + // } } diff --git a/src/Spring/Spring.Web/Util/VirtualEnvironment.cs b/src/Spring/Spring.Web/Util/VirtualEnvironment.cs index eedbd296..264f3537 100644 --- a/src/Spring/Spring.Web/Util/VirtualEnvironment.cs +++ b/src/Spring/Spring.Web/Util/VirtualEnvironment.cs @@ -30,571 +30,574 @@ using Microsoft.Extensions.Logging; #endregion -namespace Spring.Util +namespace Spring.Util; + +/// +/// Provides platform independent access to HttpRuntime methods +/// +/// +/// For e.g. testing purposes, the default environment implementation may be replaced using . +/// +/// Erich Eichinger +public sealed class VirtualEnvironment { + // default to standard HttpRuntime + private static IVirtualEnvironment instance = new HttpRuntimeEnvironment(); + /// - /// Provides platform independent access to HttpRuntime methods + /// Represents a method that handles Request related events /// - /// - /// For e.g. testing purposes, the default environment implementation may be replaced using . - /// - /// Erich Eichinger - public sealed class VirtualEnvironment + public delegate void RequestEventHandler(HttpContext context); + + /// + /// Represents a method that handles Session related events + /// + public delegate void SessionEventHandler(HttpSessionState session, CacheItemRemovedReason reason); + + private static readonly object syncEndRequestEvent = new object(); + private static RequestEventHandler s_requestEvent; + private static readonly object syncEndSessionEvent = new object(); + private static SessionEventHandler s_sessionEvent; + + private static volatile bool s_isInitialized = false; + + /// + /// Replaces the current enviroment implementation. + /// + /// the new environment implementation to be used + /// the previously set environment instance + public static IVirtualEnvironment SetInstance(IVirtualEnvironment newEnvironment) { - // default to standard HttpRuntime - private static IVirtualEnvironment instance = new HttpRuntimeEnvironment(); + IVirtualEnvironment prevEnvironment = instance; + instance = newEnvironment; + return prevEnvironment; + } - /// - /// Represents a method that handles Request related events - /// - public delegate void RequestEventHandler(HttpContext context); + #region default IVirtualEnvironment Adapter for HttpRuntime - /// - /// Represents a method that handles Session related events - /// - public delegate void SessionEventHandler(HttpSessionState session, CacheItemRemovedReason reason); + /// + /// Implementation for running within HttpRuntime + /// + private class HttpRuntimeEnvironment : IVirtualEnvironment + { + #region HttpSessionState Adapter - private static readonly object syncEndRequestEvent = new object(); - private static RequestEventHandler s_requestEvent; - private static readonly object syncEndSessionEvent = new object(); - private static SessionEventHandler s_sessionEvent; - - private static volatile bool s_isInitialized = false; - - /// - /// Replaces the current enviroment implementation. - /// - /// the new environment implementation to be used - /// the previously set environment instance - public static IVirtualEnvironment SetInstance(IVirtualEnvironment newEnvironment) + private class SessionDictionaryAdapter : ISessionState { - IVirtualEnvironment prevEnvironment = instance; - instance = newEnvironment; - return prevEnvironment; - } + private readonly HttpSessionState _sessionState; - #region default IVirtualEnvironment Adapter for HttpRuntime - - /// - /// Implementation for running within HttpRuntime - /// - private class HttpRuntimeEnvironment : IVirtualEnvironment - { - #region HttpSessionState Adapter - - private class SessionDictionaryAdapter : ISessionState + public SessionDictionaryAdapter(HttpSessionState sessionState) { - private readonly HttpSessionState _sessionState; - - public SessionDictionaryAdapter(HttpSessionState sessionState) - { - _sessionState = sessionState; - } - - - public bool Contains(object key) - { - ICollection keys = _sessionState.Keys; - foreach (string sessionKey in keys) - { - if (object.Equals(sessionKey, (string)key)) return true; - } - return false; - } - - public void Add(object key, object value) - { - _sessionState.Add((string)key, value); - } - - public void Clear() - { - _sessionState.Clear(); - } - - public IDictionaryEnumerator GetEnumerator() - { - Hashtable tableCopy = new Hashtable(); - ICollection keys = _sessionState.Keys; - foreach (string sessionKey in keys) - { - tableCopy.Add(sessionKey, _sessionState[sessionKey]); - } - return tableCopy.GetEnumerator(); - } - - public void Remove(object key) - { - _sessionState.Remove((string) key); - } - - public object this[object key] - { - get { return _sessionState[(string)key]; } - set { _sessionState[(string)key] = value; } - } - - public ICollection Keys - { - get { return _sessionState.Keys; } - } - - public ICollection Values - { - get - { - object[] values = new object[_sessionState.Count]; - _sessionState.CopyTo(values, 0); - return values; - } - } - - public bool IsReadOnly - { - get { return _sessionState.IsReadOnly; } - } - - public bool IsFixedSize - { - get { return false; } - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - public void CopyTo(Array array, int index) - { - _sessionState.CopyTo(array, index); - } - - public int Count - { - get { return _sessionState.Count; } - } - - public object SyncRoot - { - get { return _sessionState.SyncRoot; } - } - - public bool IsSynchronized - { - get { return _sessionState.IsSynchronized; } - } - - public void Abandon() - { - _sessionState.Abandon(); - } - - public bool IsCookieless - { - get { return _sessionState.IsCookieless; } - } - - public bool IsNewSession - { - get { return _sessionState.IsNewSession; } - } - - public int LCID - { - get { return _sessionState.LCID; } - set { _sessionState.LCID = value; } - } - - public SessionStateMode Mode - { - get { return _sessionState.Mode; } - } - - public string SessionID - { - get { return _sessionState.SessionID; } - } - - public int CodePage - { - get { return _sessionState.CodePage; } - set { _sessionState.CodePage = value; } - } -#if !MONO - public HttpCookieMode CookieMode - { - get { return _sessionState.CookieMode; } - } -#endif + _sessionState = sessionState; } - #endregion //HttpSessionState Adapter - - private static readonly ILogger log = LogManager.GetLogger(typeof (HttpRuntimeEnvironment)); - - private class RewriteContext : IDisposable + public bool Contains(object key) { - private string originalPath; - private bool rebaseClientPath; - private HttpContext ctx; - - public RewriteContext(string virtualDirectory, bool rebaseClientPath) + ICollection keys = _sessionState.Keys; + foreach (string sessionKey in keys) { - ctx = HttpContext.Current; - if (ctx == null) - { - return; - } - - this.rebaseClientPath = rebaseClientPath; - - string newVirtualPath = WebUtils.GetVirtualDirectory(virtualDirectory); - string currentFileDirectory = WebUtils.GetVirtualDirectory(ctx.Request.FilePath); - // only switch path if necessary - if (string.Compare(newVirtualPath, currentFileDirectory, true) != 0) - { - originalPath = ctx.Request.Url.PathAndQuery; - string newPath = newVirtualPath + "currentcontext.dummy"; - - ctx.RewritePath(newPath, rebaseClientPath); - - #region Instrumentation - - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug("rewriting path from " + currentFileDirectory + " to " + newPath + " results in " + ctx.Request.FilePath); - } - - #endregion - } + if (object.Equals(sessionKey, (string) key)) return true; } - public void Dispose() - { - if (originalPath != null) - { - if (log.IsEnabled(LogLevel.Debug)) - { - log.LogDebug("restoring path from " + ctx.Request.FilePath + " back to " + originalPath); - } - - ctx.RewritePath(originalPath, rebaseClientPath); - } - } + return false; } - public string ApplicationVirtualPath + public void Add(object key, object value) + { + _sessionState.Add((string) key, value); + } + + public void Clear() + { + _sessionState.Clear(); + } + + public IDictionaryEnumerator GetEnumerator() + { + Hashtable tableCopy = new Hashtable(); + ICollection keys = _sessionState.Keys; + foreach (string sessionKey in keys) + { + tableCopy.Add(sessionKey, _sessionState[sessionKey]); + } + + return tableCopy.GetEnumerator(); + } + + public void Remove(object key) + { + _sessionState.Remove((string) key); + } + + public object this[object key] + { + get { return _sessionState[(string) key]; } + set { _sessionState[(string) key] = value; } + } + + public ICollection Keys + { + get { return _sessionState.Keys; } + } + + public ICollection Values { get { - string appPath = HttpRuntime.AppDomainAppVirtualPath; - if (!appPath.EndsWith("/")) appPath = appPath + "/"; - return appPath; + object[] values = new object[_sessionState.Count]; + _sessionState.CopyTo(values, 0); + return values; } } - public string CurrentVirtualPath + public bool IsReadOnly { - get { return HttpContext.Current.Request.Path; } + get { return _sessionState.IsReadOnly; } } - public string CurrentVirtualFilePath + public bool IsFixedSize { - get { return HttpContext.Current.Request.FilePath; } + get { return false; } } - public string CurrentExecutionFilePath + IEnumerator IEnumerable.GetEnumerator() { - get { return HttpContext.Current.Request.CurrentExecutionFilePath; } + return GetEnumerator(); } - public NameValueCollection QueryString + public void CopyTo(Array array, int index) { - get { return HttpContext.Current.Request.QueryString; } + _sessionState.CopyTo(array, index); } - public string MapPath(string virtualPath) + public int Count { - HttpContext ctx = HttpContext.Current; - if (ctx != null) - { - return ctx.Request.MapPath(virtualPath); - } - - if (VirtualPathUtility.IsAbsolute(virtualPath) && virtualPath.StartsWith(HttpRuntime.AppDomainAppVirtualPath)) - { - virtualPath = VirtualPathUtility.ToAppRelative(virtualPath); - } - if (VirtualPathUtility.IsAppRelative(virtualPath)) - { - virtualPath = virtualPath.Substring(2); // strip "~/" - string physicalPath = Path.Combine(HttpRuntime.AppDomainAppPath, virtualPath); - return physicalPath; - } - return virtualPath; + get { return _sessionState.Count; } } - public IDisposable RewritePath(string virtualDirectory, bool rebaseClientPath) + public object SyncRoot { - return new RewriteContext(virtualDirectory, rebaseClientPath); + get { return _sessionState.SyncRoot; } } - public ISessionState Session + public bool IsSynchronized { - get { return new SessionDictionaryAdapter(HttpContext.Current.Session); } + get { return _sessionState.IsSynchronized; } } - public IDictionary RequestVariables + public void Abandon() { - get { return HttpContext.Current.Items; } + _sessionState.Abandon(); } - public NameValueCollection RequestParams + public bool IsCookieless { - get { return HttpContext.Current.Request.Params; } + get { return _sessionState.IsCookieless; } } - public Type GetCompiledType(string virtualPath) + public bool IsNewSession { - string rootedVPath = WebUtils.CombineVirtualPaths(CurrentExecutionFilePath, virtualPath); - - Type type = BuildManager.GetCompiledType(rootedVPath); - - return type; + get { return _sessionState.IsNewSession; } } - public object CreateInstanceFromVirtualPath(string virtualPath, Type requiredBaseType) + public int LCID { - string rootedVPath = WebUtils.CombineVirtualPaths(CurrentExecutionFilePath, virtualPath); - object result = BuildManager.CreateInstanceFromVirtualPath(rootedVPath, requiredBaseType); - if (!requiredBaseType.IsAssignableFrom(result.GetType())) - { - throw new HttpException(string.Format("Type '{0}' from virtual path '{1}' does not inherit from '{2}'", result.GetType(), rootedVPath, requiredBaseType)); - } - return result; + get { return _sessionState.LCID; } + set { _sessionState.LCID = value; } } + + public SessionStateMode Mode + { + get { return _sessionState.Mode; } + } + + public string SessionID + { + get { return _sessionState.SessionID; } + } + + public int CodePage + { + get { return _sessionState.CodePage; } + set { _sessionState.CodePage = value; } + } +#if !MONO + public HttpCookieMode CookieMode + { + get { return _sessionState.CookieMode; } + } +#endif } - #endregion + #endregion //HttpSessionState Adapter - /// - /// The virtual (rooted) path of the current Application containing a leading '/' as well as a trailing '/' - /// - public static string ApplicationVirtualPath + private static readonly ILogger log = LogManager.GetLogger(typeof(HttpRuntimeEnvironment)); + + private class RewriteContext : IDisposable { - get { return instance.ApplicationVirtualPath; } + private string originalPath; + private bool rebaseClientPath; + private HttpContext ctx; + + public RewriteContext(string virtualDirectory, bool rebaseClientPath) + { + ctx = HttpContext.Current; + if (ctx == null) + { + return; + } + + this.rebaseClientPath = rebaseClientPath; + + string newVirtualPath = WebUtils.GetVirtualDirectory(virtualDirectory); + string currentFileDirectory = WebUtils.GetVirtualDirectory(ctx.Request.FilePath); + // only switch path if necessary + if (string.Compare(newVirtualPath, currentFileDirectory, true) != 0) + { + originalPath = ctx.Request.Url.PathAndQuery; + string newPath = newVirtualPath + "currentcontext.dummy"; + + ctx.RewritePath(newPath, rebaseClientPath); + + #region Instrumentation + + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug("rewriting path from " + currentFileDirectory + " to " + newPath + " results in " + ctx.Request.FilePath); + } + + #endregion + } + } + + public void Dispose() + { + if (originalPath != null) + { + if (log.IsEnabled(LogLevel.Debug)) + { + log.LogDebug("restoring path from " + ctx.Request.FilePath + " back to " + originalPath); + } + + ctx.RewritePath(originalPath, rebaseClientPath); + } + } } - /// - /// The virtual (rooted) path of the current Request including - /// - public static string CurrentVirtualPath - { - get { return instance.CurrentVirtualPath; } - } - - /// - /// The virtual (rooted) path of the current Request including - /// - public static string CurrentVirtualPathAndQuery + public string ApplicationVirtualPath { get { - string result = CurrentVirtualPath; - if (QueryString.Count > 0) - { - result = result + "?" + QueryString.ToString(); - } - return result; + string appPath = HttpRuntime.AppDomainAppVirtualPath; + if (!appPath.EndsWith("/")) appPath = appPath + "/"; + return appPath; } } - /// - /// The virtual (rooted) path of the current Request without trailing - /// - public static string CurrentVirtualFilePath + public string CurrentVirtualPath { - get { return instance.CurrentVirtualFilePath; } + get { return HttpContext.Current.Request.Path; } } - /// - /// The virtual (rooted) path of the currently executing script - /// - public static string CurrentExecutionFilePath + public string CurrentVirtualFilePath { - get { return instance.CurrentExecutionFilePath; } + get { return HttpContext.Current.Request.FilePath; } } - /// - /// The query parameters - /// - public static NameValueCollection QueryString + public string CurrentExecutionFilePath { - get { return instance.QueryString; } + get { return HttpContext.Current.Request.CurrentExecutionFilePath; } } - /// - /// Returns the current Request's variable dictionary () - /// - public static IDictionary RequestVariables + public NameValueCollection QueryString { - get { return instance.RequestVariables; } + get { return HttpContext.Current.Request.QueryString; } } - /// - /// Returns the current Request's parameter dictionary () - /// - public static NameValueCollection RequestParams + public string MapPath(string virtualPath) { - get { return instance.RequestParams; } - } - - /// - /// Maps a virtual path to it's physical location - /// - public static string MapPath(string virtualPath) - { - return instance.MapPath(virtualPath); - } - - /// - /// Rewrites the , thus also affecting - /// - public static IDisposable RewritePath(string newVirtualPath, bool rebaseClientPath) - { - return instance.RewritePath(newVirtualPath, rebaseClientPath); - } - - /// - /// Returns an instance of the specified file. - /// - public static object CreateInstanceFromVirtualPath(string virtualPath, Type requiredBaseType) - { - string rootedVPath = WebUtils.CombineVirtualPaths(instance.CurrentExecutionFilePath, virtualPath); - return instance.CreateInstanceFromVirtualPath(rootedVPath, requiredBaseType); - } - - /// - /// Returns an the compiled type of the specified file. - /// - public static Type GetCompiledType(string virtualPath) - { - string rootedVPath = WebUtils.CombineVirtualPaths(instance.CurrentExecutionFilePath, virtualPath); - return instance.GetCompiledType(rootedVPath); - } - - /// - /// Receives EndRequest-event from an instance - /// and dispatches it to all handlers registered with this module. - /// - /// the HttpApplication instance sending this event - /// always - public static void RaiseEndRequest(object sender, EventArgs e) - { - // NOTE: don't sync here for performance reasons. - // It is assumed, that all handlers are registered during application startup - if (s_requestEvent != null) + HttpContext ctx = HttpContext.Current; + if (ctx != null) { - s_requestEvent(((HttpApplication)sender).Context); + return ctx.Request.MapPath(virtualPath); } - } - /// - /// Receives the EndSession-event and dispatches it to all handlers - /// registered with this module. - /// - public static void RaiseEndSession(HttpSessionState sessionState, CacheItemRemovedReason reason) - { - // NOTE: don't sync here for performance reasons. - // It is assumed, that all handlers are registered during application startup - if (s_sessionEvent != null) + if (VirtualPathUtility.IsAbsolute(virtualPath) && virtualPath.StartsWith(HttpRuntime.AppDomainAppVirtualPath)) { - s_sessionEvent(sessionState, reason); + virtualPath = VirtualPathUtility.ToAppRelative(virtualPath); } - } - /// - /// Register with this event to receive any EndRequest event occuring in the current AppDomain. - /// - public static event RequestEventHandler EndRequest - { - add + if (VirtualPathUtility.IsAppRelative(virtualPath)) { - AssertInitialized(); - lock (syncEndRequestEvent) - { - s_requestEvent += value; - } - } - remove - { - AssertInitialized(); - lock (syncEndRequestEvent) - { - s_requestEvent -= value; - } + virtualPath = virtualPath.Substring(2); // strip "~/" + string physicalPath = Path.Combine(HttpRuntime.AppDomainAppPath, virtualPath); + return physicalPath; } + + return virtualPath; } - /// - /// Register with this event to receive any EndSession event occuring in the current AppDomain - /// - /// - /// This event may be raised asynchronously on it's own thread. - /// Don't rely on e.g. being available. - /// - public static event SessionEventHandler EndSession + public IDisposable RewritePath(string virtualDirectory, bool rebaseClientPath) { - add - { - AssertInitialized(); - lock (syncEndSessionEvent) - { - s_sessionEvent += value; - } - } - remove - { - AssertInitialized(); - lock (syncEndSessionEvent) - { - s_sessionEvent -= value; - } - } + return new RewriteContext(virtualDirectory, rebaseClientPath); } - /// - /// Signals, that VirtualEnvironment is ready to accept - /// handler registrations for EndRequest and EndSession events - /// - public static void SetInitialized() + public ISessionState Session { - s_isInitialized = true; + get { return new SessionDictionaryAdapter(HttpContext.Current.Session); } } - /// - /// Is this VirtualEnviroment ready to accept handler registrations - /// for EndRequest and EndSession events ? - /// - public static bool IsInitialized + public IDictionary RequestVariables { - get { return s_isInitialized; } + get { return HttpContext.Current.Items; } } - /// - /// Ensures, that WebSupportModule has been initialized. Otherwise an exception is thrown. - /// - private static void AssertInitialized() + public NameValueCollection RequestParams { - if (!s_isInitialized) + get { return HttpContext.Current.Request.Params; } + } + + public Type GetCompiledType(string virtualPath) + { + string rootedVPath = WebUtils.CombineVirtualPaths(CurrentExecutionFilePath, virtualPath); + + Type type = BuildManager.GetCompiledType(rootedVPath); + + return type; + } + + public object CreateInstanceFromVirtualPath(string virtualPath, Type requiredBaseType) + { + string rootedVPath = WebUtils.CombineVirtualPaths(CurrentExecutionFilePath, virtualPath); + object result = BuildManager.CreateInstanceFromVirtualPath(rootedVPath, requiredBaseType); + if (!requiredBaseType.IsAssignableFrom(result.GetType())) { - string msg = - @"WebSupportModule not initialized. Did you forget to add " + - @" " + - @"to your web.config's -section?"; - throw ConfigurationUtils.CreateConfigurationException(msg); + throw new HttpException(string.Format("Type '{0}' from virtual path '{1}' does not inherit from '{2}'", result.GetType(), rootedVPath, requiredBaseType)); } - } + return result; + } } -} + + #endregion + + /// + /// The virtual (rooted) path of the current Application containing a leading '/' as well as a trailing '/' + /// + public static string ApplicationVirtualPath + { + get { return instance.ApplicationVirtualPath; } + } + + /// + /// The virtual (rooted) path of the current Request including + /// + public static string CurrentVirtualPath + { + get { return instance.CurrentVirtualPath; } + } + + /// + /// The virtual (rooted) path of the current Request including + /// + public static string CurrentVirtualPathAndQuery + { + get + { + string result = CurrentVirtualPath; + if (QueryString.Count > 0) + { + result = result + "?" + QueryString.ToString(); + } + + return result; + } + } + + /// + /// The virtual (rooted) path of the current Request without trailing + /// + public static string CurrentVirtualFilePath + { + get { return instance.CurrentVirtualFilePath; } + } + + /// + /// The virtual (rooted) path of the currently executing script + /// + public static string CurrentExecutionFilePath + { + get { return instance.CurrentExecutionFilePath; } + } + + /// + /// The query parameters + /// + public static NameValueCollection QueryString + { + get { return instance.QueryString; } + } + + /// + /// Returns the current Request's variable dictionary () + /// + public static IDictionary RequestVariables + { + get { return instance.RequestVariables; } + } + + /// + /// Returns the current Request's parameter dictionary () + /// + public static NameValueCollection RequestParams + { + get { return instance.RequestParams; } + } + + /// + /// Maps a virtual path to it's physical location + /// + public static string MapPath(string virtualPath) + { + return instance.MapPath(virtualPath); + } + + /// + /// Rewrites the , thus also affecting + /// + public static IDisposable RewritePath(string newVirtualPath, bool rebaseClientPath) + { + return instance.RewritePath(newVirtualPath, rebaseClientPath); + } + + /// + /// Returns an instance of the specified file. + /// + public static object CreateInstanceFromVirtualPath(string virtualPath, Type requiredBaseType) + { + string rootedVPath = WebUtils.CombineVirtualPaths(instance.CurrentExecutionFilePath, virtualPath); + return instance.CreateInstanceFromVirtualPath(rootedVPath, requiredBaseType); + } + + /// + /// Returns an the compiled type of the specified file. + /// + public static Type GetCompiledType(string virtualPath) + { + string rootedVPath = WebUtils.CombineVirtualPaths(instance.CurrentExecutionFilePath, virtualPath); + return instance.GetCompiledType(rootedVPath); + } + + /// + /// Receives EndRequest-event from an instance + /// and dispatches it to all handlers registered with this module. + /// + /// the HttpApplication instance sending this event + /// always + public static void RaiseEndRequest(object sender, EventArgs e) + { + // NOTE: don't sync here for performance reasons. + // It is assumed, that all handlers are registered during application startup + if (s_requestEvent != null) + { + s_requestEvent(((HttpApplication) sender).Context); + } + } + + /// + /// Receives the EndSession-event and dispatches it to all handlers + /// registered with this module. + /// + public static void RaiseEndSession(HttpSessionState sessionState, CacheItemRemovedReason reason) + { + // NOTE: don't sync here for performance reasons. + // It is assumed, that all handlers are registered during application startup + if (s_sessionEvent != null) + { + s_sessionEvent(sessionState, reason); + } + } + + /// + /// Register with this event to receive any EndRequest event occuring in the current AppDomain. + /// + public static event RequestEventHandler EndRequest + { + add + { + AssertInitialized(); + lock (syncEndRequestEvent) + { + s_requestEvent += value; + } + } + remove + { + AssertInitialized(); + lock (syncEndRequestEvent) + { + s_requestEvent -= value; + } + } + } + + /// + /// Register with this event to receive any EndSession event occuring in the current AppDomain + /// + /// + /// This event may be raised asynchronously on it's own thread. + /// Don't rely on e.g. being available. + /// + public static event SessionEventHandler EndSession + { + add + { + AssertInitialized(); + lock (syncEndSessionEvent) + { + s_sessionEvent += value; + } + } + remove + { + AssertInitialized(); + lock (syncEndSessionEvent) + { + s_sessionEvent -= value; + } + } + } + + /// + /// Signals, that VirtualEnvironment is ready to accept + /// handler registrations for EndRequest and EndSession events + /// + public static void SetInitialized() + { + s_isInitialized = true; + } + + /// + /// Is this VirtualEnviroment ready to accept handler registrations + /// for EndRequest and EndSession events ? + /// + public static bool IsInitialized + { + get { return s_isInitialized; } + } + + /// + /// Ensures, that WebSupportModule has been initialized. Otherwise an exception is thrown. + /// + private static void AssertInitialized() + { + if (!s_isInitialized) + { + string msg = + @"WebSupportModule not initialized. Did you forget to add " + + @" " + + @"to your web.config's -section?"; + throw ConfigurationUtils.CreateConfigurationException(msg); + } + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Web/Util/WebUtils.cs b/src/Spring/Spring.Web/Util/WebUtils.cs index ad00e23f..aa16a39c 100644 --- a/src/Spring/Spring.Web/Util/WebUtils.cs +++ b/src/Spring/Spring.Web/Util/WebUtils.cs @@ -25,306 +25,311 @@ using System.Web.UI; #endregion -namespace Spring.Util +namespace Spring.Util; + +/// +/// Miscellaneous web utility methods. +/// +/// Aleksandar Seovic +public sealed class WebUtils { + #region Constructor (s) / Destructor + + // CLOVER:OFF + /// - /// Miscellaneous web utility methods. + /// Creates a new instance of the class. /// - /// Aleksandar Seovic - public sealed class WebUtils + /// + ///

+ /// This is a utility class, and as such exposes no public constructors. + ///

+ ///
+ private WebUtils() { - #region Constructor (s) / Destructor + } - // CLOVER:OFF + // CLOVER:ON - /// - /// Creates a new instance of the class. - /// - /// - ///

- /// This is a utility class, and as such exposes no public constructors. - ///

- ///
- private WebUtils() - {} + #endregion - // CLOVER:ON + /// + /// Default protocol used for resolving resources in web applications + /// + internal static readonly string DEFAULT_RESOURCE_PROTOCOL = "web"; - #endregion - - /// - /// Default protocol used for resolving resources in web applications - /// - internal static readonly string DEFAULT_RESOURCE_PROTOCOL = "web"; - - /// - /// Extracts the bare ASPX page name without any extension from the - /// supplied . - /// - /// - ///

- /// Examples of what would be returned from this method given a url would be: - ///

- ///

- /// - /// 'Login.aspx' => 'Login' - /// '~/Login.aspx' => 'Login' - /// '~/B2B/SignUp.aspx' => 'SignUp' - /// 'B2B/Foo/FooServices.aspx' => 'FooServices' - /// - ///

- ///
- /// The full URL to the ASPX page. - /// - /// The bare ASPX page name without any extension. - /// - /// - /// If the supplied is or - /// contains only whitespace character(s). - /// - public static string GetPageName(string url) + /// + /// Extracts the bare ASPX page name without any extension from the + /// supplied . + /// + /// + ///

+ /// Examples of what would be returned from this method given a url would be: + ///

+ ///

+ /// + /// 'Login.aspx' => 'Login' + /// '~/Login.aspx' => 'Login' + /// '~/B2B/SignUp.aspx' => 'SignUp' + /// 'B2B/Foo/FooServices.aspx' => 'FooServices' + /// + ///

+ ///
+ /// The full URL to the ASPX page. + /// + /// The bare ASPX page name without any extension. + /// + /// + /// If the supplied is or + /// contains only whitespace character(s). + /// + public static string GetPageName(string url) + { + AssertUtils.ArgumentHasText(url, "url"); + int lastSlash = url.LastIndexOf('/'); + int lastDot = url.LastIndexOf('.'); + if (lastDot < lastSlash) { - AssertUtils.ArgumentHasText(url, "url"); - int lastSlash = url.LastIndexOf('/'); - int lastDot = url.LastIndexOf('.'); - if (lastDot < lastSlash) - { - lastDot = -1; - } - if (lastDot < 0) - { - int length = url.Length - lastSlash - 1; - return url.Substring(lastSlash + 1, length); - } - - return url.Substring(lastSlash + 1, lastDot - lastSlash - 1); + lastDot = -1; } - /// - /// Returns only the directory portion of a virtual path - /// - /// - /// The returned path is guaranteed to always have a leading and a trailing slash.
- /// If a path does not end with a file-extension it is assumed to be a directory - ///
- public static string GetVirtualDirectory(string virtualPath) + if (lastDot < 0) { - AssertUtils.ArgumentNotNull(virtualPath, "virtualPath"); - - if (virtualPath.Length == 0) - { - return "/"; - } - - if (virtualPath[0] != '/') - { - virtualPath = "/" + virtualPath; - } - - if (virtualPath[virtualPath.Length - 1] != '/') - { - int iDot = virtualPath.LastIndexOf('.'); - int iSlash = virtualPath.LastIndexOf('/'); - if (iDot < iSlash) iDot = -1; - if (iDot > -1) - { - virtualPath = virtualPath.Substring(0, iSlash + 1); - } - else - { - virtualPath = virtualPath + "/"; - } - } - return virtualPath; + int length = url.Length - lastSlash - 1; + return url.Substring(lastSlash + 1, length); } - /// - /// Returns absolute path that can be referenced within plain HTML. - /// - /// - ///

- /// If relative path starts with '/' (forward slash), no concatenation will occur - /// and it will be assumed that the relative path specified is indeed the absolute path - /// and will be returned verbatim.

- ///

- /// Otherwise, relative path will be appended to the application path, while making sure that - /// path separators are not duplicated between the paths.

- ///
- /// Application path. - /// Relative path to combine with the application path. - /// Absolute path. - public static string CreateAbsolutePath(string applicationPath, string relativePath) + return url.Substring(lastSlash + 1, lastDot - lastSlash - 1); + } + + /// + /// Returns only the directory portion of a virtual path + /// + /// + /// The returned path is guaranteed to always have a leading and a trailing slash.
+ /// If a path does not end with a file-extension it is assumed to be a directory + ///
+ public static string GetVirtualDirectory(string virtualPath) + { + AssertUtils.ArgumentNotNull(virtualPath, "virtualPath"); + + if (virtualPath.Length == 0) { - if (StringUtils.HasLength(relativePath)) - { - if (relativePath.ToLower().StartsWith("http://") || relativePath.ToLower().StartsWith("https://")) - { - return relativePath; - } - - if (relativePath.StartsWith("/")) - { - return relativePath; - } - - if (relativePath.StartsWith("~/")) - { - relativePath = relativePath.Substring(2); - } - } - - applicationPath = (applicationPath == null) ? "" : applicationPath.TrimEnd('/'); - - return string.Format("{0}/{1}", applicationPath, relativePath); + return "/"; } - /// - /// Combines a rooted base path with a relative path. - /// - /// Must be a path starting with '/' - /// the path to be combined. May start with basepath Placeholder '~' - /// the combined path - /// - /// If relativePath starts with '~', rootPath is ignored and '~' resolves to the current AppDomain's application virtual path
- /// If relativePath start with '/', rootPath is ignored and relativePath is returned as-is. - ///
- public static string CombineVirtualPaths(string rootPath, string relativePath) + if (virtualPath[0] != '/') { - AssertUtils.ArgumentHasText(rootPath, "rootPath"); - if (rootPath[0] != '/') - { - throw new ArgumentException("RootPath must start with '/'", "rootPath"); - } - - string combinedPath = relativePath; - - if (combinedPath.StartsWith("~/")) - { - combinedPath = VirtualEnvironment.ApplicationVirtualPath.TrimEnd('/') + relativePath.Substring(1); - } - - if (!combinedPath.StartsWith("/")) - { - combinedPath = GetVirtualDirectory(rootPath).TrimEnd('/') + '/' + relativePath; - } - - // TODO: reduce contained directory upwalks here - - return combinedPath; + virtualPath = "/" + virtualPath; } - /// - /// Gets the application-relative virtual path portion of the given absolute URL. - /// - /// the absolute url - /// the url relative to the current application's virtual path - public static string GetAppRelativePath(string url) + if (virtualPath[virtualPath.Length - 1] != '/') { - string appPath = VirtualEnvironment.ApplicationVirtualPath; - return GetRelativePath(appPath, url); - } - - /// - /// Gets a normalized application-relative virtual path of the given virtual path. - /// - /// - ///

- /// Examples of what would be returned from this method given a virtual path would be: - ///

- ///

- /// - /// 'Login.aspx' => 'Login.aspx' - /// '~/Login.aspx' => '/Login.aspx' - /// '~/B2B/SignUp.aspx' => '/B2B/SignUp.aspx' - /// 'B2B/Foo/FooServices.aspx' => 'B2B/Foo/FooServices.aspx' - /// - ///

- ///
- /// the virtual path. - /// the normalized virtual path - public static string GetNormalizedVirtualPath(string virtualPath) - { - if(String.IsNullOrEmpty(virtualPath)) + int iDot = virtualPath.LastIndexOf('.'); + int iSlash = virtualPath.LastIndexOf('/'); + if (iDot < iSlash) iDot = -1; + if (iDot > -1) { - return virtualPath; - } - return virtualPath.StartsWith("~/") ? virtualPath.Substring(1) : virtualPath; - } - - /// - /// Gets the virtual path portion of the given absolute URL - /// relative to the given base path. - /// - /// - /// Base path comparison is done case insensitive. - /// - /// the absolute base path - /// the absolute url - /// the url relative to the given basePath - public static string GetRelativePath(string basePath, string url) - { - // strip application path from url - string appPath = basePath.TrimEnd('/'); - string appRelativeVirtualPath = url; - if (appRelativeVirtualPath.ToLower().StartsWith(appPath.ToLower())) - { - appRelativeVirtualPath = appRelativeVirtualPath.Substring(appPath.Length); - } - return appRelativeVirtualPath; - } - - /// - /// Returns the 'logical' parent of the specified control. Technically when dealing with masterpages and control hierarchy, - /// the order goes controls->masterpage->page. But one often wants the more logical order controls->page->masterpage. - /// - ///the control, who's parent is to be determined. - ///the logical parent or null if the top of the hierarchy is reached. - /// if is null - public static Control GetLogicalParent(Control control) - { - AssertUtils.ArgumentNotNull(control, "control"); - - // to determine "correct" order of bubbling control->page->masterpage, - // the trick below is necessary because technically the hierarchy goes - // control->masterpage->page - if (control is Page) - { - control = ((Page)control).Master; - } - else if (IsMaster(control)) - { - control = null; - } - else if (IsMaster(control.Parent)) - { - control = control.Page; + virtualPath = virtualPath.Substring(0, iSlash + 1); } else { - control = control.Parent; + virtualPath = virtualPath + "/"; } - return control; } - private static bool IsMaster(Control control) - { - return (control is MasterPage); - } - - /// - /// Encode for use in URLs. - /// - /// the text to be encoded. - /// the url-encoded - /// - /// This method may be used outside of a current request. If executed within a - /// request, is used. - /// will be used otherwise. - /// - public static string UrlEncode( string value ) - { - HttpContext ctx = HttpContext.Current; - return (ctx == null) ? HttpUtility.UrlEncode( value ) : ctx.Server.UrlEncode( value ); - } + return virtualPath; } -} + + /// + /// Returns absolute path that can be referenced within plain HTML. + /// + /// + ///

+ /// If relative path starts with '/' (forward slash), no concatenation will occur + /// and it will be assumed that the relative path specified is indeed the absolute path + /// and will be returned verbatim.

+ ///

+ /// Otherwise, relative path will be appended to the application path, while making sure that + /// path separators are not duplicated between the paths.

+ ///
+ /// Application path. + /// Relative path to combine with the application path. + /// Absolute path. + public static string CreateAbsolutePath(string applicationPath, string relativePath) + { + if (StringUtils.HasLength(relativePath)) + { + if (relativePath.ToLower().StartsWith("http://") || relativePath.ToLower().StartsWith("https://")) + { + return relativePath; + } + + if (relativePath.StartsWith("/")) + { + return relativePath; + } + + if (relativePath.StartsWith("~/")) + { + relativePath = relativePath.Substring(2); + } + } + + applicationPath = (applicationPath == null) ? "" : applicationPath.TrimEnd('/'); + + return string.Format("{0}/{1}", applicationPath, relativePath); + } + + /// + /// Combines a rooted base path with a relative path. + /// + /// Must be a path starting with '/' + /// the path to be combined. May start with basepath Placeholder '~' + /// the combined path + /// + /// If relativePath starts with '~', rootPath is ignored and '~' resolves to the current AppDomain's application virtual path
+ /// If relativePath start with '/', rootPath is ignored and relativePath is returned as-is. + ///
+ public static string CombineVirtualPaths(string rootPath, string relativePath) + { + AssertUtils.ArgumentHasText(rootPath, "rootPath"); + if (rootPath[0] != '/') + { + throw new ArgumentException("RootPath must start with '/'", "rootPath"); + } + + string combinedPath = relativePath; + + if (combinedPath.StartsWith("~/")) + { + combinedPath = VirtualEnvironment.ApplicationVirtualPath.TrimEnd('/') + relativePath.Substring(1); + } + + if (!combinedPath.StartsWith("/")) + { + combinedPath = GetVirtualDirectory(rootPath).TrimEnd('/') + '/' + relativePath; + } + + // TODO: reduce contained directory upwalks here + + return combinedPath; + } + + /// + /// Gets the application-relative virtual path portion of the given absolute URL. + /// + /// the absolute url + /// the url relative to the current application's virtual path + public static string GetAppRelativePath(string url) + { + string appPath = VirtualEnvironment.ApplicationVirtualPath; + return GetRelativePath(appPath, url); + } + + /// + /// Gets a normalized application-relative virtual path of the given virtual path. + /// + /// + ///

+ /// Examples of what would be returned from this method given a virtual path would be: + ///

+ ///

+ /// + /// 'Login.aspx' => 'Login.aspx' + /// '~/Login.aspx' => '/Login.aspx' + /// '~/B2B/SignUp.aspx' => '/B2B/SignUp.aspx' + /// 'B2B/Foo/FooServices.aspx' => 'B2B/Foo/FooServices.aspx' + /// + ///

+ ///
+ /// the virtual path. + /// the normalized virtual path + public static string GetNormalizedVirtualPath(string virtualPath) + { + if (String.IsNullOrEmpty(virtualPath)) + { + return virtualPath; + } + + return virtualPath.StartsWith("~/") ? virtualPath.Substring(1) : virtualPath; + } + + /// + /// Gets the virtual path portion of the given absolute URL + /// relative to the given base path. + /// + /// + /// Base path comparison is done case insensitive. + /// + /// the absolute base path + /// the absolute url + /// the url relative to the given basePath + public static string GetRelativePath(string basePath, string url) + { + // strip application path from url + string appPath = basePath.TrimEnd('/'); + string appRelativeVirtualPath = url; + if (appRelativeVirtualPath.ToLower().StartsWith(appPath.ToLower())) + { + appRelativeVirtualPath = appRelativeVirtualPath.Substring(appPath.Length); + } + + return appRelativeVirtualPath; + } + + /// + /// Returns the 'logical' parent of the specified control. Technically when dealing with masterpages and control hierarchy, + /// the order goes controls->masterpage->page. But one often wants the more logical order controls->page->masterpage. + /// + ///the control, who's parent is to be determined. + ///the logical parent or null if the top of the hierarchy is reached. + /// if is null + public static Control GetLogicalParent(Control control) + { + AssertUtils.ArgumentNotNull(control, "control"); + + // to determine "correct" order of bubbling control->page->masterpage, + // the trick below is necessary because technically the hierarchy goes + // control->masterpage->page + if (control is Page) + { + control = ((Page) control).Master; + } + else if (IsMaster(control)) + { + control = null; + } + else if (IsMaster(control.Parent)) + { + control = control.Page; + } + else + { + control = control.Parent; + } + + return control; + } + + private static bool IsMaster(Control control) + { + return (control is MasterPage); + } + + /// + /// Encode for use in URLs. + /// + /// the text to be encoded. + /// the url-encoded + /// + /// This method may be used outside of a current request. If executed within a + /// request, is used. + /// will be used otherwise. + /// + public static string UrlEncode(string value) + { + HttpContext ctx = HttpContext.Current; + return (ctx == null) ? HttpUtility.UrlEncode(value) : ctx.Server.UrlEncode(value); + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Web/Web/Providers/ConfigurableActiveDirectoryMembershipProvider.cs b/src/Spring/Spring.Web/Web/Providers/ConfigurableActiveDirectoryMembershipProvider.cs index 9ed6215a..a7af9add 100644 --- a/src/Spring/Spring.Web/Web/Providers/ConfigurableActiveDirectoryMembershipProvider.cs +++ b/src/Spring/Spring.Web/Web/Providers/ConfigurableActiveDirectoryMembershipProvider.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -22,14 +22,11 @@ #region Imports - - #endregion -namespace Spring.Web.Providers -{ +namespace Spring.Web.Providers; /* TBD - + /// /// A spring configurable version of /// @@ -55,7 +52,7 @@ namespace Spring.Web.Providers /// /// A collection of the name/value pairs representing the provider-specific /// attributes specified in the configuration for this provider. - /// + /// public NameValueCollection Parameters { get { return this.parameters; } @@ -68,7 +65,7 @@ namespace Spring.Web.Providers /// /// /// - /// A collection of the name/value pairs representing the provider-specific + /// A collection of the name/value pairs representing the provider-specific /// attributes specified in the configuration for this provider. /// /// Values may be overridden by specifying them in list. @@ -94,6 +91,5 @@ namespace Spring.Web.Providers } } */ -} -#endif \ No newline at end of file +#endif diff --git a/src/Spring/Spring.Web/Web/Providers/ConfigurableSqlMembershipProvider.cs b/src/Spring/Spring.Web/Web/Providers/ConfigurableSqlMembershipProvider.cs index aec49247..d750b922 100644 --- a/src/Spring/Spring.Web/Web/Providers/ConfigurableSqlMembershipProvider.cs +++ b/src/Spring/Spring.Web/Web/Providers/ConfigurableSqlMembershipProvider.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -27,73 +27,72 @@ using System.Web.Security; #endregion +namespace Spring.Web.Providers; -namespace Spring.Web.Providers +/// +/// A spring configurable version of +/// +/// Erich Eichinger +[AspNetHostingPermission(SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)] +[AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)] +public class ConfigurableSqlMembershipProvider : SqlMembershipProvider, IMembershipProvider { + private bool initialized = false; + private string connectionStringName; + private NameValueCollection parameters; + /// - /// A spring configurable version of + /// The ConnectionString to be used /// - /// Erich Eichinger - [AspNetHostingPermission(SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)] - [AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)] - public class ConfigurableSqlMembershipProvider : SqlMembershipProvider, IMembershipProvider + public string ConnectionStringName { - private bool initialized = false; - private string connectionStringName; - private NameValueCollection parameters; + get { return this.connectionStringName; } + set { this.connectionStringName = value; } + } - /// - /// The ConnectionString to be used - /// - public string ConnectionStringName - { - get { return this.connectionStringName; } - set { this.connectionStringName = value; } - } + /// + /// A collection of the name/value pairs representing the provider-specific + /// attributes specified in the configuration for this provider. + /// + public NameValueCollection Parameters + { + get { return this.parameters; } + set { this.parameters = value; } + } - /// - /// A collection of the name/value pairs representing the provider-specific - /// attributes specified in the configuration for this provider. - /// - public NameValueCollection Parameters + /// + ///Initializes the provider. + /// + /// + /// + /// + /// A collection of the name/value pairs representing the provider-specific + /// attributes specified in the configuration for this provider. + /// + /// Values may be overridden by specifying them in list. + /// + ///The friendly name of the provider. + ///The or is null. + ///An attempt is made to call on a provider after the provider has already been initialized. + ///The has a length of zero or providerId attribute is not set. + public override void Initialize(string name, NameValueCollection config) + { + lock (this) { - get { return this.parameters; } - set { this.parameters = value; } - } + if (initialized) return; - /// - ///Initializes the provider. - /// - /// - /// - /// - /// A collection of the name/value pairs representing the provider-specific - /// attributes specified in the configuration for this provider. - /// - /// Values may be overridden by specifying them in list. - /// - ///The friendly name of the provider. - ///The or is null. - ///An attempt is made to call on a provider after the provider has already been initialized. - ///The has a length of zero or providerId attribute is not set. - public override void Initialize(string name, NameValueCollection config) - { - lock(this) + if (parameters != null) { - if (initialized) return; - - if (parameters != null) + foreach (string key in parameters.Keys) { - foreach(string key in parameters.Keys) - { - config[key] = parameters[key]; - } + config[key] = parameters[key]; } - config["connectionStringName"] = this.connectionStringName; - base.Initialize(name, config); - - initialized = true; } + + config["connectionStringName"] = this.connectionStringName; + base.Initialize(name, config); + + initialized = true; } } } diff --git a/src/Spring/Spring.Web/Web/Providers/ConfigurableSqlProfileProvider.cs b/src/Spring/Spring.Web/Web/Providers/ConfigurableSqlProfileProvider.cs index 581965ab..bfeb6e9e 100644 --- a/src/Spring/Spring.Web/Web/Providers/ConfigurableSqlProfileProvider.cs +++ b/src/Spring/Spring.Web/Web/Providers/ConfigurableSqlProfileProvider.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -27,72 +27,72 @@ using System.Web.Profile; #endregion -namespace Spring.Web.Providers +namespace Spring.Web.Providers; + +/// +/// +/// +/// Erich Eichinger +[AspNetHostingPermission(SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)] +[AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)] +public class ConfigurableSqlProfileProvider : SqlProfileProvider, IProfileProvider { + private bool initialized = false; + private string connectionStringName; + private NameValueCollection parameters; + /// - /// + /// The ConnectionString to be used /// - /// Erich Eichinger - [AspNetHostingPermission(SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)] - [AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)] - public class ConfigurableSqlProfileProvider : SqlProfileProvider, IProfileProvider + public string ConnectionStringName { - private bool initialized = false; - private string connectionStringName; - private NameValueCollection parameters; + get { return this.connectionStringName; } + set { this.connectionStringName = value; } + } - /// - /// The ConnectionString to be used - /// - public string ConnectionStringName - { - get { return this.connectionStringName; } - set { this.connectionStringName = value; } - } + /// + /// A collection of the name/value pairs representing the provider-specific + /// attributes specified in the configuration for this provider. + /// + public NameValueCollection Parameters + { + get { return this.parameters; } + set { this.parameters = value; } + } - /// - /// A collection of the name/value pairs representing the provider-specific - /// attributes specified in the configuration for this provider. - /// - public NameValueCollection Parameters + /// + ///Initializes the provider. + /// + /// + /// + /// + /// A collection of the name/value pairs representing the provider-specific + /// attributes specified in the configuration for this provider. + /// + /// Values may be overridden by specifying them in list. + /// + ///The friendly name of the provider. + ///The or is null. + ///An attempt is made to call on a provider after the provider has already been initialized. + ///The has a length of zero or providerId attribute is not set. + public override void Initialize(string name, NameValueCollection config) + { + lock (this) { - get { return this.parameters; } - set { this.parameters = value; } - } + if (initialized) return; - /// - ///Initializes the provider. - /// - /// - /// - /// - /// A collection of the name/value pairs representing the provider-specific - /// attributes specified in the configuration for this provider. - /// - /// Values may be overridden by specifying them in list. - /// - ///The friendly name of the provider. - ///The or is null. - ///An attempt is made to call on a provider after the provider has already been initialized. - ///The has a length of zero or providerId attribute is not set. - public override void Initialize(string name, NameValueCollection config) - { - lock (this) + if (parameters != null) { - if (initialized) return; - - if (parameters != null) + foreach (string key in parameters.Keys) { - foreach (string key in parameters.Keys) - { - config[key] = parameters[key]; - } + config[key] = parameters[key]; } - config["connectionStringName"] = this.connectionStringName; - base.Initialize(name, config); - - initialized = true; } + + config["connectionStringName"] = this.connectionStringName; + base.Initialize(name, config); + + initialized = true; } } } diff --git a/src/Spring/Spring.Web/Web/Providers/ConfigurableSqlRoleProvider.cs b/src/Spring/Spring.Web/Web/Providers/ConfigurableSqlRoleProvider.cs index 23aa8524..f7e90a30 100644 --- a/src/Spring/Spring.Web/Web/Providers/ConfigurableSqlRoleProvider.cs +++ b/src/Spring/Spring.Web/Web/Providers/ConfigurableSqlRoleProvider.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -27,72 +27,72 @@ using System.Web.Security; #endregion -namespace Spring.Web.Providers +namespace Spring.Web.Providers; + +/// +/// A spring-configurable version of +/// +/// Erich Eichinger +[AspNetHostingPermission(SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)] +[AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)] +public class ConfigurableSqlRoleProvider : SqlRoleProvider, IRoleProvider { + private bool initialized = false; + private string connectionStringName; + private NameValueCollection parameters; + /// - /// A spring-configurable version of + /// The ConnectionString to be used /// - /// Erich Eichinger - [AspNetHostingPermission(SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)] - [AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)] - public class ConfigurableSqlRoleProvider : SqlRoleProvider, IRoleProvider + public string ConnectionStringName { - private bool initialized = false; - private string connectionStringName; - private NameValueCollection parameters; + get { return this.connectionStringName; } + set { this.connectionStringName = value; } + } - /// - /// The ConnectionString to be used - /// - public string ConnectionStringName - { - get { return this.connectionStringName; } - set { this.connectionStringName = value; } - } + /// + /// A collection of the name/value pairs representing the provider-specific + /// attributes specified in the configuration for this provider. + /// + public NameValueCollection Parameters + { + get { return this.parameters; } + set { this.parameters = value; } + } - /// - /// A collection of the name/value pairs representing the provider-specific - /// attributes specified in the configuration for this provider. - /// - public NameValueCollection Parameters + /// + ///Initializes the provider. + /// + /// + /// + /// + /// A collection of the name/value pairs representing the provider-specific + /// attributes specified in the configuration for this provider. + /// + /// Values may be overridden by specifying them in list. + /// + ///The friendly name of the provider. + ///The or is null. + ///An attempt is made to call on a provider after the provider has already been initialized. + ///The has a length of zero or providerId attribute is not set. + public override void Initialize(string name, NameValueCollection config) + { + lock (this) { - get { return this.parameters; } - set { this.parameters = value; } - } + if (initialized) return; - /// - ///Initializes the provider. - /// - /// - /// - /// - /// A collection of the name/value pairs representing the provider-specific - /// attributes specified in the configuration for this provider. - /// - /// Values may be overridden by specifying them in list. - /// - ///The friendly name of the provider. - ///The or is null. - ///An attempt is made to call on a provider after the provider has already been initialized. - ///The has a length of zero or providerId attribute is not set. - public override void Initialize(string name, NameValueCollection config) - { - lock (this) + if (parameters != null) { - if (initialized) return; - - if (parameters != null) + foreach (string key in parameters.Keys) { - foreach (string key in parameters.Keys) - { - config[key] = parameters[key]; - } + config[key] = parameters[key]; } - config["connectionStringName"] = this.connectionStringName; - base.Initialize(name, config); - - initialized = true; } + + config["connectionStringName"] = this.connectionStringName; + base.Initialize(name, config); + + initialized = true; } } -} +} \ No newline at end of file diff --git a/src/Spring/Spring.Web/Web/Providers/ConfigurableXmlSiteMapProvider.cs b/src/Spring/Spring.Web/Web/Providers/ConfigurableXmlSiteMapProvider.cs index c29dbe34..d6588d3a 100644 --- a/src/Spring/Spring.Web/Web/Providers/ConfigurableXmlSiteMapProvider.cs +++ b/src/Spring/Spring.Web/Web/Providers/ConfigurableXmlSiteMapProvider.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -27,72 +27,72 @@ using System.Web.Security; #endregion -namespace Spring.Web.Providers +namespace Spring.Web.Providers; + +/// +/// A spring-configurable version of +/// +/// Erich Eichinger +[AspNetHostingPermission(SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)] +[AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)] +public class ConfigurableXmlSiteMapProvider : XmlSiteMapProvider, ISiteMapProvider { + private bool initialized; + private string siteMapFile; + private NameValueCollection parameters; + /// - /// A spring-configurable version of + /// The XML file to be used for reading in the sitemap /// - /// Erich Eichinger - [AspNetHostingPermission(SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)] - [AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)] - public class ConfigurableXmlSiteMapProvider : XmlSiteMapProvider, ISiteMapProvider + public string SiteMapFile { - private bool initialized; - private string siteMapFile; - private NameValueCollection parameters; + get { return this.siteMapFile; } + set { this.siteMapFile = value; } + } - /// - /// The XML file to be used for reading in the sitemap - /// - public string SiteMapFile - { - get { return this.siteMapFile; } - set { this.siteMapFile = value; } - } + /// + /// A collection of the name/value pairs representing the provider-specific + /// attributes specified in the configuration for this provider. + /// + public NameValueCollection Parameters + { + get { return this.parameters; } + set { this.parameters = value; } + } - /// - /// A collection of the name/value pairs representing the provider-specific - /// attributes specified in the configuration for this provider. - /// - public NameValueCollection Parameters + /// + ///Initializes the provider. + /// + /// + /// + /// + /// A collection of the name/value pairs representing the provider-specific + /// attributes specified in the configuration for this provider. + /// + /// Values may be overridden by specifying them in list. + /// + ///The friendly name of the provider. + ///The or is null. + ///An attempt is made to call on a provider after the provider has already been initialized. + ///The has a length of zero or providerId attribute is not set. + public override void Initialize(string name, NameValueCollection config) + { + lock (this) { - get { return this.parameters; } - set { this.parameters = value; } - } + if (initialized) return; - /// - ///Initializes the provider. - /// - /// - /// - /// - /// A collection of the name/value pairs representing the provider-specific - /// attributes specified in the configuration for this provider. - /// - /// Values may be overridden by specifying them in list. - /// - ///The friendly name of the provider. - ///The or is null. - ///An attempt is made to call on a provider after the provider has already been initialized. - ///The has a length of zero or providerId attribute is not set. - public override void Initialize(string name, NameValueCollection config) - { - lock (this) + if (parameters != null) { - if (initialized) return; - - if (parameters != null) + foreach (string key in parameters.Keys) { - foreach (string key in parameters.Keys) - { - config[key] = parameters[key]; - } + config[key] = parameters[key]; } - config["siteMapFile"] = this.siteMapFile; - base.Initialize(name, config); - - initialized = true; } + + config["siteMapFile"] = this.siteMapFile; + base.Initialize(name, config); + + initialized = true; } } } diff --git a/src/Spring/Spring.Web/Web/Providers/IMembershipProvider.cs b/src/Spring/Spring.Web/Web/Providers/IMembershipProvider.cs index 3ba65d8c..52b4e737 100644 --- a/src/Spring/Spring.Web/Web/Providers/IMembershipProvider.cs +++ b/src/Spring/Spring.Web/Web/Providers/IMembershipProvider.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -21,358 +21,357 @@ using System.Collections.Specialized; using System.Web.Security; -namespace Spring.Web.Providers +namespace Spring.Web.Providers; + +/// +/// An Interface for class. +/// +/// Damjan Tomic +public interface IMembershipProvider { - /// - /// An Interface for class. - /// - /// Damjan Tomic - public interface IMembershipProvider - { - /// - ///Initializes the provider. - /// - /// - ///A collection of the name/value pairs representing the provider-specific - /// attributes specified in the configuration for this provider. - /// The providerId attribute is mandatory. - /// - ///The friendly name of the provider. - ///The or is null. - ///An attempt is made to call on a provider after the provider has already been initialized. - ///The has a length of zero or providerId attribute is not set. - void Initialize(string name, NameValueCollection config); + /// + ///Initializes the provider. + /// + /// + ///A collection of the name/value pairs representing the provider-specific + /// attributes specified in the configuration for this provider. + /// The providerId attribute is mandatory. + /// + ///The friendly name of the provider. + ///The or is null. + ///An attempt is made to call on a provider after the provider has already been initialized. + ///The has a length of zero or providerId attribute is not set. + void Initialize(string name, NameValueCollection config); - /// - ///Gets the friendly name used to refer to the provider during configuration. - /// - /// - /// - ///The friendly name used to refer to the provider during configuration. - /// - /// - string Name { get; } + /// + ///Gets the friendly name used to refer to the provider during configuration. + /// + /// + /// + ///The friendly name used to refer to the provider during configuration. + /// + /// + string Name { get; } - /// - ///Gets a brief, friendly description suitable for display in administrative tools or other user interfaces (UIs). - /// - /// - /// - ///A brief, friendly description suitable for display in administrative tools or other UIs. - /// - /// - string Description { get; } + /// + ///Gets a brief, friendly description suitable for display in administrative tools or other user interfaces (UIs). + /// + /// + /// + ///A brief, friendly description suitable for display in administrative tools or other UIs. + /// + /// + string Description { get; } - /// - ///Adds a new membership user to the data source. - /// - /// - /// - ///A object populated with the information for the newly created user. - /// - /// - ///Whether or not the new user is approved to be validated. - ///The password answer for the new user - ///The user name for the new user. - ///The unique identifier from the membership data source for the user. - ///The password for the new user. - ///The password question for the new user. - ///The e-mail address for the new user. - ///A enumeration value indicating whether the user was created successfully. - MembershipUser CreateUser(string username, string password, string email, - string passwordQuestion, string passwordAnswer, bool isApproved, - object providerUserKey, out MembershipCreateStatus status); + /// + ///Adds a new membership user to the data source. + /// + /// + /// + ///A object populated with the information for the newly created user. + /// + /// + ///Whether or not the new user is approved to be validated. + ///The password answer for the new user + ///The user name for the new user. + ///The unique identifier from the membership data source for the user. + ///The password for the new user. + ///The password question for the new user. + ///The e-mail address for the new user. + ///A enumeration value indicating whether the user was created successfully. + MembershipUser CreateUser(string username, string password, string email, + string passwordQuestion, string passwordAnswer, bool isApproved, + object providerUserKey, out MembershipCreateStatus status); - /// - ///Processes a request to update the password question and answer for a membership user. - /// - /// - /// - ///true if the password question and answer are updated successfully; otherwise, false. - /// - /// - ///The new password question for the specified user. - ///The new password answer for the specified user. - ///The user to change the password question and answer for. - ///The password for the specified user. - bool ChangePasswordQuestionAndAnswer(string username, string password, - string newPasswordQuestion, string newPasswordAnswer); + /// + ///Processes a request to update the password question and answer for a membership user. + /// + /// + /// + ///true if the password question and answer are updated successfully; otherwise, false. + /// + /// + ///The new password question for the specified user. + ///The new password answer for the specified user. + ///The user to change the password question and answer for. + ///The password for the specified user. + bool ChangePasswordQuestionAndAnswer(string username, string password, + string newPasswordQuestion, string newPasswordAnswer); - /// - ///Gets the password for the specified user name from the data source. - /// - /// - /// - ///The password for the specified user name. - /// - /// - ///The user to retrieve the password for. - ///The password answer for the user. - string GetPassword(string username, string answer); + /// + ///Gets the password for the specified user name from the data source. + /// + /// + /// + ///The password for the specified user name. + /// + /// + ///The user to retrieve the password for. + ///The password answer for the user. + string GetPassword(string username, string answer); - /// - ///Processes a request to update the password for a membership user. - /// - /// - /// - ///true if the password was updated successfully; otherwise, false. - /// - /// - ///The new password for the specified user. - ///The current password for the specified user. - ///The user to update the password for. - bool ChangePassword(string username, string oldPassword, string newPassword); + /// + ///Processes a request to update the password for a membership user. + /// + /// + /// + ///true if the password was updated successfully; otherwise, false. + /// + /// + ///The new password for the specified user. + ///The current password for the specified user. + ///The user to update the password for. + bool ChangePassword(string username, string oldPassword, string newPassword); - /// - ///Resets a user's password to a new, automatically generated password. - /// - /// - /// - ///The new password for the specified user. - /// - /// - ///The user to reset the password for. - ///The password answer for the specified user. - string ResetPassword(string username, string answer); + /// + ///Resets a user's password to a new, automatically generated password. + /// + /// + /// + ///The new password for the specified user. + /// + /// + ///The user to reset the password for. + ///The password answer for the specified user. + string ResetPassword(string username, string answer); - /// - ///Updates information about a user in the data source. - /// - /// - ///A object that represents the user to update and the updated information for the user. - void UpdateUser(MembershipUser user); + /// + ///Updates information about a user in the data source. + /// + /// + ///A object that represents the user to update and the updated information for the user. + void UpdateUser(MembershipUser user); - /// - ///Verifies that the specified user name and password exist in the data source. - /// - /// - /// - ///true if the specified username and password are valid; otherwise, false. - /// - /// - ///The name of the user to validate. - ///The password for the specified user. - bool ValidateUser(string username, string password); + /// + ///Verifies that the specified user name and password exist in the data source. + /// + /// + /// + ///true if the specified username and password are valid; otherwise, false. + /// + /// + ///The name of the user to validate. + ///The password for the specified user. + bool ValidateUser(string username, string password); - /// - ///Clears a lock so that the membership user can be validated. - /// - /// - /// - ///true if the membership user was successfully unlocked; otherwise, false. - /// - /// - ///The membership user to clear the lock status for. - bool UnlockUser(string userName); + /// + ///Clears a lock so that the membership user can be validated. + /// + /// + /// + ///true if the membership user was successfully unlocked; otherwise, false. + /// + /// + ///The membership user to clear the lock status for. + bool UnlockUser(string userName); - /// - ///Gets information from the data source for a user based on the unique identifier for the membership user. Provides an option to update the last-activity date/time stamp for the user. - /// - /// - /// - ///A object populated with the specified user's information from the data source. - /// - /// - ///The unique identifier for the membership user to get information for. - ///true to update the last-activity date/time stamp for the user; false to return user information without updating the last-activity date/time stamp for the user. - MembershipUser GetUser(object providerUserKey, bool userIsOnline); + /// + ///Gets information from the data source for a user based on the unique identifier for the membership user. Provides an option to update the last-activity date/time stamp for the user. + /// + /// + /// + ///A object populated with the specified user's information from the data source. + /// + /// + ///The unique identifier for the membership user to get information for. + ///true to update the last-activity date/time stamp for the user; false to return user information without updating the last-activity date/time stamp for the user. + MembershipUser GetUser(object providerUserKey, bool userIsOnline); - /// - ///Gets information from the data source for a user. Provides an option to update the last-activity date/time stamp for the user. - /// - /// - /// - ///A object populated with the specified user's information from the data source. - /// - /// - ///The name of the user to get information for. - ///true to update the last-activity date/time stamp for the user; false to return user information without updating the last-activity date/time stamp for the user. - MembershipUser GetUser(string username, bool userIsOnline); + /// + ///Gets information from the data source for a user. Provides an option to update the last-activity date/time stamp for the user. + /// + /// + /// + ///A object populated with the specified user's information from the data source. + /// + /// + ///The name of the user to get information for. + ///true to update the last-activity date/time stamp for the user; false to return user information without updating the last-activity date/time stamp for the user. + MembershipUser GetUser(string username, bool userIsOnline); - /// - ///Gets the user name associated with the specified e-mail address. - /// - /// - /// - ///The user name associated with the specified e-mail address. If no match is found, return null. - /// - /// - ///The e-mail address to search for. - string GetUserNameByEmail(string email); + /// + ///Gets the user name associated with the specified e-mail address. + /// + /// + /// + ///The user name associated with the specified e-mail address. If no match is found, return null. + /// + /// + ///The e-mail address to search for. + string GetUserNameByEmail(string email); - /// - ///Removes a user from the membership data source. - /// - /// - /// - ///true if the user was successfully deleted; otherwise, false. - /// - /// - ///The name of the user to delete. - ///true to delete data related to the user from the database; false to leave data related to the user in the database. - bool DeleteUser(string username, bool deleteAllRelatedData); + /// + ///Removes a user from the membership data source. + /// + /// + /// + ///true if the user was successfully deleted; otherwise, false. + /// + /// + ///The name of the user to delete. + ///true to delete data related to the user from the database; false to leave data related to the user in the database. + bool DeleteUser(string username, bool deleteAllRelatedData); - /// - ///Gets a collection of all the users in the data source in pages of data. - /// - /// - /// - ///A collection that contains a page of pageSize objects beginning at the page specified by pageIndex. - /// - /// - ///The total number of matched users. - ///The index of the page of results to return. pageIndex is zero-based. - ///The size of the page of results to return. - MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords); + /// + ///Gets a collection of all the users in the data source in pages of data. + /// + /// + /// + ///A collection that contains a page of pageSize objects beginning at the page specified by pageIndex. + /// + /// + ///The total number of matched users. + ///The index of the page of results to return. pageIndex is zero-based. + ///The size of the page of results to return. + MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords); - /// - ///Gets the number of users currently accessing the application. - /// - /// - /// - ///The number of users currently accessing the application. - /// - /// - int GetNumberOfUsersOnline(); + /// + ///Gets the number of users currently accessing the application. + /// + /// + /// + ///The number of users currently accessing the application. + /// + /// + int GetNumberOfUsersOnline(); - /// - ///Gets a collection of membership users where the user name contains the specified user name to match. - /// - /// - /// - ///A collection that contains a page of pageSize objects beginning at the page specified by pageIndex. - /// - /// - ///The total number of matched users. - ///The index of the page of results to return. pageIndex is zero-based. - ///The user name to search for. - ///The size of the page of results to return. - MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize, - out int totalRecords); + /// + ///Gets a collection of membership users where the user name contains the specified user name to match. + /// + /// + /// + ///A collection that contains a page of pageSize objects beginning at the page specified by pageIndex. + /// + /// + ///The total number of matched users. + ///The index of the page of results to return. pageIndex is zero-based. + ///The user name to search for. + ///The size of the page of results to return. + MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize, + out int totalRecords); - /// - ///Gets a collection of membership users where the e-mail address contains the specified e-mail address to match. - /// - /// - /// - ///A collection that contains a page of pageSize objects beginning at the page specified by pageIndex. - /// - /// - ///The total number of matched users. - ///The index of the page of results to return. pageIndex is zero-based. - ///The e-mail address to search for. - ///The size of the page of results to return. - MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, - out int totalRecords); + /// + ///Gets a collection of membership users where the e-mail address contains the specified e-mail address to match. + /// + /// + /// + ///A collection that contains a page of pageSize objects beginning at the page specified by pageIndex. + /// + /// + ///The total number of matched users. + ///The index of the page of results to return. pageIndex is zero-based. + ///The e-mail address to search for. + ///The size of the page of results to return. + MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, + out int totalRecords); - /// - ///Indicates whether the membership provider is configured to allow users to retrieve their passwords. - /// - /// - /// - ///true if the membership provider is configured to support password retrieval; otherwise, false. The default is false. - /// - /// - bool EnablePasswordRetrieval { get; } + /// + ///Indicates whether the membership provider is configured to allow users to retrieve their passwords. + /// + /// + /// + ///true if the membership provider is configured to support password retrieval; otherwise, false. The default is false. + /// + /// + bool EnablePasswordRetrieval { get; } - /// - ///Indicates whether the membership provider is configured to allow users to reset their passwords. - /// - /// - /// - ///true if the membership provider supports password reset; otherwise, false. The default is true. - /// - /// - bool EnablePasswordReset { get; } + /// + ///Indicates whether the membership provider is configured to allow users to reset their passwords. + /// + /// + /// + ///true if the membership provider supports password reset; otherwise, false. The default is true. + /// + /// + bool EnablePasswordReset { get; } - /// - ///Gets a value indicating whether the membership provider is configured to require the user to answer a password question for password reset and retrieval. - /// - /// - /// - ///true if a password answer is required for password reset and retrieval; otherwise, false. The default is true. - /// - /// - bool RequiresQuestionAndAnswer { get; } + /// + ///Gets a value indicating whether the membership provider is configured to require the user to answer a password question for password reset and retrieval. + /// + /// + /// + ///true if a password answer is required for password reset and retrieval; otherwise, false. The default is true. + /// + /// + bool RequiresQuestionAndAnswer { get; } - /// - ///The name of the application using the custom membership provider. - /// - /// - /// - ///The name of the application using the custom membership provider. - /// - /// - string ApplicationName { get; set; } + /// + ///The name of the application using the custom membership provider. + /// + /// + /// + ///The name of the application using the custom membership provider. + /// + /// + string ApplicationName { get; set; } - /// - ///Gets the number of invalid password or password-answer attempts allowed before the membership user is locked out. - /// - /// - /// - ///The number of invalid password or password-answer attempts allowed before the membership user is locked out. - /// - /// - int MaxInvalidPasswordAttempts { get; } + /// + ///Gets the number of invalid password or password-answer attempts allowed before the membership user is locked out. + /// + /// + /// + ///The number of invalid password or password-answer attempts allowed before the membership user is locked out. + /// + /// + int MaxInvalidPasswordAttempts { get; } - /// - ///Gets the number of minutes in which a maximum number of invalid password or password-answer attempts are allowed before the membership user is locked out. - /// - /// - /// - ///The number of minutes in which a maximum number of invalid password or password-answer attempts are allowed before the membership user is locked out. - /// - /// - int PasswordAttemptWindow { get; } + /// + ///Gets the number of minutes in which a maximum number of invalid password or password-answer attempts are allowed before the membership user is locked out. + /// + /// + /// + ///The number of minutes in which a maximum number of invalid password or password-answer attempts are allowed before the membership user is locked out. + /// + /// + int PasswordAttemptWindow { get; } - /// - ///Gets a value indicating whether the membership provider is configured to require a unique e-mail address for each user name. - /// - /// - /// - ///true if the membership provider requires a unique e-mail address; otherwise, false. The default is true. - /// - /// - bool RequiresUniqueEmail { get; } + /// + ///Gets a value indicating whether the membership provider is configured to require a unique e-mail address for each user name. + /// + /// + /// + ///true if the membership provider requires a unique e-mail address; otherwise, false. The default is true. + /// + /// + bool RequiresUniqueEmail { get; } - /// - ///Gets a value indicating the format for storing passwords in the membership data store. - /// - /// - /// - ///One of the values indicating the format for storing passwords in the data store. - /// - /// - MembershipPasswordFormat PasswordFormat { get; } + /// + ///Gets a value indicating the format for storing passwords in the membership data store. + /// + /// + /// + ///One of the values indicating the format for storing passwords in the data store. + /// + /// + MembershipPasswordFormat PasswordFormat { get; } - /// - ///Gets the minimum length required for a password. - /// - /// - /// - ///The minimum length required for a password. - /// - /// - int MinRequiredPasswordLength { get; } + /// + ///Gets the minimum length required for a password. + /// + /// + /// + ///The minimum length required for a password. + /// + /// + int MinRequiredPasswordLength { get; } - /// - ///Gets the minimum number of special characters that must be present in a valid password. - /// - /// - /// - ///The minimum number of special characters that must be present in a valid password. - /// - /// - int MinRequiredNonAlphanumericCharacters { get; } + /// + ///Gets the minimum number of special characters that must be present in a valid password. + /// + /// + /// + ///The minimum number of special characters that must be present in a valid password. + /// + /// + int MinRequiredNonAlphanumericCharacters { get; } - /// - ///Gets the regular expression used to evaluate a password. - /// - /// - /// - ///A regular expression used to evaluate a password. - /// - /// - string PasswordStrengthRegularExpression { get; } - } -} + /// + ///Gets the regular expression used to evaluate a password. + /// + /// + /// + ///A regular expression used to evaluate a password. + /// + /// + string PasswordStrengthRegularExpression { get; } +} \ No newline at end of file diff --git a/src/Spring/Spring.Web/Web/Providers/IProfileProvider.cs b/src/Spring/Spring.Web/Web/Providers/IProfileProvider.cs index f417e382..4642eb2d 100644 --- a/src/Spring/Spring.Web/Web/Providers/IProfileProvider.cs +++ b/src/Spring/Spring.Web/Web/Providers/IProfileProvider.cs @@ -22,196 +22,195 @@ using System.Collections.Specialized; using System.Configuration; using System.Web.Profile; -namespace Spring.Web.Providers +namespace Spring.Web.Providers; + +/// +/// An Interface for class. +/// +/// +///

+/// Configuration for this provider requires providerId element set in web.config file, +/// as the Id of wrapped provider (defined in the Spring context). +///

+///
+/// Damjan Tomic +public interface IProfileProvider { - /// - /// An Interface for class. - /// - /// - ///

- /// Configuration for this provider requires providerId element set in web.config file, - /// as the Id of wrapped provider (defined in the Spring context). - ///

- ///
- /// Damjan Tomic - public interface IProfileProvider - { - /// - ///Initializes the provider. - /// - /// - ///A collection of the name/value pairs representing the provider-specific - /// attributes specified in the configuration for this provider. - /// The providerId attribute is mandatory. - /// - ///The friendly name of the provider. - ///The or is null. - ///An attempt is made to call on a provider after the provider has already been initialized. - ///The has a length of zero or providerId attribute is not set. - void Initialize(string name, NameValueCollection config); + /// + ///Initializes the provider. + /// + /// + ///A collection of the name/value pairs representing the provider-specific + /// attributes specified in the configuration for this provider. + /// The providerId attribute is mandatory. + /// + ///The friendly name of the provider. + ///The or is null. + ///An attempt is made to call on a provider after the provider has already been initialized. + ///The has a length of zero or providerId attribute is not set. + void Initialize(string name, NameValueCollection config); - /// - ///Gets the friendly name used to refer to the provider during configuration. - /// - /// - /// - ///The friendly name used to refer to the provider during configuration. - /// - string Name { get; } + /// + ///Gets the friendly name used to refer to the provider during configuration. + /// + /// + /// + ///The friendly name used to refer to the provider during configuration. + /// + string Name { get; } - /// - ///Gets a brief, friendly description suitable for display in administrative tools or other user interfaces (UIs). - /// - /// - /// - ///A brief, friendly description suitable for display in administrative tools or other UIs. - /// - string Description { get; } + /// + ///Gets a brief, friendly description suitable for display in administrative tools or other user interfaces (UIs). + /// + /// + /// + ///A brief, friendly description suitable for display in administrative tools or other UIs. + /// + string Description { get; } - /// - ///Returns the collection of settings property values for the specified application instance and settings property group. - /// - /// - /// - ///A containing the values for the specified settings property group. - /// - /// - ///A describing the current application use. - ///A containing the settings property group whose values are to be retrieved.2 - SettingsPropertyValueCollection GetPropertyValues(SettingsContext context, - SettingsPropertyCollection collection); + /// + ///Returns the collection of settings property values for the specified application instance and settings property group. + /// + /// + /// + ///A containing the values for the specified settings property group. + /// + /// + ///A describing the current application use. + ///A containing the settings property group whose values are to be retrieved.2 + SettingsPropertyValueCollection GetPropertyValues(SettingsContext context, + SettingsPropertyCollection collection); - /// - ///Sets the values of the specified group of property settings. - /// - /// - ///A describing the current application usage. - ///A representing the group of property settings to set.2 - void SetPropertyValues(SettingsContext context, SettingsPropertyValueCollection collection); + /// + ///Sets the values of the specified group of property settings. + /// + /// + ///A describing the current application usage. + ///A representing the group of property settings to set.2 + void SetPropertyValues(SettingsContext context, SettingsPropertyValueCollection collection); - /// - ///Gets or sets the name of the currently running application. - /// - /// - /// - ///A that contains the application's shortened name, which does not contain a full path or extension, for example, SimpleAppSettings. - /// - ///2 - string ApplicationName { get; set; } + /// + ///Gets or sets the name of the currently running application. + /// + /// + /// + ///A that contains the application's shortened name, which does not contain a full path or extension, for example, SimpleAppSettings. + /// + ///2 + string ApplicationName { get; set; } - /// - ///When overridden in a derived class, deletes profile properties and information for the supplied list of profiles. - /// - /// - /// - ///The number of profiles deleted from the data source. - /// - /// - ///A of information about profiles that are to be deleted. - int DeleteProfiles(ProfileInfoCollection profiles); + /// + ///When overridden in a derived class, deletes profile properties and information for the supplied list of profiles. + /// + /// + /// + ///The number of profiles deleted from the data source. + /// + /// + ///A of information about profiles that are to be deleted. + int DeleteProfiles(ProfileInfoCollection profiles); - /// - ///When overridden in a derived class, deletes profile properties and information for profiles that match the supplied list of user names. - /// - /// - /// - ///The number of profiles deleted from the data source. - /// - /// - ///A string array of user names for profiles to be deleted. - int DeleteProfiles(string[] usernames); + /// + ///When overridden in a derived class, deletes profile properties and information for profiles that match the supplied list of user names. + /// + /// + /// + ///The number of profiles deleted from the data source. + /// + /// + ///A string array of user names for profiles to be deleted. + int DeleteProfiles(string[] usernames); - /// - ///When overridden in a derived class, deletes all user-profile data for profiles in which the last activity date occurred before the specified date. - /// - /// - /// - ///The number of profiles deleted from the data source. - /// - /// - ///One of the values, specifying whether anonymous, authenticated, or both types of profiles are deleted. - ///A that identifies which user profiles are considered inactive. If the value of a user profile occurs on or before this date and time, the profile is considered inactive. - int DeleteInactiveProfiles(ProfileAuthenticationOption authenticationOption, - DateTime userInactiveSinceDate); + /// + ///When overridden in a derived class, deletes all user-profile data for profiles in which the last activity date occurred before the specified date. + /// + /// + /// + ///The number of profiles deleted from the data source. + /// + /// + ///One of the values, specifying whether anonymous, authenticated, or both types of profiles are deleted. + ///A that identifies which user profiles are considered inactive. If the value of a user profile occurs on or before this date and time, the profile is considered inactive. + int DeleteInactiveProfiles(ProfileAuthenticationOption authenticationOption, + DateTime userInactiveSinceDate); - /// - ///When overridden in a derived class, returns the number of profiles in which the last activity date occurred on or before the specified date. - /// - /// - /// - ///The number of profiles in which the last activity date occurred on or before the specified date. - /// - /// - ///One of the values, specifying whether anonymous, authenticated, or both types of profiles are returned. - ///A that identifies which user profiles are considered inactive. If the of a user profile occurs on or before this date and time, the profile is considered inactive. - int GetNumberOfInactiveProfiles(ProfileAuthenticationOption authenticationOption, - DateTime userInactiveSinceDate); + /// + ///When overridden in a derived class, returns the number of profiles in which the last activity date occurred on or before the specified date. + /// + /// + /// + ///The number of profiles in which the last activity date occurred on or before the specified date. + /// + /// + ///One of the values, specifying whether anonymous, authenticated, or both types of profiles are returned. + ///A that identifies which user profiles are considered inactive. If the of a user profile occurs on or before this date and time, the profile is considered inactive. + int GetNumberOfInactiveProfiles(ProfileAuthenticationOption authenticationOption, + DateTime userInactiveSinceDate); - /// - ///When overridden in a derived class, retrieves user profile data for all profiles in the data source. - /// - /// - /// - ///A containing user-profile information for all profiles in the data source. - /// - /// - ///One of the values, specifying whether anonymous, authenticated, or both types of profiles are returned. - ///When this method returns, contains the total number of profiles. - ///The index of the page of results to return. - ///The size of the page of results to return. - ProfileInfoCollection GetAllProfiles(ProfileAuthenticationOption authenticationOption, - int pageIndex, int pageSize, out int totalRecords); + /// + ///When overridden in a derived class, retrieves user profile data for all profiles in the data source. + /// + /// + /// + ///A containing user-profile information for all profiles in the data source. + /// + /// + ///One of the values, specifying whether anonymous, authenticated, or both types of profiles are returned. + ///When this method returns, contains the total number of profiles. + ///The index of the page of results to return. + ///The size of the page of results to return. + ProfileInfoCollection GetAllProfiles(ProfileAuthenticationOption authenticationOption, + int pageIndex, int pageSize, out int totalRecords); - /// - ///When overridden in a derived class, retrieves user-profile data from the data source for profiles in which the last activity date occurred on or before the specified date. - /// - /// - /// - ///A containing user-profile information about the inactive profiles. - /// - /// - ///One of the values, specifying whether anonymous, authenticated, or both types of profiles are returned. - ///A that identifies which user profiles are considered inactive. If the of a user profile occurs on or before this date and time, the profile is considered inactive. - ///When this method returns, contains the total number of profiles. - ///The index of the page of results to return. - ///The size of the page of results to return. - ProfileInfoCollection GetAllInactiveProfiles(ProfileAuthenticationOption authenticationOption, - DateTime userInactiveSinceDate, int pageIndex, - int pageSize, out int totalRecords); + /// + ///When overridden in a derived class, retrieves user-profile data from the data source for profiles in which the last activity date occurred on or before the specified date. + /// + /// + /// + ///A containing user-profile information about the inactive profiles. + /// + /// + ///One of the values, specifying whether anonymous, authenticated, or both types of profiles are returned. + ///A that identifies which user profiles are considered inactive. If the of a user profile occurs on or before this date and time, the profile is considered inactive. + ///When this method returns, contains the total number of profiles. + ///The index of the page of results to return. + ///The size of the page of results to return. + ProfileInfoCollection GetAllInactiveProfiles(ProfileAuthenticationOption authenticationOption, + DateTime userInactiveSinceDate, int pageIndex, + int pageSize, out int totalRecords); - /// - ///When overridden in a derived class, retrieves profile information for profiles in which the user name matches the specified user names. - /// - /// - /// - ///A containing user-profile information for profiles where the user name matches the supplied usernameToMatch parameter. - /// - /// - ///One of the values, specifying whether anonymous, authenticated, or both types of profiles are returned. - ///When this method returns, contains the total number of profiles. - ///The index of the page of results to return. - ///The user name to search for. - ///The size of the page of results to return. - ProfileInfoCollection FindProfilesByUserName(ProfileAuthenticationOption authenticationOption, - string usernameToMatch, int pageIndex, int pageSize, - out int totalRecords); + /// + ///When overridden in a derived class, retrieves profile information for profiles in which the user name matches the specified user names. + /// + /// + /// + ///A containing user-profile information for profiles where the user name matches the supplied usernameToMatch parameter. + /// + /// + ///One of the values, specifying whether anonymous, authenticated, or both types of profiles are returned. + ///When this method returns, contains the total number of profiles. + ///The index of the page of results to return. + ///The user name to search for. + ///The size of the page of results to return. + ProfileInfoCollection FindProfilesByUserName(ProfileAuthenticationOption authenticationOption, + string usernameToMatch, int pageIndex, int pageSize, + out int totalRecords); - /// - ///When overridden in a derived class, retrieves profile information for profiles in which the last activity date occurred on or before the specified date and the user name matches the specified user name. - /// - /// - /// - ///A containing user profile information for inactive profiles where the user name matches the supplied usernameToMatch parameter. - /// - /// - ///One of the values, specifying whether anonymous, authenticated, or both types of profiles are returned. - ///A that identifies which user profiles are considered inactive. If the value of a user profile occurs on or before this date and time, the profile is considered inactive. - ///When this method returns, contains the total number of profiles. - ///The index of the page of results to return. - ///The user name to search for. - ///The size of the page of results to return. - ProfileInfoCollection FindInactiveProfilesByUserName( - ProfileAuthenticationOption authenticationOption, string usernameToMatch, DateTime userInactiveSinceDate, - int pageIndex, int pageSize, out int totalRecords); - } + /// + ///When overridden in a derived class, retrieves profile information for profiles in which the last activity date occurred on or before the specified date and the user name matches the specified user name. + /// + /// + /// + ///A containing user profile information for inactive profiles where the user name matches the supplied usernameToMatch parameter. + /// + /// + ///One of the values, specifying whether anonymous, authenticated, or both types of profiles are returned. + ///A that identifies which user profiles are considered inactive. If the value of a user profile occurs on or before this date and time, the profile is considered inactive. + ///When this method returns, contains the total number of profiles. + ///The index of the page of results to return. + ///The user name to search for. + ///The size of the page of results to return. + ProfileInfoCollection FindInactiveProfilesByUserName( + ProfileAuthenticationOption authenticationOption, string usernameToMatch, DateTime userInactiveSinceDate, + int pageIndex, int pageSize, out int totalRecords); } diff --git a/src/Spring/Spring.Web/Web/Providers/IRoleProvider.cs b/src/Spring/Spring.Web/Web/Providers/IRoleProvider.cs index 7cac3a48..d845ef81 100644 --- a/src/Spring/Spring.Web/Web/Providers/IRoleProvider.cs +++ b/src/Spring/Spring.Web/Web/Providers/IRoleProvider.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -24,162 +24,161 @@ using System.Collections.Specialized; #endregion -namespace Spring.Web.Providers +namespace Spring.Web.Providers; + +/// +/// An Interface for class. +/// +/// +///

+/// Configuration for this provider requires providerId element set in web.config file, +/// as the Id of wrapped provider (defined in the Spring context). +///

+///
+/// Damjan Tomic +public interface IRoleProvider { - /// - /// An Interface for class. - /// - /// - ///

- /// Configuration for this provider requires providerId element set in web.config file, - /// as the Id of wrapped provider (defined in the Spring context). - ///

- ///
- /// Damjan Tomic - public interface IRoleProvider - { - /// - ///Initializes the provider. - /// - /// - ///A collection of the name/value pairs representing the provider-specific - /// attributes specified in the configuration for this provider. - /// The providerId attribute is mandatory. - /// - ///The friendly name of the provider. - ///The or is null. - ///An attempt is made to call on a provider after the provider has already been initialized. - ///The has a length of zero or providerId attribute is not set. - void Initialize(string name, NameValueCollection config); + /// + ///Initializes the provider. + /// + /// + ///A collection of the name/value pairs representing the provider-specific + /// attributes specified in the configuration for this provider. + /// The providerId attribute is mandatory. + /// + ///The friendly name of the provider. + ///The or is null. + ///An attempt is made to call on a provider after the provider has already been initialized. + ///The has a length of zero or providerId attribute is not set. + void Initialize(string name, NameValueCollection config); - /// - ///Gets the friendly name used to refer to the provider during configuration. - /// - /// - /// - ///The friendly name used to refer to the provider during configuration. - /// - string Name { get; } + /// + ///Gets the friendly name used to refer to the provider during configuration. + /// + /// + /// + ///The friendly name used to refer to the provider during configuration. + /// + string Name { get; } - /// - ///Gets a brief, friendly description suitable for display in administrative tools or other user interfaces (UIs). - /// - /// - /// - ///A brief, friendly description suitable for display in administrative tools or other UIs. - /// - string Description { get; } + /// + ///Gets a brief, friendly description suitable for display in administrative tools or other user interfaces (UIs). + /// + /// + /// + ///A brief, friendly description suitable for display in administrative tools or other UIs. + /// + string Description { get; } - /// - ///Gets a value indicating whether the specified user is in the specified role for the configured applicationName. - /// - /// - /// - ///true if the specified user is in the specified role for the configured applicationName; otherwise, false. - /// - /// - ///The user name to search for. - ///The role to search in. - bool IsUserInRole(string username, string roleName); + /// + ///Gets a value indicating whether the specified user is in the specified role for the configured applicationName. + /// + /// + /// + ///true if the specified user is in the specified role for the configured applicationName; otherwise, false. + /// + /// + ///The user name to search for. + ///The role to search in. + bool IsUserInRole(string username, string roleName); - /// - ///Gets a list of the roles that a specified user is in for the configured applicationName. - /// - /// - /// - ///A string array containing the names of all the roles that the specified user is in for the configured applicationName. - /// - /// - ///The user to return a list of roles for. - string[] GetRolesForUser(string username); + /// + ///Gets a list of the roles that a specified user is in for the configured applicationName. + /// + /// + /// + ///A string array containing the names of all the roles that the specified user is in for the configured applicationName. + /// + /// + ///The user to return a list of roles for. + string[] GetRolesForUser(string username); - /// - ///Adds a new role to the data source for the configured applicationName. - /// - /// - ///The name of the role to create. - void CreateRole(string roleName); + /// + ///Adds a new role to the data source for the configured applicationName. + /// + /// + ///The name of the role to create. + void CreateRole(string roleName); - /// - ///Removes a role from the data source for the configured applicationName. - /// - /// - /// - ///true if the role was successfully deleted; otherwise, false. - /// - /// - ///If true, throw an exception if roleName has one or more members and do not delete roleName. - ///The name of the role to delete. - bool DeleteRole(string roleName, bool throwOnPopulatedRole); + /// + ///Removes a role from the data source for the configured applicationName. + /// + /// + /// + ///true if the role was successfully deleted; otherwise, false. + /// + /// + ///If true, throw an exception if roleName has one or more members and do not delete roleName. + ///The name of the role to delete. + bool DeleteRole(string roleName, bool throwOnPopulatedRole); - /// - ///Gets a value indicating whether the specified role name already exists in the role data source for the configured applicationName. - /// - /// - /// - ///true if the role name already exists in the data source for the configured applicationName; otherwise, false. - /// - /// - ///The name of the role to search for in the data source. - bool RoleExists(string roleName); + /// + ///Gets a value indicating whether the specified role name already exists in the role data source for the configured applicationName. + /// + /// + /// + ///true if the role name already exists in the data source for the configured applicationName; otherwise, false. + /// + /// + ///The name of the role to search for in the data source. + bool RoleExists(string roleName); - /// - ///Adds the specified user names to the specified roles for the configured applicationName. - /// - /// - ///A string array of the role names to add the specified user names to. - ///A string array of user names to be added to the specified roles. - void AddUsersToRoles(string[] usernames, string[] roleNames); + /// + ///Adds the specified user names to the specified roles for the configured applicationName. + /// + /// + ///A string array of the role names to add the specified user names to. + ///A string array of user names to be added to the specified roles. + void AddUsersToRoles(string[] usernames, string[] roleNames); - /// - ///Removes the specified user names from the specified roles for the configured applicationName. - /// - /// - ///A string array of role names to remove the specified user names from. - ///A string array of user names to be removed from the specified roles. - void RemoveUsersFromRoles(string[] usernames, string[] roleNames); + /// + ///Removes the specified user names from the specified roles for the configured applicationName. + /// + /// + ///A string array of role names to remove the specified user names from. + ///A string array of user names to be removed from the specified roles. + void RemoveUsersFromRoles(string[] usernames, string[] roleNames); - /// - ///Gets a list of users in the specified role for the configured applicationName. - /// - /// - /// - ///A string array containing the names of all the users who are members of the specified role for the configured applicationName. - /// - /// - ///The name of the role to get the list of users for. - string[] GetUsersInRole(string roleName); + /// + ///Gets a list of users in the specified role for the configured applicationName. + /// + /// + /// + ///A string array containing the names of all the users who are members of the specified role for the configured applicationName. + /// + /// + ///The name of the role to get the list of users for. + string[] GetUsersInRole(string roleName); - /// - ///Gets a list of all the roles for the configured applicationName. - /// - /// - /// - ///A string array containing the names of all the roles stored in the data source for the configured applicationName. - /// - /// - string[] GetAllRoles(); + /// + ///Gets a list of all the roles for the configured applicationName. + /// + /// + /// + ///A string array containing the names of all the roles stored in the data source for the configured applicationName. + /// + /// + string[] GetAllRoles(); - /// - ///Gets an array of user names in a role where the user name contains the specified user name to match. - /// - /// - /// - ///A string array containing the names of all the users where the user name matches usernameToMatch and the user is a member of the specified role. - /// - /// - ///The user name to search for. - ///The role to search in. - string[] FindUsersInRole(string roleName, string usernameToMatch); + /// + ///Gets an array of user names in a role where the user name contains the specified user name to match. + /// + /// + /// + ///A string array containing the names of all the users where the user name matches usernameToMatch and the user is a member of the specified role. + /// + /// + ///The user name to search for. + ///The role to search in. + string[] FindUsersInRole(string roleName, string usernameToMatch); - /// - ///Gets or sets the name of the application to store and retrieve role information for. - /// - /// - /// - ///The name of the application to store and retrieve role information for. - /// - /// - string ApplicationName { get; set; } - } + /// + ///Gets or sets the name of the application to store and retrieve role information for. + /// + /// + /// + ///The name of the application to store and retrieve role information for. + /// + /// + string ApplicationName { get; set; } } diff --git a/src/Spring/Spring.Web/Web/Providers/ISiteMapProvider.cs b/src/Spring/Spring.Web/Web/Providers/ISiteMapProvider.cs index aa55d2af..524437e3 100644 --- a/src/Spring/Spring.Web/Web/Providers/ISiteMapProvider.cs +++ b/src/Spring/Spring.Web/Web/Providers/ISiteMapProvider.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -25,237 +25,236 @@ using System.Web; #endregion -namespace Spring.Web.Providers +namespace Spring.Web.Providers; + +/// +/// An Interface for class. +/// +/// +///

+/// Configuration for this provider requires providerId element set in web.config file, +/// as the Id of wrapped provider (defined in the Spring context). +///

+///
+/// Damjan Tomic +public interface ISiteMapProvider { - /// - /// An Interface for class. - /// - /// - ///

- /// Configuration for this provider requires providerId element set in web.config file, - /// as the Id of wrapped provider (defined in the Spring context). - ///

- ///
- /// Damjan Tomic - public interface ISiteMapProvider - { - /// - ///Initializes the provider. - /// - /// - ///A collection of the name/value pairs representing the provider-specific - /// attributes specified in the configuration for this provider. - /// The providerId attribute is mandatory. - /// - ///The friendly name of the provider. - ///The or is null. - ///An attempt is made to call on a provider after the provider has already been initialized. - ///The has a length of zero or providerId attribute is not set. - void Initialize(string name, NameValueCollection config); + /// + ///Initializes the provider. + /// + /// + ///A collection of the name/value pairs representing the provider-specific + /// attributes specified in the configuration for this provider. + /// The providerId attribute is mandatory. + /// + ///The friendly name of the provider. + ///The or is null. + ///An attempt is made to call on a provider after the provider has already been initialized. + ///The has a length of zero or providerId attribute is not set. + void Initialize(string name, NameValueCollection config); - /// - ///Gets the friendly name used to refer to the provider during configuration. - /// - /// - /// - ///The friendly name used to refer to the provider during configuration. - /// - /// - string Name { get; } + /// + ///Gets the friendly name used to refer to the provider during configuration. + /// + /// + /// + ///The friendly name used to refer to the provider during configuration. + /// + /// + string Name { get; } - /// - ///Gets a brief, friendly description suitable for display in administrative tools or other user interfaces (UIs). - /// - /// - /// - ///A brief, friendly description suitable for display in administrative tools or other UIs. - /// - /// - string Description { get; } + /// + ///Gets a brief, friendly description suitable for display in administrative tools or other user interfaces (UIs). + /// + /// + /// + ///A brief, friendly description suitable for display in administrative tools or other UIs. + /// + /// + string Description { get; } - /// - ///Retrieves a object that represents the currently requested page using the specified object. - /// - /// - /// - ///A that represents the currently requested page; otherwise, null, if no corresponding can be found in the or if the page context is null. - /// - /// - ///The used to match node information with the URL of the requested page. - SiteMapNode FindSiteMapNode(HttpContext context); + /// + ///Retrieves a object that represents the currently requested page using the specified object. + /// + /// + /// + ///A that represents the currently requested page; otherwise, null, if no corresponding can be found in the or if the page context is null. + /// + /// + ///The used to match node information with the URL of the requested page. + SiteMapNode FindSiteMapNode(HttpContext context); - /// - ///Retrieves a object based on a specified key. - /// - /// - /// - ///A that represents the page identified by key; otherwise, null, if no corresponding is found or if security trimming is enabled and the cannot be returned for the current user. The default is null. - /// - /// - ///A lookup key with which a is created. - SiteMapNode FindSiteMapNodeFromKey(string key); + /// + ///Retrieves a object based on a specified key. + /// + /// + /// + ///A that represents the page identified by key; otherwise, null, if no corresponding is found or if security trimming is enabled and the cannot be returned for the current user. The default is null. + /// + /// + ///A lookup key with which a is created. + SiteMapNode FindSiteMapNodeFromKey(string key); - /// - ///When overridden in a derived class, retrieves a object that represents the page at the specified URL. - /// - /// - /// - ///A that represents the page identified by rawURL; otherwise, null, if no corresponding is found or if security trimming is enabled and the cannot be returned for the current user. - /// - /// - ///A URL that identifies the page for which to retrieve a . - SiteMapNode FindSiteMapNode(string rawUrl); + /// + ///When overridden in a derived class, retrieves a object that represents the page at the specified URL. + /// + /// + /// + ///A that represents the page identified by rawURL; otherwise, null, if no corresponding is found or if security trimming is enabled and the cannot be returned for the current user. + /// + /// + ///A URL that identifies the page for which to retrieve a . + SiteMapNode FindSiteMapNode(string rawUrl); - /// - ///When overridden in a derived class, retrieves the child nodes of a specific . - /// - /// - /// - ///A read-only that contains the immediate child nodes of the specified ; otherwise, null or an empty collection, if no child nodes exist. - /// - /// - ///The for which to retrieve all child nodes. - SiteMapNodeCollection GetChildNodes(SiteMapNode node); + /// + ///When overridden in a derived class, retrieves the child nodes of a specific . + /// + /// + /// + ///A read-only that contains the immediate child nodes of the specified ; otherwise, null or an empty collection, if no child nodes exist. + /// + /// + ///The for which to retrieve all child nodes. + SiteMapNodeCollection GetChildNodes(SiteMapNode node); - /// - ///Provides an optimized lookup method for site map providers when retrieving the node for the currently requested page and fetching the parent and ancestor site map nodes for the current page. - /// - /// - /// - ///A that represents the currently requested page; otherwise, null, if the is not found or cannot be returned for the current user. - /// - /// - ///The number of ancestor site map node generations to get. A value of -1 indicates that all ancestors might be retrieved and cached by the provider. - ///upLevel is less than -1. - SiteMapNode GetCurrentNodeAndHintAncestorNodes(int upLevel); + /// + ///Provides an optimized lookup method for site map providers when retrieving the node for the currently requested page and fetching the parent and ancestor site map nodes for the current page. + /// + /// + /// + ///A that represents the currently requested page; otherwise, null, if the is not found or cannot be returned for the current user. + /// + /// + ///The number of ancestor site map node generations to get. A value of -1 indicates that all ancestors might be retrieved and cached by the provider. + ///upLevel is less than -1. + SiteMapNode GetCurrentNodeAndHintAncestorNodes(int upLevel); - /// - ///Provides an optimized lookup method for site map providers when retrieving the node for the currently requested page and fetching the site map nodes in the proximity of the current node. - /// - /// - /// - ///A that represents the currently requested page; otherwise, null, if the is not found or cannot be returned for the current user. - /// - /// - ///The number of ancestor generations to fetch. 0 indicates no ancestor nodes are retrieved and -1 indicates that all ancestors might be retrieved and cached by the provider. - ///The number of child generations to fetch. 0 indicates no descendant nodes are retrieved and a -1 indicates that all descendant nodes might be retrieved and cached by the provider. - ///upLevel or downLevel is less than -1. - SiteMapNode GetCurrentNodeAndHintNeighborhoodNodes(int upLevel, int downLevel); + /// + ///Provides an optimized lookup method for site map providers when retrieving the node for the currently requested page and fetching the site map nodes in the proximity of the current node. + /// + /// + /// + ///A that represents the currently requested page; otherwise, null, if the is not found or cannot be returned for the current user. + /// + /// + ///The number of ancestor generations to fetch. 0 indicates no ancestor nodes are retrieved and -1 indicates that all ancestors might be retrieved and cached by the provider. + ///The number of child generations to fetch. 0 indicates no descendant nodes are retrieved and a -1 indicates that all descendant nodes might be retrieved and cached by the provider. + ///upLevel or downLevel is less than -1. + SiteMapNode GetCurrentNodeAndHintNeighborhoodNodes(int upLevel, int downLevel); - /// - ///When overridden in a derived class, retrieves the parent node of a specific object. - /// - /// - /// - ///A that represents the parent of node; otherwise, null, if the has no parent or security trimming is enabled and the parent node is not accessible to the current user. - /// - /// - ///The for which to retrieve the parent node. - SiteMapNode GetParentNode(SiteMapNode node); + /// + ///When overridden in a derived class, retrieves the parent node of a specific object. + /// + /// + /// + ///A that represents the parent of node; otherwise, null, if the has no parent or security trimming is enabled and the parent node is not accessible to the current user. + /// + /// + ///The for which to retrieve the parent node. + SiteMapNode GetParentNode(SiteMapNode node); - /// - ///Provides an optimized lookup method for site map providers when retrieving an ancestor node for the currently requested page and fetching the descendant nodes for the ancestor. - /// - /// - /// - ///A that represents an ancestor of the currently requested page; otherwise, null, if the current or ancestor is not found or cannot be returned for the current user. - /// - /// - ///The number of descendant node levels to retrieve from the target ancestor node. - ///The number of ancestor node levels to traverse when retrieving the requested ancestor node. - ///walkupLevels or relativeDepthFromWalkup is less than 0. - SiteMapNode GetParentNodeRelativeToCurrentNodeAndHintDownFromParent(int walkupLevels, - int relativeDepthFromWalkup); + /// + ///Provides an optimized lookup method for site map providers when retrieving an ancestor node for the currently requested page and fetching the descendant nodes for the ancestor. + /// + /// + /// + ///A that represents an ancestor of the currently requested page; otherwise, null, if the current or ancestor is not found or cannot be returned for the current user. + /// + /// + ///The number of descendant node levels to retrieve from the target ancestor node. + ///The number of ancestor node levels to traverse when retrieving the requested ancestor node. + ///walkupLevels or relativeDepthFromWalkup is less than 0. + SiteMapNode GetParentNodeRelativeToCurrentNodeAndHintDownFromParent(int walkupLevels, + int relativeDepthFromWalkup); - /// - ///Provides an optimized lookup method for site map providers when retrieving an ancestor node for the specified object and fetching its child nodes. - /// - /// - /// - ///A that represents an ancestor of node; otherwise, null, if the current or ancestor is not found or cannot be returned for the current user. - /// - /// - ///The number of descendant node levels to retrieve from the target ancestor node. - ///The that acts as a reference point for walkupLevels and relativeDepthFromWalkup. - ///The number of ancestor node levels to traverse when retrieving the requested ancestor node. - ///The value specified for walkupLevels or relativeDepthFromWalkup is less than 0. - ///node is null. - SiteMapNode GetParentNodeRelativeToNodeAndHintDownFromParent(SiteMapNode node, int walkupLevels, - int relativeDepthFromWalkup); + /// + ///Provides an optimized lookup method for site map providers when retrieving an ancestor node for the specified object and fetching its child nodes. + /// + /// + /// + ///A that represents an ancestor of node; otherwise, null, if the current or ancestor is not found or cannot be returned for the current user. + /// + /// + ///The number of descendant node levels to retrieve from the target ancestor node. + ///The that acts as a reference point for walkupLevels and relativeDepthFromWalkup. + ///The number of ancestor node levels to traverse when retrieving the requested ancestor node. + ///The value specified for walkupLevels or relativeDepthFromWalkup is less than 0. + ///node is null. + SiteMapNode GetParentNodeRelativeToNodeAndHintDownFromParent(SiteMapNode node, int walkupLevels, + int relativeDepthFromWalkup); - /// - ///Provides a method that site map providers can override to perform an optimized retrieval of one or more levels of parent and ancestor nodes, relative to the specified object. - /// - /// - ///The number of ancestor generations to fetch. 0 indicates no ancestor nodes are retrieved and -1 indicates that all ancestors might be retrieved and cached. - ///The that acts as a reference point for upLevel. - ///upLevel is less than -1. - ///node is null. - void HintAncestorNodes(SiteMapNode node, int upLevel); + /// + ///Provides a method that site map providers can override to perform an optimized retrieval of one or more levels of parent and ancestor nodes, relative to the specified object. + /// + /// + ///The number of ancestor generations to fetch. 0 indicates no ancestor nodes are retrieved and -1 indicates that all ancestors might be retrieved and cached. + ///The that acts as a reference point for upLevel. + ///upLevel is less than -1. + ///node is null. + void HintAncestorNodes(SiteMapNode node, int upLevel); - /// - ///Provides a method that site map providers can override to perform an optimized retrieval of nodes found in the proximity of the specified node. - /// - /// - ///The number of ancestor generations to fetch. 0 indicates no ancestor nodes are retrieved and -1 indicates that all ancestors (and their descendant nodes to the level of node) might be retrieved and cached. - ///The number of descendant generations to fetch. 0 indicates no descendant nodes are retrieved and -1 indicates that all descendant nodes might be retrieved and cached. - ///The that acts as a reference point for upLevel. - ///upLevel or downLevel is less than -1. - ///node is null. - void HintNeighborhoodNodes(SiteMapNode node, int upLevel, int downLevel); + /// + ///Provides a method that site map providers can override to perform an optimized retrieval of nodes found in the proximity of the specified node. + /// + /// + ///The number of ancestor generations to fetch. 0 indicates no ancestor nodes are retrieved and -1 indicates that all ancestors (and their descendant nodes to the level of node) might be retrieved and cached. + ///The number of descendant generations to fetch. 0 indicates no descendant nodes are retrieved and -1 indicates that all descendant nodes might be retrieved and cached. + ///The that acts as a reference point for upLevel. + ///upLevel or downLevel is less than -1. + ///node is null. + void HintNeighborhoodNodes(SiteMapNode node, int upLevel, int downLevel); - /// - ///Retrieves a Boolean value indicating whether the specified object can be viewed by the user in the specified context. - /// - /// - /// - ///true if security trimming is enabled and node can be viewed by the user or security trimming is not enabled; otherwise, false. - /// - /// - ///The that contains user information. - ///The that is requested by the user. - ///context is null.- or -node is null. - bool IsAccessibleToUser(HttpContext context, SiteMapNode node); + /// + ///Retrieves a Boolean value indicating whether the specified object can be viewed by the user in the specified context. + /// + /// + /// + ///true if security trimming is enabled and node can be viewed by the user or security trimming is not enabled; otherwise, false. + /// + /// + ///The that contains user information. + ///The that is requested by the user. + ///context is null.- or -node is null. + bool IsAccessibleToUser(HttpContext context, SiteMapNode node); - /// - ///Gets the object that represents the currently requested page. - /// - /// - /// - ///A that represents the currently requested page; otherwise, null, if the is not found or cannot be returned for the current user. - /// - /// - SiteMapNode CurrentNode { get; } + /// + ///Gets the object that represents the currently requested page. + /// + /// + /// + ///A that represents the currently requested page; otherwise, null, if the is not found or cannot be returned for the current user. + /// + /// + SiteMapNode CurrentNode { get; } - /// - ///Gets or sets the parent object of the current provider. - /// - /// - /// - ///The parent provider of the current . - /// - /// - System.Web.SiteMapProvider ParentProvider { get; set; } + /// + ///Gets or sets the parent object of the current provider. + /// + /// + /// + ///The parent provider of the current . + /// + /// + System.Web.SiteMapProvider ParentProvider { get; set; } - /// - ///Gets the root object in the current provider hierarchy. - /// - /// - /// - ///An that is the top-level site map provider in the provider hierarchy that the current provider belongs to. - /// - /// - ///There is a circular reference to the current site map provider. - System.Web.SiteMapProvider RootProvider { get; } + /// + ///Gets the root object in the current provider hierarchy. + /// + /// + /// + ///An that is the top-level site map provider in the provider hierarchy that the current provider belongs to. + /// + /// + ///There is a circular reference to the current site map provider. + System.Web.SiteMapProvider RootProvider { get; } - /// - ///Gets the root object of the site map data that the current provider represents. - /// - /// - /// - ///The root of the current site map data provider. The default implementation performs security trimming on the returned node. - /// - /// - SiteMapNode RootNode { get; } - } + /// + ///Gets the root object of the site map data that the current provider represents. + /// + /// + /// + ///The root of the current site map data provider. The default implementation performs security trimming on the returned node. + /// + /// + SiteMapNode RootNode { get; } } diff --git a/src/Spring/Spring.Web/Web/Providers/MembershipProviderAdapter.cs b/src/Spring/Spring.Web/Web/Providers/MembershipProviderAdapter.cs index 82395dd8..884ff5b1 100644 --- a/src/Spring/Spring.Web/Web/Providers/MembershipProviderAdapter.cs +++ b/src/Spring/Spring.Web/Web/Providers/MembershipProviderAdapter.cs @@ -28,486 +28,485 @@ using Spring.Context.Support; #endregion -namespace Spring.Web.Providers +namespace Spring.Web.Providers; + +/// +/// Wrapper for class. +/// +/// +///

+/// Configuration for this provider requires providerId element set in web.config file, +/// as the Id of wrapped provider (defined in the Spring context). +///

+///
+/// Damjan Tomic +[AspNetHostingPermission(SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)] +[AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)] +public class MembershipProviderAdapter : MembershipProvider, IMembershipProvider { + #region Field + /// - /// Wrapper for class. + /// Reference to wrapped provider (defined in Spring context). /// - /// - ///

- /// Configuration for this provider requires providerId element set in web.config file, - /// as the Id of wrapped provider (defined in the Spring context). - ///

- ///
- /// Damjan Tomic - [AspNetHostingPermission(SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)] - [AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)] - public class MembershipProviderAdapter : MembershipProvider, IMembershipProvider + private MembershipProvider wrappedProvider; + + #endregion + + #region ProviderBase members + + /// + ///Initializes the provider. + /// + /// + ///A collection of the name/value pairs representing the provider-specific + /// attributes specified in the configuration for this provider. + /// The providerId attribute may be used to override the name being used for looking up an object definition. + /// + ///The friendly name of the provider. + ///The or is null. + ///An attempt is made to call on a provider after the provider has already been initialized. + ///The has a length of zero or providerId attribute is not set. + public override void Initialize(string name, NameValueCollection config) { - #region Field - - /// - /// Reference to wrapped provider (defined in Spring context). - /// - private MembershipProvider wrappedProvider; - - #endregion - - #region ProviderBase members - - /// - ///Initializes the provider. - /// - /// - ///A collection of the name/value pairs representing the provider-specific - /// attributes specified in the configuration for this provider. - /// The providerId attribute may be used to override the name being used for looking up an object definition. - /// - ///The friendly name of the provider. - ///The or is null. - ///An attempt is made to call on a provider after the provider has already been initialized. - ///The has a length of zero or providerId attribute is not set. - public override void Initialize(string name, NameValueCollection config) + lock (this) { - lock (this) - { - if (config == null) throw new ArgumentNullException("config"); + if (config == null) throw new ArgumentNullException("config"); - string providerId = config["providerId"]; - if (String.IsNullOrEmpty(providerId)) - providerId = name; - config.Remove("providerId"); + string providerId = config["providerId"]; + if (String.IsNullOrEmpty(providerId)) + providerId = name; + config.Remove("providerId"); - this.wrappedProvider = (MembershipProvider) WebApplicationContext.GetRootContext().GetObject(providerId); - this.wrappedProvider.Initialize(name, config); - } + this.wrappedProvider = (MembershipProvider) WebApplicationContext.GetRootContext().GetObject(providerId); + this.wrappedProvider.Initialize(name, config); } + } - /// - ///Gets the friendly name used to refer to the provider during configuration. - /// - /// - /// - ///The friendly name used to refer to the provider during configuration. - /// - /// - public override string Name - { - get { return this.wrappedProvider.Name; } - } + /// + ///Gets the friendly name used to refer to the provider during configuration. + /// + /// + /// + ///The friendly name used to refer to the provider during configuration. + /// + /// + public override string Name + { + get { return this.wrappedProvider.Name; } + } - /// - ///Gets a brief, friendly description suitable for display in administrative tools or other user interfaces (UIs). - /// - /// - /// - ///A brief, friendly description suitable for display in administrative tools or other UIs. - /// - /// - public override string Description - { - get { return this.wrappedProvider.Description; } - } + /// + ///Gets a brief, friendly description suitable for display in administrative tools or other user interfaces (UIs). + /// + /// + /// + ///A brief, friendly description suitable for display in administrative tools or other UIs. + /// + /// + public override string Description + { + get { return this.wrappedProvider.Description; } + } - #endregion + #endregion - #region System.Web.Security.MembershipProvider members - - /// - ///Adds a new membership user to the data source. - /// - /// - /// - ///A object populated with the information for the newly created user. - /// - /// - ///Whether or not the new user is approved to be validated. - ///The password answer for the new user - ///The user name for the new user. - ///The unique identifier from the membership data source for the user. - ///The password for the new user. - ///The password question for the new user. - ///The e-mail address for the new user. - ///A enumeration value indicating whether the user was created successfully. - public override MembershipUser CreateUser(string username, string password, string email, - string passwordQuestion, string passwordAnswer, bool isApproved, - object providerUserKey, out MembershipCreateStatus status) - { - return this.wrappedProvider.CreateUser(username, password, email, passwordQuestion, passwordAnswer, isApproved, providerUserKey, - out status); - } + #region System.Web.Security.MembershipProvider members - /// - ///Processes a request to update the password question and answer for a membership user. - /// - /// - /// - ///true if the password question and answer are updated successfully; otherwise, false. - /// - /// - ///The new password question for the specified user. - ///The new password answer for the specified user. - ///The user to change the password question and answer for. - ///The password for the specified user. - public override bool ChangePasswordQuestionAndAnswer(string username, string password, - string newPasswordQuestion, string newPasswordAnswer) - { - return this.wrappedProvider.ChangePasswordQuestionAndAnswer(username, password, newPasswordQuestion, newPasswordAnswer); - } + /// + ///Adds a new membership user to the data source. + /// + /// + /// + ///A object populated with the information for the newly created user. + /// + /// + ///Whether or not the new user is approved to be validated. + ///The password answer for the new user + ///The user name for the new user. + ///The unique identifier from the membership data source for the user. + ///The password for the new user. + ///The password question for the new user. + ///The e-mail address for the new user. + ///A enumeration value indicating whether the user was created successfully. + public override MembershipUser CreateUser(string username, string password, string email, + string passwordQuestion, string passwordAnswer, bool isApproved, + object providerUserKey, out MembershipCreateStatus status) + { + return this.wrappedProvider.CreateUser(username, password, email, passwordQuestion, passwordAnswer, isApproved, providerUserKey, + out status); + } - /// - ///Gets the password for the specified user name from the data source. - /// - /// - /// - ///The password for the specified user name. - /// - /// - ///The user to retrieve the password for. - ///The password answer for the user. - public override string GetPassword(string username, string answer) - { - return this.wrappedProvider.GetPassword(username, answer); - } + /// + ///Processes a request to update the password question and answer for a membership user. + /// + /// + /// + ///true if the password question and answer are updated successfully; otherwise, false. + /// + /// + ///The new password question for the specified user. + ///The new password answer for the specified user. + ///The user to change the password question and answer for. + ///The password for the specified user. + public override bool ChangePasswordQuestionAndAnswer(string username, string password, + string newPasswordQuestion, string newPasswordAnswer) + { + return this.wrappedProvider.ChangePasswordQuestionAndAnswer(username, password, newPasswordQuestion, newPasswordAnswer); + } - /// - ///Processes a request to update the password for a membership user. - /// - /// - /// - ///true if the password was updated successfully; otherwise, false. - /// - /// - ///The new password for the specified user. - ///The current password for the specified user. - ///The user to update the password for. - public override bool ChangePassword(string username, string oldPassword, string newPassword) - { - return this.wrappedProvider.ChangePassword(username, oldPassword, newPassword); - } + /// + ///Gets the password for the specified user name from the data source. + /// + /// + /// + ///The password for the specified user name. + /// + /// + ///The user to retrieve the password for. + ///The password answer for the user. + public override string GetPassword(string username, string answer) + { + return this.wrappedProvider.GetPassword(username, answer); + } - /// - ///Resets a user's password to a new, automatically generated password. - /// - /// - /// - ///The new password for the specified user. - /// - /// - ///The user to reset the password for. - ///The password answer for the specified user. - public override string ResetPassword(string username, string answer) - { - return this.wrappedProvider.ResetPassword(username, answer); - } + /// + ///Processes a request to update the password for a membership user. + /// + /// + /// + ///true if the password was updated successfully; otherwise, false. + /// + /// + ///The new password for the specified user. + ///The current password for the specified user. + ///The user to update the password for. + public override bool ChangePassword(string username, string oldPassword, string newPassword) + { + return this.wrappedProvider.ChangePassword(username, oldPassword, newPassword); + } - /// - ///Updates information about a user in the data source. - /// - /// - ///A object that represents the user to update and the updated information for the user. - public override void UpdateUser(MembershipUser user) - { - this.wrappedProvider.UpdateUser(user); - } + /// + ///Resets a user's password to a new, automatically generated password. + /// + /// + /// + ///The new password for the specified user. + /// + /// + ///The user to reset the password for. + ///The password answer for the specified user. + public override string ResetPassword(string username, string answer) + { + return this.wrappedProvider.ResetPassword(username, answer); + } - /// - ///Verifies that the specified user name and password exist in the data source. - /// - /// - /// - ///true if the specified username and password are valid; otherwise, false. - /// - /// - ///The name of the user to validate. - ///The password for the specified user. - public override bool ValidateUser(string username, string password) - { - return this.wrappedProvider.ValidateUser(username, password); - } + /// + ///Updates information about a user in the data source. + /// + /// + ///A object that represents the user to update and the updated information for the user. + public override void UpdateUser(MembershipUser user) + { + this.wrappedProvider.UpdateUser(user); + } - /// - ///Clears a lock so that the membership user can be validated. - /// - /// - /// - ///true if the membership user was successfully unlocked; otherwise, false. - /// - /// - ///The membership user to clear the lock status for. - public override bool UnlockUser(string userName) - { - return this.wrappedProvider.UnlockUser(userName); - } + /// + ///Verifies that the specified user name and password exist in the data source. + /// + /// + /// + ///true if the specified username and password are valid; otherwise, false. + /// + /// + ///The name of the user to validate. + ///The password for the specified user. + public override bool ValidateUser(string username, string password) + { + return this.wrappedProvider.ValidateUser(username, password); + } - /// - ///Gets information from the data source for a user based on the unique identifier for the membership user. Provides an option to update the last-activity date/time stamp for the user. - /// - /// - /// - ///A object populated with the specified user's information from the data source. - /// - /// - ///The unique identifier for the membership user to get information for. - ///true to update the last-activity date/time stamp for the user; false to return user information without updating the last-activity date/time stamp for the user. - public override MembershipUser GetUser(object providerUserKey, bool userIsOnline) - { - return this.wrappedProvider.GetUser(providerUserKey, userIsOnline); - } + /// + ///Clears a lock so that the membership user can be validated. + /// + /// + /// + ///true if the membership user was successfully unlocked; otherwise, false. + /// + /// + ///The membership user to clear the lock status for. + public override bool UnlockUser(string userName) + { + return this.wrappedProvider.UnlockUser(userName); + } - /// - ///Gets information from the data source for a user. Provides an option to update the last-activity date/time stamp for the user. - /// - /// - /// - ///A object populated with the specified user's information from the data source. - /// - /// - ///The name of the user to get information for. - ///true to update the last-activity date/time stamp for the user; false to return user information without updating the last-activity date/time stamp for the user. - public override MembershipUser GetUser(string username, bool userIsOnline) - { - return this.wrappedProvider.GetUser(username, userIsOnline); - } + /// + ///Gets information from the data source for a user based on the unique identifier for the membership user. Provides an option to update the last-activity date/time stamp for the user. + /// + /// + /// + ///A object populated with the specified user's information from the data source. + /// + /// + ///The unique identifier for the membership user to get information for. + ///true to update the last-activity date/time stamp for the user; false to return user information without updating the last-activity date/time stamp for the user. + public override MembershipUser GetUser(object providerUserKey, bool userIsOnline) + { + return this.wrappedProvider.GetUser(providerUserKey, userIsOnline); + } - /// - ///Gets the user name associated with the specified e-mail address. - /// - /// - /// - ///The user name associated with the specified e-mail address. If no match is found, return null. - /// - /// - ///The e-mail address to search for. - public override string GetUserNameByEmail(string email) - { - return this.wrappedProvider.GetUserNameByEmail(email); - } + /// + ///Gets information from the data source for a user. Provides an option to update the last-activity date/time stamp for the user. + /// + /// + /// + ///A object populated with the specified user's information from the data source. + /// + /// + ///The name of the user to get information for. + ///true to update the last-activity date/time stamp for the user; false to return user information without updating the last-activity date/time stamp for the user. + public override MembershipUser GetUser(string username, bool userIsOnline) + { + return this.wrappedProvider.GetUser(username, userIsOnline); + } - /// - ///Removes a user from the membership data source. - /// - /// - /// - ///true if the user was successfully deleted; otherwise, false. - /// - /// - ///The name of the user to delete. - ///true to delete data related to the user from the database; false to leave data related to the user in the database. - public override bool DeleteUser(string username, bool deleteAllRelatedData) - { - return this.wrappedProvider.DeleteUser(username, deleteAllRelatedData); - } + /// + ///Gets the user name associated with the specified e-mail address. + /// + /// + /// + ///The user name associated with the specified e-mail address. If no match is found, return null. + /// + /// + ///The e-mail address to search for. + public override string GetUserNameByEmail(string email) + { + return this.wrappedProvider.GetUserNameByEmail(email); + } - /// - ///Gets a collection of all the users in the data source in pages of data. - /// - /// - /// - ///A collection that contains a page of pageSize objects beginning at the page specified by pageIndex. - /// - /// - ///The total number of matched users. - ///The index of the page of results to return. pageIndex is zero-based. - ///The size of the page of results to return. - public override MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords) - { - return this.wrappedProvider.GetAllUsers(pageIndex, pageSize, out totalRecords); - } + /// + ///Removes a user from the membership data source. + /// + /// + /// + ///true if the user was successfully deleted; otherwise, false. + /// + /// + ///The name of the user to delete. + ///true to delete data related to the user from the database; false to leave data related to the user in the database. + public override bool DeleteUser(string username, bool deleteAllRelatedData) + { + return this.wrappedProvider.DeleteUser(username, deleteAllRelatedData); + } - /// - ///Gets the number of users currently accessing the application. - /// - /// - /// - ///The number of users currently accessing the application. - /// - /// - public override int GetNumberOfUsersOnline() - { - return this.wrappedProvider.GetNumberOfUsersOnline(); - } + /// + ///Gets a collection of all the users in the data source in pages of data. + /// + /// + /// + ///A collection that contains a page of pageSize objects beginning at the page specified by pageIndex. + /// + /// + ///The total number of matched users. + ///The index of the page of results to return. pageIndex is zero-based. + ///The size of the page of results to return. + public override MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords) + { + return this.wrappedProvider.GetAllUsers(pageIndex, pageSize, out totalRecords); + } - /// - ///Gets a collection of membership users where the user name contains the specified user name to match. - /// - /// - /// - ///A collection that contains a page of pageSize objects beginning at the page specified by pageIndex. - /// - /// - ///The total number of matched users. - ///The index of the page of results to return. pageIndex is zero-based. - ///The user name to search for. - ///The size of the page of results to return. - public override MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize, - out int totalRecords) - { - return this.wrappedProvider.FindUsersByName(usernameToMatch, pageIndex, pageSize, out totalRecords); - } + /// + ///Gets the number of users currently accessing the application. + /// + /// + /// + ///The number of users currently accessing the application. + /// + /// + public override int GetNumberOfUsersOnline() + { + return this.wrappedProvider.GetNumberOfUsersOnline(); + } - /// - ///Gets a collection of membership users where the e-mail address contains the specified e-mail address to match. - /// - /// - /// - ///A collection that contains a page of pageSize objects beginning at the page specified by pageIndex. - /// - /// - ///The total number of matched users. - ///The index of the page of results to return. pageIndex is zero-based. - ///The e-mail address to search for. - ///The size of the page of results to return. - public override MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, - out int totalRecords) - { - return this.wrappedProvider.FindUsersByEmail(emailToMatch, pageIndex, pageSize, out totalRecords); - } + /// + ///Gets a collection of membership users where the user name contains the specified user name to match. + /// + /// + /// + ///A collection that contains a page of pageSize objects beginning at the page specified by pageIndex. + /// + /// + ///The total number of matched users. + ///The index of the page of results to return. pageIndex is zero-based. + ///The user name to search for. + ///The size of the page of results to return. + public override MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize, + out int totalRecords) + { + return this.wrappedProvider.FindUsersByName(usernameToMatch, pageIndex, pageSize, out totalRecords); + } - /// - ///Indicates whether the membership provider is configured to allow users to retrieve their passwords. - /// - /// - /// - ///true if the membership provider is configured to support password retrieval; otherwise, false. The default is false. - /// - /// - public override bool EnablePasswordRetrieval - { - get { return this.wrappedProvider.EnablePasswordRetrieval; } - } + /// + ///Gets a collection of membership users where the e-mail address contains the specified e-mail address to match. + /// + /// + /// + ///A collection that contains a page of pageSize objects beginning at the page specified by pageIndex. + /// + /// + ///The total number of matched users. + ///The index of the page of results to return. pageIndex is zero-based. + ///The e-mail address to search for. + ///The size of the page of results to return. + public override MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, + out int totalRecords) + { + return this.wrappedProvider.FindUsersByEmail(emailToMatch, pageIndex, pageSize, out totalRecords); + } - /// - ///Indicates whether the membership provider is configured to allow users to reset their passwords. - /// - /// - /// - ///true if the membership provider supports password reset; otherwise, false. The default is true. - /// - /// - public override bool EnablePasswordReset - { - get { return this.wrappedProvider.EnablePasswordReset; } - } + /// + ///Indicates whether the membership provider is configured to allow users to retrieve their passwords. + /// + /// + /// + ///true if the membership provider is configured to support password retrieval; otherwise, false. The default is false. + /// + /// + public override bool EnablePasswordRetrieval + { + get { return this.wrappedProvider.EnablePasswordRetrieval; } + } - /// - ///Gets a value indicating whether the membership provider is configured to require the user to answer a password question for password reset and retrieval. - /// - /// - /// - ///true if a password answer is required for password reset and retrieval; otherwise, false. The default is true. - /// - /// - public override bool RequiresQuestionAndAnswer - { - get { return this.wrappedProvider.RequiresQuestionAndAnswer; } - } + /// + ///Indicates whether the membership provider is configured to allow users to reset their passwords. + /// + /// + /// + ///true if the membership provider supports password reset; otherwise, false. The default is true. + /// + /// + public override bool EnablePasswordReset + { + get { return this.wrappedProvider.EnablePasswordReset; } + } - /// - ///The name of the application using the custom membership provider. - /// - /// - /// - ///The name of the application using the custom membership provider. - /// - /// - public override string ApplicationName - { - get { return this.wrappedProvider.ApplicationName; } - set { this.wrappedProvider.ApplicationName = value; } - } + /// + ///Gets a value indicating whether the membership provider is configured to require the user to answer a password question for password reset and retrieval. + /// + /// + /// + ///true if a password answer is required for password reset and retrieval; otherwise, false. The default is true. + /// + /// + public override bool RequiresQuestionAndAnswer + { + get { return this.wrappedProvider.RequiresQuestionAndAnswer; } + } - /// - ///Gets the number of invalid password or password-answer attempts allowed before the membership user is locked out. - /// - /// - /// - ///The number of invalid password or password-answer attempts allowed before the membership user is locked out. - /// - /// - public override int MaxInvalidPasswordAttempts - { - get { return this.wrappedProvider.MaxInvalidPasswordAttempts; } - } + /// + ///The name of the application using the custom membership provider. + /// + /// + /// + ///The name of the application using the custom membership provider. + /// + /// + public override string ApplicationName + { + get { return this.wrappedProvider.ApplicationName; } + set { this.wrappedProvider.ApplicationName = value; } + } - /// - ///Gets the number of minutes in which a maximum number of invalid password or password-answer attempts are allowed before the membership user is locked out. - /// - /// - /// - ///The number of minutes in which a maximum number of invalid password or password-answer attempts are allowed before the membership user is locked out. - /// - /// - public override int PasswordAttemptWindow - { - get { return this.wrappedProvider.PasswordAttemptWindow; } - } + /// + ///Gets the number of invalid password or password-answer attempts allowed before the membership user is locked out. + /// + /// + /// + ///The number of invalid password or password-answer attempts allowed before the membership user is locked out. + /// + /// + public override int MaxInvalidPasswordAttempts + { + get { return this.wrappedProvider.MaxInvalidPasswordAttempts; } + } - /// - ///Gets a value indicating whether the membership provider is configured to require a unique e-mail address for each user name. - /// - /// - /// - ///true if the membership provider requires a unique e-mail address; otherwise, false. The default is true. - /// - /// - public override bool RequiresUniqueEmail - { - get { return this.wrappedProvider.RequiresUniqueEmail; } - } + /// + ///Gets the number of minutes in which a maximum number of invalid password or password-answer attempts are allowed before the membership user is locked out. + /// + /// + /// + ///The number of minutes in which a maximum number of invalid password or password-answer attempts are allowed before the membership user is locked out. + /// + /// + public override int PasswordAttemptWindow + { + get { return this.wrappedProvider.PasswordAttemptWindow; } + } - /// - ///Gets a value indicating the format for storing passwords in the membership data store. - /// - /// - /// - ///One of the values indicating the format for storing passwords in the data store. - /// - /// - public override MembershipPasswordFormat PasswordFormat - { - get { return this.wrappedProvider.PasswordFormat; } - } + /// + ///Gets a value indicating whether the membership provider is configured to require a unique e-mail address for each user name. + /// + /// + /// + ///true if the membership provider requires a unique e-mail address; otherwise, false. The default is true. + /// + /// + public override bool RequiresUniqueEmail + { + get { return this.wrappedProvider.RequiresUniqueEmail; } + } - /// - ///Gets the minimum length required for a password. - /// - /// - /// - ///The minimum length required for a password. - /// - /// - public override int MinRequiredPasswordLength - { - get { return this.wrappedProvider.MinRequiredPasswordLength; } - } + /// + ///Gets a value indicating the format for storing passwords in the membership data store. + /// + /// + /// + ///One of the values indicating the format for storing passwords in the data store. + /// + /// + public override MembershipPasswordFormat PasswordFormat + { + get { return this.wrappedProvider.PasswordFormat; } + } - /// - ///Gets the minimum number of special characters that must be present in a valid password. - /// - /// - /// - ///The minimum number of special characters that must be present in a valid password. - /// - /// - public override int MinRequiredNonAlphanumericCharacters - { - get { return this.wrappedProvider.MinRequiredNonAlphanumericCharacters; } - } + /// + ///Gets the minimum length required for a password. + /// + /// + /// + ///The minimum length required for a password. + /// + /// + public override int MinRequiredPasswordLength + { + get { return this.wrappedProvider.MinRequiredPasswordLength; } + } - /// - ///Gets the regular expression used to evaluate a password. - /// - /// - /// - ///A regular expression used to evaluate a password. - /// - /// - public override string PasswordStrengthRegularExpression - { - get { return this.wrappedProvider.PasswordStrengthRegularExpression; } - } - - #endregion - } -} + /// + ///Gets the minimum number of special characters that must be present in a valid password. + /// + /// + /// + ///The minimum number of special characters that must be present in a valid password. + /// + /// + public override int MinRequiredNonAlphanumericCharacters + { + get { return this.wrappedProvider.MinRequiredNonAlphanumericCharacters; } + } + + /// + ///Gets the regular expression used to evaluate a password. + /// + /// + /// + ///A regular expression used to evaluate a password. + /// + /// + public override string PasswordStrengthRegularExpression + { + get { return this.wrappedProvider.PasswordStrengthRegularExpression; } + } + + #endregion +} \ No newline at end of file diff --git a/src/Spring/Spring.Web/Web/Providers/ProfileProviderAdapter.cs b/src/Spring/Spring.Web/Web/Providers/ProfileProviderAdapter.cs index 5cddec89..93987dd2 100644 --- a/src/Spring/Spring.Web/Web/Providers/ProfileProviderAdapter.cs +++ b/src/Spring/Spring.Web/Web/Providers/ProfileProviderAdapter.cs @@ -25,276 +25,273 @@ using System.Web; using System.Web.Profile; using Spring.Context.Support; -namespace Spring.Web.Providers +namespace Spring.Web.Providers; + +/// +/// Wrapper for class. +/// +/// +///

+/// Configuration for this provider requires providerId element set in web.config file, +/// as the Id of wrapped provider (defined in the Spring context). +///

+///
+/// Damjan Tomic +[AspNetHostingPermission(SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)] +[AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)] +public class ProfileProviderAdapter : ProfileProvider, IProfileProvider { - /// - /// Wrapper for class. + #region Field + + /// + /// Reference to wrapped provider (defined in Spring context). /// - /// - ///

- /// Configuration for this provider requires providerId element set in web.config file, - /// as the Id of wrapped provider (defined in the Spring context). - ///

- ///
- /// Damjan Tomic - [AspNetHostingPermission(SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)] - [AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)] - public class ProfileProviderAdapter : ProfileProvider, IProfileProvider - { - #region Field + private ProfileProvider wrappedProvider; - /// - /// Reference to wrapped provider (defined in Spring context). - /// - private ProfileProvider wrappedProvider; + #endregion - #endregion + #region ProviderBase members - #region ProviderBase members - - /// - ///Initializes the provider. - /// - /// - ///A collection of the name/value pairs representing the provider-specific - /// attributes specified in the configuration for this provider. - /// The providerId attribute may be used to override the name being used for looking up an object definition. - /// - ///The friendly name of the provider. - ///The or is null. - ///An attempt is made to call on a provider after the provider has already been initialized. - ///The has a length of zero or providerId attribute is not set. - public override void Initialize(string name, NameValueCollection config) + /// + ///Initializes the provider. + /// + /// + ///A collection of the name/value pairs representing the provider-specific + /// attributes specified in the configuration for this provider. + /// The providerId attribute may be used to override the name being used for looking up an object definition. + /// + ///The friendly name of the provider. + ///The or is null. + ///An attempt is made to call on a provider after the provider has already been initialized. + ///The has a length of zero or providerId attribute is not set. + public override void Initialize(string name, NameValueCollection config) + { + lock (this) { - lock (this) - { - if (config == null) throw new ArgumentNullException("config"); + if (config == null) throw new ArgumentNullException("config"); - string providerId = config["providerId"]; - if (String.IsNullOrEmpty(providerId)) - providerId = name; - config.Remove("providerId"); + string providerId = config["providerId"]; + if (String.IsNullOrEmpty(providerId)) + providerId = name; + config.Remove("providerId"); - this.wrappedProvider = (ProfileProvider)WebApplicationContext.GetRootContext().GetObject(providerId); - this.wrappedProvider.Initialize(name, config); - } + this.wrappedProvider = (ProfileProvider) WebApplicationContext.GetRootContext().GetObject(providerId); + this.wrappedProvider.Initialize(name, config); } - - /// - ///Gets the friendly name used to refer to the provider during configuration. - /// - /// - /// - ///The friendly name used to refer to the provider during configuration. - /// - public override string Name - { - get { return this.wrappedProvider.Name; } - } - - /// - ///Gets a brief, friendly description suitable for display in administrative tools or other user interfaces (UIs). - /// - /// - /// - ///A brief, friendly description suitable for display in administrative tools or other UIs. - /// - public override string Description - { - get { return this.wrappedProvider.Description; } - } - - #endregion - - #region System.Web.Profile.ProfileProvider members - - /// - ///Returns the collection of settings property values for the specified application instance and settings property group. - /// - /// - /// - ///A containing the values for the specified settings property group. - /// - /// - ///A describing the current application use. - ///A containing the settings property group whose values are to be retrieved.2 - public override SettingsPropertyValueCollection GetPropertyValues(SettingsContext context, - SettingsPropertyCollection collection) - { - return this.wrappedProvider.GetPropertyValues(context, collection); - } - - /// - ///Sets the values of the specified group of property settings. - /// - /// - ///A describing the current application usage. - ///A representing the group of property settings to set.2 - public override void SetPropertyValues(SettingsContext context, SettingsPropertyValueCollection collection) - { - this.wrappedProvider.SetPropertyValues(context,collection); - } - - /// - ///Gets or sets the name of the currently running application. - /// - /// - /// - ///A that contains the application's shortened name, which does not contain a full path or extension, for example, SimpleAppSettings. - /// - ///2 - public override string ApplicationName - { - get { return this.wrappedProvider.ApplicationName; } - set { this.wrappedProvider.ApplicationName = value; } - } - - /// - ///When overridden in a derived class, deletes profile properties and information for the supplied list of profiles. - /// - /// - /// - ///The number of profiles deleted from the data source. - /// - /// - ///A of information about profiles that are to be deleted. - public override int DeleteProfiles(ProfileInfoCollection profiles) - { - return this.wrappedProvider.DeleteProfiles(profiles); - } - - /// - ///When overridden in a derived class, deletes profile properties and information for profiles that match the supplied list of user names. - /// - /// - /// - ///The number of profiles deleted from the data source. - /// - /// - ///A string array of user names for profiles to be deleted. - public override int DeleteProfiles(string[] usernames) - { - return this.wrappedProvider.DeleteProfiles(usernames); - } - - /// - ///When overridden in a derived class, deletes all user-profile data for profiles in which the last activity date occurred before the specified date. - /// - /// - /// - ///The number of profiles deleted from the data source. - /// - /// - ///One of the values, specifying whether anonymous, authenticated, or both types of profiles are deleted. - ///A that identifies which user profiles are considered inactive. If the value of a user profile occurs on or before this date and time, the profile is considered inactive. - public override int DeleteInactiveProfiles(ProfileAuthenticationOption authenticationOption, - DateTime userInactiveSinceDate) - { - return this.wrappedProvider.DeleteInactiveProfiles(authenticationOption, userInactiveSinceDate); - } - - /// - ///When overridden in a derived class, returns the number of profiles in which the last activity date occurred on or before the specified date. - /// - /// - /// - ///The number of profiles in which the last activity date occurred on or before the specified date. - /// - /// - ///One of the values, specifying whether anonymous, authenticated, or both types of profiles are returned. - ///A that identifies which user profiles are considered inactive. If the of a user profile occurs on or before this date and time, the profile is considered inactive. - public override int GetNumberOfInactiveProfiles(ProfileAuthenticationOption authenticationOption, - DateTime userInactiveSinceDate) - { - return this.wrappedProvider.GetNumberOfInactiveProfiles(authenticationOption, userInactiveSinceDate); - } - - /// - ///When overridden in a derived class, retrieves user profile data for all profiles in the data source. - /// - /// - /// - ///A containing user-profile information for all profiles in the data source. - /// - /// - ///One of the values, specifying whether anonymous, authenticated, or both types of profiles are returned. - ///When this method returns, contains the total number of profiles. - ///The index of the page of results to return. - ///The size of the page of results to return. - public override ProfileInfoCollection GetAllProfiles(ProfileAuthenticationOption authenticationOption, - int pageIndex, int pageSize, out int totalRecords) - { - return this.wrappedProvider.GetAllProfiles(authenticationOption, pageIndex, pageSize, out totalRecords); - } - - /// - ///When overridden in a derived class, retrieves user-profile data from the data source for profiles in which the last activity date occurred on or before the specified date. - /// - /// - /// - ///A containing user-profile information about the inactive profiles. - /// - /// - ///One of the values, specifying whether anonymous, authenticated, or both types of profiles are returned. - ///A that identifies which user profiles are considered inactive. If the of a user profile occurs on or before this date and time, the profile is considered inactive. - ///When this method returns, contains the total number of profiles. - ///The index of the page of results to return. - ///The size of the page of results to return. - public override ProfileInfoCollection GetAllInactiveProfiles(ProfileAuthenticationOption authenticationOption, - DateTime userInactiveSinceDate, int pageIndex, - int pageSize, out int totalRecords) - { - return - this.wrappedProvider.GetAllInactiveProfiles(authenticationOption, userInactiveSinceDate, pageIndex, pageSize, - out totalRecords); - } - - /// - ///When overridden in a derived class, retrieves profile information for profiles in which the user name matches the specified user names. - /// - /// - /// - ///A containing user-profile information for profiles where the user name matches the supplied usernameToMatch parameter. - /// - /// - ///One of the values, specifying whether anonymous, authenticated, or both types of profiles are returned. - ///When this method returns, contains the total number of profiles. - ///The index of the page of results to return. - ///The user name to search for. - ///The size of the page of results to return. - public override ProfileInfoCollection FindProfilesByUserName(ProfileAuthenticationOption authenticationOption, - string usernameToMatch, int pageIndex, int pageSize, - out int totalRecords) - { - return - this.wrappedProvider.FindProfilesByUserName(authenticationOption, usernameToMatch, pageIndex, pageSize, - out totalRecords); - } - - /// - ///When overridden in a derived class, retrieves profile information for profiles in which the last activity date occurred on or before the specified date and the user name matches the specified user name. - /// - /// - /// - ///A containing user profile information for inactive profiles where the user name matches the supplied usernameToMatch parameter. - /// - /// - ///One of the values, specifying whether anonymous, authenticated, or both types of profiles are returned. - ///A that identifies which user profiles are considered inactive. If the value of a user profile occurs on or before this date and time, the profile is considered inactive. - ///When this method returns, contains the total number of profiles. - ///The index of the page of results to return. - ///The user name to search for. - ///The size of the page of results to return. - public override ProfileInfoCollection FindInactiveProfilesByUserName( - ProfileAuthenticationOption authenticationOption, string usernameToMatch, DateTime userInactiveSinceDate, - int pageIndex, int pageSize, out int totalRecords) - { - return this.wrappedProvider.FindInactiveProfilesByUserName(authenticationOption, usernameToMatch, userInactiveSinceDate, - pageIndex, pageSize, out totalRecords); - } - - - #endregion - } + + /// + ///Gets the friendly name used to refer to the provider during configuration. + /// + /// + /// + ///The friendly name used to refer to the provider during configuration. + /// + public override string Name + { + get { return this.wrappedProvider.Name; } + } + + /// + ///Gets a brief, friendly description suitable for display in administrative tools or other user interfaces (UIs). + /// + /// + /// + ///A brief, friendly description suitable for display in administrative tools or other UIs. + /// + public override string Description + { + get { return this.wrappedProvider.Description; } + } + + #endregion + + #region System.Web.Profile.ProfileProvider members + + /// + ///Returns the collection of settings property values for the specified application instance and settings property group. + /// + /// + /// + ///A containing the values for the specified settings property group. + /// + /// + ///A describing the current application use. + ///A containing the settings property group whose values are to be retrieved.2 + public override SettingsPropertyValueCollection GetPropertyValues(SettingsContext context, + SettingsPropertyCollection collection) + { + return this.wrappedProvider.GetPropertyValues(context, collection); + } + + /// + ///Sets the values of the specified group of property settings. + /// + /// + ///A describing the current application usage. + ///A representing the group of property settings to set.2 + public override void SetPropertyValues(SettingsContext context, SettingsPropertyValueCollection collection) + { + this.wrappedProvider.SetPropertyValues(context, collection); + } + + /// + ///Gets or sets the name of the currently running application. + /// + /// + /// + ///A that contains the application's shortened name, which does not contain a full path or extension, for example, SimpleAppSettings. + /// + ///2 + public override string ApplicationName + { + get { return this.wrappedProvider.ApplicationName; } + set { this.wrappedProvider.ApplicationName = value; } + } + + /// + ///When overridden in a derived class, deletes profile properties and information for the supplied list of profiles. + /// + /// + /// + ///The number of profiles deleted from the data source. + /// + /// + ///A of information about profiles that are to be deleted. + public override int DeleteProfiles(ProfileInfoCollection profiles) + { + return this.wrappedProvider.DeleteProfiles(profiles); + } + + /// + ///When overridden in a derived class, deletes profile properties and information for profiles that match the supplied list of user names. + /// + /// + /// + ///The number of profiles deleted from the data source. + /// + /// + ///A string array of user names for profiles to be deleted. + public override int DeleteProfiles(string[] usernames) + { + return this.wrappedProvider.DeleteProfiles(usernames); + } + + /// + ///When overridden in a derived class, deletes all user-profile data for profiles in which the last activity date occurred before the specified date. + /// + /// + /// + ///The number of profiles deleted from the data source. + /// + /// + ///One of the values, specifying whether anonymous, authenticated, or both types of profiles are deleted. + ///A that identifies which user profiles are considered inactive. If the value of a user profile occurs on or before this date and time, the profile is considered inactive. + public override int DeleteInactiveProfiles(ProfileAuthenticationOption authenticationOption, + DateTime userInactiveSinceDate) + { + return this.wrappedProvider.DeleteInactiveProfiles(authenticationOption, userInactiveSinceDate); + } + + /// + ///When overridden in a derived class, returns the number of profiles in which the last activity date occurred on or before the specified date. + /// + /// + /// + ///The number of profiles in which the last activity date occurred on or before the specified date. + /// + /// + ///One of the values, specifying whether anonymous, authenticated, or both types of profiles are returned. + ///A that identifies which user profiles are considered inactive. If the of a user profile occurs on or before this date and time, the profile is considered inactive. + public override int GetNumberOfInactiveProfiles(ProfileAuthenticationOption authenticationOption, + DateTime userInactiveSinceDate) + { + return this.wrappedProvider.GetNumberOfInactiveProfiles(authenticationOption, userInactiveSinceDate); + } + + /// + ///When overridden in a derived class, retrieves user profile data for all profiles in the data source. + /// + /// + /// + ///A containing user-profile information for all profiles in the data source. + /// + /// + ///One of the values, specifying whether anonymous, authenticated, or both types of profiles are returned. + ///When this method returns, contains the total number of profiles. + ///The index of the page of results to return. + ///The size of the page of results to return. + public override ProfileInfoCollection GetAllProfiles(ProfileAuthenticationOption authenticationOption, + int pageIndex, int pageSize, out int totalRecords) + { + return this.wrappedProvider.GetAllProfiles(authenticationOption, pageIndex, pageSize, out totalRecords); + } + + /// + ///When overridden in a derived class, retrieves user-profile data from the data source for profiles in which the last activity date occurred on or before the specified date. + /// + /// + /// + ///A containing user-profile information about the inactive profiles. + /// + /// + ///One of the values, specifying whether anonymous, authenticated, or both types of profiles are returned. + ///A that identifies which user profiles are considered inactive. If the of a user profile occurs on or before this date and time, the profile is considered inactive. + ///When this method returns, contains the total number of profiles. + ///The index of the page of results to return. + ///The size of the page of results to return. + public override ProfileInfoCollection GetAllInactiveProfiles(ProfileAuthenticationOption authenticationOption, + DateTime userInactiveSinceDate, int pageIndex, + int pageSize, out int totalRecords) + { + return + this.wrappedProvider.GetAllInactiveProfiles(authenticationOption, userInactiveSinceDate, pageIndex, pageSize, + out totalRecords); + } + + /// + ///When overridden in a derived class, retrieves profile information for profiles in which the user name matches the specified user names. + /// + /// + /// + ///A containing user-profile information for profiles where the user name matches the supplied usernameToMatch parameter. + /// + /// + ///One of the values, specifying whether anonymous, authenticated, or both types of profiles are returned. + ///When this method returns, contains the total number of profiles. + ///The index of the page of results to return. + ///The user name to search for. + ///The size of the page of results to return. + public override ProfileInfoCollection FindProfilesByUserName(ProfileAuthenticationOption authenticationOption, + string usernameToMatch, int pageIndex, int pageSize, + out int totalRecords) + { + return + this.wrappedProvider.FindProfilesByUserName(authenticationOption, usernameToMatch, pageIndex, pageSize, + out totalRecords); + } + + /// + ///When overridden in a derived class, retrieves profile information for profiles in which the last activity date occurred on or before the specified date and the user name matches the specified user name. + /// + /// + /// + ///A containing user profile information for inactive profiles where the user name matches the supplied usernameToMatch parameter. + /// + /// + ///One of the values, specifying whether anonymous, authenticated, or both types of profiles are returned. + ///A that identifies which user profiles are considered inactive. If the value of a user profile occurs on or before this date and time, the profile is considered inactive. + ///When this method returns, contains the total number of profiles. + ///The index of the page of results to return. + ///The user name to search for. + ///The size of the page of results to return. + public override ProfileInfoCollection FindInactiveProfilesByUserName( + ProfileAuthenticationOption authenticationOption, string usernameToMatch, DateTime userInactiveSinceDate, + int pageIndex, int pageSize, out int totalRecords) + { + return this.wrappedProvider.FindInactiveProfilesByUserName(authenticationOption, usernameToMatch, userInactiveSinceDate, + pageIndex, pageSize, out totalRecords); + } + + #endregion } diff --git a/src/Spring/Spring.Web/Web/Providers/RoleProviderAdapter.cs b/src/Spring/Spring.Web/Web/Providers/RoleProviderAdapter.cs index 02b602aa..b006ec95 100644 --- a/src/Spring/Spring.Web/Web/Providers/RoleProviderAdapter.cs +++ b/src/Spring/Spring.Web/Web/Providers/RoleProviderAdapter.cs @@ -28,238 +28,234 @@ using Spring.Context.Support; #endregion +namespace Spring.Web.Providers; -namespace Spring.Web.Providers +/// +/// Wrapper for class. +/// +/// +///

+/// Configuration for this provider requires providerId element set in web.config file, +/// as the Id of wrapped provider (defined in the Spring context). +///

+///
+/// Damjan Tomic +[AspNetHostingPermission(SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)] +[AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)] +public class RoleProviderAdapter : RoleProvider, IRoleProvider { + #region Field + /// - /// Wrapper for class. + /// Reference to wrapped provider (defined in Spring context). /// - /// - ///

- /// Configuration for this provider requires providerId element set in web.config file, - /// as the Id of wrapped provider (defined in the Spring context). - ///

- ///
- /// Damjan Tomic - [AspNetHostingPermission(SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)] - [AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)] - public class RoleProviderAdapter : RoleProvider, IRoleProvider + private RoleProvider wrappedProvider; + + #endregion + + #region ProviderBase members + + /// + ///Initializes the provider. + /// + /// + ///A collection of the name/value pairs representing the provider-specific + /// attributes specified in the configuration for this provider. + /// The providerId attribute may be used to override the name being used for looking up an object definition. + /// + ///The friendly name of the provider. + ///The or is null. + ///An attempt is made to call on a provider after the provider has already been initialized. + ///The has a length of zero or providerId attribute is not set. + public override void Initialize(string name, NameValueCollection config) { - #region Field - - /// - /// Reference to wrapped provider (defined in Spring context). - /// - private RoleProvider wrappedProvider; - - #endregion - - #region ProviderBase members - - /// - ///Initializes the provider. - /// - /// - ///A collection of the name/value pairs representing the provider-specific - /// attributes specified in the configuration for this provider. - /// The providerId attribute may be used to override the name being used for looking up an object definition. - /// - ///The friendly name of the provider. - ///The or is null. - ///An attempt is made to call on a provider after the provider has already been initialized. - ///The has a length of zero or providerId attribute is not set. - public override void Initialize(string name, NameValueCollection config) + lock (this) { - lock (this) - { - if (config == null) throw new ArgumentNullException("config"); + if (config == null) throw new ArgumentNullException("config"); - string providerId = config["providerId"]; - if (String.IsNullOrEmpty(providerId)) - providerId = name; - config.Remove("providerId"); + string providerId = config["providerId"]; + if (String.IsNullOrEmpty(providerId)) + providerId = name; + config.Remove("providerId"); - this.wrappedProvider = (RoleProvider)WebApplicationContext.GetRootContext().GetObject(providerId); - this.wrappedProvider.Initialize(name,config); - } + this.wrappedProvider = (RoleProvider) WebApplicationContext.GetRootContext().GetObject(providerId); + this.wrappedProvider.Initialize(name, config); } - - /// - ///Gets the friendly name used to refer to the provider during configuration. - /// - /// - /// - ///The friendly name used to refer to the provider during configuration. - /// - public override string Name - { - get { return this.wrappedProvider.Name; } - } - - /// - ///Gets a brief, friendly description suitable for display in administrative tools or other user interfaces (UIs). - /// - /// - /// - ///A brief, friendly description suitable for display in administrative tools or other UIs. - /// - public override string Description - { - get { return this.wrappedProvider.Description; } - } - - #endregion - - #region System.Web.Security.RoleProvider members - - - /// - ///Gets a value indicating whether the specified user is in the specified role for the configured applicationName. - /// - /// - /// - ///true if the specified user is in the specified role for the configured applicationName; otherwise, false. - /// - /// - ///The user name to search for. - ///The role to search in. - public override bool IsUserInRole(string username, string roleName) - { - return this.wrappedProvider.IsUserInRole(username, roleName); - } - - /// - ///Gets a list of the roles that a specified user is in for the configured applicationName. - /// - /// - /// - ///A string array containing the names of all the roles that the specified user is in for the configured applicationName. - /// - /// - ///The user to return a list of roles for. - public override string[] GetRolesForUser(string username) - { - return this.wrappedProvider.GetRolesForUser(username); - } - - /// - ///Adds a new role to the data source for the configured applicationName. - /// - /// - ///The name of the role to create. - public override void CreateRole(string roleName) - { - this.wrappedProvider.CreateRole(roleName); - } - - /// - ///Removes a role from the data source for the configured applicationName. - /// - /// - /// - ///true if the role was successfully deleted; otherwise, false. - /// - /// - ///If true, throw an exception if roleName has one or more members and do not delete roleName. - ///The name of the role to delete. - public override bool DeleteRole(string roleName, bool throwOnPopulatedRole) - { - return this.wrappedProvider.DeleteRole(roleName, throwOnPopulatedRole); - } - - /// - ///Gets a value indicating whether the specified role name already exists in the role data source for the configured applicationName. - /// - /// - /// - ///true if the role name already exists in the data source for the configured applicationName; otherwise, false. - /// - /// - ///The name of the role to search for in the data source. - public override bool RoleExists(string roleName) - { - return this.wrappedProvider.RoleExists(roleName); - } - - /// - ///Adds the specified user names to the specified roles for the configured applicationName. - /// - /// - ///A string array of the role names to add the specified user names to. - ///A string array of user names to be added to the specified roles. - public override void AddUsersToRoles(string[] usernames, string[] roleNames) - { - this.wrappedProvider.AddUsersToRoles(usernames,roleNames); - } - - /// - ///Removes the specified user names from the specified roles for the configured applicationName. - /// - /// - ///A string array of role names to remove the specified user names from. - ///A string array of user names to be removed from the specified roles. - public override void RemoveUsersFromRoles(string[] usernames, string[] roleNames) - { - this.wrappedProvider.RemoveUsersFromRoles(usernames,roleNames); - } - - /// - ///Gets a list of users in the specified role for the configured applicationName. - /// - /// - /// - ///A string array containing the names of all the users who are members of the specified role for the configured applicationName. - /// - /// - ///The name of the role to get the list of users for. - public override string[] GetUsersInRole(string roleName) - { - return this.wrappedProvider.GetUsersInRole(roleName); - } - - /// - ///Gets a list of all the roles for the configured applicationName. - /// - /// - /// - ///A string array containing the names of all the roles stored in the data source for the configured applicationName. - /// - /// - public override string[] GetAllRoles() - { - return this.wrappedProvider.GetAllRoles(); - } - - /// - ///Gets an array of user names in a role where the user name contains the specified user name to match. - /// - /// - /// - ///A string array containing the names of all the users where the user name matches usernameToMatch and the user is a member of the specified role. - /// - /// - ///The user name to search for. - ///The role to search in. - public override string[] FindUsersInRole(string roleName, string usernameToMatch) - { - return this.wrappedProvider.FindUsersInRole(roleName, usernameToMatch); - } - - /// - ///Gets or sets the name of the application to store and retrieve role information for. - /// - /// - /// - ///The name of the application to store and retrieve role information for. - /// - /// - public override string ApplicationName - { - get { return this.wrappedProvider.ApplicationName; } - set { this.wrappedProvider.ApplicationName = value; } - } - - #endregion - } -} + + /// + ///Gets the friendly name used to refer to the provider during configuration. + /// + /// + /// + ///The friendly name used to refer to the provider during configuration. + /// + public override string Name + { + get { return this.wrappedProvider.Name; } + } + + /// + ///Gets a brief, friendly description suitable for display in administrative tools or other user interfaces (UIs). + /// + /// + /// + ///A brief, friendly description suitable for display in administrative tools or other UIs. + /// + public override string Description + { + get { return this.wrappedProvider.Description; } + } + + #endregion + + #region System.Web.Security.RoleProvider members + + /// + ///Gets a value indicating whether the specified user is in the specified role for the configured applicationName. + /// + /// + /// + ///true if the specified user is in the specified role for the configured applicationName; otherwise, false. + /// + /// + ///The user name to search for. + ///The role to search in. + public override bool IsUserInRole(string username, string roleName) + { + return this.wrappedProvider.IsUserInRole(username, roleName); + } + + /// + ///Gets a list of the roles that a specified user is in for the configured applicationName. + /// + /// + /// + ///A string array containing the names of all the roles that the specified user is in for the configured applicationName. + /// + /// + ///The user to return a list of roles for. + public override string[] GetRolesForUser(string username) + { + return this.wrappedProvider.GetRolesForUser(username); + } + + /// + ///Adds a new role to the data source for the configured applicationName. + /// + /// + ///The name of the role to create. + public override void CreateRole(string roleName) + { + this.wrappedProvider.CreateRole(roleName); + } + + /// + ///Removes a role from the data source for the configured applicationName. + /// + /// + /// + ///true if the role was successfully deleted; otherwise, false. + /// + /// + ///If true, throw an exception if roleName has one or more members and do not delete roleName. + ///The name of the role to delete. + public override bool DeleteRole(string roleName, bool throwOnPopulatedRole) + { + return this.wrappedProvider.DeleteRole(roleName, throwOnPopulatedRole); + } + + /// + ///Gets a value indicating whether the specified role name already exists in the role data source for the configured applicationName. + /// + /// + /// + ///true if the role name already exists in the data source for the configured applicationName; otherwise, false. + /// + /// + ///The name of the role to search for in the data source. + public override bool RoleExists(string roleName) + { + return this.wrappedProvider.RoleExists(roleName); + } + + /// + ///Adds the specified user names to the specified roles for the configured applicationName. + /// + /// + ///A string array of the role names to add the specified user names to. + ///A string array of user names to be added to the specified roles. + public override void AddUsersToRoles(string[] usernames, string[] roleNames) + { + this.wrappedProvider.AddUsersToRoles(usernames, roleNames); + } + + /// + ///Removes the specified user names from the specified roles for the configured applicationName. + /// + /// + ///A string array of role names to remove the specified user names from. + ///A string array of user names to be removed from the specified roles. + public override void RemoveUsersFromRoles(string[] usernames, string[] roleNames) + { + this.wrappedProvider.RemoveUsersFromRoles(usernames, roleNames); + } + + /// + ///Gets a list of users in the specified role for the configured applicationName. + /// + /// + /// + ///A string array containing the names of all the users who are members of the specified role for the configured applicationName. + /// + /// + ///The name of the role to get the list of users for. + public override string[] GetUsersInRole(string roleName) + { + return this.wrappedProvider.GetUsersInRole(roleName); + } + + /// + ///Gets a list of all the roles for the configured applicationName. + /// + /// + /// + ///A string array containing the names of all the roles stored in the data source for the configured applicationName. + /// + /// + public override string[] GetAllRoles() + { + return this.wrappedProvider.GetAllRoles(); + } + + /// + ///Gets an array of user names in a role where the user name contains the specified user name to match. + /// + /// + /// + ///A string array containing the names of all the users where the user name matches usernameToMatch and the user is a member of the specified role. + /// + /// + ///The user name to search for. + ///The role to search in. + public override string[] FindUsersInRole(string roleName, string usernameToMatch) + { + return this.wrappedProvider.FindUsersInRole(roleName, usernameToMatch); + } + + /// + ///Gets or sets the name of the application to store and retrieve role information for. + /// + /// + /// + ///The name of the application to store and retrieve role information for. + /// + /// + public override string ApplicationName + { + get { return this.wrappedProvider.ApplicationName; } + set { this.wrappedProvider.ApplicationName = value; } + } + + #endregion +} \ No newline at end of file diff --git a/src/Spring/Spring.Web/Web/Providers/SiteMapProviderAdapter.cs b/src/Spring/Spring.Web/Web/Providers/SiteMapProviderAdapter.cs index 6e5fc4c7..d6e199b6 100644 --- a/src/Spring/Spring.Web/Web/Providers/SiteMapProviderAdapter.cs +++ b/src/Spring/Spring.Web/Web/Providers/SiteMapProviderAdapter.cs @@ -27,336 +27,334 @@ using Spring.Context.Support; #endregion -namespace Spring.Web.Providers +namespace Spring.Web.Providers; + +/// +/// Wrapper for class. +/// +/// +///

+/// Configuration for this provider requires providerId element set in web.config file, +/// as the Id of wrapped provider (defined in the Spring context). +///

+///
+/// Damjan Tomic +[AspNetHostingPermission(SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)] +[AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)] +public class SiteMapProviderAdapter : SiteMapProvider, ISiteMapProvider { + #region Field + /// - /// Wrapper for class. + /// Reference to wrapped provider (defined in Spring context). /// - /// - ///

- /// Configuration for this provider requires providerId element set in web.config file, - /// as the Id of wrapped provider (defined in the Spring context). - ///

- ///
- /// Damjan Tomic - [AspNetHostingPermission(SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)] - [AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)] - public class SiteMapProviderAdapter : SiteMapProvider, ISiteMapProvider + private SiteMapProvider wrappedProvider; + + #endregion + + #region ProviderBase members + + /// + ///Initializes the provider. + /// + /// + ///A collection of the name/value pairs representing the provider-specific + /// attributes specified in the configuration for this provider. + /// The providerId attribute may be used to override the name being used for looking up an object definition. + /// + ///The friendly name of the provider. + ///The or is null. + ///An attempt is made to call on a provider after the provider has already been initialized. + ///The has a length of zero or providerId attribute is not set. + public override void Initialize(string name, NameValueCollection config) { - #region Field + if (config == null) throw new ArgumentNullException("config"); - /// - /// Reference to wrapped provider (defined in Spring context). - /// - private SiteMapProvider wrappedProvider; - - #endregion - - #region ProviderBase members - - /// - ///Initializes the provider. - /// - /// - ///A collection of the name/value pairs representing the provider-specific - /// attributes specified in the configuration for this provider. - /// The providerId attribute may be used to override the name being used for looking up an object definition. - /// - ///The friendly name of the provider. - ///The or is null. - ///An attempt is made to call on a provider after the provider has already been initialized. - ///The has a length of zero or providerId attribute is not set. - public override void Initialize(string name, NameValueCollection config) - { - if (config == null) throw new ArgumentNullException("config"); - - string providerId = config["providerId"]; - if (String.IsNullOrEmpty(providerId)) - providerId = name; - config.Remove("providerId"); - - this.wrappedProvider = (System.Web.SiteMapProvider)WebApplicationContext.GetRootContext().GetObject(providerId); - this.wrappedProvider.Initialize(name,config); - } - - /// - ///Gets the friendly name used to refer to the provider during configuration. - /// - /// - /// - ///The friendly name used to refer to the provider during configuration. - /// - /// - public override string Name - { - get { return this.wrappedProvider.Name; } - } - - /// - ///Gets a brief, friendly description suitable for display in administrative tools or other user interfaces (UIs). - /// - /// - /// - ///A brief, friendly description suitable for display in administrative tools or other UIs. - /// - /// - public override string Description - { - get { return this.wrappedProvider.Description; } - } - - #endregion - - #region System.Web.SiteMapProvider members - - /// - ///Retrieves a object that represents the currently requested page using the specified object. - /// - /// - /// - ///A that represents the currently requested page; otherwise, null, if no corresponding can be found in the or if the page context is null. - /// - /// - ///The used to match node information with the URL of the requested page. - public override SiteMapNode FindSiteMapNode(HttpContext context) - { - return this.wrappedProvider.FindSiteMapNode(context); - } - - /// - ///Retrieves a object based on a specified key. - /// - /// - /// - ///A that represents the page identified by key; otherwise, null, if no corresponding is found or if security trimming is enabled and the cannot be returned for the current user. The default is null. - /// - /// - ///A lookup key with which a is created. - public override SiteMapNode FindSiteMapNodeFromKey(string key) - { - return this.wrappedProvider.FindSiteMapNodeFromKey(key); - } - - /// - ///When overridden in a derived class, retrieves a object that represents the page at the specified URL. - /// - /// - /// - ///A that represents the page identified by rawURL; otherwise, null, if no corresponding is found or if security trimming is enabled and the cannot be returned for the current user. - /// - /// - ///A URL that identifies the page for which to retrieve a . - public override SiteMapNode FindSiteMapNode(string rawUrl) - { - return this.wrappedProvider.FindSiteMapNode(rawUrl); - } - - /// - ///When overridden in a derived class, retrieves the child nodes of a specific . - /// - /// - /// - ///A read-only that contains the immediate child nodes of the specified ; otherwise, null or an empty collection, if no child nodes exist. - /// - /// - ///The for which to retrieve all child nodes. - public override SiteMapNodeCollection GetChildNodes(SiteMapNode node) - { - return this.wrappedProvider.GetChildNodes(node); - } - - /// - ///Provides an optimized lookup method for site map providers when retrieving the node for the currently requested page and fetching the parent and ancestor site map nodes for the current page. - /// - /// - /// - ///A that represents the currently requested page; otherwise, null, if the is not found or cannot be returned for the current user. - /// - /// - ///The number of ancestor site map node generations to get. A value of -1 indicates that all ancestors might be retrieved and cached by the provider. - ///upLevel is less than -1. - public override SiteMapNode GetCurrentNodeAndHintAncestorNodes(int upLevel) - { - return this.wrappedProvider.GetCurrentNodeAndHintAncestorNodes(upLevel); - } - - /// - ///Provides an optimized lookup method for site map providers when retrieving the node for the currently requested page and fetching the site map nodes in the proximity of the current node. - /// - /// - /// - ///A that represents the currently requested page; otherwise, null, if the is not found or cannot be returned for the current user. - /// - /// - ///The number of ancestor generations to fetch. 0 indicates no ancestor nodes are retrieved and -1 indicates that all ancestors might be retrieved and cached by the provider. - ///The number of child generations to fetch. 0 indicates no descendant nodes are retrieved and a -1 indicates that all descendant nodes might be retrieved and cached by the provider. - ///upLevel or downLevel is less than -1. - public override SiteMapNode GetCurrentNodeAndHintNeighborhoodNodes(int upLevel, int downLevel) - { - return this.wrappedProvider.GetCurrentNodeAndHintNeighborhoodNodes(upLevel, downLevel); - } - - /// - ///When overridden in a derived class, retrieves the parent node of a specific object. - /// - /// - /// - ///A that represents the parent of node; otherwise, null, if the has no parent or security trimming is enabled and the parent node is not accessible to the current user. - /// - /// - ///The for which to retrieve the parent node. - public override SiteMapNode GetParentNode(SiteMapNode node) - { - return this.wrappedProvider.GetParentNode(node); - } - - /// - ///Provides an optimized lookup method for site map providers when retrieving an ancestor node for the currently requested page and fetching the descendant nodes for the ancestor. - /// - /// - /// - ///A that represents an ancestor of the currently requested page; otherwise, null, if the current or ancestor is not found or cannot be returned for the current user. - /// - /// - ///The number of descendant node levels to retrieve from the target ancestor node. - ///The number of ancestor node levels to traverse when retrieving the requested ancestor node. - ///walkupLevels or relativeDepthFromWalkup is less than 0. - public override SiteMapNode GetParentNodeRelativeToCurrentNodeAndHintDownFromParent(int walkupLevels, - int relativeDepthFromWalkup) - { - return this.wrappedProvider.GetParentNodeRelativeToCurrentNodeAndHintDownFromParent(walkupLevels, relativeDepthFromWalkup); - } - - /// - ///Provides an optimized lookup method for site map providers when retrieving an ancestor node for the specified object and fetching its child nodes. - /// - /// - /// - ///A that represents an ancestor of node; otherwise, null, if the current or ancestor is not found or cannot be returned for the current user. - /// - /// - ///The number of descendant node levels to retrieve from the target ancestor node. - ///The that acts as a reference point for walkupLevels and relativeDepthFromWalkup. - ///The number of ancestor node levels to traverse when retrieving the requested ancestor node. - ///The value specified for walkupLevels or relativeDepthFromWalkup is less than 0. - ///node is null. - public override SiteMapNode GetParentNodeRelativeToNodeAndHintDownFromParent(SiteMapNode node, int walkupLevels, - int relativeDepthFromWalkup) - { - return this.wrappedProvider.GetParentNodeRelativeToNodeAndHintDownFromParent(node, walkupLevels, relativeDepthFromWalkup); - } - - /// - /// This method is marked as protected and should never be called. - /// - /// - /// - ///A that represents the root node of the set of nodes that the current provider manages. - /// - /// - protected override SiteMapNode GetRootNodeCore() - { - throw new NotSupportedException("This method should never be called."); - } - - /// - ///Provides a method that site map providers can override to perform an optimized retrieval of one or more levels of parent and ancestor nodes, relative to the specified object. - /// - /// - ///The number of ancestor generations to fetch. 0 indicates no ancestor nodes are retrieved and -1 indicates that all ancestors might be retrieved and cached. - ///The that acts as a reference point for upLevel. - ///upLevel is less than -1. - ///node is null. - public override void HintAncestorNodes(SiteMapNode node, int upLevel) - { - this.wrappedProvider.HintAncestorNodes(node, upLevel); - } - - /// - ///Provides a method that site map providers can override to perform an optimized retrieval of nodes found in the proximity of the specified node. - /// - /// - ///The number of ancestor generations to fetch. 0 indicates no ancestor nodes are retrieved and -1 indicates that all ancestors (and their descendant nodes to the level of node) might be retrieved and cached. - ///The number of descendant generations to fetch. 0 indicates no descendant nodes are retrieved and -1 indicates that all descendant nodes might be retrieved and cached. - ///The that acts as a reference point for upLevel. - ///upLevel or downLevel is less than -1. - ///node is null. - public override void HintNeighborhoodNodes(SiteMapNode node, int upLevel, int downLevel) - { - this.wrappedProvider.HintNeighborhoodNodes(node, upLevel, downLevel); - } - - /// - ///Retrieves a Boolean value indicating whether the specified object can be viewed by the user in the specified context. - /// - /// - /// - ///true if security trimming is enabled and node can be viewed by the user or security trimming is not enabled; otherwise, false. - /// - /// - ///The that contains user information. - ///The that is requested by the user. - ///context is null.- or -node is null. - public override bool IsAccessibleToUser(HttpContext context, SiteMapNode node) - { - return this.wrappedProvider.IsAccessibleToUser(context, node); - } - - /// - ///Gets the object that represents the currently requested page. - /// - /// - /// - ///A that represents the currently requested page; otherwise, null, if the is not found or cannot be returned for the current user. - /// - /// - public override SiteMapNode CurrentNode - { - get { return this.wrappedProvider.CurrentNode; } - } - - /// - ///Gets or sets the parent object of the current provider. - /// - /// - /// - ///The parent provider of the current . - /// - /// - public override System.Web.SiteMapProvider ParentProvider - { - get { return this.wrappedProvider.ParentProvider; } - set { this.wrappedProvider.ParentProvider = value; } - } - - /// - ///Gets the root object in the current provider hierarchy. - /// - /// - /// - ///An that is the top-level site map provider in the provider hierarchy that the current provider belongs to. - /// - /// - ///There is a circular reference to the current site map provider. - public override System.Web.SiteMapProvider RootProvider - { - get { return this.wrappedProvider.RootProvider; } - } - - /// - ///Gets the root object of the site map data that the current provider represents. - /// - /// - /// - ///The root of the current site map data provider. The default implementation performs security trimming on the returned node. - /// - /// - public override SiteMapNode RootNode - { - get { return this.wrappedProvider.RootNode; } - } - - #endregion + string providerId = config["providerId"]; + if (String.IsNullOrEmpty(providerId)) + providerId = name; + config.Remove("providerId"); + this.wrappedProvider = (System.Web.SiteMapProvider) WebApplicationContext.GetRootContext().GetObject(providerId); + this.wrappedProvider.Initialize(name, config); } + + /// + ///Gets the friendly name used to refer to the provider during configuration. + /// + /// + /// + ///The friendly name used to refer to the provider during configuration. + /// + /// + public override string Name + { + get { return this.wrappedProvider.Name; } + } + + /// + ///Gets a brief, friendly description suitable for display in administrative tools or other user interfaces (UIs). + /// + /// + /// + ///A brief, friendly description suitable for display in administrative tools or other UIs. + /// + /// + public override string Description + { + get { return this.wrappedProvider.Description; } + } + + #endregion + + #region System.Web.SiteMapProvider members + + /// + ///Retrieves a object that represents the currently requested page using the specified object. + /// + /// + /// + ///A that represents the currently requested page; otherwise, null, if no corresponding can be found in the or if the page context is null. + /// + /// + ///The used to match node information with the URL of the requested page. + public override SiteMapNode FindSiteMapNode(HttpContext context) + { + return this.wrappedProvider.FindSiteMapNode(context); + } + + /// + ///Retrieves a object based on a specified key. + /// + /// + /// + ///A that represents the page identified by key; otherwise, null, if no corresponding is found or if security trimming is enabled and the cannot be returned for the current user. The default is null. + /// + /// + ///A lookup key with which a is created. + public override SiteMapNode FindSiteMapNodeFromKey(string key) + { + return this.wrappedProvider.FindSiteMapNodeFromKey(key); + } + + /// + ///When overridden in a derived class, retrieves a object that represents the page at the specified URL. + /// + /// + /// + ///A that represents the page identified by rawURL; otherwise, null, if no corresponding is found or if security trimming is enabled and the cannot be returned for the current user. + /// + /// + ///A URL that identifies the page for which to retrieve a . + public override SiteMapNode FindSiteMapNode(string rawUrl) + { + return this.wrappedProvider.FindSiteMapNode(rawUrl); + } + + /// + ///When overridden in a derived class, retrieves the child nodes of a specific . + /// + /// + /// + ///A read-only that contains the immediate child nodes of the specified ; otherwise, null or an empty collection, if no child nodes exist. + /// + /// + ///The for which to retrieve all child nodes. + public override SiteMapNodeCollection GetChildNodes(SiteMapNode node) + { + return this.wrappedProvider.GetChildNodes(node); + } + + /// + ///Provides an optimized lookup method for site map providers when retrieving the node for the currently requested page and fetching the parent and ancestor site map nodes for the current page. + /// + /// + /// + ///A that represents the currently requested page; otherwise, null, if the is not found or cannot be returned for the current user. + /// + /// + ///The number of ancestor site map node generations to get. A value of -1 indicates that all ancestors might be retrieved and cached by the provider. + ///upLevel is less than -1. + public override SiteMapNode GetCurrentNodeAndHintAncestorNodes(int upLevel) + { + return this.wrappedProvider.GetCurrentNodeAndHintAncestorNodes(upLevel); + } + + /// + ///Provides an optimized lookup method for site map providers when retrieving the node for the currently requested page and fetching the site map nodes in the proximity of the current node. + /// + /// + /// + ///A that represents the currently requested page; otherwise, null, if the is not found or cannot be returned for the current user. + /// + /// + ///The number of ancestor generations to fetch. 0 indicates no ancestor nodes are retrieved and -1 indicates that all ancestors might be retrieved and cached by the provider. + ///The number of child generations to fetch. 0 indicates no descendant nodes are retrieved and a -1 indicates that all descendant nodes might be retrieved and cached by the provider. + ///upLevel or downLevel is less than -1. + public override SiteMapNode GetCurrentNodeAndHintNeighborhoodNodes(int upLevel, int downLevel) + { + return this.wrappedProvider.GetCurrentNodeAndHintNeighborhoodNodes(upLevel, downLevel); + } + + /// + ///When overridden in a derived class, retrieves the parent node of a specific object. + /// + /// + /// + ///A that represents the parent of node; otherwise, null, if the has no parent or security trimming is enabled and the parent node is not accessible to the current user. + /// + /// + ///The for which to retrieve the parent node. + public override SiteMapNode GetParentNode(SiteMapNode node) + { + return this.wrappedProvider.GetParentNode(node); + } + + /// + ///Provides an optimized lookup method for site map providers when retrieving an ancestor node for the currently requested page and fetching the descendant nodes for the ancestor. + /// + /// + /// + ///A that represents an ancestor of the currently requested page; otherwise, null, if the current or ancestor is not found or cannot be returned for the current user. + /// + /// + ///The number of descendant node levels to retrieve from the target ancestor node. + ///The number of ancestor node levels to traverse when retrieving the requested ancestor node. + ///walkupLevels or relativeDepthFromWalkup is less than 0. + public override SiteMapNode GetParentNodeRelativeToCurrentNodeAndHintDownFromParent(int walkupLevels, + int relativeDepthFromWalkup) + { + return this.wrappedProvider.GetParentNodeRelativeToCurrentNodeAndHintDownFromParent(walkupLevels, relativeDepthFromWalkup); + } + + /// + ///Provides an optimized lookup method for site map providers when retrieving an ancestor node for the specified object and fetching its child nodes. + /// + /// + /// + ///A that represents an ancestor of node; otherwise, null, if the current or ancestor is not found or cannot be returned for the current user. + /// + /// + ///The number of descendant node levels to retrieve from the target ancestor node. + ///The that acts as a reference point for walkupLevels and relativeDepthFromWalkup. + ///The number of ancestor node levels to traverse when retrieving the requested ancestor node. + ///The value specified for walkupLevels or relativeDepthFromWalkup is less than 0. + ///node is null. + public override SiteMapNode GetParentNodeRelativeToNodeAndHintDownFromParent(SiteMapNode node, int walkupLevels, + int relativeDepthFromWalkup) + { + return this.wrappedProvider.GetParentNodeRelativeToNodeAndHintDownFromParent(node, walkupLevels, relativeDepthFromWalkup); + } + + /// + /// This method is marked as protected and should never be called. + /// + /// + /// + ///A that represents the root node of the set of nodes that the current provider manages. + /// + /// + protected override SiteMapNode GetRootNodeCore() + { + throw new NotSupportedException("This method should never be called."); + } + + /// + ///Provides a method that site map providers can override to perform an optimized retrieval of one or more levels of parent and ancestor nodes, relative to the specified object. + /// + /// + ///The number of ancestor generations to fetch. 0 indicates no ancestor nodes are retrieved and -1 indicates that all ancestors might be retrieved and cached. + ///The that acts as a reference point for upLevel. + ///upLevel is less than -1. + ///node is null. + public override void HintAncestorNodes(SiteMapNode node, int upLevel) + { + this.wrappedProvider.HintAncestorNodes(node, upLevel); + } + + /// + ///Provides a method that site map providers can override to perform an optimized retrieval of nodes found in the proximity of the specified node. + /// + /// + ///The number of ancestor generations to fetch. 0 indicates no ancestor nodes are retrieved and -1 indicates that all ancestors (and their descendant nodes to the level of node) might be retrieved and cached. + ///The number of descendant generations to fetch. 0 indicates no descendant nodes are retrieved and -1 indicates that all descendant nodes might be retrieved and cached. + ///The that acts as a reference point for upLevel. + ///upLevel or downLevel is less than -1. + ///node is null. + public override void HintNeighborhoodNodes(SiteMapNode node, int upLevel, int downLevel) + { + this.wrappedProvider.HintNeighborhoodNodes(node, upLevel, downLevel); + } + + /// + ///Retrieves a Boolean value indicating whether the specified object can be viewed by the user in the specified context. + /// + /// + /// + ///true if security trimming is enabled and node can be viewed by the user or security trimming is not enabled; otherwise, false. + /// + /// + ///The that contains user information. + ///The that is requested by the user. + ///context is null.- or -node is null. + public override bool IsAccessibleToUser(HttpContext context, SiteMapNode node) + { + return this.wrappedProvider.IsAccessibleToUser(context, node); + } + + /// + ///Gets the object that represents the currently requested page. + /// + /// + /// + ///A that represents the currently requested page; otherwise, null, if the is not found or cannot be returned for the current user. + /// + /// + public override SiteMapNode CurrentNode + { + get { return this.wrappedProvider.CurrentNode; } + } + + /// + ///Gets or sets the parent object of the current provider. + /// + /// + /// + ///The parent provider of the current . + /// + /// + public override System.Web.SiteMapProvider ParentProvider + { + get { return this.wrappedProvider.ParentProvider; } + set { this.wrappedProvider.ParentProvider = value; } + } + + /// + ///Gets the root object in the current provider hierarchy. + /// + /// + /// + ///An that is the top-level site map provider in the provider hierarchy that the current provider belongs to. + /// + /// + ///There is a circular reference to the current site map provider. + public override System.Web.SiteMapProvider RootProvider + { + get { return this.wrappedProvider.RootProvider; } + } + + /// + ///Gets the root object of the site map data that the current provider represents. + /// + /// + /// + ///The root of the current site map data provider. The default implementation performs security trimming on the returned node. + /// + /// + public override SiteMapNode RootNode + { + get { return this.wrappedProvider.RootNode; } + } + + #endregion } diff --git a/src/Spring/Spring.Web/Web/Services/WebServiceExporter.cs b/src/Spring/Spring.Web/Web/Services/WebServiceExporter.cs index 1812584a..c04fb6a5 100644 --- a/src/Spring/Spring.Web/Web/Services/WebServiceExporter.cs +++ b/src/Spring/Spring.Web/Web/Services/WebServiceExporter.cs @@ -31,547 +31,556 @@ using Spring.Proxy; #endregion -namespace Spring.Web.Services +namespace Spring.Web.Services; + +/// +/// Exports an object as a web service. +/// +/// +///

+/// The exporter will create a web service wrapper for the object that is +/// to be exposed and additionally enable its configuration as a web +/// service. +///

+///

+/// The exported object can be either a standard .NET web service +/// implementation, with methods marked using the standard +/// , or it can be a +/// plain .NET object. +///

+///
+/// Aleksandar Seovic +public class WebServiceExporter : IInitializingObject, IObjectFactoryAware, IObjectNameAware, IDisposable { /// - /// Exports an object as a web service. + /// Holds EXPORTER_ID to WebServiceExporter instance mappings. + /// + private static readonly IDictionary s_activeExporters = new Hashtable(); + + /// + /// Returns the target object instance exported by the WebServiceExporter identified by . + /// + /// + /// + public static object GetTarget(string exporterId) + { + WebServiceExporter exporterInstance; + lock (s_activeExporters.SyncRoot) + { + exporterInstance = (WebServiceExporter) s_activeExporters[exporterId]; + } + + if (exporterInstance == null) + { + throw new ArgumentNullException("exporterId", "WebService object is not associated with any active WebServiceExporter"); + } + + object target = exporterInstance.GetTargetInstance(); + if (target == null) + { + throw new ArgumentNullException("exporterId", string.Format("Failed retrieving target object for WebServiceExporter ID {0}", exporterId)); + } + + return target; + } + + #region Fields + + private WsiProfiles _wsiProfile = WsiProfiles.BasicProfile1_1; + private readonly string EXPORTER_ID = Guid.NewGuid().ToString(); + private Type _webServiceBaseType = typeof(WebService); + private string _targetName; + private string _description; + private string _name; + private string _namespace = WebServiceAttribute.DefaultNamespace; + private string[] _interfaces; + private IList _typeAttributes = new ArrayList(); + private IDictionary _memberAttributes = new Hashtable(); + + /// + /// The name of the object in the factory. + /// + private string objectName; + + /// + /// The owning factory. + /// + private IObjectFactory objectFactory; + + /// + /// The generated web service wrapper type. + /// + protected Type proxyType; + + #endregion + + #region Constructor(s) / Destructor + + /// + /// Creates a new instance of the class. + /// + public WebServiceExporter() + { + lock (s_activeExporters.SyncRoot) + { + s_activeExporters[EXPORTER_ID] = this; + } + } + + /// + /// Cleanup before GC + /// + ~WebServiceExporter() + { + Dispose(false); + } + + #region IDisposable Members + + /// + /// Disconnect the remote object from the registered remoting channels. + /// + public void Dispose() + { + GC.SuppressFinalize(this); + Dispose(true); + } + + /// + /// Stops exporting the object identified by . + /// + /// true to release both managed and unmanaged resources; false to release only unmanaged resources. + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + lock (s_activeExporters.SyncRoot) + { + s_activeExporters.Remove(this.EXPORTER_ID); + } + + objectFactory = null; + } + } + + #endregion + + #endregion + + #region Properties + + /// + /// Gets or Sets the Web Services Interoperability (WSI) specification + /// to which the Web Service claims to conform. + /// + /// + /// Default is + /// + public WsiProfiles WsiProfile + { + get { return _wsiProfile; } + set { _wsiProfile = value; } + } + + /// + /// Gets or sets the base type that web service should inherit. + /// + /// + /// Default is + /// + public Type WebServiceBaseType + { + get { return _webServiceBaseType; } + set { _webServiceBaseType = value; } + } + + /// + /// Gets or sets the name of the target object that should be exposed as a web service. + /// + /// + /// The name of the target object that should be exposed as a web service. + /// + public string TargetName + { + get { return _targetName; } + set { _targetName = value; } + } + + /// + /// Gets or sets the description of the web service (optional). + /// + /// + /// The web service description. + /// + public string Description + { + get { return _description; } + set { _description = value; } + } + + /// + /// Gets or sets the name of the web service (optional). /// /// ///

- /// The exporter will create a web service wrapper for the object that is - /// to be exposed and additionally enable its configuration as a web - /// service. - ///

- ///

- /// The exported object can be either a standard .NET web service - /// implementation, with methods marked using the standard - /// , or it can be a - /// plain .NET object. + /// Defaults to the value of the exporter's object ID. ///

///
- /// Aleksandar Seovic - public class WebServiceExporter : IInitializingObject, IObjectFactoryAware, IObjectNameAware, IDisposable + /// + /// The web service name. + /// + public string Name { - /// - /// Holds EXPORTER_ID to WebServiceExporter instance mappings. - /// - private static readonly IDictionary s_activeExporters = new Hashtable(); - - /// - /// Returns the target object instance exported by the WebServiceExporter identified by . - /// - /// - /// - public static object GetTarget( string exporterId ) + get { - WebServiceExporter exporterInstance; - lock (s_activeExporters.SyncRoot) + if (_name == null) { - exporterInstance = (WebServiceExporter)s_activeExporters[exporterId]; + _name = WebUtils.GetPageName(objectName); } - if (exporterInstance == null) - { - throw new ArgumentNullException("exporterId", "WebService object is not associated with any active WebServiceExporter"); - } - object target = exporterInstance.GetTargetInstance(); - if (target == null) - { - throw new ArgumentNullException("exporterId", string.Format( "Failed retrieving target object for WebServiceExporter ID {0}", exporterId )); - } - return target; + + return _name; + } + set { _name = value; } + } + + /// + /// Gets or sets the web service namespace. + /// + /// + /// The web service namespace. + /// + public string Namespace + { + get { return _namespace; } + set { _namespace = value; } + } + + /// + /// Gets or sets the list of interfaces whose methods should be exposed as web services. + /// + /// + /// If not set, all the interfaces implemented or inherited + /// by the target type will be used. + /// + /// The interfaces. + public string[] Interfaces + { + get { return _interfaces; } + set { _interfaces = value; } + } + + /// + /// Gets or sets a list of custom attributes + /// that should be applied to a proxy class. + /// + public IList TypeAttributes + { + get { return _typeAttributes; } + set { _typeAttributes = value; } + } + + /// + /// Gets or sets a dictionary of custom attributes + /// that should be applied to web service members. + /// + /// + /// Dictionary key is an expression that members can be matched against. + /// Value is a list of attributes that should be applied + /// to each member that matches expression. + /// + public IDictionary MemberAttributes + { + get { return _memberAttributes; } + set { _memberAttributes = value; } + } + + #endregion + + #region IObjectFactoryAware Members + + /// + /// Callback that supplies the owning factory to an object instance. + /// + /// + /// Owning + /// (may not be ). The object can immediately + /// call methods on the factory. + /// + /// + ///

+ /// Invoked after population of normal object properties but before an init + /// callback like 's + /// + /// method or a custom init-method. + ///

+ ///
+ /// + /// In case of initialization errors. + /// + public virtual IObjectFactory ObjectFactory + { + protected get { return objectFactory; } + set { objectFactory = value; } + } + + #endregion + + #region IObjectNameAware Members + + /// + /// Set the name of the object in the object factory that created this object. + /// + /// + /// The name of the object in the factory. + /// + /// + ///

+ /// Invoked after population of normal object properties but before an init + /// callback like 's + /// + /// method or a custom init-method. + ///

+ ///
+ public string ObjectName + { + protected get { return objectName; } + set { objectName = value; } + } + + #endregion + + #region IInitializingObject Members + + /// + /// Exports specified object as a web service. + /// + /// + /// In the event of misconfiguration (such as failure to set an essential + /// property) or if initialization fails. + /// + public virtual void AfterPropertiesSet() + { + ValidateConfiguration(); + GenerateProxy(); + } + + #endregion + + #region Methods + + /// + /// Returns the Web Service wrapper type for the object that is to be exposed. + /// + /// + public virtual Type GetExportedType() + { + return (proxyType != null ? proxyType : objectFactory.GetType(TargetName)); + } + + /// + /// Validates the configuration. + /// + protected virtual void ValidateConfiguration() + { + if (TargetName == null) + { + throw new ArgumentException("The TargetName property is required."); + } + } + + /// + /// Generates the web service wrapper type. + /// + protected virtual void GenerateProxy() + { + IProxyTypeBuilder builder = new WebServiceProxyTypeBuilder(this, Description, Name, Namespace, WsiProfile); + builder.Name = WebUtils.GetPageName(objectName); + builder.BaseType = WebServiceBaseType; + builder.TargetType = objectFactory.GetType(TargetName); + if (Interfaces != null && Interfaces.Length > 0) + { + builder.Interfaces = TypeResolutionUtils.ResolveInterfaceArray(Interfaces); } + builder.TypeAttributes = TypeAttributes; + builder.MemberAttributes = MemberAttributes; + + proxyType = builder.BuildProxyType(); + } + + private object GetTargetInstance() + { + return objectFactory.GetObject(TargetName); + } + + #endregion + + #region WebServiceProxyTypeBuilder inner class implementation + + private sealed class WebServiceProxyTypeBuilder : CompositionProxyTypeBuilder + { #region Fields - private WsiProfiles _wsiProfile = WsiProfiles.BasicProfile1_1; - private readonly string EXPORTER_ID = Guid.NewGuid().ToString(); - private Type _webServiceBaseType = typeof(WebService); - private string _targetName; - private string _description; - private string _name; - private string _namespace = WebServiceAttribute.DefaultNamespace; - private string[] _interfaces; - private IList _typeAttributes = new ArrayList(); - private IDictionary _memberAttributes = new Hashtable(); - - /// - /// The name of the object in the factory. - /// - private string objectName; - - /// - /// The owning factory. - /// - private IObjectFactory objectFactory; - - /// - /// The generated web service wrapper type. - /// - protected Type proxyType; + private static readonly MethodInfo WebServiceExporter_GetTargetInstance = typeof(WebServiceExporter).GetMethod("GetTarget", new Type[] { typeof(string) }); + private WebServiceExporter exporter; + private CustomAttributeBuilder webServiceAttribute; + private CustomAttributeBuilder webServiceBindingAttribute; #endregion #region Constructor(s) / Destructor - /// - /// Creates a new instance of the class. - /// - public WebServiceExporter() + public WebServiceProxyTypeBuilder(WebServiceExporter exporter, string description, string name, string ns) { - lock (s_activeExporters.SyncRoot) + this.exporter = exporter; + + // Creates a WebServiceAttribute from configuration info + this.webServiceAttribute = CreateWebServiceAttribute(description, name, ns); + } + + public WebServiceProxyTypeBuilder(WebServiceExporter exporter, string description, string name, string ns, WsiProfiles wsiProfile) + { + this.exporter = exporter; + + // Creates a WebServiceAttribute from configuration info + this.webServiceAttribute = CreateWebServiceAttribute(description, name, ns); + + // Creates a WebServiceAttribute from configuration info + this.webServiceBindingAttribute = CreateWebServiceBindingAttribute(wsiProfile); + } + + private static CustomAttributeBuilder CreateWebServiceBindingAttribute(WsiProfiles wsiProfile) + { + ReflectionUtils.CustomAttributeBuilderBuilder cabb = + new ReflectionUtils.CustomAttributeBuilderBuilder(typeof(WebServiceBindingAttribute)); + if (wsiProfile == WsiProfiles.BasicProfile1_1) { - s_activeExporters[EXPORTER_ID] = this; + cabb.AddPropertyValue("ConformsTo", wsiProfile); } + + return cabb.Build(); } - /// - /// Cleanup before GC - /// - ~WebServiceExporter() + private static CustomAttributeBuilder CreateWebServiceAttribute(string description, string name, string ns) { - Dispose( false ); - } - - #region IDisposable Members - - /// - /// Disconnect the remote object from the registered remoting channels. - /// - public void Dispose() - { - GC.SuppressFinalize( this ); - Dispose( true ); - } - - /// - /// Stops exporting the object identified by . - /// - /// true to release both managed and unmanaged resources; false to release only unmanaged resources. - protected virtual void Dispose( bool disposing ) - { - if (disposing) + ReflectionUtils.CustomAttributeBuilderBuilder cabb = + new ReflectionUtils.CustomAttributeBuilderBuilder(typeof(WebServiceAttribute)); + if (StringUtils.HasText(description)) { - lock (s_activeExporters.SyncRoot) - { - s_activeExporters.Remove( this.EXPORTER_ID ); - } - objectFactory = null; + cabb.AddPropertyValue("Description", description); } + + if (StringUtils.HasText(name)) + { + cabb.AddPropertyValue("Name", name); + } + + if (StringUtils.HasText(ns)) + { + cabb.AddPropertyValue("Namespace", ns); + } + + return cabb.Build(); } #endregion - #endregion - - #region Properties + #region Protected Methods /// - /// Gets or Sets the Web Services Interoperability (WSI) specification - /// to which the Web Service claims to conform. + /// Implements constructors for the proxy class. /// /// - /// Default is + /// This implementation generates an empty noop default constructor /// - public WsiProfiles WsiProfile + /// + /// The builder to use. + /// + protected override void ImplementConstructors(TypeBuilder builder) { - get { return _wsiProfile; } - set { _wsiProfile = value; } + MethodAttributes attributes = MethodAttributes.Public | + MethodAttributes.HideBySig | MethodAttributes.SpecialName | + MethodAttributes.RTSpecialName; + + ConstructorBuilder cb = builder.DefineConstructor( + attributes, CallingConventions.Standard, Type.EmptyTypes); + + ILGenerator il = cb.GetILGenerator(); + + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldstr, this.exporter.EXPORTER_ID); + il.Emit(OpCodes.Call, WebServiceExporter_GetTargetInstance); + il.Emit(OpCodes.Stfld, targetInstance); + + il.Emit(OpCodes.Ret); } - /// - /// Gets or sets the base type that web service should inherit. - /// - /// - /// Default is - /// - public Type WebServiceBaseType + protected override IList GetTypeAttributes(Type type) { - get { return _webServiceBaseType; } - set { _webServiceBaseType = value; } - } + IList attrs = base.GetTypeAttributes(type); - /// - /// Gets or sets the name of the target object that should be exposed as a web service. - /// - /// - /// The name of the target object that should be exposed as a web service. - /// - public string TargetName - { - get { return _targetName; } - set { _targetName = value; } - } + bool containsWebServiceAttribute = false; + bool containsWebServiceBindingAttribute = false; - /// - /// Gets or sets the description of the web service (optional). - /// - /// - /// The web service description. - /// - public string Description - { - get { return _description; } - set { _description = value; } - } - - /// - /// Gets or sets the name of the web service (optional). - /// - /// - ///

- /// Defaults to the value of the exporter's object ID. - ///

- ///
- /// - /// The web service name. - /// - public string Name - { - get + for (int i = 0; i < attrs.Count; i++) { - if (_name == null) + if (IsAttributeMatchingType(attrs[i], typeof(WebServiceAttribute))) { - _name = WebUtils.GetPageName(objectName); + // override existing WebServiceAttribute + containsWebServiceAttribute = true; + attrs[i] = webServiceAttribute; } - return _name; - } - set { _name = value; } - } - - /// - /// Gets or sets the web service namespace. - /// - /// - /// The web service namespace. - /// - public string Namespace - { - get { return _namespace; } - set { _namespace = value; } - } - - /// - /// Gets or sets the list of interfaces whose methods should be exposed as web services. - /// - /// - /// If not set, all the interfaces implemented or inherited - /// by the target type will be used. - /// - /// The interfaces. - public string[] Interfaces - { - get { return _interfaces; } - set { _interfaces = value; } - } - - /// - /// Gets or sets a list of custom attributes - /// that should be applied to a proxy class. - /// - public IList TypeAttributes - { - get { return _typeAttributes; } - set { _typeAttributes = value; } - } - - /// - /// Gets or sets a dictionary of custom attributes - /// that should be applied to web service members. - /// - /// - /// Dictionary key is an expression that members can be matched against. - /// Value is a list of attributes that should be applied - /// to each member that matches expression. - /// - public IDictionary MemberAttributes - { - get { return _memberAttributes; } - set { _memberAttributes = value; } - } - - #endregion - - #region IObjectFactoryAware Members - - /// - /// Callback that supplies the owning factory to an object instance. - /// - /// - /// Owning - /// (may not be ). The object can immediately - /// call methods on the factory. - /// - /// - ///

- /// Invoked after population of normal object properties but before an init - /// callback like 's - /// - /// method or a custom init-method. - ///

- ///
- /// - /// In case of initialization errors. - /// - public virtual IObjectFactory ObjectFactory - { - protected get { return objectFactory; } - set { objectFactory = value; } - } - - #endregion - - #region IObjectNameAware Members - - /// - /// Set the name of the object in the object factory that created this object. - /// - /// - /// The name of the object in the factory. - /// - /// - ///

- /// Invoked after population of normal object properties but before an init - /// callback like 's - /// - /// method or a custom init-method. - ///

- ///
- public string ObjectName - { - protected get { return objectName; } - set { objectName = value; } - } - - #endregion - - #region IInitializingObject Members - - /// - /// Exports specified object as a web service. - /// - /// - /// In the event of misconfiguration (such as failure to set an essential - /// property) or if initialization fails. - /// - public virtual void AfterPropertiesSet() - { - ValidateConfiguration(); - GenerateProxy(); - } - - #endregion - - #region Methods - - /// - /// Returns the Web Service wrapper type for the object that is to be exposed. - /// - /// - public virtual Type GetExportedType() - { - return (proxyType != null ? proxyType : objectFactory.GetType(TargetName)); - } - - /// - /// Validates the configuration. - /// - protected virtual void ValidateConfiguration() - { - if (TargetName == null) - { - throw new ArgumentException("The TargetName property is required."); - } - } - - /// - /// Generates the web service wrapper type. - /// - protected virtual void GenerateProxy() - { - IProxyTypeBuilder builder = new WebServiceProxyTypeBuilder(this, Description, Name, Namespace, WsiProfile); - builder.Name = WebUtils.GetPageName(objectName); - builder.BaseType = WebServiceBaseType; - builder.TargetType = objectFactory.GetType(TargetName); - if (Interfaces != null && Interfaces.Length > 0) - { - builder.Interfaces = TypeResolutionUtils.ResolveInterfaceArray(Interfaces); - } - builder.TypeAttributes = TypeAttributes; - builder.MemberAttributes = MemberAttributes; - - proxyType = builder.BuildProxyType(); - } - - private object GetTargetInstance() - { - return objectFactory.GetObject(TargetName); - } - - #endregion - - #region WebServiceProxyTypeBuilder inner class implementation - - private sealed class WebServiceProxyTypeBuilder : CompositionProxyTypeBuilder - { - #region Fields - - private static readonly MethodInfo WebServiceExporter_GetTargetInstance = typeof(WebServiceExporter).GetMethod( "GetTarget", new Type[] { typeof( string ) } ); - private WebServiceExporter exporter; - private CustomAttributeBuilder webServiceAttribute; - private CustomAttributeBuilder webServiceBindingAttribute; - - #endregion - - #region Constructor(s) / Destructor - - public WebServiceProxyTypeBuilder(WebServiceExporter exporter, string description, string name, string ns) - { - this.exporter = exporter; - - // Creates a WebServiceAttribute from configuration info - this.webServiceAttribute = CreateWebServiceAttribute(description, name, ns); - } - - public WebServiceProxyTypeBuilder(WebServiceExporter exporter, string description, string name, string ns, WsiProfiles wsiProfile) - { - this.exporter = exporter; - - // Creates a WebServiceAttribute from configuration info - this.webServiceAttribute = CreateWebServiceAttribute(description, name, ns); - - // Creates a WebServiceAttribute from configuration info - this.webServiceBindingAttribute = CreateWebServiceBindingAttribute(wsiProfile); - } - - private static CustomAttributeBuilder CreateWebServiceBindingAttribute(WsiProfiles wsiProfile) - { - ReflectionUtils.CustomAttributeBuilderBuilder cabb = - new ReflectionUtils.CustomAttributeBuilderBuilder(typeof(WebServiceBindingAttribute)); - if (wsiProfile == WsiProfiles.BasicProfile1_1) + else if (IsAttributeMatchingType(attrs[i], typeof(WebServiceBindingAttribute))) { - cabb.AddPropertyValue("ConformsTo", wsiProfile); + containsWebServiceBindingAttribute = true; } - return cabb.Build(); } - private static CustomAttributeBuilder CreateWebServiceAttribute(string description, string name, string ns) + // Add missing WebServiceAttribute + if (!containsWebServiceAttribute) { - ReflectionUtils.CustomAttributeBuilderBuilder cabb = - new ReflectionUtils.CustomAttributeBuilderBuilder(typeof(WebServiceAttribute)); - if (StringUtils.HasText(description)) - { - cabb.AddPropertyValue("Description", description); - } - if (StringUtils.HasText(name)) - { - cabb.AddPropertyValue("Name", name); - } - if (StringUtils.HasText(ns)) - { - cabb.AddPropertyValue("Namespace", ns); - } - return cabb.Build(); + attrs.Add(webServiceAttribute); } - #endregion - - #region Protected Methods - - /// - /// Implements constructors for the proxy class. - /// - /// - /// This implementation generates an empty noop default constructor - /// - /// - /// The builder to use. - /// - protected override void ImplementConstructors(TypeBuilder builder) + // Add missing WebServiceBindingAttribute + if (!containsWebServiceBindingAttribute) { - MethodAttributes attributes = MethodAttributes.Public | - MethodAttributes.HideBySig | MethodAttributes.SpecialName | - MethodAttributes.RTSpecialName; - - ConstructorBuilder cb = builder.DefineConstructor( - attributes, CallingConventions.Standard, Type.EmptyTypes); - - ILGenerator il = cb.GetILGenerator(); - - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Ldstr, this.exporter.EXPORTER_ID); - il.Emit( OpCodes.Call, WebServiceExporter_GetTargetInstance ); - il.Emit(OpCodes.Stfld, targetInstance); - - il.Emit(OpCodes.Ret); + attrs.Add(webServiceBindingAttribute); } - protected override IList GetTypeAttributes(Type type) + return attrs; + } + + protected override IList GetMethodAttributes(MethodInfo method) + { + IList attrs = base.GetMethodAttributes(method); + + bool containsWebMethodAttribute = false; + foreach (object attr in attrs) { - IList attrs = base.GetTypeAttributes(type); - - bool containsWebServiceAttribute = false; - bool containsWebServiceBindingAttribute = false; - - for (int i = 0; i < attrs.Count; i++) + if (IsAttributeMatchingType(attr, typeof(WebMethodAttribute))) { - if (IsAttributeMatchingType(attrs[i], typeof(WebServiceAttribute))) - { - // override existing WebServiceAttribute - containsWebServiceAttribute = true; - attrs[i] = webServiceAttribute; - } - else if (IsAttributeMatchingType(attrs[i], typeof(WebServiceBindingAttribute))) - { - containsWebServiceBindingAttribute = true; - } + containsWebMethodAttribute = true; + break; } - - // Add missing WebServiceAttribute - if (!containsWebServiceAttribute) - { - attrs.Add(webServiceAttribute); - } - - // Add missing WebServiceBindingAttribute - if (!containsWebServiceBindingAttribute) - { - attrs.Add(webServiceBindingAttribute); - } - - return attrs; } - protected override IList GetMethodAttributes(MethodInfo method) + // Creates default WebMethodAttribute if not set yet + if (!containsWebMethodAttribute) { - IList attrs = base.GetMethodAttributes(method); - - bool containsWebMethodAttribute = false; - foreach (object attr in attrs) - { - if (IsAttributeMatchingType(attr, typeof(WebMethodAttribute))) - { - containsWebMethodAttribute = true; - break; - } - } - - // Creates default WebMethodAttribute if not set yet - if (!containsWebMethodAttribute) - { - attrs.Add(ReflectionUtils.CreateCustomAttribute(typeof(WebMethodAttribute))); - } - - return attrs; + attrs.Add(ReflectionUtils.CreateCustomAttribute(typeof(WebMethodAttribute))); } - protected override TypeBuilder CreateTypeBuilder(string name, Type baseType) - { - return DynamicProxyManager.CreateTypeBuilder(name, baseType); - } + return attrs; + } - #endregion + protected override TypeBuilder CreateTypeBuilder(string name, Type baseType) + { + return DynamicProxyManager.CreateTypeBuilder(name, baseType); } #endregion } -} + + #endregion +} \ No newline at end of file diff --git a/src/Spring/Spring.Web/Web/Services/WebServiceHandlerFactory.cs b/src/Spring/Spring.Web/Web/Services/WebServiceHandlerFactory.cs index 366e1ff9..da5a399c 100644 --- a/src/Spring/Spring.Web/Web/Services/WebServiceHandlerFactory.cs +++ b/src/Spring/Spring.Web/Web/Services/WebServiceHandlerFactory.cs @@ -25,7 +25,6 @@ using System.Security.Permissions; using System.Web; using System.Web.UI; using System.Web.Services; - using Spring.Context; using Spring.Context.Support; using Spring.Util; @@ -39,72 +38,72 @@ using System.Collections; #endregion -namespace Spring.Web.Services +namespace Spring.Web.Services; + +/// +/// An implementation that +/// retrieves configured WebService objects from the Spring.NET web +/// application context. +/// +/// +/// This handler factory uses web service name from the URL, without the extension, +/// to find web service object in the Spring context. +/// +/// Aleksandar Seovic +[PermissionSet(SecurityAction.InheritanceDemand, Unrestricted = true)] +public class WebServiceHandlerFactory : System.Web.Services.Protocols.WebServiceHandlerFactory, IHttpHandlerFactory { +#if !MONO_2_0 + private static readonly MethodInfo CoreGetHandler = + typeof(System.Web.Services.Protocols.WebServiceHandlerFactory).GetMethod("CoreGetHandler", BindingFlags.NonPublic | BindingFlags.Instance, null, + new Type[] { typeof(Type), typeof(HttpContext), typeof(HttpRequest), typeof(HttpResponse) }, null); +#endif + /// - /// An implementation that - /// retrieves configured WebService objects from the Spring.NET web - /// application context. + /// Retrieves instance of the page from Spring web application context. /// - /// - /// This handler factory uses web service name from the URL, without the extension, - /// to find web service object in the Spring context. - /// - /// Aleksandar Seovic - [PermissionSet(SecurityAction.InheritanceDemand, Unrestricted=true)] - public class WebServiceHandlerFactory : System.Web.Services.Protocols.WebServiceHandlerFactory, IHttpHandlerFactory + /// current HttpContext + /// type of HTTP request (GET, POST, etc.) + /// requested page URL + /// translated server path for the page + /// instance of the configured page object + IHttpHandler IHttpHandlerFactory.GetHandler(HttpContext context, string requestType, string url, string path) { - #if !MONO_2_0 - private static readonly MethodInfo CoreGetHandler = - typeof(System.Web.Services.Protocols.WebServiceHandlerFactory).GetMethod("CoreGetHandler", BindingFlags.NonPublic | BindingFlags.Instance, null, - new Type[] {typeof(Type), typeof(HttpContext), typeof(HttpRequest), typeof(HttpResponse)}, null); - #endif + new AspNetHostingPermission(AspNetHostingPermissionLevel.Minimal).Demand(); - /// - /// Retrieves instance of the page from Spring web application context. - /// - /// current HttpContext - /// type of HTTP request (GET, POST, etc.) - /// requested page URL - /// translated server path for the page - /// instance of the configured page object - IHttpHandler IHttpHandlerFactory.GetHandler(HttpContext context, string requestType, string url, string path) + IConfigurableApplicationContext appContext = + WebApplicationContext.GetContext(url) as IConfigurableApplicationContext; + + if (appContext == null) { - new AspNetHostingPermission(AspNetHostingPermissionLevel.Minimal).Demand(); + throw new InvalidOperationException( + "Implementations of IApplicationContext must also implement IConfigurableApplicationContext"); + } - IConfigurableApplicationContext appContext = - WebApplicationContext.GetContext(url) as IConfigurableApplicationContext; + string appRelativeVirtualPath = WebUtils.GetAppRelativePath(url); - if (appContext == null) - { - throw new InvalidOperationException( - "Implementations of IApplicationContext must also implement IConfigurableApplicationContext"); - } + AbstractHandlerFactory.NamedObjectDefinition nod = + AbstractHandlerFactory.FindWebObjectDefinition(appRelativeVirtualPath, appContext.ObjectFactory); - string appRelativeVirtualPath = WebUtils.GetAppRelativePath(url); - - AbstractHandlerFactory.NamedObjectDefinition nod = - AbstractHandlerFactory.FindWebObjectDefinition(appRelativeVirtualPath, appContext.ObjectFactory); - - Type serviceType = null; - if (nod != null) - { + Type serviceType = null; + if (nod != null) + { #if !MONO - if (appContext.IsTypeMatch(nod.Name, typeof(WebServiceExporter))) + if (appContext.IsTypeMatch(nod.Name, typeof(WebServiceExporter))) + { + WebServiceExporter wse = (WebServiceExporter) appContext.GetObject(nod.Name); + serviceType = wse.GetExportedType(); + } + else + { + serviceType = appContext.GetType(nod.Name); + // check if the type defines a Web Service + object[] wsAttribute = serviceType.GetCustomAttributes(typeof(WebServiceAttribute), true); + if (wsAttribute.Length == 0) { - WebServiceExporter wse = (WebServiceExporter)appContext.GetObject(nod.Name); - serviceType = wse.GetExportedType(); - } - else - { - serviceType = appContext.GetType(nod.Name); - // check if the type defines a Web Service - object[] wsAttribute = serviceType.GetCustomAttributes(typeof(WebServiceAttribute), true); - if (wsAttribute.Length == 0) - { - serviceType = null; - } + serviceType = null; } + } #else serviceType = appContext.GetType(nod.Name); @@ -115,18 +114,16 @@ namespace Spring.Web.Services serviceType = null; } #endif - } - - if (serviceType == null) - { - serviceType = WebServiceParser.GetCompiledType(url, context); - } + } + if (serviceType == null) + { + serviceType = WebServiceParser.GetCompiledType(url, context); + } #if !MONO_2_0 - return (IHttpHandler) CoreGetHandler.Invoke(this, new object[] {serviceType, context, context.Request, context.Response}); + return (IHttpHandler) CoreGetHandler.Invoke(this, new object[] { serviceType, context, context.Request, context.Response }); #else - // find if the BuildManager already contains a cached value of the service type var buildCacheField = typeof(BuildManager).GetField("buildCache", BindingFlags.Static | BindingFlags.NonPublic); var buildCache = (IDictionary)buildCacheField.GetValue(null); @@ -146,8 +143,8 @@ namespace Spring.Web.Services // now that the target type is in the cache, let the default process continue return base.GetHandler(context, requestType, url, path); #endif - } } +} #if MONO_2_0 public class FakeBuildProvider : BuildProvider @@ -191,4 +188,3 @@ namespace Spring.Web.Services } } #endif -} diff --git a/src/Spring/Spring.Web/Web/Support/AbstractHandlerFactory.cs b/src/Spring/Spring.Web/Web/Support/AbstractHandlerFactory.cs index b82aff88..83faa72f 100644 --- a/src/Spring/Spring.Web/Web/Support/AbstractHandlerFactory.cs +++ b/src/Spring/Spring.Web/Web/Support/AbstractHandlerFactory.cs @@ -34,331 +34,337 @@ using Spring.Util; #endregion -namespace Spring.Web.Support +namespace Spring.Web.Support; + +/// +/// Provides base functionality for Spring.NET context-aware +/// implementations. +/// +/// +///

+/// Provides derived classes with a default implementation of +/// method. +///

+///
+/// Aleksandar Seovic +public abstract class AbstractHandlerFactory : IHttpHandlerFactory { + #region NamedObjectDefinition Utility + /// - /// Provides base functionality for Spring.NET context-aware - /// implementations. + /// Holds a named + /// + /// Erich Eichinger + protected internal class NamedObjectDefinition + { + private readonly string _name; + private readonly IObjectDefinition _objectDefinition; + + /// + /// Creates a new name/objectdefinition pair. + /// + public NamedObjectDefinition(string name, IObjectDefinition objectDefinition) + { + _name = name; + _objectDefinition = objectDefinition; + } + + /// + /// Get the name of the attached object definition + /// + public string Name + { + get { return _name; } + } + + /// + /// Get the . + /// + public IObjectDefinition ObjectDefinition + { + get { return _objectDefinition; } + } + } + + #endregion + + /// + /// Holds all handlers having == true. + /// + private readonly IDictionary _reusableHandlerCache = new CaseInsensitiveHashtable(); + + /// + /// Holds an instance of the instrinsic System.Web.UI.SimpleHandlerFactory + /// + private static readonly IHttpHandlerFactory s_simpleHandlerFactory; + + static AbstractHandlerFactory() + { + PrivilegedCommand cmd = new PrivilegedCommand(); + SecurityCritical.ExecutePrivileged(new PermissionSet(PermissionState.Unrestricted), new SecurityCritical.PrivilegedCallback(cmd.Execute)); + s_simpleHandlerFactory = cmd.Result; + } + + private class PrivilegedCommand + { + public IHttpHandlerFactory Result = null; + + public void Execute() + { + Type simpleHandlerFactoryType = typeof(IHttpHandler).Assembly.GetType("System.Web.UI.SimpleHandlerFactory"); + Result = (IHttpHandlerFactory) Activator.CreateInstance(simpleHandlerFactoryType, true); + } + } + + /// + /// Get the global instance of System.Web.UI.SimpleHandlerFactory /// /// - ///

- /// Provides derived classes with a default implementation of - /// method. - ///

+ /// This factory is a plaform version agnostic way to instantiate + /// arbitrary handlers without the need for additional reflection. ///
- /// Aleksandar Seovic - public abstract class AbstractHandlerFactory : IHttpHandlerFactory + public static IHttpHandlerFactory SimpleHandlerFactory { - #region NamedObjectDefinition Utility - /// - /// Holds a named - /// - /// Erich Eichinger - protected internal class NamedObjectDefinition + get { - private readonly string _name; - private readonly IObjectDefinition _objectDefinition; - - /// - /// Creates a new name/objectdefinition pair. - /// - public NamedObjectDefinition(string name, IObjectDefinition objectDefinition) + // instantiate lazy to avoid security exceptions in restricted reflection environments + if (s_simpleHandlerFactory == null) { - _name = name; - _objectDefinition = objectDefinition; } - /// - /// Get the name of the attached object definition - /// - public string Name - { - get { return _name; } - } - - /// - /// Get the . - /// - public IObjectDefinition ObjectDefinition - { - get { return _objectDefinition; } - } + return s_simpleHandlerFactory; } + } + + /// + /// Holds the shared logger for all factories. + /// + protected readonly ILogger Log; + + /// + /// Creates a new instance of the + /// class. + /// + protected AbstractHandlerFactory() + { + this.Log = LogManager.GetLogger(this.GetType()); + } + + /// + /// Returns an appropriate implementation. + /// + /// + /// An instance of the class that + /// provides references to intrinsic server objects. + /// + /// + /// The HTTP method of the request. + /// + /// The request URL. + /// + /// The physical path of the requested resource. + /// + /// + /// A new object that processes + /// the request. + /// + public virtual IHttpHandler GetHandler(HttpContext context, string requestType, string url, string physicalPath) + { + bool isDebug = Log.IsEnabled(LogLevel.Debug); + + #region Instrumentation + + if (isDebug) + Log.LogDebug(string.Format("GetHandler():resolving url '{0}'", url)); + #endregion - /// - /// Holds all handlers having == true. - /// - private readonly IDictionary _reusableHandlerCache = new CaseInsensitiveHashtable(); - - /// - /// Holds an instance of the instrinsic System.Web.UI.SimpleHandlerFactory - /// - private static readonly IHttpHandlerFactory s_simpleHandlerFactory; - - static AbstractHandlerFactory() + IHttpHandler handler = null; + lock (_reusableHandlerCache.SyncRoot) { - PrivilegedCommand cmd = new PrivilegedCommand(); - SecurityCritical.ExecutePrivileged(new PermissionSet(PermissionState.Unrestricted), new SecurityCritical.PrivilegedCallback(cmd.Execute)); - s_simpleHandlerFactory = cmd.Result; + handler = (IHttpHandler) _reusableHandlerCache[url]; } - private class PrivilegedCommand + if (handler != null) { - public IHttpHandlerFactory Result = null; - - public void Execute() - { - Type simpleHandlerFactoryType = typeof(IHttpHandler).Assembly.GetType("System.Web.UI.SimpleHandlerFactory"); - Result = (IHttpHandlerFactory)Activator.CreateInstance(simpleHandlerFactoryType, true); - } - } - - /// - /// Get the global instance of System.Web.UI.SimpleHandlerFactory - /// - /// - /// This factory is a plaform version agnostic way to instantiate - /// arbitrary handlers without the need for additional reflection. - /// - public static IHttpHandlerFactory SimpleHandlerFactory - { - get - { - // instantiate lazy to avoid security exceptions in restricted reflection environments - if (s_simpleHandlerFactory == null) - { - } - return s_simpleHandlerFactory; - } - } - - /// - /// Holds the shared logger for all factories. - /// - protected readonly ILogger Log; - - /// - /// Creates a new instance of the - /// class. - /// - protected AbstractHandlerFactory() - { - this.Log = LogManager.GetLogger(this.GetType()); - } - - /// - /// Returns an appropriate implementation. - /// - /// - /// An instance of the class that - /// provides references to intrinsic server objects. - /// - /// - /// The HTTP method of the request. - /// - /// The request URL. - /// - /// The physical path of the requested resource. - /// - /// - /// A new object that processes - /// the request. - /// - public virtual IHttpHandler GetHandler(HttpContext context, string requestType, string url, string physicalPath) - { - bool isDebug = Log.IsEnabled(LogLevel.Debug); - #region Instrumentation if (isDebug) - Log.LogDebug(string.Format("GetHandler():resolving url '{0}'", url)); + { + Log.LogDebug(string.Format("GetHandler():resolved url '{0}' from reusable handler cache", url)); + } #endregion - IHttpHandler handler = null; - lock (_reusableHandlerCache.SyncRoot) - { - handler = (IHttpHandler)_reusableHandlerCache[url]; - } + return handler; + } - if (handler != null) + lock (_reusableHandlerCache.SyncRoot) + { + handler = (IHttpHandler) _reusableHandlerCache[url]; + if (handler == null) { - #region Instrumentation + IConfigurableApplicationContext appContext = GetCheckedApplicationContext(url); - if (isDebug) + handler = CreateHandlerInstance(appContext, context, requestType, url, physicalPath); + + ApplyDependencyInjectionInfrastructure(handler, appContext); + + if (handler.IsReusable) { - Log.LogDebug(string.Format("GetHandler():resolved url '{0}' from reusable handler cache", url)); + _reusableHandlerCache[url] = handler; } - - #endregion - - return handler; } - lock (_reusableHandlerCache.SyncRoot) - { - handler = (IHttpHandler)_reusableHandlerCache[url]; - if (handler == null) - { - IConfigurableApplicationContext appContext = GetCheckedApplicationContext(url); + return handler; + } + } - handler = CreateHandlerInstance(appContext, context, requestType, url, physicalPath); + /// + /// Enables a factory to release an existing + /// instance. + /// + /// + /// The object to release. + /// + public virtual void ReleaseHandler(IHttpHandler handler) + { + } - ApplyDependencyInjectionInfrastructure(handler, appContext); + /// + /// Create a handler instance for the given URL. + /// + /// the application context corresponding to the current request + /// The instance for this request. + /// The HTTP data transfer method (GET, POST, ...) + /// The requested . + /// The physical path of the requested resource. + /// A handler instance for processing the current request. + protected abstract IHttpHandler CreateHandlerInstance(IConfigurableApplicationContext appContext, HttpContext context, string requestType, string rawUrl, string physicalPath); - if (handler.IsReusable) - { - _reusableHandlerCache[url] = handler; - } - } - return handler; - } + /// + /// Get the application context instance corresponding to the given absolute url and checks + /// it for contract and being not null. + /// + /// the absolute url + /// + /// if no context is found + /// + /// + /// if context is not an + /// + /// teh application context instance corresponding to the given absolute url. + /// + /// Calls to obtain a context instance. + /// + protected IConfigurableApplicationContext GetCheckedApplicationContext(string url) + { + IApplicationContext appContext = GetContext(url); + if (appContext == null) + { + throw new ArgumentException(string.Format("no application context for virtual path '{0}'", url)); } - /// - /// Enables a factory to release an existing - /// instance. - /// - /// - /// The object to release. - /// - public virtual void ReleaseHandler(IHttpHandler handler) - { } - - /// - /// Create a handler instance for the given URL. - /// - /// the application context corresponding to the current request - /// The instance for this request. - /// The HTTP data transfer method (GET, POST, ...) - /// The requested . - /// The physical path of the requested resource. - /// A handler instance for processing the current request. - protected abstract IHttpHandler CreateHandlerInstance(IConfigurableApplicationContext appContext, HttpContext context, string requestType, string rawUrl, string physicalPath); - - /// - /// Get the application context instance corresponding to the given absolute url and checks - /// it for contract and being not null. - /// - /// the absolute url - /// - /// if no context is found - /// - /// - /// if context is not an - /// - /// teh application context instance corresponding to the given absolute url. - /// - /// Calls to obtain a context instance. - /// - protected IConfigurableApplicationContext GetCheckedApplicationContext(string url) + if (!(appContext is IConfigurableApplicationContext)) { - IApplicationContext appContext = GetContext(url); - if (appContext == null) - { - throw new ArgumentException(string.Format("no application context for virtual path '{0}'", url)); - } - if (!(appContext is IConfigurableApplicationContext)) - { - throw new InvalidOperationException(string.Format("application context '{0}' for virtual path '{1}' must implement IConfigurableApplicationContext", appContext.ToString(), url)); - } - return (IConfigurableApplicationContext)appContext; + throw new InvalidOperationException(string.Format("application context '{0}' for virtual path '{1}' must implement IConfigurableApplicationContext", appContext.ToString(), url)); } - /// - /// Returns the unchecked, raw application context for the given virtual path. - /// - /// the virtual path to get the context for. - /// the context or null. - /// - /// Subclasses may override this method to change the context source. - /// By default, is used for obtaining context instances. - /// - protected virtual IApplicationContext GetContext(string virtualPath) + return (IConfigurableApplicationContext) appContext; + } + + /// + /// Returns the unchecked, raw application context for the given virtual path. + /// + /// the virtual path to get the context for. + /// the context or null. + /// + /// Subclasses may override this method to change the context source. + /// By default, is used for obtaining context instances. + /// + protected virtual IApplicationContext GetContext(string virtualPath) + { + return WebApplicationContext.GetContext(virtualPath); + } + + /// + /// DO NOT USE - this is subject to change! + /// + /// + /// + /// + /// This method requires registrars to follow the convention of registering web object definitions using their + /// application relative urls (~/mypath/mypage.aspx). + /// + /// + /// Resolve an object definition by url. + /// + protected internal static NamedObjectDefinition FindWebObjectDefinition(string appRelativeVirtualPath, IConfigurableListableObjectFactory objectFactory) + { + ILogger Log = LogManager.GetLogger(); + bool isDebug = Log.IsEnabled(LogLevel.Debug); + + // lookup definition using app-relative url + if (isDebug) + Log.LogDebug(string.Format("GetHandler():looking up definition for app-relative url '{0}'", appRelativeVirtualPath)); + string objectDefinitionName = appRelativeVirtualPath; + IObjectDefinition pageDefinition = objectFactory.GetObjectDefinition(appRelativeVirtualPath, true); + + if (pageDefinition == null) { - return WebApplicationContext.GetContext(virtualPath); - } - - /// - /// DO NOT USE - this is subject to change! - /// - /// - /// - /// - /// This method requires registrars to follow the convention of registering web object definitions using their - /// application relative urls (~/mypath/mypage.aspx). - /// - /// - /// Resolve an object definition by url. - /// - protected internal static NamedObjectDefinition FindWebObjectDefinition(string appRelativeVirtualPath, IConfigurableListableObjectFactory objectFactory) - { - ILogger Log = LogManager.GetLogger(); - bool isDebug = Log.IsEnabled(LogLevel.Debug); - - // lookup definition using app-relative url - if (isDebug) - Log.LogDebug(string.Format("GetHandler():looking up definition for app-relative url '{0}'", appRelativeVirtualPath)); - string objectDefinitionName = appRelativeVirtualPath; - IObjectDefinition pageDefinition = objectFactory.GetObjectDefinition(appRelativeVirtualPath, true); - + // try using pagename+extension and pagename only + string pageExtension = Path.GetExtension(appRelativeVirtualPath); + string pageName = WebUtils.GetPageName(appRelativeVirtualPath); + // only looks in the specified object factory -- it will *not* search parent contexts + pageDefinition = objectFactory.GetObjectDefinition(pageName + pageExtension, false); if (pageDefinition == null) { - // try using pagename+extension and pagename only - string pageExtension = Path.GetExtension(appRelativeVirtualPath); - string pageName = WebUtils.GetPageName(appRelativeVirtualPath); - // only looks in the specified object factory -- it will *not* search parent contexts - pageDefinition = objectFactory.GetObjectDefinition(pageName + pageExtension, false); - if (pageDefinition == null) - { - pageDefinition = objectFactory.GetObjectDefinition(pageName, false); - if (pageDefinition != null) - objectDefinitionName = pageName; - } - else - { - objectDefinitionName = pageName + pageExtension; - } - + pageDefinition = objectFactory.GetObjectDefinition(pageName, false); if (pageDefinition != null) - { - if (isDebug) - Log.LogDebug(string.Format("GetHandler():found definition for page-name '{0}'", objectDefinitionName)); - } - else - { - if (isDebug) - Log.LogDebug(string.Format("GetHandler():no definition found for page-name '{0}'", pageName)); - } + objectDefinitionName = pageName; + } + else + { + objectDefinitionName = pageName + pageExtension; + } + + if (pageDefinition != null) + { + if (isDebug) + Log.LogDebug(string.Format("GetHandler():found definition for page-name '{0}'", objectDefinitionName)); } else { if (isDebug) - Log.LogDebug(string.Format("GetHandler():found definition for page-url '{0}'", appRelativeVirtualPath)); + Log.LogDebug(string.Format("GetHandler():no definition found for page-name '{0}'", pageName)); } - - return (pageDefinition == null) ? (NamedObjectDefinition)null : new NamedObjectDefinition(objectDefinitionName, pageDefinition); + } + else + { + if (isDebug) + Log.LogDebug(string.Format("GetHandler():found definition for page-url '{0}'", appRelativeVirtualPath)); } - /// - /// Apply dependency injection stuff on the handler. - /// - /// the handler to be intercepted - /// the context responsible for configuring this handler - private static void ApplyDependencyInjectionInfrastructure(IHttpHandler handler, IApplicationContext applicationContext) + return (pageDefinition == null) ? (NamedObjectDefinition) null : new NamedObjectDefinition(objectDefinitionName, pageDefinition); + } + + /// + /// Apply dependency injection stuff on the handler. + /// + /// the handler to be intercepted + /// the context responsible for configuring this handler + private static void ApplyDependencyInjectionInfrastructure(IHttpHandler handler, IApplicationContext applicationContext) + { + if (handler is Control) { - if (handler is Control) + ControlInterceptor.EnsureControlIntercepted(applicationContext, (Control) handler); + } + else + { + if ((handler is ISupportsWebDependencyInjection) + && (((ISupportsWebDependencyInjection) handler).DefaultApplicationContext == null)) { - ControlInterceptor.EnsureControlIntercepted(applicationContext, (Control)handler); - } - else - { - if ((handler is ISupportsWebDependencyInjection) - && (((ISupportsWebDependencyInjection)handler).DefaultApplicationContext == null)) - { - ((ISupportsWebDependencyInjection)handler).DefaultApplicationContext = applicationContext; - } + ((ISupportsWebDependencyInjection) handler).DefaultApplicationContext = applicationContext; } } } diff --git a/src/Spring/Spring.Web/Web/Support/ContextMonitor.cs b/src/Spring/Spring.Web/Web/Support/ContextMonitor.cs index 8ec04fac..4cc4bdce 100644 --- a/src/Spring/Spring.Web/Web/Support/ContextMonitor.cs +++ b/src/Spring/Spring.Web/Web/Support/ContextMonitor.cs @@ -19,117 +19,115 @@ #endregion using System.Web; - using Spring.Context; using Spring.Context.Support; using Spring.Objects.Factory.Config; using Spring.Objects.Factory.Support; -namespace Spring.Web.Support +namespace Spring.Web.Support; + +/// +/// implementation that allows users to monitor state +/// of the Spring.NET web application context. +/// +/// +///

+/// +///

+///
+/// Aleksandar Seovic +public class ContextMonitor : IHttpHandler { /// - /// implementation that allows users to monitor state - /// of the Spring.NET web application context. + /// Initializes a new instance of the class. /// - /// - ///

- /// - ///

- ///
- /// Aleksandar Seovic - public class ContextMonitor : IHttpHandler + public ContextMonitor() { - /// - /// Initializes a new instance of the class. - /// - public ContextMonitor() - {} - - /// - /// Processes HTTP request. - /// - /// An object that provides references to the intrinsic server objects (for example, , , , and ) used to service HTTP requests. - public void ProcessRequest(HttpContext context) - { - HttpResponse res = context.Response; - res.BufferOutput = true; - - RenderHeader(res.Output, context.Request.ApplicationPath); - - if (!(WebApplicationContext.Current is IConfigurableApplicationContext appContext)) - { - throw new InvalidOperationException( - "Implementations of IApplicationContext must also implement IConfigurableApplicationContext"); - } - - var names = appContext.GetObjectDefinitionNames(); - for (var i = 0; i < names.Count; i++) - { - string name = names[i]; - RenderObjectDefinition(res.Output, name, appContext.ObjectFactory.GetObjectDefinition(name)); - } - - RenderFooter(res.Output); - } - - /// - /// Gets a value indicating whether another request can use - /// this instance. - /// - /// True if this handler is reusable, False otherwise. - public bool IsReusable - { - get { return true; } - } - - private void RenderHeader(TextWriter tw, string contextName) - { - tw.WriteLine(""); - tw.WriteLine(" "); - tw.WriteLine(" Spring.NET Context Monitor - " + contextName + ""); - tw.WriteLine(" "); - tw.WriteLine(" "); - tw.WriteLine(" "); - tw.WriteLine(" "); - RenderHeaderCell(tw, "Name"); - RenderHeaderCell(tw, "Type"); - RenderHeaderCell(tw, "Is Abstract"); - RenderHeaderCell(tw, "Is Singleton"); - RenderHeaderCell(tw, "Is Lazy Init"); - RenderHeaderCell(tw, "Scope"); - RenderHeaderCell(tw, "Page Name"); - tw.WriteLine(" "); - - } - - private void RenderHeaderCell(TextWriter tw, string text) - { - tw.WriteLine(" "); - } - - private void RenderObjectDefinition(TextWriter tw, string name, IObjectDefinition def) - { - tw.WriteLine(" "); - RenderCell(tw, name); - RenderCell(tw, def.ObjectTypeName); - RenderCell(tw, def.IsAbstract); - RenderCell(tw, def.IsSingleton); - RenderCell(tw, def.IsLazyInit); - RenderCell(tw, (def is IWebObjectDefinition ? ((IWebObjectDefinition) def).Scope.ToString() : " ")); - RenderCell(tw, (def is IWebObjectDefinition && ((IWebObjectDefinition) def).IsPage ? ((IWebObjectDefinition) def).PageName : " ")); - tw.WriteLine(" "); - } - - private void RenderCell(TextWriter tw, object value) - { - tw.WriteLine(" "); - } - - private void RenderFooter(TextWriter tw) - { - tw.WriteLine("
" + text + "
" + (value == null ? " " : value.ToString()) + "
"); - tw.WriteLine(" "); - tw.WriteLine(""); - } } -} + + /// + /// Processes HTTP request. + /// + /// An object that provides references to the intrinsic server objects (for example, , , , and ) used to service HTTP requests. + public void ProcessRequest(HttpContext context) + { + HttpResponse res = context.Response; + res.BufferOutput = true; + + RenderHeader(res.Output, context.Request.ApplicationPath); + + if (!(WebApplicationContext.Current is IConfigurableApplicationContext appContext)) + { + throw new InvalidOperationException( + "Implementations of IApplicationContext must also implement IConfigurableApplicationContext"); + } + + var names = appContext.GetObjectDefinitionNames(); + for (var i = 0; i < names.Count; i++) + { + string name = names[i]; + RenderObjectDefinition(res.Output, name, appContext.ObjectFactory.GetObjectDefinition(name)); + } + + RenderFooter(res.Output); + } + + /// + /// Gets a value indicating whether another request can use + /// this instance. + /// + /// True if this handler is reusable, False otherwise. + public bool IsReusable + { + get { return true; } + } + + private void RenderHeader(TextWriter tw, string contextName) + { + tw.WriteLine(""); + tw.WriteLine(" "); + tw.WriteLine(" Spring.NET Context Monitor - " + contextName + ""); + tw.WriteLine(" "); + tw.WriteLine(" "); + tw.WriteLine(" "); + tw.WriteLine(" "); + RenderHeaderCell(tw, "Name"); + RenderHeaderCell(tw, "Type"); + RenderHeaderCell(tw, "Is Abstract"); + RenderHeaderCell(tw, "Is Singleton"); + RenderHeaderCell(tw, "Is Lazy Init"); + RenderHeaderCell(tw, "Scope"); + RenderHeaderCell(tw, "Page Name"); + tw.WriteLine(" "); + } + + private void RenderHeaderCell(TextWriter tw, string text) + { + tw.WriteLine(" "); + } + + private void RenderObjectDefinition(TextWriter tw, string name, IObjectDefinition def) + { + tw.WriteLine(" "); + RenderCell(tw, name); + RenderCell(tw, def.ObjectTypeName); + RenderCell(tw, def.IsAbstract); + RenderCell(tw, def.IsSingleton); + RenderCell(tw, def.IsLazyInit); + RenderCell(tw, (def is IWebObjectDefinition ? ((IWebObjectDefinition) def).Scope.ToString() : " ")); + RenderCell(tw, (def is IWebObjectDefinition && ((IWebObjectDefinition) def).IsPage ? ((IWebObjectDefinition) def).PageName : " ")); + tw.WriteLine(" "); + } + + private void RenderCell(TextWriter tw, object value) + { + tw.WriteLine(" "); + } + + private void RenderFooter(TextWriter tw) + { + tw.WriteLine("
" + text + "
" + (value == null ? " " : value.ToString()) + "
"); + tw.WriteLine(" "); + tw.WriteLine(""); + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Web/Web/Support/ControlAccessor.cs b/src/Spring/Spring.Web/Web/Support/ControlAccessor.cs index 6998f18c..d63db1ae 100644 --- a/src/Spring/Spring.Web/Web/Support/ControlAccessor.cs +++ b/src/Spring/Spring.Web/Web/Support/ControlAccessor.cs @@ -1,4 +1,5 @@ #region License + /* * Copyright � 2002-2011 the original author or authors. * @@ -14,6 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + #endregion #region Imports @@ -29,207 +31,212 @@ using Spring.Util; #endregion -namespace Spring.Web.Support +namespace Spring.Web.Support; + +/// +/// Helper class for easier access to reflected Control members. +/// +/// Erich Eichinger +internal class ControlAccessor { - /// - /// Helper class for easier access to reflected Control members. - /// - /// Erich Eichinger - internal class ControlAccessor + private delegate ControlCollection CreateControlCollectionDelegate(Control target); + + private delegate void AddedControlDelegate(Control target, Control control, int index); + + private delegate void RemovedControlDelegate(Control target, Control control); + + private delegate void VoidMethodDelegate(Control target); + + private static readonly MethodInfo s_miClear; + private static readonly SafeField ControlsArrayField; + + private static readonly CreateControlCollectionDelegate BaseCreateControlCollection; + private static readonly AddedControlDelegate BaseAddedControl; + private static readonly RemovedControlDelegate BaseRemovedControl; + private static readonly VoidMethodDelegate BaseClearNamingContainer; + + static ControlAccessor() { - private delegate ControlCollection CreateControlCollectionDelegate(Control target); - private delegate void AddedControlDelegate(Control target, Control control, int index); - private delegate void RemovedControlDelegate(Control target, Control control); - private delegate void VoidMethodDelegate(Control target); + SafeField fldControls = null; + MethodInfo fnClear = null; - private static readonly MethodInfo s_miClear; - private static readonly SafeField ControlsArrayField; - - private static readonly CreateControlCollectionDelegate BaseCreateControlCollection; - private static readonly AddedControlDelegate BaseAddedControl; - private static readonly RemovedControlDelegate BaseRemovedControl; - private static readonly VoidMethodDelegate BaseClearNamingContainer; - - static ControlAccessor() + SecurityCritical.ExecutePrivileged(new PermissionSet(PermissionState.Unrestricted), delegate { - SafeField fldControls = null; - MethodInfo fnClear = null; + fnClear = GetMethod("Clear"); + fldControls = new SafeField(typeof(ControlCollection).GetField("_controls", BindingFlags.Instance | BindingFlags.NonPublic)); + }); - SecurityCritical.ExecutePrivileged(new PermissionSet(PermissionState.Unrestricted), delegate + s_miClear = fnClear; + ControlsArrayField = fldControls; + + CreateControlCollectionDelegate fnBaseCreateControlCollection = null; + AddedControlDelegate fnBaseAddedControl = null; + RemovedControlDelegate fnBaseRemovedControl = null; + VoidMethodDelegate fnBaseClearNamingContainer = null; + + SecurityCritical.ExecutePrivileged(new PermissionSet(PermissionState.Unrestricted), delegate + { + fnBaseCreateControlCollection = (CreateControlCollectionDelegate) Delegate.CreateDelegate(typeof(CreateControlCollectionDelegate), GetMethod("CreateControlCollection")); + fnBaseAddedControl = (AddedControlDelegate) Delegate.CreateDelegate(typeof(AddedControlDelegate), GetMethod("AddedControl")); + fnBaseRemovedControl = (RemovedControlDelegate) Delegate.CreateDelegate(typeof(RemovedControlDelegate), GetMethod("RemovedControl")); + fnBaseClearNamingContainer = (VoidMethodDelegate) Delegate.CreateDelegate(typeof(VoidMethodDelegate), GetMethod("ClearNamingContainer")); + }); + + BaseCreateControlCollection = fnBaseCreateControlCollection; + BaseAddedControl = fnBaseAddedControl; + BaseRemovedControl = fnBaseRemovedControl; + BaseClearNamingContainer = fnBaseClearNamingContainer; + } + + private static MethodInfo GetMethod(string name) + { + return typeof(Control).GetMethod(name, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); + } + + private static FieldInfo GetField(string name) + { + return typeof(Control).GetField(name, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); + } + + private readonly Control _targetControl; + + /// + /// Instantiates a new Accessor. + /// + /// + public ControlAccessor(Control control) + { + this._targetControl = control; + } + + /// + /// Returns the underlying ControlCollection instance. + /// + public Control GetTarget() + { + return _targetControl; + } + + /// + /// Gets or sets the ControlCollection of the target without accessing the target's property. + /// + /// + /// If the underlying collection is null, it is automatically created. + /// + public ControlCollection Controls + { + get + { + ControlCollection controls = GetChildControlCollection(); + if (controls == null) { - fnClear = GetMethod("Clear"); - fldControls = new SafeField(typeof(ControlCollection).GetField("_controls", BindingFlags.Instance | BindingFlags.NonPublic)); - }); - - s_miClear = fnClear; - ControlsArrayField = fldControls; - - CreateControlCollectionDelegate fnBaseCreateControlCollection = null; - AddedControlDelegate fnBaseAddedControl = null; - RemovedControlDelegate fnBaseRemovedControl = null; - VoidMethodDelegate fnBaseClearNamingContainer = null; - - SecurityCritical.ExecutePrivileged(new PermissionSet(PermissionState.Unrestricted), delegate - { - fnBaseCreateControlCollection = (CreateControlCollectionDelegate)Delegate.CreateDelegate(typeof(CreateControlCollectionDelegate), GetMethod("CreateControlCollection")); - fnBaseAddedControl = (AddedControlDelegate)Delegate.CreateDelegate(typeof(AddedControlDelegate), GetMethod("AddedControl")); - fnBaseRemovedControl = (RemovedControlDelegate)Delegate.CreateDelegate(typeof(RemovedControlDelegate), GetMethod("RemovedControl")); - fnBaseClearNamingContainer = (VoidMethodDelegate)Delegate.CreateDelegate(typeof(VoidMethodDelegate), GetMethod("ClearNamingContainer")); - }); - - BaseCreateControlCollection = fnBaseCreateControlCollection; - BaseAddedControl = fnBaseAddedControl; - BaseRemovedControl = fnBaseRemovedControl; - BaseClearNamingContainer = fnBaseClearNamingContainer; - } - - private static MethodInfo GetMethod(string name) - { - return typeof(Control).GetMethod(name, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); - } - private static FieldInfo GetField(string name) - { - return typeof(Control).GetField(name, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); - } - - - private readonly Control _targetControl; - - /// - /// Instantiates a new Accessor. - /// - /// - public ControlAccessor(Control control) - { - this._targetControl = control; - } - - /// - /// Returns the underlying ControlCollection instance. - /// - public Control GetTarget() - { - return _targetControl; - } - - /// - /// Gets or sets the ControlCollection of the target without accessing the target's property. - /// - /// - /// If the underlying collection is null, it is automatically created. - /// - public ControlCollection Controls - { - get - { - ControlCollection controls = GetChildControlCollection(); + controls = InterceptControlCollectionStrategy.TryCreateCollection(_targetControl); if (controls == null) { - controls = InterceptControlCollectionStrategy.TryCreateCollection(_targetControl); - if (controls == null) - { - controls = BaseCreateControlCollection(_targetControl); - } - SetChildControlCollection(controls); + controls = BaseCreateControlCollection(_targetControl); } - return controls; + + SetChildControlCollection(controls); } - set { SetChildControlCollection(value); } + + return controls; } + set { SetChildControlCollection(value); } + } - public void AddedControl(Control control, int index) + public void AddedControl(Control control, int index) + { + BaseAddedControl(_targetControl, control, index); + } + + public void RemovedControl(Control control) + { + BaseRemovedControl(_targetControl, control); + + if (!_targetControl.HasControls()) { - BaseAddedControl(_targetControl, control, index); - } - - public void RemovedControl(Control control) - { - BaseRemovedControl(_targetControl, control); - - if (!_targetControl.HasControls()) + // clear naming table etc. if collection has been cleared + // this is because we can't intercept Control.ClearNamingTable(), + // which is called by ControlCollection.Clear() after removing all controls + StackFrame frame = new StackFrame(3, false); + if (frame.GetMethod() == s_miClear) { - // clear naming table etc. if collection has been cleared - // this is because we can't intercept Control.ClearNamingTable(), - // which is called by ControlCollection.Clear() after removing all controls - StackFrame frame = new StackFrame(3, false); - if (frame.GetMethod() == s_miClear) + if (_targetControl is INamingContainer) { - if (_targetControl is INamingContainer) - { - //s_miClearNamingContainer.Invoke(_targetControl, null); - BaseClearNamingContainer(_targetControl); - } + //s_miClearNamingContainer.Invoke(_targetControl, null); + BaseClearNamingContainer(_targetControl); } } } - - public void SetControlAt(Control control, int index) - { - Control[] controls = (Control[]) ControlsArrayField.GetValue(this.Controls); - controls[index] = control; - } - - private delegate ControlCollection GetControlsDelegate(Control target); - private delegate void SetControlsDelegate(Control target, ControlCollection controls); - - private static readonly GetControlsDelegate GetChildControlCollectionInternal = GetGetControlsDelegate(); - private static readonly SetControlsDelegate SetChildControlCollectionInternal = GetSetControlsDelegate(); - - private ControlCollection GetChildControlCollection() - { - return GetChildControlCollectionInternal(_targetControl); - } - - private void SetChildControlCollection(ControlCollection controls) - { - SetChildControlCollectionInternal(_targetControl, controls); - } - - private static GetControlsDelegate GetGetControlsDelegate() - { - GetControlsDelegate handler = null; - FieldInfo controls = GetField("_controls"); - - SecurityCritical.ExecutePrivileged(new PermissionSet(PermissionState.Unrestricted), delegate - { - System.Reflection.Emit.DynamicMethod dm = new System.Reflection.Emit.DynamicMethod("get_Controls", typeof(ControlCollection), new Type[] {typeof(Control)}, typeof(Control).Module, true); - ILGenerator il = dm.GetILGenerator(); - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Ldfld, controls); - il.Emit(OpCodes.Ret); - handler = (GetControlsDelegate) dm.CreateDelegate(typeof(GetControlsDelegate)); - }); - return handler; - } - - private static SetControlsDelegate GetSetControlsDelegate() - { - SetControlsDelegate handler = null; - FieldInfo controls = GetField("_controls"); - FieldInfo occasionalFields = GetField("_occasionalFields"); - MethodInfo ensureOccasionalFields = GetMethod("EnsureOccasionalFields"); - - SecurityCritical.ExecutePrivileged(new PermissionSet(PermissionState.Unrestricted), delegate - { - System.Reflection.Emit.DynamicMethod dm = new System.Reflection.Emit.DynamicMethod("set_Controls ", null, new Type[] {typeof(Control), typeof(ControlCollection)}, typeof(Control).Module, true); - ILGenerator il = dm.GetILGenerator(); - Label occFieldsNull = il.DefineLabel(); - Label setControls = il.DefineLabel(); - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Ldfld, occasionalFields); - il.Emit(OpCodes.Brfalse_S, occFieldsNull); - il.MarkLabel(setControls); - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Ldarg_1); - il.Emit(OpCodes.Stfld, controls); - il.Emit(OpCodes.Ret); - il.MarkLabel(occFieldsNull); - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Call, ensureOccasionalFields); - il.Emit(OpCodes.Br, setControls); - handler = (SetControlsDelegate) dm.CreateDelegate(typeof(SetControlsDelegate)); - }); - return handler; - } + } + + public void SetControlAt(Control control, int index) + { + Control[] controls = (Control[]) ControlsArrayField.GetValue(this.Controls); + controls[index] = control; + } + + private delegate ControlCollection GetControlsDelegate(Control target); + + private delegate void SetControlsDelegate(Control target, ControlCollection controls); + + private static readonly GetControlsDelegate GetChildControlCollectionInternal = GetGetControlsDelegate(); + private static readonly SetControlsDelegate SetChildControlCollectionInternal = GetSetControlsDelegate(); + + private ControlCollection GetChildControlCollection() + { + return GetChildControlCollectionInternal(_targetControl); + } + + private void SetChildControlCollection(ControlCollection controls) + { + SetChildControlCollectionInternal(_targetControl, controls); + } + + private static GetControlsDelegate GetGetControlsDelegate() + { + GetControlsDelegate handler = null; + FieldInfo controls = GetField("_controls"); + + SecurityCritical.ExecutePrivileged(new PermissionSet(PermissionState.Unrestricted), delegate + { + System.Reflection.Emit.DynamicMethod dm = new System.Reflection.Emit.DynamicMethod("get_Controls", typeof(ControlCollection), new Type[] { typeof(Control) }, typeof(Control).Module, true); + ILGenerator il = dm.GetILGenerator(); + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldfld, controls); + il.Emit(OpCodes.Ret); + handler = (GetControlsDelegate) dm.CreateDelegate(typeof(GetControlsDelegate)); + }); + return handler; + } + + private static SetControlsDelegate GetSetControlsDelegate() + { + SetControlsDelegate handler = null; + FieldInfo controls = GetField("_controls"); + FieldInfo occasionalFields = GetField("_occasionalFields"); + MethodInfo ensureOccasionalFields = GetMethod("EnsureOccasionalFields"); + + SecurityCritical.ExecutePrivileged(new PermissionSet(PermissionState.Unrestricted), delegate + { + System.Reflection.Emit.DynamicMethod dm = new System.Reflection.Emit.DynamicMethod("set_Controls ", null, new Type[] { typeof(Control), typeof(ControlCollection) }, typeof(Control).Module, true); + ILGenerator il = dm.GetILGenerator(); + Label occFieldsNull = il.DefineLabel(); + Label setControls = il.DefineLabel(); + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldfld, occasionalFields); + il.Emit(OpCodes.Brfalse_S, occFieldsNull); + il.MarkLabel(setControls); + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldarg_1); + il.Emit(OpCodes.Stfld, controls); + il.Emit(OpCodes.Ret); + il.MarkLabel(occFieldsNull); + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Call, ensureOccasionalFields); + il.Emit(OpCodes.Br, setControls); + handler = (SetControlsDelegate) dm.CreateDelegate(typeof(SetControlsDelegate)); + }); + return handler; } } diff --git a/src/Spring/Spring.Web/Web/Support/ControlCollectionAccessor.cs b/src/Spring/Spring.Web/Web/Support/ControlCollectionAccessor.cs index 4377f103..b5e53fab 100644 --- a/src/Spring/Spring.Web/Web/Support/ControlCollectionAccessor.cs +++ b/src/Spring/Spring.Web/Web/Support/ControlCollectionAccessor.cs @@ -1,4 +1,5 @@ #region License + /* * Copyright � 2002-2011 the original author or authors. * @@ -14,6 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + #endregion #region Imports @@ -27,66 +29,66 @@ using Spring.Util; #endregion -namespace Spring.Web.Support -{ - /// - /// Helper class for easier access to reflected ControlCollection members. - /// - /// Erich Eichinger - internal class ControlCollectionAccessor - { - private static readonly IDynamicField _owner; - static ControlCollectionAccessor() - { - IDynamicField owner = null; +namespace Spring.Web.Support; - SecurityCritical.ExecutePrivileged( new PermissionSet(PermissionState.Unrestricted), delegate - { +/// +/// Helper class for easier access to reflected ControlCollection members. +/// +/// Erich Eichinger +internal class ControlCollectionAccessor +{ + private static readonly IDynamicField _owner; + + static ControlCollectionAccessor() + { + IDynamicField owner = null; + + SecurityCritical.ExecutePrivileged(new PermissionSet(PermissionState.Unrestricted), delegate + { #if MONO_2_0 owner = new SafeField(typeof (ControlCollection).GetField("owner", BindingFlags.Instance | BindingFlags.NonPublic)); #else - owner = new SafeField(typeof (ControlCollection).GetField("_owner", BindingFlags.Instance | BindingFlags.NonPublic)); + owner = new SafeField(typeof(ControlCollection).GetField("_owner", BindingFlags.Instance | BindingFlags.NonPublic)); #endif - }); - _owner = owner; - } + }); + _owner = owner; + } - private readonly ControlCollection _controls; - private readonly Type _controlsType; + private readonly ControlCollection _controls; + private readonly Type _controlsType; - /// - /// Returns the underlying ControlCollection instance. - /// - public ControlCollection GetTarget() - { - return _controls; - } + /// + /// Returns the underlying ControlCollection instance. + /// + public ControlCollection GetTarget() + { + return _controls; + } - /// - /// Returns the type of the underlying ControlCollection instance. - /// - public Type GetTargetType() - { - return _controlsType; - } + /// + /// Returns the type of the underlying ControlCollection instance. + /// + public Type GetTargetType() + { + return _controlsType; + } - /// - /// Creates a new Accessor for a given . - /// - /// The to be accessed - public ControlCollectionAccessor(ControlCollection controls) - { - _controls = controls; - _controlsType = controls.GetType(); - } + /// + /// Creates a new Accessor for a given . + /// + /// The to be accessed + public ControlCollectionAccessor(ControlCollection controls) + { + _controls = controls; + _controlsType = controls.GetType(); + } - /// - /// Gets or sets the owner of the underlying ControlCollection. - /// - public Control Owner - { - get { return (Control) _owner.GetValue(_controls); } - set { _owner.SetValue(_controls, value); } - } + /// + /// Gets or sets the owner of the underlying ControlCollection. + /// + public Control Owner + { + get { return (Control) _owner.GetValue(_controls); } + set { _owner.SetValue(_controls, value); } } } diff --git a/src/Spring/Spring.Web/Web/Support/ControlInterceptor.cs b/src/Spring/Spring.Web/Web/Support/ControlInterceptor.cs index 19d64249..ebe5ebab 100644 --- a/src/Spring/Spring.Web/Web/Support/ControlInterceptor.cs +++ b/src/Spring/Spring.Web/Web/Support/ControlInterceptor.cs @@ -1,4 +1,5 @@ #region License + /* * Copyright � 2002-2011 the original author or authors. * @@ -14,6 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + #endregion #region Imports @@ -25,164 +27,162 @@ using Spring.Context; #endregion -namespace Spring.Web.Support +namespace Spring.Web.Support; + +/// +/// Support Class providing a method to ensure a control has been intercepted +/// +/// Erich Eichinger +internal sealed class ControlInterceptor { - /// - /// Support Class providing a method to ensure a control has been intercepted - /// - /// Erich Eichinger - internal sealed class ControlInterceptor + private class NoOpInterceptionStrategy : IInterceptionStrategy { - private class NoOpInterceptionStrategy : IInterceptionStrategy + private static readonly ILogger Log = LogManager.GetLogger(typeof(NoOpInterceptionStrategy)); + + public bool Intercept(IApplicationContext defaultApplicationContext, ControlAccessor ctlAccessor, + ControlCollectionAccessor ctlColAccessor) { - private static readonly ILogger Log = LogManager.GetLogger( typeof( NoOpInterceptionStrategy ) ); - - public bool Intercept( IApplicationContext defaultApplicationContext, ControlAccessor ctlAccessor, - ControlCollectionAccessor ctlColAccessor ) - { - return true; - } - } - - /// - /// Holds all available interception strategies - /// - private static readonly IInterceptionStrategy[] s_availableInterceptionStrategies = new IInterceptionStrategy[] - { - new InterceptControlCollectionStrategy() - , new InterceptControlCollectionOwnerStrategy() - }; - - /// - /// The last resort interception strategy... - /// - private static readonly IInterceptionStrategy s_noopInterceptionStrategy = new NoOpInterceptionStrategy(); - - /// - /// Holds a control.GetType()->IInterceptionStrategy table. - /// - private static readonly Hashtable s_cachedInterceptionStrategies = new Hashtable(); - - /// - /// Holds well-known Type/Strategy mappings. - /// - private static readonly Hashtable s_knownInterceptionStrategies = new Hashtable(); - - static ControlInterceptor() - { - s_knownInterceptionStrategies[typeof( ControlCollection )] = s_availableInterceptionStrategies[1]; - } - - private ControlInterceptor() - { - } - - /// - /// Ensures, a control has been intercepted to support Web-DI. If not, the control will be intercepted. - /// - public static void EnsureControlIntercepted( IApplicationContext defaultApplicationContext, Control control ) - { - if (control is LiteralControl) - { - return; // nothing more to do - } - - // check control itself - if (IsDependencyInjectionAware( defaultApplicationContext, control )) - { - return; // nothing more to do - } - - // check control's ControlCollection - EnsureControlCollectionIntercepted( defaultApplicationContext, control ); - } - - private static void EnsureControlCollectionIntercepted( IApplicationContext defaultApplicationContext, Control control ) - { - // check the collection - ControlAccessor ctlAccessor = new ControlAccessor( control ); - ControlCollection childControls = ctlAccessor.Controls; - if (IsDependencyInjectionAware( defaultApplicationContext, childControls )) - { - return; // nothing more to do - } - - // check, if the collection's owner has already been intercepted - ControlCollectionAccessor ctlColAccessor = new ControlCollectionAccessor( childControls ); - if (IsDependencyInjectionAware( defaultApplicationContext, ctlColAccessor.Owner )) - { - return; // nothing more to do - } - - // lookup strategy in cache - IInterceptionStrategy strategy = null; - lock (s_cachedInterceptionStrategies) - { - strategy = (IInterceptionStrategy)s_cachedInterceptionStrategies[control.GetType()]; - } - - if (strategy != null) - { - strategy.Intercept( defaultApplicationContext, ctlAccessor, ctlColAccessor ); - } - else - { - // nothing in cache - try well-known strategies for owner resp. child collection type - strategy = (IInterceptionStrategy)s_knownInterceptionStrategies[control.GetType()]; - if (strategy == null) - { - strategy = (IInterceptionStrategy)s_knownInterceptionStrategies[childControls.GetType()]; - } - - // try intercept using well-known strategy - if (strategy != null) - { - bool bOk = strategy.Intercept( defaultApplicationContext, ctlAccessor, ctlColAccessor ); - if (!bOk) - { - strategy = null; - } - } - - // not well-known or didn't work out - if (strategy == null) - { - // probe for a strategy - bool bOk = false; - for (int i = 0; i < s_availableInterceptionStrategies.Length; i++) - { - strategy = s_availableInterceptionStrategies[i]; - bOk = strategy.Intercept( defaultApplicationContext, ctlAccessor, ctlColAccessor ); - if (bOk) - break; - } - if (!bOk) - { - LogManager.GetLogger( typeof( ControlInterceptor ) ).LogWarning(string.Format( "dependency injection not supported for control type {0}", ctlAccessor.GetTarget().GetType() )); - strategy = s_noopInterceptionStrategy; - } - } - - lock (s_cachedInterceptionStrategies) - { - s_cachedInterceptionStrategies[control.GetType()] = strategy; - } - } - } - - private static bool IsDependencyInjectionAware( IApplicationContext defaultApplicationContext, object o ) - { - ISupportsWebDependencyInjection diAware = o as ISupportsWebDependencyInjection; - if (diAware != null) - { - // If the ControlCollection is alread DI-aware ensure appContext is set - if (diAware.DefaultApplicationContext == null) - { - diAware.DefaultApplicationContext = defaultApplicationContext; - } - return true; // nothing more to do - } - return false; + return true; } } + + /// + /// Holds all available interception strategies + /// + private static readonly IInterceptionStrategy[] s_availableInterceptionStrategies = new IInterceptionStrategy[] { new InterceptControlCollectionStrategy(), new InterceptControlCollectionOwnerStrategy() }; + + /// + /// The last resort interception strategy... + /// + private static readonly IInterceptionStrategy s_noopInterceptionStrategy = new NoOpInterceptionStrategy(); + + /// + /// Holds a control.GetType()->IInterceptionStrategy table. + /// + private static readonly Hashtable s_cachedInterceptionStrategies = new Hashtable(); + + /// + /// Holds well-known Type/Strategy mappings. + /// + private static readonly Hashtable s_knownInterceptionStrategies = new Hashtable(); + + static ControlInterceptor() + { + s_knownInterceptionStrategies[typeof(ControlCollection)] = s_availableInterceptionStrategies[1]; + } + + private ControlInterceptor() + { + } + + /// + /// Ensures, a control has been intercepted to support Web-DI. If not, the control will be intercepted. + /// + public static void EnsureControlIntercepted(IApplicationContext defaultApplicationContext, Control control) + { + if (control is LiteralControl) + { + return; // nothing more to do + } + + // check control itself + if (IsDependencyInjectionAware(defaultApplicationContext, control)) + { + return; // nothing more to do + } + + // check control's ControlCollection + EnsureControlCollectionIntercepted(defaultApplicationContext, control); + } + + private static void EnsureControlCollectionIntercepted(IApplicationContext defaultApplicationContext, Control control) + { + // check the collection + ControlAccessor ctlAccessor = new ControlAccessor(control); + ControlCollection childControls = ctlAccessor.Controls; + if (IsDependencyInjectionAware(defaultApplicationContext, childControls)) + { + return; // nothing more to do + } + + // check, if the collection's owner has already been intercepted + ControlCollectionAccessor ctlColAccessor = new ControlCollectionAccessor(childControls); + if (IsDependencyInjectionAware(defaultApplicationContext, ctlColAccessor.Owner)) + { + return; // nothing more to do + } + + // lookup strategy in cache + IInterceptionStrategy strategy = null; + lock (s_cachedInterceptionStrategies) + { + strategy = (IInterceptionStrategy) s_cachedInterceptionStrategies[control.GetType()]; + } + + if (strategy != null) + { + strategy.Intercept(defaultApplicationContext, ctlAccessor, ctlColAccessor); + } + else + { + // nothing in cache - try well-known strategies for owner resp. child collection type + strategy = (IInterceptionStrategy) s_knownInterceptionStrategies[control.GetType()]; + if (strategy == null) + { + strategy = (IInterceptionStrategy) s_knownInterceptionStrategies[childControls.GetType()]; + } + + // try intercept using well-known strategy + if (strategy != null) + { + bool bOk = strategy.Intercept(defaultApplicationContext, ctlAccessor, ctlColAccessor); + if (!bOk) + { + strategy = null; + } + } + + // not well-known or didn't work out + if (strategy == null) + { + // probe for a strategy + bool bOk = false; + for (int i = 0; i < s_availableInterceptionStrategies.Length; i++) + { + strategy = s_availableInterceptionStrategies[i]; + bOk = strategy.Intercept(defaultApplicationContext, ctlAccessor, ctlColAccessor); + if (bOk) + break; + } + + if (!bOk) + { + LogManager.GetLogger(typeof(ControlInterceptor)).LogWarning(string.Format("dependency injection not supported for control type {0}", ctlAccessor.GetTarget().GetType())); + strategy = s_noopInterceptionStrategy; + } + } + + lock (s_cachedInterceptionStrategies) + { + s_cachedInterceptionStrategies[control.GetType()] = strategy; + } + } + } + + private static bool IsDependencyInjectionAware(IApplicationContext defaultApplicationContext, object o) + { + ISupportsWebDependencyInjection diAware = o as ISupportsWebDependencyInjection; + if (diAware != null) + { + // If the ControlCollection is alread DI-aware ensure appContext is set + if (diAware.DefaultApplicationContext == null) + { + diAware.DefaultApplicationContext = defaultApplicationContext; + } + + return true; // nothing more to do + } + + return false; + } } diff --git a/src/Spring/Spring.Web/Web/Support/DefaultHandlerFactory.cs b/src/Spring/Spring.Web/Web/Support/DefaultHandlerFactory.cs index eb92a80b..bcb9e011 100644 --- a/src/Spring/Spring.Web/Web/Support/DefaultHandlerFactory.cs +++ b/src/Spring/Spring.Web/Web/Support/DefaultHandlerFactory.cs @@ -27,84 +27,83 @@ using Spring.Util; #endregion -namespace Spring.Web.Support +namespace Spring.Web.Support; +#if !MONO +/// +/// SimpleHandlerFactory is used to wrap any arbitrary to make it "Spring-aware". +/// +/// +/// By default, an instance of is used as underlying factory. +/// +/// Erich Eichinger +#endif +public class DefaultHandlerFactory : AbstractHandlerFactory { + private readonly IHttpHandlerFactory _innerFactory; #if !MONO /// - /// SimpleHandlerFactory is used to wrap any arbitrary to make it "Spring-aware". + /// Creates a new instance, using a as underlying factory. /// - /// - /// By default, an instance of is used as underlying factory. - /// - /// Erich Eichinger -#endif - public class DefaultHandlerFactory : AbstractHandlerFactory - { - private readonly IHttpHandlerFactory _innerFactory; -#if !MONO - /// - /// Creates a new instance, using a as underlying factory. - /// #else /// /// Creates a new instance of the DefaultHandlerFactory /// #endif - public DefaultHandlerFactory() - : this(SimpleHandlerFactory) - { } + public DefaultHandlerFactory() + : this(SimpleHandlerFactory) + { + } - /// - /// Create a new instance, using an instance of as underlying factory. - /// - /// a type that implements - public DefaultHandlerFactory(Type innerFactoryType) - : this((IHttpHandlerFactory)Activator.CreateInstance(innerFactoryType, true)) - { - } + /// + /// Create a new instance, using an instance of as underlying factory. + /// + /// a type that implements + public DefaultHandlerFactory(Type innerFactoryType) + : this((IHttpHandlerFactory) Activator.CreateInstance(innerFactoryType, true)) + { + } - /// - /// Create a new instance, using as underlying factory. - /// - /// the factory to be wrapped. - public DefaultHandlerFactory(IHttpHandlerFactory innerFactory) - { - AssertUtils.ArgumentNotNull(innerFactory, "innerFactory"); - _innerFactory = innerFactory; - } + /// + /// Create a new instance, using as underlying factory. + /// + /// the factory to be wrapped. + public DefaultHandlerFactory(IHttpHandlerFactory innerFactory) + { + AssertUtils.ArgumentNotNull(innerFactory, "innerFactory"); + _innerFactory = innerFactory; + } - /// - /// Create a handler instance for the given URL. - /// - /// the application context corresponding to the current request - /// The instance for this request. - /// The HTTP data transfer method (GET, POST, ...) - /// The requested . - /// The physical path of the requested resource. - /// A handler instance for processing the current request. - protected override IHttpHandler CreateHandlerInstance(IConfigurableApplicationContext appContext, HttpContext context, string requestType, string rawUrl, string physicalPath) - { - IHttpHandler handler = _innerFactory.GetHandler(context, requestType, rawUrl, physicalPath); + /// + /// Create a handler instance for the given URL. + /// + /// the application context corresponding to the current request + /// The instance for this request. + /// The HTTP data transfer method (GET, POST, ...) + /// The requested . + /// The physical path of the requested resource. + /// A handler instance for processing the current request. + protected override IHttpHandler CreateHandlerInstance(IConfigurableApplicationContext appContext, HttpContext context, string requestType, string rawUrl, string physicalPath) + { + IHttpHandler handler = _innerFactory.GetHandler(context, requestType, rawUrl, physicalPath); - // find a matching object definition - string appRelativeVirtualPath = WebUtils.GetAppRelativePath(rawUrl); - NamedObjectDefinition nod = FindWebObjectDefinition(appRelativeVirtualPath, appContext.ObjectFactory); - string objectDefinitionName = (nod != null) ? nod.Name : rawUrl; + // find a matching object definition + string appRelativeVirtualPath = WebUtils.GetAppRelativePath(rawUrl); + NamedObjectDefinition nod = FindWebObjectDefinition(appRelativeVirtualPath, appContext.ObjectFactory); + string objectDefinitionName = (nod != null) ? nod.Name : rawUrl; - handler = WebSupportModule.ConfigureHandler(context, handler, appContext, objectDefinitionName, (nod != null)); - return handler; - } + handler = WebSupportModule.ConfigureHandler(context, handler, appContext, objectDefinitionName, (nod != null)); + return handler; + } - /// - /// Enables a factory to release an existing - /// instance. - /// - /// - /// The object to release. - /// - public override void ReleaseHandler(IHttpHandler handler) - { - _innerFactory.ReleaseHandler(handler); - } + /// + /// Enables a factory to release an existing + /// instance. + /// + /// + /// The object to release. + /// + public override void ReleaseHandler(IHttpHandler handler) + { + _innerFactory.ReleaseHandler(handler); } } diff --git a/src/Spring/Spring.Web/Web/Support/DefaultResultFactory.cs b/src/Spring/Spring.Web/Web/Support/DefaultResultFactory.cs index 1094bbc0..53990c5d 100644 --- a/src/Spring/Spring.Web/Web/Support/DefaultResultFactory.cs +++ b/src/Spring/Spring.Web/Web/Support/DefaultResultFactory.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -22,30 +22,29 @@ #endregion -namespace Spring.Web.Support +namespace Spring.Web.Support; + +/// +/// This result factory implementation creates instances from a given string representation. +/// +/// +/// For a larger example illustrating the customization of result processing, . +/// +/// +/// +/// +/// +/// Erich Eichinger +public class DefaultResultFactory : IResultFactory { /// - /// This result factory implementation creates instances from a given string representation. + /// Create a new from the specified . /// - /// - /// For a larger example illustrating the customization of result processing, . - /// - /// - /// - /// - /// - /// Erich Eichinger - public class DefaultResultFactory : IResultFactory + /// the result mode. + /// the string representation of the result. + /// the instance created from . + public IResult CreateResult(string resultMode, string resultText) { - /// - /// Create a new from the specified . - /// - /// the result mode. - /// the string representation of the result. - /// the instance created from . - public IResult CreateResult(string resultMode, string resultText) - { - return new Result(resultMode, resultText); - } + return new Result(resultMode, resultText); } } \ No newline at end of file diff --git a/src/Spring/Spring.Web/Web/Support/DefaultResultWebNavigator.cs b/src/Spring/Spring.Web/Web/Support/DefaultResultWebNavigator.cs index a7c43bfa..9566ff8d 100644 --- a/src/Spring/Spring.Web/Web/Support/DefaultResultWebNavigator.cs +++ b/src/Spring/Spring.Web/Web/Support/DefaultResultWebNavigator.cs @@ -26,226 +26,233 @@ using Spring.Core; #endregion -namespace Spring.Web.Support +namespace Spring.Web.Support; + +/// +/// The default implementation of the interface. +/// +public class DefaultResultWebNavigator : IResultWebNavigator { + private IWebNavigator _parentNavigator; + private bool _ignoreCase; + private IDictionary _results; + /// - /// The default implementation of the interface. + /// Indicates, whether result names are treated case sensitive by this navigator. /// - public class DefaultResultWebNavigator : IResultWebNavigator + public bool IsCaseSensitive { - private IWebNavigator _parentNavigator; - private bool _ignoreCase; - private IDictionary _results; + get { return !_ignoreCase; } + } - /// - /// Indicates, whether result names are treated case sensitive by this navigator. - /// - public bool IsCaseSensitive + /// + /// Get/Set the parent of this navigator. + /// + /// if this navigator already has a parent. + public virtual IWebNavigator ParentNavigator + { + get { return _parentNavigator; } + set { - get { return !_ignoreCase; } - } - - /// - /// Get/Set the parent of this navigator. - /// - /// if this navigator already has a parent. - public virtual IWebNavigator ParentNavigator - { - get { return _parentNavigator; } - set + if (_parentNavigator != null) { - if (_parentNavigator != null) - { - throw new InvalidOperationException("Can't set parent navigator because this navigator already has a parent"); - } - _parentNavigator = value; + throw new InvalidOperationException("Can't set parent navigator because this navigator already has a parent"); + } + + _parentNavigator = value; + } + } + + /// + /// Gets or sets map of result names to instances or their textual representations. + /// See for information on parsing textual representations. + /// + /// + /// + /// + /// + public IDictionary Results + { + get + { + return _results; + } + set + { + _results = CreateResultsDictionary(value); + } + } + + /// + /// Creates and initializes a new instance. + /// + public DefaultResultWebNavigator() + : this(null, null, true) + { + } + + /// + /// Creates and initializes a new instance. + /// + /// the parent of this instance. May be null. + /// a dictionary of result name to result mappings. May be null. + /// sets, how this navigator treats case sensitivity of result names + public DefaultResultWebNavigator(IWebNavigator parent, IDictionary initialResults, bool ignoreCase) + { + this._parentNavigator = parent; + this._ignoreCase = ignoreCase; + this._results = CreateResultsDictionary(initialResults); + } + + /// + /// Create the dictionary instance to be used by this navigator component. + /// + /// a dictionary of intitial result mappings + /// the dictionary, that will be used by this navigator. + /// + /// Implementors may override this for creating custom dictionaries. + /// + protected virtual IDictionary CreateResultsDictionary(IDictionary initialResults) + { + IDictionary newResults = (_ignoreCase) ? new CaseInsensitiveHashtable() : new Hashtable(); + if (initialResults != null) + { + foreach (DictionaryEntry entry in initialResults) + { + newResults[entry.Key.ToString()] = entry.Value; } } - /// - /// Gets or sets map of result names to instances or their textual representations. - /// See for information on parsing textual representations. - /// - /// - /// - /// - /// - public IDictionary Results + return newResults; + } + + /// + /// Determines, whether this navigator or one of its parents can + /// navigate to the destination specified in . + /// + /// the name of the navigation destination + /// true, if this navigator can navigate to the destination. + public virtual bool CanNavigateTo(string destination) + { + if (_results.Contains(destination)) { - get - { - return _results; - } - set - { - _results = CreateResultsDictionary( value ); - } + return true; } - /// - /// Creates and initializes a new instance. - /// - public DefaultResultWebNavigator() - : this( null, null, true ) - { } + return (ParentNavigator != null) ? ParentNavigator.CanNavigateTo(destination) : false; + } - /// - /// Creates and initializes a new instance. - /// - /// the parent of this instance. May be null. - /// a dictionary of result name to result mappings. May be null. - /// sets, how this navigator treats case sensitivity of result names - public DefaultResultWebNavigator( IWebNavigator parent, IDictionary initialResults, bool ignoreCase ) + /// + /// Redirects user to a URL mapped to specified result name. + /// + /// Name of the result. + /// the instance that issued this request + /// The context to use for evaluating the SpEL expression in the Result. + public virtual void NavigateTo(string destination, object sender, object context) + { + IResult result = GetResult(destination); + if (result == null) { - this._parentNavigator = parent; - this._ignoreCase = ignoreCase; - this._results = CreateResultsDictionary( initialResults ); - } - - /// - /// Create the dictionary instance to be used by this navigator component. - /// - /// a dictionary of intitial result mappings - /// the dictionary, that will be used by this navigator. - /// - /// Implementors may override this for creating custom dictionaries. - /// - protected virtual IDictionary CreateResultsDictionary( IDictionary initialResults ) - { - IDictionary newResults = (_ignoreCase) ? new CaseInsensitiveHashtable() : new Hashtable(); - if (initialResults != null) + if (ParentNavigator != null) { - foreach (DictionaryEntry entry in initialResults) - { - newResults[entry.Key.ToString()] = entry.Value; - } - } - return newResults; - } - - /// - /// Determines, whether this navigator or one of its parents can - /// navigate to the destination specified in . - /// - /// the name of the navigation destination - /// true, if this navigator can navigate to the destination. - public virtual bool CanNavigateTo( string destination ) - { - if (_results.Contains( destination )) - { - return true; - } - return (ParentNavigator != null) ? ParentNavigator.CanNavigateTo( destination ) : false; - } - - /// - /// Redirects user to a URL mapped to specified result name. - /// - /// Name of the result. - /// the instance that issued this request - /// The context to use for evaluating the SpEL expression in the Result. - public virtual void NavigateTo( string destination, object sender, object context ) - { - IResult result = GetResult( destination ); - if (result == null) - { - if (ParentNavigator != null) - { - ParentNavigator.NavigateTo( destination, sender, context ); - return; - } - HandleUnknownDestination(destination, sender, context); + ParentNavigator.NavigateTo(destination, sender, context); return; } - // If no context, 'sender' is context - if (context == null) - { - context = sender; - } - result.Navigate( context ); + HandleUnknownDestination(destination, sender, context); + return; } - /// - /// Returns a redirect url string that points to the - /// defined by this - /// result evaluated using this Page for expression - /// - /// Name of the result. - /// the instance that issued this request - /// The context to use for evaluating the SpEL expression in the Result - /// A redirect url string. - public virtual string GetResultUri( string resultName, object sender, object context ) + // If no context, 'sender' is context + if (context == null) { - IResult result = GetResult( resultName ); - if (result == null) - { - if (ParentNavigator != null) - { - return result.GetRedirectUri( context ); - } - return HandleUnknownDestination( resultName, sender, context ); - } - - // If no context, 'sender' is context - if (context == null) - { - context = sender; - } - return result.GetRedirectUri( context ); + context = sender; } - /// - /// Obtain the named result instance from the dictionary. If necessary, the actual representation of the result - /// will be converted to an instance by this method. - /// - /// - /// - protected IResult GetResult( string name ) + result.Navigate(context); + } + + /// + /// Returns a redirect url string that points to the + /// defined by this + /// result evaluated using this Page for expression + /// + /// Name of the result. + /// the instance that issued this request + /// The context to use for evaluating the SpEL expression in the Result + /// A redirect url string. + public virtual string GetResultUri(string resultName, object sender, object context) + { + IResult result = GetResult(resultName); + if (result == null) { - object val = _results[name]; - if (val == null) + if (ParentNavigator != null) { - return null; - } - else if (val is IResult) - { - return (IResult)val; - } - else if (val is String) - { - return ResultFactoryRegistry.CreateResult( (string)val ); + return result.GetRedirectUri(context); } - return HandleUnknownResultType(name, val); + return HandleUnknownDestination(resultName, sender, context); } - /// - /// Handle an unknown result object. - /// - /// the name of the result - /// the result instance obtained from the dictionary - /// - /// By default, this method throws a . - /// - protected virtual IResult HandleUnknownResultType(string name, object val) + // If no context, 'sender' is context + if (context == null) { - throw new TypeMismatchException("Unable to create result object. Please use either String or Result instances to define results." ); + context = sender; } - /// - /// Handle an unknown destination. - /// - /// the destination that could not be resolved. - /// the sender that issued the request - /// the context to be used for evaluating any dynamic parts of the destination - /// the uri as being returned from - /// - /// By default, this method throws a . - /// - protected virtual string HandleUnknownDestination( string destination, object sender, object context ) + return result.GetRedirectUri(context); + } + + /// + /// Obtain the named result instance from the dictionary. If necessary, the actual representation of the result + /// will be converted to an instance by this method. + /// + /// + /// + protected IResult GetResult(string name) + { + object val = _results[name]; + if (val == null) { - throw new ArgumentOutOfRangeException( "destination", string.Format( "No mapping found for the specified destination '{0}'.", destination ) ); + return null; } + else if (val is IResult) + { + return (IResult) val; + } + else if (val is String) + { + return ResultFactoryRegistry.CreateResult((string) val); + } + + return HandleUnknownResultType(name, val); + } + + /// + /// Handle an unknown result object. + /// + /// the name of the result + /// the result instance obtained from the dictionary + /// + /// By default, this method throws a . + /// + protected virtual IResult HandleUnknownResultType(string name, object val) + { + throw new TypeMismatchException("Unable to create result object. Please use either String or Result instances to define results."); + } + + /// + /// Handle an unknown destination. + /// + /// the destination that could not be resolved. + /// the sender that issued the request + /// the context to be used for evaluating any dynamic parts of the destination + /// the uri as being returned from + /// + /// By default, this method throws a . + /// + protected virtual string HandleUnknownDestination(string destination, object sender, object context) + { + throw new ArgumentOutOfRangeException("destination", string.Format("No mapping found for the specified destination '{0}'.", destination)); } } diff --git a/src/Spring/Spring.Web/Web/Support/HandlerMap.cs b/src/Spring/Spring.Web/Web/Support/HandlerMap.cs index b10b4ff9..69228d8c 100644 --- a/src/Spring/Spring.Web/Web/Support/HandlerMap.cs +++ b/src/Spring/Spring.Web/Web/Support/HandlerMap.cs @@ -27,211 +27,210 @@ using Microsoft.Extensions.Logging; #endregion -namespace Spring.Web.Support +namespace Spring.Web.Support; + +/// +/// Holds a list of url expressions and their corresponding names of responsible +/// or objects managed by the container. +/// +/// Erich Eichinger +public class HandlerMap : IDictionary { + private readonly ILogger Log = LogManager.GetLogger(); + + private ArrayList _internalTable = new ArrayList(); + /// - /// Holds a list of url expressions and their corresponding names of responsible - /// or objects managed by the container. + /// Maps the specified url pattern expression to an object name denoting a or object. /// - /// Erich Eichinger - public class HandlerMap : IDictionary - { - private readonly ILogger Log = LogManager.GetLogger(); + /// the string pattern (see conform to syntax) + /// an object name denoting the spring-managed handler definition + public void Add(string urlPattern, string handlerObjectName) + { + this._internalTable.Add(new HandlerMapEntry(urlPattern, handlerObjectName)); + } - private ArrayList _internalTable = new ArrayList(); + /// + /// Maps the specified url pattern expression to an object name denoting a or object. + /// + /// the url pattern + /// an object name denoting the spring-managed handler definition + public void Add(Regex urlPattern, string handlerObjectName) + { + this._internalTable.Add(new HandlerMapEntry(urlPattern, handlerObjectName)); + } - /// - /// Maps the specified url pattern expression to an object name denoting a or object. - /// - /// the string pattern (see conform to syntax) - /// an object name denoting the spring-managed handler definition - public void Add(string urlPattern, string handlerObjectName) - { - this._internalTable.Add( new HandlerMapEntry(urlPattern, handlerObjectName) ); - } + /// + /// Maps the to a handler object name by matching against all registered patterns. + /// + /// the virtual path + /// the object name + public HandlerMapEntry MapPath(string virtualPath) + { + if (Log.IsEnabled(LogLevel.Debug)) Log.LogDebug(string.Format("looking up mapping for url '{0}'", virtualPath)); + for (int i = 0; i < this._internalTable.Count; i++) + { + HandlerMapEntry handlerMapEntry = (HandlerMapEntry) this._internalTable[i]; + if (handlerMapEntry.UrlPattern.IsMatch(virtualPath)) + { + if (Log.IsEnabled(LogLevel.Debug)) Log.LogDebug(string.Format("found mapping '{0}' for url '{1}'", handlerMapEntry, virtualPath)); + return handlerMapEntry; + } + } - /// - /// Maps the specified url pattern expression to an object name denoting a or object. - /// - /// the url pattern - /// an object name denoting the spring-managed handler definition - public void Add(Regex urlPattern, string handlerObjectName) - { - this._internalTable.Add( new HandlerMapEntry(urlPattern, handlerObjectName) ); - } + if (Log.IsEnabled(LogLevel.Debug)) Log.LogDebug(string.Format("no mapping found for url '{0}'", virtualPath)); + return null; + } - /// - /// Maps the to a handler object name by matching against all registered patterns. - /// - /// the virtual path - /// the object name - public HandlerMapEntry MapPath( string virtualPath ) - { - if(Log.IsEnabled(LogLevel.Debug)) Log.LogDebug(string.Format( "looking up mapping for url '{0}'", virtualPath )); - for(int i=0;i + /// Add a new mapping + ///
+ /// an url pattern string + /// a handler object name string + void IDictionary.Add(object key, object value) + { + this.Add((string) key, (string) value); + } - if (Log.IsEnabled(LogLevel.Debug)) Log.LogDebug(string.Format("no mapping found for url '{0}'", virtualPath)); - return null; - } + /// + /// Add or replace a mapping + /// + /// + /// Getter will throw a ! + /// + /// an url pattern string + object IDictionary.this[object key] + { + get + { + throw new NotSupportedException(); + } + set + { + this.Add((string) key, (string) value); + } + } - /// - /// Add a new mapping - /// - /// an url pattern string - /// a handler object name string - void IDictionary.Add(object key, object value) - { - this.Add((string) key, (string) value); - } + /// + /// Clear the mapping table. + /// + public void Clear() + { + this._internalTable.Clear(); + } - /// - /// Add or replace a mapping - /// - /// - /// Getter will throw a ! - /// - /// an url pattern string - object IDictionary.this[object key] - { - get - { - throw new NotSupportedException(); - } - set - { - this.Add( (string)key,(string)value ); - } - } + /// + /// Always returns false. + /// + public bool IsReadOnly + { + get + { + return false; + // return this._internalTable.IsReadOnly; + } + } - /// - /// Clear the mapping table. - /// - public void Clear() - { - this._internalTable.Clear(); - } + /// + ///Gets a value indicating whether the object has a fixed size. + /// + /// + /// + ///true if the object has a fixed size; otherwise, false. + /// + ///2 + public bool IsFixedSize + { + get { return false; /*return this._internalTable.IsFixedSize;*/ } + } - /// - /// Always returns false. - /// - public bool IsReadOnly - { - get - { - return false; - // return this._internalTable.IsReadOnly; - } - } + /// + ///Copies all entries to the specified array. + /// + public void CopyTo(Array array, int index) + { + this._internalTable.CopyTo(array, index); + } - /// - ///Gets a value indicating whether the object has a fixed size. - /// - /// - /// - ///true if the object has a fixed size; otherwise, false. - /// - ///2 - public bool IsFixedSize - { - get { return false; /*return this._internalTable.IsFixedSize;*/ } - } + /// + /// Get the number of registered mappings. + /// + public int Count + { + get { return this._internalTable.Count; } + } - /// - ///Copies all entries to the specified array. - /// - public void CopyTo(Array array, int index) - { - this._internalTable.CopyTo(array, index); - } + /// + ///Gets an object that can be used to synchronize access. + /// + public object SyncRoot + { + get { return this._internalTable.SyncRoot; } + } - /// - /// Get the number of registered mappings. - /// - public int Count - { - get { return this._internalTable.Count; } - } + /// + /// Always returns false. + /// + public bool IsSynchronized + { + get { return false; /*return this._internalTable.IsSynchronized;*/ } + } - /// - ///Gets an object that can be used to synchronize access. - /// - public object SyncRoot - { - get { return this._internalTable.SyncRoot; } - } + /// + /// Get an enumerator for iterating over the list of registered mappings. + /// + IEnumerator IEnumerable.GetEnumerator() + { + return ((IEnumerable) this._internalTable).GetEnumerator(); + } - /// - /// Always returns false. - /// - public bool IsSynchronized - { - get { return false; /*return this._internalTable.IsSynchronized;*/ } - } + #region Unsupported methods - /// - /// Get an enumerator for iterating over the list of registered mappings. - /// - IEnumerator IEnumerable.GetEnumerator() - { - return ((IEnumerable) this._internalTable).GetEnumerator(); - } + /// + /// Not supported by this implementation. + /// + bool IDictionary.Contains(object key) + { + throw new NotSupportedException(); + } - #region Unsupported methods + /// + /// Not supported by this implementation. + /// + IDictionaryEnumerator IDictionary.GetEnumerator() + { + throw new NotSupportedException(); + } - /// - /// Not supported by this implementation. - /// - bool IDictionary.Contains(object key) - { - throw new NotSupportedException(); - } + /// + /// Not supported by this implementation. + /// + void IDictionary.Remove(object key) + { + throw new NotSupportedException(); + } - /// - /// Not supported by this implementation. - /// - IDictionaryEnumerator IDictionary.GetEnumerator() - { - throw new NotSupportedException(); - } + /// + /// Not supported by this implementation. + /// + ICollection IDictionary.Keys + { + get + { + throw new NotSupportedException(); + } + } - /// - /// Not supported by this implementation. - /// - void IDictionary.Remove(object key) - { - throw new NotSupportedException(); - } + /// + /// Not supported by this implementation. + /// + ICollection IDictionary.Values + { + get + { + throw new NotSupportedException(); + } + } - /// - /// Not supported by this implementation. - /// - ICollection IDictionary.Keys - { - get - { - throw new NotSupportedException(); - } - } - - /// - /// Not supported by this implementation. - /// - ICollection IDictionary.Values - { - get - { - throw new NotSupportedException(); - } - } - - #endregion - } + #endregion } diff --git a/src/Spring/Spring.Web/Web/Support/HandlerMapEntry.cs b/src/Spring/Spring.Web/Web/Support/HandlerMapEntry.cs index 3e5e879f..86c75443 100644 --- a/src/Spring/Spring.Web/Web/Support/HandlerMapEntry.cs +++ b/src/Spring/Spring.Web/Web/Support/HandlerMapEntry.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -25,68 +25,67 @@ using Spring.Util; #endregion -namespace Spring.Web.Support +namespace Spring.Web.Support; + +/// +/// Holds pairs of (url pattern, handler object name). +/// +/// +/// +/// +/// Erich Eichinger +public class HandlerMapEntry { + private Regex _urlPattern; + private string _handlerObjectName; + /// - /// Holds pairs of (url pattern, handler object name). + /// Create a new instance. /// - /// - /// - /// - /// Erich Eichinger - public class HandlerMapEntry - { - private Regex _urlPattern; - private string _handlerObjectName; + /// + /// + public HandlerMapEntry(string urlPattern, string handlerObjectName) + { + AssertUtils.ArgumentNotNull(urlPattern, "urlPattern"); + AssertUtils.ArgumentNotNull(handlerObjectName, "handlerObjectName"); + this._urlPattern = new Regex(urlPattern, RegexOptions.Compiled | RegexOptions.ECMAScript | RegexOptions.CultureInvariant | RegexOptions.IgnoreCase); + this._handlerObjectName = handlerObjectName; + } - /// - /// Create a new instance. - /// - /// - /// - public HandlerMapEntry(string urlPattern, string handlerObjectName) - { - AssertUtils.ArgumentNotNull(urlPattern, "urlPattern"); - AssertUtils.ArgumentNotNull(handlerObjectName, "handlerObjectName"); - this._urlPattern = new Regex(urlPattern, RegexOptions.Compiled|RegexOptions.ECMAScript|RegexOptions.CultureInvariant|RegexOptions.IgnoreCase); - this._handlerObjectName = handlerObjectName; - } + /// + /// Create a new instance + /// + /// + /// + public HandlerMapEntry(Regex urlPattern, string handlerObjectName) + { + AssertUtils.ArgumentNotNull(urlPattern, "urlPattern"); + AssertUtils.ArgumentNotNull(handlerObjectName, "handlerObjectName"); + this._urlPattern = urlPattern; + this._handlerObjectName = handlerObjectName; + } - /// - /// Create a new instance - /// - /// - /// - public HandlerMapEntry(Regex urlPattern, string handlerObjectName) - { - AssertUtils.ArgumentNotNull(urlPattern, "urlPattern"); - AssertUtils.ArgumentNotNull(handlerObjectName, "handlerObjectName"); - this._urlPattern = urlPattern; - this._handlerObjectName = handlerObjectName; - } + /// + /// Get the url pattern + /// + public Regex UrlPattern + { + get { return this._urlPattern; } + } - /// - /// Get the url pattern - /// - public Regex UrlPattern - { - get { return this._urlPattern; } - } + /// + /// Get the handler object name + /// + public string HandlerObjectName + { + get { return this._handlerObjectName; } + } - /// - /// Get the handler object name - /// - public string HandlerObjectName - { - get { return this._handlerObjectName; } - } - - /// - /// Return a string representation of this entry. - /// - public override string ToString() - { - return string.Format("HandlerMapEntry['{0}','{1}']", _urlPattern, _handlerObjectName); - } - } -} \ No newline at end of file + /// + /// Return a string representation of this entry. + /// + public override string ToString() + { + return string.Format("HandlerMapEntry['{0}','{1}']", _urlPattern, _handlerObjectName); + } +} diff --git a/src/Spring/Spring.Web/Web/Support/IHierarchicalWebNavigator.cs b/src/Spring/Spring.Web/Web/Support/IHierarchicalWebNavigator.cs index ff2817ea..e9ac84d1 100644 --- a/src/Spring/Spring.Web/Web/Support/IHierarchicalWebNavigator.cs +++ b/src/Spring/Spring.Web/Web/Support/IHierarchicalWebNavigator.cs @@ -22,18 +22,17 @@ #endregion -namespace Spring.Web.Support +namespace Spring.Web.Support; + +/// +/// An extension of that must be implemented by +/// navigators that can be part of a hierarchy. +/// +/// Erich Eichinger +public interface IHierarchicalWebNavigator : IWebNavigator { /// - /// An extension of that must be implemented by - /// navigators that can be part of a hierarchy. + /// If any, get the parent navigator of the current navigator instance. May be null. /// - /// Erich Eichinger - public interface IHierarchicalWebNavigator : IWebNavigator - { - /// - /// If any, get the parent navigator of the current navigator instance. May be null. - /// - IWebNavigator ParentNavigator { get; } - } + IWebNavigator ParentNavigator { get; } } \ No newline at end of file diff --git a/src/Spring/Spring.Web/Web/Support/IInterceptionStrategy.cs b/src/Spring/Spring.Web/Web/Support/IInterceptionStrategy.cs index b9ee6d06..b77ee678 100644 --- a/src/Spring/Spring.Web/Web/Support/IInterceptionStrategy.cs +++ b/src/Spring/Spring.Web/Web/Support/IInterceptionStrategy.cs @@ -1,6 +1,7 @@ #region License + /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -14,6 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + #endregion #region Imports @@ -22,22 +24,21 @@ using Spring.Context; #endregion -namespace Spring.Web.Support +namespace Spring.Web.Support; + +/// +/// Any concrete interception strategy must implement this interface +/// +/// Erich Eichinger +internal interface IInterceptionStrategy { /// - /// Any concrete interception strategy must implement this interface + /// Any implementation must never throw an exception from this method. + /// Instead false must be returned to indicate interception failure. /// - /// Erich Eichinger - internal interface IInterceptionStrategy - { - /// - /// Any implementation must never throw an exception from this method. - /// Instead false must be returned to indicate interception failure. - /// - /// - /// true, if interception succeeded. false otherwise. - /// - bool Intercept(IApplicationContext defaultApplicationContext, - ControlAccessor ctlAccessor, ControlCollectionAccessor ctlColAccessor); - } + /// + /// true, if interception succeeded. false otherwise. + /// + bool Intercept(IApplicationContext defaultApplicationContext, + ControlAccessor ctlAccessor, ControlCollectionAccessor ctlColAccessor); } \ No newline at end of file diff --git a/src/Spring/Spring.Web/Web/Support/IResult.cs b/src/Spring/Spring.Web/Web/Support/IResult.cs index b08f137a..c192003b 100644 --- a/src/Spring/Spring.Web/Web/Support/IResult.cs +++ b/src/Spring/Spring.Web/Web/Support/IResult.cs @@ -25,40 +25,40 @@ using Spring.Web.UI; #endregion -namespace Spring.Web.Support +namespace Spring.Web.Support; + +/// +/// An encapsulates concrete navigation logic. Usually executing a +/// result will invoke or . +/// +/// +/// For a larger example illustrating the customization of result processing . +/// +/// +/// +/// +/// +/// +/// +/// Erich Eichinger +public interface IResult { /// - /// An encapsulates concrete navigation logic. Usually executing a - /// result will invoke or . + /// Execute the result logic within the given . /// + /// the context to evaluate this request in. + void Navigate(object context); + + /// + /// Returns an url representation of the result logic within the given . + /// + /// the context to evaluate this request in. + /// the url corresponding to the result instance. /// - /// For a larger example illustrating the customization of result processing . + /// The returned url is not necessarily fully qualified nor absolute. Returned urls may be relative to the + /// given context.
+ /// To produce a client-usable url, consider applying e.g. or + /// before writing the result url to the response. ///
- /// - /// - /// - /// - /// - /// - /// Erich Eichinger - public interface IResult - { - /// - /// Execute the result logic within the given . - /// - /// the context to evaluate this request in. - void Navigate( object context ); - /// - /// Returns an url representation of the result logic within the given . - /// - /// the context to evaluate this request in. - /// the url corresponding to the result instance. - /// - /// The returned url is not necessarily fully qualified nor absolute. Returned urls may be relative to the - /// given context.
- /// To produce a client-usable url, consider applying e.g. or - /// before writing the result url to the response. - ///
- string GetRedirectUri( object context ); - } -} \ No newline at end of file + string GetRedirectUri(object context); +} diff --git a/src/Spring/Spring.Web/Web/Support/IResultFactory.cs b/src/Spring/Spring.Web/Web/Support/IResultFactory.cs index d19ece1b..1aec1a1c 100644 --- a/src/Spring/Spring.Web/Web/Support/IResultFactory.cs +++ b/src/Spring/Spring.Web/Web/Support/IResultFactory.cs @@ -22,30 +22,29 @@ #endregion -namespace Spring.Web.Support +namespace Spring.Web.Support; + +/// +/// A result factory is responsible for create an instance from a given string representation. +/// +/// +/// For a larger example illustrating the customization of result processing, . +/// +/// +/// +/// +/// +/// Erich Eichinger +public interface IResultFactory { /// - /// A result factory is responsible for create an instance from a given string representation. + /// Create an instance from the given string representation. /// + /// the resultMode that caused triggering this factory. + /// the remainder string to be interpreted and converted into an . + /// An instance. Must never be null! /// - /// For a larger example illustrating the customization of result processing, . + /// Note to implementors: This method must never return null. Instead exceptions should be thrown. /// - /// - /// - /// - /// - /// Erich Eichinger - public interface IResultFactory - { - /// - /// Create an instance from the given string representation. - /// - /// the resultMode that caused triggering this factory. - /// the remainder string to be interpreted and converted into an . - /// An instance. Must never be null! - /// - /// Note to implementors: This method must never return null. Instead exceptions should be thrown. - /// - IResult CreateResult( string resultMode, string resultText ); - } -} \ No newline at end of file + IResult CreateResult(string resultMode, string resultText); +} diff --git a/src/Spring/Spring.Web/Web/Support/IResultWebNavigator.cs b/src/Spring/Spring.Web/Web/Support/IResultWebNavigator.cs index a156099c..74e5e3b1 100644 --- a/src/Spring/Spring.Web/Web/Support/IResultWebNavigator.cs +++ b/src/Spring/Spring.Web/Web/Support/IResultWebNavigator.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -24,24 +24,23 @@ using System.Collections; #endregion -namespace Spring.Web.Support +namespace Spring.Web.Support; + +/// +/// Defines the interface, all hierarchical navigators capable of +/// dealing with instances must implement. +/// +public interface IResultWebNavigator : IHierarchicalWebNavigator { /// - /// Defines the interface, all hierarchical navigators capable of - /// dealing with instances must implement. + /// Contains the mappings of navigation destination names to + /// instances or their corresponding textual representations.
+ /// See for more information on how textual representations are resolved. ///
- public interface IResultWebNavigator : IHierarchicalWebNavigator - { - /// - /// Contains the mappings of navigation destination names to - /// instances or their corresponding textual representations.
- /// See for more information on how textual representations are resolved. - ///
- /// - /// - /// - /// - /// - IDictionary Results { get; set; } - } + /// + /// + /// + /// + /// + IDictionary Results { get; set; } } \ No newline at end of file diff --git a/src/Spring/Spring.Web/Web/Support/ISupportsWebDependencyInjection.cs b/src/Spring/Spring.Web/Web/Support/ISupportsWebDependencyInjection.cs index 206e4c8e..cbd401fb 100644 --- a/src/Spring/Spring.Web/Web/Support/ISupportsWebDependencyInjection.cs +++ b/src/Spring/Spring.Web/Web/Support/ISupportsWebDependencyInjection.cs @@ -1,6 +1,7 @@ #region License + /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -14,6 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + #endregion #region Imports @@ -22,76 +24,75 @@ using Spring.Context; #endregion -namespace Spring.Web.Support +namespace Spring.Web.Support; + +/// +/// "Contract"-interface of the Web-DI infrastructure. +/// +/// +/// This interface supports Spring's DI infrastructure and normally doesn't need to be implemented
+///
+/// Any Page, Control or ControlCollection implementing this interface guarantees to +/// call on any control being added +/// before it is actually added to the child-collection. +///
+/// +///

The following example shows, how to make a Control support the DI-infrastructure:

+/// +/// class MyControl : Control, ISupportsWebDependencyInjection +/// { +/// private IApplicationContext _defaultApplicationContext; +/// +/// public IApplicationContext DefaultApplicationContext +/// { +/// get { return _defaultApplicationContext; } +/// set { _defaultApplicationContext = value; } +/// } +/// +/// override protected AddedControl( Control control, int index ) +/// { +/// WebUtils.InjectDependenciesRecursive( _defaultApplicationContext, control ); +/// base.AddedControl( control, index ); +/// } +/// } +/// +///
+/// +///

The following example shows, how to make a ControlCollection support the DI-infrastructure:

+///

Note, that you MUST implement the single-argument constructor ControlCollection( Control owner )!

+/// +/// class MyControlCollection : ControlCollection, ISupportsWebDependencyInjection +/// { +/// private IApplicationContext _defaultApplicationContext; +/// +/// public MyControlCollection( Control owner ) : base( owner ) +/// {} +/// +/// public IApplicationContext DefaultApplicationContext +/// { +/// get { return _defaultApplicationContext; } +/// set { _defaultApplicationContext = value; } +/// } +/// +/// override public Add( Control child ) +/// { +/// WebUtils.InjectDependenciesRecursive( _defaultApplicationContext, child ); +/// base.Add( child ); +/// } +/// +/// override public AddAt( int index, Control child ) +/// { +/// WebUtils.InjectDependenciesRecursive( _defaultApplicationContext, child ); +/// base.AddAt( index, child ); +/// } +/// } +/// +///
+/// Erich Eichinger +public interface ISupportsWebDependencyInjection { - /// - /// "Contract"-interface of the Web-DI infrastructure. - /// - /// - /// This interface supports Spring's DI infrastructure and normally doesn't need to be implemented
- ///
- /// Any Page, Control or ControlCollection implementing this interface guarantees to - /// call on any control being added - /// before it is actually added to the child-collection. - ///
- /// - ///

The following example shows, how to make a Control support the DI-infrastructure:

- /// - /// class MyControl : Control, ISupportsWebDependencyInjection - /// { - /// private IApplicationContext _defaultApplicationContext; - /// - /// public IApplicationContext DefaultApplicationContext - /// { - /// get { return _defaultApplicationContext; } - /// set { _defaultApplicationContext = value; } - /// } - /// - /// override protected AddedControl( Control control, int index ) - /// { - /// WebUtils.InjectDependenciesRecursive( _defaultApplicationContext, control ); - /// base.AddedControl( control, index ); - /// } - /// } - /// - ///
- /// - ///

The following example shows, how to make a ControlCollection support the DI-infrastructure:

- ///

Note, that you MUST implement the single-argument constructor ControlCollection( Control owner )!

- /// - /// class MyControlCollection : ControlCollection, ISupportsWebDependencyInjection - /// { - /// private IApplicationContext _defaultApplicationContext; - /// - /// public MyControlCollection( Control owner ) : base( owner ) - /// {} - /// - /// public IApplicationContext DefaultApplicationContext - /// { - /// get { return _defaultApplicationContext; } - /// set { _defaultApplicationContext = value; } - /// } - /// - /// override public Add( Control child ) - /// { - /// WebUtils.InjectDependenciesRecursive( _defaultApplicationContext, child ); - /// base.Add( child ); - /// } - /// - /// override public AddAt( int index, Control child ) - /// { - /// WebUtils.InjectDependenciesRecursive( _defaultApplicationContext, child ); - /// base.AddAt( index, child ); - /// } - /// } - /// - ///
- /// Erich Eichinger - public interface ISupportsWebDependencyInjection - { - /// - /// Holds the default instance to be used during injecting a control-tree. - /// - IApplicationContext DefaultApplicationContext { get; set; } - } + /// + /// Holds the default instance to be used during injecting a control-tree. + /// + IApplicationContext DefaultApplicationContext { get; set; } } \ No newline at end of file diff --git a/src/Spring/Spring.Web/Web/Support/IWebNavigable.cs b/src/Spring/Spring.Web/Web/Support/IWebNavigable.cs index 558cf18b..4e7453ee 100644 --- a/src/Spring/Spring.Web/Web/Support/IWebNavigable.cs +++ b/src/Spring/Spring.Web/Web/Support/IWebNavigable.cs @@ -20,21 +20,18 @@ #region Imports - - #endregion -namespace Spring.Web.Support +namespace Spring.Web.Support; + +/// +/// Any component participating in the navigation infrastructure must implement this interface. +/// +/// Erich Eichinger +public interface IWebNavigable { /// - /// Any component participating in the navigation infrastructure must implement this interface. + /// Return the associated with this component. /// - /// Erich Eichinger - public interface IWebNavigable - { - /// - /// Return the associated with this component. - /// - IWebNavigator WebNavigator { get; } - } + IWebNavigator WebNavigator { get; } } \ No newline at end of file diff --git a/src/Spring/Spring.Web/Web/Support/IWebNavigator.cs b/src/Spring/Spring.Web/Web/Support/IWebNavigator.cs index 364f157d..b9e8e075 100644 --- a/src/Spring/Spring.Web/Web/Support/IWebNavigator.cs +++ b/src/Spring/Spring.Web/Web/Support/IWebNavigator.cs @@ -22,42 +22,41 @@ #endregion -namespace Spring.Web.Support +namespace Spring.Web.Support; + +/// +/// Any component capable of navigating and participating in the navigation logic must implement this interface. +/// +/// +/// +/// +/// +/// Erich Eichinger +public interface IWebNavigator { /// - /// Any component capable of navigating and participating in the navigation logic must implement this interface. + /// Determines, whether this navigator or one of its parents can + /// navigate to the destination specified in . /// - /// - /// - /// - /// - /// Erich Eichinger - public interface IWebNavigator - { - /// - /// Determines, whether this navigator or one of its parents can - /// navigate to the destination specified in . - /// - /// the name of the navigation destination - /// true, if this navigator can navigate to the destination. - bool CanNavigateTo( string destination ); + /// the name of the navigation destination + /// true, if this navigator can navigate to the destination. + bool CanNavigateTo(string destination); - /// - /// Instruct the navigator to navigate to the specified navigation destination. - /// - /// the destination to navigate to. - /// the sender that issued the navigation request. - /// the context to evaluate this navigation request in. - /// if this navigator cannot navigate to the specified (). - void NavigateTo( string destination, object sender, object context ); + /// + /// Instruct the navigator to navigate to the specified navigation destination. + /// + /// the destination to navigate to. + /// the sender that issued the navigation request. + /// the context to evaluate this navigation request in. + /// if this navigator cannot navigate to the specified (). + void NavigateTo(string destination, object sender, object context); - /// - /// Creates an uri poiniting to the specified navigation destination. - /// - /// the destination to navigate to. - /// the sender that issued the navigation request. - /// the context to evaluate this navigation request in. - /// if this navigator cannot navigate to the specified (). - string GetResultUri( string destination, object sender, object context ); - } + /// + /// Creates an uri poiniting to the specified navigation destination. + /// + /// the destination to navigate to. + /// the sender that issued the navigation request. + /// the context to evaluate this navigation request in. + /// if this navigator cannot navigate to the specified (). + string GetResultUri(string destination, object sender, object context); } diff --git a/src/Spring/Spring.Web/Web/Support/InterceptControlCollectionOwnerStrategy.cs b/src/Spring/Spring.Web/Web/Support/InterceptControlCollectionOwnerStrategy.cs index 7b50b38c..f3c29a0f 100644 --- a/src/Spring/Spring.Web/Web/Support/InterceptControlCollectionOwnerStrategy.cs +++ b/src/Spring/Spring.Web/Web/Support/InterceptControlCollectionOwnerStrategy.cs @@ -1,6 +1,7 @@ #region License + /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -14,6 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + #endregion #region Imports @@ -23,22 +25,21 @@ using Spring.Context; #endregion -namespace Spring.Web.Support +namespace Spring.Web.Support; + +/// +/// This strategy replaces the original collection's owner with an intercepting proxy +/// +/// Erich Eichinger +internal class InterceptControlCollectionOwnerStrategy : IInterceptionStrategy { - /// - /// This strategy replaces the original collection's owner with an intercepting proxy - /// - /// Erich Eichinger - internal class InterceptControlCollectionOwnerStrategy : IInterceptionStrategy + public bool Intercept(IApplicationContext defaultApplicationContext, ControlAccessor ctlAccessor, + ControlCollectionAccessor ctlColAccessor) { - public bool Intercept(IApplicationContext defaultApplicationContext, ControlAccessor ctlAccessor, - ControlCollectionAccessor ctlColAccessor) - { - Control target = ctlAccessor.GetTarget(); - ctlColAccessor.Owner = target is INamingContainer - ? new NamingContainerSupportsWebDependencyInjectionOwnerProxy(defaultApplicationContext, target) - : new SupportsWebDependencyInjectionOwnerProxy(defaultApplicationContext, target); - return true; - } + Control target = ctlAccessor.GetTarget(); + ctlColAccessor.Owner = target is INamingContainer + ? new NamingContainerSupportsWebDependencyInjectionOwnerProxy(defaultApplicationContext, target) + : new SupportsWebDependencyInjectionOwnerProxy(defaultApplicationContext, target); + return true; } -} \ No newline at end of file +} diff --git a/src/Spring/Spring.Web/Web/Support/InterceptControlCollectionStrategy.cs b/src/Spring/Spring.Web/Web/Support/InterceptControlCollectionStrategy.cs index fc42f7c5..174aadbf 100644 --- a/src/Spring/Spring.Web/Web/Support/InterceptControlCollectionStrategy.cs +++ b/src/Spring/Spring.Web/Web/Support/InterceptControlCollectionStrategy.cs @@ -1,4 +1,5 @@ #region License + /* * Copyright © 2002-2011 the original author or authors. * @@ -14,6 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + #endregion #region Imports @@ -28,142 +30,142 @@ using Spring.Util; #endregion -namespace Spring.Web.Support +namespace Spring.Web.Support; + +/// +/// This strategy enhances a ControlCollection's type by +/// dynamically implementing ISupportsWebDependencyInjection on this type +/// +/// Erich Eichinger +internal class InterceptControlCollectionStrategy : IInterceptionStrategy { /// - /// This strategy enhances a ControlCollection's type by - /// dynamically implementing ISupportsWebDependencyInjection on this type + /// Holds a reference to the static(!) callback-method to be used during generation of intercepted ControlCollection-Types /// - /// Erich Eichinger - internal class InterceptControlCollectionStrategy : IInterceptionStrategy + private delegate Control InjectDependenciesCallbackHandler(IApplicationContext defaultApplicationContext, Control control); + + /// + /// The list of methods to be intercepted for a ControlCollection + /// + private static readonly MethodInfo[] s_collectionMethods = new MethodInfo[] { typeof(ControlCollection).GetMethod("Add", BindingFlags.Instance | BindingFlags.Public), typeof(ControlCollection).GetMethod("AddAt", BindingFlags.Instance | BindingFlags.Public) }; + + /// + /// Holds a table of already known intercepted ControlCollection types + /// + private static readonly Hashtable s_interceptedCollectionTypeCache = new Hashtable(); + + /// + /// Intercepts the given by dynamically deriving + /// the original type and let it implement . + /// + /// the ApplicationContext to be set on the collection instance. + /// a wrapper around the owner control instance. + /// a wrapper around the collection instance. + /// true, if interception was successful. false otherwise + public bool Intercept(IApplicationContext defaultApplicationContext, + ControlAccessor ctlAccessor, ControlCollectionAccessor ctlColAccessor) { - /// - /// Holds a reference to the static(!) callback-method to be used during generation of intercepted ControlCollection-Types - /// - private delegate Control InjectDependenciesCallbackHandler(IApplicationContext defaultApplicationContext, Control control); - - /// - /// The list of methods to be intercepted for a ControlCollection - /// - private static readonly MethodInfo[] s_collectionMethods = new MethodInfo[] - { - typeof(ControlCollection).GetMethod("Add", BindingFlags.Instance | BindingFlags.Public) - , typeof (ControlCollection).GetMethod("AddAt", BindingFlags.Instance | BindingFlags.Public) - }; - - /// - /// Holds a table of already known intercepted ControlCollection types - /// - private static readonly Hashtable s_interceptedCollectionTypeCache = new Hashtable(); - - /// - /// Intercepts the given by dynamically deriving - /// the original type and let it implement . - /// - /// the ApplicationContext to be set on the collection instance. - /// a wrapper around the owner control instance. - /// a wrapper around the collection instance. - /// true, if interception was successful. false otherwise - public bool Intercept(IApplicationContext defaultApplicationContext, - ControlAccessor ctlAccessor, ControlCollectionAccessor ctlColAccessor) - { - Type collectionType = ctlColAccessor.GetTargetType(); - if (collectionType.IsSealed || - !ReflectionUtils.IsTypeVisible(collectionType, DynamicProxyManager.ASSEMBLY_NAME)) + Type collectionType = ctlColAccessor.GetTargetType(); + if (collectionType.IsSealed || + !ReflectionUtils.IsTypeVisible(collectionType, DynamicProxyManager.ASSEMBLY_NAME)) // || (null == collectionType.GetConstructor(new Type[] {typeof (Control)})) - { - return false; - } - - // this will enhance the collection's type and create a new instance of this type with fields copied from original collection - try - { - ControlCollection childControls = InterceptCollection(ctlAccessor.GetTarget(), ctlColAccessor.GetTarget() ); - ((ISupportsWebDependencyInjection)childControls).DefaultApplicationContext = defaultApplicationContext; - ctlAccessor.Controls = childControls; - } - catch - { - // this may happen, if the ControlCollection doesn't contain a standard-ctor ControlCollection( Control owner) - return false; - } - return true; + { + return false; } - private static ControlCollection InterceptCollection(Control owner, ControlCollection originalCollection) + // this will enhance the collection's type and create a new instance of this type with fields copied from original collection + try { - CreateControlCollectionDelegate factoryMethod = GetInterceptedCollectionFactory(owner.GetType(), originalCollection.GetType()); - ControlCollection interceptedCollection = factoryMethod(owner); - ReflectionUtils.MemberwiseCopy(originalCollection, interceptedCollection); - return interceptedCollection; + ControlCollection childControls = InterceptCollection(ctlAccessor.GetTarget(), ctlColAccessor.GetTarget()); + ((ISupportsWebDependencyInjection) childControls).DefaultApplicationContext = defaultApplicationContext; + ctlAccessor.Controls = childControls; + } + catch + { + // this may happen, if the ControlCollection doesn't contain a standard-ctor ControlCollection( Control owner) + return false; } - internal static ControlCollection TryCreateCollection(Control owner) + return true; + } + + private static ControlCollection InterceptCollection(Control owner, ControlCollection originalCollection) + { + CreateControlCollectionDelegate factoryMethod = GetInterceptedCollectionFactory(owner.GetType(), originalCollection.GetType()); + ControlCollection interceptedCollection = factoryMethod(owner); + ReflectionUtils.MemberwiseCopy(originalCollection, interceptedCollection); + return interceptedCollection; + } + + internal static ControlCollection TryCreateCollection(Control owner) + { + CreateControlCollectionDelegate factoryMethod = (CreateControlCollectionDelegate) s_collectionFactoryCache[owner.GetType()]; + if (factoryMethod != null) { - CreateControlCollectionDelegate factoryMethod = (CreateControlCollectionDelegate)s_collectionFactoryCache[owner.GetType()]; - if (factoryMethod != null) - { - return factoryMethod(owner); - } - return null; + return factoryMethod(owner); } - private delegate ControlCollection CreateControlCollectionDelegate(Control owner); - private static readonly Hashtable s_collectionFactoryCache = new Hashtable(); + return null; + } - private static CreateControlCollectionDelegate GetInterceptedCollectionFactory(Type ownerType, Type collectionType) + private delegate ControlCollection CreateControlCollectionDelegate(Control owner); + + private static readonly Hashtable s_collectionFactoryCache = new Hashtable(); + + private static CreateControlCollectionDelegate GetInterceptedCollectionFactory(Type ownerType, Type collectionType) + { + AssertUtils.State(typeof(Control).IsAssignableFrom(ownerType), "ownerType must be of type Control"); + AssertUtils.State(typeof(ControlCollection).IsAssignableFrom(collectionType), "collectionType must be of type ControlCollection"); + + CreateControlCollectionDelegate factoryMethod = (CreateControlCollectionDelegate) s_collectionFactoryCache[ownerType]; + if (factoryMethod == null) { - AssertUtils.State( typeof(Control).IsAssignableFrom(ownerType), "ownerType must be of type Control" ); - AssertUtils.State( typeof(ControlCollection).IsAssignableFrom(collectionType), "collectionType must be of type ControlCollection" ); - - CreateControlCollectionDelegate factoryMethod = (CreateControlCollectionDelegate)s_collectionFactoryCache[ownerType]; - if (factoryMethod == null) + lock (s_collectionFactoryCache) { - lock (s_collectionFactoryCache) + factoryMethod = (CreateControlCollectionDelegate) s_collectionFactoryCache[ownerType]; + if (factoryMethod == null) { - factoryMethod = (CreateControlCollectionDelegate)s_collectionFactoryCache[ownerType]; - if (factoryMethod == null) - { - Type interceptedCollectionType = GetInterceptedCollectionType( - collectionType - , WebDependencyInjectionUtils.InjectDependenciesRecursive - ); + Type interceptedCollectionType = GetInterceptedCollectionType( + collectionType + , WebDependencyInjectionUtils.InjectDependenciesRecursive + ); - ConstructorInfo ctor = interceptedCollectionType.GetConstructor(new Type[] { typeof(Control) }); - DynamicMethod dm = new DynamicMethod(string.Empty, typeof(ControlCollection), new Type[] { typeof(Control) }); - ILGenerator il = dm.GetILGenerator(); - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Newobj, ctor); - il.Emit(OpCodes.Ret); - factoryMethod = (CreateControlCollectionDelegate)dm.CreateDelegate(typeof(CreateControlCollectionDelegate)); - s_collectionFactoryCache[ownerType] = factoryMethod; - } + ConstructorInfo ctor = interceptedCollectionType.GetConstructor(new Type[] { typeof(Control) }); + DynamicMethod dm = new DynamicMethod(string.Empty, typeof(ControlCollection), new Type[] { typeof(Control) }); + ILGenerator il = dm.GetILGenerator(); + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Newobj, ctor); + il.Emit(OpCodes.Ret); + factoryMethod = (CreateControlCollectionDelegate) dm.CreateDelegate(typeof(CreateControlCollectionDelegate)); + s_collectionFactoryCache[ownerType] = factoryMethod; } } - return factoryMethod; } - private static Type GetInterceptedCollectionType(Type controlCollectionType, InjectDependenciesCallbackHandler staticCallback) - { - AssertUtils.State( typeof(ControlCollection).IsAssignableFrom(controlCollectionType), "controlCollectionType must be of type ControlCollection" ); + return factoryMethod; + } - Type interceptedCollectionType = (Type)s_interceptedCollectionTypeCache[controlCollectionType]; - if (interceptedCollectionType == null) + private static Type GetInterceptedCollectionType(Type controlCollectionType, InjectDependenciesCallbackHandler staticCallback) + { + AssertUtils.State(typeof(ControlCollection).IsAssignableFrom(controlCollectionType), "controlCollectionType must be of type ControlCollection"); + + Type interceptedCollectionType = (Type) s_interceptedCollectionTypeCache[controlCollectionType]; + if (interceptedCollectionType == null) + { + lock (s_interceptedCollectionTypeCache) { - lock (s_interceptedCollectionTypeCache) + MethodInfo callbackMethod = staticCallback.Method; + AssertUtils.State(callbackMethod.IsStatic && callbackMethod.IsPublic, "staticCallback must be a public static method"); + interceptedCollectionType = (Type) s_interceptedCollectionTypeCache[controlCollectionType]; + if (interceptedCollectionType == null) { - MethodInfo callbackMethod = staticCallback.Method; - AssertUtils.State(callbackMethod.IsStatic && callbackMethod.IsPublic, "staticCallback must be a public static method"); - interceptedCollectionType = (Type)s_interceptedCollectionTypeCache[controlCollectionType]; - if (interceptedCollectionType == null) - { - SupportsWebDependencyInjectionTypeBuilder builder = new SupportsWebDependencyInjectionTypeBuilder(controlCollectionType, s_collectionMethods, callbackMethod); - interceptedCollectionType = builder.BuildProxyType(); - s_interceptedCollectionTypeCache[controlCollectionType] = interceptedCollectionType; - } + SupportsWebDependencyInjectionTypeBuilder builder = new SupportsWebDependencyInjectionTypeBuilder(controlCollectionType, s_collectionMethods, callbackMethod); + interceptedCollectionType = builder.BuildProxyType(); + s_interceptedCollectionTypeCache[controlCollectionType] = interceptedCollectionType; } } - return interceptedCollectionType; } + + return interceptedCollectionType; } } diff --git a/src/Spring/Spring.Web/Web/Support/LocalResourceManager.cs b/src/Spring/Spring.Web/Web/Support/LocalResourceManager.cs index 58a89a05..7e386c96 100644 --- a/src/Spring/Spring.Web/Web/Support/LocalResourceManager.cs +++ b/src/Spring/Spring.Web/Web/Support/LocalResourceManager.cs @@ -33,197 +33,200 @@ using Spring.Util; #endregion -namespace Spring.Web.Support +namespace Spring.Web.Support; + +/// +/// This ResourceManager implementation swallows s and +/// simply returns null from if no resource is found. +/// +/// Erich Eichinger +internal abstract class LocalResourceManager : ResourceManager { + private delegate IResourceProvider GetResourceProviderDelegate(TemplateControl control); + + private static readonly GetResourceProviderDelegate getLocalResourceProvider; + private static readonly Type LocalResXResourceProviderFactoryType; + private static readonly Type LocalResXResourceProviderType; + private static readonly ResourceProviderFactory LocalResXResourceProviderFactory; + private static readonly SafeMethod fnGetLocalResourceAssembly; + /// - /// This ResourceManager implementation swallows s and - /// simply returns null from if no resource is found. + /// Avoid beforeFieldInit /// - /// Erich Eichinger - internal abstract class LocalResourceManager : ResourceManager + static LocalResourceManager() { - private delegate IResourceProvider GetResourceProviderDelegate( TemplateControl control ); - private static readonly GetResourceProviderDelegate getLocalResourceProvider; - private static readonly Type LocalResXResourceProviderFactoryType; - private static readonly Type LocalResXResourceProviderType; - private static readonly ResourceProviderFactory LocalResXResourceProviderFactory; - private static readonly SafeMethod fnGetLocalResourceAssembly; + LocalResXResourceProviderFactoryType = typeof(IResourceProvider).Assembly.GetType("System.Web.Compilation.ResXResourceProviderFactory", true); + LocalResXResourceProviderType = typeof(IResourceProvider).Assembly.GetType("System.Web.Compilation.LocalResXResourceProvider", true); - /// - /// Avoid beforeFieldInit - /// - static LocalResourceManager() + GetResourceProviderDelegate fnGetResourceProvider = null; + ResourceProviderFactory rpf = null; + SafeMethod glra = null; + SecurityCritical.ExecutePrivileged(new PermissionSet(PermissionState.Unrestricted), delegate { - LocalResXResourceProviderFactoryType = typeof(IResourceProvider).Assembly.GetType("System.Web.Compilation.ResXResourceProviderFactory", true); - LocalResXResourceProviderType = typeof(IResourceProvider).Assembly.GetType("System.Web.Compilation.LocalResXResourceProvider", true); - - GetResourceProviderDelegate fnGetResourceProvider = null; - ResourceProviderFactory rpf = null; - SafeMethod glra = null; - SecurityCritical.ExecutePrivileged(new PermissionSet(PermissionState.Unrestricted), delegate - { - fnGetResourceProvider = (GetResourceProviderDelegate)Delegate.CreateDelegate(typeof(GetResourceProviderDelegate), typeof(ResourceExpressionBuilder).GetMethod("GetLocalResourceProvider", BindingFlags.Static | BindingFlags.NonPublic, null, new Type[] { typeof(TemplateControl) }, null)); - rpf = (ResourceProviderFactory)Activator.CreateInstance( LocalResXResourceProviderFactoryType, true ); - glra = new SafeMethod(LocalResXResourceProviderType.GetMethod("GetLocalResourceAssembly", BindingFlags.Instance | BindingFlags.NonPublic)); - }); - getLocalResourceProvider = fnGetResourceProvider; - LocalResXResourceProviderFactory = rpf; - fnGetLocalResourceAssembly = glra; - } - - internal static ResourceManager GetLocalResourceManager( TemplateControl control ) - { - IResourceProvider localResourceProvider = GetLocalResourceProvider( control ); - if (localResourceProvider == null) - { - return null; - } - - if (localResourceProvider.GetType() == LocalResXResourceProviderType) - { - Assembly localResourceAssembly = GetLocalResourceAssembly( control ); - if (localResourceAssembly != null) - { - return new LocalResXAssemblyResourceManager(control, localResourceAssembly); - } - else - { - return null; - } - } - - return new ResourceProviderResourceManager(localResourceProvider); - } - - internal static IResourceProvider GetLocalResourceProvider( TemplateControl templateControl ) - { - IResourceProvider localResourceProvider = getLocalResourceProvider( templateControl ); - return localResourceProvider; - } - - internal static Assembly GetLocalResourceAssembly( TemplateControl control ) - { - object localResXResourceProvider = LocalResXResourceProviderFactory.CreateLocalResourceProvider( control.AppRelativeVirtualPath ); - Assembly localResourceAssembly = (Assembly)fnGetLocalResourceAssembly.Invoke( localResXResourceProvider, null ); - return localResourceAssembly; - } - - #region ResourceProviderResourceManager - - private class ResourceProviderResourceManager : ResourceManager - { - private bool _hasException; - private readonly IResourceProvider _resourceProvider; - - public ResourceProviderResourceManager(IResourceProvider resourceProvider) - { - _resourceProvider = resourceProvider; - } - - /// - ///Returns the value of the specified resource. - /// - /// - ///The value of the resource localized for the caller's current culture settings. If a match is not possible, null is returned. The resource value can be null. - /// - ///The name of the resource to get. - ///The name parameter is null. - public override object GetObject( string name ) - { - return this.GetObject( name, null ); - } - - /// - ///Gets the value of the resource localized for the specified culture. - /// - /// - ///The value of the resource, localized for the specified culture. If a "best match" is not possible, null is returned. - /// - ///The object that represents the culture for which the resource is localized. Note that if the resource is not localized for this culture, the lookup will fall back using the culture's property, stopping after checking in the neutral culture.If this value is null, the is obtained using the culture's property. - ///The name of the resource to get. - ///The name parameter is null. - public override object GetObject( string name, CultureInfo culture ) - { - if (_hasException) - return null; - - try - { - return _resourceProvider.GetObject(name, culture); - } - catch (Exception) - { - _hasException = true; - } - return null; - } - - public override ResourceSet GetResourceSet( CultureInfo culture, bool createIfNotExists, bool tryParents ) - { - ResourceSet resourceSet = null; - if (culture == CultureInfo.InvariantCulture) - { - resourceSet = new ResourceSet(_resourceProvider.ResourceReader); - } - return resourceSet; - } - } - - #endregion - - #region LocalResXAssemblyResourceManager - - private class LocalResXAssemblyResourceManager : ResourceManager - { - private bool _isMissingManifest = false; - - public LocalResXAssemblyResourceManager( TemplateControl templateControl, Assembly localResourceAssembly ) - : base( - VirtualPathUtility.GetFileName( templateControl.AppRelativeVirtualPath ), localResourceAssembly ) - { - AssertUtils.ArgumentNotNull( templateControl, "templateControl" ); - AssertUtils.ArgumentNotNull( localResourceAssembly, "localResourceAssembly" ); - } - - /// - ///Returns the value of the specified resource. - /// - /// - ///The value of the resource localized for the caller's current culture settings. If a match is not possible, null is returned. The resource value can be null. - /// - ///The name of the resource to get. - ///The name parameter is null. - public override object GetObject( string name ) - { - return this.GetObject( name, null ); - } - - /// - ///Gets the value of the resource localized for the specified culture. - /// - /// - ///The value of the resource, localized for the specified culture. If a "best match" is not possible, null is returned. - /// - ///The object that represents the culture for which the resource is localized. Note that if the resource is not localized for this culture, the lookup will fall back using the culture's property, stopping after checking in the neutral culture.If this value is null, the is obtained using the culture's property. - ///The name of the resource to get. - ///The name parameter is null. - public override object GetObject( string name, CultureInfo culture ) - { - if (_isMissingManifest) - return null; - - try - { - return base.GetObject( name, culture ); - } - catch (MissingManifestResourceException) - { - _isMissingManifest = true; - } - return null; - } - } - - #endregion + fnGetResourceProvider = (GetResourceProviderDelegate) Delegate.CreateDelegate(typeof(GetResourceProviderDelegate), typeof(ResourceExpressionBuilder).GetMethod("GetLocalResourceProvider", BindingFlags.Static | BindingFlags.NonPublic, null, new Type[] { typeof(TemplateControl) }, null)); + rpf = (ResourceProviderFactory) Activator.CreateInstance(LocalResXResourceProviderFactoryType, true); + glra = new SafeMethod(LocalResXResourceProviderType.GetMethod("GetLocalResourceAssembly", BindingFlags.Instance | BindingFlags.NonPublic)); + }); + getLocalResourceProvider = fnGetResourceProvider; + LocalResXResourceProviderFactory = rpf; + fnGetLocalResourceAssembly = glra; } + + internal static ResourceManager GetLocalResourceManager(TemplateControl control) + { + IResourceProvider localResourceProvider = GetLocalResourceProvider(control); + if (localResourceProvider == null) + { + return null; + } + + if (localResourceProvider.GetType() == LocalResXResourceProviderType) + { + Assembly localResourceAssembly = GetLocalResourceAssembly(control); + if (localResourceAssembly != null) + { + return new LocalResXAssemblyResourceManager(control, localResourceAssembly); + } + else + { + return null; + } + } + + return new ResourceProviderResourceManager(localResourceProvider); + } + + internal static IResourceProvider GetLocalResourceProvider(TemplateControl templateControl) + { + IResourceProvider localResourceProvider = getLocalResourceProvider(templateControl); + return localResourceProvider; + } + + internal static Assembly GetLocalResourceAssembly(TemplateControl control) + { + object localResXResourceProvider = LocalResXResourceProviderFactory.CreateLocalResourceProvider(control.AppRelativeVirtualPath); + Assembly localResourceAssembly = (Assembly) fnGetLocalResourceAssembly.Invoke(localResXResourceProvider, null); + return localResourceAssembly; + } + + #region ResourceProviderResourceManager + + private class ResourceProviderResourceManager : ResourceManager + { + private bool _hasException; + private readonly IResourceProvider _resourceProvider; + + public ResourceProviderResourceManager(IResourceProvider resourceProvider) + { + _resourceProvider = resourceProvider; + } + + /// + ///Returns the value of the specified resource. + /// + /// + ///The value of the resource localized for the caller's current culture settings. If a match is not possible, null is returned. The resource value can be null. + /// + ///The name of the resource to get. + ///The name parameter is null. + public override object GetObject(string name) + { + return this.GetObject(name, null); + } + + /// + ///Gets the value of the resource localized for the specified culture. + /// + /// + ///The value of the resource, localized for the specified culture. If a "best match" is not possible, null is returned. + /// + ///The object that represents the culture for which the resource is localized. Note that if the resource is not localized for this culture, the lookup will fall back using the culture's property, stopping after checking in the neutral culture.If this value is null, the is obtained using the culture's property. + ///The name of the resource to get. + ///The name parameter is null. + public override object GetObject(string name, CultureInfo culture) + { + if (_hasException) + return null; + + try + { + return _resourceProvider.GetObject(name, culture); + } + catch (Exception) + { + _hasException = true; + } + + return null; + } + + public override ResourceSet GetResourceSet(CultureInfo culture, bool createIfNotExists, bool tryParents) + { + ResourceSet resourceSet = null; + if (culture == CultureInfo.InvariantCulture) + { + resourceSet = new ResourceSet(_resourceProvider.ResourceReader); + } + + return resourceSet; + } + } + + #endregion + + #region LocalResXAssemblyResourceManager + + private class LocalResXAssemblyResourceManager : ResourceManager + { + private bool _isMissingManifest = false; + + public LocalResXAssemblyResourceManager(TemplateControl templateControl, Assembly localResourceAssembly) + : base( + VirtualPathUtility.GetFileName(templateControl.AppRelativeVirtualPath), localResourceAssembly) + { + AssertUtils.ArgumentNotNull(templateControl, "templateControl"); + AssertUtils.ArgumentNotNull(localResourceAssembly, "localResourceAssembly"); + } + + /// + ///Returns the value of the specified resource. + /// + /// + ///The value of the resource localized for the caller's current culture settings. If a match is not possible, null is returned. The resource value can be null. + /// + ///The name of the resource to get. + ///The name parameter is null. + public override object GetObject(string name) + { + return this.GetObject(name, null); + } + + /// + ///Gets the value of the resource localized for the specified culture. + /// + /// + ///The value of the resource, localized for the specified culture. If a "best match" is not possible, null is returned. + /// + ///The object that represents the culture for which the resource is localized. Note that if the resource is not localized for this culture, the lookup will fall back using the culture's property, stopping after checking in the neutral culture.If this value is null, the is obtained using the culture's property. + ///The name of the resource to get. + ///The name parameter is null. + public override object GetObject(string name, CultureInfo culture) + { + if (_isMissingManifest) + return null; + + try + { + return base.GetObject(name, culture); + } + catch (MissingManifestResourceException) + { + _isMissingManifest = true; + } + + return null; + } + } + + #endregion } diff --git a/src/Spring/Spring.Web/Web/Support/MappingHandlerFactory.cs b/src/Spring/Spring.Web/Web/Support/MappingHandlerFactory.cs index 426c9b96..58f41a2f 100644 --- a/src/Spring/Spring.Web/Web/Support/MappingHandlerFactory.cs +++ b/src/Spring/Spring.Web/Web/Support/MappingHandlerFactory.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -27,148 +27,149 @@ using Spring.Context; #endregion -namespace Spring.Web.Support +namespace Spring.Web.Support; + +/// +/// MappingHandleryFactory allows for full Spring-managed <httpHandlers> configuration. +/// It uses regular expressions for url matching. +/// +/// +/// +/// The example below shows, how to map all url requests to spring and let +/// resolve urls to container-managed or objects. +/// +/// // web.config +/// +/// <httpHandlers> +/// <!-- map all requests to spring (just for demo - don't do this at home!) --> +/// <add verb="*" path="*.*" type="Spring.Web.Support.MappingHandlerFactory, Spring.Web" /> +/// </httpHandlers> +/// +/// // spring-objects.config +/// +/// <object type="Spring.Web.Support.MappingHandlerFactoryConfigurer, Spring.Web"> +/// <property name="HandlerMap"> +/// <dictionary> +/// <entry key="\.ashx$" value="standardHandlerFactory" /> +/// <!-- map any request ending with *.whatever to standardHandlerFactory --> +/// <entry key="\.whatever$" value="specialHandlerFactory" /> +/// </dictionary> +/// </property> +/// </object> +/// +/// <object name="standardHandlerFactory" type="Spring.Web.Support.DefaultHandlerFactory, Spring.Web" /> +/// +/// <object name="specialHandlerFactory" type="MySpecialHandlerFactoryImpl" /> +/// +/// +/// +/// +/// +/// +/// +/// Erich Eichinger +public class MappingHandlerFactory : AbstractHandlerFactory { - /// - /// MappingHandleryFactory allows for full Spring-managed <httpHandlers> configuration. - /// It uses regular expressions for url matching. - /// - /// - /// - /// The example below shows, how to map all url requests to spring and let - /// resolve urls to container-managed or objects. - /// - /// // web.config - /// - /// <httpHandlers> - /// <!-- map all requests to spring (just for demo - don't do this at home!) --> - /// <add verb="*" path="*.*" type="Spring.Web.Support.MappingHandlerFactory, Spring.Web" /> - /// </httpHandlers> - /// - /// // spring-objects.config - /// - /// <object type="Spring.Web.Support.MappingHandlerFactoryConfigurer, Spring.Web"> - /// <property name="HandlerMap"> - /// <dictionary> - /// <entry key="\.ashx$" value="standardHandlerFactory" /> - /// <!-- map any request ending with *.whatever to standardHandlerFactory --> - /// <entry key="\.whatever$" value="specialHandlerFactory" /> - /// </dictionary> - /// </property> - /// </object> - /// - /// <object name="standardHandlerFactory" type="Spring.Web.Support.DefaultHandlerFactory, Spring.Web" /> - /// - /// <object name="specialHandlerFactory" type="MySpecialHandlerFactoryImpl" /> - /// - /// - /// - /// - /// - /// - /// - /// Erich Eichinger - public class MappingHandlerFactory : AbstractHandlerFactory - { - private static readonly HandlerMap s_handlerMap = new HandlerMap(); + private static readonly HandlerMap s_handlerMap = new HandlerMap(); - /// - /// Holds the global list of mappings from url patterns to handler names. - /// - public static HandlerMap HandlerMap - { - get { return s_handlerMap; } - } + /// + /// Holds the global list of mappings from url patterns to handler names. + /// + public static HandlerMap HandlerMap + { + get { return s_handlerMap; } + } - /// - /// Holds the cache of handler/factory pairs handed out by this factory. This is required - /// for proper handling of . - /// - private readonly Hashtable _handlerWithFactoryTable = new Hashtable(); + /// + /// Holds the cache of handler/factory pairs handed out by this factory. This is required + /// for proper handling of . + /// + private readonly Hashtable _handlerWithFactoryTable = new Hashtable(); - /// - /// Create a handler instance for the given URL. Will try to find a match of onto patterns in . - /// If a match is found, delegates the call to the matching method. - /// - /// the application context corresponding to the current request - /// The instance for this request. - /// The HTTP data transfer method (GET, POST, ...) - /// The requested . - /// The physical path of the requested resource. - /// A handler instance for processing the current request. - protected override IHttpHandler CreateHandlerInstance(IConfigurableApplicationContext appContext, HttpContext context, string requestType, string rawUrl, string physicalPath) - { - return MapHandlerInstance(appContext, context, requestType, rawUrl, physicalPath, s_handlerMap, _handlerWithFactoryTable); - } + /// + /// Create a handler instance for the given URL. Will try to find a match of onto patterns in . + /// If a match is found, delegates the call to the matching method. + /// + /// the application context corresponding to the current request + /// The instance for this request. + /// The HTTP data transfer method (GET, POST, ...) + /// The requested . + /// The physical path of the requested resource. + /// A handler instance for processing the current request. + protected override IHttpHandler CreateHandlerInstance(IConfigurableApplicationContext appContext, HttpContext context, string requestType, string rawUrl, string physicalPath) + { + return MapHandlerInstance(appContext, context, requestType, rawUrl, physicalPath, s_handlerMap, _handlerWithFactoryTable); + } - /// - /// Obtains a handler by mapping to the list of patterns in . - /// - /// the application context corresponding to the current request - /// The instance for this request. - /// The HTTP data transfer method (GET, POST, ...) - /// The requested . - /// The physical path of the requested resource. - /// - /// - /// A handler instance for processing the current request. - protected IHttpHandler MapHandlerInstance(IConfigurableApplicationContext appContext, HttpContext context, string requestType, string rawUrl, string physicalPath, HandlerMap handlerMappings, IDictionary handlerWithFactoryTable) - { - // resolve handler instance by mapping the url to the list of patterns - HandlerMapEntry handlerMapEntry = handlerMappings.MapPath(rawUrl); - if (handlerMapEntry == null) - { - throw new HttpException(404, HttpStatusCode.NotFound.ToString()); - } - object handlerObject = appContext.GetObject(handlerMapEntry.HandlerObjectName); - - if (handlerObject is IHttpHandler) - { - return (IHttpHandler) handlerObject; - } - else if (handlerObject is IHttpHandlerFactory) - { - // keep a reference to the issuing factory for later ReleaseHandler call - IHttpHandlerFactory factory = (IHttpHandlerFactory) handlerObject; - IHttpHandler handler = factory.GetHandler(context, requestType, rawUrl, physicalPath); - lock(handlerWithFactoryTable.SyncRoot) - { - handlerWithFactoryTable.Add(handler, factory); - } - return handler; - } - - throw new HttpException((int)HttpStatusCode.NotFound, HttpStatusCode.NotFound.ToString()); - } - - /// - /// Enables a factory to release an existing - /// instance. - /// - /// - /// The object to release. - /// - public override void ReleaseHandler(IHttpHandler handler) - { - ReleaseHandler(handler, this._handlerWithFactoryTable); - } - - /// - /// Removes the handler from the handler/factory dictionary and releases the handler. - /// - /// the handler to be released - /// a dictionary containing (, ) entries. - protected void ReleaseHandler( IHttpHandler handler, IDictionary _handlerWithFactoryTable ) + /// + /// Obtains a handler by mapping to the list of patterns in . + /// + /// the application context corresponding to the current request + /// The instance for this request. + /// The HTTP data transfer method (GET, POST, ...) + /// The requested . + /// The physical path of the requested resource. + /// + /// + /// A handler instance for processing the current request. + protected IHttpHandler MapHandlerInstance(IConfigurableApplicationContext appContext, HttpContext context, string requestType, string rawUrl, string physicalPath, HandlerMap handlerMappings, IDictionary handlerWithFactoryTable) + { + // resolve handler instance by mapping the url to the list of patterns + HandlerMapEntry handlerMapEntry = handlerMappings.MapPath(rawUrl); + if (handlerMapEntry == null) { - lock (_handlerWithFactoryTable.SyncRoot) - { - IHttpHandlerFactory factory = _handlerWithFactoryTable[handler] as IHttpHandlerFactory; - if (factory != null) - { - _handlerWithFactoryTable.Remove(handler); - factory.ReleaseHandler(handler); - } - } + throw new HttpException(404, HttpStatusCode.NotFound.ToString()); } - } -} + + object handlerObject = appContext.GetObject(handlerMapEntry.HandlerObjectName); + + if (handlerObject is IHttpHandler) + { + return (IHttpHandler) handlerObject; + } + else if (handlerObject is IHttpHandlerFactory) + { + // keep a reference to the issuing factory for later ReleaseHandler call + IHttpHandlerFactory factory = (IHttpHandlerFactory) handlerObject; + IHttpHandler handler = factory.GetHandler(context, requestType, rawUrl, physicalPath); + lock (handlerWithFactoryTable.SyncRoot) + { + handlerWithFactoryTable.Add(handler, factory); + } + + return handler; + } + + throw new HttpException((int) HttpStatusCode.NotFound, HttpStatusCode.NotFound.ToString()); + } + + /// + /// Enables a factory to release an existing + /// instance. + /// + /// + /// The object to release. + /// + public override void ReleaseHandler(IHttpHandler handler) + { + ReleaseHandler(handler, this._handlerWithFactoryTable); + } + + /// + /// Removes the handler from the handler/factory dictionary and releases the handler. + /// + /// the handler to be released + /// a dictionary containing (, ) entries. + protected void ReleaseHandler(IHttpHandler handler, IDictionary _handlerWithFactoryTable) + { + lock (_handlerWithFactoryTable.SyncRoot) + { + IHttpHandlerFactory factory = _handlerWithFactoryTable[handler] as IHttpHandlerFactory; + if (factory != null) + { + _handlerWithFactoryTable.Remove(handler); + factory.ReleaseHandler(handler); + } + } + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Web/Web/Support/MappingHandlerFactoryConfigurer.cs b/src/Spring/Spring.Web/Web/Support/MappingHandlerFactoryConfigurer.cs index 56b5465b..bae4575f 100644 --- a/src/Spring/Spring.Web/Web/Support/MappingHandlerFactoryConfigurer.cs +++ b/src/Spring/Spring.Web/Web/Support/MappingHandlerFactoryConfigurer.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -22,24 +22,24 @@ #endregion -namespace Spring.Web.Support +namespace Spring.Web.Support; + +/// +/// Configures . +/// +/// Erich Eichinger +public class MappingHandlerFactoryConfigurer +// : Spring.Objects.Factory.Config.IObjectPostProcessor // just a trick to have { /// - /// Configures . + /// Contains mappings of url patterns to handler objects. /// - /// Erich Eichinger - public class MappingHandlerFactoryConfigurer -// : Spring.Objects.Factory.Config.IObjectPostProcessor // just a trick to have - { - /// - /// Contains mappings of url patterns to handler objects. - /// - public HandlerMap HandlerMap - { - get - { - return MappingHandlerFactory.HandlerMap; - } + public HandlerMap HandlerMap + { + get + { + return MappingHandlerFactory.HandlerMap; + } // set // { // AssertUtils.ArgumentNotNull(value, "HandlerMap"); @@ -48,9 +48,9 @@ namespace Spring.Web.Support // GenericHandlerFactory.HandlerMap[mapEntry.UrlPattern] = mapEntry; // } // } - } + } - #region IObjectPostProcessor implementation + #region IObjectPostProcessor implementation // object IObjectPostProcessor.PostProcessBeforeInitialization(object instance, string name) // { @@ -62,6 +62,5 @@ namespace Spring.Web.Support // return instance; // } - #endregion - } -} \ No newline at end of file + #endregion +} diff --git a/src/Spring/Spring.Web/Web/Support/MimeMediaType.cs b/src/Spring/Spring.Web/Web/Support/MimeMediaType.cs index 81a39a41..5d07b799 100644 --- a/src/Spring/Spring.Web/Web/Support/MimeMediaType.cs +++ b/src/Spring/Spring.Web/Web/Support/MimeMediaType.cs @@ -24,218 +24,226 @@ using Spring.Util; #endregion -namespace Spring.Web.Support +namespace Spring.Web.Support; + +/// +/// Represents a MIME media type as defined by http://www.iana.org/assignments/media-types/ +/// +/// Erich Eichinger +public class MimeMediaType { + private static readonly List ContentTypes = new List(new string[] { "application", "audio", "example", "image", "message", "model", "multipart", "text", "video" }); + + #region Predefined Instances + /// - /// Represents a MIME media type as defined by http://www.iana.org/assignments/media-types/ + /// Predefines common application media types /// - /// Erich Eichinger - public class MimeMediaType + public sealed class Application { - private static readonly List ContentTypes = new List( new string[] { - "application", "audio", "example", "image", "message", - "model", "multipart", "text", "video" - }); - - #region Predefined Instances + /// + /// Represents "application/octet-stream" + /// + public static readonly MimeMediaType Octet = Parse("application/octet-stream"); /// - /// Predefines common application media types + /// Represents "application/pdf" /// - public sealed class Application - { - /// - /// Represents "application/octet-stream" - /// - public static readonly MimeMediaType Octet = Parse("application/octet-stream"); - /// - /// Represents "application/pdf" - /// - public static readonly MimeMediaType Pdf = Parse("application/pdf"); - /// - /// Represents "application/rtf" - /// - public static readonly MimeMediaType Rtf = Parse("application/rtf"); - /// - /// Represents "application/soap+xml" - /// - public static readonly MimeMediaType Soap = Parse("application/soap+xml"); - /// - /// Represents "application/zip" - /// - public static readonly MimeMediaType Zip = Parse("application/zip"); - } + public static readonly MimeMediaType Pdf = Parse("application/pdf"); /// - /// Predefines common image media types + /// Represents "application/rtf" /// - public sealed class Image - { - /// - /// Represents "image/gif" - /// - public static readonly MimeMediaType Gif = Parse("image/gif"); - /// - /// Represents "image/jpeg" - /// - public static readonly MimeMediaType Jpeg = Parse("image/jpeg"); - /// - /// Represents "image/tiff" - /// - public static readonly MimeMediaType Tiff = Parse("image/tiff"); - } + public static readonly MimeMediaType Rtf = Parse("application/rtf"); /// - /// Predefines common text media types + /// Represents "application/soap+xml" /// - public sealed class Text - { - /// - /// Represents "text/html" - /// - public static readonly MimeMediaType Html = Parse("text/html"); - /// - /// Represents "text/plain" - /// - public static readonly MimeMediaType Plain = Parse("text/plain"); - /// - /// Represents "text/richtext" - /// - public static readonly MimeMediaType RichText = Parse("text/richtext"); - /// - /// Represents "text/xml" - /// - public static readonly MimeMediaType Xml = Parse("text/xml"); - /// - /// Represents "text/javascript" - /// - public static readonly MimeMediaType Javascript = Parse("text/javascript"); - /// - /// Represents "text/css" - /// - public static readonly MimeMediaType Css = Parse("text/css"); - } - - #endregion - - #region Static Methods + public static readonly MimeMediaType Soap = Parse("application/soap+xml"); /// - /// Parses a string into a instance. + /// Represents "application/zip" /// - /// a valid string representation of a mediaType - /// a new instance - public static MimeMediaType Parse(string mediaType) - { - AssertUtils.ArgumentNotNull(mediaType, "mediaType"); + public static readonly MimeMediaType Zip = Parse("application/zip"); + } - string[] parts = mediaType.Split('/'); - if (parts.Length > 2) - { - throw new ArgumentException("invalid mediaType"); - } - - if (parts.Length == 1) - { - return new MimeMediaType(parts[0]); - } - else - { - return new MimeMediaType(parts[0], parts[1]); - } - } - - #endregion Static Methods - - private readonly string _contentType; - private readonly string _subType; + /// + /// Predefines common image media types + /// + public sealed class Image + { + /// + /// Represents "image/gif" + /// + public static readonly MimeMediaType Gif = Parse("image/gif"); /// - /// Creates a new media type instance representing a generic "application/octet-stream" + /// Represents "image/jpeg" /// - public MimeMediaType() - :this("application", "octet-stream") - { - } + public static readonly MimeMediaType Jpeg = Parse("image/jpeg"); /// - /// Creates a new media type instance representing a generic content type - /// with an unspecified subtype (e.g. "text/*") + /// Represents "image/tiff" /// - public MimeMediaType(string contentType) - : this(contentType, "*") - { - } + public static readonly MimeMediaType Tiff = Parse("image/tiff"); + } + + /// + /// Predefines common text media types + /// + public sealed class Text + { + /// + /// Represents "text/html" + /// + public static readonly MimeMediaType Html = Parse("text/html"); /// - /// Creates a new media type instance representing a particular media type + /// Represents "text/plain" /// - public MimeMediaType(string contentType, string subType) - { - _contentType = contentType.ToLower(); - if (!ContentTypes.Contains(_contentType)) - { - throw new ArgumentException("unknown content type", "contentType"); - } - _subType = (StringUtils.HasText(subType)) ? subType.ToLower() : "*"; - } + public static readonly MimeMediaType Plain = Parse("text/plain"); /// - /// Gets the content type of this media type instance + /// Represents "text/richtext" /// - public string ContentType - { - get { return _contentType; } - } + public static readonly MimeMediaType RichText = Parse("text/richtext"); /// - /// Gets the subtype of this media type instance + /// Represents "text/xml" /// - public string SubType - { - get { return _subType; } - } + public static readonly MimeMediaType Xml = Parse("text/xml"); /// - /// Returns a string representation of this instance. + /// Represents "text/javascript" /// - public override string ToString() - { - return string.Format("{0}/{1}", _contentType, _subType); - } + public static readonly MimeMediaType Javascript = Parse("text/javascript"); /// - /// Compares this instance to another + /// Represents "text/css" /// - /// another instance - protected bool Equals(MimeMediaType other) + public static readonly MimeMediaType Css = Parse("text/css"); + } + + #endregion + + #region Static Methods + + /// + /// Parses a string into a instance. + /// + /// a valid string representation of a mediaType + /// a new instance + public static MimeMediaType Parse(string mediaType) + { + AssertUtils.ArgumentNotNull(mediaType, "mediaType"); + + string[] parts = mediaType.Split('/'); + if (parts.Length > 2) { - if (other == null) return false; - return Equals(_contentType, other._contentType) && Equals(_subType, other._subType); + throw new ArgumentException("invalid mediaType"); } - /// - ///Determines whether the specified is equal to the current . - /// - /// - ///true if the specified is equal to the current ; otherwise, false. - /// - ///The to compare with the current . - public override bool Equals(object obj) + if (parts.Length == 1) { - if (ReferenceEquals(this, obj)) return true; - return Equals(obj as MimeMediaType); + return new MimeMediaType(parts[0]); } - - /// - ///Serves as a hash function for a particular type. is suitable for use in hashing algorithms and data structures like a hash table. - /// - /// - ///A hash code for the current . - /// - public override int GetHashCode() + else { - return _contentType.GetHashCode() + 29*_subType.GetHashCode(); + return new MimeMediaType(parts[0], parts[1]); } } + + #endregion Static Methods + + private readonly string _contentType; + private readonly string _subType; + + /// + /// Creates a new media type instance representing a generic "application/octet-stream" + /// + public MimeMediaType() + : this("application", "octet-stream") + { + } + + /// + /// Creates a new media type instance representing a generic content type + /// with an unspecified subtype (e.g. "text/*") + /// + public MimeMediaType(string contentType) + : this(contentType, "*") + { + } + + /// + /// Creates a new media type instance representing a particular media type + /// + public MimeMediaType(string contentType, string subType) + { + _contentType = contentType.ToLower(); + if (!ContentTypes.Contains(_contentType)) + { + throw new ArgumentException("unknown content type", "contentType"); + } + + _subType = (StringUtils.HasText(subType)) ? subType.ToLower() : "*"; + } + + /// + /// Gets the content type of this media type instance + /// + public string ContentType + { + get { return _contentType; } + } + + /// + /// Gets the subtype of this media type instance + /// + public string SubType + { + get { return _subType; } + } + + /// + /// Returns a string representation of this instance. + /// + public override string ToString() + { + return string.Format("{0}/{1}", _contentType, _subType); + } + + /// + /// Compares this instance to another + /// + /// another instance + protected bool Equals(MimeMediaType other) + { + if (other == null) return false; + return Equals(_contentType, other._contentType) && Equals(_subType, other._subType); + } + + /// + ///Determines whether the specified is equal to the current . + /// + /// + ///true if the specified is equal to the current ; otherwise, false. + /// + ///The to compare with the current . + public override bool Equals(object obj) + { + if (ReferenceEquals(this, obj)) return true; + return Equals(obj as MimeMediaType); + } + + /// + ///Serves as a hash function for a particular type. is suitable for use in hashing algorithms and data structures like a hash table. + /// + /// + ///A hash code for the current . + /// + public override int GetHashCode() + { + return _contentType.GetHashCode() + 29 * _subType.GetHashCode(); + } } diff --git a/src/Spring/Spring.Web/Web/Support/PageHandlerFactory.cs b/src/Spring/Spring.Web/Web/Support/PageHandlerFactory.cs index 2badcc8f..c8614715 100644 --- a/src/Spring/Spring.Web/Web/Support/PageHandlerFactory.cs +++ b/src/Spring/Spring.Web/Web/Support/PageHandlerFactory.cs @@ -22,7 +22,6 @@ using System.Collections; using System.Web; - using Spring.Context; using Spring.Context.Support; using Spring.Objects; @@ -31,90 +30,89 @@ using Spring.Util; #endregion -namespace Spring.Web.Support +namespace Spring.Web.Support; + +/// +/// Implementation of that retrieves +/// configured instances from Spring web application context. +/// +/// +/// +/// This handler factory uses the page name from the URL, without the extension, +/// to find the handler object in the Spring context. This means that the target object +/// definition doesn't need to resolve to an .aspx page -- it can be any valid +/// object that implements interface. +/// +/// +/// If the specified page is not found in the Spring application context, this +/// handler factory falls back to the standard ASP.NET behavior and tries +/// to find physical page with a given name. +/// +/// +/// In either case, handlers that implement +/// and will be provided with the references +/// to appropriate Spring.NET application context (based on the request URL) +/// and a that should be used to store the information +/// that needs to be shared by all instances of the handler. +/// +/// +/// Aleksandar Seovic +public class PageHandlerFactory : AbstractHandlerFactory { /// - /// Implementation of that retrieves - /// configured instances from Spring web application context. + /// Retrieves instance of the configured page from Spring web application context, + /// or if page is not defined in Spring config file tries to find it using standard + /// ASP.Net mechanism. /// - /// - /// - /// This handler factory uses the page name from the URL, without the extension, - /// to find the handler object in the Spring context. This means that the target object - /// definition doesn't need to resolve to an .aspx page -- it can be any valid - /// object that implements interface. - /// - /// - /// If the specified page is not found in the Spring application context, this - /// handler factory falls back to the standard ASP.NET behavior and tries - /// to find physical page with a given name. - /// - /// - /// In either case, handlers that implement - /// and will be provided with the references - /// to appropriate Spring.NET application context (based on the request URL) - /// and a that should be used to store the information - /// that needs to be shared by all instances of the handler. - /// - /// - /// Aleksandar Seovic - public class PageHandlerFactory : AbstractHandlerFactory + /// Current HttpContext + /// Type of HTTP request (GET, POST, etc.) + /// Requested page URL + /// Translated server path for the page + /// Instance of the IHttpHandler object that should be used to process request. + public override IHttpHandler GetHandler(HttpContext context, string requestType, string url, string physicalPath) { - /// - /// Retrieves instance of the configured page from Spring web application context, - /// or if page is not defined in Spring config file tries to find it using standard - /// ASP.Net mechanism. - /// - /// Current HttpContext - /// Type of HTTP request (GET, POST, etc.) - /// Requested page URL - /// Translated server path for the page - /// Instance of the IHttpHandler object that should be used to process request. - public override IHttpHandler GetHandler(HttpContext context, string requestType, string url, string physicalPath) + return base.GetHandler(context, requestType, url, physicalPath); + } + + /// + /// Create a handler instance for the given URL. + /// + /// the application context corresponding to the current request + /// The instance for this request. + /// The HTTP data transfer method (GET, POST, ...) + /// The requested . + /// The physical path of the requested resource. + /// A handler instance for the current request. + protected override IHttpHandler CreateHandlerInstance(IConfigurableApplicationContext appContext, HttpContext context, string requestType, string rawUrl, string physicalPath) + { + IHttpHandler handler; + + string appRelativeVirtualPath = WebUtils.GetAppRelativePath(rawUrl); + NamedObjectDefinition namedPageDefinition = FindWebObjectDefinition(appRelativeVirtualPath, appContext.ObjectFactory); + + if (namedPageDefinition != null) { - return base.GetHandler(context, requestType, url, physicalPath); - } - - /// - /// Create a handler instance for the given URL. - /// - /// the application context corresponding to the current request - /// The instance for this request. - /// The HTTP data transfer method (GET, POST, ...) - /// The requested . - /// The physical path of the requested resource. - /// A handler instance for the current request. - protected override IHttpHandler CreateHandlerInstance(IConfigurableApplicationContext appContext, HttpContext context, string requestType, string rawUrl, string physicalPath) - { - IHttpHandler handler; - - string appRelativeVirtualPath = WebUtils.GetAppRelativePath(rawUrl); - NamedObjectDefinition namedPageDefinition = FindWebObjectDefinition(appRelativeVirtualPath, appContext.ObjectFactory); - - if (namedPageDefinition != null) + // is this a nested call (HttpServerUtility.Transfer() or HttpServerUtility.Execute())? + if (context.Handler != null) { - // is this a nested call (HttpServerUtility.Transfer() or HttpServerUtility.Execute())? - if (context.Handler != null) - { - // all deps can/must be resolved now - handler = (IHttpHandler)appContext.GetObject(namedPageDefinition.Name, typeof(IHttpHandler), null); - } - else - { - // execution pipeline "entry-point" - create page instance only - // and defer configuration to PreRequestHandlerExecute step - handler = (IHttpHandler)appContext.CreateObject(namedPageDefinition.Name, typeof(IHttpHandler), null); - WebSupportModule.ConfigureHandler(context, handler, appContext, namedPageDefinition.Name, true); - } + // all deps can/must be resolved now + handler = (IHttpHandler) appContext.GetObject(namedPageDefinition.Name, typeof(IHttpHandler), null); } else { - handler = WebObjectUtils.CreateHandler(rawUrl); - // let WebSupportModule handle configuration - handler = WebSupportModule.ConfigureHandler(context, handler, appContext, rawUrl, false); + // execution pipeline "entry-point" - create page instance only + // and defer configuration to PreRequestHandlerExecute step + handler = (IHttpHandler) appContext.CreateObject(namedPageDefinition.Name, typeof(IHttpHandler), null); + WebSupportModule.ConfigureHandler(context, handler, appContext, namedPageDefinition.Name, true); } - - return handler; } + else + { + handler = WebObjectUtils.CreateHandler(rawUrl); + // let WebSupportModule handle configuration + handler = WebSupportModule.ConfigureHandler(context, handler, appContext, rawUrl, false); + } + + return handler; } } diff --git a/src/Spring/Spring.Web/Web/Support/Result.cs b/src/Spring/Spring.Web/Web/Support/Result.cs index d439b00d..fb40bc63 100644 --- a/src/Spring/Spring.Web/Web/Support/Result.cs +++ b/src/Spring/Spring.Web/Web/Support/Result.cs @@ -29,485 +29,490 @@ using Spring.Util; #endregion -namespace Spring.Web.Support +namespace Spring.Web.Support; + +/// +/// Represents the ASPX result page that an operation maps to. +/// +/// +///

+/// Parameters can reference variables accessible from the page using the +/// standard NAnt style property notation, namely ${varName}. +///

+///

+/// The result that is passed as the sole +/// parameter to the parameterized constructor +/// () must adhere to the +/// following format: +///

+/// +/// [<mode>:]<targetPage>[?param1,param2,...,paramN] +/// +///

+/// Only the targetPage is mandatory. +///

+///
+/// +///

+/// Examples of valid values that can be passed +/// to the the parameterized constructor +/// () include: +///

+///

+/// +/// Login.aspx +/// ~/Login.aspx +/// redirect:~/Login.aspx +/// transfer:~/Login.aspx +/// transfer:Services/Register.aspx +/// Login.aspx?username=springboy,password=7623AAjoe +/// redirect:Login.aspx?username=springboy,password=7623AAjoe +/// +///

+///
+/// Aleksandar Seovic +/// Matan Shapira +[Serializable] +public class Result : IResult { + #region Constants + /// - /// Represents the ASPX result page that an operation maps to. + /// The default . /// /// ///

- /// Parameters can reference variables accessible from the page using the - /// standard NAnt style property notation, namely ${varName}. + /// Currently defaults to . ///

+ ///
+ /// + public const ResultMode DefaultResultMode = ResultMode.Transfer; + + #endregion + + #region Fields + + private ResultMode mode = DefaultResultMode; + private string targetPage; + private IDictionary parameters; + + #endregion + + #region Constructor (s) / Destructor + + /// + /// Creates a new instance of the class. + /// + public Result() + { + } + + /// + /// Creates a new instance of the class. + /// + /// ///

- /// The result that is passed as the sole - /// parameter to the parameterized constructor - /// () must adhere to the - /// following format: + /// See both the class documentation () + /// and the reference documentation for the Spring.Web library for a + /// discussion and examples of what values the supplied + /// can have. ///

- /// - /// [<mode>:]<targetPage>[?param1,param2,...,paramN] - /// + ///
+ /// The result descriptor. + /// + /// If the supplied is or + /// contains only whitespace character(s). + /// + /// if the result mode is unknown. + public Result(string result) + { + AssertUtils.ArgumentHasText(result, "result"); + + result = ExtractAndSetResultMode(result); + + int indexOfQueryStringDelimiter = result.IndexOf('?'); + if (indexOfQueryStringDelimiter > 0) + { + ParseParameters(result.Substring(indexOfQueryStringDelimiter + 1)); + result = result.Substring(0, indexOfQueryStringDelimiter); + } + + targetPage = result.Trim(); + } + + /// + /// Creates a new instance of the class. + /// + /// ///

- /// Only the targetPage is mandatory. + /// See both the class documentation () + /// and the reference documentation for the Spring.Web library for a + /// discussion and examples of what values the supplied + /// can have. + ///

+ ///
+ /// The desired result mode. May be null to use default mode. + /// The result descriptor (without resultMode prefix!). + /// + /// If the supplied is or + /// contains only whitespace character(s). + /// + /// if the result mode is unknown. + public Result(string resultMode, string resultText) + { + AssertUtils.ArgumentHasText(resultText, "resultText"); + + this.SetResultMode(resultMode); + + string result = resultText; + int indexOfQueryStringDelimiter = result.IndexOf('?'); + if (indexOfQueryStringDelimiter > 0) + { + ParseParameters(result.Substring(indexOfQueryStringDelimiter + 1)); + result = result.Substring(0, indexOfQueryStringDelimiter); + } + + targetPage = result.Trim(); + } + + #endregion + + #region Properties + + /// + /// The . Defines which + /// method will be used to navigate to the + /// . + /// + public ResultMode Mode + { + get { return mode; } + set { mode = value; } + } + + /// + /// The target page. + /// + /// + ///

+ /// This is the (relative) path to the target page. ///

///
/// ///

- /// Examples of valid values that can be passed - /// to the the parameterized constructor - /// () include: + /// Examples of valid values would be: ///

///

/// /// Login.aspx /// ~/Login.aspx - /// redirect:~/Login.aspx - /// transfer:~/Login.aspx - /// transfer:Services/Register.aspx - /// Login.aspx?username=springboy,password=7623AAjoe - /// redirect:Login.aspx?username=springboy,password=7623AAjoe + /// ~/B2B/SignUp.aspx + /// B2B/Foo/FooServices.aspx /// ///

///
- /// Aleksandar Seovic - /// Matan Shapira - [Serializable] - public class Result : IResult + public string TargetPage { - #region Constants + get { return targetPage; } + set { targetPage = value; } + } - /// - /// The default . - /// - /// - ///

- /// Currently defaults to . - ///

- ///
- /// - public const ResultMode DefaultResultMode = ResultMode.Transfer; + /// + /// The parameters thar are to be passed to the + /// upon + /// navigation. + /// + public IDictionary Parameters + { + get { return parameters; } + set { parameters = value; } + } - #endregion + /// + /// Indicates, if should be called with preserveForm='true' | 'false'. Only relevant for ResultMode.TransferXXXX modes. + /// + public bool PreserveForm + { + get { return (Mode == ResultMode.Transfer); } + } - #region Fields + /// + /// Indicates, if should be called with endResponse='true' | 'false'. Only relevant for ResultMode.RedirectXXXX modes. + /// + public bool EndResponse + { + get { return (Mode == ResultMode.Redirect); } + } - private ResultMode mode = DefaultResultMode; - private string targetPage; - private IDictionary parameters; + #endregion - #endregion - - #region Constructor (s) / Destructor - - /// - /// Creates a new instance of the class. - /// - public Result() - { } - - /// - /// Creates a new instance of the class. - /// - /// - ///

- /// See both the class documentation () - /// and the reference documentation for the Spring.Web library for a - /// discussion and examples of what values the supplied - /// can have. - ///

- ///
- /// The result descriptor. - /// - /// If the supplied is or - /// contains only whitespace character(s). - /// - /// if the result mode is unknown. - public Result( string result ) + /// + /// Navigates to the + /// defined by this result. + /// + /// + /// The context object for parameter resolution. This is typically + /// a . + /// + public virtual void Navigate(object context) + { + switch (Mode) { - AssertUtils.ArgumentHasText( result, "result" ); + case ResultMode.Redirect: + case ResultMode.RedirectNoAbort: + DoRedirect(context); + break; + case ResultMode.Transfer: + case ResultMode.TransferNoPreserve: + DoTransfer(context); + break; + default: + throw new ArgumentOutOfRangeException(string.Format("Unknown ResultMode {0}", Mode)); + } + } - result = ExtractAndSetResultMode( result ); + /// + /// Performs a server-side transfer to the + /// defined by this result. + /// + /// + /// The context object for parameter resolution. This is typically + /// a . + /// + /// + protected virtual void DoTransfer(object context) + { + HttpContext ctx = HttpContext.Current; + SetTransferParameters(ctx.Items, context); + ctx.Server.Transfer(GetResolvedTargetPage(context), PreserveForm); + } - int indexOfQueryStringDelimiter = result.IndexOf( '?' ); - if (indexOfQueryStringDelimiter > 0) + /// + /// Resolves transfer parameters and stores them into instance. + /// + /// + /// + protected void SetTransferParameters(IDictionary contextDictionary, object context) + { + if (this.parameters != null && this.parameters.Count > 0) + { + foreach (DictionaryEntry entry in this.parameters) { - ParseParameters( result.Substring( indexOfQueryStringDelimiter + 1 ) ); - result = result.Substring( 0, indexOfQueryStringDelimiter ); - } - targetPage = result.Trim(); - } - - /// - /// Creates a new instance of the class. - /// - /// - ///

- /// See both the class documentation () - /// and the reference documentation for the Spring.Web library for a - /// discussion and examples of what values the supplied - /// can have. - ///

- ///
- /// The desired result mode. May be null to use default mode. - /// The result descriptor (without resultMode prefix!). - /// - /// If the supplied is or - /// contains only whitespace character(s). - /// - /// if the result mode is unknown. - public Result( string resultMode, string resultText ) - { - AssertUtils.ArgumentHasText( resultText, "resultText" ); - - this.SetResultMode( resultMode ); - - string result = resultText; - int indexOfQueryStringDelimiter = result.IndexOf( '?' ); - if (indexOfQueryStringDelimiter > 0) - { - ParseParameters( result.Substring( indexOfQueryStringDelimiter + 1 ) ); - result = result.Substring( 0, indexOfQueryStringDelimiter ); - } - targetPage = result.Trim(); - } - - #endregion - - #region Properties - - /// - /// The . Defines which - /// method will be used to navigate to the - /// . - /// - public ResultMode Mode - { - get { return mode; } - set { mode = value; } - } - - /// - /// The target page. - /// - /// - ///

- /// This is the (relative) path to the target page. - ///

- ///
- /// - ///

- /// Examples of valid values would be: - ///

- ///

- /// - /// Login.aspx - /// ~/Login.aspx - /// ~/B2B/SignUp.aspx - /// B2B/Foo/FooServices.aspx - /// - ///

- ///
- public string TargetPage - { - get { return targetPage; } - set { targetPage = value; } - } - - /// - /// The parameters thar are to be passed to the - /// upon - /// navigation. - /// - public IDictionary Parameters - { - get { return parameters; } - set { parameters = value; } - } - - /// - /// Indicates, if should be called with preserveForm='true' | 'false'. Only relevant for ResultMode.TransferXXXX modes. - /// - public bool PreserveForm - { - get { return (Mode == ResultMode.Transfer); } - } - - /// - /// Indicates, if should be called with endResponse='true' | 'false'. Only relevant for ResultMode.RedirectXXXX modes. - /// - public bool EndResponse - { - get { return (Mode == ResultMode.Redirect); } - } - - #endregion - - /// - /// Navigates to the - /// defined by this result. - /// - /// - /// The context object for parameter resolution. This is typically - /// a . - /// - public virtual void Navigate( object context ) - { - switch (Mode) - { - case ResultMode.Redirect: - case ResultMode.RedirectNoAbort: - DoRedirect( context ); - break; - case ResultMode.Transfer: - case ResultMode.TransferNoPreserve: - DoTransfer( context ); - break; - default: - throw new ArgumentOutOfRangeException( string.Format( "Unknown ResultMode {0}", Mode ) ); - } - } - - /// - /// Performs a server-side transfer to the - /// defined by this result. - /// - /// - /// The context object for parameter resolution. This is typically - /// a . - /// - /// - protected virtual void DoTransfer( object context ) - { - HttpContext ctx = HttpContext.Current; - SetTransferParameters( ctx.Items, context ); - ctx.Server.Transfer( GetResolvedTargetPage( context ), PreserveForm ); - } - - /// - /// Resolves transfer parameters and stores them into instance. - /// - /// - /// - protected void SetTransferParameters( IDictionary contextDictionary, object context ) - { - if (this.parameters != null && this.parameters.Count > 0) - { - foreach (DictionaryEntry entry in this.parameters) + string value = entry.Value.ToString(); + if (IsSpELRuntimeExpression(value)) { - string value = entry.Value.ToString(); - if (IsSpELRuntimeExpression( value )) - { - contextDictionary[entry.Key] = ResolveValueIfNecessary( context, value ); - } - else - { - contextDictionary[entry.Key] = entry.Value; - } + contextDictionary[entry.Key] = ResolveValueIfNecessary(context, value); + } + else + { + contextDictionary[entry.Key] = entry.Value; } } } + } - /// - /// Performs a redirect to the - /// defined by this - /// result. - /// - /// - /// The context object for parameter resolution. This is typically - /// a . - /// - /// - protected virtual void DoRedirect( object context ) + /// + /// Performs a redirect to the + /// defined by this + /// result. + /// + /// + /// The context object for parameter resolution. This is typically + /// a . + /// + /// + protected virtual void DoRedirect(object context) + { + HttpContext.Current.Response.Redirect(GetRedirectUri(context), EndResponse); + } + + /// + /// Returns a redirect url string that points to the + /// defined by this + /// result. + /// + /// + /// A redirect url string. + /// + public virtual string GetRedirectUri(object context) + { + string path = GetResolvedTargetPage(context); + + IDictionary resolvedParameters = null; + if (this.Parameters != null && this.Parameters.Count > 0) { - HttpContext.Current.Response.Redirect( GetRedirectUri( context ), EndResponse ); + resolvedParameters = new CaseInsensitiveHashtable(); + foreach (DictionaryEntry entry in this.Parameters) + { + object key = ResolveValueIfNecessary(context, entry.Key.ToString()); + object value = ResolveValueIfNecessary(context, entry.Value.ToString()); + resolvedParameters[key] = value; + } } - /// - /// Returns a redirect url string that points to the - /// defined by this - /// result. - /// - /// - /// A redirect url string. - /// - public virtual string GetRedirectUri( object context ) - { - string path = GetResolvedTargetPage( context ); + return BuildUrl(path, resolvedParameters); + } - IDictionary resolvedParameters = null; - if (this.Parameters != null && this.Parameters.Count > 0) + /// + /// Construct the actual url to be executed or returned. + /// + /// the already evaluated + /// the already evaluated parameters. + /// the url to be returned by + protected virtual string BuildUrl(string resolvedPath, IDictionary resolvedParameters) + { + StringBuilder url = new StringBuilder(256); + url.Append(resolvedPath); + if (resolvedParameters != null && resolvedParameters.Count > 0) + { + char separator = '?'; + foreach (DictionaryEntry entry in resolvedParameters) { - resolvedParameters = new CaseInsensitiveHashtable(); - foreach (DictionaryEntry entry in this.Parameters) + url.Append(separator); + url = BuildUrlParameter(url, entry.Key.ToString(), entry.Value.ToString()); + separator = '&'; + } + } + + return url.ToString(); + } + + /// + /// Append the url parameter to the url being constructed. + /// + /// the containing the url constructed so far. + /// the parameter key + /// the parameter value + /// the to use for further url construction. + protected virtual StringBuilder BuildUrlParameter(StringBuilder url, string key, string value) + { + url.Append(WebUtils.UrlEncode(key)) + .Append('=') + .Append(WebUtils.UrlEncode(value)); + + return url; + } + + /// + /// Evaluates within and returns the evaluation result. + /// + /// the context to be used for evaluation. + /// the string that might need evaluation + /// the evaluation result. Unodified if no evalution occured. + protected virtual object ResolveValueIfNecessary(object context, string value) + { + return ResolveSpELRuntimeExpressionIfNecessary(context, value); + } + + /// + /// Checks, if value is a SpEL expression ${expression} or %{expression}. + /// + private static bool IsSpELRuntimeExpression(string value) + { + // allow for 2 alternative prefixes (SPRNET-864) + return (value.StartsWith("${") || value.StartsWith("%{")) && value.EndsWith("}"); + } + + /// + /// If is a SpEL expression (${expression} or %{expression}), evaluates + /// the value against . + /// + protected static object ResolveSpELRuntimeExpressionIfNecessary(object context, string value) + { + AssertUtils.ArgumentNotNull(value, "value"); + + if (IsSpELRuntimeExpression(value)) + { + return ExpressionEvaluator.GetValue(context, value.Substring(2, value.Length - 3)); + } + + return value; + } + + /// + /// Extracts and sets this instance's + /// property from the supplied descriptor. + /// + /// + ///

+ /// The supplied descriptor is typically + /// something like /Foo.aspx or + /// redirect:http://www.springframework.net/. + ///

+ ///
+ /// + /// The result descriptor. + /// + /// + /// The supplied without the result mode + /// prefix (if any). + /// + /// + /// If the supplied starts with an illegal + /// result mode (see ). + /// + private string ExtractAndSetResultMode(string result) + { + int indexOfResultModeDelimiter = result.IndexOf(':'); + if (indexOfResultModeDelimiter > 0) + { + string resultMode = result.Substring(0, indexOfResultModeDelimiter); + SetResultMode(resultMode); + return result.Substring(indexOfResultModeDelimiter + 1); + } + + return result; + } + + /// + /// Set the actual from the parsed string. + /// + /// the parsed result mode + protected virtual void SetResultMode(string resultMode) + { + try + { + if (StringUtils.HasText(resultMode)) + { + Mode = (ResultMode) Enum.Parse(typeof(ResultMode), resultMode, true); + } + } + catch + { + throw new ArgumentOutOfRangeException("resultMode", resultMode, "Illegal result mode."); + } + } + + /// + /// Resolves dynamic expression contained in if any by calling . + /// + /// the context to be used for evaluating the expression + /// the evaluated expression + protected string GetResolvedTargetPage(object context) + { + return ResolveValueIfNecessary(context, TargetPage).ToString(); + } + + /// + /// Parses query parameters from the supplied . + /// + /// + /// The query string (may be ). + /// + private void ParseParameters(string queryString) + { + if (StringUtils.HasText(queryString)) + { + this.parameters = new CaseInsensitiveHashtable(); + string[] nameValuePairs = queryString.Split("&,".ToCharArray()); + foreach (string pair in nameValuePairs) + { + int n = pair.IndexOf('='); + if (n > 0) { - object key = ResolveValueIfNecessary( context, entry.Key.ToString() ); - object value = ResolveValueIfNecessary( context, entry.Value.ToString() ); - resolvedParameters[key] = value; - } - } - - return BuildUrl( path, resolvedParameters ); - } - - /// - /// Construct the actual url to be executed or returned. - /// - /// the already evaluated - /// the already evaluated parameters. - /// the url to be returned by - protected virtual string BuildUrl( string resolvedPath, IDictionary resolvedParameters ) - { - StringBuilder url = new StringBuilder( 256 ); - url.Append( resolvedPath ); - if (resolvedParameters != null && resolvedParameters.Count > 0) - { - char separator = '?'; - foreach (DictionaryEntry entry in resolvedParameters) - { - url.Append( separator ); - url = BuildUrlParameter( url, entry.Key.ToString(), entry.Value.ToString() ); - separator = '&'; - } - } - return url.ToString(); - } - - /// - /// Append the url parameter to the url being constructed. - /// - /// the containing the url constructed so far. - /// the parameter key - /// the parameter value - /// the to use for further url construction. - protected virtual StringBuilder BuildUrlParameter( StringBuilder url, string key, string value ) - { - url.Append( WebUtils.UrlEncode( key ) ) - .Append( '=' ) - .Append( WebUtils.UrlEncode( value ) ); - - return url; - } - - /// - /// Evaluates within and returns the evaluation result. - /// - /// the context to be used for evaluation. - /// the string that might need evaluation - /// the evaluation result. Unodified if no evalution occured. - protected virtual object ResolveValueIfNecessary( object context, string value ) - { - return ResolveSpELRuntimeExpressionIfNecessary( context, value ); - } - - /// - /// Checks, if value is a SpEL expression ${expression} or %{expression}. - /// - private static bool IsSpELRuntimeExpression( string value ) - { - // allow for 2 alternative prefixes (SPRNET-864) - return (value.StartsWith( "${" ) || value.StartsWith( "%{" )) && value.EndsWith( "}" ); - } - - /// - /// If is a SpEL expression (${expression} or %{expression}), evaluates - /// the value against . - /// - protected static object ResolveSpELRuntimeExpressionIfNecessary( object context, string value ) - { - AssertUtils.ArgumentNotNull(value, "value"); - - if (IsSpELRuntimeExpression( value )) - { - return ExpressionEvaluator.GetValue( context, value.Substring( 2, value.Length - 3 ) ); - } - return value; - } - - /// - /// Extracts and sets this instance's - /// property from the supplied descriptor. - /// - /// - ///

- /// The supplied descriptor is typically - /// something like /Foo.aspx or - /// redirect:http://www.springframework.net/. - ///

- ///
- /// - /// The result descriptor. - /// - /// - /// The supplied without the result mode - /// prefix (if any). - /// - /// - /// If the supplied starts with an illegal - /// result mode (see ). - /// - private string ExtractAndSetResultMode( string result ) - { - int indexOfResultModeDelimiter = result.IndexOf( ':' ); - if (indexOfResultModeDelimiter > 0) - { - string resultMode = result.Substring( 0, indexOfResultModeDelimiter ); - SetResultMode( resultMode ); - return result.Substring( indexOfResultModeDelimiter + 1 ); - } - return result; - } - - /// - /// Set the actual from the parsed string. - /// - /// the parsed result mode - protected virtual void SetResultMode( string resultMode ) - { - try - { - if (StringUtils.HasText( resultMode )) - { - Mode = (ResultMode)Enum.Parse( typeof( ResultMode ), resultMode, true ); - } - } - catch - { - throw new ArgumentOutOfRangeException( "resultMode", resultMode, "Illegal result mode." ); - } - } - - /// - /// Resolves dynamic expression contained in if any by calling . - /// - /// the context to be used for evaluating the expression - /// the evaluated expression - protected string GetResolvedTargetPage( object context ) - { - return ResolveValueIfNecessary( context, TargetPage ).ToString(); - } - - /// - /// Parses query parameters from the supplied . - /// - /// - /// The query string (may be ). - /// - private void ParseParameters( string queryString ) - { - if (StringUtils.HasText( queryString )) - { - this.parameters = new CaseInsensitiveHashtable(); - string[] nameValuePairs = queryString.Split( "&,".ToCharArray() ); - foreach (string pair in nameValuePairs) - { - int n = pair.IndexOf( '=' ); - if (n > 0) - { - string name = pair.Substring( 0, n ); - string val = pair.Substring( n + 1 ).Trim(); - this.parameters[name] = val; - } + string name = pair.Substring(0, n); + string val = pair.Substring(n + 1).Trim(); + this.parameters[name] = val; } } } diff --git a/src/Spring/Spring.Web/Web/Support/ResultFactoryRegistry.cs b/src/Spring/Spring.Web/Web/Support/ResultFactoryRegistry.cs index 5cd104af..fa875aa2 100644 --- a/src/Spring/Spring.Web/Web/Support/ResultFactoryRegistry.cs +++ b/src/Spring/Spring.Web/Web/Support/ResultFactoryRegistry.cs @@ -27,175 +27,174 @@ using Spring.Web.UI; #endregion -namespace Spring.Web.Support +namespace Spring.Web.Support; + +/// +/// A result factory is responsible for create an instance from a given string representation. +/// +/// +/// +/// Factories get registered with the for a certain resultMode string. +/// uses for converting strings into instances +/// implementing the corresponding navigation logic. +/// +/// +/// Result string representations are always of the form:
+/// "<resultmode>:<textual result representation>"
+/// Calling on the registry will cause the registry to first extract the leading resultmode to obtain +/// the corresponding instance and handle the actual instantiation by delegating to +/// . +///
+/// +/// The following example illustrates the usual flow: +/// +/// class MySpecialResultLogic : IResult +/// { +/// ... +/// } +/// +/// class MySpecialResultLogicFactory : IResultFactory +/// { +/// IResult Create( string mode, string expression ) { /* ... convert 'expression' into +/// MySpecialResultLogic */ } +/// } +/// +/// // register with global factory +/// ResultFactoryRegistry.RegisterResultFactory( "mySpecialMode", new MySpecialResultLogicFactory ); +/// +/// // configure your Results +/// <object type="mypage.aspx"> +/// <property name="Results"> +/// <dictionary> +/// <entry key="continue" value="mySpecialMode:<some MySpecialResultLogic string representation>" /> +/// </dictionary> +/// </property> +/// +/// // on your page call +/// myPage.SetResult("continue"); +/// +/// +///
+/// +/// +/// +/// +/// +/// +/// Erich Eichinger +public class ResultFactoryRegistry { - /// - /// A result factory is responsible for create an instance from a given string representation. - /// - /// - /// - /// Factories get registered with the for a certain resultMode string. - /// uses for converting strings into instances - /// implementing the corresponding navigation logic. - /// - /// - /// Result string representations are always of the form:
- /// "<resultmode>:<textual result representation>"
- /// Calling on the registry will cause the registry to first extract the leading resultmode to obtain - /// the corresponding instance and handle the actual instantiation by delegating to - /// . - ///
- /// - /// The following example illustrates the usual flow: - /// - /// class MySpecialResultLogic : IResult - /// { - /// ... - /// } - /// - /// class MySpecialResultLogicFactory : IResultFactory - /// { - /// IResult Create( string mode, string expression ) { /* ... convert 'expression' into - /// MySpecialResultLogic */ } - /// } - /// - /// // register with global factory - /// ResultFactoryRegistry.RegisterResultFactory( "mySpecialMode", new MySpecialResultLogicFactory ); - /// - /// // configure your Results - /// <object type="mypage.aspx"> - /// <property name="Results"> - /// <dictionary> - /// <entry key="continue" value="mySpecialMode:<some MySpecialResultLogic string representation>" /> - /// </dictionary> - /// </property> - /// - /// // on your page call - /// myPage.SetResult("continue"); - /// - /// - ///
- /// - /// - /// - /// - /// - /// - /// Erich Eichinger - public class ResultFactoryRegistry + private static readonly IDictionary s_registeredFactories = new CaseInsensitiveHashtable(); + private static volatile IResultFactory s_defaultFactory; + + static ResultFactoryRegistry() { - private static readonly IDictionary s_registeredFactories = new CaseInsensitiveHashtable(); - private static volatile IResultFactory s_defaultFactory; + Reset(); + } - static ResultFactoryRegistry() + /// + /// Resets the factory registry to its defaults. Mainly used for unit testing. + /// + public static void Reset() + { + s_defaultFactory = null; + s_registeredFactories.Clear(); + + SetDefaultFactory(new DefaultResultFactory()); + + foreach (string resultMode in Enum.GetNames(typeof(ResultMode))) { - Reset(); - } - - /// - /// Resets the factory registry to its defaults. Mainly used for unit testing. - /// - public static void Reset() - { - s_defaultFactory = null; - s_registeredFactories.Clear(); - - SetDefaultFactory( new DefaultResultFactory() ); - - foreach(string resultMode in Enum.GetNames(typeof(ResultMode))) - { - RegisterResultMode( resultMode, DefaultResultFactory ); - } - } - - /// - /// Returns the current set by . Will never be null. - /// - /// - /// The default factory is responsible for handling any unknown result modes. - /// - public static IResultFactory DefaultResultFactory - { - get { return s_defaultFactory; } - } - - /// - /// Set a new default factory - /// - /// the new default factory instance. Must not be null. - /// the previous default factory. - public static IResultFactory SetDefaultFactory(IResultFactory resultFactory) - { - AssertUtils.ArgumentNotNull(resultFactory, "resultFactory"); - - IResultFactory prevFactory = s_defaultFactory; - s_defaultFactory = resultFactory; - return prevFactory; - } - - /// - /// Registers a for the specified . - /// - /// the resultMode. Must not be null. - /// the factory respponsible for handling results. Must not be null. - /// the factory previously registered for the specified , if any. - /// - /// See overview for more information. - /// - public static IResultFactory RegisterResultMode( string resultMode, IResultFactory resultFactory ) - { - AssertUtils.ArgumentHasText(resultMode, "resultMode"); - AssertUtils.ArgumentNotNull(resultFactory, "resultFactory"); - - lock (s_registeredFactories.SyncRoot) - { - IResultFactory prevFactory = (IResultFactory) s_registeredFactories[resultMode]; - s_registeredFactories[resultMode] = resultFactory; - return prevFactory; - } - } - - /// - /// Creates a result from the specified by extracting the result mode from - /// the text and delegating to a corresponding , if any. - /// - /// the 'resultmode'-prefixed textual representation of the result instance to create. - /// - /// the instance corresponding to the textual represenation, - /// created by the - /// - /// - /// if either is null or returned null. - /// - /// This method guarantees that the return value will always be non-null.
- /// must always be of the form "<resultmode>:<textual result representation>". - /// The resultmode will be extracted and the corresponding (previously registered - /// using ) is called to actually create the instance. If no factory matches - /// resultmode, the call is handled to the . - ///
- public static IResult CreateResult( string resultText ) - { - AssertUtils.ArgumentNotNull(resultText, "resultText"); - - IResultFactory resultFactory = null; - string resultMode = null; - - int indexOfResultModeDelimiter = resultText.IndexOf( ':' ); - if (indexOfResultModeDelimiter > 0) - { - resultMode = resultText.Substring( 0, indexOfResultModeDelimiter ).Trim(); - resultFactory = (IResultFactory) s_registeredFactories[resultMode]; - resultText = resultText.Substring( indexOfResultModeDelimiter + 1 ); - } - - if (resultFactory == null) - { - resultFactory = s_defaultFactory; - } - - IResult result = resultFactory.CreateResult( resultMode, resultText ); - AssertUtils.ArgumentNotNull(result, "ResultFactories must not return null results"); - return result; + RegisterResultMode(resultMode, DefaultResultFactory); } } + + /// + /// Returns the current set by . Will never be null. + /// + /// + /// The default factory is responsible for handling any unknown result modes. + /// + public static IResultFactory DefaultResultFactory + { + get { return s_defaultFactory; } + } + + /// + /// Set a new default factory + /// + /// the new default factory instance. Must not be null. + /// the previous default factory. + public static IResultFactory SetDefaultFactory(IResultFactory resultFactory) + { + AssertUtils.ArgumentNotNull(resultFactory, "resultFactory"); + + IResultFactory prevFactory = s_defaultFactory; + s_defaultFactory = resultFactory; + return prevFactory; + } + + /// + /// Registers a for the specified . + /// + /// the resultMode. Must not be null. + /// the factory respponsible for handling results. Must not be null. + /// the factory previously registered for the specified , if any. + /// + /// See overview for more information. + /// + public static IResultFactory RegisterResultMode(string resultMode, IResultFactory resultFactory) + { + AssertUtils.ArgumentHasText(resultMode, "resultMode"); + AssertUtils.ArgumentNotNull(resultFactory, "resultFactory"); + + lock (s_registeredFactories.SyncRoot) + { + IResultFactory prevFactory = (IResultFactory) s_registeredFactories[resultMode]; + s_registeredFactories[resultMode] = resultFactory; + return prevFactory; + } + } + + /// + /// Creates a result from the specified by extracting the result mode from + /// the text and delegating to a corresponding , if any. + /// + /// the 'resultmode'-prefixed textual representation of the result instance to create. + /// + /// the instance corresponding to the textual represenation, + /// created by the + /// + /// + /// if either is null or returned null. + /// + /// This method guarantees that the return value will always be non-null.
+ /// must always be of the form "<resultmode>:<textual result representation>". + /// The resultmode will be extracted and the corresponding (previously registered + /// using ) is called to actually create the instance. If no factory matches + /// resultmode, the call is handled to the . + ///
+ public static IResult CreateResult(string resultText) + { + AssertUtils.ArgumentNotNull(resultText, "resultText"); + + IResultFactory resultFactory = null; + string resultMode = null; + + int indexOfResultModeDelimiter = resultText.IndexOf(':'); + if (indexOfResultModeDelimiter > 0) + { + resultMode = resultText.Substring(0, indexOfResultModeDelimiter).Trim(); + resultFactory = (IResultFactory) s_registeredFactories[resultMode]; + resultText = resultText.Substring(indexOfResultModeDelimiter + 1); + } + + if (resultFactory == null) + { + resultFactory = s_defaultFactory; + } + + IResult result = resultFactory.CreateResult(resultMode, resultText); + AssertUtils.ArgumentNotNull(result, "ResultFactories must not return null results"); + return result; + } } diff --git a/src/Spring/Spring.Web/Web/Support/ResultMode.cs b/src/Spring/Spring.Web/Web/Support/ResultMode.cs index 438d8e43..5ec2df1b 100644 --- a/src/Spring/Spring.Web/Web/Support/ResultMode.cs +++ b/src/Spring/Spring.Web/Web/Support/ResultMode.cs @@ -22,51 +22,51 @@ #endregion -namespace Spring.Web.Support +namespace Spring.Web.Support; + +/// +/// The various result modes. +/// +/// Aleksandar Seovic +/// +[Serializable] +public enum ResultMode { /// - /// The various result modes. + /// A server-side transfer. /// - /// Aleksandar Seovic - /// - [Serializable] - public enum ResultMode - { - /// - /// A server-side transfer. - /// - /// - ///

- /// Issues a server-side transfer using the - /// method. - ///

- ///
- /// - Transfer = 0, + /// + ///

+ /// Issues a server-side transfer using the + /// method. + ///

+ ///
+ /// + Transfer = 0, - /// - /// A redirect. - /// - /// - ///

- /// Issues a redirect (to the user-agent - typically a browser) using - /// the method. - ///

- ///
- /// - Redirect = 1, + /// + /// A redirect. + /// + /// + ///

+ /// Issues a redirect (to the user-agent - typically a browser) using + /// the method. + ///

+ ///
+ /// + Redirect = 1, - /// - /// A server-side transfer. - /// - /// - ///

- /// Issues a server-side transfer using the - /// method with parameter 'preserveForm=false'. - ///

- ///
- /// - TransferNoPreserve = 2, + /// + /// A server-side transfer. + /// + /// + ///

+ /// Issues a server-side transfer using the + /// method with parameter 'preserveForm=false'. + ///

+ ///
+ /// + TransferNoPreserve = 2, /// /// A redirect. @@ -78,6 +78,5 @@ namespace Spring.Web.Support ///

/// /// - RedirectNoAbort = 3 - } + RedirectNoAbort = 3 } diff --git a/src/Spring/Spring.Web/Web/Support/Script.cs b/src/Spring/Spring.Web/Web/Support/Script.cs index bf76f311..b8da1ab3 100644 --- a/src/Spring/Spring.Web/Web/Support/Script.cs +++ b/src/Spring/Spring.Web/Web/Support/Script.cs @@ -20,212 +20,214 @@ using Spring.Util; -namespace Spring.Web.Support +namespace Spring.Web.Support; + +/// +/// Base class that describes client side script block or file. +/// +/// +///

+/// Classes that extend this class are used by Spring.Web client-side +/// scripting support. +///

+///
+/// Aleksandar Seovic +internal abstract class Script { + internal static readonly MimeMediaType DefaultType = MimeMediaType.Text.Javascript; + + private string language; + private MimeMediaType type; + /// - /// Base class that describes client side script block or file. + /// Initialize a new Script object of the specified language /// - /// - ///

- /// Classes that extend this class are used by Spring.Web client-side - /// scripting support. - ///

- ///
- /// Aleksandar Seovic - internal abstract class Script + /// Script language. + public Script(string language) { - internal static readonly MimeMediaType DefaultType = MimeMediaType.Text.Javascript; - - private string language; - private MimeMediaType type; - - /// - /// Initialize a new Script object of the specified language - /// - /// Script language. - public Script(string language) - { - this.language = language; - } - - /// - /// Initialize a new script object of the specified type - /// - /// a - public Script(MimeMediaType type) - { - this.Type = type; - } - - /// - /// Gets or sets script language. - /// - public string Language - { - get { return language; } - set { language = value; } - } - - /// - /// Gets or sets script mime type - /// - public MimeMediaType Type - { - get { return type; } - set { AssertUtils.ArgumentNotNull(value, "Type"); type = value; } - } + this.language = language; } /// - /// Class that describes client side script block. + /// Initialize a new script object of the specified type /// - /// - ///

- /// Script blocks are used to insert script code directly into the page, - /// without references to an external file. - ///

- ///
- /// Aleksandar Seovic - internal class ScriptBlock : Script + /// a + public Script(MimeMediaType type) { - private string script; - - /// - /// Default constructor. - /// - /// Script language. - /// The script text. - public ScriptBlock(string language, string script) : base(language) - { - this.script = script; - } - - /// - /// Initialize a new script block instance. - /// - /// the script language's - /// the script body - public ScriptBlock(MimeMediaType type, string script) : base(type) - { - this.script = script; - } - - /// - /// Gets or sets the script text. - /// - /// The script text. - public string Script - { - get { return script; } - set { script = value; } - } + this.Type = type; } /// - /// Class that describes client side script file. + /// Gets or sets script language. /// - /// - ///

- /// Script file references script code in the external file. - ///

- ///
- /// Aleksandar Seovic - internal class ScriptFile : Script + public string Language { - private string fileName; - - /// - /// Initialize a new instance. - /// - /// Script language. - /// The name of the script file. - public ScriptFile(string language, string fileName) : base(language) - { - this.fileName = fileName; - } - - /// - /// Initialize a new instance. - /// - /// the script language's - /// the (virtual) path to the script - public ScriptFile(MimeMediaType type, string fileName) - : base(type) - { - this.fileName = fileName; - } - - /// - /// Gets or sets the name of the script file. - /// - /// The name of the script file. - public string FileName - { - get { return fileName; } - set { fileName = value; } - } + get { return language; } + set { language = value; } } /// - /// Class that describes client side script file. + /// Gets or sets script mime type /// - /// - ///

- /// Script file references script code in the external file. - ///

- ///
- /// Aleksandar Seovic - internal class ScriptEvent : ScriptBlock + public MimeMediaType Type { - private string element; - private string eventName; - - /// - /// Initialize a new instance. - /// - /// Script language. - /// Element ID of the event source. - /// Name of the event to handle. - /// Script text. - public ScriptEvent(string language, string element, string eventName, string script) : base(language, script) + get { return type; } + set { - this.element = element; - this.eventName = eventName; - } - - /// - /// Initialize a new instance. - /// - /// the script language's - /// Element ID of the event source. - /// Name of the event to handle. - /// Script text. - public ScriptEvent(MimeMediaType type, string element, string eventName, string script) - : base(type, script) - { - this.element = element; - this.eventName = eventName; - } - - /// - /// Gets or sets the element ID. - /// - /// The element ID. - public string Element - { - get { return element; } - set { element = value; } - } - - /// - /// Gets or sets the name of the event. - /// - /// The name of the event. - public string EventName - { - get { return eventName; } - set { eventName = value; } + AssertUtils.ArgumentNotNull(value, "Type"); + type = value; } } +} -} \ No newline at end of file +/// +/// Class that describes client side script block. +/// +/// +///

+/// Script blocks are used to insert script code directly into the page, +/// without references to an external file. +///

+///
+/// Aleksandar Seovic +internal class ScriptBlock : Script +{ + private string script; + + /// + /// Default constructor. + /// + /// Script language. + /// The script text. + public ScriptBlock(string language, string script) : base(language) + { + this.script = script; + } + + /// + /// Initialize a new script block instance. + /// + /// the script language's + /// the script body + public ScriptBlock(MimeMediaType type, string script) : base(type) + { + this.script = script; + } + + /// + /// Gets or sets the script text. + /// + /// The script text. + public string Script + { + get { return script; } + set { script = value; } + } +} + +/// +/// Class that describes client side script file. +/// +/// +///

+/// Script file references script code in the external file. +///

+///
+/// Aleksandar Seovic +internal class ScriptFile : Script +{ + private string fileName; + + /// + /// Initialize a new instance. + /// + /// Script language. + /// The name of the script file. + public ScriptFile(string language, string fileName) : base(language) + { + this.fileName = fileName; + } + + /// + /// Initialize a new instance. + /// + /// the script language's + /// the (virtual) path to the script + public ScriptFile(MimeMediaType type, string fileName) + : base(type) + { + this.fileName = fileName; + } + + /// + /// Gets or sets the name of the script file. + /// + /// The name of the script file. + public string FileName + { + get { return fileName; } + set { fileName = value; } + } +} + +/// +/// Class that describes client side script file. +/// +/// +///

+/// Script file references script code in the external file. +///

+///
+/// Aleksandar Seovic +internal class ScriptEvent : ScriptBlock +{ + private string element; + private string eventName; + + /// + /// Initialize a new instance. + /// + /// Script language. + /// Element ID of the event source. + /// Name of the event to handle. + /// Script text. + public ScriptEvent(string language, string element, string eventName, string script) : base(language, script) + { + this.element = element; + this.eventName = eventName; + } + + /// + /// Initialize a new instance. + /// + /// the script language's + /// Element ID of the event source. + /// Name of the event to handle. + /// Script text. + public ScriptEvent(MimeMediaType type, string element, string eventName, string script) + : base(type, script) + { + this.element = element; + this.eventName = eventName; + } + + /// + /// Gets or sets the element ID. + /// + /// The element ID. + public string Element + { + get { return element; } + set { element = value; } + } + + /// + /// Gets or sets the name of the event. + /// + /// The name of the event. + public string EventName + { + get { return eventName; } + set { eventName = value; } + } +} diff --git a/src/Spring/Spring.Web/Web/Support/SharedStateResourceCache.cs b/src/Spring/Spring.Web/Web/Support/SharedStateResourceCache.cs index 6f331180..64548029 100644 --- a/src/Spring/Spring.Web/Web/Support/SharedStateResourceCache.cs +++ b/src/Spring/Spring.Web/Web/Support/SharedStateResourceCache.cs @@ -26,44 +26,43 @@ using Spring.Util; #endregion -namespace Spring.Web.Support +namespace Spring.Web.Support; + +/// +/// Resource cache implementation that uses Spring.NET page/handler state to cache resources. +/// +/// Aleksandar Seovic +public class SharedStateResourceCache : AbstractResourceCache { + private readonly ISharedStateAware sharedStateHolder; + /// - /// Resource cache implementation that uses Spring.NET page/handler state to cache resources. + /// Creates a new cache instance and attaches it to the given /// - /// Aleksandar Seovic - public class SharedStateResourceCache : AbstractResourceCache + /// the holder of the shared state dictionary to be used for caching. + public SharedStateResourceCache(ISharedStateAware sharedStateHolder) { - private readonly ISharedStateAware sharedStateHolder; - - /// - /// Creates a new cache instance and attaches it to the given - /// - /// the holder of the shared state dictionary to be used for caching. - public SharedStateResourceCache(ISharedStateAware sharedStateHolder) - { - AssertUtils.ArgumentNotNull(sharedStateHolder, "sharedStateHolder"); - this.sharedStateHolder = sharedStateHolder; - } - - /// - /// Gets the list of resources from cache. - /// - /// Cache key to use for lookup. - /// A list of cached resources for the specified target object and culture. - protected override IList GetResources(string cacheKey) - { - return (IList)this.sharedStateHolder.SharedState[cacheKey]; - } - - /// - /// Puts the list of resources in the cache. - /// - /// Cache key to use for the specified resources. - /// A list of resources to cache. - protected override void PutResources(string cacheKey, IList resources) - { - this.sharedStateHolder.SharedState[cacheKey] = resources; - } + AssertUtils.ArgumentNotNull(sharedStateHolder, "sharedStateHolder"); + this.sharedStateHolder = sharedStateHolder; } -} + + /// + /// Gets the list of resources from cache. + /// + /// Cache key to use for lookup. + /// A list of cached resources for the specified target object and culture. + protected override IList GetResources(string cacheKey) + { + return (IList) this.sharedStateHolder.SharedState[cacheKey]; + } + + /// + /// Puts the list of resources in the cache. + /// + /// Cache key to use for the specified resources. + /// A list of resources to cache. + protected override void PutResources(string cacheKey, IList resources) + { + this.sharedStateHolder.SharedState[cacheKey] = resources; + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Web/Web/Support/SupportsWebDependencyInjectionMethodBuilder.cs b/src/Spring/Spring.Web/Web/Support/SupportsWebDependencyInjectionMethodBuilder.cs index b758ff58..21119bc8 100644 --- a/src/Spring/Spring.Web/Web/Support/SupportsWebDependencyInjectionMethodBuilder.cs +++ b/src/Spring/Spring.Web/Web/Support/SupportsWebDependencyInjectionMethodBuilder.cs @@ -1,4 +1,5 @@ #region License + /* * Copyright � 2002-2011 the original author or authors. * @@ -14,6 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + #endregion #region Imports @@ -24,84 +26,84 @@ using Spring.Proxy; #endregion -namespace Spring.Web.Support +namespace Spring.Web.Support; + +/// +/// This MethodBuilder emits a Callback-call before calling the base method +/// +/// Erich Eichinger +internal class SupportsWebDependencyInjectionMethodBuilder : BaseProxyMethodBuilder { + private FieldInfo _appContextField; + private MethodInfo _callbackMethod; + /// - /// This MethodBuilder emits a Callback-call before calling the base method + /// Initializes a new instance of a SupportsWebDependencyInjectionMethodBuilder /// - /// Erich Eichinger - internal class SupportsWebDependencyInjectionMethodBuilder : BaseProxyMethodBuilder + public SupportsWebDependencyInjectionMethodBuilder(TypeBuilder typeBuilder, IProxyTypeGenerator proxyGenerator, + FieldInfo appContextField, MethodInfo callbackMethod) + : base(typeBuilder, proxyGenerator, true) { - private FieldInfo _appContextField; - private MethodInfo _callbackMethod; + _appContextField = appContextField; + _callbackMethod = callbackMethod; + } - /// - /// Initializes a new instance of a SupportsWebDependencyInjectionMethodBuilder - /// - public SupportsWebDependencyInjectionMethodBuilder(TypeBuilder typeBuilder, IProxyTypeGenerator proxyGenerator, - FieldInfo appContextField, MethodInfo callbackMethod) - : base(typeBuilder, proxyGenerator, true) + /// + /// Inserts a call to a callback-method before actually calling the base-method. + /// + /// The IL generator to use + /// The method to proxy + /// The interface definition of this method, if applicable + protected override void GenerateMethod(ILGenerator il, MethodInfo method, MethodInfo interfaceMethod) + { + this.GenerateCallbackMethodCall(il, method, interfaceMethod); + base.GenerateMethod(il, method, interfaceMethod); + } + + /// + /// Emits the callback invocation. + /// + private void GenerateCallbackMethodCall(ILGenerator il, MethodInfo method, MethodInfo interfaceMethod) + { + // setup parameters for call + + // IApplicationContext is always first parameter! + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldfld, _appContextField); + + // lookup parameters needed for callback - they are matched by type in order! + ParameterInfo[] callbackParams = _callbackMethod.GetParameters(); + ParameterInfo[] paramArray = method.GetParameters(); + + Type returnType = _callbackMethod.ReturnType; + int replaceArgumentIndex = -1; + + for (int j = 1; j < callbackParams.Length; j++) { - _appContextField = appContextField; - _callbackMethod = callbackMethod; - } - - /// - /// Inserts a call to a callback-method before actually calling the base-method. - /// - /// The IL generator to use - /// The method to proxy - /// The interface definition of this method, if applicable - protected override void GenerateMethod(ILGenerator il, MethodInfo method, MethodInfo interfaceMethod) - { - this.GenerateCallbackMethodCall(il, method, interfaceMethod); - base.GenerateMethod(il, method, interfaceMethod); - } - - /// - /// Emits the callback invocation. - /// - private void GenerateCallbackMethodCall(ILGenerator il, MethodInfo method, MethodInfo interfaceMethod) - { - // setup parameters for call - - // IApplicationContext is always first parameter! - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Ldfld, _appContextField); - - // lookup parameters needed for callback - they are matched by type in order! - ParameterInfo[] callbackParams = _callbackMethod.GetParameters(); - ParameterInfo[] paramArray = method.GetParameters(); - - Type returnType = _callbackMethod.ReturnType; - int replaceArgumentIndex = -1; - - for (int j = 1; j < callbackParams.Length; j++) + for (int i = 0; i < paramArray.Length; i++) { - for (int i = 0; i < paramArray.Length; i++) + // remember the parameter to assign the value returned from the callback to + if (paramArray[i].ParameterType == returnType) { - // remember the parameter to assign the value returned from the callback to - if (paramArray[i].ParameterType == returnType) - { - replaceArgumentIndex = i; - } + replaceArgumentIndex = i; + } - if (paramArray[i].ParameterType == callbackParams[j].ParameterType) - { - il.Emit(OpCodes.Ldarg_S, i + 1); - break; - } + if (paramArray[i].ParameterType == callbackParams[j].ParameterType) + { + il.Emit(OpCodes.Ldarg_S, i + 1); + break; } } - - // invoke static(!) callback - il.EmitCall(OpCodes.Call, _callbackMethod, null); - // if callback has a result, store the result back into the first matching argument - if (replaceArgumentIndex > -1) - { - il.Emit(OpCodes.Starg_S, (byte)replaceArgumentIndex+1); - } - return; } + + // invoke static(!) callback + il.EmitCall(OpCodes.Call, _callbackMethod, null); + // if callback has a result, store the result back into the first matching argument + if (replaceArgumentIndex > -1) + { + il.Emit(OpCodes.Starg_S, (byte) replaceArgumentIndex + 1); + } + + return; } -} +} \ No newline at end of file diff --git a/src/Spring/Spring.Web/Web/Support/SupportsWebDependencyInjectionOwnerProxy.cs b/src/Spring/Spring.Web/Web/Support/SupportsWebDependencyInjectionOwnerProxy.cs index e4d18e0f..34af8a51 100644 --- a/src/Spring/Spring.Web/Web/Support/SupportsWebDependencyInjectionOwnerProxy.cs +++ b/src/Spring/Spring.Web/Web/Support/SupportsWebDependencyInjectionOwnerProxy.cs @@ -1,6 +1,7 @@ #region License + /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -14,6 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + #endregion #region Imports @@ -28,84 +30,84 @@ using Spring.Util; #endregion -namespace Spring.Web.Support +namespace Spring.Web.Support; + +/// +/// Wraps a ControlCollection.Owner control to make it DI aware +/// +/// Erich Eichinger +internal class SupportsWebDependencyInjectionOwnerProxy : Control, ISupportsWebDependencyInjection { + // Control Fields and Methods + private readonly ControlAccessor _targetControl; + private IApplicationContext _defaultApplicationContext; + /// - /// Wraps a ControlCollection.Owner control to make it DI aware + /// Wraps a control to make it DI aware /// - /// Erich Eichinger - internal class SupportsWebDependencyInjectionOwnerProxy : Control, ISupportsWebDependencyInjection + /// + /// + public SupportsWebDependencyInjectionOwnerProxy(IApplicationContext defaultApplicationContext, Control targetControl) { - // Control Fields and Methods - private readonly ControlAccessor _targetControl; - private IApplicationContext _defaultApplicationContext; + _defaultApplicationContext = defaultApplicationContext; + _targetControl = new ControlAccessor(targetControl); + } - /// - /// Wraps a control to make it DI aware - /// - /// - /// - public SupportsWebDependencyInjectionOwnerProxy(IApplicationContext defaultApplicationContext, Control targetControl) - { - _defaultApplicationContext = defaultApplicationContext; - _targetControl = new ControlAccessor(targetControl); - } - - public IApplicationContext DefaultApplicationContext - { - get { return this._defaultApplicationContext; } - set { this._defaultApplicationContext = value; } - } - - /// - /// Performs DI before adding the control to it's parent - /// - /// - /// - protected override void AddedControl(Control control, int index) - { - // do DI - Control configuredControl = WebDependencyInjectionUtils.InjectDependenciesRecursive(_defaultApplicationContext, control); - if (configuredControl != control) - { - _targetControl.SetControlAt( configuredControl, index ); - } - _targetControl.AddedControl(control, index); - } - - /// - /// Delegates call to decorated control - /// - /// - protected override void RemovedControl(Control control) - { - _targetControl.RemovedControl(control); - } + public IApplicationContext DefaultApplicationContext + { + get { return this._defaultApplicationContext; } + set { this._defaultApplicationContext = value; } } /// - /// Wraps a ControlCollection.Owner control implementing INamingContainer to make it DI aware + /// Performs DI before adding the control to it's parent /// - /// Erich Eichinger - internal class NamingContainerSupportsWebDependencyInjectionOwnerProxy : SupportsWebDependencyInjectionOwnerProxy - , INamingContainer + /// + /// + protected override void AddedControl(Control control, int index) { - private static readonly SafeField refOccasionalFields; - - static NamingContainerSupportsWebDependencyInjectionOwnerProxy() + // do DI + Control configuredControl = WebDependencyInjectionUtils.InjectDependenciesRecursive(_defaultApplicationContext, control); + if (configuredControl != control) { - SafeField fld = null; - SecurityCritical.ExecutePrivileged( new PermissionSet(PermissionState.Unrestricted), delegate - { - fld = new SafeField(typeof(Control).GetField("_occasionalFields", BindingFlags.Instance | BindingFlags.NonPublic)); - }); - refOccasionalFields = fld; + _targetControl.SetControlAt(configuredControl, index); } - public NamingContainerSupportsWebDependencyInjectionOwnerProxy(IApplicationContext defaultApplicationContext, Control targetControl) : base(defaultApplicationContext, targetControl) - { - object targetOccasionalFields = refOccasionalFields.GetValue(targetControl); - refOccasionalFields.SetValue(this, targetOccasionalFields); - } + _targetControl.AddedControl(control, index); + } + + /// + /// Delegates call to decorated control + /// + /// + protected override void RemovedControl(Control control) + { + _targetControl.RemovedControl(control); } } + +/// +/// Wraps a ControlCollection.Owner control implementing INamingContainer to make it DI aware +/// +/// Erich Eichinger +internal class NamingContainerSupportsWebDependencyInjectionOwnerProxy : SupportsWebDependencyInjectionOwnerProxy + , INamingContainer +{ + private static readonly SafeField refOccasionalFields; + + static NamingContainerSupportsWebDependencyInjectionOwnerProxy() + { + SafeField fld = null; + SecurityCritical.ExecutePrivileged(new PermissionSet(PermissionState.Unrestricted), delegate + { + fld = new SafeField(typeof(Control).GetField("_occasionalFields", BindingFlags.Instance | BindingFlags.NonPublic)); + }); + refOccasionalFields = fld; + } + + public NamingContainerSupportsWebDependencyInjectionOwnerProxy(IApplicationContext defaultApplicationContext, Control targetControl) : base(defaultApplicationContext, targetControl) + { + object targetOccasionalFields = refOccasionalFields.GetValue(targetControl); + refOccasionalFields.SetValue(this, targetOccasionalFields); + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Web/Web/Support/SupportsWebDependencyInjectionTypeBuilder.cs b/src/Spring/Spring.Web/Web/Support/SupportsWebDependencyInjectionTypeBuilder.cs index 725f9cb4..e3bbf9ce 100644 --- a/src/Spring/Spring.Web/Web/Support/SupportsWebDependencyInjectionTypeBuilder.cs +++ b/src/Spring/Spring.Web/Web/Support/SupportsWebDependencyInjectionTypeBuilder.cs @@ -1,4 +1,5 @@ #region License + /* * Copyright � 2002-2011 the original author or authors. * @@ -14,181 +15,181 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + #endregion #region Imports using System.Reflection; using System.Reflection.Emit; - using Spring.Context; using Spring.Proxy; using Spring.Util; #endregion -namespace Spring.Web.Support +namespace Spring.Web.Support; + +/// +/// This TypeBuilder dynamically implements the contract on a given type. +/// +/// Erich Eichinger +internal class SupportsWebDependencyInjectionTypeBuilder : InheritanceProxyTypeBuilder { + private const string PROXY_TYPE_NAME = "SupportsWebDependencyInjectionControlProxy"; + + private MethodInfo[] _methodsToIntercept; + private MethodInfo _staticCallbackMethod; + /// - /// This TypeBuilder dynamically implements the contract on a given type. + /// Creates a new TypeBuilder instance. /// - /// Erich Eichinger - internal class SupportsWebDependencyInjectionTypeBuilder : InheritanceProxyTypeBuilder + /// The base type the proxy shall be derived from + /// The methods to be injected with a call to staticCallbackMethod + /// The static callback method to be injected into methodsToIntercept + public SupportsWebDependencyInjectionTypeBuilder(Type targetType, MethodInfo[] methodsToIntercept, MethodInfo staticCallbackMethod) { - private const string PROXY_TYPE_NAME = "SupportsWebDependencyInjectionControlProxy"; + Name = PROXY_TYPE_NAME; - private MethodInfo[] _methodsToIntercept; - private MethodInfo _staticCallbackMethod; + base.TargetType = targetType; - /// - /// Creates a new TypeBuilder instance. - /// - /// The base type the proxy shall be derived from - /// The methods to be injected with a call to staticCallbackMethod - /// The static callback method to be injected into methodsToIntercept - public SupportsWebDependencyInjectionTypeBuilder(Type targetType, MethodInfo[] methodsToIntercept, MethodInfo staticCallbackMethod) + if (methodsToIntercept == null || methodsToIntercept.Length == 0) { - Name = PROXY_TYPE_NAME; - - base.TargetType = targetType; - - if (methodsToIntercept == null || methodsToIntercept.Length == 0) - { - throw new ArgumentException("No methods specified to be intercepted"); - } - _methodsToIntercept = methodsToIntercept; - - if (!staticCallbackMethod.IsStatic) - { - throw new ArgumentException("CallbackMethod must be static"); - } - _staticCallbackMethod = staticCallbackMethod; + throw new ArgumentException("No methods specified to be intercepted"); } - /// - /// Creates a proxy that inherits the proxied object's class. - /// - /// - /// The generated proxy type. - public override Type BuildProxyType() + _methodsToIntercept = methodsToIntercept; + + if (!staticCallbackMethod.IsStatic) { - BaseType = TargetType; - if (BaseType.IsSealed || - !ReflectionUtils.IsTypeVisible(BaseType, DynamicProxyManager.ASSEMBLY_NAME)) - { - throw new ArgumentException("Inheritance proxy cannot be created for a sealed or non-public class [" + - BaseType.FullName + "]"); - } - - TypeBuilder typeBuilder = CreateTypeBuilder(Name, BaseType); - - // declare field to hold reference to applicationContext - FieldBuilder appContextField = DeclareApplicationContextInstanceField(typeBuilder); - - // create constructors - ImplementConstructors(typeBuilder); - - // Implement IDependencyInjectionAware if necessary - if (!typeof (ISupportsWebDependencyInjection).IsAssignableFrom(BaseType)) - { - ImplementIDependencyInjectionAware(typeBuilder, BaseType, appContextField); - } - - // proxy base virtual methods - BaseProxyMethodBuilder proxyMethodBuilder = - new SupportsWebDependencyInjectionMethodBuilder(typeBuilder, this, appContextField, _staticCallbackMethod); - foreach (MethodInfo methodToIntercept in _methodsToIntercept) - { - proxyMethodBuilder.BuildProxyMethod(methodToIntercept, null); - } - - return typeBuilder.CreateType(); + throw new ArgumentException("CallbackMethod must be static"); } - /// - /// Actually implements the interface. - /// - private void ImplementIDependencyInjectionAware(TypeBuilder typeBuilder, Type targetType, FieldInfo appContextField) - { - Type intf = typeof (ISupportsWebDependencyInjection); - - // Add interface declaration to type - typeBuilder.AddInterfaceImplementation(intf); - - // get interface property - PropertyInfo piApplicationContext = intf.GetProperty("DefaultApplicationContext"); - - // define property - string fullPropertyName = typeof (ISupportsWebDependencyInjection).FullName + "." + piApplicationContext.Name; - PropertyBuilder appContextProperty = - typeBuilder.DefineProperty(fullPropertyName, PropertyAttributes.None, typeof (IApplicationContext), null); - - MethodAttributes methodAtts = MethodAttributes.Private | MethodAttributes.HideBySig | MethodAttributes.SpecialName | - MethodAttributes.NewSlot | MethodAttributes.Virtual | MethodAttributes.Final; - - // implement getter - MethodInfo getApplicationContextMethod = piApplicationContext.GetGetMethod(); - string getterMethodName = typeof (ISupportsWebDependencyInjection).FullName + "." + getApplicationContextMethod.Name; - MethodBuilder mbGet = - typeBuilder.DefineMethod(getterMethodName, - methodAtts, - getApplicationContextMethod.CallingConvention, getApplicationContextMethod.ReturnType, - Type.EmptyTypes); - - - ILGenerator ilGet = mbGet.GetILGenerator(); - ilGet.Emit(OpCodes.Ldarg_0); - ilGet.Emit(OpCodes.Ldfld, appContextField); - ilGet.Emit(OpCodes.Ret); - - typeBuilder.DefineMethodOverride(mbGet, getApplicationContextMethod); - appContextProperty.SetGetMethod(mbGet); - - // implement setter - MethodInfo setApplicationContextMethod = piApplicationContext.GetSetMethod(); - string setterMethodName = typeof (ISupportsWebDependencyInjection).FullName + "." + setApplicationContextMethod.Name; - MethodBuilder mbSet = typeBuilder.DefineMethod(setterMethodName, methodAtts, - setApplicationContextMethod.CallingConvention, - setApplicationContextMethod.ReturnType, - new Type[] {typeof (IApplicationContext)}); - - ILGenerator ilSet = mbSet.GetILGenerator(); - ilSet.Emit(OpCodes.Ldarg_0); - ilSet.Emit(OpCodes.Ldarg_1); - ilSet.Emit(OpCodes.Stfld, appContextField); - ilSet.Emit(OpCodes.Ret); - - typeBuilder.DefineMethodOverride(mbSet, setApplicationContextMethod); - appContextProperty.SetSetMethod(mbSet); - } - - /// - /// Declares field that holds the . - /// - private FieldBuilder DeclareApplicationContextInstanceField(TypeBuilder builder) - { - FieldBuilder applicationContextField; - applicationContextField = - builder.DefineField("_defaultApplicationContext", typeof (IApplicationContext), FieldAttributes.Private); - return applicationContextField; - } - - #region Public Methods - - /// - /// Determines if the specified - /// is one of those generated by this builder. - /// - /// The type to check. - /// - /// if the type is a SpringAwareControl-based proxy; - /// otherwise . - /// - public static bool IsSpringAwareControlProxy(Type type) - { - return type.FullName.StartsWith(PROXY_TYPE_NAME); - } - - #endregion + _staticCallbackMethod = staticCallbackMethod; } -} + + /// + /// Creates a proxy that inherits the proxied object's class. + /// + /// + /// The generated proxy type. + public override Type BuildProxyType() + { + BaseType = TargetType; + if (BaseType.IsSealed || + !ReflectionUtils.IsTypeVisible(BaseType, DynamicProxyManager.ASSEMBLY_NAME)) + { + throw new ArgumentException("Inheritance proxy cannot be created for a sealed or non-public class [" + + BaseType.FullName + "]"); + } + + TypeBuilder typeBuilder = CreateTypeBuilder(Name, BaseType); + + // declare field to hold reference to applicationContext + FieldBuilder appContextField = DeclareApplicationContextInstanceField(typeBuilder); + + // create constructors + ImplementConstructors(typeBuilder); + + // Implement IDependencyInjectionAware if necessary + if (!typeof(ISupportsWebDependencyInjection).IsAssignableFrom(BaseType)) + { + ImplementIDependencyInjectionAware(typeBuilder, BaseType, appContextField); + } + + // proxy base virtual methods + BaseProxyMethodBuilder proxyMethodBuilder = + new SupportsWebDependencyInjectionMethodBuilder(typeBuilder, this, appContextField, _staticCallbackMethod); + foreach (MethodInfo methodToIntercept in _methodsToIntercept) + { + proxyMethodBuilder.BuildProxyMethod(methodToIntercept, null); + } + + return typeBuilder.CreateType(); + } + + /// + /// Actually implements the interface. + /// + private void ImplementIDependencyInjectionAware(TypeBuilder typeBuilder, Type targetType, FieldInfo appContextField) + { + Type intf = typeof(ISupportsWebDependencyInjection); + + // Add interface declaration to type + typeBuilder.AddInterfaceImplementation(intf); + + // get interface property + PropertyInfo piApplicationContext = intf.GetProperty("DefaultApplicationContext"); + + // define property + string fullPropertyName = typeof(ISupportsWebDependencyInjection).FullName + "." + piApplicationContext.Name; + PropertyBuilder appContextProperty = + typeBuilder.DefineProperty(fullPropertyName, PropertyAttributes.None, typeof(IApplicationContext), null); + + MethodAttributes methodAtts = MethodAttributes.Private | MethodAttributes.HideBySig | MethodAttributes.SpecialName | + MethodAttributes.NewSlot | MethodAttributes.Virtual | MethodAttributes.Final; + + // implement getter + MethodInfo getApplicationContextMethod = piApplicationContext.GetGetMethod(); + string getterMethodName = typeof(ISupportsWebDependencyInjection).FullName + "." + getApplicationContextMethod.Name; + MethodBuilder mbGet = + typeBuilder.DefineMethod(getterMethodName, + methodAtts, + getApplicationContextMethod.CallingConvention, getApplicationContextMethod.ReturnType, + Type.EmptyTypes); + + ILGenerator ilGet = mbGet.GetILGenerator(); + ilGet.Emit(OpCodes.Ldarg_0); + ilGet.Emit(OpCodes.Ldfld, appContextField); + ilGet.Emit(OpCodes.Ret); + + typeBuilder.DefineMethodOverride(mbGet, getApplicationContextMethod); + appContextProperty.SetGetMethod(mbGet); + + // implement setter + MethodInfo setApplicationContextMethod = piApplicationContext.GetSetMethod(); + string setterMethodName = typeof(ISupportsWebDependencyInjection).FullName + "." + setApplicationContextMethod.Name; + MethodBuilder mbSet = typeBuilder.DefineMethod(setterMethodName, methodAtts, + setApplicationContextMethod.CallingConvention, + setApplicationContextMethod.ReturnType, + new Type[] { typeof(IApplicationContext) }); + + ILGenerator ilSet = mbSet.GetILGenerator(); + ilSet.Emit(OpCodes.Ldarg_0); + ilSet.Emit(OpCodes.Ldarg_1); + ilSet.Emit(OpCodes.Stfld, appContextField); + ilSet.Emit(OpCodes.Ret); + + typeBuilder.DefineMethodOverride(mbSet, setApplicationContextMethod); + appContextProperty.SetSetMethod(mbSet); + } + + /// + /// Declares field that holds the . + /// + private FieldBuilder DeclareApplicationContextInstanceField(TypeBuilder builder) + { + FieldBuilder applicationContextField; + applicationContextField = + builder.DefineField("_defaultApplicationContext", typeof(IApplicationContext), FieldAttributes.Private); + return applicationContextField; + } + + #region Public Methods + + /// + /// Determines if the specified + /// is one of those generated by this builder. + /// + /// The type to check. + /// + /// if the type is a SpringAwareControl-based proxy; + /// otherwise . + /// + public static bool IsSpringAwareControlProxy(Type type) + { + return type.FullName.StartsWith(PROXY_TYPE_NAME); + } + + #endregion +} \ No newline at end of file diff --git a/src/Spring/Spring.Web/Web/Support/WebDependencyInjectionUtils.cs b/src/Spring/Spring.Web/Web/Support/WebDependencyInjectionUtils.cs index aceb8c10..0f062e57 100644 --- a/src/Spring/Spring.Web/Web/Support/WebDependencyInjectionUtils.cs +++ b/src/Spring/Spring.Web/Web/Support/WebDependencyInjectionUtils.cs @@ -23,97 +23,97 @@ using Spring.Context; using Spring.Context.Support; using Spring.Util; -namespace Spring.Web.Support +namespace Spring.Web.Support; + +/// +/// Utilities for dependency injection in the web tier. +/// +public class WebDependencyInjectionUtils { /// - /// Utilities for dependency injection in the web tier. + /// Injects dependencies into all controls in the hierarchy + /// based on template definitions in the Spring config file. /// - public class WebDependencyInjectionUtils + /// ApplicationContext to be used + /// Control to inject dependencies into. + public static Control InjectDependenciesRecursive(IApplicationContext applicationContext, Control control) { - /// - /// Injects dependencies into all controls in the hierarchy - /// based on template definitions in the Spring config file. - /// - /// ApplicationContext to be used - /// Control to inject dependencies into. - public static Control InjectDependenciesRecursive(IApplicationContext applicationContext, Control control) + if (applicationContext != null) { - if (applicationContext != null) - { - control = InjectDependenciesRecursiveInternal(applicationContext, control); - } - return control; + control = InjectDependenciesRecursiveInternal(applicationContext, control); } - private static Control InjectDependenciesRecursiveInternal(IApplicationContext appContext, Control control) + return control; + } + + private static Control InjectDependenciesRecursiveInternal(IApplicationContext appContext, Control control) + { + if (control is LiteralControl) return control; // nothing to do + + ISupportsWebDependencyInjection diControl = control as ISupportsWebDependencyInjection; + if (diControl != null && diControl.DefaultApplicationContext != null) { - if (control is LiteralControl) return control; // nothing to do + return control; // nothing to do anymore - control cares for itself and its children + } - ISupportsWebDependencyInjection diControl = control as ISupportsWebDependencyInjection; - if (diControl != null && diControl.DefaultApplicationContext != null) + // "intercept" Control to make it DI-aware + ControlInterceptor.EnsureControlIntercepted(appContext, control); + + // if the control is a UserControl, use ApplicationContext from it's physical location + IApplicationContext appContextToUse = appContext; + UserControl userControl = control as UserControl; + if (userControl != null) + { + appContextToUse = GetControlApplicationContext(appContext, userControl); + } + + // set ApplicationContext instance + if (control is IApplicationContextAware) + { + ((IApplicationContextAware) control).ApplicationContext = appContextToUse; + } + + // inject dependencies using control's context + control = (Control) appContextToUse.ConfigureObject(control, control.GetType().FullName); + + // and now go for control's children + if (control.HasControls()) + { + ControlCollection childControls = control.Controls; + int childCount = childControls.Count; + for (int i = 0; i < childCount; i++) { - return control; // nothing to do anymore - control cares for itself and its children - } + Control c = childControls[i]; + if (c is LiteralControl) continue; - // "intercept" Control to make it DI-aware - ControlInterceptor.EnsureControlIntercepted(appContext, control); - - // if the control is a UserControl, use ApplicationContext from it's physical location - IApplicationContext appContextToUse = appContext; - UserControl userControl = control as UserControl; - if (userControl != null) - { - appContextToUse = GetControlApplicationContext(appContext, userControl); - } - - // set ApplicationContext instance - if (control is IApplicationContextAware) - { - ((IApplicationContextAware)control).ApplicationContext = appContextToUse; - } - - // inject dependencies using control's context - control = (Control)appContextToUse.ConfigureObject(control, control.GetType().FullName); - - // and now go for control's children - if (control.HasControls()) - { - ControlCollection childControls = control.Controls; - int childCount = childControls.Count; - for (int i = 0; i < childCount; i++) + Control configuredControl = InjectDependenciesRecursiveInternal(appContext, c); + if (configuredControl != c) { - Control c = childControls[i]; - if (c is LiteralControl) continue; - - Control configuredControl = InjectDependenciesRecursiveInternal(appContext, c); - if (configuredControl != c) - { - ControlAccessor ac = new ControlAccessor(c.Parent); - ac.SetControlAt(configuredControl, i); - } + ControlAccessor ac = new ControlAccessor(c.Parent); + ac.SetControlAt(configuredControl, i); } } - - return control; } - /// - /// Aquires an ApplicationContext according to a Control's TemplateSourceDirectory - /// - /// if availabe, the control's IApplicationContext instance - defaultContext otherwise - private static IApplicationContext GetControlApplicationContext(IApplicationContext defaultContext, Control control) + return control; + } + + /// + /// Aquires an ApplicationContext according to a Control's TemplateSourceDirectory + /// + /// if availabe, the control's IApplicationContext instance - defaultContext otherwise + private static IApplicationContext GetControlApplicationContext(IApplicationContext defaultContext, Control control) + { + // use control's directory for resolving context + string srcDir = control.TemplateSourceDirectory; + if (StringUtils.HasLength(srcDir)) { - // use control's directory for resolving context - string srcDir = control.TemplateSourceDirectory; - if (StringUtils.HasLength(srcDir)) - { - if (!srcDir.EndsWith("/")) srcDir += "/"; - return WebApplicationContext.GetContext(srcDir); - } - else - { - return defaultContext; - } + if (!srcDir.EndsWith("/")) srcDir += "/"; + return WebApplicationContext.GetContext(srcDir); + } + else + { + return defaultContext; } } } diff --git a/src/Spring/Spring.Web/Web/Support/WebFormsResultWebNavigator.cs b/src/Spring/Spring.Web/Web/Support/WebFormsResultWebNavigator.cs index 08a41056..13150bd9 100644 --- a/src/Spring/Spring.Web/Web/Support/WebFormsResultWebNavigator.cs +++ b/src/Spring/Spring.Web/Web/Support/WebFormsResultWebNavigator.cs @@ -26,234 +26,237 @@ using Spring.Util; #endregion -namespace Spring.Web.Support +namespace Spring.Web.Support; + +/// +/// An implementation of specific for s. +/// The navigator hierarchy equals the control hierarchy when using a . +/// +/// +/// +/// This implementation supports 2 different navigator hierarchies: +///
    +///
  • The default hierarchy defined by
  • +///
  • The hierarchy defined by a web form's hierarchy.
  • +///
+///
+/// +/// This implementation always checks the standard hierarchy first and - if a destination cannot be resolved, falls back +/// to the control hierarchy for resolving a specified navigation destination. +/// +///
+public class WebFormsResultWebNavigator : DefaultResultWebNavigator { /// - /// An implementation of specific for s. - /// The navigator hierarchy equals the control hierarchy when using a . + /// Holds the result match from . /// - /// - /// - /// This implementation supports 2 different navigator hierarchies: - ///
    - ///
  • The default hierarchy defined by
  • - ///
  • The hierarchy defined by a web form's hierarchy.
  • - ///
- ///
- /// - /// This implementation always checks the standard hierarchy first and - if a destination cannot be resolved, falls back - /// to the control hierarchy for resolving a specified navigation destination. - /// - ///
- public class WebFormsResultWebNavigator : DefaultResultWebNavigator + protected class NavigableControlInfo { /// - /// Holds the result match from . + /// The matching control /// - protected class NavigableControlInfo - { - /// - /// The matching control - /// - public readonly Control Control; - /// - /// The instance associated with the control. May be null. - /// - public readonly IWebNavigator WebNavigator; - - /// - /// Initializes the new match instance. - /// - /// the matching control. Must not be null! - public NavigableControlInfo( Control control ) - { - AssertUtils.ArgumentNotNull(control, "control"); - - Control = control; - - if (Control is IWebNavigable) - { - WebNavigator = ((IWebNavigable)Control).WebNavigator; - } - else if (Control is IWebNavigator) - { - WebNavigator = (IWebNavigator)control; - } - } - } + public readonly Control Control; /// - /// Finds the next up the control hierarchy, - /// starting at the specified . + /// The instance associated with the control. May be null. /// - /// - /// This method checks both, for controls implementing or . In addition - /// when MasterPages are used, it interprets the control hierarchy as control->page->masterpage. (). - /// - /// the control to start the search with. - /// include checking the control itself or start search with its parent. - /// requires s to hold a valid instance. - /// If found, the next or . - /// null otherwise - protected static NavigableControlInfo FindNavigableParent( Control control, bool includeSelf, bool restrictToValidNavigatorsOnly ) - { - while (control != null) - { - if (!includeSelf) - { - // Get next parent in hierarchy - control = WebUtils.GetLogicalParent( control ); - } - includeSelf = false; - - if (control is IWebNavigable || control is IWebNavigator) - { - NavigableControlInfo nci = new NavigableControlInfo(control); - if (!restrictToValidNavigatorsOnly) - { - return nci; - } - if (nci.WebNavigator != null) - { - return nci; - } - } - } - return null; - } - - private readonly Control _owner; + public readonly IWebNavigator WebNavigator; /// - /// The that this is associated with. + /// Initializes the new match instance. /// - public Control Owner + /// the matching control. Must not be null! + public NavigableControlInfo(Control control) { - get { return _owner; } - } + AssertUtils.ArgumentNotNull(control, "control"); - /// - /// Creates a new instance of a for the specified control. - /// - /// the control to be associated with this navigator. - /// the direct parent of this navigator - /// a dictionary containing results - /// specifies how to handle case for destination names. - public WebFormsResultWebNavigator( Control owner, IWebNavigator parent, IDictionary initialResults, bool ignoreCase ) - : base( parent, initialResults, ignoreCase ) - { - AssertUtils.ArgumentNotNull( owner, "owner" ); - _owner = owner; - } + Control = control; - /// - /// Determines, whether this navigator or one of its parents can - /// navigate to the destination specified in . - /// - /// the name of the navigation destination - /// true, if this navigator can navigate to the destination. - public override bool CanNavigateTo( string destination ) - { - return CheckCanNavigate( destination, true ); - } - - /// - /// Check, whether this navigator can navigate to the specified . - /// - /// the destination name to check. - /// - /// whether the check shall include the control hierarchy or - /// the standard hierarchy only. - /// - protected bool CheckCanNavigate( string destination, bool includeControlHierarchy ) - { - // check the default path - if (base.CanNavigateTo( destination )) + if (Control is IWebNavigable) { - return true; + WebNavigator = ((IWebNavigable) Control).WebNavigator; } - - // include checking the control hierarchy - if (includeControlHierarchy) + else if (Control is IWebNavigator) { - NavigableControlInfo nci = FindNavigableParent( this._owner, false, true ); - if (nci != null) - { - // when delegating upwards, the control containing the matching result - // will appear as sender - this makes dealing with expressions more "natural". - return nci.WebNavigator.CanNavigateTo( destination ); - } - } - - return false; - } - - /// - /// Returns a redirect url string that points to the - /// defined by this - /// result evaluated using this Page for expression - /// - /// Name of the result. - /// the instance that issued this request - /// The context to use for evaluating the SpEL expression in the Result - /// A redirect url string. - public override string GetResultUri( string destination, object sender, object context ) - { - if (this.CheckCanNavigate( destination, false )) - { - return base.GetResultUri( destination, sender, context ); - } - - NavigableControlInfo nci = FindNavigableParent( this._owner, false, true ); - if (nci != null) - { - // when delegating upwards, the control containing the matching result - // will appear as sender - this makes dealing with expressions more "natural". - return nci.WebNavigator.GetResultUri( destination, nci.Control, context ); - } - - return HandleUnknownDestination( destination, sender, context ); - } - - /// - /// Redirects user to a URL mapped to specified result name. - /// - /// Name of the result. - /// the instance that issued this request - /// The context to use for evaluating the SpEL expression in the Result. - public override void NavigateTo( string destination, object sender, object context ) - { - if (this.CheckCanNavigate( destination, false )) - { - base.NavigateTo( destination, sender, context ); - return; - } - - NavigableControlInfo nci = FindNavigableParent( this._owner, false, true ); - if (nci != null) - { - // when delegating upwards, the control containing the matching result - // will appear as sender - this makes dealing with expressions more "natural". - nci.WebNavigator.NavigateTo( destination, nci.Control, context ); - return; - } - - HandleUnknownDestination( destination, sender, context ); - } - - /// - /// Return the next available within - /// this control's parent hierarchy. - /// - public IWebNavigator ParentControlNavigator - { - get - { - // nci.WebNavigator is guaranteed to be non-null! - NavigableControlInfo nci = FindNavigableParent( this._owner, false, true ); - if (nci == null) return null; - return nci.WebNavigator; + WebNavigator = (IWebNavigator) control; } } } -} \ No newline at end of file + + /// + /// Finds the next up the control hierarchy, + /// starting at the specified . + /// + /// + /// This method checks both, for controls implementing or . In addition + /// when MasterPages are used, it interprets the control hierarchy as control->page->masterpage. (). + /// + /// the control to start the search with. + /// include checking the control itself or start search with its parent. + /// requires s to hold a valid instance. + /// If found, the next or . + /// null otherwise + protected static NavigableControlInfo FindNavigableParent(Control control, bool includeSelf, bool restrictToValidNavigatorsOnly) + { + while (control != null) + { + if (!includeSelf) + { + // Get next parent in hierarchy + control = WebUtils.GetLogicalParent(control); + } + + includeSelf = false; + + if (control is IWebNavigable || control is IWebNavigator) + { + NavigableControlInfo nci = new NavigableControlInfo(control); + if (!restrictToValidNavigatorsOnly) + { + return nci; + } + + if (nci.WebNavigator != null) + { + return nci; + } + } + } + + return null; + } + + private readonly Control _owner; + + /// + /// The that this is associated with. + /// + public Control Owner + { + get { return _owner; } + } + + /// + /// Creates a new instance of a for the specified control. + /// + /// the control to be associated with this navigator. + /// the direct parent of this navigator + /// a dictionary containing results + /// specifies how to handle case for destination names. + public WebFormsResultWebNavigator(Control owner, IWebNavigator parent, IDictionary initialResults, bool ignoreCase) + : base(parent, initialResults, ignoreCase) + { + AssertUtils.ArgumentNotNull(owner, "owner"); + _owner = owner; + } + + /// + /// Determines, whether this navigator or one of its parents can + /// navigate to the destination specified in . + /// + /// the name of the navigation destination + /// true, if this navigator can navigate to the destination. + public override bool CanNavigateTo(string destination) + { + return CheckCanNavigate(destination, true); + } + + /// + /// Check, whether this navigator can navigate to the specified . + /// + /// the destination name to check. + /// + /// whether the check shall include the control hierarchy or + /// the standard hierarchy only. + /// + protected bool CheckCanNavigate(string destination, bool includeControlHierarchy) + { + // check the default path + if (base.CanNavigateTo(destination)) + { + return true; + } + + // include checking the control hierarchy + if (includeControlHierarchy) + { + NavigableControlInfo nci = FindNavigableParent(this._owner, false, true); + if (nci != null) + { + // when delegating upwards, the control containing the matching result + // will appear as sender - this makes dealing with expressions more "natural". + return nci.WebNavigator.CanNavigateTo(destination); + } + } + + return false; + } + + /// + /// Returns a redirect url string that points to the + /// defined by this + /// result evaluated using this Page for expression + /// + /// Name of the result. + /// the instance that issued this request + /// The context to use for evaluating the SpEL expression in the Result + /// A redirect url string. + public override string GetResultUri(string destination, object sender, object context) + { + if (this.CheckCanNavigate(destination, false)) + { + return base.GetResultUri(destination, sender, context); + } + + NavigableControlInfo nci = FindNavigableParent(this._owner, false, true); + if (nci != null) + { + // when delegating upwards, the control containing the matching result + // will appear as sender - this makes dealing with expressions more "natural". + return nci.WebNavigator.GetResultUri(destination, nci.Control, context); + } + + return HandleUnknownDestination(destination, sender, context); + } + + /// + /// Redirects user to a URL mapped to specified result name. + /// + /// Name of the result. + /// the instance that issued this request + /// The context to use for evaluating the SpEL expression in the Result. + public override void NavigateTo(string destination, object sender, object context) + { + if (this.CheckCanNavigate(destination, false)) + { + base.NavigateTo(destination, sender, context); + return; + } + + NavigableControlInfo nci = FindNavigableParent(this._owner, false, true); + if (nci != null) + { + // when delegating upwards, the control containing the matching result + // will appear as sender - this makes dealing with expressions more "natural". + nci.WebNavigator.NavigateTo(destination, nci.Control, context); + return; + } + + HandleUnknownDestination(destination, sender, context); + } + + /// + /// Return the next available within + /// this control's parent hierarchy. + /// + public IWebNavigator ParentControlNavigator + { + get + { + // nci.WebNavigator is guaranteed to be non-null! + NavigableControlInfo nci = FindNavigableParent(this._owner, false, true); + if (nci == null) return null; + return nci.WebNavigator; + } + } +} diff --git a/src/Spring/Spring.Web/Web/Support/WebNavigableWebNavigatorAdapter.cs b/src/Spring/Spring.Web/Web/Support/WebNavigableWebNavigatorAdapter.cs index 64b1fa05..d9d8cc8a 100644 --- a/src/Spring/Spring.Web/Web/Support/WebNavigableWebNavigatorAdapter.cs +++ b/src/Spring/Spring.Web/Web/Support/WebNavigableWebNavigatorAdapter.cs @@ -22,32 +22,31 @@ #endregion -namespace Spring.Web.Support +namespace Spring.Web.Support; + +/// +/// Adapts a concrete instance as a . +/// +/// Erich Eichinger +public class WebNavigableWebNavigatorAdapter : IWebNavigable { + private readonly IWebNavigator _resultNavigator; + /// - /// Adapts a concrete instance as a . + /// Create a new adapter instance, wrapping the specified + /// into a interface. /// - /// Erich Eichinger - public class WebNavigableWebNavigatorAdapter : IWebNavigable + /// the instance to be adapted. May be null. + public WebNavigableWebNavigatorAdapter(IWebNavigator resultNavigator) { - private readonly IWebNavigator _resultNavigator; - - /// - /// Create a new adapter instance, wrapping the specified - /// into a interface. - /// - /// the instance to be adapted. May be null. - public WebNavigableWebNavigatorAdapter(IWebNavigator resultNavigator) - { - _resultNavigator = resultNavigator; - } - - /// - /// Returns the wrapped that was passed into . - /// - public IWebNavigator WebNavigator - { - get { return _resultNavigator; } - } + _resultNavigator = resultNavigator; } -} \ No newline at end of file + + /// + /// Returns the wrapped that was passed into . + /// + public IWebNavigator WebNavigator + { + get { return _resultNavigator; } + } +} diff --git a/src/Spring/Spring.Web/Web/UI/AbstractWizard.cs b/src/Spring/Spring.Web/Web/UI/AbstractWizard.cs index 204b7414..76366a53 100644 --- a/src/Spring/Spring.Web/Web/UI/AbstractWizard.cs +++ b/src/Spring/Spring.Web/Web/UI/AbstractWizard.cs @@ -22,167 +22,168 @@ using System.Collections; using System.Web.UI; using System.Web.UI.WebControls; -namespace Spring.Web.UI +namespace Spring.Web.UI; + +/// +/// Convinience implementation of the wizard-like page controller. +/// +/// +///

+/// Wizard steps are encapsulated within custom user controls. Wizard +/// controller takes care of navigation through steps and loading of the +/// appropriate user control. +///

+///

+/// Developer implementing wizard needs to inherit from this class and implement +/// abstract, read-only StepPanel property that will be used as a container +/// for the wizard steps. Navigation event handlers should call Previous and Next methods +/// from this class to change current step. +///

+///
+/// Aleksandar Seovic +public abstract class AbstractWizard : Page { + private IList steps; + /// - /// Convinience implementation of the wizard-like page controller. + /// Gets or sets a list of user controls representing wizard steps. /// - /// - ///

- /// Wizard steps are encapsulated within custom user controls. Wizard - /// controller takes care of navigation through steps and loading of the - /// appropriate user control. - ///

- ///

- /// Developer implementing wizard needs to inherit from this class and implement - /// abstract, read-only StepPanel property that will be used as a container - /// for the wizard steps. Navigation event handlers should call Previous and Next methods - /// from this class to change current step. - ///

- ///
- /// Aleksandar Seovic - public abstract class AbstractWizard : Page + public IList Steps { - private IList steps; - - /// - /// Gets or sets a list of user controls representing wizard steps. - /// - public IList Steps - { - get { return steps; } - set { steps = value; } - } - - #region Wizard navigation members - - /// - /// Gets or sets current step using step index. - /// - public int CurrentStep - { - get - { - if (ViewState["__wizard.CurrentStep"] == null) - { - ViewState["__wizard.CurrentStep"] = 0; - } - return (int) ViewState["__wizard.CurrentStep"]; - } - set { ViewState["__wizard.CurrentStep"] = value; } - } - - /// - /// Returns true if there are no steps before the current step. - /// - public bool IsFirst - { - get { return CurrentStep == 0; } - } - - /// - /// Returns true if there are no steps after the current step. - /// - public bool IsLast - { - get { return CurrentStep == Steps.Count - 1; } - } - - /// - /// Moves to the previous step in the list, if one exists. - /// - public void Previous() - { - if (!IsFirst) - { - CurrentStep--; - } - } - - /// - /// Moves to the next step in the list, if one exists. - /// - public void Next() - { - if (!IsLast) - { - CurrentStep++; - } - } - - #endregion - - #region Page lifecycle methods - - /// - /// Initializes wizard steps. - /// - /// Event arguments. - protected override void OnInit(EventArgs e) - { - InitializeSteps(steps); - base.OnInit(e); - } - - /// - /// - /// - /// - protected override void OnLoad(EventArgs e) - { - base.OnLoad(e); - } - - /// - /// Loads new step into a step panel if step has changed. - /// - /// Event arguments. - protected override void OnPreRender(EventArgs e) - { - for (int i = 0; i < StepPanel.Controls.Count; i++) - { - StepPanel.Controls[i].Visible = (i == CurrentStep); - } - base.OnPreRender(e); - } - - /// - /// Initializes all the steps. - /// - /// List of step control names. - /// List of step control instances. - private void InitializeSteps(IList stepNames) - { - foreach (string stepName in stepNames) - { - Control step = LoadStep(stepName); - StepPanel.Controls.Add(step); - } - } - - /// - /// Loads step control. - /// - private Control LoadStep(string stepControlName) - { - Control step = LoadControl(stepControlName); - - int start = stepControlName.LastIndexOf('/'); - int end = stepControlName.LastIndexOf('.'); - step.ID = stepControlName.Substring(start + 1, end - start - 1); - - return step; - } - - #endregion - - #region Abstract members - - /// - /// Panel that should serve as a container for wizard steps. - /// - protected abstract Panel StepPanel { get; } - - #endregion + get { return steps; } + set { steps = value; } } + + #region Wizard navigation members + + /// + /// Gets or sets current step using step index. + /// + public int CurrentStep + { + get + { + if (ViewState["__wizard.CurrentStep"] == null) + { + ViewState["__wizard.CurrentStep"] = 0; + } + + return (int) ViewState["__wizard.CurrentStep"]; + } + set { ViewState["__wizard.CurrentStep"] = value; } + } + + /// + /// Returns true if there are no steps before the current step. + /// + public bool IsFirst + { + get { return CurrentStep == 0; } + } + + /// + /// Returns true if there are no steps after the current step. + /// + public bool IsLast + { + get { return CurrentStep == Steps.Count - 1; } + } + + /// + /// Moves to the previous step in the list, if one exists. + /// + public void Previous() + { + if (!IsFirst) + { + CurrentStep--; + } + } + + /// + /// Moves to the next step in the list, if one exists. + /// + public void Next() + { + if (!IsLast) + { + CurrentStep++; + } + } + + #endregion + + #region Page lifecycle methods + + /// + /// Initializes wizard steps. + /// + /// Event arguments. + protected override void OnInit(EventArgs e) + { + InitializeSteps(steps); + base.OnInit(e); + } + + /// + /// + /// + /// + protected override void OnLoad(EventArgs e) + { + base.OnLoad(e); + } + + /// + /// Loads new step into a step panel if step has changed. + /// + /// Event arguments. + protected override void OnPreRender(EventArgs e) + { + for (int i = 0; i < StepPanel.Controls.Count; i++) + { + StepPanel.Controls[i].Visible = (i == CurrentStep); + } + + base.OnPreRender(e); + } + + /// + /// Initializes all the steps. + /// + /// List of step control names. + /// List of step control instances. + private void InitializeSteps(IList stepNames) + { + foreach (string stepName in stepNames) + { + Control step = LoadStep(stepName); + StepPanel.Controls.Add(step); + } + } + + /// + /// Loads step control. + /// + private Control LoadStep(string stepControlName) + { + Control step = LoadControl(stepControlName); + + int start = stepControlName.LastIndexOf('/'); + int end = stepControlName.LastIndexOf('.'); + step.ID = stepControlName.Substring(start + 1, end - start - 1); + + return step; + } + + #endregion + + #region Abstract members + + /// + /// Panel that should serve as a container for wizard steps. + /// + protected abstract Panel StepPanel { get; } + + #endregion } diff --git a/src/Spring/Spring.Web/Web/UI/Controls/AbstractBaseValidator.cs b/src/Spring/Spring.Web/Web/UI/Controls/AbstractBaseValidator.cs index 1af27b6e..62626d1c 100644 --- a/src/Spring/Spring.Web/Web/UI/Controls/AbstractBaseValidator.cs +++ b/src/Spring/Spring.Web/Web/UI/Controls/AbstractBaseValidator.cs @@ -26,25 +26,25 @@ using System.Web.UI.WebControls; #endregion -namespace Spring.Web.UI.Controls +namespace Spring.Web.UI.Controls; + +/// +/// Provides functions required for implementing validators +/// but are unfortunately not accessible from +/// +/// Erich Eichinger +public abstract class AbstractBaseValidator : BaseValidator { - /// - /// Provides functions required for implementing validators - /// but are unfortunately not accessible from - /// - /// Erich Eichinger - public abstract class AbstractBaseValidator : BaseValidator + /// + /// Registers a javascript-block to be rendered. + /// + protected void RegisterClientScriptBlock(Type type, string key, string script) { - /// - /// Registers a javascript-block to be rendered. - /// - protected void RegisterClientScriptBlock(Type type, string key, string script) - { - this.Page.ClientScript.RegisterClientScriptBlock( - typeof(RequiredCheckBoxValidator) - , "RequiredCheckBoxValidatorEvaluateIsChecked" - , -@" + this.Page.ClientScript.RegisterClientScriptBlock( + typeof(RequiredCheckBoxValidator) + , "RequiredCheckBoxValidatorEvaluateIsChecked" + , + @" " - ); - } + ); + } - /// - /// Checks, if a certain javascript-block is already registered. - /// - protected bool IsClientScriptBlockRegistered(Type type, string key) - { - return this.Page.ClientScript.IsClientScriptBlockRegistered(type, key); - } + /// + /// Checks, if a certain javascript-block is already registered. + /// + protected bool IsClientScriptBlockRegistered(Type type, string key) + { + return this.Page.ClientScript.IsClientScriptBlockRegistered(type, key); + } - /// - /// Adds an attribute to be rendered for clientside validation. - /// - protected void AddExpandoAttribute(HtmlTextWriter writer, string controlId, string attributeName, string attributeValue, bool encode) + /// + /// Adds an attribute to be rendered for clientside validation. + /// + protected void AddExpandoAttribute(HtmlTextWriter writer, string controlId, string attributeName, string attributeValue, bool encode) + { + typeof(BaseValidator).InvokeMember("AddExpandoAttribute" + , + BindingFlags.InvokeMethod | BindingFlags.NonPublic + | BindingFlags.Instance + , null + , this + , new object[] { writer, controlId, attributeName, attributeValue, encode } + ); + } + + /// + /// Is "XHTML 1.0 Transitional" rendering allowed? + /// + protected bool EnableLegacyRendering + { + get { - typeof(BaseValidator).InvokeMember("AddExpandoAttribute" - , - BindingFlags.InvokeMethod | BindingFlags.NonPublic - | BindingFlags.Instance - , null - , this - , new object[] {writer, controlId, attributeName, attributeValue, encode} - ); - } - - /// - /// Is "XHTML 1.0 Transitional" rendering allowed? - /// - protected bool EnableLegacyRendering - { - get - { - return (bool) typeof(BaseValidator).GetProperty("EnableLegacyRendering", - BindingFlags.Instance - | BindingFlags.NonPublic).GetValue(this, null); - } + return (bool) typeof(BaseValidator).GetProperty("EnableLegacyRendering", + BindingFlags.Instance + | BindingFlags.NonPublic).GetValue(this, null); } } } diff --git a/src/Spring/Spring.Web/Web/UI/Controls/AbstractValidationControl.cs b/src/Spring/Spring.Web/Web/UI/Controls/AbstractValidationControl.cs index 5b613202..93c4e8bb 100644 --- a/src/Spring/Spring.Web/Web/UI/Controls/AbstractValidationControl.cs +++ b/src/Spring/Spring.Web/Web/UI/Controls/AbstractValidationControl.cs @@ -24,255 +24,263 @@ using Spring.Util; using Spring.Validation; using Spring.Web.UI.Validation; -namespace Spring.Web.UI.Controls +namespace Spring.Web.UI.Controls; + +/// +/// Provides common functionality to all validation renderer controls. +/// +/// Erich Eichinger +public abstract class AbstractValidationControl : Control { + private string _provider; + private string _validationContainerName; + private IValidationErrorsRenderer renderer; + private IValidationErrors _validationErrors; + private IMessageSource _messageSource; + /// - /// Provides common functionality to all validation renderer controls. + /// Set a particular message source to be used for + /// resolving error messages to display texts. /// - /// Erich Eichinger - public abstract class AbstractValidationControl : Control + /// + /// If not set, the control will probe the control hierarchy + /// for containing controls implementing + /// and use the container's . + /// + public IMessageSource MessageSource { - private string _provider; - private string _validationContainerName; - private IValidationErrorsRenderer renderer; - private IValidationErrors _validationErrors; - private IMessageSource _messageSource; + get { return _messageSource; } + set { _messageSource = value; } + } - /// - /// Set a particular message source to be used for - /// resolving error messages to display texts. - /// - /// - /// If not set, the control will probe the control hierarchy - /// for containing controls implementing - /// and use the container's . - /// - public IMessageSource MessageSource - { - get { return _messageSource; } - set { _messageSource = value; } - } + /// + /// Allows to set a particular instance of the validation errors + /// collection to render. + /// + /// + /// If not set, the control will probe the control hierarchy for + /// containing controls implementing + /// and use the container's + /// + public IValidationErrors ValidationErrors + { + get { return _validationErrors; } + set { _validationErrors = value; } + } - /// - /// Allows to set a particular instance of the validation errors - /// collection to render. - /// - /// - /// If not set, the control will probe the control hierarchy for - /// containing controls implementing - /// and use the container's - /// - public IValidationErrors ValidationErrors - { - get { return _validationErrors; } - set { _validationErrors = value; } - } + /// + /// If set, will resolve to the named control specified + /// by this property. The behavior of name resolution is identical to + /// , except that if the name + /// starts with "::", the resolution will start at the page level instead of relative to this + /// control + /// + public string ValidationContainerName + { + get { return _validationContainerName; } + set { _validationContainerName = value; } + } - /// - /// If set, will resolve to the named control specified - /// by this property. The behavior of name resolution is identical to - /// , except that if the name - /// starts with "::", the resolution will start at the page level instead of relative to this - /// control - /// - public string ValidationContainerName + /// + /// Gets or sets the provider. + /// + /// The provider. + public virtual string Provider + { + get { - get { return _validationContainerName; } - set { _validationContainerName = value; } - } - - /// - /// Gets or sets the provider. - /// - /// The provider. - public virtual string Provider - { - get + if (this._provider == null) { + this._provider = this.ID; if (this._provider == null) { - this._provider = this.ID; - if (this._provider == null) - { - this._provider = string.Empty; - } + this._provider = string.Empty; } - return this._provider; } - set + + return this._provider; + } + set + { + AssertUtils.ArgumentNotNull(value, "Provider"); + this._provider = value; + } + } + + /// + /// Gets or sets the validation errors renderer to use. + /// + /// + /// If not explicitly specified, defaults to . + /// + /// The validation errors renderer to use. + public IValidationErrorsRenderer Renderer + { + get + { + if (this.renderer == null) { - AssertUtils.ArgumentNotNull(value, "Provider"); - this._provider = value; + this.renderer = CreateValidationErrorsRenderer(); + AssertUtils.ArgumentNotNull(this.renderer, "Renderer", "CreateValidationErrorsRenderer must not return null"); + } + + return this.renderer; + } + set + { + AssertUtils.ArgumentNotNull(value, "Renderer"); + this.renderer = value; + } + } + + /// + /// Create the default + /// for this ValidationControl if none is configured. + /// + protected abstract IValidationErrorsRenderer CreateValidationErrorsRenderer(); + + /// + /// Gets the MessageSource to be used for resolve error messages + /// + /// + /// By default, returns 's MessageSource. + /// + /// the to resolve message texts. May be null + protected virtual IMessageSource ResolveMessageSource() + { + IMessageSource messageSource = this.MessageSource; + if (messageSource == null) + { + IValidationContainer validationContainer = FindValidationContainer(); + messageSource = (validationContainer == null) + ? null + : validationContainer.MessageSource; + } + + return messageSource; + } + + /// + /// Gets the list of validation errors to render + /// + /// the to render. May be null + protected virtual IValidationErrors ResolveValidationErrors() + { + IValidationErrors validationErrors = this.ValidationErrors; + + if (validationErrors == null) + { + IValidationContainer container = this.FindValidationContainer(); + if (container != null) + { + validationErrors = container.ValidationErrors; } } - /// - /// Gets or sets the validation errors renderer to use. - /// - /// - /// If not explicitly specified, defaults to . - /// - /// The validation errors renderer to use. - public IValidationErrorsRenderer Renderer + return validationErrors; + } + + /// + /// Gets the , who's + /// shall be rendered by this control. + /// + /// + /// First, it tries to resolve the specified , if any. If no explicit name + /// is set, will probe the control hierarchy for controls implementing . + /// + protected virtual IValidationContainer FindValidationContainer() + { + // is an explicit container specified? + if (ValidationContainerName != null && ValidationContainerName.Length > 0) { - get + Control start = this.NamingContainer; + string containerName = this.ValidationContainerName; + // shall we do a global search? + if (containerName.StartsWith("::")) { - if (this.renderer == null) - { - this.renderer = CreateValidationErrorsRenderer(); - AssertUtils.ArgumentNotNull(this.renderer, "Renderer", "CreateValidationErrorsRenderer must not return null"); - } - return this.renderer; + containerName = containerName.Substring(2); + start = this.Page; } - set + + IValidationContainer container = start as IValidationContainer; + if (containerName.Length > 0) { - AssertUtils.ArgumentNotNull(value, "Renderer"); - this.renderer = value; + container = start.FindControl(containerName) as IValidationContainer; } + + if (container == null) + { + throw new ArgumentException( + string.Format( + "Validation Container Control specified by {0} does not exist or does not implement IValidationContainer", + this.ValidationContainerName)); + } + + return container; } - /// - /// Create the default - /// for this ValidationControl if none is configured. - /// - protected abstract IValidationErrorsRenderer CreateValidationErrorsRenderer(); - - /// - /// Gets the MessageSource to be used for resolve error messages - /// - /// - /// By default, returns 's MessageSource. - /// - /// the to resolve message texts. May be null - protected virtual IMessageSource ResolveMessageSource() + for (Control parent = this.Parent; parent != null; parent = parent.Parent) { - IMessageSource messageSource = this.MessageSource; - if (messageSource == null) + IValidationContainer container = parent as IValidationContainer; + if (container != null + && container.ValidationErrors != null) { - IValidationContainer validationContainer = FindValidationContainer(); - messageSource = (validationContainer == null) - ? null - : validationContainer.MessageSource; - } - return messageSource; - } - - /// - /// Gets the list of validation errors to render - /// - /// the to render. May be null - protected virtual IValidationErrors ResolveValidationErrors() - { - IValidationErrors validationErrors = this.ValidationErrors; - - if (validationErrors == null) - { - IValidationContainer container = this.FindValidationContainer(); - if (container != null) - { - validationErrors = container.ValidationErrors; - } - } - return validationErrors; - } - - /// - /// Gets the , who's - /// shall be rendered by this control. - /// - /// - /// First, it tries to resolve the specified , if any. If no explicit name - /// is set, will probe the control hierarchy for controls implementing . - /// - protected virtual IValidationContainer FindValidationContainer() - { - // is an explicit container specified? - if (ValidationContainerName != null && ValidationContainerName.Length > 0) - { - Control start = this.NamingContainer; - string containerName = this.ValidationContainerName; - // shall we do a global search? - if (containerName.StartsWith("::")) - { - containerName = containerName.Substring(2); - start = this.Page; - } - IValidationContainer container = start as IValidationContainer; - if (containerName.Length > 0) - { - container = start.FindControl(containerName) as IValidationContainer; - } - if (container == null) - { - throw new ArgumentException( - string.Format( - "Validation Container Control specified by {0} does not exist or does not implement IValidationContainer", - this.ValidationContainerName)); - } return container; } - - for (Control parent = this.Parent; parent != null; parent = parent.Parent) - { - IValidationContainer container = parent as IValidationContainer; - if (container != null - && container.ValidationErrors != null) - { - return container; - } - } - return null; } - /// - /// Resolves the list of validation errors either explicitely specified using - /// or obtained from the containing - /// resolved by to a list - /// of elements containing the error messages to be rendered. - /// - /// - /// - /// The list of validation errors may either be explicitely specified using - /// or will automatically be obtained from the containing resolved by - /// . - /// - /// - /// Error Messages are resolved using either an explicitely specified or the - /// obtained from the validation container. - /// - /// - /// a list containing elements. May return null - protected virtual IList ResolveErrorMessages() + return null; + } + + /// + /// Resolves the list of validation errors either explicitely specified using + /// or obtained from the containing + /// resolved by to a list + /// of elements containing the error messages to be rendered. + /// + /// + /// + /// The list of validation errors may either be explicitely specified using + /// or will automatically be obtained from the containing resolved by + /// . + /// + /// + /// Error Messages are resolved using either an explicitely specified or the + /// obtained from the validation container. + /// + /// + /// a list containing elements. May return null + protected virtual IList ResolveErrorMessages() + { + IList errorMessages; + + // good catch - idea & patch from Roberto Paterlini + if (DesignMode) { - IList errorMessages; - - // good catch - idea & patch from Roberto Paterlini - if (DesignMode) - { - errorMessages = new string[] { GetType().Name + ":" + ID }; - return errorMessages; - } - - IValidationErrors validationErrors = ResolveValidationErrors(); - if (validationErrors == null) - { - return null; - } - IMessageSource messageSource = this.ResolveMessageSource(); - - errorMessages = validationErrors.GetResolvedErrors(this.Provider, messageSource); + errorMessages = new string[] { GetType().Name + ":" + ID }; return errorMessages; } - /// - /// Renders error messages using the specified . - /// - /// - protected override void Render(HtmlTextWriter writer) + IValidationErrors validationErrors = ResolveValidationErrors(); + if (validationErrors == null) { - IList errorMessages = ResolveErrorMessages(); - - Renderer.RenderErrors(Page as Page, writer, errorMessages); + return null; } + + IMessageSource messageSource = this.ResolveMessageSource(); + + errorMessages = validationErrors.GetResolvedErrors(this.Provider, messageSource); + return errorMessages; + } + + /// + /// Renders error messages using the specified . + /// + /// + protected override void Render(HtmlTextWriter writer) + { + IList errorMessages = ResolveErrorMessages(); + + Renderer.RenderErrors(Page as Page, writer, errorMessages); } } diff --git a/src/Spring/Spring.Web/Web/UI/Controls/Calendar.cs b/src/Spring/Spring.Web/Web/UI/Controls/Calendar.cs index 26e2cc0b..a7777c6e 100644 --- a/src/Spring/Spring.Web/Web/UI/Controls/Calendar.cs +++ b/src/Spring/Spring.Web/Web/UI/Controls/Calendar.cs @@ -27,262 +27,266 @@ using Spring.Util; #endregion -namespace Spring.Web.UI.Controls +namespace Spring.Web.UI.Controls; + +/// +/// Displays a pop-up DHTML calendar. +/// +/// +///

+/// Credit: this control uses a slightly modified version of the +/// Dynarch.com DHTML Calendar, +/// written by Mihai Bazon. +///

+///
+/// Aleksandar Seovic +[ValidationProperty("SelectedDate")] +public class Calendar : WebControl, IPostBackDataHandler { + private const string AllowEditingViewStateKey = "AllowEditing"; + private const string DateFormatViewStateKey = "Format"; + private const string SelectedDateViewStateKey = "SelectedDate"; + private static readonly object EventDateChanged = new object(); + + private string skin; + /// - /// Displays a pop-up DHTML calendar. + /// Registers necessary scripts and stylesheet. /// - /// - ///

- /// Credit: this control uses a slightly modified version of the - /// Dynarch.com DHTML Calendar, - /// written by Mihai Bazon. - ///

- ///
- /// Aleksandar Seovic - [ValidationProperty("SelectedDate")] - public class Calendar : WebControl, IPostBackDataHandler + /// + /// An object that contains the event data. + /// + protected override void OnPreRender(EventArgs e) { - private const string AllowEditingViewStateKey = "AllowEditing"; - private const string DateFormatViewStateKey = "Format"; - private const string SelectedDateViewStateKey = "SelectedDate"; - private static readonly object EventDateChanged = new object(); - - private string skin; - - /// - /// Registers necessary scripts and stylesheet. - /// - /// - /// An object that contains the event data. - /// - protected override void OnPreRender(EventArgs e) + if (skin != null) { - if (skin != null) + Page.RegisterStyleFile("CalendarStyle", WebUtils.CreateAbsolutePath(Page.ScriptsRoot, "Calendar/calendar-" + skin + ".css")); + } + + Page.RegisterHeadScriptFile("Calendar", WebUtils.CreateAbsolutePath(Page.ScriptsRoot, "Calendar/calendar.js")); + Page.RegisterHeadScriptFile("CalendarLanguage", WebUtils.CreateAbsolutePath(Page.ScriptsRoot, "Calendar/lang/calendar-" + Page.UserCulture.Name + ".js")); + Page.RegisterHeadScriptFile("CalendarSetup", WebUtils.CreateAbsolutePath(Page.ScriptsRoot, "Calendar/calendar-setup.js")); + } + + /// + /// Gets a reference to the instance that contains the + /// server control. + /// + /// + /// A reference to the instance that contains the + /// server control. + /// + private new Page Page + { + get { return base.Page as Page; } + } + + /// + /// The selected date. + /// + /// The selected date. + public DateTime SelectedDate + { + get + { + if (this.ViewState[SelectedDateViewStateKey] == null) { - Page.RegisterStyleFile("CalendarStyle", WebUtils.CreateAbsolutePath(Page.ScriptsRoot, "Calendar/calendar-" + skin + ".css")); - } - Page.RegisterHeadScriptFile("Calendar", WebUtils.CreateAbsolutePath(Page.ScriptsRoot, "Calendar/calendar.js")); - Page.RegisterHeadScriptFile("CalendarLanguage", WebUtils.CreateAbsolutePath(Page.ScriptsRoot, "Calendar/lang/calendar-" + Page.UserCulture.Name + ".js")); - Page.RegisterHeadScriptFile("CalendarSetup", WebUtils.CreateAbsolutePath(Page.ScriptsRoot, "Calendar/calendar-setup.js")); - } - - /// - /// Gets a reference to the instance that contains the - /// server control. - /// - /// - /// A reference to the instance that contains the - /// server control. - /// - private new Page Page - { - get { return base.Page as Page; } - } - - /// - /// The selected date. - /// - /// The selected date. - public DateTime SelectedDate - { - get - { - if (this.ViewState[SelectedDateViewStateKey] == null) - { - return DateTime.Now; - } - return (DateTime)this.ViewState[SelectedDateViewStateKey]; - } - set { this.ViewState[SelectedDateViewStateKey] = value; } - } - - /// - /// The date format that is to be used. - /// - /// A valid date format string. - public string Format - { - get - { - if (this.ViewState[DateFormatViewStateKey] == null) - { - return Thread.CurrentThread.CurrentCulture.DateTimeFormat.ShortDatePattern; - } - return (string)this.ViewState[DateFormatViewStateKey]; - } - set { this.ViewState[DateFormatViewStateKey] = value; } - } - - /// - /// Is direct editing of the date allowed? - /// - /// - /// if direct editing of the date is allowed? - public bool AllowEditing - { - get - { - if (this.ViewState[AllowEditingViewStateKey] == null) - { - return true; - } - return (bool)this.ViewState[AllowEditingViewStateKey]; - } - set { this.ViewState[AllowEditingViewStateKey] = value; } - } - - /// - /// The (CSS) style. - /// - /// The style for the calendar. - public string Skin - { - get { return skin; } - set { skin = value; } - } - - /// - /// Renders a hidden input field that stores the value for the radio button group. - /// - /// - /// to use for rendering. - /// - protected override void Render(HtmlTextWriter writer) - { - writer.AddAttribute(HtmlTextWriterAttribute.Cellspacing, "0"); - writer.AddAttribute(HtmlTextWriterAttribute.Cellpadding, "0"); - - writer.RenderBeginTag(HtmlTextWriterTag.Table); - writer.RenderBeginTag(HtmlTextWriterTag.Tr); - writer.RenderBeginTag(HtmlTextWriterTag.Td); - - RenderTextBox(writer); - - writer.RenderEndTag(); - writer.RenderBeginTag(HtmlTextWriterTag.Td); - - if (Enabled) - { - RenderButton(writer); + return DateTime.Now; } - writer.RenderEndTag(); - writer.RenderEndTag(); - writer.RenderEndTag(); - - RenderSetupScript(writer); + return (DateTime) this.ViewState[SelectedDateViewStateKey]; } + set { this.ViewState[SelectedDateViewStateKey] = value; } + } - private void RenderTextBox(HtmlTextWriter writer) + /// + /// The date format that is to be used. + /// + /// A valid date format string. + public string Format + { + get { - writer.AddAttribute(HtmlTextWriterAttribute.Type, "text"); - writer.AddAttribute(HtmlTextWriterAttribute.Name, UniqueID); - writer.AddAttribute(HtmlTextWriterAttribute.Value, (SelectedDate != DateTime.MinValue ? SelectedDate.ToString(Format) : "")); - - if (!AllowEditing) + if (this.ViewState[DateFormatViewStateKey] == null) { - writer.AddAttribute(HtmlTextWriterAttribute.ReadOnly, "readonly"); + return Thread.CurrentThread.CurrentCulture.DateTimeFormat.ShortDatePattern; } - base.AddAttributesToRender(writer); - - - writer.RenderBeginTag(HtmlTextWriterTag.Input); - writer.RenderEndTag(); + return (string) this.ViewState[DateFormatViewStateKey]; } + set { this.ViewState[DateFormatViewStateKey] = value; } + } - private void RenderButton(HtmlTextWriter writer) + /// + /// Is direct editing of the date allowed? + /// + /// + /// if direct editing of the date is allowed? + public bool AllowEditing + { + get { - writer.AddAttribute(HtmlTextWriterAttribute.Id, ClientID + "_button"); - writer.AddAttribute(HtmlTextWriterAttribute.Src, WebUtils.CreateAbsolutePath(Page.ScriptsRoot, "Calendar/img.gif")); - writer.AddAttribute(HtmlTextWriterAttribute.Border, "0"); - - writer.RenderBeginTag(HtmlTextWriterTag.Img); - writer.RenderEndTag(); - } - - private void RenderSetupScript(HtmlTextWriter writer) - { - writer.AddAttribute("type", "text/javascript"); - - writer.RenderBeginTag(HtmlTextWriterTag.Script); - writer.WriteLine("Calendar.setup({"); - writer.WriteLine(" inputField : \"" + ClientID + "\","); - writer.WriteLine(" button : \"" + ClientID + "_button\""); - writer.WriteLine("});"); - writer.RenderEndTag(); - } - - #region IPostBackDataHandler Members - - /// - /// Raises the SelectionChanged event. - /// - public void RaisePostDataChangedEvent() - { - OnDateChanged(EventArgs.Empty); - } - - /// - /// Loads postback data into the control. - /// - /// - /// The key that should be used to retrieve data. - /// - /// The postback data collection. - /// if data has changed. - public bool LoadPostData(string postDataKey, NameValueCollection postCollection) - { - DateTime dateValue; - string dateString = postCollection[postDataKey]; - if (StringUtils.HasText(dateString)) + if (this.ViewState[AllowEditingViewStateKey] == null) { - try - { - dateValue = DateTime.Parse(dateString); - } - catch (FormatException) - { - dateValue = DateTime.MinValue; - } + return true; } - else + + return (bool) this.ViewState[AllowEditingViewStateKey]; + } + set { this.ViewState[AllowEditingViewStateKey] = value; } + } + + /// + /// The (CSS) style. + /// + /// The style for the calendar. + public string Skin + { + get { return skin; } + set { skin = value; } + } + + /// + /// Renders a hidden input field that stores the value for the radio button group. + /// + /// + /// to use for rendering. + /// + protected override void Render(HtmlTextWriter writer) + { + writer.AddAttribute(HtmlTextWriterAttribute.Cellspacing, "0"); + writer.AddAttribute(HtmlTextWriterAttribute.Cellpadding, "0"); + + writer.RenderBeginTag(HtmlTextWriterTag.Table); + writer.RenderBeginTag(HtmlTextWriterTag.Tr); + writer.RenderBeginTag(HtmlTextWriterTag.Td); + + RenderTextBox(writer); + + writer.RenderEndTag(); + writer.RenderBeginTag(HtmlTextWriterTag.Td); + + if (Enabled) + { + RenderButton(writer); + } + + writer.RenderEndTag(); + writer.RenderEndTag(); + writer.RenderEndTag(); + + RenderSetupScript(writer); + } + + private void RenderTextBox(HtmlTextWriter writer) + { + writer.AddAttribute(HtmlTextWriterAttribute.Type, "text"); + writer.AddAttribute(HtmlTextWriterAttribute.Name, UniqueID); + writer.AddAttribute(HtmlTextWriterAttribute.Value, (SelectedDate != DateTime.MinValue ? SelectedDate.ToString(Format) : "")); + + if (!AllowEditing) + { + writer.AddAttribute(HtmlTextWriterAttribute.ReadOnly, "readonly"); + } + + base.AddAttributesToRender(writer); + + writer.RenderBeginTag(HtmlTextWriterTag.Input); + writer.RenderEndTag(); + } + + private void RenderButton(HtmlTextWriter writer) + { + writer.AddAttribute(HtmlTextWriterAttribute.Id, ClientID + "_button"); + writer.AddAttribute(HtmlTextWriterAttribute.Src, WebUtils.CreateAbsolutePath(Page.ScriptsRoot, "Calendar/img.gif")); + writer.AddAttribute(HtmlTextWriterAttribute.Border, "0"); + + writer.RenderBeginTag(HtmlTextWriterTag.Img); + writer.RenderEndTag(); + } + + private void RenderSetupScript(HtmlTextWriter writer) + { + writer.AddAttribute("type", "text/javascript"); + + writer.RenderBeginTag(HtmlTextWriterTag.Script); + writer.WriteLine("Calendar.setup({"); + writer.WriteLine(" inputField : \"" + ClientID + "\","); + writer.WriteLine(" button : \"" + ClientID + "_button\""); + writer.WriteLine("});"); + writer.RenderEndTag(); + } + + #region IPostBackDataHandler Members + + /// + /// Raises the SelectionChanged event. + /// + public void RaisePostDataChangedEvent() + { + OnDateChanged(EventArgs.Empty); + } + + /// + /// Loads postback data into the control. + /// + /// + /// The key that should be used to retrieve data. + /// + /// The postback data collection. + /// if data has changed. + public bool LoadPostData(string postDataKey, NameValueCollection postCollection) + { + DateTime dateValue; + string dateString = postCollection[postDataKey]; + if (StringUtils.HasText(dateString)) + { + try + { + dateValue = DateTime.Parse(dateString); + } + catch (FormatException) { dateValue = DateTime.MinValue; } - bool changed = dateValue != this.SelectedDate; - if (changed) - { - this.ViewState[SelectedDateViewStateKey] = dateValue; - } - return changed; + } + else + { + dateValue = DateTime.MinValue; } - #endregion - - /// - /// The method that is called on postback if the date has changed. - /// - /// - /// The event argument (empty and unused). - /// - protected virtual void OnDateChanged(EventArgs e) + bool changed = dateValue != this.SelectedDate; + if (changed) { - EventHandler handler = (EventHandler)base.Events[EventDateChanged]; - if (handler != null) - { - handler(this, e); - } + this.ViewState[SelectedDateViewStateKey] = dateValue; } - /// - /// Occurs when the value of the radio button group changes between postbacks to the server. - /// - public event EventHandler DateChanged + return changed; + } + + #endregion + + /// + /// The method that is called on postback if the date has changed. + /// + /// + /// The event argument (empty and unused). + /// + protected virtual void OnDateChanged(EventArgs e) + { + EventHandler handler = (EventHandler) base.Events[EventDateChanged]; + if (handler != null) { - add { base.Events.AddHandler(EventDateChanged, value); } - remove { base.Events.RemoveHandler(EventDateChanged, value); } + handler(this, e); } } + + /// + /// Occurs when the value of the radio button group changes between postbacks to the server. + /// + public event EventHandler DateChanged + { + add { base.Events.AddHandler(EventDateChanged, value); } + remove { base.Events.RemoveHandler(EventDateChanged, value); } + } } diff --git a/src/Spring/Spring.Web/Web/UI/Controls/CheckBoxList.cs b/src/Spring/Spring.Web/Web/UI/Controls/CheckBoxList.cs index e295ed6e..cb044575 100644 --- a/src/Spring/Spring.Web/Web/UI/Controls/CheckBoxList.cs +++ b/src/Spring/Spring.Web/Web/UI/Controls/CheckBoxList.cs @@ -24,46 +24,46 @@ using System.Web.UI.WebControls; #endregion -namespace Spring.Web.UI.Controls +namespace Spring.Web.UI.Controls; + +/// +/// Adds the property to the framework's control. +/// +/// +/// When using Spring.Web's DataBinding, you should use this control for easier binding declaration. +/// +/// Erich Eichinger +public class CheckBoxList : System.Web.UI.WebControls.CheckBoxList { - /// - /// Adds the property to the framework's control. - /// - /// - /// When using Spring.Web's DataBinding, you should use this control for easier binding declaration. - /// - /// Erich Eichinger - public class CheckBoxList : System.Web.UI.WebControls.CheckBoxList - { - /// - /// Gets or Sets the list of selected values and checks the es accordingly - /// - public string[] SelectedValues - { - get - { - List vals = new List(); - foreach( ListItem item in this.Items ) - { - if (item.Selected) vals.Add(item.Value); - } - return vals.ToArray(); - } - set - { - if (value == null || value.Length == 0) - { - this.ClearSelection(); - } - else - { - List vals = new List(); - foreach (ListItem item in this.Items) - { - item.Selected = (vals.Contains(item.Value)); - } - } - } - } - } + /// + /// Gets or Sets the list of selected values and checks the es accordingly + /// + public string[] SelectedValues + { + get + { + List vals = new List(); + foreach (ListItem item in this.Items) + { + if (item.Selected) vals.Add(item.Value); + } + + return vals.ToArray(); + } + set + { + if (value == null || value.Length == 0) + { + this.ClearSelection(); + } + else + { + List vals = new List(); + foreach (ListItem item in this.Items) + { + item.Selected = (vals.Contains(item.Value)); + } + } + } + } } diff --git a/src/Spring/Spring.Web/Web/UI/Controls/CheckBoxValidator.cs b/src/Spring/Spring.Web/Web/UI/Controls/CheckBoxValidator.cs index a3c3f989..045e7f26 100644 --- a/src/Spring/Spring.Web/Web/UI/Controls/CheckBoxValidator.cs +++ b/src/Spring/Spring.Web/Web/UI/Controls/CheckBoxValidator.cs @@ -25,74 +25,75 @@ using System.Web.UI.WebControls; #endregion -namespace Spring.Web.UI.Controls +namespace Spring.Web.UI.Controls; + +/// +/// This validator allows for validating a CheckBox's "Checked" state. +/// +/// Erich Eichinger +[ToolboxData("<{0}:RequiredCheckBoxValidator runat=\"server\" ErrorMessage=\"RequiredCheckBoxValidator\">")] +public class RequiredCheckBoxValidator : AbstractBaseValidator { - /// - /// This validator allows for validating a CheckBox's "Checked" state. - /// - /// Erich Eichinger - [ToolboxData("<{0}:RequiredCheckBoxValidator runat=\"server\" ErrorMessage=\"RequiredCheckBoxValidator\">")] - public class RequiredCheckBoxValidator : AbstractBaseValidator + /// + /// Validates this validator's properties are set correctly. + /// + /// + protected override bool ControlPropertiesValid() { - /// - /// Validates this validator's properties are set correctly. - /// - /// - protected override bool ControlPropertiesValid() + string controlName = this.ControlToValidate; + if (controlName.Length == 0) { - string controlName = this.ControlToValidate; - if(controlName.Length == 0) - { - return base.ControlPropertiesValid(); - } - return true; + return base.ControlPropertiesValid(); } - /// - /// Returns the state of the checkbox's Checked property - /// - /// - protected override bool EvaluateIsValid() - { - CheckBox controlToValidate = this.NamingContainer.FindControl(this.ControlToValidate) as CheckBox; - if(controlToValidate == null) - { - return false; - } + return true; + } - return controlToValidate.Checked; + /// + /// Returns the state of the checkbox's Checked property + /// + /// + protected override bool EvaluateIsValid() + { + CheckBox controlToValidate = this.NamingContainer.FindControl(this.ControlToValidate) as CheckBox; + if (controlToValidate == null) + { + return false; } - /// - /// Adds attributes required for clientside validation - /// - /// - protected override void AddAttributesToRender(HtmlTextWriter writer) - { - base.AddAttributesToRender(writer); - if(base.RenderUplevel) - { - string controlId = this.ClientID; - writer = base.EnableLegacyRendering ? writer : null; - base.AddExpandoAttribute(writer, controlId, "evaluationfunction", "RequiredCheckBoxValidatorEvaluateIsChecked", false); - base.AddExpandoAttribute(writer, controlId, "initialvalue", "", true); - } - } + return controlToValidate.Checked; + } - /// - /// Ensures the evaluation javascript functionblock is registered - /// - /// - protected override void OnPreRender(EventArgs e) + /// + /// Adds attributes required for clientside validation + /// + /// + protected override void AddAttributesToRender(HtmlTextWriter writer) + { + base.AddAttributesToRender(writer); + if (base.RenderUplevel) { - base.OnPreRender(e); - if (!base.IsClientScriptBlockRegistered(typeof(RequiredCheckBoxValidator), "RequiredCheckBoxValidatorEvaluateIsChecked")) - { - base.RegisterClientScriptBlock( - typeof(RequiredCheckBoxValidator) - , "RequiredCheckBoxValidatorEvaluateIsChecked" - , -@" + string controlId = this.ClientID; + writer = base.EnableLegacyRendering ? writer : null; + base.AddExpandoAttribute(writer, controlId, "evaluationfunction", "RequiredCheckBoxValidatorEvaluateIsChecked", false); + base.AddExpandoAttribute(writer, controlId, "initialvalue", "", true); + } + } + + /// + /// Ensures the evaluation javascript functionblock is registered + /// + /// + protected override void OnPreRender(EventArgs e) + { + base.OnPreRender(e); + if (!base.IsClientScriptBlockRegistered(typeof(RequiredCheckBoxValidator), "RequiredCheckBoxValidatorEvaluateIsChecked")) + { + base.RegisterClientScriptBlock( + typeof(RequiredCheckBoxValidator) + , "RequiredCheckBoxValidatorEvaluateIsChecked" + , + @" " - ); - } + ); } } } diff --git a/src/Spring/Spring.Web/Web/UI/Controls/Content.cs b/src/Spring/Spring.Web/Web/UI/Controls/Content.cs index d91f3377..a6763323 100644 --- a/src/Spring/Spring.Web/Web/UI/Controls/Content.cs +++ b/src/Spring/Spring.Web/Web/UI/Controls/Content.cs @@ -20,22 +20,20 @@ #region Imports - - #endregion -namespace Spring.Web.UI.Controls +namespace Spring.Web.UI.Controls; + +/// +/// Represents Content control that can be used to populate or override placeholders +/// within the master page. +/// +/// +/// Any content defined within this control will override default content +/// in the matching control +/// within the master page +/// +/// Aleksandar Seovic +public class Content : System.Web.UI.WebControls.Content { - /// - /// Represents Content control that can be used to populate or override placeholders - /// within the master page. - /// - /// - /// Any content defined within this control will override default content - /// in the matching control - /// within the master page - /// - /// Aleksandar Seovic - public class Content : System.Web.UI.WebControls.Content - {} -} +} \ No newline at end of file diff --git a/src/Spring/Spring.Web/Web/UI/Controls/ContentPlaceholder.cs b/src/Spring/Spring.Web/Web/UI/Controls/ContentPlaceholder.cs index 969a3f15..154b284f 100644 --- a/src/Spring/Spring.Web/Web/UI/Controls/ContentPlaceholder.cs +++ b/src/Spring/Spring.Web/Web/UI/Controls/ContentPlaceholder.cs @@ -18,20 +18,18 @@ #endregion -namespace Spring.Web.UI.Controls +namespace Spring.Web.UI.Controls; + +/// +/// Represents ContentPlaceHolder control that can be used to define placeholders +/// within the master page. +/// +/// +/// Any content defined within this control will be treated as a default content +/// for the placeholder and will be rendered unless the child page overrides it +/// by defining matching control. +/// +/// Aleksandar Seovic +public class ContentPlaceHolder : System.Web.UI.WebControls.ContentPlaceHolder { - /// - /// Represents ContentPlaceHolder control that can be used to define placeholders - /// within the master page. - /// - /// - /// Any content defined within this control will be treated as a default content - /// for the placeholder and will be rendered unless the child page overrides it - /// by defining matching control. - /// - /// Aleksandar Seovic - public class ContentPlaceHolder : System.Web.UI.WebControls.ContentPlaceHolder - { - - } -} +} \ No newline at end of file diff --git a/src/Spring/Spring.Web/Web/UI/Controls/ContentReplacer.cs b/src/Spring/Spring.Web/Web/UI/Controls/ContentReplacer.cs index 2137324f..f83cc94e 100644 --- a/src/Spring/Spring.Web/Web/UI/Controls/ContentReplacer.cs +++ b/src/Spring/Spring.Web/Web/UI/Controls/ContentReplacer.cs @@ -22,111 +22,112 @@ using System.Reflection; using System.Web.UI; using Microsoft.Extensions.Logging; -namespace Spring.Web.UI.Controls +namespace Spring.Web.UI.Controls; + +/// +/// Represents Content control that can be used to populate or override placeholders +/// anywhere within the page. +/// +/// +/// +/// Any content defined within this control will override default content +/// in the matching control specified by anywhere +/// within the page. +/// +/// +/// In contrast to control, ContentReplacer can replace the content of +/// any control within the current page - it is not limited to replacing ContentPlaceholders on master pages. +/// +/// +/// This technique is useful if you want to group e.g. rendering navigation elements on 1 ascx control, but your +/// design requires navigation elements to be distributed across different places within the HTML code. +/// +/// +/// Erich Eichinger +public class ContentReplacer : Control { + private static readonly ILogger log = LogManager.GetLogger(); + + private string contentPlaceHolderID; + /// - /// Represents Content control that can be used to populate or override placeholders - /// anywhere within the page. + /// Specifies the unique id of the control, who's content is to be replaced. /// - /// - /// - /// Any content defined within this control will override default content - /// in the matching control specified by anywhere - /// within the page. - /// - /// - /// In contrast to control, ContentReplacer can replace the content of - /// any control within the current page - it is not limited to replacing ContentPlaceholders on master pages. - /// - /// - /// This technique is useful if you want to group e.g. rendering navigation elements on 1 ascx control, but your - /// design requires navigation elements to be distributed across different places within the HTML code. - /// - /// - /// Erich Eichinger - public class ContentReplacer : Control + public string ContentPlaceHolderID { - private static readonly ILogger log = LogManager.GetLogger(); + get { return contentPlaceHolderID; } + set { contentPlaceHolderID = value; } + } - private string contentPlaceHolderID; + /// + /// Overriden to correctly redirect rendermethod calls. + /// + protected override void OnPreRender(EventArgs e) + { + base.OnPreRender(e); - /// - /// Specifies the unique id of the control, who's content is to be replaced. - /// - public string ContentPlaceHolderID + // if our container is not visible, don't replace placeholder's content + if (!Visible) return; + + //log.Debug(string.Format("OnPreRender Content['{0}']", this.contentPlaceHolderID)); + Control ctlRoot = Page.Master != null ? Page.Master : (Control) Page; + + Control ctl = ctlRoot.FindControl(this.contentPlaceHolderID); + if (ctl != null) { - get { return contentPlaceHolderID; } - set { contentPlaceHolderID = value; } - } + log.LogDebug(string.Format("OnPreRender Content['{0}'] found placeholder - replacing RenderMethod", this.contentPlaceHolderID)); - /// - /// Overriden to correctly redirect rendermethod calls. - /// - protected override void OnPreRender(EventArgs e) - { - base.OnPreRender(e); + RenderMethod myRenderMethod = GetRenderMethod(); + //log.Debug(string.Format("OnPreRender Content['{0}'] renderMethod found={1}", this.contentPlaceHolderID,(myRenderMethod != null ? "true" : "false"))); - // if our container is not visible, don't replace placeholder's content - if (!Visible) return; - - //log.Debug(string.Format("OnPreRender Content['{0}']", this.contentPlaceHolderID)); - Control ctlRoot = Page.Master != null ? Page.Master : (Control) Page; - - Control ctl = ctlRoot.FindControl(this.contentPlaceHolderID); - if (ctl != null) + // prevent content control from rendering itself + this.SetRenderMethodDelegate(new RenderMethod(RenderNothing)); + if (myRenderMethod == null) { - log.LogDebug(string.Format("OnPreRender Content['{0}'] found placeholder - replacing RenderMethod",this.contentPlaceHolderID)); - - RenderMethod myRenderMethod = GetRenderMethod(); - //log.Debug(string.Format("OnPreRender Content['{0}'] renderMethod found={1}", this.contentPlaceHolderID,(myRenderMethod != null ? "true" : "false"))); - - // prevent content control from rendering itself - this.SetRenderMethodDelegate(new RenderMethod(RenderNothing)); - if (myRenderMethod == null) - { - myRenderMethod = new RenderMethod(RenderChildControls); - } - // instead replace placeholder's rendermethod to render this control's content - ctl.SetRenderMethodDelegate(myRenderMethod); - } - else - { - throw new ArgumentException(string.Format("No ContentPlaceHolder with id '{0}' defined on this page.", this.contentPlaceHolderID)); + myRenderMethod = new RenderMethod(RenderChildControls); } + + // instead replace placeholder's rendermethod to render this control's content + ctl.SetRenderMethodDelegate(myRenderMethod); } - - /// - /// Renders child controls - /// - private void RenderChildControls(HtmlTextWriter output, Control container) + else { - if (this.HasControls()) - { - foreach (Control ctl in this.Controls) - { - ctl.RenderControl(output); - } - } - } - - /// - /// Render nothing. - /// - private void RenderNothing(HtmlTextWriter output, Control container) - { - // do nothing - } - - private static readonly PropertyInfo piRareFieldsEnsured = - typeof(Control).GetProperty("RareFieldsEnsured", BindingFlags.NonPublic | BindingFlags.Instance); - private static readonly FieldInfo fiRenderMethod = - typeof(Control).GetNestedType("ControlRareFields",BindingFlags.NonPublic).GetField("RenderMethod"); - - private RenderMethod GetRenderMethod() - { - object o = piRareFieldsEnsured.GetValue(this, null); - RenderMethod myRenderMethod = (RenderMethod) fiRenderMethod.GetValue(o); - return myRenderMethod; + throw new ArgumentException(string.Format("No ContentPlaceHolder with id '{0}' defined on this page.", this.contentPlaceHolderID)); } } + + /// + /// Renders child controls + /// + private void RenderChildControls(HtmlTextWriter output, Control container) + { + if (this.HasControls()) + { + foreach (Control ctl in this.Controls) + { + ctl.RenderControl(output); + } + } + } + + /// + /// Render nothing. + /// + private void RenderNothing(HtmlTextWriter output, Control container) + { + // do nothing + } + + private static readonly PropertyInfo piRareFieldsEnsured = + typeof(Control).GetProperty("RareFieldsEnsured", BindingFlags.NonPublic | BindingFlags.Instance); + + private static readonly FieldInfo fiRenderMethod = + typeof(Control).GetNestedType("ControlRareFields", BindingFlags.NonPublic).GetField("RenderMethod"); + + private RenderMethod GetRenderMethod() + { + object o = piRareFieldsEnsured.GetValue(this, null); + RenderMethod myRenderMethod = (RenderMethod) fiRenderMethod.GetValue(o); + return myRenderMethod; + } } diff --git a/src/Spring/Spring.Web/Web/UI/Controls/DataBindingAdapter.cs b/src/Spring/Spring.Web/Web/UI/Controls/DataBindingAdapter.cs index 59c234b3..ce0ee2e7 100644 --- a/src/Spring/Spring.Web/Web/UI/Controls/DataBindingAdapter.cs +++ b/src/Spring/Spring.Web/Web/UI/Controls/DataBindingAdapter.cs @@ -2,51 +2,50 @@ using System.Web; using System.Web.UI; using System.Web.UI.WebControls; -namespace Spring.Web.UI.Controls +namespace Spring.Web.UI.Controls; + +/// +/// May be used to wrap controls for databinding that don't accept unknown attributes. +/// +[ParseChildren(false)] +public class DataBindingAdapter : WebControl { + private Control wrappedControl; + /// - /// May be used to wrap controls for databinding that don't accept unknown attributes. + /// Overridden to ensure only 1 control is wrapped by this adapter /// - [ParseChildren(false)] - public class DataBindingAdapter : WebControl + /// + protected override void AddParsedSubObject(object obj) { - private Control wrappedControl; - - /// - /// Overridden to ensure only 1 control is wrapped by this adapter - /// - /// - protected override void AddParsedSubObject(object obj) + if (obj is Control && (wrappedControl == null) && (!(obj is LiteralControl))) { - if(obj is Control && (wrappedControl == null) && (!(obj is LiteralControl))) - { - wrappedControl = (Control) obj; - this.Controls.Add(wrappedControl); - } - else if(!(obj is LiteralControl)) - { - throw new HttpException( - string.Format("DataBindingAdapter can only have 1 non-literal child", new object[] { obj.GetType().Name })); - } + wrappedControl = (Control) obj; + this.Controls.Add(wrappedControl); } - - /// - /// Returns the control wrapped by this adapter or null. - /// - public Control WrappedControl + else if (!(obj is LiteralControl)) { - get { return this.wrappedControl; } + throw new HttpException( + string.Format("DataBindingAdapter can only have 1 non-literal child", new object[] { obj.GetType().Name })); } + } - /// - /// Overridden to render wrapped control only. - /// - protected override void Render(HtmlTextWriter writer) + /// + /// Returns the control wrapped by this adapter or null. + /// + public Control WrappedControl + { + get { return this.wrappedControl; } + } + + /// + /// Overridden to render wrapped control only. + /// + protected override void Render(HtmlTextWriter writer) + { + if (wrappedControl != null) { - if (wrappedControl != null) - { - wrappedControl.RenderControl(writer); - } + wrappedControl.RenderControl(writer); } } } \ No newline at end of file diff --git a/src/Spring/Spring.Web/Web/UI/Controls/DataBindingPanel.cs b/src/Spring/Spring.Web/Web/UI/Controls/DataBindingPanel.cs index de1085ba..d42b1fb8 100644 --- a/src/Spring/Spring.Web/Web/UI/Controls/DataBindingPanel.cs +++ b/src/Spring/Spring.Web/Web/UI/Controls/DataBindingPanel.cs @@ -31,342 +31,348 @@ using Spring.Core.TypeResolution; using Spring.DataBinding; using Spring.Globalization; using Spring.Util; -using AttributeCollection=System.Web.UI.AttributeCollection; -using BindingDirection=Spring.DataBinding.BindingDirection; +using AttributeCollection = System.Web.UI.AttributeCollection; +using BindingDirection = Spring.DataBinding.BindingDirection; #endregion -namespace Spring.Web.UI.Controls +namespace Spring.Web.UI.Controls; + +/// +/// Any WebControl placed on a DataBindingPanel may be bound +/// to a model by adding an attribute "BindingTarget" +/// +/// Erich Eichinger +[PersistChildren(true), + ToolboxData("<{0}:DataBindingPanel runat=\"server\" Width=\"125px\" Height=\"50px\"> "), + ParseChildren(false), + Designer("System.Web.UI.Design.WebControls.PanelContainerDesigner, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"), + AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal), + AspNetHostingPermission(SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)] +public class DataBindingPanel : Panel { + private const string ATTR_BINDINGTARGET = "BindingTarget"; + private const string ATTR_BINDINGSOURCE = "BindingSource"; + private const string ATTR_BINDINGDIRECTION = "BindingDirection"; + private const string ATTR_BINDINGFORMATTER = "BindingFormatter"; + private const string ATTR_BINDINGTYPE = "BindingType"; + private const string ATTR_MESSAGEID = "MessageId"; + private const string ATTR_ERRORPROVIDERS = "ErrorProviders"; + + private static readonly ILogger Log = LogManager.GetLogger(); + + private delegate void TraversalAction(IWebDataBound bindingContainer, WebControl wc); + /// - /// Any WebControl placed on a DataBindingPanel may be bound - /// to a model by adding an attribute "BindingTarget" + /// Registers this control for the event of it's container. /// - /// Erich Eichinger - [PersistChildren(true), - ToolboxData("<{0}:DataBindingPanel runat=\"server\" Width=\"125px\" Height=\"50px\"> "), - ParseChildren(false), - Designer("System.Web.UI.Design.WebControls.PanelContainerDesigner, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"), - AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal), - AspNetHostingPermission(SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)] - public class DataBindingPanel : Panel + protected override void OnInit(EventArgs e) { - private const string ATTR_BINDINGTARGET = "BindingTarget"; - private const string ATTR_BINDINGSOURCE = "BindingSource"; - private const string ATTR_BINDINGDIRECTION = "BindingDirection"; - private const string ATTR_BINDINGFORMATTER = "BindingFormatter"; - private const string ATTR_BINDINGTYPE = "BindingType"; - private const string ATTR_MESSAGEID = "MessageId"; - private const string ATTR_ERRORPROVIDERS = "ErrorProviders"; + RegisterDataControl(this, new EventHandler(BindingOwner_DataBindingsInitialized)); + base.OnInit(e); + } - private static readonly ILogger Log = LogManager.GetLogger(); - - private delegate void TraversalAction(IWebDataBound bindingContainer, WebControl wc); - - /// - /// Registers this control for the event of it's container. - /// - protected override void OnInit(EventArgs e) + /// + /// Overridden to remove custom binding attributes before rendering. + /// + /// + protected override void OnPreRender(EventArgs e) + { + // remove custom attributes + if (this.HasControls()) { - RegisterDataControl(this, new EventHandler(BindingOwner_DataBindingsInitialized)); - base.OnInit(e); + this.TraverseControls(null, this.Controls, new TraversalAction(this.RemoveBindingAttributes)); } - /// - /// Overridden to remove custom binding attributes before rendering. - /// - /// - protected override void OnPreRender(EventArgs e) + base.OnPreRender(e); + } + + /// + /// Overriden to suppress rendering this control's tag + /// + /// + protected override void Render(HtmlTextWriter writer) + { + base.RenderContents(writer); + } + + /// + /// Called by the containing if bindings must be initialized. + /// + private void BindingOwner_DataBindingsInitialized(object sender, EventArgs e) + { + IWebDataBound bindingContainer = (IWebDataBound) sender; + if (this.HasControls()) { - // remove custom attributes - if (this.HasControls()) + this.TraverseControls(bindingContainer, this.Controls, new TraversalAction(this.BindControl)); + } + } + + /// + /// Adds all controls on this panel to the containing 's binding collection. + /// + /// the usercontrol containing this panel + /// the of controls to be bound + /// action to be performed on matching controls + private void TraverseControls(IWebDataBound bindingContainer, ControlCollection controls, TraversalAction action) + { + foreach (Control control in controls) + { + // DataBindingPanels must not be nested + if (control is DataBindingPanel) { - this.TraverseControls(null, this.Controls, new TraversalAction(this.RemoveBindingAttributes)); + throw new HttpException("Controls of type DataBindingPanel must not be nested"); } - base.OnPreRender(e); - } - - /// - /// Overriden to suppress rendering this control's tag - /// - /// - protected override void Render(HtmlTextWriter writer) - { - base.RenderContents(writer); - } - - /// - /// Called by the containing if bindings must be initialized. - /// - private void BindingOwner_DataBindingsInitialized(object sender, EventArgs e) - { - IWebDataBound bindingContainer = (IWebDataBound) sender; - if (this.HasControls()) + // abort recursion on LiteralControl or nested UserControl + if (control is LiteralControl + || control is UserControl) { - this.TraverseControls(bindingContainer, this.Controls, new TraversalAction(this.BindControl)); + continue; } - } - /// - /// Adds all controls on this panel to the containing 's binding collection. - /// - /// the usercontrol containing this panel - /// the of controls to be bound - /// action to be performed on matching controls - private void TraverseControls(IWebDataBound bindingContainer, ControlCollection controls, TraversalAction action) - { - foreach (Control control in controls) + // if it's a WebControl, check for binding-related attributes + WebControl wc = control as WebControl; + if (wc != null) { - // DataBindingPanels must not be nested - if (control is DataBindingPanel) + try { - throw new HttpException("Controls of type DataBindingPanel must not be nested"); + action(bindingContainer, wc); } - - // abort recursion on LiteralControl or nested UserControl - if (control is LiteralControl - || control is UserControl) + catch (Exception ex) { - continue; - } - - // if it's a WebControl, check for binding-related attributes - WebControl wc = control as WebControl; - if (wc != null) - { - try - { - action(bindingContainer, wc); - } - catch (Exception ex) - { - string msg = - string.Format("Error executing action on control '{0}' of type '{1}'", wc.UniqueID, - wc.GetType().FullName); - Log.LogError(ex, msg); - throw new HttpException(msg, ex); - } - } - - if (control.HasControls()) - { - this.TraverseControls(bindingContainer, control.Controls, action); + string msg = + string.Format("Error executing action on control '{0}' of type '{1}'", wc.UniqueID, + wc.GetType().FullName); + Log.LogError(ex, msg); + throw new HttpException(msg, ex); } } - } - /// - /// Retrieves custom binding attributes from a webcontrol and adds a new binding - /// instance to the container's if necessary. - /// - private void BindControl(IWebDataBound dataBound, WebControl theControl) - { - // special handling of adapted controls - DataBindingAdapter adapterControl = theControl as DataBindingAdapter; - - Control wc = (adapterControl != null && adapterControl.WrappedControl != null) ? adapterControl.WrappedControl : theControl; - - AttributeCollection attributeCollection = theControl.Attributes; - string bindingTarget = attributeCollection[ATTR_BINDINGTARGET]; - - // at least a BindingTarget must be specified - if (bindingTarget == null) + if (control.HasControls()) { - return; - } - attributeCollection.Remove(ATTR_BINDINGTARGET); - - // determine direction - BindingDirection bindingDirection = BindingDirection.Bidirectional; - string strBindingDirection = attributeCollection[ATTR_BINDINGDIRECTION]; - if (strBindingDirection != null) - { - bindingDirection = (BindingDirection) Enum.Parse(typeof(BindingDirection), strBindingDirection); - } - - // determine BindingSource - string bindingSource = attributeCollection[ATTR_BINDINGSOURCE]; - if (bindingSource == null) - { - bindingSource = AutoProbeSourceProperty(wc); - } - attributeCollection.Remove(ATTR_BINDINGSOURCE); - - // get formatter if any - IFormatter bindingFormatter = null; - string bindingFormatterName = attributeCollection[ATTR_BINDINGFORMATTER]; - if (bindingFormatterName != null) - { - bindingFormatter = (IFormatter) dataBound.ApplicationContext.GetObject(bindingFormatterName); - attributeCollection.Remove(ATTR_BINDINGFORMATTER); - } - - // determine source expression - string containerName = dataBound.UniqueID; - string controlName = wc.UniqueID; - string relativeControlName = null; - if ( dataBound is System.Web.UI.Page ) - { - relativeControlName = string.Format("FindControl('{0}')", controlName); - } - else if ( (Control)dataBound != this.NamingContainer) - { - relativeControlName = (controlName.StartsWith(containerName)) ? controlName.Substring(containerName.Length + 1) : controlName; - relativeControlName = string.Format("FindControl('{0}')", relativeControlName); - } - else - { - relativeControlName = wc.ID; - } - // if no bindingSource, expression evaluates to the bound control - bindingSource = (StringUtils.HasLength(bindingSource)) - ? relativeControlName + "." + bindingSource - : relativeControlName; - - Log.LogDebug(string.Format("binding control '{0}' relative to '{1}' using expression '{2}'", controlName, - containerName, bindingSource)); - - //get bindingType if any - IBinding binding = null; - string bindingTypeName = attributeCollection[ATTR_BINDINGTYPE]; - if (bindingTypeName == null) - { - bindingTypeName = AutoProbeBindingType(wc); - } - - // get messageId and errorProviders list - string messageId = attributeCollection[ATTR_MESSAGEID]; - string errorProvidersText = attributeCollection[ATTR_ERRORPROVIDERS]; - string[] errorProviders = null; - if (StringUtils.HasLength(errorProvidersText)) - { - errorProviders = (string[])new Spring.Core.TypeConversion.StringArrayConverter().ConvertFrom(errorProvidersText); - } - - // add binding to BindingManager - if (bindingTypeName != null) - { - binding = CreateBindingInstance(bindingTypeName, bindingSource, bindingTarget, bindingDirection, bindingFormatter); - binding = dataBound.BindingManager.AddBinding(binding); - } - else - { - binding = dataBound.BindingManager.AddBinding(bindingSource, bindingTarget, bindingDirection, bindingFormatter); - } - - // set error message - if (StringUtils.HasLength(messageId)) - { - binding.SetErrorMessage( messageId, errorProviders ); + this.TraverseControls(bindingContainer, control.Controls, action); } } + } - /// - /// Removes custom binding attributes from a webcontrol to avoid them being rendered. - /// - private void RemoveBindingAttributes(IWebDataBound dataBound, WebControl wc) + /// + /// Retrieves custom binding attributes from a webcontrol and adds a new binding + /// instance to the container's if necessary. + /// + private void BindControl(IWebDataBound dataBound, WebControl theControl) + { + // special handling of adapted controls + DataBindingAdapter adapterControl = theControl as DataBindingAdapter; + + Control wc = (adapterControl != null && adapterControl.WrappedControl != null) ? adapterControl.WrappedControl : theControl; + + AttributeCollection attributeCollection = theControl.Attributes; + string bindingTarget = attributeCollection[ATTR_BINDINGTARGET]; + + // at least a BindingTarget must be specified + if (bindingTarget == null) { - AttributeCollection attributeCollection = wc.Attributes; - attributeCollection.Remove(ATTR_BINDINGTARGET); - attributeCollection.Remove(ATTR_BINDINGSOURCE); - attributeCollection.Remove(ATTR_BINDINGTYPE); - attributeCollection.Remove(ATTR_BINDINGDIRECTION); + return; + } + + attributeCollection.Remove(ATTR_BINDINGTARGET); + + // determine direction + BindingDirection bindingDirection = BindingDirection.Bidirectional; + string strBindingDirection = attributeCollection[ATTR_BINDINGDIRECTION]; + if (strBindingDirection != null) + { + bindingDirection = (BindingDirection) Enum.Parse(typeof(BindingDirection), strBindingDirection); + } + + // determine BindingSource + string bindingSource = attributeCollection[ATTR_BINDINGSOURCE]; + if (bindingSource == null) + { + bindingSource = AutoProbeSourceProperty(wc); + } + + attributeCollection.Remove(ATTR_BINDINGSOURCE); + + // get formatter if any + IFormatter bindingFormatter = null; + string bindingFormatterName = attributeCollection[ATTR_BINDINGFORMATTER]; + if (bindingFormatterName != null) + { + bindingFormatter = (IFormatter) dataBound.ApplicationContext.GetObject(bindingFormatterName); attributeCollection.Remove(ATTR_BINDINGFORMATTER); } - /// - /// Probe for bindingType of know controls - /// - /// the control, who's bindingType is to be determined - /// null, if standard binding is to be used or the fully qualified typename of the binding implementation - protected virtual string AutoProbeBindingType(Control wc) + // determine source expression + string containerName = dataBound.UniqueID; + string controlName = wc.UniqueID; + string relativeControlName = null; + if (dataBound is System.Web.UI.Page) { - if (wc is ListBox && ((ListBox) wc).SelectionMode == ListSelectionMode.Multiple) - { - return typeof(MultipleSelectionListControlBinding).FullName; - } - return null; + relativeControlName = string.Format("FindControl('{0}')", controlName); + } + else if ((Control) dataBound != this.NamingContainer) + { + relativeControlName = (controlName.StartsWith(containerName)) ? controlName.Substring(containerName.Length + 1) : controlName; + relativeControlName = string.Format("FindControl('{0}')", relativeControlName); + } + else + { + relativeControlName = wc.ID; } - /// - /// Probes for a few know controls and their properties. - /// - /// - /// The 'BindingSource' expression to be used for binding this control. - /// - protected virtual string AutoProbeSourceProperty(Control wc) - { - if (wc is ListBox && ((ListBox) wc).SelectionMode == ListSelectionMode.Multiple) - { - return null; // force evaluate to control itself - } - else if (wc is CheckBoxList) - { - return "SelectedValues"; - } - else if (wc is ListControl) - { - return "SelectedValue"; - } - else if (wc is CheckBox) - { - return "Checked"; - } - else if (wc is TextBox) - { - return "Text"; - } - else if (wc is HiddenField) - { - return "Value"; - } - else if (wc is RadioButtonGroup) - { - return "Value"; - } - else if (wc is DataBindingAdapter) - { - throw new ArgumentNullException("Attribute 'BindingSource' is mandatory when using DataBindingAdapter"); - } + // if no bindingSource, expression evaluates to the bound control + bindingSource = (StringUtils.HasLength(bindingSource)) + ? relativeControlName + "." + bindingSource + : relativeControlName; - throw new ArgumentNullException("Attribute 'BindingSource' is missing and control is of unknown type"); + Log.LogDebug(string.Format("binding control '{0}' relative to '{1}' using expression '{2}'", controlName, + containerName, bindingSource)); + + //get bindingType if any + IBinding binding = null; + string bindingTypeName = attributeCollection[ATTR_BINDINGTYPE]; + if (bindingTypeName == null) + { + bindingTypeName = AutoProbeBindingType(wc); } - private static IBinding CreateBindingInstance(string bindingTypeName, string bindingSource, string bindingTarget, BindingDirection bindingDirection, IFormatter bindingFormatter) + // get messageId and errorProviders list + string messageId = attributeCollection[ATTR_MESSAGEID]; + string errorProvidersText = attributeCollection[ATTR_ERRORPROVIDERS]; + string[] errorProviders = null; + if (StringUtils.HasLength(errorProvidersText)) { - IBinding binding; - Type bindingType = TypeResolutionUtils.ResolveType(bindingTypeName); - ConstructorInfo ctor = - bindingType.GetConstructor(new Type[] {typeof(string), typeof(string), typeof(BindingDirection), typeof(IFormatter)}); - - if (ctor == null) - { - throw new ArgumentException(string.Format("Specified BindingType '{0}' does not implement constructor (string,string,BindingDirection,IFormatter)",bindingTypeName)); - } - binding = - (IBinding) - ObjectUtils.InstantiateType(ctor, new object[] {bindingSource, bindingTarget, bindingDirection, bindingFormatter}); - return binding; + errorProviders = (string[]) new Spring.Core.TypeConversion.StringArrayConverter().ConvertFrom(errorProvidersText); } - private static void RegisterDataControl(Control control, EventHandler initializeBindingHandler) + // add binding to BindingManager + if (bindingTypeName != null) { - GetBindingContainerControl(control).DataBindingsInitialized += initializeBindingHandler; + binding = CreateBindingInstance(bindingTypeName, bindingSource, bindingTarget, bindingDirection, bindingFormatter); + binding = dataBound.BindingManager.AddBinding(binding); + } + else + { + binding = dataBound.BindingManager.AddBinding(bindingSource, bindingTarget, bindingDirection, bindingFormatter); } - private static IWebDataBound GetBindingContainerControl(Control control) + // set error message + if (StringUtils.HasLength(messageId)) { - Control parent = control; - while (parent != null) - { - if (parent is IWebDataBound) - { - return (IWebDataBound) parent; - } - parent = parent.Parent; - } - return null; + binding.SetErrorMessage(messageId, errorProviders); } } + + /// + /// Removes custom binding attributes from a webcontrol to avoid them being rendered. + /// + private void RemoveBindingAttributes(IWebDataBound dataBound, WebControl wc) + { + AttributeCollection attributeCollection = wc.Attributes; + attributeCollection.Remove(ATTR_BINDINGTARGET); + attributeCollection.Remove(ATTR_BINDINGSOURCE); + attributeCollection.Remove(ATTR_BINDINGTYPE); + attributeCollection.Remove(ATTR_BINDINGDIRECTION); + attributeCollection.Remove(ATTR_BINDINGFORMATTER); + } + + /// + /// Probe for bindingType of know controls + /// + /// the control, who's bindingType is to be determined + /// null, if standard binding is to be used or the fully qualified typename of the binding implementation + protected virtual string AutoProbeBindingType(Control wc) + { + if (wc is ListBox && ((ListBox) wc).SelectionMode == ListSelectionMode.Multiple) + { + return typeof(MultipleSelectionListControlBinding).FullName; + } + + return null; + } + + /// + /// Probes for a few know controls and their properties. + /// + /// + /// The 'BindingSource' expression to be used for binding this control. + /// + protected virtual string AutoProbeSourceProperty(Control wc) + { + if (wc is ListBox && ((ListBox) wc).SelectionMode == ListSelectionMode.Multiple) + { + return null; // force evaluate to control itself + } + else if (wc is CheckBoxList) + { + return "SelectedValues"; + } + else if (wc is ListControl) + { + return "SelectedValue"; + } + else if (wc is CheckBox) + { + return "Checked"; + } + else if (wc is TextBox) + { + return "Text"; + } + else if (wc is HiddenField) + { + return "Value"; + } + else if (wc is RadioButtonGroup) + { + return "Value"; + } + else if (wc is DataBindingAdapter) + { + throw new ArgumentNullException("Attribute 'BindingSource' is mandatory when using DataBindingAdapter"); + } + + throw new ArgumentNullException("Attribute 'BindingSource' is missing and control is of unknown type"); + } + + private static IBinding CreateBindingInstance(string bindingTypeName, string bindingSource, string bindingTarget, BindingDirection bindingDirection, IFormatter bindingFormatter) + { + IBinding binding; + Type bindingType = TypeResolutionUtils.ResolveType(bindingTypeName); + ConstructorInfo ctor = + bindingType.GetConstructor(new Type[] { typeof(string), typeof(string), typeof(BindingDirection), typeof(IFormatter) }); + + if (ctor == null) + { + throw new ArgumentException(string.Format("Specified BindingType '{0}' does not implement constructor (string,string,BindingDirection,IFormatter)", bindingTypeName)); + } + + binding = + (IBinding) + ObjectUtils.InstantiateType(ctor, new object[] { bindingSource, bindingTarget, bindingDirection, bindingFormatter }); + return binding; + } + + private static void RegisterDataControl(Control control, EventHandler initializeBindingHandler) + { + GetBindingContainerControl(control).DataBindingsInitialized += initializeBindingHandler; + } + + private static IWebDataBound GetBindingContainerControl(Control control) + { + Control parent = control; + while (parent != null) + { + if (parent is IWebDataBound) + { + return (IWebDataBound) parent; + } + + parent = parent.Parent; + } + + return null; + } } diff --git a/src/Spring/Spring.Web/Web/UI/Controls/Form.cs b/src/Spring/Spring.Web/Web/UI/Controls/Form.cs index 71a3f588..9d509d60 100644 --- a/src/Spring/Spring.Web/Web/UI/Controls/Form.cs +++ b/src/Spring/Spring.Web/Web/UI/Controls/Form.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -27,90 +27,89 @@ using Spring.Util; #endregion -namespace Spring.Web.UI.Controls +namespace Spring.Web.UI.Controls; + +/// +/// This control allows for suppressing output of the 'action' attribute. +/// +/// +/// the 'action' attribute rendered by the default control causes troubles +/// in case of URL-rewriting. See e.g. 'thescripts.com' forum +/// and also JIRA SPRNET-560 for more info. +/// +/// Erich Eichinger +public class Form : HtmlForm { + private bool suppressAction = false; + private string action = null; + /// - /// This control allows for suppressing output of the 'action' attribute. + /// Sets or Gets a value indicating if the 'action' attribute shall be rendered. Defaults to 'false' /// /// - /// the 'action' attribute rendered by the default control causes troubles - /// in case of URL-rewriting. See e.g. 'thescripts.com' forum - /// and also JIRA SPRNET-560 for more info. + /// The following possibilites are available: + /// + /// If is 'true', rendering of the 'action' attribute is suppressed. + /// If is 'false' and is not set, + /// 'action' attribute will.be rendered to + /// + /// If is 'false' and is set, + /// 'action' attribute will.be rendered to + /// + /// /// - /// Erich Eichinger - public class Form : HtmlForm + public bool SuppressAction { - private bool suppressAction = false; - private string action = null; - - /// - /// Sets or Gets a value indicating if the 'action' attribute shall be rendered. Defaults to 'false' - /// - /// - /// The following possibilites are available: - /// - /// If is 'true', rendering of the 'action' attribute is suppressed. - /// If is 'false' and is not set, - /// 'action' attribute will.be rendered to - /// - /// If is 'false' and is set, - /// 'action' attribute will.be rendered to - /// - /// - /// - public bool SuppressAction - { - get { return this.suppressAction; } - set { this.suppressAction = value; } - } - - /// - /// Sets or Gets an explicit url to be rendered - /// - /// - /// The url specified here is only rendered, if is true. - /// - public new string Action - { - get { return this.action; } - set { this.action = value; } - } - - /// - /// Renders attributes but performs 'action' suppressing logic. - /// - /// - protected override void RenderAttributes(HtmlTextWriter writer) - { - base.RenderAttributes(new ActionSupressingHtmlTextWriter(writer)); - if (!this.suppressAction) - { - string url = (StringUtils.HasText(this.action)) ? this.action : Context.Request.RawUrl; - writer.WriteAttribute("action", url, true); - } - } - - #region Nested type: ActionSupressingHtmlTextWriter - - /// - /// This wrapper suppresses output of 'action' attributes. - /// - private class ActionSupressingHtmlTextWriter : HtmlTextWriter - { - public ActionSupressingHtmlTextWriter(HtmlTextWriter wrappedWriter) - : base(wrappedWriter.InnerWriter) - { - } - - public override void WriteAttribute(string name, string value, bool fEncode) - { - if (string.Compare(name, "action", true) != 0) - { - base.WriteAttribute(name, value, fEncode); - } - } - } - - #endregion + get { return this.suppressAction; } + set { this.suppressAction = value; } } -} \ No newline at end of file + + /// + /// Sets or Gets an explicit url to be rendered + /// + /// + /// The url specified here is only rendered, if is true. + /// + public new string Action + { + get { return this.action; } + set { this.action = value; } + } + + /// + /// Renders attributes but performs 'action' suppressing logic. + /// + /// + protected override void RenderAttributes(HtmlTextWriter writer) + { + base.RenderAttributes(new ActionSupressingHtmlTextWriter(writer)); + if (!this.suppressAction) + { + string url = (StringUtils.HasText(this.action)) ? this.action : Context.Request.RawUrl; + writer.WriteAttribute("action", url, true); + } + } + + #region Nested type: ActionSupressingHtmlTextWriter + + /// + /// This wrapper suppresses output of 'action' attributes. + /// + private class ActionSupressingHtmlTextWriter : HtmlTextWriter + { + public ActionSupressingHtmlTextWriter(HtmlTextWriter wrappedWriter) + : base(wrappedWriter.InnerWriter) + { + } + + public override void WriteAttribute(string name, string value, bool fEncode) + { + if (string.Compare(name, "action", true) != 0) + { + base.WriteAttribute(name, value, fEncode); + } + } + } + + #endregion +} diff --git a/src/Spring/Spring.Web/Web/UI/Controls/Head.cs b/src/Spring/Spring.Web/Web/UI/Controls/Head.cs index ec13ff86..2a503a5d 100644 --- a/src/Spring/Spring.Web/Web/UI/Controls/Head.cs +++ b/src/Spring/Spring.Web/Web/UI/Controls/Head.cs @@ -23,162 +23,163 @@ using System.Web.UI; using Spring.Util; using Spring.Web.Support; -namespace Spring.Web.UI.Controls +namespace Spring.Web.UI.Controls; + +/// +/// This control should be used instead of standard HTML head tag +/// in order to render dynamicaly registered head scripts and stylesheets. +/// +/// +/// If you need to use ASP.NETs built-in <head> tag, you should nest Spring's within ASP.NET's: +/// +/// <html> +/// <head> +/// <title>Some Title</title> +/// <spring:head> +/// <-- will render styleblocks etc. here --> +/// </spring:head> +/// </head> +/// </html> +/// +/// +/// Aleksandar Seovic +public class Head : Control { + private string _defaultStyleType = "text/css"; + /// - /// This control should be used instead of standard HTML head tag - /// in order to render dynamicaly registered head scripts and stylesheets. + /// Gets or sets the default mimetype for the <style> element's 'type' attribute /// /// - /// If you need to use ASP.NETs built-in <head> tag, you should nest Spring's within ASP.NET's: - /// - /// <html> - /// <head> - /// <title>Some Title</title> - /// <spring:head> - /// <-- will render styleblocks etc. here --> - /// </spring:head> - /// </head> - /// </html> - /// + /// Defaults to "text/css" /// - /// Aleksandar Seovic - public class Head : Control + public string DefaultStyleType { - private string _defaultStyleType = "text/css"; + get { return _defaultStyleType; } + set { _defaultStyleType = value; } + } - /// - /// Gets or sets the default mimetype for the <style> element's 'type' attribute - /// - /// - /// Defaults to "text/css" - /// - public string DefaultStyleType + /// + /// Gets a reference to the instance that contains the + /// server control. + /// + /// + private new Page Page + { + get { return base.Page as Page; } + } + + /// + /// Sends server control content to a provided object, which writes the content to + /// be rendered on + /// the client. + /// + /// The object that receives the server control content. + protected override void Render(HtmlTextWriter writer) + { + bool hasIntrinsicHead = (this.Page.Header != null); + + // don't render begin/end element if we are nested within an ASP.NET control + if (!hasIntrinsicHead) { - get { return _defaultStyleType; } - set { _defaultStyleType = value; } + writer.RenderBeginTag(HtmlTextWriterTag.Head); } - /// - /// Gets a reference to the instance that contains the - /// server control. - /// - /// - private new Page Page + RenderChildren(writer); + RenderStyleBlocks(writer); + RenderStyleFiles(writer); + RenderHeadScripts(writer); + + if (!hasIntrinsicHead) { - get { return base.Page as Page; } - } - - /// - /// Sends server control content to a provided object, which writes the content to - /// be rendered on - /// the client. - /// - /// The object that receives the server control content. - protected override void Render(HtmlTextWriter writer) - { - bool hasIntrinsicHead = (this.Page.Header != null); - - // don't render begin/end element if we are nested within an ASP.NET control - if (!hasIntrinsicHead) - { - writer.RenderBeginTag(HtmlTextWriterTag.Head); - } - - RenderChildren(writer); - RenderStyleBlocks(writer); - RenderStyleFiles(writer); - RenderHeadScripts(writer); - - if (!hasIntrinsicHead) - { - writer.RenderEndTag(); - } - } - - private void RenderStyleBlocks(HtmlTextWriter writer) - { - if (Page.Styles.Count > 0) - { - writer.AddAttribute(HtmlTextWriterAttribute.Type, _defaultStyleType); - writer.RenderBeginTag(HtmlTextWriterTag.Style); - - foreach (DictionaryEntry style in Page.Styles) - { - writer.WriteLine(style.Key + " { " + style.Value + " }"); - } - writer.RenderEndTag(); - } - } - - private void RenderStyleFiles(HtmlTextWriter writer) - { - foreach (DictionaryEntry file in Page.StyleFiles) - { - writer.AddAttribute("rel", "stylesheet"); - writer.AddAttribute(HtmlTextWriterAttribute.Type, "text/css"); - writer.AddAttribute(HtmlTextWriterAttribute.Href, WebUtils.CreateAbsolutePath(Page.CssRoot, (string)file.Value)); - - writer.RenderBeginTag(HtmlTextWriterTag.Link); - writer.RenderEndTag(); - } - } - - private void RenderHeadScripts(HtmlTextWriter writer) - { - foreach (DictionaryEntry scriptEntry in Page.HeadScripts) - { - object script = scriptEntry.Value; - if (script is ScriptEvent) - { - RenderScriptEvent(writer, script as ScriptEvent); - } - else if (script is ScriptFile) - { - RenderScriptFile(writer, script as ScriptFile); - } - else if (script is ScriptBlock) - { - RenderScriptBlock(writer, script as ScriptBlock); - } - } - } - - private void RenderScriptBlock(HtmlTextWriter writer, ScriptBlock script) - { - RenderCommonScriptAttributes(writer, script); - writer.RenderBeginTag(HtmlTextWriterTag.Script); - writer.WriteLine(script.Script); writer.RenderEndTag(); } - - private void RenderScriptFile(HtmlTextWriter writer, ScriptFile script) - { - RenderCommonScriptAttributes(writer, script); - writer.AddAttribute(HtmlTextWriterAttribute.Src, WebUtils.CreateAbsolutePath(Page.ScriptsRoot, script.FileName)); - - writer.RenderBeginTag(HtmlTextWriterTag.Script); - writer.RenderEndTag(); - } - - private void RenderScriptEvent(HtmlTextWriter writer, ScriptEvent script) - { - RenderCommonScriptAttributes(writer, script); - writer.AddAttribute(HtmlTextWriterAttribute.For, script.Element); - writer.AddAttribute("event", script.EventName); - - writer.RenderBeginTag(HtmlTextWriterTag.Script); - writer.WriteLine(script.Script); - writer.RenderEndTag(); - } - - private void RenderCommonScriptAttributes(HtmlTextWriter writer, Script script) - { - if (StringUtils.HasLength(script.Language)) - { - writer.AddAttribute("language", script.Language); - } - writer.AddAttribute("type", script.Type.ToString()); - } } -} \ No newline at end of file + + private void RenderStyleBlocks(HtmlTextWriter writer) + { + if (Page.Styles.Count > 0) + { + writer.AddAttribute(HtmlTextWriterAttribute.Type, _defaultStyleType); + writer.RenderBeginTag(HtmlTextWriterTag.Style); + + foreach (DictionaryEntry style in Page.Styles) + { + writer.WriteLine(style.Key + " { " + style.Value + " }"); + } + + writer.RenderEndTag(); + } + } + + private void RenderStyleFiles(HtmlTextWriter writer) + { + foreach (DictionaryEntry file in Page.StyleFiles) + { + writer.AddAttribute("rel", "stylesheet"); + writer.AddAttribute(HtmlTextWriterAttribute.Type, "text/css"); + writer.AddAttribute(HtmlTextWriterAttribute.Href, WebUtils.CreateAbsolutePath(Page.CssRoot, (string) file.Value)); + + writer.RenderBeginTag(HtmlTextWriterTag.Link); + writer.RenderEndTag(); + } + } + + private void RenderHeadScripts(HtmlTextWriter writer) + { + foreach (DictionaryEntry scriptEntry in Page.HeadScripts) + { + object script = scriptEntry.Value; + if (script is ScriptEvent) + { + RenderScriptEvent(writer, script as ScriptEvent); + } + else if (script is ScriptFile) + { + RenderScriptFile(writer, script as ScriptFile); + } + else if (script is ScriptBlock) + { + RenderScriptBlock(writer, script as ScriptBlock); + } + } + } + + private void RenderScriptBlock(HtmlTextWriter writer, ScriptBlock script) + { + RenderCommonScriptAttributes(writer, script); + writer.RenderBeginTag(HtmlTextWriterTag.Script); + writer.WriteLine(script.Script); + writer.RenderEndTag(); + } + + private void RenderScriptFile(HtmlTextWriter writer, ScriptFile script) + { + RenderCommonScriptAttributes(writer, script); + writer.AddAttribute(HtmlTextWriterAttribute.Src, WebUtils.CreateAbsolutePath(Page.ScriptsRoot, script.FileName)); + + writer.RenderBeginTag(HtmlTextWriterTag.Script); + writer.RenderEndTag(); + } + + private void RenderScriptEvent(HtmlTextWriter writer, ScriptEvent script) + { + RenderCommonScriptAttributes(writer, script); + writer.AddAttribute(HtmlTextWriterAttribute.For, script.Element); + writer.AddAttribute("event", script.EventName); + + writer.RenderBeginTag(HtmlTextWriterTag.Script); + writer.WriteLine(script.Script); + writer.RenderEndTag(); + } + + private void RenderCommonScriptAttributes(HtmlTextWriter writer, Script script) + { + if (StringUtils.HasLength(script.Language)) + { + writer.AddAttribute("language", script.Language); + } + + writer.AddAttribute("type", script.Type.ToString()); + } +} diff --git a/src/Spring/Spring.Web/Web/UI/Controls/LocalizedImage.cs b/src/Spring/Spring.Web/Web/UI/Controls/LocalizedImage.cs index 026e2a11..1adb5b5d 100644 --- a/src/Spring/Spring.Web/Web/UI/Controls/LocalizedImage.cs +++ b/src/Spring/Spring.Web/Web/UI/Controls/LocalizedImage.cs @@ -18,63 +18,62 @@ #endregion -namespace Spring.Web.UI.Controls +namespace Spring.Web.UI.Controls; + +/// +/// This control should be used instead of standard HTML head tag +/// in order to render dynamicaly registered head scripts and stylesheets. +/// +/// Aleksandar Seovic +public class LocalizedImage : System.Web.UI.WebControls.Image { + private string imageName; + /// - /// This control should be used instead of standard HTML head tag - /// in order to render dynamicaly registered head scripts and stylesheets. + /// Tries to determine full URL for the localized image before it's rendered. /// - /// Aleksandar Seovic - public class LocalizedImage : System.Web.UI.WebControls.Image + /// + protected override void OnPreRender(EventArgs e) { - private string imageName; + base.OnPreRender(e); + this.ImageUrl = DetermineLocalizedUrl(); + } - /// - /// Tries to determine full URL for the localized image before it's rendered. - /// - /// - protected override void OnPreRender(EventArgs e) + /// + /// Name of the image file. + /// + public string ImageName + { + get { return imageName; } + set { imageName = value; } + } + + /// + /// Gets a reference to the instance that contains the + /// server control. + /// + /// + new private Page Page + { + get { return base.Page as Page; } + } + + private string DetermineLocalizedUrl() + { + List localeParts = new List(Page.UserCulture.Name.Split('-')); + while (localeParts.Count > 0 && !FileExists(localeParts)) { - base.OnPreRender(e); - this.ImageUrl = DetermineLocalizedUrl(); + localeParts.RemoveAt(localeParts.Count - 1); } - /// - /// Name of the image file. - /// - public string ImageName - { - get { return imageName; } - set { imageName = value; } - } + string locale = String.Join("-", localeParts.ToArray()); + return Page.ImagesRoot + (locale.Length > 0 ? "/" + locale : "") + "/" + this.ImageName; + } - /// - /// Gets a reference to the instance that contains the - /// server control. - /// - /// - new private Page Page - { - get { return base.Page as Page; } - } - - private string DetermineLocalizedUrl() - { - List localeParts = new List(Page.UserCulture.Name.Split('-')); - while (localeParts.Count > 0 && !FileExists(localeParts)) - { - localeParts.RemoveAt(localeParts.Count - 1); - } - - string locale = String.Join("-", localeParts.ToArray()); - return Page.ImagesRoot + (locale.Length > 0 ? "/" + locale : "") + "/" + this.ImageName; - } - - private bool FileExists(List localeParts) - { - string locale = String.Join("-", localeParts.ToArray()); - string url = Page.ImagesRoot + "/" + locale + "/" + this.ImageName; - return File.Exists(Page.Server.MapPath(url)); - } + private bool FileExists(List localeParts) + { + string locale = String.Join("-", localeParts.ToArray()); + string url = Page.ImagesRoot + "/" + locale + "/" + this.ImageName; + return File.Exists(Page.Server.MapPath(url)); } } diff --git a/src/Spring/Spring.Web/Web/UI/Controls/Panel.cs b/src/Spring/Spring.Web/Web/UI/Controls/Panel.cs index 63539390..11a9ee43 100644 --- a/src/Spring/Spring.Web/Web/UI/Controls/Panel.cs +++ b/src/Spring/Spring.Web/Web/UI/Controls/Panel.cs @@ -24,199 +24,200 @@ using System.ComponentModel; using System.Security.Permissions; using System.Web; using System.Web.UI; - using Spring.Context; using Spring.Context.Support; using Spring.Web.Support; #endregion -namespace Spring.Web.UI.Controls +namespace Spring.Web.UI.Controls; + +/// +/// This panel provides the same features as , but provides additional means with regards to Spring. +/// +/// +/// In some cases, automatic dependency injection can cause performance problems. In this case,you can use a Panel for finer-grained control +/// over which controls are to be injected or not. +/// +/// Erich Eichinger +[PersistChildren(true), + ToolboxData("<{0}:Panel runat=\"server\" Width=\"125px\" Height=\"50px\"> "), + ParseChildren(false), + Designer("System.Web.UI.Design.WebControls.PanelContainerDesigner, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"), + AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal), + AspNetHostingPermission(SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)] +public class Panel : System.Web.UI.WebControls.Panel, ISupportsWebDependencyInjection { + // this helper class intercepts the first call to the child controls + // collection from within InitRecursive(). + // InitRecursive() is called right after the control has been added to it's parent's children. + private class InitRecursiveInterceptingControlsCollection : ControlCollection + { + private bool _passedInitRecursiveCheck = false; + + public InitRecursiveInterceptingControlsCollection(Control owner) : base(owner) + { + } + + public override Control this[int index] + { + get + { + // the following check relies on the fact, that ControlCollection is set readonly + // right before InitRecursive() is called on each child control + if (!_passedInitRecursiveCheck + && this.IsReadOnly) + { + _passedInitRecursiveCheck = true; + ((Panel) this.Owner).OnPreInitRecursive(EventArgs.Empty); + } + + return base[index]; + } + } + } + + private bool _suppressDependencyInjection; + private bool _renderContainerTag; + private string _visibleConditionExpression; + /// - /// This panel provides the same features as , but provides additional means with regards to Spring. + /// An optional SpEL expression to control this Panel's state. /// /// - /// In some cases, automatic dependency injection can cause performance problems. In this case,you can use a Panel for finer-grained control - /// over which controls are to be injected or not. + /// This panel instance is the context for evaluating the given expression. If no expression is specified, visibility behavior + /// reverts to standard behavior. /// - /// Erich Eichinger - [PersistChildren(true), - ToolboxData("<{0}:Panel runat=\"server\" Width=\"125px\" Height=\"50px\"> "), - ParseChildren(false), - Designer("System.Web.UI.Design.WebControls.PanelContainerDesigner, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"), - AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal), - AspNetHostingPermission(SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)] - public class Panel : System.Web.UI.WebControls.Panel, ISupportsWebDependencyInjection + public string VisibleIf { - // this helper class intercepts the first call to the child controls - // collection from within InitRecursive(). - // InitRecursive() is called right after the control has been added to it's parent's children. - private class InitRecursiveInterceptingControlsCollection : ControlCollection - { - private bool _passedInitRecursiveCheck = false; - - public InitRecursiveInterceptingControlsCollection(Control owner) : base(owner) - { - } - - public override Control this[int index] - { - get - { - // the following check relies on the fact, that ControlCollection is set readonly - // right before InitRecursive() is called on each child control - if (!_passedInitRecursiveCheck - && this.IsReadOnly) - { - _passedInitRecursiveCheck = true; - ((Panel)this.Owner).OnPreInitRecursive(EventArgs.Empty); - } - return base[index]; - } - } - } - - private bool _suppressDependencyInjection; - private bool _renderContainerTag; - private string _visibleConditionExpression; - - /// - /// An optional SpEL expression to control this Panel's state. - /// - /// - /// This panel instance is the context for evaluating the given expression. If no expression is specified, visibility behavior - /// reverts to standard behavior. - /// - public string VisibleIf - { - get { return _visibleConditionExpression; } - set { _visibleConditionExpression = value; } - } - - /// - /// This flag controls, whether DI on child controls will be done or not - /// - /// By default, DI will be done - public bool SuppressDependencyInjection - { - get { return _suppressDependencyInjection; } - set { _suppressDependencyInjection = value; } - } - - /// - /// This flag controls, whether this Panel's tag will be rendered. - /// - public bool RenderContainerTag - { - get { return _renderContainerTag; } - set { _renderContainerTag = value; } - } - - /// - /// Overridden to set according to if necessary. - /// - protected override void OnPreRender( EventArgs e ) - { - this.Visible = (_visibleConditionExpression != null) - ? Spring.Expressions.ExpressionEvaluator.GetValue(this, _visibleConditionExpression).Equals(true) - : this.Visible; - - base.OnPreRender( e ); - } - - /// - ///Renders the HTML opening tag of the control to the specified writer. - /// - ///An that represents the output stream to render HTML content on the client. - public override void RenderBeginTag( HtmlTextWriter writer ) - { - if (this.RenderContainerTag) - { - base.RenderBeginTag( writer ); - } - } - - /// - ///Renders the HTML closing tag of the control to the specified writer. - /// - ///An that represents the output stream to render HTML content on the client. - public override void RenderEndTag( HtmlTextWriter writer ) - { - if (this.RenderContainerTag) - { - base.RenderEndTag( writer ); - } - } - - /// - /// This method is invoked right before InitRecursive() is called for this Panel and - /// ensures, that dependencies get injected on child controls before their Init event is raised. - /// - protected virtual void OnPreInitRecursive(EventArgs e) - { - if (!_suppressDependencyInjection - && _defaultApplicationContext == null) - { - // obtain appContext of the closed parent template (.ascx/.aspx) control - IApplicationContext appCtx = WebApplicationContext.GetContext(this.TemplateSourceDirectory.TrimEnd('/') + "/"); - // NOTE: _defaultApplicationContext will be set during DI! - WebDependencyInjectionUtils.InjectDependenciesRecursive(appCtx, this); - } - } - - /// - /// Expose the context of this panel for medium trust safe access in e.g. . - /// - public new virtual HttpContext Context - { - get { return base.Context; } - } - #region Dependency Injection Support - - private IApplicationContext _defaultApplicationContext; - - /// - /// Sets / Gets the ApplicationContext instance used to configure this control - /// - IApplicationContext ISupportsWebDependencyInjection.DefaultApplicationContext - { - get { return _defaultApplicationContext; } - set { _defaultApplicationContext = value; } - } - - /// - /// Injects dependencies into control before adding it. - /// - protected override void AddedControl(Control control, int index) - { - if (!_suppressDependencyInjection - && _defaultApplicationContext != null) - { - control = WebDependencyInjectionUtils.InjectDependenciesRecursive(_defaultApplicationContext, control); - } - base.AddedControl(control, index); - } - - /// - /// Overridden to automatically aquire a reference to - /// root application context to use for DI. - /// - protected override ControlCollection CreateControlCollection() - { - // set root application context to signal, that we care - // for our children ourselves - if (_suppressDependencyInjection) - { - _defaultApplicationContext = WebApplicationContext.GetRootContext(); - return base.CreateControlCollection(); - } - else - { - return new InitRecursiveInterceptingControlsCollection(this); - } - } - - #endregion Dependency Injection Support + get { return _visibleConditionExpression; } + set { _visibleConditionExpression = value; } } + + /// + /// This flag controls, whether DI on child controls will be done or not + /// + /// By default, DI will be done + public bool SuppressDependencyInjection + { + get { return _suppressDependencyInjection; } + set { _suppressDependencyInjection = value; } + } + + /// + /// This flag controls, whether this Panel's tag will be rendered. + /// + public bool RenderContainerTag + { + get { return _renderContainerTag; } + set { _renderContainerTag = value; } + } + + /// + /// Overridden to set according to if necessary. + /// + protected override void OnPreRender(EventArgs e) + { + this.Visible = (_visibleConditionExpression != null) + ? Spring.Expressions.ExpressionEvaluator.GetValue(this, _visibleConditionExpression).Equals(true) + : this.Visible; + + base.OnPreRender(e); + } + + /// + ///Renders the HTML opening tag of the control to the specified writer. + /// + ///An that represents the output stream to render HTML content on the client. + public override void RenderBeginTag(HtmlTextWriter writer) + { + if (this.RenderContainerTag) + { + base.RenderBeginTag(writer); + } + } + + /// + ///Renders the HTML closing tag of the control to the specified writer. + /// + ///An that represents the output stream to render HTML content on the client. + public override void RenderEndTag(HtmlTextWriter writer) + { + if (this.RenderContainerTag) + { + base.RenderEndTag(writer); + } + } + + /// + /// This method is invoked right before InitRecursive() is called for this Panel and + /// ensures, that dependencies get injected on child controls before their Init event is raised. + /// + protected virtual void OnPreInitRecursive(EventArgs e) + { + if (!_suppressDependencyInjection + && _defaultApplicationContext == null) + { + // obtain appContext of the closed parent template (.ascx/.aspx) control + IApplicationContext appCtx = WebApplicationContext.GetContext(this.TemplateSourceDirectory.TrimEnd('/') + "/"); + // NOTE: _defaultApplicationContext will be set during DI! + WebDependencyInjectionUtils.InjectDependenciesRecursive(appCtx, this); + } + } + + /// + /// Expose the context of this panel for medium trust safe access in e.g. . + /// + public new virtual HttpContext Context + { + get { return base.Context; } + } + + #region Dependency Injection Support + + private IApplicationContext _defaultApplicationContext; + + /// + /// Sets / Gets the ApplicationContext instance used to configure this control + /// + IApplicationContext ISupportsWebDependencyInjection.DefaultApplicationContext + { + get { return _defaultApplicationContext; } + set { _defaultApplicationContext = value; } + } + + /// + /// Injects dependencies into control before adding it. + /// + protected override void AddedControl(Control control, int index) + { + if (!_suppressDependencyInjection + && _defaultApplicationContext != null) + { + control = WebDependencyInjectionUtils.InjectDependenciesRecursive(_defaultApplicationContext, control); + } + + base.AddedControl(control, index); + } + + /// + /// Overridden to automatically aquire a reference to + /// root application context to use for DI. + /// + protected override ControlCollection CreateControlCollection() + { + // set root application context to signal, that we care + // for our children ourselves + if (_suppressDependencyInjection) + { + _defaultApplicationContext = WebApplicationContext.GetRootContext(); + return base.CreateControlCollection(); + } + else + { + return new InitRecursiveInterceptingControlsCollection(this); + } + } + + #endregion Dependency Injection Support } diff --git a/src/Spring/Spring.Web/Web/UI/Controls/RadioButtonGroup.cs b/src/Spring/Spring.Web/Web/UI/Controls/RadioButtonGroup.cs index d88a2eb6..cd42b221 100644 --- a/src/Spring/Spring.Web/Web/UI/Controls/RadioButtonGroup.cs +++ b/src/Spring/Spring.Web/Web/UI/Controls/RadioButtonGroup.cs @@ -23,172 +23,172 @@ using System.ComponentModel; using System.Web.UI; using System.Web.UI.WebControls; -namespace Spring.Web.UI.Controls +namespace Spring.Web.UI.Controls; + +/// +/// Groups radio button controls and returns the value of the selected control +/// +/// +/// This control alows radio buttons to be data-bound to a data model of the page. +/// +/// Aleksandar Seovic +[ParseChildren(false)] +public class RadioButtonGroup : WebControl, IPostBackDataHandler { + private static readonly object EventSelectionChanged = new object(); + + private List options = new List(); + /// - /// Groups radio button controls and returns the value of the selected control + /// Overloaded to track addition of contained controls. /// - /// - /// This control alows radio buttons to be data-bound to a data model of the page. - /// - /// Aleksandar Seovic - [ParseChildren(false)] - public class RadioButtonGroup : WebControl, IPostBackDataHandler + protected override void AddedControl(Control control, int index) { - private static readonly object EventSelectionChanged = new object(); - - private List options = new List(); - - /// - /// Overloaded to track addition of contained controls. - /// - protected override void AddedControl(Control control, int index) - { - if (control is RadioButton) - { - RadioButton option = (RadioButton)control; - option.GroupName = this.ID + "Group"; - option.AutoPostBack = this.AutoPostBack; - if(option.Attributes["value"] == null) option.Attributes["value"] = option.ID; - option.Checked = (0 == string.Compare(this.Value, option.Attributes["value"])); - options.Add(control); - } - base.AddedControl (control, index); - } - - /// - /// Overloaded to track removal of a RadioButton - /// - /// - protected override void RemovedControl(Control control) - { - int index = -1; - for(int i=0;i -1) options.RemoveAt(index); - - base.RemovedControl (control); - } - - /// - /// Gets or sets the ID of the selected radio button. - /// - /// ID of the selected radio button. - public string Value + if (control is RadioButton) { - get { return (string) this.ViewState["value"]; } - set - { - this.ViewState["value"] = value; - foreach(RadioButton option in this.options) - { - option.Checked = (0==string.Compare(value, option.Attributes["value"])); - } - } + RadioButton option = (RadioButton) control; + option.GroupName = this.ID + "Group"; + option.AutoPostBack = this.AutoPostBack; + if (option.Attributes["value"] == null) option.Attributes["value"] = option.ID; + option.Checked = (0 == string.Compare(this.Value, option.Attributes["value"])); + options.Add(control); } - /// - /// Gets or sets whether form should be posted back on every selection change - /// within the radio group. - /// - [DefaultValue(false)] - public virtual bool AutoPostBack + base.AddedControl(control, index); + } + + /// + /// Overloaded to track removal of a RadioButton + /// + /// + protected override void RemovedControl(Control control) + { + int index = -1; + for (int i = 0; i < options.Count; i++) { - get - { - object autoPostBack = this.ViewState["AutoPostBack"]; - if (autoPostBack != null) - { - return (bool) autoPostBack; - } - return false; - } - set - { - this.ViewState["AutoPostBack"] = value; - foreach(RadioButton option in this.options) - { - option.AutoPostBack = value; - } - } + if (control == options[i]) index = i; } - /// - /// Registers the RadioButtonGroup for PostBack. - /// - protected override void OnPreRender(EventArgs e) + if (index > -1) options.RemoveAt(index); + + base.RemovedControl(control); + } + + /// + /// Gets or sets the ID of the selected radio button. + /// + /// ID of the selected radio button. + public string Value + { + get { return (string) this.ViewState["value"]; } + set { - base.OnPreRender(e); - if (this.Visible) + this.ViewState["value"] = value; + foreach (RadioButton option in this.options) { - Page.RegisterRequiresPostBack(this); + option.Checked = (0 == string.Compare(value, option.Attributes["value"])); } } + } - /// - /// Renders only children of this control. - /// - /// HtmlTextWriter to use for rendering. - protected override void Render(HtmlTextWriter writer) + /// + /// Gets or sets whether form should be posted back on every selection change + /// within the radio group. + /// + [DefaultValue(false)] + public virtual bool AutoPostBack + { + get { - this.RenderChildren(writer); - } - - #region IPostBackDataHandler Members - - /// - /// Loads postback data into the control. - /// - /// Key that should be used to retrieve data. - /// Postback data collection. - /// True if data has changed, false otherwise. - public bool LoadPostData(string postDataKey, NameValueCollection postCollection) - { - string newValue = postCollection[postDataKey+"Group"]; - - if (0 != string.Compare(newValue,this.Value)) + object autoPostBack = this.ViewState["AutoPostBack"]; + if (autoPostBack != null) { - this.ViewState["value"] = newValue; - return true; + return (bool) autoPostBack; } return false; } - - /// - /// Raises SelectionChanged event. - /// - public void RaisePostDataChangedEvent() + set { - OnSelectionChanged(EventArgs.Empty); - } - - #endregion - - /// - /// Method that is called on postback if selected radio button has changed. - /// - /// Empty event argument. - protected virtual void OnSelectionChanged(EventArgs e) - { - EventHandler handler = (EventHandler) base.Events[RadioButtonGroup.EventSelectionChanged]; - if (handler != null) + this.ViewState["AutoPostBack"] = value; + foreach (RadioButton option in this.options) { - handler(this, e); + option.AutoPostBack = value; } } + } - /// - /// Occurs when the value of the radio button group changes between postbacks to the server. - /// - public event EventHandler SelectionChanged + /// + /// Registers the RadioButtonGroup for PostBack. + /// + protected override void OnPreRender(EventArgs e) + { + base.OnPreRender(e); + if (this.Visible) { - add { base.Events.AddHandler(RadioButtonGroup.EventSelectionChanged, value); } - remove { base.Events.RemoveHandler(RadioButtonGroup.EventSelectionChanged, value); } + Page.RegisterRequiresPostBack(this); + } + } + + /// + /// Renders only children of this control. + /// + /// HtmlTextWriter to use for rendering. + protected override void Render(HtmlTextWriter writer) + { + this.RenderChildren(writer); + } + + #region IPostBackDataHandler Members + + /// + /// Loads postback data into the control. + /// + /// Key that should be used to retrieve data. + /// Postback data collection. + /// True if data has changed, false otherwise. + public bool LoadPostData(string postDataKey, NameValueCollection postCollection) + { + string newValue = postCollection[postDataKey + "Group"]; + + if (0 != string.Compare(newValue, this.Value)) + { + this.ViewState["value"] = newValue; + return true; } + return false; + } + /// + /// Raises SelectionChanged event. + /// + public void RaisePostDataChangedEvent() + { + OnSelectionChanged(EventArgs.Empty); + } + + #endregion + + /// + /// Method that is called on postback if selected radio button has changed. + /// + /// Empty event argument. + protected virtual void OnSelectionChanged(EventArgs e) + { + EventHandler handler = (EventHandler) base.Events[RadioButtonGroup.EventSelectionChanged]; + if (handler != null) + { + handler(this, e); + } + } + + /// + /// Occurs when the value of the radio button group changes between postbacks to the server. + /// + public event EventHandler SelectionChanged + { + add { base.Events.AddHandler(RadioButtonGroup.EventSelectionChanged, value); } + remove { base.Events.RemoveHandler(RadioButtonGroup.EventSelectionChanged, value); } } } diff --git a/src/Spring/Spring.Web/Web/UI/Controls/TabCommandEventArgs.cs b/src/Spring/Spring.Web/Web/UI/Controls/TabCommandEventArgs.cs index 863eae3a..5ab1639a 100644 --- a/src/Spring/Spring.Web/Web/UI/Controls/TabCommandEventArgs.cs +++ b/src/Spring/Spring.Web/Web/UI/Controls/TabCommandEventArgs.cs @@ -24,29 +24,28 @@ using System.Web.UI.WebControls; -namespace Spring.Web.UI.Controls -{ - /// - /// Provides information about a command raised from a - /// - /// Erich Eichinger - public class TabCommandEventArgs : CommandEventArgs - { - /// - /// Initializes a new instance. - /// - /// The name of the command raised by a . - /// The index of the tab that raised this event. - public TabCommandEventArgs(string commandName, int tabIndex) : base(commandName, tabIndex) - { - } +namespace Spring.Web.UI.Controls; - /// - /// Returns the index of the tab that raised this command. - /// - public int TabIndex - { - get { return (int) base.CommandArgument; } - } - } -} \ No newline at end of file +/// +/// Provides information about a command raised from a +/// +/// Erich Eichinger +public class TabCommandEventArgs : CommandEventArgs +{ + /// + /// Initializes a new instance. + /// + /// The name of the command raised by a . + /// The index of the tab that raised this event. + public TabCommandEventArgs(string commandName, int tabIndex) : base(commandName, tabIndex) + { + } + + /// + /// Returns the index of the tab that raised this command. + /// + public int TabIndex + { + get { return (int) base.CommandArgument; } + } +} diff --git a/src/Spring/Spring.Web/Web/UI/Controls/TabCommandEventHandler.cs b/src/Spring/Spring.Web/Web/UI/Controls/TabCommandEventHandler.cs index d1d28e11..c6f9d7cf 100644 --- a/src/Spring/Spring.Web/Web/UI/Controls/TabCommandEventHandler.cs +++ b/src/Spring/Spring.Web/Web/UI/Controls/TabCommandEventHandler.cs @@ -20,17 +20,14 @@ #region Imports - - #endregion -namespace Spring.Web.UI.Controls -{ - /// - /// Represents the method that will handle the TabCommand event. - /// - /// The source of the event. - /// A that contains the event data. - /// Erich Eichinger - public delegate void TabCommandEventHandler(object sender, TabCommandEventArgs e); -} \ No newline at end of file +namespace Spring.Web.UI.Controls; + +/// +/// Represents the method that will handle the TabCommand event. +/// +/// The source of the event. +/// A that contains the event data. +/// Erich Eichinger +public delegate void TabCommandEventHandler(object sender, TabCommandEventArgs e); \ No newline at end of file diff --git a/src/Spring/Spring.Web/Web/UI/Controls/TabContainer.cs b/src/Spring/Spring.Web/Web/UI/Controls/TabContainer.cs index 357d4883..b15352b4 100644 --- a/src/Spring/Spring.Web/Web/UI/Controls/TabContainer.cs +++ b/src/Spring/Spring.Web/Web/UI/Controls/TabContainer.cs @@ -25,92 +25,91 @@ using System.Web.UI.WebControls; #endregion -namespace Spring.Web.UI.Controls +namespace Spring.Web.UI.Controls; + +/// +/// This control is responsible for rendering tabs. +/// +/// +/// By default, this TabContainer implementation uses controls to +/// render tabs. Override to change this behaviour. +/// +/// Erich Eichinger +public class TabContainer : Control { - /// - /// This control is responsible for rendering tabs. - /// - /// - /// By default, this TabContainer implementation uses controls to - /// render tabs. Override to change this behaviour. - /// - /// Erich Eichinger - public class TabContainer : Control - { - /// - /// Represents the command name of the tab to be selected. - /// - public static readonly string SelectTabCommandName = "SelectTab"; + /// + /// Represents the command name of the tab to be selected. + /// + public static readonly string SelectTabCommandName = "SelectTab"; - /// - /// Key into the eventhandler table. - /// - private static readonly object _eventClick = new object(); + /// + /// Key into the eventhandler table. + /// + private static readonly object _eventClick = new object(); - /// - /// Occurs, when a tab control is clicked. - /// - public event TabCommandEventHandler Click - { - add { base.Events.AddHandler(_eventClick, value); } - remove { base.Events.RemoveHandler(_eventClick, value); } - } + /// + /// Occurs, when a tab control is clicked. + /// + public event TabCommandEventHandler Click + { + add { base.Events.AddHandler(_eventClick, value); } + remove { base.Events.RemoveHandler(_eventClick, value); } + } - /// - /// Catches with name '' and - /// raises the event. - /// - /// The source of the event. - /// contains event information. - /// - protected override bool OnBubbleEvent(object source, EventArgs args) - { - CommandEventArgs cea = args as CommandEventArgs; - if (cea != null && cea.CommandName == SelectTabCommandName) - { - this.OnTabClickedCommand(source, (CommandEventArgs) args); - return true; - } + /// + /// Catches with name '' and + /// raises the event. + /// + /// The source of the event. + /// contains event information. + /// + protected override bool OnBubbleEvent(object source, EventArgs args) + { + CommandEventArgs cea = args as CommandEventArgs; + if (cea != null && cea.CommandName == SelectTabCommandName) + { + this.OnTabClickedCommand(source, (CommandEventArgs) args); + return true; + } - return base.OnBubbleEvent(source, args); - } + return base.OnBubbleEvent(source, args); + } - /// - /// Raises the event. - /// - protected virtual void OnTabClickedCommand(object sender, CommandEventArgs args) - { - TabCommandEventHandler handler = (TabCommandEventHandler) base.Events[_eventClick]; - if (handler != null) - { - handler(sender, new TabCommandEventArgs(args.CommandName, Int32.Parse((string) args.CommandArgument))); - } - } + /// + /// Raises the event. + /// + protected virtual void OnTabClickedCommand(object sender, CommandEventArgs args) + { + TabCommandEventHandler handler = (TabCommandEventHandler) base.Events[_eventClick]; + if (handler != null) + { + handler(sender, new TabCommandEventArgs(args.CommandName, Int32.Parse((string) args.CommandArgument))); + } + } - /// - /// Creates a new tab for the specified view within the given container. - /// - /// The containing the view - /// The for which a new tab is to be created. - /// The index of the tab to be created. - /// - /// By default, controls are used for rendering tabs. Override this method to - /// change this behaviour. - /// - protected internal virtual void CreateTab(TabularMultiView container, TabularView view, int index) - { - LinkButton btnTab = new LinkButton(); - btnTab.Text = view.TabName; - btnTab.CommandName = "SelectTab"; - btnTab.CommandArgument = "" + index; - btnTab.ID = "Tab" + index; - btnTab.ToolTip = view.TabToolTip; - btnTab.Enabled = !view.Active; + /// + /// Creates a new tab for the specified view within the given container. + /// + /// The containing the view + /// The for which a new tab is to be created. + /// The index of the tab to be created. + /// + /// By default, controls are used for rendering tabs. Override this method to + /// change this behaviour. + /// + protected internal virtual void CreateTab(TabularMultiView container, TabularView view, int index) + { + LinkButton btnTab = new LinkButton(); + btnTab.Text = view.TabName; + btnTab.CommandName = "SelectTab"; + btnTab.CommandArgument = "" + index; + btnTab.ID = "Tab" + index; + btnTab.ToolTip = view.TabToolTip; + btnTab.Enabled = !view.Active; - WebControl span = new WebControl(HtmlTextWriterTag.Span); - span.CssClass = (view.Active) ? container.TabularMenuSelectedItemCSS : container.TabularMenuItemCSS; - span.Controls.Add(btnTab); - this.Controls.Add(span); - } - } -} + WebControl span = new WebControl(HtmlTextWriterTag.Span); + span.CssClass = (view.Active) ? container.TabularMenuSelectedItemCSS : container.TabularMenuItemCSS; + span.Controls.Add(btnTab); + this.Controls.Add(span); + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Web/Web/UI/Controls/TabularMultiView.cs b/src/Spring/Spring.Web/Web/UI/Controls/TabularMultiView.cs index 89da7200..949adb0b 100644 --- a/src/Spring/Spring.Web/Web/UI/Controls/TabularMultiView.cs +++ b/src/Spring/Spring.Web/Web/UI/Controls/TabularMultiView.cs @@ -28,271 +28,270 @@ using System.Web.UI.WebControls; #endregion -namespace Spring.Web.UI.Controls +namespace Spring.Web.UI.Controls; + +/// +/// The control allows you to build ASP.NET Web pages that present +/// the user with content arranged in tabular form. +/// +/// Erich Eichinger +[ToolboxData("<{0}:TabularMultiView runat=\"server\">")] +[ParseChildren(false)] +public class TabularMultiView : WebControl { - /// - /// The control allows you to build ASP.NET Web pages that present - /// the user with content arranged in tabular form. - /// - /// Erich Eichinger - [ToolboxData("<{0}:TabularMultiView runat=\"server\">")] - [ParseChildren(false)] - public class TabularMultiView : WebControl - { - #region Style Properties + #region Style Properties - private string m_MenuStyle = "TabMenu"; - private string m_BodyStyle = "TabBody"; - private string m_TabItemStyle = "TabItem"; - private string m_TabSelectedItemStyle = "TabSelectedItem"; + private string m_MenuStyle = "TabMenu"; + private string m_BodyStyle = "TabBody"; + private string m_TabItemStyle = "TabItem"; + private string m_TabSelectedItemStyle = "TabSelectedItem"; - /// - /// Set the style class of the panel containing the Tabs. - /// - [Bindable(true), Category("Appearance"), DefaultValue(typeof(string), "TabMenu")] - public string TabularMenuCSS - { - get { return m_MenuStyle; } - set { m_MenuStyle = value; } - } + /// + /// Set the style class of the panel containing the Tabs. + /// + [Bindable(true), Category("Appearance"), DefaultValue(typeof(string), "TabMenu")] + public string TabularMenuCSS + { + get { return m_MenuStyle; } + set { m_MenuStyle = value; } + } - /// - /// Set the style class of each Tab item. - /// - [Bindable(true), DefaultValue(typeof(string), "TabItem"), Category("Appearance")] - public string TabularMenuItemCSS - { - get { return (m_TabItemStyle); } - set { m_TabItemStyle = value; } - } + /// + /// Set the style class of each Tab item. + /// + [Bindable(true), DefaultValue(typeof(string), "TabItem"), Category("Appearance")] + public string TabularMenuItemCSS + { + get { return (m_TabItemStyle); } + set { m_TabItemStyle = value; } + } - /// - /// Set the style class of the currently selected Tab item. - /// - [Bindable(true), DefaultValue(typeof(string), "TabSelectedItem"), Category("Appearance")] - public string TabularMenuSelectedItemCSS - { - get { return m_TabSelectedItemStyle; } - set { m_TabSelectedItemStyle = value; } - } + /// + /// Set the style class of the currently selected Tab item. + /// + [Bindable(true), DefaultValue(typeof(string), "TabSelectedItem"), Category("Appearance")] + public string TabularMenuSelectedItemCSS + { + get { return m_TabSelectedItemStyle; } + set { m_TabSelectedItemStyle = value; } + } - /// - /// Set the style class of the panel containing all controls. - /// - [Bindable(true), Category("Appearance"), DefaultValue(typeof(string), "TabBody")] - public string TabularBodyCSS - { - get { return m_BodyStyle; } - set { m_BodyStyle = value; } - } + /// + /// Set the style class of the panel containing all controls. + /// + [Bindable(true), Category("Appearance"), DefaultValue(typeof(string), "TabBody")] + public string TabularBodyCSS + { + get { return m_BodyStyle; } + set { m_BodyStyle = value; } + } - #endregion + #endregion - #region Public Members + #region Public Members - /// - /// Initializes a new instance. - /// - public TabularMultiView() - : this(HtmlTextWriterTag.Div) - { - } + /// + /// Initializes a new instance. + /// + public TabularMultiView() + : this(HtmlTextWriterTag.Div) + { + } - /// - /// Initializes a new instance with the given container tag to be used for rendering. - /// - protected TabularMultiView(HtmlTextWriterTag containerTag) - : base(containerTag) - { - } + /// + /// Initializes a new instance with the given container tag to be used for rendering. + /// + protected TabularMultiView(HtmlTextWriterTag containerTag) + : base(containerTag) + { + } - /// - /// Gets or sets the index of the active View control within a control. - /// - public int ActiveTabIndex - { - get - { - if (!_controlStateInitialized) - { - return _activeViewIndexCached; - } - else - { - return _multiView.ActiveViewIndex; - } - } - set - { - if (!_controlStateInitialized) - { - _activeViewIndexCached = value; - } - else - { - _multiView.ActiveViewIndex = value; - } - } - } + /// + /// Gets or sets the index of the active View control within a control. + /// + public int ActiveTabIndex + { + get + { + if (!_controlStateInitialized) + { + return _activeViewIndexCached; + } + else + { + return _multiView.ActiveViewIndex; + } + } + set + { + if (!_controlStateInitialized) + { + _activeViewIndexCached = value; + } + else + { + _multiView.ActiveViewIndex = value; + } + } + } - /// - /// Occurs, if the active tab has changed. - /// - public event EventHandler ActiveTabChanged - { - add { base.Events.AddHandler(_eventActiveTabChanged, value); } - remove { base.Events.RemoveHandler(_eventActiveTabChanged, value); } - } + /// + /// Occurs, if the active tab has changed. + /// + public event EventHandler ActiveTabChanged + { + add { base.Events.AddHandler(_eventActiveTabChanged, value); } + remove { base.Events.RemoveHandler(_eventActiveTabChanged, value); } + } - #endregion Public Members + #endregion Public Members - #region Customizable Members + #region Customizable Members - /// - /// Create the container for tab items. - /// - protected virtual TabContainer CreateTabContainer() - { - return new TabContainer(); - } + /// + /// Create the container for tab items. + /// + protected virtual TabContainer CreateTabContainer() + { + return new TabContainer(); + } - /// - /// Creates TabContainer and MultiView - /// - protected virtual Control CreateContent(TabContainer menu, MultiView body) - { - Control content = new Control(); + /// + /// Creates TabContainer and MultiView + /// + protected virtual Control CreateContent(TabContainer menu, MultiView body) + { + Control content = new Control(); - WebControl menuPanel = new WebControl(HtmlTextWriterTag.Div); - menuPanel.CssClass = TabularMenuCSS; - menuPanel.Controls.Add(menu); - content.Controls.Add(menuPanel); + WebControl menuPanel = new WebControl(HtmlTextWriterTag.Div); + menuPanel.CssClass = TabularMenuCSS; + menuPanel.Controls.Add(menu); + content.Controls.Add(menuPanel); - WebControl bodyPanel = new WebControl(HtmlTextWriterTag.Div); - bodyPanel.CssClass = TabularBodyCSS; - bodyPanel.Controls.Add(body); - content.Controls.Add(bodyPanel); + WebControl bodyPanel = new WebControl(HtmlTextWriterTag.Div); + bodyPanel.CssClass = TabularBodyCSS; + bodyPanel.Controls.Add(body); + content.Controls.Add(bodyPanel); - return content; - } + return content; + } - #endregion + #endregion - #region Fields + #region Fields - private static readonly object _eventActiveTabChanged = new object(); + private static readonly object _eventActiveTabChanged = new object(); - private int _activeViewIndexCached = -1; - private bool _controlStateInitialized = false; + private int _activeViewIndexCached = -1; + private bool _controlStateInitialized = false; - private TabContainer _tabContainer; - private MultiView _multiView; + private TabContainer _tabContainer; + private MultiView _multiView; - /// - /// keeps parsed views until multiView is created - /// - private ArrayList _parsedViews = new ArrayList(); + /// + /// keeps parsed views until multiView is created + /// + private ArrayList _parsedViews = new ArrayList(); - #endregion + #endregion - /// - /// Initialize this control. - /// - protected override void OnInit(EventArgs e) - { - BuildControlTree(); + /// + /// Initialize this control. + /// + protected override void OnInit(EventArgs e) + { + BuildControlTree(); - base.OnInit(e); - } + base.OnInit(e); + } - private void BuildControlTree() - { - _controlStateInitialized = true; + private void BuildControlTree() + { + _controlStateInitialized = true; - EnsureChildControls(); - } + EnsureChildControls(); + } - /// - /// Creates child controls. - /// - protected override void CreateChildControls() - { - // create menu tabstrip - _tabContainer = CreateTabContainer(); - _tabContainer.Click += OnSelectTabCommand; + /// + /// Creates child controls. + /// + protected override void CreateChildControls() + { + // create menu tabstrip + _tabContainer = CreateTabContainer(); + _tabContainer.Click += OnSelectTabCommand; - // create multiview container - _multiView = new MultiView(); - _multiView.ActiveViewChanged += OnActiveViewChanged; + // create multiview container + _multiView = new MultiView(); + _multiView.ActiveViewChanged += OnActiveViewChanged; - // add views previously parsed - for (int i = 0; i < _parsedViews.Count; i++) _multiView.Controls.Add((Control) _parsedViews[i]); - _parsedViews = null; + // add views previously parsed + for (int i = 0; i < _parsedViews.Count; i++) _multiView.Controls.Add((Control) _parsedViews[i]); + _parsedViews = null; - // select defined view - if (_activeViewIndexCached != -1) - { - _multiView.ActiveViewIndex = _activeViewIndexCached; - _activeViewIndexCached = -1; - } + // select defined view + if (_activeViewIndexCached != -1) + { + _multiView.ActiveViewIndex = _activeViewIndexCached; + _activeViewIndexCached = -1; + } - // create content pane - Control content = CreateContent(_tabContainer, _multiView); - Controls.Add(content); + // create content pane + Control content = CreateContent(_tabContainer, _multiView); + Controls.Add(content); - RebuildTabs(); - } + RebuildTabs(); + } - /// - /// Adds the element to the collection of child controls. - /// - protected override void AddParsedSubObject(object obj) - { - // remember parsed views for later - if (obj is TabularView) - { - _parsedViews.Add(obj); - } - else if (!(obj is LiteralControl)) - { - throw new HttpException( - string.Format("TabularMultiView_cannot_have_children_of_type '{0}'", obj.GetType().FullName)); - } - } + /// + /// Adds the element to the collection of child controls. + /// + protected override void AddParsedSubObject(object obj) + { + // remember parsed views for later + if (obj is TabularView) + { + _parsedViews.Add(obj); + } + else if (!(obj is LiteralControl)) + { + throw new HttpException( + string.Format("TabularMultiView_cannot_have_children_of_type '{0}'", obj.GetType().FullName)); + } + } - /// - /// Called if ActiveViewIndex is changed - /// - private void RebuildTabs() - { - _tabContainer.Controls.Clear(); + /// + /// Called if ActiveViewIndex is changed + /// + private void RebuildTabs() + { + _tabContainer.Controls.Clear(); - ViewCollection views = _multiView.Views; - for (int i = 0; i < views.Count; i++) - { - TabularView view = (TabularView) views[i]; - _tabContainer.CreateTab(this, view, i); - } - } + ViewCollection views = _multiView.Views; + for (int i = 0; i < views.Count; i++) + { + TabularView view = (TabularView) views[i]; + _tabContainer.CreateTab(this, view, i); + } + } - private void OnSelectTabCommand(object sender, TabCommandEventArgs e) - { - int selectedIndex = e.TabIndex; - if (selectedIndex != _multiView.ActiveViewIndex) - { - // will trigger OnActiveViewChanged - _multiView.ActiveViewIndex = selectedIndex; - RebuildTabs(); - } - } + private void OnSelectTabCommand(object sender, TabCommandEventArgs e) + { + int selectedIndex = e.TabIndex; + if (selectedIndex != _multiView.ActiveViewIndex) + { + // will trigger OnActiveViewChanged + _multiView.ActiveViewIndex = selectedIndex; + RebuildTabs(); + } + } - private void OnActiveViewChanged(object sender, EventArgs e) - { - EventHandler handler = (EventHandler) base.Events[_eventActiveTabChanged]; - if (handler != null) - { - handler(this, e); - } - } - } + private void OnActiveViewChanged(object sender, EventArgs e) + { + EventHandler handler = (EventHandler) base.Events[_eventActiveTabChanged]; + if (handler != null) + { + handler(this, e); + } + } } diff --git a/src/Spring/Spring.Web/Web/UI/Controls/TabularView.cs b/src/Spring/Spring.Web/Web/UI/Controls/TabularView.cs index e946a73f..04f4936c 100644 --- a/src/Spring/Spring.Web/Web/UI/Controls/TabularView.cs +++ b/src/Spring/Spring.Web/Web/UI/Controls/TabularView.cs @@ -27,56 +27,55 @@ using System.Web.UI.WebControls; #endregion -namespace Spring.Web.UI.Controls +namespace Spring.Web.UI.Controls; + +/// +/// Represents a control that acts as a container for a group of controls within a control. +/// +/// Erich Eichinger +[ToolboxData("<{0}:TabularView runat=\"server\">")] +public class TabularView : View { - /// - /// Represents a control that acts as a container for a group of controls within a control. - /// - /// Erich Eichinger - [ToolboxData("<{0}:TabularView runat=\"server\">")] - public class TabularView : View - { - private static readonly PropertyInfo s_fiActive = - typeof(View).GetProperty("Active", BindingFlags.Instance | BindingFlags.NonPublic); + private static readonly PropertyInfo s_fiActive = + typeof(View).GetProperty("Active", BindingFlags.Instance | BindingFlags.NonPublic); - /// - /// Indicates if this view is currently active. - /// - public bool Active - { - get { return (bool) s_fiActive.GetValue(this, null); } - } + /// + /// Indicates if this view is currently active. + /// + public bool Active + { + get { return (bool) s_fiActive.GetValue(this, null); } + } - private string m_TabToolTip; + private string m_TabToolTip; - /// - /// Get or Set the name of the tab item associated with this view. - /// - [Description("Name of the tab.") - , NotifyParentProperty(true) - , DefaultValue("Tab") - , Category("Behavior")] - public string TabName - { - get - { - string str = (string) ViewState["m_TabName"]; - return str; - } - set { ViewState["m_TabName"] = value; } - } + /// + /// Get or Set the name of the tab item associated with this view. + /// + [Description("Name of the tab.") + , NotifyParentProperty(true) + , DefaultValue("Tab") + , Category("Behavior")] + public string TabName + { + get + { + string str = (string) ViewState["m_TabName"]; + return str; + } + set { ViewState["m_TabName"] = value; } + } - /// - /// Get or Set the tooltip text of the tab item associated with this view. - /// - [Description("Tooltip of the tab.") - , NotifyParentProperty(true) - , DefaultValue("") - , Category("Behavior")] - public string TabToolTip - { - get { return m_TabToolTip; } - set { m_TabToolTip = value; } - } - } + /// + /// Get or Set the tooltip text of the tab item associated with this view. + /// + [Description("Tooltip of the tab.") + , NotifyParentProperty(true) + , DefaultValue("") + , Category("Behavior")] + public string TabToolTip + { + get { return m_TabToolTip; } + set { m_TabToolTip = value; } + } } \ No newline at end of file diff --git a/src/Spring/Spring.Web/Web/UI/Controls/TabularViewCollection.cs b/src/Spring/Spring.Web/Web/UI/Controls/TabularViewCollection.cs index a9ce23df..45e22213 100644 --- a/src/Spring/Spring.Web/Web/UI/Controls/TabularViewCollection.cs +++ b/src/Spring/Spring.Web/Web/UI/Controls/TabularViewCollection.cs @@ -27,55 +27,56 @@ using System.Web.UI.WebControls; #endregion -namespace Spring.Web.UI.Controls +namespace Spring.Web.UI.Controls; + +/// +/// Holds the collection of controls in a . +/// +/// Erich Eichinger +[ + AspNetHostingPermission(SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal) + , AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)] +public class TabularViewCollection : ViewCollection { - /// - /// Holds the collection of controls in a . - /// - /// Erich Eichinger - [ - AspNetHostingPermission(SecurityAction.LinkDemand, Level=AspNetHostingPermissionLevel.Minimal) - , AspNetHostingPermission(SecurityAction.InheritanceDemand, Level=AspNetHostingPermissionLevel.Minimal)] - public class TabularViewCollection : ViewCollection - { - /// - /// Initialize a new instance. - /// - /// - public TabularViewCollection(Control owner) : base(owner) - { - } + /// + /// Initialize a new instance. + /// + /// + public TabularViewCollection(Control owner) : base(owner) + { + } - /// - /// Add the specified control to the collection. - /// - public override void Add(Control v) - { - if (!(v is TabularView)) - { - throw new ArgumentException("ViewCollection_must_contain_view"); - } - base.Add(v); - } + /// + /// Add the specified control to the collection. + /// + public override void Add(Control v) + { + if (!(v is TabularView)) + { + throw new ArgumentException("ViewCollection_must_contain_view"); + } - /// - /// Add the specified control to the collection. - /// - public override void AddAt(int index, Control v) - { - if (!(v is TabularView)) - { - throw new ArgumentException("ViewCollection_must_contain_view"); - } - base.AddAt(index, v); - } + base.Add(v); + } - /// - /// Obtain the specified control from the collection. - /// - public new TabularView this[int i] - { - get { return (TabularView) base[i]; } - } - } + /// + /// Add the specified control to the collection. + /// + public override void AddAt(int index, Control v) + { + if (!(v is TabularView)) + { + throw new ArgumentException("ViewCollection_must_contain_view"); + } + + base.AddAt(index, v); + } + + /// + /// Obtain the specified control from the collection. + /// + public new TabularView this[int i] + { + get { return (TabularView) base[i]; } + } } diff --git a/src/Spring/Spring.Web/Web/UI/Controls/ValidationError.cs b/src/Spring/Spring.Web/Web/UI/Controls/ValidationError.cs index e0f146c5..660f8496 100644 --- a/src/Spring/Spring.Web/Web/UI/Controls/ValidationError.cs +++ b/src/Spring/Spring.Web/Web/UI/Controls/ValidationError.cs @@ -24,22 +24,21 @@ using Spring.Web.UI.Validation; #endregion -namespace Spring.Web.UI.Controls +namespace Spring.Web.UI.Controls; + +/// +/// This control should be used to display field-level validation errors. +/// +/// Aleksandar Seovic +/// Jonathan Allenby +public class ValidationError : AbstractValidationControl { /// - /// This control should be used to display field-level validation errors. + /// Create the default + /// for this ValidationControl if none is configured. /// - /// Aleksandar Seovic - /// Jonathan Allenby - public class ValidationError : AbstractValidationControl + protected override IValidationErrorsRenderer CreateValidationErrorsRenderer() { - /// - /// Create the default - /// for this ValidationControl if none is configured. - /// - protected override IValidationErrorsRenderer CreateValidationErrorsRenderer() - { - return new SpanValidationErrorsRenderer(); - } + return new SpanValidationErrorsRenderer(); } -} \ No newline at end of file +} diff --git a/src/Spring/Spring.Web/Web/UI/Controls/ValidationSummary.cs b/src/Spring/Spring.Web/Web/UI/Controls/ValidationSummary.cs index 29fd7046..8c3baa9b 100644 --- a/src/Spring/Spring.Web/Web/UI/Controls/ValidationSummary.cs +++ b/src/Spring/Spring.Web/Web/UI/Controls/ValidationSummary.cs @@ -24,23 +24,22 @@ using Spring.Web.UI.Validation; #endregion -namespace Spring.Web.UI.Controls +namespace Spring.Web.UI.Controls; + +/// +/// This control should be used instead of standard ValidationSummary control +/// to display validation errors identified by the Spring.NET validation framework. +/// +/// Aleksandar Seovic +/// Jonathan Allenby +public class ValidationSummary : AbstractValidationControl { /// - /// This control should be used instead of standard ValidationSummary control - /// to display validation errors identified by the Spring.NET validation framework. + /// Create the default + /// for this ValidationControl if none is configured. /// - /// Aleksandar Seovic - /// Jonathan Allenby - public class ValidationSummary : AbstractValidationControl + protected override IValidationErrorsRenderer CreateValidationErrorsRenderer() { - /// - /// Create the default - /// for this ValidationControl if none is configured. - /// - protected override IValidationErrorsRenderer CreateValidationErrorsRenderer() - { - return new DivValidationErrorsRenderer(); - } + return new DivValidationErrorsRenderer(); } } \ No newline at end of file diff --git a/src/Spring/Spring.Web/Web/UI/DialogAttribute.cs b/src/Spring/Spring.Web/Web/UI/DialogAttribute.cs index ac310400..f610d696 100644 --- a/src/Spring/Spring.Web/Web/UI/DialogAttribute.cs +++ b/src/Spring/Spring.Web/Web/UI/DialogAttribute.cs @@ -18,24 +18,23 @@ #endregion -namespace Spring.Web.UI +namespace Spring.Web.UI; + +/// +/// Specifies that page should be treated as a dialog, meaning that after processing +/// is over user should return to the referring page. +/// +/// +///

+/// Pages marked with this attribute will have "close" result predefined. +///

+///

+/// Developers should call SetResult("close") from the event handler +/// in order to return control back to the calling page. +///

+///
+/// Aleksandar Seovic +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)] +public class DialogAttribute : Attribute { - /// - /// Specifies that page should be treated as a dialog, meaning that after processing - /// is over user should return to the referring page. - /// - /// - ///

- /// Pages marked with this attribute will have "close" result predefined. - ///

- ///

- /// Developers should call SetResult("close") from the event handler - /// in order to return control back to the calling page. - ///

- ///
- /// Aleksandar Seovic - [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)] - public class DialogAttribute : Attribute - { - } } diff --git a/src/Spring/Spring.Web/Web/UI/IModelPersistenceMedium.cs b/src/Spring/Spring.Web/Web/UI/IModelPersistenceMedium.cs index 9a7747a9..eed6c31a 100644 --- a/src/Spring/Spring.Web/Web/UI/IModelPersistenceMedium.cs +++ b/src/Spring/Spring.Web/Web/UI/IModelPersistenceMedium.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -24,28 +24,27 @@ using System.Web.UI; #endregion -namespace Spring.Web.UI +namespace Spring.Web.UI; + +/// +/// Abstracts storage strategy for storing model instances between requests. +/// All storage providers participating in UI model management must implement this interface. +/// +/// +/// Erich Eichinger +public interface IModelPersistenceMedium { /// - /// Abstracts storage strategy for storing model instances between requests. - /// All storage providers participating in UI model management must implement this interface. + /// Load the model for the specified control context. /// - /// - /// Erich Eichinger - public interface IModelPersistenceMedium - { - /// - /// Load the model for the specified control context. - /// - /// the control context. - /// the model for the specified control context. - object LoadFromMedium( Control context ); + /// the control context. + /// the model for the specified control context. + object LoadFromMedium(Control context); - /// - /// Save the specified model object. - /// - /// the control context. - /// the model to save. - void SaveToMedium( Control context, object modelToSave ); - } + /// + /// Save the specified model object. + /// + /// the control context. + /// the model to save. + void SaveToMedium(Control context, object modelToSave); } \ No newline at end of file diff --git a/src/Spring/Spring.Web/Web/UI/IValidationContainer.cs b/src/Spring/Spring.Web/Web/UI/IValidationContainer.cs index fa5dfb5c..76cb7012 100644 --- a/src/Spring/Spring.Web/Web/UI/IValidationContainer.cs +++ b/src/Spring/Spring.Web/Web/UI/IValidationContainer.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -25,23 +25,23 @@ using Spring.Validation; #endregion -namespace Spring.Web.UI +namespace Spring.Web.UI; + +/// +/// Abstracts access to properties required for +/// handling validation and error rendering +/// +/// Erich Eichinger +public interface IValidationContainer { /// - /// Abstracts access to properties required for - /// handling validation and error rendering + /// Gets the MessageSource to be used for + /// resolving error ids into messages /// - /// Erich Eichinger - public interface IValidationContainer - { - /// - /// Gets the MessageSource to be used for - /// resolving error ids into messages - /// - IMessageSource MessageSource { get; } - /// - /// Gets the list of validation errors kept by this container. - /// - IValidationErrors ValidationErrors { get; } - } + IMessageSource MessageSource { get; } + + /// + /// Gets the list of validation errors kept by this container. + /// + IValidationErrors ValidationErrors { get; } } \ No newline at end of file diff --git a/src/Spring/Spring.Web/Web/UI/MasterPage.cs b/src/Spring/Spring.Web/Web/UI/MasterPage.cs index 56c51d79..9e4cd4bb 100644 --- a/src/Spring/Spring.Web/Web/UI/MasterPage.cs +++ b/src/Spring/Spring.Web/Web/UI/MasterPage.cs @@ -25,7 +25,6 @@ using System.Web.UI; using Spring.Collections; using Spring.Validation; using IValidator = Spring.Validation.IValidator; - using Spring.Context; using Spring.Context.Support; using Spring.Globalization; @@ -36,580 +35,582 @@ using Spring.Web.Support; #endregion Imports -namespace Spring.Web.UI +namespace Spring.Web.UI; + +#region ASP.NET 2.0 Spring Master Page Implementation + +/// +/// Spring.NET Master Page implementation for ASP.NET 2.0 +/// +/// Aleksandar Seovic +public class MasterPage : System.Web.UI.MasterPage, IApplicationContextAware, ISupportsWebDependencyInjection, IWebNavigable { - #region ASP.NET 2.0 Spring Master Page Implementation + #region Instance Fields + + private ILocalizer localizer; + private IValidationErrors validationErrors = new ValidationErrors(); + private IMessageSource messageSource; + private IApplicationContext applicationContext; + private IApplicationContext defaultApplicationContext; + private IWebNavigator webNavigator; + private IDictionary args; + + #endregion + + #region Lifecycle methods /// - /// Spring.NET Master Page implementation for ASP.NET 2.0 + /// Initialize a new MasterPage instance. /// - /// Aleksandar Seovic - public class MasterPage : System.Web.UI.MasterPage, IApplicationContextAware, ISupportsWebDependencyInjection, IWebNavigable + public MasterPage() { - #region Instance Fields + InitializeNavigationSupport(); + } - private ILocalizer localizer; - private IValidationErrors validationErrors = new ValidationErrors(); - private IMessageSource messageSource; - private IApplicationContext applicationContext; - private IApplicationContext defaultApplicationContext; - private IWebNavigator webNavigator; - private IDictionary args; + /// + /// Initializes user control. + /// + protected override void OnInit(EventArgs e) + { + InitializeMessageSource(); - #endregion + base.OnInit(e); - #region Lifecycle methods + // initialize controls + OnInitializeControls(EventArgs.Empty); + } - /// - /// Initialize a new MasterPage instance. - /// - public MasterPage() + /// + /// Binds data from the data model into controls and raises + /// PreRender event afterwards. + /// + /// Event arguments. + protected override void OnPreRender(EventArgs e) + { + if (localizer != null) { - InitializeNavigationSupport(); + localizer.ApplyResources(this, messageSource, UserCulture); + } + else if (Page.Localizer != null) + { + Page.Localizer.ApplyResources(this, messageSource, UserCulture); } - /// - /// Initializes user control. - /// - protected override void OnInit(EventArgs e) + base.OnPreRender(e); + } + + /// + /// This event is raised before Load event and should be used to initialize + /// controls as necessary. + /// + public event EventHandler InitializeControls; + + /// + /// Raises InitializeControls event. + /// + /// Event arguments. + protected virtual void OnInitializeControls(EventArgs e) + { + if (InitializeControls != null) { - InitializeMessageSource(); - - base.OnInit(e); - - // initialize controls - OnInitializeControls(EventArgs.Empty); + InitializeControls(this, e); } + } - /// - /// Binds data from the data model into controls and raises - /// PreRender event afterwards. - /// - /// Event arguments. - protected override void OnPreRender(EventArgs e) + /// + /// Obtains a object from a user control file + /// and injects dependencies according to Spring config file. + /// + /// The virtual path to a user control file. + /// + /// Returns the specified object, with dependencies injected. + /// + protected virtual new Control LoadControl(string virtualPath) + { + Control control = base.LoadControl(virtualPath); + control = WebDependencyInjectionUtils.InjectDependenciesRecursive(defaultApplicationContext, control); + return control; + } + + /// + /// Obtains a object by type + /// and injects dependencies according to Spring config file. + /// + /// The type of a user control. + /// parameters to pass to the control + /// + /// Returns the specified object, with dependencies injected. + /// + protected virtual new Control LoadControl(Type t, params object[] parameters) + { + Control control = base.LoadControl(t, parameters); + control = WebDependencyInjectionUtils.InjectDependenciesRecursive(defaultApplicationContext, control); + return control; + } + + #endregion Control lifecycle methods + + #region Data binding events + + /// + /// This event is raised after all controls have been populated with values + /// from the data model. + /// + public event EventHandler DataBound; + + /// + /// Raises DataBound event. + /// + /// Event arguments. + protected virtual void OnDataBound(EventArgs e) + { + if (DataBound != null) { - if (localizer != null) - { - localizer.ApplyResources(this, messageSource, UserCulture); - } - else if (Page.Localizer != null) - { - Page.Localizer.ApplyResources(this, messageSource, UserCulture); - } - - base.OnPreRender(e); + DataBound(this, e); } + } - /// - /// This event is raised before Load event and should be used to initialize - /// controls as necessary. - /// - public event EventHandler InitializeControls; + /// + /// This event is raised after data model has been populated with values from + /// web controls. + /// + public event EventHandler DataUnbound; - /// - /// Raises InitializeControls event. - /// - /// Event arguments. - protected virtual void OnInitializeControls(EventArgs e) + /// + /// Raises DataBound event. + /// + /// Event arguments. + protected virtual void OnDataUnbound(EventArgs e) + { + if (DataUnbound != null) { - if (InitializeControls != null) - { - InitializeControls(this, e); - } + DataUnbound(this, e); } - - /// - /// Obtains a object from a user control file - /// and injects dependencies according to Spring config file. - /// - /// The virtual path to a user control file. - /// - /// Returns the specified object, with dependencies injected. - /// - protected virtual new Control LoadControl(string virtualPath) - { - Control control = base.LoadControl(virtualPath); - control = WebDependencyInjectionUtils.InjectDependenciesRecursive(defaultApplicationContext,control); - return control; - } - - /// - /// Obtains a object by type - /// and injects dependencies according to Spring config file. - /// - /// The type of a user control. - /// parameters to pass to the control - /// - /// Returns the specified object, with dependencies injected. - /// - protected virtual new Control LoadControl( Type t, params object[] parameters) - { - Control control = base.LoadControl( t, parameters ); - control = WebDependencyInjectionUtils.InjectDependenciesRecursive(defaultApplicationContext,control); - return control; - } - - #endregion Control lifecycle methods - - #region Data binding events - - /// - /// This event is raised after all controls have been populated with values - /// from the data model. - /// - public event EventHandler DataBound; - - /// - /// Raises DataBound event. - /// - /// Event arguments. - protected virtual void OnDataBound(EventArgs e) - { - if (DataBound != null) - { - DataBound(this, e); - } - } - - /// - /// This event is raised after data model has been populated with values from - /// web controls. - /// - public event EventHandler DataUnbound; - - /// - /// Raises DataBound event. - /// - /// Event arguments. - protected virtual void OnDataUnbound(EventArgs e) - { - if (DataUnbound != null) - { - DataUnbound(this, e); - } - } - - #endregion - - #region Application context support - - /// - /// Gets or sets the that this - /// object runs in. - /// - /// - /// - ///

- /// Normally this call will be used to initialize the object. - ///

- ///

- /// Invoked after population of normal object properties but before an - /// init callback such as - /// 's - /// - /// or a custom init-method. Invoked after the setting of any - /// 's - /// - /// property. - ///

- ///
- /// - /// In the case of application context initialization errors. - /// - /// - /// If thrown by any application context methods. - /// - /// - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public virtual IApplicationContext ApplicationContext - { - get { return applicationContext; } - set { applicationContext = value; } - } - - #endregion - - #region Message source and localization support - - /// - /// Gets or sets the localizer. - /// - /// The localizer. - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public ILocalizer Localizer - { - get { return localizer; } - set - { - localizer = value; - if (localizer.ResourceCache is NullResourceCache) - { - localizer.ResourceCache = new AspNetResourceCache(); - } - } - } - - /// - /// Gets or sets the local message source. - /// - /// The local message source. - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public IMessageSource MessageSource - { - get { return messageSource; } - set - { - messageSource = value; - if (messageSource != null && messageSource is AbstractMessageSource) - { - ((AbstractMessageSource) messageSource).ParentMessageSource = applicationContext; - } - } - } - - /// - /// Initializes local message source - /// - protected void InitializeMessageSource() - { - if (MessageSource == null) - { - string key = GetType().FullName + ".MessageSource"; - MessageSource = (IMessageSource) Context.Cache.Get(key); - - if (MessageSource == null) - { - ResourceSetMessageSource defaultMessageSource = new ResourceSetMessageSource(); - ResourceManager rm = GetLocalResourceManager(); - if (rm != null) - { - defaultMessageSource.ResourceManagers.Add(rm); - } - Context.Cache.Insert(key, defaultMessageSource); - MessageSource = defaultMessageSource; - } - } - } - - /// - /// Creates and returns local ResourceManager for this page. - /// - /// - /// - /// In ASP.NET 1.1, this method loads local resources from the web application assembly. - /// - /// - /// However, in ASP.NET 2.0, local resources are compiled into the dynamic assembly, - /// so we need to find that assembly instead and load the resources from it. - /// - /// - /// Local ResourceManager instance. - private ResourceManager GetLocalResourceManager() - { - return LocalResourceManager.GetLocalResourceManager(this); - } - - /// - /// Returns message for the specified resource name. - /// - /// Resource name. - /// Message text. - public string GetMessage(string name) - { - return messageSource.GetMessage(name, UserCulture); - } - - /// - /// Returns message for the specified resource name. - /// - /// Resource name. - /// Message arguments that will be used to format return value. - /// Formatted message text. - public string GetMessage(string name, params object[] args) - { - return messageSource.GetMessage(name, UserCulture, args); - } - - /// - /// Returns resource object for the specified resource name. - /// - /// Resource name. - /// Resource object. - public object GetResourceObject(string name) - { - return messageSource.GetResourceObject(name, UserCulture); - } - - /// - /// Gets or sets user's culture - /// - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public virtual CultureInfo UserCulture - { - get { return Page.UserCulture; } - set { Page.UserCulture = value; } - } - - #endregion - - #region Result support - - /// - /// Ensure, that is set to a valid instance. - /// - /// - /// If is not already set, creates and sets a new instance.
- /// Override this method if you don't want to inject a navigator, but need a different default. - ///
- protected virtual void InitializeNavigationSupport() - { - webNavigator = new WebFormsResultWebNavigator(this, null, null, true); - } - - /// - /// Gets/Sets the navigator to be used for handling calls. - /// - public IWebNavigator WebNavigator - { - get - { - return webNavigator; - } - set - { - webNavigator = value; - } - } - - /// - /// Gets or sets map of result names to target URLs - /// - /// - /// Using requires to implement . - /// - [Browsable( false )] - [DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden )] - public virtual IDictionary Results - { - get - { - if (WebNavigator is IResultWebNavigator) - { - return ((IResultWebNavigator)WebNavigator).Results; - } - return null; - } - set - { - if (WebNavigator is IResultWebNavigator) - { - ((IResultWebNavigator)WebNavigator).Results = value; - return; - } - throw new NotSupportedException("WebNavigator must be of type IResultWebNavigator to support Results"); - } - } - - /// - /// A convenience, case-insensitive table that may be used to e.g. pass data into SpEL expressions"/>. - /// - /// - /// By default, e.g. passes the control instance into an expression. Using - /// is an easy way to pass additional parameters into the expression - /// - /// // config: - /// - /// <property Name="Results"> - /// <dictionary> - /// <entry key="ok_clicked" value="redirect:~/ShowResult.aspx?result=%{Args['result']}" /> - /// </dictionary> - /// </property> - /// - /// // code: - /// - /// void OnOkClicked(object sender, EventArgs e) - /// { - /// Args["result"] = txtUserInput.Text; - /// SetResult("ok_clicked"); - /// } - /// - /// - public IDictionary Args - { - get - { - if (args == null) - { - args = new CaseInsensitiveHashtable(); - } - return args; - } - } - - /// - /// Redirects user to a URL mapped to specified result name. - /// - /// Result name. - protected void SetResult( string resultName ) - { - WebNavigator.NavigateTo( resultName, this, null ); - } - - - /// - /// Redirects user to a URL mapped to specified result name. - /// - /// Name of the result. - /// The context to use for evaluating the SpEL expression in the Result. - protected void SetResult( string resultName, object context ) - { - WebNavigator.NavigateTo( resultName, this, context ); - } - - - /// - /// Returns a redirect url string that points to the - /// defined by this - /// result evaluated using this Page for expression - /// - /// Name of the result. - /// A redirect url string. - protected string GetResultUrl( string resultName ) - { - return ResolveUrl( WebNavigator.GetResultUri( resultName, this, null ) ); - } - - /// - /// Returns a redirect url string that points to the - /// defined by this - /// result evaluated using this Page for expression - /// - /// Name of the result. - /// The context to use for evaluating the SpEL expression in the Result - /// A redirect url string. - protected string GetResultUrl( string resultName, object context ) - { - return ResolveUrl( WebNavigator.GetResultUri( resultName, this, context ) ); - } - - #endregion - - #region Validation support - - /// - /// Evaluates specified validators and returns True if all of them are valid. - /// - /// - ///

- /// Each validator can itself represent a collection of other validators if it is - /// an instance of or one of its derived types. - ///

- ///

- /// Please see the Validation Framework section in the documentation for more info. - ///

- ///
- /// Object to validate. - /// Validators to evaluate. - /// - /// True if all of the specified validators are valid, False otherwise. - /// - public virtual bool Validate(object validationContext, params IValidator[] validators) - { - IDictionary contextParams = CreateValidatorParameters(); - bool result = true; - foreach (IValidator validator in validators) - { - if (validator == null) - { - throw new ArgumentException("Validator is not defined."); - } - result = validator.Validate(validationContext, contextParams, this.validationErrors) && result; - } - - return result; - } - - /// - /// Gets the validation errors container. - /// - /// The validation errors container. - public virtual IValidationErrors ValidationErrors - { - get { return validationErrors; } - } - - /// - /// Creates the validator parameters. - /// - /// - /// - /// This method can be overriden if you want to pass additional parameters - /// to the validation framework, but you should make sure that you call - /// this base implementation in order to add page, session, application, - /// request, response and context to the variables collection. - /// - /// - /// - /// Dictionary containing parameters that should be passed to - /// the data validation framework. - /// - protected virtual IDictionary CreateValidatorParameters() - { - IDictionary parameters = new Dictionary(8); - parameters["page"] = this.Page; - parameters["usercontrol"] = this; - parameters["session"] = this.Session; - parameters["application"] = this.Application; - parameters["request"] = this.Request; - parameters["response"] = this.Response; - parameters["context"] = this.Context; - - return parameters; - } - - #endregion - - #region Spring Page support - - /// - /// Overrides Page property to return - /// instead of . - /// - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public new Page Page - { - get { return (Page) base.Page; } - } - - #endregion - - #region Dependency Injection Support - - /// - /// Holds the default ApplicationContext to be used during DI. - /// - IApplicationContext ISupportsWebDependencyInjection.DefaultApplicationContext - { - get { return defaultApplicationContext; } - set { defaultApplicationContext = value; } - } - - /// - /// Injects dependencies before adding the control. - /// - protected override void AddedControl(Control control,int index) - { - control = WebDependencyInjectionUtils.InjectDependenciesRecursive(defaultApplicationContext,control); - base.AddedControl(control,index); - } - - #endregion Dependency Injection Support } #endregion + + #region Application context support + + /// + /// Gets or sets the that this + /// object runs in. + /// + /// + /// + ///

+ /// Normally this call will be used to initialize the object. + ///

+ ///

+ /// Invoked after population of normal object properties but before an + /// init callback such as + /// 's + /// + /// or a custom init-method. Invoked after the setting of any + /// 's + /// + /// property. + ///

+ ///
+ /// + /// In the case of application context initialization errors. + /// + /// + /// If thrown by any application context methods. + /// + /// + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public virtual IApplicationContext ApplicationContext + { + get { return applicationContext; } + set { applicationContext = value; } + } + + #endregion + + #region Message source and localization support + + /// + /// Gets or sets the localizer. + /// + /// The localizer. + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public ILocalizer Localizer + { + get { return localizer; } + set + { + localizer = value; + if (localizer.ResourceCache is NullResourceCache) + { + localizer.ResourceCache = new AspNetResourceCache(); + } + } + } + + /// + /// Gets or sets the local message source. + /// + /// The local message source. + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public IMessageSource MessageSource + { + get { return messageSource; } + set + { + messageSource = value; + if (messageSource != null && messageSource is AbstractMessageSource) + { + ((AbstractMessageSource) messageSource).ParentMessageSource = applicationContext; + } + } + } + + /// + /// Initializes local message source + /// + protected void InitializeMessageSource() + { + if (MessageSource == null) + { + string key = GetType().FullName + ".MessageSource"; + MessageSource = (IMessageSource) Context.Cache.Get(key); + + if (MessageSource == null) + { + ResourceSetMessageSource defaultMessageSource = new ResourceSetMessageSource(); + ResourceManager rm = GetLocalResourceManager(); + if (rm != null) + { + defaultMessageSource.ResourceManagers.Add(rm); + } + + Context.Cache.Insert(key, defaultMessageSource); + MessageSource = defaultMessageSource; + } + } + } + + /// + /// Creates and returns local ResourceManager for this page. + /// + /// + /// + /// In ASP.NET 1.1, this method loads local resources from the web application assembly. + /// + /// + /// However, in ASP.NET 2.0, local resources are compiled into the dynamic assembly, + /// so we need to find that assembly instead and load the resources from it. + /// + /// + /// Local ResourceManager instance. + private ResourceManager GetLocalResourceManager() + { + return LocalResourceManager.GetLocalResourceManager(this); + } + + /// + /// Returns message for the specified resource name. + /// + /// Resource name. + /// Message text. + public string GetMessage(string name) + { + return messageSource.GetMessage(name, UserCulture); + } + + /// + /// Returns message for the specified resource name. + /// + /// Resource name. + /// Message arguments that will be used to format return value. + /// Formatted message text. + public string GetMessage(string name, params object[] args) + { + return messageSource.GetMessage(name, UserCulture, args); + } + + /// + /// Returns resource object for the specified resource name. + /// + /// Resource name. + /// Resource object. + public object GetResourceObject(string name) + { + return messageSource.GetResourceObject(name, UserCulture); + } + + /// + /// Gets or sets user's culture + /// + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public virtual CultureInfo UserCulture + { + get { return Page.UserCulture; } + set { Page.UserCulture = value; } + } + + #endregion + + #region Result support + + /// + /// Ensure, that is set to a valid instance. + /// + /// + /// If is not already set, creates and sets a new instance.
+ /// Override this method if you don't want to inject a navigator, but need a different default. + ///
+ protected virtual void InitializeNavigationSupport() + { + webNavigator = new WebFormsResultWebNavigator(this, null, null, true); + } + + /// + /// Gets/Sets the navigator to be used for handling calls. + /// + public IWebNavigator WebNavigator + { + get + { + return webNavigator; + } + set + { + webNavigator = value; + } + } + + /// + /// Gets or sets map of result names to target URLs + /// + /// + /// Using requires to implement . + /// + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public virtual IDictionary Results + { + get + { + if (WebNavigator is IResultWebNavigator) + { + return ((IResultWebNavigator) WebNavigator).Results; + } + + return null; + } + set + { + if (WebNavigator is IResultWebNavigator) + { + ((IResultWebNavigator) WebNavigator).Results = value; + return; + } + + throw new NotSupportedException("WebNavigator must be of type IResultWebNavigator to support Results"); + } + } + + /// + /// A convenience, case-insensitive table that may be used to e.g. pass data into SpEL expressions"/>. + /// + /// + /// By default, e.g. passes the control instance into an expression. Using + /// is an easy way to pass additional parameters into the expression + /// + /// // config: + /// + /// <property Name="Results"> + /// <dictionary> + /// <entry key="ok_clicked" value="redirect:~/ShowResult.aspx?result=%{Args['result']}" /> + /// </dictionary> + /// </property> + /// + /// // code: + /// + /// void OnOkClicked(object sender, EventArgs e) + /// { + /// Args["result"] = txtUserInput.Text; + /// SetResult("ok_clicked"); + /// } + /// + /// + public IDictionary Args + { + get + { + if (args == null) + { + args = new CaseInsensitiveHashtable(); + } + + return args; + } + } + + /// + /// Redirects user to a URL mapped to specified result name. + /// + /// Result name. + protected void SetResult(string resultName) + { + WebNavigator.NavigateTo(resultName, this, null); + } + + /// + /// Redirects user to a URL mapped to specified result name. + /// + /// Name of the result. + /// The context to use for evaluating the SpEL expression in the Result. + protected void SetResult(string resultName, object context) + { + WebNavigator.NavigateTo(resultName, this, context); + } + + /// + /// Returns a redirect url string that points to the + /// defined by this + /// result evaluated using this Page for expression + /// + /// Name of the result. + /// A redirect url string. + protected string GetResultUrl(string resultName) + { + return ResolveUrl(WebNavigator.GetResultUri(resultName, this, null)); + } + + /// + /// Returns a redirect url string that points to the + /// defined by this + /// result evaluated using this Page for expression + /// + /// Name of the result. + /// The context to use for evaluating the SpEL expression in the Result + /// A redirect url string. + protected string GetResultUrl(string resultName, object context) + { + return ResolveUrl(WebNavigator.GetResultUri(resultName, this, context)); + } + + #endregion + + #region Validation support + + /// + /// Evaluates specified validators and returns True if all of them are valid. + /// + /// + ///

+ /// Each validator can itself represent a collection of other validators if it is + /// an instance of or one of its derived types. + ///

+ ///

+ /// Please see the Validation Framework section in the documentation for more info. + ///

+ ///
+ /// Object to validate. + /// Validators to evaluate. + /// + /// True if all of the specified validators are valid, False otherwise. + /// + public virtual bool Validate(object validationContext, params IValidator[] validators) + { + IDictionary contextParams = CreateValidatorParameters(); + bool result = true; + foreach (IValidator validator in validators) + { + if (validator == null) + { + throw new ArgumentException("Validator is not defined."); + } + + result = validator.Validate(validationContext, contextParams, this.validationErrors) && result; + } + + return result; + } + + /// + /// Gets the validation errors container. + /// + /// The validation errors container. + public virtual IValidationErrors ValidationErrors + { + get { return validationErrors; } + } + + /// + /// Creates the validator parameters. + /// + /// + /// + /// This method can be overriden if you want to pass additional parameters + /// to the validation framework, but you should make sure that you call + /// this base implementation in order to add page, session, application, + /// request, response and context to the variables collection. + /// + /// + /// + /// Dictionary containing parameters that should be passed to + /// the data validation framework. + /// + protected virtual IDictionary CreateValidatorParameters() + { + IDictionary parameters = new Dictionary(8); + parameters["page"] = this.Page; + parameters["usercontrol"] = this; + parameters["session"] = this.Session; + parameters["application"] = this.Application; + parameters["request"] = this.Request; + parameters["response"] = this.Response; + parameters["context"] = this.Context; + + return parameters; + } + + #endregion + + #region Spring Page support + + /// + /// Overrides Page property to return + /// instead of . + /// + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public new Page Page + { + get { return (Page) base.Page; } + } + + #endregion + + #region Dependency Injection Support + + /// + /// Holds the default ApplicationContext to be used during DI. + /// + IApplicationContext ISupportsWebDependencyInjection.DefaultApplicationContext + { + get { return defaultApplicationContext; } + set { defaultApplicationContext = value; } + } + + /// + /// Injects dependencies before adding the control. + /// + protected override void AddedControl(Control control, int index) + { + control = WebDependencyInjectionUtils.InjectDependenciesRecursive(defaultApplicationContext, control); + base.AddedControl(control, index); + } + + #endregion Dependency Injection Support } + +#endregion diff --git a/src/Spring/Spring.Web/Web/UI/Page.cs b/src/Spring/Spring.Web/Web/UI/Page.cs index 23984d52..6f628dae 100644 --- a/src/Spring/Spring.Web/Web/UI/Page.cs +++ b/src/Spring/Spring.Web/Web/UI/Page.cs @@ -42,1473 +42,1483 @@ using IValidator = Spring.Validation.IValidator; #endregion -namespace Spring.Web.UI +namespace Spring.Web.UI; + +#region Result support + +#endregion + +/// +/// Represents an .aspx file, also known as a Web Forms page, requested from a +/// server that hosts an ASP.NET Web application. +/// +/// +///

+/// The Page class is associated with files that have an .aspx extension. +/// These files are compiled at run time as Page objects and cached in server memory. +///

+///

+/// This class extends and adds support for master +/// pages similar to upcoming ASP.Net 2.0 master pages feature. +///

+///

+/// It also adds support for automatic localization using local page resource file, and +/// simplifies access to global resources (resources from the message source for the +/// application context). +///

+///
+/// Aleksandar Seovic +[AspNetHostingPermission(SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)] +[AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)] +public class Page : System.Web.UI.Page, IHttpHandler, IApplicationContextAware, ISharedStateAware, + ISupportsWebDependencyInjection, IWebDataBound, IValidationContainer, IWebNavigable { - #region Result support + #region Constants + + private static readonly object EventInitializeControls = new object(); + private static readonly object EventPreLoadViewState = new object(); + private static readonly object EventDataBindingsInitialized = new object(); + private static readonly object EventDataBound = new object(); + private static readonly object EventDataUnbound = new object(); + + #endregion + + #region Instance Fields + + private object controller; + private IDictionary sharedState; + + private ILocalizer localizer; + private ICultureResolver cultureResolver = new DefaultWebCultureResolver(); + private IMessageSource messageSource; + private IBindingContainer bindingManager; + private IValidationErrors validationErrors = new ValidationErrors(); + private IWebNavigator webNavigator; + private IDictionary args; + private IApplicationContext applicationContext; + private IApplicationContext defaultApplicationContext; + private static readonly string traceCategory = "Spring.Page"; + + private IDictionary styles = new ListDictionary(); + private IDictionary styleFiles = new ListDictionary(); + private IDictionary headScripts = new ListDictionary(); + private string cssRoot = "CSS"; + private string scriptsRoot = "Scripts"; + private string imagesRoot = "Images"; + + #endregion + + #region Page lifecycle methods + + /// + /// Creates and initializes the new page instance. + /// + /// + /// Calls . + /// + public Page() + { + InitializeNavigationSupport(); + } + + /// + /// Initializes Spring.NET page internals and raises the PreInit event. + /// + /// The instance containing the event data. + protected override void OnPreInit(EventArgs e) + { + if (SharedState == null) + { + SharedState = new CaseInsensitiveHashtable(); + } + + InitializeCulture(); + InitializeMessageSource(); + + base.OnPreInit(e); + } + + /// + /// Initializes the culture. + /// + protected override void InitializeCulture() + { + CultureInfo userCulture = this.UserCulture; + Thread.CurrentThread.CurrentUICulture = userCulture; + if (userCulture.IsNeutralCulture) + { + Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(userCulture.Name); + } + else + { + Thread.CurrentThread.CurrentCulture = userCulture; + } + } + + /// + /// Initializes data model and controls. + /// + protected override void OnInit(EventArgs e) + { + InitializeBindingManager(); + + if (!IsPostBack) + { + InitializeModel(); + } + else + { + LoadModel(LoadModelFromPersistenceMedium()); + } + + base.OnInit(e); + + // initialize controls + Trace.Write(traceCategory, "Initialize Controls"); + OnInitializeControls(EventArgs.Empty); + } + + /// + /// Raises the event after page initialization. + /// + protected virtual void OnPreLoadViewState(EventArgs e) + { + EventHandler handler = (EventHandler) base.Events[EventPreLoadViewState]; + if (handler != null) + { + handler(this, e); + } + } + + /// + /// PreLoadViewState event. + /// + /// + /// + /// This event is raised if is true + /// immediately before state is restored from ViewState. + /// + /// + /// NOTE: Different from , this event + /// will also be raised if the control has no ViewState or ViewState is disabled. + /// + /// + public event EventHandler PreLoadViewState + { + add { base.Events.AddHandler(EventPreLoadViewState, value); } + remove { base.Events.RemoveHandler(EventPreLoadViewState, value); } + } + + /// + /// Raises the PreLoadViewState event for + /// this page and all contained controls. + /// + private void RaisePreLoadViewStateEvent() + { + this.OnPreLoadViewState(EventArgs.Empty); + if (this.HasControls()) + { + PreLoadViewStateRecursive(this.Controls); + } + } + + /// + /// Recursively raises PreLoadViewState event. + /// + private void PreLoadViewStateRecursive(ControlCollection controls) + { + for (int i = 0; i < controls.Count; i++) + { + Control control = controls[i]; + + if (control is UserControl) + { + ((UserControl) control).OnPreLoadViewState(EventArgs.Empty); + } + + if (control.HasControls()) + { + PreLoadViewStateRecursive(control.Controls); + } + } + } + + /// + /// Overridden to add support for + /// + /// + /// If necessary override instead of this method. + /// + protected override object LoadPageStateFromPersistenceMedium() + { + RaisePreLoadViewStateEvent(); + + // If ViewState is disabled, use BindFormData() to populate controls. + BindFormDataIfNecessary(); + + // continue with default behaviour + return LoadPageStateFromPersistenceMediumBase(); + } + + /// + /// If ViewState is disabled, calls recursively for all controls. + /// + /// + /// If ViewState is disabled, DropDownLists etc. might not fire "Changed" events. + /// + protected virtual void BindFormDataIfNecessary() + { + if (!IsViewStateEnabled) + { + BindFormDataRecursive(); + } + } + + /// + /// Calls recursively for all controls. + /// + protected void BindFormDataRecursive() + { + this.BindFormData(); + if (this.HasControls()) + { + BindFormDataRecursive(this.Controls); + } + } + + /// + /// Recursively calls for all controls. + /// + private void BindFormDataRecursive(ControlCollection controls) + { + for (int i = 0; i < controls.Count; i++) + { + Control control = controls[i]; + + if (control is UserControl) + { + ((UserControl) control).BindFormData(); + } + + if (control.HasControls()) + { + BindFormDataRecursive(control.Controls); + } + } + } + + /// + /// If necessary override this method instead of + /// + protected virtual object LoadPageStateFromPersistenceMediumBase() + { + return base.LoadPageStateFromPersistenceMedium(); + } + + /// + /// Initializes dialog result and unbinds data from the controls + /// into a data model. + /// + /// Event arguments. + protected override void OnLoad(EventArgs e) + { + // create dialog result if necessary + // if (GetType().IsDefined(typeof(DialogAttribute), true)) + // { + // if (!IsPostBack) + // { + // ViewState["__dialogResult"] = "redirect:" + Request.UrlReferrer.AbsoluteUri; + // } + // Results["close"] = new Result((string) ViewState["__dialogResult"]); + // } + + if (IsPostBack) + { + // unbind form data + UnbindFormData(); + } + + Trace.Write(traceCategory, "Execute Handlers for Load Event"); + base.OnLoad(e); + } + + /// + /// Binds data from the data model into controls and raises + /// PreRender event afterwards. + /// + /// Event arguments. + protected override void OnPreRender(EventArgs e) + { + // bind data from model to form + BindFormData(); + + if (localizer != null) + { + Trace.Write(traceCategory, "Apply Localized Resources"); + localizer.ApplyResources(this, messageSource, UserCulture); + } + + base.OnPreRender(e); + + object modelToSave = SaveModel(); + if (modelToSave != null) + { + SaveModelToPersistenceMedium(modelToSave); + } + } + + /// + /// This event is raised before Init event and should be used to initialize + /// controls as necessary. + /// + public event EventHandler InitializeControls + { + add { base.Events.AddHandler(EventInitializeControls, value); } + remove { base.Events.RemoveHandler(EventInitializeControls, value); } + } + + /// + /// Raises InitializeControls event. + /// + /// Event arguments. + protected virtual void OnInitializeControls(EventArgs e) + { + EventHandler handler = (EventHandler) base.Events[EventInitializeControls]; + if (handler != null) + { + handler(this, e); + } + } + + /// + /// Obtains a object from a user control file + /// and injects dependencies according to Spring config file. + /// + /// The virtual path to a user control file. + /// + /// Returns the specified object, with dependencies injected. + /// + protected virtual new Control LoadControl(string virtualPath) + { + Control control = base.LoadControl(virtualPath); + control = WebDependencyInjectionUtils.InjectDependenciesRecursive(defaultApplicationContext, control); + return control; + } + + /// + /// Obtains a object by type + /// and injects dependencies according to Spring config file. + /// + /// The type of a user control. + /// parameters to pass to the control + /// + /// Returns the specified object, with dependencies injected. + /// + protected virtual new Control LoadControl(Type t, params object[] parameters) + { + Control control = base.LoadControl(t, parameters); + control = WebDependencyInjectionUtils.InjectDependenciesRecursive(defaultApplicationContext, control); + return control; + } + + #endregion + + #region Model Management Support + + private IModelPersistenceMedium modelPersistenceMedium = new SessionModelPersistenceMedium(); + + /// + /// Set the strategy for storing model + /// instances between requests. + /// + /// + /// By default the strategy is used. + /// + public IModelPersistenceMedium ModelPersistenceMedium + { + set + { + AssertUtils.ArgumentNotNull(value, "ModelPersistenceMedium"); + modelPersistenceMedium = value; + } + } + + /// + /// Retrieves data model from a persistence store. + /// + /// + /// The default implementation uses to store and retrieve + /// the model for the current + /// + protected virtual object LoadModelFromPersistenceMedium() + { + //return Session[Request.CurrentExecutionFilePath + ".Model"]; + return modelPersistenceMedium.LoadFromMedium(this); + } + + /// + /// Saves data model to a persistence store. + /// + /// + /// The default implementation uses to store and retrieve + /// the model for the current + /// + protected virtual void SaveModelToPersistenceMedium(object modelToSave) + { + //Session[Request.CurrentExecutionFilePath + ".Model"] = modelToSave; + modelPersistenceMedium.SaveToMedium(this, modelToSave); + } + + /// + /// Initializes data model when the page is first loaded. + /// + /// + /// This method should be overriden by the developer + /// in order to initialize data model for the page. + /// + protected virtual void InitializeModel() + { + } + + /// + /// Loads the saved data model on postback. + /// + /// + /// This method should be overriden by the developer + /// in order to load data model for the page. + /// + protected virtual void LoadModel(object savedModel) + { + } + + /// + /// Returns a model object that should be saved. + /// + /// + /// This method should be overriden by the developer + /// in order to save data model for the page. + /// + /// + /// A model object that should be saved. + /// + protected virtual object SaveModel() + { + return null; + } + + #endregion + + #region Process and Controller support + + /// + /// Gets or sets controller for the page. + /// + /// + /// + /// Application pages should shadow this property and change its type + /// in order to make calls to controller within the page as simple as possible. + /// + /// + /// If external controller is not specified, page will serve as its own controller, + /// which will allow data binding to work properly. + /// + /// + /// Controller for the page. Defaults to the page itself. + public object Controller + { + get { return GetController(); } + set { SetController(value); } + } + + /// + /// Stores the controller to be returned by property. + /// + /// + /// The default implementation uses a field to store the reference. Derived classes may override this behaviour + /// but must ensure to also change the behaviour of accordingly. + /// + /// Controller for the page. + protected virtual void SetController(object controller) + { + this.controller = controller; + } + + /// + /// Returns the controller stored by . + /// + /// + /// The default implementation uses a field to retrieve the reference. Derived classes may override this behaviour + /// but must ensure to also change the behaviour of accordingly. + /// + /// + /// The controller for this page. + /// + /// If no controller is set, a reference to the page itself is returned. + /// + /// + protected virtual object GetController() + { + if (controller == null) + { + return this; + } + + return controller; + } + + #endregion + + #region Shared State support + + /// + /// Returns a thread-safe dictionary that contains state that is shared by + /// all instances of this page. + /// + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public IDictionary SharedState + { + get { return this.sharedState; } + set { this.sharedState = value; } + } #endregion /// - /// Represents an .aspx file, also known as a Web Forms page, requested from a - /// server that hosts an ASP.NET Web application. + /// Overrides the default PreviousPage property to return an instance of , + /// and to work properly during server-side transfers and executes. + /// + public new Page PreviousPage + { + get { return this.Context.PreviousHandler as Page; } + } + + /// + /// Publish associated with this page for convenient usage in Binding Expressions + /// + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public new virtual HttpContext Context + { + get + { + return base.Context; + } + } + + #region Master Page support + + /// + /// Gets the master page that determines the overall look of the page. + /// + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public new MasterPage Master + { + get { return (MasterPage) base.Master; } + } + + /// + /// Returns true if page uses master page, false otherwise. + /// + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool HasMaster + { + get { return Master != null || MasterPageFile != null; } + } + + #endregion + + #region CSS support + + /// + /// Gets a dictionary of registered styles. + /// + /// Registered styles. + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public IDictionary Styles + { + get { return styles; } + } + + /// + /// Gets a dictionary of registered style files. + /// + /// Registered style files. + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public IDictionary StyleFiles + { + get { return styleFiles; } + } + + /// + /// Registers single CSS style with the page. + /// + /// Style name. + /// Style definition. + public void RegisterStyle(string name, string style) + { + styles[name] = style; + } + + /// + /// Returns True if specified style is registered, False otherwise. + /// + /// Style name. + /// True if specified style is registered, False otherwise. + public bool IsStyleRegistered(string name) + { + return styles.Contains(name); + } + + /// + /// Registers CSS file with the page. + /// + /// Style file key. + /// Style file name. + public void RegisterStyleFile(string key, string fileName) + { + styleFiles[key] = fileName; + } + + /// + /// Returns True if specified style file is registered, False otherwise. + /// + /// Style file key. + /// True if specified style file is registered, False otherwise. + public bool IsStyleFileRegistered(string key) + { + return styleFiles.Contains(key); + } + + #endregion + + #region Client script support + + /// + /// Gets a dictionary of registered head scripts. + /// + /// Registered head scripts. + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public IDictionary HeadScripts + { + get { return headScripts; } + } + + /// + /// Registers script block that should be rendered within the head HTML element. + /// + /// Script key. + /// Script text. + public void RegisterHeadScriptBlock(string key, string script) + { + RegisterHeadScriptBlock(key, Script.DefaultType, script); + } + + /// + /// Registers script block that should be rendered within the head HTML element. + /// + /// Script key. + /// Script language MIME type. + /// Script text. + public void RegisterHeadScriptBlock(string key, MimeMediaType type, string script) + { + headScripts[key] = new ScriptBlock(type, script); + } + + /// + /// Registers script file that should be referenced within the head HTML element. + /// + /// Script key. + /// Script file name. + public void RegisterHeadScriptFile(string key, string fileName) + { + RegisterHeadScriptFile(key, Script.DefaultType, fileName); + } + + /// + /// Registers script file that should be referenced within the head HTML element. + /// + /// Script key. + /// Script language MIME type. + /// Script file name. + public void RegisterHeadScriptFile(string key, MimeMediaType type, string fileName) + { + headScripts[key] = new ScriptFile(type, fileName); + } + + /// + /// Registers script block that should be rendered within the head HTML element. + /// + /// Script key. + /// Element ID of the event source. + /// Name of the event to handle. + /// Script text. + public void RegisterHeadScriptEvent(string key, string element, string eventName, string script) + { + RegisterHeadScriptEvent(key, Script.DefaultType, element, eventName, script); + } + + /// + /// Registers script block that should be rendered within the head HTML element. + /// + /// Script key. + /// The scripting language's MIME type. + /// Element ID of the event source. + /// Name of the event to handle. + /// Script text. + public void RegisterHeadScriptEvent(string key, MimeMediaType mimeType, string element, string eventName, string script) + { + headScripts[key] = new ScriptEvent(mimeType, element, eventName, script); + } + + /// + /// Returns True if specified head script is registered, False otherwise. + /// + /// Script key. + /// True if specified head script is registered, False otherwise. + public bool IsHeadScriptRegistered(string key) + { + return headScripts.Contains(key); + } + + #endregion + + #region Well-known folders support + + /// + /// Gets or sets the CSS root. + /// + /// The CSS root. + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public string CssRoot + { + get { return WebUtils.CreateAbsolutePath(Request.ApplicationPath, cssRoot); } + set { cssRoot = value; } + } + + /// + /// Gets or sets the scripts root. + /// + /// The scripts root. + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public string ScriptsRoot + { + get { return WebUtils.CreateAbsolutePath(Request.ApplicationPath, scriptsRoot); } + set { scriptsRoot = value; } + } + + /// + /// Gets or sets the images root. + /// + /// The images root. + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public string ImagesRoot + { + get { return WebUtils.CreateAbsolutePath(Request.ApplicationPath, imagesRoot); } + set { imagesRoot = value; } + } + + #endregion + + #region Result support + + /// + /// Ensure, that is set to a valid instance. + /// + /// + /// If is not already set, creates and sets a new instance.
+ /// Override this method if you don't want to inject a navigator, but need a different default. + ///
+ protected virtual void InitializeNavigationSupport() + { + webNavigator = new WebFormsResultWebNavigator(this, null, null, true); + } + + /// + /// Gets/Sets the navigator to be used for handling calls. + /// + public virtual IWebNavigator WebNavigator + { + get + { + return webNavigator; + } + set + { + webNavigator = value; + } + } + + /// + /// Gets or sets map of result names to target URLs + /// + /// + /// Using requires to implement . + /// + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public virtual IDictionary Results + { + get + { + if (WebNavigator is IResultWebNavigator) + { + return ((IResultWebNavigator) WebNavigator).Results; + } + + return null; + } + set + { + if (WebNavigator is IResultWebNavigator) + { + ((IResultWebNavigator) WebNavigator).Results = value; + return; + } + + throw new NotSupportedException("WebNavigator must be of type IResultWebNavigator to support Results"); + } + } + + /// + /// A convenience, case-insensitive table that may be used to e.g. pass data into SpEL expressions"/>. + /// + /// + /// By default, e.g. passes the control instance into an expression. Using + /// is an easy way to pass additional parameters into the expression + /// + /// This example shows how to pass an arbitrary value 'age' into a result expression. + /// + /// // config: + /// + /// <property Name="Results"> + /// <dictionary> + /// <entry key="ok_clicked" value="redirect:~/ShowResult.aspx?age=%{Args['age']}" /> + /// </dictionary> + /// </property> + /// + /// // code: + /// + /// void OnOkClicked(object sender, EventArgs e) + /// { + /// Args["result"] = txtAge.Text; + /// SetResult("ok_clicked"); + /// } + /// + /// + /// + public IDictionary Args + { + get + { + if (args == null) + { + args = new CaseInsensitiveHashtable(); + } + + return args; + } + } + + /// + /// Redirects user to a URL mapped to specified result name. + /// + /// Result name. + protected void SetResult(string resultName) + { + WebNavigator.NavigateTo(resultName, this, null); + } + + /// + /// Redirects user to a URL mapped to specified result name. + /// + /// Name of the result. + /// The context to use for evaluating the SpEL expression in the Result. + protected void SetResult(string resultName, object context) + { + WebNavigator.NavigateTo(resultName, this, context); + } + + /// + /// Returns a redirect url string that points to the + /// defined by this + /// result evaluated using this Page for expression + /// + /// Name of the result. + /// A redirect url string. + protected string GetResultUrl(string resultName) + { + return ResolveUrl(WebNavigator.GetResultUri(resultName, this, null)); + } + + /// + /// Returns a redirect url string that points to the + /// defined by this + /// result evaluated using this Page for expression + /// + /// Name of the result. + /// The context to use for evaluating the SpEL expression in the Result + /// A redirect url string. + protected string GetResultUrl(string resultName, object context) + { + return ResolveUrl(WebNavigator.GetResultUri(resultName, this, context)); + } + + #endregion + + #region Validation support + + /// + ///Instructs any validation controls included on the page to validate their assigned information. + /// + /// + public new virtual void Validate() + { + base.Validate(); + } + + /// + ///Instructs the validation controls in the specified validation group to validate their assigned information. + /// + /// + ///The validation group name of the controls to validate. + public new virtual void Validate(string validationGroup) + { + base.Validate(validationGroup); + } + + /// + /// Evaluates specified validators and returns True if all of them are valid. /// /// ///

- /// The Page class is associated with files that have an .aspx extension. - /// These files are compiled at run time as Page objects and cached in server memory. + /// Each validator can itself represent a collection of other validators if it is + /// an instance of or one of its derived types. ///

///

- /// This class extends and adds support for master - /// pages similar to upcoming ASP.Net 2.0 master pages feature. - ///

- ///

- /// It also adds support for automatic localization using local page resource file, and - /// simplifies access to global resources (resources from the message source for the - /// application context). + /// Please see the Validation Framework section in the documentation for more info. ///

///
- /// Aleksandar Seovic - [AspNetHostingPermission( SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal )] - [AspNetHostingPermission( SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal )] - public class Page : System.Web.UI.Page, IHttpHandler, IApplicationContextAware, ISharedStateAware, - ISupportsWebDependencyInjection, IWebDataBound, IValidationContainer, IWebNavigable + /// Object to validate. + /// Validators to evaluate. + /// + /// True if all of the specified validators are valid, False otherwise. + /// + public bool Validate(object validationContext, params IValidator[] validators) { - #region Constants - - private static readonly object EventInitializeControls = new object(); - private static readonly object EventPreLoadViewState = new object(); - private static readonly object EventDataBindingsInitialized = new object(); - private static readonly object EventDataBound = new object(); - private static readonly object EventDataUnbound = new object(); - - #endregion - - #region Instance Fields - - private object controller; - private IDictionary sharedState; - - private ILocalizer localizer; - private ICultureResolver cultureResolver = new DefaultWebCultureResolver(); - private IMessageSource messageSource; - private IBindingContainer bindingManager; - private IValidationErrors validationErrors = new ValidationErrors(); - private IWebNavigator webNavigator; - private IDictionary args; - private IApplicationContext applicationContext; - private IApplicationContext defaultApplicationContext; - private static readonly string traceCategory = "Spring.Page"; - - private IDictionary styles = new ListDictionary(); - private IDictionary styleFiles = new ListDictionary(); - private IDictionary headScripts = new ListDictionary(); - private string cssRoot = "CSS"; - private string scriptsRoot = "Scripts"; - private string imagesRoot = "Images"; - - #endregion - - #region Page lifecycle methods - - /// - /// Creates and initializes the new page instance. - /// - /// - /// Calls . - /// - public Page() + IDictionary contextParams = CreateValidatorParameters(); + bool result = true; + foreach (IValidator validator in validators) { - InitializeNavigationSupport(); - } - - /// - /// Initializes Spring.NET page internals and raises the PreInit event. - /// - /// The instance containing the event data. - protected override void OnPreInit( EventArgs e ) - { - if (SharedState == null) + if (validator == null) { - SharedState = new CaseInsensitiveHashtable(); - } - InitializeCulture(); - InitializeMessageSource(); - - base.OnPreInit( e ); - } - - /// - /// Initializes the culture. - /// - protected override void InitializeCulture() - { - CultureInfo userCulture = this.UserCulture; - Thread.CurrentThread.CurrentUICulture = userCulture; - if (userCulture.IsNeutralCulture) - { - Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture( userCulture.Name ); - } - else - { - Thread.CurrentThread.CurrentCulture = userCulture; - } - } - - /// - /// Initializes data model and controls. - /// - protected override void OnInit( EventArgs e ) - { - InitializeBindingManager(); - - if (!IsPostBack) - { - InitializeModel(); - } - else - { - LoadModel( LoadModelFromPersistenceMedium() ); + throw new ArgumentException("Validator is not defined."); } - base.OnInit( e ); - - // initialize controls - Trace.Write( traceCategory, "Initialize Controls" ); - OnInitializeControls( EventArgs.Empty ); + result = validator.Validate(validationContext, contextParams, this.ValidationErrors) && result; } - /// - /// Raises the event after page initialization. - /// - protected virtual void OnPreLoadViewState( EventArgs e ) + return result; + } + + /// + /// Gets or sets the validation errors container. + /// + /// The validation errors container. + public virtual IValidationErrors ValidationErrors + { + get { return validationErrors; } + set { - EventHandler handler = (EventHandler)base.Events[EventPreLoadViewState]; - if (handler != null) + AssertUtils.ArgumentNotNull(value, "ValidationErrors"); + validationErrors = value; + } + } + + /// + /// Creates the validator parameters. + /// + /// + /// + /// This method can be overriden if you want to pass additional parameters + /// to the validation framework, but you should make sure that you call + /// this base implementation in order to add page, session, application, + /// request, response and context to the variables collection. + /// + /// + /// + /// Dictionary containing parameters that should be passed to + /// the data validation framework. + /// + protected virtual IDictionary CreateValidatorParameters() + { + IDictionary parameters = new Dictionary(); + parameters["page"] = this; + parameters["session"] = this.Session; + parameters["application"] = this.Application; + parameters["request"] = this.Request; + parameters["response"] = this.Response; + parameters["context"] = this.Context; + + return parameters; + } + + #endregion + + #region Data binding support + + /// + /// Initializes the data bindings. + /// + protected virtual void InitializeDataBindings() + { + } + + /// + /// Returns the key to be used for looking up a cached + /// BindingManager instance in . + /// + /// a unique key identifying the instance in the dictionary. + protected virtual string GetBindingManagerKey() + { + return CreateSharedStateKey("DataBindingManager"); + } + + /// + /// Creates a new instance. + /// + /// + /// This factory method is called if no could be found in + /// using the key returned by .
+ ///
+ /// + ///
+ /// a instance to be used for DataBinding + protected virtual IBindingContainer CreateBindingManager() + { + return new BaseBindingManager(); + } + + /// + /// Expose BindingManager via IDataBound interface + /// + IBindingContainer IDataBound.BindingManager + { + get { return this.BindingManager; } + } + + /// + /// Gets the binding manager. + /// + /// The binding manager. + protected IBindingContainer BindingManager + { + get { return this.bindingManager; } + } + + /// + /// Initializes binding manager and data bindings if necessary. + /// + private void InitializeBindingManager() + { + IDictionary sharedState = this.SharedState; + + string key = GetBindingManagerKey(); + this.bindingManager = sharedState[key] as BaseBindingManager; + if (this.bindingManager == null) + { + // access to shared state must be synchronized + lock (this.SharedState.SyncRoot) { - handler( this, e ); - } - } - - /// - /// PreLoadViewState event. - /// - /// - /// - /// This event is raised if is true - /// immediately before state is restored from ViewState. - /// - /// - /// NOTE: Different from , this event - /// will also be raised if the control has no ViewState or ViewState is disabled. - /// - /// - public event EventHandler PreLoadViewState - { - add { base.Events.AddHandler( EventPreLoadViewState, value ); } - remove { base.Events.RemoveHandler( EventPreLoadViewState, value ); } - } - - /// - /// Raises the PreLoadViewState event for - /// this page and all contained controls. - /// - private void RaisePreLoadViewStateEvent() - { - this.OnPreLoadViewState( EventArgs.Empty ); - if (this.HasControls()) - { - PreLoadViewStateRecursive( this.Controls ); - } - } - - /// - /// Recursively raises PreLoadViewState event. - /// - private void PreLoadViewStateRecursive( ControlCollection controls ) - { - for (int i = 0; i < controls.Count; i++) - { - Control control = controls[i]; - - if (control is UserControl) + this.bindingManager = sharedState[key] as BaseBindingManager; + if (this.bindingManager == null) { - ((UserControl)control).OnPreLoadViewState( EventArgs.Empty ); - } - - if (control.HasControls()) - { - PreLoadViewStateRecursive( control.Controls ); - } - } - } - - /// - /// Overridden to add support for - /// - /// - /// If necessary override instead of this method. - /// - protected override object LoadPageStateFromPersistenceMedium() - { - RaisePreLoadViewStateEvent(); - - // If ViewState is disabled, use BindFormData() to populate controls. - BindFormDataIfNecessary(); - - // continue with default behaviour - return LoadPageStateFromPersistenceMediumBase(); - } - - /// - /// If ViewState is disabled, calls recursively for all controls. - /// - /// - /// If ViewState is disabled, DropDownLists etc. might not fire "Changed" events. - /// - protected virtual void BindFormDataIfNecessary() - { - if (!IsViewStateEnabled) - { - BindFormDataRecursive(); - } - } - - /// - /// Calls recursively for all controls. - /// - protected void BindFormDataRecursive() - { - this.BindFormData(); - if (this.HasControls()) - { - BindFormDataRecursive( this.Controls ); - } - } - - /// - /// Recursively calls for all controls. - /// - private void BindFormDataRecursive( ControlCollection controls ) - { - for (int i = 0; i < controls.Count; i++) - { - Control control = controls[i]; - - if (control is UserControl) - { - ((UserControl)control).BindFormData(); - } - - if (control.HasControls()) - { - BindFormDataRecursive( control.Controls ); - } - } - } - - /// - /// If necessary override this method instead of - /// - protected virtual object LoadPageStateFromPersistenceMediumBase() - { - return base.LoadPageStateFromPersistenceMedium(); - } - - /// - /// Initializes dialog result and unbinds data from the controls - /// into a data model. - /// - /// Event arguments. - protected override void OnLoad( EventArgs e ) - { - // create dialog result if necessary - // if (GetType().IsDefined(typeof(DialogAttribute), true)) - // { - // if (!IsPostBack) - // { - // ViewState["__dialogResult"] = "redirect:" + Request.UrlReferrer.AbsoluteUri; - // } - // Results["close"] = new Result((string) ViewState["__dialogResult"]); - // } - - if (IsPostBack) - { - // unbind form data - UnbindFormData(); - } - - - Trace.Write( traceCategory, "Execute Handlers for Load Event" ); - base.OnLoad( e ); - } - - /// - /// Binds data from the data model into controls and raises - /// PreRender event afterwards. - /// - /// Event arguments. - protected override void OnPreRender( EventArgs e ) - { - // bind data from model to form - BindFormData(); - - if (localizer != null) - { - Trace.Write( traceCategory, "Apply Localized Resources" ); - localizer.ApplyResources( this, messageSource, UserCulture ); - } - - base.OnPreRender( e ); - - object modelToSave = SaveModel(); - if (modelToSave != null) - { - SaveModelToPersistenceMedium( modelToSave ); - } - } - - /// - /// This event is raised before Init event and should be used to initialize - /// controls as necessary. - /// - public event EventHandler InitializeControls - { - add { base.Events.AddHandler( EventInitializeControls, value ); } - remove { base.Events.RemoveHandler( EventInitializeControls, value ); } - } - - /// - /// Raises InitializeControls event. - /// - /// Event arguments. - protected virtual void OnInitializeControls( EventArgs e ) - { - EventHandler handler = (EventHandler)base.Events[EventInitializeControls]; - if (handler != null) - { - handler( this, e ); - } - } - - /// - /// Obtains a object from a user control file - /// and injects dependencies according to Spring config file. - /// - /// The virtual path to a user control file. - /// - /// Returns the specified object, with dependencies injected. - /// - protected virtual new Control LoadControl( string virtualPath ) - { - Control control = base.LoadControl( virtualPath ); - control = WebDependencyInjectionUtils.InjectDependenciesRecursive( defaultApplicationContext, control ); - return control; - } - - /// - /// Obtains a object by type - /// and injects dependencies according to Spring config file. - /// - /// The type of a user control. - /// parameters to pass to the control - /// - /// Returns the specified object, with dependencies injected. - /// - protected virtual new Control LoadControl( Type t, params object[] parameters ) - { - Control control = base.LoadControl( t, parameters ); - control = WebDependencyInjectionUtils.InjectDependenciesRecursive( defaultApplicationContext, control ); - return control; - } - - #endregion - - #region Model Management Support - - private IModelPersistenceMedium modelPersistenceMedium = new SessionModelPersistenceMedium(); - - /// - /// Set the strategy for storing model - /// instances between requests. - /// - /// - /// By default the strategy is used. - /// - public IModelPersistenceMedium ModelPersistenceMedium - { - set - { - AssertUtils.ArgumentNotNull(value, "ModelPersistenceMedium"); - modelPersistenceMedium = value; - } - } - - /// - /// Retrieves data model from a persistence store. - /// - /// - /// The default implementation uses to store and retrieve - /// the model for the current - /// - protected virtual object LoadModelFromPersistenceMedium() - { - //return Session[Request.CurrentExecutionFilePath + ".Model"]; - return modelPersistenceMedium.LoadFromMedium(this); - } - - /// - /// Saves data model to a persistence store. - /// - /// - /// The default implementation uses to store and retrieve - /// the model for the current - /// - protected virtual void SaveModelToPersistenceMedium( object modelToSave ) - { - //Session[Request.CurrentExecutionFilePath + ".Model"] = modelToSave; - modelPersistenceMedium.SaveToMedium(this, modelToSave); - } - - /// - /// Initializes data model when the page is first loaded. - /// - /// - /// This method should be overriden by the developer - /// in order to initialize data model for the page. - /// - protected virtual void InitializeModel() - { - } - - /// - /// Loads the saved data model on postback. - /// - /// - /// This method should be overriden by the developer - /// in order to load data model for the page. - /// - protected virtual void LoadModel( object savedModel ) - { - } - - /// - /// Returns a model object that should be saved. - /// - /// - /// This method should be overriden by the developer - /// in order to save data model for the page. - /// - /// - /// A model object that should be saved. - /// - protected virtual object SaveModel() - { - return null; - } - - #endregion - - #region Process and Controller support - - /// - /// Gets or sets controller for the page. - /// - /// - /// - /// Application pages should shadow this property and change its type - /// in order to make calls to controller within the page as simple as possible. - /// - /// - /// If external controller is not specified, page will serve as its own controller, - /// which will allow data binding to work properly. - /// - /// - /// Controller for the page. Defaults to the page itself. - public object Controller - { - get { return GetController(); } - set { SetController( value ); } - } - - /// - /// Stores the controller to be returned by property. - /// - /// - /// The default implementation uses a field to store the reference. Derived classes may override this behaviour - /// but must ensure to also change the behaviour of accordingly. - /// - /// Controller for the page. - protected virtual void SetController( object controller ) - { - this.controller = controller; - } - - /// - /// Returns the controller stored by . - /// - /// - /// The default implementation uses a field to retrieve the reference. Derived classes may override this behaviour - /// but must ensure to also change the behaviour of accordingly. - /// - /// - /// The controller for this page. - /// - /// If no controller is set, a reference to the page itself is returned. - /// - /// - protected virtual object GetController() - { - if (controller == null) - { - return this; - } - return controller; - } - - #endregion - - #region Shared State support - - /// - /// Returns a thread-safe dictionary that contains state that is shared by - /// all instances of this page. - /// - [Browsable( false )] - [DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden )] - public IDictionary SharedState - { - get { return this.sharedState; } - set { this.sharedState = value; } - } - - #endregion - - /// - /// Overrides the default PreviousPage property to return an instance of , - /// and to work properly during server-side transfers and executes. - /// - public new Page PreviousPage - { - get { return this.Context.PreviousHandler as Page; } - } - - /// - /// Publish associated with this page for convenient usage in Binding Expressions - /// - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public new virtual HttpContext Context - { - get { - return base.Context; } - } - - #region Master Page support - - /// - /// Gets the master page that determines the overall look of the page. - /// - [Browsable( false )] - [DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden )] - public new MasterPage Master - { - get { return (MasterPage)base.Master; } - } - - /// - /// Returns true if page uses master page, false otherwise. - /// - [Browsable( false )] - [DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden )] - public bool HasMaster - { - get { return Master != null || MasterPageFile != null; } - } - - #endregion - - #region CSS support - - /// - /// Gets a dictionary of registered styles. - /// - /// Registered styles. - [Browsable( false )] - [DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden )] - public IDictionary Styles - { - get { return styles; } - } - - /// - /// Gets a dictionary of registered style files. - /// - /// Registered style files. - [Browsable( false )] - [DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden )] - public IDictionary StyleFiles - { - get { return styleFiles; } - } - - /// - /// Registers single CSS style with the page. - /// - /// Style name. - /// Style definition. - public void RegisterStyle( string name, string style ) - { - styles[name] = style; - } - - /// - /// Returns True if specified style is registered, False otherwise. - /// - /// Style name. - /// True if specified style is registered, False otherwise. - public bool IsStyleRegistered( string name ) - { - return styles.Contains( name ); - } - - /// - /// Registers CSS file with the page. - /// - /// Style file key. - /// Style file name. - public void RegisterStyleFile( string key, string fileName ) - { - styleFiles[key] = fileName; - } - - /// - /// Returns True if specified style file is registered, False otherwise. - /// - /// Style file key. - /// True if specified style file is registered, False otherwise. - public bool IsStyleFileRegistered( string key ) - { - return styleFiles.Contains( key ); - } - - #endregion - - #region Client script support - - /// - /// Gets a dictionary of registered head scripts. - /// - /// Registered head scripts. - [Browsable( false )] - [DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden )] - public IDictionary HeadScripts - { - get { return headScripts; } - } - - /// - /// Registers script block that should be rendered within the head HTML element. - /// - /// Script key. - /// Script text. - public void RegisterHeadScriptBlock( string key, string script ) - { - RegisterHeadScriptBlock( key, Script.DefaultType, script ); - } - - /// - /// Registers script block that should be rendered within the head HTML element. - /// - /// Script key. - /// Script language MIME type. - /// Script text. - public void RegisterHeadScriptBlock( string key, MimeMediaType type, string script ) - { - headScripts[key] = new ScriptBlock( type, script ); - } - - /// - /// Registers script file that should be referenced within the head HTML element. - /// - /// Script key. - /// Script file name. - public void RegisterHeadScriptFile( string key, string fileName ) - { - RegisterHeadScriptFile( key, Script.DefaultType, fileName ); - } - - /// - /// Registers script file that should be referenced within the head HTML element. - /// - /// Script key. - /// Script language MIME type. - /// Script file name. - public void RegisterHeadScriptFile( string key, MimeMediaType type, string fileName ) - { - headScripts[key] = new ScriptFile( type, fileName ); - } - - /// - /// Registers script block that should be rendered within the head HTML element. - /// - /// Script key. - /// Element ID of the event source. - /// Name of the event to handle. - /// Script text. - public void RegisterHeadScriptEvent( string key, string element, string eventName, string script ) - { - RegisterHeadScriptEvent( key, Script.DefaultType, element, eventName, script ); - } - - /// - /// Registers script block that should be rendered within the head HTML element. - /// - /// Script key. - /// The scripting language's MIME type. - /// Element ID of the event source. - /// Name of the event to handle. - /// Script text. - public void RegisterHeadScriptEvent( string key, MimeMediaType mimeType, string element, string eventName, string script ) - { - headScripts[key] = new ScriptEvent( mimeType, element, eventName, script ); - } - - /// - /// Returns True if specified head script is registered, False otherwise. - /// - /// Script key. - /// True if specified head script is registered, False otherwise. - public bool IsHeadScriptRegistered( string key ) - { - return headScripts.Contains( key ); - } - - #endregion - - #region Well-known folders support - - /// - /// Gets or sets the CSS root. - /// - /// The CSS root. - [Browsable( false )] - [DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden )] - public string CssRoot - { - get { return WebUtils.CreateAbsolutePath( Request.ApplicationPath, cssRoot ); } - set { cssRoot = value; } - } - - /// - /// Gets or sets the scripts root. - /// - /// The scripts root. - [Browsable( false )] - [DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden )] - public string ScriptsRoot - { - get { return WebUtils.CreateAbsolutePath( Request.ApplicationPath, scriptsRoot ); } - set { scriptsRoot = value; } - } - - /// - /// Gets or sets the images root. - /// - /// The images root. - [Browsable( false )] - [DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden )] - public string ImagesRoot - { - get { return WebUtils.CreateAbsolutePath( Request.ApplicationPath, imagesRoot ); } - set { imagesRoot = value; } - } - - #endregion - - #region Result support - - /// - /// Ensure, that is set to a valid instance. - /// - /// - /// If is not already set, creates and sets a new instance.
- /// Override this method if you don't want to inject a navigator, but need a different default. - ///
- protected virtual void InitializeNavigationSupport() - { - webNavigator = new WebFormsResultWebNavigator( this, null, null, true ); - } - - /// - /// Gets/Sets the navigator to be used for handling calls. - /// - public virtual IWebNavigator WebNavigator - { - get - { - return webNavigator; - } - set - { - webNavigator = value; - } - } - - /// - /// Gets or sets map of result names to target URLs - /// - /// - /// Using requires to implement . - /// - [Browsable( false )] - [DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden )] - public virtual IDictionary Results - { - get - { - if (WebNavigator is IResultWebNavigator) - { - return ((IResultWebNavigator)WebNavigator).Results; - } - return null; - } - set - { - if (WebNavigator is IResultWebNavigator) - { - ((IResultWebNavigator)WebNavigator).Results = value; - return; - } - throw new NotSupportedException( "WebNavigator must be of type IResultWebNavigator to support Results" ); - } - } - - /// - /// A convenience, case-insensitive table that may be used to e.g. pass data into SpEL expressions"/>. - /// - /// - /// By default, e.g. passes the control instance into an expression. Using - /// is an easy way to pass additional parameters into the expression - /// - /// This example shows how to pass an arbitrary value 'age' into a result expression. - /// - /// // config: - /// - /// <property Name="Results"> - /// <dictionary> - /// <entry key="ok_clicked" value="redirect:~/ShowResult.aspx?age=%{Args['age']}" /> - /// </dictionary> - /// </property> - /// - /// // code: - /// - /// void OnOkClicked(object sender, EventArgs e) - /// { - /// Args["result"] = txtAge.Text; - /// SetResult("ok_clicked"); - /// } - /// - /// - /// - public IDictionary Args - { - get - { - if (args == null) - { - args = new CaseInsensitiveHashtable(); - } - return args; - } - } - - /// - /// Redirects user to a URL mapped to specified result name. - /// - /// Result name. - protected void SetResult( string resultName ) - { - WebNavigator.NavigateTo( resultName, this, null ); - } - - /// - /// Redirects user to a URL mapped to specified result name. - /// - /// Name of the result. - /// The context to use for evaluating the SpEL expression in the Result. - protected void SetResult( string resultName, object context ) - { - WebNavigator.NavigateTo( resultName, this, context ); - } - - /// - /// Returns a redirect url string that points to the - /// defined by this - /// result evaluated using this Page for expression - /// - /// Name of the result. - /// A redirect url string. - protected string GetResultUrl( string resultName ) - { - return ResolveUrl( WebNavigator.GetResultUri( resultName, this, null ) ); - } - - /// - /// Returns a redirect url string that points to the - /// defined by this - /// result evaluated using this Page for expression - /// - /// Name of the result. - /// The context to use for evaluating the SpEL expression in the Result - /// A redirect url string. - protected string GetResultUrl( string resultName, object context ) - { - return ResolveUrl( WebNavigator.GetResultUri( resultName, this, context ) ); - } - - #endregion - - #region Validation support - - /// - ///Instructs any validation controls included on the page to validate their assigned information. - /// - /// - public new virtual void Validate() - { - base.Validate(); - } - - /// - ///Instructs the validation controls in the specified validation group to validate their assigned information. - /// - /// - ///The validation group name of the controls to validate. - public new virtual void Validate(string validationGroup) - { - base.Validate(validationGroup); - } - - /// - /// Evaluates specified validators and returns True if all of them are valid. - /// - /// - ///

- /// Each validator can itself represent a collection of other validators if it is - /// an instance of or one of its derived types. - ///

- ///

- /// Please see the Validation Framework section in the documentation for more info. - ///

- ///
- /// Object to validate. - /// Validators to evaluate. - /// - /// True if all of the specified validators are valid, False otherwise. - /// - public bool Validate( object validationContext, params IValidator[] validators ) - { - IDictionary contextParams = CreateValidatorParameters(); - bool result = true; - foreach (IValidator validator in validators) - { - if (validator == null) - { - throw new ArgumentException( "Validator is not defined." ); - } - result = validator.Validate( validationContext, contextParams, this.ValidationErrors ) && result; - } - - return result; - } - - /// - /// Gets or sets the validation errors container. - /// - /// The validation errors container. - public virtual IValidationErrors ValidationErrors - { - get { return validationErrors; } - set - { - AssertUtils.ArgumentNotNull(value, "ValidationErrors"); - validationErrors = value; - } - } - - /// - /// Creates the validator parameters. - /// - /// - /// - /// This method can be overriden if you want to pass additional parameters - /// to the validation framework, but you should make sure that you call - /// this base implementation in order to add page, session, application, - /// request, response and context to the variables collection. - /// - /// - /// - /// Dictionary containing parameters that should be passed to - /// the data validation framework. - /// - protected virtual IDictionary CreateValidatorParameters() - { - IDictionary parameters = new Dictionary(); - parameters["page"] = this; - parameters["session"] = this.Session; - parameters["application"] = this.Application; - parameters["request"] = this.Request; - parameters["response"] = this.Response; - parameters["context"] = this.Context; - - return parameters; - } - - #endregion - - #region Data binding support - - /// - /// Initializes the data bindings. - /// - protected virtual void InitializeDataBindings() - { - } - - /// - /// Returns the key to be used for looking up a cached - /// BindingManager instance in . - /// - /// a unique key identifying the instance in the dictionary. - protected virtual string GetBindingManagerKey() - { - return CreateSharedStateKey( "DataBindingManager" ); - } - - /// - /// Creates a new instance. - /// - /// - /// This factory method is called if no could be found in - /// using the key returned by .
- ///
- /// - ///
- /// a instance to be used for DataBinding - protected virtual IBindingContainer CreateBindingManager() - { - return new BaseBindingManager(); - } - - /// - /// Expose BindingManager via IDataBound interface - /// - IBindingContainer IDataBound.BindingManager - { - get { return this.BindingManager; } - } - - /// - /// Gets the binding manager. - /// - /// The binding manager. - protected IBindingContainer BindingManager - { - get { return this.bindingManager; } - } - - /// - /// Initializes binding manager and data bindings if necessary. - /// - private void InitializeBindingManager() - { - IDictionary sharedState = this.SharedState; - - string key = GetBindingManagerKey(); - this.bindingManager = sharedState[key] as BaseBindingManager; - if (this.bindingManager == null) - { - // access to shared state must be synchronized - lock (this.SharedState.SyncRoot) - { - this.bindingManager = sharedState[key] as BaseBindingManager; + Trace.Write(traceCategory, "Initialize Data Bindings"); + this.bindingManager = CreateBindingManager(); if (this.bindingManager == null) { - Trace.Write( traceCategory, "Initialize Data Bindings" ); - this.bindingManager = CreateBindingManager(); - if (this.bindingManager == null) - { - throw new ArgumentNullException( "bindingManager", - "CreateBindingManager() must not return null" ); - } - InitializeDataBindings(); - sharedState[key] = this.bindingManager; - OnDataBindingsInitialized( EventArgs.Empty ); + throw new ArgumentNullException("bindingManager", + "CreateBindingManager() must not return null"); } + + InitializeDataBindings(); + sharedState[key] = this.bindingManager; + OnDataBindingsInitialized(EventArgs.Empty); } } } - - /// - /// Raises the event. - /// - protected virtual void OnDataBindingsInitialized( EventArgs e ) - { - EventHandler handler = (EventHandler)base.Events[EventDataBindingsInitialized]; - - if (handler != null) - { - handler( this, e ); - } - } - - /// - /// This event is raised after as been initialized. - /// - public event EventHandler DataBindingsInitialized - { - add - { - base.Events.AddHandler( EventDataBindingsInitialized, value ); - } - remove - { - base.Events.RemoveHandler( EventDataBindingsInitialized, value ); - } - } - - /// - /// Bind data from model to form. - /// - protected virtual void BindFormData() - { - if (BindingManager.HasBindings) - { - Trace.Write( traceCategory, "Bind Data Model onto Controls" ); - - BindingManager.BindTargetToSource( this, Controller, ValidationErrors ); - } - OnDataBound( EventArgs.Empty ); - } - - /// - /// Unbind data from form to model. - /// - protected virtual void UnbindFormData() - { - if (BindingManager.HasBindings) - { - Trace.Write( traceCategory, "Unbind Controls into Data Model" ); - - BindingManager.BindSourceToTarget( this, Controller, ValidationErrors ); - } - OnDataUnbound( EventArgs.Empty ); - } - - /// - /// This event is raised after all controls have been populated with values - /// from the data model. - /// - public event EventHandler DataBound - { - add { base.Events.AddHandler( EventDataBound, value ); } - remove { base.Events.RemoveHandler( EventDataBound, value ); } - } - - /// - /// Raises DataBound event. - /// - /// Event arguments. - protected virtual void OnDataBound( EventArgs e ) - { - EventHandler handler = (EventHandler)base.Events[EventDataBound]; - if (handler != null) - { - handler( this, e ); - } - } - - /// - /// This event is raised after data model has been populated with values from - /// web controls. - /// - public event EventHandler DataUnbound - { - add { base.Events.AddHandler( EventDataUnbound, value ); } - remove { base.Events.RemoveHandler( EventDataUnbound, value ); } - } - - /// - /// Raises DataBound event. - /// - /// Event arguments. - protected virtual void OnDataUnbound( EventArgs e ) - { - EventHandler handler = (EventHandler)base.Events[EventDataUnbound]; - if (handler != null) - { - handler( this, e ); - } - } - - #endregion - - #region Application context support - - /// - /// Gets or sets the that this - /// object runs in. - /// - /// - /// - ///

- /// Normally this call will be used to initialize the object. - ///

- ///

- /// Invoked after population of normal object properties but before an - /// init callback such as - /// 's - /// - /// or a custom init-method. Invoked after the setting of any - /// 's - /// - /// property. - ///

- ///
- /// - /// In the case of application context initialization errors. - /// - /// - /// If thrown by any application context methods. - /// - /// - [Browsable( false )] - [DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden )] - public virtual IApplicationContext ApplicationContext - { - get { return applicationContext; } - set { applicationContext = value; } - } - - #endregion - - #region Message source and localization support - - /// - /// Gets or sets the localizer. - /// - /// The localizer. - [Browsable( false )] - [DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden )] - public ILocalizer Localizer - { - get { return this.localizer; } - set - { - this.localizer = value; - if (this.localizer.ResourceCache is NullResourceCache) - { - this.localizer.ResourceCache = new SharedStateResourceCache( this ); - } - } - } - - /// - /// Gets or sets the culture resolver. - /// - /// The culture resolver. - [Browsable( false )] - [DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden )] - public ICultureResolver CultureResolver - { - get - { - // if (cultureResolver == null) - // { - // cultureResolver = new DefaultWebCultureResolver(); - // } - return cultureResolver; - } - set { cultureResolver = value; } - } - - /// - /// Gets or sets the local message source. - /// - /// The local message source. - [Browsable( false )] - [DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden )] - public IMessageSource MessageSource - { - get { return messageSource; } - set - { - messageSource = value; - if (messageSource != null && messageSource is AbstractMessageSource) - { - ((AbstractMessageSource)messageSource).ParentMessageSource = applicationContext; - } - } - } - - /// - /// Initializes local message source - /// - private void InitializeMessageSource() - { - if (MessageSource == null) - { - string MessageSourceKey = CreateSharedStateKey( "MessageSource" ); - if (this.SharedState[MessageSourceKey] == null) - { - lock (this.SharedState.SyncRoot) - { - if (this.SharedState[MessageSourceKey] == null) - { - ResourceSetMessageSource defaultMessageSource = new ResourceSetMessageSource(); - defaultMessageSource.UseCodeAsDefaultMessage = true; - ResourceManager rm = GetLocalResourceManager(); - if (rm != null) - { - defaultMessageSource.ResourceManagers.Add( rm ); - } - this.SharedState[MessageSourceKey] = defaultMessageSource; - } - } - } - - MessageSource = (IMessageSource)this.SharedState[MessageSourceKey]; - } - } - - /// - /// Creates and returns local ResourceManager for this page. - /// - /// - /// - /// In ASP.NET 1.1, this method loads local resources from the web application assembly. - /// - /// - /// However, in ASP.NET 2.0, local resources are compiled into a dynamic assembly, - /// so we need to find that assembly and load the resources from it. - /// - /// - /// Local ResourceManager instance. - private ResourceManager GetLocalResourceManager() - { - return LocalResourceManager.GetLocalResourceManager(this); - } - - /// - /// Returns message for the specified resource name. - /// - /// Resource name. - /// Message text. - public string GetMessage( string name ) - { - return messageSource.GetMessage( name, UserCulture ); - } - - /// - /// Returns message for the specified resource name. - /// - /// Resource name. - /// Message arguments that will be used to format return value. - /// Formatted message text. - public string GetMessage( string name, params object[] args ) - { - return messageSource.GetMessage( name, UserCulture, args ); - } - - /// - /// Returns resource object for the specified resource name. - /// - /// Resource name. - /// Resource object. - public object GetResourceObject( string name ) - { - return messageSource.GetResourceObject( name, UserCulture ); - } - - /// - /// Gets or sets user's culture - /// - [Browsable( false )] - [DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden )] - public virtual CultureInfo UserCulture - { - get { return CultureResolver.ResolveCulture(); } - set - { - CultureResolver.SetCulture( value ); - Thread.CurrentThread.CurrentUICulture = value; - if (value.IsNeutralCulture) - { - Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture( value.Name ); - } - else - { - Thread.CurrentThread.CurrentCulture = value; - } - OnUserCultureChanged( EventArgs.Empty ); - } - } - - /// - /// This event is raised when the value of UserLocale property changes. - /// - public event EventHandler UserCultureChanged; - - /// - /// Raises UserLocaleChanged event. - /// - /// Event arguments. - protected virtual void OnUserCultureChanged( EventArgs e ) - { - if (UserCultureChanged != null) - { - UserCultureChanged( this, e ); - } - } - - #endregion - - #region Helper methods - - /// - /// Creates a key for shared state, taking into account whether - /// this page belongs to a process or not. - /// - /// Key suffix - /// Generated unique shared state key. - protected virtual string CreateSharedStateKey( string key ) - { - return key; - } - - #endregion - - #region Dependency Injection Support - - /// - /// Holds default ApplicationContext instance to be used during DI. - /// - IApplicationContext ISupportsWebDependencyInjection.DefaultApplicationContext - { - get { return defaultApplicationContext; } - set { defaultApplicationContext = value; } - } - - /// - /// Injects dependencies into control before adding it. - /// - protected override void AddedControl( Control control, int index ) - { - control = WebDependencyInjectionUtils.InjectDependenciesRecursive( defaultApplicationContext, control ); - base.AddedControl( control, index ); - } - - #endregion Dependency Injection Support - } -} + + /// + /// Raises the event. + /// + protected virtual void OnDataBindingsInitialized(EventArgs e) + { + EventHandler handler = (EventHandler) base.Events[EventDataBindingsInitialized]; + + if (handler != null) + { + handler(this, e); + } + } + + /// + /// This event is raised after as been initialized. + /// + public event EventHandler DataBindingsInitialized + { + add + { + base.Events.AddHandler(EventDataBindingsInitialized, value); + } + remove + { + base.Events.RemoveHandler(EventDataBindingsInitialized, value); + } + } + + /// + /// Bind data from model to form. + /// + protected virtual void BindFormData() + { + if (BindingManager.HasBindings) + { + Trace.Write(traceCategory, "Bind Data Model onto Controls"); + + BindingManager.BindTargetToSource(this, Controller, ValidationErrors); + } + + OnDataBound(EventArgs.Empty); + } + + /// + /// Unbind data from form to model. + /// + protected virtual void UnbindFormData() + { + if (BindingManager.HasBindings) + { + Trace.Write(traceCategory, "Unbind Controls into Data Model"); + + BindingManager.BindSourceToTarget(this, Controller, ValidationErrors); + } + + OnDataUnbound(EventArgs.Empty); + } + + /// + /// This event is raised after all controls have been populated with values + /// from the data model. + /// + public event EventHandler DataBound + { + add { base.Events.AddHandler(EventDataBound, value); } + remove { base.Events.RemoveHandler(EventDataBound, value); } + } + + /// + /// Raises DataBound event. + /// + /// Event arguments. + protected virtual void OnDataBound(EventArgs e) + { + EventHandler handler = (EventHandler) base.Events[EventDataBound]; + if (handler != null) + { + handler(this, e); + } + } + + /// + /// This event is raised after data model has been populated with values from + /// web controls. + /// + public event EventHandler DataUnbound + { + add { base.Events.AddHandler(EventDataUnbound, value); } + remove { base.Events.RemoveHandler(EventDataUnbound, value); } + } + + /// + /// Raises DataBound event. + /// + /// Event arguments. + protected virtual void OnDataUnbound(EventArgs e) + { + EventHandler handler = (EventHandler) base.Events[EventDataUnbound]; + if (handler != null) + { + handler(this, e); + } + } + + #endregion + + #region Application context support + + /// + /// Gets or sets the that this + /// object runs in. + /// + /// + /// + ///

+ /// Normally this call will be used to initialize the object. + ///

+ ///

+ /// Invoked after population of normal object properties but before an + /// init callback such as + /// 's + /// + /// or a custom init-method. Invoked after the setting of any + /// 's + /// + /// property. + ///

+ ///
+ /// + /// In the case of application context initialization errors. + /// + /// + /// If thrown by any application context methods. + /// + /// + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public virtual IApplicationContext ApplicationContext + { + get { return applicationContext; } + set { applicationContext = value; } + } + + #endregion + + #region Message source and localization support + + /// + /// Gets or sets the localizer. + /// + /// The localizer. + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public ILocalizer Localizer + { + get { return this.localizer; } + set + { + this.localizer = value; + if (this.localizer.ResourceCache is NullResourceCache) + { + this.localizer.ResourceCache = new SharedStateResourceCache(this); + } + } + } + + /// + /// Gets or sets the culture resolver. + /// + /// The culture resolver. + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public ICultureResolver CultureResolver + { + get + { + // if (cultureResolver == null) + // { + // cultureResolver = new DefaultWebCultureResolver(); + // } + return cultureResolver; + } + set { cultureResolver = value; } + } + + /// + /// Gets or sets the local message source. + /// + /// The local message source. + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public IMessageSource MessageSource + { + get { return messageSource; } + set + { + messageSource = value; + if (messageSource != null && messageSource is AbstractMessageSource) + { + ((AbstractMessageSource) messageSource).ParentMessageSource = applicationContext; + } + } + } + + /// + /// Initializes local message source + /// + private void InitializeMessageSource() + { + if (MessageSource == null) + { + string MessageSourceKey = CreateSharedStateKey("MessageSource"); + if (this.SharedState[MessageSourceKey] == null) + { + lock (this.SharedState.SyncRoot) + { + if (this.SharedState[MessageSourceKey] == null) + { + ResourceSetMessageSource defaultMessageSource = new ResourceSetMessageSource(); + defaultMessageSource.UseCodeAsDefaultMessage = true; + ResourceManager rm = GetLocalResourceManager(); + if (rm != null) + { + defaultMessageSource.ResourceManagers.Add(rm); + } + + this.SharedState[MessageSourceKey] = defaultMessageSource; + } + } + } + + MessageSource = (IMessageSource) this.SharedState[MessageSourceKey]; + } + } + + /// + /// Creates and returns local ResourceManager for this page. + /// + /// + /// + /// In ASP.NET 1.1, this method loads local resources from the web application assembly. + /// + /// + /// However, in ASP.NET 2.0, local resources are compiled into a dynamic assembly, + /// so we need to find that assembly and load the resources from it. + /// + /// + /// Local ResourceManager instance. + private ResourceManager GetLocalResourceManager() + { + return LocalResourceManager.GetLocalResourceManager(this); + } + + /// + /// Returns message for the specified resource name. + /// + /// Resource name. + /// Message text. + public string GetMessage(string name) + { + return messageSource.GetMessage(name, UserCulture); + } + + /// + /// Returns message for the specified resource name. + /// + /// Resource name. + /// Message arguments that will be used to format return value. + /// Formatted message text. + public string GetMessage(string name, params object[] args) + { + return messageSource.GetMessage(name, UserCulture, args); + } + + /// + /// Returns resource object for the specified resource name. + /// + /// Resource name. + /// Resource object. + public object GetResourceObject(string name) + { + return messageSource.GetResourceObject(name, UserCulture); + } + + /// + /// Gets or sets user's culture + /// + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public virtual CultureInfo UserCulture + { + get { return CultureResolver.ResolveCulture(); } + set + { + CultureResolver.SetCulture(value); + Thread.CurrentThread.CurrentUICulture = value; + if (value.IsNeutralCulture) + { + Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(value.Name); + } + else + { + Thread.CurrentThread.CurrentCulture = value; + } + + OnUserCultureChanged(EventArgs.Empty); + } + } + + /// + /// This event is raised when the value of UserLocale property changes. + /// + public event EventHandler UserCultureChanged; + + /// + /// Raises UserLocaleChanged event. + /// + /// Event arguments. + protected virtual void OnUserCultureChanged(EventArgs e) + { + if (UserCultureChanged != null) + { + UserCultureChanged(this, e); + } + } + + #endregion + + #region Helper methods + + /// + /// Creates a key for shared state, taking into account whether + /// this page belongs to a process or not. + /// + /// Key suffix + /// Generated unique shared state key. + protected virtual string CreateSharedStateKey(string key) + { + return key; + } + + #endregion + + #region Dependency Injection Support + + /// + /// Holds default ApplicationContext instance to be used during DI. + /// + IApplicationContext ISupportsWebDependencyInjection.DefaultApplicationContext + { + get { return defaultApplicationContext; } + set { defaultApplicationContext = value; } + } + + /// + /// Injects dependencies into control before adding it. + /// + protected override void AddedControl(Control control, int index) + { + control = WebDependencyInjectionUtils.InjectDependenciesRecursive(defaultApplicationContext, control); + base.AddedControl(control, index); + } + + #endregion Dependency Injection Support +} \ No newline at end of file diff --git a/src/Spring/Spring.Web/Web/UI/SessionModelPersistenceMedium.cs b/src/Spring/Spring.Web/Web/UI/SessionModelPersistenceMedium.cs index 2985137f..ca801a5b 100644 --- a/src/Spring/Spring.Web/Web/UI/SessionModelPersistenceMedium.cs +++ b/src/Spring/Spring.Web/Web/UI/SessionModelPersistenceMedium.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -25,67 +25,66 @@ using System.Web.UI; #endregion -namespace Spring.Web.UI +namespace Spring.Web.UI; + +/// +/// implements -based storage for +/// UI model management. +/// +/// Erich Eichinger +public class SessionModelPersistenceMedium : IModelPersistenceMedium { /// - /// implements -based storage for - /// UI model management. + /// Load the model for the specified control context. /// - /// Erich Eichinger - public class SessionModelPersistenceMedium : IModelPersistenceMedium + /// + /// The key used for loading the model from the session dictionary is obtained by calling + /// + /// the control context. + /// the model for the specified control context. + /// + public object LoadFromMedium(Control context) { - /// - /// Load the model for the specified control context. - /// - /// - /// The key used for loading the model from the session dictionary is obtained by calling - /// - /// the control context. - /// the model for the specified control context. - /// - public object LoadFromMedium(Control context) - { - return GetItem(context, GetKey(context)); - } + return GetItem(context, GetKey(context)); + } - /// - /// Save the specified model object to session. - /// - /// - /// The key used for storing the model into the session dictionary is obtained by calling - /// - /// the control context. - /// the model to save. - /// - public void SaveToMedium(Control context, object modelToSave) - { - SetItem(context, GetKey(context), modelToSave); - } + /// + /// Save the specified model object to session. + /// + /// + /// The key used for storing the model into the session dictionary is obtained by calling + /// + /// the control context. + /// the model to save. + /// + public void SaveToMedium(Control context, object modelToSave) + { + SetItem(context, GetKey(context), modelToSave); + } - /// - /// Create the key to be used for accessing the dictionary. - /// - /// - /// - protected virtual string GetKey(Control context) - { - return context.Page.Request.CurrentExecutionFilePath + context.UniqueID + ".Model"; - } + /// + /// Create the key to be used for accessing the dictionary. + /// + /// + /// + protected virtual string GetKey(Control context) + { + return context.Page.Request.CurrentExecutionFilePath + context.UniqueID + ".Model"; + } - /// - /// Abstracts session access for unit testing. - /// - protected virtual object GetItem(Control context, string key) - { - return context.Page.Session[key]; - } + /// + /// Abstracts session access for unit testing. + /// + protected virtual object GetItem(Control context, string key) + { + return context.Page.Session[key]; + } - /// - /// Abstracts session access for unit testing. - /// - protected virtual void SetItem(Control context, string key, object item) - { - context.Page.Session[key] = item; - } + /// + /// Abstracts session access for unit testing. + /// + protected virtual void SetItem(Control context, string key, object item) + { + context.Page.Session[key] = item; } } \ No newline at end of file diff --git a/src/Spring/Spring.Web/Web/UI/UserControl.cs b/src/Spring/Spring.Web/Web/UI/UserControl.cs index 042fc8a5..fc883d5a 100644 --- a/src/Spring/Spring.Web/Web/UI/UserControl.cs +++ b/src/Spring/Spring.Web/Web/UI/UserControl.cs @@ -39,1084 +39,1094 @@ using IValidator = Spring.Validation.IValidator; #endregion -namespace Spring.Web.UI +namespace Spring.Web.UI; + +/// +/// Extends standard .Net user control by adding data binding and localization functionality. +/// +/// Aleksandar Seovic +public class UserControl : System.Web.UI.UserControl, IApplicationContextAware, IWebDataBound, ISupportsWebDependencyInjection, + IPostBackDataHandler, IValidationContainer, IWebNavigable { + #region Static fields + + private static readonly object EventPreLoadViewState = new object(); + private static readonly object EventDataBindingsInitialized = new object(); + private static readonly object EventDataBound = new object(); + private static readonly object EventDataUnbound = new object(); + + #endregion + + #region Instance Fields + + private object controller; + private ILocalizer localizer; + private IMessageSource messageSource; + private IDictionary sharedState; + private IBindingContainer bindingManager; + private IValidationErrors validationErrors = new ValidationErrors(); + private IWebNavigator webNavigator; + private IDictionary args; + private IApplicationContext applicationContext; + private IApplicationContext defaultApplicationContext; + private bool needsUnbind = false; + + #endregion + + #region Control lifecycle methods + /// - /// Extends standard .Net user control by adding data binding and localization functionality. + /// Initialize a new UserControl instance. /// - /// Aleksandar Seovic - public class UserControl : System.Web.UI.UserControl, IApplicationContextAware, IWebDataBound, ISupportsWebDependencyInjection, - IPostBackDataHandler, IValidationContainer, IWebNavigable + public UserControl() { - #region Static fields + InitializeNavigationSupport(); + } - private static readonly object EventPreLoadViewState = new object(); - private static readonly object EventDataBindingsInitialized = new object(); - private static readonly object EventDataBound = new object(); - private static readonly object EventDataUnbound = new object(); + /// + /// Initializes user control. + /// + protected override void OnInit(EventArgs e) + { + InitializeMessageSource(); + InitializeBindingManager(); - #endregion - - #region Instance Fields - - private object controller; - private ILocalizer localizer; - private IMessageSource messageSource; - private IDictionary sharedState; - private IBindingContainer bindingManager; - private IValidationErrors validationErrors = new ValidationErrors(); - private IWebNavigator webNavigator; - private IDictionary args; - private IApplicationContext applicationContext; - private IApplicationContext defaultApplicationContext; - private bool needsUnbind = false; - - #endregion - - #region Control lifecycle methods - - /// - /// Initialize a new UserControl instance. - /// - public UserControl() + if (!IsPostBack) { - InitializeNavigationSupport(); + InitializeModel(); + } + else + { + LoadModel(LoadModelFromPersistenceMedium()); } - /// - /// Initializes user control. - /// - protected override void OnInit( EventArgs e ) + base.OnInit(e); + + OnInitializeControls(EventArgs.Empty); + } + + /// + /// Raises the event after page initialization. + /// + protected internal virtual void OnPreLoadViewState(EventArgs e) + { + EventHandler handler = (EventHandler) base.Events[EventPreLoadViewState]; + if (handler != null) { - InitializeMessageSource(); - InitializeBindingManager(); + handler(this, e); + } + } - if (!IsPostBack) - { - InitializeModel(); - } - else - { - LoadModel( LoadModelFromPersistenceMedium() ); - } + /// + /// PreLoadViewState event. + /// + /// + /// + /// This event is raised if is true + /// immediately before state is restored from ViewState. + /// + /// + /// NOTE: Different from , this event will always be raised! + /// + /// + public event EventHandler PreLoadViewState + { + add { base.Events.AddHandler(EventPreLoadViewState, value); } + remove { base.Events.RemoveHandler(EventPreLoadViewState, value); } + } - base.OnInit( e ); + /// + /// This method is called during a postback if this control has been visible when being rendered to the client. + /// + /// + /// If the controls has been visible when being rendering to the client, + /// has been called during + /// + /// true if the server control's state changes as a result of the post back; otherwise false. + bool IPostBackDataHandler.LoadPostData(string postDataKey, NameValueCollection postCollection) + { + return LoadPostData(postDataKey, postCollection); + } - OnInitializeControls( EventArgs.Empty ); + /// + /// This method is called during a postback if this control has been visible when being rendered to the client. + /// + /// true if the server control's state changes as a result of the post back; otherwise false. + protected virtual bool LoadPostData(string postDataKey, NameValueCollection postCollection) + { + // mark this control for unbinding form data during OnLoad() + this.needsUnbind = true; + return false; + } + + /// + /// When implemented by a class, signals the server control object to notify the + /// ASP.NET application that the state of the control has changed. + /// + void IPostBackDataHandler.RaisePostDataChangedEvent() + { + RaisePostDataChangedEvent(); + } + + /// + /// When implemented by a class, signals the server control object to notify the + /// ASP.NET application that the state of the control has changed. + /// + protected virtual void RaisePostDataChangedEvent() + { + return; + } + + /// + /// First unbinds data from the controls into a data model and + /// then raises Load event in order to execute all associated handlers. + /// + /// Event arguments. + protected override void OnLoad(EventArgs e) + { + if (IsPostBack && needsUnbind) + { + // unbind form data + UnbindFormData(); } - /// - /// Raises the event after page initialization. - /// - protected internal virtual void OnPreLoadViewState( EventArgs e ) + base.OnLoad(e); + } + + /// + /// Binds data from the data model into controls and raises + /// PreRender event afterwards. + /// + /// Event arguments. + protected override void OnPreRender(EventArgs e) + { + if (Visible) { - EventHandler handler = (EventHandler)base.Events[EventPreLoadViewState]; - if (handler != null) + // causes IPostBackDataHandler.LoadPostData() to be called on next postback. + // this is used for indicating a required call to UnbindFormData() + Page.RegisterRequiresPostBack(this); + + BindFormData(); + + if (localizer != null) { - handler( this, e ); + localizer.ApplyResources(this, messageSource, UserCulture); + } + else if (Page.Localizer != null) + { + Page.Localizer.ApplyResources(this, messageSource, UserCulture); } } - /// - /// PreLoadViewState event. - /// - /// - /// - /// This event is raised if is true - /// immediately before state is restored from ViewState. - /// - /// - /// NOTE: Different from , this event will always be raised! - /// - /// - public event EventHandler PreLoadViewState + base.OnPreRender(e); + + object modelToSave = SaveModel(); + if (modelToSave != null) { - add { base.Events.AddHandler( EventPreLoadViewState, value ); } - remove { base.Events.RemoveHandler( EventPreLoadViewState, value ); } + SaveModelToPersistenceMedium(modelToSave); + } + } + + /// + /// This event is raised before Load event and should be used to initialize + /// controls as necessary. + /// + public event EventHandler InitializeControls; + + /// + /// Raises InitializeControls event. + /// + /// Event arguments. + protected virtual void OnInitializeControls(EventArgs e) + { + if (InitializeControls != null) + { + InitializeControls(this, e); + } + } + + /// + /// Obtains a object from a user control file + /// and injects dependencies according to Spring config file. + /// + /// The virtual path to a user control file. + /// + /// Returns the specified object, with dependencies injected. + /// + protected virtual new Control LoadControl(string virtualPath) + { + Control control = base.LoadControl(virtualPath); + control = WebDependencyInjectionUtils.InjectDependenciesRecursive(defaultApplicationContext, control); + return control; + } + + /// + /// Obtains a object by type + /// and injects dependencies according to Spring config file. + /// + /// The type of a user control. + /// parameters to pass to the control + /// + /// Returns the specified object, with dependencies injected. + /// + protected virtual new Control LoadControl(Type t, params object[] parameters) + { + Control control = base.LoadControl(t, parameters); + control = WebDependencyInjectionUtils.InjectDependenciesRecursive(defaultApplicationContext, control); + return control; + } + + #endregion + + #region Model Management Support + + private IModelPersistenceMedium modelPersistenceMedium = new SessionModelPersistenceMedium(); + + /// + /// Set the strategy for storing model + /// instances between requests. + /// + /// + /// By default the strategy is used. + /// + public IModelPersistenceMedium ModelPersistenceMedium + { + set + { + AssertUtils.ArgumentNotNull(value, "ModelPersistenceMedium"); + modelPersistenceMedium = value; + } + } + + /// + /// Retrieves data model from a persistence store. + /// + /// + /// The default implementation uses to store and retrieve + /// the model for the current + /// + protected virtual object LoadModelFromPersistenceMedium() + { + //return Session[Request.CurrentExecutionFilePath + this.UniqueID + ".Model"]; + return modelPersistenceMedium.LoadFromMedium(this); + } + + /// + /// Saves data model to a persistence store. + /// + /// + /// The default implementation uses to store and retrieve + /// the model for the current + /// + protected virtual void SaveModelToPersistenceMedium(object modelToSave) + { + //Session[Request.CurrentExecutionFilePath + this.UniqueID + ".Model"] = modelToSave; + modelPersistenceMedium.SaveToMedium(this, modelToSave); + } + + /// + /// Initializes data model when the page is first loaded. + /// + /// + /// This method should be overriden by the developer + /// in order to initialize data model for the page. + /// + protected virtual void InitializeModel() + { + } + + /// + /// Loads the saved data model on postback. + /// + /// + /// This method should be overriden by the developer + /// in order to load data model for the page. + /// + protected virtual void LoadModel(object savedModel) + { + } + + /// + /// Returns a model object that should be saved. + /// + /// + /// This method should be overriden by the developer + /// in order to save data model for the page. + /// + /// + /// A model object that should be saved. + /// + protected virtual object SaveModel() + { + return null; + } + + #endregion< + + #region Controller Support + + /// + /// Gets or sets controller for the control. + /// + /// + /// + /// Internally calls are delegated to and . + /// + /// + /// Controller for the control. + public object Controller + { + get { return GetController(); } + set { SetController(value); } + } + + /// + /// Stores the controller to be returned by property. + /// + /// + /// The default implementation uses a field to store the reference. Derived classes may override this behaviour + /// but must ensure to also change the behaviour of accordingly. + /// + /// Controller for the control. + protected virtual void SetController(object controller) + { + this.controller = controller; + } + + /// + /// Returns the controller stored by . + /// + /// + /// + /// The default implementation uses a field to retrieve the reference. + /// + /// + /// If external controller is not specified, control will serve as its own controller, + /// which will allow data binding to work properly. + /// + /// + /// You may override this method e.g. to return in order to + /// have your control bind to the same controller as your page. When overriding this behaviour, derived classes + /// must ensure to also change the behaviour of accordingly. + /// + /// + /// + /// The controller for this control. + /// If no controller is set, a reference to the control itself is returned. + /// + protected virtual object GetController() + { + if (controller == null) + { + return this; } - /// - /// This method is called during a postback if this control has been visible when being rendered to the client. - /// - /// - /// If the controls has been visible when being rendering to the client, - /// has been called during - /// - /// true if the server control's state changes as a result of the post back; otherwise false. - bool IPostBackDataHandler.LoadPostData( string postDataKey, NameValueCollection postCollection ) - { - return LoadPostData( postDataKey, postCollection ); - } + return controller; + } - /// - /// This method is called during a postback if this control has been visible when being rendered to the client. - /// - /// true if the server control's state changes as a result of the post back; otherwise false. - protected virtual bool LoadPostData( string postDataKey, NameValueCollection postCollection ) - { - // mark this control for unbinding form data during OnLoad() - this.needsUnbind = true; - return false; - } + #endregion Controller Support - /// - /// When implemented by a class, signals the server control object to notify the - /// ASP.NET application that the state of the control has changed. - /// - void IPostBackDataHandler.RaisePostDataChangedEvent() - { - RaisePostDataChangedEvent(); - } + #region Shared State support - /// - /// When implemented by a class, signals the server control object to notify the - /// ASP.NET application that the state of the control has changed. - /// - protected virtual void RaisePostDataChangedEvent() + /// + /// Returns a thread-safe dictionary that contains state that is shared by + /// all instances of this control. + /// + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + protected IDictionary SharedState + { + get { - return; - } - - - /// - /// First unbinds data from the controls into a data model and - /// then raises Load event in order to execute all associated handlers. - /// - /// Event arguments. - protected override void OnLoad( EventArgs e ) - { - if (IsPostBack && needsUnbind) + if (sharedState == null) { - // unbind form data - UnbindFormData(); - } - base.OnLoad( e ); - } + string thisTypeKey = this.GetType().FullName + this.GetType().GetHashCode() + ".SharedState"; - /// - /// Binds data from the data model into controls and raises - /// PreRender event afterwards. - /// - /// Event arguments. - protected override void OnPreRender( EventArgs e ) - { - if (Visible) - { - // causes IPostBackDataHandler.LoadPostData() to be called on next postback. - // this is used for indicating a required call to UnbindFormData() - Page.RegisterRequiresPostBack( this ); - - BindFormData(); - - if (localizer != null) - { - localizer.ApplyResources( this, messageSource, UserCulture ); - } - else if (Page.Localizer != null) - { - Page.Localizer.ApplyResources( this, messageSource, UserCulture ); - } - } - - base.OnPreRender( e ); - - object modelToSave = SaveModel(); - if (modelToSave != null) - { - SaveModelToPersistenceMedium( modelToSave ); - } - } - - /// - /// This event is raised before Load event and should be used to initialize - /// controls as necessary. - /// - public event EventHandler InitializeControls; - - /// - /// Raises InitializeControls event. - /// - /// Event arguments. - protected virtual void OnInitializeControls( EventArgs e ) - { - if (InitializeControls != null) - { - InitializeControls( this, e ); - } - } - - /// - /// Obtains a object from a user control file - /// and injects dependencies according to Spring config file. - /// - /// The virtual path to a user control file. - /// - /// Returns the specified object, with dependencies injected. - /// - protected virtual new Control LoadControl( string virtualPath ) - { - Control control = base.LoadControl( virtualPath ); - control = WebDependencyInjectionUtils.InjectDependenciesRecursive( defaultApplicationContext, control ); - return control; - } - - /// - /// Obtains a object by type - /// and injects dependencies according to Spring config file. - /// - /// The type of a user control. - /// parameters to pass to the control - /// - /// Returns the specified object, with dependencies injected. - /// - protected virtual new Control LoadControl( Type t, params object[] parameters ) - { - Control control = base.LoadControl( t, parameters ); - control = WebDependencyInjectionUtils.InjectDependenciesRecursive( defaultApplicationContext, control ); - return control; - } - - #endregion - - #region Model Management Support - - private IModelPersistenceMedium modelPersistenceMedium = new SessionModelPersistenceMedium(); - - /// - /// Set the strategy for storing model - /// instances between requests. - /// - /// - /// By default the strategy is used. - /// - public IModelPersistenceMedium ModelPersistenceMedium - { - set - { - AssertUtils.ArgumentNotNull(value, "ModelPersistenceMedium"); - modelPersistenceMedium = value; - } - } - - /// - /// Retrieves data model from a persistence store. - /// - /// - /// The default implementation uses to store and retrieve - /// the model for the current - /// - protected virtual object LoadModelFromPersistenceMedium() - { - //return Session[Request.CurrentExecutionFilePath + this.UniqueID + ".Model"]; - return modelPersistenceMedium.LoadFromMedium(this); - } - - /// - /// Saves data model to a persistence store. - /// - /// - /// The default implementation uses to store and retrieve - /// the model for the current - /// - protected virtual void SaveModelToPersistenceMedium( object modelToSave ) - { - //Session[Request.CurrentExecutionFilePath + this.UniqueID + ".Model"] = modelToSave; - modelPersistenceMedium.SaveToMedium(this, modelToSave); - } - - /// - /// Initializes data model when the page is first loaded. - /// - /// - /// This method should be overriden by the developer - /// in order to initialize data model for the page. - /// - protected virtual void InitializeModel() - { - } - - /// - /// Loads the saved data model on postback. - /// - /// - /// This method should be overriden by the developer - /// in order to load data model for the page. - /// - protected virtual void LoadModel( object savedModel ) - { - } - - /// - /// Returns a model object that should be saved. - /// - /// - /// This method should be overriden by the developer - /// in order to save data model for the page. - /// - /// - /// A model object that should be saved. - /// - protected virtual object SaveModel() - { - return null; - } - - #endregion< - - #region Controller Support - - /// - /// Gets or sets controller for the control. - /// - /// - /// - /// Internally calls are delegated to and . - /// - /// - /// Controller for the control. - public object Controller - { - get { return GetController(); } - set { SetController( value ); } - } - - /// - /// Stores the controller to be returned by property. - /// - /// - /// The default implementation uses a field to store the reference. Derived classes may override this behaviour - /// but must ensure to also change the behaviour of accordingly. - /// - /// Controller for the control. - protected virtual void SetController( object controller ) - { - this.controller = controller; - } - - /// - /// Returns the controller stored by . - /// - /// - /// - /// The default implementation uses a field to retrieve the reference. - /// - /// - /// If external controller is not specified, control will serve as its own controller, - /// which will allow data binding to work properly. - /// - /// - /// You may override this method e.g. to return in order to - /// have your control bind to the same controller as your page. When overriding this behaviour, derived classes - /// must ensure to also change the behaviour of accordingly. - /// - /// - /// - /// The controller for this control. - /// If no controller is set, a reference to the control itself is returned. - /// - protected virtual object GetController() - { - if (controller == null) - { - return this; - } - return controller; - } - - #endregion Controller Support - - #region Shared State support - - /// - /// Returns a thread-safe dictionary that contains state that is shared by - /// all instances of this control. - /// - [Browsable( false )] - [DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden )] - protected IDictionary SharedState - { - get - { + sharedState = Application[thisTypeKey] as IDictionary; if (sharedState == null) { - string thisTypeKey = this.GetType().FullName + this.GetType().GetHashCode() + ".SharedState"; - - sharedState = Application[thisTypeKey] as IDictionary; - if (sharedState == null) + Application.Lock(); + try { - Application.Lock(); - try + sharedState = Application[thisTypeKey] as IDictionary; + if (sharedState == null) { - sharedState = Application[thisTypeKey] as IDictionary; - if (sharedState == null) - { - sharedState = new SynchronizedHashtable(); - Application.Add( thisTypeKey, sharedState ); - } - } - finally - { - Application.UnLock(); + sharedState = new SynchronizedHashtable(); + Application.Add(thisTypeKey, sharedState); } } + finally + { + Application.UnLock(); + } } - return sharedState; } + + return sharedState; + } + } + + #endregion Shared State support + + #region Result support + + /// + /// Ensure, that is set to a valid instance. + /// + /// + /// If is not already set, creates and sets a new instance.
+ /// Override this method if you don't want to inject a navigator, but need a different default. + ///
+ protected virtual void InitializeNavigationSupport() + { + webNavigator = new WebFormsResultWebNavigator(this, null, null, true); + } + + /// + /// Gets/Sets the navigator to be used for handling calls. + /// + public IWebNavigator WebNavigator + { + get + { + return webNavigator; + } + set + { + webNavigator = value; + } + } + + /// + /// Gets or sets map of result names to target URLs + /// + /// + /// Using requires to implement . + /// + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public virtual IDictionary Results + { + get + { + if (WebNavigator is IResultWebNavigator) + { + return ((IResultWebNavigator) WebNavigator).Results; + } + + return null; + } + set + { + if (WebNavigator is IResultWebNavigator) + { + ((IResultWebNavigator) WebNavigator).Results = value; + return; + } + + throw new NotSupportedException("WebNavigator must be of type IResultWebNavigator to support Results"); + } + } + + /// + /// A convenience, case-insensitive table that may be used to e.g. pass data into SpEL expressions"/>. + /// + /// + /// By default, e.g. passes the control instance into an expression. Using + /// is an easy way to pass additional parameters into the expression + /// + /// // config: + /// + /// <property Name="Results"> + /// <dictionary> + /// <entry key="ok_clicked" value="redirect:~/ShowResult.aspx?result=%{Args['result']}" /> + /// </dictionary> + /// </property> + /// + /// // code: + /// + /// void OnOkClicked(object sender, EventArgs e) + /// { + /// Args["result"] = txtUserInput.Text; + /// SetResult("ok_clicked"); + /// } + /// + /// + public IDictionary Args + { + get + { + if (args == null) + { + args = new CaseInsensitiveHashtable(); + } + + return args; + } + } + + /// + /// Redirects user to a URL mapped to specified result name. + /// + /// Result name. + protected void SetResult(string resultName) + { + WebNavigator.NavigateTo(resultName, this, null); + } + + /// + /// Redirects user to a URL mapped to specified result name. + /// + /// Name of the result. + /// The context to use for evaluating the SpEL expression in the Result. + protected void SetResult(string resultName, object context) + { + WebNavigator.NavigateTo(resultName, this, context); + } + + /// + /// Returns a redirect url string that points to the + /// defined by this + /// result evaluated using this Page for expression + /// + /// Name of the result. + /// A redirect url string. + protected string GetResultUrl(string resultName) + { + return ResolveUrl(WebNavigator.GetResultUri(resultName, this, null)); + } + + /// + /// Returns a redirect url string that points to the + /// defined by this + /// result evaluated using this Page for expression + /// + /// Name of the result. + /// The context to use for evaluating the SpEL expression in the Result + /// A redirect url string. + protected string GetResultUrl(string resultName, object context) + { + return ResolveUrl(WebNavigator.GetResultUri(resultName, this, context)); + } + + #endregion + + #region Validation support + + /// + /// Evaluates specified validators and returns True if all of them are valid. + /// + /// + ///

+ /// Each validator can itself represent a collection of other validators if it is + /// an instance of or one of its derived types. + ///

+ ///

+ /// Please see the Validation Framework section in the documentation for more info. + ///

+ ///
+ /// Object to validate. + /// Validators to evaluate. + /// + /// True if all of the specified validators are valid, False otherwise. + /// + public bool Validate(object validationContext, params IValidator[] validators) + { + IDictionary contextParams = CreateValidatorParameters(); + bool result = true; + foreach (IValidator validator in validators) + { + if (validator == null) + { + throw new ArgumentException("Validator is not defined."); + } + + result = validator.Validate(validationContext, contextParams, this.ValidationErrors) && result; } - #endregion Shared State support + return result; + } - #region Result support - - /// - /// Ensure, that is set to a valid instance. - /// - /// - /// If is not already set, creates and sets a new instance.
- /// Override this method if you don't want to inject a navigator, but need a different default. - ///
- protected virtual void InitializeNavigationSupport() + /// + /// Gets or sets the validation errors container. + /// + /// The validation errors container. + public virtual IValidationErrors ValidationErrors + { + get { return validationErrors; } + set { - webNavigator = new WebFormsResultWebNavigator(this, null, null, true); + AssertUtils.ArgumentNotNull(value, "ValidationErrors"); + validationErrors = value; } + } - /// - /// Gets/Sets the navigator to be used for handling calls. - /// - public IWebNavigator WebNavigator - { - get - { - return webNavigator; - } - set - { - webNavigator = value; - } - } + /// + /// Creates the validator parameters. + /// + /// + /// + /// This method can be overriden if you want to pass additional parameters + /// to the validation framework, but you should make sure that you call + /// this base implementation in order to add page, session, application, + /// request, response and context to the variables collection. + /// + /// + /// + /// Dictionary containing parameters that should be passed to + /// the data validation framework. + /// + protected virtual IDictionary CreateValidatorParameters() + { + IDictionary parameters = new Dictionary(8); + parameters["page"] = this.Page; + parameters["usercontrol"] = this; + parameters["session"] = this.Session; + parameters["application"] = this.Application; + parameters["request"] = this.Request; + parameters["response"] = this.Response; + parameters["context"] = this.Context; - /// - /// Gets or sets map of result names to target URLs - /// - /// - /// Using requires to implement . - /// - [Browsable( false )] - [DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden )] - public virtual IDictionary Results + return parameters; + } + + #endregion + + #region Data binding support + + /// + /// Initializes the data bindings. + /// + protected virtual void InitializeDataBindings() + { + } + + /// + /// Returns the key to be used for looking up a cached + /// BindingManager instance in . + /// + /// a unique key identifying the instance in the dictionary. + protected virtual string GetBindingManagerKey() + { + return "DataBindingManager"; + } + + /// + /// Creates a new instance. + /// + /// + /// This factory method is called if no could be found in + /// using the key returned by .
+ ///
+ /// + ///
+ /// a instance to be used for DataBinding + protected virtual IBindingContainer CreateBindingManager() + { + return new BaseBindingManager(); + } + + /// + /// Gets the binding manager for this control. + /// + /// The binding manager. + public IBindingContainer BindingManager + { + get { return this.bindingManager; } + } + + /// + /// Initializes binding manager and data bindings if necessary. + /// + private void InitializeBindingManager() + { + IDictionary sharedState = this.SharedState; + + string key = GetBindingManagerKey(); + this.bindingManager = sharedState[key] as BaseBindingManager; + if (this.bindingManager == null) { - get + lock (sharedState.SyncRoot) { - if (WebNavigator is IResultWebNavigator) + this.bindingManager = sharedState[key] as BaseBindingManager; + if (this.bindingManager == null) { - return ((IResultWebNavigator)WebNavigator).Results; + try + { + this.bindingManager = CreateBindingManager(); + if (bindingManager == null) + { + throw new ArgumentNullException("bindingManager", + "CreateBindingManager() must not return null"); + } + + InitializeDataBindings(); + } + catch + { + this.bindingManager = null; + throw; + } + + sharedState[key] = this.bindingManager; + this.OnDataBindingsInitialized(EventArgs.Empty); } - return null; } - set + } + } + + /// + /// Raises the event. + /// + protected virtual void OnDataBindingsInitialized(EventArgs e) + { + EventHandler handler = (EventHandler) base.Events[EventDataBindingsInitialized]; + + if (handler != null) + { + handler(this, e); + } + } + + /// + /// This event is raised after as been initialized. + /// + public event EventHandler DataBindingsInitialized + { + add + { + base.Events.AddHandler(EventDataBindingsInitialized, value); + } + remove + { + base.Events.RemoveHandler(EventDataBindingsInitialized, value); + } + } + + /// + /// Bind data from model to form. + /// + protected internal virtual void BindFormData() + { + if (BindingManager.HasBindings) + { + BindingManager.BindTargetToSource(this, Controller, this.ValidationErrors); + } + + OnDataBound(EventArgs.Empty); + } + + /// + /// Unbind data from form to model. + /// + protected internal virtual void UnbindFormData() + { + if (BindingManager.HasBindings) + { + BindingManager.BindSourceToTarget(this, Controller, this.ValidationErrors); + } + + OnDataUnbound(EventArgs.Empty); + } + + /// + /// This event is raised after all controls have been populated with values + /// from the data model. + /// + public event EventHandler DataBound + { + add + { + base.Events.AddHandler(EventDataBound, value); + } + remove + { + base.Events.RemoveHandler(EventDataBound, value); + } + } + + /// + /// Raises DataBound event. + /// + /// Event arguments. + protected virtual void OnDataBound(EventArgs e) + { + EventHandler handler = (EventHandler) base.Events[EventDataBound]; + if (handler != null) + { + handler(this, e); + } + } + + /// + /// This event is raised after data model has been populated with values from + /// web controls. + /// + public event EventHandler DataUnbound + { + add + { + base.Events.AddHandler(EventDataUnbound, value); + } + remove + { + base.Events.RemoveHandler(EventDataUnbound, value); + } + } + + /// + /// Raises DataBound event. + /// + /// Event arguments. + protected virtual void OnDataUnbound(EventArgs e) + { + EventHandler handler = (EventHandler) base.Events[EventDataUnbound]; + if (handler != null) + { + handler(this, e); + } + } + + #endregion + + #region Application context support + + /// + /// Gets or sets the that this + /// object runs in. + /// + /// + /// + ///

+ /// Normally this call will be used to initialize the object. + ///

+ ///

+ /// Invoked after population of normal object properties but before an + /// init callback such as + /// 's + /// + /// or a custom init-method. Invoked after the setting of any + /// 's + /// + /// property. + ///

+ ///
+ /// + /// In the case of application context initialization errors. + /// + /// + /// If thrown by any application context methods. + /// + /// + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public virtual IApplicationContext ApplicationContext + { + get { return applicationContext; } + set { applicationContext = value; } + } + + #endregion + + #region Message source and localization support + + /// + /// Gets or sets the localizer. + /// + /// The localizer. + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public ILocalizer Localizer + { + get { return localizer; } + set + { + localizer = value; + if (localizer.ResourceCache is NullResourceCache) { - if (WebNavigator is IResultWebNavigator) - { - ((IResultWebNavigator)WebNavigator).Results = value; - return; - } - throw new NotSupportedException("WebNavigator must be of type IResultWebNavigator to support Results"); + localizer.ResourceCache = new AspNetResourceCache(); } } + } - /// - /// A convenience, case-insensitive table that may be used to e.g. pass data into SpEL expressions"/>. - /// - /// - /// By default, e.g. passes the control instance into an expression. Using - /// is an easy way to pass additional parameters into the expression - /// - /// // config: - /// - /// <property Name="Results"> - /// <dictionary> - /// <entry key="ok_clicked" value="redirect:~/ShowResult.aspx?result=%{Args['result']}" /> - /// </dictionary> - /// </property> - /// - /// // code: - /// - /// void OnOkClicked(object sender, EventArgs e) - /// { - /// Args["result"] = txtUserInput.Text; - /// SetResult("ok_clicked"); - /// } - /// - /// - public IDictionary Args + /// + /// Gets or sets the local message source. + /// + /// The local message source. + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public IMessageSource MessageSource + { + get { return messageSource; } + set { - get + messageSource = value; + if (messageSource != null && messageSource is AbstractMessageSource) { - if (args == null) - { - args = new CaseInsensitiveHashtable(); - } - return args; + ((AbstractMessageSource) messageSource).ParentMessageSource = applicationContext; } } + } - /// - /// Redirects user to a URL mapped to specified result name. - /// - /// Result name. - protected void SetResult( string resultName ) - { - WebNavigator.NavigateTo( resultName, this, null ); - } - - - /// - /// Redirects user to a URL mapped to specified result name. - /// - /// Name of the result. - /// The context to use for evaluating the SpEL expression in the Result. - protected void SetResult( string resultName, object context ) - { - WebNavigator.NavigateTo( resultName, this, context ); - } - - - /// - /// Returns a redirect url string that points to the - /// defined by this - /// result evaluated using this Page for expression - /// - /// Name of the result. - /// A redirect url string. - protected string GetResultUrl( string resultName ) - { - return ResolveUrl( WebNavigator.GetResultUri( resultName, this, null ) ); - } - - /// - /// Returns a redirect url string that points to the - /// defined by this - /// result evaluated using this Page for expression - /// - /// Name of the result. - /// The context to use for evaluating the SpEL expression in the Result - /// A redirect url string. - protected string GetResultUrl( string resultName, object context ) - { - return ResolveUrl( WebNavigator.GetResultUri( resultName, this, context ) ); - } - - #endregion - - #region Validation support - - /// - /// Evaluates specified validators and returns True if all of them are valid. - /// - /// - ///

- /// Each validator can itself represent a collection of other validators if it is - /// an instance of or one of its derived types. - ///

- ///

- /// Please see the Validation Framework section in the documentation for more info. - ///

- ///
- /// Object to validate. - /// Validators to evaluate. - /// - /// True if all of the specified validators are valid, False otherwise. - /// - public bool Validate( object validationContext, params IValidator[] validators ) - { - IDictionary contextParams = CreateValidatorParameters(); - bool result = true; - foreach (IValidator validator in validators) - { - if (validator == null) - { - throw new ArgumentException( "Validator is not defined." ); - } - result = validator.Validate( validationContext, contextParams, this.ValidationErrors ) && result; - } - - return result; - } - - /// - /// Gets or sets the validation errors container. - /// - /// The validation errors container. - public virtual IValidationErrors ValidationErrors - { - get { return validationErrors; } - set - { - AssertUtils.ArgumentNotNull(value, "ValidationErrors"); - validationErrors = value; - } - } - - /// - /// Creates the validator parameters. - /// - /// - /// - /// This method can be overriden if you want to pass additional parameters - /// to the validation framework, but you should make sure that you call - /// this base implementation in order to add page, session, application, - /// request, response and context to the variables collection. - /// - /// - /// - /// Dictionary containing parameters that should be passed to - /// the data validation framework. - /// - protected virtual IDictionary CreateValidatorParameters() - { - IDictionary parameters = new Dictionary(8); - parameters["page"] = this.Page; - parameters["usercontrol"] = this; - parameters["session"] = this.Session; - parameters["application"] = this.Application; - parameters["request"] = this.Request; - parameters["response"] = this.Response; - parameters["context"] = this.Context; - - return parameters; - } - - #endregion - - #region Data binding support - - /// - /// Initializes the data bindings. - /// - protected virtual void InitializeDataBindings() - { } - - /// - /// Returns the key to be used for looking up a cached - /// BindingManager instance in . - /// - /// a unique key identifying the instance in the dictionary. - protected virtual string GetBindingManagerKey() - { - return "DataBindingManager"; - } - - /// - /// Creates a new instance. - /// - /// - /// This factory method is called if no could be found in - /// using the key returned by .
- ///
- /// - ///
- /// a instance to be used for DataBinding - protected virtual IBindingContainer CreateBindingManager() - { - return new BaseBindingManager(); - } - - /// - /// Gets the binding manager for this control. - /// - /// The binding manager. - public IBindingContainer BindingManager - { - get { return this.bindingManager; } - } - - /// - /// Initializes binding manager and data bindings if necessary. - /// - private void InitializeBindingManager() + /// + /// Initializes local message source + /// + protected void InitializeMessageSource() + { + if (this.MessageSource == null) { + string key = CreateSharedStateKey("MessageSource"); IDictionary sharedState = this.SharedState; - - string key = GetBindingManagerKey(); - this.bindingManager = sharedState[key] as BaseBindingManager; - if (this.bindingManager == null) + IMessageSource messageSource = sharedState[key] as IMessageSource; + if (messageSource == null) { lock (sharedState.SyncRoot) { - this.bindingManager = sharedState[key] as BaseBindingManager; - if (this.bindingManager == null) + messageSource = sharedState[key] as IMessageSource; + if (messageSource == null) { - try + ResourceSetMessageSource defaultMessageSource = new ResourceSetMessageSource(); + defaultMessageSource.UseCodeAsDefaultMessage = true; + ResourceManager rm = GetLocalResourceManager(); + if (rm != null) { - this.bindingManager = CreateBindingManager(); - if (bindingManager == null) - { - throw new ArgumentNullException( "bindingManager", - "CreateBindingManager() must not return null" ); - } - InitializeDataBindings(); + defaultMessageSource.ResourceManagers.Add(rm); } - catch - { - this.bindingManager = null; - throw; - } - sharedState[key] = this.bindingManager; - this.OnDataBindingsInitialized( EventArgs.Empty ); + + sharedState[key] = defaultMessageSource; + messageSource = defaultMessageSource; } } } + + this.MessageSource = messageSource; } - - /// - /// Raises the event. - /// - protected virtual void OnDataBindingsInitialized( EventArgs e ) - { - EventHandler handler = (EventHandler)base.Events[EventDataBindingsInitialized]; - - if (handler != null) - { - handler( this, e ); - } - } - - /// - /// This event is raised after as been initialized. - /// - public event EventHandler DataBindingsInitialized - { - add - { - base.Events.AddHandler( EventDataBindingsInitialized, value ); - } - remove - { - base.Events.RemoveHandler( EventDataBindingsInitialized, value ); - } - } - - /// - /// Bind data from model to form. - /// - protected internal virtual void BindFormData() - { - if (BindingManager.HasBindings) - { - BindingManager.BindTargetToSource( this, Controller, this.ValidationErrors ); - } - OnDataBound( EventArgs.Empty ); - } - - /// - /// Unbind data from form to model. - /// - protected internal virtual void UnbindFormData() - { - if (BindingManager.HasBindings) - { - BindingManager.BindSourceToTarget( this, Controller, this.ValidationErrors ); - } - OnDataUnbound( EventArgs.Empty ); - } - - /// - /// This event is raised after all controls have been populated with values - /// from the data model. - /// - public event EventHandler DataBound - { - add - { - base.Events.AddHandler( EventDataBound, value ); - } - remove - { - base.Events.RemoveHandler( EventDataBound, value ); - } - } - - /// - /// Raises DataBound event. - /// - /// Event arguments. - protected virtual void OnDataBound( EventArgs e ) - { - EventHandler handler = (EventHandler)base.Events[EventDataBound]; - if (handler != null) - { - handler( this, e ); - } - } - - /// - /// This event is raised after data model has been populated with values from - /// web controls. - /// - public event EventHandler DataUnbound - { - add - { - base.Events.AddHandler( EventDataUnbound, value ); - } - remove - { - base.Events.RemoveHandler( EventDataUnbound, value ); - } - } - - /// - /// Raises DataBound event. - /// - /// Event arguments. - protected virtual void OnDataUnbound( EventArgs e ) - { - EventHandler handler = (EventHandler)base.Events[EventDataUnbound]; - if (handler != null) - { - handler( this, e ); - } - } - - #endregion - - #region Application context support - - /// - /// Gets or sets the that this - /// object runs in. - /// - /// - /// - ///

- /// Normally this call will be used to initialize the object. - ///

- ///

- /// Invoked after population of normal object properties but before an - /// init callback such as - /// 's - /// - /// or a custom init-method. Invoked after the setting of any - /// 's - /// - /// property. - ///

- ///
- /// - /// In the case of application context initialization errors. - /// - /// - /// If thrown by any application context methods. - /// - /// - [Browsable( false )] - [DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden )] - public virtual IApplicationContext ApplicationContext - { - get { return applicationContext; } - set { applicationContext = value; } - } - - #endregion - - #region Message source and localization support - - /// - /// Gets or sets the localizer. - /// - /// The localizer. - [Browsable( false )] - [DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden )] - public ILocalizer Localizer - { - get { return localizer; } - set - { - localizer = value; - if (localizer.ResourceCache is NullResourceCache) - { - localizer.ResourceCache = new AspNetResourceCache(); - } - } - } - - /// - /// Gets or sets the local message source. - /// - /// The local message source. - [Browsable( false )] - [DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden )] - public IMessageSource MessageSource - { - get { return messageSource; } - set - { - messageSource = value; - if (messageSource != null && messageSource is AbstractMessageSource) - { - ((AbstractMessageSource)messageSource).ParentMessageSource = applicationContext; - } - } - } - - /// - /// Initializes local message source - /// - protected void InitializeMessageSource() - { - if (this.MessageSource == null) - { - string key = CreateSharedStateKey( "MessageSource" ); - IDictionary sharedState = this.SharedState; - IMessageSource messageSource = sharedState[key] as IMessageSource; - if (messageSource == null) - { - lock (sharedState.SyncRoot) - { - messageSource = sharedState[key] as IMessageSource; - if (messageSource == null) - { - ResourceSetMessageSource defaultMessageSource = new ResourceSetMessageSource(); - defaultMessageSource.UseCodeAsDefaultMessage = true; - ResourceManager rm = GetLocalResourceManager(); - if (rm != null) - { - defaultMessageSource.ResourceManagers.Add( rm ); - } - sharedState[key] = defaultMessageSource; - messageSource = defaultMessageSource; - } - } - } - this.MessageSource = messageSource; - } - } - - /// - /// Creates and returns local ResourceManager for this page. - /// - /// - /// - /// In ASP.NET 1.1, this method loads local resources from the web application assembly. - /// - /// - /// However, in ASP.NET 2.0, local resources are compiled into the dynamic assembly, - /// so we need to find that assembly instead and load the resources from it. - /// - /// - /// Local ResourceManager instance. - private ResourceManager GetLocalResourceManager() - { - return LocalResourceManager.GetLocalResourceManager(this); - } - - /// - /// Returns message for the specified resource name. - /// - /// Resource name. - /// Message text. - public string GetMessage( string name ) - { - return messageSource.GetMessage( name, UserCulture ); - } - - /// - /// Returns message for the specified resource name. - /// - /// Resource name. - /// Message arguments that will be used to format return value. - /// Formatted message text. - public string GetMessage( string name, params object[] args ) - { - return messageSource.GetMessage( name, UserCulture, args ); - } - - /// - /// Returns resource object for the specified resource name. - /// - /// Resource name. - /// Resource object. - public object GetResourceObject( string name ) - { - return messageSource.GetResourceObject( name, UserCulture ); - } - - /// - /// Gets or sets user's culture - /// - [Browsable( false )] - [DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden )] - public virtual CultureInfo UserCulture - { - get { return Page.UserCulture; } - set { Page.UserCulture = value; } - } - - #endregion - - #region Spring Page support - - /// - /// Overrides Page property to return - /// instead of . - /// - [Browsable( false )] - [DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden )] - public new Page Page - { - get { return (Page)base.Page; } - } - - /// - /// Publish associated with this page for convenient usage in Binding Expressions - /// - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public new virtual HttpContext Context - { - get - { - return base.Context; - } - } - - #endregion - - #region Helper Methods - - /// - /// Creates a key for shared state, taking into account whether - /// this page belongs to a process or not. - /// - /// Key suffix - /// Generated unique shared state key. - protected string CreateSharedStateKey( string key ) - { - return key; - } - - #endregion - - #region Dependency Injection Support - - /// - /// Holds the default ApplicationContext to be used during DI. - /// - IApplicationContext ISupportsWebDependencyInjection.DefaultApplicationContext - { - get { return defaultApplicationContext; } - set { defaultApplicationContext = value; } - } - - /// - /// Injects dependencies into control before adding it. - /// - protected override void AddedControl( Control control, int index ) - { - WebDependencyInjectionUtils.InjectDependenciesRecursive( defaultApplicationContext, control ); - base.AddedControl( control, index ); - } - - #endregion Dependency Injection Support } + + /// + /// Creates and returns local ResourceManager for this page. + /// + /// + /// + /// In ASP.NET 1.1, this method loads local resources from the web application assembly. + /// + /// + /// However, in ASP.NET 2.0, local resources are compiled into the dynamic assembly, + /// so we need to find that assembly instead and load the resources from it. + /// + /// + /// Local ResourceManager instance. + private ResourceManager GetLocalResourceManager() + { + return LocalResourceManager.GetLocalResourceManager(this); + } + + /// + /// Returns message for the specified resource name. + /// + /// Resource name. + /// Message text. + public string GetMessage(string name) + { + return messageSource.GetMessage(name, UserCulture); + } + + /// + /// Returns message for the specified resource name. + /// + /// Resource name. + /// Message arguments that will be used to format return value. + /// Formatted message text. + public string GetMessage(string name, params object[] args) + { + return messageSource.GetMessage(name, UserCulture, args); + } + + /// + /// Returns resource object for the specified resource name. + /// + /// Resource name. + /// Resource object. + public object GetResourceObject(string name) + { + return messageSource.GetResourceObject(name, UserCulture); + } + + /// + /// Gets or sets user's culture + /// + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public virtual CultureInfo UserCulture + { + get { return Page.UserCulture; } + set { Page.UserCulture = value; } + } + + #endregion + + #region Spring Page support + + /// + /// Overrides Page property to return + /// instead of . + /// + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public new Page Page + { + get { return (Page) base.Page; } + } + + /// + /// Publish associated with this page for convenient usage in Binding Expressions + /// + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public new virtual HttpContext Context + { + get + { + return base.Context; + } + } + + #endregion + + #region Helper Methods + + /// + /// Creates a key for shared state, taking into account whether + /// this page belongs to a process or not. + /// + /// Key suffix + /// Generated unique shared state key. + protected string CreateSharedStateKey(string key) + { + return key; + } + + #endregion + + #region Dependency Injection Support + + /// + /// Holds the default ApplicationContext to be used during DI. + /// + IApplicationContext ISupportsWebDependencyInjection.DefaultApplicationContext + { + get { return defaultApplicationContext; } + set { defaultApplicationContext = value; } + } + + /// + /// Injects dependencies into control before adding it. + /// + protected override void AddedControl(Control control, int index) + { + WebDependencyInjectionUtils.InjectDependenciesRecursive(defaultApplicationContext, control); + base.AddedControl(control, index); + } + + #endregion Dependency Injection Support } diff --git a/src/Spring/Spring.Web/Web/UI/Validation/AbstractValidationErrorsRenderer.cs b/src/Spring/Spring.Web/Web/UI/Validation/AbstractValidationErrorsRenderer.cs index 1a04f401..39c007ec 100644 --- a/src/Spring/Spring.Web/Web/UI/Validation/AbstractValidationErrorsRenderer.cs +++ b/src/Spring/Spring.Web/Web/UI/Validation/AbstractValidationErrorsRenderer.cs @@ -20,34 +20,33 @@ using System.Web.UI; -namespace Spring.Web.UI.Validation +namespace Spring.Web.UI.Validation; + +/// +/// This class provides common members for all validation errors renderers. +/// +/// Aleksandar Seovic +public abstract class AbstractValidationErrorsRenderer : IValidationErrorsRenderer { + private string cssClass; + /// - /// This class provides common members for all validation errors renderers. + /// Gets or sets the name of the CSS class that should be used. /// - /// Aleksandar Seovic - public abstract class AbstractValidationErrorsRenderer : IValidationErrorsRenderer + /// + /// The name of the CSS class that should be used + /// + public string CssClass { - private string cssClass; - - /// - /// Gets or sets the name of the CSS class that should be used. - /// - /// - /// The name of the CSS class that should be used - /// - public string CssClass - { - get { return this.cssClass; } - set { this.cssClass = value; } - } - - /// - /// Renders validation errors using specified . - /// - /// Web form instance. - /// An HTML writer to use. - /// The list of validation errors. - public abstract void RenderErrors(Page page, HtmlTextWriter writer, IList errors); + get { return this.cssClass; } + set { this.cssClass = value; } } + + /// + /// Renders validation errors using specified . + /// + /// Web form instance. + /// An HTML writer to use. + /// The list of validation errors. + public abstract void RenderErrors(Page page, HtmlTextWriter writer, IList errors); } diff --git a/src/Spring/Spring.Web/Web/UI/Validation/DivValidationErrorsRenderer.cs b/src/Spring/Spring.Web/Web/UI/Validation/DivValidationErrorsRenderer.cs index 04df4b1d..168901ca 100644 --- a/src/Spring/Spring.Web/Web/UI/Validation/DivValidationErrorsRenderer.cs +++ b/src/Spring/Spring.Web/Web/UI/Validation/DivValidationErrorsRenderer.cs @@ -20,46 +20,46 @@ using System.Web.UI; -namespace Spring.Web.UI.Validation +namespace Spring.Web.UI.Validation; + +/// +/// Implementation of that renders +/// validation errors within a div element, using breaks between the +/// errors. +/// +/// +/// This renderer's behavior is consistent with standard ASP.NET behavior of +/// the validation summary, and is used as default renderer for Spring.NET +/// control. +/// +/// Aleksandar Seovic +public class DivValidationErrorsRenderer : AbstractValidationErrorsRenderer { /// - /// Implementation of that renders - /// validation errors within a div element, using breaks between the - /// errors. + /// Renders validation errors using specified . /// - /// - /// This renderer's behavior is consistent with standard ASP.NET behavior of - /// the validation summary, and is used as default renderer for Spring.NET - /// control. - /// - /// Aleksandar Seovic - public class DivValidationErrorsRenderer : AbstractValidationErrorsRenderer + /// Web form instance. + /// An HTML writer to use. + /// The list of validation errors. + public override void RenderErrors(Page page, HtmlTextWriter writer, IList errors) { - /// - /// Renders validation errors using specified . - /// - /// Web form instance. - /// An HTML writer to use. - /// The list of validation errors. - public override void RenderErrors(Page page, HtmlTextWriter writer, IList errors) + if (CssClass != null) { - if (CssClass != null) - { - writer.AddAttribute(HtmlTextWriterAttribute.Class, CssClass); - } - - writer.AddAttribute(HtmlTextWriterAttribute.Id, "ctl00_body_validationSummary"); - - writer.RenderBeginTag(HtmlTextWriterTag.Div); - if (errors != null && errors.Count > 0) - { - foreach (string error in errors) - { - writer.WriteLine(error); - writer.WriteFullBeginTag("br /"); - } - } - writer.RenderEndTag(); + writer.AddAttribute(HtmlTextWriterAttribute.Class, CssClass); } + + writer.AddAttribute(HtmlTextWriterAttribute.Id, "ctl00_body_validationSummary"); + + writer.RenderBeginTag(HtmlTextWriterTag.Div); + if (errors != null && errors.Count > 0) + { + foreach (string error in errors) + { + writer.WriteLine(error); + writer.WriteFullBeginTag("br /"); + } + } + + writer.RenderEndTag(); } } diff --git a/src/Spring/Spring.Web/Web/UI/Validation/IValidationErrorsRenderer.cs b/src/Spring/Spring.Web/Web/UI/Validation/IValidationErrorsRenderer.cs index 0ae7cf7c..d4973c09 100644 --- a/src/Spring/Spring.Web/Web/UI/Validation/IValidationErrorsRenderer.cs +++ b/src/Spring/Spring.Web/Web/UI/Validation/IValidationErrorsRenderer.cs @@ -19,35 +19,33 @@ #endregion using System.Web.UI; - using Spring.Web.UI.Controls; -namespace Spring.Web.UI.Validation +namespace Spring.Web.UI.Validation; + +/// +/// This interface should be implemented by all validation errors renderers. +/// +/// +/// +/// Validation errors renderers are used to decouple rendering behavior from the +/// validation errors controls such as and +/// . +/// +/// +/// This allows users to change how validation errors are rendered by simply pluggin in +/// appropriate renderer implementation into the validation errors controls using +/// Spring.NET dependency injection. +/// +/// +/// Aleksandar Seovic +public interface IValidationErrorsRenderer { /// - /// This interface should be implemented by all validation errors renderers. + /// Renders validation errors using specified . /// - /// - /// - /// Validation errors renderers are used to decouple rendering behavior from the - /// validation errors controls such as and - /// . - /// - /// - /// This allows users to change how validation errors are rendered by simply pluggin in - /// appropriate renderer implementation into the validation errors controls using - /// Spring.NET dependency injection. - /// - /// - /// Aleksandar Seovic - public interface IValidationErrorsRenderer - { - /// - /// Renders validation errors using specified . - /// - /// Web form instance. - /// An HTML writer to use. - /// The list of validation errors. - void RenderErrors(Page page, HtmlTextWriter writer, IList errors); - } + /// Web form instance. + /// An HTML writer to use. + /// The list of validation errors. + void RenderErrors(Page page, HtmlTextWriter writer, IList errors); } diff --git a/src/Spring/Spring.Web/Web/UI/Validation/IconValidationErrorsRenderer.cs b/src/Spring/Spring.Web/Web/UI/Validation/IconValidationErrorsRenderer.cs index 1dca5e27..1e51b7f9 100644 --- a/src/Spring/Spring.Web/Web/UI/Validation/IconValidationErrorsRenderer.cs +++ b/src/Spring/Spring.Web/Web/UI/Validation/IconValidationErrorsRenderer.cs @@ -21,62 +21,62 @@ using System.Text; using System.Web.UI; -namespace Spring.Web.UI.Validation +namespace Spring.Web.UI.Validation; + +/// +/// Implementation of that +/// displays an error image to let user know there is an error, and +/// tooltip to display actual error messages. +/// +/// +/// +/// This renderer's behavior is similar to Windows Forms error provider. +/// +/// +/// Aleksandar Seovic +public class IconValidationErrorsRenderer : AbstractValidationErrorsRenderer { + private string iconSrc; + /// - /// Implementation of that - /// displays an error image to let user know there is an error, and - /// tooltip to display actual error messages. + /// Gets or sets the name of the image file to use as an error icon. /// /// /// - /// This renderer's behavior is similar to Windows Forms error provider. + /// Image name should be relative to the value of the + /// property, and should not use leading path separator. /// /// - /// Aleksandar Seovic - public class IconValidationErrorsRenderer : AbstractValidationErrorsRenderer + /// The name of the image file to use as an error icon. + public string IconSrc { - private string iconSrc; + get { return this.iconSrc; } + set { this.iconSrc = value; } + } - /// - /// Gets or sets the name of the image file to use as an error icon. - /// - /// - /// - /// Image name should be relative to the value of the - /// property, and should not use leading path separator. - /// - /// - /// The name of the image file to use as an error icon. - public string IconSrc + /// + /// Renders validation errors using specified . + /// + /// Web form instance. + /// An HTML writer to use. + /// The list of validation errors. + public override void RenderErrors(Page page, HtmlTextWriter writer, IList errors) + { + if (errors != null && errors.Count > 0) { - get { return this.iconSrc; } - set { this.iconSrc = value; } - } - - /// - /// Renders validation errors using specified . - /// - /// Web form instance. - /// An HTML writer to use. - /// The list of validation errors. - public override void RenderErrors(Page page, HtmlTextWriter writer, IList errors) - { - if (errors != null && errors.Count > 0) + StringBuilder sb = new StringBuilder(); + string separator = ""; + foreach (string error in errors) { - StringBuilder sb = new StringBuilder(); - string separator = ""; - foreach (string error in errors) - { - sb.Append(separator).Append(error); - separator = "\n"; - } - writer.AddAttribute(HtmlTextWriterAttribute.Src, page.ImagesRoot + "/" + IconSrc); - writer.AddAttribute(HtmlTextWriterAttribute.Title, sb.ToString()); - - writer.RenderBeginTag(HtmlTextWriterTag.Img); - writer.RenderEndTag(); + sb.Append(separator).Append(error); + separator = "\n"; } + + writer.AddAttribute(HtmlTextWriterAttribute.Src, page.ImagesRoot + "/" + IconSrc); + writer.AddAttribute(HtmlTextWriterAttribute.Title, sb.ToString()); + + writer.RenderBeginTag(HtmlTextWriterTag.Img); + writer.RenderEndTag(); } } } diff --git a/src/Spring/Spring.Web/Web/UI/Validation/SpanValidationErrorsRenderer.cs b/src/Spring/Spring.Web/Web/UI/Validation/SpanValidationErrorsRenderer.cs index 92fd47ae..863d6326 100644 --- a/src/Spring/Spring.Web/Web/UI/Validation/SpanValidationErrorsRenderer.cs +++ b/src/Spring/Spring.Web/Web/UI/Validation/SpanValidationErrorsRenderer.cs @@ -19,49 +19,47 @@ #endregion using System.Web.UI; - using Spring.Web.UI.Controls; -namespace Spring.Web.UI.Validation +namespace Spring.Web.UI.Validation; + +/// +/// Implementation of that renders +/// validation errors within a span element, using breaks between the +/// errors. +/// +/// +/// This renderer's behavior is consistent with standard ASP.NET behavior of +/// the control validators, and is used as the default renderer for Spring.NET +/// control. +/// +/// Aleksandar Seovic +public class SpanValidationErrorsRenderer : AbstractValidationErrorsRenderer { /// - /// Implementation of that renders - /// validation errors within a span element, using breaks between the - /// errors. + /// Renders validation errors using specified . /// - /// - /// This renderer's behavior is consistent with standard ASP.NET behavior of - /// the control validators, and is used as the default renderer for Spring.NET - /// control. - /// - /// Aleksandar Seovic - public class SpanValidationErrorsRenderer : AbstractValidationErrorsRenderer + /// Web form instance. + /// An HTML writer to use. + /// The list of validation errors. + public override void RenderErrors(Page page, HtmlTextWriter writer, IList errors) { - /// - /// Renders validation errors using specified . - /// - /// Web form instance. - /// An HTML writer to use. - /// The list of validation errors. - public override void RenderErrors(Page page, HtmlTextWriter writer, IList errors) + if (errors != null && errors.Count > 0) { - if (errors != null && errors.Count > 0) + if (CssClass != null) { - if (CssClass != null) - { - writer.AddAttribute(HtmlTextWriterAttribute.Class, CssClass); - } - - writer.RenderBeginTag(HtmlTextWriterTag.Span); - - foreach (string error in errors) - { - writer.Write(error); - writer.Write(" "); - } - writer.RenderEndTag(); - + writer.AddAttribute(HtmlTextWriterAttribute.Class, CssClass); } + + writer.RenderBeginTag(HtmlTextWriterTag.Span); + + foreach (string error in errors) + { + writer.Write(error); + writer.Write(" "); + } + + writer.RenderEndTag(); } } } diff --git a/test/Directory.Build.props b/test/Directory.Build.props index 4fad41e8..afbc50b3 100644 --- a/test/Directory.Build.props +++ b/test/Directory.Build.props @@ -42,7 +42,7 @@ true TRACE;$(DefineConstants) - + diff --git a/test/Spring/Spring.Aop.Tests/Aop/Advice/DebugAdvice.cs b/test/Spring/Spring.Aop.Tests/Aop/Advice/DebugAdvice.cs index bec0ddd7..5ea8ee4d 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Advice/DebugAdvice.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Advice/DebugAdvice.cs @@ -20,67 +20,66 @@ using AopAlliance.Intercept; -namespace Spring.Aop.Advice +namespace Spring.Aop.Advice; + +/// +/// Convenience +/// implementation that displays verbose information about intercepted +/// invocations to the system console. +/// +/// +///

+/// Can be introduced into an interceptor chain to serve as a useful low +/// level debugging aid. +///

+///
+/// Rod Johnson +/// Federico Spinazzi (.NET) +/// Aleksandar Seovic (.NET) +/// +public sealed class DebugAdvice : IMethodInterceptor { - /// - /// Convenience - /// implementation that displays verbose information about intercepted - /// invocations to the system console. - /// - /// - ///

- /// Can be introduced into an interceptor chain to serve as a useful low - /// level debugging aid. - ///

- ///
- /// Rod Johnson - /// Federico Spinazzi (.NET) - /// Aleksandar Seovic (.NET) - /// - public sealed class DebugAdvice : IMethodInterceptor - { - private int _count; + private int _count; - /// - /// Gets the count of the number of times this interceptor has been - /// invoked. - /// - /// - /// The count of the number of times this interceptor has been invoked. - /// - public int Count - { - get { return _count; } - } + /// + /// Gets the count of the number of times this interceptor has been + /// invoked. + /// + /// + /// The count of the number of times this interceptor has been invoked. + /// + public int Count + { + get { return _count; } + } - /// - /// Displays verbose information about intercepted invocations to the - /// system console. - /// - /// - /// The method invocation that is being intercepted. - /// - /// - /// The result of the call to the - /// method of - /// the supplied ; this return value may - /// well have been intercepted by the interceptor. - /// - /// - /// If any of the interceptors in the chain or the target object itself - /// throws an exception. - /// - /// - /// - public object Invoke(IMethodInvocation invocation) - { - ++_count; - Console.Out.WriteLine("{0} [count={1}, invocation='{2}']", - typeof(DebugAdvice).Name, _count, invocation); - object returnValue = invocation.Proceed(); - Console.Out.WriteLine("{0} ['{1}' invocation returned '{2}']", - typeof(DebugAdvice).Name, invocation.Method.Name, returnValue); - return returnValue; - } - } + /// + /// Displays verbose information about intercepted invocations to the + /// system console. + /// + /// + /// The method invocation that is being intercepted. + /// + /// + /// The result of the call to the + /// method of + /// the supplied ; this return value may + /// well have been intercepted by the interceptor. + /// + /// + /// If any of the interceptors in the chain or the target object itself + /// throws an exception. + /// + /// + /// + public object Invoke(IMethodInvocation invocation) + { + ++_count; + Console.Out.WriteLine("{0} [count={1}, invocation='{2}']", + typeof(DebugAdvice).Name, _count, invocation); + object returnValue = invocation.Proceed(); + Console.Out.WriteLine("{0} ['{1}' invocation returned '{2}']", + typeof(DebugAdvice).Name, invocation.Method.Name, returnValue); + return returnValue; + } } diff --git a/test/Spring/Spring.Aop.Tests/Aop/Config/AopNamespaceParserTests.cs b/test/Spring/Spring.Aop.Tests/Aop/Config/AopNamespaceParserTests.cs index 72669c2a..add89860 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Config/AopNamespaceParserTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Config/AopNamespaceParserTests.cs @@ -19,80 +19,68 @@ #endregion using NUnit.Framework; - using Spring.Aop.Framework; using Spring.Context; using Spring.Context.Support; using Spring.Objects; using Spring.Objects.Factory.Xml; -namespace Spring.Aop.Config +namespace Spring.Aop.Config; + +/// +/// This class contains tests for the custom aop namespace. +/// +/// Mark Pollack +[TestFixture] +public class AopNamespaceParserTests { - /// - /// This class contains tests for the custom aop namespace. - /// - /// Mark Pollack - [TestFixture] - public class AopNamespaceParserTests + private IApplicationContext ctx; + + [SetUp] + public void Setup() { + // IS WELLKNOWN NOW + //NamespaceParserRegistry.RegisterParser(typeof(AopNamespaceParser)); + //ctx = new XmlApplicationContext( "assembly://Spring.Aop.Tests/Spring.Aop.Config/AopNamespaceParserTests.xml"); + ctx = new XmlApplicationContext(ReadOnlyXmlTestResource.GetFilePath("AopNamespaceParserTests.xml", this.GetType())); + } - private IApplicationContext ctx; + [Test] + public void Registered() + { + Assert.IsNotNull(NamespaceParserRegistry.GetParser("http://www.springframework.net/aop")); - [SetUp] - public void Setup() - { - // IS WELLKNOWN NOW - //NamespaceParserRegistry.RegisterParser(typeof(AopNamespaceParser)); - //ctx = new XmlApplicationContext( "assembly://Spring.Aop.Tests/Spring.Aop.Config/AopNamespaceParserTests.xml"); - ctx = new XmlApplicationContext(ReadOnlyXmlTestResource.GetFilePath("AopNamespaceParserTests.xml", this.GetType())); - } + IPointcut pointcut = ctx["getDescriptionCalls"] as IPointcut; + Assert.IsNotNull(pointcut); + Assert.IsFalse(AopUtils.IsAopProxy(pointcut)); + ITestObject testObject = ctx["testObject"] as ITestObject; + Assert.IsNotNull(testObject); + Assert.IsTrue(AopUtils.IsAopProxy(testObject), "Object should be an AOP proxy"); + IAdvised advised = testObject as IAdvised; + Assert.IsNotNull(advised); + IList advisors = advised.Advisors; + Assert.IsTrue(advisors.Count > 0, "Advisors should not be empty"); + } - [Test] - public void Registered() - { - Assert.IsNotNull(NamespaceParserRegistry.GetParser("http://www.springframework.net/aop")); + [Test] + public void AdviceInvokedCorrectly() + { + CountingBeforeAdvice getDescriptionCounter = ctx.GetObject("getDescriptionCounter") as CountingBeforeAdvice; + Assert.IsNotNull(getDescriptionCounter); + ITestObject testObject = GetTestObject(); - IPointcut pointcut = ctx["getDescriptionCalls"] as IPointcut; - Assert.IsNotNull(pointcut); - Assert.IsFalse(AopUtils.IsAopProxy(pointcut)); + Assert.AreEqual(0, getDescriptionCounter.GetCalls("GetDescription"), "Incorrect initial getDescription count"); + testObject.GetDescription(); - ITestObject testObject = ctx["testObject"] as ITestObject; - Assert.IsNotNull(testObject); - Assert.IsTrue(AopUtils.IsAopProxy(testObject), "Object should be an AOP proxy"); - - IAdvised advised = testObject as IAdvised; - Assert.IsNotNull(advised); - IList advisors = advised.Advisors; - Assert.IsTrue(advisors.Count > 0, "Advisors should not be empty"); - - - } - - [Test] - public void AdviceInvokedCorrectly() - { - CountingBeforeAdvice getDescriptionCounter = ctx.GetObject("getDescriptionCounter") as CountingBeforeAdvice; - Assert.IsNotNull(getDescriptionCounter); - - ITestObject testObject = GetTestObject(); - - Assert.AreEqual(0,getDescriptionCounter.GetCalls("GetDescription"),"Incorrect initial getDescription count"); - - testObject.GetDescription(); - - Assert.AreEqual(1, getDescriptionCounter.GetCalls("GetDescription"), "Incorrect getDescription count"); - - } - - private ITestObject GetTestObject() - { - return ctx.GetObject("testObject", typeof (ITestObject)) as ITestObject; - } - + Assert.AreEqual(1, getDescriptionCounter.GetCalls("GetDescription"), "Incorrect getDescription count"); + } + private ITestObject GetTestObject() + { + return ctx.GetObject("testObject", typeof(ITestObject)) as ITestObject; } } diff --git a/test/Spring/Spring.Aop.Tests/Aop/Config/AopNamespaceParserTests.xml b/test/Spring/Spring.Aop.Tests/Aop/Config/AopNamespaceParserTests.xml index 33d3bf00..f26985b7 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Config/AopNamespaceParserTests.xml +++ b/test/Spring/Spring.Aop.Tests/Aop/Config/AopNamespaceParserTests.xml @@ -1,26 +1,25 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:aop="http://www.springframework.net/aop"> - + - + - + - - - - .*GetDescription.* - - - - - + + + + .*GetDescription.* + + + - - + + + diff --git a/test/Spring/Spring.Aop.Tests/Aop/Framework/AbstractMethodInvocationTests.cs b/test/Spring/Spring.Aop.Tests/Aop/Framework/AbstractMethodInvocationTests.cs index 3726b2fe..cbf2d574 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Framework/AbstractMethodInvocationTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Framework/AbstractMethodInvocationTests.cs @@ -21,221 +21,218 @@ using System.Collections; using System.Globalization; using System.Reflection; - using AopAlliance.Intercept; - using FakeItEasy; - using NUnit.Framework; -namespace Spring.Aop.Framework +namespace Spring.Aop.Framework; + +/// +/// Unit tests for the AbstractMethodInvocation class. +/// +/// Rick Evans +/// Bruno Baia +[TestFixture] +public abstract class AbstractMethodInvocationTests { - /// - /// Unit tests for the AbstractMethodInvocation class. - /// - /// Rick Evans - /// Bruno Baia - [TestFixture] - public abstract class AbstractMethodInvocationTests - { - [SetUp] - public virtual void SetUp() + [SetUp] + public virtual void SetUp() + { + } + + protected abstract AbstractMethodInvocation CreateMethodInvocation( + object proxy, object target, MethodInfo method, MethodInfo onProxyMethod, + object[] arguments, Type targetType, IList interceptors); + + [Test] + public void InstantiationWithNullMethod() + { + Assert.Throws(() => CreateMethodInvocation(null, this, null, null, null, GetType(), null)); + } + + [Test] + public void InstantiationWithNullTarget() + { + Assert.Throws(() => CreateMethodInvocation(null, null, null, null, null, GetType(), null)); + } + + [Test] + public void ProceedWithNullInterceptorChain() + { + Target target = new Target(); + AbstractMethodInvocation join = CreateMethodInvocation( + null, target, target.GetTargetMethodNoArgs(), null, null, target.GetType(), null); + string score = (string) join.Proceed(); + Assert.AreEqual(Target.DefaultScore + Target.Suffix, score); + } + + [Test] + public void ProceedWithEmptyInterceptorChain() + { + Target target = new Target(); + AbstractMethodInvocation join = CreateMethodInvocation( + null, target, target.GetTargetMethodNoArgs(), null, null, target.GetType(), new ArrayList()); + string score = (string) join.Proceed(); + Assert.AreEqual(Target.DefaultScore + Target.Suffix, score); + } + + [Test] + public void ToStringWithoutArguments() + { + Target target = new Target(); + AbstractMethodInvocation join = CreateMethodInvocation( + null, target, target.GetTargetMethodNoArgs(), null, null, target.GetType(), new ArrayList()); + CheckToStringDoesntThrowAnException(join); + } + + [Test] + public void ToStringWithArguments() + { + Target target = new Target(); + AbstractMethodInvocation join = CreateMethodInvocation( + null, target, target.GetTargetMethod(), null, new string[] { "Five" }, target.GetType(), new ArrayList()); + CheckToStringDoesntThrowAnException(join); + } + + [Test] + public void ToStringMustNotInvokeToStringOnTarget() + { + Target target = new TargetWithBadToString(); + AbstractMethodInvocation join = CreateMethodInvocation( + null, target, target.GetTargetMethodNoArgs(), null, null, target.GetType(), new ArrayList()); + // if it hits the target the test will fail with NotSupportedException... + CheckToStringDoesntThrowAnException(join); + } + + private static string CheckToStringDoesntThrowAnException(AbstractMethodInvocation join) + { + return join.ToString(); + } + + public class Target + { + public const string Suffix = "!!!"; + public const string DefaultScore = "ONE HUNDRED AND EIGHTY"; + + public MethodInfo GetTargetMethodNoArgs() { + return GetType().GetMethod("BullseyeMethod", Type.EmptyTypes); } - protected abstract AbstractMethodInvocation CreateMethodInvocation( - object proxy, object target, MethodInfo method, MethodInfo onProxyMethod, - object[] arguments, Type targetType, IList interceptors); + public MethodInfo GetTargetMethod() + { + return GetType().GetMethod("BullseyeMethod", new Type[] { typeof(string) }); + } - [Test] - public void InstantiationWithNullMethod() - { - Assert.Throws(() => CreateMethodInvocation(null, this, null, null, null, GetType(), null)); - } + public string BullseyeMethod() + { + return BullseyeMethod(DefaultScore); + } - [Test] - public void InstantiationWithNullTarget() - { - Assert.Throws(() => CreateMethodInvocation(null, null, null, null, null, GetType(), null)); - } + public string BullseyeMethod(string score) + { + return score + Suffix; + } + } - [Test] - public void ProceedWithNullInterceptorChain() - { - Target target = new Target(); - AbstractMethodInvocation join = CreateMethodInvocation( - null, target, target.GetTargetMethodNoArgs(), null, null, target.GetType(), null); - string score = (string) join.Proceed(); - Assert.AreEqual(Target.DefaultScore + Target.Suffix, score); - } + public interface ICommand + { + void Execute(); + } - [Test] - public void ProceedWithEmptyInterceptorChain() - { - Target target = new Target(); - AbstractMethodInvocation join = CreateMethodInvocation( - null, target, target.GetTargetMethodNoArgs(), null, null, target.GetType(), new ArrayList()); - string score = (string) join.Proceed(); - Assert.AreEqual(Target.DefaultScore + Target.Suffix, score); - } + public sealed class BadCommand : ICommand + { + public void Execute() + { + throw new NotImplementedException(); + } - [Test] - public void ToStringWithoutArguments() - { - Target target = new Target(); - AbstractMethodInvocation join = CreateMethodInvocation( - null, target, target.GetTargetMethodNoArgs(), null, null, target.GetType(), new ArrayList()); - CheckToStringDoesntThrowAnException(join); - } + public MethodInfo GetTargetMethod() + { + return GetType().GetMethod("Execute", Type.EmptyTypes); + } + } - [Test] - public void ToStringWithArguments() - { - Target target = new Target(); - AbstractMethodInvocation join = CreateMethodInvocation( - null, target, target.GetTargetMethod(), null, new string[] { "Five" }, target.GetType(), new ArrayList()); - CheckToStringDoesntThrowAnException(join); - } + private sealed class TargetWithBadToString : Target + { + public override string ToString() + { + throw new NotSupportedException("ToString"); + } + } - [Test] - public void ToStringMustNotInvokeToStringOnTarget() - { - Target target = new TargetWithBadToString(); - AbstractMethodInvocation join = CreateMethodInvocation( - null, target, target.GetTargetMethodNoArgs(), null, null, target.GetType(), new ArrayList()); - // if it hits the target the test will fail with NotSupportedException... - CheckToStringDoesntThrowAnException(join); - } - - private static string CheckToStringDoesntThrowAnException(AbstractMethodInvocation join) - { - return join.ToString(); - } - - public class Target - { - public const string Suffix = "!!!"; - public const string DefaultScore = "ONE HUNDRED AND EIGHTY"; - - public MethodInfo GetTargetMethodNoArgs() - { - return GetType().GetMethod("BullseyeMethod", Type.EmptyTypes); - } - - public MethodInfo GetTargetMethod() - { - return GetType().GetMethod("BullseyeMethod", new Type[] {typeof (string)}); - } - - public string BullseyeMethod() - { - return BullseyeMethod(DefaultScore); - } - - public string BullseyeMethod(string score) - { - return score + Suffix; - } - } - - public interface ICommand - { - void Execute(); - } - - public sealed class BadCommand : ICommand - { - public void Execute() - { - throw new NotImplementedException(); - } - - public MethodInfo GetTargetMethod() - { - return GetType().GetMethod("Execute", Type.EmptyTypes); - } - } - - private sealed class TargetWithBadToString : Target - { - public override string ToString() - { - throw new NotSupportedException("ToString"); - } - } - - [Test] - public void ValidInvocation() - {/* - Target target = new Target(); + [Test] + public void ValidInvocation() + { + /* + Target target = new Target(); MockRepository repository = new MockRepository(); - IMethodInterceptor interceptor = (IMethodInterceptor) repository.CreateMock(typeof (IMethodInterceptor)); + IMethodInterceptor interceptor = (IMethodInterceptor) repository.CreateMock(typeof (IMethodInterceptor)); AbstractMethodInvocation join = CreateMethodInvocation( null, target, target.GetTargetMethodNoArgs(), null, null, target.GetType(), new object[] { interceptor }); - Expect.Call(interceptor.Invoke(join)).Returns(target.BullseyeMethod().ToLower(CultureInfo.InvariantCulture)); + Expect.Call(interceptor.Invoke(join)).Returns(target.BullseyeMethod().ToLower(CultureInfo.InvariantCulture)); repository.ReplayAll(); - string score = (string) join.Proceed(); + string score = (string) join.Proceed(); Assert.AreEqual(target.BullseyeMethod().ToLower(CultureInfo.InvariantCulture) + Target.Suffix, score); repository.VerifyAll(); */ - Target target = new Target(); - IMethodInterceptor mock = A.Fake(); - AbstractMethodInvocation join = CreateMethodInvocation( - null, target, target.GetTargetMethodNoArgs(), null, null, target.GetType(), new object[] { mock }); + Target target = new Target(); + IMethodInterceptor mock = A.Fake(); + AbstractMethodInvocation join = CreateMethodInvocation( + null, target, target.GetTargetMethodNoArgs(), null, null, target.GetType(), new object[] { mock }); - A.CallTo(() => mock.Invoke(null)).WithAnyArguments().Returns(target.BullseyeMethod().ToLower(CultureInfo.InvariantCulture)); + A.CallTo(() => mock.Invoke(null)).WithAnyArguments().Returns(target.BullseyeMethod().ToLower(CultureInfo.InvariantCulture)); - string score = (string) join.Proceed(); - Assert.AreEqual(Target.DefaultScore.ToLower(CultureInfo.InvariantCulture) + Target.Suffix, score); - } + string score = (string) join.Proceed(); + Assert.AreEqual(Target.DefaultScore.ToLower(CultureInfo.InvariantCulture) + Target.Suffix, score); + } - [Test] - public void UnwrapsTargetInvocationException_NoInterceptors() - { - BadCommand target = new BadCommand(); - AbstractMethodInvocation join = CreateMethodInvocation( - null, target, target.GetTargetMethod(), null, null, target.GetType(), new object[] { }); - try - { - join.Proceed(); - } - catch (NotImplementedException) - { - // this is good, we want this exception to bubble up... - } - catch (TargetInvocationException) - { - Assert.Fail("Must have unwrapped this."); - } - } + [Test] + public void UnwrapsTargetInvocationException_NoInterceptors() + { + BadCommand target = new BadCommand(); + AbstractMethodInvocation join = CreateMethodInvocation( + null, target, target.GetTargetMethod(), null, null, target.GetType(), new object[] { }); + try + { + join.Proceed(); + } + catch (NotImplementedException) + { + // this is good, we want this exception to bubble up... + } + catch (TargetInvocationException) + { + Assert.Fail("Must have unwrapped this."); + } + } - [Test] - public void UnwrapsTargetInvocationException_WithInterceptor() - { - BadCommand target = new BadCommand(); - IMethodInterceptor mock = A.Fake(); - AbstractMethodInvocation join = CreateMethodInvocation( - null, target, target.GetTargetMethod(), null, null, target.GetType(), new object[] {mock}); + [Test] + public void UnwrapsTargetInvocationException_WithInterceptor() + { + BadCommand target = new BadCommand(); + IMethodInterceptor mock = A.Fake(); + AbstractMethodInvocation join = CreateMethodInvocation( + null, target, target.GetTargetMethod(), null, null, target.GetType(), new object[] { mock }); - A.CallTo(() => mock.Invoke(null)).WithAnyArguments().Throws(); + A.CallTo(() => mock.Invoke(null)).WithAnyArguments().Throws(); - // we want this exception to bubble up... - Assert.Throws(() => join.Proceed()); - } + // we want this exception to bubble up... + Assert.Throws(() => join.Proceed()); + } - [Test] - public void UnwrapsTargetInvocationException_WithInterceptorThatThrowsAnException() - { - BadCommand target = new BadCommand(); - IMethodInterceptor mock = A.Fake(); - AbstractMethodInvocation join = CreateMethodInvocation( - null, target, target.GetTargetMethod(), null, null, target.GetType(), new object[] { mock }); + [Test] + public void UnwrapsTargetInvocationException_WithInterceptorThatThrowsAnException() + { + BadCommand target = new BadCommand(); + IMethodInterceptor mock = A.Fake(); + AbstractMethodInvocation join = CreateMethodInvocation( + null, target, target.GetTargetMethod(), null, null, target.GetType(), new object[] { mock }); - A.CallTo(() => mock.Invoke(null)).WithAnyArguments().Throws(); + A.CallTo(() => mock.Invoke(null)).WithAnyArguments().Throws(); - // we want this exception to bubble up... - Assert.Throws(() => join.Proceed()); - } - } -} \ No newline at end of file + // we want this exception to bubble up... + Assert.Throws(() => join.Proceed()); + } +} diff --git a/test/Spring/Spring.Aop.Tests/Aop/Framework/Adapter/AdvisorAdapterRegistrationTests.cs b/test/Spring/Spring.Aop.Tests/Aop/Framework/Adapter/AdvisorAdapterRegistrationTests.cs index fe0e9b18..0a6f0d55 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Framework/Adapter/AdvisorAdapterRegistrationTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Framework/Adapter/AdvisorAdapterRegistrationTests.cs @@ -1,4 +1,5 @@ #region License + /* * Copyright 2002-2010 the original author or authors. * @@ -14,67 +15,66 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + #endregion using NUnit.Framework; - using Spring.Context; using Spring.Context.Support; using Spring.Objects; using Spring.Objects.Factory.Xml; -namespace Spring.Aop.Framework.Adapter +namespace Spring.Aop.Framework.Adapter; + +/// +/// TestCase for AdvisorAdapterRegistrationManager mechanism. +/// +/// Dmitriy Kopylenko +/// Simon White (.NET) +[Platform("Win")] +public class AdvisorAdapterRegistrationTests { - /// - /// TestCase for AdvisorAdapterRegistrationManager mechanism. - /// - /// Dmitriy Kopylenko - /// Simon White (.NET) - [Platform("Win")] - public class AdvisorAdapterRegistrationTests - { - [Test] - public void AdvisorAdapterRegistrationManagerNotPresentInContext() - { - string configLocation = ReadOnlyXmlTestResource.GetFilePath("withoutBPPContext.xml", typeof(AdvisorAdapterRegistrationTests)); - IApplicationContext ctx = new XmlApplicationContext(configLocation); - ITestObject to = (ITestObject) ctx.GetObject("testObject"); - // just invoke any method to see if advice fired - try - { - to.ReturnsThis(); - Assert.Fail("Should throw UnknownAdviceTypeException"); - } - catch (UnknownAdviceTypeException) - { - // expected - Assert.AreEqual(0, GetAdviceImpl(to).InvocationCounter); - } - } + [Test] + public void AdvisorAdapterRegistrationManagerNotPresentInContext() + { + string configLocation = ReadOnlyXmlTestResource.GetFilePath("withoutBPPContext.xml", typeof(AdvisorAdapterRegistrationTests)); + IApplicationContext ctx = new XmlApplicationContext(configLocation); + ITestObject to = (ITestObject) ctx.GetObject("testObject"); + // just invoke any method to see if advice fired + try + { + to.ReturnsThis(); + Assert.Fail("Should throw UnknownAdviceTypeException"); + } + catch (UnknownAdviceTypeException) + { + // expected + Assert.AreEqual(0, GetAdviceImpl(to).InvocationCounter); + } + } - [Test] - public void AdvisorAdapterRegistrationManagerPresentInContext() - { - string configLocation = ReadOnlyXmlTestResource.GetFilePath("withBPPContext.xml", typeof(AdvisorAdapterRegistrationTests)); - IApplicationContext ctx = new XmlApplicationContext(configLocation); - ITestObject to = (ITestObject) ctx.GetObject("testObject"); - // just invoke any method to see if advice fired - try - { - to.ReturnsThis(); - Assert.AreEqual(1, GetAdviceImpl(to).InvocationCounter); - } - catch (UnknownAdviceTypeException) - { - Assert.Fail("Should not throw UnknownAdviceTypeException"); - } - } + [Test] + public void AdvisorAdapterRegistrationManagerPresentInContext() + { + string configLocation = ReadOnlyXmlTestResource.GetFilePath("withBPPContext.xml", typeof(AdvisorAdapterRegistrationTests)); + IApplicationContext ctx = new XmlApplicationContext(configLocation); + ITestObject to = (ITestObject) ctx.GetObject("testObject"); + // just invoke any method to see if advice fired + try + { + to.ReturnsThis(); + Assert.AreEqual(1, GetAdviceImpl(to).InvocationCounter); + } + catch (UnknownAdviceTypeException) + { + Assert.Fail("Should not throw UnknownAdviceTypeException"); + } + } - private SimpleBeforeAdviceImpl GetAdviceImpl(ITestObject to) - { - IAdvised advised = (IAdvised) to; - IAdvisor advisor = advised.Advisors[0]; - return (SimpleBeforeAdviceImpl) advisor.Advice; - } - } + private SimpleBeforeAdviceImpl GetAdviceImpl(ITestObject to) + { + IAdvised advised = (IAdvised) to; + IAdvisor advisor = advised.Advisors[0]; + return (SimpleBeforeAdviceImpl) advisor.Advice; + } } diff --git a/test/Spring/Spring.Aop.Tests/Aop/Framework/Adapter/AfterReturningAdviceInterceptorTests.cs b/test/Spring/Spring.Aop.Tests/Aop/Framework/Adapter/AfterReturningAdviceInterceptorTests.cs index 81028446..e65fb11d 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Framework/Adapter/AfterReturningAdviceInterceptorTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Framework/Adapter/AfterReturningAdviceInterceptorTests.cs @@ -21,68 +21,66 @@ using AopAlliance.Intercept; using FakeItEasy; using NUnit.Framework; - using Spring.Util; -namespace Spring.Aop.Framework.Adapter +namespace Spring.Aop.Framework.Adapter; + +/// +/// Unit tests for the AfterReturningAdviceInterceptor class. +/// +/// Rod Johnson +/// Simon White (.NET) +[TestFixture] +public sealed class AfterReturningAdviceInterceptorTests { - /// - /// Unit tests for the AfterReturningAdviceInterceptor class. - /// - /// Rod Johnson - /// Simon White (.NET) - [TestFixture] - public sealed class AfterReturningAdviceInterceptorTests + [Test] + public void PassNullAdviceToCtor() { - [Test] - public void PassNullAdviceToCtor() + Assert.Throws(() => new AfterReturningAdviceInterceptor(null)); + } + + [Test] + public void IsNotInvokedIfServiceObjectThrowsException() + { + IMethodInvocation mockInvocation = A.Fake(); + IAfterReturningAdvice mockAdvice = A.Fake(); + + A.CallTo(() => mockAdvice.AfterReturning(null, null, null, null)).WithAnyArguments().Throws(); + A.CallTo(() => mockInvocation.Method).Returns(ReflectionUtils.GetMethod(typeof(object), "HashCode", new Type[] { })); + A.CallTo(() => mockInvocation.Arguments).Returns(null); + A.CallTo(() => mockInvocation.This).Returns(new object()); + A.CallTo(() => mockInvocation.Proceed()).Returns(null); + + try { - Assert.Throws(() => new AfterReturningAdviceInterceptor(null)); + AfterReturningAdviceInterceptor interceptor = new AfterReturningAdviceInterceptor(mockAdvice); + interceptor.Invoke(mockInvocation); + Assert.Fail("Must have thrown a FormatException by this point."); } - - [Test] - public void IsNotInvokedIfServiceObjectThrowsException() + catch (FormatException) { - IMethodInvocation mockInvocation = A.Fake(); - IAfterReturningAdvice mockAdvice = A.Fake(); - - A.CallTo(() => mockAdvice.AfterReturning(null, null, null, null)).WithAnyArguments().Throws(); - A.CallTo(() => mockInvocation.Method).Returns(ReflectionUtils.GetMethod(typeof(object), "HashCode", new Type[] { })); - A.CallTo(() => mockInvocation.Arguments).Returns(null); - A.CallTo(() => mockInvocation.This).Returns(new object()); - A.CallTo(() => mockInvocation.Proceed()).Returns(null); - - try - { - AfterReturningAdviceInterceptor interceptor = new AfterReturningAdviceInterceptor(mockAdvice); - interceptor.Invoke(mockInvocation); - Assert.Fail("Must have thrown a FormatException by this point."); - } - catch (FormatException) - { - } - } - - [Test] - public void JustPassesAfterReturningAdviceExceptionUpWithoutAnyWrapping() - { - IMethodInvocation mockInvocation = A.Fake(); - IAfterReturningAdvice mockAdvice = A.Fake(); - A.CallTo(() => mockAdvice.AfterReturning(null, null, null, null)).WithAnyArguments().Throws(); - - A.CallTo(() => mockInvocation.Method).Returns(ReflectionUtils.GetMethod(typeof(object), "HashCode", new Type[] { })); - A.CallTo(() => mockInvocation.Arguments).Returns(null); - A.CallTo(() => mockInvocation.This).Returns(new object()); - A.CallTo(() => mockInvocation.Proceed()).Returns(null); - try - { - AfterReturningAdviceInterceptor interceptor = new AfterReturningAdviceInterceptor(mockAdvice); - interceptor.Invoke(mockInvocation); - Assert.Fail("Must have thrown a FormatException by this point."); - } - catch (FormatException) - { - } } } -} \ No newline at end of file + + [Test] + public void JustPassesAfterReturningAdviceExceptionUpWithoutAnyWrapping() + { + IMethodInvocation mockInvocation = A.Fake(); + IAfterReturningAdvice mockAdvice = A.Fake(); + A.CallTo(() => mockAdvice.AfterReturning(null, null, null, null)).WithAnyArguments().Throws(); + + A.CallTo(() => mockInvocation.Method).Returns(ReflectionUtils.GetMethod(typeof(object), "HashCode", new Type[] { })); + A.CallTo(() => mockInvocation.Arguments).Returns(null); + A.CallTo(() => mockInvocation.This).Returns(new object()); + A.CallTo(() => mockInvocation.Proceed()).Returns(null); + try + { + AfterReturningAdviceInterceptor interceptor = new AfterReturningAdviceInterceptor(mockAdvice); + interceptor.Invoke(mockInvocation); + Assert.Fail("Must have thrown a FormatException by this point."); + } + catch (FormatException) + { + } + } +} diff --git a/test/Spring/Spring.Aop.Tests/Aop/Framework/Adapter/ThrowsAdviceInterceptorTests.cs b/test/Spring/Spring.Aop.Tests/Aop/Framework/Adapter/ThrowsAdviceInterceptorTests.cs index 87b50d04..485b1bb4 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Framework/Adapter/ThrowsAdviceInterceptorTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Framework/Adapter/ThrowsAdviceInterceptorTests.cs @@ -21,258 +21,257 @@ using System.Reflection; using System.Runtime.Remoting; using System.Web; - using AopAlliance.Intercept; - using FakeItEasy; - using NUnit.Framework; - using Spring.Util; -namespace Spring.Aop.Framework.Adapter +namespace Spring.Aop.Framework.Adapter; + +/// +/// Unit tests for the ThrowsAdviceInterceptor class. +/// +/// Rod Johnson +/// Simon White (.NET) +[TestFixture] +public sealed partial class ThrowsAdviceInterceptorTests { - /// - /// Unit tests for the ThrowsAdviceInterceptor class. - /// - /// Rod Johnson - /// Simon White (.NET) - [TestFixture] - public sealed partial class ThrowsAdviceInterceptorTests - { - [Test] - public void NoHandlerMethods() - { - Assert.Throws(() => new ThrowsAdviceInterceptor(new object())); - } + [Test] + public void NoHandlerMethods() + { + Assert.Throws(() => new ThrowsAdviceInterceptor(new object())); + } - [Test] - public void PassNullAdviceToCtor() + [Test] + public void PassNullAdviceToCtor() + { + Assert.Throws(() => new ThrowsAdviceInterceptor(null)); + } + + [Test] + public void NotInvoked() + { + IMethodInvocation mi = A.Fake(); + + MyThrowsHandler th = new MyThrowsHandler(); + ThrowsAdviceInterceptor ti = new ThrowsAdviceInterceptor(th); + object ret = new object(); + + A.CallTo(() => mi.Proceed()).Returns(ret); + + Assert.AreEqual(ret, ti.Invoke(mi)); + Assert.AreEqual(0, th.GetCalls()); + } + + [Test] + public void NoHandlerMethodForThrowable() + { + MyThrowsHandler th = new MyThrowsHandler(); + ThrowsAdviceInterceptor ti = new ThrowsAdviceInterceptor(th); + Assert.AreEqual(2, ti.HandlerMethodCount); + Exception ex = new Exception(); + + IMethodInvocation mi = A.Fake(); + A.CallTo(() => mi.Proceed()).Throws(ex); + + try { - Assert.Throws(() => new ThrowsAdviceInterceptor(null)); + ti.Invoke(mi); + Assert.Fail(); + } + catch (Exception caught) + { + Assert.AreEqual(ex, caught); } - [Test] - public void NotInvoked() - { - IMethodInvocation mi = A.Fake(); - - MyThrowsHandler th = new MyThrowsHandler(); - ThrowsAdviceInterceptor ti = new ThrowsAdviceInterceptor(th); - object ret = new object(); + Assert.AreEqual(0, th.GetCalls()); + } - A.CallTo(() => mi.Proceed()).Returns(ret); + [Test] + public void CorrectHandlerUsed() + { + MyThrowsHandler th = new MyThrowsHandler(); + ThrowsAdviceInterceptor ti = new ThrowsAdviceInterceptor(th); + HttpException ex = new HttpException(); - Assert.AreEqual(ret, ti.Invoke(mi)); - Assert.AreEqual(0, th.GetCalls()); - } + IMethodInvocation mi = A.Fake(); - [Test] - public void NoHandlerMethodForThrowable() - { - MyThrowsHandler th = new MyThrowsHandler(); - ThrowsAdviceInterceptor ti = new ThrowsAdviceInterceptor(th); - Assert.AreEqual(2, ti.HandlerMethodCount); - Exception ex = new Exception(); + A.CallTo(() => mi.Method).Returns(ReflectionUtils.GetMethod(typeof(object), "HashCode", new Type[] { })); + A.CallTo(() => mi.Arguments).Returns(null); + A.CallTo(() => mi.This).Returns(new object()); + A.CallTo(() => mi.Proceed()).Throws(ex); - IMethodInvocation mi = A.Fake(); - A.CallTo(() => mi.Proceed()).Throws(ex); - - try - { - ti.Invoke(mi); - Assert.Fail(); - } - catch (Exception caught) - { - Assert.AreEqual(ex, caught); - } - Assert.AreEqual(0, th.GetCalls()); - } - - [Test] - public void CorrectHandlerUsed() - { - - MyThrowsHandler th = new MyThrowsHandler(); - ThrowsAdviceInterceptor ti = new ThrowsAdviceInterceptor(th); - HttpException ex = new HttpException(); - - IMethodInvocation mi = A.Fake(); - - A.CallTo(() => mi.Method).Returns(ReflectionUtils.GetMethod(typeof (object), "HashCode", new Type[] {})); - A.CallTo(() => mi.Arguments).Returns(null); - A.CallTo(() => mi.This).Returns(new object()); - A.CallTo(() => mi.Proceed()).Throws(ex); - - try - { - ti.Invoke(mi); - Assert.Fail(); - } - catch (Exception caught) - { - Assert.AreEqual(ex, caught); - } - Assert.AreEqual(1, th.GetCalls()); - Assert.AreEqual(1, th.GetCalls("HttpException")); + try + { + ti.Invoke(mi); + Assert.Fail(); + } + catch (Exception caught) + { + Assert.AreEqual(ex, caught); } - [Test] - public void NestedInnerExceptionsAreNotPickedUp() + Assert.AreEqual(1, th.GetCalls()); + Assert.AreEqual(1, th.GetCalls("HttpException")); + } + + [Test] + public void NestedInnerExceptionsAreNotPickedUp() + { + MyThrowsHandler throwsHandler = new MyThrowsHandler(); + ThrowsAdviceInterceptor throwsInterceptor = new ThrowsAdviceInterceptor(throwsHandler); + // nest the exceptions; make sure the advice gets applied because of the inner exception... + Exception exception = new FormatException("Parent", new HttpException("Inner")); + + IMethodInvocation invocation = A.Fake(); + A.CallTo(() => invocation.Proceed()).Throws(exception); + + try { - MyThrowsHandler throwsHandler = new MyThrowsHandler(); - ThrowsAdviceInterceptor throwsInterceptor = new ThrowsAdviceInterceptor(throwsHandler); - // nest the exceptions; make sure the advice gets applied because of the inner exception... - Exception exception = new FormatException("Parent", new HttpException("Inner")); + throwsInterceptor.Invoke(invocation); + Assert.Fail("Must have failed (by throwing an exception by this point - check the mock)."); + } + catch (Exception caught) + { + Assert.AreEqual(exception, caught); + } - IMethodInvocation invocation = A.Fake(); - A.CallTo(() => invocation.Proceed()).Throws(exception); + Assert.AreEqual(0, throwsHandler.GetCalls(), + "Must NOT have been handled, 'cos the HttpException was wrapped by " + + "another Exception that did not have a handler."); + Assert.AreEqual(0, throwsHandler.GetCalls("HttpException"), + "Similarly, must NOT have been handled, 'cos the HttpException was wrapped by " + + "another Exception that did not have a handler."); + } - try + [Test] + public void ChokesOnHandlerWhereMultipleMethodsAreApplicable() + { + object throwsHandler = new MultipleMethodsAreApplicableThrowsHandler(); + Assert.Throws(() => new ThrowsAdviceInterceptor(throwsHandler)); + } + + [Test] + public void CorrectHandlerUsedForSubclass() + { + MyThrowsHandler th = new MyThrowsHandler(); + ThrowsAdviceInterceptor ti = new ThrowsAdviceInterceptor(th); + // Extends RemotingException + RemotingTimeoutException ex = new RemotingTimeoutException(); + + IMethodInvocation mi = A.Fake(); + A.CallTo(() => mi.Proceed()).Throws(ex); + + try + { + ti.Invoke(mi); + Assert.Fail(); + } + catch (Exception caught) + { + Assert.AreEqual(ex, caught); + } + + Assert.AreEqual(1, th.GetCalls()); + Assert.AreEqual(1, th.GetCalls("RemotingException")); + } + + [Test] + public void HandlerMethodThrowsException() + { + Exception exception = new Exception(); + MyThrowsHandler handler = new ThrowingMyHandler(exception); + ThrowsAdviceInterceptor interceptor = new ThrowsAdviceInterceptor(handler); + + IMethodInvocation mi = A.Fake(); + A.CallTo(() => mi.Proceed()).Throws(new RemotingTimeoutException()); + + try + { + interceptor.Invoke(mi); + Assert.Fail("Should not have reached this point, should have thrown an exception."); + } + catch (Exception caught) + { + Assert.AreEqual(exception, caught); + } + + Assert.AreEqual(1, handler.GetCalls()); + Assert.AreEqual(1, handler.GetCalls("RemotingException")); + } + + private sealed class MultipleMethodsAreApplicableThrowsHandler + { + public void AfterThrowing(MethodInfo method, object[] args, object target, RemotingException ex) + { + } + + public void AfterThrowing(RemotingException ex) + { + } + } + + private class ThrowingMyHandler : MyThrowsHandler + { + private Exception exception; + + public ThrowingMyHandler(Exception ex) + { + this.exception = ex; + } + + public override void AfterThrowing(RemotingException ex) + { + base.AfterThrowing(ex); + throw exception; + } + } + + public class MyThrowsHandler : MethodCounter, IThrowsAdvice + { + public void AfterThrowing( + MethodInfo m, object[] args, object target, HttpException ex) + { + Count("HttpException"); + } + + public virtual void AfterThrowing(RemotingException ex) + { + Count("RemotingException"); + } + + // not valid, wrong number of arguments... + public void AfterThrowing(MethodInfo m, Exception ex) + { + throw new NotSupportedException("Shouldn't be called"); + } + } + + public interface IEcho + { + int A { get; set; } + + int EchoException(int i, Exception t); + } + + public class Echo : IEcho + { + private int a; + + public int A + { + get { return a; } + set { a = value; } + } + + public virtual int EchoException(int i, Exception ex) + { + if (ex != null) { - throwsInterceptor.Invoke(invocation); - Assert.Fail("Must have failed (by throwing an exception by this point - check the mock)."); + throw ex; } - catch (Exception caught) - { - Assert.AreEqual(exception, caught); - } - Assert.AreEqual(0, throwsHandler.GetCalls(), - "Must NOT have been handled, 'cos the HttpException was wrapped by " + - "another Exception that did not have a handler."); - Assert.AreEqual(0, throwsHandler.GetCalls("HttpException"), - "Similarly, must NOT have been handled, 'cos the HttpException was wrapped by " + - "another Exception that did not have a handler."); - } - [Test] - public void ChokesOnHandlerWhereMultipleMethodsAreApplicable() - { - object throwsHandler = new MultipleMethodsAreApplicableThrowsHandler(); - Assert.Throws(() => new ThrowsAdviceInterceptor(throwsHandler)); - } - - [Test] - public void CorrectHandlerUsedForSubclass() - { - MyThrowsHandler th = new MyThrowsHandler(); - ThrowsAdviceInterceptor ti = new ThrowsAdviceInterceptor(th); - // Extends RemotingException - RemotingTimeoutException ex = new RemotingTimeoutException(); - - IMethodInvocation mi = A.Fake(); - A.CallTo(() => mi.Proceed()).Throws(ex); - - try - { - ti.Invoke(mi); - Assert.Fail(); - } - catch (Exception caught) - { - Assert.AreEqual(ex, caught); - } - Assert.AreEqual(1, th.GetCalls()); - Assert.AreEqual(1, th.GetCalls("RemotingException")); - } - - [Test] - public void HandlerMethodThrowsException() - { - Exception exception = new Exception(); - MyThrowsHandler handler = new ThrowingMyHandler(exception); - ThrowsAdviceInterceptor interceptor = new ThrowsAdviceInterceptor(handler); - - IMethodInvocation mi = A.Fake(); - A.CallTo(() => mi.Proceed()).Throws(new RemotingTimeoutException()); - - try - { - interceptor.Invoke(mi); - Assert.Fail("Should not have reached this point, should have thrown an exception."); - } - catch (Exception caught) - { - Assert.AreEqual(exception, caught); - } - Assert.AreEqual(1, handler.GetCalls()); - Assert.AreEqual(1, handler.GetCalls("RemotingException")); - } - - private sealed class MultipleMethodsAreApplicableThrowsHandler - { - public void AfterThrowing(MethodInfo method, object[] args, object target, RemotingException ex) - { - } - - public void AfterThrowing(RemotingException ex) - { - } - } - - private class ThrowingMyHandler : MyThrowsHandler - { - private Exception exception; - - public ThrowingMyHandler(Exception ex) - { - this.exception = ex; - } - - public override void AfterThrowing(RemotingException ex) - { - base.AfterThrowing(ex); - throw exception; - } - } - - public class MyThrowsHandler : MethodCounter, IThrowsAdvice - { - public void AfterThrowing( - MethodInfo m, object[] args, object target, HttpException ex) - { - Count("HttpException"); - } - - public virtual void AfterThrowing(RemotingException ex) - { - Count("RemotingException"); - } - - // not valid, wrong number of arguments... - public void AfterThrowing(MethodInfo m, Exception ex) - { - throw new NotSupportedException("Shouldn't be called"); - } - } - - public interface IEcho - { - int A { get; set; } - - int EchoException(int i, Exception t); - } - - public class Echo : IEcho - { - private int a; - - public int A - { - get { return a; } - set { a = value; } - } - - public virtual int EchoException(int i, Exception ex) - { - if (ex != null) - { - throw ex; - } - return i; - } - } - - } -} \ No newline at end of file + return i; + } + } +} diff --git a/test/Spring/Spring.Aop.Tests/Aop/Framework/Adapter/UnknownAdviceTypeExceptionTests.cs b/test/Spring/Spring.Aop.Tests/Aop/Framework/Adapter/UnknownAdviceTypeExceptionTests.cs index 896b741d..3526e236 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Framework/Adapter/UnknownAdviceTypeExceptionTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Framework/Adapter/UnknownAdviceTypeExceptionTests.cs @@ -20,19 +20,18 @@ using NUnit.Framework; -namespace Spring.Aop.Framework.Adapter +namespace Spring.Aop.Framework.Adapter; + +/// +/// Unit tests for the UnknownAdviceTypeException class. +/// +/// Rick Evans +[TestFixture] +public sealed class UnknownAdviceTypeExceptionTests { - /// - /// Unit tests for the UnknownAdviceTypeException class. - /// - /// Rick Evans - [TestFixture] - public sealed class UnknownAdviceTypeExceptionTests + [Test] + public void InstantiationWithNullAdviceDoesNotThrowAnotherException() { - [Test] - public void InstantiationWithNullAdviceDoesNotThrowAnotherException() - { - new UnknownAdviceTypeException(null); - } - } + new UnknownAdviceTypeException(null); + } } diff --git a/test/Spring/Spring.Aop.Tests/Aop/Framework/AopContextTests.cs b/test/Spring/Spring.Aop.Tests/Aop/Framework/AopContextTests.cs index b92d4e52..f639ce15 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Framework/AopContextTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Framework/AopContextTests.cs @@ -22,227 +22,228 @@ using AopAlliance.Aop; using NUnit.Framework; - using AopAlliance.Intercept; using Spring.Threading; #endregion -namespace Spring.Aop.Framework +namespace Spring.Aop.Framework; + +/// +/// Unit tests for the AopContext class. +/// +/// Rick Evans +[TestFixture] +public sealed class AopContextTests { - /// - /// Unit tests for the AopContext class. - /// - /// Rick Evans - [TestFixture] - public sealed class AopContextTests + [SetUp] + public void SetUp() { - [SetUp] - public void SetUp() + // makes sure the context is always empty before any unit test... + try { - // makes sure the context is always empty before any unit test... - try + do { - do - { - AopContext.PopProxy(); - } while (true); - } - catch (AopConfigException) - { - } + AopContext.PopProxy(); + } while (true); } - - [Test] - public void CurrentProxyChokesIfNoAopProxyIsOnTheStack() + catch (AopConfigException) { - Assert.Throws(() => AopContext.CurrentProxy.ToString()); } - - [Test] - public void CurrentProxyStackJustPeeksItDoesntPop() - { - string foo = "Foo"; - AopContext.PushProxy(foo); - object fooref = AopContext.CurrentProxy; - Assert.IsTrue(ReferenceEquals(foo, fooref), - "Not the exact same instance (must be)."); - // must not have been popped off the stack by looking at it... - object foorefref = AopContext.CurrentProxy; - Assert.IsTrue(ReferenceEquals(fooref, foorefref), - "Not the exact same instance (must be)."); - } - - [Test] - public void PopProxyWithNothingOnStack() - { - Assert.Throws(() => AopContext.PopProxy()); - } - - [Test(Description = "SPRNET-1158")] - public void IsActiveMatchesStackState() - { - Assert.IsFalse(AopContext.IsActive); - AopContext.PushProxy("Foo"); - Assert.IsTrue(AopContext.IsActive); - AopContext.PopProxy(); - Assert.IsFalse(AopContext.IsActive); - } - - #region CurrentProxyIsThreadSafe - - [Test, Explicit] - public void ProxyPerformanceTests() - { - int runs = 5000000; - StopWatch watch = new StopWatch(); - - ITestObject testObject = new ChainableTestObject(null); - using (watch.Start("Naked Duration: {0}")) - { - for (int i = 0; i < runs; i++) - { - object result = testObject.DoSomething(this); - } - } - - ITestObject hardcodedWrapper = new ChainableTestObject(testObject); - using (watch.Start("Hardcoded Wrapper Duration: {0}")) - { - for (int i = 0; i < runs; i++) - { - object result = hardcodedWrapper.DoSomething(this); - } - } - - PeformanceTestAopContextInterceptor interceptor = new PeformanceTestAopContextInterceptor(); - ITestObject proxy = CreateProxy(testObject, interceptor, false); - using(watch.Start("Proxy Duration ('ExposeProxy'==false): {0}")) - { - for(int i=0;i(() => AopContext.CurrentProxy.ToString()); + } + + [Test] + public void CurrentProxyStackJustPeeksItDoesntPop() + { + string foo = "Foo"; + AopContext.PushProxy(foo); + object fooref = AopContext.CurrentProxy; + Assert.IsTrue(ReferenceEquals(foo, fooref), + "Not the exact same instance (must be)."); + // must not have been popped off the stack by looking at it... + object foorefref = AopContext.CurrentProxy; + Assert.IsTrue(ReferenceEquals(fooref, foorefref), + "Not the exact same instance (must be)."); + } + + [Test] + public void PopProxyWithNothingOnStack() + { + Assert.Throws(() => AopContext.PopProxy()); + } + + [Test(Description = "SPRNET-1158")] + public void IsActiveMatchesStackState() + { + Assert.IsFalse(AopContext.IsActive); + AopContext.PushProxy("Foo"); + Assert.IsTrue(AopContext.IsActive); + AopContext.PopProxy(); + Assert.IsFalse(AopContext.IsActive); + } + + #region CurrentProxyIsThreadSafe + + [Test, Explicit] + public void ProxyPerformanceTests() + { + int runs = 5000000; + StopWatch watch = new StopWatch(); + + ITestObject testObject = new ChainableTestObject(null); + using (watch.Start("Naked Duration: {0}")) + { + for (int i = 0; i < runs; i++) + { + object result = testObject.DoSomething(this); + } + } + + ITestObject hardcodedWrapper = new ChainableTestObject(testObject); + using (watch.Start("Hardcoded Wrapper Duration: {0}")) + { + for (int i = 0; i < runs; i++) + { + object result = hardcodedWrapper.DoSomething(this); + } + } + + PeformanceTestAopContextInterceptor interceptor = new PeformanceTestAopContextInterceptor(); + ITestObject proxy = CreateProxy(testObject, interceptor, false); + using (watch.Start("Proxy Duration ('ExposeProxy'==false): {0}")) + { + for (int i = 0; i < runs; i++) + { + object result = proxy.DoSomething(this); + } + } + + Assert.AreEqual(runs, interceptor.Calls); + + interceptor = new PeformanceTestAopContextInterceptor(); + proxy = CreateProxy(testObject, interceptor, true); + using (watch.Start("Proxy Duration ('ExposeProxy'==true): {0}")) + { + for (int i = 0; i < runs; i++) + { + object result = proxy.DoSomething(this); + } + } + + Assert.AreEqual(runs, interceptor.Calls); + } + + private class PeformanceTestAopContextInterceptor : IMethodInterceptor + { + public int Calls = 0; + + public object Invoke(IMethodInvocation invocation) + { + Calls++; + Object ret = invocation.Proceed(); + return ret; + } + } + + [Test(Description = "http://opensource.atlassian.com/projects/spring/browse/SPRNET-341")] + public void CurrentProxyIsThreadSafe() + { + ProxyTestObjectAndExposeProxy(); + + AsyncTestMethod t1 = new AsyncTestMethod(1000, new ThreadStart(ProxyTestObjectAndExposeProxy)); + AsyncTestMethod t2 = new AsyncTestMethod(1000, new ThreadStart(ProxyTestObjectAndExposeProxy)); + t1.Start(); + t2.Start(); + + t1.AssertNoException(); + t2.AssertNoException(); + } + + public interface ITestObject + { + object DoSomething(object arg); + } + + private class ChainableTestObject : ITestObject + { + private readonly ITestObject next; + + public ChainableTestObject(ITestObject next) + { + this.next = next; + } + + public virtual object DoSomething(object arg) + { + if (next != null) + { + return next.DoSomething(arg); + } + + // simulate some sensible work + string rep = string.Format("{0} {1}", this.GetType(), arg.GetHashCode()); + return arg; + } + } + + private void ProxyTestObjectAndExposeProxy() + { + TestAopContextInterceptor interceptor = new TestAopContextInterceptor(); + + ITestObject proxy = CreateProxyChain(interceptor, true); + + Assert.IsFalse(AopContext.IsActive); + Assert.AreEqual(this, proxy.DoSomething(this), "Incorrect return value"); + Assert.IsFalse(AopContext.IsActive); + Assert.AreEqual(2, interceptor.Calls); // 2 interceptions on the way + } + + private ITestObject CreateProxyChain(IAdvice interceptor, bool exposeProxy) + { + ITestObject first = new ChainableTestObject(null); + ITestObject firstProxy = CreateProxy(first, interceptor, exposeProxy); + Assert.IsNotNull(firstProxy); + + ITestObject second = new ChainableTestObject(firstProxy); + ITestObject secondProxy = CreateProxy(second, interceptor, exposeProxy); + Assert.IsNotNull(secondProxy); + return secondProxy; + } + + private ITestObject CreateProxy(object target, IAdvice interceptor, bool exposeProxy) + { + ProxyFactory pf = new ProxyFactory(target); + pf.ExposeProxy = exposeProxy; +// pf.Target = target; + pf.AddAdvice(interceptor); + + return pf.GetProxy() as ITestObject; + } + + private class TestAopContextInterceptor : IMethodInterceptor + { + public int Calls = 0; + + public object Invoke(IMethodInvocation invocation) + { + Calls++; + Assert.IsTrue(AopContext.IsActive); + Assert.IsNotNull(AopContext.CurrentProxy); + Assert.AreSame(invocation.Proxy, AopContext.CurrentProxy); + + Object ret = invocation.Proceed(); + + Assert.IsNotNull(AopContext.CurrentProxy); + Assert.IsTrue(AopContext.IsActive); + return ret; + } + } + + #endregion +} diff --git a/test/Spring/Spring.Aop.Tests/Aop/Framework/AutoProxy/AbstractAdvisorAutoProxyCreatorTests.cs b/test/Spring/Spring.Aop.Tests/Aop/Framework/AutoProxy/AbstractAdvisorAutoProxyCreatorTests.cs index 5fb72780..7c2e7a25 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Framework/AutoProxy/AbstractAdvisorAutoProxyCreatorTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Framework/AutoProxy/AbstractAdvisorAutoProxyCreatorTests.cs @@ -24,74 +24,73 @@ using NUnit.Framework; using Spring.Objects.Factory.Config; using Spring.Objects.Factory.Support; -namespace Spring.Aop.Framework.AutoProxy +namespace Spring.Aop.Framework.AutoProxy; + +/// +/// +/// Erich Eichinger +[TestFixture] +public class AbstractAdvisorAutoProxyCreatorTests { - /// - /// - /// Erich Eichinger - [TestFixture] - public class AbstractAdvisorAutoProxyCreatorTests + public class TestAdvisorAutoProxyCreator : AbstractAdvisorAutoProxyCreator { - public class TestAdvisorAutoProxyCreator : AbstractAdvisorAutoProxyCreator + public ArrayList CheckedAdvisors = new ArrayList(); + + public IList GetAdvicesAndAdvisorsForObject(Type targetType, string targetName) { - public ArrayList CheckedAdvisors = new ArrayList(); - - public IList GetAdvicesAndAdvisorsForObject(Type targetType, string targetName) - { - return base.GetAdvicesAndAdvisorsForObject(targetType, targetName, null); - } - - protected override bool IsEligibleAdvisorObject(string advisorName, Type targetType, string targetName) - { - CheckedAdvisors.Add(advisorName); - return base.IsEligibleAdvisorObject(advisorName, targetType, targetName); - } + return base.GetAdvicesAndAdvisorsForObject(targetType, targetName, null); } - public class TestAdvisor : IAdvisor + protected override bool IsEligibleAdvisorObject(string advisorName, Type targetType, string targetName) { - public string Name; - - #region Implementation of IAdvisor - - public bool IsPerInstance - { - get { throw new NotImplementedException(); } - } - - public IAdvice Advice - { - get { throw new NotImplementedException(); } - } - - #endregion - } - - [Test] - public void DoesNotAcceptInfrastructureAdvisorsDuringScanning() - { - DefaultListableObjectFactory of = new DefaultListableObjectFactory(); - - GenericObjectDefinition infrastructureAdvisorDefinition = new GenericObjectDefinition(); - infrastructureAdvisorDefinition.ObjectType = typeof (TestAdvisor); - infrastructureAdvisorDefinition.PropertyValues.Add("Name", "InfrastructureAdvisor"); - infrastructureAdvisorDefinition.Role = ObjectRole.ROLE_INFRASTRUCTURE; - of.RegisterObjectDefinition("infrastructure", infrastructureAdvisorDefinition); - - GenericObjectDefinition regularAdvisorDefinition = new GenericObjectDefinition(); - regularAdvisorDefinition.ObjectType = typeof (TestAdvisor); - regularAdvisorDefinition.PropertyValues.Add("Name", "RegularAdvisor"); -// regularAdvisorDefinition.Role = ObjectRole.ROLE_APPLICATION; - of.RegisterObjectDefinition("regular", regularAdvisorDefinition); - - TestAdvisorAutoProxyCreator apc = new TestAdvisorAutoProxyCreator(); - apc.ObjectFactory = of; - IList advisors = apc.GetAdvicesAndAdvisorsForObject(typeof (object), "dummyTarget"); - Assert.AreEqual(1, advisors.Count); - Assert.AreEqual( "RegularAdvisor", ((TestAdvisor)advisors[0]).Name ); - - Assert.AreEqual(1, apc.CheckedAdvisors.Count); - Assert.AreEqual("regular", apc.CheckedAdvisors[0]); + CheckedAdvisors.Add(advisorName); + return base.IsEligibleAdvisorObject(advisorName, targetType, targetName); } } -} \ No newline at end of file + + public class TestAdvisor : IAdvisor + { + public string Name; + + #region Implementation of IAdvisor + + public bool IsPerInstance + { + get { throw new NotImplementedException(); } + } + + public IAdvice Advice + { + get { throw new NotImplementedException(); } + } + + #endregion + } + + [Test] + public void DoesNotAcceptInfrastructureAdvisorsDuringScanning() + { + DefaultListableObjectFactory of = new DefaultListableObjectFactory(); + + GenericObjectDefinition infrastructureAdvisorDefinition = new GenericObjectDefinition(); + infrastructureAdvisorDefinition.ObjectType = typeof(TestAdvisor); + infrastructureAdvisorDefinition.PropertyValues.Add("Name", "InfrastructureAdvisor"); + infrastructureAdvisorDefinition.Role = ObjectRole.ROLE_INFRASTRUCTURE; + of.RegisterObjectDefinition("infrastructure", infrastructureAdvisorDefinition); + + GenericObjectDefinition regularAdvisorDefinition = new GenericObjectDefinition(); + regularAdvisorDefinition.ObjectType = typeof(TestAdvisor); + regularAdvisorDefinition.PropertyValues.Add("Name", "RegularAdvisor"); +// regularAdvisorDefinition.Role = ObjectRole.ROLE_APPLICATION; + of.RegisterObjectDefinition("regular", regularAdvisorDefinition); + + TestAdvisorAutoProxyCreator apc = new TestAdvisorAutoProxyCreator(); + apc.ObjectFactory = of; + IList advisors = apc.GetAdvicesAndAdvisorsForObject(typeof(object), "dummyTarget"); + Assert.AreEqual(1, advisors.Count); + Assert.AreEqual("RegularAdvisor", ((TestAdvisor) advisors[0]).Name); + + Assert.AreEqual(1, apc.CheckedAdvisors.Count); + Assert.AreEqual("regular", apc.CheckedAdvisors[0]); + } +} diff --git a/test/Spring/Spring.Aop.Tests/Aop/Framework/AutoProxy/AbstractAutoProxyCreatorTests.cs b/test/Spring/Spring.Aop.Tests/Aop/Framework/AutoProxy/AbstractAutoProxyCreatorTests.cs index b9682d0f..c65606ed 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Framework/AutoProxy/AbstractAutoProxyCreatorTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Framework/AutoProxy/AbstractAutoProxyCreatorTests.cs @@ -27,162 +27,165 @@ using Spring.Objects.Factory; using Spring.Objects.Factory.Config; using Spring.Objects.Factory.Support; -namespace Spring.Aop.Framework.AutoProxy +namespace Spring.Aop.Framework.AutoProxy; + +/// +/// +/// Erich Eichinger +[TestFixture] +public class AbstractAutoProxyCreatorTests { - /// - /// - /// Erich Eichinger - [TestFixture] - public class AbstractAutoProxyCreatorTests + public interface ITestObject { - public interface ITestObject + void Foo(); + } + + public class ObjectWithInterface : ITestObject + { + void ITestObject.Foo() { - void Foo(); - } - - public class ObjectWithInterface : ITestObject - { - void ITestObject.Foo() - {} - } - - public class ObjectWithoutInterface - { - public virtual void Foo() - { } - } - - public class TransparentProxyFactory : IFactoryObject - { - public static RemotingProxy GetRealProxy(object transparentProxy) - { - RemotingProxy rp = (RemotingProxy)RemotingServices.GetRealProxy(transparentProxy); - return rp; - } - - public class RemotingProxy : RealProxy, IRemotingTypeInfo - { - public int Count; - - public RemotingProxy() : base(typeof(MarshalByRefObject)) - {} - - public override IMessage Invoke(IMessage msg) - { - Count++; - return new ReturnMessage(null, null, 0, null, msg as IMethodCallMessage); - } - - public bool CanCastTo(Type fromType, object o) - { - return true; - } - - public string TypeName - { - get { throw new System.NotImplementedException(); } - set { throw new System.NotImplementedException(); } - } - } - - private readonly Type objectType; - private readonly RealProxy realProxy; - - public TransparentProxyFactory(Type objectType) - { - this.objectType = objectType; - this.realProxy = new RemotingProxy(); - } - - public object GetObject() - { - return realProxy.GetTransparentProxy(); - } - - public Type ObjectType - { - get { return objectType; } - } - - public bool IsSingleton - { - get { return true; } - } - } - - public class TestAutoProxyCreator : AbstractAutoProxyCreator - { - public readonly NopInterceptor NopInterceptor = new NopInterceptor(); - - public TestAutoProxyCreator(IObjectFactory objectFactory) - { - this.ObjectFactory = objectFactory; - } - - protected override IList GetAdvicesAndAdvisorsForObject(Type targetType, string targetName, ITargetSource customTargetSource) - { - if (typeof(IFactoryObject).IsAssignableFrom(targetType)) - { - return DO_NOT_PROXY; - } - return new List { NopInterceptor }; - } - } - - [Test] - public void ProxyObjectWithInterface() - { - DefaultListableObjectFactory of = new DefaultListableObjectFactory(); - of.RegisterObjectDefinition("bar", new RootObjectDefinition(typeof(ObjectWithInterface))); - - TestAutoProxyCreator apc = new TestAutoProxyCreator(of); - of.AddObjectPostProcessor(apc); - - ITestObject o = of.GetObject("bar") as ITestObject; - Assert.IsTrue(AopUtils.IsAopProxy(o)); - o.Foo(); - Assert.AreEqual(1, apc.NopInterceptor.Count); - } - - [Test] - public void ProxyObjectWithoutInterface() - { - DefaultListableObjectFactory of = new DefaultListableObjectFactory(); - of.RegisterObjectDefinition("bar", new RootObjectDefinition(typeof(ObjectWithoutInterface))); - - TestAutoProxyCreator apc = new TestAutoProxyCreator(of); - of.AddObjectPostProcessor(apc); - - ObjectWithoutInterface o = of.GetObject("bar") as ObjectWithoutInterface; - Assert.IsTrue(AopUtils.IsAopProxy(o)); - o.Foo(); - Assert.AreEqual(1, apc.NopInterceptor.Count); - } - - [Test] - [Platform("Win")] - public void ProxyTransparentProxy() - { - DefaultListableObjectFactory of = new DefaultListableObjectFactory(); - - ConstructorArgumentValues ctorArgs = new ConstructorArgumentValues(); - ctorArgs.AddNamedArgumentValue("objectType", typeof(ITestObject)); - of.RegisterObjectDefinition("bar", new RootObjectDefinition(typeof(TransparentProxyFactory), ctorArgs, null)); - - TestAutoProxyCreator apc = new TestAutoProxyCreator(of); - of.AddObjectPostProcessor(apc); - - ITestObject o = of.GetObject("bar") as ITestObject; - Assert.IsTrue(AopUtils.IsAopProxy(o)); - - // ensure interceptors get called - o.Foo(); - Assert.AreEqual(1, apc.NopInterceptor.Count); - IAdvised advised = (IAdvised) o; - - // ensure target was called - object target = advised.TargetSource.GetTarget(); - Assert.AreEqual(1, TransparentProxyFactory.GetRealProxy(target).Count); } } + + public class ObjectWithoutInterface + { + public virtual void Foo() + { + } + } + + public class TransparentProxyFactory : IFactoryObject + { + public static RemotingProxy GetRealProxy(object transparentProxy) + { + RemotingProxy rp = (RemotingProxy) RemotingServices.GetRealProxy(transparentProxy); + return rp; + } + + public class RemotingProxy : RealProxy, IRemotingTypeInfo + { + public int Count; + + public RemotingProxy() : base(typeof(MarshalByRefObject)) + { + } + + public override IMessage Invoke(IMessage msg) + { + Count++; + return new ReturnMessage(null, null, 0, null, msg as IMethodCallMessage); + } + + public bool CanCastTo(Type fromType, object o) + { + return true; + } + + public string TypeName + { + get { throw new System.NotImplementedException(); } + set { throw new System.NotImplementedException(); } + } + } + + private readonly Type objectType; + private readonly RealProxy realProxy; + + public TransparentProxyFactory(Type objectType) + { + this.objectType = objectType; + this.realProxy = new RemotingProxy(); + } + + public object GetObject() + { + return realProxy.GetTransparentProxy(); + } + + public Type ObjectType + { + get { return objectType; } + } + + public bool IsSingleton + { + get { return true; } + } + } + + public class TestAutoProxyCreator : AbstractAutoProxyCreator + { + public readonly NopInterceptor NopInterceptor = new NopInterceptor(); + + public TestAutoProxyCreator(IObjectFactory objectFactory) + { + this.ObjectFactory = objectFactory; + } + + protected override IList GetAdvicesAndAdvisorsForObject(Type targetType, string targetName, ITargetSource customTargetSource) + { + if (typeof(IFactoryObject).IsAssignableFrom(targetType)) + { + return DO_NOT_PROXY; + } + + return new List { NopInterceptor }; + } + } + + [Test] + public void ProxyObjectWithInterface() + { + DefaultListableObjectFactory of = new DefaultListableObjectFactory(); + of.RegisterObjectDefinition("bar", new RootObjectDefinition(typeof(ObjectWithInterface))); + + TestAutoProxyCreator apc = new TestAutoProxyCreator(of); + of.AddObjectPostProcessor(apc); + + ITestObject o = of.GetObject("bar") as ITestObject; + Assert.IsTrue(AopUtils.IsAopProxy(o)); + o.Foo(); + Assert.AreEqual(1, apc.NopInterceptor.Count); + } + + [Test] + public void ProxyObjectWithoutInterface() + { + DefaultListableObjectFactory of = new DefaultListableObjectFactory(); + of.RegisterObjectDefinition("bar", new RootObjectDefinition(typeof(ObjectWithoutInterface))); + + TestAutoProxyCreator apc = new TestAutoProxyCreator(of); + of.AddObjectPostProcessor(apc); + + ObjectWithoutInterface o = of.GetObject("bar") as ObjectWithoutInterface; + Assert.IsTrue(AopUtils.IsAopProxy(o)); + o.Foo(); + Assert.AreEqual(1, apc.NopInterceptor.Count); + } + + [Test] + [Platform("Win")] + public void ProxyTransparentProxy() + { + DefaultListableObjectFactory of = new DefaultListableObjectFactory(); + + ConstructorArgumentValues ctorArgs = new ConstructorArgumentValues(); + ctorArgs.AddNamedArgumentValue("objectType", typeof(ITestObject)); + of.RegisterObjectDefinition("bar", new RootObjectDefinition(typeof(TransparentProxyFactory), ctorArgs, null)); + + TestAutoProxyCreator apc = new TestAutoProxyCreator(of); + of.AddObjectPostProcessor(apc); + + ITestObject o = of.GetObject("bar") as ITestObject; + Assert.IsTrue(AopUtils.IsAopProxy(o)); + + // ensure interceptors get called + o.Foo(); + Assert.AreEqual(1, apc.NopInterceptor.Count); + IAdvised advised = (IAdvised) o; + + // ensure target was called + object target = advised.TargetSource.GetTarget(); + Assert.AreEqual(1, TransparentProxyFactory.GetRealProxy(target).Count); + } } \ No newline at end of file diff --git a/test/Spring/Spring.Aop.Tests/Aop/Framework/AutoProxy/AdvisorAutoProxyCreatorCircularReferencesTests.cs b/test/Spring/Spring.Aop.Tests/Aop/Framework/AutoProxy/AdvisorAutoProxyCreatorCircularReferencesTests.cs index a1e51ea1..efd6151f 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Framework/AutoProxy/AdvisorAutoProxyCreatorCircularReferencesTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Framework/AutoProxy/AdvisorAutoProxyCreatorCircularReferencesTests.cs @@ -23,7 +23,6 @@ using System.Reflection; using Microsoft.Extensions.Logging; using NUnit.Framework; - using Spring.Aop.Support; using Spring.Context.Support; using Spring.Objects; @@ -32,194 +31,194 @@ using Spring.Objects.Factory.Xml; #endregion -namespace Spring.Aop.Framework.AutoProxy +namespace Spring.Aop.Framework.AutoProxy; + +/// +/// Tests for auto proxy creation combined with factory object and circular references. +/// +/// Erich Eichinger (.NET) +[TestFixture] +public class AdvisorAutoProxyCreatorCircularReferencesTests { - /// - /// Tests for auto proxy creation combined with factory object and circular references. - /// - /// Erich Eichinger (.NET) - [TestFixture] - public class AdvisorAutoProxyCreatorCircularReferencesTests + [Test] + public void TestAutoProxyCreation() { - [Test] - public void TestAutoProxyCreation() - { - XmlApplicationContext context = new XmlApplicationContext(ReadOnlyXmlTestResource.GetFilePath("advisorAutoProxyCreatorCircularReferencesTests.xml", typeof(AdvisorAutoProxyCreatorCircularReferencesTests))); - CountingAfterReturningAdvisor countingAdvisor = (CountingAfterReturningAdvisor)context.GetObject("testAdvisor"); + XmlApplicationContext context = new XmlApplicationContext(ReadOnlyXmlTestResource.GetFilePath("advisorAutoProxyCreatorCircularReferencesTests.xml", typeof(AdvisorAutoProxyCreatorCircularReferencesTests))); + CountingAfterReturningAdvisor countingAdvisor = (CountingAfterReturningAdvisor) context.GetObject("testAdvisor"); - // direct deps of AutoProxyCreator are not eligable for proxying - Assert.IsFalse(AopUtils.IsAopProxy(context.GetObject("aapc"))); - Assert.IsFalse(AopUtils.IsAopProxy(countingAdvisor)); + // direct deps of AutoProxyCreator are not eligable for proxying + Assert.IsFalse(AopUtils.IsAopProxy(context.GetObject("aapc"))); + Assert.IsFalse(AopUtils.IsAopProxy(countingAdvisor)); - TestObjectFactoryObject testObjectFactory = (TestObjectFactoryObject) context.GetObject("&testObjectFactory"); - Assert.IsFalse(AopUtils.IsAopProxy(testObjectFactory)); + TestObjectFactoryObject testObjectFactory = (TestObjectFactoryObject) context.GetObject("&testObjectFactory"); + Assert.IsFalse(AopUtils.IsAopProxy(testObjectFactory)); - Assert.IsFalse(AopUtils.IsAopProxy(context.GetObject("someOtherObject"))); + Assert.IsFalse(AopUtils.IsAopProxy(context.GetObject("someOtherObject"))); - // this one is completely independent - Assert.IsTrue(AopUtils.IsAopProxy(context.GetObject("independentObject"))); + // this one is completely independent + Assert.IsTrue(AopUtils.IsAopProxy(context.GetObject("independentObject"))); + // Asserts SPRNET-1225 - advisor dependencies most not be auto-proxied + object testObject = context.GetObject("testObjectFactory"); + Assert.IsFalse(AopUtils.IsAopProxy(testObject)); - // Asserts SPRNET-1225 - advisor dependencies most not be auto-proxied - object testObject = context.GetObject("testObjectFactory"); - Assert.IsFalse(AopUtils.IsAopProxy(testObject)); + // Asserts SPRNET-1224 - factory product most be cached + context.GetObject("testObjectFactory"); + testObjectFactory.GetObjectCounter = 0; + context.GetObject("testObjectFactory"); + Assert.AreEqual(0, testObjectFactory.GetObjectCounter); - // Asserts SPRNET-1224 - factory product most be cached - context.GetObject("testObjectFactory"); - testObjectFactory.GetObjectCounter = 0; - context.GetObject("testObjectFactory"); - Assert.AreEqual(0, testObjectFactory.GetObjectCounter); + ICloneable someOtherObject = (ICloneable) context.GetObject("someOtherObject"); + someOtherObject.Clone(); + ICloneable independentObject = (ICloneable) context.GetObject("independentObject"); + independentObject.Clone(); + Assert.AreEqual(1, countingAdvisor.GetCalls()); + } +} - ICloneable someOtherObject = (ICloneable) context.GetObject("someOtherObject"); - someOtherObject.Clone(); - ICloneable independentObject = (ICloneable) context.GetObject("independentObject"); - independentObject.Clone(); - Assert.AreEqual(1, countingAdvisor.GetCalls()); - } +#region Support Classes + +public class TestDefaultAdvisorAutoProxyCreator : DefaultAdvisorAutoProxyCreator, IInitializingObject +{ + private readonly ILog _logger; + + public TestDefaultAdvisorAutoProxyCreator() + { + _logger = LogManager.GetLogger(this.GetType().Name + "#" + GetHashCode()); + _logger.LogTrace("Created instance"); } - #region Support Classes - - public class TestDefaultAdvisorAutoProxyCreator : DefaultAdvisorAutoProxyCreator, IInitializingObject + protected override IList GetAdvicesAndAdvisorsForObject(Type targetType, string targetName, ITargetSource customTargetSource) { - private readonly ILog _logger; - - public TestDefaultAdvisorAutoProxyCreator() - { - _logger = LogManager.GetLogger(this.GetType().Name + "#" + GetHashCode()); - _logger.LogTrace("Created instance"); - } - - protected override IList GetAdvicesAndAdvisorsForObject(Type targetType, string targetName, ITargetSource customTargetSource) - { - _logger.LogTrace("GetAdvicesAndAdvisorsForObject begin"); - IList advices = base.GetAdvicesAndAdvisorsForObject(targetType, targetName, customTargetSource); - _logger.LogTrace("GetAdvicesAndAdvisorsForObject end"); - return advices; - } - - public override void AfterPropertiesSet() - { - _logger.LogTrace("AfterPropertiesSet"); - base.AfterPropertiesSet(); - } + _logger.LogTrace("GetAdvicesAndAdvisorsForObject begin"); + IList advices = base.GetAdvicesAndAdvisorsForObject(targetType, targetName, customTargetSource); + _logger.LogTrace("GetAdvicesAndAdvisorsForObject end"); + return advices; } - public class CountingAfterReturningAdvisor : StaticMethodMatcherPointcutAdvisor + public override void AfterPropertiesSet() { - private ITestObject testObject; + _logger.LogTrace("AfterPropertiesSet"); + base.AfterPropertiesSet(); + } +} - public ITestObject TestObject - { - get { return this.testObject; } - set { this.testObject = value; } - } +public class CountingAfterReturningAdvisor : StaticMethodMatcherPointcutAdvisor +{ + private ITestObject testObject; - public int GetCalls() - { - return ((CountingAfterReturningAdvice) base.Advice).GetCalls(); - } - - public CountingAfterReturningAdvisor() - { - LogManager.GetLogger(this.GetType()).LogTrace("Created instance #" + this.GetHashCode()); - base.Advice = new CountingAfterReturningAdvice(); - } - - public override bool Matches(MethodInfo method, Type targetType) - { - return true; - } + public ITestObject TestObject + { + get { return this.testObject; } + set { this.testObject = value; } } - public class SomeOtherObject : ICloneable + public int GetCalls() { - public SomeOtherObject() - { - LogManager.GetLogger(this.GetType()).LogTrace("Created instance #" + this.GetHashCode()); - } - - public object Clone() - { - return this; - } + return ((CountingAfterReturningAdvice) base.Advice).GetCalls(); } - public class IndependentObject : ICloneable + public CountingAfterReturningAdvisor() { - public IndependentObject() - { - LogManager.GetLogger(this.GetType()).LogTrace("Created instance #" + this.GetHashCode()); - } - - public object Clone() - { - return this; - } + LogManager.GetLogger(this.GetType()).LogTrace("Created instance #" + this.GetHashCode()); + base.Advice = new CountingAfterReturningAdvice(); } - - public class TestObjectFactoryObject : IFactoryObject, IInitializingObject + + public override bool Matches(MethodInfo method, Type targetType) { - private bool initialized = false; - private ITestObject testObject; - private SomeOtherObject someOtherObject; - private readonly ILog _logger; + return true; + } +} - public int GetObjectCounter = 0; +public class SomeOtherObject : ICloneable +{ + public SomeOtherObject() + { + LogManager.GetLogger(this.GetType()).LogTrace("Created instance #" + this.GetHashCode()); + } - public TestObjectFactoryObject() + public object Clone() + { + return this; + } +} + +public class IndependentObject : ICloneable +{ + public IndependentObject() + { + LogManager.GetLogger(this.GetType()).LogTrace("Created instance #" + this.GetHashCode()); + } + + public object Clone() + { + return this; + } +} + +public class TestObjectFactoryObject : IFactoryObject, IInitializingObject +{ + private bool initialized = false; + private ITestObject testObject; + private SomeOtherObject someOtherObject; + private readonly ILog _logger; + + public int GetObjectCounter = 0; + + public TestObjectFactoryObject() + { + _logger = LogManager.GetLogger(this.GetType().Name + "#" + this.GetHashCode()); + _logger.LogTrace("Created instance"); + } + + public SomeOtherObject SomeOtherObject + { + get { return this.someOtherObject; } + set { this.someOtherObject = value; } + } + + public object GetObject() + { + GetObjectCounter++; + // return product only, if factory has been fully initialized! + if (!initialized) { - _logger = LogManager.GetLogger(this.GetType().Name + "#" + this.GetHashCode()); - _logger.LogTrace("Created instance"); + _logger.LogTrace("GetObject(): not initialized, returning null"); + return null; } - public SomeOtherObject SomeOtherObject - { - get { return this.someOtherObject; } - set { this.someOtherObject = value; } - } + _logger.LogTrace("GetObject(): initialized, returning testObject"); + return testObject; + } - public object GetObject() + public Type ObjectType + { + get { - GetObjectCounter++; - // return product only, if factory has been fully initialized! + // return type only if we are ready to deliver our product! if (!initialized) { - _logger.LogTrace("GetObject(): not initialized, returning null"); + _logger.LogTrace("get_ObjectType(): not initialized, returning null"); return null; } - _logger.LogTrace("GetObject(): initialized, returning testObject"); - return testObject; - } - public Type ObjectType - { - get - { - // return type only if we are ready to deliver our product! - if (!initialized) - { - _logger.LogTrace("get_ObjectType(): not initialized, returning null"); - return null; - } - _logger.LogTrace("get_ObjectType(): initialized, returning typeof(ITestObject)"); - return typeof(ITestObject); - } - } - - public bool IsSingleton - { - get { return true; } - } - - public void AfterPropertiesSet() - { - _logger.LogTrace("AfterPropertiesSet"); - Assert.IsNotNull(someOtherObject); - testObject = new TestObject(); - initialized = true; + _logger.LogTrace("get_ObjectType(): initialized, returning typeof(ITestObject)"); + return typeof(ITestObject); } } - #endregion + public bool IsSingleton + { + get { return true; } + } + + public void AfterPropertiesSet() + { + _logger.LogTrace("AfterPropertiesSet"); + Assert.IsNotNull(someOtherObject); + testObject = new TestObject(); + initialized = true; + } } + +#endregion \ No newline at end of file diff --git a/test/Spring/Spring.Aop.Tests/Aop/Framework/AutoProxy/AdvisorAutoProxyCreatorTests.cs b/test/Spring/Spring.Aop.Tests/Aop/Framework/AutoProxy/AdvisorAutoProxyCreatorTests.cs index fb46b8d6..59e67ab9 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Framework/AutoProxy/AdvisorAutoProxyCreatorTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Framework/AutoProxy/AdvisorAutoProxyCreatorTests.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -21,7 +21,6 @@ #region Imports using NUnit.Framework; - using Spring.Context.Support; using Spring.Objects; using Spring.Objects.Factory; @@ -30,91 +29,88 @@ using Spring.Threading; #endregion#region License -namespace Spring.Aop.Framework.AutoProxy +namespace Spring.Aop.Framework.AutoProxy; + +/// +/// Tests for auto proxy creation by advisor recognition. +/// +/// Rod Johnson +/// Mark Pollack (.NET) +[TestFixture] +public class AdvisorAutoProxyCreatorTests { - /// - /// Tests for auto proxy creation by advisor recognition. - /// - /// Rod Johnson - /// Mark Pollack (.NET) - [TestFixture] - public class AdvisorAutoProxyCreatorTests + private static string ADVISOR_APC_OBJECT_NAME = "aapc"; + + protected virtual IObjectFactory ObjectFactory { - private static string ADVISOR_APC_OBJECT_NAME = "aapc"; - - protected virtual IObjectFactory ObjectFactory + get { - get - { - string configLocation = ReadOnlyXmlTestResource.GetFilePath("advisorAutoProxyCreator.xml", typeof(AdvisorAutoProxyCreatorTests)); - return new XmlApplicationContext(configLocation); - } - } - - [Test] - public void DefaultExclusionPrefix() - { - DefaultAdvisorAutoProxyCreator aapc = (DefaultAdvisorAutoProxyCreator)ObjectFactory.GetObject(ADVISOR_APC_OBJECT_NAME); - Assert.AreEqual(ADVISOR_APC_OBJECT_NAME + DefaultAdvisorAutoProxyCreator.Separator, aapc.AdvisorObjectNamePrefix); - Assert.IsFalse(aapc.UsePrefix); - } - - /// - /// No pointcuts match the methods on NoSetterProperties therefore - /// there should be proxying. - /// - [Test] - public void NoProxy() - { - IObjectFactory of = ObjectFactory; - object o = of.GetObject("noSetterPropertiesObject"); - Assert.IsFalse(AopUtils.IsAopProxy(o)); - } - - /// - /// A pointcut matches the property (i.e. method set_Age) on TestObject - /// therefore there should be proxying. - /// - [Test] - public void HasProxy() - { - IObjectFactory of = ObjectFactory; - object o = of.GetObject("testObject"); - Assert.IsTrue(AopUtils.IsAopProxy(o), "Expected TestObject to be proxied"); - } - - [Test] - public void RegexpApplied() - { - IObjectFactory of = ObjectFactory; - ITestObject testObject = (ITestObject)of.GetObject("testObject"); - MethodCounter counter = (MethodCounter)of.GetObject("CountingAdvice"); - Assert.AreEqual(0,counter.GetCalls()); - testObject.Spouse = new TestObject("Daniela", 23); - Assert.AreEqual(0, counter.GetCalls()); - testObject.Name = "foo"; - Assert.AreEqual(1, counter.GetCalls()); - - } - - [Test] - public void SetLTCValue() - { - IObjectFactory of = ObjectFactory; - ITestObject testObject = (ITestObject)of.GetObject("testObject"); - OrderedLogicalThreadContextCheckAdvisor orderedBeforeLTCSet = - (OrderedLogicalThreadContextCheckAdvisor)of.GetObject("orderedBeforeLTCSet"); - Assert.AreEqual(0, orderedBeforeLTCSet.CountingBeforeAdvice.GetCalls()); - - Assert.IsNull(LogicalThreadContext.GetData(LogicalThreadContextAdvice.ORDERING_SLOT)); - Assert.AreEqual(4, testObject.Age, "Initial value of age for test object is not correct."); - int newAge = 5; - testObject.Age = newAge; - Assert.AreEqual(1, orderedBeforeLTCSet.CountingBeforeAdvice.GetCalls()); - - Assert.AreEqual(newAge, testObject.Age, "Assigned value of age for test object is not correct."); - Assert.IsNotNull(LogicalThreadContext.GetData(LogicalThreadContextAdvice.ORDERING_SLOT)); - + string configLocation = ReadOnlyXmlTestResource.GetFilePath("advisorAutoProxyCreator.xml", typeof(AdvisorAutoProxyCreatorTests)); + return new XmlApplicationContext(configLocation); } } -} \ No newline at end of file + + [Test] + public void DefaultExclusionPrefix() + { + DefaultAdvisorAutoProxyCreator aapc = (DefaultAdvisorAutoProxyCreator) ObjectFactory.GetObject(ADVISOR_APC_OBJECT_NAME); + Assert.AreEqual(ADVISOR_APC_OBJECT_NAME + DefaultAdvisorAutoProxyCreator.Separator, aapc.AdvisorObjectNamePrefix); + Assert.IsFalse(aapc.UsePrefix); + } + + /// + /// No pointcuts match the methods on NoSetterProperties therefore + /// there should be proxying. + /// + [Test] + public void NoProxy() + { + IObjectFactory of = ObjectFactory; + object o = of.GetObject("noSetterPropertiesObject"); + Assert.IsFalse(AopUtils.IsAopProxy(o)); + } + + /// + /// A pointcut matches the property (i.e. method set_Age) on TestObject + /// therefore there should be proxying. + /// + [Test] + public void HasProxy() + { + IObjectFactory of = ObjectFactory; + object o = of.GetObject("testObject"); + Assert.IsTrue(AopUtils.IsAopProxy(o), "Expected TestObject to be proxied"); + } + + [Test] + public void RegexpApplied() + { + IObjectFactory of = ObjectFactory; + ITestObject testObject = (ITestObject) of.GetObject("testObject"); + MethodCounter counter = (MethodCounter) of.GetObject("CountingAdvice"); + Assert.AreEqual(0, counter.GetCalls()); + testObject.Spouse = new TestObject("Daniela", 23); + Assert.AreEqual(0, counter.GetCalls()); + testObject.Name = "foo"; + Assert.AreEqual(1, counter.GetCalls()); + } + + [Test] + public void SetLTCValue() + { + IObjectFactory of = ObjectFactory; + ITestObject testObject = (ITestObject) of.GetObject("testObject"); + OrderedLogicalThreadContextCheckAdvisor orderedBeforeLTCSet = + (OrderedLogicalThreadContextCheckAdvisor) of.GetObject("orderedBeforeLTCSet"); + Assert.AreEqual(0, orderedBeforeLTCSet.CountingBeforeAdvice.GetCalls()); + + Assert.IsNull(LogicalThreadContext.GetData(LogicalThreadContextAdvice.ORDERING_SLOT)); + Assert.AreEqual(4, testObject.Age, "Initial value of age for test object is not correct."); + int newAge = 5; + testObject.Age = newAge; + Assert.AreEqual(1, orderedBeforeLTCSet.CountingBeforeAdvice.GetCalls()); + + Assert.AreEqual(newAge, testObject.Age, "Assigned value of age for test object is not correct."); + Assert.IsNotNull(LogicalThreadContext.GetData(LogicalThreadContextAdvice.ORDERING_SLOT)); + } +} diff --git a/test/Spring/Spring.Aop.Tests/Aop/Framework/AutoProxy/AttributeAutoProxyCreatorTests.cs b/test/Spring/Spring.Aop.Tests/Aop/Framework/AutoProxy/AttributeAutoProxyCreatorTests.cs index 3a7c6716..b2e301cd 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Framework/AutoProxy/AttributeAutoProxyCreatorTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Framework/AutoProxy/AttributeAutoProxyCreatorTests.cs @@ -21,127 +21,131 @@ #region Imports using NUnit.Framework; - using Spring.Objects; #endregion -namespace Spring.Aop.Framework.AutoProxy +namespace Spring.Aop.Framework.AutoProxy; + +/// +/// +/// +/// Erich Eichinger +[TestFixture] +public class AttributeAutoProxyCreatorTests { - /// - /// - /// - /// Erich Eichinger - [TestFixture] - public class AttributeAutoProxyCreatorTests + public interface IEmptyInterface { - public interface IEmptyInterface - {} - - [AttributeUsage( AttributeTargets.Class|AttributeTargets.Method, Inherited=false )] - private class ApcTestAttribute : Attribute {} - - private class ApcTestObject: IEmptyInterface {} - - [ApcTest] - private class AttributedApcTestObject : ApcTestObject - {} - - private class DerivedAttributedApcTestObject : AttributedApcTestObject - { - [ApcTest] - public void SomeMethod() {} - } - - [Test] - public void ThrowsOnMissingAttributeTypeList() - { - AttributeAutoProxyCreator apc = new AttributeAutoProxyCreator(); - Assert.Throws(() => apc.PostProcessAfterInitialization(new ApcTestObject(), "testObject")); - } - - [Test] - public void ThrowsOnAssigningNullAttributeList() - { - AttributeAutoProxyCreator apc = new AttributeAutoProxyCreator(); - Assert.Throws(() => apc.AttributeTypes = null); - } - - [Test] - public void AllowsEmptyAttributeList() - { - AttributeAutoProxyCreator apc = new AttributeAutoProxyCreator(); - apc.AttributeTypes = new Type[0]; - apc.PostProcessAfterInitialization( new ApcTestObject(), "testObject" ); - } - - [Test] - public void DefaultsToNotCheckInherited() - { - AttributeAutoProxyCreator apc = new AttributeAutoProxyCreator(); - Assert.IsFalse(apc.CheckInherited); - } - - [Test] - public void CreatesProxyOnAttributeMatch() - { - AttributeAutoProxyCreator apc = new AttributeAutoProxyCreator(); - apc.AttributeTypes = new Type[] { typeof(ApcTestAttribute) }; - - object result = apc.PostProcessAfterInitialization( new AttributedApcTestObject(), "testObject" ); - Assert.IsTrue( AopUtils.IsAopProxy( result ) ); - } - - [Test] - public void CreatesProxyOnInheritedAttributeMatchWhenCheckInherited() - { - AttributeAutoProxyCreator apc = new AttributeAutoProxyCreator(); - apc.AttributeTypes = new Type[] { typeof(ApcTestAttribute) }; - apc.CheckInherited = true; - object result = apc.PostProcessAfterInitialization( new DerivedAttributedApcTestObject(), "testObject" ); - Assert.IsTrue( AopUtils.IsAopProxy( result ) ); - } - - [Test] - public void DoesNotCreateProxyOnInheritedAttributeMatchWhenNotCheckInherited() - { - AttributeAutoProxyCreator apc = new AttributeAutoProxyCreator(); - apc.AttributeTypes = new Type[] { typeof(ApcTestAttribute) }; - apc.CheckInherited = false; - object result = apc.PostProcessAfterInitialization( new DerivedAttributedApcTestObject(), "testObject" ); - Assert.IsFalse( AopUtils.IsAopProxy( result ) ); - } - - [Test] - public void DoesNotCreateProxyIfNoAttributeMatch() - { - AttributeAutoProxyCreator apc = new AttributeAutoProxyCreator(); - apc.AttributeTypes = new Type[] { typeof(ApcTestAttribute) }; - - object result = apc.PostProcessAfterInitialization( new TestObject(), "testObject" ); - Assert.IsFalse( AopUtils.IsAopProxy( result ) ); - } - - [Test] - public void DoesNotCheckMethodLevelAttributes() - { - AttributeAutoProxyCreator apc = new AttributeAutoProxyCreator(); - apc.AttributeTypes = new Type[] { typeof(ApcTestAttribute) }; - apc.CheckInherited = false; // (!) - - // does not check method level attributes! - object result = apc.PostProcessAfterInitialization( new DerivedAttributedApcTestObject(), "testObject" ); - Assert.IsFalse( AopUtils.IsAopProxy( result ) ); - } - - [Test] - public void DoesNotCreateProxyIfEmptyAtributeList() - { - AttributeAutoProxyCreator apc = new AttributeAutoProxyCreator(); - apc.AttributeTypes = new Type[0]; - - object result = apc.PostProcessAfterInitialization( new ApcTestObject(), "testObject" ); - Assert.IsFalse( AopUtils.IsAopProxy( result ) ); - } } -} \ No newline at end of file + + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = false)] + private class ApcTestAttribute : Attribute + { + } + + private class ApcTestObject : IEmptyInterface + { + } + + [ApcTest] + private class AttributedApcTestObject : ApcTestObject + { + } + + private class DerivedAttributedApcTestObject : AttributedApcTestObject + { + [ApcTest] + public void SomeMethod() { } + } + + [Test] + public void ThrowsOnMissingAttributeTypeList() + { + AttributeAutoProxyCreator apc = new AttributeAutoProxyCreator(); + Assert.Throws(() => apc.PostProcessAfterInitialization(new ApcTestObject(), "testObject")); + } + + [Test] + public void ThrowsOnAssigningNullAttributeList() + { + AttributeAutoProxyCreator apc = new AttributeAutoProxyCreator(); + Assert.Throws(() => apc.AttributeTypes = null); + } + + [Test] + public void AllowsEmptyAttributeList() + { + AttributeAutoProxyCreator apc = new AttributeAutoProxyCreator(); + apc.AttributeTypes = new Type[0]; + apc.PostProcessAfterInitialization(new ApcTestObject(), "testObject"); + } + + [Test] + public void DefaultsToNotCheckInherited() + { + AttributeAutoProxyCreator apc = new AttributeAutoProxyCreator(); + Assert.IsFalse(apc.CheckInherited); + } + + [Test] + public void CreatesProxyOnAttributeMatch() + { + AttributeAutoProxyCreator apc = new AttributeAutoProxyCreator(); + apc.AttributeTypes = new Type[] { typeof(ApcTestAttribute) }; + + object result = apc.PostProcessAfterInitialization(new AttributedApcTestObject(), "testObject"); + Assert.IsTrue(AopUtils.IsAopProxy(result)); + } + + [Test] + public void CreatesProxyOnInheritedAttributeMatchWhenCheckInherited() + { + AttributeAutoProxyCreator apc = new AttributeAutoProxyCreator(); + apc.AttributeTypes = new Type[] { typeof(ApcTestAttribute) }; + apc.CheckInherited = true; + object result = apc.PostProcessAfterInitialization(new DerivedAttributedApcTestObject(), "testObject"); + Assert.IsTrue(AopUtils.IsAopProxy(result)); + } + + [Test] + public void DoesNotCreateProxyOnInheritedAttributeMatchWhenNotCheckInherited() + { + AttributeAutoProxyCreator apc = new AttributeAutoProxyCreator(); + apc.AttributeTypes = new Type[] { typeof(ApcTestAttribute) }; + apc.CheckInherited = false; + object result = apc.PostProcessAfterInitialization(new DerivedAttributedApcTestObject(), "testObject"); + Assert.IsFalse(AopUtils.IsAopProxy(result)); + } + + [Test] + public void DoesNotCreateProxyIfNoAttributeMatch() + { + AttributeAutoProxyCreator apc = new AttributeAutoProxyCreator(); + apc.AttributeTypes = new Type[] { typeof(ApcTestAttribute) }; + + object result = apc.PostProcessAfterInitialization(new TestObject(), "testObject"); + Assert.IsFalse(AopUtils.IsAopProxy(result)); + } + + [Test] + public void DoesNotCheckMethodLevelAttributes() + { + AttributeAutoProxyCreator apc = new AttributeAutoProxyCreator(); + apc.AttributeTypes = new Type[] { typeof(ApcTestAttribute) }; + apc.CheckInherited = false; // (!) + + // does not check method level attributes! + object result = apc.PostProcessAfterInitialization(new DerivedAttributedApcTestObject(), "testObject"); + Assert.IsFalse(AopUtils.IsAopProxy(result)); + } + + [Test] + public void DoesNotCreateProxyIfEmptyAtributeList() + { + AttributeAutoProxyCreator apc = new AttributeAutoProxyCreator(); + apc.AttributeTypes = new Type[0]; + + object result = apc.PostProcessAfterInitialization(new ApcTestObject(), "testObject"); + Assert.IsFalse(AopUtils.IsAopProxy(result)); + } +} diff --git a/test/Spring/Spring.Aop.Tests/Aop/Framework/AutoProxy/CreatesTestObject.cs b/test/Spring/Spring.Aop.Tests/Aop/Framework/AutoProxy/CreatesTestObject.cs index 5828418a..11beb40e 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Framework/AutoProxy/CreatesTestObject.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Framework/AutoProxy/CreatesTestObject.cs @@ -21,60 +21,58 @@ using Spring.Objects; using Spring.Objects.Factory; -namespace Spring.Aop.Framework.AutoProxy +namespace Spring.Aop.Framework.AutoProxy; + +/// +/// This is simple implementation of IFactoryObject that creates a TestObject. +/// +/// Mark Pollack +public class CreatesTestObject : IFactoryObject, IInitializingObject { - /// - /// This is simple implementation of IFactoryObject that creates a TestObject. - /// - /// Mark Pollack - public class CreatesTestObject : IFactoryObject, IInitializingObject + private bool initialized = false; + private ITestObject testObject; + + public CreatesTestObject() { - private bool initialized = false; - private ITestObject testObject; + } - public CreatesTestObject() + public object GetObject() + { + // return product only, if factory has been fully initialized! + if (!initialized) { + return null; } - - - public object GetObject() + else { - // return product only, if factory has been fully initialized! + return testObject; + } + } + + public Type ObjectType + { + get + { + // return type only if we are ready to deliver our product! if (!initialized) { return null; } else { - return testObject; + return typeof(ITestObject); } } - - public Type ObjectType - { - get - { - // return type only if we are ready to deliver our product! - if (!initialized) - { - return null; - } - else - { - return typeof(ITestObject); - } - } - } - - public bool IsSingleton - { - get { return true; } - } - - public void AfterPropertiesSet() - { - testObject = new TestObject(); - initialized = true; - } } -} \ No newline at end of file + + public bool IsSingleton + { + get { return true; } + } + + public void AfterPropertiesSet() + { + testObject = new TestObject(); + initialized = true; + } +} diff --git a/test/Spring/Spring.Aop.Tests/Aop/Framework/AutoProxy/DefaultAdvisorAutoProxyCreatorTests.cs b/test/Spring/Spring.Aop.Tests/Aop/Framework/AutoProxy/DefaultAdvisorAutoProxyCreatorTests.cs index 38ab42e4..7b86f2c0 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Framework/AutoProxy/DefaultAdvisorAutoProxyCreatorTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Framework/AutoProxy/DefaultAdvisorAutoProxyCreatorTests.cs @@ -6,66 +6,65 @@ using Spring.Context.Support; using Spring.Objects; using Spring.Objects.Factory.Support; -namespace Spring.Aop.Framework.AutoProxy +namespace Spring.Aop.Framework.AutoProxy; + +[TestFixture] +public class DefaultAdvisorAutoProxyCreatorTests { - [TestFixture] - public class DefaultAdvisorAutoProxyCreatorTests + private class CapturingAdvice : IMethodInterceptor { - private class CapturingAdvice : IMethodInterceptor + public readonly ArrayList CapturedCalls = new ArrayList(); + + public object Invoke(IMethodInvocation invocation) { - public readonly ArrayList CapturedCalls = new ArrayList(); - - public object Invoke(IMethodInvocation invocation) - { - CapturedCalls.Add(invocation); - return invocation.Proceed(); - } - } - - public interface ITestObjectFactoryObject - { - ITestObject CreateTestObject(); - } - - public class TestObjectFactoryObject : ITestObjectFactoryObject - { - public ITestObject CreateTestObject() - { - return new TestObject("TheName", 10); - } - } - - [Test] - public void CanProxyFactoryMethodProducts() - { - GenericApplicationContext ctx = new GenericApplicationContext(); - ctx.ObjectFactory.AddObjectPostProcessor(new DefaultAdvisorAutoProxyCreator()); - - CapturingAdvice capturingAdvice = new CapturingAdvice(); - ctx.ObjectFactory.RegisterSingleton("logging", new DefaultPointcutAdvisor(TruePointcut.True, capturingAdvice)); - - // register "factory" object - RootObjectDefinition rod; - rod = new RootObjectDefinition(typeof(TestObjectFactoryObject)); - ctx.ObjectFactory.RegisterObjectDefinition("test", rod); - - // register product, referencing the factory object - rod = new RootObjectDefinition(typeof(ITestObject)); - rod.FactoryObjectName = "test"; - rod.FactoryMethodName = "CreateTestObject"; - ctx.ObjectFactory.RegisterObjectDefinition("testProduct", rod); - - ctx.Refresh(); - - ITestObjectFactoryObject fo = (ITestObjectFactoryObject) ctx.GetObject("test"); - Assert.IsTrue( AopUtils.IsAopProxy(fo) ); - Assert.AreEqual("CreateTestObject", ((IMethodInvocation)capturingAdvice.CapturedCalls[0]).Method.Name); - - capturingAdvice.CapturedCalls.Clear(); - ITestObject to = (ITestObject)ctx.GetObject("testProduct"); - Assert.IsTrue( AopUtils.IsAopProxy(to) ); - Assert.AreEqual("TheName", to.Name); - Assert.AreEqual("get_Name", ((IMethodInvocation)capturingAdvice.CapturedCalls[0]).Method.Name); + CapturedCalls.Add(invocation); + return invocation.Proceed(); } } -} \ No newline at end of file + + public interface ITestObjectFactoryObject + { + ITestObject CreateTestObject(); + } + + public class TestObjectFactoryObject : ITestObjectFactoryObject + { + public ITestObject CreateTestObject() + { + return new TestObject("TheName", 10); + } + } + + [Test] + public void CanProxyFactoryMethodProducts() + { + GenericApplicationContext ctx = new GenericApplicationContext(); + ctx.ObjectFactory.AddObjectPostProcessor(new DefaultAdvisorAutoProxyCreator()); + + CapturingAdvice capturingAdvice = new CapturingAdvice(); + ctx.ObjectFactory.RegisterSingleton("logging", new DefaultPointcutAdvisor(TruePointcut.True, capturingAdvice)); + + // register "factory" object + RootObjectDefinition rod; + rod = new RootObjectDefinition(typeof(TestObjectFactoryObject)); + ctx.ObjectFactory.RegisterObjectDefinition("test", rod); + + // register product, referencing the factory object + rod = new RootObjectDefinition(typeof(ITestObject)); + rod.FactoryObjectName = "test"; + rod.FactoryMethodName = "CreateTestObject"; + ctx.ObjectFactory.RegisterObjectDefinition("testProduct", rod); + + ctx.Refresh(); + + ITestObjectFactoryObject fo = (ITestObjectFactoryObject) ctx.GetObject("test"); + Assert.IsTrue(AopUtils.IsAopProxy(fo)); + Assert.AreEqual("CreateTestObject", ((IMethodInvocation) capturingAdvice.CapturedCalls[0]).Method.Name); + + capturingAdvice.CapturedCalls.Clear(); + ITestObject to = (ITestObject) ctx.GetObject("testProduct"); + Assert.IsTrue(AopUtils.IsAopProxy(to)); + Assert.AreEqual("TheName", to.Name); + Assert.AreEqual("get_Name", ((IMethodInvocation) capturingAdvice.CapturedCalls[0]).Method.Name); + } +} diff --git a/test/Spring/Spring.Aop.Tests/Aop/Framework/AutoProxy/InfrastructureAdvisorAutoProxyCreator.cs b/test/Spring/Spring.Aop.Tests/Aop/Framework/AutoProxy/InfrastructureAdvisorAutoProxyCreator.cs index baba0beb..ec2f5eb5 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Framework/AutoProxy/InfrastructureAdvisorAutoProxyCreator.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Framework/AutoProxy/InfrastructureAdvisorAutoProxyCreator.cs @@ -23,63 +23,62 @@ using NUnit.Framework; using Spring.Objects.Factory.Config; using Spring.Objects.Factory.Support; -namespace Spring.Aop.Framework.AutoProxy +namespace Spring.Aop.Framework.AutoProxy; + +/// +/// +/// Erich Eichinger +[TestFixture] +public class InfrastructureAdvisorAutoProxyCreatorTests { - /// - /// - /// Erich Eichinger - [TestFixture] - public class InfrastructureAdvisorAutoProxyCreatorTests + public class TestAdvisorAutoProxyCreator : InfrastructureAdvisorAutoProxyCreator { - public class TestAdvisorAutoProxyCreator : InfrastructureAdvisorAutoProxyCreator + public IList GetAdvicesAndAdvisorsForObject(Type targetType, string targetName) { - public IList GetAdvicesAndAdvisorsForObject(Type targetType, string targetName) - { - return base.GetAdvicesAndAdvisorsForObject(targetType, targetName, null); - } - } - - public class TestAdvisor : IAdvisor - { - public string Name; - - #region Implementation of IAdvisor - - public bool IsPerInstance - { - get { throw new NotImplementedException(); } - } - - public IAdvice Advice - { - get { throw new NotImplementedException(); } - } - - #endregion - } - - [Test] - public void DoesAcceptInfrastructureAdvisorsOnlyDuringScanning() - { - DefaultListableObjectFactory of = new DefaultListableObjectFactory(); - - GenericObjectDefinition infrastructureAdvisorDefinition = new GenericObjectDefinition(); - infrastructureAdvisorDefinition.ObjectType = typeof(TestAdvisor); - infrastructureAdvisorDefinition.PropertyValues.Add("Name", "InfrastructureAdvisor"); - infrastructureAdvisorDefinition.Role = ObjectRole.ROLE_INFRASTRUCTURE; - of.RegisterObjectDefinition("infrastructure", infrastructureAdvisorDefinition); - - GenericObjectDefinition regularAdvisorDefinition = new GenericObjectDefinition(); - regularAdvisorDefinition.ObjectType = typeof(TestAdvisor); - regularAdvisorDefinition.PropertyValues.Add("Name", "RegularAdvisor"); - // regularAdvisorDefinition.Role = ObjectRole.ROLE_APPLICATION; - of.RegisterObjectDefinition("regular", regularAdvisorDefinition); - - TestAdvisorAutoProxyCreator apc = new TestAdvisorAutoProxyCreator(); - apc.ObjectFactory = of; - IList advisors = apc.GetAdvicesAndAdvisorsForObject(typeof(object), "dummyTarget"); - Assert.AreEqual(1, advisors.Count); - Assert.AreEqual("InfrastructureAdvisor", ((TestAdvisor)advisors[0]).Name); + return base.GetAdvicesAndAdvisorsForObject(targetType, targetName, null); } } -} \ No newline at end of file + + public class TestAdvisor : IAdvisor + { + public string Name; + + #region Implementation of IAdvisor + + public bool IsPerInstance + { + get { throw new NotImplementedException(); } + } + + public IAdvice Advice + { + get { throw new NotImplementedException(); } + } + + #endregion + } + + [Test] + public void DoesAcceptInfrastructureAdvisorsOnlyDuringScanning() + { + DefaultListableObjectFactory of = new DefaultListableObjectFactory(); + + GenericObjectDefinition infrastructureAdvisorDefinition = new GenericObjectDefinition(); + infrastructureAdvisorDefinition.ObjectType = typeof(TestAdvisor); + infrastructureAdvisorDefinition.PropertyValues.Add("Name", "InfrastructureAdvisor"); + infrastructureAdvisorDefinition.Role = ObjectRole.ROLE_INFRASTRUCTURE; + of.RegisterObjectDefinition("infrastructure", infrastructureAdvisorDefinition); + + GenericObjectDefinition regularAdvisorDefinition = new GenericObjectDefinition(); + regularAdvisorDefinition.ObjectType = typeof(TestAdvisor); + regularAdvisorDefinition.PropertyValues.Add("Name", "RegularAdvisor"); + // regularAdvisorDefinition.Role = ObjectRole.ROLE_APPLICATION; + of.RegisterObjectDefinition("regular", regularAdvisorDefinition); + + TestAdvisorAutoProxyCreator apc = new TestAdvisorAutoProxyCreator(); + apc.ObjectFactory = of; + IList advisors = apc.GetAdvicesAndAdvisorsForObject(typeof(object), "dummyTarget"); + Assert.AreEqual(1, advisors.Count); + Assert.AreEqual("InfrastructureAdvisor", ((TestAdvisor) advisors[0]).Name); + } +} diff --git a/test/Spring/Spring.Aop.Tests/Aop/Framework/AutoProxy/LogicalThreadContextAdvice.cs b/test/Spring/Spring.Aop.Tests/Aop/Framework/AutoProxy/LogicalThreadContextAdvice.cs index 2418f59b..460b0231 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Framework/AutoProxy/LogicalThreadContextAdvice.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Framework/AutoProxy/LogicalThreadContextAdvice.cs @@ -2,13 +2,13 @@ /* * Copyright 2002-2010 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. @@ -25,15 +25,14 @@ using Spring.Threading; #endregion -namespace Spring.Aop.Framework.AutoProxy -{ - public class LogicalThreadContextAdvice : IMethodBeforeAdvice - { - public static string ORDERING_SLOT = "ordering_slot"; +namespace Spring.Aop.Framework.AutoProxy; - public void Before(MethodInfo method, object[] args, object target) - { - LogicalThreadContext.SetData(ORDERING_SLOT, new object()); - } +public class LogicalThreadContextAdvice : IMethodBeforeAdvice +{ + public static string ORDERING_SLOT = "ordering_slot"; + + public void Before(MethodInfo method, object[] args, object target) + { + LogicalThreadContext.SetData(ORDERING_SLOT, new object()); } -} \ No newline at end of file +} diff --git a/test/Spring/Spring.Aop.Tests/Aop/Framework/AutoProxy/NoSetterProperties.cs b/test/Spring/Spring.Aop.Tests/Aop/Framework/AutoProxy/NoSetterProperties.cs index bb859e01..beac63e8 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Framework/AutoProxy/NoSetterProperties.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Framework/AutoProxy/NoSetterProperties.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -20,25 +20,24 @@ using System.Text; -namespace Spring.Aop.Framework.AutoProxy +namespace Spring.Aop.Framework.AutoProxy; + +public class NoSetterProperties { - public class NoSetterProperties + public string FancyName { - public string FancyName + get { - get - { - return "Joe Suave"; - } + return "Joe Suave"; } - - public void DoWork() + } + + public void DoWork() + { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < 100; i++) { - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < 100; i++) - { - sb.Append(i); - } + sb.Append(i); } } } diff --git a/test/Spring/Spring.Aop.Tests/Aop/Framework/AutoProxy/ObjectNameAutoProxyCreatorTests.cs b/test/Spring/Spring.Aop.Tests/Aop/Framework/AutoProxy/ObjectNameAutoProxyCreatorTests.cs index 729f91c0..3249ffeb 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Framework/AutoProxy/ObjectNameAutoProxyCreatorTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Framework/AutoProxy/ObjectNameAutoProxyCreatorTests.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -29,133 +29,131 @@ using Spring.Objects.Factory.Xml; #endregion#region License -namespace Spring.Aop.Framework.AutoProxy +namespace Spring.Aop.Framework.AutoProxy; + +/// +/// Tests for ObjectNameAutoProxyCreator functionality +/// +/// Mark Pollack +[TestFixture] +public class ObjectNameAutoProxyCreatorTests { - /// - /// Tests for ObjectNameAutoProxyCreator functionality - /// - /// Mark Pollack - [TestFixture] - public class ObjectNameAutoProxyCreatorTests + private IApplicationContext ctx; + + [SetUp] + public void SetUp() { - private IApplicationContext ctx; - - [SetUp] - public void SetUp() - { - string configLocation = - ReadOnlyXmlTestResource.GetFilePath("objectNameAutoProxyCreatorTests.xml", - typeof (ObjectNameAutoProxyCreatorTests)); - ctx = new XmlApplicationContext(configLocation); - } - - [Test] - public void NoProxy() - { - ITestObject testObject = (ITestObject) ctx.GetObject("noproxy"); - Assert.IsFalse(AopUtils.IsAopProxy(testObject), testObject + " is not an AOP proxy"); - Assert.AreEqual("noproxy", testObject.Name); - } - - [Test] - public void ProxyWithExactNameMatch() - { - ITestObject testObject = (ITestObject) ctx.GetObject("testObject"); - ProxyAssertions(testObject, 1); - Assert.AreEqual("SimpleTestObject", testObject.Name); - } - - [Test] - public void ProxyWithDoubleProxyingInvokesInterceptorsOnceOnly() - { - ITestObject testObject = (ITestObject)ctx.GetObject("doubleProxy"); - ProxyAssertions(testObject, 1); - Assert.AreEqual("doubleProxy", testObject.Name); - } - - [Test] - public void ProxyWithWildcardMatchSuffix() - { - ITestObject testObject = (ITestObject) ctx.GetObject("SmithFamilyMember"); - ProxyAssertions(testObject, 1); - Assert.AreEqual("John Smith", testObject.Name); - } - - [Test] - public void ProxyWithTwoWildcardsMatch() - { - ITestObject testObject = (ITestObject)ctx.GetObject("twoWildcardsTestObject"); - ProxyAssertions(testObject, 1); - Assert.AreEqual("Damjan Tomic", testObject.Name); - } - - [Test] - public void AppliesToCreatedObjectsNotFactoryObject() - { - ITestObject testObject = (ITestObject) ctx.GetObject("factoryObject"); - ProxyAssertions(testObject, 1); - } - - [Test] - public void FrozenProxy() - { - ITestObject testObject = (ITestObject)ctx.GetObject("frozen"); - Assert.IsTrue( ((IAdvised)testObject).IsFrozen); - } - - [Test] - public void Introduction() - { - object obj = ctx.GetObject("introductionUsingDecorator"); - Assert.IsNotNull(obj as IIsModified); - ITestObject testObject = (ITestObject) obj; - NopInterceptor nop = (NopInterceptor)ctx.GetObject("introductionNopInterceptor"); - Assert.AreEqual(0, nop.Count); - Assert.IsTrue(AopUtils.IsCompositionAopProxy(testObject), testObject + " is not an Composition AOP Proxy"); - int age = 5; - testObject.Age = age; - Assert.AreEqual(age, testObject.Age); - Assert.IsNotNull(testObject as IIsModified); - Assert.IsTrue(((IIsModified)testObject).IsModified); - Assert.AreEqual(3, nop.Count); - Assert.AreEqual("introductionUsingDecorator", testObject.Name); - } - - - private void ProxyAssertions(ITestObject testObject, int nopInterceptorCount) - { - NopInterceptor nop = (NopInterceptor) ctx.GetObject("nopInterceptor"); - Assert.AreEqual(0, nop.Count); - Assert.IsTrue(AopUtils.IsCompositionAopProxy(testObject), testObject + " is not an AOP Proxy"); - int age = 5; - testObject.Age = age; - Assert.AreEqual(age, testObject.Age); - Assert.AreEqual(2*nopInterceptorCount, nop.Count); - } - - [Test] - public void DecoratorProxyWithWildcardMatch() - { - ITestObject testObject = (ITestObject)ctx.GetObject("decoratorProxy"); - DecoratorProxyAssertions(testObject); - Assert.AreEqual("decoratorProxy", testObject.Name); - } - - private void DecoratorProxyAssertions(ITestObject testObject) - { - CountingBeforeAdvice cba = (CountingBeforeAdvice) ctx.GetObject("countingBeforeAdvice"); - NopInterceptor nop = (NopInterceptor)ctx.GetObject("nopInterceptor"); - Assert.AreEqual(0, cba.GetCalls()); - Assert.AreEqual(0, nop.Count); - Assert.IsTrue(AopUtils.IsDecoratorAopProxy(testObject), testObject + " is not an AOP Proxy"); - //extra advice calls are due to test IsDecoratorAopProxy and call to .GetType in impl - Assert.AreEqual(1, nop.Count); - Assert.AreEqual(1, cba.GetCalls()); - int age = 5; - testObject.Age = age; - Assert.AreEqual(age, testObject.Age); - Assert.AreEqual(3, nop.Count); - Assert.AreEqual(3, cba.GetCalls()); - } + string configLocation = + ReadOnlyXmlTestResource.GetFilePath("objectNameAutoProxyCreatorTests.xml", + typeof(ObjectNameAutoProxyCreatorTests)); + ctx = new XmlApplicationContext(configLocation); } -} \ No newline at end of file + + [Test] + public void NoProxy() + { + ITestObject testObject = (ITestObject) ctx.GetObject("noproxy"); + Assert.IsFalse(AopUtils.IsAopProxy(testObject), testObject + " is not an AOP proxy"); + Assert.AreEqual("noproxy", testObject.Name); + } + + [Test] + public void ProxyWithExactNameMatch() + { + ITestObject testObject = (ITestObject) ctx.GetObject("testObject"); + ProxyAssertions(testObject, 1); + Assert.AreEqual("SimpleTestObject", testObject.Name); + } + + [Test] + public void ProxyWithDoubleProxyingInvokesInterceptorsOnceOnly() + { + ITestObject testObject = (ITestObject) ctx.GetObject("doubleProxy"); + ProxyAssertions(testObject, 1); + Assert.AreEqual("doubleProxy", testObject.Name); + } + + [Test] + public void ProxyWithWildcardMatchSuffix() + { + ITestObject testObject = (ITestObject) ctx.GetObject("SmithFamilyMember"); + ProxyAssertions(testObject, 1); + Assert.AreEqual("John Smith", testObject.Name); + } + + [Test] + public void ProxyWithTwoWildcardsMatch() + { + ITestObject testObject = (ITestObject) ctx.GetObject("twoWildcardsTestObject"); + ProxyAssertions(testObject, 1); + Assert.AreEqual("Damjan Tomic", testObject.Name); + } + + [Test] + public void AppliesToCreatedObjectsNotFactoryObject() + { + ITestObject testObject = (ITestObject) ctx.GetObject("factoryObject"); + ProxyAssertions(testObject, 1); + } + + [Test] + public void FrozenProxy() + { + ITestObject testObject = (ITestObject) ctx.GetObject("frozen"); + Assert.IsTrue(((IAdvised) testObject).IsFrozen); + } + + [Test] + public void Introduction() + { + object obj = ctx.GetObject("introductionUsingDecorator"); + Assert.IsNotNull(obj as IIsModified); + ITestObject testObject = (ITestObject) obj; + NopInterceptor nop = (NopInterceptor) ctx.GetObject("introductionNopInterceptor"); + Assert.AreEqual(0, nop.Count); + Assert.IsTrue(AopUtils.IsCompositionAopProxy(testObject), testObject + " is not an Composition AOP Proxy"); + int age = 5; + testObject.Age = age; + Assert.AreEqual(age, testObject.Age); + Assert.IsNotNull(testObject as IIsModified); + Assert.IsTrue(((IIsModified) testObject).IsModified); + Assert.AreEqual(3, nop.Count); + Assert.AreEqual("introductionUsingDecorator", testObject.Name); + } + + private void ProxyAssertions(ITestObject testObject, int nopInterceptorCount) + { + NopInterceptor nop = (NopInterceptor) ctx.GetObject("nopInterceptor"); + Assert.AreEqual(0, nop.Count); + Assert.IsTrue(AopUtils.IsCompositionAopProxy(testObject), testObject + " is not an AOP Proxy"); + int age = 5; + testObject.Age = age; + Assert.AreEqual(age, testObject.Age); + Assert.AreEqual(2 * nopInterceptorCount, nop.Count); + } + + [Test] + public void DecoratorProxyWithWildcardMatch() + { + ITestObject testObject = (ITestObject) ctx.GetObject("decoratorProxy"); + DecoratorProxyAssertions(testObject); + Assert.AreEqual("decoratorProxy", testObject.Name); + } + + private void DecoratorProxyAssertions(ITestObject testObject) + { + CountingBeforeAdvice cba = (CountingBeforeAdvice) ctx.GetObject("countingBeforeAdvice"); + NopInterceptor nop = (NopInterceptor) ctx.GetObject("nopInterceptor"); + Assert.AreEqual(0, cba.GetCalls()); + Assert.AreEqual(0, nop.Count); + Assert.IsTrue(AopUtils.IsDecoratorAopProxy(testObject), testObject + " is not an AOP Proxy"); + //extra advice calls are due to test IsDecoratorAopProxy and call to .GetType in impl + Assert.AreEqual(1, nop.Count); + Assert.AreEqual(1, cba.GetCalls()); + int age = 5; + testObject.Age = age; + Assert.AreEqual(age, testObject.Age); + Assert.AreEqual(3, nop.Count); + Assert.AreEqual(3, cba.GetCalls()); + } +} diff --git a/test/Spring/Spring.Aop.Tests/Aop/Framework/AutoProxy/OrderedLogicalThreadContextCheckAdvisor.cs b/test/Spring/Spring.Aop.Tests/Aop/Framework/AutoProxy/OrderedLogicalThreadContextCheckAdvisor.cs index aeb1c894..2a560374 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Framework/AutoProxy/OrderedLogicalThreadContextCheckAdvisor.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Framework/AutoProxy/OrderedLogicalThreadContextCheckAdvisor.cs @@ -27,82 +27,78 @@ using Spring.Threading; #endregion -namespace Spring.Aop.Framework.AutoProxy +namespace Spring.Aop.Framework.AutoProxy; + +/// +/// Before advisor that allow us to manipulate ordering to check +/// that superclass sorting works correctly. +/// +/// +/// It doesn't actually do anything except count +/// method invocations and check for presence of a value in the +/// LogicalThreadContext. +/// +/// Mark Pollack (.NET) +public class OrderedLogicalThreadContextCheckAdvisor : StaticMethodMatcherPointcutAdvisor, IInitializingObject { - /// - /// Before advisor that allow us to manipulate ordering to check - /// that superclass sorting works correctly. - /// - /// - /// It doesn't actually do anything except count - /// method invocations and check for presence of a value in the - /// LogicalThreadContext. - /// - /// Mark Pollack (.NET) - public class OrderedLogicalThreadContextCheckAdvisor : StaticMethodMatcherPointcutAdvisor, IInitializingObject + public virtual bool RequireLTCHasValue { - - public virtual bool RequireLTCHasValue - { - get { return requireLtcHasValue; } + get { return requireLtcHasValue; } - set { requireLtcHasValue = value; } + set { requireLtcHasValue = value; } + } + + public virtual CountingBeforeAdvice CountingBeforeAdvice + { + get { return (CountingBeforeAdvice) Advice; } + } + + /// Should we insist on the presence of a transaction attribute or refuse to accept one? + private bool requireLtcHasValue = false; + + public virtual void AfterPropertiesSet() + { + Advice = new LTCCountingBeforeAdvice(this); + } + + public override bool Matches(MethodInfo method, Type targetClass) + { + return method.Name.StartsWith("set_Age"); + } + + private class LTCCountingBeforeAdvice : CountingBeforeAdvice + { + private OrderedLogicalThreadContextCheckAdvisor enclosingInstance; + + public LTCCountingBeforeAdvice(OrderedLogicalThreadContextCheckAdvisor enclosingInstance) + { + this.enclosingInstance = enclosingInstance; } - public virtual CountingBeforeAdvice CountingBeforeAdvice + public OrderedLogicalThreadContextCheckAdvisor EnclosingInstance { - get { return (CountingBeforeAdvice) Advice; } + get { return enclosingInstance; } } - /// Should we insist on the presence of a transaction attribute or refuse to accept one? - private bool requireLtcHasValue = false; - - - public virtual void AfterPropertiesSet() + public override void Before(MethodInfo method, object[] args, object target) { - Advice = new LTCCountingBeforeAdvice(this); - } - - public override bool Matches(MethodInfo method, Type targetClass) - { - return method.Name.StartsWith("set_Age"); - } - - - private class LTCCountingBeforeAdvice : CountingBeforeAdvice - { - private OrderedLogicalThreadContextCheckAdvisor enclosingInstance; - - public LTCCountingBeforeAdvice(OrderedLogicalThreadContextCheckAdvisor enclosingInstance) + // do check for presence of LTC value.... + if (EnclosingInstance.requireLtcHasValue) { - this.enclosingInstance = enclosingInstance; - } - - - public OrderedLogicalThreadContextCheckAdvisor EnclosingInstance - { - get { return enclosingInstance; } - } - - public override void Before(MethodInfo method, object[] args, object target) - { - // do check for presence of LTC value.... - if (EnclosingInstance.requireLtcHasValue) + if (LogicalThreadContext.GetData(LogicalThreadContextAdvice.ORDERING_SLOT) == null) { - if (LogicalThreadContext.GetData(LogicalThreadContextAdvice.ORDERING_SLOT) == null) - { - throw new SystemException("Expected object in LTC ORDERING_SLOT"); - } + throw new SystemException("Expected object in LTC ORDERING_SLOT"); } - else - { - if (LogicalThreadContext.GetData(LogicalThreadContextAdvice.ORDERING_SLOT) != null) - { - throw new SystemException("Expected no object in LTC ORDERING_SLOT"); - } - } - base.Before(method, args, target); } + else + { + if (LogicalThreadContext.GetData(LogicalThreadContextAdvice.ORDERING_SLOT) != null) + { + throw new SystemException("Expected no object in LTC ORDERING_SLOT"); + } + } + + base.Before(method, args, target); } } -} \ No newline at end of file +} diff --git a/test/Spring/Spring.Aop.Tests/Aop/Framework/AutoProxy/PointcutFilteringAutoProxyCreatorTests.cs b/test/Spring/Spring.Aop.Tests/Aop/Framework/AutoProxy/PointcutFilteringAutoProxyCreatorTests.cs index bd8c274d..45cf924d 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Framework/AutoProxy/PointcutFilteringAutoProxyCreatorTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Framework/AutoProxy/PointcutFilteringAutoProxyCreatorTests.cs @@ -26,38 +26,37 @@ using Spring.Objects; #endregion -namespace Spring.Aop.Framework.AutoProxy +namespace Spring.Aop.Framework.AutoProxy; + +/// +/// +/// +/// Erich Eichinger +[TestFixture] +public class PointcutFilteringAutoProxyCreatorTests { - /// - /// - /// - /// Erich Eichinger - [TestFixture] - public class PointcutFilteringAutoProxyCreatorTests + [Test] + public void CreatesProxyOnPointcutMatch() { - [Test] - public void CreatesProxyOnPointcutMatch() - { - PointcutFilteringAutoProxyCreator apc = new PointcutFilteringAutoProxyCreator(); - apc.Pointcut = new SdkRegularExpressionMethodPointcut(".*\\.GetHashCode"); - object result = apc.PostProcessAfterInitialization( new TestObject(), "testObject" ); - Assert.IsTrue(AopUtils.IsAopProxy(result)); - } - - [Test] - public void DoesNotCreateProxyIfNoPointcutMatch() - { - PointcutFilteringAutoProxyCreator apc = new PointcutFilteringAutoProxyCreator(); - apc.Pointcut = new SdkRegularExpressionMethodPointcut(".*\\.DOEsNOTExist"); - object result = apc.PostProcessAfterInitialization( new TestObject(), "testObject" ); - Assert.IsFalse(AopUtils.IsAopProxy(result)); - } - - [Test] - public void ThrowsArgumentExceptionIfNoCriteriaSpecified() - { - PointcutFilteringAutoProxyCreator apc = new PointcutFilteringAutoProxyCreator(); - Assert.Throws(() => apc.PostProcessAfterInitialization(new TestObject(), "testObject")); - } + PointcutFilteringAutoProxyCreator apc = new PointcutFilteringAutoProxyCreator(); + apc.Pointcut = new SdkRegularExpressionMethodPointcut(".*\\.GetHashCode"); + object result = apc.PostProcessAfterInitialization(new TestObject(), "testObject"); + Assert.IsTrue(AopUtils.IsAopProxy(result)); } -} \ No newline at end of file + + [Test] + public void DoesNotCreateProxyIfNoPointcutMatch() + { + PointcutFilteringAutoProxyCreator apc = new PointcutFilteringAutoProxyCreator(); + apc.Pointcut = new SdkRegularExpressionMethodPointcut(".*\\.DOEsNOTExist"); + object result = apc.PostProcessAfterInitialization(new TestObject(), "testObject"); + Assert.IsFalse(AopUtils.IsAopProxy(result)); + } + + [Test] + public void ThrowsArgumentExceptionIfNoCriteriaSpecified() + { + PointcutFilteringAutoProxyCreator apc = new PointcutFilteringAutoProxyCreator(); + Assert.Throws(() => apc.PostProcessAfterInitialization(new TestObject(), "testObject")); + } +} diff --git a/test/Spring/Spring.Aop.Tests/Aop/Framework/AutoProxy/TypeNameAutoProxyCreatorTests.cs b/test/Spring/Spring.Aop.Tests/Aop/Framework/AutoProxy/TypeNameAutoProxyCreatorTests.cs index dccc8b63..2bdb435c 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Framework/AutoProxy/TypeNameAutoProxyCreatorTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Framework/AutoProxy/TypeNameAutoProxyCreatorTests.cs @@ -25,71 +25,71 @@ using Spring.Objects; #endregion -namespace Spring.Aop.Framework.AutoProxy +namespace Spring.Aop.Framework.AutoProxy; + +/// +/// +/// +/// Erich Eichinger +[TestFixture] +public class TypeNameAutoProxyCreatorTests { - /// - /// - /// - /// Erich Eichinger - [TestFixture] - public class TypeNameAutoProxyCreatorTests + private class MyLocalTestObject : TestObject { - private class MyLocalTestObject: TestObject - {} - - [Test] - public void ThrowsOnMissingTypeNames() - { - TypeNameAutoProxyCreator apc = new TypeNameAutoProxyCreator(); - Assert.Throws(() => apc.PostProcessAfterInitialization(new TestObject(), "testObject")); - } - - [Test] - public void ThrowsOnAssigningNullTypeNames() - { - TypeNameAutoProxyCreator apc = new TypeNameAutoProxyCreator(); - Assert.Throws(() => apc.TypeNames = null); - } - - [Test] - public void AllowsEmptyTypeNameList() - { - TypeNameAutoProxyCreator apc = new TypeNameAutoProxyCreator(); - apc.TypeNames = new string[] {}; - - apc.PostProcessAfterInitialization( new TestObject(), "testObject" ); - } - - [Test] - public void CreatesProxyOnTypeNameMatch() - { - TypeNameAutoProxyCreator apc = new TypeNameAutoProxyCreator(); - apc.TypeNames = new string[] { "Spring.Objects.Test*", "*MyLocal*" }; - - object result = apc.PostProcessAfterInitialization( new TestObject(), "testObject" ); - Assert.IsTrue( AopUtils.IsAopProxy( result ) ); - result = apc.PostProcessAfterInitialization( new MyLocalTestObject(), "myLocalTestObject" ); - Assert.IsTrue( AopUtils.IsAopProxy( result ) ); - } - - [Test] - public void DoesNotCreateProxyIfNoTypeNameMatch() - { - TypeNameAutoProxyCreator apc = new TypeNameAutoProxyCreator(); - apc.TypeNames = new string[] { "Foo*" }; - - object result = apc.PostProcessAfterInitialization( new TestObject(), "testObject" ); - Assert.IsFalse( AopUtils.IsAopProxy( result ) ); - } - - [Test] - public void DoesNotCreateProxyIfEmptyTypeNameList() - { - TypeNameAutoProxyCreator apc = new TypeNameAutoProxyCreator(); - apc.TypeNames = new string[] {}; - - object result = apc.PostProcessAfterInitialization( new TestObject(), "testObject" ); - Assert.IsFalse( AopUtils.IsAopProxy( result ) ); - } } -} \ No newline at end of file + + [Test] + public void ThrowsOnMissingTypeNames() + { + TypeNameAutoProxyCreator apc = new TypeNameAutoProxyCreator(); + Assert.Throws(() => apc.PostProcessAfterInitialization(new TestObject(), "testObject")); + } + + [Test] + public void ThrowsOnAssigningNullTypeNames() + { + TypeNameAutoProxyCreator apc = new TypeNameAutoProxyCreator(); + Assert.Throws(() => apc.TypeNames = null); + } + + [Test] + public void AllowsEmptyTypeNameList() + { + TypeNameAutoProxyCreator apc = new TypeNameAutoProxyCreator(); + apc.TypeNames = new string[] { }; + + apc.PostProcessAfterInitialization(new TestObject(), "testObject"); + } + + [Test] + public void CreatesProxyOnTypeNameMatch() + { + TypeNameAutoProxyCreator apc = new TypeNameAutoProxyCreator(); + apc.TypeNames = new string[] { "Spring.Objects.Test*", "*MyLocal*" }; + + object result = apc.PostProcessAfterInitialization(new TestObject(), "testObject"); + Assert.IsTrue(AopUtils.IsAopProxy(result)); + result = apc.PostProcessAfterInitialization(new MyLocalTestObject(), "myLocalTestObject"); + Assert.IsTrue(AopUtils.IsAopProxy(result)); + } + + [Test] + public void DoesNotCreateProxyIfNoTypeNameMatch() + { + TypeNameAutoProxyCreator apc = new TypeNameAutoProxyCreator(); + apc.TypeNames = new string[] { "Foo*" }; + + object result = apc.PostProcessAfterInitialization(new TestObject(), "testObject"); + Assert.IsFalse(AopUtils.IsAopProxy(result)); + } + + [Test] + public void DoesNotCreateProxyIfEmptyTypeNameList() + { + TypeNameAutoProxyCreator apc = new TypeNameAutoProxyCreator(); + apc.TypeNames = new string[] { }; + + object result = apc.PostProcessAfterInitialization(new TestObject(), "testObject"); + Assert.IsFalse(AopUtils.IsAopProxy(result)); + } +} diff --git a/test/Spring/Spring.Aop.Tests/Aop/Framework/AutoProxy/advisorAutoProxyCreatorCircularReferencesTests.xml b/test/Spring/Spring.Aop.Tests/Aop/Framework/AutoProxy/advisorAutoProxyCreatorCircularReferencesTests.xml index 2c12e6dc..e793a66d 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Framework/AutoProxy/advisorAutoProxyCreatorCircularReferencesTests.xml +++ b/test/Spring/Spring.Aop.Tests/Aop/Framework/AutoProxy/advisorAutoProxyCreatorCircularReferencesTests.xml @@ -1,35 +1,35 @@  Reproduces a problem with AutoProxyCreators, IFactoryObjects, circular dependencies and a certain order of object definitions - + - - - - - + + + + + - + - + - + diff --git a/test/Spring/Spring.Aop.Tests/Aop/Framework/CountingAfterReturningAdvice.cs b/test/Spring/Spring.Aop.Tests/Aop/Framework/CountingAfterReturningAdvice.cs index 3fb35f2a..5770f774 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Framework/CountingAfterReturningAdvice.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Framework/CountingAfterReturningAdvice.cs @@ -24,19 +24,18 @@ using System.Reflection; #endregion -namespace Spring.Aop.Framework +namespace Spring.Aop.Framework; + +/// +/// Simple after returning advice example that we can use for counting checks. +/// +/// Rod Johnson +/// Bruno Baia (.NET) +[Serializable] +public class CountingAfterReturningAdvice : MethodCounter, IAfterReturningAdvice { - /// - /// Simple after returning advice example that we can use for counting checks. - /// - /// Rod Johnson - /// Bruno Baia (.NET) - [Serializable] - public class CountingAfterReturningAdvice : MethodCounter, IAfterReturningAdvice + public void AfterReturning(object returnValue, MethodInfo method, object[] args, object target) { - public void AfterReturning(object returnValue, MethodInfo method, object[] args, object target) - { - Count(method); - } + Count(method); } -} \ No newline at end of file +} diff --git a/test/Spring/Spring.Aop.Tests/Aop/Framework/CountingBeforeAdvice.cs b/test/Spring/Spring.Aop.Tests/Aop/Framework/CountingBeforeAdvice.cs index 1e8c9028..de48c2ed 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Framework/CountingBeforeAdvice.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Framework/CountingBeforeAdvice.cs @@ -24,19 +24,18 @@ using System.Reflection; #endregion -namespace Spring.Aop.Framework +namespace Spring.Aop.Framework; + +/// +/// Simple before advice example that we can use for counting checks. +/// +/// Rod Johnson +/// Choy Rim (.NET) +[Serializable] +public class CountingBeforeAdvice : MethodCounter, IMethodBeforeAdvice { - /// - /// Simple before advice example that we can use for counting checks. - /// - /// Rod Johnson - /// Choy Rim (.NET) - [Serializable] - public class CountingBeforeAdvice : MethodCounter, IMethodBeforeAdvice - { - public virtual void Before(MethodInfo method, object[] args, object target) - { - Count(method); - } - } + public virtual void Before(MethodInfo method, object[] args, object target) + { + Count(method); + } } diff --git a/test/Spring/Spring.Aop.Tests/Aop/Framework/CountingMultiAdvice.cs b/test/Spring/Spring.Aop.Tests/Aop/Framework/CountingMultiAdvice.cs index 689408b6..74074123 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Framework/CountingMultiAdvice.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Framework/CountingMultiAdvice.cs @@ -24,29 +24,28 @@ using System.Reflection; #endregion -namespace Spring.Aop.Framework +namespace Spring.Aop.Framework; + +/// +/// Advice object that implements multiple Advice interfaces. +/// +/// Juergen Hoeller +/// Bruno Baia (.NET) +public class CountingMultiAdvice : MethodCounter, + IMethodBeforeAdvice, IAfterReturningAdvice, IThrowsAdvice { - /// - /// Advice object that implements multiple Advice interfaces. - /// - /// Juergen Hoeller - /// Bruno Baia (.NET) - public class CountingMultiAdvice : MethodCounter, - IMethodBeforeAdvice, IAfterReturningAdvice, IThrowsAdvice + public void Before(MethodInfo method, object[] args, object target) { - public void Before(MethodInfo method, object[] args, object target) - { - Count(method); - } - - public void AfterReturning(object returnValue, MethodInfo method, object[] args, object target) - { - Count(method); - } - - public void AfterThrowing(ApplicationException aex) - { - Count(aex.GetType().Name); - } + Count(method); } -} \ No newline at end of file + + public void AfterReturning(object returnValue, MethodInfo method, object[] args, object target) + { + Count(method); + } + + public void AfterThrowing(ApplicationException aex) + { + Count(aex.GetType().Name); + } +} diff --git a/test/Spring/Spring.Aop.Tests/Aop/Framework/CountingThrowsAdvice.cs b/test/Spring/Spring.Aop.Tests/Aop/Framework/CountingThrowsAdvice.cs index 6641685f..7f45d6f4 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Framework/CountingThrowsAdvice.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Framework/CountingThrowsAdvice.cs @@ -22,24 +22,23 @@ #endregion -namespace Spring.Aop.Framework -{ - /// - /// Simple throw advice example that we can use for counting checks. - /// - /// Rod Johnson - /// Bruno Baia (.NET) - [Serializable] - public class CountingThrowsAdvice : MethodCounter, IThrowsAdvice - { - public void AfterThrowing(Exception ex) - { - Count(ex.GetType().Name); - } +namespace Spring.Aop.Framework; - public void AfterThrowing(ApplicationException aex) - { - Count(aex.GetType().Name); - } +/// +/// Simple throw advice example that we can use for counting checks. +/// +/// Rod Johnson +/// Bruno Baia (.NET) +[Serializable] +public class CountingThrowsAdvice : MethodCounter, IThrowsAdvice +{ + public void AfterThrowing(Exception ex) + { + Count(ex.GetType().Name); + } + + public void AfterThrowing(ApplicationException aex) + { + Count(aex.GetType().Name); } } diff --git a/test/Spring/Spring.Aop.Tests/Aop/Framework/DynamicMethodInvocationTests.cs b/test/Spring/Spring.Aop.Tests/Aop/Framework/DynamicMethodInvocationTests.cs index 3c327546..feefa37d 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Framework/DynamicMethodInvocationTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Framework/DynamicMethodInvocationTests.cs @@ -22,23 +22,21 @@ using System.Reflection; using System.Collections; - using NUnit.Framework; #endregion -namespace Spring.Aop.Framework +namespace Spring.Aop.Framework; + +/// +/// Unit tests for the DynamicMethodInvocation class. +/// +/// Bruno Baia +[TestFixture] +public class DynamicMethodInvocationTests : AbstractMethodInvocationTests { - /// - /// Unit tests for the DynamicMethodInvocation class. - /// - /// Bruno Baia - [TestFixture] - public class DynamicMethodInvocationTests : AbstractMethodInvocationTests - { - protected override AbstractMethodInvocation CreateMethodInvocation(object proxy, object target, MethodInfo method, MethodInfo onProxyMethod, object[] arguments, Type targetType, IList interceptors) - { - return new DynamicMethodInvocation(proxy, target, method, onProxyMethod, arguments, targetType, interceptors); - } - } -} \ No newline at end of file + protected override AbstractMethodInvocation CreateMethodInvocation(object proxy, object target, MethodInfo method, MethodInfo onProxyMethod, object[] arguments, Type targetType, IList interceptors) + { + return new DynamicMethodInvocation(proxy, target, method, onProxyMethod, arguments, targetType, interceptors); + } +} diff --git a/test/Spring/Spring.Aop.Tests/Aop/Framework/DynamicProxy/AbstractAopProxyTests.cs b/test/Spring/Spring.Aop.Tests/Aop/Framework/DynamicProxy/AbstractAopProxyTests.cs index 1cbfbfaa..54374fd7 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Framework/DynamicProxy/AbstractAopProxyTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Framework/DynamicProxy/AbstractAopProxyTests.cs @@ -18,12 +18,9 @@ using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters; using System.Runtime.Serialization.Formatters.Binary; using System.Reflection; - using AopAlliance.Aop; using AopAlliance.Intercept; - using FakeItEasy; - using Spring.Aop.Interceptor; using Spring.Aop.Support; using Spring.Expressions; @@ -31,2695 +28,2708 @@ using Spring.Objects; using Spring.Proxy; using Spring.Threading; using Spring.Util; - using NUnit.Framework; #pragma warning disable SYSLIB0050 -namespace Spring.Aop.Framework.DynamicProxy +namespace Spring.Aop.Framework.DynamicProxy; + +/// +/// Useful base class for Aop proxy test cases. +/// +/// Rod Johnson +/// Juergen Hoeller +/// Bruno Baia (.NET) +public abstract class AbstractAopProxyTests { - /// - /// Useful base class for Aop proxy test cases. - /// - /// Rod Johnson - /// Juergen Hoeller - /// Bruno Baia (.NET) - public abstract class AbstractAopProxyTests + protected MockTargetSource mockTargetSource = new MockTargetSource(); + + /* + * Make a clean target source available if code wants to use it. + * The target must be set. Verification will be automatic in tearDown + * to ensure that it was used appropriately by code. + */ + + [OneTimeSetUp] + public void FixtureSetUp() { - protected MockTargetSource mockTargetSource = new MockTargetSource(); + // SystemUtils.RegisterLoadedAssemblyResolver(); + } - /* - * Make a clean target source available if code wants to use it. - * The target must be set. Verification will be automatic in tearDown - * to ensure that it was used appropriately by code. - */ + [SetUp] + protected void SetUp() + { + mockTargetSource.Reset(); + } - [OneTimeSetUp] - public void FixtureSetUp() + [TearDown] + protected void TearDown() + { + mockTargetSource.Verify(); + } + + protected abstract object CreateProxy(AdvisedSupport advisedSupport); + + protected abstract Type CreateAopProxyType(AdvisedSupport advisedSupport); + + protected virtual IAopProxy CreateAopProxy(AdvisedSupport advisedSupport) + { + Type proxyType = CreateAopProxyType(advisedSupport); + ConstructorInfo proxyCtorInfo = proxyType.GetConstructor(new Type[] { typeof(IAdvised) }); + + ExpressionEvaluator.GetValue(advisedSupport, "Activate()"); + return (IAopProxy) proxyCtorInfo.Invoke(new object[] { advisedSupport }); + } + + private object SerializeAndDeserialize(object s) + { + // Serialize the session + using (Stream stream = new MemoryStream()) { - // SystemUtils.RegisterLoadedAssemblyResolver(); + BinaryFormatter formatter = new BinaryFormatter(); + formatter.AssemblyFormat = FormatterAssemblyStyle.Full; + formatter.TypeFormat = FormatterTypeStyle.TypesAlways; + formatter.Serialize(stream, s); + + // Deserialize the session + stream.Position = 0; + object res = formatter.Deserialize(stream); + return res; + } + } + + public interface ISerializableTestObject + { + string TestData { get; set; } + } + + [Serializable] + public class SerializableTestObject : ISerializableTestObject, IDeserializationCallback + { + public static int InstanceCount; + + public SerializableTestObject() + { + InstanceCount++; } - [SetUp] - protected void SetUp() + public string TestData { get { return testData; } set { testData = value; } } + + private string testData; + + public void OnDeserialization(object sender) { - mockTargetSource.Reset(); - } - - [TearDown] - protected void TearDown() - { - mockTargetSource.Verify(); - } - - protected abstract object CreateProxy(AdvisedSupport advisedSupport); - - protected abstract Type CreateAopProxyType(AdvisedSupport advisedSupport); - - protected virtual IAopProxy CreateAopProxy(AdvisedSupport advisedSupport) - { - Type proxyType = CreateAopProxyType(advisedSupport); - ConstructorInfo proxyCtorInfo = proxyType.GetConstructor(new Type[] { typeof(IAdvised) }); - - ExpressionEvaluator.GetValue(advisedSupport, "Activate()"); - return (IAopProxy)proxyCtorInfo.Invoke(new object[] { advisedSupport }); - } - - private object SerializeAndDeserialize(object s) - { - // Serialize the session - using (Stream stream = new MemoryStream()) - { - BinaryFormatter formatter = new BinaryFormatter(); - formatter.AssemblyFormat = FormatterAssemblyStyle.Full; - formatter.TypeFormat = FormatterTypeStyle.TypesAlways; - formatter.Serialize(stream, s); - - // Deserialize the session - stream.Position = 0; - object res = formatter.Deserialize(stream); - return res; - } - } - - public interface ISerializableTestObject - { - string TestData { get; set; } - } - - [Serializable] - public class SerializableTestObject : ISerializableTestObject, IDeserializationCallback - { - public static int InstanceCount; - - public SerializableTestObject() + // only count non-proxy type deserializations + if (!AopUtils.IsAopProxy(this)) { InstanceCount++; } - - public string TestData { get { return testData; } set { testData = value; } } - - private string testData; - - public void OnDeserialization(object sender) - { - // only count non-proxy type deserializations - if (!AopUtils.IsAopProxy(this)) - { - InstanceCount++; - } - } - } - - [Serializable] - public class CustomSerializableTestObject : ISerializableTestObject, ISerializable, IDeserializationCallback - { - public static int InstanceCount; - - public CustomSerializableTestObject() - { - InstanceCount++; - } - - protected CustomSerializableTestObject(SerializationInfo info, StreamingContext context) - { - TestData = info.GetString("testData"); - } - - public void GetObjectData(SerializationInfo info, StreamingContext context) - { - info.AddValue("testData", TestData); - } - - public string TestData { get { return testData; } set { testData = value; } } - - public void OnDeserialization(object sender) - { - if (!AopUtils.IsAopProxy(this)) - { - InstanceCount++; - } - } - - [NonSerialized] - private string testData; - } - - [Test] - public void CanSerializeDeserializeSerializable() - { - int instanceCount; - ISerializableTestObject target = new SerializableTestObject(); - target.TestData = "testData"; - AdvisedSupport advised = new AdvisedSupport(); - advised.Target = target; - advised.Interfaces = new Type[] { typeof(ISerializableTestObject) }; - // advised.AddAdvisor(new DefaultPointcutAdvisor(new NopInterceptor())); - - ISerializableTestObject to = (ISerializableTestObject)CreateAopProxy(advised); - - instanceCount = SerializableTestObject.InstanceCount; - to = (ISerializableTestObject)SerializeAndDeserialize(to); - - // new instance was created - Assert.AreEqual(instanceCount + 1, SerializableTestObject.InstanceCount); - // values were (de-)serialized - Assert.AreEqual(target.TestData, to.TestData); - } - - [Test] - public void CanSerializeDeserializeISerializable() - { - int instanceCount; - ISerializableTestObject target = new CustomSerializableTestObject(); - target.TestData = "testData"; - AdvisedSupport advised = new AdvisedSupport(); - advised.Target = target; - advised.Interfaces = new Type[] { typeof(ISerializableTestObject) }; - // advised.AddAdvisor(new DefaultPointcutAdvisor(new NopInterceptor())); - - ISerializableTestObject to = (ISerializableTestObject)CreateAopProxy(advised); - - instanceCount = CustomSerializableTestObject.InstanceCount; - to = (ISerializableTestObject)SerializeAndDeserialize(to); - - // new instance was created - Assert.AreEqual(instanceCount + 1, CustomSerializableTestObject.InstanceCount); - // values were (de-)serialized - Assert.AreEqual(target.TestData, to.TestData); - } - - [Test(Description = "Simple test that if we set values we can get them out again.")] - public void ValuesStick() - { - int age1 = 33; - int age2 = 37; - string name = "tony"; - - TestObject target = new TestObject(); - target.Age = age1; - ProxyFactory pf1 = new ProxyFactory(target); - pf1.AddAdvisor(new DefaultPointcutAdvisor(new NopInterceptor())); - pf1.AddAdvisor(new DefaultPointcutAdvisor(new TimestampIntroductionInterceptor())); - ITestObject to = target; - - Assert.AreEqual(age1, to.Age); - to.Age = age2; - Assert.AreEqual(age2, to.Age); - Assert.IsNull(to.Name); - to.Name = name; - Assert.AreEqual(name, to.Name); - } - - public interface ITestPerson - { - long Id { get; set; } - string Name { get; set; } - } - - public interface ITestCustomer : ITestPerson - { - string Company { get; set; } - } - - public class TestCustomer : ITestCustomer - { - private long _id; - private string _name; - private string _company; - - public long Id - { - get { return _id; } - set { _id = value; } - } - - public string Name - { - get { return _name; } - set { _name = value; } - } - - public string Company - { - get { return _company; } - set { _company = value; } - } - } - - [Test(Description = "http://jira.springframework.org/browse/SPRNET-1174")] - public void ImplementsInterfaceHierarchy() - { - IMethodInterceptor mi = A.Fake(); - - A.CallTo(() => mi.Invoke(A.That.Matches(x => x.Method.Name == "get_Id"))).Returns((long) 5).Once(); - A.CallTo(() => mi.Invoke(A.That.Matches(x => x.Method.Name == "get_Name"))).Returns("Customer Name").Once(); - A.CallTo(() => mi.Invoke(A.That.Matches(x => x.Method.Name == "get_Company"))).Returns("Customer Company").Once(); - - AdvisedSupport advised = new AdvisedSupport(); - advised.AddAdvice(mi); - advised.Interfaces = new[] { typeof(ITestCustomer) }; - - ITestCustomer to = CreateProxy(advised) as ITestCustomer; - Assert.IsNotNull(to); - Assert.AreEqual((long) 5, to.Id, "Incorrect Id"); - Assert.AreEqual("Customer Name", to.Name, "Incorrect Name"); - Assert.AreEqual("Customer Company", to.Company, "Incorrect Company"); - } - - //[Test] - to be called from derived fixtures - public virtual void Equality() - { - TestCustomer customer = new TestCustomer(); - - AdvisedSupport advised = new AdvisedSupport(); - advised.Target = customer; - advised.Interfaces = new Type[] { typeof(ITestCustomer) }; - - ITestCustomer to = CreateProxy(advised) as ITestCustomer; - Assert.IsNotNull(to); - Assert.IsTrue( to.Equals(to), "identity must be equal" ); - Assert.AreEqual(to, to); - Assert.AreEqual(to, ((IAdvised)to).TargetSource.GetTarget()); - } - - [Test] - public void Does_proxy_interfacemethods_without_implementation_and_by_default_throws_NotSupportedException() - { - AdvisedSupport advised = new AdvisedSupport(); - advised.TargetSource = new DynamicTargetSource(typeof(object), null); - advised.Interfaces = new Type[] { typeof(ITestObject) }; - - ITestObject proxy = CreateProxy(advised) as ITestObject; - Assert.IsNotNull(proxy); - - Assert.Throws(() => proxy.GetDescription(), "Target 'target' is null."); - } - - [Test] - public void Does_proxy_interfacemethods_without_implementation_and_delegates_to_interceptors() - { - DynamicInvocationTestInterceptor invocationInterceptor = new DynamicInvocationTestInterceptor(); - DynamicTargetSource targetSource = new DynamicTargetSource(typeof(object), null); - - AdvisedSupport advised = new AdvisedSupport(); - advised.TargetSource = targetSource; - advised.Interfaces = new Type[] { typeof(ITestObject) }; - advised.AddAdvice(invocationInterceptor); - ITestObject proxy = CreateProxy(advised) as ITestObject; - Assert.IsNotNull(proxy); - - // target null, call handled by interceptor - targetSource.Target = null; - invocationInterceptor.CallProceed = false; - proxy.GetDescription(); - Assert.AreEqual("GetDescription", invocationInterceptor.LastMethodInvocation.Method.Name); - } - - [Test] - public void Does_proxy_interfacemethods_without_implementation_and_throws_ArgumentNullException_On_NullTarget() - { - DynamicInvocationTestInterceptor invocationInterceptor = new DynamicInvocationTestInterceptor(); - DynamicTargetSource targetSource = new DynamicTargetSource(typeof(object), null); - - AdvisedSupport advised = new AdvisedSupport(); - advised.TargetSource = targetSource; - advised.Interfaces = new Type[] { typeof(ITestObject) }; - advised.AddAdvice(invocationInterceptor); - ITestObject proxy = CreateProxy(advised) as ITestObject; - Assert.IsNotNull(proxy); - - // target null, call not handled by interceptor - targetSource.Target = null; - invocationInterceptor.CallProceed = true; - var ex = Assert.Throws(() => proxy.GetDescription()); - Assert.That(ex.Message, Does.Contain("'target'")); - } - - [Test] - public void Does_proxy_interfacemethods_without_implementation_and_throws_NotSupportedException_On_Incompatible_Target() - { - DynamicInvocationTestInterceptor invocationInterceptor = new DynamicInvocationTestInterceptor(); - DynamicTargetSource targetSource = new DynamicTargetSource(typeof(object), null); - - AdvisedSupport advised = new AdvisedSupport(); - advised.TargetSource = targetSource; - advised.Interfaces = new Type[] { typeof(ITestObject) }; - advised.AddAdvice(invocationInterceptor); - ITestObject proxy = CreateProxy(advised) as ITestObject; - Assert.IsNotNull(proxy); - - // target incompatible, call not handled by interceptor - targetSource.Target = new object(); - invocationInterceptor.CallProceed = true; - Assert.Throws(() => proxy.GetDescription(), "Target 'target' of type 'System.Object' does not support methods of 'Spring.Objects.ITestObject'."); - } - - [Test] - public void NoInterceptorWithNoTarget() - { - AdvisedSupport advised = new AdvisedSupport(); - advised.Interfaces = new Type[] { typeof(ITestObject) }; - - ITestObject to = CreateProxy(advised) as ITestObject; - Assert.Throws(() => to.GetDescription(), "Target 'target' of type 'System.Object' does not support methods of 'Spring.Objects.ITestObject'."); - } - - [Test] - public void InterceptorHandledCallWithNoTarget() - { - int age = 26; - IMethodInterceptor mock = A.Fake(); - A.CallTo(() => mock.Invoke(A.That.Not.IsNull())).Returns(age); - - AdvisedSupport advised = new AdvisedSupport(); - advised.AddAdvice(mock); - advised.Interfaces = new Type[] { typeof(ITestObject) }; - - ITestObject to = CreateProxy(advised) as ITestObject; - Assert.IsNotNull(to); - Assert.IsTrue(to.Age == age, "Incorrect age"); - } - - [Test] - public void InterceptorUnhandledCallWithNoTarget() - { - AdvisedSupport advised = new AdvisedSupport(); - advised.AddAdvice(new NopInterceptor()); - advised.Interfaces = new Type[] { typeof(ITestObject) }; - - ITestObject to = CreateProxy(advised) as ITestObject; - Assert.IsNotNull(to); - Assert.Throws(() => to.GetDescription(), "Target 'target' of type 'System.Object' does not support methods of 'Spring.Objects.ITestObject'."); - } - - [Test] - public void ProxyAProxy() - { - ITestObject target = new TestObject(); - target.Age = 26; - - AdvisedSupport advised = new AdvisedSupport(target); - advised.AddAdvice(new NopInterceptor()); - IAopProxy aop = CreateAopProxy(advised); - ITestObject proxy1 = (ITestObject)aop.GetProxy(); - Assert.AreEqual(target.Age, proxy1.Age, "Incorrect age"); - - advised = new AdvisedSupport(proxy1); - advised.AddAdvice(new NopInterceptor()); - aop = CreateAopProxy(advised); - ITestObject proxy2 = (ITestObject)aop.GetProxy(); - Assert.AreEqual(target.Age, proxy2.Age, "Incorrect age"); - } - - // SPRNET-655 - [Test] - public void ProxyAProxyWhereClassExplicitlyImplementsInterfacesWithSameMethodNamesAndSignatures() - { - TheCommand target = new TheCommand(); - - // proxy - AdvisedSupport advised = new AdvisedSupport(target); - advised.AddAdvice(new NopInterceptor()); - object proxy = CreateProxy(advised); - - // proxy again - advised = new AdvisedSupport(proxy); - advised.AddAdvice(new NopInterceptor()); - proxy = CreateAopProxy(advised); - - IServiceCommand serviceCommand = proxy as IServiceCommand; - Assert.IsNotNull(serviceCommand); - serviceCommand.Execute(); - - IBusinessCommand businessCommand = proxy as IBusinessCommand; - Assert.IsNotNull(businessCommand); - businessCommand.Execute(); - - Assert.AreEqual(1, serviceCommand.ServiceCount); - Assert.AreEqual(1, businessCommand.BusinessCount); - } - - public interface IServiceCommand - { - int ServiceCount { get; } - - void Execute(); - } - - public interface IBusinessCommand - { - int BusinessCount { get; } - - void Execute(); - } - - public class TheCommand : IServiceCommand, IBusinessCommand - { - private int _serviceCount = 0; - int IServiceCommand.ServiceCount - { - get { return _serviceCount; } - } - - void IServiceCommand.Execute() - { - _serviceCount++; - } - - private int _businessCount = 0; - int IBusinessCommand.BusinessCount - { - get { return _businessCount; } - } - - void IBusinessCommand.Execute() - { - _businessCount++; - } - } - - [Test] - public void EqualsMethod() - { - TestObject target = new TestObject(); - - AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(ITestObject) }); - advised.Target = target; - IAopProxy aopProxy = CreateAopProxy(advised); - object proxy = aopProxy.GetProxy(); - - Assert.IsNotNull(proxy); - Assert.AreEqual(target, proxy, "Equals() returned false"); - } - - [Test] - public void GetHashCodeMethod() - { - TestObject target = new TestObject(); - - AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(ITestObject) }); - advised.Target = target; - IAopProxy aopProxy = CreateAopProxy(advised); - object proxy = aopProxy.GetProxy(); - - Assert.IsNotNull(proxy); - Assert.AreEqual(target.GetHashCode(), proxy.GetHashCode(), "GetHashCode() not equal"); - } - - [Test] - [Platform("Win")] - public void ProxyMethodWithRefOutParametersWithDirectCall() - { - PublicRefOutTestObject target = new PublicRefOutTestObject(); - - AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(IRefOutTestObject) }); - advised.Target = target; - - IAopProxy aopProxy = CreateAopProxy(advised); - IRefOutTestObject proxy = aopProxy.GetProxy() as IRefOutTestObject; - Assert.IsNotNull(proxy); - - TestsProxyMethodWithRefOutParameters(proxy); - } - - [Test] - [Platform("Win")] - public void ProxyMethodWithRefOutParametersWithDynamicReflection() - { - PublicRefOutTestObject target = new PublicRefOutTestObject(); - - AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(IRefOutTestObject) }); - advised.Target = target; - NopInterceptor ni = new NopInterceptor(); - advised.AddAdvice(ni); - - IAopProxy aopProxy = CreateAopProxy(advised); - IRefOutTestObject proxy = aopProxy.GetProxy() as IRefOutTestObject; - Assert.IsNotNull(proxy); - - TestsProxyMethodWithRefOutParameters(proxy); - - Assert.AreEqual(1, ni.Count); - } - - [Test] - [Platform("Win")] - public virtual void ProxyMethodWithRefOutParametersWithStandardReflection() - { - InternalRefOutTestObject target = new InternalRefOutTestObject(); - - AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(IRefOutTestObject) }); - advised.Target = target; - NopInterceptor ni = new NopInterceptor(); - advised.AddAdvice(ni); - - IAopProxy aopProxy = CreateAopProxy(advised); - IRefOutTestObject proxy = aopProxy.GetProxy() as IRefOutTestObject; - Assert.IsNotNull(proxy); - - TestsProxyMethodWithRefOutParameters(proxy); - - Assert.AreEqual(1, ni.Count); - } - - private void TestsProxyMethodWithRefOutParameters(IRefOutTestObject instance) - { - int valueType = 0; - TestObject obj = null; - EnumValue enumValue = EnumValue.Initial; - bool refValueType = false; - int outValueType; - String refObj = null; - TestObject outObj; - EnumValue refEnum = EnumValue.Initial; - EnumValue outEnum = EnumValue.Initial; - Guid refGuid = Guid.NewGuid(); - Guid outGuid = Guid.NewGuid(); - - instance.DoIt(valueType, obj, enumValue, ref refValueType, out outValueType, ref refObj, out outObj, ref refEnum, out outEnum, ref refGuid, out outGuid); - - Assert.AreEqual(0, valueType); - Assert.AreEqual(null, obj); - Assert.AreEqual(EnumValue.Initial, enumValue); - Assert.AreEqual(true, refValueType); - Assert.AreEqual(1, outValueType); - Assert.AreEqual("RefObj", refObj); - Assert.IsNotNull(outObj); - Assert.AreEqual("OutObj", outObj.Name); - Assert.AreEqual(EnumValue.Ref, refEnum); - Assert.AreEqual(EnumValue.Out, outEnum); - Assert.AreEqual(Guid.Empty, refGuid); - Assert.AreEqual(Guid.Empty, outGuid); - } - - public enum EnumValue - { - Initial, - Ref, - Out, - Another - } - - public interface IRefOutTestObject - { - int DoIt(int valueType, TestObject obj, EnumValue enumValue, - ref bool refValueType, out int outValueType, - ref String refObj, out TestObject outObj, - ref EnumValue refEnum, out EnumValue outEnum, - ref Guid refGuid, out Guid outGuid); - } - - public class PublicRefOutTestObject : IRefOutTestObject - { - public int DoIt(int valueType, TestObject obj, EnumValue enumValue, - ref bool refValueType, out int outValueType, - ref String refObj, out TestObject outObj, - ref EnumValue refEnum, out EnumValue outEnum, - ref Guid refGuid, out Guid outGuid) - { - valueType++; - obj = new TestObject("Bruno", 27); - enumValue = EnumValue.Another; - refValueType = true; - outValueType = 1; - refObj += "RefObj"; - outObj = new TestObject("OutObj", 27); - refEnum = EnumValue.Ref; - outEnum = EnumValue.Out; - refGuid = Guid.Empty; - outGuid = Guid.Empty; - - return 0; - } - } - - internal class InternalRefOutTestObject : PublicRefOutTestObject - { - } - - [Test] - [Platform("Win")] - public void ProxyGenericMethodWithRefOutParametersWithDirectCall() - { - PublicRefOutGenericTestObject target = new PublicRefOutGenericTestObject(); - - AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(IRefOutGenericTestObject) }); - advised.Target = target; - - IAopProxy aopProxy = CreateAopProxy(advised); - IRefOutGenericTestObject proxy = aopProxy.GetProxy() as IRefOutGenericTestObject; - Assert.IsNotNull(proxy); - - TestsProxyGenericMethodWithRefOutParameters(proxy); - } - - [Test] - [Platform("Win")] - public void ProxyGenericMethodWithRefOutParametersWithDynamicReflection() - { - PublicRefOutGenericTestObject target = new PublicRefOutGenericTestObject(); - - AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(IRefOutGenericTestObject) }); - advised.Target = target; - NopInterceptor ni = new NopInterceptor(); - advised.AddAdvice(ni); - - IAopProxy aopProxy = CreateAopProxy(advised); - IRefOutGenericTestObject proxy = aopProxy.GetProxy() as IRefOutGenericTestObject; - Assert.IsNotNull(proxy); - - TestsProxyGenericMethodWithRefOutParameters(proxy); - - Assert.AreEqual(3, ni.Count); - } - - [Test] - [Platform("Win")] - public virtual void ProxyGenericMethodWithRefOutParametersWithStandardReflection() - { - InternalRefOutGenericTestObject target = new InternalRefOutGenericTestObject(); - - AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(IRefOutGenericTestObject) }); - advised.Target = target; - NopInterceptor ni = new NopInterceptor(); - advised.AddAdvice(ni); - - IAopProxy aopProxy = CreateAopProxy(advised); - IRefOutGenericTestObject proxy = aopProxy.GetProxy() as IRefOutGenericTestObject; - Assert.IsNotNull(proxy); - - TestsProxyGenericMethodWithRefOutParameters(proxy); - - Assert.AreEqual(3, ni.Count); - } - - private void TestsProxyGenericMethodWithRefOutParameters(IRefOutGenericTestObject instance) - { - EnumValue enumValue = EnumValue.Another; - EnumValue refEnum = EnumValue.Ref; - EnumValue outEnum = EnumValue.Out; - EnumValue enumResult = instance.DoIt(enumValue, ref refEnum, out outEnum); - Assert.AreEqual(EnumValue.Another, refEnum); - Assert.AreEqual(EnumValue.Another, outEnum); - Assert.AreEqual(EnumValue.Another, enumResult); - - TestObject objectValue = new TestObject("Value", 28); - TestObject refObject = new TestObject("Ref", 28); - TestObject outObject = new TestObject("Out", 28); - TestObject objectResult = instance.DoIt(objectValue, ref refObject, out outObject); - Assert.AreEqual("Value", refObject.Name); - Assert.AreEqual("Value", outObject.Name); - Assert.AreEqual("Value", objectResult.Name); - - int intValue = 1; - int refInt = 2; - int outInt = 3; - int intResult = instance.DoIt(intValue, ref refInt, out outInt); - Assert.AreEqual(1, refInt); - Assert.AreEqual(1, outInt); - Assert.AreEqual(1, intResult); - } - - public interface IRefOutGenericTestObject - { - T DoIt(T param, ref T refParam, out T outParam); - } - - public class PublicRefOutGenericTestObject : IRefOutGenericTestObject - { - public T DoIt(T paramValue, ref T refParam, out T outParam) - { - refParam = paramValue; - outParam = paramValue; - - return paramValue; - } - } - - internal class InternalRefOutGenericTestObject : PublicRefOutGenericTestObject - { - } - - [Test] - public void ToStringMethod() - { - TestObject target = new TestObject(); - - AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(ITestObject) }); - advised.Target = target; - IAopProxy aopProxy = CreateAopProxy(advised); - object proxy = aopProxy.GetProxy(); - - Assert.IsNotNull(proxy); - Assert.AreEqual(target.ToString(), proxy.ToString(), "ToString() not equal"); - } - - [Test] - public void InterceptGenericMethod() - { - AbstractProxyTypeBuilderTests.ClassWithGenericMethod target = - new AbstractProxyTypeBuilderTests.ClassWithGenericMethod(); - mockTargetSource.SetTarget(target); - - NopInterceptor ni = new NopInterceptor(); - - AdvisedSupport advised = new AdvisedSupport(mockTargetSource); - advised.AddAdvice(ni); - - AbstractProxyTypeBuilderTests.InterfaceWithGenericMethod proxy = - CreateProxy(advised) as AbstractProxyTypeBuilderTests.InterfaceWithGenericMethod; - Assert.IsNotNull(proxy); - - proxy.PolymorphicMethod(); - proxy.PolymorphicMethod(); - - string result1 = proxy.PolymorphicMethod("coucou"); - Assert.AreEqual("coucou", result1); - - proxy.WithGenericParameter(); - - proxy.WithGenericParameterAndGenericArgument("ola"); - - string result2 = proxy.WithGenericParameterAndGenericArgumentAndGenericReturnType("ola"); - Assert.AreEqual("ola", result2); - - proxy.WithInterfaceConstraint(); - - proxy.WithBaseTypeConstraint(); - - proxy.WithBaseTypeAndInterfaceConstraints(); - - proxy.WithMixedConstraint(); - Assert.AreEqual(10, ni.Count); - - //if (this is DecoratorAopProxyTests) - //{ - // DynamicProxyManager.SaveAssembly(); - //} - } - - [Test] - public void InterceptGenericInterface() - { - AbstractProxyTypeBuilderTests.ClassThatImplementsGenericInterface target = - new AbstractProxyTypeBuilderTests.ClassThatImplementsGenericInterface(); - mockTargetSource.SetTarget(target); - - NopInterceptor ni = new NopInterceptor(); - - AdvisedSupport advised = new AdvisedSupport(mockTargetSource); - advised.AddAdvice(ni); - - AbstractProxyTypeBuilderTests.GenericInterface proxy = - CreateProxy(advised) as AbstractProxyTypeBuilderTests.GenericInterface; - Assert.IsNotNull(proxy); - - TestObject to1 = proxy.Create(); - Assert.IsNotNull(to1); - - TestObject to2 = proxy.Populate(new TestObject()); - Assert.IsNotNull(to2); - Assert.AreEqual("Populated", to2.Name); - - Assert.AreEqual(2, ni.Count); - } - - [Test(Description = "http://opensource.atlassian.com/projects/spring/browse/SPRNET-340")] - [Platform("Win")] - public void MultiThreadedProxyCreation() - { - MultiThreadedProxyCreation(5); - } - - private void MultiThreadedProxyCreation(int howMany) - { - AsyncTestMethod[] threads = new AsyncTestMethod[howMany]; - for (int i = 0; i < howMany; i++) - threads[i] = new AsyncTestMethod(10, new ThreadStart(ProxyTestObject)); - for (int i = 0; i < howMany; i++) - threads[i].Start(); - for (int i = 0; i < howMany; i++) - threads[i].AssertNoException(); - } - - private void ProxyTestObject() - { - TestObject target = new TestObject(); - target.Age = 26; - - AdvisedSupport advised = new AdvisedSupport(target); - advised.AddAdvice(new NopInterceptor()); - - ITestObject proxy = CreateProxy(advised) as ITestObject; - Assert.IsNotNull(proxy); - Assert.AreEqual(target.Age, proxy.Age, "Incorrect age"); - } - - [Test] - public void ProxyTargetTypeAttributes() - { - MarkerClass target = new MarkerClass(); - - AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(IMarkerInterface) }); - advised.Target = target; - IAopProxy aopProxy = CreateAopProxy(advised); - - object proxy = aopProxy.GetProxy(); - Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to GetProxy() was null."); - - object[] attrs = proxy.GetType().GetCustomAttributes(false); - Assert.IsNotNull(attrs, "Should have had 1 attribute applied to the target type."); - Assert.AreEqual(1, attrs.Length, "Should have had 1 attribute applied to the target type."); - Assert.AreEqual(typeof(MarkerAttribute), attrs[0].GetType(), "Wrong System.Type of Attribute applied to the target type."); - } - - [Test] - public void DoesNotProxyTargetTypeAttributesWithProxyTargetAttributesEqualsFalse() - { - MarkerClass target = new MarkerClass(); - - AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(IMarkerInterface) }); - advised.Target = target; - advised.ProxyTargetAttributes = false; - IAopProxy aopProxy = CreateAopProxy(advised); - - object proxy = aopProxy.GetProxy(); - Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to GetProxy() was null."); - - object[] attrs = proxy.GetType().GetCustomAttributes(false); - Assert.IsNotNull(attrs); - Assert.AreEqual(0, attrs.Length, "Should not have attribute applied to the target type."); - } - - [Test] - public void ProxyTargetMethodAttributes() - { - MarkerClass target = new MarkerClass(); - - AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(IMarkerInterface) }); - advised.Target = target; - IAopProxy aopProxy = CreateAopProxy(advised); - - object proxy = aopProxy.GetProxy(); - Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to GetProxy() was null."); - - MethodInfo method = proxy.GetType().GetMethod("Spring.Aop.Framework.DynamicProxy.AbstractAopProxyTests+IMarkerInterface.MarkerMethod", BindingFlags.NonPublic | BindingFlags.Instance); - if (method == null) - { - method = proxy.GetType().GetMethod("MarkerMethod"); - } - Assert.IsNotNull(method); - - object[] attrs = method.GetCustomAttributes(false); - Assert.IsNotNull(attrs, "Should have 1 attribute applied to the target method."); - Assert.AreEqual(1, attrs.Length, "Should have 1 attribute applied to the target method."); - Assert.AreEqual(typeof(MarkerAttribute), attrs[0].GetType(), "Wrong System.Type of Attribute applied to the target method."); - } - - [Test] - public void DoesNotProxyTargetMethodAttributesWithProxyTargetAttributesEqualsFalse() - { - MarkerClass target = new MarkerClass(); - - AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(IMarkerInterface) }); - advised.Target = target; - advised.ProxyTargetAttributes = false; - IAopProxy aopProxy = CreateAopProxy(advised); - - object proxy = aopProxy.GetProxy(); - Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to GetProxy() was null."); - - MethodInfo method = proxy.GetType().GetMethod("Spring.Aop.Framework.DynamicProxy.AbstractAopProxyTests+IMarkerInterface.MarkerMethod", BindingFlags.NonPublic | BindingFlags.Instance); - if (method == null) - { - method = proxy.GetType().GetMethod("MarkerMethod"); - } - Assert.IsNotNull(method); - - object[] attrs = method.GetCustomAttributes(false); - Assert.IsNotNull(attrs); - Assert.AreEqual(0, attrs.Length, "Should not have attribute applied to the target method."); - } - - [Test] - public void ProxyTargetMethodParameterAttributes() - { - MarkerClass target = new MarkerClass(); - - AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(IMarkerInterface) }); - advised.Target = target; - IAopProxy aopProxy = CreateAopProxy(advised); - - object proxy = aopProxy.GetProxy(); - Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to GetProxy() was null."); - - MethodInfo method = proxy.GetType().GetMethod("Spring.Aop.Framework.DynamicProxy.AbstractAopProxyTests+IMarkerInterface.MarkerMethod", BindingFlags.NonPublic | BindingFlags.Instance); - if (method == null) - { - method = proxy.GetType().GetMethod("MarkerMethod"); - } - Assert.IsNotNull(method); - - object[] attrs = method.GetParameters()[1].GetCustomAttributes(false); - Assert.IsNotNull(attrs, "Should have had 1 attribute applied to the method's parameter."); - Assert.AreEqual(1, attrs.Length, "Should have had 1 attribute applied to the method's parameter."); - Assert.AreEqual(typeof(MarkerAttribute), attrs[0].GetType(), "Wrong System.Type of Attribute applied to the method's parameter."); - } - - [Test] - public void DoesNotProxyTargetMethodParameterAttributesWithProxyTargetAttributesEqualsFalse() - { - MarkerClass target = new MarkerClass(); - - AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(IMarkerInterface) }); - advised.Target = target; - advised.ProxyTargetAttributes = false; - IAopProxy aopProxy = CreateAopProxy(advised); - - object proxy = aopProxy.GetProxy(); - Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to GetProxy() was null."); - - MethodInfo method = proxy.GetType().GetMethod("Spring.Aop.Framework.DynamicProxy.AbstractAopProxyTests+IMarkerInterface.MarkerMethod", BindingFlags.NonPublic | BindingFlags.Instance); - if (method == null) - { - method = proxy.GetType().GetMethod("MarkerMethod"); - } - Assert.IsNotNull(method); - - object[] attrs = method.GetParameters()[1].GetCustomAttributes(false); - Assert.IsNotNull(attrs); - Assert.AreEqual(0, attrs.Length, "Should not have attribute applied to the method's parameter."); - } - - [Test] - public void ProxyTargetMethodReturnValueAttributes() - { - MarkerClass target = new MarkerClass(); - - AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(IMarkerInterface) }); - advised.Target = target; - IAopProxy aopProxy = CreateAopProxy(advised); - - object proxy = aopProxy.GetProxy(); - Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to GetProxy() was null."); - - MethodInfo method = proxy.GetType().GetMethod("Spring.Aop.Framework.DynamicProxy.AbstractAopProxyTests+IMarkerInterface.MarkerMethod", BindingFlags.NonPublic | BindingFlags.Instance); - if (method == null) - { - method = proxy.GetType().GetMethod("MarkerMethod"); - } - Assert.IsNotNull(method); - - object[] attrs = method.ReturnTypeCustomAttributes.GetCustomAttributes(false); - Assert.IsNotNull(attrs, "Should have had 1 attribute applied to the method's return value."); - Assert.AreEqual(1, attrs.Length, "Should have had 1 attribute applied to the method's return value."); - Assert.AreEqual(typeof(MarkerAttribute), attrs[0].GetType(), "Wrong System.Type of Attribute applied to the method's return value."); - } - - [Test] - public void DoesNotProxyTargetMethodReturnValueAttributesWithProxyTargetAttributesEqualsFalse() - { - MarkerClass target = new MarkerClass(); - - AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(IMarkerInterface) }); - advised.Target = target; - advised.ProxyTargetAttributes = false; - IAopProxy aopProxy = CreateAopProxy(advised); - - object proxy = aopProxy.GetProxy(); - Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to GetProxy() was null."); - - MethodInfo method = proxy.GetType().GetMethod("Spring.Aop.Framework.DynamicProxy.AbstractAopProxyTests+IMarkerInterface.MarkerMethod", BindingFlags.NonPublic | BindingFlags.Instance); - if (method == null) - { - method = proxy.GetType().GetMethod("MarkerMethod"); - } - Assert.IsNotNull(method); - - object[] attrs = method.ReturnTypeCustomAttributes.GetCustomAttributes(false); - Assert.IsNotNull(attrs); - Assert.AreEqual(0, attrs.Length, "Should not have attribute applied to the method's return value."); - } - - public sealed class MarkerAttribute : Attribute - { - } - - public interface IMarkerInterface - { - void MarkerMethod(int param1, string param2); - } - - [Marker] - public class MarkerClass : IMarkerInterface - { - [Marker] - [return: Marker] - public void MarkerMethod(int param1, [Marker]string param2) - { - } - - [Marker] - [return: Marker] - public virtual void MarkerVirtualMethod(int param1, [Marker]string param2) - { - } - } - - [Test] - public void AddAdviceAtRuntime() - { - TestObject target = new TestObject(); - CountingBeforeAdvice cba = new CountingBeforeAdvice(); - - ProxyFactory pf = new ProxyFactory(target); - ITestObject proxy = (ITestObject)CreateProxy(pf); - - proxy.Age.ToString(); - Assert.AreEqual(0, cba.GetCalls()); - ((IAdvised)proxy).AddAdvice(cba); - proxy.Age.ToString(); - Assert.AreEqual(1, cba.GetCalls()); - } - - [Test] - public void SerializationAdviceAndTargetNotSerializable() - { - TestObject to = new TestObject(); - Assert.IsFalse(SerializationTestUtils.IsSerializable(to)); - - ProxyFactory pf = new ProxyFactory(to); - - pf.AddAdvice(new NopInterceptor()); - ITestObject proxy = (ITestObject)CreateAopProxy(pf).GetProxy(); - - Assert.IsFalse(SerializationTestUtils.IsSerializable(proxy)); - } - - [Test] - public void SerializationAdviceNotSerializable() - { - SerializablePerson sp = new SerializablePerson(); - Assert.IsTrue(SerializationTestUtils.IsSerializable(sp)); - - ProxyFactory pf = new ProxyFactory(sp); - - // This isn't serializable - IAdvice i = new NopInterceptor(); - pf.AddAdvice(i); - Assert.IsFalse(SerializationTestUtils.IsSerializable(i)); - Object proxy = CreateAopProxy(pf).GetProxy(); - - Assert.IsFalse(SerializationTestUtils.IsSerializable(proxy)); - } - - [Test] - public void SerializationSerializableTargetAndAdvice() - { - SerializablePerson personTarget = new SerializablePerson(); - personTarget.Name = "jim"; - personTarget.Age = 26; - - Assert.IsTrue(SerializationTestUtils.IsSerializable(personTarget)); - - ProxyFactory pf = new ProxyFactory(personTarget); - - CountingThrowsAdvice cta = new CountingThrowsAdvice(); - - pf.AddAdvice(new SerializableNopInterceptor()); - // Try various advice types - pf.AddAdvice(new CountingBeforeAdvice()); - pf.AddAdvice(new CountingAfterReturningAdvice()); - pf.AddAdvice(cta); - IPerson p = (IPerson)CreateAopProxy(pf).GetProxy(); - - p.Echo(null); - Assert.AreEqual(0, cta.GetCalls()); - try - { - p.Echo(new Exception()); - } - catch (Exception) - { - } - Assert.AreEqual(1, cta.GetCalls()); - - // Will throw exception if it fails - IPerson p2 = (IPerson)SerializationTestUtils.SerializeAndDeserialize(p); - Assert.AreNotSame(p, p2); - Assert.AreEqual(p.GetName(), p2.GetName()); - Assert.AreEqual(p.GetAge(), p2.GetAge()); - Assert.IsTrue(AopUtils.IsAopProxy(p2), "Deserialized object is an AOP proxy"); - - IAdvised a1 = (IAdvised)p; - IAdvised a2 = (IAdvised)p2; - // Check we can manipulate state of p2 - Assert.AreEqual(a1.Advisors.Count, a2.Advisors.Count); - - // This should work as SerializablePerson is equal - Assert.AreEqual(p, p2, "Proxies should be equal, even after one was serialized"); - - // Check we can add a new advisor to the target - NopInterceptor ni = new NopInterceptor(); - p2.GetAge(); - Assert.AreEqual(0, ni.Count); - a2.AddAdvice(ni); - p2.GetAge(); - Assert.AreEqual(1, ni.Count); - - cta = (CountingThrowsAdvice)a2.Advisors[3].Advice; - p2.Echo(null); - Assert.AreEqual(1, cta.GetCalls()); - try - { - p2.Echo(new Exception()); - } - catch (Exception) - { - - } - Assert.AreEqual(2, cta.GetCalls()); - } - - /// - /// Check that the two MethodInvocations necessary are independent - /// and don't conflict. - /// - [Test] - public void OneAdvisedObjectCallsAnother() - { - int age1 = 33; - int age2 = 37; - - TestObject target1 = new TestObject(); - ProxyFactory pf1 = new ProxyFactory(target1); - // Permit proxy and invocation checkers to get context from AopContext - pf1.ExposeProxy = true; - NopInterceptor di1 = new NopInterceptor(); - pf1.AddAdvice(0, di1); - pf1.AddAdvice(1, new ProxyMatcherInterceptor()); - pf1.AddAdvice(2, new MethodInvocationMatcherInterceptor()); - ITestObject advised1 = (ITestObject)pf1.GetProxy(); - advised1.Age = age1; // = 1 invocation - - TestObject target2 = new TestObject(); - ProxyFactory pf2 = new ProxyFactory(target2); - pf2.ExposeProxy = true; - NopInterceptor di2 = new NopInterceptor(); - pf2.AddAdvice(0, di2); - pf2.AddAdvice(1, new ProxyMatcherInterceptor()); - pf2.AddAdvice(2, new MethodInvocationMatcherInterceptor()); - ITestObject advised2 = (ITestObject)CreateProxy(pf2); - advised2.Age = age2; - advised1.Spouse = advised2; // = 2 invocations - - Assert.AreEqual(age1, advised1.Age, "Advised one has correct age"); // = 3 invocations - Assert.AreEqual(age2, advised2.Age, "Advised two has correct age"); - // Means extra call on advised 2 - Assert.AreEqual(age2, advised1.Spouse.Age, "Advised one spouse has correct age"); // = 4 invocations on 1 and another one on 2 - Assert.AreEqual(4, di1.Count, "one was invoked correct number of times"); - // Got hit by call to advised1.getSpouse().Age - Assert.AreEqual(3, di2.Count, "one was invoked correct number of times"); - } - - private class MethodInvocationMatcherInterceptor : IMethodInterceptor - { - public object Invoke(IMethodInvocation invocation) - { - MethodInfo m = invocation.Method; - Object retval = invocation.Proceed(); - Assert.AreEqual(m, invocation.Method, "Method invocation should have same method on way back"); - return retval; - } - } - - private class ProxyMatcherInterceptor : IMethodInterceptor - { - public object Invoke(IMethodInvocation invocation) - { - Object proxy = AopContext.CurrentProxy; - Object ret = invocation.Proceed(); - Assert.IsTrue(proxy == AopContext.CurrentProxy, "Proxy should be the same on way back"); - return ret; - } - } - - [Test] - public void Reentrance() - { - int age1 = 33; - - TestObject target1 = new TestObject(); - ProxyFactory pf1 = new ProxyFactory(target1); - NopInterceptor di1 = new NopInterceptor(); - pf1.AddAdvice(0, di1); - ITestObject advised1 = (ITestObject)CreateProxy(pf1); - - advised1.Age = age1; // = 1 invocation - advised1.Spouse = advised1; // = 2 invocations - - Assert.AreEqual(2, di1.Count, "one was invoked correct number of times"); - - Assert.AreEqual(age1, advised1.Age, "Advised one has correct age"); // = 3 invocations - Assert.AreEqual(3, di1.Count, "one was invoked correct number of times"); - - // = 5 invocations, as reentrant call to spouse is advised also - Assert.AreEqual(age1, advised1.Spouse.Age, "Advised spouse has correct age"); - - Assert.AreEqual(5, di1.Count, "one was invoked correct number of times"); - } - - [Test] - public void TargetCanGetProxy() - { - NopInterceptor di = new NopInterceptor(); - INeedsToSeeProxy target = new TargetChecker(); - ProxyFactory proxyFactory = new ProxyFactory(target); - proxyFactory.ExposeProxy = true; - Assert.IsTrue(proxyFactory.ExposeProxy); - - proxyFactory.AddAdvice(0, di); - INeedsToSeeProxy proxied = (INeedsToSeeProxy)CreateProxy(proxyFactory); - - Assert.AreEqual(0, di.Count); - Assert.AreEqual(0, target.Count); - proxied.IncrementViaThis(); - Assert.AreEqual(1, target.Count, "Increment happened"); - - Assert.AreEqual(1, di.Count, "Only one invocation via AOP as use of this wasn't proxied"); - // 1 invocation - Assert.AreEqual(1, proxied.Count, "Increment happened"); - proxied.IncrementViaProxy(); // 2 invoocations - Assert.AreEqual(2, target.Count, "Increment happened"); - Assert.AreEqual(4, di.Count, "3 more invocations via AOP as the first call was reentrant through the proxy"); - } - - /// - /// Check that although a method is eligible for advice chain optimization and - /// direct reflective invocation, it doesn't happen if we've asked to see the proxy, - /// so as to guarantee a consistent programming model. - /// - [Test] - public void TargetCanGetProxyEvenIfNoAdviceChain() - { - NeedsToSeeProxy target = new NeedsToSeeProxy(); - AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(INeedsToSeeProxy) }); - advised.Target = target; - advised.ExposeProxy = true; - - // Now let's try it with the special target - IAopProxy aop = CreateAopProxy(advised); - INeedsToSeeProxy proxied = (INeedsToSeeProxy)aop.GetProxy(); - - // It will complain if it can't get the proxy - proxied.IncrementViaProxy(); - } - - [Test] - public void TargetCantGetProxyByDefault() - { - NeedsToSeeProxy et = new NeedsToSeeProxy(); - ProxyFactory pf1 = new ProxyFactory(et); - Assert.IsFalse(pf1.ExposeProxy); - INeedsToSeeProxy proxied = (INeedsToSeeProxy)CreateProxy(pf1); - Assert.Throws(() => proxied.IncrementViaProxy()); - } - - [Test(Description = "Test that the proxy returns itself when the target returns 'this'.")] - public void TargetReturnsThis() - { - // Test return value - TestObject raw = new OwnSpouse(); - - AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(ITestObject) }); - advised.Target = raw; - - ITestObject to = (ITestObject)CreateProxy(advised); - Assert.IsTrue(to.Spouse == to, "this return is wrapped in proxy"); - } - - public class OwnSpouse : TestObject - { - public override ITestObject Spouse - { - get { return this; } - } - } - - [Test] - public void TargetThrowsException() - { - Exception expectedException = new ApplicationException(); - - // Test return value - AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(ITestObject) }); - advised.Target = new TestObject(); - IAopProxy aop = CreateAopProxy(advised); - - try - { - ITestObject to = (ITestObject)aop.GetProxy(); - to.Exceptional(expectedException); - Assert.Fail("Should have thrown exception raised by target"); - } - catch (Exception ex) - { - Assert.AreEqual(expectedException, ex, "exception matches"); - } - } - - [Test] - public void InterceptorThrowsException() - { - Exception expectedException = new ApplicationException(); - - IMethodInterceptor mi = new ThrowExceptionInterceptor(expectedException); - - AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(ITestObject) }); - advised.Target = new TestObject(); - advised.AddAdvice(mi); - IAopProxy aop = CreateAopProxy(advised); - - try - { - ITestObject to = (ITestObject)aop.GetProxy(); - to.Name = "Bruno"; - Assert.Fail("Should have thrown exception raised by interceptor"); - } - catch (Exception ex) - { - Assert.AreEqual(expectedException, ex, "exception matches"); - } - } - - private class ThrowExceptionInterceptor : IMethodInterceptor - { - private Exception _exception; - - public ThrowExceptionInterceptor(Exception ex) - { - _exception = ex; - } - - public object Invoke(IMethodInvocation invocation) - { - throw _exception; - } - } - - // TODO : Introduction tests - /* - [Test(Description = "Test stateful interceptor")] - public void MixinWithIntroductionAdvisor() - { - TestObject to = new TestObject(); - AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(ITestObject) }); - advised.AddAdvisor(new LockMixinAdvisor()); - advised.Target = to; - - CheckTestObjectIntroduction(advised); - } - - [Test] - public void MixinWithIntroductionInfo() - { - TestObject to = new TestObject(); - AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(ITestObject) }); - advised.AddAdvice(new LockMixin()); - advised.Target = to; - - CheckTestObjectIntroduction(advised); - } - - private void CheckTestObjectIntroduction(AdvisedSupport advised) - { - int newAge = 65; - - ITestObject ito = (ITestObject) CreateProxy(advised); - ito.Age = newAge; - Assert.IsTrue(ito.Age == newAge); - - ILockable lockable = (ILockable) ito; - Assert.IsFalse(lockable.Locked()); - lockable.DoLock(); - - Assert.IsTrue(ito.Age == newAge); - try - { - ito.Age = 1; - Assert.Fail("Setters should fail when locked"); - } - catch (LockedException) - { - // ok - } - Assert.IsTrue(ito.Age == newAge); - - // Unlock - Assert.IsTrue(lockable.Locked()); - lockable.Unlock(); - ito.Age = 1; - Assert.IsTrue(ito.Age == 1); - } - */ - - [Test] - public void MultipleProceedCalls() - { - TestObject to = new TestObject(); - AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(ITestObject) }); - advised.Target = to; - advised.AddAdvice(new RetryAdvice()); - NopInterceptor ni = new NopInterceptor(); - advised.AddAdvice(ni); - - ITestObject ito = (ITestObject)CreateProxy(advised); - ito.Age = 27; - - Assert.AreEqual(2, ni.Count); - } - - public class RetryAdvice : IMethodInterceptor - { - public object Invoke(IMethodInvocation invocation) - { - invocation.Proceed(); - return invocation.Proceed(); - } - } - - [Test] - public void ReplaceArgument() - { - TestObject to = new TestObject(); - AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(ITestObject) }); - advised.Target = to; - advised.AddAdvisor(new StringSetterNullReplacementAdvisor(new StringSetterNullReplacementAdvice())); - - ITestObject ito = (ITestObject)CreateProxy(advised); - int newAge = 5; - ito.Age = newAge; - Assert.IsTrue(ito.Age == newAge); - String newName = "greg"; - ito.Name = newName; - Assert.AreEqual(newName, ito.Name); - - ito.Name = null; - - // Null replacement magic should work - Assert.IsTrue(ito.Name.Equals("")); - } - - [Test] - public void ReplaceArgumentDescendingPropagation() - { - TestObject to = new TestObject(); - AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(ITestObject) }); - advised.Target = to; - advised.AddAdvisor(new StringSetterNullReplacementAdvisor(new StringSetterNullReplacementAdvice())); - NopInterceptor ni = new NopInterceptor(); - advised.AddAdvisor(new StringSetterNullReplacementAdvisor(ni)); - - ITestObject ito = (ITestObject)CreateProxy(advised); - int newAge = 5; - ito.Age = newAge; - Assert.IsTrue(ito.Age == newAge); - String newName = "greg"; - ito.Name = newName; - Assert.AreEqual(newName, ito.Name); - - ito.Name = null; - - // Null replacement magic should work - Assert.IsTrue(ito.Name.Equals("")); - - // StringSetterNullReplacementAdvisor should not be fire twice - Assert.AreEqual(0, ni.Count); - } - - [Test] - public void ReplaceArgumentAscendingPropagation() - { - TestObject to = new TestObject(); - AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(ITestObject) }); - advised.Target = to; - advised.AddAdvice(new CheckArgumentsAfterProceedAdvice()); - advised.AddAdvisor(new StringSetterNullReplacementAdvisor(new StringSetterNullReplacementAdvice())); - - ITestObject ito = (ITestObject)CreateProxy(advised); - ito.Name = null; - } - - /// - /// Fires on setter methods that take a string. - /// - public class StringSetterNullReplacementAdvisor : DynamicMethodMatcherPointcutAdvisor - { - public StringSetterNullReplacementAdvisor(IAdvice advice) - : base(advice) - { - } - - public override bool Matches(MethodInfo method, Type targetType, object[] args) - { - return (args[0] == null); - } - - public override bool Matches(MethodInfo method, Type targetType) - { - return method.Name.StartsWith("set_") && - method.GetParameters().Length == 1 && - method.GetParameters()[0].ParameterType == typeof(string); - } - } - - /// - /// Replaces null arg with "". - /// - public class StringSetterNullReplacementAdvice : IMethodInterceptor - { - public object Invoke(IMethodInvocation invocation) - { - // We know it can only be invoked if there's a single parameter of type string - invocation.Arguments[0] = ""; - return invocation.Proceed(); - } - } - - public class CheckArgumentsAfterProceedAdvice : IMethodInterceptor - { - public object Invoke(IMethodInvocation invocation) - { - object returnValue = invocation.Proceed(); - - // Null replacement magic should work - Assert.IsNotNull(invocation.Arguments[0]); - - return returnValue; - } - } - - /// - /// http://forum.springframework.net/showthread.php?t=504 - /// - [Test] - public void CanCastProxyToIAdvised() - { - TestObject to = new TestObject(); - AdvisedSupport advisedSupport = new AdvisedSupport(to); - NopInterceptor ni = new NopInterceptor(); - advisedSupport.AddAdvice(0, ni); - - ITestObject ito = (ITestObject)CreateProxy(advisedSupport); - Assert.AreEqual(0, ni.Count); - ito.Age = 23; - Assert.AreEqual(23, ito.Age); - Assert.AreEqual(2, ni.Count); - - IAdvised advised = (IAdvised)ito; - Assert.AreEqual(1, advised.Advisors.Count, "Have 1 advisor"); - Assert.AreEqual(ni, advised.Advisors[0].Advice); - NopInterceptor ni2 = new NopInterceptor(); - advised.AddAdvice(1, ni2); - ito.Name = "Bruno"; - Assert.AreEqual(3, ni.Count); - Assert.AreEqual(1, ni2.Count); - // will remove ni - advised.RemoveAdvisor(0); - Assert.IsNotNull(ito.Age); - // Unchanged - Assert.AreEqual(3, ni.Count); - Assert.AreEqual(2, ni2.Count); - - CountingBeforeAdvice cba = new CountingBeforeAdvice(); - Assert.AreEqual(0, cba.GetCalls()); - advised.AddAdvice(cba); - ito.Age = 16; - Assert.AreEqual(16, ito.Age); - Assert.AreEqual(2, cba.GetCalls()); - } - - [Test] - public void CannotAddInterceptorWhenFrozen() - { - TestObject target = new TestObject(); - target.Age = 21; - ProxyFactory pf = new ProxyFactory(target); - Assert.IsFalse(pf.IsFrozen); - pf.AddAdvice(new NopInterceptor()); - ITestObject proxied = (ITestObject)CreateProxy(pf); - pf.IsFrozen = true; - try - { - pf.AddAdvice(0, new NopInterceptor()); - Assert.Fail("Shouldn't be able to add interceptor when frozen"); - } - catch (AopConfigException ex) - { - Assert.IsTrue(ex.Message.IndexOf("frozen") > -1); - } - - // Check it still works: proxy factory state shouldn't have been corrupted - Assert.AreEqual(target.Age, proxied.Age); - Assert.AreEqual(1, ((IAdvised)proxied).Advisors.Count); - } - - [Test(Description = "Check that casting to Advised can't get around advice freeze.")] - public void CannotAddAdvisorWhenFrozenUsingCast() - { - TestObject target = new TestObject(); - target.Age = 21; - ProxyFactory pf = new ProxyFactory(target); - Assert.IsFalse(pf.IsFrozen); - pf.AddAdvice(new NopInterceptor()); - ITestObject proxied = (ITestObject)CreateProxy(pf); - pf.IsFrozen = true; - IAdvised advised = (IAdvised)proxied; - - Assert.IsTrue(pf.IsFrozen); - try - { - advised.AddAdvisor(new DefaultPointcutAdvisor(new NopInterceptor())); - Assert.Fail("Shouldn't be able to add Advisor when frozen"); - } - catch (AopConfigException ex) - { - Assert.IsTrue(ex.Message.IndexOf("frozen") > -1); - } - - // Check it still works: proxy factory state shouldn't have been corrupted - Assert.AreEqual(target.Age, proxied.Age); - Assert.AreEqual(1, advised.Advisors.Count); - } - - [Test] - public void CannotRemoveAdvisorWhenFrozen() - { - TestObject target = new TestObject(); - target.Age = 21; - ProxyFactory pf = new ProxyFactory(target); - Assert.IsFalse(pf.IsFrozen); - pf.AddAdvice(new NopInterceptor()); - ITestObject proxied = (ITestObject)CreateProxy(pf); - pf.IsFrozen = true; - IAdvised advised = (IAdvised)proxied; - - Assert.IsTrue(pf.IsFrozen); - try - { - advised.RemoveAdvisor(0); - Assert.Fail("Shouldn't be able to remove Advisor when frozen"); - } - catch (AopConfigException ex) - { - Assert.IsTrue(ex.Message.IndexOf("frozen") > -1); - } - - // Didn't get removed - Assert.AreEqual(1, advised.Advisors.Count); - pf.IsFrozen = false; - // Can now remove it - advised.RemoveAdvisor(0); - // Check it still works: proxy factory state shouldn't have been corrupted - Assert.AreEqual(target.Age, proxied.Age); - Assert.AreEqual(0, advised.Advisors.Count); - } - - [Test(Description = "Check that the string is informative.")] - public void ProxyConfigString() - { - TestObject target = new TestObject(); - ProxyFactory pf = new ProxyFactory(target); - pf.Interfaces = new Type[] { typeof(ITestObject) }; - pf.AddAdvice(new NopInterceptor()); - IMethodBeforeAdvice mba = new CountingBeforeAdvice(); - IAdvisor advisor = new DefaultPointcutAdvisor(new NameMatchMethodPointcut(), mba); - pf.AddAdvisor(advisor); - ITestObject proxied = (ITestObject)CreateProxy(pf); - - String proxyConfigString = ((IAdvised)proxied).ToProxyConfigString(); - Assert.IsTrue(proxyConfigString.IndexOf(advisor.ToString()) != -1); - Assert.IsTrue(proxyConfigString.IndexOf("1 interface") != -1); - } - - // TODO : Opaque can be implemented if really usefull (To increase performance) - /* - public void testCanPreventCastToAdvisedUsingOpaque() - { - TestObject target = new TestObject(); - ProxyFactory pf = new ProxyFactory(target); - pf.Interfaces = new Type[] { typeof(ITestObject) }; - pf.AddAdvice(new NopInterceptor()); - CountingBeforeAdvice mba = new CountingBeforeAdvice(); - NameMatchMethodPointcut nmmp = new NameMatchMethodPointcut(); - nmmp.MappedName = "set_Age"; - IAdvisor advisor = new DefaultPointcutAdvisor(nmmp, mba); - pf.AddAdvisor(advisor); - Assert.IsFalse(pf.Opaque, "Opaque defaults to false"); - pf.Opaque = true; - Assert.IsTrue(pf.Opaque, "Opaque now true for this config"); - ITestObject proxied = (ITestObject) CreateProxy(pf); - proxied.Age = 10; - Assert.AreEqual(10, proxied.Age); - Assert.AreEqual(1, mba.GetCalls()); - - Assert.IsFalse(proxied is IAdvised, "Cannot be cast to Advised", ); - } - */ - - // TODO AdviceSupportListeners test - /* - [Test] - public void AdviceSupportListeners() - { - TestObject target = new TestObject(); - target.Age = 21; - - ProxyFactory pf = new ProxyFactory(target); - CountingAdvisorListener l = new CountingAdvisorListener(pc); - pf.AddListener(l); - RefreshCountingAdvisorChainFactory acf = new RefreshCountingAdvisorChainFactory(); - // Should be automatically added as a listener - pf.AdvisorChainFactory(acf); - Assert.IsFalse(pf.isActive()); - Assert.AreEqual(0, l.activates); - Assert.AreEqual(0, acf.refreshes); - ITestObject proxied = (ITestObject)CreateProxy(pf); - Assert.AreEqual(1, acf.refreshes); - Assert.AreEqual(1, l.activates); - Assert.IsTrue(pc.isActive()); - Assert.AreEqual(target.Age, proxied.Age); - Assert.AreEqual(0, l.adviceChanges); - NopInterceptor ni = new NopInterceptor(); - pf.addAdvice(0, ni); - Assert.AreEqual(1, l.adviceChanges); - Assert.AreEqual(2, acf.refreshes); - Assert.AreEqual(target.Age, proxied.Age); - pf.removeAdvice(ni); - Assert.AreEqual(2, l.adviceChanges); - Assert.AreEqual(3, acf.refreshes); - Assert.AreEqual(target.Age, proxied.Age); - pf.getProxy(); - Assert.AreEqual(1, l.activates); - - pf.RemoveListener(l); - Assert.AreEqual(2, l.adviceChanges); - pf.AddAdvisor(new DefaultPointcutAdvisor(new NopInterceptor())); - // No longer counting - Assert.AreEqual(2, l.adviceChanges); - } - - public class CountingAdvisorListener : IAdvisedSupportListener - { - public int adviceChanges; - public int activates; - private AdvisedSupport expectedSource; - - public CountingAdvisorListener(AdvisedSupport expectedSource) - { - this.expectedSource = expectedSource; - } - - public void AdviceChanged(AdvisedSupport source) - { - Assert.AreEqual(expectedSource, source); - ++adviceChanges; - } - - public void Activated(AdvisedSupport source) - { - Assert.AreEqual(expectedSource,source); - ++activates; - } - } - - public class RefreshCountingAdvisorChainFactory : IAdvisorChainFactory - { - public int refreshes; - - public void AdviceChanged(AdvisedSupport source) - { - ++refreshes; - } - - public IList GetInterceptors(IAdvised advised, object proxy, string methodId, MethodInfo method, Type targetType) - { - return AdvisorChainFactoryUtils.CalculateInterceptors(advised, proxy, method, targetType); - } - - public void Activated(AdvisedSupport source) - { - ++refreshes; - } - } -*/ - - [Test] - public void DynamicMethodPointcutThatAlwaysAppliesStatically() - { - TestObject to = new TestObject(); - ProxyFactory pf = new ProxyFactory(new Type[] { typeof(ITestObject) }); - TestDynamicPointcutAdvisor dp = new TestDynamicPointcutAdvisor(new NopInterceptor(), "get_Age"); - pf.AddAdvisor(dp); - pf.Target = to; - ITestObject it = (ITestObject)CreateProxy(pf); - Assert.AreEqual(dp.count, 0); - int age = it.Age; - Assert.IsNotNull(age); // avoid mono mcs CS0218 - Assert.AreEqual(dp.count, 1); - it.Age = 11; - Assert.AreEqual(it.Age, 11); - Assert.AreEqual(dp.count, 2); - } - - [Test] - public void DynamicMethodPointcutThatAppliesStaticallyOnlyToSetters() - { - TestObject to = new TestObject(); - ProxyFactory pf = new ProxyFactory(new Type[] { typeof(ITestObject) }); - // Could apply dynamically to property Age but not to property Name - ForSettersOnlyPointcutAdvisor dp = new ForSettersOnlyPointcutAdvisor(new NopInterceptor(), "Age"); - pf.AddAdvisor(dp); - this.mockTargetSource.SetTarget(to); - pf.TargetSource = mockTargetSource; - ITestObject it = (ITestObject)CreateProxy(pf); - Assert.AreEqual(dp.count, 0); - int age = it.Age; - Assert.IsNotNull(age); // avoid mono mcs error CS0219 - // Statically vetoed - Assert.AreEqual(0, dp.count); - it.Age = 11; - Assert.AreEqual(it.Age, 11); - Assert.AreEqual(dp.count, 1); - // Applies statically but not dynamically - it.Name = "joe"; - Assert.AreEqual(dp.count, 1); - } - - private class TestDynamicPointcutAdvisor : DynamicMethodMatcherPointcutAdvisor - { - private string pattern; - public int count = 0; - - public TestDynamicPointcutAdvisor(IAdvice advice, string pattern) - : - base(advice) - { - this.pattern = pattern; - } - - public override bool Matches(MethodInfo method, Type targetType, object[] args) - { - bool run = method.Name.IndexOf(pattern) != -1; - if (run) ++count; - return run; - } - } - - private class ForSettersOnlyPointcutAdvisor : TestDynamicPointcutAdvisor - { - public ForSettersOnlyPointcutAdvisor(IAdvice advice, string pattern) - : - base(advice, pattern) - { - } - - public override bool Matches(MethodInfo method, Type targetType) - { - return method.Name.StartsWith("set_"); - } - } - - [Test] - public void StaticMethodPointcut() - { - TestObject to = new TestObject(); - ProxyFactory pf = new ProxyFactory(new Type[] { typeof(ITestObject) }); - NopInterceptor ni = new NopInterceptor(); - TestStaticPointcutAdvisor sp = new TestStaticPointcutAdvisor(ni, "get_Age"); - pf.AddAdvisor(sp); - pf.Target = to; - ITestObject it = (ITestObject)CreateProxy(pf); - Assert.AreEqual(ni.Count, 0); - int age = it.Age; - Assert.IsNotNull(age); // avoid mono mcs error CS0219 - Assert.AreEqual(ni.Count, 1); - it.Age = 11; - Assert.AreEqual(it.Age, 11); - Assert.AreEqual(ni.Count, 2); - } - - private class TestStaticPointcutAdvisor : StaticMethodMatcherPointcutAdvisor - { - private string pattern; - private int count; - - public TestStaticPointcutAdvisor(IAdvice advice, String pattern) - : - base(advice) - { - this.pattern = pattern; - } - - public override bool Matches(MethodInfo method, Type targetType) - { - bool run = method.Name.IndexOf(pattern) != -1; - if (run) ++count; - return run; - } - } - - // TODO ? ReflectiveMethodInvocation is not Cloneable - /* - [Test(Description="There are times when we want to call proceed() twice.")] - public void CloneInvocationToProceedThreeTimes() - { - //We can do this if we clone the invocation. - - TestObject to = new TestObject(); - ProxyFactory pf = new ProxyFactory(to); - pf.AddInterface(typeof(ITestObject)); - - TwoBirthdayAdvice twoBirthdayAdvice = new TwoBirthdayAdvice(); - - TwoBirthdayPointcutAdvisor sp = new TwoBirthdayPointcutAdvisor(twoBirthdayAdvice); - pf.AddAdvisor(sp); - ITestObject ito = (ITestObject)CreateProxy(pf); - - int age = 20; - ito.Age = age; - Assert.AreEqual(age, ito.Age); - // Should return the age before the third, AOP-induced birthday - Assert.AreEqual(age + 2, ito.haveBirthday()); - // Return the final age produced by 3 birthdays - Assert.AreEqual(age + 3, ito.Age); - } - - private class TwoBirthdayPointcutAdvisor : StaticMethodMatcherPointcutAdvisor - { - public TwoBirthdayPointcutAdvisor(IAdvice advice) - : base(advice) - { - } - - public override bool Matches(MethodInfo method, Type targetType) - { - return "haveBirthday".Equals(method.Name); - } - } - - private class TwoBirthdayAdvice : IMethodInterceptor - { - public object Invoke(IMethodInvocation invocation) - { - // Clone the invocation to proceed three times - // "The Moor's Last Sigh": this technology can cause premature aging - IMethodInvocation clone1 = ((ReflectiveMethodInvocation)invocation).InvocableClone(); - IMethodInvocation clone2 = ((ReflectiveMethodInvocation)invocation).InvocableClone(); - clone1.Proceed(); - clone2.Proceed(); - return invocation.Proceed(); - } - } - - // // We want to change the arguments on a clone: it shouldn't affect the original. - // public void testCanChangeArgumentsIndependentlyOnClonedInvocation() throws Throwable - // { - // TestObject to = new TestObject(); - // ProxyFactory pc = new ProxyFactory(to); - // pc.addInterface(typeof(ITestObject)); - - // // Changes the name, then changes it back. - // MethodInterceptor nameReverter = new MethodInterceptor() { - // public Object invoke(MethodInvocation mi) throws Throwable { - // MethodInvocation clone = ((ReflectiveMethodInvocation) mi).invocableClone(); - // String oldName = ((ITestObject) mi.getThis()).Name; - // clone.getArguments()[0] = oldName; - // // Original method invocation should be unaffected by changes to argument list of clone - // mi.proceed(); - // return clone.proceed(); - // } - // }; - - // class NameSaver implements MethodInterceptor { - // private List names = new LinkedList(); - - // public Object invoke(MethodInvocation mi) throws Throwable { - // names.add(mi.getArguments()[0]); - // return mi.proceed(); - // } - // } - - // NameSaver saver = new NameSaver(); - - // pc.addAdvisor(new DefaultPointcutAdvisor(Pointcuts.SETTERS, nameReverter)); - // pc.addAdvisor(new DefaultPointcutAdvisor(Pointcuts.SETTERS, saver)); - // ITestObject it = (ITestObject) createProxy(pc); - - // String name1 = "tony"; - // String name2 = "gordon"; - - // to.setName(name1); - // Assert.AreEqual(name1, to.Name); - - // it.setName(name2); - // // NameReverter saved it back - // Assert.AreEqual(name1, it.Name); - // Assert.AreEqual(2, saver.names.size()); - // Assert.AreEqual(name2, saver.names.get(0)); - // Assert.AreEqual(name1, saver.names.get(1)); - // } - */ - - [Test] - public void OverloadedMethodsWithDifferentAdvice() - { - Overloads target = new Overloads(); - ProxyFactory pf = new ProxyFactory(target); - NopInterceptor overloadVoid = new NopInterceptor(); - pf.AddAdvisor(new OverloadVoidPointcutAdvisor(overloadVoid)); - NopInterceptor overloadInt = new NopInterceptor(); - pf.AddAdvisor(new OverloadIntPointcutAdvisor(overloadInt)); - - IOverloads proxy = (IOverloads)CreateProxy(pf); - - Assert.AreEqual(0, overloadInt.Count); - Assert.AreEqual(0, overloadVoid.Count); - proxy.Overload(); - Assert.AreEqual(0, overloadInt.Count); - Assert.AreEqual(1, overloadVoid.Count); - Assert.AreEqual(25, proxy.Overload(25)); - Assert.AreEqual(1, overloadInt.Count); - Assert.AreEqual(1, overloadVoid.Count); - proxy.NoAdvice(); - Assert.AreEqual(1, overloadInt.Count); - Assert.AreEqual(1, overloadVoid.Count); - } - - public interface IOverloads - { - void Overload(); - int Overload(int i); - string Overload(string foo); - void NoAdvice(); - } - - public class Overloads : IOverloads - { - public void Overload() - { - } - - public int Overload(int i) - { - return i; - } - - public string Overload(string foo) - { - return foo; - } - - public void NoAdvice() - { - } - } - - private class OverloadVoidPointcutAdvisor : StaticMethodMatcherPointcutAdvisor - { - public OverloadVoidPointcutAdvisor(IAdvice advice) - : base(advice) - { - } - - public override bool Matches(MethodInfo method, Type targetType) - { - return method.Name.Equals("Overload") && method.GetParameters().Length == 0; - } - } - - private class OverloadIntPointcutAdvisor : StaticMethodMatcherPointcutAdvisor - { - public OverloadIntPointcutAdvisor(IAdvice advice) - : base(advice) - { - } - - public override bool Matches(MethodInfo method, Type targetType) - { - return method.Name.Equals("Overload") && method.GetParameters().Length == 1 && - method.GetParameters()[0].ParameterType == typeof(int); - } - } - - // TODO : IAdvised.TargetSource is read only (no setter) - /* - [Test] - public void ExistingProxyChangesTarget() - { - TestObject to1 = new TestObject(); - to1.Age = 33; - - TestObject to2 = new TestObject(); - to2.Age = 26; - to2.Name = "Juergen"; - TestObject to3 = new TestObject(); - to3.Age = 37; - ProxyFactory pf = new ProxyFactory(to1); - NopInterceptor nop = new NopInterceptor(); - pf.AddAdvice(nop); - ITestObject proxy = (ITestObject)CreateProxy(pf); - Assert.AreEqual(nop.Count, 0); - Assert.AreEqual(to1.Age, proxy.Age); - Assert.AreEqual(nop.Count, 1); - // Change to a new static target - pf.Target = to2; - Assert.AreEqual(to2.Age, proxy.Age); - Assert.AreEqual(nop.Count, 2); - - // Change to a new dynamic target - HotSwappableTargetSource hts = new HotSwappableTargetSource(to3); - pf.TargetSource = hts; - Assert.AreEqual(to3.Age, proxy.Age); - Assert.AreEqual(nop.Count, 3); - hts.Swap(to1); - Assert.AreEqual(to1.Age, proxy.Age); - to1.Name = "Colin"; - Assert.AreEqual(to1.Name, proxy.Name); - Assert.AreEqual(nop.Count, 5); - - // Change back, relying on casting to Advised - IAdvised advised = (IAdvised)proxy; - Assert.AreSame(hts, advised.TargetSource); - SingletonTargetSource sts = new SingletonTargetSource(to2); - advised.TargetSource = sts; - Assert.AreEqual(to2.Name, proxy.Name); - Assert.AreSame(sts, advised.TargetSource); - Assert.AreEqual(to2.Age, proxy.Age); - } - - [Test] - public void ProxyIsBoundBeforeTargetSourceInvoked() - { - TestObject target = new TestObject(); - ProxyFactory pf = new ProxyFactory(target); - pf.AddAdvice(new DebugInterceptor()); - pf.ExposeProxy = true; - ITestObject proxy = (ITestObject) CreateProxy(pf); - IAdvised config = (IAdvised) proxy; - // This class just checks proxy is bound before getTarget() call - config.setTargetSource(new TargetSource() { - public Class getTargetClass() { - return TestObject.class; - } - - public boolean isStatic() { - return false; - } - - public Object getTarget() throws Exception { - Assert.AreEqual(proxy, AopContext.currentProxy()); - return target; - } - - public void releaseTarget(Object target) throws Exception { - } - }); - - // Just test anything: it will fail if context wasn't found - Assert.AreEqual(0, proxy.Age); - } - */ - - [Test] - public void BeforeAdvisorIsInvoked() - { - CountingBeforeAdvice cba = new CountingBeforeAdvice(); - IAdvisor matchesNoArgsAdvisor = new NoArgsMethodPointcutAdvisor(cba); - TestObject target = new TestObject(); - target.Age = 80; - ProxyFactory pf = new ProxyFactory(target); - pf.AddAdvice(new NopInterceptor()); - pf.AddAdvisor(matchesNoArgsAdvisor); - Assert.AreEqual(matchesNoArgsAdvisor, pf.Advisors[1], "Advisor was added"); - ITestObject proxied = (ITestObject)CreateProxy(pf); - Assert.AreEqual(0, cba.GetCalls()); - Assert.AreEqual(0, cba.GetCalls("get_Age")); - Assert.AreEqual(target.Age, proxied.Age); - Assert.AreEqual(1, cba.GetCalls()); - Assert.AreEqual(1, cba.GetCalls("get_Age")); - Assert.AreEqual(0, cba.GetCalls("set_Age")); - // Won't be advised - proxied.Age = 26; - Assert.AreEqual(1, cba.GetCalls()); - Assert.AreEqual(26, proxied.Age); - } - - private class NoArgsMethodPointcutAdvisor : StaticMethodMatcherPointcutAdvisor - { - public NoArgsMethodPointcutAdvisor(IAdvice advice) - : base(advice) - { - } - - public override bool Matches(MethodInfo method, Type targetType) - { - return method.GetParameters().Length == 0; - } - } - - // TODO : Multi advice not supported ? - - [Test] - [Ignore("Multi advice not supported for now.")] - public void MultiAdvice() - { - CountingMultiAdvice cma = new CountingMultiAdvice(); - IAdvisor matchesNoArgsAdvisor = new NoArgsOrNotExceptionalMethodPointcutAdvisor(cma); - TestObject target = new TestObject(); - target.Age = 80; - ProxyFactory pf = new ProxyFactory(target); - pf.AddAdvice(new NopInterceptor()); - pf.AddAdvisor(matchesNoArgsAdvisor); - Assert.AreEqual(matchesNoArgsAdvisor, pf.Advisors[1], "Advisor was added"); - ITestObject proxied = (ITestObject)CreateProxy(pf); - - Assert.AreEqual(0, cma.GetCalls()); - Assert.AreEqual(0, cma.GetCalls("get_Age")); - Assert.AreEqual(target.Age, proxied.Age); - Assert.AreEqual(2, cma.GetCalls()); - Assert.AreEqual(2, cma.GetCalls("get_Age")); - Assert.AreEqual(0, cma.GetCalls("set_Age")); - // Won't be advised - proxied.Age = 26; - Assert.AreEqual(2, cma.GetCalls()); - Assert.AreEqual(26, proxied.Age); - Assert.AreEqual(4, cma.GetCalls()); - try - { - proxied.Exceptional(new ApplicationException("foo")); - Assert.Fail("Should have thrown ApplicationException"); - } - catch (ApplicationException) - { - // expected - } - Assert.AreEqual(6, cma.GetCalls()); - } - - private class NoArgsOrNotExceptionalMethodPointcutAdvisor : StaticMethodMatcherPointcutAdvisor - { - public NoArgsOrNotExceptionalMethodPointcutAdvisor(IAdvice advice) - : base(advice) - { - } - - public override bool Matches(MethodInfo method, Type targetType) - { - return method.GetParameters().Length == 0 || method.Name == "Exceptional"; - } - } - - [Test] - public void BeforeAdviceThrowsException() - { - ApplicationException aex = new ApplicationException(); - CountingBeforeNonSetterAdvice ba = new CountingBeforeNonSetterAdvice(aex); - - TestObject target = new TestObject(); - target.Age = 80; - NopInterceptor nop1 = new NopInterceptor(); - NopInterceptor nop2 = new NopInterceptor(2); - ProxyFactory pf = new ProxyFactory(target); - pf.AddAdvice(nop1); - pf.AddAdvice(ba); - pf.AddAdvice(nop2); - ITestObject proxied = (ITestObject)CreateProxy(pf); - // Won't throw an exception - Assert.AreEqual(target.Age, proxied.Age); - Assert.AreEqual(1, ba.GetCalls()); - Assert.AreEqual(1, ba.GetCalls("get_Age")); - Assert.AreEqual(1, nop1.Count); - Assert.AreEqual(1, nop2.Count); - // Will fail, after invoking Nop1 - try - { - proxied.Age = 26; - Assert.Fail("before advice should have ended chain"); - } - catch (ApplicationException ex) - { - Assert.AreEqual(aex, ex); - } - Assert.AreEqual(2, ba.GetCalls()); - Assert.AreEqual(2, nop1.Count); - // Nop2 didn't get invoked when the exception was thrown - Assert.AreEqual(1, nop2.Count); - // Shouldn't have changed value in joinpoint - Assert.AreEqual(target.Age, proxied.Age); - } - - private class CountingBeforeNonSetterAdvice : CountingBeforeAdvice - { - private Exception _exception; - - public CountingBeforeNonSetterAdvice(Exception ex) - { - _exception = ex; - } - - public override void Before(MethodInfo method, object[] args, object target) - { - base.Before(method, args, target); - - if (method.Name.StartsWith("set_")) - throw _exception; - } - } - - [Test] - public void AfterReturningAdvisorIsInvoked() - { - SummingAfterAdvice aa = new SummingAfterAdvice(); - IAdvisor matchesIntAdvisor = new ReturnsIntPointcutAdvisor(aa); - TestObject target = new TestObject(); - ProxyFactory pf = new ProxyFactory(target); - pf.AddAdvice(new NopInterceptor()); - pf.AddAdvisor(matchesIntAdvisor); - Assert.AreEqual(matchesIntAdvisor, pf.Advisors[1], "Advisor was added"); - ITestObject proxied = (ITestObject)CreateProxy(pf); - Assert.AreEqual(0, aa.sum); - int i1 = 12; - int i2 = 13; - - // Won't be advised - proxied.Age = i1; - Assert.AreEqual(i1, proxied.Age); - Assert.AreEqual(i1, aa.sum); - proxied.Age = i2; - Assert.AreEqual(i2, proxied.Age); - Assert.AreEqual(i1 + i2, aa.sum); - Assert.AreEqual(i2, proxied.Age); - } - - private class SummingAfterAdvice : IAfterReturningAdvice - { - public int sum; - - public void AfterReturning(Object returnValue, MethodInfo method, Object[] args, Object target) - { - sum += ((int)returnValue); - } - } - - private class ReturnsIntPointcutAdvisor : StaticMethodMatcherPointcutAdvisor - { - public ReturnsIntPointcutAdvisor(IAdvice advice) - : base(advice) - { - } - - public override bool Matches(MethodInfo method, Type targetType) - { - return method.ReturnType == typeof(int); - } - } - - [Test] - public void AfterReturningAdvisorIsNotInvokedOnException() - { - CountingAfterReturningAdvice car = new CountingAfterReturningAdvice(); - TestObject target = new TestObject(); - ProxyFactory pf = new ProxyFactory(target); - pf.AddAdvice(new NopInterceptor()); - pf.AddAdvice(car); - Assert.AreEqual(car, pf.Advisors[1].Advice, "Advice was wrapped in Advisor and added"); - ITestObject proxied = (ITestObject)CreateProxy(pf); - Assert.AreEqual(0, car.GetCalls()); - int age = 10; - proxied.Age = age; - Assert.AreEqual(age, proxied.Age); - Assert.AreEqual(2, car.GetCalls()); - Exception ex = new Exception(); - // On exception it won't be invoked - try - { - proxied.Exceptional(ex); - Assert.Fail("Should have thrown Exception"); - } - catch (Exception caught) - { - Assert.AreSame(ex, caught); - } - Assert.AreEqual(2, car.GetCalls()); - } - -#if !NETCOREAPP - [Test] - public void ThrowsAdvisorIsInvoked() - { - // Reacts to HttpException and RemotingException - var th = new Spring.Aop.Framework.Adapter.ThrowsAdviceInterceptorTests.MyThrowsHandler(); - IAdvisor matchesEchoAdvisor = new EchoPointcutAdvisor(th); - var target = new Spring.Aop.Framework.Adapter.ThrowsAdviceInterceptorTests.Echo(); - target.A = 16; - ProxyFactory pf = new ProxyFactory(target); - pf.AddAdvice(new NopInterceptor()); - pf.AddAdvisor(matchesEchoAdvisor); - Assert.AreEqual(matchesEchoAdvisor, pf.Advisors[1], "Advisor was added"); - var proxied = (Spring.Aop.Framework.Adapter.ThrowsAdviceInterceptorTests.IEcho)CreateProxy(pf); - Assert.AreEqual(0, th.GetCalls()); - Assert.AreEqual(target.A, proxied.A); - Assert.AreEqual(0, th.GetCalls()); - Exception ex = new Exception(); - // Will be advised but doesn't match - try - { - proxied.EchoException(1, ex); - Assert.Fail("Should have thrown Exception"); - } - catch (Exception caught) - { - Assert.AreEqual(ex, caught); - } - - ex = new System.Web.HttpException(); - try - { - proxied.EchoException(1, ex); - Assert.Fail("Should have thrown HttpException"); - } - catch (System.Web.HttpException caught) - { - Assert.AreEqual(ex, caught); - } - Assert.AreEqual(1, th.GetCalls("HttpException")); - } -#endif - - private class EchoPointcutAdvisor : StaticMethodMatcherPointcutAdvisor - { - public EchoPointcutAdvisor(IAdvice advice) - : base(advice) - { - } - - public override bool Matches(MethodInfo method, Type targetType) - { - return method.Name.StartsWith("Echo"); - } - } - -#if !NETCOREAPP - [Test] - public void AddThrowsAdviceWithoutAdvisor() - { - // Reacts to ServletException and RemoteException - var th = new Spring.Aop.Framework.Adapter.ThrowsAdviceInterceptorTests.MyThrowsHandler(); - - var target = new Spring.Aop.Framework.Adapter.ThrowsAdviceInterceptorTests.Echo(); - target.A = 16; - ProxyFactory pf = new ProxyFactory(target); - pf.AddAdvice(new NopInterceptor()); - pf.AddAdvice(th); - var proxied = (Spring.Aop.Framework.Adapter.ThrowsAdviceInterceptorTests.IEcho) CreateProxy(pf); - Assert.AreEqual(0, th.GetCalls()); - Assert.AreEqual(target.A, proxied.A); - Assert.AreEqual(0, th.GetCalls()); - Exception ex = new Exception(); - // Will be advised but doesn't match - try - { - proxied.EchoException(1, ex); - Assert.Fail("Should have thrown Exception"); - } - catch (Exception caught) - { - Assert.AreEqual(ex, caught); - } - - // Subclass of RemoteException - ex = new System.Runtime.Remoting.RemotingTimeoutException(); - try - { - proxied.EchoException(1, ex); - Assert.Fail("Should have thrown RemotingTimeoutException"); - } - catch (System.Runtime.Remoting.RemotingTimeoutException caught) - { - Assert.AreEqual(ex, caught); - } - Assert.AreEqual(1, th.GetCalls("RemotingException")); - } -#endif - - [Test] - public void ArgumentsModification() - { - } - - - public interface ITargetClass - { - string TargetMethod(string arg); - } - - public class TargetClass : ITargetClass - { - public string TargetMethod(string arg) - { - if (arg == null) - { - throw new ArgumentException(); - } - return arg; - } - } - - public class Interceptor1 : IMethodInterceptor - { - public object Invoke(IMethodInvocation invocation) - { - invocation.Proceed(); - - return invocation.Arguments[0]; - } - } - - public class Interceptor2 : IMethodInterceptor - { - public object Invoke(IMethodInvocation invocation) - { - invocation.Arguments[0] = null; - - return invocation.Proceed(); - } - } - - - public interface INeedsToSeeProxy - { - int Count { get; } - - void IncrementViaThis(); - - void IncrementViaProxy(); - - void Increment(); - } - - public class NeedsToSeeProxy : INeedsToSeeProxy - { - private int _count; - public int Count - { - get { return _count; } - } - - public void IncrementViaThis() - { - this.Increment(); - } - - public void IncrementViaProxy() - { - INeedsToSeeProxy thisViaProxy = (INeedsToSeeProxy)AopContext.CurrentProxy; - thisViaProxy.Increment(); - IAdvised advised = (IAdvised)thisViaProxy; - CheckAdvised(advised); - } - - protected virtual void CheckAdvised(IAdvised advised) - { - } - - public void Increment() - { - ++_count; - } - } - - public class TargetChecker : NeedsToSeeProxy - { - protected override void CheckAdvised(IAdvised advised) - { - // TODO replace this check: no longer possible - //Assert.AreEqual(advised.getTarget(), this); - } - } - - public class DynamicTargetSource : ITargetSource - { - private object target; - private Type targetType; - - public DynamicTargetSource(Type targetType, object target) - { - this.targetType = targetType; - this.target = target; - } - - public object Target - { - get { return target; } - set { target = value; } - } - - public Type TargetType - { - get { return targetType; } - set { targetType = value; } - } - - public bool IsStatic - { - get { return false; } - } - - public virtual object GetTarget() - { - return target; - } - - public void ReleaseTarget(object target) - { } - } - - public class DynamicInvocationTestInterceptor : IMethodInterceptor - { - public bool CallProceed = false; - public IMethodInvocation LastMethodInvocation; - - public object Invoke(IMethodInvocation invocation) - { - LastMethodInvocation = invocation; - if (CallProceed) - { - return invocation.Proceed(); - } - return null; - } + } + } + + [Serializable] + public class CustomSerializableTestObject : ISerializableTestObject, ISerializable, IDeserializationCallback + { + public static int InstanceCount; + + public CustomSerializableTestObject() + { + InstanceCount++; + } + + protected CustomSerializableTestObject(SerializationInfo info, StreamingContext context) + { + TestData = info.GetString("testData"); + } + + public void GetObjectData(SerializationInfo info, StreamingContext context) + { + info.AddValue("testData", TestData); + } + + public string TestData { get { return testData; } set { testData = value; } } + + public void OnDeserialization(object sender) + { + if (!AopUtils.IsAopProxy(this)) + { + InstanceCount++; + } + } + + [NonSerialized] private string testData; + } + + [Test] + public void CanSerializeDeserializeSerializable() + { + int instanceCount; + ISerializableTestObject target = new SerializableTestObject(); + target.TestData = "testData"; + AdvisedSupport advised = new AdvisedSupport(); + advised.Target = target; + advised.Interfaces = new Type[] { typeof(ISerializableTestObject) }; + // advised.AddAdvisor(new DefaultPointcutAdvisor(new NopInterceptor())); + + ISerializableTestObject to = (ISerializableTestObject) CreateAopProxy(advised); + + instanceCount = SerializableTestObject.InstanceCount; + to = (ISerializableTestObject) SerializeAndDeserialize(to); + + // new instance was created + Assert.AreEqual(instanceCount + 1, SerializableTestObject.InstanceCount); + // values were (de-)serialized + Assert.AreEqual(target.TestData, to.TestData); + } + + [Test] + public void CanSerializeDeserializeISerializable() + { + int instanceCount; + ISerializableTestObject target = new CustomSerializableTestObject(); + target.TestData = "testData"; + AdvisedSupport advised = new AdvisedSupport(); + advised.Target = target; + advised.Interfaces = new Type[] { typeof(ISerializableTestObject) }; + // advised.AddAdvisor(new DefaultPointcutAdvisor(new NopInterceptor())); + + ISerializableTestObject to = (ISerializableTestObject) CreateAopProxy(advised); + + instanceCount = CustomSerializableTestObject.InstanceCount; + to = (ISerializableTestObject) SerializeAndDeserialize(to); + + // new instance was created + Assert.AreEqual(instanceCount + 1, CustomSerializableTestObject.InstanceCount); + // values were (de-)serialized + Assert.AreEqual(target.TestData, to.TestData); + } + + [Test(Description = "Simple test that if we set values we can get them out again.")] + public void ValuesStick() + { + int age1 = 33; + int age2 = 37; + string name = "tony"; + + TestObject target = new TestObject(); + target.Age = age1; + ProxyFactory pf1 = new ProxyFactory(target); + pf1.AddAdvisor(new DefaultPointcutAdvisor(new NopInterceptor())); + pf1.AddAdvisor(new DefaultPointcutAdvisor(new TimestampIntroductionInterceptor())); + ITestObject to = target; + + Assert.AreEqual(age1, to.Age); + to.Age = age2; + Assert.AreEqual(age2, to.Age); + Assert.IsNull(to.Name); + to.Name = name; + Assert.AreEqual(name, to.Name); + } + + public interface ITestPerson + { + long Id { get; set; } + string Name { get; set; } + } + + public interface ITestCustomer : ITestPerson + { + string Company { get; set; } + } + + public class TestCustomer : ITestCustomer + { + private long _id; + private string _name; + private string _company; + + public long Id + { + get { return _id; } + set { _id = value; } + } + + public string Name + { + get { return _name; } + set { _name = value; } + } + + public string Company + { + get { return _company; } + set { _company = value; } + } + } + + [Test(Description = "http://jira.springframework.org/browse/SPRNET-1174")] + public void ImplementsInterfaceHierarchy() + { + IMethodInterceptor mi = A.Fake(); + + A.CallTo(() => mi.Invoke(A.That.Matches(x => x.Method.Name == "get_Id"))).Returns((long) 5).Once(); + A.CallTo(() => mi.Invoke(A.That.Matches(x => x.Method.Name == "get_Name"))).Returns("Customer Name").Once(); + A.CallTo(() => mi.Invoke(A.That.Matches(x => x.Method.Name == "get_Company"))).Returns("Customer Company").Once(); + + AdvisedSupport advised = new AdvisedSupport(); + advised.AddAdvice(mi); + advised.Interfaces = new[] { typeof(ITestCustomer) }; + + ITestCustomer to = CreateProxy(advised) as ITestCustomer; + Assert.IsNotNull(to); + Assert.AreEqual((long) 5, to.Id, "Incorrect Id"); + Assert.AreEqual("Customer Name", to.Name, "Incorrect Name"); + Assert.AreEqual("Customer Company", to.Company, "Incorrect Company"); + } + + //[Test] - to be called from derived fixtures + public virtual void Equality() + { + TestCustomer customer = new TestCustomer(); + + AdvisedSupport advised = new AdvisedSupport(); + advised.Target = customer; + advised.Interfaces = new Type[] { typeof(ITestCustomer) }; + + ITestCustomer to = CreateProxy(advised) as ITestCustomer; + Assert.IsNotNull(to); + Assert.IsTrue(to.Equals(to), "identity must be equal"); + Assert.AreEqual(to, to); + Assert.AreEqual(to, ((IAdvised) to).TargetSource.GetTarget()); + } + + [Test] + public void Does_proxy_interfacemethods_without_implementation_and_by_default_throws_NotSupportedException() + { + AdvisedSupport advised = new AdvisedSupport(); + advised.TargetSource = new DynamicTargetSource(typeof(object), null); + advised.Interfaces = new Type[] { typeof(ITestObject) }; + + ITestObject proxy = CreateProxy(advised) as ITestObject; + Assert.IsNotNull(proxy); + + Assert.Throws(() => proxy.GetDescription(), "Target 'target' is null."); + } + + [Test] + public void Does_proxy_interfacemethods_without_implementation_and_delegates_to_interceptors() + { + DynamicInvocationTestInterceptor invocationInterceptor = new DynamicInvocationTestInterceptor(); + DynamicTargetSource targetSource = new DynamicTargetSource(typeof(object), null); + + AdvisedSupport advised = new AdvisedSupport(); + advised.TargetSource = targetSource; + advised.Interfaces = new Type[] { typeof(ITestObject) }; + advised.AddAdvice(invocationInterceptor); + ITestObject proxy = CreateProxy(advised) as ITestObject; + Assert.IsNotNull(proxy); + + // target null, call handled by interceptor + targetSource.Target = null; + invocationInterceptor.CallProceed = false; + proxy.GetDescription(); + Assert.AreEqual("GetDescription", invocationInterceptor.LastMethodInvocation.Method.Name); + } + + [Test] + public void Does_proxy_interfacemethods_without_implementation_and_throws_ArgumentNullException_On_NullTarget() + { + DynamicInvocationTestInterceptor invocationInterceptor = new DynamicInvocationTestInterceptor(); + DynamicTargetSource targetSource = new DynamicTargetSource(typeof(object), null); + + AdvisedSupport advised = new AdvisedSupport(); + advised.TargetSource = targetSource; + advised.Interfaces = new Type[] { typeof(ITestObject) }; + advised.AddAdvice(invocationInterceptor); + ITestObject proxy = CreateProxy(advised) as ITestObject; + Assert.IsNotNull(proxy); + + // target null, call not handled by interceptor + targetSource.Target = null; + invocationInterceptor.CallProceed = true; + var ex = Assert.Throws(() => proxy.GetDescription()); + Assert.That(ex.Message, Does.Contain("'target'")); + } + + [Test] + public void Does_proxy_interfacemethods_without_implementation_and_throws_NotSupportedException_On_Incompatible_Target() + { + DynamicInvocationTestInterceptor invocationInterceptor = new DynamicInvocationTestInterceptor(); + DynamicTargetSource targetSource = new DynamicTargetSource(typeof(object), null); + + AdvisedSupport advised = new AdvisedSupport(); + advised.TargetSource = targetSource; + advised.Interfaces = new Type[] { typeof(ITestObject) }; + advised.AddAdvice(invocationInterceptor); + ITestObject proxy = CreateProxy(advised) as ITestObject; + Assert.IsNotNull(proxy); + + // target incompatible, call not handled by interceptor + targetSource.Target = new object(); + invocationInterceptor.CallProceed = true; + Assert.Throws(() => proxy.GetDescription(), "Target 'target' of type 'System.Object' does not support methods of 'Spring.Objects.ITestObject'."); + } + + [Test] + public void NoInterceptorWithNoTarget() + { + AdvisedSupport advised = new AdvisedSupport(); + advised.Interfaces = new Type[] { typeof(ITestObject) }; + + ITestObject to = CreateProxy(advised) as ITestObject; + Assert.Throws(() => to.GetDescription(), "Target 'target' of type 'System.Object' does not support methods of 'Spring.Objects.ITestObject'."); + } + + [Test] + public void InterceptorHandledCallWithNoTarget() + { + int age = 26; + IMethodInterceptor mock = A.Fake(); + A.CallTo(() => mock.Invoke(A.That.Not.IsNull())).Returns(age); + + AdvisedSupport advised = new AdvisedSupport(); + advised.AddAdvice(mock); + advised.Interfaces = new Type[] { typeof(ITestObject) }; + + ITestObject to = CreateProxy(advised) as ITestObject; + Assert.IsNotNull(to); + Assert.IsTrue(to.Age == age, "Incorrect age"); + } + + [Test] + public void InterceptorUnhandledCallWithNoTarget() + { + AdvisedSupport advised = new AdvisedSupport(); + advised.AddAdvice(new NopInterceptor()); + advised.Interfaces = new Type[] { typeof(ITestObject) }; + + ITestObject to = CreateProxy(advised) as ITestObject; + Assert.IsNotNull(to); + Assert.Throws(() => to.GetDescription(), "Target 'target' of type 'System.Object' does not support methods of 'Spring.Objects.ITestObject'."); + } + + [Test] + public void ProxyAProxy() + { + ITestObject target = new TestObject(); + target.Age = 26; + + AdvisedSupport advised = new AdvisedSupport(target); + advised.AddAdvice(new NopInterceptor()); + IAopProxy aop = CreateAopProxy(advised); + ITestObject proxy1 = (ITestObject) aop.GetProxy(); + Assert.AreEqual(target.Age, proxy1.Age, "Incorrect age"); + + advised = new AdvisedSupport(proxy1); + advised.AddAdvice(new NopInterceptor()); + aop = CreateAopProxy(advised); + ITestObject proxy2 = (ITestObject) aop.GetProxy(); + Assert.AreEqual(target.Age, proxy2.Age, "Incorrect age"); + } + + // SPRNET-655 + [Test] + public void ProxyAProxyWhereClassExplicitlyImplementsInterfacesWithSameMethodNamesAndSignatures() + { + TheCommand target = new TheCommand(); + + // proxy + AdvisedSupport advised = new AdvisedSupport(target); + advised.AddAdvice(new NopInterceptor()); + object proxy = CreateProxy(advised); + + // proxy again + advised = new AdvisedSupport(proxy); + advised.AddAdvice(new NopInterceptor()); + proxy = CreateAopProxy(advised); + + IServiceCommand serviceCommand = proxy as IServiceCommand; + Assert.IsNotNull(serviceCommand); + serviceCommand.Execute(); + + IBusinessCommand businessCommand = proxy as IBusinessCommand; + Assert.IsNotNull(businessCommand); + businessCommand.Execute(); + + Assert.AreEqual(1, serviceCommand.ServiceCount); + Assert.AreEqual(1, businessCommand.BusinessCount); + } + + public interface IServiceCommand + { + int ServiceCount { get; } + + void Execute(); + } + + public interface IBusinessCommand + { + int BusinessCount { get; } + + void Execute(); + } + + public class TheCommand : IServiceCommand, IBusinessCommand + { + private int _serviceCount = 0; + + int IServiceCommand.ServiceCount + { + get { return _serviceCount; } + } + + void IServiceCommand.Execute() + { + _serviceCount++; + } + + private int _businessCount = 0; + + int IBusinessCommand.BusinessCount + { + get { return _businessCount; } + } + + void IBusinessCommand.Execute() + { + _businessCount++; + } + } + + [Test] + public void EqualsMethod() + { + TestObject target = new TestObject(); + + AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(ITestObject) }); + advised.Target = target; + IAopProxy aopProxy = CreateAopProxy(advised); + object proxy = aopProxy.GetProxy(); + + Assert.IsNotNull(proxy); + Assert.AreEqual(target, proxy, "Equals() returned false"); + } + + [Test] + public void GetHashCodeMethod() + { + TestObject target = new TestObject(); + + AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(ITestObject) }); + advised.Target = target; + IAopProxy aopProxy = CreateAopProxy(advised); + object proxy = aopProxy.GetProxy(); + + Assert.IsNotNull(proxy); + Assert.AreEqual(target.GetHashCode(), proxy.GetHashCode(), "GetHashCode() not equal"); + } + + [Test] + [Platform("Win")] + public void ProxyMethodWithRefOutParametersWithDirectCall() + { + PublicRefOutTestObject target = new PublicRefOutTestObject(); + + AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(IRefOutTestObject) }); + advised.Target = target; + + IAopProxy aopProxy = CreateAopProxy(advised); + IRefOutTestObject proxy = aopProxy.GetProxy() as IRefOutTestObject; + Assert.IsNotNull(proxy); + + TestsProxyMethodWithRefOutParameters(proxy); + } + + [Test] + [Platform("Win")] + public void ProxyMethodWithRefOutParametersWithDynamicReflection() + { + PublicRefOutTestObject target = new PublicRefOutTestObject(); + + AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(IRefOutTestObject) }); + advised.Target = target; + NopInterceptor ni = new NopInterceptor(); + advised.AddAdvice(ni); + + IAopProxy aopProxy = CreateAopProxy(advised); + IRefOutTestObject proxy = aopProxy.GetProxy() as IRefOutTestObject; + Assert.IsNotNull(proxy); + + TestsProxyMethodWithRefOutParameters(proxy); + + Assert.AreEqual(1, ni.Count); + } + + [Test] + [Platform("Win")] + public virtual void ProxyMethodWithRefOutParametersWithStandardReflection() + { + InternalRefOutTestObject target = new InternalRefOutTestObject(); + + AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(IRefOutTestObject) }); + advised.Target = target; + NopInterceptor ni = new NopInterceptor(); + advised.AddAdvice(ni); + + IAopProxy aopProxy = CreateAopProxy(advised); + IRefOutTestObject proxy = aopProxy.GetProxy() as IRefOutTestObject; + Assert.IsNotNull(proxy); + + TestsProxyMethodWithRefOutParameters(proxy); + + Assert.AreEqual(1, ni.Count); + } + + private void TestsProxyMethodWithRefOutParameters(IRefOutTestObject instance) + { + int valueType = 0; + TestObject obj = null; + EnumValue enumValue = EnumValue.Initial; + bool refValueType = false; + int outValueType; + String refObj = null; + TestObject outObj; + EnumValue refEnum = EnumValue.Initial; + EnumValue outEnum = EnumValue.Initial; + Guid refGuid = Guid.NewGuid(); + Guid outGuid = Guid.NewGuid(); + + instance.DoIt(valueType, obj, enumValue, ref refValueType, out outValueType, ref refObj, out outObj, ref refEnum, out outEnum, ref refGuid, out outGuid); + + Assert.AreEqual(0, valueType); + Assert.AreEqual(null, obj); + Assert.AreEqual(EnumValue.Initial, enumValue); + Assert.AreEqual(true, refValueType); + Assert.AreEqual(1, outValueType); + Assert.AreEqual("RefObj", refObj); + Assert.IsNotNull(outObj); + Assert.AreEqual("OutObj", outObj.Name); + Assert.AreEqual(EnumValue.Ref, refEnum); + Assert.AreEqual(EnumValue.Out, outEnum); + Assert.AreEqual(Guid.Empty, refGuid); + Assert.AreEqual(Guid.Empty, outGuid); + } + + public enum EnumValue + { + Initial, + Ref, + Out, + Another + } + + public interface IRefOutTestObject + { + int DoIt(int valueType, TestObject obj, EnumValue enumValue, + ref bool refValueType, out int outValueType, + ref String refObj, out TestObject outObj, + ref EnumValue refEnum, out EnumValue outEnum, + ref Guid refGuid, out Guid outGuid); + } + + public class PublicRefOutTestObject : IRefOutTestObject + { + public int DoIt(int valueType, TestObject obj, EnumValue enumValue, + ref bool refValueType, out int outValueType, + ref String refObj, out TestObject outObj, + ref EnumValue refEnum, out EnumValue outEnum, + ref Guid refGuid, out Guid outGuid) + { + valueType++; + obj = new TestObject("Bruno", 27); + enumValue = EnumValue.Another; + refValueType = true; + outValueType = 1; + refObj += "RefObj"; + outObj = new TestObject("OutObj", 27); + refEnum = EnumValue.Ref; + outEnum = EnumValue.Out; + refGuid = Guid.Empty; + outGuid = Guid.Empty; + + return 0; + } + } + + internal class InternalRefOutTestObject : PublicRefOutTestObject + { + } + + [Test] + [Platform("Win")] + public void ProxyGenericMethodWithRefOutParametersWithDirectCall() + { + PublicRefOutGenericTestObject target = new PublicRefOutGenericTestObject(); + + AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(IRefOutGenericTestObject) }); + advised.Target = target; + + IAopProxy aopProxy = CreateAopProxy(advised); + IRefOutGenericTestObject proxy = aopProxy.GetProxy() as IRefOutGenericTestObject; + Assert.IsNotNull(proxy); + + TestsProxyGenericMethodWithRefOutParameters(proxy); + } + + [Test] + [Platform("Win")] + public void ProxyGenericMethodWithRefOutParametersWithDynamicReflection() + { + PublicRefOutGenericTestObject target = new PublicRefOutGenericTestObject(); + + AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(IRefOutGenericTestObject) }); + advised.Target = target; + NopInterceptor ni = new NopInterceptor(); + advised.AddAdvice(ni); + + IAopProxy aopProxy = CreateAopProxy(advised); + IRefOutGenericTestObject proxy = aopProxy.GetProxy() as IRefOutGenericTestObject; + Assert.IsNotNull(proxy); + + TestsProxyGenericMethodWithRefOutParameters(proxy); + + Assert.AreEqual(3, ni.Count); + } + + [Test] + [Platform("Win")] + public virtual void ProxyGenericMethodWithRefOutParametersWithStandardReflection() + { + InternalRefOutGenericTestObject target = new InternalRefOutGenericTestObject(); + + AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(IRefOutGenericTestObject) }); + advised.Target = target; + NopInterceptor ni = new NopInterceptor(); + advised.AddAdvice(ni); + + IAopProxy aopProxy = CreateAopProxy(advised); + IRefOutGenericTestObject proxy = aopProxy.GetProxy() as IRefOutGenericTestObject; + Assert.IsNotNull(proxy); + + TestsProxyGenericMethodWithRefOutParameters(proxy); + + Assert.AreEqual(3, ni.Count); + } + + private void TestsProxyGenericMethodWithRefOutParameters(IRefOutGenericTestObject instance) + { + EnumValue enumValue = EnumValue.Another; + EnumValue refEnum = EnumValue.Ref; + EnumValue outEnum = EnumValue.Out; + EnumValue enumResult = instance.DoIt(enumValue, ref refEnum, out outEnum); + Assert.AreEqual(EnumValue.Another, refEnum); + Assert.AreEqual(EnumValue.Another, outEnum); + Assert.AreEqual(EnumValue.Another, enumResult); + + TestObject objectValue = new TestObject("Value", 28); + TestObject refObject = new TestObject("Ref", 28); + TestObject outObject = new TestObject("Out", 28); + TestObject objectResult = instance.DoIt(objectValue, ref refObject, out outObject); + Assert.AreEqual("Value", refObject.Name); + Assert.AreEqual("Value", outObject.Name); + Assert.AreEqual("Value", objectResult.Name); + + int intValue = 1; + int refInt = 2; + int outInt = 3; + int intResult = instance.DoIt(intValue, ref refInt, out outInt); + Assert.AreEqual(1, refInt); + Assert.AreEqual(1, outInt); + Assert.AreEqual(1, intResult); + } + + public interface IRefOutGenericTestObject + { + T DoIt(T param, ref T refParam, out T outParam); + } + + public class PublicRefOutGenericTestObject : IRefOutGenericTestObject + { + public T DoIt(T paramValue, ref T refParam, out T outParam) + { + refParam = paramValue; + outParam = paramValue; + + return paramValue; + } + } + + internal class InternalRefOutGenericTestObject : PublicRefOutGenericTestObject + { + } + + [Test] + public void ToStringMethod() + { + TestObject target = new TestObject(); + + AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(ITestObject) }); + advised.Target = target; + IAopProxy aopProxy = CreateAopProxy(advised); + object proxy = aopProxy.GetProxy(); + + Assert.IsNotNull(proxy); + Assert.AreEqual(target.ToString(), proxy.ToString(), "ToString() not equal"); + } + + [Test] + public void InterceptGenericMethod() + { + AbstractProxyTypeBuilderTests.ClassWithGenericMethod target = + new AbstractProxyTypeBuilderTests.ClassWithGenericMethod(); + mockTargetSource.SetTarget(target); + + NopInterceptor ni = new NopInterceptor(); + + AdvisedSupport advised = new AdvisedSupport(mockTargetSource); + advised.AddAdvice(ni); + + AbstractProxyTypeBuilderTests.InterfaceWithGenericMethod proxy = + CreateProxy(advised) as AbstractProxyTypeBuilderTests.InterfaceWithGenericMethod; + Assert.IsNotNull(proxy); + + proxy.PolymorphicMethod(); + proxy.PolymorphicMethod(); + + string result1 = proxy.PolymorphicMethod("coucou"); + Assert.AreEqual("coucou", result1); + + proxy.WithGenericParameter(); + + proxy.WithGenericParameterAndGenericArgument("ola"); + + string result2 = proxy.WithGenericParameterAndGenericArgumentAndGenericReturnType("ola"); + Assert.AreEqual("ola", result2); + + proxy.WithInterfaceConstraint(); + + proxy.WithBaseTypeConstraint(); + + proxy.WithBaseTypeAndInterfaceConstraints(); + + proxy.WithMixedConstraint(); + Assert.AreEqual(10, ni.Count); + + //if (this is DecoratorAopProxyTests) + //{ + // DynamicProxyManager.SaveAssembly(); + //} + } + + [Test] + public void InterceptGenericInterface() + { + AbstractProxyTypeBuilderTests.ClassThatImplementsGenericInterface target = + new AbstractProxyTypeBuilderTests.ClassThatImplementsGenericInterface(); + mockTargetSource.SetTarget(target); + + NopInterceptor ni = new NopInterceptor(); + + AdvisedSupport advised = new AdvisedSupport(mockTargetSource); + advised.AddAdvice(ni); + + AbstractProxyTypeBuilderTests.GenericInterface proxy = + CreateProxy(advised) as AbstractProxyTypeBuilderTests.GenericInterface; + Assert.IsNotNull(proxy); + + TestObject to1 = proxy.Create(); + Assert.IsNotNull(to1); + + TestObject to2 = proxy.Populate(new TestObject()); + Assert.IsNotNull(to2); + Assert.AreEqual("Populated", to2.Name); + + Assert.AreEqual(2, ni.Count); + } + + [Test(Description = "http://opensource.atlassian.com/projects/spring/browse/SPRNET-340")] + [Platform("Win")] + public void MultiThreadedProxyCreation() + { + MultiThreadedProxyCreation(5); + } + + private void MultiThreadedProxyCreation(int howMany) + { + AsyncTestMethod[] threads = new AsyncTestMethod[howMany]; + for (int i = 0; i < howMany; i++) + threads[i] = new AsyncTestMethod(10, new ThreadStart(ProxyTestObject)); + for (int i = 0; i < howMany; i++) + threads[i].Start(); + for (int i = 0; i < howMany; i++) + threads[i].AssertNoException(); + } + + private void ProxyTestObject() + { + TestObject target = new TestObject(); + target.Age = 26; + + AdvisedSupport advised = new AdvisedSupport(target); + advised.AddAdvice(new NopInterceptor()); + + ITestObject proxy = CreateProxy(advised) as ITestObject; + Assert.IsNotNull(proxy); + Assert.AreEqual(target.Age, proxy.Age, "Incorrect age"); + } + + [Test] + public void ProxyTargetTypeAttributes() + { + MarkerClass target = new MarkerClass(); + + AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(IMarkerInterface) }); + advised.Target = target; + IAopProxy aopProxy = CreateAopProxy(advised); + + object proxy = aopProxy.GetProxy(); + Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to GetProxy() was null."); + + object[] attrs = proxy.GetType().GetCustomAttributes(false); + Assert.IsNotNull(attrs, "Should have had 1 attribute applied to the target type."); + Assert.AreEqual(1, attrs.Length, "Should have had 1 attribute applied to the target type."); + Assert.AreEqual(typeof(MarkerAttribute), attrs[0].GetType(), "Wrong System.Type of Attribute applied to the target type."); + } + + [Test] + public void DoesNotProxyTargetTypeAttributesWithProxyTargetAttributesEqualsFalse() + { + MarkerClass target = new MarkerClass(); + + AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(IMarkerInterface) }); + advised.Target = target; + advised.ProxyTargetAttributes = false; + IAopProxy aopProxy = CreateAopProxy(advised); + + object proxy = aopProxy.GetProxy(); + Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to GetProxy() was null."); + + object[] attrs = proxy.GetType().GetCustomAttributes(false); + Assert.IsNotNull(attrs); + Assert.AreEqual(0, attrs.Length, "Should not have attribute applied to the target type."); + } + + [Test] + public void ProxyTargetMethodAttributes() + { + MarkerClass target = new MarkerClass(); + + AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(IMarkerInterface) }); + advised.Target = target; + IAopProxy aopProxy = CreateAopProxy(advised); + + object proxy = aopProxy.GetProxy(); + Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to GetProxy() was null."); + + MethodInfo method = proxy.GetType().GetMethod("Spring.Aop.Framework.DynamicProxy.AbstractAopProxyTests+IMarkerInterface.MarkerMethod", BindingFlags.NonPublic | BindingFlags.Instance); + if (method == null) + { + method = proxy.GetType().GetMethod("MarkerMethod"); + } + + Assert.IsNotNull(method); + + object[] attrs = method.GetCustomAttributes(false); + Assert.IsNotNull(attrs, "Should have 1 attribute applied to the target method."); + Assert.AreEqual(1, attrs.Length, "Should have 1 attribute applied to the target method."); + Assert.AreEqual(typeof(MarkerAttribute), attrs[0].GetType(), "Wrong System.Type of Attribute applied to the target method."); + } + + [Test] + public void DoesNotProxyTargetMethodAttributesWithProxyTargetAttributesEqualsFalse() + { + MarkerClass target = new MarkerClass(); + + AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(IMarkerInterface) }); + advised.Target = target; + advised.ProxyTargetAttributes = false; + IAopProxy aopProxy = CreateAopProxy(advised); + + object proxy = aopProxy.GetProxy(); + Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to GetProxy() was null."); + + MethodInfo method = proxy.GetType().GetMethod("Spring.Aop.Framework.DynamicProxy.AbstractAopProxyTests+IMarkerInterface.MarkerMethod", BindingFlags.NonPublic | BindingFlags.Instance); + if (method == null) + { + method = proxy.GetType().GetMethod("MarkerMethod"); + } + + Assert.IsNotNull(method); + + object[] attrs = method.GetCustomAttributes(false); + Assert.IsNotNull(attrs); + Assert.AreEqual(0, attrs.Length, "Should not have attribute applied to the target method."); + } + + [Test] + public void ProxyTargetMethodParameterAttributes() + { + MarkerClass target = new MarkerClass(); + + AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(IMarkerInterface) }); + advised.Target = target; + IAopProxy aopProxy = CreateAopProxy(advised); + + object proxy = aopProxy.GetProxy(); + Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to GetProxy() was null."); + + MethodInfo method = proxy.GetType().GetMethod("Spring.Aop.Framework.DynamicProxy.AbstractAopProxyTests+IMarkerInterface.MarkerMethod", BindingFlags.NonPublic | BindingFlags.Instance); + if (method == null) + { + method = proxy.GetType().GetMethod("MarkerMethod"); + } + + Assert.IsNotNull(method); + + object[] attrs = method.GetParameters()[1].GetCustomAttributes(false); + Assert.IsNotNull(attrs, "Should have had 1 attribute applied to the method's parameter."); + Assert.AreEqual(1, attrs.Length, "Should have had 1 attribute applied to the method's parameter."); + Assert.AreEqual(typeof(MarkerAttribute), attrs[0].GetType(), "Wrong System.Type of Attribute applied to the method's parameter."); + } + + [Test] + public void DoesNotProxyTargetMethodParameterAttributesWithProxyTargetAttributesEqualsFalse() + { + MarkerClass target = new MarkerClass(); + + AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(IMarkerInterface) }); + advised.Target = target; + advised.ProxyTargetAttributes = false; + IAopProxy aopProxy = CreateAopProxy(advised); + + object proxy = aopProxy.GetProxy(); + Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to GetProxy() was null."); + + MethodInfo method = proxy.GetType().GetMethod("Spring.Aop.Framework.DynamicProxy.AbstractAopProxyTests+IMarkerInterface.MarkerMethod", BindingFlags.NonPublic | BindingFlags.Instance); + if (method == null) + { + method = proxy.GetType().GetMethod("MarkerMethod"); + } + + Assert.IsNotNull(method); + + object[] attrs = method.GetParameters()[1].GetCustomAttributes(false); + Assert.IsNotNull(attrs); + Assert.AreEqual(0, attrs.Length, "Should not have attribute applied to the method's parameter."); + } + + [Test] + public void ProxyTargetMethodReturnValueAttributes() + { + MarkerClass target = new MarkerClass(); + + AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(IMarkerInterface) }); + advised.Target = target; + IAopProxy aopProxy = CreateAopProxy(advised); + + object proxy = aopProxy.GetProxy(); + Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to GetProxy() was null."); + + MethodInfo method = proxy.GetType().GetMethod("Spring.Aop.Framework.DynamicProxy.AbstractAopProxyTests+IMarkerInterface.MarkerMethod", BindingFlags.NonPublic | BindingFlags.Instance); + if (method == null) + { + method = proxy.GetType().GetMethod("MarkerMethod"); + } + + Assert.IsNotNull(method); + + object[] attrs = method.ReturnTypeCustomAttributes.GetCustomAttributes(false); + Assert.IsNotNull(attrs, "Should have had 1 attribute applied to the method's return value."); + Assert.AreEqual(1, attrs.Length, "Should have had 1 attribute applied to the method's return value."); + Assert.AreEqual(typeof(MarkerAttribute), attrs[0].GetType(), "Wrong System.Type of Attribute applied to the method's return value."); + } + + [Test] + public void DoesNotProxyTargetMethodReturnValueAttributesWithProxyTargetAttributesEqualsFalse() + { + MarkerClass target = new MarkerClass(); + + AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(IMarkerInterface) }); + advised.Target = target; + advised.ProxyTargetAttributes = false; + IAopProxy aopProxy = CreateAopProxy(advised); + + object proxy = aopProxy.GetProxy(); + Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to GetProxy() was null."); + + MethodInfo method = proxy.GetType().GetMethod("Spring.Aop.Framework.DynamicProxy.AbstractAopProxyTests+IMarkerInterface.MarkerMethod", BindingFlags.NonPublic | BindingFlags.Instance); + if (method == null) + { + method = proxy.GetType().GetMethod("MarkerMethod"); + } + + Assert.IsNotNull(method); + + object[] attrs = method.ReturnTypeCustomAttributes.GetCustomAttributes(false); + Assert.IsNotNull(attrs); + Assert.AreEqual(0, attrs.Length, "Should not have attribute applied to the method's return value."); + } + + public sealed class MarkerAttribute : Attribute + { + } + + public interface IMarkerInterface + { + void MarkerMethod(int param1, string param2); + } + + [Marker] + public class MarkerClass : IMarkerInterface + { + [Marker] + [return: Marker] + public void MarkerMethod(int param1, [Marker] string param2) + { + } + + [Marker] + [return: Marker] + public virtual void MarkerVirtualMethod(int param1, [Marker] string param2) + { + } + } + + [Test] + public void AddAdviceAtRuntime() + { + TestObject target = new TestObject(); + CountingBeforeAdvice cba = new CountingBeforeAdvice(); + + ProxyFactory pf = new ProxyFactory(target); + ITestObject proxy = (ITestObject) CreateProxy(pf); + + proxy.Age.ToString(); + Assert.AreEqual(0, cba.GetCalls()); + ((IAdvised) proxy).AddAdvice(cba); + proxy.Age.ToString(); + Assert.AreEqual(1, cba.GetCalls()); + } + + [Test] + public void SerializationAdviceAndTargetNotSerializable() + { + TestObject to = new TestObject(); + Assert.IsFalse(SerializationTestUtils.IsSerializable(to)); + + ProxyFactory pf = new ProxyFactory(to); + + pf.AddAdvice(new NopInterceptor()); + ITestObject proxy = (ITestObject) CreateAopProxy(pf).GetProxy(); + + Assert.IsFalse(SerializationTestUtils.IsSerializable(proxy)); + } + + [Test] + public void SerializationAdviceNotSerializable() + { + SerializablePerson sp = new SerializablePerson(); + Assert.IsTrue(SerializationTestUtils.IsSerializable(sp)); + + ProxyFactory pf = new ProxyFactory(sp); + + // This isn't serializable + IAdvice i = new NopInterceptor(); + pf.AddAdvice(i); + Assert.IsFalse(SerializationTestUtils.IsSerializable(i)); + Object proxy = CreateAopProxy(pf).GetProxy(); + + Assert.IsFalse(SerializationTestUtils.IsSerializable(proxy)); + } + + [Test] + public void SerializationSerializableTargetAndAdvice() + { + SerializablePerson personTarget = new SerializablePerson(); + personTarget.Name = "jim"; + personTarget.Age = 26; + + Assert.IsTrue(SerializationTestUtils.IsSerializable(personTarget)); + + ProxyFactory pf = new ProxyFactory(personTarget); + + CountingThrowsAdvice cta = new CountingThrowsAdvice(); + + pf.AddAdvice(new SerializableNopInterceptor()); + // Try various advice types + pf.AddAdvice(new CountingBeforeAdvice()); + pf.AddAdvice(new CountingAfterReturningAdvice()); + pf.AddAdvice(cta); + IPerson p = (IPerson) CreateAopProxy(pf).GetProxy(); + + p.Echo(null); + Assert.AreEqual(0, cta.GetCalls()); + try + { + p.Echo(new Exception()); + } + catch (Exception) + { + } + + Assert.AreEqual(1, cta.GetCalls()); + + // Will throw exception if it fails + IPerson p2 = (IPerson) SerializationTestUtils.SerializeAndDeserialize(p); + Assert.AreNotSame(p, p2); + Assert.AreEqual(p.GetName(), p2.GetName()); + Assert.AreEqual(p.GetAge(), p2.GetAge()); + Assert.IsTrue(AopUtils.IsAopProxy(p2), "Deserialized object is an AOP proxy"); + + IAdvised a1 = (IAdvised) p; + IAdvised a2 = (IAdvised) p2; + // Check we can manipulate state of p2 + Assert.AreEqual(a1.Advisors.Count, a2.Advisors.Count); + + // This should work as SerializablePerson is equal + Assert.AreEqual(p, p2, "Proxies should be equal, even after one was serialized"); + + // Check we can add a new advisor to the target + NopInterceptor ni = new NopInterceptor(); + p2.GetAge(); + Assert.AreEqual(0, ni.Count); + a2.AddAdvice(ni); + p2.GetAge(); + Assert.AreEqual(1, ni.Count); + + cta = (CountingThrowsAdvice) a2.Advisors[3].Advice; + p2.Echo(null); + Assert.AreEqual(1, cta.GetCalls()); + try + { + p2.Echo(new Exception()); + } + catch (Exception) + { + } + + Assert.AreEqual(2, cta.GetCalls()); + } + + /// + /// Check that the two MethodInvocations necessary are independent + /// and don't conflict. + /// + [Test] + public void OneAdvisedObjectCallsAnother() + { + int age1 = 33; + int age2 = 37; + + TestObject target1 = new TestObject(); + ProxyFactory pf1 = new ProxyFactory(target1); + // Permit proxy and invocation checkers to get context from AopContext + pf1.ExposeProxy = true; + NopInterceptor di1 = new NopInterceptor(); + pf1.AddAdvice(0, di1); + pf1.AddAdvice(1, new ProxyMatcherInterceptor()); + pf1.AddAdvice(2, new MethodInvocationMatcherInterceptor()); + ITestObject advised1 = (ITestObject) pf1.GetProxy(); + advised1.Age = age1; // = 1 invocation + + TestObject target2 = new TestObject(); + ProxyFactory pf2 = new ProxyFactory(target2); + pf2.ExposeProxy = true; + NopInterceptor di2 = new NopInterceptor(); + pf2.AddAdvice(0, di2); + pf2.AddAdvice(1, new ProxyMatcherInterceptor()); + pf2.AddAdvice(2, new MethodInvocationMatcherInterceptor()); + ITestObject advised2 = (ITestObject) CreateProxy(pf2); + advised2.Age = age2; + advised1.Spouse = advised2; // = 2 invocations + + Assert.AreEqual(age1, advised1.Age, "Advised one has correct age"); // = 3 invocations + Assert.AreEqual(age2, advised2.Age, "Advised two has correct age"); + // Means extra call on advised 2 + Assert.AreEqual(age2, advised1.Spouse.Age, "Advised one spouse has correct age"); // = 4 invocations on 1 and another one on 2 + Assert.AreEqual(4, di1.Count, "one was invoked correct number of times"); + // Got hit by call to advised1.getSpouse().Age + Assert.AreEqual(3, di2.Count, "one was invoked correct number of times"); + } + + private class MethodInvocationMatcherInterceptor : IMethodInterceptor + { + public object Invoke(IMethodInvocation invocation) + { + MethodInfo m = invocation.Method; + Object retval = invocation.Proceed(); + Assert.AreEqual(m, invocation.Method, "Method invocation should have same method on way back"); + return retval; + } + } + + private class ProxyMatcherInterceptor : IMethodInterceptor + { + public object Invoke(IMethodInvocation invocation) + { + Object proxy = AopContext.CurrentProxy; + Object ret = invocation.Proceed(); + Assert.IsTrue(proxy == AopContext.CurrentProxy, "Proxy should be the same on way back"); + return ret; + } + } + + [Test] + public void Reentrance() + { + int age1 = 33; + + TestObject target1 = new TestObject(); + ProxyFactory pf1 = new ProxyFactory(target1); + NopInterceptor di1 = new NopInterceptor(); + pf1.AddAdvice(0, di1); + ITestObject advised1 = (ITestObject) CreateProxy(pf1); + + advised1.Age = age1; // = 1 invocation + advised1.Spouse = advised1; // = 2 invocations + + Assert.AreEqual(2, di1.Count, "one was invoked correct number of times"); + + Assert.AreEqual(age1, advised1.Age, "Advised one has correct age"); // = 3 invocations + Assert.AreEqual(3, di1.Count, "one was invoked correct number of times"); + + // = 5 invocations, as reentrant call to spouse is advised also + Assert.AreEqual(age1, advised1.Spouse.Age, "Advised spouse has correct age"); + + Assert.AreEqual(5, di1.Count, "one was invoked correct number of times"); + } + + [Test] + public void TargetCanGetProxy() + { + NopInterceptor di = new NopInterceptor(); + INeedsToSeeProxy target = new TargetChecker(); + ProxyFactory proxyFactory = new ProxyFactory(target); + proxyFactory.ExposeProxy = true; + Assert.IsTrue(proxyFactory.ExposeProxy); + + proxyFactory.AddAdvice(0, di); + INeedsToSeeProxy proxied = (INeedsToSeeProxy) CreateProxy(proxyFactory); + + Assert.AreEqual(0, di.Count); + Assert.AreEqual(0, target.Count); + proxied.IncrementViaThis(); + Assert.AreEqual(1, target.Count, "Increment happened"); + + Assert.AreEqual(1, di.Count, "Only one invocation via AOP as use of this wasn't proxied"); + // 1 invocation + Assert.AreEqual(1, proxied.Count, "Increment happened"); + proxied.IncrementViaProxy(); // 2 invoocations + Assert.AreEqual(2, target.Count, "Increment happened"); + Assert.AreEqual(4, di.Count, "3 more invocations via AOP as the first call was reentrant through the proxy"); + } + + /// + /// Check that although a method is eligible for advice chain optimization and + /// direct reflective invocation, it doesn't happen if we've asked to see the proxy, + /// so as to guarantee a consistent programming model. + /// + [Test] + public void TargetCanGetProxyEvenIfNoAdviceChain() + { + NeedsToSeeProxy target = new NeedsToSeeProxy(); + AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(INeedsToSeeProxy) }); + advised.Target = target; + advised.ExposeProxy = true; + + // Now let's try it with the special target + IAopProxy aop = CreateAopProxy(advised); + INeedsToSeeProxy proxied = (INeedsToSeeProxy) aop.GetProxy(); + + // It will complain if it can't get the proxy + proxied.IncrementViaProxy(); + } + + [Test] + public void TargetCantGetProxyByDefault() + { + NeedsToSeeProxy et = new NeedsToSeeProxy(); + ProxyFactory pf1 = new ProxyFactory(et); + Assert.IsFalse(pf1.ExposeProxy); + INeedsToSeeProxy proxied = (INeedsToSeeProxy) CreateProxy(pf1); + Assert.Throws(() => proxied.IncrementViaProxy()); + } + + [Test(Description = "Test that the proxy returns itself when the target returns 'this'.")] + public void TargetReturnsThis() + { + // Test return value + TestObject raw = new OwnSpouse(); + + AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(ITestObject) }); + advised.Target = raw; + + ITestObject to = (ITestObject) CreateProxy(advised); + Assert.IsTrue(to.Spouse == to, "this return is wrapped in proxy"); + } + + public class OwnSpouse : TestObject + { + public override ITestObject Spouse + { + get { return this; } + } + } + + [Test] + public void TargetThrowsException() + { + Exception expectedException = new ApplicationException(); + + // Test return value + AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(ITestObject) }); + advised.Target = new TestObject(); + IAopProxy aop = CreateAopProxy(advised); + + try + { + ITestObject to = (ITestObject) aop.GetProxy(); + to.Exceptional(expectedException); + Assert.Fail("Should have thrown exception raised by target"); + } + catch (Exception ex) + { + Assert.AreEqual(expectedException, ex, "exception matches"); + } + } + + [Test] + public void InterceptorThrowsException() + { + Exception expectedException = new ApplicationException(); + + IMethodInterceptor mi = new ThrowExceptionInterceptor(expectedException); + + AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(ITestObject) }); + advised.Target = new TestObject(); + advised.AddAdvice(mi); + IAopProxy aop = CreateAopProxy(advised); + + try + { + ITestObject to = (ITestObject) aop.GetProxy(); + to.Name = "Bruno"; + Assert.Fail("Should have thrown exception raised by interceptor"); + } + catch (Exception ex) + { + Assert.AreEqual(expectedException, ex, "exception matches"); + } + } + + private class ThrowExceptionInterceptor : IMethodInterceptor + { + private Exception _exception; + + public ThrowExceptionInterceptor(Exception ex) + { + _exception = ex; + } + + public object Invoke(IMethodInvocation invocation) + { + throw _exception; + } + } + + // TODO : Introduction tests + /* + [Test(Description = "Test stateful interceptor")] + public void MixinWithIntroductionAdvisor() + { + TestObject to = new TestObject(); + AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(ITestObject) }); + advised.AddAdvisor(new LockMixinAdvisor()); + advised.Target = to; + + CheckTestObjectIntroduction(advised); + } + + [Test] + public void MixinWithIntroductionInfo() + { + TestObject to = new TestObject(); + AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(ITestObject) }); + advised.AddAdvice(new LockMixin()); + advised.Target = to; + + CheckTestObjectIntroduction(advised); + } + + private void CheckTestObjectIntroduction(AdvisedSupport advised) + { + int newAge = 65; + + ITestObject ito = (ITestObject) CreateProxy(advised); + ito.Age = newAge; + Assert.IsTrue(ito.Age == newAge); + + ILockable lockable = (ILockable) ito; + Assert.IsFalse(lockable.Locked()); + lockable.DoLock(); + + Assert.IsTrue(ito.Age == newAge); + try + { + ito.Age = 1; + Assert.Fail("Setters should fail when locked"); + } + catch (LockedException) + { + // ok + } + Assert.IsTrue(ito.Age == newAge); + + // Unlock + Assert.IsTrue(lockable.Locked()); + lockable.Unlock(); + ito.Age = 1; + Assert.IsTrue(ito.Age == 1); + } + */ + + [Test] + public void MultipleProceedCalls() + { + TestObject to = new TestObject(); + AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(ITestObject) }); + advised.Target = to; + advised.AddAdvice(new RetryAdvice()); + NopInterceptor ni = new NopInterceptor(); + advised.AddAdvice(ni); + + ITestObject ito = (ITestObject) CreateProxy(advised); + ito.Age = 27; + + Assert.AreEqual(2, ni.Count); + } + + public class RetryAdvice : IMethodInterceptor + { + public object Invoke(IMethodInvocation invocation) + { + invocation.Proceed(); + return invocation.Proceed(); + } + } + + [Test] + public void ReplaceArgument() + { + TestObject to = new TestObject(); + AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(ITestObject) }); + advised.Target = to; + advised.AddAdvisor(new StringSetterNullReplacementAdvisor(new StringSetterNullReplacementAdvice())); + + ITestObject ito = (ITestObject) CreateProxy(advised); + int newAge = 5; + ito.Age = newAge; + Assert.IsTrue(ito.Age == newAge); + String newName = "greg"; + ito.Name = newName; + Assert.AreEqual(newName, ito.Name); + + ito.Name = null; + + // Null replacement magic should work + Assert.IsTrue(ito.Name.Equals("")); + } + + [Test] + public void ReplaceArgumentDescendingPropagation() + { + TestObject to = new TestObject(); + AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(ITestObject) }); + advised.Target = to; + advised.AddAdvisor(new StringSetterNullReplacementAdvisor(new StringSetterNullReplacementAdvice())); + NopInterceptor ni = new NopInterceptor(); + advised.AddAdvisor(new StringSetterNullReplacementAdvisor(ni)); + + ITestObject ito = (ITestObject) CreateProxy(advised); + int newAge = 5; + ito.Age = newAge; + Assert.IsTrue(ito.Age == newAge); + String newName = "greg"; + ito.Name = newName; + Assert.AreEqual(newName, ito.Name); + + ito.Name = null; + + // Null replacement magic should work + Assert.IsTrue(ito.Name.Equals("")); + + // StringSetterNullReplacementAdvisor should not be fire twice + Assert.AreEqual(0, ni.Count); + } + + [Test] + public void ReplaceArgumentAscendingPropagation() + { + TestObject to = new TestObject(); + AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(ITestObject) }); + advised.Target = to; + advised.AddAdvice(new CheckArgumentsAfterProceedAdvice()); + advised.AddAdvisor(new StringSetterNullReplacementAdvisor(new StringSetterNullReplacementAdvice())); + + ITestObject ito = (ITestObject) CreateProxy(advised); + ito.Name = null; + } + + /// + /// Fires on setter methods that take a string. + /// + public class StringSetterNullReplacementAdvisor : DynamicMethodMatcherPointcutAdvisor + { + public StringSetterNullReplacementAdvisor(IAdvice advice) + : base(advice) + { + } + + public override bool Matches(MethodInfo method, Type targetType, object[] args) + { + return (args[0] == null); + } + + public override bool Matches(MethodInfo method, Type targetType) + { + return method.Name.StartsWith("set_") && + method.GetParameters().Length == 1 && + method.GetParameters()[0].ParameterType == typeof(string); + } + } + + /// + /// Replaces null arg with "". + /// + public class StringSetterNullReplacementAdvice : IMethodInterceptor + { + public object Invoke(IMethodInvocation invocation) + { + // We know it can only be invoked if there's a single parameter of type string + invocation.Arguments[0] = ""; + return invocation.Proceed(); + } + } + + public class CheckArgumentsAfterProceedAdvice : IMethodInterceptor + { + public object Invoke(IMethodInvocation invocation) + { + object returnValue = invocation.Proceed(); + + // Null replacement magic should work + Assert.IsNotNull(invocation.Arguments[0]); + + return returnValue; + } + } + + /// + /// http://forum.springframework.net/showthread.php?t=504 + /// + [Test] + public void CanCastProxyToIAdvised() + { + TestObject to = new TestObject(); + AdvisedSupport advisedSupport = new AdvisedSupport(to); + NopInterceptor ni = new NopInterceptor(); + advisedSupport.AddAdvice(0, ni); + + ITestObject ito = (ITestObject) CreateProxy(advisedSupport); + Assert.AreEqual(0, ni.Count); + ito.Age = 23; + Assert.AreEqual(23, ito.Age); + Assert.AreEqual(2, ni.Count); + + IAdvised advised = (IAdvised) ito; + Assert.AreEqual(1, advised.Advisors.Count, "Have 1 advisor"); + Assert.AreEqual(ni, advised.Advisors[0].Advice); + NopInterceptor ni2 = new NopInterceptor(); + advised.AddAdvice(1, ni2); + ito.Name = "Bruno"; + Assert.AreEqual(3, ni.Count); + Assert.AreEqual(1, ni2.Count); + // will remove ni + advised.RemoveAdvisor(0); + Assert.IsNotNull(ito.Age); + // Unchanged + Assert.AreEqual(3, ni.Count); + Assert.AreEqual(2, ni2.Count); + + CountingBeforeAdvice cba = new CountingBeforeAdvice(); + Assert.AreEqual(0, cba.GetCalls()); + advised.AddAdvice(cba); + ito.Age = 16; + Assert.AreEqual(16, ito.Age); + Assert.AreEqual(2, cba.GetCalls()); + } + + [Test] + public void CannotAddInterceptorWhenFrozen() + { + TestObject target = new TestObject(); + target.Age = 21; + ProxyFactory pf = new ProxyFactory(target); + Assert.IsFalse(pf.IsFrozen); + pf.AddAdvice(new NopInterceptor()); + ITestObject proxied = (ITestObject) CreateProxy(pf); + pf.IsFrozen = true; + try + { + pf.AddAdvice(0, new NopInterceptor()); + Assert.Fail("Shouldn't be able to add interceptor when frozen"); + } + catch (AopConfigException ex) + { + Assert.IsTrue(ex.Message.IndexOf("frozen") > -1); + } + + // Check it still works: proxy factory state shouldn't have been corrupted + Assert.AreEqual(target.Age, proxied.Age); + Assert.AreEqual(1, ((IAdvised) proxied).Advisors.Count); + } + + [Test(Description = "Check that casting to Advised can't get around advice freeze.")] + public void CannotAddAdvisorWhenFrozenUsingCast() + { + TestObject target = new TestObject(); + target.Age = 21; + ProxyFactory pf = new ProxyFactory(target); + Assert.IsFalse(pf.IsFrozen); + pf.AddAdvice(new NopInterceptor()); + ITestObject proxied = (ITestObject) CreateProxy(pf); + pf.IsFrozen = true; + IAdvised advised = (IAdvised) proxied; + + Assert.IsTrue(pf.IsFrozen); + try + { + advised.AddAdvisor(new DefaultPointcutAdvisor(new NopInterceptor())); + Assert.Fail("Shouldn't be able to add Advisor when frozen"); + } + catch (AopConfigException ex) + { + Assert.IsTrue(ex.Message.IndexOf("frozen") > -1); + } + + // Check it still works: proxy factory state shouldn't have been corrupted + Assert.AreEqual(target.Age, proxied.Age); + Assert.AreEqual(1, advised.Advisors.Count); + } + + [Test] + public void CannotRemoveAdvisorWhenFrozen() + { + TestObject target = new TestObject(); + target.Age = 21; + ProxyFactory pf = new ProxyFactory(target); + Assert.IsFalse(pf.IsFrozen); + pf.AddAdvice(new NopInterceptor()); + ITestObject proxied = (ITestObject) CreateProxy(pf); + pf.IsFrozen = true; + IAdvised advised = (IAdvised) proxied; + + Assert.IsTrue(pf.IsFrozen); + try + { + advised.RemoveAdvisor(0); + Assert.Fail("Shouldn't be able to remove Advisor when frozen"); + } + catch (AopConfigException ex) + { + Assert.IsTrue(ex.Message.IndexOf("frozen") > -1); + } + + // Didn't get removed + Assert.AreEqual(1, advised.Advisors.Count); + pf.IsFrozen = false; + // Can now remove it + advised.RemoveAdvisor(0); + // Check it still works: proxy factory state shouldn't have been corrupted + Assert.AreEqual(target.Age, proxied.Age); + Assert.AreEqual(0, advised.Advisors.Count); + } + + [Test(Description = "Check that the string is informative.")] + public void ProxyConfigString() + { + TestObject target = new TestObject(); + ProxyFactory pf = new ProxyFactory(target); + pf.Interfaces = new Type[] { typeof(ITestObject) }; + pf.AddAdvice(new NopInterceptor()); + IMethodBeforeAdvice mba = new CountingBeforeAdvice(); + IAdvisor advisor = new DefaultPointcutAdvisor(new NameMatchMethodPointcut(), mba); + pf.AddAdvisor(advisor); + ITestObject proxied = (ITestObject) CreateProxy(pf); + + String proxyConfigString = ((IAdvised) proxied).ToProxyConfigString(); + Assert.IsTrue(proxyConfigString.IndexOf(advisor.ToString()) != -1); + Assert.IsTrue(proxyConfigString.IndexOf("1 interface") != -1); + } + + // TODO : Opaque can be implemented if really usefull (To increase performance) + /* + public void testCanPreventCastToAdvisedUsingOpaque() + { + TestObject target = new TestObject(); + ProxyFactory pf = new ProxyFactory(target); + pf.Interfaces = new Type[] { typeof(ITestObject) }; + pf.AddAdvice(new NopInterceptor()); + CountingBeforeAdvice mba = new CountingBeforeAdvice(); + NameMatchMethodPointcut nmmp = new NameMatchMethodPointcut(); + nmmp.MappedName = "set_Age"; + IAdvisor advisor = new DefaultPointcutAdvisor(nmmp, mba); + pf.AddAdvisor(advisor); + Assert.IsFalse(pf.Opaque, "Opaque defaults to false"); + pf.Opaque = true; + Assert.IsTrue(pf.Opaque, "Opaque now true for this config"); + ITestObject proxied = (ITestObject) CreateProxy(pf); + proxied.Age = 10; + Assert.AreEqual(10, proxied.Age); + Assert.AreEqual(1, mba.GetCalls()); + + Assert.IsFalse(proxied is IAdvised, "Cannot be cast to Advised", ); + } + */ + + // TODO AdviceSupportListeners test + /* + [Test] + public void AdviceSupportListeners() + { + TestObject target = new TestObject(); + target.Age = 21; + + ProxyFactory pf = new ProxyFactory(target); + CountingAdvisorListener l = new CountingAdvisorListener(pc); + pf.AddListener(l); + RefreshCountingAdvisorChainFactory acf = new RefreshCountingAdvisorChainFactory(); + // Should be automatically added as a listener + pf.AdvisorChainFactory(acf); + Assert.IsFalse(pf.isActive()); + Assert.AreEqual(0, l.activates); + Assert.AreEqual(0, acf.refreshes); + ITestObject proxied = (ITestObject)CreateProxy(pf); + Assert.AreEqual(1, acf.refreshes); + Assert.AreEqual(1, l.activates); + Assert.IsTrue(pc.isActive()); + Assert.AreEqual(target.Age, proxied.Age); + Assert.AreEqual(0, l.adviceChanges); + NopInterceptor ni = new NopInterceptor(); + pf.addAdvice(0, ni); + Assert.AreEqual(1, l.adviceChanges); + Assert.AreEqual(2, acf.refreshes); + Assert.AreEqual(target.Age, proxied.Age); + pf.removeAdvice(ni); + Assert.AreEqual(2, l.adviceChanges); + Assert.AreEqual(3, acf.refreshes); + Assert.AreEqual(target.Age, proxied.Age); + pf.getProxy(); + Assert.AreEqual(1, l.activates); + + pf.RemoveListener(l); + Assert.AreEqual(2, l.adviceChanges); + pf.AddAdvisor(new DefaultPointcutAdvisor(new NopInterceptor())); + // No longer counting + Assert.AreEqual(2, l.adviceChanges); + } + + public class CountingAdvisorListener : IAdvisedSupportListener + { + public int adviceChanges; + public int activates; + private AdvisedSupport expectedSource; + + public CountingAdvisorListener(AdvisedSupport expectedSource) + { + this.expectedSource = expectedSource; + } + + public void AdviceChanged(AdvisedSupport source) + { + Assert.AreEqual(expectedSource, source); + ++adviceChanges; + } + + public void Activated(AdvisedSupport source) + { + Assert.AreEqual(expectedSource,source); + ++activates; + } + } + + public class RefreshCountingAdvisorChainFactory : IAdvisorChainFactory + { + public int refreshes; + + public void AdviceChanged(AdvisedSupport source) + { + ++refreshes; + } + + public IList GetInterceptors(IAdvised advised, object proxy, string methodId, MethodInfo method, Type targetType) + { + return AdvisorChainFactoryUtils.CalculateInterceptors(advised, proxy, method, targetType); + } + + public void Activated(AdvisedSupport source) + { + ++refreshes; + } + } +*/ + + [Test] + public void DynamicMethodPointcutThatAlwaysAppliesStatically() + { + TestObject to = new TestObject(); + ProxyFactory pf = new ProxyFactory(new Type[] { typeof(ITestObject) }); + TestDynamicPointcutAdvisor dp = new TestDynamicPointcutAdvisor(new NopInterceptor(), "get_Age"); + pf.AddAdvisor(dp); + pf.Target = to; + ITestObject it = (ITestObject) CreateProxy(pf); + Assert.AreEqual(dp.count, 0); + int age = it.Age; + Assert.IsNotNull(age); // avoid mono mcs CS0218 + Assert.AreEqual(dp.count, 1); + it.Age = 11; + Assert.AreEqual(it.Age, 11); + Assert.AreEqual(dp.count, 2); + } + + [Test] + public void DynamicMethodPointcutThatAppliesStaticallyOnlyToSetters() + { + TestObject to = new TestObject(); + ProxyFactory pf = new ProxyFactory(new Type[] { typeof(ITestObject) }); + // Could apply dynamically to property Age but not to property Name + ForSettersOnlyPointcutAdvisor dp = new ForSettersOnlyPointcutAdvisor(new NopInterceptor(), "Age"); + pf.AddAdvisor(dp); + this.mockTargetSource.SetTarget(to); + pf.TargetSource = mockTargetSource; + ITestObject it = (ITestObject) CreateProxy(pf); + Assert.AreEqual(dp.count, 0); + int age = it.Age; + Assert.IsNotNull(age); // avoid mono mcs error CS0219 + // Statically vetoed + Assert.AreEqual(0, dp.count); + it.Age = 11; + Assert.AreEqual(it.Age, 11); + Assert.AreEqual(dp.count, 1); + // Applies statically but not dynamically + it.Name = "joe"; + Assert.AreEqual(dp.count, 1); + } + + private class TestDynamicPointcutAdvisor : DynamicMethodMatcherPointcutAdvisor + { + private string pattern; + public int count = 0; + + public TestDynamicPointcutAdvisor(IAdvice advice, string pattern) + : + base(advice) + { + this.pattern = pattern; + } + + public override bool Matches(MethodInfo method, Type targetType, object[] args) + { + bool run = method.Name.IndexOf(pattern) != -1; + if (run) ++count; + return run; + } + } + + private class ForSettersOnlyPointcutAdvisor : TestDynamicPointcutAdvisor + { + public ForSettersOnlyPointcutAdvisor(IAdvice advice, string pattern) + : + base(advice, pattern) + { + } + + public override bool Matches(MethodInfo method, Type targetType) + { + return method.Name.StartsWith("set_"); + } + } + + [Test] + public void StaticMethodPointcut() + { + TestObject to = new TestObject(); + ProxyFactory pf = new ProxyFactory(new Type[] { typeof(ITestObject) }); + NopInterceptor ni = new NopInterceptor(); + TestStaticPointcutAdvisor sp = new TestStaticPointcutAdvisor(ni, "get_Age"); + pf.AddAdvisor(sp); + pf.Target = to; + ITestObject it = (ITestObject) CreateProxy(pf); + Assert.AreEqual(ni.Count, 0); + int age = it.Age; + Assert.IsNotNull(age); // avoid mono mcs error CS0219 + Assert.AreEqual(ni.Count, 1); + it.Age = 11; + Assert.AreEqual(it.Age, 11); + Assert.AreEqual(ni.Count, 2); + } + + private class TestStaticPointcutAdvisor : StaticMethodMatcherPointcutAdvisor + { + private string pattern; + private int count; + + public TestStaticPointcutAdvisor(IAdvice advice, String pattern) + : + base(advice) + { + this.pattern = pattern; + } + + public override bool Matches(MethodInfo method, Type targetType) + { + bool run = method.Name.IndexOf(pattern) != -1; + if (run) ++count; + return run; + } + } + + // TODO ? ReflectiveMethodInvocation is not Cloneable + /* + [Test(Description="There are times when we want to call proceed() twice.")] + public void CloneInvocationToProceedThreeTimes() + { + //We can do this if we clone the invocation. + + TestObject to = new TestObject(); + ProxyFactory pf = new ProxyFactory(to); + pf.AddInterface(typeof(ITestObject)); + + TwoBirthdayAdvice twoBirthdayAdvice = new TwoBirthdayAdvice(); + + TwoBirthdayPointcutAdvisor sp = new TwoBirthdayPointcutAdvisor(twoBirthdayAdvice); + pf.AddAdvisor(sp); + ITestObject ito = (ITestObject)CreateProxy(pf); + + int age = 20; + ito.Age = age; + Assert.AreEqual(age, ito.Age); + // Should return the age before the third, AOP-induced birthday + Assert.AreEqual(age + 2, ito.haveBirthday()); + // Return the final age produced by 3 birthdays + Assert.AreEqual(age + 3, ito.Age); + } + + private class TwoBirthdayPointcutAdvisor : StaticMethodMatcherPointcutAdvisor + { + public TwoBirthdayPointcutAdvisor(IAdvice advice) + : base(advice) + { + } + + public override bool Matches(MethodInfo method, Type targetType) + { + return "haveBirthday".Equals(method.Name); + } + } + + private class TwoBirthdayAdvice : IMethodInterceptor + { + public object Invoke(IMethodInvocation invocation) + { + // Clone the invocation to proceed three times + // "The Moor's Last Sigh": this technology can cause premature aging + IMethodInvocation clone1 = ((ReflectiveMethodInvocation)invocation).InvocableClone(); + IMethodInvocation clone2 = ((ReflectiveMethodInvocation)invocation).InvocableClone(); + clone1.Proceed(); + clone2.Proceed(); + return invocation.Proceed(); + } + } + + // // We want to change the arguments on a clone: it shouldn't affect the original. + // public void testCanChangeArgumentsIndependentlyOnClonedInvocation() throws Throwable + // { + // TestObject to = new TestObject(); + // ProxyFactory pc = new ProxyFactory(to); + // pc.addInterface(typeof(ITestObject)); + + // // Changes the name, then changes it back. + // MethodInterceptor nameReverter = new MethodInterceptor() { + // public Object invoke(MethodInvocation mi) throws Throwable { + // MethodInvocation clone = ((ReflectiveMethodInvocation) mi).invocableClone(); + // String oldName = ((ITestObject) mi.getThis()).Name; + // clone.getArguments()[0] = oldName; + // // Original method invocation should be unaffected by changes to argument list of clone + // mi.proceed(); + // return clone.proceed(); + // } + // }; + + // class NameSaver implements MethodInterceptor { + // private List names = new LinkedList(); + + // public Object invoke(MethodInvocation mi) throws Throwable { + // names.add(mi.getArguments()[0]); + // return mi.proceed(); + // } + // } + + // NameSaver saver = new NameSaver(); + + // pc.addAdvisor(new DefaultPointcutAdvisor(Pointcuts.SETTERS, nameReverter)); + // pc.addAdvisor(new DefaultPointcutAdvisor(Pointcuts.SETTERS, saver)); + // ITestObject it = (ITestObject) createProxy(pc); + + // String name1 = "tony"; + // String name2 = "gordon"; + + // to.setName(name1); + // Assert.AreEqual(name1, to.Name); + + // it.setName(name2); + // // NameReverter saved it back + // Assert.AreEqual(name1, it.Name); + // Assert.AreEqual(2, saver.names.size()); + // Assert.AreEqual(name2, saver.names.get(0)); + // Assert.AreEqual(name1, saver.names.get(1)); + // } + */ + + [Test] + public void OverloadedMethodsWithDifferentAdvice() + { + Overloads target = new Overloads(); + ProxyFactory pf = new ProxyFactory(target); + NopInterceptor overloadVoid = new NopInterceptor(); + pf.AddAdvisor(new OverloadVoidPointcutAdvisor(overloadVoid)); + NopInterceptor overloadInt = new NopInterceptor(); + pf.AddAdvisor(new OverloadIntPointcutAdvisor(overloadInt)); + + IOverloads proxy = (IOverloads) CreateProxy(pf); + + Assert.AreEqual(0, overloadInt.Count); + Assert.AreEqual(0, overloadVoid.Count); + proxy.Overload(); + Assert.AreEqual(0, overloadInt.Count); + Assert.AreEqual(1, overloadVoid.Count); + Assert.AreEqual(25, proxy.Overload(25)); + Assert.AreEqual(1, overloadInt.Count); + Assert.AreEqual(1, overloadVoid.Count); + proxy.NoAdvice(); + Assert.AreEqual(1, overloadInt.Count); + Assert.AreEqual(1, overloadVoid.Count); + } + + public interface IOverloads + { + void Overload(); + int Overload(int i); + string Overload(string foo); + void NoAdvice(); + } + + public class Overloads : IOverloads + { + public void Overload() + { + } + + public int Overload(int i) + { + return i; + } + + public string Overload(string foo) + { + return foo; + } + + public void NoAdvice() + { + } + } + + private class OverloadVoidPointcutAdvisor : StaticMethodMatcherPointcutAdvisor + { + public OverloadVoidPointcutAdvisor(IAdvice advice) + : base(advice) + { + } + + public override bool Matches(MethodInfo method, Type targetType) + { + return method.Name.Equals("Overload") && method.GetParameters().Length == 0; + } + } + + private class OverloadIntPointcutAdvisor : StaticMethodMatcherPointcutAdvisor + { + public OverloadIntPointcutAdvisor(IAdvice advice) + : base(advice) + { + } + + public override bool Matches(MethodInfo method, Type targetType) + { + return method.Name.Equals("Overload") && method.GetParameters().Length == 1 && + method.GetParameters()[0].ParameterType == typeof(int); + } + } + + // TODO : IAdvised.TargetSource is read only (no setter) + /* + [Test] + public void ExistingProxyChangesTarget() + { + TestObject to1 = new TestObject(); + to1.Age = 33; + + TestObject to2 = new TestObject(); + to2.Age = 26; + to2.Name = "Juergen"; + TestObject to3 = new TestObject(); + to3.Age = 37; + ProxyFactory pf = new ProxyFactory(to1); + NopInterceptor nop = new NopInterceptor(); + pf.AddAdvice(nop); + ITestObject proxy = (ITestObject)CreateProxy(pf); + Assert.AreEqual(nop.Count, 0); + Assert.AreEqual(to1.Age, proxy.Age); + Assert.AreEqual(nop.Count, 1); + // Change to a new static target + pf.Target = to2; + Assert.AreEqual(to2.Age, proxy.Age); + Assert.AreEqual(nop.Count, 2); + + // Change to a new dynamic target + HotSwappableTargetSource hts = new HotSwappableTargetSource(to3); + pf.TargetSource = hts; + Assert.AreEqual(to3.Age, proxy.Age); + Assert.AreEqual(nop.Count, 3); + hts.Swap(to1); + Assert.AreEqual(to1.Age, proxy.Age); + to1.Name = "Colin"; + Assert.AreEqual(to1.Name, proxy.Name); + Assert.AreEqual(nop.Count, 5); + + // Change back, relying on casting to Advised + IAdvised advised = (IAdvised)proxy; + Assert.AreSame(hts, advised.TargetSource); + SingletonTargetSource sts = new SingletonTargetSource(to2); + advised.TargetSource = sts; + Assert.AreEqual(to2.Name, proxy.Name); + Assert.AreSame(sts, advised.TargetSource); + Assert.AreEqual(to2.Age, proxy.Age); + } + + [Test] + public void ProxyIsBoundBeforeTargetSourceInvoked() + { + TestObject target = new TestObject(); + ProxyFactory pf = new ProxyFactory(target); + pf.AddAdvice(new DebugInterceptor()); + pf.ExposeProxy = true; + ITestObject proxy = (ITestObject) CreateProxy(pf); + IAdvised config = (IAdvised) proxy; + // This class just checks proxy is bound before getTarget() call + config.setTargetSource(new TargetSource() { + public Class getTargetClass() { + return TestObject.class; + } + + public boolean isStatic() { + return false; + } + + public Object getTarget() throws Exception { + Assert.AreEqual(proxy, AopContext.currentProxy()); + return target; + } + + public void releaseTarget(Object target) throws Exception { + } + }); + + // Just test anything: it will fail if context wasn't found + Assert.AreEqual(0, proxy.Age); + } + */ + + [Test] + public void BeforeAdvisorIsInvoked() + { + CountingBeforeAdvice cba = new CountingBeforeAdvice(); + IAdvisor matchesNoArgsAdvisor = new NoArgsMethodPointcutAdvisor(cba); + TestObject target = new TestObject(); + target.Age = 80; + ProxyFactory pf = new ProxyFactory(target); + pf.AddAdvice(new NopInterceptor()); + pf.AddAdvisor(matchesNoArgsAdvisor); + Assert.AreEqual(matchesNoArgsAdvisor, pf.Advisors[1], "Advisor was added"); + ITestObject proxied = (ITestObject) CreateProxy(pf); + Assert.AreEqual(0, cba.GetCalls()); + Assert.AreEqual(0, cba.GetCalls("get_Age")); + Assert.AreEqual(target.Age, proxied.Age); + Assert.AreEqual(1, cba.GetCalls()); + Assert.AreEqual(1, cba.GetCalls("get_Age")); + Assert.AreEqual(0, cba.GetCalls("set_Age")); + // Won't be advised + proxied.Age = 26; + Assert.AreEqual(1, cba.GetCalls()); + Assert.AreEqual(26, proxied.Age); + } + + private class NoArgsMethodPointcutAdvisor : StaticMethodMatcherPointcutAdvisor + { + public NoArgsMethodPointcutAdvisor(IAdvice advice) + : base(advice) + { + } + + public override bool Matches(MethodInfo method, Type targetType) + { + return method.GetParameters().Length == 0; + } + } + + // TODO : Multi advice not supported ? + + [Test] + [Ignore("Multi advice not supported for now.")] + public void MultiAdvice() + { + CountingMultiAdvice cma = new CountingMultiAdvice(); + IAdvisor matchesNoArgsAdvisor = new NoArgsOrNotExceptionalMethodPointcutAdvisor(cma); + TestObject target = new TestObject(); + target.Age = 80; + ProxyFactory pf = new ProxyFactory(target); + pf.AddAdvice(new NopInterceptor()); + pf.AddAdvisor(matchesNoArgsAdvisor); + Assert.AreEqual(matchesNoArgsAdvisor, pf.Advisors[1], "Advisor was added"); + ITestObject proxied = (ITestObject) CreateProxy(pf); + + Assert.AreEqual(0, cma.GetCalls()); + Assert.AreEqual(0, cma.GetCalls("get_Age")); + Assert.AreEqual(target.Age, proxied.Age); + Assert.AreEqual(2, cma.GetCalls()); + Assert.AreEqual(2, cma.GetCalls("get_Age")); + Assert.AreEqual(0, cma.GetCalls("set_Age")); + // Won't be advised + proxied.Age = 26; + Assert.AreEqual(2, cma.GetCalls()); + Assert.AreEqual(26, proxied.Age); + Assert.AreEqual(4, cma.GetCalls()); + try + { + proxied.Exceptional(new ApplicationException("foo")); + Assert.Fail("Should have thrown ApplicationException"); + } + catch (ApplicationException) + { + // expected + } + + Assert.AreEqual(6, cma.GetCalls()); + } + + private class NoArgsOrNotExceptionalMethodPointcutAdvisor : StaticMethodMatcherPointcutAdvisor + { + public NoArgsOrNotExceptionalMethodPointcutAdvisor(IAdvice advice) + : base(advice) + { + } + + public override bool Matches(MethodInfo method, Type targetType) + { + return method.GetParameters().Length == 0 || method.Name == "Exceptional"; + } + } + + [Test] + public void BeforeAdviceThrowsException() + { + ApplicationException aex = new ApplicationException(); + CountingBeforeNonSetterAdvice ba = new CountingBeforeNonSetterAdvice(aex); + + TestObject target = new TestObject(); + target.Age = 80; + NopInterceptor nop1 = new NopInterceptor(); + NopInterceptor nop2 = new NopInterceptor(2); + ProxyFactory pf = new ProxyFactory(target); + pf.AddAdvice(nop1); + pf.AddAdvice(ba); + pf.AddAdvice(nop2); + ITestObject proxied = (ITestObject) CreateProxy(pf); + // Won't throw an exception + Assert.AreEqual(target.Age, proxied.Age); + Assert.AreEqual(1, ba.GetCalls()); + Assert.AreEqual(1, ba.GetCalls("get_Age")); + Assert.AreEqual(1, nop1.Count); + Assert.AreEqual(1, nop2.Count); + // Will fail, after invoking Nop1 + try + { + proxied.Age = 26; + Assert.Fail("before advice should have ended chain"); + } + catch (ApplicationException ex) + { + Assert.AreEqual(aex, ex); + } + + Assert.AreEqual(2, ba.GetCalls()); + Assert.AreEqual(2, nop1.Count); + // Nop2 didn't get invoked when the exception was thrown + Assert.AreEqual(1, nop2.Count); + // Shouldn't have changed value in joinpoint + Assert.AreEqual(target.Age, proxied.Age); + } + + private class CountingBeforeNonSetterAdvice : CountingBeforeAdvice + { + private Exception _exception; + + public CountingBeforeNonSetterAdvice(Exception ex) + { + _exception = ex; + } + + public override void Before(MethodInfo method, object[] args, object target) + { + base.Before(method, args, target); + + if (method.Name.StartsWith("set_")) + throw _exception; + } + } + + [Test] + public void AfterReturningAdvisorIsInvoked() + { + SummingAfterAdvice aa = new SummingAfterAdvice(); + IAdvisor matchesIntAdvisor = new ReturnsIntPointcutAdvisor(aa); + TestObject target = new TestObject(); + ProxyFactory pf = new ProxyFactory(target); + pf.AddAdvice(new NopInterceptor()); + pf.AddAdvisor(matchesIntAdvisor); + Assert.AreEqual(matchesIntAdvisor, pf.Advisors[1], "Advisor was added"); + ITestObject proxied = (ITestObject) CreateProxy(pf); + Assert.AreEqual(0, aa.sum); + int i1 = 12; + int i2 = 13; + + // Won't be advised + proxied.Age = i1; + Assert.AreEqual(i1, proxied.Age); + Assert.AreEqual(i1, aa.sum); + proxied.Age = i2; + Assert.AreEqual(i2, proxied.Age); + Assert.AreEqual(i1 + i2, aa.sum); + Assert.AreEqual(i2, proxied.Age); + } + + private class SummingAfterAdvice : IAfterReturningAdvice + { + public int sum; + + public void AfterReturning(Object returnValue, MethodInfo method, Object[] args, Object target) + { + sum += ((int) returnValue); + } + } + + private class ReturnsIntPointcutAdvisor : StaticMethodMatcherPointcutAdvisor + { + public ReturnsIntPointcutAdvisor(IAdvice advice) + : base(advice) + { + } + + public override bool Matches(MethodInfo method, Type targetType) + { + return method.ReturnType == typeof(int); + } + } + + [Test] + public void AfterReturningAdvisorIsNotInvokedOnException() + { + CountingAfterReturningAdvice car = new CountingAfterReturningAdvice(); + TestObject target = new TestObject(); + ProxyFactory pf = new ProxyFactory(target); + pf.AddAdvice(new NopInterceptor()); + pf.AddAdvice(car); + Assert.AreEqual(car, pf.Advisors[1].Advice, "Advice was wrapped in Advisor and added"); + ITestObject proxied = (ITestObject) CreateProxy(pf); + Assert.AreEqual(0, car.GetCalls()); + int age = 10; + proxied.Age = age; + Assert.AreEqual(age, proxied.Age); + Assert.AreEqual(2, car.GetCalls()); + Exception ex = new Exception(); + // On exception it won't be invoked + try + { + proxied.Exceptional(ex); + Assert.Fail("Should have thrown Exception"); + } + catch (Exception caught) + { + Assert.AreSame(ex, caught); + } + + Assert.AreEqual(2, car.GetCalls()); + } + +#if !NETCOREAPP + [Test] + public void ThrowsAdvisorIsInvoked() + { + // Reacts to HttpException and RemotingException + var th = new Spring.Aop.Framework.Adapter.ThrowsAdviceInterceptorTests.MyThrowsHandler(); + IAdvisor matchesEchoAdvisor = new EchoPointcutAdvisor(th); + var target = new Spring.Aop.Framework.Adapter.ThrowsAdviceInterceptorTests.Echo(); + target.A = 16; + ProxyFactory pf = new ProxyFactory(target); + pf.AddAdvice(new NopInterceptor()); + pf.AddAdvisor(matchesEchoAdvisor); + Assert.AreEqual(matchesEchoAdvisor, pf.Advisors[1], "Advisor was added"); + var proxied = (Spring.Aop.Framework.Adapter.ThrowsAdviceInterceptorTests.IEcho) CreateProxy(pf); + Assert.AreEqual(0, th.GetCalls()); + Assert.AreEqual(target.A, proxied.A); + Assert.AreEqual(0, th.GetCalls()); + Exception ex = new Exception(); + // Will be advised but doesn't match + try + { + proxied.EchoException(1, ex); + Assert.Fail("Should have thrown Exception"); + } + catch (Exception caught) + { + Assert.AreEqual(ex, caught); + } + + ex = new System.Web.HttpException(); + try + { + proxied.EchoException(1, ex); + Assert.Fail("Should have thrown HttpException"); + } + catch (System.Web.HttpException caught) + { + Assert.AreEqual(ex, caught); + } + + Assert.AreEqual(1, th.GetCalls("HttpException")); + } +#endif + + private class EchoPointcutAdvisor : StaticMethodMatcherPointcutAdvisor + { + public EchoPointcutAdvisor(IAdvice advice) + : base(advice) + { + } + + public override bool Matches(MethodInfo method, Type targetType) + { + return method.Name.StartsWith("Echo"); + } + } + +#if !NETCOREAPP + [Test] + public void AddThrowsAdviceWithoutAdvisor() + { + // Reacts to ServletException and RemoteException + var th = new Spring.Aop.Framework.Adapter.ThrowsAdviceInterceptorTests.MyThrowsHandler(); + + var target = new Spring.Aop.Framework.Adapter.ThrowsAdviceInterceptorTests.Echo(); + target.A = 16; + ProxyFactory pf = new ProxyFactory(target); + pf.AddAdvice(new NopInterceptor()); + pf.AddAdvice(th); + var proxied = (Spring.Aop.Framework.Adapter.ThrowsAdviceInterceptorTests.IEcho) CreateProxy(pf); + Assert.AreEqual(0, th.GetCalls()); + Assert.AreEqual(target.A, proxied.A); + Assert.AreEqual(0, th.GetCalls()); + Exception ex = new Exception(); + // Will be advised but doesn't match + try + { + proxied.EchoException(1, ex); + Assert.Fail("Should have thrown Exception"); + } + catch (Exception caught) + { + Assert.AreEqual(ex, caught); + } + + // Subclass of RemoteException + ex = new System.Runtime.Remoting.RemotingTimeoutException(); + try + { + proxied.EchoException(1, ex); + Assert.Fail("Should have thrown RemotingTimeoutException"); + } + catch (System.Runtime.Remoting.RemotingTimeoutException caught) + { + Assert.AreEqual(ex, caught); + } + + Assert.AreEqual(1, th.GetCalls("RemotingException")); + } +#endif + + [Test] + public void ArgumentsModification() + { + } + + public interface ITargetClass + { + string TargetMethod(string arg); + } + + public class TargetClass : ITargetClass + { + public string TargetMethod(string arg) + { + if (arg == null) + { + throw new ArgumentException(); + } + + return arg; + } + } + + public class Interceptor1 : IMethodInterceptor + { + public object Invoke(IMethodInvocation invocation) + { + invocation.Proceed(); + + return invocation.Arguments[0]; + } + } + + public class Interceptor2 : IMethodInterceptor + { + public object Invoke(IMethodInvocation invocation) + { + invocation.Arguments[0] = null; + + return invocation.Proceed(); + } + } + + public interface INeedsToSeeProxy + { + int Count { get; } + + void IncrementViaThis(); + + void IncrementViaProxy(); + + void Increment(); + } + + public class NeedsToSeeProxy : INeedsToSeeProxy + { + private int _count; + + public int Count + { + get { return _count; } + } + + public void IncrementViaThis() + { + this.Increment(); + } + + public void IncrementViaProxy() + { + INeedsToSeeProxy thisViaProxy = (INeedsToSeeProxy) AopContext.CurrentProxy; + thisViaProxy.Increment(); + IAdvised advised = (IAdvised) thisViaProxy; + CheckAdvised(advised); + } + + protected virtual void CheckAdvised(IAdvised advised) + { + } + + public void Increment() + { + ++_count; + } + } + + public class TargetChecker : NeedsToSeeProxy + { + protected override void CheckAdvised(IAdvised advised) + { + // TODO replace this check: no longer possible + //Assert.AreEqual(advised.getTarget(), this); + } + } + + public class DynamicTargetSource : ITargetSource + { + private object target; + private Type targetType; + + public DynamicTargetSource(Type targetType, object target) + { + this.targetType = targetType; + this.target = target; + } + + public object Target + { + get { return target; } + set { target = value; } + } + + public Type TargetType + { + get { return targetType; } + set { targetType = value; } + } + + public bool IsStatic + { + get { return false; } + } + + public virtual object GetTarget() + { + return target; + } + + public void ReleaseTarget(object target) + { + } + } + + public class DynamicInvocationTestInterceptor : IMethodInterceptor + { + public bool CallProceed = false; + public IMethodInvocation LastMethodInvocation; + + public object Invoke(IMethodInvocation invocation) + { + LastMethodInvocation = invocation; + if (CallProceed) + { + return invocation.Proceed(); + } + + return null; } } } diff --git a/test/Spring/Spring.Aop.Tests/Aop/Framework/DynamicProxy/AopUtilsTests.cs b/test/Spring/Spring.Aop.Tests/Aop/Framework/DynamicProxy/AopUtilsTests.cs index 0b2dc1f1..c94f8988 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Framework/DynamicProxy/AopUtilsTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Framework/DynamicProxy/AopUtilsTests.cs @@ -20,212 +20,209 @@ using System.Collections; using System.Reflection; - using FakeItEasy; - using NUnit.Framework; using Spring.Aop.Interceptor; using Spring.Aop.Support; using Spring.Collections; using Spring.Objects; -namespace Spring.Aop.Framework.DynamicProxy +namespace Spring.Aop.Framework.DynamicProxy; + +/// +/// Unit tests for the AopUtils class. +/// +/// Rod Johnson +/// Choy Rim (.NET) +[TestFixture] +public sealed class AopUtilsTests { - /// - /// Unit tests for the AopUtils class. - /// - /// Rod Johnson - /// Choy Rim (.NET) - [TestFixture] - public sealed class AopUtilsTests + [SetUp] + public void SetUp() { - [SetUp] - public void SetUp() - { - } - - [Test] - public void PointcutCanNeverApply() - { - IPointcut pointcut = new NeverMatchesPointcut(); - Assert.IsFalse(AopUtils.CanApply(pointcut, typeof (Object), null)); - } - - [Test] - public void PointcutAlwaysApplies() - { - Assert.IsTrue(AopUtils.CanApply(new DefaultPointcutAdvisor(new NopInterceptor()), typeof (Object), null)); - Assert.IsTrue(AopUtils.CanApply(new DefaultPointcutAdvisor(new NopInterceptor()), typeof (TestObject), new Type[] {typeof (ITestObject)})); - } - - [Test] - public void PointcutAppliesToOneMethodOnObject() - { - IPointcut pointcut = new OneMethodTestPointcut(); - Assert.IsTrue(AopUtils.CanApply(pointcut, typeof (object), null), - "Must return true if we're not proxying interfaces."); - Assert.IsFalse(AopUtils.CanApply(pointcut, typeof (object), - new Type[] {typeof (ITestObject)}), - "Must return false if we're proxying interfaces."); - } - - [Test] - public void PointcutAppliesToOneInterfaceOfSeveral() - { - IPointcut pointcut = new OneInterfaceTestPointcut(); - - // Will return true if we're proxying interfaces including ITestObject - Assert.IsTrue(AopUtils.CanApply(pointcut, typeof (TestObject), new Type[] {typeof (ITestObject), typeof (IComparable)})); - - // Will return true if we're proxying interfaces including ITestObject - Assert.IsFalse(AopUtils.CanApply(pointcut, typeof (TestObject), new Type[] {typeof (IComparable)})); - } - - [Test] - public void CanApplyWithAdvisorYieldsTrueIfAdvisorIsNotKnownAdvisorType() - { - IAdvisor advisor = A.Fake(); - Assert.IsTrue(AopUtils.CanApply(advisor, typeof (TestObject), null)); - } - - [Test] - public void CanApplyWithAdvisorYieldsTrueIfAdvisorIsNull() - { - Assert.IsTrue(AopUtils.CanApply((IAdvisor) null, typeof (TestObject), null)); - } - - /// - /// Test preconditions for all tests related to GetAllInterfaces - /// - [Test] - public void GetAllInterfacesTestsPreconditions() - { - DerivedTestObject testObject = new DerivedTestObject(); - IList interfaces = new ArrayList(testObject.GetType().GetInterfaces()); - Assert.AreEqual(9, interfaces.Count, "Incorrect number of interfaces"); - Assert.IsTrue(interfaces.Contains(typeof(ITestObject)), "Does not contain ITestObject"); - Assert.IsTrue(interfaces.Contains(typeof(IOther)), "Does not contain IOther"); - } - - [Test] - public void GetAllInterfacesWithNull() - { - Type[] interfaces = AopUtils.GetAllInterfaces(null); - Assert.IsNotNull(interfaces, - "Must never return null, even if the argument is null."); - Assert.AreEqual(0, interfaces.Length, - "Must return an empty array is the argument is null."); - } - - [Test] - public void GetAllInterfacesFromTypeWithNull() - { - Assert.Throws(() => AopUtils.GetAllInterfacesFromType(null)); - } - - [Test] - public void GetAllInterfacesWithObjectThatDoesntImpementAnything() - { - ImplementsNothing instance = new ImplementsNothing(); - Type[] interfaces = AopUtils.GetAllInterfaces(instance); - Assert.IsNotNull(interfaces, - "Must never return null, even if the argument doesn't implement any interfaces."); - Assert.AreEqual(0, interfaces.Length, - "Must return an empty array is the argument doesn't implement any interfaces."); - } - - [Test] - public void GetAllInterfacesSunnyDay() - { - ImplementsTwoInterfaces instance = new ImplementsTwoInterfaces(); - Type[] interfaces = AopUtils.GetAllInterfaces(instance); - Assert.IsNotNull(interfaces, "Must never return null."); - Assert.AreEqual(2, interfaces.Length, - "Implements two interfaces."); - ISet ifaces = new ListSet(interfaces); - Assert.IsTrue( - ifaces.ContainsAll( - new Type [] {typeof(IDisposable), typeof(ICloneable)}), - "Did not find the correct interfaces."); - } - - [Test] - public void GetAllInterfacesWithObjectThatInheritsInterfaces() - { - InheritsOneInterface instance = new InheritsOneInterface(); - Type[] interfaces = AopUtils.GetAllInterfaces(instance); - Assert.IsNotNull(interfaces, "Must never return null."); - Assert.AreEqual(1, interfaces.Length, - "Inherited one interface from superclass."); - Type iface = interfaces[0]; - Assert.IsNotNull(iface, "Returned interface cannot be null."); - Assert.AreEqual(typeof(IDisposable), iface, "Wrong interface returned."); - } - - [Test] - public void CanApplyWithTrueIntroductionAdvisor() - { - IIntroductionAdvisor mockIntroAdvisor = A.Fake(); - A.CallTo(() => mockIntroAdvisor.TypeFilter).Returns(TrueTypeFilter.True); - - Assert.IsTrue(AopUtils.CanApply(mockIntroAdvisor, typeof (TestObject), null)); - } - - #region Helper Classes - - private sealed class OneMethodTestPointcut : StaticMethodMatcherPointcut - { - public override bool Matches(MethodInfo m, Type targetClass) - { - return m.Name.Equals("GetHashCode"); - } - } - - private sealed class OneInterfaceTestPointcut : StaticMethodMatcherPointcut - { - public override bool Matches(MethodInfo m, Type targetClass) - { - return m.Name.Equals("ReturnsThis"); - } - } - - private sealed class NeverMatchesPointcut : StaticMethodMatcherPointcut - { - public override bool Matches(MethodInfo m, Type targetClass) - { - return false; - } - } - - private sealed class ImplementsNothing - { - } - - private abstract class ImplementsOneInterface : IDisposable - { - public void Dispose() - { - throw new NotImplementedException(); - } - } - - private sealed class InheritsOneInterface : ImplementsOneInterface - { - } - - private sealed class ImplementsTwoInterfaces : IDisposable, ICloneable - { - public void Dispose() - { - throw new NotImplementedException(); - } - - public object Clone() - { - throw new NotImplementedException(); - } - } - - #endregion } -} \ No newline at end of file + + [Test] + public void PointcutCanNeverApply() + { + IPointcut pointcut = new NeverMatchesPointcut(); + Assert.IsFalse(AopUtils.CanApply(pointcut, typeof(Object), null)); + } + + [Test] + public void PointcutAlwaysApplies() + { + Assert.IsTrue(AopUtils.CanApply(new DefaultPointcutAdvisor(new NopInterceptor()), typeof(Object), null)); + Assert.IsTrue(AopUtils.CanApply(new DefaultPointcutAdvisor(new NopInterceptor()), typeof(TestObject), new Type[] { typeof(ITestObject) })); + } + + [Test] + public void PointcutAppliesToOneMethodOnObject() + { + IPointcut pointcut = new OneMethodTestPointcut(); + Assert.IsTrue(AopUtils.CanApply(pointcut, typeof(object), null), + "Must return true if we're not proxying interfaces."); + Assert.IsFalse(AopUtils.CanApply(pointcut, typeof(object), + new Type[] { typeof(ITestObject) }), + "Must return false if we're proxying interfaces."); + } + + [Test] + public void PointcutAppliesToOneInterfaceOfSeveral() + { + IPointcut pointcut = new OneInterfaceTestPointcut(); + + // Will return true if we're proxying interfaces including ITestObject + Assert.IsTrue(AopUtils.CanApply(pointcut, typeof(TestObject), new Type[] { typeof(ITestObject), typeof(IComparable) })); + + // Will return true if we're proxying interfaces including ITestObject + Assert.IsFalse(AopUtils.CanApply(pointcut, typeof(TestObject), new Type[] { typeof(IComparable) })); + } + + [Test] + public void CanApplyWithAdvisorYieldsTrueIfAdvisorIsNotKnownAdvisorType() + { + IAdvisor advisor = A.Fake(); + Assert.IsTrue(AopUtils.CanApply(advisor, typeof(TestObject), null)); + } + + [Test] + public void CanApplyWithAdvisorYieldsTrueIfAdvisorIsNull() + { + Assert.IsTrue(AopUtils.CanApply((IAdvisor) null, typeof(TestObject), null)); + } + + /// + /// Test preconditions for all tests related to GetAllInterfaces + /// + [Test] + public void GetAllInterfacesTestsPreconditions() + { + DerivedTestObject testObject = new DerivedTestObject(); + IList interfaces = new ArrayList(testObject.GetType().GetInterfaces()); + Assert.AreEqual(9, interfaces.Count, "Incorrect number of interfaces"); + Assert.IsTrue(interfaces.Contains(typeof(ITestObject)), "Does not contain ITestObject"); + Assert.IsTrue(interfaces.Contains(typeof(IOther)), "Does not contain IOther"); + } + + [Test] + public void GetAllInterfacesWithNull() + { + Type[] interfaces = AopUtils.GetAllInterfaces(null); + Assert.IsNotNull(interfaces, + "Must never return null, even if the argument is null."); + Assert.AreEqual(0, interfaces.Length, + "Must return an empty array is the argument is null."); + } + + [Test] + public void GetAllInterfacesFromTypeWithNull() + { + Assert.Throws(() => AopUtils.GetAllInterfacesFromType(null)); + } + + [Test] + public void GetAllInterfacesWithObjectThatDoesntImpementAnything() + { + ImplementsNothing instance = new ImplementsNothing(); + Type[] interfaces = AopUtils.GetAllInterfaces(instance); + Assert.IsNotNull(interfaces, + "Must never return null, even if the argument doesn't implement any interfaces."); + Assert.AreEqual(0, interfaces.Length, + "Must return an empty array is the argument doesn't implement any interfaces."); + } + + [Test] + public void GetAllInterfacesSunnyDay() + { + ImplementsTwoInterfaces instance = new ImplementsTwoInterfaces(); + Type[] interfaces = AopUtils.GetAllInterfaces(instance); + Assert.IsNotNull(interfaces, "Must never return null."); + Assert.AreEqual(2, interfaces.Length, + "Implements two interfaces."); + ISet ifaces = new ListSet(interfaces); + Assert.IsTrue( + ifaces.ContainsAll( + new Type[] { typeof(IDisposable), typeof(ICloneable) }), + "Did not find the correct interfaces."); + } + + [Test] + public void GetAllInterfacesWithObjectThatInheritsInterfaces() + { + InheritsOneInterface instance = new InheritsOneInterface(); + Type[] interfaces = AopUtils.GetAllInterfaces(instance); + Assert.IsNotNull(interfaces, "Must never return null."); + Assert.AreEqual(1, interfaces.Length, + "Inherited one interface from superclass."); + Type iface = interfaces[0]; + Assert.IsNotNull(iface, "Returned interface cannot be null."); + Assert.AreEqual(typeof(IDisposable), iface, "Wrong interface returned."); + } + + [Test] + public void CanApplyWithTrueIntroductionAdvisor() + { + IIntroductionAdvisor mockIntroAdvisor = A.Fake(); + A.CallTo(() => mockIntroAdvisor.TypeFilter).Returns(TrueTypeFilter.True); + + Assert.IsTrue(AopUtils.CanApply(mockIntroAdvisor, typeof(TestObject), null)); + } + + #region Helper Classes + + private sealed class OneMethodTestPointcut : StaticMethodMatcherPointcut + { + public override bool Matches(MethodInfo m, Type targetClass) + { + return m.Name.Equals("GetHashCode"); + } + } + + private sealed class OneInterfaceTestPointcut : StaticMethodMatcherPointcut + { + public override bool Matches(MethodInfo m, Type targetClass) + { + return m.Name.Equals("ReturnsThis"); + } + } + + private sealed class NeverMatchesPointcut : StaticMethodMatcherPointcut + { + public override bool Matches(MethodInfo m, Type targetClass) + { + return false; + } + } + + private sealed class ImplementsNothing + { + } + + private abstract class ImplementsOneInterface : IDisposable + { + public void Dispose() + { + throw new NotImplementedException(); + } + } + + private sealed class InheritsOneInterface : ImplementsOneInterface + { + } + + private sealed class ImplementsTwoInterfaces : IDisposable, ICloneable + { + public void Dispose() + { + throw new NotImplementedException(); + } + + public object Clone() + { + throw new NotImplementedException(); + } + } + + #endregion +} diff --git a/test/Spring/Spring.Aop.Tests/Aop/Framework/DynamicProxy/CachedAopProxyFactoryTests.cs b/test/Spring/Spring.Aop.Tests/Aop/Framework/DynamicProxy/CachedAopProxyFactoryTests.cs index 342c8652..af941d75 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Framework/DynamicProxy/CachedAopProxyFactoryTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Framework/DynamicProxy/CachedAopProxyFactoryTests.cs @@ -26,146 +26,145 @@ using Spring.Aop.Support; #endregion -namespace Spring.Aop.Framework.DynamicProxy +namespace Spring.Aop.Framework.DynamicProxy; + +/// +/// Unit tests for the CachedAopProxyFactoryTests class. +/// +/// Bruno Baia +[TestFixture] +public sealed class CachedAopProxyFactoryTests : DefaultAopProxyFactoryTests { - /// - /// Unit tests for the CachedAopProxyFactoryTests class. - /// - /// Bruno Baia - [TestFixture] - public sealed class CachedAopProxyFactoryTests : DefaultAopProxyFactoryTests - { - protected override IAopProxy CreateAopProxy(ProxyFactory advisedSupport) - { - // return (IAopProxy) advisedSupport.GetProxy(); - IAopProxyFactory apf = new CachedAopProxyFactory(); - return apf.CreateAopProxy(advisedSupport); - } - - [SetUp] - public void SetUp() - { - CachedAopProxyFactory.ClearCache(); - } - - [Test] - public void DoesNotCacheWithDifferentBaseType() - { - // Decorated-based proxy (BaseType == TargetType) - ProxyFactory advisedSupport = new ProxyFactory(new TestObject()); - advisedSupport.ProxyTargetType = true; - CreateAopProxy(advisedSupport); - - // Composition-based proxy (BaseType = BaseCompositionAopProxy) - advisedSupport = new ProxyFactory(new TestObject()); - advisedSupport.ProxyTargetType = false; - CreateAopProxy(advisedSupport); - - AssertAopProxyTypeCacheCount(2); - } - - [Test] - public void DoesNotCacheWithDifferentTargetType() - { - ProxyFactory advisedSupport = new ProxyFactory(new BadCommand()); - CreateAopProxy(advisedSupport); - - advisedSupport = new ProxyFactory(new GoodCommand()); - CreateAopProxy(advisedSupport); - - AssertAopProxyTypeCacheCount(2); - } - - [Test] - public void DoesNotCacheWithDifferentProxyTargetAttributes() - { - ProxyFactory advisedSupport = new ProxyFactory(new GoodCommand()); - advisedSupport.ProxyTargetAttributes = true; - CreateAopProxy(advisedSupport); - - advisedSupport = new ProxyFactory(new GoodCommand()); - advisedSupport.ProxyTargetAttributes = false; - CreateAopProxy(advisedSupport); - - AssertAopProxyTypeCacheCount(2); - } - - [Test] - public void DoesNotCacheWithDifferentInterfaces() - { - ProxyFactory advisedSupport = new ProxyFactory(new TestObject()); - CreateAopProxy(advisedSupport); - - advisedSupport = new ProxyFactory(new TestObject()); - advisedSupport.AddInterface(typeof(IPerson)); - CreateAopProxy(advisedSupport); - - AssertAopProxyTypeCacheCount(2); - - // Same with Introductions - advisedSupport = new ProxyFactory(new TestObject()); - TimestampIntroductionInterceptor ti = new TimestampIntroductionInterceptor(); - ti.TimeStamp = new DateTime(666L); - IIntroductionAdvisor introduction = new DefaultIntroductionAdvisor(ti, typeof(ITimeStamped)); - advisedSupport.AddIntroduction(introduction); - CreateAopProxy(advisedSupport); - - AssertAopProxyTypeCacheCount(3); - } - - [Test] - public void DoesCacheWithTwoDecoratorBasedProxy() - { - ProxyFactory advisedSupport = new ProxyFactory(new TestObject()); - advisedSupport.ProxyTargetType = true; - CreateAopProxy(advisedSupport); - - advisedSupport = new ProxyFactory(new TestObject()); - advisedSupport.ProxyTargetType = true; - CreateAopProxy(advisedSupport); - - AssertAopProxyTypeCacheCount(1); - } - - [Test] - public void DoesCacheWithTwoCompositionBasedProxy() - { - ProxyFactory advisedSupport = new ProxyFactory(new TestObject()); - CreateAopProxy(advisedSupport); - - advisedSupport = new ProxyFactory(new TestObject()); - CreateAopProxy(advisedSupport); - - AssertAopProxyTypeCacheCount(1); - } - - private void AssertAopProxyTypeCacheCount(int count) - { - Assert.AreEqual(count, CachedAopProxyFactory.CountCachedTypes); - } - - #region Helper classes definitions - - public interface ICommand - { - void Execute(); - } - - public sealed class BadCommand : ICommand - { - public void Execute() - { - throw new NotImplementedException(); - } - } - - public sealed class GoodCommand : ICommand - { - public void Execute() - { - } - } - - #endregion + protected override IAopProxy CreateAopProxy(ProxyFactory advisedSupport) + { + // return (IAopProxy) advisedSupport.GetProxy(); + IAopProxyFactory apf = new CachedAopProxyFactory(); + return apf.CreateAopProxy(advisedSupport); } -} \ No newline at end of file + + [SetUp] + public void SetUp() + { + CachedAopProxyFactory.ClearCache(); + } + + [Test] + public void DoesNotCacheWithDifferentBaseType() + { + // Decorated-based proxy (BaseType == TargetType) + ProxyFactory advisedSupport = new ProxyFactory(new TestObject()); + advisedSupport.ProxyTargetType = true; + CreateAopProxy(advisedSupport); + + // Composition-based proxy (BaseType = BaseCompositionAopProxy) + advisedSupport = new ProxyFactory(new TestObject()); + advisedSupport.ProxyTargetType = false; + CreateAopProxy(advisedSupport); + + AssertAopProxyTypeCacheCount(2); + } + + [Test] + public void DoesNotCacheWithDifferentTargetType() + { + ProxyFactory advisedSupport = new ProxyFactory(new BadCommand()); + CreateAopProxy(advisedSupport); + + advisedSupport = new ProxyFactory(new GoodCommand()); + CreateAopProxy(advisedSupport); + + AssertAopProxyTypeCacheCount(2); + } + + [Test] + public void DoesNotCacheWithDifferentProxyTargetAttributes() + { + ProxyFactory advisedSupport = new ProxyFactory(new GoodCommand()); + advisedSupport.ProxyTargetAttributes = true; + CreateAopProxy(advisedSupport); + + advisedSupport = new ProxyFactory(new GoodCommand()); + advisedSupport.ProxyTargetAttributes = false; + CreateAopProxy(advisedSupport); + + AssertAopProxyTypeCacheCount(2); + } + + [Test] + public void DoesNotCacheWithDifferentInterfaces() + { + ProxyFactory advisedSupport = new ProxyFactory(new TestObject()); + CreateAopProxy(advisedSupport); + + advisedSupport = new ProxyFactory(new TestObject()); + advisedSupport.AddInterface(typeof(IPerson)); + CreateAopProxy(advisedSupport); + + AssertAopProxyTypeCacheCount(2); + + // Same with Introductions + advisedSupport = new ProxyFactory(new TestObject()); + TimestampIntroductionInterceptor ti = new TimestampIntroductionInterceptor(); + ti.TimeStamp = new DateTime(666L); + IIntroductionAdvisor introduction = new DefaultIntroductionAdvisor(ti, typeof(ITimeStamped)); + advisedSupport.AddIntroduction(introduction); + CreateAopProxy(advisedSupport); + + AssertAopProxyTypeCacheCount(3); + } + + [Test] + public void DoesCacheWithTwoDecoratorBasedProxy() + { + ProxyFactory advisedSupport = new ProxyFactory(new TestObject()); + advisedSupport.ProxyTargetType = true; + CreateAopProxy(advisedSupport); + + advisedSupport = new ProxyFactory(new TestObject()); + advisedSupport.ProxyTargetType = true; + CreateAopProxy(advisedSupport); + + AssertAopProxyTypeCacheCount(1); + } + + [Test] + public void DoesCacheWithTwoCompositionBasedProxy() + { + ProxyFactory advisedSupport = new ProxyFactory(new TestObject()); + CreateAopProxy(advisedSupport); + + advisedSupport = new ProxyFactory(new TestObject()); + CreateAopProxy(advisedSupport); + + AssertAopProxyTypeCacheCount(1); + } + + private void AssertAopProxyTypeCacheCount(int count) + { + Assert.AreEqual(count, CachedAopProxyFactory.CountCachedTypes); + } + + #region Helper classes definitions + + public interface ICommand + { + void Execute(); + } + + public sealed class BadCommand : ICommand + { + public void Execute() + { + throw new NotImplementedException(); + } + } + + public sealed class GoodCommand : ICommand + { + public void Execute() + { + } + } + + #endregion +} diff --git a/test/Spring/Spring.Aop.Tests/Aop/Framework/DynamicProxy/CompositionAopProxyTests.cs b/test/Spring/Spring.Aop.Tests/Aop/Framework/DynamicProxy/CompositionAopProxyTests.cs index d02fa7d9..4fa3d0c5 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Framework/DynamicProxy/CompositionAopProxyTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Framework/DynamicProxy/CompositionAopProxyTests.cs @@ -25,94 +25,93 @@ using Spring.Objects; #endregion -namespace Spring.Aop.Framework.DynamicProxy +namespace Spring.Aop.Framework.DynamicProxy; + +/// +/// Additional and overridden tests for the composition-based proxy. +/// +/// Rod Johnson +/// Juergen Hoeller +/// Bruno Baia (.NET) +[TestFixture] +public class CompositionAopProxyTests : AbstractAopProxyTests { - /// - /// Additional and overridden tests for the composition-based proxy. - /// - /// Rod Johnson - /// Juergen Hoeller - /// Bruno Baia (.NET) - [TestFixture] - public class CompositionAopProxyTests : AbstractAopProxyTests + protected override object CreateProxy(AdvisedSupport advisedSupport) { - protected override object CreateProxy(AdvisedSupport advisedSupport) - { - Assert.IsFalse(advisedSupport.ProxyTargetType, "Not forcible decorator-based proxy"); - object proxy = CreateAopProxy(advisedSupport).GetProxy(); - Assert.IsTrue(AopUtils.IsCompositionAopProxy(proxy), "Should be a composition-based proxy: " + proxy.GetType()); - return proxy; - } - - protected override Type CreateAopProxyType(AdvisedSupport advisedSupport) - { - return new CompositionAopProxyTypeBuilder(advisedSupport).BuildProxyType(); - } - - [Test] - public override void Equality() - { - base.Equality(); - } - - [Test] - public void ProxyIsJustInterface() - { - TestObject target = new TestObject(); - target.Age = 32; - - AdvisedSupport advised = new AdvisedSupport(); - advised.Target = target; - advised.Interfaces = new Type[] { typeof(ITestObject) }; - - object proxy = CreateProxy(advised); - - Assert.IsTrue(proxy is ITestObject); - Assert.IsFalse(proxy is TestObject); - } - - #region ReturnsThisWhenProxyIsIncompatible - - [Test] - public void ReturnsThisWhenProxyIsIncompatible() - { - FooBar obj = new FooBar(); - - AdvisedSupport advised = new AdvisedSupport(); - advised.Target = obj; - advised.Interfaces = new Type[] { typeof(IFoo) }; - - IFoo proxy = (IFoo)CreateProxy(advised); - - Assert.AreSame(obj, proxy.GetBarThis(), - "Target should be returned when return types are incompatible"); - Assert.AreSame(proxy, proxy.GetFooThis(), - "Proxy should be returned when return types are compatible"); - } - - public interface IFoo - { - IBar GetBarThis(); - IFoo GetFooThis(); - } - - public interface IBar - { - } - - public class FooBar : IFoo, IBar - { - public IBar GetBarThis() - { - return this; - } - - public IFoo GetFooThis() - { - return this; - } - } - - #endregion + Assert.IsFalse(advisedSupport.ProxyTargetType, "Not forcible decorator-based proxy"); + object proxy = CreateAopProxy(advisedSupport).GetProxy(); + Assert.IsTrue(AopUtils.IsCompositionAopProxy(proxy), "Should be a composition-based proxy: " + proxy.GetType()); + return proxy; } + + protected override Type CreateAopProxyType(AdvisedSupport advisedSupport) + { + return new CompositionAopProxyTypeBuilder(advisedSupport).BuildProxyType(); + } + + [Test] + public override void Equality() + { + base.Equality(); + } + + [Test] + public void ProxyIsJustInterface() + { + TestObject target = new TestObject(); + target.Age = 32; + + AdvisedSupport advised = new AdvisedSupport(); + advised.Target = target; + advised.Interfaces = new Type[] { typeof(ITestObject) }; + + object proxy = CreateProxy(advised); + + Assert.IsTrue(proxy is ITestObject); + Assert.IsFalse(proxy is TestObject); + } + + #region ReturnsThisWhenProxyIsIncompatible + + [Test] + public void ReturnsThisWhenProxyIsIncompatible() + { + FooBar obj = new FooBar(); + + AdvisedSupport advised = new AdvisedSupport(); + advised.Target = obj; + advised.Interfaces = new Type[] { typeof(IFoo) }; + + IFoo proxy = (IFoo) CreateProxy(advised); + + Assert.AreSame(obj, proxy.GetBarThis(), + "Target should be returned when return types are incompatible"); + Assert.AreSame(proxy, proxy.GetFooThis(), + "Proxy should be returned when return types are compatible"); + } + + public interface IFoo + { + IBar GetBarThis(); + IFoo GetFooThis(); + } + + public interface IBar + { + } + + public class FooBar : IFoo, IBar + { + public IBar GetBarThis() + { + return this; + } + + public IFoo GetFooThis() + { + return this; + } + } + + #endregion } \ No newline at end of file diff --git a/test/Spring/Spring.Aop.Tests/Aop/Framework/DynamicProxy/DecoratorAopProxyTests.cs b/test/Spring/Spring.Aop.Tests/Aop/Framework/DynamicProxy/DecoratorAopProxyTests.cs index 6b350aa5..c8bc38cd 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Framework/DynamicProxy/DecoratorAopProxyTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Framework/DynamicProxy/DecoratorAopProxyTests.cs @@ -27,395 +27,397 @@ using Spring.Objects; #endregion -namespace Spring.Aop.Framework.DynamicProxy +namespace Spring.Aop.Framework.DynamicProxy; + +/// +/// Additional and overridden tests for the decorator-based proxy. +/// +/// Rod Johnson +/// Juergen Hoeller +/// Bruno Baia (.NET) +[TestFixture] +public class DecoratorAopProxyTests : AbstractAopProxyTests { - /// - /// Additional and overridden tests for the decorator-based proxy. - /// - /// Rod Johnson - /// Juergen Hoeller - /// Bruno Baia (.NET) - [TestFixture] - public class DecoratorAopProxyTests : AbstractAopProxyTests + protected override object CreateProxy(AdvisedSupport advisedSupport) { - protected override object CreateProxy(AdvisedSupport advisedSupport) - { - advisedSupport.ProxyTargetType = true; - object proxy = CreateAopProxy(advisedSupport).GetProxy(); - Assert.IsTrue(AopUtils.IsDecoratorAopProxy(proxy)); - return proxy; - } - - protected override Type CreateAopProxyType(AdvisedSupport advisedSupport) - { - return new DecoratorAopProxyTypeBuilder(advisedSupport).BuildProxyType(); - } - - [Test] - [Ignore("TODO: doesn't work yet for decorator proxies")] - public override void Equality() - { - // TODO - find a way to correctly handle decorator proxy equality - base.Equality(); - } - - [Test] - public void CannotProxySealedClass() - { - SealedTestObject target = new SealedTestObject(); - mockTargetSource.SetTarget(target); - AdvisedSupport advised = new AdvisedSupport(new Type[] { }); - advised.TargetSource = mockTargetSource; - - Assert.Throws(() => CreateAopProxy(advised)); - } - - [Test] - public void CannotProxyNonPublicClass() - { - NonPublicTestObject target = new NonPublicTestObject(); - mockTargetSource.SetTarget(target); - AdvisedSupport advised = new AdvisedSupport(new Type[] { }); - advised.TargetSource = mockTargetSource; - - Assert.Throws(() => CreateAopProxy(advised)); - } - - [Test] - public void ProxyCanBeClassAndInterface() - { - TestObject target = new TestObject(); - target.Age = 32; - mockTargetSource.SetTarget(target); - AdvisedSupport advised = new AdvisedSupport(); - advised.TargetSource = mockTargetSource; - IAopProxy aop = CreateAopProxy(advised); - - object proxy = aop.GetProxy(); - Assert.IsTrue(AopUtils.IsDecoratorAopProxy(proxy), "Should be a decorator-based proxy"); - Assert.IsTrue(proxy is ITestObject); - Assert.IsTrue(proxy is TestObject); - - ITestObject itb = (ITestObject)proxy; - Assert.AreEqual(32, itb.Age, "Incorrect age"); - TestObject tb = (TestObject)proxy; - Assert.AreEqual(32, tb.Age, "Incorrect age"); - } - - [Test] - public void InterceptVirtualMethod() - { - DoesNotImplementInterfaceTestObject target = new DoesNotImplementInterfaceTestObject(); - target.Name = "Bruno"; - mockTargetSource.SetTarget(target); - - NopInterceptor ni = new NopInterceptor(); - - AdvisedSupport advised = new AdvisedSupport(); - advised.TargetSource = mockTargetSource; - advised.AddAdvice(ni); - - DoesNotImplementInterfaceTestObject proxy = CreateProxy(advised) as DoesNotImplementInterfaceTestObject; - Assert.IsNotNull(proxy); - - Assert.AreEqual(target.Name, proxy.Name, "Incorrect name"); - proxy.Name = "Bruno Baia"; - Assert.AreEqual("Bruno Baia", proxy.Name, "Incorrect name"); - - Assert.AreEqual(3, ni.Count); - } - - [Test] - public void InterceptProtectedVirtualMethod() - { - DoesNotImplementInterfaceTestObject target = new DoesNotImplementInterfaceTestObject(); - target.Name = "Bruno"; - mockTargetSource.SetTarget(target); - - NopInterceptor ni = new NopInterceptor(); - - AdvisedSupport advised = new AdvisedSupport(); - advised.TargetSource = mockTargetSource; - advised.AddAdvice(ni); - - DoesNotImplementInterfaceTestObject proxy = CreateProxy(advised) as DoesNotImplementInterfaceTestObject; - Assert.IsNotNull(proxy); - - // GetName() calls underlying protected "GetNameInternal()" which calls get_Name - Assert.AreEqual(target.Name, proxy.GetName(), "Incorrect name"); - target.Name = "Bruno Baia"; - Assert.AreEqual("Bruno Baia", proxy.GetName(), "Incorrect name"); - - Assert.AreEqual(2, ni.Count); - } - - [Test] - public void InterceptInheritedVirtualMethods() - { - DoesNotImplementInterfaceTestObject target = new DerivedDoesNotImplementInterfaceTestObject(); - target.Name = "Bruno"; - mockTargetSource.SetTarget(target); - - NopInterceptor ni = new NopInterceptor(); - - AdvisedSupport advised = new AdvisedSupport(); - advised.TargetSource = mockTargetSource; - advised.AddAdvice(ni); - - DoesNotImplementInterfaceTestObject proxy = CreateProxy(advised) as DoesNotImplementInterfaceTestObject; - Assert.IsNotNull(proxy); - - // GetName() calls underlying protected "GetNameInternal()" which calls get_Name - Assert.AreEqual(target.Name, proxy.GetName(), "Incorrect name"); - proxy.Name = "Bruno Baia"; - Assert.AreEqual("Bruno Baia", proxy.Name, "Incorrect name"); - - Assert.AreEqual(3, ni.Count); - } - - [Test] - public void CannotInterceptFinalMethodThatDoesNotBelongToAnInterface() - { - DoesNotImplementInterfaceTestObject target = new DoesNotImplementInterfaceTestObject(); - target.Location = "Paris"; - mockTargetSource.SetTarget(target); - - NopInterceptor ni = new NopInterceptor(); - - AdvisedSupport advised = new AdvisedSupport(); - advised.TargetSource = mockTargetSource; - advised.AddAdvice(ni); - - DoesNotImplementInterfaceTestObject proxy = CreateProxy(advised) as DoesNotImplementInterfaceTestObject; - Assert.IsNotNull(proxy); - - // Location is final and doesn't belong to an interface so can't proxy. - // method call goes directly to the proxy - // and will not have access to the valid _location field - Assert.IsNull(proxy.Location); - - Assert.AreEqual(0, ni.Count); - } - - [Test] - public void InterceptFinalMethodThatBelongsToAnInterface() - { - TestObject target = new TestObject(); - target.Name = "Bruno"; - mockTargetSource.SetTarget(target); - - NopInterceptor ni = new NopInterceptor(); - - AdvisedSupport advised = new AdvisedSupport(mockTargetSource); - advised.AddAdvice(ni); - - // Cast to the interface that method belongs to - ITestObject proxy = CreateProxy(advised) as ITestObject; - Assert.IsNotNull(proxy); - - Assert.AreEqual(target.Name, proxy.Name, "Incorrect name"); - proxy.Name = "Bruno Baia"; - Assert.AreEqual("Bruno Baia", proxy.Name, "Incorrect name"); - - Assert.AreEqual(3, ni.Count); - } - - [Test] - public override void ProxyMethodWithRefOutParametersWithStandardReflection() - { - Assert.Throws(() => ProxyMethodWithRefOutParametersWithStandardReflectionWrapped(), "Cannot create decorator-based IAopProxy for a non visible class [Spring.Aop.Framework.DynamicProxy.AbstractAopProxyTests+InternalRefOutTestObject]"); - } - - private void ProxyMethodWithRefOutParametersWithStandardReflectionWrapped() - { - base.ProxyMethodWithRefOutParametersWithStandardReflection(); - } - - [Test] - public override void ProxyGenericMethodWithRefOutParametersWithStandardReflection() - { - Assert.Throws(() => ProxyGenericMethodWithRefOutParametersWithStandardReflectionWrapped(), "Cannot create decorator-based IAopProxy for a non visible class [Spring.Aop.Framework.DynamicProxy.AbstractAopProxyTests+InternalRefOutGenericTestObject]"); - } - - private void ProxyGenericMethodWithRefOutParametersWithStandardReflectionWrapped() - { - base.ProxyGenericMethodWithRefOutParametersWithStandardReflection(); - } - - #region Attributes - - [Test] - public void ProxyTargetVirtualMethodAttributes() - { - MarkerClass target = new MarkerClass(); - - AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(IMarkerInterface) }); - advised.Target = target; - IAopProxy aopProxy = CreateAopProxy(advised); - - object proxy = aopProxy.GetProxy(); - Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to GetProxy() was null."); - - MethodInfo method = proxy.GetType().GetMethod("MarkerVirtualMethod"); - Assert.IsNotNull(method); - - object[] attrs = method.GetCustomAttributes(false); - Assert.IsNotNull(attrs, "Should have 1 attribute applied to the target method."); - Assert.AreEqual(1, attrs.Length, "Should have 1 attribute applied to the target method."); - Assert.AreEqual(typeof(MarkerAttribute), attrs[0].GetType(), "Wrong System.Type of Attribute applied to the target method."); - } - - [Test] - public void DoesNotProxyTargetVirtualMethodAttributesWithProxyTargetAttributesEqualsFalse() - { - MarkerClass target = new MarkerClass(); - - AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(IMarkerInterface) }); - advised.Target = target; - advised.ProxyTargetAttributes = false; - IAopProxy aopProxy = CreateAopProxy(advised); - - object proxy = aopProxy.GetProxy(); - Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to GetProxy() was null."); - - MethodInfo method = proxy.GetType().GetMethod("MarkerVirtualMethod"); - Assert.IsNotNull(method); - - object[] attrs = method.GetCustomAttributes(false); - Assert.IsNotNull(attrs); - Assert.AreEqual(0, attrs.Length, "Should not have attribute applied to the target method."); - } - - [Test] - public void ProxyTargetVirtualMethodParameterAttributes() - { - MarkerClass target = new MarkerClass(); - - AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(IMarkerInterface) }); - advised.Target = target; - IAopProxy aopProxy = CreateAopProxy(advised); - - object proxy = aopProxy.GetProxy(); - Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to GetProxy() was null."); - - MethodInfo method = proxy.GetType().GetMethod("MarkerVirtualMethod"); - Assert.IsNotNull(method); - - object[] attrs = method.GetParameters()[1].GetCustomAttributes(false); - Assert.IsNotNull(attrs, "Should have had 1 attribute applied to the method's parameter."); - Assert.AreEqual(1, attrs.Length, "Should have had 1 attribute applied to the method's parameter."); - Assert.AreEqual(typeof(MarkerAttribute), attrs[0].GetType(), "Wrong System.Type of Attribute applied to the method's parameter."); - } - - [Test] - public void DoesNotProxyTargetVirtualMethodParameterAttributesWithProxyTargetAttributesEqualsFalse() - { - MarkerClass target = new MarkerClass(); - - AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(IMarkerInterface) }); - advised.Target = target; - advised.ProxyTargetAttributes = false; - IAopProxy aopProxy = CreateAopProxy(advised); - - object proxy = aopProxy.GetProxy(); - Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to GetProxy() was null."); - - MethodInfo method = proxy.GetType().GetMethod("MarkerVirtualMethod"); - Assert.IsNotNull(method); - - object[] attrs = method.GetParameters()[1].GetCustomAttributes(false); - Assert.IsNotNull(attrs); - Assert.AreEqual(0, attrs.Length, "Should not have attribute applied to the method's parameter."); - } - - [Test] - public void ProxyTargetVirtualMethodReturnValueAttributes() - { - MarkerClass target = new MarkerClass(); - - AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(IMarkerInterface) }); - advised.Target = target; - IAopProxy aopProxy = CreateAopProxy(advised); - - object proxy = aopProxy.GetProxy(); - Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to GetProxy() was null."); - - MethodInfo method = proxy.GetType().GetMethod("MarkerVirtualMethod"); - Assert.IsNotNull(method); - - object[] attrs = method.ReturnTypeCustomAttributes.GetCustomAttributes(false); - Assert.IsNotNull(attrs, "Should have had 1 attribute applied to the method's return value."); - Assert.AreEqual(1, attrs.Length, "Should have had 1 attribute applied to the method's return value."); - Assert.AreEqual(typeof(MarkerAttribute), attrs[0].GetType(), "Wrong System.Type of Attribute applied to the method's return value."); - } - - [Test] - public void DoesNotProxyTargetVirtualMethodReturnValueAttributesWithProxyTargetAttributesEqualsFalse() - { - MarkerClass target = new MarkerClass(); - - AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(IMarkerInterface) }); - advised.Target = target; - advised.ProxyTargetAttributes = false; - IAopProxy aopProxy = CreateAopProxy(advised); - - object proxy = aopProxy.GetProxy(); - Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to GetProxy() was null."); - - MethodInfo method = proxy.GetType().GetMethod("MarkerVirtualMethod"); - Assert.IsNotNull(method); - - object[] attrs = method.ReturnTypeCustomAttributes.GetCustomAttributes(false); - Assert.IsNotNull(attrs); - Assert.AreEqual(0, attrs.Length, "Should not have attribute applied to the method's return value."); - } - - #endregion - - #region Helper classes definitions - - internal class NonPublicTestObject - { - } - - public sealed class SealedTestObject - { - } - - public class DoesNotImplementInterfaceTestObject - { - // virtual property - private string _name; - public virtual string Name - { - get { return _name; } - set { _name = value; } - } - - // final method - private string _location; - public string Location - { - get { return _location; } - set { _location = value; } - } - - // protected virtual method - protected virtual string GetNameInternal() - { - return this.Name; - } - - // public final method calling protected - public string GetName() - { - return GetNameInternal(); - } - } - - public class DerivedDoesNotImplementInterfaceTestObject : DoesNotImplementInterfaceTestObject - {} - - #endregion + advisedSupport.ProxyTargetType = true; + object proxy = CreateAopProxy(advisedSupport).GetProxy(); + Assert.IsTrue(AopUtils.IsDecoratorAopProxy(proxy)); + return proxy; } + + protected override Type CreateAopProxyType(AdvisedSupport advisedSupport) + { + return new DecoratorAopProxyTypeBuilder(advisedSupport).BuildProxyType(); + } + + [Test] + [Ignore("TODO: doesn't work yet for decorator proxies")] + public override void Equality() + { + // TODO - find a way to correctly handle decorator proxy equality + base.Equality(); + } + + [Test] + public void CannotProxySealedClass() + { + SealedTestObject target = new SealedTestObject(); + mockTargetSource.SetTarget(target); + AdvisedSupport advised = new AdvisedSupport(new Type[] { }); + advised.TargetSource = mockTargetSource; + + Assert.Throws(() => CreateAopProxy(advised)); + } + + [Test] + public void CannotProxyNonPublicClass() + { + NonPublicTestObject target = new NonPublicTestObject(); + mockTargetSource.SetTarget(target); + AdvisedSupport advised = new AdvisedSupport(new Type[] { }); + advised.TargetSource = mockTargetSource; + + Assert.Throws(() => CreateAopProxy(advised)); + } + + [Test] + public void ProxyCanBeClassAndInterface() + { + TestObject target = new TestObject(); + target.Age = 32; + mockTargetSource.SetTarget(target); + AdvisedSupport advised = new AdvisedSupport(); + advised.TargetSource = mockTargetSource; + IAopProxy aop = CreateAopProxy(advised); + + object proxy = aop.GetProxy(); + Assert.IsTrue(AopUtils.IsDecoratorAopProxy(proxy), "Should be a decorator-based proxy"); + Assert.IsTrue(proxy is ITestObject); + Assert.IsTrue(proxy is TestObject); + + ITestObject itb = (ITestObject) proxy; + Assert.AreEqual(32, itb.Age, "Incorrect age"); + TestObject tb = (TestObject) proxy; + Assert.AreEqual(32, tb.Age, "Incorrect age"); + } + + [Test] + public void InterceptVirtualMethod() + { + DoesNotImplementInterfaceTestObject target = new DoesNotImplementInterfaceTestObject(); + target.Name = "Bruno"; + mockTargetSource.SetTarget(target); + + NopInterceptor ni = new NopInterceptor(); + + AdvisedSupport advised = new AdvisedSupport(); + advised.TargetSource = mockTargetSource; + advised.AddAdvice(ni); + + DoesNotImplementInterfaceTestObject proxy = CreateProxy(advised) as DoesNotImplementInterfaceTestObject; + Assert.IsNotNull(proxy); + + Assert.AreEqual(target.Name, proxy.Name, "Incorrect name"); + proxy.Name = "Bruno Baia"; + Assert.AreEqual("Bruno Baia", proxy.Name, "Incorrect name"); + + Assert.AreEqual(3, ni.Count); + } + + [Test] + public void InterceptProtectedVirtualMethod() + { + DoesNotImplementInterfaceTestObject target = new DoesNotImplementInterfaceTestObject(); + target.Name = "Bruno"; + mockTargetSource.SetTarget(target); + + NopInterceptor ni = new NopInterceptor(); + + AdvisedSupport advised = new AdvisedSupport(); + advised.TargetSource = mockTargetSource; + advised.AddAdvice(ni); + + DoesNotImplementInterfaceTestObject proxy = CreateProxy(advised) as DoesNotImplementInterfaceTestObject; + Assert.IsNotNull(proxy); + + // GetName() calls underlying protected "GetNameInternal()" which calls get_Name + Assert.AreEqual(target.Name, proxy.GetName(), "Incorrect name"); + target.Name = "Bruno Baia"; + Assert.AreEqual("Bruno Baia", proxy.GetName(), "Incorrect name"); + + Assert.AreEqual(2, ni.Count); + } + + [Test] + public void InterceptInheritedVirtualMethods() + { + DoesNotImplementInterfaceTestObject target = new DerivedDoesNotImplementInterfaceTestObject(); + target.Name = "Bruno"; + mockTargetSource.SetTarget(target); + + NopInterceptor ni = new NopInterceptor(); + + AdvisedSupport advised = new AdvisedSupport(); + advised.TargetSource = mockTargetSource; + advised.AddAdvice(ni); + + DoesNotImplementInterfaceTestObject proxy = CreateProxy(advised) as DoesNotImplementInterfaceTestObject; + Assert.IsNotNull(proxy); + + // GetName() calls underlying protected "GetNameInternal()" which calls get_Name + Assert.AreEqual(target.Name, proxy.GetName(), "Incorrect name"); + proxy.Name = "Bruno Baia"; + Assert.AreEqual("Bruno Baia", proxy.Name, "Incorrect name"); + + Assert.AreEqual(3, ni.Count); + } + + [Test] + public void CannotInterceptFinalMethodThatDoesNotBelongToAnInterface() + { + DoesNotImplementInterfaceTestObject target = new DoesNotImplementInterfaceTestObject(); + target.Location = "Paris"; + mockTargetSource.SetTarget(target); + + NopInterceptor ni = new NopInterceptor(); + + AdvisedSupport advised = new AdvisedSupport(); + advised.TargetSource = mockTargetSource; + advised.AddAdvice(ni); + + DoesNotImplementInterfaceTestObject proxy = CreateProxy(advised) as DoesNotImplementInterfaceTestObject; + Assert.IsNotNull(proxy); + + // Location is final and doesn't belong to an interface so can't proxy. + // method call goes directly to the proxy + // and will not have access to the valid _location field + Assert.IsNull(proxy.Location); + + Assert.AreEqual(0, ni.Count); + } + + [Test] + public void InterceptFinalMethodThatBelongsToAnInterface() + { + TestObject target = new TestObject(); + target.Name = "Bruno"; + mockTargetSource.SetTarget(target); + + NopInterceptor ni = new NopInterceptor(); + + AdvisedSupport advised = new AdvisedSupport(mockTargetSource); + advised.AddAdvice(ni); + + // Cast to the interface that method belongs to + ITestObject proxy = CreateProxy(advised) as ITestObject; + Assert.IsNotNull(proxy); + + Assert.AreEqual(target.Name, proxy.Name, "Incorrect name"); + proxy.Name = "Bruno Baia"; + Assert.AreEqual("Bruno Baia", proxy.Name, "Incorrect name"); + + Assert.AreEqual(3, ni.Count); + } + + [Test] + public override void ProxyMethodWithRefOutParametersWithStandardReflection() + { + Assert.Throws(() => ProxyMethodWithRefOutParametersWithStandardReflectionWrapped(), "Cannot create decorator-based IAopProxy for a non visible class [Spring.Aop.Framework.DynamicProxy.AbstractAopProxyTests+InternalRefOutTestObject]"); + } + + private void ProxyMethodWithRefOutParametersWithStandardReflectionWrapped() + { + base.ProxyMethodWithRefOutParametersWithStandardReflection(); + } + + [Test] + public override void ProxyGenericMethodWithRefOutParametersWithStandardReflection() + { + Assert.Throws(() => ProxyGenericMethodWithRefOutParametersWithStandardReflectionWrapped(), "Cannot create decorator-based IAopProxy for a non visible class [Spring.Aop.Framework.DynamicProxy.AbstractAopProxyTests+InternalRefOutGenericTestObject]"); + } + + private void ProxyGenericMethodWithRefOutParametersWithStandardReflectionWrapped() + { + base.ProxyGenericMethodWithRefOutParametersWithStandardReflection(); + } + + #region Attributes + + [Test] + public void ProxyTargetVirtualMethodAttributes() + { + MarkerClass target = new MarkerClass(); + + AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(IMarkerInterface) }); + advised.Target = target; + IAopProxy aopProxy = CreateAopProxy(advised); + + object proxy = aopProxy.GetProxy(); + Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to GetProxy() was null."); + + MethodInfo method = proxy.GetType().GetMethod("MarkerVirtualMethod"); + Assert.IsNotNull(method); + + object[] attrs = method.GetCustomAttributes(false); + Assert.IsNotNull(attrs, "Should have 1 attribute applied to the target method."); + Assert.AreEqual(1, attrs.Length, "Should have 1 attribute applied to the target method."); + Assert.AreEqual(typeof(MarkerAttribute), attrs[0].GetType(), "Wrong System.Type of Attribute applied to the target method."); + } + + [Test] + public void DoesNotProxyTargetVirtualMethodAttributesWithProxyTargetAttributesEqualsFalse() + { + MarkerClass target = new MarkerClass(); + + AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(IMarkerInterface) }); + advised.Target = target; + advised.ProxyTargetAttributes = false; + IAopProxy aopProxy = CreateAopProxy(advised); + + object proxy = aopProxy.GetProxy(); + Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to GetProxy() was null."); + + MethodInfo method = proxy.GetType().GetMethod("MarkerVirtualMethod"); + Assert.IsNotNull(method); + + object[] attrs = method.GetCustomAttributes(false); + Assert.IsNotNull(attrs); + Assert.AreEqual(0, attrs.Length, "Should not have attribute applied to the target method."); + } + + [Test] + public void ProxyTargetVirtualMethodParameterAttributes() + { + MarkerClass target = new MarkerClass(); + + AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(IMarkerInterface) }); + advised.Target = target; + IAopProxy aopProxy = CreateAopProxy(advised); + + object proxy = aopProxy.GetProxy(); + Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to GetProxy() was null."); + + MethodInfo method = proxy.GetType().GetMethod("MarkerVirtualMethod"); + Assert.IsNotNull(method); + + object[] attrs = method.GetParameters()[1].GetCustomAttributes(false); + Assert.IsNotNull(attrs, "Should have had 1 attribute applied to the method's parameter."); + Assert.AreEqual(1, attrs.Length, "Should have had 1 attribute applied to the method's parameter."); + Assert.AreEqual(typeof(MarkerAttribute), attrs[0].GetType(), "Wrong System.Type of Attribute applied to the method's parameter."); + } + + [Test] + public void DoesNotProxyTargetVirtualMethodParameterAttributesWithProxyTargetAttributesEqualsFalse() + { + MarkerClass target = new MarkerClass(); + + AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(IMarkerInterface) }); + advised.Target = target; + advised.ProxyTargetAttributes = false; + IAopProxy aopProxy = CreateAopProxy(advised); + + object proxy = aopProxy.GetProxy(); + Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to GetProxy() was null."); + + MethodInfo method = proxy.GetType().GetMethod("MarkerVirtualMethod"); + Assert.IsNotNull(method); + + object[] attrs = method.GetParameters()[1].GetCustomAttributes(false); + Assert.IsNotNull(attrs); + Assert.AreEqual(0, attrs.Length, "Should not have attribute applied to the method's parameter."); + } + + [Test] + public void ProxyTargetVirtualMethodReturnValueAttributes() + { + MarkerClass target = new MarkerClass(); + + AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(IMarkerInterface) }); + advised.Target = target; + IAopProxy aopProxy = CreateAopProxy(advised); + + object proxy = aopProxy.GetProxy(); + Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to GetProxy() was null."); + + MethodInfo method = proxy.GetType().GetMethod("MarkerVirtualMethod"); + Assert.IsNotNull(method); + + object[] attrs = method.ReturnTypeCustomAttributes.GetCustomAttributes(false); + Assert.IsNotNull(attrs, "Should have had 1 attribute applied to the method's return value."); + Assert.AreEqual(1, attrs.Length, "Should have had 1 attribute applied to the method's return value."); + Assert.AreEqual(typeof(MarkerAttribute), attrs[0].GetType(), "Wrong System.Type of Attribute applied to the method's return value."); + } + + [Test] + public void DoesNotProxyTargetVirtualMethodReturnValueAttributesWithProxyTargetAttributesEqualsFalse() + { + MarkerClass target = new MarkerClass(); + + AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(IMarkerInterface) }); + advised.Target = target; + advised.ProxyTargetAttributes = false; + IAopProxy aopProxy = CreateAopProxy(advised); + + object proxy = aopProxy.GetProxy(); + Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to GetProxy() was null."); + + MethodInfo method = proxy.GetType().GetMethod("MarkerVirtualMethod"); + Assert.IsNotNull(method); + + object[] attrs = method.ReturnTypeCustomAttributes.GetCustomAttributes(false); + Assert.IsNotNull(attrs); + Assert.AreEqual(0, attrs.Length, "Should not have attribute applied to the method's return value."); + } + + #endregion + + #region Helper classes definitions + + internal class NonPublicTestObject + { + } + + public sealed class SealedTestObject + { + } + + public class DoesNotImplementInterfaceTestObject + { + // virtual property + private string _name; + + public virtual string Name + { + get { return _name; } + set { _name = value; } + } + + // final method + private string _location; + + public string Location + { + get { return _location; } + set { _location = value; } + } + + // protected virtual method + protected virtual string GetNameInternal() + { + return this.Name; + } + + // public final method calling protected + public string GetName() + { + return GetNameInternal(); + } + } + + public class DerivedDoesNotImplementInterfaceTestObject : DoesNotImplementInterfaceTestObject + { + } + + #endregion } diff --git a/test/Spring/Spring.Aop.Tests/Aop/Framework/DynamicProxy/DefaultAopProxyFactoryTests.cs b/test/Spring/Spring.Aop.Tests/Aop/Framework/DynamicProxy/DefaultAopProxyFactoryTests.cs index 6118f2fe..6377141b 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Framework/DynamicProxy/DefaultAopProxyFactoryTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Framework/DynamicProxy/DefaultAopProxyFactoryTests.cs @@ -25,80 +25,79 @@ using Spring.Objects; #endregion -namespace Spring.Aop.Framework.DynamicProxy +namespace Spring.Aop.Framework.DynamicProxy; + +/// +/// Unit tests for the DefaultAopProxyFactory class. +/// +/// Bruno Baia +[TestFixture] +public class DefaultAopProxyFactoryTests { - /// - /// Unit tests for the DefaultAopProxyFactory class. - /// - /// Bruno Baia - [TestFixture] - public class DefaultAopProxyFactoryTests - { - protected virtual IAopProxy CreateAopProxy(ProxyFactory advisedSupport) - { + protected virtual IAopProxy CreateAopProxy(ProxyFactory advisedSupport) + { // return (IAopProxy) advisedSupport.GetProxy(); - IAopProxyFactory apf = new DefaultAopProxyFactory(); - return apf.CreateAopProxy(advisedSupport); - } - - [Test] - public void NullConfig() - { - IAopProxyFactory apf = new DefaultAopProxyFactory(); - Assert.Throws(() => apf.CreateAopProxy(null),"Cannot create IAopProxy with null ProxyConfig" ); - } - - [Test] - public void NoInterceptorsAndNoTarget() - { - ProxyFactory advisedSupport = new ProxyFactory(new Type[] { typeof(ITestObject) }); - Assert.Throws(() => CreateAopProxy(advisedSupport), "Cannot create IAopProxy with no advisors and no target source"); - } - - [Test] - public void TargetDoesNotImplementAnyInterfaces() - { - ProxyFactory advisedSupport = new ProxyFactory(); - advisedSupport.AopProxyFactory = new DefaultAopProxyFactory(); - advisedSupport.ProxyTargetType = false; - advisedSupport.Target = new DoesNotImplementAnyInterfacesTestObject(); - - IAopProxy aopProxy = CreateAopProxy(advisedSupport); - Assert.IsNotNull(aopProxy); - Assert.IsTrue(AopUtils.IsDecoratorAopProxy(aopProxy)); - } - - [Test] - public void TargetImplementsAnInterface() - { - ProxyFactory advisedSupport = new ProxyFactory(new TestObject()); - IAopProxy aopProxy = CreateAopProxy(advisedSupport); - Assert.IsNotNull(aopProxy); - - Assert.IsTrue(AopUtils.IsCompositionAopProxy(aopProxy)); - } - - [Test] - public void TargetImplementsAnInterfaceWithProxyTargetTypeSetToTrue() - { - ProxyFactory advisedSupport = new ProxyFactory(); - advisedSupport.ProxyTargetType = true; - advisedSupport.Target = new TestObject(); - - IAopProxy aopProxy = CreateAopProxy(advisedSupport); - Assert.IsNotNull(aopProxy); - Assert.IsTrue(AopUtils.IsDecoratorAopProxy(aopProxy)); - } - - #region Helper classes definitions - - public class DoesNotImplementAnyInterfacesTestObject - { - public virtual void SomeMethod() - { - } - } - - #endregion + IAopProxyFactory apf = new DefaultAopProxyFactory(); + return apf.CreateAopProxy(advisedSupport); } -} \ No newline at end of file + + [Test] + public void NullConfig() + { + IAopProxyFactory apf = new DefaultAopProxyFactory(); + Assert.Throws(() => apf.CreateAopProxy(null), "Cannot create IAopProxy with null ProxyConfig"); + } + + [Test] + public void NoInterceptorsAndNoTarget() + { + ProxyFactory advisedSupport = new ProxyFactory(new Type[] { typeof(ITestObject) }); + Assert.Throws(() => CreateAopProxy(advisedSupport), "Cannot create IAopProxy with no advisors and no target source"); + } + + [Test] + public void TargetDoesNotImplementAnyInterfaces() + { + ProxyFactory advisedSupport = new ProxyFactory(); + advisedSupport.AopProxyFactory = new DefaultAopProxyFactory(); + advisedSupport.ProxyTargetType = false; + advisedSupport.Target = new DoesNotImplementAnyInterfacesTestObject(); + + IAopProxy aopProxy = CreateAopProxy(advisedSupport); + Assert.IsNotNull(aopProxy); + Assert.IsTrue(AopUtils.IsDecoratorAopProxy(aopProxy)); + } + + [Test] + public void TargetImplementsAnInterface() + { + ProxyFactory advisedSupport = new ProxyFactory(new TestObject()); + IAopProxy aopProxy = CreateAopProxy(advisedSupport); + Assert.IsNotNull(aopProxy); + + Assert.IsTrue(AopUtils.IsCompositionAopProxy(aopProxy)); + } + + [Test] + public void TargetImplementsAnInterfaceWithProxyTargetTypeSetToTrue() + { + ProxyFactory advisedSupport = new ProxyFactory(); + advisedSupport.ProxyTargetType = true; + advisedSupport.Target = new TestObject(); + + IAopProxy aopProxy = CreateAopProxy(advisedSupport); + Assert.IsNotNull(aopProxy); + Assert.IsTrue(AopUtils.IsDecoratorAopProxy(aopProxy)); + } + + #region Helper classes definitions + + public class DoesNotImplementAnyInterfacesTestObject + { + public virtual void SomeMethod() + { + } + } + + #endregion +} diff --git a/test/Spring/Spring.Aop.Tests/Aop/Framework/DynamicProxy/InheritanceAopProxyTests.cs b/test/Spring/Spring.Aop.Tests/Aop/Framework/DynamicProxy/InheritanceAopProxyTests.cs index df3087ed..c73595b3 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Framework/DynamicProxy/InheritanceAopProxyTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Framework/DynamicProxy/InheritanceAopProxyTests.cs @@ -21,7 +21,6 @@ #region Imports using NUnit.Framework; - using Spring.Objects; using Spring.Aop.Interceptor; using System.Reflection; @@ -29,411 +28,410 @@ using Spring.Expressions; #endregion -namespace Spring.Aop.Framework.DynamicProxy +namespace Spring.Aop.Framework.DynamicProxy; + +/// +/// Additional and overridden tests for the inheritance-based proxy. +/// +/// Bruno Baia +[TestFixture] +public class InheritanceAopProxyTests { - /// - /// Additional and overridden tests for the inheritance-based proxy. - /// - /// Bruno Baia - [TestFixture] - public class InheritanceAopProxyTests + protected object CreateProxy(AdvisedSupport advisedSupport) { - protected object CreateProxy(AdvisedSupport advisedSupport) - { - Type proxyType = new InheritanceAopProxyTypeBuilder(advisedSupport).BuildProxyType(); - ConstructorInfo proxyCtorInfo = proxyType.GetConstructor(new Type[] { typeof(IAdvised) }); + Type proxyType = new InheritanceAopProxyTypeBuilder(advisedSupport).BuildProxyType(); + ConstructorInfo proxyCtorInfo = proxyType.GetConstructor(new Type[] { typeof(IAdvised) }); - ExpressionEvaluator.GetValue(advisedSupport, "Activate()"); - return ((IAopProxy)proxyCtorInfo.Invoke(new object[] { advisedSupport })).GetProxy(); + ExpressionEvaluator.GetValue(advisedSupport, "Activate()"); + return ((IAopProxy) proxyCtorInfo.Invoke(new object[] { advisedSupport })).GetProxy(); + } + + [Test] + public void DirectCall() + { + AdvisedSupport advised = new AdvisedSupport(); + advised.Target = new InheritanceTestObject(); + + object proxy = CreateProxy(advised); + //DynamicProxyManager.SaveAssembly(); + + Assert.IsTrue(proxy is InheritanceTestObject); + InheritanceTestObject proxiedClass = proxy as InheritanceTestObject; + proxiedClass.Name = "DirectCall"; + Assert.AreEqual("DirectCall", proxiedClass.Name); + + Assert.IsTrue(proxy is IIncrementable); + IIncrementable proxiedIntf = proxy as IIncrementable; + proxiedIntf.Increment(); + Assert.AreEqual(1, proxiedIntf.Value); + } + + [Test] + public void ProxyTargetTypeOnly() + { + AdvisedSupport advised = new AdvisedSupport(); + advised.Target = new InheritanceTestObject("ProxyTargetTypeOnly"); + + object proxy = CreateProxy(advised); + //DynamicProxyManager.SaveAssembly(); + + Assert.IsTrue(proxy is InheritanceTestObject); + InheritanceTestObject proxiedClass = proxy as InheritanceTestObject; + Assert.AreNotEqual("ProxyTargetTypeOnly", proxiedClass.Name); + } + + [Test] + public void CallBaseConstructor() + { + AdvisedSupport advised = new AdvisedSupport(); + advised.Target = new InheritanceTestObject(); + + object proxy = CreateProxy(advised); + //DynamicProxyManager.SaveAssembly(); + + Assert.IsTrue(proxy is InheritanceTestObject); + InheritanceTestObject proxiedClass = proxy as InheritanceTestObject; + Assert.AreEqual("InheritanceTestObject", proxiedClass.Name); + } + + [Test] + public void InterceptVirtualMethod() + { + NopInterceptor ni = new NopInterceptor(); + + AdvisedSupport advised = new AdvisedSupport(); + advised.Target = new InheritanceTestObject(); + advised.AddAdvice(ni); + + object proxy = CreateProxy(advised); + //DynamicProxyManager.SaveAssembly(); + + Assert.IsTrue(proxy is InheritanceTestObject); + InheritanceTestObject proxiedClass = proxy as InheritanceTestObject; + proxiedClass.Name = "InterceptVirtualMethod"; + Assert.AreEqual("InterceptVirtualMethod", proxiedClass.Name); + Assert.AreEqual(2, ni.Count); + } + + [Test] + //SPRNET-1168 + public void InterceptVirtualMethodAndAmbiguousMatches() + { + NopInterceptor ni = new NopInterceptor(); + + AdvisedSupport advised = new AdvisedSupport(); + advised.Target = new AmbiguousMatchesTestObject(); + advised.AddAdvice(ni); + + object proxy = CreateProxy(advised); + //DynamicProxyManager.SaveAssembly(); + + Assert.IsTrue(proxy is AmbiguousMatchesTestObject); + AmbiguousMatchesTestObject proxiedClass = proxy as AmbiguousMatchesTestObject; + proxiedClass.DoIt(new TestObject()); + Assert.AreEqual(1, ni.Count); + } + + public class AmbiguousMatchesTestObject + { + public virtual void DoIt(object obj) + { } - [Test] - public void DirectCall() + public virtual void DoIt(ITestObject obj) { - AdvisedSupport advised = new AdvisedSupport(); - advised.Target = new InheritanceTestObject(); - - object proxy = CreateProxy(advised); - //DynamicProxyManager.SaveAssembly(); - - Assert.IsTrue(proxy is InheritanceTestObject); - InheritanceTestObject proxiedClass = proxy as InheritanceTestObject; - proxiedClass.Name = "DirectCall"; - Assert.AreEqual("DirectCall", proxiedClass.Name); - - Assert.IsTrue(proxy is IIncrementable); - IIncrementable proxiedIntf = proxy as IIncrementable; - proxiedIntf.Increment(); - Assert.AreEqual(1, proxiedIntf.Value); - } - - [Test] - public void ProxyTargetTypeOnly() - { - AdvisedSupport advised = new AdvisedSupport(); - advised.Target = new InheritanceTestObject("ProxyTargetTypeOnly"); - - object proxy = CreateProxy(advised); - //DynamicProxyManager.SaveAssembly(); - - Assert.IsTrue(proxy is InheritanceTestObject); - InheritanceTestObject proxiedClass = proxy as InheritanceTestObject; - Assert.AreNotEqual("ProxyTargetTypeOnly", proxiedClass.Name); - } - - [Test] - public void CallBaseConstructor() - { - AdvisedSupport advised = new AdvisedSupport(); - advised.Target = new InheritanceTestObject(); - - object proxy = CreateProxy(advised); - //DynamicProxyManager.SaveAssembly(); - - Assert.IsTrue(proxy is InheritanceTestObject); - InheritanceTestObject proxiedClass = proxy as InheritanceTestObject; - Assert.AreEqual("InheritanceTestObject", proxiedClass.Name); - } - - [Test] - public void InterceptVirtualMethod() - { - NopInterceptor ni = new NopInterceptor(); - - AdvisedSupport advised = new AdvisedSupport(); - advised.Target = new InheritanceTestObject(); - advised.AddAdvice(ni); - - object proxy = CreateProxy(advised); - //DynamicProxyManager.SaveAssembly(); - - Assert.IsTrue(proxy is InheritanceTestObject); - InheritanceTestObject proxiedClass = proxy as InheritanceTestObject; - proxiedClass.Name = "InterceptVirtualMethod"; - Assert.AreEqual("InterceptVirtualMethod", proxiedClass.Name); - Assert.AreEqual(2, ni.Count); - } - - [Test] - //SPRNET-1168 - public void InterceptVirtualMethodAndAmbiguousMatches() - { - NopInterceptor ni = new NopInterceptor(); - - AdvisedSupport advised = new AdvisedSupport(); - advised.Target = new AmbiguousMatchesTestObject(); - advised.AddAdvice(ni); - - object proxy = CreateProxy(advised); - //DynamicProxyManager.SaveAssembly(); - - Assert.IsTrue(proxy is AmbiguousMatchesTestObject); - AmbiguousMatchesTestObject proxiedClass = proxy as AmbiguousMatchesTestObject; - proxiedClass.DoIt(new TestObject()); - Assert.AreEqual(1, ni.Count); - } - - public class AmbiguousMatchesTestObject - { - public virtual void DoIt(object obj) - { - } - - public virtual void DoIt(ITestObject obj) - { - } - } - - [Test] - public void InterceptVirtualGenericMethod() - { - NopInterceptor ni = new NopInterceptor(); - - AdvisedSupport advised = new AdvisedSupport(); - advised.Target = new AnotherTestObject(); - advised.AddAdvice(ni); - - object proxy = CreateProxy(advised); - //DynamicProxyManager.SaveAssembly(); - - Assert.IsTrue(proxy is AnotherTestObject); - AnotherTestObject proxiedClass = proxy as AnotherTestObject; - Assert.AreEqual(typeof(int), proxiedClass.GenericMethod()); - Assert.AreEqual(1, ni.Count); - } - - [Test] - // SPRNET-1429 - public void InterceptVirtualGenericMethodWithGenericParameter() - { - NopInterceptor ni = new NopInterceptor(); - - AdvisedSupport advised = new AdvisedSupport(); - advised.Target = new AnotherTestObject(); - advised.AddAdvice(ni); - - object proxy = CreateProxy(advised); - //DynamicProxyManager.SaveAssembly(); - - Assert.IsTrue(proxy is AnotherTestObject); - AnotherTestObject proxiedClass = proxy as AnotherTestObject; - Assert.AreEqual("Hello", proxiedClass.AnotherGenericMethod("Hello")); - Assert.AreEqual(1, ni.Count); - } - - public class AnotherTestObject - { - public virtual Type GenericMethod() - { - return typeof(T); - } - - // Test ambiguous match - public virtual Type GenericMethod() - { - return typeof(string); - } - - public virtual T AnotherGenericMethod(T arg) - { - return arg; - } - } - - [Test] - public void DoesNotInterceptFinalMethod() - { - NopInterceptor ni = new NopInterceptor(); - - AdvisedSupport advised = new AdvisedSupport(); - advised.Target = new InheritanceTestObject(); - advised.AddAdvice(ni); - - object proxy = CreateProxy(advised); - //DynamicProxyManager.SaveAssembly(); - - Assert.IsTrue(proxy is InheritanceTestObject); - InheritanceTestObject proxiedClass = proxy as InheritanceTestObject; - proxiedClass.Name = "DoesNotInterceptFinalMethod"; - Assert.AreEqual("DoesNotInterceptFinalMethod", proxiedClass.Name); - Assert.AreEqual(2, ni.Count); - - proxiedClass.Reset(); - Assert.AreEqual(2, ni.Count); - Assert.AreEqual("InheritanceTestObject", proxiedClass.Name); - Assert.AreEqual(3, ni.Count); - } - - [Test] - public void DoesNotInterceptInternalMethod() - { - NopInterceptor ni = new NopInterceptor(); - - AdvisedSupport advised = new AdvisedSupport(); - advised.Target = new InheritanceTestObject(); - advised.AddAdvice(ni); - - object proxy = CreateProxy(advised); - //DynamicProxyManager.SaveAssembly(); - - Assert.IsTrue(proxy is InheritanceTestObject); - InheritanceTestObject proxiedClass = proxy as InheritanceTestObject; - proxiedClass.InternalToDo(); - Assert.AreEqual(0, ni.Count); - } - - [Test] - public void InterceptVirtualMethodThatBelongsToAnInterface() - { - NopInterceptor ni = new NopInterceptor(); - - AdvisedSupport advised = new AdvisedSupport(new InheritanceTestObject()); - advised.AddAdvice(ni); - - object proxy = CreateProxy(advised); - //DynamicProxyManager.SaveAssembly(); - - Assert.IsTrue(proxy is InheritanceTestObject); - InheritanceTestObject proxiedClass = proxy as InheritanceTestObject; - proxiedClass.Increment(); - Assert.AreEqual(1, ni.Count); - - Assert.IsTrue(proxy is IIncrementable); - IIncrementable proxiedInterface = proxy as IIncrementable; - proxiedInterface.Increment(); - Assert.AreEqual(2, ni.Count); - } - - [Test] - public void InterceptNonVirtualMethodThatBelongsToAnInterface() - { - NopInterceptor ni = new NopInterceptor(); - - AdvisedSupport advised = new AdvisedSupport(new InheritanceTestObject()); - advised.AddAdvice(ni); - - object proxy = CreateProxy(advised); - //DynamicProxyManager.SaveAssembly(); - - Assert.IsTrue(proxy is InheritanceTestObject); - InheritanceTestObject proxiedClass = proxy as InheritanceTestObject; - Assert.AreEqual(0, proxiedClass.Value); - Assert.AreEqual(0, ni.Count); - - Assert.IsTrue(proxy is IIncrementable); - IIncrementable proxiedInterface = proxy as IIncrementable; - proxiedInterface.Increment(); - Assert.AreEqual(1, proxiedInterface.Value); - Assert.AreEqual(2, ni.Count); - } - - [Test] - public void InterceptThisCalls() - { - NopInterceptor ni = new NopInterceptor(); - - AdvisedSupport advised = new AdvisedSupport(new InheritanceTestObject()); - advised.AddAdvice(ni); - - object proxy = CreateProxy(advised); - //DynamicProxyManager.SaveAssembly(); - - Assert.IsTrue(proxy is InheritanceTestObject); - InheritanceTestObject proxiedClass = proxy as InheritanceTestObject; - proxiedClass.IncrementTwice(); - Assert.AreEqual(2, ni.Count); - Assert.AreEqual(2, proxiedClass.Value); - } - - [Test] - public void InterceptProtectedMethod() - { - NopInterceptor ni = new NopInterceptor(); - - AdvisedSupport advised = new AdvisedSupport(new InheritanceTestObject()); - advised.AddAdvice(ni); - - object proxy = CreateProxy(advised); - //DynamicProxyManager.SaveAssembly(); - - Assert.IsTrue(proxy is InheritanceTestObject); - InheritanceTestObject proxiedClass = proxy as InheritanceTestObject; - proxiedClass.Todo(); - Assert.AreEqual(1, ni.Count); - } - - [Test] - public void InterceptInheritedMethods() - { - NopInterceptor ni = new NopInterceptor(); - - AdvisedSupport advised = new AdvisedSupport(new InheritanceTestObject()); - advised.AddAdvice(ni); - - object proxy = CreateProxy(advised); - //DynamicProxyManager.SaveAssembly(); - - Assert.IsTrue(proxy is InheritanceTestObject); - InheritanceTestObject proxiedClass = proxy as InheritanceTestObject; - proxiedClass.Todo(); - proxiedClass.Name = "Erich"; - Assert.AreEqual("Erich", proxiedClass.Name); - Assert.AreEqual(3, ni.Count); } } - #region Helper Classes - - public interface IIncrementable + [Test] + public void InterceptVirtualGenericMethod() { - int Value {get; set;} - void Increment(); + NopInterceptor ni = new NopInterceptor(); + + AdvisedSupport advised = new AdvisedSupport(); + advised.Target = new AnotherTestObject(); + advised.AddAdvice(ni); + + object proxy = CreateProxy(advised); + //DynamicProxyManager.SaveAssembly(); + + Assert.IsTrue(proxy is AnotherTestObject); + AnotherTestObject proxiedClass = proxy as AnotherTestObject; + Assert.AreEqual(typeof(int), proxiedClass.GenericMethod()); + Assert.AreEqual(1, ni.Count); } - public class InheritanceTestObject : IIncrementable + [Test] + // SPRNET-1429 + public void InterceptVirtualGenericMethodWithGenericParameter() { - // virtual method - private string _name; - public virtual string Name + NopInterceptor ni = new NopInterceptor(); + + AdvisedSupport advised = new AdvisedSupport(); + advised.Target = new AnotherTestObject(); + advised.AddAdvice(ni); + + object proxy = CreateProxy(advised); + //DynamicProxyManager.SaveAssembly(); + + Assert.IsTrue(proxy is AnotherTestObject); + AnotherTestObject proxiedClass = proxy as AnotherTestObject; + Assert.AreEqual("Hello", proxiedClass.AnotherGenericMethod("Hello")); + Assert.AreEqual(1, ni.Count); + } + + public class AnotherTestObject + { + public virtual Type GenericMethod() { - get { return _name; } - set { _name = value; } + return typeof(T); } - // many constructors - public InheritanceTestObject() : this("InheritanceTestObject", 0) + // Test ambiguous match + public virtual Type GenericMethod() { + return typeof(string); } - public InheritanceTestObject(string name) : this(name, 0) + public virtual T AnotherGenericMethod(T arg) { + return arg; } + } - public InheritanceTestObject(string name, int value) - { - this._name = name; - this._value = value; - } + [Test] + public void DoesNotInterceptFinalMethod() + { + NopInterceptor ni = new NopInterceptor(); - #region IIncrementable Members + AdvisedSupport advised = new AdvisedSupport(); + advised.Target = new InheritanceTestObject(); + advised.AddAdvice(ni); - // non virtual method that belongs to an interface - private int _value; - public int Value - { - get { return _value; } - set { _value = value; } - } + object proxy = CreateProxy(advised); + //DynamicProxyManager.SaveAssembly(); - // virtual method that belongs to an interface too - public virtual void Increment() - { - // this call - this._value++; - } + Assert.IsTrue(proxy is InheritanceTestObject); + InheritanceTestObject proxiedClass = proxy as InheritanceTestObject; + proxiedClass.Name = "DoesNotInterceptFinalMethod"; + Assert.AreEqual("DoesNotInterceptFinalMethod", proxiedClass.Name); + Assert.AreEqual(2, ni.Count); - #endregion + proxiedClass.Reset(); + Assert.AreEqual(2, ni.Count); + Assert.AreEqual("InheritanceTestObject", proxiedClass.Name); + Assert.AreEqual(3, ni.Count); + } - // final method - public void Reset() - { - this._name = "InheritanceTestObject"; - this._value = 0; - } + [Test] + public void DoesNotInterceptInternalMethod() + { + NopInterceptor ni = new NopInterceptor(); + AdvisedSupport advised = new AdvisedSupport(); + advised.Target = new InheritanceTestObject(); + advised.AddAdvice(ni); + + object proxy = CreateProxy(advised); + //DynamicProxyManager.SaveAssembly(); + + Assert.IsTrue(proxy is InheritanceTestObject); + InheritanceTestObject proxiedClass = proxy as InheritanceTestObject; + proxiedClass.InternalToDo(); + Assert.AreEqual(0, ni.Count); + } + + [Test] + public void InterceptVirtualMethodThatBelongsToAnInterface() + { + NopInterceptor ni = new NopInterceptor(); + + AdvisedSupport advised = new AdvisedSupport(new InheritanceTestObject()); + advised.AddAdvice(ni); + + object proxy = CreateProxy(advised); + //DynamicProxyManager.SaveAssembly(); + + Assert.IsTrue(proxy is InheritanceTestObject); + InheritanceTestObject proxiedClass = proxy as InheritanceTestObject; + proxiedClass.Increment(); + Assert.AreEqual(1, ni.Count); + + Assert.IsTrue(proxy is IIncrementable); + IIncrementable proxiedInterface = proxy as IIncrementable; + proxiedInterface.Increment(); + Assert.AreEqual(2, ni.Count); + } + + [Test] + public void InterceptNonVirtualMethodThatBelongsToAnInterface() + { + NopInterceptor ni = new NopInterceptor(); + + AdvisedSupport advised = new AdvisedSupport(new InheritanceTestObject()); + advised.AddAdvice(ni); + + object proxy = CreateProxy(advised); + //DynamicProxyManager.SaveAssembly(); + + Assert.IsTrue(proxy is InheritanceTestObject); + InheritanceTestObject proxiedClass = proxy as InheritanceTestObject; + Assert.AreEqual(0, proxiedClass.Value); + Assert.AreEqual(0, ni.Count); + + Assert.IsTrue(proxy is IIncrementable); + IIncrementable proxiedInterface = proxy as IIncrementable; + proxiedInterface.Increment(); + Assert.AreEqual(1, proxiedInterface.Value); + Assert.AreEqual(2, ni.Count); + } + + [Test] + public void InterceptThisCalls() + { + NopInterceptor ni = new NopInterceptor(); + + AdvisedSupport advised = new AdvisedSupport(new InheritanceTestObject()); + advised.AddAdvice(ni); + + object proxy = CreateProxy(advised); + //DynamicProxyManager.SaveAssembly(); + + Assert.IsTrue(proxy is InheritanceTestObject); + InheritanceTestObject proxiedClass = proxy as InheritanceTestObject; + proxiedClass.IncrementTwice(); + Assert.AreEqual(2, ni.Count); + Assert.AreEqual(2, proxiedClass.Value); + } + + [Test] + public void InterceptProtectedMethod() + { + NopInterceptor ni = new NopInterceptor(); + + AdvisedSupport advised = new AdvisedSupport(new InheritanceTestObject()); + advised.AddAdvice(ni); + + object proxy = CreateProxy(advised); + //DynamicProxyManager.SaveAssembly(); + + Assert.IsTrue(proxy is InheritanceTestObject); + InheritanceTestObject proxiedClass = proxy as InheritanceTestObject; + proxiedClass.Todo(); + Assert.AreEqual(1, ni.Count); + } + + [Test] + public void InterceptInheritedMethods() + { + NopInterceptor ni = new NopInterceptor(); + + AdvisedSupport advised = new AdvisedSupport(new InheritanceTestObject()); + advised.AddAdvice(ni); + + object proxy = CreateProxy(advised); + //DynamicProxyManager.SaveAssembly(); + + Assert.IsTrue(proxy is InheritanceTestObject); + InheritanceTestObject proxiedClass = proxy as InheritanceTestObject; + proxiedClass.Todo(); + proxiedClass.Name = "Erich"; + Assert.AreEqual("Erich", proxiedClass.Name); + Assert.AreEqual(3, ni.Count); + } +} + +#region Helper Classes + +public interface IIncrementable +{ + int Value { get; set; } + void Increment(); +} + +public class InheritanceTestObject : IIncrementable +{ + // virtual method + private string _name; + + public virtual string Name + { + get { return _name; } + set { _name = value; } + } + + // many constructors + public InheritanceTestObject() : this("InheritanceTestObject", 0) + { + } + + public InheritanceTestObject(string name) : this(name, 0) + { + } + + public InheritanceTestObject(string name, int value) + { + this._name = name; + this._value = value; + } + + #region IIncrementable Members + + // non virtual method that belongs to an interface + private int _value; + + public int Value + { + get { return _value; } + set { _value = value; } + } + + // virtual method that belongs to an interface too + public virtual void Increment() + { // this call - public void IncrementTwice() - { - this.Increment(); - this.Increment(); - } - - // protected method call - public void Todo() - { - ProtectedTodo(); - } - - protected virtual void ProtectedTodo() - { - - } - - // "internal virtual" is not supported on net 1.0 CLR - // see http://support.microsoft.com/?scid=kb%3Ben-us%3B317129&x=11&y=12 - internal virtual void InternalToDo() - { - - } - - internal protected virtual void InternalProtectedToDo() - { - - } + this._value++; } - public class DerivedInheritanceTestObject : InheritanceTestObject - {} - #endregion -} \ No newline at end of file + + // final method + public void Reset() + { + this._name = "InheritanceTestObject"; + this._value = 0; + } + + // this call + public void IncrementTwice() + { + this.Increment(); + this.Increment(); + } + + // protected method call + public void Todo() + { + ProtectedTodo(); + } + + protected virtual void ProtectedTodo() + { + } + + // "internal virtual" is not supported on net 1.0 CLR + // see http://support.microsoft.com/?scid=kb%3Ben-us%3B317129&x=11&y=12 + internal virtual void InternalToDo() + { + } + + internal protected virtual void InternalProtectedToDo() + { + } +} + +public class DerivedInheritanceTestObject : InheritanceTestObject +{ +} + +#endregion diff --git a/test/Spring/Spring.Aop.Tests/Aop/Framework/DynamicProxy/IsAopProxyTests.cs b/test/Spring/Spring.Aop.Tests/Aop/Framework/DynamicProxy/IsAopProxyTests.cs index 5da27575..c9a004ab 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Framework/DynamicProxy/IsAopProxyTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Framework/DynamicProxy/IsAopProxyTests.cs @@ -4,79 +4,78 @@ using Spring.Context.Support; using Spring.Objects; using Spring.Objects.Factory.Xml; -namespace Spring.Aop.Framework.DynamicProxy +namespace Spring.Aop.Framework.DynamicProxy; + +[TestFixture] +public class IsAopProxyTests { - [TestFixture] - public class IsAopProxyTests + private TestObject _target; + + [SetUp] + public void SetUp() { - private TestObject _target; + _target = new TestObject("Michael", 23); + } - [SetUp] - public void SetUp() + [Test] + public void TargetIsNotAProxy() + { + Assert.False(AopUtils.IsAopProxy(_target)); + Assert.False(AopUtils.IsInheritanceAopProxy(_target)); + Assert.False(AopUtils.IsInheritanceAopProxyType(_target.GetType())); + } + + [Test] + public void IsCompositionProxy() + { + var pf = new ProxyFactory(typeof(ITestObject), new DebugAdvice()); + pf.Target = _target; + Assert.False(pf.ProxyTargetType); + + var proxy = (ITestObject) pf.GetProxy(); + + Assert.True(AopUtils.IsCompositionAopProxy(proxy)); + Assert.True(AopUtils.IsAopProxy(proxy)); + Assert.IsNotInstanceOf(proxy); + } + + [Test] + public void IsDecoratorProxy() + { + var pf = new ProxyFactory(new DebugAdvice()); + pf.Target = _target; + pf.ProxyTargetType = true; + + var proxy = (TestObject) pf.GetProxy(); + Assert.True(AopUtils.IsDecoratorAopProxy(proxy)); + Assert.True(AopUtils.IsAopProxy(proxy)); + } + + [Test] + public void IsInheritanceBasedProxyTypeReturnsFalseForNull() + { + Assert.False(AopUtils.IsInheritanceAopProxyType(null)); + } + + [Test] + public void IsInheritanceBasedProxyReturnsFalseForNull() + { + Assert.False(AopUtils.IsInheritanceAopProxy(null)); + } + + [Test] + public void IsInheritanceBasedProxy() + { + using (var ctx = new XmlApplicationContext(ReadOnlyXmlTestResource.GetFilePath("IsAopProxyTests.xml", this.GetType()))) { - _target = new TestObject("Michael", 23); - } - - [Test] - public void TargetIsNotAProxy() - { - Assert.False(AopUtils.IsAopProxy(_target)); - Assert.False(AopUtils.IsInheritanceAopProxy(_target)); - Assert.False(AopUtils.IsInheritanceAopProxyType(_target.GetType())); - } + var proxy = (TestObject) ctx["michael"]; + Assert.AreEqual("Michael", proxy.Name); - [Test] - public void IsCompositionProxy() - { - var pf = new ProxyFactory(typeof(ITestObject), new DebugAdvice()); - pf.Target = _target; - Assert.False(pf.ProxyTargetType); + Assert.True(AopUtils.IsInheritanceAopProxyType(proxy.GetType())); + Assert.True(AopUtils.IsAopProxyType(proxy.GetType())); - var proxy = (ITestObject)pf.GetProxy(); - - Assert.True(AopUtils.IsCompositionAopProxy(proxy)); + Assert.True(AopUtils.IsInheritanceAopProxy(proxy)); Assert.True(AopUtils.IsAopProxy(proxy)); - Assert.IsNotInstanceOf(proxy); - } - - [Test] - public void IsDecoratorProxy() - { - var pf = new ProxyFactory(new DebugAdvice()); - pf.Target = _target; - pf.ProxyTargetType = true; - - var proxy = (TestObject)pf.GetProxy(); - Assert.True(AopUtils.IsDecoratorAopProxy(proxy)); - Assert.True(AopUtils.IsAopProxy(proxy)); - } - - [Test] - public void IsInheritanceBasedProxyTypeReturnsFalseForNull() - { - Assert.False(AopUtils.IsInheritanceAopProxyType(null)); - } - - [Test] - public void IsInheritanceBasedProxyReturnsFalseForNull() - { - Assert.False(AopUtils.IsInheritanceAopProxy(null)); - } - - [Test] - public void IsInheritanceBasedProxy() - { - using (var ctx = new XmlApplicationContext(ReadOnlyXmlTestResource.GetFilePath("IsAopProxyTests.xml", this.GetType()))) - { - var proxy = (TestObject)ctx["michael"]; - Assert.AreEqual("Michael", proxy.Name); - - Assert.True(AopUtils.IsInheritanceAopProxyType(proxy.GetType())); - Assert.True(AopUtils.IsAopProxyType(proxy.GetType())); - - Assert.True(AopUtils.IsInheritanceAopProxy(proxy)); - Assert.True(AopUtils.IsAopProxy(proxy)); - } } } -} \ No newline at end of file +} diff --git a/test/Spring/Spring.Aop.Tests/Aop/Framework/DynamicProxy/IsAopProxyTests.xml b/test/Spring/Spring.Aop.Tests/Aop/Framework/DynamicProxy/IsAopProxyTests.xml index 6b15132a..16a405cc 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Framework/DynamicProxy/IsAopProxyTests.xml +++ b/test/Spring/Spring.Aop.Tests/Aop/Framework/DynamicProxy/IsAopProxyTests.xml @@ -1,26 +1,26 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:aop="http://www.springframework.net/aop"> - - - - michael - - - - - debugInterceptor - - - + + + + michael + + + + + debugInterceptor + + + - - - - + + + + - + diff --git a/test/Spring/Spring.Aop.Tests/Aop/Framework/DynamicProxy/MockTargetSource.cs b/test/Spring/Spring.Aop.Tests/Aop/Framework/DynamicProxy/MockTargetSource.cs index 99693d49..31c8b036 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Framework/DynamicProxy/MockTargetSource.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Framework/DynamicProxy/MockTargetSource.cs @@ -22,63 +22,62 @@ #endregion -namespace Spring.Aop.Framework.DynamicProxy +namespace Spring.Aop.Framework.DynamicProxy; + +/// +/// Useful implementation +/// that checks calls to GetTarget and ReleaseTarget. +/// +/// Rod Johnson +/// Bruno Baia (.NET) +public class MockTargetSource : ITargetSource { - /// - /// Useful implementation - /// that checks calls to GetTarget and ReleaseTarget. - /// - /// Rod Johnson - /// Bruno Baia (.NET) - public class MockTargetSource : ITargetSource + private object _target; + + public int gets; + public int releases; + + public void Reset() { - private object _target; - - public int gets; - public int releases; - - public void Reset() - { - this._target = null; - gets = releases = 0; - } - - public void SetTarget(Object target) - { - this._target = target; - } - - public void Verify() - { - if (gets != releases) - throw new Exception("Expectation failed: " + gets + " gets and " + releases + " releases"); - } - - #region ITargetSource Members - - public Type TargetType - { - get { return _target.GetType(); } - } - - public bool IsStatic - { - get { return false; } - } - - public object GetTarget() - { - ++gets; - return _target; - } - - public void ReleaseTarget(object target) - { - if (target != this._target) - throw new Exception("Released wrong target"); - ++releases; - } - - #endregion + this._target = null; + gets = releases = 0; } + + public void SetTarget(Object target) + { + this._target = target; + } + + public void Verify() + { + if (gets != releases) + throw new Exception("Expectation failed: " + gets + " gets and " + releases + " releases"); + } + + #region ITargetSource Members + + public Type TargetType + { + get { return _target.GetType(); } + } + + public bool IsStatic + { + get { return false; } + } + + public object GetTarget() + { + ++gets; + return _target; + } + + public void ReleaseTarget(object target) + { + if (target != this._target) + throw new Exception("Released wrong target"); + ++releases; + } + + #endregion } diff --git a/test/Spring/Spring.Aop.Tests/Aop/Framework/HashtableCachingAdvisorChainFactoryTests.cs b/test/Spring/Spring.Aop.Tests/Aop/Framework/HashtableCachingAdvisorChainFactoryTests.cs index 94326777..783f055d 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Framework/HashtableCachingAdvisorChainFactoryTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Framework/HashtableCachingAdvisorChainFactoryTests.cs @@ -24,58 +24,57 @@ using NUnit.Framework; #endregion -namespace Spring.Aop.Framework +namespace Spring.Aop.Framework; + +/// +/// Unit tests for the HashtableCachingAdvisorChainFactory class. +/// +/// Rick Evans +[TestFixture] +public sealed class HashtableCachingAdvisorChainFactoryTests { - /// - /// Unit tests for the HashtableCachingAdvisorChainFactory class. + #region SetUp + + /// + /// The setup logic executed before the execution of this test fixture. /// - /// Rick Evans - [TestFixture] - public sealed class HashtableCachingAdvisorChainFactoryTests + [OneTimeSetUp] + public void FixtureSetUp() { - #region SetUp - - /// - /// The setup logic executed before the execution of this test fixture. - /// - [OneTimeSetUp] - public void FixtureSetUp() - { - } + } - /// - /// The setup logic executed before the execution of each individual test. - /// - [SetUp] - public void SetUp() - { - } - - #endregion + /// + /// The setup logic executed before the execution of each individual test. + /// + [SetUp] + public void SetUp() + { + } - #region TearDown - - /// - /// The tear down logic executed after the execution of each individual test. - /// - [TearDown] - public void TearDown() - { - } + #endregion - /// - /// The tear down logic executed after the entire test fixture has executed. - /// - [OneTimeTearDown] - public void FixtureTearDown() - { - } - - #endregion + #region TearDown - [Test] - public void Instantiation() { + /// + /// The tear down logic executed after the execution of each individual test. + /// + [TearDown] + public void TearDown() + { + } - } - } -} + /// + /// The tear down logic executed after the entire test fixture has executed. + /// + [OneTimeTearDown] + public void FixtureTearDown() + { + } + + #endregion + + [Test] + public void Instantiation() + { + } +} \ No newline at end of file diff --git a/test/Spring/Spring.Aop.Tests/Aop/Framework/IIsModified.cs b/test/Spring/Spring.Aop.Tests/Aop/Framework/IIsModified.cs index 44e225da..8ab72327 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Framework/IIsModified.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Framework/IIsModified.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -18,10 +18,9 @@ #endregion -namespace Spring.Aop.Framework +namespace Spring.Aop.Framework; + +public interface IIsModified { - public interface IIsModified - { - bool IsModified { get; set; } - } + bool IsModified { get; set; } } diff --git a/test/Spring/Spring.Aop.Tests/Aop/Framework/ITimeStamped.cs b/test/Spring/Spring.Aop.Tests/Aop/Framework/ITimeStamped.cs index 1332f906..7f3e17dd 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Framework/ITimeStamped.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Framework/ITimeStamped.cs @@ -1,38 +1,40 @@ #region License + /* * Copyright 2002-2010 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 + #region Imports #endregion -namespace Spring.Aop.Framework +namespace Spring.Aop.Framework; + +/// +/// This interface can be implemented by cacheable objects +/// or cache entries, to enable the freshness of objects +/// to be checked. +/// +/// Rod Johnson +/// Choy Rim (.NET) +public interface ITimeStamped { - /// - /// This interface can be implemented by cacheable objects - /// or cache entries, to enable the freshness of objects - /// to be checked. - /// - /// Rod Johnson - /// Choy Rim (.NET) - public interface ITimeStamped - { - /// - /// Return the timestamp for this object. - /// - DateTime TimeStamp { get; } - } + /// + /// Return the timestamp for this object. + /// + DateTime TimeStamp { get; } } diff --git a/test/Spring/Spring.Aop.Tests/Aop/Framework/IsModifiedMixin.cs b/test/Spring/Spring.Aop.Tests/Aop/Framework/IsModifiedMixin.cs index a2d04c26..8dd3ba80 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Framework/IsModifiedMixin.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Framework/IsModifiedMixin.cs @@ -21,23 +21,23 @@ using AopAlliance.Aop; using Spring.Aop.Support; -namespace Spring.Aop.Framework +namespace Spring.Aop.Framework; + +public class IsModifiedMixin : IIsModified, IAdvice { - public class IsModifiedMixin : IIsModified, IAdvice - { - private bool isModified = true; + private bool isModified = true; - public virtual bool IsModified - { - get { return isModified; } - set { isModified = value; } - } - } - - public class IsModifiedAdvisor : DefaultIntroductionAdvisor + public virtual bool IsModified + { + get { return isModified; } + set { isModified = value; } + } +} + +public class IsModifiedAdvisor : DefaultIntroductionAdvisor +{ + public IsModifiedAdvisor() + : base(new IsModifiedMixin()) { - public IsModifiedAdvisor() - : base(new IsModifiedMixin()) - {} } } diff --git a/test/Spring/Spring.Aop.Tests/Aop/Framework/MethodCounter.cs b/test/Spring/Spring.Aop.Tests/Aop/Framework/MethodCounter.cs index 91869bff..9ed0b334 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Framework/MethodCounter.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Framework/MethodCounter.cs @@ -1,66 +1,71 @@ #region License + /* * Copyright 2002-2010 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 + #region Imports using System.Collections; using System.Reflection; + #endregion -namespace Spring.Aop.Framework +namespace Spring.Aop.Framework; + +/// +/// Useful base class for counting advices etc. +/// +/// Rod Johnson +/// Choy Rim (.NET) +[Serializable] +public class MethodCounter { - /// - /// Useful base class for counting advices etc. - /// - /// Rod Johnson - /// Choy Rim (.NET) - [Serializable] - public class MethodCounter - { - /// Method name --> count, does not understand overloading - private Hashtable map = new Hashtable(); - private int allCount; - - protected internal virtual void Count(MethodBase m) - { - Count(m.Name); - } - - protected internal virtual void Count(string methodName) - { - int count = GetCalls(methodName); - ++count; - map[methodName] = count; - ++allCount; - } - - public virtual int GetCalls(string methodName) - { - int count = 0; - if ( map.ContainsKey(methodName) ) - { - count = (int) map[methodName]; - } - return count; - } - - public virtual int GetCalls() - { - return allCount; - } - } + /// Method name --> count, does not understand overloading + private Hashtable map = new Hashtable(); + + private int allCount; + + protected internal virtual void Count(MethodBase m) + { + Count(m.Name); + } + + protected internal virtual void Count(string methodName) + { + int count = GetCalls(methodName); + ++count; + map[methodName] = count; + ++allCount; + } + + public virtual int GetCalls(string methodName) + { + int count = 0; + if (map.ContainsKey(methodName)) + { + count = (int) map[methodName]; + } + + return count; + } + + public virtual int GetCalls() + { + return allCount; + } } diff --git a/test/Spring/Spring.Aop.Tests/Aop/Framework/PrototypeTargetTests.cs b/test/Spring/Spring.Aop.Tests/Aop/Framework/PrototypeTargetTests.cs index c447ff45..c25aa2a8 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Framework/PrototypeTargetTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Framework/PrototypeTargetTests.cs @@ -1,4 +1,5 @@ #region License + /* * Copyright 2002-2010 the original author or authors. * @@ -14,6 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + #endregion #region Imports @@ -21,80 +23,81 @@ using Spring.Objects.Factory; using Spring.Objects.Factory.Xml; using AopAlliance.Intercept; - using NUnit.Framework; + #endregion -namespace Spring.Aop.Framework +namespace Spring.Aop.Framework; + +/// +/// +/// +/// Juergen Hoeller +/// Simon White (.NET) +[TestFixture] +public class PrototypeTargetTests { - /// - /// - /// - /// Juergen Hoeller - /// Simon White (.NET) - [TestFixture] - public class PrototypeTargetTests - { - [Test] - public void PrototypeProxyWithPrototypeTarget() - { - TestObjectImpl.constructionCount = 0; - IObjectFactory iof = new XmlObjectFactory(new ReadOnlyXmlTestResource("prototypeTarget.xml", GetType())); - for (int i = 0 ; i < 10 ; i++) - { - int crap = TestObjectImpl.constructionCount; - TestObject to = (TestObject) iof.GetObject("testObjectPrototype"); - crap = TestObjectImpl.constructionCount; - to.DoSomething(); - } - TestInterceptor interceptor = (TestInterceptor) iof.GetObject("testInterceptor"); - Assert.AreEqual(10, TestObjectImpl.constructionCount); - Assert.AreEqual(10, interceptor.invocationCount); - } + [Test] + public void PrototypeProxyWithPrototypeTarget() + { + TestObjectImpl.constructionCount = 0; + IObjectFactory iof = new XmlObjectFactory(new ReadOnlyXmlTestResource("prototypeTarget.xml", GetType())); + for (int i = 0; i < 10; i++) + { + int crap = TestObjectImpl.constructionCount; + TestObject to = (TestObject) iof.GetObject("testObjectPrototype"); + crap = TestObjectImpl.constructionCount; + to.DoSomething(); + } - [Test] - public void SingletonProxyWithPrototypeTarget() - { - TestObjectImpl.constructionCount = 0; - IObjectFactory iof = new XmlObjectFactory(new ReadOnlyXmlTestResource("prototypeTarget.xml", GetType())); - for (int i = 0; i < 10; i++) - { - TestObject to = (TestObject) iof.GetObject("testObjectSingleton"); - to.DoSomething(); - } - TestInterceptor interceptor = (TestInterceptor) iof.GetObject("testInterceptor"); - Assert.AreEqual(1, TestObjectImpl.constructionCount); - Assert.AreEqual(10, interceptor.invocationCount); - } + TestInterceptor interceptor = (TestInterceptor) iof.GetObject("testInterceptor"); + Assert.AreEqual(10, TestObjectImpl.constructionCount); + Assert.AreEqual(10, interceptor.invocationCount); + } - public interface TestObject - { - void DoSomething(); - } + [Test] + public void SingletonProxyWithPrototypeTarget() + { + TestObjectImpl.constructionCount = 0; + IObjectFactory iof = new XmlObjectFactory(new ReadOnlyXmlTestResource("prototypeTarget.xml", GetType())); + for (int i = 0; i < 10; i++) + { + TestObject to = (TestObject) iof.GetObject("testObjectSingleton"); + to.DoSomething(); + } - public class TestObjectImpl : TestObject - { - public static int constructionCount = 0; + TestInterceptor interceptor = (TestInterceptor) iof.GetObject("testInterceptor"); + Assert.AreEqual(1, TestObjectImpl.constructionCount); + Assert.AreEqual(10, interceptor.invocationCount); + } - public TestObjectImpl() - { - constructionCount++; - } + public interface TestObject + { + void DoSomething(); + } - public void DoSomething() - { - } - } + public class TestObjectImpl : TestObject + { + public static int constructionCount = 0; - public class TestInterceptor : IMethodInterceptor - { - public int invocationCount = 0; + public TestObjectImpl() + { + constructionCount++; + } - public object Invoke(IMethodInvocation methodInvocation) - { - invocationCount++; - return methodInvocation.Proceed(); - } - } - } + public void DoSomething() + { + } + } + + public class TestInterceptor : IMethodInterceptor + { + public int invocationCount = 0; + + public object Invoke(IMethodInvocation methodInvocation) + { + invocationCount++; + return methodInvocation.Proceed(); + } + } } diff --git a/test/Spring/Spring.Aop.Tests/Aop/Framework/ProxyConfigTests.cs b/test/Spring/Spring.Aop.Tests/Aop/Framework/ProxyConfigTests.cs index 3d3446d8..b5d16a4e 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Framework/ProxyConfigTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Framework/ProxyConfigTests.cs @@ -25,34 +25,33 @@ using NUnit.Framework; #endregion -namespace Spring.Aop.Framework +namespace Spring.Aop.Framework; + +/// +/// Unit tests for the ProxyConfig class. +/// +/// Rick Evans +[TestFixture] +public sealed class ProxyConfigTests { - /// - /// Unit tests for the ProxyConfig class. - /// - /// Rick Evans - [TestFixture] - public sealed class ProxyConfigTests - { - [Test] - public void Instantiation() - { + [Test] + public void Instantiation() + { + } - } + [Category("Performance")] + [Test, Explicit] + public void InstantiationPerformance() + { + int iterations = 10000; - [Category("Performance")] - [Test, Explicit] - public void InstantiationPerformance() + Stopwatch watch = Stopwatch.StartNew(); + for (int i = 0; i < iterations; i++) { - int iterations = 10000; - - Stopwatch watch = Stopwatch.StartNew(); - for (int i = 0; i < iterations; i++) - { - new ProxyConfig(); - } - watch.Stop(); - Console.WriteLine("Instantiation time: {0}ms", watch.ElapsedMilliseconds); + new ProxyConfig(); } - } + + watch.Stop(); + Console.WriteLine("Instantiation time: {0}ms", watch.ElapsedMilliseconds); + } } diff --git a/test/Spring/Spring.Aop.Tests/Aop/Framework/ProxyFactoryObjectTests.cs b/test/Spring/Spring.Aop.Tests/Aop/Framework/ProxyFactoryObjectTests.cs index 6f117b92..13230c98 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Framework/ProxyFactoryObjectTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Framework/ProxyFactoryObjectTests.cs @@ -23,9 +23,7 @@ using System.Reflection; using System.Text; using AopAlliance.Aop; using AopAlliance.Intercept; - using FakeItEasy; - using NUnit.Framework; using Spring.Aop.Advice; using Spring.Aop.Interceptor; @@ -40,360 +38,356 @@ using Spring.Objects.Factory.Xml; using Spring.Proxy; using Spring.Threading; -namespace Spring.Aop.Framework +namespace Spring.Aop.Framework; + +/// +/// Integration test cases for the ProxyFactoryObject, using an XML object factory. +/// +/// Rod Johnson +/// Federico Spinazzi (.NET) +/// Choy Rim (.NET) +/// Aleksandar Seovic (.NET) +[TestFixture] +public sealed class ProxyFactoryObjectTests { - /// - /// Integration test cases for the ProxyFactoryObject, using an XML object factory. - /// - /// Rod Johnson - /// Federico Spinazzi (.NET) - /// Choy Rim (.NET) - /// Aleksandar Seovic (.NET) - [TestFixture] - public sealed class ProxyFactoryObjectTests + private IObjectFactory factory; + + [SetUp] + public void SetUp() { - private IObjectFactory factory; + factory = new XmlObjectFactory(new ReadOnlyXmlTestResource("proxyFactoryTests.xml", GetType())); + } - [SetUp] - public void SetUp() + [Test] + public void TargetThrowsInvalidCastException() + { + Exception expectedException = new InvalidCastException(); + ITestObject test1 = (ITestObject) factory.GetObject("test1"); + try + { + test1.Exceptional(expectedException); + Assert.Fail("Should have thrown exception raised by target"); + } + catch (Exception ex) + { + Assert.AreEqual(expectedException, ex, "exception matches"); + Assert.AreEqual(1, test1.ExceptionMethodCallCount); + } + } + + [Test] + public void IsCompositionProxy() + { + ITestObject test1 = (ITestObject) factory.GetObject("test1"); + Assert.IsTrue(AopUtils.IsCompositionAopProxy(test1), "test1 is a composition proxy"); + } + + [Test] + public void GetObjectTypeWithDirectTarget() + { + IObjectFactory bf = new XmlObjectFactory( + new ReadOnlyXmlTestResource("proxyFactoryTargetSourceTests.xml", + GetType())); + + // We have a counting before advice here + CountingBeforeAdvice cba = (CountingBeforeAdvice) bf.GetObject("countingBeforeAdvice"); + Assert.AreEqual(0, cba.GetCalls()); + + ITestObject tb = (ITestObject) bf.GetObject("directTarget"); + Assert.IsTrue(tb.Name.Equals("Adam")); + Assert.AreEqual(1, cba.GetCalls()); + + ProxyFactoryObject pfb = (ProxyFactoryObject) bf.GetObject("&directTarget"); + Assert.IsTrue(typeof(ITestObject).IsAssignableFrom(pfb.ObjectType), "Has correct object type"); + } + + [Test] + public void GetObjectTypeWithTargetViaTargetSource() + { + IObjectFactory bf = new XmlObjectFactory( + new ReadOnlyXmlTestResource("proxyFactoryTargetSourceTests.xml", + GetType())); + ITestObject tb = (ITestObject) bf.GetObject("viaTargetSource"); + Assert.IsTrue(tb.Name.Equals("Adam")); + ProxyFactoryObject pfb = (ProxyFactoryObject) bf.GetObject("&viaTargetSource"); + Assert.IsTrue(typeof(ITestObject).IsAssignableFrom(pfb.ObjectType), "Has correct object type"); + } + + [Test] + public void GetObjectTypeWithNoTargetOrTargetSource() + { + IObjectFactory bf = + new XmlObjectFactory(new ReadOnlyXmlTestResource("proxyFactoryTargetSourceTests.xml", GetType())); + bf.GetObject("noTarget"); + IFactoryObject pfb = (ProxyFactoryObject) bf.GetObject("&noTarget"); + Assert.IsTrue(typeof(ITestObject).IsAssignableFrom(pfb.ObjectType), "Has correct object type"); + } + + /// + /// The instances are equal, but do not have object identity. + /// Interceptors and interfaces and the target are the same. + /// + [Test] + public void SingletonInstancesAreEqual() + { + ITestObject test1 = (ITestObject) factory.GetObject("test1"); + ITestObject test1_1 = (ITestObject) factory.GetObject("test1"); + Assert.AreEqual(test1, test1_1, "Singleton instances =="); + test1.Age = 25; + Assert.AreEqual(test1.Age, test1_1.Age); + test1.Age = 250; + Assert.AreEqual(test1.Age, test1_1.Age); + IAdvised pc1 = (IAdvised) test1; + IAdvised pc2 = (IAdvised) test1_1; + Assert.AreEqual(pc1.Advisors, pc2.Advisors); + int oldLength = pc1.Advisors.Count; + NopInterceptor di = new NopInterceptor(); + pc1.AddAdvice(1, di); + Assert.AreEqual(pc1.Advisors, pc2.Advisors); + Assert.AreEqual(oldLength + 1, pc2.Advisors.Count, "Now have one more advisor"); + Assert.AreEqual(di.Count, 0); + test1.Age = (5); + Assert.AreEqual(test1_1.Age, test1.Age); + Assert.AreEqual(3, di.Count); + } + + [Test] + public void PrototypeInstancesAreNotEqual() + { + ITestObject test2 = (ITestObject) factory.GetObject("prototype"); + ITestObject test2_1 = (ITestObject) factory.GetObject("prototype"); + Assert.IsTrue(test2 != test2_1, "Prototype instances !="); + Assert.IsTrue(TestObject.Equals(test2, test2_1), "Prototype instances equal"); + } + + [Test] + public void PrototypeInstancesAreIndependent() + { + IObjectFactory objectFactory = new XmlObjectFactory(new ReadOnlyXmlTestResource("prototypeTests.xml", GetType())); + // Initial count value set in object factory XML + int INITIAL_COUNT = 10; + + // Check it works without AOP + ISideEffectObject raw = (ISideEffectObject) objectFactory.GetObject("prototypeTarget"); + Assert.AreEqual(INITIAL_COUNT, raw.Count); + raw.doWork(); + Assert.AreEqual(INITIAL_COUNT + 1, raw.Count); + raw = (ISideEffectObject) objectFactory.GetObject("prototypeTarget"); + Assert.AreEqual(INITIAL_COUNT, raw.Count); + + // Now try with advised instances + ISideEffectObject prototype2FirstInstance = (ISideEffectObject) objectFactory.GetObject("prototype"); + Assert.AreEqual(INITIAL_COUNT, prototype2FirstInstance.Count); + prototype2FirstInstance.doWork(); + Assert.AreEqual(INITIAL_COUNT + 1, prototype2FirstInstance.Count); + + ISideEffectObject prototype2SecondInstance = (ISideEffectObject) objectFactory.GetObject("prototype"); + Assert.IsFalse(prototype2FirstInstance == prototype2SecondInstance, "Prototypes are not =="); + Assert.AreEqual(INITIAL_COUNT, prototype2SecondInstance.Count); + Assert.AreEqual(INITIAL_COUNT + 1, prototype2FirstInstance.Count); + } + + /// Test invoker is automatically added to manipulate target + [Test] + public void AutoInvoker() + { + String name = "Hieronymous"; + TestObject target = (TestObject) factory.GetObject("test"); + target.Name = name; + ITestObject autoInvoker = (ITestObject) factory.GetObject("autoInvoker"); + Assert.IsTrue(autoInvoker.Name.Equals(name)); + } + + [Test] + public void CanGetFactoryReferenceAndManipulate() + { + ITestObject to = (ITestObject) factory.GetObject("test1"); + // no exception + string dummy = to.Name; + + IAdvised config = (IAdvised) to; + Assert.AreEqual(1, config.Advisors.Count, "Object should have only one advisors"); + + Exception ex = new NotSupportedException("Invoke"); + // Add evil interceptor to head of list + config.AddAdvice(0, new EvilMethodInterceptor(ex)); + Assert.AreEqual(2, config.Advisors.Count, "The advisor count is wrong after adding an advisor programmatically."); + + try + { + // evil interceptor should throw exception + dummy = to.Name; + Assert.Fail("Evil interceptor added programmatically should fail all method calls, but it didn't"); + } + catch (Exception thrown) + { + Assert.AreEqual(thrown, ex, "The thrown exception is not the one we were looking for."); + } + } + + /// + /// Must see effect immediately on behaviour. + /// TODO (EE): Note that we can't add or remove interfaces without reconfiguring the singleton. + /// + [Test, Ignore("change according to ProxyFactoryBeanTests.canAddAndRemoveAdvicesOnSingleton")] + public void CanAddAndRemoveIntroductionsOnSingleton() + { + try + { + ITimeStamped ts = (ITimeStamped) factory.GetObject("test1"); + Assert.Fail("Shouldn't implement ITimeStamped before manipulation"); + } + catch (InvalidCastException) { - factory = new XmlObjectFactory(new ReadOnlyXmlTestResource("proxyFactoryTests.xml", GetType())); } - [Test] - public void TargetThrowsInvalidCastException() + ProxyFactoryObject config = (ProxyFactoryObject) factory.GetObject("&test1"); + long time = 666L; + TimestampIntroductionInterceptor ti = new TimestampIntroductionInterceptor(); + ti.TimeStamp = new DateTime(time); + IIntroductionAdvisor advisor = new DefaultIntroductionAdvisor(ti, typeof(ITimeStamped)); + + // add to front of introduction chain + int oldCount = config.Introductions.Count; + config.AddIntroduction(0, advisor); + Assert.IsTrue(config.Introductions.Count == oldCount + 1); + + ITimeStamped ts2 = (ITimeStamped) factory.GetObject("test1"); + Assert.IsTrue(ts2.TimeStamp == new DateTime(time)); + + // Can remove + config.RemoveIntroduction(advisor); + Assert.IsTrue(config.Introductions.Count == oldCount); + + // Existing reference will still work + object o = ts2.TimeStamp; + + // But new proxies should not implement ITimeStamped + try { - Exception expectedException = new InvalidCastException(); - ITestObject test1 = (ITestObject)factory.GetObject("test1"); - try - { - test1.Exceptional(expectedException); - Assert.Fail("Should have thrown exception raised by target"); - } - catch (Exception ex) - { - Assert.AreEqual(expectedException, ex, "exception matches"); - Assert.AreEqual(1, test1.ExceptionMethodCallCount); - } + ts2 = (ITimeStamped) factory.GetObject("test1"); + Assert.Fail("Should no longer implement ITimeStamped"); + } + catch (InvalidCastException) + { + // expected... } - [Test] - public void IsCompositionProxy() + // Now check non-effect of removing interceptor that isn't there + oldCount = config.Advisors.Count; + config.RemoveAdvice(new DebugAdvice()); + Assert.IsTrue(config.Advisors.Count == oldCount); + + ITestObject it = (ITestObject) ts2; + DebugAdvice debugInterceptor = new DebugAdvice(); + config.AddAdvice(0, debugInterceptor); + object foo = it.Spouse; + Assert.AreEqual(1, debugInterceptor.Count); + config.RemoveAdvice(debugInterceptor); + foo = it.Spouse; + // not invoked again + Assert.IsTrue(debugInterceptor.Count == 1); + } + + /// Try adding and removing interfaces and interceptors on prototype. + /// Changes will only affect future references obtained from the factory. + /// Each instance will be independent. + /// + [Test] + public void CanAddAndRemoveAspectInterfacesOnPrototype() + { + try + { + ITimeStamped ts = (ITimeStamped) factory.GetObject("test2"); + Assert.Fail("Shouldn't implement ITimeStamped before manipulation"); + } + catch (InvalidCastException) { - ITestObject test1 = (ITestObject)factory.GetObject("test1"); - Assert.IsTrue(AopUtils.IsCompositionAopProxy(test1), "test1 is a composition proxy"); } - [Test] - public void GetObjectTypeWithDirectTarget() + IAdvised config = (IAdvised) factory.GetObject("&test2"); + long time = 666L; + TimestampIntroductionInterceptor ti = new TimestampIntroductionInterceptor(); + ti.TimeStamp = new DateTime(time); + IIntroductionAdvisor advisor = new DefaultIntroductionAdvisor(ti, typeof(ITimeStamped)); + + // add to front of introduction chain + int oldCount = config.Introductions.Count; + config.AddIntroduction(0, advisor); + Assert.IsTrue(config.Introductions.Count == oldCount + 1); + + ITimeStamped ts2 = (ITimeStamped) factory.GetObject("test2"); + Assert.IsTrue(ts2.TimeStamp == new DateTime(time)); + + // Can remove + config.RemoveIntroduction(advisor); + Assert.IsTrue(config.Introductions.Count == oldCount); + + // Existing reference will still work + object o = ts2.TimeStamp; + + // But new proxies should not implement ITimeStamped + try + { + ts2 = (ITimeStamped) factory.GetObject("test2"); + Assert.Fail("Should no longer implement ITimeStamped"); + } + catch (InvalidCastException) { - IObjectFactory bf = new XmlObjectFactory( - new ReadOnlyXmlTestResource("proxyFactoryTargetSourceTests.xml", - GetType())); - - // We have a counting before advice here - CountingBeforeAdvice cba = (CountingBeforeAdvice)bf.GetObject("countingBeforeAdvice"); - Assert.AreEqual(0, cba.GetCalls()); - - ITestObject tb = (ITestObject)bf.GetObject("directTarget"); - Assert.IsTrue(tb.Name.Equals("Adam")); - Assert.AreEqual(1, cba.GetCalls()); - - ProxyFactoryObject pfb = (ProxyFactoryObject)bf.GetObject("&directTarget"); - Assert.IsTrue(typeof(ITestObject).IsAssignableFrom(pfb.ObjectType), "Has correct object type"); } - [Test] - public void GetObjectTypeWithTargetViaTargetSource() - { - IObjectFactory bf = new XmlObjectFactory( - new ReadOnlyXmlTestResource("proxyFactoryTargetSourceTests.xml", - GetType())); - ITestObject tb = (ITestObject)bf.GetObject("viaTargetSource"); - Assert.IsTrue(tb.Name.Equals("Adam")); - ProxyFactoryObject pfb = (ProxyFactoryObject)bf.GetObject("&viaTargetSource"); - Assert.IsTrue(typeof(ITestObject).IsAssignableFrom(pfb.ObjectType), "Has correct object type"); - } + // Now check non-effect of removing interceptor that isn't there + ITestObject it = (ITestObject) factory.GetObject("test2"); + config = (IAdvised) it; - [Test] - public void GetObjectTypeWithNoTargetOrTargetSource() - { - IObjectFactory bf = - new XmlObjectFactory(new ReadOnlyXmlTestResource("proxyFactoryTargetSourceTests.xml", GetType())); - bf.GetObject("noTarget"); - IFactoryObject pfb = (ProxyFactoryObject)bf.GetObject("&noTarget"); - Assert.IsTrue(typeof(ITestObject).IsAssignableFrom(pfb.ObjectType), "Has correct object type"); - } + oldCount = config.Advisors.Count; + config.RemoveAdvice(new DebugAdvice()); + Assert.IsTrue(config.Advisors.Count == oldCount); - /// - /// The instances are equal, but do not have object identity. - /// Interceptors and interfaces and the target are the same. - /// - [Test] - public void SingletonInstancesAreEqual() - { - ITestObject test1 = (ITestObject)factory.GetObject("test1"); - ITestObject test1_1 = (ITestObject)factory.GetObject("test1"); - Assert.AreEqual(test1, test1_1, "Singleton instances =="); - test1.Age = 25; - Assert.AreEqual(test1.Age, test1_1.Age); - test1.Age = 250; - Assert.AreEqual(test1.Age, test1_1.Age); - IAdvised pc1 = (IAdvised)test1; - IAdvised pc2 = (IAdvised)test1_1; - Assert.AreEqual(pc1.Advisors, pc2.Advisors); - int oldLength = pc1.Advisors.Count; - NopInterceptor di = new NopInterceptor(); - pc1.AddAdvice(1, di); - Assert.AreEqual(pc1.Advisors, pc2.Advisors); - Assert.AreEqual(oldLength + 1, pc2.Advisors.Count, "Now have one more advisor"); - Assert.AreEqual(di.Count, 0); - test1.Age = (5); - Assert.AreEqual(test1_1.Age, test1.Age); - Assert.AreEqual(3, di.Count); - } + DebugAdvice debugInterceptor = new DebugAdvice(); + config.AddAdvice(0, debugInterceptor); + object foo = it.Spouse; + Assert.AreEqual(1, debugInterceptor.Count); + config.RemoveAdvice(debugInterceptor); + foo = it.Spouse; + // not invoked again + Assert.IsTrue(debugInterceptor.Count == 1); + } - [Test] - public void PrototypeInstancesAreNotEqual() - { - ITestObject test2 = (ITestObject)factory.GetObject("prototype"); - ITestObject test2_1 = (ITestObject)factory.GetObject("prototype"); - Assert.IsTrue(test2 != test2_1, "Prototype instances !="); - Assert.IsTrue(TestObject.Equals(test2, test2_1), "Prototype instances equal"); - } + /// + /// Note that we can't add or remove interfaces without reconfiguring the + /// singleton. + /// + [Test] + public void CanAddAndRemoveAspectInterfacesOnSingletonByCasting() + { + ITestObject it = (ITestObject) factory.GetObject("test1"); + IAdvised pc = (IAdvised) it; + object name = it.Age; + NopInterceptor di = new NopInterceptor(); + pc.AddAdvice(0, di); + Assert.AreEqual(0, di.Count); + it.Age = 25; + Assert.AreEqual(25, it.Age); + Assert.AreEqual(2, di.Count); + } - [Test] - public void PrototypeInstancesAreIndependent() - { - IObjectFactory objectFactory = new XmlObjectFactory(new ReadOnlyXmlTestResource("prototypeTests.xml", GetType())); - // Initial count value set in object factory XML - int INITIAL_COUNT = 10; - - - // Check it works without AOP - ISideEffectObject raw = (ISideEffectObject)objectFactory.GetObject("prototypeTarget"); - Assert.AreEqual(INITIAL_COUNT, raw.Count); - raw.doWork(); - Assert.AreEqual(INITIAL_COUNT + 1, raw.Count); - raw = (ISideEffectObject)objectFactory.GetObject("prototypeTarget"); - Assert.AreEqual(INITIAL_COUNT, raw.Count); - - // Now try with advised instances - ISideEffectObject prototype2FirstInstance = (ISideEffectObject)objectFactory.GetObject("prototype"); - Assert.AreEqual(INITIAL_COUNT, prototype2FirstInstance.Count); - prototype2FirstInstance.doWork(); - Assert.AreEqual(INITIAL_COUNT + 1, prototype2FirstInstance.Count); - - ISideEffectObject prototype2SecondInstance = (ISideEffectObject)objectFactory.GetObject("prototype"); - Assert.IsFalse(prototype2FirstInstance == prototype2SecondInstance, "Prototypes are not =="); - Assert.AreEqual(INITIAL_COUNT, prototype2SecondInstance.Count); - Assert.AreEqual(INITIAL_COUNT + 1, prototype2FirstInstance.Count); - - - } - - - /// Test invoker is automatically added to manipulate target - [Test] - public void AutoInvoker() - { - String name = "Hieronymous"; - TestObject target = (TestObject)factory.GetObject("test"); - target.Name = name; - ITestObject autoInvoker = (ITestObject)factory.GetObject("autoInvoker"); - Assert.IsTrue(autoInvoker.Name.Equals(name)); - } - - [Test] - public void CanGetFactoryReferenceAndManipulate() - { - ITestObject to = (ITestObject)factory.GetObject("test1"); - // no exception - string dummy = to.Name; - - IAdvised config = (IAdvised)to; - Assert.AreEqual(1, config.Advisors.Count, "Object should have only one advisors"); - - Exception ex = new NotSupportedException("Invoke"); - // Add evil interceptor to head of list - config.AddAdvice(0, new EvilMethodInterceptor(ex)); - Assert.AreEqual(2, config.Advisors.Count, "The advisor count is wrong after adding an advisor programmatically."); - - try - { - // evil interceptor should throw exception - dummy = to.Name; - Assert.Fail("Evil interceptor added programmatically should fail all method calls, but it didn't"); - } - catch (Exception thrown) - { - Assert.AreEqual(thrown, ex, "The thrown exception is not the one we were looking for."); - } - } - - /// - /// Must see effect immediately on behaviour. - /// TODO (EE): Note that we can't add or remove interfaces without reconfiguring the singleton. - /// - [Test, Ignore("change according to ProxyFactoryBeanTests.canAddAndRemoveAdvicesOnSingleton")] - public void CanAddAndRemoveIntroductionsOnSingleton() - { - try - { - ITimeStamped ts = (ITimeStamped)factory.GetObject("test1"); - Assert.Fail("Shouldn't implement ITimeStamped before manipulation"); - } - catch (InvalidCastException) - { - } - - ProxyFactoryObject config = (ProxyFactoryObject)factory.GetObject("&test1"); - long time = 666L; - TimestampIntroductionInterceptor ti = new TimestampIntroductionInterceptor(); - ti.TimeStamp = new DateTime(time); - IIntroductionAdvisor advisor = new DefaultIntroductionAdvisor(ti, typeof(ITimeStamped)); - - // add to front of introduction chain - int oldCount = config.Introductions.Count; - config.AddIntroduction(0, advisor); - Assert.IsTrue(config.Introductions.Count == oldCount + 1); - - ITimeStamped ts2 = (ITimeStamped)factory.GetObject("test1"); - Assert.IsTrue(ts2.TimeStamp == new DateTime(time)); - - // Can remove - config.RemoveIntroduction(advisor); - Assert.IsTrue(config.Introductions.Count == oldCount); - - // Existing reference will still work - object o = ts2.TimeStamp; - - // But new proxies should not implement ITimeStamped - try - { - ts2 = (ITimeStamped)factory.GetObject("test1"); - Assert.Fail("Should no longer implement ITimeStamped"); - } - catch (InvalidCastException) - { - // expected... - } - - // Now check non-effect of removing interceptor that isn't there - oldCount = config.Advisors.Count; - config.RemoveAdvice(new DebugAdvice()); - Assert.IsTrue(config.Advisors.Count == oldCount); - - ITestObject it = (ITestObject)ts2; - DebugAdvice debugInterceptor = new DebugAdvice(); - config.AddAdvice(0, debugInterceptor); - object foo = it.Spouse; - Assert.AreEqual(1, debugInterceptor.Count); - config.RemoveAdvice(debugInterceptor); - foo = it.Spouse; - // not invoked again - Assert.IsTrue(debugInterceptor.Count == 1); - } - - /// Try adding and removing interfaces and interceptors on prototype. - /// Changes will only affect future references obtained from the factory. - /// Each instance will be independent. - /// - [Test] - public void CanAddAndRemoveAspectInterfacesOnPrototype() - { - try - { - ITimeStamped ts = (ITimeStamped)factory.GetObject("test2"); - Assert.Fail("Shouldn't implement ITimeStamped before manipulation"); - } - catch (InvalidCastException) - { - } - - IAdvised config = (IAdvised)factory.GetObject("&test2"); - long time = 666L; - TimestampIntroductionInterceptor ti = new TimestampIntroductionInterceptor(); - ti.TimeStamp = new DateTime(time); - IIntroductionAdvisor advisor = new DefaultIntroductionAdvisor(ti, typeof(ITimeStamped)); - - // add to front of introduction chain - int oldCount = config.Introductions.Count; - config.AddIntroduction(0, advisor); - Assert.IsTrue(config.Introductions.Count == oldCount + 1); - - ITimeStamped ts2 = (ITimeStamped)factory.GetObject("test2"); - Assert.IsTrue(ts2.TimeStamp == new DateTime(time)); - - // Can remove - config.RemoveIntroduction(advisor); - Assert.IsTrue(config.Introductions.Count == oldCount); - - // Existing reference will still work - object o = ts2.TimeStamp; - - // But new proxies should not implement ITimeStamped - try - { - ts2 = (ITimeStamped)factory.GetObject("test2"); - Assert.Fail("Should no longer implement ITimeStamped"); - } - catch (InvalidCastException) - { - } - - // Now check non-effect of removing interceptor that isn't there - ITestObject it = (ITestObject)factory.GetObject("test2"); - config = (IAdvised)it; - - oldCount = config.Advisors.Count; - config.RemoveAdvice(new DebugAdvice()); - Assert.IsTrue(config.Advisors.Count == oldCount); - - DebugAdvice debugInterceptor = new DebugAdvice(); - config.AddAdvice(0, debugInterceptor); - object foo = it.Spouse; - Assert.AreEqual(1, debugInterceptor.Count); - config.RemoveAdvice(debugInterceptor); - foo = it.Spouse; - // not invoked again - Assert.IsTrue(debugInterceptor.Count == 1); - } - - /// - /// Note that we can't add or remove interfaces without reconfiguring the - /// singleton. - /// - [Test] - public void CanAddAndRemoveAspectInterfacesOnSingletonByCasting() - { - ITestObject it = (ITestObject)factory.GetObject("test1"); - IAdvised pc = (IAdvised)it; - object name = it.Age; - NopInterceptor di = new NopInterceptor(); - pc.AddAdvice(0, di); - Assert.AreEqual(0, di.Count); - it.Age = 25; - Assert.AreEqual(25, it.Age); - Assert.AreEqual(2, di.Count); - } - - [Test] - public void MethodPointcuts() - { - ITestObject tb = (ITestObject)factory.GetObject("pointcuts"); - PointcutForVoid.Reset(); - Assert.IsTrue((PointcutForVoid.methodNames.Count == 0), "No methods intercepted"); - object o = tb.Age; - Assert.IsTrue((PointcutForVoid.methodNames.Count == 0), "Not void: shouldn't have intercepted"); - tb.Age = 1; - o = tb.Age; - tb.Name = "Tristan"; - tb.ToString(); - Assert.AreEqual(2, PointcutForVoid.methodNames.Count, "Recorded wrong number of invocations"); - Assert.AreEqual("set_Age", PointcutForVoid.methodNames[0]); - Assert.AreEqual("set_Name", PointcutForVoid.methodNames[1]); - } + [Test] + public void MethodPointcuts() + { + ITestObject tb = (ITestObject) factory.GetObject("pointcuts"); + PointcutForVoid.Reset(); + Assert.IsTrue((PointcutForVoid.methodNames.Count == 0), "No methods intercepted"); + object o = tb.Age; + Assert.IsTrue((PointcutForVoid.methodNames.Count == 0), "Not void: shouldn't have intercepted"); + tb.Age = 1; + o = tb.Age; + tb.Name = "Tristan"; + tb.ToString(); + Assert.AreEqual(2, PointcutForVoid.methodNames.Count, "Recorded wrong number of invocations"); + Assert.AreEqual("set_Age", PointcutForVoid.methodNames[0]); + Assert.AreEqual("set_Name", PointcutForVoid.methodNames[1]); + } #if !NETCOREAPP [Test] @@ -401,7 +395,7 @@ namespace Spring.Aop.Framework { IObjectFactory f = new XmlObjectFactory(new ReadOnlyXmlTestResource("throwsAdvice.xml", GetType())); var th = (Spring.Aop.Framework.Adapter.ThrowsAdviceInterceptorTests.MyThrowsHandler) f.GetObject("throwsAdvice"); - CountingBeforeAdvice cba = (CountingBeforeAdvice)f.GetObject("countingBeforeAdvice"); + CountingBeforeAdvice cba = (CountingBeforeAdvice) f.GetObject("countingBeforeAdvice"); Assert.AreEqual(0, cba.GetCalls()); Assert.AreEqual(0, th.GetCalls()); var echo = (Spring.Aop.Framework.Adapter.ThrowsAdviceInterceptorTests.IEcho) f.GetObject("throwsAdvised"); @@ -418,6 +412,7 @@ namespace Spring.Aop.Framework { Assert.AreEqual(expected, ex); } + // No throws handler method: count should still be 0 Assert.AreEqual(0, th.GetCalls()); @@ -432,341 +427,343 @@ namespace Spring.Aop.Framework { Assert.AreEqual(expected, ex); } + // One match Assert.AreEqual(1, th.GetCalls("HttpException")); } #endif - /// Checks that globals get invoked, - /// and that they can add aspect interfaces unavailable - /// to other objects. These interfaces don't need - /// to be included in proxiedInterface []. - /// - [Test] - public void GlobalsCanAddAspectInterfaces() + /// Checks that globals get invoked, + /// and that they can add aspect interfaces unavailable + /// to other objects. These interfaces don't need + /// to be included in proxiedInterface []. + /// + [Test] + public void GlobalsCanAddAspectInterfaces() + { + IAddedGlobalInterface agi = (IAddedGlobalInterface) factory.GetObject("autoInvoker"); + Assert.IsTrue(agi.GlobalsAdded == -1); + + ProxyFactoryObject pfb = (ProxyFactoryObject) factory.GetObject("&validGlobals"); + pfb.GetObject(); // for creation + Assert.AreEqual(2, pfb.Advisors.Count, "Proxy should have 1 global and 1 explicit advisor"); + Assert.AreEqual(1, pfb.Introductions.Count, "Proxy should have 1 global introduction"); + + agi.GlobalsAdded = ((IAdvised) agi).Introductions.Count; + Assert.IsTrue(agi.GlobalsAdded == 1); + + IApplicationEventListener l = (IApplicationEventListener) factory.GetObject("validGlobals"); + agi = (IAddedGlobalInterface) l; + Assert.IsTrue(agi.GlobalsAdded == -1); + Assert.Throws(() => factory.GetObject("test1")); + } + + [Test] + public void IsSingletonFalseReturnsNew_ProxyInstance_NotNewProxyTargetSource() + { + GoodCommand target = new GoodCommand(); + IObjectFactory mock = A.Fake(); + A.CallTo(() => mock.GetObject("singleton")).Returns(target).Twice(); + + ProxyFactoryObject fac = new ProxyFactoryObject(); + fac.ProxyInterfaces = new string[] { typeof(ICommand).FullName }; + fac.IsSingleton = false; + fac.TargetName = "singleton"; + fac.ObjectFactory = mock; + fac.AddAdvice(new NopInterceptor()); + + ICommand one = (ICommand) fac.GetObject(); + ICommand two = (ICommand) fac.GetObject(); + Assert.IsFalse(ReferenceEquals(one, two)); + } + + [Test] + public void IsSingletonTrueReturnsNew_ProxyInstance_NotNewProxyTargetSource() + { + GoodCommand target = new GoodCommand(); + IObjectFactory mock = A.Fake(); + A.CallTo(() => mock.GetObject("singleton")).Returns(target); + + ProxyFactoryObject fac = new ProxyFactoryObject(); + fac.ProxyInterfaces = new string[] { typeof(ICommand).FullName }; + fac.IsSingleton = true; // default, just being explicit... + fac.TargetName = "singleton"; + fac.ObjectFactory = mock; + fac.AddAdvice(new NopInterceptor()); + + ICommand one = (ICommand) fac.GetObject(); + ICommand two = (ICommand) fac.GetObject(); + Assert.IsTrue(ReferenceEquals(one, two)); + } + + private ProxyFactoryObject CreateFrozenProxyFactory() + { + ProxyFactoryObject fac = new ProxyFactoryObject(); + fac.AddInterface(typeof(ITestObject)); + fac.IsFrozen = true; + fac.AddAdvisor(new PointcutForVoid()); // this is ok, no proxy created yet + fac.GetObject(); + return fac; + } + + [Test] + public void AddAdvisorWhenConfigIsFrozen() + { + ProxyFactoryObject fac = CreateFrozenProxyFactory(); + try { - IAddedGlobalInterface agi = (IAddedGlobalInterface) factory.GetObject("autoInvoker"); - Assert.IsTrue(agi.GlobalsAdded == -1); - - ProxyFactoryObject pfb = (ProxyFactoryObject) factory.GetObject("&validGlobals"); - pfb.GetObject(); // for creation - Assert.AreEqual(2, pfb.Advisors.Count, "Proxy should have 1 global and 1 explicit advisor"); - Assert.AreEqual(1, pfb.Introductions.Count, "Proxy should have 1 global introduction"); - - agi.GlobalsAdded = ((IAdvised) agi).Introductions.Count; - Assert.IsTrue(agi.GlobalsAdded == 1); - - IApplicationEventListener l = (IApplicationEventListener) factory.GetObject("validGlobals"); - agi = (IAddedGlobalInterface) l; - Assert.IsTrue(agi.GlobalsAdded == -1); - Assert.Throws(() => factory.GetObject("test1")); + fac.AddAdvisor(new PointcutForVoid()); // not ok + Assert.Fail("changing a frozen config must throw AopConfigException"); } - - [Test] - public void IsSingletonFalseReturnsNew_ProxyInstance_NotNewProxyTargetSource() + catch (AopConfigException) { - GoodCommand target = new GoodCommand(); - IObjectFactory mock = A.Fake(); - A.CallTo(() => mock.GetObject("singleton")).Returns(target).Twice(); + } + } + + [Test] + public void RemoveAdvisorWhenConfigIsFrozen() + { + ProxyFactoryObject fac = CreateFrozenProxyFactory(); + fac.IsFrozen = true; + Assert.Throws(() => fac.RemoveAdvisor(new PointcutForVoid())); + } + + [Test] + public void ReplaceAdvisorWhenConfigIsFrozen() + { + ProxyFactoryObject fac = CreateFrozenProxyFactory(); + fac.IsFrozen = true; + Assert.Throws(() => fac.ReplaceAdvisor(new PointcutForVoid(), new PointcutForVoid())); + } + + [Test] + public void TargetAtEndOfInterceptorList() + { + GoodCommand target = new GoodCommand(); + NopInterceptor advice = new NopInterceptor(); + + IObjectFactory mock = A.Fake(); + A.CallTo(() => mock.GetObject("advice")).Returns(advice); + A.CallTo(() => mock.GetObject("singleton")).Returns(target); + A.CallTo(() => mock.GetType("singleton")).Returns(typeof(GoodCommand)); + + ProxyFactoryObject fac = new ProxyFactoryObject(); + fac.ProxyInterfaces = new string[] { typeof(ICommand).FullName }; + fac.IsSingleton = true; // default, just being explicit... + fac.InterceptorNames = new string[] { "advice", "singleton" }; + fac.ObjectFactory = mock; + + ICommand one = (ICommand) fac.GetObject(); + ICommand two = (ICommand) fac.GetObject(); + Assert.IsTrue(ReferenceEquals(one, two)); + one.Execute(); + Assert.AreEqual(1, advice.Count); + two.Execute(); + Assert.AreEqual(2, advice.Count); + } + + [Test] + public void MakeSurePrototypeTargetIsNotNeedlesslyCreatedDuringInitialization_Unit() + { + GoodCommand target = new GoodCommand(); + NopInterceptor advice = new NopInterceptor(); + + IObjectFactory factory = A.Fake(); + + ProxyFactoryObject fac = new ProxyFactoryObject(); + fac.ProxyInterfaces = new[] { typeof(ICommand).FullName }; + fac.IsSingleton = false; + fac.InterceptorNames = new[] { "advice", "prototype" }; + fac.ObjectFactory = factory; + + A.CallTo(() => factory.IsSingleton("advice")).Returns(true); + A.CallTo(() => factory.GetObject("advice")).Returns(advice); + A.CallTo(() => factory.GetType("prototype")).Returns(target.GetType()); + A.CallTo(() => factory.GetObject("prototype")).Returns(target); + + fac.GetObject(); + } + + [Test] + public void MakeSurePrototypeTargetIsNotNeedlesslyCreatedDuringInitialization_Integration() + { + try + { + RootObjectDefinition advice = new RootObjectDefinition(typeof(NopInterceptor)); + // prototype target... + RootObjectDefinition target = new RootObjectDefinition(typeof(InstantiationCountingCommand), false); + + DefaultListableObjectFactory ctx = new DefaultListableObjectFactory(); + ctx.RegisterObjectDefinition("advice", advice); + ctx.RegisterObjectDefinition("prototype", target); ProxyFactoryObject fac = new ProxyFactoryObject(); fac.ProxyInterfaces = new string[] { typeof(ICommand).FullName }; fac.IsSingleton = false; - fac.TargetName = "singleton"; - fac.ObjectFactory = mock; - fac.AddAdvice(new NopInterceptor()); + fac.InterceptorNames = new string[] { "advice", "prototype" }; + fac.ObjectFactory = ctx; - ICommand one = (ICommand)fac.GetObject(); - ICommand two = (ICommand)fac.GetObject(); - Assert.IsFalse(ReferenceEquals(one, two)); - } - - [Test] - public void IsSingletonTrueReturnsNew_ProxyInstance_NotNewProxyTargetSource() - { - GoodCommand target = new GoodCommand(); - IObjectFactory mock = A.Fake(); - A.CallTo(() => mock.GetObject("singleton")).Returns(target); - - ProxyFactoryObject fac = new ProxyFactoryObject(); - fac.ProxyInterfaces = new string[] { typeof(ICommand).FullName }; - fac.IsSingleton = true; // default, just being explicit... - fac.TargetName = "singleton"; - fac.ObjectFactory = mock; - fac.AddAdvice(new NopInterceptor()); - - ICommand one = (ICommand)fac.GetObject(); - ICommand two = (ICommand)fac.GetObject(); - Assert.IsTrue(ReferenceEquals(one, two)); - } - - private ProxyFactoryObject CreateFrozenProxyFactory() - { - ProxyFactoryObject fac = new ProxyFactoryObject(); - fac.AddInterface(typeof(ITestObject)); - fac.IsFrozen = true; - fac.AddAdvisor(new PointcutForVoid()); // this is ok, no proxy created yet + Assert.AreEqual(0, InstantiationCountingCommand.NumberOfInstantiations, + "Prototype target instance is being (needlessly) created during PFO initialization."); fac.GetObject(); - return fac; - } - - [Test] - public void AddAdvisorWhenConfigIsFrozen() - { - ProxyFactoryObject fac = CreateFrozenProxyFactory(); - try - { - fac.AddAdvisor(new PointcutForVoid()); // not ok - Assert.Fail("changing a frozen config must throw AopConfigException"); - } - catch (AopConfigException) - {} - } - - [Test] - public void RemoveAdvisorWhenConfigIsFrozen() - { - ProxyFactoryObject fac = CreateFrozenProxyFactory(); - fac.IsFrozen = true; - Assert.Throws(() => fac.RemoveAdvisor(new PointcutForVoid())); - } - - [Test] - public void ReplaceAdvisorWhenConfigIsFrozen() - { - ProxyFactoryObject fac = CreateFrozenProxyFactory(); - fac.IsFrozen = true; - Assert.Throws(() => fac.ReplaceAdvisor(new PointcutForVoid(), new PointcutForVoid())); - } - - [Test] - public void TargetAtEndOfInterceptorList() - { - GoodCommand target = new GoodCommand(); - NopInterceptor advice = new NopInterceptor(); - - IObjectFactory mock = A.Fake(); - A.CallTo(() => mock.GetObject("advice")).Returns(advice); - A.CallTo(() => mock.GetObject("singleton")).Returns(target); - A.CallTo(() => mock.GetType("singleton")).Returns(typeof(GoodCommand)); - - ProxyFactoryObject fac = new ProxyFactoryObject(); - fac.ProxyInterfaces = new string[] { typeof(ICommand).FullName }; - fac.IsSingleton = true; // default, just being explicit... - fac.InterceptorNames = new string[] { "advice", "singleton" }; - fac.ObjectFactory = mock; - - ICommand one = (ICommand)fac.GetObject(); - ICommand two = (ICommand)fac.GetObject(); - Assert.IsTrue(ReferenceEquals(one, two)); - one.Execute(); - Assert.AreEqual(1, advice.Count); - two.Execute(); - Assert.AreEqual(2, advice.Count); - } - - [Test] - public void MakeSurePrototypeTargetIsNotNeedlesslyCreatedDuringInitialization_Unit() - { - GoodCommand target = new GoodCommand(); - NopInterceptor advice = new NopInterceptor(); - - IObjectFactory factory = A.Fake(); - - ProxyFactoryObject fac = new ProxyFactoryObject(); - fac.ProxyInterfaces = new[] {typeof(ICommand).FullName}; - fac.IsSingleton = false; - fac.InterceptorNames = new[] {"advice", "prototype"}; - fac.ObjectFactory = factory; - - A.CallTo(() => factory.IsSingleton("advice")).Returns(true); - A.CallTo(() => factory.GetObject("advice")).Returns(advice); - A.CallTo(() => factory.GetType("prototype")).Returns(target.GetType()); - A.CallTo(() => factory.GetObject("prototype")).Returns(target); - + Assert.AreEqual(1, InstantiationCountingCommand.NumberOfInstantiations, "Expected 1 inst"); fac.GetObject(); + Assert.AreEqual(2, InstantiationCountingCommand.NumberOfInstantiations); } - - [Test] - public void MakeSurePrototypeTargetIsNotNeedlesslyCreatedDuringInitialization_Integration() + finally { - try - { - RootObjectDefinition advice = new RootObjectDefinition(typeof(NopInterceptor)); - // prototype target... - RootObjectDefinition target = new RootObjectDefinition(typeof(InstantiationCountingCommand), false); - - DefaultListableObjectFactory ctx = new DefaultListableObjectFactory(); - ctx.RegisterObjectDefinition("advice", advice); - ctx.RegisterObjectDefinition("prototype", target); - - ProxyFactoryObject fac = new ProxyFactoryObject(); - fac.ProxyInterfaces = new string[] { typeof(ICommand).FullName }; - fac.IsSingleton = false; - fac.InterceptorNames = new string[] { "advice", "prototype" }; - fac.ObjectFactory = ctx; - - Assert.AreEqual(0, InstantiationCountingCommand.NumberOfInstantiations, - "Prototype target instance is being (needlessly) created during PFO initialization."); - fac.GetObject(); - Assert.AreEqual(1, InstantiationCountingCommand.NumberOfInstantiations, "Expected 1 inst"); - fac.GetObject(); - Assert.AreEqual(2, InstantiationCountingCommand.NumberOfInstantiations); - } - finally - { - InstantiationCountingCommand.NumberOfInstantiations = 0; - } + InstantiationCountingCommand.NumberOfInstantiations = 0; } + } - [Test] - public void SingletonProxyWithPrototypeTargetCreatesTargetOnlyOnce() + [Test] + public void SingletonProxyWithPrototypeTargetCreatesTargetOnlyOnce() + { + try { - try - { - RootObjectDefinition advice = new RootObjectDefinition(typeof(NopInterceptor)); - // prototype target... - RootObjectDefinition target = new RootObjectDefinition(typeof(InstantiationCountingCommand), false); + RootObjectDefinition advice = new RootObjectDefinition(typeof(NopInterceptor)); + // prototype target... + RootObjectDefinition target = new RootObjectDefinition(typeof(InstantiationCountingCommand), false); - DefaultListableObjectFactory ctx = new DefaultListableObjectFactory(); - ctx.RegisterObjectDefinition("advice", advice); - ctx.RegisterObjectDefinition("prototype", target); - - ProxyFactoryObject fac = new ProxyFactoryObject(); - fac.ProxyInterfaces = new string[] { typeof(ICommand).FullName }; - fac.IsSingleton = true; - fac.InterceptorNames = new string[] { "advice", "prototype" }; - fac.ObjectFactory = ctx; - - Assert.AreEqual(0, InstantiationCountingCommand.NumberOfInstantiations, "First Call"); - fac.GetObject(); - Assert.AreEqual(1, InstantiationCountingCommand.NumberOfInstantiations, "Second Call"); - fac.GetObject(); - Assert.AreEqual(1, InstantiationCountingCommand.NumberOfInstantiations, "Third Call"); - } - - finally - { - InstantiationCountingCommand.NumberOfInstantiations = 0; - } - } - - public class InstantiationCountingCommand : ICommand - { - private static int numberOfInstantiations = 0; - - public InstantiationCountingCommand() - { - ++numberOfInstantiations; - } - - public static int NumberOfInstantiations - { - get { return numberOfInstantiations; } - set { numberOfInstantiations = value; } - } - - public void Execute() - { - } - } - - [Test] - public void NullNameInInterceptorNamesArrayThrowAopConfigException() - { - IObjectFactory factory = A.Fake(); + DefaultListableObjectFactory ctx = new DefaultListableObjectFactory(); + ctx.RegisterObjectDefinition("advice", advice); + ctx.RegisterObjectDefinition("prototype", target); ProxyFactoryObject fac = new ProxyFactoryObject(); fac.ProxyInterfaces = new string[] { typeof(ICommand).FullName }; - fac.IsSingleton = false; - fac.InterceptorNames = new string[] { null, null }; - fac.ObjectFactory = factory; - Assert.Throws(() => fac.GetObject()); + fac.IsSingleton = true; + fac.InterceptorNames = new string[] { "advice", "prototype" }; + fac.ObjectFactory = ctx; + + Assert.AreEqual(0, InstantiationCountingCommand.NumberOfInstantiations, "First Call"); + fac.GetObject(); + Assert.AreEqual(1, InstantiationCountingCommand.NumberOfInstantiations, "Second Call"); + fac.GetObject(); + Assert.AreEqual(1, InstantiationCountingCommand.NumberOfInstantiations, "Third Call"); } - [Test] - public void PassEmptyInterceptorNamesArray_WithTargetThatImplementsAnInterfaceCanBeCastToSaidInterface() + finally { - IObjectFactory factory = A.Fake(); - - ProxyFactoryObject fac = new ProxyFactoryObject(); - fac.ProxyInterfaces = new string[] { }; - fac.Target = new GoodCommand(); - fac.ObjectFactory = factory; - - IAdvised advised = fac.GetObject() as IAdvised; - Assert.IsNotNull(advised); - - ICommand cmd = fac.GetObject() as ICommand; - Assert.IsNotNull(cmd); - - DoesntImplementAnyInterfaces obj = fac.GetObject() as DoesntImplementAnyInterfaces; - Assert.IsNull(obj); + InstantiationCountingCommand.NumberOfInstantiations = 0; } + } - [Test] - public void PassNullToTheProxyInterfacesProperty() + public class InstantiationCountingCommand : ICommand + { + private static int numberOfInstantiations = 0; + + public InstantiationCountingCommand() { - ProxyFactoryObject fac = new ProxyFactoryObject(); - Assert.Throws(() => fac.ProxyInterfaces = null); + ++numberOfInstantiations; } - [Test] - public void PassClassNotInterfaceNameToTheProxyInterfacesProperty() + public static int NumberOfInstantiations { - ProxyFactoryObject fac = new ProxyFactoryObject(); - Assert.Throws(() => fac.ProxyInterfaces = new string[] { typeof(GoodCommand).FullName }); + get { return numberOfInstantiations; } + set { numberOfInstantiations = value; } } - [Test] - public void PassRubbishNameToTheProxyInterfacesProperty() + public void Execute() { - ProxyFactoryObject fac = new ProxyFactoryObject(); - Assert.Throws(() => fac.ProxyInterfaces = new string[] { "Hey" }); } + } - [Test] - public void PassNullElementListToTheProxyInterfacesProperty() + [Test] + public void NullNameInInterceptorNamesArrayThrowAopConfigException() + { + IObjectFactory factory = A.Fake(); + + ProxyFactoryObject fac = new ProxyFactoryObject(); + fac.ProxyInterfaces = new string[] { typeof(ICommand).FullName }; + fac.IsSingleton = false; + fac.InterceptorNames = new string[] { null, null }; + fac.ObjectFactory = factory; + Assert.Throws(() => fac.GetObject()); + } + + [Test] + public void PassEmptyInterceptorNamesArray_WithTargetThatImplementsAnInterfaceCanBeCastToSaidInterface() + { + IObjectFactory factory = A.Fake(); + + ProxyFactoryObject fac = new ProxyFactoryObject(); + fac.ProxyInterfaces = new string[] { }; + fac.Target = new GoodCommand(); + fac.ObjectFactory = factory; + + IAdvised advised = fac.GetObject() as IAdvised; + Assert.IsNotNull(advised); + + ICommand cmd = fac.GetObject() as ICommand; + Assert.IsNotNull(cmd); + + DoesntImplementAnyInterfaces obj = fac.GetObject() as DoesntImplementAnyInterfaces; + Assert.IsNull(obj); + } + + [Test] + public void PassNullToTheProxyInterfacesProperty() + { + ProxyFactoryObject fac = new ProxyFactoryObject(); + Assert.Throws(() => fac.ProxyInterfaces = null); + } + + [Test] + public void PassClassNotInterfaceNameToTheProxyInterfacesProperty() + { + ProxyFactoryObject fac = new ProxyFactoryObject(); + Assert.Throws(() => fac.ProxyInterfaces = new string[] { typeof(GoodCommand).FullName }); + } + + [Test] + public void PassRubbishNameToTheProxyInterfacesProperty() + { + ProxyFactoryObject fac = new ProxyFactoryObject(); + Assert.Throws(() => fac.ProxyInterfaces = new string[] { "Hey" }); + } + + [Test] + public void PassNullElementListToTheProxyInterfacesProperty() + { + ProxyFactoryObject fac = new ProxyFactoryObject(); + Assert.Throws(() => fac.ProxyInterfaces = new string[] { null }); + } + + [Test] + public void ProxiedObjectUnwrapsTargetInvocationException() + { + ProxyFactoryObject fac = new ProxyFactoryObject(); + fac.AddInterface(typeof(ICommand)); + fac.AddAdvice(new NopInterceptor()); + fac.Target = new BadCommand(); + + ICommand cmd = (ICommand) fac.GetObject(); + try { - ProxyFactoryObject fac = new ProxyFactoryObject(); - Assert.Throws(() => fac.ProxyInterfaces = new string[] { null }); + cmd.Execute(); } - - [Test] - public void ProxiedObjectUnwrapsTargetInvocationException() + catch (NotImplementedException) { - ProxyFactoryObject fac = new ProxyFactoryObject(); - fac.AddInterface(typeof(ICommand)); - fac.AddAdvice(new NopInterceptor()); - fac.Target = new BadCommand(); - - ICommand cmd = (ICommand)fac.GetObject(); - try - { - cmd.Execute(); - } - catch (NotImplementedException) - { - // this is good, we want this exception to bubble up... - } - catch (TargetInvocationException) - { - Assert.Fail("Must have unwrapped this."); - } + // this is good, we want this exception to bubble up... } - - [Test] - public void FactoryWrapsObjectInSingletonTargetSource() + catch (TargetInvocationException) { - IObjectFactory bf = new XmlObjectFactory( - new ReadOnlyXmlTestResource("proxyFactoryTargetSourceTests.xml", - GetType())); - ITestObject tb = (ITestObject)bf.GetObject("viaTargetSource"); - Assert.IsTrue(tb.Name.Equals("Adam")); - ProxyFactoryObject pfb = (ProxyFactoryObject)bf.GetObject("&viaTargetSource"); - Assert.IsTrue(typeof(ITestObject).IsAssignableFrom(pfb.ObjectType), "Has correct object type"); - Assert.AreEqual(typeof(SingletonTargetSource), pfb.TargetSource.GetType(), "Incorrect target source, expected singleton"); + Assert.Fail("Must have unwrapped this."); } + } + + [Test] + public void FactoryWrapsObjectInSingletonTargetSource() + { + IObjectFactory bf = new XmlObjectFactory( + new ReadOnlyXmlTestResource("proxyFactoryTargetSourceTests.xml", + GetType())); + ITestObject tb = (ITestObject) bf.GetObject("viaTargetSource"); + Assert.IsTrue(tb.Name.Equals("Adam")); + ProxyFactoryObject pfb = (ProxyFactoryObject) bf.GetObject("&viaTargetSource"); + Assert.IsTrue(typeof(ITestObject).IsAssignableFrom(pfb.ObjectType), "Has correct object type"); + Assert.AreEqual(typeof(SingletonTargetSource), pfb.TargetSource.GetType(), "Incorrect target source, expected singleton"); + } #if !NETCOREAPP [Test(Description = "http://opensource.atlassian.com/projects/spring/browse/SPRNET-293")] @@ -800,10 +797,10 @@ namespace Spring.Aop.Framework } #endif - [Test(Description = "http://opensource.atlassian.com/projects/spring/browse/SPRNET-500")] - public void NotAccessibleInterfaceProxying() - { - const string xml = @" + [Test(Description = "http://opensource.atlassian.com/projects/spring/browse/SPRNET-500")] + public void NotAccessibleInterfaceProxying() + { + const string xml = @" @@ -822,260 +819,256 @@ namespace Spring.Aop.Framework "; + MemoryStream stream = new MemoryStream(new UTF8Encoding().GetBytes(xml)); + IResource resource = new InputStreamResource(stream, "Test ProxyFactoryObject"); + XmlObjectFactory objectFactory = new XmlObjectFactory(resource, null); - MemoryStream stream = new MemoryStream(new UTF8Encoding().GetBytes(xml)); - IResource resource = new InputStreamResource(stream, "Test ProxyFactoryObject"); - XmlObjectFactory objectFactory = new XmlObjectFactory(resource, null); + HelperInterface2 hc = (HelperInterface2) objectFactory.GetObject("MyProxy"); + Console.WriteLine(hc.SecondDoSomething()); + } - HelperInterface2 hc = (HelperInterface2)objectFactory.GetObject("MyProxy"); - Console.WriteLine(hc.SecondDoSomething()); + [Test] + public void ProxyFactoryObjectIsThreadSafe() + { + const int WORKERS = 10; + + AsyncTestMethod[] workers = new AsyncTestMethod[WORKERS]; + for (int i = 0; i < WORKERS; i++) + { + workers[i] = new AsyncTestMethod(1, new ThreadStart(CallGetObject)); } - [Test] - public void ProxyFactoryObjectIsThreadSafe() + for (int i = 0; i < WORKERS; i++) { - const int WORKERS = 10; + workers[i].Start(); + } - AsyncTestMethod[] workers = new AsyncTestMethod[WORKERS]; - for(int i=0;i + /// Fires only on void methods. Saves list of methods intercepted. + /// + public class PointcutForVoid : DynamicMethodMatcherPointcutAdvisor + { + private class AnonymousClassMethodInterceptor1 : IMethodInterceptor + { + public Object Invoke(IMethodInvocation invocation) + { + methodNames.Add(invocation.Method.Name); + return invocation.Proceed(); } } - [Test] - public void ProxyTypeDoesntChangeIfSameConfig() - { - ProxyFactoryObject factoryObject = (ProxyFactoryObject) this.factory.GetObject( "&concurrentPrototype" ); - Type testObjectType1 = factoryObject.GetObject().GetType(); - Type testObjectType2 = factoryObject.GetObject().GetType(); + public static IList methodNames; - Assert.AreSame(testObjectType1, testObjectType2); + public static void Reset() + { + methodNames.Clear(); } - [Test] - public void ProxyTypeChangesIfConfigChanges() + public PointcutForVoid() + : base(new AnonymousClassMethodInterceptor1()) { - ProxyFactoryObject factoryObject = (ProxyFactoryObject) this.factory.GetObject( "&concurrentPrototype" ); - Type testObjectType1 = factoryObject.GetObject().GetType(); - - factoryObject.Interfaces = new Type[] {}; - Type testObjectType2 = factoryObject.GetObject().GetType(); - - Assert.AreNotSame( testObjectType1,testObjectType2 ); - } - - #region WorkerThread Class - - public class WorkerThread - { - private Exception _exception; - private Thread _thread; - private WaitCallback _callback; - private object _arg; - - public WorkerThread(string name, WaitCallback callback,object arg) - { - this._arg = arg; - this._callback = callback; - _thread = new Thread( new ThreadStart( Run ) ); - _thread.IsBackground = true; - _thread.Name = name; - } - - public void Start() - { - _thread.Start(); - } - - public void Join() - { - if (_thread.IsAlive) - { - _thread.Join(); - } - } - - public Exception Exception - { - get { return this._exception; } - } - - private void Run() - { - try - { - _callback( _arg ); - } - catch(Exception ex) - { - _exception = ex; - } - } - } - - #endregion WorkerThread Class - - #region Helper Classes - - public interface ICommand - { - void Execute(); - } - - public sealed class BadCommand : ICommand - { - public void Execute() - { - throw new NotImplementedException(); - } - } - - public sealed class GoodCommand : ICommand - { - public void Execute() - { - } - } - - public sealed class RemotableCommand : MarshalByRefObject, ICommand - { - public void Execute() - { - } } /// - /// Fires only on void methods. Saves list of methods intercepted. + /// Must fire only if it returns void. /// - public class PointcutForVoid : DynamicMethodMatcherPointcutAdvisor + public override bool Matches(MethodInfo method, Type targetType, object[] args) { - private class AnonymousClassMethodInterceptor1 : IMethodInterceptor - { - public Object Invoke(IMethodInvocation invocation) - { - methodNames.Add(invocation.Method.Name); - return invocation.Proceed(); - } - } - - public static IList methodNames; - - public static void Reset() - { - methodNames.Clear(); - } - - public PointcutForVoid() - : base(new AnonymousClassMethodInterceptor1()) - { - } - - /// - /// Must fire only if it returns void. - /// - public override bool Matches(MethodInfo method, Type targetType, object[] args) - { - return method.ReturnType == typeof(void); - } - - static PointcutForVoid() - { - methodNames = new ArrayList(); - } + return method.ReturnType == typeof(void); } - /// Aspect interface - public interface IAddedGlobalInterface + static PointcutForVoid() { - int GlobalsAdded { get; set; } - } - - /// Use as a global interceptor. Checks that - /// global interceptors can add aspect interfaces. - /// NB: Add only via global interceptors in XML file. - /// - public class GlobalIntroduction : IAdvice, IAddedGlobalInterface - { - private int globalsAdded = -1; - - public int GlobalsAdded - { - get { return globalsAdded; } - set { globalsAdded = value; } - } - } - - private class EvilMethodInterceptor : IMethodInterceptor - { - private Exception ex; - - public EvilMethodInterceptor(Exception ex) - { - this.ex = ex; - } - - public object Invoke(IMethodInvocation invocation) - { - throw ex; - } - } - - #endregion - } - - #region HelpersForNotAccessibleInterfaceProxyingTest - - public class HelperClassForNotAccessibleInterfaceProxyingTest : HelperInterface1, HelperInterface2 - { - public string FirstDoSomething() - { - return "FirstDoSomething (internal interface implementation)"; - } - - public string SecondDoSomething() - { - return "SecondDoSomething (public interface implementation)"; + methodNames = new ArrayList(); } } - internal interface HelperInterface1 + /// Aspect interface + public interface IAddedGlobalInterface { - string FirstDoSomething(); + int GlobalsAdded { get; set; } } - public interface HelperInterface2 + /// Use as a global interceptor. Checks that + /// global interceptors can add aspect interfaces. + /// NB: Add only via global interceptors in XML file. + /// + public class GlobalIntroduction : IAdvice, IAddedGlobalInterface { - string SecondDoSomething(); + private int globalsAdded = -1; + + public int GlobalsAdded + { + get { return globalsAdded; } + set { globalsAdded = value; } + } + } + + private class EvilMethodInterceptor : IMethodInterceptor + { + private Exception ex; + + public EvilMethodInterceptor(Exception ex) + { + this.ex = ex; + } + + public object Invoke(IMethodInvocation invocation) + { + throw ex; + } } #endregion - - } + +#region HelpersForNotAccessibleInterfaceProxyingTest + +public class HelperClassForNotAccessibleInterfaceProxyingTest : HelperInterface1, HelperInterface2 +{ + public string FirstDoSomething() + { + return "FirstDoSomething (internal interface implementation)"; + } + + public string SecondDoSomething() + { + return "SecondDoSomething (public interface implementation)"; + } +} + +internal interface HelperInterface1 +{ + string FirstDoSomething(); +} + +public interface HelperInterface2 +{ + string SecondDoSomething(); +} + +#endregion diff --git a/test/Spring/Spring.Aop.Tests/Aop/Framework/ProxyFactoryTests.cs b/test/Spring/Spring.Aop.Tests/Aop/Framework/ProxyFactoryTests.cs index a9f968e3..bc47de0e 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Framework/ProxyFactoryTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Framework/ProxyFactoryTests.cs @@ -21,185 +21,93 @@ using System.Runtime.Serialization; using AopAlliance.Aop; using AopAlliance.Intercept; - using FakeItEasy; - using NUnit.Framework; using Spring.Aop.Interceptor; using Spring.Aop.Support; using Spring.Objects; using Spring.Util; -namespace Spring.Aop.Framework +namespace Spring.Aop.Framework; + +/// +/// Unit tests for the ProxyFactory class. +/// +/// Rod Johnson +/// Choy Rim (.NET) +/// Rick Evans (.NET) +[TestFixture] +public sealed class ProxyFactoryTests { - /// - /// Unit tests for the ProxyFactory class. - /// - /// Rod Johnson - /// Choy Rim (.NET) - /// Rick Evans (.NET) - [TestFixture] - public sealed class ProxyFactoryTests + public interface IDoubleClickable { - public interface IDoubleClickable + event EventHandler DoubleClick; + + void FireDoubleClickEvent(); + } + + public interface IDoubleClickableIntroduction : + IDoubleClickable, IAdvice + { + } + + private class DoubleClickableIntroduction : + IDoubleClickableIntroduction + { + public event EventHandler DoubleClick; + + public void FireDoubleClickEvent() { - event EventHandler DoubleClick; - - void FireDoubleClickEvent(); - } - - public interface IDoubleClickableIntroduction : - IDoubleClickable, IAdvice - { - } - - private class DoubleClickableIntroduction : - IDoubleClickableIntroduction - { - public event EventHandler DoubleClick; - - public void FireDoubleClickEvent() + if (DoubleClick != null) { - if (DoubleClick != null) - { - DoubleClick(this, EventArgs.Empty); - } + DoubleClick(this, EventArgs.Empty); } } + } - [Test] - public void AddAndRemoveEventHandlerThroughIntroduction() + [Test] + public void AddAndRemoveEventHandlerThroughIntroduction() + { + TestObject target = new TestObject(); + DoubleClickableIntroduction dci = new DoubleClickableIntroduction(); + DefaultIntroductionAdvisor advisor = new DefaultIntroductionAdvisor(dci); + CountingBeforeAdvice countingBeforeAdvice = new CountingBeforeAdvice(); + target.Name = "SOME-NAME"; + ProxyFactory pf = new ProxyFactory(target); + pf.AddIntroduction(advisor); + pf.AddAdvisor(new DefaultPointcutAdvisor(countingBeforeAdvice)); + object proxy = pf.GetProxy(); + ITestObject to = proxy as ITestObject; + Assert.IsNotNull(to); + Assert.AreEqual("SOME-NAME", to.Name); + IDoubleClickable doubleClickable = proxy as IDoubleClickable; + // add event handler through introduction + doubleClickable.DoubleClick += new EventHandler(OnClick); + OnClickWasCalled = false; + doubleClickable.FireDoubleClickEvent(); + Assert.IsTrue(OnClickWasCalled); + Assert.AreEqual(3, countingBeforeAdvice.GetCalls()); + // remove event handler through introduction + doubleClickable.DoubleClick -= new EventHandler(OnClick); + OnClickWasCalled = false; + doubleClickable.FireDoubleClickEvent(); + Assert.IsFalse(OnClickWasCalled); + Assert.AreEqual(5, countingBeforeAdvice.GetCalls()); + } + + private bool OnClickWasCalled = false; + + private void OnClick(object sender, EventArgs e) + { + OnClickWasCalled = true; + } + + [Test] + public void CacheTest() + { + for (int i = 0; i < 2; i++) { TestObject target = new TestObject(); - DoubleClickableIntroduction dci = new DoubleClickableIntroduction(); - DefaultIntroductionAdvisor advisor = new DefaultIntroductionAdvisor(dci); - CountingBeforeAdvice countingBeforeAdvice = new CountingBeforeAdvice(); - target.Name = "SOME-NAME"; - ProxyFactory pf = new ProxyFactory(target); - pf.AddIntroduction(advisor); - pf.AddAdvisor(new DefaultPointcutAdvisor(countingBeforeAdvice)); - object proxy = pf.GetProxy(); - ITestObject to = proxy as ITestObject; - Assert.IsNotNull(to); - Assert.AreEqual("SOME-NAME", to.Name); - IDoubleClickable doubleClickable = proxy as IDoubleClickable; - // add event handler through introduction - doubleClickable.DoubleClick += new EventHandler(OnClick); - OnClickWasCalled = false; - doubleClickable.FireDoubleClickEvent(); - Assert.IsTrue(OnClickWasCalled); - Assert.AreEqual(3, countingBeforeAdvice.GetCalls()); - // remove event handler through introduction - doubleClickable.DoubleClick -= new EventHandler(OnClick); - OnClickWasCalled = false; - doubleClickable.FireDoubleClickEvent(); - Assert.IsFalse(OnClickWasCalled); - Assert.AreEqual(5, countingBeforeAdvice.GetCalls()); - } - - private bool OnClickWasCalled = false; - - private void OnClick(object sender, EventArgs e) - { - OnClickWasCalled = true; - } - - [Test] - public void CacheTest() - { - - for (int i = 0; i < 2; i++) - { - TestObject target = new TestObject(); - NopInterceptor nopInterceptor = new NopInterceptor(); - CountingBeforeAdvice countingBeforeAdvice = new CountingBeforeAdvice(); - ProxyFactory pf = new ProxyFactory(); - pf.Target = target; - pf.AddAdvice(nopInterceptor); - pf.AddAdvisor(new DefaultPointcutAdvisor(countingBeforeAdvice)); - object proxy = pf.GetProxy(); - } - - // fails when running in resharper/testdriven.net - // DynamicProxyManager.SaveAssembly(); - - } - - [Test] - public void AddAndRemoveEventHandlerThroughInterceptor() - { - TestObject target = new TestObject(); - NopInterceptor nopInterceptor = new NopInterceptor(); - CountingBeforeAdvice countingBeforeAdvice = new CountingBeforeAdvice(); - target.Name = "SOME-NAME"; - ProxyFactory pf = new ProxyFactory(target); - pf.AddAdvice(nopInterceptor); - pf.AddAdvisor(new DefaultPointcutAdvisor(countingBeforeAdvice)); - object proxy = pf.GetProxy(); - ITestObject to = proxy as ITestObject; - // add event handler through proxy - to.Click += new EventHandler(OnClick); - OnClickWasCalled = false; - to.OnClick(); - Assert.IsTrue(OnClickWasCalled); - Assert.AreEqual(2, countingBeforeAdvice.GetCalls()); - // remove event handler through proxy - to.Click -= new EventHandler(OnClick); - OnClickWasCalled = false; - to.OnClick(); - Assert.IsFalse(OnClickWasCalled); - Assert.AreEqual(4, countingBeforeAdvice.GetCalls()); - } - - private class TestObject2 : TestObject - { - public bool EqualsOverrideWasCalled = false; - - public override bool Equals(object obj) - { - EqualsOverrideWasCalled = true; - return true; - } - - public override int GetHashCode() - { - return base.GetHashCode(); - } - } - - [Test] - public void CallsEqualsOverride() - { - TestObject2 target = new TestObject2(); - target.Name = "SOME-NAME"; - ProxyFactory pf = new ProxyFactory(target); - object proxy = pf.GetProxy(); - ITestObject to = proxy as ITestObject; - Assert.IsNotNull(to); - Assert.AreEqual("SOME-NAME", to.Name); - - target.EqualsOverrideWasCalled = false; - Assert.IsTrue(to.Equals(proxy)); - Assert.IsTrue(target.EqualsOverrideWasCalled); - - target.EqualsOverrideWasCalled = false; - Assert.IsTrue(proxy.Equals(to)); - Assert.IsTrue(target.EqualsOverrideWasCalled); - - target.EqualsOverrideWasCalled = false; - Assert.IsTrue(target.Equals(to)); - Assert.IsTrue(target.EqualsOverrideWasCalled); - - target.EqualsOverrideWasCalled = false; - Assert.IsTrue(to.Equals(target)); - Assert.IsTrue(target.EqualsOverrideWasCalled); - } - - [Test] - public void CreateProxyFactoryWithoutTargetThenSetTarget() - { - TestObject target = new TestObject(); - target.Name = "Adam"; NopInterceptor nopInterceptor = new NopInterceptor(); CountingBeforeAdvice countingBeforeAdvice = new CountingBeforeAdvice(); ProxyFactory pf = new ProxyFactory(); @@ -207,463 +115,551 @@ namespace Spring.Aop.Framework pf.AddAdvice(nopInterceptor); pf.AddAdvisor(new DefaultPointcutAdvisor(countingBeforeAdvice)); object proxy = pf.GetProxy(); - ITestObject to = (ITestObject)proxy; - Assert.AreEqual("Adam", to.Name); - Assert.AreEqual(1, countingBeforeAdvice.GetCalls()); } - [Test] - public void InstantiateWithNullTarget() + // fails when running in resharper/testdriven.net + // DynamicProxyManager.SaveAssembly(); + } + + [Test] + public void AddAndRemoveEventHandlerThroughInterceptor() + { + TestObject target = new TestObject(); + NopInterceptor nopInterceptor = new NopInterceptor(); + CountingBeforeAdvice countingBeforeAdvice = new CountingBeforeAdvice(); + target.Name = "SOME-NAME"; + ProxyFactory pf = new ProxyFactory(target); + pf.AddAdvice(nopInterceptor); + pf.AddAdvisor(new DefaultPointcutAdvisor(countingBeforeAdvice)); + object proxy = pf.GetProxy(); + ITestObject to = proxy as ITestObject; + // add event handler through proxy + to.Click += new EventHandler(OnClick); + OnClickWasCalled = false; + to.OnClick(); + Assert.IsTrue(OnClickWasCalled); + Assert.AreEqual(2, countingBeforeAdvice.GetCalls()); + // remove event handler through proxy + to.Click -= new EventHandler(OnClick); + OnClickWasCalled = false; + to.OnClick(); + Assert.IsFalse(OnClickWasCalled); + Assert.AreEqual(4, countingBeforeAdvice.GetCalls()); + } + + private class TestObject2 : TestObject + { + public bool EqualsOverrideWasCalled = false; + + public override bool Equals(object obj) { - Assert.Throws(() => new ProxyFactory((object) null)); + EqualsOverrideWasCalled = true; + return true; } - [Test] - public void AddNullInterface() + public override int GetHashCode() { - Assert.Throws(() => new ProxyFactory().AddInterface(null)); - } - - [Test] - public void AddInterfaceWhenConfigurationIsFrozen() - { - ProxyFactory factory = new ProxyFactory(); - factory.IsFrozen = true; - Assert.Throws(() => factory.AddInterface(typeof(ITestObject))); - } - - [Test] - public void IndexOfMethods() - { - TestObject target = new TestObject(); - ProxyFactory pf = new ProxyFactory(target); - NopInterceptor nop = new NopInterceptor(); - IAdvisor advisor = new DefaultPointcutAdvisor(new CountingBeforeAdvice()); - IAdvised advised = (IAdvised)pf.GetProxy(); - // Can use advised and ProxyFactory interchangeably - advised.AddAdvice(nop); - pf.AddAdvisor(advisor); - Assert.AreEqual(-1, pf.IndexOf((IInterceptor)null)); - Assert.AreEqual(-1, pf.IndexOf(new NopInterceptor())); - Assert.AreEqual(0, pf.IndexOf(nop)); - Assert.AreEqual(-1, advised.IndexOf((IAdvisor)null)); - Assert.AreEqual(1, pf.IndexOf(advisor)); - Assert.AreEqual(-1, advised.IndexOf(new DefaultPointcutAdvisor(null))); - } - - [Test] - public void RemoveAdvisorByReference() - { - TestObject target = new TestObject(); - ProxyFactory pf = new ProxyFactory(target); - NopInterceptor nop = new NopInterceptor(); - CountingBeforeAdvice cba = new CountingBeforeAdvice(); - IAdvisor advisor = new DefaultPointcutAdvisor(cba); - pf.AddAdvice(nop); - pf.AddAdvisor(advisor); - ITestObject proxied = (ITestObject)pf.GetProxy(); - proxied.Age = 5; - Assert.AreEqual(1, cba.GetCalls()); - Assert.AreEqual(1, nop.Count); - Assert.IsFalse(pf.RemoveAdvisor(null)); - Assert.IsTrue(pf.RemoveAdvisor(advisor)); - Assert.AreEqual(5, proxied.Age); - Assert.AreEqual(1, cba.GetCalls()); - Assert.AreEqual(2, nop.Count); - Assert.IsFalse(pf.RemoveAdvisor(new DefaultPointcutAdvisor(null))); - } - - [Test] - public void RemoveAdvisorByIndex() - { - TestObject target = new TestObject(); - ProxyFactory pf = new ProxyFactory(target); - NopInterceptor nop = new NopInterceptor(); - CountingBeforeAdvice cba = new CountingBeforeAdvice(); - IAdvisor advisor = new DefaultPointcutAdvisor(cba); - pf.AddAdvice(nop); - pf.AddAdvisor(advisor); - NopInterceptor nop2 = new NopInterceptor(2); // make instance unique (see SPRNET-847) - pf.AddAdvice(nop2); - ITestObject proxied = (ITestObject)pf.GetProxy(); - proxied.Age = 5; - Assert.AreEqual(1, cba.GetCalls()); - Assert.AreEqual(1, nop.Count); - Assert.AreEqual(1, nop2.Count); - // Removes counting before advisor - pf.RemoveAdvisor(1); - Assert.AreEqual(5, proxied.Age); - Assert.AreEqual(1, cba.GetCalls()); - Assert.AreEqual(2, nop.Count); - Assert.AreEqual(2, nop2.Count); - // Removes Nop1 - pf.RemoveAdvisor(0); - Assert.AreEqual(5, proxied.Age); - Assert.AreEqual(1, cba.GetCalls()); - Assert.AreEqual(2, nop.Count); - Assert.AreEqual(3, nop2.Count); - - // Check out of bounds - try - { - pf.RemoveAdvisor(-1); - Assert.Fail("Supposed to throw exception"); - } - catch (AopConfigException) - { - // Ok - } - - try - { - pf.RemoveAdvisor(2); - Assert.Fail("Supposed to throw exception"); - } - catch (AopConfigException) - { - // Ok - } - - Assert.AreEqual(5, proxied.Age); - Assert.AreEqual(4, nop2.Count); - } - - [Test] - public void TryRemoveNonProxiedInterface() - { - ProxyFactory factory = new ProxyFactory(new TestObject()); - Assert.IsFalse(factory.RemoveInterface(typeof(IServiceProvider))); - } - - [Test] - public void RemoveProxiedInterface() - { - ProxyFactory factory = new ProxyFactory(new TestObject()); - Assert.IsTrue(factory.RemoveInterface(typeof(ITestObject))); - } - - [Test] - public void ReplaceAdvisor() - { - TestObject target = new TestObject(); - ProxyFactory pf = new ProxyFactory(target); - NopInterceptor nop = new NopInterceptor(); - CountingBeforeAdvice cba1 = new CountingBeforeAdvice(); - CountingBeforeAdvice cba2 = new CountingBeforeAdvice(); - IAdvisor advisor1 = new DefaultPointcutAdvisor(cba1); - IAdvisor advisor2 = new DefaultPointcutAdvisor(cba2); - pf.AddAdvisor(advisor1); - pf.AddAdvice(nop); - ITestObject proxied = (ITestObject)pf.GetProxy(); - // Use the type cast feature - // Replace etc methods on advised should be same as on ProxyFactory - IAdvised advised = (IAdvised)proxied; - proxied.Age = 5; - Assert.AreEqual(1, cba1.GetCalls()); - Assert.AreEqual(0, cba2.GetCalls()); - Assert.AreEqual(1, nop.Count); - Assert.IsFalse(advised.ReplaceAdvisor(null, null)); - Assert.IsFalse(advised.ReplaceAdvisor(null, advisor2)); - Assert.IsFalse(advised.ReplaceAdvisor(advisor1, null)); - Assert.IsTrue(advised.ReplaceAdvisor(advisor1, advisor2)); - Assert.AreEqual(advisor2, pf.Advisors[0]); - Assert.AreEqual(5, proxied.Age); - Assert.AreEqual(1, cba1.GetCalls()); - Assert.AreEqual(2, nop.Count); - Assert.AreEqual(1, cba2.GetCalls()); - Assert.IsFalse(pf.ReplaceAdvisor(new DefaultPointcutAdvisor(null), advisor1)); - } - - [Test] - public void IgnoresAdvisorDuplicates() - { - CountingBeforeAdvice cba1 = new CountingBeforeAdvice(); - IAdvisor advisor1 = new DefaultPointcutAdvisor(cba1); - - AdvisedSupport advSup = new AdvisedSupport(); - advSup.AddAdvisor(advisor1); - advSup.AddAdvisor(advisor1); - - Assert.AreEqual(1, advSup.Advisors.Count); - } - - private class AnonymousClassTimeStamped : ITimeStamped - { - public AnonymousClassTimeStamped(ProxyFactoryTests enclosingInstance) - { - InitBlock(enclosingInstance); - } - - private void InitBlock(ProxyFactoryTests enclosingInstance) - { - this.enclosingInstance = enclosingInstance; - } - - private ProxyFactoryTests enclosingInstance; - - public ProxyFactoryTests Enclosing_Instance - { - get { return enclosingInstance; } - - } - - public DateTime TimeStamp - { - get { throw new NotSupportedException("TimeStamp"); } - } - } - - [Test] - public void AddRepeatedInterface() - { - ITimeStamped tst = new AnonymousClassTimeStamped(this); - ProxyFactory pf = new ProxyFactory(tst); - // We've already implicitly added this interface. - // This call should be ignored without error - pf.AddInterface(typeof(ITimeStamped)); - // All cool - ITimeStamped ts = (ITimeStamped)pf.GetProxy(); - } - - internal class TestObjectSubclass : TestObject, IComparable - { - public override int CompareTo(Object arg0) - { - throw new NotSupportedException("compareTo"); - } - } - - [Test] - public void GetsAllInterfaces() - { - // Extend to get new interface - TestObjectSubclass raw = new TestObjectSubclass(); - ProxyFactory factory = new ProxyFactory(raw); - Assert.AreEqual(8, factory.Interfaces.Count, "Found correct number of interfaces"); - //System.out.println("Proxied interfaces are " + StringUtils.arrayToDelimitedString(factory.getProxiedInterfaces(), ",")); - ITestObject tb = (ITestObject)factory.GetProxy(); - Assert.IsTrue(tb is IOther, "Picked up secondary interface"); - - raw.Age = 25; - Assert.IsTrue(tb.Age == raw.Age); - - DateTime t = new DateTime(2004, 8, 1); - TimestampIntroductionInterceptor ti = new TimestampIntroductionInterceptor(t); - - Console.WriteLine(StringUtils.CollectionToDelimitedString(factory.Interfaces, "/")); - - //factory.addAdvisor(0, new DefaultIntroductionAdvisor(ti, typeof(ITimeStamped))); - factory.AddIntroduction( - new DefaultIntroductionAdvisor(ti, typeof(ITimeStamped)) - ); - - Console.WriteLine(StringUtils.CollectionToDelimitedString(factory.Interfaces, "/")); - - ITimeStamped ts = (ITimeStamped)factory.GetProxy(); - Assert.IsTrue(ts.TimeStamp == t); - // Shouldn't fail; - ((IOther)ts).Absquatulate(); - } - - private class AnonymousClassInterceptor : IInterceptor - { - } - - [Test] - public void CanOnlyAddMethodInterceptors() - { - ProxyFactory factory = new ProxyFactory(new TestObject()); - factory.AddAdvice(0, new NopInterceptor()); - try - { - factory.AddAdvice(0, new AnonymousClassInterceptor()); - Assert.Fail("Should only be able to add MethodInterceptors"); - } - catch (AopConfigException) - { - } - - // Check we can still use it - IOther other = (IOther)factory.GetProxy(); - other.Absquatulate(); - } - - [Test] - public void InterceptorInclusionMethods() - { - NopInterceptor di = new NopInterceptor(); - NopInterceptor diUnused = new NopInterceptor(1); // // make instance unique (see SPRNET-847) - ProxyFactory factory = new ProxyFactory(new TestObject()); - factory.AddAdvice(0, di); - ITestObject tb = (ITestObject)factory.GetProxy(); - Assert.IsTrue(factory.AdviceIncluded(di)); - Assert.IsTrue(!factory.AdviceIncluded(diUnused)); - Assert.IsTrue(factory.CountAdviceOfType(typeof(NopInterceptor)) == 1); - - factory.AddAdvice(0, diUnused); - Assert.IsTrue(factory.AdviceIncluded(diUnused)); - Assert.IsTrue(factory.CountAdviceOfType(typeof(NopInterceptor)) == 2); - } - - [Test] - public void AddAdvisedSupportListener() - { - //MLP SPRNET-1367 - //IDynamicMock mock = new DynamicMock(typeof(IAdvisedSupportListener)); - //IAdvisedSupportListener listener = (IAdvisedSupportListener)mock.Object; - IAdvisedSupportListener listener = A.Fake(); - //listener.Activated(); - //mock.Expect("Activated"); - - ProxyFactory factory = new ProxyFactory(new TestObject()); - factory.AddListener(listener); - factory.GetProxy(); - - A.CallTo(() => listener.Activated(A._)).MustHaveHappened(); - } - - [Test] - public void AdvisedSupportListenerMethodsAreCalledAppropriately() - { - IAdvisedSupportListener listener = A.Fake(); - - ProxyFactory factory = new ProxyFactory(new TestObject()); - factory.AddListener(listener); - - // must fire the Activated callback... - factory.GetProxy(); - // must fire the AdviceChanged callback... - factory.AddAdvice(new NopInterceptor()); - // must fire the InterfacesChanged callback... - factory.AddInterface(typeof(ISerializable)); - - A.CallTo(() => listener.Activated(A.That.Not.IsNull())).MustHaveHappened(); - A.CallTo(() => listener.AdviceChanged(A.That.Not.IsNull())).MustHaveHappened(); - A.CallTo(() => listener.InterfacesChanged(A.That.Not.IsNull())).MustHaveHappened(); - } - - [Test] - public void AdvisedSupportListenerMethodsAre_NOT_CalledIfProxyHasNotBeenCreated() - { - IAdvisedSupportListener listener = A.Fake(); - - ProxyFactory factory = new ProxyFactory(new TestObject()); - factory.AddListener(listener); - - // must not fire the AdviceChanged callback... - factory.AddAdvice(new NopInterceptor()); - // must not fire the InterfacesChanged callback... - factory.AddInterface(typeof(ISerializable)); - - A.CallTo(() => listener.AdviceChanged(A._)).MustNotHaveHappened(); - A.CallTo(() => listener.InterfacesChanged(A._)).MustNotHaveHappened(); - } - - [Test] - public void AddNullAdvisedSupportListenerIsOk() - { - ProxyFactory factory = new ProxyFactory(new TestObject()); - factory.AddListener(null); - } - - [Test] - public void RemoveNullAdvisedSupportListenerIsOk() - { - ProxyFactory factory = new ProxyFactory(new TestObject()); - factory.RemoveListener(null); - } - - [Test] - public void RemoveAdvisedSupportListener() - { - IAdvisedSupportListener listener = A.Fake(); - - ProxyFactory factory = new ProxyFactory(new TestObject()); - factory.AddListener(listener); - factory.RemoveListener(listener); - - factory.GetProxy(); - - // check that no lifecycle callback methods were invoked on the listener... - A.CallTo(() => listener.Activated(null)).WithAnyArguments().MustNotHaveHappened(); - A.CallTo(() => listener.AdviceChanged(null)).WithAnyArguments().MustNotHaveHappened(); - A.CallTo(() => listener.InterfacesChanged(null)).WithAnyArguments().MustNotHaveHappened(); - } - - [Test] - public void Frozen_RemoveAdvisor() - { - ProxyFactory factory = new ProxyFactory(); - factory.IsFrozen = true; - Assert.Throws(() => factory.RemoveAdvisor(null)); - } - - public interface IMultiProxyingTestInterface - { - string TestMethod(string arg); - } - - public interface IMultiProxyingTestInterface2 : IMultiProxyingTestInterface { } - - public class MultiProxyingTestClass : IMultiProxyingTestInterface2 - { - public int InvocationCounter; - - public string TestMethod(string arg) - { - InvocationCounter++; - return arg + "|" + arg; - } - } - - public interface ICountingIntroduction - { - void Inc(); - } - - public class TestCountingIntroduction : ICountingIntroduction, IAdvice - { - public int Counter; - - public void Inc() - { - Counter++; - } - } - - [Test] - public void NestedProxiesDontInvokeSameAdviceOrIntroductionTwice() - { - MultiProxyingTestClass testObj = new MultiProxyingTestClass(); - ProxyFactory pf1 = new ProxyFactory(); - pf1.Target = testObj; - - NopInterceptor di = new NopInterceptor(); - NopInterceptor diUnused = new NopInterceptor(1); // // make instance unique (see SPRNET-847) - TestCountingIntroduction countingMixin = new TestCountingIntroduction(); - - pf1.AddAdvice(diUnused); - pf1.AddAdvisor(new DefaultPointcutAdvisor(di)); - pf1.AddIntroduction(new DefaultIntroductionAdvisor(countingMixin)); - - object innerProxy = pf1.GetProxy(); - ProxyFactory pf2 = new ProxyFactory(); - pf2.Target = innerProxy; - pf2.AddAdvice(diUnused); - pf2.AddAdvisor(new DefaultPointcutAdvisor(di)); - pf2.AddIntroduction(new DefaultIntroductionAdvisor(countingMixin)); - - object outerProxy = pf2.GetProxy(); - - // any advice instance is invoked once only - string result = ((IMultiProxyingTestInterface)outerProxy).TestMethod("arg"); - Assert.AreEqual(1, testObj.InvocationCounter); - Assert.AreEqual("arg|arg", result); - Assert.AreEqual(1, di.Count); - - // any introduction instance is invoked once only - ((ICountingIntroduction)outerProxy).Inc(); - Assert.AreEqual(1, countingMixin.Counter); + return base.GetHashCode(); } } + + [Test] + public void CallsEqualsOverride() + { + TestObject2 target = new TestObject2(); + target.Name = "SOME-NAME"; + ProxyFactory pf = new ProxyFactory(target); + object proxy = pf.GetProxy(); + ITestObject to = proxy as ITestObject; + Assert.IsNotNull(to); + Assert.AreEqual("SOME-NAME", to.Name); + + target.EqualsOverrideWasCalled = false; + Assert.IsTrue(to.Equals(proxy)); + Assert.IsTrue(target.EqualsOverrideWasCalled); + + target.EqualsOverrideWasCalled = false; + Assert.IsTrue(proxy.Equals(to)); + Assert.IsTrue(target.EqualsOverrideWasCalled); + + target.EqualsOverrideWasCalled = false; + Assert.IsTrue(target.Equals(to)); + Assert.IsTrue(target.EqualsOverrideWasCalled); + + target.EqualsOverrideWasCalled = false; + Assert.IsTrue(to.Equals(target)); + Assert.IsTrue(target.EqualsOverrideWasCalled); + } + + [Test] + public void CreateProxyFactoryWithoutTargetThenSetTarget() + { + TestObject target = new TestObject(); + target.Name = "Adam"; + NopInterceptor nopInterceptor = new NopInterceptor(); + CountingBeforeAdvice countingBeforeAdvice = new CountingBeforeAdvice(); + ProxyFactory pf = new ProxyFactory(); + pf.Target = target; + pf.AddAdvice(nopInterceptor); + pf.AddAdvisor(new DefaultPointcutAdvisor(countingBeforeAdvice)); + object proxy = pf.GetProxy(); + ITestObject to = (ITestObject) proxy; + Assert.AreEqual("Adam", to.Name); + Assert.AreEqual(1, countingBeforeAdvice.GetCalls()); + } + + [Test] + public void InstantiateWithNullTarget() + { + Assert.Throws(() => new ProxyFactory((object) null)); + } + + [Test] + public void AddNullInterface() + { + Assert.Throws(() => new ProxyFactory().AddInterface(null)); + } + + [Test] + public void AddInterfaceWhenConfigurationIsFrozen() + { + ProxyFactory factory = new ProxyFactory(); + factory.IsFrozen = true; + Assert.Throws(() => factory.AddInterface(typeof(ITestObject))); + } + + [Test] + public void IndexOfMethods() + { + TestObject target = new TestObject(); + ProxyFactory pf = new ProxyFactory(target); + NopInterceptor nop = new NopInterceptor(); + IAdvisor advisor = new DefaultPointcutAdvisor(new CountingBeforeAdvice()); + IAdvised advised = (IAdvised) pf.GetProxy(); + // Can use advised and ProxyFactory interchangeably + advised.AddAdvice(nop); + pf.AddAdvisor(advisor); + Assert.AreEqual(-1, pf.IndexOf((IInterceptor) null)); + Assert.AreEqual(-1, pf.IndexOf(new NopInterceptor())); + Assert.AreEqual(0, pf.IndexOf(nop)); + Assert.AreEqual(-1, advised.IndexOf((IAdvisor) null)); + Assert.AreEqual(1, pf.IndexOf(advisor)); + Assert.AreEqual(-1, advised.IndexOf(new DefaultPointcutAdvisor(null))); + } + + [Test] + public void RemoveAdvisorByReference() + { + TestObject target = new TestObject(); + ProxyFactory pf = new ProxyFactory(target); + NopInterceptor nop = new NopInterceptor(); + CountingBeforeAdvice cba = new CountingBeforeAdvice(); + IAdvisor advisor = new DefaultPointcutAdvisor(cba); + pf.AddAdvice(nop); + pf.AddAdvisor(advisor); + ITestObject proxied = (ITestObject) pf.GetProxy(); + proxied.Age = 5; + Assert.AreEqual(1, cba.GetCalls()); + Assert.AreEqual(1, nop.Count); + Assert.IsFalse(pf.RemoveAdvisor(null)); + Assert.IsTrue(pf.RemoveAdvisor(advisor)); + Assert.AreEqual(5, proxied.Age); + Assert.AreEqual(1, cba.GetCalls()); + Assert.AreEqual(2, nop.Count); + Assert.IsFalse(pf.RemoveAdvisor(new DefaultPointcutAdvisor(null))); + } + + [Test] + public void RemoveAdvisorByIndex() + { + TestObject target = new TestObject(); + ProxyFactory pf = new ProxyFactory(target); + NopInterceptor nop = new NopInterceptor(); + CountingBeforeAdvice cba = new CountingBeforeAdvice(); + IAdvisor advisor = new DefaultPointcutAdvisor(cba); + pf.AddAdvice(nop); + pf.AddAdvisor(advisor); + NopInterceptor nop2 = new NopInterceptor(2); // make instance unique (see SPRNET-847) + pf.AddAdvice(nop2); + ITestObject proxied = (ITestObject) pf.GetProxy(); + proxied.Age = 5; + Assert.AreEqual(1, cba.GetCalls()); + Assert.AreEqual(1, nop.Count); + Assert.AreEqual(1, nop2.Count); + // Removes counting before advisor + pf.RemoveAdvisor(1); + Assert.AreEqual(5, proxied.Age); + Assert.AreEqual(1, cba.GetCalls()); + Assert.AreEqual(2, nop.Count); + Assert.AreEqual(2, nop2.Count); + // Removes Nop1 + pf.RemoveAdvisor(0); + Assert.AreEqual(5, proxied.Age); + Assert.AreEqual(1, cba.GetCalls()); + Assert.AreEqual(2, nop.Count); + Assert.AreEqual(3, nop2.Count); + + // Check out of bounds + try + { + pf.RemoveAdvisor(-1); + Assert.Fail("Supposed to throw exception"); + } + catch (AopConfigException) + { + // Ok + } + + try + { + pf.RemoveAdvisor(2); + Assert.Fail("Supposed to throw exception"); + } + catch (AopConfigException) + { + // Ok + } + + Assert.AreEqual(5, proxied.Age); + Assert.AreEqual(4, nop2.Count); + } + + [Test] + public void TryRemoveNonProxiedInterface() + { + ProxyFactory factory = new ProxyFactory(new TestObject()); + Assert.IsFalse(factory.RemoveInterface(typeof(IServiceProvider))); + } + + [Test] + public void RemoveProxiedInterface() + { + ProxyFactory factory = new ProxyFactory(new TestObject()); + Assert.IsTrue(factory.RemoveInterface(typeof(ITestObject))); + } + + [Test] + public void ReplaceAdvisor() + { + TestObject target = new TestObject(); + ProxyFactory pf = new ProxyFactory(target); + NopInterceptor nop = new NopInterceptor(); + CountingBeforeAdvice cba1 = new CountingBeforeAdvice(); + CountingBeforeAdvice cba2 = new CountingBeforeAdvice(); + IAdvisor advisor1 = new DefaultPointcutAdvisor(cba1); + IAdvisor advisor2 = new DefaultPointcutAdvisor(cba2); + pf.AddAdvisor(advisor1); + pf.AddAdvice(nop); + ITestObject proxied = (ITestObject) pf.GetProxy(); + // Use the type cast feature + // Replace etc methods on advised should be same as on ProxyFactory + IAdvised advised = (IAdvised) proxied; + proxied.Age = 5; + Assert.AreEqual(1, cba1.GetCalls()); + Assert.AreEqual(0, cba2.GetCalls()); + Assert.AreEqual(1, nop.Count); + Assert.IsFalse(advised.ReplaceAdvisor(null, null)); + Assert.IsFalse(advised.ReplaceAdvisor(null, advisor2)); + Assert.IsFalse(advised.ReplaceAdvisor(advisor1, null)); + Assert.IsTrue(advised.ReplaceAdvisor(advisor1, advisor2)); + Assert.AreEqual(advisor2, pf.Advisors[0]); + Assert.AreEqual(5, proxied.Age); + Assert.AreEqual(1, cba1.GetCalls()); + Assert.AreEqual(2, nop.Count); + Assert.AreEqual(1, cba2.GetCalls()); + Assert.IsFalse(pf.ReplaceAdvisor(new DefaultPointcutAdvisor(null), advisor1)); + } + + [Test] + public void IgnoresAdvisorDuplicates() + { + CountingBeforeAdvice cba1 = new CountingBeforeAdvice(); + IAdvisor advisor1 = new DefaultPointcutAdvisor(cba1); + + AdvisedSupport advSup = new AdvisedSupport(); + advSup.AddAdvisor(advisor1); + advSup.AddAdvisor(advisor1); + + Assert.AreEqual(1, advSup.Advisors.Count); + } + + private class AnonymousClassTimeStamped : ITimeStamped + { + public AnonymousClassTimeStamped(ProxyFactoryTests enclosingInstance) + { + InitBlock(enclosingInstance); + } + + private void InitBlock(ProxyFactoryTests enclosingInstance) + { + this.enclosingInstance = enclosingInstance; + } + + private ProxyFactoryTests enclosingInstance; + + public ProxyFactoryTests Enclosing_Instance + { + get { return enclosingInstance; } + } + + public DateTime TimeStamp + { + get { throw new NotSupportedException("TimeStamp"); } + } + } + + [Test] + public void AddRepeatedInterface() + { + ITimeStamped tst = new AnonymousClassTimeStamped(this); + ProxyFactory pf = new ProxyFactory(tst); + // We've already implicitly added this interface. + // This call should be ignored without error + pf.AddInterface(typeof(ITimeStamped)); + // All cool + ITimeStamped ts = (ITimeStamped) pf.GetProxy(); + } + + internal class TestObjectSubclass : TestObject, IComparable + { + public override int CompareTo(Object arg0) + { + throw new NotSupportedException("compareTo"); + } + } + + [Test] + public void GetsAllInterfaces() + { + // Extend to get new interface + TestObjectSubclass raw = new TestObjectSubclass(); + ProxyFactory factory = new ProxyFactory(raw); + Assert.AreEqual(8, factory.Interfaces.Count, "Found correct number of interfaces"); + //System.out.println("Proxied interfaces are " + StringUtils.arrayToDelimitedString(factory.getProxiedInterfaces(), ",")); + ITestObject tb = (ITestObject) factory.GetProxy(); + Assert.IsTrue(tb is IOther, "Picked up secondary interface"); + + raw.Age = 25; + Assert.IsTrue(tb.Age == raw.Age); + + DateTime t = new DateTime(2004, 8, 1); + TimestampIntroductionInterceptor ti = new TimestampIntroductionInterceptor(t); + + Console.WriteLine(StringUtils.CollectionToDelimitedString(factory.Interfaces, "/")); + + //factory.addAdvisor(0, new DefaultIntroductionAdvisor(ti, typeof(ITimeStamped))); + factory.AddIntroduction( + new DefaultIntroductionAdvisor(ti, typeof(ITimeStamped)) + ); + + Console.WriteLine(StringUtils.CollectionToDelimitedString(factory.Interfaces, "/")); + + ITimeStamped ts = (ITimeStamped) factory.GetProxy(); + Assert.IsTrue(ts.TimeStamp == t); + // Shouldn't fail; + ((IOther) ts).Absquatulate(); + } + + private class AnonymousClassInterceptor : IInterceptor + { + } + + [Test] + public void CanOnlyAddMethodInterceptors() + { + ProxyFactory factory = new ProxyFactory(new TestObject()); + factory.AddAdvice(0, new NopInterceptor()); + try + { + factory.AddAdvice(0, new AnonymousClassInterceptor()); + Assert.Fail("Should only be able to add MethodInterceptors"); + } + catch (AopConfigException) + { + } + + // Check we can still use it + IOther other = (IOther) factory.GetProxy(); + other.Absquatulate(); + } + + [Test] + public void InterceptorInclusionMethods() + { + NopInterceptor di = new NopInterceptor(); + NopInterceptor diUnused = new NopInterceptor(1); // // make instance unique (see SPRNET-847) + ProxyFactory factory = new ProxyFactory(new TestObject()); + factory.AddAdvice(0, di); + ITestObject tb = (ITestObject) factory.GetProxy(); + Assert.IsTrue(factory.AdviceIncluded(di)); + Assert.IsTrue(!factory.AdviceIncluded(diUnused)); + Assert.IsTrue(factory.CountAdviceOfType(typeof(NopInterceptor)) == 1); + + factory.AddAdvice(0, diUnused); + Assert.IsTrue(factory.AdviceIncluded(diUnused)); + Assert.IsTrue(factory.CountAdviceOfType(typeof(NopInterceptor)) == 2); + } + + [Test] + public void AddAdvisedSupportListener() + { + //MLP SPRNET-1367 + //IDynamicMock mock = new DynamicMock(typeof(IAdvisedSupportListener)); + //IAdvisedSupportListener listener = (IAdvisedSupportListener)mock.Object; + IAdvisedSupportListener listener = A.Fake(); + //listener.Activated(); + //mock.Expect("Activated"); + + ProxyFactory factory = new ProxyFactory(new TestObject()); + factory.AddListener(listener); + factory.GetProxy(); + + A.CallTo(() => listener.Activated(A._)).MustHaveHappened(); + } + + [Test] + public void AdvisedSupportListenerMethodsAreCalledAppropriately() + { + IAdvisedSupportListener listener = A.Fake(); + + ProxyFactory factory = new ProxyFactory(new TestObject()); + factory.AddListener(listener); + + // must fire the Activated callback... + factory.GetProxy(); + // must fire the AdviceChanged callback... + factory.AddAdvice(new NopInterceptor()); + // must fire the InterfacesChanged callback... + factory.AddInterface(typeof(ISerializable)); + + A.CallTo(() => listener.Activated(A.That.Not.IsNull())).MustHaveHappened(); + A.CallTo(() => listener.AdviceChanged(A.That.Not.IsNull())).MustHaveHappened(); + A.CallTo(() => listener.InterfacesChanged(A.That.Not.IsNull())).MustHaveHappened(); + } + + [Test] + public void AdvisedSupportListenerMethodsAre_NOT_CalledIfProxyHasNotBeenCreated() + { + IAdvisedSupportListener listener = A.Fake(); + + ProxyFactory factory = new ProxyFactory(new TestObject()); + factory.AddListener(listener); + + // must not fire the AdviceChanged callback... + factory.AddAdvice(new NopInterceptor()); + // must not fire the InterfacesChanged callback... + factory.AddInterface(typeof(ISerializable)); + + A.CallTo(() => listener.AdviceChanged(A._)).MustNotHaveHappened(); + A.CallTo(() => listener.InterfacesChanged(A._)).MustNotHaveHappened(); + } + + [Test] + public void AddNullAdvisedSupportListenerIsOk() + { + ProxyFactory factory = new ProxyFactory(new TestObject()); + factory.AddListener(null); + } + + [Test] + public void RemoveNullAdvisedSupportListenerIsOk() + { + ProxyFactory factory = new ProxyFactory(new TestObject()); + factory.RemoveListener(null); + } + + [Test] + public void RemoveAdvisedSupportListener() + { + IAdvisedSupportListener listener = A.Fake(); + + ProxyFactory factory = new ProxyFactory(new TestObject()); + factory.AddListener(listener); + factory.RemoveListener(listener); + + factory.GetProxy(); + + // check that no lifecycle callback methods were invoked on the listener... + A.CallTo(() => listener.Activated(null)).WithAnyArguments().MustNotHaveHappened(); + A.CallTo(() => listener.AdviceChanged(null)).WithAnyArguments().MustNotHaveHappened(); + A.CallTo(() => listener.InterfacesChanged(null)).WithAnyArguments().MustNotHaveHappened(); + } + + [Test] + public void Frozen_RemoveAdvisor() + { + ProxyFactory factory = new ProxyFactory(); + factory.IsFrozen = true; + Assert.Throws(() => factory.RemoveAdvisor(null)); + } + + public interface IMultiProxyingTestInterface + { + string TestMethod(string arg); + } + + public interface IMultiProxyingTestInterface2 : IMultiProxyingTestInterface + { + } + + public class MultiProxyingTestClass : IMultiProxyingTestInterface2 + { + public int InvocationCounter; + + public string TestMethod(string arg) + { + InvocationCounter++; + return arg + "|" + arg; + } + } + + public interface ICountingIntroduction + { + void Inc(); + } + + public class TestCountingIntroduction : ICountingIntroduction, IAdvice + { + public int Counter; + + public void Inc() + { + Counter++; + } + } + + [Test] + public void NestedProxiesDontInvokeSameAdviceOrIntroductionTwice() + { + MultiProxyingTestClass testObj = new MultiProxyingTestClass(); + ProxyFactory pf1 = new ProxyFactory(); + pf1.Target = testObj; + + NopInterceptor di = new NopInterceptor(); + NopInterceptor diUnused = new NopInterceptor(1); // // make instance unique (see SPRNET-847) + TestCountingIntroduction countingMixin = new TestCountingIntroduction(); + + pf1.AddAdvice(diUnused); + pf1.AddAdvisor(new DefaultPointcutAdvisor(di)); + pf1.AddIntroduction(new DefaultIntroductionAdvisor(countingMixin)); + + object innerProxy = pf1.GetProxy(); + ProxyFactory pf2 = new ProxyFactory(); + pf2.Target = innerProxy; + pf2.AddAdvice(diUnused); + pf2.AddAdvisor(new DefaultPointcutAdvisor(di)); + pf2.AddIntroduction(new DefaultIntroductionAdvisor(countingMixin)); + + object outerProxy = pf2.GetProxy(); + + // any advice instance is invoked once only + string result = ((IMultiProxyingTestInterface) outerProxy).TestMethod("arg"); + Assert.AreEqual(1, testObj.InvocationCounter); + Assert.AreEqual("arg|arg", result); + Assert.AreEqual(1, di.Count); + + // any introduction instance is invoked once only + ((ICountingIntroduction) outerProxy).Inc(); + Assert.AreEqual(1, countingMixin.Counter); + } } \ No newline at end of file diff --git a/test/Spring/Spring.Aop.Tests/Aop/Framework/ReflectiveMethodInvocationTests.cs b/test/Spring/Spring.Aop.Tests/Aop/Framework/ReflectiveMethodInvocationTests.cs index 432d09e2..06677ce0 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Framework/ReflectiveMethodInvocationTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Framework/ReflectiveMethodInvocationTests.cs @@ -22,24 +22,22 @@ using System.Reflection; using System.Collections; - using NUnit.Framework; #endregion -namespace Spring.Aop.Framework +namespace Spring.Aop.Framework; + +/// +/// Unit tests for the ReflectiveMethodInvocation class. +/// +/// Rick Evans +/// Bruno Baia +[TestFixture] +public class ReflectiveMethodInvocationTests : AbstractMethodInvocationTests { - /// - /// Unit tests for the ReflectiveMethodInvocation class. - /// - /// Rick Evans - /// Bruno Baia - [TestFixture] - public class ReflectiveMethodInvocationTests : AbstractMethodInvocationTests + protected override AbstractMethodInvocation CreateMethodInvocation(object proxy, object target, MethodInfo method, MethodInfo onProxyMethod, object[] arguments, Type targetType, IList interceptors) { - protected override AbstractMethodInvocation CreateMethodInvocation(object proxy, object target, MethodInfo method, MethodInfo onProxyMethod, object[] arguments, Type targetType, IList interceptors) - { - return new ReflectiveMethodInvocation(proxy, target, method, onProxyMethod, arguments, targetType, interceptors); - } + return new ReflectiveMethodInvocation(proxy, target, method, onProxyMethod, arguments, targetType, interceptors); } -} \ No newline at end of file +} diff --git a/test/Spring/Spring.Aop.Tests/Aop/Framework/TimestampIntroductionInterceptor.cs b/test/Spring/Spring.Aop.Tests/Aop/Framework/TimestampIntroductionInterceptor.cs index e64c8d24..79054dc8 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Framework/TimestampIntroductionInterceptor.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Framework/TimestampIntroductionInterceptor.cs @@ -1,20 +1,23 @@ #region License + /* * Copyright 2002-2010 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 + #region Imports using AopAlliance.Aop; @@ -22,45 +25,44 @@ using AopAlliance.Intercept; #endregion -namespace Spring.Aop.Framework +namespace Spring.Aop.Framework; + +/// +/// Test introduction ported from Spring.Java. +/// +/// +/// The name is deceptive because it isn't implemented as an interceptor. +/// It's an introduction which is handled differently in Spring.NET. +/// Keeping the name is useful as a placeholder for future porting work. +/// +/// Spring.Java Folks +/// Choy Rim (.NET) +public class TimestampIntroductionInterceptor : IAdvice, ITimeStamped, IInterceptor { - /// - /// Test introduction ported from Spring.Java. - /// - /// - /// The name is deceptive because it isn't implemented as an interceptor. - /// It's an introduction which is handled differently in Spring.NET. - /// Keeping the name is useful as a placeholder for future porting work. - /// - /// Spring.Java Folks - /// Choy Rim (.NET) - public class TimestampIntroductionInterceptor : IAdvice, ITimeStamped, IInterceptor - { - private DateTime ts; + private DateTime ts; - public TimestampIntroductionInterceptor() - { - } + public TimestampIntroductionInterceptor() + { + } - public TimestampIntroductionInterceptor(DateTime ts) - { - this.ts = ts; - } - - #region ITimeStamped Members + public TimestampIntroductionInterceptor(DateTime ts) + { + this.ts = ts; + } - public DateTime TimeStamp - { - get - { - return this.ts; - } - set - { - this.ts = value; - } - } + #region ITimeStamped Members - #endregion - } + public DateTime TimeStamp + { + get + { + return this.ts; + } + set + { + this.ts = value; + } + } + + #endregion } diff --git a/test/Spring/Spring.Aop.Tests/Aop/Framework/UnsupportedInterceptor.cs b/test/Spring/Spring.Aop.Tests/Aop/Framework/UnsupportedInterceptor.cs index 2ca0cc3b..07a4c930 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Framework/UnsupportedInterceptor.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Framework/UnsupportedInterceptor.cs @@ -1,12 +1,11 @@ using AopAlliance.Intercept; -namespace Spring.Aop.Framework +namespace Spring.Aop.Framework; + +public class UnsupportedInterceptor : IMethodInterceptor { - public class UnsupportedInterceptor : IMethodInterceptor - { - public object Invoke(IMethodInvocation invocation) - { - throw new NotImplementedException(invocation.Method.Name); - } - } + public object Invoke(IMethodInvocation invocation) + { + throw new NotImplementedException(invocation.Method.Name); + } } diff --git a/test/Spring/Spring.Aop.Tests/Aop/ISimpleBeforeAdvice.cs b/test/Spring/Spring.Aop.Tests/Aop/ISimpleBeforeAdvice.cs index 7448291b..8809dc32 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/ISimpleBeforeAdvice.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/ISimpleBeforeAdvice.cs @@ -1,36 +1,35 @@ #region License + /* * Copyright 2002-2010 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 #region Imports - - #endregion -namespace Spring.Aop +namespace Spring.Aop; + +/// +/// Simple BeforeAdvice targeted for testing +/// +/// Dmitriy Kopylenko +/// Simon White (.NET) +public interface ISimpleBeforeAdvice : IBeforeAdvice { - /// - /// Simple BeforeAdvice targeted for testing - /// - /// Dmitriy Kopylenko - /// Simon White (.NET) - public interface ISimpleBeforeAdvice : IBeforeAdvice - { - void Before(); - } + void Before(); } diff --git a/test/Spring/Spring.Aop.Tests/Aop/Interceptor/NopInterceptor.cs b/test/Spring/Spring.Aop.Tests/Aop/Interceptor/NopInterceptor.cs index 8ba2e1a5..18fcb0c2 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Interceptor/NopInterceptor.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Interceptor/NopInterceptor.cs @@ -24,61 +24,61 @@ using System.Reflection; #endregion -namespace Spring.Aop.Interceptor +namespace Spring.Aop.Interceptor; + +/// +/// Trivial interceptor that can be introduced into an interceptor chain to +/// aid in debugging. +/// +/// Rod Johnson +/// Choy Rim (.NET) +public class NopInterceptor : IMethodBeforeAdvice { - /// - /// Trivial interceptor that can be introduced into an interceptor chain to - /// aid in debugging. - /// - /// Rod Johnson - /// Choy Rim (.NET) - public class NopInterceptor : IMethodBeforeAdvice - { - protected int instanceId; - protected int count; + protected int instanceId; + protected int count; + public NopInterceptor() : this(0) + { + } - public NopInterceptor() : this(0) - { - } + public NopInterceptor(int instanceId) + { + this.instanceId = instanceId; + } - public NopInterceptor(int instanceId) - { - this.instanceId = instanceId; - } + public int InstanceId + { + get { return instanceId; } + } - public int InstanceId - { - get { return instanceId; } - } + public int Count + { + get { return this.count; } + } - public int Count - { - get { return this.count; } - } + public void Before(MethodInfo method, object[] args, object target) + { + ++count; + } - public void Before(MethodInfo method, object[] args, object target) - { - ++count; - } + public override bool Equals(Object other) + { + if (!(other is NopInterceptor)) + { + return false; + } - public override bool Equals(Object other) - { - if (!(other is NopInterceptor)) - { - return false; - } - if (this == other) - { - return true; - } - return (instanceId == ((NopInterceptor) other).InstanceId) - && (count == ((NopInterceptor) other).count); - } + if (this == other) + { + return true; + } - public override int GetHashCode() - { - return instanceId + 13 * count; - } - } -} \ No newline at end of file + return (instanceId == ((NopInterceptor) other).InstanceId) + && (count == ((NopInterceptor) other).count); + } + + public override int GetHashCode() + { + return instanceId + 13 * count; + } +} diff --git a/test/Spring/Spring.Aop.Tests/Aop/Interceptor/SerializableNopInterceptor.cs b/test/Spring/Spring.Aop.Tests/Aop/Interceptor/SerializableNopInterceptor.cs index 89473a6b..d28e6573 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Interceptor/SerializableNopInterceptor.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Interceptor/SerializableNopInterceptor.cs @@ -1,52 +1,53 @@ #region License + /* * Copyright 2002-2010 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 #region Imports using System.Runtime.Serialization; + #endregion -namespace Spring.Aop.Interceptor +namespace Spring.Aop.Interceptor; + +/// +/// Subclass of NopInterceptor that is serializable and +/// can be used to test proxy serialization. +/// +/// Rod Johnson +/// Simon White (.NET) +[Serializable] +public sealed class SerializableNopInterceptor : NopInterceptor, ISerializable { - /// - /// Subclass of NopInterceptor that is serializable and - /// can be used to test proxy serialization. - /// - /// Rod Johnson - /// Simon White (.NET) - [Serializable] - public sealed class SerializableNopInterceptor : NopInterceptor, ISerializable - { - public SerializableNopInterceptor() - { - } + public SerializableNopInterceptor() + { + } - public SerializableNopInterceptor(SerializationInfo info, StreamingContext ctxt) - { - this.instanceId = (int) info.GetValue("InstanceId", typeof(int)); - this.count = (int)info.GetValue("Count", typeof(int)); - } + public SerializableNopInterceptor(SerializationInfo info, StreamingContext ctxt) + { + this.instanceId = (int) info.GetValue("InstanceId", typeof(int)); + this.count = (int) info.GetValue("Count", typeof(int)); + } - public void GetObjectData(SerializationInfo info, StreamingContext ctxt) - { - info.AddValue("InstanceId", InstanceId); - info.AddValue("Count", Count); - } - - } + public void GetObjectData(SerializationInfo info, StreamingContext ctxt) + { + info.AddValue("InstanceId", InstanceId); + info.AddValue("Count", Count); + } } diff --git a/test/Spring/Spring.Aop.Tests/Aop/SimpleBeforeAdviceAdapter.cs b/test/Spring/Spring.Aop.Tests/Aop/SimpleBeforeAdviceAdapter.cs index aabe2276..e2bc3e29 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/SimpleBeforeAdviceAdapter.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/SimpleBeforeAdviceAdapter.cs @@ -1,50 +1,53 @@ #region License + /* * Copyright 2002-2010 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 #region Imports using AopAlliance.Aop; using AopAlliance.Intercept; - using Spring.Aop.Framework.Adapter; + #endregion -namespace Spring.Aop -{ - /// - /// - /// - /// Dmitriy Kopylenko - /// Simon White (.NET) - [Serializable] - public class SimpleBeforeAdviceAdapter : IAdvisorAdapter - { - #region IAdvisorAdapter Members - public bool SupportsAdvice(IAdvice advice) - { - return advice is ISimpleBeforeAdvice; - } +namespace Spring.Aop; - public IInterceptor GetInterceptor(IAdvisor advisor) - { - ISimpleBeforeAdvice advice = (ISimpleBeforeAdvice) advisor.Advice; - return new SimpleBeforeAdviceInterceptor(advice) ; - } - #endregion - } +/// +/// +/// +/// Dmitriy Kopylenko +/// Simon White (.NET) +[Serializable] +public class SimpleBeforeAdviceAdapter : IAdvisorAdapter +{ + #region IAdvisorAdapter Members + + public bool SupportsAdvice(IAdvice advice) + { + return advice is ISimpleBeforeAdvice; + } + + public IInterceptor GetInterceptor(IAdvisor advisor) + { + ISimpleBeforeAdvice advice = (ISimpleBeforeAdvice) advisor.Advice; + return new SimpleBeforeAdviceInterceptor(advice); + } + + #endregion } diff --git a/test/Spring/Spring.Aop.Tests/Aop/SimpleBeforeAdviceImpl.cs b/test/Spring/Spring.Aop.Tests/Aop/SimpleBeforeAdviceImpl.cs index 7e59d227..bb114abd 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/SimpleBeforeAdviceImpl.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/SimpleBeforeAdviceImpl.cs @@ -1,59 +1,64 @@ #region License + /* * Copyright 2002-2010 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 #region Imports - - #endregion -namespace Spring.Aop +namespace Spring.Aop; + +/// +/// +/// +/// Dmitriy Kopylenko +/// Simon White (.NET) +public class SimpleBeforeAdviceImpl : ISimpleBeforeAdvice { - /// - /// - /// - /// Dmitriy Kopylenko - /// Simon White (.NET) - public class SimpleBeforeAdviceImpl : ISimpleBeforeAdvice - { - private int _invocationCounter; + private int _invocationCounter; - #region Properties - public int InvocationCounter - { - get - { - return _invocationCounter; - } - } - #endregion + #region Properties - #region Constructors - public SimpleBeforeAdviceImpl() - { - } - #endregion + public int InvocationCounter + { + get + { + return _invocationCounter; + } + } - #region ISimpleBeforeAdvice Members - public void Before() - { - ++_invocationCounter; - } - #endregion - } + #endregion + + #region Constructors + + public SimpleBeforeAdviceImpl() + { + } + + #endregion + + #region ISimpleBeforeAdvice Members + + public void Before() + { + ++_invocationCounter; + } + + #endregion } diff --git a/test/Spring/Spring.Aop.Tests/Aop/SimpleBeforeAdviceInterceptor.cs b/test/Spring/Spring.Aop.Tests/Aop/SimpleBeforeAdviceInterceptor.cs index af5ef65d..c8154acb 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/SimpleBeforeAdviceInterceptor.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/SimpleBeforeAdviceInterceptor.cs @@ -1,50 +1,56 @@ #region License + /* * Copyright 2002-2010 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 #region Imports using AopAlliance.Intercept; + #endregion -namespace Spring.Aop -{ - /// - /// - /// - /// Dmitriy Kopylenko - /// Simon White (.NET) - public class SimpleBeforeAdviceInterceptor : IMethodInterceptor - { - private ISimpleBeforeAdvice _advice; - - #region Constructors - public SimpleBeforeAdviceInterceptor(ISimpleBeforeAdvice advice) - { - this._advice = advice; - } - #endregion +namespace Spring.Aop; - #region IMethodInterceptor Members - public object Invoke(IMethodInvocation mi) - { - _advice.Before(); - return mi.Proceed(); - } - #endregion - } +/// +/// +/// +/// Dmitriy Kopylenko +/// Simon White (.NET) +public class SimpleBeforeAdviceInterceptor : IMethodInterceptor +{ + private ISimpleBeforeAdvice _advice; + + #region Constructors + + public SimpleBeforeAdviceInterceptor(ISimpleBeforeAdvice advice) + { + this._advice = advice; + } + + #endregion + + #region IMethodInterceptor Members + + public object Invoke(IMethodInvocation mi) + { + _advice.Before(); + return mi.Proceed(); + } + + #endregion } diff --git a/test/Spring/Spring.Aop.Tests/Aop/Support/AbstractRegularExpressionMethodPointcutTests.cs b/test/Spring/Spring.Aop.Tests/Aop/Support/AbstractRegularExpressionMethodPointcutTests.cs index 5b5735e4..db61bfe9 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Support/AbstractRegularExpressionMethodPointcutTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Support/AbstractRegularExpressionMethodPointcutTests.cs @@ -1,143 +1,141 @@ #region License + /* * Copyright 2002-2010 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 #region Imports using System.Reflection; - using Spring.Util; - using NUnit.Framework; + #endregion -namespace Spring.Aop.Support +namespace Spring.Aop.Support; + +/// +/// Unit tests for the AbstractRegularExpressionMethodPointcut class. +/// +/// Rod Johnson +/// Dmitriy Kopylenko +/// Simon White (.NET) +public abstract class AbstractRegularExpressionMethodPointcutTests { - /// - /// Unit tests for the AbstractRegularExpressionMethodPointcut class. - /// - /// Rod Johnson - /// Dmitriy Kopylenko - /// Simon White (.NET) - public abstract class AbstractRegularExpressionMethodPointcutTests - { - private AbstractRegularExpressionMethodPointcut pointcut; + private AbstractRegularExpressionMethodPointcut pointcut; - [SetUp] - protected void SetUp() - { - pointcut = GetRegexpMethodPointcut(); - } + [SetUp] + protected void SetUp() + { + pointcut = GetRegexpMethodPointcut(); + } - protected abstract AbstractRegularExpressionMethodPointcut GetRegexpMethodPointcut(); + protected abstract AbstractRegularExpressionMethodPointcut GetRegexpMethodPointcut(); - [Test] - public void NoPatternSupplied() - { - NoPatternSuppliedTests(pointcut); - } + [Test] + public void NoPatternSupplied() + { + NoPatternSuppliedTests(pointcut); + } - [Test] - public void SerializationWithNoPatternSupplied() - { - pointcut = (AbstractRegularExpressionMethodPointcut) SerializationTestUtils.SerializeAndDeserialize(pointcut); - NoPatternSuppliedTests(pointcut); - } + [Test] + public void SerializationWithNoPatternSupplied() + { + pointcut = (AbstractRegularExpressionMethodPointcut) SerializationTestUtils.SerializeAndDeserialize(pointcut); + NoPatternSuppliedTests(pointcut); + } - protected void NoPatternSuppliedTests(AbstractRegularExpressionMethodPointcut rpc) - { - Assert.IsFalse(rpc.Matches(typeof(object).GetMethod("GetHashCode"), typeof(int))); - Assert.IsFalse(rpc.Matches(typeof(object).GetMethod("GetType"), typeof(Type))); - Assert.AreEqual(0, rpc.Patterns.Length); - } + protected void NoPatternSuppliedTests(AbstractRegularExpressionMethodPointcut rpc) + { + Assert.IsFalse(rpc.Matches(typeof(object).GetMethod("GetHashCode"), typeof(int))); + Assert.IsFalse(rpc.Matches(typeof(object).GetMethod("GetType"), typeof(Type))); + Assert.AreEqual(0, rpc.Patterns.Length); + } - [Test] - public void ExactMatch() - { - pointcut.Pattern = "System.Object.GetHashCode"; - ExactMatchTests(pointcut); - pointcut = (AbstractRegularExpressionMethodPointcut) SerializationTestUtils.SerializeAndDeserialize(pointcut); - ExactMatchTests(pointcut); - } + [Test] + public void ExactMatch() + { + pointcut.Pattern = "System.Object.GetHashCode"; + ExactMatchTests(pointcut); + pointcut = (AbstractRegularExpressionMethodPointcut) SerializationTestUtils.SerializeAndDeserialize(pointcut); + ExactMatchTests(pointcut); + } + protected void ExactMatchWithGenericTypeTests(AbstractRegularExpressionMethodPointcut rpc) + { + // assumes rpc.setPattern("System.Collections.Generic.List"); + Assert.IsTrue(rpc.Matches(typeof(System.Collections.Generic.List).GetMethod("Add"), typeof(int))); + Assert.IsFalse(rpc.Matches(typeof(System.Collections.Generic.List).GetMethod("GetType"), typeof(Type))); + } - protected void ExactMatchWithGenericTypeTests(AbstractRegularExpressionMethodPointcut rpc) - { - // assumes rpc.setPattern("System.Collections.Generic.List"); - Assert.IsTrue(rpc.Matches(typeof(System.Collections.Generic.List).GetMethod("Add"), typeof(int))); - Assert.IsFalse(rpc.Matches(typeof(System.Collections.Generic.List).GetMethod("GetType"), typeof(Type))); - } + [Test] + public void ExactMatchWithGenericType() + { + pointcut.Pattern = "System.Collections.Generic.List.Add"; + ExactMatchWithGenericTypeTests(pointcut); + pointcut = (AbstractRegularExpressionMethodPointcut) SerializationTestUtils.SerializeAndDeserialize(pointcut); + ExactMatchWithGenericTypeTests(pointcut); + } - [Test] - public void ExactMatchWithGenericType() - { - pointcut.Pattern = "System.Collections.Generic.List.Add"; - ExactMatchWithGenericTypeTests(pointcut); - pointcut = (AbstractRegularExpressionMethodPointcut)SerializationTestUtils.SerializeAndDeserialize(pointcut); - ExactMatchWithGenericTypeTests(pointcut); - } + [Test] + public void WildcardWithGenericType() + { + pointcut.Pattern = ".*List.Add"; + Assert.IsTrue(pointcut.Matches(typeof(System.Collections.Generic.List).GetMethod("Add"), typeof(int))); + Assert.IsFalse(pointcut.Matches(typeof(System.Collections.Generic.List).GetMethod("GetType"), typeof(Type))); + } - [Test] - public void WildcardWithGenericType() - { - pointcut.Pattern = ".*List.Add"; - Assert.IsTrue(pointcut.Matches(typeof(System.Collections.Generic.List).GetMethod("Add"), typeof(int))); - Assert.IsFalse(pointcut.Matches(typeof(System.Collections.Generic.List).GetMethod("GetType"), typeof(Type))); - } + [Test] + public void WildcardForOneClassWithGenericType() + { + pointcut.Pattern = "System.Collections.*"; + Assert.IsTrue(pointcut.Matches(typeof(System.Collections.Generic.List).GetMethod("Add"), typeof(int))); + Assert.IsFalse(pointcut.Matches(typeof(System.Collections.Generic.List).GetMethod("GetType"), typeof(Type))); + } - [Test] - public void WildcardForOneClassWithGenericType() - { - pointcut.Pattern = "System.Collections.*"; - Assert.IsTrue(pointcut.Matches(typeof(System.Collections.Generic.List).GetMethod("Add"), typeof(int))); - Assert.IsFalse(pointcut.Matches(typeof(System.Collections.Generic.List).GetMethod("GetType"), typeof(Type))); - } + protected void ExactMatchTests(AbstractRegularExpressionMethodPointcut rpc) + { + // assumes rpc.setPattern("java.lang.Object.hashCode"); + Assert.IsTrue(rpc.Matches(typeof(object).GetMethod("GetHashCode"), typeof(int))); + Assert.IsFalse(rpc.Matches(typeof(object).GetMethod("GetType"), typeof(Type))); + } - protected void ExactMatchTests(AbstractRegularExpressionMethodPointcut rpc) - { - // assumes rpc.setPattern("java.lang.Object.hashCode"); - Assert.IsTrue(rpc.Matches(typeof(object).GetMethod("GetHashCode"), typeof(int))); - Assert.IsFalse(rpc.Matches(typeof(object).GetMethod("GetType"), typeof(Type))); - } + [Test] + public void Wildcard() + { + pointcut.Pattern = ".*Object.GetHashCode"; + Assert.IsTrue(pointcut.Matches(typeof(object).GetMethod("GetHashCode"), typeof(int))); + Assert.IsFalse(pointcut.Matches(typeof(object).GetMethod("GetType"), typeof(Type))); + } - [Test] - public void Wildcard() - { - pointcut.Pattern = ".*Object.GetHashCode"; - Assert.IsTrue(pointcut.Matches(typeof(object).GetMethod("GetHashCode"), typeof(int))); - Assert.IsFalse(pointcut.Matches(typeof(object).GetMethod("GetType"), typeof(Type))); - } - - [Test] - public void WildcardForOneClass() - { - pointcut.Pattern = "System.Object.*"; - Assert.IsTrue(pointcut.Matches(typeof(object).GetMethod("GetHashCode"), typeof(int))); - Assert.IsTrue(pointcut.Matches(typeof(object).GetMethod("GetType"), typeof(Type))); - } + [Test] + public void WildcardForOneClass() + { + pointcut.Pattern = "System.Object.*"; + Assert.IsTrue(pointcut.Matches(typeof(object).GetMethod("GetHashCode"), typeof(int))); + Assert.IsTrue(pointcut.Matches(typeof(object).GetMethod("GetType"), typeof(Type))); + } - [Test] - public void MatchesObjectClass() - { - pointcut.Pattern = "Object.*"; - Assert.IsTrue(pointcut.Matches(typeof(Exception).GetMethod("GetHashCode"), typeof(TargetException))); - // Doesn't match - Assert.IsFalse(pointcut.Matches(typeof(Exception).GetMethod("ToString"), typeof(Exception))); - } - - } + [Test] + public void MatchesObjectClass() + { + pointcut.Pattern = "Object.*"; + Assert.IsTrue(pointcut.Matches(typeof(Exception).GetMethod("GetHashCode"), typeof(TargetException))); + // Doesn't match + Assert.IsFalse(pointcut.Matches(typeof(Exception).GetMethod("ToString"), typeof(Exception))); + } } diff --git a/test/Spring/Spring.Aop.Tests/Aop/Support/AttributeMatchMethodPointcutTests.cs b/test/Spring/Spring.Aop.Tests/Aop/Support/AttributeMatchMethodPointcutTests.cs index d626f002..0c9dd1ce 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Support/AttributeMatchMethodPointcutTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Support/AttributeMatchMethodPointcutTests.cs @@ -25,236 +25,236 @@ using System.Reflection; #endregion -namespace Spring.Aop.Support +namespace Spring.Aop.Support; + +/// +/// Unit tests for the AttributeMatchMethodPointcut class. +/// +/// Rick Evans +/// Ronald Wildenberg +[TestFixture] +public sealed class AttributeMatchMethodPointcutTests { - /// - /// Unit tests for the AttributeMatchMethodPointcut class. - /// - /// Rick Evans - /// Ronald Wildenberg - [TestFixture] - public sealed class AttributeMatchMethodPointcutTests - { - [Test] - public void InstantiationWithASunnyDayAttributeType() - { - new AttributeMatchMethodPointcut(typeof(SerializableAttribute)); - } - - [Test] - public void InstantiationWithNonAttributeType() - { - Assert.Throws(() => new AttributeMatchMethodPointcut(GetType())); - } - - [Test] - public void AttributeSetterWithNonAttributeType() - { - AttributeMatchMethodPointcut cut = new AttributeMatchMethodPointcut(); - Assert.Throws(() => cut.Attribute = GetType()); - } - - [Test] - public void AttributeSetterWithNullType() - { - AttributeMatchMethodPointcut cut = new AttributeMatchMethodPointcut(); - cut.Attribute = null; // must allow this (no Exception)... - } - - [Test] - public void AttributeSetterWithASunnyDayAttributeType() - { - AttributeMatchMethodPointcut cut = new AttributeMatchMethodPointcut(); - cut.Attribute = typeof(SerializableAttribute); // must allow this too (no Exception)... - } - - [Test] - public void MatchesWithASunnyDayAttributeTypeAndNoInheritance() - { - AttributeMatchMethodPointcut cut = new AttributeMatchMethodPointcut(); - cut.Attribute = typeof(MarkupAttribute); - bool matches = cut.Matches(typeof(WithMarkup).GetMethod("Bing"), null); - Assert.IsTrue(matches, "Method was decorated with the target attribute, so this must match."); - } - - [Test] - public void MatchesWithASunnyDayAttributeTypeAndInheritance() - { - AttributeMatchMethodPointcut cut = new AttributeMatchMethodPointcut(); - cut.Attribute = typeof(MarkupAttribute); - bool matches = cut.Matches(typeof(InheritedWithMarkup).GetMethod("Bing"), null); - Assert.IsTrue(matches, "Inherited method was decorated with the target attribute, so this must match."); - } - - [Test] - public void MatchesWithAMethodThatDontMatchTheAttributeTypeAndNoInheritance() - { - AttributeMatchMethodPointcut cut = new AttributeMatchMethodPointcut(); - cut.Attribute = typeof(MarkupAttribute); - bool matches = cut.Matches(typeof(WithMarkup).GetMethod("RiloKiley"), null); - Assert.IsFalse(matches, "Method was not decorated with the target attribute, so this must not match."); - } - - [Test] - public void MatchesWithAnInheritedMethodThatDontMatchTheAttributeTypeAndNoInheritance() - { - AttributeMatchMethodPointcut cut = new AttributeMatchMethodPointcut(); - cut.Attribute = typeof(MarkupAttribute); - bool matches = cut.Matches(typeof(InheritedWithMarkup).GetMethod("RiloKiley"), null); - Assert.IsFalse(matches, "Inherited method was not decorated with the target attribute, so this must not match."); - } - - /// - /// Confirms that without interfaces checking, a method that is implemented from an interface, will not match. - /// - [Test] - public void MatchesWithAnInterfaceMethodThatMatchesTheAttributeTypeAndNoCheckInterfaces() - { - AttributeMatchMethodPointcut cut = new AttributeMatchMethodPointcut(); - cut.Attribute = typeof(MarkupAttribute); - cut.CheckInterfaces = false; - bool matches = cut.Matches(typeof(ImplementingClass).GetMethod("OtherTestMethod"), null); - Assert.IsFalse(matches, "Implementing method was not decorated with the target attribute, so this must not match since CheckInterfaces is false."); - } - - /// - /// Confirms that with interface checking, a method that is implementing an interface method - /// where the attribute is defined will match. - /// - [Test] - public void MatchesWithAnInterfaceMethodThatMatchesTheAttributeTypeAndCheckInterfaces() - { - AttributeMatchMethodPointcut cut = new AttributeMatchMethodPointcut(); - cut.Attribute = typeof(MarkupAttribute); - cut.CheckInterfaces = true; - bool matches = cut.Matches(typeof(ImplementingClass).GetMethod("OtherTestMethod"), null); - Assert.IsTrue(matches, "Implementing method was not decorated with the target attribute, " + - "but the method from the interface was, so this must match."); - } - - /// - /// Confirms that with interfaces checking, a method that is indirectly implementing an interface method - /// where the attribute is defined will match. - /// - [Test] - public void MatchesWithAnIndirectInterfaceMethodThatMatchesTheAttributeTypeAndCheckInterfaces() - { - AttributeMatchMethodPointcut cut = new AttributeMatchMethodPointcut(); - cut.Attribute = typeof(MarkupAttribute); - cut.CheckInterfaces = true; - bool matches = cut.Matches(typeof(ImplementingClass).GetMethod("TestMethod", new Type[] { }), null); - Assert.IsTrue(matches, "Implementing method was not decorated with the target attribute, but the" + - " method from an indirectly implemented interface was, so this must match."); - } - - /// - /// Confirms that overloading methods do not match, whatever the attributes. - /// - [Test] - public void MatchesWithAnOverloadedInterfaceMethod() - { - AttributeMatchMethodPointcut cut = new AttributeMatchMethodPointcut(); - cut.Attribute = typeof(MarkupAttribute); - cut.CheckInterfaces = true; - bool matches = cut.Matches(typeof(ImplementingClass).GetMethod("TestMethod", new Type[] { typeof(string) }), null); - Assert.IsFalse(matches, "Overloaded method from an implemented interface is not decorated with" + - " the attribute, so should not match."); - } - - /// - /// Confirms that methods, defined in a subclass of a class that implements an interface that - /// has methods that have been decorated with an attribute, match. - /// - [Test] - public void MatchesWithAnIndirectInterfaceMethodFromSubclassThatMatchesTheAttributeTypeAndCheckInterfaces() - { - AttributeMatchMethodPointcut cut = new AttributeMatchMethodPointcut(); - cut.Attribute = typeof(MarkupAttribute); - cut.CheckInterfaces = true; - bool matches = cut.Matches(typeof(InheritedImplementingClass).GetMethod("TestMethod", new Type[] { }), null); - Assert.IsTrue(matches, "Implementing method from subclass was not decorated with the target attribute " + - "but the method from an indirectly implemented interface was, so this must match."); - } - - /// - /// Confirms that methods, explicitly implemented in the derived classes will match - /// - [Test(Description="SPRNET-1314")] - public void MatchesWhenExplicitlyImplemed() - { - AttributeMatchMethodPointcut cut = new AttributeMatchMethodPointcut(); - cut.Attribute = typeof(MarkupAttribute); - cut.CheckInterfaces = true; - - // Only methods implemented expicitly are marked with attribute - foreach (MethodInfo mi in typeof(ExplicitlyImplementingClass).GetMethods(BindingFlags.Instance | BindingFlags.NonPublic)) - { - if (mi.Name.IndexOf('.') == -1) continue; - bool matches = cut.Matches(mi, null); - Assert.IsTrue(matches, "Explicitly implemented method must match"); - } - - } - - #region Helper classes definitions - - [AttributeUsage(AttributeTargets.Method)] - private sealed class MarkupAttribute : Attribute {} - - private class WithMarkup - { - [Markup] - public void Bing() {} - - public void RiloKiley() {} - } - - private sealed class InheritedWithMarkup : WithMarkup - { - } - - private interface SuperInterface - { - [Markup] - void TestMethod(); - - void TestMethod(string param); - } - - private interface SubInterface : SuperInterface - { - [Markup] - void OtherTestMethod(); - } - - private interface AnotherSuperInterface - { - [Markup] - void TestMethod(); - } - - private class ImplementingClass : SubInterface - { - public void TestMethod() {} - - public void TestMethod(string param) {} - - public void OtherTestMethod() {} - } - - private sealed class InheritedImplementingClass : ImplementingClass - { - } - - private class ExplicitlyImplementingClass : SuperInterface, AnotherSuperInterface - { - void AnotherSuperInterface.TestMethod() { } - - void SuperInterface.TestMethod() { } - - public void TestMethod(string param) {} - } - - #endregion + [Test] + public void InstantiationWithASunnyDayAttributeType() + { + new AttributeMatchMethodPointcut(typeof(SerializableAttribute)); } + + [Test] + public void InstantiationWithNonAttributeType() + { + Assert.Throws(() => new AttributeMatchMethodPointcut(GetType())); + } + + [Test] + public void AttributeSetterWithNonAttributeType() + { + AttributeMatchMethodPointcut cut = new AttributeMatchMethodPointcut(); + Assert.Throws(() => cut.Attribute = GetType()); + } + + [Test] + public void AttributeSetterWithNullType() + { + AttributeMatchMethodPointcut cut = new AttributeMatchMethodPointcut(); + cut.Attribute = null; // must allow this (no Exception)... + } + + [Test] + public void AttributeSetterWithASunnyDayAttributeType() + { + AttributeMatchMethodPointcut cut = new AttributeMatchMethodPointcut(); + cut.Attribute = typeof(SerializableAttribute); // must allow this too (no Exception)... + } + + [Test] + public void MatchesWithASunnyDayAttributeTypeAndNoInheritance() + { + AttributeMatchMethodPointcut cut = new AttributeMatchMethodPointcut(); + cut.Attribute = typeof(MarkupAttribute); + bool matches = cut.Matches(typeof(WithMarkup).GetMethod("Bing"), null); + Assert.IsTrue(matches, "Method was decorated with the target attribute, so this must match."); + } + + [Test] + public void MatchesWithASunnyDayAttributeTypeAndInheritance() + { + AttributeMatchMethodPointcut cut = new AttributeMatchMethodPointcut(); + cut.Attribute = typeof(MarkupAttribute); + bool matches = cut.Matches(typeof(InheritedWithMarkup).GetMethod("Bing"), null); + Assert.IsTrue(matches, "Inherited method was decorated with the target attribute, so this must match."); + } + + [Test] + public void MatchesWithAMethodThatDontMatchTheAttributeTypeAndNoInheritance() + { + AttributeMatchMethodPointcut cut = new AttributeMatchMethodPointcut(); + cut.Attribute = typeof(MarkupAttribute); + bool matches = cut.Matches(typeof(WithMarkup).GetMethod("RiloKiley"), null); + Assert.IsFalse(matches, "Method was not decorated with the target attribute, so this must not match."); + } + + [Test] + public void MatchesWithAnInheritedMethodThatDontMatchTheAttributeTypeAndNoInheritance() + { + AttributeMatchMethodPointcut cut = new AttributeMatchMethodPointcut(); + cut.Attribute = typeof(MarkupAttribute); + bool matches = cut.Matches(typeof(InheritedWithMarkup).GetMethod("RiloKiley"), null); + Assert.IsFalse(matches, "Inherited method was not decorated with the target attribute, so this must not match."); + } + + /// + /// Confirms that without interfaces checking, a method that is implemented from an interface, will not match. + /// + [Test] + public void MatchesWithAnInterfaceMethodThatMatchesTheAttributeTypeAndNoCheckInterfaces() + { + AttributeMatchMethodPointcut cut = new AttributeMatchMethodPointcut(); + cut.Attribute = typeof(MarkupAttribute); + cut.CheckInterfaces = false; + bool matches = cut.Matches(typeof(ImplementingClass).GetMethod("OtherTestMethod"), null); + Assert.IsFalse(matches, "Implementing method was not decorated with the target attribute, so this must not match since CheckInterfaces is false."); + } + + /// + /// Confirms that with interface checking, a method that is implementing an interface method + /// where the attribute is defined will match. + /// + [Test] + public void MatchesWithAnInterfaceMethodThatMatchesTheAttributeTypeAndCheckInterfaces() + { + AttributeMatchMethodPointcut cut = new AttributeMatchMethodPointcut(); + cut.Attribute = typeof(MarkupAttribute); + cut.CheckInterfaces = true; + bool matches = cut.Matches(typeof(ImplementingClass).GetMethod("OtherTestMethod"), null); + Assert.IsTrue(matches, "Implementing method was not decorated with the target attribute, " + + "but the method from the interface was, so this must match."); + } + + /// + /// Confirms that with interfaces checking, a method that is indirectly implementing an interface method + /// where the attribute is defined will match. + /// + [Test] + public void MatchesWithAnIndirectInterfaceMethodThatMatchesTheAttributeTypeAndCheckInterfaces() + { + AttributeMatchMethodPointcut cut = new AttributeMatchMethodPointcut(); + cut.Attribute = typeof(MarkupAttribute); + cut.CheckInterfaces = true; + bool matches = cut.Matches(typeof(ImplementingClass).GetMethod("TestMethod", new Type[] { }), null); + Assert.IsTrue(matches, "Implementing method was not decorated with the target attribute, but the" + + " method from an indirectly implemented interface was, so this must match."); + } + + /// + /// Confirms that overloading methods do not match, whatever the attributes. + /// + [Test] + public void MatchesWithAnOverloadedInterfaceMethod() + { + AttributeMatchMethodPointcut cut = new AttributeMatchMethodPointcut(); + cut.Attribute = typeof(MarkupAttribute); + cut.CheckInterfaces = true; + bool matches = cut.Matches(typeof(ImplementingClass).GetMethod("TestMethod", new Type[] { typeof(string) }), null); + Assert.IsFalse(matches, "Overloaded method from an implemented interface is not decorated with" + + " the attribute, so should not match."); + } + + /// + /// Confirms that methods, defined in a subclass of a class that implements an interface that + /// has methods that have been decorated with an attribute, match. + /// + [Test] + public void MatchesWithAnIndirectInterfaceMethodFromSubclassThatMatchesTheAttributeTypeAndCheckInterfaces() + { + AttributeMatchMethodPointcut cut = new AttributeMatchMethodPointcut(); + cut.Attribute = typeof(MarkupAttribute); + cut.CheckInterfaces = true; + bool matches = cut.Matches(typeof(InheritedImplementingClass).GetMethod("TestMethod", new Type[] { }), null); + Assert.IsTrue(matches, "Implementing method from subclass was not decorated with the target attribute " + + "but the method from an indirectly implemented interface was, so this must match."); + } + + /// + /// Confirms that methods, explicitly implemented in the derived classes will match + /// + [Test(Description = "SPRNET-1314")] + public void MatchesWhenExplicitlyImplemed() + { + AttributeMatchMethodPointcut cut = new AttributeMatchMethodPointcut(); + cut.Attribute = typeof(MarkupAttribute); + cut.CheckInterfaces = true; + + // Only methods implemented expicitly are marked with attribute + foreach (MethodInfo mi in typeof(ExplicitlyImplementingClass).GetMethods(BindingFlags.Instance | BindingFlags.NonPublic)) + { + if (mi.Name.IndexOf('.') == -1) continue; + bool matches = cut.Matches(mi, null); + Assert.IsTrue(matches, "Explicitly implemented method must match"); + } + } + + #region Helper classes definitions + + [AttributeUsage(AttributeTargets.Method)] + private sealed class MarkupAttribute : Attribute + { + } + + private class WithMarkup + { + [Markup] + public void Bing() { } + + public void RiloKiley() { } + } + + private sealed class InheritedWithMarkup : WithMarkup + { + } + + private interface SuperInterface + { + [Markup] + void TestMethod(); + + void TestMethod(string param); + } + + private interface SubInterface : SuperInterface + { + [Markup] + void OtherTestMethod(); + } + + private interface AnotherSuperInterface + { + [Markup] + void TestMethod(); + } + + private class ImplementingClass : SubInterface + { + public void TestMethod() { } + + public void TestMethod(string param) { } + + public void OtherTestMethod() { } + } + + private sealed class InheritedImplementingClass : ImplementingClass + { + } + + private class ExplicitlyImplementingClass : SuperInterface, AnotherSuperInterface + { + void AnotherSuperInterface.TestMethod() { } + + void SuperInterface.TestMethod() { } + + public void TestMethod(string param) { } + } + + #endregion } diff --git a/test/Spring/Spring.Aop.Tests/Aop/Support/ControlFlowPointcutTests.cs b/test/Spring/Spring.Aop.Tests/Aop/Support/ControlFlowPointcutTests.cs index 4178dc0e..045e2d3e 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Support/ControlFlowPointcutTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Support/ControlFlowPointcutTests.cs @@ -29,199 +29,198 @@ using Spring.Objects; #endregion -namespace Spring.Aop.Support +namespace Spring.Aop.Support; + +/// +/// Unit tests for the ControlFlowPointcut class. +/// +/// Rod Johnson +/// Simon White (.NET) +[TestFixture] +public sealed class ControlFlowPointcutTests { - /// - /// Unit tests for the ControlFlowPointcut class. - /// - /// Rod Johnson - /// Simon White (.NET) - [TestFixture] - public sealed class ControlFlowPointcutTests - { - [Test] - [Category("Integration")] - public void Matches() - { - SerializablePerson target = new SerializablePerson(); - target.SetAge(27); - ControlFlowPointcut cflow = new ControlFlowPointcut(typeof(One), "GetAge"); - ProxyFactory factory = new ProxyFactory(target); - NopInterceptor nop = new NopInterceptor(); - IPerson proxied = (IPerson) factory.GetProxy(); - factory.AddAdvisor(new DefaultPointcutAdvisor(cflow, nop)); + [Test] + [Category("Integration")] + public void Matches() + { + SerializablePerson target = new SerializablePerson(); + target.SetAge(27); + ControlFlowPointcut cflow = new ControlFlowPointcut(typeof(One), "GetAge"); + ProxyFactory factory = new ProxyFactory(target); + NopInterceptor nop = new NopInterceptor(); + IPerson proxied = (IPerson) factory.GetProxy(); + factory.AddAdvisor(new DefaultPointcutAdvisor(cflow, nop)); - // not advised, not under One... - Assert.AreEqual(target.GetAge(), proxied.GetAge()); - Assert.AreEqual(0, nop.Count, "Whoops, appear to be advising when not under One's cflow."); + // not advised, not under One... + Assert.AreEqual(target.GetAge(), proxied.GetAge()); + Assert.AreEqual(0, nop.Count, "Whoops, appear to be advising when not under One's cflow."); - // will be advised... - One one = new One(); - Assert.AreEqual(27, one.GetAge(proxied)); - Assert.AreEqual(1, nop.Count, "Not advising when under One's cflow (must be)."); + // will be advised... + One one = new One(); + Assert.AreEqual(27, one.GetAge(proxied)); + Assert.AreEqual(1, nop.Count, "Not advising when under One's cflow (must be)."); - // won't be advised... - Assert.AreEqual(target.GetAge(), new One().NoMatch(proxied)); - Assert.AreEqual(1, nop.Count, "Whoops, appear to be advising when under One's cflow scope, BUT NOT under a target method's cflow scope."); - Assert.AreEqual(3, cflow.EvaluationCount, "Pointcut not invoked the correct number of times."); - } + // won't be advised... + Assert.AreEqual(target.GetAge(), new One().NoMatch(proxied)); + Assert.AreEqual(1, nop.Count, "Whoops, appear to be advising when under One's cflow scope, BUT NOT under a target method's cflow scope."); + Assert.AreEqual(3, cflow.EvaluationCount, "Pointcut not invoked the correct number of times."); + } - private sealed class One - { - // attribute is required so that the delegated call is NOT jitted away... - [MethodImpl(MethodImplOptions.NoInlining)] - public int GetAge(IPerson proxied) - { - return proxied.GetAge(); - } + private sealed class One + { + // attribute is required so that the delegated call is NOT jitted away... + [MethodImpl(MethodImplOptions.NoInlining)] + public int GetAge(IPerson proxied) + { + return proxied.GetAge(); + } - public int NoMatch(IPerson proxied) - { - return proxied.GetAge(); - } + public int NoMatch(IPerson proxied) + { + return proxied.GetAge(); + } - // similarly, attribute is required so that the delegated call is NOT jitted away... - [MethodImpl(MethodImplOptions.NoInlining)] - public void Set(IPerson proxied) - { - proxied.SetAge(5); - } - } + // similarly, attribute is required so that the delegated call is NOT jitted away... + [MethodImpl(MethodImplOptions.NoInlining)] + public void Set(IPerson proxied) + { + proxied.SetAge(5); + } + } - /// - /// Check that we can use a cflow pointcut only in conjunction with - /// a static pointcut: e.g. all setter methods that are invoked under - /// a particular class. - /// - /// - /// This greatly reduces the number of calls to the cflow pointcut, - /// meaning that it's not so prohibitively expensive. - /// - [Test] - [Category("Integration")] - public void SelectiveApplication() - { - SerializablePerson target = new SerializablePerson(); - target.SetAge(27); - NopInterceptor nop = new NopInterceptor(); - ControlFlowPointcut cflow = new ControlFlowPointcut(typeof (One)); - IPointcut settersUnderOne = Pointcuts.Intersection(SetterPointcut.Instance, cflow); - ProxyFactory pf = new ProxyFactory(target); - IPerson proxied = (IPerson) pf.GetProxy(); - pf.AddAdvisor(new DefaultPointcutAdvisor(settersUnderOne, nop)); + /// + /// Check that we can use a cflow pointcut only in conjunction with + /// a static pointcut: e.g. all setter methods that are invoked under + /// a particular class. + /// + /// + /// This greatly reduces the number of calls to the cflow pointcut, + /// meaning that it's not so prohibitively expensive. + /// + [Test] + [Category("Integration")] + public void SelectiveApplication() + { + SerializablePerson target = new SerializablePerson(); + target.SetAge(27); + NopInterceptor nop = new NopInterceptor(); + ControlFlowPointcut cflow = new ControlFlowPointcut(typeof(One)); + IPointcut settersUnderOne = Pointcuts.Intersection(SetterPointcut.Instance, cflow); + ProxyFactory pf = new ProxyFactory(target); + IPerson proxied = (IPerson) pf.GetProxy(); + pf.AddAdvisor(new DefaultPointcutAdvisor(settersUnderOne, nop)); - // Not advised, not under One - target.SetAge(16); - Assert.AreEqual(0, nop.Count); + // Not advised, not under One + target.SetAge(16); + Assert.AreEqual(0, nop.Count); - // Not advised; under One but not a setter - Assert.AreEqual(16, new One().GetAge(proxied)); - Assert.AreEqual(0, nop.Count); + // Not advised; under One but not a setter + Assert.AreEqual(16, new One().GetAge(proxied)); + Assert.AreEqual(0, nop.Count); - // Won't be advised - new One().Set(proxied); - Assert.AreEqual(1, nop.Count); + // Won't be advised + new One().Set(proxied); + Assert.AreEqual(1, nop.Count); - // We saved most evaluations - Assert.AreEqual(1, cflow.EvaluationCount); - } + // We saved most evaluations + Assert.AreEqual(1, cflow.EvaluationCount); + } - [Test] - public void EvaluationCountIncrementedEvenIfPointcutDoesNotMatch() - { - ControlFlowPointcut cut = new ControlFlowPointcut(typeof(One)); - cut.Matches(null, null, null); // args are ingored in this impl... - Assert.AreEqual(1, cut.EvaluationCount); - cut.Matches(null, null, null); // args are ingored in this impl... - Assert.AreEqual(2, cut.EvaluationCount); - } + [Test] + public void EvaluationCountIncrementedEvenIfPointcutDoesNotMatch() + { + ControlFlowPointcut cut = new ControlFlowPointcut(typeof(One)); + cut.Matches(null, null, null); // args are ingored in this impl... + Assert.AreEqual(1, cut.EvaluationCount); + cut.Matches(null, null, null); // args are ingored in this impl... + Assert.AreEqual(2, cut.EvaluationCount); + } - [Test] - public void EvaluationCountIncrementedOnEveryMatch() - { - Type oneType = typeof(One); - ControlFlowPointcut cut = new ControlFlowPointcut(oneType); - MethodInfo method = oneType.GetMethod("GetAge"); - cut.Matches(method, oneType, null); - Assert.AreEqual(1, cut.EvaluationCount); - cut.Matches(method, oneType, null); - Assert.AreEqual(2, cut.EvaluationCount); - } + [Test] + public void EvaluationCountIncrementedOnEveryMatch() + { + Type oneType = typeof(One); + ControlFlowPointcut cut = new ControlFlowPointcut(oneType); + MethodInfo method = oneType.GetMethod("GetAge"); + cut.Matches(method, oneType, null); + Assert.AreEqual(1, cut.EvaluationCount); + cut.Matches(method, oneType, null); + Assert.AreEqual(2, cut.EvaluationCount); + } - [Test] - public void DefaultClassFilterImplAlwaysMatchesRegardless() - { - Type oneType = typeof(One); - ControlFlowPointcut cut = new ControlFlowPointcut(oneType); - ITypeFilter filter = cut.TypeFilter; - Assert.IsTrue(filter.Matches(oneType), - "Must always match regardless of the supplied argument Type."); - Assert.IsTrue(filter.Matches(GetType()), - "Must always match even if the supplied argument Type is not " + - "a match for the Type supplied in the ctor."); - Assert.IsTrue(filter.Matches(null), // args are ingored in this impl... - "Must always match even if the supplied argument Type is null"); - } + [Test] + public void DefaultClassFilterImplAlwaysMatchesRegardless() + { + Type oneType = typeof(One); + ControlFlowPointcut cut = new ControlFlowPointcut(oneType); + ITypeFilter filter = cut.TypeFilter; + Assert.IsTrue(filter.Matches(oneType), + "Must always match regardless of the supplied argument Type."); + Assert.IsTrue(filter.Matches(GetType()), + "Must always match even if the supplied argument Type is not " + + "a match for the Type supplied in the ctor."); + Assert.IsTrue(filter.Matches(null), // args are ingored in this impl... + "Must always match even if the supplied argument Type is null"); + } - [Test] - public void StaticMethodMatchImplAlwaysMatchesRegardless() - { - Type oneType = typeof(One); - ControlFlowPointcut cut = new ControlFlowPointcut(oneType); - IMethodMatcher filter = cut.MethodMatcher; - MethodInfo method = oneType.GetMethod("GetAge"); - Assert.IsTrue(filter.Matches(method, oneType), - "Must always match regardless of the supplied arguments."); - Assert.IsTrue(filter.Matches(method, GetType()), - "Must always match even if the supplied argument method and Type are not " + - "a match for the name and Type supplied in the ctor."); - Assert.IsTrue(filter.Matches(null, null), // args are ingored in this impl... - "Must always match even if the supplied arguments are null"); - } + [Test] + public void StaticMethodMatchImplAlwaysMatchesRegardless() + { + Type oneType = typeof(One); + ControlFlowPointcut cut = new ControlFlowPointcut(oneType); + IMethodMatcher filter = cut.MethodMatcher; + MethodInfo method = oneType.GetMethod("GetAge"); + Assert.IsTrue(filter.Matches(method, oneType), + "Must always match regardless of the supplied arguments."); + Assert.IsTrue(filter.Matches(method, GetType()), + "Must always match even if the supplied argument method and Type are not " + + "a match for the name and Type supplied in the ctor."); + Assert.IsTrue(filter.Matches(null, null), // args are ingored in this impl... + "Must always match even if the supplied arguments are null"); + } - [Test] - public void DynamicMethodMatchWithJustTypeSpecifiedInCtor() - { - ControlFlowPointcut cut = new ControlFlowPointcut(GetType()); - IMethodMatcher filter = cut.MethodMatcher; - Assert.IsTrue(filter.Matches(null, null, null), // args are ingored in this impl... - "Must match - under cflow of Type specified in ctor"); - } + [Test] + public void DynamicMethodMatchWithJustTypeSpecifiedInCtor() + { + ControlFlowPointcut cut = new ControlFlowPointcut(GetType()); + IMethodMatcher filter = cut.MethodMatcher; + Assert.IsTrue(filter.Matches(null, null, null), // args are ingored in this impl... + "Must match - under cflow of Type specified in ctor"); + } - [Test] - public void DynamicMethodMatchWithTypeAndMethodNameSpecifiedInCtor() - { - ControlFlowPointcut cut = new ControlFlowPointcut( - GetType(), "DynamicMethodMatchWithTypeAndMethodNameSpecifiedInCtor"); - IMethodMatcher filter = cut.MethodMatcher; - Assert.IsTrue(filter.Matches(null, null, null), // args are ingored in this impl... - "Must match - under cflow of Type specified in ctor"); - } + [Test] + public void DynamicMethodMatchWithTypeAndMethodNameSpecifiedInCtor() + { + ControlFlowPointcut cut = new ControlFlowPointcut( + GetType(), "DynamicMethodMatchWithTypeAndMethodNameSpecifiedInCtor"); + IMethodMatcher filter = cut.MethodMatcher; + Assert.IsTrue(filter.Matches(null, null, null), // args are ingored in this impl... + "Must match - under cflow of Type specified in ctor"); + } - [Test] - public void DynamicMethodMatchWithTypeAndMethodNameSpecifiedInCtorNoMatch() - { - ControlFlowPointcut cut = new ControlFlowPointcut(GetType(), "KiloRiley"); - IMethodMatcher filter = cut.MethodMatcher; - Assert.IsFalse(filter.Matches(null, null, null), // args are ingored in this impl... - "Must not match - under cflow of Type specified in ctor, but no match on method name."); - } + [Test] + public void DynamicMethodMatchWithTypeAndMethodNameSpecifiedInCtorNoMatch() + { + ControlFlowPointcut cut = new ControlFlowPointcut(GetType(), "KiloRiley"); + IMethodMatcher filter = cut.MethodMatcher; + Assert.IsFalse(filter.Matches(null, null, null), // args are ingored in this impl... + "Must not match - under cflow of Type specified in ctor, but no match on method name."); + } - #region Helper Classes + #region Helper Classes - /// - /// Pointcut to catch all methods beginning with 'Set'. - /// - private class SetterPointcut : StaticMethodMatcherPointcut - { - public static SetterPointcut Instance = new SetterPointcut(); + /// + /// Pointcut to catch all methods beginning with 'Set'. + /// + private class SetterPointcut : StaticMethodMatcherPointcut + { + public static SetterPointcut Instance = new SetterPointcut(); - public override bool Matches(MethodInfo methodBase, Type targetType) - { - return methodBase.Name.StartsWith("Set"); - } - } + public override bool Matches(MethodInfo methodBase, Type targetType) + { + return methodBase.Name.StartsWith("Set"); + } + } - #endregion - } + #endregion } diff --git a/test/Spring/Spring.Aop.Tests/Aop/Support/DefaultIntroductionAdvisorTests.cs b/test/Spring/Spring.Aop.Tests/Aop/Support/DefaultIntroductionAdvisorTests.cs index 31b0574e..9ea774e2 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Support/DefaultIntroductionAdvisorTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Support/DefaultIntroductionAdvisorTests.cs @@ -21,70 +21,74 @@ using AopAlliance.Aop; using NUnit.Framework; -namespace Spring.Aop.Support +namespace Spring.Aop.Support; + +/// +/// +/// Erich Eichinger +[TestFixture] +public class DefaultIntroductionAdvisorTests { - /// - /// - /// Erich Eichinger - [TestFixture] - public class DefaultIntroductionAdvisorTests + public interface IBaseInterface { - public interface IBaseInterface { } - public interface IDerivedInterface : IBaseInterface { } + } - private class TestIntroductionAdvice : IDerivedInterface, IAdvice + public interface IDerivedInterface : IBaseInterface + { + } + + private class TestIntroductionAdvice : IDerivedInterface, IAdvice + { + private object equalsToObject; + + public void SetEqualsToObject(object other) { - private object equalsToObject; - - public void SetEqualsToObject(object other) - { - equalsToObject = other; - } - - public override bool Equals(object obj) - { - return object.Equals(equalsToObject, obj); - } - - public override int GetHashCode() - { - return base.GetHashCode(); - } + equalsToObject = other; } - [Test] - public void EqualsOnAdviceEqualAndInterfacesEqual() + public override bool Equals(object obj) { - TestIntroductionAdvice to1 = new TestIntroductionAdvice(); - TestIntroductionAdvice to2 = new TestIntroductionAdvice(); - to1.SetEqualsToObject(to2); - to2.SetEqualsToObject(to1); - - DefaultIntroductionAdvisor a1 = new DefaultIntroductionAdvisor(to1); - DefaultIntroductionAdvisor a2 = new DefaultIntroductionAdvisor(to2); - bool result = a1.Equals(a2); - - Assert.IsTrue(result); + return object.Equals(equalsToObject, obj); } - [Test] - public void BailsIfInterfaceTypeIsNotAnInterface() + public override int GetHashCode() { - Assert.Throws(() => new DefaultIntroductionAdvisor(new TestIntroductionAdvice(), GetType()), "Type [Spring.Aop.Support.DefaultIntroductionAdvisorTests] is not an interface; cannot be used in an introduction."); - } - - [Test] - public void IntroductionMustImplementIntroducedInterfaces() - { - DefaultIntroductionAdvisor advisor = new DefaultIntroductionAdvisor(new TestIntroductionAdvice(), typeof(ICloneable)); - Assert.Throws(() => advisor.ValidateInterfaces(), "Introduction [Spring.Aop.Support.DefaultIntroductionAdvisorTests+TestIntroductionAdvice] does not implement interface 'System.ICloneable' specified in introduction advice."); - } - - [Test] - public void BaseInterfacesAreValid() - { - DefaultIntroductionAdvisor advisor = new DefaultIntroductionAdvisor(new TestIntroductionAdvice(), typeof(IBaseInterface)); - advisor.ValidateInterfaces(); + return base.GetHashCode(); } } + + [Test] + public void EqualsOnAdviceEqualAndInterfacesEqual() + { + TestIntroductionAdvice to1 = new TestIntroductionAdvice(); + TestIntroductionAdvice to2 = new TestIntroductionAdvice(); + to1.SetEqualsToObject(to2); + to2.SetEqualsToObject(to1); + + DefaultIntroductionAdvisor a1 = new DefaultIntroductionAdvisor(to1); + DefaultIntroductionAdvisor a2 = new DefaultIntroductionAdvisor(to2); + bool result = a1.Equals(a2); + + Assert.IsTrue(result); + } + + [Test] + public void BailsIfInterfaceTypeIsNotAnInterface() + { + Assert.Throws(() => new DefaultIntroductionAdvisor(new TestIntroductionAdvice(), GetType()), "Type [Spring.Aop.Support.DefaultIntroductionAdvisorTests] is not an interface; cannot be used in an introduction."); + } + + [Test] + public void IntroductionMustImplementIntroducedInterfaces() + { + DefaultIntroductionAdvisor advisor = new DefaultIntroductionAdvisor(new TestIntroductionAdvice(), typeof(ICloneable)); + Assert.Throws(() => advisor.ValidateInterfaces(), "Introduction [Spring.Aop.Support.DefaultIntroductionAdvisorTests+TestIntroductionAdvice] does not implement interface 'System.ICloneable' specified in introduction advice."); + } + + [Test] + public void BaseInterfacesAreValid() + { + DefaultIntroductionAdvisor advisor = new DefaultIntroductionAdvisor(new TestIntroductionAdvice(), typeof(IBaseInterface)); + advisor.ValidateInterfaces(); + } } diff --git a/test/Spring/Spring.Aop.Tests/Aop/Support/DelegatingIntroductionInterceptorTests.cs b/test/Spring/Spring.Aop.Tests/Aop/Support/DelegatingIntroductionInterceptorTests.cs index ef900b8f..a4651342 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Support/DelegatingIntroductionInterceptorTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Support/DelegatingIntroductionInterceptorTests.cs @@ -1,4 +1,5 @@ #region License + /* * Copyright 2002-2010 the original author or authors. * @@ -14,165 +15,164 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + #endregion using NUnit.Framework; using AopAlliance.Aop; - using FakeItEasy; - using Spring.Aop.Framework; using Spring.Objects; -namespace Spring.Aop.Support +namespace Spring.Aop.Support; + +/// +/// Translation of DelegatingIntroductionInterceptor unit tests to Spring.NET. +/// +/// +/// Spring.NET doesn't have a DelegatingIntroductionInterceptor because it handles +/// introductions without using interception. So all the unit tests show how similar +/// things can be done in Spring.NET. +/// +/// Rod Johnson +/// Choy Rim (.NET) +[TestFixture] +public class DelegatingIntroductionInterceptorTests { - /// - /// Translation of DelegatingIntroductionInterceptor unit tests to Spring.NET. - /// - /// - /// Spring.NET doesn't have a DelegatingIntroductionInterceptor because it handles - /// introductions without using interception. So all the unit tests show how similar - /// things can be done in Spring.NET. - /// - /// Rod Johnson - /// Choy Rim (.NET) - [TestFixture] - public class DelegatingIntroductionInterceptorTests - { - private static readonly DateTime EXPECTED_TIMESTAMP = new DateTime(2004,8,1); + private static readonly DateTime EXPECTED_TIMESTAMP = new DateTime(2004, 8, 1); - [Test] - public void testNullTarget() - { - Assert.Throws(() => new DefaultIntroductionAdvisor(null, typeof(ITimeStamped))); - } + [Test] + public void testNullTarget() + { + Assert.Throws(() => new DefaultIntroductionAdvisor(null, typeof(ITimeStamped))); + } - public interface ITimeStampedIntroduction: ITimeStamped, IAdvice - { - } + public interface ITimeStampedIntroduction : ITimeStamped, IAdvice + { + } - [Test] - public void TestIntroductionInterceptorWithDelegation() - { - TestObject raw = new TestObject(); - Assert.IsTrue(! (raw is ITimeStamped)); - ProxyFactory factory = new ProxyFactory(raw); + [Test] + public void TestIntroductionInterceptorWithDelegation() + { + TestObject raw = new TestObject(); + Assert.IsTrue(!(raw is ITimeStamped)); + ProxyFactory factory = new ProxyFactory(raw); - ITimeStampedIntroduction ts = A.Fake(); - A.CallTo(() => ts.TimeStamp).Returns(EXPECTED_TIMESTAMP); + ITimeStampedIntroduction ts = A.Fake(); + A.CallTo(() => ts.TimeStamp).Returns(EXPECTED_TIMESTAMP); - DefaultIntroductionAdvisor advisor = new DefaultIntroductionAdvisor(ts); - factory.AddIntroduction(advisor); + DefaultIntroductionAdvisor advisor = new DefaultIntroductionAdvisor(ts); + factory.AddIntroduction(advisor); - ITimeStamped tsp = (ITimeStamped) factory.GetProxy(); - Assert.IsTrue(tsp.TimeStamp == EXPECTED_TIMESTAMP); - } + ITimeStamped tsp = (ITimeStamped) factory.GetProxy(); + Assert.IsTrue(tsp.TimeStamp == EXPECTED_TIMESTAMP); + } - // we have to mark the ISubTimeStamped interface with the IAdvice marker - // in order to use it as an introduction. - public interface ISubTimeStampedIntroduction: ISubTimeStamped, IAdvice - { - } + // we have to mark the ISubTimeStamped interface with the IAdvice marker + // in order to use it as an introduction. + public interface ISubTimeStampedIntroduction : ISubTimeStamped, IAdvice + { + } - [Test] - public void TestIntroductionInterceptorWithInterfaceHierarchy() - { - TestObject raw = new TestObject(); - Assert.IsTrue(! (raw is ISubTimeStamped)); - ProxyFactory factory = new ProxyFactory(raw); + [Test] + public void TestIntroductionInterceptorWithInterfaceHierarchy() + { + TestObject raw = new TestObject(); + Assert.IsTrue(!(raw is ISubTimeStamped)); + ProxyFactory factory = new ProxyFactory(raw); - ISubTimeStampedIntroduction ts = A.Fake(); - A.CallTo(() => ts.TimeStamp).Returns(EXPECTED_TIMESTAMP); + ISubTimeStampedIntroduction ts = A.Fake(); + A.CallTo(() => ts.TimeStamp).Returns(EXPECTED_TIMESTAMP); - DefaultIntroductionAdvisor advisor = new DefaultIntroductionAdvisor(ts); - // we must add introduction, not an advisor - factory.AddIntroduction(advisor); + DefaultIntroductionAdvisor advisor = new DefaultIntroductionAdvisor(ts); + // we must add introduction, not an advisor + factory.AddIntroduction(advisor); - object proxy = factory.GetProxy(); - ISubTimeStamped tsp = (ISubTimeStamped) proxy; - Assert.IsTrue(tsp.TimeStamp == EXPECTED_TIMESTAMP); - } + object proxy = factory.GetProxy(); + ISubTimeStamped tsp = (ISubTimeStamped) proxy; + Assert.IsTrue(tsp.TimeStamp == EXPECTED_TIMESTAMP); + } - [Test] - public void TestIntroductionInterceptorWithSuperInterface() - { - TestObject raw = new TestObject(); - Assert.IsTrue(! (raw is ITimeStamped)); - ProxyFactory factory = new ProxyFactory(raw); + [Test] + public void TestIntroductionInterceptorWithSuperInterface() + { + TestObject raw = new TestObject(); + Assert.IsTrue(!(raw is ITimeStamped)); + ProxyFactory factory = new ProxyFactory(raw); - ISubTimeStampedIntroduction ts = A.Fake(); - A.CallTo(() => ts.TimeStamp).Returns(EXPECTED_TIMESTAMP); + ISubTimeStampedIntroduction ts = A.Fake(); + A.CallTo(() => ts.TimeStamp).Returns(EXPECTED_TIMESTAMP); - factory.AddIntroduction(0, new DefaultIntroductionAdvisor( - ts, - typeof(ITimeStamped)) - ); + factory.AddIntroduction(0, new DefaultIntroductionAdvisor( + ts, + typeof(ITimeStamped)) + ); - ITimeStamped tsp = (ITimeStamped) factory.GetProxy(); - Assert.IsTrue(!(tsp is ISubTimeStamped)); - Assert.IsTrue(tsp.TimeStamp == EXPECTED_TIMESTAMP); - } + ITimeStamped tsp = (ITimeStamped) factory.GetProxy(); + Assert.IsTrue(!(tsp is ISubTimeStamped)); + Assert.IsTrue(tsp.TimeStamp == EXPECTED_TIMESTAMP); + } - /// - /// test introduction. - /// It must include the IAdvice marker interface to be a - /// valid introduction. - /// - private class Test : ITimeStamped, ITest, IAdvice - { - private DateTime _timestamp; + /// + /// test introduction. + /// It must include the IAdvice marker interface to be a + /// valid introduction. + /// + private class Test : ITimeStamped, ITest, IAdvice + { + private DateTime _timestamp; - public Test(DateTime timestamp) - { - _timestamp = timestamp; - } - public void Foo() - { - } - public DateTime TimeStamp - { - get - { - return _timestamp; - } - } - } + public Test(DateTime timestamp) + { + _timestamp = timestamp; + } - public void TestAutomaticInterfaceRecognitionInDelegate() - { - IIntroductionAdvisor ia = new DefaultIntroductionAdvisor(new Test(EXPECTED_TIMESTAMP)); + public void Foo() + { + } - TestObject target = new TestObject(); - ProxyFactory pf = new ProxyFactory(target); - pf.AddIntroduction(0, ia); + public DateTime TimeStamp + { + get + { + return _timestamp; + } + } + } - ITimeStamped ts = (ITimeStamped) pf.GetProxy(); + public void TestAutomaticInterfaceRecognitionInDelegate() + { + IIntroductionAdvisor ia = new DefaultIntroductionAdvisor(new Test(EXPECTED_TIMESTAMP)); - Assert.IsTrue(ts.TimeStamp == EXPECTED_TIMESTAMP); - ((ITest) ts).Foo(); + TestObject target = new TestObject(); + ProxyFactory pf = new ProxyFactory(target); + pf.AddIntroduction(0, ia); - int age = ((ITestObject) ts).Age; - } + ITimeStamped ts = (ITimeStamped) pf.GetProxy(); - /* - * The rest of the tests in the original tested subclassing the - * DelegatingIntroductionInterceptor. - * - * Since we don't need to subclass anything to make a delegating - * introduction, the rest of the tests are not necessary. - */ + Assert.IsTrue(ts.TimeStamp == EXPECTED_TIMESTAMP); + ((ITest) ts).Foo(); - // must be public to be used for AOP - // AOP creates a new assembly which must have access to the - // interfaces that it intends to expose. - public interface ITest - { - void Foo(); - } + int age = ((ITestObject) ts).Age; + } - public interface ISubTimeStamped : ITimeStamped - { - } + /* + * The rest of the tests in the original tested subclassing the + * DelegatingIntroductionInterceptor. + * + * Since we don't need to subclass anything to make a delegating + * introduction, the rest of the tests are not necessary. + */ - } + // must be public to be used for AOP + // AOP creates a new assembly which must have access to the + // interfaces that it intends to expose. + public interface ITest + { + void Foo(); + } + + public interface ISubTimeStamped : ITimeStamped + { + } } diff --git a/test/Spring/Spring.Aop.Tests/Aop/Support/RegularExpressionMethodPointcutAdvisorTests.cs b/test/Spring/Spring.Aop.Tests/Aop/Support/RegularExpressionMethodPointcutAdvisorTests.cs index 87359549..368e5676 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Support/RegularExpressionMethodPointcutAdvisorTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Support/RegularExpressionMethodPointcutAdvisorTests.cs @@ -1,4 +1,5 @@ #region License + /* * Copyright 2002-2010 the original author or authors. * @@ -14,6 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + #endregion #region Imports @@ -24,114 +26,113 @@ using Spring.Objects; using Spring.Objects.Factory; using Spring.Objects.Factory.Xml; using Spring.Util; - using NUnit.Framework; + #endregion -namespace Spring.Aop.Support +namespace Spring.Aop.Support; + +/// +/// Unit tests for RegularExpressionMethodPointcutAdvisorTests. +/// +/// Rod Johnson +/// Simon White (.NET) +[TestFixture] +public class RegularExpressionMethodPointcutAdvisorTests { - /// - /// Unit tests for RegularExpressionMethodPointcutAdvisorTests. - /// - /// Rod Johnson - /// Simon White (.NET) - [TestFixture] - public class RegularExpressionMethodPointcutAdvisorTests - { - [OneTimeSetUp] - public void FixtureSetUp() - { - SystemUtils.RegisterLoadedAssemblyResolver(); - } + [OneTimeSetUp] + public void FixtureSetUp() + { + SystemUtils.RegisterLoadedAssemblyResolver(); + } - /// - /// Basic use case, a single pattern defined. - /// - [Test] - public void SinglePattern() - { - IObjectFactory iof = new XmlObjectFactory(new ReadOnlyXmlTestResource("RegularExpressionSetterTests.xml", GetType())); - IPerson advised = (IPerson) iof.GetObject("SettersAdvised"); - // Interceptor behind regexp advisor - NopInterceptor nop = (NopInterceptor) iof.GetObject("NopInterceptor"); - Assert.AreEqual(0, nop.Count); + /// + /// Basic use case, a single pattern defined. + /// + [Test] + public void SinglePattern() + { + IObjectFactory iof = new XmlObjectFactory(new ReadOnlyXmlTestResource("RegularExpressionSetterTests.xml", GetType())); + IPerson advised = (IPerson) iof.GetObject("SettersAdvised"); + // Interceptor behind regexp advisor + NopInterceptor nop = (NopInterceptor) iof.GetObject("NopInterceptor"); + Assert.AreEqual(0, nop.Count); - int newAge = 12; - // Not advised - advised.Exceptional(null); - Assert.AreEqual(0, nop.Count); - advised.SetAge(newAge); - Assert.AreEqual(newAge, advised.GetAge()); - // Only setter fired - Assert.AreEqual(1, nop.Count); - } + int newAge = 12; + // Not advised + advised.Exceptional(null); + Assert.AreEqual(0, nop.Count); + advised.SetAge(newAge); + Assert.AreEqual(newAge, advised.GetAge()); + // Only setter fired + Assert.AreEqual(1, nop.Count); + } - /// - /// Multiple patterns defined within a single advisor. - /// - [Test] - public void MultiplePatterns() - { - IObjectFactory iof = new XmlObjectFactory(new ReadOnlyXmlTestResource("RegularExpressionSetterTests.xml", GetType())); - IPerson advised = (IPerson) iof.GetObject("SettersAndReturnsThisAdvised"); + /// + /// Multiple patterns defined within a single advisor. + /// + [Test] + public void MultiplePatterns() + { + IObjectFactory iof = new XmlObjectFactory(new ReadOnlyXmlTestResource("RegularExpressionSetterTests.xml", GetType())); + IPerson advised = (IPerson) iof.GetObject("SettersAndReturnsThisAdvised"); - // Interceptor behind regexp advisor - NopInterceptor nop = (NopInterceptor) iof.GetObject("NopInterceptor"); - Assert.AreEqual(0, nop.Count); + // Interceptor behind regexp advisor + NopInterceptor nop = (NopInterceptor) iof.GetObject("NopInterceptor"); + Assert.AreEqual(0, nop.Count); - int newAge = 12; - // Not advised - advised.Exceptional(null); - Assert.AreEqual(0, nop.Count); + int newAge = 12; + // Not advised + advised.Exceptional(null); + Assert.AreEqual(0, nop.Count); - // This is proxied - advised.ReturnsThis(); - Assert.AreEqual(1, nop.Count); + // This is proxied + advised.ReturnsThis(); + Assert.AreEqual(1, nop.Count); - // Only setter is advised - advised.SetAge(newAge); - Assert.AreEqual(2, nop.Count); + // Only setter is advised + advised.SetAge(newAge); + Assert.AreEqual(2, nop.Count); - Assert.AreEqual(newAge, advised.GetAge()); - Assert.AreEqual(2, nop.Count); - } + Assert.AreEqual(newAge, advised.GetAge()); + Assert.AreEqual(2, nop.Count); + } - [Test] - [Platform("Win")] - public void Serialization() - { - IObjectFactory iof = new XmlObjectFactory(new ReadOnlyXmlTestResource("RegularExpressionSetterTests.xml", GetType())); - IPerson p = (IPerson) iof.GetObject("SerializableSettersAdvised"); - // Interceptor behind regexp advisor - NopInterceptor nop = (NopInterceptor) iof.GetObject("NopInterceptor"); - Assert.AreEqual(0, nop.Count); + [Test] + [Platform("Win")] + public void Serialization() + { + IObjectFactory iof = new XmlObjectFactory(new ReadOnlyXmlTestResource("RegularExpressionSetterTests.xml", GetType())); + IPerson p = (IPerson) iof.GetObject("SerializableSettersAdvised"); + // Interceptor behind regexp advisor + NopInterceptor nop = (NopInterceptor) iof.GetObject("NopInterceptor"); + Assert.AreEqual(0, nop.Count); - int newAge = 12; - // Not advised - Assert.AreEqual(0, p.GetAge()); - Assert.AreEqual(0, nop.Count); + int newAge = 12; + // Not advised + Assert.AreEqual(0, p.GetAge()); + Assert.AreEqual(0, nop.Count); - // This is proxied - p.SetAge(newAge); - Assert.AreEqual(1, nop.Count); - p.SetAge(newAge); - Assert.AreEqual(newAge, p.GetAge()); - // Only setter fired - Assert.AreEqual(2, nop.Count); + // This is proxied + p.SetAge(newAge); + Assert.AreEqual(1, nop.Count); + p.SetAge(newAge); + Assert.AreEqual(newAge, p.GetAge()); + // Only setter fired + Assert.AreEqual(2, nop.Count); - // Serialize and continue... + // Serialize and continue... #if !NETCOREAPP // deep chains for Type serialization problems, not worth the effort at the moment - p = (IPerson) SerializationTestUtils.SerializeAndDeserialize(p); - Assert.AreEqual(newAge, p.GetAge()); + p = (IPerson) SerializationTestUtils.SerializeAndDeserialize(p); + Assert.AreEqual(newAge, p.GetAge()); #endif - // Remembers count, but we need to get a new reference to nop... - nop = (SerializableNopInterceptor) ((IAdvised) p).Advisors[0].Advice; - Assert.AreEqual(2, nop.Count); - Assert.AreEqual("SerializableSettersAdvised", p.GetName()); - p.SetAge(newAge + 1); - Assert.AreEqual(3, nop.Count); - Assert.AreEqual(newAge + 1, p.GetAge()); - } - } + // Remembers count, but we need to get a new reference to nop... + nop = (SerializableNopInterceptor) ((IAdvised) p).Advisors[0].Advice; + Assert.AreEqual(2, nop.Count); + Assert.AreEqual("SerializableSettersAdvised", p.GetName()); + p.SetAge(newAge + 1); + Assert.AreEqual(3, nop.Count); + Assert.AreEqual(newAge + 1, p.GetAge()); + } } diff --git a/test/Spring/Spring.Aop.Tests/Aop/Support/RootTypeFilterTests.cs b/test/Spring/Spring.Aop.Tests/Aop/Support/RootTypeFilterTests.cs index 7dca57e3..4b4686e4 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Support/RootTypeFilterTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Support/RootTypeFilterTests.cs @@ -24,19 +24,18 @@ using NUnit.Framework; #endregion -namespace Spring.Aop.Support +namespace Spring.Aop.Support; + +/// +/// Unit tests for the RootTypeFilter class. +/// +/// Rick Evans +[TestFixture] +public sealed class RootTypeFilterTests { - /// - /// Unit tests for the RootTypeFilter class. - /// - /// Rick Evans - [TestFixture] - public sealed class RootTypeFilterTests + [Test] + public void InstantiationWithNullRootType() { - [Test] - public void InstantiationWithNullRootType() - { - Assert.Throws(() => new RootTypeFilter(null)); - } - } + Assert.Throws(() => new RootTypeFilter(null)); + } } diff --git a/test/Spring/Spring.Aop.Tests/Aop/Support/SdkRegularExpressionMethodPointcutTests.cs b/test/Spring/Spring.Aop.Tests/Aop/Support/SdkRegularExpressionMethodPointcutTests.cs index a0684fbd..758a5a2f 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Support/SdkRegularExpressionMethodPointcutTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Support/SdkRegularExpressionMethodPointcutTests.cs @@ -2,13 +2,13 @@ /* * Copyright 2002-2010 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. @@ -27,109 +27,108 @@ using Spring.Util; #endregion -namespace Spring.Aop.Support +namespace Spring.Aop.Support; + +/// +/// Unit tests for the SdkRegularExpressionMethodPointcut class. +/// +/// Dmitriy Kopylenko +/// Rick Evans (.NET) +[TestFixture] +public sealed class SdkRegularExpressionMethodPointcutTests : AbstractRegularExpressionMethodPointcutTests { - /// - /// Unit tests for the SdkRegularExpressionMethodPointcut class. - /// - /// Dmitriy Kopylenko - /// Rick Evans (.NET) - [TestFixture] - public sealed class SdkRegularExpressionMethodPointcutTests : AbstractRegularExpressionMethodPointcutTests - { - /// - /// The setup logic executed before the execution of this test fixture. - /// - [OneTimeSetUp] - public void FixtureSetUp() - { - // enable (null appender) logging, to ensure that the logging code is exercised - LogManager.LoggerFactory = NullLoggerFactory.Instance; - } + /// + /// The setup logic executed before the execution of this test fixture. + /// + [OneTimeSetUp] + public void FixtureSetUp() + { + // enable (null appender) logging, to ensure that the logging code is exercised + LogManager.LoggerFactory = NullLoggerFactory.Instance; + } - /// - /// Returns the method pointcut implementation to be tested. - /// - /// The implementation. - protected override AbstractRegularExpressionMethodPointcut GetRegexpMethodPointcut() - { - return new SdkRegularExpressionMethodPointcut(); - } + /// + /// Returns the method pointcut implementation to be tested. + /// + /// The implementation. + protected override AbstractRegularExpressionMethodPointcut GetRegexpMethodPointcut() + { + return new SdkRegularExpressionMethodPointcut(); + } - [Test] - public void InstantiationViaSerialization() - { - SdkRegularExpressionMethodPointcut initial = new SdkRegularExpressionMethodPointcut(); - initial.Pattern = "Foo"; - SdkRegularExpressionMethodPointcut pcut = (SdkRegularExpressionMethodPointcut) SerializationTestUtils.SerializeAndDeserialize(initial); - Assert.IsNotNull(pcut, "Deserialized instance must (obviously) not be null."); - Assert.AreEqual(initial.Pattern, pcut.Pattern, "Pattern property not deserialized correctly."); - } + [Test] + public void InstantiationViaSerialization() + { + SdkRegularExpressionMethodPointcut initial = new SdkRegularExpressionMethodPointcut(); + initial.Pattern = "Foo"; + SdkRegularExpressionMethodPointcut pcut = (SdkRegularExpressionMethodPointcut) SerializationTestUtils.SerializeAndDeserialize(initial); + Assert.IsNotNull(pcut, "Deserialized instance must (obviously) not be null."); + Assert.AreEqual(initial.Pattern, pcut.Pattern, "Pattern property not deserialized correctly."); + } - /// - /// This exercises the logger after deserialization. - /// - [Test] - public void TryMatchesAfterSerialization() - { - SdkRegularExpressionMethodPointcut initial = new SdkRegularExpressionMethodPointcut(); - initial.Pattern = "Foo"; - SdkRegularExpressionMethodPointcut pcut = (SdkRegularExpressionMethodPointcut) SerializationTestUtils.SerializeAndDeserialize(initial); - Assert.IsNotNull(pcut, "Deserialized instance must (obviously) not be null."); - Type type = GetType(); - bool isMatch = pcut.Matches(type.GetMethod("ForMatchingPurposesOnly"), type); - Assert.IsFalse(isMatch, "Whoops, should not be matching here at all."); - } + /// + /// This exercises the logger after deserialization. + /// + [Test] + public void TryMatchesAfterSerialization() + { + SdkRegularExpressionMethodPointcut initial = new SdkRegularExpressionMethodPointcut(); + initial.Pattern = "Foo"; + SdkRegularExpressionMethodPointcut pcut = (SdkRegularExpressionMethodPointcut) SerializationTestUtils.SerializeAndDeserialize(initial); + Assert.IsNotNull(pcut, "Deserialized instance must (obviously) not be null."); + Type type = GetType(); + bool isMatch = pcut.Matches(type.GetMethod("ForMatchingPurposesOnly"), type); + Assert.IsFalse(isMatch, "Whoops, should not be matching here at all."); + } - public void ForMatchingPurposesOnly () - { - } - - [Test] - public void MixedPatternsAndDefaultOptions() - { - Type type = GetType(); - SdkRegularExpressionMethodPointcut pcut = new SdkRegularExpressionMethodPointcut(); + public void ForMatchingPurposesOnly() + { + } - pcut.DefaultOptions = RegexOptions.None; - pcut.Patterns = new object[] {"forMatching*", new Regex("xyz*", RegexOptions.Compiled)}; - Assert.IsFalse(pcut.Matches(type.GetMethod("ForMatchingPurposesOnly"), type)); - - pcut.DefaultOptions = RegexOptions.IgnoreCase; - pcut.Patterns = new object[] { "forMatching*", new Regex("xyz*", RegexOptions.Compiled) }; - Assert.IsTrue(pcut.Matches(type.GetMethod("ForMatchingPurposesOnly"), type)); + [Test] + public void MixedPatternsAndDefaultOptions() + { + Type type = GetType(); + SdkRegularExpressionMethodPointcut pcut = new SdkRegularExpressionMethodPointcut(); - pcut.DefaultOptions = RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace; - pcut.Patterns = new object[] { "for matc \nhing*", new Regex("xyz*", RegexOptions.Compiled) }; - Assert.IsTrue(pcut.Matches(type.GetMethod("ForMatchingPurposesOnly"), type)); - } + pcut.DefaultOptions = RegexOptions.None; + pcut.Patterns = new object[] { "forMatching*", new Regex("xyz*", RegexOptions.Compiled) }; + Assert.IsFalse(pcut.Matches(type.GetMethod("ForMatchingPurposesOnly"), type)); - [Test] - public void SetPatternToNull() - { - SdkRegularExpressionMethodPointcut pcut = new SdkRegularExpressionMethodPointcut(); - Assert.Throws(() => pcut.Pattern = null); - } + pcut.DefaultOptions = RegexOptions.IgnoreCase; + pcut.Patterns = new object[] { "forMatching*", new Regex("xyz*", RegexOptions.Compiled) }; + Assert.IsTrue(pcut.Matches(type.GetMethod("ForMatchingPurposesOnly"), type)); - [Test] - public void SetPatternsPluralToNull() - { - SdkRegularExpressionMethodPointcut pcut = new SdkRegularExpressionMethodPointcut(); - Assert.Throws(() => pcut.Patterns = null); - } + pcut.DefaultOptions = RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace; + pcut.Patterns = new object[] { "for matc \nhing*", new Regex("xyz*", RegexOptions.Compiled) }; + Assert.IsTrue(pcut.Matches(type.GetMethod("ForMatchingPurposesOnly"), type)); + } - [Test] - public void SetPatternsPluralToStringArrayWithNullValue() - { - SdkRegularExpressionMethodPointcut pcut = new SdkRegularExpressionMethodPointcut(); - Assert.Throws(() => pcut.Patterns = new string[] { null }); - } + [Test] + public void SetPatternToNull() + { + SdkRegularExpressionMethodPointcut pcut = new SdkRegularExpressionMethodPointcut(); + Assert.Throws(() => pcut.Pattern = null); + } - [Test] - public void InstantiationWithSuppliedPattern() - { - SdkRegularExpressionMethodPointcut pcut = new SdkRegularExpressionMethodPointcut("Foo"); - Assert.AreEqual("Foo", pcut.Pattern, "Pattern supplied via the ctor was not set."); - } - } + [Test] + public void SetPatternsPluralToNull() + { + SdkRegularExpressionMethodPointcut pcut = new SdkRegularExpressionMethodPointcut(); + Assert.Throws(() => pcut.Patterns = null); + } + + [Test] + public void SetPatternsPluralToStringArrayWithNullValue() + { + SdkRegularExpressionMethodPointcut pcut = new SdkRegularExpressionMethodPointcut(); + Assert.Throws(() => pcut.Patterns = new string[] { null }); + } + + [Test] + public void InstantiationWithSuppliedPattern() + { + SdkRegularExpressionMethodPointcut pcut = new SdkRegularExpressionMethodPointcut("Foo"); + Assert.AreEqual("Foo", pcut.Pattern, "Pattern supplied via the ctor was not set."); + } } diff --git a/test/Spring/Spring.Aop.Tests/Aop/Support/TypeFiltersTests.cs b/test/Spring/Spring.Aop.Tests/Aop/Support/TypeFiltersTests.cs index 122a21aa..b0a1f7d7 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Support/TypeFiltersTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Support/TypeFiltersTests.cs @@ -2,13 +2,13 @@ /* * Copyright 2002-2010 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. @@ -25,42 +25,41 @@ using Spring.Objects; #endregion -namespace Spring.Aop.Support +namespace Spring.Aop.Support; + +/// +/// Unit tests for the TypeFilters class. +/// +/// Rod Johnson +/// Choy Rim (.NET) +[TestFixture] +public sealed class TypeFiltersTests { - /// - /// Unit tests for the TypeFilters class. - /// - /// Rod Johnson - /// Choy Rim (.NET) - [TestFixture] - public sealed class TypeFiltersTests - { - private ITypeFilter exceptionFilter = new RootTypeFilter(typeof (Exception)); - private ITypeFilter itoFilter = new RootTypeFilter(typeof (ITestObject)); - private ITypeFilter hasRootCauseFilter = new RootTypeFilter(typeof (StackOverflowException)); + private ITypeFilter exceptionFilter = new RootTypeFilter(typeof(Exception)); + private ITypeFilter itoFilter = new RootTypeFilter(typeof(ITestObject)); + private ITypeFilter hasRootCauseFilter = new RootTypeFilter(typeof(StackOverflowException)); - [Test] - public void Union() - { - Assert.IsTrue(exceptionFilter.Matches(typeof (SystemException))); - Assert.IsFalse(exceptionFilter.Matches(typeof (TestObject))); - Assert.IsFalse(itoFilter.Matches(typeof (Exception))); - Assert.IsTrue(itoFilter.Matches(typeof (TestObject))); - ITypeFilter union = TypeFilters.Union(exceptionFilter, itoFilter); - Assert.IsTrue(union.Matches(typeof (SystemException))); - Assert.IsTrue(union.Matches(typeof (TestObject))); - } + [Test] + public void Union() + { + Assert.IsTrue(exceptionFilter.Matches(typeof(SystemException))); + Assert.IsFalse(exceptionFilter.Matches(typeof(TestObject))); + Assert.IsFalse(itoFilter.Matches(typeof(Exception))); + Assert.IsTrue(itoFilter.Matches(typeof(TestObject))); + ITypeFilter union = TypeFilters.Union(exceptionFilter, itoFilter); + Assert.IsTrue(union.Matches(typeof(SystemException))); + Assert.IsTrue(union.Matches(typeof(TestObject))); + } - [Test] - public void Intersection() - { - Assert.IsTrue(exceptionFilter.Matches(typeof (SystemException))); - Assert.IsTrue(hasRootCauseFilter.Matches(typeof (StackOverflowException))); + [Test] + public void Intersection() + { + Assert.IsTrue(exceptionFilter.Matches(typeof(SystemException))); + Assert.IsTrue(hasRootCauseFilter.Matches(typeof(StackOverflowException))); - ITypeFilter intersection = TypeFilters.Intersection(exceptionFilter, hasRootCauseFilter); - Assert.IsFalse(intersection.Matches(typeof (SystemException))); - Assert.IsFalse(intersection.Matches(typeof (TestObject))); - Assert.IsTrue(intersection.Matches(typeof (StackOverflowException))); - } - } -} + ITypeFilter intersection = TypeFilters.Intersection(exceptionFilter, hasRootCauseFilter); + Assert.IsFalse(intersection.Matches(typeof(SystemException))); + Assert.IsFalse(intersection.Matches(typeof(TestObject))); + Assert.IsTrue(intersection.Matches(typeof(StackOverflowException))); + } +} \ No newline at end of file diff --git a/test/Spring/Spring.Aop.Tests/Aop/Target/EmptyTargetSourceTests.cs b/test/Spring/Spring.Aop.Tests/Aop/Target/EmptyTargetSourceTests.cs index 46240034..355eb27d 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Target/EmptyTargetSourceTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Target/EmptyTargetSourceTests.cs @@ -25,36 +25,35 @@ using Spring.Util; #endregion -namespace Spring.Aop.Target +namespace Spring.Aop.Target; + +/// +/// Unit tests for the EmptyTargetSource class. +/// +/// Rick Evans +[TestFixture] +public sealed class EmptyTargetSourceTests { - /// - /// Unit tests for the EmptyTargetSource class. - /// - /// Rick Evans - [TestFixture] - public sealed class EmptyTargetSourceTests + [Test] + public void Deserialization() { - [Test] - public void Deserialization() - { - ITargetSource deserializedVersion - = (ITargetSource) SerializationTestUtils.SerializeAndDeserialize( - EmptyTargetSource.Empty); - Assert.IsTrue(Object.ReferenceEquals(EmptyTargetSource.Empty, deserializedVersion), - "Singleton instance not being deserialized correctly"); - } + ITargetSource deserializedVersion + = (ITargetSource) SerializationTestUtils.SerializeAndDeserialize( + EmptyTargetSource.Empty); + Assert.IsTrue(Object.ReferenceEquals(EmptyTargetSource.Empty, deserializedVersion), + "Singleton instance not being deserialized correctly"); + } - [Test] - public void IsSerializable() - { - Assert.IsTrue(SerializationTestUtils.IsSerializable(EmptyTargetSource.Empty), - "EmptyTargetSource.Empty must be serializable."); - } + [Test] + public void IsSerializable() + { + Assert.IsTrue(SerializationTestUtils.IsSerializable(EmptyTargetSource.Empty), + "EmptyTargetSource.Empty must be serializable."); + } - [Test] - public void IsStatic() - { - Assert.IsTrue(EmptyTargetSource.Empty.IsStatic, "Must be static."); - } + [Test] + public void IsStatic() + { + Assert.IsTrue(EmptyTargetSource.Empty.IsStatic, "Must be static."); } } diff --git a/test/Spring/Spring.Aop.Tests/Aop/Target/HotSwappableTargetSourceTests.cs b/test/Spring/Spring.Aop.Tests/Aop/Target/HotSwappableTargetSourceTests.cs index 42faca25..b9afb113 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Target/HotSwappableTargetSourceTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Target/HotSwappableTargetSourceTests.cs @@ -26,96 +26,95 @@ using Spring.Objects.Factory.Xml; #endregion -namespace Spring.Aop.Target +namespace Spring.Aop.Target; + +/// +/// Unit tests for the HotSwappableTargetSource class. +/// +/// Rod Johnson +/// Federico Spinazzi (.NET) +[TestFixture] +public sealed class HotSwappableTargetSourceTests { - /// - /// Unit tests for the HotSwappableTargetSource class. - /// - /// Rod Johnson - /// Federico Spinazzi (.NET) - [TestFixture] - public sealed class HotSwappableTargetSourceTests - { - /// Initial count value set in Object factory XML - private const int INITIAL_COUNT = 10; + /// Initial count value set in Object factory XML + private const int INITIAL_COUNT = 10; - private IObjectFactory ObjectFactory; + private IObjectFactory ObjectFactory; - [SetUp] - public void SetUp() - { - this.ObjectFactory = new XmlObjectFactory( - new ReadOnlyXmlTestResource("hotSwapTests.xml", GetType())); - } + [SetUp] + public void SetUp() + { + this.ObjectFactory = new XmlObjectFactory( + new ReadOnlyXmlTestResource("hotSwapTests.xml", GetType())); + } - /// - /// We must simulate container shutdown, which should clear threads. - /// - [TearDown] - public void TearDown() - { - this.ObjectFactory.Dispose(); - } + /// + /// We must simulate container shutdown, which should clear threads. + /// + [TearDown] + public void TearDown() + { + this.ObjectFactory.Dispose(); + } - [Test] - [Category("Integration")] - public void ValidSwaps() - { - ISideEffectObject target1 = (ISideEffectObject) ObjectFactory.GetObject("target1"); - ISideEffectObject target2 = (ISideEffectObject) ObjectFactory.GetObject("target2"); + [Test] + [Category("Integration")] + public void ValidSwaps() + { + ISideEffectObject target1 = (ISideEffectObject) ObjectFactory.GetObject("target1"); + ISideEffectObject target2 = (ISideEffectObject) ObjectFactory.GetObject("target2"); - ISideEffectObject proxied = (ISideEffectObject) ObjectFactory.GetObject("swappable"); - // assertEquals(target1, ((Advised) proxied).getTarget()); - Assert.AreEqual(target1.Count, proxied.Count); - proxied.doWork(); - Assert.AreEqual(INITIAL_COUNT + 1, proxied.Count); + ISideEffectObject proxied = (ISideEffectObject) ObjectFactory.GetObject("swappable"); + // assertEquals(target1, ((Advised) proxied).getTarget()); + Assert.AreEqual(target1.Count, proxied.Count); + proxied.doWork(); + Assert.AreEqual(INITIAL_COUNT + 1, proxied.Count); - HotSwappableTargetSource swapper = (HotSwappableTargetSource) ObjectFactory.GetObject("swapper"); - Object old = swapper.Swap(target2); - Assert.AreEqual(target1, old, "Correct old target was returned"); + HotSwappableTargetSource swapper = (HotSwappableTargetSource) ObjectFactory.GetObject("swapper"); + Object old = swapper.Swap(target2); + Assert.AreEqual(target1, old, "Correct old target was returned"); - // TODO should be able to make this assertion: need to fix target handling - // in AdvisedSupport - //assertEquals(target2, ((Advised) proxied).getTarget()); + // TODO should be able to make this assertion: need to fix target handling + // in AdvisedSupport + //assertEquals(target2, ((Advised) proxied).getTarget()); - Assert.AreEqual(20, proxied.Count); - proxied.doWork(); - Assert.AreEqual(21, target2.Count); + Assert.AreEqual(20, proxied.Count); + proxied.doWork(); + Assert.AreEqual(21, target2.Count); - // Swap it back - swapper.Swap(target1); - Assert.AreEqual(target1.Count, proxied.Count); - } + // Swap it back + swapper.Swap(target1); + Assert.AreEqual(target1.Count, proxied.Count); + } - [Test] - public void RejectsSwapToNull() - { - HotSwappableTargetSource source = new HotSwappableTargetSource(null); - Assert.Throws(() => source.Swap(null)); - } + [Test] + public void RejectsSwapToNull() + { + HotSwappableTargetSource source = new HotSwappableTargetSource(null); + Assert.Throws(() => source.Swap(null)); + } - [Test] - public void SwapDoesIndeedReturnTheOldTarget() - { - HotSwappableTargetSource source = new HotSwappableTargetSource(this); - object foo = source.Swap(new SideEffectObject()); - Assert.IsTrue(object.ReferenceEquals(this, foo), - "Swap() is not returning the old target."); - } + [Test] + public void SwapDoesIndeedReturnTheOldTarget() + { + HotSwappableTargetSource source = new HotSwappableTargetSource(this); + object foo = source.Swap(new SideEffectObject()); + Assert.IsTrue(object.ReferenceEquals(this, foo), + "Swap() is not returning the old target."); + } - [Test] - public void InstantiationWithNullIsOk() - { - new HotSwappableTargetSource(null); - } + [Test] + public void InstantiationWithNullIsOk() + { + new HotSwappableTargetSource(null); + } - [Test] - public void InstantiationWithInitialTarget() - { - HotSwappableTargetSource source = new HotSwappableTargetSource(this); - object foo = source.GetTarget(); - Assert.IsTrue(object.ReferenceEquals(this, foo), - "Ctor is not storing the supplied target."); - } - } + [Test] + public void InstantiationWithInitialTarget() + { + HotSwappableTargetSource source = new HotSwappableTargetSource(this); + object foo = source.GetTarget(); + Assert.IsTrue(object.ReferenceEquals(this, foo), + "Ctor is not storing the supplied target."); + } } diff --git a/test/Spring/Spring.Aop.Tests/Aop/Target/PrototypeTargetSourceTests.cs b/test/Spring/Spring.Aop.Tests/Aop/Target/PrototypeTargetSourceTests.cs index f70d592d..eada6d76 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Target/PrototypeTargetSourceTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Target/PrototypeTargetSourceTests.cs @@ -21,112 +21,110 @@ using FakeItEasy; using Microsoft.Extensions.Logging.Abstractions; using NUnit.Framework; - using Spring.Objects.Factory; using Spring.Objects.Factory.Xml; -namespace Spring.Aop.Target +namespace Spring.Aop.Target; + +/// +/// Unit tests for the PrototypeTargetSource class. +/// +/// Rod Johnson +/// Federico Spinazzi +[TestFixture] +public sealed class PrototypeTargetSourceTests { /// - /// Unit tests for the PrototypeTargetSource class. + /// The setup logic executed before the execution of this test fixture. /// - /// Rod Johnson - /// Federico Spinazzi - [TestFixture] - public sealed class PrototypeTargetSourceTests + [OneTimeSetUp] + public void FixtureSetUp() { - /// - /// The setup logic executed before the execution of this test fixture. - /// - [OneTimeSetUp] - public void FixtureSetUp() - { - // enable (null appender) logging, just to ensure that the logging code is correct - LogManager.LoggerFactory = NullLoggerFactory.Instance; - } - - /// - /// Test that multiple invocations of the prototype object will result - /// in no change to visible state, as a new instance is used. - /// With the singleton, there will be change. - /// - [Test] - public void PrototypeAndSingletonBehaveDifferently() - { - int initialCount = 10; - IObjectFactory of = new XmlObjectFactory(new ReadOnlyXmlTestResource("prototypeTargetSourceTests.xml", GetType())); - ISideEffectObject singleton = (ISideEffectObject)of.GetObject("singleton"); - Assert.AreEqual(initialCount, singleton.Count); - singleton.doWork(); - Assert.AreEqual(initialCount + 1, singleton.Count); - - ISideEffectObject prototype = (ISideEffectObject)of.GetObject("prototype"); - Assert.AreEqual(initialCount, prototype.Count); - singleton.doWork(); - Assert.AreEqual(initialCount, prototype.Count); - - ISideEffectObject prototypeByName = (ISideEffectObject)of.GetObject("prototypeByName"); - Assert.AreEqual(initialCount, prototypeByName.Count); - singleton.doWork(); - Assert.AreEqual(initialCount, prototypeByName.Count); - } - - [Test] - public void TargetType() - { - SideEffectObject target = new SideEffectObject(); - - IObjectFactory factory = A.Fake(); - - A.CallTo(() => factory.IsPrototype(null)).Returns(true); - A.CallTo(() => factory.GetType(null)).Returns(typeof(SideEffectObject)); - - PrototypeTargetSource source = new PrototypeTargetSource(); - source.ObjectFactory = factory; - Assert.AreEqual(target.GetType(), source.TargetType, "Wrong TargetType being returned."); - } - - [Test] - public void IsStatic() - { - PrototypeTargetSource source = new PrototypeTargetSource(); - Assert.IsFalse(source.IsStatic, "Must not be static."); - } - - [Test] - public void WithNonSingletonTargetObject() - { - IObjectFactory factory = A.Fake(); - const string objectName = "Foo"; - - A.CallTo(() => factory.IsPrototype(objectName)).Returns(false); - PrototypeTargetSource source = new PrototypeTargetSource(); - source.TargetObjectName = objectName; - - Assert.Throws(delegate { source.ObjectFactory = factory; }); - } - - [Test] - public void GetTarget() - { - IObjectFactory factory = A.Fake(); - SideEffectObject target = new SideEffectObject(); - A.CallTo(() => factory.IsPrototype("foo")).Returns(true); - A.CallTo(() => factory.GetObject("foo")).Returns(target); - A.CallTo(() => factory.GetType("foo")).Returns(typeof(string)); - - PrototypeTargetSource source = new PrototypeTargetSource(); - source.TargetObjectName = "foo"; - source.ObjectFactory = factory; - Assert.IsTrue(object.ReferenceEquals(source.GetTarget(), target), - "Initial target source reference not being returned by GetTarget()."); - } - - [Test] - public void AfterPropertiesSetWithoutTargetObjectNameBeingSet() - { - PrototypeTargetSource source = new PrototypeTargetSource(); - Assert.Throws(() => source.AfterPropertiesSet()); - } + // enable (null appender) logging, just to ensure that the logging code is correct + LogManager.LoggerFactory = NullLoggerFactory.Instance; } -} + + /// + /// Test that multiple invocations of the prototype object will result + /// in no change to visible state, as a new instance is used. + /// With the singleton, there will be change. + /// + [Test] + public void PrototypeAndSingletonBehaveDifferently() + { + int initialCount = 10; + IObjectFactory of = new XmlObjectFactory(new ReadOnlyXmlTestResource("prototypeTargetSourceTests.xml", GetType())); + ISideEffectObject singleton = (ISideEffectObject) of.GetObject("singleton"); + Assert.AreEqual(initialCount, singleton.Count); + singleton.doWork(); + Assert.AreEqual(initialCount + 1, singleton.Count); + + ISideEffectObject prototype = (ISideEffectObject) of.GetObject("prototype"); + Assert.AreEqual(initialCount, prototype.Count); + singleton.doWork(); + Assert.AreEqual(initialCount, prototype.Count); + + ISideEffectObject prototypeByName = (ISideEffectObject) of.GetObject("prototypeByName"); + Assert.AreEqual(initialCount, prototypeByName.Count); + singleton.doWork(); + Assert.AreEqual(initialCount, prototypeByName.Count); + } + + [Test] + public void TargetType() + { + SideEffectObject target = new SideEffectObject(); + + IObjectFactory factory = A.Fake(); + + A.CallTo(() => factory.IsPrototype(null)).Returns(true); + A.CallTo(() => factory.GetType(null)).Returns(typeof(SideEffectObject)); + + PrototypeTargetSource source = new PrototypeTargetSource(); + source.ObjectFactory = factory; + Assert.AreEqual(target.GetType(), source.TargetType, "Wrong TargetType being returned."); + } + + [Test] + public void IsStatic() + { + PrototypeTargetSource source = new PrototypeTargetSource(); + Assert.IsFalse(source.IsStatic, "Must not be static."); + } + + [Test] + public void WithNonSingletonTargetObject() + { + IObjectFactory factory = A.Fake(); + const string objectName = "Foo"; + + A.CallTo(() => factory.IsPrototype(objectName)).Returns(false); + PrototypeTargetSource source = new PrototypeTargetSource(); + source.TargetObjectName = objectName; + + Assert.Throws(delegate { source.ObjectFactory = factory; }); + } + + [Test] + public void GetTarget() + { + IObjectFactory factory = A.Fake(); + SideEffectObject target = new SideEffectObject(); + A.CallTo(() => factory.IsPrototype("foo")).Returns(true); + A.CallTo(() => factory.GetObject("foo")).Returns(target); + A.CallTo(() => factory.GetType("foo")).Returns(typeof(string)); + + PrototypeTargetSource source = new PrototypeTargetSource(); + source.TargetObjectName = "foo"; + source.ObjectFactory = factory; + Assert.IsTrue(object.ReferenceEquals(source.GetTarget(), target), + "Initial target source reference not being returned by GetTarget()."); + } + + [Test] + public void AfterPropertiesSetWithoutTargetObjectNameBeingSet() + { + PrototypeTargetSource source = new PrototypeTargetSource(); + Assert.Throws(() => source.AfterPropertiesSet()); + } +} \ No newline at end of file diff --git a/test/Spring/Spring.Aop.Tests/Aop/Target/SimplePoolTargetSourceTests.cs b/test/Spring/Spring.Aop.Tests/Aop/Target/SimplePoolTargetSourceTests.cs index c9f703c3..04969656 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Target/SimplePoolTargetSourceTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Target/SimplePoolTargetSourceTests.cs @@ -1,94 +1,91 @@ using NUnit.Framework; - using Spring.Objects.Factory; using Spring.Objects.Factory.Xml; + /* -* Copyright 2002-2010 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. -*/ -namespace Spring.Aop.Target + * Copyright 2002-2010 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. + */ +namespace Spring.Aop.Target; + +/// Tests for pooling invoker interceptor +/// TODO need to make these tests stronger: it's hard to +/// make too many assumptions about a pool +/// +/// Rod Johnson +/// Federico Spinazzi (.Net) +[TestFixture] +public class SimplePoolTargetSourceTests { - - /// Tests for pooling invoker interceptor - /// TODO need to make these tests stronger: it's hard to - /// make too many assumptions about a pool - /// - /// Rod Johnson - /// Federico Spinazzi (.Net) - [TestFixture] - public class SimplePoolTargetSourceTests - { - - /// Initial count value set in Object factory XML - private const int INITIAL_COUNT = 10; - - private XmlObjectFactory objectFactory; - - [SetUp] - public void SetUp() - { - objectFactory = new XmlObjectFactory(new ReadOnlyXmlTestResource("simplePoolTests.xml", GetType())); - } - - /// We must simulate container shutdown, which should clear threads. - [TearDown] - public void TearDown() - { - // Will call pool.close() - this.objectFactory.Dispose(); - } - - private void Functionality(System.String name) - { - ISideEffectObject pooled = (ISideEffectObject) objectFactory.GetObject(name); - Assert.AreEqual(INITIAL_COUNT, pooled.Count); - pooled.doWork(); - Assert.AreEqual(INITIAL_COUNT + 1, pooled.Count); - - pooled = (ISideEffectObject) objectFactory.GetObject(name); - // Just check that it works--we can't make assumptions - // about the count - pooled.doWork(); - //Assert.AreEqual(INITIAL_COUNT + 1, pooled.Count ); - } - - [Test] - public virtual void Functionality() - { - Functionality("pooled"); - } - - [Test] - public virtual void FunctionalityWithNoInterceptors() - { - Functionality("pooledNoInterceptors"); - } - - [Test] - public virtual void ConfigMixin() - { - ISideEffectObject pooled = (ISideEffectObject) objectFactory.GetObject("pooledWithMixin"); - Assert.AreEqual(INITIAL_COUNT, pooled.Count); - PoolingConfig conf = (PoolingConfig) objectFactory.GetObject("pooledWithMixin"); - // TODO one invocation from setup - // assertEquals(1, conf.getInvocations()); - pooled.doWork(); - // assertEquals("No objects active", 0, conf.getActive()); - Assert.AreEqual(25, conf.MaxSize, "Correct target source"); - // assertTrue("Some free", conf.getFree() > 0); - //assertEquals(2, conf.getInvocations()); - Assert.AreEqual(25, conf.MaxSize); - } - } -} \ No newline at end of file + /// Initial count value set in Object factory XML + private const int INITIAL_COUNT = 10; + + private XmlObjectFactory objectFactory; + + [SetUp] + public void SetUp() + { + objectFactory = new XmlObjectFactory(new ReadOnlyXmlTestResource("simplePoolTests.xml", GetType())); + } + + /// We must simulate container shutdown, which should clear threads. + [TearDown] + public void TearDown() + { + // Will call pool.close() + this.objectFactory.Dispose(); + } + + private void Functionality(System.String name) + { + ISideEffectObject pooled = (ISideEffectObject) objectFactory.GetObject(name); + Assert.AreEqual(INITIAL_COUNT, pooled.Count); + pooled.doWork(); + Assert.AreEqual(INITIAL_COUNT + 1, pooled.Count); + + pooled = (ISideEffectObject) objectFactory.GetObject(name); + // Just check that it works--we can't make assumptions + // about the count + pooled.doWork(); + //Assert.AreEqual(INITIAL_COUNT + 1, pooled.Count ); + } + + [Test] + public virtual void Functionality() + { + Functionality("pooled"); + } + + [Test] + public virtual void FunctionalityWithNoInterceptors() + { + Functionality("pooledNoInterceptors"); + } + + [Test] + public virtual void ConfigMixin() + { + ISideEffectObject pooled = (ISideEffectObject) objectFactory.GetObject("pooledWithMixin"); + Assert.AreEqual(INITIAL_COUNT, pooled.Count); + PoolingConfig conf = (PoolingConfig) objectFactory.GetObject("pooledWithMixin"); + // TODO one invocation from setup + // assertEquals(1, conf.getInvocations()); + pooled.doWork(); + // assertEquals("No objects active", 0, conf.getActive()); + Assert.AreEqual(25, conf.MaxSize, "Correct target source"); + // assertTrue("Some free", conf.getFree() > 0); + //assertEquals(2, conf.getInvocations()); + Assert.AreEqual(25, conf.MaxSize); + } +} diff --git a/test/Spring/Spring.Aop.Tests/Aop/Target/SingletonTargetSourceTests.cs b/test/Spring/Spring.Aop.Tests/Aop/Target/SingletonTargetSourceTests.cs index 610cf2e1..418f6501 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Target/SingletonTargetSourceTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Target/SingletonTargetSourceTests.cs @@ -24,56 +24,55 @@ using NUnit.Framework; #endregion -namespace Spring.Aop.Target +namespace Spring.Aop.Target; + +/// +/// Unit tests for the SingletonTargetSource class. +/// +/// Rick Evans +[TestFixture] +public sealed class SingletonTargetSourceTests { - /// - /// Unit tests for the SingletonTargetSource class. - /// - /// Rick Evans - [TestFixture] - public sealed class SingletonTargetSourceTests - { - [Test] - public void InstantiationWithNullTargetSource() - { - Assert.Throws(() => new SingletonTargetSource(null)); - } + [Test] + public void InstantiationWithNullTargetSource() + { + Assert.Throws(() => new SingletonTargetSource(null)); + } - [Test] - public void TargetType() - { - SingletonTargetSource source = new SingletonTargetSource(this); - Assert.AreEqual(GetType(), source.TargetType, "Wrong TargetType being returned."); - } + [Test] + public void TargetType() + { + SingletonTargetSource source = new SingletonTargetSource(this); + Assert.AreEqual(GetType(), source.TargetType, "Wrong TargetType being returned."); + } - [Test] - public void IsStatic() - { - SingletonTargetSource source = new SingletonTargetSource(this); - Assert.IsTrue(source.IsStatic, "Must be static."); - } + [Test] + public void IsStatic() + { + SingletonTargetSource source = new SingletonTargetSource(this); + Assert.IsTrue(source.IsStatic, "Must be static."); + } - [Test] - public void GetTarget() - { - SingletonTargetSource source = new SingletonTargetSource(this); - Assert.IsTrue(object.ReferenceEquals(source.GetTarget(), this), - "Same target source reference not being returned by GetTarget()."); - } + [Test] + public void GetTarget() + { + SingletonTargetSource source = new SingletonTargetSource(this); + Assert.IsTrue(object.ReferenceEquals(source.GetTarget(), this), + "Same target source reference not being returned by GetTarget()."); + } - [Test] - public void EqualsSameInstance() - { - SingletonTargetSource lhs = new SingletonTargetSource(this); - SingletonTargetSource rhs = new SingletonTargetSource(this); - Assert.AreEqual(lhs, rhs, "Equals() not correct for same instance comparison."); - } + [Test] + public void EqualsSameInstance() + { + SingletonTargetSource lhs = new SingletonTargetSource(this); + SingletonTargetSource rhs = new SingletonTargetSource(this); + Assert.AreEqual(lhs, rhs, "Equals() not correct for same instance comparison."); + } - [Test] - public void EqualsNullInstance() - { - SingletonTargetSource lhs = new SingletonTargetSource(this); - Assert.IsFalse(lhs.Equals(null), "Equals() not correct for null instance comparison."); - } - } + [Test] + public void EqualsNullInstance() + { + SingletonTargetSource lhs = new SingletonTargetSource(this); + Assert.IsFalse(lhs.Equals(null), "Equals() not correct for null instance comparison."); + } } diff --git a/test/Spring/Spring.Aop.Tests/Aop/Target/ThreadLocalTargetSourceTests.cs b/test/Spring/Spring.Aop.Tests/Aop/Target/ThreadLocalTargetSourceTests.cs index b0864695..4cee799a 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Target/ThreadLocalTargetSourceTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Target/ThreadLocalTargetSourceTests.cs @@ -1,18 +1,18 @@ /* -* Copyright 2002-2010 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. -*/ + * Copyright 2002-2010 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. + */ using System.Reflection; using System.Collections; @@ -22,207 +22,205 @@ using Spring.Objects; using Spring.Objects.Factory; using Spring.Objects.Factory.Xml; -namespace Spring.Aop.Target +namespace Spring.Aop.Target; + +/// Rod Johnson +/// Federico Spinazzi +[TestFixture] +public class ThreadLocalTargetSourceTests { - /// Rod Johnson - /// Federico Spinazzi - [TestFixture] - public class ThreadLocalTargetSourceTests + /// Initial count value set in Object factory XML + private const int INITIAL_COUNT = 10; + + private XmlObjectFactory ObjectFactory; + + private ILog log; + + [SetUp] + public void SetUp() { - /// Initial count value set in Object factory XML - private const int INITIAL_COUNT = 10; - - private XmlObjectFactory ObjectFactory; - - private ILog log; - - [SetUp] - public void SetUp () - { - this.ObjectFactory = new XmlObjectFactory ( - new ReadOnlyXmlTestResource ("threadLocalTests.xml", GetType ())); - log = LogManager.GetLogger (MethodBase.GetCurrentMethod ().DeclaringType); - } - - /// We must simulate container shutdown, which should clear threads. - [TearDown] - public void TearDown () - { - this.ObjectFactory.Dispose (); - } - - /// Check we can use two different ThreadLocalTargetSources - /// managing objects of different types without them interfering - /// with one another. - /// - [Test] - public virtual void UseDifferentManagedInstancesInSameThread () - { - ISideEffectObject apartment = (ISideEffectObject) ObjectFactory.GetObject ("apartment"); - Assert.AreEqual (INITIAL_COUNT, apartment.Count); - apartment.doWork (); - Assert.AreEqual (INITIAL_COUNT + 1, apartment.Count); - - ITestObject test = (ITestObject) ObjectFactory.GetObject ("threadLocal2"); - Assert.AreEqual ("Rod", test.Name); - Assert.AreEqual ("Kerry", test.Spouse.Name); - } - - [Test] - public virtual void ReuseInSameThread () - { - ISideEffectObject apartment = (ISideEffectObject) ObjectFactory.GetObject ("apartment"); - Assert.AreEqual (INITIAL_COUNT, apartment.Count); - apartment.doWork (); - Assert.AreEqual (INITIAL_COUNT + 1, apartment.Count); - - apartment = (ISideEffectObject) ObjectFactory.GetObject ("apartment"); - Assert.AreEqual (INITIAL_COUNT + 1, apartment.Count); - } - - /// Relies on introduction - /// - /// - [Test] - public virtual void CanGetStatsViaMixinIfThereIsAnInterceptorTakingCareOfThem () - { - IThreadLocalTargetSourceStats stats = (IThreadLocalTargetSourceStats) ObjectFactory.GetObject ("apartment"); - Assert.AreEqual (0, stats.Invocations); - ISideEffectObject apartment = (ISideEffectObject) ObjectFactory.GetObject ("apartment"); - apartment.doWork (); - Assert.AreEqual (1, stats.Invocations); - Assert.AreEqual (0, stats.Hits); - apartment.doWork (); - Assert.AreEqual (2, stats.Invocations); - Assert.AreEqual (1, stats.Hits); - // Only one thread so only one object can have been bound - Assert.AreEqual (1, stats.Objects); - } - - - public class Runner - { - private ILog log = LogManager.GetLogger (MethodBase.GetCurrentMethod ().DeclaringType); - private ThreadLocalTargetSourceTests factory; - public ISideEffectObject mine; - - public Runner (ThreadLocalTargetSourceTests enclosingInstance) - { - this.factory = enclosingInstance; - } - - public virtual void Run () - { - log.LogDebug("getting object"); - this.mine = (ISideEffectObject) factory.ObjectFactory.GetObject ("apartment"); - log.LogDebug(String.Format ("got object; hash code: {0}", this.mine.GetHashCode ())); - Assert.AreEqual (ThreadLocalTargetSourceTests.INITIAL_COUNT, mine.Count); - mine.doWork (); - Assert.AreEqual (ThreadLocalTargetSourceTests.INITIAL_COUNT + 1, mine.Count); - } - } - - [Test] - public virtual void NewThreadHasOwnInstance () - { - ISideEffectObject apartment = (ISideEffectObject) ObjectFactory.GetObject ("apartment"); - log.LogDebug(String.Format ("got object; hash code: {0}", apartment.GetHashCode ())); - Assert.AreEqual (INITIAL_COUNT, apartment.Count); - apartment.doWork (); - apartment.doWork (); - apartment.doWork (); - Assert.AreEqual (INITIAL_COUNT + 3, apartment.Count); - - Runner r = new Runner (this); - Thread t = new Thread (new ThreadStart (r.Run)); - t.Start (); - t.Join (); - - Assert.IsNotNull (r); - - // Check it didn't affect the other thread's copy - Assert.AreEqual (INITIAL_COUNT + 3, apartment.Count); - - // When we use other thread's copy in this thread - // it should behave like ours - Assert.AreEqual (INITIAL_COUNT + 3, r.mine.Count); - - // Bound to two threads - Assert.AreEqual (2, ((IThreadLocalTargetSourceStats) apartment).Objects); - } - - private static bool multiThreadedTestFailed = false; - - [Test] - public virtual void MultiThreadedTest() - { - multiThreadedTestFailed = false; - - this.ObjectFactory = new XmlObjectFactory( - new ReadOnlyXmlTestResource("threadLocalTests.xml", GetType())); - log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - - // Initialize property. - IMultiThreadInterface mtObject = (IMultiThreadInterface)ObjectFactory.GetObject("mtTest"); - - // Start threads. - ArrayList threads = new ArrayList(); - for (int i = 0; i < 100; i++) - { - Thread thread = new Thread(new ParameterizedThreadStart(CheckName)); - threads.Add(thread); - thread.Start(mtObject); - } - - // Wait for threads to end. - foreach (Thread thread in threads) - { - thread.Join(); - } - - Assert.IsFalse(multiThreadedTestFailed); - } - - private void CheckName(object mtObject) - { - string name = ((IMultiThreadInterface)mtObject).GenerateAndSetName(100); - - // Returned name should be equal to property. - if (!name.Equals(((IMultiThreadInterface)mtObject).Name)) - { - multiThreadedTestFailed = true; - } - //Console.WriteLine(String.Format("Expected: {0}; Actual: {1}", - // name, ((IMultiThreadInterface)mtObject).Name)); - } - - #region Helper classes - - public interface IMultiThreadInterface - { - string Name { get; } - string GenerateAndSetName(int sleep); - } - - public class MultiThreadClass : IMultiThreadInterface - { - private string _name; - - public string Name - { - get { return _name; } - } - - public string GenerateAndSetName(int sleep) - { - string generated = "Thread_" + Thread.CurrentThread.ManagedThreadId; - _name = generated; - - Thread.Sleep(sleep); - return generated; - } - } - - #endregion + this.ObjectFactory = new XmlObjectFactory( + new ReadOnlyXmlTestResource("threadLocalTests.xml", GetType())); + log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); } + + /// We must simulate container shutdown, which should clear threads. + [TearDown] + public void TearDown() + { + this.ObjectFactory.Dispose(); + } + + /// Check we can use two different ThreadLocalTargetSources + /// managing objects of different types without them interfering + /// with one another. + /// + [Test] + public virtual void UseDifferentManagedInstancesInSameThread() + { + ISideEffectObject apartment = (ISideEffectObject) ObjectFactory.GetObject("apartment"); + Assert.AreEqual(INITIAL_COUNT, apartment.Count); + apartment.doWork(); + Assert.AreEqual(INITIAL_COUNT + 1, apartment.Count); + + ITestObject test = (ITestObject) ObjectFactory.GetObject("threadLocal2"); + Assert.AreEqual("Rod", test.Name); + Assert.AreEqual("Kerry", test.Spouse.Name); + } + + [Test] + public virtual void ReuseInSameThread() + { + ISideEffectObject apartment = (ISideEffectObject) ObjectFactory.GetObject("apartment"); + Assert.AreEqual(INITIAL_COUNT, apartment.Count); + apartment.doWork(); + Assert.AreEqual(INITIAL_COUNT + 1, apartment.Count); + + apartment = (ISideEffectObject) ObjectFactory.GetObject("apartment"); + Assert.AreEqual(INITIAL_COUNT + 1, apartment.Count); + } + + /// Relies on introduction + /// + /// + [Test] + public virtual void CanGetStatsViaMixinIfThereIsAnInterceptorTakingCareOfThem() + { + IThreadLocalTargetSourceStats stats = (IThreadLocalTargetSourceStats) ObjectFactory.GetObject("apartment"); + Assert.AreEqual(0, stats.Invocations); + ISideEffectObject apartment = (ISideEffectObject) ObjectFactory.GetObject("apartment"); + apartment.doWork(); + Assert.AreEqual(1, stats.Invocations); + Assert.AreEqual(0, stats.Hits); + apartment.doWork(); + Assert.AreEqual(2, stats.Invocations); + Assert.AreEqual(1, stats.Hits); + // Only one thread so only one object can have been bound + Assert.AreEqual(1, stats.Objects); + } + + public class Runner + { + private ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private ThreadLocalTargetSourceTests factory; + public ISideEffectObject mine; + + public Runner(ThreadLocalTargetSourceTests enclosingInstance) + { + this.factory = enclosingInstance; + } + + public virtual void Run() + { + log.LogDebug("getting object"); + this.mine = (ISideEffectObject) factory.ObjectFactory.GetObject("apartment"); + log.LogDebug(String.Format("got object; hash code: {0}", this.mine.GetHashCode())); + Assert.AreEqual(ThreadLocalTargetSourceTests.INITIAL_COUNT, mine.Count); + mine.doWork(); + Assert.AreEqual(ThreadLocalTargetSourceTests.INITIAL_COUNT + 1, mine.Count); + } + } + + [Test] + public virtual void NewThreadHasOwnInstance() + { + ISideEffectObject apartment = (ISideEffectObject) ObjectFactory.GetObject("apartment"); + log.LogDebug(String.Format("got object; hash code: {0}", apartment.GetHashCode())); + Assert.AreEqual(INITIAL_COUNT, apartment.Count); + apartment.doWork(); + apartment.doWork(); + apartment.doWork(); + Assert.AreEqual(INITIAL_COUNT + 3, apartment.Count); + + Runner r = new Runner(this); + Thread t = new Thread(new ThreadStart(r.Run)); + t.Start(); + t.Join(); + + Assert.IsNotNull(r); + + // Check it didn't affect the other thread's copy + Assert.AreEqual(INITIAL_COUNT + 3, apartment.Count); + + // When we use other thread's copy in this thread + // it should behave like ours + Assert.AreEqual(INITIAL_COUNT + 3, r.mine.Count); + + // Bound to two threads + Assert.AreEqual(2, ((IThreadLocalTargetSourceStats) apartment).Objects); + } + + private static bool multiThreadedTestFailed = false; + + [Test] + public virtual void MultiThreadedTest() + { + multiThreadedTestFailed = false; + + this.ObjectFactory = new XmlObjectFactory( + new ReadOnlyXmlTestResource("threadLocalTests.xml", GetType())); + log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + // Initialize property. + IMultiThreadInterface mtObject = (IMultiThreadInterface) ObjectFactory.GetObject("mtTest"); + + // Start threads. + ArrayList threads = new ArrayList(); + for (int i = 0; i < 100; i++) + { + Thread thread = new Thread(new ParameterizedThreadStart(CheckName)); + threads.Add(thread); + thread.Start(mtObject); + } + + // Wait for threads to end. + foreach (Thread thread in threads) + { + thread.Join(); + } + + Assert.IsFalse(multiThreadedTestFailed); + } + + private void CheckName(object mtObject) + { + string name = ((IMultiThreadInterface) mtObject).GenerateAndSetName(100); + + // Returned name should be equal to property. + if (!name.Equals(((IMultiThreadInterface) mtObject).Name)) + { + multiThreadedTestFailed = true; + } + //Console.WriteLine(String.Format("Expected: {0}; Actual: {1}", + // name, ((IMultiThreadInterface)mtObject).Name)); + } + + #region Helper classes + + public interface IMultiThreadInterface + { + string Name { get; } + string GenerateAndSetName(int sleep); + } + + public class MultiThreadClass : IMultiThreadInterface + { + private string _name; + + public string Name + { + get { return _name; } + } + + public string GenerateAndSetName(int sleep) + { + string generated = "Thread_" + Thread.CurrentThread.ManagedThreadId; + _name = generated; + + Thread.Sleep(sleep); + return generated; + } + } + + #endregion } diff --git a/test/Spring/Spring.Aop.Tests/Aop/TrueMethodMatcherTests.cs b/test/Spring/Spring.Aop.Tests/Aop/TrueMethodMatcherTests.cs index d5f9fe38..6f3d6463 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/TrueMethodMatcherTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/TrueMethodMatcherTests.cs @@ -26,51 +26,50 @@ using Spring.Util; #endregion -namespace Spring.Aop +namespace Spring.Aop; + +/// +/// Unit tests for the TrueMethodMatcher class. +/// +/// Rick Evans +[TestFixture] +public sealed class TrueMethodMatcherTests { - /// - /// Unit tests for the TrueMethodMatcher class. - /// - /// Rick Evans - [TestFixture] - public sealed class TrueMethodMatcherTests + [Test] + public void Deserialization() { - [Test] - public void Deserialization() - { - IMethodMatcher deserializedVersion - = (IMethodMatcher) SerializationTestUtils.SerializeAndDeserialize( - TrueMethodMatcher.True); - Assert.IsTrue(Object.ReferenceEquals(TrueMethodMatcher.True, deserializedVersion), - "Singleton instance not being deserialized correctly"); - } + IMethodMatcher deserializedVersion + = (IMethodMatcher) SerializationTestUtils.SerializeAndDeserialize( + TrueMethodMatcher.True); + Assert.IsTrue(Object.ReferenceEquals(TrueMethodMatcher.True, deserializedVersion), + "Singleton instance not being deserialized correctly"); + } - [Test] - public void IsSerializable() - { - Assert.IsTrue(SerializationTestUtils.IsSerializable(TrueMethodMatcher.True), - "TrueMethodMatcher must be serializable."); - } + [Test] + public void IsSerializable() + { + Assert.IsTrue(SerializationTestUtils.IsSerializable(TrueMethodMatcher.True), + "TrueMethodMatcher must be serializable."); + } - [Test] - public void AlwaysMatchesEvenOnNullArguments() - { - Assert.IsTrue(TrueMethodMatcher.True.Matches(null, null), - "Must always match (return true)."); - } + [Test] + public void AlwaysMatchesEvenOnNullArguments() + { + Assert.IsTrue(TrueMethodMatcher.True.Matches(null, null), + "Must always match (return true)."); + } - [Test] - public void AlwaysMatches() - { - Assert.IsTrue(TrueMethodMatcher.True.Matches( - (MethodInfo) MethodBase.GetCurrentMethod(), GetType()), - "Must always match (return true)."); - } + [Test] + public void AlwaysMatches() + { + Assert.IsTrue(TrueMethodMatcher.True.Matches( + (MethodInfo) MethodBase.GetCurrentMethod(), GetType()), + "Must always match (return true)."); + } - [Test] - public void IsRuntime() - { - Assert.IsFalse(TrueMethodMatcher.True.IsRuntime, "Must NOT be runtime."); - } + [Test] + public void IsRuntime() + { + Assert.IsFalse(TrueMethodMatcher.True.IsRuntime, "Must NOT be runtime."); } } diff --git a/test/Spring/Spring.Aop.Tests/Aop/TruePointcutTests.cs b/test/Spring/Spring.Aop.Tests/Aop/TruePointcutTests.cs index 38502ec8..cbb15cde 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/TruePointcutTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/TruePointcutTests.cs @@ -25,30 +25,29 @@ using Spring.Util; #endregion -namespace Spring.Aop -{ - /// - /// Unit tests for the TruePointcut class. - /// - /// Rick Evans - [TestFixture] - public sealed class TruePointcutTests - { - [Test] - public void Deserialization() - { - IPointcut deserializedVersion - = (IPointcut) SerializationTestUtils.SerializeAndDeserialize( - TruePointcut.True); - Assert.IsTrue(Object.ReferenceEquals(TruePointcut.True, deserializedVersion), - "Singleton instance not being deserialized correctly"); - } +namespace Spring.Aop; - [Test] - public void IsSerializable() - { - Assert.IsTrue(SerializationTestUtils.IsSerializable(TruePointcut.True), - "TruePointcut must be serializable."); - } - } +/// +/// Unit tests for the TruePointcut class. +/// +/// Rick Evans +[TestFixture] +public sealed class TruePointcutTests +{ + [Test] + public void Deserialization() + { + IPointcut deserializedVersion + = (IPointcut) SerializationTestUtils.SerializeAndDeserialize( + TruePointcut.True); + Assert.IsTrue(Object.ReferenceEquals(TruePointcut.True, deserializedVersion), + "Singleton instance not being deserialized correctly"); + } + + [Test] + public void IsSerializable() + { + Assert.IsTrue(SerializationTestUtils.IsSerializable(TruePointcut.True), + "TruePointcut must be serializable."); + } } diff --git a/test/Spring/Spring.Aop.Tests/Aop/TrueTypeFilterTests.cs b/test/Spring/Spring.Aop.Tests/Aop/TrueTypeFilterTests.cs index 834820fe..fc2f95ef 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/TrueTypeFilterTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/TrueTypeFilterTests.cs @@ -25,49 +25,49 @@ using Spring.Util; #endregion -namespace Spring.Aop +namespace Spring.Aop; + +/// +/// Unit tests for the TrueTypeFilter class. +/// +/// Rick Evans +[TestFixture] +public sealed class TrueTypeFilterTests { - /// - /// Unit tests for the TrueTypeFilter class. - /// - /// Rick Evans - [TestFixture] - public sealed class TrueTypeFilterTests - { - [Test] - public void Deserialization() - { - ITypeFilter deserializedVersion - = (ITypeFilter) SerializationTestUtils.SerializeAndDeserialize( - TrueTypeFilter.True); - Assert.IsTrue(Object.ReferenceEquals(TrueTypeFilter.True, deserializedVersion), - "Singleton instance not being deserialized correctly"); - } + [Test] + public void Deserialization() + { + ITypeFilter deserializedVersion + = (ITypeFilter) SerializationTestUtils.SerializeAndDeserialize( + TrueTypeFilter.True); + Assert.IsTrue(Object.ReferenceEquals(TrueTypeFilter.True, deserializedVersion), + "Singleton instance not being deserialized correctly"); + } - [Test] - public void IsSerializable() - { - Assert.IsTrue(SerializationTestUtils.IsSerializable(TrueTypeFilter.True), - "TrueClassFilter must be serializable."); - } + [Test] + public void IsSerializable() + { + Assert.IsTrue(SerializationTestUtils.IsSerializable(TrueTypeFilter.True), + "TrueClassFilter must be serializable."); + } - [Test] - public void AlwaysMatchesEvenOnNullArgument() - { - Assert.IsTrue(TrueTypeFilter.True.Matches(null), - "Must always match (return true)."); - } + [Test] + public void AlwaysMatchesEvenOnNullArgument() + { + Assert.IsTrue(TrueTypeFilter.True.Matches(null), + "Must always match (return true)."); + } - [Test] - public void AlwaysMatches() - { - Assert.IsTrue(TrueTypeFilter.True.Matches(GetType()), - "Must always match (return true)."); - } - [Test] - public void ToStringAlwaysTrue() - { - Assert.AreEqual("TrueTypeFilter.True", TrueTypeFilter.True.ToString() ); - } - } + [Test] + public void AlwaysMatches() + { + Assert.IsTrue(TrueTypeFilter.True.Matches(GetType()), + "Must always match (return true)."); + } + + [Test] + public void ToStringAlwaysTrue() + { + Assert.AreEqual("TrueTypeFilter.True", TrueTypeFilter.True.ToString()); + } } diff --git a/test/Spring/Spring.Aop.Tests/AopCompilerOptionsTests.cs b/test/Spring/Spring.Aop.Tests/AopCompilerOptionsTests.cs index f2c47029..f03904c1 100644 --- a/test/Spring/Spring.Aop.Tests/AopCompilerOptionsTests.cs +++ b/test/Spring/Spring.Aop.Tests/AopCompilerOptionsTests.cs @@ -26,18 +26,17 @@ using Spring.Aop; #endregion -namespace Spring +namespace Spring; + +/// Test that the AOP assembly is built with the correct DebugAttributes in release and debug builds. +/// +/// Mark Pollack +[TestFixture] +public sealed class AopCompilerOptionsTests : CompilerOptionsTests { - /// Test that the AOP assembly is built with the correct DebugAttributes in release and debug builds. - /// - /// Mark Pollack - [TestFixture] - public sealed class AopCompilerOptionsTests : CompilerOptionsTests + [OneTimeSetUp] + public void FixtureSetUp() { - [OneTimeSetUp] - public void FixtureSetUp() - { - AssemblyToCheck = Assembly.GetAssembly(typeof (TruePointcut)); - } + AssemblyToCheck = Assembly.GetAssembly(typeof(TruePointcut)); } } \ No newline at end of file diff --git a/test/Spring/Spring.Aop.Tests/AopExceptionTests.cs b/test/Spring/Spring.Aop.Tests/AopExceptionTests.cs index 9874b8a1..f2a0b365 100644 --- a/test/Spring/Spring.Aop.Tests/AopExceptionTests.cs +++ b/test/Spring/Spring.Aop.Tests/AopExceptionTests.cs @@ -21,24 +21,22 @@ #region Imports using System.Reflection; - using NUnit.Framework; #endregion -namespace Spring +namespace Spring; + +/// +/// Unit tests for all of the exception classes in the Spring.Aop library... +/// +/// Rick Evans +[TestFixture] +public sealed class AopExceptionTests : ExceptionsTest { - /// - /// Unit tests for all of the exception classes in the Spring.Aop library... - /// - /// Rick Evans - [TestFixture] - public sealed class AopExceptionTests : ExceptionsTest + [OneTimeSetUp] + public void FixtureSetUp() { - [OneTimeSetUp] - public void FixtureSetUp () - { - AssemblyToCheck = Assembly.GetAssembly (typeof (Spring.Aop.TruePointcut)); - } + AssemblyToCheck = Assembly.GetAssembly(typeof(Spring.Aop.TruePointcut)); } -} +} \ No newline at end of file diff --git a/test/Spring/Spring.Aop.Tests/AopSerializationTests.cs b/test/Spring/Spring.Aop.Tests/AopSerializationTests.cs index a2200797..bfb9daa2 100644 --- a/test/Spring/Spring.Aop.Tests/AopSerializationTests.cs +++ b/test/Spring/Spring.Aop.Tests/AopSerializationTests.cs @@ -32,104 +32,104 @@ using Spring.Objects.Factory; #pragma warning disable SYSLIB0050 -namespace Spring +namespace Spring; + +/// +/// Ensure, that all framework implementations of IAdvice and IAdvisor are serializable +/// +/// Erich Eichinger +[TestFixture] +public class AopSerializationTests { - /// - /// Ensure, that all framework implementations of IAdvice and IAdvisor are serializable - /// - /// Erich Eichinger - [TestFixture] - public class AopSerializationTests + [Test] + public void AllAopInfrastructureTypesAreSerializable() { - [Test] - public void AllAopInfrastructureTypesAreSerializable() + ArrayList brokenTypes = new ArrayList(); + + foreach (Type t in GetTypesToTest()) { - ArrayList brokenTypes = new ArrayList(); - - foreach (Type t in GetTypesToTest()) + if (!ExcludeTypeFromTest(t) + && IsAopInfrastructureType(t)) { - if (!ExcludeTypeFromTest(t) - && IsAopInfrastructureType(t)) + if (!CheckIsSerializable(t)) { - if (!CheckIsSerializable(t)) - { - brokenTypes.Add(string.Format("{0} or one of its base classes are not marked as serializable\n", t.FullName)); - continue; - } - if (t.IsAbstract) continue; + brokenTypes.Add(string.Format("{0} or one of its base classes are not marked as serializable\n", t.FullName)); + continue; + } - // perform a fast ser/deser check - try - { - object o = FormatterServices.GetSafeUninitializedObject(t); - o = SerializeAndDeserialize(o); - } - catch (SerializationException sex) - { - brokenTypes.Add(string.Format("{0}: {1}\n", t.FullName, sex.Message)); - } - catch (Exception ex) - { - Console.WriteLine(string.Format("WARN: {0}: {1}\n", t.FullName, ex)); - } + if (t.IsAbstract) continue; + + // perform a fast ser/deser check + try + { + object o = FormatterServices.GetSafeUninitializedObject(t); + o = SerializeAndDeserialize(o); + } + catch (SerializationException sex) + { + brokenTypes.Add(string.Format("{0}: {1}\n", t.FullName, sex.Message)); + } + catch (Exception ex) + { + Console.WriteLine(string.Format("WARN: {0}: {1}\n", t.FullName, ex)); } } - - Assert.IsEmpty(brokenTypes); } - protected bool CheckIsSerializable(Type t) - { - if (t == typeof(object)) return true; + Assert.IsEmpty(brokenTypes); + } - return (t.IsSerializable && CheckIsSerializable(t.BaseType)); - } + protected bool CheckIsSerializable(Type t) + { + if (t == typeof(object)) return true; - protected virtual ICollection GetTypesToTest() - { - return GetAssemblyToTest().GetTypes(); - // return new Type[] { typeof(DynamicMethodMatcherPointcutAdvisor) }; - } + return (t.IsSerializable && CheckIsSerializable(t.BaseType)); + } - protected virtual Assembly GetAssemblyToTest() - { - return typeof(IAdvice).Assembly; - } + protected virtual ICollection GetTypesToTest() + { + return GetAssemblyToTest().GetTypes(); + // return new Type[] { typeof(DynamicMethodMatcherPointcutAdvisor) }; + } - protected virtual bool ExcludeTypeFromTest(Type t) - { - return false //t.IsAbstract - || t.IsInterface - || typeof(IApplicationContextAware).IsAssignableFrom(t) - || typeof(IObjectFactoryAware).IsAssignableFrom(t) + protected virtual Assembly GetAssemblyToTest() + { + return typeof(IAdvice).Assembly; + } + + protected virtual bool ExcludeTypeFromTest(Type t) + { + return false //t.IsAbstract + || t.IsInterface + || typeof(IApplicationContextAware).IsAssignableFrom(t) + || typeof(IObjectFactoryAware).IsAssignableFrom(t) ; - } + } - protected virtual bool IsAopInfrastructureType(Type t) + protected virtual bool IsAopInfrastructureType(Type t) + { + return typeof(IAdvisedSupportListener).IsAssignableFrom(t) + || typeof(ITargetSource).IsAssignableFrom(t) + || typeof(IAdvice).IsAssignableFrom(t) + || typeof(IAdvisor).IsAssignableFrom(t) + || typeof(IMethodMatcher).IsAssignableFrom(t) + || typeof(IPointcut).IsAssignableFrom(t); + } + + private object SerializeAndDeserialize(object s) + { + // Serialize the session + using (Stream stream = new MemoryStream()) { - return typeof(IAdvisedSupportListener).IsAssignableFrom(t) - || typeof(ITargetSource).IsAssignableFrom(t) - || typeof(IAdvice).IsAssignableFrom(t) - || typeof(IAdvisor).IsAssignableFrom(t) - || typeof(IMethodMatcher).IsAssignableFrom(t) - || typeof(IPointcut).IsAssignableFrom(t); - } + BinaryFormatter formatter = new BinaryFormatter(); + formatter.AssemblyFormat = FormatterAssemblyStyle.Full; + formatter.TypeFormat = FormatterTypeStyle.TypesAlways; + formatter.Serialize(stream, s); - private object SerializeAndDeserialize(object s) - { - // Serialize the session - using (Stream stream = new MemoryStream()) - { - BinaryFormatter formatter = new BinaryFormatter(); - formatter.AssemblyFormat = FormatterAssemblyStyle.Full; - formatter.TypeFormat = FormatterTypeStyle.TypesAlways; - formatter.Serialize(stream, s); - - // Deserialize the session - stream.Position = 0; - object res = formatter.Deserialize(stream); - return res; - } + // Deserialize the session + stream.Position = 0; + object res = formatter.Deserialize(stream); + return res; } } } diff --git a/test/Spring/Spring.Aop.Tests/App.config b/test/Spring/Spring.Aop.Tests/App.config index 5821ad64..5f9361b0 100644 --- a/test/Spring/Spring.Aop.Tests/App.config +++ b/test/Spring/Spring.Aop.Tests/App.config @@ -15,24 +15,24 @@ See the License for the specific language governing permissions and limitations under the License. --> - - -
- - + + +
+ + - - - - - - - - - + + --> + + + + + + \ No newline at end of file diff --git a/test/Spring/Spring.Aop.Tests/Aspects/Cache/CacheAspectIntegrationTests.cs b/test/Spring/Spring.Aop.Tests/Aspects/Cache/CacheAspectIntegrationTests.cs index 481fbcf7..921b22f3 100644 --- a/test/Spring/Spring.Aop.Tests/Aspects/Cache/CacheAspectIntegrationTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aspects/Cache/CacheAspectIntegrationTests.cs @@ -30,210 +30,208 @@ using Spring.Objects.Factory; #endregion -namespace Spring.Aspects.Cache +namespace Spring.Aspects.Cache; + +/// +/// Unit tests for the CacheParameterAdvice class. +/// +/// Aleksandar Seovic +[TestFixture] +public sealed class CacheAspectIntegrationTests { + private GenericApplicationContext context; + private CacheAspect cacheAspect; + + [SetUp] + public void SetUp() + { + context = new GenericApplicationContext(); + + cacheAspect = new CacheAspect(); + cacheAspect.ApplicationContext = context; + } + + [Test] + public void TestCaching() + { + ICache cache = new NonExpiringCache(); + context.ObjectFactory.RegisterSingleton("inventors", cache); + + ProxyFactory pf = new ProxyFactory(new InventorStore()); + pf.AddAdvisors(cacheAspect); + + IInventorStore store = (IInventorStore) pf.GetProxy(); + + Assert.AreEqual(0, cache.Count); + + IList inventors = store.GetAll(); + Assert.AreEqual(2, cache.Count); + + store.Delete((Inventor) inventors[0]); + Assert.AreEqual(1, cache.Count); + + Inventor tesla = store.Load("Nikola Tesla"); + Assert.AreEqual(2, cache.Count); + + store.Save(tesla); + Assert.AreEqual(2, cache.Count); + Assert.AreEqual("Serbian", ((Inventor) cache.Get("Nikola Tesla")).Nationality); + + store.DeleteAll(); + Assert.AreEqual(0, cache.Count); + } + + [Test] + public void TestCacheResultDoesNotReturnInvalidType() + { + ICache cache = new NonExpiringCache(); + context.ObjectFactory.RegisterSingleton("inventors", cache); + + ProxyFactory pf = new ProxyFactory(new InventorStore()); + pf.AddAdvisors(cacheAspect); + + IInventorStore store = (IInventorStore) pf.GetProxy(); + + cache.Insert("Nikola Tesla", "WrongTypeForMethodSignature"); + + Inventor value = store.Load("Nikola Tesla"); + + Assert.That(value, Is.AssignableTo(typeof(Inventor)), "CacheAspect returned a cached type that is incompatible with the method signature return type"); + } + /// - /// Unit tests for the CacheParameterAdvice class. + /// http://jira.springframework.org/browse/SPRNET-1226 /// - /// Aleksandar Seovic - [TestFixture] - public sealed class CacheAspectIntegrationTests + [Test] + public void NoCacheKeySpecified() { - private GenericApplicationContext context; - private CacheAspect cacheAspect; + ICache cache = new NonExpiringCache(); + context.ObjectFactory.RegisterSingleton("inventors", cache); - [SetUp] - public void SetUp() - { - context = new GenericApplicationContext(); + ProxyFactory pf = new ProxyFactory(new InventorStore()); + pf.AddAdvisors(cacheAspect); - cacheAspect = new CacheAspect(); - cacheAspect.ApplicationContext = context; - } - - [Test] - public void TestCaching() - { - ICache cache = new NonExpiringCache(); - context.ObjectFactory.RegisterSingleton("inventors", cache); - - ProxyFactory pf = new ProxyFactory(new InventorStore()); - pf.AddAdvisors(cacheAspect); - - IInventorStore store = (IInventorStore)pf.GetProxy(); - - Assert.AreEqual(0, cache.Count); - - IList inventors = store.GetAll(); - Assert.AreEqual(2, cache.Count); - - store.Delete((Inventor)inventors[0]); - Assert.AreEqual(1, cache.Count); - - Inventor tesla = store.Load("Nikola Tesla"); - Assert.AreEqual(2, cache.Count); - - store.Save(tesla); - Assert.AreEqual(2, cache.Count); - Assert.AreEqual("Serbian", ((Inventor)cache.Get("Nikola Tesla")).Nationality); - - store.DeleteAll(); - Assert.AreEqual(0, cache.Count); - } - - [Test] - public void TestCacheResultDoesNotReturnInvalidType() - { - ICache cache = new NonExpiringCache(); - context.ObjectFactory.RegisterSingleton("inventors", cache); - - ProxyFactory pf = new ProxyFactory(new InventorStore()); - pf.AddAdvisors(cacheAspect); - - IInventorStore store = (IInventorStore)pf.GetProxy(); - - cache.Insert("Nikola Tesla", "WrongTypeForMethodSignature"); - - Inventor value = store.Load("Nikola Tesla"); - - Assert.That(value, Is.AssignableTo(typeof(Inventor)), "CacheAspect returned a cached type that is incompatible with the method signature return type"); - } - - /// - /// http://jira.springframework.org/browse/SPRNET-1226 - /// - [Test] - public void NoCacheKeySpecified() - { - ICache cache = new NonExpiringCache(); - context.ObjectFactory.RegisterSingleton("inventors", cache); - - ProxyFactory pf = new ProxyFactory(new InventorStore()); - pf.AddAdvisors(cacheAspect); - - IInventorStore store = (IInventorStore)pf.GetProxy(); - Assert.Throws(() => store.GetAllNoCacheKey()); - } - - [Test] - public void CacheDoesNotExist() - { - //ICache cache = new NonExpiringCache(); - //context.ObjectFactory.RegisterSingleton("losers", cache); - - ProxyFactory pf = new ProxyFactory(new InventorStore()); - pf.AddAdvisors(cacheAspect); - - IInventorStore store = (IInventorStore)pf.GetProxy(); - Assert.Throws(() => store.GetAll()); - } - - [Test] - public void CacheDoesNotImplementICache() - { - context.ObjectFactory.RegisterSingleton("inventors", new Object()); - - ProxyFactory pf = new ProxyFactory(new InventorStore()); - pf.AddAdvisors(cacheAspect); - - IInventorStore store = (IInventorStore)pf.GetProxy(); - Assert.Throws(() => store.GetAll()); - } - - [Test(Description = "http://jira.springframework.org/browse/SPRNET-959")] - public void UseMethodInfoForKeyGeneration() - { - ICache cache = new NonExpiringCache(); - context.ObjectFactory.RegisterSingleton("defaultCache", cache); - - ProxyFactory pf = new ProxyFactory(new GenericDao()); - pf.AddAdvisors(cacheAspect); - - IGenericDao dao = (IGenericDao)pf.GetProxy(); - - Assert.AreEqual(0, cache.Count); - - dao.Load(1); - Assert.AreEqual(1, cache.Count); - - // actually, it should be null, because default(string) = null - // but it returns the NullValue marker created by the CacheResultAttribute - Assert.IsNotNull(cache.Get("String_1")); - } + IInventorStore store = (IInventorStore) pf.GetProxy(); + Assert.Throws(() => store.GetAllNoCacheKey()); } - #region Inner Class : CacheParameterTarget - - public interface IInventorStore + [Test] + public void CacheDoesNotExist() { - IList GetAll(); - IList GetAllNoCacheKey(); - Inventor Load(string name); - void Save(Inventor inventor); - void Delete(Inventor inventor); - void DeleteAll(); + //ICache cache = new NonExpiringCache(); + //context.ObjectFactory.RegisterSingleton("losers", cache); + + ProxyFactory pf = new ProxyFactory(new InventorStore()); + pf.AddAdvisors(cacheAspect); + + IInventorStore store = (IInventorStore) pf.GetProxy(); + Assert.Throws(() => store.GetAll()); } - public sealed class InventorStore : IInventorStore + [Test] + public void CacheDoesNotImplementICache() { - private IDictionary inventors = new ListDictionary(); + context.ObjectFactory.RegisterSingleton("inventors", new Object()); - public InventorStore() - { - Inventor tesla = new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), null); - Inventor pupin = new Inventor("Mihajlo Pupin", new DateTime(1854, 10, 9), null); - inventors.Add("Nikola Tesla", tesla); - inventors.Add("Mihajlo Pupin", pupin); - } + ProxyFactory pf = new ProxyFactory(new InventorStore()); + pf.AddAdvisors(cacheAspect); - [CacheResultItems("inventors", "Name")] - public IList GetAll() - { - return new ArrayList(inventors.Values); - } - - - [CacheResult(CacheName = "inventors")] - public IList GetAllNoCacheKey() - { - return new ArrayList(inventors.Values); - } - - [CacheResult("inventors", "#name")] - public Inventor Load(string name) - { - return (Inventor) inventors[name]; - } - - public void Save([CacheParameter("inventors", "Name")] Inventor inventor) - { - inventor.Nationality = "Serbian"; - } - - [InvalidateCache("inventors", Keys = "#inventor.Name")] - public void Delete(Inventor inventor) - { - } - - [InvalidateCache("inventors")] - public void DeleteAll() - { - } + IInventorStore store = (IInventorStore) pf.GetProxy(); + Assert.Throws(() => store.GetAll()); } - public interface IGenericDao + [Test(Description = "http://jira.springframework.org/browse/SPRNET-959")] + public void UseMethodInfoForKeyGeneration() { - T Load(IdT id); - } + ICache cache = new NonExpiringCache(); + context.ObjectFactory.RegisterSingleton("defaultCache", cache); - public sealed class GenericDao : IGenericDao - { - [CacheResult("defaultCache", "#Load.ReturnType.Name + '_' + #id")] - public T Load(IdT id) - { - return default(T); - } - } + ProxyFactory pf = new ProxyFactory(new GenericDao()); + pf.AddAdvisors(cacheAspect); - #endregion + IGenericDao dao = (IGenericDao) pf.GetProxy(); + + Assert.AreEqual(0, cache.Count); + + dao.Load(1); + Assert.AreEqual(1, cache.Count); + + // actually, it should be null, because default(string) = null + // but it returns the NullValue marker created by the CacheResultAttribute + Assert.IsNotNull(cache.Get("String_1")); + } } + +#region Inner Class : CacheParameterTarget + +public interface IInventorStore +{ + IList GetAll(); + IList GetAllNoCacheKey(); + Inventor Load(string name); + void Save(Inventor inventor); + void Delete(Inventor inventor); + void DeleteAll(); +} + +public sealed class InventorStore : IInventorStore +{ + private IDictionary inventors = new ListDictionary(); + + public InventorStore() + { + Inventor tesla = new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), null); + Inventor pupin = new Inventor("Mihajlo Pupin", new DateTime(1854, 10, 9), null); + inventors.Add("Nikola Tesla", tesla); + inventors.Add("Mihajlo Pupin", pupin); + } + + [CacheResultItems("inventors", "Name")] + public IList GetAll() + { + return new ArrayList(inventors.Values); + } + + [CacheResult(CacheName = "inventors")] + public IList GetAllNoCacheKey() + { + return new ArrayList(inventors.Values); + } + + [CacheResult("inventors", "#name")] + public Inventor Load(string name) + { + return (Inventor) inventors[name]; + } + + public void Save([CacheParameter("inventors", "Name")] Inventor inventor) + { + inventor.Nationality = "Serbian"; + } + + [InvalidateCache("inventors", Keys = "#inventor.Name")] + public void Delete(Inventor inventor) + { + } + + [InvalidateCache("inventors")] + public void DeleteAll() + { + } +} + +public interface IGenericDao +{ + T Load(IdT id); +} + +public sealed class GenericDao : IGenericDao +{ + [CacheResult("defaultCache", "#Load.ReturnType.Name + '_' + #id")] + public T Load(IdT id) + { + return default(T); + } +} + +#endregion diff --git a/test/Spring/Spring.Aop.Tests/Aspects/Cache/CacheParameterAdviceTests.cs b/test/Spring/Spring.Aop.Tests/Aspects/Cache/CacheParameterAdviceTests.cs index cc79e044..11cbd9c7 100644 --- a/test/Spring/Spring.Aop.Tests/Aspects/Cache/CacheParameterAdviceTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aspects/Cache/CacheParameterAdviceTests.cs @@ -19,128 +19,125 @@ #endregion using System.Reflection; - using FakeItEasy; - using NUnit.Framework; using Spring.Caching; using Spring.Context; -namespace Spring.Aspects.Cache +namespace Spring.Aspects.Cache; + +/// +/// Unit tests for the CacheParameterAdvice class. +/// +/// Aleksandar Seovic +[TestFixture] +public sealed class CacheParameterAdviceTests { - /// - /// Unit tests for the CacheParameterAdvice class. - /// - /// Aleksandar Seovic - [TestFixture] - public sealed class CacheParameterAdviceTests + private IApplicationContext mockContext; + private CacheParameterAdvice advice; + private ICache cache; + + [SetUp] + public void SetUp() { - private IApplicationContext mockContext; - private CacheParameterAdvice advice; - private ICache cache; + mockContext = A.Fake(); - [SetUp] - public void SetUp() - { - mockContext = A.Fake(); + advice = new CacheParameterAdvice(); + advice.ApplicationContext = mockContext; - advice = new CacheParameterAdvice(); - advice.ApplicationContext = mockContext; - - cache = new NonExpiringCache(); - } - - [Test] - public void TestSimpleParameterCaching() - { - MethodInfo method = typeof(SimpleCacheParameterTarget).GetMethod("Save"); - object[] args = new object[] {new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian")}; - - ExpectCacheInstanceRetrieval("cache", cache); - - // parameter value should be added to cache - advice.AfterReturning(null, method, args, null); - Assert.AreEqual(1, cache.Count); - Assert.AreEqual(args[0], cache.Get("Nikola Tesla")); - } - - [Test] - public void TestSimpleWithMethodInfoParameterCaching() - { - MethodInfo method = typeof(SimpleWithMethodInfoCacheParameterTarget).GetMethod("Save"); - object[] args = new object[] { new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian") }; - - ExpectCacheInstanceRetrieval("cache", cache); - - // parameter value should be added to cache - advice.AfterReturning(null, method, args, null); - Assert.AreEqual(1, cache.Count); - Assert.AreEqual(args[0], cache.Get("Save-Nikola Tesla")); - } - - [Test] - public void TestMultipleParameterCaching() - { - MethodInfo method = typeof(MultipleCacheParameterTarget).GetMethod("Save"); - object[] args = new object[] { new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian") }; - - ExpectCacheInstanceRetrieval("cache", cache); - ExpectCacheInstanceRetrieval("cache", cache); - - // parameter value should be added to both cache - advice.AfterReturning(null, method, args, null); - Assert.AreEqual(2, cache.Count); - Assert.AreEqual(args[0], cache.Get("Nikola Tesla")); - Assert.AreEqual(args[0], cache.Get("Serbian")); - } - - [Test] - public void TestConditionParameterCaching() - { - MethodInfo method = typeof(ConditionCacheParameterTarget).GetMethod("Save"); - object[] args = new object[] { new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian") }; - - // parameter value should not be added to cache - advice.AfterReturning(null, method, args, null); - Assert.AreEqual(0, cache.Count); - } - - private void ExpectCacheInstanceRetrieval(string cacheName, ICache cacheToReturn) - { - A.CallTo(() => mockContext.GetObject(cacheName)).Returns(cacheToReturn).Once(); - } + cache = new NonExpiringCache(); } - public interface ICacheParameterTarget + [Test] + public void TestSimpleParameterCaching() { - void Save(Inventor inventor); + MethodInfo method = typeof(SimpleCacheParameterTarget).GetMethod("Save"); + object[] args = new object[] { new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian") }; + + ExpectCacheInstanceRetrieval("cache", cache); + + // parameter value should be added to cache + advice.AfterReturning(null, method, args, null); + Assert.AreEqual(1, cache.Count); + Assert.AreEqual(args[0], cache.Get("Nikola Tesla")); } - public sealed class SimpleCacheParameterTarget : ICacheParameterTarget + [Test] + public void TestSimpleWithMethodInfoParameterCaching() { - public void Save([CacheParameter("cache", "Name")] Inventor inventor) - { - } + MethodInfo method = typeof(SimpleWithMethodInfoCacheParameterTarget).GetMethod("Save"); + object[] args = new object[] { new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian") }; + + ExpectCacheInstanceRetrieval("cache", cache); + + // parameter value should be added to cache + advice.AfterReturning(null, method, args, null); + Assert.AreEqual(1, cache.Count); + Assert.AreEqual(args[0], cache.Get("Save-Nikola Tesla")); } - public sealed class SimpleWithMethodInfoCacheParameterTarget : ICacheParameterTarget + [Test] + public void TestMultipleParameterCaching() { - public void Save([CacheParameter("cache", "#Save.Name + '-' + Name")] Inventor inventor) - { - } + MethodInfo method = typeof(MultipleCacheParameterTarget).GetMethod("Save"); + object[] args = new object[] { new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian") }; + + ExpectCacheInstanceRetrieval("cache", cache); + ExpectCacheInstanceRetrieval("cache", cache); + + // parameter value should be added to both cache + advice.AfterReturning(null, method, args, null); + Assert.AreEqual(2, cache.Count); + Assert.AreEqual(args[0], cache.Get("Nikola Tesla")); + Assert.AreEqual(args[0], cache.Get("Serbian")); } - public sealed class MultipleCacheParameterTarget : ICacheParameterTarget + [Test] + public void TestConditionParameterCaching() { - public void Save([CacheParameter("cache", "Name")][CacheParameter("cache", "Nationality")] Inventor inventor) - { - } + MethodInfo method = typeof(ConditionCacheParameterTarget).GetMethod("Save"); + object[] args = new object[] { new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian") }; + + // parameter value should not be added to cache + advice.AfterReturning(null, method, args, null); + Assert.AreEqual(0, cache.Count); } - public sealed class ConditionCacheParameterTarget : ICacheParameterTarget + private void ExpectCacheInstanceRetrieval(string cacheName, ICache cacheToReturn) + { + A.CallTo(() => mockContext.GetObject(cacheName)).Returns(cacheToReturn).Once(); + } +} + +public interface ICacheParameterTarget +{ + void Save(Inventor inventor); +} + +public sealed class SimpleCacheParameterTarget : ICacheParameterTarget +{ + public void Save([CacheParameter("cache", "Name")] Inventor inventor) + { + } +} + +public sealed class SimpleWithMethodInfoCacheParameterTarget : ICacheParameterTarget +{ + public void Save([CacheParameter("cache", "#Save.Name + '-' + Name")] Inventor inventor) + { + } +} + +public sealed class MultipleCacheParameterTarget : ICacheParameterTarget +{ + public void Save([CacheParameter("cache", "Name")] [CacheParameter("cache", "Nationality")] Inventor inventor) + { + } +} + +public sealed class ConditionCacheParameterTarget : ICacheParameterTarget +{ + public void Save([CacheParameter("cache", "Name", Condition = "Nationality == 'French'")] Inventor inventor) { - public void Save([CacheParameter("cache", "Name", Condition = "Nationality == 'French'")] Inventor inventor) - { - } } } diff --git a/test/Spring/Spring.Aop.Tests/Aspects/Cache/CacheResultAdviceTests.cs b/test/Spring/Spring.Aop.Tests/Aspects/Cache/CacheResultAdviceTests.cs index 30ec8836..e0044d48 100644 --- a/test/Spring/Spring.Aop.Tests/Aspects/Cache/CacheResultAdviceTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aspects/Cache/CacheResultAdviceTests.cs @@ -22,551 +22,550 @@ using System.Collections; using System.Reflection; using System.Runtime.Serialization.Formatters.Binary; using AopAlliance.Intercept; - using FakeItEasy; - using NUnit.Framework; using Spring.Caching; using Spring.Context; -namespace Spring.Aspects.Cache +namespace Spring.Aspects.Cache; + +/// +/// Unit tests for the CacheResultAdvice class. +/// +/// Aleksandar Seovic +[TestFixture] +public sealed class CacheResultAdviceTests { + object[] IGNORED_ARGS = null; + + private IMethodInvocation mockInvocation; + private IApplicationContext mockContext; + private CacheResultAdvice advice; + private ICache resultCache; + private ICache itemCache; + private ICache binaryFormatterCache; + private CacheResultTarget cacheResultTarget = new CacheResultTarget(); + + [SetUp] + public void SetUp() + { + mockInvocation = A.Fake(); + mockContext = A.Fake(); + + advice = new CacheResultAdvice(); + advice.ApplicationContext = mockContext; + + resultCache = new NonExpiringCache(); + itemCache = new NonExpiringCache(); + binaryFormatterCache = new BinaryFormatterCache(); + } + /// - /// Unit tests for the CacheResultAdvice class. + /// Change History: + /// 2007-08-22 (oakinger): changed behaviour to cache null values as well /// - /// Aleksandar Seovic - [TestFixture] - public sealed class CacheResultAdviceTests + [Test] + public void CacheResultOfMethodThatReturnsNull() { - object[] IGNORED_ARGS = null; + MethodInfo method = new VoidMethod(cacheResultTarget.ReturnsNothing).Method; + object expectedReturnValue = null; - private IMethodInvocation mockInvocation; - private IApplicationContext mockContext; - private CacheResultAdvice advice; - private ICache resultCache; - private ICache itemCache; - private ICache binaryFormatterCache; - private CacheResultTarget cacheResultTarget = new CacheResultTarget(); + ExpectAttributeRetrieval(method); + ExpectCacheKeyGeneration(method, null); + ExpectCacheInstanceRetrieval("results", resultCache); + ExpectCallToProceed(expectedReturnValue); - [SetUp] - public void SetUp() - { - mockInvocation = A.Fake(); - mockContext = A.Fake(); - - advice = new CacheResultAdvice(); - advice.ApplicationContext = mockContext; - - resultCache = new NonExpiringCache(); - itemCache = new NonExpiringCache(); - binaryFormatterCache = new BinaryFormatterCache(); - } - - /// - /// Change History: - /// 2007-08-22 (oakinger): changed behaviour to cache null values as well - /// - [Test] - public void CacheResultOfMethodThatReturnsNull() - { - MethodInfo method = new VoidMethod(cacheResultTarget.ReturnsNothing).Method; - object expectedReturnValue = null; - - ExpectAttributeRetrieval(method); - ExpectCacheKeyGeneration(method, null); - ExpectCacheInstanceRetrieval("results", resultCache); - ExpectCallToProceed(expectedReturnValue); - - // check that the null retVal is cached as well - it might be - // the result of an expensive webservice/database call etc. - object returnValue = advice.Invoke(mockInvocation); - Assert.AreEqual(expectedReturnValue, returnValue); - Assert.AreEqual(1, resultCache.Count); - } - - [Test] - public void CacheResultOfMethodThatReturnsNullWithSerializingCache() - { - MethodInfo method = new VoidMethod(cacheResultTarget.ReturnsNothing).Method; - object expectedReturnValue = null; - - ExpectAttributeRetrieval(method); - ExpectCacheKeyGeneration(method, null); - ExpectCacheInstanceRetrieval("results", binaryFormatterCache); - ExpectCallToProceed(expectedReturnValue); - - // check that the null retVal is cached as well - it might be - // the result of an expensive webservice/database call etc. - object returnValue = advice.Invoke(mockInvocation); - Assert.AreEqual(expectedReturnValue, returnValue); - Assert.AreEqual(1, binaryFormatterCache.Count); - - // cached value should be returned - object cachedValue = advice.Invoke(mockInvocation); - Assert.IsNull(cachedValue, "Should recognize cached value as null-value marker."); - } - - [Test] - public void CacheResultOfMethodThatReturnsObject() - { - MethodInfo method = new IntMethod(cacheResultTarget.ReturnsScalar).Method; - object expectedReturnValue = CacheResultTarget.Scalar; - - ExpectAttributeRetrieval(method); - ExpectCacheKeyGeneration(method, null); - ExpectCacheInstanceRetrieval("results", resultCache); - ExpectCallToProceed(expectedReturnValue); - - // return value should be added to cache - object returnValue = advice.Invoke(mockInvocation); - Assert.AreEqual(expectedReturnValue, returnValue); - Assert.AreEqual(1, resultCache.Count); - - // cached value should be returned - object cachedValue = advice.Invoke(mockInvocation); - Assert.AreEqual(expectedReturnValue, cachedValue); - Assert.AreEqual(1, resultCache.Count); - Assert.AreSame(returnValue, cachedValue); - } - - [Test] - public void CacheResultOfMethodThatReturnsCollection() - { - MethodInfo method = new EnumerableResultMethod(cacheResultTarget.ReturnsCollection).Method; - object expectedReturnValue = new object[] {"one", "two", "three"}; - - ExpectAttributeRetrieval(method); - ExpectCacheKeyGeneration(method, 5, expectedReturnValue); - ExpectCacheInstanceRetrieval("results", resultCache); - ExpectCallToProceed(new object[] {"one", "two", "three"}); - - // return value should be added to cache - object returnValue = advice.Invoke(mockInvocation); - Assert.AreEqual(expectedReturnValue, returnValue); - Assert.AreEqual(1, resultCache.Count); - - // cached value should be returned - object cachedValue = advice.Invoke(mockInvocation); - Assert.AreEqual(expectedReturnValue, cachedValue); - Assert.AreNotSame(expectedReturnValue, cachedValue); - Assert.AreEqual(expectedReturnValue, resultCache.Get(5)); - Assert.AreEqual(1, resultCache.Count); - Assert.AreSame(returnValue, cachedValue); - Assert.AreSame(cachedValue, resultCache.Get(5)); - } - - [Test] - public void CacheResultAndItemsOfMethodThatReturnsCollection() - { - MethodInfo method = new EnumerableResultMethod(cacheResultTarget.ReturnsCollectionAndItems).Method; - object expectedReturnValue = new object[] {"one", "two", "three"}; - - ExpectAttributeRetrieval(method); - ExpectCacheKeyGeneration(method, 5, expectedReturnValue); - ExpectCacheInstanceRetrieval("results", resultCache); - ExpectCallToProceed(new object[] {"one", "two", "three"}); - ExpectCacheInstanceRetrieval("items", itemCache); - - // return value should be added to result cache and each item to item cache - object returnValue = advice.Invoke(mockInvocation); - Assert.AreEqual(expectedReturnValue, returnValue); - Assert.AreEqual(1, resultCache.Count); - Assert.AreEqual(3, itemCache.Count); - - // cached value should be returned - object cachedValue = advice.Invoke(mockInvocation); - Assert.AreEqual(expectedReturnValue, cachedValue); - Assert.AreNotSame(expectedReturnValue, cachedValue); - Assert.AreEqual(expectedReturnValue, resultCache.Get(5)); - Assert.AreEqual(1, resultCache.Count); - Assert.AreEqual(3, itemCache.Count); - Assert.AreSame(returnValue, cachedValue); - Assert.AreSame(cachedValue, resultCache.Get(5)); - } - - [Test] - public void CacheOnlyItemsOfMethodThatReturnsCollection() - { - MethodInfo method = new EnumerableResultMethod(cacheResultTarget.ReturnsItems).Method; - object expectedReturnValue = new object[] { "one", "two", "three" }; - - ExpectAttributeRetrieval(method); - ExpectCacheKeyGeneration(method, 5, expectedReturnValue); - ExpectCallToProceed(new object[] { "one", "two", "three" }); - ExpectCacheInstanceRetrieval("items", itemCache); - - // return value should be added to result cache and each item to item cache - object returnValue = advice.Invoke(mockInvocation); - Assert.AreEqual(expectedReturnValue, returnValue); - Assert.AreEqual(0, resultCache.Count); - Assert.AreEqual(3, itemCache.Count); - - ExpectAttributeRetrieval(method); - ExpectCallToProceed(new object[] { "one", "two", "three" }); - ExpectCacheKeyGeneration(method, 5, expectedReturnValue); - - object newReturnValue = advice.Invoke(mockInvocation); - Assert.AreEqual(expectedReturnValue, newReturnValue); - Assert.AreEqual(0, resultCache.Count); - Assert.AreEqual(3, itemCache.Count); - Assert.AreEqual("two", itemCache.Get("two")); - Assert.AreNotSame(returnValue, newReturnValue); - } - - [Test] - public void CacheOnlyItemsOfMethodThatReturnsCollectionWithinTwoDifferentCaches() - { - MethodInfo method = new EnumerableResultMethod(cacheResultTarget.MultipleCacheResultItems).Method; - object expectedReturnValue = new object[] { "one", "two", "three" }; - - ExpectAttributeRetrieval(method); - ExpectCacheKeyGeneration(method, 5, expectedReturnValue); - ExpectCallToProceed(new object[] { "one", "two", "three" }); - ExpectCacheInstanceRetrieval("items", itemCache); - - // return value should be added to result cache and each item to item cache - object returnValue = advice.Invoke(mockInvocation); - Assert.AreEqual(expectedReturnValue, returnValue); - Assert.AreEqual(0, resultCache.Count); - Assert.AreEqual(6, itemCache.Count); - - // and again, but without Proceed() and item cache access... - ExpectAttributeRetrieval(method); - ExpectCacheKeyGeneration(method, 5, expectedReturnValue); - ExpectCallToProceed(new object[] { "one", "two", "three" }); - - // new return value should be returned - object newReturnValue = advice.Invoke(mockInvocation); - Assert.AreEqual(expectedReturnValue, newReturnValue); - Assert.AreEqual(0, resultCache.Count); - Assert.AreEqual(6, itemCache.Count); - Assert.AreEqual("two", itemCache.Get("two")); - Assert.AreEqual("two", itemCache.Get("TWO")); - Assert.AreNotSame(returnValue, newReturnValue); - } - - [Test] - public void CacheOnlyItemsOfMethodThatReturnsCollectionOnCondition() - { - MethodInfo method = new EnumerableResultMethod(cacheResultTarget.CacheResultItemsWithCondition).Method; - object expectedReturnValue = new object[] {"one", "two", "three"}; - - ExpectAttributeRetrieval(method); - ExpectCacheKeyGeneration(method, 5, expectedReturnValue); - ExpectCallToProceed(new object[] {"one", "two", "three"}); - ExpectCacheInstanceRetrieval("items", itemCache); - - // return value should be added to result cache and each item to item cache - object returnValue = advice.Invoke(mockInvocation); - Assert.AreEqual(expectedReturnValue, returnValue); - Assert.AreEqual(2, itemCache.Count); - Assert.AreEqual("two", itemCache.Get("two")); - Assert.AreEqual("three", itemCache.Get("three")); - } - - [Test] - public void CacheResultOfMethodThatReturnsCollectionOnCondition() - { - MethodInfo method = new EnumerableResultMethod(cacheResultTarget.CacheResultWithCondition).Method; - object expectedReturnValue = new object[] {}; - - ExpectAttributeRetrieval(method); - ExpectCacheKeyGeneration(method, 5, expectedReturnValue); - ExpectCacheInstanceRetrieval("results", resultCache); - ExpectCallToProceed(new object[] {}); - - // return value should not be added to cache - object returnValue = advice.Invoke(mockInvocation); - Assert.AreEqual(expectedReturnValue, returnValue); - Assert.AreEqual(0, resultCache.Count); - } - - [Test] - public void AcceptsEnumerableOnlyReturn() - { - MethodInfo method = new EnumerableResultMethod(cacheResultTarget.ReturnsEnumerableOnlyAndItems).Method; - object[] args = new object[] { "one", "two", "three" }; - EnumerableOnlyResult expectedReturnValue = new EnumerableOnlyResult(args); - - ExpectAttributeRetrieval(method); - ExpectCacheKeyGeneration(method, 5, expectedReturnValue.InnerArray); - ExpectCacheInstanceRetrieval("results", resultCache); - ExpectCallToProceed(expectedReturnValue); - ExpectCacheInstanceRetrieval("items", itemCache); - - // return value should be added to result cache and each item to item cache - object returnValue = advice.Invoke(mockInvocation); - Assert.AreEqual(1, resultCache.Count); - Assert.AreEqual(3, itemCache.Count); - Assert.AreSame(expectedReturnValue, returnValue); - Assert.AreSame(expectedReturnValue, resultCache.Get(5)); - - // and again, but without Proceed() and item cache access... - ExpectAttributeRetrieval(method); - ExpectCacheKeyGeneration(method, 5, IGNORED_ARGS); - - // cached value should be returned, cache remains unchanged - object cachedValue = advice.Invoke(mockInvocation); - Assert.AreSame(expectedReturnValue, cachedValue); - Assert.AreSame(returnValue, cachedValue); - Assert.AreSame(expectedReturnValue, resultCache.Get(5)); - Assert.AreEqual(1, resultCache.Count); - Assert.AreEqual(3, itemCache.Count); - } - - [Test] - public void CacheResultOfMethodThatReturnsCollectionContainingNullItems() - { - MethodInfo method = new EnumerableResultMethod(cacheResultTarget.ReturnsEnumerableOnlyAndItems).Method; - object expectedReturnValue = new object[] { null, "two", null }; - - ExpectAttributeRetrieval(method); - ExpectCacheKeyGeneration(method, 5, expectedReturnValue); - ExpectCacheInstanceRetrieval("results", resultCache); - ExpectCallToProceed(expectedReturnValue); - ExpectCacheInstanceRetrieval("items", itemCache); - - // return value should be added to result cache and each item to item cache - object returnValue = advice.Invoke(mockInvocation); - Assert.AreSame(expectedReturnValue, returnValue); - Assert.AreEqual(1, resultCache.Count); - Assert.AreEqual(2, itemCache.Count); // 2 null items result into 1 cached item - - // and again, but without Proceed() and item cache access... - ExpectAttributeRetrieval(method); - ExpectCacheKeyGeneration(method, 5, IGNORED_ARGS); - - // cached value should be returned - object cachedValue = advice.Invoke(mockInvocation); - Assert.AreSame(expectedReturnValue, cachedValue); - Assert.AreSame(returnValue, cachedValue); - Assert.AreSame(expectedReturnValue, resultCache.Get(5)); - Assert.AreEqual(1, resultCache.Count); - Assert.AreEqual(2, itemCache.Count); - } - - [Test] - public void CacheResultWithMethodInfo() - { - MethodInfo method = new EnumerableResultMethod(cacheResultTarget.CacheResultWithMethodInfo).Method; - object expectedReturnValue = new object[] {"one", "two", "three"}; - - ExpectAttributeRetrieval(method); - ExpectCacheKeyGeneration(method, 5, expectedReturnValue); - ExpectCacheInstanceRetrieval("results", resultCache); - ExpectCallToProceed(new object[] {"one", "two", "three"}); - - // return value should be added to cache - object returnValue = advice.Invoke(mockInvocation); - Assert.AreEqual(expectedReturnValue, returnValue); - Assert.AreEqual(1, resultCache.Count); - Assert.AreEqual(returnValue, resultCache.Get("CacheResultWithMethodInfo-5")); - } - - [Test] - public void CacheResultItemsWithMethodInfo() - { - MethodInfo method = new EnumerableResultMethod(cacheResultTarget.CacheResultItemsWithMethodInfo).Method; - object expectedReturnValue = new object[] {"one", "two", "three"}; - - ExpectAttributeRetrieval(method); - ExpectCacheKeyGeneration(method, 5, expectedReturnValue); - ExpectCallToProceed(new object[] {"one", "two", "three"}); - ExpectCacheInstanceRetrieval("items", itemCache); - - // return value should be added to result cache and each item to item cache - object returnValue = advice.Invoke(mockInvocation); - Assert.AreEqual(expectedReturnValue, returnValue); - Assert.AreEqual(0, resultCache.Count); - Assert.AreEqual(3, itemCache.Count); - Assert.AreEqual("two", itemCache.Get("CacheResultItemsWithMethodInfo-two")); - } - - private void ExpectAttributeRetrieval(MethodInfo method) - { - A.CallTo(() => mockInvocation.Method).Returns(method); - } - - private void ExpectCacheKeyGeneration(MethodInfo method, params object[] arguments) - { - A.CallTo(() => mockInvocation.Arguments).Returns(arguments); - } - - private void ExpectCacheInstanceRetrieval(string cacheName, ICache cache) - { - A.CallTo(() => mockContext.GetObject(cacheName)).Returns(cache); - } - - private void ExpectCacheInstanceRetrieval(string cacheName, ICache cache, int repeatTimes) - { - A.CallTo(() => mockContext.GetObject(cacheName)).Returns(cache).NumberOfTimes(repeatTimes); - } - - private void ExpectCallToProceed(object expectedReturnValue, int repeatTimes) - { - A.CallTo(() => mockInvocation.Proceed()).Returns(expectedReturnValue).NumberOfTimes(repeatTimes); - } - - private void ExpectCallToProceed(object expectedReturnValue) - { - A.CallTo(() => mockInvocation.Proceed()).Returns(expectedReturnValue); - } + // check that the null retVal is cached as well - it might be + // the result of an expensive webservice/database call etc. + object returnValue = advice.Invoke(mockInvocation); + Assert.AreEqual(expectedReturnValue, returnValue); + Assert.AreEqual(1, resultCache.Count); } - #region Inner Class : CacheResultTarget - - public delegate void VoidMethod(); - public delegate int IntMethod(); - public delegate IEnumerable EnumerableResultMethod(int key, params object[] elements); - - public class EnumerableOnlyResult : IEnumerable + [Test] + public void CacheResultOfMethodThatReturnsNullWithSerializingCache() { - private object[] _args; + MethodInfo method = new VoidMethod(cacheResultTarget.ReturnsNothing).Method; + object expectedReturnValue = null; - public EnumerableOnlyResult(params object[] args) - { - _args = args; - } + ExpectAttributeRetrieval(method); + ExpectCacheKeyGeneration(method, null); + ExpectCacheInstanceRetrieval("results", binaryFormatterCache); + ExpectCallToProceed(expectedReturnValue); - public IEnumerator GetEnumerator() - { - return _args.GetEnumerator(); - } + // check that the null retVal is cached as well - it might be + // the result of an expensive webservice/database call etc. + object returnValue = advice.Invoke(mockInvocation); + Assert.AreEqual(expectedReturnValue, returnValue); + Assert.AreEqual(1, binaryFormatterCache.Count); - public override bool Equals(object obj) - { - Assert.AreEqual(_args, ((EnumerableOnlyResult)obj)._args); - return true; - } - - public override int GetHashCode() - { - return _args.GetHashCode(); - } - - public override string ToString() - { - return _args.ToString(); - } - - public int Length { get { return _args.Length; } } - - public object[] InnerArray - { - get { return _args; } - } + // cached value should be returned + object cachedValue = advice.Invoke(mockInvocation); + Assert.IsNull(cachedValue, "Should recognize cached value as null-value marker."); } - public interface ICacheResultTarget + [Test] + public void CacheResultOfMethodThatReturnsObject() { - void ReturnsNothing(); - int ReturnsScalar(); - IEnumerable ReturnsCollection(int key, params object[] elements); - IEnumerable ReturnsCollectionAndItems(int key, params object[] elements); - IEnumerable ReturnsItems(int key, params object[] elements); + MethodInfo method = new IntMethod(cacheResultTarget.ReturnsScalar).Method; + object expectedReturnValue = CacheResultTarget.Scalar; + + ExpectAttributeRetrieval(method); + ExpectCacheKeyGeneration(method, null); + ExpectCacheInstanceRetrieval("results", resultCache); + ExpectCallToProceed(expectedReturnValue); + + // return value should be added to cache + object returnValue = advice.Invoke(mockInvocation); + Assert.AreEqual(expectedReturnValue, returnValue); + Assert.AreEqual(1, resultCache.Count); + + // cached value should be returned + object cachedValue = advice.Invoke(mockInvocation); + Assert.AreEqual(expectedReturnValue, cachedValue); + Assert.AreEqual(1, resultCache.Count); + Assert.AreSame(returnValue, cachedValue); } - public sealed class CacheResultTarget : ICacheResultTarget + [Test] + public void CacheResultOfMethodThatReturnsCollection() { - public const int Scalar = int.MaxValue; + MethodInfo method = new EnumerableResultMethod(cacheResultTarget.ReturnsCollection).Method; + object expectedReturnValue = new object[] { "one", "two", "three" }; - [CacheResult("results", "'key'")] - public void ReturnsNothing() - { - } + ExpectAttributeRetrieval(method); + ExpectCacheKeyGeneration(method, 5, expectedReturnValue); + ExpectCacheInstanceRetrieval("results", resultCache); + ExpectCallToProceed(new object[] { "one", "two", "three" }); - [CacheResult("results", "'key'")] - public int ReturnsScalar() - { - return Scalar; - } + // return value should be added to cache + object returnValue = advice.Invoke(mockInvocation); + Assert.AreEqual(expectedReturnValue, returnValue); + Assert.AreEqual(1, resultCache.Count); - [CacheResult("results", "#key")] - public IEnumerable ReturnsCollection(int key, params object[] elements) - { - return elements; - } - - [CacheResult("results", "#key")] - [CacheResultItems("items", "''+#this")] - public IEnumerable ReturnsCollectionAndItems(int key, params object[] elements) - { - return elements; - } - - [CacheResult("results", "#key")] - [CacheResultItems("items", "''+#this")] - public IEnumerable ReturnsEnumerableOnlyAndItems(int key, params object[] elements) - { - return new EnumerableOnlyResult(elements); - } - - [CacheResultItems("items", "#this")] - public IEnumerable ReturnsItems(int key, params object[] elements) - { - return elements; - } - - [CacheResultItems("items", "#this")] - [CacheResultItems("items", "#this.ToUpper()")] - public IEnumerable MultipleCacheResultItems(int key, params object[] elements) - { - return elements; - } - - [CacheResult("results", "#CacheResultWithMethodInfo.Name + '-' + #key")] - public IEnumerable CacheResultWithMethodInfo(int key, params object[] elements) - { - return elements; - } - - [CacheResultItems("items", "#CacheResultItemsWithMethodInfo.Name + '-' + #this")] - public IEnumerable CacheResultItemsWithMethodInfo(int key, params object[] elements) - { - return elements; - } - - [CacheResultItems("items", "#this", Condition = "#this.StartsWith('t')")] - public IEnumerable CacheResultItemsWithCondition(int key, params object[] elements) - { - return elements; - } - - [CacheResult("results", "#key", Condition = "#this.Length > 0")] - public IEnumerable CacheResultWithCondition(int key, params object[] elements) - { - return elements; - } + // cached value should be returned + object cachedValue = advice.Invoke(mockInvocation); + Assert.AreEqual(expectedReturnValue, cachedValue); + Assert.AreNotSame(expectedReturnValue, cachedValue); + Assert.AreEqual(expectedReturnValue, resultCache.Get(5)); + Assert.AreEqual(1, resultCache.Count); + Assert.AreSame(returnValue, cachedValue); + Assert.AreSame(cachedValue, resultCache.Get(5)); } - #endregion - - class BinaryFormatterCache : NonExpiringCache + [Test] + public void CacheResultAndItemsOfMethodThatReturnsCollection() { - protected override void DoInsert(object key, object value, System.TimeSpan timeToLive) - { - BinaryFormatter fmt = new BinaryFormatter(); - using (MemoryStream stream = new MemoryStream()) - { - fmt.Serialize(stream, value); - stream.Seek(0, SeekOrigin.Begin); - value = stream.ToArray(); - } + MethodInfo method = new EnumerableResultMethod(cacheResultTarget.ReturnsCollectionAndItems).Method; + object expectedReturnValue = new object[] { "one", "two", "three" }; - base.DoInsert(key, value, timeToLive); - } + ExpectAttributeRetrieval(method); + ExpectCacheKeyGeneration(method, 5, expectedReturnValue); + ExpectCacheInstanceRetrieval("results", resultCache); + ExpectCallToProceed(new object[] { "one", "two", "three" }); + ExpectCacheInstanceRetrieval("items", itemCache); - public override object Get(object key) - { - byte[] bytes = (byte[])base.Get(key); + // return value should be added to result cache and each item to item cache + object returnValue = advice.Invoke(mockInvocation); + Assert.AreEqual(expectedReturnValue, returnValue); + Assert.AreEqual(1, resultCache.Count); + Assert.AreEqual(3, itemCache.Count); - if (bytes == null) - { - return null; - } + // cached value should be returned + object cachedValue = advice.Invoke(mockInvocation); + Assert.AreEqual(expectedReturnValue, cachedValue); + Assert.AreNotSame(expectedReturnValue, cachedValue); + Assert.AreEqual(expectedReturnValue, resultCache.Get(5)); + Assert.AreEqual(1, resultCache.Count); + Assert.AreEqual(3, itemCache.Count); + Assert.AreSame(returnValue, cachedValue); + Assert.AreSame(cachedValue, resultCache.Get(5)); + } - BinaryFormatter fmt = new BinaryFormatter(); - return fmt.Deserialize(new MemoryStream(bytes)); - } + [Test] + public void CacheOnlyItemsOfMethodThatReturnsCollection() + { + MethodInfo method = new EnumerableResultMethod(cacheResultTarget.ReturnsItems).Method; + object expectedReturnValue = new object[] { "one", "two", "three" }; + + ExpectAttributeRetrieval(method); + ExpectCacheKeyGeneration(method, 5, expectedReturnValue); + ExpectCallToProceed(new object[] { "one", "two", "three" }); + ExpectCacheInstanceRetrieval("items", itemCache); + + // return value should be added to result cache and each item to item cache + object returnValue = advice.Invoke(mockInvocation); + Assert.AreEqual(expectedReturnValue, returnValue); + Assert.AreEqual(0, resultCache.Count); + Assert.AreEqual(3, itemCache.Count); + + ExpectAttributeRetrieval(method); + ExpectCallToProceed(new object[] { "one", "two", "three" }); + ExpectCacheKeyGeneration(method, 5, expectedReturnValue); + + object newReturnValue = advice.Invoke(mockInvocation); + Assert.AreEqual(expectedReturnValue, newReturnValue); + Assert.AreEqual(0, resultCache.Count); + Assert.AreEqual(3, itemCache.Count); + Assert.AreEqual("two", itemCache.Get("two")); + Assert.AreNotSame(returnValue, newReturnValue); + } + + [Test] + public void CacheOnlyItemsOfMethodThatReturnsCollectionWithinTwoDifferentCaches() + { + MethodInfo method = new EnumerableResultMethod(cacheResultTarget.MultipleCacheResultItems).Method; + object expectedReturnValue = new object[] { "one", "two", "three" }; + + ExpectAttributeRetrieval(method); + ExpectCacheKeyGeneration(method, 5, expectedReturnValue); + ExpectCallToProceed(new object[] { "one", "two", "three" }); + ExpectCacheInstanceRetrieval("items", itemCache); + + // return value should be added to result cache and each item to item cache + object returnValue = advice.Invoke(mockInvocation); + Assert.AreEqual(expectedReturnValue, returnValue); + Assert.AreEqual(0, resultCache.Count); + Assert.AreEqual(6, itemCache.Count); + + // and again, but without Proceed() and item cache access... + ExpectAttributeRetrieval(method); + ExpectCacheKeyGeneration(method, 5, expectedReturnValue); + ExpectCallToProceed(new object[] { "one", "two", "three" }); + + // new return value should be returned + object newReturnValue = advice.Invoke(mockInvocation); + Assert.AreEqual(expectedReturnValue, newReturnValue); + Assert.AreEqual(0, resultCache.Count); + Assert.AreEqual(6, itemCache.Count); + Assert.AreEqual("two", itemCache.Get("two")); + Assert.AreEqual("two", itemCache.Get("TWO")); + Assert.AreNotSame(returnValue, newReturnValue); + } + + [Test] + public void CacheOnlyItemsOfMethodThatReturnsCollectionOnCondition() + { + MethodInfo method = new EnumerableResultMethod(cacheResultTarget.CacheResultItemsWithCondition).Method; + object expectedReturnValue = new object[] { "one", "two", "three" }; + + ExpectAttributeRetrieval(method); + ExpectCacheKeyGeneration(method, 5, expectedReturnValue); + ExpectCallToProceed(new object[] { "one", "two", "three" }); + ExpectCacheInstanceRetrieval("items", itemCache); + + // return value should be added to result cache and each item to item cache + object returnValue = advice.Invoke(mockInvocation); + Assert.AreEqual(expectedReturnValue, returnValue); + Assert.AreEqual(2, itemCache.Count); + Assert.AreEqual("two", itemCache.Get("two")); + Assert.AreEqual("three", itemCache.Get("three")); + } + + [Test] + public void CacheResultOfMethodThatReturnsCollectionOnCondition() + { + MethodInfo method = new EnumerableResultMethod(cacheResultTarget.CacheResultWithCondition).Method; + object expectedReturnValue = new object[] { }; + + ExpectAttributeRetrieval(method); + ExpectCacheKeyGeneration(method, 5, expectedReturnValue); + ExpectCacheInstanceRetrieval("results", resultCache); + ExpectCallToProceed(new object[] { }); + + // return value should not be added to cache + object returnValue = advice.Invoke(mockInvocation); + Assert.AreEqual(expectedReturnValue, returnValue); + Assert.AreEqual(0, resultCache.Count); + } + + [Test] + public void AcceptsEnumerableOnlyReturn() + { + MethodInfo method = new EnumerableResultMethod(cacheResultTarget.ReturnsEnumerableOnlyAndItems).Method; + object[] args = new object[] { "one", "two", "three" }; + EnumerableOnlyResult expectedReturnValue = new EnumerableOnlyResult(args); + + ExpectAttributeRetrieval(method); + ExpectCacheKeyGeneration(method, 5, expectedReturnValue.InnerArray); + ExpectCacheInstanceRetrieval("results", resultCache); + ExpectCallToProceed(expectedReturnValue); + ExpectCacheInstanceRetrieval("items", itemCache); + + // return value should be added to result cache and each item to item cache + object returnValue = advice.Invoke(mockInvocation); + Assert.AreEqual(1, resultCache.Count); + Assert.AreEqual(3, itemCache.Count); + Assert.AreSame(expectedReturnValue, returnValue); + Assert.AreSame(expectedReturnValue, resultCache.Get(5)); + + // and again, but without Proceed() and item cache access... + ExpectAttributeRetrieval(method); + ExpectCacheKeyGeneration(method, 5, IGNORED_ARGS); + + // cached value should be returned, cache remains unchanged + object cachedValue = advice.Invoke(mockInvocation); + Assert.AreSame(expectedReturnValue, cachedValue); + Assert.AreSame(returnValue, cachedValue); + Assert.AreSame(expectedReturnValue, resultCache.Get(5)); + Assert.AreEqual(1, resultCache.Count); + Assert.AreEqual(3, itemCache.Count); + } + + [Test] + public void CacheResultOfMethodThatReturnsCollectionContainingNullItems() + { + MethodInfo method = new EnumerableResultMethod(cacheResultTarget.ReturnsEnumerableOnlyAndItems).Method; + object expectedReturnValue = new object[] { null, "two", null }; + + ExpectAttributeRetrieval(method); + ExpectCacheKeyGeneration(method, 5, expectedReturnValue); + ExpectCacheInstanceRetrieval("results", resultCache); + ExpectCallToProceed(expectedReturnValue); + ExpectCacheInstanceRetrieval("items", itemCache); + + // return value should be added to result cache and each item to item cache + object returnValue = advice.Invoke(mockInvocation); + Assert.AreSame(expectedReturnValue, returnValue); + Assert.AreEqual(1, resultCache.Count); + Assert.AreEqual(2, itemCache.Count); // 2 null items result into 1 cached item + + // and again, but without Proceed() and item cache access... + ExpectAttributeRetrieval(method); + ExpectCacheKeyGeneration(method, 5, IGNORED_ARGS); + + // cached value should be returned + object cachedValue = advice.Invoke(mockInvocation); + Assert.AreSame(expectedReturnValue, cachedValue); + Assert.AreSame(returnValue, cachedValue); + Assert.AreSame(expectedReturnValue, resultCache.Get(5)); + Assert.AreEqual(1, resultCache.Count); + Assert.AreEqual(2, itemCache.Count); + } + + [Test] + public void CacheResultWithMethodInfo() + { + MethodInfo method = new EnumerableResultMethod(cacheResultTarget.CacheResultWithMethodInfo).Method; + object expectedReturnValue = new object[] { "one", "two", "three" }; + + ExpectAttributeRetrieval(method); + ExpectCacheKeyGeneration(method, 5, expectedReturnValue); + ExpectCacheInstanceRetrieval("results", resultCache); + ExpectCallToProceed(new object[] { "one", "two", "three" }); + + // return value should be added to cache + object returnValue = advice.Invoke(mockInvocation); + Assert.AreEqual(expectedReturnValue, returnValue); + Assert.AreEqual(1, resultCache.Count); + Assert.AreEqual(returnValue, resultCache.Get("CacheResultWithMethodInfo-5")); + } + + [Test] + public void CacheResultItemsWithMethodInfo() + { + MethodInfo method = new EnumerableResultMethod(cacheResultTarget.CacheResultItemsWithMethodInfo).Method; + object expectedReturnValue = new object[] { "one", "two", "three" }; + + ExpectAttributeRetrieval(method); + ExpectCacheKeyGeneration(method, 5, expectedReturnValue); + ExpectCallToProceed(new object[] { "one", "two", "three" }); + ExpectCacheInstanceRetrieval("items", itemCache); + + // return value should be added to result cache and each item to item cache + object returnValue = advice.Invoke(mockInvocation); + Assert.AreEqual(expectedReturnValue, returnValue); + Assert.AreEqual(0, resultCache.Count); + Assert.AreEqual(3, itemCache.Count); + Assert.AreEqual("two", itemCache.Get("CacheResultItemsWithMethodInfo-two")); + } + + private void ExpectAttributeRetrieval(MethodInfo method) + { + A.CallTo(() => mockInvocation.Method).Returns(method); + } + + private void ExpectCacheKeyGeneration(MethodInfo method, params object[] arguments) + { + A.CallTo(() => mockInvocation.Arguments).Returns(arguments); + } + + private void ExpectCacheInstanceRetrieval(string cacheName, ICache cache) + { + A.CallTo(() => mockContext.GetObject(cacheName)).Returns(cache); + } + + private void ExpectCacheInstanceRetrieval(string cacheName, ICache cache, int repeatTimes) + { + A.CallTo(() => mockContext.GetObject(cacheName)).Returns(cache).NumberOfTimes(repeatTimes); + } + + private void ExpectCallToProceed(object expectedReturnValue, int repeatTimes) + { + A.CallTo(() => mockInvocation.Proceed()).Returns(expectedReturnValue).NumberOfTimes(repeatTimes); + } + + private void ExpectCallToProceed(object expectedReturnValue) + { + A.CallTo(() => mockInvocation.Proceed()).Returns(expectedReturnValue); } } + +#region Inner Class : CacheResultTarget + +public delegate void VoidMethod(); + +public delegate int IntMethod(); + +public delegate IEnumerable EnumerableResultMethod(int key, params object[] elements); + +public class EnumerableOnlyResult : IEnumerable +{ + private object[] _args; + + public EnumerableOnlyResult(params object[] args) + { + _args = args; + } + + public IEnumerator GetEnumerator() + { + return _args.GetEnumerator(); + } + + public override bool Equals(object obj) + { + Assert.AreEqual(_args, ((EnumerableOnlyResult) obj)._args); + return true; + } + + public override int GetHashCode() + { + return _args.GetHashCode(); + } + + public override string ToString() + { + return _args.ToString(); + } + + public int Length { get { return _args.Length; } } + + public object[] InnerArray + { + get { return _args; } + } +} + +public interface ICacheResultTarget +{ + void ReturnsNothing(); + int ReturnsScalar(); + IEnumerable ReturnsCollection(int key, params object[] elements); + IEnumerable ReturnsCollectionAndItems(int key, params object[] elements); + IEnumerable ReturnsItems(int key, params object[] elements); +} + +public sealed class CacheResultTarget : ICacheResultTarget +{ + public const int Scalar = int.MaxValue; + + [CacheResult("results", "'key'")] + public void ReturnsNothing() + { + } + + [CacheResult("results", "'key'")] + public int ReturnsScalar() + { + return Scalar; + } + + [CacheResult("results", "#key")] + public IEnumerable ReturnsCollection(int key, params object[] elements) + { + return elements; + } + + [CacheResult("results", "#key")] + [CacheResultItems("items", "''+#this")] + public IEnumerable ReturnsCollectionAndItems(int key, params object[] elements) + { + return elements; + } + + [CacheResult("results", "#key")] + [CacheResultItems("items", "''+#this")] + public IEnumerable ReturnsEnumerableOnlyAndItems(int key, params object[] elements) + { + return new EnumerableOnlyResult(elements); + } + + [CacheResultItems("items", "#this")] + public IEnumerable ReturnsItems(int key, params object[] elements) + { + return elements; + } + + [CacheResultItems("items", "#this")] + [CacheResultItems("items", "#this.ToUpper()")] + public IEnumerable MultipleCacheResultItems(int key, params object[] elements) + { + return elements; + } + + [CacheResult("results", "#CacheResultWithMethodInfo.Name + '-' + #key")] + public IEnumerable CacheResultWithMethodInfo(int key, params object[] elements) + { + return elements; + } + + [CacheResultItems("items", "#CacheResultItemsWithMethodInfo.Name + '-' + #this")] + public IEnumerable CacheResultItemsWithMethodInfo(int key, params object[] elements) + { + return elements; + } + + [CacheResultItems("items", "#this", Condition = "#this.StartsWith('t')")] + public IEnumerable CacheResultItemsWithCondition(int key, params object[] elements) + { + return elements; + } + + [CacheResult("results", "#key", Condition = "#this.Length > 0")] + public IEnumerable CacheResultWithCondition(int key, params object[] elements) + { + return elements; + } +} + +#endregion + +class BinaryFormatterCache : NonExpiringCache +{ + protected override void DoInsert(object key, object value, System.TimeSpan timeToLive) + { + BinaryFormatter fmt = new BinaryFormatter(); + using (MemoryStream stream = new MemoryStream()) + { + fmt.Serialize(stream, value); + stream.Seek(0, SeekOrigin.Begin); + value = stream.ToArray(); + } + + base.DoInsert(key, value, timeToLive); + } + + public override object Get(object key) + { + byte[] bytes = (byte[]) base.Get(key); + + if (bytes == null) + { + return null; + } + + BinaryFormatter fmt = new BinaryFormatter(); + return fmt.Deserialize(new MemoryStream(bytes)); + } +} \ No newline at end of file diff --git a/test/Spring/Spring.Aop.Tests/Aspects/Cache/InvalidateCacheAdviceTests.cs b/test/Spring/Spring.Aop.Tests/Aspects/Cache/InvalidateCacheAdviceTests.cs index 98b26327..17a51daf 100644 --- a/test/Spring/Spring.Aop.Tests/Aspects/Cache/InvalidateCacheAdviceTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aspects/Cache/InvalidateCacheAdviceTests.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -19,154 +19,150 @@ #endregion using System.Reflection; - using FakeItEasy; - using NUnit.Framework; - using Spring.Caching; using Spring.Context; -namespace Spring.Aspects.Cache +namespace Spring.Aspects.Cache; + +/// +/// Unit tests for the InvalidateCacheAdvice class. +/// +/// Aleksandar Seovic +[TestFixture] +public sealed class InvalidateCacheAdviceTests { - /// - /// Unit tests for the InvalidateCacheAdvice class. - /// - /// Aleksandar Seovic - [TestFixture] - public sealed class InvalidateCacheAdviceTests + private IApplicationContext mockContext; + private InvalidateCacheAdvice advice; + private ICache cache; + + [SetUp] + public void SetUp() { - private IApplicationContext mockContext; - private InvalidateCacheAdvice advice; - private ICache cache; + mockContext = A.Fake(); - [SetUp] - public void SetUp() - { - mockContext = A.Fake(); + advice = new InvalidateCacheAdvice(); + advice.ApplicationContext = mockContext; - advice = new InvalidateCacheAdvice(); - advice.ApplicationContext = mockContext; - - cache = new NonExpiringCache(); - cache.Insert(1, "one"); - cache.Insert(2, "two"); - cache.Insert(3, "three"); - } - - [Test] - public void TestSingleKeyInvalidation() - { - MethodInfo method = typeof(InvalidateCacheTarget).GetMethod("InvalidateSingle"); - object[] args = new object[] { 2 }; - - ExpectCacheInstanceRetrieval("cache", cache); - - Assert.AreEqual(3, cache.Count); - - // item "two" should be removed from cache - advice.AfterReturning(null, method, args, null); - Assert.AreEqual(2, cache.Count); - Assert.IsNull(cache.Get(2)); - } - - [Test] - public void TestMultiKeyInvalidation() - { - MethodInfo method = typeof(InvalidateCacheTarget).GetMethod("InvalidateMulti"); - object[] args = new object[] { 2 }; - - ExpectCacheInstanceRetrieval("cache", cache); - - Assert.AreEqual(3, cache.Count); - - // all items except item "two" should be removed from cache - advice.AfterReturning(null, method, args, null); - Assert.AreEqual(1, cache.Count); - Assert.AreEqual("two", cache.Get(2)); - } - - [Test] - public void TestWholeCacheInvalidation() - { - MethodInfo method = typeof(InvalidateCacheTarget).GetMethod("InvalidateAll"); - - ExpectCacheInstanceRetrieval("cache", cache); - - Assert.AreEqual(3, cache.Count); - - // all items should be removed from cache - advice.AfterReturning(null, method, null, null); - Assert.AreEqual(0, cache.Count); - } - - [Test] - public void TestMultipleCachesInvalidation() - { - MethodInfo method = typeof(InvalidateCacheTarget).GetMethod("InvalidateMultipleCaches"); - object[] args = new object[] { 2 }; - - ExpectCacheInstanceRetrieval("cache", cache); - ExpectCacheInstanceRetrieval("cache", cache); - - Assert.AreEqual(3, cache.Count); - - // item "two" should be removed from cache - // all items except item "two" should be removed from cache - advice.AfterReturning(null, method, args, null); - Assert.AreEqual(0, cache.Count); - } - - [Test] - public void TestConditionInvalidation() - { - MethodInfo method = typeof(InvalidateCacheTarget).GetMethod("InvalidateWithCondition"); - object[] args = new object[] { 3 }; - - Assert.AreEqual(3, cache.Count); - - // no items should be removed from cache - advice.AfterReturning(null, method, args, null); - Assert.AreEqual(3, cache.Count); - Assert.AreEqual("three", cache.Get(3)); - } - - private void ExpectCacheInstanceRetrieval(string cacheName, ICache cacheToReturn) - { - A.CallTo(() => mockContext.GetObject(cacheName)).Returns(cacheToReturn).Once(); - } + cache = new NonExpiringCache(); + cache.Insert(1, "one"); + cache.Insert(2, "two"); + cache.Insert(3, "three"); } - #region Inner Class : InvalidateCacheTarget - - public sealed class InvalidateCacheTarget + [Test] + public void TestSingleKeyInvalidation() { - [InvalidateCache("cache", Keys = "#key")] - public void InvalidateSingle(int key) - { - } + MethodInfo method = typeof(InvalidateCacheTarget).GetMethod("InvalidateSingle"); + object[] args = new object[] { 2 }; - [InvalidateCache("cache", Keys = "{1, 2, 3} - { #key }")] - public void InvalidateMulti(int key) - { - } + ExpectCacheInstanceRetrieval("cache", cache); - [InvalidateCache("cache")] - public void InvalidateAll() - { - } + Assert.AreEqual(3, cache.Count); - [InvalidateCache("cache", Keys = "#key")] - [InvalidateCache("cache", Keys = "{1, 2, 3} - { #key }")] - public void InvalidateMultipleCaches(int key) - { - } - - [InvalidateCache("cache", Keys = "{1, 2, 3} - { #key }", Condition="#key != 3")] - public void InvalidateWithCondition(int key) - { - } + // item "two" should be removed from cache + advice.AfterReturning(null, method, args, null); + Assert.AreEqual(2, cache.Count); + Assert.IsNull(cache.Get(2)); } - #endregion -} \ No newline at end of file + [Test] + public void TestMultiKeyInvalidation() + { + MethodInfo method = typeof(InvalidateCacheTarget).GetMethod("InvalidateMulti"); + object[] args = new object[] { 2 }; + + ExpectCacheInstanceRetrieval("cache", cache); + + Assert.AreEqual(3, cache.Count); + + // all items except item "two" should be removed from cache + advice.AfterReturning(null, method, args, null); + Assert.AreEqual(1, cache.Count); + Assert.AreEqual("two", cache.Get(2)); + } + + [Test] + public void TestWholeCacheInvalidation() + { + MethodInfo method = typeof(InvalidateCacheTarget).GetMethod("InvalidateAll"); + + ExpectCacheInstanceRetrieval("cache", cache); + + Assert.AreEqual(3, cache.Count); + + // all items should be removed from cache + advice.AfterReturning(null, method, null, null); + Assert.AreEqual(0, cache.Count); + } + + [Test] + public void TestMultipleCachesInvalidation() + { + MethodInfo method = typeof(InvalidateCacheTarget).GetMethod("InvalidateMultipleCaches"); + object[] args = new object[] { 2 }; + + ExpectCacheInstanceRetrieval("cache", cache); + ExpectCacheInstanceRetrieval("cache", cache); + + Assert.AreEqual(3, cache.Count); + + // item "two" should be removed from cache + // all items except item "two" should be removed from cache + advice.AfterReturning(null, method, args, null); + Assert.AreEqual(0, cache.Count); + } + + [Test] + public void TestConditionInvalidation() + { + MethodInfo method = typeof(InvalidateCacheTarget).GetMethod("InvalidateWithCondition"); + object[] args = new object[] { 3 }; + + Assert.AreEqual(3, cache.Count); + + // no items should be removed from cache + advice.AfterReturning(null, method, args, null); + Assert.AreEqual(3, cache.Count); + Assert.AreEqual("three", cache.Get(3)); + } + + private void ExpectCacheInstanceRetrieval(string cacheName, ICache cacheToReturn) + { + A.CallTo(() => mockContext.GetObject(cacheName)).Returns(cacheToReturn).Once(); + } +} + +#region Inner Class : InvalidateCacheTarget + +public sealed class InvalidateCacheTarget +{ + [InvalidateCache("cache", Keys = "#key")] + public void InvalidateSingle(int key) + { + } + + [InvalidateCache("cache", Keys = "{1, 2, 3} - { #key }")] + public void InvalidateMulti(int key) + { + } + + [InvalidateCache("cache")] + public void InvalidateAll() + { + } + + [InvalidateCache("cache", Keys = "#key")] + [InvalidateCache("cache", Keys = "{1, 2, 3} - { #key }")] + public void InvalidateMultipleCaches(int key) + { + } + + [InvalidateCache("cache", Keys = "{1, 2, 3} - { #key }", Condition = "#key != 3")] + public void InvalidateWithCondition(int key) + { + } +} + +#endregion diff --git a/test/Spring/Spring.Aop.Tests/Aspects/Exception/ExceptionHandlerAspectIntegrationTests.cs b/test/Spring/Spring.Aop.Tests/Aspects/Exception/ExceptionHandlerAspectIntegrationTests.cs index 7b615112..299e8d33 100644 --- a/test/Spring/Spring.Aop.Tests/Aspects/Exception/ExceptionHandlerAspectIntegrationTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aspects/Exception/ExceptionHandlerAspectIntegrationTests.cs @@ -29,504 +29,497 @@ using Spring.Util; #endregion -namespace Spring.Aspects.Exceptions +namespace Spring.Aspects.Exceptions; + +/// +/// This class contains tests for ExceptionHandlerAdvice +/// +/// Mark Pollack +[TestFixture] +public class ExceptionHandlerAspectIntegrationTests { - /// - /// This class contains tests for ExceptionHandlerAdvice - /// - /// Mark Pollack - [TestFixture] - public class ExceptionHandlerAspectIntegrationTests + private ExceptionHandlerAdvice exceptionHandlerAdvice; + private CapturingLoggerFactory loggerFactory; + private ILoggerFactory originalFactory; + private static bool spelActionExecuted = false; + + [SetUp] + public void Setup() { - private ExceptionHandlerAdvice exceptionHandlerAdvice; - private CapturingLoggerFactory loggerFactory; - private ILoggerFactory originalFactory; - private static bool spelActionExecuted = false; + originalFactory = LogManager.LoggerFactory; + loggerFactory = new CapturingLoggerFactory(); + LogManager.LoggerFactory = loggerFactory; + exceptionHandlerAdvice = new ExceptionHandlerAdvice(); + } - [SetUp] - public void Setup() + public class CapturingLoggerFactory : ILoggerFactory + { + public List LoggerEvents { get; set; } = []; + + public void Dispose() { - originalFactory = LogManager.LoggerFactory; - loggerFactory = new CapturingLoggerFactory(); - LogManager.LoggerFactory = loggerFactory; - exceptionHandlerAdvice = new ExceptionHandlerAdvice(); } - public class CapturingLoggerFactory : ILoggerFactory + public ILogger CreateLogger(string categoryName) { - public List LoggerEvents { get; set; }= []; + return new CapturingLogger(LoggerEvents); + } - - public void Dispose() + public class CapturingLogger(List loggedEvents) : ILogger + { + public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter) { + var message = formatter(state, exception); + loggedEvents.Add(message); } - public ILogger CreateLogger(string categoryName) + public bool IsEnabled(LogLevel logLevel) { - return new CapturingLogger(LoggerEvents); + return true; } - public class CapturingLogger(List loggedEvents) : ILogger - { - public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter) - { - var message = formatter(state, exception); - loggedEvents.Add(message); - } - - public bool IsEnabled(LogLevel logLevel) - { - return true; - } - - public IDisposable BeginScope(TState state) - { - return null; - } - } - - public void AddProvider(ILoggerProvider provider) + public IDisposable BeginScope(TState state) { + return null; } } - [TearDown] - public void TearDown() + public void AddProvider(ILoggerProvider provider) { - // loggerFactoryAdapter.LogMessages.Clear(); - - //reset so other tests can produce some output if needed. - loggerFactory.LoggerEvents.Clear(); - LogManager.LoggerFactory = originalFactory; } + } - [Test] - public void ExecuteSpelAction() + [TearDown] + public void TearDown() + { + // loggerFactoryAdapter.LogMessages.Clear(); + + //reset so other tests can produce some output if needed. + loggerFactory.LoggerEvents.Clear(); + LogManager.LoggerFactory = originalFactory; + } + + [Test] + public void ExecuteSpelAction() + { + string executeHandlerText = + "on exception name ArithmeticException execute Spring.Aspects.Exceptions.ExceptionHandlerAspectIntegrationTests.Executed(true)"; + ITestObject to = CreateTestObjectProxy(executeHandlerText); + + try { - string executeHandlerText = - "on exception name ArithmeticException execute Spring.Aspects.Exceptions.ExceptionHandlerAspectIntegrationTests.Executed(true)"; - ITestObject to = CreateTestObjectProxy(executeHandlerText); - - try - { - to.Exceptional(new ArithmeticException()); - } - catch (ArithmeticException) - { - Assert.IsTrue(spelActionExecuted); - } + to.Exceptional(new ArithmeticException()); } - - public static void Executed(bool val) + catch (ArithmeticException) { - spelActionExecuted = val; + Assert.IsTrue(spelActionExecuted); } + } - [Test] - public void LoggingTest() + public static void Executed(bool val) + { + spelActionExecuted = val; + } + + [Test] + public void LoggingTest() + { + LogExceptionHandler logHandler = new LogExceptionHandler(); + logHandler.LogName = "adviceHandler"; + string testText = + @"'Hello World, exception message = ' + #e.Message + ', target method = ' + #method.Name"; + logHandler.SourceExceptionNames.Add("ArithmeticException"); + logHandler.ActionExpressionText = testText; + + exceptionHandlerAdvice.ExceptionHandlers.Add(logHandler); + + exceptionHandlerAdvice.AfterPropertiesSet(); + + ProxyFactory pf = new ProxyFactory(new TestObject()); + pf.AddAdvice(exceptionHandlerAdvice); + ITestObject to = (ITestObject) pf.GetProxy(); + + try { - LogExceptionHandler logHandler = new LogExceptionHandler(); - logHandler.LogName = "adviceHandler"; - string testText = - @"'Hello World, exception message = ' + #e.Message + ', target method = ' + #method.Name"; - logHandler.SourceExceptionNames.Add("ArithmeticException"); - logHandler.ActionExpressionText = testText; - - exceptionHandlerAdvice.ExceptionHandlers.Add(logHandler); - - exceptionHandlerAdvice.AfterPropertiesSet(); - - ProxyFactory pf = new ProxyFactory(new TestObject()); - pf.AddAdvice(exceptionHandlerAdvice); - ITestObject to = (ITestObject)pf.GetProxy(); - - try - { - to.Exceptional(new ArithmeticException()); - Assert.Fail("Should have thrown exception when only logging"); - } - catch (ArithmeticException) - { - bool found = false; - foreach (var loggerEvent in loggerFactory.LoggerEvents) - { - if (loggerEvent.IndexOf("Hello World") >= 0) - { - found = true; - } - } - Assert.IsTrue(found, "did not find logging output"); - } + to.Exceptional(new ArithmeticException()); + Assert.Fail("Should have thrown exception when only logging"); } - - [Test] - public void LoggingTestWithString() - { - string logHandlerText = "on exception name ArithmeticException log 'My Message, Method Name ' + #method.Name"; - - ExecuteLoggingHandler(logHandlerText, "My Message"); - } - - [Test] - public void LoggingTestWithStringExplicitHandler() - { - string logHandlerText = "on exception name ArithmeticException log 'My Message, Method Name ' + #method.Name"; - - ExecuteLoggingHandler(logHandlerText, "My Message"); - } - - [Test] - public void LoggingTestWithConstraintExpression() - { - string logHandlerText = "on exception (#e is T(System.ArithmeticException)) log 'My Message, Method Name ' + #method.Name"; - - ExecuteLoggingHandler(logHandlerText, "My Message"); - } - - [Test] - public void LoggingTestWithConstraintExpressionWithExceptionHandlerInList() - { - LogExceptionHandler exHandler = new LogExceptionHandler(); - exHandler.ConstraintExpressionText = "#e is T(System.ArithmeticException)"; - exHandler.LogName = "adviceHandler"; - exHandler.ActionExpressionText = "#log.Fatal('Request Timeout occured', #e)"; - - ExecuteLoggingHandlerInList(exHandler, "Request Timeout"); - } - - [Test] - public void LoggingTestWithConstraintExpressionWithKeyedExceptionHandler() - { - LogExceptionHandler exHandler = new LogExceptionHandler(); - ExecuteLoggingHandlerWithKeyedLogHandler(exHandler, - @"on exception (#e is T(System.ArithmeticException)) log 'Request Timeout occured'", "Request Timeout"); - } - - [Test] - public void LoggingTestWithBadString() - { - string logHandlerText = "on foobar name ArithmeticException log 'My Message, Method Name ' + #method.Name"; - - Assert.Throws(() => ExecuteLoggingHandler(logHandlerText, "My Message")); - } - - [Test] - public void LoggingTestWithInvalidConstraintExpression() - { - string logHandlerText = "on exception (#e is System.FooBar) log 'My Message, Method Name ' + #method.Name"; - - ExecuteLoggingHandler(logHandlerText, "Was not able to evaluate constraint expression [#e is System.FooBar]"); - - } - - [Test] - public void LoggingTestWithNonBooleanConstraintExpression() - { - string logHandlerText = "on exception (1+1) log 'My Message, Method Name ' + #method.Name"; - - ExecuteLoggingHandler(logHandlerText, "Was not able to unbox constraint expression to boolean [1+1]"); - - } - - private void ExecuteLoggingHandler(string logHandlerText, string searchString) - { - ITestObject to = CreateTestObjectProxy(logHandlerText); - - try - { - to.Exceptional(new ArithmeticException()); - } - catch (ArithmeticException) - { - AssertSearchString(searchString); - } - } - - private void ExecuteLoggingHandlerInList(IExceptionHandler handler, string searchString) - { - ITestObject to = CreateTestObjectProxyInList(handler); - - try - { - to.Exceptional(new ArithmeticException()); - } - catch (ArithmeticException) - { - AssertSearchString(searchString); - } - } - - private void ExecuteLoggingHandlerWithKeyedLogHandler(IExceptionHandler handler, string handlerText, string searchString) - { - ITestObject to = CreateTestObjectProxyWithKeyedHandler(handler, handlerText); - - try - { - to.Exceptional(new ArithmeticException()); - } - catch (ArithmeticException) - { - AssertSearchString(searchString); - } - } - - [Test] - public void TranslationWithString() - { - string translationHandlerText = - "on exception name ArithmeticException translate new System.InvalidOperationException('My Message, Method Name ' + #method.Name, #e)"; - - ITestObject to = CreateTestObjectProxy(translationHandlerText); - AssertTranslation(to); - } - - - [Test] - public void TranslateWithExceptionHandlerInstance() - { - TranslationExceptionHandler exHandler = new TranslationExceptionHandler(); - IList exceptionNames = new ArrayList(); - exceptionNames.Add("ArithmeticException"); - exHandler.SourceExceptionNames = exceptionNames; - exHandler.ActionExpressionText = - "new System.InvalidOperationException('My Message, Method Name ' + #method.Name, #e)"; - ITestObject to = CreateTestObjectProxy(exHandler); - AssertTranslation(to); - } - - private static void AssertTranslation(ITestObject to) - { - try - { - to.Exceptional(new ArithmeticException("Bad Math")); - Assert.Fail("Should have thrown exception"); - } - catch (InvalidOperationException e) - { - Assert.That(e.InnerException, Is.InstanceOf(typeof(ArithmeticException)), "Inner exception."); - Assert.AreEqual("My Message, Method Name Exceptional", e.Message); - } - catch (Exception e) - { - Assert.That(e, Is.InstanceOf(typeof (InvalidOperationException)), "wrong exception type thrown."); - } - } - - [Test] - public void WrapWithString() - { - string translationHandlerText = - "on exception name ArithmeticException wrap System.InvalidOperationException 'My Message'"; - - ITestObject to = CreateTestObjectProxy(translationHandlerText); - try - { - to.Exceptional(new ArithmeticException("Bad Math")); - Assert.Fail("Should have thrown exception"); - } - catch (InvalidOperationException e) - { - Assert.That(e.InnerException, Is.InstanceOf(typeof(ArithmeticException))); - Assert.AreEqual("My Message", e.Message); - } - catch (Exception e) - { - Assert.That(e, Is.InstanceOf(typeof(InvalidOperationException))); - } - } - - [Test] - public void WrapWithStringDefaultMessage() - { - string translationHandlerText = - "on exception name ArithmeticException wrap System.InvalidOperationException"; - - ITestObject to = CreateTestObjectProxy(translationHandlerText); - try - { - to.Exceptional(new ArithmeticException("Bad Math")); - Assert.Fail("Should have thrown exception"); - } - catch (InvalidOperationException e) - { - Assert.AreEqual("Wrapped ArithmeticException", e.Message); - } - catch (Exception e) - { - Assert.That(e, Is.InstanceOf(typeof(InvalidOperationException))); - } - } - - - [Test] - public void ReplaceWithString() - { - string translationHandlerText = - "on exception name ArithmeticException replace System.InvalidOperationException 'My Message'"; - - ITestObject to = CreateTestObjectProxy(translationHandlerText); - try - { - to.Exceptional(new ArithmeticException("Bad Math")); - Assert.Fail("Should have thrown exception"); - } - catch (InvalidOperationException e) - { - Assert.IsNull(e.InnerException); - Assert.AreEqual("My Message", e.Message); - } - catch (Exception e) - { - Assert.That(e, Is.InstanceOf(typeof(InvalidOperationException))); - } - } - - [Test] - public void ReplaceWithStringDefaultMessage() - { - string translationHandlerText = - "on exception name ArithmeticException replace System.InvalidOperationException"; - - ITestObject to = CreateTestObjectProxy(translationHandlerText); - try - { - to.Exceptional(new ArithmeticException("Bad Math")); - Assert.Fail("Should have thrown exception"); - } - catch (InvalidOperationException e) - { - Assert.IsNull(e.InnerException); - Assert.AreEqual("Replaced ArithmeticException", e.Message); - } - catch (Exception e) - { - Assert.That(e, Is.InstanceOf(typeof(InvalidOperationException))); - } - } - - [Test] - public void SwallowWithString() - { - string returnHandlerText = "on exception name ArithmeticException swallow"; - ITestObject to = CreateTestObjectProxy(returnHandlerText); - try - { - to.Exceptional(new ArithmeticException("Bad Math")); - } - catch (Exception e) - { - Assert.Fail("Should not have thrown exception" + e); - } - } - - [Test] - public void SwallowReturnTypeIsValueType() - { - string returnHandlerText = "on exception name ArithmeticException swallow"; - ITestObject to = CreateTestObjectProxy(returnHandlerText); - try - { - to.ExceptionalWithReturnValue(new ArithmeticException("Bad Math")); - } - catch (Exception e) - { - Assert.Fail("Should not have thrown exception. Exception type = " + e.GetType()); - } - } - - - [Test] - public void ReturnWithString() - { - string returnHandlerText = "on exception name ArithmeticException return 12"; - ITestObject to = CreateTestObjectProxy(returnHandlerText); - try - { - int retVal = to.ExceptionalWithReturnValue(new ArithmeticException("Bad Math")); - Assert.AreEqual(12, retVal); - } - catch (Exception) - { - Assert.Fail("Should not have thrown exception"); - } - } - - [Test] - public void ChainLogAndWrap() - { - string logHandlerText = "on exception name ArithmeticException log 'My Message, Method Name ' + #method.Name"; - string translationHandlerText = "on exception name ArithmeticException wrap System.InvalidOperationException 'My Message'"; - exceptionHandlerAdvice.ExceptionHandlers.Add(logHandlerText); - exceptionHandlerAdvice.ExceptionHandlers.Add(translationHandlerText); - exceptionHandlerAdvice.AfterPropertiesSet(); - ProxyFactory pf = new ProxyFactory(new TestObject()); - pf.AddAdvice(exceptionHandlerAdvice); - ITestObject to = (ITestObject)pf.GetProxy(); - try - { - to.Exceptional(new ArithmeticException("Bad Math")); - Assert.Fail("Should have thrown exception"); - } - catch (InvalidOperationException e) - { - Assert.IsNotNull(e.InnerException); - Exception innerEx = e.InnerException; - Assert.AreEqual("My Message", e.Message); - Assert.AreEqual("Bad Math", innerEx.Message); - } - catch (Exception e) - { - Assert.That(e, Is.InstanceOf(typeof(InvalidOperationException))); - } - - - } - - private ITestObject CreateTestObjectProxy(string logHandlerText) - { - exceptionHandlerAdvice.ExceptionHandlers.Add(logHandlerText); - return CreateProxy(); - } - - private ITestObject CreateTestObjectProxy(IExceptionHandler exceptionHander) - { - exceptionHandlerAdvice.ExceptionHandlers.Add(exceptionHander); - return CreateProxy(); - } - - private ITestObject CreateTestObjectProxyInList(IExceptionHandler exceptionHander) - { - exceptionHandlerAdvice.ExceptionHandlers.Add(exceptionHander); - return CreateProxy(); - } - - private ITestObject CreateTestObjectProxyWithKeyedHandler(IExceptionHandler exceptionHander, string handlerText) - { - exceptionHandlerAdvice.ExceptionHandlerDictionary.Add("log", exceptionHander); - exceptionHandlerAdvice.ExceptionHandlers.Add(handlerText); - return CreateProxy(); - } - - private ITestObject CreateProxy() - { - exceptionHandlerAdvice.AfterPropertiesSet(); - ProxyFactory pf = new ProxyFactory(new TestObject()); - pf.AddAdvice(exceptionHandlerAdvice); - return (ITestObject)pf.GetProxy(); - } - - private void AssertSearchString(string searchString) + catch (ArithmeticException) { bool found = false; foreach (var loggerEvent in loggerFactory.LoggerEvents) { - if (loggerEvent.IndexOf(searchString) >= 0) + if (loggerEvent.IndexOf("Hello World") >= 0) { found = true; } } - Assert.IsTrue(found, "did not find logging output [" + searchString + "] Logging values = " - + StringUtils.CollectionToCommaDelimitedString(loggerFactory.LoggerEvents)); + + Assert.IsTrue(found, "did not find logging output"); } } + + [Test] + public void LoggingTestWithString() + { + string logHandlerText = "on exception name ArithmeticException log 'My Message, Method Name ' + #method.Name"; + + ExecuteLoggingHandler(logHandlerText, "My Message"); + } + + [Test] + public void LoggingTestWithStringExplicitHandler() + { + string logHandlerText = "on exception name ArithmeticException log 'My Message, Method Name ' + #method.Name"; + + ExecuteLoggingHandler(logHandlerText, "My Message"); + } + + [Test] + public void LoggingTestWithConstraintExpression() + { + string logHandlerText = "on exception (#e is T(System.ArithmeticException)) log 'My Message, Method Name ' + #method.Name"; + + ExecuteLoggingHandler(logHandlerText, "My Message"); + } + + [Test] + public void LoggingTestWithConstraintExpressionWithExceptionHandlerInList() + { + LogExceptionHandler exHandler = new LogExceptionHandler(); + exHandler.ConstraintExpressionText = "#e is T(System.ArithmeticException)"; + exHandler.LogName = "adviceHandler"; + exHandler.ActionExpressionText = "#log.Fatal('Request Timeout occured', #e)"; + + ExecuteLoggingHandlerInList(exHandler, "Request Timeout"); + } + + [Test] + public void LoggingTestWithConstraintExpressionWithKeyedExceptionHandler() + { + LogExceptionHandler exHandler = new LogExceptionHandler(); + ExecuteLoggingHandlerWithKeyedLogHandler(exHandler, + @"on exception (#e is T(System.ArithmeticException)) log 'Request Timeout occured'", "Request Timeout"); + } + + [Test] + public void LoggingTestWithBadString() + { + string logHandlerText = "on foobar name ArithmeticException log 'My Message, Method Name ' + #method.Name"; + + Assert.Throws(() => ExecuteLoggingHandler(logHandlerText, "My Message")); + } + + [Test] + public void LoggingTestWithInvalidConstraintExpression() + { + string logHandlerText = "on exception (#e is System.FooBar) log 'My Message, Method Name ' + #method.Name"; + + ExecuteLoggingHandler(logHandlerText, "Was not able to evaluate constraint expression [#e is System.FooBar]"); + } + + [Test] + public void LoggingTestWithNonBooleanConstraintExpression() + { + string logHandlerText = "on exception (1+1) log 'My Message, Method Name ' + #method.Name"; + + ExecuteLoggingHandler(logHandlerText, "Was not able to unbox constraint expression to boolean [1+1]"); + } + + private void ExecuteLoggingHandler(string logHandlerText, string searchString) + { + ITestObject to = CreateTestObjectProxy(logHandlerText); + + try + { + to.Exceptional(new ArithmeticException()); + } + catch (ArithmeticException) + { + AssertSearchString(searchString); + } + } + + private void ExecuteLoggingHandlerInList(IExceptionHandler handler, string searchString) + { + ITestObject to = CreateTestObjectProxyInList(handler); + + try + { + to.Exceptional(new ArithmeticException()); + } + catch (ArithmeticException) + { + AssertSearchString(searchString); + } + } + + private void ExecuteLoggingHandlerWithKeyedLogHandler(IExceptionHandler handler, string handlerText, string searchString) + { + ITestObject to = CreateTestObjectProxyWithKeyedHandler(handler, handlerText); + + try + { + to.Exceptional(new ArithmeticException()); + } + catch (ArithmeticException) + { + AssertSearchString(searchString); + } + } + + [Test] + public void TranslationWithString() + { + string translationHandlerText = + "on exception name ArithmeticException translate new System.InvalidOperationException('My Message, Method Name ' + #method.Name, #e)"; + + ITestObject to = CreateTestObjectProxy(translationHandlerText); + AssertTranslation(to); + } + + [Test] + public void TranslateWithExceptionHandlerInstance() + { + TranslationExceptionHandler exHandler = new TranslationExceptionHandler(); + IList exceptionNames = new ArrayList(); + exceptionNames.Add("ArithmeticException"); + exHandler.SourceExceptionNames = exceptionNames; + exHandler.ActionExpressionText = + "new System.InvalidOperationException('My Message, Method Name ' + #method.Name, #e)"; + ITestObject to = CreateTestObjectProxy(exHandler); + AssertTranslation(to); + } + + private static void AssertTranslation(ITestObject to) + { + try + { + to.Exceptional(new ArithmeticException("Bad Math")); + Assert.Fail("Should have thrown exception"); + } + catch (InvalidOperationException e) + { + Assert.That(e.InnerException, Is.InstanceOf(typeof(ArithmeticException)), "Inner exception."); + Assert.AreEqual("My Message, Method Name Exceptional", e.Message); + } + catch (Exception e) + { + Assert.That(e, Is.InstanceOf(typeof(InvalidOperationException)), "wrong exception type thrown."); + } + } + + [Test] + public void WrapWithString() + { + string translationHandlerText = + "on exception name ArithmeticException wrap System.InvalidOperationException 'My Message'"; + + ITestObject to = CreateTestObjectProxy(translationHandlerText); + try + { + to.Exceptional(new ArithmeticException("Bad Math")); + Assert.Fail("Should have thrown exception"); + } + catch (InvalidOperationException e) + { + Assert.That(e.InnerException, Is.InstanceOf(typeof(ArithmeticException))); + Assert.AreEqual("My Message", e.Message); + } + catch (Exception e) + { + Assert.That(e, Is.InstanceOf(typeof(InvalidOperationException))); + } + } + + [Test] + public void WrapWithStringDefaultMessage() + { + string translationHandlerText = + "on exception name ArithmeticException wrap System.InvalidOperationException"; + + ITestObject to = CreateTestObjectProxy(translationHandlerText); + try + { + to.Exceptional(new ArithmeticException("Bad Math")); + Assert.Fail("Should have thrown exception"); + } + catch (InvalidOperationException e) + { + Assert.AreEqual("Wrapped ArithmeticException", e.Message); + } + catch (Exception e) + { + Assert.That(e, Is.InstanceOf(typeof(InvalidOperationException))); + } + } + + [Test] + public void ReplaceWithString() + { + string translationHandlerText = + "on exception name ArithmeticException replace System.InvalidOperationException 'My Message'"; + + ITestObject to = CreateTestObjectProxy(translationHandlerText); + try + { + to.Exceptional(new ArithmeticException("Bad Math")); + Assert.Fail("Should have thrown exception"); + } + catch (InvalidOperationException e) + { + Assert.IsNull(e.InnerException); + Assert.AreEqual("My Message", e.Message); + } + catch (Exception e) + { + Assert.That(e, Is.InstanceOf(typeof(InvalidOperationException))); + } + } + + [Test] + public void ReplaceWithStringDefaultMessage() + { + string translationHandlerText = + "on exception name ArithmeticException replace System.InvalidOperationException"; + + ITestObject to = CreateTestObjectProxy(translationHandlerText); + try + { + to.Exceptional(new ArithmeticException("Bad Math")); + Assert.Fail("Should have thrown exception"); + } + catch (InvalidOperationException e) + { + Assert.IsNull(e.InnerException); + Assert.AreEqual("Replaced ArithmeticException", e.Message); + } + catch (Exception e) + { + Assert.That(e, Is.InstanceOf(typeof(InvalidOperationException))); + } + } + + [Test] + public void SwallowWithString() + { + string returnHandlerText = "on exception name ArithmeticException swallow"; + ITestObject to = CreateTestObjectProxy(returnHandlerText); + try + { + to.Exceptional(new ArithmeticException("Bad Math")); + } + catch (Exception e) + { + Assert.Fail("Should not have thrown exception" + e); + } + } + + [Test] + public void SwallowReturnTypeIsValueType() + { + string returnHandlerText = "on exception name ArithmeticException swallow"; + ITestObject to = CreateTestObjectProxy(returnHandlerText); + try + { + to.ExceptionalWithReturnValue(new ArithmeticException("Bad Math")); + } + catch (Exception e) + { + Assert.Fail("Should not have thrown exception. Exception type = " + e.GetType()); + } + } + + [Test] + public void ReturnWithString() + { + string returnHandlerText = "on exception name ArithmeticException return 12"; + ITestObject to = CreateTestObjectProxy(returnHandlerText); + try + { + int retVal = to.ExceptionalWithReturnValue(new ArithmeticException("Bad Math")); + Assert.AreEqual(12, retVal); + } + catch (Exception) + { + Assert.Fail("Should not have thrown exception"); + } + } + + [Test] + public void ChainLogAndWrap() + { + string logHandlerText = "on exception name ArithmeticException log 'My Message, Method Name ' + #method.Name"; + string translationHandlerText = "on exception name ArithmeticException wrap System.InvalidOperationException 'My Message'"; + exceptionHandlerAdvice.ExceptionHandlers.Add(logHandlerText); + exceptionHandlerAdvice.ExceptionHandlers.Add(translationHandlerText); + exceptionHandlerAdvice.AfterPropertiesSet(); + ProxyFactory pf = new ProxyFactory(new TestObject()); + pf.AddAdvice(exceptionHandlerAdvice); + ITestObject to = (ITestObject) pf.GetProxy(); + try + { + to.Exceptional(new ArithmeticException("Bad Math")); + Assert.Fail("Should have thrown exception"); + } + catch (InvalidOperationException e) + { + Assert.IsNotNull(e.InnerException); + Exception innerEx = e.InnerException; + Assert.AreEqual("My Message", e.Message); + Assert.AreEqual("Bad Math", innerEx.Message); + } + catch (Exception e) + { + Assert.That(e, Is.InstanceOf(typeof(InvalidOperationException))); + } + } + + private ITestObject CreateTestObjectProxy(string logHandlerText) + { + exceptionHandlerAdvice.ExceptionHandlers.Add(logHandlerText); + return CreateProxy(); + } + + private ITestObject CreateTestObjectProxy(IExceptionHandler exceptionHander) + { + exceptionHandlerAdvice.ExceptionHandlers.Add(exceptionHander); + return CreateProxy(); + } + + private ITestObject CreateTestObjectProxyInList(IExceptionHandler exceptionHander) + { + exceptionHandlerAdvice.ExceptionHandlers.Add(exceptionHander); + return CreateProxy(); + } + + private ITestObject CreateTestObjectProxyWithKeyedHandler(IExceptionHandler exceptionHander, string handlerText) + { + exceptionHandlerAdvice.ExceptionHandlerDictionary.Add("log", exceptionHander); + exceptionHandlerAdvice.ExceptionHandlers.Add(handlerText); + return CreateProxy(); + } + + private ITestObject CreateProxy() + { + exceptionHandlerAdvice.AfterPropertiesSet(); + ProxyFactory pf = new ProxyFactory(new TestObject()); + pf.AddAdvice(exceptionHandlerAdvice); + return (ITestObject) pf.GetProxy(); + } + + private void AssertSearchString(string searchString) + { + bool found = false; + foreach (var loggerEvent in loggerFactory.LoggerEvents) + { + if (loggerEvent.IndexOf(searchString) >= 0) + { + found = true; + } + } + + Assert.IsTrue(found, "did not find logging output [" + searchString + "] Logging values = " + + StringUtils.CollectionToCommaDelimitedString(loggerFactory.LoggerEvents)); + } } diff --git a/test/Spring/Spring.Aop.Tests/Aspects/Logging/SimpleLoggingAdviceTests.cs b/test/Spring/Spring.Aop.Tests/Aspects/Logging/SimpleLoggingAdviceTests.cs index 192abf05..450db3fd 100644 --- a/test/Spring/Spring.Aop.Tests/Aspects/Logging/SimpleLoggingAdviceTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aspects/Logging/SimpleLoggingAdviceTests.cs @@ -19,204 +19,202 @@ #endregion using System.Reflection; - using AopAlliance.Intercept; - using FakeItEasy; using FakeItEasy.Configuration; using Microsoft.Extensions.Logging; using NUnit.Framework; using Spring.Aop.Framework; -namespace Spring.Aspects.Logging +namespace Spring.Aspects.Logging; + +/// +/// This class contains tests for SimpleLoggingAdvice +/// +/// Mark Pollack +[TestFixture] +public class SimpleLoggingAdviceTests { - /// - /// This class contains tests for SimpleLoggingAdvice - /// - /// Mark Pollack - [TestFixture] - public class SimpleLoggingAdviceTests + public interface ITestTarget { - public interface ITestTarget + void DoSomething(); + } + + private class TestTarget : ITestTarget + { + public void DoSomething() { - void DoSomething(); - } - - private class TestTarget : ITestTarget - { - public void DoSomething() - { } - } - - [SetUp] - public void Setup() - { - } - - [Test] - public void IntegrationTest() - { - ProxyFactory pf = new ProxyFactory(new TestTarget()); - - ILog log = A.Fake(); - SimpleLoggingAdvice loggingAdvice = new SimpleLoggingAdvice(log); - pf.AddAdvice(loggingAdvice); - - A.CallTo(() => log.IsEnabled(LogLevel.Trace)).Returns(true); - - object proxy = pf.GetProxy(); - ITestTarget ptt = (ITestTarget)proxy; - ptt.DoSomething(); - - log.VerifyLogMustHaveHappened(LogLevel.Trace, "Entering DoSomething"); - log.VerifyLogMustHaveHappened(LogLevel.Trace, "Exiting DoSomething"); - } - - [Test] - public void SunnyDayLoggingCorrectly() - { - ILog log = A.Fake(); - IMethodInvocation methodInvocation = A.Fake(); - - MethodInfo mi = typeof(string).GetMethod("ToString", Type.EmptyTypes); - //two additional calls the method are to retrieve the method name on entry/exit... - A.CallTo(() => methodInvocation.Method).Returns(mi); - A.CallTo(() => log.IsEnabled(LogLevel.Trace)).Returns(true); - A.CallTo(() => methodInvocation.Proceed()).Returns(null); - - TestableSimpleLoggingAdvice loggingAdvice = new TestableSimpleLoggingAdvice(true); - loggingAdvice.CallInvokeUnderLog(methodInvocation, log); - - log.VerifyLogMustHaveHappened(LogLevel.Trace, "Entering ToString"); - log.VerifyLogMustHaveHappened(LogLevel.Trace, "Exiting ToString"); - } - - [Test] - public void SunnyDayLoggingCorrectlyDebugLevel() - { - ILog log = A.Fake(); - IMethodInvocation methodInvocation = A.Fake(); - - MethodInfo mi = typeof(string).GetMethod("ToString", Type.EmptyTypes); - //two additional calls the method are to retrieve the method name on entry/exit... - A.CallTo(() => methodInvocation.Method).Returns(mi); - - A.CallTo(() => log.IsEnabled(LogLevel.Trace)).Returns(false); - A.CallTo(() => log.IsEnabled(LogLevel.Debug)).Returns(true); - - A.CallTo(() => methodInvocation.Proceed()).Returns(null); - - TestableSimpleLoggingAdvice loggingAdvice = new TestableSimpleLoggingAdvice(true); - loggingAdvice.LogLevel = LogLevel.Debug; - Assert.IsTrue(loggingAdvice.CallIsInterceptorEnabled(methodInvocation, log)); - loggingAdvice.CallInvokeUnderLog(methodInvocation, log); - - log.VerifyLogMustHaveHappened(LogLevel.Debug, "Entering ToString"); - log.VerifyLogMustHaveHappened(LogLevel.Debug, "Exiting ToString"); - } - - [Test] - public void ExceptionPathStillLogsCorrectly() - { - ILog log = A.Fake(); - IMethodInvocation methodInvocation = A.Fake(); - - MethodInfo mi = typeof(string).GetMethod("ToString", Type.EmptyTypes); - //two additional calls the method are to retrieve the method name on entry/exit... - A.CallTo(() => methodInvocation.Method).Returns(mi); - A.CallTo(() => log.IsEnabled(LogLevel.Trace)).Returns(true); - - Exception e = new ArgumentException("bad value"); - A.CallTo(() => methodInvocation.Proceed()).Throws(e); - - TestableSimpleLoggingAdvice loggingAdvice = new TestableSimpleLoggingAdvice(true); - try - { - loggingAdvice.CallInvokeUnderLog(methodInvocation, log); - Assert.Fail("Must have propagated the IllegalArgumentException."); - } - catch (ArgumentException) - { - } - - log.VerifyLogMustHaveHappened(LogLevel.Trace, "Entering ToString"); - log.VerifyLogMustHaveHappened(LogLevel.Trace, "Exception thrown in ToString, ToString"); - } - - [Test] - public void SunnyDayLoggingAllOptionalInformationCorrectly() - { - ILog log = A.Fake(); - IMethodInvocation methodInvocation = A.Fake(); - - MethodInfo mi = typeof(Dog).GetMethod("Bark"); - //two additional calls the method are to retrieve the method name on entry/exit... - A.CallTo(() => methodInvocation.Method).Returns(mi); - int[] luckyNumbers = new int[] { 1, 2, 3 }; - object[] args = new object[] { "hello", luckyNumbers }; - - A.CallTo(() => methodInvocation.Arguments).Returns(args); - A.CallTo(() => log.IsEnabled(LogLevel.Trace)).Returns(true); - A.CallTo(() => methodInvocation.Proceed()).Returns(4); - - TestableSimpleLoggingAdvice loggingAdvice = new TestableSimpleLoggingAdvice(true); - loggingAdvice.LogExecutionTime = true; - loggingAdvice.LogMethodArguments = true; - loggingAdvice.LogUniqueIdentifier = true; - - loggingAdvice.CallInvokeUnderLog(methodInvocation, log); - - log.VerifyLogMustHaveHappened(LogLevel.Trace, "Entering Bark"); - log.VerifyLogMustHaveHappened(LogLevel.Trace, "Exiting Bark"); } } - public class Dog + [SetUp] + public void Setup() { - public int Bark(string message, int[] luckyNumbers) - { - return 4; - } } - public static class LoggerExtensions + [Test] + public void IntegrationTest() { - public static void VerifyLogMustHaveHappened(this ILogger logger, LogLevel level, string message) + ProxyFactory pf = new ProxyFactory(new TestTarget()); + + ILog log = A.Fake(); + SimpleLoggingAdvice loggingAdvice = new SimpleLoggingAdvice(log); + pf.AddAdvice(loggingAdvice); + + A.CallTo(() => log.IsEnabled(LogLevel.Trace)).Returns(true); + + object proxy = pf.GetProxy(); + ITestTarget ptt = (ITestTarget) proxy; + ptt.DoSomething(); + + log.VerifyLogMustHaveHappened(LogLevel.Trace, "Entering DoSomething"); + log.VerifyLogMustHaveHappened(LogLevel.Trace, "Exiting DoSomething"); + } + + [Test] + public void SunnyDayLoggingCorrectly() + { + ILog log = A.Fake(); + IMethodInvocation methodInvocation = A.Fake(); + + MethodInfo mi = typeof(string).GetMethod("ToString", Type.EmptyTypes); + //two additional calls the method are to retrieve the method name on entry/exit... + A.CallTo(() => methodInvocation.Method).Returns(mi); + A.CallTo(() => log.IsEnabled(LogLevel.Trace)).Returns(true); + A.CallTo(() => methodInvocation.Proceed()).Returns(null); + + TestableSimpleLoggingAdvice loggingAdvice = new TestableSimpleLoggingAdvice(true); + loggingAdvice.CallInvokeUnderLog(methodInvocation, log); + + log.VerifyLogMustHaveHappened(LogLevel.Trace, "Entering ToString"); + log.VerifyLogMustHaveHappened(LogLevel.Trace, "Exiting ToString"); + } + + [Test] + public void SunnyDayLoggingCorrectlyDebugLevel() + { + ILog log = A.Fake(); + IMethodInvocation methodInvocation = A.Fake(); + + MethodInfo mi = typeof(string).GetMethod("ToString", Type.EmptyTypes); + //two additional calls the method are to retrieve the method name on entry/exit... + A.CallTo(() => methodInvocation.Method).Returns(mi); + + A.CallTo(() => log.IsEnabled(LogLevel.Trace)).Returns(false); + A.CallTo(() => log.IsEnabled(LogLevel.Debug)).Returns(true); + + A.CallTo(() => methodInvocation.Proceed()).Returns(null); + + TestableSimpleLoggingAdvice loggingAdvice = new TestableSimpleLoggingAdvice(true); + loggingAdvice.LogLevel = LogLevel.Debug; + Assert.IsTrue(loggingAdvice.CallIsInterceptorEnabled(methodInvocation, log)); + loggingAdvice.CallInvokeUnderLog(methodInvocation, log); + + log.VerifyLogMustHaveHappened(LogLevel.Debug, "Entering ToString"); + log.VerifyLogMustHaveHappened(LogLevel.Debug, "Exiting ToString"); + } + + [Test] + public void ExceptionPathStillLogsCorrectly() + { + ILog log = A.Fake(); + IMethodInvocation methodInvocation = A.Fake(); + + MethodInfo mi = typeof(string).GetMethod("ToString", Type.EmptyTypes); + //two additional calls the method are to retrieve the method name on entry/exit... + A.CallTo(() => methodInvocation.Method).Returns(mi); + A.CallTo(() => log.IsEnabled(LogLevel.Trace)).Returns(true); + + Exception e = new ArgumentException("bad value"); + A.CallTo(() => methodInvocation.Proceed()).Throws(e); + + TestableSimpleLoggingAdvice loggingAdvice = new TestableSimpleLoggingAdvice(true); + try + { + loggingAdvice.CallInvokeUnderLog(methodInvocation, log); + Assert.Fail("Must have propagated the IllegalArgumentException."); + } + catch (ArgumentException) { - try - { - logger.VerifyLog(level, message) - .MustHaveHappened(); - } - catch (Exception e) - { - throw new ExpectationException($"while verifying a call to log with message: \"{message}\"", e); - } } - public static void VerifyLogMustNotHaveHappened(this ILogger logger, LogLevel level, string message) - { - try - { - logger.VerifyLog(level, message) - .MustNotHaveHappened(); - } - catch (Exception e) - { - throw new ExpectationException($"while verifying a call to log with message: \"{message}\"", e); - } - } + log.VerifyLogMustHaveHappened(LogLevel.Trace, "Entering ToString"); + log.VerifyLogMustHaveHappened(LogLevel.Trace, "Exception thrown in ToString, ToString"); + } - public static IVoidArgumentValidationConfiguration VerifyLog(this ILogger logger, LogLevel level, - string message) - { - return A.CallTo(() => logger.Log( - level, - A._, - A.That.Matches(e => e.ToString().Contains(message)), - A._, - A>._) - ); - } + [Test] + public void SunnyDayLoggingAllOptionalInformationCorrectly() + { + ILog log = A.Fake(); + IMethodInvocation methodInvocation = A.Fake(); + + MethodInfo mi = typeof(Dog).GetMethod("Bark"); + //two additional calls the method are to retrieve the method name on entry/exit... + A.CallTo(() => methodInvocation.Method).Returns(mi); + int[] luckyNumbers = new int[] { 1, 2, 3 }; + object[] args = new object[] { "hello", luckyNumbers }; + + A.CallTo(() => methodInvocation.Arguments).Returns(args); + A.CallTo(() => log.IsEnabled(LogLevel.Trace)).Returns(true); + A.CallTo(() => methodInvocation.Proceed()).Returns(4); + + TestableSimpleLoggingAdvice loggingAdvice = new TestableSimpleLoggingAdvice(true); + loggingAdvice.LogExecutionTime = true; + loggingAdvice.LogMethodArguments = true; + loggingAdvice.LogUniqueIdentifier = true; + + loggingAdvice.CallInvokeUnderLog(methodInvocation, log); + + log.VerifyLogMustHaveHappened(LogLevel.Trace, "Entering Bark"); + log.VerifyLogMustHaveHappened(LogLevel.Trace, "Exiting Bark"); + } +} + +public class Dog +{ + public int Bark(string message, int[] luckyNumbers) + { + return 4; + } +} + +public static class LoggerExtensions +{ + public static void VerifyLogMustHaveHappened(this ILogger logger, LogLevel level, string message) + { + try + { + logger.VerifyLog(level, message) + .MustHaveHappened(); + } + catch (Exception e) + { + throw new ExpectationException($"while verifying a call to log with message: \"{message}\"", e); + } + } + + public static void VerifyLogMustNotHaveHappened(this ILogger logger, LogLevel level, string message) + { + try + { + logger.VerifyLog(level, message) + .MustNotHaveHappened(); + } + catch (Exception e) + { + throw new ExpectationException($"while verifying a call to log with message: \"{message}\"", e); + } + } + + public static IVoidArgumentValidationConfiguration VerifyLog(this ILogger logger, LogLevel level, + string message) + { + return A.CallTo(() => logger.Log( + level, + A._, + A.That.Matches(e => e.ToString().Contains(message)), + A._, + A>._) + ); } } diff --git a/test/Spring/Spring.Aop.Tests/Aspects/Logging/TestableSimpleLoggingAdvice.cs b/test/Spring/Spring.Aop.Tests/Aspects/Logging/TestableSimpleLoggingAdvice.cs index 20d9654d..87fff535 100644 --- a/test/Spring/Spring.Aop.Tests/Aspects/Logging/TestableSimpleLoggingAdvice.cs +++ b/test/Spring/Spring.Aop.Tests/Aspects/Logging/TestableSimpleLoggingAdvice.cs @@ -20,50 +20,49 @@ using AopAlliance.Intercept; -namespace Spring.Aspects.Logging +namespace Spring.Aspects.Logging; + +/// +/// This is simple wrapper to expose the protected methood InvokeUnderLog in the class +/// SimpleLoggingAdvice for testing purposes. +/// +/// Mark Pollack +public class TestableSimpleLoggingAdvice : SimpleLoggingAdvice { /// - /// This is simple wrapper to expose the protected methood InvokeUnderLog in the class - /// SimpleLoggingAdvice for testing purposes. + /// Initializes a new instance of the class. /// - /// Mark Pollack - public class TestableSimpleLoggingAdvice : SimpleLoggingAdvice + /// if set to true [use dynamic logger]. + public TestableSimpleLoggingAdvice(bool useDynamicLogger) : base(useDynamicLogger) { - /// - /// Initializes a new instance of the class. - /// - /// if set to true [use dynamic logger]. - public TestableSimpleLoggingAdvice(bool useDynamicLogger) : base(useDynamicLogger) - { - } + } - /// - /// Initializes a new instance of the class. - /// - public TestableSimpleLoggingAdvice() - { - } + /// + /// Initializes a new instance of the class. + /// + public TestableSimpleLoggingAdvice() + { + } - /// - /// Calls the protected InvokeUnderLog method - /// - /// The invocation. - /// The log. - /// The result of the call to IMethodInvocation.Proceed() - public object CallInvokeUnderLog(IMethodInvocation invocation, ILog log) - { - return InvokeUnderLog(invocation, log); - } + /// + /// Calls the protected InvokeUnderLog method + /// + /// The invocation. + /// The log. + /// The result of the call to IMethodInvocation.Proceed() + public object CallInvokeUnderLog(IMethodInvocation invocation, ILog log) + { + return InvokeUnderLog(invocation, log); + } - /// - /// Calls the IsInterceptorEnabled method. - /// - /// The invocation. - /// The log. - /// The result of the protected method IsInterceptorEnabled - public bool CallIsInterceptorEnabled(IMethodInvocation invocation, ILog log) - { - return IsInterceptorEnabled(invocation, log); - } + /// + /// Calls the IsInterceptorEnabled method. + /// + /// The invocation. + /// The log. + /// The result of the protected method IsInterceptorEnabled + public bool CallIsInterceptorEnabled(IMethodInvocation invocation, ILog log) + { + return IsInterceptorEnabled(invocation, log); } } diff --git a/test/Spring/Spring.Aop.Tests/Aspects/RetryAdviceTests.cs b/test/Spring/Spring.Aop.Tests/Aspects/RetryAdviceTests.cs index 7727ebe1..253ee4e2 100644 --- a/test/Spring/Spring.Aop.Tests/Aspects/RetryAdviceTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aspects/RetryAdviceTests.cs @@ -26,183 +26,181 @@ using Spring.Aop.Framework; #endregion -namespace Spring.Aspects +namespace Spring.Aspects; + +/// +/// This class contains tests for RetryAdvice +/// +/// Mark Pollack +[TestFixture] +public class RetryAdviceTests { - /// - /// This class contains tests for RetryAdvice - /// - /// Mark Pollack - [TestFixture] - public class RetryAdviceTests + [SetUp] + public void Setup() { - [SetUp] - public void Setup() + } + + [Test] + public void TestSunnyDay() + { + InvokeOncePassOnceFail(false, false); + InvokeOncePassOnceFail(false, true); + InvokeOncePassOnceFail(true, false); + InvokeOncePassOnceFail(true, true); + } + + [Test] + public void TestUnexpectedException() + { + InvokeOnceFailWithUnexceptedException(false, false); + } + + private static void InvokeOncePassOnceFail(bool useExceptionName, bool isDelay) + { + TestSleepHandler testSleepHandler = new TestSleepHandler(); + ITestRemoteService rs = GetRemoteService(2, useExceptionName, isDelay, testSleepHandler); + + rs.DoTransfer(); + AssertSleepsAndReset(testSleepHandler, 2, isDelay); + + rs = GetRemoteService(3, useExceptionName, isDelay, testSleepHandler); + try { - } - - [Test] - public void TestSunnyDay() - { - InvokeOncePassOnceFail(false, false); - InvokeOncePassOnceFail(false, true); - InvokeOncePassOnceFail(true, false); - InvokeOncePassOnceFail(true, true); - - } - - [Test] - public void TestUnexpectedException() - { - InvokeOnceFailWithUnexceptedException(false, false); - } - - private static void InvokeOncePassOnceFail(bool useExceptionName, bool isDelay) - { - TestSleepHandler testSleepHandler = new TestSleepHandler(); - ITestRemoteService rs = GetRemoteService(2, useExceptionName, isDelay, testSleepHandler); - rs.DoTransfer(); + Assert.Fail("Should have failed."); + } + catch (ArithmeticException) + { + // they maximum retry count is 3, thus only 2 sleep calls AssertSleepsAndReset(testSleepHandler, 2, isDelay); - - rs = GetRemoteService(3, useExceptionName, isDelay, testSleepHandler); - try - { - rs.DoTransfer(); - Assert.Fail("Should have failed."); - } catch (ArithmeticException) - { - // they maximum retry count is 3, thus only 2 sleep calls - AssertSleepsAndReset(testSleepHandler, 2, isDelay); - } } + } - private static void InvokeOnceFailWithUnexceptedException(bool useExceptionName, bool isDelay) + private static void InvokeOnceFailWithUnexceptedException(bool useExceptionName, bool isDelay) + { + TestSleepHandler testSleepHandler = new TestSleepHandler(); + ITestRemoteService rs = GetRemoteService(3, useExceptionName, isDelay, testSleepHandler); + try { - TestSleepHandler testSleepHandler = new TestSleepHandler(); - ITestRemoteService rs = GetRemoteService(3, useExceptionName, isDelay, testSleepHandler); - try - { - rs.DoTransfer2(); - Assert.Fail("Should have failed."); - } - catch (ArgumentException) - { - - } + rs.DoTransfer2(); + Assert.Fail("Should have failed."); } - - private static void AssertSleepsAndReset(TestSleepHandler testSleepHandler, int numFailures, bool isDelay) + catch (ArgumentException) { - Assert.AreEqual(numFailures, testSleepHandler.CalledTimeSpans.Count); - for(int i=0;i +/// Unit tests for the CacheParameterAdvice class. +/// +/// Aleksandar Seovic +[TestFixture] +public sealed class ParameterValidationAdviceTests { - /// - /// Unit tests for the CacheParameterAdvice class. - /// - /// Aleksandar Seovic - [TestFixture] - public sealed class ParameterValidationAdviceTests + private IApplicationContext mockContext; + private ParameterValidationAdvice advice; + private RequiredValidator requiredValidator; + + [SetUp] + public void SetUp() { - private IApplicationContext mockContext; - private ParameterValidationAdvice advice; - private RequiredValidator requiredValidator; + mockContext = A.Fake(); - [SetUp] - public void SetUp() - { - mockContext = A.Fake(); + advice = new ParameterValidationAdvice(); + advice.ApplicationContext = mockContext; - advice = new ParameterValidationAdvice(); - advice.ApplicationContext = mockContext; - - requiredValidator = new RequiredValidator(); - requiredValidator.Actions.Add(new ErrorMessageAction("error.required", "errors")); - } - - [Test] - public void TestValidArgument() - { - MethodInfo method = typeof(ValidationTarget).GetMethod("Save"); - Inventor inventor = new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian"); - ValidationTarget target = new ValidationTarget(); - object[] args = new object[] {inventor}; - - ExpectValidatorRetrieval("required", requiredValidator); - - advice.Before(method, args, target); - method.Invoke(target, args); - Assert.AreEqual("NIKOLA TESLA", inventor.Name); - } - - [Test] - public void TestInvalidArgument() - { - MethodInfo method = typeof(ValidationTarget).GetMethod("Save"); - - ExpectValidatorRetrieval("required", requiredValidator); - - Assert.Throws(() => advice.Before(method, new object[] {null}, new ValidationTarget())); - } - - private void ExpectValidatorRetrieval(string validatorName, IValidator validator) - { - A.CallTo(() => mockContext.GetObject(validatorName)).Returns(validator).Once(); - } + requiredValidator = new RequiredValidator(); + requiredValidator.Actions.Add(new ErrorMessageAction("error.required", "errors")); } - #region Inner Class : ValidationTarget - - public interface IValidationTarget + [Test] + public void TestValidArgument() { - void Save(Inventor inventor); + MethodInfo method = typeof(ValidationTarget).GetMethod("Save"); + Inventor inventor = new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian"); + ValidationTarget target = new ValidationTarget(); + object[] args = new object[] { inventor }; + + ExpectValidatorRetrieval("required", requiredValidator); + + advice.Before(method, args, target); + method.Invoke(target, args); + Assert.AreEqual("NIKOLA TESLA", inventor.Name); } - public sealed class ValidationTarget : IValidationTarget + [Test] + public void TestInvalidArgument() { - public void Save([Validated("required")] Inventor inventor) - { - inventor.Name = inventor.Name.ToUpper(); - } + MethodInfo method = typeof(ValidationTarget).GetMethod("Save"); + + ExpectValidatorRetrieval("required", requiredValidator); + + Assert.Throws(() => advice.Before(method, new object[] { null }, new ValidationTarget())); } - #endregion + private void ExpectValidatorRetrieval(string validatorName, IValidator validator) + { + A.CallTo(() => mockContext.GetObject(validatorName)).Returns(validator).Once(); + } } + +#region Inner Class : ValidationTarget + +public interface IValidationTarget +{ + void Save(Inventor inventor); +} + +public sealed class ValidationTarget : IValidationTarget +{ + public void Save([Validated("required")] Inventor inventor) + { + inventor.Name = inventor.Name.ToUpper(); + } +} + +#endregion diff --git a/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Framework/AutoProxy/advisorAutoProxyCreator.xml b/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Framework/AutoProxy/advisorAutoProxyCreator.xml index b77334a8..2e6122c4 100644 --- a/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Framework/AutoProxy/advisorAutoProxyCreator.xml +++ b/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Framework/AutoProxy/advisorAutoProxyCreator.xml @@ -1,70 +1,73 @@  - + - - Matches all Advisors in the factory: we don't use a prefix - + + Matches all Advisors in the factory: we don't use a prefix + - + - + - - - - + + + + - - - - + + + + - - Don't set order value: should remain int.MAXVALUE, so it's non-ordered - - + + Don't set order value: should remain int.MAXVALUE, so it's non-ordered + + - - - - - - - - - + - - - - + + + + + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + - - \ No newline at end of file diff --git a/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Framework/AutoProxy/objectNameAutoProxyCreatorTests.xml b/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Framework/AutoProxy/objectNameAutoProxyCreatorTests.xml index 8f36c728..6594c7ea 100644 --- a/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Framework/AutoProxy/objectNameAutoProxyCreatorTests.xml +++ b/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Framework/AutoProxy/objectNameAutoProxyCreatorTests.xml @@ -1,153 +1,155 @@  - + - - - - frozen - - - - - nopInterceptor - - - - - - - - - *Wildcards* - testObject - myTestObj* - *FamilyMember - doubleProxy - - - - - nopInterceptor - - - + + + + frozen + + + + + nopInterceptor + + + + - - - - factoryObject - - - - - nopInterceptor - - - + + + + *Wildcards* + testObject + myTestObj* + *FamilyMember + doubleProxy + + + + + nopInterceptor + + + - - - - doubleProxy - - - - - nopInterceptor - - - + + + + factoryObject + + + + + nopInterceptor + + + - - - - decoratorProx* - - - - - - nopInterceptor - countingBeforeAdvice - - - + + + + doubleProxy + + + + + nopInterceptor + + + - - - - - *introductionUsingDecorator - - - - - introductionNopInterceptor - isModifiedAdvisor - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + decoratorProx* + + + + + + nopInterceptor + countingBeforeAdvice + + + - - - - - - - + + + + *introductionUsingDecorator + + + + + introductionNopInterceptor + isModifiedAdvisor + + + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - \ No newline at end of file diff --git a/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Framework/adapter/withBPPContext.xml b/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Framework/adapter/withBPPContext.xml index ede07cad..8f5b9313 100644 --- a/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Framework/adapter/withBPPContext.xml +++ b/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Framework/adapter/withBPPContext.xml @@ -1,21 +1,29 @@ - - - - - - - - - - testObjectTarget - Spring.Objects.ITestObject - simpleBeforeAdviceAdvisor - - - - - + + + + + + + + + + + + + testObjectTarget + + + Spring.Objects.ITestObject + + + simpleBeforeAdviceAdvisor + + + + + + \ No newline at end of file diff --git a/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Framework/adapter/withoutBPPContext.xml b/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Framework/adapter/withoutBPPContext.xml index 80b5a46a..14138c25 100644 --- a/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Framework/adapter/withoutBPPContext.xml +++ b/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Framework/adapter/withoutBPPContext.xml @@ -1,19 +1,27 @@ - - - - - - - - - - testObjectTarget - Spring.Objects.ITestObject - simpleBeforeAdviceAdvisor - - - - + + + + + + + + + + + + + testObjectTarget + + + Spring.Objects.ITestObject + + + simpleBeforeAdviceAdvisor + + + + + diff --git a/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Framework/innerBeanTarget.xml b/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Framework/innerBeanTarget.xml index 048687b6..5d35c5e1 100644 --- a/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Framework/innerBeanTarget.xml +++ b/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Framework/innerBeanTarget.xml @@ -5,35 +5,37 @@ autowire without ambiguity from target and proxy. --> - + + + + + + + + + + innerObjectTarget + + + + + + nopInterceptor + + + + + - - - - - - - innerObjectTarget - - - - - nopInterceptor - - - - - - \ No newline at end of file diff --git a/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Framework/prototypeTarget.xml b/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Framework/prototypeTarget.xml index 1eb013fb..19b59ab9 100644 --- a/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Framework/prototypeTarget.xml +++ b/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Framework/prototypeTarget.xml @@ -1,44 +1,48 @@ - + - + - + - - testObjectTarget - - - Spring.Aop.Framework.PrototypeTargetTests+TestObject - - - false - - - - testInterceptor - - - + + + testObjectTarget + + + + Spring.Aop.Framework.PrototypeTargetTests+TestObject + + + false + + + + testInterceptor + + + - - testObjectTarget - - Spring.Aop.Framework.PrototypeTargetTests+TestObject - - - true - - - - testInterceptor - - - + + + testObjectTarget + + + Spring.Aop.Framework.PrototypeTargetTests+TestObject + + + true + + + + testInterceptor + + + diff --git a/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Framework/prototypeTests.xml b/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Framework/prototypeTests.xml index 8583e242..87f11c95 100644 --- a/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Framework/prototypeTests.xml +++ b/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Framework/prototypeTests.xml @@ -4,43 +4,56 @@ Tests for independent prototype behaviour. --> - + - - - 10 - - - - 10 - + + + 10 + + + + + + 10 + + + + + + + + + test + + + debugInterceptor + + - - - - - test - debugInterceptor - - - prototypeTarget - debugInterceptor - false - - - - - - Adam - - - --> - \ No newline at end of file diff --git a/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Framework/proxyFactoryDoubleTargetSourceTests.xml b/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Framework/proxyFactoryDoubleTargetSourceTests.xml index e5debf88..e62f5323 100644 --- a/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Framework/proxyFactoryDoubleTargetSourceTests.xml +++ b/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Framework/proxyFactoryDoubleTargetSourceTests.xml @@ -3,54 +3,72 @@ +--> + + + + + + + + Eve + + + + + + + + Adam + + + + + + + + + + + + + + Spring.Objects.ITestObject + + + + adamTargetSource + + + countingBeforeAdvice + + + + + + + + + + + Spring.Objects.ITestObject + + + + adam + + + + + - - - - - - Eve - - - - - - Adam - - - - - - - - - - - - Spring.Objects.ITestObject - - adamTargetSource - countingBeforeAdvice - - - - - - - Spring.Objects.ITestObject - - adam - - - \ No newline at end of file diff --git a/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Framework/proxyFactoryTargetSourceTests.xml b/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Framework/proxyFactoryTargetSourceTests.xml index a9f66538..0711e6c8 100644 --- a/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Framework/proxyFactoryTargetSourceTests.xml +++ b/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Framework/proxyFactoryTargetSourceTests.xml @@ -4,55 +4,59 @@ Tests for independent prototype behaviour. --> - + - - - - - - - - - - - - - + + + + - - - + + + + - - - - - - - - - - - - - - - + - - - Spring.Objects.ITestObject - nopInterceptor,unsupportedInterceptor - + - - - + + + + + + + + + + + + + + + + + + + + + + + + Spring.Objects.ITestObject + + + nopInterceptor,unsupportedInterceptor + + + + + + \ No newline at end of file diff --git a/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Framework/proxyFactoryTests.xml b/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Framework/proxyFactoryTests.xml index cbc06c6c..6975c166 100644 --- a/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Framework/proxyFactoryTests.xml +++ b/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Framework/proxyFactoryTests.xml @@ -1,135 +1,196 @@ - + - - - custom - 666 - - - - - - Spring.Objects.ITestObject - - debugInterceptor - - - - - - Spring.Objects.ITestObject - test - global* - global* - - - - Spring.Objects.ITestObject - false - test - + + + + custom + + + 666 + + - - custom - 666 - - - - - - - - Spring.Objects.ITestObject - false - false - concurrentPrototypeTarget - global* - - - - Spring.Objects.ITestObject - false - test - - - - Spring.Objects.ITestObject - test - pointcutForVoid - - - - - - - - - - - - - - - - Spring.Context.IApplicationEventListener - target2 - debugInterceptor,global* - global* - - - - - - - - - + + + + + Spring.Objects.ITestObject + + + + + + debugInterceptor + + + + + + + + Spring.Objects.ITestObject + + + test + + + global* + + + global* + + + + + + Spring.Objects.ITestObject + + + false + + + test + + + + + + custom + + + 666 + + + + + + + + + + + + Spring.Objects.ITestObject + + + false + + + false + + + concurrentPrototypeTarget + + + global* + + + + + + Spring.Objects.ITestObject + + + false + + + test + + + + + + Spring.Objects.ITestObject + + + test + + + pointcutForVoid + + + + + + + + + + + + + + + + + + Spring.Context.IApplicationEventListener + + + target2 + + + debugInterceptor,global* + + + global* + + + + + + + + + + diff --git a/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Framework/serializationTests.xml b/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Framework/serializationTests.xml index 99b2811c..df4aab0d 100644 --- a/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Framework/serializationTests.xml +++ b/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Framework/serializationTests.xml @@ -4,52 +4,68 @@ Tests for independent prototype behaviour. --> - + - - - - - - - - serializableNopInterceptor - Spring.Objects.Person - - - serializableSingleton - - - - - - - serializablePrototype - + + + + + + + + + serializableNopInterceptor + + + Spring.Objects.Person + + + + + serializableSingleton + + + + + + + + + serializablePrototype + + + + + + serializableNopInterceptor,prototypeTarget + + + Spring.Objects.Person + + + + false + + + + + + + nopInterceptor + + + + + - - serializableNopInterceptor,prototypeTarget - Spring.Objects.Person - - false - - - - - nopInterceptor - - - - - \ No newline at end of file diff --git a/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Framework/throwsAdvice.xml b/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Framework/throwsAdvice.xml index 9bff42cd..26ffa0a4 100644 --- a/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Framework/throwsAdvice.xml +++ b/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Framework/throwsAdvice.xml @@ -4,14 +4,14 @@ --> - - - + + + + type="Spring.Aop.Framework.Adapter.ThrowsAdviceInterceptorTests+MyThrowsHandler" /> - + + value="countingBeforeAdvice,nopInterceptor,throwsAdvice" /> diff --git a/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Support/RegularExpressionSetterTests.xml b/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Support/RegularExpressionSetterTests.xml index 347f0f1b..fe6fd85d 100644 --- a/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Support/RegularExpressionSetterTests.xml +++ b/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Support/RegularExpressionSetterTests.xml @@ -1,57 +1,87 @@ - + + + + + + custom + + + 666 + + + + + + + + + + + + .*Set.* + + + + + + Spring.Objects.IPerson + + + + + + SettersAdvisor + + + + + + Spring.Objects.IPerson + + + + + SerializableSettersAdvised + + + + + SettersAdvisor + + + + + + + + + + + .*Set.* + .*ReturnsThis + + + + + + + Spring.Objects.IPerson + + + + true + + + + + + SettersAndReturnsThisAdvisor + + - - - custom - 666 - - - - - - - - .*Set.* - - - - Spring.Objects.IPerson - - SettersAdvisor - - - - Spring.Objects.IPerson - - - SerializableSettersAdvised - - - SettersAdvisor - - - - - - - - .*Set.* - .*ReturnsThis - - - - - - Spring.Objects.IPerson - - true - - SettersAndReturnsThisAdvisor - - \ No newline at end of file diff --git a/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Target/commonsPoolTests.xml b/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Target/commonsPoolTests.xml index f34d925f..8cd137bc 100644 --- a/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Target/commonsPoolTests.xml +++ b/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Target/commonsPoolTests.xml @@ -1,54 +1,54 @@ - - - 10 - - - - - prototypeTest - - - 25 - - - - - - - - GetPoolingConfigMixin - - - - - - - - - - nop - - - - - - - - - - - - - poolConfigAdvisor - - - - true - - + + + 10 + + + + + prototypeTest + + + 25 + + + + + + + + GetPoolingConfigMixin + + + + + + + + + + nop + + + + + + + + + + + + + poolConfigAdvisor + + + + true + + diff --git a/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Target/hotSwapTests.xml b/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Target/hotSwapTests.xml index 3e3a2b35..37f4ab36 100644 --- a/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Target/hotSwapTests.xml +++ b/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Target/hotSwapTests.xml @@ -1,19 +1,19 @@ - - - - - - - - - - - - - - + + + + + + + + + + + + + + diff --git a/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Target/prototypeTargetSourceTests.xml b/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Target/prototypeTargetSourceTests.xml index 6ffa6d5e..b867871d 100644 --- a/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Target/prototypeTargetSourceTests.xml +++ b/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Target/prototypeTargetSourceTests.xml @@ -6,36 +6,54 @@ - - - 10 - - - - 10 - - - - prototypeTest - - - - - - test - debugInterceptor - - + + + + 10 + + + + + + 10 + + + + + + prototypeTest + + + + + + + + test + + + debugInterceptor + + + - - debugInterceptor - - - - prototypeTest - debugInterceptor - - + + + + + debugInterceptor + + + + + + prototypeTest + + + debugInterceptor + + + \ No newline at end of file diff --git a/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Target/simplePoolTests.xml b/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Target/simplePoolTests.xml index 94253981..c33f3780 100644 --- a/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Target/simplePoolTests.xml +++ b/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Target/simplePoolTests.xml @@ -1,54 +1,54 @@ - - - 10 - - - - - prototypeTest - - - 25 - - - - - - - - GetPoolingConfigMixin - - - - - - - - - - nop - - - - - - - - - - - - - poolConfigAdvisor - - - - true - - + + + 10 + + + + + prototypeTest + + + 25 + + + + + + + + GetPoolingConfigMixin + + + + + + + + + + nop + + + + + + + + + + + + + poolConfigAdvisor + + + + true + + diff --git a/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Target/threadLocalTests.xml b/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Target/threadLocalTests.xml index ff1e1147..83bff34a 100644 --- a/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Target/threadLocalTests.xml +++ b/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Target/threadLocalTests.xml @@ -1,81 +1,81 @@ - - - 10 - - - - - prototypeTest - - - - - - - - - - GetStatsMixin - - - - - - - statsAdvisor - - - debugInterceptor - - - - - - - true - - - - - - Kerry - - - - - Rod - - - - - - - - test - - - - - - - + + + 10 + + + + + prototypeTest + + + + + + + + + + GetStatsMixin + + + + + + + statsAdvisor + + + debugInterceptor + + + + + + + true + + + + + + Kerry + + + + + Rod + + + + + + + + test + + + + + + + - - - - - - - - + + + + + + + + diff --git a/test/Spring/Spring.Benchmark/Classes/Singleton.cs b/test/Spring/Spring.Benchmark/Classes/Singleton.cs index 73884bb1..638f78b6 100644 --- a/test/Spring/Spring.Benchmark/Classes/Singleton.cs +++ b/test/Spring/Spring.Benchmark/Classes/Singleton.cs @@ -1,80 +1,79 @@ -namespace Spring.Benchmark.Classes +namespace Spring.Benchmark.Classes; + +public interface ISingleton1 { - public interface ISingleton1 + void DoSomething(); +} + +public interface ISingleton2 +{ + void DoSomething(); +} + +public interface ISingleton3 +{ + void DoSomething(); +} + +public class Singleton1 : ISingleton1 +{ + private static int counter; + + public Singleton1() { - void DoSomething(); + System.Threading.Interlocked.Increment(ref counter); } - public interface ISingleton2 + public static int Instances { - void DoSomething(); + get { return counter; } + set { counter = value; } } - public interface ISingleton3 + public void DoSomething() { - void DoSomething(); - } - - public class Singleton1 : ISingleton1 - { - private static int counter; - - public Singleton1() - { - System.Threading.Interlocked.Increment(ref counter); - } - - public static int Instances - { - get { return counter; } - set { counter = value; } - } - - public void DoSomething() - { - Console.WriteLine("Hello"); - } - } - - public class Singleton2 : ISingleton2 - { - private static int counter; - - public Singleton2() - { - System.Threading.Interlocked.Increment(ref counter); - } - - public static int Instances - { - get { return counter; } - set { counter = value; } - } - - public void DoSomething() - { - Console.WriteLine("Hello"); - } - } - - public class Singleton3 : ISingleton3 - { - private static int counter; - - public Singleton3() - { - System.Threading.Interlocked.Increment(ref counter); - } - - public static int Instances - { - get { return counter; } - set { counter = value; } - } - - public void DoSomething() - { - Console.WriteLine("Hello"); - } + Console.WriteLine("Hello"); + } +} + +public class Singleton2 : ISingleton2 +{ + private static int counter; + + public Singleton2() + { + System.Threading.Interlocked.Increment(ref counter); + } + + public static int Instances + { + get { return counter; } + set { counter = value; } + } + + public void DoSomething() + { + Console.WriteLine("Hello"); + } +} + +public class Singleton3 : ISingleton3 +{ + private static int counter; + + public Singleton3() + { + System.Threading.Interlocked.Increment(ref counter); + } + + public static int Instances + { + get { return counter; } + set { counter = value; } + } + + public void DoSomething() + { + Console.WriteLine("Hello"); } } diff --git a/test/Spring/Spring.Benchmark/Classes/Transient.cs b/test/Spring/Spring.Benchmark/Classes/Transient.cs index 743ffffc..740152d5 100644 --- a/test/Spring/Spring.Benchmark/Classes/Transient.cs +++ b/test/Spring/Spring.Benchmark/Classes/Transient.cs @@ -1,80 +1,79 @@ -namespace Spring.Benchmark.Classes +namespace Spring.Benchmark.Classes; + +public interface ITransient1 { - public interface ITransient1 + void DoSomething(); +} + +public interface ITransient2 +{ + void DoSomething(); +} + +public interface ITransient3 +{ + void DoSomething(); +} + +public class Transient1 : ITransient1 +{ + private static int counter; + + public Transient1() { - void DoSomething(); + System.Threading.Interlocked.Increment(ref counter); } - public interface ITransient2 + public static int Instances { - void DoSomething(); + get { return counter; } + set { counter = value; } } - public interface ITransient3 + public void DoSomething() { - void DoSomething(); - } - - public class Transient1 : ITransient1 - { - private static int counter; - - public Transient1() - { - System.Threading.Interlocked.Increment(ref counter); - } - - public static int Instances - { - get { return counter; } - set { counter = value; } - } - - public void DoSomething() - { - Console.WriteLine("World"); - } - } - - public class Transient2 : ITransient2 - { - private static int counter; - - public Transient2() - { - System.Threading.Interlocked.Increment(ref counter); - } - - public static int Instances - { - get { return counter; } - set { counter = value; } - } - - public void DoSomething() - { - Console.WriteLine("World"); - } - } - - public class Transient3 : ITransient3 - { - private static int counter; - - public Transient3() - { - System.Threading.Interlocked.Increment(ref counter); - } - - public static int Instances - { - get { return counter; } - set { counter = value; } - } - - public void DoSomething() - { - Console.WriteLine("World"); - } + Console.WriteLine("World"); + } +} + +public class Transient2 : ITransient2 +{ + private static int counter; + + public Transient2() + { + System.Threading.Interlocked.Increment(ref counter); + } + + public static int Instances + { + get { return counter; } + set { counter = value; } + } + + public void DoSomething() + { + Console.WriteLine("World"); + } +} + +public class Transient3 : ITransient3 +{ + private static int counter; + + public Transient3() + { + System.Threading.Interlocked.Increment(ref counter); + } + + public static int Instances + { + get { return counter; } + set { counter = value; } + } + + public void DoSomething() + { + Console.WriteLine("World"); } } diff --git a/test/Spring/Spring.Benchmark/ContainerBenchmark.cs b/test/Spring/Spring.Benchmark/ContainerBenchmark.cs index 3c750836..89a93767 100644 --- a/test/Spring/Spring.Benchmark/ContainerBenchmark.cs +++ b/test/Spring/Spring.Benchmark/ContainerBenchmark.cs @@ -22,52 +22,50 @@ using BenchmarkDotNet.Attributes; using Spring.Benchmark.Classes; using Spring.Context.Support; -namespace Spring.Benchmark +namespace Spring.Benchmark; + +[ClrJob, CoreJob] +[MemoryDiagnoser] +public class ContainerBenchmark { - [ClrJob, CoreJob] - [MemoryDiagnoser] - public class ContainerBenchmark + private XmlApplicationContext container; + + [Params(5_000)] public int Iterations { get; set; } + + [GlobalSetup] + public void GlobalSetup() { - private XmlApplicationContext container; + container = new XmlApplicationContext("ContainerBenchmark.xml"); + container.Refresh(); + } - [Params(5_000)] - public int Iterations { get; set; } - - [GlobalSetup] - public void GlobalSetup() + [Benchmark] + public bool ResolveTransient() + { + bool ok = true; + for (int i = 0; i < Iterations; i++) { - container = new XmlApplicationContext("ContainerBenchmark.xml"); - container.Refresh(); + var transient1 = (ITransient1) container.GetObject(typeof(ITransient1).FullName); + var transient2 = (ITransient2) container.GetObject(typeof(ITransient2).FullName); + var transient3 = (ITransient3) container.GetObject(typeof(ITransient3).FullName); + ok &= transient1 != null && transient2 != null && transient3 != null; } - [Benchmark] - public bool ResolveTransient() - { - bool ok = true; - for (int i = 0; i < Iterations; i++) - { - var transient1 = (ITransient1) container.GetObject(typeof(ITransient1).FullName); - var transient2 = (ITransient2) container.GetObject(typeof(ITransient2).FullName); - var transient3 = (ITransient3) container.GetObject(typeof(ITransient3).FullName); - ok &= transient1 != null && transient2 != null && transient3 != null; - } + return ok; + } - return ok; - } - - [Benchmark] - public bool ResolveSingleton() + [Benchmark] + public bool ResolveSingleton() + { + bool ok = true; + for (int i = 0; i < Iterations; i++) { - bool ok = true; - for (int i = 0; i < Iterations; i++) - { - var transient1 = (ISingleton1) container.GetObject(typeof(ISingleton1).FullName); - var transient2 = (ISingleton2) container.GetObject(typeof(ISingleton2).FullName); - var transient3 = (ISingleton3) container.GetObject(typeof(ISingleton3).FullName); - ok &= transient1 != null && transient2 != null && transient3 != null; - } - - return ok; + var transient1 = (ISingleton1) container.GetObject(typeof(ISingleton1).FullName); + var transient2 = (ISingleton2) container.GetObject(typeof(ISingleton2).FullName); + var transient3 = (ISingleton3) container.GetObject(typeof(ISingleton3).FullName); + ok &= transient1 != null && transient2 != null && transient3 != null; } + + return ok; } } diff --git a/test/Spring/Spring.Benchmark/ContainerBenchmark.xml b/test/Spring/Spring.Benchmark/ContainerBenchmark.xml index 53c4cb39..2fa19651 100644 --- a/test/Spring/Spring.Benchmark/ContainerBenchmark.xml +++ b/test/Spring/Spring.Benchmark/ContainerBenchmark.xml @@ -4,11 +4,17 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.net http://www.springframework.net/xsd/spring-objects.xsd"> - - - - - - + + + + + + diff --git a/test/Spring/Spring.Benchmark/HybridSetBenchmark.cs b/test/Spring/Spring.Benchmark/HybridSetBenchmark.cs index 48be0462..a03d3c29 100644 --- a/test/Spring/Spring.Benchmark/HybridSetBenchmark.cs +++ b/test/Spring/Spring.Benchmark/HybridSetBenchmark.cs @@ -1,4 +1,5 @@ #region License + // /* // * Copyright 2018 the original author or authors. // * @@ -14,72 +15,71 @@ // * See the License for the specific language governing permissions and // * limitations under the License. // */ + #endregion using BenchmarkDotNet.Attributes; using Spring.Collections; using Spring.Objects.Factory.Support; -namespace Spring.Benchmark -{ - [ClrJob, CoreJob] - [MemoryDiagnoser] - public class HybridSetBenchmark - { - private HashedSet hashedSet; - private HashSet hashSet; - private HybridSet hybridSet; - private MethodOverrides[] items; - - [GlobalSetup] - public void GlobalSetup() - { - items = new MethodOverrides[100]; - for (int i = 0; i < items.Length; i++) - { - items[i] = new MethodOverrides(); - } - } - - [IterationSetup] - public void Setup() - { - hashSet = new HashSet(); - hybridSet = new HybridSet(); - hashedSet = new HashedSet(); - } +namespace Spring.Benchmark; - [Params(1, 5, 10, 20)] - public int Iterations { get; set; } - - [Benchmark] - public void AddHashSet() +[ClrJob, CoreJob] +[MemoryDiagnoser] +public class HybridSetBenchmark +{ + private HashedSet hashedSet; + private HashSet hashSet; + private HybridSet hybridSet; + private MethodOverrides[] items; + + [GlobalSetup] + public void GlobalSetup() + { + items = new MethodOverrides[100]; + for (int i = 0; i < items.Length; i++) { - int iterations = Iterations; - for (int i = 0; i < iterations; ++i) - { - hashSet.Add(items[i]); - } - } - - [Benchmark] - public void AddHashedSet() + items[i] = new MethodOverrides(); + } + } + + [IterationSetup] + public void Setup() + { + hashSet = new HashSet(); + hybridSet = new HybridSet(); + hashedSet = new HashedSet(); + } + + [Params(1, 5, 10, 20)] public int Iterations { get; set; } + + [Benchmark] + public void AddHashSet() + { + int iterations = Iterations; + for (int i = 0; i < iterations; ++i) { - int iterations = Iterations; - for (int i = 0; i < iterations; ++i) - { - hashedSet.Add(items[i]); - } - } - - [Benchmark] - public void AddHybridSet() + hashSet.Add(items[i]); + } + } + + [Benchmark] + public void AddHashedSet() + { + int iterations = Iterations; + for (int i = 0; i < iterations; ++i) { - int iterations = Iterations; - for (int i = 0; i < iterations; ++i) - { - hybridSet.Add(items[i]); - } + hashedSet.Add(items[i]); + } + } + + [Benchmark] + public void AddHybridSet() + { + int iterations = Iterations; + for (int i = 0; i < iterations; ++i) + { + hybridSet.Add(items[i]); } } } diff --git a/test/Spring/Spring.Benchmark/Program.cs b/test/Spring/Spring.Benchmark/Program.cs index 892eb9cf..2726d8eb 100644 --- a/test/Spring/Spring.Benchmark/Program.cs +++ b/test/Spring/Spring.Benchmark/Program.cs @@ -1,12 +1,11 @@ using BenchmarkDotNet.Running; -namespace Spring.Benchmark +namespace Spring.Benchmark; + +public static class Program { - public static class Program + public static void Main(string[] args) { - public static void Main(string[] args) - { - BenchmarkSwitcher.FromAssembly(typeof(HybridSetBenchmark).Assembly).Run(args); - } + BenchmarkSwitcher.FromAssembly(typeof(HybridSetBenchmark).Assembly).Run(args); } -} \ No newline at end of file +} diff --git a/test/Spring/Spring.Benchmark/Spring.Benchmark.csproj b/test/Spring/Spring.Benchmark/Spring.Benchmark.csproj index 5c2feab6..2175320a 100644 --- a/test/Spring/Spring.Benchmark/Spring.Benchmark.csproj +++ b/test/Spring/Spring.Benchmark/Spring.Benchmark.csproj @@ -1,23 +1,23 @@ - - Exe - net472;net8.0 - Spring.Benchmark - + + Exe + net472;net8.0 + Spring.Benchmark + - - - + + + - - - + + + - - - PreserveNewest - - + + + PreserveNewest + + diff --git a/test/Spring/Spring.Core.Tests/App.config b/test/Spring/Spring.Core.Tests/App.config index b97cb179..7cffd8a8 100644 --- a/test/Spring/Spring.Core.Tests/App.config +++ b/test/Spring/Spring.Core.Tests/App.config @@ -20,28 +20,32 @@ limitations under the License.
-
-
+
+
- -
+ +
-
+
- -
-
- +
+ +
+ -
- +
+ -
-
+
+
@@ -51,8 +55,8 @@ limitations under the License. -
-
+
+
@@ -64,17 +68,17 @@ limitations under the License. - - + + - + - + @@ -85,30 +89,30 @@ limitations under the License. - + - + schemaLocation="assembly://Spring.Core.Tests/Spring.Context.Support/testobject.xsd" /> - + type='Spring.Context.Support.XmlApplicationContext, Spring.Core' + name='Parent'> + - + - + 12 @@ -121,7 +125,7 @@ limitations under the License. - + @@ -131,15 +135,15 @@ limitations under the License. - + type='Spring.Context.Support.XmlApplicationContext, Spring.Core' + name='Parent'> + - + - + @@ -147,7 +151,7 @@ limitations under the License. - + @@ -155,7 +159,7 @@ limitations under the License. - + @@ -164,22 +168,23 @@ limitations under the License. - + - + - + - + Provider=Microsoft.Jet.OLEDB.4.0; Data Source=c:\Northwind.mdb;User ID=Admin;Password=; @@ -190,8 +195,9 @@ limitations under the License. - - + + @@ -220,12 +226,12 @@ limitations under the License.
- - + + - + diff --git a/test/Spring/Spring.Core.Tests/AssemblyInfo.cs b/test/Spring/Spring.Core.Tests/AssemblyInfo.cs index 1be18a23..d3c3ab80 100644 --- a/test/Spring/Spring.Core.Tests/AssemblyInfo.cs +++ b/test/Spring/Spring.Core.Tests/AssemblyInfo.cs @@ -1,5 +1,5 @@ using System.Reflection; -[assembly: System.Security.SecurityRules(System.Security.SecurityRuleSet.Level1)] +[assembly: System.Security.SecurityRules(System.Security.SecurityRuleSet.Level1)] [assembly: AssemblyTitle("Spring.Core Tests")] [assembly: AssemblyDescription("Unit tests for Spring.Core assembly")] diff --git a/test/Spring/Spring.Core.Tests/Caching/AbstractCacheTests.cs b/test/Spring/Spring.Core.Tests/Caching/AbstractCacheTests.cs index abc8d682..fcbdda55 100644 --- a/test/Spring/Spring.Core.Tests/Caching/AbstractCacheTests.cs +++ b/test/Spring/Spring.Core.Tests/Caching/AbstractCacheTests.cs @@ -19,137 +19,135 @@ #endregion using FakeItEasy; - using NUnit.Framework; -namespace Spring.Caching +namespace Spring.Caching; + +/// +/// Tests behaviour to ensure, +/// that derived classes maybe rely on this default behaviour +/// +/// Erich Eichinger +[TestFixture] +public class AbstractCacheTests { + #region ExposingAbstractCache utility class + /// - /// Tests behaviour to ensure, - /// that derived classes maybe rely on this default behaviour + /// Exposes DoInsert() method for testing /// - /// Erich Eichinger - [TestFixture] - public class AbstractCacheTests + public abstract class ExposingAbstractCache : AbstractCache { - #region ExposingAbstractCache utility class - - /// - /// Exposes DoInsert() method for testing - /// - public abstract class ExposingAbstractCache : AbstractCache + protected override void DoInsert(object key, object value, TimeSpan timeToLive) { - protected override void DoInsert(object key, object value, TimeSpan timeToLive) - { - DoInsertExposed(key, value, timeToLive); - } - - public abstract void DoInsertExposed(object key, object value, TimeSpan timeToLive); + DoInsertExposed(key, value, timeToLive); } - #endregion + public abstract void DoInsertExposed(object key, object value, TimeSpan timeToLive); + } - TimeSpan expectedPerItemTTL; - TimeSpan expectedPerCacheTTL; - ExposingAbstractCache cache; - string[] KEYS = new string[] {"keyA", "keyB"}; + #endregion - [SetUp] - public void SetUp() - { - cache = A.Fake(options => options.CallsBaseMethods()); + TimeSpan expectedPerItemTTL; + TimeSpan expectedPerCacheTTL; + ExposingAbstractCache cache; + string[] KEYS = new string[] { "keyA", "keyB" }; - expectedPerItemTTL = new TimeSpan(0, 0, 10); - expectedPerCacheTTL = new TimeSpan(0, 0, 20); + [SetUp] + public void SetUp() + { + cache = A.Fake(options => options.CallsBaseMethods()); - cache.TimeToLive = expectedPerCacheTTL; - } + expectedPerItemTTL = new TimeSpan(0, 0, 10); + expectedPerCacheTTL = new TimeSpan(0, 0, 20); - [Test] - public void TestDefaults() - { - ExposingAbstractCache localCache = A.Fake(); - Assert.AreEqual(TimeSpan.Zero, localCache.TimeToLive); - Assert.AreEqual(false, localCache.EnforceTimeToLive); - } + cache.TimeToLive = expectedPerCacheTTL; + } - [Test] - public void AppliesPerCacheDefaultsIfNoPerItemValuesGiven() - { - // set expectations - cache.DoInsertExposed("key", "value", expectedPerCacheTTL); - cache.Insert("key", "value", expectedPerCacheTTL); - A.CallTo(() => cache.DoInsertExposed("key", "value", expectedPerCacheTTL)).MustHaveHappened(); - } + [Test] + public void TestDefaults() + { + ExposingAbstractCache localCache = A.Fake(); + Assert.AreEqual(TimeSpan.Zero, localCache.TimeToLive); + Assert.AreEqual(false, localCache.EnforceTimeToLive); + } - [Test] - public void AppliesPerCacheDefaultsIfTTLLessThanZero() - { - cache.Insert("key", "value", new TimeSpan(Timeout.Infinite)); - A.CallTo(() => cache.DoInsertExposed("key", "value", expectedPerCacheTTL)).MustHaveHappened(); + [Test] + public void AppliesPerCacheDefaultsIfNoPerItemValuesGiven() + { + // set expectations + cache.DoInsertExposed("key", "value", expectedPerCacheTTL); + cache.Insert("key", "value", expectedPerCacheTTL); + A.CallTo(() => cache.DoInsertExposed("key", "value", expectedPerCacheTTL)).MustHaveHappened(); + } - cache.Insert("key", "value", new TimeSpan(-1)); - A.CallTo(() => cache.DoInsertExposed("key", "value", expectedPerCacheTTL)).MustHaveHappened(); + [Test] + public void AppliesPerCacheDefaultsIfTTLLessThanZero() + { + cache.Insert("key", "value", new TimeSpan(Timeout.Infinite)); + A.CallTo(() => cache.DoInsertExposed("key", "value", expectedPerCacheTTL)).MustHaveHappened(); - cache.Insert("key", "value", new TimeSpan(long.MinValue)); - A.CallTo(() => cache.DoInsertExposed("key", "value", expectedPerCacheTTL)).MustHaveHappened(); + cache.Insert("key", "value", new TimeSpan(-1)); + A.CallTo(() => cache.DoInsertExposed("key", "value", expectedPerCacheTTL)).MustHaveHappened(); - cache.Insert("key", "value", TimeSpan.MinValue); - A.CallTo(() => cache.DoInsertExposed("key", "value", expectedPerCacheTTL)).MustHaveHappened(); - } + cache.Insert("key", "value", new TimeSpan(long.MinValue)); + A.CallTo(() => cache.DoInsertExposed("key", "value", expectedPerCacheTTL)).MustHaveHappened(); - [Test] - public void AppliesPerCacheDefaultsIfEnfored() - { - cache.EnforceTimeToLive = true; - cache.Insert("key", "value", expectedPerItemTTL); + cache.Insert("key", "value", TimeSpan.MinValue); + A.CallTo(() => cache.DoInsertExposed("key", "value", expectedPerCacheTTL)).MustHaveHappened(); + } - A.CallTo(() => cache.DoInsertExposed("key", "value", expectedPerCacheTTL)).MustHaveHappened(); - } + [Test] + public void AppliesPerCacheDefaultsIfEnfored() + { + cache.EnforceTimeToLive = true; + cache.Insert("key", "value", expectedPerItemTTL); - [Test] - public void AppliesZeroTTLIfTTLIsZero() - { - cache.Insert("key", "value", TimeSpan.Zero); + A.CallTo(() => cache.DoInsertExposed("key", "value", expectedPerCacheTTL)).MustHaveHappened(); + } - A.CallTo(() => cache.DoInsertExposed("key", "value", TimeSpan.Zero)).MustHaveHappened(); - } + [Test] + public void AppliesZeroTTLIfTTLIsZero() + { + cache.Insert("key", "value", TimeSpan.Zero); - [Test] - public void AppliesPerItemTTLIfTTLGreaterZero() - { - cache.Insert("key", "value", expectedPerItemTTL); + A.CallTo(() => cache.DoInsertExposed("key", "value", TimeSpan.Zero)).MustHaveHappened(); + } - A.CallTo(() => cache.DoInsertExposed("key", "value", expectedPerItemTTL)).MustHaveHappened(); - } + [Test] + public void AppliesPerItemTTLIfTTLGreaterZero() + { + cache.Insert("key", "value", expectedPerItemTTL); - [Test] - public void RemoveAllCausesCallsToRemove() - { - cache.RemoveAll(KEYS); + A.CallTo(() => cache.DoInsertExposed("key", "value", expectedPerItemTTL)).MustHaveHappened(); + } - A.CallTo(() => cache.Remove(KEYS[0])).MustHaveHappened(); - A.CallTo(() => cache.Remove(KEYS[1])).MustHaveHappened(); - } + [Test] + public void RemoveAllCausesCallsToRemove() + { + cache.RemoveAll(KEYS); - [Test] - public void ClearCausesCallToRemoveAllUsingKeys() - { - A.CallTo(() => cache.Keys).Returns(this.KEYS); + A.CallTo(() => cache.Remove(KEYS[0])).MustHaveHappened(); + A.CallTo(() => cache.Remove(KEYS[1])).MustHaveHappened(); + } - cache.Clear(); + [Test] + public void ClearCausesCallToRemoveAllUsingKeys() + { + A.CallTo(() => cache.Keys).Returns(this.KEYS); - A.CallTo(() => cache.Keys).MustHaveHappened(); - A.CallTo(() => cache.RemoveAll(KEYS)).MustHaveHappened(); - } + cache.Clear(); - [Test] - public void CountUsingKeys() - { - // set expectations - A.CallTo(() => cache.Keys).Returns(this.KEYS); + A.CallTo(() => cache.Keys).MustHaveHappened(); + A.CallTo(() => cache.RemoveAll(KEYS)).MustHaveHappened(); + } - Assert.AreEqual(this.KEYS.Length, cache.Count); - } + [Test] + public void CountUsingKeys() + { + // set expectations + A.CallTo(() => cache.Keys).Returns(this.KEYS); + + Assert.AreEqual(this.KEYS.Length, cache.Count); } } \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/Caching/BaseCacheAttributeTests.cs b/test/Spring/Spring.Core.Tests/Caching/BaseCacheAttributeTests.cs index 29a21134..450a8f66 100644 --- a/test/Spring/Spring.Core.Tests/Caching/BaseCacheAttributeTests.cs +++ b/test/Spring/Spring.Core.Tests/Caching/BaseCacheAttributeTests.cs @@ -24,82 +24,79 @@ using NUnit.Framework; #endregion -namespace Spring.Caching +namespace Spring.Caching; + +/// +/// +/// +/// Erich Eichinger +[TestFixture] +public class BaseCacheAttributeTests { - /// - /// - /// - /// Erich Eichinger - [TestFixture] - public class BaseCacheAttributeTests + private BaseCacheAttribute att; + + private class DerivedCacheAttribute : BaseCacheAttribute { - private BaseCacheAttribute att; - - private class DerivedCacheAttribute : BaseCacheAttribute + public DerivedCacheAttribute() { - public DerivedCacheAttribute() - { - - } - - public DerivedCacheAttribute(string cacheName, string key) - : base(cacheName, key) - { - - } } - public string TestProperty + public DerivedCacheAttribute(string cacheName, string key) + : base(cacheName, key) { - get { return "OK"; } - } - - [SetUp] - public void SetUp() - { - att = new DerivedCacheAttribute(); - } - - [Test] - public void CacheNameIsSet() - { - att.CacheName = "MyCache"; - Assert.AreEqual("MyCache", att.CacheName); - } - - [Test] - public void KeyIsParsed() - { - att.Key = "TestProperty"; - string result = att.KeyExpression.GetValue(this) as string; - Assert.AreEqual("OK", result); - } - - [Test] - public void ConditionIsParsed() - { - att.Condition = "TestProperty"; - string result = att.ConditionExpression.GetValue(this) as string; - Assert.AreEqual("OK", result); - } - - [Test] - public void AllowsForExtendedTimeSpanConverterSyntax() - { - att.TimeToLive = "5ms"; - Assert.AreEqual(new TimeSpan(0, 0, 0, 0, 5), att.TimeToLiveTimeSpan); - } - - [Test] - public void KeyCannotBeEmptyString() - { - Assert.Throws(() => att = new DerivedCacheAttribute("someName", string.Empty)); - } - - [Test] - public void KeyCannotBeNull() - { - Assert.Throws(() => att = new DerivedCacheAttribute("someName", null)); } } -} \ No newline at end of file + + public string TestProperty + { + get { return "OK"; } + } + + [SetUp] + public void SetUp() + { + att = new DerivedCacheAttribute(); + } + + [Test] + public void CacheNameIsSet() + { + att.CacheName = "MyCache"; + Assert.AreEqual("MyCache", att.CacheName); + } + + [Test] + public void KeyIsParsed() + { + att.Key = "TestProperty"; + string result = att.KeyExpression.GetValue(this) as string; + Assert.AreEqual("OK", result); + } + + [Test] + public void ConditionIsParsed() + { + att.Condition = "TestProperty"; + string result = att.ConditionExpression.GetValue(this) as string; + Assert.AreEqual("OK", result); + } + + [Test] + public void AllowsForExtendedTimeSpanConverterSyntax() + { + att.TimeToLive = "5ms"; + Assert.AreEqual(new TimeSpan(0, 0, 0, 0, 5), att.TimeToLiveTimeSpan); + } + + [Test] + public void KeyCannotBeEmptyString() + { + Assert.Throws(() => att = new DerivedCacheAttribute("someName", string.Empty)); + } + + [Test] + public void KeyCannotBeNull() + { + Assert.Throws(() => att = new DerivedCacheAttribute("someName", null)); + } +} diff --git a/test/Spring/Spring.Core.Tests/Collections/AbstractQueueTests.cs b/test/Spring/Spring.Core.Tests/Collections/AbstractQueueTests.cs index 5280d308..d0d76084 100644 --- a/test/Spring/Spring.Core.Tests/Collections/AbstractQueueTests.cs +++ b/test/Spring/Spring.Core.Tests/Collections/AbstractQueueTests.cs @@ -25,193 +25,195 @@ using NUnit.Framework; #endregion -namespace Spring.Collections +namespace Spring.Collections; + +/// +/// Unit tests for the AbstractQueue class. +/// +/// Griffin Caprio +[TestFixture] +public sealed class AbstractQueueTests { - /// - /// Unit tests for the AbstractQueue class. - /// - /// Griffin Caprio - [TestFixture] - public sealed class AbstractQueueTests - { - private sealed class SucceedQueue : AbstractQueue - { - - public override int Count - { - get { return 0; } - } - public override int Capacity - { - get - { - return 0; - } - } - public override bool Offer(object x) - { - if (x == null) - { - throw new NullReferenceException(); - } - return true; - } + private sealed class SucceedQueue : AbstractQueue + { + public override int Count + { + get { return 0; } + } - public override object Peek() - { - return Int32.Parse("1"); - } + public override int Capacity + { + get + { + return 0; + } + } - public override object Poll() - { - return Int32.Parse("1"); - } + public override bool Offer(object x) + { + if (x == null) + { + throw new NullReferenceException(); + } - public override IEnumerator GetEnumerator() - { - return null; - } + return true; + } - public override void CopyTo(Array array, Int32 index) - { - } + public override object Peek() + { + return Int32.Parse("1"); + } - public override object SyncRoot - { - get { return null; } + public override object Poll() + { + return Int32.Parse("1"); + } - } + public override IEnumerator GetEnumerator() + { + return null; + } - public override Boolean IsSynchronized - { - get { return false; } + public override void CopyTo(Array array, Int32 index) + { + } - } + public override object SyncRoot + { + get { return null; } + } - public override bool IsEmpty - { - get { throw new NotImplementedException(); } - } - } + public override Boolean IsSynchronized + { + get { return false; } + } - private sealed class FailQueue : AbstractQueue - { - public override int Count - { - get { return 0; } - } - public override int Capacity - { - get - { - return 0; - } - } - public override bool Offer(object x) - { - if (x == null) - { - throw new NullReferenceException(); - } - return false; - } + public override bool IsEmpty + { + get { throw new NotImplementedException(); } + } + } - public override object Peek() - { - return null; - } + private sealed class FailQueue : AbstractQueue + { + public override int Count + { + get { return 0; } + } - public override object Poll() - { - return null; - } + public override int Capacity + { + get + { + return 0; + } + } - public override IEnumerator GetEnumerator() - { - return null; - } + public override bool Offer(object x) + { + if (x == null) + { + throw new NullReferenceException(); + } - public override void CopyTo(Array array, Int32 index) - { - } + return false; + } - public override object SyncRoot - { - get { return null; } - } + public override object Peek() + { + return null; + } - public override Boolean IsSynchronized - { - get { return false; } - } + public override object Poll() + { + return null; + } - public override bool IsEmpty - { - get { throw new NotImplementedException(); } - } - } + public override IEnumerator GetEnumerator() + { + return null; + } - [Test] - public void AddSucceed() - { - SucceedQueue q = new SucceedQueue(); - Assert.IsTrue(q.Add(Int32.Parse("2"))); - } + public override void CopyTo(Array array, Int32 index) + { + } - [Test] - public void AddFail() - { - FailQueue q = new FailQueue(); - Assert.Throws(() => q.Add(Int32.Parse("1"))); - } + public override object SyncRoot + { + get { return null; } + } - [Test] - public void AddNPE() - { - SucceedQueue q = new SucceedQueue(); - Assert.Throws(() => q.Add(null)); - } + public override Boolean IsSynchronized + { + get { return false; } + } - [Test] - public void RemoveSucceed() - { - SucceedQueue q = new SucceedQueue(); - q.Remove(); - } + public override bool IsEmpty + { + get { throw new NotImplementedException(); } + } + } - [Test] - public void RemoveFail() - { - FailQueue q = new FailQueue(); - Assert.Throws(() => q.Remove()); - } + [Test] + public void AddSucceed() + { + SucceedQueue q = new SucceedQueue(); + Assert.IsTrue(q.Add(Int32.Parse("2"))); + } - [Test] - public void ElementSucceed() - { - SucceedQueue q = new SucceedQueue(); - q.Element(); - } + [Test] + public void AddFail() + { + FailQueue q = new FailQueue(); + Assert.Throws(() => q.Add(Int32.Parse("1"))); + } - [Test] - public void ElementF() - { - FailQueue q = new FailQueue(); - Assert.Throws(() => q.Element()); - } + [Test] + public void AddNPE() + { + SucceedQueue q = new SucceedQueue(); + Assert.Throws(() => q.Add(null)); + } - [Test] - public void AddAll1() - { - SucceedQueue q = new SucceedQueue(); - Assert.Throws(() => q.AddAll(null)); - } + [Test] + public void RemoveSucceed() + { + SucceedQueue q = new SucceedQueue(); + q.Remove(); + } - [Test] - public void AddAllSelf() - { - SucceedQueue q = new SucceedQueue(); - Assert.Throws(() => q.AddAll(q)); - } - } -} \ No newline at end of file + [Test] + public void RemoveFail() + { + FailQueue q = new FailQueue(); + Assert.Throws(() => q.Remove()); + } + + [Test] + public void ElementSucceed() + { + SucceedQueue q = new SucceedQueue(); + q.Element(); + } + + [Test] + public void ElementF() + { + FailQueue q = new FailQueue(); + Assert.Throws(() => q.Element()); + } + + [Test] + public void AddAll1() + { + SucceedQueue q = new SucceedQueue(); + Assert.Throws(() => q.AddAll(null)); + } + + [Test] + public void AddAllSelf() + { + SucceedQueue q = new SucceedQueue(); + Assert.Throws(() => q.AddAll(q)); + } +} diff --git a/test/Spring/Spring.Core.Tests/Collections/CaseInsensitiveHashtableTests.cs b/test/Spring/Spring.Core.Tests/Collections/CaseInsensitiveHashtableTests.cs index 9efa7693..019722a9 100644 --- a/test/Spring/Spring.Core.Tests/Collections/CaseInsensitiveHashtableTests.cs +++ b/test/Spring/Spring.Core.Tests/Collections/CaseInsensitiveHashtableTests.cs @@ -28,131 +28,132 @@ using NUnit.Framework; #endregion -namespace Spring.Collections +namespace Spring.Collections; + +/// +/// +/// +/// Erich Eichinger +[TestFixture] +public class CaseInsensitiveHashtableTests { - /// - /// - /// - /// Erich Eichinger - [TestFixture] - public class CaseInsensitiveHashtableTests + private static object SerializeDeserializeObject(object exp) { - private static object SerializeDeserializeObject(object exp) + byte[] data; + BinaryFormatter formatter = new BinaryFormatter(); + using (MemoryStream ms = new MemoryStream()) { - byte[] data; - BinaryFormatter formatter = new BinaryFormatter(); - using (MemoryStream ms = new MemoryStream()) - { - formatter.Serialize(ms, exp); - ms.Flush(); - data = ms.ToArray(); - } - - using (MemoryStream ms = new MemoryStream(data)) - { - exp = formatter.Deserialize(ms); - } - - return exp; + formatter.Serialize(ms, exp); + ms.Flush(); + data = ms.ToArray(); } - [Test] - public void IsSerializable() + using (MemoryStream ms = new MemoryStream(data)) { - CaseInsensitiveHashtable storiginal = new CaseInsensitiveHashtable(); - storiginal.Add("key", "value"); - CaseInsensitiveHashtable st = (CaseInsensitiveHashtable)SerializeDeserializeObject(storiginal); - Assert.AreNotSame(storiginal, st); - Assert.AreEqual("value", st["KEY"]); - Assert.AreEqual(1, st.Count); + exp = formatter.Deserialize(ms); } - [Test] - public void AcceptsNonStringKeys() - { - CaseInsensitiveHashtable st = new CaseInsensitiveHashtable(); + return exp; + } - object key = new object(); - st.Add(key, "value"); - Assert.AreEqual(1, st.Count); - Assert.AreEqual("value", st[key]); - Assert.IsNull(st[new object()]); + [Test] + public void IsSerializable() + { + CaseInsensitiveHashtable storiginal = new CaseInsensitiveHashtable(); + storiginal.Add("key", "value"); + CaseInsensitiveHashtable st = (CaseInsensitiveHashtable) SerializeDeserializeObject(storiginal); + Assert.AreNotSame(storiginal, st); + Assert.AreEqual("value", st["KEY"]); + Assert.AreEqual(1, st.Count); + } + + [Test] + public void AcceptsNonStringKeys() + { + CaseInsensitiveHashtable st = new CaseInsensitiveHashtable(); + + object key = new object(); + st.Add(key, "value"); + Assert.AreEqual(1, st.Count); + Assert.AreEqual("value", st[key]); + Assert.IsNull(st[new object()]); + } + + [Test] + public void IgnoresCase() + { + CaseInsensitiveHashtable st = new CaseInsensitiveHashtable(); + st.Add("key", "value"); + Assert.AreEqual("value", st["KEY"]); + st["KeY"] = "value2"; + Assert.AreEqual(1, st.Count); + Assert.AreEqual("value2", st["key"]); + + try + { + st.Add("KEY", "value2"); + Assert.Fail(); + } + catch (ArgumentException) + { } - [Test] - public void IgnoresCase() + Hashtable ht = new Hashtable(); + ht.Add("key", "value"); + ht.Add("KEY", "value"); + try { - CaseInsensitiveHashtable st = new CaseInsensitiveHashtable(); - st.Add("key", "value"); - Assert.AreEqual("value", st["KEY"]); - st["KeY"] = "value2"; - Assert.AreEqual(1, st.Count); - Assert.AreEqual("value2", st["key"]); + st = new CaseInsensitiveHashtable(ht, CultureInfo.InvariantCulture); + Assert.Fail(); + } + catch (ArgumentException) + { + } + } - try + [Test] + public void InitializeFromOtherCopiesValues() + { + Hashtable ht = new Hashtable(); + ht["key"] = "value"; + ht["key2"] = "value2"; + + CaseInsensitiveHashtable st = new CaseInsensitiveHashtable(ht, CultureInfo.InvariantCulture); + Assert.AreEqual(2, st.Count); + ht.Remove("key"); + Assert.AreEqual(1, ht.Count); + Assert.AreEqual(2, st.Count); + } + + /// + /// On my NB gives + /// Duration: 00:00:11.0937500 + /// Duration: 00:00:05.3593750 + /// + [Test, Explicit] + public void ComparePerformance() + { + const int runs = 30000000; + StopWatch watch = new StopWatch(); + + Hashtable ht = CollectionsUtil.CreateCaseInsensitiveHashtable(); + for (int i = 0; i < 1000000; i++) ht.Add(Guid.NewGuid().ToString(), "val"); // gen. higher number of elements results in OOM exception???? + CaseInsensitiveHashtable ciht = new CaseInsensitiveHashtable(ht, CultureInfo.InvariantCulture); + + using (watch.Start("Duration: {0}")) + { + for (int i = 0; i < runs; i++) { - st.Add("KEY", "value2"); - Assert.Fail(); + object v = ht["somekey"]; } - catch (ArgumentException) - { } - - Hashtable ht = new Hashtable(); - ht.Add("key", "value"); - ht.Add("KEY", "value"); - try - { - st = new CaseInsensitiveHashtable(ht, CultureInfo.InvariantCulture); - Assert.Fail(); - } - catch (ArgumentException) - { } } - [Test] - public void InitializeFromOtherCopiesValues() + using (watch.Start("Duration: {0}")) { - Hashtable ht = new Hashtable(); - ht["key"] = "value"; - ht["key2"] = "value2"; - - CaseInsensitiveHashtable st = new CaseInsensitiveHashtable(ht, CultureInfo.InvariantCulture); - Assert.AreEqual(2, st.Count); - ht.Remove("key"); - Assert.AreEqual(1, ht.Count); - Assert.AreEqual(2, st.Count); - } - - /// - /// On my NB gives - /// Duration: 00:00:11.0937500 - /// Duration: 00:00:05.3593750 - /// - [Test, Explicit] - public void ComparePerformance() - { - const int runs = 30000000; - StopWatch watch = new StopWatch(); - - Hashtable ht = CollectionsUtil.CreateCaseInsensitiveHashtable(); - for (int i = 0; i < 1000000; i++) ht.Add(Guid.NewGuid().ToString(), "val"); // gen. higher number of elements results in OOM exception???? - CaseInsensitiveHashtable ciht = new CaseInsensitiveHashtable(ht, CultureInfo.InvariantCulture); - - using (watch.Start("Duration: {0}")) + for (int i = 0; i < runs; i++) { - for (int i = 0; i < runs; i++) - { - object v = ht["somekey"]; - } - } - - using (watch.Start("Duration: {0}")) - { - for (int i = 0; i < runs; i++) - { - object v = ciht["somekey"]; - } + object v = ciht["somekey"]; } } } -} \ No newline at end of file +} diff --git a/test/Spring/Spring.Core.Tests/Collections/Generic/LinkedHashDictionaryTest.cs b/test/Spring/Spring.Core.Tests/Collections/Generic/LinkedHashDictionaryTest.cs index 0e04c650..003dc165 100644 --- a/test/Spring/Spring.Core.Tests/Collections/Generic/LinkedHashDictionaryTest.cs +++ b/test/Spring/Spring.Core.Tests/Collections/Generic/LinkedHashDictionaryTest.cs @@ -20,82 +20,80 @@ using NUnit.Framework; -namespace Spring.Collections.Generic +namespace Spring.Collections.Generic; + +/// +/// This class contains tests for LinkedHashDictionary +/// +/// Zbynek Vyskovsky, kvr@centrum.cz +[TestFixture] +public class LinkedHashDictionaryTest { - /// - /// This class contains tests for LinkedHashDictionary - /// - /// Zbynek Vyskovsky, kvr@centrum.cz - [TestFixture] - public class LinkedHashDictionaryTest + private IDictionary _testDictionary; + + [SetUp] + public void Setup() { - private IDictionary _testDictionary; + _testDictionary = new LinkedHashDictionary(); + _testDictionary.Add(0, "a"); + _testDictionary.Add(1, "b"); + _testDictionary.Add(2, "c"); + _testDictionary.Add(3, "d"); + _testDictionary.Add(4, "e"); + } - [SetUp] - public void Setup() - { - _testDictionary = new LinkedHashDictionary(); - _testDictionary.Add(0, "a"); - _testDictionary.Add(1, "b"); - _testDictionary.Add(2, "c"); - _testDictionary.Add(3, "d"); - _testDictionary.Add(4, "e"); - } + [Test] + public void CanAddEntries() + { + Assert.IsTrue(_testDictionary.ContainsKey(0)); + Assert.IsTrue(_testDictionary.ContainsKey(1)); + Assert.IsTrue(_testDictionary.ContainsKey(2)); + Assert.IsTrue(_testDictionary.ContainsKey(3)); + Assert.IsTrue(_testDictionary.ContainsKey(4)); + } - [Test] - public void CanAddEntries() - { - Assert.IsTrue(_testDictionary.ContainsKey(0)); - Assert.IsTrue(_testDictionary.ContainsKey(1)); - Assert.IsTrue(_testDictionary.ContainsKey(2)); - Assert.IsTrue(_testDictionary.ContainsKey(3)); - Assert.IsTrue(_testDictionary.ContainsKey(4)); - } + [Test] + public void AddAtExistingIndexOverwritesEntry() + { + _testDictionary.Add(1, "b2"); + Assert.AreEqual("b2", _testDictionary[1]); + } - [Test] - public void AddAtExistingIndexOverwritesEntry() - { - _testDictionary.Add(1, "b2"); - Assert.AreEqual("b2", _testDictionary[1]); - } + [Test] + public void CanAccessValuesByIndex() + { + Assert.AreEqual("a", _testDictionary[0]); + Assert.AreEqual("b", _testDictionary[1]); + } - [Test] - public void CanAccessValuesByIndex() - { - Assert.AreEqual("a", _testDictionary[0]); - Assert.AreEqual("b", _testDictionary[1]); - } + /// + /// Determines whether this instance [can retreive keys]. + /// + [Test] + public void CanRetreiveKeys() + { + int[] keys = _testDictionary.Keys.ToArray(); + Assert.AreEqual(5, keys.Length); + Assert.AreEqual(0, keys[0]); + Assert.AreEqual(1, keys[1]); + Assert.AreEqual(2, keys[2]); + Assert.AreEqual(3, keys[3]); + Assert.AreEqual(4, keys[4]); + } - /// - /// Determines whether this instance [can retreive keys]. - /// - [Test] - public void CanRetreiveKeys() - { - int[] keys = _testDictionary.Keys.ToArray(); - Assert.AreEqual(5, keys.Length); - Assert.AreEqual(0, keys[0]); - Assert.AreEqual(1, keys[1]); - Assert.AreEqual(2, keys[2]); - Assert.AreEqual(3, keys[3]); - Assert.AreEqual(4, keys[4]); - } + [Test] + public void CanRemoveEntriesByIndex() + { + _testDictionary.Remove(3); + _testDictionary.Remove(2); + Assert.AreEqual(3, _testDictionary.Count); - [Test] - public void CanRemoveEntriesByIndex() - { - _testDictionary.Remove(3); - _testDictionary.Remove(2); - Assert.AreEqual(3, _testDictionary.Count); + _testDictionary.Remove(1); + Assert.AreEqual(2, _testDictionary.Count); - _testDictionary.Remove(1); - Assert.AreEqual(2, _testDictionary.Count); - - _testDictionary.Remove(4); - _testDictionary.Remove(0); - Assert.AreEqual(0, _testDictionary.Count); - Assert.AreEqual(0, _testDictionary.Keys.Count); - } - + _testDictionary.Remove(4); + _testDictionary.Remove(0); + Assert.AreEqual(0, _testDictionary.Count); + Assert.AreEqual(0, _testDictionary.Keys.Count); } } diff --git a/test/Spring/Spring.Core.Tests/Collections/Generic/ReadOnlyDictionaryTests.cs b/test/Spring/Spring.Core.Tests/Collections/Generic/ReadOnlyDictionaryTests.cs index 53cb537f..565ef866 100644 --- a/test/Spring/Spring.Core.Tests/Collections/Generic/ReadOnlyDictionaryTests.cs +++ b/test/Spring/Spring.Core.Tests/Collections/Generic/ReadOnlyDictionaryTests.cs @@ -21,70 +21,66 @@ #region Imports using NUnit.Framework; + //using NUnit.Framework.SyntaxHelpers; #endregion -namespace Spring.Collections.Generic +namespace Spring.Collections.Generic; + +/// +/// This class contains tests for ReadOnlyDictionary +/// +/// Mark Pollack +[TestFixture] +public class ReadOnlyDictionaryTests { - /// - /// This class contains tests for ReadOnlyDictionary - /// - /// Mark Pollack - [TestFixture] - public class ReadOnlyDictionaryTests + private IDictionary personDictionary; + private IDictionary readonlyPersonDictionary; + + [SetUp] + public void Setup() { - private IDictionary personDictionary; - private IDictionary readonlyPersonDictionary; - - [SetUp] - public void Setup() - { - personDictionary = new Dictionary(); - personDictionary.Add("Mark", 38); - personDictionary.Add("Daniela", 38); - readonlyPersonDictionary = new ReadOnlyDictionary(personDictionary); - - } - - [Test] - public void TestSunnyDay() - { - - Assert.That(readonlyPersonDictionary.IsReadOnly, Is.True); - Assert.That(readonlyPersonDictionary.Contains(new KeyValuePair("Mark", 38))); - Assert.That(readonlyPersonDictionary.ContainsKey("Mark"), Is.True); - Assert.That(readonlyPersonDictionary.Count, Is.EqualTo(2)); - } - - [Test] - public void Exceptions() - { - //updating to nunit 2.5 would be nice to use Assert.That( SomeMethod, Throws.Exception()); - // Execute(delegate { }); - - Execute(() => { readonlyPersonDictionary["Mark"] = 4; }); - Execute(() => readonlyPersonDictionary.Add("Gabriel", 3)); - Execute(() => readonlyPersonDictionary.Add(new KeyValuePair("Mark", 38))); - Execute(() => readonlyPersonDictionary.Clear()); - Execute(() => readonlyPersonDictionary.Remove("Mark")); - Execute(() => readonlyPersonDictionary.Remove(new KeyValuePair("Mark", 38))); - } - - public void Execute(DoInTryCatch exceptionDelegate) - { - try - { - exceptionDelegate.Invoke(); - Assert.Fail("Should throw NotSupportedException"); - } catch (NotSupportedException) - { - - } - } - - public delegate void DoInTryCatch(); - - + personDictionary = new Dictionary(); + personDictionary.Add("Mark", 38); + personDictionary.Add("Daniela", 38); + readonlyPersonDictionary = new ReadOnlyDictionary(personDictionary); } + + [Test] + public void TestSunnyDay() + { + Assert.That(readonlyPersonDictionary.IsReadOnly, Is.True); + Assert.That(readonlyPersonDictionary.Contains(new KeyValuePair("Mark", 38))); + Assert.That(readonlyPersonDictionary.ContainsKey("Mark"), Is.True); + Assert.That(readonlyPersonDictionary.Count, Is.EqualTo(2)); + } + + [Test] + public void Exceptions() + { + //updating to nunit 2.5 would be nice to use Assert.That( SomeMethod, Throws.Exception()); + // Execute(delegate { }); + + Execute(() => { readonlyPersonDictionary["Mark"] = 4; }); + Execute(() => readonlyPersonDictionary.Add("Gabriel", 3)); + Execute(() => readonlyPersonDictionary.Add(new KeyValuePair("Mark", 38))); + Execute(() => readonlyPersonDictionary.Clear()); + Execute(() => readonlyPersonDictionary.Remove("Mark")); + Execute(() => readonlyPersonDictionary.Remove(new KeyValuePair("Mark", 38))); + } + + public void Execute(DoInTryCatch exceptionDelegate) + { + try + { + exceptionDelegate.Invoke(); + Assert.Fail("Should throw NotSupportedException"); + } + catch (NotSupportedException) + { + } + } + + public delegate void DoInTryCatch(); } diff --git a/test/Spring/Spring.Core.Tests/Collections/HashedSetTests.cs b/test/Spring/Spring.Core.Tests/Collections/HashedSetTests.cs index e1d16271..f86841fc 100644 --- a/test/Spring/Spring.Core.Tests/Collections/HashedSetTests.cs +++ b/test/Spring/Spring.Core.Tests/Collections/HashedSetTests.cs @@ -24,23 +24,22 @@ using NUnit.Framework; #endregion -namespace Spring.Collections +namespace Spring.Collections; + +/// +/// Unit tests for the HashedSet class. +/// +/// Rick Evans +[TestFixture] +public class HashedSetTests : SetTests { - /// - /// Unit tests for the HashedSet class. + /// + /// The setup logic executed before the execution of each individual test. /// - /// Rick Evans - [TestFixture] - public class HashedSetTests : SetTests + [SetUp] + public override void SetUp() { - /// - /// The setup logic executed before the execution of each individual test. - /// - [SetUp] - public override void SetUp () - { - Set = new HashedSet (); - SetForSetOps = new HashedSet (); - } - } + Set = new HashedSet(); + SetForSetOps = new HashedSet(); + } } diff --git a/test/Spring/Spring.Core.Tests/Collections/HybridSetTests.cs b/test/Spring/Spring.Core.Tests/Collections/HybridSetTests.cs index 642100da..5b9ebc5d 100644 --- a/test/Spring/Spring.Core.Tests/Collections/HybridSetTests.cs +++ b/test/Spring/Spring.Core.Tests/Collections/HybridSetTests.cs @@ -24,23 +24,22 @@ using NUnit.Framework; #endregion -namespace Spring.Collections +namespace Spring.Collections; + +/// +/// Unit tests for the HybridSet class. +/// +/// Rick Evans +[TestFixture] +public class HybridSetTests : SetTests { - /// - /// Unit tests for the HybridSet class. + /// + /// The setup logic executed before the execution of each individual test. /// - /// Rick Evans - [TestFixture] - public class HybridSetTests : SetTests + [SetUp] + public override void SetUp() { - /// - /// The setup logic executed before the execution of each individual test. - /// - [SetUp] - public override void SetUp () - { - Set = new HybridSet (); - SetForSetOps = new HybridSet (); - } + Set = new HybridSet(); + SetForSetOps = new HybridSet(); } } diff --git a/test/Spring/Spring.Core.Tests/Collections/ImmutableSetTests.cs b/test/Spring/Spring.Core.Tests/Collections/ImmutableSetTests.cs index 35787949..8fa563e7 100644 --- a/test/Spring/Spring.Core.Tests/Collections/ImmutableSetTests.cs +++ b/test/Spring/Spring.Core.Tests/Collections/ImmutableSetTests.cs @@ -24,170 +24,177 @@ using NUnit.Framework; #endregion -namespace Spring.Collections +namespace Spring.Collections; + +/// +/// Unit tests for the ImmutableSet wrapper class. +/// +/// Rick Evans +[TestFixture] +public class ImmutableSetTests { - /// - /// Unit tests for the ImmutableSet wrapper class. + /// + /// The setup logic executed before the execution of each individual test. /// - /// Rick Evans - [TestFixture] - public class ImmutableSetTests + [SetUp] + public void SetUp() { - /// - /// The setup logic executed before the execution of each individual test. - /// - [SetUp] - public void SetUp () { - Set = new ImmutableSet (new HybridSet (new object [] {1, 2, 3})); - } + Set = new ImmutableSet(new HybridSet(new object[] { 1, 2, 3 })); + } - /// - /// The tear down logic executed after the execution of each individual test. - /// - [TearDown] - public void TearDown () { - Set = null; - } + /// + /// The tear down logic executed after the execution of each individual test. + /// + [TearDown] + public void TearDown() + { + Set = null; + } - [Test] - public void Add() + [Test] + public void Add() + { + Assert.Throws(() => Set.Add(1)); + } + + [Test] + public void AddAll() + { + Assert.Throws(() => Set.AddAll(new int[] { 4, 5, 6 })); + } + + [Test] + public void Remove() + { + Assert.Throws(() => Set.Remove(1)); + } + + [Test] + public void RemoveAll() + { + object[] removed = new object[] { 1, 3 }; + Assert.Throws(() => Set.RemoveAll(removed)); + } + + [Test] + public void RetainAll() + { + Assert.Throws(() => Set.RetainAll(new object[] { 1, 9 })); + } + + [Test] + public void Clear() + { + Assert.Throws(() => Set.Clear()); + } + + [Test] + public void IsEmpty() + { + Assert.IsFalse(Set.IsEmpty); + ISet mySet = new ImmutableSet(new HybridSet()); + Assert.IsTrue(mySet.IsEmpty); + } + + [Test] + public void Contains() + { + Assert.IsFalse(Set.Contains("Funk")); + Assert.IsTrue(Set.Contains(1)); + } + + [Test] + public void ContainsAll() + { + Assert.IsFalse(Set.ContainsAll(new object[] { "Funk", 1, 2, 3 })); + Assert.IsTrue(Set.ContainsAll(new object[] { 1, 3, 2 })); + } + + [Test] + public void CopyTo() + { + int[] expected = new int[] { 1, 2, 3 }; + int[] actual = new int [Set.Count]; + Set.CopyTo(actual, 0); + Assert.AreEqual(expected.Length, actual.Length); + for (int i = 0; i < expected.Length; ++i) { - Assert.Throws(() => Set.Add(1)); + Assert.AreEqual(expected[i], actual[i]); } + } - [Test] - public void AddAll() + [Test] + public void EnumeratesOk() + { + int[] expected = new int[] { 1, 2, 3 }; + int i = 0; + foreach (int actual in Set) { - Assert.Throws(() => Set.AddAll(new int[] {4, 5, 6})); + Assert.AreEqual(expected[i++], actual); } + } - [Test] - public void Remove() + [Test] + public void ClonedInstanceMustStillBeImmutable() + { + ISet clone = (ISet) Set.Clone(); + Assert.Throws(() => clone.Add("bad chair, bad chair")); + } + + [Test] + public void MinusYieldsImmutableCone() + { + ISet mySet = new ListSet(new int[] { 1, 2 }); + ISet clone = Set.Minus(mySet); + Assert.IsNotNull(clone); + Assert.AreEqual(1, clone.Count); + Assert.Throws(() => clone.Add("bad chair, bad chair")); + } + + [Test] + public void UnionYieldsImmutableCone() + { + ISet mySet = new ListSet(new int[] { 1, 4 }); + ISet clone = Set.Union(mySet); + Assert.IsNotNull(clone); + Assert.AreEqual(4, clone.Count); + Assert.Throws(() => clone.Add("bad chair, bad chair")); + } + + [Test] + public void IntersectionYieldsImmutableCone() + { + ISet mySet = new ListSet(new int[] { 1, 4 }); + ISet clone = Set.Intersect(mySet); + Assert.IsNotNull(clone); + Assert.AreEqual(1, clone.Count); + Assert.Throws(() => clone.Add("bad chair, bad chair")); + } + + [Test] + public void ExclusiveOrYieldsImmutableCone() + { + ISet mySet = new ListSet(new int[] { 1, 4 }); + ISet clone = Set.ExclusiveOr(mySet); + Assert.IsNotNull(clone); + Assert.AreEqual(3, clone.Count); + Assert.Throws(() => clone.Add("bad chair, bad chair")); + } + + /// + /// The ISet being tested. + /// + protected virtual ISet Set + { + get { - Assert.Throws(() => Set.Remove(1)); + return _set; } - - [Test] - public void RemoveAll() + set { - object[] removed = new object[] {1, 3}; - Assert.Throws(() => Set.RemoveAll(removed)); + _set = value; } + } - [Test] - public void RetainAll() - { - Assert.Throws(() => Set.RetainAll(new object[] {1, 9})); - } - - [Test] - public void Clear() - { - Assert.Throws(() => Set.Clear()); - } - - [Test] - public void IsEmpty() { - Assert.IsFalse (Set.IsEmpty); - ISet mySet = new ImmutableSet (new HybridSet ()); - Assert.IsTrue (mySet.IsEmpty); - } - - [Test] - public void Contains() { - Assert.IsFalse (Set.Contains ("Funk")); - Assert.IsTrue (Set.Contains (1)); - } - - [Test] - public void ContainsAll() - { - Assert.IsFalse(Set.ContainsAll(new object[] {"Funk", 1, 2, 3})); - Assert.IsTrue(Set.ContainsAll(new object[] {1, 3, 2})); - } - - [Test] - public void CopyTo() { - int [] expected = new int [] {1, 2, 3}; - int [] actual = new int [Set.Count]; - Set.CopyTo (actual, 0); - Assert.AreEqual (expected.Length, actual.Length); - for (int i = 0; i < expected.Length; ++i) { - Assert.AreEqual (expected [i], actual [i]); - } - } - - [Test] - public void EnumeratesOk () { - int [] expected = new int [] {1, 2, 3}; - int i = 0; - foreach (int actual in Set) { - Assert.AreEqual (expected [i++], actual); - } - } - - [Test] - public void ClonedInstanceMustStillBeImmutable() - { - ISet clone = (ISet) Set.Clone(); - Assert.Throws(() => clone.Add("bad chair, bad chair")); - } - - [Test] - public void MinusYieldsImmutableCone() - { - ISet mySet = new ListSet(new int[] {1, 2}); - ISet clone = Set.Minus(mySet); - Assert.IsNotNull(clone); - Assert.AreEqual(1, clone.Count); - Assert.Throws(() => clone.Add("bad chair, bad chair")); - } - - [Test] - public void UnionYieldsImmutableCone() - { - ISet mySet = new ListSet(new int[] {1, 4}); - ISet clone = Set.Union(mySet); - Assert.IsNotNull(clone); - Assert.AreEqual(4, clone.Count); - Assert.Throws(() => clone.Add("bad chair, bad chair")); - } - - [Test] - public void IntersectionYieldsImmutableCone() - { - ISet mySet = new ListSet(new int[] {1, 4}); - ISet clone = Set.Intersect(mySet); - Assert.IsNotNull(clone); - Assert.AreEqual(1, clone.Count); - Assert.Throws(() => clone.Add("bad chair, bad chair")); - } - - [Test] - public void ExclusiveOrYieldsImmutableCone() - { - ISet mySet = new ListSet(new int[] {1, 4}); - ISet clone = Set.ExclusiveOr(mySet); - Assert.IsNotNull(clone); - Assert.AreEqual(3, clone.Count); - Assert.Throws(() => clone.Add("bad chair, bad chair")); - } - - /// - /// The ISet being tested. - /// - protected virtual ISet Set - { - get - { - return _set; - } - set - { - _set = value; - } - } - - private ISet _set; - } + private ISet _set; } diff --git a/test/Spring/Spring.Core.Tests/Collections/LinkedListTests.cs b/test/Spring/Spring.Core.Tests/Collections/LinkedListTests.cs index 4213f663..a522d2c9 100644 --- a/test/Spring/Spring.Core.Tests/Collections/LinkedListTests.cs +++ b/test/Spring/Spring.Core.Tests/Collections/LinkedListTests.cs @@ -21,222 +21,220 @@ #region Imports using System.Collections; - using NUnit.Framework; #endregion -namespace Spring.Collections +namespace Spring.Collections; + +/// +/// Set of tests for Spring.Util.LinkedList. +/// +/// Simon White +[TestFixture] +public sealed class LinkedListTests { - /// - /// Set of tests for Spring.Util.LinkedList. - /// - /// Simon White - [TestFixture] - public sealed class LinkedListTests - { - [Test] - public void AddMultipleObjects() - { - LinkedList ll = new LinkedList(); - ll.Add("item1"); - ll.Add("item2"); - ll.Add("item3"); - Assert.IsTrue(ll.Count == 3, "Expected 3 items not " + ll.Count); - Assert.IsTrue(ll[0].Equals("item1"), "Expected first element to be \"item1\" not " + ll[0]); - Assert.IsTrue(ll[1].Equals("item2"), "Expected second element to be \"item2\" not " + ll[1]); - } + [Test] + public void AddMultipleObjects() + { + LinkedList ll = new LinkedList(); + ll.Add("item1"); + ll.Add("item2"); + ll.Add("item3"); + Assert.IsTrue(ll.Count == 3, "Expected 3 items not " + ll.Count); + Assert.IsTrue(ll[0].Equals("item1"), "Expected first element to be \"item1\" not " + ll[0]); + Assert.IsTrue(ll[1].Equals("item2"), "Expected second element to be \"item2\" not " + ll[1]); + } - [Test] - public void Insert() - { - LinkedList ll = new LinkedList(); - ll.Add("item1"); - ll.Add("item2"); - ll.Insert(1, "item1andahalf"); - Assert.IsTrue(ll.Count == 3, "Expected 3 items not " + ll.Count); - Assert.IsTrue(ll[0].Equals("item1"), "Expected first element to be \"item1\" not " + ll[0]); - Assert.IsTrue(ll[1].Equals("item1andahalf"), "Expected second element to be \"item1andahalf\" not " + ll[1]); - Assert.IsTrue(ll[2].Equals("item2"), "Expected third element to be \"item2\" not " + ll[0]); - } + [Test] + public void Insert() + { + LinkedList ll = new LinkedList(); + ll.Add("item1"); + ll.Add("item2"); + ll.Insert(1, "item1andahalf"); + Assert.IsTrue(ll.Count == 3, "Expected 3 items not " + ll.Count); + Assert.IsTrue(ll[0].Equals("item1"), "Expected first element to be \"item1\" not " + ll[0]); + Assert.IsTrue(ll[1].Equals("item1andahalf"), "Expected second element to be \"item1andahalf\" not " + ll[1]); + Assert.IsTrue(ll[2].Equals("item2"), "Expected third element to be \"item2\" not " + ll[0]); + } - [Test] - public void RemoveAt() - { - LinkedList ll = new LinkedList(); - ll.Add("item1"); - ll.Add("item2"); - ll.Add("item3"); - ll.RemoveAt(1); - Assert.IsTrue(ll.Count == 2, "Expected 2 items not " + ll.Count); - Assert.IsTrue(ll[0].Equals("item1"), "Expected first element to be \"item1\" not " + ll[0]); - Assert.IsTrue(ll[1].Equals("item3"), "Expected second element to be \"item3\" not " + ll[1]); - } + [Test] + public void RemoveAt() + { + LinkedList ll = new LinkedList(); + ll.Add("item1"); + ll.Add("item2"); + ll.Add("item3"); + ll.RemoveAt(1); + Assert.IsTrue(ll.Count == 2, "Expected 2 items not " + ll.Count); + Assert.IsTrue(ll[0].Equals("item1"), "Expected first element to be \"item1\" not " + ll[0]); + Assert.IsTrue(ll[1].Equals("item3"), "Expected second element to be \"item3\" not " + ll[1]); + } - [Test] - public void RemoveObject() - { - string item1 = "item1"; - string item2 = "item2"; - string item3 = "item3"; - LinkedList ll = new LinkedList(); - ll.Add(item1); - ll.Add(item2); - ll.Add(item3); - ll.Remove(item2); - Assert.IsTrue(ll.Count == 2, "Expected 2 items not " + ll.Count); - Assert.IsTrue(ll[0].Equals("item1"), "Expected first element to be \"item1\" not " + ll[0]); - Assert.IsTrue(ll[1].Equals("item3"), "Expected second element to be \"item3\" not " + ll[1]); - } + [Test] + public void RemoveObject() + { + string item1 = "item1"; + string item2 = "item2"; + string item3 = "item3"; + LinkedList ll = new LinkedList(); + ll.Add(item1); + ll.Add(item2); + ll.Add(item3); + ll.Remove(item2); + Assert.IsTrue(ll.Count == 2, "Expected 2 items not " + ll.Count); + Assert.IsTrue(ll[0].Equals("item1"), "Expected first element to be \"item1\" not " + ll[0]); + Assert.IsTrue(ll[1].Equals("item3"), "Expected second element to be \"item3\" not " + ll[1]); + } - [Test] - public void RemoveAtOnEmptyLinkedList() - { - LinkedList ll = new LinkedList(); - Assert.Throws(() => ll.RemoveAt(0)); - } + [Test] + public void RemoveAtOnEmptyLinkedList() + { + LinkedList ll = new LinkedList(); + Assert.Throws(() => ll.RemoveAt(0)); + } - [Test] - public void Enumerator() - { - LinkedList ll = new LinkedList(); - ll.Add("item1"); - ll.Add("item2"); - ll.Add("item3"); - IEnumerator ienum = ll.GetEnumerator(); - Assert.IsTrue(ienum.MoveNext()); - Assert.IsTrue(ienum.Current.Equals("item1"), "Expected first element to be \"item1\" not " + ienum.Current); - Assert.IsTrue(ienum.MoveNext()); - Assert.IsTrue(ienum.Current.Equals("item2"), "Expected second element to be \"item2\" not " + ienum.Current); - } + [Test] + public void Enumerator() + { + LinkedList ll = new LinkedList(); + ll.Add("item1"); + ll.Add("item2"); + ll.Add("item3"); + IEnumerator ienum = ll.GetEnumerator(); + Assert.IsTrue(ienum.MoveNext()); + Assert.IsTrue(ienum.Current.Equals("item1"), "Expected first element to be \"item1\" not " + ienum.Current); + Assert.IsTrue(ienum.MoveNext()); + Assert.IsTrue(ienum.Current.Equals("item2"), "Expected second element to be \"item2\" not " + ienum.Current); + } - [Test] - public void EnumeratorModification() - { - LinkedList ll = new LinkedList(); - ll.Add("item1"); - ll.Add("item2"); - ll.Add("item3"); - IEnumerator ienum = ll.GetEnumerator(); - Assert.IsTrue(ienum.MoveNext()); - ll.RemoveAt(0); - Assert.Throws(() => ienum.MoveNext()); - } + [Test] + public void EnumeratorModification() + { + LinkedList ll = new LinkedList(); + ll.Add("item1"); + ll.Add("item2"); + ll.Add("item3"); + IEnumerator ienum = ll.GetEnumerator(); + Assert.IsTrue(ienum.MoveNext()); + ll.RemoveAt(0); + Assert.Throws(() => ienum.MoveNext()); + } - [Test] - public void ConstructorWithIList() - { - ArrayList al = new ArrayList(); - al.Add("al1"); - al.Add("al2"); - al.Add("al3"); - LinkedList ll = new LinkedList(al); - Assert.IsTrue(ll.Count == 3, "Expected 3 items not " + ll.Count); - Assert.IsTrue(ll[0].Equals("al1"), "Expected first element to be \"al1\" not " + ll[0]); - Assert.IsTrue(ll[1].Equals("al2"), "Expected second element to be \"al2\" not " + ll[1]); - } + [Test] + public void ConstructorWithIList() + { + ArrayList al = new ArrayList(); + al.Add("al1"); + al.Add("al2"); + al.Add("al3"); + LinkedList ll = new LinkedList(al); + Assert.IsTrue(ll.Count == 3, "Expected 3 items not " + ll.Count); + Assert.IsTrue(ll[0].Equals("al1"), "Expected first element to be \"al1\" not " + ll[0]); + Assert.IsTrue(ll[1].Equals("al2"), "Expected second element to be \"al2\" not " + ll[1]); + } - [Test] - public void IndexOfObject() - { - string item1 = "item1"; - string item2 = "item2"; - string item3 = "item3"; - LinkedList ll = new LinkedList(); - ll.Add(item1); - ll.Add(item2); - ll.Add(item3); - int index = ll.IndexOf(item2); - Assert.IsTrue(index == 1, "Expected index of 1 not " + index); - } + [Test] + public void IndexOfObject() + { + string item1 = "item1"; + string item2 = "item2"; + string item3 = "item3"; + LinkedList ll = new LinkedList(); + ll.Add(item1); + ll.Add(item2); + ll.Add(item3); + int index = ll.IndexOf(item2); + Assert.IsTrue(index == 1, "Expected index of 1 not " + index); + } - [Test] - public void CopyToWithZeroIndex() - { - LinkedList ll = new LinkedList(); - ll.Add("item1"); - ll.Add("item2"); - ll.Add("item3"); - string[] strings = new string[3]; - ll.CopyTo(strings, 0); - Assert.IsTrue(strings[0].Equals("item1"), "Expected first element to be \"item1\" not " + strings[0]); - Assert.IsTrue(strings[1].Equals("item2"), "Expected second element to be \"item2\" not " + strings[1]); - Assert.IsTrue(strings[2].Equals("item3"), "Expected third element to be \"item3\" not " + strings[2]); - } + [Test] + public void CopyToWithZeroIndex() + { + LinkedList ll = new LinkedList(); + ll.Add("item1"); + ll.Add("item2"); + ll.Add("item3"); + string[] strings = new string[3]; + ll.CopyTo(strings, 0); + Assert.IsTrue(strings[0].Equals("item1"), "Expected first element to be \"item1\" not " + strings[0]); + Assert.IsTrue(strings[1].Equals("item2"), "Expected second element to be \"item2\" not " + strings[1]); + Assert.IsTrue(strings[2].Equals("item3"), "Expected third element to be \"item3\" not " + strings[2]); + } - [Test] - public void CopyToWithNonZeroIndex() - { - LinkedList ll = new LinkedList(); - ll.Add("item1"); - ll.Add("item2"); - ll.Add("item3"); - string[] strings = new string[5]; - strings[0] = "string1"; - strings[1] = "string2"; - ll.CopyTo(strings, 2); - Assert.IsTrue(strings[0].Equals("string1"), "Expected first element to be \"string1\" not " + strings[0]); - Assert.IsTrue(strings[1].Equals("string2"), "Expected second element to be \"string2\" not " + strings[1]); - Assert.IsTrue(strings[2].Equals("item1"), "Expected third element to be \"item1\" not " + strings[2]); - Assert.IsTrue(strings[3].Equals("item2"), "Expected fourth element to be \"item2\" not " + strings[3]); - Assert.IsTrue(strings[4].Equals("item3"), "Expected fifth element to be \"item3\" not " + strings[4]); - } + [Test] + public void CopyToWithNonZeroIndex() + { + LinkedList ll = new LinkedList(); + ll.Add("item1"); + ll.Add("item2"); + ll.Add("item3"); + string[] strings = new string[5]; + strings[0] = "string1"; + strings[1] = "string2"; + ll.CopyTo(strings, 2); + Assert.IsTrue(strings[0].Equals("string1"), "Expected first element to be \"string1\" not " + strings[0]); + Assert.IsTrue(strings[1].Equals("string2"), "Expected second element to be \"string2\" not " + strings[1]); + Assert.IsTrue(strings[2].Equals("item1"), "Expected third element to be \"item1\" not " + strings[2]); + Assert.IsTrue(strings[3].Equals("item2"), "Expected fourth element to be \"item2\" not " + strings[3]); + Assert.IsTrue(strings[4].Equals("item3"), "Expected fifth element to be \"item3\" not " + strings[4]); + } - [Test] - public void CopyToWithNullArray() - { - LinkedList ll = new LinkedList(); - ll.Add("item1"); - Assert.Throws(() => ll.CopyTo(null, 0)); - } + [Test] + public void CopyToWithNullArray() + { + LinkedList ll = new LinkedList(); + ll.Add("item1"); + Assert.Throws(() => ll.CopyTo(null, 0)); + } - [Test] - public void CopyToWithNegativeIndex() - { - LinkedList ll = new LinkedList(); - ll.Add("item1"); - string[] strings = new string[1]; - Assert.Throws(() => ll.CopyTo(strings, -1)); - } + [Test] + public void CopyToWithNegativeIndex() + { + LinkedList ll = new LinkedList(); + ll.Add("item1"); + string[] strings = new string[1]; + Assert.Throws(() => ll.CopyTo(strings, -1)); + } - [Test] - public void CopyToWithIndexGreaterThanArrayLength() - { - LinkedList ll = new LinkedList(); - ll.Add("item1"); - string[] strings = new string[1]; - Assert.Throws(() => ll.CopyTo(strings, 2)); - } + [Test] + public void CopyToWithIndexGreaterThanArrayLength() + { + LinkedList ll = new LinkedList(); + ll.Add("item1"); + string[] strings = new string[1]; + Assert.Throws(() => ll.CopyTo(strings, 2)); + } - [Test] - public void CopyToWithInsufficientSizeArray() - { - LinkedList ll = new LinkedList(); - ll.Add("item1"); - ll.Add("item2"); - string[] strings = new string[2]; - Assert.Throws(() => ll.CopyTo(strings, 1)); - } + [Test] + public void CopyToWithInsufficientSizeArray() + { + LinkedList ll = new LinkedList(); + ll.Add("item1"); + ll.Add("item2"); + string[] strings = new string[2]; + Assert.Throws(() => ll.CopyTo(strings, 1)); + } - [Test] - public void Contains() - { - LinkedList ll = new LinkedList(); - Assert.IsFalse(ll.Contains("Foo")); - - ll = new LinkedList(); - Assert.IsFalse(ll.Contains(null)); - ll.Add("Foo"); - ll.Add(null); - ll.Add("Bar"); - Assert.IsTrue(ll.Contains(null)); - Assert.IsTrue(ll.Contains("Bar")); - Assert.IsTrue(ll.Contains("Foo")); + [Test] + public void Contains() + { + LinkedList ll = new LinkedList(); + Assert.IsFalse(ll.Contains("Foo")); - ll = new LinkedList(); - ll.Add("Foo"); - ll.Add("Bar"); - Assert.IsFalse(ll.Contains(null)); - } - } + ll = new LinkedList(); + Assert.IsFalse(ll.Contains(null)); + ll.Add("Foo"); + ll.Add(null); + ll.Add("Bar"); + Assert.IsTrue(ll.Contains(null)); + Assert.IsTrue(ll.Contains("Bar")); + Assert.IsTrue(ll.Contains("Foo")); + + ll = new LinkedList(); + ll.Add("Foo"); + ll.Add("Bar"); + Assert.IsFalse(ll.Contains(null)); + } } diff --git a/test/Spring/Spring.Core.Tests/Collections/ListSetTests.cs b/test/Spring/Spring.Core.Tests/Collections/ListSetTests.cs index 908fd55d..27c6e8e6 100644 --- a/test/Spring/Spring.Core.Tests/Collections/ListSetTests.cs +++ b/test/Spring/Spring.Core.Tests/Collections/ListSetTests.cs @@ -24,23 +24,22 @@ using NUnit.Framework; #endregion -namespace Spring.Collections +namespace Spring.Collections; + +/// +/// Unit tests for the ListSet class. +/// +/// Rick Evans +[TestFixture] +public class ListSetTests : SetTests { - /// - /// Unit tests for the ListSet class. + /// + /// The setup logic executed before the execution of each individual test. /// - /// Rick Evans - [TestFixture] - public class ListSetTests : SetTests + [SetUp] + public override void SetUp() { - /// - /// The setup logic executed before the execution of each individual test. - /// - [SetUp] - public override void SetUp () - { - Set = new ListSet (); - SetForSetOps = new ListSet (); - } - } + Set = new ListSet(); + SetForSetOps = new ListSet(); + } } diff --git a/test/Spring/Spring.Core.Tests/Collections/PriorityQueueTests.cs b/test/Spring/Spring.Core.Tests/Collections/PriorityQueueTests.cs index 848bb7df..1a27d707 100644 --- a/test/Spring/Spring.Core.Tests/Collections/PriorityQueueTests.cs +++ b/test/Spring/Spring.Core.Tests/Collections/PriorityQueueTests.cs @@ -3,448 +3,457 @@ using System.Runtime.Serialization.Formatters.Binary; using NUnit.Framework; using Spring.Util; -namespace Spring.Collections +namespace Spring.Collections; + +[TestFixture] +public class PriorityQueueTests { - [TestFixture] - public class PriorityQueueTests - { - protected static Int32 zero = Int32.Parse("0"); - protected static Int32 one = Int32.Parse("1"); - protected static Int32 two = Int32.Parse("2"); - protected static Int32 three = Int32.Parse("3"); - protected static Int32 four = Int32.Parse("4"); - protected static Int32 five = Int32.Parse("5"); - protected static Int32 six = Int32.Parse("6"); - protected static Int32 seven = Int32.Parse("7"); - protected static Int32 eight = Int32.Parse("8"); - protected static Int32 nine = Int32.Parse("9"); - protected static Int32 m1 = Int32.Parse("-1"); - protected static Int32 m2 = Int32.Parse("-2"); - protected static Int32 m3 = Int32.Parse("-3"); - protected static Int32 m4 = Int32.Parse("-4"); - protected static Int32 m5 = Int32.Parse("-5"); - protected static Int32 m10 = Int32.Parse("-10"); - private int SIZE = 20; + protected static Int32 zero = Int32.Parse("0"); + protected static Int32 one = Int32.Parse("1"); + protected static Int32 two = Int32.Parse("2"); + protected static Int32 three = Int32.Parse("3"); + protected static Int32 four = Int32.Parse("4"); + protected static Int32 five = Int32.Parse("5"); + protected static Int32 six = Int32.Parse("6"); + protected static Int32 seven = Int32.Parse("7"); + protected static Int32 eight = Int32.Parse("8"); + protected static Int32 nine = Int32.Parse("9"); + protected static Int32 m1 = Int32.Parse("-1"); + protected static Int32 m2 = Int32.Parse("-2"); + protected static Int32 m3 = Int32.Parse("-3"); + protected static Int32 m4 = Int32.Parse("-4"); + protected static Int32 m5 = Int32.Parse("-5"); + protected static Int32 m10 = Int32.Parse("-10"); + private int SIZE = 20; - internal class MyReverseComparator : IComparer - { - public virtual int Compare(Object x, Object y) - { - int i = (int)x; - int j = (int)y; - if (i < j) - return 1; - if (i > j) - return - 1; - return 0; - } - } + internal class MyReverseComparator : IComparer + { + public virtual int Compare(Object x, Object y) + { + int i = (int) x; + int j = (int) y; + if (i < j) + return 1; + if (i > j) + return -1; + return 0; + } + } - private PriorityQueue populatedQueue(int n) - { - PriorityQueue q = new PriorityQueue(n); - Assert.IsTrue((q.Count == 0)); - for (int i = n - 1; i >= 0; i -= 2) - Assert.IsTrue(q.Offer(i)); - for (int i = (n & 1); i < n; i += 2) - Assert.IsTrue(q.Offer(i)); - Assert.IsFalse((q.Count == 0)); - Assert.AreEqual(n, q.Count); - return q; - } + private PriorityQueue populatedQueue(int n) + { + PriorityQueue q = new PriorityQueue(n); + Assert.IsTrue((q.Count == 0)); + for (int i = n - 1; i >= 0; i -= 2) + Assert.IsTrue(q.Offer(i)); + for (int i = (n & 1); i < n; i += 2) + Assert.IsTrue(q.Offer(i)); + Assert.IsFalse((q.Count == 0)); + Assert.AreEqual(n, q.Count); + return q; + } - [Test] - public void CreateUnboundedQueue() - { - Assert.AreEqual(0, new PriorityQueue(SIZE).Count); - } + [Test] + public void CreateUnboundedQueue() + { + Assert.AreEqual(0, new PriorityQueue(SIZE).Count); + } - [Test] - public void ThrowsArgumentExceptionForZeroCapacity() - { - Assert.Throws(() => new PriorityQueue(0)); - } + [Test] + public void ThrowsArgumentExceptionForZeroCapacity() + { + Assert.Throws(() => new PriorityQueue(0)); + } - [Test] - public void ThrowsArgumentNullExceptionForNullCollection() - { - Assert.Throws(() => new PriorityQueue(null)); - } + [Test] + public void ThrowsArgumentNullExceptionForNullCollection() + { + Assert.Throws(() => new PriorityQueue(null)); + } - [Test] - public void ThrowsArgumentNullExceptionForNullCollectionElements() - { - object[] ints = new object[SIZE]; - Assert.Throws(() => new PriorityQueue(new ArrayList(ints))); - } + [Test] + public void ThrowsArgumentNullExceptionForNullCollectionElements() + { + object[] ints = new object[SIZE]; + Assert.Throws(() => new PriorityQueue(new ArrayList(ints))); + } - [Test] - public void ThrowsArgumentNullExceptionForSomeNullCollectionElements() - { - object[] ints = new object[SIZE]; - for (int i = 0; i < SIZE - 1; ++i) - ints[i] = i; - Assert.Throws(() => new PriorityQueue(new ArrayList(ints))); - } + [Test] + public void ThrowsArgumentNullExceptionForSomeNullCollectionElements() + { + object[] ints = new object[SIZE]; + for (int i = 0; i < SIZE - 1; ++i) + ints[i] = i; + Assert.Throws(() => new PriorityQueue(new ArrayList(ints))); + } - [Test] - public void ConstructorFromExistingCollection() - { - Int32[] ints = new Int32[SIZE]; - for (int i = 0; i < SIZE; ++i) - ints[i] = i; - PriorityQueue q = new PriorityQueue(new ArrayList(ints)); - for (int i = 0; i < SIZE; ++i) - Assert.AreEqual(ints[i], q.Poll()); - Assert.IsTrue( q.IsEmpty ); - } + [Test] + public void ConstructorFromExistingCollection() + { + Int32[] ints = new Int32[SIZE]; + for (int i = 0; i < SIZE; ++i) + ints[i] = i; + PriorityQueue q = new PriorityQueue(new ArrayList(ints)); + for (int i = 0; i < SIZE; ++i) + Assert.AreEqual(ints[i], q.Poll()); + Assert.IsTrue(q.IsEmpty); + } - [Test] - public void ConstructorUsingComparator() - { - MyReverseComparator cmp = new MyReverseComparator(); - PriorityQueue q = new PriorityQueue(SIZE, cmp); - Assert.AreEqual(cmp, q.Comparator()); - Int32[] ints = new Int32[SIZE]; - for (int i = 0; i < SIZE; ++i) - ints[i] = i; - q.AddAll(new ArrayList(ints)); - for (int i = SIZE - 1; i >= 0; --i) - Assert.AreEqual(ints[i], q.Poll()); - Assert.IsTrue( q.IsEmpty ); - } + [Test] + public void ConstructorUsingComparator() + { + MyReverseComparator cmp = new MyReverseComparator(); + PriorityQueue q = new PriorityQueue(SIZE, cmp); + Assert.AreEqual(cmp, q.Comparator()); + Int32[] ints = new Int32[SIZE]; + for (int i = 0; i < SIZE; ++i) + ints[i] = i; + q.AddAll(new ArrayList(ints)); + for (int i = SIZE - 1; i >= 0; --i) + Assert.AreEqual(ints[i], q.Poll()); + Assert.IsTrue(q.IsEmpty); + } - [Test] - public void IsEmpty() - { - PriorityQueue q = new PriorityQueue(2); - Assert.IsTrue( q.IsEmpty ); - q.Add(1); - Assert.IsFalse( q.IsEmpty ); - q.Add(2); - q.Remove(); - q.Remove(); - Assert.IsTrue( q.IsEmpty ); - } + [Test] + public void IsEmpty() + { + PriorityQueue q = new PriorityQueue(2); + Assert.IsTrue(q.IsEmpty); + q.Add(1); + Assert.IsFalse(q.IsEmpty); + q.Add(2); + q.Remove(); + q.Remove(); + Assert.IsTrue(q.IsEmpty); + } - [Test] - public void Size() - { - PriorityQueue q = populatedQueue(SIZE); - for (int i = 0; i < SIZE; ++i) - { - Assert.AreEqual(SIZE - i, q.Count); - q.Remove(); - } - for (int i = 0; i < SIZE; ++i) - { - Assert.AreEqual(i, q.Count); - q.Add(i); - } - } + [Test] + public void Size() + { + PriorityQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) + { + Assert.AreEqual(SIZE - i, q.Count); + q.Remove(); + } - [Test] - public void OfferWithNullObject() - { - PriorityQueue q = new PriorityQueue(1); - Assert.Throws(() => q.Offer(null)); - } + for (int i = 0; i < SIZE; ++i) + { + Assert.AreEqual(i, q.Count); + q.Add(i); + } + } - [Test] - public void AddWithNullObject() - { - PriorityQueue q = new PriorityQueue(1); - Assert.Throws(() => q.Add(null)); - } + [Test] + public void OfferWithNullObject() + { + PriorityQueue q = new PriorityQueue(1); + Assert.Throws(() => q.Offer(null)); + } - [Test] - public void OfferWithComparableElements() - { - PriorityQueue q = new PriorityQueue(1); - Assert.IsTrue(q.Offer(zero)); - Assert.IsTrue(q.Offer(one)); - } + [Test] + public void AddWithNullObject() + { + PriorityQueue q = new PriorityQueue(1); + Assert.Throws(() => q.Add(null)); + } - [Test] - public void OfferNonComparable() - { - PriorityQueue q = new PriorityQueue(1); - q.Offer(new Object()); - Assert.Throws(() => q.Offer(new Object())); - } + [Test] + public void OfferWithComparableElements() + { + PriorityQueue q = new PriorityQueue(1); + Assert.IsTrue(q.Offer(zero)); + Assert.IsTrue(q.Offer(one)); + } - [Test] - public void AddWithComparableElements() - { - PriorityQueue q = new PriorityQueue(SIZE); - for (int i = 0; i < SIZE; ++i) - { - Assert.AreEqual(i, q.Count); - Assert.IsTrue(q.Add(i)); - } - } + [Test] + public void OfferNonComparable() + { + PriorityQueue q = new PriorityQueue(1); + q.Offer(new Object()); + Assert.Throws(() => q.Offer(new Object())); + } - [Test] - public void AddAllWithNullElements() - { - PriorityQueue q = new PriorityQueue(1); - Assert.Throws(() => q.AddAll(null)); - } + [Test] + public void AddWithComparableElements() + { + PriorityQueue q = new PriorityQueue(SIZE); + for (int i = 0; i < SIZE; ++i) + { + Assert.AreEqual(i, q.Count); + Assert.IsTrue(q.Add(i)); + } + } - [Test] - public void AddAllWithCollectionWithNullElements() - { - PriorityQueue q = new PriorityQueue(SIZE); - object[] ints = new object[SIZE]; - Assert.Throws(() => q.AddAll(new ArrayList(ints))); - } + [Test] + public void AddAllWithNullElements() + { + PriorityQueue q = new PriorityQueue(1); + Assert.Throws(() => q.AddAll(null)); + } - [Test] - public void AddAllWithCollectionWithSomeNullElements() - { - PriorityQueue q = new PriorityQueue(SIZE); - object[] ints = new object[SIZE]; - for (int i = 0; i < SIZE - 1; ++i) - ints[i] = i; - Assert.Throws(() => q.AddAll(new ArrayList(ints))); - } + [Test] + public void AddAllWithCollectionWithNullElements() + { + PriorityQueue q = new PriorityQueue(SIZE); + object[] ints = new object[SIZE]; + Assert.Throws(() => q.AddAll(new ArrayList(ints))); + } - [Test] - public void AddAllWithCollection() - { - Int32[] empty = new Int32[0]; - Int32[] ints = new Int32[SIZE]; - for (int i = 0; i < SIZE; ++i) - ints[i] = (SIZE - 1 - i); - PriorityQueue q = new PriorityQueue(SIZE); - Assert.IsFalse(q.AddAll(new ArrayList(empty))); - Assert.IsTrue(q.AddAll(new ArrayList(ints))); - for (int i = 0; i < SIZE; ++i) - Assert.AreEqual(i, q.Poll()); - } + [Test] + public void AddAllWithCollectionWithSomeNullElements() + { + PriorityQueue q = new PriorityQueue(SIZE); + object[] ints = new object[SIZE]; + for (int i = 0; i < SIZE - 1; ++i) + ints[i] = i; + Assert.Throws(() => q.AddAll(new ArrayList(ints))); + } - [Test] - public void Poll() - { - PriorityQueue q = populatedQueue(SIZE); - for (int i = 0; i < SIZE; ++i) - { - Assert.AreEqual(i, (q.Poll())); - } - Assert.IsNull(q.Poll()); - } + [Test] + public void AddAllWithCollection() + { + Int32[] empty = new Int32[0]; + Int32[] ints = new Int32[SIZE]; + for (int i = 0; i < SIZE; ++i) + ints[i] = (SIZE - 1 - i); + PriorityQueue q = new PriorityQueue(SIZE); + Assert.IsFalse(q.AddAll(new ArrayList(empty))); + Assert.IsTrue(q.AddAll(new ArrayList(ints))); + for (int i = 0; i < SIZE; ++i) + Assert.AreEqual(i, q.Poll()); + } - [Test] - public void Peek() - { - PriorityQueue q = populatedQueue(SIZE); - for (int i = 0; i < SIZE; ++i) - { - Assert.AreEqual(i, (q.Peek())); - q.Poll(); - Assert.IsTrue(q.Peek() == null || i != (int)(q.Peek())); - } - Assert.IsNull(q.Peek()); - } + [Test] + public void Poll() + { + PriorityQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) + { + Assert.AreEqual(i, (q.Poll())); + } - [Test] - public void Element() - { - PriorityQueue q = populatedQueue(SIZE); - for (int i = 0; i < SIZE; ++i) - { - Assert.AreEqual(i, (q.Element())); - q.Poll(); - } - Assert.Throws(() => q.Element()); - } + Assert.IsNull(q.Poll()); + } - [Test] - public void Remove() - { - PriorityQueue q = populatedQueue(SIZE); - for (int i = 0; i < SIZE; ++i) - { - Assert.AreEqual(i, (q.Remove())); - } - Assert.Throws(() => q.Remove()); - } + [Test] + public void Peek() + { + PriorityQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) + { + Assert.AreEqual(i, (q.Peek())); + q.Poll(); + Assert.IsTrue(q.Peek() == null || i != (int) (q.Peek())); + } - [Test] - public void RemoveElement() - { - PriorityQueue q = populatedQueue(SIZE); - for (int i = 1; i < SIZE; i += 2) - { - Assert.IsTrue(q.Remove(i)); - } - for (int i = 0; i < SIZE; i += 2) - { - Assert.IsTrue(q.Remove(i)); - Assert.IsFalse(q.Remove((i + 1))); - } - Assert.IsTrue((q.Count == 0)); - } + Assert.IsNull(q.Peek()); + } - [Test] - public void Contains() - { - PriorityQueue q = populatedQueue(SIZE); - for (int i = 0; i < SIZE; ++i) - { - Assert.IsTrue(CollectionUtils.Contains(q, i)); - q.Poll(); - Assert.IsFalse(CollectionUtils.Contains(q, i)); - } - } + [Test] + public void Element() + { + PriorityQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) + { + Assert.AreEqual(i, (q.Element())); + q.Poll(); + } - [Test] - public void Clear() - { - PriorityQueue q = populatedQueue(SIZE); - q.Clear(); - Assert.IsTrue((q.Count == 0)); - Assert.AreEqual(0, q.Count); - q.Add(1); - Assert.IsFalse((q.Count == 0)); - q.Clear(); - Assert.IsTrue((q.Count == 0)); - } + Assert.Throws(() => q.Element()); + } - [Test] - public void ContainsAll() - { - PriorityQueue q = populatedQueue(SIZE); - PriorityQueue p = new PriorityQueue(SIZE); - for (int i = 0; i < SIZE; ++i) - { - Assert.IsTrue(CollectionUtils.ContainsAll(q, p)); - Assert.IsFalse(CollectionUtils.ContainsAll(p, q)); - p.Add(i); - } - Assert.IsTrue(CollectionUtils.ContainsAll(p, q)); - } + [Test] + public void Remove() + { + PriorityQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) + { + Assert.AreEqual(i, (q.Remove())); + } - [Test] - public void RemoveAll() - { - for (int i = 1; i < SIZE; ++i) - { - PriorityQueue q = populatedQueue(SIZE); - PriorityQueue p = populatedQueue(i); - CollectionUtils.RemoveAll(q, p); - Assert.AreEqual(SIZE - i, q.Count); - for (int j = 0; j < i; ++j) - { - Int32 I = (int) p.Remove(); - Assert.IsFalse(CollectionUtils.Contains(q, I)); - } - } - } + Assert.Throws(() => q.Remove()); + } - [Test] - public void ToArrayObject() - { - PriorityQueue q = populatedQueue(SIZE); - Object[] o = (Object[]) CollectionUtils.ToArrayList(q).ToArray(typeof (object)); - Array.Sort(o); - for (int i = 0; i < o.Length; i++) - Assert.AreEqual(o[i], q.Poll()); - } + [Test] + public void RemoveElement() + { + PriorityQueue q = populatedQueue(SIZE); + for (int i = 1; i < SIZE; i += 2) + { + Assert.IsTrue(q.Remove(i)); + } - [Test] - public void ToArrayNonObject() - { - PriorityQueue q = populatedQueue(SIZE); - Int32[] ints = (Int32[]) CollectionUtils.ToArrayList(q).ToArray(typeof (int)); - Array.Sort(ints); - for (int i = 0; i < ints.Length; i++) - Assert.AreEqual(ints[i], q.Poll()); - } + for (int i = 0; i < SIZE; i += 2) + { + Assert.IsTrue(q.Remove(i)); + Assert.IsFalse(q.Remove((i + 1))); + } - [Test] - public void Iterator() - { - PriorityQueue q = populatedQueue(SIZE); - int i = 0; - IEnumerator it = q.GetEnumerator(); - while (it.MoveNext()) - { - Assert.IsTrue(CollectionUtils.Contains(q, it.Current)); - ++i; - } - Assert.AreEqual(i, SIZE); - } + Assert.IsTrue((q.Count == 0)); + } - [Test] - public void Serialization() - { - PriorityQueue q = populatedQueue(SIZE); - MemoryStream bout = new MemoryStream(10000); + [Test] + public void Contains() + { + PriorityQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) + { + Assert.IsTrue(CollectionUtils.Contains(q, i)); + q.Poll(); + Assert.IsFalse(CollectionUtils.Contains(q, i)); + } + } - BinaryFormatter formatter = new BinaryFormatter(); - formatter.Serialize(bout, q); + [Test] + public void Clear() + { + PriorityQueue q = populatedQueue(SIZE); + q.Clear(); + Assert.IsTrue((q.Count == 0)); + Assert.AreEqual(0, q.Count); + q.Add(1); + Assert.IsFalse((q.Count == 0)); + q.Clear(); + Assert.IsTrue((q.Count == 0)); + } - MemoryStream bin = new MemoryStream(bout.ToArray()); - BinaryFormatter formatter2 = new BinaryFormatter(); + [Test] + public void ContainsAll() + { + PriorityQueue q = populatedQueue(SIZE); + PriorityQueue p = new PriorityQueue(SIZE); + for (int i = 0; i < SIZE; ++i) + { + Assert.IsTrue(CollectionUtils.ContainsAll(q, p)); + Assert.IsFalse(CollectionUtils.ContainsAll(p, q)); + p.Add(i); + } - PriorityQueue r = (PriorityQueue) formatter2.Deserialize(bin); + Assert.IsTrue(CollectionUtils.ContainsAll(p, q)); + } - Assert.AreEqual(q.Count, r.Count); - while (!(q.Count == 0)) - Assert.AreEqual(q.Remove(), r.Remove()); - } + [Test] + public void RemoveAll() + { + for (int i = 1; i < SIZE; ++i) + { + PriorityQueue q = populatedQueue(SIZE); + PriorityQueue p = populatedQueue(i); + CollectionUtils.RemoveAll(q, p); + Assert.AreEqual(SIZE - i, q.Count); + for (int j = 0; j < i; ++j) + { + Int32 I = (int) p.Remove(); + Assert.IsFalse(CollectionUtils.Contains(q, I)); + } + } + } - [Test] - public void QueueCopyToArrayWithSmallerDestinationArray() - { - PriorityQueue source = populatedQueue(SIZE); - object[] dest = new object[SIZE / 2]; - Assert.Throws(() => source.CopyTo(dest)); - } + [Test] + public void ToArrayObject() + { + PriorityQueue q = populatedQueue(SIZE); + Object[] o = (Object[]) CollectionUtils.ToArrayList(q).ToArray(typeof(object)); + Array.Sort(o); + for (int i = 0; i < o.Length; i++) + Assert.AreEqual(o[i], q.Poll()); + } - [Test] - public void QueueCopyToArrayWithIndexOutOfDestinationArrayRange() - { - PriorityQueue source = populatedQueue(SIZE); - object[] dest = new object[SIZE / 2]; - Assert.Throws(() => source.CopyTo(dest, 11)); - } + [Test] + public void ToArrayNonObject() + { + PriorityQueue q = populatedQueue(SIZE); + Int32[] ints = (Int32[]) CollectionUtils.ToArrayList(q).ToArray(typeof(int)); + Array.Sort(ints); + for (int i = 0; i < ints.Length; i++) + Assert.AreEqual(ints[i], q.Poll()); + } - [Test] - public void QueueCopyToArrayWithValidSizeButInvalidStartingIndex() - { - PriorityQueue source = populatedQueue(SIZE); - object[] dest = new object[SIZE]; - Assert.Throws(() => source.CopyTo(dest, 10)); - } + [Test] + public void Iterator() + { + PriorityQueue q = populatedQueue(SIZE); + int i = 0; + IEnumerator it = q.GetEnumerator(); + while (it.MoveNext()) + { + Assert.IsTrue(CollectionUtils.Contains(q, it.Current)); + ++i; + } - [Test] - public void CompleteQueueCopyToArrayWithValidSize() - { - PriorityQueue source = populatedQueue(SIZE); - object[] dest = new object[SIZE]; - source.CopyTo(dest); - for (int i = 0; i < SIZE; i++) - { - Assert.AreEqual(source.Poll(), dest[i]); - } - } + Assert.AreEqual(i, SIZE); + } - [Test] - public void PartialQueueCopyToArrayWithValidSize() - { - PriorityQueue source = populatedQueue(SIZE); - object[] dest = new object[SIZE*2]; - source.CopyTo(dest, SIZE / 2); - for ( int i = 0; i < SIZE; i++ ) - { - Assert.IsNull(dest[i]); - } - for ( int i = SIZE; i < SIZE / 2; i++ ) - { - Assert.AreEqual(dest[i], i - SIZE / 2 ); - } - } - } -} \ No newline at end of file + [Test] + public void Serialization() + { + PriorityQueue q = populatedQueue(SIZE); + MemoryStream bout = new MemoryStream(10000); + + BinaryFormatter formatter = new BinaryFormatter(); + formatter.Serialize(bout, q); + + MemoryStream bin = new MemoryStream(bout.ToArray()); + BinaryFormatter formatter2 = new BinaryFormatter(); + + PriorityQueue r = (PriorityQueue) formatter2.Deserialize(bin); + + Assert.AreEqual(q.Count, r.Count); + while (!(q.Count == 0)) + Assert.AreEqual(q.Remove(), r.Remove()); + } + + [Test] + public void QueueCopyToArrayWithSmallerDestinationArray() + { + PriorityQueue source = populatedQueue(SIZE); + object[] dest = new object[SIZE / 2]; + Assert.Throws(() => source.CopyTo(dest)); + } + + [Test] + public void QueueCopyToArrayWithIndexOutOfDestinationArrayRange() + { + PriorityQueue source = populatedQueue(SIZE); + object[] dest = new object[SIZE / 2]; + Assert.Throws(() => source.CopyTo(dest, 11)); + } + + [Test] + public void QueueCopyToArrayWithValidSizeButInvalidStartingIndex() + { + PriorityQueue source = populatedQueue(SIZE); + object[] dest = new object[SIZE]; + Assert.Throws(() => source.CopyTo(dest, 10)); + } + + [Test] + public void CompleteQueueCopyToArrayWithValidSize() + { + PriorityQueue source = populatedQueue(SIZE); + object[] dest = new object[SIZE]; + source.CopyTo(dest); + for (int i = 0; i < SIZE; i++) + { + Assert.AreEqual(source.Poll(), dest[i]); + } + } + + [Test] + public void PartialQueueCopyToArrayWithValidSize() + { + PriorityQueue source = populatedQueue(SIZE); + object[] dest = new object[SIZE * 2]; + source.CopyTo(dest, SIZE / 2); + for (int i = 0; i < SIZE; i++) + { + Assert.IsNull(dest[i]); + } + + for (int i = SIZE; i < SIZE / 2; i++) + { + Assert.AreEqual(dest[i], i - SIZE / 2); + } + } +} diff --git a/test/Spring/Spring.Core.Tests/Collections/SetTests.cs b/test/Spring/Spring.Core.Tests/Collections/SetTests.cs index 96fd0ea1..e15a8eca 100644 --- a/test/Spring/Spring.Core.Tests/Collections/SetTests.cs +++ b/test/Spring/Spring.Core.Tests/Collections/SetTests.cs @@ -24,312 +24,314 @@ using NUnit.Framework; #endregion -namespace Spring.Collections +namespace Spring.Collections; + +/// +/// Base class for tests on the +/// interface. +/// +/// +///

+/// This defines a set of tests that exercise the contract of the set interface. +/// Subclasses need only supply a concrete ISET imnplementation instance... this +/// instance must be set on the Set property exposed by this class in the +/// SetUp method. The Set instance must be empty for the start of each new test. +///

+///

+/// The SetForSetOps needs to be set during the SetUp method too. +///

+///
+/// Rick Evans +public abstract class SetTests { - /// - /// Base class for tests on the - /// interface. + protected static readonly object StuffOne = "This Is"; + + protected static readonly object StuffTwo = "Uncle"; + + protected static readonly object StuffThree = "Bob"; + + protected readonly object[] UniqueStuff = new object[] { StuffOne, StuffTwo, StuffThree }; + + protected readonly object[] DuplicatedStuff = new object[] { StuffOne, StuffTwo, StuffTwo }; + + /// + /// The setup logic executed before the execution of each individual test. + /// + public abstract void SetUp(); + + /// + /// The tear down logic executed after the execution of each individual test. + /// + [TearDown] + public virtual void TearDown() + { + Set = null; + SetForSetOps = null; + } + + [Test] + public void Union() + { + Set.AddAll(UniqueStuff); + SetForSetOps.AddAll(new object[] { "Bar", StuffOne }); + ISet union = Set.Union(SetForSetOps); + Assert.IsTrue(union.Count == UniqueStuff.Length + 1); + Assert.IsFalse(object.ReferenceEquals(union, Set), "Got back same instance after set operation."); + Assert.IsTrue(Set.Count == UniqueStuff.Length); + Assert.IsTrue(SetForSetOps.Count == 2); + } + + [Test] + public void Intersect() + { + Set.AddAll(UniqueStuff); + SetForSetOps.AddAll(new object[] { "Bar", StuffOne }); + ISet intersection = Set.Intersect(SetForSetOps); + Assert.IsTrue(intersection.Count == 1); + Assert.IsFalse(object.ReferenceEquals(intersection, Set), "Got back same instance after set operation."); + Assert.IsTrue(Set.Count == UniqueStuff.Length); + Assert.IsTrue(SetForSetOps.Count == 2); + } + + [Test] + public void Minus() + { + Set.AddAll(UniqueStuff); + SetForSetOps.AddAll(new object[] { "Bar", StuffOne }); + ISet minus = Set.Minus(SetForSetOps); + Assert.IsTrue(minus.Count == UniqueStuff.Length - 1); + Assert.IsFalse(object.ReferenceEquals(minus, Set), "Got back same instance after set operation."); + Assert.IsTrue(Set.Count == UniqueStuff.Length); + Assert.IsTrue(SetForSetOps.Count == 2); + } + + [Test] + public void ExclusiveOr() + { + Set.AddAll(UniqueStuff); + SetForSetOps.AddAll(new object[] { "Bar", StuffOne }); + ISet xor = Set.ExclusiveOr(SetForSetOps); + Assert.IsTrue(xor.Count == 3); + Assert.IsTrue(xor.ContainsAll(new object[] { "Bar", StuffTwo, StuffThree })); + Assert.IsFalse(object.ReferenceEquals(xor, Set), "Got back same instance after set operation."); + Assert.IsTrue(Set.Count == UniqueStuff.Length); + Assert.IsTrue(SetForSetOps.Count == 2); + } + + [Test] + public void Contains() + { + Set.AddAll(UniqueStuff); + Assert.IsTrue(Set.Contains(StuffThree)); + Assert.IsFalse(Set.Contains("SourDough")); + } + + [Test] + public void ContainsAll() + { + Set.AddAll(UniqueStuff); + Assert.IsTrue(Set.ContainsAll(new object[] { StuffThree, StuffTwo, StuffOne })); + } + + [Test] + public void IsEmpty() + { + Set.Add(StuffOne); + Set.Remove(StuffOne); + Assert.IsTrue(Set.IsEmpty); + } + + [Test] + public void Add() + { + Assert.IsTrue(Set.Add(StuffOne)); + Assert.IsTrue(Set.Count == 1, "Added 1 unique item, but the Count property wasn't sitting at 1."); + } + + [Test] + public void AddNull() + { + if (SupportsNull) + { + Assert.IsTrue(Set.Add(StuffOne)); + Assert.IsTrue(Set.Add(null)); + Assert.IsTrue(Set.Count == 2, "Added 2 unique item (one null), but the Count property wasn't sitting at 2."); + Assert.IsFalse(Set.Add(null)); + Assert.IsTrue(Set.Count == 2, "Added null to a set already containing null, but the Count property changed."); + } + } + + [Test] + public void EnumeratesNull() + { + if (SupportsNull) + { + Set.AddAll(new object[] { StuffOne, null, StuffTwo }); + bool gotNull = false; + foreach (object o in Set) + { + if (o == null) + { + gotNull = true; + break; + } + } + + Assert.IsTrue(gotNull, "Stuffed a null value into the set but didn't get it back when enumerating over the set."); + } + } + + [Test] + public void CopiesNull() + { + if (SupportsNull) + { + object[] expected = new object[] { StuffOne, null, StuffTwo }; + Set.AddAll(expected); + object[] actual = new object [expected.Length]; + Set.CopyTo(actual, 0); + bool gotNull = false; + foreach (object o in actual) + { + if (o == null) + { + gotNull = true; + break; + } + } + + Assert.IsTrue(gotNull, "Copied a set with a null value into an array, but the resulting array did not contain a a null."); + } + } + + [Test] + public void AddDuplicate() + { + Set.Add(StuffOne); + Assert.IsFalse(Set.Add(StuffOne)); + Assert.IsTrue(Set.Count == 1, "Added 2 duplicate items, but the Count property wasn't sitting at 1."); + } + + [Test] + public void AddAll() + { + Assert.IsTrue(Set.AddAll(UniqueStuff)); + Assert.IsTrue(Set.Count == UniqueStuff.Length, "Added 3 unique items, but the Count property wasn't sitting at 3."); + } + + [Test] + public void AddAllDuplicated() + { + Assert.IsTrue(Set.AddAll(DuplicatedStuff)); + Assert.IsTrue(Set.Count == 2, "Added 3 (2 duplicated) items, but the Count property wasn't sitting at 2."); + } + + [Test] + public void Remove() + { + Set.AddAll(UniqueStuff); + Set.Remove(StuffOne); + Assert.IsTrue(Set.Count == (UniqueStuff.Length - 1)); + Assert.IsFalse(Set.Contains(StuffOne)); + Assert.IsTrue(Set.Contains(StuffTwo)); + Assert.IsTrue(Set.Contains(StuffThree)); + } + + [Test] + public void RemoveNull() + { + if (SupportsNull) + { + Set.AddAll(UniqueStuff); + Assert.IsFalse(Set.Remove(null)); + Set.Add(null); + Assert.IsTrue(Set.Remove(null)); + } + } + + [Test] + public void RemoveAll() + { + Set.AddAll(UniqueStuff); + object[] removed = new object[] { StuffOne, StuffTwo }; + Set.RemoveAll(removed); + Assert.IsTrue(Set.Count == (UniqueStuff.Length - removed.Length)); + Assert.IsFalse(Set.Contains(StuffOne)); + Assert.IsFalse(Set.Contains(StuffTwo)); + Assert.IsTrue(Set.Contains(StuffThree)); + } + + [Test] + public void RetainAll() + { + Set.AddAll(UniqueStuff); + Set.RetainAll(new object[] { StuffOne, StuffTwo }); + Assert.IsTrue(Set.Count == 2); + Assert.IsTrue(Set.Contains(StuffOne)); + Assert.IsTrue(Set.Contains(StuffTwo)); + Assert.IsFalse(Set.Contains(StuffThree)); + } + + [Test] + public void Clear() + { + Set.AddAll(UniqueStuff); + Set.Clear(); + Assert.IsTrue(Set.Count == 0, "Calling Clear () did not remove all of the elements."); + } + + /// + /// The ISet being tested. + /// + protected virtual ISet Set + { + get + { + return _set; + } + set + { + _set = value; + } + } + + /// + /// An extra ISet instance for use during the set operation tests. + /// + protected virtual ISet SetForSetOps + { + get + { + return _setForSetOps; + } + set + { + _setForSetOps = value; + } + } + + /// + /// Does the Set being tested support the addition of null values? /// /// ///

- /// This defines a set of tests that exercise the contract of the set interface. - /// Subclasses need only supply a concrete ISET imnplementation instance... this - /// instance must be set on the Set property exposed by this class in the - /// SetUp method. The Set instance must be empty for the start of each new test. - ///

- ///

- /// The SetForSetOps needs to be set during the SetUp method too. + /// If true, then the tests that test the handling of the null value + /// will be executed. ///

///
- /// Rick Evans - public abstract class SetTests + protected bool SupportsNull { - protected static readonly object StuffOne = "This Is"; - - protected static readonly object StuffTwo = "Uncle"; - - protected static readonly object StuffThree = "Bob"; - - protected readonly object [] UniqueStuff = new object [] {StuffOne, StuffTwo, StuffThree}; - - protected readonly object [] DuplicatedStuff = new object [] {StuffOne, StuffTwo, StuffTwo}; - - /// - /// The setup logic executed before the execution of each individual test. - /// - public abstract void SetUp (); - - /// - /// The tear down logic executed after the execution of each individual test. - /// - [TearDown] - public virtual void TearDown () { - Set = null; - SetForSetOps = null; - } - - [Test] - public void Union() + get { - Set.AddAll (UniqueStuff); - SetForSetOps.AddAll (new object [] {"Bar", StuffOne}); - ISet union = Set.Union (SetForSetOps); - Assert.IsTrue (union.Count == UniqueStuff.Length + 1); - Assert.IsFalse (object.ReferenceEquals (union, Set), "Got back same instance after set operation."); - Assert.IsTrue (Set.Count == UniqueStuff.Length); - Assert.IsTrue (SetForSetOps.Count == 2); + return _setSupportsNullValue; } - - [Test] - public void Intersect() + set { - Set.AddAll (UniqueStuff); - SetForSetOps.AddAll (new object [] {"Bar", StuffOne}); - ISet intersection = Set.Intersect (SetForSetOps); - Assert.IsTrue (intersection.Count == 1); - Assert.IsFalse (object.ReferenceEquals (intersection, Set), "Got back same instance after set operation."); - Assert.IsTrue (Set.Count == UniqueStuff.Length); - Assert.IsTrue (SetForSetOps.Count == 2); + _setSupportsNullValue = value; } + } - [Test] - public void Minus() - { - Set.AddAll (UniqueStuff); - SetForSetOps.AddAll (new object [] {"Bar", StuffOne}); - ISet minus = Set.Minus (SetForSetOps); - Assert.IsTrue (minus.Count == UniqueStuff.Length - 1); - Assert.IsFalse (object.ReferenceEquals (minus, Set), "Got back same instance after set operation."); - Assert.IsTrue (Set.Count == UniqueStuff.Length); - Assert.IsTrue (SetForSetOps.Count == 2); - } - - [Test] - public void ExclusiveOr() - { - Set.AddAll (UniqueStuff); - SetForSetOps.AddAll (new object [] {"Bar", StuffOne}); - ISet xor = Set.ExclusiveOr (SetForSetOps); - Assert.IsTrue (xor.Count == 3); - Assert.IsTrue (xor.ContainsAll (new object [] {"Bar", StuffTwo, StuffThree})); - Assert.IsFalse (object.ReferenceEquals (xor, Set), "Got back same instance after set operation."); - Assert.IsTrue (Set.Count == UniqueStuff.Length); - Assert.IsTrue (SetForSetOps.Count == 2); - } - - [Test] - public void Contains() - { - Set.AddAll (UniqueStuff); - Assert.IsTrue (Set.Contains (StuffThree)); - Assert.IsFalse (Set.Contains ("SourDough")); - } - - [Test] - public void ContainsAll() - { - Set.AddAll (UniqueStuff); - Assert.IsTrue (Set.ContainsAll (new object [] {StuffThree, StuffTwo, StuffOne})); - } - - [Test] - public void IsEmpty () - { - Set.Add (StuffOne); - Set.Remove (StuffOne); - Assert.IsTrue (Set.IsEmpty); - } - - [Test] - public void Add() - { - Assert.IsTrue (Set.Add (StuffOne)); - Assert.IsTrue (Set.Count == 1, "Added 1 unique item, but the Count property wasn't sitting at 1."); - } - - [Test] - public void AddNull() - { - if (SupportsNull) - { - Assert.IsTrue (Set.Add (StuffOne)); - Assert.IsTrue (Set.Add (null)); - Assert.IsTrue (Set.Count == 2, "Added 2 unique item (one null), but the Count property wasn't sitting at 2."); - Assert.IsFalse (Set.Add (null)); - Assert.IsTrue (Set.Count == 2, "Added null to a set already containing null, but the Count property changed."); - } - } - - [Test] - public void EnumeratesNull() - { - if (SupportsNull) - { - Set.AddAll (new object [] {StuffOne, null, StuffTwo}); - bool gotNull = false; - foreach (object o in Set) - { - if (o == null) - { - gotNull = true; - break; - } - } - Assert.IsTrue (gotNull, "Stuffed a null value into the set but didn't get it back when enumerating over the set."); - } - } - - [Test] - public void CopiesNull () - { - if (SupportsNull) - { - object [] expected = new object [] {StuffOne, null, StuffTwo}; - Set.AddAll (expected); - object [] actual = new object [expected.Length]; - Set.CopyTo (actual, 0); - bool gotNull = false; - foreach (object o in actual) - { - if (o == null) - { - gotNull = true; - break; - } - } - Assert.IsTrue (gotNull, "Copied a set with a null value into an array, but the resulting array did not contain a a null."); - } - } - - [Test] - public void AddDuplicate() - { - Set.Add (StuffOne); - Assert.IsFalse (Set.Add (StuffOne)); - Assert.IsTrue (Set.Count == 1, "Added 2 duplicate items, but the Count property wasn't sitting at 1."); - } - - [Test] - public void AddAll() - { - Assert.IsTrue (Set.AddAll (UniqueStuff)); - Assert.IsTrue (Set.Count == UniqueStuff.Length, "Added 3 unique items, but the Count property wasn't sitting at 3."); - } - - [Test] - public void AddAllDuplicated() - { - Assert.IsTrue (Set.AddAll (DuplicatedStuff)); - Assert.IsTrue (Set.Count == 2, "Added 3 (2 duplicated) items, but the Count property wasn't sitting at 2."); - } - - [Test] - public void Remove() - { - Set.AddAll (UniqueStuff); - Set.Remove (StuffOne); - Assert.IsTrue (Set.Count == (UniqueStuff.Length - 1)); - Assert.IsFalse (Set.Contains (StuffOne)); - Assert.IsTrue (Set.Contains (StuffTwo)); - Assert.IsTrue (Set.Contains (StuffThree)); - } - - [Test] - public void RemoveNull() - { - if (SupportsNull) - { - Set.AddAll (UniqueStuff); - Assert.IsFalse (Set.Remove (null)); - Set.Add (null); - Assert.IsTrue (Set.Remove (null)); - } - } - - [Test] - public void RemoveAll() - { - Set.AddAll (UniqueStuff); - object [] removed = new object [] {StuffOne, StuffTwo}; - Set.RemoveAll (removed); - Assert.IsTrue (Set.Count == (UniqueStuff.Length - removed.Length)); - Assert.IsFalse (Set.Contains (StuffOne)); - Assert.IsFalse (Set.Contains (StuffTwo)); - Assert.IsTrue (Set.Contains (StuffThree)); - } - - [Test] - public void RetainAll() - { - Set.AddAll (UniqueStuff); - Set.RetainAll (new object [] {StuffOne, StuffTwo}); - Assert.IsTrue (Set.Count == 2); - Assert.IsTrue (Set.Contains (StuffOne)); - Assert.IsTrue (Set.Contains (StuffTwo)); - Assert.IsFalse (Set.Contains (StuffThree)); - } - - [Test] - public void Clear() - { - Set.AddAll (UniqueStuff); - Set.Clear (); - Assert.IsTrue (Set.Count == 0, "Calling Clear () did not remove all of the elements."); - } - - /// - /// The ISet being tested. - /// - protected virtual ISet Set - { - get - { - return _set; - } - set - { - _set = value; - } - } - - /// - /// An extra ISet instance for use during the set operation tests. - /// - protected virtual ISet SetForSetOps - { - get - { - return _setForSetOps; - } - set - { - _setForSetOps = value; - } - } - - /// - /// Does the Set being tested support the addition of null values? - /// - /// - ///

- /// If true, then the tests that test the handling of the null value - /// will be executed. - ///

- ///
- protected bool SupportsNull - { - get - { - return _setSupportsNullValue; - } - set - { - _setSupportsNullValue = value; - } - } - - private ISet _set; - private ISet _setForSetOps; - private bool _setSupportsNullValue = true; - } -} + private ISet _set; + private ISet _setForSetOps; + private bool _setSupportsNullValue = true; +} \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/Collections/SortedSetTests.cs b/test/Spring/Spring.Core.Tests/Collections/SortedSetTests.cs index 588a9954..8fd7177b 100644 --- a/test/Spring/Spring.Core.Tests/Collections/SortedSetTests.cs +++ b/test/Spring/Spring.Core.Tests/Collections/SortedSetTests.cs @@ -24,40 +24,39 @@ using NUnit.Framework; #endregion -namespace Spring.Collections +namespace Spring.Collections; + +/// +/// Unit tests for the SortedSet class. +/// +/// Rick Evans +[TestFixture] +public class SortedSetTests : SetTests { - /// - /// Unit tests for the SortedSet class. - /// - /// Rick Evans - [TestFixture] - public class SortedSetTests : SetTests + [OneTimeSetUp] + public void Init() { - [OneTimeSetUp] - public void Init () - { - SupportsNull = false; - } + SupportsNull = false; + } - /// - /// The setup logic executed before the execution of each individual test. - /// - [SetUp] - public override void SetUp () - { - Set = new SortedSet (); - SetForSetOps = new SortedSet (); - } + /// + /// The setup logic executed before the execution of each individual test. + /// + [SetUp] + public override void SetUp() + { + Set = new SortedSet(); + SetForSetOps = new SortedSet(); + } - [Test] - public void IsOrdered () + [Test] + public void IsOrdered() + { + ISet mySet = new SortedSet(new int[] { 2, 4, 5, 1, 3, 0 }); + int j = 0; + foreach (object o in mySet) { - ISet mySet = new SortedSet (new int [] {2, 4, 5, 1, 3, 0}); - int j = 0; - foreach (object o in mySet) - { - Assert.AreEqual (j++, o, "Found element out of order while iterating over SortedSet"); - } + Assert.AreEqual(j++, o, "Found element out of order while iterating over SortedSet"); } } } diff --git a/test/Spring/Spring.Core.Tests/Collections/StaticSetTests.cs b/test/Spring/Spring.Core.Tests/Collections/StaticSetTests.cs index bea8670c..b0aeec7a 100644 --- a/test/Spring/Spring.Core.Tests/Collections/StaticSetTests.cs +++ b/test/Spring/Spring.Core.Tests/Collections/StaticSetTests.cs @@ -24,103 +24,102 @@ using NUnit.Framework; #endregion -namespace Spring.Collections +namespace Spring.Collections; + +/// +/// Unit tests for the static methods of the Set class. +/// +/// Rick Evans +[TestFixture] +public sealed class StaticSetTests { - /// - /// Unit tests for the static methods of the Set class. + /// + /// The setup logic executed before the execution of each individual test. /// - /// Rick Evans - [TestFixture] - public sealed class StaticSetTests + [SetUp] + public void SetUp() { - /// - /// The setup logic executed before the execution of each individual test. - /// - [SetUp] - public void SetUp () - { - one = new ListSet (new object [] {1, "Foo", 2}); - two = new ListSet (new object [] {1, 3}); - } + one = new ListSet(new object[] { 1, "Foo", 2 }); + two = new ListSet(new object[] { 1, 3 }); + } - [Test] - public void Xor () - { - ISet actual = Set.ExclusiveOr (one, two); - Assert.IsNotNull (actual); - Assert.AreEqual (3, actual.Count); - Assert.IsTrue (actual.ContainsAll (new object [] {"Foo", 2, 3})); - CheckThatOriginalsHaveNotBeenModified (); + [Test] + public void Xor() + { + ISet actual = Set.ExclusiveOr(one, two); + Assert.IsNotNull(actual); + Assert.AreEqual(3, actual.Count); + Assert.IsTrue(actual.ContainsAll(new object[] { "Foo", 2, 3 })); + CheckThatOriginalsHaveNotBeenModified(); - Assert.IsNull (Set.ExclusiveOr (null, null)); + Assert.IsNull(Set.ExclusiveOr(null, null)); - actual = Set.ExclusiveOr (null, two); - Assert.AreEqual (two, actual); + actual = Set.ExclusiveOr(null, two); + Assert.AreEqual(two, actual); - actual = Set.ExclusiveOr (one, null); - Assert.AreEqual (one, actual); - } + actual = Set.ExclusiveOr(one, null); + Assert.AreEqual(one, actual); + } - [Test] - public void Minus () - { - ISet actual = Set.Minus (one, two); - Assert.IsNotNull (actual); - Assert.AreEqual (2, actual.Count); - Assert.IsTrue (actual.ContainsAll (new object [] {"Foo", 2})); - CheckThatOriginalsHaveNotBeenModified (); + [Test] + public void Minus() + { + ISet actual = Set.Minus(one, two); + Assert.IsNotNull(actual); + Assert.AreEqual(2, actual.Count); + Assert.IsTrue(actual.ContainsAll(new object[] { "Foo", 2 })); + CheckThatOriginalsHaveNotBeenModified(); - Assert.IsNull (Set.Minus (null, two)); - } + Assert.IsNull(Set.Minus(null, two)); + } - [Test] - public void Union () - { - ISet actual = Set.Union (one, two); - Assert.IsNotNull (actual); - Assert.AreEqual (4, actual.Count); - Assert.IsTrue (actual.ContainsAll (new object [] {1, "Foo", 2, 3})); - CheckThatOriginalsHaveNotBeenModified (); + [Test] + public void Union() + { + ISet actual = Set.Union(one, two); + Assert.IsNotNull(actual); + Assert.AreEqual(4, actual.Count); + Assert.IsTrue(actual.ContainsAll(new object[] { 1, "Foo", 2, 3 })); + CheckThatOriginalsHaveNotBeenModified(); - Assert.IsNull (Set.Union (null, null)); + Assert.IsNull(Set.Union(null, null)); - actual = Set.Union (null, two); - Assert.AreEqual (two, actual); + actual = Set.Union(null, two); + Assert.AreEqual(two, actual); - actual = Set.Union (one, null); - Assert.AreEqual (one, actual); - } + actual = Set.Union(one, null); + Assert.AreEqual(one, actual); + } - [Test] - public void Intersect () - { - ISet actual = Set.Intersect (one, two); - Assert.IsNotNull (actual); - Assert.AreEqual (1, actual.Count); - Assert.IsTrue (actual.Contains (1)); - CheckThatOriginalsHaveNotBeenModified (); + [Test] + public void Intersect() + { + ISet actual = Set.Intersect(one, two); + Assert.IsNotNull(actual); + Assert.AreEqual(1, actual.Count); + Assert.IsTrue(actual.Contains(1)); + CheckThatOriginalsHaveNotBeenModified(); - Assert.IsNull (Set.Intersect (null, null)); + Assert.IsNull(Set.Intersect(null, null)); - actual = Set.Intersect (null, two); - Assert.AreEqual (0, actual.Count); + actual = Set.Intersect(null, two); + Assert.AreEqual(0, actual.Count); - actual = Set.Intersect (one, null); - Assert.AreEqual (0, actual.Count); - } + actual = Set.Intersect(one, null); + Assert.AreEqual(0, actual.Count); + } - private void CheckThatOriginalsHaveNotBeenModified () - { - Assert.IsNotNull (one, "Set operation modified the original sets."); - Assert.AreEqual (3, one.Count, "Set operation modified the original sets."); - Assert.IsTrue (one.ContainsAll (new object [] {1, "Foo", 2}), "Set operation modified the original sets."); + private void CheckThatOriginalsHaveNotBeenModified() + { + Assert.IsNotNull(one, "Set operation modified the original sets."); + Assert.AreEqual(3, one.Count, "Set operation modified the original sets."); + Assert.IsTrue(one.ContainsAll(new object[] { 1, "Foo", 2 }), "Set operation modified the original sets."); - Assert.IsNotNull (two, "Set operation modified the original sets."); - Assert.AreEqual (2, two.Count, "Set operation modified the original sets."); - Assert.IsTrue (two.ContainsAll (new object [] {1, 3}), "Set operation modified the original sets."); - } + Assert.IsNotNull(two, "Set operation modified the original sets."); + Assert.AreEqual(2, two.Count, "Set operation modified the original sets."); + Assert.IsTrue(two.ContainsAll(new object[] { 1, 3 }), "Set operation modified the original sets."); + } - private ISet one; - private ISet two; - } + private ISet one; + private ISet two; } diff --git a/test/Spring/Spring.Core.Tests/Collections/SynchronizedHashtableTests.cs b/test/Spring/Spring.Core.Tests/Collections/SynchronizedHashtableTests.cs index bc2f60e2..c524ecc2 100644 --- a/test/Spring/Spring.Core.Tests/Collections/SynchronizedHashtableTests.cs +++ b/test/Spring/Spring.Core.Tests/Collections/SynchronizedHashtableTests.cs @@ -21,171 +21,174 @@ #region Imports using System.Collections; - using NUnit.Framework; #endregion -namespace Spring.Collections +namespace Spring.Collections; + +/// +/// +/// +/// Erich Eichinger +/// $Id: $ +[TestFixture] +public class SynchronizedHashtableTests { - /// - /// - /// - /// Erich Eichinger - /// $Id: $ - [TestFixture] - public class SynchronizedHashtableTests + [Test] + public void BehavesLikeHashtable() { - [Test] - public void BehavesLikeHashtable() + SynchronizedHashtable st = new SynchronizedHashtable(); + st.Add("key", "value"); + Assert.AreEqual("value", st["key"]); + st["key"] = "value2"; + Assert.AreEqual("value2", st["key"]); + st["key2"] = "value3"; + Assert.AreEqual("value3", st["key2"]); + + try + { + st.Add("key", "value4"); + Assert.Fail(); + } + catch (ArgumentException) { - SynchronizedHashtable st = new SynchronizedHashtable(); - st.Add("key", "value"); - Assert.AreEqual("value", st["key"]); - st["key"] = "value2"; - Assert.AreEqual("value2", st["key"]); - st["key2"] = "value3"; - Assert.AreEqual("value3", st["key2"]); - - try - { - st.Add("key", "value4"); - Assert.Fail(); - } - catch(ArgumentException) - {} - - Assert.AreEqual(2, st.Count); } - [Test] - public void InitializeFromOtherCopiesValues() - { - Hashtable ht = new Hashtable(); - ht["key"] = "value"; - ht["key2"] = "value2"; + Assert.AreEqual(2, st.Count); + } - SynchronizedHashtable st = new SynchronizedHashtable(ht, false); - Assert.AreEqual(2, st.Count); - ht.Remove("key"); - Assert.AreEqual(1, ht.Count); - Assert.AreEqual(2, st.Count); + [Test] + public void InitializeFromOtherCopiesValues() + { + Hashtable ht = new Hashtable(); + ht["key"] = "value"; + ht["key2"] = "value2"; + + SynchronizedHashtable st = new SynchronizedHashtable(ht, false); + Assert.AreEqual(2, st.Count); + ht.Remove("key"); + Assert.AreEqual(1, ht.Count); + Assert.AreEqual(2, st.Count); + } + + [Test] + public void DefaultsToCaseSensitive() + { + SynchronizedHashtable st = new SynchronizedHashtable(); + st.Add("key", "value"); + st.Add("KEY", "value"); + Assert.AreEqual(2, st.Count); + } + + [Test] + public void IgnoreCaseIgnoresCase() + { + SynchronizedHashtable st = new SynchronizedHashtable(true); + st.Add("key", "value"); + Assert.AreEqual("value", st["KEY"]); + st["KeY"] = "value2"; + Assert.AreEqual(1, st.Count); + Assert.AreEqual("value2", st["key"]); + + try + { + st.Add("KEY", "value2"); + Assert.Fail(); + } + catch (ArgumentException) + { } - [Test] - public void DefaultsToCaseSensitive() + Hashtable ht = new Hashtable(); + ht.Add("key", "value"); + ht.Add("KEY", "value"); + try { - SynchronizedHashtable st = new SynchronizedHashtable(); - st.Add("key","value"); - st.Add("KEY","value"); - Assert.AreEqual(2, st.Count); + st = new SynchronizedHashtable(ht, true); + Assert.Fail(); } - - [Test] - public void IgnoreCaseIgnoresCase() + catch (ArgumentException) { - SynchronizedHashtable st = new SynchronizedHashtable(true); - st.Add("key", "value"); - Assert.AreEqual("value", st["KEY"]); - st["KeY"] = "value2"; - Assert.AreEqual(1, st.Count); - Assert.AreEqual("value2", st["key"]); - - try - { - st.Add("KEY", "value2"); - Assert.Fail(); - } - catch (ArgumentException) - {} - - Hashtable ht = new Hashtable(); - ht.Add("key","value"); - ht.Add("KEY","value"); - try - { - st = new SynchronizedHashtable(ht, true); - Assert.Fail(); - } - catch (ArgumentException) - {} } + } - [Test] - public void WrapKeepsOriginalHashtableReference() - { - Hashtable ht = new Hashtable(); - ht["key"] = "value"; - ht["key2"] = "value2"; + [Test] + public void WrapKeepsOriginalHashtableReference() + { + Hashtable ht = new Hashtable(); + ht["key"] = "value"; + ht["key2"] = "value2"; - SynchronizedHashtable st = SynchronizedHashtable.Wrap(ht); - Assert.AreEqual(2, st.Count); - ht.Remove("key"); - Assert.AreEqual(1, ht.Count); - Assert.AreEqual(1, st.Count); - } + SynchronizedHashtable st = SynchronizedHashtable.Wrap(ht); + Assert.AreEqual(2, st.Count); + ht.Remove("key"); + Assert.AreEqual(1, ht.Count); + Assert.AreEqual(1, st.Count); + } - /// - /// On my Notebook gives - /// Normal Hashtable: 00:00:00.0937500 - /// Synced Hashtable: 00:00:00.9375000 - /// =locking *has* a peformance impact. - /// - [Test, Explicit] - public void TestLockingPerformanceImpact() - { - StopWatch watch = new StopWatch(); - object[] buckets = new object[10]; - - int iterations = 10000000; + /// + /// On my Notebook gives + /// Normal Hashtable: 00:00:00.0937500 + /// Synced Hashtable: 00:00:00.9375000 + /// =locking *has* a peformance impact. + /// + [Test, Explicit] + public void TestLockingPerformanceImpact() + { + StopWatch watch = new StopWatch(); + object[] buckets = new object[10]; - IDictionary testDict = new Hashtable(); - buckets[5] = "value"; - object testResult; + int iterations = 10000000; - using(watch.Start("Normal Hashtable: {0}")) - for(int i=0;i - /// On my Notebook gives - /// Method returning exception: 00:00:00.0156250 - /// Method throwing exception: 00:00:02.1562500 - /// - [Test, Explicit] - public void TestPeformanceImpactOfThrowingExceptions() - { - StopWatch watch = new StopWatch(); + /// + /// On my Notebook gives + /// Method returning exception: 00:00:00.0156250 + /// Method throwing exception: 00:00:02.1562500 + /// + [Test, Explicit] + public void TestPeformanceImpactOfThrowingExceptions() + { + StopWatch watch = new StopWatch(); - int iterations = 1000000; + int iterations = 1000000; - using(watch.Start("Method returning exception: {0}")) - for(int i=0;i - /// R/W PlaceOfBirth property - ///
- public Place POB - { - get { return pob; } - set { pob = value; } - } - - /// - /// Readonly - /// - public Place PlaceOfBirth - { - get { return pob; } - } - - public int GetAge(DateTime on) - { - // not very accurate, but it will do the job ;-) - return on.Year - dob.Year; - } } - public class Place + public Inventor(string name, DateTime dateOfBirth, string nationality) { - public string City; - public string Country; + this.Name = name; + this.dob = dateOfBirth; + this.Nationality = nationality; + this.pob = new Place(); } - public class Society + public DateTime DOB { - public string Name = "League of Extraordinary Gentlemen"; - public static string Advisors = "advisors"; - public static string President = "president"; - public const byte ByteConst = 1; + get { return dob; } + set { dob = value; } + } - private IList members = new ArrayList(); - private IDictionary officers = new Hashtable(); + /// + /// R/W PlaceOfBirth property + /// + public Place POB + { + get { return pob; } + set { pob = value; } + } - public IList Members + /// + /// Readonly + /// + public Place PlaceOfBirth + { + get { return pob; } + } + + public int GetAge(DateTime on) + { + // not very accurate, but it will do the job ;-) + return on.Year - dob.Year; + } +} + +public class Place +{ + public string City; + public string Country; +} + +public class Society +{ + public string Name = "League of Extraordinary Gentlemen"; + public static string Advisors = "advisors"; + public static string President = "president"; + public const byte ByteConst = 1; + + private IList members = new ArrayList(); + private IDictionary officers = new Hashtable(); + + public IList Members + { + get { return members; } + } + + public IDictionary Officers + { + get { return officers; } + } + + public bool IsMember(string name) + { + bool found = false; + foreach (Inventor inventor in members) { - get { return members; } - } - - public IDictionary Officers - { - get { return officers; } - } - - public bool IsMember(string name) - { - bool found = false; - foreach (Inventor inventor in members) + if (inventor.Name == name) { - if (inventor.Name == name) - { - found = true; - break; - } + found = true; + break; } - return found; } + + return found; } - - -} \ No newline at end of file +} diff --git a/test/Spring/Spring.Core.Tests/CompilerOptionsTests.cs b/test/Spring/Spring.Core.Tests/CompilerOptionsTests.cs index f840cb0c..ec597a20 100644 --- a/test/Spring/Spring.Core.Tests/CompilerOptionsTests.cs +++ b/test/Spring/Spring.Core.Tests/CompilerOptionsTests.cs @@ -26,43 +26,44 @@ using NUnit.Framework; #endregion -namespace Spring +namespace Spring; + +/// +/// Tests the various exception classes. +/// +/// +/// +/// Shamelessly lifted from the NAnt test suite. +/// +/// +public abstract class CompilerOptionsTests { - /// - /// Tests the various exception classes. - /// - /// - /// - /// Shamelessly lifted from the NAnt test suite. - /// - /// - public abstract class CompilerOptionsTests + #region Tests + + [Test] + public void TestBuildCompliance() { - #region Tests + ProcessAssembly(AssemblyToCheck); + } - [Test] - public void TestBuildCompliance() - { - ProcessAssembly(AssemblyToCheck); - } + #endregion - #endregion - - private void ProcessAssembly(Assembly assembly) - { - object[] attributes = assembly.GetCustomAttributes(typeof (DebuggableAttribute), false); + private void ProcessAssembly(Assembly assembly) + { + object[] attributes = assembly.GetCustomAttributes(typeof(DebuggableAttribute), false); #if DEBUG && TRACE - if (attributes.Length == 0) - { - Assert.Fail("No DebugAttributes found in debug build"); - } - ProcessDebugBuild(attributes); + if (attributes.Length == 0) + { + Assert.Fail("No DebugAttributes found in debug build"); + } + + ProcessDebugBuild(attributes); #endif #if TRACE && !DEBUG if (attributes.Length == 0) { - // This was build with VS.NET Release mode and no DebugAttributes were added. + // This was build with VS.NET Release mode and no DebugAttributes were added. } else { @@ -70,64 +71,60 @@ namespace Spring ProcessReleaseBuild(attributes); } #endif - } - - private void ProcessReleaseBuild(object[] attributes) - { - foreach (Attribute attribute in attributes) - { - if (attribute is DebuggableAttribute) - { - DebuggableAttribute debuggableAttribute = attribute as DebuggableAttribute; - if (debuggableAttribute.IsJITOptimizerDisabled) - { - Assert.Fail("IsJITOptimizerDisabled should be set to false for Release builds."); - } - if (debuggableAttribute.IsJITTrackingEnabled) - { - Assert.Fail("IsJITTrackingEnabled should be set to false for Release builds."); - } - } - } - } - - - private void ProcessDebugBuild(object[] attributes) - { - foreach (Attribute attribute in attributes) - { - if (attribute is DebuggableAttribute) - { - DebuggableAttribute debuggableAttribute = attribute as DebuggableAttribute; - if (debuggableAttribute.IsJITOptimizerDisabled == false) - { - Assert.Fail("IsJITOptimizerDisabled should be set to true for Debug builds."); - } - if (debuggableAttribute.IsJITTrackingEnabled == false) - { - Assert.Fail("IsJITTrackingEnabled should be set to true for Debug builds."); - } - } - } - } - - - - #region Properties - - /// - /// Specify the assembly whose metadata will be checked for a given release mode (debug/release). - /// - protected Assembly AssemblyToCheck - { - get { return _assemblyToCheck; } - set { _assemblyToCheck = value; } - } - - #endregion - - private Assembly _assemblyToCheck = null; - - } -} \ No newline at end of file + + private void ProcessReleaseBuild(object[] attributes) + { + foreach (Attribute attribute in attributes) + { + if (attribute is DebuggableAttribute) + { + DebuggableAttribute debuggableAttribute = attribute as DebuggableAttribute; + if (debuggableAttribute.IsJITOptimizerDisabled) + { + Assert.Fail("IsJITOptimizerDisabled should be set to false for Release builds."); + } + + if (debuggableAttribute.IsJITTrackingEnabled) + { + Assert.Fail("IsJITTrackingEnabled should be set to false for Release builds."); + } + } + } + } + + private void ProcessDebugBuild(object[] attributes) + { + foreach (Attribute attribute in attributes) + { + if (attribute is DebuggableAttribute) + { + DebuggableAttribute debuggableAttribute = attribute as DebuggableAttribute; + if (debuggableAttribute.IsJITOptimizerDisabled == false) + { + Assert.Fail("IsJITOptimizerDisabled should be set to true for Debug builds."); + } + + if (debuggableAttribute.IsJITTrackingEnabled == false) + { + Assert.Fail("IsJITTrackingEnabled should be set to true for Debug builds."); + } + } + } + } + + #region Properties + + /// + /// Specify the assembly whose metadata will be checked for a given release mode (debug/release). + /// + protected Assembly AssemblyToCheck + { + get { return _assemblyToCheck; } + set { _assemblyToCheck = value; } + } + + #endregion + + private Assembly _assemblyToCheck = null; +} diff --git a/test/Spring/Spring.Core.Tests/Context/ApplicationEventArgsTests.cs b/test/Spring/Spring.Core.Tests/Context/ApplicationEventArgsTests.cs index 05610b84..04dd1e7a 100644 --- a/test/Spring/Spring.Core.Tests/Context/ApplicationEventArgsTests.cs +++ b/test/Spring/Spring.Core.Tests/Context/ApplicationEventArgsTests.cs @@ -1,34 +1,33 @@ using NUnit.Framework; -namespace Spring.Context +namespace Spring.Context; + +[TestFixture] +public class ApplicationEventArgsTests { - [TestFixture] - public class ApplicationEventArgsTests - { - private ApplicationEventArgs _args; + private ApplicationEventArgs _args; - [SetUp] - public void Init() - { - _args = new ApplicationEventArgs(); - } + [SetUp] + public void Init() + { + _args = new ApplicationEventArgs(); + } - [TearDown] - public void Destroy() - { - _args = null; - } + [TearDown] + public void Destroy() + { + _args = null; + } - [Test] - public void ArgsTimeStamp() - { - Assert.IsTrue(_args.TimeStamp.ToString("MM/dd/yyyy").Equals(DateTime.Now.ToString("MM/dd/yyyy"))); - } + [Test] + public void ArgsTimeStamp() + { + Assert.IsTrue(_args.TimeStamp.ToString("MM/dd/yyyy").Equals(DateTime.Now.ToString("MM/dd/yyyy"))); + } - [Test] - public void ArgsMilliTimestamp() - { - Assert.IsTrue((_args.TimeStamp.Ticks - 621355968000000000)/10000 == _args.EventTimeMilliseconds); - } - } -} \ No newline at end of file + [Test] + public void ArgsMilliTimestamp() + { + Assert.IsTrue((_args.TimeStamp.Ticks - 621355968000000000) / 10000 == _args.EventTimeMilliseconds); + } +} diff --git a/test/Spring/Spring.Core.Tests/Context/Attributes/AbstractConfigurationClassPostProcessorTests.cs b/test/Spring/Spring.Core.Tests/Context/Attributes/AbstractConfigurationClassPostProcessorTests.cs index 792aa6c2..f4012c85 100644 --- a/test/Spring/Spring.Core.Tests/Context/Attributes/AbstractConfigurationClassPostProcessorTests.cs +++ b/test/Spring/Spring.Core.Tests/Context/Attributes/AbstractConfigurationClassPostProcessorTests.cs @@ -24,330 +24,336 @@ using Spring.Objects.Factory.Support; using Spring.Objects.Factory.Config; using Spring.Objects.Factory.Xml; -namespace Spring.Context.Attributes +namespace Spring.Context.Attributes; + +public abstract class AbstractConfigurationClassPostProcessorTests { + protected AbstractApplicationContext _ctx; - public abstract class AbstractConfigurationClassPostProcessorTests + [SetUp] + public void _SetUp() { - protected AbstractApplicationContext _ctx; - - [SetUp] - public void _SetUp() - { - SingletonParent.InstanceCount = 0; - SingletonChild.InstanceCount = 0; - PrototypeParent.InstanceCount = 0; - PrototypeChild.InstanceCount = 0; - CreateApplicationContext(); - } - - - protected abstract void CreateApplicationContext(); - - - [Test] - public void Can_Assign_Init_And_Destroy_Methods() - { - IObjectDefinition def = _ctx.GetObjectDefinition(typeof(ObjectWithInitAndDestroyMethods).Name); - - Assert.That(def, Is.Not.Null); - Assert.That(def.InitMethodName, Is.EqualTo("CallToInit")); - Assert.That(def.DestroyMethodName, Is.EqualTo("CallToDestroy")); - } - - [Test] - public void Can_Import_Configurations_From_Additional_Classes() - { - Assert.That(_ctx.GetObject(typeof(AnImportedType).Name), Is.Not.Null); - } - - [Test] - public void Can_Respect_Assigned_Aliases() - { - var firstObject = _ctx["TheFirstAlias"]; - var secondObject = _ctx["TheSecondAlias"]; - Assert.That(firstObject, Is.InstanceOf()); - Assert.That(secondObject, Is.InstanceOf()); - } - - [Test] - public void Can_Respect_Assigned_Name() - { - var result = _ctx["TheName"]; - Assert.That(result, Is.InstanceOf()); - } - - [Test] - public void Can_Respect_Default_Singleton_Scope() - { - var firstObject = (SingletonChild)_ctx[typeof(SingletonChild).Name]; - var secondObject = (SingletonChild)_ctx[typeof(SingletonChild).Name]; - - Assert.That(SingletonChild.InstanceCount, Is.EqualTo(1)); - Assert.That(firstObject, Is.SameAs(secondObject)); - } - - [Test] - public void Can_Respect_Default_Singleton_Scope_With_Explicit_Prototype_Dependency() - { - var firstObject = (SingletonParent)_ctx[typeof(SingletonParent).Name]; - var secondObject = (SingletonParent)_ctx[typeof(SingletonParent).Name]; - - Assert.That(SingletonParent.InstanceCount, Is.EqualTo(1)); - //Assert.That(PrototypeChild.InstanceCount, Is.EqualTo(2)); // Requires scoped proxies - Assert.That(firstObject, Is.SameAs(secondObject)); - } - - [Test] - public void Can_Respect_Explicit_Prototype_Scope() - { - var firstObject = (PrototypeChild)_ctx[typeof(PrototypeChild).Name]; - var secondObject = (PrototypeChild)_ctx[typeof(PrototypeChild).Name]; - - Assert.That(PrototypeChild.InstanceCount, Is.EqualTo(3)); // One instance used by SingletonParent - Assert.That(firstObject, Is.Not.SameAs(secondObject)); - } - - [Test] - public void Can_Respect_Explicit_Prototype_Scope_With_Default_Singleton_Dependency() - { - var firstObject = (PrototypeParent)_ctx[typeof(PrototypeParent).Name]; - var secondObject = (PrototypeParent)_ctx[typeof(PrototypeParent).Name]; - - Assert.That(PrototypeParent.InstanceCount, Is.EqualTo(2)); - Assert.That(SingletonChild.InstanceCount, Is.EqualTo(1)); - Assert.That(firstObject, Is.Not.SameAs(secondObject)); - } - - [Test] - public void Can_Respect_Lazy_Attribute() - { - Assert.That(_ctx.GetObjectDefinition(typeof(ImplicitLazyInitObject).Name).IsLazyInit, Is.True); - Assert.That(_ctx.GetObjectDefinition(typeof(ExplicitLazyInitObject).Name).IsLazyInit, Is.True); - Assert.That(_ctx.GetObjectDefinition(typeof(ExplicitNonLazyInitObject).Name).IsLazyInit, Is.False); - } - - [Test] - public void Can_Retreive_Actual_Objects_From_Context() - { - Assert.That(_ctx[typeof(SingletonParent).Name], Is.TypeOf()); - Assert.That(_ctx[typeof(PrototypeChild).Name], Is.TypeOf()); - } - - [Test] - public void Can_Satisfy_Dependencies_Of_Objects() - { - Assert.That(((SingletonParent)_ctx[typeof(SingletonParent).Name]).Child, Is.Not.Null); - } - - - [Test] - public void Can_Respect_Imported_Resources() - { - Assert.That(_ctx["xmlRegisteredObject"], Is.Not.Null); - } + SingletonParent.InstanceCount = 0; + SingletonChild.InstanceCount = 0; + PrototypeParent.InstanceCount = 0; + PrototypeChild.InstanceCount = 0; + CreateApplicationContext(); } - public class ObjectWithInitAndDestroyMethods + protected abstract void CreateApplicationContext(); + + [Test] + public void Can_Assign_Init_And_Destroy_Methods() { - public void CallToDestroy() { } - public void CallToInit() { } + IObjectDefinition def = _ctx.GetObjectDefinition(typeof(ObjectWithInitAndDestroyMethods).Name); + + Assert.That(def, Is.Not.Null); + Assert.That(def.InitMethodName, Is.EqualTo("CallToInit")); + Assert.That(def.DestroyMethodName, Is.EqualTo("CallToDestroy")); } - - - - [Configuration] - [ImportResource("assembly://Spring.Core.Tests/Spring.Context.Attributes/ObjectDefinitions.xml", DefinitionReader = typeof(XmlObjectDefinitionReader))] - [ImportResource("assembly://Spring.Core.Tests/Spring.Context.Attributes/ObjectDefinitionsTwo.xml")] - public class TheImportedConfigurationClass + [Test] + public void Can_Import_Configurations_From_Additional_Classes() { - [ObjectDef] - public virtual AnImportedType AnImportedType() - { - return new AnImportedType(); - } + Assert.That(_ctx.GetObject(typeof(AnImportedType).Name), Is.Not.Null); } - [Configuration] - [Import(typeof(TheImportedConfigurationClass))] - public class TheConfigurationClass + [Test] + public void Can_Respect_Assigned_Aliases() { - [ObjectDef(Names = "TheName")] - public virtual SingleNamedObject NamedObject() - { - return new SingleNamedObject(); - } - - [ObjectDef(DestroyMethod = "CallToDestroy", InitMethod = "CallToInit")] - public virtual ObjectWithInitAndDestroyMethods ObjectWithInitAndDestroyMethods() - { - return new ObjectWithInitAndDestroyMethods(); - } - - [ObjectDef(Names = "TheFirstAlias,TheSecondAlias")] - public virtual ObjectWithAnAlias ObjectWithAnAlias() - { - return new ObjectWithAnAlias(); - } - - [ObjectDef] - [Scope(ObjectScope.Prototype)] - public virtual PrototypeParent PrototypeParent() - { - return new PrototypeParent(SingletonChild()); - } - - [ObjectDef] - [Scope(ObjectScope.Prototype)] - public virtual PrototypeChild PrototypeChild() - { - return new PrototypeChild(); - } - - [ObjectDef] - public virtual SingletonParent SingletonParent() - { - return new SingletonParent(PrototypeChild()); - } - - [ObjectDef] - public virtual SingletonChild SingletonChild() - { - return new SingletonChild(); - } - - [ObjectDef] - [Lazy] - public virtual ImplicitLazyInitObject ImplicitLazyInitObject() - { - return new ImplicitLazyInitObject(); - } - - [ObjectDef] - [Lazy(true)] - public virtual ExplicitLazyInitObject ExplicitLazyInitObject() - { - return new ExplicitLazyInitObject(); - } - - [ObjectDef] - [Lazy(false)] - public virtual ExplicitNonLazyInitObject ExplicitNonLazyInitObject() - { - return new ExplicitNonLazyInitObject(); - } - + var firstObject = _ctx["TheFirstAlias"]; + var secondObject = _ctx["TheSecondAlias"]; + Assert.That(firstObject, Is.InstanceOf()); + Assert.That(secondObject, Is.InstanceOf()); } - - [Configuration] - public class DerivedConfiguration : BaseConfigurationClass + [Test] + public void Can_Respect_Assigned_Name() { - [ObjectDef] - public virtual TestObject DerivedDefinition() - { - return new TestObject(BaseDefinition()); - } + var result = _ctx["TheName"]; + Assert.That(result, Is.InstanceOf()); } - public class BaseConfigurationClass + [Test] + public void Can_Respect_Default_Singleton_Scope() { - [ObjectDef] - public virtual string BaseDefinition() - { - return Guid.NewGuid().ToString(); - } + var firstObject = (SingletonChild) _ctx[typeof(SingletonChild).Name]; + var secondObject = (SingletonChild) _ctx[typeof(SingletonChild).Name]; + + Assert.That(SingletonChild.InstanceCount, Is.EqualTo(1)); + Assert.That(firstObject, Is.SameAs(secondObject)); } - public class TypeRegisteredInXml { } - - public class TypeRegisteredInXmlTwo { } - - public class AnImportedType { } - - public class ImplicitLazyInitObject { } - - public class ExplicitLazyInitObject { } - - public class ExplicitNonLazyInitObject { } - - public class ObjectWithAnAlias { } - - public class SingleNamedObject { } - - public class SingletonParent + [Test] + public void Can_Respect_Default_Singleton_Scope_With_Explicit_Prototype_Dependency() { - public static int InstanceCount = 0; - private PrototypeChild _child; + var firstObject = (SingletonParent) _ctx[typeof(SingletonParent).Name]; + var secondObject = (SingletonParent) _ctx[typeof(SingletonParent).Name]; - public SingletonParent(PrototypeChild child) - { - InstanceCount++; - _child = child; - } - - public PrototypeChild Child - { - get - { - return _child; - } - } + Assert.That(SingletonParent.InstanceCount, Is.EqualTo(1)); + //Assert.That(PrototypeChild.InstanceCount, Is.EqualTo(2)); // Requires scoped proxies + Assert.That(firstObject, Is.SameAs(secondObject)); } - public class SingletonChild + [Test] + public void Can_Respect_Explicit_Prototype_Scope() { - public static int InstanceCount = 0; + var firstObject = (PrototypeChild) _ctx[typeof(PrototypeChild).Name]; + var secondObject = (PrototypeChild) _ctx[typeof(PrototypeChild).Name]; - public SingletonChild() - { - InstanceCount++; - } + Assert.That(PrototypeChild.InstanceCount, Is.EqualTo(3)); // One instance used by SingletonParent + Assert.That(firstObject, Is.Not.SameAs(secondObject)); } - public class PrototypeParent + [Test] + public void Can_Respect_Explicit_Prototype_Scope_With_Default_Singleton_Dependency() { - public static int InstanceCount = 0; - private SingletonChild _child; + var firstObject = (PrototypeParent) _ctx[typeof(PrototypeParent).Name]; + var secondObject = (PrototypeParent) _ctx[typeof(PrototypeParent).Name]; - public PrototypeParent(SingletonChild child) - { - InstanceCount++; - _child = child; - } - - public SingletonChild Child - { - get - { - return _child; - } - } + Assert.That(PrototypeParent.InstanceCount, Is.EqualTo(2)); + Assert.That(SingletonChild.InstanceCount, Is.EqualTo(1)); + Assert.That(firstObject, Is.Not.SameAs(secondObject)); } - public class PrototypeChild + [Test] + public void Can_Respect_Lazy_Attribute() { - public static int InstanceCount = 0; - - public PrototypeChild() - { - InstanceCount++; - } + Assert.That(_ctx.GetObjectDefinition(typeof(ImplicitLazyInitObject).Name).IsLazyInit, Is.True); + Assert.That(_ctx.GetObjectDefinition(typeof(ExplicitLazyInitObject).Name).IsLazyInit, Is.True); + Assert.That(_ctx.GetObjectDefinition(typeof(ExplicitNonLazyInitObject).Name).IsLazyInit, Is.False); } - public class TestObject + [Test] + public void Can_Retreive_Actual_Objects_From_Context() { - private readonly string _value; + Assert.That(_ctx[typeof(SingletonParent).Name], Is.TypeOf()); + Assert.That(_ctx[typeof(PrototypeChild).Name], Is.TypeOf()); + } - public TestObject(string value) - { - _value = value; - } + [Test] + public void Can_Satisfy_Dependencies_Of_Objects() + { + Assert.That(((SingletonParent) _ctx[typeof(SingletonParent).Name]).Child, Is.Not.Null); + } - public string Value + [Test] + public void Can_Respect_Imported_Resources() + { + Assert.That(_ctx["xmlRegisteredObject"], Is.Not.Null); + } +} + +public class ObjectWithInitAndDestroyMethods +{ + public void CallToDestroy() { } + public void CallToInit() { } +} + +[Configuration] +[ImportResource("assembly://Spring.Core.Tests/Spring.Context.Attributes/ObjectDefinitions.xml", DefinitionReader = typeof(XmlObjectDefinitionReader))] +[ImportResource("assembly://Spring.Core.Tests/Spring.Context.Attributes/ObjectDefinitionsTwo.xml")] +public class TheImportedConfigurationClass +{ + [ObjectDef] + public virtual AnImportedType AnImportedType() + { + return new AnImportedType(); + } +} + +[Configuration] +[Import(typeof(TheImportedConfigurationClass))] +public class TheConfigurationClass +{ + [ObjectDef(Names = "TheName")] + public virtual SingleNamedObject NamedObject() + { + return new SingleNamedObject(); + } + + [ObjectDef(DestroyMethod = "CallToDestroy", InitMethod = "CallToInit")] + public virtual ObjectWithInitAndDestroyMethods ObjectWithInitAndDestroyMethods() + { + return new ObjectWithInitAndDestroyMethods(); + } + + [ObjectDef(Names = "TheFirstAlias,TheSecondAlias")] + public virtual ObjectWithAnAlias ObjectWithAnAlias() + { + return new ObjectWithAnAlias(); + } + + [ObjectDef] + [Scope(ObjectScope.Prototype)] + public virtual PrototypeParent PrototypeParent() + { + return new PrototypeParent(SingletonChild()); + } + + [ObjectDef] + [Scope(ObjectScope.Prototype)] + public virtual PrototypeChild PrototypeChild() + { + return new PrototypeChild(); + } + + [ObjectDef] + public virtual SingletonParent SingletonParent() + { + return new SingletonParent(PrototypeChild()); + } + + [ObjectDef] + public virtual SingletonChild SingletonChild() + { + return new SingletonChild(); + } + + [ObjectDef] + [Lazy] + public virtual ImplicitLazyInitObject ImplicitLazyInitObject() + { + return new ImplicitLazyInitObject(); + } + + [ObjectDef] + [Lazy(true)] + public virtual ExplicitLazyInitObject ExplicitLazyInitObject() + { + return new ExplicitLazyInitObject(); + } + + [ObjectDef] + [Lazy(false)] + public virtual ExplicitNonLazyInitObject ExplicitNonLazyInitObject() + { + return new ExplicitNonLazyInitObject(); + } +} + +[Configuration] +public class DerivedConfiguration : BaseConfigurationClass +{ + [ObjectDef] + public virtual TestObject DerivedDefinition() + { + return new TestObject(BaseDefinition()); + } +} + +public class BaseConfigurationClass +{ + [ObjectDef] + public virtual string BaseDefinition() + { + return Guid.NewGuid().ToString(); + } +} + +public class TypeRegisteredInXml +{ +} + +public class TypeRegisteredInXmlTwo +{ +} + +public class AnImportedType +{ +} + +public class ImplicitLazyInitObject +{ +} + +public class ExplicitLazyInitObject +{ +} + +public class ExplicitNonLazyInitObject +{ +} + +public class ObjectWithAnAlias +{ +} + +public class SingleNamedObject +{ +} + +public class SingletonParent +{ + public static int InstanceCount = 0; + private PrototypeChild _child; + + public SingletonParent(PrototypeChild child) + { + InstanceCount++; + _child = child; + } + + public PrototypeChild Child + { + get { - get { return _value; } + return _child; } } } + +public class SingletonChild +{ + public static int InstanceCount = 0; + + public SingletonChild() + { + InstanceCount++; + } +} + +public class PrototypeParent +{ + public static int InstanceCount = 0; + private SingletonChild _child; + + public PrototypeParent(SingletonChild child) + { + InstanceCount++; + _child = child; + } + + public SingletonChild Child + { + get + { + return _child; + } + } +} + +public class PrototypeChild +{ + public static int InstanceCount = 0; + + public PrototypeChild() + { + InstanceCount++; + } +} + +public class TestObject +{ + private readonly string _value; + + public TestObject(string value) + { + _value = value; + } + + public string Value + { + get { return _value; } + } +} diff --git a/test/Spring/Spring.Core.Tests/Context/Attributes/AssemblyObjectDefinitionScannerTests.cs b/test/Spring/Spring.Core.Tests/Context/Attributes/AssemblyObjectDefinitionScannerTests.cs index 0fcbc5e8..52745de4 100644 --- a/test/Spring/Spring.Core.Tests/Context/Attributes/AssemblyObjectDefinitionScannerTests.cs +++ b/test/Spring/Spring.Core.Tests/Context/Attributes/AssemblyObjectDefinitionScannerTests.cs @@ -19,31 +19,29 @@ #endregion using NUnit.Framework; - using Spring.Objects.Factory.Support; -namespace Spring.Context.Attributes -{ - [TestFixture] - public class AssemblyObjectDefinitionScannerTests - { - [Test] - public void Can_Create_Custom_Scan_Routine() - { - var scanner = new ScanOverridingAssemblyObjectDefinitionScanner(); - var registry = new DefaultListableObjectFactory(); - scanner.ScanAndRegisterTypes(registry); - Assert.That(registry.ObjectDefinitionCount, Is.EqualTo(1), "found multiple definitions"); - Assert.That(registry.GetObject(), Is.Not.Null, - "correct single defintion was not registered"); - } +namespace Spring.Context.Attributes; - private class ScanOverridingAssemblyObjectDefinitionScanner : AssemblyObjectDefinitionScanner +[TestFixture] +public class AssemblyObjectDefinitionScannerTests +{ + [Test] + public void Can_Create_Custom_Scan_Routine() + { + var scanner = new ScanOverridingAssemblyObjectDefinitionScanner(); + var registry = new DefaultListableObjectFactory(); + scanner.ScanAndRegisterTypes(registry); + Assert.That(registry.ObjectDefinitionCount, Is.EqualTo(1), "found multiple definitions"); + Assert.That(registry.GetObject(), Is.Not.Null, + "correct single defintion was not registered"); + } + + private class ScanOverridingAssemblyObjectDefinitionScanner : AssemblyObjectDefinitionScanner + { + public override IEnumerable Scan() { - public override IEnumerable Scan() - { - return new Type[] {typeof (ComponentScan.ScanComponentsAndAddToContext.ConfigurationImpl)}; - } + return new Type[] { typeof(ComponentScan.ScanComponentsAndAddToContext.ConfigurationImpl) }; } } -} \ No newline at end of file +} diff --git a/test/Spring/Spring.Core.Tests/Context/Attributes/AssemblyTypeScannerTests.cs b/test/Spring/Spring.Core.Tests/Context/Attributes/AssemblyTypeScannerTests.cs index b4fccab1..0d024445 100644 --- a/test/Spring/Spring.Core.Tests/Context/Attributes/AssemblyTypeScannerTests.cs +++ b/test/Spring/Spring.Core.Tests/Context/Attributes/AssemblyTypeScannerTests.cs @@ -22,100 +22,99 @@ using NUnit.Framework; using Spring.Core; using Spring.Util; -namespace Spring.Context.Attributes +namespace Spring.Context.Attributes; + +[TestFixture] +public class AssemblyTypeScannerTests { - [TestFixture] - public class AssemblyTypeScannerTests + #region Setup/Teardown + + [SetUp] + public void _TestSetup() { - #region Setup/Teardown + _scanner = new AssemblyObjectDefinitionScanner(); + } - [SetUp] - public void _TestSetup() + #endregion + + [Test] + public void AssemblyHavingType_T_Adds_Assembly() + { + _scanner.AssemblyHavingType(); + Assert.That(TypeSources.Any(t => t.Contains(typeof(IOrdered)))); + } + + [Test] + public void IncludeType_T_Adds_Type() + { + _scanner.IncludeType(); + _scanner.IncludeType(); + + IncludePredicates.Any(p => p(typeof(IOrdered))); + IncludePredicates.Any(p => p(typeof(IPriorityOrdered))); + } + + [Test] + public void WithExcludeFilter_Excludes_Type() + { + //var scanner1 = new AssemblyObjectDefinitionScanner(); + + _scanner.IncludeType(); + _scanner.IncludeType(); + _scanner.WithExcludeFilter(t => t.Name.StartsWith("TheImported")); + + IEnumerable types = _scanner.Scan(); + + //Assert.That(types.Any(t => t.Name == "TheConfigurationClass")); + //Assert.False(types.Any(t => t.Name == "TheImportedConfigurationClass")); + + Assert.That(types, Contains.Item((typeof(TheConfigurationClass)))); + Assert.False(types.Contains(typeof(TheImportedConfigurationClass))); + } + + [Test] + public void WithIncludeFilter_Includes_Types() + { + _scanner.WithIncludeFilter(t => t.Name.Contains("ConfigurationClass")); + + var types = _scanner.Scan().ToList(); + + Assert.That(types, Contains.Item((typeof(TheConfigurationClass)))); + Assert.That(types, Contains.Item((typeof(TheImportedConfigurationClass)))); + Assert.That(types.Count, Is.EqualTo(2)); + } + + private AssemblyObjectDefinitionScanner _scanner; + + private List> ExcludePredicates + { + get { - _scanner = new AssemblyObjectDefinitionScanner(); - } - - #endregion - - [Test] - public void AssemblyHavingType_T_Adds_Assembly() - { - _scanner.AssemblyHavingType(); - Assert.That(TypeSources.Any(t => t.Contains(typeof(IOrdered)))); - } - - [Test] - public void IncludeType_T_Adds_Type() - { - _scanner.IncludeType(); - _scanner.IncludeType(); - - IncludePredicates.Any(p => p(typeof(IOrdered))); - IncludePredicates.Any(p => p(typeof(IPriorityOrdered))); - } - - [Test] - public void WithExcludeFilter_Excludes_Type() - { - //var scanner1 = new AssemblyObjectDefinitionScanner(); - - _scanner.IncludeType(); - _scanner.IncludeType(); - _scanner.WithExcludeFilter(t => t.Name.StartsWith("TheImported")); - - IEnumerable types = _scanner.Scan(); - - //Assert.That(types.Any(t => t.Name == "TheConfigurationClass")); - //Assert.False(types.Any(t => t.Name == "TheImportedConfigurationClass")); - - Assert.That(types, Contains.Item((typeof(TheConfigurationClass)))); - Assert.False(types.Contains(typeof(TheImportedConfigurationClass))); - } - - [Test] - public void WithIncludeFilter_Includes_Types() - { - _scanner.WithIncludeFilter(t => t.Name.Contains("ConfigurationClass")); - - var types = _scanner.Scan().ToList(); - - Assert.That(types, Contains.Item((typeof(TheConfigurationClass)))); - Assert.That(types, Contains.Item((typeof(TheImportedConfigurationClass)))); - Assert.That(types.Count, Is.EqualTo(2)); - } - - private AssemblyObjectDefinitionScanner _scanner; - - private List> ExcludePredicates - { - get - { - //get at the collection of excludePredicates from the private field - //(yuck!-- test smell, but at least its wrapped up in a neat private property getter!) - return - (List>)(ReflectionUtils.GetInstanceFieldValue(_scanner, "TypeExclusionPredicates")); - } - } - - private List> IncludePredicates - { - get - { - //get at the collection of includePredicates from the private field - //(yuck!-- test smell, but at least its wrapped up in a neat private property getter!) - return - (List>)(ReflectionUtils.GetInstanceFieldValue(_scanner, "TypeInclusionPredicates")); - } - } - - private List> TypeSources - { - get - { - //get at the collection of typeSources from the private field - //(yuck!-- test smell, but at least its wrapped up in a neat private property getter!) - return (List>)(ReflectionUtils.GetInstanceFieldValue(_scanner, "TypeSources")); - } + //get at the collection of excludePredicates from the private field + //(yuck!-- test smell, but at least its wrapped up in a neat private property getter!) + return + (List>) (ReflectionUtils.GetInstanceFieldValue(_scanner, "TypeExclusionPredicates")); } } -} \ No newline at end of file + + private List> IncludePredicates + { + get + { + //get at the collection of includePredicates from the private field + //(yuck!-- test smell, but at least its wrapped up in a neat private property getter!) + return + (List>) (ReflectionUtils.GetInstanceFieldValue(_scanner, "TypeInclusionPredicates")); + } + } + + private List> TypeSources + { + get + { + //get at the collection of typeSources from the private field + //(yuck!-- test smell, but at least its wrapped up in a neat private property getter!) + return (List>) (ReflectionUtils.GetInstanceFieldValue(_scanner, "TypeSources")); + } + } +} diff --git a/test/Spring/Spring.Core.Tests/Context/Attributes/CodeConfigApplicationContextTests.cs b/test/Spring/Spring.Core.Tests/Context/Attributes/CodeConfigApplicationContextTests.cs index 1424d899..9423ac7e 100644 --- a/test/Spring/Spring.Core.Tests/Context/Attributes/CodeConfigApplicationContextTests.cs +++ b/test/Spring/Spring.Core.Tests/Context/Attributes/CodeConfigApplicationContextTests.cs @@ -18,27 +18,22 @@ #endregion - using NUnit.Framework; using Spring.Context.Support; -namespace Spring.Context.Attributes +namespace Spring.Context.Attributes; + +[TestFixture] +public class CodeConfigApplicationContextTests : AbstractConfigurationClassPostProcessorTests { - [TestFixture] - public class CodeConfigApplicationContextTests : AbstractConfigurationClassPostProcessorTests + protected override void CreateApplicationContext() { + GenericApplicationContext ctx = new GenericApplicationContext(); - protected override void CreateApplicationContext() - { - GenericApplicationContext ctx = new GenericApplicationContext(); + ctx.ScanAllAssemblies(); - ctx.ScanAllAssemblies(); - - ctx.Refresh(); - - _ctx = ctx; - } + ctx.Refresh(); + _ctx = ctx; } - } diff --git a/test/Spring/Spring.Core.Tests/Context/Attributes/ConfigurationClassObjectDefinitionReaderTests.cs b/test/Spring/Spring.Core.Tests/Context/Attributes/ConfigurationClassObjectDefinitionReaderTests.cs index 92caff71..682e21a5 100644 --- a/test/Spring/Spring.Core.Tests/Context/Attributes/ConfigurationClassObjectDefinitionReaderTests.cs +++ b/test/Spring/Spring.Core.Tests/Context/Attributes/ConfigurationClassObjectDefinitionReaderTests.cs @@ -19,21 +19,19 @@ #endregion using NUnit.Framework; - using Spring.Objects.Factory.Support; -namespace Spring.Context.Attributes +namespace Spring.Context.Attributes; + +[TestFixture] +public class ConfigurationClassObjectDefinitionReaderTests { - [TestFixture] - public class ConfigurationClassObjectDefinitionReaderTests + [Test] + public void ShouldNotTryToResolveAbstractDefinitionsToType() { - [Test] - public void ShouldNotTryToResolveAbstractDefinitionsToType() - { - GenericObjectDefinition definition = new GenericObjectDefinition(); - definition.ObjectTypeName = "~/Default.aspx"; - definition.IsAbstract = true; - Assert.That(ConfigurationClassObjectDefinitionReader.CheckConfigurationClassCandidate(definition), Is.False); - } + GenericObjectDefinition definition = new GenericObjectDefinition(); + definition.ObjectTypeName = "~/Default.aspx"; + definition.IsAbstract = true; + Assert.That(ConfigurationClassObjectDefinitionReader.CheckConfigurationClassCandidate(definition), Is.False); } } \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/Context/Attributes/ConfigurationClassParserTests.cs b/test/Spring/Spring.Core.Tests/Context/Attributes/ConfigurationClassParserTests.cs index ee7dfa59..6c9b5841 100644 --- a/test/Spring/Spring.Core.Tests/Context/Attributes/ConfigurationClassParserTests.cs +++ b/test/Spring/Spring.Core.Tests/Context/Attributes/ConfigurationClassParserTests.cs @@ -19,7 +19,6 @@ #endregion using NUnit.Framework; - using Spring.Context.Attributes; using Spring.Objects.Factory.Parsing; @@ -71,4 +70,4 @@ namespace ConfigurationNameSpace2 return "B"; } } -} \ No newline at end of file +} diff --git a/test/Spring/Spring.Core.Tests/Context/Attributes/ConfigurationClassPostProcessorTests.cs b/test/Spring/Spring.Core.Tests/Context/Attributes/ConfigurationClassPostProcessorTests.cs index 74463044..02c94fef 100644 --- a/test/Spring/Spring.Core.Tests/Context/Attributes/ConfigurationClassPostProcessorTests.cs +++ b/test/Spring/Spring.Core.Tests/Context/Attributes/ConfigurationClassPostProcessorTests.cs @@ -22,50 +22,42 @@ using NUnit.Framework; using Spring.Context.Support; using Spring.Objects.Factory.Support; -namespace Spring.Context.Attributes +namespace Spring.Context.Attributes; + +[TestFixture] +public class ConfigurationClassPostProcessorTests : AbstractConfigurationClassPostProcessorTests { - [TestFixture] - public class ConfigurationClassPostProcessorTests : AbstractConfigurationClassPostProcessorTests + protected override void CreateApplicationContext() { + GenericApplicationContext ctx = new GenericApplicationContext(); - protected override void CreateApplicationContext() - { - GenericApplicationContext ctx = new GenericApplicationContext(); + var configDefinitionBuilder = ObjectDefinitionBuilder.GenericObjectDefinition(typeof(TheConfigurationClass)); + ctx.RegisterObjectDefinition(configDefinitionBuilder.ObjectDefinition.ObjectTypeName, configDefinitionBuilder.ObjectDefinition); - var configDefinitionBuilder = ObjectDefinitionBuilder.GenericObjectDefinition(typeof(TheConfigurationClass)); - ctx.RegisterObjectDefinition(configDefinitionBuilder.ObjectDefinition.ObjectTypeName, configDefinitionBuilder.ObjectDefinition); + var postProcessorDefintionBuilder = ObjectDefinitionBuilder.GenericObjectDefinition(typeof(ConfigurationClassPostProcessor)); + ctx.RegisterObjectDefinition(postProcessorDefintionBuilder.ObjectDefinition.ObjectTypeName, postProcessorDefintionBuilder.ObjectDefinition); - var postProcessorDefintionBuilder = ObjectDefinitionBuilder.GenericObjectDefinition(typeof(ConfigurationClassPostProcessor)); - ctx.RegisterObjectDefinition(postProcessorDefintionBuilder.ObjectDefinition.ObjectTypeName, postProcessorDefintionBuilder.ObjectDefinition); + Assert.That(ctx.ObjectDefinitionCount, Is.EqualTo(2)); - Assert.That(ctx.ObjectDefinitionCount, Is.EqualTo(2)); + ctx.Refresh(); - ctx.Refresh(); - - _ctx = ctx; - } - - - [Test] - public void ShouldAllowConfigurationClassInheritance() - { - var factory = new DefaultListableObjectFactory(); - factory.RegisterObjectDefinition("DerivedConfiguration", new GenericObjectDefinition - { - ObjectType = typeof(DerivedConfiguration) - }); - - var processor = new ConfigurationClassPostProcessor(); - - processor.PostProcessObjectFactory(factory); - - // we should get singleton instances only - TestObject testObject = (TestObject) factory.GetObject("DerivedDefinition"); - string singletonParent = (string) factory.GetObject("BaseDefinition"); - - - Assert.That(testObject.Value, Is.SameAs(singletonParent)); - } + _ctx = ctx; } + [Test] + public void ShouldAllowConfigurationClassInheritance() + { + var factory = new DefaultListableObjectFactory(); + factory.RegisterObjectDefinition("DerivedConfiguration", new GenericObjectDefinition { ObjectType = typeof(DerivedConfiguration) }); + + var processor = new ConfigurationClassPostProcessor(); + + processor.PostProcessObjectFactory(factory); + + // we should get singleton instances only + TestObject testObject = (TestObject) factory.GetObject("DerivedDefinition"); + string singletonParent = (string) factory.GetObject("BaseDefinition"); + + Assert.That(testObject.Value, Is.SameAs(singletonParent)); + } } diff --git a/test/Spring/Spring.Core.Tests/Context/Attributes/ImportResourceAttributeTests.cs b/test/Spring/Spring.Core.Tests/Context/Attributes/ImportResourceAttributeTests.cs index a37ddceb..542757b9 100644 --- a/test/Spring/Spring.Core.Tests/Context/Attributes/ImportResourceAttributeTests.cs +++ b/test/Spring/Spring.Core.Tests/Context/Attributes/ImportResourceAttributeTests.cs @@ -22,43 +22,41 @@ using NUnit.Framework; using Spring.Objects.Factory.Xml; using Spring.Objects.Factory.Support; -namespace Spring.Context.Attributes +namespace Spring.Context.Attributes; + +[TestFixture] +public class ImportResourceAttributeTests { - [TestFixture] - public class ImportResourceAttributeTests + [Test] + public void Uses_XmlObjectDefinitionReader_By_Default() { - [Test] - public void Uses_XmlObjectDefinitionReader_By_Default() - { - var attrib = new ImportResourceAttribute("the resource"); + var attrib = new ImportResourceAttribute("the resource"); - Assert.That(attrib.DefinitionReader, Is.EqualTo(typeof(XmlObjectDefinitionReader))); + Assert.That(attrib.DefinitionReader, Is.EqualTo(typeof(XmlObjectDefinitionReader))); + } + + [Test] + public void Can_Assign_NonDefault_DefinitionReader() + { + var attrib = new ImportResourceAttribute("the resource"); + attrib.DefinitionReader = typeof(AbstractObjectDefinitionReader); + + Assert.That(attrib.DefinitionReader, Is.EqualTo(typeof(AbstractObjectDefinitionReader))); + } + + [Test] + public void DefinitionReader_Can_Prevent_Improper_Types() + { + ImportResourceAttribute attrib = new ImportResourceAttribute("the resource"); + + try + { + attrib.DefinitionReader = typeof(Object); // <--need to pass *anything* ensured *not* to implement IObjectDefinitionReader + Assert.Fail("Expected Exception of type ArgumentException not thrown!"); } - - [Test] - public void Can_Assign_NonDefault_DefinitionReader() + catch (ArgumentException) { - var attrib = new ImportResourceAttribute("the resource"); - attrib.DefinitionReader = typeof(AbstractObjectDefinitionReader); - - Assert.That(attrib.DefinitionReader, Is.EqualTo(typeof(AbstractObjectDefinitionReader))); - } - - [Test] - public void DefinitionReader_Can_Prevent_Improper_Types() - { - ImportResourceAttribute attrib = new ImportResourceAttribute("the resource"); - - try - { - attrib.DefinitionReader = typeof(Object);// <--need to pass *anything* ensured *not* to implement IObjectDefinitionReader - Assert.Fail("Expected Exception of type ArgumentException not thrown!"); - } - catch (ArgumentException) - { - //swallow the expected exception - } - + //swallow the expected exception } } } diff --git a/test/Spring/Spring.Core.Tests/Context/Attributes/ObjectDefAttributeTests.cs b/test/Spring/Spring.Core.Tests/Context/Attributes/ObjectDefAttributeTests.cs index 96ccf3f1..537707fc 100644 --- a/test/Spring/Spring.Core.Tests/Context/Attributes/ObjectDefAttributeTests.cs +++ b/test/Spring/Spring.Core.Tests/Context/Attributes/ObjectDefAttributeTests.cs @@ -20,35 +20,30 @@ using NUnit.Framework; -namespace Spring.Context.Attributes +namespace Spring.Context.Attributes; + +[TestFixture] +public class ObjectDefAttributeTests { - [TestFixture] - public class ObjectDefAttributeTests + [Test] + public void Can_Accept_Single_Name() { - [Test] - public void Can_Accept_Single_Name() - { - var def = new ObjectDefAttribute(); + var def = new ObjectDefAttribute(); - def.Names = "Steve"; + def.Names = "Steve"; - Assert.That(def.NamesToArray[0], Is.EqualTo("Steve")); - } + Assert.That(def.NamesToArray[0], Is.EqualTo("Steve")); + } + [Test] + public void Can_Accept_Multiple_Names() + { + var def = new ObjectDefAttribute(); + var names = "Name1,Name2,Name3"; - [Test] - public void Can_Accept_Multiple_Names() - { - var def = new ObjectDefAttribute(); - var names = "Name1,Name2,Name3"; - - def.Names = names; - Assert.That(def.NamesToArray[0], Is.EqualTo("Name1")); - Assert.That(def.NamesToArray[1], Is.EqualTo("Name2")); - Assert.That(def.NamesToArray[2], Is.EqualTo("Name3")); - - } - - + def.Names = names; + Assert.That(def.NamesToArray[0], Is.EqualTo("Name1")); + Assert.That(def.NamesToArray[1], Is.EqualTo("Name2")); + Assert.That(def.NamesToArray[2], Is.EqualTo("Name3")); } } diff --git a/test/Spring/Spring.Core.Tests/Context/Attributes/ObjectDefinitions.xml b/test/Spring/Spring.Core.Tests/Context/Attributes/ObjectDefinitions.xml index d6ef5c57..2e3f6c98 100644 --- a/test/Spring/Spring.Core.Tests/Context/Attributes/ObjectDefinitions.xml +++ b/test/Spring/Spring.Core.Tests/Context/Attributes/ObjectDefinitions.xml @@ -1,6 +1,6 @@  - - + + diff --git a/test/Spring/Spring.Core.Tests/Context/Attributes/ObjectDefinitionsTwo.xml b/test/Spring/Spring.Core.Tests/Context/Attributes/ObjectDefinitionsTwo.xml index 26eae23a..1deb842b 100644 --- a/test/Spring/Spring.Core.Tests/Context/Attributes/ObjectDefinitionsTwo.xml +++ b/test/Spring/Spring.Core.Tests/Context/Attributes/ObjectDefinitionsTwo.xml @@ -1,6 +1,6 @@  - - + + diff --git a/test/Spring/Spring.Core.Tests/Context/Attributes/ScanningConfigurationClassPostProcessorTests.cs b/test/Spring/Spring.Core.Tests/Context/Attributes/ScanningConfigurationClassPostProcessorTests.cs index 7b82160b..f7715641 100644 --- a/test/Spring/Spring.Core.Tests/Context/Attributes/ScanningConfigurationClassPostProcessorTests.cs +++ b/test/Spring/Spring.Core.Tests/Context/Attributes/ScanningConfigurationClassPostProcessorTests.cs @@ -19,24 +19,22 @@ #endregion using NUnit.Framework; - using Spring.Context.Support; using Spring.Objects.Factory.Xml; -namespace Spring.Context.Attributes -{ - [TestFixture] - public class ScanningConfigurationClassPostProcessorTests : AbstractConfigurationClassPostProcessorTests - { - protected override void CreateApplicationContext() - { - _ctx = new XmlApplicationContext(ReadOnlyXmlTestResource.GetFilePath("SimpleScanTest.xml", GetType())); - } +namespace Spring.Context.Attributes; - [Test] - public void ContextNotNull() - { - Assert.That(_ctx, Is.Not.Null); - } +[TestFixture] +public class ScanningConfigurationClassPostProcessorTests : AbstractConfigurationClassPostProcessorTests +{ + protected override void CreateApplicationContext() + { + _ctx = new XmlApplicationContext(ReadOnlyXmlTestResource.GetFilePath("SimpleScanTest.xml", GetType())); + } + + [Test] + public void ContextNotNull() + { + Assert.That(_ctx, Is.Not.Null); } } diff --git a/test/Spring/Spring.Core.Tests/Context/Attributes/SimpleScanTest.xml b/test/Spring/Spring.Core.Tests/Context/Attributes/SimpleScanTest.xml index 1e86ed12..0f688840 100644 --- a/test/Spring/Spring.Core.Tests/Context/Attributes/SimpleScanTest.xml +++ b/test/Spring/Spring.Core.Tests/Context/Attributes/SimpleScanTest.xml @@ -1,8 +1,8 @@  - - - + + + diff --git a/test/Spring/Spring.Core.Tests/Context/Attributes/SimpleScanTests.cs b/test/Spring/Spring.Core.Tests/Context/Attributes/SimpleScanTests.cs index 611b4b3b..047ddd74 100644 --- a/test/Spring/Spring.Core.Tests/Context/Attributes/SimpleScanTests.cs +++ b/test/Spring/Spring.Core.Tests/Context/Attributes/SimpleScanTests.cs @@ -20,70 +20,67 @@ using System.Collections; using NUnit.Framework; - using Spring.Context.Support; using Spring.Example.Scannable; using Spring.Objects.Factory; using Spring.Objects.Factory.Xml; -namespace Spring.Context.Attributes +namespace Spring.Context.Attributes; + +public class SimpleScanTests { + private IApplicationContext _applicationContext; - public class SimpleScanTests + [SetUp] + public void Setup() { - private IApplicationContext _applicationContext; - - [SetUp] - public void Setup() - { - _applicationContext = new XmlApplicationContext(ReadOnlyXmlTestResource.GetFilePath("SimpleScanTest.xml", GetType())); - } - - //[Test] - public void FooService() - { - - IFooService fooService = GetObject(); - - } - - public T GetObject() - { - return (T)DoGetInstance(typeof(T), null); - } - public T GetObject(string name) - { - return (T)DoGetInstance(typeof(T), name); - } - - protected object DoGetInstance(Type serviceType, string key) - { - if (key == null) - { - IEnumerator it = DoGetAllInstances(serviceType).GetEnumerator(); - if (it.MoveNext()) - { - return it.Current; - } - throw new ObjectCreationException(string.Format("no services of type '{0}' defined", serviceType.FullName)); - } - return _applicationContext.GetObject(key, serviceType); - } - - /// - /// Resolves service instances by type. - /// - /// Type of service requested. - /// - /// Sequence of service instance objects matching the . - /// - protected IEnumerable DoGetAllInstances(Type serviceType) - { - foreach (string objectName in _applicationContext.GetObjectNamesForType(serviceType)) - { - yield return _applicationContext.GetObject(objectName); - } - } - + _applicationContext = new XmlApplicationContext(ReadOnlyXmlTestResource.GetFilePath("SimpleScanTest.xml", GetType())); } -} \ No newline at end of file + + //[Test] + public void FooService() + { + IFooService fooService = GetObject(); + } + + public T GetObject() + { + return (T) DoGetInstance(typeof(T), null); + } + + public T GetObject(string name) + { + return (T) DoGetInstance(typeof(T), name); + } + + protected object DoGetInstance(Type serviceType, string key) + { + if (key == null) + { + IEnumerator it = DoGetAllInstances(serviceType).GetEnumerator(); + if (it.MoveNext()) + { + return it.Current; + } + + throw new ObjectCreationException(string.Format("no services of type '{0}' defined", serviceType.FullName)); + } + + return _applicationContext.GetObject(key, serviceType); + } + + /// + /// Resolves service instances by type. + /// + /// Type of service requested. + /// + /// Sequence of service instance objects matching the . + /// + protected IEnumerable DoGetAllInstances(Type serviceType) + { + foreach (string objectName in _applicationContext.GetObjectNamesForType(serviceType)) + { + yield return _applicationContext.GetObject(objectName); + } + } +} diff --git a/test/Spring/Spring.Core.Tests/Context/CommonTypes.cs b/test/Spring/Spring.Core.Tests/Context/CommonTypes.cs index dea42205..00744e2c 100644 --- a/test/Spring/Spring.Core.Tests/Context/CommonTypes.cs +++ b/test/Spring/Spring.Core.Tests/Context/CommonTypes.cs @@ -29,141 +29,139 @@ using Spring.Objects.Factory.Support; #endregion -namespace Spring.Context +namespace Spring.Context; + +/// +/// This class contains common mock implementations of Context interfaces, +/// used for testing. +/// +[Serializable] +public class MockContextAwareObject : MarshalByRefObject, + IApplicationContextAware, IMessageSourceAware, IResourceLoaderAware { - /// - /// This class contains common mock implementations of Context interfaces, - /// used for testing. - /// - [Serializable] - public class MockContextAwareObject : MarshalByRefObject, - IApplicationContextAware, IMessageSourceAware, IResourceLoaderAware - { - private IApplicationContext _applicationContext; - private IResourceLoader _resourceLoader; - private IMessageSource _messageSource; + private IApplicationContext _applicationContext; + private IResourceLoader _resourceLoader; + private IMessageSource _messageSource; - public IApplicationContext GetApplicationContext() - { - return _applicationContext; - } + public IApplicationContext GetApplicationContext() + { + return _applicationContext; + } - public IApplicationContext ApplicationContext - { - set { _applicationContext = value; } - get { return _applicationContext; } - } + public IApplicationContext ApplicationContext + { + set { _applicationContext = value; } + get { return _applicationContext; } + } - public IResourceLoader ResourceLoader - { - set { _resourceLoader = value; } - get { return _resourceLoader; } - } + public IResourceLoader ResourceLoader + { + set { _resourceLoader = value; } + get { return _resourceLoader; } + } - public IMessageSource MessageSource - { - get { return _messageSource; } - set { _messageSource = value; } - } - } + public IMessageSource MessageSource + { + get { return _messageSource; } + set { _messageSource = value; } + } +} - public class MockApplicationContext : AbstractApplicationContext - { - private string _mockName; - private bool _isVerified; - private DefaultListableObjectFactory factory; - private int expectedCloseCalls; - private int actualCloseCalls; +public class MockApplicationContext : AbstractApplicationContext +{ + private string _mockName; + private bool _isVerified; + private DefaultListableObjectFactory factory; + private int expectedCloseCalls; + private int actualCloseCalls; - public void SetCloseCalls(int expectedCalls) - { - expectedCloseCalls = expectedCalls; - } + public void SetCloseCalls(int expectedCalls) + { + expectedCloseCalls = expectedCalls; + } - public MockApplicationContext() : this(null, null) - { - } + public MockApplicationContext() : this(null, null) + { + } - public MockApplicationContext(string name) : this(name, null) - { - _mockName = name; - factory = new DefaultListableObjectFactory(); - } + public MockApplicationContext(string name) : this(name, null) + { + _mockName = name; + factory = new DefaultListableObjectFactory(); + } - /// - /// Initializes a new instance of the MockApplicationContext class. - /// - public MockApplicationContext(IApplicationContext parentContext) - { - factory = new DefaultListableObjectFactory(parentContext); - } + /// + /// Initializes a new instance of the MockApplicationContext class. + /// + public MockApplicationContext(IApplicationContext parentContext) + { + factory = new DefaultListableObjectFactory(parentContext); + } - public MockApplicationContext(string name, IApplicationContext parentContext) : base(name, true, parentContext) - { - _mockName = name; - factory = new DefaultListableObjectFactory(GetInternalParentObjectFactory()); - } + public MockApplicationContext(string name, IApplicationContext parentContext) : base(name, true, parentContext) + { + _mockName = name; + factory = new DefaultListableObjectFactory(GetInternalParentObjectFactory()); + } - public override bool IsObjectNameInUse(string objectName) - { - return factory.IsObjectNameInUse(objectName); - } + public override bool IsObjectNameInUse(string objectName) + { + return factory.IsObjectNameInUse(objectName); + } - public override IConfigurableListableObjectFactory ObjectFactory - { - get { return factory; } - } + public override IConfigurableListableObjectFactory ObjectFactory + { + get { return factory; } + } - protected override void RefreshObjectFactory() - { - } + protected override void RefreshObjectFactory() + { + } - public void RegisterSingleton() - { - RootObjectDefinition mcaoDef = new RootObjectDefinition(typeof (MockContextAwareObject), new MutablePropertyValues(), true); - factory.RegisterObjectDefinition("mcao-single", mcaoDef); - } + public void RegisterSingleton() + { + RootObjectDefinition mcaoDef = new RootObjectDefinition(typeof(MockContextAwareObject), new MutablePropertyValues(), true); + factory.RegisterObjectDefinition("mcao-single", mcaoDef); + } - public void RegisterObject() - { - RootObjectDefinition mcaoDef = new RootObjectDefinition(typeof (MockContextAwareObject), new MutablePropertyValues(), false); - factory.RegisterObjectDefinition("mcao-proto", mcaoDef); - } + public void RegisterObject() + { + RootObjectDefinition mcaoDef = new RootObjectDefinition(typeof(MockContextAwareObject), new MutablePropertyValues(), false); + factory.RegisterObjectDefinition("mcao-proto", mcaoDef); + } - public override void Dispose() - { - actualCloseCalls++; - } + public override void Dispose() + { + actualCloseCalls++; + } - #region IMockObject Members + #region IMockObject Members - public void NotImplemented(string methodName) - { - throw new NotImplementedException(methodName + " is not currently implemented"); - } + public void NotImplemented(string methodName) + { + throw new NotImplementedException(methodName + " is not currently implemented"); + } - public string MockName - { - get { return _mockName; } - set { _mockName = value; } - } + public string MockName + { + get { return _mockName; } + set { _mockName = value; } + } - #endregion + #endregion - #region IVerifiable Members + #region IVerifiable Members - public void Verify() - { - Assert.AreEqual(actualCloseCalls, expectedCloseCalls, "Did not receive the expected Count for object " + MockName); - _isVerified = true; - } + public void Verify() + { + Assert.AreEqual(actualCloseCalls, expectedCloseCalls, "Did not receive the expected Count for object " + MockName); + _isVerified = true; + } - public bool IsVerified - { - get { return _isVerified; } - } + public bool IsVerified + { + get { return _isVerified; } + } - #endregion - } - -} \ No newline at end of file + #endregion +} diff --git a/test/Spring/Spring.Core.Tests/Context/Config/AttributeConfigObjectDefinitionParserTests.cs b/test/Spring/Spring.Core.Tests/Context/Config/AttributeConfigObjectDefinitionParserTests.cs index cc9e2154..6323b07c 100644 --- a/test/Spring/Spring.Core.Tests/Context/Config/AttributeConfigObjectDefinitionParserTests.cs +++ b/test/Spring/Spring.Core.Tests/Context/Config/AttributeConfigObjectDefinitionParserTests.cs @@ -23,28 +23,27 @@ using Spring.Context.Attributes; using Spring.Context.Support; using Spring.Objects.Factory.Xml; -namespace Spring.Context.Config +namespace Spring.Context.Config; + +[TestFixture] +public class AttributeConfigObjectDefinitionParserTests { - [TestFixture] - public class AttributeConfigObjectDefinitionParserTests + private XmlApplicationContext _applicationContext; + + [SetUp] + public void Setup() { - private XmlApplicationContext _applicationContext; + } - [SetUp] - public void Setup() - { - } + [Test] + public void RegisteredComponents() + { + _applicationContext = new XmlApplicationContext(ReadOnlyXmlTestResource.GetFilePath("ConfigFiles.AttributeConfigParser.xml", GetType())); + var objectDefintionNames = _applicationContext.ObjectFactory.GetObjectDefinitionNames(); - [Test] - public void RegisteredComponents() - { - _applicationContext = new XmlApplicationContext(ReadOnlyXmlTestResource.GetFilePath("ConfigFiles.AttributeConfigParser.xml", GetType())); - var objectDefintionNames = _applicationContext.ObjectFactory.GetObjectDefinitionNames(); - - Assert.That(objectDefintionNames.Contains(AttributeConfigUtils.CONFIGURATION_ATTRIBUTE_PROCESSOR_OBJECT_NAME), Is.True); - Assert.That(objectDefintionNames.Contains(AttributeConfigUtils.AUTOWIRED_ATTRIBUTE_PROCESSOR_OBJECT_NAME), Is.True); - Assert.That(objectDefintionNames.Contains(AttributeConfigUtils.REQUIRED_ATTRIBUTE_PROCESSOR_OBJECT_NAME), Is.True); - Assert.That(objectDefintionNames.Contains(AttributeConfigUtils.INITDESTROY_ATTRIBUTE_PROCESSOR_OBJECT_NAME), Is.True); - } + Assert.That(objectDefintionNames.Contains(AttributeConfigUtils.CONFIGURATION_ATTRIBUTE_PROCESSOR_OBJECT_NAME), Is.True); + Assert.That(objectDefintionNames.Contains(AttributeConfigUtils.AUTOWIRED_ATTRIBUTE_PROCESSOR_OBJECT_NAME), Is.True); + Assert.That(objectDefintionNames.Contains(AttributeConfigUtils.REQUIRED_ATTRIBUTE_PROCESSOR_OBJECT_NAME), Is.True); + Assert.That(objectDefintionNames.Contains(AttributeConfigUtils.INITDESTROY_ATTRIBUTE_PROCESSOR_OBJECT_NAME), Is.True); } } diff --git a/test/Spring/Spring.Core.Tests/Context/Config/ComponentScanObjectDefinitionParserAssemblyFilterTests.cs b/test/Spring/Spring.Core.Tests/Context/Config/ComponentScanObjectDefinitionParserAssemblyFilterTests.cs index fd8ecd87..bbaaf04d 100644 --- a/test/Spring/Spring.Core.Tests/Context/Config/ComponentScanObjectDefinitionParserAssemblyFilterTests.cs +++ b/test/Spring/Spring.Core.Tests/Context/Config/ComponentScanObjectDefinitionParserAssemblyFilterTests.cs @@ -2,47 +2,46 @@ using Spring.Context.Support; using Spring.Objects.Factory.Xml; -namespace Spring.Context.Config +namespace Spring.Context.Config; + +[TestFixture] +public class ComponentScanObjectDefinitionParserAssemblyFilterTests { - [TestFixture] - public class ComponentScanObjectDefinitionParserAssemblyFilterTests + private IApplicationContext _applicationContext; + + [SetUp] + public void Setup() { - private IApplicationContext _applicationContext; + } - [SetUp] - public void Setup() - { - } + [Test] + public void BaseAssembliesAttributeRequired() + { + Assert.That(() => { _applicationContext = new XmlApplicationContext(ReadOnlyXmlTestResource.GetFilePath("ConfigFiles.BaseAssemblyTestWithout.xml", GetType())); }, + Throws.Exception); + } - [Test] - public void BaseAssembliesAttributeRequired() - { - Assert.That(() => { _applicationContext = new XmlApplicationContext(ReadOnlyXmlTestResource.GetFilePath("ConfigFiles.BaseAssemblyTestWithout.xml", GetType())); }, - Throws.Exception); - } + [Test] + public void SingleAssemblyNameProvided() + { + _applicationContext = new XmlApplicationContext(ReadOnlyXmlTestResource.GetFilePath("ConfigFiles.BaseAssemblyTestSingle.xml", GetType())); - [Test] - public void SingleAssemblyNameProvided() - { - _applicationContext = new XmlApplicationContext(ReadOnlyXmlTestResource.GetFilePath("ConfigFiles.BaseAssemblyTestSingle.xml", GetType())); + Assert.That(_applicationContext.GetObjectDefinitionNames().Count, Is.GreaterThan(0)); + } - Assert.That(_applicationContext.GetObjectDefinitionNames().Count, Is.GreaterThan(0)); - } + [Test] + public void MultipleAssemblyNameProvided() + { + _applicationContext = new XmlApplicationContext(ReadOnlyXmlTestResource.GetFilePath("ConfigFiles.BaseAssemblyTestMultiple.xml", GetType())); - [Test] - public void MultipleAssemblyNameProvided() - { - _applicationContext = new XmlApplicationContext(ReadOnlyXmlTestResource.GetFilePath("ConfigFiles.BaseAssemblyTestMultiple.xml", GetType())); + Assert.That(_applicationContext.GetObjectDefinitionNames().Count, Is.GreaterThan(0)); + } - Assert.That(_applicationContext.GetObjectDefinitionNames().Count, Is.GreaterThan(0)); - } - [Test] - public void NegativeAssemblyNameProvided() - { - _applicationContext = new XmlApplicationContext(ReadOnlyXmlTestResource.GetFilePath("ConfigFiles.BaseAssemblyTestNegative.xml", GetType())); - - Assert.That(_applicationContext.GetObjectDefinitionNames().Count, Is.EqualTo(4)); - } + [Test] + public void NegativeAssemblyNameProvided() + { + _applicationContext = new XmlApplicationContext(ReadOnlyXmlTestResource.GetFilePath("ConfigFiles.BaseAssemblyTestNegative.xml", GetType())); + Assert.That(_applicationContext.GetObjectDefinitionNames().Count, Is.EqualTo(4)); } } diff --git a/test/Spring/Spring.Core.Tests/Context/Config/ComponentScanObjectDefinitionParserTests.cs b/test/Spring/Spring.Core.Tests/Context/Config/ComponentScanObjectDefinitionParserTests.cs index f17b4b28..8c985cb3 100644 --- a/test/Spring/Spring.Core.Tests/Context/Config/ComponentScanObjectDefinitionParserTests.cs +++ b/test/Spring/Spring.Core.Tests/Context/Config/ComponentScanObjectDefinitionParserTests.cs @@ -47,7 +47,7 @@ namespace Spring.Context.Config _applicationContext = new XmlApplicationContext(ReadOnlyXmlTestResource.GetFilePath("ConfigFiles.ComponentScan1.xml", GetType())); var objectDefinitionNames = _applicationContext.ObjectFactory.GetObjectDefinitionNames(); - Assert.That(objectDefinitionNames.Count, Is.EqualTo(5+4)); + Assert.That(objectDefinitionNames.Count, Is.EqualTo(5 + 4)); Assert.That(_applicationContext.GetObject(prefix + "ComponentImpl"), Is.Not.Null); Assert.That(_applicationContext.GetObject(prefix + "ServiceImpl"), Is.Not.Null); Assert.That(_applicationContext.GetObject(prefix + "RepositoryImpl"), Is.Not.Null); @@ -87,6 +87,7 @@ namespace Spring.Context.Config Assert.That(objectDefinitionNames.Contains("prototype"), Is.False); Assert.That(objectDefinitionNames.Contains("ComponentScan.NameGenerator.Prototype"), Is.True); } + [Test] public void ComponentsLazyLoaded() { @@ -122,10 +123,10 @@ namespace Spring.Context.Config [Test] public void ComponentsUseDefaultAutoWire() { - _applicationContext = new XmlApplicationContext(ReadOnlyXmlTestResource.GetFilePath("ConfigFiles.ComponentScan5.xml", GetType())); - var prototypeDef = _applicationContext.ObjectFactory.GetObjectDefinition("Prototype"); + _applicationContext = new XmlApplicationContext(ReadOnlyXmlTestResource.GetFilePath("ConfigFiles.ComponentScan5.xml", GetType())); + var prototypeDef = _applicationContext.ObjectFactory.GetObjectDefinition("Prototype"); - Assert.That(prototypeDef.AutowireMode == AutoWiringMode.ByName); + Assert.That(prototypeDef.AutowireMode == AutoWiringMode.ByName); } [Test] @@ -136,7 +137,7 @@ namespace Spring.Context.Config Assert.That(objectDef.HasQualifier(typeof(QualifierAttribute).Name), Is.True); - var attr = objectDef.GetQualifier(typeof (QualifierAttribute).Name).GetAttribute(AutowireCandidateQualifier.VALUE_KEY); + var attr = objectDef.GetQualifier(typeof(QualifierAttribute).Name).GetAttribute(AutowireCandidateQualifier.VALUE_KEY); Assert.That(attr, Is.EqualTo("action")); } @@ -145,7 +146,7 @@ namespace Spring.Context.Config { _applicationContext = new XmlApplicationContext(ReadOnlyXmlTestResource.GetFilePath("ConfigFiles.ComponentScan6.xml", GetType())); var objectDef = _applicationContext.ObjectFactory.GetObjectDefinition("Attribute") as ScannedGenericObjectDefinition; - var qualifier = objectDef.GetQualifier(typeof (MyQualifier).Name); + var qualifier = objectDef.GetQualifier(typeof(MyQualifier).Name); Assert.That(qualifier, Is.Not.Null); @@ -179,7 +180,6 @@ namespace Spring.Context.Config Assert.That(objectDefintionNames.Contains(AttributeConfigUtils.REQUIRED_ATTRIBUTE_PROCESSOR_OBJECT_NAME), Is.True); Assert.That(objectDefintionNames.Contains(AttributeConfigUtils.INITDESTROY_ATTRIBUTE_PROCESSOR_OBJECT_NAME), Is.True); } - } } @@ -277,7 +277,7 @@ namespace ComponentScan.ComponentsUseDefaults public interface IFoo { } - + [Component("Prototype")] public class PrototypeImpl : IFoo { @@ -302,11 +302,10 @@ namespace ComponentScan.Qualifier } [Component("Attribute")] - [MyQualifier(Foo="Funny")] + [MyQualifier(Foo = "Funny")] public class QualifierAttributeImpl : IFoo { } - } namespace ComponentScan.NameGenerator diff --git a/test/Spring/Spring.Core.Tests/Context/Config/ComponentScanObjectDefinitionParserTypeFilterTests.cs b/test/Spring/Spring.Core.Tests/Context/Config/ComponentScanObjectDefinitionParserTypeFilterTests.cs index fc49b275..2d1d58e0 100644 --- a/test/Spring/Spring.Core.Tests/Context/Config/ComponentScanObjectDefinitionParserTypeFilterTests.cs +++ b/test/Spring/Spring.Core.Tests/Context/Config/ComponentScanObjectDefinitionParserTypeFilterTests.cs @@ -25,7 +25,6 @@ using Spring.Objects.Factory; using Spring.Objects.Factory.Xml; using Spring.Context.Support; - namespace Spring.Context.Config { [TestFixture] @@ -132,7 +131,6 @@ namespace Spring.Context.Config Assert.That(_applicationContext.GetObject("SomeExcludeType"), Is.Not.Null); Assert.That(() => { _applicationContext.GetObject("SomeIncludeType1"); }, Throws.Exception.TypeOf()); } - } } @@ -150,7 +148,7 @@ namespace XmlAssemblyTypeScanner.Test.Include1 [ObjectDef] public virtual SomeIncludeType1 SomeIncludeType1() { - return new SomeIncludeType1(); + return new SomeIncludeType1(); } } @@ -159,8 +157,8 @@ namespace XmlAssemblyTypeScanner.Test.Include1 } public interface IFunny - {} - + { + } public class TestFilter : ITypeFilter { @@ -169,7 +167,6 @@ namespace XmlAssemblyTypeScanner.Test.Include1 return type.Name.Equals("SomeIncludeConfiguration1"); } } - } namespace XmlAssemblyTypeScanner.Test.Include2 @@ -207,7 +204,6 @@ namespace XmlAssemblyTypeScanner.Test.Include [Configuration] public class SomeExcludeConfiguration3 { - [ObjectDef] public virtual SomeExcludeType SomeExcludeType() { diff --git a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/AttributeConfigParser.xml b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/AttributeConfigParser.xml index f4b24465..82a3b313 100644 --- a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/AttributeConfigParser.xml +++ b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/AttributeConfigParser.xml @@ -1,8 +1,8 @@  - - - + + + diff --git a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/BaseAssemblyTestMultiple.xml b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/BaseAssemblyTestMultiple.xml index f0fce716..33b17636 100644 --- a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/BaseAssemblyTestMultiple.xml +++ b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/BaseAssemblyTestMultiple.xml @@ -1,8 +1,8 @@  - - - + + + diff --git a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/BaseAssemblyTestNegative.xml b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/BaseAssemblyTestNegative.xml index bf2405fc..755a34bb 100644 --- a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/BaseAssemblyTestNegative.xml +++ b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/BaseAssemblyTestNegative.xml @@ -1,8 +1,8 @@  - - - + + + diff --git a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/BaseAssemblyTestSingle.xml b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/BaseAssemblyTestSingle.xml index ce45156c..ed52d1c9 100644 --- a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/BaseAssemblyTestSingle.xml +++ b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/BaseAssemblyTestSingle.xml @@ -1,8 +1,8 @@  - - - + + + diff --git a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/BaseAssemblyTestWithout.xml b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/BaseAssemblyTestWithout.xml index 7d781430..249b9210 100644 --- a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/BaseAssemblyTestWithout.xml +++ b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/BaseAssemblyTestWithout.xml @@ -1,8 +1,8 @@  - - - + + + diff --git a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/ComponentScan1.xml b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/ComponentScan1.xml index a68cc463..85efb926 100644 --- a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/ComponentScan1.xml +++ b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/ComponentScan1.xml @@ -2,9 +2,9 @@ - - - - + + + + diff --git a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/ComponentScan2.xml b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/ComponentScan2.xml index 629573f8..3f820953 100644 --- a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/ComponentScan2.xml +++ b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/ComponentScan2.xml @@ -2,9 +2,9 @@ - - - - + + + + diff --git a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/ComponentScan3.xml b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/ComponentScan3.xml index 87c3cf85..2605eab4 100644 --- a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/ComponentScan3.xml +++ b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/ComponentScan3.xml @@ -2,10 +2,10 @@ - - - - + + + + diff --git a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/ComponentScan31.xml b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/ComponentScan31.xml index 1162c903..be276164 100644 --- a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/ComponentScan31.xml +++ b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/ComponentScan31.xml @@ -2,10 +2,10 @@ - - - - + + + + diff --git a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/ComponentScan4.xml b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/ComponentScan4.xml index 5946e407..1048319a 100644 --- a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/ComponentScan4.xml +++ b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/ComponentScan4.xml @@ -2,9 +2,9 @@ - - - - + + + + diff --git a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/ComponentScan5.xml b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/ComponentScan5.xml index 30b6dbe4..b785171b 100644 --- a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/ComponentScan5.xml +++ b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/ComponentScan5.xml @@ -3,9 +3,9 @@ xmlns:context="http://www.springframework.net/context" default-lazy-init="true" default-autowire="byName"> - - - - + + + + diff --git a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/ComponentScan6.xml b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/ComponentScan6.xml index da0b4171..5d1bddb4 100644 --- a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/ComponentScan6.xml +++ b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/ComponentScan6.xml @@ -2,9 +2,9 @@ - - - - + + + + diff --git a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/ComponentScanAttributeConfigFalse.xml b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/ComponentScanAttributeConfigFalse.xml index 740a3e73..daef8fe7 100644 --- a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/ComponentScanAttributeConfigFalse.xml +++ b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/ComponentScanAttributeConfigFalse.xml @@ -2,7 +2,7 @@ - - + + diff --git a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/ComponentScanAttributeConfigTrue.xml b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/ComponentScanAttributeConfigTrue.xml index fac0ba27..c2cf3f7c 100644 --- a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/ComponentScanAttributeConfigTrue.xml +++ b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/ComponentScanAttributeConfigTrue.xml @@ -2,7 +2,7 @@ - - + + diff --git a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/TypeScannerTestAssignableExclude.xml b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/TypeScannerTestAssignableExclude.xml index 625a311b..bafdb2f1 100644 --- a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/TypeScannerTestAssignableExclude.xml +++ b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/TypeScannerTestAssignableExclude.xml @@ -2,10 +2,11 @@ - - - - - + + + + + diff --git a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/TypeScannerTestAssignableInclude.xml b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/TypeScannerTestAssignableInclude.xml index 53a660e8..d89c1a47 100644 --- a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/TypeScannerTestAssignableInclude.xml +++ b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/TypeScannerTestAssignableInclude.xml @@ -2,13 +2,16 @@ - - - - - - - - + + + + + + + + diff --git a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/TypeScannerTestAttributeExclude.xml b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/TypeScannerTestAttributeExclude.xml index 26458303..8a569e7f 100644 --- a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/TypeScannerTestAttributeExclude.xml +++ b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/TypeScannerTestAttributeExclude.xml @@ -2,10 +2,11 @@ - - - - - + + + + + diff --git a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/TypeScannerTestAttributeInclude.xml b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/TypeScannerTestAttributeInclude.xml index bacd9861..2fdf6f91 100644 --- a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/TypeScannerTestAttributeInclude.xml +++ b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/TypeScannerTestAttributeInclude.xml @@ -2,12 +2,13 @@ - - - + + + + + + - - - diff --git a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/TypeScannerTestCustomExclude.xml b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/TypeScannerTestCustomExclude.xml index 73a7710a..be6adce3 100644 --- a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/TypeScannerTestCustomExclude.xml +++ b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/TypeScannerTestCustomExclude.xml @@ -2,10 +2,11 @@ - - - - - + + + + + diff --git a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/TypeScannerTestCustomInclude.xml b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/TypeScannerTestCustomInclude.xml index 8299fb19..4b291764 100644 --- a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/TypeScannerTestCustomInclude.xml +++ b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/TypeScannerTestCustomInclude.xml @@ -2,12 +2,14 @@ - - - - - - - + + + + + + + diff --git a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/TypeScannerTestRegExExclude.xml b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/TypeScannerTestRegExExclude.xml index 096c39e8..492eaeb2 100644 --- a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/TypeScannerTestRegExExclude.xml +++ b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/TypeScannerTestRegExExclude.xml @@ -2,10 +2,10 @@ - - - - + + + + diff --git a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/TypeScannerTestRegExInclude.xml b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/TypeScannerTestRegExInclude.xml index 0e929860..9187cca5 100644 --- a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/TypeScannerTestRegExInclude.xml +++ b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/TypeScannerTestRegExInclude.xml @@ -2,9 +2,9 @@ - - - - + + + + diff --git a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/TypeScannerTestRegExInclude2.xml b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/TypeScannerTestRegExInclude2.xml index 0727c5ed..b64bdf82 100644 --- a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/TypeScannerTestRegExInclude2.xml +++ b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/TypeScannerTestRegExInclude2.xml @@ -2,10 +2,10 @@ - - - - - + + + + + diff --git a/test/Spring/Spring.Core.Tests/Context/Config/ContextNamespaceParserTests.cs b/test/Spring/Spring.Core.Tests/Context/Config/ContextNamespaceParserTests.cs index 2d55d81c..0b971284 100644 --- a/test/Spring/Spring.Core.Tests/Context/Config/ContextNamespaceParserTests.cs +++ b/test/Spring/Spring.Core.Tests/Context/Config/ContextNamespaceParserTests.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2010-2011 the original author or authors. + * Copyright � 2010-2011 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. @@ -18,24 +18,22 @@ #endregion - using NUnit.Framework; using Spring.Objects.Factory.Xml; -namespace Spring.Context.Config +namespace Spring.Context.Config; + +[TestFixture] +public class ContextNamespaceParserTests { - [TestFixture] - public class ContextNamespaceParserTests + [SetUp] + public void Setup() { - [SetUp] - public void Setup() - { - } - - [Test] - public void RegisteredAsWellKnownParser() - { - Assert.IsNotNull(NamespaceParserRegistry.GetParser("http://www.springframework.net/context")); - } } -} \ No newline at end of file + + [Test] + public void RegisteredAsWellKnownParser() + { + Assert.IsNotNull(NamespaceParserRegistry.GetParser("http://www.springframework.net/context")); + } +} diff --git a/test/Spring/Spring.Core.Tests/Context/ContextExceptionTests.cs b/test/Spring/Spring.Core.Tests/Context/ContextExceptionTests.cs index d515fb4a..dc6355ae 100644 --- a/test/Spring/Spring.Core.Tests/Context/ContextExceptionTests.cs +++ b/test/Spring/Spring.Core.Tests/Context/ContextExceptionTests.cs @@ -21,24 +21,22 @@ #region Imports using System.Reflection; - using NUnit.Framework; #endregion -namespace Spring.Context +namespace Spring.Context; + +/// +/// Unit tests for all of the exception classes in the Spring.Context library... +/// +/// Rick Evans +[TestFixture] +public sealed class ContextExceptionTests : ExceptionsTest { - /// - /// Unit tests for all of the exception classes in the Spring.Context library... - /// - /// Rick Evans - [TestFixture] - public sealed class ContextExceptionTests : ExceptionsTest + [OneTimeSetUp] + public void FixtureSetUp() { - [OneTimeSetUp] - public void FixtureSetUp () - { - AssemblyToCheck = Assembly.GetAssembly (typeof (Spring.Context.ApplicationContextException)); - } + AssemblyToCheck = Assembly.GetAssembly(typeof(Spring.Context.ApplicationContextException)); } -} +} \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/Context/ContextListenerObject.cs b/test/Spring/Spring.Core.Tests/Context/ContextListenerObject.cs index 9743cc08..97bad6a8 100644 --- a/test/Spring/Spring.Core.Tests/Context/ContextListenerObject.cs +++ b/test/Spring/Spring.Core.Tests/Context/ContextListenerObject.cs @@ -20,84 +20,84 @@ using Spring.Context.Events; #endregion -namespace Spring.Context +namespace Spring.Context; + +/// +/// Test object for receiving application context events. +/// +/// Mark Pollack +public sealed class ContextListenerObject : IApplicationContextAware, IApplicationEventListener { - /// - /// Test object for receiving application context events. - /// - /// Mark Pollack - public sealed class ContextListenerObject : IApplicationContextAware, IApplicationEventListener - { - private IApplicationContext _ctx; - private bool _appListenerContextRefreshed = false; - private bool _appListenerContextClosed = false; - private bool _ctxRefreshed = false; - private bool _ctxClosed = false; + private IApplicationContext _ctx; + private bool _appListenerContextRefreshed = false; + private bool _appListenerContextClosed = false; + private bool _ctxRefreshed = false; + private bool _ctxClosed = false; - public ContextListenerObject() - { - } + public ContextListenerObject() + { + } - public IApplicationContext ApplicationContext - { - set - { - _ctx = value; - _ctx.ContextEvent += new ApplicationEventHandler(ContextRefreshedHandler); - } - get { return _ctx; } - } + public IApplicationContext ApplicationContext + { + set + { + _ctx = value; + _ctx.ContextEvent += new ApplicationEventHandler(ContextRefreshedHandler); + } + get { return _ctx; } + } - public bool AppListenerContextRefreshed - { - get { return _appListenerContextRefreshed; } - } + public bool AppListenerContextRefreshed + { + get { return _appListenerContextRefreshed; } + } - public bool AppListenerContextClosed - { - get { return _appListenerContextClosed; } - } + public bool AppListenerContextClosed + { + get { return _appListenerContextClosed; } + } - public bool CtxRefreshed - { - get { return _ctxRefreshed; } - } + public bool CtxRefreshed + { + get { return _ctxRefreshed; } + } - public bool CtxClosed - { - get { return _ctxClosed; } - } + public bool CtxClosed + { + get { return _ctxClosed; } + } - public void HandleApplicationEvent(object source, ApplicationEventArgs e) - { - ContextEventArgs ctxArgs = e as ContextEventArgs; - if (ctxArgs != null) - { - if (ctxArgs.Event == ContextEventArgs.ContextEvent.Refreshed) - { - _appListenerContextRefreshed = true; - } - if (ctxArgs.Event == ContextEventArgs.ContextEvent.Closed) - { - _appListenerContextClosed = true; - } - } - } + public void HandleApplicationEvent(object source, ApplicationEventArgs e) + { + ContextEventArgs ctxArgs = e as ContextEventArgs; + if (ctxArgs != null) + { + if (ctxArgs.Event == ContextEventArgs.ContextEvent.Refreshed) + { + _appListenerContextRefreshed = true; + } - private void ContextRefreshedHandler(object sender, ApplicationEventArgs e) - { - ContextEventArgs args = e as ContextEventArgs; - if (args != null) - { - if (args.Event == ContextEventArgs.ContextEvent.Refreshed) - { - _ctxRefreshed = true; - } - else if (args.Event == ContextEventArgs.ContextEvent.Closed) - { - _ctxClosed = true; - } - } - } - } -} \ No newline at end of file + if (ctxArgs.Event == ContextEventArgs.ContextEvent.Closed) + { + _appListenerContextClosed = true; + } + } + } + + private void ContextRefreshedHandler(object sender, ApplicationEventArgs e) + { + ContextEventArgs args = e as ContextEventArgs; + if (args != null) + { + if (args.Event == ContextEventArgs.ContextEvent.Refreshed) + { + _ctxRefreshed = true; + } + else if (args.Event == ContextEventArgs.ContextEvent.Closed) + { + _ctxClosed = true; + } + } + } +} diff --git a/test/Spring/Spring.Core.Tests/Context/EventListenerAttributeTests.cs b/test/Spring/Spring.Core.Tests/Context/EventListenerAttributeTests.cs index 4d9d01fe..8e5059af 100644 --- a/test/Spring/Spring.Core.Tests/Context/EventListenerAttributeTests.cs +++ b/test/Spring/Spring.Core.Tests/Context/EventListenerAttributeTests.cs @@ -20,24 +20,24 @@ using NUnit.Framework; -namespace Spring.Context +namespace Spring.Context; + +[TestFixture] +public sealed class EventListenerAttributeTests { - [TestFixture] - public sealed class EventListenerAttributeTests - { - [Test] - public void ReadEventListenerAttribute() - { - Attribute[] attributes = Attribute.GetCustomAttributes(typeof (IApplicationEventListener)); - bool found = false; - foreach (Attribute attribute in attributes) - { - if (attribute is EventListenerAttribute) - { - found = true; - } - } - Assert.IsTrue(found, "EventListener Attribute not found"); - } - } -} \ No newline at end of file + [Test] + public void ReadEventListenerAttribute() + { + Attribute[] attributes = Attribute.GetCustomAttributes(typeof(IApplicationEventListener)); + bool found = false; + foreach (Attribute attribute in attributes) + { + if (attribute is EventListenerAttribute) + { + found = true; + } + } + + Assert.IsTrue(found, "EventListener Attribute not found"); + } +} diff --git a/test/Spring/Spring.Core.Tests/Context/Events/ConsoleListenerTests.cs b/test/Spring/Spring.Core.Tests/Context/Events/ConsoleListenerTests.cs index 18ad9af0..0eef674c 100644 --- a/test/Spring/Spring.Core.Tests/Context/Events/ConsoleListenerTests.cs +++ b/test/Spring/Spring.Core.Tests/Context/Events/ConsoleListenerTests.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -20,16 +20,15 @@ using NUnit.Framework; -namespace Spring.Context.Events +namespace Spring.Context.Events; + +[TestFixture] +public class ConsoleListenerTests { - [TestFixture] - public class ConsoleListenerTests - { - [Test] - public void ConsoleOnApplicationEvent() - { - ConsoleListener listener = new ConsoleListener(); - listener.HandleApplicationEvent( this, new ApplicationEventArgs() ); - } - } + [Test] + public void ConsoleOnApplicationEvent() + { + ConsoleListener listener = new ConsoleListener(); + listener.HandleApplicationEvent(this, new ApplicationEventArgs()); + } } diff --git a/test/Spring/Spring.Core.Tests/Context/Support/AbstractApplicationContextTests.cs b/test/Spring/Spring.Core.Tests/Context/Support/AbstractApplicationContextTests.cs index 0e68bcc6..29fbf8ca 100644 --- a/test/Spring/Spring.Core.Tests/Context/Support/AbstractApplicationContextTests.cs +++ b/test/Spring/Spring.Core.Tests/Context/Support/AbstractApplicationContextTests.cs @@ -19,7 +19,6 @@ #endregion using FakeItEasy; - using NUnit.Framework; using Spring.Core; using Spring.Core.IO; @@ -30,376 +29,373 @@ using Spring.Objects.Factory.Config; using Spring.Objects.Factory.Support; using Spring.Objects.Factory.Xml; -namespace Spring.Context.Support +namespace Spring.Context.Support; + +[TestFixture] +public class AbstractApplicationContextTests { - [TestFixture] - public class AbstractApplicationContextTests - { - private MockApplicationContext _context; + private MockApplicationContext _context; - [SetUp] - public void Init() - { - EverythingAwareObject.InstanceCount = 0; - EverythingAwareObjectFactoryPostProcessor.InstanceCount = 0; - EverythingAwareObjectPostProcessor.InstanceCount = 0; - _context = new MockApplicationContext("MockApplicationContextName"); - } + [SetUp] + public void Init() + { + EverythingAwareObject.InstanceCount = 0; + EverythingAwareObjectFactoryPostProcessor.InstanceCount = 0; + EverythingAwareObjectPostProcessor.InstanceCount = 0; + _context = new MockApplicationContext("MockApplicationContextName"); + } - [TearDown] - public void Destroy() - { - _context.Dispose(); - _context = null; - } + [TearDown] + public void Destroy() + { + _context.Dispose(); + _context = null; + } + public void ContextAwareDisplayName() + { + } - public void ContextAwareDisplayName() + [Test] + public void ExecutesAllContextEventHandlersAndRethrowsExceptionsThrownDuringContextEventHandlingByDefault() + { + MockApplicationContext appCtx = new MockApplicationContext(); + bool secondHandlerExecuted = false; + appCtx.ContextEvent += (sender, e) => { + throw new ApplicationException("dummy"); + }; + appCtx.ContextEvent += (sender, e) => + { + secondHandlerExecuted = true; + }; + ApplicationException resultException = null; + try + { + appCtx.PublishEvent(this, new ApplicationEventArgs()); + Assert.Fail(); + } + catch (ApplicationContextException e) + { + resultException = (ApplicationException) e.GetBaseException(); } - [Test] - public void ExecutesAllContextEventHandlersAndRethrowsExceptionsThrownDuringContextEventHandlingByDefault() - { - MockApplicationContext appCtx = new MockApplicationContext(); - bool secondHandlerExecuted = false; - appCtx.ContextEvent += (sender, e) => + Assert.AreEqual("dummy", resultException.Message); + Assert.IsTrue(secondHandlerExecuted); + } + + [Test] + public void DoesNotSearchParentContextForMessageSource() + { + IMessageSource msgSource = A.Fake(); + MockApplicationContext parentCtx = new MockApplicationContext("parentContext"); + parentCtx.ObjectFactory.RegisterSingleton(AbstractApplicationContext.MessageSourceObjectName, msgSource); + MockApplicationContext childContext = new MockApplicationContext("childContext", parentCtx); + parentCtx.Refresh(); + childContext.Refresh(); + + Assert.AreNotSame(msgSource, childContext.MessageSource); + Assert.AreSame(msgSource, parentCtx.MessageSource); + Assert.AreEqual(msgSource, ((IHierarchicalMessageSource) childContext.MessageSource).ParentMessageSource); + } + + [Test] + public void DoesNotSearchParentContextForEventRegistry() + { + IEventRegistry eventRegistry = A.Fake(); + MockApplicationContext parentCtx = new MockApplicationContext("parentContext"); + parentCtx.ObjectFactory.RegisterSingleton(AbstractApplicationContext.EventRegistryObjectName, eventRegistry); + MockApplicationContext childContext = new MockApplicationContext("childContext", parentCtx); + parentCtx.Refresh(); + childContext.Refresh(); + + Assert.AreSame(eventRegistry, parentCtx.EventRegistry); + Assert.AreNotSame(eventRegistry, childContext.EventRegistry); + } + + /// + /// Tests the case where there is an object in the context with the name of the + /// default message source name, that is NOT an IMessageSource. + /// + [Test] + public void InvalidMessageSourceObject() + { + RootObjectDefinition def = new RootObjectDefinition(typeof(TestObject)); + ((DefaultListableObjectFactory) _context.ObjectFactory) + .RegisterObjectDefinition(AbstractApplicationContext.MessageSourceObjectName, def); + _context.Refresh(); + object foo = _context + .GetObject(AbstractApplicationContext.MessageSourceObjectName); + Assert.IsTrue(foo is ITestObject, + "Registered non-IMessageSource object under the default message source name, but " + + "failed to get it out of the context. Object retrieved is of type [ " + foo.GetType() + "]."); + } + + /// + /// Tests the case where there is an object in the context with the name of the + /// default event registry name, that is NOT an IEventRegistry. + /// + [Test] + public void InvalidEventRegistryObject() + { + RootObjectDefinition def = new RootObjectDefinition(typeof(TestObject)); + ((DefaultListableObjectFactory) _context.ObjectFactory) + .RegisterObjectDefinition(AbstractApplicationContext.EventRegistryObjectName, def); + _context.Refresh(); + object foo = _context + .GetObject(AbstractApplicationContext.EventRegistryObjectName); + Assert.IsTrue(foo is ITestObject, + "Registered non-IEventRegistry object under the default message source name, but " + + "failed to get it out of the context. Object retrieved is of type [ " + foo.GetType() + "]."); + } + + [Test] + public void ContextAwareSingletonWasCalledBack() + { + _context.RegisterSingleton(); + _context.Refresh(); + MockContextAwareObject mcao1 = (MockContextAwareObject) _context.GetObject("mcao-single"); + Assert.IsTrue(mcao1.ApplicationContext == _context, "context"); + object mcao2 = _context.GetObject("mcao-single"); + Assert.IsTrue(mcao1 == mcao2, "same"); + Assert.IsTrue(_context.IsSingleton("mcao-single"), "singleton?"); + } + + [Test] + public void ContextAwarePrototypeWasCalledBack() + { + _context.RegisterObject(); + _context.Refresh(); + MockContextAwareObject mcao1 = (MockContextAwareObject) _context.GetObject("mcao-proto"); + Assert.IsTrue(mcao1.ApplicationContext == _context, "context"); + Assert.IsTrue(!_context.IsSingleton("mcao-proto"), "singleton"); + MockContextAwareObject mcao2 = (MockContextAwareObject) _context.GetObject("mcao-proto"); + Assert.IsTrue(mcao1 != mcao2, "instance"); + } + + [Test] + public void ContextAwareSingletonGetName() + { + _context.RegisterSingleton(); + _context.Refresh(); + MockContextAwareObject mcao1 = (MockContextAwareObject) _context.GetObject("mcao-single"); + Assert.AreEqual(mcao1.ApplicationContext.Name, "MockApplicationContextName"); + } + + [Test] + public void ContextAwarePrototypeGetName() + { + _context.RegisterObject(); + _context.Refresh(); + MockContextAwareObject mcao1 = (MockContextAwareObject) _context.GetObject("mcao-proto"); + Assert.AreEqual(mcao1.ApplicationContext.Name, "MockApplicationContextName"); + } + + [Test] + public void ParentNull() + { + Assert.IsNull(_context.ParentContext, "parent is not null"); + } + + [Test] + public void ParentNotNullGrandparentNull() + { + IApplicationContext parentContext = new MockApplicationContext("MockApplicationContextParent"); + _context = new MockApplicationContext("MockApplicationContextName", parentContext); + Assert.IsNotNull(_context.ParentContext, "parent is null"); + Assert.IsNull(_context.ParentContext.ParentContext, "parent is null"); + } + + #region OrderOfKnownProcessorInterfaces Utility Classes + + public enum ObjectProcessingState + { + SetObjectName, + SetObjectFactory, + SetApplicationContext, + PostProcessObjectFactory, + ObjectPostProcessorBeforeInitialization, + ObjectPostProcessorAfterInitialization, + } + + public class EverythingAwareObject : + IObjectNameAware, + IObjectFactoryAware, + IApplicationContextAware + { + public static int InstanceCount = 0; + + private ObjectProcessingState currentState; + + public EverythingAwareObject() + { + InstanceCount++; + } + + public EverythingAwareObject(int expectObjectPostProcessorInstances) + : this() + { + // ensure postprocessor has been instantiated *before* this object + Assert.AreEqual(expectObjectPostProcessorInstances, EverythingAwareObjectPostProcessor.InstanceCount); + } + + public ObjectProcessingState CurrentState + { + get { return currentState; } + set { currentState = value; } + } + + public IApplicationContext ApplicationContext + { + get { throw new NotImplementedException(); } + set { - throw new ApplicationException("dummy"); - }; - appCtx.ContextEvent += (sender, e) => + Assert.AreEqual(ObjectProcessingState.SetApplicationContext, this.CurrentState); + this.CurrentState++; + } + } + + public string ObjectName + { + set { - secondHandlerExecuted = true; - }; - - - ApplicationException resultException = null; - try - { - appCtx.PublishEvent(this, new ApplicationEventArgs()); - Assert.Fail(); - } - catch (ApplicationContextException e) - { - resultException = (ApplicationException) e.GetBaseException(); - } - - Assert.AreEqual("dummy", resultException.Message); - Assert.IsTrue(secondHandlerExecuted); + Assert.AreEqual(ObjectProcessingState.SetObjectName, this.CurrentState); + this.CurrentState++; + } } - [Test] - public void DoesNotSearchParentContextForMessageSource() - { - IMessageSource msgSource = A.Fake(); - MockApplicationContext parentCtx = new MockApplicationContext("parentContext"); - parentCtx.ObjectFactory.RegisterSingleton(AbstractApplicationContext.MessageSourceObjectName, msgSource); - MockApplicationContext childContext = new MockApplicationContext("childContext", parentCtx); - parentCtx.Refresh(); - childContext.Refresh(); + private bool objectFactorySet = false; - Assert.AreNotSame( msgSource, childContext.MessageSource ); - Assert.AreSame(msgSource, parentCtx.MessageSource); - Assert.AreEqual(msgSource, ((IHierarchicalMessageSource)childContext.MessageSource).ParentMessageSource); + public IObjectFactory ObjectFactory + { + set + { + // ignore multiple calls (due to OF also set during AbstractObjectFactory.AddObjectPostProcessor()) + if (objectFactorySet) + { + return; + } + + objectFactorySet = true; + Assert.AreEqual(ObjectProcessingState.SetObjectFactory, this.CurrentState); + this.CurrentState++; + } + } + } + + public class EverythingAwareObjectFactoryPostProcessor : EverythingAwareObject, + IObjectFactoryPostProcessor + { + public new static int InstanceCount = 0; + + public EverythingAwareObjectFactoryPostProcessor() + { + InstanceCount++; } - [Test] - public void DoesNotSearchParentContextForEventRegistry() + public void PostProcessObjectFactory(IConfigurableListableObjectFactory factory) { - IEventRegistry eventRegistry = A.Fake(); - MockApplicationContext parentCtx = new MockApplicationContext("parentContext"); - parentCtx.ObjectFactory.RegisterSingleton(AbstractApplicationContext.EventRegistryObjectName, eventRegistry); - MockApplicationContext childContext = new MockApplicationContext("childContext", parentCtx); - parentCtx.Refresh(); - childContext.Refresh(); + Assert.AreEqual(ObjectProcessingState.PostProcessObjectFactory, CurrentState); + CurrentState++; + } + } - Assert.AreSame( eventRegistry, parentCtx.EventRegistry ); - Assert.AreNotSame( eventRegistry, childContext.EventRegistry ); + public class EverythingAwareObjectPostProcessor : EverythingAwareObjectFactoryPostProcessor, + IObjectPostProcessor + { + public new static int InstanceCount = 0; + + public EverythingAwareObjectPostProcessor() + { + InstanceCount++; } - /// - /// Tests the case where there is an object in the context with the name of the - /// default message source name, that is NOT an IMessageSource. - /// - [Test] - public void InvalidMessageSourceObject() - { - RootObjectDefinition def = new RootObjectDefinition(typeof (TestObject)); - ((DefaultListableObjectFactory) _context.ObjectFactory) - .RegisterObjectDefinition(AbstractApplicationContext.MessageSourceObjectName, def); - _context.Refresh(); - object foo = _context - .GetObject(AbstractApplicationContext.MessageSourceObjectName); - Assert.IsTrue(foo is ITestObject, - "Registered non-IMessageSource object under the default message source name, but " + - "failed to get it out of the context. Object retrieved is of type [ " + foo.GetType() + "]."); - } - - /// - /// Tests the case where there is an object in the context with the name of the - /// default event registry name, that is NOT an IEventRegistry. - /// - [Test] - public void InvalidEventRegistryObject() - { - RootObjectDefinition def = new RootObjectDefinition(typeof (TestObject)); - ((DefaultListableObjectFactory) _context.ObjectFactory) - .RegisterObjectDefinition(AbstractApplicationContext.EventRegistryObjectName, def); - _context.Refresh(); - object foo = _context - .GetObject(AbstractApplicationContext.EventRegistryObjectName); - Assert.IsTrue(foo is ITestObject, - "Registered non-IEventRegistry object under the default message source name, but " + - "failed to get it out of the context. Object retrieved is of type [ " + foo.GetType() + "]."); - } - - [Test] - public void ContextAwareSingletonWasCalledBack() - { - _context.RegisterSingleton(); - _context.Refresh(); - MockContextAwareObject mcao1 = (MockContextAwareObject)_context.GetObject("mcao-single"); - Assert.IsTrue(mcao1.ApplicationContext == _context, "context"); - object mcao2 = _context.GetObject("mcao-single"); - Assert.IsTrue(mcao1 == mcao2, "same"); - Assert.IsTrue(_context.IsSingleton("mcao-single"), "singleton?"); - } - - [Test] - public void ContextAwarePrototypeWasCalledBack() - { - _context.RegisterObject(); - _context.Refresh(); - MockContextAwareObject mcao1 = (MockContextAwareObject)_context.GetObject("mcao-proto"); - Assert.IsTrue(mcao1.ApplicationContext == _context, "context"); - Assert.IsTrue(! _context.IsSingleton("mcao-proto"), "singleton"); - MockContextAwareObject mcao2 = (MockContextAwareObject) _context.GetObject("mcao-proto"); - Assert.IsTrue(mcao1 != mcao2, "instance"); - - } - - [Test] - public void ContextAwareSingletonGetName() - { - _context.RegisterSingleton(); - _context.Refresh(); - MockContextAwareObject mcao1 = (MockContextAwareObject)_context.GetObject("mcao-single"); - Assert.AreEqual(mcao1.ApplicationContext.Name, "MockApplicationContextName"); - } - - [Test] - public void ContextAwarePrototypeGetName() - { - _context.RegisterObject(); - _context.Refresh(); - MockContextAwareObject mcao1 = (MockContextAwareObject)_context.GetObject("mcao-proto"); - Assert.AreEqual(mcao1.ApplicationContext.Name, "MockApplicationContextName"); - } - - [Test] - public void ParentNull() - { - Assert.IsNull(_context.ParentContext, "parent is not null"); - } - - [Test] - public void ParentNotNullGrandparentNull() - { - IApplicationContext parentContext = new MockApplicationContext("MockApplicationContextParent"); - _context = new MockApplicationContext("MockApplicationContextName", parentContext); - Assert.IsNotNull(_context.ParentContext, "parent is null"); - Assert.IsNull(_context.ParentContext.ParentContext, "parent is null"); - } - - #region OrderOfKnownProcessorInterfaces Utility Classes - - public enum ObjectProcessingState - { - SetObjectName, - SetObjectFactory, - SetApplicationContext, - PostProcessObjectFactory, - ObjectPostProcessorBeforeInitialization, - ObjectPostProcessorAfterInitialization, - } - - public class EverythingAwareObject : - IObjectNameAware, - IObjectFactoryAware, - IApplicationContextAware - { - public static int InstanceCount = 0; - - private ObjectProcessingState currentState; - - public EverythingAwareObject() - { - InstanceCount++; - } - - public EverythingAwareObject(int expectObjectPostProcessorInstances) - :this() - { - // ensure postprocessor has been instantiated *before* this object - Assert.AreEqual(expectObjectPostProcessorInstances, EverythingAwareObjectPostProcessor.InstanceCount); - } - - public ObjectProcessingState CurrentState - { - get { return currentState;} - set { currentState = value; } - } - - public IApplicationContext ApplicationContext - { - get { throw new NotImplementedException(); } - set - { - Assert.AreEqual(ObjectProcessingState.SetApplicationContext, this.CurrentState); - this.CurrentState++; - } - } - - public string ObjectName - { - set - { - Assert.AreEqual(ObjectProcessingState.SetObjectName, this.CurrentState); - this.CurrentState++; - } - } - - private bool objectFactorySet = false; - public IObjectFactory ObjectFactory - { - set - { - // ignore multiple calls (due to OF also set during AbstractObjectFactory.AddObjectPostProcessor()) - if (objectFactorySet) - { - return; - } - objectFactorySet = true; - Assert.AreEqual(ObjectProcessingState.SetObjectFactory, this.CurrentState); - this.CurrentState++; - } - } - } - - public class EverythingAwareObjectFactoryPostProcessor : EverythingAwareObject, - IObjectFactoryPostProcessor - { - public new static int InstanceCount = 0; - - public EverythingAwareObjectFactoryPostProcessor() - { - InstanceCount++; - } - - public void PostProcessObjectFactory(IConfigurableListableObjectFactory factory) - { - Assert.AreEqual(ObjectProcessingState.PostProcessObjectFactory, CurrentState); - CurrentState++; - } - } - - public class EverythingAwareObjectPostProcessor : EverythingAwareObjectFactoryPostProcessor, - IObjectPostProcessor - { - public new static int InstanceCount = 0; - - public EverythingAwareObjectPostProcessor() - { - InstanceCount++; - } - - public EverythingAwareObjectPostProcessor(int expectObjectFactoryPostProcessorInstances) - :this() - { - // ensure factorypostprocessor has been instantiated *before* this object - Assert.AreEqual(expectObjectFactoryPostProcessorInstances, EverythingAwareObjectFactoryPostProcessor.InstanceCount); - } - - public object PostProcessBeforeInitialization(object instance, string name) - { - Assert.AreNotEqual(this, instance); - Assert.AreEqual(ObjectProcessingState.ObjectPostProcessorBeforeInitialization, CurrentState); - CurrentState++; - return instance; - } - - public object PostProcessAfterInitialization(object instance, string objectName) - { - Assert.AreNotEqual(this, instance); - Assert.AreEqual(ObjectProcessingState.ObjectPostProcessorAfterInitialization, CurrentState); - CurrentState++; - return instance; - } - } - - #endregion - - [Test] - public void OrderOfKnownProcessorInterfaces() - { - DefaultListableObjectFactory objectFactory = (DefaultListableObjectFactory)this._context.ObjectFactory; - RootObjectDefinition def; - def = new RootObjectDefinition(typeof(EverythingAwareObjectPostProcessor)); - objectFactory.RegisterObjectDefinition("everythingAwareObjectPostProcessor", def); - _context.Refresh(); - } - - [Test] - public void OrderOfKnownProcessorInstantiation() - { - DefaultListableObjectFactory objectFactory = (DefaultListableObjectFactory)this._context.ObjectFactory; - RootObjectDefinition def; - // note the order of registration (checks instantiation does not occur in order of registration) - def = new RootObjectDefinition(typeof(EverythingAwareObject)); - def.ConstructorArgumentValues.AddIndexedArgumentValue(0, 1); - objectFactory.RegisterObjectDefinition("everythingAwareObject", def); - def = new RootObjectDefinition(typeof(EverythingAwareObjectPostProcessor)); - def.ConstructorArgumentValues.AddIndexedArgumentValue(0, 1); - objectFactory.RegisterObjectDefinition("everythingAwareObjectPostProcessor", def); - def = new RootObjectDefinition(typeof(EverythingAwareObjectFactoryPostProcessor)); - objectFactory.RegisterObjectDefinition("everythingAwareObjectFactoryPostProcessor", def); - _context.Refresh(); - } - - [Test] - public void DefaultObjectFactoryProcessorsDontGetAddedTwice() - { - MockApplicationContext myContext = new MockApplicationContext("myContext"); - DefaultListableObjectFactory objectFactory = (DefaultListableObjectFactory)myContext.ObjectFactory; - Assert.AreEqual(0, objectFactory.ObjectPostProcessorCount); - myContext.Refresh(); - int defaultProcessors = objectFactory.ObjectPostProcessors.Count; - myContext.Refresh(); - Assert.AreEqual(defaultProcessors, objectFactory.ObjectPostProcessors.Count); - } - - [Test] - public void ThrowsCannotLoadObjectTypeExceptionOnInvalidTypename() + public EverythingAwareObjectPostProcessor(int expectObjectFactoryPostProcessorInstances) + : this() + { + // ensure factorypostprocessor has been instantiated *before* this object + Assert.AreEqual(expectObjectFactoryPostProcessorInstances, EverythingAwareObjectFactoryPostProcessor.InstanceCount); + } + + public object PostProcessBeforeInitialization(object instance, string name) + { + Assert.AreNotEqual(this, instance); + Assert.AreEqual(ObjectProcessingState.ObjectPostProcessorBeforeInitialization, CurrentState); + CurrentState++; + return instance; + } + + public object PostProcessAfterInitialization(object instance, string objectName) + { + Assert.AreNotEqual(this, instance); + Assert.AreEqual(ObjectProcessingState.ObjectPostProcessorAfterInitialization, CurrentState); + CurrentState++; + return instance; + } + } + + #endregion + + [Test] + public void OrderOfKnownProcessorInterfaces() + { + DefaultListableObjectFactory objectFactory = (DefaultListableObjectFactory) this._context.ObjectFactory; + RootObjectDefinition def; + def = new RootObjectDefinition(typeof(EverythingAwareObjectPostProcessor)); + objectFactory.RegisterObjectDefinition("everythingAwareObjectPostProcessor", def); + _context.Refresh(); + } + + [Test] + public void OrderOfKnownProcessorInstantiation() + { + DefaultListableObjectFactory objectFactory = (DefaultListableObjectFactory) this._context.ObjectFactory; + RootObjectDefinition def; + // note the order of registration (checks instantiation does not occur in order of registration) + def = new RootObjectDefinition(typeof(EverythingAwareObject)); + def.ConstructorArgumentValues.AddIndexedArgumentValue(0, 1); + objectFactory.RegisterObjectDefinition("everythingAwareObject", def); + def = new RootObjectDefinition(typeof(EverythingAwareObjectPostProcessor)); + def.ConstructorArgumentValues.AddIndexedArgumentValue(0, 1); + objectFactory.RegisterObjectDefinition("everythingAwareObjectPostProcessor", def); + def = new RootObjectDefinition(typeof(EverythingAwareObjectFactoryPostProcessor)); + objectFactory.RegisterObjectDefinition("everythingAwareObjectFactoryPostProcessor", def); + _context.Refresh(); + } + + [Test] + public void DefaultObjectFactoryProcessorsDontGetAddedTwice() + { + MockApplicationContext myContext = new MockApplicationContext("myContext"); + DefaultListableObjectFactory objectFactory = (DefaultListableObjectFactory) myContext.ObjectFactory; + Assert.AreEqual(0, objectFactory.ObjectPostProcessorCount); + myContext.Refresh(); + int defaultProcessors = objectFactory.ObjectPostProcessors.Count; + myContext.Refresh(); + Assert.AreEqual(defaultProcessors, objectFactory.ObjectPostProcessors.Count); + } + + [Test] + public void ThrowsCannotLoadObjectTypeExceptionOnInvalidTypename() + { + try { - try - { MockApplicationContext myContext = new MockApplicationContext("myContext"); - DefaultListableObjectFactory objectFactory = (DefaultListableObjectFactory)myContext.ObjectFactory; + DefaultListableObjectFactory objectFactory = (DefaultListableObjectFactory) myContext.ObjectFactory; XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(objectFactory); reader.LoadObjectDefinitions(new StringResource( - @" + @" ")); myContext.Refresh(); - } - catch (Exception e) - { + } + catch (Exception e) + { // Console.WriteLine(e); Assert.IsInstanceOf(typeof(CannotLoadObjectTypeException), e); - } } - } -} \ No newline at end of file + } +} diff --git a/test/Spring/Spring.Core.Tests/Context/Support/AbstractMessageSourceTests.cs b/test/Spring/Spring.Core.Tests/Context/Support/AbstractMessageSourceTests.cs index ef3998c1..ee673123 100644 --- a/test/Spring/Spring.Core.Tests/Context/Support/AbstractMessageSourceTests.cs +++ b/test/Spring/Spring.Core.Tests/Context/Support/AbstractMessageSourceTests.cs @@ -19,194 +19,191 @@ #endregion using System.Globalization; - using FakeItEasy; - using NUnit.Framework; -namespace Spring.Context.Support +namespace Spring.Context.Support; + +[TestFixture] +public sealed class AbstractMessageSourceTests : AbstractMessageSource { - [TestFixture] - public sealed class AbstractMessageSourceTests : AbstractMessageSource - { - [SetUp] - public void Init() - { - ResetMe(); - } + [SetUp] + public void Init() + { + ResetMe(); + } - [Test] - public void GetResolvableNullCodes() - { - var res = A.Fake(); - A.CallTo(() => res.DefaultMessage).Returns(null); + [Test] + public void GetResolvableNullCodes() + { + var res = A.Fake(); + A.CallTo(() => res.DefaultMessage).Returns(null); - Assert.Throws(() => GetMessage(res, CultureInfo.CurrentCulture)); - } + Assert.Throws(() => GetMessage(res, CultureInfo.CurrentCulture)); + } - [Test] - public void GetResolvableDefaultsToParentMessageSource() - { - string MSGCODE = "nullCode"; - object[] MSGARGS = new object[] { "arg1", "arg2" }; + [Test] + public void GetResolvableDefaultsToParentMessageSource() + { + string MSGCODE = "nullCode"; + object[] MSGARGS = new object[] { "arg1", "arg2" }; - IMessageSourceResolvable res = A.Fake(); - A.CallTo(() => res.GetArguments()).Returns(MSGARGS); - A.CallTo(() => res.GetCodes()).Returns(new string[] {MSGCODE}).Once(); + IMessageSourceResolvable res = A.Fake(); + A.CallTo(() => res.GetArguments()).Returns(MSGARGS); + A.CallTo(() => res.GetCodes()).Returns(new string[] { MSGCODE }).Once(); - IMessageSource parentSource = A.Fake(); - A.CallTo(() => parentSource.GetMessage(MSGCODE, null, CultureInfo.CurrentCulture, A._)).Returns("MockMessageSource"); - ParentMessageSource = parentSource; + IMessageSource parentSource = A.Fake(); + A.CallTo(() => parentSource.GetMessage(MSGCODE, null, CultureInfo.CurrentCulture, A._)).Returns("MockMessageSource"); + ParentMessageSource = parentSource; - Assert.AreEqual("MockMessageSource", GetMessage(res, CultureInfo.CurrentCulture), "My Message"); - } + Assert.AreEqual("MockMessageSource", GetMessage(res, CultureInfo.CurrentCulture), "My Message"); + } - [Test] - public void GetMessageParentMessageSource() - { - object[] args = new object[] {"arguments"}; - IMessageSource parentSource = A.Fake(); - A.CallTo(() => parentSource.GetMessage("null", null, CultureInfo.CurrentCulture, A._)).Returns("my parent message"); - ParentMessageSource = parentSource; - Assert.AreEqual("my parent message", GetMessage("null", "message", CultureInfo.CurrentCulture, args[0])); - } + [Test] + public void GetMessageParentMessageSource() + { + object[] args = new object[] { "arguments" }; + IMessageSource parentSource = A.Fake(); + A.CallTo(() => parentSource.GetMessage("null", null, CultureInfo.CurrentCulture, A._)).Returns("my parent message"); + ParentMessageSource = parentSource; + Assert.AreEqual("my parent message", GetMessage("null", "message", CultureInfo.CurrentCulture, args[0])); + } - [Test] - public void GetMessageResolvableDefaultMessage() - { - IMessageSourceResolvable res = A.Fake(); - A.CallTo(() => res.DefaultMessage).Returns("MyDefaultMessage"); - A.CallTo(() => res.GetCodes()).Returns(null); - A.CallTo(() => res.GetArguments()).Returns(null); + [Test] + public void GetMessageResolvableDefaultMessage() + { + IMessageSourceResolvable res = A.Fake(); + A.CallTo(() => res.DefaultMessage).Returns("MyDefaultMessage"); + A.CallTo(() => res.GetCodes()).Returns(null); + A.CallTo(() => res.GetArguments()).Returns(null); - Assert.AreEqual("MyDefaultMessage", GetMessage(res, CultureInfo.CurrentCulture), "Default"); - } + Assert.AreEqual("MyDefaultMessage", GetMessage(res, CultureInfo.CurrentCulture), "Default"); + } - [Test] - public void GetMessageResolvableReturnsFirstCode() - { - IMessageSourceResolvable res = A.Fake(); - A.CallTo(() => res.DefaultMessage).Returns(null); - A.CallTo(() => res.GetCodes()).Returns(new string[] {"null"}); - A.CallTo(() => res.GetArguments()).Returns(null); + [Test] + public void GetMessageResolvableReturnsFirstCode() + { + IMessageSourceResolvable res = A.Fake(); + A.CallTo(() => res.DefaultMessage).Returns(null); + A.CallTo(() => res.GetCodes()).Returns(new string[] { "null" }); + A.CallTo(() => res.GetArguments()).Returns(null); - UseCodeAsDefaultMessage = true; - Assert.AreEqual("null", GetMessage(res, CultureInfo.CurrentCulture), "Code"); - } + UseCodeAsDefaultMessage = true; + Assert.AreEqual("null", GetMessage(res, CultureInfo.CurrentCulture), "Code"); + } - [Test] - public void GetMessageResolvableNoValidMessage() - { - IMessageSourceResolvable res = A.Fake(); - A.CallTo(() => res.DefaultMessage).Returns(null); - A.CallTo(() => res.GetCodes()).Returns(null); - A.CallTo(() => res.GetArguments()).Returns(null); + [Test] + public void GetMessageResolvableNoValidMessage() + { + IMessageSourceResolvable res = A.Fake(); + A.CallTo(() => res.DefaultMessage).Returns(null); + A.CallTo(() => res.GetCodes()).Returns(null); + A.CallTo(() => res.GetArguments()).Returns(null); - Assert.Throws(() => GetMessage(res, CultureInfo.CurrentCulture)); - } + Assert.Throws(() => GetMessage(res, CultureInfo.CurrentCulture)); + } - [Test] - public void GetMessageResolvableValidMessageAndCode() - { - IMessageSourceResolvable res = A.Fake(); - A.CallTo(() => res.GetCodes()).Returns(new string[] {"code1"}); - A.CallTo(() => res.GetArguments()).Returns(new object[] { "my", "arguments" }); + [Test] + public void GetMessageResolvableValidMessageAndCode() + { + IMessageSourceResolvable res = A.Fake(); + A.CallTo(() => res.GetCodes()).Returns(new string[] { "code1" }); + A.CallTo(() => res.GetArguments()).Returns(new object[] { "my", "arguments" }); - Assert.AreEqual("my arguments", GetMessage(res, CultureInfo.CurrentCulture), "Resolve"); - } + Assert.AreEqual("my arguments", GetMessage(res, CultureInfo.CurrentCulture), "Resolve"); + } - [Test] - public void GetMessageResolvableValidMessageAndCodeNullCulture() - { - IMessageSourceResolvable res = A.Fake(); - A.CallTo(() => res.GetCodes()).Returns(new string[] { "code1" }); - A.CallTo(() => res.GetArguments()).Returns(new object[] { "my", "arguments" }); + [Test] + public void GetMessageResolvableValidMessageAndCodeNullCulture() + { + IMessageSourceResolvable res = A.Fake(); + A.CallTo(() => res.GetCodes()).Returns(new string[] { "code1" }); + A.CallTo(() => res.GetArguments()).Returns(new object[] { "my", "arguments" }); - Assert.AreEqual("my arguments", GetMessage(res, null), "Resolve"); - } + Assert.AreEqual("my arguments", GetMessage(res, null), "Resolve"); + } - [Test] - public void GetMessageNullCode() - { - Assert.Throws(() => GetMessage(null)); - } + [Test] + public void GetMessageNullCode() + { + Assert.Throws(() => GetMessage(null)); + } - [Test] - public void GetMessageValidMessageAndCode() - { - Assert.AreEqual("my arguments", GetMessage("code1", new object[] {"my", "arguments"}), "Resolve"); - } + [Test] + public void GetMessageValidMessageAndCode() + { + Assert.AreEqual("my arguments", GetMessage("code1", new object[] { "my", "arguments" }), "Resolve"); + } - [Test] - public void GetMessageValidMessageAndCodeNullCulture() - { - Assert.AreEqual("my arguments", GetMessage("code1", null, new object[] {"my", "arguments"}), "Resolve"); - } + [Test] + public void GetMessageValidMessageAndCodeNullCulture() + { + Assert.AreEqual("my arguments", GetMessage("code1", null, new object[] { "my", "arguments" }), "Resolve"); + } - [Test] - public void GetMessageUseDefaultCode() - { - UseCodeAsDefaultMessage = true; - Assert.AreEqual("null", GetMessage("null", new object[] {"arguments"}), "message"); - Assert.IsTrue(UseCodeAsDefaultMessage, "default"); - } + [Test] + public void GetMessageUseDefaultCode() + { + UseCodeAsDefaultMessage = true; + Assert.AreEqual("null", GetMessage("null", new object[] { "arguments" }), "message"); + Assert.IsTrue(UseCodeAsDefaultMessage, "default"); + } - [Test] - public void GetMessageNoValidMessage() - { - Assert.Throws(() => GetMessage("null", new object[] {"arguments"})); - } + [Test] + public void GetMessageNoValidMessage() + { + Assert.Throws(() => GetMessage("null", new object[] { "arguments" })); + } - [Test] - public void GetMessageWithResolvableArguments() - { - IMessageSourceResolvable res = A.Fake(); - A.CallTo(() => res.GetCodes()).Returns(new string[] { "code1" }); - A.CallTo(() => res.GetArguments()).Returns(new object[] { "my", "resolvable" }); + [Test] + public void GetMessageWithResolvableArguments() + { + IMessageSourceResolvable res = A.Fake(); + A.CallTo(() => res.GetCodes()).Returns(new string[] { "code1" }); + A.CallTo(() => res.GetArguments()).Returns(new object[] { "my", "resolvable" }); - Assert.AreEqual("spring my resolvable", GetMessage("code2", CultureInfo.CurrentCulture, new object[] {"spring", res}), "Resolve"); - } + Assert.AreEqual("spring my resolvable", GetMessage("code2", CultureInfo.CurrentCulture, new object[] { "spring", res }), "Resolve"); + } - [Test] - public void GetMessageResolvableValidMessageAndCodNullMessageFormat() - { - IMessageSourceResolvable res = A.Fake(); - A.CallTo(() => res.DefaultMessage).Returns("myDefaultMessage"); - A.CallTo(() => res.GetCodes()).Returns(new string[] { "nullCode" }); - A.CallTo(() => res.GetArguments()).Returns(null); + [Test] + public void GetMessageResolvableValidMessageAndCodNullMessageFormat() + { + IMessageSourceResolvable res = A.Fake(); + A.CallTo(() => res.DefaultMessage).Returns("myDefaultMessage"); + A.CallTo(() => res.GetCodes()).Returns(new string[] { "nullCode" }); + A.CallTo(() => res.GetArguments()).Returns(null); - Assert.AreEqual("myDefaultMessage", GetMessage(res, null), "Resolve"); - } + Assert.AreEqual("myDefaultMessage", GetMessage(res, null), "Resolve"); + } - private void ResetMe() - { - ParentMessageSource = null; - UseCodeAsDefaultMessage = false; - } + private void ResetMe() + { + ParentMessageSource = null; + UseCodeAsDefaultMessage = false; + } - protected override string ResolveMessage(string code, CultureInfo cultureInfo) - { - if (code.Equals("null")) - { - return null; - } - else if (code.Equals("nullCode")) - { - return null; - } - else - { - return "{0} {1}"; - } - } + protected override string ResolveMessage(string code, CultureInfo cultureInfo) + { + if (code.Equals("null")) + { + return null; + } + else if (code.Equals("nullCode")) + { + return null; + } + else + { + return "{0} {1}"; + } + } - protected override object ResolveObject(string code, CultureInfo cultureInfo) - { - return null; - } + protected override object ResolveObject(string code, CultureInfo cultureInfo) + { + return null; + } - protected override void ApplyResourcesToObject(object value, string objectName, CultureInfo cultureInfo) - { - } - } -} \ No newline at end of file + protected override void ApplyResourcesToObject(object value, string objectName, CultureInfo cultureInfo) + { + } +} diff --git a/test/Spring/Spring.Core.Tests/Context/Support/ApplicationContextAwareProcessorTests.cs b/test/Spring/Spring.Core.Tests/Context/Support/ApplicationContextAwareProcessorTests.cs index 88254c1f..fff7abc0 100644 --- a/test/Spring/Spring.Core.Tests/Context/Support/ApplicationContextAwareProcessorTests.cs +++ b/test/Spring/Spring.Core.Tests/Context/Support/ApplicationContextAwareProcessorTests.cs @@ -21,130 +21,129 @@ using System.Security.Policy; using NUnit.Framework; -namespace Spring.Context.Support +namespace Spring.Context.Support; + +[TestFixture] +public sealed class ApplicationContextAwareProcessorTests { - [TestFixture] - public sealed class ApplicationContextAwareProcessorTests - { - [Test] - public void AttachResourceLoader() - { - MockApplicationContext ctx = new MockApplicationContext("MockApplicationContext"); - ApplicationContextAwareProcessor processor = new ApplicationContextAwareProcessor(ctx); - MockContextAwareObject obj = new MockContextAwareObject(); - Assert.IsNull(obj.ResourceLoader, "ResourceLoader Does Not Equal"); - MockContextAwareObject obj2 = (MockContextAwareObject) processor.PostProcessBeforeInitialization(obj, "MyContextAwareObject"); - Assert.AreEqual(ctx, obj2.ResourceLoader, "ResourceLoader Does Not Equal"); - } + [Test] + public void AttachResourceLoader() + { + MockApplicationContext ctx = new MockApplicationContext("MockApplicationContext"); + ApplicationContextAwareProcessor processor = new ApplicationContextAwareProcessor(ctx); + MockContextAwareObject obj = new MockContextAwareObject(); + Assert.IsNull(obj.ResourceLoader, "ResourceLoader Does Not Equal"); + MockContextAwareObject obj2 = (MockContextAwareObject) processor.PostProcessBeforeInitialization(obj, "MyContextAwareObject"); + Assert.AreEqual(ctx, obj2.ResourceLoader, "ResourceLoader Does Not Equal"); + } - [Test] - public void DoNotAttachResourceLoaderForRegularObject() - { - MockApplicationContext ctx = new MockApplicationContext(); - ApplicationContextAwareProcessor processor = new ApplicationContextAwareProcessor(ctx); - object obj = new object(); - object obj1 = processor.PostProcessBeforeInitialization(obj, "MyContextAwareObject"); - Assert.AreEqual(obj, obj1, "Objects don't equal"); - } + [Test] + public void DoNotAttachResourceLoaderForRegularObject() + { + MockApplicationContext ctx = new MockApplicationContext(); + ApplicationContextAwareProcessor processor = new ApplicationContextAwareProcessor(ctx); + object obj = new object(); + object obj1 = processor.PostProcessBeforeInitialization(obj, "MyContextAwareObject"); + Assert.AreEqual(obj, obj1, "Objects don't equal"); + } - [Test] - public void AttachContext() - { - MockApplicationContext ctx = new MockApplicationContext(); - ApplicationContextAwareProcessor processor = new ApplicationContextAwareProcessor(ctx); - MockContextAwareObject obj = new MockContextAwareObject(); - Assert.IsNull(obj.GetApplicationContext(), "Context Does Not Equal"); - MockContextAwareObject obj2 = (MockContextAwareObject) processor.PostProcessBeforeInitialization(obj, "MyContextAwareObject"); - Assert.AreEqual(ctx, obj2.GetApplicationContext(), "Context Does Not Equal"); - } + [Test] + public void AttachContext() + { + MockApplicationContext ctx = new MockApplicationContext(); + ApplicationContextAwareProcessor processor = new ApplicationContextAwareProcessor(ctx); + MockContextAwareObject obj = new MockContextAwareObject(); + Assert.IsNull(obj.GetApplicationContext(), "Context Does Not Equal"); + MockContextAwareObject obj2 = (MockContextAwareObject) processor.PostProcessBeforeInitialization(obj, "MyContextAwareObject"); + Assert.AreEqual(ctx, obj2.GetApplicationContext(), "Context Does Not Equal"); + } - [Test] - public void DoNotAttachContextForRegularObject() - { - MockApplicationContext ctx = new MockApplicationContext(); - ApplicationContextAwareProcessor processor = new ApplicationContextAwareProcessor(ctx); - object obj = new object(); - object obj1 = processor.PostProcessBeforeInitialization(obj, "MyContextAwareObject"); - Assert.AreEqual(obj, obj1, "Objects don't equal"); - } + [Test] + public void DoNotAttachContextForRegularObject() + { + MockApplicationContext ctx = new MockApplicationContext(); + ApplicationContextAwareProcessor processor = new ApplicationContextAwareProcessor(ctx); + object obj = new object(); + object obj1 = processor.PostProcessBeforeInitialization(obj, "MyContextAwareObject"); + Assert.AreEqual(obj, obj1, "Objects don't equal"); + } - [Test] - public void AfterInitReturnsSameInstanceAsWasPassedIn() - { - MockApplicationContext ctx = new MockApplicationContext(); - ApplicationContextAwareProcessor processor = new ApplicationContextAwareProcessor(ctx); - object obj = new object(); - object obj1 = processor.PostProcessAfterInitialization(obj, "MyContextAwareObject"); - Assert.AreEqual(obj, obj1, "Objects don't equal"); - } + [Test] + public void AfterInitReturnsSameInstanceAsWasPassedIn() + { + MockApplicationContext ctx = new MockApplicationContext(); + ApplicationContextAwareProcessor processor = new ApplicationContextAwareProcessor(ctx); + object obj = new object(); + object obj1 = processor.PostProcessAfterInitialization(obj, "MyContextAwareObject"); + Assert.AreEqual(obj, obj1, "Objects don't equal"); + } - [Test] - public void AlwaysIgnoresProxiedMessageSourceAwareObjects() - { - PostProcessTProxiedObject(new ProcessedObjectChecker( - _AlwaysIgnoresProxiedMessageSourceAwareObjects)); - } + [Test] + public void AlwaysIgnoresProxiedMessageSourceAwareObjects() + { + PostProcessTProxiedObject(new ProcessedObjectChecker( + _AlwaysIgnoresProxiedMessageSourceAwareObjects)); + } - private void _AlwaysIgnoresProxiedMessageSourceAwareObjects(MockContextAwareObject obj) - { - Assert.IsNull(obj.MessageSource, - "Transparent proxy IMessageSourceAware object was not ignored (must be)."); - } + private void _AlwaysIgnoresProxiedMessageSourceAwareObjects(MockContextAwareObject obj) + { + Assert.IsNull(obj.MessageSource, + "Transparent proxy IMessageSourceAware object was not ignored (must be)."); + } - [Test] - public void AlwaysIgnoresProxiedResourceLoaderAwareObjects() - { - PostProcessTProxiedObject(new ProcessedObjectChecker( - _AlwaysIgnoresProxiedResourceLoaderAwareObjects)); - } + [Test] + public void AlwaysIgnoresProxiedResourceLoaderAwareObjects() + { + PostProcessTProxiedObject(new ProcessedObjectChecker( + _AlwaysIgnoresProxiedResourceLoaderAwareObjects)); + } - private void _AlwaysIgnoresProxiedResourceLoaderAwareObjects(MockContextAwareObject obj) - { - Assert.IsNull(obj.ResourceLoader, - "Transparent proxy IResourceLoaderAware object was not ignored (must be)."); - } + private void _AlwaysIgnoresProxiedResourceLoaderAwareObjects(MockContextAwareObject obj) + { + Assert.IsNull(obj.ResourceLoader, + "Transparent proxy IResourceLoaderAware object was not ignored (must be)."); + } - [Test] - public void AlwaysIgnoresProxiedApplicationContextAwareAwareObjects() - { - PostProcessTProxiedObject(new ProcessedObjectChecker( - _AlwaysIgnoresProxiedApplicationContextAwareAwareObjects)); - } + [Test] + public void AlwaysIgnoresProxiedApplicationContextAwareAwareObjects() + { + PostProcessTProxiedObject(new ProcessedObjectChecker( + _AlwaysIgnoresProxiedApplicationContextAwareAwareObjects)); + } - private void _AlwaysIgnoresProxiedApplicationContextAwareAwareObjects(MockContextAwareObject obj) - { - Assert.IsNull(obj.ApplicationContext, - "Transparent proxy IApplicationContextAwareAware object was not ignored (must be)."); - } + private void _AlwaysIgnoresProxiedApplicationContextAwareAwareObjects(MockContextAwareObject obj) + { + Assert.IsNull(obj.ApplicationContext, + "Transparent proxy IApplicationContextAwareAware object was not ignored (must be)."); + } - private void PostProcessTProxiedObject(ProcessedObjectChecker test) - { - AppDomain domain = null; - try - { - AppDomainSetup setup = new AppDomainSetup(); - setup.ApplicationBase = Environment.CurrentDirectory; - domain = AppDomain.CreateDomain("Spring", new Evidence(AppDomain.CurrentDomain.Evidence), setup); - object foo = domain.CreateInstanceAndUnwrap(GetType().Assembly.FullName, typeof(MockContextAwareObject).FullName); - - MockApplicationContext ctx = new MockApplicationContext(); - ApplicationContextAwareProcessor processor = new ApplicationContextAwareProcessor(ctx); - MockContextAwareObject afterFoo = (MockContextAwareObject) processor.PostProcessBeforeInitialization(foo, "MyContextAwareObject"); - test(afterFoo); - } - finally - { - try - { - AppDomain.Unload(domain); - } - catch (Exception ex) - { - Console.Write("Error unloading AppDomain used during testing : " + ex); - } - } - } + private void PostProcessTProxiedObject(ProcessedObjectChecker test) + { + AppDomain domain = null; + try + { + AppDomainSetup setup = new AppDomainSetup(); + setup.ApplicationBase = Environment.CurrentDirectory; + domain = AppDomain.CreateDomain("Spring", new Evidence(AppDomain.CurrentDomain.Evidence), setup); + object foo = domain.CreateInstanceAndUnwrap(GetType().Assembly.FullName, typeof(MockContextAwareObject).FullName); - private delegate void ProcessedObjectChecker(MockContextAwareObject obj); - } + MockApplicationContext ctx = new MockApplicationContext(); + ApplicationContextAwareProcessor processor = new ApplicationContextAwareProcessor(ctx); + MockContextAwareObject afterFoo = (MockContextAwareObject) processor.PostProcessBeforeInitialization(foo, "MyContextAwareObject"); + test(afterFoo); + } + finally + { + try + { + AppDomain.Unload(domain); + } + catch (Exception ex) + { + Console.Write("Error unloading AppDomain used during testing : " + ex); + } + } + } + + private delegate void ProcessedObjectChecker(MockContextAwareObject obj); } \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/Context/Support/ApplicationContextExtensionTests.cs b/test/Spring/Spring.Core.Tests/Context/Support/ApplicationContextExtensionTests.cs index 60d66383..7f47e075 100644 --- a/test/Spring/Spring.Core.Tests/Context/Support/ApplicationContextExtensionTests.cs +++ b/test/Spring/Spring.Core.Tests/Context/Support/ApplicationContextExtensionTests.cs @@ -1,11 +1,10 @@ using NUnit.Framework; - using Spring.Objects; #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -22,45 +21,43 @@ using Spring.Objects; #endregion -namespace Spring.Context.Support +namespace Spring.Context.Support; + +/// +/// Test configuration of the application context with custom parsers, +/// resource handlers, and type aliases. +/// +[TestFixture] +public class ApplicationContextExtensionTests { /// - /// Test configuration of the application context with custom parsers, - /// resource handlers, and type aliases. + /// Create an instance of the test. /// - [TestFixture] - public class ApplicationContextExtensionTests + public ApplicationContextExtensionTests() { - /// - /// Create an instance of the test. - /// - public ApplicationContextExtensionTests() - {} - - /// - /// Test using a custom parser to create our familiar "TestObject" - /// - [Test] - public void UsingCustomParsers() - { - ContextRegistry.Clear(); - IApplicationContext ctx = ContextRegistry.GetContext(); - Assert.IsNotNull(ctx); - - IApplicationContext parentCtx = ContextRegistry.GetContext("Parent"); - Assert.IsNotNull(parentCtx, "Parent context not registered."); - - TestObject to = (TestObject) ctx.GetObject("Parent"); - Assert.IsNotNull(to); - Assert.IsTrue(TestObjectConfigParser.ParseElementCalled); - - TestObject to2 = (TestObject) ctx.GetObject("testObject"); - Assert.AreEqual(12, to2.Age); - Assert.AreEqual("John", to2.Name); - - Assert.AreEqual(2, ctx.ObjectDefinitionCount); - - } - } -} \ No newline at end of file + + /// + /// Test using a custom parser to create our familiar "TestObject" + /// + [Test] + public void UsingCustomParsers() + { + ContextRegistry.Clear(); + IApplicationContext ctx = ContextRegistry.GetContext(); + Assert.IsNotNull(ctx); + + IApplicationContext parentCtx = ContextRegistry.GetContext("Parent"); + Assert.IsNotNull(parentCtx, "Parent context not registered."); + + TestObject to = (TestObject) ctx.GetObject("Parent"); + Assert.IsNotNull(to); + Assert.IsTrue(TestObjectConfigParser.ParseElementCalled); + + TestObject to2 = (TestObject) ctx.GetObject("testObject"); + Assert.AreEqual(12, to2.Age); + Assert.AreEqual("John", to2.Name); + + Assert.AreEqual(2, ctx.ObjectDefinitionCount); + } +} diff --git a/test/Spring/Spring.Core.Tests/Context/Support/ApplicationObjectSupportTests.cs b/test/Spring/Spring.Core.Tests/Context/Support/ApplicationObjectSupportTests.cs index b606ebec..d1a98920 100644 --- a/test/Spring/Spring.Core.Tests/Context/Support/ApplicationObjectSupportTests.cs +++ b/test/Spring/Spring.Core.Tests/Context/Support/ApplicationObjectSupportTests.cs @@ -20,390 +20,385 @@ using Spring.Core.IO; using Spring.Objects.Factory; using Spring.Objects.Factory.Config; -namespace Spring.Context.Support +namespace Spring.Context.Support; + +[TestFixture] +public class ApplicationObjectSupportTests { - [TestFixture] - public class ApplicationObjectSupportTests - { - internal class MyApplicationObjectSupport : ApplicationObjectSupport - { - private bool _init = false; + internal class MyApplicationObjectSupport : ApplicationObjectSupport + { + private bool _init = false; - public MyApplicationObjectSupport() : base() - { - } + public MyApplicationObjectSupport() : base() + { + } - public MyApplicationObjectSupport(IApplicationContext applicationContext) : base(applicationContext) - { - } + public MyApplicationObjectSupport(IApplicationContext applicationContext) : base(applicationContext) + { + } - protected override Type RequiredType => typeof (MockApplicationContext); + protected override Type RequiredType => typeof(MockApplicationContext); - protected override void InitApplicationContext() - { - _init = true; - } + protected override void InitApplicationContext() + { + _init = true; + } - public bool Init => _init; - } + public bool Init => _init; + } - internal class MyContext2 : IApplicationContext - { - public void Dispose() - { - } + internal class MyContext2 : IApplicationContext + { + public void Dispose() + { + } - public IApplicationContext ParentContext => null; + public IApplicationContext ParentContext => null; - public DateTime StartupDate => new DateTime(); + public DateTime StartupDate => new DateTime(); #pragma warning disable 67 - public event ApplicationEventHandler ContextEvent; + public event ApplicationEventHandler ContextEvent; #pragma warning restore 67 - public long StartupDateMilliseconds => 0; + public long StartupDateMilliseconds => 0; - public string Name - { - get => AbstractApplicationContext.DefaultRootContextName; - set - { - } - } - - public IObjectDefinition GetObjectDefinition(string name) + public string Name + { + get => AbstractApplicationContext.DefaultRootContextName; + set { - return null; } - - public IObjectDefinition GetObjectDefinition(string name, bool includeAncestors) - { - return null; - } - - public IReadOnlyList GetObjectDefinitionNames(bool includeAncestors) - { - return null; - } - - public string[] GetObjectDefinitionNames(Type type) - { - return null; - } - - public IReadOnlyList GetObjectNamesForType(Type type) - { - return null; - } - - public IReadOnlyList GetObjectNames() - { - return null; - } - - public IReadOnlyList GetObjectNamesForType(Type type, bool includePrototypes, bool includeFactoryObjects) - { - return null; - } - - public IReadOnlyList GetObjectNames(bool includePrototypes, bool includeFactoryObjects) - { - return null; - } - - IReadOnlyList IListableObjectFactory.GetObjectDefinitionNames() - { - return null; - } - - public IReadOnlyDictionary GetObjectsOfType(Type type) - { - return null; - } - - public IReadOnlyDictionary GetObjects() - { - return null; - } - - public IReadOnlyDictionary GetObjectsOfType(Type type, bool includePrototypes, bool includeFactoryObjects) - { - return null; - } - - public IReadOnlyDictionary GetObjects(bool includePrototypes, bool includeFactoryObjects) - { - return null; - } - - public T GetObject() - { - throw new NotImplementedException(); - } - - public int ObjectDefinitionCount => 0; - - public bool ContainsObjectDefinition(string name) - { - return false; - } - - public bool IsCaseSensitive => true; - - public object this[string name] => null; - - public bool ContainsObject(string name) - { - return false; - } - - public IReadOnlyList GetAliases(string name) - { - return null; - } - - public bool IsTypeMatch(string name) - { - return false; - } - - public object CreateObject(string name, Type requiredType, object[] arguments) - { - return null; - } - - public T CreateObject(string name, object[] arguments) - { - return Activator.CreateInstance(); - } - - public object GetObject(string name, Type requiredType) - { - return null; - } - - object IObjectFactory.GetObject(string name) - { - return null; - } - - public T GetObject(string name) - { - return Activator.CreateInstance(); - } - - public object GetObject(string name, object[] arguments) - { - return null; - } - - public T GetObject(string name, object[] arguments) - { - return Activator.CreateInstance(); - } - - public object GetObject(string name, Type requiredType, object[] arguments) - { - return null; - } - - public bool IsSingleton(string name) - { - return false; - } - - - public bool IsPrototype(string name) - { - return false; - } - - public Type GetType(string name) - { - return null; - } - - - public bool IsTypeMatch(string name, Type targetType) - { - return false; - } - - public object ConfigureObject(object target) - { - return null; - } - - public object ConfigureObject(object target, string name) - { - return null; - } - - public object ConfigureObject(object target, string name, IObjectDefinition definition) - { - return null; - } - - public IObjectFactory ParentObjectFactory => null; - - public bool ContainsLocalObject(string name) - { - return false; - } - - public string GetMessage(IMessageSourceResolvable resolvable, CultureInfo culture) - { - return null; - } - - string IMessageSource.GetMessage(string name, CultureInfo culture, params object[] args) - { - return null; - } - - string IMessageSource.GetMessage(string name) - { - return null; - } - - string IMessageSource.GetMessage(string name, params object[] args) - { - return null; - } - - string IMessageSource.GetMessage(string name, CultureInfo cultureInfo) - { - return null; - } - - public string GetMessage(string name, string defaultMessage, CultureInfo culture, params object[] arguments) - { - return null; - } - - object IMessageSource.GetResourceObject(string name, CultureInfo culture) - { - return null; - } - - object IMessageSource.GetResourceObject(string name) - { - return null; - } - - void IMessageSource.ApplyResources(object value, string objectName, CultureInfo cultureInfo) - { - } - - public IResource GetResource(string location) - { - return null; - } - - public void PublishEvents(object sourceObject) - { - throw new NotImplementedException(); - } - - public void Subscribe(object subscriber) - { - throw new NotImplementedException(); - } - - public void Subscribe(object subscriber, Type targetSourceType) - { - throw new NotImplementedException(); - } - - - public void Unsubscribe(object subscriber) - { - throw new NotImplementedException(); - } - - public void Unsubscribe(object subscriber, Type targetSourceType) - { - throw new NotImplementedException(); - } - - public void PublishEvent(object sender, ApplicationEventArgs e) - { - throw new NotImplementedException(); - } - } - - internal class MyContext2Subclass : MyContext2 - { - } - - internal class MyApplicationObjectSupportConcrete : ApplicationObjectSupport - { - private bool _init; - - public MyApplicationObjectSupportConcrete() : base() - { - } - - public MyApplicationObjectSupportConcrete(IApplicationContext applicationContext) : base(applicationContext) - { - } - - protected override void InitApplicationContext() - { - base.InitApplicationContext(); - _init = true; - } - - public bool Init => _init; - } - - - [Test] - public void InvalidContextSubclass() - { - ApplicationObjectSupport support = new MyApplicationObjectSupport(); - Assert.Throws(() => support.ApplicationContext = new MyContext2()); - } - - [Test] - public void ValidContextSubClassOfAContext() - { - MyApplicationObjectSupportConcrete support = new MyApplicationObjectSupportConcrete(); - support.ApplicationContext = new MyContext2(); - } - - [Test] - public void ValidContextIApplicationContext() - { - MyApplicationObjectSupportConcrete support = new MyApplicationObjectSupportConcrete(); - support.ApplicationContext = new MyContext2(); - Assert.IsTrue(support.Init); - Assert.IsNotNull(support.MessageSourceAccessor); - } - - [Test] - public void ValidContextSubClass() - { - MyApplicationObjectSupport support = new MyApplicationObjectSupport(); - support.ApplicationContext = new MockApplicationContext(); - Assert.IsTrue(support.Init); - } - - [Test] - public void ReinitWithSameContext() - { - MockApplicationContext ctx = new MockApplicationContext(); - ApplicationObjectSupport support = new MyApplicationObjectSupport(ctx); - support.ApplicationContext = ctx; - Assert.AreEqual(ctx, support.ApplicationContext); - } - - [Test] - public void ReinitWithDiffContext() - { - MockApplicationContext ctx = new MockApplicationContext(); - ApplicationObjectSupport support = new MyApplicationObjectSupport(ctx); - Assert.Throws(() => support.ApplicationContext = new MockApplicationContext()); - } - } -} \ No newline at end of file + } + + public IObjectDefinition GetObjectDefinition(string name) + { + return null; + } + + public IObjectDefinition GetObjectDefinition(string name, bool includeAncestors) + { + return null; + } + + public IReadOnlyList GetObjectDefinitionNames(bool includeAncestors) + { + return null; + } + + public string[] GetObjectDefinitionNames(Type type) + { + return null; + } + + public IReadOnlyList GetObjectNamesForType(Type type) + { + return null; + } + + public IReadOnlyList GetObjectNames() + { + return null; + } + + public IReadOnlyList GetObjectNamesForType(Type type, bool includePrototypes, bool includeFactoryObjects) + { + return null; + } + + public IReadOnlyList GetObjectNames(bool includePrototypes, bool includeFactoryObjects) + { + return null; + } + + IReadOnlyList IListableObjectFactory.GetObjectDefinitionNames() + { + return null; + } + + public IReadOnlyDictionary GetObjectsOfType(Type type) + { + return null; + } + + public IReadOnlyDictionary GetObjects() + { + return null; + } + + public IReadOnlyDictionary GetObjectsOfType(Type type, bool includePrototypes, bool includeFactoryObjects) + { + return null; + } + + public IReadOnlyDictionary GetObjects(bool includePrototypes, bool includeFactoryObjects) + { + return null; + } + + public T GetObject() + { + throw new NotImplementedException(); + } + + public int ObjectDefinitionCount => 0; + + public bool ContainsObjectDefinition(string name) + { + return false; + } + + public bool IsCaseSensitive => true; + + public object this[string name] => null; + + public bool ContainsObject(string name) + { + return false; + } + + public IReadOnlyList GetAliases(string name) + { + return null; + } + + public bool IsTypeMatch(string name) + { + return false; + } + + public object CreateObject(string name, Type requiredType, object[] arguments) + { + return null; + } + + public T CreateObject(string name, object[] arguments) + { + return Activator.CreateInstance(); + } + + public object GetObject(string name, Type requiredType) + { + return null; + } + + object IObjectFactory.GetObject(string name) + { + return null; + } + + public T GetObject(string name) + { + return Activator.CreateInstance(); + } + + public object GetObject(string name, object[] arguments) + { + return null; + } + + public T GetObject(string name, object[] arguments) + { + return Activator.CreateInstance(); + } + + public object GetObject(string name, Type requiredType, object[] arguments) + { + return null; + } + + public bool IsSingleton(string name) + { + return false; + } + + public bool IsPrototype(string name) + { + return false; + } + + public Type GetType(string name) + { + return null; + } + + public bool IsTypeMatch(string name, Type targetType) + { + return false; + } + + public object ConfigureObject(object target) + { + return null; + } + + public object ConfigureObject(object target, string name) + { + return null; + } + + public object ConfigureObject(object target, string name, IObjectDefinition definition) + { + return null; + } + + public IObjectFactory ParentObjectFactory => null; + + public bool ContainsLocalObject(string name) + { + return false; + } + + public string GetMessage(IMessageSourceResolvable resolvable, CultureInfo culture) + { + return null; + } + + string IMessageSource.GetMessage(string name, CultureInfo culture, params object[] args) + { + return null; + } + + string IMessageSource.GetMessage(string name) + { + return null; + } + + string IMessageSource.GetMessage(string name, params object[] args) + { + return null; + } + + string IMessageSource.GetMessage(string name, CultureInfo cultureInfo) + { + return null; + } + + public string GetMessage(string name, string defaultMessage, CultureInfo culture, params object[] arguments) + { + return null; + } + + object IMessageSource.GetResourceObject(string name, CultureInfo culture) + { + return null; + } + + object IMessageSource.GetResourceObject(string name) + { + return null; + } + + void IMessageSource.ApplyResources(object value, string objectName, CultureInfo cultureInfo) + { + } + + public IResource GetResource(string location) + { + return null; + } + + public void PublishEvents(object sourceObject) + { + throw new NotImplementedException(); + } + + public void Subscribe(object subscriber) + { + throw new NotImplementedException(); + } + + public void Subscribe(object subscriber, Type targetSourceType) + { + throw new NotImplementedException(); + } + + public void Unsubscribe(object subscriber) + { + throw new NotImplementedException(); + } + + public void Unsubscribe(object subscriber, Type targetSourceType) + { + throw new NotImplementedException(); + } + + public void PublishEvent(object sender, ApplicationEventArgs e) + { + throw new NotImplementedException(); + } + } + + internal class MyContext2Subclass : MyContext2 + { + } + + internal class MyApplicationObjectSupportConcrete : ApplicationObjectSupport + { + private bool _init; + + public MyApplicationObjectSupportConcrete() : base() + { + } + + public MyApplicationObjectSupportConcrete(IApplicationContext applicationContext) : base(applicationContext) + { + } + + protected override void InitApplicationContext() + { + base.InitApplicationContext(); + _init = true; + } + + public bool Init => _init; + } + + [Test] + public void InvalidContextSubclass() + { + ApplicationObjectSupport support = new MyApplicationObjectSupport(); + Assert.Throws(() => support.ApplicationContext = new MyContext2()); + } + + [Test] + public void ValidContextSubClassOfAContext() + { + MyApplicationObjectSupportConcrete support = new MyApplicationObjectSupportConcrete(); + support.ApplicationContext = new MyContext2(); + } + + [Test] + public void ValidContextIApplicationContext() + { + MyApplicationObjectSupportConcrete support = new MyApplicationObjectSupportConcrete(); + support.ApplicationContext = new MyContext2(); + Assert.IsTrue(support.Init); + Assert.IsNotNull(support.MessageSourceAccessor); + } + + [Test] + public void ValidContextSubClass() + { + MyApplicationObjectSupport support = new MyApplicationObjectSupport(); + support.ApplicationContext = new MockApplicationContext(); + Assert.IsTrue(support.Init); + } + + [Test] + public void ReinitWithSameContext() + { + MockApplicationContext ctx = new MockApplicationContext(); + ApplicationObjectSupport support = new MyApplicationObjectSupport(ctx); + support.ApplicationContext = ctx; + Assert.AreEqual(ctx, support.ApplicationContext); + } + + [Test] + public void ReinitWithDiffContext() + { + MockApplicationContext ctx = new MockApplicationContext(); + ApplicationObjectSupport support = new MyApplicationObjectSupport(ctx); + Assert.Throws(() => support.ApplicationContext = new MockApplicationContext()); + } +} diff --git a/test/Spring/Spring.Core.Tests/Context/Support/Assembler.cs b/test/Spring/Spring.Core.Tests/Context/Support/Assembler.cs index d3ef8ff2..b733211e 100644 --- a/test/Spring/Spring.Core.Tests/Context/Support/Assembler.cs +++ b/test/Spring/Spring.Core.Tests/Context/Support/Assembler.cs @@ -18,39 +18,35 @@ #endregion -namespace Spring.Context.Support +namespace Spring.Context.Support; + +#region Test Utility Classes + +#endregion + +/// Mark Pollack +public class Assembler { - #region Test Utility Classes + private Service service; + private Logic logic; + private string name; - #endregion - - - /// Mark Pollack - public class Assembler + public Logic Logic { - private Service service; - private Logic logic; - private string name; + set { logic = value; } + } - public Logic Logic - { - set { logic = value; } - } + public Service Service + { + set { service = value; } + } - public Service Service - { - set { service = value; } - } + public string ObjectName + { + set { name = value; } + } - - public string ObjectName - { - set { name = value; } - } - - public void Test() - { - - } + public void Test() + { } } \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/Context/Support/CodeConfigApplicationContextTests.cs b/test/Spring/Spring.Core.Tests/Context/Support/CodeConfigApplicationContextTests.cs index 0dcbcd9c..45a33ed6 100644 --- a/test/Spring/Spring.Core.Tests/Context/Support/CodeConfigApplicationContextTests.cs +++ b/test/Spring/Spring.Core.Tests/Context/Support/CodeConfigApplicationContextTests.cs @@ -21,113 +21,108 @@ using NUnit.Framework; using Spring.Context.Attributes; -namespace Spring.Context.Support +namespace Spring.Context.Support; + +[TestFixture] +public class CodeConfigApplicationContextTests { - [TestFixture] - public class CodeConfigApplicationContextTests + private CodeConfigApplicationContext context; + private AssemblyObjectDefinitionScanner scanner; + + [SetUp] + public void _TestSetup() { - private CodeConfigApplicationContext context; - private AssemblyObjectDefinitionScanner scanner; - - [SetUp] - public void _TestSetup() - { - context = new CodeConfigApplicationContext(); - scanner = new AssemblyObjectDefinitionScanner(); - } - - [Test] - public void Can_Filter_For_Assembly_Based_On_Assembly_Metadata() - { - context.ScanWithAssemblyFilter(a => a.GetName().Name.StartsWith("Spring.Core.")); - context.Refresh(); - - AssertExpectedObjectsAreRegisteredWith(context, 45); - } - - [Test] - public void Can_Filter_For_Assembly_Containing_Specific_Type_But_Having_NO_Definitions() - { - //specifically filter assemblies for one that we *know* will result in NO [Configuration] types in it - context.ScanWithAssemblyFilter(assy => assy.GetTypes().Any(type => type.FullName.Contains(typeof(Spring.Core.IOrdered).Name))); - context.Refresh(); - - Assert.That(context.DefaultListableObjectFactory.ObjectDefinitionCount, Is.EqualTo(4)); - } - - [Test] - public void Can_Filter_For_Assembly_Containing_Specific_Type() - { - context.ScanWithAssemblyFilter(assy => assy.GetTypes().Any(type => type.FullName.Contains(typeof(MarkerTypeForScannerToFind).Name))); - context.Refresh(); - - AssertExpectedObjectsAreRegisteredWith(context, 45); - } - - [Test] - public void Can_Filter_For_Specific_Type() - { - context.ScanWithTypeFilter(type => type.FullName.Contains(typeof(TheImportedConfigurationClass).Name)); - context.Refresh(); - - Assert.That(context.DefaultListableObjectFactory.ObjectDefinitionCount, Is.EqualTo(8)); - } - - [Test] - public void Can_Filter_For_Specific_Types_With_Compound_Predicate() - { - context.ScanWithTypeFilter(type => type.FullName.Contains(typeof(TheImportedConfigurationClass).Name) || type.FullName.Contains(typeof(TheConfigurationClass).Name)); - context.Refresh(); - - AssertExpectedObjectsAreRegisteredWith(context, 19); - } - - [Test] - public void Can_Filter_For_Specific_Types_With_Multiple_Include_Filters() - { - scanner.WithIncludeFilter(type => type.FullName.Contains(typeof(TheImportedConfigurationClass).Name)); - scanner.WithIncludeFilter(type => type.FullName.Contains(typeof(TheConfigurationClass).Name)); - - context.Scan(scanner); - context.Refresh(); - - AssertExpectedObjectsAreRegisteredWith(context, 19); - } - - [Test] - public void Can_Perform_Scan_With_No_Filtering() - { - context.ScanAllAssemblies(); - context.Refresh(); - - AssertExpectedObjectsAreRegisteredWith(context, 45); - } - - private void AssertExpectedObjectsAreRegisteredWith(GenericApplicationContext context, int expectedDefinitionCount) - { - // only check names that are not part of configuration namespace test - List names = new List(context.DefaultListableObjectFactory.GetObjectDefinitionNames()); - names.RemoveAll(x => x.StartsWith("ConfigurationNameSpace")); - - - if (names.Count != expectedDefinitionCount) - { - Console.WriteLine("Actual types registered with the container:"); - foreach (var name in names) - { - Console.WriteLine(name); - } - } - - - Assert.That(names.Count, Is.EqualTo(expectedDefinitionCount)); - } - + context = new CodeConfigApplicationContext(); + scanner = new AssemblyObjectDefinitionScanner(); } - //DO NOT DELETE: this empty class req'd by the scanning tests! - public class MarkerTypeForScannerToFind + [Test] + public void Can_Filter_For_Assembly_Based_On_Assembly_Metadata() { + context.ScanWithAssemblyFilter(a => a.GetName().Name.StartsWith("Spring.Core.")); + context.Refresh(); + AssertExpectedObjectsAreRegisteredWith(context, 45); + } + + [Test] + public void Can_Filter_For_Assembly_Containing_Specific_Type_But_Having_NO_Definitions() + { + //specifically filter assemblies for one that we *know* will result in NO [Configuration] types in it + context.ScanWithAssemblyFilter(assy => assy.GetTypes().Any(type => type.FullName.Contains(typeof(Spring.Core.IOrdered).Name))); + context.Refresh(); + + Assert.That(context.DefaultListableObjectFactory.ObjectDefinitionCount, Is.EqualTo(4)); + } + + [Test] + public void Can_Filter_For_Assembly_Containing_Specific_Type() + { + context.ScanWithAssemblyFilter(assy => assy.GetTypes().Any(type => type.FullName.Contains(typeof(MarkerTypeForScannerToFind).Name))); + context.Refresh(); + + AssertExpectedObjectsAreRegisteredWith(context, 45); + } + + [Test] + public void Can_Filter_For_Specific_Type() + { + context.ScanWithTypeFilter(type => type.FullName.Contains(typeof(TheImportedConfigurationClass).Name)); + context.Refresh(); + + Assert.That(context.DefaultListableObjectFactory.ObjectDefinitionCount, Is.EqualTo(8)); + } + + [Test] + public void Can_Filter_For_Specific_Types_With_Compound_Predicate() + { + context.ScanWithTypeFilter(type => type.FullName.Contains(typeof(TheImportedConfigurationClass).Name) || type.FullName.Contains(typeof(TheConfigurationClass).Name)); + context.Refresh(); + + AssertExpectedObjectsAreRegisteredWith(context, 19); + } + + [Test] + public void Can_Filter_For_Specific_Types_With_Multiple_Include_Filters() + { + scanner.WithIncludeFilter(type => type.FullName.Contains(typeof(TheImportedConfigurationClass).Name)); + scanner.WithIncludeFilter(type => type.FullName.Contains(typeof(TheConfigurationClass).Name)); + + context.Scan(scanner); + context.Refresh(); + + AssertExpectedObjectsAreRegisteredWith(context, 19); + } + + [Test] + public void Can_Perform_Scan_With_No_Filtering() + { + context.ScanAllAssemblies(); + context.Refresh(); + + AssertExpectedObjectsAreRegisteredWith(context, 45); + } + + private void AssertExpectedObjectsAreRegisteredWith(GenericApplicationContext context, int expectedDefinitionCount) + { + // only check names that are not part of configuration namespace test + List names = new List(context.DefaultListableObjectFactory.GetObjectDefinitionNames()); + names.RemoveAll(x => x.StartsWith("ConfigurationNameSpace")); + + if (names.Count != expectedDefinitionCount) + { + Console.WriteLine("Actual types registered with the container:"); + foreach (var name in names) + { + Console.WriteLine(name); + } + } + + Assert.That(names.Count, Is.EqualTo(expectedDefinitionCount)); } } + +//DO NOT DELETE: this empty class req'd by the scanning tests! +public class MarkerTypeForScannerToFind +{ +} diff --git a/test/Spring/Spring.Core.Tests/Context/Support/ContextLocatorHandlerTests.cs b/test/Spring/Spring.Core.Tests/Context/Support/ContextLocatorHandlerTests.cs index fe654c59..2501db53 100644 --- a/test/Spring/Spring.Core.Tests/Context/Support/ContextLocatorHandlerTests.cs +++ b/test/Spring/Spring.Core.Tests/Context/Support/ContextLocatorHandlerTests.cs @@ -23,182 +23,180 @@ using System.Configuration; using System.Xml; using NUnit.Framework; - using Spring.Objects.Factory; using Spring.Util; using ConfigurationException = System.Configuration.ConfigurationException; #endregion -namespace Spring.Context.Support +namespace Spring.Context.Support; + +/// +/// Unit tests for the ContextHandler class. +/// +/// Mark Pollack +/// Rick Evans +[TestFixture] +public sealed class ContextHandlerTests { - /// - /// Unit tests for the ContextHandler class. - /// - /// Mark Pollack - /// Rick Evans - [TestFixture] - public sealed class ContextHandlerTests - { - private XmlElement configurationElement; + private XmlElement configurationElement; - [SetUp] - public void SetUp() - { - ContextRegistry.Clear(); - } + [SetUp] + public void SetUp() + { + ContextRegistry.Clear(); + } - [TearDown] - public void TearDown() - { - ContextRegistry.Clear(); - } + [TearDown] + public void TearDown() + { + ContextRegistry.Clear(); + } - [Test] - public void CreateContextSuccessful() - { - const string xmlData = - @" + [Test] + public void CreateContextSuccessful() + { + const string xmlData = + @" "; - CreateConfigurationElement(xmlData); + CreateConfigurationElement(xmlData); - ContextHandler ctxHandler = new ContextHandler(); - IApplicationContext ctx = (IApplicationContext) ctxHandler.Create(null, null, configurationElement); - Assert.AreEqual(ctx, ContextRegistry.GetContext()); - Assert.AreEqual(1, ContextRegistry.GetContext().ObjectDefinitionCount); - } + ContextHandler ctxHandler = new ContextHandler(); + IApplicationContext ctx = (IApplicationContext) ctxHandler.Create(null, null, configurationElement); + Assert.AreEqual(ctx, ContextRegistry.GetContext()); + Assert.AreEqual(1, ContextRegistry.GetContext().ObjectDefinitionCount); + } - [Test] - public void CreateRootContextFailure() - { - const string xmlData = - @" + [Test] + public void CreateRootContextFailure() + { + const string xmlData = + @" "; - CreateConfigurationElement(xmlData); + CreateConfigurationElement(xmlData); - ContextHandler ctxHandler = new ContextHandler(); - try - { - IApplicationContext ctx = (IApplicationContext) ctxHandler.Create(null, null, configurationElement); - Assert.Fail(""); - } - catch(ConfigurationException cfgex) - { - Assert.IsInstanceOf(typeof(ObjectDefinitionStoreException), cfgex.InnerException); - } - } - - [Test] - public void CreateChildContextFailure() + ContextHandler ctxHandler = new ContextHandler(); + try { - const string xmlData = - @" + IApplicationContext ctx = (IApplicationContext) ctxHandler.Create(null, null, configurationElement); + Assert.Fail(""); + } + catch (ConfigurationException cfgex) + { + Assert.IsInstanceOf(typeof(ObjectDefinitionStoreException), cfgex.InnerException); + } + } + + [Test] + public void CreateChildContextFailure() + { + const string xmlData = + @" "; - CreateConfigurationElement(xmlData); + CreateConfigurationElement(xmlData); - ContextHandler ctxHandler = new ContextHandler(); - try - { - IApplicationContext ctx = (IApplicationContext) ctxHandler.Create(new StaticApplicationContext(), null, configurationElement); - Assert.Fail(""); - } - catch(ConfigurationException cfgex) - { - Assert.IsInstanceOf(typeof(ObjectDefinitionStoreException), cfgex.InnerException); - } + ContextHandler ctxHandler = new ContextHandler(); + try + { + IApplicationContext ctx = (IApplicationContext) ctxHandler.Create(new StaticApplicationContext(), null, configurationElement); + Assert.Fail(""); } + catch (ConfigurationException cfgex) + { + Assert.IsInstanceOf(typeof(ObjectDefinitionStoreException), cfgex.InnerException); + } + } - /// - /// Expect failure when using a type that does not inherit from IApplicationContext - /// - [Test] - public void ContextNotOfCorrectType() - { - const string xmlData = - @" + /// + /// Expect failure when using a type that does not inherit from IApplicationContext + /// + [Test] + public void ContextNotOfCorrectType() + { + const string xmlData = + @" "; - CreateConfigurationElement(xmlData); - ContextHandler ctxHandler = new ContextHandler(); - Assert.Throws(() => ctxHandler.Create(null, null, configurationElement)); - } + CreateConfigurationElement(xmlData); + ContextHandler ctxHandler = new ContextHandler(); + Assert.Throws(() => ctxHandler.Create(null, null, configurationElement)); + } - [Test] - public void CreatedFromNullXmlElement() - { - ContextHandler ctxHandler = new ContextHandler(); - Assert.Throws(() => ctxHandler.Create(null, null, null)); - } + [Test] + public void CreatedFromNullXmlElement() + { + ContextHandler ctxHandler = new ContextHandler(); + Assert.Throws(() => ctxHandler.Create(null, null, null)); + } - [Test] - public void DefaultsToXmlApplicationContextType() - { - const string xmlData = - @" + [Test] + public void DefaultsToXmlApplicationContextType() + { + const string xmlData = + @" "; - CreateConfigurationElement(xmlData); - ContextHandler ctxHandler = new ContextHandler(); - IApplicationContext ctx = (IApplicationContext) ctxHandler.Create(null, null, configurationElement); - Assert.AreEqual(typeof (XmlApplicationContext), ctx.GetType(), - "Default type is not the XmlApplicationContext type; it must be."); - } + CreateConfigurationElement(xmlData); + ContextHandler ctxHandler = new ContextHandler(); + IApplicationContext ctx = (IApplicationContext) ctxHandler.Create(null, null, configurationElement); + Assert.AreEqual(typeof(XmlApplicationContext), ctx.GetType(), + "Default type is not the XmlApplicationContext type; it must be."); + } - [Test(Description="SPRNET-105")] - public void ChokesIfChildContextsUseTheSameName() - { - const string xmlData = - @" + [Test(Description = "SPRNET-105")] + public void ChokesIfChildContextsUseTheSameName() + { + const string xmlData = + @" "; - CreateConfigurationElement(xmlData); - ContextHandler ctxHandler = new ContextHandler(); - Assert.Throws(() => ctxHandler.Create(null, null, configurationElement)); - } + CreateConfigurationElement(xmlData); + ContextHandler ctxHandler = new ContextHandler(); + Assert.Throws(() => ctxHandler.Create(null, null, configurationElement)); + } - private void CreateConfigurationElement(string xmlData) - { - XmlDocument xmlDoc = new XmlDocument(); - xmlDoc.Load(new StringReader(xmlData)); - configurationElement = xmlDoc.DocumentElement; - } + private void CreateConfigurationElement(string xmlData) + { + XmlDocument xmlDoc = new XmlDocument(); + xmlDoc.Load(new StringReader(xmlData)); + configurationElement = xmlDoc.DocumentElement; + } - // integration test; touches just about every class in the Spring.NET core... - [Test] - public void LoadParentChildContextsHierarchy() - { - //need a second section for another independent test as CongfigurationSettings.GetConfig will - //not be called twice by .NET - IApplicationContext ctx - = (IApplicationContext) ConfigurationUtils.GetSection("spring2/context"); + // integration test; touches just about every class in the Spring.NET core... + [Test] + public void LoadParentChildContextsHierarchy() + { + //need a second section for another independent test as CongfigurationSettings.GetConfig will + //not be called twice by .NET + IApplicationContext ctx + = (IApplicationContext) ConfigurationUtils.GetSection("spring2/context"); - Assert.IsNotNull(ctx); - IApplicationContext parentCtx = ContextRegistry.GetContext("Parent"); - Assert.IsNotNull(parentCtx, "Parent context not registered."); - Assert.AreEqual("Parent", parentCtx.Name, "Parent's DisplayName property not picked up from config file."); - IApplicationContext childCtx = ContextRegistry.GetContext("Child"); - Assert.IsNotNull(childCtx, "Child context not registered."); - Assert.AreEqual("Child", childCtx.Name, "Child's DisplayName property not picked up from config file."); - Assert.AreEqual("Parent", childCtx.ParentContext.Name); - IApplicationContext grandchildCtx = ContextRegistry.GetContext("Grandchild"); - Assert.IsNotNull(grandchildCtx, "Grandchild context not registered."); - Assert.AreEqual("Grandchild", grandchildCtx.Name, "Grandchild's DisplayName property not picked up from config file."); - Assert.AreEqual("Child", grandchildCtx.ParentContext.Name); + Assert.IsNotNull(ctx); + IApplicationContext parentCtx = ContextRegistry.GetContext("Parent"); + Assert.IsNotNull(parentCtx, "Parent context not registered."); + Assert.AreEqual("Parent", parentCtx.Name, "Parent's DisplayName property not picked up from config file."); + IApplicationContext childCtx = ContextRegistry.GetContext("Child"); + Assert.IsNotNull(childCtx, "Child context not registered."); + Assert.AreEqual("Child", childCtx.Name, "Child's DisplayName property not picked up from config file."); + Assert.AreEqual("Parent", childCtx.ParentContext.Name); + IApplicationContext grandchildCtx = ContextRegistry.GetContext("Grandchild"); + Assert.IsNotNull(grandchildCtx, "Grandchild context not registered."); + Assert.AreEqual("Grandchild", grandchildCtx.Name, "Grandchild's DisplayName property not picked up from config file."); + Assert.AreEqual("Child", grandchildCtx.ParentContext.Name); - // ensure proper objects have been loaded into the correct context... - Assert.IsTrue(parentCtx.ContainsObjectDefinition("Parent"), "Parent context object not present (must be)."); - Assert.IsFalse(parentCtx.ContainsObjectDefinition("Child"), "Wrong (child context) object present in Parent context."); + // ensure proper objects have been loaded into the correct context... + Assert.IsTrue(parentCtx.ContainsObjectDefinition("Parent"), "Parent context object not present (must be)."); + Assert.IsFalse(parentCtx.ContainsObjectDefinition("Child"), "Wrong (child context) object present in Parent context."); - Assert.IsTrue(childCtx.ContainsObjectDefinition("Child"), "Child context object not present (must be)."); - Assert.IsFalse(childCtx.ContainsObjectDefinition("Parent"), "Wrong (parent context) object present in Child context."); + Assert.IsTrue(childCtx.ContainsObjectDefinition("Child"), "Child context object not present (must be)."); + Assert.IsFalse(childCtx.ContainsObjectDefinition("Parent"), "Wrong (parent context) object present in Child context."); - Assert.IsTrue(grandchildCtx.ContainsObjectDefinition("Grandchild"), "Grandchild context object not present (must be)."); - Assert.IsFalse(grandchildCtx.ContainsObjectDefinition("Child"), "Wrong (parent context) object present in Grandchild context."); - Assert.IsFalse(grandchildCtx.ContainsObjectDefinition("Parent"), "Wrong (parent context) object present in Grandchild context."); - } - } + Assert.IsTrue(grandchildCtx.ContainsObjectDefinition("Grandchild"), "Grandchild context object not present (must be)."); + Assert.IsFalse(grandchildCtx.ContainsObjectDefinition("Child"), "Wrong (parent context) object present in Grandchild context."); + Assert.IsFalse(grandchildCtx.ContainsObjectDefinition("Parent"), "Wrong (parent context) object present in Grandchild context."); + } } diff --git a/test/Spring/Spring.Core.Tests/Context/Support/ContextRegistryTests.cs b/test/Spring/Spring.Core.Tests/Context/Support/ContextRegistryTests.cs index 31c1e5e0..a4bf4cf3 100644 --- a/test/Spring/Spring.Core.Tests/Context/Support/ContextRegistryTests.cs +++ b/test/Spring/Spring.Core.Tests/Context/Support/ContextRegistryTests.cs @@ -23,9 +23,7 @@ using System.Configuration; using System.Reflection; using System.Xml; - using NUnit.Framework; - using Spring.Objects; using Spring.Proxy; using Spring.Objects.Factory.Support; @@ -34,299 +32,293 @@ using ConfigurationException = System.Configuration.ConfigurationException; #endregion -namespace Spring.Context.Support +namespace Spring.Context.Support; + +/// +/// Unit tests for the ContextRegistry class. +/// +/// Rick Evans +[TestFixture] +public sealed class ContextRegistryTests { - /// - /// Unit tests for the ContextRegistry class. - /// - /// Rick Evans - [TestFixture] - public sealed class ContextRegistryTests + [SetUp] + public void SetUp() { + ContextRegistry.Clear(); + ResetConfigurationSystem(); + } + + private static void ResetConfigurationSystem() + { + if (SystemUtils.MonoRuntime) + { + return; + } + + FieldInfo initStateRef = typeof(ConfigurationManager).GetField("s_initState", BindingFlags.NonPublic | BindingFlags.Static); + object notStarted = Activator.CreateInstance(initStateRef.FieldType); + initStateRef.SetValue(null, notStarted); + } + + /// + /// This handler simulates an undefined configuration section + /// + private static object GetNullSection(object parent, object context, XmlNode section) + { + return null; + } + + /// + /// This handler simulates calls to ContextRegistry during context creation + /// + private static object GetContextRecursive(object parent, object context, XmlNode section) + { + return ContextRegistry.GetContext(); // this must fail! + } + + [Test] + public void ThrowsInvalidOperationExceptionOnRecursiveCallsToGetContext() + { + using (new HookableContextHandler.Guard(GetContextRecursive)) + { + try + { + ContextRegistry.GetContext("somename"); + Assert.Fail("Should throw an exception"); + } + catch (ConfigurationException ex) + { + InvalidOperationException rootCause = ex.GetBaseException() as InvalidOperationException; + Assert.IsNotNull(rootCause); + Assert.AreEqual("root context is currently in creation.", rootCause.Message.Substring(0, 38)); + } + } + } + + [Test] + public void RegisterRootContext() + { + MockApplicationContext ctx = new MockApplicationContext(); + ContextRegistry.RegisterContext(ctx); + IApplicationContext context = ContextRegistry.GetContext(); + Assert.IsNotNull(context, + "Root context is null even though a context has been registered."); + Assert.IsTrue(Object.ReferenceEquals(ctx, context), + "Root context was not the same as the first context registered (it must be)."); + } + + [Test] + public void RegisterNamedRootContext() + { + const string ctxName = "bingo"; + MockApplicationContext ctx = new MockApplicationContext(ctxName); + ContextRegistry.RegisterContext(ctx); + IApplicationContext rootContext = ContextRegistry.GetContext(); + Assert.IsNotNull(rootContext, + "Root context is null even though a context has been registered."); + Assert.AreEqual(ctxName, rootContext.Name, + "Root context name is different even though the root context has been registered under the lookup name."); + } + + [Test] + public void RegisterNamedContext() + { + const string ctxName = "bingo"; + MockApplicationContext ctx = new MockApplicationContext(ctxName); + ContextRegistry.RegisterContext(ctx); + IApplicationContext context = ContextRegistry.GetContext(ctxName); + Assert.IsNotNull(context, + "Named context is null even though a context has been registered under the lookup name."); + Assert.IsTrue(Object.ReferenceEquals(ctx, context), + "Named context was not the same as the registered context (it must be)."); + } + + [Test] + public void GetContextWithNullName() + { + Assert.Throws(() => ContextRegistry.GetContext(null)); + } + + [Test] + public void GetContextWithEmptyName() + { + Assert.Throws(() => ContextRegistry.GetContext("")); + } + + [Test] + public void GetRootContextNotRegisteredThrowsException() + { + Assert.Throws(() => + { + using (new HookableContextHandler.Guard(GetNullSection)) + { + ContextRegistry.GetContext(); + } + }, "No context registered. Use the 'RegisterContext' method or the 'spring/context' section from your configuration file."); + } + + [Test] + public void GetContextByNameNotRegisteredThrowsException() + { + Assert.Throws( + () => ContextRegistry.GetContext("bingo"), + "No context registered under name 'bingo'. Use the 'RegisterContext' method or the 'spring/context' section from your configuration file."); + } + + [Test] + public void CanBuildProxyForClassWithProtectedConstructor() + { + CompositionProxyTypeBuilder typeBuilder = new CompositionProxyTypeBuilder(); + typeBuilder.TargetType = typeof(ClassWithProtectedCtor); + typeBuilder.BuildProxyType(); + } + + [Test] + public void ClearWithDynamicProxies() + { + CompositionProxyTypeBuilder typeBuilder = new CompositionProxyTypeBuilder(); + typeBuilder.TargetType = typeof(TestObject); + Type proxyType = typeBuilder.BuildProxyType(); + + DefaultListableObjectFactory of = new DefaultListableObjectFactory(); + RootObjectDefinition od1 = new RootObjectDefinition(proxyType, false); + od1.PropertyValues.Add("Name", "Bruno"); + of.RegisterObjectDefinition("testObject", od1); + + GenericApplicationContext ctx1 = new GenericApplicationContext(of); + ContextRegistry.RegisterContext(ctx1); + + ITestObject to1 = ContextRegistry.GetContext().GetObject("testObject") as ITestObject; + Assert.IsNotNull(to1); + Assert.AreEqual("Bruno", to1.Name); + + DefaultListableObjectFactory of2 = new DefaultListableObjectFactory(); + RootObjectDefinition od2 = new RootObjectDefinition(proxyType, false); + od2.PropertyValues.Add("Name", "Baia"); + of2.RegisterObjectDefinition("testObject", od2); + GenericApplicationContext ctx2 = new GenericApplicationContext(of2); + + ContextRegistry.Clear(); + + ITestObject to2 = ctx2.GetObject("testObject") as ITestObject; + Assert.IsNotNull(to2); + Assert.AreEqual("Baia", to2.Name); + } + + // TODO : Add support for .NET 1.x + [Test] + public void ClearWithConfigurationSection() + { + IApplicationContext ctx1 = ContextRegistry.GetContext(); + ContextRegistry.Clear(); + IApplicationContext ctx2 = ContextRegistry.GetContext(); + + Assert.AreNotSame(ctx1, ctx2); + } + + [Test(Description = "SPRNET-105")] + public void ChokesIfChildContextRegisteredUnderNameOfAnExistingContext() + { + MockApplicationContext original = new MockApplicationContext("original"); + ContextRegistry.RegisterContext(original); + MockApplicationContext duplicate = new MockApplicationContext("original"); + Assert.Throws(() => ContextRegistry.RegisterContext(duplicate)); + } + + [Test] + public void RemovesContextFromRegistryWhenContextCloses() + { + StaticApplicationContext appCtx = new StaticApplicationContext(); + appCtx.Name = "myCtx"; + ContextRegistry.RegisterContext(appCtx); + Assert.IsTrue(ContextRegistry.IsContextRegistered(appCtx.Name)); + appCtx.Dispose(); + Assert.IsFalse(ContextRegistry.IsContextRegistered(appCtx.Name)); + } + + [TestFixture] + public class WhenHierarchicalContextsAllHaveDefaultNames + { + private MockApplicationContext _parentContext; + private MockApplicationContext _childContext; + private MockApplicationContext _grandChildContext; + private MockApplicationContext _greatGrandChildContext; + + private string _expectedParentName; + private string _expectedChildName; + private string _expectedGrandChildName; + private string _expectedGreatGrandChildName; + + [OneTimeSetUp] + public void InitializeAllTests() + { + _expectedParentName = AbstractApplicationContext.DefaultRootContextName; + _expectedChildName = string.Format("{0}/{1}", _expectedParentName, AbstractApplicationContext.DefaultRootContextName); + _expectedGrandChildName = string.Format("{0}/{1}/{2}", _expectedParentName, _expectedChildName, AbstractApplicationContext.DefaultRootContextName); + _expectedGreatGrandChildName = string.Format("{0}/{1}/{2}/{3}", _expectedParentName, _expectedChildName, _expectedGrandChildName, AbstractApplicationContext.DefaultRootContextName); + } + [SetUp] - public void SetUp() + public void Setup() { - ContextRegistry.Clear(); - ResetConfigurationSystem(); - } - - private static void ResetConfigurationSystem() - { - if (SystemUtils.MonoRuntime) - { - return; - } - FieldInfo initStateRef = typeof(ConfigurationManager).GetField("s_initState", BindingFlags.NonPublic | BindingFlags.Static); - object notStarted = Activator.CreateInstance(initStateRef.FieldType); - initStateRef.SetValue(null, notStarted); - } - - /// - /// This handler simulates an undefined configuration section - /// - private static object GetNullSection(object parent, object context, XmlNode section) - { - return null; - } - - /// - /// This handler simulates calls to ContextRegistry during context creation - /// - private static object GetContextRecursive(object parent, object context, XmlNode section) - { - return ContextRegistry.GetContext(); // this must fail! - } - - [Test] - public void ThrowsInvalidOperationExceptionOnRecursiveCallsToGetContext() - { - using (new HookableContextHandler.Guard(GetContextRecursive)) - { - try - { - ContextRegistry.GetContext("somename"); - Assert.Fail("Should throw an exception"); - } - catch (ConfigurationException ex) - { - InvalidOperationException rootCause = ex.GetBaseException() as InvalidOperationException; - Assert.IsNotNull(rootCause); - Assert.AreEqual("root context is currently in creation.", rootCause.Message.Substring(0, 38)); - } - } - } - - [Test] - public void RegisterRootContext() - { - MockApplicationContext ctx = new MockApplicationContext(); - ContextRegistry.RegisterContext(ctx); - IApplicationContext context = ContextRegistry.GetContext(); - Assert.IsNotNull(context, - "Root context is null even though a context has been registered."); - Assert.IsTrue(Object.ReferenceEquals(ctx, context), - "Root context was not the same as the first context registered (it must be)."); - } - - [Test] - public void RegisterNamedRootContext() - { - const string ctxName = "bingo"; - MockApplicationContext ctx = new MockApplicationContext(ctxName); - ContextRegistry.RegisterContext(ctx); - IApplicationContext rootContext = ContextRegistry.GetContext(); - Assert.IsNotNull(rootContext, - "Root context is null even though a context has been registered."); - Assert.AreEqual(ctxName, rootContext.Name, - "Root context name is different even though the root context has been registered under the lookup name."); - } - - [Test] - public void RegisterNamedContext() - { - const string ctxName = "bingo"; - MockApplicationContext ctx = new MockApplicationContext(ctxName); - ContextRegistry.RegisterContext(ctx); - IApplicationContext context = ContextRegistry.GetContext(ctxName); - Assert.IsNotNull(context, - "Named context is null even though a context has been registered under the lookup name."); - Assert.IsTrue(Object.ReferenceEquals(ctx, context), - "Named context was not the same as the registered context (it must be)."); - } - - [Test] - public void GetContextWithNullName() - { - Assert.Throws(() => ContextRegistry.GetContext(null)); - } - - [Test] - public void GetContextWithEmptyName() - { - Assert.Throws(() => ContextRegistry.GetContext("")); - } - - [Test] - public void GetRootContextNotRegisteredThrowsException() - { - Assert.Throws(() => - { - using (new HookableContextHandler.Guard(GetNullSection)) - { - ContextRegistry.GetContext(); - } - }, "No context registered. Use the 'RegisterContext' method or the 'spring/context' section from your configuration file."); - } - - - [Test] - public void GetContextByNameNotRegisteredThrowsException() - { - Assert.Throws( - () => ContextRegistry.GetContext("bingo"), - "No context registered under name 'bingo'. Use the 'RegisterContext' method or the 'spring/context' section from your configuration file."); - } - - [Test] - public void CanBuildProxyForClassWithProtectedConstructor() - { - CompositionProxyTypeBuilder typeBuilder = new CompositionProxyTypeBuilder(); - typeBuilder.TargetType = typeof(ClassWithProtectedCtor); - typeBuilder.BuildProxyType(); - } - - [Test] - public void ClearWithDynamicProxies() - { - CompositionProxyTypeBuilder typeBuilder = new CompositionProxyTypeBuilder(); - typeBuilder.TargetType = typeof(TestObject); - Type proxyType = typeBuilder.BuildProxyType(); - - DefaultListableObjectFactory of = new DefaultListableObjectFactory(); - RootObjectDefinition od1 = new RootObjectDefinition(proxyType, false); - od1.PropertyValues.Add("Name", "Bruno"); - of.RegisterObjectDefinition("testObject", od1); - - GenericApplicationContext ctx1 = new GenericApplicationContext(of); - ContextRegistry.RegisterContext(ctx1); - - ITestObject to1 = ContextRegistry.GetContext().GetObject("testObject") as ITestObject; - Assert.IsNotNull(to1); - Assert.AreEqual("Bruno", to1.Name); - - DefaultListableObjectFactory of2 = new DefaultListableObjectFactory(); - RootObjectDefinition od2 = new RootObjectDefinition(proxyType, false); - od2.PropertyValues.Add("Name", "Baia"); - of2.RegisterObjectDefinition("testObject", od2); - GenericApplicationContext ctx2 = new GenericApplicationContext(of2); - + //ensure prior-registered contexts are removed ContextRegistry.Clear(); - ITestObject to2 = ctx2.GetObject("testObject") as ITestObject; - Assert.IsNotNull(to2); - Assert.AreEqual("Baia", to2.Name); + _parentContext = new MockApplicationContext(); + _parentContext.MockName = "parent"; + + _childContext = new MockApplicationContext(_parentContext); + _childContext.MockName = "child"; + _childContext.ParentContext = _parentContext; + + _grandChildContext = new MockApplicationContext(_childContext); + _grandChildContext.MockName = "grandchild"; + _grandChildContext.ParentContext = _childContext; + + _greatGrandChildContext = new MockApplicationContext(_grandChildContext); + _greatGrandChildContext.MockName = "greatgrandchild"; + _greatGrandChildContext.ParentContext = _grandChildContext; } - // TODO : Add support for .NET 1.x [Test] - public void ClearWithConfigurationSection() + public void RegisterContext_ConstructsNestedPathBasedNames_IfRegisterdInHierarchicalOrder() { - IApplicationContext ctx1 = ContextRegistry.GetContext(); - ContextRegistry.Clear(); - IApplicationContext ctx2 = ContextRegistry.GetContext(); + ContextRegistry.RegisterContext(_parentContext); + ContextRegistry.RegisterContext(_childContext); + ContextRegistry.RegisterContext(_grandChildContext); + ContextRegistry.RegisterContext(_greatGrandChildContext); - Assert.AreNotSame(ctx1, ctx2); + Assert.AreEqual(_expectedParentName, ContextRegistry.GetContext().Name); + Assert.AreEqual(_expectedChildName, ContextRegistry.GetContext(_expectedChildName).Name); + Assert.AreEqual(_expectedGrandChildName, ContextRegistry.GetContext(_expectedGrandChildName).Name); + Assert.AreEqual(_expectedGreatGrandChildName, ContextRegistry.GetContext(_expectedGreatGrandChildName).Name); } - [Test(Description = "SPRNET-105")] - public void ChokesIfChildContextRegisteredUnderNameOfAnExistingContext() - { - MockApplicationContext original = new MockApplicationContext("original"); - ContextRegistry.RegisterContext(original); - MockApplicationContext duplicate = new MockApplicationContext("original"); - Assert.Throws(() => ContextRegistry.RegisterContext(duplicate)); - } - - [Test] - public void RemovesContextFromRegistryWhenContextCloses() + public void RegisterContext_ConstructsNestedPathBasedNames_IfRegisteringAMixOfDefaultAndExplicitNamedContexts() { - StaticApplicationContext appCtx = new StaticApplicationContext(); - appCtx.Name = "myCtx"; - ContextRegistry.RegisterContext(appCtx); - Assert.IsTrue(ContextRegistry.IsContextRegistered(appCtx.Name)); - appCtx.Dispose(); - Assert.IsFalse(ContextRegistry.IsContextRegistered(appCtx.Name)); + //modify the expected names for the decendent contexts for this one test + string childContextInitialName = AbstractApplicationContext.DefaultRootContextName + "_CUSTOM"; + _expectedChildName = string.Format("{0}/{1}", _expectedParentName, childContextInitialName); + _expectedGrandChildName = string.Format("{0}/{1}/{2}", _expectedParentName, _expectedChildName, AbstractApplicationContext.DefaultRootContextName); + _expectedGreatGrandChildName = string.Format("{0}/{1}/{2}/{3}", _expectedParentName, _expectedChildName, _expectedGrandChildName, AbstractApplicationContext.DefaultRootContextName); + + //setup custom child instance for this one test + _childContext = new MockApplicationContext(_expectedChildName); + _childContext.MockName = "child"; + _childContext.ParentContext = _parentContext; + _grandChildContext.ParentContext = _childContext; + + //register contexts in conflict with hierarchical order + ContextRegistry.RegisterContext(_parentContext); + ContextRegistry.RegisterContext(_childContext); + ContextRegistry.RegisterContext(_grandChildContext); + ContextRegistry.RegisterContext(_greatGrandChildContext); + + Assert.AreEqual(_expectedParentName, ContextRegistry.GetContext(_expectedParentName).Name); + Assert.AreEqual(_expectedChildName, ContextRegistry.GetContext(_expectedChildName).Name); + Assert.AreEqual(_expectedGrandChildName, ContextRegistry.GetContext(_expectedGrandChildName).Name); + Assert.AreEqual(_expectedGreatGrandChildName, ContextRegistry.GetContext(_expectedGreatGrandChildName).Name); } - - [TestFixture] - public class WhenHierarchicalContextsAllHaveDefaultNames - { - private MockApplicationContext _parentContext; - private MockApplicationContext _childContext; - private MockApplicationContext _grandChildContext; - private MockApplicationContext _greatGrandChildContext; - - private string _expectedParentName; - private string _expectedChildName; - private string _expectedGrandChildName; - private string _expectedGreatGrandChildName; - - - [OneTimeSetUp] - public void InitializeAllTests() - { - _expectedParentName = AbstractApplicationContext.DefaultRootContextName; - _expectedChildName = string.Format("{0}/{1}", _expectedParentName, AbstractApplicationContext.DefaultRootContextName); - _expectedGrandChildName = string.Format("{0}/{1}/{2}",_expectedParentName, _expectedChildName, AbstractApplicationContext.DefaultRootContextName); - _expectedGreatGrandChildName = string.Format("{0}/{1}/{2}/{3}",_expectedParentName, _expectedChildName, _expectedGrandChildName, AbstractApplicationContext.DefaultRootContextName); - } - - [SetUp] - public void Setup() - { - //ensure prior-registered contexts are removed - ContextRegistry.Clear(); - - _parentContext = new MockApplicationContext(); - _parentContext.MockName = "parent"; - - _childContext = new MockApplicationContext(_parentContext); - _childContext.MockName = "child"; - _childContext.ParentContext = _parentContext; - - _grandChildContext = new MockApplicationContext(_childContext); - _grandChildContext.MockName = "grandchild"; - _grandChildContext.ParentContext = _childContext; - - _greatGrandChildContext = new MockApplicationContext(_grandChildContext); - _greatGrandChildContext.MockName = "greatgrandchild"; - _greatGrandChildContext.ParentContext = _grandChildContext; - } - - - [Test] - public void RegisterContext_ConstructsNestedPathBasedNames_IfRegisterdInHierarchicalOrder() - { - ContextRegistry.RegisterContext(_parentContext); - ContextRegistry.RegisterContext(_childContext); - ContextRegistry.RegisterContext(_grandChildContext); - ContextRegistry.RegisterContext(_greatGrandChildContext); - - Assert.AreEqual(_expectedParentName, ContextRegistry.GetContext().Name); - Assert.AreEqual(_expectedChildName, ContextRegistry.GetContext(_expectedChildName).Name); - Assert.AreEqual(_expectedGrandChildName, ContextRegistry.GetContext(_expectedGrandChildName).Name); - Assert.AreEqual(_expectedGreatGrandChildName, ContextRegistry.GetContext(_expectedGreatGrandChildName).Name); - } - - [Test] - public void RegisterContext_ConstructsNestedPathBasedNames_IfRegisteringAMixOfDefaultAndExplicitNamedContexts() - { - //modify the expected names for the decendent contexts for this one test - string childContextInitialName = AbstractApplicationContext.DefaultRootContextName + "_CUSTOM"; - _expectedChildName = string.Format("{0}/{1}", _expectedParentName, childContextInitialName); - _expectedGrandChildName = string.Format("{0}/{1}/{2}", _expectedParentName, _expectedChildName, AbstractApplicationContext.DefaultRootContextName); - _expectedGreatGrandChildName = string.Format("{0}/{1}/{2}/{3}", _expectedParentName, _expectedChildName, _expectedGrandChildName, AbstractApplicationContext.DefaultRootContextName); - - //setup custom child instance for this one test - _childContext = new MockApplicationContext(_expectedChildName); - _childContext.MockName = "child"; - _childContext.ParentContext = _parentContext; - _grandChildContext.ParentContext = _childContext; - - //register contexts in conflict with hierarchical order - ContextRegistry.RegisterContext(_parentContext); - ContextRegistry.RegisterContext(_childContext); - ContextRegistry.RegisterContext(_grandChildContext); - ContextRegistry.RegisterContext(_greatGrandChildContext); - - - Assert.AreEqual(_expectedParentName, ContextRegistry.GetContext(_expectedParentName).Name); - Assert.AreEqual(_expectedChildName, ContextRegistry.GetContext(_expectedChildName).Name); - Assert.AreEqual(_expectedGrandChildName, ContextRegistry.GetContext(_expectedGrandChildName).Name); - Assert.AreEqual(_expectedGreatGrandChildName, ContextRegistry.GetContext(_expectedGreatGrandChildName).Name); - } - } - } } diff --git a/test/Spring/Spring.Core.Tests/Context/Support/DefaultMessageSourceResolvableTests.cs b/test/Spring/Spring.Core.Tests/Context/Support/DefaultMessageSourceResolvableTests.cs index 5c7c1985..c73c5cd1 100644 --- a/test/Spring/Spring.Core.Tests/Context/Support/DefaultMessageSourceResolvableTests.cs +++ b/test/Spring/Spring.Core.Tests/Context/Support/DefaultMessageSourceResolvableTests.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -19,93 +19,90 @@ #endregion using System.Text; - using FakeItEasy; - using NUnit.Framework; -namespace Spring.Context.Support +namespace Spring.Context.Support; + +/// +/// Unit tests for the DefaultMessageSourceResolvable class. +/// +[TestFixture] +public sealed class DefaultMessageSourceResolvableTests { - /// - /// Unit tests for the DefaultMessageSourceResolvable class. - /// - [TestFixture] - public sealed class DefaultMessageSourceResolvableTests - { - [SetUp] - public void Init() - { - } + [SetUp] + public void Init() + { + } - [Test] - public void InstantiationWithASingleCodeDefaultsToEmptyDefaultMessage() - { - DefaultMessageSourceResolvable dmr = new DefaultMessageSourceResolvable("foo"); - Assert.AreEqual(string.Empty, dmr.DefaultMessage, - "Not defaulting to non null empty string value (it must)."); - } + [Test] + public void InstantiationWithASingleCodeDefaultsToEmptyDefaultMessage() + { + DefaultMessageSourceResolvable dmr = new DefaultMessageSourceResolvable("foo"); + Assert.AreEqual(string.Empty, dmr.DefaultMessage, + "Not defaulting to non null empty string value (it must)."); + } - [Test] - public void NullLastCode() - { - DefaultMessageSourceResolvable dmr = new DefaultMessageSourceResolvable(null, null); - Assert.IsNull(dmr.LastCode); - } + [Test] + public void NullLastCode() + { + DefaultMessageSourceResolvable dmr = new DefaultMessageSourceResolvable(null, null); + Assert.IsNull(dmr.LastCode); + } - [Test] - public void LastCode() - { - DefaultMessageSourceResolvable dmr = new DefaultMessageSourceResolvable(new string[] {"code1"}, null); - Assert.AreEqual("code1", dmr.LastCode); - } + [Test] + public void LastCode() + { + DefaultMessageSourceResolvable dmr = new DefaultMessageSourceResolvable(new string[] { "code1" }, null); + Assert.AreEqual("code1", dmr.LastCode); + } - [Test] - public void ResolvableToString() - { - string[] codes = new string[] {"code1", "code2"}; - object[] arguments = new object[] {"argument1", "argument2"}; - string defaultMessage = "defaultMessage"; - DefaultMessageSourceResolvable dmr = new DefaultMessageSourceResolvable(codes, arguments, defaultMessage); - Assert.AreEqual(getResolvableString(), dmr.ToString(), "to string"); - } + [Test] + public void ResolvableToString() + { + string[] codes = new string[] { "code1", "code2" }; + object[] arguments = new object[] { "argument1", "argument2" }; + string defaultMessage = "defaultMessage"; + DefaultMessageSourceResolvable dmr = new DefaultMessageSourceResolvable(codes, arguments, defaultMessage); + Assert.AreEqual(getResolvableString(), dmr.ToString(), "to string"); + } - [Test] - public void ResolvableToStringNullArguments() - { - string[] codes = new string[] {"code1", "code2"}; - string defaultMessage = "defaultMessage"; - DefaultMessageSourceResolvable dmr = new DefaultMessageSourceResolvable(codes, null, defaultMessage); - Assert.AreEqual(getResolvableStringNull(), dmr.ToString(), "to string"); - } + [Test] + public void ResolvableToStringNullArguments() + { + string[] codes = new string[] { "code1", "code2" }; + string defaultMessage = "defaultMessage"; + DefaultMessageSourceResolvable dmr = new DefaultMessageSourceResolvable(codes, null, defaultMessage); + Assert.AreEqual(getResolvableStringNull(), dmr.ToString(), "to string"); + } - [Test] - public void DefaultResolvableFromExistingResolvable() - { - IMessageSourceResolvable res = A.Fake(); - A.CallTo(() => res.DefaultMessage).Returns("defaultMessageFromMock"); - A.CallTo(() => res.GetCodes()).Returns(new string[] { "code1FromMock" }); - A.CallTo(() => res.GetArguments()).Returns(new object[] { "ArgumentFromMock" }); + [Test] + public void DefaultResolvableFromExistingResolvable() + { + IMessageSourceResolvable res = A.Fake(); + A.CallTo(() => res.DefaultMessage).Returns("defaultMessageFromMock"); + A.CallTo(() => res.GetCodes()).Returns(new string[] { "code1FromMock" }); + A.CallTo(() => res.GetArguments()).Returns(new object[] { "ArgumentFromMock" }); - DefaultMessageSourceResolvable dmr = new DefaultMessageSourceResolvable(res); - Assert.AreEqual("defaultMessageFromMock", dmr.DefaultMessage, "default"); - Assert.AreEqual("code1FromMock", dmr.LastCode, "codes"); - Assert.AreEqual("ArgumentFromMock", (dmr.GetArguments())[0], "arguments"); - } + DefaultMessageSourceResolvable dmr = new DefaultMessageSourceResolvable(res); + Assert.AreEqual("defaultMessageFromMock", dmr.DefaultMessage, "default"); + Assert.AreEqual("code1FromMock", dmr.LastCode, "codes"); + Assert.AreEqual("ArgumentFromMock", (dmr.GetArguments())[0], "arguments"); + } - private string getResolvableString() - { - StringBuilder builder = new StringBuilder(); - builder.Append("codes=[code1,code2]; arguments=[(String)[argument1], (String)[argument2]]; "); - builder.Append("defaultMessage=[defaultMessage]"); - return builder.ToString(); - } + private string getResolvableString() + { + StringBuilder builder = new StringBuilder(); + builder.Append("codes=[code1,code2]; arguments=[(String)[argument1], (String)[argument2]]; "); + builder.Append("defaultMessage=[defaultMessage]"); + return builder.ToString(); + } - private string getResolvableStringNull() - { - StringBuilder builder = new StringBuilder(); - builder.Append("codes=[code1,code2]; arguments=[null]; "); - builder.Append("defaultMessage=[defaultMessage]"); - return builder.ToString(); - } - } -} \ No newline at end of file + private string getResolvableStringNull() + { + StringBuilder builder = new StringBuilder(); + builder.Append("codes=[code1,code2]; arguments=[null]; "); + builder.Append("defaultMessage=[defaultMessage]"); + return builder.ToString(); + } +} diff --git a/test/Spring/Spring.Core.Tests/Context/Support/DelegatingMessageSourceTests.cs b/test/Spring/Spring.Core.Tests/Context/Support/DelegatingMessageSourceTests.cs index a628fa0f..ccbef67c 100644 --- a/test/Spring/Spring.Core.Tests/Context/Support/DelegatingMessageSourceTests.cs +++ b/test/Spring/Spring.Core.Tests/Context/Support/DelegatingMessageSourceTests.cs @@ -19,214 +19,211 @@ #endregion using System.Globalization; - using FakeItEasy; - using NUnit.Framework; -namespace Spring.Context.Support +namespace Spring.Context.Support; + +/// +/// Unit tests for the DelegatingMessageSource class. +/// +/// Rick Evans +[TestFixture] +public sealed class DelegatingMessageSourceTests { - /// - /// Unit tests for the DelegatingMessageSource class. - /// - /// Rick Evans - [TestFixture] - public sealed class DelegatingMessageSourceTests - { - private const string LookupKey = "rick"; - private IMessageSource _messageSource; + private const string LookupKey = "rick"; + private IMessageSource _messageSource; - private IMessageSource MockMessageSource - { - get - { - return _messageSource; - } - } - - /// - /// The setup logic executed before the execution of each individual test. - /// - [SetUp] - public void SetUp() + private IMessageSource MockMessageSource + { + get { - _messageSource = A.Fake(); + return _messageSource; } - - [Test] - public void Instantiation() - { - DelegatingMessageSource source = new DelegatingMessageSource(); - Assert.IsNotNull(source.ParentMessageSource, "ParentMessageSource property must *never* be null."); - } - - [Test] - public void InstantiationWithSuppliedParentMessageSource() - { - DelegatingMessageSource source - = new DelegatingMessageSource(MockMessageSource); - Assert.IsNotNull(source.ParentMessageSource, - "ParentMessageSource property must *never* be null."); - Assert.IsTrue(Object.ReferenceEquals(source.ParentMessageSource, MockMessageSource)); - } - - [Test] - public void GetMessage() - { - const string expectedName = "Rick Evans"; - A.CallTo(() => MockMessageSource.GetMessage(LookupKey)).Returns(expectedName); - DelegatingMessageSource source = new DelegatingMessageSource(MockMessageSource); - string name = source.GetMessage(LookupKey); - Assert.AreEqual(expectedName, name); - } - - [Test] - public void GetMessageNoDelegateTarget() - { - DelegatingMessageSource source = new DelegatingMessageSource(); - Assert.Throws(() => source.GetMessage(LookupKey)); - } - - [Test] - public void GetMessageWithCulture() - { - const string expectedName = "Rick Evans"; - A.CallTo(() => MockMessageSource.GetMessage(LookupKey, CultureInfo.InvariantCulture)).Returns(expectedName); - DelegatingMessageSource source = new DelegatingMessageSource(MockMessageSource); - string name = source.GetMessage(LookupKey, CultureInfo.InvariantCulture); - Assert.AreEqual(expectedName, name); - } - - [Test] - public void GetMessageWithCultureNoDelegateTarget() - { - DelegatingMessageSource source = new DelegatingMessageSource(); - Assert.Throws(() => source.GetMessage(LookupKey, CultureInfo.InvariantCulture)); - } - - [Test] - public void GetMessageWithParams() - { - const string expectedName = "Rick Evans"; - A.CallTo(() => MockMessageSource.GetMessage(LookupKey, new string[] {"Rick", "Evans"})).Returns(expectedName); - DelegatingMessageSource source = new DelegatingMessageSource(MockMessageSource); - string name = source.GetMessage(LookupKey, "Rick", "Evans"); - Assert.AreEqual(expectedName, name); - } - - [Test] - public void GetMessageWithParamsNoDelegateTarget() - { - DelegatingMessageSource source = new DelegatingMessageSource(); - Assert.Throws(() => source.GetMessage(LookupKey, "Rick", "Evans")); - } - - [Test] - public void GetMessageWithCultureAndParams() - { - const string expectedName = "Rick Evans"; - A.CallTo(() => MockMessageSource.GetMessage(LookupKey, CultureInfo.InvariantCulture, new string[] {"Rick", "Evans"})).Returns(expectedName); - DelegatingMessageSource source = new DelegatingMessageSource(MockMessageSource); - string name = source.GetMessage(LookupKey, CultureInfo.InvariantCulture, "Rick", "Evans"); - Assert.AreEqual(expectedName, name); - } - - [Test] - public void GetMessageWithCultureAndParamsNoDelegateTarget() - { - DelegatingMessageSource source = new DelegatingMessageSource(); - Assert.Throws(() => source.GetMessage(LookupKey, CultureInfo.InvariantCulture, "Rick", "Evans")); - } - - [Test] - public void GetMessageWithMessageSourceResolvableAndCulture() - { - const string expectedName = "Rick Evans"; - DelegatingMessageSource source = new DelegatingMessageSource(MockMessageSource); - A.CallTo(() => MockMessageSource.GetMessage((IMessageSourceResolvable)null, CultureInfo.InvariantCulture)).Returns(expectedName); - - string name = source.GetMessage((IMessageSourceResolvable) null, CultureInfo.InvariantCulture); - Assert.AreEqual(expectedName, name); - } - - [Test] - public void GetMessageWithNoParentMessageSourceAndMessageSourceResolvableAndCulture() - { - const string expectedName = "Rick Evans"; - - IMessageSourceResolvable resolvable = A.Fake(); - A.CallTo(() => resolvable.DefaultMessage).Returns(expectedName); - - DelegatingMessageSource source = new DelegatingMessageSource(); - string name = source.GetMessage(resolvable, CultureInfo.InvariantCulture); - Assert.AreEqual(expectedName, name); - } - - [Test] - public void GetMessageWithNoParentMessageSourceAndNullDefaultMessageSourceResolvableWithNoCodesAndCulture() - { - IMessageSourceResolvable resolver = new DefaultMessageSourceResolvable( - new string[] {}, new object[] {}, string.Empty); - DelegatingMessageSource source = new DelegatingMessageSource(); - Assert.Throws(() => source.GetMessage(resolver, CultureInfo.InvariantCulture)); - } - - [Test] - public void GetMessageWithNoParentMessageSourceAndNullDefaultMessageSourceResolvableAndCulture() - { - IMessageSourceResolvable resolver = new DefaultMessageSourceResolvable( - new string[] {"foo"}, new object[] {}, string.Empty); - DelegatingMessageSource source = new DelegatingMessageSource(); - Assert.Throws(() => source.GetMessage(resolver, CultureInfo.InvariantCulture)); - } - - [Test] - public void GetResourceObject() - { - const string expectedName = "Rick Evans"; - A.CallTo(() => MockMessageSource.GetResourceObject(LookupKey)).Returns(expectedName); - DelegatingMessageSource source = new DelegatingMessageSource(MockMessageSource); - string name = (string) source.GetResourceObject(LookupKey); - Assert.AreEqual(expectedName, name); - } - - [Test] - public void GetResourceObjectWithNoParentMessageSource() - { - DelegatingMessageSource source = new DelegatingMessageSource(); - Assert.Throws(() => source.GetResourceObject(LookupKey)); - } - - [Test] - public void GetResourceObjectWithCulture() - { - const string expectedName = "Rick Evans"; - A.CallTo(() => MockMessageSource.GetResourceObject(LookupKey, CultureInfo.InvariantCulture)).Returns(expectedName); - DelegatingMessageSource source = new DelegatingMessageSource(MockMessageSource); - string name = (string) source.GetResourceObject(LookupKey, CultureInfo.InvariantCulture); - Assert.AreEqual(expectedName, name); - } - - [Test] - public void GetResourceObjectWithNoParentMessageSourceWithCulture() - { - DelegatingMessageSource source = new DelegatingMessageSource(); - Assert.Throws(() => source.GetResourceObject(LookupKey, CultureInfo.InvariantCulture)); - } - - [Test] - public void ApplyResources() - { - MockMessageSource.ApplyResources(12, "rick", CultureInfo.InvariantCulture); - DelegatingMessageSource source = new DelegatingMessageSource(MockMessageSource); - source.ApplyResources(12, "rick", CultureInfo.InvariantCulture); - } - - [Test] - public void ApplyResourcesWithNoParentMessageSource() - { - DelegatingMessageSource source = new DelegatingMessageSource(); - Assert.Throws(() => source.ApplyResources(12, "rick", CultureInfo.InvariantCulture)); - } } -} + + /// + /// The setup logic executed before the execution of each individual test. + /// + [SetUp] + public void SetUp() + { + _messageSource = A.Fake(); + } + + [Test] + public void Instantiation() + { + DelegatingMessageSource source = new DelegatingMessageSource(); + Assert.IsNotNull(source.ParentMessageSource, "ParentMessageSource property must *never* be null."); + } + + [Test] + public void InstantiationWithSuppliedParentMessageSource() + { + DelegatingMessageSource source + = new DelegatingMessageSource(MockMessageSource); + Assert.IsNotNull(source.ParentMessageSource, + "ParentMessageSource property must *never* be null."); + Assert.IsTrue(Object.ReferenceEquals(source.ParentMessageSource, MockMessageSource)); + } + + [Test] + public void GetMessage() + { + const string expectedName = "Rick Evans"; + A.CallTo(() => MockMessageSource.GetMessage(LookupKey)).Returns(expectedName); + DelegatingMessageSource source = new DelegatingMessageSource(MockMessageSource); + string name = source.GetMessage(LookupKey); + Assert.AreEqual(expectedName, name); + } + + [Test] + public void GetMessageNoDelegateTarget() + { + DelegatingMessageSource source = new DelegatingMessageSource(); + Assert.Throws(() => source.GetMessage(LookupKey)); + } + + [Test] + public void GetMessageWithCulture() + { + const string expectedName = "Rick Evans"; + A.CallTo(() => MockMessageSource.GetMessage(LookupKey, CultureInfo.InvariantCulture)).Returns(expectedName); + DelegatingMessageSource source = new DelegatingMessageSource(MockMessageSource); + string name = source.GetMessage(LookupKey, CultureInfo.InvariantCulture); + Assert.AreEqual(expectedName, name); + } + + [Test] + public void GetMessageWithCultureNoDelegateTarget() + { + DelegatingMessageSource source = new DelegatingMessageSource(); + Assert.Throws(() => source.GetMessage(LookupKey, CultureInfo.InvariantCulture)); + } + + [Test] + public void GetMessageWithParams() + { + const string expectedName = "Rick Evans"; + A.CallTo(() => MockMessageSource.GetMessage(LookupKey, new string[] { "Rick", "Evans" })).Returns(expectedName); + DelegatingMessageSource source = new DelegatingMessageSource(MockMessageSource); + string name = source.GetMessage(LookupKey, "Rick", "Evans"); + Assert.AreEqual(expectedName, name); + } + + [Test] + public void GetMessageWithParamsNoDelegateTarget() + { + DelegatingMessageSource source = new DelegatingMessageSource(); + Assert.Throws(() => source.GetMessage(LookupKey, "Rick", "Evans")); + } + + [Test] + public void GetMessageWithCultureAndParams() + { + const string expectedName = "Rick Evans"; + A.CallTo(() => MockMessageSource.GetMessage(LookupKey, CultureInfo.InvariantCulture, new string[] { "Rick", "Evans" })).Returns(expectedName); + DelegatingMessageSource source = new DelegatingMessageSource(MockMessageSource); + string name = source.GetMessage(LookupKey, CultureInfo.InvariantCulture, "Rick", "Evans"); + Assert.AreEqual(expectedName, name); + } + + [Test] + public void GetMessageWithCultureAndParamsNoDelegateTarget() + { + DelegatingMessageSource source = new DelegatingMessageSource(); + Assert.Throws(() => source.GetMessage(LookupKey, CultureInfo.InvariantCulture, "Rick", "Evans")); + } + + [Test] + public void GetMessageWithMessageSourceResolvableAndCulture() + { + const string expectedName = "Rick Evans"; + DelegatingMessageSource source = new DelegatingMessageSource(MockMessageSource); + A.CallTo(() => MockMessageSource.GetMessage((IMessageSourceResolvable) null, CultureInfo.InvariantCulture)).Returns(expectedName); + + string name = source.GetMessage((IMessageSourceResolvable) null, CultureInfo.InvariantCulture); + Assert.AreEqual(expectedName, name); + } + + [Test] + public void GetMessageWithNoParentMessageSourceAndMessageSourceResolvableAndCulture() + { + const string expectedName = "Rick Evans"; + + IMessageSourceResolvable resolvable = A.Fake(); + A.CallTo(() => resolvable.DefaultMessage).Returns(expectedName); + + DelegatingMessageSource source = new DelegatingMessageSource(); + string name = source.GetMessage(resolvable, CultureInfo.InvariantCulture); + Assert.AreEqual(expectedName, name); + } + + [Test] + public void GetMessageWithNoParentMessageSourceAndNullDefaultMessageSourceResolvableWithNoCodesAndCulture() + { + IMessageSourceResolvable resolver = new DefaultMessageSourceResolvable( + new string[] { }, new object[] { }, string.Empty); + DelegatingMessageSource source = new DelegatingMessageSource(); + Assert.Throws(() => source.GetMessage(resolver, CultureInfo.InvariantCulture)); + } + + [Test] + public void GetMessageWithNoParentMessageSourceAndNullDefaultMessageSourceResolvableAndCulture() + { + IMessageSourceResolvable resolver = new DefaultMessageSourceResolvable( + new string[] { "foo" }, new object[] { }, string.Empty); + DelegatingMessageSource source = new DelegatingMessageSource(); + Assert.Throws(() => source.GetMessage(resolver, CultureInfo.InvariantCulture)); + } + + [Test] + public void GetResourceObject() + { + const string expectedName = "Rick Evans"; + A.CallTo(() => MockMessageSource.GetResourceObject(LookupKey)).Returns(expectedName); + DelegatingMessageSource source = new DelegatingMessageSource(MockMessageSource); + string name = (string) source.GetResourceObject(LookupKey); + Assert.AreEqual(expectedName, name); + } + + [Test] + public void GetResourceObjectWithNoParentMessageSource() + { + DelegatingMessageSource source = new DelegatingMessageSource(); + Assert.Throws(() => source.GetResourceObject(LookupKey)); + } + + [Test] + public void GetResourceObjectWithCulture() + { + const string expectedName = "Rick Evans"; + A.CallTo(() => MockMessageSource.GetResourceObject(LookupKey, CultureInfo.InvariantCulture)).Returns(expectedName); + DelegatingMessageSource source = new DelegatingMessageSource(MockMessageSource); + string name = (string) source.GetResourceObject(LookupKey, CultureInfo.InvariantCulture); + Assert.AreEqual(expectedName, name); + } + + [Test] + public void GetResourceObjectWithNoParentMessageSourceWithCulture() + { + DelegatingMessageSource source = new DelegatingMessageSource(); + Assert.Throws(() => source.GetResourceObject(LookupKey, CultureInfo.InvariantCulture)); + } + + [Test] + public void ApplyResources() + { + MockMessageSource.ApplyResources(12, "rick", CultureInfo.InvariantCulture); + DelegatingMessageSource source = new DelegatingMessageSource(MockMessageSource); + source.ApplyResources(12, "rick", CultureInfo.InvariantCulture); + } + + [Test] + public void ApplyResourcesWithNoParentMessageSource() + { + DelegatingMessageSource source = new DelegatingMessageSource(); + Assert.Throws(() => source.ApplyResources(12, "rick", CultureInfo.InvariantCulture)); + } +} \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/Context/Support/Logic.cs b/test/Spring/Spring.Core.Tests/Context/Support/Logic.cs index fa317329..946acd9e 100644 --- a/test/Spring/Spring.Core.Tests/Context/Support/Logic.cs +++ b/test/Spring/Spring.Core.Tests/Context/Support/Logic.cs @@ -20,28 +20,25 @@ using Spring.Objects.Factory; -namespace Spring.Context.Support +namespace Spring.Context.Support; + +/// Mark Pollack +public class Logic : IObjectNameAware { - /// Mark Pollack - public class Logic : IObjectNameAware + private string objectName; + private Assembler assembler; + + public Assembler Assembler { - - private string objectName; - private Assembler assembler; - - - public Assembler Assembler - { - set { assembler = value; } - } - - #region IObjectNameAware Members - - public string ObjectName - { - set { objectName = value; } - } - - #endregion + set { assembler = value; } } -} \ No newline at end of file + + #region IObjectNameAware Members + + public string ObjectName + { + set { objectName = value; } + } + + #endregion +} diff --git a/test/Spring/Spring.Core.Tests/Context/Support/MessageSourceAccessorTests.cs b/test/Spring/Spring.Core.Tests/Context/Support/MessageSourceAccessorTests.cs index f9a8ac38..5e575c35 100644 --- a/test/Spring/Spring.Core.Tests/Context/Support/MessageSourceAccessorTests.cs +++ b/test/Spring/Spring.Core.Tests/Context/Support/MessageSourceAccessorTests.cs @@ -19,111 +19,107 @@ #endregion using System.Globalization; - using FakeItEasy; - using NUnit.Framework; using Spring.Globalization; -namespace Spring.Context.Support +namespace Spring.Context.Support; + +[TestFixture] +public class MessageSourceAccessorTests { - [TestFixture] - public class MessageSourceAccessorTests + [OneTimeSetUp] + public void TestFixtureSetUp() { - [OneTimeSetUp] - public void TestFixtureSetUp() - { - CultureTestScope.Set(); - } - - [OneTimeTearDown] - public void TestFixtureTearDown() - { - CultureTestScope.Reset(); - } - - private readonly string MSGCODE = "code1"; - private readonly CultureInfo MSGCULTURE = new CultureInfo("fr"); - private readonly object[] MSGARGS = new object[] { "argument1" }; - private readonly string MSGRESULT = "my message"; - - - private IMessageSource mockMsgSource; - private IMessageSourceResolvable mockMsgSourceResolvable; - - [SetUp] - public void SetUp() - { - mockMsgSource = A.Fake(); - mockMsgSourceResolvable = A.Fake(); - } - - [TearDown] - public void TearDown() - { - } - - [Test] - public void GetMessageCodeCultureArgs() - { - A.CallTo(() => mockMsgSource.GetMessage(MSGCODE, MSGCULTURE, MSGARGS)).Returns(MSGRESULT); - - MessageSourceAccessor msgSourceAccessor = new MessageSourceAccessor(mockMsgSource); - Assert.AreEqual(MSGRESULT, msgSourceAccessor.GetMessage(MSGCODE, MSGCULTURE, MSGARGS)); - } - - [Test] - public void GetMessageCodeArgs() - { - A.CallTo(() => mockMsgSource.GetMessage(MSGCODE, MSGCULTURE, MSGARGS)).Returns(MSGRESULT); - - MessageSourceAccessor msgSourceAccessor = new MessageSourceAccessor(mockMsgSource, MSGCULTURE); - Assert.AreEqual(MSGRESULT, msgSourceAccessor.GetMessage(MSGCODE, MSGARGS)); - } - - [Test] - public void GetMessageCodeArgsDefaultsToCurrentUICulture() - { - A.CallTo(() => mockMsgSource.GetMessage(MSGCODE, CultureInfo.CurrentUICulture, MSGARGS)).Returns(MSGRESULT); - - MessageSourceAccessor msgSourceAccessor = new MessageSourceAccessor(mockMsgSource); - Assert.AreEqual(MSGRESULT, msgSourceAccessor.GetMessage(MSGCODE, MSGARGS)); - } - - [Test] - public void GetMessageCodeCulture() - { - A.CallTo(() => mockMsgSource.GetMessage(MSGCODE, MSGCULTURE)).Returns(MSGRESULT); - - MessageSourceAccessor msgSourceAccessor = new MessageSourceAccessor(mockMsgSource); - Assert.AreEqual(MSGRESULT, msgSourceAccessor.GetMessage(MSGCODE, MSGCULTURE)); - } - - [Test] - public void GetMessageCodeDefaultsToCurrentUICulture() - { - A.CallTo(() => mockMsgSource.GetMessage(MSGCODE, CultureInfo.CurrentUICulture)).Returns(MSGRESULT); - - MessageSourceAccessor msgSourceAccessor = new MessageSourceAccessor(mockMsgSource); - Assert.AreEqual(MSGRESULT, msgSourceAccessor.GetMessage(MSGCODE)); - } - - [Test] - public void GetMessageResolvableCulture() - { - A.CallTo(() => mockMsgSource.GetMessage(mockMsgSourceResolvable, MSGCULTURE)).Returns(MSGRESULT); - - MessageSourceAccessor msgSourceAccessor = new MessageSourceAccessor(mockMsgSource); - Assert.AreEqual(MSGRESULT, msgSourceAccessor.GetMessage(mockMsgSourceResolvable, MSGCULTURE)); - } - - [Test] - public void GetMessageResolvableDefaultsToCurrentUICulture() - { - A.CallTo(() => mockMsgSource.GetMessage(mockMsgSourceResolvable, CultureInfo.CurrentUICulture)).Returns(MSGRESULT); - - MessageSourceAccessor msgSourceAccessor = new MessageSourceAccessor(mockMsgSource); - Assert.AreEqual(MSGRESULT, msgSourceAccessor.GetMessage(mockMsgSourceResolvable)); - } + CultureTestScope.Set(); } -} \ No newline at end of file + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + CultureTestScope.Reset(); + } + + private readonly string MSGCODE = "code1"; + private readonly CultureInfo MSGCULTURE = new CultureInfo("fr"); + private readonly object[] MSGARGS = new object[] { "argument1" }; + private readonly string MSGRESULT = "my message"; + + private IMessageSource mockMsgSource; + private IMessageSourceResolvable mockMsgSourceResolvable; + + [SetUp] + public void SetUp() + { + mockMsgSource = A.Fake(); + mockMsgSourceResolvable = A.Fake(); + } + + [TearDown] + public void TearDown() + { + } + + [Test] + public void GetMessageCodeCultureArgs() + { + A.CallTo(() => mockMsgSource.GetMessage(MSGCODE, MSGCULTURE, MSGARGS)).Returns(MSGRESULT); + + MessageSourceAccessor msgSourceAccessor = new MessageSourceAccessor(mockMsgSource); + Assert.AreEqual(MSGRESULT, msgSourceAccessor.GetMessage(MSGCODE, MSGCULTURE, MSGARGS)); + } + + [Test] + public void GetMessageCodeArgs() + { + A.CallTo(() => mockMsgSource.GetMessage(MSGCODE, MSGCULTURE, MSGARGS)).Returns(MSGRESULT); + + MessageSourceAccessor msgSourceAccessor = new MessageSourceAccessor(mockMsgSource, MSGCULTURE); + Assert.AreEqual(MSGRESULT, msgSourceAccessor.GetMessage(MSGCODE, MSGARGS)); + } + + [Test] + public void GetMessageCodeArgsDefaultsToCurrentUICulture() + { + A.CallTo(() => mockMsgSource.GetMessage(MSGCODE, CultureInfo.CurrentUICulture, MSGARGS)).Returns(MSGRESULT); + + MessageSourceAccessor msgSourceAccessor = new MessageSourceAccessor(mockMsgSource); + Assert.AreEqual(MSGRESULT, msgSourceAccessor.GetMessage(MSGCODE, MSGARGS)); + } + + [Test] + public void GetMessageCodeCulture() + { + A.CallTo(() => mockMsgSource.GetMessage(MSGCODE, MSGCULTURE)).Returns(MSGRESULT); + + MessageSourceAccessor msgSourceAccessor = new MessageSourceAccessor(mockMsgSource); + Assert.AreEqual(MSGRESULT, msgSourceAccessor.GetMessage(MSGCODE, MSGCULTURE)); + } + + [Test] + public void GetMessageCodeDefaultsToCurrentUICulture() + { + A.CallTo(() => mockMsgSource.GetMessage(MSGCODE, CultureInfo.CurrentUICulture)).Returns(MSGRESULT); + + MessageSourceAccessor msgSourceAccessor = new MessageSourceAccessor(mockMsgSource); + Assert.AreEqual(MSGRESULT, msgSourceAccessor.GetMessage(MSGCODE)); + } + + [Test] + public void GetMessageResolvableCulture() + { + A.CallTo(() => mockMsgSource.GetMessage(mockMsgSourceResolvable, MSGCULTURE)).Returns(MSGRESULT); + + MessageSourceAccessor msgSourceAccessor = new MessageSourceAccessor(mockMsgSource); + Assert.AreEqual(MSGRESULT, msgSourceAccessor.GetMessage(mockMsgSourceResolvable, MSGCULTURE)); + } + + [Test] + public void GetMessageResolvableDefaultsToCurrentUICulture() + { + A.CallTo(() => mockMsgSource.GetMessage(mockMsgSourceResolvable, CultureInfo.CurrentUICulture)).Returns(MSGRESULT); + + MessageSourceAccessor msgSourceAccessor = new MessageSourceAccessor(mockMsgSource); + Assert.AreEqual(MSGRESULT, msgSourceAccessor.GetMessage(mockMsgSourceResolvable)); + } +} diff --git a/test/Spring/Spring.Core.Tests/Context/Support/NamespaceParsersSectionHandlerTests.cs b/test/Spring/Spring.Core.Tests/Context/Support/NamespaceParsersSectionHandlerTests.cs index 5c46f2e3..b2fd02d1 100644 --- a/test/Spring/Spring.Core.Tests/Context/Support/NamespaceParsersSectionHandlerTests.cs +++ b/test/Spring/Spring.Core.Tests/Context/Support/NamespaceParsersSectionHandlerTests.cs @@ -26,92 +26,91 @@ using NUnit.Framework; #endregion -namespace Spring.Context.Support +namespace Spring.Context.Support; + +/// +/// Unit tests for the NamespaceParsersSectionHandler class. +/// +/// Rick Evans +[TestFixture] +public sealed class NamespaceParsersSectionHandlerTests { - /// - /// Unit tests for the NamespaceParsersSectionHandler class. - /// - /// Rick Evans - [TestFixture] - public sealed class NamespaceParsersSectionHandlerTests - { - [Test] - public void ParseSectionSunnyDay() - { - const string xml = @" + [Test] + public void ParseSectionSunnyDay() + { + const string xml = @" "; - NamespaceParsersSectionHandler handler = new NamespaceParsersSectionHandler(); - handler.Create(null, null, BuildConfigurationSection(xml)); - } + NamespaceParsersSectionHandler handler = new NamespaceParsersSectionHandler(); + handler.Create(null, null, BuildConfigurationSection(xml)); + } - [Test] - public void ParseSectionWithHandlerThatDoesNotImplement_IXmlObjectDefinitionParser() - { - const string xml = @" + [Test] + public void ParseSectionWithHandlerThatDoesNotImplement_IXmlObjectDefinitionParser() + { + const string xml = @" "; - NamespaceParsersSectionHandler handler = new NamespaceParsersSectionHandler(); - Assert.Throws(() => handler.Create(null, null, BuildConfigurationSection(xml))); - } + NamespaceParsersSectionHandler handler = new NamespaceParsersSectionHandler(); + Assert.Throws(() => handler.Create(null, null, BuildConfigurationSection(xml))); + } - [Test] - public void ParseSectionWithBadTypeForHandler() - { - const string xml = @" + [Test] + public void ParseSectionWithBadTypeForHandler() + { + const string xml = @" "; - NamespaceParsersSectionHandler handler = new NamespaceParsersSectionHandler(); - Assert.Throws(() => handler.Create(null, null, BuildConfigurationSection(xml))); - } + NamespaceParsersSectionHandler handler = new NamespaceParsersSectionHandler(); + Assert.Throws(() => handler.Create(null, null, BuildConfigurationSection(xml))); + } - [Test] - public void ParseSectionWithNoChildParserNamespaceElements() - { - const string xml = @" + [Test] + public void ParseSectionWithNoChildParserNamespaceElements() + { + const string xml = @" "; - NamespaceParsersSectionHandler handler = new NamespaceParsersSectionHandler(); - handler.Create(null, null, BuildConfigurationSection(xml)); - } + NamespaceParsersSectionHandler handler = new NamespaceParsersSectionHandler(); + handler.Create(null, null, BuildConfigurationSection(xml)); + } - [Test] - public void ParseSectionWithEmptyType() - { - const string xml = @" + [Test] + public void ParseSectionWithEmptyType() + { + const string xml = @" "; - NamespaceParsersSectionHandler handler = new NamespaceParsersSectionHandler(); - Assert.Throws(() => handler.Create(null, null, BuildConfigurationSection(xml))); - } + NamespaceParsersSectionHandler handler = new NamespaceParsersSectionHandler(); + Assert.Throws(() => handler.Create(null, null, BuildConfigurationSection(xml))); + } - [Test] - public void WithParserElementThatIsMissingTheTypeAttribute() - { - const string xml = @" + [Test] + public void WithParserElementThatIsMissingTheTypeAttribute() + { + const string xml = @" "; - NamespaceParsersSectionHandler handler = new NamespaceParsersSectionHandler(); - Assert.Throws(() => handler.Create(null, null, BuildConfigurationSection(xml))); - } + NamespaceParsersSectionHandler handler = new NamespaceParsersSectionHandler(); + Assert.Throws(() => handler.Create(null, null, BuildConfigurationSection(xml))); + } - private static XmlNode BuildConfigurationSection(string xml) - { - XmlDocument doc = new XmlDocument(); - doc.LoadXml(xml); - return doc.DocumentElement; - } - } -} \ No newline at end of file + private static XmlNode BuildConfigurationSection(string xml) + { + XmlDocument doc = new XmlDocument(); + doc.LoadXml(xml); + return doc.DocumentElement; + } +} diff --git a/test/Spring/Spring.Core.Tests/Context/Support/NullMessageSourceTests.cs b/test/Spring/Spring.Core.Tests/Context/Support/NullMessageSourceTests.cs index 2529568f..39fec133 100644 --- a/test/Spring/Spring.Core.Tests/Context/Support/NullMessageSourceTests.cs +++ b/test/Spring/Spring.Core.Tests/Context/Support/NullMessageSourceTests.cs @@ -20,40 +20,39 @@ using NUnit.Framework; -namespace Spring.Context.Support +namespace Spring.Context.Support; + +/// +/// Unit tests for the NullMessageSource class. +/// +/// +[TestFixture] +public sealed class NullMessageSourceTests { - /// - /// Unit tests for the NullMessageSource class. - /// - /// - [TestFixture] - public sealed class NullMessageSourceTests - { - [Test] - public void CanonicalInstanceIsNotNull() - { - Assert.IsNotNull(NullMessageSource.Null); - } + [Test] + public void CanonicalInstanceIsNotNull() + { + Assert.IsNotNull(NullMessageSource.Null); + } - [Test] - public void ResolveMessageSpitsbackWhatItWasGiven() - { - const string expected = "foo"; - string message = NullMessageSource.Null.GetMessage(expected); - Assert.AreEqual(expected, message); - } + [Test] + public void ResolveMessageSpitsbackWhatItWasGiven() + { + const string expected = "foo"; + string message = NullMessageSource.Null.GetMessage(expected); + Assert.AreEqual(expected, message); + } - [Test] - public void ResolveObjectReturnsNull() - { - object anObject = NullMessageSource.Null.GetResourceObject(""); - Assert.IsNull(anObject); - } + [Test] + public void ResolveObjectReturnsNull() + { + object anObject = NullMessageSource.Null.GetResourceObject(""); + Assert.IsNull(anObject); + } - [Test] - public void ApplyResourcesDoesNothing() - { - NullMessageSource.Null.ApplyResources("", "foo", null); - } - } -} \ No newline at end of file + [Test] + public void ApplyResourcesDoesNothing() + { + NullMessageSource.Null.ApplyResources("", "foo", null); + } +} diff --git a/test/Spring/Spring.Core.Tests/Context/Support/ResourceSetMessageSourceTests.cs b/test/Spring/Spring.Core.Tests/Context/Support/ResourceSetMessageSourceTests.cs index dc72f373..124ef927 100644 --- a/test/Spring/Spring.Core.Tests/Context/Support/ResourceSetMessageSourceTests.cs +++ b/test/Spring/Spring.Core.Tests/Context/Support/ResourceSetMessageSourceTests.cs @@ -26,394 +26,386 @@ using Spring.Globalization; using Spring.Objects; using Spring.Util; -namespace Spring.Context.Support +namespace Spring.Context.Support; + +/// +/// Unit tests for the ResourceSetMessageSource class. +/// +/// +[TestFixture] +public sealed class ResourceSetMessageSourceTests { - /// - /// Unit tests for the ResourceSetMessageSource class. - /// - /// - [TestFixture] - public sealed class ResourceSetMessageSourceTests + private ResourceSetMessageSource messageSource; + + private const string ResourceNamespace = "Spring.Resources"; + + private const string ResourceFileName = "Spring.Context.Tests"; + + // The namespace is added during the build... + private const string ResourceBaseName = ResourceNamespace + "." + ResourceFileName; + private IList resourceManagerList; + + [OneTimeSetUp] + public void TestFixtureSetUp() { - private ResourceSetMessageSource messageSource; + CultureTestScope.Set(); + } - private const string ResourceNamespace = "Spring.Resources"; - private const string ResourceFileName = "Spring.Context.Tests"; - // The namespace is added during the build... - private const string ResourceBaseName = ResourceNamespace + "." + ResourceFileName; - private IList resourceManagerList; + [OneTimeTearDown] + public void TestFixtureTearDown() + { + CultureTestScope.Reset(); + } - [OneTimeSetUp] - public void TestFixtureSetUp() + /// + /// Populate a known ResourceManager in the resourceManagerList. + /// + [SetUp] + public void Init() + { + messageSource = new ResourceSetMessageSource(); + resourceManagerList = new List(); + Assembly ass = this.GetType().Assembly; + resourceManagerList.Add(new ResourceManager(ResourceBaseName, ass)); + } + + [TearDown] + public void Destroy() + { + messageSource = null; + } + + public void DoTestMessageAccess(bool hasParentContext, bool useCodeAsDefaultMessage) + { + StaticApplicationContext ac = new StaticApplicationContext(); + if (hasParentContext) { - CultureTestScope.Set(); + StaticApplicationContext parent = new StaticApplicationContext(); + parent.Refresh(); + ac.ParentContext = parent; } - [OneTimeTearDown] - public void TestFixtureTearDown() + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.Add("resourceManagers", resourceManagerList); + if (useCodeAsDefaultMessage) { - CultureTestScope.Reset(); + pvs.Add("UseCodeAsDefaultMessage", true); } - /// - /// Populate a known ResourceManager in the resourceManagerList. - /// - [SetUp] - public void Init() - { - messageSource = new ResourceSetMessageSource(); - resourceManagerList = new List(); - Assembly ass = this.GetType().Assembly; - resourceManagerList.Add(new ResourceManager(ResourceBaseName, ass)); - } + ac.RegisterSingleton("messageSource", typeof(ResourceSetMessageSource), pvs); + ac.Refresh(); - [TearDown] - public void Destroy() - { - messageSource = null; - } + // Localizaiton fallbacks + GetMessageLocalizationFallbacks(ac); - public void DoTestMessageAccess(bool hasParentContext, bool useCodeAsDefaultMessage) + // MessageSourceAccessor functionality + MessageSourceAccessor accessor = new MessageSourceAccessor(ac); + Assert.AreEqual("message3", accessor.GetMessage("code3", CultureInfo.CurrentUICulture, null)); + + // IMessageSourceResolveable + Assert.AreEqual("message3", ac.GetMessage("code3", CultureInfo.CurrentUICulture, null)); + IMessageSourceResolvable resolvable = new DefaultMessageSourceResolvable("code3"); + + Assert.AreEqual("message3", ac.GetMessage(resolvable, CultureInfo.CurrentUICulture)); + resolvable = new DefaultMessageSourceResolvable(new string[] { "code4", "code3" }); + Assert.AreEqual("message3", ac.GetMessage(resolvable, CultureInfo.CurrentUICulture)); + + Assert.AreEqual("message3", ac.GetMessage("code3", CultureInfo.CurrentUICulture, null)); + resolvable = new DefaultMessageSourceResolvable(new string[] { "code4", "code3" }); + Assert.AreEqual("message3", ac.GetMessage(resolvable, CultureInfo.CurrentUICulture)); + + object[] arguments = new object[] { "Hello", new DefaultMessageSourceResolvable(new string[] { "code1" }) }; + Assert.AreEqual("Hello, message1", ac.GetMessage("hello", CultureInfo.CurrentUICulture, arguments)); + + // test default message without and with args + Assert.AreEqual("default", ac.GetMessage(null, "default", CultureInfo.CurrentUICulture, null)); + Assert.AreEqual("default", ac.GetMessage(null, "default", CultureInfo.CurrentUICulture, arguments)); + + /* not supported + Assert.AreEqual("{0}, default", ac.GetMessage(null, "{0}, default", CultureInfo.CurrentUICulture, null)); + */ + + Assert.AreEqual("Hello, default", ac.GetMessage(null, "{0}, default", CultureInfo.CurrentUICulture, arguments)); + + // test resolvable with default message, without and with args + resolvable = new DefaultMessageSourceResolvable(null, null, "default"); + Assert.AreEqual("default", ac.GetMessage(resolvable, CultureInfo.CurrentUICulture)); + resolvable = new DefaultMessageSourceResolvable(null, arguments, "default"); + Assert.AreEqual("default", ac.GetMessage(resolvable, CultureInfo.CurrentUICulture)); + + /* not supported + resolvable = new DefaultMessageSourceResolvable(null, null, "{0}, default"); + Assert.AreEqual("{0}, default", ac.GetMessage(resolvable, CultureInfo.CurrentUICulture)); + */ + + resolvable = new DefaultMessageSourceResolvable(null, arguments, "{0}, default"); + Assert.AreEqual("Hello, default", ac.GetMessage(resolvable, CultureInfo.CurrentUICulture)); + + // test message args + Assert.AreEqual("Arg1, Arg2", ac.GetMessage("hello", CultureInfo.CurrentUICulture, new object[] { "Arg1", "Arg2" })); + + /* not supported + Assert.AreEqual("{0}, {1}", ac.GetMessage("hello", CultureInfo.CurrentUICulture, null)); + */ + + /* not supported + Assert.AreEqual("Hello\nWorld", ac.GetMessage("escaped")); + } + else { - StaticApplicationContext ac = new StaticApplicationContext(); - if (hasParentContext) + Assert.AreEqual("Hello\\nWorld", ac.GetMessage("escaped")); + } + */ + + try + { + Assert.AreEqual("MyNonExistantMessage", ac.GetMessage("MyNonExistantMessage")); + if (!useCodeAsDefaultMessage) { - StaticApplicationContext parent = new StaticApplicationContext(); - parent.Refresh(); - ac.ParentContext = parent; + Assert.Fail("Should have thrown NoSuchMessagException"); } - - MutablePropertyValues pvs = new MutablePropertyValues(); - pvs.Add("resourceManagers", resourceManagerList); + } + catch (NoSuchMessageException e) + { if (useCodeAsDefaultMessage) { - pvs.Add("UseCodeAsDefaultMessage", true); + Assert.Fail("Should have returned code as default message."); + e.ToString(); } - ac.RegisterSingleton("messageSource", typeof(ResourceSetMessageSource), pvs); - ac.Refresh(); - - - // Localizaiton fallbacks - GetMessageLocalizationFallbacks(ac); - - // MessageSourceAccessor functionality - MessageSourceAccessor accessor = new MessageSourceAccessor(ac); - Assert.AreEqual("message3", accessor.GetMessage("code3", CultureInfo.CurrentUICulture, null)); - - // IMessageSourceResolveable - Assert.AreEqual("message3", ac.GetMessage("code3", CultureInfo.CurrentUICulture, null)); - IMessageSourceResolvable resolvable = new DefaultMessageSourceResolvable("code3"); - - Assert.AreEqual("message3", ac.GetMessage(resolvable, CultureInfo.CurrentUICulture)); - resolvable = new DefaultMessageSourceResolvable(new string[] { "code4", "code3" }); - Assert.AreEqual("message3", ac.GetMessage(resolvable, CultureInfo.CurrentUICulture)); - - Assert.AreEqual("message3", ac.GetMessage("code3", CultureInfo.CurrentUICulture, null)); - resolvable = new DefaultMessageSourceResolvable(new string[] { "code4", "code3" }); - Assert.AreEqual("message3", ac.GetMessage(resolvable, CultureInfo.CurrentUICulture)); - - object[] arguments = new object[] { "Hello", new DefaultMessageSourceResolvable(new string[] { "code1" }) }; - Assert.AreEqual("Hello, message1", ac.GetMessage("hello", CultureInfo.CurrentUICulture, arguments)); - - - // test default message without and with args - Assert.AreEqual("default", ac.GetMessage(null, "default", CultureInfo.CurrentUICulture, null)); - Assert.AreEqual("default", ac.GetMessage(null, "default", CultureInfo.CurrentUICulture, arguments)); - - /* not supported - Assert.AreEqual("{0}, default", ac.GetMessage(null, "{0}, default", CultureInfo.CurrentUICulture, null)); - */ - - Assert.AreEqual("Hello, default", ac.GetMessage(null, "{0}, default", CultureInfo.CurrentUICulture, arguments)); - - // test resolvable with default message, without and with args - resolvable = new DefaultMessageSourceResolvable(null, null, "default"); - Assert.AreEqual("default", ac.GetMessage(resolvable, CultureInfo.CurrentUICulture)); - resolvable = new DefaultMessageSourceResolvable(null, arguments, "default"); - Assert.AreEqual("default", ac.GetMessage(resolvable, CultureInfo.CurrentUICulture)); - - /* not supported - resolvable = new DefaultMessageSourceResolvable(null, null, "{0}, default"); - Assert.AreEqual("{0}, default", ac.GetMessage(resolvable, CultureInfo.CurrentUICulture)); - */ - - resolvable = new DefaultMessageSourceResolvable(null, arguments, "{0}, default"); - Assert.AreEqual("Hello, default", ac.GetMessage(resolvable, CultureInfo.CurrentUICulture)); - - - // test message args - Assert.AreEqual("Arg1, Arg2", ac.GetMessage("hello", CultureInfo.CurrentUICulture, new object[] { "Arg1", "Arg2" })); - - /* not supported - Assert.AreEqual("{0}, {1}", ac.GetMessage("hello", CultureInfo.CurrentUICulture, null)); - */ - - - /* not supported - Assert.AreEqual("Hello\nWorld", ac.GetMessage("escaped")); - } - else - { - Assert.AreEqual("Hello\\nWorld", ac.GetMessage("escaped")); - } - */ - - - try - { - Assert.AreEqual("MyNonExistantMessage", ac.GetMessage("MyNonExistantMessage")); - if (!useCodeAsDefaultMessage) - { - Assert.Fail("Should have thrown NoSuchMessagException"); - } - } - catch (NoSuchMessageException e) - { - if (useCodeAsDefaultMessage) - { - Assert.Fail("Should have returned code as default message."); - e.ToString(); - } - } - - } - - [Test] - public void SimpleFormat() - { - string msg = String.Format(CultureInfo.CurrentUICulture, "\"Hello World\""); - Assert.AreEqual("\"Hello World\"", msg); - } -#if !MONO - //Spring's CultureTestScope seems incompatible on .NET 1.1 with NUnit's new in 2.5.2 changes for setting UI Culture. - [Test] - [SetUICulture("de-DE")] - public void MessageAccessFallbackTurnedOff() - { - DoTestMessageAccess(false, false); - } - - - [Test] - [SetUICulture("de-DE")] - public void MessageAccessFallbackTurnedOn() - { - DoTestMessageAccess(false, true); - } - - - [Test] - [SetUICulture("de-DE")] - public void MessageAccessWithParentAndFallbackTurnedOff() - { - DoTestMessageAccess(true, false); - } -#endif - - /// - /// Test to string shows expected message with base name listing. - /// - [Test] - public void ResourceSetMessageSourceToString() - { - messageSource.ResourceManagers = resourceManagerList; - Assert.AreEqual("ResourceSetMessageSource with ResourceManagers of base names = [Spring.Resources.Spring.Context.Tests]", - messageSource.ToString(), "ToString not as expected"); - } - - /// - /// Happy day scenario where the requested message key is found and substitutions are made. - /// - [Test] - [SetUICulture("de-DE")] - public void ResourceSetMessageSourceGetMessage() - { - messageSource.ResourceManagers = resourceManagerList; - GetMessageLocalizationFallbacks(messageSource); - } - - private void GetMessageLocalizationFallbacks(IMessageSource msgSource) - { - Assert.AreEqual("Dies ist Spring.NET", - msgSource.GetMessage("MyMessage", new object[] { "Spring", ".NET" }), "message not as expected"); - - Assert.AreEqual("Isso e Spring.NET", - msgSource.GetMessage("MyMessage", new CultureInfo("pt-BR"), new object[] { "Spring", ".NET" }), "message not as expected"); - - Assert.AreEqual("Visual Studio liebt Spring.NET", - msgSource.GetMessage("MyNewMessage", new object[] { "Spring", ".NET" }), "message not as expected"); - - // test localization fallbacks - Assert.AreEqual("Visual Studio loves Spring.NET", - msgSource.GetMessage("MyNewMessage", new CultureInfo("pt-BR"), new object[] { "Spring", ".NET" }), "message not as expected"); - - Assert.AreEqual("Des is Spring.NET", - msgSource.GetMessage("MyMessage", new CultureInfo("de-AT"), new object[] { "Spring", ".NET" }), "message not as expected"); - - Assert.AreEqual("Dies ist Spring.NET", - msgSource.GetMessage("MyMessage", new CultureInfo("de"), new object[] { "Spring", ".NET" }), "message not as expected"); - - Assert.AreEqual("Visual Studio liebt Spring.NET", - msgSource.GetMessage("MyNewMessage", new CultureInfo("de-AT"), new object[] { "Spring", ".NET" }), "message not as expected"); - - // extra tests for the "exotic" serbian culture - if (!SystemUtils.MonoRuntime) - { - - Assert.AreEqual("Ovo je Spring.NET", - msgSource.GetMessage("MyMessage", new CultureInfo(CultureInfoUtils.SerbianLatinCultureName), new object[] { "Spring", ".NET" }), "message not as expected"); - - - Assert.AreEqual("Ово је Spring.NET", - msgSource.GetMessage("MyMessage", new CultureInfo(CultureInfoUtils.SerbianCyrillicCultureName), - new object[] { "Spring", ".NET" }), "message not as expected"); - - Assert.AreEqual("Visual Studio voli Spring.NET", - msgSource.GetMessage("MyNewMessage", new CultureInfo(CultureInfoUtils.SerbianCyrillicCultureName), new object[] { "Spring", ".NET" }), "message not as expected"); - - Assert.AreEqual("First name", - msgSource.GetMessage("field.firstname", new CultureInfo(CultureInfoUtils.SerbianCyrillicCultureName)), "message not as expected"); - } - } - -#if !NETCOREAPP - /// - /// Test the happy day scenario of returning an object - /// - [Test] - public void GetResource() - { - //Add another resource manager to the list - Assembly ass = Assembly.Load("Spring.Core.Tests"); - string baseName = "Spring" + "." + "Resources.Images"; - - resourceManagerList.Add(new ResourceManager(baseName, ass)); - messageSource.ResourceManagers = resourceManagerList; - object obj = messageSource.GetResourceObject("bubblechamber", CultureInfo.CurrentCulture); - Assert.IsNotNull(obj, "expected to retrieve object form resource set"); - System.Drawing.Bitmap bitMap = null; - - //.NET 1.0 returns this as a base64 string while .NET 1.1 returns it as a Bitmap - //There are some isues with resx compatability between framework versions. - if (obj is string) - { - //thanks dotnetdave for the string to bitmap cookbook. - //http://www.vsdntips.com/Tips/VS.NET/Csharp/76.aspx - string ImageText = obj as string; - Byte[] bitmapData = new Byte[ImageText.Length]; - bitmapData = Convert.FromBase64String(FixBase64ForImage(ImageText)); - var streamBitmap = new System.IO.MemoryStream(bitmapData); - bitMap = new System.Drawing.Bitmap((System.Drawing.Bitmap) System.Drawing.Image.FromStream(streamBitmap)); - - } - else - { - bitMap = obj as System.Drawing.Bitmap; - } - Assert.IsNotNull(bitMap, "expected to retrieve BitMap. Instead Type = " + obj.GetType()); - Assert.AreEqual(146, bitMap.Size.Width, "Width of image wrong"); - Assert.AreEqual(119, bitMap.Size.Height, "Height of image wrong"); - - object obj2 = messageSource.GetResourceObject("notExist", CultureInfo.CurrentCulture); - Assert.IsNull(obj2, "non existent resourse found"); - } - - private string FixBase64ForImage(string Image) - { - var sbText = new System.Text.StringBuilder(Image, Image.Length); - sbText.Replace("\r\n", String.Empty); - sbText.Replace(" ", String.Empty); - return sbText.ToString(); - } - - /// - /// Test applying a family of resources to an object. - /// - [Test] - public void ApplyResources() - { - //Add another resource manager to the list - TestObject to = new TestObject(); - var mgr = new System.ComponentModel.ComponentResourceManager(to.GetType()); - resourceManagerList.Add(mgr); - messageSource.ResourceManagers = resourceManagerList; - - messageSource.ApplyResources(to, "testObject", CultureInfo.CurrentCulture); - Assert.AreEqual("Mark", to.Name); - Assert.AreEqual(35, to.Age); - } -#endif - - /// - /// Test when the code being resolves itself implements IMessageResolvable. - /// - [Test] - public void MessageResolveableGetMessage() - { - string[] codes = { "field.firstname" }; - DefaultMessageSourceResolvable dmr = new DefaultMessageSourceResolvable(codes, null); - - messageSource.ResourceManagers = resourceManagerList; - Assert.AreEqual(messageSource.GetMessage("error.required", CultureInfo.CurrentCulture, dmr, "dude!"), "First name is required dude!", "message not as expected"); - } - - /// - /// Get exception when resource doesn't exist. - /// - [Test] - public void ResourceSetMessageSourceGetNonExistantResource() - { - messageSource.ResourceManagers = resourceManagerList; - Assert.Throws(() => messageSource.GetMessage("MyNonExistantMessage", CultureInfo.CurrentCulture, new object[] { "Spring", ".NET" })); - } - - /// - /// Test resource whose value is null. - /// - [Test] - [Ignore("See SPRNET-246")] - public void GetNullResourceIn2PointOh() - { - messageSource.ResourceManagers = resourceManagerList; - object resource = messageSource.GetResourceObject("MyNullMessage", CultureInfo.InvariantCulture); - Assert.AreEqual(String.Empty, resource, "should've returned empty string"); - } - - /// - /// Exercise repeated requests to hit the cache of MessageSets. Note order of test is not assured - /// in NUnit. - /// - [Test] - public void ResourceSetMessageSourceCachedMessage() - { - messageSource.ResourceManagers = resourceManagerList; - Assert.AreEqual("This is Spring.NET", messageSource.GetMessage("MyMessage", CultureInfo.InvariantCulture, new object[] { "Spring", ".NET" }), "message"); - Assert.AreEqual("Visual Studio loves Spring.NET", messageSource.GetMessage("MyNewMessage", CultureInfo.InvariantCulture, "Spring", ".NET"), "message"); - Assert.AreEqual("This is Spring.NET", messageSource.GetMessage("MyMessage", CultureInfo.InvariantCulture, new object[] { "Spring", ".NET" }), "message"); - } - - /// - /// Test when there are two resource managers listed. - /// - [Test] - public void TwoResourceManagers() - { - //Add another resource manager to the list - Assembly ass = Assembly.Load("Spring.Core.Tests"); - string baseName = "Spring" + "." + "Resources.SampleResources"; - resourceManagerList.Add(new ResourceManager(baseName, ass)); - - messageSource.ResourceManagers = resourceManagerList; - - //Repeat the test for the first resource manager - - Assert.AreEqual("This is Spring.NET", - messageSource.GetMessage("MyMessage", new CultureInfo("en"), new object[] { "Spring", ".NET" }), "message not as expected"); - - //Now with the newly added one - Assert.AreEqual("Hello Mr. Anderson", - messageSource.GetMessage("message", - new object[] { "Mr.", "Anderson" }), "message not as expected"); } } + + [Test] + public void SimpleFormat() + { + string msg = String.Format(CultureInfo.CurrentUICulture, "\"Hello World\""); + Assert.AreEqual("\"Hello World\"", msg); + } +#if !MONO + //Spring's CultureTestScope seems incompatible on .NET 1.1 with NUnit's new in 2.5.2 changes for setting UI Culture. + [Test] + [SetUICulture("de-DE")] + public void MessageAccessFallbackTurnedOff() + { + DoTestMessageAccess(false, false); + } + + [Test] + [SetUICulture("de-DE")] + public void MessageAccessFallbackTurnedOn() + { + DoTestMessageAccess(false, true); + } + + [Test] + [SetUICulture("de-DE")] + public void MessageAccessWithParentAndFallbackTurnedOff() + { + DoTestMessageAccess(true, false); + } +#endif + + /// + /// Test to string shows expected message with base name listing. + /// + [Test] + public void ResourceSetMessageSourceToString() + { + messageSource.ResourceManagers = resourceManagerList; + Assert.AreEqual("ResourceSetMessageSource with ResourceManagers of base names = [Spring.Resources.Spring.Context.Tests]", + messageSource.ToString(), "ToString not as expected"); + } + + /// + /// Happy day scenario where the requested message key is found and substitutions are made. + /// + [Test] + [SetUICulture("de-DE")] + public void ResourceSetMessageSourceGetMessage() + { + messageSource.ResourceManagers = resourceManagerList; + GetMessageLocalizationFallbacks(messageSource); + } + + private void GetMessageLocalizationFallbacks(IMessageSource msgSource) + { + Assert.AreEqual("Dies ist Spring.NET", + msgSource.GetMessage("MyMessage", new object[] { "Spring", ".NET" }), "message not as expected"); + + Assert.AreEqual("Isso e Spring.NET", + msgSource.GetMessage("MyMessage", new CultureInfo("pt-BR"), new object[] { "Spring", ".NET" }), "message not as expected"); + + Assert.AreEqual("Visual Studio liebt Spring.NET", + msgSource.GetMessage("MyNewMessage", new object[] { "Spring", ".NET" }), "message not as expected"); + + // test localization fallbacks + Assert.AreEqual("Visual Studio loves Spring.NET", + msgSource.GetMessage("MyNewMessage", new CultureInfo("pt-BR"), new object[] { "Spring", ".NET" }), "message not as expected"); + + Assert.AreEqual("Des is Spring.NET", + msgSource.GetMessage("MyMessage", new CultureInfo("de-AT"), new object[] { "Spring", ".NET" }), "message not as expected"); + + Assert.AreEqual("Dies ist Spring.NET", + msgSource.GetMessage("MyMessage", new CultureInfo("de"), new object[] { "Spring", ".NET" }), "message not as expected"); + + Assert.AreEqual("Visual Studio liebt Spring.NET", + msgSource.GetMessage("MyNewMessage", new CultureInfo("de-AT"), new object[] { "Spring", ".NET" }), "message not as expected"); + + // extra tests for the "exotic" serbian culture + if (!SystemUtils.MonoRuntime) + { + Assert.AreEqual("Ovo je Spring.NET", + msgSource.GetMessage("MyMessage", new CultureInfo(CultureInfoUtils.SerbianLatinCultureName), new object[] { "Spring", ".NET" }), "message not as expected"); + + Assert.AreEqual("Ово је Spring.NET", + msgSource.GetMessage("MyMessage", new CultureInfo(CultureInfoUtils.SerbianCyrillicCultureName), + new object[] { "Spring", ".NET" }), "message not as expected"); + + Assert.AreEqual("Visual Studio voli Spring.NET", + msgSource.GetMessage("MyNewMessage", new CultureInfo(CultureInfoUtils.SerbianCyrillicCultureName), new object[] { "Spring", ".NET" }), "message not as expected"); + + Assert.AreEqual("First name", + msgSource.GetMessage("field.firstname", new CultureInfo(CultureInfoUtils.SerbianCyrillicCultureName)), "message not as expected"); + } + } + +#if !NETCOREAPP + /// + /// Test the happy day scenario of returning an object + /// + [Test] + public void GetResource() + { + //Add another resource manager to the list + Assembly ass = Assembly.Load("Spring.Core.Tests"); + string baseName = "Spring" + "." + "Resources.Images"; + + resourceManagerList.Add(new ResourceManager(baseName, ass)); + messageSource.ResourceManagers = resourceManagerList; + object obj = messageSource.GetResourceObject("bubblechamber", CultureInfo.CurrentCulture); + Assert.IsNotNull(obj, "expected to retrieve object form resource set"); + System.Drawing.Bitmap bitMap = null; + + //.NET 1.0 returns this as a base64 string while .NET 1.1 returns it as a Bitmap + //There are some isues with resx compatability between framework versions. + if (obj is string) + { + //thanks dotnetdave for the string to bitmap cookbook. + //http://www.vsdntips.com/Tips/VS.NET/Csharp/76.aspx + string ImageText = obj as string; + Byte[] bitmapData = new Byte[ImageText.Length]; + bitmapData = Convert.FromBase64String(FixBase64ForImage(ImageText)); + var streamBitmap = new System.IO.MemoryStream(bitmapData); + bitMap = new System.Drawing.Bitmap((System.Drawing.Bitmap) System.Drawing.Image.FromStream(streamBitmap)); + + } + else + { + bitMap = obj as System.Drawing.Bitmap; + } + Assert.IsNotNull(bitMap, "expected to retrieve BitMap. Instead Type = " + obj.GetType()); + Assert.AreEqual(146, bitMap.Size.Width, "Width of image wrong"); + Assert.AreEqual(119, bitMap.Size.Height, "Height of image wrong"); + + object obj2 = messageSource.GetResourceObject("notExist", CultureInfo.CurrentCulture); + Assert.IsNull(obj2, "non existent resourse found"); + } + + private string FixBase64ForImage(string Image) + { + var sbText = new System.Text.StringBuilder(Image, Image.Length); + sbText.Replace("\r\n", String.Empty); + sbText.Replace(" ", String.Empty); + return sbText.ToString(); + } + + /// + /// Test applying a family of resources to an object. + /// + [Test] + public void ApplyResources() + { + //Add another resource manager to the list + TestObject to = new TestObject(); + var mgr = new System.ComponentModel.ComponentResourceManager(to.GetType()); + resourceManagerList.Add(mgr); + messageSource.ResourceManagers = resourceManagerList; + + messageSource.ApplyResources(to, "testObject", CultureInfo.CurrentCulture); + Assert.AreEqual("Mark", to.Name); + Assert.AreEqual(35, to.Age); + } +#endif + + /// + /// Test when the code being resolves itself implements IMessageResolvable. + /// + [Test] + public void MessageResolveableGetMessage() + { + string[] codes = { "field.firstname" }; + DefaultMessageSourceResolvable dmr = new DefaultMessageSourceResolvable(codes, null); + + messageSource.ResourceManagers = resourceManagerList; + Assert.AreEqual(messageSource.GetMessage("error.required", CultureInfo.CurrentCulture, dmr, "dude!"), "First name is required dude!", "message not as expected"); + } + + /// + /// Get exception when resource doesn't exist. + /// + [Test] + public void ResourceSetMessageSourceGetNonExistantResource() + { + messageSource.ResourceManagers = resourceManagerList; + Assert.Throws(() => messageSource.GetMessage("MyNonExistantMessage", CultureInfo.CurrentCulture, new object[] { "Spring", ".NET" })); + } + + /// + /// Test resource whose value is null. + /// + [Test] + [Ignore("See SPRNET-246")] + public void GetNullResourceIn2PointOh() + { + messageSource.ResourceManagers = resourceManagerList; + object resource = messageSource.GetResourceObject("MyNullMessage", CultureInfo.InvariantCulture); + Assert.AreEqual(String.Empty, resource, "should've returned empty string"); + } + + /// + /// Exercise repeated requests to hit the cache of MessageSets. Note order of test is not assured + /// in NUnit. + /// + [Test] + public void ResourceSetMessageSourceCachedMessage() + { + messageSource.ResourceManagers = resourceManagerList; + Assert.AreEqual("This is Spring.NET", messageSource.GetMessage("MyMessage", CultureInfo.InvariantCulture, new object[] { "Spring", ".NET" }), "message"); + Assert.AreEqual("Visual Studio loves Spring.NET", messageSource.GetMessage("MyNewMessage", CultureInfo.InvariantCulture, "Spring", ".NET"), "message"); + Assert.AreEqual("This is Spring.NET", messageSource.GetMessage("MyMessage", CultureInfo.InvariantCulture, new object[] { "Spring", ".NET" }), "message"); + } + + /// + /// Test when there are two resource managers listed. + /// + [Test] + public void TwoResourceManagers() + { + //Add another resource manager to the list + Assembly ass = Assembly.Load("Spring.Core.Tests"); + string baseName = "Spring" + "." + "Resources.SampleResources"; + resourceManagerList.Add(new ResourceManager(baseName, ass)); + + messageSource.ResourceManagers = resourceManagerList; + + //Repeat the test for the first resource manager + + Assert.AreEqual("This is Spring.NET", + messageSource.GetMessage("MyMessage", new CultureInfo("en"), new object[] { "Spring", ".NET" }), "message not as expected"); + + //Now with the newly added one + Assert.AreEqual("Hello Mr. Anderson", + messageSource.GetMessage("message", + new object[] { "Mr.", "Anderson" }), "message not as expected"); + } } diff --git a/test/Spring/Spring.Core.Tests/Context/Support/Service.cs b/test/Spring/Spring.Core.Tests/Context/Support/Service.cs index 7a81ba06..c29b20a0 100644 --- a/test/Spring/Spring.Core.Tests/Context/Support/Service.cs +++ b/test/Spring/Spring.Core.Tests/Context/Support/Service.cs @@ -18,55 +18,53 @@ #endregion -namespace Spring.Context.Support -{ - /// Mark Pollack - public class Service : IApplicationContextAware, IMessageSourceAware, IDisposable +namespace Spring.Context.Support; + +/// Mark Pollack +public class Service : IApplicationContextAware, IMessageSourceAware, IDisposable +{ + private IApplicationContext applicationContext; + private IMessageSource messageSource; + private IResourceLoaderAware[] resources; + private bool properlyDestroyed = false; + + public IApplicationContext ApplicationContext { - private IApplicationContext applicationContext; - private IMessageSource messageSource; - private IResourceLoaderAware[] resources; - private bool properlyDestroyed = false; + get { return applicationContext; } + set { applicationContext = value; } + } - public IApplicationContext ApplicationContext + public IMessageSource MessageSource + { + set { - get { return applicationContext; } - set { applicationContext = value; } - } - - public IMessageSource MessageSource - { - set + if (messageSource != null) { - if (messageSource != null) - { - throw new InvalidOperationException("MessageSource should not be set twice"); - } - messageSource = value; - } - get - { - return messageSource; + throw new InvalidOperationException("MessageSource should not be set twice"); } + messageSource = value; } - - - public IResourceLoaderAware[] Resources + get { - get { return resources; } - set { resources = value; } - } - - public bool ProperlyDestroyed - { - get { return properlyDestroyed; } - } - - public void Dispose() - { - properlyDestroyed = true; - //TODO - try to get object while destroying, expect ObjectCreationNotAllowedException + return messageSource; } } + + public IResourceLoaderAware[] Resources + { + get { return resources; } + set { resources = value; } + } + + public bool ProperlyDestroyed + { + get { return properlyDestroyed; } + } + + public void Dispose() + { + properlyDestroyed = true; + //TODO - try to get object while destroying, expect ObjectCreationNotAllowedException + } } \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/Context/Support/StaticApplicationContextTests.cs b/test/Spring/Spring.Core.Tests/Context/Support/StaticApplicationContextTests.cs index 37bb6c2d..9345ddef 100644 --- a/test/Spring/Spring.Core.Tests/Context/Support/StaticApplicationContextTests.cs +++ b/test/Spring/Spring.Core.Tests/Context/Support/StaticApplicationContextTests.cs @@ -21,29 +21,28 @@ using System.Globalization; using NUnit.Framework; -namespace Spring.Context.Support -{ - [TestFixture] - public class StaticApplicationContextTests - { - [Test] - public void AddMessageTest() - { - StaticApplicationContext ctx = new StaticApplicationContext(); - ctx.Refresh(); - ctx.AddMessage("code1", CultureInfo.CurrentUICulture, "this is {0}"); - Assert.AreEqual("this is Spring.NET", ctx.GetMessage("code1", "Spring.NET")); - } +namespace Spring.Context.Support; - [Test] - public void RegisterObjectPrototype() - { - StaticApplicationContext ctx = new StaticApplicationContext(); - ctx.RegisterPrototype("my object", typeof(MockContextAwareObject), null); - MockContextAwareObject ctx1 = (MockContextAwareObject) ctx.GetObject("my object"); - MockContextAwareObject ctx2 = (MockContextAwareObject) ctx.GetObject("my object"); - Assert.IsTrue(ctx1 != ctx2); - Assert.IsTrue(!ctx.IsSingleton("my object")); - } +[TestFixture] +public class StaticApplicationContextTests +{ + [Test] + public void AddMessageTest() + { + StaticApplicationContext ctx = new StaticApplicationContext(); + ctx.Refresh(); + ctx.AddMessage("code1", CultureInfo.CurrentUICulture, "this is {0}"); + Assert.AreEqual("this is Spring.NET", ctx.GetMessage("code1", "Spring.NET")); } -} \ No newline at end of file + + [Test] + public void RegisterObjectPrototype() + { + StaticApplicationContext ctx = new StaticApplicationContext(); + ctx.RegisterPrototype("my object", typeof(MockContextAwareObject), null); + MockContextAwareObject ctx1 = (MockContextAwareObject) ctx.GetObject("my object"); + MockContextAwareObject ctx2 = (MockContextAwareObject) ctx.GetObject("my object"); + Assert.IsTrue(ctx1 != ctx2); + Assert.IsTrue(!ctx.IsSingleton("my object")); + } +} diff --git a/test/Spring/Spring.Core.Tests/Context/Support/StaticMessageSourceTests.cs b/test/Spring/Spring.Core.Tests/Context/Support/StaticMessageSourceTests.cs index 8c2b5d50..37ba8ca4 100644 --- a/test/Spring/Spring.Core.Tests/Context/Support/StaticMessageSourceTests.cs +++ b/test/Spring/Spring.Core.Tests/Context/Support/StaticMessageSourceTests.cs @@ -23,61 +23,62 @@ using NUnit.Framework; using Spring.Globalization; using Spring.Objects; -namespace Spring.Context.Support +namespace Spring.Context.Support; + +/// +/// Unit tests for the StaticMessageSource class. +/// +[TestFixture] +public sealed class StaticMessageSourceTests { - /// - /// Unit tests for the StaticMessageSource class. - /// - [TestFixture] - public sealed class StaticMessageSourceTests + [OneTimeSetUp] + public void TestFixtureSetUp() { - [OneTimeSetUp] - public void TestFixtureSetUp() - { - CultureTestScope.Set(); - } + CultureTestScope.Set(); + } - [OneTimeTearDown] - public void TestFixtureTearDown() - { - CultureTestScope.Reset(); - } + [OneTimeTearDown] + public void TestFixtureTearDown() + { + CultureTestScope.Reset(); + } - [Test] - [SetUICulture("de-DE")] - public void GetMessageDefaultsToCurrentUICulture() - { - StaticMessageSource msgSource = new StaticMessageSource(); - msgSource.AddMessage("code", CultureInfo.CurrentUICulture, "{0}"); - Assert.AreEqual("my message", msgSource.GetMessage("code", "my message"), "message"); + [Test] + [SetUICulture("de-DE")] + public void GetMessageDefaultsToCurrentUICulture() + { + StaticMessageSource msgSource = new StaticMessageSource(); + msgSource.AddMessage("code", CultureInfo.CurrentUICulture, "{0}"); + Assert.AreEqual("my message", msgSource.GetMessage("code", "my message"), "message"); - try - { - msgSource.GetMessage("code", CultureInfo.CurrentCulture); - Assert.Fail("message"); - } - catch(NoSuchMessageException) - {} - } - - [Test] - public void GetMessageCode() + try { - StaticMessageSource msgSource = new StaticMessageSource(); - msgSource.AddMessage("code", CultureInfo.CurrentUICulture, "{0} {1}"); - Assert.AreEqual("my message", - msgSource.GetMessage("code", CultureInfo.CurrentUICulture, new object[] {"my", "message"}), - "message"); + msgSource.GetMessage("code", CultureInfo.CurrentCulture); + Assert.Fail("message"); } - - [Test] - public void StaticMessageSourceToString() + catch (NoSuchMessageException) { - StaticMessageSource msgSource = new StaticMessageSource(); - msgSource.AddMessage("code1", CultureInfo.CurrentUICulture, "{0} {1}"); - Assert.AreEqual("StaticMessageSource : ['code1_" + CultureInfo.CurrentUICulture.Name + "' : '{0} {1}']", - msgSource.ToString()); } + } + + [Test] + public void GetMessageCode() + { + StaticMessageSource msgSource = new StaticMessageSource(); + msgSource.AddMessage("code", CultureInfo.CurrentUICulture, "{0} {1}"); + Assert.AreEqual("my message", + msgSource.GetMessage("code", CultureInfo.CurrentUICulture, new object[] { "my", "message" }), + "message"); + } + + [Test] + public void StaticMessageSourceToString() + { + StaticMessageSource msgSource = new StaticMessageSource(); + msgSource.AddMessage("code1", CultureInfo.CurrentUICulture, "{0} {1}"); + Assert.AreEqual("StaticMessageSource : ['code1_" + CultureInfo.CurrentUICulture.Name + "' : '{0} {1}']", + msgSource.ToString()); + } #if !NETCOREAPP [Test] @@ -91,92 +92,93 @@ namespace Spring.Context.Support } #endif - [Test] - public void ApplyResourcesWithNullObject() - { - TestObject value = new TestObject(); - StaticMessageSource msgSource = new StaticMessageSource(); - msgSource.ApplyResources(null, "testObject", CultureInfo.InvariantCulture); - Assert.AreEqual(null, value.Name); - Assert.AreEqual(0, value.Age); - } - - [Test] - public void ApplyResourcesWithNullLookupKey() - { - TestObject value = new TestObject(); - StaticMessageSource msgSource = new StaticMessageSource(); - - try - { - msgSource.ApplyResources(value, null, CultureInfo.InvariantCulture); - Assert.Fail("ArgumentNullException was expected"); - } catch (ArgumentNullException e) - { - Assert.IsNotNull(e); - } - Assert.AreEqual(null, value.Name); - Assert.AreEqual(0, value.Age); - } - - [Test] - public void GetResourceObjectWithCodeAndCulture() - { - TestObject value = new TestObject("Rick", 30); - StaticMessageSource msgSource = new StaticMessageSource(); - msgSource.AddObject("rick", CultureInfo.InstalledUICulture, value); - - TestObject retrieved = (TestObject) - msgSource.GetResourceObject("rick", CultureInfo.InstalledUICulture); - Assert.IsNotNull(retrieved, - "Object previously added to StaticMessageSource was not retrieved " + - "when using same lookup code and CultureInfo."); - Assert.IsTrue(ReferenceEquals(value, retrieved), - "Object returned from StaticMessageSource was not the same one " + - "that was previously added (it must be)."); - } - - [Test] - public void GetResourceObjectWithCode() - { - TestObject value = new TestObject("Rick", 30); - StaticMessageSource msgSource = new StaticMessageSource(); - msgSource.AddObject("rick", CultureInfo.CurrentUICulture, value); - - TestObject retrieved = (TestObject) - msgSource.GetResourceObject("rick"); - Assert.IsNotNull(retrieved, - "Object previously added to StaticMessageSource was not retrieved " + - "when using same lookup code."); - Assert.IsTrue(ReferenceEquals(value, retrieved), - "Object returned from StaticMessageSource was not the same one " + - "that was previously added (it must be)."); - } - - [Test] - public void GetResourceObjectThatAintPreviouslyBeenAddedDoesntYieldAnything() - { - StaticMessageSource msgSource = new StaticMessageSource(); - TestObject retrieved = (TestObject) - msgSource.GetResourceObject("rick"); - Assert.IsNull(retrieved, - "Getting 'some (?) weird object out of an empty StaticMessageSource"); - } - - [Test] - public void GetResourceObjectWithCodeAssumesCurrentUICulture() - { - TestObject value = new TestObject("Rick", 30); - StaticMessageSource msgSource = new StaticMessageSource(); - msgSource.AddObject("rick", CultureInfo.InvariantCulture, value); - - // assumes object was previously added using CultureInfo.CurrentUICulture - TestObject retrieved = (TestObject) - msgSource.GetResourceObject("rick"); - Assert.IsNull(retrieved, - "Object previously added to StaticMessageSource " + - "(using CultureInfo.InvariantCulture) was (wrongly) retrieved " + - "when using same lookup code."); - } + [Test] + public void ApplyResourcesWithNullObject() + { + TestObject value = new TestObject(); + StaticMessageSource msgSource = new StaticMessageSource(); + msgSource.ApplyResources(null, "testObject", CultureInfo.InvariantCulture); + Assert.AreEqual(null, value.Name); + Assert.AreEqual(0, value.Age); } -} \ No newline at end of file + + [Test] + public void ApplyResourcesWithNullLookupKey() + { + TestObject value = new TestObject(); + StaticMessageSource msgSource = new StaticMessageSource(); + + try + { + msgSource.ApplyResources(value, null, CultureInfo.InvariantCulture); + Assert.Fail("ArgumentNullException was expected"); + } + catch (ArgumentNullException e) + { + Assert.IsNotNull(e); + } + + Assert.AreEqual(null, value.Name); + Assert.AreEqual(0, value.Age); + } + + [Test] + public void GetResourceObjectWithCodeAndCulture() + { + TestObject value = new TestObject("Rick", 30); + StaticMessageSource msgSource = new StaticMessageSource(); + msgSource.AddObject("rick", CultureInfo.InstalledUICulture, value); + + TestObject retrieved = (TestObject) + msgSource.GetResourceObject("rick", CultureInfo.InstalledUICulture); + Assert.IsNotNull(retrieved, + "Object previously added to StaticMessageSource was not retrieved " + + "when using same lookup code and CultureInfo."); + Assert.IsTrue(ReferenceEquals(value, retrieved), + "Object returned from StaticMessageSource was not the same one " + + "that was previously added (it must be)."); + } + + [Test] + public void GetResourceObjectWithCode() + { + TestObject value = new TestObject("Rick", 30); + StaticMessageSource msgSource = new StaticMessageSource(); + msgSource.AddObject("rick", CultureInfo.CurrentUICulture, value); + + TestObject retrieved = (TestObject) + msgSource.GetResourceObject("rick"); + Assert.IsNotNull(retrieved, + "Object previously added to StaticMessageSource was not retrieved " + + "when using same lookup code."); + Assert.IsTrue(ReferenceEquals(value, retrieved), + "Object returned from StaticMessageSource was not the same one " + + "that was previously added (it must be)."); + } + + [Test] + public void GetResourceObjectThatAintPreviouslyBeenAddedDoesntYieldAnything() + { + StaticMessageSource msgSource = new StaticMessageSource(); + TestObject retrieved = (TestObject) + msgSource.GetResourceObject("rick"); + Assert.IsNull(retrieved, + "Getting 'some (?) weird object out of an empty StaticMessageSource"); + } + + [Test] + public void GetResourceObjectWithCodeAssumesCurrentUICulture() + { + TestObject value = new TestObject("Rick", 30); + StaticMessageSource msgSource = new StaticMessageSource(); + msgSource.AddObject("rick", CultureInfo.InvariantCulture, value); + + // assumes object was previously added using CultureInfo.CurrentUICulture + TestObject retrieved = (TestObject) + msgSource.GetResourceObject("rick"); + Assert.IsNull(retrieved, + "Object previously added to StaticMessageSource " + + "(using CultureInfo.InvariantCulture) was (wrongly) retrieved " + + "when using same lookup code."); + } +} diff --git a/test/Spring/Spring.Core.Tests/Context/Support/TestObjectConfigParser.cs b/test/Spring/Spring.Core.Tests/Context/Support/TestObjectConfigParser.cs index 96e9d43f..a67e9c72 100644 --- a/test/Spring/Spring.Core.Tests/Context/Support/TestObjectConfigParser.cs +++ b/test/Spring/Spring.Core.Tests/Context/Support/TestObjectConfigParser.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -24,77 +24,74 @@ using Spring.Objects.Factory.Config; using Spring.Objects.Factory.Support; using Spring.Objects.Factory.Xml; -namespace Spring.Context.Support +namespace Spring.Context.Support; + +/// +/// A simple parser to create TestObjects. +/// +public class TestObjectConfigParser : ObjectsNamespaceParser { /// - /// A simple parser to create TestObjects. + /// Has the method been called? /// - public class TestObjectConfigParser : ObjectsNamespaceParser + public static bool ParseElementCalled = false; + + /// + /// Create an instance of the parser + /// + public TestObjectConfigParser() { - /// - /// Has the method been called? - /// - public static bool ParseElementCalled = false; - - /// - /// Create an instance of the parser - /// - public TestObjectConfigParser() - { - } - - /// - /// Parse the specified element and register any resulting - /// IObjectDefinitions with the IObjectDefinitionRegistry that is - /// embedded in the supplied ParserContext. - /// - /// The element to be parsed into one or more IObjectDefinitions - /// The object encapsulating the current state of the parsing - /// process. - /// - /// The primary IObjectDefinition (can be null as explained above) - /// - /// - /// Implementations should return the primary IObjectDefinition - /// that results from the parse phase if they wish to used nested - /// inside (for example) a <property> tag. - /// Implementations may return null if they will not - /// be used in a nested scenario. - /// - /// - public override IObjectDefinition ParseElement(XmlElement element, ParserContext parserContext) - { - ParseElementCalled = true; - ObjectDefinitionHolder holder = ParseTestObjectDefinition(element, parserContext); - ObjectDefinitionReaderUtils.RegisterObjectDefinition(holder, parserContext.Registry); - return null; - } - - - private ObjectDefinitionHolder ParseTestObjectDefinition(XmlElement rootElement, ParserContext parserContext) - { - MutablePropertyValues properties = new MutablePropertyValues(); - - XmlNodeList childNodes = rootElement.ChildNodes; - - //Get all properties (from non whitespace nodes) - foreach (XmlNode childNode in childNodes) - { - if (XmlNodeType.Whitespace != childNode.NodeType) - { - properties.Add(new PropertyValue(childNode.LocalName, childNode.InnerText)); - } - } - IConfigurableObjectDefinition od = new RootObjectDefinition(typeof (TestObject), null, properties); - od.IsSingleton = false; - - //HardCoded for now. - string id = "testObject"; - //id = ObjectDefinitionReaderUtils.GenerateObjectName(od, reader.ObjectReader.Registry); - - return new ObjectDefinitionHolder(od, id); - - - } } -} \ No newline at end of file + + /// + /// Parse the specified element and register any resulting + /// IObjectDefinitions with the IObjectDefinitionRegistry that is + /// embedded in the supplied ParserContext. + /// + /// The element to be parsed into one or more IObjectDefinitions + /// The object encapsulating the current state of the parsing + /// process. + /// + /// The primary IObjectDefinition (can be null as explained above) + /// + /// + /// Implementations should return the primary IObjectDefinition + /// that results from the parse phase if they wish to used nested + /// inside (for example) a <property> tag. + /// Implementations may return null if they will not + /// be used in a nested scenario. + /// + /// + public override IObjectDefinition ParseElement(XmlElement element, ParserContext parserContext) + { + ParseElementCalled = true; + ObjectDefinitionHolder holder = ParseTestObjectDefinition(element, parserContext); + ObjectDefinitionReaderUtils.RegisterObjectDefinition(holder, parserContext.Registry); + return null; + } + + private ObjectDefinitionHolder ParseTestObjectDefinition(XmlElement rootElement, ParserContext parserContext) + { + MutablePropertyValues properties = new MutablePropertyValues(); + + XmlNodeList childNodes = rootElement.ChildNodes; + + //Get all properties (from non whitespace nodes) + foreach (XmlNode childNode in childNodes) + { + if (XmlNodeType.Whitespace != childNode.NodeType) + { + properties.Add(new PropertyValue(childNode.LocalName, childNode.InnerText)); + } + } + + IConfigurableObjectDefinition od = new RootObjectDefinition(typeof(TestObject), null, properties); + od.IsSingleton = false; + + //HardCoded for now. + string id = "testObject"; + //id = ObjectDefinitionReaderUtils.GenerateObjectName(od, reader.ObjectReader.Registry); + + return new ObjectDefinitionHolder(od, id); + } +} diff --git a/test/Spring/Spring.Core.Tests/Context/Support/TypeAliasesSectionHandlerTests.cs b/test/Spring/Spring.Core.Tests/Context/Support/TypeAliasesSectionHandlerTests.cs index c757fd9d..cedaf0bd 100644 --- a/test/Spring/Spring.Core.Tests/Context/Support/TypeAliasesSectionHandlerTests.cs +++ b/test/Spring/Spring.Core.Tests/Context/Support/TypeAliasesSectionHandlerTests.cs @@ -28,135 +28,135 @@ using Spring.Objects; #endregion -namespace Spring.Context.Support +namespace Spring.Context.Support; + +/// +/// Unit tests for the TypeAliasesSectionHandler class. +/// +[TestFixture] +public sealed class TypeAliasesSectionHandlerTests { - /// - /// Unit tests for the TypeAliasesSectionHandler class. - /// - [TestFixture] - public sealed class TypeAliasesSectionHandlerTests - { - [Test] - public void ParseSectionSunnyDay() - { - const string xml = @" + [Test] + public void ParseSectionSunnyDay() + { + const string xml = @" "; - Assert.IsNull(TypeRegistry.ResolveType("fiona.apple"), "TypeRegistry already contains an alias for the type being tested (it must not)."); + Assert.IsNull(TypeRegistry.ResolveType("fiona.apple"), "TypeRegistry already contains an alias for the type being tested (it must not)."); - TypeAliasesSectionHandler handler = new TypeAliasesSectionHandler(); - handler.Create(null, null, BuildConfigurationSection(xml)); + TypeAliasesSectionHandler handler = new TypeAliasesSectionHandler(); + handler.Create(null, null, BuildConfigurationSection(xml)); - Type type = TypeRegistry.ResolveType("fiona.apple"); - Assert.AreEqual(typeof (TestObject), type, "The type alias was not registered by the TypeAliasesSectionHandler."); - } + Type type = TypeRegistry.ResolveType("fiona.apple"); + Assert.AreEqual(typeof(TestObject), type, "The type alias was not registered by the TypeAliasesSectionHandler."); + } - [Test] - public void WithGenericType() - { - const string xml = @" + [Test] + public void WithGenericType() + { + const string xml = @" "; - TypeAliasesSectionHandler handler = new TypeAliasesSectionHandler(); - handler.Create(null, null, BuildConfigurationSection(xml)); - } + TypeAliasesSectionHandler handler = new TypeAliasesSectionHandler(); + handler.Create(null, null, BuildConfigurationSection(xml)); + } - [Test] - public void WithGenericTypeDefinition() - { - const string xml = @" + [Test] + public void WithGenericTypeDefinition() + { + const string xml = @" "; - TypeAliasesSectionHandler handler = new TypeAliasesSectionHandler(); - handler.Create(null, null, BuildConfigurationSection(xml)); - } + TypeAliasesSectionHandler handler = new TypeAliasesSectionHandler(); + handler.Create(null, null, BuildConfigurationSection(xml)); + } - [Test] - public void WithNonExistentType() - { - const string xml = @" + [Test] + public void WithNonExistentType() + { + const string xml = @" "; - TypeAliasesSectionHandler handler = new TypeAliasesSectionHandler(); - Assert.Throws(() => handler.Create(null, null, BuildConfigurationSection(xml))); - } + TypeAliasesSectionHandler handler = new TypeAliasesSectionHandler(); + Assert.Throws(() => handler.Create(null, null, BuildConfigurationSection(xml))); + } - [Test] - public void WithEmptyTypeName() - { - const string xml = @" + [Test] + public void WithEmptyTypeName() + { + const string xml = @" "; - TypeAliasesSectionHandler handler = new TypeAliasesSectionHandler(); - Assert.Throws(() => handler.Create(null, null, BuildConfigurationSection(xml))); - } + TypeAliasesSectionHandler handler = new TypeAliasesSectionHandler(); + Assert.Throws(() => handler.Create(null, null, BuildConfigurationSection(xml))); + } - [Test] - public void WithWhitespacedTypeName() - { - const string xml = @" + [Test] + public void WithWhitespacedTypeName() + { + const string xml = @" "; - TypeAliasesSectionHandler handler = new TypeAliasesSectionHandler(); - Assert.Throws(() => handler.Create(null, null, BuildConfigurationSection(xml))); - } + TypeAliasesSectionHandler handler = new TypeAliasesSectionHandler(); + Assert.Throws(() => handler.Create(null, null, BuildConfigurationSection(xml))); + } - [Test] - public void WithEmptyAlias() - { - const string xml = @" + [Test] + public void WithEmptyAlias() + { + const string xml = @" "; - TypeAliasesSectionHandler handler = new TypeAliasesSectionHandler(); - Assert.Throws(() => handler.Create(null, null, BuildConfigurationSection(xml))); - } + TypeAliasesSectionHandler handler = new TypeAliasesSectionHandler(); + Assert.Throws(() => handler.Create(null, null, BuildConfigurationSection(xml))); + } - [Test] - public void WithWhitespacedAlias() - { - const string xml = @" + [Test] + public void WithWhitespacedAlias() + { + const string xml = @" "; - TypeAliasesSectionHandler handler = new TypeAliasesSectionHandler(); - Assert.Throws(() => handler.Create(null, null, BuildConfigurationSection(xml))); - } + TypeAliasesSectionHandler handler = new TypeAliasesSectionHandler(); + Assert.Throws(() => handler.Create(null, null, BuildConfigurationSection(xml))); + } - [Test] - public void ParseSectionWithNoChildParserNamespaceElements() - { - const string xml = @" + [Test] + public void ParseSectionWithNoChildParserNamespaceElements() + { + const string xml = @" "; - TypeAliasesSectionHandler handler = new TypeAliasesSectionHandler(); - handler.Create(null, null, BuildConfigurationSection(xml)); - } + TypeAliasesSectionHandler handler = new TypeAliasesSectionHandler(); + handler.Create(null, null, BuildConfigurationSection(xml)); + } - [Test] - public void ParseSectionWithGuffChildParserNamespaceElementsIsAllowed() - { - const string xml = @" + [Test] + public void ParseSectionWithGuffChildParserNamespaceElementsIsAllowed() + { + const string xml = @" @@ -165,39 +165,38 @@ namespace Spring.Context.Support "; - TypeAliasesSectionHandler handler = new TypeAliasesSectionHandler(); - handler.Create(null, null, BuildConfigurationSection(xml)); - } + TypeAliasesSectionHandler handler = new TypeAliasesSectionHandler(); + handler.Create(null, null, BuildConfigurationSection(xml)); + } - [Test] - public void WithAliasElementThatIsMissingTheNameAttribute() - { - const string xml = @" + [Test] + public void WithAliasElementThatIsMissingTheNameAttribute() + { + const string xml = @" "; - TypeAliasesSectionHandler handler = new TypeAliasesSectionHandler(); - Assert.Throws(() => handler.Create(null, null, BuildConfigurationSection(xml))); - } + TypeAliasesSectionHandler handler = new TypeAliasesSectionHandler(); + Assert.Throws(() => handler.Create(null, null, BuildConfigurationSection(xml))); + } - [Test] - public void WithAliasElementThatIsMissingTheTypeAttribute() - { - const string xml = @" + [Test] + public void WithAliasElementThatIsMissingTheTypeAttribute() + { + const string xml = @" "; - TypeAliasesSectionHandler handler = new TypeAliasesSectionHandler(); - Assert.Throws(() => handler.Create(null, null, BuildConfigurationSection(xml))); - } + TypeAliasesSectionHandler handler = new TypeAliasesSectionHandler(); + Assert.Throws(() => handler.Create(null, null, BuildConfigurationSection(xml))); + } - private static XmlNode BuildConfigurationSection(string xml) - { - XmlDocument doc = new XmlDocument(); - doc.LoadXml(xml); - return doc.DocumentElement; - } - } -} \ No newline at end of file + private static XmlNode BuildConfigurationSection(string xml) + { + XmlDocument doc = new XmlDocument(); + doc.LoadXml(xml); + return doc.DocumentElement; + } +} diff --git a/test/Spring/Spring.Core.Tests/Context/Support/XmlApplicationContentArgsTests.cs b/test/Spring/Spring.Core.Tests/Context/Support/XmlApplicationContentArgsTests.cs index 13ef0b2d..fd29c9a3 100644 --- a/test/Spring/Spring.Core.Tests/Context/Support/XmlApplicationContentArgsTests.cs +++ b/test/Spring/Spring.Core.Tests/Context/Support/XmlApplicationContentArgsTests.cs @@ -1,22 +1,21 @@ using NUnit.Framework; -namespace Spring.Context.Support -{ - [TestFixture] - public class XmlApplicationContentArgsTests - { - [Test] - public void Default_CaseSensitivity_isTrue() - { - XmlApplicationContextArgs args = new XmlApplicationContextArgs(string.Empty,null,null,null); - Assert.True(args.CaseSensitive); - } +namespace Spring.Context.Support; - [Test] - public void Default_AutoRefresh_isTrue() - { - XmlApplicationContextArgs args = new XmlApplicationContextArgs(string.Empty, null, null, null); - Assert.True(args.Refresh); - } +[TestFixture] +public class XmlApplicationContentArgsTests +{ + [Test] + public void Default_CaseSensitivity_isTrue() + { + XmlApplicationContextArgs args = new XmlApplicationContextArgs(string.Empty, null, null, null); + Assert.True(args.CaseSensitive); + } + + [Test] + public void Default_AutoRefresh_isTrue() + { + XmlApplicationContextArgs args = new XmlApplicationContextArgs(string.Empty, null, null, null); + Assert.True(args.Refresh); } } diff --git a/test/Spring/Spring.Core.Tests/Context/Support/XmlApplicationContextTests-SPRNET1231.xml b/test/Spring/Spring.Core.Tests/Context/Support/XmlApplicationContextTests-SPRNET1231.xml index b440a927..005dd33b 100644 --- a/test/Spring/Spring.Core.Tests/Context/Support/XmlApplicationContextTests-SPRNET1231.xml +++ b/test/Spring/Spring.Core.Tests/Context/Support/XmlApplicationContextTests-SPRNET1231.xml @@ -1,10 +1,11 @@  - + + + + + - - - - \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/Context/Support/XmlApplicationContextTests.cs b/test/Spring/Spring.Core.Tests/Context/Support/XmlApplicationContextTests.cs index 586f01fe..d2fe6c31 100644 --- a/test/Spring/Spring.Core.Tests/Context/Support/XmlApplicationContextTests.cs +++ b/test/Spring/Spring.Core.Tests/Context/Support/XmlApplicationContextTests.cs @@ -25,419 +25,417 @@ using Spring.Objects.Factory; using Spring.Objects.Factory.Config; using Spring.Objects.Factory.Xml; -namespace Spring.Context.Support +namespace Spring.Context.Support; + +/// +/// Test creation of application context from XML. +/// +/// Mark Pollack +[TestFixture] +public sealed class XmlApplicationContextTests { - /// - /// Test creation of application context from XML. - /// - /// Mark Pollack - [TestFixture] - public sealed class XmlApplicationContextTests + [Test(Description = "http://jira.springframework.org/browse/SPRNET-1231")] + public void SPRNET1231_DoesNotInvokeFactoryMethodDuringObjectFactoryPostProcessing() { - [Test(Description = "http://jira.springframework.org/browse/SPRNET-1231")] - public void SPRNET1231_DoesNotInvokeFactoryMethodDuringObjectFactoryPostProcessing() + string configLocation = TestResourceLoader.GetAssemblyResourceUri(this.GetType(), "XmlApplicationContextTests-SPRNET1231.xml"); + XmlApplicationContext ctx = new XmlApplicationContext(configLocation); + } + + private class SPRNET1231ObjectFactoryPostProcessor : IObjectFactoryPostProcessor + { + public void PostProcessObjectFactory(IConfigurableListableObjectFactory factory) { - string configLocation = TestResourceLoader.GetAssemblyResourceUri(this.GetType(), "XmlApplicationContextTests-SPRNET1231.xml"); - XmlApplicationContext ctx = new XmlApplicationContext(configLocation); - + SPRNET1231FactoryObject testFactory = (SPRNET1231FactoryObject) factory.GetObject("testFactory"); + Assert.AreEqual(0, testFactory.count); } + } - private class SPRNET1231ObjectFactoryPostProcessor : IObjectFactoryPostProcessor + private class SPRNET1231FactoryObject + { + public int count; + + public ITestObject GetProduct() { - public void PostProcessObjectFactory(IConfigurableListableObjectFactory factory) - { - SPRNET1231FactoryObject testFactory = (SPRNET1231FactoryObject)factory.GetObject("testFactory"); - Assert.AreEqual(0, testFactory.count); - } + count++; + return new TestObject("test" + count, count); } + } - private class SPRNET1231FactoryObject + [Test] + public void InnerObjectWithPostProcessing() + { + try { - public int count; - - public ITestObject GetProduct() - { - count++; - return new TestObject("test" + count, count); - } + XmlApplicationContext ctx = new XmlApplicationContext(false, "assembly://Spring.Core.Tests/Spring.Context.Support/innerObjectsWithPostProcessor.xml"); + ctx.GetObject("hasInnerObjects"); + Assert.Fail("should throw ObjectCreationException"); } - - - [Test] - public void InnerObjectWithPostProcessing() + catch (ObjectCreationException e) { - try - { - XmlApplicationContext ctx = new XmlApplicationContext(false, "assembly://Spring.Core.Tests/Spring.Context.Support/innerObjectsWithPostProcessor.xml"); - ctx.GetObject("hasInnerObjects"); - Assert.Fail("should throw ObjectCreationException"); - } - catch (ObjectCreationException e) - { - NoSuchObjectDefinitionException ex = e.InnerException as NoSuchObjectDefinitionException; - Assert.IsNotNull(ex); - //Pass - } + NoSuchObjectDefinitionException ex = e.InnerException as NoSuchObjectDefinitionException; + Assert.IsNotNull(ex); + //Pass } + } - [Test] - public void NoConfigLocation() - { - Assert.Throws(() => new XmlApplicationContext()); - } + [Test] + public void NoConfigLocation() + { + Assert.Throws(() => new XmlApplicationContext()); + } - [Test] - public void SingleConfigLocation() - { - XmlApplicationContext ctx = - new XmlApplicationContext(false, "assembly://Spring.Core.Tests/Spring.Context.Support/simpleContext.xml"); - Assert.IsTrue(ctx.ContainsObject("someMessageSource")); - ctx.Dispose(); - } + [Test] + public void SingleConfigLocation() + { + XmlApplicationContext ctx = + new XmlApplicationContext(false, "assembly://Spring.Core.Tests/Spring.Context.Support/simpleContext.xml"); + Assert.IsTrue(ctx.ContainsObject("someMessageSource")); + ctx.Dispose(); + } - [Test] - public void MultipleConfigLocations() - { - XmlApplicationContext ctx = - new XmlApplicationContext(false, "assembly://Spring.Core.Tests/Spring.Context.Support/contextB.xml", - "assembly://Spring.Core.Tests/Spring.Context.Support/contextC.xml", - "assembly://Spring.Core.Tests/Spring.Context.Support/contextA.xml"); - Assert.IsTrue(ctx.ContainsObject("service")); - Assert.IsTrue(ctx.ContainsObject("logicOne")); - Assert.IsTrue(ctx.ContainsObject("logicTwo")); - Service service = (Service) ctx.GetObject("service"); - ctx.Refresh(); - Assert.IsTrue(service.ProperlyDestroyed); - service = (Service) ctx.GetObject("service"); - ctx.Dispose(); - Assert.IsTrue(service.ProperlyDestroyed); - } + [Test] + public void MultipleConfigLocations() + { + XmlApplicationContext ctx = + new XmlApplicationContext(false, "assembly://Spring.Core.Tests/Spring.Context.Support/contextB.xml", + "assembly://Spring.Core.Tests/Spring.Context.Support/contextC.xml", + "assembly://Spring.Core.Tests/Spring.Context.Support/contextA.xml"); + Assert.IsTrue(ctx.ContainsObject("service")); + Assert.IsTrue(ctx.ContainsObject("logicOne")); + Assert.IsTrue(ctx.ContainsObject("logicTwo")); + Service service = (Service) ctx.GetObject("service"); + ctx.Refresh(); + Assert.IsTrue(service.ProperlyDestroyed); + service = (Service) ctx.GetObject("service"); + ctx.Dispose(); + Assert.IsTrue(service.ProperlyDestroyed); + } - [Test] - public void ContextWithInvalidValueType() - { - try - { - XmlApplicationContext ctx = - new XmlApplicationContext(false, - "assembly://Spring.Core.Tests/Spring.Context.Support/invalidValueType.xml"); - Assert.Fail("Should have thrown ObjectCreationException for context", ctx); - } - catch (ObjectCreationException ex) - { - Assert.IsTrue(ex.Message.IndexOf((typeof (TypeMismatchException).Name)) != -1); - Assert.IsTrue(ex.Message.IndexOf(("UseCodeAsDefaultMessage")) != -1); - } - } - - [Test] - [Ignore("Need to add Spring.TypeLoadException")] - public void ContextWithInvalidLazyType() + [Test] + public void ContextWithInvalidValueType() + { + try { XmlApplicationContext ctx = new XmlApplicationContext(false, - "assembly://Spring.Core.Tests/Spring.Context.Support/invalidType.xml"); - Assert.IsTrue(ctx.ContainsObject("someMessageSource")); - ctx.GetObject("someMessageSource"); + "assembly://Spring.Core.Tests/Spring.Context.Support/invalidValueType.xml"); + Assert.Fail("Should have thrown ObjectCreationException for context", ctx); } - - [Test] - public void CaseInsensitiveContext() + catch (ObjectCreationException ex) { - XmlApplicationContext ctx = - new XmlApplicationContext(false, "assembly://Spring.Core.Tests/Spring.Context.Support/objects.xml"); - Assert.IsTrue(ctx.ContainsObject("goran")); - Assert.IsTrue(ctx.ContainsObject("Goran")); - Assert.IsTrue(ctx.ContainsObject("GORAN")); - Assert.AreEqual(ctx.GetObject("goran"), ctx.GetObject("GORAN")); + Assert.IsTrue(ex.Message.IndexOf((typeof(TypeMismatchException).Name)) != -1); + Assert.IsTrue(ex.Message.IndexOf(("UseCodeAsDefaultMessage")) != -1); } - - [Test] - public void GetObjectOnUnknownIdThrowsNoSuchObjectDefinition() - { - XmlApplicationContext ctx = - new XmlApplicationContext(false, "assembly://Spring.Core.Tests/Spring.Context.Support/objects.xml"); - string DOES_NOT_EXIST = "does_not_exist"; - Assert.IsFalse(ctx.ContainsObject(DOES_NOT_EXIST)); - Assert.Throws(() => ctx.GetObject(DOES_NOT_EXIST)); - } - - [Test] - public void FactoryObjectsAreNotInstantiatedBeforeObjectFactoryPostProcessorsAreApplied() - { - XmlApplicationContext ctx = new XmlApplicationContext("Spring/Context/Support/SPRNET-192.xml"); - LogFactoryObject logFactory = (LogFactoryObject) ctx["&log"]; - Assert.AreEqual("foo", logFactory.LogName); - } - - /// - /// Make sure that if an IObjectPostProcessor is defined as abstract - /// the creation of an IApplicationContext will not try to instantiate it. - /// - [Test] - public void ContextWithPostProcessors() - { - CountingObjectPostProcessor.Count = 0; - CoutingObjectFactoryPostProcessor.Count = 0; - - IApplicationContext ctx = - new XmlApplicationContext("assembly://Spring.Core.Tests/Spring.Context.Support/objects.xml"); - - Assert.IsTrue(ctx.ContainsObject("abstractObjectProcessorPrototype")); - Assert.IsTrue(ctx.ContainsObject("abstractFactoryProcessorPrototype")); - - Assert.AreEqual(0, CountingObjectPostProcessor.Count); - Assert.AreEqual(0, CoutingObjectFactoryPostProcessor.Count); - } - - /// - /// Make sure that ConfigureObject() completly configures target - /// object (goes through whole lifecycle of object creation and - /// applies all processors). - /// - [Test] - public void ConfigureObject() - { - const string objDefLocation = "assembly://Spring.Core.Tests/Spring.Context.Support/objects.xml"; - - XmlApplicationContext xmlContext = new XmlApplicationContext(new string[] {objDefLocation}); - - object objGoran = xmlContext.GetObject("goran"); - Assert.IsTrue(objGoran is TestObject); - TestObject fooGet = objGoran as TestObject; - - TestObject fooConfigure = new TestObject(); - xmlContext.ConfigureObject(fooConfigure, "goran"); - Assert.IsNotNull(fooGet); - Assert.AreEqual(fooGet.Name, fooConfigure.Name); - Assert.AreEqual(fooGet.Age, fooConfigure.Age); - Assert.AreEqual(fooGet.ObjectName, fooConfigure.ObjectName); - Assert.IsNotNull(fooGet.ObjectName); - Assert.AreEqual(xmlContext, fooGet.ApplicationContext); - Assert.AreEqual(xmlContext, fooConfigure.ApplicationContext); - } - - - [Test] - public void ContextLifeCycle() - { - IApplicationContext ctx = - new XmlApplicationContext("assembly://Spring.Core.Tests/Spring.Context/contextlifecycle.xml"); - IConfigurableApplicationContext configCtx = ctx as IConfigurableApplicationContext; - Assert.IsNotNull(configCtx); - ContextListenerObject clo; - using (configCtx) - { - clo = configCtx["contextListenerObject"] as ContextListenerObject; - Assert.IsNotNull(clo); - Assert.IsTrue(clo.AppListenerContextRefreshed, - "Object did not receive context refreshed event via IApplicationListener"); - Assert.IsTrue(clo.CtxRefreshed, "Object did not receive context refreshed event via direct wiring"); - } - Assert.IsTrue(clo.AppListenerContextClosed, - "Object did not receive context closed event via IApplicationContextListener"); - Assert.IsTrue(clo.CtxClosed, "Object did not receive context closed event via direct wiring."); - } - - [Test] - public void RefreshDisposesExistingObjectFactory_SPRNET479() - { - string tmp = typeof (DestroyTester).FullName; - Console.WriteLine(tmp); - - IApplicationContext ctx = - new XmlApplicationContext("assembly://Spring.Core.Tests/Spring.Context.Support/objects.xml"); - - DestroyTester destroyTester = (DestroyTester) ctx.GetObject("destroyTester"); - DisposeTester disposeTester = (DisposeTester) ctx.GetObject("disposeTester"); - Assert.IsFalse(destroyTester.IsDestroyed); - Assert.IsFalse(disposeTester.IsDisposed); - - ((IConfigurableApplicationContext) ctx).Refresh(); - - Assert.IsTrue(destroyTester.IsDestroyed); - Assert.IsTrue(disposeTester.IsDisposed); - } - - [Test] - public void GenericApplicationContextWithXmlObjectDefinitions() - { - GenericApplicationContext ctx = new GenericApplicationContext(); - XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(ctx); - reader.LoadObjectDefinitions("assembly://Spring.Core.Tests/Spring.Context.Support/contextB.xml"); - reader.LoadObjectDefinitions("assembly://Spring.Core.Tests/Spring.Context.Support/contextC.xml"); - reader.LoadObjectDefinitions("assembly://Spring.Core.Tests/Spring.Context.Support/contextA.xml"); - ctx.Refresh(); - - Assert.IsTrue(ctx.ContainsObject("service")); - Assert.IsTrue(ctx.ContainsObject("logicOne")); - Assert.IsTrue(ctx.ContainsObject("logicTwo")); - ctx.Dispose(); - - } - - [Test] - public void GenericApplicationContextConstructorTests() - { - IApplicationContext ctx = new XmlApplicationContext("assembly://Spring.Core.Tests/Spring.Context/contextlifecycle.xml"); - GenericApplicationContext genericCtx = new GenericApplicationContext(ctx); - genericCtx = new GenericApplicationContext("test", true, ctx); - } - - #region Helper classes - - public class DisposeTester : IDisposable - { - private bool isDisposed = false; - - public bool IsDisposed - { - get { return isDisposed; } - } - - public void Dispose() - { - if (isDisposed) throw new InvalidOperationException("must not be disposed twice"); - isDisposed = true; - } - } - - public class DestroyTester - { - private bool isDestroyed = false; - - public bool IsDestroyed - { - get { return isDestroyed; } - } - - public void DestroyMe() - { - if (isDestroyed) throw new InvalidOperationException("must not be destroyed twice"); - isDestroyed = true; - } - } - - /// - /// Utility class to keep track of object construction. - /// - public class CountingObjectPostProcessor : IObjectPostProcessor - { - private static int count; - - /// - /// Property Count (int) - /// - public static int Count - { - get { return count; } - set { count = value; } - } - - /// - /// Create an instance and increment the counter - /// - public CountingObjectPostProcessor() - { - count++; - } - - #region IObjectPostProcessor Members - - /// - /// No op implementation - /// - /// object to process - /// name of object - /// processed object - public object PostProcessAfterInitialization(object obj, string objectName) - { - return obj; - } - - /// - /// No op implementation - /// - /// object to process - /// name of object - /// processed object - public object PostProcessBeforeInitialization(object obj, string name) - { - return obj; - } - - #endregion - } - - - /// - /// Utility class to keep track of object construction. - /// - public class CoutingObjectFactoryPostProcessor : IObjectFactoryPostProcessor - { - private static int count; - - /// - /// Property Count (int) - /// - public static int Count - { - get { return count; } - set { count = value; } - } - - /// - /// Create an instance and increment the counter - /// - public CoutingObjectFactoryPostProcessor() - { - count++; - } - - #region IObjectFactoryPostProcessor Members - - /// - /// no op - /// - /// factory to post process - public void PostProcessObjectFactory(IConfigurableListableObjectFactory factory) - { - } - - #endregion - } - - #endregion } - public class SingletonTestingObjectPostProcessor : IObjectPostProcessor, IApplicationContextAware + + [Test] + [Ignore("Need to add Spring.TypeLoadException")] + public void ContextWithInvalidLazyType() { - private IApplicationContext applicationContext; + XmlApplicationContext ctx = + new XmlApplicationContext(false, + "assembly://Spring.Core.Tests/Spring.Context.Support/invalidType.xml"); + Assert.IsTrue(ctx.ContainsObject("someMessageSource")); + ctx.GetObject("someMessageSource"); + } + + [Test] + public void CaseInsensitiveContext() + { + XmlApplicationContext ctx = + new XmlApplicationContext(false, "assembly://Spring.Core.Tests/Spring.Context.Support/objects.xml"); + Assert.IsTrue(ctx.ContainsObject("goran")); + Assert.IsTrue(ctx.ContainsObject("Goran")); + Assert.IsTrue(ctx.ContainsObject("GORAN")); + Assert.AreEqual(ctx.GetObject("goran"), ctx.GetObject("GORAN")); + } + + [Test] + public void GetObjectOnUnknownIdThrowsNoSuchObjectDefinition() + { + XmlApplicationContext ctx = + new XmlApplicationContext(false, "assembly://Spring.Core.Tests/Spring.Context.Support/objects.xml"); + string DOES_NOT_EXIST = "does_not_exist"; + Assert.IsFalse(ctx.ContainsObject(DOES_NOT_EXIST)); + Assert.Throws(() => ctx.GetObject(DOES_NOT_EXIST)); + } + + [Test] + public void FactoryObjectsAreNotInstantiatedBeforeObjectFactoryPostProcessorsAreApplied() + { + XmlApplicationContext ctx = new XmlApplicationContext("Spring/Context/Support/SPRNET-192.xml"); + LogFactoryObject logFactory = (LogFactoryObject) ctx["&log"]; + Assert.AreEqual("foo", logFactory.LogName); + } + + /// + /// Make sure that if an IObjectPostProcessor is defined as abstract + /// the creation of an IApplicationContext will not try to instantiate it. + /// + [Test] + public void ContextWithPostProcessors() + { + CountingObjectPostProcessor.Count = 0; + CoutingObjectFactoryPostProcessor.Count = 0; + + IApplicationContext ctx = + new XmlApplicationContext("assembly://Spring.Core.Tests/Spring.Context.Support/objects.xml"); + + Assert.IsTrue(ctx.ContainsObject("abstractObjectProcessorPrototype")); + Assert.IsTrue(ctx.ContainsObject("abstractFactoryProcessorPrototype")); + + Assert.AreEqual(0, CountingObjectPostProcessor.Count); + Assert.AreEqual(0, CoutingObjectFactoryPostProcessor.Count); + } + + /// + /// Make sure that ConfigureObject() completly configures target + /// object (goes through whole lifecycle of object creation and + /// applies all processors). + /// + [Test] + public void ConfigureObject() + { + const string objDefLocation = "assembly://Spring.Core.Tests/Spring.Context.Support/objects.xml"; + + XmlApplicationContext xmlContext = new XmlApplicationContext(new string[] { objDefLocation }); + + object objGoran = xmlContext.GetObject("goran"); + Assert.IsTrue(objGoran is TestObject); + TestObject fooGet = objGoran as TestObject; + + TestObject fooConfigure = new TestObject(); + xmlContext.ConfigureObject(fooConfigure, "goran"); + Assert.IsNotNull(fooGet); + Assert.AreEqual(fooGet.Name, fooConfigure.Name); + Assert.AreEqual(fooGet.Age, fooConfigure.Age); + Assert.AreEqual(fooGet.ObjectName, fooConfigure.ObjectName); + Assert.IsNotNull(fooGet.ObjectName); + Assert.AreEqual(xmlContext, fooGet.ApplicationContext); + Assert.AreEqual(xmlContext, fooConfigure.ApplicationContext); + } + + [Test] + public void ContextLifeCycle() + { + IApplicationContext ctx = + new XmlApplicationContext("assembly://Spring.Core.Tests/Spring.Context/contextlifecycle.xml"); + IConfigurableApplicationContext configCtx = ctx as IConfigurableApplicationContext; + Assert.IsNotNull(configCtx); + ContextListenerObject clo; + using (configCtx) + { + clo = configCtx["contextListenerObject"] as ContextListenerObject; + Assert.IsNotNull(clo); + Assert.IsTrue(clo.AppListenerContextRefreshed, + "Object did not receive context refreshed event via IApplicationListener"); + Assert.IsTrue(clo.CtxRefreshed, "Object did not receive context refreshed event via direct wiring"); + } + + Assert.IsTrue(clo.AppListenerContextClosed, + "Object did not receive context closed event via IApplicationContextListener"); + Assert.IsTrue(clo.CtxClosed, "Object did not receive context closed event via direct wiring."); + } + + [Test] + public void RefreshDisposesExistingObjectFactory_SPRNET479() + { + string tmp = typeof(DestroyTester).FullName; + Console.WriteLine(tmp); + + IApplicationContext ctx = + new XmlApplicationContext("assembly://Spring.Core.Tests/Spring.Context.Support/objects.xml"); + + DestroyTester destroyTester = (DestroyTester) ctx.GetObject("destroyTester"); + DisposeTester disposeTester = (DisposeTester) ctx.GetObject("disposeTester"); + Assert.IsFalse(destroyTester.IsDestroyed); + Assert.IsFalse(disposeTester.IsDisposed); + + ((IConfigurableApplicationContext) ctx).Refresh(); + + Assert.IsTrue(destroyTester.IsDestroyed); + Assert.IsTrue(disposeTester.IsDisposed); + } + + [Test] + public void GenericApplicationContextWithXmlObjectDefinitions() + { + GenericApplicationContext ctx = new GenericApplicationContext(); + XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(ctx); + reader.LoadObjectDefinitions("assembly://Spring.Core.Tests/Spring.Context.Support/contextB.xml"); + reader.LoadObjectDefinitions("assembly://Spring.Core.Tests/Spring.Context.Support/contextC.xml"); + reader.LoadObjectDefinitions("assembly://Spring.Core.Tests/Spring.Context.Support/contextA.xml"); + ctx.Refresh(); + + Assert.IsTrue(ctx.ContainsObject("service")); + Assert.IsTrue(ctx.ContainsObject("logicOne")); + Assert.IsTrue(ctx.ContainsObject("logicTwo")); + ctx.Dispose(); + } + + [Test] + public void GenericApplicationContextConstructorTests() + { + IApplicationContext ctx = new XmlApplicationContext("assembly://Spring.Core.Tests/Spring.Context/contextlifecycle.xml"); + GenericApplicationContext genericCtx = new GenericApplicationContext(ctx); + genericCtx = new GenericApplicationContext("test", true, ctx); + } + + #region Helper classes + + public class DisposeTester : IDisposable + { + private bool isDisposed = false; + + public bool IsDisposed + { + get { return isDisposed; } + } + + public void Dispose() + { + if (isDisposed) throw new InvalidOperationException("must not be disposed twice"); + isDisposed = true; + } + } + + public class DestroyTester + { + private bool isDestroyed = false; + + public bool IsDestroyed + { + get { return isDestroyed; } + } + + public void DestroyMe() + { + if (isDestroyed) throw new InvalidOperationException("must not be destroyed twice"); + isDestroyed = true; + } + } + + /// + /// Utility class to keep track of object construction. + /// + public class CountingObjectPostProcessor : IObjectPostProcessor + { + private static int count; + + /// + /// Property Count (int) + /// + public static int Count + { + get { return count; } + set { count = value; } + } + + /// + /// Create an instance and increment the counter + /// + public CountingObjectPostProcessor() + { + count++; + } + #region IObjectPostProcessor Members - public object PostProcessBeforeInitialization(object instance, string name) + /// + /// No op implementation + /// + /// object to process + /// name of object + /// processed object + public object PostProcessAfterInitialization(object obj, string objectName) { - return instance; + return obj; } - public object PostProcessAfterInitialization(object instance, string objectName) + /// + /// No op implementation + /// + /// object to process + /// name of object + /// processed object + public object PostProcessBeforeInitialization(object obj, string name) { - Console.WriteLine("post process " + objectName); - if (this.applicationContext.IsSingleton(objectName)) - { - return instance; - } - return instance; - } - - #endregion - - #region IApplicationContextAware Members - - public IApplicationContext ApplicationContext - { - set { this.applicationContext = value; } + return obj; } #endregion } -} \ No newline at end of file + + /// + /// Utility class to keep track of object construction. + /// + public class CoutingObjectFactoryPostProcessor : IObjectFactoryPostProcessor + { + private static int count; + + /// + /// Property Count (int) + /// + public static int Count + { + get { return count; } + set { count = value; } + } + + /// + /// Create an instance and increment the counter + /// + public CoutingObjectFactoryPostProcessor() + { + count++; + } + + #region IObjectFactoryPostProcessor Members + + /// + /// no op + /// + /// factory to post process + public void PostProcessObjectFactory(IConfigurableListableObjectFactory factory) + { + } + + #endregion + } + + #endregion +} + +public class SingletonTestingObjectPostProcessor : IObjectPostProcessor, IApplicationContextAware +{ + private IApplicationContext applicationContext; + + #region IObjectPostProcessor Members + + public object PostProcessBeforeInitialization(object instance, string name) + { + return instance; + } + + public object PostProcessAfterInitialization(object instance, string objectName) + { + Console.WriteLine("post process " + objectName); + if (this.applicationContext.IsSingleton(objectName)) + { + return instance; + } + + return instance; + } + + #endregion + + #region IApplicationContextAware Members + + public IApplicationContext ApplicationContext + { + set { this.applicationContext = value; } + } + + #endregion +} diff --git a/test/Spring/Spring.Core.Tests/Context/Support/contextA.xml b/test/Spring/Spring.Core.Tests/Context/Support/contextA.xml index fc0aa240..6a44b76c 100644 --- a/test/Spring/Spring.Core.Tests/Context/Support/contextA.xml +++ b/test/Spring/Spring.Core.Tests/Context/Support/contextA.xml @@ -1,14 +1,14 @@  - + - - - - - - - + + + + + + + diff --git a/test/Spring/Spring.Core.Tests/Context/Support/contextB.xml b/test/Spring/Spring.Core.Tests/Context/Support/contextB.xml index a3b6568e..7578861f 100644 --- a/test/Spring/Spring.Core.Tests/Context/Support/contextB.xml +++ b/test/Spring/Spring.Core.Tests/Context/Support/contextB.xml @@ -1,8 +1,8 @@  - - - - - + + + + + diff --git a/test/Spring/Spring.Core.Tests/Context/Support/contextC.xml b/test/Spring/Spring.Core.Tests/Context/Support/contextC.xml index 4c9abac8..d9976765 100644 --- a/test/Spring/Spring.Core.Tests/Context/Support/contextC.xml +++ b/test/Spring/Spring.Core.Tests/Context/Support/contextC.xml @@ -1,8 +1,8 @@  - - - - - + + + + + \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/Context/Support/import1.xml b/test/Spring/Spring.Core.Tests/Context/Support/import1.xml index dabd9953..f053ceaa 100644 --- a/test/Spring/Spring.Core.Tests/Context/Support/import1.xml +++ b/test/Spring/Spring.Core.Tests/Context/Support/import1.xml @@ -2,14 +2,14 @@ - - - - + + + + + + + + + - - - - - \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/Context/Support/innerObjectsWithPostProcessor.xml b/test/Spring/Spring.Core.Tests/Context/Support/innerObjectsWithPostProcessor.xml index fd32386a..569f7dde 100644 --- a/test/Spring/Spring.Core.Tests/Context/Support/innerObjectsWithPostProcessor.xml +++ b/test/Spring/Spring.Core.Tests/Context/Support/innerObjectsWithPostProcessor.xml @@ -2,25 +2,26 @@ - - - - - hasInner - - - 5 - - - - - inner1 - - - 6 - + + + + + hasInner + + + 5 + + + + + inner1 + + + 6 + + + - - - + \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/Context/Support/invalidType.xml b/test/Spring/Spring.Core.Tests/Context/Support/invalidType.xml index 5e0032b1..ec615d39 100644 --- a/test/Spring/Spring.Core.Tests/Context/Support/invalidType.xml +++ b/test/Spring/Spring.Core.Tests/Context/Support/invalidType.xml @@ -2,9 +2,9 @@ - - + + diff --git a/test/Spring/Spring.Core.Tests/Context/Support/invalidValueType.xml b/test/Spring/Spring.Core.Tests/Context/Support/invalidValueType.xml index 3cb3307c..4646ae10 100644 --- a/test/Spring/Spring.Core.Tests/Context/Support/invalidValueType.xml +++ b/test/Spring/Spring.Core.Tests/Context/Support/invalidValueType.xml @@ -3,10 +3,10 @@ - - - + + + diff --git a/test/Spring/Spring.Core.Tests/Context/Support/objects.xml b/test/Spring/Spring.Core.Tests/Context/Support/objects.xml index d31ba0bb..a1e8d42e 100644 --- a/test/Spring/Spring.Core.Tests/Context/Support/objects.xml +++ b/test/Spring/Spring.Core.Tests/Context/Support/objects.xml @@ -1,27 +1,29 @@ - - + + - - + + - - - + + + - - - + + + - - + + diff --git a/test/Spring/Spring.Core.Tests/Context/Support/simpleContext.xml b/test/Spring/Spring.Core.Tests/Context/Support/simpleContext.xml index 48161fe4..2b9441c7 100644 --- a/test/Spring/Spring.Core.Tests/Context/Support/simpleContext.xml +++ b/test/Spring/Spring.Core.Tests/Context/Support/simpleContext.xml @@ -2,13 +2,13 @@ - + - + - - - + + + diff --git a/test/Spring/Spring.Core.Tests/Context/Support/testobject.xsd b/test/Spring/Spring.Core.Tests/Context/Support/testobject.xsd index 242311ae..2265b47f 100644 --- a/test/Spring/Spring.Core.Tests/Context/Support/testobject.xsd +++ b/test/Spring/Spring.Core.Tests/Context/Support/testobject.xsd @@ -1,13 +1,14 @@ - - - - - - - - + xmlns="http://schemas.springframework.net/testobject" + xmlns:mstns="http://schemas.springframework.net/testobject" + xmlns:xs="http://www.w3.org/2001/XMLSchema"> + + + + + + + + \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/Context/contextlifecycle.xml b/test/Spring/Spring.Core.Tests/Context/contextlifecycle.xml index 553f7c8c..a40ba85b 100644 --- a/test/Spring/Spring.Core.Tests/Context/contextlifecycle.xml +++ b/test/Spring/Spring.Core.Tests/Context/contextlifecycle.xml @@ -1,11 +1,11 @@ - - + + - - Tests for notificaton on application lifecycle events. - + + Tests for notificaton on application lifecycle events. + - + \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/Core/ComposedCriteriaTests.cs b/test/Spring/Spring.Core.Tests/Core/ComposedCriteriaTests.cs index 31c2cf57..19ed089c 100644 --- a/test/Spring/Spring.Core.Tests/Core/ComposedCriteriaTests.cs +++ b/test/Spring/Spring.Core.Tests/Core/ComposedCriteriaTests.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -25,54 +25,53 @@ using NUnit.Framework; #endregion -namespace Spring.Core +namespace Spring.Core; + +[TestFixture] +public class ComposedCriteriaTests : ComposedCriteria { - [TestFixture] - public class ComposedCriteriaTests : ComposedCriteria - { - public ComposedCriteriaTests() : base() {} - public ComposedCriteriaTests( ICriteria criteria ) : base( criteria ) {} - [Test] - public void IsSatisfiedWithNoCriteria() - { - ComposedCriteriaTests composedCriteria = new ComposedCriteriaTests(); - Assert.IsTrue(composedCriteria.IsSatisfied("foo")); - } + public ComposedCriteriaTests() : base() { } + public ComposedCriteriaTests(ICriteria criteria) : base(criteria) { } - [Test] - public void SatifiesMyUpperCaseCriteria() - { - ComposedCriteriaTests composedCriteria = new ComposedCriteriaTests(new MyUpperCaseCriteria()); - Assert.IsTrue(composedCriteria.IsSatisfied("HELLO")); - Assert.IsFalse(composedCriteria.IsSatisfied("hello")); - } + [Test] + public void IsSatisfiedWithNoCriteria() + { + ComposedCriteriaTests composedCriteria = new ComposedCriteriaTests(); + Assert.IsTrue(composedCriteria.IsSatisfied("foo")); + } - [Test] - public void SatifiesTwoCriteria() - { - ComposedCriteriaTests composedCriteria = new ComposedCriteriaTests(); - composedCriteria.Add(new MyUpperCaseCriteria()); - composedCriteria.Add(new MyStringCriteria()); - Assert.IsTrue(composedCriteria.IsSatisfied("HELLO")); - Assert.IsFalse(composedCriteria.IsSatisfied("GOODBYE")); - Assert.IsTrue( composedCriteria.Criteria.Count == 2 ); - } + [Test] + public void SatifiesMyUpperCaseCriteria() + { + ComposedCriteriaTests composedCriteria = new ComposedCriteriaTests(new MyUpperCaseCriteria()); + Assert.IsTrue(composedCriteria.IsSatisfied("HELLO")); + Assert.IsFalse(composedCriteria.IsSatisfied("hello")); + } - internal class MyUpperCaseCriteria : ICriteria - { - public bool IsSatisfied(object datum) - { - return Regex.Match((string) datum, "[A-Z]").Success; - } - } + [Test] + public void SatifiesTwoCriteria() + { + ComposedCriteriaTests composedCriteria = new ComposedCriteriaTests(); + composedCriteria.Add(new MyUpperCaseCriteria()); + composedCriteria.Add(new MyStringCriteria()); + Assert.IsTrue(composedCriteria.IsSatisfied("HELLO")); + Assert.IsFalse(composedCriteria.IsSatisfied("GOODBYE")); + Assert.IsTrue(composedCriteria.Criteria.Count == 2); + } - internal class MyStringCriteria : ICriteria - { - public bool IsSatisfied(object datum) - { - return datum.ToString().ToLower() == "hello"; - } - } + internal class MyUpperCaseCriteria : ICriteria + { + public bool IsSatisfied(object datum) + { + return Regex.Match((string) datum, "[A-Z]").Success; + } + } - } -} \ No newline at end of file + internal class MyStringCriteria : ICriteria + { + public bool IsSatisfied(object datum) + { + return datum.ToString().ToLower() == "hello"; + } + } +} diff --git a/test/Spring/Spring.Core.Tests/Core/ControlFlowFactoryTests.cs b/test/Spring/Spring.Core.Tests/Core/ControlFlowFactoryTests.cs index 1a1cfedf..c8f93f59 100644 --- a/test/Spring/Spring.Core.Tests/Core/ControlFlowFactoryTests.cs +++ b/test/Spring/Spring.Core.Tests/Core/ControlFlowFactoryTests.cs @@ -26,96 +26,95 @@ using Spring.Objects; #endregion -namespace Spring.Core +namespace Spring.Core; + +/// +/// Unit tests for the default IControlFlow implementation returned by the +/// ControlFlowFactory class. +/// +/// Rick Evans +[TestFixture] +public sealed class ControlFlowFactoryTests { - /// - /// Unit tests for the default IControlFlow implementation returned by the - /// ControlFlowFactory class. - /// - /// Rick Evans - [TestFixture] - public sealed class ControlFlowFactoryTests - { - [Test] - public void CreateControlFlow() - { - IControlFlow cflow = ControlFlowFactory.CreateControlFlow(); - Assert.IsNotNull(cflow, "The ControlFlowFactory factory class is returning a " + - "null IControlFlow instance (it, obviously, must not)"); - } + [Test] + public void CreateControlFlow() + { + IControlFlow cflow = ControlFlowFactory.CreateControlFlow(); + Assert.IsNotNull(cflow, "The ControlFlowFactory factory class is returning a " + + "null IControlFlow instance (it, obviously, must not)"); + } - [Test] - public void CreateControlFlowReturnsDistinctInstance() - { - IControlFlow cflow1 = ControlFlowFactory.CreateControlFlow(); - IControlFlow cflow2 = ControlFlowFactory.CreateControlFlow(); - Assert.IsFalse(Object.ReferenceEquals(cflow1, cflow2), "The ControlFlowFactory " + - "factory class is not returning distinct IControlFlow instances (its always " + - "the same instance)"); - } + [Test] + public void CreateControlFlowReturnsDistinctInstance() + { + IControlFlow cflow1 = ControlFlowFactory.CreateControlFlow(); + IControlFlow cflow2 = ControlFlowFactory.CreateControlFlow(); + Assert.IsFalse(Object.ReferenceEquals(cflow1, cflow2), "The ControlFlowFactory " + + "factory class is not returning distinct IControlFlow instances (its always " + + "the same instance)"); + } - [Test] - public void DefaultCflowUnderThisTest() - { - IControlFlow cflow = ControlFlowFactory.CreateControlFlow(); - bool isUnder = cflow.Under(GetType()); - Assert.IsTrue(isUnder, string.Format( - "The IControlFlow implementation created by the ControlFlowFactory factory class " + - "would appear to have a faulty Under(Type) implementation : [{0}]", cflow.GetType())); - } + [Test] + public void DefaultCflowUnderThisTest() + { + IControlFlow cflow = ControlFlowFactory.CreateControlFlow(); + bool isUnder = cflow.Under(GetType()); + Assert.IsTrue(isUnder, string.Format( + "The IControlFlow implementation created by the ControlFlowFactory factory class " + + "would appear to have a faulty Under(Type) implementation : [{0}]", cflow.GetType())); + } - [Test] - public void DefaultCflowIsNotUnderSomeArbitraryClass() - { - IControlFlow cflow = ControlFlowFactory.CreateControlFlow(); - bool isUnder = cflow.Under(typeof (TestObject)); - Assert.IsFalse(isUnder, string.Format( - "The IControlFlow implementation created by the ControlFlowFactory factory class " + - "would appear to have a faulty Under(Type) implementation : [{0}]", cflow.GetType())); - } + [Test] + public void DefaultCflowIsNotUnderSomeArbitraryClass() + { + IControlFlow cflow = ControlFlowFactory.CreateControlFlow(); + bool isUnder = cflow.Under(typeof(TestObject)); + Assert.IsFalse(isUnder, string.Format( + "The IControlFlow implementation created by the ControlFlowFactory factory class " + + "would appear to have a faulty Under(Type) implementation : [{0}]", cflow.GetType())); + } - [Test] - public void DefaultCflowUnderThisTestAndTestMethodName() - { - IControlFlow cflow = ControlFlowFactory.CreateControlFlow(); - bool isUnder = cflow.Under(GetType(), MethodBase.GetCurrentMethod().Name); - Assert.IsTrue(isUnder, string.Format( - "The IControlFlow implementation created by the ControlFlowFactory factory class " + - "would appear to have a faulty Under(Type,string) implementation : [{0}]", - cflow.GetType())); - } + [Test] + public void DefaultCflowUnderThisTestAndTestMethodName() + { + IControlFlow cflow = ControlFlowFactory.CreateControlFlow(); + bool isUnder = cflow.Under(GetType(), MethodBase.GetCurrentMethod().Name); + Assert.IsTrue(isUnder, string.Format( + "The IControlFlow implementation created by the ControlFlowFactory factory class " + + "would appear to have a faulty Under(Type,string) implementation : [{0}]", + cflow.GetType())); + } - [Test] - public void DefaultCflowIsNotUnderThisTestAndSomeRandomMethodName() - { - IControlFlow cflow = ControlFlowFactory.CreateControlFlow(); - bool isUnder = cflow.Under(GetType(), "PlayingYouALikeTheFoolYouAre"); - Assert.IsFalse(isUnder, string.Format( - "The IControlFlow implementation created by the ControlFlowFactory factory class " + - "would appear to have a faulty Under(Type,string) implementation : [{0}]", - cflow.GetType())); - } + [Test] + public void DefaultCflowIsNotUnderThisTestAndSomeRandomMethodName() + { + IControlFlow cflow = ControlFlowFactory.CreateControlFlow(); + bool isUnder = cflow.Under(GetType(), "PlayingYouALikeTheFoolYouAre"); + Assert.IsFalse(isUnder, string.Format( + "The IControlFlow implementation created by the ControlFlowFactory factory class " + + "would appear to have a faulty Under(Type,string) implementation : [{0}]", + cflow.GetType())); + } - [Test] - public void DefaultCflowUnderToken() - { - IControlFlow cflow = ControlFlowFactory.CreateControlFlow(); - bool isUnder = cflow.UnderToken("Cflow"); - Assert.IsTrue(isUnder, string.Format( - "The IControlFlow implementation created by the ControlFlowFactory factory " + - "class would appear to have a faulty UnderToken(string) implementation : [{0}]", - cflow.GetType())); - } + [Test] + public void DefaultCflowUnderToken() + { + IControlFlow cflow = ControlFlowFactory.CreateControlFlow(); + bool isUnder = cflow.UnderToken("Cflow"); + Assert.IsTrue(isUnder, string.Format( + "The IControlFlow implementation created by the ControlFlowFactory factory " + + "class would appear to have a faulty UnderToken(string) implementation : [{0}]", + cflow.GetType())); + } - [Test] - public void DefaultCflowIsNotUnderSomeArbitraryToken() - { - IControlFlow cflow = ControlFlowFactory.CreateControlFlow(); - bool isUnder = cflow.UnderToken("GoatsCheeseAndSoda"); - Assert.IsFalse(isUnder, string.Format( - "The IControlFlow implementation created by the ControlFlowFactory factory class " + - "would appear to have a faulty UnderToken(string) implementation : [{0}]", - cflow.GetType())); - } - } -} \ No newline at end of file + [Test] + public void DefaultCflowIsNotUnderSomeArbitraryToken() + { + IControlFlow cflow = ControlFlowFactory.CreateControlFlow(); + bool isUnder = cflow.UnderToken("GoatsCheeseAndSoda"); + Assert.IsFalse(isUnder, string.Format( + "The IControlFlow implementation created by the ControlFlowFactory factory class " + + "would appear to have a faulty UnderToken(string) implementation : [{0}]", + cflow.GetType())); + } +} diff --git a/test/Spring/Spring.Core.Tests/Core/IO/AssemblyResourceTest.cs b/test/Spring/Spring.Core.Tests/Core/IO/AssemblyResourceTest.cs index 7690a694..8abd0391 100644 --- a/test/Spring/Spring.Core.Tests/Core/IO/AssemblyResourceTest.cs +++ b/test/Spring/Spring.Core.Tests/Core/IO/AssemblyResourceTest.cs @@ -24,220 +24,221 @@ using NUnit.Framework; #endregion -namespace Spring.Core.IO +namespace Spring.Core.IO; + +/// +/// Unit tests for AssemblyResource +/// +/// Aleksandar Seovic +/// Federico Spinazzi +[TestFixture] +public class AssemblyResourceTest { - /// - /// Unit tests for AssemblyResource - /// - /// Aleksandar Seovic - /// Federico Spinazzi - [TestFixture] - public class AssemblyResourceTest + #region SetUp/TearDown + + [SetUp] + public void SetUp() { - #region SetUp/TearDown + } - [SetUp] - public void SetUp() - {} + [TearDown] + public void TearDown() + { + } - [TearDown] - public void TearDown() - {} + #endregion - #endregion + /// + /// Use incorrect format for an assembly resource. Using + /// comma delimited instead of '/'. + /// + [Test] + public void CreateWithMalformedResourceName() + { + Assert.Throws(() => new AssemblyResource("assembly://Spring.Core.Tests,Spring.TestResource.txt")); + } - /// - /// Use incorrect format for an assembly resource. Using - /// comma delimited instead of '/'. - /// - [Test] - public void CreateWithMalformedResourceName() + /// + /// Use old format, no longer supported (actually never publicly released) + /// that used 'dot' notation to seperate the namespace and resource name. + /// + [Test] + public void CreateWithObsoleteResourceName() + { + Assert.Throws(() => new AssemblyResource("assembly://Spring.Core.Tests/Spring.TestResource.txt")); + } + + /// + /// Use the correct format but with an invalid assembly name. + /// + [Test] + public void CreateFromInvalidAssembly() + { + Assert.Throws(() => new AssemblyResource("assembly://Xyz.Invalid.Assembly/Spring/TestResource.txt")); + } + + /// + /// Sunny day scenario that creates IResources and ensures the + /// correct contents can be read from them. + /// + [Test] + public void CreateValidAssemblyResource() + { + IResource res = new AssemblyResource("assembly://Spring.Core.Tests/Spring/TestResource.txt"); + AssertResourceContent(res, "Spring.TestResource.txt"); + IResource res2 = new AssemblyResource("assembly://Spring.Core.Tests/Spring.Core.IO/TestResource.txt"); + AssertResourceContent(res2, "Spring.Core.IO.TestResource.txt"); + } + + /// + /// Use correct assembly name, but incorrect namespace and resource name. + /// + [Test] + public void CreateInvalidAssemblyResource() + { + IResource res = new AssemblyResource("assembly://Spring.Core.Tests/Xyz/InvalidResource.txt"); + Assert.IsFalse(res.Exists, "Exists should return false"); + Assert.IsNull(res.InputStream, "Stream should be null"); + } + + [Test] + public void CreateRelativeWhenNotRelative() + { + IResource res = new AssemblyResource("assembly://Spring.Core.Tests/Spring/TestResource.txt"); + IResource res2 = res.CreateRelative("Spring.Core.Tests/Spring.Core.IO/TestResource.txt"); + AssertResourceContent(res2, "Spring.Core.IO.TestResource.txt"); + } + + /// + /// Test creating a resource relative to the location of the first. + /// The first resource is physically located in the root of the project since + /// the default namespace of the Spring.Core.Tests project is + /// 'Spring'. The notation './IO/TestResource.txt' will navigate + /// down to the 'Spring.Core.IO' namespace and CreateRelative will + /// then retrieve the similarly named TestResource.txt located there. + /// + [Test] + public void CreateRelativeInChildNamespace() + { + IResource res = new AssemblyResource("assembly://Spring.Core.Tests/Spring/TestResource.txt"); + IResource res2 = res.CreateRelative("./Core.IO/TestResource.txt"); + AssertResourceContent(res2, "Spring.Core.IO.TestResource.txt"); + } + + /// + /// Test creating a resource relative to the location of the first. + /// The first resource is physically located in the root of the project since + /// the default namespace of the Spring.Core.Tests project is + /// 'Spring'. The notation 'IO/TestResource.txt' will navigate + /// down to the 'Spring.Core.IO' namespace and CreateRelative will + /// then retrieve the similarly named TestResource.txt located there. + /// + [Test] + public void CreateRelativeInChildNamespaceWithoutPrefix() + { + IResource res = new AssemblyResource("assembly://Spring.Core.Tests/Spring/TestResource.txt"); + IResource res2 = res.CreateRelative("Core.IO/TestResource.txt"); + AssertResourceContent(res2, "Spring.Core.IO.TestResource.txt"); + } + + /// + /// Test creating a resource relative to the root of the assembly. + /// The first resource is physically located in the root of the project since + /// the default namespace of the Spring.Core.Tests project is + /// 'Spring'. The notation '/Spring.Core.IO/TestResource.txt' will navigate + /// down to the 'Spring.Core.IO' namespace and CreateRelative will + /// then retrieve the similarly named TestResource.txt located there. + /// + [Test] + public void CreateRelativeToRoot() + { + IResource res = new AssemblyResource("assembly://Spring.Core.Tests/Spring/TestResource.txt"); + IResource res2 = res.CreateRelative("/Spring.Core.IO/TestResource.txt"); + AssertResourceContent(res2, "Spring.Core.IO.TestResource.txt"); + } + + /// + /// Test creating a resource relative to the location of the first. + /// The first resource is physically located in the Spring.Core.IO directory + /// of the project and corresponds to the namespace 'Spring.Core.IO'. + /// The notation '../../TestResource.txt' will navigate up to the + /// root 'Spring' namespace and CreateRelative will then + /// retrieve the similarly named TestResource.txt located there + /// + [Test] + public void CreateRelativeInParentNamespace() + { + IResource res = new AssemblyResource("assembly://Spring.Core.Tests/Spring.Core.IO/TestResource.txt"); + IResource res2 = res.CreateRelative("../../TestResource.txt"); + AssertResourceContent(res2, "Spring.TestResource.txt"); + } + + /// + /// Test creating a resource relative to the location of the first. + /// The first resource is physically located in the Spring.Core.IO + /// directory of the project and corresponds to the namespace + /// 'Spring.Core.IO'. The notation '../../Objects/Factory/TestResource.txt' + /// will navigate up to the root 'Spring' namespace and then down + /// into the 'Spring.Object.Factory' namespace and CreateRelative + /// will then retrieve the similarly named TestResource.txt located there. + /// + [Test] + public void CreateRelativeInNotStraightParentNamespace() + { + IResource res = new AssemblyResource("assembly://Spring.Core.Tests/Spring.Core.IO/TestResource.txt"); + IResource res2 = res.CreateRelative("../../Objects/Factory/TestResource.txt"); + AssertResourceContent(res2, "Spring.Objects.Factory.TestResource.txt"); + } + + /// + /// Test creating a resource relative to the location of the first. + /// In this case the first resource is an assembly and the second is + /// uses the file URI. + /// The file URI used three slashes '///' which is interpreted to + /// mean the root of where the assembly is located on the file system. + /// The file 'abstract.xml' is located under Spring.Data in the VS.NET project + /// but a build-event copies these files under the location + /// of Spring.Core.Tests.dll. + /// + [Test] + public void CreateRelativeWithAReferenceToAFileResource() + { + IResource res = new AssemblyResource("assembly://Spring.Core.Tests/Spring.Core.IO/TestResource.txt"); + const string path = "Data/Spring/Objects/Factory/Xml/abstract.xml"; + IResource res2 = res.CreateRelative("file://~/" + path); + using (StreamReader r = File.OpenText(path)) { - Assert.Throws(() => new AssemblyResource("assembly://Spring.Core.Tests,Spring.TestResource.txt")); - } - - /// - /// Use old format, no longer supported (actually never publicly released) - /// that used 'dot' notation to seperate the namespace and resource name. - /// - [Test] - public void CreateWithObsoleteResourceName() - { - Assert.Throws(() => new AssemblyResource("assembly://Spring.Core.Tests/Spring.TestResource.txt")); - } - - /// - /// Use the correct format but with an invalid assembly name. - /// - [Test] - public void CreateFromInvalidAssembly() - { - Assert.Throws(() => new AssemblyResource("assembly://Xyz.Invalid.Assembly/Spring/TestResource.txt")); - } - - /// - /// Sunny day scenario that creates IResources and ensures the - /// correct contents can be read from them. - /// - [Test] - public void CreateValidAssemblyResource() - { - IResource res = new AssemblyResource("assembly://Spring.Core.Tests/Spring/TestResource.txt"); - AssertResourceContent(res, "Spring.TestResource.txt"); - IResource res2 = new AssemblyResource("assembly://Spring.Core.Tests/Spring.Core.IO/TestResource.txt"); - AssertResourceContent(res2, "Spring.Core.IO.TestResource.txt"); - } - - /// - /// Use correct assembly name, but incorrect namespace and resource name. - /// - [Test] - public void CreateInvalidAssemblyResource() - { - IResource res = new AssemblyResource("assembly://Spring.Core.Tests/Xyz/InvalidResource.txt"); - Assert.IsFalse(res.Exists, "Exists should return false"); - Assert.IsNull(res.InputStream, "Stream should be null"); - } - - [Test] - public void CreateRelativeWhenNotRelative() - { - IResource res = new AssemblyResource("assembly://Spring.Core.Tests/Spring/TestResource.txt"); - IResource res2 = res.CreateRelative("Spring.Core.Tests/Spring.Core.IO/TestResource.txt"); - AssertResourceContent(res2, "Spring.Core.IO.TestResource.txt"); - } - - /// - /// Test creating a resource relative to the location of the first. - /// The first resource is physically located in the root of the project since - /// the default namespace of the Spring.Core.Tests project is - /// 'Spring'. The notation './IO/TestResource.txt' will navigate - /// down to the 'Spring.Core.IO' namespace and CreateRelative will - /// then retrieve the similarly named TestResource.txt located there. - /// - [Test] - public void CreateRelativeInChildNamespace() - { - IResource res = new AssemblyResource("assembly://Spring.Core.Tests/Spring/TestResource.txt"); - IResource res2 = res.CreateRelative("./Core.IO/TestResource.txt"); - AssertResourceContent(res2, "Spring.Core.IO.TestResource.txt"); - } - - /// - /// Test creating a resource relative to the location of the first. - /// The first resource is physically located in the root of the project since - /// the default namespace of the Spring.Core.Tests project is - /// 'Spring'. The notation 'IO/TestResource.txt' will navigate - /// down to the 'Spring.Core.IO' namespace and CreateRelative will - /// then retrieve the similarly named TestResource.txt located there. - /// - [Test] - public void CreateRelativeInChildNamespaceWithoutPrefix() - { - IResource res = new AssemblyResource("assembly://Spring.Core.Tests/Spring/TestResource.txt"); - IResource res2 = res.CreateRelative("Core.IO/TestResource.txt"); - AssertResourceContent(res2, "Spring.Core.IO.TestResource.txt"); - } - - /// - /// Test creating a resource relative to the root of the assembly. - /// The first resource is physically located in the root of the project since - /// the default namespace of the Spring.Core.Tests project is - /// 'Spring'. The notation '/Spring.Core.IO/TestResource.txt' will navigate - /// down to the 'Spring.Core.IO' namespace and CreateRelative will - /// then retrieve the similarly named TestResource.txt located there. - /// - [Test] - public void CreateRelativeToRoot() - { - IResource res = new AssemblyResource("assembly://Spring.Core.Tests/Spring/TestResource.txt"); - IResource res2 = res.CreateRelative("/Spring.Core.IO/TestResource.txt"); - AssertResourceContent(res2, "Spring.Core.IO.TestResource.txt"); - } - - /// - /// Test creating a resource relative to the location of the first. - /// The first resource is physically located in the Spring.Core.IO directory - /// of the project and corresponds to the namespace 'Spring.Core.IO'. - /// The notation '../../TestResource.txt' will navigate up to the - /// root 'Spring' namespace and CreateRelative will then - /// retrieve the similarly named TestResource.txt located there - /// - [Test] - public void CreateRelativeInParentNamespace() - { - IResource res = new AssemblyResource("assembly://Spring.Core.Tests/Spring.Core.IO/TestResource.txt"); - IResource res2 = res.CreateRelative("../../TestResource.txt"); - AssertResourceContent(res2, "Spring.TestResource.txt"); - } - - /// - /// Test creating a resource relative to the location of the first. - /// The first resource is physically located in the Spring.Core.IO - /// directory of the project and corresponds to the namespace - /// 'Spring.Core.IO'. The notation '../../Objects/Factory/TestResource.txt' - /// will navigate up to the root 'Spring' namespace and then down - /// into the 'Spring.Object.Factory' namespace and CreateRelative - /// will then retrieve the similarly named TestResource.txt located there. - /// - [Test] - public void CreateRelativeInNotStraightParentNamespace() - { - IResource res = new AssemblyResource("assembly://Spring.Core.Tests/Spring.Core.IO/TestResource.txt"); - IResource res2 = res.CreateRelative("../../Objects/Factory/TestResource.txt"); - AssertResourceContent(res2, "Spring.Objects.Factory.TestResource.txt"); - } - - /// - /// Test creating a resource relative to the location of the first. - /// In this case the first resource is an assembly and the second is - /// uses the file URI. - /// The file URI used three slashes '///' which is interpreted to - /// mean the root of where the assembly is located on the file system. - /// The file 'abstract.xml' is located under Spring.Data in the VS.NET project - /// but a build-event copies these files under the location - /// of Spring.Core.Tests.dll. - /// - [Test] - public void CreateRelativeWithAReferenceToAFileResource() - { - IResource res = new AssemblyResource("assembly://Spring.Core.Tests/Spring.Core.IO/TestResource.txt"); - const string path = "Data/Spring/Objects/Factory/Xml/abstract.xml"; - IResource res2 = res.CreateRelative("file://~/" + path); - using (StreamReader r = File.OpenText(path)) + string content = r.ReadToEnd(); + using (StreamReader reader = new StreamReader(res2.InputStream)) { - string content = r.ReadToEnd(); - using (StreamReader reader = new StreamReader(res2.InputStream)) - { - Assert.AreEqual(content, reader.ReadToEnd(), "Resource content is not as expected"); - } - } - } - - /// - /// Try to create a relative resource, but use too many '..' to navigate - /// past the root namespace, off into la-la land. - /// - [Test] - public void TooMuchParentNamespacesAbove() - { - IResource res = new AssemblyResource("assembly://Spring.Core.Tests/Spring.Core.IO/TestResource.txt"); - Assert.Throws(() => res.CreateRelative("../../../../TestResource.txt")); - } - - /// - /// Utility method to compare a resource that contains a single string with - /// an exemplar. - /// - /// The resource to read a line from - /// the expected value of the line. - private void AssertResourceContent(IResource res, string expectedContent) - { - Assert.IsTrue(res.Exists); - using (StreamReader reader = new StreamReader(res.InputStream)) - { - Assert.AreEqual(expectedContent, reader.ReadLine(), "Resource content is not as expected"); + Assert.AreEqual(content, reader.ReadToEnd(), "Resource content is not as expected"); } } } -} \ No newline at end of file + + /// + /// Try to create a relative resource, but use too many '..' to navigate + /// past the root namespace, off into la-la land. + /// + [Test] + public void TooMuchParentNamespacesAbove() + { + IResource res = new AssemblyResource("assembly://Spring.Core.Tests/Spring.Core.IO/TestResource.txt"); + Assert.Throws(() => res.CreateRelative("../../../../TestResource.txt")); + } + + /// + /// Utility method to compare a resource that contains a single string with + /// an exemplar. + /// + /// The resource to read a line from + /// the expected value of the line. + private void AssertResourceContent(IResource res, string expectedContent) + { + Assert.IsTrue(res.Exists); + using (StreamReader reader = new StreamReader(res.InputStream)) + { + Assert.AreEqual(expectedContent, reader.ReadLine(), "Resource content is not as expected"); + } + } +} diff --git a/test/Spring/Spring.Core.Tests/Core/IO/ConfigSectionResourceTests.cs b/test/Spring/Spring.Core.Tests/Core/IO/ConfigSectionResourceTests.cs index 40e280f2..4a54b5e2 100644 --- a/test/Spring/Spring.Core.Tests/Core/IO/ConfigSectionResourceTests.cs +++ b/test/Spring/Spring.Core.Tests/Core/IO/ConfigSectionResourceTests.cs @@ -1,86 +1,84 @@ using System.Xml; using NUnit.Framework; - using Spring.Util; -namespace Spring.Core.IO +namespace Spring.Core.IO; + +/// +/// Summary description for ConfigSectionResourceTests. +/// +[TestFixture] +public class ConfigSectionResourceTests { - /// - /// Summary description for ConfigSectionResourceTests. - /// - [TestFixture] - public class ConfigSectionResourceTests + private class TestXmlUrlResolver : XmlUrlResolver { - private class TestXmlUrlResolver : XmlUrlResolver + public override object GetEntity(Uri absoluteUri, string role, Type ofObjectToReturn) { - public override object GetEntity(Uri absoluteUri, string role, Type ofObjectToReturn) - { - object result = base.GetEntity(absoluteUri, role, ofObjectToReturn); - return result; - } - - public override Uri ResolveUri(Uri baseUri, string relativeUri) - { - Console.WriteLine("baseUri=" + baseUri); - Console.WriteLine("relativeUri=" + relativeUri); - Uri result = base.ResolveUri(baseUri, relativeUri); - return result; - } + object result = base.GetEntity(absoluteUri, role, ofObjectToReturn); + return result; } - private ConfigSectionResource CreateConfigSectionResource(string filename) + public override Uri ResolveUri(Uri baseUri, string relativeUri) { - ConfigXmlDocument xmlDoc = new ConfigXmlDocument(); - - Uri testUri = TestResourceLoader.GetUri(this, filename); - - xmlDoc.Load("test config section", testUri.AbsoluteUri); - XmlNamespaceManager nsmgr = new XmlNamespaceManager(xmlDoc.NameTable); - nsmgr.AddNamespace("od", "http://www.springframework.net"); - XmlElement configElement = (XmlElement)xmlDoc.SelectSingleNode("//configuration/spring/od:objects", nsmgr); - - ConfigSectionResource csr = new ConfigSectionResource( configElement); - return csr; - } - -#if NETFRAMEWORK - [Test] - public void CanCreate() - { - ConfigSectionResource csr = CreateConfigSectionResource("_config1.xml"); - Assert.IsFalse(csr.Exists); - Assert.IsNull(csr.File); // always null - Assert.IsNull(csr.Uri); - Assert.IsTrue(csr.Description.StartsWith("config [") ); - Assert.IsTrue(csr.Description.EndsWith("#objects]") ); - } -#endif - - [Test] - public void ThrowsOnNullSectionName() - { - Assert.Throws(() => new ConfigSectionResource((string) null)); - } - - [Test] - public void ThrowsOnNullConfigElement() - { - Assert.Throws(() => new ConfigSectionResource((XmlElement) null)); - } - - [Test] - public void ThrowsIoExceptionIfConfigSectionDoesNotExist() - { - IResource res = new ConfigSectionResource(Guid.NewGuid().ToString()); - - try - { - Stream istm = res.InputStream; - Assert.Fail("Did not receive expected IOException!"); - } - catch(IOException) - { - } + Console.WriteLine("baseUri=" + baseUri); + Console.WriteLine("relativeUri=" + relativeUri); + Uri result = base.ResolveUri(baseUri, relativeUri); + return result; } } -} \ No newline at end of file + + private ConfigSectionResource CreateConfigSectionResource(string filename) + { + ConfigXmlDocument xmlDoc = new ConfigXmlDocument(); + + Uri testUri = TestResourceLoader.GetUri(this, filename); + + xmlDoc.Load("test config section", testUri.AbsoluteUri); + XmlNamespaceManager nsmgr = new XmlNamespaceManager(xmlDoc.NameTable); + nsmgr.AddNamespace("od", "http://www.springframework.net"); + XmlElement configElement = (XmlElement) xmlDoc.SelectSingleNode("//configuration/spring/od:objects", nsmgr); + + ConfigSectionResource csr = new ConfigSectionResource(configElement); + return csr; + } + +#if NETFRAMEWORK + [Test] + public void CanCreate() + { + ConfigSectionResource csr = CreateConfigSectionResource("_config1.xml"); + Assert.IsFalse(csr.Exists); + Assert.IsNull(csr.File); // always null + Assert.IsNull(csr.Uri); + Assert.IsTrue(csr.Description.StartsWith("config [") ); + Assert.IsTrue(csr.Description.EndsWith("#objects]") ); + } +#endif + + [Test] + public void ThrowsOnNullSectionName() + { + Assert.Throws(() => new ConfigSectionResource((string) null)); + } + + [Test] + public void ThrowsOnNullConfigElement() + { + Assert.Throws(() => new ConfigSectionResource((XmlElement) null)); + } + + [Test] + public void ThrowsIoExceptionIfConfigSectionDoesNotExist() + { + IResource res = new ConfigSectionResource(Guid.NewGuid().ToString()); + + try + { + Stream istm = res.InputStream; + Assert.Fail("Did not receive expected IOException!"); + } + catch (IOException) + { + } + } +} diff --git a/test/Spring/Spring.Core.Tests/Core/IO/ConfigurableResourceLoaderTests.cs b/test/Spring/Spring.Core.Tests/Core/IO/ConfigurableResourceLoaderTests.cs index 16af630a..232c1621 100644 --- a/test/Spring/Spring.Core.Tests/Core/IO/ConfigurableResourceLoaderTests.cs +++ b/test/Spring/Spring.Core.Tests/Core/IO/ConfigurableResourceLoaderTests.cs @@ -24,160 +24,161 @@ using NUnit.Framework; #endregion -namespace Spring.Core.IO +namespace Spring.Core.IO; + +/// +/// Unit tests for the ConfigurableResourceLoader class. +/// +/// Aleksandar Seovic +[TestFixture] +public sealed class ConfigurableResourceLoaderTests { - /// - /// Unit tests for the ConfigurableResourceLoader class. - /// - /// Aleksandar Seovic - [TestFixture] - public sealed class ConfigurableResourceLoaderTests - { - private ConfigurableResourceLoader loader; + private ConfigurableResourceLoader loader; - [SetUp] - public void SetUp() + [SetUp] + public void SetUp() + { + loader = new ConfigurableResourceLoader(); + } + + #region ConfigurableResourceLoader.GetResource Tests + + /// + /// Tests that loader correctly loads files specified by absolute name, regardless + /// of the fact whether protocol name is specified or not. + /// + [Test] + public void GetAbsoluteFileSystemResource() + { + string fileName = Path.GetTempFileName(); + try { - loader = new ConfigurableResourceLoader(); + IResource withoutProtocol = loader.GetResource(fileName); + Assert.IsNotNull(withoutProtocol, "Resource should not be null"); + Assert.IsTrue(withoutProtocol is FileSystemResource, "Expected FileSystemResource"); + Assert.IsTrue(withoutProtocol.Exists, "Resource should exist but it does not"); + + IResource withProtocol = loader.GetResource("file:///" + fileName); + Assert.IsNotNull(withProtocol, "Resource should not be null"); + Assert.IsTrue(withProtocol is FileSystemResource, "Expected FileSystemResource"); + Assert.IsTrue(withProtocol.Exists, "Resource should exist but it does not"); } - - #region ConfigurableResourceLoader.GetResource Tests - - /// - /// Tests that loader correctly loads files specified by absolute name, regardless - /// of the fact whether protocol name is specified or not. - /// - [Test] - public void GetAbsoluteFileSystemResource() - { - string fileName = Path.GetTempFileName(); - try - { - IResource withoutProtocol = loader.GetResource(fileName); - Assert.IsNotNull(withoutProtocol, "Resource should not be null"); - Assert.IsTrue(withoutProtocol is FileSystemResource, "Expected FileSystemResource"); - Assert.IsTrue(withoutProtocol.Exists, "Resource should exist but it does not"); - - IResource withProtocol = loader.GetResource("file:///" + fileName); - Assert.IsNotNull(withProtocol, "Resource should not be null"); - Assert.IsTrue(withProtocol is FileSystemResource, "Expected FileSystemResource"); - Assert.IsTrue(withProtocol.Exists, "Resource should exist but it does not"); - } - finally - { - new FileInfo(fileName).Delete(); - } - } - - [Test] - public void GetResourceThatSupportsTheSpecialHomeCharacter() - { - string filename = "foo.txt"; - FileInfo expectedFile = - new FileInfo(Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, filename))); - StreamWriter writer = expectedFile.CreateText(); - FileSystemResource res = (FileSystemResource) loader.GetResource("~/" + filename); - Assert.AreEqual(expectedFile.FullName, res.File.FullName); - try - { - writer.Close(); - } - catch (IOException) - { - } - try - { - expectedFile.Delete(); - } - catch (IOException) - { - } - } - - [Test] - public void GetResourceThatSupportsTheSpecialHomeCharacter_WithLeadingWhitespace() + finally + { + new FileInfo(fileName).Delete(); + } + } + + [Test] + public void GetResourceThatSupportsTheSpecialHomeCharacter() + { + string filename = "foo.txt"; + FileInfo expectedFile = + new FileInfo(Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, filename))); + StreamWriter writer = expectedFile.CreateText(); + FileSystemResource res = (FileSystemResource) loader.GetResource("~/" + filename); + Assert.AreEqual(expectedFile.FullName, res.File.FullName); + try + { + writer.Close(); + } + catch (IOException) { - string filename = "foo.txt"; - FileInfo expectedFile = - new FileInfo(Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, filename))); - StreamWriter writer = expectedFile.CreateText(); - FileSystemResource res = (FileSystemResource) loader.GetResource(" ~/" + filename); - Assert.AreEqual(expectedFile.FullName, res.File.FullName); - try - { - writer.Close(); - } - catch (IOException) - { - } - try - { - expectedFile.Delete(); - } - catch (IOException) - { - } } - /// - /// Tests that loader correctly loads files specified by relative name, regardless - /// of the fact whether protocol name is specified or not. - /// - [Test] - public void GetRelativeFileSystemResource() - { - string fileName = "test.tmp"; - FileInfo fi = new FileInfo(fileName); - FileStream fs = fi.Create(); - fs.Close(); - - try - { - IResource withoutProtocol = loader.GetResource(fileName); - Assert.IsNotNull(withoutProtocol, "Resource should not be null"); - Assert.IsTrue(withoutProtocol is FileSystemResource, "Expected FileSystemResource"); - Assert.IsTrue(withoutProtocol.Exists, "Resource should exist but it does not"); - - IResource withProtocol = loader.GetResource("file://" + fileName); - Assert.IsNotNull(withProtocol, "Resource should not be null"); - Assert.IsTrue(withProtocol is FileSystemResource, "Expected FileSystemResource"); - Assert.IsTrue(withProtocol.Exists, "Resource should exist but it does not"); - } - finally - { - fi.Delete(); - } - } - - /// - /// Tests that loader can load UrlResource over HTTP protocol - /// - [Test] - [Explicit] - public void GetHttpUrlResource() - { - IResource res = loader.GetResource("http://www.springframework.net/license.html"); - Assert.IsNotNull(res, "Resource should not be null"); - Assert.AreEqual(typeof(UrlResource), res.GetType()); - } - - /// - /// Tests that loader can load UrlResource over assembly pseudo protocol - /// - [Test] - public void GetAssemblyResource() - { - IResource res = loader.GetResource("assembly://Spring.Core.Tests/Spring/TestResource.txt"); - Assert.IsNotNull(res, "Resource should not be null"); - Assert.AreEqual(typeof(AssemblyResource), res.GetType()); - } - - #endregion - - [Test] - public void GetResourceForNonMappedProtocol() - { - Assert.Throws(() => new ConfigurableResourceLoader().GetResource("beep://foo.xml")); + try + { + expectedFile.Delete(); } - } -} \ No newline at end of file + catch (IOException) + { + } + } + + [Test] + public void GetResourceThatSupportsTheSpecialHomeCharacter_WithLeadingWhitespace() + { + string filename = "foo.txt"; + FileInfo expectedFile = + new FileInfo(Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, filename))); + StreamWriter writer = expectedFile.CreateText(); + FileSystemResource res = (FileSystemResource) loader.GetResource(" ~/" + filename); + Assert.AreEqual(expectedFile.FullName, res.File.FullName); + try + { + writer.Close(); + } + catch (IOException) + { + } + + try + { + expectedFile.Delete(); + } + catch (IOException) + { + } + } + + /// + /// Tests that loader correctly loads files specified by relative name, regardless + /// of the fact whether protocol name is specified or not. + /// + [Test] + public void GetRelativeFileSystemResource() + { + string fileName = "test.tmp"; + FileInfo fi = new FileInfo(fileName); + FileStream fs = fi.Create(); + fs.Close(); + + try + { + IResource withoutProtocol = loader.GetResource(fileName); + Assert.IsNotNull(withoutProtocol, "Resource should not be null"); + Assert.IsTrue(withoutProtocol is FileSystemResource, "Expected FileSystemResource"); + Assert.IsTrue(withoutProtocol.Exists, "Resource should exist but it does not"); + + IResource withProtocol = loader.GetResource("file://" + fileName); + Assert.IsNotNull(withProtocol, "Resource should not be null"); + Assert.IsTrue(withProtocol is FileSystemResource, "Expected FileSystemResource"); + Assert.IsTrue(withProtocol.Exists, "Resource should exist but it does not"); + } + finally + { + fi.Delete(); + } + } + + /// + /// Tests that loader can load UrlResource over HTTP protocol + /// + [Test] + [Explicit] + public void GetHttpUrlResource() + { + IResource res = loader.GetResource("http://www.springframework.net/license.html"); + Assert.IsNotNull(res, "Resource should not be null"); + Assert.AreEqual(typeof(UrlResource), res.GetType()); + } + + /// + /// Tests that loader can load UrlResource over assembly pseudo protocol + /// + [Test] + public void GetAssemblyResource() + { + IResource res = loader.GetResource("assembly://Spring.Core.Tests/Spring/TestResource.txt"); + Assert.IsNotNull(res, "Resource should not be null"); + Assert.AreEqual(typeof(AssemblyResource), res.GetType()); + } + + #endregion + + [Test] + public void GetResourceForNonMappedProtocol() + { + Assert.Throws(() => new ConfigurableResourceLoader().GetResource("beep://foo.xml")); + } +} diff --git a/test/Spring/Spring.Core.Tests/Core/IO/EncodedResourceTests.cs b/test/Spring/Spring.Core.Tests/Core/IO/EncodedResourceTests.cs index 220b6cbd..b7e0d44f 100644 --- a/test/Spring/Spring.Core.Tests/Core/IO/EncodedResourceTests.cs +++ b/test/Spring/Spring.Core.Tests/Core/IO/EncodedResourceTests.cs @@ -22,74 +22,73 @@ using System.Text; using NUnit.Framework; using Spring.Util; -namespace Spring.Core.IO +namespace Spring.Core.IO; + +/// +/// +/// Erich Eichinger +[TestFixture] +public class EncodedResourceTests { - /// - /// - /// Erich Eichinger - [TestFixture] - public class EncodedResourceTests + [Test] + public void HashcodeIsCalculatedUsingResourceOnly() { - [Test] - public void HashcodeIsCalculatedUsingResourceOnly() - { - StringResource testResource = new StringResource("test"); - EncodedResource er1 = new EncodedResource(testResource, Encoding.ASCII, true); - EncodedResource er2 = new EncodedResource(testResource, Encoding.UTF8, false); + StringResource testResource = new StringResource("test"); + EncodedResource er1 = new EncodedResource(testResource, Encoding.ASCII, true); + EncodedResource er2 = new EncodedResource(testResource, Encoding.UTF8, false); - Assert.AreEqual(testResource.GetHashCode(), er1.GetHashCode()); - Assert.AreEqual(er1.GetHashCode(), er2.GetHashCode()); - } + Assert.AreEqual(testResource.GetHashCode(), er1.GetHashCode()); + Assert.AreEqual(er1.GetHashCode(), er2.GetHashCode()); + } - [Test] - public void OpensReaderWithDefaults() - { - EncodedResource r = new EncodedResource( new StringResource("test") ); - StreamReader reader = (StreamReader)r.OpenReader(); - Assert.AreEqual(Encoding.UTF8.EncodingName, reader.CurrentEncoding.EncodingName); - Assert.AreEqual("test", reader.ReadToEnd()); - } + [Test] + public void OpensReaderWithDefaults() + { + EncodedResource r = new EncodedResource(new StringResource("test")); + StreamReader reader = (StreamReader) r.OpenReader(); + Assert.AreEqual(Encoding.UTF8.EncodingName, reader.CurrentEncoding.EncodingName); + Assert.AreEqual("test", reader.ReadToEnd()); + } - [Test] - public void OpensReaderWithAutoDetectEncoding() - { - string expected = "test"; - Encoding utf32 = new UTF32Encoding(false, true); - byte[] resourceData = GetBytes(expected, utf32); - resourceData = (byte[])ArrayUtils.Concat(utf32.GetPreamble(), resourceData); - EncodedResource r = new EncodedResource( new InputStreamResource( new MemoryStream( resourceData), "description" ), Encoding.UTF8, true); - StreamReader reader = (StreamReader)r.OpenReader(); - Assert.AreEqual(Encoding.UTF8.EncodingName, reader.CurrentEncoding.EncodingName); - string actual = reader.ReadToEnd(); - Assert.AreEqual( "\uFEFF" + expected , actual); + [Test] + public void OpensReaderWithAutoDetectEncoding() + { + string expected = "test"; + Encoding utf32 = new UTF32Encoding(false, true); + byte[] resourceData = GetBytes(expected, utf32); + resourceData = (byte[]) ArrayUtils.Concat(utf32.GetPreamble(), resourceData); + EncodedResource r = new EncodedResource(new InputStreamResource(new MemoryStream(resourceData), "description"), Encoding.UTF8, true); + StreamReader reader = (StreamReader) r.OpenReader(); + Assert.AreEqual(Encoding.UTF8.EncodingName, reader.CurrentEncoding.EncodingName); + string actual = reader.ReadToEnd(); + Assert.AreEqual("\uFEFF" + expected, actual); // interestingly the line below is *not* true! // Assert.AreEqual(utf32.GetString(resourceData), actual); - Assert.AreEqual(utf32, reader.CurrentEncoding); - } - - [Test] - public void OpensReaderWithoutAutoDetectEncoding() - { - string expected = "test"; - Encoding utf32 = new UTF32Encoding(false, true); - byte[] resourceData = GetBytes(expected, utf32); - EncodedResource r = new EncodedResource(new InputStreamResource(new MemoryStream(resourceData), "description"), Encoding.UTF8, false); - StreamReader reader = (StreamReader)r.OpenReader(); - Assert.AreEqual(Encoding.UTF8.EncodingName, reader.CurrentEncoding.EncodingName); - string actual = reader.ReadToEnd(); -// Assert.AreEqual("\uFFFD\uFFFD\0\0t\0\0\0e\0\0\0s\0\0\0t\0\0\0", actual); - Assert.AreEqual(Encoding.UTF8.GetString(resourceData), actual); - Assert.AreEqual(Encoding.UTF8.EncodingName, reader.CurrentEncoding.EncodingName); - } - - /// - /// Returns the text bytes including the encoding's preamble (), if any. - /// - private byte[] GetBytes(string text, Encoding encoding) - { - byte[] resourceData = encoding.GetBytes(text); - resourceData = (byte[])ArrayUtils.Concat(encoding.GetPreamble(), resourceData); - return resourceData; - } + Assert.AreEqual(utf32, reader.CurrentEncoding); } -} \ No newline at end of file + + [Test] + public void OpensReaderWithoutAutoDetectEncoding() + { + string expected = "test"; + Encoding utf32 = new UTF32Encoding(false, true); + byte[] resourceData = GetBytes(expected, utf32); + EncodedResource r = new EncodedResource(new InputStreamResource(new MemoryStream(resourceData), "description"), Encoding.UTF8, false); + StreamReader reader = (StreamReader) r.OpenReader(); + Assert.AreEqual(Encoding.UTF8.EncodingName, reader.CurrentEncoding.EncodingName); + string actual = reader.ReadToEnd(); +// Assert.AreEqual("\uFFFD\uFFFD\0\0t\0\0\0e\0\0\0s\0\0\0t\0\0\0", actual); + Assert.AreEqual(Encoding.UTF8.GetString(resourceData), actual); + Assert.AreEqual(Encoding.UTF8.EncodingName, reader.CurrentEncoding.EncodingName); + } + + /// + /// Returns the text bytes including the encoding's preamble (), if any. + /// + private byte[] GetBytes(string text, Encoding encoding) + { + byte[] resourceData = encoding.GetBytes(text); + resourceData = (byte[]) ArrayUtils.Concat(encoding.GetPreamble(), resourceData); + return resourceData; + } +} diff --git a/test/Spring/Spring.Core.Tests/Core/IO/FileSystemResourceCommonTests.cs b/test/Spring/Spring.Core.Tests/Core/IO/FileSystemResourceCommonTests.cs index 634a79df..1d4c3627 100644 --- a/test/Spring/Spring.Core.Tests/Core/IO/FileSystemResourceCommonTests.cs +++ b/test/Spring/Spring.Core.Tests/Core/IO/FileSystemResourceCommonTests.cs @@ -25,296 +25,301 @@ using NUnit.Framework; #endregion -namespace Spring.Core.IO +namespace Spring.Core.IO; + +/// +/// Common Unit tests for all FileSystemResource derived classes. +/// +/// Erich Eichinger +public abstract class FileSystemResourceCommonTests { + protected const string TemporaryFileName = "temp.file"; + + protected abstract FileSystemResource CreateResourceInstance(string resourceName); + /// - /// Common Unit tests for all FileSystemResource derived classes. + /// Creates a FileInfo instance representing the original location of the given assembly /// - /// Erich Eichinger - public abstract class FileSystemResourceCommonTests + /// + /// Use this instead of the "Assembly.Location" property to get the original location before shadow copying! + /// + protected static FileInfo GetAssemblyLocation(Assembly assembly) { - protected const string TemporaryFileName = "temp.file"; + return new FileInfo(new Uri(assembly.Location).LocalPath); + } - protected abstract FileSystemResource CreateResourceInstance(string resourceName); + protected static FileInfo CreateFileForTheCurrentDirectory() + { + return new FileInfo(Path.GetFullPath( + Path.Combine(AppDomain.CurrentDomain.BaseDirectory, TemporaryFileName))); + } - /// - /// Creates a FileInfo instance representing the original location of the given assembly - /// - /// - /// Use this instead of the "Assembly.Location" property to get the original location before shadow copying! - /// - protected static FileInfo GetAssemblyLocation(Assembly assembly) + [Test] + public void CreateFileSystemResourceWithPathName() + { + FileSystemResource fileSystemResource = CreateResourceInstance(TemporaryFileName); + Assert.AreEqual(TemporaryFileName, fileSystemResource.File.Name); + } + + [Test] + public void FileSystemResourceExists() + { + FileInfo file = GetAssemblyLocation(Assembly.GetExecutingAssembly()); + FileSystemResource fileSystemResource = CreateResourceInstance("~/" + file.Name); + Assert.IsTrue(fileSystemResource.Exists); + } + + [Test] + public void FileSystemResourceNotExists() + { + Assert.IsFalse(CreateResourceInstance("asdfasfadf").Exists); + } + + [Test] + public void FileSystemResourceOpenNonExistanceFile() + { + FileSystemResource fileSystemResource = CreateResourceInstance(TemporaryFileName); + Stream inputStream; + Assert.Throws(() => inputStream = fileSystemResource.InputStream); + } + + [Test] + public void FileSystemResourceValidInputStream() + { + FileInfo file = GetAssemblyLocation(Assembly.GetExecutingAssembly()); + FileSystemResource fileSystemResource = CreateResourceInstance("~/" + file.Name); + using (Stream inputStream = fileSystemResource.InputStream) { - return new FileInfo(new Uri(assembly.Location).LocalPath); - } - - protected static FileInfo CreateFileForTheCurrentDirectory() - { - return new FileInfo(Path.GetFullPath( - Path.Combine(AppDomain.CurrentDomain.BaseDirectory, TemporaryFileName))); - } - - [Test] - public void CreateFileSystemResourceWithPathName() - { - FileSystemResource fileSystemResource = CreateResourceInstance(TemporaryFileName); - Assert.AreEqual(TemporaryFileName, fileSystemResource.File.Name); - } - - [Test] - public void FileSystemResourceExists() - { - FileInfo file = GetAssemblyLocation(Assembly.GetExecutingAssembly()); - FileSystemResource fileSystemResource = CreateResourceInstance("~/" + file.Name); - Assert.IsTrue(fileSystemResource.Exists); - } - - [Test] - public void FileSystemResourceNotExists() - { - Assert.IsFalse(CreateResourceInstance("asdfasfadf").Exists); - } - - [Test] - public void FileSystemResourceOpenNonExistanceFile() - { - FileSystemResource fileSystemResource = CreateResourceInstance(TemporaryFileName); - Stream inputStream; - Assert.Throws(() => inputStream = fileSystemResource.InputStream); - } - - [Test] - public void FileSystemResourceValidInputStream() - { - FileInfo file = GetAssemblyLocation(Assembly.GetExecutingAssembly()); - FileSystemResource fileSystemResource = CreateResourceInstance("~/" + file.Name); - using(Stream inputStream = fileSystemResource.InputStream) - { - Assert.IsNotNull(inputStream); - } - } - - [Test] - public void FileSystemResourceGivesOpenedInputStream() - { - FileInfo file = GetAssemblyLocation(Assembly.GetExecutingAssembly()); - FileSystemResource fileSystemResource = CreateResourceInstance("~/" + file.Name); - using(Stream inputStream = fileSystemResource.InputStream) - { - Assert.IsTrue(inputStream.CanRead); - } - } - - [Test] - public void GetDescription() - { - FileSystemResource fileSystemResource = CreateResourceInstance(TemporaryFileName); - string expectedDescription = "file [" + fileSystemResource.File.FullName + "]"; - Assert.AreEqual(expectedDescription, fileSystemResource.Description); - } - - [Test] - public void GetURL() - { - FileSystemResource fileSystemResource = CreateResourceInstance(TemporaryFileName); - Assert.IsNotNull(fileSystemResource.Uri); - } - - /// - /// Even though the 'root' resource points to a nonexistent subdirectory, surfing 'up' to the parent - /// via a relative path should still work... - /// - [Test] - public void CreateRelativeFromNonExistentOriginalResource() - { - // a suitable subdirectory of total pish - IResource resource = CreateResourceInstance("dork/muller.venken"); - Assert.IsFalse(resource.Exists, - "This test needs to feed off of a base resource that explicitly *doesn't* exist; but the resource seems to exist anyway."); - IResource relative = - resource.CreateRelative("../" + GetAssemblyLocation(Assembly.GetExecutingAssembly()).Name); - Assert.IsTrue(relative.Exists); - } - - [Test] - public void CreateRelativeResourceIsEqualToOriginalAfterBouncingUpAndDownTheDirectoryTree() - { - IResource resource = new FileSystemResource(GetAssemblyLocation(Assembly.GetExecutingAssembly()).FullName); - IResource relative = - resource.CreateRelative("foo/bar/../../" + GetAssemblyLocation(Assembly.GetExecutingAssembly()).Name); - Assert.IsTrue(relative.Exists); - Assert.IsTrue(resource.Equals(relative)); - } - - [Test] - public void CreateRelativeWithNullRelativePath() - { - IResource resource = CreateResourceInstance("."); - Assert.Throws(() => resource.CreateRelative(null)); - } - - [Test] - public void CreateRelativeWithEmptyRelativePath() - { - IResource resource = CreateResourceInstance("boba.licious"); - IResource relative = resource.CreateRelative(string.Empty); - Assert.IsFalse(relative.Exists); - } - - [Test] - public void RelativeResourceWhenNotRelative() - { - IResource res = CreateResourceInstance("dummy.txt"); - IResource res2 = CreateResourceInstance("/index.html"); - - IResource rel0 = res.CreateRelative("/index.html"); - Assert.IsTrue(rel0 is FileSystemResource); - Assert.AreEqual(res2.File.FullName, rel0.File.FullName); - } - - [Test] - public void RelativeResourceFromRoot() - { - FileSystemResource res = CreateResourceInstance(@"/dummy.txt"); - FileSystemResource res2; - - IResource rel0 = res.CreateRelative("/index.html"); - Assert.IsTrue(rel0 is FileSystemResource); - res2 = CreateResourceInstance("/index.html"); - Assert.AreEqual(res2.File.FullName, rel0.File.FullName); - - IResource rel1 = res.CreateRelative(@"index.html"); - Assert.IsTrue(rel1 is FileSystemResource); - res2 = CreateResourceInstance("/index.html"); - Assert.AreEqual(res2.File.FullName, rel1.File.FullName); - - IResource rel2 = res.CreateRelative(@"samples/artfair/index.html"); - Assert.IsTrue(rel2 is FileSystemResource); - res2 = CreateResourceInstance("/samples/artfair/index.html"); - Assert.AreEqual(res2.File.FullName, rel2.File.FullName); - - IResource rel3 = res.CreateRelative(@"./samples/artfair/index.html"); - Assert.IsTrue(rel3 is FileSystemResource); - res2 = CreateResourceInstance("/samples/artfair/index.html"); - Assert.AreEqual(res2.File.FullName, rel3.File.FullName); - } - - [Test] - public void RelativeResourceFromSubfolder() - { - FileSystemResource res = CreateResourceInstance(@"/samples/artfair/dummy.txt"); - FileSystemResource resExpected; - - IResource rel0 = res.CreateRelative(@"/index.html"); - Assert.IsTrue(rel0 is FileSystemResource); - resExpected = CreateResourceInstance("/index.html"); - Assert.AreEqual(resExpected.File.FullName, rel0.File.FullName); - - IResource rel1 = res.CreateRelative(@"index.html"); - Assert.IsTrue(rel1 is FileSystemResource); - resExpected = CreateResourceInstance("/samples/artfair/index.html"); - Assert.AreEqual(resExpected.File.FullName, rel1.File.FullName); - - IResource rel2 = res.CreateRelative(@"demo\index.html"); - Assert.IsTrue(rel2 is FileSystemResource); - resExpected = CreateResourceInstance("/samples/artfair/demo/index.html"); - Assert.AreEqual(resExpected.File.FullName, rel2.File.FullName); - - IResource rel3 = res.CreateRelative(@"./demo/index.html"); - Assert.IsTrue(rel3 is FileSystemResource); - resExpected = CreateResourceInstance("/samples/artfair/demo/index.html"); - Assert.AreEqual(resExpected.File.FullName, rel3.File.FullName); - - IResource rel4 = res.CreateRelative(@"../calculator/index.html"); - Assert.IsTrue(rel4 is FileSystemResource); - resExpected = CreateResourceInstance("/samples/calculator/index.html"); - Assert.AreEqual(resExpected.File.FullName, rel4.File.FullName); - - IResource rel5 = res.CreateRelative(@"..\..\index.html"); - resExpected = CreateResourceInstance("/index.html"); - Assert.AreEqual(resExpected.File.FullName, rel5.File.FullName); - } - - [Test] - public void RelativeResourceTooManyBackLevels() - { - FileSystemResource res = CreateResourceInstance("/samples/artfair/dummy.txt"); - Assert.Throws(() => res.CreateRelative("../../../index.html")); - } - - [Test] - public void SupportsAndResolvesTheSpecialHomeCharacter_SunnyDay() - { - FileInfo file = - new FileInfo(Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, TemporaryFileName))); - StreamWriter writer = file.CreateText(); - FileSystemResource res = CreateResourceInstance("~/" + TemporaryFileName); - Assert.IsTrue(res.File.Exists); - Assert.AreEqual(file.FullName.ToLower(), res.File.FullName.ToLower()); - try - { - writer.Close(); - } - catch(IOException) - {} - try - { - file.Delete(); - } - catch(IOException) - {} - } - - [Test] - [Ignore("problematic between framework versions")] - public void SupportsAndResolvesTheSpecialHomeCharacter_SunnyDayEvenWithLeadingWhitespace() - { - FileInfo file = - new FileInfo(Path.GetFullPath( - Path.Combine(AppDomain.CurrentDomain.BaseDirectory, TemporaryFileName))); - StreamWriter writer = file.CreateText(); - FileSystemResource res = CreateResourceInstance(" ~/" + TemporaryFileName); - Assert.AreEqual(file.FullName.ToLower(), res.File.FullName.ToLower()); - try - { - writer.Close(); - } - catch(IOException) - {} - try - { - file.Delete(); - } - catch(IOException) - {} - } - - [Test] - public void SupportsAndResolvesTheSpecialHomeCharacter_OnlyIfSpecialHomeCharacterIsFirstCharacter() - { - FileSystemResource res = CreateResourceInstance("foo~.txt"); - // must not have replaced ~; its only valid at the start of a resource name... - Assert.AreEqual("foo~.txt", res.File.Name); - } - - [Test] - public void Resolution_PlainVanilla() - { - FileInfo file = CreateFileForTheCurrentDirectory(); - IResource res = CreateResourceInstance(TemporaryFileName); - Assert.AreEqual(file.FullName.ToLower(), res.File.FullName.ToLower(), - "The bare file name all by itself must have resolved to a file in the current " + - "directory of the currently executing domain."); - } - - [Test] - public void Resolution_WithSpecialHomeCharacter() - { - FileInfo file = CreateFileForTheCurrentDirectory(); - IResource res = CreateResourceInstance("~/" + TemporaryFileName); - Assert.AreEqual(file.FullName.ToLower(), res.File.FullName.ToLower(), - "The file name with ~/ must have resolved to a file " + - "in the current directory of the currently executing domain."); + Assert.IsNotNull(inputStream); } } + + [Test] + public void FileSystemResourceGivesOpenedInputStream() + { + FileInfo file = GetAssemblyLocation(Assembly.GetExecutingAssembly()); + FileSystemResource fileSystemResource = CreateResourceInstance("~/" + file.Name); + using (Stream inputStream = fileSystemResource.InputStream) + { + Assert.IsTrue(inputStream.CanRead); + } + } + + [Test] + public void GetDescription() + { + FileSystemResource fileSystemResource = CreateResourceInstance(TemporaryFileName); + string expectedDescription = "file [" + fileSystemResource.File.FullName + "]"; + Assert.AreEqual(expectedDescription, fileSystemResource.Description); + } + + [Test] + public void GetURL() + { + FileSystemResource fileSystemResource = CreateResourceInstance(TemporaryFileName); + Assert.IsNotNull(fileSystemResource.Uri); + } + + /// + /// Even though the 'root' resource points to a nonexistent subdirectory, surfing 'up' to the parent + /// via a relative path should still work... + /// + [Test] + public void CreateRelativeFromNonExistentOriginalResource() + { + // a suitable subdirectory of total pish + IResource resource = CreateResourceInstance("dork/muller.venken"); + Assert.IsFalse(resource.Exists, + "This test needs to feed off of a base resource that explicitly *doesn't* exist; but the resource seems to exist anyway."); + IResource relative = + resource.CreateRelative("../" + GetAssemblyLocation(Assembly.GetExecutingAssembly()).Name); + Assert.IsTrue(relative.Exists); + } + + [Test] + public void CreateRelativeResourceIsEqualToOriginalAfterBouncingUpAndDownTheDirectoryTree() + { + IResource resource = new FileSystemResource(GetAssemblyLocation(Assembly.GetExecutingAssembly()).FullName); + IResource relative = + resource.CreateRelative("foo/bar/../../" + GetAssemblyLocation(Assembly.GetExecutingAssembly()).Name); + Assert.IsTrue(relative.Exists); + Assert.IsTrue(resource.Equals(relative)); + } + + [Test] + public void CreateRelativeWithNullRelativePath() + { + IResource resource = CreateResourceInstance("."); + Assert.Throws(() => resource.CreateRelative(null)); + } + + [Test] + public void CreateRelativeWithEmptyRelativePath() + { + IResource resource = CreateResourceInstance("boba.licious"); + IResource relative = resource.CreateRelative(string.Empty); + Assert.IsFalse(relative.Exists); + } + + [Test] + public void RelativeResourceWhenNotRelative() + { + IResource res = CreateResourceInstance("dummy.txt"); + IResource res2 = CreateResourceInstance("/index.html"); + + IResource rel0 = res.CreateRelative("/index.html"); + Assert.IsTrue(rel0 is FileSystemResource); + Assert.AreEqual(res2.File.FullName, rel0.File.FullName); + } + + [Test] + public void RelativeResourceFromRoot() + { + FileSystemResource res = CreateResourceInstance(@"/dummy.txt"); + FileSystemResource res2; + + IResource rel0 = res.CreateRelative("/index.html"); + Assert.IsTrue(rel0 is FileSystemResource); + res2 = CreateResourceInstance("/index.html"); + Assert.AreEqual(res2.File.FullName, rel0.File.FullName); + + IResource rel1 = res.CreateRelative(@"index.html"); + Assert.IsTrue(rel1 is FileSystemResource); + res2 = CreateResourceInstance("/index.html"); + Assert.AreEqual(res2.File.FullName, rel1.File.FullName); + + IResource rel2 = res.CreateRelative(@"samples/artfair/index.html"); + Assert.IsTrue(rel2 is FileSystemResource); + res2 = CreateResourceInstance("/samples/artfair/index.html"); + Assert.AreEqual(res2.File.FullName, rel2.File.FullName); + + IResource rel3 = res.CreateRelative(@"./samples/artfair/index.html"); + Assert.IsTrue(rel3 is FileSystemResource); + res2 = CreateResourceInstance("/samples/artfair/index.html"); + Assert.AreEqual(res2.File.FullName, rel3.File.FullName); + } + + [Test] + public void RelativeResourceFromSubfolder() + { + FileSystemResource res = CreateResourceInstance(@"/samples/artfair/dummy.txt"); + FileSystemResource resExpected; + + IResource rel0 = res.CreateRelative(@"/index.html"); + Assert.IsTrue(rel0 is FileSystemResource); + resExpected = CreateResourceInstance("/index.html"); + Assert.AreEqual(resExpected.File.FullName, rel0.File.FullName); + + IResource rel1 = res.CreateRelative(@"index.html"); + Assert.IsTrue(rel1 is FileSystemResource); + resExpected = CreateResourceInstance("/samples/artfair/index.html"); + Assert.AreEqual(resExpected.File.FullName, rel1.File.FullName); + + IResource rel2 = res.CreateRelative(@"demo\index.html"); + Assert.IsTrue(rel2 is FileSystemResource); + resExpected = CreateResourceInstance("/samples/artfair/demo/index.html"); + Assert.AreEqual(resExpected.File.FullName, rel2.File.FullName); + + IResource rel3 = res.CreateRelative(@"./demo/index.html"); + Assert.IsTrue(rel3 is FileSystemResource); + resExpected = CreateResourceInstance("/samples/artfair/demo/index.html"); + Assert.AreEqual(resExpected.File.FullName, rel3.File.FullName); + + IResource rel4 = res.CreateRelative(@"../calculator/index.html"); + Assert.IsTrue(rel4 is FileSystemResource); + resExpected = CreateResourceInstance("/samples/calculator/index.html"); + Assert.AreEqual(resExpected.File.FullName, rel4.File.FullName); + + IResource rel5 = res.CreateRelative(@"..\..\index.html"); + resExpected = CreateResourceInstance("/index.html"); + Assert.AreEqual(resExpected.File.FullName, rel5.File.FullName); + } + + [Test] + public void RelativeResourceTooManyBackLevels() + { + FileSystemResource res = CreateResourceInstance("/samples/artfair/dummy.txt"); + Assert.Throws(() => res.CreateRelative("../../../index.html")); + } + + [Test] + public void SupportsAndResolvesTheSpecialHomeCharacter_SunnyDay() + { + FileInfo file = + new FileInfo(Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, TemporaryFileName))); + StreamWriter writer = file.CreateText(); + FileSystemResource res = CreateResourceInstance("~/" + TemporaryFileName); + Assert.IsTrue(res.File.Exists); + Assert.AreEqual(file.FullName.ToLower(), res.File.FullName.ToLower()); + try + { + writer.Close(); + } + catch (IOException) + { + } + + try + { + file.Delete(); + } + catch (IOException) + { + } + } + + [Test] + [Ignore("problematic between framework versions")] + public void SupportsAndResolvesTheSpecialHomeCharacter_SunnyDayEvenWithLeadingWhitespace() + { + FileInfo file = + new FileInfo(Path.GetFullPath( + Path.Combine(AppDomain.CurrentDomain.BaseDirectory, TemporaryFileName))); + StreamWriter writer = file.CreateText(); + FileSystemResource res = CreateResourceInstance(" ~/" + TemporaryFileName); + Assert.AreEqual(file.FullName.ToLower(), res.File.FullName.ToLower()); + try + { + writer.Close(); + } + catch (IOException) + { + } + + try + { + file.Delete(); + } + catch (IOException) + { + } + } + + [Test] + public void SupportsAndResolvesTheSpecialHomeCharacter_OnlyIfSpecialHomeCharacterIsFirstCharacter() + { + FileSystemResource res = CreateResourceInstance("foo~.txt"); + // must not have replaced ~; its only valid at the start of a resource name... + Assert.AreEqual("foo~.txt", res.File.Name); + } + + [Test] + public void Resolution_PlainVanilla() + { + FileInfo file = CreateFileForTheCurrentDirectory(); + IResource res = CreateResourceInstance(TemporaryFileName); + Assert.AreEqual(file.FullName.ToLower(), res.File.FullName.ToLower(), + "The bare file name all by itself must have resolved to a file in the current " + + "directory of the currently executing domain."); + } + + [Test] + public void Resolution_WithSpecialHomeCharacter() + { + FileInfo file = CreateFileForTheCurrentDirectory(); + IResource res = CreateResourceInstance("~/" + TemporaryFileName); + Assert.AreEqual(file.FullName.ToLower(), res.File.FullName.ToLower(), + "The file name with ~/ must have resolved to a file " + + "in the current directory of the currently executing domain."); + } } \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/Core/IO/FileSystemResourceTests.cs b/test/Spring/Spring.Core.Tests/Core/IO/FileSystemResourceTests.cs index 7aa805d9..2f8a6906 100644 --- a/test/Spring/Spring.Core.Tests/Core/IO/FileSystemResourceTests.cs +++ b/test/Spring/Spring.Core.Tests/Core/IO/FileSystemResourceTests.cs @@ -24,301 +24,302 @@ using NUnit.Framework; #endregion -namespace Spring.Core.IO +namespace Spring.Core.IO; + +/// +/// Unit tests for the FileSystemResourceTest class. +/// +/// Rick Evans +[Platform("Win")] +public class FileSystemResourceTests : FileSystemResourceCommonTests { - /// - /// Unit tests for the FileSystemResourceTest class. - /// - /// Rick Evans - [Platform("Win")] - public class FileSystemResourceTests : FileSystemResourceCommonTests + protected override FileSystemResource CreateResourceInstance(string resourceName) { - protected override FileSystemResource CreateResourceInstance( string resourceName ) + return new FileSystemResource(resourceName); + } + + [Test] + public void LeadingProtocolIsNotTreatedRelative() + { + FileSystemResource res = new FileSystemResource(@"file://\\server\share\samples\artfair\"); + FileSystemResource res2 = (FileSystemResource) res.CreateRelative(@"file://./index.html"); + Assert.AreEqual(new Uri(Path.Combine(Environment.CurrentDirectory, "index.html")).AbsolutePath, res2.Uri.AbsolutePath); + } + + [Test] + public void RelativeUncResourceTooManyBackLevels() + { + FileSystemResource res = new FileSystemResource(@"\\server\share\samples\artfair\dummy.txt"); + Assert.Throws(() => res.CreateRelative(@"..\..\..\index.html")); + } + + [Test(Description = "SPRNET-89")] + public void SPRNET_89_SupportUrlEncodedLocationsWithSpaces() + { + string path = Path.GetFullPath("spaced dir"); + Directory.CreateDirectory(path); + string filePath = Path.Combine(path, "spaced file.txt"); + using (StreamWriter text = File.CreateText(filePath)) { - return new FileSystemResource(resourceName); + text.WriteLine("hello world"); } - [Test] - public void LeadingProtocolIsNotTreatedRelative() + FileSystemResource res = new FileSystemResource(new Uri(filePath).AbsoluteUri); + using (Stream s = res.InputStream) { - FileSystemResource res = new FileSystemResource(@"file://\\server\share\samples\artfair\"); - FileSystemResource res2 = (FileSystemResource) res.CreateRelative(@"file://./index.html"); - Assert.AreEqual(new Uri(Path.Combine(Environment.CurrentDirectory, "index.html")).AbsolutePath, res2.Uri.AbsolutePath); - } - - [Test] - public void RelativeUncResourceTooManyBackLevels() - { - FileSystemResource res = new FileSystemResource(@"\\server\share\samples\artfair\dummy.txt"); - Assert.Throws(() => res.CreateRelative(@"..\..\..\index.html")); - } - - [Test(Description="SPRNET-89")] - public void SPRNET_89_SupportUrlEncodedLocationsWithSpaces() - { - string path = Path.GetFullPath("spaced dir"); - Directory.CreateDirectory(path); - string filePath = Path.Combine(path, "spaced file.txt"); - using (StreamWriter text = File.CreateText(filePath)) + using (TextReader reader = new StreamReader(s)) { - text.WriteLine("hello world"); - } - FileSystemResource res = new FileSystemResource(new Uri(filePath).AbsoluteUri); - using (Stream s = res.InputStream) - { - using (TextReader reader = new StreamReader(s)) - { - Assert.AreEqual("hello world", reader.ReadLine()); - } + Assert.AreEqual("hello world", reader.ReadLine()); } } + } - [Test(Description = "http://opensource.atlassian.com/projects/spring/browse/SPRNET-320")] - public void SupportsSpecialUriCharacter() + [Test(Description = "http://opensource.atlassian.com/projects/spring/browse/SPRNET-320")] + public void SupportsSpecialUriCharacter() + { + string path = Path.GetFullPath("dir#"); + Directory.CreateDirectory(path); + string filePath = Path.Combine(path, "file.txt"); + using (StreamWriter text = File.CreateText(filePath)) { - string path = Path.GetFullPath("dir#"); - Directory.CreateDirectory(path); - string filePath = Path.Combine(path, "file.txt"); - using (StreamWriter text = File.CreateText(filePath)) + text.WriteLine("hello world"); + } + + FileSystemResource res = new FileSystemResource(new Uri(filePath).AbsoluteUri); + using (Stream s = res.InputStream) + { + using (TextReader reader = new StreamReader(s)) { - text.WriteLine("hello world"); - } - FileSystemResource res = new FileSystemResource(new Uri(filePath).AbsoluteUri); - using (Stream s = res.InputStream) - { - using (TextReader reader = new StreamReader(s)) - { - Assert.AreEqual("hello world", reader.ReadLine()); - } + Assert.AreEqual("hello world", reader.ReadLine()); } } + } - [Test] - public void Resolution_WithProtocolAndSpecialHomeCharacter() + [Test] + public void Resolution_WithProtocolAndSpecialHomeCharacter() + { + FileInfo file = CreateFileForTheCurrentDirectory(); + IResource res = new FileSystemResource("file://~/" + TemporaryFileName); + Assert.AreEqual(file.FullName, res.File.FullName, + "The file name with file://~ must have resolved to a file " + + "in the current directory of the currently executing domain."); + } + + [Test] + public void Resolution_WithProtocolAndSpecialHomeCharacterParentDirectory() + { + FileInfo file = new FileInfo(Path.GetFullPath( + Path.Combine(AppDomain.CurrentDomain.BaseDirectory, TemporaryFileName))); + IResource res = new FileSystemResource("file://~/../" + TemporaryFileName); + string fileNameOneDirectoryUp = file.Directory.Parent.FullName + "\\" + TemporaryFileName; + Assert.AreEqual(fileNameOneDirectoryUp, res.File.FullName, + "The file name with file://~/.. must have resolved to a file " + + "in the parent directory of the currently executing domain."); + } + + [Test] + public void CreateRelativeWithParent() + { + // use the filename of the declaring assembly as the root... + string rootpath = GetType().Assembly.Location; + DirectoryInfo rootdir = new DirectoryInfo(Path.GetDirectoryName(rootpath)); + _testCreateRelative(rootpath, rootdir.Parent.FullName, @"../"); + } + + [Test] + public void CreateRelativeWithSuperParent() + { + // use the filename of the declaring assembly as the root... + string rootpath = GetType().Assembly.Location; + DirectoryInfo rootdir = new DirectoryInfo(Path.GetDirectoryName(rootpath)); + _testCreateRelative(rootpath, rootdir.Parent.Parent.FullName, @"..\..\"); + } + + [Test] + public void CreateRelativeInSameDirectory() + { + // use the filename of the declaring assembly as the root... + string rootpath = GetType().Assembly.Location; + DirectoryInfo rootdir = new DirectoryInfo(Path.GetDirectoryName(rootpath)); + _testCreateRelative(rootpath, rootdir.FullName, @".\"); + } + + [Test] + public void CreateRelativeInSubdirectoryDirectory() + { + string subdirname = "Stuff"; + // use the filename of the declaring assembly as the root... + string rootpath = GetType().Assembly.Location; + DirectoryInfo rootdir = new DirectoryInfo(Path.GetDirectoryName(rootpath)); + DirectoryInfo subdir = rootdir.CreateSubdirectory(subdirname); + try { - FileInfo file = CreateFileForTheCurrentDirectory(); - IResource res = new FileSystemResource("file://~/" + TemporaryFileName); - Assert.AreEqual(file.FullName, res.File.FullName, - "The file name with file://~ must have resolved to a file " + - "in the current directory of the currently executing domain."); + _testCreateRelative(rootpath, subdir.FullName, subdirname + "/"); + // let's get obtuse... specify the parent directory of the subdirectory (i.e. the root directory again) + _testCreateRelative(rootpath, rootdir.FullName, subdirname + "/../"); } - - [Test] - public void Resolution_WithProtocolAndSpecialHomeCharacterParentDirectory() + finally { - FileInfo file = new FileInfo(Path.GetFullPath( - Path.Combine(AppDomain.CurrentDomain.BaseDirectory, TemporaryFileName))); - IResource res = new FileSystemResource("file://~/../" + TemporaryFileName); - string fileNameOneDirectoryUp = file.Directory.Parent.FullName + "\\" + TemporaryFileName; - Assert.AreEqual(fileNameOneDirectoryUp, res.File.FullName, - "The file name with file://~/.. must have resolved to a file " + - "in the parent directory of the currently executing domain."); - } - - [Test] - public void CreateRelativeWithParent() - { - // use the filename of the declaring assembly as the root... - string rootpath = GetType().Assembly.Location; - DirectoryInfo rootdir = new DirectoryInfo(Path.GetDirectoryName(rootpath)); - _testCreateRelative(rootpath, rootdir.Parent.FullName, @"../"); - } - - [Test] - public void CreateRelativeWithSuperParent() - { - // use the filename of the declaring assembly as the root... - string rootpath = GetType().Assembly.Location; - DirectoryInfo rootdir = new DirectoryInfo(Path.GetDirectoryName(rootpath)); - _testCreateRelative(rootpath, rootdir.Parent.Parent.FullName, @"..\..\"); - } - - [Test] - public void CreateRelativeInSameDirectory() - { - // use the filename of the declaring assembly as the root... - string rootpath = GetType().Assembly.Location; - DirectoryInfo rootdir = new DirectoryInfo(Path.GetDirectoryName(rootpath)); - _testCreateRelative(rootpath, rootdir.FullName, @".\"); - } - - [Test] - public void CreateRelativeInSubdirectoryDirectory() - { - string subdirname = "Stuff"; - // use the filename of the declaring assembly as the root... - string rootpath = GetType().Assembly.Location; - DirectoryInfo rootdir = new DirectoryInfo(Path.GetDirectoryName(rootpath)); - DirectoryInfo subdir = rootdir.CreateSubdirectory(subdirname); - try - { - _testCreateRelative(rootpath, subdir.FullName, subdirname + "/"); - // let's get obtuse... specify the parent directory of the subdirectory (i.e. the root directory again) - _testCreateRelative(rootpath, rootdir.FullName, subdirname + "/../"); - } - finally - { - if (subdir.Exists) - { - try - { - subdir.Delete(); - } - catch (IOException) - { - } - } - } - } - - /// - /// Helper method... - /// - private void _testCreateRelative(string rootPath, string targetPath, string relativePath) - { - string filename = "stuff.txt"; - FileInfo file = new FileInfo(Path.GetFullPath(Path.Combine(targetPath, filename))); - // create a temporary file in whatever 'targetpath' dir we've been passed... - StreamWriter writer = file.CreateText(); - // test that the CreateRelative () method works with the supplied 'relativePath' - IResource resource = new FileSystemResource(rootPath); - IResource relative = resource.CreateRelative(relativePath + filename); - Assert.IsTrue(relative.Exists); - if (file.Exists) + if (subdir.Exists) { try { - writer.Close(); - file.Delete(); + subdir.Delete(); } catch (IOException) { } } } + } - [Test] - public void RelativeLocalFileSystemResourceWhenNotRelative() + /// + /// Helper method... + /// + private void _testCreateRelative(string rootPath, string targetPath, string relativePath) + { + string filename = "stuff.txt"; + FileInfo file = new FileInfo(Path.GetFullPath(Path.Combine(targetPath, filename))); + // create a temporary file in whatever 'targetpath' dir we've been passed... + StreamWriter writer = file.CreateText(); + // test that the CreateRelative () method works with the supplied 'relativePath' + IResource resource = new FileSystemResource(rootPath); + IResource relative = resource.CreateRelative(relativePath + filename); + Assert.IsTrue(relative.Exists); + if (file.Exists) { - FileSystemResource res = new FileSystemResource(@"C:\dummy.txt"); - - IResource rel0 = res.CreateRelative(@"c:\index.html"); - Assert.IsTrue(rel0 is FileSystemResource); - Assert.AreEqual(@"file [c:\index.html]", rel0.Description); - } - - [Test] - public void RelativeLocalFileSystemResourceFromRoot() - { - FileSystemResource res = new FileSystemResource(@"c:\dummy.txt"); - - IResource rel0 = res.CreateRelative(@"\index.html"); - Assert.IsTrue(rel0 is FileSystemResource); - Assert.AreEqual(@"file [c:\index.html]", rel0.Description); - - IResource rel1 = res.CreateRelative(@"index.html"); - Assert.IsTrue(rel1 is FileSystemResource); - Assert.AreEqual(@"file [c:\index.html]", rel1.Description); - - IResource rel2 = res.CreateRelative(@"samples/artfair/index.html"); - Assert.IsTrue(rel2 is FileSystemResource); - Assert.AreEqual(@"file [c:\samples\artfair\index.html]", rel2.Description); - - IResource rel3 = res.CreateRelative(@".\samples\artfair\index.html"); - Assert.IsTrue(rel3 is FileSystemResource); - Assert.AreEqual(@"file [c:\samples\artfair\index.html]", rel3.Description); - } - - [Test] - public void RelativeLocalFileSystemResourceFromSubfolder() - { - FileSystemResource res = new FileSystemResource(@"c:\samples\artfair\dummy.txt"); - - IResource rel0 = res.CreateRelative(@"/index.html"); - Assert.IsTrue(rel0 is FileSystemResource); - Assert.AreEqual(@"file [c:\index.html]", rel0.Description); - - IResource rel1 = res.CreateRelative(@"index.html"); - Assert.IsTrue(rel1 is FileSystemResource); - Assert.AreEqual(@"file [c:\samples\artfair\index.html]", rel1.Description); - - IResource rel2 = res.CreateRelative(@"demo\index.html"); - Assert.IsTrue(rel2 is FileSystemResource); - Assert.AreEqual(@"file [c:\samples\artfair\demo\index.html]", rel2.Description); - - IResource rel3 = res.CreateRelative(@"./demo/index.html"); - Assert.IsTrue(rel3 is FileSystemResource); - Assert.AreEqual(@"file [c:\samples\artfair\demo\index.html]", rel3.Description); - - IResource rel4 = res.CreateRelative(@"../calculator/index.html"); - Assert.IsTrue(rel4 is FileSystemResource); - Assert.AreEqual(@"file [c:\samples\calculator\index.html]", rel4.Description); - - IResource rel5 = res.CreateRelative(@"..\..\index.html"); - Assert.IsTrue(rel5 is FileSystemResource); - Assert.AreEqual(@"file [c:\index.html]", rel5.Description); - } - - [Test] - public void RelativeUncResourceWhenNotRelative() - { - FileSystemResource res = new FileSystemResource(@"\\server\share\dummy.txt"); - - IResource rel0 = res.CreateRelative(@"\\server\share\index.html"); - Assert.IsTrue(rel0 is FileSystemResource); - Assert.AreEqual(@"file [\\server\share\index.html]", rel0.Description); - } - - [Test] - public void RelativeUncResourceFromRoot() - { - FileSystemResource res = new FileSystemResource(@"\\server\share\dummy.txt"); - - IResource rel0 = res.CreateRelative(@"\index.html"); - Assert.IsTrue(rel0 is FileSystemResource); - Assert.AreEqual(@"file [\\server\share\index.html]", rel0.Description); - - IResource rel1 = res.CreateRelative(@"index.html"); - Assert.IsTrue(rel1 is FileSystemResource); - Assert.AreEqual(@"file [\\server\share\index.html]", rel1.Description); - - IResource rel2 = res.CreateRelative(@"samples/artfair/index.html"); - Assert.IsTrue(rel2 is FileSystemResource); - Assert.AreEqual(@"file [\\server\share\samples\artfair\index.html]", rel2.Description); - - IResource rel3 = res.CreateRelative(@".\samples\artfair\index.html"); - Assert.IsTrue(rel3 is FileSystemResource); - Assert.AreEqual(@"file [\\server\share\samples\artfair\index.html]", rel3.Description); - } - - [Test] - public void RelativeUncResourceFromSubfolder() - { - FileSystemResource res = new FileSystemResource(@"\\server\share\samples\artfair\dummy.txt"); - - IResource rel0 = res.CreateRelative(@"/index.html"); - Assert.IsTrue(rel0 is FileSystemResource); - Assert.AreEqual(@"file [\\server\share\index.html]", rel0.Description); - - IResource rel1 = res.CreateRelative(@"index.html"); - Assert.IsTrue(rel1 is FileSystemResource); - Assert.AreEqual(@"file [\\server\share\samples\artfair\index.html]", rel1.Description); - - IResource rel2 = res.CreateRelative(@"demo\index.html"); - Assert.IsTrue(rel2 is FileSystemResource); - Assert.AreEqual(@"file [\\server\share\samples\artfair\demo\index.html]", rel2.Description); - - IResource rel3 = res.CreateRelative(@"./demo/index.html"); - Assert.IsTrue(rel3 is FileSystemResource); - Assert.AreEqual(@"file [\\server\share\samples\artfair\demo\index.html]", rel3.Description); - - IResource rel4 = res.CreateRelative(@"../calculator/index.html"); - Assert.IsTrue(rel4 is FileSystemResource); - Assert.AreEqual(@"file [\\server\share\samples\calculator\index.html]", rel4.Description); - - IResource rel5 = res.CreateRelative(@"..\..\index.html"); - Assert.IsTrue(rel5 is FileSystemResource); - Assert.AreEqual(@"file [\\server\share\index.html]", rel5.Description); + try + { + writer.Close(); + file.Delete(); + } + catch (IOException) + { + } } } -} \ No newline at end of file + + [Test] + public void RelativeLocalFileSystemResourceWhenNotRelative() + { + FileSystemResource res = new FileSystemResource(@"C:\dummy.txt"); + + IResource rel0 = res.CreateRelative(@"c:\index.html"); + Assert.IsTrue(rel0 is FileSystemResource); + Assert.AreEqual(@"file [c:\index.html]", rel0.Description); + } + + [Test] + public void RelativeLocalFileSystemResourceFromRoot() + { + FileSystemResource res = new FileSystemResource(@"c:\dummy.txt"); + + IResource rel0 = res.CreateRelative(@"\index.html"); + Assert.IsTrue(rel0 is FileSystemResource); + Assert.AreEqual(@"file [c:\index.html]", rel0.Description); + + IResource rel1 = res.CreateRelative(@"index.html"); + Assert.IsTrue(rel1 is FileSystemResource); + Assert.AreEqual(@"file [c:\index.html]", rel1.Description); + + IResource rel2 = res.CreateRelative(@"samples/artfair/index.html"); + Assert.IsTrue(rel2 is FileSystemResource); + Assert.AreEqual(@"file [c:\samples\artfair\index.html]", rel2.Description); + + IResource rel3 = res.CreateRelative(@".\samples\artfair\index.html"); + Assert.IsTrue(rel3 is FileSystemResource); + Assert.AreEqual(@"file [c:\samples\artfair\index.html]", rel3.Description); + } + + [Test] + public void RelativeLocalFileSystemResourceFromSubfolder() + { + FileSystemResource res = new FileSystemResource(@"c:\samples\artfair\dummy.txt"); + + IResource rel0 = res.CreateRelative(@"/index.html"); + Assert.IsTrue(rel0 is FileSystemResource); + Assert.AreEqual(@"file [c:\index.html]", rel0.Description); + + IResource rel1 = res.CreateRelative(@"index.html"); + Assert.IsTrue(rel1 is FileSystemResource); + Assert.AreEqual(@"file [c:\samples\artfair\index.html]", rel1.Description); + + IResource rel2 = res.CreateRelative(@"demo\index.html"); + Assert.IsTrue(rel2 is FileSystemResource); + Assert.AreEqual(@"file [c:\samples\artfair\demo\index.html]", rel2.Description); + + IResource rel3 = res.CreateRelative(@"./demo/index.html"); + Assert.IsTrue(rel3 is FileSystemResource); + Assert.AreEqual(@"file [c:\samples\artfair\demo\index.html]", rel3.Description); + + IResource rel4 = res.CreateRelative(@"../calculator/index.html"); + Assert.IsTrue(rel4 is FileSystemResource); + Assert.AreEqual(@"file [c:\samples\calculator\index.html]", rel4.Description); + + IResource rel5 = res.CreateRelative(@"..\..\index.html"); + Assert.IsTrue(rel5 is FileSystemResource); + Assert.AreEqual(@"file [c:\index.html]", rel5.Description); + } + + [Test] + public void RelativeUncResourceWhenNotRelative() + { + FileSystemResource res = new FileSystemResource(@"\\server\share\dummy.txt"); + + IResource rel0 = res.CreateRelative(@"\\server\share\index.html"); + Assert.IsTrue(rel0 is FileSystemResource); + Assert.AreEqual(@"file [\\server\share\index.html]", rel0.Description); + } + + [Test] + public void RelativeUncResourceFromRoot() + { + FileSystemResource res = new FileSystemResource(@"\\server\share\dummy.txt"); + + IResource rel0 = res.CreateRelative(@"\index.html"); + Assert.IsTrue(rel0 is FileSystemResource); + Assert.AreEqual(@"file [\\server\share\index.html]", rel0.Description); + + IResource rel1 = res.CreateRelative(@"index.html"); + Assert.IsTrue(rel1 is FileSystemResource); + Assert.AreEqual(@"file [\\server\share\index.html]", rel1.Description); + + IResource rel2 = res.CreateRelative(@"samples/artfair/index.html"); + Assert.IsTrue(rel2 is FileSystemResource); + Assert.AreEqual(@"file [\\server\share\samples\artfair\index.html]", rel2.Description); + + IResource rel3 = res.CreateRelative(@".\samples\artfair\index.html"); + Assert.IsTrue(rel3 is FileSystemResource); + Assert.AreEqual(@"file [\\server\share\samples\artfair\index.html]", rel3.Description); + } + + [Test] + public void RelativeUncResourceFromSubfolder() + { + FileSystemResource res = new FileSystemResource(@"\\server\share\samples\artfair\dummy.txt"); + + IResource rel0 = res.CreateRelative(@"/index.html"); + Assert.IsTrue(rel0 is FileSystemResource); + Assert.AreEqual(@"file [\\server\share\index.html]", rel0.Description); + + IResource rel1 = res.CreateRelative(@"index.html"); + Assert.IsTrue(rel1 is FileSystemResource); + Assert.AreEqual(@"file [\\server\share\samples\artfair\index.html]", rel1.Description); + + IResource rel2 = res.CreateRelative(@"demo\index.html"); + Assert.IsTrue(rel2 is FileSystemResource); + Assert.AreEqual(@"file [\\server\share\samples\artfair\demo\index.html]", rel2.Description); + + IResource rel3 = res.CreateRelative(@"./demo/index.html"); + Assert.IsTrue(rel3 is FileSystemResource); + Assert.AreEqual(@"file [\\server\share\samples\artfair\demo\index.html]", rel3.Description); + + IResource rel4 = res.CreateRelative(@"../calculator/index.html"); + Assert.IsTrue(rel4 is FileSystemResource); + Assert.AreEqual(@"file [\\server\share\samples\calculator\index.html]", rel4.Description); + + IResource rel5 = res.CreateRelative(@"..\..\index.html"); + Assert.IsTrue(rel5 is FileSystemResource); + Assert.AreEqual(@"file [\\server\share\index.html]", rel5.Description); + } +} diff --git a/test/Spring/Spring.Core.Tests/Core/IO/InputStreamResourceTests.cs b/test/Spring/Spring.Core.Tests/Core/IO/InputStreamResourceTests.cs index 628ef658..523f0504 100644 --- a/test/Spring/Spring.Core.Tests/Core/IO/InputStreamResourceTests.cs +++ b/test/Spring/Spring.Core.Tests/Core/IO/InputStreamResourceTests.cs @@ -24,84 +24,85 @@ using NUnit.Framework; #endregion -namespace Spring.Core.IO +namespace Spring.Core.IO; + +/// +/// Unit tests for the InputStreamResource class. +/// +/// Rick Evans +[TestFixture] +public sealed class InputStreamResourceTests { - /// - /// Unit tests for the InputStreamResource class. - /// - /// Rick Evans - [TestFixture] - public sealed class InputStreamResourceTests + [Test] + public void Instantiation() { - [Test] - public void Instantiation () + FileInfo file = null; + Stream stream = null; + try { - FileInfo file = null; - Stream stream = null; - try + file = new FileInfo("Instantiation"); + stream = file.Create(); + InputStreamResource res = new InputStreamResource(stream, "A temporary resource."); + Assert.IsTrue(res.IsOpen); + Assert.IsTrue(res.Exists); + Assert.IsNotNull(res.InputStream); + } + finally + { + try { - file = new FileInfo ("Instantiation"); - stream = file.Create (); - InputStreamResource res = new InputStreamResource (stream, "A temporary resource."); - Assert.IsTrue (res.IsOpen); - Assert.IsTrue (res.Exists); - Assert.IsNotNull (res.InputStream); - } - finally - { - try + if (stream != null) { - if (stream != null) - { - stream.Close (); - } - if (file != null - && file.Exists) - { - file.Delete (); - } - } - catch {} - } - } + stream.Close(); + } - [Test] - public void InstantiationWithNull () - { - Assert.Throws(() => new InputStreamResource (null, "A null resource.")); - } - - [Test] - public void ReadStreamMultipleTimes () - { - FileInfo file = null; - Stream stream = null; - try - { - file = new FileInfo ("ReadStreamMultipleTimes"); - stream = file.Create (); - // attempting to read this stream twice is an error... - InputStreamResource res = new InputStreamResource (stream, "A temporary resource."); - Stream streamOne = res.InputStream; - Stream streamTwo; - Assert.Throws(() => streamTwo = res.InputStream); // should bail here - } - finally - { - try + if (file != null + && file.Exists) { - if (stream != null) - { - stream.Close (); - } - if (file != null - && file.Exists) - { - file.Delete (); - } - } - catch {} + file.Delete(); + } } + catch { } } - } + } + + [Test] + public void InstantiationWithNull() + { + Assert.Throws(() => new InputStreamResource(null, "A null resource.")); + } + + [Test] + public void ReadStreamMultipleTimes() + { + FileInfo file = null; + Stream stream = null; + try + { + file = new FileInfo("ReadStreamMultipleTimes"); + stream = file.Create(); + // attempting to read this stream twice is an error... + InputStreamResource res = new InputStreamResource(stream, "A temporary resource."); + Stream streamOne = res.InputStream; + Stream streamTwo; + Assert.Throws(() => streamTwo = res.InputStream); // should bail here + } + finally + { + try + { + if (stream != null) + { + stream.Close(); + } + + if (file != null + && file.Exists) + { + file.Delete(); + } + } + catch { } + } + } } diff --git a/test/Spring/Spring.Core.Tests/Core/IO/ResourceConverterTests.cs b/test/Spring/Spring.Core.Tests/Core/IO/ResourceConverterTests.cs index fc56852f..37b2013f 100644 --- a/test/Spring/Spring.Core.Tests/Core/IO/ResourceConverterTests.cs +++ b/test/Spring/Spring.Core.Tests/Core/IO/ResourceConverterTests.cs @@ -25,95 +25,92 @@ using NUnit.Framework; #endregion -namespace Spring.Core.IO +namespace Spring.Core.IO; + +/// +/// Unit tests for the ResourceConverter class. +/// +/// Rick Evans +[TestFixture] +public sealed class ResourceConverterTests { - /// - /// Unit tests for the ResourceConverter class. - /// - /// Rick Evans - [TestFixture] - public sealed class ResourceConverterTests - { - /// - /// The setup logic executed before the execution of this test fixture. - /// - [OneTimeSetUp] - public void FixtureSetUp() - { - // enable (null appender) logging, just to ensure that the logging code is correct - LogManager.LoggerFactory = NullLoggerFactory.Instance; - } + /// + /// The setup logic executed before the execution of this test fixture. + /// + [OneTimeSetUp] + public void FixtureSetUp() + { + // enable (null appender) logging, just to ensure that the logging code is correct + LogManager.LoggerFactory = NullLoggerFactory.Instance; + } - [Test] - public void CanConvertFrom() - { - ResourceConverter vrt = new ResourceConverter(); - Assert.IsTrue(vrt.CanConvertFrom(typeof (string)), "Conversion from a string instance must be supported."); - Assert.IsFalse(vrt.CanConvertFrom(typeof (int))); - } + [Test] + public void CanConvertFrom() + { + ResourceConverter vrt = new ResourceConverter(); + Assert.IsTrue(vrt.CanConvertFrom(typeof(string)), "Conversion from a string instance must be supported."); + Assert.IsFalse(vrt.CanConvertFrom(typeof(int))); + } - [Test] - public void ConvertFrom() - { - ResourceConverter vrt = new ResourceConverter(); - object actual = vrt.ConvertFrom("file://localhost/"); - Assert.IsNotNull(actual); - IResource res = actual as IResource; - Assert.IsNotNull(res); - Assert.IsFalse(res.Exists); - } + [Test] + public void ConvertFrom() + { + ResourceConverter vrt = new ResourceConverter(); + object actual = vrt.ConvertFrom("file://localhost/"); + Assert.IsNotNull(actual); + IResource res = actual as IResource; + Assert.IsNotNull(res); + Assert.IsFalse(res.Exists); + } - [Test] - public void ConvertFromNullReference() - { - ResourceConverter vrt = new ResourceConverter(); - Assert.Throws(() => vrt.ConvertFrom(null)); - } + [Test] + public void ConvertFromNullReference() + { + ResourceConverter vrt = new ResourceConverter(); + Assert.Throws(() => vrt.ConvertFrom(null)); + } - [Test] - public void ConvertFromNonSupportedOptionBails() - { - ResourceConverter vrt = new ResourceConverter(); - Assert.Throws(() => vrt.ConvertFrom(new TestFixtureAttribute())); - } + [Test] + public void ConvertFromNonSupportedOptionBails() + { + ResourceConverter vrt = new ResourceConverter(); + Assert.Throws(() => vrt.ConvertFrom(new TestFixtureAttribute())); + } - [Test] - [Platform("Win")] - public void ConvertFromWithEnvironmentVariableExpansion() - { - string filename = Guid.NewGuid().ToString(); + [Test] + [Platform("Win")] + public void ConvertFromWithEnvironmentVariableExpansion() + { + string filename = Guid.NewGuid().ToString(); - // TODO : won't pass on anything other than Win9x boxes... - ResourceConverter vrt = new ResourceConverter(); - string path = string.Format(@"${{userprofile}}\{0}.txt", filename); - IResource resource = (IResource) vrt.ConvertFrom(path); + // TODO : won't pass on anything other than Win9x boxes... + ResourceConverter vrt = new ResourceConverter(); + string path = string.Format(@"${{userprofile}}\{0}.txt", filename); + IResource resource = (IResource) vrt.ConvertFrom(path); - string userprofile = Environment.GetEnvironmentVariable("userprofile"); + string userprofile = Environment.GetEnvironmentVariable("userprofile"); - Assert.IsFalse(resource.Exists, - string.Format("Darn. Should be supplying a rubbish non-existant resource. " + - "You don't actually have a file called '{0}.txt' in your user directory do you?", filename)); - Assert.IsTrue(resource.Description.IndexOf(userprofile) > -1, - "Environment variable not expanded."); - } + Assert.IsFalse(resource.Exists, + string.Format("Darn. Should be supplying a rubbish non-existant resource. " + + "You don't actually have a file called '{0}.txt' in your user directory do you?", filename)); + Assert.IsTrue(resource.Description.IndexOf(userprofile) > -1, + "Environment variable not expanded."); + } - [Test] - public void DoesNotChokeOnUnresolvableEnvironmentVariableExpansion() - { - string foldername = Guid.NewGuid().ToString(); - string filename = Guid.NewGuid().ToString(); + [Test] + public void DoesNotChokeOnUnresolvableEnvironmentVariableExpansion() + { + string foldername = Guid.NewGuid().ToString(); + string filename = Guid.NewGuid().ToString(); - ResourceConverter vrt = new ResourceConverter(); - string path = string.Format(@"${{{0}}}\{1}.txt", foldername, filename); - IResource resource = (IResource) vrt.ConvertFrom(path); + ResourceConverter vrt = new ResourceConverter(); + string path = string.Format(@"${{{0}}}\{1}.txt", foldername, filename); + IResource resource = (IResource) vrt.ConvertFrom(path); - Assert.IsFalse(resource.Exists, - string.Format("Darn. Should be supplying a rubbish non-existant resource. " + - "You don't actually have a file called '{0}.txt' in your user directory do you?", filename)); - Assert.IsTrue(resource.Description.IndexOf(foldername) > -1, - "Rubbish environment variable not preserved as-is."); - - - } - } + Assert.IsFalse(resource.Exists, + string.Format("Darn. Should be supplying a rubbish non-existant resource. " + + "You don't actually have a file called '{0}.txt' in your user directory do you?", filename)); + Assert.IsTrue(resource.Description.IndexOf(foldername) > -1, + "Rubbish environment variable not preserved as-is."); + } } diff --git a/test/Spring/Spring.Core.Tests/Core/IO/ResourceHandlerRegistryTests.cs b/test/Spring/Spring.Core.Tests/Core/IO/ResourceHandlerRegistryTests.cs index 5109ab1e..708335a0 100644 --- a/test/Spring/Spring.Core.Tests/Core/IO/ResourceHandlerRegistryTests.cs +++ b/test/Spring/Spring.Core.Tests/Core/IO/ResourceHandlerRegistryTests.cs @@ -24,98 +24,97 @@ using NUnit.Framework; #endregion -namespace Spring.Core.IO +namespace Spring.Core.IO; + +/// +/// Unit tests for the ConfigurableResourceLoader class. +/// +/// Aleksandar Seovic +[TestFixture] +public sealed class ResourceHandlerRegistryTests { - /// - /// Unit tests for the ConfigurableResourceLoader class. - /// - /// Aleksandar Seovic - [TestFixture] - public sealed class ResourceHandlerRegistryTests - { - [Test] - public void WithNullProtocolName() - { - Assert.Throws(() => ResourceHandlerRegistry.RegisterResourceHandler(null, GetType())); - } + [Test] + public void WithNullProtocolName() + { + Assert.Throws(() => ResourceHandlerRegistry.RegisterResourceHandler(null, GetType())); + } - [Test] - public void WithNullIResourceHandlerType() - { - Assert.Throws(() => ResourceHandlerRegistry.RegisterResourceHandler("beep", (Type) null)); - } + [Test] + public void WithNullIResourceHandlerType() + { + Assert.Throws(() => ResourceHandlerRegistry.RegisterResourceHandler("beep", (Type) null)); + } - [Test] - public void WithWhitespacedProtocolName() - { - Assert.Throws(() => ResourceHandlerRegistry.RegisterResourceHandler("\t ", GetType())); - } + [Test] + public void WithWhitespacedProtocolName() + { + Assert.Throws(() => ResourceHandlerRegistry.RegisterResourceHandler("\t ", GetType())); + } - [Test] - public void WithNonIResourceHandlerType() - { - Assert.Throws(() => ResourceHandlerRegistry.RegisterResourceHandler("beep", GetType())); - } + [Test] + public void WithNonIResourceHandlerType() + { + Assert.Throws(() => ResourceHandlerRegistry.RegisterResourceHandler("beep", GetType())); + } - [Test] - public void WithIResourceHandlerTypeWithNoValidCtor() - { - Assert.Throws(() => ResourceHandlerRegistry.RegisterResourceHandler("beep", typeof(IncompatibleResource))); - } + [Test] + public void WithIResourceHandlerTypeWithNoValidCtor() + { + Assert.Throws(() => ResourceHandlerRegistry.RegisterResourceHandler("beep", typeof(IncompatibleResource))); + } - [Test] - public void AddProtocolMappingSilentlyOverwritesExistingProtocol() + [Test] + public void AddProtocolMappingSilentlyOverwritesExistingProtocol() + { + ResourceHandlerRegistry.RegisterResourceHandler("beep", typeof(FileSystemResource)); + // overwrite, must not complain... + ResourceHandlerRegistry.RegisterResourceHandler("beep", typeof(AssemblyResource)); + IResource res = new ConfigurableResourceLoader().GetResource("beep://Spring.Core.Tests/Spring/TestResource.txt"); + Assert.IsNotNull(res, "Resource must not be null"); + Assert.AreEqual(typeof(AssemblyResource), res.GetType(), + "The original IResource Type associated with the 'beep' protocol " + + "must have been overwritten; expecting an AssemblyResource 'cos " + + "we registered it last under the 'beep' protocol."); + } + + /// + /// Deso not expose a constructor that takes a single string argument. + /// + private sealed class IncompatibleResource : IResource + { + public bool IsOpen { - ResourceHandlerRegistry.RegisterResourceHandler("beep", typeof(FileSystemResource)); - // overwrite, must not complain... - ResourceHandlerRegistry.RegisterResourceHandler("beep", typeof(AssemblyResource)); - IResource res = new ConfigurableResourceLoader().GetResource("beep://Spring.Core.Tests/Spring/TestResource.txt"); - Assert.IsNotNull(res, "Resource must not be null"); - Assert.AreEqual(typeof(AssemblyResource), res.GetType(), - "The original IResource Type associated with the 'beep' protocol " + - "must have been overwritten; expecting an AssemblyResource 'cos " + - "we registered it last under the 'beep' protocol."); + get { throw new NotImplementedException(); } } - /// - /// Deso not expose a constructor that takes a single string argument. - /// - private sealed class IncompatibleResource : IResource - { - public bool IsOpen - { - get { throw new NotImplementedException(); } - } + public Uri Uri + { + get { throw new NotImplementedException(); } + } - public Uri Uri - { - get { throw new NotImplementedException(); } - } + public FileInfo File + { + get { throw new NotImplementedException(); } + } - public FileInfo File - { - get { throw new NotImplementedException(); } - } + public string Description + { + get { throw new NotImplementedException(); } + } - public string Description - { - get { throw new NotImplementedException(); } - } + public bool Exists + { + get { throw new NotImplementedException(); } + } - public bool Exists - { - get { throw new NotImplementedException(); } - } + public IResource CreateRelative(string relativePath) + { + throw new NotImplementedException(); + } - public IResource CreateRelative(string relativePath) - { - throw new NotImplementedException(); - } - - public Stream InputStream - { - get { throw new NotImplementedException(); } - } - } - } + public Stream InputStream + { + get { throw new NotImplementedException(); } + } + } } \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/Core/IO/StringResourceTests.cs b/test/Spring/Spring.Core.Tests/Core/IO/StringResourceTests.cs index 777670a4..a8581d87 100644 --- a/test/Spring/Spring.Core.Tests/Core/IO/StringResourceTests.cs +++ b/test/Spring/Spring.Core.Tests/Core/IO/StringResourceTests.cs @@ -25,79 +25,78 @@ using NUnit.Framework; #endregion -namespace Spring.Core.IO +namespace Spring.Core.IO; + +/// +/// +/// +/// Erich Eichinger +[TestFixture] +public class StringResourceTests { - /// - /// - /// - /// Erich Eichinger - [TestFixture] - public class StringResourceTests + [Test] + public void EnsureDefaults() { - [Test] - public void EnsureDefaults() - { - Encoding enc = Encoding.Default; - string FOO_CONTENT = "foo"; - string FOO_DESCRIPTION = "foo description"; + Encoding enc = Encoding.Default; + string FOO_CONTENT = "foo"; + string FOO_DESCRIPTION = "foo description"; - StringResource r = new StringResource(FOO_CONTENT); - Assert.AreEqual(FOO_CONTENT, r.Content); - Assert.AreEqual(enc, r.Encoding); - Assert.AreEqual(string.Empty, r.Description); + StringResource r = new StringResource(FOO_CONTENT); + Assert.AreEqual(FOO_CONTENT, r.Content); + Assert.AreEqual(enc, r.Encoding); + Assert.AreEqual(string.Empty, r.Description); - enc = new UTF7Encoding(); - r = new StringResource(FOO_CONTENT, enc, FOO_DESCRIPTION); - Assert.AreEqual(FOO_CONTENT, r.Content); - Assert.AreEqual(enc, r.Encoding); - Assert.AreEqual(FOO_DESCRIPTION, r.Description); - } - - [Test] - public void ReturnsCorrectEncodedStream() - { - string FOO_CONTENT = "foo\u4567"; - StringResource r = new StringResource(FOO_CONTENT, Encoding.GetEncoding("utf-16")); - Assert.AreEqual(FOO_CONTENT, r.Content); - Stream istm = r.InputStream; - Assert.IsTrue(istm.CanRead); - - byte[] chars = new byte[istm.Length]; - istm.Read(chars, 0, chars.Length); - istm.Close(); - string result = Encoding.GetEncoding("utf-16").GetString( chars ); - Assert.AreEqual(FOO_CONTENT, result); - } - - [Test] - public void DoesntSupportRelativeResources() - { - StringResource r = new StringResource(string.Empty); - Assert.Throws(() => r.CreateRelative("foo")); - } - - [Test] - public void AcceptsNullContent() - { - Encoding utf7 = new UTF7Encoding(); - StringResource r = new StringResource(null, utf7); - Assert.AreEqual(string.Empty, r.Content); - Stream stm = r.InputStream; - Assert.IsTrue(stm.CanRead); - Assert.IsNotNull(stm); - Assert.AreEqual(0, stm.Length); - stm.Close(); - } - - [Test] - public void AlwaysExists() - { - StringResource r = new StringResource(null); - Assert.IsTrue(r.Exists); - r = new StringResource(string.Empty); - Assert.IsTrue(r.Exists); - r = new StringResource("foo"); - Assert.IsTrue(r.Exists); - } + enc = new UTF7Encoding(); + r = new StringResource(FOO_CONTENT, enc, FOO_DESCRIPTION); + Assert.AreEqual(FOO_CONTENT, r.Content); + Assert.AreEqual(enc, r.Encoding); + Assert.AreEqual(FOO_DESCRIPTION, r.Description); } -} \ No newline at end of file + + [Test] + public void ReturnsCorrectEncodedStream() + { + string FOO_CONTENT = "foo\u4567"; + StringResource r = new StringResource(FOO_CONTENT, Encoding.GetEncoding("utf-16")); + Assert.AreEqual(FOO_CONTENT, r.Content); + Stream istm = r.InputStream; + Assert.IsTrue(istm.CanRead); + + byte[] chars = new byte[istm.Length]; + istm.Read(chars, 0, chars.Length); + istm.Close(); + string result = Encoding.GetEncoding("utf-16").GetString(chars); + Assert.AreEqual(FOO_CONTENT, result); + } + + [Test] + public void DoesntSupportRelativeResources() + { + StringResource r = new StringResource(string.Empty); + Assert.Throws(() => r.CreateRelative("foo")); + } + + [Test] + public void AcceptsNullContent() + { + Encoding utf7 = new UTF7Encoding(); + StringResource r = new StringResource(null, utf7); + Assert.AreEqual(string.Empty, r.Content); + Stream stm = r.InputStream; + Assert.IsTrue(stm.CanRead); + Assert.IsNotNull(stm); + Assert.AreEqual(0, stm.Length); + stm.Close(); + } + + [Test] + public void AlwaysExists() + { + StringResource r = new StringResource(null); + Assert.IsTrue(r.Exists); + r = new StringResource(string.Empty); + Assert.IsTrue(r.Exists); + r = new StringResource("foo"); + Assert.IsTrue(r.Exists); + } +} diff --git a/test/Spring/Spring.Core.Tests/Core/IO/UrlResourceTest.cs b/test/Spring/Spring.Core.Tests/Core/IO/UrlResourceTest.cs index e551dd4b..83d5d98c 100644 --- a/test/Spring/Spring.Core.Tests/Core/IO/UrlResourceTest.cs +++ b/test/Spring/Spring.Core.Tests/Core/IO/UrlResourceTest.cs @@ -24,137 +24,136 @@ using NUnit.Framework; #endregion -namespace Spring.Core.IO +namespace Spring.Core.IO; + +/// +/// Unit tests for the UrlResource class. +/// +[TestFixture] +public sealed class UrlResourceTests { - /// - /// Unit tests for the UrlResource class. - /// - [TestFixture] - public sealed class UrlResourceTests + private const string FILE_PROTOCOL_PREFIX = "file:///"; + + [Test] + public void CreateUrlResourceWithGivenPath() { - private const string FILE_PROTOCOL_PREFIX = "file:///"; + UrlResource urlResource = new UrlResource(FILE_PROTOCOL_PREFIX + "C:/temp"); + Assert.AreEqual("C:/temp", urlResource.Uri.AbsolutePath); + } - [Test] - public void CreateUrlResourceWithGivenPath() + [Test] + public void CreateInvalidUrlResource() + { + string uri = null; + Assert.Throws(() => new UrlResource(uri)); + } + + [Test] + [Platform("Win")] + public void GetValidFileInfo() + { + UrlResource urlResource = new UrlResource(FILE_PROTOCOL_PREFIX + "C:/temp"); + Assert.AreEqual("C:\\temp", urlResource.File.FullName); + } + + [Test, Explicit] + public void ExistsValidHttp() + { + UrlResource urlResource = new UrlResource("http://www.springframework.net/"); + Assert.IsTrue(urlResource.Exists); + } + + [Test] + public void GetInvalidFileInfo() + { + UrlResource urlResource = new UrlResource("http://www.springframework.net/"); + FileInfo file; + Assert.Throws(() => file = urlResource.File); + } + + [Test] + public void GetInvalidFileInfoWithOddPort() + { + UrlResource urlResource = new UrlResource("http://www.springframework.net:76/"); + FileInfo temp; + Assert.Throws(() => temp = urlResource.File); + } + + [Test] + public void GetDescription() + { + UrlResource urlResource = new UrlResource(FILE_PROTOCOL_PREFIX + "C:/temp"); + Assert.AreEqual("URL [file:///C:/temp]", urlResource.Description); + } + + [Test] + public void GetValidInputStreamForFileProtocol() + { + string fileName = Path.GetTempFileName(); + FileStream fs = File.Create(fileName); + fs.Close(); + using (Stream inputStream = new UrlResource(FILE_PROTOCOL_PREFIX + fileName).InputStream) { - UrlResource urlResource = new UrlResource(FILE_PROTOCOL_PREFIX + "C:/temp"); - Assert.AreEqual("C:/temp", urlResource.Uri.AbsolutePath); - } - - [Test] - public void CreateInvalidUrlResource() - { - string uri = null; - Assert.Throws(() => new UrlResource(uri)); - } - - [Test] - [Platform("Win")] - public void GetValidFileInfo() - { - UrlResource urlResource = new UrlResource(FILE_PROTOCOL_PREFIX + "C:/temp"); - Assert.AreEqual("C:\\temp", urlResource.File.FullName); - } - - [Test, Explicit] - public void ExistsValidHttp() - { - UrlResource urlResource = new UrlResource("http://www.springframework.net/"); - Assert.IsTrue(urlResource.Exists); - } - - [Test] - public void GetInvalidFileInfo() - { - UrlResource urlResource = new UrlResource("http://www.springframework.net/"); - FileInfo file; - Assert.Throws(() => file = urlResource.File); - } - - [Test] - public void GetInvalidFileInfoWithOddPort() - { - UrlResource urlResource = new UrlResource("http://www.springframework.net:76/"); - FileInfo temp; - Assert.Throws(() => temp = urlResource.File); - } - - [Test] - public void GetDescription() - { - UrlResource urlResource = new UrlResource(FILE_PROTOCOL_PREFIX + "C:/temp"); - Assert.AreEqual("URL [file:///C:/temp]", urlResource.Description); - } - - [Test] - public void GetValidInputStreamForFileProtocol() - { - string fileName = Path.GetTempFileName(); - FileStream fs = File.Create(fileName); - fs.Close(); - using (Stream inputStream = new UrlResource(FILE_PROTOCOL_PREFIX + fileName).InputStream) - { - Assert.IsTrue(inputStream.CanRead); - } - } - - [Test] - public void RelativeResourceFromRoot() - { - UrlResource res = new UrlResource("http://www.springframework.net/documentation.html"); - - IResource rel0 = res.CreateRelative("/index.html"); - Assert.IsTrue(rel0 is UrlResource); - Assert.AreEqual("URL [http://www.springframework.net/index.html]", rel0.Description); - - IResource rel1 = res.CreateRelative("index.html"); - Assert.IsTrue(rel1 is UrlResource); - Assert.AreEqual("URL [http://www.springframework.net/index.html]", rel1.Description); - - IResource rel2 = res.CreateRelative("samples/artfair/index.html"); - Assert.IsTrue(rel2 is UrlResource); - Assert.AreEqual("URL [http://www.springframework.net/samples/artfair/index.html]", rel2.Description); - - IResource rel3 = res.CreateRelative("./samples/artfair/index.html"); - Assert.IsTrue(rel3 is UrlResource); - Assert.AreEqual("URL [http://www.springframework.net/samples/artfair/index.html]", rel3.Description); - } - - [Test] - public void RelativeResourceFromSubfolder() - { - UrlResource res = new UrlResource("http://www.springframework.net/samples/artfair/download.html"); - - IResource rel0 = res.CreateRelative("/index.html"); - Assert.IsTrue(rel0 is UrlResource); - Assert.AreEqual("URL [http://www.springframework.net/index.html]", rel0.Description); - - IResource rel1 = res.CreateRelative("index.html"); - Assert.IsTrue(rel1 is UrlResource); - Assert.AreEqual("URL [http://www.springframework.net/samples/artfair/index.html]", rel1.Description); - - IResource rel2 = res.CreateRelative("demo/index.html"); - Assert.IsTrue(rel2 is UrlResource); - Assert.AreEqual("URL [http://www.springframework.net/samples/artfair/demo/index.html]", rel2.Description); - - IResource rel3 = res.CreateRelative("./demo/index.html"); - Assert.IsTrue(rel3 is UrlResource); - Assert.AreEqual("URL [http://www.springframework.net/samples/artfair/demo/index.html]", rel3.Description); - - IResource rel4 = res.CreateRelative("../calculator/index.html"); - Assert.IsTrue(rel4 is UrlResource); - Assert.AreEqual("URL [http://www.springframework.net/samples/calculator/index.html]", rel4.Description); - - IResource rel5 = res.CreateRelative("../../index.html"); - Assert.IsTrue(rel5 is UrlResource); - Assert.AreEqual("URL [http://www.springframework.net/index.html]", rel5.Description); - } - - [Test] - public void RelativeResourceTooManyBackLevels() - { - UrlResource res = new UrlResource("http://www.springframework.net/samples/artfair/download.html"); - Assert.Throws(() => res.CreateRelative("../../../index.html")); + Assert.IsTrue(inputStream.CanRead); } } -} \ No newline at end of file + + [Test] + public void RelativeResourceFromRoot() + { + UrlResource res = new UrlResource("http://www.springframework.net/documentation.html"); + + IResource rel0 = res.CreateRelative("/index.html"); + Assert.IsTrue(rel0 is UrlResource); + Assert.AreEqual("URL [http://www.springframework.net/index.html]", rel0.Description); + + IResource rel1 = res.CreateRelative("index.html"); + Assert.IsTrue(rel1 is UrlResource); + Assert.AreEqual("URL [http://www.springframework.net/index.html]", rel1.Description); + + IResource rel2 = res.CreateRelative("samples/artfair/index.html"); + Assert.IsTrue(rel2 is UrlResource); + Assert.AreEqual("URL [http://www.springframework.net/samples/artfair/index.html]", rel2.Description); + + IResource rel3 = res.CreateRelative("./samples/artfair/index.html"); + Assert.IsTrue(rel3 is UrlResource); + Assert.AreEqual("URL [http://www.springframework.net/samples/artfair/index.html]", rel3.Description); + } + + [Test] + public void RelativeResourceFromSubfolder() + { + UrlResource res = new UrlResource("http://www.springframework.net/samples/artfair/download.html"); + + IResource rel0 = res.CreateRelative("/index.html"); + Assert.IsTrue(rel0 is UrlResource); + Assert.AreEqual("URL [http://www.springframework.net/index.html]", rel0.Description); + + IResource rel1 = res.CreateRelative("index.html"); + Assert.IsTrue(rel1 is UrlResource); + Assert.AreEqual("URL [http://www.springframework.net/samples/artfair/index.html]", rel1.Description); + + IResource rel2 = res.CreateRelative("demo/index.html"); + Assert.IsTrue(rel2 is UrlResource); + Assert.AreEqual("URL [http://www.springframework.net/samples/artfair/demo/index.html]", rel2.Description); + + IResource rel3 = res.CreateRelative("./demo/index.html"); + Assert.IsTrue(rel3 is UrlResource); + Assert.AreEqual("URL [http://www.springframework.net/samples/artfair/demo/index.html]", rel3.Description); + + IResource rel4 = res.CreateRelative("../calculator/index.html"); + Assert.IsTrue(rel4 is UrlResource); + Assert.AreEqual("URL [http://www.springframework.net/samples/calculator/index.html]", rel4.Description); + + IResource rel5 = res.CreateRelative("../../index.html"); + Assert.IsTrue(rel5 is UrlResource); + Assert.AreEqual("URL [http://www.springframework.net/index.html]", rel5.Description); + } + + [Test] + public void RelativeResourceTooManyBackLevels() + { + UrlResource res = new UrlResource("http://www.springframework.net/samples/artfair/download.html"); + Assert.Throws(() => res.CreateRelative("../../../index.html")); + } +} diff --git a/test/Spring/Spring.Core.Tests/Core/MethodArgumentsCriteriaTests.cs b/test/Spring/Spring.Core.Tests/Core/MethodArgumentsCriteriaTests.cs index 1eb3e731..4a8bc0e6 100644 --- a/test/Spring/Spring.Core.Tests/Core/MethodArgumentsCriteriaTests.cs +++ b/test/Spring/Spring.Core.Tests/Core/MethodArgumentsCriteriaTests.cs @@ -21,103 +21,102 @@ #region Imports using System.Reflection; - using NUnit.Framework; using Spring.Objects; #endregion -namespace Spring.Core +namespace Spring.Core; + +/// +/// Unit tests for the MethodArgumentsCriteria class. +/// +/// Rick Evans +/// Bruno Baia +[TestFixture] +public sealed class MethodArgumentsCriteriaTests { - /// - /// Unit tests for the MethodArgumentsCriteria class. - /// - /// Rick Evans - /// Bruno Baia - [TestFixture] - public sealed class MethodArgumentsCriteriaTests + [Test] + public void IsNotSatisfiedWithNull() { - [Test] - public void IsNotSatisfiedWithNull() { - MethodArgumentsCriteria criteria = new MethodArgumentsCriteria(); - Assert.IsFalse (criteria.IsSatisfied (null), "Was satisified with null."); - } + MethodArgumentsCriteria criteria = new MethodArgumentsCriteria(); + Assert.IsFalse(criteria.IsSatisfied(null), "Was satisified with null."); + } - [Test] - public void IsSatisfiedWithNoParametersByDefault() - { - MethodArgumentsCriteria criteria = new MethodArgumentsCriteria(); - MethodInfo method = GetType().GetMethod ("Foo"); - Assert.IsTrue (criteria.IsSatisfied (method), "Was not satisified with a method that takes no parameters by default."); - } + [Test] + public void IsSatisfiedWithNoParametersByDefault() + { + MethodArgumentsCriteria criteria = new MethodArgumentsCriteria(); + MethodInfo method = GetType().GetMethod("Foo"); + Assert.IsTrue(criteria.IsSatisfied(method), "Was not satisified with a method that takes no parameters by default."); + } - [Test] - public void IsSatisfied() - { - MethodArgumentsCriteria criteria = new MethodArgumentsCriteria( - new Object[] { "Bruno", DateTime.Now, new TestObject("Bruno", 29) }); - MethodInfo method = GetType ().GetMethod ("BoJangles"); - Assert.IsTrue (criteria.IsSatisfied (method), "Was not satisified with a method that takes a whole buncha parameters."); + [Test] + public void IsSatisfied() + { + MethodArgumentsCriteria criteria = new MethodArgumentsCriteria( + new Object[] { "Bruno", DateTime.Now, new TestObject("Bruno", 29) }); + MethodInfo method = GetType().GetMethod("BoJangles"); + Assert.IsTrue(criteria.IsSatisfied(method), "Was not satisified with a method that takes a whole buncha parameters."); - method = GetType().GetMethod ("BadBobbyBoJangles"); - Assert.IsFalse (criteria.IsSatisfied (method), "Was satisified with a (bad) method that takes a whole buncha parameters."); - } + method = GetType().GetMethod("BadBobbyBoJangles"); + Assert.IsFalse(criteria.IsSatisfied(method), "Was satisified with a (bad) method that takes a whole buncha parameters."); + } - [Test] - public void IsSatisfiedIsPolymorphic() - { - // i.e. derived types satisfy the criteria if a base type or interface is - // specified as one of the parameter types - MethodArgumentsCriteria criteria - = new MethodArgumentsCriteria(new Object[] { new TestObject("Bruno", 29) }); - MethodInfo method = GetType().GetMethod ("Diddly"); - Assert.IsTrue (criteria.IsSatisfied (method), "Was not satisified with a method that takes a base class as a parameter."); - } + [Test] + public void IsSatisfiedIsPolymorphic() + { + // i.e. derived types satisfy the criteria if a base type or interface is + // specified as one of the parameter types + MethodArgumentsCriteria criteria + = new MethodArgumentsCriteria(new Object[] { new TestObject("Bruno", 29) }); + MethodInfo method = GetType().GetMethod("Diddly"); + Assert.IsTrue(criteria.IsSatisfied(method), "Was not satisified with a method that takes a base class as a parameter."); + } - [Test] - public void IsSatisfiedWithParamsArguments() - { - MethodArgumentsCriteria criteria = new MethodArgumentsCriteria(new Object[] { 29, "Bruno" }); - MethodInfo method = GetType().GetMethod("ParamsArguments"); - Assert.IsTrue(criteria.IsSatisfied(method), "Was not satisified with a method that takes a parameter array ('params') as a parameter."); + [Test] + public void IsSatisfiedWithParamsArguments() + { + MethodArgumentsCriteria criteria = new MethodArgumentsCriteria(new Object[] { 29, "Bruno" }); + MethodInfo method = GetType().GetMethod("ParamsArguments"); + Assert.IsTrue(criteria.IsSatisfied(method), "Was not satisified with a method that takes a parameter array ('params') as a parameter."); - criteria = new MethodArgumentsCriteria(new Object[] { 29, new string[] { "Bruno", "Rick" } }); - method = GetType().GetMethod("ParamsArguments"); - Assert.IsTrue(criteria.IsSatisfied(method), "Was not satisified with a method that takes a parameter array ('params') as a parameter."); + criteria = new MethodArgumentsCriteria(new Object[] { 29, new string[] { "Bruno", "Rick" } }); + method = GetType().GetMethod("ParamsArguments"); + Assert.IsTrue(criteria.IsSatisfied(method), "Was not satisified with a method that takes a parameter array ('params') as a parameter."); - criteria = new MethodArgumentsCriteria(new Object[] { 29 }); - method = GetType().GetMethod("ParamsArguments"); - Assert.IsTrue(criteria.IsSatisfied(method), "Was not satisified with a method that takes a parameter array ('params') as a parameter."); + criteria = new MethodArgumentsCriteria(new Object[] { 29 }); + method = GetType().GetMethod("ParamsArguments"); + Assert.IsTrue(criteria.IsSatisfied(method), "Was not satisified with a method that takes a parameter array ('params') as a parameter."); - criteria = new MethodArgumentsCriteria(new Object[] { 29, "Bruno", "Rick", "James" }); - method = GetType().GetMethod("ParamsArguments"); - Assert.IsTrue(criteria.IsSatisfied(method), "Was not satisified with a method that takes a parameter array ('params') as a parameter."); + criteria = new MethodArgumentsCriteria(new Object[] { 29, "Bruno", "Rick", "James" }); + method = GetType().GetMethod("ParamsArguments"); + Assert.IsTrue(criteria.IsSatisfied(method), "Was not satisified with a method that takes a parameter array ('params') as a parameter."); - criteria = new MethodArgumentsCriteria(new Object[] { 29, new string[] { "Bruno", "Rick" }, "James" }); - method = GetType().GetMethod("ParamsArguments"); - Assert.IsFalse(criteria.IsSatisfied(method), "Was not satisified with a method that takes a parameter array ('params') as a parameter."); - } + criteria = new MethodArgumentsCriteria(new Object[] { 29, new string[] { "Bruno", "Rick" }, "James" }); + method = GetType().GetMethod("ParamsArguments"); + Assert.IsFalse(criteria.IsSatisfied(method), "Was not satisified with a method that takes a parameter array ('params') as a parameter."); + } - // some methods for testing signatures... - public void Foo () - { - } + // some methods for testing signatures... + public void Foo() + { + } - public DateTime BoJangles (string one, DateTime two, TestObject three) - { - return DateTime.Now; - } + public DateTime BoJangles(string one, DateTime two, TestObject three) + { + return DateTime.Now; + } - public void BadBobbyBoJangles(string one, DateTime two, string bing) - { - } + public void BadBobbyBoJangles(string one, DateTime two, string bing) + { + } - public void Diddly (ITestObject three) - { - } + public void Diddly(ITestObject three) + { + } - public void ParamsArguments(int foo, params string[] strs) - { - } - } + public void ParamsArguments(int foo, params string[] strs) + { + } } diff --git a/test/Spring/Spring.Core.Tests/Core/MethodGenericArgumentsCountCriteriaTests.cs b/test/Spring/Spring.Core.Tests/Core/MethodGenericArgumentsCountCriteriaTests.cs index 6e9b35c2..75eb2cd6 100644 --- a/test/Spring/Spring.Core.Tests/Core/MethodGenericArgumentsCountCriteriaTests.cs +++ b/test/Spring/Spring.Core.Tests/Core/MethodGenericArgumentsCountCriteriaTests.cs @@ -21,76 +21,74 @@ #region Imports using System.Reflection; - using NUnit.Framework; #endregion -namespace Spring.Core +namespace Spring.Core; + +/// +/// Unit tests for the MethodGenericArgumentsCountCriteria class. +/// +/// Bruno Baia +[TestFixture] +public sealed class MethodGenericArgumentsCountCriteriaTests { - /// - /// Unit tests for the MethodGenericArgumentsCountCriteria class. - /// - /// Bruno Baia - [TestFixture] - public sealed class MethodGenericArgumentsCountCriteriaTests + [Test] + public void Instantiation() { - [Test] - public void Instantiation () - { - MethodGenericArgumentsCountCriteria criteria = new MethodGenericArgumentsCountCriteria(); - Assert.AreEqual (0, criteria.ExpectedGenericArgumentCount); - criteria = new MethodGenericArgumentsCountCriteria(10); - Assert.AreEqual(10, criteria.ExpectedGenericArgumentCount); - } + MethodGenericArgumentsCountCriteria criteria = new MethodGenericArgumentsCountCriteria(); + Assert.AreEqual(0, criteria.ExpectedGenericArgumentCount); + criteria = new MethodGenericArgumentsCountCriteria(10); + Assert.AreEqual(10, criteria.ExpectedGenericArgumentCount); + } - [Test] - public void InstantiationBailsWithGenericArgumentCountSetToLessThanZero () - { - Assert.Throws(() => new MethodGenericArgumentsCountCriteria(-10)); - } + [Test] + public void InstantiationBailsWithGenericArgumentCountSetToLessThanZero() + { + Assert.Throws(() => new MethodGenericArgumentsCountCriteria(-10)); + } - [Test] - public void BailsWhenExpectedGenericArgumentCountSetToLessThanZero() - { - MethodGenericArgumentsCountCriteria criteria = new MethodGenericArgumentsCountCriteria(); - Assert.Throws(() => criteria.ExpectedGenericArgumentCount = -12); - } + [Test] + public void BailsWhenExpectedGenericArgumentCountSetToLessThanZero() + { + MethodGenericArgumentsCountCriteria criteria = new MethodGenericArgumentsCountCriteria(); + Assert.Throws(() => criteria.ExpectedGenericArgumentCount = -12); + } - [Test] - public void IsSatisfied () - { - MethodGenericArgumentsCountCriteria criteria = new MethodGenericArgumentsCountCriteria(); - MethodInfo method = GetType().GetMethod("NoGenericArgument", BindingFlags.Public | BindingFlags.Instance); - Assert.IsTrue(criteria.IsSatisfied(method)); + [Test] + public void IsSatisfied() + { + MethodGenericArgumentsCountCriteria criteria = new MethodGenericArgumentsCountCriteria(); + MethodInfo method = GetType().GetMethod("NoGenericArgument", BindingFlags.Public | BindingFlags.Instance); + Assert.IsTrue(criteria.IsSatisfied(method)); - criteria = new MethodGenericArgumentsCountCriteria(1); - method = GetType().GetMethod("OneGenericArgument", BindingFlags.Public | BindingFlags.Instance); - Assert.IsTrue (criteria.IsSatisfied (method)); + criteria = new MethodGenericArgumentsCountCriteria(1); + method = GetType().GetMethod("OneGenericArgument", BindingFlags.Public | BindingFlags.Instance); + Assert.IsTrue(criteria.IsSatisfied(method)); - criteria = new MethodGenericArgumentsCountCriteria(2); - method = GetType().GetMethod("TwoGenericArguments", BindingFlags.Public | BindingFlags.Instance); - Assert.IsTrue (criteria.IsSatisfied (method)); - } + criteria = new MethodGenericArgumentsCountCriteria(2); + method = GetType().GetMethod("TwoGenericArguments", BindingFlags.Public | BindingFlags.Instance); + Assert.IsTrue(criteria.IsSatisfied(method)); + } - [Test] - public void IsNotSatisfiedWithNull () - { - MethodGenericArgumentsCountCriteria criteria = new MethodGenericArgumentsCountCriteria(); - Assert.IsFalse (criteria.IsSatisfied (null)); - } + [Test] + public void IsNotSatisfiedWithNull() + { + MethodGenericArgumentsCountCriteria criteria = new MethodGenericArgumentsCountCriteria(); + Assert.IsFalse(criteria.IsSatisfied(null)); + } - // some methods for testing signatures... - public void NoGenericArgument() - { - } + // some methods for testing signatures... + public void NoGenericArgument() + { + } - public void OneGenericArgument() - { - } + public void OneGenericArgument() + { + } - public void TwoGenericArguments() - { - } - } -} + public void TwoGenericArguments() + { + } +} \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/Core/MethodParametersCountCriteriaTests.cs b/test/Spring/Spring.Core.Tests/Core/MethodParametersCountCriteriaTests.cs index 3764365f..3033bc07 100644 --- a/test/Spring/Spring.Core.Tests/Core/MethodParametersCountCriteriaTests.cs +++ b/test/Spring/Spring.Core.Tests/Core/MethodParametersCountCriteriaTests.cs @@ -21,117 +21,115 @@ #region Imports using System.Reflection; - using NUnit.Framework; #endregion -namespace Spring.Core +namespace Spring.Core; + +/// +/// Unit tests for the MethodParametersCountCriteria class. +/// +/// Rick Evans +[TestFixture] +public sealed class MethodParametersCountCriteriaTests { - /// - /// Unit tests for the MethodParametersCountCriteria class. - /// - /// Rick Evans - [TestFixture] - public sealed class MethodParametersCountCriteriaTests + [Test] + public void Instantiation() { - [Test] - public void Instantiation () - { - MethodParametersCountCriteria criteria = new MethodParametersCountCriteria (); - Assert.AreEqual (0, criteria.ExpectedParameterCount); - criteria = new MethodParametersCountCriteria (10); - Assert.AreEqual (10, criteria.ExpectedParameterCount); - } + MethodParametersCountCriteria criteria = new MethodParametersCountCriteria(); + Assert.AreEqual(0, criteria.ExpectedParameterCount); + criteria = new MethodParametersCountCriteria(10); + Assert.AreEqual(10, criteria.ExpectedParameterCount); + } - [Test] - public void InstantiationBailsWithParameterCountSetToLessThanZero () - { - Assert.Throws(() => new MethodParametersCountCriteria (-10)); - } + [Test] + public void InstantiationBailsWithParameterCountSetToLessThanZero() + { + Assert.Throws(() => new MethodParametersCountCriteria(-10)); + } - [Test] - public void BailsWhenExpectedParameterCountSetToLessThanZero () - { - MethodParametersCountCriteria criteria = new MethodParametersCountCriteria (); - Assert.Throws(() => criteria.ExpectedParameterCount = -12); - } + [Test] + public void BailsWhenExpectedParameterCountSetToLessThanZero() + { + MethodParametersCountCriteria criteria = new MethodParametersCountCriteria(); + Assert.Throws(() => criteria.ExpectedParameterCount = -12); + } - [Test] - public void IsSatisfiedWithNoParameter () - { - MethodParametersCountCriteria criteria = new MethodParametersCountCriteria (); - MethodInfo method = GetType ().GetMethod ("NoParameter", BindingFlags.Public | BindingFlags.Instance); - Assert.IsTrue (criteria.IsSatisfied (method)); + [Test] + public void IsSatisfiedWithNoParameter() + { + MethodParametersCountCriteria criteria = new MethodParametersCountCriteria(); + MethodInfo method = GetType().GetMethod("NoParameter", BindingFlags.Public | BindingFlags.Instance); + Assert.IsTrue(criteria.IsSatisfied(method)); - criteria = new MethodParametersCountCriteria(0); - method = GetType().GetMethod("NoParameter", BindingFlags.Public | BindingFlags.Instance); - Assert.IsTrue(criteria.IsSatisfied(method)); + criteria = new MethodParametersCountCriteria(0); + method = GetType().GetMethod("NoParameter", BindingFlags.Public | BindingFlags.Instance); + Assert.IsTrue(criteria.IsSatisfied(method)); - criteria = new MethodParametersCountCriteria(); - criteria.ExpectedParameterCount = 0; - method = GetType().GetMethod("NoParameter", BindingFlags.Public | BindingFlags.Instance); - Assert.IsTrue(criteria.IsSatisfied(method)); - } + criteria = new MethodParametersCountCriteria(); + criteria.ExpectedParameterCount = 0; + method = GetType().GetMethod("NoParameter", BindingFlags.Public | BindingFlags.Instance); + Assert.IsTrue(criteria.IsSatisfied(method)); + } - [Test] - public void IsSatisfiedWithOneParameter () - { - MethodParametersCountCriteria criteria = new MethodParametersCountCriteria (1); - MethodInfo method = GetType().GetMethod("OneParameter", BindingFlags.Public | BindingFlags.Instance); - Assert.IsTrue (criteria.IsSatisfied (method)); - } + [Test] + public void IsSatisfiedWithOneParameter() + { + MethodParametersCountCriteria criteria = new MethodParametersCountCriteria(1); + MethodInfo method = GetType().GetMethod("OneParameter", BindingFlags.Public | BindingFlags.Instance); + Assert.IsTrue(criteria.IsSatisfied(method)); + } - [Test] - public void IsSatisfiedWithTwoParameters () - { - MethodParametersCountCriteria criteria = new MethodParametersCountCriteria(2); - MethodInfo method = GetType().GetMethod("TwoParameters", BindingFlags.Public | BindingFlags.Instance); - Assert.IsTrue (criteria.IsSatisfied (method)); - } + [Test] + public void IsSatisfiedWithTwoParameters() + { + MethodParametersCountCriteria criteria = new MethodParametersCountCriteria(2); + MethodInfo method = GetType().GetMethod("TwoParameters", BindingFlags.Public | BindingFlags.Instance); + Assert.IsTrue(criteria.IsSatisfied(method)); + } - [Test] - public void IsSatisfiedWithParamsParameters () - { - MethodParametersCountCriteria criteria = new MethodParametersCountCriteria(1); - MethodInfo method = GetType().GetMethod("ParamsParameters", BindingFlags.Public | BindingFlags.Instance); - Assert.IsFalse(criteria.IsSatisfied(method)); + [Test] + public void IsSatisfiedWithParamsParameters() + { + MethodParametersCountCriteria criteria = new MethodParametersCountCriteria(1); + MethodInfo method = GetType().GetMethod("ParamsParameters", BindingFlags.Public | BindingFlags.Instance); + Assert.IsFalse(criteria.IsSatisfied(method)); - criteria = new MethodParametersCountCriteria(2); - method = GetType().GetMethod("ParamsParameters", BindingFlags.Public | BindingFlags.Instance); - Assert.IsTrue(criteria.IsSatisfied(method)); + criteria = new MethodParametersCountCriteria(2); + method = GetType().GetMethod("ParamsParameters", BindingFlags.Public | BindingFlags.Instance); + Assert.IsTrue(criteria.IsSatisfied(method)); - criteria = new MethodParametersCountCriteria (3); - method = GetType().GetMethod("ParamsParameters", BindingFlags.Public | BindingFlags.Instance); - Assert.IsTrue (criteria.IsSatisfied (method)); + criteria = new MethodParametersCountCriteria(3); + method = GetType().GetMethod("ParamsParameters", BindingFlags.Public | BindingFlags.Instance); + Assert.IsTrue(criteria.IsSatisfied(method)); - criteria = new MethodParametersCountCriteria(5); - method = GetType().GetMethod("ParamsParameters", BindingFlags.Public | BindingFlags.Instance); - Assert.IsTrue(criteria.IsSatisfied(method)); - } + criteria = new MethodParametersCountCriteria(5); + method = GetType().GetMethod("ParamsParameters", BindingFlags.Public | BindingFlags.Instance); + Assert.IsTrue(criteria.IsSatisfied(method)); + } - [Test] - public void IsNotSatisfiedWithNull () - { - MethodParametersCountCriteria criteria = new MethodParametersCountCriteria (); - Assert.IsFalse (criteria.IsSatisfied (null)); - } + [Test] + public void IsNotSatisfiedWithNull() + { + MethodParametersCountCriteria criteria = new MethodParametersCountCriteria(); + Assert.IsFalse(criteria.IsSatisfied(null)); + } - // some methods for testing signatures... - public void NoParameter () - { - } + // some methods for testing signatures... + public void NoParameter() + { + } - public void OneParameter (int foo) - { - } + public void OneParameter(int foo) + { + } - public void TwoParameters (int foo, int bar) - { - } + public void TwoParameters(int foo, int bar) + { + } - public void ParamsParameters(int foo, int bar, params string[] strs) - { - } - } + public void ParamsParameters(int foo, int bar, params string[] strs) + { + } } diff --git a/test/Spring/Spring.Core.Tests/Core/MethodParametersCriteriaTests.cs b/test/Spring/Spring.Core.Tests/Core/MethodParametersCriteriaTests.cs index ef96dfbf..538347fa 100644 --- a/test/Spring/Spring.Core.Tests/Core/MethodParametersCriteriaTests.cs +++ b/test/Spring/Spring.Core.Tests/Core/MethodParametersCriteriaTests.cs @@ -21,96 +21,95 @@ #region Imports using System.Reflection; - using NUnit.Framework; using Spring.Objects; #endregion -namespace Spring.Core +namespace Spring.Core; + +/// +/// Unit tests for the MethodParametersCriteria class. +/// +/// Rick Evans +/// Bruno Baia +[TestFixture] +public sealed class MethodParametersCriteriaTests { - /// - /// Unit tests for the MethodParametersCriteria class. - /// - /// Rick Evans - /// Bruno Baia - [TestFixture] - public sealed class MethodParametersCriteriaTests + [Test] + public void IsNotSatisfiedWithNull() { - [Test] - public void IsNotSatisfiedWithNull () { - MethodParametersCriteria criteria = new MethodParametersCriteria (); - Assert.IsFalse (criteria.IsSatisfied (null), "Was satisified with null."); - } + MethodParametersCriteria criteria = new MethodParametersCriteria(); + Assert.IsFalse(criteria.IsSatisfied(null), "Was satisified with null."); + } - [Test] - public void IsSatisfiedWithNoParametersByDefault () - { - MethodParametersCriteria criteria = new MethodParametersCriteria (); - MethodInfo method = GetType ().GetMethod ("Foo"); - Assert.IsTrue (criteria.IsSatisfied (method), "Was not satisified with a method that takes no parameters by default."); - } + [Test] + public void IsSatisfiedWithNoParametersByDefault() + { + MethodParametersCriteria criteria = new MethodParametersCriteria(); + MethodInfo method = GetType().GetMethod("Foo"); + Assert.IsTrue(criteria.IsSatisfied(method), "Was not satisified with a method that takes no parameters by default."); + } - [Test] - public void IsNotSatisfiedWhenOnlyFinalParamMatches() - { - MethodParametersCriteria criteria = new MethodParametersCriteria( - new Type[] { typeof(object), typeof(object), typeof(TestObject) }); - MethodInfo method = GetType().GetMethod("BoJangles"); - Assert.IsFalse(criteria.IsSatisfied(method), "Was satisified with a method that only matches on the final parameter."); - } + [Test] + public void IsNotSatisfiedWhenOnlyFinalParamMatches() + { + MethodParametersCriteria criteria = new MethodParametersCriteria( + new Type[] { typeof(object), typeof(object), typeof(TestObject) }); + MethodInfo method = GetType().GetMethod("BoJangles"); + Assert.IsFalse(criteria.IsSatisfied(method), "Was satisified with a method that only matches on the final parameter."); + } - [Test] - public void IsSatisfied () - { - MethodParametersCriteria criteria = new MethodParametersCriteria ( - new Type [] {typeof (string), typeof (DBNull), typeof (TestObject)}); - MethodInfo method = GetType ().GetMethod ("BoJangles"); - Assert.IsTrue (criteria.IsSatisfied (method), "Was not satisified with a method that takes a whole buncha parameters."); + [Test] + public void IsSatisfied() + { + MethodParametersCriteria criteria = new MethodParametersCriteria( + new Type[] { typeof(string), typeof(DBNull), typeof(TestObject) }); + MethodInfo method = GetType().GetMethod("BoJangles"); + Assert.IsTrue(criteria.IsSatisfied(method), "Was not satisified with a method that takes a whole buncha parameters."); - method = GetType ().GetMethod ("BadBobbyBoJangles"); - Assert.IsFalse (criteria.IsSatisfied (method), "Was satisified with a (bad) method that takes a whole buncha parameters."); - } + method = GetType().GetMethod("BadBobbyBoJangles"); + Assert.IsFalse(criteria.IsSatisfied(method), "Was satisified with a (bad) method that takes a whole buncha parameters."); + } - [Test] - public void IsNotSatisfiedIsPolymorphic () - { - // i.e. derived types satisfy the criteria if a base type or interface is - // specified as one of the parameter types - MethodParametersCriteria criteria - = new MethodParametersCriteria (new Type [] {typeof (TestObject)}); - MethodInfo method = GetType ().GetMethod ("Diddly"); - Assert.IsFalse(criteria.IsSatisfied (method), "Was not satisified with a method that takes a base class as a parameter."); - } + [Test] + public void IsNotSatisfiedIsPolymorphic() + { + // i.e. derived types satisfy the criteria if a base type or interface is + // specified as one of the parameter types + MethodParametersCriteria criteria + = new MethodParametersCriteria(new Type[] { typeof(TestObject) }); + MethodInfo method = GetType().GetMethod("Diddly"); + Assert.IsFalse(criteria.IsSatisfied(method), "Was not satisified with a method that takes a base class as a parameter."); + } - [Test] - public void IsSatisfiedWithParamsParameters() - { - MethodParametersCriteria criteria = new MethodParametersCriteria(new Type[] { typeof(int), typeof(string[]) }); - MethodInfo method = GetType().GetMethod("ParamsParameters"); - Assert.IsTrue(criteria.IsSatisfied(method), "Was not satisified with a method that takes a parameter array ('params') as a parameter."); - } + [Test] + public void IsSatisfiedWithParamsParameters() + { + MethodParametersCriteria criteria = new MethodParametersCriteria(new Type[] { typeof(int), typeof(string[]) }); + MethodInfo method = GetType().GetMethod("ParamsParameters"); + Assert.IsTrue(criteria.IsSatisfied(method), "Was not satisified with a method that takes a parameter array ('params') as a parameter."); + } - // some methods for testing signatures... - public void Foo () - { - } + // some methods for testing signatures... + public void Foo() + { + } - public DateTime BoJangles (string one, DBNull two, TestObject three) - { - return DateTime.Now; - } + public DateTime BoJangles(string one, DBNull two, TestObject three) + { + return DateTime.Now; + } - public void BadBobbyBoJangles (string one, DBNull two, string bing) - { - } + public void BadBobbyBoJangles(string one, DBNull two, string bing) + { + } - public void Diddly (ITestObject three) - { - } + public void Diddly(ITestObject three) + { + } - public void ParamsParameters(int foo, params string[] strs) - { - } - } + public void ParamsParameters(int foo, params string[] strs) + { + } } diff --git a/test/Spring/Spring.Core.Tests/Core/MethodReturnTypeCriteriaTests.cs b/test/Spring/Spring.Core.Tests/Core/MethodReturnTypeCriteriaTests.cs index f136a777..2ae9640f 100644 --- a/test/Spring/Spring.Core.Tests/Core/MethodReturnTypeCriteriaTests.cs +++ b/test/Spring/Spring.Core.Tests/Core/MethodReturnTypeCriteriaTests.cs @@ -21,43 +21,43 @@ #region Imports using System.Reflection; - using NUnit.Framework; #endregion -namespace Spring.Core +namespace Spring.Core; + +/// +/// Unit tests for the MethodReturnTypeCriteria class. +/// +[TestFixture] +public sealed class MethodReturnTypeCriteriaTests { - /// - /// Unit tests for the MethodReturnTypeCriteria class. - /// - [TestFixture] - public sealed class MethodReturnTypeCriteriaTests + [Test] + public void IsSatisfied() { - [Test] - public void IsSatisfied () { - MethodReturnTypeCriteria criteria = new MethodReturnTypeCriteria (typeof (bool)); - MethodInfo method = GetType ().GetMethod ("SomeKindOfWonderful", BindingFlags.NonPublic | BindingFlags.Instance); - Assert.IsTrue (criteria.IsSatisfied (method)); - } + MethodReturnTypeCriteria criteria = new MethodReturnTypeCriteria(typeof(bool)); + MethodInfo method = GetType().GetMethod("SomeKindOfWonderful", BindingFlags.NonPublic | BindingFlags.Instance); + Assert.IsTrue(criteria.IsSatisfied(method)); + } - private bool SomeKindOfWonderful () - { - return true; - } + private bool SomeKindOfWonderful() + { + return true; + } - [Test] - public void IsSatisfiedWithVoidByDefault () - { - MethodReturnTypeCriteria criteria = new MethodReturnTypeCriteria (); - MethodInfo method = GetType ().GetMethod ("IsSatisfied"); - Assert.IsTrue (criteria.IsSatisfied (method)); - } - - [Test] - public void IsNotSatisfiedWithNull () { - MethodReturnTypeCriteria criteria = new MethodReturnTypeCriteria (); - Assert.IsFalse (criteria.IsSatisfied (null)); - } - } + [Test] + public void IsSatisfiedWithVoidByDefault() + { + MethodReturnTypeCriteria criteria = new MethodReturnTypeCriteria(); + MethodInfo method = GetType().GetMethod("IsSatisfied"); + Assert.IsTrue(criteria.IsSatisfied(method)); + } + + [Test] + public void IsNotSatisfiedWithNull() + { + MethodReturnTypeCriteria criteria = new MethodReturnTypeCriteria(); + Assert.IsFalse(criteria.IsSatisfied(null)); + } } diff --git a/test/Spring/Spring.Core.Tests/Core/OrderComparatorTests.cs b/test/Spring/Spring.Core.Tests/Core/OrderComparatorTests.cs index 9514870f..21125be5 100644 --- a/test/Spring/Spring.Core.Tests/Core/OrderComparatorTests.cs +++ b/test/Spring/Spring.Core.Tests/Core/OrderComparatorTests.cs @@ -25,55 +25,54 @@ using Spring.Util; #endregion -namespace Spring.Core +namespace Spring.Core; + +/// +/// Unit tests for the OrderComparator class. +/// +/// Rick Evans +[TestFixture] +public sealed class OrderComparatorTests { - /// - /// Unit tests for the OrderComparator class. - /// - /// Rick Evans - [TestFixture] - public sealed class OrderComparatorTests + [Test] + public void OrdersCorrectly() { - [Test] - public void OrdersCorrectly () + Ordered one = new Ordered(1); + Ordered fifty = new Ordered(50); + string max = "Max"; // should be stuck at the end 'cos it doesnt implement IOrdered + object[] list = new object[] { max, one, fifty }; + Array.Sort(list, new OrderComparator()); + Assert.AreEqual(one, list[0]); + Assert.AreEqual(fifty, list[1]); + Assert.AreEqual(max, list[2]); + } + + [Test] + public void DoesntBailWhenFedNulls() + { + Ordered one = new Ordered(1); + object[] list = new object[] { null, one, null }; + ArrayUtils.Sort(list, new OrderComparator()); + Assert.AreEqual(one, list[0], "order comparator instance should be first"); + Assert.AreEqual(null, list[1]); + Assert.AreEqual(null, list[2]); + } + + internal sealed class Ordered : IOrdered + { + public Ordered(int order) { - Ordered one = new Ordered (1); - Ordered fifty = new Ordered (50); - string max = "Max"; // should be stuck at the end 'cos it doesnt implement IOrdered - object [] list = new object [] {max, one, fifty}; - Array.Sort (list, new OrderComparator ()); - Assert.AreEqual (one, list [0]); - Assert.AreEqual (fifty, list [1]); - Assert.AreEqual (max, list [2]); + _order = order; } - [Test] - public void DoesntBailWhenFedNulls () + public int Order { - Ordered one = new Ordered (1); - object [] list = new object [] {null, one, null}; - ArrayUtils.Sort(list, new OrderComparator ()); - Assert.AreEqual (one, list [0], "order comparator instance should be first"); - Assert.AreEqual (null, list [1]); - Assert.AreEqual (null, list [2]); - } - - internal sealed class Ordered : IOrdered - { - public Ordered (int order) + get { - _order = order; + return _order; } - - public int Order - { - get - { - return _order; - } - } - - private int _order; } - } + + private int _order; + } } diff --git a/test/Spring/Spring.Core.Tests/Core/RegularExpressionEventNameCriteriaTests.cs b/test/Spring/Spring.Core.Tests/Core/RegularExpressionEventNameCriteriaTests.cs index 152b586c..58c16a62 100644 --- a/test/Spring/Spring.Core.Tests/Core/RegularExpressionEventNameCriteriaTests.cs +++ b/test/Spring/Spring.Core.Tests/Core/RegularExpressionEventNameCriteriaTests.cs @@ -21,49 +21,47 @@ #region Imports using System.Reflection; - using Spring.Objects; - using NUnit.Framework; #endregion -namespace Spring.Core +namespace Spring.Core; + +/// +/// Unit tests for the RegularExpressionEventNameCriteria class. +/// +[TestFixture] +public class RegularExpressionEventNameCriteriaTests { - /// - /// Unit tests for the RegularExpressionEventNameCriteria class. - /// - [TestFixture] - public class RegularExpressionEventNameCriteriaTests + [Test] + public void IsSatisfied() { - [Test] - public void IsSatisfied () { - RegularExpressionEventNameCriteria criteria = new RegularExpressionEventNameCriteria("Click"); - EventInfo evt = typeof(TestObject).GetEvent("Click"); - Assert.IsTrue (criteria.IsSatisfied (evt)); - } + RegularExpressionEventNameCriteria criteria = new RegularExpressionEventNameCriteria("Click"); + EventInfo evt = typeof(TestObject).GetEvent("Click"); + Assert.IsTrue(criteria.IsSatisfied(evt)); + } - [Test] - public void IsNotSatisfiedWithGarbage () - { - RegularExpressionEventNameCriteria criteria = new RegularExpressionEventNameCriteria ("BingoBango"); - EventInfo evt = typeof(TestObject).GetEvent("Click"); - Assert.IsFalse (criteria.IsSatisfied (evt)); - } + [Test] + public void IsNotSatisfiedWithGarbage() + { + RegularExpressionEventNameCriteria criteria = new RegularExpressionEventNameCriteria("BingoBango"); + EventInfo evt = typeof(TestObject).GetEvent("Click"); + Assert.IsFalse(criteria.IsSatisfied(evt)); + } - [Test] - public void IsNotSatisfiedWithNull () - { - RegularExpressionEventNameCriteria criteria = new RegularExpressionEventNameCriteria("Click"); - Assert.IsFalse (criteria.IsSatisfied (null)); - } + [Test] + public void IsNotSatisfiedWithNull() + { + RegularExpressionEventNameCriteria criteria = new RegularExpressionEventNameCriteria("Click"); + Assert.IsFalse(criteria.IsSatisfied(null)); + } - [Test] - public void IsSatisfiedWithAnythingByDefault () - { - RegularExpressionEventNameCriteria criteria = new RegularExpressionEventNameCriteria (); - EventInfo evt = typeof (TestObject).GetEvent ("Click"); - Assert.IsTrue (criteria.IsSatisfied (evt)); - } - } + [Test] + public void IsSatisfiedWithAnythingByDefault() + { + RegularExpressionEventNameCriteria criteria = new RegularExpressionEventNameCriteria(); + EventInfo evt = typeof(TestObject).GetEvent("Click"); + Assert.IsTrue(criteria.IsSatisfied(evt)); + } } diff --git a/test/Spring/Spring.Core.Tests/Core/RegularExpressionMethodNameCriteriaTests.cs b/test/Spring/Spring.Core.Tests/Core/RegularExpressionMethodNameCriteriaTests.cs index bc778706..107cd66d 100644 --- a/test/Spring/Spring.Core.Tests/Core/RegularExpressionMethodNameCriteriaTests.cs +++ b/test/Spring/Spring.Core.Tests/Core/RegularExpressionMethodNameCriteriaTests.cs @@ -21,49 +21,47 @@ #region Imports using System.Reflection; - using Spring.Objects; using NUnit.Framework; #endregion -namespace Spring.Core +namespace Spring.Core; + +/// +/// Unit tests for the RegularExpressionMethodNameCriteria class. +/// +[TestFixture] +public class RegularExpressionMethodNameCriteriaTests { - /// - /// Unit tests for the RegularExpressionMethodNameCriteria class. - /// - [TestFixture] - public class RegularExpressionMethodNameCriteriaTests + [Test] + public void IsSatisfied() { - [Test] - public void IsSatisfied () - { - RegularExpressionMethodNameCriteria criteria = new RegularExpressionMethodNameCriteria ("Click"); - MethodInfo method = typeof(TestObject).GetMethod("OnClick"); - Assert.IsTrue (criteria.IsSatisfied (method)); - } + RegularExpressionMethodNameCriteria criteria = new RegularExpressionMethodNameCriteria("Click"); + MethodInfo method = typeof(TestObject).GetMethod("OnClick"); + Assert.IsTrue(criteria.IsSatisfied(method)); + } - [Test] - public void IsNotSatisfiedWithGarbage () - { - RegularExpressionMethodNameCriteria criteria = new RegularExpressionMethodNameCriteria ("BingoBango"); - MethodInfo method = typeof(TestObject).GetMethod("OnClick"); - Assert.IsFalse (criteria.IsSatisfied (method)); - } + [Test] + public void IsNotSatisfiedWithGarbage() + { + RegularExpressionMethodNameCriteria criteria = new RegularExpressionMethodNameCriteria("BingoBango"); + MethodInfo method = typeof(TestObject).GetMethod("OnClick"); + Assert.IsFalse(criteria.IsSatisfied(method)); + } - [Test] - public void IsNotSatisfiedWithNull () - { - RegularExpressionMethodNameCriteria criteria = new RegularExpressionMethodNameCriteria("OnClick"); - Assert.IsFalse (criteria.IsSatisfied (null)); - } + [Test] + public void IsNotSatisfiedWithNull() + { + RegularExpressionMethodNameCriteria criteria = new RegularExpressionMethodNameCriteria("OnClick"); + Assert.IsFalse(criteria.IsSatisfied(null)); + } - [Test] - public void IsSatisfiedWithAnythingByDefault () - { - RegularExpressionMethodNameCriteria criteria = new RegularExpressionMethodNameCriteria (); - MethodInfo method = typeof(TestObject).GetMethod("OnClick"); - Assert.IsTrue (criteria.IsSatisfied (method)); - } + [Test] + public void IsSatisfiedWithAnythingByDefault() + { + RegularExpressionMethodNameCriteria criteria = new RegularExpressionMethodNameCriteria(); + MethodInfo method = typeof(TestObject).GetMethod("OnClick"); + Assert.IsTrue(criteria.IsSatisfied(method)); } } diff --git a/test/Spring/Spring.Core.Tests/Core/TypeConversion/CredentialConverterTests.cs b/test/Spring/Spring.Core.Tests/Core/TypeConversion/CredentialConverterTests.cs index b404afd9..7fac7d71 100644 --- a/test/Spring/Spring.Core.Tests/Core/TypeConversion/CredentialConverterTests.cs +++ b/test/Spring/Spring.Core.Tests/Core/TypeConversion/CredentialConverterTests.cs @@ -2,13 +2,13 @@ /* * Copyright � 2002-2011 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. @@ -21,116 +21,114 @@ #region Imports using System.Net; - using NUnit.Framework; #endregion -namespace Spring.Core.TypeConversion +namespace Spring.Core.TypeConversion; + +/// +/// Unit tests for the CredentialConverter class. +/// +/// Bruno Baia +[TestFixture] +public sealed class CredentialConverterTests { - /// - /// Unit tests for the CredentialConverter class. - /// - /// Bruno Baia - [TestFixture] - public sealed class CredentialConverterTests + [Test] + public void ConvertFromNullReference() { - [Test] - public void ConvertFromNullReference() - { - CredentialConverter cc = new CredentialConverter(); - Assert.Throws(() => cc.ConvertFrom(null)); - } - - [Test] - public void ConvertFromNonSupportedOptionBails() - { - CredentialConverter cc = new CredentialConverter(); - Assert.Throws(() => cc.ConvertFrom(12)); - } - - [Test] - public void ConvertFrom() - { - CredentialConverter cc = new CredentialConverter(); - object credential = cc.ConvertFrom(@"Spring\bbaia:sprnet"); - Assert.IsNotNull(credential); - Assert.IsTrue(credential is NetworkCredential); - - NetworkCredential nc = (NetworkCredential)credential; - Assert.AreEqual("Spring", nc.Domain); - Assert.AreEqual("bbaia", nc.UserName); - Assert.AreEqual("sprnet", nc.Password); - } - - [Test] - public void ConvertFromEmptyString() - { - CredentialConverter cc = new CredentialConverter(); - Assert.Throws(() => cc.ConvertFrom(string.Empty)); - } - - [Test] - public void ConvertFromMalformedString() - { - CredentialConverter cc = new CredentialConverter(); - Assert.Throws(() => cc.ConvertFrom(@"Spring:bbaia\sprnet")); - } - - [Test] - public void ConvertFromStringWithoutDomain() - { - CredentialConverter cc = new CredentialConverter(); - object credential = cc.ConvertFrom(@"bbaia:sprnet"); - Assert.IsNotNull(credential); - Assert.IsTrue(credential is NetworkCredential); - - NetworkCredential nc = (NetworkCredential)credential; - Assert.AreEqual(string.Empty, nc.Domain); - Assert.AreEqual("bbaia", nc.UserName); - Assert.AreEqual("sprnet", nc.Password); - } - - [Test] - public void ConvertFromStringWithIncorrectDomain() - { - CredentialConverter cc = new CredentialConverter(); - Assert.Throws(() => cc.ConvertFrom(@"\bbaia:sprnet")); - } - - [Test] - public void ConvertFromStringWithoutPassword() - { - CredentialConverter cc = new CredentialConverter(); - object credential = cc.ConvertFrom(@"Spring\bbaia"); - Assert.IsNotNull(credential); - Assert.IsTrue(credential is NetworkCredential); - - NetworkCredential nc = (NetworkCredential)credential; - Assert.AreEqual("Spring", nc.Domain); - Assert.AreEqual("bbaia", nc.UserName); - Assert.AreEqual(string.Empty, nc.Password); - } - - [Test] - public void ConvertFromStringWithIncorrectPassword() - { - CredentialConverter cc = new CredentialConverter(); - Assert.Throws(() => cc.ConvertFrom(@"\bbaia:")); - } - - [Test] - public void ConvertFromStringWithUsernameOnly() - { - CredentialConverter cc = new CredentialConverter(); - object credential = cc.ConvertFrom(@"bbaia"); - Assert.IsNotNull(credential); - Assert.IsTrue(credential is NetworkCredential); - - NetworkCredential nc = (NetworkCredential)credential; - Assert.AreEqual(string.Empty, nc.Domain); - Assert.AreEqual("bbaia", nc.UserName); - Assert.AreEqual(string.Empty, nc.Password); - } + CredentialConverter cc = new CredentialConverter(); + Assert.Throws(() => cc.ConvertFrom(null)); } -} \ No newline at end of file + + [Test] + public void ConvertFromNonSupportedOptionBails() + { + CredentialConverter cc = new CredentialConverter(); + Assert.Throws(() => cc.ConvertFrom(12)); + } + + [Test] + public void ConvertFrom() + { + CredentialConverter cc = new CredentialConverter(); + object credential = cc.ConvertFrom(@"Spring\bbaia:sprnet"); + Assert.IsNotNull(credential); + Assert.IsTrue(credential is NetworkCredential); + + NetworkCredential nc = (NetworkCredential) credential; + Assert.AreEqual("Spring", nc.Domain); + Assert.AreEqual("bbaia", nc.UserName); + Assert.AreEqual("sprnet", nc.Password); + } + + [Test] + public void ConvertFromEmptyString() + { + CredentialConverter cc = new CredentialConverter(); + Assert.Throws(() => cc.ConvertFrom(string.Empty)); + } + + [Test] + public void ConvertFromMalformedString() + { + CredentialConverter cc = new CredentialConverter(); + Assert.Throws(() => cc.ConvertFrom(@"Spring:bbaia\sprnet")); + } + + [Test] + public void ConvertFromStringWithoutDomain() + { + CredentialConverter cc = new CredentialConverter(); + object credential = cc.ConvertFrom(@"bbaia:sprnet"); + Assert.IsNotNull(credential); + Assert.IsTrue(credential is NetworkCredential); + + NetworkCredential nc = (NetworkCredential) credential; + Assert.AreEqual(string.Empty, nc.Domain); + Assert.AreEqual("bbaia", nc.UserName); + Assert.AreEqual("sprnet", nc.Password); + } + + [Test] + public void ConvertFromStringWithIncorrectDomain() + { + CredentialConverter cc = new CredentialConverter(); + Assert.Throws(() => cc.ConvertFrom(@"\bbaia:sprnet")); + } + + [Test] + public void ConvertFromStringWithoutPassword() + { + CredentialConverter cc = new CredentialConverter(); + object credential = cc.ConvertFrom(@"Spring\bbaia"); + Assert.IsNotNull(credential); + Assert.IsTrue(credential is NetworkCredential); + + NetworkCredential nc = (NetworkCredential) credential; + Assert.AreEqual("Spring", nc.Domain); + Assert.AreEqual("bbaia", nc.UserName); + Assert.AreEqual(string.Empty, nc.Password); + } + + [Test] + public void ConvertFromStringWithIncorrectPassword() + { + CredentialConverter cc = new CredentialConverter(); + Assert.Throws(() => cc.ConvertFrom(@"\bbaia:")); + } + + [Test] + public void ConvertFromStringWithUsernameOnly() + { + CredentialConverter cc = new CredentialConverter(); + object credential = cc.ConvertFrom(@"bbaia"); + Assert.IsNotNull(credential); + Assert.IsTrue(credential is NetworkCredential); + + NetworkCredential nc = (NetworkCredential) credential; + Assert.AreEqual(string.Empty, nc.Domain); + Assert.AreEqual("bbaia", nc.UserName); + Assert.AreEqual(string.Empty, nc.Password); + } +} diff --git a/test/Spring/Spring.Core.Tests/Core/TypeConversion/CustomNumberConverterTests.cs b/test/Spring/Spring.Core.Tests/Core/TypeConversion/CustomNumberConverterTests.cs index 1df8b505..7220232f 100644 --- a/test/Spring/Spring.Core.Tests/Core/TypeConversion/CustomNumberConverterTests.cs +++ b/test/Spring/Spring.Core.Tests/Core/TypeConversion/CustomNumberConverterTests.cs @@ -21,102 +21,90 @@ #region Imports using System.Globalization; - using NUnit.Framework; #endregion -namespace Spring.Core.TypeConversion +namespace Spring.Core.TypeConversion; + +/// +/// Unit tests for the CustomNumberConverter class. +/// +[TestFixture] +public class CustomNumberConverterTests { - /// - /// Unit tests for the CustomNumberConverter class. - /// - [TestFixture] - public class CustomNumberConverterTests + [Test] + public void Instantiation() { - [Test] - public void Instantiation() - { - CustomNumberConverter verter - = new CustomNumberConverter(typeof(int), null, true); - // mmm, this should still pass... it aint a number though - verter - = new CustomNumberConverter(typeof(bool), null, true); - } + CustomNumberConverter verter + = new CustomNumberConverter(typeof(int), null, true); + // mmm, this should still pass... it aint a number though + verter + = new CustomNumberConverter(typeof(bool), null, true); + } - [Test] - public void InstantiationWithNonPrimitiveType() - { - Assert.Throws(() => new CustomNumberConverter(typeof(CustomNumberConverterTests), null, true)); - } + [Test] + public void InstantiationWithNonPrimitiveType() + { + Assert.Throws(() => new CustomNumberConverter(typeof(CustomNumberConverterTests), null, true)); + } - [Test] - public void CanConvertFromString() - { - CustomNumberConverter verter = new CustomNumberConverter(typeof(int), null, true); - Assert.IsTrue(verter.CanConvertFrom(typeof(string))); - Assert.IsFalse(verter.CanConvertFrom(null)); - } + [Test] + public void CanConvertFromString() + { + CustomNumberConverter verter = new CustomNumberConverter(typeof(int), null, true); + Assert.IsTrue(verter.CanConvertFrom(typeof(string))); + Assert.IsFalse(verter.CanConvertFrom(null)); + } - [Test] - public void ConvertsEmptyStringToZeroWhenAllowed() - { - CustomNumberConverter verter = new CustomNumberConverter(typeof(int), null, true); - int actual = (int) verter.ConvertFrom(null, CultureInfo.CurrentUICulture, string.Empty); - Assert.AreEqual(0, actual); - } + [Test] + public void ConvertsEmptyStringToZeroWhenAllowed() + { + CustomNumberConverter verter = new CustomNumberConverter(typeof(int), null, true); + int actual = (int) verter.ConvertFrom(null, CultureInfo.CurrentUICulture, string.Empty); + Assert.AreEqual(0, actual); + } - [Test] - public void ConvertFromSupportedNumericType() + [Test] + public void ConvertFromSupportedNumericType() + { + Type[] numTypes = new Type[] { typeof(int), typeof(uint), typeof(short), typeof(ushort), typeof(long), typeof(ulong), typeof(float), typeof(double), }; + int expected = 12; + foreach (Type numType in numTypes) { - Type[] numTypes = new Type[] + try { - typeof(int), - typeof(uint), - typeof(short), - typeof(ushort), - typeof(long), - typeof(ulong), - typeof(float), - typeof(double), - }; - int expected = 12; - foreach (Type numType in numTypes) + CustomNumberConverter verter = new CustomNumberConverter(numType, null, true); + object actual = verter.ConvertFrom(null, CultureInfo.CurrentUICulture, expected.ToString()); + Assert.AreEqual(expected, actual); + } + catch (Exception ex) { - try - { - CustomNumberConverter verter = new CustomNumberConverter(numType, null, true); - object actual = verter.ConvertFrom(null, CultureInfo.CurrentUICulture, expected.ToString()); - Assert.AreEqual(expected, actual); - } - catch (Exception ex) - { - Assert.Fail("Bailed when converting type '" + numType + "' : " + ex); - } + Assert.Fail("Bailed when converting type '" + numType + "' : " + ex); } } - - [Test] - public void BailsOnEmptyStringWhenNotAllowed() - { - CustomNumberConverter verter - = new CustomNumberConverter(typeof(int), null, false); - Assert.Throws(() => verter.ConvertFrom(null, CultureInfo.CurrentUICulture, string.Empty)); - } - - [Test] - public void ConvertFromNonSupportedNumericTypeOptionBails() - { - CustomNumberConverter verter - = new CustomNumberConverter(typeof(char), null, false); - Assert.Throws(() => verter.ConvertFrom("12")); - } - - [Test] - public void ConvertFromNonSupportedOptionBails() - { - CustomNumberConverter verter = new CustomNumberConverter(typeof(int), null, false); - Assert.Throws(() => verter.ConvertFrom(12)); - } } -} \ No newline at end of file + + [Test] + public void BailsOnEmptyStringWhenNotAllowed() + { + CustomNumberConverter verter + = new CustomNumberConverter(typeof(int), null, false); + Assert.Throws(() => verter.ConvertFrom(null, CultureInfo.CurrentUICulture, string.Empty)); + } + + [Test] + public void ConvertFromNonSupportedNumericTypeOptionBails() + { + CustomNumberConverter verter + = new CustomNumberConverter(typeof(char), null, false); + Assert.Throws(() => verter.ConvertFrom("12")); + } + + [Test] + public void ConvertFromNonSupportedOptionBails() + { + CustomNumberConverter verter = new CustomNumberConverter(typeof(int), null, false); + Assert.Throws(() => verter.ConvertFrom(12)); + } +} diff --git a/test/Spring/Spring.Core.Tests/Core/TypeConversion/FileInfoConverterTests.cs b/test/Spring/Spring.Core.Tests/Core/TypeConversion/FileInfoConverterTests.cs index e474f785..ebfa97cf 100644 --- a/test/Spring/Spring.Core.Tests/Core/TypeConversion/FileInfoConverterTests.cs +++ b/test/Spring/Spring.Core.Tests/Core/TypeConversion/FileInfoConverterTests.cs @@ -2,13 +2,13 @@ /* * Copyright � 2002-2011 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. @@ -24,54 +24,53 @@ using NUnit.Framework; #endregion -namespace Spring.Core.TypeConversion +namespace Spring.Core.TypeConversion; + +/// +/// Unit tests for the FileInfoConverter class. +/// +/// Rick Evans +[TestFixture] +public sealed class FileInfoConverterTests { - /// - /// Unit tests for the FileInfoConverter class. - /// - /// Rick Evans - [TestFixture] - public sealed class FileInfoConverterTests + [Test] + public void CanConvertFrom() { - [Test] - public void CanConvertFrom() - { - FileInfoConverter vrt = new FileInfoConverter(); - Assert.IsTrue(vrt.CanConvertFrom(typeof (string)), "Conversion from a string instance must be supported."); - Assert.IsFalse(vrt.CanConvertFrom(typeof (int))); - } - - [Test] - public void ConvertFrom() - { - FileInfoConverter vrt = new FileInfoConverter(); - object file = vrt.ConvertFrom("././ManAhShoahDoLoveThoseGrits"); - Assert.IsNotNull(file); - Assert.AreEqual(typeof (FileInfo), file.GetType()); - } - - [Test] - public void FileConverter() - { - FileInfoConverter converter = new FileInfoConverter(); - object file = converter.ConvertFrom("C:/test/myfile.txt"); - Assert.IsNotNull(file); - Assert.IsTrue(file is FileInfo); - Assert.AreEqual(new FileInfo("C:/test/myfile.txt").FullName, ((FileInfo) file).FullName); - } - - [Test] - public void ConvertFromNullReference() - { - FileInfoConverter vrt = new FileInfoConverter(); - Assert.Throws(() => vrt.ConvertFrom(null)); - } - - [Test] - public void ConvertFromNonSupportedOptionBails() - { - FileInfoConverter vrt = new FileInfoConverter(); - Assert.Throws(() => vrt.ConvertFrom(12)); - } + FileInfoConverter vrt = new FileInfoConverter(); + Assert.IsTrue(vrt.CanConvertFrom(typeof(string)), "Conversion from a string instance must be supported."); + Assert.IsFalse(vrt.CanConvertFrom(typeof(int))); } -} \ No newline at end of file + + [Test] + public void ConvertFrom() + { + FileInfoConverter vrt = new FileInfoConverter(); + object file = vrt.ConvertFrom("././ManAhShoahDoLoveThoseGrits"); + Assert.IsNotNull(file); + Assert.AreEqual(typeof(FileInfo), file.GetType()); + } + + [Test] + public void FileConverter() + { + FileInfoConverter converter = new FileInfoConverter(); + object file = converter.ConvertFrom("C:/test/myfile.txt"); + Assert.IsNotNull(file); + Assert.IsTrue(file is FileInfo); + Assert.AreEqual(new FileInfo("C:/test/myfile.txt").FullName, ((FileInfo) file).FullName); + } + + [Test] + public void ConvertFromNullReference() + { + FileInfoConverter vrt = new FileInfoConverter(); + Assert.Throws(() => vrt.ConvertFrom(null)); + } + + [Test] + public void ConvertFromNonSupportedOptionBails() + { + FileInfoConverter vrt = new FileInfoConverter(); + Assert.Throws(() => vrt.ConvertFrom(12)); + } +} diff --git a/test/Spring/Spring.Core.Tests/Core/TypeConversion/NameValueConverterTests.cs b/test/Spring/Spring.Core.Tests/Core/TypeConversion/NameValueConverterTests.cs index 908b205f..deb80733 100644 --- a/test/Spring/Spring.Core.Tests/Core/TypeConversion/NameValueConverterTests.cs +++ b/test/Spring/Spring.Core.Tests/Core/TypeConversion/NameValueConverterTests.cs @@ -21,66 +21,64 @@ #region Imports using System.Collections.Specialized; - using NUnit.Framework; using Spring.Objects; #endregion -namespace Spring.Core.TypeConversion +namespace Spring.Core.TypeConversion; + +/// +/// Unit tests for the NameValueConverter class. +/// +/// Rick Evans +[TestFixture] +public sealed class NameValueConverterTests { - /// - /// Unit tests for the NameValueConverter class. - /// - /// Rick Evans - [TestFixture] - public sealed class NameValueConverterTests + [Test] + public void CanConvertFromString() { - [Test] - public void CanConvertFromString () - { - NameValueConverter vrt = new NameValueConverter (); - Assert.IsTrue (vrt.CanConvertFrom (typeof (string)), "Conversion from a string instance must be supported."); - } + NameValueConverter vrt = new NameValueConverter(); + Assert.IsTrue(vrt.CanConvertFrom(typeof(string)), "Conversion from a string instance must be supported."); + } - [Test] - public void CanConvertOnlyFromString() - { - NameValueConverter vrt = new NameValueConverter (); - Assert.IsFalse(vrt.CanConvertFrom(typeof(TestObject)), - "Seem to be able to convert from non-supported Type."); - } + [Test] + public void CanConvertOnlyFromString() + { + NameValueConverter vrt = new NameValueConverter(); + Assert.IsFalse(vrt.CanConvertFrom(typeof(TestObject)), + "Seem to be able to convert from non-supported Type."); + } - [Test] - public void ConvertFrom () - { - string xml = - "" + - " " + - " " + - ""; - NameValueConverter vrt = new NameValueConverter (); - NameValueCollection actual = vrt.ConvertFrom (xml) as NameValueCollection; - Assert.IsNotNull (actual); - Assert.AreEqual (2, actual.Count); - Assert.AreEqual ("one", actual.GetKey (0)); - Assert.AreEqual ("two", actual.GetKey (1)); - Assert.AreEqual ("1", actual ["one"]); - Assert.AreEqual ("2", actual ["two"]); - } + [Test] + public void ConvertFrom() + { + string xml = + "" + + " " + + " " + + ""; + NameValueConverter vrt = new NameValueConverter(); + NameValueCollection actual = vrt.ConvertFrom(xml) as NameValueCollection; + Assert.IsNotNull(actual); + Assert.AreEqual(2, actual.Count); + Assert.AreEqual("one", actual.GetKey(0)); + Assert.AreEqual("two", actual.GetKey(1)); + Assert.AreEqual("1", actual["one"]); + Assert.AreEqual("2", actual["two"]); + } - [Test] - public void ConvertFromNullReference() - { - NameValueConverter vrt = new NameValueConverter(); - Assert.Throws(() => vrt.ConvertFrom(null)); - } + [Test] + public void ConvertFromNullReference() + { + NameValueConverter vrt = new NameValueConverter(); + Assert.Throws(() => vrt.ConvertFrom(null)); + } - [Test] - public void ConvertFromNonSupportedOptionBails() - { - NameValueConverter vrt = new NameValueConverter(); - Assert.Throws(() => vrt.ConvertFrom(true)); - } - } + [Test] + public void ConvertFromNonSupportedOptionBails() + { + NameValueConverter vrt = new NameValueConverter(); + Assert.Throws(() => vrt.ConvertFrom(true)); + } } diff --git a/test/Spring/Spring.Core.Tests/Core/TypeConversion/RGBColorConverterTests.cs b/test/Spring/Spring.Core.Tests/Core/TypeConversion/RGBColorConverterTests.cs index 1907ee7d..ab424bcc 100644 --- a/test/Spring/Spring.Core.Tests/Core/TypeConversion/RGBColorConverterTests.cs +++ b/test/Spring/Spring.Core.Tests/Core/TypeConversion/RGBColorConverterTests.cs @@ -2,13 +2,13 @@ /* * Copyright � 2002-2011 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. @@ -25,55 +25,55 @@ using NUnit.Framework; #endregion -namespace Spring.Core.TypeConversion +namespace Spring.Core.TypeConversion; + +/// +/// Unit tests for the RGBColorConverter class. +/// +/// Rick Evans +[TestFixture] +public sealed class RGBColorConverterTests { - /// - /// Unit tests for the RGBColorConverter class. - /// - /// Rick Evans - [TestFixture] - public sealed class RGBColorConverterTests + [Test] + public void ConvertFromRGB() { - [Test] - public void ConvertFromRGB() - { - Color expected = Color.BlanchedAlmond; - RGBColorConverter converter = new RGBColorConverter(); - Color actual = - (Color) converter.ConvertFrom(String.Format("{0}, {1}, {2}", expected.R, expected.G, expected.B)); - Assert.AreEqual(expected.A, actual.A); - Assert.AreEqual(expected.R, actual.R); - Assert.AreEqual(expected.G, actual.G); - Assert.AreEqual(expected.B, actual.B); - } + Color expected = Color.BlanchedAlmond; + RGBColorConverter converter = new RGBColorConverter(); + Color actual = + (Color) converter.ConvertFrom(String.Format("{0}, {1}, {2}", expected.R, expected.G, expected.B)); + Assert.AreEqual(expected.A, actual.A); + Assert.AreEqual(expected.R, actual.R); + Assert.AreEqual(expected.G, actual.G); + Assert.AreEqual(expected.B, actual.B); + } - [Test] - public void ConvertFromCommaSeparatedListWithNotEnoughValues() - { - RGBColorConverter converter = new RGBColorConverter(); - Assert.Throws(() => converter.ConvertFrom("255, 235")); - } + [Test] + public void ConvertFromCommaSeparatedListWithNotEnoughValues() + { + RGBColorConverter converter = new RGBColorConverter(); + Assert.Throws(() => converter.ConvertFrom("255, 235")); + } - [Test] - public void ConvertFromCommaSeparatedListWithOutOfRangeValue() - { - RGBColorConverter converter = new RGBColorConverter(); - Assert.Throws(() => converter.ConvertFrom("255, 235, 4567")); - } + [Test] + public void ConvertFromCommaSeparatedListWithOutOfRangeValue() + { + RGBColorConverter converter = new RGBColorConverter(); + Assert.Throws(() => converter.ConvertFrom("255, 235, 4567")); + } - [Test] - public void ConvertFromNullReference() - { - RGBColorConverter vrt = new RGBColorConverter(); - Assert.Throws(() => vrt.ConvertFrom(null)); - } + [Test] + public void ConvertFromNullReference() + { + RGBColorConverter vrt = new RGBColorConverter(); + Assert.Throws(() => vrt.ConvertFrom(null)); + } - [Test] - public void ConvertFromEmptyString() - { - RGBColorConverter vrt = new RGBColorConverter(); - Assert.Throws(() => vrt.ConvertFrom(string.Empty)); - } + [Test] + public void ConvertFromEmptyString() + { + RGBColorConverter vrt = new RGBColorConverter(); + Assert.Throws(() => vrt.ConvertFrom(string.Empty)); + } #if NETFRAMEWORK [Test] @@ -93,32 +93,31 @@ namespace Spring.Core.TypeConversion } #endif - [Test] - public void ConvertFromNonSupportedOptionBails() - { - RGBColorConverter vrt = new RGBColorConverter(); - Assert.Throws(() => vrt.ConvertFrom(12)); - } - - [Test] - public void ConvertFromARGB() - { - Color expected = Color.BlanchedAlmond; - RGBColorConverter converter = new RGBColorConverter(); - Color actual = - (Color) converter.ConvertFrom(String.Format("{0}, {1}, {2}, {3}", expected.A, expected.R, expected.G, expected.B)); - Assert.AreEqual(expected.A, actual.A); - Assert.AreEqual(expected.R, actual.R); - Assert.AreEqual(expected.G, actual.G); - Assert.AreEqual(expected.B, actual.B); - } - - [Test] - public void CanConvertFrom() - { - RGBColorConverter vrt = new RGBColorConverter(); - Assert.IsTrue(vrt.CanConvertFrom(typeof (string)), "Conversion from a string instance must be supported."); - Assert.IsFalse(vrt.CanConvertFrom(typeof (int))); - } + [Test] + public void ConvertFromNonSupportedOptionBails() + { + RGBColorConverter vrt = new RGBColorConverter(); + Assert.Throws(() => vrt.ConvertFrom(12)); } -} \ No newline at end of file + + [Test] + public void ConvertFromARGB() + { + Color expected = Color.BlanchedAlmond; + RGBColorConverter converter = new RGBColorConverter(); + Color actual = + (Color) converter.ConvertFrom(String.Format("{0}, {1}, {2}, {3}", expected.A, expected.R, expected.G, expected.B)); + Assert.AreEqual(expected.A, actual.A); + Assert.AreEqual(expected.R, actual.R); + Assert.AreEqual(expected.G, actual.G); + Assert.AreEqual(expected.B, actual.B); + } + + [Test] + public void CanConvertFrom() + { + RGBColorConverter vrt = new RGBColorConverter(); + Assert.IsTrue(vrt.CanConvertFrom(typeof(string)), "Conversion from a string instance must be supported."); + Assert.IsFalse(vrt.CanConvertFrom(typeof(int))); + } +} diff --git a/test/Spring/Spring.Core.Tests/Core/TypeConversion/RegexConverterTests.cs b/test/Spring/Spring.Core.Tests/Core/TypeConversion/RegexConverterTests.cs index cec3fc2c..6591aaf5 100644 --- a/test/Spring/Spring.Core.Tests/Core/TypeConversion/RegexConverterTests.cs +++ b/test/Spring/Spring.Core.Tests/Core/TypeConversion/RegexConverterTests.cs @@ -2,13 +2,13 @@ /* * Copyright � 2002-2011 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. @@ -21,42 +21,40 @@ #region Imports using System.Text.RegularExpressions; - using NUnit.Framework; #endregion -namespace Spring.Core.TypeConversion +namespace Spring.Core.TypeConversion; + +/// +/// Unit tests for the RegexConverter class. +/// +/// Bruno Baia +[TestFixture] +public sealed class RegexConverterTests { - /// - /// Unit tests for the RegexConverter class. - /// - /// Bruno Baia - [TestFixture] - public sealed class RegexConverterTests + [Test] + public void ConvertFromNullReference() { - [Test] - public void ConvertFromNullReference() - { - RegexConverter rc = new RegexConverter(); - Assert.Throws(() => rc.ConvertFrom(null)); - } + RegexConverter rc = new RegexConverter(); + Assert.Throws(() => rc.ConvertFrom(null)); + } - [Test] - public void ConvertFromNonSupportedOptionBails() - { - RegexConverter rc = new RegexConverter(); - Assert.Throws(() => rc.ConvertFrom(12)); - } + [Test] + public void ConvertFromNonSupportedOptionBails() + { + RegexConverter rc = new RegexConverter(); + Assert.Throws(() => rc.ConvertFrom(12)); + } - [Test] - public void ConvertFrom() - { - RegexConverter rc = new RegexConverter(); - object regex = rc.ConvertFrom("[a-z]"); - Assert.IsNotNull(regex); - Assert.IsTrue(regex is Regex); - Assert.IsFalse(((Regex)regex).IsMatch("2")); - } + [Test] + public void ConvertFrom() + { + RegexConverter rc = new RegexConverter(); + object regex = rc.ConvertFrom("[a-z]"); + Assert.IsNotNull(regex); + Assert.IsTrue(regex is Regex); + Assert.IsFalse(((Regex) regex).IsMatch("2")); } } \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/Core/TypeConversion/RegistryKeyConverterTests.cs b/test/Spring/Spring.Core.Tests/Core/TypeConversion/RegistryKeyConverterTests.cs index 79559113..fc47d298 100644 --- a/test/Spring/Spring.Core.Tests/Core/TypeConversion/RegistryKeyConverterTests.cs +++ b/test/Spring/Spring.Core.Tests/Core/TypeConversion/RegistryKeyConverterTests.cs @@ -23,60 +23,58 @@ using NUnit.Framework; #pragma warning disable CA1416 // is only supported on windows -namespace Spring.Core.TypeConversion +namespace Spring.Core.TypeConversion; + +/// +/// Unit tests for the RegistryKeyConverter class. +/// +/// Aleksandar Seovic +[Platform("Win")] +public sealed class RegistryKeyConverterTests { - /// - /// Unit tests for the RegistryKeyConverter class. - /// - /// Aleksandar Seovic - [Platform("Win")] - public sealed class RegistryKeyConverterTests + [Test] + public void ConvertFromNullReference() { - [Test] - public void ConvertFromNullReference() - { - RegistryKeyConverter rkc = new RegistryKeyConverter(); - Assert.Throws(() => rkc.ConvertFrom(null)); - } - - [Test] - public void ConvertFromNonSupportedOptionBails() - { - RegistryKeyConverter rkc = new RegistryKeyConverter(); - Assert.Throws(() => rkc.ConvertFrom(12)); - } - - [Test] - public void ConvertFrom() - { - RegistryKeyConverter rkc = new RegistryKeyConverter(); - Assert.AreEqual(Registry.CurrentUser, rkc.ConvertFrom("HKEY_CURRENT_USER")); - Assert.AreEqual(Registry.CurrentUser.OpenSubKey("Software").Name, - ((RegistryKey) rkc.ConvertFrom(@"HKEY_CURRENT_USER\Software")).Name); - Assert.AreEqual(Registry.CurrentUser.OpenSubKey("Software").OpenSubKey("Microsoft").Name, - ((RegistryKey) rkc.ConvertFrom(@"HKEY_CURRENT_USER\Software\Microsoft")).Name); - } - - [Test] - public void ConvertFromEmptyString() - { - RegistryKeyConverter rkc = new RegistryKeyConverter(); - Assert.Throws(() => rkc.ConvertFrom(string.Empty)); - } - - [Test] - public void ConvertFromBadKeyString() - { - RegistryKeyConverter rkc = new RegistryKeyConverter(); - Assert.Throws(() => rkc.ConvertFrom(@"HKEY_CURRENT_USER\sdgsdfgsdfgxadas\Xyz\Abc"), @"Registry key [HKEY_CURRENT_USER\sdgsdfgsdfgxadas] does not exist."); - } - - [Test] - public void ConvertFromBadHiveString() - { - RegistryKeyConverter rkc = new RegistryKeyConverter(); - Assert.Throws(() => rkc.ConvertFrom(@"HKEY_ERROR\sdgsdfgsdfgxadas"), "Invalid root hive name [HKEY_ERROR]."); - } - + RegistryKeyConverter rkc = new RegistryKeyConverter(); + Assert.Throws(() => rkc.ConvertFrom(null)); } -} \ No newline at end of file + + [Test] + public void ConvertFromNonSupportedOptionBails() + { + RegistryKeyConverter rkc = new RegistryKeyConverter(); + Assert.Throws(() => rkc.ConvertFrom(12)); + } + + [Test] + public void ConvertFrom() + { + RegistryKeyConverter rkc = new RegistryKeyConverter(); + Assert.AreEqual(Registry.CurrentUser, rkc.ConvertFrom("HKEY_CURRENT_USER")); + Assert.AreEqual(Registry.CurrentUser.OpenSubKey("Software").Name, + ((RegistryKey) rkc.ConvertFrom(@"HKEY_CURRENT_USER\Software")).Name); + Assert.AreEqual(Registry.CurrentUser.OpenSubKey("Software").OpenSubKey("Microsoft").Name, + ((RegistryKey) rkc.ConvertFrom(@"HKEY_CURRENT_USER\Software\Microsoft")).Name); + } + + [Test] + public void ConvertFromEmptyString() + { + RegistryKeyConverter rkc = new RegistryKeyConverter(); + Assert.Throws(() => rkc.ConvertFrom(string.Empty)); + } + + [Test] + public void ConvertFromBadKeyString() + { + RegistryKeyConverter rkc = new RegistryKeyConverter(); + Assert.Throws(() => rkc.ConvertFrom(@"HKEY_CURRENT_USER\sdgsdfgsdfgxadas\Xyz\Abc"), @"Registry key [HKEY_CURRENT_USER\sdgsdfgsdfgxadas] does not exist."); + } + + [Test] + public void ConvertFromBadHiveString() + { + RegistryKeyConverter rkc = new RegistryKeyConverter(); + Assert.Throws(() => rkc.ConvertFrom(@"HKEY_ERROR\sdgsdfgsdfgxadas"), "Invalid root hive name [HKEY_ERROR]."); + } +} diff --git a/test/Spring/Spring.Core.Tests/Core/TypeConversion/ResourceManagerTests.cs b/test/Spring/Spring.Core.Tests/Core/TypeConversion/ResourceManagerTests.cs index 24f89121..9038d47b 100644 --- a/test/Spring/Spring.Core.Tests/Core/TypeConversion/ResourceManagerTests.cs +++ b/test/Spring/Spring.Core.Tests/Core/TypeConversion/ResourceManagerTests.cs @@ -21,109 +21,105 @@ #region Imports using System.Resources; - using NUnit.Framework; #endregion -namespace Spring.Core.TypeConversion +namespace Spring.Core.TypeConversion; + +/// +/// Unit tests for the ResourceManagerConverter class. +/// +/// Mark Pollack +[TestFixture] +public sealed class ResourceManagerConverterTests { - /// - /// Unit tests for the ResourceManagerConverter class. + /// + /// Test that we indicate we can convert from strings only. /// - /// Mark Pollack - [TestFixture] - public sealed class ResourceManagerConverterTests + [Test] + public void CanConvertFrom() { - /// - /// Test that we indicate we can convert from strings only. - /// - [Test] - public void CanConvertFrom () - { - ResourceManagerConverter cvt = new ResourceManagerConverter (); - Assert.IsTrue (cvt.CanConvertFrom (typeof (string)), "Conversion from a string instance must be supported."); - Assert.IsFalse (cvt.CanConvertFrom (null)); - } + ResourceManagerConverter cvt = new ResourceManagerConverter(); + Assert.IsTrue(cvt.CanConvertFrom(typeof(string)), "Conversion from a string instance must be supported."); + Assert.IsFalse(cvt.CanConvertFrom(null)); + } - /// - /// Test sunny day scenario to convert from resource name, assembly name string pair - /// - [Test] - public void ConvertFrom () - { - - ResourceManagerConverter cvt = new ResourceManagerConverter(); - object actual = cvt.ConvertFrom ("Spring.TestResource.txt, Spring.Core.Tests"); - Assert.IsNotNull (actual); - Assert.AreEqual (typeof (ResourceManager), actual.GetType()); + /// + /// Test sunny day scenario to convert from resource name, assembly name string pair + /// + [Test] + public void ConvertFrom() + { + ResourceManagerConverter cvt = new ResourceManagerConverter(); + object actual = cvt.ConvertFrom("Spring.TestResource.txt, Spring.Core.Tests"); + Assert.IsNotNull(actual); + Assert.AreEqual(typeof(ResourceManager), actual.GetType()); + } - } - - /// - /// Test passing a null instance and see if expected exception is raised - /// - [Test] - public void ConvertFromNullReference () - { - ResourceManagerConverter cvt = new ResourceManagerConverter(); - Assert.Throws(() => cvt.ConvertFrom (null)); - } + /// + /// Test passing a null instance and see if expected exception is raised + /// + [Test] + public void ConvertFromNullReference() + { + ResourceManagerConverter cvt = new ResourceManagerConverter(); + Assert.Throws(() => cvt.ConvertFrom(null)); + } - /// - /// Test passing a single string with no ',' - /// - [Test] - public void ConvertFromSingleString () - { - ResourceManagerConverter cvt = new ResourceManagerConverter(); - Assert.Throws(() => cvt.ConvertFrom ("Spring.TestResource.txt")); - } + /// + /// Test passing a single string with no ',' + /// + [Test] + public void ConvertFromSingleString() + { + ResourceManagerConverter cvt = new ResourceManagerConverter(); + Assert.Throws(() => cvt.ConvertFrom("Spring.TestResource.txt")); + } - /// - /// Test passing a single ',' - /// - [Test] - public void ConvertFromSingleComma () - { - ResourceManagerConverter cvt = new ResourceManagerConverter(); - Assert.Throws(() => cvt.ConvertFrom (",")); - } + /// + /// Test passing a single ',' + /// + [Test] + public void ConvertFromSingleComma() + { + ResourceManagerConverter cvt = new ResourceManagerConverter(); + Assert.Throws(() => cvt.ConvertFrom(",")); + } - /// - /// Test passing only assembly name - /// - [Test] - public void ConvertFromOnlyAssemblyNAme () - { - ResourceManagerConverter cvt = new ResourceManagerConverter(); - Assert.Throws(() => cvt.ConvertFrom (",Spring.Core.Tests")); - } + /// + /// Test passing only assembly name + /// + [Test] + public void ConvertFromOnlyAssemblyNAme() + { + ResourceManagerConverter cvt = new ResourceManagerConverter(); + Assert.Throws(() => cvt.ConvertFrom(",Spring.Core.Tests")); + } - /// - /// Test passing only assembly name - /// - [Test] - public void ConvertFromOnlyResourceName() - { - ResourceManagerConverter cvt = new ResourceManagerConverter(); - Assert.Throws(() => cvt.ConvertFrom ("Spring.TestResource.txt,")); - } + /// + /// Test passing only assembly name + /// + [Test] + public void ConvertFromOnlyResourceName() + { + ResourceManagerConverter cvt = new ResourceManagerConverter(); + Assert.Throws(() => cvt.ConvertFrom("Spring.TestResource.txt,")); + } #if NETFRAMEWORK - [Test] - public void ConvertFromBadAssembly() - { - ResourceManagerConverter cvt = new ResourceManagerConverter(); - Assert.Throws(() => cvt.ConvertFrom ("Spring.TestResource.txt, FooAssembly")); - } + [Test] + public void ConvertFromBadAssembly() + { + ResourceManagerConverter cvt = new ResourceManagerConverter(); + Assert.Throws(() => cvt.ConvertFrom ("Spring.TestResource.txt, FooAssembly")); + } #endif - [Test] - public void ConvertFromBad_App_GlobalResources() - { - ResourceManagerConverter cvt = new ResourceManagerConverter(); - Assert.Throws(() => cvt.ConvertFrom("Spring.TestResource.txt, "+ResourceManagerConverter.APP_GLOBALRESOURCES_ASSEMBLYNAME)); - } - } + [Test] + public void ConvertFromBad_App_GlobalResources() + { + ResourceManagerConverter cvt = new ResourceManagerConverter(); + Assert.Throws(() => cvt.ConvertFrom("Spring.TestResource.txt, " + ResourceManagerConverter.APP_GLOBALRESOURCES_ASSEMBLYNAME)); + } } diff --git a/test/Spring/Spring.Core.Tests/Core/TypeConversion/RuntimeTypeConverterTests.cs b/test/Spring/Spring.Core.Tests/Core/TypeConversion/RuntimeTypeConverterTests.cs index 77ef2d3a..752d78d9 100644 --- a/test/Spring/Spring.Core.Tests/Core/TypeConversion/RuntimeTypeConverterTests.cs +++ b/test/Spring/Spring.Core.Tests/Core/TypeConversion/RuntimeTypeConverterTests.cs @@ -24,60 +24,59 @@ using NUnit.Framework; #endregion -namespace Spring.Core.TypeConversion +namespace Spring.Core.TypeConversion; + +/// +/// Unit tests for the RuntimeTypeConverter class. +/// +[TestFixture] +public class RuntimeTypeConverterTests { - /// - /// Unit tests for the RuntimeTypeConverter class. - /// - [TestFixture] - public class RuntimeTypeConverterTests + [Test] + public void CanConvertFrom() { - [Test] - public void CanConvertFrom () - { - RuntimeTypeConverter cnv = new RuntimeTypeConverter (); - Assert.IsTrue (cnv.CanConvertFrom (typeof (string)), "Mmm... I can't convert from a string to a Type."); - Assert.IsFalse (cnv.CanConvertFrom (GetType ()), "Mmm... managed to convert to a Type from a Type of this test. Boing!"); - } + RuntimeTypeConverter cnv = new RuntimeTypeConverter(); + Assert.IsTrue(cnv.CanConvertFrom(typeof(string)), "Mmm... I can't convert from a string to a Type."); + Assert.IsFalse(cnv.CanConvertFrom(GetType()), "Mmm... managed to convert to a Type from a Type of this test. Boing!"); + } - [Test] - public void CanConvertTo () - { - RuntimeTypeConverter cnv = new RuntimeTypeConverter (); - Assert.IsTrue (cnv.CanConvertTo (typeof (Type)), "Mmm... I can't convert to a Type at all."); - Assert.IsFalse (cnv.CanConvertTo (typeof (void)), "Mmm... managed to convert to a Type from a bad type. Boing!"); - } + [Test] + public void CanConvertTo() + { + RuntimeTypeConverter cnv = new RuntimeTypeConverter(); + Assert.IsTrue(cnv.CanConvertTo(typeof(Type)), "Mmm... I can't convert to a Type at all."); + Assert.IsFalse(cnv.CanConvertTo(typeof(void)), "Mmm... managed to convert to a Type from a bad type. Boing!"); + } - [Test] - public void ConvertFromNonSupportedType () - { - RuntimeTypeConverter cnv = new RuntimeTypeConverter (); - Assert.Throws(() => cnv.ConvertFrom (12)); - } + [Test] + public void ConvertFromNonSupportedType() + { + RuntimeTypeConverter cnv = new RuntimeTypeConverter(); + Assert.Throws(() => cnv.ConvertFrom(12)); + } - [Test] - public void ConvertFromString () - { - RuntimeTypeConverter cnv = new RuntimeTypeConverter (); - object foo = cnv.ConvertFrom ("System.String"); - Assert.IsNotNull (foo); - Assert.AreEqual (GetType().GetType().FullName, foo.GetType ().FullName); - } + [Test] + public void ConvertFromString() + { + RuntimeTypeConverter cnv = new RuntimeTypeConverter(); + object foo = cnv.ConvertFrom("System.String"); + Assert.IsNotNull(foo); + Assert.AreEqual(GetType().GetType().FullName, foo.GetType().FullName); + } - [Test] - public void ConvertToString () - { - RuntimeTypeConverter cnv = new RuntimeTypeConverter (); - object foo = cnv.ConvertTo (typeof (string), typeof (string)); - Assert.IsNotNull (foo); - Assert.AreEqual (typeof (string).AssemblyQualifiedName, foo); - } + [Test] + public void ConvertToString() + { + RuntimeTypeConverter cnv = new RuntimeTypeConverter(); + object foo = cnv.ConvertTo(typeof(string), typeof(string)); + Assert.IsNotNull(foo); + Assert.AreEqual(typeof(string).AssemblyQualifiedName, foo); + } - [Test] - public void ConvertToStringFromNonSupportedType () - { - RuntimeTypeConverter cnv = new RuntimeTypeConverter (); - Assert.Throws(() => cnv.ConvertTo (typeof (string), GetType ())); - } - } + [Test] + public void ConvertToStringFromNonSupportedType() + { + RuntimeTypeConverter cnv = new RuntimeTypeConverter(); + Assert.Throws(() => cnv.ConvertTo(typeof(string), GetType())); + } } diff --git a/test/Spring/Spring.Core.Tests/Core/TypeConversion/StreamConverterTests.cs b/test/Spring/Spring.Core.Tests/Core/TypeConversion/StreamConverterTests.cs index 3b9814ee..d5f0bc70 100644 --- a/test/Spring/Spring.Core.Tests/Core/TypeConversion/StreamConverterTests.cs +++ b/test/Spring/Spring.Core.Tests/Core/TypeConversion/StreamConverterTests.cs @@ -25,50 +25,49 @@ using NUnit.Framework; #endregion -namespace Spring.Core.TypeConversion +namespace Spring.Core.TypeConversion; + +/// +/// Unit tests for the StreamConverter class. +/// +/// Rick Evans +[TestFixture] +public sealed class StreamConverterTests { - /// - /// Unit tests for the StreamConverter class. - /// - /// Rick Evans - [TestFixture] - public sealed class StreamConverterTests - { - [Test] - public void CanConvertFrom() - { - StreamConverter vrt = new StreamConverter(); - Assert.IsTrue(vrt.CanConvertFrom(typeof (string)), - "Conversion from a string instance must be supported."); - Assert.IsFalse(vrt.CanConvertFrom(typeof (int))); - } + [Test] + public void CanConvertFrom() + { + StreamConverter vrt = new StreamConverter(); + Assert.IsTrue(vrt.CanConvertFrom(typeof(string)), + "Conversion from a string instance must be supported."); + Assert.IsFalse(vrt.CanConvertFrom(typeof(int))); + } - [Test] - [Explicit] // requires one to be connected to the 'net... - public void ConvertFrom() - { - StreamConverter vrt = new StreamConverter(); - Stream actual = vrt.ConvertFrom("http://www.springframework.net/") as Stream; - Assert.IsNotNull(actual); - } + [Test] + [Explicit] // requires one to be connected to the 'net... + public void ConvertFrom() + { + StreamConverter vrt = new StreamConverter(); + Stream actual = vrt.ConvertFrom("http://www.springframework.net/") as Stream; + Assert.IsNotNull(actual); + } - [Test] - [Explicit] // fails if there is a transparent proxy that redirects to error page for non existing URL - public void ConvertFromValidButNonExistingStreamResource() - { - Assert.Throws(() => new StreamConverter().ConvertFrom("http://www.aaaabbbbccccddd.com")); - } + [Test] + [Explicit] // fails if there is a transparent proxy that redirects to error page for non existing URL + public void ConvertFromValidButNonExistingStreamResource() + { + Assert.Throws(() => new StreamConverter().ConvertFrom("http://www.aaaabbbbccccddd.com")); + } - [Test] - public void ConvertFromNullReference() - { - Assert.Throws(() => new StreamConverter().ConvertFrom(null)); - } + [Test] + public void ConvertFromNullReference() + { + Assert.Throws(() => new StreamConverter().ConvertFrom(null)); + } - [Test] - public void ConvertFromNonSupportedOptionBails() - { - Assert.Throws(() => new StreamConverter().ConvertFrom(12)); - } - } -} \ No newline at end of file + [Test] + public void ConvertFromNonSupportedOptionBails() + { + Assert.Throws(() => new StreamConverter().ConvertFrom(12)); + } +} diff --git a/test/Spring/Spring.Core.Tests/Core/TypeConversion/StringArrayConverterTests.cs b/test/Spring/Spring.Core.Tests/Core/TypeConversion/StringArrayConverterTests.cs index 0727fea6..610b4e2b 100644 --- a/test/Spring/Spring.Core.Tests/Core/TypeConversion/StringArrayConverterTests.cs +++ b/test/Spring/Spring.Core.Tests/Core/TypeConversion/StringArrayConverterTests.cs @@ -26,124 +26,123 @@ using Spring.Util; #endregion -namespace Spring.Core.TypeConversion +namespace Spring.Core.TypeConversion; + +/// +/// Unit tests for the StringArrayConverter class. +/// +/// Rick Evans +[TestFixture] +public sealed class StringArrayConverterTests { - /// - /// Unit tests for the StringArrayConverter class. - /// - /// Rick Evans - [TestFixture] - public sealed class StringArrayConverterTests + [Test] + public void CanConvertFrom() { - [Test] - public void CanConvertFrom() - { - StringArrayConverter vrt = new StringArrayConverter(); - Assert.IsTrue(vrt.CanConvertFrom(typeof (string)), "Conversion from a string instance must be supported."); - Assert.IsFalse(vrt.CanConvertFrom(null)); - } - - [Test] - public void ConvertFrom() - { - object[] expected = new object[] {"1", "Foo", "3"}; - StringArrayConverter vrt = new StringArrayConverter(); - object actual = vrt.ConvertFrom("1,Foo,3"); - Assert.IsNotNull(actual); - Assert.AreEqual(typeof (string[]), actual.GetType()); - Assert.AreEqual(3, ((string[]) actual).Length, "Wrong number of elements in the resulting array."); - Assert.IsTrue(ArrayUtils.AreEqual(expected, (string[]) actual), - "Individual array elements not correctly converted."); - } - - [Test] - public void ConvertFromPreservesExtraneousWhitespace() - { - object[] expected = new object[] {"1 ", " Foo ", " 3"}; - StringArrayConverter vrt = new StringArrayConverter(); - object actual = vrt.ConvertFrom("1 , Foo , 3"); - Assert.IsNotNull(actual); - Assert.AreEqual(typeof (string[]), actual.GetType()); - Assert.IsTrue(ArrayUtils.AreEqual(expected, (string[]) actual), - "Individual array elements not correctly converted (check the whitespace?)."); - } - - [Test] - public void ConvertFromNullReference() - { - StringArrayConverter vrt = new StringArrayConverter(); - Assert.Throws(() => vrt.ConvertFrom(null)); - } - - [Test] - public void ConvertFromNonSupportedOptionBails() - { - StringArrayConverter vrt = new StringArrayConverter(); - Assert.Throws(() => vrt.ConvertFrom(12)); - } - - [Test] - public void EnsureCultureListSeparatorIsIgnored() - { - CultureInfo originalCulture = Thread.CurrentThread.CurrentCulture; - try - { - CultureInfo frenchCulture = new CultureInfo("fr-FR"); - Thread.CurrentThread.CurrentCulture = frenchCulture; - object[] expected = new object[] {"1", "Foo", "3"}; - StringArrayConverter vrt = new StringArrayConverter(); - // France uses the ';' (semi-colon) to separate list items... - object actual = vrt.ConvertFrom("1,Foo,3"); - Assert.IsNotNull(actual); - Assert.AreEqual(typeof (string[]), actual.GetType()); - Assert.IsTrue(ArrayUtils.AreEqual(expected, (string[]) actual), - "Individual array elements not correctly converted."); - } - finally - { - Thread.CurrentThread.CurrentCulture = originalCulture; - } - } - - [Test] - public void EmptyListSeparator() - { - StringArrayConverter vrt = new StringArrayConverter(); - Assert.Throws(() => vrt.ListSeparator = string.Empty); - } - - [Test] - public void TooLongListSeparator() - { - StringArrayConverter vrt = new StringArrayConverter(); - Assert.Throws(() => vrt.ListSeparator = " "); - } - - [Test] - public void CustomListSeparator() - { - object[] expected = new object[] {"1", "Foo", "3"}; - StringArrayConverter vrt = new StringArrayConverter(); - const string customSeparator = "#"; - vrt.ListSeparator = customSeparator; - object actual = vrt.ConvertFrom(string.Format("1{0}Foo{0}3", customSeparator)); - Assert.IsNotNull(actual); - Assert.AreEqual(typeof (string[]), actual.GetType()); - Assert.IsTrue(ArrayUtils.AreEqual(expected, (string[]) actual), - "Individual array elements not correctly converted."); - } - - [Test] - public void NullingTheListSeparatorMakesItRevertToTheDefault() - { - object[] expected = new object[] {"1", "Foo", "3"}; - StringArrayConverter vrt = new StringArrayConverter(); - vrt.ListSeparator = null; - object actual = vrt.ConvertFrom("1,Foo,3"); - Assert.IsNotNull(actual); - Assert.AreEqual(typeof (string[]), actual.GetType()); - Assert.IsTrue(ArrayUtils.AreEqual(expected, (string[]) actual), - "Individual array elements not correctly converted."); - } + StringArrayConverter vrt = new StringArrayConverter(); + Assert.IsTrue(vrt.CanConvertFrom(typeof(string)), "Conversion from a string instance must be supported."); + Assert.IsFalse(vrt.CanConvertFrom(null)); } -} \ No newline at end of file + + [Test] + public void ConvertFrom() + { + object[] expected = new object[] { "1", "Foo", "3" }; + StringArrayConverter vrt = new StringArrayConverter(); + object actual = vrt.ConvertFrom("1,Foo,3"); + Assert.IsNotNull(actual); + Assert.AreEqual(typeof(string[]), actual.GetType()); + Assert.AreEqual(3, ((string[]) actual).Length, "Wrong number of elements in the resulting array."); + Assert.IsTrue(ArrayUtils.AreEqual(expected, (string[]) actual), + "Individual array elements not correctly converted."); + } + + [Test] + public void ConvertFromPreservesExtraneousWhitespace() + { + object[] expected = new object[] { "1 ", " Foo ", " 3" }; + StringArrayConverter vrt = new StringArrayConverter(); + object actual = vrt.ConvertFrom("1 , Foo , 3"); + Assert.IsNotNull(actual); + Assert.AreEqual(typeof(string[]), actual.GetType()); + Assert.IsTrue(ArrayUtils.AreEqual(expected, (string[]) actual), + "Individual array elements not correctly converted (check the whitespace?)."); + } + + [Test] + public void ConvertFromNullReference() + { + StringArrayConverter vrt = new StringArrayConverter(); + Assert.Throws(() => vrt.ConvertFrom(null)); + } + + [Test] + public void ConvertFromNonSupportedOptionBails() + { + StringArrayConverter vrt = new StringArrayConverter(); + Assert.Throws(() => vrt.ConvertFrom(12)); + } + + [Test] + public void EnsureCultureListSeparatorIsIgnored() + { + CultureInfo originalCulture = Thread.CurrentThread.CurrentCulture; + try + { + CultureInfo frenchCulture = new CultureInfo("fr-FR"); + Thread.CurrentThread.CurrentCulture = frenchCulture; + object[] expected = new object[] { "1", "Foo", "3" }; + StringArrayConverter vrt = new StringArrayConverter(); + // France uses the ';' (semi-colon) to separate list items... + object actual = vrt.ConvertFrom("1,Foo,3"); + Assert.IsNotNull(actual); + Assert.AreEqual(typeof(string[]), actual.GetType()); + Assert.IsTrue(ArrayUtils.AreEqual(expected, (string[]) actual), + "Individual array elements not correctly converted."); + } + finally + { + Thread.CurrentThread.CurrentCulture = originalCulture; + } + } + + [Test] + public void EmptyListSeparator() + { + StringArrayConverter vrt = new StringArrayConverter(); + Assert.Throws(() => vrt.ListSeparator = string.Empty); + } + + [Test] + public void TooLongListSeparator() + { + StringArrayConverter vrt = new StringArrayConverter(); + Assert.Throws(() => vrt.ListSeparator = " "); + } + + [Test] + public void CustomListSeparator() + { + object[] expected = new object[] { "1", "Foo", "3" }; + StringArrayConverter vrt = new StringArrayConverter(); + const string customSeparator = "#"; + vrt.ListSeparator = customSeparator; + object actual = vrt.ConvertFrom(string.Format("1{0}Foo{0}3", customSeparator)); + Assert.IsNotNull(actual); + Assert.AreEqual(typeof(string[]), actual.GetType()); + Assert.IsTrue(ArrayUtils.AreEqual(expected, (string[]) actual), + "Individual array elements not correctly converted."); + } + + [Test] + public void NullingTheListSeparatorMakesItRevertToTheDefault() + { + object[] expected = new object[] { "1", "Foo", "3" }; + StringArrayConverter vrt = new StringArrayConverter(); + vrt.ListSeparator = null; + object actual = vrt.ConvertFrom("1,Foo,3"); + Assert.IsNotNull(actual); + Assert.AreEqual(typeof(string[]), actual.GetType()); + Assert.IsTrue(ArrayUtils.AreEqual(expected, (string[]) actual), + "Individual array elements not correctly converted."); + } +} diff --git a/test/Spring/Spring.Core.Tests/Core/TypeConversion/TimeSpanConverterTests.cs b/test/Spring/Spring.Core.Tests/Core/TypeConversion/TimeSpanConverterTests.cs index 92ec4012..07552d09 100644 --- a/test/Spring/Spring.Core.Tests/Core/TypeConversion/TimeSpanConverterTests.cs +++ b/test/Spring/Spring.Core.Tests/Core/TypeConversion/TimeSpanConverterTests.cs @@ -2,13 +2,13 @@ /* * Copyright � 2002-2011 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. @@ -24,110 +24,109 @@ using NUnit.Framework; #endregion -namespace Spring.Core.TypeConversion +namespace Spring.Core.TypeConversion; + +/// +/// Unit tests for the TimeSpanConverter class. +/// +/// Bruno Baia +[TestFixture] +public sealed class TimeSpanConverterTests { - /// - /// Unit tests for the TimeSpanConverter class. - /// - /// Bruno Baia - [TestFixture] - public sealed class TimeSpanConverterTests + [Test] + public void ConvertFromNullReference() { - [Test] - public void ConvertFromNullReference() - { - TimeSpanConverter tsc = new TimeSpanConverter(); - Assert.Throws(() => tsc.ConvertFrom(null)); - } - - [Test] - public void ConvertFromNonSupportedOptionBails() - { - TimeSpanConverter tsc = new TimeSpanConverter(); - Assert.Throws(() => tsc.ConvertFrom(12)); - } - - [Test] - public void ConvertFromStringMalformed() - { - TimeSpanConverter tsc = new TimeSpanConverter(); - Assert.Throws(() => tsc.ConvertFrom("15a")); - } - - [Test] - public void BaseConvertFrom() - { - TimeSpanConverter tsc = new TimeSpanConverter(); - object timeSpan = tsc.ConvertFrom("00:00:10"); - Assert.IsNotNull(timeSpan); - Assert.IsTrue(timeSpan is TimeSpan); - Assert.AreEqual(TimeSpan.FromSeconds(10), (TimeSpan)timeSpan); - } - - [Test] - public void ConvertFrom() - { - TimeSpanConverter tsc = new TimeSpanConverter(); - object timeSpan = tsc.ConvertFrom("1000"); - Assert.IsNotNull(timeSpan); - Assert.IsTrue(timeSpan is TimeSpan); - Assert.AreEqual(TimeSpan.Parse("1000"), (TimeSpan)timeSpan); - } - - [Test] - public void ConvertFromStringWithMilliSecondSpecifier() - { - TimeSpanConverter tsc = new TimeSpanConverter(); - object timeSpan = tsc.ConvertFrom("100ms"); - Assert.IsNotNull(timeSpan); - Assert.IsTrue(timeSpan is TimeSpan); - Assert.AreEqual(TimeSpan.FromMilliseconds(100), (TimeSpan)timeSpan); - } - - [Test] - public void ConvertFromStringWithSecondSpecifier() - { - TimeSpanConverter tsc = new TimeSpanConverter(); - object timeSpan = tsc.ConvertFrom("10s"); - Assert.IsNotNull(timeSpan); - Assert.IsTrue(timeSpan is TimeSpan); - Assert.AreEqual(TimeSpan.FromSeconds(10), (TimeSpan)timeSpan); - } - - [Test] - public void ConvertFromStringWithMinuteSpecifier() - { - TimeSpanConverter tsc = new TimeSpanConverter(); - object timeSpan = tsc.ConvertFrom("2m"); - Assert.IsNotNull(timeSpan); - Assert.IsTrue(timeSpan is TimeSpan); - Assert.AreEqual(TimeSpan.FromMinutes(2), (TimeSpan)timeSpan); - } - - [Test] - public void ConvertFromStringWithHourSpecifier() - { - TimeSpanConverter tsc = new TimeSpanConverter(); - - object timeSpan = tsc.ConvertFrom("1H"); - Assert.IsNotNull(timeSpan); - Assert.IsTrue(timeSpan is TimeSpan); - Assert.AreEqual(TimeSpan.FromHours(1), (TimeSpan)timeSpan); - - tsc.ConvertFrom("1h"); - Assert.IsNotNull(timeSpan); - Assert.IsTrue(timeSpan is TimeSpan); - Assert.AreEqual(TimeSpan.FromHours(1), (TimeSpan)timeSpan); - } - - [Test] - public void ConvertFromStringWithDaySpecifier() - { - TimeSpanConverter tsc = new TimeSpanConverter(); - object timeSpan = tsc.ConvertFrom("1d"); - Assert.IsNotNull(timeSpan); - Assert.IsTrue(timeSpan is TimeSpan); - Assert.AreEqual(TimeSpan.FromDays(1), (TimeSpan)timeSpan); - } + TimeSpanConverter tsc = new TimeSpanConverter(); + Assert.Throws(() => tsc.ConvertFrom(null)); } -} \ No newline at end of file + + [Test] + public void ConvertFromNonSupportedOptionBails() + { + TimeSpanConverter tsc = new TimeSpanConverter(); + Assert.Throws(() => tsc.ConvertFrom(12)); + } + + [Test] + public void ConvertFromStringMalformed() + { + TimeSpanConverter tsc = new TimeSpanConverter(); + Assert.Throws(() => tsc.ConvertFrom("15a")); + } + + [Test] + public void BaseConvertFrom() + { + TimeSpanConverter tsc = new TimeSpanConverter(); + object timeSpan = tsc.ConvertFrom("00:00:10"); + Assert.IsNotNull(timeSpan); + Assert.IsTrue(timeSpan is TimeSpan); + Assert.AreEqual(TimeSpan.FromSeconds(10), (TimeSpan) timeSpan); + } + + [Test] + public void ConvertFrom() + { + TimeSpanConverter tsc = new TimeSpanConverter(); + object timeSpan = tsc.ConvertFrom("1000"); + Assert.IsNotNull(timeSpan); + Assert.IsTrue(timeSpan is TimeSpan); + Assert.AreEqual(TimeSpan.Parse("1000"), (TimeSpan) timeSpan); + } + + [Test] + public void ConvertFromStringWithMilliSecondSpecifier() + { + TimeSpanConverter tsc = new TimeSpanConverter(); + object timeSpan = tsc.ConvertFrom("100ms"); + Assert.IsNotNull(timeSpan); + Assert.IsTrue(timeSpan is TimeSpan); + Assert.AreEqual(TimeSpan.FromMilliseconds(100), (TimeSpan) timeSpan); + } + + [Test] + public void ConvertFromStringWithSecondSpecifier() + { + TimeSpanConverter tsc = new TimeSpanConverter(); + object timeSpan = tsc.ConvertFrom("10s"); + Assert.IsNotNull(timeSpan); + Assert.IsTrue(timeSpan is TimeSpan); + Assert.AreEqual(TimeSpan.FromSeconds(10), (TimeSpan) timeSpan); + } + + [Test] + public void ConvertFromStringWithMinuteSpecifier() + { + TimeSpanConverter tsc = new TimeSpanConverter(); + object timeSpan = tsc.ConvertFrom("2m"); + Assert.IsNotNull(timeSpan); + Assert.IsTrue(timeSpan is TimeSpan); + Assert.AreEqual(TimeSpan.FromMinutes(2), (TimeSpan) timeSpan); + } + + [Test] + public void ConvertFromStringWithHourSpecifier() + { + TimeSpanConverter tsc = new TimeSpanConverter(); + + object timeSpan = tsc.ConvertFrom("1H"); + Assert.IsNotNull(timeSpan); + Assert.IsTrue(timeSpan is TimeSpan); + Assert.AreEqual(TimeSpan.FromHours(1), (TimeSpan) timeSpan); + + tsc.ConvertFrom("1h"); + Assert.IsNotNull(timeSpan); + Assert.IsTrue(timeSpan is TimeSpan); + Assert.AreEqual(TimeSpan.FromHours(1), (TimeSpan) timeSpan); + } + + [Test] + public void ConvertFromStringWithDaySpecifier() + { + TimeSpanConverter tsc = new TimeSpanConverter(); + object timeSpan = tsc.ConvertFrom("1d"); + Assert.IsNotNull(timeSpan); + Assert.IsTrue(timeSpan is TimeSpan); + Assert.AreEqual(TimeSpan.FromDays(1), (TimeSpan) timeSpan); + } +} diff --git a/test/Spring/Spring.Core.Tests/Core/TypeConversion/TypeConversionUtilsTests.cs b/test/Spring/Spring.Core.Tests/Core/TypeConversion/TypeConversionUtilsTests.cs index da3f3053..93eee8b7 100644 --- a/test/Spring/Spring.Core.Tests/Core/TypeConversion/TypeConversionUtilsTests.cs +++ b/test/Spring/Spring.Core.Tests/Core/TypeConversion/TypeConversionUtilsTests.cs @@ -24,53 +24,52 @@ using NUnit.Framework; #endregion -namespace Spring.Core.TypeConversion +namespace Spring.Core.TypeConversion; + +/// +/// This class contains tests for TypeConversionUtils +/// +/// Mark Pollack +/// Andreas Kluth +[TestFixture] +public class TypeConversionUtilsTests { - /// - /// This class contains tests for TypeConversionUtils - /// - /// Mark Pollack - /// Andreas Kluth - [TestFixture] - public class TypeConversionUtilsTests + [Test] + public void NullAbleTest() { - [Test] - public void NullAbleTest() - { - object o = TypeConversionUtils.ConvertValueIfNecessary(typeof(DateTime?), "", "bla"); - Assert.IsNull(o); - } - - [Test] - [SetCulture( "en-US" )] - public void ConvertValueForDecimalMarkWithPointReturnsValue() - { - object o = TypeConversionUtils.ConvertValueIfNecessary( typeof( Double ), "1.2", "foo" ); - Assert.That( o, Is.EqualTo( 1.2 ) ); - } - - [Test] - [SetCulture( "en-US" )] - public void ConvertValueForDecimalMarkWithCommaFails() - { - TestDelegate testDelegate = () => TypeConversionUtils.ConvertValueIfNecessary( typeof( Double ), "1,2", "foo" ); - Assert.Throws( testDelegate ); - } - - [Test] - [SetCulture( "nl-NL" )] - public void ConvertValueWithDutchCultureForDecimalMarkWithPointReturnsValue() - { - object o = TypeConversionUtils.ConvertValueIfNecessary( typeof( Double ), "1.2", "foo" ); - Assert.That( o, Is.EqualTo( 1.2 ) ); - } - - [Test] - [SetCulture( "nl-NL" )] - public void ConvertValueWithDutchCultureForDecimalMarkWithCommaReturnsValue() - { - object o = TypeConversionUtils.ConvertValueIfNecessary( typeof( Double ), "1,2", "foo" ); - Assert.That( o, Is.EqualTo( 1.2 ) ); - } + object o = TypeConversionUtils.ConvertValueIfNecessary(typeof(DateTime?), "", "bla"); + Assert.IsNull(o); } -} \ No newline at end of file + + [Test] + [SetCulture("en-US")] + public void ConvertValueForDecimalMarkWithPointReturnsValue() + { + object o = TypeConversionUtils.ConvertValueIfNecessary(typeof(Double), "1.2", "foo"); + Assert.That(o, Is.EqualTo(1.2)); + } + + [Test] + [SetCulture("en-US")] + public void ConvertValueForDecimalMarkWithCommaFails() + { + TestDelegate testDelegate = () => TypeConversionUtils.ConvertValueIfNecessary(typeof(Double), "1,2", "foo"); + Assert.Throws(testDelegate); + } + + [Test] + [SetCulture("nl-NL")] + public void ConvertValueWithDutchCultureForDecimalMarkWithPointReturnsValue() + { + object o = TypeConversionUtils.ConvertValueIfNecessary(typeof(Double), "1.2", "foo"); + Assert.That(o, Is.EqualTo(1.2)); + } + + [Test] + [SetCulture("nl-NL")] + public void ConvertValueWithDutchCultureForDecimalMarkWithCommaReturnsValue() + { + object o = TypeConversionUtils.ConvertValueIfNecessary(typeof(Double), "1,2", "foo"); + Assert.That(o, Is.EqualTo(1.2)); + } +} diff --git a/test/Spring/Spring.Core.Tests/Core/TypeConversion/TypeConverterRegistryTests.cs b/test/Spring/Spring.Core.Tests/Core/TypeConversion/TypeConverterRegistryTests.cs index 93233bc5..20523afa 100644 --- a/test/Spring/Spring.Core.Tests/Core/TypeConversion/TypeConverterRegistryTests.cs +++ b/test/Spring/Spring.Core.Tests/Core/TypeConversion/TypeConverterRegistryTests.cs @@ -21,57 +21,55 @@ #region Imports using System.ComponentModel; - using NUnit.Framework; #endregion -namespace Spring.Core.TypeConversion +namespace Spring.Core.TypeConversion; + +/// +/// Unit tests for the TypeConverterRegistry class. +/// +/// Bruno Baia +[TestFixture] +public sealed class TypeConverterRegistryTests { - /// - /// Unit tests for the TypeConverterRegistry class. - /// - /// Bruno Baia - [TestFixture] - public sealed class TypeConverterRegistryTests + [Test] + public void GetConverterForEnums() { - [Test] - public void GetConverterForEnums() - { - TypeConverter converter = TypeConverterRegistry.GetConverter(typeof(DayOfWeek)); - Assert.IsTrue(converter is EnumConverter); - } + TypeConverter converter = TypeConverterRegistry.GetConverter(typeof(DayOfWeek)); + Assert.IsTrue(converter is EnumConverter); + } - [Test] - public void GetInternalConverter() - { - TypeConverter converter = TypeConverterRegistry.GetConverter(typeof(int)); - Assert.IsTrue(converter is Int32Converter); - } + [Test] + public void GetInternalConverter() + { + TypeConverter converter = TypeConverterRegistry.GetConverter(typeof(int)); + Assert.IsTrue(converter is Int32Converter); + } - [Test] - public void GetSpringConverter() - { - TypeConverter converter = TypeConverterRegistry.GetConverter(typeof(string[])); - Assert.IsTrue(converter is StringArrayConverter); - } + [Test] + public void GetSpringConverter() + { + TypeConverter converter = TypeConverterRegistry.GetConverter(typeof(string[])); + Assert.IsTrue(converter is StringArrayConverter); + } - [Test] - public void RegisterConverter() - { - TypeConverterRegistry.RegisterConverter("System.DateTime", "System.ComponentModel.DateTimeConverter"); - } + [Test] + public void RegisterConverter() + { + TypeConverterRegistry.RegisterConverter("System.DateTime", "System.ComponentModel.DateTimeConverter"); + } - [Test] - public void RegisterConverterWithNonResolvableType() - { - Assert.Throws(() => TypeConverterRegistry.RegisterConverter("Systemm.DateTime", "System.ComponentModel.DateTimeConverter")); - } + [Test] + public void RegisterConverterWithNonResolvableType() + { + Assert.Throws(() => TypeConverterRegistry.RegisterConverter("Systemm.DateTime", "System.ComponentModel.DateTimeConverter")); + } - [Test] - public void RegisterConverterWithNonTypeConverter() - { - Assert.Throws(() => TypeConverterRegistry.RegisterConverter("System.DateTime", "System.DateTime")); - } + [Test] + public void RegisterConverterWithNonTypeConverter() + { + Assert.Throws(() => TypeConverterRegistry.RegisterConverter("System.DateTime", "System.DateTime")); } } diff --git a/test/Spring/Spring.Core.Tests/Core/TypeConversion/UniqueKeyConverterTests.cs b/test/Spring/Spring.Core.Tests/Core/TypeConversion/UniqueKeyConverterTests.cs index a4c9e1a2..2f081b5a 100644 --- a/test/Spring/Spring.Core.Tests/Core/TypeConversion/UniqueKeyConverterTests.cs +++ b/test/Spring/Spring.Core.Tests/Core/TypeConversion/UniqueKeyConverterTests.cs @@ -26,98 +26,96 @@ using Spring.Util; #endregion -namespace Spring.Core.TypeConversion +namespace Spring.Core.TypeConversion; + +/// +/// Tests functionality. +/// +/// Erich Eichinger +[TestFixture] +public class UniqueKeyConverterTests { - /// - /// Tests functionality. - /// - /// Erich Eichinger - [TestFixture] - public class UniqueKeyConverterTests + [Test] + public void CanConvertFromStringOnly() { - [Test] - public void CanConvertFromStringOnly() - { - TypeConverter c = new UniqueKeyConverter(); - Assert.IsTrue(c.CanConvertFrom(typeof(string))); - Assert.IsFalse(c.CanConvertFrom(typeof(object))); - } - - [Test] - public void CanConvertToStringOnly() - { - TypeConverter c = new UniqueKeyConverter(); - Assert.IsTrue(c.CanConvertTo(typeof(string))); - Assert.IsFalse(c.CanConvertTo(typeof(object))); - } - - [Test] - public void ConvertToStringOrUniqueKeyOnly() - { - TypeConverter c = new UniqueKeyConverter(); - UniqueKey key = UniqueKey.GetInstanceScoped(new object(), "PartialKey"); - - c.ConvertTo(key, typeof(UniqueKey)); - c.ConvertTo(key, typeof(string)); - try - { - c.ConvertTo(key, typeof(object)); - Assert.Fail(); - } - catch(NotSupportedException) {} - } - - [Test] - public void ConvertFromStringOrUniqueKeyOnly() - { - TypeConverter c = new UniqueKeyConverter(); - UniqueKey key = UniqueKey.GetInstanceScoped(new object(), "PartialKey"); - c.ConvertFrom(key); - c.ConvertFrom(key.ToString()); - try - { - c.ConvertFrom(new object()); - Assert.Fail(); - } - catch(NotSupportedException) {} - } - - [Test] - public void ConvertFromReturnsNullIfInputNull() - { - TypeConverter c = new UniqueKeyConverter(); - Assert.IsNull(c.ConvertFrom(null)); - } - - [Test] - public void ConvertToReturnsNullIfInputNull() - { - TypeConverter c = new UniqueKeyConverter(); - Assert.IsNull(c.ConvertTo(null, typeof(string))); - } - - [Test] - public void ConvertToEqualsToString() - { - object testObject = new object(); - UniqueKey key = UniqueKey.GetInstanceScoped(testObject, "PartialKey"); - - TypeConverter c = new UniqueKeyConverter(); - string stringKey = (string) c.ConvertTo(key, typeof(string)); - Assert.AreEqual(key.ToString(), stringKey); - } - - [Test] - public void ConvertToAndFromAreInSync() - { - object testObject = new object(); - UniqueKey expectedKey = UniqueKey.GetInstanceScoped(testObject, "PartialKey"); - - TypeConverter c = new UniqueKeyConverter(); - string stringKey = (string)c.ConvertTo(expectedKey, typeof(string)); - UniqueKey key2 = (UniqueKey) c.ConvertFrom(stringKey); - Assert.AreEqual( expectedKey, key2 ); - } - + TypeConverter c = new UniqueKeyConverter(); + Assert.IsTrue(c.CanConvertFrom(typeof(string))); + Assert.IsFalse(c.CanConvertFrom(typeof(object))); } -} \ No newline at end of file + + [Test] + public void CanConvertToStringOnly() + { + TypeConverter c = new UniqueKeyConverter(); + Assert.IsTrue(c.CanConvertTo(typeof(string))); + Assert.IsFalse(c.CanConvertTo(typeof(object))); + } + + [Test] + public void ConvertToStringOrUniqueKeyOnly() + { + TypeConverter c = new UniqueKeyConverter(); + UniqueKey key = UniqueKey.GetInstanceScoped(new object(), "PartialKey"); + + c.ConvertTo(key, typeof(UniqueKey)); + c.ConvertTo(key, typeof(string)); + try + { + c.ConvertTo(key, typeof(object)); + Assert.Fail(); + } + catch (NotSupportedException) { } + } + + [Test] + public void ConvertFromStringOrUniqueKeyOnly() + { + TypeConverter c = new UniqueKeyConverter(); + UniqueKey key = UniqueKey.GetInstanceScoped(new object(), "PartialKey"); + c.ConvertFrom(key); + c.ConvertFrom(key.ToString()); + try + { + c.ConvertFrom(new object()); + Assert.Fail(); + } + catch (NotSupportedException) { } + } + + [Test] + public void ConvertFromReturnsNullIfInputNull() + { + TypeConverter c = new UniqueKeyConverter(); + Assert.IsNull(c.ConvertFrom(null)); + } + + [Test] + public void ConvertToReturnsNullIfInputNull() + { + TypeConverter c = new UniqueKeyConverter(); + Assert.IsNull(c.ConvertTo(null, typeof(string))); + } + + [Test] + public void ConvertToEqualsToString() + { + object testObject = new object(); + UniqueKey key = UniqueKey.GetInstanceScoped(testObject, "PartialKey"); + + TypeConverter c = new UniqueKeyConverter(); + string stringKey = (string) c.ConvertTo(key, typeof(string)); + Assert.AreEqual(key.ToString(), stringKey); + } + + [Test] + public void ConvertToAndFromAreInSync() + { + object testObject = new object(); + UniqueKey expectedKey = UniqueKey.GetInstanceScoped(testObject, "PartialKey"); + + TypeConverter c = new UniqueKeyConverter(); + string stringKey = (string) c.ConvertTo(expectedKey, typeof(string)); + UniqueKey key2 = (UniqueKey) c.ConvertFrom(stringKey); + Assert.AreEqual(expectedKey, key2); + } +} diff --git a/test/Spring/Spring.Core.Tests/Core/TypeConversion/UriConverterTests.cs b/test/Spring/Spring.Core.Tests/Core/TypeConversion/UriConverterTests.cs index 103f255d..f112b33d 100644 --- a/test/Spring/Spring.Core.Tests/Core/TypeConversion/UriConverterTests.cs +++ b/test/Spring/Spring.Core.Tests/Core/TypeConversion/UriConverterTests.cs @@ -24,59 +24,58 @@ using NUnit.Framework; #endregion -namespace Spring.Core.TypeConversion +namespace Spring.Core.TypeConversion; + +/// +/// Unit tests for the UriConverter class. +/// +/// Rick Evans +[TestFixture] +public sealed class UriConverterTests { - /// - /// Unit tests for the UriConverter class. - /// - /// Rick Evans - [TestFixture] - public sealed class UriConverterTests + [Test] + public void CanConvertFrom() { - [Test] - public void CanConvertFrom () - { - UriConverter vrt = new UriConverter (); - Assert.IsTrue (vrt.CanConvertFrom (typeof (string)), "Conversion from a string instance must be supported."); - Assert.IsFalse (vrt.CanConvertFrom (typeof (int))); - } + UriConverter vrt = new UriConverter(); + Assert.IsTrue(vrt.CanConvertFrom(typeof(string)), "Conversion from a string instance must be supported."); + Assert.IsFalse(vrt.CanConvertFrom(typeof(int))); + } - [Test] - public void ConvertFrom () - { - UriConverter vrt = new UriConverter (); - object actual = vrt.ConvertFrom ("svn://localhost/Spring/trunk/"); - Assert.IsNotNull (actual); - Assert.AreEqual (typeof (System.Uri), actual.GetType ()); - } + [Test] + public void ConvertFrom() + { + UriConverter vrt = new UriConverter(); + object actual = vrt.ConvertFrom("svn://localhost/Spring/trunk/"); + Assert.IsNotNull(actual); + Assert.AreEqual(typeof(System.Uri), actual.GetType()); + } - [Test] - public void ConvertFromMalformedUriBails () + [Test] + public void ConvertFromMalformedUriBails() + { + try { - try - { - UriConverter vrt = new UriConverter (); - object actual = vrt.ConvertFrom ("$TheAngelGang"); - } - catch (Exception ex) - { - // check that the inner exception was doe to the malformed URL - Assert.IsTrue (ex.InnerException is UriFormatException); - } + UriConverter vrt = new UriConverter(); + object actual = vrt.ConvertFrom("$TheAngelGang"); } - - [Test] - public void ConvertFromNullReference () + catch (Exception ex) { - UriConverter vrt = new UriConverter (); - Assert.Throws(() => vrt.ConvertFrom (null)); + // check that the inner exception was doe to the malformed URL + Assert.IsTrue(ex.InnerException is UriFormatException); } + } - [Test] - public void ConvertFromNonSupportedOptionBails () - { - UriConverter vrt = new UriConverter (); - Assert.Throws(() => vrt.ConvertFrom (12)); - } - } + [Test] + public void ConvertFromNullReference() + { + UriConverter vrt = new UriConverter(); + Assert.Throws(() => vrt.ConvertFrom(null)); + } + + [Test] + public void ConvertFromNonSupportedOptionBails() + { + UriConverter vrt = new UriConverter(); + Assert.Throws(() => vrt.ConvertFrom(12)); + } } diff --git a/test/Spring/Spring.Core.Tests/Core/TypeResolution/CachedTypeResolverTests.cs b/test/Spring/Spring.Core.Tests/Core/TypeResolution/CachedTypeResolverTests.cs index 76a01600..6cf95744 100644 --- a/test/Spring/Spring.Core.Tests/Core/TypeResolution/CachedTypeResolverTests.cs +++ b/test/Spring/Spring.Core.Tests/Core/TypeResolution/CachedTypeResolverTests.cs @@ -19,36 +19,34 @@ #endregion using FakeItEasy; - using NUnit.Framework; -namespace Spring.Core.TypeResolution +namespace Spring.Core.TypeResolution; + +/// +/// Unit tests for the CachedTypeResolver class. +/// +/// Rick Evans +[TestFixture] +public sealed class CachedTypeResolverTests { - /// - /// Unit tests for the CachedTypeResolver class. - /// - /// Rick Evans - [TestFixture] - public sealed class CachedTypeResolverTests + [SetUp] + public void SetUp() { - [SetUp] - public void SetUp() - { - } - - [Test] - public void ResolveWithNullTypeName() - { - ITypeResolver mockResolver = A.Fake(); - - CachedTypeResolver resolver = new CachedTypeResolver(mockResolver); - Assert.Throws(() => resolver.Resolve(null)); - } - - [Test] - public void InstantiateWithNullTypeResolver() - { - Assert.Throws(() => new CachedTypeResolver(null)); - } } -} \ No newline at end of file + + [Test] + public void ResolveWithNullTypeName() + { + ITypeResolver mockResolver = A.Fake(); + + CachedTypeResolver resolver = new CachedTypeResolver(mockResolver); + Assert.Throws(() => resolver.Resolve(null)); + } + + [Test] + public void InstantiateWithNullTypeResolver() + { + Assert.Throws(() => new CachedTypeResolver(null)); + } +} diff --git a/test/Spring/Spring.Core.Tests/Core/TypeResolution/GenericTypeResolverTests.cs b/test/Spring/Spring.Core.Tests/Core/TypeResolution/GenericTypeResolverTests.cs index ebd3c216..d752df14 100644 --- a/test/Spring/Spring.Core.Tests/Core/TypeResolution/GenericTypeResolverTests.cs +++ b/test/Spring/Spring.Core.Tests/Core/TypeResolution/GenericTypeResolverTests.cs @@ -25,100 +25,99 @@ using Spring.Objects; #endregion -namespace Spring.Core.TypeResolution +namespace Spring.Core.TypeResolution; + +/// +/// Unit tests for the GenericTypeResolver class. +/// +/// Bruno Baia +[TestFixture] +public class GenericTypeResolverTests : TypeResolverTests { - /// - /// Unit tests for the GenericTypeResolver class. - /// - /// Bruno Baia - [TestFixture] - public class GenericTypeResolverTests : TypeResolverTests + protected override ITypeResolver GetTypeResolver() { - protected override ITypeResolver GetTypeResolver() - { - return new GenericTypeResolver(); - } + return new GenericTypeResolver(); + } - [Test] - public void ResolveLocalAssemblyGenericType() - { - Type t = GetTypeResolver().Resolve("Spring.Objects.TestGenericObject< int, string>"); - Assert.AreEqual(typeof(TestGenericObject), t); - } + [Test] + public void ResolveLocalAssemblyGenericType() + { + Type t = GetTypeResolver().Resolve("Spring.Objects.TestGenericObject< int, string>"); + Assert.AreEqual(typeof(TestGenericObject), t); + } - [Test] - public void ResolveLocalAssemblyGenericTypeDefinition() - { - // CLOVER:ON - Type t = GetTypeResolver().Resolve("Spring.Objects.TestGenericObject< ,>"); - // CLOVER:OFF - Assert.AreEqual(typeof(TestGenericObject<,>), t); - } + [Test] + public void ResolveLocalAssemblyGenericTypeDefinition() + { + // CLOVER:ON + Type t = GetTypeResolver().Resolve("Spring.Objects.TestGenericObject< ,>"); + // CLOVER:OFF + Assert.AreEqual(typeof(TestGenericObject<,>), t); + } - [Test] - public void ResolveLocalAssemblyGenericTypeOpen() - { - Assert.Throws(() => GetTypeResolver().Resolve("Spring.Objects.TestGenericObject")); - } + [Test] + public void ResolveLocalAssemblyGenericTypeOpen() + { + Assert.Throws(() => GetTypeResolver().Resolve("Spring.Objects.TestGenericObject")); + } - [Test] - public void ResolveGenericTypeWithAssemblyName() - { - Type t = GetTypeResolver().Resolve("System.Collections.Generic.Stack, System"); - Assert.AreEqual(typeof(System.Collections.Generic.Stack), t); - } + [Test] + public void ResolveGenericTypeWithAssemblyName() + { + Type t = GetTypeResolver().Resolve("System.Collections.Generic.Stack, System"); + Assert.AreEqual(typeof(System.Collections.Generic.Stack), t); + } - [Test] - public void ResolveGenericArrayType() - { - Type t = GetTypeResolver().Resolve("System.Nullable<[System.Int32, mscorlib]>[,]"); - Assert.AreEqual(typeof(int?[,]), t); - t = GetTypeResolver().Resolve("System.Nullable`1[int][,]"); - Assert.AreEqual(typeof(int?[,]), t); - } + [Test] + public void ResolveGenericArrayType() + { + Type t = GetTypeResolver().Resolve("System.Nullable<[System.Int32, mscorlib]>[,]"); + Assert.AreEqual(typeof(int?[,]), t); + t = GetTypeResolver().Resolve("System.Nullable`1[int][,]"); + Assert.AreEqual(typeof(int?[,]), t); + } - [Test] - public void ResolveGenericArrayTypeWithAssemblyName() - { - Type t = GetTypeResolver().Resolve("System.Nullable<[System.Int32, mscorlib]>[,], mscorlib"); - Assert.AreEqual(typeof(int?[,]), t); - t = GetTypeResolver().Resolve("System.Nullable<[System.Int32, mscorlib]>[,], mscorlib"); - Assert.AreEqual(typeof(int?[,]), t); - t = GetTypeResolver().Resolve("System.Nullable`1[[System.Int32, mscorlib]][,], mscorlib"); - Assert.AreEqual(typeof(int?[,]), t); - } + [Test] + public void ResolveGenericArrayTypeWithAssemblyName() + { + Type t = GetTypeResolver().Resolve("System.Nullable<[System.Int32, mscorlib]>[,], mscorlib"); + Assert.AreEqual(typeof(int?[,]), t); + t = GetTypeResolver().Resolve("System.Nullable<[System.Int32, mscorlib]>[,], mscorlib"); + Assert.AreEqual(typeof(int?[,]), t); + t = GetTypeResolver().Resolve("System.Nullable`1[[System.Int32, mscorlib]][,], mscorlib"); + Assert.AreEqual(typeof(int?[,]), t); + } - [Test] - public void ResolveAmbiguousGenericTypeWithAssemblyName() - { - Assert.Throws(() => GetTypeResolver().Resolve("Spring.Objects.TestGenericObject, System, string>")); - } + [Test] + public void ResolveAmbiguousGenericTypeWithAssemblyName() + { + Assert.Throws(() => GetTypeResolver().Resolve("Spring.Objects.TestGenericObject, System, string>")); + } - [Test] - public void ResolveMalformedGenericType() - { - Assert.Throws(() => GetTypeResolver().Resolve("Spring.Objects.TestGenericObject>")); - } + [Test] + public void ResolveMalformedGenericType() + { + Assert.Throws(() => GetTypeResolver().Resolve("Spring.Objects.TestGenericObject>")); + } - [Test] - public void ResolveNestedGenericTypeWithAssemblyName() - { - Type t = GetTypeResolver().Resolve("System.Collections.Generic.Stack< Spring.Objects.TestGenericObject >, System"); - Assert.AreEqual(typeof(System.Collections.Generic.Stack>), t); - } + [Test] + public void ResolveNestedGenericTypeWithAssemblyName() + { + Type t = GetTypeResolver().Resolve("System.Collections.Generic.Stack< Spring.Objects.TestGenericObject >, System"); + Assert.AreEqual(typeof(System.Collections.Generic.Stack>), t); + } - [Test] - public void ResolveClrNotationStyleGenericTypeWithAssemblyName() - { - Type t = GetTypeResolver().Resolve("System.Collections.Generic.Stack`1[ [Spring.Objects.TestGenericObject`2[int, string], Spring.Core.Tests] ], System"); - Assert.AreEqual(typeof(System.Collections.Generic.Stack>), t); - } + [Test] + public void ResolveClrNotationStyleGenericTypeWithAssemblyName() + { + Type t = GetTypeResolver().Resolve("System.Collections.Generic.Stack`1[ [Spring.Objects.TestGenericObject`2[int, string], Spring.Core.Tests] ], System"); + Assert.AreEqual(typeof(System.Collections.Generic.Stack>), t); + } - [Test] - public void ResolveNestedQuotedGenericTypeWithAssemblyName() - { - Type t = GetTypeResolver().Resolve("System.Collections.Generic.Stack< [Spring.Objects.TestGenericObject, Spring.Core.Tests] >, System"); - Assert.AreEqual(typeof(System.Collections.Generic.Stack>), t); - } + [Test] + public void ResolveNestedQuotedGenericTypeWithAssemblyName() + { + Type t = GetTypeResolver().Resolve("System.Collections.Generic.Stack< [Spring.Objects.TestGenericObject, Spring.Core.Tests] >, System"); + Assert.AreEqual(typeof(System.Collections.Generic.Stack>), t); } } diff --git a/test/Spring/Spring.Core.Tests/Core/TypeResolution/TypeAssemblyHolderTests.cs b/test/Spring/Spring.Core.Tests/Core/TypeResolution/TypeAssemblyHolderTests.cs index 77a0ab83..61f809a8 100644 --- a/test/Spring/Spring.Core.Tests/Core/TypeResolution/TypeAssemblyHolderTests.cs +++ b/test/Spring/Spring.Core.Tests/Core/TypeResolution/TypeAssemblyHolderTests.cs @@ -25,53 +25,52 @@ using Spring.Objects; #endregion -namespace Spring.Core.TypeResolution +namespace Spring.Core.TypeResolution; + +/// +/// +/// +/// Erich Eichinger +[TestFixture] +public class TypeAssemblyHolderTests { - /// - /// - /// - /// Erich Eichinger - [TestFixture] - public class TypeAssemblyHolderTests + [Test] + public void CanTakeQualifiedType() { - [Test] - public void CanTakeQualifiedType() - { - Type testType = typeof(TestObject); - TypeAssemblyHolder tah = new TypeAssemblyHolder(testType.AssemblyQualifiedName); - Assert.IsTrue(tah.IsAssemblyQualified); - Assert.AreEqual(testType.FullName, tah.TypeName); - Assert.AreEqual(testType.Assembly.FullName, tah.AssemblyName); - } + Type testType = typeof(TestObject); + TypeAssemblyHolder tah = new TypeAssemblyHolder(testType.AssemblyQualifiedName); + Assert.IsTrue(tah.IsAssemblyQualified); + Assert.AreEqual(testType.FullName, tah.TypeName); + Assert.AreEqual(testType.Assembly.FullName, tah.AssemblyName); + } - [Test] - public void CanTakeUnqualifiedType() - { - Type testType = typeof(TestObject); - TypeAssemblyHolder tah = new TypeAssemblyHolder(testType.FullName); - Assert.IsFalse(tah.IsAssemblyQualified); - Assert.AreEqual(testType.FullName, tah.TypeName); - Assert.AreEqual(null, tah.AssemblyName); - } + [Test] + public void CanTakeUnqualifiedType() + { + Type testType = typeof(TestObject); + TypeAssemblyHolder tah = new TypeAssemblyHolder(testType.FullName); + Assert.IsFalse(tah.IsAssemblyQualified); + Assert.AreEqual(testType.FullName, tah.TypeName); + Assert.AreEqual(null, tah.AssemblyName); + } - [Test] - public void CanTakeUnqualifiedGenericType() - { - Type testType = typeof(TestGenericObject); - TypeAssemblyHolder tah = new TypeAssemblyHolder(testType.FullName); - Assert.IsFalse(tah.IsAssemblyQualified); - Assert.AreEqual(testType.FullName, tah.TypeName); - Assert.AreEqual(null, tah.AssemblyName); - } + [Test] + public void CanTakeUnqualifiedGenericType() + { + Type testType = typeof(TestGenericObject); + TypeAssemblyHolder tah = new TypeAssemblyHolder(testType.FullName); + Assert.IsFalse(tah.IsAssemblyQualified); + Assert.AreEqual(testType.FullName, tah.TypeName); + Assert.AreEqual(null, tah.AssemblyName); + } - [Test] - public void CanTakeQualifiedGenericType() - { - Type testType = typeof(TestGenericObject); - TypeAssemblyHolder tah = new TypeAssemblyHolder(testType.AssemblyQualifiedName); - Assert.IsTrue(tah.IsAssemblyQualified); - Assert.AreEqual(testType.FullName, tah.TypeName); - Assert.AreEqual(testType.Assembly.FullName, tah.AssemblyName); - } + [Test] + public void CanTakeQualifiedGenericType() + { + Type testType = typeof(TestGenericObject); + TypeAssemblyHolder tah = new TypeAssemblyHolder(testType.AssemblyQualifiedName); + Assert.IsTrue(tah.IsAssemblyQualified); + Assert.AreEqual(testType.FullName, tah.TypeName); + Assert.AreEqual(testType.Assembly.FullName, tah.AssemblyName); } } diff --git a/test/Spring/Spring.Core.Tests/Core/TypeResolution/TypeRegistryTests.cs b/test/Spring/Spring.Core.Tests/Core/TypeResolution/TypeRegistryTests.cs index 717aef33..e5892a6d 100644 --- a/test/Spring/Spring.Core.Tests/Core/TypeResolution/TypeRegistryTests.cs +++ b/test/Spring/Spring.Core.Tests/Core/TypeResolution/TypeRegistryTests.cs @@ -1,727 +1,725 @@ #region License -/* - * Copyright � 2002-2011 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. +/* + * Copyright � 2002-2011 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 +#endregion #region Imports using NUnit.Framework; using Spring.Objects; using Spring.Objects.Factory; - -using IBar=Spring.Objects.Factory.IBar; +using IBar = Spring.Objects.Factory.IBar; using Spring.Context; using Spring.Context.Support; #endregion -namespace Spring.Core.TypeResolution +namespace Spring.Core.TypeResolution; + +/// +/// Unit tests for the TypeRegistry class. +/// +/// Aleksandar Seovic +/// Rick Evans +[TestFixture] +public sealed class TypeRegistryTests { - /// - /// Unit tests for the TypeRegistry class. - /// - /// Aleksandar Seovic - /// Rick Evans - [TestFixture] - public sealed class TypeRegistryTests - { - [Test] - public void TestAliasResolution() - { - TypeRegistry.RegisterType("Foo", typeof (Foo)); - TypeRegistry.RegisterType("Bar", "Spring.Objects.Factory.Bar, Spring.Core.Tests"); - - Assert.AreEqual(TypeRegistry.ResolveType("Foo"), typeof (Foo)); - Assert.AreEqual(TypeRegistry.ResolveType("Bar"), typeof (Bar)); - - IApplicationContext ctx = - new XmlApplicationContext("assembly://Spring.Core.Tests/Spring.Core.TypeResolution/aliasedObjects.xml"); - - Foo foo = ctx.GetObject("aliasedType") as Foo; - Assert.IsNotNull(foo); - Assert.IsNotNull(foo.Bar); - Assert.AreEqual(foo.Bar, typeof (Bar)); - Assert.IsTrue(typeof (IBar).IsAssignableFrom(foo.Bar)); - } - - [Test] - public void ResolveTypeWithNullAliasArg() - { - Assert.Throws(() => TypeRegistry.ResolveType(null)); - } - - [Test] - public void ResolveTypeWithEmptyAliasArg() - { - Assert.Throws(() => TypeRegistry.ResolveType(string.Empty)); - } - - [Test] - public void ResolveTypeWithWhitespacedAliasArg() - { - Assert.Throws(() => TypeRegistry.ResolveType(" ")); - } - - [Test] - public void RegisterTypeWithNullAliasArg() - { - Assert.Throws(() => TypeRegistry.RegisterType(null, typeof (TestObject))); - } - - [Test] - public void RegisterTypeWithEmptyAliasArg() - { - Assert.Throws(() => TypeRegistry.RegisterType(string.Empty, typeof (TestObject))); - } - - [Test] - public void RegisterTypeWithWhitespacedAliasArg() - { - Assert.Throws(() => TypeRegistry.RegisterType(" ", typeof (TestObject))); - } - - [Test] - public void RegisterTypeWithNullTypeArg() - { - Assert.Throws(() => TypeRegistry.RegisterType("foo", (Type) null)); - } - - [Test] - public void RegisterTypeWithNullTypeStringArg() - { - Assert.Throws(() => TypeRegistry.RegisterType("foo", (string) null)); - } - - [Test] - public void RegisterTypeWithEmptyTypeStringArg() - { - Assert.Throws(() => TypeRegistry.RegisterType("foo", string.Empty)); - } - - [Test] - public void RegisterTypeWithWhitespacedTypeStringArg() - { - Assert.Throws(() => TypeRegistry.RegisterType("foo", " ")); - } - - [Test] - public void ReturnsNullIfNoTypeAliasRegistered() - { - Type type = TypeRegistry.ResolveType("panko"); - Assert.IsNull(type, "Must return null if no Type is registered under the supplied alias."); - } - - [Test] - public void RegisteringAnAliasTwiceDoesNotThrowException() - { - const string Alias = "foo"; - - TypeRegistry.RegisterType(Alias, typeof (TestObject)); - TypeRegistry.RegisterType(Alias, GetType()); - - Type type = TypeRegistry.ResolveType(Alias); - Assert.AreEqual(GetType(), type, "Overriding Type was not registered."); - } - - [Test] - public void ResolveIntegerByName() - { - Assert.AreEqual(typeof (int), - TypeRegistry.ResolveType("int")); - } - - [Test] - public void ResolveChar() - { - Assert.AreEqual(typeof (char), - TypeRegistry.ResolveType(TypeRegistry.CharAlias)); - } - - [Test] - public void ResolveInteger() - { - Assert.AreEqual(typeof (int), - TypeRegistry.ResolveType(TypeRegistry.Int32Alias)); - } - - [Test] - public void ResolveDecimal() - { - Assert.AreEqual(typeof (decimal), - TypeRegistry.ResolveType(TypeRegistry.DecimalAlias)); - } - - [Test] - public void ResolveUnsignedIntegerByName() - { - Assert.AreEqual(typeof (uint), - TypeRegistry.ResolveType("uint")); - } - - [Test] - public void ResolveUnsignedInteger() - { - Assert.AreEqual(typeof (uint), - TypeRegistry.ResolveType(TypeRegistry.UInt32Alias)); - } - - [Test] - public void ResolveFloatByName() - { - Assert.AreEqual(typeof (float), - TypeRegistry.ResolveType("float")); - } - - [Test] - public void ResolveFloat() - { - Assert.AreEqual(typeof (float), - TypeRegistry.ResolveType(TypeRegistry.FloatAlias)); - } - - [Test] - public void ResolveDoubleByName() - { - Assert.AreEqual(typeof (double), - TypeRegistry.ResolveType("double")); - } - - [Test] - public void ResolveDouble() - { - Assert.AreEqual(typeof (double), - TypeRegistry.ResolveType(TypeRegistry.DoubleAlias)); - } - - [Test] - public void ResolveLongByName() - { - Assert.AreEqual(typeof (long), - TypeRegistry.ResolveType("long")); - } - - [Test] - public void ResolveLong() - { - Assert.AreEqual(typeof (long), - TypeRegistry.ResolveType(TypeRegistry.Int64Alias)); - } - - [Test] - public void ResolveUnsignedLongByName() - { - Assert.AreEqual(typeof (ulong), - TypeRegistry.ResolveType("ulong")); - } - - [Test] - public void ResolveUnsignedLong() - { - Assert.AreEqual(typeof (ulong), - TypeRegistry.ResolveType(TypeRegistry.UInt64Alias)); - } - - [Test] - public void ResolveShortByName() - { - Assert.AreEqual(typeof (short), - TypeRegistry.ResolveType("short")); - } - - [Test] - public void ResolveShort() - { - Assert.AreEqual(typeof (short), - TypeRegistry.ResolveType(TypeRegistry.Int16Alias)); - } - - [Test] - public void ResolveUnsignedShortByName() - { - Assert.AreEqual(typeof (ushort), - TypeRegistry.ResolveType("ushort")); - } - - [Test] - public void ResolveUnsignedShort() - { - Assert.AreEqual(typeof (ushort), - TypeRegistry.ResolveType(TypeRegistry.UInt16Alias)); - } - - [Test] - public void ResolveDate() - { - Assert.AreEqual(typeof (DateTime), - TypeRegistry.ResolveType(TypeRegistry.DateAlias)); - } - - [Test] - public void ResolveBool() - { - Assert.AreEqual(typeof (bool), - TypeRegistry.ResolveType(TypeRegistry.BoolAlias)); - } - - [Test] - public void ResolveIntegerByVBName() - { - Assert.AreEqual(typeof (int), - TypeRegistry.ResolveType("Integer")); - } - - [Test] - public void ResolveVBInteger() - { - Assert.AreEqual(typeof (int), - TypeRegistry.ResolveType(TypeRegistry.Int32AliasVB)); - } - - [Test] - public void ResolveVBDecimal() - { - Assert.AreEqual(typeof (decimal), - TypeRegistry.ResolveType(TypeRegistry.DecimalAliasVB)); - } - - [Test] - public void ResolveSingleByName() - { - Assert.AreEqual(typeof (float), - TypeRegistry.ResolveType("Single")); - } - - [Test] - public void ResolveSingle() - { - Assert.AreEqual(typeof (float), - TypeRegistry.ResolveType(TypeRegistry.SingleAlias)); - } - - [Test] - public void ResolveVBDouble() - { - Assert.AreEqual(typeof (double), - TypeRegistry.ResolveType(TypeRegistry.DoubleAliasVB)); - } - - [Test] - public void ResolveVBLong() - { - Assert.AreEqual(typeof (long), - TypeRegistry.ResolveType(TypeRegistry.Int64AliasVB)); - } - - [Test] - public void ResolveVBShort() - { - Assert.AreEqual(typeof (short), - TypeRegistry.ResolveType(TypeRegistry.Int16AliasVB)); - } - - [Test] - public void ResolveVBDate() - { - Assert.AreEqual(typeof (DateTime), - TypeRegistry.ResolveType(TypeRegistry.DateAliasVB)); - } - - [Test] - public void ResolveVBBool() - { - Assert.AreEqual(typeof (bool), - TypeRegistry.ResolveType(TypeRegistry.BoolAliasVB)); - } - - [Test] - public void ResolveString() - { - Assert.AreEqual(typeof(string), - TypeRegistry.ResolveType(TypeRegistry.StringAlias)); - } - - [Test] - public void ResolveVBString() - { - Assert.AreEqual(typeof(string), - TypeRegistry.ResolveType(TypeRegistry.StringAliasVB)); - } - - [Test] - public void ResolveStringArray() - { - Assert.AreEqual(typeof (string[]), - TypeRegistry.ResolveType(TypeRegistry.StringArrayAlias)); - } - - [Test] - public void ResolveVBStringArray() - { - Assert.AreEqual(typeof (string[]), - TypeRegistry.ResolveType(TypeRegistry.StringArrayAliasVB)); - } - - [Test] - public void ResolveObject() - { - Assert.AreEqual(typeof(object), - TypeRegistry.ResolveType(TypeRegistry.ObjectAlias)); - } - - [Test] - public void ResolveVBObject() - { - Assert.AreEqual(typeof(object), - TypeRegistry.ResolveType(TypeRegistry.ObjectAliasVB)); - } - - [Test] - public void ResolveObjectArray() - { - Assert.AreEqual(typeof(object[]), - TypeRegistry.ResolveType(TypeRegistry.ObjectArrayAlias)); - } - - [Test] - public void ResolveVBObjectArray() - { - Assert.AreEqual(typeof(object[]), - TypeRegistry.ResolveType(TypeRegistry.ObjectArrayAliasVB)); - } - - [Test] - public void ResolveCharArray() - { - Assert.AreEqual(typeof (char[]), - TypeRegistry.ResolveType(TypeRegistry.CharArrayAlias)); - } - - [Test] - public void ResolveVBCharArray() - { - Assert.AreEqual(typeof (char[]), - TypeRegistry.ResolveType(TypeRegistry.CharArrayAliasVB)); - } - - [Test] - public void ResolveInt32Array() - { - Assert.AreEqual(typeof (int[]), - TypeRegistry.ResolveType(TypeRegistry.Int32ArrayAlias)); - } - - [Test] - public void ResolveVBInt32Array() - { - Assert.AreEqual(typeof (int[]), - TypeRegistry.ResolveType(TypeRegistry.Int32ArrayAliasVB)); - } - - [Test] - public void ResolveInt16Array() - { - Assert.AreEqual(typeof (short[]), - TypeRegistry.ResolveType(TypeRegistry.Int16ArrayAlias)); - } - - [Test] - public void ResolveVBInt16Array() - { - Assert.AreEqual(typeof (short[]), - TypeRegistry.ResolveType(TypeRegistry.Int16ArrayAliasVB)); - } - - [Test] - public void ResolveInt64Array() - { - Assert.AreEqual(typeof (long[]), - TypeRegistry.ResolveType(TypeRegistry.Int64ArrayAlias)); - } - - [Test] - public void ResolveVBInt64Array() - { - Assert.AreEqual(typeof (long[]), - TypeRegistry.ResolveType(TypeRegistry.Int64ArrayAliasVB)); - } - - [Test] - public void ResolveUInt16Array() - { - Assert.AreEqual(typeof (ushort[]), - TypeRegistry.ResolveType(TypeRegistry.UInt16ArrayAlias)); - } - - [Test] - public void ResolveUInt32Array() - { - Assert.AreEqual(typeof (uint[]), - TypeRegistry.ResolveType(TypeRegistry.UInt32ArrayAlias)); - } - - [Test] - public void ResolveUInt64Array() - { - Assert.AreEqual(typeof (ulong[]), - TypeRegistry.ResolveType(TypeRegistry.UInt64ArrayAlias)); - } - - [Test] - public void ResolveBoolArray() - { - Assert.AreEqual(typeof (bool[]), - TypeRegistry.ResolveType(TypeRegistry.BoolArrayAlias)); - } - - [Test] - public void ResolveVBBoolArray() - { - Assert.AreEqual(typeof (bool[]), - TypeRegistry.ResolveType(TypeRegistry.BoolArrayAliasVB)); - } - - [Test] - public void ResolveDateArray() - { - Assert.AreEqual(typeof (DateTime[]), - TypeRegistry.ResolveType(TypeRegistry.DateTimeArrayAlias)); - } - - [Test] - public void ResolveVBDateArray() - { - Assert.AreEqual(typeof (DateTime[]), - TypeRegistry.ResolveType(TypeRegistry.DateTimeArrayAliasVB)); - } - - [Test] - public void ResolveFloatArray() - { - Assert.AreEqual(typeof (float[]), - TypeRegistry.ResolveType(TypeRegistry.FloatArrayAlias)); - } - - [Test] - public void ResolveVBSingleArray() - { - Assert.AreEqual(typeof (float[]), - TypeRegistry.ResolveType(TypeRegistry.SingleArrayAliasVB)); - } - - [Test] - public void ResolveDoubleArray() - { - Assert.AreEqual(typeof (double[]), - TypeRegistry.ResolveType(TypeRegistry.DoubleArrayAlias)); - } - - [Test] - public void ResolveVBDoubleArray() - { - Assert.AreEqual(typeof (double[]), - TypeRegistry.ResolveType(TypeRegistry.DoubleArrayAliasVB)); - } - - [Test] - public void ResolveNullableChar() - { - Assert.AreEqual(typeof(char?), - TypeRegistry.ResolveType(TypeRegistry.NullableCharAlias)); - Assert.AreEqual(typeof(Nullable), - TypeRegistry.ResolveType(TypeRegistry.NullableCharAlias)); - } - - [Test] - public void ResolveNullableInteger() - { - Assert.AreEqual(typeof(int?), - TypeRegistry.ResolveType(TypeRegistry.NullableInt32Alias)); - Assert.AreEqual(typeof(Nullable), - TypeRegistry.ResolveType(TypeRegistry.NullableInt32Alias)); - } - - [Test] - public void ResolveNullableDecimal() - { - Assert.AreEqual(typeof(decimal?), - TypeRegistry.ResolveType(TypeRegistry.NullableDecimalAlias)); - Assert.AreEqual(typeof(Nullable), - TypeRegistry.ResolveType(TypeRegistry.NullableDecimalAlias)); - } - - [Test] - public void ResolveNullableUnsignedInteger() - { - Assert.AreEqual(typeof(uint?), - TypeRegistry.ResolveType(TypeRegistry.NullableUInt32Alias)); - Assert.AreEqual(typeof(Nullable), - TypeRegistry.ResolveType(TypeRegistry.NullableUInt32Alias)); - } - - [Test] - public void ResolveNullableFloat() - { - Assert.AreEqual(typeof(float?), - TypeRegistry.ResolveType(TypeRegistry.NullableFloatAlias)); - Assert.AreEqual(typeof(Nullable), - TypeRegistry.ResolveType(TypeRegistry.NullableFloatAlias)); - } - - [Test] - public void ResolveNullableDouble() - { - Assert.AreEqual(typeof(double?), - TypeRegistry.ResolveType(TypeRegistry.NullableDoubleAlias)); - Assert.AreEqual(typeof(Nullable), - TypeRegistry.ResolveType(TypeRegistry.NullableDoubleAlias)); - } - - [Test] - public void ResolveNullableLong() - { - Assert.AreEqual(typeof(long?), - TypeRegistry.ResolveType(TypeRegistry.NullableInt64Alias)); - Assert.AreEqual(typeof(Nullable), - TypeRegistry.ResolveType(TypeRegistry.NullableInt64Alias)); - } - - [Test] - public void ResolveNullableUnsignedLong() - { - Assert.AreEqual(typeof(ulong?), - TypeRegistry.ResolveType(TypeRegistry.NullableUInt64Alias)); - Assert.AreEqual(typeof(Nullable), - TypeRegistry.ResolveType(TypeRegistry.NullableUInt64Alias)); - } - - [Test] - public void ResolveNullableShort() - { - Assert.AreEqual(typeof(short?), - TypeRegistry.ResolveType(TypeRegistry.NullableInt16Alias)); - Assert.AreEqual(typeof(Nullable), - TypeRegistry.ResolveType(TypeRegistry.NullableInt16Alias)); - } - - [Test] - public void ResolveNullableUnsignedShort() - { - Assert.AreEqual(typeof(ushort?), - TypeRegistry.ResolveType(TypeRegistry.NullableUInt16Alias)); - Assert.AreEqual(typeof(Nullable), - TypeRegistry.ResolveType(TypeRegistry.NullableUInt16Alias)); - } - - [Test] - public void ResolveNullableBool() - { - Assert.AreEqual(typeof(bool?), - TypeRegistry.ResolveType(TypeRegistry.NullableBoolAlias)); - Assert.AreEqual(typeof(Nullable), - TypeRegistry.ResolveType(TypeRegistry.NullableBoolAlias)); - } - - [Test] - public void ResolveNullableCharArray() - { - Assert.AreEqual(typeof(char?[]), - TypeRegistry.ResolveType(TypeRegistry.NullableCharArrayAlias)); - } - - [Test] - public void ResolveNullableInt32Array() - { - Assert.AreEqual(typeof(int?[]), - TypeRegistry.ResolveType(TypeRegistry.NullableInt32ArrayAlias)); - } - - [Test] - public void ResolveNullableDecimalArray() - { - Assert.AreEqual(typeof(decimal?[]), - TypeRegistry.ResolveType(TypeRegistry.NullableDecimalArrayAlias)); - } - - [Test] - public void ResolveNullableInt16Array() - { - Assert.AreEqual(typeof(short?[]), - TypeRegistry.ResolveType(TypeRegistry.NullableInt16ArrayAlias)); - } - - [Test] - public void ResolveNullableInt64Array() - { - Assert.AreEqual(typeof(long?[]), - TypeRegistry.ResolveType(TypeRegistry.NullableInt64ArrayAlias)); - } - - [Test] - public void ResolveNullableUInt16Array() - { - Assert.AreEqual(typeof(ushort?[]), - TypeRegistry.ResolveType(TypeRegistry.NullableUInt16ArrayAlias)); - } - - [Test] - public void ResolveNullableUInt32Array() - { - Assert.AreEqual(typeof(uint?[]), - TypeRegistry.ResolveType(TypeRegistry.NullableUInt32ArrayAlias)); - } - - [Test] - public void ResolveNullableUInt64Array() - { - Assert.AreEqual(typeof(ulong?[]), - TypeRegistry.ResolveType(TypeRegistry.NullableUInt64ArrayAlias)); - } - - [Test] - public void ResolveNullableBoolArray() - { - Assert.AreEqual(typeof(bool?[]), - TypeRegistry.ResolveType(TypeRegistry.NullableBoolArrayAlias)); - } - - [Test] - public void ResolveNullableFloatArray() - { - Assert.AreEqual(typeof(float?[]), - TypeRegistry.ResolveType(TypeRegistry.NullableFloatArrayAlias)); - } - - [Test] - public void ResolveNullableDoubleArray() - { - Assert.AreEqual(typeof(double?[]), - TypeRegistry.ResolveType(TypeRegistry.NullableDoubleArrayAlias)); - } - } - - internal class Foo - { - private Type bar; - - public Type Bar - { - get { return bar; } - set { bar = value; } - } - } + [Test] + public void TestAliasResolution() + { + TypeRegistry.RegisterType("Foo", typeof(Foo)); + TypeRegistry.RegisterType("Bar", "Spring.Objects.Factory.Bar, Spring.Core.Tests"); + + Assert.AreEqual(TypeRegistry.ResolveType("Foo"), typeof(Foo)); + Assert.AreEqual(TypeRegistry.ResolveType("Bar"), typeof(Bar)); + + IApplicationContext ctx = + new XmlApplicationContext("assembly://Spring.Core.Tests/Spring.Core.TypeResolution/aliasedObjects.xml"); + + Foo foo = ctx.GetObject("aliasedType") as Foo; + Assert.IsNotNull(foo); + Assert.IsNotNull(foo.Bar); + Assert.AreEqual(foo.Bar, typeof(Bar)); + Assert.IsTrue(typeof(IBar).IsAssignableFrom(foo.Bar)); + } + + [Test] + public void ResolveTypeWithNullAliasArg() + { + Assert.Throws(() => TypeRegistry.ResolveType(null)); + } + + [Test] + public void ResolveTypeWithEmptyAliasArg() + { + Assert.Throws(() => TypeRegistry.ResolveType(string.Empty)); + } + + [Test] + public void ResolveTypeWithWhitespacedAliasArg() + { + Assert.Throws(() => TypeRegistry.ResolveType(" ")); + } + + [Test] + public void RegisterTypeWithNullAliasArg() + { + Assert.Throws(() => TypeRegistry.RegisterType(null, typeof(TestObject))); + } + + [Test] + public void RegisterTypeWithEmptyAliasArg() + { + Assert.Throws(() => TypeRegistry.RegisterType(string.Empty, typeof(TestObject))); + } + + [Test] + public void RegisterTypeWithWhitespacedAliasArg() + { + Assert.Throws(() => TypeRegistry.RegisterType(" ", typeof(TestObject))); + } + + [Test] + public void RegisterTypeWithNullTypeArg() + { + Assert.Throws(() => TypeRegistry.RegisterType("foo", (Type) null)); + } + + [Test] + public void RegisterTypeWithNullTypeStringArg() + { + Assert.Throws(() => TypeRegistry.RegisterType("foo", (string) null)); + } + + [Test] + public void RegisterTypeWithEmptyTypeStringArg() + { + Assert.Throws(() => TypeRegistry.RegisterType("foo", string.Empty)); + } + + [Test] + public void RegisterTypeWithWhitespacedTypeStringArg() + { + Assert.Throws(() => TypeRegistry.RegisterType("foo", " ")); + } + + [Test] + public void ReturnsNullIfNoTypeAliasRegistered() + { + Type type = TypeRegistry.ResolveType("panko"); + Assert.IsNull(type, "Must return null if no Type is registered under the supplied alias."); + } + + [Test] + public void RegisteringAnAliasTwiceDoesNotThrowException() + { + const string Alias = "foo"; + + TypeRegistry.RegisterType(Alias, typeof(TestObject)); + TypeRegistry.RegisterType(Alias, GetType()); + + Type type = TypeRegistry.ResolveType(Alias); + Assert.AreEqual(GetType(), type, "Overriding Type was not registered."); + } + + [Test] + public void ResolveIntegerByName() + { + Assert.AreEqual(typeof(int), + TypeRegistry.ResolveType("int")); + } + + [Test] + public void ResolveChar() + { + Assert.AreEqual(typeof(char), + TypeRegistry.ResolveType(TypeRegistry.CharAlias)); + } + + [Test] + public void ResolveInteger() + { + Assert.AreEqual(typeof(int), + TypeRegistry.ResolveType(TypeRegistry.Int32Alias)); + } + + [Test] + public void ResolveDecimal() + { + Assert.AreEqual(typeof(decimal), + TypeRegistry.ResolveType(TypeRegistry.DecimalAlias)); + } + + [Test] + public void ResolveUnsignedIntegerByName() + { + Assert.AreEqual(typeof(uint), + TypeRegistry.ResolveType("uint")); + } + + [Test] + public void ResolveUnsignedInteger() + { + Assert.AreEqual(typeof(uint), + TypeRegistry.ResolveType(TypeRegistry.UInt32Alias)); + } + + [Test] + public void ResolveFloatByName() + { + Assert.AreEqual(typeof(float), + TypeRegistry.ResolveType("float")); + } + + [Test] + public void ResolveFloat() + { + Assert.AreEqual(typeof(float), + TypeRegistry.ResolveType(TypeRegistry.FloatAlias)); + } + + [Test] + public void ResolveDoubleByName() + { + Assert.AreEqual(typeof(double), + TypeRegistry.ResolveType("double")); + } + + [Test] + public void ResolveDouble() + { + Assert.AreEqual(typeof(double), + TypeRegistry.ResolveType(TypeRegistry.DoubleAlias)); + } + + [Test] + public void ResolveLongByName() + { + Assert.AreEqual(typeof(long), + TypeRegistry.ResolveType("long")); + } + + [Test] + public void ResolveLong() + { + Assert.AreEqual(typeof(long), + TypeRegistry.ResolveType(TypeRegistry.Int64Alias)); + } + + [Test] + public void ResolveUnsignedLongByName() + { + Assert.AreEqual(typeof(ulong), + TypeRegistry.ResolveType("ulong")); + } + + [Test] + public void ResolveUnsignedLong() + { + Assert.AreEqual(typeof(ulong), + TypeRegistry.ResolveType(TypeRegistry.UInt64Alias)); + } + + [Test] + public void ResolveShortByName() + { + Assert.AreEqual(typeof(short), + TypeRegistry.ResolveType("short")); + } + + [Test] + public void ResolveShort() + { + Assert.AreEqual(typeof(short), + TypeRegistry.ResolveType(TypeRegistry.Int16Alias)); + } + + [Test] + public void ResolveUnsignedShortByName() + { + Assert.AreEqual(typeof(ushort), + TypeRegistry.ResolveType("ushort")); + } + + [Test] + public void ResolveUnsignedShort() + { + Assert.AreEqual(typeof(ushort), + TypeRegistry.ResolveType(TypeRegistry.UInt16Alias)); + } + + [Test] + public void ResolveDate() + { + Assert.AreEqual(typeof(DateTime), + TypeRegistry.ResolveType(TypeRegistry.DateAlias)); + } + + [Test] + public void ResolveBool() + { + Assert.AreEqual(typeof(bool), + TypeRegistry.ResolveType(TypeRegistry.BoolAlias)); + } + + [Test] + public void ResolveIntegerByVBName() + { + Assert.AreEqual(typeof(int), + TypeRegistry.ResolveType("Integer")); + } + + [Test] + public void ResolveVBInteger() + { + Assert.AreEqual(typeof(int), + TypeRegistry.ResolveType(TypeRegistry.Int32AliasVB)); + } + + [Test] + public void ResolveVBDecimal() + { + Assert.AreEqual(typeof(decimal), + TypeRegistry.ResolveType(TypeRegistry.DecimalAliasVB)); + } + + [Test] + public void ResolveSingleByName() + { + Assert.AreEqual(typeof(float), + TypeRegistry.ResolveType("Single")); + } + + [Test] + public void ResolveSingle() + { + Assert.AreEqual(typeof(float), + TypeRegistry.ResolveType(TypeRegistry.SingleAlias)); + } + + [Test] + public void ResolveVBDouble() + { + Assert.AreEqual(typeof(double), + TypeRegistry.ResolveType(TypeRegistry.DoubleAliasVB)); + } + + [Test] + public void ResolveVBLong() + { + Assert.AreEqual(typeof(long), + TypeRegistry.ResolveType(TypeRegistry.Int64AliasVB)); + } + + [Test] + public void ResolveVBShort() + { + Assert.AreEqual(typeof(short), + TypeRegistry.ResolveType(TypeRegistry.Int16AliasVB)); + } + + [Test] + public void ResolveVBDate() + { + Assert.AreEqual(typeof(DateTime), + TypeRegistry.ResolveType(TypeRegistry.DateAliasVB)); + } + + [Test] + public void ResolveVBBool() + { + Assert.AreEqual(typeof(bool), + TypeRegistry.ResolveType(TypeRegistry.BoolAliasVB)); + } + + [Test] + public void ResolveString() + { + Assert.AreEqual(typeof(string), + TypeRegistry.ResolveType(TypeRegistry.StringAlias)); + } + + [Test] + public void ResolveVBString() + { + Assert.AreEqual(typeof(string), + TypeRegistry.ResolveType(TypeRegistry.StringAliasVB)); + } + + [Test] + public void ResolveStringArray() + { + Assert.AreEqual(typeof(string[]), + TypeRegistry.ResolveType(TypeRegistry.StringArrayAlias)); + } + + [Test] + public void ResolveVBStringArray() + { + Assert.AreEqual(typeof(string[]), + TypeRegistry.ResolveType(TypeRegistry.StringArrayAliasVB)); + } + + [Test] + public void ResolveObject() + { + Assert.AreEqual(typeof(object), + TypeRegistry.ResolveType(TypeRegistry.ObjectAlias)); + } + + [Test] + public void ResolveVBObject() + { + Assert.AreEqual(typeof(object), + TypeRegistry.ResolveType(TypeRegistry.ObjectAliasVB)); + } + + [Test] + public void ResolveObjectArray() + { + Assert.AreEqual(typeof(object[]), + TypeRegistry.ResolveType(TypeRegistry.ObjectArrayAlias)); + } + + [Test] + public void ResolveVBObjectArray() + { + Assert.AreEqual(typeof(object[]), + TypeRegistry.ResolveType(TypeRegistry.ObjectArrayAliasVB)); + } + + [Test] + public void ResolveCharArray() + { + Assert.AreEqual(typeof(char[]), + TypeRegistry.ResolveType(TypeRegistry.CharArrayAlias)); + } + + [Test] + public void ResolveVBCharArray() + { + Assert.AreEqual(typeof(char[]), + TypeRegistry.ResolveType(TypeRegistry.CharArrayAliasVB)); + } + + [Test] + public void ResolveInt32Array() + { + Assert.AreEqual(typeof(int[]), + TypeRegistry.ResolveType(TypeRegistry.Int32ArrayAlias)); + } + + [Test] + public void ResolveVBInt32Array() + { + Assert.AreEqual(typeof(int[]), + TypeRegistry.ResolveType(TypeRegistry.Int32ArrayAliasVB)); + } + + [Test] + public void ResolveInt16Array() + { + Assert.AreEqual(typeof(short[]), + TypeRegistry.ResolveType(TypeRegistry.Int16ArrayAlias)); + } + + [Test] + public void ResolveVBInt16Array() + { + Assert.AreEqual(typeof(short[]), + TypeRegistry.ResolveType(TypeRegistry.Int16ArrayAliasVB)); + } + + [Test] + public void ResolveInt64Array() + { + Assert.AreEqual(typeof(long[]), + TypeRegistry.ResolveType(TypeRegistry.Int64ArrayAlias)); + } + + [Test] + public void ResolveVBInt64Array() + { + Assert.AreEqual(typeof(long[]), + TypeRegistry.ResolveType(TypeRegistry.Int64ArrayAliasVB)); + } + + [Test] + public void ResolveUInt16Array() + { + Assert.AreEqual(typeof(ushort[]), + TypeRegistry.ResolveType(TypeRegistry.UInt16ArrayAlias)); + } + + [Test] + public void ResolveUInt32Array() + { + Assert.AreEqual(typeof(uint[]), + TypeRegistry.ResolveType(TypeRegistry.UInt32ArrayAlias)); + } + + [Test] + public void ResolveUInt64Array() + { + Assert.AreEqual(typeof(ulong[]), + TypeRegistry.ResolveType(TypeRegistry.UInt64ArrayAlias)); + } + + [Test] + public void ResolveBoolArray() + { + Assert.AreEqual(typeof(bool[]), + TypeRegistry.ResolveType(TypeRegistry.BoolArrayAlias)); + } + + [Test] + public void ResolveVBBoolArray() + { + Assert.AreEqual(typeof(bool[]), + TypeRegistry.ResolveType(TypeRegistry.BoolArrayAliasVB)); + } + + [Test] + public void ResolveDateArray() + { + Assert.AreEqual(typeof(DateTime[]), + TypeRegistry.ResolveType(TypeRegistry.DateTimeArrayAlias)); + } + + [Test] + public void ResolveVBDateArray() + { + Assert.AreEqual(typeof(DateTime[]), + TypeRegistry.ResolveType(TypeRegistry.DateTimeArrayAliasVB)); + } + + [Test] + public void ResolveFloatArray() + { + Assert.AreEqual(typeof(float[]), + TypeRegistry.ResolveType(TypeRegistry.FloatArrayAlias)); + } + + [Test] + public void ResolveVBSingleArray() + { + Assert.AreEqual(typeof(float[]), + TypeRegistry.ResolveType(TypeRegistry.SingleArrayAliasVB)); + } + + [Test] + public void ResolveDoubleArray() + { + Assert.AreEqual(typeof(double[]), + TypeRegistry.ResolveType(TypeRegistry.DoubleArrayAlias)); + } + + [Test] + public void ResolveVBDoubleArray() + { + Assert.AreEqual(typeof(double[]), + TypeRegistry.ResolveType(TypeRegistry.DoubleArrayAliasVB)); + } + + [Test] + public void ResolveNullableChar() + { + Assert.AreEqual(typeof(char?), + TypeRegistry.ResolveType(TypeRegistry.NullableCharAlias)); + Assert.AreEqual(typeof(Nullable), + TypeRegistry.ResolveType(TypeRegistry.NullableCharAlias)); + } + + [Test] + public void ResolveNullableInteger() + { + Assert.AreEqual(typeof(int?), + TypeRegistry.ResolveType(TypeRegistry.NullableInt32Alias)); + Assert.AreEqual(typeof(Nullable), + TypeRegistry.ResolveType(TypeRegistry.NullableInt32Alias)); + } + + [Test] + public void ResolveNullableDecimal() + { + Assert.AreEqual(typeof(decimal?), + TypeRegistry.ResolveType(TypeRegistry.NullableDecimalAlias)); + Assert.AreEqual(typeof(Nullable), + TypeRegistry.ResolveType(TypeRegistry.NullableDecimalAlias)); + } + + [Test] + public void ResolveNullableUnsignedInteger() + { + Assert.AreEqual(typeof(uint?), + TypeRegistry.ResolveType(TypeRegistry.NullableUInt32Alias)); + Assert.AreEqual(typeof(Nullable), + TypeRegistry.ResolveType(TypeRegistry.NullableUInt32Alias)); + } + + [Test] + public void ResolveNullableFloat() + { + Assert.AreEqual(typeof(float?), + TypeRegistry.ResolveType(TypeRegistry.NullableFloatAlias)); + Assert.AreEqual(typeof(Nullable), + TypeRegistry.ResolveType(TypeRegistry.NullableFloatAlias)); + } + + [Test] + public void ResolveNullableDouble() + { + Assert.AreEqual(typeof(double?), + TypeRegistry.ResolveType(TypeRegistry.NullableDoubleAlias)); + Assert.AreEqual(typeof(Nullable), + TypeRegistry.ResolveType(TypeRegistry.NullableDoubleAlias)); + } + + [Test] + public void ResolveNullableLong() + { + Assert.AreEqual(typeof(long?), + TypeRegistry.ResolveType(TypeRegistry.NullableInt64Alias)); + Assert.AreEqual(typeof(Nullable), + TypeRegistry.ResolveType(TypeRegistry.NullableInt64Alias)); + } + + [Test] + public void ResolveNullableUnsignedLong() + { + Assert.AreEqual(typeof(ulong?), + TypeRegistry.ResolveType(TypeRegistry.NullableUInt64Alias)); + Assert.AreEqual(typeof(Nullable), + TypeRegistry.ResolveType(TypeRegistry.NullableUInt64Alias)); + } + + [Test] + public void ResolveNullableShort() + { + Assert.AreEqual(typeof(short?), + TypeRegistry.ResolveType(TypeRegistry.NullableInt16Alias)); + Assert.AreEqual(typeof(Nullable), + TypeRegistry.ResolveType(TypeRegistry.NullableInt16Alias)); + } + + [Test] + public void ResolveNullableUnsignedShort() + { + Assert.AreEqual(typeof(ushort?), + TypeRegistry.ResolveType(TypeRegistry.NullableUInt16Alias)); + Assert.AreEqual(typeof(Nullable), + TypeRegistry.ResolveType(TypeRegistry.NullableUInt16Alias)); + } + + [Test] + public void ResolveNullableBool() + { + Assert.AreEqual(typeof(bool?), + TypeRegistry.ResolveType(TypeRegistry.NullableBoolAlias)); + Assert.AreEqual(typeof(Nullable), + TypeRegistry.ResolveType(TypeRegistry.NullableBoolAlias)); + } + + [Test] + public void ResolveNullableCharArray() + { + Assert.AreEqual(typeof(char?[]), + TypeRegistry.ResolveType(TypeRegistry.NullableCharArrayAlias)); + } + + [Test] + public void ResolveNullableInt32Array() + { + Assert.AreEqual(typeof(int?[]), + TypeRegistry.ResolveType(TypeRegistry.NullableInt32ArrayAlias)); + } + + [Test] + public void ResolveNullableDecimalArray() + { + Assert.AreEqual(typeof(decimal?[]), + TypeRegistry.ResolveType(TypeRegistry.NullableDecimalArrayAlias)); + } + + [Test] + public void ResolveNullableInt16Array() + { + Assert.AreEqual(typeof(short?[]), + TypeRegistry.ResolveType(TypeRegistry.NullableInt16ArrayAlias)); + } + + [Test] + public void ResolveNullableInt64Array() + { + Assert.AreEqual(typeof(long?[]), + TypeRegistry.ResolveType(TypeRegistry.NullableInt64ArrayAlias)); + } + + [Test] + public void ResolveNullableUInt16Array() + { + Assert.AreEqual(typeof(ushort?[]), + TypeRegistry.ResolveType(TypeRegistry.NullableUInt16ArrayAlias)); + } + + [Test] + public void ResolveNullableUInt32Array() + { + Assert.AreEqual(typeof(uint?[]), + TypeRegistry.ResolveType(TypeRegistry.NullableUInt32ArrayAlias)); + } + + [Test] + public void ResolveNullableUInt64Array() + { + Assert.AreEqual(typeof(ulong?[]), + TypeRegistry.ResolveType(TypeRegistry.NullableUInt64ArrayAlias)); + } + + [Test] + public void ResolveNullableBoolArray() + { + Assert.AreEqual(typeof(bool?[]), + TypeRegistry.ResolveType(TypeRegistry.NullableBoolArrayAlias)); + } + + [Test] + public void ResolveNullableFloatArray() + { + Assert.AreEqual(typeof(float?[]), + TypeRegistry.ResolveType(TypeRegistry.NullableFloatArrayAlias)); + } + + [Test] + public void ResolveNullableDoubleArray() + { + Assert.AreEqual(typeof(double?[]), + TypeRegistry.ResolveType(TypeRegistry.NullableDoubleArrayAlias)); + } +} + +internal class Foo +{ + private Type bar; + + public Type Bar + { + get { return bar; } + set { bar = value; } + } } \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/Core/TypeResolution/TypeResolutionUtilsTests.cs b/test/Spring/Spring.Core.Tests/Core/TypeResolution/TypeResolutionUtilsTests.cs index 3d51c347..f0feadaa 100644 --- a/test/Spring/Spring.Core.Tests/Core/TypeResolution/TypeResolutionUtilsTests.cs +++ b/test/Spring/Spring.Core.Tests/Core/TypeResolution/TypeResolutionUtilsTests.cs @@ -21,94 +21,91 @@ #region Imports using System.Reflection; - using NUnit.Framework; - using Spring.Objects; #endregion -namespace Spring.Core.TypeResolution +namespace Spring.Core.TypeResolution; + +/// +/// Unit tests for the TypeResolutionUtils class. +/// +[TestFixture] +public sealed class TypeResolutionUtilsTests { - /// - /// Unit tests for the TypeResolutionUtils class. - /// - [TestFixture] - public sealed class TypeResolutionUtilsTests + [Test] + public void ResolveFromAssemblyQualifiedName() { - [Test] - public void ResolveFromAssemblyQualifiedName() - { - Type testObjectType = TypeResolutionUtils.ResolveType("Spring.Objects.TestObject, Spring.Core.Tests"); - Assert.IsNotNull(testObjectType); - Assert.IsTrue(testObjectType.Equals(typeof (TestObject))); - } - - [Test] - public void ResolveFromBadAssemblyQualifiedName() - { - Assert.Throws(() => TypeResolutionUtils.ResolveType("Spring.Objects.TestObject, Spring.Core.FooTests")); - } - - [Test] - public void ResolveFromShortName() - { - Type testObjectType = TypeResolutionUtils.ResolveType("Spring.Objects.TestObject"); - Assert.IsNotNull(testObjectType); - Assert.IsTrue(testObjectType.Equals(typeof (TestObject))); - } - - [Test] - public void ResolveFromBadShortName() - { - Assert.Throws(() => TypeResolutionUtils.ResolveType("Spring.Objects.FooBarTestObject")); - } - - [Test] - public void ResolveInterfaceArrayFromStringArray() - { - Type[] expected = new Type[] { typeof(IFoo) }; - string[] input = new string[] { typeof(IFoo).AssemblyQualifiedName }; - IList actual = TypeResolutionUtils.ResolveInterfaceArray(input); - Assert.IsNotNull(actual); - Assert.AreEqual(expected.Length, actual.Count); - Assert.AreEqual(expected[0], actual[0]); - } - - [Test] - public void ResolveInterfaceArrayFromStringArrayWithNonInterfaceTypes() - { - string[] input = new string[] { GetType().AssemblyQualifiedName }; - Assert.Throws(() => TypeResolutionUtils.ResolveInterfaceArray(input)); - } - - [Test] - public void MethodMatch() - { - MethodInfo absquatulateMethod = typeof(TestObject).GetMethod("Absquatulate"); - Assert.IsTrue(TypeResolutionUtils.MethodMatch("*", absquatulateMethod), "Should match '*'"); - Assert.IsTrue(TypeResolutionUtils.MethodMatch("*tulate", absquatulateMethod), "Should match '*tulate'"); - Assert.IsTrue(TypeResolutionUtils.MethodMatch("Absqua*", absquatulateMethod), "Should match 'Absqua*'"); - Assert.IsTrue(TypeResolutionUtils.MethodMatch("*quatul*", absquatulateMethod), "Should match '*quatul*'"); - Assert.IsTrue(TypeResolutionUtils.MethodMatch("Absquatulate", absquatulateMethod), "Should match 'Absquatulate'"); - Assert.IsTrue(TypeResolutionUtils.MethodMatch("Absquatulate()", absquatulateMethod), "Should match 'Absquatulate()'"); - Assert.IsTrue(TypeResolutionUtils.MethodMatch("Absquatulate()", absquatulateMethod), "Should match 'Absquatulate()'"); - Assert.IsFalse(TypeResolutionUtils.MethodMatch("Absquatulate(string)", absquatulateMethod), "Should not match 'Absquatulate(string)'"); - - MethodInfo addPeriodicElementMethod = typeof(TestObject).GetMethod("AddPeriodicElement"); - Assert.IsTrue(TypeResolutionUtils.MethodMatch("AddPeriodicElement", addPeriodicElementMethod), "Should match 'AddPeriodicElement'"); - Assert.IsFalse(TypeResolutionUtils.MethodMatch("AddPeriodicElement()", addPeriodicElementMethod), "Should not match 'AddPeriodicElement()'"); - Assert.IsFalse(TypeResolutionUtils.MethodMatch("AddPeriodicElement(string)", addPeriodicElementMethod), "Should not match 'AddPeriodicElement(string)'"); - Assert.IsTrue(TypeResolutionUtils.MethodMatch("AddPeriodicElement(string, string)", addPeriodicElementMethod), "Should match 'AddPeriodicElement(string, string)'"); - } - - #region Helper classes - - internal interface IFoo - { - bool Spanglish(string foo, object[] args); - } - - #endregion + Type testObjectType = TypeResolutionUtils.ResolveType("Spring.Objects.TestObject, Spring.Core.Tests"); + Assert.IsNotNull(testObjectType); + Assert.IsTrue(testObjectType.Equals(typeof(TestObject))); } -} \ No newline at end of file + + [Test] + public void ResolveFromBadAssemblyQualifiedName() + { + Assert.Throws(() => TypeResolutionUtils.ResolveType("Spring.Objects.TestObject, Spring.Core.FooTests")); + } + + [Test] + public void ResolveFromShortName() + { + Type testObjectType = TypeResolutionUtils.ResolveType("Spring.Objects.TestObject"); + Assert.IsNotNull(testObjectType); + Assert.IsTrue(testObjectType.Equals(typeof(TestObject))); + } + + [Test] + public void ResolveFromBadShortName() + { + Assert.Throws(() => TypeResolutionUtils.ResolveType("Spring.Objects.FooBarTestObject")); + } + + [Test] + public void ResolveInterfaceArrayFromStringArray() + { + Type[] expected = new Type[] { typeof(IFoo) }; + string[] input = new string[] { typeof(IFoo).AssemblyQualifiedName }; + IList actual = TypeResolutionUtils.ResolveInterfaceArray(input); + Assert.IsNotNull(actual); + Assert.AreEqual(expected.Length, actual.Count); + Assert.AreEqual(expected[0], actual[0]); + } + + [Test] + public void ResolveInterfaceArrayFromStringArrayWithNonInterfaceTypes() + { + string[] input = new string[] { GetType().AssemblyQualifiedName }; + Assert.Throws(() => TypeResolutionUtils.ResolveInterfaceArray(input)); + } + + [Test] + public void MethodMatch() + { + MethodInfo absquatulateMethod = typeof(TestObject).GetMethod("Absquatulate"); + Assert.IsTrue(TypeResolutionUtils.MethodMatch("*", absquatulateMethod), "Should match '*'"); + Assert.IsTrue(TypeResolutionUtils.MethodMatch("*tulate", absquatulateMethod), "Should match '*tulate'"); + Assert.IsTrue(TypeResolutionUtils.MethodMatch("Absqua*", absquatulateMethod), "Should match 'Absqua*'"); + Assert.IsTrue(TypeResolutionUtils.MethodMatch("*quatul*", absquatulateMethod), "Should match '*quatul*'"); + Assert.IsTrue(TypeResolutionUtils.MethodMatch("Absquatulate", absquatulateMethod), "Should match 'Absquatulate'"); + Assert.IsTrue(TypeResolutionUtils.MethodMatch("Absquatulate()", absquatulateMethod), "Should match 'Absquatulate()'"); + Assert.IsTrue(TypeResolutionUtils.MethodMatch("Absquatulate()", absquatulateMethod), "Should match 'Absquatulate()'"); + Assert.IsFalse(TypeResolutionUtils.MethodMatch("Absquatulate(string)", absquatulateMethod), "Should not match 'Absquatulate(string)'"); + + MethodInfo addPeriodicElementMethod = typeof(TestObject).GetMethod("AddPeriodicElement"); + Assert.IsTrue(TypeResolutionUtils.MethodMatch("AddPeriodicElement", addPeriodicElementMethod), "Should match 'AddPeriodicElement'"); + Assert.IsFalse(TypeResolutionUtils.MethodMatch("AddPeriodicElement()", addPeriodicElementMethod), "Should not match 'AddPeriodicElement()'"); + Assert.IsFalse(TypeResolutionUtils.MethodMatch("AddPeriodicElement(string)", addPeriodicElementMethod), "Should not match 'AddPeriodicElement(string)'"); + Assert.IsTrue(TypeResolutionUtils.MethodMatch("AddPeriodicElement(string, string)", addPeriodicElementMethod), "Should match 'AddPeriodicElement(string, string)'"); + } + + #region Helper classes + + internal interface IFoo + { + bool Spanglish(string foo, object[] args); + } + + #endregion +} diff --git a/test/Spring/Spring.Core.Tests/Core/TypeResolution/TypeResolverTests.cs b/test/Spring/Spring.Core.Tests/Core/TypeResolution/TypeResolverTests.cs index 5b945573..d066dc22 100644 --- a/test/Spring/Spring.Core.Tests/Core/TypeResolution/TypeResolverTests.cs +++ b/test/Spring/Spring.Core.Tests/Core/TypeResolution/TypeResolverTests.cs @@ -26,71 +26,70 @@ using Spring.Objects; #endregion -namespace Spring.Core.TypeResolution +namespace Spring.Core.TypeResolution; + +/// +/// Unit tests for the TypeResolver class. +/// +/// Rick Evans +/// Bruno Baia +[TestFixture] +public class TypeResolverTests { - /// - /// Unit tests for the TypeResolver class. - /// - /// Rick Evans - /// Bruno Baia - [TestFixture] - public class TypeResolverTests + protected virtual ITypeResolver GetTypeResolver() { - protected virtual ITypeResolver GetTypeResolver() - { - return new TypeResolver(); - } + return new TypeResolver(); + } - [Test] - public void ResolveLocalAssemblyType() - { - Type t = GetTypeResolver().Resolve("Spring.Objects.TestObject"); - Assert.AreEqual(typeof (TestObject), t); - } + [Test] + public void ResolveLocalAssemblyType() + { + Type t = GetTypeResolver().Resolve("Spring.Objects.TestObject"); + Assert.AreEqual(typeof(TestObject), t); + } - [Test] - public void ResolveWithPartialAssemblyName() - { - Type t = GetTypeResolver().Resolve("System.Data.IDbConnection, System.Data"); - Assert.AreEqual(typeof (IDbConnection), t); - } + [Test] + public void ResolveWithPartialAssemblyName() + { + Type t = GetTypeResolver().Resolve("System.Data.IDbConnection, System.Data"); + Assert.AreEqual(typeof(IDbConnection), t); + } - /// - /// Tests that the resolve method throws the correct exception - /// when supplied a load of old rubbish as a type name. - /// - [Test] - public void ResolveWithNonExistentTypeName() - { - Assert.Throws(() => GetTypeResolver().Resolve("RaskolnikovsDilemma, System.StPetersburg")); - } + /// + /// Tests that the resolve method throws the correct exception + /// when supplied a load of old rubbish as a type name. + /// + [Test] + public void ResolveWithNonExistentTypeName() + { + Assert.Throws(() => GetTypeResolver().Resolve("RaskolnikovsDilemma, System.StPetersburg")); + } - [Test] - public void ResolveBadArgs() - { - Assert.Throws(() => GetTypeResolver().Resolve(null)); - } + [Test] + public void ResolveBadArgs() + { + Assert.Throws(() => GetTypeResolver().Resolve(null)); + } - [Test] - public void ResolveLocalAssemblyTypeWithFullAssemblyQualifiedName() - { - Type t = GetTypeResolver().Resolve(typeof(TestObject).AssemblyQualifiedName); - Assert.AreEqual(typeof (TestObject), t); - } + [Test] + public void ResolveLocalAssemblyTypeWithFullAssemblyQualifiedName() + { + Type t = GetTypeResolver().Resolve(typeof(TestObject).AssemblyQualifiedName); + Assert.AreEqual(typeof(TestObject), t); + } - [Test] - public void LoadTypeFromSystemAssemblySpecifyingOnlyTheAssemblyDisplayName() - { - string stringType = typeof(string).FullName + ", System"; - Assert.Throws(() => GetTypeResolver().Resolve(stringType)); - } + [Test] + public void LoadTypeFromSystemAssemblySpecifyingOnlyTheAssemblyDisplayName() + { + string stringType = typeof(string).FullName + ", System"; + Assert.Throws(() => GetTypeResolver().Resolve(stringType)); + } - [Test] - public void LoadTypeFromSystemAssemblySpecifyingTheFullAssemblyName() - { - string stringType = typeof(string).AssemblyQualifiedName; - Type t = GetTypeResolver().Resolve(stringType); - Assert.AreEqual(typeof(string), t); - } + [Test] + public void LoadTypeFromSystemAssemblySpecifyingTheFullAssemblyName() + { + string stringType = typeof(string).AssemblyQualifiedName; + Type t = GetTypeResolver().Resolve(stringType); + Assert.AreEqual(typeof(string), t); } } diff --git a/test/Spring/Spring.Core.Tests/Core/TypeResolution/aliasedObjects.xml b/test/Spring/Spring.Core.Tests/Core/TypeResolution/aliasedObjects.xml index 7c826c49..fdc98992 100644 --- a/test/Spring/Spring.Core.Tests/Core/TypeResolution/aliasedObjects.xml +++ b/test/Spring/Spring.Core.Tests/Core/TypeResolution/aliasedObjects.xml @@ -1,9 +1,9 @@ - + - - - - - + + + + + diff --git a/test/Spring/Spring.Core.Tests/CoreCompilerOptionsTests.cs b/test/Spring/Spring.Core.Tests/CoreCompilerOptionsTests.cs index 0ee9e334..aa7e7726 100644 --- a/test/Spring/Spring.Core.Tests/CoreCompilerOptionsTests.cs +++ b/test/Spring/Spring.Core.Tests/CoreCompilerOptionsTests.cs @@ -26,18 +26,17 @@ using Spring.Objects; #endregion -namespace Spring +namespace Spring; + +/// Test that the AOP assembly is built with the correct DebugAttributes in release and debug builds. +/// +/// Mark Pollack +[TestFixture] +public sealed class CoreCompilerOptionsTests : CompilerOptionsTests { - /// Test that the AOP assembly is built with the correct DebugAttributes in release and debug builds. - /// - /// Mark Pollack - [TestFixture] - public sealed class CoreCompilerOptionsTests : CompilerOptionsTests + [OneTimeSetUp] + public void FixtureSetUp() { - [OneTimeSetUp] - public void FixtureSetUp() - { - AssemblyToCheck = Assembly.GetAssembly(typeof (ObjectsException)); - } + AssemblyToCheck = Assembly.GetAssembly(typeof(ObjectsException)); } } \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/CoreExceptionTests.cs b/test/Spring/Spring.Core.Tests/CoreExceptionTests.cs index 3db7727a..db8989b8 100644 --- a/test/Spring/Spring.Core.Tests/CoreExceptionTests.cs +++ b/test/Spring/Spring.Core.Tests/CoreExceptionTests.cs @@ -26,19 +26,18 @@ using Spring.Objects; #endregion -namespace Spring +namespace Spring; + +/// +/// Unit tests for all of the exception classes in the Spring.Core library... +/// +/// Rick Evans +[TestFixture] +public sealed class CoreExceptionTests : ExceptionsTest { - /// - /// Unit tests for all of the exception classes in the Spring.Core library... - /// - /// Rick Evans - [TestFixture] - public sealed class CoreExceptionTests : ExceptionsTest + [OneTimeSetUp] + public void FixtureSetUp() { - [OneTimeSetUp] - public void FixtureSetUp() - { - AssemblyToCheck = Assembly.GetAssembly(typeof (ObjectsException)); - } + AssemblyToCheck = Assembly.GetAssembly(typeof(ObjectsException)); } -} \ No newline at end of file +} diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Context/Support/SPRNET-192.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Context/Support/SPRNET-192.xml index 035714e7..7b4c8a81 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Context/Support/SPRNET-192.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Context/Support/SPRNET-192.xml @@ -1,17 +1,18 @@  - - - ${log} - - - - - - - - - - + xsi:schemaLocation="http://www.springframework.net http://www.springframework.net/xsd/spring-objects.xsd"> + + + ${log} + + + + + + + + + + \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Config/AnotherDaoConfig.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Config/AnotherDaoConfig.xml index ad89d3d6..de3042a1 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Config/AnotherDaoConfig.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Config/AnotherDaoConfig.xml @@ -1,11 +1,12 @@ - -
- - - - - - + +
+ + + + + + diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Config/DaoConfig.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Config/DaoConfig.xml index 2d9a1861..f8bea3be 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Config/DaoConfig.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Config/DaoConfig.xml @@ -1,11 +1,12 @@ - -
- - - - - - + +
+ + + + + + diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Config/DatabaseConfig.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Config/DatabaseConfig.xml index e519cf1e..f5a0eff7 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Config/DatabaseConfig.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Config/DatabaseConfig.xml @@ -1,9 +1,10 @@ - - + + - + + + + - - - diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Config/FirstPropertyPlaceholderConfigurer.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Config/FirstPropertyPlaceholderConfigurer.xml index a486550e..54a84045 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Config/FirstPropertyPlaceholderConfigurer.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Config/FirstPropertyPlaceholderConfigurer.xml @@ -16,19 +16,19 @@ limitations under the License. --> - - - + + + - - - - - - - - - - + + + + + + + + + + \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Config/PPC-SPRNET-55.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Config/PPC-SPRNET-55.xml index b394efba..426a3088 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Config/PPC-SPRNET-55.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Config/PPC-SPRNET-55.xml @@ -15,43 +15,43 @@ See the License for the specific language governing permissions and limitations under the License. --> - - - ${connection.string} - - - - - - - - - - - - - config:// - file://Spring/Objects/Factory/Config/DaoConfig.xml - file://Spring/Objects/Factory/Config/AnotherDaoConfig.xml - - - - - - - - - - - - - config:// - file://Spring/Objects/Factory/Config/DaoConfig.xml - file://Spring/Objects/Factory/Config/AnotherDaoConfig.xml - - - - - + xsi:schemaLocation="http://www.springframework.net http://www.springframework.net/xsd/spring-objects.xsd"> + + + ${connection.string} + + + + + + + + + + + + + config:// + file://Spring/Objects/Factory/Config/DaoConfig.xml + file://Spring/Objects/Factory/Config/AnotherDaoConfig.xml + + + + + + + + + + + + + config:// + file://Spring/Objects/Factory/Config/DaoConfig.xml + file://Spring/Objects/Factory/Config/AnotherDaoConfig.xml + + + + + \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Config/PPCTwoLocationsOneSectionTests.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Config/PPCTwoLocationsOneSectionTests.xml index 56c7a129..1778d270 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Config/PPCTwoLocationsOneSectionTests.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Config/PPCTwoLocationsOneSectionTests.xml @@ -14,33 +14,37 @@ 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. --> - - + - - ${maxResults} - - - - - - ${connection.string} - - - - - + + + + ${maxResults} + + + + + + + + + ${connection.string} + + + + + - config:// - file://Spring/Objects/Factory/Config/DaoConfig.xml + config:// + file://Spring/Objects/Factory/Config/DaoConfig.xml - - - DaoConfiguration - - + + + DaoConfiguration + + \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Config/PPCTwoLocationsTwoSectionsTests.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Config/PPCTwoLocationsTwoSectionsTests.xml index b107cca2..b629f473 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Config/PPCTwoLocationsTwoSectionsTests.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Config/PPCTwoLocationsTwoSectionsTests.xml @@ -14,32 +14,36 @@ 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. --> - - + - - ${maxResults} - - - - - - ${connection.string} - - - - - + + + + ${maxResults} + + + + + + + + + ${connection.string} + + + + + - config:// - file://Spring/Objects/Factory/Config/DatabaseConfig.xml + config:// + file://Spring/Objects/Factory/Config/DatabaseConfig.xml - - - DaoConfiguration,DatabaseConfiguration - - + + + DaoConfiguration,DatabaseConfiguration + + \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Config/PPCWithTypesTests.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Config/PPCWithTypesTests.xml index 942f9783..589ddb04 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Config/PPCWithTypesTests.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Config/PPCWithTypesTests.xml @@ -16,38 +16,38 @@ limitations under the License. --> - - - - Gribouille - Blutch - - - - - - - - - - - mine - your - - - + + + + Gribouille + Blutch + + + + + + + + + + + mine + your + + + + + + + + + + + + + + + + - - - - - - - - - - - - - \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Config/PropertyPlaceholderConfigurerTests.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Config/PropertyPlaceholderConfigurerTests.xml index ffbe0665..aca6bace 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Config/PropertyPlaceholderConfigurerTests.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Config/PropertyPlaceholderConfigurerTests.xml @@ -14,26 +14,30 @@ 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. --> - - + - - ${maxResults} - - - - - - ${connection.string} - - - - - - DaoConfiguration,DatabaseConfiguration - - + + + + ${maxResults} + + + + + + + + + ${connection.string} + + + + + + DaoConfiguration,DatabaseConfiguration + + \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Config/PropertyResourceConfigurerTests.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Config/PropertyResourceConfigurerTests.xml index 802374d7..8139a451 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Config/PropertyResourceConfigurerTests.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Config/PropertyResourceConfigurerTests.xml @@ -1,6 +1,6 @@ + xsi:schemaLocation="http://www.springframework.net http://www.springframework.net/xsd/spring-objects.xsd"> @@ -17,7 +17,8 @@ - + @@ -29,13 +30,13 @@ Start Name - - - - %{test.name.1} - + + + + %{test.name.1} + - + %{test.name.2} diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Config/SecondPropertyPlaceholderConfigurer.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Config/SecondPropertyPlaceholderConfigurer.xml index 0d5c4ed1..937e5cf9 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Config/SecondPropertyPlaceholderConfigurer.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Config/SecondPropertyPlaceholderConfigurer.xml @@ -15,15 +15,15 @@ See the License for the specific language governing permissions and limitations under the License. --> - - - - - - - - - - + + + + + + + + + + \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Config/TypeAliases.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Config/TypeAliases.xml index 90bdb50c..8c0dec71 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Config/TypeAliases.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Config/TypeAliases.xml @@ -1,59 +1,60 @@ - - - - - - - - - + + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + - + + + + - - + - - - - + + + + + + + - - - - + + + + - - - - - + + + + - - - - - 30 - - + + + + + + 30 + + \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/Resources/resource-imports.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/Resources/resource-imports.xml index a83af33e..408296a3 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/Resources/resource-imports.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/Resources/resource-imports.xml @@ -1,8 +1,8 @@ - + Rick diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/abstract.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/abstract.xml index 815d854b..93f7d09a 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/abstract.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/abstract.xml @@ -1,6 +1,6 @@ - - - + + + diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/array-autowire.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/array-autowire.xml index 3e79e8e1..3707696e 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/array-autowire.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/array-autowire.xml @@ -1,18 +1,15 @@ - - + - - - - - - + + + + diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/autowire.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/autowire.xml index 85d3eb2e..ad16b1a2 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/autowire.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/autowire.xml @@ -1,68 +1,68 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/bad-external-resources.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/bad-external-resources.xml index a2aa53b4..d9343c8b 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/bad-external-resources.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/bad-external-resources.xml @@ -1,8 +1,8 @@ - + diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/bad-named-constructor-arg.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/bad-named-constructor-arg.xml index 2e03c6aa..2212c5eb 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/bad-named-constructor-arg.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/bad-named-constructor-arg.xml @@ -1,15 +1,15 @@ - - - - - Isaac Newton - - - 87 - - + + + + + Isaac Newton + + + 87 + + diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/child.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/child.xml index 647fc9b8..38f3c774 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/child.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/child.xml @@ -1,58 +1,58 @@ - - - - - override - - - - - - - - - - - prototypeOverridesInheritedSingleton - - - - - - - prototype-override - - - - - - - prototype-override - - - - - - - overrideParentObject - - - - - + + + + + override + + + + + + + + + + + prototypeOverridesInheritedSingleton + + + + + + + prototype-override + + + + + + + prototype-override + + + + + + + overrideParentObject + + + + + diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/classnotfound.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/classnotfound.xml index 4b43cd02..3b7eb718 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/classnotfound.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/classnotfound.xml @@ -1,10 +1,10 @@ - - - + + + diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/collectionConversionGeneric.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/collectionConversionGeneric.xml index 02fd9c04..3ad986d6 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/collectionConversionGeneric.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/collectionConversionGeneric.xml @@ -2,32 +2,32 @@ - - - - 123 - 234 - 345 - - - + + + + 123 + 234 + 345 + + + - - - - - - - - - + + + + + + + + + - - - - 123 - - - + + + + 123 + + + diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/collectionMerging.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/collectionMerging.xml index 0334ac8e..864cc27f 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/collectionMerging.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/collectionMerging.xml @@ -3,210 +3,209 @@ - - - - Rob Harrop - Rod Johnson - - - + + + + Rob Harrop + Rod Johnson + + + - - - - Juergen Hoeller - - - + + + + Juergen Hoeller + + + - - - - - - - - + + + + + + + - - - - Rob Harrop - - - + + + + Rob Harrop + + + - - - - Sally Greenwood - - - + + + + Sally Greenwood + + + - - - - - - - - - - + + + + + + + + - - - - - - - - + + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - + + + + + + + + - - - - Rob Harrop - Rod Johnson - - - + + + + Rob Harrop + Rod Johnson + + + - - - - Juergen Hoeller - - - - - - - - - - - + + + + Juergen Hoeller + + + - - - - Rob Harrop - - - + + + + + + + - - - - Sally Greenwood - - - - - - - - - - - - - + + + + Rob Harrop + + + - - - - - - - - + + + + Sally Greenwood + + + - - - - - - - - + + + + + + + + + - - - - - - - - - - - + + + + + + + + - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/collectionMergingGeneric.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/collectionMergingGeneric.xml index 852018dc..982b8a6a 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/collectionMergingGeneric.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/collectionMergingGeneric.xml @@ -3,23 +3,22 @@ + + + + Rob Harrop + Rod Johnson + + + - - - - Rob Harrop - Rod Johnson - - - + + + + Juergen Hoeller + + + - - - - Juergen Hoeller - - - - diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/collections.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/collections.xml index 3707a775..6f600b63 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/collections.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/collections.xml @@ -1,559 +1,570 @@ - - Tests for list and map handling in an XML object definition file. - - - - - - - rick - - Rick Evans - - - - uncleelvis - - Elvis Orten - - - - - - - - - Rick Evans - - - Elvis Orten - - - - - - - - - - - - Rick Evans - - - - - - Elvis Orten - - - - - - - I have no properties and I'm happy without them. - - - - - - - 1 - - - 12 - - - - - - - Mark - - - 35 - - - - Dell - IBM T41 - - - - - - Aleks - - - 30 - - - - Nadja - - - - - - Jenny - - - 30 - - - - - - - - Simple object, without any collections. - - - The name of the user - David - - - 27 - - - - - Rod - - - 32 - - - List of Rod's friends - - - - - - - - - Jenny - - - 30 - - - - - - - - David - - - 27 - - - - - Rod - - - 32 - - - - - - - - - - - loner - - - 26 - - - - - - - - - - - - literal - - - - - - + + Tests for list and map handling in an XML object definition file. + + + + + + + rick + + Rick Evans + + + + uncleelvis + + Elvis Orten + + + + + + + + + Rick Evans + + + Elvis Orten + + + + + + + + + + + + Rick Evans + + + + + + Elvis Orten + + + + + + + I have no properties and I'm happy without them. + + + + + + + 1 + + + 12 + + + + + + + Mark + + + 35 + + + + Dell + IBM T41 + + + + + + Aleks + + + 30 + + + + Nadja + + + + + + Jenny + + + 30 + + + + + + + + Simple object, without any collections. + + + The name of the user + David + + + 27 + + + + + Rod + + + 32 + + + List of Rod's friends + + + + + + + + + Jenny + + + 30 + + + + + + + + David + + + 27 + + + + + Rod + + + 32 + + + + + + + + + + + loner + + + 26 + + + + + + + + + + + + literal + + + + + - - - - - - - - - - - - - - - verbose - - - - - - - - - - - - - - - aliased - - - - - aliased - - - - - aliased - - - - - - - - - - - - - - - - - bar - - - fum - - - - - - - - - - - - bar - - - - - - - - - - - - - - - bar - - - - - - - - - - - - bar - - - - - - - zero - - - bar - - - - - - - - ba - - - - - - - - bar - - - - - - - - - - - - - - - - - - bar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - one - - - - - - - - System.String - System.Exception - - - - - - - bar - jenny - - - - Spring.Collections.LinkedList - - - - - - bar - jenny - - - - Spring.Collections.LinkedList - - - true - - - - - - bar - jenny - - - - Spring.Collections.HybridSet - - - - - - bar - jenny - - - - Spring.Collections.HybridSet - - - true - - - - - - - bar - - - jenny - - - - - System.Collections.Hashtable - - - - - - - bar - - - jenny - - - - - System.Collections.Hashtable - - - true - - - - - - - - - - - - - - - - - - - - Rick Evans - 30 - - - Uncle Elvis - 47 - + + + - - - - - 1 + 1 - date('1974-8-24').Month - 'Aleksandar Seovic'.ToUpper() - DateTime.Today > date('1974-8-24') - - - - - - 1 + 1 - - - date('1974-8-24').Month - - - 'Aleksandar Seovic'.ToUpper() - - - DateTime.Today > date('1974-8-24') - - - - - - - - 1 + 1 - date('1974-8-24').Month - 'Aleksandar Seovic'.ToUpper() - DateTime.Today > date('1974-8-24') - - - - - - 1 + 1 - - - date('1974-8-24').Month - - - 'Aleksandar Seovic'.ToUpper() - - - DateTime.Today > date('1974-8-24') - - - - + + + + + + + + + + + + verbose + + + + + + + + + + + + + + + aliased + + + + + aliased + + + + + aliased + + + + + + + + + + + + + + + + + bar + + + fum + + + + + + + + + + + + bar + + + + + + + + + + + + + + + bar + + + + + + + + + + + + bar + + + + + + + zero + + + bar + + + + + + + + ba + + + + + + + + bar + + + + + + + + + + + + + + + + + + bar + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + one + + + + + + + + System.String + System.Exception + + + + + + + bar + jenny + + + + Spring.Collections.LinkedList + + + + + + bar + jenny + + + + Spring.Collections.LinkedList + + + true + + + + + + bar + jenny + + + + Spring.Collections.HybridSet + + + + + + bar + jenny + + + + Spring.Collections.HybridSet + + + true + + + + + + + bar + + + jenny + + + + + System.Collections.Hashtable + + + + + + + bar + + + jenny + + + + + System.Collections.Hashtable + + + true + + + + + + + + + + + + + + + + + + + + + Rick Evans + + + 30 + + + + + Uncle Elvis + + + 47 + + + + + + + + 1 + 1 + date('1974-8-24').Month + 'Aleksandar Seovic'.ToUpper() + DateTime.Today > date('1974-8-24') + + + + + + 1 + 1 + + + date('1974-8-24').Month + + + 'Aleksandar Seovic'.ToUpper() + + + DateTime.Today > date('1974-8-24') + + + + + + + + 1 + 1 + date('1974-8-24').Month + 'Aleksandar Seovic'.ToUpper() + DateTime.Today > date('1974-8-24') + + + + + + 1 + 1 + + + date('1974-8-24').Month + + + 'Aleksandar Seovic'.ToUpper() + + + DateTime.Today > date('1974-8-24') + + + + diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/constructor-arg.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/constructor-arg.xml index cc909e98..89ed978d 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/constructor-arg.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/constructor-arg.xml @@ -1,149 +1,149 @@ + xsi:schemaLocation="http://www.springframework.net http://www.springframework.net/xsd/spring-objects.xsd"> - - - - - - - - - - - - - - - - - - - - - - - - - - - bird - - - - - - - wife - - - - mmm - 99 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - False - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + bird + + + + + + + wife + + + + mmm + 99 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + False + + + diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/ctor-args.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/ctor-args.xml index f189ebdb..42cb0bf8 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/ctor-args.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/ctor-args.xml @@ -1,16 +1,16 @@ - - Tests for list and map handling in an XML object definition file. - - - - - - - - - - - + + Tests for list and map handling in an XML object definition file. + + + + + + + + + + + diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/default-autowire.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/default-autowire.xml index da455470..04e8a546 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/default-autowire.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/default-autowire.xml @@ -1,21 +1,21 @@ - - - - - - - - - - - - - Kerry - - + + + + + + + + + + + + + Kerry + + diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/default-destroy-methods.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/default-destroy-methods.xml index 39a8407b..99efd79f 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/default-destroy-methods.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/default-destroy-methods.xml @@ -1,17 +1,17 @@ - - - + - + + + diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/default-initializers.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/default-initializers.xml index 69be468c..eed859b6 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/default-initializers.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/default-initializers.xml @@ -1,23 +1,23 @@ - - - - - 7 - - + - - - 7 - - + + + 7 + + + + + + 7 + + diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/default-lazy-init.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/default-lazy-init.xml index ffd66205..614ac2d7 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/default-lazy-init.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/default-lazy-init.xml @@ -1,26 +1,26 @@ - - - + - - - - - + + + + + + + diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/dependenciesmaterializethis.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/dependenciesmaterializethis.xml index b69aba9a..df66c9ff 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/dependenciesmaterializethis.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/dependenciesmaterializethis.xml @@ -4,63 +4,63 @@ the dao. Involves factory objects. --> - + - - + + - - - + + + - - - - - - - - - - - - + + + + + + + + + + + + diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/enums.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/enums.xml index 23fa1a72..e84c6ae8 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/enums.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/enums.xml @@ -1,23 +1,23 @@ - - - - Rod - - - Create - - - + + diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/event-wiring-prototypes.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/event-wiring-prototypes.xml index c70b4b92..ed662638 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/event-wiring-prototypes.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/event-wiring-prototypes.xml @@ -1,21 +1,21 @@ - + - + - - + + - - - - - - + + + + + + diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/event-wiring.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/event-wiring.xml index aa22b70b..b031c372 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/event-wiring.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/event-wiring.xml @@ -1,81 +1,81 @@ - - - - + + - + - - - - - - + - - - - - - + + + + + + + + + + + + + - - - - - - + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/expressions.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/expressions.xml index 55dbe364..e636ae42 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/expressions.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/expressions.xml @@ -1,49 +1,49 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/external-resources.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/external-resources.xml index 8f4db0bf..d641582f 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/external-resources.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/external-resources.xml @@ -1,10 +1,10 @@ + xsi:schemaLocation="http://www.springframework.net http://www.springframework.net/xsd/spring-objects.xsd"> - - - Jenny - - + + + Jenny + + diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/factory-methods.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/factory-methods.xml index 2335252b..763a2f73 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/factory-methods.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/factory-methods.xml @@ -1,67 +1,66 @@ - + + factory-method="DefaultInstance"> - + - + factory-method="NewInstance"> + - - - + factory-method="newInsTance"> + + + + singleton="false" factory-method="defaultInstance"> - + - - + factory-method="newInstance" singleton="false"> + + - - - + factory-method="newInstance" singleton="false"> + + + - - - - + factory-method="newInstance" singleton="false"> + + + + - + + factory-method="createTestObject"> - - + factory-method="creATETestoBject"> + + - + - + - - diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/factorycircle.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/factorycircle.xml index 1cb38d5b..08002e7d 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/factorycircle.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/factorycircle.xml @@ -1,13 +1,13 @@ - - - - - - - + + + + + + + diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/field-props-factory.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/field-props-factory.xml index 519bbfd5..3e1180a3 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/field-props-factory.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/field-props-factory.xml @@ -1,8 +1,8 @@ - + @@ -13,22 +13,24 @@ System.Globalization.CultureInfo.CurrentUICulture, Mscorlib - - + + - + DefauLT - - + + @@ -42,42 +44,48 @@ EmPTytypeS - - + + - + - + MyDefaultCulture - - - + + + - + System.Globalization.CultureInfo.LittleBobbyBoJangles, Mscorlib - + - + System.Type.Foo, Mscorlib - + diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/initializers.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/initializers.xml index b3e4ba81..ef808e1c 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/initializers.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/initializers.xml @@ -1,41 +1,41 @@ - - - - - 7 - - - - - - - - - - - - - - + + + + + 7 + + + + + + + + + + + + + + diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/invalid-factory.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/invalid-factory.xml index 0562f3e8..83e5631b 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/invalid-factory.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/invalid-factory.xml @@ -1,13 +1,13 @@ - - - - - false - - + + + + + false + + \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/invalid.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/invalid.xml index 69245f80..2fdf2fb6 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/invalid.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/invalid.xml @@ -1,24 +1,24 @@ - - - - - - Jenny - - - 30 - - - - - - - - + + + + + + Jenny + + + 30 + + + + + + + + diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/invoke-factory.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/invoke-factory.xml index 4110be9c..0cd2a938 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/invoke-factory.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/invoke-factory.xml @@ -1,8 +1,8 @@ - + System.Globalization.CultureInfo, Mscorlib diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/lazy-init-multithreaded.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/lazy-init-multithreaded.xml index cb51e834..885dfaea 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/lazy-init-multithreaded.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/lazy-init-multithreaded.xml @@ -1,13 +1,13 @@  - - - - + + + + diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/locale.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/locale.xml index 0942242f..ab69eed8 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/locale.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/locale.xml @@ -1,11 +1,11 @@  + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.springframework.net http://www.springframework.net/xsd/spring-objects.xsd"> - - - - + + + + diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/no-objects.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/no-objects.xml index 68baf049..09fb74da 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/no-objects.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/no-objects.xml @@ -1,12 +1,12 @@  - - - + + + diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/notfullyspecified.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/notfullyspecified.xml index 96307ff9..bfc30e2d 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/notfullyspecified.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/notfullyspecified.xml @@ -1,13 +1,13 @@ - - - - - - Provider=SQLOLEDB - - + + + + + + Provider=SQLOLEDB + + \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/objectNameGeneration.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/objectNameGeneration.xml index 75850119..dad4a0ac 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/objectNameGeneration.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/objectNameGeneration.xml @@ -1,26 +1,26 @@ - + - - - - - + + + + + - - - - - + + + + + + + + + + + - - - - - - diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/parent.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/parent.xml index 2b6ada8a..0cbc6f2c 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/parent.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/parent.xml @@ -1,33 +1,45 @@ - + - - - - - - - parent - 1 - - + + + + + + + + parent + + + 1 + + + - parent - 1 - - - - parent - 2 - - - + + parent + + + 1 + + + + + + parent + + + 2 + + + + diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/reftypes.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/reftypes.xml index 9ff6ae24..e4a35aa7 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/reftypes.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/reftypes.xml @@ -1,205 +1,205 @@ - - - - - Jenny - - - 30 - - - - - - - - - - - - 27 - - - - - - - - - Andrew - - - 36 - - - - - - - - - Emma - - - 31 - - - - - - - - - Georgia - - - 33 - - - - - - - - - ego - - - 1 - - - - - + - - - - outer - - - 0 - - + + + Jenny + + + 30 + + + + + - - - - hasInner - - - 5 - - - + - inner1 + - 6 + 27 - - - - - - - inner2 - - - 7 - - - - - - - - - - - inner3 - - - 8 - - - - - - - inner4 - - - 9 - - - - - - + + + + - - - hasInner - - - 5 - - - + - inner1 + Andrew - 6 + 36 - - - - - - - inner2 - - - 7 - - - - - - innerFriendOfAFriend - - - 7 - - - - - - - - - - - - - - inner3 - - - 8 - - - - - - + + + + + + + + Emma + + + 31 + + + + + + + + + Georgia + + + 33 + + + + + + + + + ego + + + 1 + + + + + + + + + + outer + + + 0 + + + + + + + hasInner + + + 5 + + + + + inner1 + + + 6 + + + + + + + + inner2 + + + 7 + + + + + + + + + + + inner3 + + + 8 + + + + + + + inner4 + + + 9 + + + + + + + + + + hasInner + + + 5 + + + + + inner1 + + + 6 + + + + + + + + inner2 + + + 7 + + + + + + innerFriendOfAFriend + + + 7 + + + + + + + + + + + + + + inner3 + + + 8 + + + + + + diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/satisfiedalldependencycheck.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/satisfiedalldependencycheck.xml index 5fcd9bba..78967f4f 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/satisfiedalldependencycheck.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/satisfiedalldependencycheck.xml @@ -1,23 +1,23 @@ - - - - - - - - 33 - - - Rod - - - - + + + + + + + + 33 + + + Rod + + + + diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/satisfiedobjectdependencycheck.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/satisfiedobjectdependencycheck.xml index 78b77126..eb726099 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/satisfiedobjectdependencycheck.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/satisfiedobjectdependencycheck.xml @@ -1,18 +1,18 @@ - - - - - - - - - - + + + + + + + + + + diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/satisfiedsimpledependencycheck.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/satisfiedsimpledependencycheck.xml index 57c7b142..242e6796 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/satisfiedsimpledependencycheck.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/satisfiedsimpledependencycheck.xml @@ -1,18 +1,18 @@ - - - - - 33 - - - Rod - - + + + + + 33 + + + Rod + + diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/schema-validation.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/schema-validation.xml index 1abbfb88..aca2ab3e 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/schema-validation.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/schema-validation.xml @@ -1,8 +1,9 @@ - + - + \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/simple-constructor-arg.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/simple-constructor-arg.xml index 310a1021..4f1908f5 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/simple-constructor-arg.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/simple-constructor-arg.xml @@ -1,21 +1,21 @@ + xsi:schemaLocation="http://www.springframework.net http://www.springframework.net/xsd/spring-objects.xsd"> - - - bird - - - - + + + bird + + + + + + + + + + - - - - - - diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/test.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/test.xml index 5f2abfcf..849f3454 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/test.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/test.xml @@ -1,116 +1,120 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.springframework.net http://www.springframework.net/xsd/spring-objects.xsd"> - - - Rod - - - 31 - - - - - + + + Rod + + + 31 + + + + + - - - Roderick - - - + + + Roderick + + + - - - Kerry - - - 34 - - - - - + + + Kerry + + + 34 + + + + + - - - Kathy - - - 28 - - - - - + + + Kathy + + + 28 + + + + + - - - typeMismatch - - - 34x - - - - - + + + typeMismatch + + + 34x + + + + + - - + + - + - - + + - - - false - - + + + false + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - listenerVeto - - - 66 - - + + + listenerVeto + + + 66 + + - + - - - + + + diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/unsatisfiedAllDependencyCheckMissingSimple.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/unsatisfiedAllDependencyCheckMissingSimple.xml index 0845836c..967ae2e0 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/unsatisfiedAllDependencyCheckMissingSimple.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/unsatisfiedAllDependencyCheckMissingSimple.xml @@ -1,19 +1,21 @@ - - - - - tony - - - --> - - - + - + + + tony + + + + + --> + + + + + diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/unsatisfiedalldependencycheckmissingobjects.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/unsatisfiedalldependencycheckmissingobjects.xml index fa622191..5dd04d86 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/unsatisfiedalldependencycheckmissingobjects.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/unsatisfiedalldependencycheckmissingobjects.xml @@ -1,19 +1,18 @@ - - - - - 33 - - - Rod - - + + + + 33 + + + Rod + + diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/unsatisfiedobjectdependencycheck.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/unsatisfiedobjectdependencycheck.xml index 8c076799..75132b09 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/unsatisfiedobjectdependencycheck.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/unsatisfiedobjectdependencycheck.xml @@ -1,11 +1,11 @@ - - - - + + + + diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/unsatisfiedsimpledependencycheck.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/unsatisfiedsimpledependencycheck.xml index aa9b87b7..cd5cc275 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/unsatisfiedsimpledependencycheck.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/unsatisfiedsimpledependencycheck.xml @@ -1,11 +1,11 @@ - - - - + + + + diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/wellformed-but-bad.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/wellformed-but-bad.xml index 1b469413..4058571e 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/wellformed-but-bad.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/wellformed-but-bad.xml @@ -1,7 +1,9 @@  - - - + xsi:schemaLocation="http://www.springframework.net http://www.springframework.net/xsd/spring-objects.xsd"> + + + + + diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/concurrent.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/concurrent.xml index 9462abc8..d08b520f 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/concurrent.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/concurrent.xml @@ -1,21 +1,21 @@ - + - - - 2004/08/08 - - - - - 2000/02/02 - - + + + 2004/08/08 + + + + + 2000/02/02 + + diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/leaf.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/leaf.xml index 2c48f507..2eae1c17 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/leaf.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/leaf.xml @@ -1,17 +1,17 @@ - + - - - custom - - - 25 - - + + + custom + + + 25 + + diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/middle.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/middle.xml index c817458c..a552d858 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/middle.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/middle.xml @@ -1,21 +1,21 @@ - + - - - - custom - - - 666 - - - - + + + + custom + + + 666 + + + + diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/root.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/root.xml index 8cdb7ee8..d39d6505 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/root.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/root.xml @@ -1,22 +1,22 @@ - - - - - - - custom - - - 25 - - - - - - false - - + + + + + + + custom + + + 25 + + + + + + false + + diff --git a/test/Spring/Spring.Core.Tests/DataBinding/BaseBindingManagerTests.cs b/test/Spring/Spring.Core.Tests/DataBinding/BaseBindingManagerTests.cs index 7efec8e3..f8a7c90a 100644 --- a/test/Spring/Spring.Core.Tests/DataBinding/BaseBindingManagerTests.cs +++ b/test/Spring/Spring.Core.Tests/DataBinding/BaseBindingManagerTests.cs @@ -19,304 +19,304 @@ #endregion using System.Collections; - using NUnit.Framework; using Spring.Core; using Spring.Globalization.Formatters; using Spring.Validation; -namespace Spring.DataBinding +namespace Spring.DataBinding; + +/// +/// Test cases for the BaseBindingManager. +/// +/// Aleksandar Seovic +[TestFixture] +public class BaseBindingManagerTests { - /// - /// Test cases for the BaseBindingManager. - /// - /// Aleksandar Seovic - [TestFixture] - public class BaseBindingManagerTests + private BaseBindingManager mgr; + + [OneTimeSetUp] + public void SetUp() { - private BaseBindingManager mgr; + mgr = new BaseBindingManager(); + mgr.AddBinding("['name']", "Name"); + mgr.AddBinding("['dob']", "DOB"); + mgr.AddBinding("['dateofgraduation']", "DateOfGraduation"); + mgr.AddBinding("['inventions']", "Inventions"); + mgr.AddBinding("['cityOfBirth']", "PlaceOfBirth.City"); + mgr.AddBinding("['countryOfBirth']", "PlaceOfBirth.Country"); + } - [OneTimeSetUp] - public void SetUp() + [Test] + public void WithoutTypeConversion() + { + Hashtable source = new Hashtable(); + Inventor target = new Inventor(); + + source["name"] = "Nikola Tesla"; + source["dob"] = new DateTime(1856, 7, 9); + + // I know this is pupin's graduation year but I need a date here + source["dateofgraduation"] = new DateTime(1883, 1, 1); + source["inventions"] = new string[] { "One", "Two" }; + + mgr.BindSourceToTarget(source, target, null); + + Assert.IsTrue(mgr.HasBindings); + Assert.AreEqual("Nikola Tesla", target.Name); + Assert.AreEqual(new DateTime(1856, 7, 9), target.DOB); + Assert.AreEqual(new string[] { "One", "Two" }, target.Inventions); + Assert.IsNull(target.PlaceOfBirth.City); + Assert.IsNull(target.PlaceOfBirth.Country); + + target.Name = "Tesla, Nikola"; + target.DOB = DateTime.Today; + target.PlaceOfBirth.City = "Smiljan"; + target.PlaceOfBirth.Country = "Lika"; + + mgr.BindTargetToSource(source, target, null); + Assert.AreEqual("Tesla, Nikola", source["name"]); + Assert.AreEqual(DateTime.Today, source["dob"]); + Assert.AreEqual("One", ((string[]) source["inventions"])[0]); + Assert.AreEqual("Smiljan", source["cityOfBirth"]); + Assert.AreEqual("Lika", source["countryOfBirth"]); + } + + [Test] + public void WithTypeConversion() + { + Hashtable source = new Hashtable(); + Inventor target = new Inventor(); + + source["name"] = "Nikola Tesla"; + source["dob"] = "1856-7-9"; + source["inventions"] = "One,Two"; + + // I know this is pupin's graduation year but I need a date here + source["dateofgraduation"] = "1883-1-1"; + + mgr.BindSourceToTarget(source, target, null); + + Assert.IsTrue(mgr.HasBindings); + Assert.AreEqual("Nikola Tesla", target.Name); + Assert.AreEqual(new DateTime(1856, 7, 9), target.DOB); + Assert.AreEqual(new string[] { "One", "Two" }, target.Inventions); + Assert.IsNull(target.PlaceOfBirth.City); + Assert.IsNull(target.PlaceOfBirth.Country); + + target.Name = "Tesla, Nikola"; + target.DOB = DateTime.Today; + target.PlaceOfBirth.City = "Smiljan"; + target.PlaceOfBirth.Country = "Lika"; + + mgr.BindTargetToSource(source, target, null); + Assert.AreEqual("Tesla, Nikola", source["name"]); + Assert.AreEqual(DateTime.Today, source["dob"]); + Assert.AreEqual("One", ((string[]) source["inventions"])[0]); + Assert.AreEqual("Smiljan", source["cityOfBirth"]); + Assert.AreEqual("Lika", source["countryOfBirth"]); + } + + [Test] + public void BindNullValues() + { + Hashtable source; + Inventor target; + + target = new Inventor(); + source = new Hashtable(); + + // this is legal (dog is nullable) + BaseBindingManager mgr = new BaseBindingManager(); + mgr.AddBinding("['dateofgraduation']", "DateOfGraduation"); + + source["dateofgraduation"] = null; + target.DateOfGraduation = DateTime.Now; + mgr.BindSourceToTarget(source, target, null); + Assert.IsNull(target.DateOfGraduation); + + source["dateofgraduation"] = DateTime.Now; + mgr.BindTargetToSource(source, target, null); + Assert.IsNull(source["dateofgraduation"]); + } + + [Test] + public void BindNullValuesWithFormatter() + { + Hashtable source; + Inventor target; + + target = new Inventor(); + source = new Hashtable(); + + // this is legal (dog is nullable) + BaseBindingManager mgr = new BaseBindingManager(); + mgr.AddBinding("['dateofgraduation']", "DateOfGraduation", new HasTextFilteringFormatter(null, null)); + + source["dateofgraduation"] = string.Empty; + target.DateOfGraduation = DateTime.Now; + mgr.BindSourceToTarget(source, target, null); + Assert.IsNull(target.DateOfGraduation); + } + + [Test] + public void UnhandledTypeConversionExceptionSourceToTarget() + { + BaseBindingManager dbm = new BaseBindingManager(); + Hashtable source = new Hashtable(); + source["boolValue"] = false; + Inventor target = new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian"); + + dbm.AddBinding("['boolValue']", "DOB"); + + try { - mgr = new BaseBindingManager(); - mgr.AddBinding("['name']", "Name"); - mgr.AddBinding("['dob']", "DOB"); - mgr.AddBinding("['dateofgraduation']", "DateOfGraduation"); - mgr.AddBinding("['inventions']", "Inventions"); - mgr.AddBinding("['cityOfBirth']", "PlaceOfBirth.City"); - mgr.AddBinding("['countryOfBirth']", "PlaceOfBirth.Country"); - } - - [Test] - public void WithoutTypeConversion() - { - Hashtable source = new Hashtable(); - Inventor target = new Inventor(); - - source["name"] = "Nikola Tesla"; - source["dob"] = new DateTime(1856, 7, 9); - - // I know this is pupin's graduation year but I need a date here - source["dateofgraduation"] = new DateTime(1883,1,1); - source["inventions"] = new string[] {"One", "Two"}; - - mgr.BindSourceToTarget(source, target, null); - - Assert.IsTrue(mgr.HasBindings); - Assert.AreEqual("Nikola Tesla", target.Name); - Assert.AreEqual(new DateTime(1856, 7, 9), target.DOB); - Assert.AreEqual(new string[] {"One", "Two"}, target.Inventions); - Assert.IsNull(target.PlaceOfBirth.City); - Assert.IsNull(target.PlaceOfBirth.Country); - - target.Name = "Tesla, Nikola"; - target.DOB = DateTime.Today; - target.PlaceOfBirth.City = "Smiljan"; - target.PlaceOfBirth.Country = "Lika"; - - mgr.BindTargetToSource(source, target, null); - Assert.AreEqual("Tesla, Nikola", source["name"]); - Assert.AreEqual(DateTime.Today, source["dob"]); - Assert.AreEqual("One", ((string[]) source["inventions"])[0]); - Assert.AreEqual("Smiljan", source["cityOfBirth"]); - Assert.AreEqual("Lika", source["countryOfBirth"]); - } - - [Test] - public void WithTypeConversion() - { - Hashtable source = new Hashtable(); - Inventor target = new Inventor(); - - source["name"] = "Nikola Tesla"; - source["dob"] = "1856-7-9"; - source["inventions"] = "One,Two"; - - // I know this is pupin's graduation year but I need a date here - source["dateofgraduation"] = "1883-1-1"; - - mgr.BindSourceToTarget(source, target, null); - - Assert.IsTrue(mgr.HasBindings); - Assert.AreEqual("Nikola Tesla", target.Name); - Assert.AreEqual(new DateTime(1856, 7, 9), target.DOB); - Assert.AreEqual(new string[] {"One", "Two"}, target.Inventions); - Assert.IsNull(target.PlaceOfBirth.City); - Assert.IsNull(target.PlaceOfBirth.Country); - - target.Name = "Tesla, Nikola"; - target.DOB = DateTime.Today; - target.PlaceOfBirth.City = "Smiljan"; - target.PlaceOfBirth.Country = "Lika"; - - mgr.BindTargetToSource(source, target, null); - Assert.AreEqual("Tesla, Nikola", source["name"]); - Assert.AreEqual(DateTime.Today, source["dob"]); - Assert.AreEqual("One", ((string[]) source["inventions"])[0]); - Assert.AreEqual("Smiljan", source["cityOfBirth"]); - Assert.AreEqual("Lika", source["countryOfBirth"]); - - } - - [Test] - public void BindNullValues() - { - Hashtable source; - Inventor target; - - target = new Inventor(); - source = new Hashtable(); - - // this is legal (dog is nullable) - BaseBindingManager mgr = new BaseBindingManager(); - mgr.AddBinding("['dateofgraduation']", "DateOfGraduation"); - - source["dateofgraduation"] = null; - target.DateOfGraduation = DateTime.Now; - mgr.BindSourceToTarget(source, target, null); - Assert.IsNull(target.DateOfGraduation); - - source["dateofgraduation"] = DateTime.Now; - mgr.BindTargetToSource(source, target, null); - Assert.IsNull(source["dateofgraduation"]); - } - - [Test] - public void BindNullValuesWithFormatter() - { - Hashtable source; - Inventor target; - - target = new Inventor(); - source = new Hashtable(); - - // this is legal (dog is nullable) - BaseBindingManager mgr = new BaseBindingManager(); - mgr.AddBinding("['dateofgraduation']", "DateOfGraduation", new HasTextFilteringFormatter(null, null)); - - source["dateofgraduation"] = string.Empty; - target.DateOfGraduation = DateTime.Now; - mgr.BindSourceToTarget(source, target, null); - Assert.IsNull(target.DateOfGraduation); - } - - [Test] - public void UnhandledTypeConversionExceptionSourceToTarget() - { - BaseBindingManager dbm = new BaseBindingManager(); - Hashtable source = new Hashtable(); - source["boolValue"] = false; - Inventor target = new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian"); - - dbm.AddBinding("['boolValue']", "DOB"); - - try - { - dbm.BindSourceToTarget(source, target, null); - Assert.Fail("Binding boolean to date should throw an exception."); - } - catch (TypeMismatchException) - {} - - // binding state is not remembered with ValidationErrors=null! - dbm.BindTargetToSource(source, target, null); - Assert.AreEqual(target.DOB, source["boolValue"]); - } - - [Test] - public void UnhandledTypeConversionExceptionTargetToSource() - { - BaseBindingManager dbm = new BaseBindingManager(); - Inventor st = new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian"); - st.Inventions = new string[] {"Invention One", "Invention Two"}; - - dbm.AddBinding("pob", "DOB"); - - try - { - dbm.BindTargetToSource(st, st, null); - Assert.Fail("Binding date to custom Place type should throw an exception."); - } - catch (TypeMismatchException) - {} - - // binding state is not remembered with ValidationErrors=null! - try - { - dbm.BindSourceToTarget(st, st, null); - Assert.Fail("Binding custom Place to date type should throw an exception."); - } - catch (TypeMismatchException) - {} - } - - [Test] - public void HandledTypeConversionExceptionSourceToTarget() - { - BaseBindingManager dbm = new BaseBindingManager(); - IValidationErrors errors = new ValidationErrors(); - Hashtable source = new Hashtable(); - source["boolValue"] = false; - Inventor target = new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian"); - - SimpleExpressionBinding binding = new SimpleExpressionBinding("['boolValue']", "DOB"); - binding.SetErrorMessage("error", "errors"); - dbm.AddBinding(binding); - - dbm.BindSourceToTarget(source, target, errors); - Assert.IsFalse(binding.IsValid(errors)); - Assert.IsFalse(errors.IsEmpty); - Assert.AreEqual(1, errors.GetErrors("errors").Count); - - // make sure that the old value doesn't override current invalid value - dbm.BindTargetToSource(source, target, errors); - Assert.AreEqual(false, source["boolValue"]); - } - - [Test] - public void HandledTypeConversionExceptionTargetToSource() - { - BaseBindingManager dbm = new BaseBindingManager(); - IValidationErrors errors = new ValidationErrors(); - Inventor st = new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian"); - st.Inventions = new string[] {"Invention One", "Invention Two"}; - - SimpleExpressionBinding binding = new SimpleExpressionBinding("pob", "DOB"); - binding.SetErrorMessage("error", "errors"); - dbm.AddBinding(binding); - - dbm.BindTargetToSource(st, st, errors); - Assert.IsFalse(binding.IsValid(errors)); - Assert.IsFalse(errors.IsEmpty); - Assert.AreEqual(1, errors.GetErrors("errors").Count); - - // make sure that the old value doesn't override current invalid value - dbm.BindSourceToTarget(st, st, errors); - Assert.AreEqual(new DateTime(1856, 7, 9), st.DOB); - } - - [Test] - public void DirectionSourceToTarget() - { - BaseBindingManager dbm = new BaseBindingManager(); - Inventor source = new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian"); - Hashtable target = new Hashtable(); - - dbm.AddBinding("Name", "['name']", BindingDirection.SourceToTarget); dbm.BindSourceToTarget(source, target, null); - Assert.AreEqual("Nikola Tesla", target["name"]); - - target["name"] = "Mihajlo Pupin"; - dbm.BindTargetToSource(source, target, null); - Assert.AreEqual("Nikola Tesla", source.Name); + Assert.Fail("Binding boolean to date should throw an exception."); } - - [Test] - public void DirectionTargetToSource() + catch (TypeMismatchException) { - BaseBindingManager dbm = new BaseBindingManager(); - Inventor source = new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian"); - Hashtable target = new Hashtable(); - - dbm.AddBinding("Name", "['name']", BindingDirection.TargetToSource); - dbm.BindSourceToTarget(source, target, null); - Assert.IsNull(target["name"]); - - target["name"] = "Mihajlo Pupin"; - dbm.BindTargetToSource(source, target, null); - Assert.AreEqual("Mihajlo Pupin", source.Name); } + // binding state is not remembered with ValidationErrors=null! + dbm.BindTargetToSource(source, target, null); + Assert.AreEqual(target.DOB, source["boolValue"]); + } + + [Test] + public void UnhandledTypeConversionExceptionTargetToSource() + { + BaseBindingManager dbm = new BaseBindingManager(); + Inventor st = new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian"); + st.Inventions = new string[] { "Invention One", "Invention Two" }; + + dbm.AddBinding("pob", "DOB"); + + try + { + dbm.BindTargetToSource(st, st, null); + Assert.Fail("Binding date to custom Place type should throw an exception."); + } + catch (TypeMismatchException) + { + } + + // binding state is not remembered with ValidationErrors=null! + try + { + dbm.BindSourceToTarget(st, st, null); + Assert.Fail("Binding custom Place to date type should throw an exception."); + } + catch (TypeMismatchException) + { + } + } + + [Test] + public void HandledTypeConversionExceptionSourceToTarget() + { + BaseBindingManager dbm = new BaseBindingManager(); + IValidationErrors errors = new ValidationErrors(); + Hashtable source = new Hashtable(); + source["boolValue"] = false; + Inventor target = new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian"); + + SimpleExpressionBinding binding = new SimpleExpressionBinding("['boolValue']", "DOB"); + binding.SetErrorMessage("error", "errors"); + dbm.AddBinding(binding); + + dbm.BindSourceToTarget(source, target, errors); + Assert.IsFalse(binding.IsValid(errors)); + Assert.IsFalse(errors.IsEmpty); + Assert.AreEqual(1, errors.GetErrors("errors").Count); + + // make sure that the old value doesn't override current invalid value + dbm.BindTargetToSource(source, target, errors); + Assert.AreEqual(false, source["boolValue"]); + } + + [Test] + public void HandledTypeConversionExceptionTargetToSource() + { + BaseBindingManager dbm = new BaseBindingManager(); + IValidationErrors errors = new ValidationErrors(); + Inventor st = new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian"); + st.Inventions = new string[] { "Invention One", "Invention Two" }; + + SimpleExpressionBinding binding = new SimpleExpressionBinding("pob", "DOB"); + binding.SetErrorMessage("error", "errors"); + dbm.AddBinding(binding); + + dbm.BindTargetToSource(st, st, errors); + Assert.IsFalse(binding.IsValid(errors)); + Assert.IsFalse(errors.IsEmpty); + Assert.AreEqual(1, errors.GetErrors("errors").Count); + + // make sure that the old value doesn't override current invalid value + dbm.BindSourceToTarget(st, st, errors); + Assert.AreEqual(new DateTime(1856, 7, 9), st.DOB); + } + + [Test] + public void DirectionSourceToTarget() + { + BaseBindingManager dbm = new BaseBindingManager(); + Inventor source = new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian"); + Hashtable target = new Hashtable(); + + dbm.AddBinding("Name", "['name']", BindingDirection.SourceToTarget); + dbm.BindSourceToTarget(source, target, null); + Assert.AreEqual("Nikola Tesla", target["name"]); + + target["name"] = "Mihajlo Pupin"; + dbm.BindTargetToSource(source, target, null); + Assert.AreEqual("Nikola Tesla", source.Name); + } + + [Test] + public void DirectionTargetToSource() + { + BaseBindingManager dbm = new BaseBindingManager(); + Inventor source = new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian"); + Hashtable target = new Hashtable(); + + dbm.AddBinding("Name", "['name']", BindingDirection.TargetToSource); + dbm.BindSourceToTarget(source, target, null); + Assert.IsNull(target["name"]); + + target["name"] = "Mihajlo Pupin"; + dbm.BindTargetToSource(source, target, null); + Assert.AreEqual("Mihajlo Pupin", source.Name); + } + // [Test] // public void ResetBindingStates() // { // BaseBindingManager dbm = new BaseBindingManager(); // Inventor source = new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian"); // Hashtable target = new Hashtable(); -// +// // dbm.AddBinding("Name", "['name']"); // dbm.AddBinding("WrongProperty", "['wrongproperty']"); -// +// // try // { // dbm.BindSourceToTarget(source, target, null); // throw new AssertionException("should throw InvalidPropertyException"); // } catch(Spring.Objects.InvalidPropertyException) {} // ok -// +// // // will ignore previously failed bindings - bindingState is false // dbm.BindSourceToTarget(source, target, null); -// +// // // now reset states // dbm.ResetBindingStates(); -// +// // // now throws again // try // { // dbm.BindSourceToTarget(source, target, null); // throw new AssertionException("should throw InvalidPropertyException"); -// } -// catch(Spring.Objects.InvalidPropertyException) {} // ok +// } +// catch(Spring.Objects.InvalidPropertyException) {} // ok // } - } -} \ No newline at end of file +} diff --git a/test/Spring/Spring.Core.Tests/DataBinding/SimpleExpressionBindingTests.cs b/test/Spring/Spring.Core.Tests/DataBinding/SimpleExpressionBindingTests.cs index 5de4e4cc..a9a89ad1 100644 --- a/test/Spring/Spring.Core.Tests/DataBinding/SimpleExpressionBindingTests.cs +++ b/test/Spring/Spring.Core.Tests/DataBinding/SimpleExpressionBindingTests.cs @@ -20,23 +20,23 @@ using NUnit.Framework; -namespace Spring.DataBinding +namespace Spring.DataBinding; + +/// +/// Test cases for the SimpleExpressionBinding class. +/// +/// Aleksandar Seovic +[TestFixture] +public class SimpleExpressionBindingTests { - /// - /// Test cases for the SimpleExpressionBinding class. - /// - /// Aleksandar Seovic - [TestFixture] - public class SimpleExpressionBindingTests + private class BindToNullable_TestEntity { - private class BindToNullable_TestEntity - { - private Nullable sortOrder; - public Nullable SortOrder { get { return sortOrder; } set { sortOrder = value; } } - } + private Nullable sortOrder; + public Nullable SortOrder { get { return sortOrder; } set { sortOrder = value; } } + } #if !NETCOREAPP - [Test(Description="http://jira.springframework.org/browse/SPRNET-996")] + [Test(Description = "http://jira.springframework.org/browse/SPRNET-996")] public void BindToNullable() { System.Web.UI.WebControls.TextBox textBox = new System.Web.UI.WebControls.TextBox(); @@ -47,34 +47,33 @@ namespace Spring.DataBinding } #endif - [Test] - public void WithNullMessageId() - { - Assert.Throws(() => new SimpleExpressionBinding("exp", "exp").SetErrorMessage(null, "errors")); - } - - [Test] - public void WithEmptyMessageId() - { - Assert.Throws(() => new SimpleExpressionBinding("exp", "exp").SetErrorMessage("", "errors")); - } - - [Test] - public void WithWhitespaceMessageId() - { - Assert.Throws(() => new SimpleExpressionBinding("exp", "exp").SetErrorMessage("\t ", "errors")); - } - - [Test] - public void WithNullProviders() - { - Assert.Throws(() => new SimpleExpressionBinding("exp", "exp").SetErrorMessage("error", null)); - } - - [Test] - public void WithEmptyProviders() - { - Assert.Throws(() => new SimpleExpressionBinding("exp", "exp").SetErrorMessage("error", new string[0])); - } + [Test] + public void WithNullMessageId() + { + Assert.Throws(() => new SimpleExpressionBinding("exp", "exp").SetErrorMessage(null, "errors")); } -} \ No newline at end of file + + [Test] + public void WithEmptyMessageId() + { + Assert.Throws(() => new SimpleExpressionBinding("exp", "exp").SetErrorMessage("", "errors")); + } + + [Test] + public void WithWhitespaceMessageId() + { + Assert.Throws(() => new SimpleExpressionBinding("exp", "exp").SetErrorMessage("\t ", "errors")); + } + + [Test] + public void WithNullProviders() + { + Assert.Throws(() => new SimpleExpressionBinding("exp", "exp").SetErrorMessage("error", null)); + } + + [Test] + public void WithEmptyProviders() + { + Assert.Throws(() => new SimpleExpressionBinding("exp", "exp").SetErrorMessage("error", new string[0])); + } +} diff --git a/test/Spring/Spring.Core.Tests/Example/Scannable/FooService.cs b/test/Spring/Spring.Core.Tests/Example/Scannable/FooService.cs index 9e4238ed..78c9afd5 100644 --- a/test/Spring/Spring.Core.Tests/Example/Scannable/FooService.cs +++ b/test/Spring/Spring.Core.Tests/Example/Scannable/FooService.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2010-2011 the original author or authors. + * Copyright � 2010-2011 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. @@ -20,32 +20,28 @@ using Spring.Stereotype; -namespace Spring.Example.Scannable +namespace Spring.Example.Scannable; + +/// +/// +/// +/// Mark Pollack +[Service] +public class FooService : IFooService { - /// - /// - /// - /// Mark Pollack - [Service] - public class FooService : IFooService + private string foo; + + private bool initCalled; + + public string Foo { - private string foo; - - private bool initCalled; - - - - public string Foo - { - get { return foo; } - set { foo = value; } - } - - public bool InitCalled - { - get { return initCalled; } - set { initCalled = value; } - } + get { return foo; } + set { foo = value; } } -} \ No newline at end of file + public bool InitCalled + { + get { return initCalled; } + set { initCalled = value; } + } +} diff --git a/test/Spring/Spring.Core.Tests/Example/Scannable/IFooDao.cs b/test/Spring/Spring.Core.Tests/Example/Scannable/IFooDao.cs index de78ead8..ce08d6d8 100644 --- a/test/Spring/Spring.Core.Tests/Example/Scannable/IFooDao.cs +++ b/test/Spring/Spring.Core.Tests/Example/Scannable/IFooDao.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2010-2011 the original author or authors. + * Copyright � 2010-2011 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. @@ -18,15 +18,13 @@ #endregion -namespace Spring.Example.Scannable -{ - /// - /// - /// - /// Mark Pollack - public interface IFooDao - { - string FindFoo(string id); - } +namespace Spring.Example.Scannable; -} \ No newline at end of file +/// +/// +/// +/// Mark Pollack +public interface IFooDao +{ + string FindFoo(string id); +} diff --git a/test/Spring/Spring.Core.Tests/Example/Scannable/IFooService.cs b/test/Spring/Spring.Core.Tests/Example/Scannable/IFooService.cs index 8b0ed44d..2038c9e9 100644 --- a/test/Spring/Spring.Core.Tests/Example/Scannable/IFooService.cs +++ b/test/Spring/Spring.Core.Tests/Example/Scannable/IFooService.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2010-2011 the original author or authors. + * Copyright � 2010-2011 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. @@ -18,18 +18,15 @@ #endregion -namespace Spring.Example.Scannable +namespace Spring.Example.Scannable; + +/// +/// Simple service for testing of component scanning +/// +/// Mark Pollack +public interface IFooService { - /// - /// Simple service for testing of component scanning - /// - /// Mark Pollack - public interface IFooService - { - string Foo { get; set; } + string Foo { get; set; } - bool InitCalled { get; set; } - - } - -} \ No newline at end of file + bool InitCalled { get; set; } +} diff --git a/test/Spring/Spring.Core.Tests/Example/Scannable/StubFooDao.cs b/test/Spring/Spring.Core.Tests/Example/Scannable/StubFooDao.cs index 3d15ebbc..edaefabd 100644 --- a/test/Spring/Spring.Core.Tests/Example/Scannable/StubFooDao.cs +++ b/test/Spring/Spring.Core.Tests/Example/Scannable/StubFooDao.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2010-2011 the original author or authors. + * Copyright � 2010-2011 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. @@ -20,19 +20,17 @@ using Spring.Stereotype; -namespace Spring.Example.Scannable -{ - /// - /// - /// - /// Mark Pollack - [Repository] - public class StubFooDao : IFooDao - { - public string FindFoo(string id) - { - return "bar"; - } - } +namespace Spring.Example.Scannable; -} \ No newline at end of file +/// +/// +/// +/// Mark Pollack +[Repository] +public class StubFooDao : IFooDao +{ + public string FindFoo(string id) + { + return "bar"; + } +} diff --git a/test/Spring/Spring.Core.Tests/ExceptionsTest.cs b/test/Spring/Spring.Core.Tests/ExceptionsTest.cs index c626d7a2..eedbbd2b 100644 --- a/test/Spring/Spring.Core.Tests/ExceptionsTest.cs +++ b/test/Spring/Spring.Core.Tests/ExceptionsTest.cs @@ -28,420 +28,423 @@ using NUnit.Framework; #pragma warning disable SYSLIB0050 #pragma warning disable SYSLIB0051 -namespace Spring +namespace Spring; + +/// +/// Tests the various exception classes. +/// +/// +/// +/// Shamelessly lifted from the NAnt test suite. +/// +/// +public abstract class ExceptionsTest : StandardsComplianceTest { - /// - /// Tests the various exception classes. - /// - /// - /// - /// Shamelessly lifted from the NAnt test suite. - /// - /// - public abstract class ExceptionsTest : StandardsComplianceTest - { - // sorry folks, but this is really a special case - default ctor policy doesn't apply here - private bool ExcludeFromConstructorPolicyCheck(Type t) + // sorry folks, but this is really a special case - default ctor policy doesn't apply here + private bool ExcludeFromConstructorPolicyCheck(Type t) + { + //TODO: uncomment when making SyntaxErrorException public: + if (t.FullName == "Spring.Expressions.SyntaxErrorException") return true; + return false; + } + + protected ExceptionsTest() + { + CheckedType = typeof(Exception); + } + + #region Tests + + [Test] + public void TestStandardsCompliance() + { + ProcessAssembly(AssemblyToCheck); + } + + [Test] + public void TestThisTest() + { + ProcessAssembly(Assembly.GetAssembly(GetType())); + } + + #endregion + + #region Methods + + protected override void CheckStandardsCompliance(Assembly assembly, Type t) + { + // check to see that the exception is correctly named, with "Exception" at the end + bool nameIsValid = t.Name.EndsWith("Exception"); + Assert.IsTrue(nameIsValid, t.Name + " class name must end with Exception."); + if (t.IsAbstract) { - //TODO: uncomment when making SyntaxErrorException public: - if (t.FullName == "Spring.Expressions.SyntaxErrorException") return true; - return false; + return; } - protected ExceptionsTest() - { - CheckedType = typeof (Exception); - } + if (!ExcludeFromConstructorPolicyCheck(t)) + { + // Does the exception have the 3 standard constructors? + // Default constructor + CheckPublicConstructor(t, "()"); + // Constructor with a single string parameter + CheckPublicConstructor(t, "(string message)", typeof(String)); + // Constructor with a string and an inner exception + CheckPublicConstructor(t, "(string message, Exception inner)", + typeof(String), typeof(Exception)); + } - #region Tests + // check to see if the serialization constructor is present + // if exception is sealed, constructor should be private + // if exception is not sealed, constructor should be protected + if (t.IsSealed) + { + // check to see if the private serialization constructor is present... + CheckPrivateConstructor(t, "(SerializationInfo info, StreamingContext context)", + typeof(SerializationInfo), + typeof(StreamingContext)); + } + else + { + // check to see if the protected serialization constructor is present... + CheckProtectedConstructor(t, "(SerializationInfo info, StreamingContext context)", + typeof(SerializationInfo), + typeof(StreamingContext)); + } - [Test] - public void TestStandardsCompliance() - { - ProcessAssembly(AssemblyToCheck); - } - - [Test] - public void TestThisTest() - { - ProcessAssembly(Assembly.GetAssembly(GetType())); - } - - #endregion - - #region Methods - - protected override void CheckStandardsCompliance(Assembly assembly, Type t) - { - // check to see that the exception is correctly named, with "Exception" at the end - bool nameIsValid = t.Name.EndsWith("Exception"); - Assert.IsTrue(nameIsValid, t.Name + " class name must end with Exception."); - if (t.IsAbstract) - { - return; - } - - if (!ExcludeFromConstructorPolicyCheck(t)) + // check to see if the type is marked as serializable + Assert.IsTrue(t.IsSerializable, t.Name + " is not serializable, missing [Serializable]?"); + // check to see if there are any public fields. These should be properties instead... + FieldInfo[] publicFields = t.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance); + if (publicFields.Length != 0) + { + foreach (FieldInfo fieldInfo in publicFields) { - // Does the exception have the 3 standard constructors? - // Default constructor - CheckPublicConstructor(t, "()"); - // Constructor with a single string parameter - CheckPublicConstructor(t, "(string message)", typeof (String)); - // Constructor with a string and an inner exception - CheckPublicConstructor(t, "(string message, Exception inner)", - typeof (String), typeof (Exception)); + Assert.Fail(t.Name + "." + fieldInfo.Name + " is a public field, should be exposed through property instead."); } + } + // If this exception has any fields, check to make sure it has a + // version of GetObjectData. If not, it does't serialize those fields. + FieldInfo[] fields = + t.GetFields(BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); + if (fields.Length != 0) + { + if (t.GetMethod("GetObjectData", BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance) == null) + { + Assert.Fail(t.Name + " does not implement GetObjectData but has private fields."); + } + } - // check to see if the serialization constructor is present - // if exception is sealed, constructor should be private - // if exception is not sealed, constructor should be protected - if (t.IsSealed) - { - // check to see if the private serialization constructor is present... - CheckPrivateConstructor(t, "(SerializationInfo info, StreamingContext context)", - typeof (SerializationInfo), - typeof (StreamingContext)); - } - else - { - // check to see if the protected serialization constructor is present... - CheckProtectedConstructor(t, "(SerializationInfo info, StreamingContext context)", - typeof (SerializationInfo), - typeof (StreamingContext)); - } - // check to see if the type is marked as serializable - Assert.IsTrue(t.IsSerializable, t.Name + " is not serializable, missing [Serializable]?"); - // check to see if there are any public fields. These should be properties instead... - FieldInfo[] publicFields = t.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance); - if (publicFields.Length != 0) - { - foreach (FieldInfo fieldInfo in publicFields) - { - Assert.Fail(t.Name + "." + fieldInfo.Name + " is a public field, should be exposed through property instead."); - } - } - // If this exception has any fields, check to make sure it has a - // version of GetObjectData. If not, it does't serialize those fields. - FieldInfo[] fields = - t.GetFields(BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); - if (fields.Length != 0) - { - if (t.GetMethod("GetObjectData", BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance) == null) - { - Assert.Fail(t.Name + " does not implement GetObjectData but has private fields."); - } - } - if (!t.IsAbstract - && !ExcludeFromConstructorPolicyCheck(t)) - { - CheckInstantiation(t); - } - } + if (!t.IsAbstract + && !ExcludeFromConstructorPolicyCheck(t)) + { + CheckInstantiation(t); + } + } - private void CheckPublicConstructor(Type t, string description, params Type[] parameters) - { - // locate constructor - ConstructorInfo ci = - t.GetConstructor(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, null, parameters, null); - // fail if constructor does not exist - Assert.IsNotNull(ci, t.Name + description + " is a required constructor."); - // fail if constructor is private - Assert.IsFalse(ci.IsPrivate, t.Name + description + " is private, must be public."); - // fail if constructor is protected - Assert.IsFalse(ci.IsFamily, t.Name + description + " is internal, must be public."); - // fail if constructor is internal - Assert.IsFalse(ci.IsAssembly, t.Name + description + " is internal, must be public."); - // fail if constructor is protected internal - Assert.IsFalse(ci.IsFamilyOrAssembly, t.Name + description + " is protected internal, must be public."); - // sanity check to make sure the constructor is public - Assert.IsTrue(ci.IsPublic, t.Name + description + " is not public, must be public."); - } + private void CheckPublicConstructor(Type t, string description, params Type[] parameters) + { + // locate constructor + ConstructorInfo ci = + t.GetConstructor(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, null, parameters, null); + // fail if constructor does not exist + Assert.IsNotNull(ci, t.Name + description + " is a required constructor."); + // fail if constructor is private + Assert.IsFalse(ci.IsPrivate, t.Name + description + " is private, must be public."); + // fail if constructor is protected + Assert.IsFalse(ci.IsFamily, t.Name + description + " is internal, must be public."); + // fail if constructor is internal + Assert.IsFalse(ci.IsAssembly, t.Name + description + " is internal, must be public."); + // fail if constructor is protected internal + Assert.IsFalse(ci.IsFamilyOrAssembly, t.Name + description + " is protected internal, must be public."); + // sanity check to make sure the constructor is public + Assert.IsTrue(ci.IsPublic, t.Name + description + " is not public, must be public."); + } - private void CheckProtectedConstructor(Type t, string description, params Type[] parameters) - { - // locate constructor - ConstructorInfo ci = - t.GetConstructor(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, null, parameters, null); - // fail if constructor does not exist - Assert.IsNotNull(ci, t.Name + description + " is a required constructor."); - // fail if constructor is public - Assert.IsFalse(ci.IsPublic, t.Name + description + " is public, must be protected."); - // fail if constructor is private - Assert.IsFalse(ci.IsPrivate, t.Name + description + " is private, must be public or protected."); - // fail if constructor is internal - Assert.IsFalse(ci.IsAssembly, t.Name + description + " is internal, must be protected."); - // fail if constructor is protected internal - Assert.IsFalse(ci.IsFamilyOrAssembly, t.Name + description + " is protected internal, must be protected."); - // sanity check to make sure the constructor is protected - Assert.IsTrue(ci.IsFamily, t.Name + description + " is not protected, must be protected."); - } + private void CheckProtectedConstructor(Type t, string description, params Type[] parameters) + { + // locate constructor + ConstructorInfo ci = + t.GetConstructor(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, null, parameters, null); + // fail if constructor does not exist + Assert.IsNotNull(ci, t.Name + description + " is a required constructor."); + // fail if constructor is public + Assert.IsFalse(ci.IsPublic, t.Name + description + " is public, must be protected."); + // fail if constructor is private + Assert.IsFalse(ci.IsPrivate, t.Name + description + " is private, must be public or protected."); + // fail if constructor is internal + Assert.IsFalse(ci.IsAssembly, t.Name + description + " is internal, must be protected."); + // fail if constructor is protected internal + Assert.IsFalse(ci.IsFamilyOrAssembly, t.Name + description + " is protected internal, must be protected."); + // sanity check to make sure the constructor is protected + Assert.IsTrue(ci.IsFamily, t.Name + description + " is not protected, must be protected."); + } - private void CheckPrivateConstructor(Type t, string description, params Type[] parameters) - { - // locate constructor - ConstructorInfo ci = - t.GetConstructor(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, null, parameters, null); - // fail if constructor does not exist - Assert.IsNotNull(ci, t.Name + description + " is a required constructor."); - // fail if constructor is public - Assert.IsFalse(ci.IsPublic, t.Name + description + " is public, must be private."); - // fail if constructor is protected - Assert.IsFalse(ci.IsFamily, t.Name + description + " is protected, must be private."); - // fail if constructor is internal - Assert.IsFalse(ci.IsAssembly, t.Name + description + " is internal, must be private."); - // fail if constructor is protected internal - Assert.IsFalse(ci.IsFamilyOrAssembly, t.Name + description + " is protected internal, must be private."); - // sanity check to make sure the constructor is private - Assert.IsTrue(ci.IsPrivate, t.Name + description + " is not private, must be private."); - } + private void CheckPrivateConstructor(Type t, string description, params Type[] parameters) + { + // locate constructor + ConstructorInfo ci = + t.GetConstructor(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, null, parameters, null); + // fail if constructor does not exist + Assert.IsNotNull(ci, t.Name + description + " is a required constructor."); + // fail if constructor is public + Assert.IsFalse(ci.IsPublic, t.Name + description + " is public, must be private."); + // fail if constructor is protected + Assert.IsFalse(ci.IsFamily, t.Name + description + " is protected, must be private."); + // fail if constructor is internal + Assert.IsFalse(ci.IsAssembly, t.Name + description + " is internal, must be private."); + // fail if constructor is protected internal + Assert.IsFalse(ci.IsFamilyOrAssembly, t.Name + description + " is protected internal, must be private."); + // sanity check to make sure the constructor is private + Assert.IsTrue(ci.IsPrivate, t.Name + description + " is not private, must be private."); + } - /// - /// If we've got here, then the standards compliance tests have passed... - /// - /// The exception type being tested. - private void CheckInstantiation(Type t) - { - // attempt to instantiate the 3 standard ctors... - ConstructorInfo ctor = t.GetConstructor(Type.EmptyTypes); - try - { - ctor.Invoke(null); - } - catch (Exception ex) - { - Assert.Fail("Ctor () for '" + t.Name + "' threw an exception : " + ex.Message); - } - ctor = t.GetConstructor(new Type[] {typeof (string)}); - try - { - Exception ex = (Exception) ctor.Invoke(new object[] {"My Fingers Turn To Fists"}); - Assert.IsNotNull(ex.Message, t.Name + "'s Message was null."); - } - catch (Exception ex) - { - Assert.Fail("Ctor (string) for '" + t.Name + "' threw an exception : " + ex.Message); - } - ctor = t.GetConstructor(new Type[] {typeof (string), typeof (Exception)}); - try - { - Exception ex = (Exception) ctor.Invoke(new object[] {"My Fingers Turn To Fists", new FormatException("Bing")}); - Assert.IsNotNull(ex.Message, t.Name + "'s Message was null."); - Assert.IsNotNull(ex.InnerException, t.Name + "'s InnerException was null."); - Assert.AreEqual("Bing", ex.InnerException.Message); - } - catch (Exception ex) - { - Assert.Fail("Ctor (string, Exception) for '" + t.Name + "' threw an exception : " + ex.Message); - } - // test the serialization ctor - try - { - ctor = t.GetConstructor(new Type[] {typeof (string)}); - Exception ex = (Exception) ctor.Invoke(new object[] {"HungerHurtsButStarvingWorks"}); - BinaryFormatter bf = new BinaryFormatter(); - MemoryStream ms = new MemoryStream(); - bf.Serialize(ms, ex); - ms.Seek(0,0); - Exception inex = (Exception)bf.Deserialize(ms); - Assert.IsNotNull(inex); - } - catch (Exception ex) - { - Assert.Fail("Ctor (Serialization) for '" + t.Name + "' threw an exception : " + ex.Message); - } + /// + /// If we've got here, then the standards compliance tests have passed... + /// + /// The exception type being tested. + private void CheckInstantiation(Type t) + { + // attempt to instantiate the 3 standard ctors... + ConstructorInfo ctor = t.GetConstructor(Type.EmptyTypes); + try + { + ctor.Invoke(null); + } + catch (Exception ex) + { + Assert.Fail("Ctor () for '" + t.Name + "' threw an exception : " + ex.Message); + } - } + ctor = t.GetConstructor(new Type[] { typeof(string) }); + try + { + Exception ex = (Exception) ctor.Invoke(new object[] { "My Fingers Turn To Fists" }); + Assert.IsNotNull(ex.Message, t.Name + "'s Message was null."); + } + catch (Exception ex) + { + Assert.Fail("Ctor (string) for '" + t.Name + "' threw an exception : " + ex.Message); + } - #endregion + ctor = t.GetConstructor(new Type[] { typeof(string), typeof(Exception) }); + try + { + Exception ex = (Exception) ctor.Invoke(new object[] { "My Fingers Turn To Fists", new FormatException("Bing") }); + Assert.IsNotNull(ex.Message, t.Name + "'s Message was null."); + Assert.IsNotNull(ex.InnerException, t.Name + "'s InnerException was null."); + Assert.AreEqual("Bing", ex.InnerException.Message); + } + catch (Exception ex) + { + Assert.Fail("Ctor (string, Exception) for '" + t.Name + "' threw an exception : " + ex.Message); + } - #region Properties + // test the serialization ctor + try + { + ctor = t.GetConstructor(new Type[] { typeof(string) }); + Exception ex = (Exception) ctor.Invoke(new object[] { "HungerHurtsButStarvingWorks" }); + BinaryFormatter bf = new BinaryFormatter(); + MemoryStream ms = new MemoryStream(); + bf.Serialize(ms, ex); + ms.Seek(0, 0); + Exception inex = (Exception) bf.Deserialize(ms); + Assert.IsNotNull(inex); + } + catch (Exception ex) + { + Assert.Fail("Ctor (Serialization) for '" + t.Name + "' threw an exception : " + ex.Message); + } + } - /// - /// We will test all of the exceptions in this assembly for their correctness. - /// - protected Assembly AssemblyToCheck - { - get { return _assemblyToCheck; } - set { _assemblyToCheck = value; } - } + #endregion - #endregion + #region Properties - private Assembly _assemblyToCheck = null; - } + /// + /// We will test all of the exceptions in this assembly for their correctness. + /// + protected Assembly AssemblyToCheck + { + get { return _assemblyToCheck; } + set { _assemblyToCheck = value; } + } - #region Inner Class : SimpleTestException + #endregion - /// - /// Do nothing exception to verify that the exception tester - /// is working correctly. - /// - [Serializable] - public class SimpleTestException : ApplicationException - { - #region Public Instance Constructors - - public SimpleTestException() - { - } - - public SimpleTestException(string message) : base(message) - { - } - - public SimpleTestException(string message, Exception inner) - : base(message, inner) - { - } - - #endregion Public Instance Constructors - - #region Protected Instance Constructors - - // deserialization constructor - protected SimpleTestException( - SerializationInfo info, StreamingContext context) - : base(info, context) - { - } - - #endregion Protected Instance Constructors - } - - #endregion - - #region Inner Class : TestException - - /// - /// Exception to verify that the exception tester is working correctly. - /// - [Serializable] - public class TestException : ApplicationException, ISerializable - { - #region Private Instance Fields - - private int _value; - - #endregion Private Instance Fields - - #region Public Instance Constructors - - public TestException() - { - } - - public TestException(string message) : base(message) - { - } - - public TestException(string message, Exception inner) - : base(message, inner) - { - } - - // constructors that take the added value - public TestException(string message, int value) : base(message) - { - _value = value; - } - - #endregion Public Instance Constructors - - #region Protected Instance Constructors - - // deserialization constructor - protected TestException(SerializationInfo info, StreamingContext context) : base(info, context) - { - _value = info.GetInt32("Value"); - } - - #endregion Protected Instance Constructors - - #region Public Instance Properties - - public int Value - { - get { return _value; } - } - - #endregion Public Instance Properties - - #region Override implementation of ApplicationException - - // Called by the frameworks during serialization - // to fetch the data from an object. - public override void GetObjectData( - SerializationInfo info, StreamingContext context) - { - base.GetObjectData(info, context); - info.AddValue("Value", _value); - } - - // overridden Message property. This will give the - // proper textual representation of the exception, - // with the added field value. - public override string Message - { - get - { - // NOTE: should be localized... - string s = - string.Format( - CultureInfo.InvariantCulture, "Value: {0}", _value); - return base.Message + Environment.NewLine + s; - } - } - - #endregion Override implementation of ApplicationException - } - - #endregion - - #region Inner Class : SealedTestException - - /// - /// Exception to verify that the exception tester is working on - /// sealed exception. - /// - [Serializable] - public sealed class SealedTestException : TestException - { - #region Public Instance Constructors - - public SealedTestException() - { - } - - public SealedTestException(string message) : base(message) - { - } - - public SealedTestException(string message, Exception inner) - : base(message, inner) - { - } - - // constructors that take the added value - public SealedTestException(string message, int value) - : base(message, value) - { - } - - #endregion Public Instance Constructors - - #region Private Instance Constructors - - // deserialization constructor - private SealedTestException( - SerializationInfo info, StreamingContext context) - : base(info, context) - { - } - - #endregion Private Instance Constructors - } - - #endregion + private Assembly _assemblyToCheck = null; } + +#region Inner Class : SimpleTestException + +/// +/// Do nothing exception to verify that the exception tester +/// is working correctly. +/// +[Serializable] +public class SimpleTestException : ApplicationException +{ + #region Public Instance Constructors + + public SimpleTestException() + { + } + + public SimpleTestException(string message) : base(message) + { + } + + public SimpleTestException(string message, Exception inner) + : base(message, inner) + { + } + + #endregion Public Instance Constructors + + #region Protected Instance Constructors + + // deserialization constructor + protected SimpleTestException( + SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + + #endregion Protected Instance Constructors +} + +#endregion + +#region Inner Class : TestException + +/// +/// Exception to verify that the exception tester is working correctly. +/// +[Serializable] +public class TestException : ApplicationException, ISerializable +{ + #region Private Instance Fields + + private int _value; + + #endregion Private Instance Fields + + #region Public Instance Constructors + + public TestException() + { + } + + public TestException(string message) : base(message) + { + } + + public TestException(string message, Exception inner) + : base(message, inner) + { + } + + // constructors that take the added value + public TestException(string message, int value) : base(message) + { + _value = value; + } + + #endregion Public Instance Constructors + + #region Protected Instance Constructors + + // deserialization constructor + protected TestException(SerializationInfo info, StreamingContext context) : base(info, context) + { + _value = info.GetInt32("Value"); + } + + #endregion Protected Instance Constructors + + #region Public Instance Properties + + public int Value + { + get { return _value; } + } + + #endregion Public Instance Properties + + #region Override implementation of ApplicationException + + // Called by the frameworks during serialization + // to fetch the data from an object. + public override void GetObjectData( + SerializationInfo info, StreamingContext context) + { + base.GetObjectData(info, context); + info.AddValue("Value", _value); + } + + // overridden Message property. This will give the + // proper textual representation of the exception, + // with the added field value. + public override string Message + { + get + { + // NOTE: should be localized... + string s = + string.Format( + CultureInfo.InvariantCulture, "Value: {0}", _value); + return base.Message + Environment.NewLine + s; + } + } + + #endregion Override implementation of ApplicationException +} + +#endregion + +#region Inner Class : SealedTestException + +/// +/// Exception to verify that the exception tester is working on +/// sealed exception. +/// +[Serializable] +public sealed class SealedTestException : TestException +{ + #region Public Instance Constructors + + public SealedTestException() + { + } + + public SealedTestException(string message) : base(message) + { + } + + public SealedTestException(string message, Exception inner) + : base(message, inner) + { + } + + // constructors that take the added value + public SealedTestException(string message, int value) + : base(message, value) + { + } + + #endregion Public Instance Constructors + + #region Private Instance Constructors + + // deserialization constructor + private SealedTestException( + SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + + #endregion Private Instance Constructors +} + +#endregion diff --git a/test/Spring/Spring.Core.Tests/Expressions/ConstructorNodeTests.cs b/test/Spring/Spring.Core.Tests/Expressions/ConstructorNodeTests.cs index 55ab3ee3..57a058eb 100644 --- a/test/Spring/Spring.Core.Tests/Expressions/ConstructorNodeTests.cs +++ b/test/Spring/Spring.Core.Tests/Expressions/ConstructorNodeTests.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -24,86 +24,87 @@ using NUnit.Framework; #endregion -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// +/// +/// Erich Eichinger +[TestFixture] +public class ConstructorNodeTests { - /// - /// - /// - /// Erich Eichinger - [TestFixture] - public class ConstructorNodeTests + #region Test Classes + + public class PublicTestClass { - #region Test Classes + public string _s; + public int _i; - public class PublicTestClass + public PublicTestClass(string s) + : this(s, -1) { - public string _s; - public int _i; - - public PublicTestClass(string s) - :this(s, -1) - {} - - protected PublicTestClass(string s, int i) - { - _s = s; _i=i; - } } - private class PrivateTestClass : PublicTestClass + protected PublicTestClass(string s, int i) { - private PrivateTestClass(string s, int i) - :base(s,i) - { - } - } - - #endregion Test Classes - - [Test] - public void CanCreatePublicInstance() - { - ConstructorNode ctorNode = new ConstructorNode(typeof(PublicTestClass)); - StringLiteralNode sNode = new StringLiteralNode("theValue"); - ctorNode.AddArgument(sNode); - - PublicTestClass instance = (PublicTestClass) ((IExpression)ctorNode).GetValue(); - Assert.AreEqual( sNode.Text, instance._s ); - Assert.AreEqual( -1, instance._i ); - } - - [Test] - public void CanCreatePublicInstanceWithNonPublicConstructor() - { - ConstructorNode ctorNode = new ConstructorNode(); - ctorNode.Text=typeof(PublicTestClass).FullName; - StringLiteralNode sNode = new StringLiteralNode(); - sNode.Text = "theValue2"; - ctorNode.addChild(sNode); - IntLiteralNode iNode = new IntLiteralNode(); - iNode.Text="2"; - ctorNode.addChild(iNode); - - PublicTestClass instance = (PublicTestClass) ((IExpression)ctorNode).GetValue(); - Assert.AreEqual( sNode.Text, instance._s ); - Assert.AreEqual( 2, instance._i ); - } - - [Test] - public void CanCreateNonPublicInstanceWithNonPublicConstructor() - { - ConstructorNode ctorNode = new ConstructorNode(); - ctorNode.Text=typeof(PrivateTestClass).FullName; - StringLiteralNode sNode = new StringLiteralNode(); - sNode.Text = "theValue3"; - ctorNode.addChild(sNode); - IntLiteralNode iNode = new IntLiteralNode(); - iNode.Text="3"; - ctorNode.addChild(iNode); - - PublicTestClass instance = (PublicTestClass) ((IExpression)ctorNode).GetValue(); - Assert.AreEqual( sNode.Text, instance._s ); - Assert.AreEqual( 3, instance._i ); + _s = s; + _i = i; } } -} \ No newline at end of file + + private class PrivateTestClass : PublicTestClass + { + private PrivateTestClass(string s, int i) + : base(s, i) + { + } + } + + #endregion Test Classes + + [Test] + public void CanCreatePublicInstance() + { + ConstructorNode ctorNode = new ConstructorNode(typeof(PublicTestClass)); + StringLiteralNode sNode = new StringLiteralNode("theValue"); + ctorNode.AddArgument(sNode); + + PublicTestClass instance = (PublicTestClass) ((IExpression) ctorNode).GetValue(); + Assert.AreEqual(sNode.Text, instance._s); + Assert.AreEqual(-1, instance._i); + } + + [Test] + public void CanCreatePublicInstanceWithNonPublicConstructor() + { + ConstructorNode ctorNode = new ConstructorNode(); + ctorNode.Text = typeof(PublicTestClass).FullName; + StringLiteralNode sNode = new StringLiteralNode(); + sNode.Text = "theValue2"; + ctorNode.addChild(sNode); + IntLiteralNode iNode = new IntLiteralNode(); + iNode.Text = "2"; + ctorNode.addChild(iNode); + + PublicTestClass instance = (PublicTestClass) ((IExpression) ctorNode).GetValue(); + Assert.AreEqual(sNode.Text, instance._s); + Assert.AreEqual(2, instance._i); + } + + [Test] + public void CanCreateNonPublicInstanceWithNonPublicConstructor() + { + ConstructorNode ctorNode = new ConstructorNode(); + ctorNode.Text = typeof(PrivateTestClass).FullName; + StringLiteralNode sNode = new StringLiteralNode(); + sNode.Text = "theValue3"; + ctorNode.addChild(sNode); + IntLiteralNode iNode = new IntLiteralNode(); + iNode.Text = "3"; + ctorNode.addChild(iNode); + + PublicTestClass instance = (PublicTestClass) ((IExpression) ctorNode).GetValue(); + Assert.AreEqual(sNode.Text, instance._s); + Assert.AreEqual(3, instance._i); + } +} diff --git a/test/Spring/Spring.Core.Tests/Expressions/ExpressionEvaluatorTests.cs b/test/Spring/Spring.Core.Tests/Expressions/ExpressionEvaluatorTests.cs index 854d7d14..286b7ed4 100644 --- a/test/Spring/Spring.Core.Tests/Expressions/ExpressionEvaluatorTests.cs +++ b/test/Spring/Spring.Core.Tests/Expressions/ExpressionEvaluatorTests.cs @@ -47,3117 +47,3115 @@ using Spring.Util; #endregion -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// This class contains tests for ExpressionEvaluator. +/// +/// Aleksandar Seovic +[TestFixture] +public sealed class ExpressionEvaluatorTests { - /// - /// This class contains tests for ExpressionEvaluator. - /// - /// Aleksandar Seovic - [TestFixture] - public sealed class ExpressionEvaluatorTests + #region Helper classes for threading tests + + public class AsyncTestExpressionEvaluation : AsyncTestTask { - #region Helper classes for threading tests + private IExpression exp; + private object rootContext; + private object expected; + private IDictionary variables; - public class AsyncTestExpressionEvaluation : AsyncTestTask + public AsyncTestExpressionEvaluation(int iterations, IExpression exp, object rootContext, object expected, + IDictionary variables) + : base(iterations) { - private IExpression exp; - private object rootContext; - private object expected; - private IDictionary variables; - - public AsyncTestExpressionEvaluation(int iterations, IExpression exp, object rootContext, object expected, - IDictionary variables) - : base(iterations) - { - this.exp = exp; - this.rootContext = rootContext; - this.expected = expected; - this.variables = variables; - } - - public override void DoExecute() - { - object result = exp.GetValue(rootContext, variables); - Assert.AreEqual(expected, result); - } - } - - #endregion - - private Inventor tesla; - private Inventor pupin; - private Society ieee; - - #region SetUp and TearDown - - /// - /// The setup logic executed before the execution of each individual test. - /// - [SetUp] - public void SetUp() - { - ContextRegistry.Clear(); - tesla = new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian"); - tesla.Inventions = new string[] - { - "Telephone repeater", "Rotating magnetic field principle", - "Polyphase alternating-current system", "Induction motor", - "Alternating-current power transmission", "Tesla coil transformer", - "Wireless communication", "Radio", "Fluorescent lights" - }; - tesla.PlaceOfBirth.City = "Smiljan"; - - pupin = new Inventor("Mihajlo Pupin", new DateTime(1854, 10, 9), "Serbian"); - pupin.Inventions = - new string[] { "Long distance telephony & telegraphy", "Secondary X-Ray radiation", "Sonar" }; - pupin.PlaceOfBirth.City = "Idvor"; - pupin.PlaceOfBirth.Country = "Serbia"; - - ieee = new Society(); - ieee.Members.Add(tesla); - ieee.Members.Add(pupin); - ieee.Officers["president"] = pupin; - ieee.Officers["advisors"] = new Inventor[] { tesla, pupin }; - // not historically accurate, but I need an array in the map ;-) - - TypeRegistry.RegisterType("Society", typeof(Society)); - } - - [OneTimeTearDown] - public void TearDown() - { - //DynamicCodeManager.SaveAssembly(); - } - - #endregion - - #region Serialization Tests - - /// - /// GetObjectData() is not overridden on purpose !!! - /// - [Serializable] - private class SerializationTestExpression : BaseNode - { - private int testValue = 0; - - public int TestValue - { - get { return testValue; } - } - - public SerializationTestExpression(int testValue) - { - this.testValue = testValue; - } - - protected SerializationTestExpression(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } - - protected override object Get(object context, EvaluationContext evalContext) - { - throw new NotImplementedException(); - } - } - - /// - /// Tests serialization + deserialization of all BaseNode derived types - /// - [Test] - public void AllExpressionNodeTypesAreSerializable() - { - Type[] possibleTypes = typeof(BaseNode).Assembly.GetTypes(); - - BinaryFormatter formatter = new BinaryFormatter(); - - // look for all BaseNode derived types defined in assembly Spring.Core - for (int i = 0; i < possibleTypes.Length; i++) - { - Type t = possibleTypes[i]; - if (t != typeof(BaseNode) - && typeof(BaseNode).IsAssignableFrom(t) - && (!t.IsAbstract) - ) - { - //Console.WriteLine("testing " + t.FullName); - - // create using for public default ctor - IExpression exp = (IExpression)Activator.CreateInstance(t, true); - // serialize and deserialize it - exp = SerializeDeserializeExpression(exp); - exp = SerializeDeserializeExpressionUsingSoap(exp); - } - } - } - - /// - /// implements . - /// Thus members in derived classes won't get automatically serialized. - /// - [Test] - public void MembersDontGetSerializedByDefault() - { - SerializationTestExpression exp = new SerializationTestExpression(5); - Assert.AreEqual(5, exp.TestValue); - SerializationTestExpression exp2 = (SerializationTestExpression)SerializeDeserializeExpression(exp); - Assert.AreEqual(0, exp2.TestValue); - } - - /// - /// This test ensures, that the default node-type is serializable. - /// - /// - /// date() is parsed into DateLiteralNode( down:<default node type> ). - /// Normally antlr.CommonAST is the default node used by antlr. To enable serialization, Spring - /// uses a custom ASTFactory in - /// - [Test] - public void ExpressionDateLiteralNodeMaintainsStateAfterSerialization() - { - IExpression exp = Expression.Parse("date('08-24-1974', 'MM-dd-yyyy')"); - - Assert.AreEqual(new DateTime(1974, 8, 24), exp.GetValue(null)); - - exp = SerializeDeserializeExpression(exp); - - Assert.AreEqual(new DateTime(1974, 8, 24), exp.GetValue(null)); - } - - private static IExpression SerializeDeserializeExpression(IExpression exp) - { - byte[] data; - BinaryFormatter formatter = new BinaryFormatter(); - using (MemoryStream ms = new MemoryStream()) - { - formatter.Serialize(ms, exp); - ms.Flush(); - data = ms.ToArray(); - } - - using (MemoryStream ms = new MemoryStream(data)) - { - exp = (IExpression)formatter.Deserialize(ms); - } - - return exp; - } - - private static IExpression SerializeDeserializeExpressionUsingSoap(IExpression exp) - { - string xml; - SoapFormatter formatter = new SoapFormatter(); - using (MemoryStream ms = new MemoryStream()) - { - formatter.Serialize(ms, exp); - ms.Position = 0; - byte[] b = new byte[ms.Length]; - ms.Read(b, 0, (int)ms.Length); - xml = Encoding.ASCII.GetString(b, 0, b.Length); - } - using (StringReader sr = new StringReader(xml)) - { - byte[] b = Encoding.ASCII.GetBytes(xml); - Stream stream = new MemoryStream(b); - exp = (IExpression)formatter.Deserialize(stream); - } - return exp; - } - - #endregion Serialization Tests - - [Test] - public void TestConstantRead() - { - object value = ExpressionEvaluator.GetValue(null, "Society.ByteConst == 1"); - Assert.AreEqual(true, value); - } - - [Test] - public void TestBitwiseXOR() - { - object value = ExpressionEvaluator.GetValue(null, "'123' + 1"); - Assert.AreEqual("1231", value); - } - - [Test] - public void TestMixedAddition() - { - object value = ExpressionEvaluator.GetValue(null, "'123' + 1"); - Assert.AreEqual("1231", value); - } - - [Test(Description = "SPRNET-1507 - Test 1")] - public void TestExpandoObject() - { - dynamic dynamicObject = new System.Dynamic.ExpandoObject(); - //add property at run-time - dynamicObject.IssueId = "1507"; - - object value = ExpressionEvaluator.GetValue(dynamicObject, "IssueId"); - Assert.AreEqual("1507", value); - } - - [Test(Description = "SPRNET-1507 - Test 2")] - public void TestExpandoObjectWithNotExistedProperty() - { - try - { - dynamic dynamicObject = new System.Dynamic.ExpandoObject(); - - ExpressionEvaluator.GetValue(dynamicObject, "PropertyName"); - Assert.Fail(); - } - catch (InvalidPropertyException ex) - { - Assert.AreEqual( - "'PropertyName' node cannot be resolved for the specified context [System.Dynamic.ExpandoObject].", - ex.Message); - } - } - - [Test(Description = "SPRNET-944")] - public void DateTests() - { - string dateLiteral = (string)ExpressionEvaluator.GetValue(null, "'date'"); - Assert.AreEqual("date", dateLiteral); - } - - [Test(Description = "http://jira.springframework.org/browse/SPRNET-944")] - public void TestDateVariableExpression() - { - Dictionary vars = new Dictionary(); - vars["date"] = "2008-05-15"; - object value = ExpressionEvaluator.GetValue(null, "#date", vars); - Assert.That(value, Is.EqualTo("2008-05-15")); - } - - [Test(Description = "http://jira.springframework.org/browse/SPRNET-1155")] - public void TestDateVariableExpressionCamelCased() - { - Dictionary vars = new Dictionary(); - vars["Date"] = "2008-05-15"; - object value = ExpressionEvaluator.GetValue(null, "#Date", vars); - Assert.That(value, Is.EqualTo("2008-05-15")); - } - - [Test] - public void ThrowsSyntaxErrorException() - { - try - { - ExpressionEvaluator.GetValue(null, "'date"); // unclose string literal - Assert.Fail(); - } - catch (RecognitionException ex) - { - Assert.AreEqual("Syntax Error on line 1, column 6: expecting ''', found '' in expression"+Environment.NewLine+"''date'", ex.Message); - } - } - - /// - /// Should throw exception for null root object - /// - [Test] - public void NullRoot() - { - Assert.Throws(() => ExpressionEvaluator.GetValue(null, "dummy.expression")); - } - - /// - /// Should throw exception for null root object - /// - [Test] - public void TryingToSetTheValueOfNonSettableNode() - { - Assert.Throws(() => ExpressionEvaluator.SetValue(null, "10", 5)); - } - - /// - /// Should return root itself for empty expression - /// - [Test] - public void GetNullOrEmptyExpression() - { - DateTime now = DateTime.Now; - Assert.AreEqual(ExpressionEvaluator.GetValue(now, null), now); - Assert.AreEqual(ExpressionEvaluator.GetValue(now, ""), now); - } - - /// - /// Should fail when setting value for the empty expression - /// - [Test] - public void SetNullOrEmptyExpression() - { - Assert.Throws(() => ExpressionEvaluator.SetValue("xyz", null, "abc")); - } - - /// - /// Tests null literal. - /// - [Test] - public void TestNullLiteral() - { - Assert.IsNull(ExpressionEvaluator.GetValue(null, "null")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "'xyz' == null")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "null != 'xyz'")); - } - - [Test] - public void TestUnicode() - { - Assert.AreEqual("\u6f22\u5b57", ExpressionEvaluator.GetValue(null, "'\u6f22\u5b57'")); - } - /// - /// Tests string literals. - /// - [Test] - public void TestStringLiterals() - { - Assert.AreEqual("literal string", ExpressionEvaluator.GetValue(null, "'literal string'")); - Assert.AreEqual("literal 'string", ExpressionEvaluator.GetValue(null, "'literal ''string'")); - Assert.AreEqual(string.Empty, ExpressionEvaluator.GetValue(null, "''")); - Assert.AreEqual("escaped \t string \n", ExpressionEvaluator.GetValue(null, "'escaped \t string \n'")); - //Debug.Write(ExpressionEvaluator.GetValue(null, "'escaped\tstring\nsecond line\n\nfourth line'")); - } - - /// - /// Tests integer literals. - /// - [Test] - public void TestIntLiterals() - { - object int32 = ExpressionEvaluator.GetValue(null, Int32.MaxValue.ToString()); - Assert.AreEqual(int32, Int32.MaxValue); - Assert.IsTrue(int32 is Int32); - Assert.AreEqual(32, ExpressionEvaluator.GetValue(null, "0x20")); - - Assert.AreEqual(Int64.MaxValue.ToString(), ExpressionEvaluator.GetValue(null, Int64.MaxValue.ToString() + ".ToString()")); - Assert.AreEqual(Int64.MaxValue.ToString(), ExpressionEvaluator.GetValue(null, "long.MaxValue.ToString()")); - - object int64 = ExpressionEvaluator.GetValue(null, Int64.MaxValue.ToString()); - Assert.AreEqual(int64, Int64.MaxValue); - Assert.IsTrue(int64 is Int64); - } - - /// - /// Tests hexadecimal integer literals. - /// - [Test] - public void TestHexLiterals() - { - IExpression exp = Expression.Parse("0x20"); - Assert.AreEqual(32, exp.GetValue()); - Assert.AreEqual(32, exp.GetValue()); - Assert.AreEqual(255, ExpressionEvaluator.GetValue(null, "0xFF")); - Assert.AreEqual(Int32.MaxValue, ExpressionEvaluator.GetValue(null, "0x7FFFFFFF")); - Assert.AreEqual(Int64.MaxValue, ExpressionEvaluator.GetValue(null, "0x7FFFFFFFFFFFFFFF")); - Assert.AreEqual(Int32.MinValue, ExpressionEvaluator.GetValue(null, "0x80000000")); - Assert.AreEqual(Int64.MinValue, ExpressionEvaluator.GetValue(null, "0x8000000000000000")); - } - - /// - /// Tests real literals. - /// - [Test] - public void TestRealLiterals() - { - IExpression exp = Expression.Parse("3.402823E+38"); - exp.GetValue(); - object s = exp.GetValue(); - object d = ExpressionEvaluator.GetValue(null, "1.797693E+308"); - object dec = ExpressionEvaluator.GetValue(null, "1000.00m"); - - - Assert.IsTrue(s is Double); - Assert.IsTrue(d is Double); - Assert.IsTrue(dec is Decimal); - - Assert.AreEqual(s, 3.402823E+38); - Assert.AreEqual(d, 1.797693E+308); - - Assert.AreEqual(5.25F, ExpressionEvaluator.GetValue(null, "5.25f")); - Assert.AreEqual(0.75d, ExpressionEvaluator.GetValue(null, "0.75D")); - - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "1000 == 1e3 and 1e+4 != 1000")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "100 < 1000.00m and 10000.00 > 1000")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "100 < 1000.00 and 10000.00m > 1e2")); - } - - /// - /// Tests boolean literals. - /// - [Test] - public void TestBooleanLiterals() - { - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "true")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "false")); - } - - /// - /// Tests date literals. - /// - [Test] - public void TestDateLiterals() - { - IExpression exp = Expression.Parse("date('1974/08/24')"); - Assert.AreEqual(new DateTime(1974, 8, 24), exp.GetValue()); - Assert.AreEqual(new DateTime(1974, 8, 24), exp.GetValue()); - Assert.AreEqual(new DateTime(1974, 8, 24), ExpressionEvaluator.GetValue(null, "date('1974-08-24')")); - Assert.AreEqual(new DateTime(1974, 8, 24), ExpressionEvaluator.GetValue(null, "date('08-24-1974', 'MM-dd-yyyy')")); - Assert.AreEqual(new DateTime(1974, 8, 24), ExpressionEvaluator.GetValue(null, "date('08/24/1974', 'MM/dd/yyyy')")); - Assert.AreEqual(new DateTime(1974, 8, 24, 12, 35, 6), ExpressionEvaluator.GetValue(null, "date('1974-08-24 12:35:06Z', 'u')")); - Assert.AreEqual(1974, ExpressionEvaluator.GetValue(null, "date('1974/08/24').Year")); - Assert.AreEqual(2005, ExpressionEvaluator.GetValue(null, "date('1974/08/24').AddYears(31).Year")); - } - - /// - /// Tests simple property and field accessors and mutators - /// - [Test] - public void TestSimplePropertyAccess() - { - Assert.AreEqual(DateTime.Today, ExpressionEvaluator.GetValue(null, "DateTime.Today")); - Assert.AreEqual("Nikola Tesla", ExpressionEvaluator.GetValue(tesla, "Name")); - Assert.AreEqual("Idvor", ExpressionEvaluator.GetValue(pupin, "PlaceOfBirth.City")); - ExpressionEvaluator.SetValue(tesla, "PlaceOfBirth.Country", "Croatia"); - Assert.AreEqual("Croatia", ExpressionEvaluator.GetValue(tesla, "PlaceOfBirth.Country")); - ExpressionEvaluator.SetValue(pupin, "Name", "Michael Pupin"); - Assert.AreEqual("Michael Pupin", ExpressionEvaluator.GetValue(pupin, "Name")); - Assert.AreEqual(new DateTime(1856, 7, 9), ExpressionEvaluator.GetValue(tesla, "DOB")); - Assert.AreEqual(1856, ExpressionEvaluator.GetValue(tesla, "DOB.Year")); - } - - /// - /// Tests that simple property and field accessors and mutators are case-insensitive. - /// - [Test] - public void SimplePropertyAccessIsCaseInsensitive() - { - Assert.AreEqual("Nikola Tesla", ExpressionEvaluator.GetValue(tesla, "nAme")); - Assert.AreEqual("Idvor", ExpressionEvaluator.GetValue(pupin, "Placeofbirth.city")); - ExpressionEvaluator.SetValue(tesla, "PlaceOfBirth.CountRY", "Croatia"); - Assert.AreEqual("Croatia", ExpressionEvaluator.GetValue(tesla, "Placeofbirth.COUNtry")); - ExpressionEvaluator.SetValue(pupin, "NAME", "Michael Pupin"); - Assert.AreEqual("Michael Pupin", ExpressionEvaluator.GetValue(pupin, "name")); - Assert.AreEqual(new DateTime(1856, 7, 9), ExpressionEvaluator.GetValue(tesla, "dob")); - Assert.AreEqual(1856, ExpressionEvaluator.GetValue(tesla, "DOb.YEar")); - } - - /// - /// Tests setting and getting shadowed properties - /// - [Test] - public void TestShadowedPropertyAccess() - { - ShadowingTestsMostSpezializedClass o; - - // test read - o = new ShadowingTestsMostSpezializedClass(); - o.SomeValue = "SomeString"; - Assert.AreEqual("SomeString", ExpressionEvaluator.GetValue(o, "SomeValue")); - - // test write - o = new ShadowingTestsMostSpezializedClass(); - ExpressionEvaluator.SetValue(o, "SomeValue", "SomeOtherString"); - Assert.AreEqual("SomeOtherString", o.SomeValue); - - // test readonly shadowed - o = new ShadowingTestsMostSpezializedClass(); - ((ShadowingTestsBaseClass)o).ReadonlyShadowedValue = "SomeString1"; - Assert.AreEqual("SomeString1", ExpressionEvaluator.GetValue(o, "ReadonlyShadowedValue")); - try - { - ExpressionEvaluator.SetValue(o, "ReadonlyShadowedValue", "SomeString2"); - Assert.Fail("Setting readonly property should throw NotWritablePropertyException"); - } - catch (NotWritablePropertyException) - { } - Assert.AreEqual("SomeString1", ExpressionEvaluator.GetValue(o, "ReadonlyShadowedValue")); - - // test writeonly shadowed - o = new ShadowingTestsMostSpezializedClass(); - ExpressionEvaluator.SetValue(o, "WriteonlyShadowedValue", "SomeString3"); - Assert.AreEqual("SomeString3", ((ShadowingTestsBaseClass)o).WriteonlyShadowedValue); - try - { - ExpressionEvaluator.GetValue(o, "WriteonlyShadowedValue"); - Assert.Fail("Getting writeonly property should throw NotReadablePropertyException"); - } - catch (NotReadablePropertyException) - { } - } - - /// - /// Tests indexed property and field accessors and mutators - /// - [Test] - public void TestIndexedPropertyAccess() - { - TypeRegistry.RegisterType("Society", typeof(Society)); - - // arrays and lists - Assert.AreEqual("Induction motor", ExpressionEvaluator.GetValue(tesla, "Inventions[3]")); - Assert.AreEqual("Nikola Tesla", ExpressionEvaluator.GetValue(ieee, "Members[0].Name")); - Assert.AreEqual("Wireless communication", ExpressionEvaluator.GetValue(ieee, "Members[0].Inventions[6]")); - - // maps - Assert.AreEqual(pupin, ExpressionEvaluator.GetValue(ieee, "Officers['president']")); - Assert.AreEqual("Idvor", ExpressionEvaluator.GetValue(ieee, "Officers['president'].PlaceOfBirth.City")); - Assert.AreEqual(tesla, ExpressionEvaluator.GetValue(ieee, "Officers['advisors'][0]")); - Assert.AreEqual("Polyphase alternating-current system", - ExpressionEvaluator.GetValue(ieee, "Officers['advisors'][0].Inventions[2]")); - - // maps with non-literal parameters - Dictionary vars = new Dictionary(); - vars["prez"] = "president"; - Assert.AreEqual(pupin, ExpressionEvaluator.GetValue(ieee, "Officers[#prez]", vars)); - - Assert.AreEqual(pupin, ExpressionEvaluator.GetValue(ieee, "Officers[Society.President]")); - Assert.AreEqual("Idvor", ExpressionEvaluator.GetValue(ieee, "Officers[Society.President].PlaceOfBirth.City")); - Assert.AreEqual(tesla, ExpressionEvaluator.GetValue(ieee, "Officers[Society.Advisors][0]")); - Assert.AreEqual("Polyphase alternating-current system", - ExpressionEvaluator.GetValue(ieee, "Officers[Society.Advisors][0].Inventions[2]")); - - // try to set some values - ExpressionEvaluator.SetValue(ieee, "Officers['advisors'][0].PlaceOfBirth.Country", "Croatia"); - Assert.AreEqual("Croatia", ExpressionEvaluator.GetValue(tesla, "PlaceOfBirth.Country")); - ExpressionEvaluator.SetValue(ieee, "Officers['president'].Name", "Michael Pupin"); - Assert.AreEqual("Michael Pupin", ExpressionEvaluator.GetValue(pupin, "Name")); - ExpressionEvaluator.SetValue(ieee, "Officers['advisors']", new Inventor[] { pupin, tesla }); - Assert.AreEqual(pupin, ExpressionEvaluator.GetValue(ieee, "Officers['advisors'][0]")); - Assert.AreEqual(tesla, ExpressionEvaluator.GetValue(ieee, "Officers['advisors'][1]")); - - // generic indexer - Bar bar = new Bar(); - Foo foo = new Foo(); - IExpression exp = Expression.Parse("[1]"); - Assert.AreEqual(2, exp.GetValue(bar)); - Assert.AreEqual(2, exp.GetValue(bar)); - Assert.AreEqual("test_1", ExpressionEvaluator.GetValue(foo, "[1, 'test']")); - } - - /// - /// Tests indexer access with invalid number of indices - /// - [Test] - public void TestIndexedPropertyAccessWithInvalidNumberOfIndices() - { - Assert.Throws(() => ExpressionEvaluator.GetValue(tesla, "Inventions[3, 2]")); - } - - /// - /// Tests method accessors - /// - [Test] - public void TestMethodAccess() - { - Guid guid = Guid.NewGuid(); - - TypeRegistry.RegisterType("Guid", typeof(Guid)); - Assert.AreEqual(guid.ToString(), ExpressionEvaluator.GetValue(guid, "ToString()")); - Assert.AreEqual(guid.ToString("n"), ExpressionEvaluator.GetValue(guid, "ToString('n')")); - Assert.AreEqual(16, ExpressionEvaluator.GetValue(null, "Guid.NewGuid().ToByteArray().Length")); - - Assert.AreEqual(2005 - tesla.DOB.Year, - ExpressionEvaluator.GetValue(ieee, "Members[0].GetAge(date('2005-01-01'))")); - } - - [Test] - public void TestMethodEvaluationOnDifferentContextType() - { - IExpression expression = Expression.Parse("ToString('dummy', null)"); - Assert.AreEqual("dummy", expression.GetValue(0m, null)); - Assert.AreEqual("dummy", expression.GetValue(0, null)); - } - - [Test] - public void TestMethodEvaluationOnDifferentArgumentTypes() - { - IExpression expression = Expression.Parse("Foo(#var1)"); - MethodInvokationCases testContext = new MethodInvokationCases(); - Dictionary args = new Dictionary(); - args["var1"] = "myString"; - Assert.AreEqual("myString", expression.GetValue(testContext, args)); - args["var1"] = 12; - Assert.AreEqual(12, expression.GetValue(testContext, args)); - } - - /// - /// Tests missing method accessors - /// - [Test] - public void TestMissingMethodAccess() - { - Assert.Throws(() => ExpressionEvaluator.GetValue("xyz", "ToStringilyLingily()")); - } - - /// - /// Tests projection node - /// - [Test] - public void TestProjection() - { - IList placesOfBirth = (IList)ExpressionEvaluator.GetValue(ieee, "Members.!{PlaceOfBirth.City}"); - - Assert.AreEqual(2, placesOfBirth.Count); - Assert.AreEqual("Smiljan", placesOfBirth[0]); - Assert.AreEqual("Idvor", placesOfBirth[1]); - - IList names = (IList)ExpressionEvaluator.GetValue(ieee, "Officers['advisors'].!{Name}"); - Assert.AreEqual(2, names.Count); - Assert.AreEqual("Nikola Tesla", names[0]); - Assert.AreEqual("Mihajlo Pupin", names[1]); - } - - /// - /// Tests selection node - /// - [Test] - public void TestSelection() - { - IList memberSelection = - (IList)ExpressionEvaluator.GetValue(ieee, "Members.?{PlaceOfBirth.City == 'Smiljan'}"); - - Assert.AreEqual(1, memberSelection.Count); - Assert.AreEqual("Nikola Tesla", ((Inventor)memberSelection[0]).Name); - - IList serbianOfficers = - (IList)ExpressionEvaluator.GetValue(ieee, "Officers['advisors'].?{Nationality == 'Serbian'}"); - Assert.AreEqual(2, serbianOfficers.Count); - Assert.AreEqual("Nikola Tesla", ((Inventor)serbianOfficers[0]).Name); - Assert.AreEqual("Mihajlo Pupin", ((Inventor)serbianOfficers[1]).Name); - - Inventor first = - (Inventor)ExpressionEvaluator.GetValue(ieee, "Officers['advisors'].^{Nationality == 'Serbian'}"); - Assert.AreEqual("Nikola Tesla", first.Name); - - Inventor last = - (Inventor)ExpressionEvaluator.GetValue(ieee, "Officers['advisors'].${Nationality == 'Serbian'}"); - Assert.AreEqual("Mihajlo Pupin", last.Name); - } - - /// - /// Tests type node - /// - [Test] - public void TestTypeNode() - { - IExpression exp = Expression.Parse("T(DateTime)"); - exp.GetValue(); - Assert.AreEqual(typeof(DateTime), exp.GetValue()); - - Assert.AreEqual(typeof(DateTime), ExpressionEvaluator.GetValue(null, "T(System.DateTime)")); - Assert.AreEqual(typeof(DateTime[]), ExpressionEvaluator.GetValue(null, "T(System.DateTime[], mscorlib)")); - Assert.AreEqual(typeof(ExpressionEvaluator), ExpressionEvaluator.GetValue(null, "T(Spring.Expressions.ExpressionEvaluator, Spring.Core)")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(tesla, "T(System.DateTime) == DOB.GetType()")); - } - - /// - /// Tests type node - /// - [Test] - public void TestTypeNodeWithArrays() - { - Assert.AreEqual(typeof(DateTime[]), ExpressionEvaluator.GetValue(null, "T(System.DateTime[])")); - Assert.AreEqual(typeof(DateTime[,]), ExpressionEvaluator.GetValue(null, "T(System.DateTime[,])")); - Assert.AreEqual(typeof(DateTime[]), ExpressionEvaluator.GetValue(null, "T(System.DateTime[], mscorlib)")); - Assert.AreEqual(typeof(DateTime[,]), ExpressionEvaluator.GetValue(null, "T(System.DateTime[,], mscorlib)")); - } - - /// - /// Tests type node - /// - [Test] - public void TestTypeNodeWithAssemblyQualifiedName() - { - Assert.AreEqual(typeof(ExpressionEvaluator), ExpressionEvaluator.GetValue(null, string.Format("T({0})", typeof(ExpressionEvaluator).AssemblyQualifiedName))); - } - - /// - /// Tests type node - /// - [Test] - public void TestTypeNodeWithGenericAssemblyQualifiedName() - { -// Assert.AreEqual(typeof(int?), ExpressionEvaluator.GetValue(null, "T(System.Nullable`1[System.Int32], mscorlib)")); -// Assert.AreEqual(typeof(int?), ExpressionEvaluator.GetValue(null, "T(System.Nullable`1[[System.Int32, mscorlib]], mscorlib)")); - Assert.AreEqual(typeof(int?), ExpressionEvaluator.GetValue(null, "T(System.Nullable`1[[int]], mscorlib)")); - Assert.AreEqual(typeof(System.Collections.Generic.Dictionary), ExpressionEvaluator.GetValue(null, "T(System.Collections.Generic.Dictionary`2[System.String,System.Boolean],mscorlib)")); - } - - [Test] - public void TestGenericDictionary() - { - ExpressionEvaluator.GetValue(null, - "T(System.Collections.Generic.Dictionary`2[System.String,System.Boolean],mscorlib)"); - } - - /// - /// Tests type node - /// - [Test] - public void TestTypeNodeWithAliasedGenericArguments() - { - Assert.AreEqual(typeof(System.Collections.Generic.Dictionary), ExpressionEvaluator.GetValue(null, "T(System.Collections.Generic.Dictionary`2[string,bool],mscorlib)")); - } - - /// - /// Tests type node - /// - [Test] - public void TestTypeNodeWithGenericAssemblyQualifiedArrayName() - { - Assert.AreEqual(typeof(int?[,]), ExpressionEvaluator.GetValue(null, "T(System.Nullable`1[[System.Int32, mscorlib]][,], mscorlib)")); - } - - /// - /// Tests constructor node - /// - [Test] - public void TestConstructor() - { - TypeRegistry.RegisterType(typeof(Inventor)); - - IExpression exp = Expression.Parse("new System.DateTime(2004, 8, 14)"); - Assert.AreEqual(1000, ExpressionEvaluator.GetValue(null, "new Decimal(1000)")); - Assert.AreEqual(new DateTime(2004, 8, 14), exp.GetValue(null)); - Assert.AreEqual(new DateTime(2004, 8, 14), exp.GetValue("xyz")); - Assert.AreEqual(new DateTime(1974, 8, 24), - ExpressionEvaluator.GetValue(null, "new DateTime(2004, 8, 14).AddDays(10).AddYears(-30)")); - - // test named arguments - Inventor ana = - (Inventor) - ExpressionEvaluator.GetValue(null, - "new Inventor(Name = 'Ana Maria Seovic', DOB = date('2004-08-14'), Nationality = 'American')"); - Assert.AreEqual("Ana Maria Seovic", ana.Name); - Assert.AreEqual(new DateTime(2004, 8, 14), ana.DOB); - Assert.AreEqual("American", ana.Nationality); - - Inventor aleks = - (Inventor) - ExpressionEvaluator.GetValue(null, - "new Inventor('Aleksandar Seovic', date('1974-08-24'), 'Serbian', Inventions = {'SPELL'})"); - Assert.AreEqual("Aleksandar Seovic", aleks.Name); - Assert.AreEqual(new DateTime(1974, 8, 24), aleks.DOB); - Assert.AreEqual("Serbian", aleks.Nationality); - Assert.AreEqual(1, aleks.Inventions.Length); - Assert.AreEqual("SPELL", aleks.Inventions[0]); - } - - /// - /// Tests missing constructor - /// - [Test] - public void TestMissingConstructor() - { - Assert.Throws(() => ExpressionEvaluator.GetValue(null, "new Decimal('xyz')")); - } - - /// - /// Tests expression list node - /// - [Test] - public void TestExpressionList() - { - TypeRegistry.RegisterType("Inventor", typeof(Inventor)); - Assert.AreEqual(3, - ExpressionEvaluator.GetValue(ieee.Members, - "(Add(new Inventor('Aleksandar Seovic', date('1974-08-24'), 'Serbian')); Count)")); - Assert.AreEqual(3, - ExpressionEvaluator.GetValue(ieee, - "Members.(Add(new Inventor('Ana Maria Seovic', date('2004-08-14'), 'Serbian')); RemoveAt(1); Count)")); - Assert.AreEqual("Aleksandar Seovic", - ExpressionEvaluator.GetValue(ieee.Members, - "([1].PlaceOfBirth.City = 'Beograd'; [1].PlaceOfBirth.Country = 'Serbia'; [1].Name)")); - Assert.AreEqual("Beograd", ((Inventor)ieee.Members[1]).PlaceOfBirth.City); - } - - /// - /// Tests assignment node - /// - [Test] - public void TestAssignNode() - { - Inventor inventor = new Inventor(); - Assert.AreEqual("Aleksandar Seovic", ExpressionEvaluator.GetValue(inventor, "Name = 'Aleksandar Seovic'")); - Assert.AreEqual(new DateTime(1974, 8, 24), - ExpressionEvaluator.GetValue(inventor, "DOB = date('1974-08-24')")); - Assert.AreEqual("Serbian", ExpressionEvaluator.GetValue(inventor, "Nationality = 'Serbian'")); - Assert.AreEqual("Ana Maria Seovic", - ExpressionEvaluator.GetValue(inventor, - "(DOB = date('2004-08-14'); Name = 'Ana Maria Seovic')")); - Assert.AreEqual(new DateTime(2004, 8, 14), inventor.DOB); - ExpressionEvaluator.GetValue(ieee, "Officers['vp'] = Members[0]"); - Assert.AreEqual("Nikola Tesla", ((Inventor)ieee.Officers["vp"]).Name); - } - - /// - /// Tests default node - /// - [Test] - public void TestDefaultNode() - { - Assert.AreEqual("default", ExpressionEvaluator.GetValue(null, "null ?? 'default'")); - Assert.AreEqual(1, ExpressionEvaluator.GetValue(null, "null ?? 2 * 2 - 3")); - Assert.AreEqual("Nikola Tesla", ExpressionEvaluator.GetValue(tesla, "null ?? #root.Name")); - - Assert.AreEqual("default", ExpressionEvaluator.GetValue(null, "'default' ?? 'xyz'")); - Assert.AreEqual(1, ExpressionEvaluator.GetValue(null, "2 * 2 - 3 ?? 5")); - Assert.AreEqual("Nikola Tesla", ExpressionEvaluator.GetValue(tesla, "#root.Name ?? 'Pupin'")); - } - - /// - /// Tests variable node - /// - [Test] - public void TestVariableNode() - { - Dictionary vars = new Dictionary(); - vars["newName"] = "Aleksandar Seovic"; - Assert.AreEqual("Ana Maria Seovic", - ExpressionEvaluator.GetValue(null, "#newName = 'Ana Maria Seovic'", vars)); - Assert.AreEqual("Ana Maria Seovic", ExpressionEvaluator.GetValue(tesla, "Name = #newName", vars)); - Assert.AreEqual("Nikola Tesla", - ExpressionEvaluator.GetValue(tesla, "(#oldName = Name; Name = 'Nikola Tesla')", vars)); - Assert.AreEqual("Nikola Tesla", ((Inventor)ExpressionEvaluator.GetValue(tesla, "#this", vars)).Name); - Assert.AreEqual("Nikola Tesla", - ExpressionEvaluator.GetValue(tesla, "(Nationality = 'Srbin'; #this).Name", vars)); - Assert.AreEqual("Nikola Tesla", tesla.Name); - Assert.AreEqual("Srbin", tesla.Nationality); - Assert.AreEqual("Ana Maria Seovic", vars["oldName"]); - Assert.AreEqual(tesla, ExpressionEvaluator.GetValue(tesla, "#root", vars)); - } - - - /// - /// Try to set 'this' variable - /// - [Test] - public void TryToSetThis() - { - Assert.Throws(() => ExpressionEvaluator.SetValue(null, "#this", "xyz")); - } - - /// - /// Try to set 'root' variable - /// - [Test] - public void TryToSetRoot() - { - Assert.Throws(() => ExpressionEvaluator.SetValue(null, "#root", "xyz")); - } - - /// - /// Tests ternary node - /// - [Test] - public void TestTernaryNode() - { - IExpression exp = Expression.Parse("true ? 'trueExp' : 'falseExp'"); - exp.GetValue(); - - Assert.AreEqual("trueExp", exp.GetValue()); - Assert.AreEqual("falseExp", ExpressionEvaluator.GetValue(null, "false ? 'trueExp' : 'falseExp'")); - Assert.AreEqual("trueExp", ExpressionEvaluator.GetValue(null, "(true ? 'trueExp' : 'falseExp')")); - Assert.AreEqual("falseExp", ExpressionEvaluator.GetValue(null, "(false ? 'trueExp' : 'falseExp')")); - - ExpressionEvaluator.SetValue(ieee, "Name", "IEEE"); - Dictionary vars = new Dictionary(); - vars["queryName"] = "Nikola Tesla"; - string expression = - @"IsMember(#queryName) - ? #queryName + ' is a member of the ' + Name + ' Society' - : #queryName + ' is not a member of ' + Name + ' Society'"; - Assert.AreEqual("Nikola Tesla is a member of the IEEE Society", - ExpressionEvaluator.GetValue(ieee, expression, vars)); - } - - /// - /// Tests logical OR operator - /// - [Test] - public void TestLogicalOrOperator() - { - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "true or true")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "false or false")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "true or false")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "false or true")); - string expression = @"IsMember('Nikola Tesla') or IsMember('Albert Einstien')"; - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(ieee, expression)); - } - - /// - /// Tests bitwise OR operator - /// - [Test] - public void TestBitwiseOrOperator() - { - Assert.AreEqual( 1 | 2, ExpressionEvaluator.GetValue(null, "1 or 2")); - Assert.AreEqual( 1 | -2, ExpressionEvaluator.GetValue(null, "1 or -2")); - Assert.AreEqual(RegexOptions.IgnoreCase | RegexOptions.Compiled, ExpressionEvaluator.GetValue(null, "T(System.Text.RegularExpressions.RegexOptions).IgnoreCase or T(System.Text.RegularExpressions.RegexOptions).Compiled")); - } - - /// - /// Tests logical AND operator - /// - [Test] - public void TestLogicalAndOperator() - { - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "true and true")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "false and false")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "true and false")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "false and true")); - string expression = @"IsMember('Nikola Tesla') and IsMember('Mihajlo Pupin')"; - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(ieee, expression)); - } - - /// - /// Tests bitwise OR operator - /// - [Test] - public void TestBitwiseAndOperator() - { - Assert.AreEqual(1 & 3, ExpressionEvaluator.GetValue(null, "1 and 3")); - Assert.AreEqual(1 & -1, ExpressionEvaluator.GetValue(null, "1 and -1")); - Dictionary vars = new Dictionary(); - vars["ALL"] = (RegexOptions) 0xFFFF; - Assert.AreEqual(RegexOptions.IgnoreCase, ExpressionEvaluator.GetValue(null, "T(System.Text.RegularExpressions.RegexOptions).IgnoreCase and #ALL", vars)); - } - - /// - /// Tests logical NOT operator - /// - [Test] - public void TestLogicalNotOperator() - { - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "!true")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "!false")); - string expression = @"IsMember('Nikola Tesla') and !IsMember('Mihajlo Pupin')"; - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(ieee, expression)); - Assert.AreEqual( ~RegexOptions.Compiled, ExpressionEvaluator.GetValue(null, "!T(System.Text.RegularExpressions.RegexOptions).Compiled")); - } - - /// - /// Tests bitwise OR operator - /// - [Test] - public void TestXorOperator() - { - Assert.AreEqual(1 ^ 3, ExpressionEvaluator.GetValue(null, "1 xor 3")); - Assert.AreEqual(1 ^ -1, ExpressionEvaluator.GetValue(null, "1 xor -1")); - Assert.AreEqual(true ^ false, ExpressionEvaluator.GetValue(null, "true xor false")); - Assert.AreEqual(true ^ true, ExpressionEvaluator.GetValue(null, "true xor true")); - Assert.AreEqual(RegexOptions.IgnoreCase ^ RegexOptions.Compiled, ExpressionEvaluator.GetValue(null, "T(System.Text.RegularExpressions.RegexOptions).IgnoreCase xor T(System.Text.RegularExpressions.RegexOptions).Compiled")); - } - - /// - /// Tests logical operator presedance - /// - [Test] - public void TestLogicalOperatorPresedance() - { - // NOT over AND - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "!false and false")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "!false and true")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "!true and false")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "!true and true")); - - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "!(false and false)")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "!(false and true)")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "!(true and false)")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "!(true and true)")); - - // NOT over OR - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "!false or false")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "!false or true")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "!true or false")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "!true or true")); - - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "!(false or false)")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "!(false or true)")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "!(true or false)")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "!(true or true)")); - - // AND over OR - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "false and false or false")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "false and false or true")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "false and true or false")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "false and true or true")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "true and false or false")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "true and false or true")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "true and true or false")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "true and true or true")); - - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "false and (false or false)")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "false and (false or true)")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "false and (true or false)")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "false and (true or true)")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "true and (false or false)")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "true and (false or true)")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "true and (true or false)")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "true and (true or true)")); - } - - /// - /// Tests equality operator. - /// - [Test] - public void TestEqualityOperator() - { - // Null - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "null == null")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "null == 'xyz'")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "123 == null")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "null == 123")); - - // Bool - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "false == false")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "true == true")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "false == true")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "true == false")); - - // Int - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "2 == 2")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "-5 == -5")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "2 == -5")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "-5 == 2")); - - // String - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "'test' == 'test'")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "'Test' == 'test'")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "'test' == 'Test'")); - - // DateTime - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "date('1974-08-24') == date('1974-08-24')")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "DateTime.Today == DateTime.Today")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "DateTime.Today == date('1974-08-24')")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "date('1974-08-24') == DateTime.Today")); - - // Enums - Foo foo = new Foo(FooType.One); - TypeRegistry.RegisterType("FooType", typeof(FooType)); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(foo, "Type == FooType.One")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(foo, "Type == 'One'")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(foo, "Type == 'Two'")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(foo, "FooType.One == Type")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(foo, "'One' == Type")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(foo, "'Two' == Type")); - } - - /// - /// Tests inequality operator. - /// - [Test] - public void TestInqualityOperator() - { - // Null - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "null != null")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "123 != null")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "null != 'xyz'")); - - // Bool - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "false != false")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "true != true")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "false != true")); - - // Int - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "2 != 2.0")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "-5.0 != -5")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "2.0 != -5")); - - // String - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "'test' != 'test'")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "'Test' != 'test'")); - - // DateTime - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "date('1974-08-24') != date('1974-08-24')")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "DateTime.Today != DateTime.Today")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "DateTime.Today != date('1974-08-24')")); - } - - /// - /// Tests less than operator. - /// - [Test] - public void TestLessThanOperator() - { - // Null - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "null < null")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "123 < null")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "null < 'xyz'")); - - // Bool - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "false < true")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "true < true")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "true < false")); - - // Int - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "2 < 2.0")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "-5.0 < 2")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "2 < -5.0")); - - // String - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "'test' < 'test'")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "'Test' < 'test'")); - - // DateTime - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "date('1974-08-24') < date('1974-08-24')")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "date('1974-08-24') < DateTime.Today")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "DateTime.Today < date('1974-08-24')")); - } - - /// - /// Tests less than or equal operator. - /// - [Test] - public void TestLessThanOrEqualOperator() - { - // Null - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "null <= null")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "123 <= null")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "null <= 'xyz'")); - - // Bool - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "false <= true")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "true <= true")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "true <= false")); - - // Int - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "2 <= 2.0")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "-5.0 <= 2")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "2.0 <= -5")); - - // String - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "'test' <= 'test'")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "'Test' <= 'test'")); - - // DateTime - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "date('1974-08-24') <= date('1974-08-24')")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "date('1974-08-24') <= DateTime.Today")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "DateTime.Today <= date('1974-08-24')")); - } - - /// - /// Tests greater than operator. - /// - [Test] - public void TestGreaterThanOperator() - { - // Null - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "null > null")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "123 > null")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "null > 'xyz'")); - - // Bool - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "false > true")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "true > true")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "true > false")); - - // Int - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "2 > 2.0")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "-5.0 > 2")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "2 > -5.0")); - - // String - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "'test' > 'test'")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "'Test' > 'test'")); - - // DateTime - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "date('1974-08-24') > date('1974-08-24')")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "date('1974-08-24') > DateTime.Today")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "DateTime.Today > date('1974-08-24')")); - } - - /// - /// Tests greater than or equal operator. - /// - [Test] - public void TestGreaterThanOrEqualOperator() - { - // Null - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "null >= null")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "123 >= null")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "null >= 'xyz'")); - - // Bool - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "false >= true")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "true >= true")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "true >= false")); - - // Int - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "2.0 >= 2")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "-5 >= 2.0")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "2.0 >= -5")); - - // String - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "'test' >= 'test'")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "'Test' >= 'test'")); - - // DateTime - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "date('1974-08-24') >= date('1974-08-24')")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "date('1974-08-24') >= DateTime.Today")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "DateTime.Today >= date('1974-08-24')")); - } - - /// - /// Tests IN operator. - /// - [Test] - public void TestInOperator() - { - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "null in null")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "3 in {1, 2, 3, 4, 5}")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "!(3 in {1, 2, 3, 4, 5})")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "'xyz' in new string[] {'abc', 'xyz'}")); - Assert.IsTrue( - (bool)ExpressionEvaluator.GetValue(null, "'xyz' in #{'abc' : 'Value 1', 'xyz' : DateTime.Today}")); - } - - /// - /// Tests IS operator. - /// - [Test] - public void TestIsOperator() - { - TypeRegistry.RegisterType(typeof(IList)); - TypeRegistry.RegisterType(typeof(IDictionary)); - - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "null is null")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "5 is null")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "null is int")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "5 is int")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "!(5 is int)")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "{1, 2, 3, 4, 5} is IList")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "new string[] {'abc', 'xyz'} is T(string[])")); - Assert.IsTrue( - (bool)ExpressionEvaluator.GetValue(null, "#{'abc' : 'Value 1', 'xyz' : DateTime.Today} is IDictionary")); - } - - /// - /// Tests BETWEEN operator. - /// - [Test] - public void TestBetweenOperator() - { - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "null between {1, 5}")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "0 between {1, 5}")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "1 between {1, 5}")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "3 between {1, 5}")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "5 between {1, 5}")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "6 between {1, 5}")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "!(6 between {1, 5})")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "'efg' between {'abc', 'xyz'}")); - Assert.IsTrue( - (bool)ExpressionEvaluator.GetValue(null, "DateTime.Today between {DateTime.Today, DateTime.Now}")); - Assert.IsFalse( - (bool)ExpressionEvaluator.GetValue(null, "DateTime.Today between {DateTime.Now, DateTime.Now}")); - } -#if !MONO - /// - /// Tests LIKE operator. - /// - [Test] - public void TestLikeOperator() - { - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "'A' like '?'")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "'Abc' like '?'")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "'Abc' like '[A-Z]b?'")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "'Abc' like '*'")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "'Aleksandar' like 'Aleks*'")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "'Ana Maria Seovic' like '*Maria*'")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "'Marija Seovic' like '*Seovic'")); - } -#endif - /// - /// Tests MATCHES operator. - /// - [Test] - public void TestMatchesOperator() - { - string emailCheck = - @"^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$"; - - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(emailCheck, "'A' matches #this")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(emailCheck, "'aleks@seovic.com' matches #this")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(emailCheck, "'@seovic.com' matches #this")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(emailCheck, "'seovic.com' matches #this")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(emailCheck, "'aleks' matches #this")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(emailCheck, "'aleks@' matches #this")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(emailCheck, "'aleks@seovic' matches #this")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "'5.0067' matches '^-?\\d+(\\.\\d{2})?$'")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, @"'5.00' matches '^-?\d+(\.\d{2})?$'")); - } - - /// - /// Type coercion failure. - /// - [Test] - public void TestTypeCoercionForUncoercableTypes() - { - Assert.Throws(() => ExpressionEvaluator.GetValue(null, "'xyz' > 123")); - } - - /// - /// Type comparison failure. - /// - [Test] - public void TestComparisonOfInstancesThatDoNotImplementIComparable() - { - Dictionary vars = new Dictionary(); - vars["tesla"] = tesla; - vars["pupin"] = pupin; - Assert.Throws(() => ExpressionEvaluator.GetValue(null, "#tesla > #pupin", vars)); - } - - /// - /// Tests addition operator. - /// - [Test] - public void TestAddOperator() - { - // numbers - Assert.AreEqual(2, ExpressionEvaluator.GetValue(null, "1 + 1")); - Assert.AreEqual(2, ExpressionEvaluator.GetValue(null, "1e0 + 1")); - Assert.AreEqual(0, ExpressionEvaluator.GetValue(null, "-1e0 + 1")); - Assert.AreEqual(-2, ExpressionEvaluator.GetValue(null, "-1e0 + -1")); - Assert.AreEqual(Decimal.Parse("2.0", NumberFormatInfo.InvariantInfo), - ExpressionEvaluator.GetValue(null, "1.0m + 1.0")); - Assert.AreEqual(9, ExpressionEvaluator.GetValue(null, "2.0 + 3e0 + 4")); - - // strings - Assert.AreEqual("test string", ExpressionEvaluator.GetValue(null, "'test' + ' ' + 'string'")); - Assert.AreEqual("test 2", ExpressionEvaluator.GetValue(null, "'test' + ' ' + 2")); - Assert.AreEqual("test " + DateTime.Today.ToString(), - ExpressionEvaluator.GetValue(null, "'test' + ' ' + DateTime.Today")); - Assert.AreEqual("test", ExpressionEvaluator.GetValue(null, "'test' + #this")); // can concat null - Assert.AreEqual("test", ExpressionEvaluator.GetValue(null, "#this+'test'")); // can concat null - - // dates - DateTime anaDOB = new DateTime(2004, 8, 14); - DateTime aleksDOB = new DateTime(1974, 8, 24); - TimeSpan diff = anaDOB - aleksDOB; - IDictionary vars = new Dictionary(); - vars["ts"] = diff; - - Assert.AreEqual(anaDOB, ExpressionEvaluator.GetValue(null, "date('1974-08-24') + #ts", vars)); - Assert.AreEqual(new DateTime(1974, 8, 29), ExpressionEvaluator.GetValue(null, "date('1974-08-24') + 5")); - Assert.AreEqual(new DateTime(1974, 8, 29), - ExpressionEvaluator.GetValue(null, "date('1974-08-24') + '5.0:0'")); - } - - /// - /// Tests addition operator with invalid arguments. - /// - [Test] - public void TestAddOperatorWithInvalidArguments() - { - Assert.Throws(() => ExpressionEvaluator.GetValue(null, "DateTime.Today + false")); - } - - /// - /// Tests subtraction operator. - /// - [Test] - public void TestSubtractOperator() - { - // numbers - Assert.AreEqual(2, ExpressionEvaluator.GetValue(null, "3 - 1")); - Assert.AreEqual(-2, ExpressionEvaluator.GetValue(null, "1 - 3")); - Assert.AreEqual(4, ExpressionEvaluator.GetValue(null, "1 - -3")); - Assert.AreEqual(Decimal.Parse("-9000.00", NumberFormatInfo.InvariantInfo), - ExpressionEvaluator.GetValue(null, "1000.00m - 1e4")); - Assert.AreEqual(-5, ExpressionEvaluator.GetValue(null, "2.0 - 3e0 - 4")); - - // dates - DateTime anaDOB = new DateTime(2004, 8, 14); - DateTime aleksDOB = new DateTime(1974, 8, 24); - TimeSpan diff = anaDOB - aleksDOB; - Dictionary vars = new Dictionary(); - vars["ts"] = diff; - - Assert.AreEqual(aleksDOB, ExpressionEvaluator.GetValue(null, "date('2004-08-14') - #ts", vars)); - Assert.AreEqual(diff, ExpressionEvaluator.GetValue(null, "date('2004-08-14') - date('1974-08-24')")); - Assert.AreEqual(new DateTime(1974, 8, 19), ExpressionEvaluator.GetValue(null, "date('1974-08-24') - 5")); - Assert.AreEqual(new DateTime(1974, 8, 19), - ExpressionEvaluator.GetValue(null, "date('1974-08-24') - '5.0:0'")); - } - - /// - /// Tests subtraction operator with invalid arguments. - /// - [Test] - public void TestSubtractOperatorWithInvalidArguments() - { - Assert.Throws(() => ExpressionEvaluator.GetValue(null, "DateTime.Today - false")); - } - - /// - /// Tests multiplication operator. - /// - [Test] - public void TestMultiplyOperator() - { - Assert.AreEqual(4, ExpressionEvaluator.GetValue(null, "2 * 2")); - Assert.AreEqual(-6, ExpressionEvaluator.GetValue(null, "2 * -3")); - Assert.AreEqual(6, ExpressionEvaluator.GetValue(null, "-2 * -3")); - Assert.AreEqual(Decimal.Parse("1000000.00", NumberFormatInfo.InvariantInfo), - ExpressionEvaluator.GetValue(null, "1000.00m * 1e3")); - Assert.AreEqual(24, ExpressionEvaluator.GetValue(null, "2.0 * 3e0 * 4")); - } - - /// - /// Tests multiplication operator with invalid arguments. - /// - [Test] - public void TestMultiplyOperatorWithInvalidArguments() - { - Assert.Throws(() => ExpressionEvaluator.GetValue(null, "DateTime.Today * false")); - } - - /// - /// Tests division operator. - /// - [Test] - public void TestDivideOperator() - { - Assert.AreEqual(1, ExpressionEvaluator.GetValue(null, "2 / 2")); - Assert.AreEqual(-2, ExpressionEvaluator.GetValue(null, "6 / -3")); - Assert.AreEqual(2, ExpressionEvaluator.GetValue(null, "-6 / -3")); - Assert.AreEqual(Decimal.Parse("1.00", NumberFormatInfo.InvariantInfo), - ExpressionEvaluator.GetValue(null, "1000.00m / 1e3")); - Assert.AreEqual(1, ExpressionEvaluator.GetValue(null, "8.0 / 4e0 / 2")); - } - - /// - /// Tests division operator with invalid arguments. - /// - [Test] - public void TestDivideOperatorWithInvalidArguments() - { - Assert.Throws(() => ExpressionEvaluator.GetValue(null, "DateTime.Today / false")); - } - - /// - /// Tests modulus operator. - /// - [Test] - public void TestModulusOperator() - { - Assert.AreEqual(0, ExpressionEvaluator.GetValue(null, "2 % 2")); - Assert.AreEqual(2, ExpressionEvaluator.GetValue(null, "6 % -4")); - Assert.AreEqual(-1, ExpressionEvaluator.GetValue(null, "-6 % -5")); - Assert.AreEqual(Decimal.Parse("5.00", NumberFormatInfo.InvariantInfo), - ExpressionEvaluator.GetValue(null, "1005.00m % 1e3")); - Assert.AreEqual(1, ExpressionEvaluator.GetValue(null, "8.0 % 5e0 % 2")); - } - - /// - /// Tests modulus operator with invalid arguments. - /// - [Test] - public void TestModulusOperatorWithInvalidArguments() - { - Assert.Throws(() => ExpressionEvaluator.GetValue(null, "DateTime.Today % false")); - } - - /// - /// Tests power operator. - /// - [Test] - public void TestPowerOperator() - { - Assert.AreEqual(8, ExpressionEvaluator.GetValue(null, "2 ^ +3")); - Assert.AreEqual(16, ExpressionEvaluator.GetValue(null, "-2 ^ 4")); - Assert.AreEqual(-32, ExpressionEvaluator.GetValue(null, "-2 ^ 5")); - Assert.AreEqual(.0625, ExpressionEvaluator.GetValue(null, "4 ^ -2")); - Assert.AreEqual(2, ExpressionEvaluator.GetValue(null, "+4 ^ .5")); - } - - /// - /// Tests power operator with invalid arguments. - /// - [Test] - public void TestPowerOperatorWithInvalidArguments() - { - Assert.Throws(() => ExpressionEvaluator.GetValue(null, "DateTime.Today ^ false")); - } - - /// - /// Tests unary minus operator with invalid argument. - /// - [Test] - public void TestUnaryMinusOperatorWithInvalidArguments() - { - Assert.Throws(() => ExpressionEvaluator.GetValue(null, "-false")); - } - - /// - /// Tests unary plus operator with invalid argument. - /// - [Test] - public void TestUnaryPlusOperatorWithInvalidArguments() - { - Assert.Throws(() => ExpressionEvaluator.GetValue(null, "+false")); - } - - /// - /// Tests operator precedence. - /// - [Test] - public void TestOperatorPrecedence() - { - Assert.AreEqual(-3, ExpressionEvaluator.GetValue(null, "1+2-3*8/2/2")); - Assert.AreEqual(-45, ExpressionEvaluator.GetValue(null, "1+2-3*8^2/2/2")); - Assert.AreEqual(0, ExpressionEvaluator.GetValue(null, "1+2-3*8/2^2/2")); - Assert.AreEqual(-4.5, ExpressionEvaluator.GetValue(null, "1+(2-3*8)/2.0/2")); - } - - /// - /// Tests Spring reference when reference to a non-existant object is specified. - /// - [Test] - public void TestReferenceForNonExistantObject() - { - ContextRegistry.RegisterContext(new XmlApplicationContext(false, "assembly://Spring.Core.Tests/Spring.Context.Support/objects.xml")); - Assert.Throws(() => ExpressionEvaluator.GetValue(null, "@(dummyRef)")); - } - - /// - /// Tests Spring reference. - /// - [Test] - public void TestReference() - { - ContextRegistry.RegisterContext( - new XmlApplicationContext(false, "assembly://Spring.Core.Tests/Spring.Context.Support/objects.xml")); - Assert.AreEqual(typeof(TestObject), ExpressionEvaluator.GetValue(null, "@(goran)").GetType()); - - IApplicationContext ctx = - new XmlApplicationContext(false, "assembly://Spring.Core.Tests/Spring.Context.Support/objects.xml"); - ctx.Name = "myContext"; - ContextRegistry.RegisterContext(ctx); - - Assert.AreEqual(typeof(TestObject), - ExpressionEvaluator.GetValue(null, "@(myContext:goran)").GetType()); - - // string literals allowed for contextname - Assert.AreEqual(typeof(TestObject), - ExpressionEvaluator.GetValue(null, "@('myContext':goran)").GetType()); - } - - /// - /// Since Expression-References require the context to be added to ContextRegistry, - /// they work only if the objectdefinition's "lazy-init" is true. - /// - [Test] - public void TestReferenceByExpression() - { - //TODO: write a test showing that expressions don't work without "lazy-init": - /* - - - - - */ - - ContextRegistry.RegisterContext( - new XmlApplicationContext(false, "assembly://Spring.Core.Tests/Spring.Context.Support/objects.xml")); - - TestObject testObject = ExpressionEvaluator.GetValue(null, "@(goran)") as TestObject; - - TestObjectContainer testObjectContainer = - ExpressionEvaluator.GetValue(null, "@(testObjectContainer_lazy)") as TestObjectContainer; - - Assert.IsNotNull(testObject); - Assert.AreSame(testObject, testObjectContainer.TestObject); - } - - /// - /// Ensure context-names my contain dots and slashes - /// - [Test] - public void TestQualifiedNameMayContainDotsAndSlashes() - { - IApplicationContext ctx = - new XmlApplicationContext(false, "assembly://Spring.Core.Tests/Spring.Context.Support/objects.xml"); - ctx.Name = @"my.Context/bla\"; - ContextRegistry.RegisterContext(ctx); - - Assert.AreEqual(typeof(TestObject), - ExpressionEvaluator.GetValue(null, @"@(my.Context/bla\:goran)").GetType()); -// Assert.AreEqual(typeof(TestObject), -// ExpressionEvaluator.GetValue(null, "@(my\\.Context:goran)").GetType()); - } - - /// - /// Tests attribute expression. - /// - [Test] - public void TestAttribute() - { - TypeRegistry.RegisterType("WebMethod", typeof(WebMethodAttribute)); - TypeRegistry.RegisterType("TransactionOption", typeof(TransactionOption)); - - Assert.IsInstanceOf(typeof(SerializableAttribute), - ExpressionEvaluator.GetValue(null, "@[System.Serializable]")); - Assert.IsInstanceOf(typeof(SerializableAttribute), - ExpressionEvaluator.GetValue(null, "@[System.Serializable()]")); - Assert.IsInstanceOf(typeof(WebMethodAttribute), ExpressionEvaluator.GetValue(null, "@[WebMethod]")); - - WebMethodAttribute webMethod = (WebMethodAttribute)ExpressionEvaluator.GetValue(null, "@[WebMethod(true)]"); - Assert.IsTrue(webMethod.EnableSession); - - webMethod = (WebMethodAttribute) - ExpressionEvaluator.GetValue( - null, - "@[WebMethod(false, CacheDuration = 60, Description = 'my web method', TransactionOption = TransactionOption.Required)]"); - Assert.AreEqual(60, webMethod.CacheDuration); - Assert.AreEqual("my web method", webMethod.Description); - Assert.AreEqual(TransactionOption.Required, webMethod.TransactionOption); - } - - [Test] - public void TestDelegateFunctionExpressions() - { - //for purposes of an example in documentation - Dictionary vars = new Dictionary(); - vars["sqrt"] = new DoubleFunction(Sqrt); - double result = (double)ExpressionEvaluator.GetValue(null, "#sqrt(64)", vars); - Assert.AreEqual(8, result); - - vars = new Dictionary(); - vars["max"] = new DoubleFunctionTwoArgs(Max); - result = (double) ExpressionEvaluator.GetValue(null, "#max(5,25)", vars); - Assert.AreEqual(25, result); - - - } - - private delegate double DoubleFunction(double arg); - - private double Sqrt(double arg) - { - return Math.Sqrt(arg); - } - - private delegate double DoubleFunctionTwoArgs(double arg1, double arg2); - - private double Max(double arg1, double arg2) - { - return Math.Max(arg1, arg2); - } - - /// - /// Type lambda expressions. - /// - [Test] - public void TestLambdaExpressions() - { - TypeRegistry.RegisterType(typeof(Math)); - - // simple function - Assert.AreEqual(4, - ExpressionEvaluator.GetValue(null, "(#add = {|x, y| $x + $y}; #add(2, 2))", new Dictionary())); - Assert.AreEqual(25, - ExpressionEvaluator.GetValue(null, "(#max = {|x, y| $x > $y ? $x : $y }; #max(5,25))", - new Dictionary())); - - // recursive function - Assert.AreEqual(120, - ExpressionEvaluator.GetValue(null, - "(#fact = {|n| $n <= 1 ? 1 : $n * #fact($n-1) }; #fact(5))", - new Dictionary())); - - // function invoked within projection expression - string expr = "(#upper = {|txt| $txt.ToUpper() }; !{ #upper(Name) })"; - IList upperNames = (IList)ExpressionEvaluator.GetValue(ieee.Members, expr, new Dictionary()); - Assert.AreEqual("NIKOLA TESLA", upperNames[0]); - Assert.AreEqual("MIHAJLO PUPIN", upperNames[1]); - - // function that delegates to a function passed as a parameter - Dictionary vars = new Dictionary(); - Expression.RegisterFunction("sqrt", "{|n| Math.Sqrt($n)}", vars); - Expression.RegisterFunction("fact", "{|n| $n <= 1 ? 1 : $n * #fact($n-1)}", vars); - string expr2 = - @"( - #delegate = {|f,n| $f($n) }; - #d = #delegate; - - #result = { #delegate(#sqrt, 4), #d(#fact, 5), #delegate({|n| $n ^ 2 }, 5) } - )"; - IList results = (IList)ExpressionEvaluator.GetValue(null, expr2, vars); - Assert.AreEqual(2, results[0]); - Assert.AreEqual(120, results[1]); - Assert.AreEqual(25, results[2]); - - // function assignment - Assert.AreEqual(120, - ExpressionEvaluator.GetValue(null, - "(#fact = {|n| $n <= 1 ? 1 : $n * #fact($n-1) }; #f = #fact; #f(5))", - new Dictionary())); - } - - #region Collection Processor and Aggregator tests - - [Test] - public void TestCountAggregator() - { - int[] arr = new int[] { 24, 8, 14, 8 }; - Assert.AreEqual(4, ExpressionEvaluator.GetValue(arr, "count()")); - Assert.AreEqual(3, ExpressionEvaluator.GetValue(null, "{1, 5, -3}.count()")); - Assert.AreEqual(0, ExpressionEvaluator.GetValue(null, "count()")); - } - - [Test] - public void TestCustomCollectionProcessor() - { - // Test for the purposes of creating documentation example. - Dictionary vars = new Dictionary(); - vars["EvenSum"] = new IntEvenSumCollectionProcessor(); - Assert.AreEqual(6, ExpressionEvaluator.GetValue(null, "{1, 2, 3, 4}.EvenSum()", vars)); - - } - - private class IntEvenSumCollectionProcessor : ICollectionProcessor - { - public object Process(ICollection source, object[] args) - { - object total = 0d; - foreach (object item in source) - { - if (item != null) - { - if (NumberUtils.IsInteger(item)) - { - if ((int)item % 2 == 0) - { - total = NumberUtils.Add(total, item); - } - } - else - { - throw new ArgumentException("Sum can only be calculated for a collection of numeric values."); - } - } - } - - return total; - } - } - - [Test] - public void TestSumAggregator() - { - int[] arr = new int[] { 24, 8, 14, 8 }; - Assert.AreEqual(54, ExpressionEvaluator.GetValue(arr, "sum()")); - Assert.AreEqual(13, ExpressionEvaluator.GetValue(null, "{1, 5, -3, 10}.sum()")); - - object[] arr2 = new object[] { 5, 5.8, 12.2, 1 }; - object result = ExpressionEvaluator.GetValue(arr2, "sum()"); - Assert.IsInstanceOf(typeof(double), result); - Assert.AreEqual(24, result); - } - - [Test] - public void TestSumAggregatorWithNonNumber() - { - object[] arr = new object[] { 5, "ana", 12.2, 1 }; - Assert.Throws(() => ExpressionEvaluator.GetValue(arr, "sum()")); - } - - [Test] - public void TestAverageAggregator() - { - int[] arr = new int[] { 24, 8, 16, 8 }; - Assert.AreEqual(14, ExpressionEvaluator.GetValue(arr, "average()")); - Assert.AreEqual(3, ExpressionEvaluator.GetValue(null, "{1, 5, -4, 10}.average()")); - Assert.AreEqual(3.5, ExpressionEvaluator.GetValue(null, "{1, 5, -2, 10}.average()")); - - object[] arr2 = new object[] { 5, 5.8, 12.2, 1 }; - object result = ExpressionEvaluator.GetValue(arr2, "average()"); - Assert.IsInstanceOf(typeof(double), result); - Assert.AreEqual(6, result); - } - - [Test] - public void TestAverageAggregatorWithNonNumber() - { - object[] arr = new object[] { 5, "ana", 12.2, 1 }; - Assert.Throws(() => ExpressionEvaluator.GetValue(arr, "average()")); - } - - [Test] - public void TestMinAggregator() - { - int[] arr = new int[] { 24, 8, 14, 8 }; - Assert.AreEqual(8, ExpressionEvaluator.GetValue(arr, "min()")); - Assert.AreEqual(-3, ExpressionEvaluator.GetValue(null, "{1, 5, -3, 10}.min()")); - - object[] arr2 = new object[] { 5, 5.8, 12.2, 1 }; - object result = ExpressionEvaluator.GetValue(arr2, "min()"); - Assert.IsInstanceOf(typeof(int), result); - Assert.AreEqual(1, result); - - Assert.IsNull(ExpressionEvaluator.GetValue(ObjectUtils.EmptyObjects, "min()")); - } - - [Test] - public void TestMinAggregatorWithNonComparable() - { - object[] arr = new object[] { new Object(), new Object() }; - Assert.Throws(() => ExpressionEvaluator.GetValue(arr, "min()")); - } - - [Test] - public void TestMinAggregatorWithMixedTypes() - { - object[] arr = new object[] { 5, "ana", 12.2, 1 }; - Assert.Throws(() => ExpressionEvaluator.GetValue(arr, "min()")); - } - - [Test] - public void TestMaxAggregator() - { - int[] arr = new int[] { 24, 8, 14, 8 }; - Assert.AreEqual(24, ExpressionEvaluator.GetValue(arr, "max()")); - Assert.AreEqual(10, ExpressionEvaluator.GetValue(null, "{1, 5, -3, 10}.max()")); - - object[] arr2 = new object[] { 5, 5.8, 12.2, 1 }; - object result = ExpressionEvaluator.GetValue(arr2, "max()"); - Assert.IsInstanceOf(typeof(double), result); - Assert.AreEqual(12.2, result); - - Assert.IsNull(ExpressionEvaluator.GetValue(ObjectUtils.EmptyObjects, "max()")); - } - - [Test] - public void TestMaxAggregatorWithNonComparable() - { - object[] arr = new object[] { new Object(), new Object() }; - Assert.Throws(() => ExpressionEvaluator.GetValue(arr, "max()")); - } - - [Test] - public void TestMaxAggregatorWithMixedTypes() - { - object[] arr = new object[] { 5, "ana", 12.2, 1 }; - Assert.Throws(() => ExpressionEvaluator.GetValue(arr, "max()")); - } - - [Test] - public void TestSortProcessor() - { - int[] arr = new int[] { 24, 8, 14, 6 }; - Assert.AreEqual(new int[] { 6, 8, 14, 24 }, ExpressionEvaluator.GetValue(arr, "sort()")); - Assert.AreEqual(new int[] { 6, 8, 14, 24 }, ExpressionEvaluator.GetValue(arr, "sort(true)")); - Assert.AreEqual(new int[] { 24, 14, 8, 6 }, ExpressionEvaluator.GetValue(arr, "sort(false)")); - - string[] arr2 = new string[] { "abc", "xyz", "stuv", "efg", "dcb" }; - Assert.AreEqual(new string[] { "abc", "dcb", "efg", "stuv", "xyz" }, - ExpressionEvaluator.GetValue(arr2, "sort()")); - - DateTime[] arr3 = new DateTime[] { DateTime.Today, DateTime.MaxValue, DateTime.MinValue }; - Assert.AreEqual(new DateTime[] { DateTime.MinValue, DateTime.Today, DateTime.MaxValue }, - ExpressionEvaluator.GetValue(arr3, "sort()")); - - Assert.AreEqual(new object[] { -3.3, 1.2, 5.5 }, ExpressionEvaluator.GetValue(null, "{1.2, 5.5, -3.3}.sort()")); - Assert.IsNull(ExpressionEvaluator.GetValue(null, "sort()")); - - ISet set = new ListSet(arr); - Assert.AreEqual(new int[] { 6, 8, 14, 24 }, ExpressionEvaluator.GetValue(set, "sort()")); - } - - [Test(Description="sort supports any ICollection containing elements of uniform type")] - public void TestSortProcessorWithSimpleICollectionType() - { - Stack stack = new Stack(new int[] { 24, 8, 14, 6 }); - ExpressionEvaluator.GetValue(stack, "sort()"); - } - - [Test] - public void TestNonNullProcessor() - { - string[] arr2 = new string[] { "abc", "xyz", null, "abc", "def", null }; - Assert.AreEqual(new string[] { "abc", "xyz", "abc", "def" }, - ExpressionEvaluator.GetValue(arr2, "nonNull()")); - Assert.AreEqual(new string[] { "abc", "abc", "def", "xyz" }, - ExpressionEvaluator.GetValue(arr2, "nonNull().sort()")); - } - - [Test] - public void TestDistinctProcessor() - { - int[] arr = new int[] { 24, 8, 8, 6, 24, 6, 8, 6 }; - Assert.AreEqual(new int[] { 6, 8, 24 }, ExpressionEvaluator.GetValue(arr, "distinct().sort()")); - - string[] arr2 = new string[] { "abc", "xyz", "abc", "def", null, "def" }; - Assert.AreEqual(new string[] { null, "abc", "def", "xyz" }, - ExpressionEvaluator.GetValue(arr2, "distinct(true).sort()")); - Assert.AreEqual(new string[] { "abc", "def", "xyz" }, - ExpressionEvaluator.GetValue(arr2, "distinct(false).sort()")); - Assert.AreEqual(new string[] { "abc", "def", "xyz" }, - ExpressionEvaluator.GetValue(arr2, "distinct().sort()")); - } - - [Test] - public void TestDistinctProcessorWithInvalidArgumentType() - { - int[] arr = new int[] { 24, 8, 8, 6, 24, 6, 8, 6 }; - Assert.Throws(() => ExpressionEvaluator.GetValue(arr, "distinct(6)")); - } - - [Test] - public void TestDistinctProcessorWithInvalidNumberOfArguments() - { - int[] arr = new int[] { 24, 8, 8, 6, 24, 6, 8, 6 }; - Assert.Throws(() => ExpressionEvaluator.GetValue(arr, "distinct(true, 4, 'xyz')")); - } - - [Test] - public void TestConversionProcessor() - { - object[] arr = new object[] { "0", 1, 1.1m, "1.1", 1.1f }; - decimal[] result = (decimal[]) ExpressionEvaluator.GetValue(arr, "convert(decimal)"); - Assert.AreEqual( 0.0m, result[0] ); - Assert.AreEqual(1.0m, result[1]); - Assert.AreEqual(1.1m, result[2]); - Assert.AreEqual(1.1m, result[3]); - Assert.AreEqual(1.1m, result[4]); - } - - [Test] - public void TestReverseProcessor() - { - object[] arr = new object[] { "0", 1, 2.1m, "3", 4.1f }; - object[] result = new ArrayList( (ICollection) ExpressionEvaluator.GetValue(arr, "reverse()") ).ToArray(); - Assert.AreEqual(new object[] { 4.1f, "3", 2.1m, 1, "0" }, result); - } - - #endregion - - /// - /// Type SetValue. - /// - [Test] - public void TestSetValue() - { - Dictionary vars = new Dictionary(); - vars["tesla"] = tesla; - vars["pupin"] = pupin; - ExpressionEvaluator.SetValue(null, "#tesla.Name", vars, "Tesla, Nikola"); - Assert.AreEqual("Tesla, Nikola", tesla.Name); - } - - /// - /// Tests property access with null in the path. - /// - [Test] - public void TestPropertyGetWithNullInThePath() - { - Assert.Throws(() => ExpressionEvaluator.GetValue(new Inventor(), "Name.Length")); - } - - /// - /// Tests property set with null in the path. - /// - [Test] - public void TestPropertySetWithNullInThePath() - { - Assert.Throws(() => ExpressionEvaluator.SetValue(new Inventor(), "Name.Length", 20)); - } - - /// - /// Tries to set value of the PropertyOrFieldNode that represents type. - /// - [Test] - public void TestTypeSet() - { - Assert.Throws(() => ExpressionEvaluator.SetValue(null, "DateTime", 20)); - } - - /// - /// Reproduce SPRNET-408. - /// - /// - /// http://opensource.atlassian.com/projects/spring/browse/SPRNET-408 - /// http://forum.springframework.net/showthread.php?t=933 - /// - [Test(Description = "Test to reproduce SPRNET-408")] - public void TestNullableTypes() - { - Foo foo = new Foo(); - Assert.IsNull(ExpressionEvaluator.GetValue(foo, "NullableDate")); - Assert.IsNull(ExpressionEvaluator.GetValue(foo, "NullableInt")); - - ExpressionEvaluator.SetValue(foo, "NullableDate", DateTime.Today); - ExpressionEvaluator.SetValue(foo, "NullableDate", null); - ExpressionEvaluator.SetValue(foo, "NullableDate", "2004-08-14"); - ExpressionEvaluator.SetValue(foo, "NullableDate", DateTime.Today); - ExpressionEvaluator.SetValue(foo, "NullableInt", 1); - ExpressionEvaluator.SetValue(foo, "NullableInt", null); - ExpressionEvaluator.SetValue(foo, "NullableInt", "5"); - ExpressionEvaluator.SetValue(foo, "NullableInt", 1); - - Assert.IsInstanceOf(typeof(DateTime?), ExpressionEvaluator.GetValue(foo, "NullableDate")); - Assert.IsInstanceOf(typeof(Int32?), ExpressionEvaluator.GetValue(foo, "NullableInt")); - - Assert.AreEqual(DateTime.Today, ExpressionEvaluator.GetValue(foo, "NullableDate")); - Assert.AreEqual(1, ExpressionEvaluator.GetValue(foo, "NullableInt")); - - int? test = 1; - Assert.IsInstanceOf(typeof(Int32?), ExpressionEvaluator.GetValue(test, "#root")); - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(test, "#root != null")); - Assert.AreEqual(1, ExpressionEvaluator.GetValue(test, "#root")); - - test = null; - Assert.IsTrue((bool)ExpressionEvaluator.GetValue(test, "#root == null")); - Assert.IsNull(ExpressionEvaluator.GetValue(test, "#root")); - } - - /// - /// Reproduce SPRNET-462. - /// - /// - /// http://opensource.atlassian.com/projects/spring/browse/SPRNET-462 - /// http://forum.springframework.net/showthread.php?t=1515 - /// - [Test(Description = "Test to reproduce SPRNET-462")] - public void TestMethodResolutionWithNullArguments() - { - DateTime today = DateTime.Today; - Assert.AreEqual(today.ToString("d"), ExpressionEvaluator.GetValue(today, "ToString('d')")); - - TypeRegistry.RegisterType(typeof(TypeRegistry)); - try - { - ExpressionEvaluator.GetValue(null, "TypeRegistry.RegisterType(null)"); - Assert.Fail("Should throw ArgumentNullException"); - } - catch (ArgumentNullException) - { } - - try - { - ExpressionEvaluator.GetValue(null, "TypeRegistry.RegisterType(null, 'System.Object')"); - Assert.Fail("Should throw ArgumentNullException"); - } - catch (ArgumentNullException) - { } - - try - { - ExpressionEvaluator.GetValue(null, "TypeRegistry.RegisterType(null, null)"); - Assert.Fail("Should throw AmbiguousMatchException"); - } - catch (AmbiguousMatchException) - { } - - try - { - ExpressionEvaluator.GetValue(null, "TypeRegistry.RegisterType(null, null, null)"); - Assert.Fail("Should throw ArgumentException"); - } - catch (ArgumentException) - { } - - try - { - ExpressionEvaluator.GetValue(null, "TypeRegistry.RegisterType(int, string)"); - Assert.Fail("Should throw ArgumentException"); - } - catch (ArgumentException) - { } - } - - /// - /// Reproduce SPRNET-464. - /// - /// - /// http://opensource.atlassian.com/projects/spring/browse/SPRNET-464 - /// http://forum.springframework.net/showthread.php?t=1515 - /// - [Test(Description = "Test to reproduce SPRNET-464")] - public void TestMethodResolutionWithParamArray() - { - Foo foo = new Foo(); - Assert.AreEqual("a|b|c", foo.MethodWithArrayArgument(new string[] { "a", "b", "c" })); - Assert.AreEqual("a||c", foo.MethodWithArrayArgument(new string[] { "a", null, "c" })); - Assert.AreEqual("a|b|c", foo.MethodWithParamArray("a", "b", "c")); - Assert.AreEqual("a||c", foo.MethodWithParamArray("a", null, "c")); - - Assert.AreEqual("a|b|c", ExpressionEvaluator.GetValue(foo, "MethodWithArrayArgument(new string[] { 'a', 'b', 'c' })")); - Assert.AreEqual("a||c", ExpressionEvaluator.GetValue(foo, "MethodWithArrayArgument(new string[] { 'a', null, 'c' })")); - Assert.AreEqual("a|b|c", ExpressionEvaluator.GetValue(foo, "MethodWithParamArray('a', 'b', 'c')")); - Assert.AreEqual("a||c", ExpressionEvaluator.GetValue(foo, "MethodWithParamArray('a', null, 'c')")); - - Assert.AreEqual("a|b|c", ExpressionEvaluator.GetValue(foo, "MethodWithParamArray(false, 'a', 'b', 'c')")); - Assert.AreEqual("a||c", ExpressionEvaluator.GetValue(foo, "MethodWithParamArray(false, 'a', null, 'c')")); - Assert.AreEqual("A|B|C", ExpressionEvaluator.GetValue(foo, "MethodWithParamArray(true, 'a', 'b', 'c')")); - Assert.AreEqual("A||C", ExpressionEvaluator.GetValue(foo, "MethodWithParamArray(true, 'a', null, 'c')")); - } - - [Test] - public void TestMethodResolutionResolvesToExactMatchOfArgumentTypes() - { - Dictionary args = new Dictionary(); - args["bars"] = new Bar[] { new Bar() }; - Foo foo = new Foo(); - - // ensure no one changed our test class - Assert.AreEqual("ExactMatch", foo.MethodWithSimilarArguments(1, (Bar[])args["bars"])); - Assert.AreEqual("AssignableMatch", foo.MethodWithSimilarArguments(1, (ICollection)args["bars"])); - - Assert.AreEqual("ExactMatch", ExpressionEvaluator.GetValue(foo, "MethodWithSimilarArguments(1, #bars)", args)); - } - - /// - /// Test to show that a large number of parameters can be passed to methods - /// - [Test] - public void TestMethodResolutionWithLargeNumberOfParametersDoesNotThrow() - { - int expectedResult = 150; - int result = 0; - - Foo foo = new Foo(); - string expression = $"MethodWithParamArray({String.Join(", ", Enumerable.Range(0, expectedResult))})"; - - Assert.DoesNotThrow(() => - { - result = (int)ExpressionEvaluator.GetValue(foo, expression); - }); - - Assert.AreEqual(expectedResult, result); + this.exp = exp; + this.rootContext = rootContext; + this.expected = expected; + this.variables = variables; } - [Test] - public void TestIndexerResolutionResolvesToExactMatchOfArgumentTypes() - { - Dictionary args = new Dictionary(); - args["bars"] = new Bar[] { new Bar() }; - Foo foo = new Foo(); - - // ensure no one changed our test class - Assert.AreEqual("ExactMatch", foo[(Bar[])args["bars"]]); - Assert.AreEqual("AssignableMatch", foo[(ICollection)args["bars"]]); - - Assert.AreEqual("ExactMatch", ExpressionEvaluator.GetValue(foo, "#root[#bars]", args)); - } - - - [Test] - public void TestCtorResolutionResolvesToExactMatchOfArgumentTypes() - { - TypeRegistry.RegisterType(typeof(Foo)); - Dictionary args = new Dictionary(); - args["bars"] = new Bar[] { new Bar() }; - - // ensure no one changed our test class - Foo foo1 = new Foo(1, (Bar[])args["bars"]); - try - { - Foo foo2 = new Foo(1, (ICollection)args["bars"]); - } - catch (InvalidOperationException) { } - - Assert.IsNotNull(ExpressionEvaluator.GetValue(null, "new Foo(1, #bars)", args)); - } - - [Test] - public void TestCtorResolutionWithParamArray() - { - TypeRegistry.RegisterType(typeof(Foo)); - Assert.IsNotNull(ExpressionEvaluator.GetValue(null, "new Foo('a', 'b', 'c')")); - Assert.IsNotNull(ExpressionEvaluator.GetValue(null, "new Foo('a', null, 'c')")); - Assert.IsNotNull(ExpressionEvaluator.GetValue(null, "new Foo(false, 'a', 'b', 'c')")); - Assert.IsNotNull(ExpressionEvaluator.GetValue(null, "new Foo(false, 'a', null, 'c')")); - } - - /// - /// Reproduce SPRNET-470. - /// - /// - /// http://opensource.atlassian.com/projects/spring/browse/SPRNET-470 - /// http://forum.springframework.net/showthread.php?t=1574 - /// - [Test(Description = "Test to reproduce SPRNET-470")] - public void TestPropertyAccessForTypes() - { - Assert.AreEqual(Int32.MaxValue, ExpressionEvaluator.GetValue(null, "Int32.MaxValue")); - Assert.AreEqual(Int32.MaxValue, ExpressionEvaluator.GetValue(null, "T(System.Int32).MaxValue")); - Assert.AreEqual(typeof(Int32).FullName, ExpressionEvaluator.GetValue(null, "Int32.FullName")); - Assert.AreEqual(typeof(Int32).FullName, ExpressionEvaluator.GetValue(null, "T(System.Int32).FullName")); - Assert.IsFalse((bool)ExpressionEvaluator.GetValue(null, "Int32.IsSubclassOf(Int64)")); - - TypeRegistry.RegisterType(typeof(FooType)); - Assert.AreEqual(FooType.One, ExpressionEvaluator.GetValue(null, "FooType.One")); - Assert.AreEqual(typeof(FooType).FullName, ExpressionEvaluator.GetValue(null, "FooType.FullName")); - } - - /// - /// Reproduce SPRNET-450 - /// Try to set/get numeric value from enum type property/field - /// - /// - /// http://opensource.atlassian.com/projects/spring/browse/SPRNET-450 - /// http://forum.springframework.net/showthread.php?t=1353 - /// - [Test] - public void TestSetEnumTypePropertyOrFieldFromNumeric() - { - //object val = Convert.ChangeType((Int16) 1, typeof(Int32)); - //Assert.AreEqual( typeof(Int32), val.GetType() ); - - IExpression expField = Expression.Parse("SampleEnumField"); - IExpression expProperty = Expression.Parse("SampleEnumProperty"); - IExpression expFlagsField = Expression.Parse("SampleFlagsEnumField"); - IExpression expFlagsProperty = Expression.Parse("SampleFlagsEnumProperty"); - - TestEnumTypePropertyClass o = new TestEnumTypePropertyClass(); - - // test field set operations - expField.SetValue(o, TestEnumTypePropertyClass.ESampleEnumType.Trunk); - Assert.AreEqual(TestEnumTypePropertyClass.ESampleEnumType.Trunk, o.SampleEnumField); - - expField.SetValue(o, (short) 1); - Assert.AreEqual(TestEnumTypePropertyClass.ESampleEnumType.Trunk, o.SampleEnumField); - - expField.SetValue(o, 1); - Assert.AreEqual(TestEnumTypePropertyClass.ESampleEnumType.Trunk, o.SampleEnumField); - - expField.SetValue(o, (long) 1); - Assert.AreEqual(TestEnumTypePropertyClass.ESampleEnumType.Trunk, o.SampleEnumField); - - // test property set operations - expProperty.SetValue(o, TestEnumTypePropertyClass.ESampleEnumType.Trunk); - Assert.AreEqual(TestEnumTypePropertyClass.ESampleEnumType.Trunk, o.SampleEnumField); - - expProperty.SetValue(o, (short) 1); - Assert.AreEqual(TestEnumTypePropertyClass.ESampleEnumType.Trunk, o.SampleEnumField); - - expProperty.SetValue(o, 1); - Assert.AreEqual(TestEnumTypePropertyClass.ESampleEnumType.Trunk, o.SampleEnumField); - - expProperty.SetValue(o, (long) 1); - Assert.AreEqual(TestEnumTypePropertyClass.ESampleEnumType.Trunk, o.SampleEnumField); - - expProperty.SetValue(o, "Trunk"); - Assert.AreEqual(TestEnumTypePropertyClass.ESampleEnumType.Trunk, o.SampleEnumField); - - try - { - expProperty.SetValue(o, 1.0); - Assert.Fail("should throw"); - } - catch (TypeMismatchException e) - { - Assert.IsTrue(e.Message.StartsWith("Cannot convert property value of type [System.Double]")); - } - - try - { - expProperty.SetValue(o, ((float)1.0)); - Assert.Fail("should throw"); - } - catch (TypeMismatchException e) - { - Assert.IsTrue(e.Message.StartsWith("Cannot convert property value of type [System.Single]")); - } - - // test get operations - object val = expField.GetValue(o); - Assert.AreEqual(typeof(TestEnumTypePropertyClass.ESampleEnumType), val.GetType()); - Assert.AreEqual(TestEnumTypePropertyClass.ESampleEnumType.Trunk, val); - - val = expProperty.GetValue(o); - Assert.AreEqual(typeof(TestEnumTypePropertyClass.ESampleEnumType), val.GetType()); - Assert.AreEqual(TestEnumTypePropertyClass.ESampleEnumType.Trunk, val); - - // test bitwise combined enum set - try - { - // not allowed since -1 is not defined in enum - expField.SetValue(o, -1); - Assert.Fail("should throw"); - } - catch (TypeMismatchException ex) - { - Assert.IsTrue( - ex.Message.StartsWith("Cannot convert property value of type [System.Int32] to required type")); - } - - try - { - // not allowed since -1 is not a representation of any bitwise combination of the enum's values. - expFlagsField.SetValue(o, -1); - Assert.Fail("should throw"); - } - catch (TypeMismatchException ex) - { - Assert.IsTrue( - ex.Message.StartsWith("Cannot convert property value of type [System.Int32] to required type")); - } - - expFlagsField.SetValue(o, - TestEnumTypePropertyClass.ESampleFlagsEnumType.SOME | - TestEnumTypePropertyClass.ESampleFlagsEnumType.SOMEOTHER); - Assert.AreEqual( - TestEnumTypePropertyClass.ESampleFlagsEnumType.SOME | - TestEnumTypePropertyClass.ESampleFlagsEnumType.SOMEOTHER, o.SampleFlagsEnumField); - } - - /// - /// Test to reproduce SPRNET-342, provided on the forum. - /// - /// - /// http://opensource.atlassian.com/projects/spring/browse/SPRNET-342 - /// http://forum.springframework.net/showthread.php?t=614 - /// - [Test] - public void ForumTestThread614() - { - TypeRegistry.RegisterType(typeof(Sample)); - - IExpression e = Expression.Parse("new Sample(O, T, H)"); - - Sample d1 = new Sample("A", "B", "C"); - Sample d2 = new Sample("A", "B", "Z"); - - Sample tmp1 = (Sample)e.GetValue(d1); - Assert.AreEqual("A", tmp1.O); - Assert.AreEqual("B", tmp1.T); - Assert.AreEqual("C", tmp1.H); - - Sample tmp2 = (Sample)e.GetValue(d2); - Assert.AreEqual("A", tmp2.O); - Assert.AreEqual("B", tmp2.T); - Assert.AreEqual("Z", tmp2.H); - } - - /// - /// More "to the point" test to reproduce SPRNET-342 - /// - /// - /// http://opensource.atlassian.com/projects/spring/browse/SPRNET-342 - /// http://forum.springframework.net/showthread.php?t=614 - /// - [Test] - public void RootContextChangeTest() - { - IExpression e = Expression.Parse("#root"); - - Assert.AreEqual("RootA", e.GetValue("RootA")); - Assert.AreEqual("RootB", e.GetValue("RootB")); - } - - /// - /// Hopefully detects threading issues during Expression evaluation - /// - /// - /// A single expression instance may be evaluated against different contexts on different threads. - /// - [Test] - public void ExpressionEvaluationIsThreadSafe() - { - IExpression exp = Expression.Parse("PlaceOfBirth.Country"); - - Inventor seovic = new Inventor("Aleksandar Seovic", new DateTime(1974, 08, 24), "Serbian"); - - AsyncTestTask t1 = new AsyncTestExpressionEvaluation(2000, exp, tesla, tesla.PlaceOfBirth.Country, null).Start(); - AsyncTestTask t2 = new AsyncTestExpressionEvaluation(2000, exp, pupin, pupin.PlaceOfBirth.Country, null).Start(); - AsyncTestTask t3 = new AsyncTestExpressionEvaluation(2000, exp, seovic, seovic.PlaceOfBirth.Country, null).Start(); - - IExpression exp2 = Expression.Parse("(#fact = {|n| $n <= 1 ? 1 : $n * #fact($n-1) }; #fact(#root))"); - - AsyncTestTask t4 = new AsyncTestExpressionEvaluation(2000, exp2, 5, 120, new Dictionary()).Start(); - AsyncTestTask t5 = new AsyncTestExpressionEvaluation(2000, exp2, 6, 720, new Dictionary()).Start(); - - t1.AssertNoException(); - t2.AssertNoException(); - t3.AssertNoException(); - t4.AssertNoException(); - t5.AssertNoException(); - } - - /// - /// Hopefully detects threading issues during Expression parsing - /// - [Test] - public void ExpressionParserIsThreadSafe() - { - AsyncTestTask t1 = new AsyncTestMethod(200, new ThreadStart(TestOperatorPrecedence)).Start(); - AsyncTestTask t2 = new AsyncTestMethod(200, new ThreadStart(TestOperatorPrecedence)).Start(); - AsyncTestTask t3 = new AsyncTestMethod(200, new ThreadStart(TestOperatorPrecedence)).Start(); - - t1.AssertNoException(); - t2.AssertNoException(); - t3.AssertNoException(); - } - - - /// - /// Checks if Expression Language array initializers work properly. - /// - [Test] - public void TestArrayConstructor() - { - object obj = ExpressionEvaluator.GetValue(null, "new int[] {3, 4, 5, 6}"); - Assert.IsNotNull(obj); - Assert.IsInstanceOf(typeof(int[]), obj); - int[] intarray = (int[])obj; - Assert.AreEqual(4, intarray.Length); - for (int i = 0; i < intarray.Length; i++) - { - Assert.AreEqual(i + 3, intarray[i]); - } - - obj = ExpressionEvaluator.GetValue(null, "new long[5]"); - Assert.IsNotNull(obj); - Assert.IsInstanceOf(typeof(long[]), obj); - long[] longarray = obj as long[]; - Assert.AreEqual(5, longarray.Length); - for (int i = 0; i < longarray.Length; i++) - { - Assert.AreEqual(0, longarray[i]); - } - - obj = ExpressionEvaluator.GetValue(null, "new double[4, 5]"); - Assert.IsNotNull(obj); - Assert.IsInstanceOf(typeof(double[,]), obj); - double[,] twodimarray = obj as double[,]; - Assert.AreEqual(4 * 5, twodimarray.Length); - for (int i = 0; i < 4; i++) - { - for (int j = 0; j < 5; j++) - { - Assert.AreEqual(0.0, twodimarray[i, j]); - } - } - - obj = ExpressionEvaluator.GetValue(null, "new int[Int32.Parse('11')]"); - Assert.IsNotNull(obj); - Assert.IsInstanceOf(typeof(int[]), obj); - intarray = obj as int[]; - Assert.AreEqual(11, intarray.Length); - } - - [Test] - public void TestMethodArgumentNodesResolveAgainstThisContext() - { - IExpression exp; - - // case #root == #this - ToString() will be applied to #this - exp = Expression.Parse("long.Parse(ToString())"); - object result = exp.GetValue(100); - Assert.AreEqual((long)100, result); - - // case #root != #this in Projection - ToString() will be applied to #this - exp = Expression.Parse("(ToString(); #noop ={|val| $val}; !{#noop(ToString()) } )"); - result = exp.GetValue(new int[] { 100, 200 }, new Dictionary()); - Assert.AreEqual(new string[] { "100", "200" }, result); - - // case #root != #this in Selection - ToString() will be applied to #this - exp = Expression.Parse("(#noop ={|val| $val}; ?{#noop(ToString()=='100')} )"); - result = exp.GetValue(new int[] { 100, 200 }, new Dictionary()); - IList list = new ArrayList(); - list.Add(100); - Assert.AreEqual(list, result); - } - - [Test] - public void TestAccessVisibility() - { - AccessVisibilityCases cases = new AccessVisibilityCases(); - - try - { - ExpressionEvaluator.SetValue(cases, "_privateReadonlyField", "notsoreadonly"); - Assert.Fail("writing to readonly field should throw " + typeof(NotWritablePropertyException).FullName); - } - catch (NotWritablePropertyException) { } - - try - { - ExpressionEvaluator.SetValue(cases, "PrivateReadonlyProperty", "notsoreadonly"); - Assert.Fail("writing to readonly field should throw " + typeof(NotWritablePropertyException).FullName); - } - catch (NotWritablePropertyException) { } - - Assert.AreEqual("_privateField", ExpressionEvaluator.GetValue(cases, "_privateField")); - Assert.AreEqual("_protectedField", ExpressionEvaluator.GetValue(cases, "_protectedField")); - Assert.AreEqual("_publicField", ExpressionEvaluator.GetValue(cases, "_publicField")); - - Assert.AreEqual("PrivateProperty", ExpressionEvaluator.GetValue(cases, "PrivateProperty")); - Assert.AreEqual("ProtectedProperty", ExpressionEvaluator.GetValue(cases, "ProtectedProperty")); - Assert.AreEqual("PublicProperty", ExpressionEvaluator.GetValue(cases, "PublicProperty")); - - Assert.AreEqual("PrivateIndexer", ExpressionEvaluator.GetValue(cases, "#root[1]")); - Assert.AreEqual("ProtectedIndexer", ExpressionEvaluator.GetValue(cases, "#root[1.0]")); - Assert.AreEqual("PublicIndexer", ExpressionEvaluator.GetValue(cases, "#root['']")); - - Assert.AreEqual("PrivateMethod", ExpressionEvaluator.GetValue(cases, "GetPrivateMethod()")); - Assert.AreEqual("ProtectedMethod", ExpressionEvaluator.GetValue(cases, "GetProtectedMethod()")); - Assert.AreEqual("PublicMethod", ExpressionEvaluator.GetValue(cases, "GetPublicMethod()")); - } - - #region TestAccessVisibility Classes - - internal class AccessVisibilityCases - { - private readonly string _privateReadonlyField = "_privateReadonlyField"; - private string _privateField = "_privateField"; - protected string _protectedField = "_protectedField"; - public string _publicField = "_publicField"; - - - public AccessVisibilityCases() - { - Assert.IsTrue(_privateReadonlyField != string.Empty); - Assert.IsTrue(_privateField != string.Empty); - } - - private string PrivateReadonlyProperty { get { return "PrivateReadonlyProperty"; } } - private string PrivateProperty { get { return "PrivateProperty"; } } - protected string ProtectedProperty { get { return "ProtectedProperty"; } } - public string PublicProperty { get { return "PublicProperty"; } } - - private string this[int intindex] { get { return "PrivateIndexer"; } } - protected string this[double strindex] { get { return "ProtectedIndexer"; } } - public string this[string strindex] { get { return "PublicIndexer"; } } - - private string GetPrivateMethod() { return "PrivateMethod"; } - protected string GetProtectedMethod() { return "ProtectedMethod"; } - public string GetPublicMethod() { return "PublicMethod"; } - } - - #endregion - - #region TestMethodInvocation Classes - - class MethodInvokationCases - { - public string Foo(string stringArg) { return stringArg; } - public int Foo(int intArg) { return intArg; } - } - - #endregion - - #region Set operations tests - - [Test] - public void TestUnionOperator() - { - object o = ExpressionEvaluator.GetValue(null, "{1,2,3} + {3,4,5}"); - Assert.IsInstanceOf(typeof(ISet), o); - ISet union = (ISet)o; - Assert.AreEqual(5, union.Count); - Assert.IsTrue(union.Contains(1)); - Assert.IsTrue(union.Contains(3)); - Assert.IsTrue(union.Contains(5)); - - o = ExpressionEvaluator.GetValue(null, "{1,2,3} + {3,4,5} + {'ivan', 'gox', 'damjao', 5}"); - Assert.IsInstanceOf(typeof(ISet), o); - union = (ISet)o; - Assert.AreEqual(8, union.Count); - Assert.IsTrue(union.Contains(1)); - Assert.IsTrue(union.Contains("ivan")); - - ISet testset = new ListSet(); - testset.AddAll(new int[] { 1, 2, 3, 5, 8 }); - o = ExpressionEvaluator.GetValue(testset, "#this + {1, 2, 13, 15}"); - Assert.IsInstanceOf(typeof(ISet), o); - union = (ISet)o; - Assert.AreEqual(7, union.Count); - Assert.IsTrue(union.Contains(1)); - Assert.IsTrue(union.Contains(15)); - - o = ExpressionEvaluator.GetValue(null, "#{1:'one', 2:'two', 3:'three'} + #{1:'ivan', 5:'five'}"); - Assert.IsInstanceOf(typeof(IDictionary), o); - IDictionary result = (IDictionary)o; - Assert.AreEqual(4, result.Count); - Assert.AreEqual("one", result[1]); - Assert.AreEqual("five", result[5]); - } - - [Test] - public void TestUnionOperatorBad() - { - Assert.Throws(() => ExpressionEvaluator.GetValue(null, "#{1:'one', 2:'two', 3:'three'} + {1, 5}")); - } - - [Test] - public void TestIntersectionOperator() - { - object o = ExpressionEvaluator.GetValue(null, "{111, 'ivan', 23, 24} * {111, 11, 'ivan'}"); - Assert.IsInstanceOf(typeof(ISet), o); - ISet intersection = (ISet)o; - Assert.AreEqual(2, intersection.Count); - Assert.IsTrue(intersection.Contains(111)); - Assert.IsTrue(intersection.Contains("ivan")); - - o = ExpressionEvaluator.GetValue(null, "{24, 25, 'aaa' + 'bb'} * {date('2007/2/5').day * 5, 24 - 1}"); - Assert.IsInstanceOf(typeof(ISet), o); - intersection = (ISet)o; - Assert.AreEqual(1, intersection.Count); - Assert.IsTrue(intersection.Contains(25)); - - ISet testset = new ListSet(); - testset.AddAll(new int[] { 1, 2, 3, 5, 8 }); - o = ExpressionEvaluator.GetValue(testset, "#this * #{1:'one', 10:'ten'}"); - Assert.IsInstanceOf(typeof(ISet), o); - intersection = (ISet)o; - Assert.AreEqual(1, intersection.Count); - Assert.IsTrue(intersection.Contains(1)); - - o = ExpressionEvaluator.GetValue(null, "#{1:'one', 2:'two', 3:'three'} * #{1:'ivan', 5:'five'}"); - Assert.IsInstanceOf(typeof(IDictionary), o); - IDictionary result = (IDictionary)o; - Assert.AreEqual(1, result.Count); - Assert.AreEqual("one", result[1]); - - o = ExpressionEvaluator.GetValue(null, "#{1:'one', 2:'two', 3:'three'} * {1, 2, 5, 7}"); - Assert.IsInstanceOf(typeof(IDictionary), o); - result = (IDictionary)o; - Assert.AreEqual(2, result.Count); - Assert.AreEqual("one", result[1]); - Assert.AreEqual("two", result[2]); - } - - [Test] - public void TestIntersectionOperatorBad() - { - Assert.Throws(() => ExpressionEvaluator.GetValue(null, "#{1:'one', 2:'two', 3:'three'} * 'something'")); - } - - [Test] - public void TestDifferenceOperator() - { - object o = ExpressionEvaluator.GetValue(null, "{111, 11} - {14, 12, 11}"); - Assert.IsInstanceOf(typeof(ISet), o); - ISet diff = (ISet)o; - Assert.AreEqual(1, diff.Count); - Assert.IsTrue(diff.Contains(111)); - - o = ExpressionEvaluator.GetValue(null, "{111, 11} - {14, 12, 11} - {111}"); - Assert.IsInstanceOf(typeof(ISet), o); - diff = (ISet)o; - Assert.AreEqual(0, diff.Count); - - ISet testset = new ListSet(); - testset.AddAll(new int[] { 1, 2, 3, 5, 8 }); - o = ExpressionEvaluator.GetValue(testset, "#this - #{1:'one', 10:'ten'}"); - Assert.IsInstanceOf(typeof(ISet), o); - diff = (ISet)o; - Assert.AreEqual(4, diff.Count); - Assert.IsFalse(diff.Contains(1)); - - o = ExpressionEvaluator.GetValue(null, "#{1:'one', 2:'two', 3:'three'} - #{1:'ivan', 5:'five'}"); - Assert.IsInstanceOf(typeof(IDictionary), o); - IDictionary result = (IDictionary)o; - Assert.AreEqual(2, result.Count); - Assert.IsNull(result[1]); - Assert.AreEqual("three", result[3]); - - o = ExpressionEvaluator.GetValue(null, "#{1:'one', 2:'two', 3:'three'} - {1, 2, 3, 5, 7}"); - Assert.IsInstanceOf(typeof(IDictionary), o); - result = (IDictionary)o; - Assert.AreEqual(0, result.Count); - } - - [Test] - public void TestDifferenceOperatorBad() - { - Assert.Throws(() => ExpressionEvaluator.GetValue(null, "#{1:'one', 2:'two', 3:'three'} - 'something'")); - } - - #endregion - - #region Performance tests - - private DateTime start, stop; - - //[Test] - public void PerformanceTests() - { - int n = 10000000; - object x = ""; - IDictionary vars = new Dictionary(); - - // tesla.PlaceOfBirth - start = DateTime.Now; - for (int i = 0; i < n; i++) - { - x = tesla.PlaceOfBirth; - } - stop = DateTime.Now; - PrintTest("tesla.PlaceOfBirth (direct)", n, Elapsed); - - // start = DateTime.Now; - // for (int i = 0; i < n; i++) - // { - // x = ExpressionEvaluator.GetValue(tesla, "PlaceOfBirth", vars); - // } - // stop = DateTime.Now; - // PrintTest("tesla.PlaceOfBirth (multi-parse)", n, Elapsed); - - start = DateTime.Now; - IExpression exp = Expression.Parse("PlaceOfBirth"); - for (int i = 0; i < n; i++) - { - x = exp.GetValue(tesla, vars); - } - stop = DateTime.Now; - PrintTest("tesla.PlaceOfBirth (single-parse)", n, Elapsed); - - // ieee.Officers['advisors'][0].Inventions[2] - start = DateTime.Now; - for (int i = 0; i < n; i++) - { - x = ((Inventor)((IList)ieee.Officers["advisors"])[0]).Inventions[2]; - } - stop = DateTime.Now; - PrintTest("ieee.Officers['advisors'][0].Inventions[2] (direct)", n, Elapsed); - - // start = DateTime.Now; - // for (int i = 0; i < n / 10; i++) - // { - // x = ExpressionEvaluator.GetValue(ieee, "Officers['advisors'][0].Inventions[2]", vars); - // } - // stop = DateTime.Now; - // PrintTest("ieee.Officers['advisors'][0].Inventions[2] (multi-parse)", n / 10, Elapsed); - - start = DateTime.Now; - exp = Expression.Parse("Officers['advisors'][0].Inventions[2]"); - for (int i = 0; i < n; i++) - { - x = exp.GetValue(ieee, vars); - } - stop = DateTime.Now; - PrintTest("ieee.Officers['advisors'][0].Inventions[2] (single-parse)", n, Elapsed); - - x.ToString(); - } - - private double Elapsed - { - get { return (stop.Ticks - start.Ticks) / 10000000f; } - } - - private static void PrintTest(string name, int iterations, double duration) - { - Debug.WriteLine( - String.Format("{0,-60} {1,12:#,###} {2,12:##0.000} {3,12:#,###}", name, iterations, duration, - iterations / duration)); - } - - #endregion - - #region Method Inheritance tests - - [Test] - public void TestInheritedMethodInvocation() - { - DerivedSingleMethodTestClass testClass = new DerivedSingleMethodTestClass(); - Assert.AreEqual("Hello World", ExpressionEvaluator.GetValue(testClass, "#root.GetString()")); - } - - [Test] - public void TestStaticInheritedMethodInvocation() - { - Assert.AreEqual("Hello Static World from SingleMethodTestClass", DerivedSingleMethodTestClass.StaticMethod()); - Assert.AreEqual("Hello Static World from SingleMethodTestClass", ExpressionEvaluator.GetValue(null, string.Format("T({0}).StaticMethod()", typeof(DerivedSingleMethodTestClass).FullName))); - - Assert.AreEqual("SingleMethodTestClass.ShadowedStaticMethod", SingleMethodTestClass.ShadowedStaticMethod()); - Assert.AreEqual("DerivedSingleMethodTestClass.ShadowedStaticMethod", DerivedSingleMethodTestClass.ShadowedStaticMethod()); - Assert.AreEqual("SingleMethodTestClass.ShadowedStaticMethod", ExpressionEvaluator.GetValue(null, string.Format("T({0}).ShadowedStaticMethod()", typeof(SingleMethodTestClass).FullName))); - Assert.AreEqual("DerivedSingleMethodTestClass.ShadowedStaticMethod", ExpressionEvaluator.GetValue(null, string.Format("T({0}).ShadowedStaticMethod()", typeof(DerivedSingleMethodTestClass).FullName))); - } - - #endregion - - private static void DumpNode(AST rootNode, int level) - { - Trace.WriteLine(new string(' ', level) + rootNode.ToString()); - - int numberOfChildren = rootNode.getNumberOfChildren(); - if (numberOfChildren > 0) - { - AST node = rootNode.getFirstChild(); - while (node != null) - { - DumpNode(node, level + 2); - node = node.getNextSibling(); - } - } - } - } - - #region Helper classes - - internal class SingleMethodTestClass - { - protected static string GetMethodName(MethodBase method) - { - return method.DeclaringType.Name + "." + method.Name; - } - - public static string StaticMethod() - { - return "Hello Static World from SingleMethodTestClass"; - } - - public static string ShadowedStaticMethod() - { - return GetMethodName(MethodInfo.GetCurrentMethod()); - } - - public string GetString() - { - return "Hello World"; - } - } - - internal class DerivedSingleMethodTestClass : SingleMethodTestClass - { - public new static string ShadowedStaticMethod() - { - return GetMethodName(MethodInfo.GetCurrentMethod()); - } - } - - internal class TestObjectContainer - { - private TestObject testObject; - - public TestObject TestObject - { - get { return this.testObject; } - set { this.testObject = value; } - } - } - - internal class TestEnumTypePropertyClass - { - [Flags] - internal enum ESampleFlagsEnumType : int - { - NONE = 0, - SOME = 1, - SOMEOTHER = 2, - } - - internal enum ESampleEnumType : int - { - Van = 0, - Trunk = 1, - Air = 2 - } - - public ESampleFlagsEnumType SampleFlagsEnumField; - public ESampleEnumType SampleEnumField; - - public ESampleFlagsEnumType SampleFlagsEnumProperty - { - get { return SampleFlagsEnumField; } - set { SampleFlagsEnumField = value; } - } - - public ESampleEnumType SampleEnumProperty - { - get { return SampleEnumField; } - set { SampleEnumField = value; } - } - } - - internal sealed class Bar - { - private int[] numbers = new int[] { 1, 2, 3 }; - - public int this[int index] - { - get { return numbers[index]; } - } - } - - internal class Foo - { - private FooType type; - private Nullable nullableDate; - private Nullable nullableInt; - - public Foo() : this(FooType.One) - { - } - - public Foo(FooType type) - { - this.type = type; - } - - public Foo(params string[] values) - { - } - - public Foo(bool flag, params string[] values) - { - } - - public Foo(int flag, Bar[] bars) - { - } - - public Foo(int flag, ICollection bars) - { - throw new InvalidOperationException("should have selected ctor(int, Bar[])"); - } - - public string this[Bar[] bars] - { - get { return "ExactMatch"; } - } - - public string this[ICollection bars] - { - get { return "AssignableMatch"; } - } - - public object this[int foo, string key] - { - get { return key + "_" + foo; } - } - - public FooType Type - { - get { return type; } - } - - public DateTime? NullableDate - { - get { return nullableDate; } - set { nullableDate = value; } - } - - public int? NullableInt - { - get { return nullableInt; } - set { nullableInt = value; } - } - - public string MethodWithSimilarArguments(int flags, Bar[] bars) - { - return "ExactMatch"; - } - - public string MethodWithSimilarArguments(int flags, ICollection bar) - { - return "AssignableMatch"; - } - - public string MethodWithArrayArgument(string[] values) - { - return string.Join("|", values); - } - - public string MethodWithParamArray(params string[] values) - { - return string.Join("|", values); - } - - public string MethodWithParamArray(bool uppercase, params string[] values) - { - string ret = string.Join("|", values); - return (uppercase ? ret.ToUpper() : ret); - } - - public int MethodWithParamArray(params int[] values) - { - return values.Length; - } - } - - internal enum FooType - { - One, - Two, - Three - } - - internal class Sample - { - public string O; - public string T; - public string H; - - public Sample(string o, string t, string h) + public override void DoExecute() { - O = o; - T = t; - H = h; + object result = exp.GetValue(rootContext, variables); + Assert.AreEqual(expected, result); } } #endregion - #region Shadowing Test Helper Classes + private Inventor tesla; + private Inventor pupin; + private Society ieee; - internal class ShadowingTestsBaseClass + #region SetUp and TearDown + + /// + /// The setup logic executed before the execution of each individual test. + /// + [SetUp] + public void SetUp() { - private object _someValue; - private object _readonlyShadowedValue; - private object _writeonlyShadowedValue; + ContextRegistry.Clear(); + tesla = new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian"); + tesla.Inventions = new string[] { "Telephone repeater", "Rotating magnetic field principle", "Polyphase alternating-current system", "Induction motor", "Alternating-current power transmission", "Tesla coil transformer", "Wireless communication", "Radio", "Fluorescent lights" }; + tesla.PlaceOfBirth.City = "Smiljan"; - public object SomeValue + pupin = new Inventor("Mihajlo Pupin", new DateTime(1854, 10, 9), "Serbian"); + pupin.Inventions = + new string[] { "Long distance telephony & telegraphy", "Secondary X-Ray radiation", "Sonar" }; + pupin.PlaceOfBirth.City = "Idvor"; + pupin.PlaceOfBirth.Country = "Serbia"; + + ieee = new Society(); + ieee.Members.Add(tesla); + ieee.Members.Add(pupin); + ieee.Officers["president"] = pupin; + ieee.Officers["advisors"] = new Inventor[] { tesla, pupin }; + // not historically accurate, but I need an array in the map ;-) + + TypeRegistry.RegisterType("Society", typeof(Society)); + } + + [OneTimeTearDown] + public void TearDown() + { + //DynamicCodeManager.SaveAssembly(); + } + + #endregion + + #region Serialization Tests + + /// + /// GetObjectData() is not overridden on purpose !!! + /// + [Serializable] + private class SerializationTestExpression : BaseNode + { + private int testValue = 0; + + public int TestValue { - get { return _someValue; } - set { _someValue = value; } + get { return testValue; } } - public object ReadonlyShadowedValue + public SerializationTestExpression(int testValue) { - get { return _readonlyShadowedValue; } - set { _readonlyShadowedValue = value; } + this.testValue = testValue; } - public object WriteonlyShadowedValue + protected SerializationTestExpression(SerializationInfo info, StreamingContext context) + : base(info, context) { - get { return _writeonlyShadowedValue; } - set { _writeonlyShadowedValue = value; } + } + + protected override object Get(object context, EvaluationContext evalContext) + { + throw new NotImplementedException(); } } - internal class ShadowingTestsSpezializedClass : ShadowingTestsBaseClass + /// + /// Tests serialization + deserialization of all BaseNode derived types + /// + [Test] + public void AllExpressionNodeTypesAreSerializable() { - public new string SomeValue - { - get { return (string)base.SomeValue; } - set { base.SomeValue = value; } - } + Type[] possibleTypes = typeof(BaseNode).Assembly.GetTypes(); - public new string ReadonlyShadowedValue - { - get { return (string)base.ReadonlyShadowedValue; } - } + BinaryFormatter formatter = new BinaryFormatter(); - public new string WriteonlyShadowedValue + // look for all BaseNode derived types defined in assembly Spring.Core + for (int i = 0; i < possibleTypes.Length; i++) { - set { base.WriteonlyShadowedValue = value; } + Type t = possibleTypes[i]; + if (t != typeof(BaseNode) + && typeof(BaseNode).IsAssignableFrom(t) + && (!t.IsAbstract) + ) + { + //Console.WriteLine("testing " + t.FullName); + + // create using for public default ctor + IExpression exp = (IExpression) Activator.CreateInstance(t, true); + // serialize and deserialize it + exp = SerializeDeserializeExpression(exp); + exp = SerializeDeserializeExpressionUsingSoap(exp); + } } } - internal class ShadowingTestsMoreSpezializedClass : ShadowingTestsSpezializedClass + /// + /// implements . + /// Thus members in derived classes won't get automatically serialized. + /// + [Test] + public void MembersDontGetSerializedByDefault() { + SerializationTestExpression exp = new SerializationTestExpression(5); + Assert.AreEqual(5, exp.TestValue); + SerializationTestExpression exp2 = (SerializationTestExpression) SerializeDeserializeExpression(exp); + Assert.AreEqual(0, exp2.TestValue); } - internal class ShadowingTestsMostSpezializedClass : ShadowingTestsMoreSpezializedClass + /// + /// This test ensures, that the default node-type is serializable. + /// + /// + /// date() is parsed into DateLiteralNode( down:<default node type> ). + /// Normally antlr.CommonAST is the default node used by antlr. To enable serialization, Spring + /// uses a custom ASTFactory in + /// + [Test] + public void ExpressionDateLiteralNodeMaintainsStateAfterSerialization() { + IExpression exp = Expression.Parse("date('08-24-1974', 'MM-dd-yyyy')"); + + Assert.AreEqual(new DateTime(1974, 8, 24), exp.GetValue(null)); + + exp = SerializeDeserializeExpression(exp); + + Assert.AreEqual(new DateTime(1974, 8, 24), exp.GetValue(null)); } - #endregion // Shadowing Test Helper Classes + private static IExpression SerializeDeserializeExpression(IExpression exp) + { + byte[] data; + BinaryFormatter formatter = new BinaryFormatter(); + using (MemoryStream ms = new MemoryStream()) + { + formatter.Serialize(ms, exp); + ms.Flush(); + data = ms.ToArray(); + } + using (MemoryStream ms = new MemoryStream(data)) + { + exp = (IExpression) formatter.Deserialize(ms); + } + return exp; + } + + private static IExpression SerializeDeserializeExpressionUsingSoap(IExpression exp) + { + string xml; + SoapFormatter formatter = new SoapFormatter(); + using (MemoryStream ms = new MemoryStream()) + { + formatter.Serialize(ms, exp); + ms.Position = 0; + byte[] b = new byte[ms.Length]; + ms.Read(b, 0, (int) ms.Length); + xml = Encoding.ASCII.GetString(b, 0, b.Length); + } + + using (StringReader sr = new StringReader(xml)) + { + byte[] b = Encoding.ASCII.GetBytes(xml); + Stream stream = new MemoryStream(b); + exp = (IExpression) formatter.Deserialize(stream); + } + + return exp; + } + + #endregion Serialization Tests + + [Test] + public void TestConstantRead() + { + object value = ExpressionEvaluator.GetValue(null, "Society.ByteConst == 1"); + Assert.AreEqual(true, value); + } + + [Test] + public void TestBitwiseXOR() + { + object value = ExpressionEvaluator.GetValue(null, "'123' + 1"); + Assert.AreEqual("1231", value); + } + + [Test] + public void TestMixedAddition() + { + object value = ExpressionEvaluator.GetValue(null, "'123' + 1"); + Assert.AreEqual("1231", value); + } + + [Test(Description = "SPRNET-1507 - Test 1")] + public void TestExpandoObject() + { + dynamic dynamicObject = new System.Dynamic.ExpandoObject(); + //add property at run-time + dynamicObject.IssueId = "1507"; + + object value = ExpressionEvaluator.GetValue(dynamicObject, "IssueId"); + Assert.AreEqual("1507", value); + } + + [Test(Description = "SPRNET-1507 - Test 2")] + public void TestExpandoObjectWithNotExistedProperty() + { + try + { + dynamic dynamicObject = new System.Dynamic.ExpandoObject(); + + ExpressionEvaluator.GetValue(dynamicObject, "PropertyName"); + Assert.Fail(); + } + catch (InvalidPropertyException ex) + { + Assert.AreEqual( + "'PropertyName' node cannot be resolved for the specified context [System.Dynamic.ExpandoObject].", + ex.Message); + } + } + + [Test(Description = "SPRNET-944")] + public void DateTests() + { + string dateLiteral = (string) ExpressionEvaluator.GetValue(null, "'date'"); + Assert.AreEqual("date", dateLiteral); + } + + [Test(Description = "http://jira.springframework.org/browse/SPRNET-944")] + public void TestDateVariableExpression() + { + Dictionary vars = new Dictionary(); + vars["date"] = "2008-05-15"; + object value = ExpressionEvaluator.GetValue(null, "#date", vars); + Assert.That(value, Is.EqualTo("2008-05-15")); + } + + [Test(Description = "http://jira.springframework.org/browse/SPRNET-1155")] + public void TestDateVariableExpressionCamelCased() + { + Dictionary vars = new Dictionary(); + vars["Date"] = "2008-05-15"; + object value = ExpressionEvaluator.GetValue(null, "#Date", vars); + Assert.That(value, Is.EqualTo("2008-05-15")); + } + + [Test] + public void ThrowsSyntaxErrorException() + { + try + { + ExpressionEvaluator.GetValue(null, "'date"); // unclose string literal + Assert.Fail(); + } + catch (RecognitionException ex) + { + Assert.AreEqual("Syntax Error on line 1, column 6: expecting ''', found '' in expression" + Environment.NewLine + "''date'", ex.Message); + } + } + + /// + /// Should throw exception for null root object + /// + [Test] + public void NullRoot() + { + Assert.Throws(() => ExpressionEvaluator.GetValue(null, "dummy.expression")); + } + + /// + /// Should throw exception for null root object + /// + [Test] + public void TryingToSetTheValueOfNonSettableNode() + { + Assert.Throws(() => ExpressionEvaluator.SetValue(null, "10", 5)); + } + + /// + /// Should return root itself for empty expression + /// + [Test] + public void GetNullOrEmptyExpression() + { + DateTime now = DateTime.Now; + Assert.AreEqual(ExpressionEvaluator.GetValue(now, null), now); + Assert.AreEqual(ExpressionEvaluator.GetValue(now, ""), now); + } + + /// + /// Should fail when setting value for the empty expression + /// + [Test] + public void SetNullOrEmptyExpression() + { + Assert.Throws(() => ExpressionEvaluator.SetValue("xyz", null, "abc")); + } + + /// + /// Tests null literal. + /// + [Test] + public void TestNullLiteral() + { + Assert.IsNull(ExpressionEvaluator.GetValue(null, "null")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "'xyz' == null")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "null != 'xyz'")); + } + + [Test] + public void TestUnicode() + { + Assert.AreEqual("\u6f22\u5b57", ExpressionEvaluator.GetValue(null, "'\u6f22\u5b57'")); + } + + /// + /// Tests string literals. + /// + [Test] + public void TestStringLiterals() + { + Assert.AreEqual("literal string", ExpressionEvaluator.GetValue(null, "'literal string'")); + Assert.AreEqual("literal 'string", ExpressionEvaluator.GetValue(null, "'literal ''string'")); + Assert.AreEqual(string.Empty, ExpressionEvaluator.GetValue(null, "''")); + Assert.AreEqual("escaped \t string \n", ExpressionEvaluator.GetValue(null, "'escaped \t string \n'")); + //Debug.Write(ExpressionEvaluator.GetValue(null, "'escaped\tstring\nsecond line\n\nfourth line'")); + } + + /// + /// Tests integer literals. + /// + [Test] + public void TestIntLiterals() + { + object int32 = ExpressionEvaluator.GetValue(null, Int32.MaxValue.ToString()); + Assert.AreEqual(int32, Int32.MaxValue); + Assert.IsTrue(int32 is Int32); + Assert.AreEqual(32, ExpressionEvaluator.GetValue(null, "0x20")); + + Assert.AreEqual(Int64.MaxValue.ToString(), ExpressionEvaluator.GetValue(null, Int64.MaxValue.ToString() + ".ToString()")); + Assert.AreEqual(Int64.MaxValue.ToString(), ExpressionEvaluator.GetValue(null, "long.MaxValue.ToString()")); + + object int64 = ExpressionEvaluator.GetValue(null, Int64.MaxValue.ToString()); + Assert.AreEqual(int64, Int64.MaxValue); + Assert.IsTrue(int64 is Int64); + } + + /// + /// Tests hexadecimal integer literals. + /// + [Test] + public void TestHexLiterals() + { + IExpression exp = Expression.Parse("0x20"); + Assert.AreEqual(32, exp.GetValue()); + Assert.AreEqual(32, exp.GetValue()); + Assert.AreEqual(255, ExpressionEvaluator.GetValue(null, "0xFF")); + Assert.AreEqual(Int32.MaxValue, ExpressionEvaluator.GetValue(null, "0x7FFFFFFF")); + Assert.AreEqual(Int64.MaxValue, ExpressionEvaluator.GetValue(null, "0x7FFFFFFFFFFFFFFF")); + Assert.AreEqual(Int32.MinValue, ExpressionEvaluator.GetValue(null, "0x80000000")); + Assert.AreEqual(Int64.MinValue, ExpressionEvaluator.GetValue(null, "0x8000000000000000")); + } + + /// + /// Tests real literals. + /// + [Test] + public void TestRealLiterals() + { + IExpression exp = Expression.Parse("3.402823E+38"); + exp.GetValue(); + object s = exp.GetValue(); + object d = ExpressionEvaluator.GetValue(null, "1.797693E+308"); + object dec = ExpressionEvaluator.GetValue(null, "1000.00m"); + + Assert.IsTrue(s is Double); + Assert.IsTrue(d is Double); + Assert.IsTrue(dec is Decimal); + + Assert.AreEqual(s, 3.402823E+38); + Assert.AreEqual(d, 1.797693E+308); + + Assert.AreEqual(5.25F, ExpressionEvaluator.GetValue(null, "5.25f")); + Assert.AreEqual(0.75d, ExpressionEvaluator.GetValue(null, "0.75D")); + + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "1000 == 1e3 and 1e+4 != 1000")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "100 < 1000.00m and 10000.00 > 1000")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "100 < 1000.00 and 10000.00m > 1e2")); + } + + /// + /// Tests boolean literals. + /// + [Test] + public void TestBooleanLiterals() + { + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "true")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "false")); + } + + /// + /// Tests date literals. + /// + [Test] + public void TestDateLiterals() + { + IExpression exp = Expression.Parse("date('1974/08/24')"); + Assert.AreEqual(new DateTime(1974, 8, 24), exp.GetValue()); + Assert.AreEqual(new DateTime(1974, 8, 24), exp.GetValue()); + Assert.AreEqual(new DateTime(1974, 8, 24), ExpressionEvaluator.GetValue(null, "date('1974-08-24')")); + Assert.AreEqual(new DateTime(1974, 8, 24), ExpressionEvaluator.GetValue(null, "date('08-24-1974', 'MM-dd-yyyy')")); + Assert.AreEqual(new DateTime(1974, 8, 24), ExpressionEvaluator.GetValue(null, "date('08/24/1974', 'MM/dd/yyyy')")); + Assert.AreEqual(new DateTime(1974, 8, 24, 12, 35, 6), ExpressionEvaluator.GetValue(null, "date('1974-08-24 12:35:06Z', 'u')")); + Assert.AreEqual(1974, ExpressionEvaluator.GetValue(null, "date('1974/08/24').Year")); + Assert.AreEqual(2005, ExpressionEvaluator.GetValue(null, "date('1974/08/24').AddYears(31).Year")); + } + + /// + /// Tests simple property and field accessors and mutators + /// + [Test] + public void TestSimplePropertyAccess() + { + Assert.AreEqual(DateTime.Today, ExpressionEvaluator.GetValue(null, "DateTime.Today")); + Assert.AreEqual("Nikola Tesla", ExpressionEvaluator.GetValue(tesla, "Name")); + Assert.AreEqual("Idvor", ExpressionEvaluator.GetValue(pupin, "PlaceOfBirth.City")); + ExpressionEvaluator.SetValue(tesla, "PlaceOfBirth.Country", "Croatia"); + Assert.AreEqual("Croatia", ExpressionEvaluator.GetValue(tesla, "PlaceOfBirth.Country")); + ExpressionEvaluator.SetValue(pupin, "Name", "Michael Pupin"); + Assert.AreEqual("Michael Pupin", ExpressionEvaluator.GetValue(pupin, "Name")); + Assert.AreEqual(new DateTime(1856, 7, 9), ExpressionEvaluator.GetValue(tesla, "DOB")); + Assert.AreEqual(1856, ExpressionEvaluator.GetValue(tesla, "DOB.Year")); + } + + /// + /// Tests that simple property and field accessors and mutators are case-insensitive. + /// + [Test] + public void SimplePropertyAccessIsCaseInsensitive() + { + Assert.AreEqual("Nikola Tesla", ExpressionEvaluator.GetValue(tesla, "nAme")); + Assert.AreEqual("Idvor", ExpressionEvaluator.GetValue(pupin, "Placeofbirth.city")); + ExpressionEvaluator.SetValue(tesla, "PlaceOfBirth.CountRY", "Croatia"); + Assert.AreEqual("Croatia", ExpressionEvaluator.GetValue(tesla, "Placeofbirth.COUNtry")); + ExpressionEvaluator.SetValue(pupin, "NAME", "Michael Pupin"); + Assert.AreEqual("Michael Pupin", ExpressionEvaluator.GetValue(pupin, "name")); + Assert.AreEqual(new DateTime(1856, 7, 9), ExpressionEvaluator.GetValue(tesla, "dob")); + Assert.AreEqual(1856, ExpressionEvaluator.GetValue(tesla, "DOb.YEar")); + } + + /// + /// Tests setting and getting shadowed properties + /// + [Test] + public void TestShadowedPropertyAccess() + { + ShadowingTestsMostSpezializedClass o; + + // test read + o = new ShadowingTestsMostSpezializedClass(); + o.SomeValue = "SomeString"; + Assert.AreEqual("SomeString", ExpressionEvaluator.GetValue(o, "SomeValue")); + + // test write + o = new ShadowingTestsMostSpezializedClass(); + ExpressionEvaluator.SetValue(o, "SomeValue", "SomeOtherString"); + Assert.AreEqual("SomeOtherString", o.SomeValue); + + // test readonly shadowed + o = new ShadowingTestsMostSpezializedClass(); + ((ShadowingTestsBaseClass) o).ReadonlyShadowedValue = "SomeString1"; + Assert.AreEqual("SomeString1", ExpressionEvaluator.GetValue(o, "ReadonlyShadowedValue")); + try + { + ExpressionEvaluator.SetValue(o, "ReadonlyShadowedValue", "SomeString2"); + Assert.Fail("Setting readonly property should throw NotWritablePropertyException"); + } + catch (NotWritablePropertyException) + { + } + + Assert.AreEqual("SomeString1", ExpressionEvaluator.GetValue(o, "ReadonlyShadowedValue")); + + // test writeonly shadowed + o = new ShadowingTestsMostSpezializedClass(); + ExpressionEvaluator.SetValue(o, "WriteonlyShadowedValue", "SomeString3"); + Assert.AreEqual("SomeString3", ((ShadowingTestsBaseClass) o).WriteonlyShadowedValue); + try + { + ExpressionEvaluator.GetValue(o, "WriteonlyShadowedValue"); + Assert.Fail("Getting writeonly property should throw NotReadablePropertyException"); + } + catch (NotReadablePropertyException) + { + } + } + + /// + /// Tests indexed property and field accessors and mutators + /// + [Test] + public void TestIndexedPropertyAccess() + { + TypeRegistry.RegisterType("Society", typeof(Society)); + + // arrays and lists + Assert.AreEqual("Induction motor", ExpressionEvaluator.GetValue(tesla, "Inventions[3]")); + Assert.AreEqual("Nikola Tesla", ExpressionEvaluator.GetValue(ieee, "Members[0].Name")); + Assert.AreEqual("Wireless communication", ExpressionEvaluator.GetValue(ieee, "Members[0].Inventions[6]")); + + // maps + Assert.AreEqual(pupin, ExpressionEvaluator.GetValue(ieee, "Officers['president']")); + Assert.AreEqual("Idvor", ExpressionEvaluator.GetValue(ieee, "Officers['president'].PlaceOfBirth.City")); + Assert.AreEqual(tesla, ExpressionEvaluator.GetValue(ieee, "Officers['advisors'][0]")); + Assert.AreEqual("Polyphase alternating-current system", + ExpressionEvaluator.GetValue(ieee, "Officers['advisors'][0].Inventions[2]")); + + // maps with non-literal parameters + Dictionary vars = new Dictionary(); + vars["prez"] = "president"; + Assert.AreEqual(pupin, ExpressionEvaluator.GetValue(ieee, "Officers[#prez]", vars)); + + Assert.AreEqual(pupin, ExpressionEvaluator.GetValue(ieee, "Officers[Society.President]")); + Assert.AreEqual("Idvor", ExpressionEvaluator.GetValue(ieee, "Officers[Society.President].PlaceOfBirth.City")); + Assert.AreEqual(tesla, ExpressionEvaluator.GetValue(ieee, "Officers[Society.Advisors][0]")); + Assert.AreEqual("Polyphase alternating-current system", + ExpressionEvaluator.GetValue(ieee, "Officers[Society.Advisors][0].Inventions[2]")); + + // try to set some values + ExpressionEvaluator.SetValue(ieee, "Officers['advisors'][0].PlaceOfBirth.Country", "Croatia"); + Assert.AreEqual("Croatia", ExpressionEvaluator.GetValue(tesla, "PlaceOfBirth.Country")); + ExpressionEvaluator.SetValue(ieee, "Officers['president'].Name", "Michael Pupin"); + Assert.AreEqual("Michael Pupin", ExpressionEvaluator.GetValue(pupin, "Name")); + ExpressionEvaluator.SetValue(ieee, "Officers['advisors']", new Inventor[] { pupin, tesla }); + Assert.AreEqual(pupin, ExpressionEvaluator.GetValue(ieee, "Officers['advisors'][0]")); + Assert.AreEqual(tesla, ExpressionEvaluator.GetValue(ieee, "Officers['advisors'][1]")); + + // generic indexer + Bar bar = new Bar(); + Foo foo = new Foo(); + IExpression exp = Expression.Parse("[1]"); + Assert.AreEqual(2, exp.GetValue(bar)); + Assert.AreEqual(2, exp.GetValue(bar)); + Assert.AreEqual("test_1", ExpressionEvaluator.GetValue(foo, "[1, 'test']")); + } + + /// + /// Tests indexer access with invalid number of indices + /// + [Test] + public void TestIndexedPropertyAccessWithInvalidNumberOfIndices() + { + Assert.Throws(() => ExpressionEvaluator.GetValue(tesla, "Inventions[3, 2]")); + } + + /// + /// Tests method accessors + /// + [Test] + public void TestMethodAccess() + { + Guid guid = Guid.NewGuid(); + + TypeRegistry.RegisterType("Guid", typeof(Guid)); + Assert.AreEqual(guid.ToString(), ExpressionEvaluator.GetValue(guid, "ToString()")); + Assert.AreEqual(guid.ToString("n"), ExpressionEvaluator.GetValue(guid, "ToString('n')")); + Assert.AreEqual(16, ExpressionEvaluator.GetValue(null, "Guid.NewGuid().ToByteArray().Length")); + + Assert.AreEqual(2005 - tesla.DOB.Year, + ExpressionEvaluator.GetValue(ieee, "Members[0].GetAge(date('2005-01-01'))")); + } + + [Test] + public void TestMethodEvaluationOnDifferentContextType() + { + IExpression expression = Expression.Parse("ToString('dummy', null)"); + Assert.AreEqual("dummy", expression.GetValue(0m, null)); + Assert.AreEqual("dummy", expression.GetValue(0, null)); + } + + [Test] + public void TestMethodEvaluationOnDifferentArgumentTypes() + { + IExpression expression = Expression.Parse("Foo(#var1)"); + MethodInvokationCases testContext = new MethodInvokationCases(); + Dictionary args = new Dictionary(); + args["var1"] = "myString"; + Assert.AreEqual("myString", expression.GetValue(testContext, args)); + args["var1"] = 12; + Assert.AreEqual(12, expression.GetValue(testContext, args)); + } + + /// + /// Tests missing method accessors + /// + [Test] + public void TestMissingMethodAccess() + { + Assert.Throws(() => ExpressionEvaluator.GetValue("xyz", "ToStringilyLingily()")); + } + + /// + /// Tests projection node + /// + [Test] + public void TestProjection() + { + IList placesOfBirth = (IList) ExpressionEvaluator.GetValue(ieee, "Members.!{PlaceOfBirth.City}"); + + Assert.AreEqual(2, placesOfBirth.Count); + Assert.AreEqual("Smiljan", placesOfBirth[0]); + Assert.AreEqual("Idvor", placesOfBirth[1]); + + IList names = (IList) ExpressionEvaluator.GetValue(ieee, "Officers['advisors'].!{Name}"); + Assert.AreEqual(2, names.Count); + Assert.AreEqual("Nikola Tesla", names[0]); + Assert.AreEqual("Mihajlo Pupin", names[1]); + } + + /// + /// Tests selection node + /// + [Test] + public void TestSelection() + { + IList memberSelection = + (IList) ExpressionEvaluator.GetValue(ieee, "Members.?{PlaceOfBirth.City == 'Smiljan'}"); + + Assert.AreEqual(1, memberSelection.Count); + Assert.AreEqual("Nikola Tesla", ((Inventor) memberSelection[0]).Name); + + IList serbianOfficers = + (IList) ExpressionEvaluator.GetValue(ieee, "Officers['advisors'].?{Nationality == 'Serbian'}"); + Assert.AreEqual(2, serbianOfficers.Count); + Assert.AreEqual("Nikola Tesla", ((Inventor) serbianOfficers[0]).Name); + Assert.AreEqual("Mihajlo Pupin", ((Inventor) serbianOfficers[1]).Name); + + Inventor first = + (Inventor) ExpressionEvaluator.GetValue(ieee, "Officers['advisors'].^{Nationality == 'Serbian'}"); + Assert.AreEqual("Nikola Tesla", first.Name); + + Inventor last = + (Inventor) ExpressionEvaluator.GetValue(ieee, "Officers['advisors'].${Nationality == 'Serbian'}"); + Assert.AreEqual("Mihajlo Pupin", last.Name); + } + + /// + /// Tests type node + /// + [Test] + public void TestTypeNode() + { + IExpression exp = Expression.Parse("T(DateTime)"); + exp.GetValue(); + Assert.AreEqual(typeof(DateTime), exp.GetValue()); + + Assert.AreEqual(typeof(DateTime), ExpressionEvaluator.GetValue(null, "T(System.DateTime)")); + Assert.AreEqual(typeof(DateTime[]), ExpressionEvaluator.GetValue(null, "T(System.DateTime[], mscorlib)")); + Assert.AreEqual(typeof(ExpressionEvaluator), ExpressionEvaluator.GetValue(null, "T(Spring.Expressions.ExpressionEvaluator, Spring.Core)")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(tesla, "T(System.DateTime) == DOB.GetType()")); + } + + /// + /// Tests type node + /// + [Test] + public void TestTypeNodeWithArrays() + { + Assert.AreEqual(typeof(DateTime[]), ExpressionEvaluator.GetValue(null, "T(System.DateTime[])")); + Assert.AreEqual(typeof(DateTime[,]), ExpressionEvaluator.GetValue(null, "T(System.DateTime[,])")); + Assert.AreEqual(typeof(DateTime[]), ExpressionEvaluator.GetValue(null, "T(System.DateTime[], mscorlib)")); + Assert.AreEqual(typeof(DateTime[,]), ExpressionEvaluator.GetValue(null, "T(System.DateTime[,], mscorlib)")); + } + + /// + /// Tests type node + /// + [Test] + public void TestTypeNodeWithAssemblyQualifiedName() + { + Assert.AreEqual(typeof(ExpressionEvaluator), ExpressionEvaluator.GetValue(null, string.Format("T({0})", typeof(ExpressionEvaluator).AssemblyQualifiedName))); + } + + /// + /// Tests type node + /// + [Test] + public void TestTypeNodeWithGenericAssemblyQualifiedName() + { +// Assert.AreEqual(typeof(int?), ExpressionEvaluator.GetValue(null, "T(System.Nullable`1[System.Int32], mscorlib)")); +// Assert.AreEqual(typeof(int?), ExpressionEvaluator.GetValue(null, "T(System.Nullable`1[[System.Int32, mscorlib]], mscorlib)")); + Assert.AreEqual(typeof(int?), ExpressionEvaluator.GetValue(null, "T(System.Nullable`1[[int]], mscorlib)")); + Assert.AreEqual(typeof(System.Collections.Generic.Dictionary), ExpressionEvaluator.GetValue(null, "T(System.Collections.Generic.Dictionary`2[System.String,System.Boolean],mscorlib)")); + } + + [Test] + public void TestGenericDictionary() + { + ExpressionEvaluator.GetValue(null, + "T(System.Collections.Generic.Dictionary`2[System.String,System.Boolean],mscorlib)"); + } + + /// + /// Tests type node + /// + [Test] + public void TestTypeNodeWithAliasedGenericArguments() + { + Assert.AreEqual(typeof(System.Collections.Generic.Dictionary), ExpressionEvaluator.GetValue(null, "T(System.Collections.Generic.Dictionary`2[string,bool],mscorlib)")); + } + + /// + /// Tests type node + /// + [Test] + public void TestTypeNodeWithGenericAssemblyQualifiedArrayName() + { + Assert.AreEqual(typeof(int?[,]), ExpressionEvaluator.GetValue(null, "T(System.Nullable`1[[System.Int32, mscorlib]][,], mscorlib)")); + } + + /// + /// Tests constructor node + /// + [Test] + public void TestConstructor() + { + TypeRegistry.RegisterType(typeof(Inventor)); + + IExpression exp = Expression.Parse("new System.DateTime(2004, 8, 14)"); + Assert.AreEqual(1000, ExpressionEvaluator.GetValue(null, "new Decimal(1000)")); + Assert.AreEqual(new DateTime(2004, 8, 14), exp.GetValue(null)); + Assert.AreEqual(new DateTime(2004, 8, 14), exp.GetValue("xyz")); + Assert.AreEqual(new DateTime(1974, 8, 24), + ExpressionEvaluator.GetValue(null, "new DateTime(2004, 8, 14).AddDays(10).AddYears(-30)")); + + // test named arguments + Inventor ana = + (Inventor) + ExpressionEvaluator.GetValue(null, + "new Inventor(Name = 'Ana Maria Seovic', DOB = date('2004-08-14'), Nationality = 'American')"); + Assert.AreEqual("Ana Maria Seovic", ana.Name); + Assert.AreEqual(new DateTime(2004, 8, 14), ana.DOB); + Assert.AreEqual("American", ana.Nationality); + + Inventor aleks = + (Inventor) + ExpressionEvaluator.GetValue(null, + "new Inventor('Aleksandar Seovic', date('1974-08-24'), 'Serbian', Inventions = {'SPELL'})"); + Assert.AreEqual("Aleksandar Seovic", aleks.Name); + Assert.AreEqual(new DateTime(1974, 8, 24), aleks.DOB); + Assert.AreEqual("Serbian", aleks.Nationality); + Assert.AreEqual(1, aleks.Inventions.Length); + Assert.AreEqual("SPELL", aleks.Inventions[0]); + } + + /// + /// Tests missing constructor + /// + [Test] + public void TestMissingConstructor() + { + Assert.Throws(() => ExpressionEvaluator.GetValue(null, "new Decimal('xyz')")); + } + + /// + /// Tests expression list node + /// + [Test] + public void TestExpressionList() + { + TypeRegistry.RegisterType("Inventor", typeof(Inventor)); + Assert.AreEqual(3, + ExpressionEvaluator.GetValue(ieee.Members, + "(Add(new Inventor('Aleksandar Seovic', date('1974-08-24'), 'Serbian')); Count)")); + Assert.AreEqual(3, + ExpressionEvaluator.GetValue(ieee, + "Members.(Add(new Inventor('Ana Maria Seovic', date('2004-08-14'), 'Serbian')); RemoveAt(1); Count)")); + Assert.AreEqual("Aleksandar Seovic", + ExpressionEvaluator.GetValue(ieee.Members, + "([1].PlaceOfBirth.City = 'Beograd'; [1].PlaceOfBirth.Country = 'Serbia'; [1].Name)")); + Assert.AreEqual("Beograd", ((Inventor) ieee.Members[1]).PlaceOfBirth.City); + } + + /// + /// Tests assignment node + /// + [Test] + public void TestAssignNode() + { + Inventor inventor = new Inventor(); + Assert.AreEqual("Aleksandar Seovic", ExpressionEvaluator.GetValue(inventor, "Name = 'Aleksandar Seovic'")); + Assert.AreEqual(new DateTime(1974, 8, 24), + ExpressionEvaluator.GetValue(inventor, "DOB = date('1974-08-24')")); + Assert.AreEqual("Serbian", ExpressionEvaluator.GetValue(inventor, "Nationality = 'Serbian'")); + Assert.AreEqual("Ana Maria Seovic", + ExpressionEvaluator.GetValue(inventor, + "(DOB = date('2004-08-14'); Name = 'Ana Maria Seovic')")); + Assert.AreEqual(new DateTime(2004, 8, 14), inventor.DOB); + ExpressionEvaluator.GetValue(ieee, "Officers['vp'] = Members[0]"); + Assert.AreEqual("Nikola Tesla", ((Inventor) ieee.Officers["vp"]).Name); + } + + /// + /// Tests default node + /// + [Test] + public void TestDefaultNode() + { + Assert.AreEqual("default", ExpressionEvaluator.GetValue(null, "null ?? 'default'")); + Assert.AreEqual(1, ExpressionEvaluator.GetValue(null, "null ?? 2 * 2 - 3")); + Assert.AreEqual("Nikola Tesla", ExpressionEvaluator.GetValue(tesla, "null ?? #root.Name")); + + Assert.AreEqual("default", ExpressionEvaluator.GetValue(null, "'default' ?? 'xyz'")); + Assert.AreEqual(1, ExpressionEvaluator.GetValue(null, "2 * 2 - 3 ?? 5")); + Assert.AreEqual("Nikola Tesla", ExpressionEvaluator.GetValue(tesla, "#root.Name ?? 'Pupin'")); + } + + /// + /// Tests variable node + /// + [Test] + public void TestVariableNode() + { + Dictionary vars = new Dictionary(); + vars["newName"] = "Aleksandar Seovic"; + Assert.AreEqual("Ana Maria Seovic", + ExpressionEvaluator.GetValue(null, "#newName = 'Ana Maria Seovic'", vars)); + Assert.AreEqual("Ana Maria Seovic", ExpressionEvaluator.GetValue(tesla, "Name = #newName", vars)); + Assert.AreEqual("Nikola Tesla", + ExpressionEvaluator.GetValue(tesla, "(#oldName = Name; Name = 'Nikola Tesla')", vars)); + Assert.AreEqual("Nikola Tesla", ((Inventor) ExpressionEvaluator.GetValue(tesla, "#this", vars)).Name); + Assert.AreEqual("Nikola Tesla", + ExpressionEvaluator.GetValue(tesla, "(Nationality = 'Srbin'; #this).Name", vars)); + Assert.AreEqual("Nikola Tesla", tesla.Name); + Assert.AreEqual("Srbin", tesla.Nationality); + Assert.AreEqual("Ana Maria Seovic", vars["oldName"]); + Assert.AreEqual(tesla, ExpressionEvaluator.GetValue(tesla, "#root", vars)); + } + + /// + /// Try to set 'this' variable + /// + [Test] + public void TryToSetThis() + { + Assert.Throws(() => ExpressionEvaluator.SetValue(null, "#this", "xyz")); + } + + /// + /// Try to set 'root' variable + /// + [Test] + public void TryToSetRoot() + { + Assert.Throws(() => ExpressionEvaluator.SetValue(null, "#root", "xyz")); + } + + /// + /// Tests ternary node + /// + [Test] + public void TestTernaryNode() + { + IExpression exp = Expression.Parse("true ? 'trueExp' : 'falseExp'"); + exp.GetValue(); + + Assert.AreEqual("trueExp", exp.GetValue()); + Assert.AreEqual("falseExp", ExpressionEvaluator.GetValue(null, "false ? 'trueExp' : 'falseExp'")); + Assert.AreEqual("trueExp", ExpressionEvaluator.GetValue(null, "(true ? 'trueExp' : 'falseExp')")); + Assert.AreEqual("falseExp", ExpressionEvaluator.GetValue(null, "(false ? 'trueExp' : 'falseExp')")); + + ExpressionEvaluator.SetValue(ieee, "Name", "IEEE"); + Dictionary vars = new Dictionary(); + vars["queryName"] = "Nikola Tesla"; + string expression = + @"IsMember(#queryName) + ? #queryName + ' is a member of the ' + Name + ' Society' + : #queryName + ' is not a member of ' + Name + ' Society'"; + Assert.AreEqual("Nikola Tesla is a member of the IEEE Society", + ExpressionEvaluator.GetValue(ieee, expression, vars)); + } + + /// + /// Tests logical OR operator + /// + [Test] + public void TestLogicalOrOperator() + { + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "true or true")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "false or false")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "true or false")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "false or true")); + string expression = @"IsMember('Nikola Tesla') or IsMember('Albert Einstien')"; + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(ieee, expression)); + } + + /// + /// Tests bitwise OR operator + /// + [Test] + public void TestBitwiseOrOperator() + { + Assert.AreEqual(1 | 2, ExpressionEvaluator.GetValue(null, "1 or 2")); + Assert.AreEqual(1 | -2, ExpressionEvaluator.GetValue(null, "1 or -2")); + Assert.AreEqual(RegexOptions.IgnoreCase | RegexOptions.Compiled, ExpressionEvaluator.GetValue(null, "T(System.Text.RegularExpressions.RegexOptions).IgnoreCase or T(System.Text.RegularExpressions.RegexOptions).Compiled")); + } + + /// + /// Tests logical AND operator + /// + [Test] + public void TestLogicalAndOperator() + { + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "true and true")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "false and false")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "true and false")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "false and true")); + string expression = @"IsMember('Nikola Tesla') and IsMember('Mihajlo Pupin')"; + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(ieee, expression)); + } + + /// + /// Tests bitwise OR operator + /// + [Test] + public void TestBitwiseAndOperator() + { + Assert.AreEqual(1 & 3, ExpressionEvaluator.GetValue(null, "1 and 3")); + Assert.AreEqual(1 & -1, ExpressionEvaluator.GetValue(null, "1 and -1")); + Dictionary vars = new Dictionary(); + vars["ALL"] = (RegexOptions) 0xFFFF; + Assert.AreEqual(RegexOptions.IgnoreCase, ExpressionEvaluator.GetValue(null, "T(System.Text.RegularExpressions.RegexOptions).IgnoreCase and #ALL", vars)); + } + + /// + /// Tests logical NOT operator + /// + [Test] + public void TestLogicalNotOperator() + { + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "!true")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "!false")); + string expression = @"IsMember('Nikola Tesla') and !IsMember('Mihajlo Pupin')"; + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(ieee, expression)); + Assert.AreEqual(~RegexOptions.Compiled, ExpressionEvaluator.GetValue(null, "!T(System.Text.RegularExpressions.RegexOptions).Compiled")); + } + + /// + /// Tests bitwise OR operator + /// + [Test] + public void TestXorOperator() + { + Assert.AreEqual(1 ^ 3, ExpressionEvaluator.GetValue(null, "1 xor 3")); + Assert.AreEqual(1 ^ -1, ExpressionEvaluator.GetValue(null, "1 xor -1")); + Assert.AreEqual(true ^ false, ExpressionEvaluator.GetValue(null, "true xor false")); + Assert.AreEqual(true ^ true, ExpressionEvaluator.GetValue(null, "true xor true")); + Assert.AreEqual(RegexOptions.IgnoreCase ^ RegexOptions.Compiled, ExpressionEvaluator.GetValue(null, "T(System.Text.RegularExpressions.RegexOptions).IgnoreCase xor T(System.Text.RegularExpressions.RegexOptions).Compiled")); + } + + /// + /// Tests logical operator presedance + /// + [Test] + public void TestLogicalOperatorPresedance() + { + // NOT over AND + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "!false and false")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "!false and true")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "!true and false")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "!true and true")); + + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "!(false and false)")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "!(false and true)")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "!(true and false)")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "!(true and true)")); + + // NOT over OR + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "!false or false")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "!false or true")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "!true or false")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "!true or true")); + + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "!(false or false)")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "!(false or true)")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "!(true or false)")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "!(true or true)")); + + // AND over OR + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "false and false or false")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "false and false or true")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "false and true or false")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "false and true or true")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "true and false or false")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "true and false or true")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "true and true or false")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "true and true or true")); + + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "false and (false or false)")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "false and (false or true)")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "false and (true or false)")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "false and (true or true)")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "true and (false or false)")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "true and (false or true)")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "true and (true or false)")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "true and (true or true)")); + } + + /// + /// Tests equality operator. + /// + [Test] + public void TestEqualityOperator() + { + // Null + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "null == null")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "null == 'xyz'")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "123 == null")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "null == 123")); + + // Bool + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "false == false")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "true == true")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "false == true")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "true == false")); + + // Int + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "2 == 2")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "-5 == -5")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "2 == -5")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "-5 == 2")); + + // String + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "'test' == 'test'")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "'Test' == 'test'")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "'test' == 'Test'")); + + // DateTime + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "date('1974-08-24') == date('1974-08-24')")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "DateTime.Today == DateTime.Today")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "DateTime.Today == date('1974-08-24')")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "date('1974-08-24') == DateTime.Today")); + + // Enums + Foo foo = new Foo(FooType.One); + TypeRegistry.RegisterType("FooType", typeof(FooType)); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(foo, "Type == FooType.One")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(foo, "Type == 'One'")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(foo, "Type == 'Two'")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(foo, "FooType.One == Type")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(foo, "'One' == Type")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(foo, "'Two' == Type")); + } + + /// + /// Tests inequality operator. + /// + [Test] + public void TestInqualityOperator() + { + // Null + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "null != null")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "123 != null")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "null != 'xyz'")); + + // Bool + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "false != false")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "true != true")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "false != true")); + + // Int + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "2 != 2.0")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "-5.0 != -5")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "2.0 != -5")); + + // String + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "'test' != 'test'")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "'Test' != 'test'")); + + // DateTime + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "date('1974-08-24') != date('1974-08-24')")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "DateTime.Today != DateTime.Today")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "DateTime.Today != date('1974-08-24')")); + } + + /// + /// Tests less than operator. + /// + [Test] + public void TestLessThanOperator() + { + // Null + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "null < null")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "123 < null")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "null < 'xyz'")); + + // Bool + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "false < true")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "true < true")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "true < false")); + + // Int + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "2 < 2.0")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "-5.0 < 2")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "2 < -5.0")); + + // String + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "'test' < 'test'")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "'Test' < 'test'")); + + // DateTime + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "date('1974-08-24') < date('1974-08-24')")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "date('1974-08-24') < DateTime.Today")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "DateTime.Today < date('1974-08-24')")); + } + + /// + /// Tests less than or equal operator. + /// + [Test] + public void TestLessThanOrEqualOperator() + { + // Null + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "null <= null")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "123 <= null")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "null <= 'xyz'")); + + // Bool + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "false <= true")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "true <= true")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "true <= false")); + + // Int + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "2 <= 2.0")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "-5.0 <= 2")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "2.0 <= -5")); + + // String + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "'test' <= 'test'")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "'Test' <= 'test'")); + + // DateTime + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "date('1974-08-24') <= date('1974-08-24')")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "date('1974-08-24') <= DateTime.Today")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "DateTime.Today <= date('1974-08-24')")); + } + + /// + /// Tests greater than operator. + /// + [Test] + public void TestGreaterThanOperator() + { + // Null + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "null > null")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "123 > null")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "null > 'xyz'")); + + // Bool + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "false > true")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "true > true")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "true > false")); + + // Int + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "2 > 2.0")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "-5.0 > 2")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "2 > -5.0")); + + // String + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "'test' > 'test'")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "'Test' > 'test'")); + + // DateTime + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "date('1974-08-24') > date('1974-08-24')")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "date('1974-08-24') > DateTime.Today")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "DateTime.Today > date('1974-08-24')")); + } + + /// + /// Tests greater than or equal operator. + /// + [Test] + public void TestGreaterThanOrEqualOperator() + { + // Null + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "null >= null")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "123 >= null")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "null >= 'xyz'")); + + // Bool + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "false >= true")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "true >= true")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "true >= false")); + + // Int + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "2.0 >= 2")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "-5 >= 2.0")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "2.0 >= -5")); + + // String + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "'test' >= 'test'")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "'Test' >= 'test'")); + + // DateTime + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "date('1974-08-24') >= date('1974-08-24')")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "date('1974-08-24') >= DateTime.Today")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "DateTime.Today >= date('1974-08-24')")); + } + + /// + /// Tests IN operator. + /// + [Test] + public void TestInOperator() + { + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "null in null")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "3 in {1, 2, 3, 4, 5}")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "!(3 in {1, 2, 3, 4, 5})")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "'xyz' in new string[] {'abc', 'xyz'}")); + Assert.IsTrue( + (bool) ExpressionEvaluator.GetValue(null, "'xyz' in #{'abc' : 'Value 1', 'xyz' : DateTime.Today}")); + } + + /// + /// Tests IS operator. + /// + [Test] + public void TestIsOperator() + { + TypeRegistry.RegisterType(typeof(IList)); + TypeRegistry.RegisterType(typeof(IDictionary)); + + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "null is null")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "5 is null")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "null is int")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "5 is int")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "!(5 is int)")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "{1, 2, 3, 4, 5} is IList")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "new string[] {'abc', 'xyz'} is T(string[])")); + Assert.IsTrue( + (bool) ExpressionEvaluator.GetValue(null, "#{'abc' : 'Value 1', 'xyz' : DateTime.Today} is IDictionary")); + } + + /// + /// Tests BETWEEN operator. + /// + [Test] + public void TestBetweenOperator() + { + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "null between {1, 5}")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "0 between {1, 5}")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "1 between {1, 5}")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "3 between {1, 5}")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "5 between {1, 5}")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "6 between {1, 5}")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "!(6 between {1, 5})")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "'efg' between {'abc', 'xyz'}")); + Assert.IsTrue( + (bool) ExpressionEvaluator.GetValue(null, "DateTime.Today between {DateTime.Today, DateTime.Now}")); + Assert.IsFalse( + (bool) ExpressionEvaluator.GetValue(null, "DateTime.Today between {DateTime.Now, DateTime.Now}")); + } +#if !MONO + /// + /// Tests LIKE operator. + /// + [Test] + public void TestLikeOperator() + { + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "'A' like '?'")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "'Abc' like '?'")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "'Abc' like '[A-Z]b?'")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "'Abc' like '*'")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "'Aleksandar' like 'Aleks*'")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "'Ana Maria Seovic' like '*Maria*'")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, "'Marija Seovic' like '*Seovic'")); + } +#endif + /// + /// Tests MATCHES operator. + /// + [Test] + public void TestMatchesOperator() + { + string emailCheck = + @"^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$"; + + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(emailCheck, "'A' matches #this")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(emailCheck, "'aleks@seovic.com' matches #this")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(emailCheck, "'@seovic.com' matches #this")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(emailCheck, "'seovic.com' matches #this")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(emailCheck, "'aleks' matches #this")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(emailCheck, "'aleks@' matches #this")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(emailCheck, "'aleks@seovic' matches #this")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "'5.0067' matches '^-?\\d+(\\.\\d{2})?$'")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(null, @"'5.00' matches '^-?\d+(\.\d{2})?$'")); + } + + /// + /// Type coercion failure. + /// + [Test] + public void TestTypeCoercionForUncoercableTypes() + { + Assert.Throws(() => ExpressionEvaluator.GetValue(null, "'xyz' > 123")); + } + + /// + /// Type comparison failure. + /// + [Test] + public void TestComparisonOfInstancesThatDoNotImplementIComparable() + { + Dictionary vars = new Dictionary(); + vars["tesla"] = tesla; + vars["pupin"] = pupin; + Assert.Throws(() => ExpressionEvaluator.GetValue(null, "#tesla > #pupin", vars)); + } + + /// + /// Tests addition operator. + /// + [Test] + public void TestAddOperator() + { + // numbers + Assert.AreEqual(2, ExpressionEvaluator.GetValue(null, "1 + 1")); + Assert.AreEqual(2, ExpressionEvaluator.GetValue(null, "1e0 + 1")); + Assert.AreEqual(0, ExpressionEvaluator.GetValue(null, "-1e0 + 1")); + Assert.AreEqual(-2, ExpressionEvaluator.GetValue(null, "-1e0 + -1")); + Assert.AreEqual(Decimal.Parse("2.0", NumberFormatInfo.InvariantInfo), + ExpressionEvaluator.GetValue(null, "1.0m + 1.0")); + Assert.AreEqual(9, ExpressionEvaluator.GetValue(null, "2.0 + 3e0 + 4")); + + // strings + Assert.AreEqual("test string", ExpressionEvaluator.GetValue(null, "'test' + ' ' + 'string'")); + Assert.AreEqual("test 2", ExpressionEvaluator.GetValue(null, "'test' + ' ' + 2")); + Assert.AreEqual("test " + DateTime.Today.ToString(), + ExpressionEvaluator.GetValue(null, "'test' + ' ' + DateTime.Today")); + Assert.AreEqual("test", ExpressionEvaluator.GetValue(null, "'test' + #this")); // can concat null + Assert.AreEqual("test", ExpressionEvaluator.GetValue(null, "#this+'test'")); // can concat null + + // dates + DateTime anaDOB = new DateTime(2004, 8, 14); + DateTime aleksDOB = new DateTime(1974, 8, 24); + TimeSpan diff = anaDOB - aleksDOB; + IDictionary vars = new Dictionary(); + vars["ts"] = diff; + + Assert.AreEqual(anaDOB, ExpressionEvaluator.GetValue(null, "date('1974-08-24') + #ts", vars)); + Assert.AreEqual(new DateTime(1974, 8, 29), ExpressionEvaluator.GetValue(null, "date('1974-08-24') + 5")); + Assert.AreEqual(new DateTime(1974, 8, 29), + ExpressionEvaluator.GetValue(null, "date('1974-08-24') + '5.0:0'")); + } + + /// + /// Tests addition operator with invalid arguments. + /// + [Test] + public void TestAddOperatorWithInvalidArguments() + { + Assert.Throws(() => ExpressionEvaluator.GetValue(null, "DateTime.Today + false")); + } + + /// + /// Tests subtraction operator. + /// + [Test] + public void TestSubtractOperator() + { + // numbers + Assert.AreEqual(2, ExpressionEvaluator.GetValue(null, "3 - 1")); + Assert.AreEqual(-2, ExpressionEvaluator.GetValue(null, "1 - 3")); + Assert.AreEqual(4, ExpressionEvaluator.GetValue(null, "1 - -3")); + Assert.AreEqual(Decimal.Parse("-9000.00", NumberFormatInfo.InvariantInfo), + ExpressionEvaluator.GetValue(null, "1000.00m - 1e4")); + Assert.AreEqual(-5, ExpressionEvaluator.GetValue(null, "2.0 - 3e0 - 4")); + + // dates + DateTime anaDOB = new DateTime(2004, 8, 14); + DateTime aleksDOB = new DateTime(1974, 8, 24); + TimeSpan diff = anaDOB - aleksDOB; + Dictionary vars = new Dictionary(); + vars["ts"] = diff; + + Assert.AreEqual(aleksDOB, ExpressionEvaluator.GetValue(null, "date('2004-08-14') - #ts", vars)); + Assert.AreEqual(diff, ExpressionEvaluator.GetValue(null, "date('2004-08-14') - date('1974-08-24')")); + Assert.AreEqual(new DateTime(1974, 8, 19), ExpressionEvaluator.GetValue(null, "date('1974-08-24') - 5")); + Assert.AreEqual(new DateTime(1974, 8, 19), + ExpressionEvaluator.GetValue(null, "date('1974-08-24') - '5.0:0'")); + } + + /// + /// Tests subtraction operator with invalid arguments. + /// + [Test] + public void TestSubtractOperatorWithInvalidArguments() + { + Assert.Throws(() => ExpressionEvaluator.GetValue(null, "DateTime.Today - false")); + } + + /// + /// Tests multiplication operator. + /// + [Test] + public void TestMultiplyOperator() + { + Assert.AreEqual(4, ExpressionEvaluator.GetValue(null, "2 * 2")); + Assert.AreEqual(-6, ExpressionEvaluator.GetValue(null, "2 * -3")); + Assert.AreEqual(6, ExpressionEvaluator.GetValue(null, "-2 * -3")); + Assert.AreEqual(Decimal.Parse("1000000.00", NumberFormatInfo.InvariantInfo), + ExpressionEvaluator.GetValue(null, "1000.00m * 1e3")); + Assert.AreEqual(24, ExpressionEvaluator.GetValue(null, "2.0 * 3e0 * 4")); + } + + /// + /// Tests multiplication operator with invalid arguments. + /// + [Test] + public void TestMultiplyOperatorWithInvalidArguments() + { + Assert.Throws(() => ExpressionEvaluator.GetValue(null, "DateTime.Today * false")); + } + + /// + /// Tests division operator. + /// + [Test] + public void TestDivideOperator() + { + Assert.AreEqual(1, ExpressionEvaluator.GetValue(null, "2 / 2")); + Assert.AreEqual(-2, ExpressionEvaluator.GetValue(null, "6 / -3")); + Assert.AreEqual(2, ExpressionEvaluator.GetValue(null, "-6 / -3")); + Assert.AreEqual(Decimal.Parse("1.00", NumberFormatInfo.InvariantInfo), + ExpressionEvaluator.GetValue(null, "1000.00m / 1e3")); + Assert.AreEqual(1, ExpressionEvaluator.GetValue(null, "8.0 / 4e0 / 2")); + } + + /// + /// Tests division operator with invalid arguments. + /// + [Test] + public void TestDivideOperatorWithInvalidArguments() + { + Assert.Throws(() => ExpressionEvaluator.GetValue(null, "DateTime.Today / false")); + } + + /// + /// Tests modulus operator. + /// + [Test] + public void TestModulusOperator() + { + Assert.AreEqual(0, ExpressionEvaluator.GetValue(null, "2 % 2")); + Assert.AreEqual(2, ExpressionEvaluator.GetValue(null, "6 % -4")); + Assert.AreEqual(-1, ExpressionEvaluator.GetValue(null, "-6 % -5")); + Assert.AreEqual(Decimal.Parse("5.00", NumberFormatInfo.InvariantInfo), + ExpressionEvaluator.GetValue(null, "1005.00m % 1e3")); + Assert.AreEqual(1, ExpressionEvaluator.GetValue(null, "8.0 % 5e0 % 2")); + } + + /// + /// Tests modulus operator with invalid arguments. + /// + [Test] + public void TestModulusOperatorWithInvalidArguments() + { + Assert.Throws(() => ExpressionEvaluator.GetValue(null, "DateTime.Today % false")); + } + + /// + /// Tests power operator. + /// + [Test] + public void TestPowerOperator() + { + Assert.AreEqual(8, ExpressionEvaluator.GetValue(null, "2 ^ +3")); + Assert.AreEqual(16, ExpressionEvaluator.GetValue(null, "-2 ^ 4")); + Assert.AreEqual(-32, ExpressionEvaluator.GetValue(null, "-2 ^ 5")); + Assert.AreEqual(.0625, ExpressionEvaluator.GetValue(null, "4 ^ -2")); + Assert.AreEqual(2, ExpressionEvaluator.GetValue(null, "+4 ^ .5")); + } + + /// + /// Tests power operator with invalid arguments. + /// + [Test] + public void TestPowerOperatorWithInvalidArguments() + { + Assert.Throws(() => ExpressionEvaluator.GetValue(null, "DateTime.Today ^ false")); + } + + /// + /// Tests unary minus operator with invalid argument. + /// + [Test] + public void TestUnaryMinusOperatorWithInvalidArguments() + { + Assert.Throws(() => ExpressionEvaluator.GetValue(null, "-false")); + } + + /// + /// Tests unary plus operator with invalid argument. + /// + [Test] + public void TestUnaryPlusOperatorWithInvalidArguments() + { + Assert.Throws(() => ExpressionEvaluator.GetValue(null, "+false")); + } + + /// + /// Tests operator precedence. + /// + [Test] + public void TestOperatorPrecedence() + { + Assert.AreEqual(-3, ExpressionEvaluator.GetValue(null, "1+2-3*8/2/2")); + Assert.AreEqual(-45, ExpressionEvaluator.GetValue(null, "1+2-3*8^2/2/2")); + Assert.AreEqual(0, ExpressionEvaluator.GetValue(null, "1+2-3*8/2^2/2")); + Assert.AreEqual(-4.5, ExpressionEvaluator.GetValue(null, "1+(2-3*8)/2.0/2")); + } + + /// + /// Tests Spring reference when reference to a non-existant object is specified. + /// + [Test] + public void TestReferenceForNonExistantObject() + { + ContextRegistry.RegisterContext(new XmlApplicationContext(false, "assembly://Spring.Core.Tests/Spring.Context.Support/objects.xml")); + Assert.Throws(() => ExpressionEvaluator.GetValue(null, "@(dummyRef)")); + } + + /// + /// Tests Spring reference. + /// + [Test] + public void TestReference() + { + ContextRegistry.RegisterContext( + new XmlApplicationContext(false, "assembly://Spring.Core.Tests/Spring.Context.Support/objects.xml")); + Assert.AreEqual(typeof(TestObject), ExpressionEvaluator.GetValue(null, "@(goran)").GetType()); + + IApplicationContext ctx = + new XmlApplicationContext(false, "assembly://Spring.Core.Tests/Spring.Context.Support/objects.xml"); + ctx.Name = "myContext"; + ContextRegistry.RegisterContext(ctx); + + Assert.AreEqual(typeof(TestObject), + ExpressionEvaluator.GetValue(null, "@(myContext:goran)").GetType()); + + // string literals allowed for contextname + Assert.AreEqual(typeof(TestObject), + ExpressionEvaluator.GetValue(null, "@('myContext':goran)").GetType()); + } + + /// + /// Since Expression-References require the context to be added to ContextRegistry, + /// they work only if the objectdefinition's "lazy-init" is true. + /// + [Test] + public void TestReferenceByExpression() + { + //TODO: write a test showing that expressions don't work without "lazy-init": + /* + + + + + */ + + ContextRegistry.RegisterContext( + new XmlApplicationContext(false, "assembly://Spring.Core.Tests/Spring.Context.Support/objects.xml")); + + TestObject testObject = ExpressionEvaluator.GetValue(null, "@(goran)") as TestObject; + + TestObjectContainer testObjectContainer = + ExpressionEvaluator.GetValue(null, "@(testObjectContainer_lazy)") as TestObjectContainer; + + Assert.IsNotNull(testObject); + Assert.AreSame(testObject, testObjectContainer.TestObject); + } + + /// + /// Ensure context-names my contain dots and slashes + /// + [Test] + public void TestQualifiedNameMayContainDotsAndSlashes() + { + IApplicationContext ctx = + new XmlApplicationContext(false, "assembly://Spring.Core.Tests/Spring.Context.Support/objects.xml"); + ctx.Name = @"my.Context/bla\"; + ContextRegistry.RegisterContext(ctx); + + Assert.AreEqual(typeof(TestObject), + ExpressionEvaluator.GetValue(null, @"@(my.Context/bla\:goran)").GetType()); +// Assert.AreEqual(typeof(TestObject), +// ExpressionEvaluator.GetValue(null, "@(my\\.Context:goran)").GetType()); + } + + /// + /// Tests attribute expression. + /// + [Test] + public void TestAttribute() + { + TypeRegistry.RegisterType("WebMethod", typeof(WebMethodAttribute)); + TypeRegistry.RegisterType("TransactionOption", typeof(TransactionOption)); + + Assert.IsInstanceOf(typeof(SerializableAttribute), + ExpressionEvaluator.GetValue(null, "@[System.Serializable]")); + Assert.IsInstanceOf(typeof(SerializableAttribute), + ExpressionEvaluator.GetValue(null, "@[System.Serializable()]")); + Assert.IsInstanceOf(typeof(WebMethodAttribute), ExpressionEvaluator.GetValue(null, "@[WebMethod]")); + + WebMethodAttribute webMethod = (WebMethodAttribute) ExpressionEvaluator.GetValue(null, "@[WebMethod(true)]"); + Assert.IsTrue(webMethod.EnableSession); + + webMethod = (WebMethodAttribute) + ExpressionEvaluator.GetValue( + null, + "@[WebMethod(false, CacheDuration = 60, Description = 'my web method', TransactionOption = TransactionOption.Required)]"); + Assert.AreEqual(60, webMethod.CacheDuration); + Assert.AreEqual("my web method", webMethod.Description); + Assert.AreEqual(TransactionOption.Required, webMethod.TransactionOption); + } + + [Test] + public void TestDelegateFunctionExpressions() + { + //for purposes of an example in documentation + Dictionary vars = new Dictionary(); + vars["sqrt"] = new DoubleFunction(Sqrt); + double result = (double) ExpressionEvaluator.GetValue(null, "#sqrt(64)", vars); + Assert.AreEqual(8, result); + + vars = new Dictionary(); + vars["max"] = new DoubleFunctionTwoArgs(Max); + result = (double) ExpressionEvaluator.GetValue(null, "#max(5,25)", vars); + Assert.AreEqual(25, result); + } + + private delegate double DoubleFunction(double arg); + + private double Sqrt(double arg) + { + return Math.Sqrt(arg); + } + + private delegate double DoubleFunctionTwoArgs(double arg1, double arg2); + + private double Max(double arg1, double arg2) + { + return Math.Max(arg1, arg2); + } + + /// + /// Type lambda expressions. + /// + [Test] + public void TestLambdaExpressions() + { + TypeRegistry.RegisterType(typeof(Math)); + + // simple function + Assert.AreEqual(4, + ExpressionEvaluator.GetValue(null, "(#add = {|x, y| $x + $y}; #add(2, 2))", new Dictionary())); + Assert.AreEqual(25, + ExpressionEvaluator.GetValue(null, "(#max = {|x, y| $x > $y ? $x : $y }; #max(5,25))", + new Dictionary())); + + // recursive function + Assert.AreEqual(120, + ExpressionEvaluator.GetValue(null, + "(#fact = {|n| $n <= 1 ? 1 : $n * #fact($n-1) }; #fact(5))", + new Dictionary())); + + // function invoked within projection expression + string expr = "(#upper = {|txt| $txt.ToUpper() }; !{ #upper(Name) })"; + IList upperNames = (IList) ExpressionEvaluator.GetValue(ieee.Members, expr, new Dictionary()); + Assert.AreEqual("NIKOLA TESLA", upperNames[0]); + Assert.AreEqual("MIHAJLO PUPIN", upperNames[1]); + + // function that delegates to a function passed as a parameter + Dictionary vars = new Dictionary(); + Expression.RegisterFunction("sqrt", "{|n| Math.Sqrt($n)}", vars); + Expression.RegisterFunction("fact", "{|n| $n <= 1 ? 1 : $n * #fact($n-1)}", vars); + string expr2 = + @"( + #delegate = {|f,n| $f($n) }; + #d = #delegate; + + #result = { #delegate(#sqrt, 4), #d(#fact, 5), #delegate({|n| $n ^ 2 }, 5) } + )"; + IList results = (IList) ExpressionEvaluator.GetValue(null, expr2, vars); + Assert.AreEqual(2, results[0]); + Assert.AreEqual(120, results[1]); + Assert.AreEqual(25, results[2]); + + // function assignment + Assert.AreEqual(120, + ExpressionEvaluator.GetValue(null, + "(#fact = {|n| $n <= 1 ? 1 : $n * #fact($n-1) }; #f = #fact; #f(5))", + new Dictionary())); + } + + #region Collection Processor and Aggregator tests + + [Test] + public void TestCountAggregator() + { + int[] arr = new int[] { 24, 8, 14, 8 }; + Assert.AreEqual(4, ExpressionEvaluator.GetValue(arr, "count()")); + Assert.AreEqual(3, ExpressionEvaluator.GetValue(null, "{1, 5, -3}.count()")); + Assert.AreEqual(0, ExpressionEvaluator.GetValue(null, "count()")); + } + + [Test] + public void TestCustomCollectionProcessor() + { + // Test for the purposes of creating documentation example. + Dictionary vars = new Dictionary(); + vars["EvenSum"] = new IntEvenSumCollectionProcessor(); + Assert.AreEqual(6, ExpressionEvaluator.GetValue(null, "{1, 2, 3, 4}.EvenSum()", vars)); + } + + private class IntEvenSumCollectionProcessor : ICollectionProcessor + { + public object Process(ICollection source, object[] args) + { + object total = 0d; + foreach (object item in source) + { + if (item != null) + { + if (NumberUtils.IsInteger(item)) + { + if ((int) item % 2 == 0) + { + total = NumberUtils.Add(total, item); + } + } + else + { + throw new ArgumentException("Sum can only be calculated for a collection of numeric values."); + } + } + } + + return total; + } + } + + [Test] + public void TestSumAggregator() + { + int[] arr = new int[] { 24, 8, 14, 8 }; + Assert.AreEqual(54, ExpressionEvaluator.GetValue(arr, "sum()")); + Assert.AreEqual(13, ExpressionEvaluator.GetValue(null, "{1, 5, -3, 10}.sum()")); + + object[] arr2 = new object[] { 5, 5.8, 12.2, 1 }; + object result = ExpressionEvaluator.GetValue(arr2, "sum()"); + Assert.IsInstanceOf(typeof(double), result); + Assert.AreEqual(24, result); + } + + [Test] + public void TestSumAggregatorWithNonNumber() + { + object[] arr = new object[] { 5, "ana", 12.2, 1 }; + Assert.Throws(() => ExpressionEvaluator.GetValue(arr, "sum()")); + } + + [Test] + public void TestAverageAggregator() + { + int[] arr = new int[] { 24, 8, 16, 8 }; + Assert.AreEqual(14, ExpressionEvaluator.GetValue(arr, "average()")); + Assert.AreEqual(3, ExpressionEvaluator.GetValue(null, "{1, 5, -4, 10}.average()")); + Assert.AreEqual(3.5, ExpressionEvaluator.GetValue(null, "{1, 5, -2, 10}.average()")); + + object[] arr2 = new object[] { 5, 5.8, 12.2, 1 }; + object result = ExpressionEvaluator.GetValue(arr2, "average()"); + Assert.IsInstanceOf(typeof(double), result); + Assert.AreEqual(6, result); + } + + [Test] + public void TestAverageAggregatorWithNonNumber() + { + object[] arr = new object[] { 5, "ana", 12.2, 1 }; + Assert.Throws(() => ExpressionEvaluator.GetValue(arr, "average()")); + } + + [Test] + public void TestMinAggregator() + { + int[] arr = new int[] { 24, 8, 14, 8 }; + Assert.AreEqual(8, ExpressionEvaluator.GetValue(arr, "min()")); + Assert.AreEqual(-3, ExpressionEvaluator.GetValue(null, "{1, 5, -3, 10}.min()")); + + object[] arr2 = new object[] { 5, 5.8, 12.2, 1 }; + object result = ExpressionEvaluator.GetValue(arr2, "min()"); + Assert.IsInstanceOf(typeof(int), result); + Assert.AreEqual(1, result); + + Assert.IsNull(ExpressionEvaluator.GetValue(ObjectUtils.EmptyObjects, "min()")); + } + + [Test] + public void TestMinAggregatorWithNonComparable() + { + object[] arr = new object[] { new Object(), new Object() }; + Assert.Throws(() => ExpressionEvaluator.GetValue(arr, "min()")); + } + + [Test] + public void TestMinAggregatorWithMixedTypes() + { + object[] arr = new object[] { 5, "ana", 12.2, 1 }; + Assert.Throws(() => ExpressionEvaluator.GetValue(arr, "min()")); + } + + [Test] + public void TestMaxAggregator() + { + int[] arr = new int[] { 24, 8, 14, 8 }; + Assert.AreEqual(24, ExpressionEvaluator.GetValue(arr, "max()")); + Assert.AreEqual(10, ExpressionEvaluator.GetValue(null, "{1, 5, -3, 10}.max()")); + + object[] arr2 = new object[] { 5, 5.8, 12.2, 1 }; + object result = ExpressionEvaluator.GetValue(arr2, "max()"); + Assert.IsInstanceOf(typeof(double), result); + Assert.AreEqual(12.2, result); + + Assert.IsNull(ExpressionEvaluator.GetValue(ObjectUtils.EmptyObjects, "max()")); + } + + [Test] + public void TestMaxAggregatorWithNonComparable() + { + object[] arr = new object[] { new Object(), new Object() }; + Assert.Throws(() => ExpressionEvaluator.GetValue(arr, "max()")); + } + + [Test] + public void TestMaxAggregatorWithMixedTypes() + { + object[] arr = new object[] { 5, "ana", 12.2, 1 }; + Assert.Throws(() => ExpressionEvaluator.GetValue(arr, "max()")); + } + + [Test] + public void TestSortProcessor() + { + int[] arr = new int[] { 24, 8, 14, 6 }; + Assert.AreEqual(new int[] { 6, 8, 14, 24 }, ExpressionEvaluator.GetValue(arr, "sort()")); + Assert.AreEqual(new int[] { 6, 8, 14, 24 }, ExpressionEvaluator.GetValue(arr, "sort(true)")); + Assert.AreEqual(new int[] { 24, 14, 8, 6 }, ExpressionEvaluator.GetValue(arr, "sort(false)")); + + string[] arr2 = new string[] { "abc", "xyz", "stuv", "efg", "dcb" }; + Assert.AreEqual(new string[] { "abc", "dcb", "efg", "stuv", "xyz" }, + ExpressionEvaluator.GetValue(arr2, "sort()")); + + DateTime[] arr3 = new DateTime[] { DateTime.Today, DateTime.MaxValue, DateTime.MinValue }; + Assert.AreEqual(new DateTime[] { DateTime.MinValue, DateTime.Today, DateTime.MaxValue }, + ExpressionEvaluator.GetValue(arr3, "sort()")); + + Assert.AreEqual(new object[] { -3.3, 1.2, 5.5 }, ExpressionEvaluator.GetValue(null, "{1.2, 5.5, -3.3}.sort()")); + Assert.IsNull(ExpressionEvaluator.GetValue(null, "sort()")); + + ISet set = new ListSet(arr); + Assert.AreEqual(new int[] { 6, 8, 14, 24 }, ExpressionEvaluator.GetValue(set, "sort()")); + } + + [Test(Description = "sort supports any ICollection containing elements of uniform type")] + public void TestSortProcessorWithSimpleICollectionType() + { + Stack stack = new Stack(new int[] { 24, 8, 14, 6 }); + ExpressionEvaluator.GetValue(stack, "sort()"); + } + + [Test] + public void TestNonNullProcessor() + { + string[] arr2 = new string[] { "abc", "xyz", null, "abc", "def", null }; + Assert.AreEqual(new string[] { "abc", "xyz", "abc", "def" }, + ExpressionEvaluator.GetValue(arr2, "nonNull()")); + Assert.AreEqual(new string[] { "abc", "abc", "def", "xyz" }, + ExpressionEvaluator.GetValue(arr2, "nonNull().sort()")); + } + + [Test] + public void TestDistinctProcessor() + { + int[] arr = new int[] { 24, 8, 8, 6, 24, 6, 8, 6 }; + Assert.AreEqual(new int[] { 6, 8, 24 }, ExpressionEvaluator.GetValue(arr, "distinct().sort()")); + + string[] arr2 = new string[] { "abc", "xyz", "abc", "def", null, "def" }; + Assert.AreEqual(new string[] { null, "abc", "def", "xyz" }, + ExpressionEvaluator.GetValue(arr2, "distinct(true).sort()")); + Assert.AreEqual(new string[] { "abc", "def", "xyz" }, + ExpressionEvaluator.GetValue(arr2, "distinct(false).sort()")); + Assert.AreEqual(new string[] { "abc", "def", "xyz" }, + ExpressionEvaluator.GetValue(arr2, "distinct().sort()")); + } + + [Test] + public void TestDistinctProcessorWithInvalidArgumentType() + { + int[] arr = new int[] { 24, 8, 8, 6, 24, 6, 8, 6 }; + Assert.Throws(() => ExpressionEvaluator.GetValue(arr, "distinct(6)")); + } + + [Test] + public void TestDistinctProcessorWithInvalidNumberOfArguments() + { + int[] arr = new int[] { 24, 8, 8, 6, 24, 6, 8, 6 }; + Assert.Throws(() => ExpressionEvaluator.GetValue(arr, "distinct(true, 4, 'xyz')")); + } + + [Test] + public void TestConversionProcessor() + { + object[] arr = new object[] { "0", 1, 1.1m, "1.1", 1.1f }; + decimal[] result = (decimal[]) ExpressionEvaluator.GetValue(arr, "convert(decimal)"); + Assert.AreEqual(0.0m, result[0]); + Assert.AreEqual(1.0m, result[1]); + Assert.AreEqual(1.1m, result[2]); + Assert.AreEqual(1.1m, result[3]); + Assert.AreEqual(1.1m, result[4]); + } + + [Test] + public void TestReverseProcessor() + { + object[] arr = new object[] { "0", 1, 2.1m, "3", 4.1f }; + object[] result = new ArrayList((ICollection) ExpressionEvaluator.GetValue(arr, "reverse()")).ToArray(); + Assert.AreEqual(new object[] { 4.1f, "3", 2.1m, 1, "0" }, result); + } + + #endregion + + /// + /// Type SetValue. + /// + [Test] + public void TestSetValue() + { + Dictionary vars = new Dictionary(); + vars["tesla"] = tesla; + vars["pupin"] = pupin; + ExpressionEvaluator.SetValue(null, "#tesla.Name", vars, "Tesla, Nikola"); + Assert.AreEqual("Tesla, Nikola", tesla.Name); + } + + /// + /// Tests property access with null in the path. + /// + [Test] + public void TestPropertyGetWithNullInThePath() + { + Assert.Throws(() => ExpressionEvaluator.GetValue(new Inventor(), "Name.Length")); + } + + /// + /// Tests property set with null in the path. + /// + [Test] + public void TestPropertySetWithNullInThePath() + { + Assert.Throws(() => ExpressionEvaluator.SetValue(new Inventor(), "Name.Length", 20)); + } + + /// + /// Tries to set value of the PropertyOrFieldNode that represents type. + /// + [Test] + public void TestTypeSet() + { + Assert.Throws(() => ExpressionEvaluator.SetValue(null, "DateTime", 20)); + } + + /// + /// Reproduce SPRNET-408. + /// + /// + /// http://opensource.atlassian.com/projects/spring/browse/SPRNET-408 + /// http://forum.springframework.net/showthread.php?t=933 + /// + [Test(Description = "Test to reproduce SPRNET-408")] + public void TestNullableTypes() + { + Foo foo = new Foo(); + Assert.IsNull(ExpressionEvaluator.GetValue(foo, "NullableDate")); + Assert.IsNull(ExpressionEvaluator.GetValue(foo, "NullableInt")); + + ExpressionEvaluator.SetValue(foo, "NullableDate", DateTime.Today); + ExpressionEvaluator.SetValue(foo, "NullableDate", null); + ExpressionEvaluator.SetValue(foo, "NullableDate", "2004-08-14"); + ExpressionEvaluator.SetValue(foo, "NullableDate", DateTime.Today); + ExpressionEvaluator.SetValue(foo, "NullableInt", 1); + ExpressionEvaluator.SetValue(foo, "NullableInt", null); + ExpressionEvaluator.SetValue(foo, "NullableInt", "5"); + ExpressionEvaluator.SetValue(foo, "NullableInt", 1); + + Assert.IsInstanceOf(typeof(DateTime?), ExpressionEvaluator.GetValue(foo, "NullableDate")); + Assert.IsInstanceOf(typeof(Int32?), ExpressionEvaluator.GetValue(foo, "NullableInt")); + + Assert.AreEqual(DateTime.Today, ExpressionEvaluator.GetValue(foo, "NullableDate")); + Assert.AreEqual(1, ExpressionEvaluator.GetValue(foo, "NullableInt")); + + int? test = 1; + Assert.IsInstanceOf(typeof(Int32?), ExpressionEvaluator.GetValue(test, "#root")); + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(test, "#root != null")); + Assert.AreEqual(1, ExpressionEvaluator.GetValue(test, "#root")); + + test = null; + Assert.IsTrue((bool) ExpressionEvaluator.GetValue(test, "#root == null")); + Assert.IsNull(ExpressionEvaluator.GetValue(test, "#root")); + } + + /// + /// Reproduce SPRNET-462. + /// + /// + /// http://opensource.atlassian.com/projects/spring/browse/SPRNET-462 + /// http://forum.springframework.net/showthread.php?t=1515 + /// + [Test(Description = "Test to reproduce SPRNET-462")] + public void TestMethodResolutionWithNullArguments() + { + DateTime today = DateTime.Today; + Assert.AreEqual(today.ToString("d"), ExpressionEvaluator.GetValue(today, "ToString('d')")); + + TypeRegistry.RegisterType(typeof(TypeRegistry)); + try + { + ExpressionEvaluator.GetValue(null, "TypeRegistry.RegisterType(null)"); + Assert.Fail("Should throw ArgumentNullException"); + } + catch (ArgumentNullException) + { + } + + try + { + ExpressionEvaluator.GetValue(null, "TypeRegistry.RegisterType(null, 'System.Object')"); + Assert.Fail("Should throw ArgumentNullException"); + } + catch (ArgumentNullException) + { + } + + try + { + ExpressionEvaluator.GetValue(null, "TypeRegistry.RegisterType(null, null)"); + Assert.Fail("Should throw AmbiguousMatchException"); + } + catch (AmbiguousMatchException) + { + } + + try + { + ExpressionEvaluator.GetValue(null, "TypeRegistry.RegisterType(null, null, null)"); + Assert.Fail("Should throw ArgumentException"); + } + catch (ArgumentException) + { + } + + try + { + ExpressionEvaluator.GetValue(null, "TypeRegistry.RegisterType(int, string)"); + Assert.Fail("Should throw ArgumentException"); + } + catch (ArgumentException) + { + } + } + + /// + /// Reproduce SPRNET-464. + /// + /// + /// http://opensource.atlassian.com/projects/spring/browse/SPRNET-464 + /// http://forum.springframework.net/showthread.php?t=1515 + /// + [Test(Description = "Test to reproduce SPRNET-464")] + public void TestMethodResolutionWithParamArray() + { + Foo foo = new Foo(); + Assert.AreEqual("a|b|c", foo.MethodWithArrayArgument(new string[] { "a", "b", "c" })); + Assert.AreEqual("a||c", foo.MethodWithArrayArgument(new string[] { "a", null, "c" })); + Assert.AreEqual("a|b|c", foo.MethodWithParamArray("a", "b", "c")); + Assert.AreEqual("a||c", foo.MethodWithParamArray("a", null, "c")); + + Assert.AreEqual("a|b|c", ExpressionEvaluator.GetValue(foo, "MethodWithArrayArgument(new string[] { 'a', 'b', 'c' })")); + Assert.AreEqual("a||c", ExpressionEvaluator.GetValue(foo, "MethodWithArrayArgument(new string[] { 'a', null, 'c' })")); + Assert.AreEqual("a|b|c", ExpressionEvaluator.GetValue(foo, "MethodWithParamArray('a', 'b', 'c')")); + Assert.AreEqual("a||c", ExpressionEvaluator.GetValue(foo, "MethodWithParamArray('a', null, 'c')")); + + Assert.AreEqual("a|b|c", ExpressionEvaluator.GetValue(foo, "MethodWithParamArray(false, 'a', 'b', 'c')")); + Assert.AreEqual("a||c", ExpressionEvaluator.GetValue(foo, "MethodWithParamArray(false, 'a', null, 'c')")); + Assert.AreEqual("A|B|C", ExpressionEvaluator.GetValue(foo, "MethodWithParamArray(true, 'a', 'b', 'c')")); + Assert.AreEqual("A||C", ExpressionEvaluator.GetValue(foo, "MethodWithParamArray(true, 'a', null, 'c')")); + } + + [Test] + public void TestMethodResolutionResolvesToExactMatchOfArgumentTypes() + { + Dictionary args = new Dictionary(); + args["bars"] = new Bar[] { new Bar() }; + Foo foo = new Foo(); + + // ensure no one changed our test class + Assert.AreEqual("ExactMatch", foo.MethodWithSimilarArguments(1, (Bar[]) args["bars"])); + Assert.AreEqual("AssignableMatch", foo.MethodWithSimilarArguments(1, (ICollection) args["bars"])); + + Assert.AreEqual("ExactMatch", ExpressionEvaluator.GetValue(foo, "MethodWithSimilarArguments(1, #bars)", args)); + } + + /// + /// Test to show that a large number of parameters can be passed to methods + /// + [Test] + public void TestMethodResolutionWithLargeNumberOfParametersDoesNotThrow() + { + int expectedResult = 150; + int result = 0; + + Foo foo = new Foo(); + string expression = $"MethodWithParamArray({String.Join(", ", Enumerable.Range(0, expectedResult))})"; + + Assert.DoesNotThrow(() => + { + result = (int) ExpressionEvaluator.GetValue(foo, expression); + }); + + Assert.AreEqual(expectedResult, result); + } + + [Test] + public void TestIndexerResolutionResolvesToExactMatchOfArgumentTypes() + { + Dictionary args = new Dictionary(); + args["bars"] = new Bar[] { new Bar() }; + Foo foo = new Foo(); + + // ensure no one changed our test class + Assert.AreEqual("ExactMatch", foo[(Bar[]) args["bars"]]); + Assert.AreEqual("AssignableMatch", foo[(ICollection) args["bars"]]); + + Assert.AreEqual("ExactMatch", ExpressionEvaluator.GetValue(foo, "#root[#bars]", args)); + } + + [Test] + public void TestCtorResolutionResolvesToExactMatchOfArgumentTypes() + { + TypeRegistry.RegisterType(typeof(Foo)); + Dictionary args = new Dictionary(); + args["bars"] = new Bar[] { new Bar() }; + + // ensure no one changed our test class + Foo foo1 = new Foo(1, (Bar[]) args["bars"]); + try + { + Foo foo2 = new Foo(1, (ICollection) args["bars"]); + } + catch (InvalidOperationException) { } + + Assert.IsNotNull(ExpressionEvaluator.GetValue(null, "new Foo(1, #bars)", args)); + } + + [Test] + public void TestCtorResolutionWithParamArray() + { + TypeRegistry.RegisterType(typeof(Foo)); + Assert.IsNotNull(ExpressionEvaluator.GetValue(null, "new Foo('a', 'b', 'c')")); + Assert.IsNotNull(ExpressionEvaluator.GetValue(null, "new Foo('a', null, 'c')")); + Assert.IsNotNull(ExpressionEvaluator.GetValue(null, "new Foo(false, 'a', 'b', 'c')")); + Assert.IsNotNull(ExpressionEvaluator.GetValue(null, "new Foo(false, 'a', null, 'c')")); + } + + /// + /// Reproduce SPRNET-470. + /// + /// + /// http://opensource.atlassian.com/projects/spring/browse/SPRNET-470 + /// http://forum.springframework.net/showthread.php?t=1574 + /// + [Test(Description = "Test to reproduce SPRNET-470")] + public void TestPropertyAccessForTypes() + { + Assert.AreEqual(Int32.MaxValue, ExpressionEvaluator.GetValue(null, "Int32.MaxValue")); + Assert.AreEqual(Int32.MaxValue, ExpressionEvaluator.GetValue(null, "T(System.Int32).MaxValue")); + Assert.AreEqual(typeof(Int32).FullName, ExpressionEvaluator.GetValue(null, "Int32.FullName")); + Assert.AreEqual(typeof(Int32).FullName, ExpressionEvaluator.GetValue(null, "T(System.Int32).FullName")); + Assert.IsFalse((bool) ExpressionEvaluator.GetValue(null, "Int32.IsSubclassOf(Int64)")); + + TypeRegistry.RegisterType(typeof(FooType)); + Assert.AreEqual(FooType.One, ExpressionEvaluator.GetValue(null, "FooType.One")); + Assert.AreEqual(typeof(FooType).FullName, ExpressionEvaluator.GetValue(null, "FooType.FullName")); + } + + /// + /// Reproduce SPRNET-450 + /// Try to set/get numeric value from enum type property/field + /// + /// + /// http://opensource.atlassian.com/projects/spring/browse/SPRNET-450 + /// http://forum.springframework.net/showthread.php?t=1353 + /// + [Test] + public void TestSetEnumTypePropertyOrFieldFromNumeric() + { + //object val = Convert.ChangeType((Int16) 1, typeof(Int32)); + //Assert.AreEqual( typeof(Int32), val.GetType() ); + + IExpression expField = Expression.Parse("SampleEnumField"); + IExpression expProperty = Expression.Parse("SampleEnumProperty"); + IExpression expFlagsField = Expression.Parse("SampleFlagsEnumField"); + IExpression expFlagsProperty = Expression.Parse("SampleFlagsEnumProperty"); + + TestEnumTypePropertyClass o = new TestEnumTypePropertyClass(); + + // test field set operations + expField.SetValue(o, TestEnumTypePropertyClass.ESampleEnumType.Trunk); + Assert.AreEqual(TestEnumTypePropertyClass.ESampleEnumType.Trunk, o.SampleEnumField); + + expField.SetValue(o, (short) 1); + Assert.AreEqual(TestEnumTypePropertyClass.ESampleEnumType.Trunk, o.SampleEnumField); + + expField.SetValue(o, 1); + Assert.AreEqual(TestEnumTypePropertyClass.ESampleEnumType.Trunk, o.SampleEnumField); + + expField.SetValue(o, (long) 1); + Assert.AreEqual(TestEnumTypePropertyClass.ESampleEnumType.Trunk, o.SampleEnumField); + + // test property set operations + expProperty.SetValue(o, TestEnumTypePropertyClass.ESampleEnumType.Trunk); + Assert.AreEqual(TestEnumTypePropertyClass.ESampleEnumType.Trunk, o.SampleEnumField); + + expProperty.SetValue(o, (short) 1); + Assert.AreEqual(TestEnumTypePropertyClass.ESampleEnumType.Trunk, o.SampleEnumField); + + expProperty.SetValue(o, 1); + Assert.AreEqual(TestEnumTypePropertyClass.ESampleEnumType.Trunk, o.SampleEnumField); + + expProperty.SetValue(o, (long) 1); + Assert.AreEqual(TestEnumTypePropertyClass.ESampleEnumType.Trunk, o.SampleEnumField); + + expProperty.SetValue(o, "Trunk"); + Assert.AreEqual(TestEnumTypePropertyClass.ESampleEnumType.Trunk, o.SampleEnumField); + + try + { + expProperty.SetValue(o, 1.0); + Assert.Fail("should throw"); + } + catch (TypeMismatchException e) + { + Assert.IsTrue(e.Message.StartsWith("Cannot convert property value of type [System.Double]")); + } + + try + { + expProperty.SetValue(o, ((float) 1.0)); + Assert.Fail("should throw"); + } + catch (TypeMismatchException e) + { + Assert.IsTrue(e.Message.StartsWith("Cannot convert property value of type [System.Single]")); + } + + // test get operations + object val = expField.GetValue(o); + Assert.AreEqual(typeof(TestEnumTypePropertyClass.ESampleEnumType), val.GetType()); + Assert.AreEqual(TestEnumTypePropertyClass.ESampleEnumType.Trunk, val); + + val = expProperty.GetValue(o); + Assert.AreEqual(typeof(TestEnumTypePropertyClass.ESampleEnumType), val.GetType()); + Assert.AreEqual(TestEnumTypePropertyClass.ESampleEnumType.Trunk, val); + + // test bitwise combined enum set + try + { + // not allowed since -1 is not defined in enum + expField.SetValue(o, -1); + Assert.Fail("should throw"); + } + catch (TypeMismatchException ex) + { + Assert.IsTrue( + ex.Message.StartsWith("Cannot convert property value of type [System.Int32] to required type")); + } + + try + { + // not allowed since -1 is not a representation of any bitwise combination of the enum's values. + expFlagsField.SetValue(o, -1); + Assert.Fail("should throw"); + } + catch (TypeMismatchException ex) + { + Assert.IsTrue( + ex.Message.StartsWith("Cannot convert property value of type [System.Int32] to required type")); + } + + expFlagsField.SetValue(o, + TestEnumTypePropertyClass.ESampleFlagsEnumType.SOME | + TestEnumTypePropertyClass.ESampleFlagsEnumType.SOMEOTHER); + Assert.AreEqual( + TestEnumTypePropertyClass.ESampleFlagsEnumType.SOME | + TestEnumTypePropertyClass.ESampleFlagsEnumType.SOMEOTHER, o.SampleFlagsEnumField); + } + + /// + /// Test to reproduce SPRNET-342, provided on the forum. + /// + /// + /// http://opensource.atlassian.com/projects/spring/browse/SPRNET-342 + /// http://forum.springframework.net/showthread.php?t=614 + /// + [Test] + public void ForumTestThread614() + { + TypeRegistry.RegisterType(typeof(Sample)); + + IExpression e = Expression.Parse("new Sample(O, T, H)"); + + Sample d1 = new Sample("A", "B", "C"); + Sample d2 = new Sample("A", "B", "Z"); + + Sample tmp1 = (Sample) e.GetValue(d1); + Assert.AreEqual("A", tmp1.O); + Assert.AreEqual("B", tmp1.T); + Assert.AreEqual("C", tmp1.H); + + Sample tmp2 = (Sample) e.GetValue(d2); + Assert.AreEqual("A", tmp2.O); + Assert.AreEqual("B", tmp2.T); + Assert.AreEqual("Z", tmp2.H); + } + + /// + /// More "to the point" test to reproduce SPRNET-342 + /// + /// + /// http://opensource.atlassian.com/projects/spring/browse/SPRNET-342 + /// http://forum.springframework.net/showthread.php?t=614 + /// + [Test] + public void RootContextChangeTest() + { + IExpression e = Expression.Parse("#root"); + + Assert.AreEqual("RootA", e.GetValue("RootA")); + Assert.AreEqual("RootB", e.GetValue("RootB")); + } + + /// + /// Hopefully detects threading issues during Expression evaluation + /// + /// + /// A single expression instance may be evaluated against different contexts on different threads. + /// + [Test] + public void ExpressionEvaluationIsThreadSafe() + { + IExpression exp = Expression.Parse("PlaceOfBirth.Country"); + + Inventor seovic = new Inventor("Aleksandar Seovic", new DateTime(1974, 08, 24), "Serbian"); + + AsyncTestTask t1 = new AsyncTestExpressionEvaluation(2000, exp, tesla, tesla.PlaceOfBirth.Country, null).Start(); + AsyncTestTask t2 = new AsyncTestExpressionEvaluation(2000, exp, pupin, pupin.PlaceOfBirth.Country, null).Start(); + AsyncTestTask t3 = new AsyncTestExpressionEvaluation(2000, exp, seovic, seovic.PlaceOfBirth.Country, null).Start(); + + IExpression exp2 = Expression.Parse("(#fact = {|n| $n <= 1 ? 1 : $n * #fact($n-1) }; #fact(#root))"); + + AsyncTestTask t4 = new AsyncTestExpressionEvaluation(2000, exp2, 5, 120, new Dictionary()).Start(); + AsyncTestTask t5 = new AsyncTestExpressionEvaluation(2000, exp2, 6, 720, new Dictionary()).Start(); + + t1.AssertNoException(); + t2.AssertNoException(); + t3.AssertNoException(); + t4.AssertNoException(); + t5.AssertNoException(); + } + + /// + /// Hopefully detects threading issues during Expression parsing + /// + [Test] + public void ExpressionParserIsThreadSafe() + { + AsyncTestTask t1 = new AsyncTestMethod(200, new ThreadStart(TestOperatorPrecedence)).Start(); + AsyncTestTask t2 = new AsyncTestMethod(200, new ThreadStart(TestOperatorPrecedence)).Start(); + AsyncTestTask t3 = new AsyncTestMethod(200, new ThreadStart(TestOperatorPrecedence)).Start(); + + t1.AssertNoException(); + t2.AssertNoException(); + t3.AssertNoException(); + } + + /// + /// Checks if Expression Language array initializers work properly. + /// + [Test] + public void TestArrayConstructor() + { + object obj = ExpressionEvaluator.GetValue(null, "new int[] {3, 4, 5, 6}"); + Assert.IsNotNull(obj); + Assert.IsInstanceOf(typeof(int[]), obj); + int[] intarray = (int[]) obj; + Assert.AreEqual(4, intarray.Length); + for (int i = 0; i < intarray.Length; i++) + { + Assert.AreEqual(i + 3, intarray[i]); + } + + obj = ExpressionEvaluator.GetValue(null, "new long[5]"); + Assert.IsNotNull(obj); + Assert.IsInstanceOf(typeof(long[]), obj); + long[] longarray = obj as long[]; + Assert.AreEqual(5, longarray.Length); + for (int i = 0; i < longarray.Length; i++) + { + Assert.AreEqual(0, longarray[i]); + } + + obj = ExpressionEvaluator.GetValue(null, "new double[4, 5]"); + Assert.IsNotNull(obj); + Assert.IsInstanceOf(typeof(double[,]), obj); + double[,] twodimarray = obj as double[,]; + Assert.AreEqual(4 * 5, twodimarray.Length); + for (int i = 0; i < 4; i++) + { + for (int j = 0; j < 5; j++) + { + Assert.AreEqual(0.0, twodimarray[i, j]); + } + } + + obj = ExpressionEvaluator.GetValue(null, "new int[Int32.Parse('11')]"); + Assert.IsNotNull(obj); + Assert.IsInstanceOf(typeof(int[]), obj); + intarray = obj as int[]; + Assert.AreEqual(11, intarray.Length); + } + + [Test] + public void TestMethodArgumentNodesResolveAgainstThisContext() + { + IExpression exp; + + // case #root == #this - ToString() will be applied to #this + exp = Expression.Parse("long.Parse(ToString())"); + object result = exp.GetValue(100); + Assert.AreEqual((long) 100, result); + + // case #root != #this in Projection - ToString() will be applied to #this + exp = Expression.Parse("(ToString(); #noop ={|val| $val}; !{#noop(ToString()) } )"); + result = exp.GetValue(new int[] { 100, 200 }, new Dictionary()); + Assert.AreEqual(new string[] { "100", "200" }, result); + + // case #root != #this in Selection - ToString() will be applied to #this + exp = Expression.Parse("(#noop ={|val| $val}; ?{#noop(ToString()=='100')} )"); + result = exp.GetValue(new int[] { 100, 200 }, new Dictionary()); + IList list = new ArrayList(); + list.Add(100); + Assert.AreEqual(list, result); + } + + [Test] + public void TestAccessVisibility() + { + AccessVisibilityCases cases = new AccessVisibilityCases(); + + try + { + ExpressionEvaluator.SetValue(cases, "_privateReadonlyField", "notsoreadonly"); + Assert.Fail("writing to readonly field should throw " + typeof(NotWritablePropertyException).FullName); + } + catch (NotWritablePropertyException) { } + + try + { + ExpressionEvaluator.SetValue(cases, "PrivateReadonlyProperty", "notsoreadonly"); + Assert.Fail("writing to readonly field should throw " + typeof(NotWritablePropertyException).FullName); + } + catch (NotWritablePropertyException) { } + + Assert.AreEqual("_privateField", ExpressionEvaluator.GetValue(cases, "_privateField")); + Assert.AreEqual("_protectedField", ExpressionEvaluator.GetValue(cases, "_protectedField")); + Assert.AreEqual("_publicField", ExpressionEvaluator.GetValue(cases, "_publicField")); + + Assert.AreEqual("PrivateProperty", ExpressionEvaluator.GetValue(cases, "PrivateProperty")); + Assert.AreEqual("ProtectedProperty", ExpressionEvaluator.GetValue(cases, "ProtectedProperty")); + Assert.AreEqual("PublicProperty", ExpressionEvaluator.GetValue(cases, "PublicProperty")); + + Assert.AreEqual("PrivateIndexer", ExpressionEvaluator.GetValue(cases, "#root[1]")); + Assert.AreEqual("ProtectedIndexer", ExpressionEvaluator.GetValue(cases, "#root[1.0]")); + Assert.AreEqual("PublicIndexer", ExpressionEvaluator.GetValue(cases, "#root['']")); + + Assert.AreEqual("PrivateMethod", ExpressionEvaluator.GetValue(cases, "GetPrivateMethod()")); + Assert.AreEqual("ProtectedMethod", ExpressionEvaluator.GetValue(cases, "GetProtectedMethod()")); + Assert.AreEqual("PublicMethod", ExpressionEvaluator.GetValue(cases, "GetPublicMethod()")); + } + + #region TestAccessVisibility Classes + + internal class AccessVisibilityCases + { + private readonly string _privateReadonlyField = "_privateReadonlyField"; + private string _privateField = "_privateField"; + protected string _protectedField = "_protectedField"; + public string _publicField = "_publicField"; + + public AccessVisibilityCases() + { + Assert.IsTrue(_privateReadonlyField != string.Empty); + Assert.IsTrue(_privateField != string.Empty); + } + + private string PrivateReadonlyProperty { get { return "PrivateReadonlyProperty"; } } + private string PrivateProperty { get { return "PrivateProperty"; } } + protected string ProtectedProperty { get { return "ProtectedProperty"; } } + public string PublicProperty { get { return "PublicProperty"; } } + + private string this[int intindex] { get { return "PrivateIndexer"; } } + protected string this[double strindex] { get { return "ProtectedIndexer"; } } + public string this[string strindex] { get { return "PublicIndexer"; } } + + private string GetPrivateMethod() { return "PrivateMethod"; } + protected string GetProtectedMethod() { return "ProtectedMethod"; } + public string GetPublicMethod() { return "PublicMethod"; } + } + + #endregion + + #region TestMethodInvocation Classes + + class MethodInvokationCases + { + public string Foo(string stringArg) { return stringArg; } + public int Foo(int intArg) { return intArg; } + } + + #endregion + + #region Set operations tests + + [Test] + public void TestUnionOperator() + { + object o = ExpressionEvaluator.GetValue(null, "{1,2,3} + {3,4,5}"); + Assert.IsInstanceOf(typeof(ISet), o); + ISet union = (ISet) o; + Assert.AreEqual(5, union.Count); + Assert.IsTrue(union.Contains(1)); + Assert.IsTrue(union.Contains(3)); + Assert.IsTrue(union.Contains(5)); + + o = ExpressionEvaluator.GetValue(null, "{1,2,3} + {3,4,5} + {'ivan', 'gox', 'damjao', 5}"); + Assert.IsInstanceOf(typeof(ISet), o); + union = (ISet) o; + Assert.AreEqual(8, union.Count); + Assert.IsTrue(union.Contains(1)); + Assert.IsTrue(union.Contains("ivan")); + + ISet testset = new ListSet(); + testset.AddAll(new int[] { 1, 2, 3, 5, 8 }); + o = ExpressionEvaluator.GetValue(testset, "#this + {1, 2, 13, 15}"); + Assert.IsInstanceOf(typeof(ISet), o); + union = (ISet) o; + Assert.AreEqual(7, union.Count); + Assert.IsTrue(union.Contains(1)); + Assert.IsTrue(union.Contains(15)); + + o = ExpressionEvaluator.GetValue(null, "#{1:'one', 2:'two', 3:'three'} + #{1:'ivan', 5:'five'}"); + Assert.IsInstanceOf(typeof(IDictionary), o); + IDictionary result = (IDictionary) o; + Assert.AreEqual(4, result.Count); + Assert.AreEqual("one", result[1]); + Assert.AreEqual("five", result[5]); + } + + [Test] + public void TestUnionOperatorBad() + { + Assert.Throws(() => ExpressionEvaluator.GetValue(null, "#{1:'one', 2:'two', 3:'three'} + {1, 5}")); + } + + [Test] + public void TestIntersectionOperator() + { + object o = ExpressionEvaluator.GetValue(null, "{111, 'ivan', 23, 24} * {111, 11, 'ivan'}"); + Assert.IsInstanceOf(typeof(ISet), o); + ISet intersection = (ISet) o; + Assert.AreEqual(2, intersection.Count); + Assert.IsTrue(intersection.Contains(111)); + Assert.IsTrue(intersection.Contains("ivan")); + + o = ExpressionEvaluator.GetValue(null, "{24, 25, 'aaa' + 'bb'} * {date('2007/2/5').day * 5, 24 - 1}"); + Assert.IsInstanceOf(typeof(ISet), o); + intersection = (ISet) o; + Assert.AreEqual(1, intersection.Count); + Assert.IsTrue(intersection.Contains(25)); + + ISet testset = new ListSet(); + testset.AddAll(new int[] { 1, 2, 3, 5, 8 }); + o = ExpressionEvaluator.GetValue(testset, "#this * #{1:'one', 10:'ten'}"); + Assert.IsInstanceOf(typeof(ISet), o); + intersection = (ISet) o; + Assert.AreEqual(1, intersection.Count); + Assert.IsTrue(intersection.Contains(1)); + + o = ExpressionEvaluator.GetValue(null, "#{1:'one', 2:'two', 3:'three'} * #{1:'ivan', 5:'five'}"); + Assert.IsInstanceOf(typeof(IDictionary), o); + IDictionary result = (IDictionary) o; + Assert.AreEqual(1, result.Count); + Assert.AreEqual("one", result[1]); + + o = ExpressionEvaluator.GetValue(null, "#{1:'one', 2:'two', 3:'three'} * {1, 2, 5, 7}"); + Assert.IsInstanceOf(typeof(IDictionary), o); + result = (IDictionary) o; + Assert.AreEqual(2, result.Count); + Assert.AreEqual("one", result[1]); + Assert.AreEqual("two", result[2]); + } + + [Test] + public void TestIntersectionOperatorBad() + { + Assert.Throws(() => ExpressionEvaluator.GetValue(null, "#{1:'one', 2:'two', 3:'three'} * 'something'")); + } + + [Test] + public void TestDifferenceOperator() + { + object o = ExpressionEvaluator.GetValue(null, "{111, 11} - {14, 12, 11}"); + Assert.IsInstanceOf(typeof(ISet), o); + ISet diff = (ISet) o; + Assert.AreEqual(1, diff.Count); + Assert.IsTrue(diff.Contains(111)); + + o = ExpressionEvaluator.GetValue(null, "{111, 11} - {14, 12, 11} - {111}"); + Assert.IsInstanceOf(typeof(ISet), o); + diff = (ISet) o; + Assert.AreEqual(0, diff.Count); + + ISet testset = new ListSet(); + testset.AddAll(new int[] { 1, 2, 3, 5, 8 }); + o = ExpressionEvaluator.GetValue(testset, "#this - #{1:'one', 10:'ten'}"); + Assert.IsInstanceOf(typeof(ISet), o); + diff = (ISet) o; + Assert.AreEqual(4, diff.Count); + Assert.IsFalse(diff.Contains(1)); + + o = ExpressionEvaluator.GetValue(null, "#{1:'one', 2:'two', 3:'three'} - #{1:'ivan', 5:'five'}"); + Assert.IsInstanceOf(typeof(IDictionary), o); + IDictionary result = (IDictionary) o; + Assert.AreEqual(2, result.Count); + Assert.IsNull(result[1]); + Assert.AreEqual("three", result[3]); + + o = ExpressionEvaluator.GetValue(null, "#{1:'one', 2:'two', 3:'three'} - {1, 2, 3, 5, 7}"); + Assert.IsInstanceOf(typeof(IDictionary), o); + result = (IDictionary) o; + Assert.AreEqual(0, result.Count); + } + + [Test] + public void TestDifferenceOperatorBad() + { + Assert.Throws(() => ExpressionEvaluator.GetValue(null, "#{1:'one', 2:'two', 3:'three'} - 'something'")); + } + + #endregion + + #region Performance tests + + private DateTime start, stop; + + //[Test] + public void PerformanceTests() + { + int n = 10000000; + object x = ""; + IDictionary vars = new Dictionary(); + + // tesla.PlaceOfBirth + start = DateTime.Now; + for (int i = 0; i < n; i++) + { + x = tesla.PlaceOfBirth; + } + + stop = DateTime.Now; + PrintTest("tesla.PlaceOfBirth (direct)", n, Elapsed); + + // start = DateTime.Now; + // for (int i = 0; i < n; i++) + // { + // x = ExpressionEvaluator.GetValue(tesla, "PlaceOfBirth", vars); + // } + // stop = DateTime.Now; + // PrintTest("tesla.PlaceOfBirth (multi-parse)", n, Elapsed); + + start = DateTime.Now; + IExpression exp = Expression.Parse("PlaceOfBirth"); + for (int i = 0; i < n; i++) + { + x = exp.GetValue(tesla, vars); + } + + stop = DateTime.Now; + PrintTest("tesla.PlaceOfBirth (single-parse)", n, Elapsed); + + // ieee.Officers['advisors'][0].Inventions[2] + start = DateTime.Now; + for (int i = 0; i < n; i++) + { + x = ((Inventor) ((IList) ieee.Officers["advisors"])[0]).Inventions[2]; + } + + stop = DateTime.Now; + PrintTest("ieee.Officers['advisors'][0].Inventions[2] (direct)", n, Elapsed); + + // start = DateTime.Now; + // for (int i = 0; i < n / 10; i++) + // { + // x = ExpressionEvaluator.GetValue(ieee, "Officers['advisors'][0].Inventions[2]", vars); + // } + // stop = DateTime.Now; + // PrintTest("ieee.Officers['advisors'][0].Inventions[2] (multi-parse)", n / 10, Elapsed); + + start = DateTime.Now; + exp = Expression.Parse("Officers['advisors'][0].Inventions[2]"); + for (int i = 0; i < n; i++) + { + x = exp.GetValue(ieee, vars); + } + + stop = DateTime.Now; + PrintTest("ieee.Officers['advisors'][0].Inventions[2] (single-parse)", n, Elapsed); + + x.ToString(); + } + + private double Elapsed + { + get { return (stop.Ticks - start.Ticks) / 10000000f; } + } + + private static void PrintTest(string name, int iterations, double duration) + { + Debug.WriteLine( + String.Format("{0,-60} {1,12:#,###} {2,12:##0.000} {3,12:#,###}", name, iterations, duration, + iterations / duration)); + } + + #endregion + + #region Method Inheritance tests + + [Test] + public void TestInheritedMethodInvocation() + { + DerivedSingleMethodTestClass testClass = new DerivedSingleMethodTestClass(); + Assert.AreEqual("Hello World", ExpressionEvaluator.GetValue(testClass, "#root.GetString()")); + } + + [Test] + public void TestStaticInheritedMethodInvocation() + { + Assert.AreEqual("Hello Static World from SingleMethodTestClass", DerivedSingleMethodTestClass.StaticMethod()); + Assert.AreEqual("Hello Static World from SingleMethodTestClass", ExpressionEvaluator.GetValue(null, string.Format("T({0}).StaticMethod()", typeof(DerivedSingleMethodTestClass).FullName))); + + Assert.AreEqual("SingleMethodTestClass.ShadowedStaticMethod", SingleMethodTestClass.ShadowedStaticMethod()); + Assert.AreEqual("DerivedSingleMethodTestClass.ShadowedStaticMethod", DerivedSingleMethodTestClass.ShadowedStaticMethod()); + Assert.AreEqual("SingleMethodTestClass.ShadowedStaticMethod", ExpressionEvaluator.GetValue(null, string.Format("T({0}).ShadowedStaticMethod()", typeof(SingleMethodTestClass).FullName))); + Assert.AreEqual("DerivedSingleMethodTestClass.ShadowedStaticMethod", ExpressionEvaluator.GetValue(null, string.Format("T({0}).ShadowedStaticMethod()", typeof(DerivedSingleMethodTestClass).FullName))); + } + + #endregion + + private static void DumpNode(AST rootNode, int level) + { + Trace.WriteLine(new string(' ', level) + rootNode.ToString()); + + int numberOfChildren = rootNode.getNumberOfChildren(); + if (numberOfChildren > 0) + { + AST node = rootNode.getFirstChild(); + while (node != null) + { + DumpNode(node, level + 2); + node = node.getNextSibling(); + } + } + } } + +#region Helper classes + +internal class SingleMethodTestClass +{ + protected static string GetMethodName(MethodBase method) + { + return method.DeclaringType.Name + "." + method.Name; + } + + public static string StaticMethod() + { + return "Hello Static World from SingleMethodTestClass"; + } + + public static string ShadowedStaticMethod() + { + return GetMethodName(MethodInfo.GetCurrentMethod()); + } + + public string GetString() + { + return "Hello World"; + } +} + +internal class DerivedSingleMethodTestClass : SingleMethodTestClass +{ + public new static string ShadowedStaticMethod() + { + return GetMethodName(MethodInfo.GetCurrentMethod()); + } +} + +internal class TestObjectContainer +{ + private TestObject testObject; + + public TestObject TestObject + { + get { return this.testObject; } + set { this.testObject = value; } + } +} + +internal class TestEnumTypePropertyClass +{ + [Flags] + internal enum ESampleFlagsEnumType : int + { + NONE = 0, + SOME = 1, + SOMEOTHER = 2, + } + + internal enum ESampleEnumType : int + { + Van = 0, + Trunk = 1, + Air = 2 + } + + public ESampleFlagsEnumType SampleFlagsEnumField; + public ESampleEnumType SampleEnumField; + + public ESampleFlagsEnumType SampleFlagsEnumProperty + { + get { return SampleFlagsEnumField; } + set { SampleFlagsEnumField = value; } + } + + public ESampleEnumType SampleEnumProperty + { + get { return SampleEnumField; } + set { SampleEnumField = value; } + } +} + +internal sealed class Bar +{ + private int[] numbers = new int[] { 1, 2, 3 }; + + public int this[int index] + { + get { return numbers[index]; } + } +} + +internal class Foo +{ + private FooType type; + private Nullable nullableDate; + private Nullable nullableInt; + + public Foo() : this(FooType.One) + { + } + + public Foo(FooType type) + { + this.type = type; + } + + public Foo(params string[] values) + { + } + + public Foo(bool flag, params string[] values) + { + } + + public Foo(int flag, Bar[] bars) + { + } + + public Foo(int flag, ICollection bars) + { + throw new InvalidOperationException("should have selected ctor(int, Bar[])"); + } + + public string this[Bar[] bars] + { + get { return "ExactMatch"; } + } + + public string this[ICollection bars] + { + get { return "AssignableMatch"; } + } + + public object this[int foo, string key] + { + get { return key + "_" + foo; } + } + + public FooType Type + { + get { return type; } + } + + public DateTime? NullableDate + { + get { return nullableDate; } + set { nullableDate = value; } + } + + public int? NullableInt + { + get { return nullableInt; } + set { nullableInt = value; } + } + + public string MethodWithSimilarArguments(int flags, Bar[] bars) + { + return "ExactMatch"; + } + + public string MethodWithSimilarArguments(int flags, ICollection bar) + { + return "AssignableMatch"; + } + + public string MethodWithArrayArgument(string[] values) + { + return string.Join("|", values); + } + + public string MethodWithParamArray(params string[] values) + { + return string.Join("|", values); + } + + public string MethodWithParamArray(bool uppercase, params string[] values) + { + string ret = string.Join("|", values); + return (uppercase ? ret.ToUpper() : ret); + } + + public int MethodWithParamArray(params int[] values) + { + return values.Length; + } +} + +internal enum FooType +{ + One, + Two, + Three +} + +internal class Sample +{ + public string O; + public string T; + public string H; + + public Sample(string o, string t, string h) + { + O = o; + T = t; + H = h; + } +} + +#endregion + +#region Shadowing Test Helper Classes + +internal class ShadowingTestsBaseClass +{ + private object _someValue; + private object _readonlyShadowedValue; + private object _writeonlyShadowedValue; + + public object SomeValue + { + get { return _someValue; } + set { _someValue = value; } + } + + public object ReadonlyShadowedValue + { + get { return _readonlyShadowedValue; } + set { _readonlyShadowedValue = value; } + } + + public object WriteonlyShadowedValue + { + get { return _writeonlyShadowedValue; } + set { _writeonlyShadowedValue = value; } + } +} + +internal class ShadowingTestsSpezializedClass : ShadowingTestsBaseClass +{ + public new string SomeValue + { + get { return (string) base.SomeValue; } + set { base.SomeValue = value; } + } + + public new string ReadonlyShadowedValue + { + get { return (string) base.ReadonlyShadowedValue; } + } + + public new string WriteonlyShadowedValue + { + set { base.WriteonlyShadowedValue = value; } + } +} + +internal class ShadowingTestsMoreSpezializedClass : ShadowingTestsSpezializedClass +{ +} + +internal class ShadowingTestsMostSpezializedClass : ShadowingTestsMoreSpezializedClass +{ +} + +#endregion // Shadowing Test Helper Classes \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/Expressions/FunctionNodeTests.cs b/test/Spring/Spring.Core.Tests/Expressions/FunctionNodeTests.cs index d09cdfc7..d5feead3 100644 --- a/test/Spring/Spring.Core.Tests/Expressions/FunctionNodeTests.cs +++ b/test/Spring/Spring.Core.Tests/Expressions/FunctionNodeTests.cs @@ -24,92 +24,91 @@ using NUnit.Framework; #endregion -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// +/// +/// Erich Eichinger +[TestFixture] +public class FunctionNodeTests { - /// - /// - /// - /// Erich Eichinger - [TestFixture] - public class FunctionNodeTests + [Test] + public void ExecutesLambdaFunction() { - [Test] - public void ExecutesLambdaFunction() + Dictionary vars = new Dictionary(); + Expression.RegisterFunction("ident", "{|n| $n}", vars); + + FunctionNode fn = new FunctionNode(); + fn.Text = "ident"; + StringLiteralNode str = new StringLiteralNode(); + str.Text = "theValue"; + fn.addChild(str); + + IExpression exp = fn; + Assert.AreEqual(str.Text, exp.GetValue(null, vars)); + } + + [Test] + public void ExecutesDelegate() + { + Dictionary vars = new Dictionary(); + vars["concat"] = new TestCallback(Concat); + + FunctionNode fn = new FunctionNode(); + fn.Text = "concat"; + StringLiteralNode str = new StringLiteralNode(); + str.Text = "theValue"; + fn.addChild(str); + StringLiteralNode str2 = new StringLiteralNode(); + str2.Text = "theValue"; + fn.addChild(str2); + + IExpression exp = fn; + Assert.AreEqual(string.Format("{0},{1},{2}", this.GetHashCode(), str.Text, str2.Text), exp.GetValue(null, vars)); + } + + private delegate string TestCallback(string arg1, string arg2); + + private string Concat(string arg1, string arg2) + { + return string.Format("{0},{1},{2}", this.GetHashCode(), arg1, arg2); + } + + [Category("Performance")] + [Test, Explicit] + public void ExecutesDelegatePerformance() + { + Dictionary vars = new Dictionary(5); + WaitCallback noop = delegate(object arg) { - Dictionary vars = new Dictionary(); - Expression.RegisterFunction("ident", "{|n| $n}", vars); + // noop + }; + vars["noop"] = noop; - FunctionNode fn = new FunctionNode(); - fn.Text = "ident"; - StringLiteralNode str = new StringLiteralNode(); - str.Text = "theValue"; - fn.addChild(str); + FunctionNode fn = new FunctionNode(); + fn.Text = "noop"; + StringLiteralNode str = new StringLiteralNode(); + str.Text = "theArg"; + fn.addChild(str); - IExpression exp = fn; - Assert.AreEqual(str.Text, exp.GetValue(null, vars)); - } + int ITERATIONS = 10000000; - [Test] - public void ExecutesDelegate() + StopWatch watch = new StopWatch(); + using (watch.Start("Duration Direct: {0}")) { - Dictionary vars = new Dictionary(); - vars["concat"] = new TestCallback(Concat); - - FunctionNode fn = new FunctionNode(); - fn.Text = "concat"; - StringLiteralNode str = new StringLiteralNode(); - str.Text = "theValue"; - fn.addChild(str); - StringLiteralNode str2 = new StringLiteralNode(); - str2.Text = "theValue"; - fn.addChild(str2); - - IExpression exp = fn; - Assert.AreEqual(string.Format("{0},{1},{2}", this.GetHashCode(), str.Text, str2.Text), exp.GetValue(null, vars)); - } - - private delegate string TestCallback(string arg1, string arg2); - - private string Concat(string arg1, string arg2) - { - return string.Format("{0},{1},{2}", this.GetHashCode(), arg1, arg2); - } - - [Category("Performance")] - [Test, Explicit] - public void ExecutesDelegatePerformance() - { - Dictionary vars = new Dictionary(5); - WaitCallback noop = delegate (object arg) - { - // noop - }; - vars["noop"] = noop; - - FunctionNode fn = new FunctionNode(); - fn.Text = "noop"; - StringLiteralNode str = new StringLiteralNode(); - str.Text = "theArg"; - fn.addChild(str); - - int ITERATIONS = 10000000; - - StopWatch watch = new StopWatch(); - using (watch.Start("Duration Direct: {0}")) + for (int i = 0; i < ITERATIONS; i++) { - for (int i = 0; i < ITERATIONS; i++) - { - ((WaitCallback)vars["noop"])(str.getText()); - } + ((WaitCallback) vars["noop"])(str.getText()); } + } - using (watch.Start("Duration SpEL: {0}")) + using (watch.Start("Duration SpEL: {0}")) + { + for (int i = 0; i < ITERATIONS; i++) { - for (int i = 0; i < ITERATIONS; i++) - { - fn.GetValue(null, vars); - } + fn.GetValue(null, vars); } } } -} \ No newline at end of file +} diff --git a/test/Spring/Spring.Core.Tests/Expressions/MethodNodeTests.cs b/test/Spring/Spring.Core.Tests/Expressions/MethodNodeTests.cs index 82c4cfb7..fa71bdfe 100644 --- a/test/Spring/Spring.Core.Tests/Expressions/MethodNodeTests.cs +++ b/test/Spring/Spring.Core.Tests/Expressions/MethodNodeTests.cs @@ -26,117 +26,125 @@ using Spring.Expressions.Processors; #endregion -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// +/// +/// Erich Eichinger +[TestFixture] +public class MethodNodeTests { - /// - /// - /// - /// Erich Eichinger - [TestFixture] - public class MethodNodeTests + private class MyTestCollectionProcessor : ICollectionProcessor { - private class MyTestCollectionProcessor : ICollectionProcessor + public object Process(ICollection source, object[] args) { - public object Process(ICollection source, object[] args) - { - return source; - } + return source; } - - [Test] - public void CallCustomCollectionProcessor() - { - Dictionary vars = new Dictionary(); - vars["myCollProc"] = new MyTestCollectionProcessor(); - - MethodNode mn = new MethodNode(); - mn.Text = "myCollProc"; - - IExpression exp = mn; - int[] input = new int[] {1, 2, 3}; - Assert.AreSame(input, exp.GetValue(input, vars)); - } - - [Test, Explicit] - public void PerformanceOfMethodEvaluationOnDifferentContextTypes() - { - MethodNode mn = new MethodNode(); - mn.Text = "ToString"; - - TypeNode nln = new TypeNode(); - nln.Text = "System.Globalization.CultureInfo"; - - PropertyOrFieldNode pn = new PropertyOrFieldNode(); - pn.Text = "InvariantCulture"; - - - Expression exp = new Expression(); - exp.addChild(nln); - exp.addChild(pn); - - StringLiteralNode sln = new StringLiteralNode(); - sln.Text = "dummy"; - - mn.addChild(sln); - mn.addChild(exp); - - IExpression mnExp = mn; - Assert.AreEqual("dummy", mnExp.GetValue(0m, null)); - - int runs = 10000000; - - StopWatch watch = new StopWatch(); - using (watch.Start("Duration: {0}")) - { - for (int i = 0; i < runs; i++) - { - mnExp.GetValue(0m, null); - } - } - } - - #region StopWatch - - private class StopWatch - { - private DateTime _startTime; - private TimeSpan _elapsed; - - private class Stopper : IDisposable - { - private readonly StopWatch _owner; - private readonly string _format; - public Stopper(StopWatch owner, string format) { _owner = owner; _format = format; } - public void Dispose() { _owner.Stop(_format); GC.SuppressFinalize(this); } - } - - public IDisposable Start(string outputFormat) - { - Stopper stopper = new Stopper(this, outputFormat); - _startTime = DateTime.Now; - return stopper; - } - - private void Stop(string outputFormat) - { - _elapsed = DateTime.Now.Subtract(_startTime); - if (outputFormat != null) - { - Console.WriteLine(outputFormat, _elapsed); - } - } - - public DateTime StartTime - { - get { return _startTime; } - } - - public TimeSpan Elapsed - { - get { return _elapsed; } - } - } - - #endregion } -} \ No newline at end of file + + [Test] + public void CallCustomCollectionProcessor() + { + Dictionary vars = new Dictionary(); + vars["myCollProc"] = new MyTestCollectionProcessor(); + + MethodNode mn = new MethodNode(); + mn.Text = "myCollProc"; + + IExpression exp = mn; + int[] input = new int[] { 1, 2, 3 }; + Assert.AreSame(input, exp.GetValue(input, vars)); + } + + [Test, Explicit] + public void PerformanceOfMethodEvaluationOnDifferentContextTypes() + { + MethodNode mn = new MethodNode(); + mn.Text = "ToString"; + + TypeNode nln = new TypeNode(); + nln.Text = "System.Globalization.CultureInfo"; + + PropertyOrFieldNode pn = new PropertyOrFieldNode(); + pn.Text = "InvariantCulture"; + + Expression exp = new Expression(); + exp.addChild(nln); + exp.addChild(pn); + + StringLiteralNode sln = new StringLiteralNode(); + sln.Text = "dummy"; + + mn.addChild(sln); + mn.addChild(exp); + + IExpression mnExp = mn; + Assert.AreEqual("dummy", mnExp.GetValue(0m, null)); + + int runs = 10000000; + + StopWatch watch = new StopWatch(); + using (watch.Start("Duration: {0}")) + { + for (int i = 0; i < runs; i++) + { + mnExp.GetValue(0m, null); + } + } + } + + #region StopWatch + + private class StopWatch + { + private DateTime _startTime; + private TimeSpan _elapsed; + + private class Stopper : IDisposable + { + private readonly StopWatch _owner; + private readonly string _format; + + public Stopper(StopWatch owner, string format) + { + _owner = owner; + _format = format; + } + + public void Dispose() + { + _owner.Stop(_format); + GC.SuppressFinalize(this); + } + } + + public IDisposable Start(string outputFormat) + { + Stopper stopper = new Stopper(this, outputFormat); + _startTime = DateTime.Now; + return stopper; + } + + private void Stop(string outputFormat) + { + _elapsed = DateTime.Now.Subtract(_startTime); + if (outputFormat != null) + { + Console.WriteLine(outputFormat, _elapsed); + } + } + + public DateTime StartTime + { + get { return _startTime; } + } + + public TimeSpan Elapsed + { + get { return _elapsed; } + } + } + + #endregion +} diff --git a/test/Spring/Spring.Core.Tests/Expressions/OpADDTests.cs b/test/Spring/Spring.Core.Tests/Expressions/OpADDTests.cs index df967b3f..284889dc 100644 --- a/test/Spring/Spring.Core.Tests/Expressions/OpADDTests.cs +++ b/test/Spring/Spring.Core.Tests/Expressions/OpADDTests.cs @@ -1,50 +1,50 @@ #region License -/* - * Copyright 2002-2010 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. +/* + * Copyright 2002-2010 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 NUnit.Framework; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// +/// Erich Eichinger +[TestFixture] +public class OpADDTests { - /// - /// - /// Erich Eichinger - [TestFixture] - public class OpADDTests + [Test] + public void CanAddStrings() { - [Test] - public void CanAddStrings() - { - OpADD add = new OpADD(); - add.addChild( new StringLiteralNode("20")); - add.addChild( new StringLiteralNode("30")); - object result = add.GetValue(null, null); - Assert.AreEqual("2030", result); - } - [Test] - public void CanAddNumbers() - { - OpADD add = new OpADD(); - add.addChild( new IntLiteralNode("20")); - add.addChild( new IntLiteralNode("30")); - object result = add.GetValue(null, null); - Assert.AreEqual(50, result); - } + OpADD add = new OpADD(); + add.addChild(new StringLiteralNode("20")); + add.addChild(new StringLiteralNode("30")); + object result = add.GetValue(null, null); + Assert.AreEqual("2030", result); } -} \ No newline at end of file + + [Test] + public void CanAddNumbers() + { + OpADD add = new OpADD(); + add.addChild(new IntLiteralNode("20")); + add.addChild(new IntLiteralNode("30")); + object result = add.GetValue(null, null); + Assert.AreEqual(50, result); + } +} diff --git a/test/Spring/Spring.Core.Tests/Expressions/OpANDTests.cs b/test/Spring/Spring.Core.Tests/Expressions/OpANDTests.cs index c6b59da6..78c36c48 100644 --- a/test/Spring/Spring.Core.Tests/Expressions/OpANDTests.cs +++ b/test/Spring/Spring.Core.Tests/Expressions/OpANDTests.cs @@ -20,37 +20,36 @@ using NUnit.Framework; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// Unit tests for the OpAND class. +/// +/// Erich Eichinger +[TestFixture] +public class OpANDTests { - /// - /// Unit tests for the OpAND class. - /// - /// Erich Eichinger - [TestFixture] - public class OpANDTests + [Test] + public void AndsNumbers() { - [Test] - public void AndsNumbers() - { - OpAND band = new OpAND(new IntLiteralNode("2"), new IntLiteralNode("3")); - Assert.AreEqual( 2 & 3, band.GetValue(null,null) ); - } - - [Test] - public void AndsBooleans() - { - OpAND band1 = new OpAND(new BooleanLiteralNode("true"), new BooleanLiteralNode("true")); - Assert.AreEqual(true, band1.GetValue(null, null)); - - OpAND band2 = new OpAND(new BooleanLiteralNode("true"), new BooleanLiteralNode("false")); - Assert.AreEqual(false, band2.GetValue(null, null)); - } - - [Test(Description = "SPRNET-1381")] - public void TestShortcircuitAndOperator() - { - object boolean = ExpressionEvaluator.GetValue(new Inventor(), "Name != null and Name.Length == 0"); - Assert.AreEqual(false, boolean); - } + OpAND band = new OpAND(new IntLiteralNode("2"), new IntLiteralNode("3")); + Assert.AreEqual(2 & 3, band.GetValue(null, null)); } -} \ No newline at end of file + + [Test] + public void AndsBooleans() + { + OpAND band1 = new OpAND(new BooleanLiteralNode("true"), new BooleanLiteralNode("true")); + Assert.AreEqual(true, band1.GetValue(null, null)); + + OpAND band2 = new OpAND(new BooleanLiteralNode("true"), new BooleanLiteralNode("false")); + Assert.AreEqual(false, band2.GetValue(null, null)); + } + + [Test(Description = "SPRNET-1381")] + public void TestShortcircuitAndOperator() + { + object boolean = ExpressionEvaluator.GetValue(new Inventor(), "Name != null and Name.Length == 0"); + Assert.AreEqual(false, boolean); + } +} diff --git a/test/Spring/Spring.Core.Tests/Expressions/OpORTests.cs b/test/Spring/Spring.Core.Tests/Expressions/OpORTests.cs index 9342644f..e97b95ab 100644 --- a/test/Spring/Spring.Core.Tests/Expressions/OpORTests.cs +++ b/test/Spring/Spring.Core.Tests/Expressions/OpORTests.cs @@ -20,34 +20,33 @@ using NUnit.Framework; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// Unit tests for the OpOR class. +/// +/// Erich Eichinger +[TestFixture] +public class OpORTests { - /// - /// Unit tests for the OpOR class. - /// - /// Erich Eichinger - [TestFixture] - public class OpORTests + [Test] + public void OrsNumbers() { - [Test] - public void OrsNumbers() - { - OpOR bor = new OpOR(new IntLiteralNode("2"), new IntLiteralNode("3")); - Assert.AreEqual(2 | 3, bor.GetValue(null, null)); - } - - [Test] - public void OrsBooleans() - { - OpOR bor = new OpOR(new BooleanLiteralNode("false"), new BooleanLiteralNode("true")); - Assert.AreEqual(false || true , bor.GetValue(null, null)); - } - - [Test(Description = "SPRNET-1381")] - public void TestShortcircuitOrOperator() - { - object boolean = ExpressionEvaluator.GetValue(new Inventor(), "Name == null or Name.Length == 0"); - Assert.AreEqual(true, boolean); - } + OpOR bor = new OpOR(new IntLiteralNode("2"), new IntLiteralNode("3")); + Assert.AreEqual(2 | 3, bor.GetValue(null, null)); } -} \ No newline at end of file + + [Test] + public void OrsBooleans() + { + OpOR bor = new OpOR(new BooleanLiteralNode("false"), new BooleanLiteralNode("true")); + Assert.AreEqual(false || true, bor.GetValue(null, null)); + } + + [Test(Description = "SPRNET-1381")] + public void TestShortcircuitOrOperator() + { + object boolean = ExpressionEvaluator.GetValue(new Inventor(), "Name == null or Name.Length == 0"); + Assert.AreEqual(true, boolean); + } +} diff --git a/test/Spring/Spring.Core.Tests/Expressions/OpXORTests.cs b/test/Spring/Spring.Core.Tests/Expressions/OpXORTests.cs index 9b9e157a..25bd8cc4 100644 --- a/test/Spring/Spring.Core.Tests/Expressions/OpXORTests.cs +++ b/test/Spring/Spring.Core.Tests/Expressions/OpXORTests.cs @@ -20,30 +20,29 @@ using NUnit.Framework; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// Unit tests for the OpXOR class. +/// +/// Erich Eichinger +[TestFixture] +public class OpXORTests { - /// - /// Unit tests for the OpXOR class. - /// - /// Erich Eichinger - [TestFixture] - public class OpXORTests + [Test] + public void XorsNumbers() { - [Test] - public void XorsNumbers() - { - OpXOR bxor = new OpXOR(new IntLiteralNode("2"), new IntLiteralNode("3")); - Assert.AreEqual(2 ^ 3, bxor.GetValue(null, null)); - } - - [Test] - public void XorsBooleans() - { - OpXOR bxor1 = new OpXOR(new BooleanLiteralNode("true"), new BooleanLiteralNode("false")); - Assert.AreEqual(true ^ false, bxor1.GetValue(null, null)); - - OpXOR bxor2 = new OpXOR(new BooleanLiteralNode("true"), new BooleanLiteralNode("true")); - Assert.AreEqual(true ^ true, bxor2.GetValue(null, null)); - } + OpXOR bxor = new OpXOR(new IntLiteralNode("2"), new IntLiteralNode("3")); + Assert.AreEqual(2 ^ 3, bxor.GetValue(null, null)); } -} \ No newline at end of file + + [Test] + public void XorsBooleans() + { + OpXOR bxor1 = new OpXOR(new BooleanLiteralNode("true"), new BooleanLiteralNode("false")); + Assert.AreEqual(true ^ false, bxor1.GetValue(null, null)); + + OpXOR bxor2 = new OpXOR(new BooleanLiteralNode("true"), new BooleanLiteralNode("true")); + Assert.AreEqual(true ^ true, bxor2.GetValue(null, null)); + } +} diff --git a/test/Spring/Spring.Core.Tests/Expressions/Processors/ConversionProcessorTests.cs b/test/Spring/Spring.Core.Tests/Expressions/Processors/ConversionProcessorTests.cs index 73fccde3..15fc9b96 100644 --- a/test/Spring/Spring.Core.Tests/Expressions/Processors/ConversionProcessorTests.cs +++ b/test/Spring/Spring.Core.Tests/Expressions/Processors/ConversionProcessorTests.cs @@ -22,74 +22,72 @@ using System.Collections; using NUnit.Framework; - using Spring.Globalization; #endregion -namespace Spring.Expressions.Processors +namespace Spring.Expressions.Processors; + +/// +/// +/// +/// Erich Eichinger +[TestFixture] +public class ConversionProcessorTests { - /// - /// - /// - /// Erich Eichinger - [TestFixture] - public class ConversionProcessorTests + [OneTimeSetUp] + public void FixtureSetUp() { - [OneTimeSetUp] - public void FixtureSetUp() - { - CultureTestScope.Set(); - } + CultureTestScope.Set(); + } - [OneTimeTearDown] - public void FixtureTearDown() - { - CultureTestScope.Reset(); - } + [OneTimeTearDown] + public void FixtureTearDown() + { + CultureTestScope.Reset(); + } - [Test] - public void RequiresTypeArgument() + [Test] + public void RequiresTypeArgument() + { + ConversionProcessor cp = new ConversionProcessor(); + try { - ConversionProcessor cp = new ConversionProcessor(); - try - { - cp.Process(new object[] {0, 1}, null); - Assert.Fail("should throw"); - } - catch (ArgumentNullException) - { - } + cp.Process(new object[] { 0, 1 }, null); + Assert.Fail("should throw"); } - - [Test] - public void ReturnsListAsIsIfNullOrEmpty() + catch (ArgumentNullException) { - ConversionProcessor cp = new ConversionProcessor(); - object result; - result = cp.Process(null, new object[] { typeof(int) }); - Assert.IsNull(result); - ICollection input = new object[] {}; - result = cp.Process(input, new object[] { typeof(int) }); - Assert.AreEqual( input, result ); - } - - [Test] - public void ReturnsTypedArray() - { - ConversionProcessor cp = new ConversionProcessor(); - object result = cp.Process( new object[] { 0, 1 }, new object[] { typeof(int) }); - Assert.IsTrue( result is int[] ); - } - - [Test] - public void UsesTypeConverterRegistryForConversion() - { - ConversionProcessor cp = new ConversionProcessor(); - ICollection result = (ICollection) cp.Process(new object[] { "0", 1, 1.1m, "1.1", 1.1f }, new object[] { typeof(decimal) }); - decimal sum = 0; - foreach (decimal element in result) sum += element; - Assert.AreEqual( 4.3f, sum ); } } -} \ No newline at end of file + + [Test] + public void ReturnsListAsIsIfNullOrEmpty() + { + ConversionProcessor cp = new ConversionProcessor(); + object result; + result = cp.Process(null, new object[] { typeof(int) }); + Assert.IsNull(result); + ICollection input = new object[] { }; + result = cp.Process(input, new object[] { typeof(int) }); + Assert.AreEqual(input, result); + } + + [Test] + public void ReturnsTypedArray() + { + ConversionProcessor cp = new ConversionProcessor(); + object result = cp.Process(new object[] { 0, 1 }, new object[] { typeof(int) }); + Assert.IsTrue(result is int[]); + } + + [Test] + public void UsesTypeConverterRegistryForConversion() + { + ConversionProcessor cp = new ConversionProcessor(); + ICollection result = (ICollection) cp.Process(new object[] { "0", 1, 1.1m, "1.1", 1.1f }, new object[] { typeof(decimal) }); + decimal sum = 0; + foreach (decimal element in result) sum += element; + Assert.AreEqual(4.3f, sum); + } +} diff --git a/test/Spring/Spring.Core.Tests/Expressions/Processors/OrderByProcessorTests.cs b/test/Spring/Spring.Core.Tests/Expressions/Processors/OrderByProcessorTests.cs index 6d74aea3..01c42f41 100644 --- a/test/Spring/Spring.Core.Tests/Expressions/Processors/OrderByProcessorTests.cs +++ b/test/Spring/Spring.Core.Tests/Expressions/Processors/OrderByProcessorTests.cs @@ -24,55 +24,55 @@ using NUnit.Framework; #endregion -namespace Spring.Expressions.Processors +namespace Spring.Expressions.Processors; + +/// +/// +/// +/// Erich Eichinger +[TestFixture] +public class OrderByProcessorTests { - /// - /// - /// - /// Erich Eichinger - [TestFixture] - public class OrderByProcessorTests + [Test] + public void OrderByExpressionString() { - [Test] - public void OrderByExpressionString() - { - IExpression exp = Expression.Parse("orderBy('ToString()')"); - object[] input = new object[] { 'b', 1, 2.0, "a" }; + IExpression exp = Expression.Parse("orderBy('ToString()')"); + object[] input = new object[] { 'b', 1, 2.0, "a" }; - Assert.AreEqual( new object[] { 1,2.0,"a",'b' }, exp.GetValue(input) ); - } - - [Test] - public void OrderByLambdaFunction() - { - IExpression exp = Expression.Parse("orderBy({|a,b| $a.ToString().CompareTo($b.ToString())})"); - object[] input = new object[] { 'b', 1, 2.0, "a" }; - - Assert.AreEqual(new object[] { 1, 2.0, "a", 'b' }, exp.GetValue(input)); - - Dictionary vars = new Dictionary(); - Expression.RegisterFunction( "compare", "{|a,b| $a.ToString().CompareTo($b.ToString())}", vars); - exp = Expression.Parse("orderBy(#compare)"); - Assert.AreEqual(new object[] { 1, 2.0, "a", 'b' }, exp.GetValue(input, vars)); - } - - [Test] - public void OrderByDelegate() - { - Dictionary vars = new Dictionary(); - vars["compare"] = new CompareCallback(CompareObjects); - - IExpression exp = Expression.Parse("orderBy(#compare)"); - object[] input = new object[] { 'b', 1, 2.0, "a" }; - - Assert.AreEqual(new object[] { 1, 2.0, "a", 'b' }, exp.GetValue(input, vars)); - } - - private delegate int CompareCallback(object x, object y); - private int CompareObjects(object x, object y) - { - if (x == y) return 0; - return x.ToString().CompareTo(""+y); - } + Assert.AreEqual(new object[] { 1, 2.0, "a", 'b' }, exp.GetValue(input)); } -} \ No newline at end of file + + [Test] + public void OrderByLambdaFunction() + { + IExpression exp = Expression.Parse("orderBy({|a,b| $a.ToString().CompareTo($b.ToString())})"); + object[] input = new object[] { 'b', 1, 2.0, "a" }; + + Assert.AreEqual(new object[] { 1, 2.0, "a", 'b' }, exp.GetValue(input)); + + Dictionary vars = new Dictionary(); + Expression.RegisterFunction("compare", "{|a,b| $a.ToString().CompareTo($b.ToString())}", vars); + exp = Expression.Parse("orderBy(#compare)"); + Assert.AreEqual(new object[] { 1, 2.0, "a", 'b' }, exp.GetValue(input, vars)); + } + + [Test] + public void OrderByDelegate() + { + Dictionary vars = new Dictionary(); + vars["compare"] = new CompareCallback(CompareObjects); + + IExpression exp = Expression.Parse("orderBy(#compare)"); + object[] input = new object[] { 'b', 1, 2.0, "a" }; + + Assert.AreEqual(new object[] { 1, 2.0, "a", 'b' }, exp.GetValue(input, vars)); + } + + private delegate int CompareCallback(object x, object y); + + private int CompareObjects(object x, object y) + { + if (x == y) return 0; + return x.ToString().CompareTo("" + y); + } +} diff --git a/test/Spring/Spring.Core.Tests/Expressions/PropertyOrFieldNodeTests.cs b/test/Spring/Spring.Core.Tests/Expressions/PropertyOrFieldNodeTests.cs index 49729553..bf5f79f8 100644 --- a/test/Spring/Spring.Core.Tests/Expressions/PropertyOrFieldNodeTests.cs +++ b/test/Spring/Spring.Core.Tests/Expressions/PropertyOrFieldNodeTests.cs @@ -21,37 +21,36 @@ using NUnit.Framework; using Spring.Objects; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// Tests the behavior of PropertyOrFieldNode expression node +/// +/// Erich Eichinger +[TestFixture] +public class PropertyOrFieldNodeTests { - /// - /// Tests the behavior of PropertyOrFieldNode expression node - /// - /// Erich Eichinger - [TestFixture] - public class PropertyOrFieldNodeTests + private class BaseClass { - private class BaseClass - { - private ITestObject objectProp; + private ITestObject objectProp; - public string StringProp { get { return "BaseStringProp"; }} - public ITestObject ObjectProp { get { return objectProp; } set { objectProp = value; } } - } + public string StringProp { get { return "BaseStringProp"; } } + public ITestObject ObjectProp { get { return objectProp; } set { objectProp = value; } } + } - private class DerivedClass : BaseClass - { - public new DateTime StringProp { get { return new DateTime(2008,1,1); }} - } + private class DerivedClass : BaseClass + { + public new DateTime StringProp { get { return new DateTime(2008, 1, 1); } } + } + [Test] + public void UseMostSpecificOverride() + { + PropertyOrFieldNode pofNode = new PropertyOrFieldNode(); + pofNode.Text = "StringProp"; - [Test] - public void UseMostSpecificOverride() - { - PropertyOrFieldNode pofNode = new PropertyOrFieldNode(); - pofNode.Text = "StringProp"; - - Assert.AreEqual(new DateTime(2008,1,1), ((IExpression) pofNode).GetValue(new DerivedClass())); - } + Assert.AreEqual(new DateTime(2008, 1, 1), ((IExpression) pofNode).GetValue(new DerivedClass())); + } #if !NETCOREAPP [Test] @@ -70,5 +69,4 @@ namespace Spring.Expressions Assert.AreSame( tpo, ouc.ObjectProp ); } #endif - } -} \ No newline at end of file +} diff --git a/test/Spring/Spring.Core.Tests/Expressions/ReferenceNodeTests.cs b/test/Spring/Spring.Core.Tests/Expressions/ReferenceNodeTests.cs index 9d273cf6..6c934d35 100644 --- a/test/Spring/Spring.Core.Tests/Expressions/ReferenceNodeTests.cs +++ b/test/Spring/Spring.Core.Tests/Expressions/ReferenceNodeTests.cs @@ -25,160 +25,159 @@ using Spring.Core.IO; using Spring.Objects.Factory.Xml; using System.Text; -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// +/// +/// Erich Eichinger +[TestFixture] +public class ReferenceNodeTests { - /// - /// - /// - /// Erich Eichinger - [TestFixture] - public class ReferenceNodeTests + private class MyTestObject { - private class MyTestObject - { - public object MyField { get; set; } - } + public object MyField { get; set; } + } - [TearDown] - public void TearDown() => ContextRegistry.Clear(); + [TearDown] + public void TearDown() => ContextRegistry.Clear(); - [Test] - public void DoesNotCallContextRegistryForLocalObjectFactoryReferences() - { - var xml = $@" + [Test] + public void DoesNotCallContextRegistryForLocalObjectFactoryReferences() + { + var xml = $@" "; - var objectFactory = new XmlObjectFactory(new StringResource(xml, Encoding.UTF8)); - var theObject = new object(); - objectFactory.RegisterSingleton("theObject", theObject); + var objectFactory = new XmlObjectFactory(new StringResource(xml, Encoding.UTF8)); + var theObject = new object(); + objectFactory.RegisterSingleton("theObject", theObject); - var to = (MyTestObject) objectFactory.GetObject("foo"); - Assert.That(theObject, Is.SameAs(to.MyField)); - } + var to = (MyTestObject) objectFactory.GetObject("foo"); + Assert.That(theObject, Is.SameAs(to.MyField)); + } - [Test] - public void UseDefaultContextRegistryWhenNoContextProvided() - { - var defaultXml = $@" + [Test] + public void UseDefaultContextRegistryWhenNoContextProvided() + { + var defaultXml = $@" "; - var defaultContext = GetContextFromXmlString(defaultXml, AbstractApplicationContext.DefaultRootContextName); - ContextRegistry.RegisterContext(defaultContext); + var defaultContext = GetContextFromXmlString(defaultXml, AbstractApplicationContext.DefaultRootContextName); + ContextRegistry.RegisterContext(defaultContext); - var expectedObject = defaultContext.GetObject("theObject"); + var expectedObject = defaultContext.GetObject("theObject"); - var expression = Expression.Parse("@(theObject)"); - var value = expression.GetValue(null, new Dictionary()); + var expression = Expression.Parse("@(theObject)"); + var value = expression.GetValue(null, new Dictionary()); - Assert.That(value, Is.SameAs(expectedObject)); - } + Assert.That(value, Is.SameAs(expectedObject)); + } - [Test] - public void ThrowsApplicationContextException_WhenContextNotRegistered() - { - var defaultXml = $@" + [Test] + public void ThrowsApplicationContextException_WhenContextNotRegistered() + { + var defaultXml = $@" "; - var defaultContext = GetContextFromXmlString(defaultXml, AbstractApplicationContext.DefaultRootContextName); - ContextRegistry.RegisterContext(defaultContext); + var defaultContext = GetContextFromXmlString(defaultXml, AbstractApplicationContext.DefaultRootContextName); + ContextRegistry.RegisterContext(defaultContext); - var expression = Expression.Parse("@(anotherContext:theObject).Value"); - void Get() => expression.GetValue(null, new Dictionary()); + var expression = Expression.Parse("@(anotherContext:theObject).Value"); + void Get() => expression.GetValue(null, new Dictionary()); - Assert.That(Get, Throws.InstanceOf()); - } + Assert.That(Get, Throws.InstanceOf()); + } - [Test] - public void WhenContextNameSpecifiedInExpression_UseThatContext() - { - const string anotherContextName = "AnotherContext"; + [Test] + public void WhenContextNameSpecifiedInExpression_UseThatContext() + { + const string anotherContextName = "AnotherContext"; - var defaultXml = $@" + var defaultXml = $@" "; - var anotherXml = $@" + var anotherXml = $@" "; - var defaultContext = GetContextFromXmlString(defaultXml, AbstractApplicationContext.DefaultRootContextName); - ContextRegistry.RegisterContext(defaultContext); + var defaultContext = GetContextFromXmlString(defaultXml, AbstractApplicationContext.DefaultRootContextName); + ContextRegistry.RegisterContext(defaultContext); - var anotherContext = GetContextFromXmlString(anotherXml, anotherContextName); - ContextRegistry.RegisterContext(anotherContext); + var anotherContext = GetContextFromXmlString(anotherXml, anotherContextName); + ContextRegistry.RegisterContext(anotherContext); - var expectedObject = anotherContext.GetObject("theObject"); + var expectedObject = anotherContext.GetObject("theObject"); - var expression = Expression.Parse($"@({anotherContextName}:theObject)"); - var resolvedObject = expression.GetValue(null, new Dictionary()); + var expression = Expression.Parse($"@({anotherContextName}:theObject)"); + var resolvedObject = expression.GetValue(null, new Dictionary()); - Assert.That(resolvedObject, Is.SameAs(expectedObject)); - } + Assert.That(resolvedObject, Is.SameAs(expectedObject)); + } - [Test] - public void UseObjectFactoryFromVariables() - { - const string anotherContextName = "AnotherContext"; + [Test] + public void UseObjectFactoryFromVariables() + { + const string anotherContextName = "AnotherContext"; - var defaultXml = $@" + var defaultXml = $@" "; - var anotherXml = $@" + var anotherXml = $@" "; - var defaultContext = GetContextFromXmlString(defaultXml, AbstractApplicationContext.DefaultRootContextName); - ContextRegistry.RegisterContext(defaultContext); + var defaultContext = GetContextFromXmlString(defaultXml, AbstractApplicationContext.DefaultRootContextName); + ContextRegistry.RegisterContext(defaultContext); - var anotherContext = GetContextFromXmlString(anotherXml, anotherContextName); - var variables = new Dictionary { [Expression.ReservedVariableNames.RESERVEDPREFIX + "CurrentObjectFactory"] = anotherContext.ObjectFactory }; - var expectedObject = anotherContext.GetObject("theObject"); + var anotherContext = GetContextFromXmlString(anotherXml, anotherContextName); + var variables = new Dictionary { [Expression.ReservedVariableNames.RESERVEDPREFIX + "CurrentObjectFactory"] = anotherContext.ObjectFactory }; + var expectedObject = anotherContext.GetObject("theObject"); - var expression = Expression.Parse("@(theObject)"); - var resolvedObject = expression.GetValue(null, variables); + var expression = Expression.Parse("@(theObject)"); + var resolvedObject = expression.GetValue(null, variables); - Assert.That(resolvedObject, Is.SameAs(expectedObject)); - } + Assert.That(resolvedObject, Is.SameAs(expectedObject)); + } - [Test] - public void ShouldThrowException_WhenFactoryProvidedInVariables_IsNotOfTypeIObjectFactory() - { - var defaultXml = $@" + [Test] + public void ShouldThrowException_WhenFactoryProvidedInVariables_IsNotOfTypeIObjectFactory() + { + var defaultXml = $@" "; - var defaultContext = GetContextFromXmlString(defaultXml, AbstractApplicationContext.DefaultRootContextName); - ContextRegistry.RegisterContext(defaultContext); + var defaultContext = GetContextFromXmlString(defaultXml, AbstractApplicationContext.DefaultRootContextName); + ContextRegistry.RegisterContext(defaultContext); - var variables = new Dictionary { [Expression.ReservedVariableNames.RESERVEDPREFIX + "CurrentObjectFactory"] = new object() }; + var variables = new Dictionary { [Expression.ReservedVariableNames.RESERVEDPREFIX + "CurrentObjectFactory"] = new object() }; - var expression = Expression.Parse("@(theObject)"); + var expression = Expression.Parse("@(theObject)"); - void Get() => expression.GetValue(null, variables); + void Get() => expression.GetValue(null, variables); - Assert.That(Get, Throws.InstanceOf()); - } + Assert.That(Get, Throws.InstanceOf()); + } - private static GenericApplicationContext GetContextFromXmlString(string xmlString, string contextName) - { - var stringResource = new StringResource(xmlString, Encoding.UTF8); - var objectFactory = new XmlObjectFactory(stringResource); + private static GenericApplicationContext GetContextFromXmlString(string xmlString, string contextName) + { + var stringResource = new StringResource(xmlString, Encoding.UTF8); + var objectFactory = new XmlObjectFactory(stringResource); - return new GenericApplicationContext(objectFactory) { Name = contextName }; - } + return new GenericApplicationContext(objectFactory) { Name = contextName }; } } diff --git a/test/Spring/Spring.Core.Tests/Expressions/SelectionNodeTests.cs b/test/Spring/Spring.Core.Tests/Expressions/SelectionNodeTests.cs index 4f6507df..c7df982e 100644 --- a/test/Spring/Spring.Core.Tests/Expressions/SelectionNodeTests.cs +++ b/test/Spring/Spring.Core.Tests/Expressions/SelectionNodeTests.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -25,39 +25,38 @@ using NUnit.Framework; #endregion -namespace Spring.Expressions +namespace Spring.Expressions; + +/// +/// +/// +/// Erich Eichinger +[TestFixture] +public class SelectionNodeTests { - /// - /// - /// - /// Erich Eichinger - [TestFixture] - public class SelectionNodeTests + [Test] + public void RespectsLimits() { - [Test] - public void RespectsLimits() - { - char[] input = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n' }; - char[] result; + char[] input = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n' }; + char[] result; - result = Evaluate("?{ true }", input); - Assert.AreEqual(input, result); - result = Evaluate("?{ true, 5, 10 }", input); - Assert.AreEqual( new char[] { 'f', 'g', 'h', 'i', 'j', 'k' }, result ); - result = Evaluate("?{ true, 5 }", input); - Assert.AreEqual(new char[] { 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n' }, result); - result = Evaluate("?{ true, 0, 10 }", input); - Assert.AreEqual(new char[] { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k' }, result); + result = Evaluate("?{ true }", input); + Assert.AreEqual(input, result); + result = Evaluate("?{ true, 5, 10 }", input); + Assert.AreEqual(new char[] { 'f', 'g', 'h', 'i', 'j', 'k' }, result); + result = Evaluate("?{ true, 5 }", input); + Assert.AreEqual(new char[] { 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n' }, result); + result = Evaluate("?{ true, 0, 10 }", input); + Assert.AreEqual(new char[] { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k' }, result); - result = Evaluate("?{ T(System.Convert).ToInt32(#this) % 2 == 0, 1, 3 }", input); - Assert.AreEqual(new char[] { 'd', 'f', 'h' }, result); - } - - private char[] Evaluate(string expression, char[] input) - { - IExpression expr = Expression.Parse(expression); - ICollection collection = (ICollection)expr.GetValue(input); - return (char[]) new ArrayList(collection).ToArray(typeof(char)); - } + result = Evaluate("?{ T(System.Convert).ToInt32(#this) % 2 == 0, 1, 3 }", input); + Assert.AreEqual(new char[] { 'd', 'f', 'h' }, result); } -} \ No newline at end of file + + private char[] Evaluate(string expression, char[] input) + { + IExpression expr = Expression.Parse(expression); + ICollection collection = (ICollection) expr.GetValue(input); + return (char[]) new ArrayList(collection).ToArray(typeof(char)); + } +} diff --git a/test/Spring/Spring.Core.Tests/Globalization/AbstractLocalizerTests.cs b/test/Spring/Spring.Core.Tests/Globalization/AbstractLocalizerTests.cs index 1fa79843..074fff6f 100644 --- a/test/Spring/Spring.Core.Tests/Globalization/AbstractLocalizerTests.cs +++ b/test/Spring/Spring.Core.Tests/Globalization/AbstractLocalizerTests.cs @@ -21,132 +21,131 @@ #region Imports using System.Globalization; - using NUnit.Framework; - using Spring.Context; #endregion -namespace Spring.Globalization +namespace Spring.Globalization; + +/// +/// Unit tests for the localizers. +/// +/// Aleksandar Seovic +public abstract class AbstractLocalizerTests { - /// - /// Unit tests for the localizers. - /// - /// Aleksandar Seovic - public abstract class AbstractLocalizerTests + private ILocalizer localizer; + + [OneTimeSetUp] + public void TestFixtureSetUp() { - private ILocalizer localizer; + CultureTestScope.Set("de-AT", "sr"); + } - [OneTimeSetUp] - public void TestFixtureSetUp() - { - CultureTestScope.Set("de-AT", "sr"); - } + [OneTimeTearDown] + public void TestFixtureTearDown() + { + CultureTestScope.Reset(); + } - [OneTimeTearDown] - public void TestFixtureTearDown() - { - CultureTestScope.Reset(); - } + [SetUp] + public void Init() + { + localizer = CreateLocalizer(); + } - [SetUp] - public void Init() - { - localizer = CreateLocalizer(); - } + [Test] + public void TestInvariantCulture() + { + Inventor tesla = CreateInventor(CultureInfo.InvariantCulture); + Assert.AreEqual("Nikola Tesla", tesla.Name); + Assert.AreEqual("Serbian", tesla.Nationality); + Assert.AreEqual(new DateTime(1856, 7, 9), tesla.DOB); + Assert.AreEqual("Croatia", tesla.PlaceOfBirth.Country); + Assert.AreEqual("Smiljan", tesla.PlaceOfBirth.City); + } - [Test] - public void TestInvariantCulture() - { - Inventor tesla = CreateInventor(CultureInfo.InvariantCulture); - Assert.AreEqual("Nikola Tesla", tesla.Name); - Assert.AreEqual("Serbian", tesla.Nationality); - Assert.AreEqual(new DateTime(1856, 7, 9), tesla.DOB); - Assert.AreEqual("Croatia", tesla.PlaceOfBirth.Country); - Assert.AreEqual("Smiljan", tesla.PlaceOfBirth.City); - } + [Test] + public void TestSerbianLatin() + { + Inventor tesla = CreateInventor(new CultureInfo(CultureInfoUtils.SerbianLatinCultureName)); + Assert.AreEqual("Nikola Tesla", tesla.Name); + Assert.AreEqual("Srbin", tesla.Nationality); + Assert.AreEqual(new DateTime(1856, 7, 9), tesla.DOB); + Assert.AreEqual("Hrvatska", tesla.PlaceOfBirth.Country); + Assert.AreEqual("Smiljan", tesla.PlaceOfBirth.City); + } - [Test] - public void TestSerbianLatin() - { - Inventor tesla = CreateInventor(new CultureInfo(CultureInfoUtils.SerbianLatinCultureName)); - Assert.AreEqual("Nikola Tesla", tesla.Name); - Assert.AreEqual("Srbin", tesla.Nationality); - Assert.AreEqual(new DateTime(1856, 7, 9), tesla.DOB); - Assert.AreEqual("Hrvatska", tesla.PlaceOfBirth.Country); - Assert.AreEqual("Smiljan", tesla.PlaceOfBirth.City); - } + [Test] + public void TestSerbianCyrillic() + { + Inventor tesla = CreateInventor(new CultureInfo(CultureInfoUtils.SerbianCyrillicCultureName)); + Assert.AreEqual("Ðикола ТеÑла", tesla.Name); + Assert.AreEqual("Србин", tesla.Nationality); + Assert.AreEqual(new DateTime(1856, 7, 9), tesla.DOB); + Assert.AreEqual("ХрватÑка", tesla.PlaceOfBirth.Country); + Assert.AreEqual("Смиљан", tesla.PlaceOfBirth.City); + } - [Test] - public void TestSerbianCyrillic() - { - Inventor tesla = CreateInventor(new CultureInfo(CultureInfoUtils.SerbianCyrillicCultureName)); - Assert.AreEqual("Ðикола ТеÑла", tesla.Name); - Assert.AreEqual("Србин", tesla.Nationality); - Assert.AreEqual(new DateTime(1856, 7, 9), tesla.DOB); - Assert.AreEqual("ХрватÑка", tesla.PlaceOfBirth.Country); - Assert.AreEqual("Смиљан", tesla.PlaceOfBirth.City); - } - - [Test] - public void NullReferenceHandling() - { + [Test] + public void NullReferenceHandling() + { // ResourceSetMessageSource messageSource = new ResourceSetMessageSource(); // messageSource.ResourceManagers.Add(new ResourceManager("Spring.Resources.Tesla", GetType().Assembly)); // ResourceSetLocalizer localizer = new ResourceSetLocalizer(); - IMessageSource messageSource = CreateMessageSource(); + IMessageSource messageSource = CreateMessageSource(); - // target must not be null - try - { - localizer.ApplyResources(null, messageSource, CultureInfo.InvariantCulture); - Assert.Fail(); - } - catch (ArgumentNullException) { } - try - { - localizer.ApplyResources(null, messageSource); - Assert.Fail(); - } - catch (ArgumentNullException) { } - - // messageSource may be null - localizer.ApplyResources(new object(), null); - localizer.ApplyResources(new object(), null, CultureInfo.InvariantCulture); - - try - { - localizer.ApplyResources(new object(), messageSource, null); - Assert.Fail(); - } - catch (ArgumentNullException) { } - } -#if !MONO - [Test] - public void DefaultResolvesUsingCurrentUICulture() + // target must not be null + try { - Inventor tesla = CreateInventor(null); - Assert.AreEqual("Nikola Tesla", tesla.Name); - Assert.AreEqual("Srbin", tesla.Nationality); - } -#endif - private Inventor CreateInventor(CultureInfo culture) - { - Inventor inventor = new Inventor(); - IMessageSource messageSource = CreateMessageSource(); - if (culture == null) - { - localizer.ApplyResources(inventor, messageSource); - } - else - { - localizer.ApplyResources(inventor, messageSource, culture); - } - return inventor; + localizer.ApplyResources(null, messageSource, CultureInfo.InvariantCulture); + Assert.Fail(); } + catch (ArgumentNullException) { } - protected abstract ILocalizer CreateLocalizer(); - protected abstract IMessageSource CreateMessageSource(); + try + { + localizer.ApplyResources(null, messageSource); + Assert.Fail(); + } + catch (ArgumentNullException) { } + + // messageSource may be null + localizer.ApplyResources(new object(), null); + localizer.ApplyResources(new object(), null, CultureInfo.InvariantCulture); + + try + { + localizer.ApplyResources(new object(), messageSource, null); + Assert.Fail(); + } + catch (ArgumentNullException) { } } -} \ No newline at end of file +#if !MONO + [Test] + public void DefaultResolvesUsingCurrentUICulture() + { + Inventor tesla = CreateInventor(null); + Assert.AreEqual("Nikola Tesla", tesla.Name); + Assert.AreEqual("Srbin", tesla.Nationality); + } +#endif + private Inventor CreateInventor(CultureInfo culture) + { + Inventor inventor = new Inventor(); + IMessageSource messageSource = CreateMessageSource(); + if (culture == null) + { + localizer.ApplyResources(inventor, messageSource); + } + else + { + localizer.ApplyResources(inventor, messageSource, culture); + } + + return inventor; + } + + protected abstract ILocalizer CreateLocalizer(); + protected abstract IMessageSource CreateMessageSource(); +} diff --git a/test/Spring/Spring.Core.Tests/Globalization/CultureInfoUtils.cs b/test/Spring/Spring.Core.Tests/Globalization/CultureInfoUtils.cs index a317ca1a..5fc02f76 100644 --- a/test/Spring/Spring.Core.Tests/Globalization/CultureInfoUtils.cs +++ b/test/Spring/Spring.Core.Tests/Globalization/CultureInfoUtils.cs @@ -20,48 +20,47 @@ using System.Globalization; -namespace Spring.Globalization +namespace Spring.Globalization; + +/// +/// Helper class for Globalization Tests +/// +/// Ensure the appropriate culture name for serbian due to changes of the CultureInfo classes +/// in recent releases of the .NET framework.In short, sr-SP-Latn->sr-Latn-CS and sr-SP-Cyrl->sr-Cyrl-CS. See http://blogs.msdn.com/kierans/archive/2006/08/02/687267.aspx +/// and http://blogs.msdn.com/shawnste/archive/2006/11/14/problems-compiling-resources-in-net-2-0-apps-after-updates.aspx for +/// additional information. +/// Also, provide for detection of runtime OS to respond to need for different asserts to reflect changes in Serbian Localization within the OS +/// introduced after Windows7. +/// +/// Mark Pollack +public class CultureInfoUtils { - /// - /// Helper class for Globalization Tests - /// - /// Ensure the appropriate culture name for serbian due to changes of the CultureInfo classes - /// in recent releases of the .NET framework.In short, sr-SP-Latn->sr-Latn-CS and sr-SP-Cyrl->sr-Cyrl-CS. See http://blogs.msdn.com/kierans/archive/2006/08/02/687267.aspx - /// and http://blogs.msdn.com/shawnste/archive/2006/11/14/problems-compiling-resources-in-net-2-0-apps-after-updates.aspx for - /// additional information. - /// Also, provide for detection of runtime OS to respond to need for different asserts to reflect changes in Serbian Localization within the OS - /// introduced after Windows7. - /// - /// Mark Pollack - public class CultureInfoUtils + private static readonly string srLatn = "sr-SP-Latn"; + private static readonly string srCyrl = "sr-SP-Cyrl"; + + static CultureInfoUtils() { - private static readonly string srLatn = "sr-SP-Latn"; - private static readonly string srCyrl = "sr-SP-Cyrl"; - - static CultureInfoUtils() + foreach (CultureInfo ci in CultureInfo.GetCultures(CultureTypes.AllCultures)) { - foreach (CultureInfo ci in CultureInfo.GetCultures(CultureTypes.AllCultures)) + //address changes in 2006 (see blog posts above) + if (ci.Name.Equals("sr-Latn-CS")) { - //address changes in 2006 (see blog posts above) - if (ci.Name.Equals("sr-Latn-CS")) - { - srLatn = "sr-Latn-CS"; - srCyrl = "sr-Cyrl-CS"; - break; - } + srLatn = "sr-Latn-CS"; + srCyrl = "sr-Cyrl-CS"; + break; + } - //address changes introduced in Windows 10 "November 2015 Update" (build 10586) - if (ci.Name.Equals("sr-Latn-RS")) - { - srLatn = "sr-Latn-RS"; - srCyrl = "sr-Cyrl-RS"; - break; - } + //address changes introduced in Windows 10 "November 2015 Update" (build 10586) + if (ci.Name.Equals("sr-Latn-RS")) + { + srLatn = "sr-Latn-RS"; + srCyrl = "sr-Cyrl-RS"; + break; } } - - public static string SerbianCyrillicCultureName => srCyrl; - - public static string SerbianLatinCultureName => srLatn; } + + public static string SerbianCyrillicCultureName => srCyrl; + + public static string SerbianLatinCultureName => srLatn; } diff --git a/test/Spring/Spring.Core.Tests/Globalization/CultureTestScope.cs b/test/Spring/Spring.Core.Tests/Globalization/CultureTestScope.cs index 648fe140..08edcf06 100644 --- a/test/Spring/Spring.Core.Tests/Globalization/CultureTestScope.cs +++ b/test/Spring/Spring.Core.Tests/Globalization/CultureTestScope.cs @@ -24,54 +24,53 @@ using System.Globalization; #endregion -namespace Spring.Globalization +namespace Spring.Globalization; + +/// +/// Helps setting/resetting current thread cultures. +/// +/// Erich Eichinger +public class CultureTestScope : IDisposable { - /// - /// Helps setting/resetting current thread cultures. - /// - /// Erich Eichinger - public class CultureTestScope : IDisposable + [ThreadStatic] private static CultureTestScope s_currentScope; + + public static void Set() { - [ThreadStatic] - private static CultureTestScope s_currentScope; - - public static void Set() - { - Set("en-GB", "de-DE"); - } - - public static void Set(string culture, string uiCulture) - { - s_currentScope = new CultureTestScope(culture, uiCulture); - } - - public static void Reset() - { - CultureTestScope scope = s_currentScope; s_currentScope = null; - scope.Dispose(); - } - - private readonly CultureInfo _prevCulture; - private readonly CultureInfo _prevUICulture; - - private CultureTestScope(string culture, string uiCulture) - { - this._prevCulture = Thread.CurrentThread.CurrentCulture; - this._prevUICulture = Thread.CurrentThread.CurrentUICulture; - - Thread.CurrentThread.CurrentCulture = new CultureInfo(culture); - Thread.CurrentThread.CurrentUICulture = new CultureInfo(uiCulture); - } - - void IDisposable.Dispose() - { - this.Dispose(); - } - - private void Dispose() - { - Thread.CurrentThread.CurrentCulture = this._prevCulture; - Thread.CurrentThread.CurrentUICulture = this._prevUICulture; - } + Set("en-GB", "de-DE"); } -} \ No newline at end of file + + public static void Set(string culture, string uiCulture) + { + s_currentScope = new CultureTestScope(culture, uiCulture); + } + + public static void Reset() + { + CultureTestScope scope = s_currentScope; + s_currentScope = null; + scope.Dispose(); + } + + private readonly CultureInfo _prevCulture; + private readonly CultureInfo _prevUICulture; + + private CultureTestScope(string culture, string uiCulture) + { + this._prevCulture = Thread.CurrentThread.CurrentCulture; + this._prevUICulture = Thread.CurrentThread.CurrentUICulture; + + Thread.CurrentThread.CurrentCulture = new CultureInfo(culture); + Thread.CurrentThread.CurrentUICulture = new CultureInfo(uiCulture); + } + + void IDisposable.Dispose() + { + this.Dispose(); + } + + private void Dispose() + { + Thread.CurrentThread.CurrentCulture = this._prevCulture; + Thread.CurrentThread.CurrentUICulture = this._prevUICulture; + } +} diff --git a/test/Spring/Spring.Core.Tests/Globalization/Formatters/BooleanFormatterTests.cs b/test/Spring/Spring.Core.Tests/Globalization/Formatters/BooleanFormatterTests.cs index e69de29b..8b137891 100644 --- a/test/Spring/Spring.Core.Tests/Globalization/Formatters/BooleanFormatterTests.cs +++ b/test/Spring/Spring.Core.Tests/Globalization/Formatters/BooleanFormatterTests.cs @@ -0,0 +1 @@ + diff --git a/test/Spring/Spring.Core.Tests/Globalization/Formatters/CurrencyFormatterTests.cs b/test/Spring/Spring.Core.Tests/Globalization/Formatters/CurrencyFormatterTests.cs index 8a9c3a06..25048028 100644 --- a/test/Spring/Spring.Core.Tests/Globalization/Formatters/CurrencyFormatterTests.cs +++ b/test/Spring/Spring.Core.Tests/Globalization/Formatters/CurrencyFormatterTests.cs @@ -20,54 +20,54 @@ using NUnit.Framework; -namespace Spring.Globalization.Formatters +namespace Spring.Globalization.Formatters; + +/// +/// Unit tests for CurrencyFormatter class. +/// +/// Aleksandar Seovic +public class CurrencyFormatterTests { - /// - /// Unit tests for CurrencyFormatter class. - /// - /// Aleksandar Seovic - public class CurrencyFormatterTests + [Test] + public void FormatNullValue() { - [Test] - public void FormatNullValue() - { - CurrencyFormatter fmt = new CurrencyFormatter(); - Assert.Throws(() => fmt.Format(null)); - } + CurrencyFormatter fmt = new CurrencyFormatter(); + Assert.Throws(() => fmt.Format(null)); + } - [Test] - public void ParseNullOrEmptyValue() - { - CurrencyFormatter fmt = new CurrencyFormatter(); - Assert.AreEqual(0, fmt.Parse(null)); - Assert.IsTrue(fmt.Parse("") is double); - } + [Test] + public void ParseNullOrEmptyValue() + { + CurrencyFormatter fmt = new CurrencyFormatter(); + Assert.AreEqual(0, fmt.Parse(null)); + Assert.IsTrue(fmt.Parse("") is double); + } - [Test] - public void FormatNonNumber() - { - CurrencyFormatter fmt = new CurrencyFormatter(); - Assert.Throws(() => fmt.Format("not a number")); - } + [Test] + public void FormatNonNumber() + { + CurrencyFormatter fmt = new CurrencyFormatter(); + Assert.Throws(() => fmt.Format("not a number")); + } - [Test] - [Platform("Win")] - public void FormatUsingDefaults() - { - CurrencyFormatter fmt = new CurrencyFormatter("en-US"); - Assert.AreEqual("$1,234.00", fmt.Format(1234)); - Assert.AreEqual("$1,234.56", fmt.Format(1234.56)); - Assert.AreEqual("($1,234.00)", fmt.Format(-1234)); - Assert.AreEqual("($1,234.56)", fmt.Format(-1234.56)); + [Test] + [Platform("Win")] + public void FormatUsingDefaults() + { + CurrencyFormatter fmt = new CurrencyFormatter("en-US"); + Assert.AreEqual("$1,234.00", fmt.Format(1234)); + Assert.AreEqual("$1,234.56", fmt.Format(1234.56)); + Assert.AreEqual("($1,234.00)", fmt.Format(-1234)); + Assert.AreEqual("($1,234.56)", fmt.Format(-1234.56)); - fmt = new CurrencyFormatter(CultureInfoUtils.SerbianLatinCultureName); + fmt = new CurrencyFormatter(CultureInfoUtils.SerbianLatinCultureName); - Assert.AreEqual("1.234 RSD", fmt.Format(1234)); - Assert.AreEqual("1.235 RSD", fmt.Format(1234.56)); - Assert.AreEqual("-1.234 RSD", fmt.Format(-1234)); - Assert.AreEqual("-1.235 RSD", fmt.Format(-1234.56)); + Assert.AreEqual("1.234 RSD", fmt.Format(1234)); + Assert.AreEqual("1.235 RSD", fmt.Format(1234.56)); + Assert.AreEqual("-1.234 RSD", fmt.Format(-1234)); + Assert.AreEqual("-1.235 RSD", fmt.Format(-1234.56)); - fmt = new CurrencyFormatter(CultureInfoUtils.SerbianCyrillicCultureName); + fmt = new CurrencyFormatter(CultureInfoUtils.SerbianCyrillicCultureName); #if NETFRAMEWORK Assert.AreEqual("1.234,00 дин.", fmt.Format(1234)); @@ -75,29 +75,29 @@ namespace Spring.Globalization.Formatters Assert.AreEqual("-1.234,00 дин.", fmt.Format(-1234)); Assert.AreEqual("-1.234,56 дин.", fmt.Format(-1234.56)); #else - Assert.AreEqual("1.234 RSD", fmt.Format(1234)); - Assert.AreEqual("1.235 RSD", fmt.Format(1234.56)); - Assert.AreEqual("-1.234 RSD", fmt.Format(-1234)); - Assert.AreEqual("-1.235 RSD", fmt.Format(-1234.56)); + Assert.AreEqual("1.234 RSD", fmt.Format(1234)); + Assert.AreEqual("1.235 RSD", fmt.Format(1234.56)); + Assert.AreEqual("-1.234 RSD", fmt.Format(-1234)); + Assert.AreEqual("-1.235 RSD", fmt.Format(-1234.56)); #endif - } + } - [Test] - [Platform("Win")] - public void ParseUsingDefaults() - { - CurrencyFormatter fmt = new CurrencyFormatter("en-US"); - Assert.AreEqual(1234, fmt.Parse("$1,234.00")); - Assert.AreEqual(1234.56, fmt.Parse("$1,234.56")); - Assert.AreEqual(-1234, fmt.Parse("($1,234.00)")); - Assert.AreEqual(-1234.56, fmt.Parse("($1,234.56)")); + [Test] + [Platform("Win")] + public void ParseUsingDefaults() + { + CurrencyFormatter fmt = new CurrencyFormatter("en-US"); + Assert.AreEqual(1234, fmt.Parse("$1,234.00")); + Assert.AreEqual(1234.56, fmt.Parse("$1,234.56")); + Assert.AreEqual(-1234, fmt.Parse("($1,234.00)")); + Assert.AreEqual(-1234.56, fmt.Parse("($1,234.56)")); - fmt = new CurrencyFormatter(CultureInfoUtils.SerbianLatinCultureName); + fmt = new CurrencyFormatter(CultureInfoUtils.SerbianLatinCultureName); - Assert.AreEqual(1234, fmt.Parse("1.234 RSD")); - Assert.AreEqual(-1234, fmt.Parse("-1.234 RSD")); + Assert.AreEqual(1234, fmt.Parse("1.234 RSD")); + Assert.AreEqual(-1234, fmt.Parse("-1.234 RSD")); - fmt = new CurrencyFormatter(CultureInfoUtils.SerbianCyrillicCultureName); + fmt = new CurrencyFormatter(CultureInfoUtils.SerbianCyrillicCultureName); #if NETFRAMEWORK Assert.AreEqual(1234, fmt.Parse("1.234,00 дин.")); @@ -105,32 +105,32 @@ namespace Spring.Globalization.Formatters Assert.AreEqual(-1234, fmt.Parse("-1.234,00 дин.")); Assert.AreEqual(-1234.56, fmt.Parse("-1.234,56 дин.")); #endif - } + } - [Test] - [Platform("Win")] - public void FormatUsingCustomSettings() - { - CurrencyFormatter fmt = new CurrencyFormatter("en-US"); - fmt.DecimalDigits = 0; - fmt.NegativePattern = 1; - Assert.AreEqual("$1,234", fmt.Format(1234)); - Assert.AreEqual("$1,235", fmt.Format(1234.56)); - Assert.AreEqual("-$1,234", fmt.Format(-1234)); - Assert.AreEqual("-$1,235", fmt.Format(-1234.56)); + [Test] + [Platform("Win")] + public void FormatUsingCustomSettings() + { + CurrencyFormatter fmt = new CurrencyFormatter("en-US"); + fmt.DecimalDigits = 0; + fmt.NegativePattern = 1; + Assert.AreEqual("$1,234", fmt.Format(1234)); + Assert.AreEqual("$1,235", fmt.Format(1234.56)); + Assert.AreEqual("-$1,234", fmt.Format(-1234)); + Assert.AreEqual("-$1,235", fmt.Format(-1234.56)); - fmt = new CurrencyFormatter(CultureInfoUtils.SerbianLatinCultureName); - fmt.PositivePattern = 1; - fmt.CurrencySymbol = "din"; + fmt = new CurrencyFormatter(CultureInfoUtils.SerbianLatinCultureName); + fmt.PositivePattern = 1; + fmt.CurrencySymbol = "din"; - Assert.AreEqual("1.234din", fmt.Format(1234)); - Assert.AreEqual("1.235din", fmt.Format(1234.56)); - Assert.AreEqual("-1.234 din", fmt.Format(-1234)); - Assert.AreEqual("-1.235 din", fmt.Format(-1234.56)); + Assert.AreEqual("1.234din", fmt.Format(1234)); + Assert.AreEqual("1.235din", fmt.Format(1234.56)); + Assert.AreEqual("-1.234 din", fmt.Format(-1234)); + Assert.AreEqual("-1.235 din", fmt.Format(-1234.56)); - fmt = new CurrencyFormatter(CultureInfoUtils.SerbianCyrillicCultureName); - fmt.GroupSizes = new int[] { 1, 2 }; - fmt.GroupSeparator = "'"; + fmt = new CurrencyFormatter(CultureInfoUtils.SerbianCyrillicCultureName); + fmt.GroupSizes = new int[] { 1, 2 }; + fmt.GroupSeparator = "'"; #if NETFRAMEWORK Assert.AreEqual("1'23'4,00 дин.", fmt.Format(1234)); @@ -138,36 +138,36 @@ namespace Spring.Globalization.Formatters Assert.AreEqual("-1'23'4,00 дин.", fmt.Format(-1234)); Assert.AreEqual("-1'23'4,56 дин.", fmt.Format(-1234.56)); #else - Assert.AreEqual("1'23'4 RSD", fmt.Format(1234)); - Assert.AreEqual("1'23'5 RSD", fmt.Format(1234.56)); - Assert.AreEqual("-1'23'4 RSD", fmt.Format(-1234)); - Assert.AreEqual("-1'23'5 RSD", fmt.Format(-1234.56)); + Assert.AreEqual("1'23'4 RSD", fmt.Format(1234)); + Assert.AreEqual("1'23'5 RSD", fmt.Format(1234.56)); + Assert.AreEqual("-1'23'4 RSD", fmt.Format(-1234)); + Assert.AreEqual("-1'23'5 RSD", fmt.Format(-1234.56)); #endif - } + } - [Test] - [Platform("Win")] - public void ParseUsingCustomSettings() - { - CurrencyFormatter fmt = new CurrencyFormatter("en-US"); - fmt.DecimalDigits = 0; - fmt.NegativePattern = 1; - Assert.AreEqual(1234, fmt.Parse("$1,234")); - Assert.AreEqual(1234.56, fmt.Parse("$1,234.56")); - Assert.AreEqual(-1234, fmt.Parse("-$1,234")); - Assert.AreEqual(-1234.56, fmt.Parse("-$1,234.56")); + [Test] + [Platform("Win")] + public void ParseUsingCustomSettings() + { + CurrencyFormatter fmt = new CurrencyFormatter("en-US"); + fmt.DecimalDigits = 0; + fmt.NegativePattern = 1; + Assert.AreEqual(1234, fmt.Parse("$1,234")); + Assert.AreEqual(1234.56, fmt.Parse("$1,234.56")); + Assert.AreEqual(-1234, fmt.Parse("-$1,234")); + Assert.AreEqual(-1234.56, fmt.Parse("-$1,234.56")); - fmt = new CurrencyFormatter("sr-SP-Latn"); - fmt.PositivePattern = 1; - fmt.CurrencySymbol = "din"; - Assert.AreEqual(1234, fmt.Parse("1.234,00din")); - Assert.AreEqual(1234.56, fmt.Parse("1.234,56din")); - Assert.AreEqual(-1234, fmt.Parse("-1.234,00 din")); - Assert.AreEqual(-1234.56, fmt.Parse("-1.234,56 din")); + fmt = new CurrencyFormatter("sr-SP-Latn"); + fmt.PositivePattern = 1; + fmt.CurrencySymbol = "din"; + Assert.AreEqual(1234, fmt.Parse("1.234,00din")); + Assert.AreEqual(1234.56, fmt.Parse("1.234,56din")); + Assert.AreEqual(-1234, fmt.Parse("-1.234,00 din")); + Assert.AreEqual(-1234.56, fmt.Parse("-1.234,56 din")); - fmt = new CurrencyFormatter(CultureInfoUtils.SerbianCyrillicCultureName); - fmt.GroupSizes = new int[] { 1, 2 }; - fmt.GroupSeparator = "'"; + fmt = new CurrencyFormatter(CultureInfoUtils.SerbianCyrillicCultureName); + fmt.GroupSizes = new int[] { 1, 2 }; + fmt.GroupSeparator = "'"; #if NETFRAMEWORK Assert.AreEqual(1234, fmt.Parse("1'23'4,00 дин.")); @@ -175,6 +175,5 @@ namespace Spring.Globalization.Formatters Assert.AreEqual(-1234, fmt.Parse("-1'23'4,00 дин.")); Assert.AreEqual(-1234.56, fmt.Parse("-1'23'4,56 дин.")); #endif - } } } diff --git a/test/Spring/Spring.Core.Tests/Globalization/Formatters/DateTimeFormatterTests.cs b/test/Spring/Spring.Core.Tests/Globalization/Formatters/DateTimeFormatterTests.cs index 956a3f68..166990b3 100644 --- a/test/Spring/Spring.Core.Tests/Globalization/Formatters/DateTimeFormatterTests.cs +++ b/test/Spring/Spring.Core.Tests/Globalization/Formatters/DateTimeFormatterTests.cs @@ -20,88 +20,86 @@ using NUnit.Framework; -namespace Spring.Globalization.Formatters +namespace Spring.Globalization.Formatters; + +/// +/// Unit tests for DateTimeFormatter class. +/// +/// Aleksandar Seovic +public class DateTimeFormatterTests { - /// - /// Unit tests for DateTimeFormatter class. - /// - /// Aleksandar Seovic - public class DateTimeFormatterTests + [Test] + public void FormatNullValue() { - [Test] - public void FormatNullValue() - { - DateTimeFormatter fmt = new DateTimeFormatter("d"); - Assert.Throws(() => fmt.Format(null)); - } + DateTimeFormatter fmt = new DateTimeFormatter("d"); + Assert.Throws(() => fmt.Format(null)); + } - [Test] - public void ParseNullOrEmptyValue() - { - DateTimeFormatter fmt = new DateTimeFormatter("d"); - Assert.AreEqual(DateTime.MinValue, fmt.Parse(null)); - Assert.IsTrue(fmt.Parse("") is DateTime); - } + [Test] + public void ParseNullOrEmptyValue() + { + DateTimeFormatter fmt = new DateTimeFormatter("d"); + Assert.AreEqual(DateTime.MinValue, fmt.Parse(null)); + Assert.IsTrue(fmt.Parse("") is DateTime); + } - [Test] - public void FormatNonDate() - { - DateTimeFormatter fmt = new DateTimeFormatter("d"); - Assert.Throws(() => fmt.Format("not a date")); - } + [Test] + public void FormatNonDate() + { + DateTimeFormatter fmt = new DateTimeFormatter("d"); + Assert.Throws(() => fmt.Format("not a date")); + } - [Test] - [Platform("Win")] - public void FormatUsingDefaults() - { - DateTimeFormatter fmt = new DateTimeFormatter("d", "en-US"); - - Assert.AreEqual("8/14/2004", fmt.Format(new DateTime(2004, 8, 14))); - Assert.AreEqual("8/24/1974", fmt.Format(new DateTime(1974, 8, 24))); + [Test] + [Platform("Win")] + public void FormatUsingDefaults() + { + DateTimeFormatter fmt = new DateTimeFormatter("d", "en-US"); - fmt = new DateTimeFormatter("dd-MMM-yyyy", "en-US"); - Assert.AreEqual("14-Aug-2004", fmt.Format(new DateTime(2004, 8, 14))); - Assert.AreEqual("24-Aug-1974", fmt.Format(new DateTime(1974, 8, 24))); + Assert.AreEqual("8/14/2004", fmt.Format(new DateTime(2004, 8, 14))); + Assert.AreEqual("8/24/1974", fmt.Format(new DateTime(1974, 8, 24))); - fmt = new DateTimeFormatter("D", CultureInfoUtils.SerbianLatinCultureName); + fmt = new DateTimeFormatter("dd-MMM-yyyy", "en-US"); + Assert.AreEqual("14-Aug-2004", fmt.Format(new DateTime(2004, 8, 14))); + Assert.AreEqual("24-Aug-1974", fmt.Format(new DateTime(1974, 8, 24))); - Assert.AreEqual("subota, 14. avgust 2004.", fmt.Format(new DateTime(2004, 8, 14))); - Assert.AreEqual("subota, 24. avgust 1974.", fmt.Format(new DateTime(1974, 8, 24))); + fmt = new DateTimeFormatter("D", CultureInfoUtils.SerbianLatinCultureName); - fmt = new DateTimeFormatter("dd-MMM-yyyy", CultureInfoUtils.SerbianCyrillicCultureName); + Assert.AreEqual("subota, 14. avgust 2004.", fmt.Format(new DateTime(2004, 8, 14))); + Assert.AreEqual("subota, 24. avgust 1974.", fmt.Format(new DateTime(1974, 8, 24))); + + fmt = new DateTimeFormatter("dd-MMM-yyyy", CultureInfoUtils.SerbianCyrillicCultureName); #if NETFRAMEWORK - Assert.AreEqual("14-авг.-2004", fmt.Format(new DateTime(2004, 8, 14))); - Assert.AreEqual("24-авг.-1974", fmt.Format(new DateTime(1974, 8, 24))); + Assert.AreEqual("14-авг.-2004", fmt.Format(new DateTime(2004, 8, 14))); + Assert.AreEqual("24-авг.-1974", fmt.Format(new DateTime(1974, 8, 24))); #else Assert.AreEqual("14-авг-2004", fmt.Format(new DateTime(2004, 8, 14))); Assert.AreEqual("24-авг-1974", fmt.Format(new DateTime(1974, 8, 24))); #endif - } + } - [Test] - [Platform("Win")] - [Ignore("Problematic due to framework differences")] - public void ParseUsingDefaults() - { - DateTimeFormatter fmt = new DateTimeFormatter("d", "en-US"); - Assert.AreEqual(new DateTime(2004, 8, 14), fmt.Parse("8/14/2004")); - Assert.AreEqual(new DateTime(1974, 8, 24), fmt.Parse("8/24/1974")); + [Test] + [Platform("Win")] + [Ignore("Problematic due to framework differences")] + public void ParseUsingDefaults() + { + DateTimeFormatter fmt = new DateTimeFormatter("d", "en-US"); + Assert.AreEqual(new DateTime(2004, 8, 14), fmt.Parse("8/14/2004")); + Assert.AreEqual(new DateTime(1974, 8, 24), fmt.Parse("8/24/1974")); - fmt = new DateTimeFormatter("dd-MMM-yyyy", "en-US"); - Assert.AreEqual(new DateTime(2004, 8, 14), fmt.Parse("14-Aug-2004")); - Assert.AreEqual(new DateTime(1974, 8, 24), fmt.Parse("24-Aug-1974")); + fmt = new DateTimeFormatter("dd-MMM-yyyy", "en-US"); + Assert.AreEqual(new DateTime(2004, 8, 14), fmt.Parse("14-Aug-2004")); + Assert.AreEqual(new DateTime(1974, 8, 24), fmt.Parse("24-Aug-1974")); - fmt = new DateTimeFormatter("D", CultureInfoUtils.SerbianLatinCultureName); + fmt = new DateTimeFormatter("D", CultureInfoUtils.SerbianLatinCultureName); - Assert.AreEqual(new DateTime(2004, 8, 14), fmt.Parse("subota, 14. avgust 2004.")); - Assert.AreEqual(new DateTime(1974, 8, 24), fmt.Parse("subota, 24. avgust 1974.")); + Assert.AreEqual(new DateTime(2004, 8, 14), fmt.Parse("subota, 14. avgust 2004.")); + Assert.AreEqual(new DateTime(1974, 8, 24), fmt.Parse("subota, 24. avgust 1974.")); - fmt = new DateTimeFormatter("dd-MMM-yyyy", CultureInfoUtils.SerbianCyrillicCultureName); + fmt = new DateTimeFormatter("dd-MMM-yyyy", CultureInfoUtils.SerbianCyrillicCultureName); - Assert.AreEqual(new DateTime(2004, 8, 14), fmt.Parse("14-авг-2004")); - Assert.AreEqual(new DateTime(1974, 8, 24), fmt.Parse("24-авг-1974")); - - } + Assert.AreEqual(new DateTime(2004, 8, 14), fmt.Parse("14-авг-2004")); + Assert.AreEqual(new DateTime(1974, 8, 24), fmt.Parse("24-авг-1974")); } } diff --git a/test/Spring/Spring.Core.Tests/Globalization/Formatters/FilteringFormatterTests.cs b/test/Spring/Spring.Core.Tests/Globalization/Formatters/FilteringFormatterTests.cs index 26767e08..e75fd79b 100644 --- a/test/Spring/Spring.Core.Tests/Globalization/Formatters/FilteringFormatterTests.cs +++ b/test/Spring/Spring.Core.Tests/Globalization/Formatters/FilteringFormatterTests.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -19,67 +19,64 @@ #endregion using FakeItEasy; - using NUnit.Framework; -namespace Spring.Globalization.Formatters +namespace Spring.Globalization.Formatters; + +/// +/// +/// +/// Erich Eichinger +[TestFixture] +public class FilteringFormatterTests { - /// - /// - /// - /// Erich Eichinger - [TestFixture] - public class FilteringFormatterTests + public class TestFilteringFormatter : FilteringFormatter { - public class TestFilteringFormatter : FilteringFormatter + public TestFilteringFormatter(IFormatter underlyingFormatter) : base(underlyingFormatter) { - public TestFilteringFormatter(IFormatter underlyingFormatter) : base(underlyingFormatter) - { - } - - protected override string FilterValueToParse(string value) - { - return this.DoFilterValueToParse(value); - } - - public virtual string DoFilterValueToParse(string value) - { - return base.FilterValueToParse(value); - } - - protected override object FilterValueToFormat(object value) - { - return this.DoFilterValueToFormat(value); - } - - public virtual object DoFilterValueToFormat(object value) - { - return base.FilterValueToFormat(value); - } - } - [Test] - public void FiltersOnParseAndFormat() + protected override string FilterValueToParse(string value) { - IFormatter underlyingFormatter = A.Fake(); - TestFilteringFormatter formatter = A.Fake(x => x - .CallsBaseMethods() - .WithArgumentsForConstructor(new[] {underlyingFormatter})); + return this.DoFilterValueToParse(value); + } - string inputText = "inputText"; - string filteredInputText = "filteredInputText"; - object outputValue = new object(); - object filteredOutputValue = new object(); + public virtual string DoFilterValueToParse(string value) + { + return base.FilterValueToParse(value); + } - A.CallTo(() => formatter.DoFilterValueToParse(inputText)).Returns(filteredInputText); - A.CallTo(() => underlyingFormatter.Parse(filteredInputText)).Returns(outputValue); + protected override object FilterValueToFormat(object value) + { + return this.DoFilterValueToFormat(value); + } - A.CallTo(() => formatter.DoFilterValueToFormat(outputValue)).Returns(filteredOutputValue); - A.CallTo(() => underlyingFormatter.Format(filteredOutputValue)).Returns(inputText); - - Assert.AreSame(outputValue, formatter.Parse(inputText)); - Assert.AreEqual(inputText, formatter.Format(outputValue)); + public virtual object DoFilterValueToFormat(object value) + { + return base.FilterValueToFormat(value); } } -} \ No newline at end of file + + [Test] + public void FiltersOnParseAndFormat() + { + IFormatter underlyingFormatter = A.Fake(); + TestFilteringFormatter formatter = A.Fake(x => x + .CallsBaseMethods() + .WithArgumentsForConstructor(new[] { underlyingFormatter })); + + string inputText = "inputText"; + string filteredInputText = "filteredInputText"; + object outputValue = new object(); + object filteredOutputValue = new object(); + + A.CallTo(() => formatter.DoFilterValueToParse(inputText)).Returns(filteredInputText); + A.CallTo(() => underlyingFormatter.Parse(filteredInputText)).Returns(outputValue); + + A.CallTo(() => formatter.DoFilterValueToFormat(outputValue)).Returns(filteredOutputValue); + A.CallTo(() => underlyingFormatter.Format(filteredOutputValue)).Returns(inputText); + + Assert.AreSame(outputValue, formatter.Parse(inputText)); + Assert.AreEqual(inputText, formatter.Format(outputValue)); + } +} diff --git a/test/Spring/Spring.Core.Tests/Globalization/Formatters/FloatFormatterTests.cs b/test/Spring/Spring.Core.Tests/Globalization/Formatters/FloatFormatterTests.cs index 70fcdf21..58c5d286 100644 --- a/test/Spring/Spring.Core.Tests/Globalization/Formatters/FloatFormatterTests.cs +++ b/test/Spring/Spring.Core.Tests/Globalization/Formatters/FloatFormatterTests.cs @@ -20,78 +20,77 @@ using NUnit.Framework; -namespace Spring.Globalization.Formatters +namespace Spring.Globalization.Formatters; + +/// +/// Unit tests for FloatFormatter class. +/// +/// Aleksandar Seovic +public class FloatFormatterTests { - /// - /// Unit tests for FloatFormatter class. - /// - /// Aleksandar Seovic - public class FloatFormatterTests - { - [Test] - public void FormatNullValue() - { - FloatFormatter fmt = new FloatFormatter(); - Assert.Throws(() => fmt.Format(null)); - } + [Test] + public void FormatNullValue() + { + FloatFormatter fmt = new FloatFormatter(); + Assert.Throws(() => fmt.Format(null)); + } - [Test] - public void ParseNullOrEmptyValue() - { - FloatFormatter fmt = new FloatFormatter(); - Assert.AreEqual(0, fmt.Parse(null)); - Assert.IsTrue(fmt.Parse("") is double); - } + [Test] + public void ParseNullOrEmptyValue() + { + FloatFormatter fmt = new FloatFormatter(); + Assert.AreEqual(0, fmt.Parse(null)); + Assert.IsTrue(fmt.Parse("") is double); + } - [Test] - public void FormatNonNumber() - { - FloatFormatter fmt = new FloatFormatter(); - Assert.Throws(() => fmt.Format("not a number")); - } + [Test] + public void FormatNonNumber() + { + FloatFormatter fmt = new FloatFormatter(); + Assert.Throws(() => fmt.Format("not a number")); + } - [Test] - [Platform("Win")] - public void FormatUsingDefaults() - { - FloatFormatter fmt = new FloatFormatter(FloatFormatter.DefaultFormat, "en-US"); - Assert.AreEqual("1234.00", fmt.Format(1234)); - Assert.AreEqual("-1234.00", fmt.Format(-1234)); + [Test] + [Platform("Win")] + public void FormatUsingDefaults() + { + FloatFormatter fmt = new FloatFormatter(FloatFormatter.DefaultFormat, "en-US"); + Assert.AreEqual("1234.00", fmt.Format(1234)); + Assert.AreEqual("-1234.00", fmt.Format(-1234)); - fmt = new FloatFormatter(FloatFormatter.DefaultFormat, "sr-SP-Latn"); -#if NETFRAMEWORK + fmt = new FloatFormatter(FloatFormatter.DefaultFormat, "sr-SP-Latn"); +#if NETFRAMEWORK Assert.AreEqual("1234,00", fmt.Format(1234)); Assert.AreEqual("-1234,00", fmt.Format(-1234)); #else - Assert.AreEqual("1234,000", fmt.Format(1234)); - Assert.AreEqual("-1234,000", fmt.Format(-1234)); + Assert.AreEqual("1234,000", fmt.Format(1234)); + Assert.AreEqual("-1234,000", fmt.Format(-1234)); #endif - } + } - [Test] - public void ParseUsingDefaults() - { - FloatFormatter fmt = new FloatFormatter(FloatFormatter.DefaultFormat, "en-US"); - Assert.AreEqual(1234.56, fmt.Parse("1234.56")); - Assert.AreEqual(-1234, fmt.Parse("-1234")); - Assert.AreEqual(1234.56, fmt.Parse("1.23456e+003")); - Assert.AreEqual(-1234, fmt.Parse("-1.234e+003")); + [Test] + public void ParseUsingDefaults() + { + FloatFormatter fmt = new FloatFormatter(FloatFormatter.DefaultFormat, "en-US"); + Assert.AreEqual(1234.56, fmt.Parse("1234.56")); + Assert.AreEqual(-1234, fmt.Parse("-1234")); + Assert.AreEqual(1234.56, fmt.Parse("1.23456e+003")); + Assert.AreEqual(-1234, fmt.Parse("-1.234e+003")); - fmt = new FloatFormatter(FloatFormatter.DefaultFormat, "sr-SP-Cyrl"); - Assert.AreEqual(1234.56, fmt.Parse("1234,56")); - Assert.AreEqual(-1234, fmt.Parse("-1234")); - Assert.AreEqual(1234.56, fmt.Parse("1,23456e+003")); - Assert.AreEqual(-1234, fmt.Parse("-1,234e+003")); - } + fmt = new FloatFormatter(FloatFormatter.DefaultFormat, "sr-SP-Cyrl"); + Assert.AreEqual(1234.56, fmt.Parse("1234,56")); + Assert.AreEqual(-1234, fmt.Parse("-1234")); + Assert.AreEqual(1234.56, fmt.Parse("1,23456e+003")); + Assert.AreEqual(-1234, fmt.Parse("-1,234e+003")); + } - [Test] - public void FormatUsingCustomSettings() - { - FloatFormatter fmt = new FloatFormatter("{0:e3}", "en-US"); - Assert.AreEqual("1.234e+003", fmt.Format(1234)); - Assert.AreEqual("-1.234e+003", fmt.Format(-1234)); - Assert.AreEqual("1.235e+003", fmt.Format(1234.56)); - Assert.AreEqual("-1.235e+003", fmt.Format(-1234.56)); - } + [Test] + public void FormatUsingCustomSettings() + { + FloatFormatter fmt = new FloatFormatter("{0:e3}", "en-US"); + Assert.AreEqual("1.234e+003", fmt.Format(1234)); + Assert.AreEqual("-1.234e+003", fmt.Format(-1234)); + Assert.AreEqual("1.235e+003", fmt.Format(1234.56)); + Assert.AreEqual("-1.235e+003", fmt.Format(-1234.56)); } } diff --git a/test/Spring/Spring.Core.Tests/Globalization/Formatters/HasTextFilteringFormatterTests.cs b/test/Spring/Spring.Core.Tests/Globalization/Formatters/HasTextFilteringFormatterTests.cs index 880ecbee..98cbe99a 100644 --- a/test/Spring/Spring.Core.Tests/Globalization/Formatters/HasTextFilteringFormatterTests.cs +++ b/test/Spring/Spring.Core.Tests/Globalization/Formatters/HasTextFilteringFormatterTests.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -24,38 +24,37 @@ using NUnit.Framework; #endregion -namespace Spring.Globalization.Formatters +namespace Spring.Globalization.Formatters; + +/// +/// +/// +/// Erich Eichinger +[TestFixture] +public class HasTextFilteringFormatterTests { - /// - /// - /// - /// Erich Eichinger - [TestFixture] - public class HasTextFilteringFormatterTests + [Test] + public void ReplacesNullAndWhitespacesByDefaultValue() { - [Test] - public void ReplacesNullAndWhitespacesByDefaultValue() - { - string defaultValue = "theDefaultValue"; - HasTextFilteringFormatter fmt = new HasTextFilteringFormatter(defaultValue, null); + string defaultValue = "theDefaultValue"; + HasTextFilteringFormatter fmt = new HasTextFilteringFormatter(defaultValue, null); - Assert.AreEqual( defaultValue, fmt.Parse(null)); - Assert.AreEqual(defaultValue, fmt.Parse(string.Empty)); - Assert.AreEqual( defaultValue, fmt.Parse("\t \n\r")); - Assert.AreEqual(" text \n", fmt.Parse(" text \n")); - } - - [Test] - public void DoesntAffectFormat() - { - string defaultValue = "theDefaultValue"; - HasTextFilteringFormatter fmt = new HasTextFilteringFormatter(defaultValue, null); - - Assert.AreEqual(null, fmt.Format(null)); - Assert.AreEqual(string.Empty, fmt.Format(string.Empty)); - Assert.AreEqual("\t \n\r", fmt.Format("\t \n\r")); - object o = new object(); - Assert.AreEqual(o.ToString(), fmt.Format(o)); - } + Assert.AreEqual(defaultValue, fmt.Parse(null)); + Assert.AreEqual(defaultValue, fmt.Parse(string.Empty)); + Assert.AreEqual(defaultValue, fmt.Parse("\t \n\r")); + Assert.AreEqual(" text \n", fmt.Parse(" text \n")); } -} \ No newline at end of file + + [Test] + public void DoesntAffectFormat() + { + string defaultValue = "theDefaultValue"; + HasTextFilteringFormatter fmt = new HasTextFilteringFormatter(defaultValue, null); + + Assert.AreEqual(null, fmt.Format(null)); + Assert.AreEqual(string.Empty, fmt.Format(string.Empty)); + Assert.AreEqual("\t \n\r", fmt.Format("\t \n\r")); + object o = new object(); + Assert.AreEqual(o.ToString(), fmt.Format(o)); + } +} diff --git a/test/Spring/Spring.Core.Tests/Globalization/Formatters/IntegerFormatterTests.cs b/test/Spring/Spring.Core.Tests/Globalization/Formatters/IntegerFormatterTests.cs index 42acff86..c4ec6aa6 100644 --- a/test/Spring/Spring.Core.Tests/Globalization/Formatters/IntegerFormatterTests.cs +++ b/test/Spring/Spring.Core.Tests/Globalization/Formatters/IntegerFormatterTests.cs @@ -20,68 +20,67 @@ using NUnit.Framework; -namespace Spring.Globalization.Formatters +namespace Spring.Globalization.Formatters; + +/// +/// Unit tests for IntegerFormatter class. +/// +/// Aleksandar Seovic +[TestFixture] +public class IntegerFormatterTests { - /// - /// Unit tests for IntegerFormatter class. - /// - /// Aleksandar Seovic - [TestFixture] - public class IntegerFormatterTests - { - [Test] - public void FormatNullValue() - { - IntegerFormatter fmt = new IntegerFormatter(); - Assert.Throws(() => fmt.Format(null)); - } + [Test] + public void FormatNullValue() + { + IntegerFormatter fmt = new IntegerFormatter(); + Assert.Throws(() => fmt.Format(null)); + } - [Test] - public void ParseNullOrEmptyValue() - { - IntegerFormatter fmt = new IntegerFormatter(); - Assert.AreEqual( 0, fmt.Parse(null)); - Assert.AreEqual( 0, fmt.Parse(string.Empty) ); - } + [Test] + public void ParseNullOrEmptyValue() + { + IntegerFormatter fmt = new IntegerFormatter(); + Assert.AreEqual(0, fmt.Parse(null)); + Assert.AreEqual(0, fmt.Parse(string.Empty)); + } - [Test] - public void FormatNonNumber() - { - IntegerFormatter fmt = new IntegerFormatter(); - Assert.Throws(() => fmt.Format("not a number")); - } + [Test] + public void FormatNonNumber() + { + IntegerFormatter fmt = new IntegerFormatter(); + Assert.Throws(() => fmt.Format("not a number")); + } - [Test] - public void FormatUsingDefaults() - { - IntegerFormatter fmt = new IntegerFormatter(); - Assert.AreEqual("1234", fmt.Format(1234)); - Assert.AreEqual("-1234", fmt.Format(-1234)); - } + [Test] + public void FormatUsingDefaults() + { + IntegerFormatter fmt = new IntegerFormatter(); + Assert.AreEqual("1234", fmt.Format(1234)); + Assert.AreEqual("-1234", fmt.Format(-1234)); + } - [Test] - public void ParseUsingDefaults() - { - IntegerFormatter fmt = new IntegerFormatter(); - Assert.AreEqual(1234, fmt.Parse("1234")); - Assert.AreEqual(-1234, fmt.Parse("-1234")); - } + [Test] + public void ParseUsingDefaults() + { + IntegerFormatter fmt = new IntegerFormatter(); + Assert.AreEqual(1234, fmt.Parse("1234")); + Assert.AreEqual(-1234, fmt.Parse("-1234")); + } - [Test] - public void FormatUsingCustomSettings() - { - IntegerFormatter fmt = new IntegerFormatter("{0:00000}"); - Assert.AreEqual("01234", fmt.Format(1234)); - Assert.AreEqual("-01234", fmt.Format(-1234)); + [Test] + public void FormatUsingCustomSettings() + { + IntegerFormatter fmt = new IntegerFormatter("{0:00000}"); + Assert.AreEqual("01234", fmt.Format(1234)); + Assert.AreEqual("-01234", fmt.Format(-1234)); - fmt = new IntegerFormatter("{0,10}"); - Assert.AreEqual(" 1234", fmt.Format(1234)); + fmt = new IntegerFormatter("{0,10}"); + Assert.AreEqual(" 1234", fmt.Format(1234)); - fmt = new IntegerFormatter("{0,-10}"); - Assert.AreEqual("1234 ", fmt.Format(1234)); + fmt = new IntegerFormatter("{0,-10}"); + Assert.AreEqual("1234 ", fmt.Format(1234)); - fmt = new IntegerFormatter("{0:(###) ###-####}"); - Assert.AreEqual("(813) 555-4034", fmt.Format(8135554034)); - } + fmt = new IntegerFormatter("{0:(###) ###-####}"); + Assert.AreEqual("(813) 555-4034", fmt.Format(8135554034)); } } diff --git a/test/Spring/Spring.Core.Tests/Globalization/Formatters/NumberFormatterTests.cs b/test/Spring/Spring.Core.Tests/Globalization/Formatters/NumberFormatterTests.cs index 77997cdf..973cb6fb 100644 --- a/test/Spring/Spring.Core.Tests/Globalization/Formatters/NumberFormatterTests.cs +++ b/test/Spring/Spring.Core.Tests/Globalization/Formatters/NumberFormatterTests.cs @@ -20,125 +20,123 @@ using NUnit.Framework; -namespace Spring.Globalization.Formatters +namespace Spring.Globalization.Formatters; + +/// +/// Unit tests for NumberFormatter class. +/// +/// Aleksandar Seovic +public class NumberFormatterTests { - /// - /// Unit tests for NumberFormatter class. - /// - /// Aleksandar Seovic - public class NumberFormatterTests - { - [Test] - public void FormatNullValue() - { - NumberFormatter fmt = new NumberFormatter(); - Assert.Throws(() => fmt.Format(null)); - } + [Test] + public void FormatNullValue() + { + NumberFormatter fmt = new NumberFormatter(); + Assert.Throws(() => fmt.Format(null)); + } - [Test] - public void ParseNullOrEmptyValue() - { - NumberFormatter fmt = new NumberFormatter(); - Assert.AreEqual(0, fmt.Parse(null)); - Assert.IsTrue(fmt.Parse("") is double); - } + [Test] + public void ParseNullOrEmptyValue() + { + NumberFormatter fmt = new NumberFormatter(); + Assert.AreEqual(0, fmt.Parse(null)); + Assert.IsTrue(fmt.Parse("") is double); + } - [Test] - public void FormatNonNumber() - { - NumberFormatter fmt = new NumberFormatter(); - Assert.Throws(() => fmt.Format("not a number")); - } + [Test] + public void FormatNonNumber() + { + NumberFormatter fmt = new NumberFormatter(); + Assert.Throws(() => fmt.Format("not a number")); + } - [Test] - [Platform("Win")] - public void FormatUsingDefaults() - { - NumberFormatter fmt = new NumberFormatter("en-US"); - Assert.AreEqual("1,234.00", fmt.Format(1234)); - Assert.AreEqual("1,234.56", fmt.Format(1234.56)); - Assert.AreEqual("-1,234.00", fmt.Format(-1234)); - Assert.AreEqual("-1,234.56", fmt.Format(-1234.56)); + [Test] + [Platform("Win")] + public void FormatUsingDefaults() + { + NumberFormatter fmt = new NumberFormatter("en-US"); + Assert.AreEqual("1,234.00", fmt.Format(1234)); + Assert.AreEqual("1,234.56", fmt.Format(1234.56)); + Assert.AreEqual("-1,234.00", fmt.Format(-1234)); + Assert.AreEqual("-1,234.56", fmt.Format(-1234.56)); - fmt = new NumberFormatter("sr-SP-Latn"); + fmt = new NumberFormatter("sr-SP-Latn"); #if NETFRAMEWORK Assert.AreEqual("1.234,00", fmt.Format(1234)); Assert.AreEqual("1.234,56", fmt.Format(1234.56)); Assert.AreEqual("-1.234,00", fmt.Format(-1234)); Assert.AreEqual("-1.234,56", fmt.Format(-1234.56)); #else - Assert.AreEqual("1.234,000", fmt.Format(1234)); - Assert.AreEqual("1.234,560", fmt.Format(1234.56)); - Assert.AreEqual("-1.234,000", fmt.Format(-1234)); - Assert.AreEqual("-1.234,560", fmt.Format(-1234.56)); + Assert.AreEqual("1.234,000", fmt.Format(1234)); + Assert.AreEqual("1.234,560", fmt.Format(1234.56)); + Assert.AreEqual("-1.234,000", fmt.Format(-1234)); + Assert.AreEqual("-1.234,560", fmt.Format(-1234.56)); #endif - } + } - [Test] - [Platform("Win")] - public void ParseUsingDefaults() - { - NumberFormatter fmt = new NumberFormatter("en-US"); - Assert.AreEqual(1234, fmt.Parse("1,234.00")); - Assert.AreEqual(1234.56, fmt.Parse("1,234.56")); - Assert.AreEqual(-1234, fmt.Parse("-1,234.00")); - Assert.AreEqual(-1234.56, fmt.Parse("-1,234.56")); + [Test] + [Platform("Win")] + public void ParseUsingDefaults() + { + NumberFormatter fmt = new NumberFormatter("en-US"); + Assert.AreEqual(1234, fmt.Parse("1,234.00")); + Assert.AreEqual(1234.56, fmt.Parse("1,234.56")); + Assert.AreEqual(-1234, fmt.Parse("-1,234.00")); + Assert.AreEqual(-1234.56, fmt.Parse("-1,234.56")); - fmt = new NumberFormatter("sr-SP-Latn"); - Assert.AreEqual(1234, fmt.Parse("1.234,00")); - Assert.AreEqual(1234.56, fmt.Parse("1.234,56")); - Assert.AreEqual(-1234, fmt.Parse("-1.234,00")); - Assert.AreEqual(-1234.56, fmt.Parse("-1.234,56")); - } + fmt = new NumberFormatter("sr-SP-Latn"); + Assert.AreEqual(1234, fmt.Parse("1.234,00")); + Assert.AreEqual(1234.56, fmt.Parse("1.234,56")); + Assert.AreEqual(-1234, fmt.Parse("-1.234,00")); + Assert.AreEqual(-1234.56, fmt.Parse("-1.234,56")); + } - [Test] - [Platform("Win")] - public void FormatUsingCustomSettings() - { - NumberFormatter fmt = new NumberFormatter("en-US"); - fmt.DecimalDigits = 0; - fmt.NegativePattern = 0; - Assert.AreEqual("1,234", fmt.Format(1234)); - Assert.AreEqual("1,235", fmt.Format(1234.56)); - Assert.AreEqual("(1,234)", fmt.Format(-1234)); - Assert.AreEqual("(1,235)", fmt.Format(-1234.56)); + [Test] + [Platform("Win")] + public void FormatUsingCustomSettings() + { + NumberFormatter fmt = new NumberFormatter("en-US"); + fmt.DecimalDigits = 0; + fmt.NegativePattern = 0; + Assert.AreEqual("1,234", fmt.Format(1234)); + Assert.AreEqual("1,235", fmt.Format(1234.56)); + Assert.AreEqual("(1,234)", fmt.Format(-1234)); + Assert.AreEqual("(1,235)", fmt.Format(-1234.56)); + + fmt = new NumberFormatter("sr-SP-Cyrl"); + fmt.GroupSizes = new int[] { 1, 2 }; + fmt.GroupSeparator = "'"; - fmt = new NumberFormatter("sr-SP-Cyrl"); - fmt.GroupSizes = new int[] {1, 2}; - fmt.GroupSeparator = "'"; - #if NETFRAMEWORK Assert.AreEqual("1'23'4,00", fmt.Format(1234)); Assert.AreEqual("1'23'4,56", fmt.Format(1234.56)); Assert.AreEqual("-1'23'4,00", fmt.Format(-1234)); Assert.AreEqual("-1'23'4,56", fmt.Format(-1234.56)); #else - Assert.AreEqual("1'23'4,000", fmt.Format(1234)); - Assert.AreEqual("1'23'4,560", fmt.Format(1234.56)); - Assert.AreEqual("-1'23'4,000", fmt.Format(-1234)); - Assert.AreEqual("-1'23'4,560", fmt.Format(-1234.56)); + Assert.AreEqual("1'23'4,000", fmt.Format(1234)); + Assert.AreEqual("1'23'4,560", fmt.Format(1234.56)); + Assert.AreEqual("-1'23'4,000", fmt.Format(-1234)); + Assert.AreEqual("-1'23'4,560", fmt.Format(-1234.56)); #endif - } + } - [Test] - public void ParseUsingCustomSettings() - { - NumberFormatter fmt = new NumberFormatter("en-US"); - fmt.DecimalDigits = 0; - fmt.NegativePattern = 0; - Assert.AreEqual(1234, fmt.Parse("1,234")); - Assert.AreEqual(1234.56, fmt.Parse("1,234.56")); - Assert.AreEqual(-1234, fmt.Parse("(1,234)")); - Assert.AreEqual(-1234.56, fmt.Parse("(1,234.56)")); - - fmt = new NumberFormatter("sr-SP-Cyrl"); - fmt.GroupSizes = new int[] {1, 2}; - fmt.GroupSeparator = "'"; - Assert.AreEqual(1234, fmt.Parse("1'23'4,00")); - Assert.AreEqual(1234.56, fmt.Parse("1'23'4,56")); - Assert.AreEqual(-1234, fmt.Parse("-1'23'4,00")); - Assert.AreEqual(-1234.56, fmt.Parse("-1'23'4,56")); - } + [Test] + public void ParseUsingCustomSettings() + { + NumberFormatter fmt = new NumberFormatter("en-US"); + fmt.DecimalDigits = 0; + fmt.NegativePattern = 0; + Assert.AreEqual(1234, fmt.Parse("1,234")); + Assert.AreEqual(1234.56, fmt.Parse("1,234.56")); + Assert.AreEqual(-1234, fmt.Parse("(1,234)")); + Assert.AreEqual(-1234.56, fmt.Parse("(1,234.56)")); + fmt = new NumberFormatter("sr-SP-Cyrl"); + fmt.GroupSizes = new int[] { 1, 2 }; + fmt.GroupSeparator = "'"; + Assert.AreEqual(1234, fmt.Parse("1'23'4,00")); + Assert.AreEqual(1234.56, fmt.Parse("1'23'4,56")); + Assert.AreEqual(-1234, fmt.Parse("-1'23'4,00")); + Assert.AreEqual(-1234.56, fmt.Parse("-1'23'4,56")); } } diff --git a/test/Spring/Spring.Core.Tests/Globalization/Formatters/PercentFormatterTests.cs b/test/Spring/Spring.Core.Tests/Globalization/Formatters/PercentFormatterTests.cs index 55cc2327..4eba78d4 100644 --- a/test/Spring/Spring.Core.Tests/Globalization/Formatters/PercentFormatterTests.cs +++ b/test/Spring/Spring.Core.Tests/Globalization/Formatters/PercentFormatterTests.cs @@ -20,94 +20,93 @@ using NUnit.Framework; -namespace Spring.Globalization.Formatters +namespace Spring.Globalization.Formatters; + +/// +/// Unit tests for PercentFormatter class. +/// +/// Aleksandar Seovic +public class PercentFormatterTests { - /// - /// Unit tests for PercentFormatter class. - /// - /// Aleksandar Seovic - public class PercentFormatterTests - { - [Test] - public void FormatNullValue() - { - PercentFormatter fmt = new PercentFormatter(); - Assert.Throws(() => fmt.Format(null)); - } + [Test] + public void FormatNullValue() + { + PercentFormatter fmt = new PercentFormatter(); + Assert.Throws(() => fmt.Format(null)); + } - [Test] - public void ParseNullOrEmptyValue() - { - PercentFormatter fmt = new PercentFormatter(); - Assert.AreEqual(0, fmt.Parse(null)); - Assert.IsTrue(fmt.Parse("") is double); - } + [Test] + public void ParseNullOrEmptyValue() + { + PercentFormatter fmt = new PercentFormatter(); + Assert.AreEqual(0, fmt.Parse(null)); + Assert.IsTrue(fmt.Parse("") is double); + } - [Test] - public void FormatNonNumber() - { - PercentFormatter fmt = new PercentFormatter(); - Assert.Throws(() => fmt.Format("not a number")); - } + [Test] + public void FormatNonNumber() + { + PercentFormatter fmt = new PercentFormatter(); + Assert.Throws(() => fmt.Format("not a number")); + } - [Test] - [Platform("Win")] - public void FormatUsingDefaults() - { - PercentFormatter fmt = new PercentFormatter("en-US"); - Assert.AreEqual("25.00%", fmt.Format(0.25).Replace(" ", "")); - Assert.AreEqual("25.34%", fmt.Format(0.2534).Replace(" ", "")); + [Test] + [Platform("Win")] + public void FormatUsingDefaults() + { + PercentFormatter fmt = new PercentFormatter("en-US"); + Assert.AreEqual("25.00%", fmt.Format(0.25).Replace(" ", "")); + Assert.AreEqual("25.34%", fmt.Format(0.2534).Replace(" ", "")); - fmt = new PercentFormatter("sr-SP-Latn"); + fmt = new PercentFormatter("sr-SP-Latn"); #if NETFRAMEWORK Assert.AreEqual("25,00%", fmt.Format(0.25)); Assert.AreEqual("25,34%", fmt.Format(0.2534)); #else - Assert.AreEqual("25,000%", fmt.Format(0.25)); - Assert.AreEqual("25,340%", fmt.Format(0.2534)); + Assert.AreEqual("25,000%", fmt.Format(0.25)); + Assert.AreEqual("25,340%", fmt.Format(0.2534)); #endif - } + } - [Test] - public void ParseUsingDefaults() - { - PercentFormatter fmt = new PercentFormatter("en-US"); - Assert.AreEqual(0.25, fmt.Parse("25.00 %")); - Assert.AreEqual(0.2534, fmt.Parse("25.34 %")); + [Test] + public void ParseUsingDefaults() + { + PercentFormatter fmt = new PercentFormatter("en-US"); + Assert.AreEqual(0.25, fmt.Parse("25.00 %")); + Assert.AreEqual(0.2534, fmt.Parse("25.34 %")); - fmt = new PercentFormatter("sr-SP-Latn"); - Assert.AreEqual(0.25, fmt.Parse("25,00%")); - Assert.AreEqual(0.2534, fmt.Parse("25,34%")); - } + fmt = new PercentFormatter("sr-SP-Latn"); + Assert.AreEqual(0.25, fmt.Parse("25,00%")); + Assert.AreEqual(0.2534, fmt.Parse("25,34%")); + } - [Test] - public void FormatUsingCustomSettings() - { - PercentFormatter fmt = new PercentFormatter("en-US"); - fmt.DecimalDigits = 0; - fmt.PositivePattern = 1; - Assert.AreEqual("25%", fmt.Format(0.25)); - Assert.AreEqual("25%", fmt.Format(0.2534)); + [Test] + public void FormatUsingCustomSettings() + { + PercentFormatter fmt = new PercentFormatter("en-US"); + fmt.DecimalDigits = 0; + fmt.PositivePattern = 1; + Assert.AreEqual("25%", fmt.Format(0.25)); + Assert.AreEqual("25%", fmt.Format(0.2534)); - fmt = new PercentFormatter("sr-SP-Latn"); - fmt.DecimalDigits = 1; - Assert.AreEqual("25,0%", fmt.Format(0.25)); - Assert.AreEqual("25,3%", fmt.Format(0.2534)); - } + fmt = new PercentFormatter("sr-SP-Latn"); + fmt.DecimalDigits = 1; + Assert.AreEqual("25,0%", fmt.Format(0.25)); + Assert.AreEqual("25,3%", fmt.Format(0.2534)); + } - [Test] - public void ParseUsingCustomSettings() - { - PercentFormatter fmt = new PercentFormatter("en-US"); - fmt.DecimalDigits = 0; - fmt.PositivePattern = 1; - Assert.AreEqual(0.25, fmt.Parse("25%")); - Assert.AreEqual(0.2534, fmt.Parse("25.34%")); + [Test] + public void ParseUsingCustomSettings() + { + PercentFormatter fmt = new PercentFormatter("en-US"); + fmt.DecimalDigits = 0; + fmt.PositivePattern = 1; + Assert.AreEqual(0.25, fmt.Parse("25%")); + Assert.AreEqual(0.2534, fmt.Parse("25.34%")); - fmt = new PercentFormatter("sr-SP-Latn"); - fmt.DecimalDigits = 1; - Assert.AreEqual(0.25, fmt.Parse("25,0%")); - Assert.AreEqual(0.253, fmt.Parse("25,3%")); - } + fmt = new PercentFormatter("sr-SP-Latn"); + fmt.DecimalDigits = 1; + Assert.AreEqual(0.25, fmt.Parse("25,0%")); + Assert.AreEqual(0.253, fmt.Parse("25,3%")); } } diff --git a/test/Spring/Spring.Core.Tests/Globalization/Localizers/ResourceSetLocalizerTests.cs b/test/Spring/Spring.Core.Tests/Globalization/Localizers/ResourceSetLocalizerTests.cs index 00150e05..5bd2666f 100644 --- a/test/Spring/Spring.Core.Tests/Globalization/Localizers/ResourceSetLocalizerTests.cs +++ b/test/Spring/Spring.Core.Tests/Globalization/Localizers/ResourceSetLocalizerTests.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -22,42 +22,39 @@ using System.Globalization; using System.Resources; - using NUnit.Framework; - using Spring.Context; using Spring.Context.Support; #endregion -namespace Spring.Globalization.Localizers +namespace Spring.Globalization.Localizers; + +/// +/// Unit tests for the ResourceSetLocalizer class. +/// +/// Aleksandar Seovic +[TestFixture] +public sealed class ResourceSetLocalizerTests : AbstractLocalizerTests { - /// - /// Unit tests for the ResourceSetLocalizer class. - /// - /// Aleksandar Seovic - [TestFixture] - public sealed class ResourceSetLocalizerTests : AbstractLocalizerTests + protected override ILocalizer CreateLocalizer() { - protected override ILocalizer CreateLocalizer() - { - return new ResourceSetLocalizer(); - } + return new ResourceSetLocalizer(); + } - protected override IMessageSource CreateMessageSource() - { - ResourceSetMessageSource messageSource = new ResourceSetMessageSource(); - messageSource.ResourceManagers.Add(new ResourceManager("Spring.Resources.Tesla", GetType().Assembly)); - return messageSource; - } + protected override IMessageSource CreateMessageSource() + { + ResourceSetMessageSource messageSource = new ResourceSetMessageSource(); + messageSource.ResourceManagers.Add(new ResourceManager("Spring.Resources.Tesla", GetType().Assembly)); + return messageSource; + } - [Test] - public void DoesNotThrowOnMissingResource() - { - ResourceSetMessageSource messageSource = new ResourceSetMessageSource(); - messageSource.ResourceManagers.Add(new ResourceManager("do not exist", GetType().Assembly)); - ResourceSetLocalizer localizer = new ResourceSetLocalizer(); - localizer.ApplyResources(new Inventor(), messageSource, CultureInfo.InvariantCulture); - } + [Test] + public void DoesNotThrowOnMissingResource() + { + ResourceSetMessageSource messageSource = new ResourceSetMessageSource(); + messageSource.ResourceManagers.Add(new ResourceManager("do not exist", GetType().Assembly)); + ResourceSetLocalizer localizer = new ResourceSetLocalizer(); + localizer.ApplyResources(new Inventor(), messageSource, CultureInfo.InvariantCulture); } } diff --git a/test/Spring/Spring.Core.Tests/Globalization/Resolvers/DefaultCultureResolverTests.cs b/test/Spring/Spring.Core.Tests/Globalization/Resolvers/DefaultCultureResolverTests.cs index 8365d5d2..24fad4a0 100644 --- a/test/Spring/Spring.Core.Tests/Globalization/Resolvers/DefaultCultureResolverTests.cs +++ b/test/Spring/Spring.Core.Tests/Globalization/Resolvers/DefaultCultureResolverTests.cs @@ -25,52 +25,51 @@ using NUnit.Framework; #endregion -namespace Spring.Globalization.Resolvers +namespace Spring.Globalization.Resolvers; + +/// +/// Unit tests for the DefaultCultureResolver class. +/// +/// Rick Evans +[TestFixture] +public sealed class DefaultCultureResolverTests { - /// - /// Unit tests for the DefaultCultureResolver class. - /// - /// Rick Evans - [TestFixture] - public sealed class DefaultCultureResolverTests + [Test] + public void ResolveCultureYieldsThreadsCultureAfterInitialization() { - [Test] - public void ResolveCultureYieldsThreadsCultureAfterInitialization() - { - DefaultCultureResolver resolver = new DefaultCultureResolver(); - Assert.AreEqual(Thread.CurrentThread.CurrentUICulture, resolver.ResolveCulture(), - "Not defaulting to the culture of the current thread."); - } - - [Test] - public void DefaultCultureIsNullAfterInitialization() - { - DefaultCultureResolver resolver = new DefaultCultureResolver(); - Assert.IsNull(resolver.DefaultCulture, "Must be null until explicitly set."); - } - - [Test] - public void DefaultCultureIsYieldedForResolveCulture() - { - DefaultCultureResolver resolver = new DefaultCultureResolver(); - resolver.DefaultCulture = CultureInfo.InvariantCulture; - Assert.AreEqual(CultureInfo.InvariantCulture, resolver.ResolveCulture(), - "Not returning the DefaultCulture (it must if the DefaultCulture " + - "property has been set explicitly)."); - } - - [Test] - public void NullingDefaultCultureYieldsThreadsCultureForResolveCulture() - { - DefaultCultureResolver resolver = new DefaultCultureResolver(); - resolver.DefaultCulture = CultureInfo.InvariantCulture; - Assert.AreEqual(CultureInfo.InvariantCulture, resolver.ResolveCulture(), - "Not returning the DefaultCulture (it must if the DefaultCulture " + - "property has been set explicitly)."); - resolver.DefaultCulture = null; - Assert.AreEqual(Thread.CurrentThread.CurrentUICulture, resolver.ResolveCulture(), - "Not falling back to the culture of the current thread after " + - "DefaultCulture property is nulled out (it must)."); - } + DefaultCultureResolver resolver = new DefaultCultureResolver(); + Assert.AreEqual(Thread.CurrentThread.CurrentUICulture, resolver.ResolveCulture(), + "Not defaulting to the culture of the current thread."); } -} \ No newline at end of file + + [Test] + public void DefaultCultureIsNullAfterInitialization() + { + DefaultCultureResolver resolver = new DefaultCultureResolver(); + Assert.IsNull(resolver.DefaultCulture, "Must be null until explicitly set."); + } + + [Test] + public void DefaultCultureIsYieldedForResolveCulture() + { + DefaultCultureResolver resolver = new DefaultCultureResolver(); + resolver.DefaultCulture = CultureInfo.InvariantCulture; + Assert.AreEqual(CultureInfo.InvariantCulture, resolver.ResolveCulture(), + "Not returning the DefaultCulture (it must if the DefaultCulture " + + "property has been set explicitly)."); + } + + [Test] + public void NullingDefaultCultureYieldsThreadsCultureForResolveCulture() + { + DefaultCultureResolver resolver = new DefaultCultureResolver(); + resolver.DefaultCulture = CultureInfo.InvariantCulture; + Assert.AreEqual(CultureInfo.InvariantCulture, resolver.ResolveCulture(), + "Not returning the DefaultCulture (it must if the DefaultCulture " + + "property has been set explicitly)."); + resolver.DefaultCulture = null; + Assert.AreEqual(Thread.CurrentThread.CurrentUICulture, resolver.ResolveCulture(), + "Not falling back to the culture of the current thread after " + + "DefaultCulture property is nulled out (it must)."); + } +} diff --git a/test/Spring/Spring.Core.Tests/HookableContextHandler.cs b/test/Spring/Spring.Core.Tests/HookableContextHandler.cs index b32686c2..1eb1939d 100644 --- a/test/Spring/Spring.Core.Tests/HookableContextHandler.cs +++ b/test/Spring/Spring.Core.Tests/HookableContextHandler.cs @@ -26,73 +26,72 @@ using Spring.Context.Support; #endregion -namespace Spring +namespace Spring; + +/// +/// Replace the original context handler with this hookable version for testing ContextRegistry +/// +/// Erich Eichinger +public class HookableContextHandler : IConfigurationSectionHandler { + private IConfigurationSectionHandler baseHandler = new ContextHandler(); + /// - /// Replace the original context handler with this hookable version for testing ContextRegistry + /// May be used to wrap codeblocks within using(new Guard(new CreateContextFromSectionHandler(MyTestSectionHandler))) { ... } /// - /// Erich Eichinger - public class HookableContextHandler : IConfigurationSectionHandler + public class Guard : IDisposable { - private IConfigurationSectionHandler baseHandler = new ContextHandler(); + private readonly CreateContextFromSectionHandler _prevInst; /// - /// May be used to wrap codeblocks within using(new Guard(new CreateContextFromSectionHandler(MyTestSectionHandler))) { ... } + /// Initializes a new instance of the class. /// - public class Guard : IDisposable + public Guard(CreateContextFromSectionHandler sectionHandler) { - private readonly CreateContextFromSectionHandler _prevInst; - - /// - /// Initializes a new instance of the class. - /// - public Guard(CreateContextFromSectionHandler sectionHandler) - { - NUnit.Framework.Assert.IsNotNull(sectionHandler); - _prevInst = SetSectionHandler(sectionHandler); - } - - public void Dispose() - { - SetSectionHandler(_prevInst); - } + NUnit.Framework.Assert.IsNotNull(sectionHandler); + _prevInst = SetSectionHandler(sectionHandler); } - public delegate object CreateContextFromSectionHandler(object parent, object configContext, XmlNode section); - - private static CreateContextFromSectionHandler s_callback; - - public static CreateContextFromSectionHandler callback + public void Dispose() { - get { return s_callback; } - } - - public static CreateContextFromSectionHandler SetSectionHandler(CreateContextFromSectionHandler sectionHandler) - { - CreateContextFromSectionHandler prevInstance = s_callback; - s_callback = sectionHandler; - return prevInstance; - } - - /// - ///Creates a configuration section. - /// - /// - /// - ///The created section object. - /// - /// - ///Parent object. - ///Section XML node. - ///Configuration context object.2 - public object Create(object parent, object configContext, XmlNode section) - { - if (s_callback != null) - { - return s_callback(parent, configContext, section); - } - - return baseHandler.Create(parent, configContext, section); + SetSectionHandler(_prevInst); } } -} \ No newline at end of file + + public delegate object CreateContextFromSectionHandler(object parent, object configContext, XmlNode section); + + private static CreateContextFromSectionHandler s_callback; + + public static CreateContextFromSectionHandler callback + { + get { return s_callback; } + } + + public static CreateContextFromSectionHandler SetSectionHandler(CreateContextFromSectionHandler sectionHandler) + { + CreateContextFromSectionHandler prevInstance = s_callback; + s_callback = sectionHandler; + return prevInstance; + } + + /// + ///Creates a configuration section. + /// + /// + /// + ///The created section object. + /// + /// + ///Parent object. + ///Section XML node. + ///Configuration context object.2 + public object Create(object parent, object configContext, XmlNode section) + { + if (s_callback != null) + { + return s_callback(parent, configContext, section); + } + + return baseHandler.Create(parent, configContext, section); + } +} diff --git a/test/Spring/Spring.Core.Tests/Objects/ClassWithProtectedCtor.cs b/test/Spring/Spring.Core.Tests/Objects/ClassWithProtectedCtor.cs index 82005da0..9caed6cb 100644 --- a/test/Spring/Spring.Core.Tests/Objects/ClassWithProtectedCtor.cs +++ b/test/Spring/Spring.Core.Tests/Objects/ClassWithProtectedCtor.cs @@ -1,13 +1,12 @@ -namespace Spring.Objects -{ - public class ClassWithProtectedCtor : IOther - { - protected ClassWithProtectedCtor() - { - } +namespace Spring.Objects; - public void Absquatulate() - { - } +public class ClassWithProtectedCtor : IOther +{ + protected ClassWithProtectedCtor() + { } -} \ No newline at end of file + + public void Absquatulate() + { + } +} diff --git a/test/Spring/Spring.Core.Tests/Objects/DerivedTestObject.cs b/test/Spring/Spring.Core.Tests/Objects/DerivedTestObject.cs index 8c5d64b9..50a7a152 100644 --- a/test/Spring/Spring.Core.Tests/Objects/DerivedTestObject.cs +++ b/test/Spring/Spring.Core.Tests/Objects/DerivedTestObject.cs @@ -22,35 +22,34 @@ #endregion -namespace Spring.Objects +namespace Spring.Objects; + +/// +/// Adds some extra interfaces and properties to the base clas +/// so that we can test extra odd corner cases and suchlike. +/// +/// Juergen Hoeller +/// Rick Evans (.NET) +public class DerivedTestObject : TestObject, IDisposable { - /// - /// Adds some extra interfaces and properties to the base clas - /// so that we can test extra odd corner cases and suchlike. - /// - /// Juergen Hoeller - /// Rick Evans (.NET) - public class DerivedTestObject : TestObject, IDisposable + public const string NicknamePrefix = "#"; + + private bool destroyed; + private string nickers; + + public virtual void Dispose() { - public const string NicknamePrefix = "#"; - - private bool destroyed; - private string nickers; - - public virtual void Dispose() - { - destroyed = true; - } - - public virtual bool WasDestroyed() - { - return destroyed; - } - - public new string Nickname - { - get { return this.nickers; } - set { this.nickers = NicknamePrefix + value; } - } + destroyed = true; } -} \ No newline at end of file + + public virtual bool WasDestroyed() + { + return destroyed; + } + + public new string Nickname + { + get { return this.nickers; } + set { this.nickers = NicknamePrefix + value; } + } +} diff --git a/test/Spring/Spring.Core.Tests/Objects/Events/Support/EventManipulationUtilsTests.cs b/test/Spring/Spring.Core.Tests/Objects/Events/Support/EventManipulationUtilsTests.cs index 2540c88f..1d39e319 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Events/Support/EventManipulationUtilsTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Events/Support/EventManipulationUtilsTests.cs @@ -25,124 +25,123 @@ using NUnit.Framework; #endregion -namespace Spring.Objects.Events.Support.Tests +namespace Spring.Objects.Events.Support.Tests; + +/// +/// Unit tests for the EventManipulationUtils class. +/// +[TestFixture] +public sealed class EventManipulationUtilsTests { - /// - /// Unit tests for the EventManipulationUtils class. - /// - [TestFixture] - public sealed class EventManipulationUtilsTests - { - [Test] - public void FoundEventHandlers() - { - Type pubType = typeof (SimpleEventPublisher); - EventInfo[] events = pubType.GetEvents(); + [Test] + public void FoundEventHandlers() + { + Type pubType = typeof(SimpleEventPublisher); + EventInfo[] events = pubType.GetEvents(); - foreach (EventInfo currentEvent in events) - { - Type eventHandlerType = currentEvent.EventHandlerType; - MethodInfo invoke = eventHandlerType.GetMethod("Invoke"); - Assert.IsNotNull(EventManipulationUtils.GetMethodInfoMatchingSignature(invoke, typeof (SimpleEventSubscriber))); - } - } + foreach (EventInfo currentEvent in events) + { + Type eventHandlerType = currentEvent.EventHandlerType; + MethodInfo invoke = eventHandlerType.GetMethod("Invoke"); + Assert.IsNotNull(EventManipulationUtils.GetMethodInfoMatchingSignature(invoke, typeof(SimpleEventSubscriber))); + } + } - [Test] - public void FoundSomeEventHandlers() - { - Type pubType = typeof (SimpleEventPublisher); - EventInfo[] events = pubType.GetEvents(); - foreach (EventInfo currentEvent in events) - { - Type eventHandlerType = currentEvent.EventHandlerType; - MethodInfo invoke = eventHandlerType.GetMethod("Invoke"); - if (currentEvent.Name == "MyFirstEvent" || currentEvent.Name == "MySecondEvent") - { - Assert.IsNotNull(EventManipulationUtils.GetMethodInfoMatchingSignature(invoke, typeof (SomeEventSubscriber))); - } - else - { - Assert.IsNull(EventManipulationUtils.GetMethodInfoMatchingSignature(invoke, typeof (SomeEventSubscriber))); - } - } - } + [Test] + public void FoundSomeEventHandlers() + { + Type pubType = typeof(SimpleEventPublisher); + EventInfo[] events = pubType.GetEvents(); + foreach (EventInfo currentEvent in events) + { + Type eventHandlerType = currentEvent.EventHandlerType; + MethodInfo invoke = eventHandlerType.GetMethod("Invoke"); + if (currentEvent.Name == "MyFirstEvent" || currentEvent.Name == "MySecondEvent") + { + Assert.IsNotNull(EventManipulationUtils.GetMethodInfoMatchingSignature(invoke, typeof(SomeEventSubscriber))); + } + else + { + Assert.IsNull(EventManipulationUtils.GetMethodInfoMatchingSignature(invoke, typeof(SomeEventSubscriber))); + } + } + } - [Test] - public void FoundNoHandlers() - { - Type pubType = typeof (SimpleEventPublisher); - EventInfo[] events = pubType.GetEvents(); + [Test] + public void FoundNoHandlers() + { + Type pubType = typeof(SimpleEventPublisher); + EventInfo[] events = pubType.GetEvents(); - foreach (EventInfo currentEvent in events) - { - Type eventHandlerType = currentEvent.EventHandlerType; - MethodInfo invoke = eventHandlerType.GetMethod("Invoke"); - Assert.IsNull(EventManipulationUtils.GetMethodInfoMatchingSignature(invoke, typeof (NoEventSubscriber))); - } - } + foreach (EventInfo currentEvent in events) + { + Type eventHandlerType = currentEvent.EventHandlerType; + MethodInfo invoke = eventHandlerType.GetMethod("Invoke"); + Assert.IsNull(EventManipulationUtils.GetMethodInfoMatchingSignature(invoke, typeof(NoEventSubscriber))); + } + } - #region Helper Classes + #region Helper Classes - internal delegate void Delegate1(object source, string name); + internal delegate void Delegate1(object source, string name); - internal delegate string Delegate2(string name, bool flag); + internal delegate string Delegate2(string name, bool flag); - internal delegate bool Delegate3(string name, bool flag); + internal delegate bool Delegate3(string name, bool flag); - internal class SimpleEventPublisher - { + internal class SimpleEventPublisher + { #pragma warning disable 67 - public event Delegate1 MyFirstEvent; - public event Delegate2 MySecondEvent; - public event Delegate3 MyThirdEvent; + public event Delegate1 MyFirstEvent; + public event Delegate2 MySecondEvent; + public event Delegate3 MyThirdEvent; #pragma warning restore 67 + } + + internal class SimpleEventSubscriber + { + public void MyFirstEvent_Handler(object source, string name) + { } - internal class SimpleEventSubscriber - { - public void MyFirstEvent_Handler(object source, string name) - { - } + public string MySecondEvent_Handler(string name, bool flag) + { + return String.Empty; + } - public string MySecondEvent_Handler(string name, bool flag) - { - return String.Empty; - } + public bool MyThirdEvent_Handler(string name, bool flag) + { + return false; + } + } - public bool MyThirdEvent_Handler(string name, bool flag) - { - return false; - } - } + internal class NoEventSubscriber + { + public void MyFirstEvent_Handler(object source, string name, bool flag) + { + } - internal class NoEventSubscriber - { - public void MyFirstEvent_Handler(object source, string name, bool flag) - { - } + public void MySecondEvent_Handler(string name, bool flag) + { + } - public void MySecondEvent_Handler(string name, bool flag) - { - } + public string MyThirdEvent_Handler(string name) + { + return String.Empty; + } + } - public string MyThirdEvent_Handler(string name) - { - return String.Empty; - } - } + internal class SomeEventSubscriber + { + public void MyFirstEvent_Handler(object source, string name) + { + } - internal class SomeEventSubscriber - { - public void MyFirstEvent_Handler(object source, string name) - { - } + public string MySecondEvent_Handler(string name, bool flag) + { + return String.Empty; + } + } - public string MySecondEvent_Handler(string name, bool flag) - { - return String.Empty; - } - } - - #endregion - } + #endregion } \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/Objects/Events/Support/EventRegistryTests.cs b/test/Spring/Spring.Core.Tests/Objects/Events/Support/EventRegistryTests.cs index 2a537dc0..d9a3c4bf 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Events/Support/EventRegistryTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Events/Support/EventRegistryTests.cs @@ -20,324 +20,323 @@ using NUnit.Framework; -namespace Spring.Objects.Events.Support.Tests +namespace Spring.Objects.Events.Support.Tests; + +[TestFixture] +public class EventRegistryTests { - [TestFixture] - public class EventRegistryTests - { - #region Helper Classes + #region Helper Classes - internal delegate void SimpleClientEvent(object sender, MyClientEventArgs args); + internal delegate void SimpleClientEvent(object sender, MyClientEventArgs args); - internal delegate string SimpleClientEvent2(MyClientEventArgs args); + internal delegate string SimpleClientEvent2(MyClientEventArgs args); - internal class SimpleClient2 - { - public event SimpleClientEvent MyClientEvent; + internal class SimpleClient2 + { + public event SimpleClientEvent MyClientEvent; - public SimpleClient2() - { - } - - public void ClientMethodThatTriggersEvent() - { - if (MyClientEvent != null) - { - MyClientEvent(this, new MyClientEventArgs("Event raised")); - } - } - } - - internal interface ISimpleClient - { - event SimpleClientEvent MyClientEvent1; - event SimpleClientEvent MyClientEvent2; - event SimpleClientEvent2 MyClientEvent3; - } - - internal class SimpleClient : ISimpleClient - { - private string _clientName; - - public event SimpleClientEvent MyClientEvent1; - public event SimpleClientEvent MyClientEvent2; - public event SimpleClientEvent2 MyClientEvent3; - - public SimpleClient(string clientName) - { - _clientName = clientName; - } - - public void ClientMethodThatTriggersEvent() - { - if (MyClientEvent1 != null) - { - MyClientEvent1(this, new MyClientEventArgs("Event raised from " + _clientName)); - } - } - - public void ClientMethodThatTriggersEvent2() - { - if (MyClientEvent2 != null) - { - MyClientEvent2(this, new MyClientEventArgs("Event raised from " + _clientName)); - } - } - - public void ClientMethodThatTriggersEvent3() - { - if (MyClientEvent3 != null) - { - MyClientEvent3(new MyClientEventArgs("Event raised from " + _clientName)); - } - } - } - - internal class MyClientEventArgs : EventArgs - { - private string _eventMessage; - - public MyClientEventArgs(string eventMessage) - { - _eventMessage = eventMessage; - } - - public string EventMessage - { - get { return _eventMessage; } - } - } - - internal class SimpleSubscriber - { - protected int _eventCount; - - protected bool _eventRaised = false; - - public SimpleSubscriber() - { - } - - public int EventCount - { - get { return _eventCount; } - } - - public bool EventRaised - { - get { return _eventRaised; } - } - } - - internal class EventSubscriber : SimpleSubscriber - { - public EventSubscriber() - { - } - - public void HandleClientEvents(object sender, MyClientEventArgs args) - { - _eventRaised = true; - _eventCount++; - } - } - - internal class NoEventSubscriber : SimpleSubscriber - { - public NoEventSubscriber() - { - } - - public void HandleClientEvents(object sender) - { - _eventRaised = true; - } - } - - internal class OtherEventSubscriber : SimpleSubscriber - { - public OtherEventSubscriber() - { - } - - public string HandleClientEvents(MyClientEventArgs args) - { - _eventRaised = true; - return String.Empty; - } - } - - #endregion - - [Test] - public void RespectsInheritance() - { - SimpleClient source = new SimpleClient("foo"); - - IEventRegistry registry = new EventRegistry(); - registry.PublishEvents(source); - - EventSubscriber sub = new EventSubscriber(); - Assert.IsFalse(sub.EventRaised, "Event raised"); - - source.ClientMethodThatTriggersEvent(); - Assert.IsFalse(sub.EventRaised, "Event raised"); - - registry.Subscribe(sub, typeof(ISimpleClient)); - source.ClientMethodThatTriggersEvent(); - Assert.IsTrue(sub.EventRaised, "Event Not Raised"); - } - - [Test] - public void PublishAllEvents() - { - IEventRegistry registry = new EventRegistry(); - SimpleClient client = new SimpleClient("PublishAllEvents"); - registry.PublishEvents(client); - EventSubscriber sub = new EventSubscriber(); - Assert.IsFalse(sub.EventRaised, "Event raised"); - - client.ClientMethodThatTriggersEvent(); - Assert.IsFalse(sub.EventRaised, "Event raised"); - - registry.Subscribe(sub); - client.ClientMethodThatTriggersEvent(); - Assert.IsTrue(sub.EventRaised, "Event Not Raised"); - } - - [Test] - public void PublishAllEventsMultipleSubscribers() - { - IEventRegistry registry = new EventRegistry(); - SimpleClient client = new SimpleClient("PublishAllEvents"); - registry.PublishEvents(client); - EventSubscriber sub = new EventSubscriber(); - EventSubscriber sub2 = new EventSubscriber(); - Assert.IsFalse(sub.EventRaised, "Event raised"); - Assert.IsFalse(sub2.EventRaised, "Event raised"); - - client.ClientMethodThatTriggersEvent(); - Assert.IsFalse(sub.EventRaised, "Event raised"); - Assert.IsFalse(sub2.EventRaised, "Event raised"); - - registry.Subscribe(sub); - registry.Subscribe(sub2); - client.ClientMethodThatTriggersEvent(); - Assert.IsTrue(sub.EventRaised, "Event Not Raised"); - Assert.IsTrue(sub2.EventRaised, "Event Not Raised"); - } - - [Test] - public void PublishAllEventsMultipleSubscribersAndUnsubscribe() + public SimpleClient2() { - IEventRegistry registry = new EventRegistry(); - SimpleClient client = new SimpleClient("PublishAllEvents"); - registry.PublishEvents(client); - EventSubscriber sub = new EventSubscriber(); - EventSubscriber sub2 = new EventSubscriber(); - registry.Subscribe(sub); - registry.Subscribe(sub2); - client.ClientMethodThatTriggersEvent(); - Assert.IsTrue(sub.EventRaised, "Event Not Raised"); - Assert.IsTrue(sub2.EventRaised, "Event Not Raised"); - Assert.AreEqual(1, sub.EventCount); - Assert.AreEqual(1, sub2.EventCount); - - registry.Unsubscribe(sub2); - client.ClientMethodThatTriggersEvent(); - Assert.AreEqual(2, sub.EventCount); - Assert.AreEqual(1, sub2.EventCount); } - [Test] - public void PublishAllEventsSubscribeToNamedEvents() - { - IEventRegistry registry = new EventRegistry(); - SimpleClient client = new SimpleClient("PublishAllEvents"); - SimpleClient2 client2 = new SimpleClient2(); + public void ClientMethodThatTriggersEvent() + { + if (MyClientEvent != null) + { + MyClientEvent(this, new MyClientEventArgs("Event raised")); + } + } + } - registry.PublishEvents(client); - registry.PublishEvents(client2); + internal interface ISimpleClient + { + event SimpleClientEvent MyClientEvent1; + event SimpleClientEvent MyClientEvent2; + event SimpleClientEvent2 MyClientEvent3; + } - EventSubscriber sub = new EventSubscriber(); - EventSubscriber sub2 = new EventSubscriber(); + internal class SimpleClient : ISimpleClient + { + private string _clientName; - Assert.IsFalse(sub.EventRaised, "Event raised"); - Assert.IsFalse(sub2.EventRaised, "Event raised"); + public event SimpleClientEvent MyClientEvent1; + public event SimpleClientEvent MyClientEvent2; + public event SimpleClientEvent2 MyClientEvent3; - client.ClientMethodThatTriggersEvent(); - client2.ClientMethodThatTriggersEvent(); - Assert.IsFalse(sub.EventRaised, "Event raised"); - Assert.IsFalse(sub2.EventRaised, "Event raised"); + public SimpleClient(string clientName) + { + _clientName = clientName; + } - registry.Subscribe(sub, typeof (SimpleClient)); - registry.Subscribe(sub2, typeof (SimpleClient2)); + public void ClientMethodThatTriggersEvent() + { + if (MyClientEvent1 != null) + { + MyClientEvent1(this, new MyClientEventArgs("Event raised from " + _clientName)); + } + } - client.ClientMethodThatTriggersEvent(); - Assert.IsTrue(sub.EventRaised, "Event Not Raised"); - Assert.IsFalse(sub2.EventRaised, "Event raised"); + public void ClientMethodThatTriggersEvent2() + { + if (MyClientEvent2 != null) + { + MyClientEvent2(this, new MyClientEventArgs("Event raised from " + _clientName)); + } + } - client2.ClientMethodThatTriggersEvent(); - Assert.IsTrue(sub.EventRaised, "Event Not Raised"); - Assert.IsTrue(sub2.EventRaised, "Event Not Raised"); - } + public void ClientMethodThatTriggersEvent3() + { + if (MyClientEvent3 != null) + { + MyClientEvent3(new MyClientEventArgs("Event raised from " + _clientName)); + } + } + } - [Test] - public void NoValidEventHandlersOrEventsToSubscribeto() - { - IEventRegistry registry = new EventRegistry(); - SimpleClient client = new SimpleClient("PublishAllEvents"); - NoEventSubscriber sub = new NoEventSubscriber(); - registry.PublishEvents(client); + internal class MyClientEventArgs : EventArgs + { + private string _eventMessage; - Assert.IsFalse(sub.EventRaised, "Event raised"); - client.ClientMethodThatTriggersEvent(); - Assert.IsFalse(sub.EventRaised, "Event raised"); + public MyClientEventArgs(string eventMessage) + { + _eventMessage = eventMessage; + } - registry.Subscribe(sub); - client.ClientMethodThatTriggersEvent(); - Assert.IsFalse(sub.EventRaised, "Event Raised"); - } + public string EventMessage + { + get { return _eventMessage; } + } + } - [Test] - public void NoPublishers() - { - IEventRegistry registry = new EventRegistry(); - SimpleClient client = new SimpleClient("PublishAllEvents"); - SimpleSubscriber sub = new SimpleSubscriber(); - Assert.IsFalse(sub.EventRaised, "Event raised"); + internal class SimpleSubscriber + { + protected int _eventCount; - client.ClientMethodThatTriggersEvent(); - Assert.IsFalse(sub.EventRaised, "Event raised"); + protected bool _eventRaised = false; - registry.Subscribe(sub); - client.ClientMethodThatTriggersEvent(); - Assert.IsFalse(sub.EventRaised, "Event Raised"); - } + public SimpleSubscriber() + { + } - [Test] - public void PublishAllEventsAndSubscribeToSome() - { - IEventRegistry registry = new EventRegistry(); - SimpleClient client = new SimpleClient("PublishAllEventsAndSubscribeToSome"); - registry.PublishEvents(client); - EventSubscriber sub = new EventSubscriber(); - OtherEventSubscriber sub2 = new OtherEventSubscriber(); - Assert.IsFalse(sub.EventRaised, "Event raised"); - Assert.IsFalse(sub2.EventRaised, "Event raised"); + public int EventCount + { + get { return _eventCount; } + } - client.ClientMethodThatTriggersEvent(); - Assert.IsFalse(sub.EventRaised, "Event raised"); + public bool EventRaised + { + get { return _eventRaised; } + } + } - client.ClientMethodThatTriggersEvent3(); - Assert.IsFalse(sub2.EventRaised, "Event raised"); + internal class EventSubscriber : SimpleSubscriber + { + public EventSubscriber() + { + } - registry.Subscribe(sub); - registry.Subscribe(sub2); - client.ClientMethodThatTriggersEvent(); - client.ClientMethodThatTriggersEvent3(); - Assert.IsTrue(sub.EventRaised, "Event Not Raised"); - Assert.IsTrue(sub2.EventRaised, "Event Not Raised"); - } - } -} \ No newline at end of file + public void HandleClientEvents(object sender, MyClientEventArgs args) + { + _eventRaised = true; + _eventCount++; + } + } + + internal class NoEventSubscriber : SimpleSubscriber + { + public NoEventSubscriber() + { + } + + public void HandleClientEvents(object sender) + { + _eventRaised = true; + } + } + + internal class OtherEventSubscriber : SimpleSubscriber + { + public OtherEventSubscriber() + { + } + + public string HandleClientEvents(MyClientEventArgs args) + { + _eventRaised = true; + return String.Empty; + } + } + + #endregion + + [Test] + public void RespectsInheritance() + { + SimpleClient source = new SimpleClient("foo"); + + IEventRegistry registry = new EventRegistry(); + registry.PublishEvents(source); + + EventSubscriber sub = new EventSubscriber(); + Assert.IsFalse(sub.EventRaised, "Event raised"); + + source.ClientMethodThatTriggersEvent(); + Assert.IsFalse(sub.EventRaised, "Event raised"); + + registry.Subscribe(sub, typeof(ISimpleClient)); + source.ClientMethodThatTriggersEvent(); + Assert.IsTrue(sub.EventRaised, "Event Not Raised"); + } + + [Test] + public void PublishAllEvents() + { + IEventRegistry registry = new EventRegistry(); + SimpleClient client = new SimpleClient("PublishAllEvents"); + registry.PublishEvents(client); + EventSubscriber sub = new EventSubscriber(); + Assert.IsFalse(sub.EventRaised, "Event raised"); + + client.ClientMethodThatTriggersEvent(); + Assert.IsFalse(sub.EventRaised, "Event raised"); + + registry.Subscribe(sub); + client.ClientMethodThatTriggersEvent(); + Assert.IsTrue(sub.EventRaised, "Event Not Raised"); + } + + [Test] + public void PublishAllEventsMultipleSubscribers() + { + IEventRegistry registry = new EventRegistry(); + SimpleClient client = new SimpleClient("PublishAllEvents"); + registry.PublishEvents(client); + EventSubscriber sub = new EventSubscriber(); + EventSubscriber sub2 = new EventSubscriber(); + Assert.IsFalse(sub.EventRaised, "Event raised"); + Assert.IsFalse(sub2.EventRaised, "Event raised"); + + client.ClientMethodThatTriggersEvent(); + Assert.IsFalse(sub.EventRaised, "Event raised"); + Assert.IsFalse(sub2.EventRaised, "Event raised"); + + registry.Subscribe(sub); + registry.Subscribe(sub2); + client.ClientMethodThatTriggersEvent(); + Assert.IsTrue(sub.EventRaised, "Event Not Raised"); + Assert.IsTrue(sub2.EventRaised, "Event Not Raised"); + } + + [Test] + public void PublishAllEventsMultipleSubscribersAndUnsubscribe() + { + IEventRegistry registry = new EventRegistry(); + SimpleClient client = new SimpleClient("PublishAllEvents"); + registry.PublishEvents(client); + EventSubscriber sub = new EventSubscriber(); + EventSubscriber sub2 = new EventSubscriber(); + registry.Subscribe(sub); + registry.Subscribe(sub2); + client.ClientMethodThatTriggersEvent(); + Assert.IsTrue(sub.EventRaised, "Event Not Raised"); + Assert.IsTrue(sub2.EventRaised, "Event Not Raised"); + Assert.AreEqual(1, sub.EventCount); + Assert.AreEqual(1, sub2.EventCount); + + registry.Unsubscribe(sub2); + client.ClientMethodThatTriggersEvent(); + Assert.AreEqual(2, sub.EventCount); + Assert.AreEqual(1, sub2.EventCount); + } + + [Test] + public void PublishAllEventsSubscribeToNamedEvents() + { + IEventRegistry registry = new EventRegistry(); + SimpleClient client = new SimpleClient("PublishAllEvents"); + SimpleClient2 client2 = new SimpleClient2(); + + registry.PublishEvents(client); + registry.PublishEvents(client2); + + EventSubscriber sub = new EventSubscriber(); + EventSubscriber sub2 = new EventSubscriber(); + + Assert.IsFalse(sub.EventRaised, "Event raised"); + Assert.IsFalse(sub2.EventRaised, "Event raised"); + + client.ClientMethodThatTriggersEvent(); + client2.ClientMethodThatTriggersEvent(); + Assert.IsFalse(sub.EventRaised, "Event raised"); + Assert.IsFalse(sub2.EventRaised, "Event raised"); + + registry.Subscribe(sub, typeof(SimpleClient)); + registry.Subscribe(sub2, typeof(SimpleClient2)); + + client.ClientMethodThatTriggersEvent(); + Assert.IsTrue(sub.EventRaised, "Event Not Raised"); + Assert.IsFalse(sub2.EventRaised, "Event raised"); + + client2.ClientMethodThatTriggersEvent(); + Assert.IsTrue(sub.EventRaised, "Event Not Raised"); + Assert.IsTrue(sub2.EventRaised, "Event Not Raised"); + } + + [Test] + public void NoValidEventHandlersOrEventsToSubscribeto() + { + IEventRegistry registry = new EventRegistry(); + SimpleClient client = new SimpleClient("PublishAllEvents"); + NoEventSubscriber sub = new NoEventSubscriber(); + registry.PublishEvents(client); + + Assert.IsFalse(sub.EventRaised, "Event raised"); + client.ClientMethodThatTriggersEvent(); + Assert.IsFalse(sub.EventRaised, "Event raised"); + + registry.Subscribe(sub); + client.ClientMethodThatTriggersEvent(); + Assert.IsFalse(sub.EventRaised, "Event Raised"); + } + + [Test] + public void NoPublishers() + { + IEventRegistry registry = new EventRegistry(); + SimpleClient client = new SimpleClient("PublishAllEvents"); + SimpleSubscriber sub = new SimpleSubscriber(); + Assert.IsFalse(sub.EventRaised, "Event raised"); + + client.ClientMethodThatTriggersEvent(); + Assert.IsFalse(sub.EventRaised, "Event raised"); + + registry.Subscribe(sub); + client.ClientMethodThatTriggersEvent(); + Assert.IsFalse(sub.EventRaised, "Event Raised"); + } + + [Test] + public void PublishAllEventsAndSubscribeToSome() + { + IEventRegistry registry = new EventRegistry(); + SimpleClient client = new SimpleClient("PublishAllEventsAndSubscribeToSome"); + registry.PublishEvents(client); + EventSubscriber sub = new EventSubscriber(); + OtherEventSubscriber sub2 = new OtherEventSubscriber(); + Assert.IsFalse(sub.EventRaised, "Event raised"); + Assert.IsFalse(sub2.EventRaised, "Event raised"); + + client.ClientMethodThatTriggersEvent(); + Assert.IsFalse(sub.EventRaised, "Event raised"); + + client.ClientMethodThatTriggersEvent3(); + Assert.IsFalse(sub2.EventRaised, "Event raised"); + + registry.Subscribe(sub); + registry.Subscribe(sub2); + client.ClientMethodThatTriggersEvent(); + client.ClientMethodThatTriggersEvent3(); + Assert.IsTrue(sub.EventRaised, "Event Not Raised"); + Assert.IsTrue(sub2.EventRaised, "Event Not Raised"); + } +} diff --git a/test/Spring/Spring.Core.Tests/Objects/ExpressionTestObject.cs b/test/Spring/Spring.Core.Tests/Objects/ExpressionTestObject.cs index 7c761bec..f4435aec 100644 --- a/test/Spring/Spring.Core.Tests/Objects/ExpressionTestObject.cs +++ b/test/Spring/Spring.Core.Tests/Objects/ExpressionTestObject.cs @@ -1,48 +1,47 @@ using System.Collections; using Spring.Expressions; -namespace Spring.Objects +namespace Spring.Objects; + +public class ExpressionTestObject { - public class ExpressionTestObject + private IExpression expressionOne; + private IExpression expressionTwo; + private string someString; + private DateTime someDate; + private IDictionary someDictionary; + + public ExpressionTestObject(string someString) { - private IExpression expressionOne; - private IExpression expressionTwo; - private string someString; - private DateTime someDate; - private IDictionary someDictionary; - - public ExpressionTestObject(string someString) - { - this.someString = someString; - } - - public IExpression ExpressionOne - { - get { return expressionOne; } - set { expressionOne = value; } - } - - public IExpression ExpressionTwo - { - get { return expressionTwo; } - set { expressionTwo = value; } - } - - public string SomeString - { - get { return someString; } - } - - public DateTime SomeDate - { - get { return someDate; } - set { someDate = value; } - } - - public IDictionary SomeDictionary - { - get { return someDictionary; } - set { someDictionary = value; } - } + this.someString = someString; } -} \ No newline at end of file + + public IExpression ExpressionOne + { + get { return expressionOne; } + set { expressionOne = value; } + } + + public IExpression ExpressionTwo + { + get { return expressionTwo; } + set { expressionTwo = value; } + } + + public string SomeString + { + get { return someString; } + } + + public DateTime SomeDate + { + get { return someDate; } + set { someDate = value; } + } + + public IDictionary SomeDictionary + { + get { return someDictionary; } + set { someDictionary = value; } + } +} diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/AbstractListableObjectFactoryTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/AbstractListableObjectFactoryTests.cs index 2daab8d8..f026bade 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/AbstractListableObjectFactoryTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/AbstractListableObjectFactoryTests.cs @@ -24,89 +24,88 @@ using NUnit.Framework; #endregion -namespace Spring.Objects.Factory +namespace Spring.Objects.Factory; + +/// +/// Unit tests for the AbstractListableObjectFactory class. +/// +/// Rod Johnson +/// Rick Evans (.NET) +public abstract class AbstractListableObjectFactoryTests : + AbstractObjectFactoryTests { /// - /// Unit tests for the AbstractListableObjectFactory class. + /// Subclasses must initialize this (via the derived ObjectFactory property). /// - /// Rod Johnson - /// Rick Evans (.NET) - public abstract class AbstractListableObjectFactoryTests : - AbstractObjectFactoryTests + protected internal virtual IListableObjectFactory ListableObjectFactory { - /// - /// Subclasses must initialize this (via the derived ObjectFactory property). - /// - protected internal virtual IListableObjectFactory ListableObjectFactory + get { - get + if (!(ObjectFactory is IListableObjectFactory)) { - if (!(ObjectFactory is IListableObjectFactory)) - { - throw new SystemException("IListableObjectFactory required..."); - } - - return (IListableObjectFactory) ObjectFactory; + throw new SystemException("IListableObjectFactory required..."); } - } - /// - /// Subclasses can override this. - /// - [Test] - public virtual void Count() - { - AssertCount(19); - } - - protected internal void AssertCount(int count) - { - var defnames = ListableObjectFactory.GetObjectDefinitionNames(true); - Assert.IsTrue( - defnames.Count == count, - $"We should have {count} objects, not {defnames.Count}."); - } - - [Test] - public virtual void ObjectCount() - { - AssertTestObjectCount(12); - } - - public virtual void AssertTestObjectCount(int count) - { - var defnames = ListableObjectFactory.GetObjectNamesForType(typeof(TestObject)); - Assert.IsTrue( - defnames.Count == count, - $"We should have {count} objects for class {typeof(TestObject).FullName}, not {defnames.Count}."); - } - - [Test] - public virtual void GetDefinitionsForNoSuchClass() - { - var defnames = ListableObjectFactory.GetObjectNamesForType(typeof(string)); - Assert.IsTrue(defnames.Count == 0, "No string definitions"); - } - - /// - /// Check that count refers to factory class, not - /// object class (we don't know what type factories may return, - /// and it may even change over time). - /// - [Test] - public virtual void GetCountForFactoryClass() - { - int count = ListableObjectFactory.GetObjectNamesForType(typeof(IFactoryObject)).Count; - Assert.IsTrue( - count == 2, - $"Should have 2 factories, not {count}."); - } - - [Test] - public virtual void ContainsObjectDefinition() - { - Assert.IsTrue(ListableObjectFactory.ContainsObjectDefinition("rod")); - Assert.IsTrue(ListableObjectFactory.ContainsObjectDefinition("roderick")); + return (IListableObjectFactory) ObjectFactory; } } + + /// + /// Subclasses can override this. + /// + [Test] + public virtual void Count() + { + AssertCount(19); + } + + protected internal void AssertCount(int count) + { + var defnames = ListableObjectFactory.GetObjectDefinitionNames(true); + Assert.IsTrue( + defnames.Count == count, + $"We should have {count} objects, not {defnames.Count}."); + } + + [Test] + public virtual void ObjectCount() + { + AssertTestObjectCount(12); + } + + public virtual void AssertTestObjectCount(int count) + { + var defnames = ListableObjectFactory.GetObjectNamesForType(typeof(TestObject)); + Assert.IsTrue( + defnames.Count == count, + $"We should have {count} objects for class {typeof(TestObject).FullName}, not {defnames.Count}."); + } + + [Test] + public virtual void GetDefinitionsForNoSuchClass() + { + var defnames = ListableObjectFactory.GetObjectNamesForType(typeof(string)); + Assert.IsTrue(defnames.Count == 0, "No string definitions"); + } + + /// + /// Check that count refers to factory class, not + /// object class (we don't know what type factories may return, + /// and it may even change over time). + /// + [Test] + public virtual void GetCountForFactoryClass() + { + int count = ListableObjectFactory.GetObjectNamesForType(typeof(IFactoryObject)).Count; + Assert.IsTrue( + count == 2, + $"Should have 2 factories, not {count}."); + } + + [Test] + public virtual void ContainsObjectDefinition() + { + Assert.IsTrue(ListableObjectFactory.ContainsObjectDefinition("rod")); + Assert.IsTrue(ListableObjectFactory.ContainsObjectDefinition("roderick")); + } } diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/AbstractObjectFactoryTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/AbstractObjectFactoryTests.cs index 7acbaf2a..9505b844 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/AbstractObjectFactoryTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/AbstractObjectFactoryTests.cs @@ -21,7 +21,6 @@ #region Imports using NUnit.Framework; - using Spring.Core.IO; using Spring.Objects.Factory.Config; using Spring.Objects.Factory.Support; @@ -31,563 +30,562 @@ using System.Collections; #endregion -namespace Spring.Objects.Factory +namespace Spring.Objects.Factory; + +/// +/// Subclasses must override SetUp () to initialize the object factory +/// and any other variables they need. +/// +/// Rod Johnson +/// Rick Evans (.NET) +public abstract class AbstractObjectFactoryTests { - /// - /// Subclasses must override SetUp () to initialize the object factory - /// and any other variables they need. - /// - /// Rod Johnson - /// Rick Evans (.NET) - public abstract class AbstractObjectFactoryTests + #region Properties + + protected internal abstract AbstractObjectFactory CreateObjectFactory(bool caseSensitive); + + private AbstractObjectFactory cachedFactory; + + protected AbstractObjectFactory ObjectFactory { - #region Properties - - protected internal abstract AbstractObjectFactory CreateObjectFactory(bool caseSensitive); - - private AbstractObjectFactory cachedFactory; - - protected AbstractObjectFactory ObjectFactory - { - get { return cachedFactory; } - set { cachedFactory = value; } - } - - #endregion - - #region Case Insensitive Tests - - [Test] - public void RespectsCaseInsensitiveNamesAndAliases() - { - AbstractObjectFactory of = CreateObjectFactory(false); - - object testObject = new object(); - of.RegisterSingleton("name", testObject); - of.RegisterAlias("NAME", "alias"); - - try - { - of.RegisterAlias("NaMe", "AlIaS"); - Assert.Fail(); - } - catch (ObjectDefinitionStoreException ex) - { - Assert.IsTrue(-1 < ex.Message.IndexOf("already registered")); - } - - Assert.AreEqual(1, of.GetAliases("nAmE").Count); - Assert.AreEqual(testObject, of.GetObject("nAmE")); - Assert.AreEqual(testObject, of.GetObject("ALIAS")); - } - - #endregion - - /// - /// Roderick objects inherits from rod, overriding name only. - /// - [Test] - public void Inheritance() - { - Assert.IsTrue(ObjectFactory.ContainsObject("rod")); - Assert.IsTrue(ObjectFactory.ContainsObject("roderick")); - TestObject rod = (TestObject)ObjectFactory["rod"]; - TestObject roderick = (TestObject)ObjectFactory["roderick"]; - Assert.IsTrue(rod != roderick, "not == "); - Assert.IsTrue(rod.Name.Equals("Rod"), "rod.name is Rod"); - Assert.IsTrue(rod.Age == 31, "rod.age is 31"); - Assert.IsTrue(roderick.Name.Equals("Roderick"), "roderick.name is Roderick"); - Assert.IsTrue(roderick.Age == rod.Age, "roderick.age was inherited"); - } - - [Test] - public virtual void GetObjectWithNullName() - { - Assert.Throws(() => ObjectFactory.GetObject(null)); - } - - /// - /// Test that InitializingObject objects receive the AfterPropertiesSet () callback. - /// - [Test] - public void InitializingObjectCallback() - { - MustBeInitialized mbi = - (MustBeInitialized)ObjectFactory["mustBeInitialized"]; - // The dummy business method will throw an exception if the - // AfterPropertiesSet () callback wasn't invoked - mbi.BusinessMethod(); - } - - /// - /// Test that InitializingObject/ObjectFactoryAware/DisposableObject objects - /// receive the AfterPropertiesSet () callback before ObjectFactoryAware - /// callbacks. - /// - [Test] - public void LifecycleCallbacks() - { - LifecycleObject lb = (LifecycleObject)ObjectFactory.GetObject("lifecycle"); - Assert.AreEqual("lifecycle", lb.ObjectName); - // The dummy business method will throw an exception if the - // necessary callbacks weren't invoked in the right order - lb.BusinessMethod(); - Assert.IsFalse(lb.Destroyed, "Was destroyed"); - } - - [Test(Description = "SPRNET-1208")] - public void AddObjectFactoryOnObjectFactoryAwareObjectPostProcessors() - { - AbstractObjectFactory aof = ObjectFactory; - LifecycleObject.PostProcessor lb = new LifecycleObject.PostProcessor(); - aof.AddObjectPostProcessor(lb); - Assert.AreSame(aof, lb.ObjectFactory); - } - - [Test] - public void FindsValidInstance() - { - object o = ObjectFactory.GetObject("rod"); - Assert.IsTrue(o is TestObject, "Rod object is a TestObject"); - TestObject rod = (TestObject)o; - Assert.IsTrue(rod.Name.Equals("Rod"), "rod.name is Rod"); - Assert.IsTrue(rod.Age == 31, "rod.age is 31"); - } - - [Test] - public void GetInstanceByMatchingClass() - { - object o = ObjectFactory.GetObject("rod", typeof(TestObject)); - Assert.IsTrue(o is TestObject, "Rod object is a TestObject"); - } - - [Test] - public void GetInstanceByNonmatchingClass() - { - try - { - ObjectFactory.GetObject("rod", typeof(IObjectFactory)); - Assert.Fail("Rod object is not of type IObjectFactory; GetObjectInstance(rod, typeof (IObjectFactory)) should throw ObjectNotOfRequiredTypeException"); - } - catch (ObjectNotOfRequiredTypeException ex) - { - Assert.IsTrue(ex.ObjectName.Equals("rod"), "Exception has correct object name"); - Assert.IsTrue(ex.RequiredType.Equals(typeof(IObjectFactory)), "Exception requiredType must be ObjectFactory.class"); - Assert.IsTrue(typeof(TestObject).IsAssignableFrom(ex.ActualType), "Exception actualType as TestObject.class"); - Assert.IsTrue(ex.ActualInstance == ObjectFactory.GetObject("rod"), "Actual instance is correct"); - } - } - - [Test] - public virtual void GetSharedInstanceByMatchingClass() - { - object o = ObjectFactory.GetObject("rod", typeof(TestObject)); - Assert.IsTrue(o is TestObject, "Rod object is a TestObject"); - } - - [Test] - public virtual void GetSharedInstanceByMatchingClassNoCatch() - { - object o = ObjectFactory.GetObject("rod", typeof(TestObject)); - Assert.IsTrue(o is TestObject, "Rod object is a TestObject"); - } - - [Test] - public void GetSharedInstanceByNonmatchingClass() - { - try - { - ObjectFactory.GetObject("rod", typeof(IObjectFactory)); - Assert.Fail("Rod object is not of type ObjectFactory; getObjectInstance(rod, ObjectFactory.class) should throw ObjectNotOfRequiredTypeException"); - } - catch (ObjectNotOfRequiredTypeException ex) - { - // So far, so good - Assert.IsTrue(ex.ObjectName.Equals("rod"), "Exception has correct object name"); - Assert.IsTrue(ex.RequiredType.Equals(typeof(IObjectFactory)), "Exception requiredType must be IObjectFactory class"); - Assert.IsTrue(typeof(TestObject).IsAssignableFrom(ex.ActualType), "Exception actualType as TestObject class"); - } - catch (Exception ex) - { - Assert.Fail("Shouldn't throw exception on getting valid instance with matching class : " + ex.Message); - } - } - - [Test] - public virtual void SharedInstancesAreEqual() - { - try - { - object o = ObjectFactory.GetObject("rod"); - Assert.IsTrue(o is TestObject, "Rod object1 is a TestObject"); - object o1 = ObjectFactory.GetObject("rod"); - Assert.IsTrue(o1 is TestObject, "Rod object2 is a TestObject"); - Assert.IsTrue(o == o1, "Object equals applies"); - } - catch - { - Assert.Fail("Shouldn't throw exception on getting valid instance"); - } - } - - [Test] - public void NotThere() - { - Assert.IsFalse(ObjectFactory.ContainsObject("Mr Squiggle")); - Assert.Throws(() => ObjectFactory.GetObject("Mr Squiggle")); - } - - [Test] - public void ValidEmpty() - { - try - { - object o = ObjectFactory.GetObject("validEmpty"); - Assert.IsTrue(o is TestObject, "validEmpty object is a TestObject"); - TestObject ve = (TestObject)o; - Assert.IsTrue(ve.Name == null && ve.Age == 0 && ve.Spouse == null, "Valid empty has defaults"); - } - catch - { - Assert.Fail("Shouldn't throw exception on valid empty"); - } - } - - [Test] - public void RegisterNullCustomTypeConverter() - { - Assert.Throws(() => ObjectFactory.RegisterCustomConverter(null, null)); - } - - [Test] - public virtual void TypeMismatch() - { - try - { - ObjectFactory.GetObject("typeMismatch"); - Assert.Fail("Shouldn't succeed with type mismatch"); - } - catch (ObjectCreationException wex) - { - Assert.IsTrue(wex.InnerException is PropertyAccessExceptionsException); - PropertyAccessExceptionsException ex = (PropertyAccessExceptionsException)wex.InnerException; - // Furthers - Assert.IsTrue(ex.ExceptionCount == 1, "Has one error"); - Assert.IsTrue(ex.GetPropertyAccessException("age") != null, "Error is for field age"); - - TestObject tb = (TestObject)ex.ObjectWrapper.WrappedInstance; - Assert.IsTrue(tb.Age == 0, "Age still has default"); - Assert.IsTrue(ex.GetPropertyAccessException("age").PropertyChangeArgs.NewValue.Equals("34x"), "We have rejected age in exception"); - Assert.IsTrue(tb.Name.Equals("typeMismatch"), "valid name stuck"); - Assert.IsTrue(tb.Spouse.Name.Equals("Rod"), "valid spouse stuck"); - } - } - - [Test] - public virtual void GrandParentDefinitionFoundInObjectFactory() - { - TestObject dad = (TestObject)ObjectFactory.GetObject("father"); - Assert.IsTrue(dad.Name.Equals("Albert"), "Dad has correct name"); - } - - [Test] - public virtual void GrandParentDefinitionFoundInObjectFactoryWithType() - { - TestObject dad = (TestObject)ObjectFactory.GetObject("typedfather", typeof(TestObject)); - Assert.AreEqual(null, dad.Name, "Dad has not correct name"); - } - - [Test] - public virtual void GrandParentDefinitionFoundInObjectFactoryWithArguments() - { - TestObject dad = (TestObject)ObjectFactory.GetObject("namedfather", new object[] { "Hugo", 65 }); - Assert.AreEqual("Hugo", dad.Name, "Dad has not correct name"); - Assert.AreEqual(65, dad.Age, "Dad has not correct age"); - } - - [Test] - public virtual void GrandParentDefinitionFoundInObjectFactoryWithTypeAndArguments() - { - TestObject dad = (TestObject)ObjectFactory.GetObject("typedfather", typeof(TestObject), new object[] { "Chris", 66 }); - Assert.AreEqual("Chris", dad.Name, "Dad has not correct name"); - Assert.AreEqual(66, dad.Age, "Dad has not correct age"); - } - - [Test(Description = "Extra check that the type is really passed on to the parent factory")] - public virtual void GrandParentDefinitionFoundInObjectFactoryWithTypeAndArgumentsWithWrongType() - { - try - { - TestObject dad = (TestObject)ObjectFactory.GetObject("typedfather", typeof(string), new object[] { "Chris", 66 }); - Assert.Fail("should throw ObjectNotOfRequiredTypeException"); - } - catch (ObjectNotOfRequiredTypeException) - { - } - } - - [Test] - public virtual void FactorySingleton() - { - Assert.IsTrue(ObjectFactory.IsSingleton("&singletonFactory")); - Assert.IsTrue(ObjectFactory.IsSingleton("singletonFactory")); - TestObject tb = (TestObject)ObjectFactory.GetObject("singletonFactory"); - Assert.IsTrue(tb.Name.Equals(DummyFactory.SINGLETON_NAME), "Singleton from factory has correct name, not " + tb.Name); - DummyFactory factory = (DummyFactory)ObjectFactory.GetObject("&singletonFactory"); - TestObject tb2 = (TestObject)ObjectFactory.GetObject("singletonFactory"); - Assert.IsTrue(tb == tb2, "Singleton references =="); - Assert.IsTrue(factory.ObjectFactory != null, "FactoryObject is ObjectFactoryAware"); - } - - [Test] - public virtual void FactoryPrototype() - { - Assert.IsTrue(ObjectFactory.IsSingleton("&prototypeFactory")); - Assert.IsFalse(ObjectFactory.IsSingleton("prototypeFactory")); - TestObject tb = (TestObject)ObjectFactory.GetObject("prototypeFactory"); - Assert.IsTrue(!tb.Name.Equals(DummyFactory.SINGLETON_NAME)); - TestObject tb2 = (TestObject)ObjectFactory.GetObject("prototypeFactory"); - Assert.IsTrue(tb != tb2, "Prototype references !="); - } - - /// - /// Check that we can get the factory object itself. - /// This is only possible if we're dealing with a factory - /// - [Test] - public virtual void GetFactoryItself() - { - DummyFactory factory = (DummyFactory)ObjectFactory.GetObject("&singletonFactory"); - Assert.IsTrue(factory != null); - } - - /// Check that AfterPropertiesSet gets called on factory. - [Test] - public virtual void FactoryIsInitialized() - { - TestObject tb = (TestObject)ObjectFactory.GetObject("singletonFactory"); - DummyFactory factory = (DummyFactory)ObjectFactory.GetObject("&singletonFactory"); - Assert.IsTrue(factory.WasInitialized, "Factory was not initialized even though it implemented IInitializingObject"); - } - - /// - /// It should be illegal to dereference a normal object as a factory. - /// - [Test] - public virtual void RejectsFactoryGetOnNormalObject() - { - Assert.Throws(() => ObjectFactory.GetObject("&rod")); - } - - [Test] - public virtual void Aliasing() - { - string alias = "rods alias"; - try - { - ObjectFactory.GetObject(alias); - Assert.Fail("Shouldn't permit factory get on normal object"); - } - catch (NoSuchObjectDefinitionException ex) - { - Assert.IsTrue(alias.Equals(ex.ObjectName)); - } - - // Create alias - ObjectFactory.RegisterAlias("rod", alias); - object rod = ObjectFactory.GetObject("rod"); - object aliasRod = ObjectFactory.GetObject(alias); - Assert.IsTrue(rod == aliasRod); - Assert.Throws(() => ObjectFactory.RegisterAlias("father", alias)); - } - - [Test] - public void RegisterSingletonWithEmptyName() - { - Assert.Throws(() => ObjectFactory.RegisterSingleton(Environment.NewLine, DBNull.Value)); - } - - [Test] - public void RegisterSingletonWithNullName() - { - Assert.Throws(() => ObjectFactory.RegisterSingleton(null, DBNull.Value)); - } - - [Test] - public void GetSingletonNamesReflectsOrderOfRegistration() - { - AbstractObjectFactory of; - of = CreateObjectFactory(true); - of.RegisterSingleton("A", new object()); - of.RegisterSingleton("C", new object()); - of.RegisterSingleton("B", new object()); - Assert.AreEqual(new string[] { "A", "C", "B" }, of.GetSingletonNames()); - - of = CreateObjectFactory(false); - of.RegisterSingleton("A", new object()); - of.RegisterSingleton("C", new object()); - of.RegisterSingleton("B", new object()); - Assert.AreEqual(new string[] { "A", "C", "B" }, of.GetSingletonNames(typeof(object))); - } - - [Test] - public void ContainsSingletonWithEmptyName() - { - Assert.Throws(() => ObjectFactory.ContainsSingleton(Environment.NewLine)); - } - - [Test] - public void ContainsSingletonWithNullName() - { - Assert.Throws(() => ObjectFactory.ContainsSingleton(null)); - } - - [Test] - public void AliasWithEmptyName() - { - Assert.Throws(() => ObjectFactory.RegisterAlias(Environment.NewLine, "the whipping boy")); - } - - [Test] - public void AliasWithEmptyAlias() - { - Assert.Throws(() => ObjectFactory.RegisterAlias("rick", Environment.NewLine)); - } - - // [Test] - // [ExpectedException(typeof(ObjectDefinitionStoreException))] - // public void ChokesIfNotGivenSupportedIObjectDefinitionImplementation() - // { - // ObjectFactory.GetObject("unsupportedDefinition"); - // } - - /// - /// This test resembles a scenario that may happen e.g. using ProxyFactoryObject proxying sibling objects with cyclic dependencies - /// - [Test] - public void CanResolveCyclicSingletonFactoryObjectProductDependencies() - { - AbstractObjectFactory of = this.CreateObjectFactory(true); - - GenericObjectDefinition od = new GenericObjectDefinition(); - od.ObjectTypeName = typeof(TestObject).FullName; - od.IsSingleton = true; - od.PropertyValues.Add(new PropertyValue("Spouse", new RuntimeObjectReference("product2"))); - of.RegisterObjectDefinition("product1Target", od); - - GenericObjectDefinition od2 = new GenericObjectDefinition(); - od2.ObjectTypeName = typeof(TestObject).FullName; - od2.IsSingleton = true; - od2.PropertyValues.Add(new PropertyValue("Sibling", new RuntimeObjectReference("product1"))); - of.RegisterObjectDefinition("product2Target", od2); - - of.RegisterSingleton("product1", new ObjectReferenceFactoryObject("product1Target", of)); - of.RegisterSingleton("product2", new ObjectReferenceFactoryObject("product2Target", of)); - - TestObject to = (TestObject)of.GetObject("product1"); - Assert.NotNull(to); - Assert.NotNull(to.Spouse); - Assert.NotNull(((TestObject)to.Spouse).Sibling); - } - - [Test] - public void ThrowsOnCyclicDependenciesOnNonSingletons() - { - AbstractObjectFactory of = this.CreateObjectFactory(true); - - GenericObjectDefinition od = new GenericObjectDefinition(); - od.ObjectTypeName = typeof(TestObject).FullName; - od.IsSingleton = false; - od.PropertyValues.Add(new PropertyValue("Spouse", new RuntimeObjectReference("product2"))); - of.RegisterObjectDefinition("product1", od); - - GenericObjectDefinition od2 = new GenericObjectDefinition(); - od2.ObjectTypeName = typeof(TestObject).FullName; - od2.IsSingleton = false; - od2.PropertyValues.Add(new PropertyValue("Sibling", new RuntimeObjectReference("product1"))); - of.RegisterObjectDefinition("product2", od2); - - try - { - of.GetObject("product1"); - Assert.Fail(); - } - catch (ObjectCurrentlyInCreationException ex) - { - Assert.AreEqual("product1", ex.ObjectName); - } - } - - private void GetTheTestObject() - { - if (DateTime.Now.Millisecond % 2 == 0) - { - ObjectFactory.GetObject("theObject"); - } - else - { - ObjectFactory.GetObject("theSpouse"); - } - } - - [Test] - public void GetObjectIsThreadSafe() - { - ObjectFactory = CreateObjectFactory(true); - - GenericObjectDefinition theSpouse = new GenericObjectDefinition(); - theSpouse.ObjectTypeName = typeof(TestObject).FullName; - theSpouse.IsSingleton = false; - ObjectFactory.RegisterObjectDefinition("theSpouse", theSpouse); - - GenericObjectDefinition theObject = new GenericObjectDefinition(); - theObject.ObjectTypeName = typeof(TestObject).FullName; - theObject.IsSingleton = false; - theObject.PropertyValues.Add("Spouse", theSpouse); - ObjectFactory.RegisterObjectDefinition("theObject", theObject); - - AsyncTestTask t1 = new AsyncTestMethod(20000, new ThreadStart(GetTheTestObject)).Start(); - AsyncTestTask t2 = new AsyncTestMethod(20000, new ThreadStart(GetTheTestObject)).Start(); - AsyncTestTask t3 = new AsyncTestMethod(20000, new ThreadStart(GetTheTestObject)).Start(); - AsyncTestTask t4 = new AsyncTestMethod(20000, new ThreadStart(GetTheTestObject)).Start(); - - t1.AssertNoException(); - t2.AssertNoException(); - t3.AssertNoException(); - t4.AssertNoException(); - } - + get { return cachedFactory; } + set { cachedFactory = value; } } - [TestFixture] - public class SPRNET_1334 + #endregion + + #region Case Insensitive Tests + + [Test] + public void RespectsCaseInsensitiveNamesAndAliases() { - public static AbstractObjectFactory CreateObjectFactory(bool caseSensitive) + AbstractObjectFactory of = CreateObjectFactory(false); + + object testObject = new object(); + of.RegisterSingleton("name", testObject); + of.RegisterAlias("NAME", "alias"); + + try { - return new DefaultListableObjectFactory(caseSensitive); + of.RegisterAlias("NaMe", "AlIaS"); + Assert.Fail(); + } + catch (ObjectDefinitionStoreException ex) + { + Assert.IsTrue(-1 < ex.Message.IndexOf("already registered")); } - [Test] - public void CanDisposeFactoryWhenDependentObjectCallsFactoryInDispose() + Assert.AreEqual(1, of.GetAliases("nAmE").Count); + Assert.AreEqual(testObject, of.GetObject("nAmE")); + Assert.AreEqual(testObject, of.GetObject("ALIAS")); + } + + #endregion + + /// + /// Roderick objects inherits from rod, overriding name only. + /// + [Test] + public void Inheritance() + { + Assert.IsTrue(ObjectFactory.ContainsObject("rod")); + Assert.IsTrue(ObjectFactory.ContainsObject("roderick")); + TestObject rod = (TestObject) ObjectFactory["rod"]; + TestObject roderick = (TestObject) ObjectFactory["roderick"]; + Assert.IsTrue(rod != roderick, "not == "); + Assert.IsTrue(rod.Name.Equals("Rod"), "rod.name is Rod"); + Assert.IsTrue(rod.Age == 31, "rod.age is 31"); + Assert.IsTrue(roderick.Name.Equals("Roderick"), "roderick.name is Roderick"); + Assert.IsTrue(roderick.Age == rod.Age, "roderick.age was inherited"); + } + + [Test] + public virtual void GetObjectWithNullName() + { + Assert.Throws(() => ObjectFactory.GetObject(null)); + } + + /// + /// Test that InitializingObject objects receive the AfterPropertiesSet () callback. + /// + [Test] + public void InitializingObjectCallback() + { + MustBeInitialized mbi = + (MustBeInitialized) ObjectFactory["mustBeInitialized"]; + // The dummy business method will throw an exception if the + // AfterPropertiesSet () callback wasn't invoked + mbi.BusinessMethod(); + } + + /// + /// Test that InitializingObject/ObjectFactoryAware/DisposableObject objects + /// receive the AfterPropertiesSet () callback before ObjectFactoryAware + /// callbacks. + /// + [Test] + public void LifecycleCallbacks() + { + LifecycleObject lb = (LifecycleObject) ObjectFactory.GetObject("lifecycle"); + Assert.AreEqual("lifecycle", lb.ObjectName); + // The dummy business method will throw an exception if the + // necessary callbacks weren't invoked in the right order + lb.BusinessMethod(); + Assert.IsFalse(lb.Destroyed, "Was destroyed"); + } + + [Test(Description = "SPRNET-1208")] + public void AddObjectFactoryOnObjectFactoryAwareObjectPostProcessors() + { + AbstractObjectFactory aof = ObjectFactory; + LifecycleObject.PostProcessor lb = new LifecycleObject.PostProcessor(); + aof.AddObjectPostProcessor(lb); + Assert.AreSame(aof, lb.ObjectFactory); + } + + [Test] + public void FindsValidInstance() + { + object o = ObjectFactory.GetObject("rod"); + Assert.IsTrue(o is TestObject, "Rod object is a TestObject"); + TestObject rod = (TestObject) o; + Assert.IsTrue(rod.Name.Equals("Rod"), "rod.name is Rod"); + Assert.IsTrue(rod.Age == 31, "rod.age is 31"); + } + + [Test] + public void GetInstanceByMatchingClass() + { + object o = ObjectFactory.GetObject("rod", typeof(TestObject)); + Assert.IsTrue(o is TestObject, "Rod object is a TestObject"); + } + + [Test] + public void GetInstanceByNonmatchingClass() + { + try { - AbstractObjectFactory factory = CreateObjectFactory(false); - ConfigureObjectFactory(factory as IObjectDefinitionRegistry); + ObjectFactory.GetObject("rod", typeof(IObjectFactory)); + Assert.Fail("Rod object is not of type IObjectFactory; GetObjectInstance(rod, typeof (IObjectFactory)) should throw ObjectNotOfRequiredTypeException"); + } + catch (ObjectNotOfRequiredTypeException ex) + { + Assert.IsTrue(ex.ObjectName.Equals("rod"), "Exception has correct object name"); + Assert.IsTrue(ex.RequiredType.Equals(typeof(IObjectFactory)), "Exception requiredType must be ObjectFactory.class"); + Assert.IsTrue(typeof(TestObject).IsAssignableFrom(ex.ActualType), "Exception actualType as TestObject.class"); + Assert.IsTrue(ex.ActualInstance == ObjectFactory.GetObject("rod"), "Actual instance is correct"); + } + } - ParentClass parent = (ParentClass)factory.GetObject("Parent"); - Assert.That(parent, Is.Not.Null); + [Test] + public virtual void GetSharedInstanceByMatchingClass() + { + object o = ObjectFactory.GetObject("rod", typeof(TestObject)); + Assert.IsTrue(o is TestObject, "Rod object is a TestObject"); + } - DisposableClass innerObject = (DisposableClass)parent.InnerObject; - innerObject.ObjectFactory = factory; + [Test] + public virtual void GetSharedInstanceByMatchingClassNoCatch() + { + object o = ObjectFactory.GetObject("rod", typeof(TestObject)); + Assert.IsTrue(o is TestObject, "Rod object is a TestObject"); + } - factory.Dispose(); + [Test] + public void GetSharedInstanceByNonmatchingClass() + { + try + { + ObjectFactory.GetObject("rod", typeof(IObjectFactory)); + Assert.Fail("Rod object is not of type ObjectFactory; getObjectInstance(rod, ObjectFactory.class) should throw ObjectNotOfRequiredTypeException"); + } + catch (ObjectNotOfRequiredTypeException ex) + { + // So far, so good + Assert.IsTrue(ex.ObjectName.Equals("rod"), "Exception has correct object name"); + Assert.IsTrue(ex.RequiredType.Equals(typeof(IObjectFactory)), "Exception requiredType must be IObjectFactory class"); + Assert.IsTrue(typeof(TestObject).IsAssignableFrom(ex.ActualType), "Exception actualType as TestObject class"); + } + catch (Exception ex) + { + Assert.Fail("Shouldn't throw exception on getting valid instance with matching class : " + ex.Message); + } + } - Assert.Pass("Test concluded successfully."); + [Test] + public virtual void SharedInstancesAreEqual() + { + try + { + object o = ObjectFactory.GetObject("rod"); + Assert.IsTrue(o is TestObject, "Rod object1 is a TestObject"); + object o1 = ObjectFactory.GetObject("rod"); + Assert.IsTrue(o1 is TestObject, "Rod object2 is a TestObject"); + Assert.IsTrue(o == o1, "Object equals applies"); + } + catch + { + Assert.Fail("Shouldn't throw exception on getting valid instance"); + } + } + + [Test] + public void NotThere() + { + Assert.IsFalse(ObjectFactory.ContainsObject("Mr Squiggle")); + Assert.Throws(() => ObjectFactory.GetObject("Mr Squiggle")); + } + + [Test] + public void ValidEmpty() + { + try + { + object o = ObjectFactory.GetObject("validEmpty"); + Assert.IsTrue(o is TestObject, "validEmpty object is a TestObject"); + TestObject ve = (TestObject) o; + Assert.IsTrue(ve.Name == null && ve.Age == 0 && ve.Spouse == null, "Valid empty has defaults"); + } + catch + { + Assert.Fail("Shouldn't throw exception on valid empty"); + } + } + + [Test] + public void RegisterNullCustomTypeConverter() + { + Assert.Throws(() => ObjectFactory.RegisterCustomConverter(null, null)); + } + + [Test] + public virtual void TypeMismatch() + { + try + { + ObjectFactory.GetObject("typeMismatch"); + Assert.Fail("Shouldn't succeed with type mismatch"); + } + catch (ObjectCreationException wex) + { + Assert.IsTrue(wex.InnerException is PropertyAccessExceptionsException); + PropertyAccessExceptionsException ex = (PropertyAccessExceptionsException) wex.InnerException; + // Furthers + Assert.IsTrue(ex.ExceptionCount == 1, "Has one error"); + Assert.IsTrue(ex.GetPropertyAccessException("age") != null, "Error is for field age"); + + TestObject tb = (TestObject) ex.ObjectWrapper.WrappedInstance; + Assert.IsTrue(tb.Age == 0, "Age still has default"); + Assert.IsTrue(ex.GetPropertyAccessException("age").PropertyChangeArgs.NewValue.Equals("34x"), "We have rejected age in exception"); + Assert.IsTrue(tb.Name.Equals("typeMismatch"), "valid name stuck"); + Assert.IsTrue(tb.Spouse.Name.Equals("Rod"), "valid spouse stuck"); + } + } + + [Test] + public virtual void GrandParentDefinitionFoundInObjectFactory() + { + TestObject dad = (TestObject) ObjectFactory.GetObject("father"); + Assert.IsTrue(dad.Name.Equals("Albert"), "Dad has correct name"); + } + + [Test] + public virtual void GrandParentDefinitionFoundInObjectFactoryWithType() + { + TestObject dad = (TestObject) ObjectFactory.GetObject("typedfather", typeof(TestObject)); + Assert.AreEqual(null, dad.Name, "Dad has not correct name"); + } + + [Test] + public virtual void GrandParentDefinitionFoundInObjectFactoryWithArguments() + { + TestObject dad = (TestObject) ObjectFactory.GetObject("namedfather", new object[] { "Hugo", 65 }); + Assert.AreEqual("Hugo", dad.Name, "Dad has not correct name"); + Assert.AreEqual(65, dad.Age, "Dad has not correct age"); + } + + [Test] + public virtual void GrandParentDefinitionFoundInObjectFactoryWithTypeAndArguments() + { + TestObject dad = (TestObject) ObjectFactory.GetObject("typedfather", typeof(TestObject), new object[] { "Chris", 66 }); + Assert.AreEqual("Chris", dad.Name, "Dad has not correct name"); + Assert.AreEqual(66, dad.Age, "Dad has not correct age"); + } + + [Test(Description = "Extra check that the type is really passed on to the parent factory")] + public virtual void GrandParentDefinitionFoundInObjectFactoryWithTypeAndArgumentsWithWrongType() + { + try + { + TestObject dad = (TestObject) ObjectFactory.GetObject("typedfather", typeof(string), new object[] { "Chris", 66 }); + Assert.Fail("should throw ObjectNotOfRequiredTypeException"); + } + catch (ObjectNotOfRequiredTypeException) + { + } + } + + [Test] + public virtual void FactorySingleton() + { + Assert.IsTrue(ObjectFactory.IsSingleton("&singletonFactory")); + Assert.IsTrue(ObjectFactory.IsSingleton("singletonFactory")); + TestObject tb = (TestObject) ObjectFactory.GetObject("singletonFactory"); + Assert.IsTrue(tb.Name.Equals(DummyFactory.SINGLETON_NAME), "Singleton from factory has correct name, not " + tb.Name); + DummyFactory factory = (DummyFactory) ObjectFactory.GetObject("&singletonFactory"); + TestObject tb2 = (TestObject) ObjectFactory.GetObject("singletonFactory"); + Assert.IsTrue(tb == tb2, "Singleton references =="); + Assert.IsTrue(factory.ObjectFactory != null, "FactoryObject is ObjectFactoryAware"); + } + + [Test] + public virtual void FactoryPrototype() + { + Assert.IsTrue(ObjectFactory.IsSingleton("&prototypeFactory")); + Assert.IsFalse(ObjectFactory.IsSingleton("prototypeFactory")); + TestObject tb = (TestObject) ObjectFactory.GetObject("prototypeFactory"); + Assert.IsTrue(!tb.Name.Equals(DummyFactory.SINGLETON_NAME)); + TestObject tb2 = (TestObject) ObjectFactory.GetObject("prototypeFactory"); + Assert.IsTrue(tb != tb2, "Prototype references !="); + } + + /// + /// Check that we can get the factory object itself. + /// This is only possible if we're dealing with a factory + /// + [Test] + public virtual void GetFactoryItself() + { + DummyFactory factory = (DummyFactory) ObjectFactory.GetObject("&singletonFactory"); + Assert.IsTrue(factory != null); + } + + /// Check that AfterPropertiesSet gets called on factory. + [Test] + public virtual void FactoryIsInitialized() + { + TestObject tb = (TestObject) ObjectFactory.GetObject("singletonFactory"); + DummyFactory factory = (DummyFactory) ObjectFactory.GetObject("&singletonFactory"); + Assert.IsTrue(factory.WasInitialized, "Factory was not initialized even though it implemented IInitializingObject"); + } + + /// + /// It should be illegal to dereference a normal object as a factory. + /// + [Test] + public virtual void RejectsFactoryGetOnNormalObject() + { + Assert.Throws(() => ObjectFactory.GetObject("&rod")); + } + + [Test] + public virtual void Aliasing() + { + string alias = "rods alias"; + try + { + ObjectFactory.GetObject(alias); + Assert.Fail("Shouldn't permit factory get on normal object"); + } + catch (NoSuchObjectDefinitionException ex) + { + Assert.IsTrue(alias.Equals(ex.ObjectName)); } - private void ConfigureObjectFactory(IObjectDefinitionRegistry factory) + // Create alias + ObjectFactory.RegisterAlias("rod", alias); + object rod = ObjectFactory.GetObject("rod"); + object aliasRod = ObjectFactory.GetObject(alias); + Assert.IsTrue(rod == aliasRod); + Assert.Throws(() => ObjectFactory.RegisterAlias("father", alias)); + } + + [Test] + public void RegisterSingletonWithEmptyName() + { + Assert.Throws(() => ObjectFactory.RegisterSingleton(Environment.NewLine, DBNull.Value)); + } + + [Test] + public void RegisterSingletonWithNullName() + { + Assert.Throws(() => ObjectFactory.RegisterSingleton(null, DBNull.Value)); + } + + [Test] + public void GetSingletonNamesReflectsOrderOfRegistration() + { + AbstractObjectFactory of; + of = CreateObjectFactory(true); + of.RegisterSingleton("A", new object()); + of.RegisterSingleton("C", new object()); + of.RegisterSingleton("B", new object()); + Assert.AreEqual(new string[] { "A", "C", "B" }, of.GetSingletonNames()); + + of = CreateObjectFactory(false); + of.RegisterSingleton("A", new object()); + of.RegisterSingleton("C", new object()); + of.RegisterSingleton("B", new object()); + Assert.AreEqual(new string[] { "A", "C", "B" }, of.GetSingletonNames(typeof(object))); + } + + [Test] + public void ContainsSingletonWithEmptyName() + { + Assert.Throws(() => ObjectFactory.ContainsSingleton(Environment.NewLine)); + } + + [Test] + public void ContainsSingletonWithNullName() + { + Assert.Throws(() => ObjectFactory.ContainsSingleton(null)); + } + + [Test] + public void AliasWithEmptyName() + { + Assert.Throws(() => ObjectFactory.RegisterAlias(Environment.NewLine, "the whipping boy")); + } + + [Test] + public void AliasWithEmptyAlias() + { + Assert.Throws(() => ObjectFactory.RegisterAlias("rick", Environment.NewLine)); + } + + // [Test] + // [ExpectedException(typeof(ObjectDefinitionStoreException))] + // public void ChokesIfNotGivenSupportedIObjectDefinitionImplementation() + // { + // ObjectFactory.GetObject("unsupportedDefinition"); + // } + + /// + /// This test resembles a scenario that may happen e.g. using ProxyFactoryObject proxying sibling objects with cyclic dependencies + /// + [Test] + public void CanResolveCyclicSingletonFactoryObjectProductDependencies() + { + AbstractObjectFactory of = this.CreateObjectFactory(true); + + GenericObjectDefinition od = new GenericObjectDefinition(); + od.ObjectTypeName = typeof(TestObject).FullName; + od.IsSingleton = true; + od.PropertyValues.Add(new PropertyValue("Spouse", new RuntimeObjectReference("product2"))); + of.RegisterObjectDefinition("product1Target", od); + + GenericObjectDefinition od2 = new GenericObjectDefinition(); + od2.ObjectTypeName = typeof(TestObject).FullName; + od2.IsSingleton = true; + od2.PropertyValues.Add(new PropertyValue("Sibling", new RuntimeObjectReference("product1"))); + of.RegisterObjectDefinition("product2Target", od2); + + of.RegisterSingleton("product1", new ObjectReferenceFactoryObject("product1Target", of)); + of.RegisterSingleton("product2", new ObjectReferenceFactoryObject("product2Target", of)); + + TestObject to = (TestObject) of.GetObject("product1"); + Assert.NotNull(to); + Assert.NotNull(to.Spouse); + Assert.NotNull(((TestObject) to.Spouse).Sibling); + } + + [Test] + public void ThrowsOnCyclicDependenciesOnNonSingletons() + { + AbstractObjectFactory of = this.CreateObjectFactory(true); + + GenericObjectDefinition od = new GenericObjectDefinition(); + od.ObjectTypeName = typeof(TestObject).FullName; + od.IsSingleton = false; + od.PropertyValues.Add(new PropertyValue("Spouse", new RuntimeObjectReference("product2"))); + of.RegisterObjectDefinition("product1", od); + + GenericObjectDefinition od2 = new GenericObjectDefinition(); + od2.ObjectTypeName = typeof(TestObject).FullName; + od2.IsSingleton = false; + od2.PropertyValues.Add(new PropertyValue("Sibling", new RuntimeObjectReference("product1"))); + of.RegisterObjectDefinition("product2", od2); + + try { - XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(factory); - reader.LoadObjectDefinitions(new StringResource(@" + of.GetObject("product1"); + Assert.Fail(); + } + catch (ObjectCurrentlyInCreationException ex) + { + Assert.AreEqual("product1", ex.ObjectName); + } + } + + private void GetTheTestObject() + { + if (DateTime.Now.Millisecond % 2 == 0) + { + ObjectFactory.GetObject("theObject"); + } + else + { + ObjectFactory.GetObject("theSpouse"); + } + } + + [Test] + public void GetObjectIsThreadSafe() + { + ObjectFactory = CreateObjectFactory(true); + + GenericObjectDefinition theSpouse = new GenericObjectDefinition(); + theSpouse.ObjectTypeName = typeof(TestObject).FullName; + theSpouse.IsSingleton = false; + ObjectFactory.RegisterObjectDefinition("theSpouse", theSpouse); + + GenericObjectDefinition theObject = new GenericObjectDefinition(); + theObject.ObjectTypeName = typeof(TestObject).FullName; + theObject.IsSingleton = false; + theObject.PropertyValues.Add("Spouse", theSpouse); + ObjectFactory.RegisterObjectDefinition("theObject", theObject); + + AsyncTestTask t1 = new AsyncTestMethod(20000, new ThreadStart(GetTheTestObject)).Start(); + AsyncTestTask t2 = new AsyncTestMethod(20000, new ThreadStart(GetTheTestObject)).Start(); + AsyncTestTask t3 = new AsyncTestMethod(20000, new ThreadStart(GetTheTestObject)).Start(); + AsyncTestTask t4 = new AsyncTestMethod(20000, new ThreadStart(GetTheTestObject)).Start(); + + t1.AssertNoException(); + t2.AssertNoException(); + t3.AssertNoException(); + t4.AssertNoException(); + } +} + +[TestFixture] +public class SPRNET_1334 +{ + public static AbstractObjectFactory CreateObjectFactory(bool caseSensitive) + { + return new DefaultListableObjectFactory(caseSensitive); + } + + [Test] + public void CanDisposeFactoryWhenDependentObjectCallsFactoryInDispose() + { + AbstractObjectFactory factory = CreateObjectFactory(false); + ConfigureObjectFactory(factory as IObjectDefinitionRegistry); + + ParentClass parent = (ParentClass) factory.GetObject("Parent"); + Assert.That(parent, Is.Not.Null); + + DisposableClass innerObject = (DisposableClass) parent.InnerObject; + innerObject.ObjectFactory = factory; + + factory.Dispose(); + + Assert.Pass("Test concluded successfully."); + } + + private void ConfigureObjectFactory(IObjectDefinitionRegistry factory) + { + XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(factory); + reader.LoadObjectDefinitions(new StringResource(@" @@ -609,403 +607,397 @@ namespace Spring.Objects.Factory ")); + } + + public class ParentClass + { + private string _name; + + public string Name + { + get { return _name; } + set { _name = value; } } - public class ParentClass + private IDisposable _innerObject; + + public IDisposable InnerObject { - private string _name; - - public string Name - { - get { return _name; } - set { _name = value; } - } - - private IDisposable _innerObject; - - public IDisposable InnerObject - { - get { return _innerObject; } - set { _innerObject = value; } - } - } - - public class DisposableClass : IDisposable - { - private AbstractObjectFactory _objectFactory; - public AbstractObjectFactory ObjectFactory - { - get { return _objectFactory; } - set { _objectFactory = value; } - } - - public void Dispose() - { - Console.WriteLine("DisposableClass.Dispose()"); - if (ObjectFactory == null) - return; - - object parent = ObjectFactory.GetObject("Parent"); - if (parent == null) - Console.WriteLine("parent == null"); - } - + get { return _innerObject; } + set { _innerObject = value; } } } - [TestFixture] - public class SPRNET_1338 + public class DisposableClass : IDisposable { - private static AbstractObjectFactory _cachedFactory; + private AbstractObjectFactory _objectFactory; - protected static AbstractObjectFactory ObjectFactory + public AbstractObjectFactory ObjectFactory { - get { return _cachedFactory; } - set { _cachedFactory = value; } + get { return _objectFactory; } + set { _objectFactory = value; } } - [SetUp] - public void _SetUp() + public void Dispose() { - ObjectFactory = CreateObjectFactory(true); + Console.WriteLine("DisposableClass.Dispose()"); + if (ObjectFactory == null) + return; - GenericObjectDefinition threadCreatorInsideConstructor = new GenericObjectDefinition(); - threadCreatorInsideConstructor.ObjectTypeName = typeof(ThreadCreatorInsideConstructor).FullName; - threadCreatorInsideConstructor.IsSingleton = true; - ObjectFactory.RegisterObjectDefinition("threadCreatorInsideConstructor", threadCreatorInsideConstructor); + object parent = ObjectFactory.GetObject("Parent"); + if (parent == null) + Console.WriteLine("parent == null"); + } + } +} - GenericObjectDefinition threadCreatorInsideDispose = new GenericObjectDefinition(); - threadCreatorInsideDispose.ObjectTypeName = typeof(ThreadCreatorInsideDispose).FullName; - threadCreatorInsideDispose.IsSingleton = true; - ObjectFactory.RegisterObjectDefinition("threadCreatorInsideDispose", threadCreatorInsideDispose); +[TestFixture] +public class SPRNET_1338 +{ + private static AbstractObjectFactory _cachedFactory; + + protected static AbstractObjectFactory ObjectFactory + { + get { return _cachedFactory; } + set { _cachedFactory = value; } + } + + [SetUp] + public void _SetUp() + { + ObjectFactory = CreateObjectFactory(true); + + GenericObjectDefinition threadCreatorInsideConstructor = new GenericObjectDefinition(); + threadCreatorInsideConstructor.ObjectTypeName = typeof(ThreadCreatorInsideConstructor).FullName; + threadCreatorInsideConstructor.IsSingleton = true; + ObjectFactory.RegisterObjectDefinition("threadCreatorInsideConstructor", threadCreatorInsideConstructor); + + GenericObjectDefinition threadCreatorInsideDispose = new GenericObjectDefinition(); + threadCreatorInsideDispose.ObjectTypeName = typeof(ThreadCreatorInsideDispose).FullName; + threadCreatorInsideDispose.IsSingleton = true; + ObjectFactory.RegisterObjectDefinition("threadCreatorInsideDispose", threadCreatorInsideDispose); + } + + [Test] + [Ignore("Test fails -- waiting for verification re: if bug exists in Java impl")] + public void CanAvoidLockContentionDuringObjectFactoryDisposal() + { + Thread t = new Thread(CreateThreadContentionFromDispose); + t.Start(); + t.Join(20000); + + if (t.ThreadState == System.Threading.ThreadState.WaitSleepJoin) + Assert.Fail("Lock Contention Blocked Successful Dispose of ObjectFactory!"); + } + + [Test] + public void CanAvoidLockContentionDuringObjectInstantiation() + { + Thread t = new Thread(CreateThreadContentionFromConstructor); + t.Start(); + t.Join(20000); + + if (t.ThreadState == System.Threading.ThreadState.WaitSleepJoin) + Assert.Fail("Lock Contention Blocked Successful Instantiation of Singleton Test Object!"); + } + + public static AbstractObjectFactory CreateObjectFactory(bool caseSensitive) + { + return new DefaultListableObjectFactory(caseSensitive); + } + + private void CreateThreadContentionFromConstructor() + { + ObjectFactory.GetObject("threadCreatorInsideConstructor"); + } + + private void CreateThreadContentionFromDispose() + { + ObjectFactory.GetObject("threadCreatorInsideDispose"); + ObjectFactory.Dispose(); + } + + internal class ThreadCreatorInsideDispose : IDisposable + { + public ThreadCreatorInsideDispose() + { } - [Test] - [Ignore("Test fails -- waiting for verification re: if bug exists in Java impl")] - public void CanAvoidLockContentionDuringObjectFactoryDisposal() + public void Dispose() { - Thread t = new Thread(CreateThreadContentionFromDispose); + Thread t = new Thread(ConcurentThreadDisposeProc); t.Start(); - t.Join(20000); - - if (t.ThreadState == System.Threading.ThreadState.WaitSleepJoin) - Assert.Fail("Lock Contention Blocked Successful Dispose of ObjectFactory!"); + t.Join(); } - [Test] - public void CanAvoidLockContentionDuringObjectInstantiation() - { - Thread t = new Thread(CreateThreadContentionFromConstructor); - t.Start(); - t.Join(20000); - - if (t.ThreadState == System.Threading.ThreadState.WaitSleepJoin) - Assert.Fail("Lock Contention Blocked Successful Instantiation of Singleton Test Object!"); - } - - public static AbstractObjectFactory CreateObjectFactory(bool caseSensitive) - { - return new DefaultListableObjectFactory(caseSensitive); - } - - private void CreateThreadContentionFromConstructor() + private static void ConcurentThreadDisposeProc() { ObjectFactory.GetObject("threadCreatorInsideConstructor"); } + } - private void CreateThreadContentionFromDispose() + internal class ThreadCreatorInsideConstructor + { + public ThreadCreatorInsideConstructor() + { + Thread t = new Thread(ConcurentThreadProc); + t.Start(); + t.Join(); + } + + private static void ConcurentThreadProc() { ObjectFactory.GetObject("threadCreatorInsideDispose"); - ObjectFactory.Dispose(); } - - internal class ThreadCreatorInsideDispose : IDisposable - { - public ThreadCreatorInsideDispose() - { - } - - public void Dispose() - { - Thread t = new Thread(ConcurentThreadDisposeProc); - t.Start(); - t.Join(); - } - - private static void ConcurentThreadDisposeProc() - { - ObjectFactory.GetObject("threadCreatorInsideConstructor"); - } - } - - internal class ThreadCreatorInsideConstructor - { - public ThreadCreatorInsideConstructor() - { - Thread t = new Thread(ConcurentThreadProc); - t.Start(); - t.Join(); - } - - private static void ConcurentThreadProc() - { - ObjectFactory.GetObject("threadCreatorInsideDispose"); - } - } - - } - - [TestFixture] - public class SPRNET_1315 - { - private static AbstractObjectFactory _cachedFactory; - - private static int _childCounter; - - private static int _parentCounter; - - private static ArrayList invocationLog = new ArrayList(); - - protected static AbstractObjectFactory ObjectFactory - { - get { return _cachedFactory; } - set { _cachedFactory = value; } - } - - [SetUp] - public void _Setup() - { - ObjectFactory = new DefaultListableObjectFactory(true); - invocationLog.Clear(); - _parentCounter = 0; - _childCounter = 0; - } - - [Test] - public void When_ParentAndChildArePrototypes_ConstructorInjection_DoesNotEnforceDestructionOrder() - { - WireParentAndChildWWithImpliedDependencyByConstructorInjection(false, false); - - Parent theParent = ObjectFactory.GetObject("parent") as Parent; - theParent.Dispose(); - - Assert.AreEqual(0, _parentCounter, "Should have no remaining parent objects after dispose"); - Assert.AreEqual(1, _childCounter, "Should have exactly ONE child object"); - Assert.IsNotNull(theParent.InjectedChild, "Parent's child dependency not set as expected"); - Assert.AreEqual("Parent Destructor", invocationLog[2], "Parent Destructor wasn't called third!"); - Assert.AreEqual(3, invocationLog.Count, "Should have no further object lifecycle behavior after parent destruction!"); - } - - [Test] - public void When_ParentAndChildArePrototypes_ConstructorInjection_EnforcesConstructionOrder() - { - WireParentAndChildWWithImpliedDependencyByConstructorInjection(false, false); - - Parent theParent = ObjectFactory.GetObject("parent") as Parent; - - Assert.AreEqual(1, _parentCounter, "Should have exactly ONE parent object"); - Assert.AreEqual(1, _childCounter, "Should have exactly ONE child object"); - Assert.IsNotNull(theParent.InjectedChild, "Parent's child dependency not set as expected"); - Assert.AreEqual("Child Constructor", invocationLog[0], "Child Constructor wasn't called first!"); - Assert.AreEqual("Parent Constructor", invocationLog[1], "Parent Constructor wasn't called second!"); - - } - - [Test] - public void When_ParentAndChildArePrototypes_DependsOn_DoesNotEnforceDestructionOrder() - { - WireParentAndChildWithDependsOnDeclarationDependency(false, false); - - Parent theParent = ObjectFactory.GetObject("parent") as Parent; - theParent.Dispose(); - - Assert.AreEqual(0, _parentCounter, "Should have no remaining parent objects after dispose"); - Assert.AreEqual(1, _childCounter, "Should have exactly ONE child object"); - - Assert.AreEqual("Parent Destructor", invocationLog[2], "Parent Destructor wasn't called third!"); - Assert.AreEqual(3, invocationLog.Count, "Should have no further object lifecycle behavior after parent destruction!"); - } - - [Test] - public void When_ParentAndChildArePrototypes_DependsOn_EnforcesConstructionOrder() - { - WireParentAndChildWithDependsOnDeclarationDependency(false, false); - - Parent theParent = ObjectFactory.GetObject("parent") as Parent; - - Assert.AreEqual(1, _parentCounter, "Should have exactly ONE parent object"); - Assert.AreEqual(1, _childCounter, "Should have exactly ONE child object"); - Assert.AreEqual("Child Constructor", invocationLog[0], "Child Constructor wasn't called first!"); - Assert.AreEqual("Parent Constructor", invocationLog[1], "Parent Constructor wasn't called second!"); - - } - - [Test] - public void When_ParentAndChildAreSingletons_ConstructorInjection_EnforcesDestructionOrder() - { - WireParentAndChildWWithImpliedDependencyByConstructorInjection(true, true); - - //triger the construction of the singletons - ObjectFactory.GetObject("parent"); - - //trigger the disposal of the singletons - ObjectFactory.Dispose(); - - Assert.AreEqual(0, _parentCounter, "Should have no remaining parent objects after dispose"); - Assert.AreEqual(0, _childCounter, "Should have no remaining child objects after dispose"); - Assert.AreEqual("Parent Destructor", invocationLog[2], "Parent Destructor wasn't called third!"); - Assert.AreEqual("Child Destructor", invocationLog[3], "Child Destructor wasn't called fourth!"); - Assert.AreEqual(4, invocationLog.Count, "Should have no further object lifecycle behavior after parent destruction!"); - } - - [Test] - public void When_ParentAndChildAreSingletons_DependsOn_EnforcesDestructionOrder() - { - WireParentAndChildWithDependsOnDeclarationDependency(true, true); - - //triger the construction of the singletons - ObjectFactory.GetObject("parent"); - - //make certain they are created successfully - Assert.AreEqual(1, _parentCounter, "Should have exactly ONE parent object"); - Assert.AreEqual(1, _childCounter, "Should have exactly ONE child object"); - - //trigger the disposal of the singletons - ObjectFactory.Dispose(); - - Assert.AreEqual(0, _parentCounter, "Should have no remaining parent objects after dispose"); - Assert.AreEqual(0, _childCounter, "Should have no remaining child objects after dispose"); - Assert.AreEqual("Parent Destructor", invocationLog[2], "Parent Destructor wasn't called third!"); - Assert.AreEqual("Child Destructor", invocationLog[3], "Child Destructor wasn't called fourth!"); - Assert.AreEqual(4, invocationLog.Count, "Should have no further object lifecycle behavior after child destruction!"); - } - - [Test] - public void When_ParentIsProttpyeAndChildIsSingleton_ConstructorInjection_DoesNotEnforcesDestructionOrder() - { - WireParentAndChildWWithImpliedDependencyByConstructorInjection(false, true); - - //triger the construction of the singletons - ObjectFactory.GetObject("parent"); - - //trigger the disposal of the singletons - ObjectFactory.Dispose(); - - Assert.AreEqual(1, _parentCounter, "Should have ONE remaining parent objects after dispose"); - Assert.AreEqual(0, _childCounter, "Should have no remaining child objects after dispose"); - Assert.AreEqual("Child Destructor", invocationLog[2], "Child Destructor wasn't called third!"); - Assert.AreEqual(3, invocationLog.Count, "Should have no further object lifecycle behavior after child destruction!"); - } - - [Test] - public void When_ParentIsSingletonAndChildIsPrototype_ConstructorInjection_DoesNotEnforcesDestructionOrder() - { - WireParentAndChildWWithImpliedDependencyByConstructorInjection(true, false); - - //triger the construction of the singletons - ObjectFactory.GetObject("parent"); - - //trigger the disposal of the singletons - ObjectFactory.Dispose(); - - Assert.AreEqual(0, _parentCounter, "Should have no remaining parent objects after dispose"); - Assert.AreEqual(1, _childCounter, "Should have ONE remaining child object after dispose"); - Assert.AreEqual("Parent Destructor", invocationLog[2], "Child Destructor wasn't called third!"); - Assert.AreEqual(3, invocationLog.Count, "Should have no further object lifecycle behavior after parent destruction!"); - } - - [Test] - public void When_ParentIsSingletonAndChildIsPrototype_DependsOn_EnforcesDestructionOrder() - { - WireParentAndChildWithDependsOnDeclarationDependency(true, false); - - //triger the construction of the singletons - ObjectFactory.GetObject("parent"); - - //make certain they are created successfully - Assert.AreEqual(1, _parentCounter, "Should have exactly ONE parent object"); - Assert.AreEqual(1, _childCounter, "Should have exactly ONE child object"); - - //trigger the disposal of the singletons - ObjectFactory.Dispose(); - - Assert.AreEqual(0, _parentCounter, "Should have no remaining parent objects after dispose"); - Assert.AreEqual(1, _childCounter, "Should have no remaining child objects after dispose"); - Assert.AreEqual("Parent Destructor", invocationLog[2], "Parent Destructor wasn't called third!"); - Assert.AreEqual(3, invocationLog.Count, "Should have no further object lifecycle behavior after parent destruction!"); - } - - private void WireParentAndChildWithDependsOnDeclarationDependency(bool parentIsSingleton, bool childIsSingleton) - { - GenericObjectDefinition child = new GenericObjectDefinition(); - child.ObjectTypeName = typeof(Child).FullName; - child.IsSingleton = childIsSingleton; - ObjectFactory.RegisterObjectDefinition("child", child); - - GenericObjectDefinition parent = new GenericObjectDefinition(); - parent.ObjectTypeName = typeof(Parent).FullName; - parent.IsSingleton = parentIsSingleton; - parent.DependsOn = new string[] { "child" }; - ObjectFactory.RegisterObjectDefinition("parent", parent); - } - - private static void WireParentAndChildWWithImpliedDependencyByConstructorInjection(bool parentIsSingleton, bool childIsSingleton) - { - GenericObjectDefinition child = new GenericObjectDefinition(); - child.ObjectTypeName = typeof(Child).FullName; - child.IsSingleton = childIsSingleton; - ObjectFactory.RegisterObjectDefinition("child", child); - - GenericObjectDefinition parent = new GenericObjectDefinition(); - parent.ObjectTypeName = typeof(Parent).FullName; - parent.IsSingleton = parentIsSingleton; - parent.ConstructorArgumentValues.AddIndexedArgumentValue(0, new RuntimeObjectReference("child")); - ObjectFactory.RegisterObjectDefinition("parent", parent); - } - - public class Parent : IDisposable - { - - private Child _child; - - public Parent() - : this(null) - { - } - - public Parent(Child child) - { - _child = child; - _parentCounter++; - invocationLog.Add("Parent Constructor"); - } - - public Child InjectedChild - { - get { return _child; } - } - - public void Dispose() - { - _parentCounter--; - invocationLog.Add("Parent Destructor"); - } - } - - public class Child : IDisposable - { - public Child() - { - _childCounter++; - invocationLog.Add("Child Constructor"); - } - - public void Dispose() - { - _childCounter--; - invocationLog.Add("Child Destructor"); - } - } - + } +} + +[TestFixture] +public class SPRNET_1315 +{ + private static AbstractObjectFactory _cachedFactory; + + private static int _childCounter; + + private static int _parentCounter; + + private static ArrayList invocationLog = new ArrayList(); + + protected static AbstractObjectFactory ObjectFactory + { + get { return _cachedFactory; } + set { _cachedFactory = value; } + } + + [SetUp] + public void _Setup() + { + ObjectFactory = new DefaultListableObjectFactory(true); + invocationLog.Clear(); + _parentCounter = 0; + _childCounter = 0; + } + + [Test] + public void When_ParentAndChildArePrototypes_ConstructorInjection_DoesNotEnforceDestructionOrder() + { + WireParentAndChildWWithImpliedDependencyByConstructorInjection(false, false); + + Parent theParent = ObjectFactory.GetObject("parent") as Parent; + theParent.Dispose(); + + Assert.AreEqual(0, _parentCounter, "Should have no remaining parent objects after dispose"); + Assert.AreEqual(1, _childCounter, "Should have exactly ONE child object"); + Assert.IsNotNull(theParent.InjectedChild, "Parent's child dependency not set as expected"); + Assert.AreEqual("Parent Destructor", invocationLog[2], "Parent Destructor wasn't called third!"); + Assert.AreEqual(3, invocationLog.Count, "Should have no further object lifecycle behavior after parent destruction!"); + } + + [Test] + public void When_ParentAndChildArePrototypes_ConstructorInjection_EnforcesConstructionOrder() + { + WireParentAndChildWWithImpliedDependencyByConstructorInjection(false, false); + + Parent theParent = ObjectFactory.GetObject("parent") as Parent; + + Assert.AreEqual(1, _parentCounter, "Should have exactly ONE parent object"); + Assert.AreEqual(1, _childCounter, "Should have exactly ONE child object"); + Assert.IsNotNull(theParent.InjectedChild, "Parent's child dependency not set as expected"); + Assert.AreEqual("Child Constructor", invocationLog[0], "Child Constructor wasn't called first!"); + Assert.AreEqual("Parent Constructor", invocationLog[1], "Parent Constructor wasn't called second!"); + } + + [Test] + public void When_ParentAndChildArePrototypes_DependsOn_DoesNotEnforceDestructionOrder() + { + WireParentAndChildWithDependsOnDeclarationDependency(false, false); + + Parent theParent = ObjectFactory.GetObject("parent") as Parent; + theParent.Dispose(); + + Assert.AreEqual(0, _parentCounter, "Should have no remaining parent objects after dispose"); + Assert.AreEqual(1, _childCounter, "Should have exactly ONE child object"); + + Assert.AreEqual("Parent Destructor", invocationLog[2], "Parent Destructor wasn't called third!"); + Assert.AreEqual(3, invocationLog.Count, "Should have no further object lifecycle behavior after parent destruction!"); + } + + [Test] + public void When_ParentAndChildArePrototypes_DependsOn_EnforcesConstructionOrder() + { + WireParentAndChildWithDependsOnDeclarationDependency(false, false); + + Parent theParent = ObjectFactory.GetObject("parent") as Parent; + + Assert.AreEqual(1, _parentCounter, "Should have exactly ONE parent object"); + Assert.AreEqual(1, _childCounter, "Should have exactly ONE child object"); + Assert.AreEqual("Child Constructor", invocationLog[0], "Child Constructor wasn't called first!"); + Assert.AreEqual("Parent Constructor", invocationLog[1], "Parent Constructor wasn't called second!"); + } + + [Test] + public void When_ParentAndChildAreSingletons_ConstructorInjection_EnforcesDestructionOrder() + { + WireParentAndChildWWithImpliedDependencyByConstructorInjection(true, true); + + //triger the construction of the singletons + ObjectFactory.GetObject("parent"); + + //trigger the disposal of the singletons + ObjectFactory.Dispose(); + + Assert.AreEqual(0, _parentCounter, "Should have no remaining parent objects after dispose"); + Assert.AreEqual(0, _childCounter, "Should have no remaining child objects after dispose"); + Assert.AreEqual("Parent Destructor", invocationLog[2], "Parent Destructor wasn't called third!"); + Assert.AreEqual("Child Destructor", invocationLog[3], "Child Destructor wasn't called fourth!"); + Assert.AreEqual(4, invocationLog.Count, "Should have no further object lifecycle behavior after parent destruction!"); + } + + [Test] + public void When_ParentAndChildAreSingletons_DependsOn_EnforcesDestructionOrder() + { + WireParentAndChildWithDependsOnDeclarationDependency(true, true); + + //triger the construction of the singletons + ObjectFactory.GetObject("parent"); + + //make certain they are created successfully + Assert.AreEqual(1, _parentCounter, "Should have exactly ONE parent object"); + Assert.AreEqual(1, _childCounter, "Should have exactly ONE child object"); + + //trigger the disposal of the singletons + ObjectFactory.Dispose(); + + Assert.AreEqual(0, _parentCounter, "Should have no remaining parent objects after dispose"); + Assert.AreEqual(0, _childCounter, "Should have no remaining child objects after dispose"); + Assert.AreEqual("Parent Destructor", invocationLog[2], "Parent Destructor wasn't called third!"); + Assert.AreEqual("Child Destructor", invocationLog[3], "Child Destructor wasn't called fourth!"); + Assert.AreEqual(4, invocationLog.Count, "Should have no further object lifecycle behavior after child destruction!"); + } + + [Test] + public void When_ParentIsProttpyeAndChildIsSingleton_ConstructorInjection_DoesNotEnforcesDestructionOrder() + { + WireParentAndChildWWithImpliedDependencyByConstructorInjection(false, true); + + //triger the construction of the singletons + ObjectFactory.GetObject("parent"); + + //trigger the disposal of the singletons + ObjectFactory.Dispose(); + + Assert.AreEqual(1, _parentCounter, "Should have ONE remaining parent objects after dispose"); + Assert.AreEqual(0, _childCounter, "Should have no remaining child objects after dispose"); + Assert.AreEqual("Child Destructor", invocationLog[2], "Child Destructor wasn't called third!"); + Assert.AreEqual(3, invocationLog.Count, "Should have no further object lifecycle behavior after child destruction!"); + } + + [Test] + public void When_ParentIsSingletonAndChildIsPrototype_ConstructorInjection_DoesNotEnforcesDestructionOrder() + { + WireParentAndChildWWithImpliedDependencyByConstructorInjection(true, false); + + //triger the construction of the singletons + ObjectFactory.GetObject("parent"); + + //trigger the disposal of the singletons + ObjectFactory.Dispose(); + + Assert.AreEqual(0, _parentCounter, "Should have no remaining parent objects after dispose"); + Assert.AreEqual(1, _childCounter, "Should have ONE remaining child object after dispose"); + Assert.AreEqual("Parent Destructor", invocationLog[2], "Child Destructor wasn't called third!"); + Assert.AreEqual(3, invocationLog.Count, "Should have no further object lifecycle behavior after parent destruction!"); + } + + [Test] + public void When_ParentIsSingletonAndChildIsPrototype_DependsOn_EnforcesDestructionOrder() + { + WireParentAndChildWithDependsOnDeclarationDependency(true, false); + + //triger the construction of the singletons + ObjectFactory.GetObject("parent"); + + //make certain they are created successfully + Assert.AreEqual(1, _parentCounter, "Should have exactly ONE parent object"); + Assert.AreEqual(1, _childCounter, "Should have exactly ONE child object"); + + //trigger the disposal of the singletons + ObjectFactory.Dispose(); + + Assert.AreEqual(0, _parentCounter, "Should have no remaining parent objects after dispose"); + Assert.AreEqual(1, _childCounter, "Should have no remaining child objects after dispose"); + Assert.AreEqual("Parent Destructor", invocationLog[2], "Parent Destructor wasn't called third!"); + Assert.AreEqual(3, invocationLog.Count, "Should have no further object lifecycle behavior after parent destruction!"); + } + + private void WireParentAndChildWithDependsOnDeclarationDependency(bool parentIsSingleton, bool childIsSingleton) + { + GenericObjectDefinition child = new GenericObjectDefinition(); + child.ObjectTypeName = typeof(Child).FullName; + child.IsSingleton = childIsSingleton; + ObjectFactory.RegisterObjectDefinition("child", child); + + GenericObjectDefinition parent = new GenericObjectDefinition(); + parent.ObjectTypeName = typeof(Parent).FullName; + parent.IsSingleton = parentIsSingleton; + parent.DependsOn = new string[] { "child" }; + ObjectFactory.RegisterObjectDefinition("parent", parent); + } + + private static void WireParentAndChildWWithImpliedDependencyByConstructorInjection(bool parentIsSingleton, bool childIsSingleton) + { + GenericObjectDefinition child = new GenericObjectDefinition(); + child.ObjectTypeName = typeof(Child).FullName; + child.IsSingleton = childIsSingleton; + ObjectFactory.RegisterObjectDefinition("child", child); + + GenericObjectDefinition parent = new GenericObjectDefinition(); + parent.ObjectTypeName = typeof(Parent).FullName; + parent.IsSingleton = parentIsSingleton; + parent.ConstructorArgumentValues.AddIndexedArgumentValue(0, new RuntimeObjectReference("child")); + ObjectFactory.RegisterObjectDefinition("parent", parent); + } + + public class Parent : IDisposable + { + private Child _child; + + public Parent() + : this(null) + { + } + + public Parent(Child child) + { + _child = child; + _parentCounter++; + invocationLog.Add("Parent Constructor"); + } + + public Child InjectedChild + { + get { return _child; } + } + + public void Dispose() + { + _parentCounter--; + invocationLog.Add("Parent Destructor"); + } + } + + public class Child : IDisposable + { + public Child() + { + _childCounter++; + invocationLog.Add("Child Constructor"); + } + + public void Dispose() + { + _childCounter--; + invocationLog.Add("Child Destructor"); + } } } diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/AutowireByQualifierAttributeTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/AutowireByQualifierAttributeTests.cs index c49e3a1e..56b84af5 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/AutowireByQualifierAttributeTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/AutowireByQualifierAttributeTests.cs @@ -26,62 +26,61 @@ using AutowireTestFieldNormal = Spring.Objects.Factory.Attributes.ByQualifierAtt using AutowireTestMethodNormal = Spring.Objects.Factory.Attributes.ByQualifierAttribute.AutowireTestMethodNormal; using AutowireTestPropertyNormal = Spring.Objects.Factory.Attributes.ByQualifierAttribute.AutowireTestPropertyNormal; -namespace Spring.Objects.Factory.Attributes +namespace Spring.Objects.Factory.Attributes; + +[TestFixture] +public class AutowireByQualifierAttributeTests { - [TestFixture] - public class AutowireByQualifierAttributeTests + private XmlApplicationContext _applicationContext; + + [SetUp] + public void Setup() { - private XmlApplicationContext _applicationContext; + _applicationContext = new XmlApplicationContext(false, + "assembly://Spring.Core.Tests/Spring.Objects.Factory.Attributes/ByQualifierAttributeObjects.xml"); + } - [SetUp] - public void Setup() - { - _applicationContext = new XmlApplicationContext(false, - "assembly://Spring.Core.Tests/Spring.Objects.Factory.Attributes/ByQualifierAttributeObjects.xml"); - } + [Test] + public void InjectOnField() + { + var testObj = (AutowireTestFieldNormal) _applicationContext.GetObject("AutowireTestField"); + var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestField"); - [Test] - public void InjectOnField() - { - var testObj = (AutowireTestFieldNormal) _applicationContext.GetObject("AutowireTestField"); - var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestField"); + Assert.That(testObj.ciao, Is.Not.Null); + Assert.That(testObj.ciao.GetType(), Is.EqualTo(typeof(CiaoFoo))); + Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(1)); + } - Assert.That(testObj.ciao, Is.Not.Null); - Assert.That(testObj.ciao.GetType(), Is.EqualTo(typeof(CiaoFoo))); - Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(1)); - } + [Test] + public void InjectOnProperty() + { + var testObj = (AutowireTestPropertyNormal) _applicationContext.GetObject("AutowireTestProperty"); + var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestProperty"); - [Test] - public void InjectOnProperty() - { - var testObj = (AutowireTestPropertyNormal) _applicationContext.GetObject("AutowireTestProperty"); - var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestProperty"); + Assert.That(testObj.Ciao, Is.Not.Null); + Assert.That(testObj.Ciao.GetType(), Is.EqualTo(typeof(CiaoFoo))); + Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(1)); + } - Assert.That(testObj.Ciao, Is.Not.Null); - Assert.That(testObj.Ciao.GetType(), Is.EqualTo(typeof(CiaoFoo))); - Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(1)); - } + [Test] + public void InjectOnMethod() + { + var testObj = (AutowireTestMethodNormal) _applicationContext.GetObject("AutowireTestMethod"); + var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestMethod"); - [Test] - public void InjectOnMethod() - { - var testObj = (AutowireTestMethodNormal) _applicationContext.GetObject("AutowireTestMethod"); - var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestMethod"); + Assert.That(testObj.ciao, Is.Not.Null); + Assert.That(testObj.ciao.GetType(), Is.EqualTo(typeof(CiaoFoo))); + Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(1)); + } - Assert.That(testObj.ciao, Is.Not.Null); - Assert.That(testObj.ciao.GetType(), Is.EqualTo(typeof(CiaoFoo))); - Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(1)); - } + [Test] + public void InjectOnConstructor() + { + var testObj = (AutowireTestConstructorNormal) _applicationContext.GetObject("AutowireTestConstructor"); + var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestConstructor"); - [Test] - public void InjectOnConstructor() - { - var testObj = (AutowireTestConstructorNormal)_applicationContext.GetObject("AutowireTestConstructor"); - var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestConstructor"); - - Assert.That(testObj.ciao, Is.Not.Null); - Assert.That(testObj.ciao.GetType(), Is.EqualTo(typeof(CiaoFoo))); - Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(0)); - } + Assert.That(testObj.ciao, Is.Not.Null); + Assert.That(testObj.ciao.GetType(), Is.EqualTo(typeof(CiaoFoo))); + Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(0)); } } diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/AutowireByQualifierTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/AutowireByQualifierTests.cs index b4ec6c5d..39eaaae1 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/AutowireByQualifierTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/AutowireByQualifierTests.cs @@ -26,62 +26,61 @@ using AutowireTestFieldNormal = Spring.Objects.Factory.Attributes.ByQualifier.Au using AutowireTestMethodNormal = Spring.Objects.Factory.Attributes.ByQualifier.AutowireTestMethodNormal; using AutowireTestPropertyNormal = Spring.Objects.Factory.Attributes.ByQualifier.AutowireTestPropertyNormal; -namespace Spring.Objects.Factory.Attributes +namespace Spring.Objects.Factory.Attributes; + +[TestFixture] +public class AutowireByQualifierTests { - [TestFixture] - public class AutowireByQualifierTests + private XmlApplicationContext _applicationContext; + + [SetUp] + public void Setup() { - private XmlApplicationContext _applicationContext; + _applicationContext = new XmlApplicationContext(false, + "assembly://Spring.Core.Tests/Spring.Objects.Factory.Attributes/ByQualifierObjects.xml"); + } - [SetUp] - public void Setup() - { - _applicationContext = new XmlApplicationContext(false, - "assembly://Spring.Core.Tests/Spring.Objects.Factory.Attributes/ByQualifierObjects.xml"); - } + [Test] + public void InjectOnField() + { + var testObj = (AutowireTestFieldNormal) _applicationContext.GetObject("AutowireTestField"); + var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestField"); - [Test] - public void InjectOnField() - { - var testObj = (AutowireTestFieldNormal) _applicationContext.GetObject("AutowireTestField"); - var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestField"); + Assert.That(testObj.ciao, Is.Not.Null); + Assert.That(testObj.ciao.GetType(), Is.EqualTo(typeof(CiaoFoo))); + Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(1)); + } - Assert.That(testObj.ciao, Is.Not.Null); - Assert.That(testObj.ciao.GetType(), Is.EqualTo(typeof(CiaoFoo))); - Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(1)); - } + [Test] + public void InjectOnProperty() + { + var testObj = (AutowireTestPropertyNormal) _applicationContext.GetObject("AutowireTestProperty"); + var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestProperty"); - [Test] - public void InjectOnProperty() - { - var testObj = (AutowireTestPropertyNormal) _applicationContext.GetObject("AutowireTestProperty"); - var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestProperty"); + Assert.That(testObj.Ciao, Is.Not.Null); + Assert.That(testObj.Ciao.GetType(), Is.EqualTo(typeof(CiaoFoo))); + Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(1)); + } - Assert.That(testObj.Ciao, Is.Not.Null); - Assert.That(testObj.Ciao.GetType(), Is.EqualTo(typeof(CiaoFoo))); - Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(1)); - } + [Test] + public void InjectOnMethod() + { + var testObj = (AutowireTestMethodNormal) _applicationContext.GetObject("AutowireTestMethod"); + var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestMethod"); - [Test] - public void InjectOnMethod() - { - var testObj = (AutowireTestMethodNormal) _applicationContext.GetObject("AutowireTestMethod"); - var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestMethod"); + Assert.That(testObj.ciao, Is.Not.Null); + Assert.That(testObj.ciao.GetType(), Is.EqualTo(typeof(CiaoFoo))); + Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(1)); + } - Assert.That(testObj.ciao, Is.Not.Null); - Assert.That(testObj.ciao.GetType(), Is.EqualTo(typeof(CiaoFoo))); - Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(1)); - } + [Test] + public void InjectOnConstructor() + { + var testObj = (AutowireTestConstructorNormal) _applicationContext.GetObject("AutowireTestConstructor"); + var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestConstructor"); - [Test] - public void InjectOnConstructor() - { - var testObj = (AutowireTestConstructorNormal)_applicationContext.GetObject("AutowireTestConstructor"); - var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestConstructor"); - - Assert.That(testObj.ciao, Is.Not.Null); - Assert.That(testObj.ciao.GetType(), Is.EqualTo(typeof(CiaoFoo))); - Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(0)); - } + Assert.That(testObj.ciao, Is.Not.Null); + Assert.That(testObj.ciao.GetType(), Is.EqualTo(typeof(CiaoFoo))); + Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(0)); } } diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/AutowireByTypeFailTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/AutowireByTypeFailTests.cs index 2fb6fbf4..ae8676bf 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/AutowireByTypeFailTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/AutowireByTypeFailTests.cs @@ -22,67 +22,66 @@ using NUnit.Framework; using Spring.Context.Support; using Spring.Objects.Factory.Attributes.ByType; -namespace Spring.Objects.Factory.Attributes +namespace Spring.Objects.Factory.Attributes; + +[TestFixture] +public class AutowireByTypeFailTests { - [TestFixture] - public class AutowireByTypeFailTests + private XmlApplicationContext _applicationContext; + + [SetUp] + public void Setup() { - private XmlApplicationContext _applicationContext; + _applicationContext = new XmlApplicationContext(false, + "assembly://Spring.Core.Tests/Spring.Objects.Factory.Attributes/ByTypeFailObjects.xml"); + } - [SetUp] - public void Setup() + [Test] + public void FailFieldInjectionTooManyObjects() + { + Exception ex = null; + try { - _applicationContext = new XmlApplicationContext(false, - "assembly://Spring.Core.Tests/Spring.Objects.Factory.Attributes/ByTypeFailObjects.xml"); + var testObj = (AutowireTestFieldNormal) _applicationContext.GetObject("AutowireTestFieldNormal"); } + catch (Exception e) { ex = e; } - [Test] - public void FailFieldInjectionTooManyObjects() + Assert.That(ex, Is.Not.Null, "Should throw an exception"); + Assert.That(ex.Message, Does.Contain("Injection of autowired dependencies failed")); + } + + [Test] + public void FailPropertyInjectionTooManyObjects() + { + Exception ex = null; + try { - Exception ex = null; - try - { - var testObj = (AutowireTestFieldNormal)_applicationContext.GetObject("AutowireTestFieldNormal"); - } - catch (Exception e) { ex = e; } - - Assert.That(ex, Is.Not.Null, "Should throw an exception"); - Assert.That(ex.Message, Does.Contain("Injection of autowired dependencies failed")); + var testObj = (AutowireTestPropertyNormal) _applicationContext.GetObject("AutowireTestPropertyNormal"); } + catch (Exception e) { ex = e; } - [Test] - public void FailPropertyInjectionTooManyObjects() + Assert.That(ex, Is.Not.Null, "Should throw an exception"); + Assert.That(ex.Message, Does.Contain("Injection of autowired dependencies failed")); + } + + [Test] + public void FailMethodInjectionTooManyObjects() + { + Exception ex = null; + try { - Exception ex = null; - try - { - var testObj = (AutowireTestPropertyNormal)_applicationContext.GetObject("AutowireTestPropertyNormal"); - } - catch (Exception e) { ex = e; } - - Assert.That(ex, Is.Not.Null, "Should throw an exception"); - Assert.That(ex.Message, Does.Contain("Injection of autowired dependencies failed")); + var testObj = (AutowireTestMethodNormal) _applicationContext.GetObject("AutowireTestMethodNormal"); } + catch (Exception e) { ex = e; } - [Test] - public void FailMethodInjectionTooManyObjects() - { - Exception ex = null; - try - { - var testObj = (AutowireTestMethodNormal)_applicationContext.GetObject("AutowireTestMethodNormal"); - } - catch (Exception e) { ex = e; } + Assert.That(ex, Is.Not.Null, "Should throw an exception"); + Assert.That(ex.Message, Does.Contain("Injection of autowired dependencies failed")); + } - Assert.That(ex, Is.Not.Null, "Should throw an exception"); - Assert.That(ex.Message, Does.Contain("Injection of autowired dependencies failed")); - } - - [Test] - public void FailConstructorInjectionTooManyObjects() - { - var ex = Assert.Throws(() => _applicationContext.GetObject("AutowireTestConstructorNormal")); - Assert.That(ex.Message, Does.Contain("Error creating object with name")); - } + [Test] + public void FailConstructorInjectionTooManyObjects() + { + var ex = Assert.Throws(() => _applicationContext.GetObject("AutowireTestConstructorNormal")); + Assert.That(ex.Message, Does.Contain("Error creating object with name")); } } diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/AutowireByTypeNormalTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/AutowireByTypeNormalTests.cs index fcba09ff..1223c748 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/AutowireByTypeNormalTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/AutowireByTypeNormalTests.cs @@ -22,58 +22,57 @@ using NUnit.Framework; using Spring.Context.Support; using Spring.Objects.Factory.Attributes.ByType; -namespace Spring.Objects.Factory.Attributes +namespace Spring.Objects.Factory.Attributes; + +[TestFixture] +public class AutowireByTypeNormalTests { - [TestFixture] - public class AutowireByTypeNormalTests + private XmlApplicationContext _applicationContext; + + [SetUp] + public void Setup() { - private XmlApplicationContext _applicationContext; + _applicationContext = new XmlApplicationContext(false, + "assembly://Spring.Core.Tests/Spring.Objects.Factory.Attributes/ByTypeNormalObjects.xml"); + } - [SetUp] - public void Setup() - { - _applicationContext = new XmlApplicationContext(false, - "assembly://Spring.Core.Tests/Spring.Objects.Factory.Attributes/ByTypeNormalObjects.xml"); - } + [Test] + public void InjectOnField() + { + var testObj = (AutowireTestFieldNormal) _applicationContext.GetObject("AutowireTestFieldNormal"); + var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestFieldNormal"); - [Test] - public void InjectOnField() - { - var testObj = (AutowireTestFieldNormal) _applicationContext.GetObject("AutowireTestFieldNormal"); - var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestFieldNormal"); + Assert.That(testObj.hello, Is.Not.Null); + Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(1)); + } - Assert.That(testObj.hello, Is.Not.Null); - Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(1)); - } + [Test] + public void InjectOnProperty() + { + var testObj = (AutowireTestPropertyNormal) _applicationContext.GetObject("AutowireTestPropertyNormal"); + var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestPropertyNormal"); - [Test] - public void InjectOnProperty() - { - var testObj = (AutowireTestPropertyNormal) _applicationContext.GetObject("AutowireTestPropertyNormal"); - var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestPropertyNormal"); + Assert.That(testObj.Hello, Is.Not.Null); + Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(1)); + } - Assert.That(testObj.Hello, Is.Not.Null); - Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(1)); - } + [Test] + public void InjectOnMethod() + { + var testObj = (AutowireTestMethodNormal) _applicationContext.GetObject("AutowireTestMethodNormal"); + var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestMethodNormal"); - [Test] - public void InjectOnMethod() - { - var testObj = (AutowireTestMethodNormal) _applicationContext.GetObject("AutowireTestMethodNormal"); - var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestMethodNormal"); + Assert.That(testObj.hello, Is.Not.Null); + Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(1)); + } - Assert.That(testObj.hello, Is.Not.Null); - Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(1)); - } + [Test] + public void InjectOnConstructor() + { + var testObj = (AutowireTestConstructorNormal) _applicationContext.GetObject("AutowireTestConstructorNormal"); + var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestConstructorNormal"); - [Test] - public void InjectOnConstructor() - { - var testObj = (AutowireTestConstructorNormal)_applicationContext.GetObject("AutowireTestConstructorNormal"); - var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestConstructorNormal"); - - Assert.That(testObj.hello, Is.Not.Null); - Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(0)); - } + Assert.That(testObj.hello, Is.Not.Null); + Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(0)); } } diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/AutowireByTypeNotRequiredTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/AutowireByTypeNotRequiredTests.cs index 60860f2d..94d250fd 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/AutowireByTypeNotRequiredTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/AutowireByTypeNotRequiredTests.cs @@ -22,48 +22,47 @@ using NUnit.Framework; using Spring.Context.Support; using Spring.Objects.Factory.Attributes.ByType; -namespace Spring.Objects.Factory.Attributes +namespace Spring.Objects.Factory.Attributes; + +[TestFixture] +public class AutowireByTypeNotRequiredTests { - [TestFixture] - public class AutowireByTypeNotRequiredTests + private XmlApplicationContext _applicationContext; + + [SetUp] + public void Setup() { - private XmlApplicationContext _applicationContext; + _applicationContext = new XmlApplicationContext(false, + "assembly://Spring.Core.Tests/Spring.Objects.Factory.Attributes/ByTypeNotRequiredObjects.xml"); + } - [SetUp] - public void Setup() - { - _applicationContext = new XmlApplicationContext(false, - "assembly://Spring.Core.Tests/Spring.Objects.Factory.Attributes/ByTypeNotRequiredObjects.xml"); - } + [Test] + public void InjectOnField() + { + var testObj = (AutowireTestFieldNotRequired) _applicationContext.GetObject("AutowireTestField"); + var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestField"); - [Test] - public void InjectOnField() - { - var testObj = (AutowireTestFieldNotRequired) _applicationContext.GetObject("AutowireTestField"); - var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestField"); + Assert.That(testObj.hello, Is.Null); + Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(0)); + } - Assert.That(testObj.hello, Is.Null); - Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(0)); - } + [Test] + public void InjectOnProperty() + { + var testObj = (AutowireTestPropertyNotRequired) _applicationContext.GetObject("AutowireTestProperty"); + var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestProperty"); - [Test] - public void InjectOnProperty() - { - var testObj = (AutowireTestPropertyNotRequired) _applicationContext.GetObject("AutowireTestProperty"); - var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestProperty"); + Assert.That(testObj.Hello, Is.Null); + Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(0)); + } - Assert.That(testObj.Hello, Is.Null); - Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(0)); - } + [Test] + public void InjectOnMethod() + { + var testObj = (AutowireTestMethodNotRequired) _applicationContext.GetObject("AutowireTestMethod"); + var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestMethod"); - [Test] - public void InjectOnMethod() - { - var testObj = (AutowireTestMethodNotRequired) _applicationContext.GetObject("AutowireTestMethod"); - var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestMethod"); - - Assert.That(testObj.hello, Is.Null); - Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(0)); - } + Assert.That(testObj.hello, Is.Null); + Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(0)); } } diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/AutowireByTypePrimaryTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/AutowireByTypePrimaryTests.cs index 314e5f9a..8482a557 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/AutowireByTypePrimaryTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/AutowireByTypePrimaryTests.cs @@ -22,58 +22,57 @@ using NUnit.Framework; using Spring.Context.Support; using Spring.Objects.Factory.Attributes.ByType; -namespace Spring.Objects.Factory.Attributes +namespace Spring.Objects.Factory.Attributes; + +[TestFixture] +public class AutowireByTypePrimaryTests { - [TestFixture] - public class AutowireByTypePrimaryTests + private XmlApplicationContext _applicationContext; + + [SetUp] + public void Setup() { - private XmlApplicationContext _applicationContext; + _applicationContext = new XmlApplicationContext(false, + "assembly://Spring.Core.Tests/Spring.Objects.Factory.Attributes/ByTypePrimaryObjects.xml"); + } - [SetUp] - public void Setup() - { - _applicationContext = new XmlApplicationContext(false, - "assembly://Spring.Core.Tests/Spring.Objects.Factory.Attributes/ByTypePrimaryObjects.xml"); - } + [Test] + public void InjectOnField() + { + var testObj = (AutowireTestFieldNormal) _applicationContext.GetObject("AutowireTestFieldNormal"); + var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestFieldNormal"); - [Test] - public void InjectOnField() - { - var testObj = (AutowireTestFieldNormal) _applicationContext.GetObject("AutowireTestFieldNormal"); - var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestFieldNormal"); + Assert.That(testObj.hello, Is.Not.Null); + Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(1)); + } - Assert.That(testObj.hello, Is.Not.Null); - Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(1)); - } + [Test] + public void InjectOnProperty() + { + var testObj = (AutowireTestPropertyNormal) _applicationContext.GetObject("AutowireTestPropertyNormal"); + var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestPropertyNormal"); - [Test] - public void InjectOnProperty() - { - var testObj = (AutowireTestPropertyNormal) _applicationContext.GetObject("AutowireTestPropertyNormal"); - var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestPropertyNormal"); + Assert.That(testObj.Hello, Is.Not.Null); + Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(1)); + } - Assert.That(testObj.Hello, Is.Not.Null); - Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(1)); - } + [Test] + public void InjectOnMethod() + { + var testObj = (AutowireTestMethodNormal) _applicationContext.GetObject("AutowireTestMethodNormal"); + var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestMethodNormal"); - [Test] - public void InjectOnMethod() - { - var testObj = (AutowireTestMethodNormal) _applicationContext.GetObject("AutowireTestMethodNormal"); - var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestMethodNormal"); + Assert.That(testObj.hello, Is.Not.Null); + Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(1)); + } - Assert.That(testObj.hello, Is.Not.Null); - Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(1)); - } + [Test] + public void InjectOnConstructor() + { + var testObj = (AutowireTestConstructorNormal) _applicationContext.GetObject("AutowireTestConstructorNormal"); + var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestConstructorNormal"); - [Test] - public void InjectOnConstructor() - { - var testObj = (AutowireTestConstructorNormal)_applicationContext.GetObject("AutowireTestConstructorNormal"); - var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestConstructorNormal"); - - Assert.That(testObj.hello, Is.Not.Null); - Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(0)); - } + Assert.That(testObj.hello, Is.Not.Null); + Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(0)); } } diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/AutowireByValueTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/AutowireByValueTests.cs index ab9cb0c6..614c98e7 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/AutowireByValueTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/AutowireByValueTests.cs @@ -19,76 +19,74 @@ #endregion using NUnit.Framework; - using Spring.Context.Support; using Spring.Objects.Factory.Attributes.ByValue; -namespace Spring.Objects.Factory.Attributes +namespace Spring.Objects.Factory.Attributes; + +[TestFixture] +public class AutowireByValueTests { - [TestFixture] - public class AutowireByValueTests + private XmlApplicationContext _applicationContext; + + [SetUp] + public void Setup() { - private XmlApplicationContext _applicationContext; + ContextRegistry.Clear(); + _applicationContext = new XmlApplicationContext(false, "assembly://Spring.Core.Tests/Spring.Objects.Factory.Attributes/ByValueObjects.xml"); + ContextRegistry.RegisterContext(_applicationContext); + } - [SetUp] - public void Setup() - { - ContextRegistry.Clear(); - _applicationContext = new XmlApplicationContext(false, "assembly://Spring.Core.Tests/Spring.Objects.Factory.Attributes/ByValueObjects.xml"); - ContextRegistry.RegisterContext(_applicationContext); - } + [TearDown] + public void Dispose() + { + ContextRegistry.Clear(); + } - [TearDown] - public void Dispose() - { - ContextRegistry.Clear(); - } + [Test] + public void InjectOnField() + { + var testObj = (AutowireTestFieldNormal) _applicationContext.GetObject("AutowireTestField"); + var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestField"); - [Test] - public void InjectOnField() - { - var testObj = (AutowireTestFieldNormal) _applicationContext.GetObject("AutowireTestField"); - var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestField"); + Assert.That(testObj.ciao, Is.Not.Null); + Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(0)); + } - Assert.That(testObj.ciao, Is.Not.Null); - Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(0)); - } + [Test] + public void InjectOnProperty() + { + var testObj = (AutowireTestPropertyNormal) _applicationContext.GetObject("AutowireTestProperty"); + var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestProperty"); - [Test] - public void InjectOnProperty() - { - var testObj = (AutowireTestPropertyNormal) _applicationContext.GetObject("AutowireTestProperty"); - var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestProperty"); + Assert.That(testObj.Ciao, Is.Not.Null); + Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(0)); + } - Assert.That(testObj.Ciao, Is.Not.Null); - Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(0)); - } + [Test] + public void InjectOnMethod() + { + var testObj = (AutowireTestMethodNormal) _applicationContext.GetObject("AutowireTestMethod"); + var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestMethod"); - [Test] - public void InjectOnMethod() - { - var testObj = (AutowireTestMethodNormal) _applicationContext.GetObject("AutowireTestMethod"); - var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestMethod"); + Assert.That(testObj.ciao, Is.Not.Null); + Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(0)); + } - Assert.That(testObj.ciao, Is.Not.Null); - Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(0)); - } + [Test] + public void InjectOnConstructor() + { + var testObj = (AutowireTestConstructorNormal) _applicationContext.GetObject("AutowireTestConstructor"); + var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestConstructor"); - [Test] - public void InjectOnConstructor() - { - var testObj = (AutowireTestConstructorNormal)_applicationContext.GetObject("AutowireTestConstructor"); - var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestConstructor"); + Assert.That(testObj.ciao, Is.Not.Null); + Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(0)); + } - Assert.That(testObj.ciao, Is.Not.Null); - Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(0)); - } - - [Test] - public void InjectPropertyPlaceholderValue() - { - var testObj = (AutowireTestPropertyPlaceHolder)_applicationContext.GetObject("AutowireTestPropertyPlaceHolder"); - Assert.That(testObj.greeting, Is.EqualTo("ciao")); - } + [Test] + public void InjectPropertyPlaceholderValue() + { + var testObj = (AutowireTestPropertyPlaceHolder) _applicationContext.GetObject("AutowireTestPropertyPlaceHolder"); + Assert.That(testObj.greeting, Is.EqualTo("ciao")); } } diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/AutowireCollectionTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/AutowireCollectionTests.cs index 6cd72745..da845c01 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/AutowireCollectionTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/AutowireCollectionTests.cs @@ -23,83 +23,82 @@ using Spring.Context.Support; using Spring.Objects.Factory.Attributes.ByType; using Spring.Objects.Factory.Attributes.Collections; -namespace Spring.Objects.Factory.Attributes +namespace Spring.Objects.Factory.Attributes; + +[TestFixture] +public class AutowireCollectionTests { - [TestFixture] - public class AutowireCollectionTests + private XmlApplicationContext _applicationContext; + + [SetUp] + public void Setup() { - private XmlApplicationContext _applicationContext; + _applicationContext = new XmlApplicationContext(false, + "assembly://Spring.Core.Tests/Spring.Objects.Factory.Attributes/CollectionObjects.xml"); + } - [SetUp] - public void Setup() + [Test] + public void InjectIntoList() + { + var testObj = (AutowireTestList) _applicationContext.GetObject("AutowireTestList"); + var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestList"); + + Assert.That(testObj.foos, Is.Not.Null); + Assert.That(testObj.foos.Count, Is.EqualTo(2)); + Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(2)); + } + + [Test] + public void InjectIntoSet() + { + var testObj = (AutowireTestSet) _applicationContext.GetObject("AutowireTestSet"); + var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestSet"); + + Assert.That(testObj.foos, Is.Not.Null); + Assert.That(testObj.foos.Count, Is.EqualTo(2)); + Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(2)); + } + + [Test] + public void InjectIntoDictionary() + { + var testObj = (AutowireTestDictionary) _applicationContext.GetObject("AutowireTestDictionary"); + var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestDictionary"); + + Assert.That(testObj.foos, Is.Not.Null); + Assert.That(testObj.foos.Count, Is.EqualTo(2)); + Assert.That(testObj.foos.ContainsKey("HelloFoo"), Is.True); + Assert.That(testObj.foos.ContainsKey("CiaoFoo"), Is.True); + Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(2)); + } + + [Test] + public void InjectIntoDictionaryFail() + { + Exception ex = null; + + try { - _applicationContext = new XmlApplicationContext(false, - "assembly://Spring.Core.Tests/Spring.Objects.Factory.Attributes/CollectionObjects.xml"); + var testObj = (AutowireTestDictionaryFail) _applicationContext.GetObject("AutowireTestDictionaryFail"); + } + catch (Exception e) + { + ex = e; } - [Test] - public void InjectIntoList() - { - var testObj = (AutowireTestList)_applicationContext.GetObject("AutowireTestList"); - var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestList"); + Assert.That(ex, Is.Not.Null); + Assert.That(ex.InnerException.InnerException.Message.Contains("first generic to be a string"), Is.True); + } - Assert.That(testObj.foos, Is.Not.Null); - Assert.That(testObj.foos.Count, Is.EqualTo(2)); - Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(2)); - } + [Test] + public void InjectIntoListWithQualifier() + { + var testObj = (AutowireTestQualifier) _applicationContext.GetObject("AutowireTestQualifier"); + var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestQualifier"); - [Test] - public void InjectIntoSet() - { - var testObj = (AutowireTestSet)_applicationContext.GetObject("AutowireTestSet"); - var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestSet"); - - Assert.That(testObj.foos, Is.Not.Null); - Assert.That(testObj.foos.Count, Is.EqualTo(2)); - Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(2)); - } - - [Test] - public void InjectIntoDictionary() - { - var testObj = (AutowireTestDictionary)_applicationContext.GetObject("AutowireTestDictionary"); - var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestDictionary"); - - Assert.That(testObj.foos, Is.Not.Null); - Assert.That(testObj.foos.Count, Is.EqualTo(2)); - Assert.That(testObj.foos.ContainsKey("HelloFoo"), Is.True); - Assert.That(testObj.foos.ContainsKey("CiaoFoo"), Is.True); - Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(2)); - } - - [Test] - public void InjectIntoDictionaryFail() - { - Exception ex = null; - - try - { - var testObj = (AutowireTestDictionaryFail)_applicationContext.GetObject("AutowireTestDictionaryFail"); - } - catch (Exception e) - { - ex = e; - } - - Assert.That(ex, Is.Not.Null); - Assert.That(ex.InnerException.InnerException.Message.Contains("first generic to be a string"), Is.True); - } - - [Test] - public void InjectIntoListWithQualifier() - { - var testObj = (AutowireTestQualifier)_applicationContext.GetObject("AutowireTestQualifier"); - var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestQualifier"); - - Assert.That(testObj.foos, Is.Not.Null); - Assert.That(testObj.foos.Count, Is.EqualTo(1)); - Assert.That(testObj.foos[0].GetType(), Is.EqualTo(typeof(CiaoFoo))); - Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(1)); - } + Assert.That(testObj.foos, Is.Not.Null); + Assert.That(testObj.foos.Count, Is.EqualTo(1)); + Assert.That(testObj.foos[0].GetType(), Is.EqualTo(typeof(CiaoFoo))); + Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(1)); } } diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/AutowireTestObjects.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/AutowireTestObjects.cs index fd1aca20..06924ec1 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/AutowireTestObjects.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/AutowireTestObjects.cs @@ -25,14 +25,12 @@ namespace Spring.Objects.Factory.Attributes.ByType public class AutowireTestFieldNormal { - [Autowired] - public IFoo hello; + [Autowired] public IFoo hello; } public class AutowireTestPropertyNormal { - [Autowired] - public IFoo Hello { get; set; } + [Autowired] public IFoo Hello { get; set; } } public class AutowireTestMethodNormal @@ -59,14 +57,12 @@ namespace Spring.Objects.Factory.Attributes.ByType public class AutowireTestFieldNotRequired { - [Autowired(Required = false)] - public IFoo hello; + [Autowired(Required = false)] public IFoo hello; } public class AutowireTestPropertyNotRequired { - [Autowired(Required = false)] - public IFoo Hello { get; set; } + [Autowired(Required = false)] public IFoo Hello { get; set; } } public class AutowireTestMethodNotRequired @@ -79,23 +75,18 @@ namespace Spring.Objects.Factory.Attributes.ByType this.hello = hello; } } - } namespace Spring.Objects.Factory.Attributes.ByQualifier { public class AutowireTestFieldNormal { - [Autowired] - [Qualifier("ciao")] - public IFoo ciao; + [Autowired] [Qualifier("ciao")] public IFoo ciao; } public class AutowireTestPropertyNormal { - [Autowired] - [Qualifier("ciao")] - public IFoo Ciao { get; set; } + [Autowired] [Qualifier("ciao")] public IFoo Ciao { get; set; } } public class AutowireTestMethodNormal @@ -132,8 +123,7 @@ namespace Spring.Objects.Factory.Attributes.ByQualifierAttribute public class AutowireTestFieldNormal { - [Autowired] - [Dialect(Language = "Italian")] + [Autowired] [Dialect(Language = "Italian")] public IFoo ciao; } @@ -171,14 +161,12 @@ namespace Spring.Objects.Factory.Attributes.ByValue { public class AutowireTestFieldNormal { - [Value("@(CiaoFoo)")] - public IFoo ciao; + [Value("@(CiaoFoo)")] public IFoo ciao; } public class AutowireTestPropertyNormal { - [Value("@(CiaoFoo)")] - public IFoo Ciao { get; set; } + [Value("@(CiaoFoo)")] public IFoo Ciao { get; set; } } public class AutowireTestMethodNormal @@ -205,44 +193,34 @@ namespace Spring.Objects.Factory.Attributes.ByValue public class AutowireTestPropertyPlaceHolder { - [Value("${greeting}")] - public string greeting; + [Value("${greeting}")] public string greeting; } - } namespace Spring.Objects.Factory.Attributes.Collections { public class AutowireTestList { - [Autowired] - public IList foos; + [Autowired] public IList foos; } - + public class AutowireTestSet { - [Autowired] - public Spring.Collections.Generic.ISet foos; + [Autowired] public Spring.Collections.Generic.ISet foos; } public class AutowireTestDictionary { - [Autowired] - public IDictionary foos; + [Autowired] public IDictionary foos; } public class AutowireTestDictionaryFail { - [Autowired] - public IDictionary foos; + [Autowired] public IDictionary foos; } public class AutowireTestQualifier { - [Autowired] - [Qualifier("ciao")] - public IList foos; + [Autowired] [Qualifier("ciao")] public IList foos; } - - -} \ No newline at end of file +} diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/ByQualifierAttributeObjects.xml b/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/ByQualifierAttributeObjects.xml index 74b98ba6..88f19020 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/ByQualifierAttributeObjects.xml +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/ByQualifierAttributeObjects.xml @@ -1,36 +1,36 @@ - - - - - - - + - - - - - + + + + + - + + + + + - + - + - + + + diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/ByQualifierObjects.xml b/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/ByQualifierObjects.xml index 43de7378..7f49f4b3 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/ByQualifierObjects.xml +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/ByQualifierObjects.xml @@ -1,32 +1,32 @@ - - - - - + - - - + + + - + + + - + - + - + + + diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/ByTypeFailObjects.xml b/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/ByTypeFailObjects.xml index db5c0fe1..bdf0b5d1 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/ByTypeFailObjects.xml +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/ByTypeFailObjects.xml @@ -1,28 +1,28 @@ - - - + - + - + - + - + - + + + diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/ByTypeNormalObjects.xml b/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/ByTypeNormalObjects.xml index dfa67481..f60dbb0d 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/ByTypeNormalObjects.xml +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/ByTypeNormalObjects.xml @@ -1,25 +1,25 @@ - - - + - + - + - + - + + + diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/ByTypeNotRequiredObjects.xml b/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/ByTypeNotRequiredObjects.xml index 4dfff1e7..214e9ee5 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/ByTypeNotRequiredObjects.xml +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/ByTypeNotRequiredObjects.xml @@ -1,18 +1,18 @@ - - - + - + - + + + diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/ByTypePrimaryObjects.xml b/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/ByTypePrimaryObjects.xml index d30bd950..226fde02 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/ByTypePrimaryObjects.xml +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/ByTypePrimaryObjects.xml @@ -1,29 +1,29 @@ - - - + - + - + - + - + - + + + diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/ByValueObjects.config b/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/ByValueObjects.config index a8034dac..6191fcf4 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/ByValueObjects.config +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/ByValueObjects.config @@ -3,13 +3,13 @@ -
+
-
+
- + diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/ByValueObjects.xml b/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/ByValueObjects.xml index 49e7d6e6..fb8f1d04 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/ByValueObjects.xml +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/ByValueObjects.xml @@ -1,37 +1,38 @@ - - - - - - + + + + - + - + - + - + - + - + - + + + diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/CollectionObjects.xml b/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/CollectionObjects.xml index 8623f311..d3cbf6d9 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/CollectionObjects.xml +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/CollectionObjects.xml @@ -1,36 +1,36 @@ - - - - - + - - - + + + - + + + - + - + - + - + + + diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/MyRequiredAttribute.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/MyRequiredAttribute.cs index 7892d5a1..e65ca70e 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/MyRequiredAttribute.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/MyRequiredAttribute.cs @@ -18,15 +18,13 @@ #endregion -namespace Spring.Objects.Factory.Attributes +namespace Spring.Objects.Factory.Attributes; + +/// +/// Custom attribute to indicate required setter property +/// +/// Mark Pollack +[AttributeUsage(AttributeTargets.Property)] +public class MyRequiredAttribute : Attribute { - /// - /// Custom attribute to indicate required setter property - /// - /// Mark Pollack - [AttributeUsage(AttributeTargets.Property)] - public class MyRequiredAttribute : Attribute - { - - } -} \ No newline at end of file +} diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/PostConstructAttributeTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/PostConstructAttributeTests.cs index b94c67ad..10cfa8bb 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/PostConstructAttributeTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/PostConstructAttributeTests.cs @@ -23,156 +23,149 @@ using Spring.Context.Support; using Spring.Objects.Factory.Config; using Spring.Objects.Factory.Support; -namespace Spring.Objects.Factory.Attributes +namespace Spring.Objects.Factory.Attributes; + +[TestFixture] +public class PostConstructAttributeTests { - [TestFixture] - public class PostConstructAttributeTests + private GenericApplicationContext _applicationContext; + + [SetUp] + public void Setup() { - private GenericApplicationContext _applicationContext; - + _applicationContext = new GenericApplicationContext(); - [SetUp] - public void Setup() - { - _applicationContext = new GenericApplicationContext(); + var objDef = new RootObjectDefinition(typeof(InitDestroyAttributeObjectPostProcessor)); + objDef.Role = ObjectRole.ROLE_INFRASTRUCTURE; + _applicationContext.ObjectFactory.RegisterObjectDefinition("InitDestroyAttributeObjectPostProcessor", objDef); - var objDef = new RootObjectDefinition(typeof (InitDestroyAttributeObjectPostProcessor)); - objDef.Role = ObjectRole.ROLE_INFRASTRUCTURE; - _applicationContext.ObjectFactory.RegisterObjectDefinition("InitDestroyAttributeObjectPostProcessor", objDef); + objDef = new RootObjectDefinition(typeof(PostContructTestObject1)); + _applicationContext.ObjectFactory.RegisterObjectDefinition("PostContructTestObject1", objDef); - objDef = new RootObjectDefinition(typeof(PostContructTestObject1)); - _applicationContext.ObjectFactory.RegisterObjectDefinition("PostContructTestObject1", objDef); + objDef = new RootObjectDefinition(typeof(PostContructTestObject2)); + _applicationContext.ObjectFactory.RegisterObjectDefinition("PostContructTestObject2", objDef); - objDef = new RootObjectDefinition(typeof(PostContructTestObject2)); - _applicationContext.ObjectFactory.RegisterObjectDefinition("PostContructTestObject2", objDef); - - objDef = new RootObjectDefinition(typeof(PostContructTestObject3)); - _applicationContext.ObjectFactory.RegisterObjectDefinition("PostContructTestObject3", objDef); + objDef = new RootObjectDefinition(typeof(PostContructTestObject3)); + _applicationContext.ObjectFactory.RegisterObjectDefinition("PostContructTestObject3", objDef); - objDef = new RootObjectDefinition(typeof(PostContructTestObject4)); - objDef.Scope = "prototype"; - _applicationContext.ObjectFactory.RegisterObjectDefinition("PostContructTestObject4", objDef); + objDef = new RootObjectDefinition(typeof(PostContructTestObject4)); + objDef.Scope = "prototype"; + _applicationContext.ObjectFactory.RegisterObjectDefinition("PostContructTestObject4", objDef); - objDef = new RootObjectDefinition(typeof(PostContructTestObject5)); - _applicationContext.ObjectFactory.RegisterObjectDefinition("PostContructTestObject5", objDef); + objDef = new RootObjectDefinition(typeof(PostContructTestObject5)); + _applicationContext.ObjectFactory.RegisterObjectDefinition("PostContructTestObject5", objDef); - objDef = new RootObjectDefinition(typeof(PostContructTestObject1)); - objDef.InitMethodName = "Init1"; - _applicationContext.ObjectFactory.RegisterObjectDefinition("PostContructTestObject6", objDef); + objDef = new RootObjectDefinition(typeof(PostContructTestObject1)); + objDef.InitMethodName = "Init1"; + _applicationContext.ObjectFactory.RegisterObjectDefinition("PostContructTestObject6", objDef); - _applicationContext.Refresh(); - } - - - [Test] - public void PostContructMethodExecuted() - { - var testObj = (PostContructTestObject1)_applicationContext.GetObject("PostContructTestObject1"); - - Assert.That(testObj.InitCalled, Is.EqualTo(1)); - } - - [Test] - public void ExecutedInCorrectOrder() - { - var testObj = (PostContructTestObject2)_applicationContext.GetObject("PostContructTestObject2"); - - Assert.That(testObj.InitCalled, Is.EqualTo(2), "Two PostContruct methods defined, need to have two method calls."); - Assert.That(testObj.CalledAfter, Is.True, "Order of PostConstruct not followed."); - } - - [Test] - public void NoExceptionIfMethodHasReturnValue() - { - var testObj = (PostContructTestObject3)_applicationContext.GetObject("PostContructTestObject3"); - - Assert.That(testObj.InitCalled, Is.EqualTo(1), "A PostContruct method with return value should run the init method."); - } - - [Test] - public void WithArgumentMustThrowException() - { - Assert.That(() => { _applicationContext.GetObject("PostContructTestObject4"); }, Throws.Exception.TypeOf()); - } - - [Test] - public void AttributeOnbaseTypeMethod() - { - var testObj = (PostContructTestObject5)_applicationContext.GetObject("PostContructTestObject5"); - - Assert.That(testObj.InitCalled, Is.EqualTo(1)); - } - - [Test] - public void SameMethodDefinedInXml() - { - var testObj = (PostContructTestObject1)_applicationContext.GetObject("PostContructTestObject6"); - - Assert.That(testObj.InitCalled, Is.EqualTo(1)); - } + _applicationContext.Refresh(); } - - public class PostContructTestObject1 + [Test] + public void PostContructMethodExecuted() { - public int InitCalled { get; set; } + var testObj = (PostContructTestObject1) _applicationContext.GetObject("PostContructTestObject1"); - [PostConstruct] - public void Init1() - { - InitCalled++; - } + Assert.That(testObj.InitCalled, Is.EqualTo(1)); } - public class PostContructTestObject2 + [Test] + public void ExecutedInCorrectOrder() { - public int InitCalled { get; set; } - public bool Init1Called { get; set; } - public bool CalledAfter { get; set; } + var testObj = (PostContructTestObject2) _applicationContext.GetObject("PostContructTestObject2"); - [PostConstruct(Order = 1)] - public void Init1() - { - InitCalled++; - Init1Called = true; - } - - [PostConstruct(Order = 2)] - public void Init2() - { - InitCalled++; - if (Init1Called) - CalledAfter = true; - } + Assert.That(testObj.InitCalled, Is.EqualTo(2), "Two PostContruct methods defined, need to have two method calls."); + Assert.That(testObj.CalledAfter, Is.True, "Order of PostConstruct not followed."); } - public class PostContructTestObject3 + [Test] + public void NoExceptionIfMethodHasReturnValue() { - public int InitCalled { get; set; } + var testObj = (PostContructTestObject3) _applicationContext.GetObject("PostContructTestObject3"); - [PostConstruct] - private bool Init1() - { - InitCalled++; - return true; - } + Assert.That(testObj.InitCalled, Is.EqualTo(1), "A PostContruct method with return value should run the init method."); } - public class PostContructTestObject4 + [Test] + public void WithArgumentMustThrowException() { - public int InitCalled { get; set; } - - [PostConstruct] - private void Init1(bool enabled) - { - InitCalled++; - } + Assert.That(() => { _applicationContext.GetObject("PostContructTestObject4"); }, Throws.Exception.TypeOf()); } - public class PostContructTestObject5 : PostContructTestObject1 + [Test] + public void AttributeOnbaseTypeMethod() { + var testObj = (PostContructTestObject5) _applicationContext.GetObject("PostContructTestObject5"); + Assert.That(testObj.InitCalled, Is.EqualTo(1)); } + [Test] + public void SameMethodDefinedInXml() + { + var testObj = (PostContructTestObject1) _applicationContext.GetObject("PostContructTestObject6"); + Assert.That(testObj.InitCalled, Is.EqualTo(1)); + } +} + +public class PostContructTestObject1 +{ + public int InitCalled { get; set; } + + [PostConstruct] + public void Init1() + { + InitCalled++; + } +} + +public class PostContructTestObject2 +{ + public int InitCalled { get; set; } + public bool Init1Called { get; set; } + public bool CalledAfter { get; set; } + + [PostConstruct(Order = 1)] + public void Init1() + { + InitCalled++; + Init1Called = true; + } + + [PostConstruct(Order = 2)] + public void Init2() + { + InitCalled++; + if (Init1Called) + CalledAfter = true; + } +} + +public class PostContructTestObject3 +{ + public int InitCalled { get; set; } + + [PostConstruct] + private bool Init1() + { + InitCalled++; + return true; + } +} + +public class PostContructTestObject4 +{ + public int InitCalled { get; set; } + + [PostConstruct] + private void Init1(bool enabled) + { + InitCalled++; + } +} + +public class PostContructTestObject5 : PostContructTestObject1 +{ } diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/PreDestroyAttributeTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/PreDestroyAttributeTests.cs index 656c0206..edc999eb 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/PreDestroyAttributeTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/PreDestroyAttributeTests.cs @@ -23,169 +23,166 @@ using Spring.Context.Support; using Spring.Objects.Factory.Config; using Spring.Objects.Factory.Support; -namespace Spring.Objects.Factory.Attributes +namespace Spring.Objects.Factory.Attributes; + +[TestFixture] +public class PreDestroyAttributeTests { - [TestFixture] - public class PreDestroyAttributeTests + private GenericApplicationContext _applicationContext; + + [SetUp] + public void Setup() { - private GenericApplicationContext _applicationContext; + _applicationContext = new GenericApplicationContext(); + var objDef = new RootObjectDefinition(typeof(InitDestroyAttributeObjectPostProcessor)); + objDef.Role = ObjectRole.ROLE_INFRASTRUCTURE; + _applicationContext.ObjectFactory.RegisterObjectDefinition("InitDestroyAttributeObjectPostProcessor", objDef); - [SetUp] - public void Setup() - { - _applicationContext = new GenericApplicationContext(); + objDef = new RootObjectDefinition(typeof(PreDestroyTestObject1)); + _applicationContext.ObjectFactory.RegisterObjectDefinition("PreDestroyTestObject1", objDef); - var objDef = new RootObjectDefinition(typeof(InitDestroyAttributeObjectPostProcessor)); - objDef.Role = ObjectRole.ROLE_INFRASTRUCTURE; - _applicationContext.ObjectFactory.RegisterObjectDefinition("InitDestroyAttributeObjectPostProcessor", objDef); + objDef = new RootObjectDefinition(typeof(PreDestroyTestObject2)); + _applicationContext.ObjectFactory.RegisterObjectDefinition("PreDestroyTestObject2", objDef); - objDef = new RootObjectDefinition(typeof(PreDestroyTestObject1)); - _applicationContext.ObjectFactory.RegisterObjectDefinition("PreDestroyTestObject1", objDef); + objDef = new RootObjectDefinition(typeof(PreDestroyTestObject3)); + objDef.DestroyMethodName = "Destroy"; + _applicationContext.ObjectFactory.RegisterObjectDefinition("PreDestroyTestObject3", objDef); - objDef = new RootObjectDefinition(typeof(PreDestroyTestObject2)); - _applicationContext.ObjectFactory.RegisterObjectDefinition("PreDestroyTestObject2", objDef); + objDef = new RootObjectDefinition(typeof(PreDestroyTestObject4)); + _applicationContext.ObjectFactory.RegisterObjectDefinition("PreDestroyTestObject4", objDef); - objDef = new RootObjectDefinition(typeof(PreDestroyTestObject3)); - objDef.DestroyMethodName = "Destroy"; - _applicationContext.ObjectFactory.RegisterObjectDefinition("PreDestroyTestObject3", objDef); + objDef = new RootObjectDefinition(typeof(PreDestroyTestObject5)); + _applicationContext.ObjectFactory.RegisterObjectDefinition("PreDestroyTestObject5", objDef); - objDef = new RootObjectDefinition(typeof(PreDestroyTestObject4)); - _applicationContext.ObjectFactory.RegisterObjectDefinition("PreDestroyTestObject4", objDef); + _applicationContext.Refresh(); + } - objDef = new RootObjectDefinition(typeof(PreDestroyTestObject5)); - _applicationContext.ObjectFactory.RegisterObjectDefinition("PreDestroyTestObject5", objDef); + [Test] + public void PreDestroyMethodExecution() + { + DestroyTester.ExecutionCount1 = 0; + var testObj = _applicationContext.GetObject("PreDestroyTestObject1"); + _applicationContext.Dispose(); - _applicationContext.Refresh(); - } + Assert.That(DestroyTester.ExecutionCount1, Is.EqualTo(1)); + } - [Test] - public void PreDestroyMethodExecution() - { - DestroyTester.ExecutionCount1 = 0; - var testObj = _applicationContext.GetObject("PreDestroyTestObject1"); - _applicationContext.Dispose(); + [Test] + public void PreDestroyInBaseType() + { + DestroyTester.ExecutionCount2 = 0; + var testObj = _applicationContext.GetObject("PreDestroyTestObject2"); + _applicationContext.Dispose(); - Assert.That(DestroyTester.ExecutionCount1, Is.EqualTo(1)); - } + Assert.That(DestroyTester.ExecutionCount2, Is.EqualTo(1)); + } - [Test] - public void PreDestroyInBaseType() - { - DestroyTester.ExecutionCount2 = 0; - var testObj = _applicationContext.GetObject("PreDestroyTestObject2"); - _applicationContext.Dispose(); + [Test] + public void SameMethodDefinedInXml() + { + DestroyTester.ExecutionCount3 = 0; + var testObj = _applicationContext.GetObject("PreDestroyTestObject3"); + _applicationContext.Dispose(); - Assert.That(DestroyTester.ExecutionCount2, Is.EqualTo(1)); - } + Assert.That(DestroyTester.ExecutionCount3, Is.EqualTo(1)); + } - [Test] - public void SameMethodDefinedInXml() - { - DestroyTester.ExecutionCount3 = 0; - var testObj = _applicationContext.GetObject("PreDestroyTestObject3"); - _applicationContext.Dispose(); + [Test] + public void InCorrectOrder() + { + DestroyTester.ExecutionCount4 = 0; + var testObj = (PreDestroyTestObject4) _applicationContext.GetObject("PreDestroyTestObject4"); + _applicationContext.Dispose(); - Assert.That(DestroyTester.ExecutionCount3, Is.EqualTo(1)); - } + Assert.That(DestroyTester.ExecutionCount4, Is.EqualTo(2)); + Assert.That(DestroyTester.CorrectOrder, Is.True); + } - [Test] - public void InCorrectOrder() - { - DestroyTester.ExecutionCount4 = 0; - var testObj = (PreDestroyTestObject4)_applicationContext.GetObject("PreDestroyTestObject4"); - _applicationContext.Dispose(); - - Assert.That(DestroyTester.ExecutionCount4, Is.EqualTo(2)); - Assert.That(DestroyTester.CorrectOrder, Is.True); - } - - [Test] - public void WithArgumentMustThrowException() - { - Assert.That(() => + [Test] + public void WithArgumentMustThrowException() + { + Assert.That(() => { DestroyTester.ExecutionCount5 = 0; - var testObj = (PreDestroyTestObject5)_applicationContext.GetObject("PreDestroyTestObject5"); + var testObj = (PreDestroyTestObject5) _applicationContext.GetObject("PreDestroyTestObject5"); _applicationContext.Dispose(); }, - Throws.Nothing); - } - } - - public class PreDestroyTestObject1 - { - [PreDestroy] - public void Destroy() - { - DestroyTester.ExecutionCount1++; - } - } - - public class PreDestroyBase - { - [PreDestroy] - public void Destroy() - { - DestroyTester.ExecutionCount2++; - } - } - - public class PreDestroyTestObject2 : PreDestroyBase - { - } - - public class PreDestroyTestObject3 - { - [PreDestroy] - public void Destroy() - { - DestroyTester.ExecutionCount3++; - } - } - - public class PreDestroyTestObject4 - { - public PreDestroyTestObject4() - { - DestroyTester.Destroy1Called = false; - DestroyTester.CorrectOrder = false; - } - - [PreDestroy(Order = 1)] - public void Destroy1() - { - DestroyTester.ExecutionCount4++; - DestroyTester.Destroy1Called = true; - } - - [PreDestroy(Order = 2)] - public void Destroy2() - { - DestroyTester.ExecutionCount4++; - if (DestroyTester.Destroy1Called) - DestroyTester.CorrectOrder = true; - } - } - - public class PreDestroyTestObject5 - { - [PreDestroy] - public void Destroy(bool arugment) - { - DestroyTester.ExecutionCount5++; - } - } - - - public static class DestroyTester - { - public static int ExecutionCount1 { get; set; } - public static int ExecutionCount2 { get; set; } - public static int ExecutionCount3 { get; set; } - public static int ExecutionCount4 { get; set; } - public static int ExecutionCount5 { get; set; } - public static bool Destroy1Called { get; set; } - public static bool CorrectOrder { get; set; } + Throws.Nothing); } } + +public class PreDestroyTestObject1 +{ + [PreDestroy] + public void Destroy() + { + DestroyTester.ExecutionCount1++; + } +} + +public class PreDestroyBase +{ + [PreDestroy] + public void Destroy() + { + DestroyTester.ExecutionCount2++; + } +} + +public class PreDestroyTestObject2 : PreDestroyBase +{ +} + +public class PreDestroyTestObject3 +{ + [PreDestroy] + public void Destroy() + { + DestroyTester.ExecutionCount3++; + } +} + +public class PreDestroyTestObject4 +{ + public PreDestroyTestObject4() + { + DestroyTester.Destroy1Called = false; + DestroyTester.CorrectOrder = false; + } + + [PreDestroy(Order = 1)] + public void Destroy1() + { + DestroyTester.ExecutionCount4++; + DestroyTester.Destroy1Called = true; + } + + [PreDestroy(Order = 2)] + public void Destroy2() + { + DestroyTester.ExecutionCount4++; + if (DestroyTester.Destroy1Called) + DestroyTester.CorrectOrder = true; + } +} + +public class PreDestroyTestObject5 +{ + [PreDestroy] + public void Destroy(bool arugment) + { + DestroyTester.ExecutionCount5++; + } +} + +public static class DestroyTester +{ + public static int ExecutionCount1 { get; set; } + public static int ExecutionCount2 { get; set; } + public static int ExecutionCount3 { get; set; } + public static int ExecutionCount4 { get; set; } + public static int ExecutionCount5 { get; set; } + public static bool Destroy1Called { get; set; } + public static bool CorrectOrder { get; set; } +} diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/RequiredAttributeObjectPostProcessorTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/RequiredAttributeObjectPostProcessorTests.cs index cacee607..8a41f09f 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/RequiredAttributeObjectPostProcessorTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/RequiredAttributeObjectPostProcessorTests.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -26,103 +26,100 @@ using Spring.Context.Support; #endregion -namespace Spring.Objects.Factory.Attributes +namespace Spring.Objects.Factory.Attributes; + +/// +/// This class contains tests for RequiredAttributeObjectPostProcessor. +/// +/// Mark Pollack +[TestFixture] +public class RequiredAttributeObjectPostProcessorTests { - /// - /// This class contains tests for RequiredAttributeObjectPostProcessor. - /// - /// Mark Pollack - [TestFixture] - public class RequiredAttributeObjectPostProcessorTests + [SetUp] + public void Setup() { - [SetUp] - public void Setup() - { - } + } - [Test] - public void WithRequiredPropertyOmitted() - { - try - { - XmlApplicationContext ctx = - new XmlApplicationContext(false, - "assembly://Spring.Core.Tests/Spring.Objects.Factory.Attributes/RequiredWithOneRequiredPropertyOmitted.xml"); - Assert.Fail("Should have thrown ObjectCreationException"); - } - catch (ObjectCreationException ex) - { - string message = ex.InnerException.Message; - Assert.IsTrue(message.IndexOf("Property") > -1); - Assert.IsTrue(message.IndexOf("Age") > -1); - Assert.IsTrue(message.IndexOf("testObject") > -1); - } - } - - [Test] - public void WithThreeRequiredPropertiesOmitted() - { - try - { - XmlApplicationContext ctx = - new XmlApplicationContext(false, - "assembly://Spring.Core.Tests/Spring.Objects.Factory.Attributes/RequiredWithThreeRequiredPropertiesOmitted.xml"); - Assert.Fail("Should have thrown ObjectCreationException"); - } - catch (ObjectCreationException ex) - { - string message = ex.InnerException.Message; - Assert.IsTrue(message.IndexOf("Properties") > -1); - Assert.IsTrue(message.IndexOf("Age") > -1); - Assert.IsTrue(message.IndexOf("FavoriteColor") > -1); - Assert.IsTrue(message.IndexOf("JobTitle") > -1); - Assert.IsTrue(message.IndexOf("testObject") > -1); - } - } - - [Test] - public void WithOnlyRequiredPropertiesSpecified() + [Test] + public void WithRequiredPropertyOmitted() + { + try { XmlApplicationContext ctx = - new XmlApplicationContext(false, - "assembly://Spring.Core.Tests/Spring.Objects.Factory.Attributes/RequiredWithAllRequiredPropertiesProvided.xml"); - RequiredTestObject to = (RequiredTestObject) ctx.GetObject("testObject"); - Assert.AreEqual(24, to.Age); - Assert.AreEqual("Blue", to.GetFavoriteColor()); + new XmlApplicationContext(false, + "assembly://Spring.Core.Tests/Spring.Objects.Factory.Attributes/RequiredWithOneRequiredPropertyOmitted.xml"); + Assert.Fail("Should have thrown ObjectCreationException"); } - - [Test] - public void Reflection() + catch (ObjectCreationException ex) { - foreach (PropertyInfo pi in typeof(RequiredTestObject).GetProperties(BindingFlags.Instance | BindingFlags.Public)) - { - if (pi.Name.Equals("Age")) - { - object[] attribs = pi.GetCustomAttributes(typeof (RequiredAttribute), true); - Assert.Greater(attribs.Length, 0); - } - } - + string message = ex.InnerException.Message; + Assert.IsTrue(message.IndexOf("Property") > -1); + Assert.IsTrue(message.IndexOf("Age") > -1); + Assert.IsTrue(message.IndexOf("testObject") > -1); } - - [Test] - public void WithCustomAttribute() - { - try - { - XmlApplicationContext ctx = - new XmlApplicationContext(false, - "assembly://Spring.Core.Tests/Spring.Objects.Factory.Attributes/RequiredWithCustomAttribute.xml"); - Assert.Fail("Should have thrown ObjectCreationException"); - } - catch (ObjectCreationException ex) - { - string message = ex.InnerException.Message; - Assert.IsTrue(message.IndexOf("Property") > -1); - Assert.IsTrue(message.IndexOf("Name") > -1); - Assert.IsTrue(message.IndexOf("testObject") > -1); - } - } - } -} \ No newline at end of file + + [Test] + public void WithThreeRequiredPropertiesOmitted() + { + try + { + XmlApplicationContext ctx = + new XmlApplicationContext(false, + "assembly://Spring.Core.Tests/Spring.Objects.Factory.Attributes/RequiredWithThreeRequiredPropertiesOmitted.xml"); + Assert.Fail("Should have thrown ObjectCreationException"); + } + catch (ObjectCreationException ex) + { + string message = ex.InnerException.Message; + Assert.IsTrue(message.IndexOf("Properties") > -1); + Assert.IsTrue(message.IndexOf("Age") > -1); + Assert.IsTrue(message.IndexOf("FavoriteColor") > -1); + Assert.IsTrue(message.IndexOf("JobTitle") > -1); + Assert.IsTrue(message.IndexOf("testObject") > -1); + } + } + + [Test] + public void WithOnlyRequiredPropertiesSpecified() + { + XmlApplicationContext ctx = + new XmlApplicationContext(false, + "assembly://Spring.Core.Tests/Spring.Objects.Factory.Attributes/RequiredWithAllRequiredPropertiesProvided.xml"); + RequiredTestObject to = (RequiredTestObject) ctx.GetObject("testObject"); + Assert.AreEqual(24, to.Age); + Assert.AreEqual("Blue", to.GetFavoriteColor()); + } + + [Test] + public void Reflection() + { + foreach (PropertyInfo pi in typeof(RequiredTestObject).GetProperties(BindingFlags.Instance | BindingFlags.Public)) + { + if (pi.Name.Equals("Age")) + { + object[] attribs = pi.GetCustomAttributes(typeof(RequiredAttribute), true); + Assert.Greater(attribs.Length, 0); + } + } + } + + [Test] + public void WithCustomAttribute() + { + try + { + XmlApplicationContext ctx = + new XmlApplicationContext(false, + "assembly://Spring.Core.Tests/Spring.Objects.Factory.Attributes/RequiredWithCustomAttribute.xml"); + Assert.Fail("Should have thrown ObjectCreationException"); + } + catch (ObjectCreationException ex) + { + string message = ex.InnerException.Message; + Assert.IsTrue(message.IndexOf("Property") > -1); + Assert.IsTrue(message.IndexOf("Name") > -1); + Assert.IsTrue(message.IndexOf("testObject") > -1); + } + } +} diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/RequiredTestObject.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/RequiredTestObject.cs index ebb31b0f..3683b222 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/RequiredTestObject.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/RequiredTestObject.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -18,66 +18,63 @@ #endregion +namespace Spring.Objects.Factory.Attributes; -namespace Spring.Objects.Factory.Attributes +/// +/// Test object for testing 'required' attribute functionality. +/// +/// Mark Pollack +public class RequiredTestObject : IObjectNameAware, IObjectFactoryAware { - /// - /// Test object for testing 'required' attribute functionality. - /// - /// Mark Pollack - public class RequiredTestObject : IObjectNameAware, IObjectFactoryAware + private string name; + + private int age; + + private string favoriteColor; + + private string jobTitle; + + [Required] + public int Age { - private string name; - - private int age; - - private string favoriteColor; - - private string jobTitle; - - [Required] - public int Age - { - get { return age; } - set { age = value; } - } - - [MyRequired] - public string Name - { - get { return name; } - set { name = value; } - } - - - [Required] - public string FavoriteColor - { - set { favoriteColor = value; } - } - - public string GetFavoriteColor() - { - return favoriteColor; - } - - [Required] - public string JobTitle - { - get { return jobTitle; } - set { jobTitle = value; } - } - - [Required] - public string ObjectName - { - set { } - } - - [Required] - public IObjectFactory ObjectFactory - { - set { } - } + get { return age; } + set { age = value; } } -} \ No newline at end of file + + [MyRequired] + public string Name + { + get { return name; } + set { name = value; } + } + + [Required] + public string FavoriteColor + { + set { favoriteColor = value; } + } + + public string GetFavoriteColor() + { + return favoriteColor; + } + + [Required] + public string JobTitle + { + get { return jobTitle; } + set { jobTitle = value; } + } + + [Required] + public string ObjectName + { + set { } + } + + [Required] + public IObjectFactory ObjectFactory + { + set { } + } +} diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/RequiredWithAllRequiredPropertiesProvided.xml b/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/RequiredWithAllRequiredPropertiesProvided.xml index 78138a6e..b732c953 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/RequiredWithAllRequiredPropertiesProvided.xml +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/RequiredWithAllRequiredPropertiesProvided.xml @@ -1,12 +1,12 @@  - + - + - - - - - + + + + + diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/RequiredWithCustomAttribute.xml b/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/RequiredWithCustomAttribute.xml index d1f311a5..758ed4b9 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/RequiredWithCustomAttribute.xml +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/RequiredWithCustomAttribute.xml @@ -1,11 +1,12 @@  - + - - - + + + - + diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/RequiredWithOneRequiredPropertyOmitted.xml b/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/RequiredWithOneRequiredPropertyOmitted.xml index b7206973..b6a7a557 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/RequiredWithOneRequiredPropertyOmitted.xml +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/RequiredWithOneRequiredPropertyOmitted.xml @@ -1,12 +1,12 @@  - + - + - - - - - + + + + + diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/RequiredWithThreeRequiredPropertiesOmitted.xml b/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/RequiredWithThreeRequiredPropertiesOmitted.xml index 3ae41a51..f204b990 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/RequiredWithThreeRequiredPropertiesOmitted.xml +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Attributes/RequiredWithThreeRequiredPropertiesOmitted.xml @@ -1,10 +1,10 @@  - + - + - - - + + + diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/ConcurrentObjectFactoryTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/ConcurrentObjectFactoryTests.cs index dff9fba3..0a8be595 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/ConcurrentObjectFactoryTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/ConcurrentObjectFactoryTests.cs @@ -23,83 +23,78 @@ using Spring.Core.IO; using Spring.Objects.Factory.Xml; using Spring.Threading; -namespace Spring.Objects.Factory +namespace Spring.Objects.Factory; + +[TestFixture] +public class ConcurrentObjectFactoryTests { - [TestFixture] - public class ConcurrentObjectFactoryTests + private IObjectFactory factory; + + private DateTime date1 = DateTime.Parse("2004/08/08"); + + private DateTime date2 = DateTime.Parse("2000/02/02"); + + [SetUp] + public void SetUp() { - private IObjectFactory factory; + IResource resource = new ReadOnlyXmlTestResource("concurrent.xml", GetType()); + factory = new XmlObjectFactory(resource); + } - private DateTime date1 = DateTime.Parse("2004/08/08"); - - private DateTime date2 = DateTime.Parse("2000/02/02"); - - [SetUp] - public void SetUp() + [Test] + public void SingleThread() + { + for (int i = 0; i < 100; i++) { - IResource resource = new ReadOnlyXmlTestResource("concurrent.xml", GetType()); - factory = new XmlObjectFactory(resource); - } - - [Test] - public void SingleThread() - { - for (int i = 0; i < 100; i++) - { - PerformTest(); - } - } - - [Test] - public void Concurrent() - { - AsyncTestTask t1 = new ObjectFactoryTask(500, this).Start(); - - t1.AssertNoException(); - - } - - - - private void PerformTest() - { - ConcurrentObject c1 = (ConcurrentObject) factory.GetObject("object1"); - ConcurrentObject c2 = (ConcurrentObject) factory.GetObject("object2"); - - Assert.AreEqual(date1, c1.Date); - Assert.AreEqual(date2, c2.Date); - - - } - - public class ConcurrentObject - { - private DateTime date; - - public DateTime Date - { - get { return date; } - set { date = value; } - } - } - - public class ObjectFactoryTask : AsyncTestTask - { - private ConcurrentObjectFactoryTests test; - public ObjectFactoryTask(int iterations, ConcurrentObjectFactoryTests test) - : base(iterations) - { - this.test = test; - } - - #region Overrides of AsyncTestTask - - public override void DoExecute() - { - test.PerformTest(); - } - - #endregion + PerformTest(); } } -} \ No newline at end of file + + [Test] + public void Concurrent() + { + AsyncTestTask t1 = new ObjectFactoryTask(500, this).Start(); + + t1.AssertNoException(); + } + + private void PerformTest() + { + ConcurrentObject c1 = (ConcurrentObject) factory.GetObject("object1"); + ConcurrentObject c2 = (ConcurrentObject) factory.GetObject("object2"); + + Assert.AreEqual(date1, c1.Date); + Assert.AreEqual(date2, c2.Date); + } + + public class ConcurrentObject + { + private DateTime date; + + public DateTime Date + { + get { return date; } + set { date = value; } + } + } + + public class ObjectFactoryTask : AsyncTestTask + { + private ConcurrentObjectFactoryTests test; + + public ObjectFactoryTask(int iterations, ConcurrentObjectFactoryTests test) + : base(iterations) + { + this.test = test; + } + + #region Overrides of AsyncTestTask + + public override void DoExecute() + { + test.PerformTest(); + } + + #endregion + } +} diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/AbstractFactoryObjectTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/AbstractFactoryObjectTests.cs index 3643eb87..74885030 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/AbstractFactoryObjectTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/AbstractFactoryObjectTests.cs @@ -19,71 +19,69 @@ #endregion using FakeItEasy; - using NUnit.Framework; -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Unit tests for the basic functionality of the AbstractFactoryObject class. +/// +/// Rick Evans +[TestFixture] +public sealed class AbstractFactoryObjectTests { - /// - /// Unit tests for the basic functionality of the AbstractFactoryObject class. - /// - /// Rick Evans - [TestFixture] - public sealed class AbstractFactoryObjectTests + [SetUp] + public void Setup() { - [SetUp] - public void Setup() + } + + [Test] + public void DisposeCallbackIsNotInvokedOnDisposeIfInPrototypeMode() + { + IDisposable disposable = A.Fake(); + DummyFactoryObject factory = new DummyFactoryObject(disposable); + + factory.IsSingleton = false; + factory.GetObject(); + factory.Dispose(); + + // in prototype mode, so the Dispose() method of the object must not be called... + A.CallTo(() => disposable.Dispose()).MustNotHaveHappened(); + } + + [Test] + public void DisposeCallbackIsInvokedOnDispose() + { + IDisposable disposable = A.Fake(); + + DummyFactoryObject factory = new DummyFactoryObject(disposable); + factory.AfterPropertiesSet(); + factory.Dispose(); + + A.CallTo(() => disposable.Dispose()).MustHaveHappenedOnceExactly(); + } + + private sealed class DummyFactoryObject : AbstractFactoryObject + { + public object theObject; + + public DummyFactoryObject() : this(new object()) { } - [Test] - public void DisposeCallbackIsNotInvokedOnDisposeIfInPrototypeMode() + public DummyFactoryObject(object theObject) { - IDisposable disposable = A.Fake(); - DummyFactoryObject factory = new DummyFactoryObject(disposable); - - factory.IsSingleton = false; - factory.GetObject(); - factory.Dispose(); - - // in prototype mode, so the Dispose() method of the object must not be called... - A.CallTo(() => disposable.Dispose()).MustNotHaveHappened(); + this.theObject = theObject; } - [Test] - public void DisposeCallbackIsInvokedOnDispose() + public override Type ObjectType { - IDisposable disposable = A.Fake(); - - DummyFactoryObject factory = new DummyFactoryObject(disposable); - factory.AfterPropertiesSet(); - factory.Dispose(); - - A.CallTo(() => disposable.Dispose()).MustHaveHappenedOnceExactly(); + get { return typeof(object); } } - private sealed class DummyFactoryObject : AbstractFactoryObject + protected override object CreateInstance() { - public object theObject; - - public DummyFactoryObject() : this (new object()) - { - } - - public DummyFactoryObject(object theObject) - { - this.theObject = theObject; - } - - public override Type ObjectType - { - get { return typeof(object); } - } - - protected override object CreateInstance() - { - return theObject; - } + return theObject; } - } + } } diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/CommandLineArgsVariableSourceTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/CommandLineArgsVariableSourceTests.cs index b5223081..d9be5b80 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/CommandLineArgsVariableSourceTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/CommandLineArgsVariableSourceTests.cs @@ -24,55 +24,54 @@ using NUnit.Framework; #endregion -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Unit tests for the CommandLineArgsVariableSource class. +/// +/// Aleksandar Seovic +[TestFixture] +public sealed class CommandLineArgsVariableSourceTests { - /// - /// Unit tests for the CommandLineArgsVariableSource class. - /// - /// Aleksandar Seovic - [TestFixture] - public sealed class CommandLineArgsVariableSourceTests + [Test] + public void TestVariablesResolution() { - [Test] - public void TestVariablesResolution() - { - CommandLineArgsVariableSource vs = new CommandLineArgsVariableSource( - new string[] {"program.exe", "file.txt", "/name:Aleks Seovic", "/framework:Spring.NET"}); + CommandLineArgsVariableSource vs = new CommandLineArgsVariableSource( + new string[] { "program.exe", "file.txt", "/name:Aleks Seovic", "/framework:Spring.NET" }); - // existing vars - Assert.AreEqual("Spring.NET", vs.ResolveVariable("FRAMEWORK")); - Assert.AreEqual("Spring.NET", vs.ResolveVariable("framework")); - Assert.AreEqual("Aleks Seovic", vs.ResolveVariable("name")); - Assert.AreEqual("Aleks Seovic", vs.ResolveVariable("NAME")); + // existing vars + Assert.AreEqual("Spring.NET", vs.ResolveVariable("FRAMEWORK")); + Assert.AreEqual("Spring.NET", vs.ResolveVariable("framework")); + Assert.AreEqual("Aleks Seovic", vs.ResolveVariable("name")); + Assert.AreEqual("Aleks Seovic", vs.ResolveVariable("NAME")); - // non-existant variable - Assert.IsNull(vs.ResolveVariable("dummy")); - } + // non-existant variable + Assert.IsNull(vs.ResolveVariable("dummy")); + } - [Test] - public void TestVariablesResolutionWithCustomPrefixAndSeparator() - { - CommandLineArgsVariableSource vs = new CommandLineArgsVariableSource( - new string[] { "program.exe", "file.txt", "--Name=Aleks Seovic", "--Framework=Spring.NET" }); - vs.ArgumentPrefix = "--"; - vs.ValueSeparator = "="; + [Test] + public void TestVariablesResolutionWithCustomPrefixAndSeparator() + { + CommandLineArgsVariableSource vs = new CommandLineArgsVariableSource( + new string[] { "program.exe", "file.txt", "--Name=Aleks Seovic", "--Framework=Spring.NET" }); + vs.ArgumentPrefix = "--"; + vs.ValueSeparator = "="; - // existing vars - Assert.AreEqual("Spring.NET", vs.ResolveVariable("FRAMEWORK")); - Assert.AreEqual("Spring.NET", vs.ResolveVariable("framework")); - Assert.AreEqual("Aleks Seovic", vs.ResolveVariable("name")); - Assert.AreEqual("Aleks Seovic", vs.ResolveVariable("NAME")); + // existing vars + Assert.AreEqual("Spring.NET", vs.ResolveVariable("FRAMEWORK")); + Assert.AreEqual("Spring.NET", vs.ResolveVariable("framework")); + Assert.AreEqual("Aleks Seovic", vs.ResolveVariable("name")); + Assert.AreEqual("Aleks Seovic", vs.ResolveVariable("NAME")); - // non-existant variable - Assert.IsNull(vs.ResolveVariable("dummy")); - } + // non-existant variable + Assert.IsNull(vs.ResolveVariable("dummy")); + } - [Test] - [Explicit] - public void TestLiveVariablesResolutionWithTestDriven() - { - CommandLineArgsVariableSource vs = new CommandLineArgsVariableSource(); - Assert.IsTrue(vs.ResolveVariable("AssemblyName").StartsWith("TestDriven.TestRunner.Server")); - } + [Test] + [Explicit] + public void TestLiveVariablesResolutionWithTestDriven() + { + CommandLineArgsVariableSource vs = new CommandLineArgsVariableSource(); + Assert.IsTrue(vs.ResolveVariable("AssemblyName").StartsWith("TestDriven.TestRunner.Server")); } } diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/ConfigSectionVariableSourceTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/ConfigSectionVariableSourceTests.cs index 3e7ce3f9..8670ccd6 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/ConfigSectionVariableSourceTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/ConfigSectionVariableSourceTests.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -24,56 +24,54 @@ using NUnit.Framework; #endregion -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Unit tests for the ConfigSectionVariableSource class. +/// +/// Aleksandar Seovic +[TestFixture] +public sealed class ConfigSectionVariableSourceTests { - /// - /// Unit tests for the ConfigSectionVariableSource class. - /// - /// Aleksandar Seovic - [TestFixture] - public sealed class ConfigSectionVariableSourceTests + [Test] + public void TestVariablesResolutionWithSingleSection() { - [Test] - public void TestVariablesResolutionWithSingleSection() - { - ConfigSectionVariableSource vs = new ConfigSectionVariableSource(); - vs.SectionName = "DaoConfiguration"; + ConfigSectionVariableSource vs = new ConfigSectionVariableSource(); + vs.SectionName = "DaoConfiguration"; - // existing vars - Assert.AreEqual("1000", vs.ResolveVariable("maxResults")); - Assert.AreEqual("1000", vs.ResolveVariable("MAXResults")); + // existing vars + Assert.AreEqual("1000", vs.ResolveVariable("maxResults")); + Assert.AreEqual("1000", vs.ResolveVariable("MAXResults")); - // non-existant variable - Assert.IsNull(vs.ResolveVariable("dummy")); - } - - [Test] - public void TestVariablesResolutionWithTwoSections() - { - ConfigSectionVariableSource vs = new ConfigSectionVariableSource(); - vs.SectionNames = new string[] { "DaoConfiguration", "DatabaseConfiguration" }; - - // existing vars - Assert.AreEqual("1000", vs.ResolveVariable("maxResults")); - Assert.AreEqual("1000", vs.ResolveVariable("MAXResults")); - Assert.AreEqual(@"Provider=Microsoft.Jet.OLEDB.4.0; Data Source=c:\Northwind.mdb;User ID=Admin;Password=;", - vs.ResolveVariable("connection.string")); - Assert.AreEqual(@"Provider=Microsoft.Jet.OLEDB.4.0; Data Source=c:\Northwind.mdb;User ID=Admin;Password=;", - vs.ResolveVariable("Connection.String")); - - // non-existant variable - Assert.IsNull(vs.ResolveVariable("dummy")); - } - - [Test] - public void TestVariableResolutionFromApplicationSettingsSchema() - { - ConfigSectionVariableSource vs = new ConfigSectionVariableSource(); - vs.SectionName = "applicationSettings/MyApp.Properties.Settings"; - Assert.AreEqual("1000", vs.ResolveVariable("maxResults")); - Assert.AreEqual(@"Provider=Microsoft.Jet.OLEDB.4.0; Data Source=c:\Northwind.mdb;User ID=Admin;Password=;", - vs.ResolveVariable("connection.string")); - } + // non-existant variable + Assert.IsNull(vs.ResolveVariable("dummy")); } + [Test] + public void TestVariablesResolutionWithTwoSections() + { + ConfigSectionVariableSource vs = new ConfigSectionVariableSource(); + vs.SectionNames = new string[] { "DaoConfiguration", "DatabaseConfiguration" }; + + // existing vars + Assert.AreEqual("1000", vs.ResolveVariable("maxResults")); + Assert.AreEqual("1000", vs.ResolveVariable("MAXResults")); + Assert.AreEqual(@"Provider=Microsoft.Jet.OLEDB.4.0; Data Source=c:\Northwind.mdb;User ID=Admin;Password=;", + vs.ResolveVariable("connection.string")); + Assert.AreEqual(@"Provider=Microsoft.Jet.OLEDB.4.0; Data Source=c:\Northwind.mdb;User ID=Admin;Password=;", + vs.ResolveVariable("Connection.String")); + + // non-existant variable + Assert.IsNull(vs.ResolveVariable("dummy")); + } + + [Test] + public void TestVariableResolutionFromApplicationSettingsSchema() + { + ConfigSectionVariableSource vs = new ConfigSectionVariableSource(); + vs.SectionName = "applicationSettings/MyApp.Properties.Settings"; + Assert.AreEqual("1000", vs.ResolveVariable("maxResults")); + Assert.AreEqual(@"Provider=Microsoft.Jet.OLEDB.4.0; Data Source=c:\Northwind.mdb;User ID=Admin;Password=;", + vs.ResolveVariable("connection.string")); + } } diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/ConfigurableVariableSourceTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/ConfigurableVariableSourceTests.cs index 52c04f03..c172b0fb 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/ConfigurableVariableSourceTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/ConfigurableVariableSourceTests.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -20,31 +20,30 @@ using NUnit.Framework; -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Unit tests for the ConfigurableVariableSource class. +/// +/// Bruno Baia +[TestFixture] +public sealed class ConfigurableVariableSourceTests { - /// - /// Unit tests for the ConfigurableVariableSource class. - /// - /// Bruno Baia - [TestFixture] - public sealed class ConfigurableVariableSourceTests + [Test] + public void Basic() { - [Test] - public void Basic() - { - ConfigurableVariableSource vs = new ConfigurableVariableSource(); - vs.Variables.Add("Key1", "Value1"); - vs.Variables.Add("Key2", "Value2"); + ConfigurableVariableSource vs = new ConfigurableVariableSource(); + vs.Variables.Add("Key1", "Value1"); + vs.Variables.Add("Key2", "Value2"); - // existing vars - Assert.IsTrue(vs.CanResolveVariable("key1")); // case insensitive - Assert.AreEqual("Value1", vs.ResolveVariable("key1")); // case insensitive - Assert.IsTrue(vs.CanResolveVariable("Key2")); - Assert.AreEqual("Value2", vs.ResolveVariable("Key2")); + // existing vars + Assert.IsTrue(vs.CanResolveVariable("key1")); // case insensitive + Assert.AreEqual("Value1", vs.ResolveVariable("key1")); // case insensitive + Assert.IsTrue(vs.CanResolveVariable("Key2")); + Assert.AreEqual("Value2", vs.ResolveVariable("Key2")); - // non-existant variable - Assert.IsFalse(vs.CanResolveVariable("Key3")); - Assert.IsNull(vs.ResolveVariable("Key3")); - } + // non-existant variable + Assert.IsFalse(vs.CanResolveVariable("Key3")); + Assert.IsNull(vs.ResolveVariable("Key3")); } -} \ No newline at end of file +} diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/ConfigurationReaderTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/ConfigurationReaderTests.cs index eb90b19c..7b911bf5 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/ConfigurationReaderTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/ConfigurationReaderTests.cs @@ -23,23 +23,21 @@ using System.Collections.Specialized; using System.Configuration; using System.Text; - using NUnit.Framework; - using Spring.Core.IO; #endregion -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Unit tests for the ConfigurationReader class. +/// +/// Rick Evans +[TestFixture] +public sealed class ConfigurationReaderTests { - /// - /// Unit tests for the ConfigurationReader class. - /// - /// Rick Evans - [TestFixture] - public sealed class ConfigurationReaderTests - { - private const string SunnyDayXml = @" + private const string SunnyDayXml = @"
@@ -50,50 +48,50 @@ namespace Spring.Objects.Factory.Config "; - /// - /// Unfortunately ConfigurationManager doesn't accept uri's. - /// - [Test] - public void ConfigurationManagerCannotReadFromUrl() + /// + /// Unfortunately ConfigurationManager doesn't accept uri's. + /// + [Test] + public void ConfigurationManagerCannotReadFromUrl() + { + try + { + ConfigurationManager.OpenExeConfiguration("http://localhost/something.config"); + Assert.Fail(); + } + catch (ConfigurationErrorsException cfgex) { - try - { - ConfigurationManager.OpenExeConfiguration("http://localhost/something.config"); - Assert.Fail(); - } - catch (ConfigurationErrorsException cfgex) - { #if NETFRAMEWORK - Assert.IsInstanceOf(typeof(NotSupportedException), cfgex.InnerException); + Assert.IsInstanceOf(typeof(NotSupportedException), cfgex.InnerException); #else Assert.IsInstanceOf(typeof(ArgumentException), cfgex.InnerException); #endif - } } + } - [Test] - public void ReadSunnyDay() + [Test] + public void ReadSunnyDay() + { + using (Stream stream = new MemoryStream(Encoding.UTF8.GetBytes(SunnyDayXml))) { - using (Stream stream = new MemoryStream(Encoding.UTF8.GetBytes(SunnyDayXml))) - { - NameValueCollection props = ConfigurationReader.Read(new InputStreamResource(stream, ""), "foo"); - Assert.IsNotNull(props, - "Failed to read in any properties at all (props is null)."); - Assert.AreEqual(2, props.Count, - "Wrong number of properties read in."); - Assert.AreEqual("kiley", - props["rilo"], - "Wrong value for second property"); - Assert.AreEqual("lewis", - props["jenny"], - "Wrong value for second property"); - } + NameValueCollection props = ConfigurationReader.Read(new InputStreamResource(stream, ""), "foo"); + Assert.IsNotNull(props, + "Failed to read in any properties at all (props is null)."); + Assert.AreEqual(2, props.Count, + "Wrong number of properties read in."); + Assert.AreEqual("kiley", + props["rilo"], + "Wrong value for second property"); + Assert.AreEqual("lewis", + props["jenny"], + "Wrong value for second property"); } + } - [Test] - public void GetSectionLocalSectionHandler() - { - string xml = @" + [Test] + public void GetSectionLocalSectionHandler() + { + string xml = @"
@@ -105,20 +103,20 @@ namespace Spring.Objects.Factory.Config "; - using (Stream stream = new MemoryStream(Encoding.UTF8.GetBytes(xml))) - { - ConnectionStringsSection css = ConfigurationReader.GetSection(new InputStreamResource(stream, ""), "connectionStrings"); - Assert.IsNotNull(css, "Failed to read in any properties at all (props is null)."); - Assert.IsNotNull(css.ConnectionStrings["Sales"]); - Assert.AreEqual("System.Data.SqlClient", css.ConnectionStrings["Sales"].ProviderName); - Assert.AreEqual("server=myserver;database=Products;uid=user name;pwd=secure password", css.ConnectionStrings["Sales"].ConnectionString); - } - } - - [Test] - public void GetSectionMachineInheritedSectionHandler() + using (Stream stream = new MemoryStream(Encoding.UTF8.GetBytes(xml))) { - string xml = @" + ConnectionStringsSection css = ConfigurationReader.GetSection(new InputStreamResource(stream, ""), "connectionStrings"); + Assert.IsNotNull(css, "Failed to read in any properties at all (props is null)."); + Assert.IsNotNull(css.ConnectionStrings["Sales"]); + Assert.AreEqual("System.Data.SqlClient", css.ConnectionStrings["Sales"].ProviderName); + Assert.AreEqual("server=myserver;database=Products;uid=user name;pwd=secure password", css.ConnectionStrings["Sales"].ConnectionString); + } + } + + [Test] + public void GetSectionMachineInheritedSectionHandler() + { + string xml = @" "; - using (Stream stream = new MemoryStream(Encoding.UTF8.GetBytes(xml))) - { - ConnectionStringsSection css = ConfigurationReader.GetSection(new InputStreamResource(stream, ""), "connectionStrings"); - Assert.IsNotNull(css, "Failed to read in any properties at all (props is null)."); - Assert.IsNotNull(css.ConnectionStrings["Sales"]); - Assert.AreEqual("System.Data.SqlClient", css.ConnectionStrings["Sales"].ProviderName); - Assert.AreEqual("server=myserver;database=Products;uid=user name;pwd=secure password", css.ConnectionStrings["Sales"].ConnectionString); - } - } - - [Test] - public void GetSectionSunnyDay() + using (Stream stream = new MemoryStream(Encoding.UTF8.GetBytes(xml))) { - using (Stream stream = new MemoryStream(Encoding.UTF8.GetBytes(SunnyDayXml))) - { - NameValueCollection props = ConfigurationReader.Read(new InputStreamResource(stream, ""), "foo"); - Assert.IsNotNull(props, - "Failed to read in any properties at all (props is null)."); - Assert.AreEqual(2, props.Count, - "Wrong number of properties read in."); - Assert.AreEqual("kiley", - props["rilo"], - "Wrong value for second property"); - Assert.AreEqual("lewis", - props["jenny"], - "Wrong value for second property"); - } + ConnectionStringsSection css = ConfigurationReader.GetSection(new InputStreamResource(stream, ""), "connectionStrings"); + Assert.IsNotNull(css, "Failed to read in any properties at all (props is null)."); + Assert.IsNotNull(css.ConnectionStrings["Sales"]); + Assert.AreEqual("System.Data.SqlClient", css.ConnectionStrings["Sales"].ProviderName); + Assert.AreEqual("server=myserver;database=Products;uid=user name;pwd=secure password", css.ConnectionStrings["Sales"].ConnectionString); } + } - [Test] - public void ReadWithOverrideOfPreviouslyExistingValues() + [Test] + public void GetSectionSunnyDay() + { + using (Stream stream = new MemoryStream(Encoding.UTF8.GetBytes(SunnyDayXml))) { - using(Stream stream = new MemoryStream(Encoding.UTF8.GetBytes(SunnyDayXml))) - { - NameValueCollection defaults = new NameValueCollection(); - defaults.Add("jenny", "agutter"); - NameValueCollection props - = ConfigurationReader.Read(new InputStreamResource(stream, ""), "foo", defaults); - Assert.IsTrue(ReferenceEquals(defaults, props), "Must have got same collection as was passed in."); - Assert.AreEqual("lewis", props["jenny"], "Wrong value for overridden property (was not overridden"); - } + NameValueCollection props = ConfigurationReader.Read(new InputStreamResource(stream, ""), "foo"); + Assert.IsNotNull(props, + "Failed to read in any properties at all (props is null)."); + Assert.AreEqual(2, props.Count, + "Wrong number of properties read in."); + Assert.AreEqual("kiley", + props["rilo"], + "Wrong value for second property"); + Assert.AreEqual("lewis", + props["jenny"], + "Wrong value for second property"); } + } - [Test] - public void ReadWithOverrideOfPreviouslyExistingValuesButWithOverrideSwitchedOff() + [Test] + public void ReadWithOverrideOfPreviouslyExistingValues() + { + using (Stream stream = new MemoryStream(Encoding.UTF8.GetBytes(SunnyDayXml))) { - using(Stream stream = new MemoryStream(Encoding.UTF8.GetBytes(SunnyDayXml))) - { - NameValueCollection defaults = new NameValueCollection(); - defaults.Add("jenny", "agutter"); - NameValueCollection props - = ConfigurationReader.Read(new InputStreamResource(stream, ""), "foo", defaults, false); - Assert.IsTrue(ReferenceEquals(defaults, props), "Must have got same collection as was passed in."); - Assert.AreEqual("agutter,lewis", props["jenny"], "Wrong value for overridden property (was not overridden"); - } + NameValueCollection defaults = new NameValueCollection(); + defaults.Add("jenny", "agutter"); + NameValueCollection props + = ConfigurationReader.Read(new InputStreamResource(stream, ""), "foo", defaults); + Assert.IsTrue(ReferenceEquals(defaults, props), "Must have got same collection as was passed in."); + Assert.AreEqual("lewis", props["jenny"], "Wrong value for overridden property (was not overridden"); } + } - [Test] - public void ReadWithNullExistingValuesPassedIn() + [Test] + public void ReadWithOverrideOfPreviouslyExistingValuesButWithOverrideSwitchedOff() + { + using (Stream stream = new MemoryStream(Encoding.UTF8.GetBytes(SunnyDayXml))) { - using(Stream stream = new MemoryStream(Encoding.UTF8.GetBytes(SunnyDayXml))) - { - NameValueCollection props - = ConfigurationReader.Read(new InputStreamResource(stream, ""), "foo", null); - Assert.IsNotNull(props, "Failed to read in any properties at all (props is null)."); - Assert.AreEqual(2, props.Count, "Wrong number of properties read in."); - Assert.AreEqual("kiley", props["rilo"], "Wrong value for second property"); - Assert.AreEqual("lewis", props["jenny"], "Wrong value for second property"); - } + NameValueCollection defaults = new NameValueCollection(); + defaults.Add("jenny", "agutter"); + NameValueCollection props + = ConfigurationReader.Read(new InputStreamResource(stream, ""), "foo", defaults, false); + Assert.IsTrue(ReferenceEquals(defaults, props), "Must have got same collection as was passed in."); + Assert.AreEqual("agutter,lewis", props["jenny"], "Wrong value for overridden property (was not overridden"); } + } - [Test] - public void ReadWithNoConfigSectionSectionDefaultsToNameValueSectionHandler() + [Test] + public void ReadWithNullExistingValuesPassedIn() + { + using (Stream stream = new MemoryStream(Encoding.UTF8.GetBytes(SunnyDayXml))) { - const string NoConfigSectionXml = @" + NameValueCollection props + = ConfigurationReader.Read(new InputStreamResource(stream, ""), "foo", null); + Assert.IsNotNull(props, "Failed to read in any properties at all (props is null)."); + Assert.AreEqual(2, props.Count, "Wrong number of properties read in."); + Assert.AreEqual("kiley", props["rilo"], "Wrong value for second property"); + Assert.AreEqual("lewis", props["jenny"], "Wrong value for second property"); + } + } + + [Test] + public void ReadWithNoConfigSectionSectionDefaultsToNameValueSectionHandler() + { + const string NoConfigSectionXml = @" "; - using(Stream stream = new MemoryStream(Encoding.UTF8.GetBytes(NoConfigSectionXml))) - { - NameValueCollection props - = ConfigurationReader.Read(new InputStreamResource(stream, ""), "foo", null); - Assert.IsNotNull(props, "Failed to read in any properties at all (props is null)."); - Assert.AreEqual(2, props.Count, "Wrong number of properties read in."); - Assert.AreEqual("kiley", props["rilo"], "Wrong value for second property"); - Assert.AreEqual("lewis", props["jenny"], "Wrong value for second property"); - } - } - - [Test] - public void TryReadFromNonExistantConfigSection() + using (Stream stream = new MemoryStream(Encoding.UTF8.GetBytes(NoConfigSectionXml))) { - Assert.Throws(() => - { - using (Stream stream = new MemoryStream(Encoding.UTF8.GetBytes(SunnyDayXml))) - { - ConfigurationReader.Read(new InputStreamResource(stream, ""), "ELNOMBRE", null); - } - }, "Cannot read config section 'ELNOMBRE' - section not found."); + NameValueCollection props + = ConfigurationReader.Read(new InputStreamResource(stream, ""), "foo", null); + Assert.IsNotNull(props, "Failed to read in any properties at all (props is null)."); + Assert.AreEqual(2, props.Count, "Wrong number of properties read in."); + Assert.AreEqual("kiley", props["rilo"], "Wrong value for second property"); + Assert.AreEqual("lewis", props["jenny"], "Wrong value for second property"); } } + + [Test] + public void TryReadFromNonExistantConfigSection() + { + Assert.Throws(() => + { + using (Stream stream = new MemoryStream(Encoding.UTF8.GetBytes(SunnyDayXml))) + { + ConfigurationReader.Read(new InputStreamResource(stream, ""), "ELNOMBRE", null); + } + }, "Cannot read config section 'ELNOMBRE' - section not found."); + } } diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/ConnectionStringsVariableSourceTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/ConnectionStringsVariableSourceTests.cs index 4bf5c0d7..98e4fa64 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/ConnectionStringsVariableSourceTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/ConnectionStringsVariableSourceTests.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -24,28 +24,27 @@ using NUnit.Framework; #endregion -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Unit tests for the ConnectionStringsVariableSource class. +/// +/// Aleksandar Seovic +[TestFixture] +public sealed class ConnectionStringsVariableSourceTests { - /// - /// Unit tests for the ConnectionStringsVariableSource class. - /// - /// Aleksandar Seovic - [TestFixture] - public sealed class ConnectionStringsVariableSourceTests + [Test] + public void TestVariablesResolution() { - [Test] - public void TestVariablesResolution() - { - ConnectionStringsVariableSource vs = new ConnectionStringsVariableSource(); + ConnectionStringsVariableSource vs = new ConnectionStringsVariableSource(); - // existing vars - Assert.AreEqual("mySqlServerConnectionString", vs.ResolveVariable("mySqlDataSource.connectionString")); - Assert.AreEqual("System.Data.SqlClient", vs.ResolveVariable("mySqlDataSource.providerName")); - Assert.AreEqual("myOracleConnectionString", vs.ResolveVariable("myOracleDataSource.connectionString")); - Assert.AreEqual("System.Data.OracleClient", vs.ResolveVariable("myOracleDataSource.providerName")); + // existing vars + Assert.AreEqual("mySqlServerConnectionString", vs.ResolveVariable("mySqlDataSource.connectionString")); + Assert.AreEqual("System.Data.SqlClient", vs.ResolveVariable("mySqlDataSource.providerName")); + Assert.AreEqual("myOracleConnectionString", vs.ResolveVariable("myOracleDataSource.connectionString")); + Assert.AreEqual("System.Data.OracleClient", vs.ResolveVariable("myOracleDataSource.providerName")); - // non-existant variable - Assert.IsNull(vs.ResolveVariable("dummy")); - } + // non-existant variable + Assert.IsNull(vs.ResolveVariable("dummy")); } } diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/ConstructorArgumentValuesTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/ConstructorArgumentValuesTests.cs index 190e52d9..c44f7a51 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/ConstructorArgumentValuesTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/ConstructorArgumentValuesTests.cs @@ -25,268 +25,267 @@ using Spring.Collections; #endregion -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Unit tests for the ConstructorArgumentValues class. +/// +/// Rick Evans (.NET) +[TestFixture] +public sealed class ConstructorArgumentValuesTests { - /// - /// Unit tests for the ConstructorArgumentValues class. - /// - /// Rick Evans (.NET) - [TestFixture] - public sealed class ConstructorArgumentValuesTests - { - [Test] - public void Instantiation() - { - ConstructorArgumentValues values = new ConstructorArgumentValues(); - Assert.IsNotNull(values.GenericArgumentValues, "The 'GenericArgumentValues' property was not initialised."); - Assert.IsNotNull(values.IndexedArgumentValues, "The 'IndexedArgumentValues' property was not initialised."); - Assert.IsNotNull(values.NamedArgumentValues, "The 'NamedArgumentValues' property was not initialised."); - Assert.AreEqual(0, values.ArgumentCount, "There were some arguments in a newly initialised instance."); - Assert.IsTrue(values.Empty, "A newly initialised instance was not initially empty."); - } + [Test] + public void Instantiation() + { + ConstructorArgumentValues values = new ConstructorArgumentValues(); + Assert.IsNotNull(values.GenericArgumentValues, "The 'GenericArgumentValues' property was not initialised."); + Assert.IsNotNull(values.IndexedArgumentValues, "The 'IndexedArgumentValues' property was not initialised."); + Assert.IsNotNull(values.NamedArgumentValues, "The 'NamedArgumentValues' property was not initialised."); + Assert.AreEqual(0, values.ArgumentCount, "There were some arguments in a newly initialised instance."); + Assert.IsTrue(values.Empty, "A newly initialised instance was not initially empty."); + } - [Test] - public void GetGenericArgumentValueIgnoresAlreadyUsedValues() - { - ISet used = new ListSet(); + [Test] + public void GetGenericArgumentValueIgnoresAlreadyUsedValues() + { + ISet used = new ListSet(); - ConstructorArgumentValues values = new ConstructorArgumentValues(); - values.AddGenericArgumentValue(1); - values.AddGenericArgumentValue(2); - values.AddGenericArgumentValue(3); + ConstructorArgumentValues values = new ConstructorArgumentValues(); + values.AddGenericArgumentValue(1); + values.AddGenericArgumentValue(2); + values.AddGenericArgumentValue(3); - Type intType = typeof (int); - ConstructorArgumentValues.ValueHolder one = values.GetGenericArgumentValue(intType, used); - Assert.AreEqual(1, one.Value); - used.Add(one); - ConstructorArgumentValues.ValueHolder two = values.GetGenericArgumentValue(intType, used); - Assert.AreEqual(2, two.Value); - used.Add(two); - ConstructorArgumentValues.ValueHolder three = values.GetGenericArgumentValue(intType, used); - Assert.AreEqual(3, three.Value); - used.Add(three); - ConstructorArgumentValues.ValueHolder four = values.GetGenericArgumentValue(intType, used); - Assert.IsNull(four); - } + Type intType = typeof(int); + ConstructorArgumentValues.ValueHolder one = values.GetGenericArgumentValue(intType, used); + Assert.AreEqual(1, one.Value); + used.Add(one); + ConstructorArgumentValues.ValueHolder two = values.GetGenericArgumentValue(intType, used); + Assert.AreEqual(2, two.Value); + used.Add(two); + ConstructorArgumentValues.ValueHolder three = values.GetGenericArgumentValue(intType, used); + Assert.AreEqual(3, three.Value); + used.Add(three); + ConstructorArgumentValues.ValueHolder four = values.GetGenericArgumentValue(intType, used); + Assert.IsNull(four); + } - [Test] - public void GetGeneric_Untyped_ArgumentValue() - { - ConstructorArgumentValues values = new ConstructorArgumentValues(); - const string expectedValue = "Rick"; - values.AddGenericArgumentValue(expectedValue); + [Test] + public void GetGeneric_Untyped_ArgumentValue() + { + ConstructorArgumentValues values = new ConstructorArgumentValues(); + const string expectedValue = "Rick"; + values.AddGenericArgumentValue(expectedValue); - ConstructorArgumentValues.ValueHolder name = values.GetGenericArgumentValue(null, null); - Assert.IsNotNull(name, - "Must get non-null valueholder back if no required type is specified."); - Assert.AreEqual(expectedValue, name.Value); - } + ConstructorArgumentValues.ValueHolder name = values.GetGenericArgumentValue(null, null); + Assert.IsNotNull(name, + "Must get non-null valueholder back if no required type is specified."); + Assert.AreEqual(expectedValue, name.Value); + } - [Test] - public void GetGeneric_Untyped_ArgumentValueWithOnlyStronglyTypedValuesInTheCtorValueList() - { - ConstructorArgumentValues values = new ConstructorArgumentValues(); - const string expectedValue = "Rick"; - values.AddGenericArgumentValue(expectedValue, typeof(string).FullName); + [Test] + public void GetGeneric_Untyped_ArgumentValueWithOnlyStronglyTypedValuesInTheCtorValueList() + { + ConstructorArgumentValues values = new ConstructorArgumentValues(); + const string expectedValue = "Rick"; + values.AddGenericArgumentValue(expectedValue, typeof(string).FullName); - ConstructorArgumentValues.ValueHolder name = values.GetGenericArgumentValue(null, null); - Assert.IsNull(name, - "Must get null valueholder back if no required type is specified but only " + - "strongly typed values are present in the ctor values list."); - } + ConstructorArgumentValues.ValueHolder name = values.GetGenericArgumentValue(null, null); + Assert.IsNull(name, + "Must get null valueholder back if no required type is specified but only " + + "strongly typed values are present in the ctor values list."); + } - [Test] - public void GetArgumentValueIgnoresAlreadyUsedValues() - { - ISet used = new ListSet(); + [Test] + public void GetArgumentValueIgnoresAlreadyUsedValues() + { + ISet used = new ListSet(); - ConstructorArgumentValues values = new ConstructorArgumentValues(); - values.AddGenericArgumentValue(1); - values.AddNamedArgumentValue("2", 2); - values.AddIndexedArgumentValue(3, 3); + ConstructorArgumentValues values = new ConstructorArgumentValues(); + values.AddGenericArgumentValue(1); + values.AddNamedArgumentValue("2", 2); + values.AddIndexedArgumentValue(3, 3); - Type intType = typeof (int); - ConstructorArgumentValues.ValueHolder one = values.GetArgumentValue(10, string.Empty, intType, used); - Assert.AreEqual(1, one.Value); - used.Add(one); - ConstructorArgumentValues.ValueHolder two = values.GetArgumentValue(10, "2", intType, used); - Assert.AreEqual(2, two.Value); - used.Add(two); - ConstructorArgumentValues.ValueHolder three = values.GetArgumentValue(3, string.Empty, intType, used); - Assert.AreEqual(3, three.Value); - used.Add(three); - ConstructorArgumentValues.ValueHolder four = values.GetArgumentValue(10, string.Empty, intType, used); - Assert.IsNull(four); - } + Type intType = typeof(int); + ConstructorArgumentValues.ValueHolder one = values.GetArgumentValue(10, string.Empty, intType, used); + Assert.AreEqual(1, one.Value); + used.Add(one); + ConstructorArgumentValues.ValueHolder two = values.GetArgumentValue(10, "2", intType, used); + Assert.AreEqual(2, two.Value); + used.Add(two); + ConstructorArgumentValues.ValueHolder three = values.GetArgumentValue(3, string.Empty, intType, used); + Assert.AreEqual(3, three.Value); + used.Add(three); + ConstructorArgumentValues.ValueHolder four = values.GetArgumentValue(10, string.Empty, intType, used); + Assert.IsNull(four); + } - [Test] - public void AddNamedArgumentWithNullName() - { - ConstructorArgumentValues values = new ConstructorArgumentValues(); - Assert.Throws(() => values.AddNamedArgumentValue(null, 1)); - } + [Test] + public void AddNamedArgumentWithNullName() + { + ConstructorArgumentValues values = new ConstructorArgumentValues(); + Assert.Throws(() => values.AddNamedArgumentValue(null, 1)); + } - [Test] - public void AddNamedArgumentWithEmptyStringName() - { - ConstructorArgumentValues values = new ConstructorArgumentValues(); - Assert.Throws(() => values.AddNamedArgumentValue(string.Empty, 1)); - } + [Test] + public void AddNamedArgumentWithEmptyStringName() + { + ConstructorArgumentValues values = new ConstructorArgumentValues(); + Assert.Throws(() => values.AddNamedArgumentValue(string.Empty, 1)); + } - [Test] - public void AddNamedArgumentWithWhitespaceStringName() - { - ConstructorArgumentValues values = new ConstructorArgumentValues(); - Assert.Throws(() => values.AddNamedArgumentValue(Environment.NewLine + " ", 1)); - } + [Test] + public void AddNamedArgumentWithWhitespaceStringName() + { + ConstructorArgumentValues values = new ConstructorArgumentValues(); + Assert.Throws(() => values.AddNamedArgumentValue(Environment.NewLine + " ", 1)); + } - [Test] - public void AddIndexedArgumentValue() - { - ConstructorArgumentValues values = new ConstructorArgumentValues(); - values.AddIndexedArgumentValue(1, DBNull.Value); - Assert.IsFalse(values.Empty, "Added one value, but the collection is sayin' it's empty."); - Assert.AreEqual(1, values.ArgumentCount, "Added one value, but the collection ain't sayin' that it's got a single element in it."); - Assert.AreEqual(1, values.IndexedArgumentValues.Count, "Added one indexed value, but the collection of indexed values ain't sayin' that it's got a single element in it."); - } + [Test] + public void AddIndexedArgumentValue() + { + ConstructorArgumentValues values = new ConstructorArgumentValues(); + values.AddIndexedArgumentValue(1, DBNull.Value); + Assert.IsFalse(values.Empty, "Added one value, but the collection is sayin' it's empty."); + Assert.AreEqual(1, values.ArgumentCount, "Added one value, but the collection ain't sayin' that it's got a single element in it."); + Assert.AreEqual(1, values.IndexedArgumentValues.Count, "Added one indexed value, but the collection of indexed values ain't sayin' that it's got a single element in it."); + } - [Test] - public void AddGenericArgumentValue() - { - ConstructorArgumentValues values = new ConstructorArgumentValues(); - values.AddGenericArgumentValue(DBNull.Value); - Assert.IsFalse(values.Empty, "Added one value, but the collection is sayin' it's empty."); - Assert.AreEqual(1, values.ArgumentCount, "Added one value, but the collection ain't sayin' that it's got a single element in it."); - Assert.AreEqual(1, values.GenericArgumentValues.Count, "Added one generic value, but the collection of indexed values ain't sayin' that it's got a single element in it."); - } + [Test] + public void AddGenericArgumentValue() + { + ConstructorArgumentValues values = new ConstructorArgumentValues(); + values.AddGenericArgumentValue(DBNull.Value); + Assert.IsFalse(values.Empty, "Added one value, but the collection is sayin' it's empty."); + Assert.AreEqual(1, values.ArgumentCount, "Added one value, but the collection ain't sayin' that it's got a single element in it."); + Assert.AreEqual(1, values.GenericArgumentValues.Count, "Added one generic value, but the collection of indexed values ain't sayin' that it's got a single element in it."); + } - [Test] - public void GetIndexedArgumentValue() - { - ConstructorArgumentValues values = new ConstructorArgumentValues(); - Assert.IsNull(values.GetIndexedArgumentValue(0, typeof (object)), "Mmm... managed to get a non null instance back from an empty instance."); - values.AddIndexedArgumentValue(16, DBNull.Value, typeof (DBNull).FullName); - Assert.IsNull(values.GetIndexedArgumentValue(0, typeof (object)), "Mmm... managed to get a non null instance back from an instance that should have now't at the specified index."); - ConstructorArgumentValues.ValueHolder value = - values.GetIndexedArgumentValue(16, typeof (DBNull)); - Assert.IsNotNull(value, "Stored a value at a specified index, but got null when retrieving it."); - Assert.AreSame(DBNull.Value, value.Value, "The value stored at the specified index was not the exact same instance as was added."); - ConstructorArgumentValues.ValueHolder wrongValue = - values.GetIndexedArgumentValue(16, typeof (string)); - Assert.IsNull(wrongValue, "Stored a value at a specified index, and got it (or rather something) back when retrieving it with the wrong Type specified."); - } + [Test] + public void GetIndexedArgumentValue() + { + ConstructorArgumentValues values = new ConstructorArgumentValues(); + Assert.IsNull(values.GetIndexedArgumentValue(0, typeof(object)), "Mmm... managed to get a non null instance back from an empty instance."); + values.AddIndexedArgumentValue(16, DBNull.Value, typeof(DBNull).FullName); + Assert.IsNull(values.GetIndexedArgumentValue(0, typeof(object)), "Mmm... managed to get a non null instance back from an instance that should have now't at the specified index."); + ConstructorArgumentValues.ValueHolder value = + values.GetIndexedArgumentValue(16, typeof(DBNull)); + Assert.IsNotNull(value, "Stored a value at a specified index, but got null when retrieving it."); + Assert.AreSame(DBNull.Value, value.Value, "The value stored at the specified index was not the exact same instance as was added."); + ConstructorArgumentValues.ValueHolder wrongValue = + values.GetIndexedArgumentValue(16, typeof(string)); + Assert.IsNull(wrongValue, "Stored a value at a specified index, and got it (or rather something) back when retrieving it with the wrong Type specified."); + } - [Test] - public void GetGenericArgumentValue() - { - ConstructorArgumentValues values = new ConstructorArgumentValues(); - Assert.IsNull(values.GetGenericArgumentValue(typeof (object)), "Mmm... managed to get a non null instance back from an empty instance."); - values.AddGenericArgumentValue(DBNull.Value, typeof (DBNull).FullName); - Assert.IsNull(values.GetGenericArgumentValue(typeof (string)), "Mmm... managed to get a non null instance back from an instance that should have now't with the specified Type."); - ConstructorArgumentValues.ValueHolder value = - values.GetGenericArgumentValue(typeof (DBNull)); - Assert.IsNotNull(value, "Stored a value of a specified Type, but got null when retrieving it using said Type."); - Assert.AreSame(DBNull.Value, value.Value, "The value stored at the specified index was not the exact same instance as was added."); - } + [Test] + public void GetGenericArgumentValue() + { + ConstructorArgumentValues values = new ConstructorArgumentValues(); + Assert.IsNull(values.GetGenericArgumentValue(typeof(object)), "Mmm... managed to get a non null instance back from an empty instance."); + values.AddGenericArgumentValue(DBNull.Value, typeof(DBNull).FullName); + Assert.IsNull(values.GetGenericArgumentValue(typeof(string)), "Mmm... managed to get a non null instance back from an instance that should have now't with the specified Type."); + ConstructorArgumentValues.ValueHolder value = + values.GetGenericArgumentValue(typeof(DBNull)); + Assert.IsNotNull(value, "Stored a value of a specified Type, but got null when retrieving it using said Type."); + Assert.AreSame(DBNull.Value, value.Value, "The value stored at the specified index was not the exact same instance as was added."); + } - [Test] - public void GetArgumentValue() - { - ConstructorArgumentValues values = new ConstructorArgumentValues(); - Assert.IsNull(values.GetArgumentValue(0, typeof (object)), "Mmm... managed to get a non null instance back from an empty instance."); - values.AddGenericArgumentValue(DBNull.Value, typeof (DBNull).FullName); - values.AddNamedArgumentValue("foo", DBNull.Value); - values.AddIndexedArgumentValue(16, DBNull.Value, typeof (DBNull).FullName); - Assert.IsNull(values.GetArgumentValue(100, typeof (string)), "Mmm... managed to get a non null instance back from an instance that should have now't with the specified Type."); - ConstructorArgumentValues.ValueHolder value = - values.GetArgumentValue(-3, typeof (DBNull)); - Assert.IsNotNull(value, "Stored a value of a specified Type at a specified index, but got null when retrieving it using the wrong index but the correct Type."); - Assert.AreSame(DBNull.Value, value.Value, "The retrieved value was not the exact same instance as was added."); - - value = values.GetArgumentValue("foo", typeof (DBNull)); - Assert.IsNotNull(value, "Stored a value of a specified Type under a name, but got null when retrieving it using the wrong name but the correct Type."); - Assert.AreSame(DBNull.Value, value.Value, "The retrieved value was not the exact same instance as was added."); - } + [Test] + public void GetArgumentValue() + { + ConstructorArgumentValues values = new ConstructorArgumentValues(); + Assert.IsNull(values.GetArgumentValue(0, typeof(object)), "Mmm... managed to get a non null instance back from an empty instance."); + values.AddGenericArgumentValue(DBNull.Value, typeof(DBNull).FullName); + values.AddNamedArgumentValue("foo", DBNull.Value); + values.AddIndexedArgumentValue(16, DBNull.Value, typeof(DBNull).FullName); + Assert.IsNull(values.GetArgumentValue(100, typeof(string)), "Mmm... managed to get a non null instance back from an instance that should have now't with the specified Type."); + ConstructorArgumentValues.ValueHolder value = + values.GetArgumentValue(-3, typeof(DBNull)); + Assert.IsNotNull(value, "Stored a value of a specified Type at a specified index, but got null when retrieving it using the wrong index but the correct Type."); + Assert.AreSame(DBNull.Value, value.Value, "The retrieved value was not the exact same instance as was added."); - [Test] - public void AddAllDoesntChokeOnNullArgument() - { - ConstructorArgumentValues values = new ConstructorArgumentValues(); - values.AddAll(null); - } + value = values.GetArgumentValue("foo", typeof(DBNull)); + Assert.IsNotNull(value, "Stored a value of a specified Type under a name, but got null when retrieving it using the wrong name but the correct Type."); + Assert.AreSame(DBNull.Value, value.Value, "The retrieved value was not the exact same instance as was added."); + } - [Test] - public void AddAllFromOther() - { - ConstructorArgumentValues other = new ConstructorArgumentValues(); - other.AddIndexedArgumentValue(1, DBNull.Value); - other.AddIndexedArgumentValue(2, "Foo"); - other.AddIndexedArgumentValue(3, 3); + [Test] + public void AddAllDoesntChokeOnNullArgument() + { + ConstructorArgumentValues values = new ConstructorArgumentValues(); + values.AddAll(null); + } - ConstructorArgumentValues values = new ConstructorArgumentValues(); - values.AddAll(other); - Assert.AreEqual(other.ArgumentCount, values.ArgumentCount, - "Must have been the same since one was filled up with the values in the other."); - } + [Test] + public void AddAllFromOther() + { + ConstructorArgumentValues other = new ConstructorArgumentValues(); + other.AddIndexedArgumentValue(1, DBNull.Value); + other.AddIndexedArgumentValue(2, "Foo"); + other.AddIndexedArgumentValue(3, 3); - [Test] - public void AddRangeOfIndexedArgumentValues() - { - ConstructorArgumentValues values = new ConstructorArgumentValues(); - values.AddIndexedArgumentValue(1, DBNull.Value); - values.AddIndexedArgumentValue(2, "Foo"); - values.AddIndexedArgumentValue(3, 3); - new ConstructorArgumentValues(values); - Assert.IsFalse(values.Empty, "Added three indexed values(as a range), but the collection is sayin' it's empty."); - Assert.AreEqual(3, values.ArgumentCount, "Added three indexed values(as a range), but the collection ain't sayin' that it's got 3 elements in it."); - Assert.AreEqual(3, values.IndexedArgumentValues.Count, "Added three indexed values(as a range), but the collection of indexed values ain't sayin' that it's got 3 elements in it."); - } + ConstructorArgumentValues values = new ConstructorArgumentValues(); + values.AddAll(other); + Assert.AreEqual(other.ArgumentCount, values.ArgumentCount, + "Must have been the same since one was filled up with the values in the other."); + } - [Test] - public void NamedArgumentsAreCaseInsensitive() - { - ConstructorArgumentValues values = new ConstructorArgumentValues(); - values.AddNamedArgumentValue("foo", "sball"); - Assert.AreEqual(1, values.NamedArgumentValues.Count, "Added one named argument but it doesn't seem to have been added to the named arguments collection."); - Assert.AreEqual(1, values.ArgumentCount, "Added one named argument but it doesn't seem to be reflected in the overall argument count."); - Assert.IsTrue(values.ContainsNamedArgument("FOo"), "Mmm, the ContainsNamedArgument() method eveidently IS case sensitive (which is wrong)."); - ConstructorArgumentValues.ValueHolder arg = values.GetNamedArgumentValue("fOo"); - Assert.IsNotNull(arg, "The named argument previously added could not be pulled from the ctor arg collection."); - Assert.AreEqual("sball", arg.Value, "The value of the named argument passed in is not the same as the one that was pulled out."); - } + [Test] + public void AddRangeOfIndexedArgumentValues() + { + ConstructorArgumentValues values = new ConstructorArgumentValues(); + values.AddIndexedArgumentValue(1, DBNull.Value); + values.AddIndexedArgumentValue(2, "Foo"); + values.AddIndexedArgumentValue(3, 3); + new ConstructorArgumentValues(values); + Assert.IsFalse(values.Empty, "Added three indexed values(as a range), but the collection is sayin' it's empty."); + Assert.AreEqual(3, values.ArgumentCount, "Added three indexed values(as a range), but the collection ain't sayin' that it's got 3 elements in it."); + Assert.AreEqual(3, values.IndexedArgumentValues.Count, "Added three indexed values(as a range), but the collection of indexed values ain't sayin' that it's got 3 elements in it."); + } - [Test] - public void AddNamedArgument() - { - ConstructorArgumentValues values = new ConstructorArgumentValues(); - values.AddNamedArgumentValue("foo", "sball"); - Assert.AreEqual(1, values.NamedArgumentValues.Count, "Added one named argument but it doesn't seem to have been added to the named arguments collection."); - Assert.AreEqual(1, values.ArgumentCount, "Added one named argument but it doesn't seem to be reflected in the overall argument count."); - ConstructorArgumentValues.ValueHolder arg = values.GetNamedArgumentValue("foo"); - Assert.IsNotNull(arg, "The named argument previously added could not be pulled from the ctor arg collection."); - Assert.AreEqual("sball", arg.Value, "The value of the named argument passed in is not the same as the one that was pulled out."); - } + [Test] + public void NamedArgumentsAreCaseInsensitive() + { + ConstructorArgumentValues values = new ConstructorArgumentValues(); + values.AddNamedArgumentValue("foo", "sball"); + Assert.AreEqual(1, values.NamedArgumentValues.Count, "Added one named argument but it doesn't seem to have been added to the named arguments collection."); + Assert.AreEqual(1, values.ArgumentCount, "Added one named argument but it doesn't seem to be reflected in the overall argument count."); + Assert.IsTrue(values.ContainsNamedArgument("FOo"), "Mmm, the ContainsNamedArgument() method eveidently IS case sensitive (which is wrong)."); + ConstructorArgumentValues.ValueHolder arg = values.GetNamedArgumentValue("fOo"); + Assert.IsNotNull(arg, "The named argument previously added could not be pulled from the ctor arg collection."); + Assert.AreEqual("sball", arg.Value, "The value of the named argument passed in is not the same as the one that was pulled out."); + } - [Test] - public void AddNamedArgumentFromAotherCtorArgCollection() - { - ConstructorArgumentValues values = new ConstructorArgumentValues(); - values.AddNamedArgumentValue("foo", "sball"); - ConstructorArgumentValues copy = new ConstructorArgumentValues(values); - Assert.AreEqual(1, copy.NamedArgumentValues.Count, "Added one named argument but it doesn't seem to have been added to the named arguments collection."); - Assert.AreEqual(1, copy.ArgumentCount, "Added one named argument but it doesn't seem to be reflected in the overall argument count."); - ConstructorArgumentValues.ValueHolder arg = copy.GetNamedArgumentValue("foo"); - Assert.IsNotNull(arg, "The named argument previously added could not be pulled from the ctor arg collection."); - Assert.AreEqual("sball", arg.Value, "The value of the named argument passed in is not the same as the one that was pulled out."); - } + [Test] + public void AddNamedArgument() + { + ConstructorArgumentValues values = new ConstructorArgumentValues(); + values.AddNamedArgumentValue("foo", "sball"); + Assert.AreEqual(1, values.NamedArgumentValues.Count, "Added one named argument but it doesn't seem to have been added to the named arguments collection."); + Assert.AreEqual(1, values.ArgumentCount, "Added one named argument but it doesn't seem to be reflected in the overall argument count."); + ConstructorArgumentValues.ValueHolder arg = values.GetNamedArgumentValue("foo"); + Assert.IsNotNull(arg, "The named argument previously added could not be pulled from the ctor arg collection."); + Assert.AreEqual("sball", arg.Value, "The value of the named argument passed in is not the same as the one that was pulled out."); + } - [Test] - public void ValueHolderToStringsNicely() - { - ConstructorArgumentValues values = new ConstructorArgumentValues(); - values.AddGenericArgumentValue(1, typeof(int).FullName); - ConstructorArgumentValues.ValueHolder vh = values.GetGenericArgumentValue(typeof(int)); - Assert.AreEqual("'1' [System.Int32]", vh.ToString()); - } - } -} \ No newline at end of file + [Test] + public void AddNamedArgumentFromAotherCtorArgCollection() + { + ConstructorArgumentValues values = new ConstructorArgumentValues(); + values.AddNamedArgumentValue("foo", "sball"); + ConstructorArgumentValues copy = new ConstructorArgumentValues(values); + Assert.AreEqual(1, copy.NamedArgumentValues.Count, "Added one named argument but it doesn't seem to have been added to the named arguments collection."); + Assert.AreEqual(1, copy.ArgumentCount, "Added one named argument but it doesn't seem to be reflected in the overall argument count."); + ConstructorArgumentValues.ValueHolder arg = copy.GetNamedArgumentValue("foo"); + Assert.IsNotNull(arg, "The named argument previously added could not be pulled from the ctor arg collection."); + Assert.AreEqual("sball", arg.Value, "The value of the named argument passed in is not the same as the one that was pulled out."); + } + + [Test] + public void ValueHolderToStringsNicely() + { + ConstructorArgumentValues values = new ConstructorArgumentValues(); + values.AddGenericArgumentValue(1, typeof(int).FullName); + ConstructorArgumentValues.ValueHolder vh = values.GetGenericArgumentValue(typeof(int)); + Assert.AreEqual("'1' [System.Int32]", vh.ToString()); + } +} diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/CustomConverterConfigurerTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/CustomConverterConfigurerTests.cs index 4c7eab92..ca6cad77 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/CustomConverterConfigurerTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/CustomConverterConfigurerTests.cs @@ -21,92 +21,89 @@ using System.Collections; using System.ComponentModel; using System.Drawing; - using FakeItEasy; - using NUnit.Framework; -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Unit tests for the CustomConverterConfigurer class. +/// +/// Rick Evans +[TestFixture] +public sealed class CustomConverterConfigurerTests { - /// - /// Unit tests for the CustomConverterConfigurer class. - /// - /// Rick Evans - [TestFixture] - public sealed class CustomConverterConfigurerTests + private IConfigurableListableObjectFactory factory; + + [SetUp] + public void SetUp() { - private IConfigurableListableObjectFactory factory; + factory = A.Fake(); + } - [SetUp] - public void SetUp() - { - factory = A.Fake(); - } + [Test] + public void UseInvalidKeyForConverterMapKey() + { + IDictionary converters = new Hashtable(); + converters.Add(12, typeof(DateTimeConverter)); - [Test] - public void UseInvalidKeyForConverterMapKey() - { - IDictionary converters = new Hashtable(); - converters.Add(12, typeof(DateTimeConverter)); + CustomConverterConfigurer config = new CustomConverterConfigurer(); + config.CustomConverters = converters; + Assert.Throws(() => config.PostProcessObjectFactory(factory)); + } - CustomConverterConfigurer config = new CustomConverterConfigurer(); - config.CustomConverters = converters; - Assert.Throws(() => config.PostProcessObjectFactory(factory)); - } + [Test] + public void UseNonTypeConverterForConverterMapValue() + { + IDictionary converters = new Hashtable(); + converters.Add(typeof(DateTime), null); - [Test] - public void UseNonTypeConverterForConverterMapValue() - { - IDictionary converters = new Hashtable(); - converters.Add( typeof(DateTime), null); + CustomConverterConfigurer config = new CustomConverterConfigurer(); + config.CustomConverters = converters; + Assert.Throws(() => config.PostProcessObjectFactory(factory)); + } - CustomConverterConfigurer config = new CustomConverterConfigurer(); - config.CustomConverters = converters; - Assert.Throws(() => config.PostProcessObjectFactory(factory)); - } + [Test] + public void UseNonResolvableTypeForConverterMapKey() + { + IDictionary converters = new Hashtable(); + // purposely misspelled... :D + converters.Add("Systemm.Date", typeof(DateTimeConverter)); - [Test] - public void UseNonResolvableTypeForConverterMapKey() - { - IDictionary converters = new Hashtable(); - // purposely misspelled... :D - converters.Add("Systemm.Date", typeof(DateTimeConverter)); + CustomConverterConfigurer config = new CustomConverterConfigurer(); + config.CustomConverters = converters; + Assert.Throws(() => config.PostProcessObjectFactory(factory)); + } - CustomConverterConfigurer config = new CustomConverterConfigurer(); - config.CustomConverters = converters; - Assert.Throws(() => config.PostProcessObjectFactory(factory)); - } + /// + /// Just tests that the configurer doesn't blow up and + /// doesn't register anything ('cos we ain't supplied anything). + /// + [Test] + public void DontSupplyAnyCustomConverters() + { + CustomConverterConfigurer config = new CustomConverterConfigurer(); + config.CustomConverters = null; + config.PostProcessObjectFactory(factory); + } - /// - /// Just tests that the configurer doesn't blow up and - /// doesn't register anything ('cos we ain't supplied anything). - /// - [Test] - public void DontSupplyAnyCustomConverters() - { - CustomConverterConfigurer config = new CustomConverterConfigurer(); - config.CustomConverters = null; - config.PostProcessObjectFactory(factory); - } + [Test] + public void SunnyDayScenario() + { + IDictionary converters = new Hashtable(); + Type dateTimeType = typeof(DateTime); + DateTimeConverter dateTimeConverter = new DateTimeConverter(); + Type colorType = typeof(Color); + ColorConverter colorConverter = new ColorConverter(); - [Test] - public void SunnyDayScenario() - { - IDictionary converters = new Hashtable(); - Type dateTimeType = typeof(DateTime); - DateTimeConverter dateTimeConverter = new DateTimeConverter(); - Type colorType = typeof(Color); - ColorConverter colorConverter = new ColorConverter(); + converters.Add(dateTimeType, dateTimeConverter); + converters.Add(colorType, colorConverter); - converters.Add(dateTimeType, dateTimeConverter); - converters.Add(colorType, colorConverter); + factory.RegisterCustomConverter(dateTimeType, dateTimeConverter); + factory.RegisterCustomConverter(colorType, colorConverter); - factory.RegisterCustomConverter(dateTimeType, dateTimeConverter); - factory.RegisterCustomConverter(colorType, colorConverter); - - CustomConverterConfigurer config = new CustomConverterConfigurer(); - config.CustomConverters = converters; - config.PostProcessObjectFactory(factory); - } + CustomConverterConfigurer config = new CustomConverterConfigurer(); + config.CustomConverters = converters; + config.PostProcessObjectFactory(factory); } } diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/DelegateFactoryObjectTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/DelegateFactoryObjectTests.cs index d3b27d13..31267b7a 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/DelegateFactoryObjectTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/DelegateFactoryObjectTests.cs @@ -25,146 +25,145 @@ using Spring.Util; #endregion -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Unit tests for the DelegateFactoryObject class. +/// +/// Rick Evans +[TestFixture] +public sealed class DelegateFactoryObjectTests { - /// - /// Unit tests for the DelegateFactoryObject class. - /// - /// Rick Evans - [TestFixture] - public sealed class DelegateFactoryObjectTests - { - [Test] - public void StaticDelegateWithInstanceMethod() - { - DelegateFactoryObject fob = new DelegateFactoryObject(); - fob.DelegateType = typeof (PopHandler); - fob.TargetType = typeof (OneThirstyDude); - fob.MethodName = "HandlePop"; - fob.IsSingleton = false; - fob.AfterPropertiesSet(); - Assert.Throws(() => fob.GetObject()); - } + [Test] + public void StaticDelegateWithInstanceMethod() + { + DelegateFactoryObject fob = new DelegateFactoryObject(); + fob.DelegateType = typeof(PopHandler); + fob.TargetType = typeof(OneThirstyDude); + fob.MethodName = "HandlePop"; + fob.IsSingleton = false; + fob.AfterPropertiesSet(); + Assert.Throws(() => fob.GetObject()); + } - [Test] - public void StaticDelegate() - { - DelegateFactoryObject fob = new DelegateFactoryObject(); - fob.DelegateType = typeof (PopHandler); - fob.TargetType = typeof (OneThirstyDude); - fob.MethodName = "StaticHandlePop"; - fob.IsSingleton = false; - fob.AfterPropertiesSet(); - PopHandler popper = (PopHandler) fob.GetObject(); - Assert.IsNotNull(popper); - Assert.AreEqual(fob.MethodName, popper.Method.Name); - } + [Test] + public void StaticDelegate() + { + DelegateFactoryObject fob = new DelegateFactoryObject(); + fob.DelegateType = typeof(PopHandler); + fob.TargetType = typeof(OneThirstyDude); + fob.MethodName = "StaticHandlePop"; + fob.IsSingleton = false; + fob.AfterPropertiesSet(); + PopHandler popper = (PopHandler) fob.GetObject(); + Assert.IsNotNull(popper); + Assert.AreEqual(fob.MethodName, popper.Method.Name); + } - [Test] - public void InstanceSingletonDelegate() - { - DelegateFactoryObject fob = new DelegateFactoryObject(); - fob.DelegateType = typeof (PopHandler); - OneThirstyDude dude = new OneThirstyDude(); - fob.TargetObject = dude; - fob.MethodName = "HandlePop"; - fob.AfterPropertiesSet(); - PopHandler popper = (PopHandler) fob.GetObject(); - Assert.IsNotNull(popper); - Assert.AreEqual(fob.MethodName, popper.Method.Name); - string soda = "The Drink Of Champions"; - popper(this, soda); - Assert.AreEqual(soda, dude.Soda); - PopHandler other = (PopHandler) fob.GetObject(); - Assert.IsTrue(ReferenceEquals(popper, other)); - } + [Test] + public void InstanceSingletonDelegate() + { + DelegateFactoryObject fob = new DelegateFactoryObject(); + fob.DelegateType = typeof(PopHandler); + OneThirstyDude dude = new OneThirstyDude(); + fob.TargetObject = dude; + fob.MethodName = "HandlePop"; + fob.AfterPropertiesSet(); + PopHandler popper = (PopHandler) fob.GetObject(); + Assert.IsNotNull(popper); + Assert.AreEqual(fob.MethodName, popper.Method.Name); + string soda = "The Drink Of Champions"; + popper(this, soda); + Assert.AreEqual(soda, dude.Soda); + PopHandler other = (PopHandler) fob.GetObject(); + Assert.IsTrue(ReferenceEquals(popper, other)); + } - [Test] - public void InstancePrototypeDelegate() - { - DelegateFactoryObject fob = new DelegateFactoryObject(); - fob.IsSingleton = false; - fob.DelegateType = typeof (PopHandler); - OneThirstyDude dude = new OneThirstyDude(); - fob.TargetObject = dude; - fob.MethodName = "HandlePop"; - fob.IsSingleton = false; - fob.AfterPropertiesSet(); - PopHandler one = (PopHandler) fob.GetObject(); - PopHandler two = (PopHandler) fob.GetObject(); - Assert.IsFalse(ReferenceEquals(one, two)); - } + [Test] + public void InstancePrototypeDelegate() + { + DelegateFactoryObject fob = new DelegateFactoryObject(); + fob.IsSingleton = false; + fob.DelegateType = typeof(PopHandler); + OneThirstyDude dude = new OneThirstyDude(); + fob.TargetObject = dude; + fob.MethodName = "HandlePop"; + fob.IsSingleton = false; + fob.AfterPropertiesSet(); + PopHandler one = (PopHandler) fob.GetObject(); + PopHandler two = (PopHandler) fob.GetObject(); + Assert.IsFalse(ReferenceEquals(one, two)); + } - [Test] - public void ObjectType() - { - DelegateFactoryObject fob = new DelegateFactoryObject(); - Assert.IsNotNull(fob.ObjectType, "Should never be null (should default to typeof(Delegate)) "); - Assert.AreEqual(typeof (Delegate), fob.ObjectType, "Not defaulting to typeof(Delegate)."); - } + [Test] + public void ObjectType() + { + DelegateFactoryObject fob = new DelegateFactoryObject(); + Assert.IsNotNull(fob.ObjectType, "Should never be null (should default to typeof(Delegate)) "); + Assert.AreEqual(typeof(Delegate), fob.ObjectType, "Not defaulting to typeof(Delegate)."); + } - [Test] - public void MissingDelegateType() - { - DelegateFactoryObject fob = new DelegateFactoryObject(); - Assert.Throws(() => fob.AfterPropertiesSet()); - } + [Test] + public void MissingDelegateType() + { + DelegateFactoryObject fob = new DelegateFactoryObject(); + Assert.Throws(() => fob.AfterPropertiesSet()); + } - [Test] - public void BadDelegateType() - { - DelegateFactoryObject fob = new DelegateFactoryObject(); - fob.DelegateType = DBNull.Value.GetType(); - Assert.Throws(() => fob.AfterPropertiesSet()); - } + [Test] + public void BadDelegateType() + { + DelegateFactoryObject fob = new DelegateFactoryObject(); + fob.DelegateType = DBNull.Value.GetType(); + Assert.Throws(() => fob.AfterPropertiesSet()); + } - [Test] - public void NullMethodName() - { - DelegateFactoryObject fob = new DelegateFactoryObject(); - fob.DelegateType = typeof (EventHandler); - fob.TargetType = typeof (OneThirstyDude); - Assert.Throws(() => fob.AfterPropertiesSet()); - } + [Test] + public void NullMethodName() + { + DelegateFactoryObject fob = new DelegateFactoryObject(); + fob.DelegateType = typeof(EventHandler); + fob.TargetType = typeof(OneThirstyDude); + Assert.Throws(() => fob.AfterPropertiesSet()); + } - [Test] - public void EmptyMethodName() - { - DelegateFactoryObject fob = new DelegateFactoryObject(); - fob.DelegateType = typeof (EventHandler); - fob.TargetType = typeof (OneThirstyDude); - fob.MethodName = string.Empty; - Assert.Throws(() => fob.AfterPropertiesSet()); - } + [Test] + public void EmptyMethodName() + { + DelegateFactoryObject fob = new DelegateFactoryObject(); + fob.DelegateType = typeof(EventHandler); + fob.TargetType = typeof(OneThirstyDude); + fob.MethodName = string.Empty; + Assert.Throws(() => fob.AfterPropertiesSet()); + } - [Test] - public void WhitespacedMethodName() - { - DelegateFactoryObject fob = new DelegateFactoryObject(); - fob.DelegateType = typeof (EventHandler); - fob.TargetType = typeof (OneThirstyDude); - fob.MethodName = "\n"; - Assert.Throws(() => fob.AfterPropertiesSet()); - } + [Test] + public void WhitespacedMethodName() + { + DelegateFactoryObject fob = new DelegateFactoryObject(); + fob.DelegateType = typeof(EventHandler); + fob.TargetType = typeof(OneThirstyDude); + fob.MethodName = "\n"; + Assert.Throws(() => fob.AfterPropertiesSet()); + } - [Test] - public void MissingATarget() - { - DelegateFactoryObject fob = new DelegateFactoryObject(); - fob.DelegateType = typeof (EventHandler); - fob.MethodName = "I Love You Laura Palmer, I Really Do"; - Assert.Throws(() => fob.AfterPropertiesSet()); - } + [Test] + public void MissingATarget() + { + DelegateFactoryObject fob = new DelegateFactoryObject(); + fob.DelegateType = typeof(EventHandler); + fob.MethodName = "I Love You Laura Palmer, I Really Do"; + Assert.Throws(() => fob.AfterPropertiesSet()); + } - [Test] - public void ChokesIfBothTargetTypeAndTargetObjectSupplied() - { - DelegateFactoryObject fob = new DelegateFactoryObject(); - fob.DelegateType = typeof (PopHandler); - fob.TargetType = typeof (OneThirstyDude); - fob.TargetObject = new OneThirstyDude(); - fob.MethodName = "I Love You Laura Palmer, I Really Do"; - Assert.Throws(() => fob.AfterPropertiesSet()); - } - } -} \ No newline at end of file + [Test] + public void ChokesIfBothTargetTypeAndTargetObjectSupplied() + { + DelegateFactoryObject fob = new DelegateFactoryObject(); + fob.DelegateType = typeof(PopHandler); + fob.TargetType = typeof(OneThirstyDude); + fob.TargetObject = new OneThirstyDude(); + fob.MethodName = "I Love You Laura Palmer, I Really Do"; + Assert.Throws(() => fob.AfterPropertiesSet()); + } +} diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/DelegateObjectFactoryConfigurerTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/DelegateObjectFactoryConfigurerTests.cs index f5c752bf..e51b302f 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/DelegateObjectFactoryConfigurerTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/DelegateObjectFactoryConfigurerTests.cs @@ -1,19 +1,19 @@ #region License -/* - * Copyright 2002-2010 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. +/* + * Copyright 2002-2010 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 @@ -22,49 +22,48 @@ using NUnit.Framework; using Spring.Context; using Spring.Context.Support; -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// +/// Erich Eichinger +[TestFixture] +public class DelegateObjectFactoryConfigurerIntegrationTests { - /// - /// - /// Erich Eichinger - [TestFixture] - public class DelegateObjectFactoryConfigurerIntegrationTests + private class MockObjectFactoryPostProcessor : IObjectFactoryPostProcessor { - private class MockObjectFactoryPostProcessor : IObjectFactoryPostProcessor + public bool Called; + + public void PostProcessObjectFactory(IConfigurableListableObjectFactory factory) { - public bool Called; - - public void PostProcessObjectFactory(IConfigurableListableObjectFactory factory) - { - Called = true; - } - } - - [Test] - public void ExecutesBeforeObjectFactoryPostProcessing() - { - MockObjectFactoryPostProcessor mofp = new MockObjectFactoryPostProcessor(); - - IConfigurableApplicationContext ctx = new XmlApplicationContext(false, "name", false, null); - ctx.AddObjectFactoryPostProcessor(new DelegateObjectFactoryConfigurer(of => of.RegisterSingleton("mofp", mofp))); - - ctx.Refresh(); - Assert.IsTrue(mofp.Called); - } - - [Test] - public void CanBeUsedToReconfigureAnApplicationContextOnRefresh() - { - MockObjectFactoryPostProcessor mofp = new MockObjectFactoryPostProcessor(); - - IConfigurableApplicationContext ctx = new XmlApplicationContext(false, "name", false, null); - ctx.AddObjectFactoryPostProcessor(new DelegateObjectFactoryConfigurer(of => of.RegisterSingleton("mofp", mofp))); - - ctx.Refresh(); - - mofp.Called = false; - ctx.Refresh(); - Assert.IsTrue(mofp.Called); + Called = true; } } + + [Test] + public void ExecutesBeforeObjectFactoryPostProcessing() + { + MockObjectFactoryPostProcessor mofp = new MockObjectFactoryPostProcessor(); + + IConfigurableApplicationContext ctx = new XmlApplicationContext(false, "name", false, null); + ctx.AddObjectFactoryPostProcessor(new DelegateObjectFactoryConfigurer(of => of.RegisterSingleton("mofp", mofp))); + + ctx.Refresh(); + Assert.IsTrue(mofp.Called); + } + + [Test] + public void CanBeUsedToReconfigureAnApplicationContextOnRefresh() + { + MockObjectFactoryPostProcessor mofp = new MockObjectFactoryPostProcessor(); + + IConfigurableApplicationContext ctx = new XmlApplicationContext(false, "name", false, null); + ctx.AddObjectFactoryPostProcessor(new DelegateObjectFactoryConfigurer(of => of.RegisterSingleton("mofp", mofp))); + + ctx.Refresh(); + + mofp.Called = false; + ctx.Refresh(); + Assert.IsTrue(mofp.Called); + } } diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/DestructionAwareObjectPostProcessorTest.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/DestructionAwareObjectPostProcessorTest.cs index 1b953ee3..7f7a727c 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/DestructionAwareObjectPostProcessorTest.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/DestructionAwareObjectPostProcessorTest.cs @@ -22,64 +22,62 @@ using NUnit.Framework; using Spring.Context.Support; using Spring.Objects.Factory.Support; -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +[TestFixture] +public class DestructionAwareObjectPostProcessorTest { - [TestFixture] - public class DestructionAwareObjectPostProcessorTest + private GenericApplicationContext _context; + + [SetUp] + public void Setup() { - private GenericApplicationContext _context; + _context = new GenericApplicationContext(); - [SetUp] - public void Setup() - { - _context = new GenericApplicationContext(); + var objectDefinition = new RootObjectDefinition(typeof(DestructionPostProcessor)); + objectDefinition.Role = ObjectRole.ROLE_INFRASTRUCTURE; + _context.ObjectFactory.RegisterObjectDefinition("DestructionPostProcessor", objectDefinition); - var objectDefinition = new RootObjectDefinition(typeof(DestructionPostProcessor)); - objectDefinition.Role = ObjectRole.ROLE_INFRASTRUCTURE; - _context.ObjectFactory.RegisterObjectDefinition("DestructionPostProcessor", objectDefinition); + var objectDef = new RootObjectDefinition(typeof(DestroyTester)); + _context.ObjectFactory.RegisterObjectDefinition("DestroyTester", objectDef); - var objectDef = new RootObjectDefinition(typeof(DestroyTester)); - _context.ObjectFactory.RegisterObjectDefinition("DestroyTester", objectDef); - - _context.Refresh(); - } - - [Test] - public void PostProcessBeforeDestructionIsCalled() - { - var testObj = _context.GetObject("DestroyTester"); - _context.Dispose(); - - Assert.That(DestructionTester.MethodCalled, Is.EqualTo(1)); - } + _context.Refresh(); } - public class DestructionPostProcessor : IDestructionAwareObjectPostProcessor + [Test] + public void PostProcessBeforeDestructionIsCalled() { - public void PostProcessBeforeDestruction(object instance, string name) - { - if (instance.GetType() == typeof(DestroyTester)) - DestructionTester.MethodCalled++; - } + var testObj = _context.GetObject("DestroyTester"); + _context.Dispose(); - public object PostProcessBeforeInitialization(object instance, string name) - { - return instance; - } - - public object PostProcessAfterInitialization(object instance, string objectName) - { - return instance; - } - } - - public class DestroyTester - { - - } - - public static class DestructionTester - { - public static int MethodCalled { get; set; } + Assert.That(DestructionTester.MethodCalled, Is.EqualTo(1)); } } + +public class DestructionPostProcessor : IDestructionAwareObjectPostProcessor +{ + public void PostProcessBeforeDestruction(object instance, string name) + { + if (instance.GetType() == typeof(DestroyTester)) + DestructionTester.MethodCalled++; + } + + public object PostProcessBeforeInitialization(object instance, string name) + { + return instance; + } + + public object PostProcessAfterInitialization(object instance, string objectName) + { + return instance; + } +} + +public class DestroyTester +{ +} + +public static class DestructionTester +{ + public static int MethodCalled { get; set; } +} diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/DictionaryFactoryObjectTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/DictionaryFactoryObjectTests.cs index c0524c24..5ebbafb1 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/DictionaryFactoryObjectTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/DictionaryFactoryObjectTests.cs @@ -21,91 +21,90 @@ using System.Collections; using NUnit.Framework; -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Unit tests for the DictionaryFactoryObject class. +/// +/// Rick Evans +[TestFixture] +public sealed class DictionaryFactoryObjectTests { - /// - /// Unit tests for the DictionaryFactoryObject class. - /// - /// Rick Evans - [TestFixture] - public sealed class DictionaryFactoryObjectTests - { - [Test] - public void SetTargetDictionaryTypeToNonDictionaryType() - { - DictionaryFactoryObject dfo = new DictionaryFactoryObject(); - Assert.Throws(() => dfo.TargetDictionaryType = typeof (ICollection), "The Type passed to the TargetDictionaryType property must implement the 'System.Collections.IDictionary' interface."); - } + [Test] + public void SetTargetDictionaryTypeToNonDictionaryType() + { + DictionaryFactoryObject dfo = new DictionaryFactoryObject(); + Assert.Throws(() => dfo.TargetDictionaryType = typeof(ICollection), "The Type passed to the TargetDictionaryType property must implement the 'System.Collections.IDictionary' interface."); + } - [Test] - public void SetTargetDictionaryTypeToDerivedIDictionaryInterfaceType() - { - DictionaryFactoryObject dfo = new DictionaryFactoryObject(); - Assert.Throws(() => dfo.TargetDictionaryType = typeof (IExtendedDictionary), "The Type passed to the TargetDictionaryType property cannot be an interface; it must be a concrete class that implements the 'System.Collections.IDictionary' interface."); - } + [Test] + public void SetTargetDictionaryTypeToDerivedIDictionaryInterfaceType() + { + DictionaryFactoryObject dfo = new DictionaryFactoryObject(); + Assert.Throws(() => dfo.TargetDictionaryType = typeof(IExtendedDictionary), "The Type passed to the TargetDictionaryType property cannot be an interface; it must be a concrete class that implements the 'System.Collections.IDictionary' interface."); + } - [Test] - public void SetTargetDictionaryTypeToAbstractIDictionaryInterfaceType() - { - DictionaryFactoryObject dfo = new DictionaryFactoryObject(); - Assert.Throws(() => dfo.TargetDictionaryType = typeof (AbstractDictionary), "The Type passed to the TargetDictionaryType property cannot be abstract (MustInherit in VisualBasic.NET); it must be a concrete class that implements the 'System.Collections.IDictionary' interface."); - } + [Test] + public void SetTargetDictionaryTypeToAbstractIDictionaryInterfaceType() + { + DictionaryFactoryObject dfo = new DictionaryFactoryObject(); + Assert.Throws(() => dfo.TargetDictionaryType = typeof(AbstractDictionary), "The Type passed to the TargetDictionaryType property cannot be abstract (MustInherit in VisualBasic.NET); it must be a concrete class that implements the 'System.Collections.IDictionary' interface."); + } - private interface IExtendedDictionary : IDictionary - { - } + private interface IExtendedDictionary : IDictionary + { + } - private abstract class AbstractDictionary : Hashtable - { - } + private abstract class AbstractDictionary : Hashtable + { + } - [Test] - public void SetTargetDictionaryTypeToNull() - { - DictionaryFactoryObject dfo = new DictionaryFactoryObject(); - Assert.Throws(() => dfo.TargetDictionaryType = null); - } + [Test] + public void SetTargetDictionaryTypeToNull() + { + DictionaryFactoryObject dfo = new DictionaryFactoryObject(); + Assert.Throws(() => dfo.TargetDictionaryType = null); + } - [Test] - public void GetObjectWithoutSupplyingASourceDictionary() - { - DictionaryFactoryObject dfo = new DictionaryFactoryObject(); - dfo.IsSingleton = false; - Assert.Throws(() => dfo.GetObject(), "The 'SourceDictionary' property cannot be null (Nothing in Visual Basic.NET)."); - } + [Test] + public void GetObjectWithoutSupplyingASourceDictionary() + { + DictionaryFactoryObject dfo = new DictionaryFactoryObject(); + dfo.IsSingleton = false; + Assert.Throws(() => dfo.GetObject(), "The 'SourceDictionary' property cannot be null (Nothing in Visual Basic.NET)."); + } - [Test] - public void ObjectTypeReallyIsIDictionary() - { - Assert.AreEqual(typeof (IDictionary), new DictionaryFactoryObject().ObjectType); - } + [Test] + public void ObjectTypeReallyIsIDictionary() + { + Assert.AreEqual(typeof(IDictionary), new DictionaryFactoryObject().ObjectType); + } - [Test] - public void GetObjectReallyDoesPopulateANewIDictionaryInstanceWithTheElementsOfTheSourceDictionary() - { - // man, that has got to be my longest ever test name :D ... - IDictionary source = new Hashtable(); - TestObject rick = new TestObject("Rick", 30); - source.Add(rick.Name, rick); - TestObject mark = new TestObject("Mark", 35); - source.Add(mark.Name, mark); - TestObject griffin = new TestObject("Griffin", 21); - source.Add(griffin.Name, griffin); + [Test] + public void GetObjectReallyDoesPopulateANewIDictionaryInstanceWithTheElementsOfTheSourceDictionary() + { + // man, that has got to be my longest ever test name :D ... + IDictionary source = new Hashtable(); + TestObject rick = new TestObject("Rick", 30); + source.Add(rick.Name, rick); + TestObject mark = new TestObject("Mark", 35); + source.Add(mark.Name, mark); + TestObject griffin = new TestObject("Griffin", 21); + source.Add(griffin.Name, griffin); - DictionaryFactoryObject dfo = new DictionaryFactoryObject(); - dfo.SourceDictionary = source; - dfo.AfterPropertiesSet(); + DictionaryFactoryObject dfo = new DictionaryFactoryObject(); + dfo.SourceDictionary = source; + dfo.AfterPropertiesSet(); - IDictionary dic = (IDictionary) dfo.GetObject(); - Assert.IsNotNull(dic); - Assert.AreEqual(source.Count, dic.Count); - foreach (DictionaryEntry entry in dic) - { - string name = (string) entry.Key; - TestObject dude = (TestObject) entry.Value; - TestObject originalDude = (TestObject) source[name]; - Assert.IsTrue(object.ReferenceEquals(dude, originalDude)); - } - } - } + IDictionary dic = (IDictionary) dfo.GetObject(); + Assert.IsNotNull(dic); + Assert.AreEqual(source.Count, dic.Count); + foreach (DictionaryEntry entry in dic) + { + string name = (string) entry.Key; + TestObject dude = (TestObject) entry.Value; + TestObject originalDude = (TestObject) source[name]; + Assert.IsTrue(object.ReferenceEquals(dude, originalDude)); + } + } } diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/DictionaryVariableSourceTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/DictionaryVariableSourceTests.cs index 678daf6f..ba5b22cc 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/DictionaryVariableSourceTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/DictionaryVariableSourceTests.cs @@ -1,143 +1,141 @@ using System.Collections; using NUnit.Framework; -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +[TestFixture] +public class DictionaryVariableSourceTests { - [TestFixture] - public class DictionaryVariableSourceTests + [Test] + public void CanEnumerateDictionary() { - [Test] - public void CanEnumerateDictionary() + DictionaryVariableSource dvs = new DictionaryVariableSource(); + + dvs.Add("key1", "theValue"); + dvs.Add("key2", "theValue"); + + foreach (KeyValuePair dv in dvs) { - DictionaryVariableSource dvs = new DictionaryVariableSource(); - - dvs.Add("key1", "theValue"); - dvs.Add("key2", "theValue"); - - foreach (KeyValuePair dv in dvs) - { - Assert.AreEqual("theValue", dv.Value); - } - + Assert.AreEqual("theValue", dv.Value); } + } - [Test] - public void CanResolveVariable_RespectsCaseInsensitivity() + [Test] + public void CanResolveVariable_RespectsCaseInsensitivity() + { + DictionaryVariableSource caseInsensitive = new DictionaryVariableSource(); + caseInsensitive.Add("key1", "value1"); + + Assert.True(caseInsensitive.CanResolveVariable("KEY1")); + } + + [Test] + public void CanResolveVariable_RespectsCaseSensitivity() + { + DictionaryVariableSource caseSensitive = new DictionaryVariableSource(false); + caseSensitive.Add("KEY1", "value1"); + + Assert.False(caseSensitive.CanResolveVariable("key1")); + } + + [Test] + public void Iniitialize_WithStringArray_FillsKeyValuesInPairs() + { + DictionaryVariableSource dvs = new DictionaryVariableSource(new string[] { "key1", "value1", "key2", "value2" }); + + Assert.AreEqual("value1", dvs.ResolveVariable("key1")); + Assert.AreEqual("value2", dvs.ResolveVariable("key2")); + } + + [Test] + public void Iniitialize_WithStringArray_ThrowsException_WhenOddNumberOfStringsProvided() + { + try { - DictionaryVariableSource caseInsensitive = new DictionaryVariableSource(); - caseInsensitive.Add("key1", "value1"); - - Assert.True(caseInsensitive.CanResolveVariable("KEY1")); + new DictionaryVariableSource(new string[] { "key1", "value1", "key2", "value2", "orphanedKey1" }); + Assert.Fail("Expected ArgumentOutOfRangeException not thrown."); } - - [Test] - public void CanResolveVariable_RespectsCaseSensitivity() + catch (ArgumentOutOfRangeException) { - DictionaryVariableSource caseSensitive = new DictionaryVariableSource(false); - caseSensitive.Add("KEY1", "value1"); - - Assert.False(caseSensitive.CanResolveVariable("key1")); } + } - [Test] - public void Iniitialize_WithStringArray_FillsKeyValuesInPairs() + [Test] + public void Initialize_WithCaseSensitiveFlag_AddsCaseSensitiveKeys() + { + DictionaryVariableSource dvs = new DictionaryVariableSource(false); + dvs.Add("key1", "lowercasevalue"); + dvs.Add("KEY1", "uppercasevalue"); + + Assert.AreEqual("lowercasevalue", dvs.ResolveVariable("key1")); + Assert.AreEqual("uppercasevalue", dvs.ResolveVariable("KEY1")); + } + + [Test] + public void Initialize_WithDictionaryConstructor_AddsCaseInsensitiveKeys() + { + IDictionary dict = new Hashtable(); + dict.Add("key1", "value1"); + dict.Add("KEY2", "value2"); + + DictionaryVariableSource dvs = new DictionaryVariableSource(dict); + + Assert.AreEqual("value1", dvs.ResolveVariable("KEY1")); + Assert.AreEqual("value2", dvs.ResolveVariable("key2")); + } + + [Test] + public void Initialize_WithDictionaryConstructor_AddsKeys() + { + IDictionary dict = new Hashtable(); + dict.Add("key1", "value1"); + dict.Add("key2", "value2"); + + DictionaryVariableSource dvs = new DictionaryVariableSource(dict); + + Assert.AreEqual("value1", dvs.ResolveVariable("key1")); + Assert.AreEqual("value2", dvs.ResolveVariable("key2")); + } + + [Test] + public void Initialize_WithDictionaryConstructorAndCaseSensitiveFlag_AddsCaseSensitiveKeys() + { + IDictionary dict = new Hashtable(); + dict.Add("key1", "lowecasevalue"); + dict.Add("KEY1", "uppercasevalue"); + + DictionaryVariableSource dvs = new DictionaryVariableSource(dict, false); + + Assert.AreEqual("lowecasevalue", dvs.ResolveVariable("key1")); + Assert.AreEqual("uppercasevalue", dvs.ResolveVariable("KEY1")); + } + + [Test] + public void Initialize_WithEmptyConstructor_AddsCaseInsensitiveKeys() + { + DictionaryVariableSource dvs = new DictionaryVariableSource(); + dvs.Add("key1", "value1"); + dvs.Add("KEY2", "value2"); + + Assert.AreEqual("value1", dvs.ResolveVariable("KEY1")); + Assert.AreEqual("value2", dvs.ResolveVariable("key2")); + } + + [Test] + public void Requesting_KeyNotFound_ThrowsException() + { + const string THE_KEY = "key-found"; + + DictionaryVariableSource dvs = new DictionaryVariableSource(); + dvs.Add(THE_KEY, "value-found"); + + try { - DictionaryVariableSource dvs = new DictionaryVariableSource(new string[] { "key1", "value1", "key2", "value2" }); - - Assert.AreEqual("value1", dvs.ResolveVariable("key1")); - Assert.AreEqual("value2", dvs.ResolveVariable("key2")); + dvs.ResolveVariable("not" + THE_KEY); + Assert.Fail("Expected ArgumentException not thrown."); } - - [Test] - public void Iniitialize_WithStringArray_ThrowsException_WhenOddNumberOfStringsProvided() + catch (ArgumentException) { - try - { - new DictionaryVariableSource(new string[] { "key1", "value1", "key2", "value2", "orphanedKey1" }); - Assert.Fail("Expected ArgumentOutOfRangeException not thrown."); - } - catch (ArgumentOutOfRangeException) - { - } - } - - [Test] - public void Initialize_WithCaseSensitiveFlag_AddsCaseSensitiveKeys() - { - DictionaryVariableSource dvs = new DictionaryVariableSource(false); - dvs.Add("key1", "lowercasevalue"); - dvs.Add("KEY1", "uppercasevalue"); - - Assert.AreEqual("lowercasevalue", dvs.ResolveVariable("key1")); - Assert.AreEqual("uppercasevalue", dvs.ResolveVariable("KEY1")); - } - - [Test] - public void Initialize_WithDictionaryConstructor_AddsCaseInsensitiveKeys() - { - IDictionary dict = new Hashtable(); - dict.Add("key1", "value1"); - dict.Add("KEY2", "value2"); - - DictionaryVariableSource dvs = new DictionaryVariableSource(dict); - - Assert.AreEqual("value1", dvs.ResolveVariable("KEY1")); - Assert.AreEqual("value2", dvs.ResolveVariable("key2")); - } - - [Test] - public void Initialize_WithDictionaryConstructor_AddsKeys() - { - IDictionary dict = new Hashtable(); - dict.Add("key1", "value1"); - dict.Add("key2", "value2"); - - DictionaryVariableSource dvs = new DictionaryVariableSource(dict); - - Assert.AreEqual("value1", dvs.ResolveVariable("key1")); - Assert.AreEqual("value2", dvs.ResolveVariable("key2")); - } - - [Test] - public void Initialize_WithDictionaryConstructorAndCaseSensitiveFlag_AddsCaseSensitiveKeys() - { - IDictionary dict = new Hashtable(); - dict.Add("key1", "lowecasevalue"); - dict.Add("KEY1", "uppercasevalue"); - - DictionaryVariableSource dvs = new DictionaryVariableSource(dict, false); - - Assert.AreEqual("lowecasevalue", dvs.ResolveVariable("key1")); - Assert.AreEqual("uppercasevalue", dvs.ResolveVariable("KEY1")); - } - - [Test] - public void Initialize_WithEmptyConstructor_AddsCaseInsensitiveKeys() - { - DictionaryVariableSource dvs = new DictionaryVariableSource(); - dvs.Add("key1", "value1"); - dvs.Add("KEY2", "value2"); - - Assert.AreEqual("value1", dvs.ResolveVariable("KEY1")); - Assert.AreEqual("value2", dvs.ResolveVariable("key2")); - } - - [Test] - public void Requesting_KeyNotFound_ThrowsException() - { - const string THE_KEY = "key-found"; - - DictionaryVariableSource dvs = new DictionaryVariableSource(); - dvs.Add(THE_KEY, "value-found"); - - try - { - dvs.ResolveVariable("not" + THE_KEY); - Assert.Fail("Expected ArgumentException not thrown."); - } - catch (ArgumentException) - { - } } } } diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/EnvironmentVariableSourceTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/EnvironmentVariableSourceTests.cs index dd55eedf..c7f06ba3 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/EnvironmentVariableSourceTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/EnvironmentVariableSourceTests.cs @@ -24,28 +24,26 @@ using NUnit.Framework; #endregion -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Unit tests for the EnvironmentVariableSource class. +/// +/// Aleksandar Seovic +[TestFixture] +public sealed class EnvironmentVariableSourceTests { - /// - /// Unit tests for the EnvironmentVariableSource class. - /// - /// Aleksandar Seovic - [TestFixture] - public sealed class EnvironmentVariableSourceTests + [Test] + public void TestVariablesResolution() { - [Test] - public void TestVariablesResolution() - { - EnvironmentVariableSource vs = new EnvironmentVariableSource(); + EnvironmentVariableSource vs = new EnvironmentVariableSource(); - // existing vars - Assert.AreEqual(Environment.GetEnvironmentVariable("path"), vs.ResolveVariable("path")); - Assert.AreEqual(Environment.GetEnvironmentVariable("PATH"), vs.ResolveVariable("PATH")); - Assert.AreEqual(Environment.GetEnvironmentVariable("ComputerName"), vs.ResolveVariable("computerName")); - - // non-existant variable - Assert.IsNull(vs.ResolveVariable("dummy")); - } + // existing vars + Assert.AreEqual(Environment.GetEnvironmentVariable("path"), vs.ResolveVariable("path")); + Assert.AreEqual(Environment.GetEnvironmentVariable("PATH"), vs.ResolveVariable("PATH")); + Assert.AreEqual(Environment.GetEnvironmentVariable("ComputerName"), vs.ResolveVariable("computerName")); + // non-existant variable + Assert.IsNull(vs.ResolveVariable("dummy")); } } diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/EventValuesTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/EventValuesTests.cs index 92ad6b00..ed6f1f00 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/EventValuesTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/EventValuesTests.cs @@ -1,147 +1,152 @@ using NUnit.Framework; -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +[TestFixture] +public class EventValuesTests { - [TestFixture] - public class EventValuesTests - { - [Test] - public void EmptyEventValues() - { - EventValues eventValues = new EventValues(); - Assert.AreEqual( 0, eventValues.Events.Count ); - } - [Test] - public void OneEventValue() - { - EventValues eventValues = new EventValues(); - eventValues.AddHandler( new MyEventHandler()); - Assert.AreEqual( 1, eventValues.Events.Count ); - } - [Test] - public void TwoEventHandlersForSameEvent() - { - EventValues eventValues = new EventValues(); - eventValues.AddHandler( new MyEventHandler()); - eventValues.AddHandler( new MyEventHandler()); - Assert.AreEqual( 1, eventValues.Events.Count ); - } - [Test] - public void CopyEventHandlerValues() - { - EventValues eventValues = new EventValues(); - eventValues.AddHandler( new MyEventHandler()); - eventValues.AddHandler( new MyEventHandler()); - Assert.AreEqual( 1, eventValues.Events.Count ); - EventValues eventValues2 = new EventValues(eventValues); - Assert.AreEqual( 1, eventValues2.Events.Count ); - } - [Test] - public void NullEventHandlerValue() - { - EventValues eventValues = new EventValues(); - eventValues.AddAll( null ); - Assert.AreEqual( 0, eventValues.Events.Count ); - } - internal class MyEventHandler : IEventHandlerValue - { - #region IEventHandlerValue Members + [Test] + public void EmptyEventValues() + { + EventValues eventValues = new EventValues(); + Assert.AreEqual(0, eventValues.Events.Count); + } - private object _source = new object(); - private string _eventName = "MyEvent"; - private string _methodName = "MyEventHandlerMethod"; - public object Source - { - get - { - return _source; - } - set - { - _source = value; - } - } + [Test] + public void OneEventValue() + { + EventValues eventValues = new EventValues(); + eventValues.AddHandler(new MyEventHandler()); + Assert.AreEqual(1, eventValues.Events.Count); + } - public string EventName - { - get - { - return _eventName; - } - set - { - _eventName = value; - } - } + [Test] + public void TwoEventHandlersForSameEvent() + { + EventValues eventValues = new EventValues(); + eventValues.AddHandler(new MyEventHandler()); + eventValues.AddHandler(new MyEventHandler()); + Assert.AreEqual(1, eventValues.Events.Count); + } - public string MethodName - { - get - { - return _methodName; - } - set - { - _methodName = value; - } - } + [Test] + public void CopyEventHandlerValues() + { + EventValues eventValues = new EventValues(); + eventValues.AddHandler(new MyEventHandler()); + eventValues.AddHandler(new MyEventHandler()); + Assert.AreEqual(1, eventValues.Events.Count); + EventValues eventValues2 = new EventValues(eventValues); + Assert.AreEqual(1, eventValues2.Events.Count); + } - public void Wire(object source, object handler) - { - } + [Test] + public void NullEventHandlerValue() + { + EventValues eventValues = new EventValues(); + eventValues.AddAll(null); + Assert.AreEqual(0, eventValues.Events.Count); + } - #endregion + internal class MyEventHandler : IEventHandlerValue + { + #region IEventHandlerValue Members - } - internal class MyEventHandler2 : IEventHandlerValue - { - #region IEventHandlerValue Members + private object _source = new object(); + private string _eventName = "MyEvent"; + private string _methodName = "MyEventHandlerMethod"; - private object _source = new object(); - private string _eventName = "MyEvent"; - private string _methodName = "MyEventHandlerMethod"; - public object Source - { - get - { - return _source; - } - set - { - _source = value; - } - } + public object Source + { + get + { + return _source; + } + set + { + _source = value; + } + } - public string EventName - { - get - { - return _eventName; - } - set - { - _eventName = value; - } - } + public string EventName + { + get + { + return _eventName; + } + set + { + _eventName = value; + } + } - public string MethodName - { - get - { - return _methodName; - } - set - { - _methodName = value; - } - } + public string MethodName + { + get + { + return _methodName; + } + set + { + _methodName = value; + } + } - public void Wire(object source, object handler) - { - } + public void Wire(object source, object handler) + { + } - #endregion + #endregion + } - } - } -} \ No newline at end of file + internal class MyEventHandler2 : IEventHandlerValue + { + #region IEventHandlerValue Members + + private object _source = new object(); + private string _eventName = "MyEvent"; + private string _methodName = "MyEventHandlerMethod"; + + public object Source + { + get + { + return _source; + } + set + { + _source = value; + } + } + + public string EventName + { + get + { + return _eventName; + } + set + { + _eventName = value; + } + } + + public string MethodName + { + get + { + return _methodName; + } + set + { + _methodName = value; + } + } + + public void Wire(object source, object handler) + { + } + + #endregion + } +} diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/FieldRetrievingFactoryObjectTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/FieldRetrievingFactoryObjectTests.cs index 2f575cf4..7ee073eb 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/FieldRetrievingFactoryObjectTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/FieldRetrievingFactoryObjectTests.cs @@ -24,200 +24,199 @@ using NUnit.Framework; #endregion -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Unit tests for the FieldRetrievingFactoryObject class. +/// +/// Juergen Hoeller +/// Rick Evans +[TestFixture] +public sealed class FieldRetrievingFactoryObjectTests { - /// - /// Unit tests for the FieldRetrievingFactoryObject class. - /// - /// Juergen Hoeller - /// Rick Evans - [TestFixture] - public sealed class FieldRetrievingFactoryObjectTests + [Test] + public void StaticField() { - [Test] - public void StaticField() - { - FieldRetrievingFactoryObject fac = new FieldRetrievingFactoryObject(); - fac.StaticField = "Spring.Objects.Factory.Config.FinalFielder.Name, Spring.Core.Tests"; - fac.ObjectName = "foo"; - fac.AfterPropertiesSet(); - Assert.AreEqual(typeof (string), fac.ObjectType); - object actual = fac.GetObject(); - Assert.AreEqual(FinalFielder.Name, actual); - } - - [Test] - public void StaticFieldWithWhitespace() - { - FieldRetrievingFactoryObject fac = new FieldRetrievingFactoryObject(); - fac.StaticField = "\tSpring.Objects.Factory.Config.FinalFielder.Name, Spring.Core.Tests "; - fac.ObjectName = "foo"; - fac.AfterPropertiesSet(); - Assert.AreEqual(typeof (string), fac.ObjectType); - object actual = fac.GetObject(); - Assert.AreEqual(FinalFielder.Name, actual); - } - - [Test] - public void StaticFieldThatAintAssemblyQualifiedShouldStillBeResolved() - { - FieldRetrievingFactoryObject fac = new FieldRetrievingFactoryObject(); - fac.StaticField = "Spring.Objects.Factory.Config.FinalFielder.Name"; - fac.ObjectName = "foo"; - fac.AfterPropertiesSet(); - Assert.AreEqual(typeof (string), fac.ObjectType); - object actual = fac.GetObject(); - Assert.AreEqual(FinalFielder.Name, actual); - } - - [Test] - public void StaticFieldSystemClass() - { - FieldRetrievingFactoryObject fac = new FieldRetrievingFactoryObject(); - fac.StaticField = "System.DBNull.Value"; - fac.ObjectName = "foo"; - fac.AfterPropertiesSet(); - Assert.AreEqual(typeof (DBNull), fac.ObjectType); - object actual = fac.GetObject(); - Assert.AreEqual(DBNull.Value, actual); - } - - [Test] - public void UsesObjectNameForStaticField() - { - FieldRetrievingFactoryObject fac = new FieldRetrievingFactoryObject(); - fac.ObjectName = "System.Type.Delimiter"; - fac.AfterPropertiesSet(); - Assert.AreEqual(typeof (char), fac.ObjectType); - object actual = fac.GetObject(); - Assert.AreEqual(Type.Delimiter, actual); - } - - [Test] - public void OnlyUsesObjectNameForStaticFieldIfTheStaticFieldHasNotBeenSet() - { - FieldRetrievingFactoryObject fac = new FieldRetrievingFactoryObject(); - fac.ObjectName = "System.DBNull.Value"; - fac.StaticField = "Spring.Objects.Factory.Config.FinalFielder.Name"; - fac.AfterPropertiesSet(); - Assert.AreEqual(typeof (string), fac.ObjectType); - object actual = fac.GetObject(); - Assert.AreEqual(FinalFielder.Name, actual); - } - - [Test] - public void StaticFieldViaClassAndFieldName() - { - FieldRetrievingFactoryObject fac = new FieldRetrievingFactoryObject(); - fac.TargetField = "Name"; - fac.TargetType = typeof (FinalFielder); - fac.ObjectName = "foo"; - fac.AfterPropertiesSet(); - object actual = fac.GetObject(); - Assert.AreEqual(FinalFielder.Name, actual); - } - - [Test] - public void IsSingleton() - { - FieldRetrievingFactoryObject fac = new FieldRetrievingFactoryObject(); - Assert.IsTrue(fac.IsSingleton); - } - - [Test] - public void InstanceField() - { - FinalFielder expected = new FinalFielder(); - expected.Age = 56; - FieldRetrievingFactoryObject fac = new FieldRetrievingFactoryObject(); - fac.TargetObject = expected; - fac.TargetField = "Age"; - fac.ObjectName = "foo"; - fac.AfterPropertiesSet(); - object actual = fac.GetObject(); - Assert.AreEqual(expected.Age, actual); - } - - [Test] - public void NothingSet() - { - FieldRetrievingFactoryObject fac = new FieldRetrievingFactoryObject(); - fac.ObjectName = "foo"; - Assert.Throws(() => fac.AfterPropertiesSet()); - } - - [Test] - public void JustTargetField() - { - FieldRetrievingFactoryObject fac = new FieldRetrievingFactoryObject(); - fac.TargetField = "Space"; - fac.ObjectName = "foo"; - Assert.Throws(() => fac.AfterPropertiesSet()); - } - - [Test] - public void JustTargetType() - { - FieldRetrievingFactoryObject fac = new FieldRetrievingFactoryObject(); - fac.TargetType = GetType(); - fac.ObjectName = "foo"; - Assert.Throws(() => fac.AfterPropertiesSet()); - } - - [Test] - public void JustTargetObject() - { - FieldRetrievingFactoryObject fac = new FieldRetrievingFactoryObject(); - fac.TargetObject = this; - fac.ObjectName = "foo"; - Assert.Throws(() => fac.AfterPropertiesSet()); - } - - [Test] - public void BailsWhenStaticFieldPassedGumpfh() - { - FieldRetrievingFactoryObject fac = new FieldRetrievingFactoryObject(); - fac.StaticField = "Goob"; // no field specified - fac.ObjectName = "foo"; - Assert.Throws(() => fac.AfterPropertiesSet()); - } - - [Test] - public void StaticFieldIsCaseINsenSiTiVE() - { - FieldRetrievingFactoryObject fac = new FieldRetrievingFactoryObject(); - fac.StaticField = "System.Type.emptytyPES, Mscorlib"; - fac.ObjectName = "foo"; - fac.AfterPropertiesSet(); - Assert.AreEqual(typeof (Type[]), fac.ObjectType); - Type[] actual = fac.GetObject() as Type[]; - Assert.IsNotNull(actual); - Assert.AreEqual(Type.EmptyTypes.Length, actual.Length); - } - - [Test] - public void BailsOnNonExistantField() - { - FieldRetrievingFactoryObject fac = new FieldRetrievingFactoryObject(); - fac.StaticField = "Spring.Objects.Factory.Config.FinalFielder.Rubbish, Spring.Core.Tests"; - fac.ObjectName = "foo"; - Assert.Throws(() => fac.AfterPropertiesSet()); - } - - [Test] - public void BailsWhenBothTargetTypeAndTargetObjectPropsAreSet() - { - FieldRetrievingFactoryObject fac = new FieldRetrievingFactoryObject(); - fac.TargetObject = this; - fac.TargetType = GetType(); - Assert.Throws(() => fac.AfterPropertiesSet()); - } + FieldRetrievingFactoryObject fac = new FieldRetrievingFactoryObject(); + fac.StaticField = "Spring.Objects.Factory.Config.FinalFielder.Name, Spring.Core.Tests"; + fac.ObjectName = "foo"; + fac.AfterPropertiesSet(); + Assert.AreEqual(typeof(string), fac.ObjectType); + object actual = fac.GetObject(); + Assert.AreEqual(FinalFielder.Name, actual); } - internal sealed class FinalFielder + [Test] + public void StaticFieldWithWhitespace() { - public const string Name = "WalkingTall"; - - public int Age = 43; + FieldRetrievingFactoryObject fac = new FieldRetrievingFactoryObject(); + fac.StaticField = "\tSpring.Objects.Factory.Config.FinalFielder.Name, Spring.Core.Tests "; + fac.ObjectName = "foo"; + fac.AfterPropertiesSet(); + Assert.AreEqual(typeof(string), fac.ObjectType); + object actual = fac.GetObject(); + Assert.AreEqual(FinalFielder.Name, actual); } -} \ No newline at end of file + + [Test] + public void StaticFieldThatAintAssemblyQualifiedShouldStillBeResolved() + { + FieldRetrievingFactoryObject fac = new FieldRetrievingFactoryObject(); + fac.StaticField = "Spring.Objects.Factory.Config.FinalFielder.Name"; + fac.ObjectName = "foo"; + fac.AfterPropertiesSet(); + Assert.AreEqual(typeof(string), fac.ObjectType); + object actual = fac.GetObject(); + Assert.AreEqual(FinalFielder.Name, actual); + } + + [Test] + public void StaticFieldSystemClass() + { + FieldRetrievingFactoryObject fac = new FieldRetrievingFactoryObject(); + fac.StaticField = "System.DBNull.Value"; + fac.ObjectName = "foo"; + fac.AfterPropertiesSet(); + Assert.AreEqual(typeof(DBNull), fac.ObjectType); + object actual = fac.GetObject(); + Assert.AreEqual(DBNull.Value, actual); + } + + [Test] + public void UsesObjectNameForStaticField() + { + FieldRetrievingFactoryObject fac = new FieldRetrievingFactoryObject(); + fac.ObjectName = "System.Type.Delimiter"; + fac.AfterPropertiesSet(); + Assert.AreEqual(typeof(char), fac.ObjectType); + object actual = fac.GetObject(); + Assert.AreEqual(Type.Delimiter, actual); + } + + [Test] + public void OnlyUsesObjectNameForStaticFieldIfTheStaticFieldHasNotBeenSet() + { + FieldRetrievingFactoryObject fac = new FieldRetrievingFactoryObject(); + fac.ObjectName = "System.DBNull.Value"; + fac.StaticField = "Spring.Objects.Factory.Config.FinalFielder.Name"; + fac.AfterPropertiesSet(); + Assert.AreEqual(typeof(string), fac.ObjectType); + object actual = fac.GetObject(); + Assert.AreEqual(FinalFielder.Name, actual); + } + + [Test] + public void StaticFieldViaClassAndFieldName() + { + FieldRetrievingFactoryObject fac = new FieldRetrievingFactoryObject(); + fac.TargetField = "Name"; + fac.TargetType = typeof(FinalFielder); + fac.ObjectName = "foo"; + fac.AfterPropertiesSet(); + object actual = fac.GetObject(); + Assert.AreEqual(FinalFielder.Name, actual); + } + + [Test] + public void IsSingleton() + { + FieldRetrievingFactoryObject fac = new FieldRetrievingFactoryObject(); + Assert.IsTrue(fac.IsSingleton); + } + + [Test] + public void InstanceField() + { + FinalFielder expected = new FinalFielder(); + expected.Age = 56; + FieldRetrievingFactoryObject fac = new FieldRetrievingFactoryObject(); + fac.TargetObject = expected; + fac.TargetField = "Age"; + fac.ObjectName = "foo"; + fac.AfterPropertiesSet(); + object actual = fac.GetObject(); + Assert.AreEqual(expected.Age, actual); + } + + [Test] + public void NothingSet() + { + FieldRetrievingFactoryObject fac = new FieldRetrievingFactoryObject(); + fac.ObjectName = "foo"; + Assert.Throws(() => fac.AfterPropertiesSet()); + } + + [Test] + public void JustTargetField() + { + FieldRetrievingFactoryObject fac = new FieldRetrievingFactoryObject(); + fac.TargetField = "Space"; + fac.ObjectName = "foo"; + Assert.Throws(() => fac.AfterPropertiesSet()); + } + + [Test] + public void JustTargetType() + { + FieldRetrievingFactoryObject fac = new FieldRetrievingFactoryObject(); + fac.TargetType = GetType(); + fac.ObjectName = "foo"; + Assert.Throws(() => fac.AfterPropertiesSet()); + } + + [Test] + public void JustTargetObject() + { + FieldRetrievingFactoryObject fac = new FieldRetrievingFactoryObject(); + fac.TargetObject = this; + fac.ObjectName = "foo"; + Assert.Throws(() => fac.AfterPropertiesSet()); + } + + [Test] + public void BailsWhenStaticFieldPassedGumpfh() + { + FieldRetrievingFactoryObject fac = new FieldRetrievingFactoryObject(); + fac.StaticField = "Goob"; // no field specified + fac.ObjectName = "foo"; + Assert.Throws(() => fac.AfterPropertiesSet()); + } + + [Test] + public void StaticFieldIsCaseINsenSiTiVE() + { + FieldRetrievingFactoryObject fac = new FieldRetrievingFactoryObject(); + fac.StaticField = "System.Type.emptytyPES, Mscorlib"; + fac.ObjectName = "foo"; + fac.AfterPropertiesSet(); + Assert.AreEqual(typeof(Type[]), fac.ObjectType); + Type[] actual = fac.GetObject() as Type[]; + Assert.IsNotNull(actual); + Assert.AreEqual(Type.EmptyTypes.Length, actual.Length); + } + + [Test] + public void BailsOnNonExistantField() + { + FieldRetrievingFactoryObject fac = new FieldRetrievingFactoryObject(); + fac.StaticField = "Spring.Objects.Factory.Config.FinalFielder.Rubbish, Spring.Core.Tests"; + fac.ObjectName = "foo"; + Assert.Throws(() => fac.AfterPropertiesSet()); + } + + [Test] + public void BailsWhenBothTargetTypeAndTargetObjectPropsAreSet() + { + FieldRetrievingFactoryObject fac = new FieldRetrievingFactoryObject(); + fac.TargetObject = this; + fac.TargetType = GetType(); + Assert.Throws(() => fac.AfterPropertiesSet()); + } +} + +internal sealed class FinalFielder +{ + public const string Name = "WalkingTall"; + + public int Age = 43; +} diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/ListFactoryObjectTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/ListFactoryObjectTests.cs index c3352052..45899422 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/ListFactoryObjectTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/ListFactoryObjectTests.cs @@ -25,89 +25,83 @@ using NUnit.Framework; #endregion -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Unit tests for the ListFactoryObject class. +/// +/// Rick Evans +[TestFixture] +public sealed class ListFactoryObjectTests { - /// - /// Unit tests for the ListFactoryObject class. - /// - /// Rick Evans - [TestFixture] - public sealed class ListFactoryObjectTests - { - [Test] - public void SetTargetListTypeToNonListType() - { - ListFactoryObject lfo = new ListFactoryObject(); - Assert.Throws(() => lfo.TargetListType = typeof (ICollection), "The Type passed to the TargetListType property must implement the 'System.Collections.IList' interface."); - } + [Test] + public void SetTargetListTypeToNonListType() + { + ListFactoryObject lfo = new ListFactoryObject(); + Assert.Throws(() => lfo.TargetListType = typeof(ICollection), "The Type passed to the TargetListType property must implement the 'System.Collections.IList' interface."); + } - [Test] - public void SetTargetListTypeToDerivedIListInterfaceType() - { - ListFactoryObject lfo = new ListFactoryObject(); - Assert.Throws(() => lfo.TargetListType = typeof (IExtendedList), "The Type passed to the TargetListType property cannot be an interface; it must be a concrete class that implements the 'System.Collections.IList' interface."); - } + [Test] + public void SetTargetListTypeToDerivedIListInterfaceType() + { + ListFactoryObject lfo = new ListFactoryObject(); + Assert.Throws(() => lfo.TargetListType = typeof(IExtendedList), "The Type passed to the TargetListType property cannot be an interface; it must be a concrete class that implements the 'System.Collections.IList' interface."); + } - [Test] - public void SetTargetListTypeToAbstractIListInterfaceType() - { - ListFactoryObject lfo = new ListFactoryObject(); - Assert.Throws(() => lfo.TargetListType = typeof (AbstractList), "The Type passed to the TargetListType property cannot be abstract (MustInherit in VisualBasic.NET); it must be a concrete class that implements the 'System.Collections.IList' interface."); - } + [Test] + public void SetTargetListTypeToAbstractIListInterfaceType() + { + ListFactoryObject lfo = new ListFactoryObject(); + Assert.Throws(() => lfo.TargetListType = typeof(AbstractList), "The Type passed to the TargetListType property cannot be abstract (MustInherit in VisualBasic.NET); it must be a concrete class that implements the 'System.Collections.IList' interface."); + } - private interface IExtendedList : IList - { - } + private interface IExtendedList : IList + { + } - private abstract class AbstractList : ArrayList - { - } + private abstract class AbstractList : ArrayList + { + } - [Test] - public void SetTargetListTypeToNull() - { - ListFactoryObject lfo = new ListFactoryObject(); - Assert.Throws(() => lfo.TargetListType = null); - } + [Test] + public void SetTargetListTypeToNull() + { + ListFactoryObject lfo = new ListFactoryObject(); + Assert.Throws(() => lfo.TargetListType = null); + } - [Test] - public void GetObjectWithoutSupplyingASourceList() - { - ListFactoryObject lfo = new ListFactoryObject(); - lfo.IsSingleton = false; - Assert.Throws(() => lfo.GetObject(), "The 'SourceList' property cannot be null (Nothing in Visual Basic.NET)."); - } + [Test] + public void GetObjectWithoutSupplyingASourceList() + { + ListFactoryObject lfo = new ListFactoryObject(); + lfo.IsSingleton = false; + Assert.Throws(() => lfo.GetObject(), "The 'SourceList' property cannot be null (Nothing in Visual Basic.NET)."); + } - [Test] - public void ObjectTypeReallyIsIList() - { - Assert.AreEqual(typeof (IList), new ListFactoryObject().ObjectType); - } + [Test] + public void ObjectTypeReallyIsIList() + { + Assert.AreEqual(typeof(IList), new ListFactoryObject().ObjectType); + } - [Test] - public void GetObjectReallyDoesPopulateANewIListInstanceWithTheElementsOfTheSourceList() - { - // man, that has got to be my second longest ever test name :D ... - IList source = new TestObject[] - { - new TestObject("Rick", 30), - new TestObject("Mark", 35), - new TestObject("Griffin", 21), - }; + [Test] + public void GetObjectReallyDoesPopulateANewIListInstanceWithTheElementsOfTheSourceList() + { + // man, that has got to be my second longest ever test name :D ... + IList source = new TestObject[] { new TestObject("Rick", 30), new TestObject("Mark", 35), new TestObject("Griffin", 21), }; - ListFactoryObject lfo = new ListFactoryObject(); - lfo.SourceList = source; - lfo.AfterPropertiesSet(); + ListFactoryObject lfo = new ListFactoryObject(); + lfo.SourceList = source; + lfo.AfterPropertiesSet(); - IList list = (IList) lfo.GetObject(); - Assert.IsNotNull(list); - Assert.AreEqual(source.Count, list.Count); - for (int i = 0; i < list.Count; ++i) - { - TestObject dude = (TestObject) list[i]; - TestObject originalDude = (TestObject) source[i]; - Assert.IsTrue(object.ReferenceEquals(dude, originalDude)); - } - } - } -} \ No newline at end of file + IList list = (IList) lfo.GetObject(); + Assert.IsNotNull(list); + Assert.AreEqual(source.Count, list.Count); + for (int i = 0; i < list.Count; ++i) + { + TestObject dude = (TestObject) list[i]; + TestObject originalDude = (TestObject) source[i]; + Assert.IsTrue(object.ReferenceEquals(dude, originalDude)); + } + } +} diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/LogFactoryObjectTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/LogFactoryObjectTests.cs index 914a25c8..983adfc6 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/LogFactoryObjectTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/LogFactoryObjectTests.cs @@ -24,104 +24,103 @@ using NUnit.Framework; #endregion -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Unit tests for the LogFactoryObject class. +/// +/// Rick Evans (.NET) +[TestFixture] +public sealed class LogFactoryObjectTests { - /// - /// Unit tests for the LogFactoryObject class. - /// - /// Rick Evans (.NET) - [TestFixture] - public sealed class LogFactoryObjectTests - { - [Test] - public void CheckThatLogNamePropertyMustBeSet() - { - LogFactoryObject fac = new LogFactoryObject(); - Assert.Throws(() => fac.GetObject()); - } + [Test] + public void CheckThatLogNamePropertyMustBeSet() + { + LogFactoryObject fac = new LogFactoryObject(); + Assert.Throws(() => fac.GetObject()); + } - [Test] - public void CheckLogNamePropertyWithNullName() - { - LogFactoryObject fac = new LogFactoryObject(); - Assert.Throws(() => fac.LogName = null); - } + [Test] + public void CheckLogNamePropertyWithNullName() + { + LogFactoryObject fac = new LogFactoryObject(); + Assert.Throws(() => fac.LogName = null); + } - [Test] - public void CheckLogNamePropertyWithEmptyName() - { - LogFactoryObject fac = new LogFactoryObject(); - Assert.Throws(() => fac.LogName = string.Empty); - } + [Test] + public void CheckLogNamePropertyWithEmptyName() + { + LogFactoryObject fac = new LogFactoryObject(); + Assert.Throws(() => fac.LogName = string.Empty); + } - [Test] - public void CheckInstantiationWithNullName() - { - Assert.Throws(() => new LogFactoryObject(null)); - } + [Test] + public void CheckInstantiationWithNullName() + { + Assert.Throws(() => new LogFactoryObject(null)); + } - [Test] - public void CheckInstantiationWithEmptyName() - { - Assert.Throws(() => new LogFactoryObject(string.Empty)); - } + [Test] + public void CheckInstantiationWithEmptyName() + { + Assert.Throws(() => new LogFactoryObject(string.Empty)); + } - [Test] - public void CheckLogNamePropertyStripsRedundantWhitespaceFromName() - { - LogFactoryObject fac = new LogFactoryObject(); - fac.LogName = " Foo "; - Assert.AreEqual("Foo", fac.LogName); - } + [Test] + public void CheckLogNamePropertyStripsRedundantWhitespaceFromName() + { + LogFactoryObject fac = new LogFactoryObject(); + fac.LogName = " Foo "; + Assert.AreEqual("Foo", fac.LogName); + } - [Test] - public void CheckGetObjectWorksWithValidLogName() - { - LogFactoryObject fac = new LogFactoryObject(); - fac.LogName = "Foo"; - ILog log = fac.GetObject() as ILog; - Assert.IsNotNull(log, "Mmm... pulled a null ILog instance from a properly configured LogFactoryObject instance."); - } + [Test] + public void CheckGetObjectWorksWithValidLogName() + { + LogFactoryObject fac = new LogFactoryObject(); + fac.LogName = "Foo"; + ILog log = fac.GetObject() as ILog; + Assert.IsNotNull(log, "Mmm... pulled a null ILog instance from a properly configured LogFactoryObject instance."); + } - [Test] - public void CheckGetObjectReturnsSharedInstance() - { - LogFactoryObject fac = new LogFactoryObject(); - fac.LogName = "Foo"; - ILog log = fac.GetObject() as ILog; - ILog anotherLogInstance = fac.GetObject() as ILog; - Assert.IsTrue(log == anotherLogInstance, - "Okay, the LogFactoryObject ain't returning shared instances (it should)."); - } + [Test] + public void CheckGetObjectReturnsSharedInstance() + { + LogFactoryObject fac = new LogFactoryObject(); + fac.LogName = "Foo"; + ILog log = fac.GetObject() as ILog; + ILog anotherLogInstance = fac.GetObject() as ILog; + Assert.IsTrue(log == anotherLogInstance, + "Okay, the LogFactoryObject ain't returning shared instances (it should)."); + } - [Test] - public void CheckAfterPropertiesSetBlowsUpIfNotCorrectlyConfigured() - { - LogFactoryObject fac = new LogFactoryObject(); - Assert.Throws(() => fac.AfterPropertiesSet(), "The 'LogName' property has not been set."); - } + [Test] + public void CheckAfterPropertiesSetBlowsUpIfNotCorrectlyConfigured() + { + LogFactoryObject fac = new LogFactoryObject(); + Assert.Throws(() => fac.AfterPropertiesSet(), "The 'LogName' property has not been set."); + } - [Test] - public void CheckAfterPropertiesSetPassesIfCorrectlyConfigured() - { - LogFactoryObject fac = new LogFactoryObject("Bing!"); - fac.AfterPropertiesSet(); - } + [Test] + public void CheckAfterPropertiesSetPassesIfCorrectlyConfigured() + { + LogFactoryObject fac = new LogFactoryObject("Bing!"); + fac.AfterPropertiesSet(); + } - [Test] - public void ItsDefinitelyASingletonYeah() - { - LogFactoryObject fac = new LogFactoryObject("Bing!"); - Assert.IsTrue(fac.IsSingleton, - "The LogFactoryObject class must be configured to return shared instances (it currently ain't)."); - } + [Test] + public void ItsDefinitelyASingletonYeah() + { + LogFactoryObject fac = new LogFactoryObject("Bing!"); + Assert.IsTrue(fac.IsSingleton, + "The LogFactoryObject class must be configured to return shared instances (it currently ain't)."); + } - [Test] - public void ObjectTypePropertyYieldsTheCorrectType() - { - LogFactoryObject fac = new LogFactoryObject("Bing!"); - Assert.AreEqual(typeof (ILog), fac.ObjectType, - "Mmm... the LogFactoryObject class ain't giving back ILog types (it must)."); - } - } + [Test] + public void ObjectTypePropertyYieldsTheCorrectType() + { + LogFactoryObject fac = new LogFactoryObject("Bing!"); + Assert.AreEqual(typeof(ILog), fac.ObjectType, + "Mmm... the LogFactoryObject class ain't giving back ILog types (it must)."); + } } diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/MethodInvokingFactoryObjectTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/MethodInvokingFactoryObjectTests.cs index 26d78a10..d578b6cb 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/MethodInvokingFactoryObjectTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/MethodInvokingFactoryObjectTests.cs @@ -2,13 +2,13 @@ /* * Copyright 2002-2010 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. @@ -27,261 +27,260 @@ using Spring.Objects.Support; #endregion -namespace Spring.Objects.Factory.Config -{ - /// - /// Set of unit tests for the MethodInvokingFactoryObject. - /// - /// Colin Sampaleanu - /// Simon White (.NET) - [TestFixture] - public class MethodInvokingFactoryObjectTests - { - [Test] - public void InvokeGenericMethod() - { - TestClass1 tc1 = new TestClass1(); - MethodInvokingFactoryObject mcfo = new MethodInvokingFactoryObject(); - mcfo.TargetType = typeof(Activator); - mcfo.TargetMethod = "CreateInstance"; - mcfo.AfterPropertiesSet(); +namespace Spring.Objects.Factory.Config; - object obj = mcfo.GetObject(); - Assert.IsNotNull(obj); - Assert.IsTrue(obj is TestObject); +/// +/// Set of unit tests for the MethodInvokingFactoryObject. +/// +/// Colin Sampaleanu +/// Simon White (.NET) +[TestFixture] +public class MethodInvokingFactoryObjectTests +{ + [Test] + public void InvokeGenericMethod() + { + TestClass1 tc1 = new TestClass1(); + MethodInvokingFactoryObject mcfo = new MethodInvokingFactoryObject(); + mcfo.TargetType = typeof(Activator); + mcfo.TargetMethod = "CreateInstance"; + mcfo.AfterPropertiesSet(); + + object obj = mcfo.GetObject(); + Assert.IsNotNull(obj); + Assert.IsTrue(obj is TestObject); + } + + [Test] + public void GetSingletonNonStatic() + { + TestClass1 tc1 = new TestClass1(); + MethodInvokingFactoryObject mcfo = new MethodInvokingFactoryObject(); + mcfo.TargetObject = tc1; + mcfo.TargetMethod = "Method1"; + mcfo.AfterPropertiesSet(); + int i = (int) mcfo.GetObject(); + Assert.IsTrue(i == 1); + i = (int) mcfo.GetObject(); + Assert.IsTrue(i == 1); + Assert.IsTrue(mcfo.IsSingleton); + } + + [Test] + public void GetNonSingletonNonStatic() + { + TestClass1 tc1 = new TestClass1(); + MethodInvokingFactoryObject mcfo = new MethodInvokingFactoryObject(); + mcfo.TargetObject = tc1; + mcfo.TargetMethod = "Method1"; + mcfo.IsSingleton = false; + mcfo.AfterPropertiesSet(); + int i = (int) mcfo.GetObject(); + Assert.IsTrue(i == 1); + i = (int) mcfo.GetObject(); + Assert.IsTrue(i == 2); + Assert.IsFalse(mcfo.IsSingleton); + } + + [Test] + public void GetSingletonStatic() + { + TestClass1._staticField1 = 0; + MethodInvokingFactoryObject mcfo = new MethodInvokingFactoryObject(); + mcfo.TargetType = typeof(TestClass1); + mcfo.TargetMethod = "StaticMethod1"; + mcfo.AfterPropertiesSet(); + int i = (int) mcfo.GetObject(); + Assert.IsTrue(i == 1); + i = (int) mcfo.GetObject(); + Assert.IsTrue(i == 1); + Assert.IsTrue(mcfo.IsSingleton); + } + + [Test] + public void GetNonSingletonStatic() + { + TestClass1._staticField1 = 0; + MethodInvokingFactoryObject mcfo = new MethodInvokingFactoryObject(); + mcfo.TargetType = typeof(TestClass1); + mcfo.TargetMethod = "StaticMethod1"; + mcfo.IsSingleton = false; + mcfo.AfterPropertiesSet(); + int i = (int) mcfo.GetObject(); + Assert.IsTrue(i == 1); + i = (int) mcfo.GetObject(); + Assert.IsTrue(i == 2); + Assert.IsFalse(mcfo.IsSingleton); + } + + [Test] + public void InvokingAMethodThatHasAVoidReturnTypeReturnsNullPlaceHolder() + { + MethodInvokingFactoryObject mcfo = new MethodInvokingFactoryObject(); + mcfo.TargetType = typeof(TestClass1); + mcfo.TargetMethod = "VoidRetvalMethod"; + mcfo.AfterPropertiesSet(); + Assert.AreEqual(MethodInvoker.Void, mcfo.GetObject()); + } + + [Test] + public void GetSupertypesMatchNumArgs() + { + TestClass1._staticField1 = 0; + MethodInvokingFactoryObject mcfo = new MethodInvokingFactoryObject(); + mcfo.TargetType = typeof(TestClass1); + mcfo.TargetMethod = "Supertypes"; + mcfo.Arguments = new Object[] { new ArrayList(), new ArrayList(), "hello" }; + // should pass + mcfo.AfterPropertiesSet(); + } + + [Test] + public void GetSupertypesTooManyArgs() + { + MethodInvokingFactoryObject mcfo = new MethodInvokingFactoryObject(); + mcfo.TargetType = typeof(TestClass1); + mcfo.TargetMethod = "Supertypes2"; + mcfo.Arguments = new Object[] { new ArrayList(), new ArrayList(), "hello", "bogus" }; + Assert.Throws(() => mcfo.AfterPropertiesSet(), "Unable to determine which exact method to call; found '2' matches."); + } + + [Test] + public void GetMisMatchedArgumentTypes() + { + MethodInvokingFactoryObject mcfo = new MethodInvokingFactoryObject(); + mcfo.TargetType = typeof(TestClass1); + mcfo.TargetMethod = "Supertypes"; + mcfo.Arguments = new Object[] { "1", "2", "3" }; + Assert.Throws(() => mcfo.AfterPropertiesSet()); + } + + [Test] + public void GetObjectType() + { + TestClass1 tc1 = new TestClass1(); + MethodInvokingFactoryObject mcfo = new MethodInvokingFactoryObject(); + mcfo.TargetObject = tc1; + mcfo.TargetMethod = "Method1"; + mcfo.AfterPropertiesSet(); + Assert.IsTrue(typeof(int).Equals(mcfo.ObjectType)); + + mcfo = new MethodInvokingFactoryObject(); + mcfo.TargetType = typeof(TestClass1); + mcfo.TargetMethod = "VoidRetvalMethod"; + mcfo.AfterPropertiesSet(); + Type objType = mcfo.ObjectType; + Assert.IsTrue(objType.Equals(MethodInvoker.Void.GetType())); + + // verify that we can call a method with args that are subtypes of the + // target method arg types + TestClass1._staticField1 = 0; + mcfo = new MethodInvokingFactoryObject(); + mcfo.TargetType = typeof(TestClass1); + mcfo.TargetMethod = "Supertypes"; + mcfo.Arguments = new Object[] { new ArrayList(), new ArrayList(), "hello" }; + mcfo.AfterPropertiesSet(); + objType = mcfo.ObjectType; + } + + [Test] + public void ObjectTypeIsNullIfAfterPropertiesSetHasNotYetBeenInvoked() + { + MethodInvokingFactoryObject mcfo = new MethodInvokingFactoryObject(); + mcfo.TargetType = typeof(TestClass1); + mcfo.TargetMethod = "VoidRetvalMethod"; + Assert.IsNull(mcfo.ObjectType, + "ObjectType property value must only be set to a non null value " + + "AFTER the AfterPropertiesSet() method has been invoked."); + } + + [Test] + public void BailsIfTheTargetMethodPropertyAintSet() + { + MethodInvokingFactoryObject mcfo = new MethodInvokingFactoryObject(); + Assert.Throws(() => mcfo.AfterPropertiesSet(), "The 'TargetMethod' property is required."); + } + + [Test] + public void AfterPropertiesSetBogusMethod() + { + MethodInvokingFactoryObject mcfo = new MethodInvokingFactoryObject(); + mcfo.TargetObject = this; + mcfo.TargetMethod = "whatever"; + Assert.Throws(() => mcfo.AfterPropertiesSet()); + } + + [Test] + public void AfterPropertiesSetBogusStaticMethod() + { + MethodInvokingFactoryObject mcfo = new MethodInvokingFactoryObject(); + mcfo.TargetType = typeof(TestClass1); + mcfo.TargetMethod = "some.bogus.Method.name"; + Assert.Throws(() => mcfo.AfterPropertiesSet()); + } + + [Test] + public void AfterPropertiesSetStaticMethodMissingArgs() + { + MethodInvokingFactoryObject mcfo = new MethodInvokingFactoryObject(); + mcfo.TargetType = typeof(TestClass1); + mcfo.TargetMethod = "Method1"; + Assert.Throws(() => mcfo.AfterPropertiesSet()); + } + + [Test] + public void AfterPropertiesSetMissingMethod() + { + MethodInvokingFactoryObject mcfo = new MethodInvokingFactoryObject(); + mcfo.TargetObject = this; + Assert.Throws(() => mcfo.AfterPropertiesSet()); + } + + [Test] + public void InvokeWithNullArgument() + { + MethodInvoker methodInvoker = new MethodInvoker(); + methodInvoker.TargetType = GetType(); + methodInvoker.TargetMethod = "NullArgument"; + methodInvoker.Arguments = new object[] { null }; + methodInvoker.Prepare(); + methodInvoker.Invoke(); + } + + public static void NullArgument(object arg) + { + } + + // a test class to work with + public class TestClass1 + { + public static int _staticField1; + public int _field1 = 0; + + public int Method1() + { + return ++_field1; } - [Test] - public void GetSingletonNonStatic() - { - TestClass1 tc1 = new TestClass1(); - MethodInvokingFactoryObject mcfo = new MethodInvokingFactoryObject(); - mcfo.TargetObject = tc1; - mcfo.TargetMethod = "Method1"; - mcfo.AfterPropertiesSet(); - int i = (int) mcfo.GetObject(); - Assert.IsTrue(i == 1); - i = (int) mcfo.GetObject(); - Assert.IsTrue(i == 1); - Assert.IsTrue(mcfo.IsSingleton); - } + public static int StaticMethod1() + { + return ++_staticField1; + } - [Test] - public void GetNonSingletonNonStatic() - { - TestClass1 tc1 = new TestClass1(); - MethodInvokingFactoryObject mcfo = new MethodInvokingFactoryObject(); - mcfo.TargetObject = tc1; - mcfo.TargetMethod = "Method1"; - mcfo.IsSingleton = false; - mcfo.AfterPropertiesSet(); - int i = (int) mcfo.GetObject(); - Assert.IsTrue(i == 1); - i = (int) mcfo.GetObject(); - Assert.IsTrue(i == 2); - Assert.IsFalse(mcfo.IsSingleton); - } + public static void VoidRetvalMethod() + { + } - [Test] - public void GetSingletonStatic() - { - TestClass1._staticField1 = 0; - MethodInvokingFactoryObject mcfo = new MethodInvokingFactoryObject(); - mcfo.TargetType = typeof (TestClass1); - mcfo.TargetMethod = "StaticMethod1"; - mcfo.AfterPropertiesSet(); - int i = (int) mcfo.GetObject(); - Assert.IsTrue(i == 1); - i = (int) mcfo.GetObject(); - Assert.IsTrue(i == 1); - Assert.IsTrue(mcfo.IsSingleton); - } + public static void Supertypes(ICollection c, IList l, string s) + { + } - [Test] - public void GetNonSingletonStatic() - { - TestClass1._staticField1 = 0; - MethodInvokingFactoryObject mcfo = new MethodInvokingFactoryObject(); - mcfo.TargetType = typeof(TestClass1); - mcfo.TargetMethod = "StaticMethod1"; - mcfo.IsSingleton = false; - mcfo.AfterPropertiesSet(); - int i = (int) mcfo.GetObject(); - Assert.IsTrue(i == 1); - i = (int) mcfo.GetObject(); - Assert.IsTrue(i == 2); - Assert.IsFalse(mcfo.IsSingleton); - } + public static void Supertypes2(ICollection c, IList l, string s, object i) + { + } - [Test] - public void InvokingAMethodThatHasAVoidReturnTypeReturnsNullPlaceHolder() - { - MethodInvokingFactoryObject mcfo = new MethodInvokingFactoryObject(); - mcfo.TargetType = typeof (TestClass1); - mcfo.TargetMethod = "VoidRetvalMethod"; - mcfo.AfterPropertiesSet(); - Assert.AreEqual(MethodInvoker.Void, mcfo.GetObject()); - } - - [Test] - public void GetSupertypesMatchNumArgs() - { - TestClass1._staticField1 = 0; - MethodInvokingFactoryObject mcfo = new MethodInvokingFactoryObject(); - mcfo.TargetType = typeof (TestClass1); - mcfo.TargetMethod = "Supertypes"; - mcfo.Arguments = new Object[] {new ArrayList(), new ArrayList(), "hello"}; - // should pass - mcfo.AfterPropertiesSet(); - } - - [Test] - public void GetSupertypesTooManyArgs() - { - MethodInvokingFactoryObject mcfo = new MethodInvokingFactoryObject(); - mcfo.TargetType = typeof (TestClass1); - mcfo.TargetMethod = "Supertypes2"; - mcfo.Arguments = new Object[] {new ArrayList(), new ArrayList(), "hello", "bogus"}; - Assert.Throws(() => mcfo.AfterPropertiesSet(), "Unable to determine which exact method to call; found '2' matches."); - } - - [Test] - public void GetMisMatchedArgumentTypes() - { - MethodInvokingFactoryObject mcfo = new MethodInvokingFactoryObject(); - mcfo.TargetType = typeof (TestClass1); - mcfo.TargetMethod = "Supertypes"; - mcfo.Arguments = new Object[] {"1", "2", "3"}; - Assert.Throws(() => mcfo.AfterPropertiesSet()); - } - - [Test] - public void GetObjectType() - { - TestClass1 tc1 = new TestClass1(); - MethodInvokingFactoryObject mcfo = new MethodInvokingFactoryObject(); - mcfo.TargetObject = tc1; - mcfo.TargetMethod = "Method1"; - mcfo.AfterPropertiesSet(); - Assert.IsTrue(typeof (int).Equals(mcfo.ObjectType)); - - mcfo = new MethodInvokingFactoryObject(); - mcfo.TargetType = typeof (TestClass1); - mcfo.TargetMethod = "VoidRetvalMethod"; - mcfo.AfterPropertiesSet(); - Type objType = mcfo.ObjectType; - Assert.IsTrue(objType.Equals(MethodInvoker.Void.GetType())); - - // verify that we can call a method with args that are subtypes of the - // target method arg types - TestClass1._staticField1 = 0; - mcfo = new MethodInvokingFactoryObject(); - mcfo.TargetType = typeof (TestClass1); - mcfo.TargetMethod = "Supertypes"; - mcfo.Arguments = new Object[] {new ArrayList(), new ArrayList(), "hello"}; - mcfo.AfterPropertiesSet(); - objType = mcfo.ObjectType; - } - - [Test] - public void ObjectTypeIsNullIfAfterPropertiesSetHasNotYetBeenInvoked() - { - MethodInvokingFactoryObject mcfo = new MethodInvokingFactoryObject(); - mcfo.TargetType = typeof (TestClass1); - mcfo.TargetMethod = "VoidRetvalMethod"; - Assert.IsNull(mcfo.ObjectType, - "ObjectType property value must only be set to a non null value " + - "AFTER the AfterPropertiesSet() method has been invoked."); - } - - [Test] - public void BailsIfTheTargetMethodPropertyAintSet() - { - MethodInvokingFactoryObject mcfo = new MethodInvokingFactoryObject(); - Assert.Throws(() => mcfo.AfterPropertiesSet(), "The 'TargetMethod' property is required."); - } - - [Test] - public void AfterPropertiesSetBogusMethod() - { - MethodInvokingFactoryObject mcfo = new MethodInvokingFactoryObject(); - mcfo.TargetObject = this; - mcfo.TargetMethod = "whatever"; - Assert.Throws(() => mcfo.AfterPropertiesSet()); - } - - [Test] - public void AfterPropertiesSetBogusStaticMethod() - { - MethodInvokingFactoryObject mcfo = new MethodInvokingFactoryObject(); - mcfo.TargetType = typeof (TestClass1); - mcfo.TargetMethod = "some.bogus.Method.name"; - Assert.Throws(() => mcfo.AfterPropertiesSet()); - } - - [Test] - public void AfterPropertiesSetStaticMethodMissingArgs() - { - MethodInvokingFactoryObject mcfo = new MethodInvokingFactoryObject(); - mcfo.TargetType = typeof (TestClass1); - mcfo.TargetMethod = "Method1"; - Assert.Throws(() => mcfo.AfterPropertiesSet()); - } - - [Test] - public void AfterPropertiesSetMissingMethod() - { - MethodInvokingFactoryObject mcfo = new MethodInvokingFactoryObject(); - mcfo.TargetObject = this; - Assert.Throws(() => mcfo.AfterPropertiesSet()); - } - - [Test] - public void InvokeWithNullArgument() - { - MethodInvoker methodInvoker = new MethodInvoker(); - methodInvoker.TargetType = GetType(); - methodInvoker.TargetMethod = "NullArgument"; - methodInvoker.Arguments = new object[] {null}; - methodInvoker.Prepare(); - methodInvoker.Invoke(); - } - - public static void NullArgument(object arg) - { - } - - // a test class to work with - public class TestClass1 - { - public static int _staticField1; - public int _field1 = 0; - - public int Method1() - { - return ++_field1; - } - - public static int StaticMethod1() - { - return ++_staticField1; - } - - public static void VoidRetvalMethod() - { - } - - public static void Supertypes(ICollection c, IList l, string s) - { - } - - public static void Supertypes2(ICollection c, IList l, string s, object i) - { - } - - public static void Supertypes2(ICollection c, IList l, string s, string s2) - { - } - } - } -} \ No newline at end of file + public static void Supertypes2(ICollection c, IList l, string s, string s2) + { + } + } +} diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/ObjectDefinitionVisitorTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/ObjectDefinitionVisitorTests.cs index 6ba428c7..e8cfd664 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/ObjectDefinitionVisitorTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/ObjectDefinitionVisitorTests.cs @@ -23,139 +23,138 @@ using System.Collections.Specialized; using NUnit.Framework; using Spring.Objects.Factory.Support; -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Unit tests for the ObjectDefinitionVisitor class +/// +/// Bruno Baia +[TestFixture] +public class ObjectDefinitionVisitorTests { - /// - /// Unit tests for the ObjectDefinitionVisitor class - /// - /// Bruno Baia - [TestFixture] - public class ObjectDefinitionVisitorTests + private Hashtable properties; + + [SetUp] + public void SetUp() { - private Hashtable properties; - - [SetUp] - public void SetUp() - { - properties = CollectionsUtil.CreateCaseInsensitiveHashtable(); - properties.Add("Property", "Value"); - } - - private string ParseAndResolveVariables(string rawText) - { - if (rawText.StartsWith("$")) - { - return (string) properties[rawText.Substring(1)]; - } - return rawText; - } - - [Test] - public void BadConstructorCall() - { - Assert.Throws(() => new ObjectDefinitionVisitor(null)); - } - - [Test] - public void VisitObjectTypeName() - { - IObjectDefinition od = new RootObjectDefinition(); - od.ObjectTypeName = "$Property"; - - ObjectDefinitionVisitor odv = new ObjectDefinitionVisitor(new ObjectDefinitionVisitor.ResolveHandler(ParseAndResolveVariables)); - odv.VisitObjectDefinition(od); - - Assert.AreEqual("Value", od.ObjectTypeName); - } - - [Test] - public void VisitPropertyValues() - { - IObjectDefinition od = new RootObjectDefinition(); - od.PropertyValues.Add("PropertyName", "$Property"); - - ObjectDefinitionVisitor odv = new ObjectDefinitionVisitor(new ObjectDefinitionVisitor.ResolveHandler(ParseAndResolveVariables)); - odv.VisitObjectDefinition(od); - - Assert.AreEqual("Value", od.PropertyValues.GetPropertyValue("PropertyName").Value); - } - - - [Test] - public void VisitManagedList() - { - IObjectDefinition od = new RootObjectDefinition(); - ManagedList ml = new ManagedList(); - ml.ElementTypeName = "$Property"; - ml.Add("$Property"); - od.PropertyValues.Add("PropertyName", ml); - - ObjectDefinitionVisitor odv = new ObjectDefinitionVisitor(new ObjectDefinitionVisitor.ResolveHandler(ParseAndResolveVariables)); - odv.VisitObjectDefinition(od); - - ManagedList list = od.PropertyValues.GetPropertyValue("PropertyName").Value as ManagedList; - - Assert.IsNotNull(list, "Property value is not of type ManagedList. Type = [" + - od.PropertyValues.GetPropertyValue("PropertyName").Value.GetType() + "]"); - Assert.AreEqual("Value", list.ElementTypeName); - Assert.AreEqual("Value", list[0]); - } - - [Test] - public void VisitManagedSet() - { - IObjectDefinition od = new RootObjectDefinition(); - ManagedSet ms = new ManagedSet(); - ms.ElementTypeName = "$Property"; - ms.Add("$Property"); - od.PropertyValues.Add("PropertyName", ms); - - ObjectDefinitionVisitor odv = new ObjectDefinitionVisitor(new ObjectDefinitionVisitor.ResolveHandler(ParseAndResolveVariables)); - odv.VisitObjectDefinition(od); - - ManagedSet set = od.PropertyValues.GetPropertyValue("PropertyName").Value as ManagedSet; - - Assert.AreEqual("Value", set.ElementTypeName); - IEnumerator enumerator = set.GetEnumerator(); - enumerator.MoveNext(); - Assert.AreEqual("Value", enumerator.Current); - } - - [Test] - public void VisitManagedDictionary() - { - IObjectDefinition od = new RootObjectDefinition(); - ManagedDictionary md = new ManagedDictionary(); - md.KeyTypeName = "$Property"; - md.ValueTypeName = "$Property"; - md.Add("Key", "$Property"); - od.PropertyValues.Add("PropertyName", md); - - ObjectDefinitionVisitor odv = new ObjectDefinitionVisitor(new ObjectDefinitionVisitor.ResolveHandler(ParseAndResolveVariables)); - odv.VisitObjectDefinition(od); - - ManagedDictionary dictionary = od.PropertyValues.GetPropertyValue("PropertyName").Value as ManagedDictionary; - - Assert.AreEqual("Value", dictionary.KeyTypeName); - Assert.AreEqual("Value", dictionary.ValueTypeName); - Assert.AreEqual("Value", dictionary["Key"]); - } - - [Test] - public void VisitNameValueCollection() - { - IObjectDefinition od = new RootObjectDefinition(); - NameValueCollection nvc = new NameValueCollection(); - nvc["Key"] = "$Property"; - od.PropertyValues.Add("PropertyName", nvc); - - ObjectDefinitionVisitor odv = new ObjectDefinitionVisitor(new ObjectDefinitionVisitor.ResolveHandler(ParseAndResolveVariables)); - odv.VisitObjectDefinition(od); - - NameValueCollection visitedNvc = - od.PropertyValues.GetPropertyValue("PropertyName").Value as NameValueCollection; - - Assert.AreEqual("Value", visitedNvc["Key"]); - } + properties = CollectionsUtil.CreateCaseInsensitiveHashtable(); + properties.Add("Property", "Value"); } -} \ No newline at end of file + + private string ParseAndResolveVariables(string rawText) + { + if (rawText.StartsWith("$")) + { + return (string) properties[rawText.Substring(1)]; + } + + return rawText; + } + + [Test] + public void BadConstructorCall() + { + Assert.Throws(() => new ObjectDefinitionVisitor(null)); + } + + [Test] + public void VisitObjectTypeName() + { + IObjectDefinition od = new RootObjectDefinition(); + od.ObjectTypeName = "$Property"; + + ObjectDefinitionVisitor odv = new ObjectDefinitionVisitor(new ObjectDefinitionVisitor.ResolveHandler(ParseAndResolveVariables)); + odv.VisitObjectDefinition(od); + + Assert.AreEqual("Value", od.ObjectTypeName); + } + + [Test] + public void VisitPropertyValues() + { + IObjectDefinition od = new RootObjectDefinition(); + od.PropertyValues.Add("PropertyName", "$Property"); + + ObjectDefinitionVisitor odv = new ObjectDefinitionVisitor(new ObjectDefinitionVisitor.ResolveHandler(ParseAndResolveVariables)); + odv.VisitObjectDefinition(od); + + Assert.AreEqual("Value", od.PropertyValues.GetPropertyValue("PropertyName").Value); + } + + [Test] + public void VisitManagedList() + { + IObjectDefinition od = new RootObjectDefinition(); + ManagedList ml = new ManagedList(); + ml.ElementTypeName = "$Property"; + ml.Add("$Property"); + od.PropertyValues.Add("PropertyName", ml); + + ObjectDefinitionVisitor odv = new ObjectDefinitionVisitor(new ObjectDefinitionVisitor.ResolveHandler(ParseAndResolveVariables)); + odv.VisitObjectDefinition(od); + + ManagedList list = od.PropertyValues.GetPropertyValue("PropertyName").Value as ManagedList; + + Assert.IsNotNull(list, "Property value is not of type ManagedList. Type = [" + + od.PropertyValues.GetPropertyValue("PropertyName").Value.GetType() + "]"); + Assert.AreEqual("Value", list.ElementTypeName); + Assert.AreEqual("Value", list[0]); + } + + [Test] + public void VisitManagedSet() + { + IObjectDefinition od = new RootObjectDefinition(); + ManagedSet ms = new ManagedSet(); + ms.ElementTypeName = "$Property"; + ms.Add("$Property"); + od.PropertyValues.Add("PropertyName", ms); + + ObjectDefinitionVisitor odv = new ObjectDefinitionVisitor(new ObjectDefinitionVisitor.ResolveHandler(ParseAndResolveVariables)); + odv.VisitObjectDefinition(od); + + ManagedSet set = od.PropertyValues.GetPropertyValue("PropertyName").Value as ManagedSet; + + Assert.AreEqual("Value", set.ElementTypeName); + IEnumerator enumerator = set.GetEnumerator(); + enumerator.MoveNext(); + Assert.AreEqual("Value", enumerator.Current); + } + + [Test] + public void VisitManagedDictionary() + { + IObjectDefinition od = new RootObjectDefinition(); + ManagedDictionary md = new ManagedDictionary(); + md.KeyTypeName = "$Property"; + md.ValueTypeName = "$Property"; + md.Add("Key", "$Property"); + od.PropertyValues.Add("PropertyName", md); + + ObjectDefinitionVisitor odv = new ObjectDefinitionVisitor(new ObjectDefinitionVisitor.ResolveHandler(ParseAndResolveVariables)); + odv.VisitObjectDefinition(od); + + ManagedDictionary dictionary = od.PropertyValues.GetPropertyValue("PropertyName").Value as ManagedDictionary; + + Assert.AreEqual("Value", dictionary.KeyTypeName); + Assert.AreEqual("Value", dictionary.ValueTypeName); + Assert.AreEqual("Value", dictionary["Key"]); + } + + [Test] + public void VisitNameValueCollection() + { + IObjectDefinition od = new RootObjectDefinition(); + NameValueCollection nvc = new NameValueCollection(); + nvc["Key"] = "$Property"; + od.PropertyValues.Add("PropertyName", nvc); + + ObjectDefinitionVisitor odv = new ObjectDefinitionVisitor(new ObjectDefinitionVisitor.ResolveHandler(ParseAndResolveVariables)); + odv.VisitObjectDefinition(od); + + NameValueCollection visitedNvc = + od.PropertyValues.GetPropertyValue("PropertyName").Value as NameValueCollection; + + Assert.AreEqual("Value", visitedNvc["Key"]); + } +} diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/ObjectFactoryCreatingFactoryObjectTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/ObjectFactoryCreatingFactoryObjectTests.cs index 3ba7178d..a5ceaecd 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/ObjectFactoryCreatingFactoryObjectTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/ObjectFactoryCreatingFactoryObjectTests.cs @@ -19,85 +19,83 @@ #endregion using FakeItEasy; - using NUnit.Framework; -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Unit tests for the ObjectFactoryCreatingFactoryObject class. +/// +/// Colin Sampaleanu +/// Simon White (.NET) +[TestFixture] +public sealed class ObjectFactoryCreatingFactoryObjectTests { - /// - /// Unit tests for the ObjectFactoryCreatingFactoryObject class. - /// - /// Colin Sampaleanu - /// Simon White (.NET) - [TestFixture] - public sealed class ObjectFactoryCreatingFactoryObjectTests - { - [SetUp] - public void Setup() - { - } + [SetUp] + public void Setup() + { + } - [Test] - public void SunnyDay() - { - TestObject dude = new TestObject("Rick Evans", 30); - IObjectFactory objectFactory = A.Fake(); - const string lookupObjectName = "rick"; - A.CallTo(() => objectFactory.GetObject(lookupObjectName)).Returns(dude).Twice(); - ObjectFactoryCreatingFactoryObject factory = new ObjectFactoryCreatingFactoryObject(); - factory.ObjectFactory = objectFactory; - factory.TargetObjectName = lookupObjectName; - factory.AfterPropertiesSet(); + [Test] + public void SunnyDay() + { + TestObject dude = new TestObject("Rick Evans", 30); + IObjectFactory objectFactory = A.Fake(); + const string lookupObjectName = "rick"; + A.CallTo(() => objectFactory.GetObject(lookupObjectName)).Returns(dude).Twice(); + ObjectFactoryCreatingFactoryObject factory = new ObjectFactoryCreatingFactoryObject(); + factory.ObjectFactory = objectFactory; + factory.TargetObjectName = lookupObjectName; + factory.AfterPropertiesSet(); - IGenericObjectFactory gof = (IGenericObjectFactory) factory.GetObject(); - IGenericObjectFactory gofOther = (IGenericObjectFactory) factory.GetObject(); - Assert.IsTrue(Object.ReferenceEquals(gof, gofOther), - "Not returning a shared instance (Singleton = true)."); - TestObject one = (TestObject) gof.GetObject(); - Assert.IsNotNull(one, "Must never return null (IFactoryObject contract)."); - TestObject two = (TestObject) gof.GetObject(); - Assert.IsNotNull(two, "Must never return null (IFactoryObject contract)."); - Assert.IsTrue(Object.ReferenceEquals(one, two), - "Not returning the same instance."); - } + IGenericObjectFactory gof = (IGenericObjectFactory) factory.GetObject(); + IGenericObjectFactory gofOther = (IGenericObjectFactory) factory.GetObject(); + Assert.IsTrue(Object.ReferenceEquals(gof, gofOther), + "Not returning a shared instance (Singleton = true)."); + TestObject one = (TestObject) gof.GetObject(); + Assert.IsNotNull(one, "Must never return null (IFactoryObject contract)."); + TestObject two = (TestObject) gof.GetObject(); + Assert.IsNotNull(two, "Must never return null (IFactoryObject contract)."); + Assert.IsTrue(Object.ReferenceEquals(one, two), + "Not returning the same instance."); + } - [Test] - public void PrototypeModeWithSingletonTarget() - { - TestObject dude = new TestObject("Rick Evans", 30); - IObjectFactory objectFactory = A.Fake(); - const string lookupObjectName = "rick"; - A.CallTo(() => objectFactory.GetObject(lookupObjectName)).Returns(dude).Twice(); - ObjectFactoryCreatingFactoryObject factory = new ObjectFactoryCreatingFactoryObject(); - factory.ObjectFactory = objectFactory; - factory.TargetObjectName = lookupObjectName; - factory.IsSingleton = false; - factory.AfterPropertiesSet(); + [Test] + public void PrototypeModeWithSingletonTarget() + { + TestObject dude = new TestObject("Rick Evans", 30); + IObjectFactory objectFactory = A.Fake(); + const string lookupObjectName = "rick"; + A.CallTo(() => objectFactory.GetObject(lookupObjectName)).Returns(dude).Twice(); + ObjectFactoryCreatingFactoryObject factory = new ObjectFactoryCreatingFactoryObject(); + factory.ObjectFactory = objectFactory; + factory.TargetObjectName = lookupObjectName; + factory.IsSingleton = false; + factory.AfterPropertiesSet(); - IGenericObjectFactory gofOne = (IGenericObjectFactory) factory.GetObject(); - IGenericObjectFactory gofTwo = (IGenericObjectFactory) factory.GetObject(); - Assert.IsFalse(Object.ReferenceEquals(gofOne, gofTwo), - "Not returning distinct instances (Prototype = true)."); - TestObject one = (TestObject) gofOne.GetObject(); - Assert.IsNotNull(one, "Must never return null (IFactoryObject contract)."); - TestObject two = (TestObject) gofTwo.GetObject(); - Assert.IsNotNull(two, "Must never return null (IFactoryObject contract)."); - Assert.IsTrue(Object.ReferenceEquals(one, two), - "Not returning the same instance to singleton object."); - } + IGenericObjectFactory gofOne = (IGenericObjectFactory) factory.GetObject(); + IGenericObjectFactory gofTwo = (IGenericObjectFactory) factory.GetObject(); + Assert.IsFalse(Object.ReferenceEquals(gofOne, gofTwo), + "Not returning distinct instances (Prototype = true)."); + TestObject one = (TestObject) gofOne.GetObject(); + Assert.IsNotNull(one, "Must never return null (IFactoryObject contract)."); + TestObject two = (TestObject) gofTwo.GetObject(); + Assert.IsNotNull(two, "Must never return null (IFactoryObject contract)."); + Assert.IsTrue(Object.ReferenceEquals(one, two), + "Not returning the same instance to singleton object."); + } - [Test] - public void WithMissingObjectName() - { - ObjectFactoryCreatingFactoryObject factory - = new ObjectFactoryCreatingFactoryObject(); - Assert.Throws(() => factory.AfterPropertiesSet(), "The 'TargetObjectName' property must have a value."); - } + [Test] + public void WithMissingObjectName() + { + ObjectFactoryCreatingFactoryObject factory + = new ObjectFactoryCreatingFactoryObject(); + Assert.Throws(() => factory.AfterPropertiesSet(), "The 'TargetObjectName' property must have a value."); + } - [Test] - public void ObjectTypeReallyIsIGenericObjectFactory() - { - Assert.AreEqual(typeof (IGenericObjectFactory), new ObjectFactoryCreatingFactoryObject().ObjectType); - } - } -} \ No newline at end of file + [Test] + public void ObjectTypeReallyIsIGenericObjectFactory() + { + Assert.AreEqual(typeof(IGenericObjectFactory), new ObjectFactoryCreatingFactoryObject().ObjectType); + } +} diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/ObjectReferenceFactoryObjectTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/ObjectReferenceFactoryObjectTests.cs index 9a1cba7b..0967b296 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/ObjectReferenceFactoryObjectTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/ObjectReferenceFactoryObjectTests.cs @@ -19,95 +19,93 @@ #endregion using FakeItEasy; - using NUnit.Framework; -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Unit tests for the ObjectReferenceFactoryObject class. +/// +/// Rick Evans +[TestFixture] +public sealed class ObjectReferenceFactoryObjectTests { - /// - /// Unit tests for the ObjectReferenceFactoryObject class. - /// - /// Rick Evans - [TestFixture] - public sealed class ObjectReferenceFactoryObjectTests + private IObjectFactory factory; + + [SetUp] + public void SetUp() { - private IObjectFactory factory; + factory = A.Fake(); + } - [SetUp] - public void SetUp() - { - factory = A.Fake(); - } + [Test] + public void NullTargetObjectName() + { + ObjectReferenceFactoryObject fac = new ObjectReferenceFactoryObject(); + // simulate IFactoryObjectAware interface... + Assert.Throws(() => fac.ObjectFactory = null); + } - [Test] - public void NullTargetObjectName() - { - ObjectReferenceFactoryObject fac = new ObjectReferenceFactoryObject(); - // simulate IFactoryObjectAware interface... - Assert.Throws(() => fac.ObjectFactory = null); - } + [Test] + public void WhitespaceTargetObjectName() + { + ObjectReferenceFactoryObject fac = new ObjectReferenceFactoryObject(); + fac.TargetObjectName = string.Empty; + // simulate IFactoryObjectAware interface... + Assert.Throws(() => fac.ObjectFactory = null); + } - [Test] - public void WhitespaceTargetObjectName() - { - ObjectReferenceFactoryObject fac = new ObjectReferenceFactoryObject(); - fac.TargetObjectName = string.Empty; - // simulate IFactoryObjectAware interface... - Assert.Throws(() => fac.ObjectFactory = null); - } + [Test] + public void FactoryDoesNotContainTargetObject() + { + A.CallTo(() => factory.ContainsObject("bojangles")).Returns(false); - [Test] - public void FactoryDoesNotContainTargetObject() - { - A.CallTo(() => factory.ContainsObject("bojangles")).Returns(false); + ObjectReferenceFactoryObject fac = new ObjectReferenceFactoryObject(); + fac.TargetObjectName = "bojangles"; - ObjectReferenceFactoryObject fac = new ObjectReferenceFactoryObject(); - fac.TargetObjectName = "bojangles"; + // simulate IFactoryObjectAware interface... + Assert.Throws(() => fac.ObjectFactory = factory, + "Must have bailed with a " + + "NoSuchObjectDefinitionException 'cos the object doesn't " + + "exist in the associated factory."); + } - // simulate IFactoryObjectAware interface... - Assert.Throws(() => fac.ObjectFactory = factory, - "Must have bailed with a " + - "NoSuchObjectDefinitionException 'cos the object doesn't " + - "exist in the associated factory."); - } + [Test] + public void DelegatesThroughToFactoryFor_IsSingleton() + { + A.CallTo(() => factory.ContainsObject("bojangles")).Returns(true); + A.CallTo(() => factory.IsSingleton("bojangles")).Returns(true); - [Test] - public void DelegatesThroughToFactoryFor_IsSingleton() - { - A.CallTo(() => factory.ContainsObject("bojangles")).Returns(true); - A.CallTo(() => factory.IsSingleton("bojangles")).Returns(true); + ObjectReferenceFactoryObject fac = new ObjectReferenceFactoryObject(); + fac.TargetObjectName = "bojangles"; + fac.ObjectFactory = factory; - ObjectReferenceFactoryObject fac = new ObjectReferenceFactoryObject(); - fac.TargetObjectName = "bojangles"; - fac.ObjectFactory = factory; + Assert.IsTrue(fac.IsSingleton); + } - Assert.IsTrue(fac.IsSingleton); - } + [Test] + public void DelegatesThroughToFactoryFor_GetObject() + { + A.CallTo(() => factory.ContainsObject("bojangles")).Returns(true); + A.CallTo(() => factory.GetObject("bojangles")).Returns("Rick"); - [Test] - public void DelegatesThroughToFactoryFor_GetObject() - { - A.CallTo(() => factory.ContainsObject("bojangles")).Returns(true); - A.CallTo(() => factory.GetObject("bojangles")).Returns("Rick"); + ObjectReferenceFactoryObject fac = new ObjectReferenceFactoryObject(); + fac.TargetObjectName = "bojangles"; + fac.ObjectFactory = factory; - ObjectReferenceFactoryObject fac = new ObjectReferenceFactoryObject(); - fac.TargetObjectName = "bojangles"; - fac.ObjectFactory = factory; + Assert.AreEqual("Rick", fac.GetObject()); + } - Assert.AreEqual("Rick", fac.GetObject()); - } + [Test] + public void DelegatesThroughToFactoryFor_ObjectType() + { + A.CallTo(() => factory.ContainsObject("bojangles")).Returns(true); + A.CallTo(() => factory.GetType("bojangles")).Returns(GetType()); - [Test] - public void DelegatesThroughToFactoryFor_ObjectType() - { - A.CallTo(() => factory.ContainsObject("bojangles")).Returns(true); - A.CallTo(() => factory.GetType("bojangles")).Returns(GetType()); + ObjectReferenceFactoryObject fac = new ObjectReferenceFactoryObject(); + fac.TargetObjectName = "bojangles"; + fac.ObjectFactory = factory; - ObjectReferenceFactoryObject fac = new ObjectReferenceFactoryObject(); - fac.TargetObjectName = "bojangles"; - fac.ObjectFactory = factory; - - Assert.AreEqual(GetType(), fac.ObjectType); - } + Assert.AreEqual(GetType(), fac.ObjectType); } } \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/PropertyFileVariableSourceTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/PropertyFileVariableSourceTests.cs index e0387f09..d0fffcfc 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/PropertyFileVariableSourceTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/PropertyFileVariableSourceTests.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -25,72 +25,67 @@ using Spring.Core.IO; #endregion -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Unit tests for the PropertyFileVariableSource class. +/// +/// Aleksandar Seovic +[TestFixture] +public sealed class PropertyFileVariableSourceTests { - /// - /// Unit tests for the PropertyFileVariableSource class. - /// - /// Aleksandar Seovic - [TestFixture] - public sealed class PropertyFileVariableSourceTests + [Test] + public void TestVariablesResolutionWithSingleLocation() { - [Test] - public void TestVariablesResolutionWithSingleLocation() - { - PropertyFileVariableSource vs = new PropertyFileVariableSource(); - vs.Location = - new AssemblyResource( - "assembly://Spring.Core.Tests/Spring.Data.Spring.Objects.Factory.Config/one.properties"); + PropertyFileVariableSource vs = new PropertyFileVariableSource(); + vs.Location = + new AssemblyResource( + "assembly://Spring.Core.Tests/Spring.Data.Spring.Objects.Factory.Config/one.properties"); - // existing vars - Assert.AreEqual("Aleks Seovic", vs.ResolveVariable("name")); - Assert.AreEqual("32", vs.ResolveVariable("age")); + // existing vars + Assert.AreEqual("Aleks Seovic", vs.ResolveVariable("name")); + Assert.AreEqual("32", vs.ResolveVariable("age")); - // non-existant variable - Assert.IsNull(vs.ResolveVariable("dummy")); - } - - [Test] - public void TestMissingResourceLocation() - { - PropertyFileVariableSource vs = new PropertyFileVariableSource(); - vs.IgnoreMissingResources = true; - vs.Locations = new IResource[] - { - new AssemblyResource( - "assembly://Spring.Core.Tests/Spring.Data.Spring.Objects.Factory.Config/non-existent.properties") - , - new AssemblyResource( - "assembly://Spring.Core.Tests/Spring.Data.Spring.Objects.Factory.Config/one.properties") - , - }; - - // existing vars - Assert.AreEqual("Aleks Seovic", vs.ResolveVariable("name")); - Assert.AreEqual("32", vs.ResolveVariable("age")); - } - - - [Test] - public void TestVariablesResolutionWithTwoLocations() - { - PropertyFileVariableSource vs = new PropertyFileVariableSource(); - vs.Locations = new IResource[] - { - new AssemblyResource( - "assembly://Spring.Core.Tests/Spring.Data.Spring.Objects.Factory.Config/one.properties") - , - new AssemblyResource( - "assembly://Spring.Core.Tests/Spring.Data.Spring.Objects.Factory.Config/two.properties") - }; - - // existing vars - Assert.AreEqual("Aleksandar Seovic", vs.ResolveVariable("name")); // should be overriden by the second file - Assert.AreEqual("32", vs.ResolveVariable("age")); - Assert.AreEqual("Marija,Ana,Nadja", vs.ResolveVariable("family")); - - // non-existant variable - Assert.IsNull(vs.ResolveVariable("dummy")); - } + // non-existant variable + Assert.IsNull(vs.ResolveVariable("dummy")); } -} \ No newline at end of file + + [Test] + public void TestMissingResourceLocation() + { + PropertyFileVariableSource vs = new PropertyFileVariableSource(); + vs.IgnoreMissingResources = true; + vs.Locations = new IResource[] + { + new AssemblyResource( + "assembly://Spring.Core.Tests/Spring.Data.Spring.Objects.Factory.Config/non-existent.properties"), + new AssemblyResource( + "assembly://Spring.Core.Tests/Spring.Data.Spring.Objects.Factory.Config/one.properties"), + }; + + // existing vars + Assert.AreEqual("Aleks Seovic", vs.ResolveVariable("name")); + Assert.AreEqual("32", vs.ResolveVariable("age")); + } + + [Test] + public void TestVariablesResolutionWithTwoLocations() + { + PropertyFileVariableSource vs = new PropertyFileVariableSource(); + vs.Locations = new IResource[] + { + new AssemblyResource( + "assembly://Spring.Core.Tests/Spring.Data.Spring.Objects.Factory.Config/one.properties"), + new AssemblyResource( + "assembly://Spring.Core.Tests/Spring.Data.Spring.Objects.Factory.Config/two.properties") + }; + + // existing vars + Assert.AreEqual("Aleksandar Seovic", vs.ResolveVariable("name")); // should be overriden by the second file + Assert.AreEqual("32", vs.ResolveVariable("age")); + Assert.AreEqual("Marija,Ana,Nadja", vs.ResolveVariable("family")); + + // non-existant variable + Assert.IsNull(vs.ResolveVariable("dummy")); + } +} diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/PropertyOverrideConfigurerTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/PropertyOverrideConfigurerTests.cs index 97a123b9..aff3ef00 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/PropertyOverrideConfigurerTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/PropertyOverrideConfigurerTests.cs @@ -19,7 +19,6 @@ #endregion using System.Collections.Specialized; - using FakeItEasy; using Microsoft.Extensions.Logging.Abstractions; using NUnit.Framework; @@ -27,154 +26,153 @@ using Spring.Context.Support; using Spring.Core.IO; using Spring.Objects.Factory.Xml; -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Unit tests for the PropertyOverrideConfigurer class. +/// +/// Rick Evans +[TestFixture] +public sealed class PropertyOverrideConfigurerTests { - /// - /// Unit tests for the PropertyOverrideConfigurer class. - /// - /// Rick Evans - [TestFixture] - public sealed class PropertyOverrideConfigurerTests - { - [SetUp] - public void Setup() - { - } + [SetUp] + public void Setup() + { + } - /// - /// The setup logic executed before the execution of this test fixture. - /// - [OneTimeSetUp] - public void FixtureSetUp() - { - // enable (null appender) logging, just to ensure that the logging code is correct - LogManager.LoggerFactory = NullLoggerFactory.Instance; - } + /// + /// The setup logic executed before the execution of this test fixture. + /// + [OneTimeSetUp] + public void FixtureSetUp() + { + // enable (null appender) logging, just to ensure that the logging code is correct + LogManager.LoggerFactory = NullLoggerFactory.Instance; + } - [Test] - public void AddPropertyValue() - { - StaticApplicationContext ac = new StaticApplicationContext(); - ac.RegisterSingleton("tb1", typeof(TestObject), new MutablePropertyValues()); - ac.RegisterSingleton("tb2", typeof(TestObject), new MutablePropertyValues()); - MutablePropertyValues pvs = new MutablePropertyValues(); - pvs.Add("Properties", ""); - ac.RegisterSingleton("configurer1", typeof(PropertyOverrideConfigurer), pvs); - pvs = new MutablePropertyValues(); - pvs.Add("Properties", ""); - pvs.Add("order", "0"); - ac.RegisterSingleton("configurer2", typeof(PropertyOverrideConfigurer), pvs); - ac.Refresh(); - TestObject tb1 = (TestObject)ac.GetObject("tb1"); - TestObject tb2 = (TestObject)ac.GetObject("tb2"); - Assert.AreEqual(99, tb1.Age); - Assert.AreEqual(99, tb2.Age); - Assert.AreEqual(null, tb1.Name); - Assert.AreEqual("test", tb2.Name); - } + [Test] + public void AddPropertyValue() + { + StaticApplicationContext ac = new StaticApplicationContext(); + ac.RegisterSingleton("tb1", typeof(TestObject), new MutablePropertyValues()); + ac.RegisterSingleton("tb2", typeof(TestObject), new MutablePropertyValues()); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.Add("Properties", ""); + ac.RegisterSingleton("configurer1", typeof(PropertyOverrideConfigurer), pvs); + pvs = new MutablePropertyValues(); + pvs.Add("Properties", ""); + pvs.Add("order", "0"); + ac.RegisterSingleton("configurer2", typeof(PropertyOverrideConfigurer), pvs); + ac.Refresh(); + TestObject tb1 = (TestObject) ac.GetObject("tb1"); + TestObject tb2 = (TestObject) ac.GetObject("tb2"); + Assert.AreEqual(99, tb1.Age); + Assert.AreEqual(99, tb2.Age); + Assert.AreEqual(null, tb1.Name); + Assert.AreEqual("test", tb2.Name); + } - [Test] - public void OverridePropertyValue() - { - StaticApplicationContext ac = new StaticApplicationContext(); + [Test] + public void OverridePropertyValue() + { + StaticApplicationContext ac = new StaticApplicationContext(); - MutablePropertyValues pvs = new MutablePropertyValues(); - pvs.Add("Age", 27); - pvs.Add("Name", "Bruno"); - ac.RegisterSingleton("tb1", typeof(TestObject), pvs); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.Add("Age", 27); + pvs.Add("Name", "Bruno"); + ac.RegisterSingleton("tb1", typeof(TestObject), pvs); - pvs = new MutablePropertyValues(); - pvs.Add("Properties", ""); - ac.RegisterSingleton("configurer", typeof (PropertyOverrideConfigurer), pvs); + pvs = new MutablePropertyValues(); + pvs.Add("Properties", ""); + ac.RegisterSingleton("configurer", typeof(PropertyOverrideConfigurer), pvs); - ac.Refresh(); - TestObject tb1 = (TestObject) ac.GetObject("tb1"); - Assert.AreEqual(99, tb1.Age); - Assert.AreEqual("test", tb1.Name); - } + ac.Refresh(); + TestObject tb1 = (TestObject) ac.GetObject("tb1"); + Assert.AreEqual(99, tb1.Age); + Assert.AreEqual("test", tb1.Name); + } - [Test] - public void OverridePropertyReference() - { - StaticApplicationContext ac = new StaticApplicationContext(); + [Test] + public void OverridePropertyReference() + { + StaticApplicationContext ac = new StaticApplicationContext(); - MutablePropertyValues pvs = new MutablePropertyValues(); - pvs.Add("Spouse", new RuntimeObjectReference("spouse1")); - ac.RegisterSingleton("tb1", typeof(TestObject), pvs); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.Add("Spouse", new RuntimeObjectReference("spouse1")); + ac.RegisterSingleton("tb1", typeof(TestObject), pvs); - ac.RegisterSingleton("spouse1", typeof(TestObject), new MutablePropertyValues()); - ac.RegisterSingleton("spouse2", typeof(TestObject), new MutablePropertyValues()); + ac.RegisterSingleton("spouse1", typeof(TestObject), new MutablePropertyValues()); + ac.RegisterSingleton("spouse2", typeof(TestObject), new MutablePropertyValues()); - pvs = new MutablePropertyValues(); - pvs.Add("Properties", ""); - ac.RegisterSingleton("configurer", typeof(PropertyOverrideConfigurer), pvs); + pvs = new MutablePropertyValues(); + pvs.Add("Properties", ""); + ac.RegisterSingleton("configurer", typeof(PropertyOverrideConfigurer), pvs); - ac.Refresh(); - TestObject tb1 = (TestObject)ac.GetObject("tb1"); - TestObject spouse2 = (TestObject)ac.GetObject("spouse2"); - Assert.AreEqual(spouse2, tb1.Spouse); - } + ac.Refresh(); + TestObject tb1 = (TestObject) ac.GetObject("tb1"); + TestObject spouse2 = (TestObject) ac.GetObject("spouse2"); + Assert.AreEqual(spouse2, tb1.Spouse); + } - [Test] - public void OverridePropertyExpression() - { - StaticApplicationContext ac = new StaticApplicationContext(); + [Test] + public void OverridePropertyExpression() + { + StaticApplicationContext ac = new StaticApplicationContext(); - MutablePropertyValues pvs = new MutablePropertyValues(); - pvs.Add("Age", new ExpressionHolder("26+1")); - ac.RegisterSingleton("tb1", typeof(TestObject), pvs); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.Add("Age", new ExpressionHolder("26+1")); + ac.RegisterSingleton("tb1", typeof(TestObject), pvs); - pvs = new MutablePropertyValues(); - pvs.Add("Properties", ""); - ac.RegisterSingleton("configurer", typeof(PropertyOverrideConfigurer), pvs); + pvs = new MutablePropertyValues(); + pvs.Add("Properties", ""); + ac.RegisterSingleton("configurer", typeof(PropertyOverrideConfigurer), pvs); - ac.Refresh(); - TestObject tb1 = (TestObject)ac.GetObject("tb1"); - Assert.AreEqual(25, tb1.Age); - } + ac.Refresh(); + TestObject tb1 = (TestObject) ac.GetObject("tb1"); + Assert.AreEqual(25, tb1.Age); + } - [Test] - public void MalformedOverrideKey() - { - IConfigurableListableObjectFactory objectFactory = A.Fake(); - IConfigurableListableObjectFactory fac = objectFactory; + [Test] + public void MalformedOverrideKey() + { + IConfigurableListableObjectFactory objectFactory = A.Fake(); + IConfigurableListableObjectFactory fac = objectFactory; - PropertyOverrideConfigurer cfg = new PropertyOverrideConfigurer(); - NameValueCollection defaultProperties = new NameValueCollection(); - defaultProperties.Add("malformedKey", "Rick Evans"); - cfg.Properties = defaultProperties; + PropertyOverrideConfigurer cfg = new PropertyOverrideConfigurer(); + NameValueCollection defaultProperties = new NameValueCollection(); + defaultProperties.Add("malformedKey", "Rick Evans"); + cfg.Properties = defaultProperties; - Assert.Throws(() => cfg.PostProcessObjectFactory(fac)); - } + Assert.Throws(() => cfg.PostProcessObjectFactory(fac)); + } - [Test] - public void MissingObjectDefinitionDoesntRaiseFatalException() - { - const string valueTo_NOT_BeOveridden = "Jenny Lewis"; - TestObject foo = new TestObject(valueTo_NOT_BeOveridden, 30); - IConfigurableListableObjectFactory objectFactory = A.Fake(); - A.CallTo(() => objectFactory.GetObjectDefinition("rubbish")).Returns(null); - IConfigurableListableObjectFactory fac = objectFactory; + [Test] + public void MissingObjectDefinitionDoesntRaiseFatalException() + { + const string valueTo_NOT_BeOveridden = "Jenny Lewis"; + TestObject foo = new TestObject(valueTo_NOT_BeOveridden, 30); + IConfigurableListableObjectFactory objectFactory = A.Fake(); + A.CallTo(() => objectFactory.GetObjectDefinition("rubbish")).Returns(null); + IConfigurableListableObjectFactory fac = objectFactory; - PropertyOverrideConfigurer cfg = new PropertyOverrideConfigurer(); - NameValueCollection defaultProperties = new NameValueCollection(); - defaultProperties.Add("rubbish.Name", "Rick Evans"); - cfg.Properties = defaultProperties; + PropertyOverrideConfigurer cfg = new PropertyOverrideConfigurer(); + NameValueCollection defaultProperties = new NameValueCollection(); + defaultProperties.Add("rubbish.Name", "Rick Evans"); + cfg.Properties = defaultProperties; - cfg.PostProcessObjectFactory(fac); - Assert.AreEqual(valueTo_NOT_BeOveridden, foo.Name, "Property value was overridden, but a rubbish objectName root was supplied."); - } + cfg.PostProcessObjectFactory(fac); + Assert.AreEqual(valueTo_NOT_BeOveridden, foo.Name, "Property value was overridden, but a rubbish objectName root was supplied."); + } - [Test] - public void ViaXML() - { - IResource resource = new ReadOnlyXmlTestResource("PropertyResourceConfigurerTests.xml", GetType()); - XmlObjectFactory xbf = new XmlObjectFactory(resource); - PropertyOverrideConfigurer poc = (PropertyOverrideConfigurer) xbf.GetObject("OverrideConfigurer"); - Assert.IsNotNull(poc); - poc.PostProcessObjectFactory(xbf); - TestObject to = (TestObject) xbf.GetObject("Test2"); - Assert.AreEqual("Overriden Name", to.Name); - } - } + [Test] + public void ViaXML() + { + IResource resource = new ReadOnlyXmlTestResource("PropertyResourceConfigurerTests.xml", GetType()); + XmlObjectFactory xbf = new XmlObjectFactory(resource); + PropertyOverrideConfigurer poc = (PropertyOverrideConfigurer) xbf.GetObject("OverrideConfigurer"); + Assert.IsNotNull(poc); + poc.PostProcessObjectFactory(xbf); + TestObject to = (TestObject) xbf.GetObject("Test2"); + Assert.AreEqual("Overriden Name", to.Name); + } } diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/PropertyPathFactoryObjectTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/PropertyPathFactoryObjectTests.cs index 623fd775..52fce295 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/PropertyPathFactoryObjectTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/PropertyPathFactoryObjectTests.cs @@ -20,129 +20,127 @@ using FakeItEasy; using NUnit.Framework; - using Spring.Core; -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Unit tests for the PropertyPathFactoryObject class. +/// +/// Rick Evans +[TestFixture] +public sealed class PropertyPathFactoryObjectTests { - /// - /// Unit tests for the PropertyPathFactoryObject class. - /// - /// Rick Evans - [TestFixture] - public sealed class PropertyPathFactoryObjectTests - { - private IObjectFactory mockFactory; + private IObjectFactory mockFactory; - [SetUp] - public void SetUp() - { - mockFactory = A.Fake(); - } + [SetUp] + public void SetUp() + { + mockFactory = A.Fake(); + } - [Test] - public void GetObject_ViaTargetObjectName() - { - A.CallTo(() => mockFactory.IsSingleton("foo")).Returns(true); - A.CallTo(() => mockFactory.GetObject("foo")).Returns(new TestObject("Fiona Apple", 28)); + [Test] + public void GetObject_ViaTargetObjectName() + { + A.CallTo(() => mockFactory.IsSingleton("foo")).Returns(true); + A.CallTo(() => mockFactory.GetObject("foo")).Returns(new TestObject("Fiona Apple", 28)); - PropertyPathFactoryObject fac = new PropertyPathFactoryObject(); - fac.TargetObjectName = "foo"; - fac.PropertyPath = "name"; - fac.ObjectFactory = mockFactory; - string name = (string) fac.GetObject(); - Assert.AreEqual("Fiona Apple", name); - } + PropertyPathFactoryObject fac = new PropertyPathFactoryObject(); + fac.TargetObjectName = "foo"; + fac.PropertyPath = "name"; + fac.ObjectFactory = mockFactory; + string name = (string) fac.GetObject(); + Assert.AreEqual("Fiona Apple", name); + } - [Test] - public void GetObject_ViaTargetObjectNameWithNestedPropertyPath() - { - A.CallTo(() => mockFactory.IsSingleton("foo")).Returns(true); - TestObject target = new TestObject("Fiona Apple", 28); - target.Spouse = target; - A.CallTo(() => mockFactory.GetObject("foo")).Returns(target); + [Test] + public void GetObject_ViaTargetObjectNameWithNestedPropertyPath() + { + A.CallTo(() => mockFactory.IsSingleton("foo")).Returns(true); + TestObject target = new TestObject("Fiona Apple", 28); + target.Spouse = target; + A.CallTo(() => mockFactory.GetObject("foo")).Returns(target); - PropertyPathFactoryObject fac = new PropertyPathFactoryObject(); - fac.TargetObjectName = "foo"; - fac.PropertyPath = "spouse.name"; - fac.ObjectFactory = mockFactory; - string name = (string) fac.GetObject(); - Assert.AreEqual("Fiona Apple", name); - } + PropertyPathFactoryObject fac = new PropertyPathFactoryObject(); + fac.TargetObjectName = "foo"; + fac.PropertyPath = "spouse.name"; + fac.ObjectFactory = mockFactory; + string name = (string) fac.GetObject(); + Assert.AreEqual("Fiona Apple", name); + } - [Test] - public void GetObject_ViaObjectName() - { - A.CallTo(() => mockFactory.GetObject("foo")).Returns(new TestObject("Fiona Apple", 28)); - A.CallTo(() => mockFactory.IsSingleton("foo")).Returns(true); + [Test] + public void GetObject_ViaObjectName() + { + A.CallTo(() => mockFactory.GetObject("foo")).Returns(new TestObject("Fiona Apple", 28)); + A.CallTo(() => mockFactory.IsSingleton("foo")).Returns(true); - PropertyPathFactoryObject fac = new PropertyPathFactoryObject(); - fac.ObjectName = "foo.name"; - fac.ObjectFactory = mockFactory; - string name = (string) fac.GetObject(); - Assert.AreEqual("Fiona Apple", name); - } + PropertyPathFactoryObject fac = new PropertyPathFactoryObject(); + fac.ObjectName = "foo.name"; + fac.ObjectFactory = mockFactory; + string name = (string) fac.GetObject(); + Assert.AreEqual("Fiona Apple", name); + } - [Test] - public void GetObject_ViaObjectNameThatStartsWithAPeriod() - { - A.CallTo(() => mockFactory.IsSingleton("foo")).Returns(true); - A.CallTo(() => mockFactory.GetObject("foo")).Returns(new TestObject("Fiona Apple", 28)); + [Test] + public void GetObject_ViaObjectNameThatStartsWithAPeriod() + { + A.CallTo(() => mockFactory.IsSingleton("foo")).Returns(true); + A.CallTo(() => mockFactory.GetObject("foo")).Returns(new TestObject("Fiona Apple", 28)); - PropertyPathFactoryObject fac = new PropertyPathFactoryObject(); - fac.ObjectName = ".foo.name"; - Assert.Throws(() => fac.ObjectFactory = mockFactory); - } + PropertyPathFactoryObject fac = new PropertyPathFactoryObject(); + fac.ObjectName = ".foo.name"; + Assert.Throws(() => fac.ObjectFactory = mockFactory); + } - [Test] - public void GetObject_MakeSureLeadingAndTrailingWhitspaceIsTrimmed() - { - A.CallTo(() => mockFactory.IsSingleton("foo")).Returns(true); - A.CallTo(() => mockFactory.GetObject("foo")).Returns(new TestObject("Fiona Apple", 28)); + [Test] + public void GetObject_MakeSureLeadingAndTrailingWhitspaceIsTrimmed() + { + A.CallTo(() => mockFactory.IsSingleton("foo")).Returns(true); + A.CallTo(() => mockFactory.GetObject("foo")).Returns(new TestObject("Fiona Apple", 28)); - PropertyPathFactoryObject fac = new PropertyPathFactoryObject(); - fac.ObjectName = " \nfoo.name "; - fac.ObjectFactory = mockFactory; - string name = (string) fac.GetObject(); - Assert.AreEqual("Fiona Apple", name); - } + PropertyPathFactoryObject fac = new PropertyPathFactoryObject(); + fac.ObjectName = " \nfoo.name "; + fac.ObjectFactory = mockFactory; + string name = (string) fac.GetObject(); + Assert.AreEqual("Fiona Apple", name); + } - [Test] - public void GetObject_ViaObjectNameWithNestedPropertyPath() - { - A.CallTo(() => mockFactory.IsSingleton("foo")).Returns(true); - TestObject target = new TestObject("Fiona Apple", 28); - target.Spouse = target; - A.CallTo(() => mockFactory.GetObject("foo")).Returns(target); + [Test] + public void GetObject_ViaObjectNameWithNestedPropertyPath() + { + A.CallTo(() => mockFactory.IsSingleton("foo")).Returns(true); + TestObject target = new TestObject("Fiona Apple", 28); + target.Spouse = target; + A.CallTo(() => mockFactory.GetObject("foo")).Returns(target); - PropertyPathFactoryObject fac = new PropertyPathFactoryObject(); - fac.ObjectName = "foo.spouse.name"; - fac.ObjectFactory = mockFactory; - string name = (string) fac.GetObject(); - Assert.AreEqual("Fiona Apple", name); - } + PropertyPathFactoryObject fac = new PropertyPathFactoryObject(); + fac.ObjectName = "foo.spouse.name"; + fac.ObjectFactory = mockFactory; + string name = (string) fac.GetObject(); + Assert.AreEqual("Fiona Apple", name); + } - [Test] - public void GetObject_ViaObjectNameWithNullInNestedPropertyPath() - { - A.CallTo(() => mockFactory.IsSingleton("foo")).Returns(true); - A.CallTo(() => mockFactory.GetObject("foo")).Returns(new TestObject("Fiona Apple", 28)); + [Test] + public void GetObject_ViaObjectNameWithNullInNestedPropertyPath() + { + A.CallTo(() => mockFactory.IsSingleton("foo")).Returns(true); + A.CallTo(() => mockFactory.GetObject("foo")).Returns(new TestObject("Fiona Apple", 28)); - PropertyPathFactoryObject fac = new PropertyPathFactoryObject(); - fac.ObjectName = "foo.spouse.name"; - Assert.Throws(() => fac.ObjectFactory = mockFactory); - } + PropertyPathFactoryObject fac = new PropertyPathFactoryObject(); + fac.ObjectName = "foo.spouse.name"; + Assert.Throws(() => fac.ObjectFactory = mockFactory); + } - [Test] - public void GetObject_PropertyPathEvaluatesToNull() - { - A.CallTo(() => mockFactory.IsSingleton("foo")).Returns(true); - A.CallTo(() => mockFactory.GetObject("foo")).Returns(new TestObject(null, 28)); + [Test] + public void GetObject_PropertyPathEvaluatesToNull() + { + A.CallTo(() => mockFactory.IsSingleton("foo")).Returns(true); + A.CallTo(() => mockFactory.GetObject("foo")).Returns(new TestObject(null, 28)); - PropertyPathFactoryObject fac = new PropertyPathFactoryObject(); - fac.ObjectName = "foo.name"; - fac.ObjectFactory = mockFactory; - Assert.Throws(() => fac.GetObject()); - } - } + PropertyPathFactoryObject fac = new PropertyPathFactoryObject(); + fac.ObjectName = "foo.name"; + fac.ObjectFactory = mockFactory; + Assert.Throws(() => fac.GetObject()); + } } diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/PropertyPlaceholderConfigurerTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/PropertyPlaceholderConfigurerTests.cs index 079b6d7d..0d15df63 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/PropertyPlaceholderConfigurerTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/PropertyPlaceholderConfigurerTests.cs @@ -21,7 +21,6 @@ using System.Collections; using System.Collections.Specialized; using FakeItEasy; - using NUnit.Framework; using Spring.Collections; using Spring.Context; @@ -31,451 +30,446 @@ using Spring.Objects.Factory.Support; using Spring.Objects.Factory.Xml; using Spring.Util; -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Unit tests for the PropertyPlaceholderConfigurer class. +/// +/// Rick Evans +[TestFixture] +public sealed class PropertyPlaceholderConfigurerTests { - /// - /// Unit tests for the PropertyPlaceholderConfigurer class. - /// - /// Rick Evans - [TestFixture] - public sealed class PropertyPlaceholderConfigurerTests - { #if !NETCOREAPP private static string testConnectionString = @"Provider=Microsoft.Jet.OLEDB.4.0; Data Source=c:\Northwind.mdb;User ID=Admin;Password=;"; private static string testConnectionStringTwo = @"Provider=Microsoft.Jet.OLEDB.4.0; Data Source=c:\Northwind.mdb;User ID=Admin;Password=Ernie;"; #endif - [SetUp] - public void SetUp() + [SetUp] + public void SetUp() + { + } + + [Test] + public void MismatchBetweenNumberOfConfigNamesAndNumberOfLocations() + { + PropertyPlaceholderConfigurer cfg = new PropertyPlaceholderConfigurer(); + cfg.Locations = new IResource[] { A.Fake() }; // will never get to the point where we check the validity + cfg.ConfigSections = new string[] { "", "" }; + Assert.Throws(() => cfg.PostProcessObjectFactory(A.Fake())); + } + + [Test] + public void OneConfigNameIsOKForLotsOfLocations() + { + PropertyPlaceholderConfigurer cfg = new PropertyPlaceholderConfigurer(); + IResource mock = A.Fake(); + A.CallTo(() => mock.Exists).Returns(true); + A.CallTo(() => mock.InputStream).Throws(new FileNotFoundException()); + + cfg.Locations = new IResource[] { mock }; + cfg.ConfigSections = new string[] { "" }; + Assert.Throws(() => cfg.PostProcessObjectFactory(A.Fake())); + } + + [Test] + public void ChokesOnBadResourceLocationIfIgnoreBadResourcesFlagNotSetToTrue() + { + PropertyPlaceholderConfigurer cfg = new PropertyPlaceholderConfigurer(); + cfg.IgnoreResourceNotFound = false; + IResource mock = A.Fake(); + A.CallTo(() => mock.Exists).Returns(false); + + cfg.Locations = new IResource[] { mock }; + cfg.ConfigSections = new string[] { "" }; + Assert.Throws(() => cfg.PostProcessObjectFactory(A.Fake())); + } + + [Test] + public void DoesNotChokeOnBadResourceLocationIfIgnoreBadResourcesFlagSetToTrue() + { + PropertyPlaceholderConfigurer cfg = new PropertyPlaceholderConfigurer(); + cfg.IgnoreResourceNotFound = true; + IResource mockResource = A.Fake(); + A.CallTo(() => mockResource.Exists).Returns(false); + cfg.Location = mockResource; + cfg.ConfigSections = new string[] { "" }; + IConfigurableListableObjectFactory mockFactory = A.Fake(); + A.CallTo(() => mockFactory.GetObjectDefinitionNames(false)).Returns(new string[] { }); + + cfg.PostProcessObjectFactory(mockFactory); + } + + [Test] + public void WithCircularReference() + { + StaticApplicationContext ac = new StaticApplicationContext(); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.Add("age", "${age}"); + pvs.Add("name", "name${var}"); + pvs.Add("spouse", new RuntimeObjectReference("${ref}")); + ac.RegisterSingleton("tb1", typeof(TestObject), pvs); + pvs = new MutablePropertyValues(); + pvs.Add("age", "${age}"); + pvs.Add("name", "name${age}"); + ac.RegisterSingleton("tb2", typeof(TestObject), pvs); + pvs = new MutablePropertyValues(); + pvs.Add("Properties", ""); + ac.RegisterSingleton("configurer1", typeof(PropertyPlaceholderConfigurer), pvs); + pvs = new MutablePropertyValues(); + pvs.Add("Properties", ""); + pvs.Add("order", "0"); + ac.RegisterSingleton("configurer2", typeof(PropertyPlaceholderConfigurer), pvs); + Assert.Throws(() => ac.Refresh()); + } + + [Test] + public void WithDefaultProperties() + { + const string defName = "foo"; + const string placeholder = "${name}"; + MutablePropertyValues pvs = new MutablePropertyValues(); + + const string theProperty = "name"; + pvs.Add(theProperty, placeholder); + RootObjectDefinition def = new RootObjectDefinition(typeof(TestObject), pvs); + + IConfigurableListableObjectFactory mock = A.Fake(); + A.CallTo(() => mock.GetObjectDefinitionNames(false)).Returns(new string[] { defName }); + A.CallTo(() => mock.GetObjectDefinition(defName, false)).Returns(def); + + PropertyPlaceholderConfigurer cfg = new PropertyPlaceholderConfigurer(); + NameValueCollection defaultProperties = new NameValueCollection(); + const string expectedName = "Rick Evans"; + defaultProperties.Add(theProperty, expectedName); + cfg.Properties = defaultProperties; + cfg.PostProcessObjectFactory(mock); + Assert.AreEqual(expectedName, def.PropertyValues.GetPropertyValue(theProperty).Value, + "Property placeholder value was not replaced with the resolved value."); + + A.CallTo(() => mock.AddEmbeddedValueResolver(A._)).MustHaveHappened(); + } + + [Test] + public void IncludingAncestors() + { + const string defName = "foo"; + const string placeholder = "${name}"; + MutablePropertyValues pvs = new MutablePropertyValues(); + + const string theProperty = "name"; + pvs.Add(theProperty, placeholder); + RootObjectDefinition def = new RootObjectDefinition(typeof(TestObject), pvs); + + IConfigurableListableObjectFactory mock = A.Fake(); + A.CallTo(() => mock.GetObjectDefinitionNames(true)).Returns(new string[] { defName }); + A.CallTo(() => mock.GetObjectDefinition(defName, true)).Returns(def); + + PropertyPlaceholderConfigurer cfg = new PropertyPlaceholderConfigurer(); + cfg.IncludeAncestors = true; + + NameValueCollection defaultProperties = new NameValueCollection(); + const string expectedName = "Rick Evans"; + defaultProperties.Add(theProperty, expectedName); + cfg.Properties = defaultProperties; + cfg.PostProcessObjectFactory(mock); + Assert.AreEqual(expectedName, def.PropertyValues.GetPropertyValue(theProperty).Value, + "Property placeholder value was not replaced with the resolved value."); + + A.CallTo(() => mock.AddEmbeddedValueResolver(A._)).MustHaveHappened(); + } + + /// + /// Fallback is the default mode. Check if the PROCESSOR_ARCHITECTURE + /// variable is replaced. + /// + [Test] + [Platform("Win")] + public void WithEnvironmentVariableFallback() + { + StaticApplicationContext ac = new StaticApplicationContext(); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.Add("touchy", "${PROCESSOR_ARCHITECTURE}"); + ac.RegisterSingleton("to", typeof(TestObject), pvs); + + pvs = new MutablePropertyValues(); + ac.RegisterSingleton("configurer", typeof(PropertyPlaceholderConfigurer), pvs); + ac.Refresh(); + + TestObject to = (TestObject) ac["to"]; + Assert.AreEqual(Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE"), + to.Touchy); + } + + /// + /// Fallback is the default mode. Explicity provide a value using the + /// property (NameValueCollection Properties) of PropertyPlaceholder. + /// Fallback mode will not change the value since it has been explicity set. + /// + [Test] + public void WithEnvironmentPropertyNotUsed() + { + StaticApplicationContext ac = new StaticApplicationContext(); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.Add("touchy", "${PROCESSOR_ARCHITECTURE}"); + ac.RegisterSingleton("to", typeof(TestObject), pvs); + + pvs = new MutablePropertyValues(); + NameValueCollection nvc = new NameValueCollection(); + nvc.Add("PROCESSOR_ARCHITECTURE", "G5"); + pvs.Add("properties", nvc); + ac.RegisterSingleton("configurer", typeof(PropertyPlaceholderConfigurer), pvs); + ac.Refresh(); + + TestObject to = (TestObject) ac["to"]; + Assert.AreEqual("G5", to.Touchy, "Fallback mode is not respecting previously set values."); + } + + /// + /// Set the environment variable mode to override. Now expect the environment + /// variable setting to override the explicitly defined name value collection. + /// + [Test] + [Platform("Win")] + public void WithOverridingEnvironmentProperty() + { + StaticApplicationContext ac = new StaticApplicationContext(); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.Add("touchy", "${PROCESSOR_ARCHITECTURE}"); + ac.RegisterSingleton("to", typeof(TestObject), pvs); + + pvs = new MutablePropertyValues(); + NameValueCollection nvc = new NameValueCollection(); + nvc.Add("PROCESSOR_ARCHITECTURE", "G5"); + pvs.Add("properties", nvc); + pvs.Add("environmentVariableMode", EnvironmentVariableMode.Override); + ac.RegisterSingleton("configurer", typeof(PropertyPlaceholderConfigurer), pvs); + ac.Refresh(); + + TestObject to = (TestObject) ac["to"]; + Assert.AreEqual(Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE"), + to.Touchy); + } + + [Test] + public void WithUnresolvableEnvironmentProperty() + { + StaticApplicationContext ac = new StaticApplicationContext(); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.Add("touchy", "${PROCESSOR_ARCHITECTURE}"); + ac.RegisterSingleton("to", typeof(TestObject), pvs); + + pvs = new MutablePropertyValues(); + pvs.Add("environmentVariableMode", EnvironmentVariableMode.Never); + ac.RegisterSingleton("configurer", typeof(PropertyPlaceholderConfigurer), pvs); + Assert.Throws(() => ac.Refresh(), "Error registering object with name 'to' defined in '' : Could not resolve placeholder 'PROCESSOR_ARCHITECTURE'."); + } + + [Test] + public void WithUnresolvablePlaceholder() + { + StaticApplicationContext ac = new StaticApplicationContext(); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.Add("name", "${ref}"); + ac.RegisterSingleton("tb", typeof(TestObject), pvs); + ac.RegisterSingleton("configurer", typeof(PropertyPlaceholderConfigurer), null); + try { - } - - [Test] - public void MismatchBetweenNumberOfConfigNamesAndNumberOfLocations() - { - PropertyPlaceholderConfigurer cfg = new PropertyPlaceholderConfigurer(); - cfg.Locations = new IResource[] { A.Fake() }; // will never get to the point where we check the validity - cfg.ConfigSections = new string[] { "", "" }; - Assert.Throws(() => cfg.PostProcessObjectFactory(A.Fake())); - } - - [Test] - public void OneConfigNameIsOKForLotsOfLocations() - { - PropertyPlaceholderConfigurer cfg = new PropertyPlaceholderConfigurer(); - IResource mock = A.Fake(); - A.CallTo(() => mock.Exists).Returns(true); - A.CallTo(() => mock.InputStream).Throws(new FileNotFoundException()); - - cfg.Locations = new IResource [] {mock}; - cfg.ConfigSections = new string[] { "" }; - Assert.Throws(() => cfg.PostProcessObjectFactory(A.Fake())); - } - - [Test] - public void ChokesOnBadResourceLocationIfIgnoreBadResourcesFlagNotSetToTrue() - { - PropertyPlaceholderConfigurer cfg = new PropertyPlaceholderConfigurer(); - cfg.IgnoreResourceNotFound = false; - IResource mock = A.Fake(); - A.CallTo(() => mock.Exists).Returns(false); - - cfg.Locations = new IResource [] { mock}; - cfg.ConfigSections = new string[] { "" }; - Assert.Throws(() => cfg.PostProcessObjectFactory(A.Fake())); - } - - [Test] - public void DoesNotChokeOnBadResourceLocationIfIgnoreBadResourcesFlagSetToTrue() - { - PropertyPlaceholderConfigurer cfg = new PropertyPlaceholderConfigurer(); - cfg.IgnoreResourceNotFound = true; - IResource mockResource = A.Fake(); - A.CallTo(() => mockResource.Exists).Returns(false); - cfg.Location = mockResource; - cfg.ConfigSections = new string[] { "" }; - IConfigurableListableObjectFactory mockFactory = A.Fake(); - A.CallTo(() => mockFactory.GetObjectDefinitionNames(false)).Returns(new string[] {}); - - cfg.PostProcessObjectFactory(mockFactory); - } - - [Test] - public void WithCircularReference() - { - StaticApplicationContext ac = new StaticApplicationContext(); - MutablePropertyValues pvs = new MutablePropertyValues(); - pvs.Add("age", "${age}"); - pvs.Add("name", "name${var}"); - pvs.Add("spouse", new RuntimeObjectReference("${ref}")); - ac.RegisterSingleton("tb1", typeof (TestObject), pvs); - pvs = new MutablePropertyValues(); - pvs.Add("age", "${age}"); - pvs.Add("name", "name${age}"); - ac.RegisterSingleton("tb2", typeof (TestObject), pvs); - pvs = new MutablePropertyValues(); - pvs.Add("Properties", ""); - ac.RegisterSingleton("configurer1", typeof (PropertyPlaceholderConfigurer), pvs); - pvs = new MutablePropertyValues(); - pvs.Add("Properties", ""); - pvs.Add("order", "0"); - ac.RegisterSingleton("configurer2", typeof (PropertyPlaceholderConfigurer), pvs); - Assert.Throws(() => ac.Refresh()); - } - - [Test] - public void WithDefaultProperties() - { - const string defName = "foo"; - const string placeholder = "${name}"; - MutablePropertyValues pvs = new MutablePropertyValues(); - - const string theProperty = "name"; - pvs.Add(theProperty, placeholder); - RootObjectDefinition def = new RootObjectDefinition(typeof(TestObject), pvs); - - IConfigurableListableObjectFactory mock = A.Fake(); - A.CallTo(() => mock.GetObjectDefinitionNames(false)).Returns(new string [] {defName}); - A.CallTo(() => mock.GetObjectDefinition(defName, false)).Returns(def); - - PropertyPlaceholderConfigurer cfg = new PropertyPlaceholderConfigurer(); - NameValueCollection defaultProperties = new NameValueCollection(); - const string expectedName = "Rick Evans"; - defaultProperties.Add(theProperty, expectedName); - cfg.Properties = defaultProperties; - cfg.PostProcessObjectFactory(mock); - Assert.AreEqual(expectedName, def.PropertyValues.GetPropertyValue(theProperty).Value, - "Property placeholder value was not replaced with the resolved value."); - - A.CallTo(() => mock.AddEmbeddedValueResolver(A._)).MustHaveHappened(); - } - - [Test] - public void IncludingAncestors() - { - const string defName = "foo"; - const string placeholder = "${name}"; - MutablePropertyValues pvs = new MutablePropertyValues(); - - - const string theProperty = "name"; - pvs.Add(theProperty, placeholder); - RootObjectDefinition def = new RootObjectDefinition(typeof(TestObject), pvs); - - IConfigurableListableObjectFactory mock = A.Fake(); - A.CallTo(() => mock.GetObjectDefinitionNames(true)).Returns(new string[] { defName }); - A.CallTo(() => mock.GetObjectDefinition(defName, true)).Returns(def); - - PropertyPlaceholderConfigurer cfg = new PropertyPlaceholderConfigurer(); - cfg.IncludeAncestors = true; - - NameValueCollection defaultProperties = new NameValueCollection(); - const string expectedName = "Rick Evans"; - defaultProperties.Add(theProperty, expectedName); - cfg.Properties = defaultProperties; - cfg.PostProcessObjectFactory(mock); - Assert.AreEqual(expectedName, def.PropertyValues.GetPropertyValue(theProperty).Value, - "Property placeholder value was not replaced with the resolved value."); - - A.CallTo(() => mock.AddEmbeddedValueResolver(A._)).MustHaveHappened(); - } - - /// - /// Fallback is the default mode. Check if the PROCESSOR_ARCHITECTURE - /// variable is replaced. - /// - [Test] - [Platform("Win")] - public void WithEnvironmentVariableFallback() - { - StaticApplicationContext ac = new StaticApplicationContext(); - MutablePropertyValues pvs = new MutablePropertyValues(); - pvs.Add("touchy", "${PROCESSOR_ARCHITECTURE}"); - ac.RegisterSingleton("to", typeof (TestObject), pvs); - - pvs = new MutablePropertyValues(); - ac.RegisterSingleton("configurer", typeof (PropertyPlaceholderConfigurer), pvs); - ac.Refresh(); - - TestObject to = (TestObject) ac["to"]; - Assert.AreEqual(Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE"), - to.Touchy); - } - - /// - /// Fallback is the default mode. Explicity provide a value using the - /// property (NameValueCollection Properties) of PropertyPlaceholder. - /// Fallback mode will not change the value since it has been explicity set. - /// - [Test] - public void WithEnvironmentPropertyNotUsed() - { - StaticApplicationContext ac = new StaticApplicationContext(); - MutablePropertyValues pvs = new MutablePropertyValues(); - pvs.Add("touchy", "${PROCESSOR_ARCHITECTURE}"); - ac.RegisterSingleton("to", typeof (TestObject), pvs); - - pvs = new MutablePropertyValues(); - NameValueCollection nvc = new NameValueCollection(); - nvc.Add("PROCESSOR_ARCHITECTURE", "G5"); - pvs.Add("properties", nvc); - ac.RegisterSingleton("configurer", typeof (PropertyPlaceholderConfigurer), pvs); - ac.Refresh(); - - TestObject to = (TestObject) ac["to"]; - Assert.AreEqual("G5", to.Touchy, "Fallback mode is not respecting previously set values."); - } - - /// - /// Set the environment variable mode to override. Now expect the environment - /// variable setting to override the explicitly defined name value collection. - /// - [Test] - [Platform("Win")] - public void WithOverridingEnvironmentProperty() - { - StaticApplicationContext ac = new StaticApplicationContext(); - MutablePropertyValues pvs = new MutablePropertyValues(); - pvs.Add("touchy", "${PROCESSOR_ARCHITECTURE}"); - ac.RegisterSingleton("to", typeof (TestObject), pvs); - - pvs = new MutablePropertyValues(); - NameValueCollection nvc = new NameValueCollection(); - nvc.Add("PROCESSOR_ARCHITECTURE", "G5"); - pvs.Add("properties", nvc); - pvs.Add("environmentVariableMode", EnvironmentVariableMode.Override); - ac.RegisterSingleton("configurer", typeof (PropertyPlaceholderConfigurer), pvs); - ac.Refresh(); - - TestObject to = (TestObject) ac["to"]; - Assert.AreEqual(Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE"), - to.Touchy); - } - - [Test] - public void WithUnresolvableEnvironmentProperty() - { - StaticApplicationContext ac = new StaticApplicationContext(); - MutablePropertyValues pvs = new MutablePropertyValues(); - pvs.Add("touchy", "${PROCESSOR_ARCHITECTURE}"); - ac.RegisterSingleton("to", typeof (TestObject), pvs); - - pvs = new MutablePropertyValues(); - pvs.Add("environmentVariableMode", EnvironmentVariableMode.Never); - ac.RegisterSingleton("configurer", typeof (PropertyPlaceholderConfigurer), pvs); - Assert.Throws(() => ac.Refresh(), "Error registering object with name 'to' defined in '' : Could not resolve placeholder 'PROCESSOR_ARCHITECTURE'."); - } - - [Test] - public void WithUnresolvablePlaceholder() - { - StaticApplicationContext ac = new StaticApplicationContext(); - MutablePropertyValues pvs = new MutablePropertyValues(); - pvs.Add("name", "${ref}"); - ac.RegisterSingleton("tb", typeof (TestObject), pvs); - ac.RegisterSingleton("configurer", typeof (PropertyPlaceholderConfigurer), null); - try - { - ac.Refresh(); - Assert.Fail("Should have thrown ObjectDefinitionStoreException"); - } - catch (ObjectDefinitionStoreException ex) - { - // expected - Assert.IsTrue(ex.Message.IndexOf("ref") != -1); - } - } - - [Test] - public void WithExpressionProperty() - { - StaticApplicationContext ac = new StaticApplicationContext(); - MutablePropertyValues pvs = new MutablePropertyValues(); - pvs.Add("age", new ExpressionHolder("${age}")); - ac.RegisterSingleton("to1", typeof(TestObject), pvs); - - pvs = new MutablePropertyValues(); - NameValueCollection nvc = new NameValueCollection(); - nvc.Add("age", "'0x7FFFFFFF'"); - pvs.Add("properties", nvc); - ac.RegisterSingleton("configurer", typeof(PropertyPlaceholderConfigurer), pvs); ac.Refresh(); - - - TestObject to1 = (TestObject)ac.GetObject("to1");; - Assert.AreEqual(2147483647, to1.Age); - + Assert.Fail("Should have thrown ObjectDefinitionStoreException"); } + catch (ObjectDefinitionStoreException ex) + { + // expected + Assert.IsTrue(ex.Message.IndexOf("ref") != -1); + } + } - [Test] - public void SunnyDay() - { - StaticApplicationContext ac = new StaticApplicationContext(); + [Test] + public void WithExpressionProperty() + { + StaticApplicationContext ac = new StaticApplicationContext(); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.Add("age", new ExpressionHolder("${age}")); + ac.RegisterSingleton("to1", typeof(TestObject), pvs); + pvs = new MutablePropertyValues(); + NameValueCollection nvc = new NameValueCollection(); + nvc.Add("age", "'0x7FFFFFFF'"); + pvs.Add("properties", nvc); + ac.RegisterSingleton("configurer", typeof(PropertyPlaceholderConfigurer), pvs); + ac.Refresh(); - MutablePropertyValues pvs = new MutablePropertyValues(); - pvs.Add("age", "${age}"); - RootObjectDefinition def - = new RootObjectDefinition("${fqn}", new ConstructorArgumentValues(), pvs); - ac.RegisterObjectDefinition("tb3", def); + TestObject to1 = (TestObject) ac.GetObject("to1"); + ; + Assert.AreEqual(2147483647, to1.Age); + } + [Test] + public void SunnyDay() + { + StaticApplicationContext ac = new StaticApplicationContext(); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.Add("age", "${age}"); + RootObjectDefinition def + = new RootObjectDefinition("${fqn}", new ConstructorArgumentValues(), pvs); + ac.RegisterObjectDefinition("tb3", def); - pvs = new MutablePropertyValues(); - pvs.Add("age", "${age}"); - pvs.Add("name", "name${var}${"); - pvs.Add("spouse", new RuntimeObjectReference("${ref}")); - ac.RegisterSingleton("tb1", typeof (TestObject), pvs); + pvs = new MutablePropertyValues(); + pvs.Add("age", "${age}"); + pvs.Add("name", "name${var}${"); + pvs.Add("spouse", new RuntimeObjectReference("${ref}")); + ac.RegisterSingleton("tb1", typeof(TestObject), pvs); - ConstructorArgumentValues cas = new ConstructorArgumentValues(); - cas.AddIndexedArgumentValue(1, "${age}"); - cas.AddGenericArgumentValue("${var}name${age}"); + ConstructorArgumentValues cas = new ConstructorArgumentValues(); + cas.AddIndexedArgumentValue(1, "${age}"); + cas.AddGenericArgumentValue("${var}name${age}"); - pvs = new MutablePropertyValues(); - ArrayList friends = new ManagedList(); - friends.Add("na${age}me"); - friends.Add(new RuntimeObjectReference("${ref}")); - pvs.Add("friends", friends); + pvs = new MutablePropertyValues(); + ArrayList friends = new ManagedList(); + friends.Add("na${age}me"); + friends.Add(new RuntimeObjectReference("${ref}")); + pvs.Add("friends", friends); - ISet someSet = new ManagedSet(); - someSet.Add("na${age}me"); - someSet.Add(new RuntimeObjectReference("${ref}")); - pvs.Add("someSet", someSet); + ISet someSet = new ManagedSet(); + someSet.Add("na${age}me"); + someSet.Add(new RuntimeObjectReference("${ref}")); + pvs.Add("someSet", someSet); - IDictionary someDictionary = new ManagedDictionary(); - someDictionary["key1"] = new RuntimeObjectReference("${ref}"); - someDictionary["key2"] = "${age}name"; - MutablePropertyValues innerPvs = new MutablePropertyValues(); - someDictionary["key3"] = new RootObjectDefinition(typeof (TestObject), innerPvs); - someDictionary["key4"] = new ChildObjectDefinition("tb1", innerPvs); - pvs.Add("someMap", someDictionary); + IDictionary someDictionary = new ManagedDictionary(); + someDictionary["key1"] = new RuntimeObjectReference("${ref}"); + someDictionary["key2"] = "${age}name"; + MutablePropertyValues innerPvs = new MutablePropertyValues(); + someDictionary["key3"] = new RootObjectDefinition(typeof(TestObject), innerPvs); + someDictionary["key4"] = new ChildObjectDefinition("tb1", innerPvs); + pvs.Add("someMap", someDictionary); - RootObjectDefinition definition = new RootObjectDefinition(typeof (TestObject), cas, pvs); - ac.DefaultListableObjectFactory.RegisterObjectDefinition("tb2", definition); + RootObjectDefinition definition = new RootObjectDefinition(typeof(TestObject), cas, pvs); + ac.DefaultListableObjectFactory.RegisterObjectDefinition("tb2", definition); - pvs = new MutablePropertyValues(); - pvs.Add("Properties", ""); - ac.RegisterSingleton("configurer", typeof (PropertyPlaceholderConfigurer), pvs); - ac.Refresh(); + pvs = new MutablePropertyValues(); + pvs.Add("Properties", ""); + ac.RegisterSingleton("configurer", typeof(PropertyPlaceholderConfigurer), pvs); + ac.Refresh(); - TestObject tb1 = (TestObject) ac.GetObject("tb1"); - TestObject tb2 = (TestObject) ac.GetObject("tb2"); - TestObject tb3 = (TestObject) ac.GetObject("tb3"); - Assert.AreEqual(98, tb1.Age); - Assert.AreEqual(98, tb2.Age); - Assert.AreEqual(98, tb3.Age); - Assert.AreEqual("namemyvar${", tb1.Name); - Assert.AreEqual("myvarname98", tb2.Name); - Assert.AreEqual(tb2, tb1.Spouse); - Assert.AreEqual(2, tb2.Friends.Count); - IEnumerator ie = tb2.Friends.GetEnumerator(); - ie.MoveNext(); - Assert.AreEqual("na98me", ie.Current); - ie.MoveNext(); - Assert.AreEqual(tb2, ie.Current); - Assert.AreEqual(2, tb2.SomeSet.Count); - Assert.IsTrue(tb2.SomeSet.Contains("na98me")); - Assert.IsTrue(tb2.SomeSet.Contains(tb2)); - Assert.AreEqual(4, tb2.SomeMap.Count); - Assert.AreEqual(tb2, tb2.SomeMap["key1"]); - Assert.AreEqual("98name", tb2.SomeMap["key2"]); - TestObject inner1 = (TestObject) tb2.SomeMap["key3"]; - TestObject inner2 = (TestObject) tb2.SomeMap["key4"]; - Assert.AreEqual(0, inner1.Age); - Assert.AreEqual(null, inner1.Name); - Assert.AreEqual(98, inner2.Age); - Assert.AreEqual("namemyvar${", inner2.Name); - } + TestObject tb1 = (TestObject) ac.GetObject("tb1"); + TestObject tb2 = (TestObject) ac.GetObject("tb2"); + TestObject tb3 = (TestObject) ac.GetObject("tb3"); + Assert.AreEqual(98, tb1.Age); + Assert.AreEqual(98, tb2.Age); + Assert.AreEqual(98, tb3.Age); + Assert.AreEqual("namemyvar${", tb1.Name); + Assert.AreEqual("myvarname98", tb2.Name); + Assert.AreEqual(tb2, tb1.Spouse); + Assert.AreEqual(2, tb2.Friends.Count); + IEnumerator ie = tb2.Friends.GetEnumerator(); + ie.MoveNext(); + Assert.AreEqual("na98me", ie.Current); + ie.MoveNext(); + Assert.AreEqual(tb2, ie.Current); + Assert.AreEqual(2, tb2.SomeSet.Count); + Assert.IsTrue(tb2.SomeSet.Contains("na98me")); + Assert.IsTrue(tb2.SomeSet.Contains(tb2)); + Assert.AreEqual(4, tb2.SomeMap.Count); + Assert.AreEqual(tb2, tb2.SomeMap["key1"]); + Assert.AreEqual("98name", tb2.SomeMap["key2"]); + TestObject inner1 = (TestObject) tb2.SomeMap["key3"]; + TestObject inner2 = (TestObject) tb2.SomeMap["key4"]; + Assert.AreEqual(0, inner1.Age); + Assert.AreEqual(null, inner1.Name); + Assert.AreEqual(98, inner2.Age); + Assert.AreEqual("namemyvar${", inner2.Name); + } - /// - /// Makes sure that an appropriate exception is raised when trying - /// to resolve this placeholder... ${foo} with this value... foo=ba${foo}r - /// - [Test] - public void ChokesOnCircularReferenceToPlaceHolder() - { - RootObjectDefinition def = new RootObjectDefinition(); - def.ObjectType = typeof (TestObject); - ConstructorArgumentValues args = new ConstructorArgumentValues(); - args.AddNamedArgumentValue("name", "${foo}"); - def.ConstructorArgumentValues = args; + /// + /// Makes sure that an appropriate exception is raised when trying + /// to resolve this placeholder... ${foo} with this value... foo=ba${foo}r + /// + [Test] + public void ChokesOnCircularReferenceToPlaceHolder() + { + RootObjectDefinition def = new RootObjectDefinition(); + def.ObjectType = typeof(TestObject); + ConstructorArgumentValues args = new ConstructorArgumentValues(); + args.AddNamedArgumentValue("name", "${foo}"); + def.ConstructorArgumentValues = args; - NameValueCollection properties = new NameValueCollection(); - const string expectedName = "ba${foo}r"; - properties.Add("foo", expectedName); + NameValueCollection properties = new NameValueCollection(); + const string expectedName = "ba${foo}r"; + properties.Add("foo", expectedName); - IConfigurableListableObjectFactory mock = A.Fake(); - A.CallTo(() => mock.GetObjectDefinitionNames(false)).Returns(new string[] {"foo"}); - A.CallTo(() => mock.GetObjectDefinition(null, false)).WithAnyArguments().Returns(def); + IConfigurableListableObjectFactory mock = A.Fake(); + A.CallTo(() => mock.GetObjectDefinitionNames(false)).Returns(new string[] { "foo" }); + A.CallTo(() => mock.GetObjectDefinition(null, false)).WithAnyArguments().Returns(def); - PropertyPlaceholderConfigurer cfg = new PropertyPlaceholderConfigurer(); - cfg.Properties = properties; - try - { - cfg.PostProcessObjectFactory(mock); - Assert.Fail("Should have raised an ObjectDefinitionStoreException by this point."); - } - catch (ObjectDefinitionStoreException) - { - } - } + PropertyPlaceholderConfigurer cfg = new PropertyPlaceholderConfigurer(); + cfg.Properties = properties; + try + { + cfg.PostProcessObjectFactory(mock); + Assert.Fail("Should have raised an ObjectDefinitionStoreException by this point."); + } + catch (ObjectDefinitionStoreException) + { + } + } - [Test] - public void ReplacesNamedCtorArgument() - { - RootObjectDefinition def = new RootObjectDefinition(); - def.ObjectType = typeof (TestObject); - ConstructorArgumentValues args = new ConstructorArgumentValues(); - args.AddNamedArgumentValue("name", "${hope.floats}"); - def.ConstructorArgumentValues = args; + [Test] + public void ReplacesNamedCtorArgument() + { + RootObjectDefinition def = new RootObjectDefinition(); + def.ObjectType = typeof(TestObject); + ConstructorArgumentValues args = new ConstructorArgumentValues(); + args.AddNamedArgumentValue("name", "${hope.floats}"); + def.ConstructorArgumentValues = args; - NameValueCollection properties = new NameValueCollection(); - const string expectedName = "Rick"; - properties.Add("hope.floats", expectedName); + NameValueCollection properties = new NameValueCollection(); + const string expectedName = "Rick"; + properties.Add("hope.floats", expectedName); - IConfigurableListableObjectFactory mock = A.Fake(); - A.CallTo(() => mock.GetObjectDefinitionNames(false)).Returns(new string[] {"foo"}); - A.CallTo(() => mock.GetObjectDefinition(null, false)).WithAnyArguments().Returns(def); + IConfigurableListableObjectFactory mock = A.Fake(); + A.CallTo(() => mock.GetObjectDefinitionNames(false)).Returns(new string[] { "foo" }); + A.CallTo(() => mock.GetObjectDefinition(null, false)).WithAnyArguments().Returns(def); - PropertyPlaceholderConfigurer cfg = new PropertyPlaceholderConfigurer(); - cfg.Properties = properties; - cfg.PostProcessObjectFactory(mock); + PropertyPlaceholderConfigurer cfg = new PropertyPlaceholderConfigurer(); + cfg.Properties = properties; + cfg.PostProcessObjectFactory(mock); - A.CallTo(() => mock.AddEmbeddedValueResolver(A._)).MustHaveHappened(); + A.CallTo(() => mock.AddEmbeddedValueResolver(A._)).MustHaveHappened(); - Assert.AreEqual(expectedName, - def.ConstructorArgumentValues.GetNamedArgumentValue("name").Value, - "Named argument placeholder value was not replaced."); - } + Assert.AreEqual(expectedName, + def.ConstructorArgumentValues.GetNamedArgumentValue("name").Value, + "Named argument placeholder value was not replaced."); + } - [Test] - public void UsingCustomMarkers() - { - RootObjectDefinition def = new RootObjectDefinition(); - def.ObjectType = typeof (TestObject); - ConstructorArgumentValues args = new ConstructorArgumentValues(); - args.AddNamedArgumentValue("name", "#hope.floats#"); - def.ConstructorArgumentValues = args; + [Test] + public void UsingCustomMarkers() + { + RootObjectDefinition def = new RootObjectDefinition(); + def.ObjectType = typeof(TestObject); + ConstructorArgumentValues args = new ConstructorArgumentValues(); + args.AddNamedArgumentValue("name", "#hope.floats#"); + def.ConstructorArgumentValues = args; - NameValueCollection properties = new NameValueCollection(); - const string expectedName = "Rick"; - properties.Add("hope.floats", expectedName); + NameValueCollection properties = new NameValueCollection(); + const string expectedName = "Rick"; + properties.Add("hope.floats", expectedName); - IConfigurableListableObjectFactory mock = A.Fake(); - A.CallTo(() => mock.GetObjectDefinitionNames(false)).Returns(new string[] {"foo"}); - A.CallTo(() => mock.GetObjectDefinition(null, false)).WithAnyArguments().Returns(def); + IConfigurableListableObjectFactory mock = A.Fake(); + A.CallTo(() => mock.GetObjectDefinitionNames(false)).Returns(new string[] { "foo" }); + A.CallTo(() => mock.GetObjectDefinition(null, false)).WithAnyArguments().Returns(def); - PropertyPlaceholderConfigurer cfg = new PropertyPlaceholderConfigurer(); - cfg.PlaceholderPrefix = cfg.PlaceholderSuffix = "#"; - cfg.Properties = properties; - cfg.PostProcessObjectFactory(mock); + PropertyPlaceholderConfigurer cfg = new PropertyPlaceholderConfigurer(); + cfg.PlaceholderPrefix = cfg.PlaceholderSuffix = "#"; + cfg.Properties = properties; + cfg.PostProcessObjectFactory(mock); - A.CallTo(() => mock.AddEmbeddedValueResolver(null)).WithAnyArguments().MustHaveHappened(); + A.CallTo(() => mock.AddEmbeddedValueResolver(null)).WithAnyArguments().MustHaveHappened(); - Assert.AreEqual(expectedName, - def.ConstructorArgumentValues.GetNamedArgumentValue("name").Value, - "Named argument placeholder value was not replaced."); - } + Assert.AreEqual(expectedName, + def.ConstructorArgumentValues.GetNamedArgumentValue("name").Value, + "Named argument placeholder value was not replaced."); + } #if !NETCOREAPP /// @@ -526,7 +520,7 @@ namespace Spring.Objects.Factory.Config /// Test that if two locations configure the same properties they are appended /// or not depending on the property /// - [Test(Description="SPRNET-55")] + [Test(Description = "SPRNET-55")] public void WithAppend() { string resourceName = "Spring/Objects/Factory/Config/PPC-SPRNET-55.xml"; @@ -548,85 +542,80 @@ namespace Spring.Objects.Factory.Config } #endif - [Test] - public void WithIgnoreUnresolvablePlaceholder() - { - const string defName = "foo"; - const string placeholder = "${name}"; - TestObject foo = new TestObject(placeholder, 30); - MutablePropertyValues pvs = new MutablePropertyValues(); + [Test] + public void WithIgnoreUnresolvablePlaceholder() + { + const string defName = "foo"; + const string placeholder = "${name}"; + TestObject foo = new TestObject(placeholder, 30); + MutablePropertyValues pvs = new MutablePropertyValues(); - pvs.Add("name", placeholder); - RootObjectDefinition def = new RootObjectDefinition(typeof(TestObject), pvs); + pvs.Add("name", placeholder); + RootObjectDefinition def = new RootObjectDefinition(typeof(TestObject), pvs); - IConfigurableListableObjectFactory mock = A.Fake(); - A.CallTo(() => mock.GetObjectDefinitionNames(false)).Returns(new string [] {defName}); - A.CallTo(() => mock.GetObjectDefinition(defName, false)).Returns(def); + IConfigurableListableObjectFactory mock = A.Fake(); + A.CallTo(() => mock.GetObjectDefinitionNames(false)).Returns(new string[] { defName }); + A.CallTo(() => mock.GetObjectDefinition(defName, false)).Returns(def); - PropertyPlaceholderConfigurer cfg = new PropertyPlaceholderConfigurer(); - cfg.IgnoreUnresolvablePlaceholders = true; - cfg.PostProcessObjectFactory(mock); - Assert.AreEqual(placeholder, foo.Name); + PropertyPlaceholderConfigurer cfg = new PropertyPlaceholderConfigurer(); + cfg.IgnoreUnresolvablePlaceholders = true; + cfg.PostProcessObjectFactory(mock); + Assert.AreEqual(placeholder, foo.Name); - A.CallTo(() => mock.AddEmbeddedValueResolver(null)).WithAnyArguments().MustHaveHappened(); - } + A.CallTo(() => mock.AddEmbeddedValueResolver(null)).WithAnyArguments().MustHaveHappened(); + } - [Test] - public void ViaXML() - { - IResource resource = new ReadOnlyXmlTestResource("PropertyResourceConfigurerTests.xml", GetType()); - XmlObjectFactory xbf = new XmlObjectFactory(resource); - PropertyPlaceholderConfigurer ppc = (PropertyPlaceholderConfigurer) xbf.GetObject("PlaceholderConfigurer"); - Assert.IsNotNull(ppc); - ppc.PostProcessObjectFactory(xbf); - TestObject to = (TestObject) xbf.GetObject("Test1"); - Assert.AreEqual("A DefName", to.Name); - } + [Test] + public void ViaXML() + { + IResource resource = new ReadOnlyXmlTestResource("PropertyResourceConfigurerTests.xml", GetType()); + XmlObjectFactory xbf = new XmlObjectFactory(resource); + PropertyPlaceholderConfigurer ppc = (PropertyPlaceholderConfigurer) xbf.GetObject("PlaceholderConfigurer"); + Assert.IsNotNull(ppc); + ppc.PostProcessObjectFactory(xbf); + TestObject to = (TestObject) xbf.GetObject("Test1"); + Assert.AreEqual("A DefName", to.Name); + } - [Test] - public void ViaXMLAndConfigSection() - { - IResource resource = new ReadOnlyXmlTestResource("PropertyResourceConfigurerTests.xml", GetType()); - XmlObjectFactory xbf = new XmlObjectFactory(resource); - PropertyPlaceholderConfigurer ppc = (PropertyPlaceholderConfigurer) xbf.GetObject("ConfigSectionPlaceholderConfigurer"); - Assert.IsNotNull(ppc); - ppc.PostProcessObjectFactory(xbf); + [Test] + public void ViaXMLAndConfigSection() + { + IResource resource = new ReadOnlyXmlTestResource("PropertyResourceConfigurerTests.xml", GetType()); + XmlObjectFactory xbf = new XmlObjectFactory(resource); + PropertyPlaceholderConfigurer ppc = (PropertyPlaceholderConfigurer) xbf.GetObject("ConfigSectionPlaceholderConfigurer"); + Assert.IsNotNull(ppc); + ppc.PostProcessObjectFactory(xbf); - Assert.AreEqual("name from section", ((TestObject)xbf.GetObject("Test3")).Name); - Assert.AreEqual("name from sectiongroup/section", ((TestObject)xbf.GetObject("Test4")).Name); - } + Assert.AreEqual("name from section", ((TestObject) xbf.GetObject("Test3")).Name); + Assert.AreEqual("name from sectiongroup/section", ((TestObject) xbf.GetObject("Test4")).Name); + } - [Test] - public void WithTypes() - { - IApplicationContext ctx = new XmlApplicationContext( - "file://Spring/Objects/Factory/Config/PPCWithTypesTests.xml"); + [Test] + public void WithTypes() + { + IApplicationContext ctx = new XmlApplicationContext( + "file://Spring/Objects/Factory/Config/PPCWithTypesTests.xml"); - object obj = ctx["testObject"]; - Assert.IsTrue(obj is TestObject); + object obj = ctx["testObject"]; + Assert.IsTrue(obj is TestObject); - TestObject to = (TestObject)obj; + TestObject to = (TestObject) obj; - Assert.AreEqual(2, to.Pets.Count); - Assert.AreEqual(2, to.PeriodicTable.Count); - Assert.AreEqual(2, to.Computers.Count); - Assert.IsTrue(to.PeriodicTable.Contains("C")); - } + Assert.AreEqual(2, to.Pets.Count); + Assert.AreEqual(2, to.PeriodicTable.Count); + Assert.AreEqual(2, to.Computers.Count); + Assert.IsTrue(to.PeriodicTable.Contains("C")); + } - [Test] - public void WithMultipleXml_MultiplePropertyPlaceholderConfigurersAndOrder_CanReplaceValueFromOtherXml() - { - var context = - new XmlApplicationContext( - new[] - { - "file://Spring/Objects/Factory/Config/FirstPropertyPlaceholderConfigurer.xml", - "file://Spring/Objects/Factory/Config/SecondPropertyPlaceholderConfigurer.xml" - }); + [Test] + public void WithMultipleXml_MultiplePropertyPlaceholderConfigurersAndOrder_CanReplaceValueFromOtherXml() + { + var context = + new XmlApplicationContext( + new[] { "file://Spring/Objects/Factory/Config/FirstPropertyPlaceholderConfigurer.xml", "file://Spring/Objects/Factory/Config/SecondPropertyPlaceholderConfigurer.xml" }); - var testObject = context.GetObject("testObject"); + var testObject = context.GetObject("testObject"); - Assert.AreEqual("correct_name", testObject.Name); - } + Assert.AreEqual("correct_name", testObject.Name); } } diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/PropertyRetrievingFactoryObjectTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/PropertyRetrievingFactoryObjectTests.cs index 083b3483..d51ca89a 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/PropertyRetrievingFactoryObjectTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/PropertyRetrievingFactoryObjectTests.cs @@ -26,317 +26,316 @@ using Spring.Core; #endregion -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Unit tests for the PropertyRetrievingFactoryObject class. +/// +/// Rick Evans +[TestFixture] +public sealed class PropertyRetrievingFactoryObjectTests { - /// - /// Unit tests for the PropertyRetrievingFactoryObject class. - /// - /// Rick Evans - [TestFixture] - public sealed class PropertyRetrievingFactoryObjectTests - { - [Test] - public void Instantiation() - { - PropertyRetrievingFactoryObject fac = new PropertyRetrievingFactoryObject(); - Assert.IsNotNull(fac.Arguments); - } + [Test] + public void Instantiation() + { + PropertyRetrievingFactoryObject fac = new PropertyRetrievingFactoryObject(); + Assert.IsNotNull(fac.Arguments); + } - [Test] - public void BailsWhenStaticPropertyIsSetToNull() - { - PropertyRetrievingFactoryObject fac = new PropertyRetrievingFactoryObject(); - Assert.Throws(() => fac.StaticProperty = null); - } + [Test] + public void BailsWhenStaticPropertyIsSetToNull() + { + PropertyRetrievingFactoryObject fac = new PropertyRetrievingFactoryObject(); + Assert.Throws(() => fac.StaticProperty = null); + } - /// - /// Test support for nested static properties. - /// - [Test] - public void NestedStaticProperty() - { - PropertyRetrievingFactoryObject fac = new PropertyRetrievingFactoryObject(); - fac.StaticProperty = "Spring.Objects.Factory.Config.PropertyObject.StaticProperty.Age, Spring.Core.Tests"; - fac.AfterPropertiesSet(); - Assert.AreEqual(typeof (int), fac.ObjectType); - object actual = fac.GetObject(); - Assert.AreEqual(PropertyObject.Age, actual); - } + /// + /// Test support for nested static properties. + /// + [Test] + public void NestedStaticProperty() + { + PropertyRetrievingFactoryObject fac = new PropertyRetrievingFactoryObject(); + fac.StaticProperty = "Spring.Objects.Factory.Config.PropertyObject.StaticProperty.Age, Spring.Core.Tests"; + fac.AfterPropertiesSet(); + Assert.AreEqual(typeof(int), fac.ObjectType); + object actual = fac.GetObject(); + Assert.AreEqual(PropertyObject.Age, actual); + } - /// - /// Test support for nested indexed static and instance properties. - /// - [Test] - public void MixOfNestedIndexedStaticAndInstanceProperty() - { - PropertyRetrievingFactoryObject fac = new PropertyRetrievingFactoryObject(); - fac.StaticProperty = "Spring.Objects.Factory.Config.PropertyObject.StaticProperty.Item, Spring.Core.Tests"; - fac.Arguments = new object[] {0}; - fac.AfterPropertiesSet(); - Assert.AreEqual(typeof (int), fac.ObjectType); - object actual = fac.GetObject(); - Assert.AreEqual(PropertyObject.StaticProperty[0], actual); - } + /// + /// Test support for nested indexed static and instance properties. + /// + [Test] + public void MixOfNestedIndexedStaticAndInstanceProperty() + { + PropertyRetrievingFactoryObject fac = new PropertyRetrievingFactoryObject(); + fac.StaticProperty = "Spring.Objects.Factory.Config.PropertyObject.StaticProperty.Item, Spring.Core.Tests"; + fac.Arguments = new object[] { 0 }; + fac.AfterPropertiesSet(); + Assert.AreEqual(typeof(int), fac.ObjectType); + object actual = fac.GetObject(); + Assert.AreEqual(PropertyObject.StaticProperty[0], actual); + } - /// - /// Test support for really really nested indexed static and instance properties. - /// - [Test] - public void SuperMixOfNestedIndexedStaticAndInstanceProperty() - { - PropertyRetrievingFactoryObject fac = new PropertyRetrievingFactoryObject(); - fac.StaticProperty = "Spring.Objects.Factory.Config.PropertyObject.StaticProperty.StaticProperty.Item, Spring.Core.Tests"; - fac.Arguments = new object[] {0}; - fac.AfterPropertiesSet(); - Assert.AreEqual(typeof (int), fac.ObjectType); - object actual = fac.GetObject(); - Assert.AreEqual(PropertyObject.StaticProperty[0], actual); - } + /// + /// Test support for really really nested indexed static and instance properties. + /// + [Test] + public void SuperMixOfNestedIndexedStaticAndInstanceProperty() + { + PropertyRetrievingFactoryObject fac = new PropertyRetrievingFactoryObject(); + fac.StaticProperty = "Spring.Objects.Factory.Config.PropertyObject.StaticProperty.StaticProperty.Item, Spring.Core.Tests"; + fac.Arguments = new object[] { 0 }; + fac.AfterPropertiesSet(); + Assert.AreEqual(typeof(int), fac.ObjectType); + object actual = fac.GetObject(); + Assert.AreEqual(PropertyObject.StaticProperty[0], actual); + } - [Test] - public void ResistsSettingTheArgumentsToNull() - { - PropertyRetrievingFactoryObject fac = new PropertyRetrievingFactoryObject(); - fac.Arguments = null; - Assert.IsNotNull(fac.Arguments); - } + [Test] + public void ResistsSettingTheArgumentsToNull() + { + PropertyRetrievingFactoryObject fac = new PropertyRetrievingFactoryObject(); + fac.Arguments = null; + Assert.IsNotNull(fac.Arguments); + } - [Test] - public void StaticProperty() - { - PropertyRetrievingFactoryObject fac = new PropertyRetrievingFactoryObject(); - fac.StaticProperty = "Spring.Objects.Factory.Config.PropertyObject.Age, Spring.Core.Tests"; - fac.AfterPropertiesSet(); - Assert.AreEqual(typeof (int), fac.ObjectType); - object actual = fac.GetObject(); - Assert.AreEqual(PropertyObject.Age, actual); - } + [Test] + public void StaticProperty() + { + PropertyRetrievingFactoryObject fac = new PropertyRetrievingFactoryObject(); + fac.StaticProperty = "Spring.Objects.Factory.Config.PropertyObject.Age, Spring.Core.Tests"; + fac.AfterPropertiesSet(); + Assert.AreEqual(typeof(int), fac.ObjectType); + object actual = fac.GetObject(); + Assert.AreEqual(PropertyObject.Age, actual); + } - [Test] - public void StaticPropertyThatAintAssemblyQualifiedShouldStillBeResolved() - { - PropertyRetrievingFactoryObject fac = new PropertyRetrievingFactoryObject(); - fac.StaticProperty = "Spring.Objects.Factory.Config.PropertyObject.Age"; - fac.AfterPropertiesSet(); - Assert.AreEqual(typeof (int), fac.ObjectType); - object actual = fac.GetObject(); - Assert.AreEqual(PropertyObject.Age, actual); - } + [Test] + public void StaticPropertyThatAintAssemblyQualifiedShouldStillBeResolved() + { + PropertyRetrievingFactoryObject fac = new PropertyRetrievingFactoryObject(); + fac.StaticProperty = "Spring.Objects.Factory.Config.PropertyObject.Age"; + fac.AfterPropertiesSet(); + Assert.AreEqual(typeof(int), fac.ObjectType); + object actual = fac.GetObject(); + Assert.AreEqual(PropertyObject.Age, actual); + } - [Test] - public void StaticPropertyViaClassAndFieldName() - { - PropertyRetrievingFactoryObject fac = new PropertyRetrievingFactoryObject(); - fac.TargetProperty = "Age"; - fac.TargetType = typeof (PropertyObject); - fac.AfterPropertiesSet(); - object actual = fac.GetObject(); - Assert.AreEqual(PropertyObject.Age, actual); - } + [Test] + public void StaticPropertyViaClassAndFieldName() + { + PropertyRetrievingFactoryObject fac = new PropertyRetrievingFactoryObject(); + fac.TargetProperty = "Age"; + fac.TargetType = typeof(PropertyObject); + fac.AfterPropertiesSet(); + object actual = fac.GetObject(); + Assert.AreEqual(PropertyObject.Age, actual); + } - [Test] - public void InstanceProperty() - { - PropertyObject expected = new PropertyObject(); - expected.Name = "Haruki Murakami"; - PropertyRetrievingFactoryObject fac = new PropertyRetrievingFactoryObject(); - fac.TargetObject = expected; - fac.TargetProperty = "Name"; - fac.AfterPropertiesSet(); - object actual = fac.GetObject(); - Assert.AreEqual(expected.Name, actual); - } + [Test] + public void InstanceProperty() + { + PropertyObject expected = new PropertyObject(); + expected.Name = "Haruki Murakami"; + PropertyRetrievingFactoryObject fac = new PropertyRetrievingFactoryObject(); + fac.TargetObject = expected; + fac.TargetProperty = "Name"; + fac.AfterPropertiesSet(); + object actual = fac.GetObject(); + Assert.AreEqual(expected.Name, actual); + } - /// - /// Test support for nested properties on an instance. - /// - [Test] - public void NestedInstanceProperty() - { - TestObject person = new TestObject(); - person.Age = 20; - TestObject spouse = new TestObject(); - spouse.Age = 21; - person.Spouse = spouse; - PropertyRetrievingFactoryObject fac = new PropertyRetrievingFactoryObject(); - fac.TargetObject = person; - fac.TargetProperty = "spouse.age"; - fac.AfterPropertiesSet(); - object actual = fac.GetObject(); - int expectedAge = 21; - Assert.AreEqual(expectedAge, actual); - } + /// + /// Test support for nested properties on an instance. + /// + [Test] + public void NestedInstanceProperty() + { + TestObject person = new TestObject(); + person.Age = 20; + TestObject spouse = new TestObject(); + spouse.Age = 21; + person.Spouse = spouse; + PropertyRetrievingFactoryObject fac = new PropertyRetrievingFactoryObject(); + fac.TargetObject = person; + fac.TargetProperty = "spouse.age"; + fac.AfterPropertiesSet(); + object actual = fac.GetObject(); + int expectedAge = 21; + Assert.AreEqual(expectedAge, actual); + } - [Test] - public void IndexedProperty() - { - PropertyObject expected = new PropertyObject(); - PropertyRetrievingFactoryObject fac = new PropertyRetrievingFactoryObject(); - fac.TargetObject = expected; - fac.TargetProperty = "Item"; - fac.Arguments = new object[] {2}; - fac.AfterPropertiesSet(); - object actual = fac.GetObject(); - Assert.AreEqual(expected[2], actual); - } + [Test] + public void IndexedProperty() + { + PropertyObject expected = new PropertyObject(); + PropertyRetrievingFactoryObject fac = new PropertyRetrievingFactoryObject(); + fac.TargetObject = expected; + fac.TargetProperty = "Item"; + fac.Arguments = new object[] { 2 }; + fac.AfterPropertiesSet(); + object actual = fac.GetObject(); + Assert.AreEqual(expected[2], actual); + } - [Test] - public void BailsWhenReadingIndexedPropertyWithNoArguments() - { - PropertyObject expected = new PropertyObject(); - PropertyRetrievingFactoryObject fac = new PropertyRetrievingFactoryObject(); - fac.TargetObject = expected; - fac.TargetProperty = "Item"; - Assert.Throws(() => fac.AfterPropertiesSet()); - } + [Test] + public void BailsWhenReadingIndexedPropertyWithNoArguments() + { + PropertyObject expected = new PropertyObject(); + PropertyRetrievingFactoryObject fac = new PropertyRetrievingFactoryObject(); + fac.TargetObject = expected; + fac.TargetProperty = "Item"; + Assert.Throws(() => fac.AfterPropertiesSet()); + } - [Test] - public void BailsOnWriteOnlyProperty() - { - PropertyObject expected = new PropertyObject(); - PropertyRetrievingFactoryObject fac = new PropertyRetrievingFactoryObject(); - fac.TargetObject = expected; - fac.TargetProperty = "Greenness"; - Assert.Throws(() => fac.AfterPropertiesSet()); - } + [Test] + public void BailsOnWriteOnlyProperty() + { + PropertyObject expected = new PropertyObject(); + PropertyRetrievingFactoryObject fac = new PropertyRetrievingFactoryObject(); + fac.TargetObject = expected; + fac.TargetProperty = "Greenness"; + Assert.Throws(() => fac.AfterPropertiesSet()); + } - [Test] - public void BailsOnNonExistantProperty() - { - PropertyObject expected = new PropertyObject(); - PropertyRetrievingFactoryObject fac = new PropertyRetrievingFactoryObject(); - fac.TargetObject = expected; - fac.TargetProperty = "Blister"; - Assert.Throws(() => fac.AfterPropertiesSet()); - } + [Test] + public void BailsOnNonExistantProperty() + { + PropertyObject expected = new PropertyObject(); + PropertyRetrievingFactoryObject fac = new PropertyRetrievingFactoryObject(); + fac.TargetObject = expected; + fac.TargetProperty = "Blister"; + Assert.Throws(() => fac.AfterPropertiesSet()); + } - [Test] - public void IsSingleton() - { - PropertyRetrievingFactoryObject fac = new PropertyRetrievingFactoryObject(); - fac.IsSingleton = false; - fac.TargetProperty = "Age"; - fac.TargetType = typeof (PropertyObject); - fac.AfterPropertiesSet(); - object actual = fac.GetObject(); - Assert.AreEqual(PropertyObject.Age, actual); + [Test] + public void IsSingleton() + { + PropertyRetrievingFactoryObject fac = new PropertyRetrievingFactoryObject(); + fac.IsSingleton = false; + fac.TargetProperty = "Age"; + fac.TargetType = typeof(PropertyObject); + fac.AfterPropertiesSet(); + object actual = fac.GetObject(); + Assert.AreEqual(PropertyObject.Age, actual); - PropertyObject.Age = 94; - object tryTwo = fac.GetObject(); - Assert.AreEqual(PropertyObject.Age, tryTwo); - } + PropertyObject.Age = 94; + object tryTwo = fac.GetObject(); + Assert.AreEqual(PropertyObject.Age, tryTwo); + } - [Test] - public void BailsWhenNotConfigured() - { - PropertyRetrievingFactoryObject fac = new PropertyRetrievingFactoryObject(); - Assert.Throws(() => fac.AfterPropertiesSet(), "One of the TargetType or TargetObject properties must be set."); - } + [Test] + public void BailsWhenNotConfigured() + { + PropertyRetrievingFactoryObject fac = new PropertyRetrievingFactoryObject(); + Assert.Throws(() => fac.AfterPropertiesSet(), "One of the TargetType or TargetObject properties must be set."); + } - [Test] - public void BailsWhenJustTargetPropertyIsSet() - { - PropertyRetrievingFactoryObject fac = new PropertyRetrievingFactoryObject(); - fac.TargetProperty = "Funk"; - Assert.Throws(() => fac.AfterPropertiesSet()); - } + [Test] + public void BailsWhenJustTargetPropertyIsSet() + { + PropertyRetrievingFactoryObject fac = new PropertyRetrievingFactoryObject(); + fac.TargetProperty = "Funk"; + Assert.Throws(() => fac.AfterPropertiesSet()); + } - [Test] - public void BailsWhenJustTargetTypeIsSet() - { - PropertyRetrievingFactoryObject fac = new PropertyRetrievingFactoryObject(); - fac.TargetType = GetType(); - Assert.Throws(() => fac.AfterPropertiesSet()); - } + [Test] + public void BailsWhenJustTargetTypeIsSet() + { + PropertyRetrievingFactoryObject fac = new PropertyRetrievingFactoryObject(); + fac.TargetType = GetType(); + Assert.Throws(() => fac.AfterPropertiesSet()); + } - [Test] - public void BailsWhenJustTargetObjectIsSet() - { - PropertyRetrievingFactoryObject fac = new PropertyRetrievingFactoryObject(); - fac.TargetObject = this; - Assert.Throws(() => fac.AfterPropertiesSet(), "The TargetProperty property is required."); - } + [Test] + public void BailsWhenJustTargetObjectIsSet() + { + PropertyRetrievingFactoryObject fac = new PropertyRetrievingFactoryObject(); + fac.TargetObject = this; + Assert.Throws(() => fac.AfterPropertiesSet(), "The TargetProperty property is required."); + } - [Test] - public void BailsWhenStaticPropertyPassedGumpfh() - { - PropertyRetrievingFactoryObject fac = new PropertyRetrievingFactoryObject(); - Assert.Throws(() => fac.StaticProperty = "Boog"); // no field specified - } + [Test] + public void BailsWhenStaticPropertyPassedGumpfh() + { + PropertyRetrievingFactoryObject fac = new PropertyRetrievingFactoryObject(); + Assert.Throws(() => fac.StaticProperty = "Boog"); // no field specified + } - [Test] - public void StaticPropertyCaseINsenSiTiVE() - { - PropertyRetrievingFactoryObject fac = new PropertyRetrievingFactoryObject(); - fac.StaticProperty = "System.Globalization.CultureInfo.CURRENtUiCultURE, Mscorlib"; - fac.AfterPropertiesSet(); - Assert.AreEqual(typeof (CultureInfo), fac.ObjectType); - CultureInfo actual = fac.GetObject() as CultureInfo; - Assert.IsNotNull(actual); - Assert.AreEqual(CultureInfo.CurrentUICulture, actual); - } + [Test] + public void StaticPropertyCaseINsenSiTiVE() + { + PropertyRetrievingFactoryObject fac = new PropertyRetrievingFactoryObject(); + fac.StaticProperty = "System.Globalization.CultureInfo.CURRENtUiCultURE, Mscorlib"; + fac.AfterPropertiesSet(); + Assert.AreEqual(typeof(CultureInfo), fac.ObjectType); + CultureInfo actual = fac.GetObject() as CultureInfo; + Assert.IsNotNull(actual); + Assert.AreEqual(CultureInfo.CurrentUICulture, actual); + } - [Test] - public void GetDateTimeDotNowToTestHandlingOfPrototypesIsCorrect() - { - PropertyRetrievingFactoryObject fac = new PropertyRetrievingFactoryObject(); - fac.TargetType = typeof(DateTime); - fac.TargetProperty = "Now"; - fac.IsSingleton = false; - fac.AfterPropertiesSet(); - DateTime then = (DateTime) fac.GetObject(); - Assert.IsNotNull(then); - Thread.Sleep(TimeSpan.FromMilliseconds(10)); - DateTime now = (DateTime) fac.GetObject(); - Assert.IsNotNull(now); - Assert.AreNotEqual(then, now); - } - } + [Test] + public void GetDateTimeDotNowToTestHandlingOfPrototypesIsCorrect() + { + PropertyRetrievingFactoryObject fac = new PropertyRetrievingFactoryObject(); + fac.TargetType = typeof(DateTime); + fac.TargetProperty = "Now"; + fac.IsSingleton = false; + fac.AfterPropertiesSet(); + DateTime then = (DateTime) fac.GetObject(); + Assert.IsNotNull(then); + Thread.Sleep(TimeSpan.FromMilliseconds(10)); + DateTime now = (DateTime) fac.GetObject(); + Assert.IsNotNull(now); + Assert.AreNotEqual(then, now); + } +} - internal sealed class PropertyObject - { - private static int _age = 74; +internal sealed class PropertyObject +{ + private static int _age = 74; - public static int Age - { - get { return _age; } - set { _age = value; } - } + public static int Age + { + get { return _age; } + set { _age = value; } + } - private string _name; + private string _name; - public string Name - { - get { return _name; } - set { _name = value; } - } + public string Name + { + get { return _name; } + set { _name = value; } + } - private int[] _battingAverage = new int[] {1000, 350, 400}; + private int[] _battingAverage = new int[] { 1000, 350, 400 }; - public int[] Averages - { - get { return _battingAverage; } - } + public int[] Averages + { + get { return _battingAverage; } + } - public int this[int index] - { - get { return _battingAverage[index]; } - set { _battingAverage[index] = value; } - } + public int this[int index] + { + get { return _battingAverage[index]; } + set { _battingAverage[index] = value; } + } - public bool Greenness - { - set - { - // no-op... just here for non-readability - } - } + public bool Greenness + { + set + { + // no-op... just here for non-readability + } + } - private static readonly PropertyObject _staticProperty = new PropertyObject(); + private static readonly PropertyObject _staticProperty = new PropertyObject(); - public static PropertyObject StaticProperty - { - get { return _staticProperty; } - } - } -} \ No newline at end of file + public static PropertyObject StaticProperty + { + get { return _staticProperty; } + } +} diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/RegistryVariableSourceTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/RegistryVariableSourceTests.cs index 9e8f166c..04cbdc1b 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/RegistryVariableSourceTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/RegistryVariableSourceTests.cs @@ -23,53 +23,52 @@ using NUnit.Framework; #pragma warning disable CA1416 // is only supported on windows -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Unit tests for the RegistryVariableSource class. +/// +/// Aleksandar Seovic +[Platform("Win")] +public sealed class RegistryVariableSourceTests { - /// - /// Unit tests for the RegistryVariableSource class. - /// - /// Aleksandar Seovic - [Platform("Win")] - public sealed class RegistryVariableSourceTests + private RegistryKey key; + + [SetUp] + public void SetUp() { - private RegistryKey key; + key = Registry.CurrentUser.CreateSubKey("RegistryVariableSourceTests"); + key.SetValue("name", "Aleks Seovic"); + key.SetValue("computer_name", "%COMPUTERNAME% is the name of my computer", RegistryValueKind.ExpandString); + key.SetValue("age", 32, RegistryValueKind.DWord); + key.SetValue("family", new string[] { "Marija", "Ana", "Nadja" }); + key.SetValue("bday", new byte[] { 24, 8, 74 }); + key.Flush(); + } - [SetUp] - public void SetUp() - { - key = Registry.CurrentUser.CreateSubKey("RegistryVariableSourceTests"); - key.SetValue("name", "Aleks Seovic"); - key.SetValue("computer_name", "%COMPUTERNAME% is the name of my computer", RegistryValueKind.ExpandString); - key.SetValue("age", 32, RegistryValueKind.DWord); - key.SetValue("family", new string[] {"Marija", "Ana", "Nadja"}); - key.SetValue("bday", new byte[] {24, 8, 74}); - key.Flush(); - } + [TearDown] + public void TearDown() + { + Registry.CurrentUser.DeleteSubKey("RegistryVariableSourceTests"); + } - [TearDown] - public void TearDown() - { - Registry.CurrentUser.DeleteSubKey("RegistryVariableSourceTests"); - } + [Test] + public void TestVariablesResolution() + { + RegistryVariableSource rvs = new RegistryVariableSource(); + rvs.Key = key; - [Test] - public void TestVariablesResolution() - { - RegistryVariableSource rvs = new RegistryVariableSource(); - rvs.Key = key; + // existing vars + Assert.AreEqual("Aleks Seovic", rvs.ResolveVariable("name")); + Assert.AreEqual(Environment.GetEnvironmentVariable("COMPUTERNAME") + " is the name of my computer", + rvs.ResolveVariable("computer_name")); + Assert.AreEqual("32", rvs.ResolveVariable("age")); + // multi_sz + Assert.AreEqual("Marija,Ana,Nadja", rvs.ResolveVariable("family")); + // binary + Assert.AreEqual(null, rvs.ResolveVariable("bday")); - // existing vars - Assert.AreEqual("Aleks Seovic", rvs.ResolveVariable("name")); - Assert.AreEqual(Environment.GetEnvironmentVariable("COMPUTERNAME") + " is the name of my computer", - rvs.ResolveVariable("computer_name")); - Assert.AreEqual("32", rvs.ResolveVariable("age")); - // multi_sz - Assert.AreEqual( "Marija,Ana,Nadja", rvs.ResolveVariable("family")); - // binary - Assert.AreEqual( null, rvs.ResolveVariable("bday")); - - // non-existant variable - Assert.IsNull(rvs.ResolveVariable("xyz")); - } + // non-existant variable + Assert.IsNull(rvs.ResolveVariable("xyz")); } } diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/ResourceHandlerConfigurerTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/ResourceHandlerConfigurerTests.cs index b1aae7b9..e786f232 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/ResourceHandlerConfigurerTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/ResourceHandlerConfigurerTests.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -19,104 +19,94 @@ #endregion using System.Collections; - using FakeItEasy; - using NUnit.Framework; - using Spring.Core.IO; using Spring.Util; -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Unit tests for the TypeAliasConfigurer class +/// +/// Mark Pollack +[TestFixture] +public class ResourceHandlerConfigurerTests { - /// - /// Unit tests for the TypeAliasConfigurer class - /// - /// Mark Pollack - [TestFixture] - public class ResourceHandlerConfigurerTests + [SetUp] + public void SetUp() { - [SetUp] - public void SetUp() - { - } + } - [Test] - public void Serialization() - { - IDictionary resourceHandlers = new Hashtable(); - resourceHandlers.Add("httpsss", typeof(UrlResource).AssemblyQualifiedName); + [Test] + public void Serialization() + { + IDictionary resourceHandlers = new Hashtable(); + resourceHandlers.Add("httpsss", typeof(UrlResource).AssemblyQualifiedName); - ResourceHandlerConfigurer resourceHandlerConfiguer = new ResourceHandlerConfigurer(); - resourceHandlerConfiguer.ResourceHandlers = resourceHandlers; + ResourceHandlerConfigurer resourceHandlerConfiguer = new ResourceHandlerConfigurer(); + resourceHandlerConfiguer.ResourceHandlers = resourceHandlers; + resourceHandlerConfiguer.Order = 1; - resourceHandlerConfiguer.Order = 1; + SerializationTestUtils.SerializeAndDeserialize(resourceHandlerConfiguer); + } - SerializationTestUtils.SerializeAndDeserialize(resourceHandlerConfiguer); - } + [Test] + public void UseInvalidTypeForDictionaryValue() + { + IDictionary resourceHandlers = new Hashtable(); + resourceHandlers.Add("httpsss", new Hashtable()); - [Test] - public void UseInvalidTypeForDictionaryValue() - { - IDictionary resourceHandlers = new Hashtable(); - resourceHandlers.Add("httpsss", new Hashtable()); + ResourceHandlerConfigurer resourceHandlerConfiguer = new ResourceHandlerConfigurer(); + resourceHandlerConfiguer.ResourceHandlers = resourceHandlers; - ResourceHandlerConfigurer resourceHandlerConfiguer = new ResourceHandlerConfigurer(); - resourceHandlerConfiguer.ResourceHandlers = resourceHandlers; + Assert.Throws(() => resourceHandlerConfiguer.PostProcessObjectFactory(A.Fake())); + } - Assert.Throws(() => resourceHandlerConfiguer.PostProcessObjectFactory(A.Fake())); - } + [Test] + public void UseNonResolvableTypeForDictionaryValue() + { + IDictionary resourceHandlers = new Hashtable(); + resourceHandlers.Add("httpsss", "Spring.Core.IO.UrrrrlResource, Spring.Core"); - [Test] - public void UseNonResolvableTypeForDictionaryValue() - { - IDictionary resourceHandlers = new Hashtable(); - resourceHandlers.Add("httpsss", "Spring.Core.IO.UrrrrlResource, Spring.Core"); + ResourceHandlerConfigurer resourceHandlerConfiguer = new ResourceHandlerConfigurer(); + resourceHandlerConfiguer.ResourceHandlers = resourceHandlers; - ResourceHandlerConfigurer resourceHandlerConfiguer = new ResourceHandlerConfigurer(); - resourceHandlerConfiguer.ResourceHandlers = resourceHandlers; + Assert.Throws(() => resourceHandlerConfiguer.PostProcessObjectFactory(A.Fake())); + } + [Test] + public void SunnyDayScenarioUsingType() + { + IDictionary resourceHandlers = new Hashtable(); + resourceHandlers.Add("httpsss", typeof(UrlResource)); - Assert.Throws(() => resourceHandlerConfiguer.PostProcessObjectFactory(A.Fake())); - } + CreateConfigurerAndTestNewProtcol(resourceHandlers); + } - [Test] - public void SunnyDayScenarioUsingType() - { + [Test] + public void SunnyDayScenarioUsingTypeString() + { + IDictionary typeAliases = new Hashtable(); + typeAliases.Add("httpsss", "Spring.Core.IO.UrlResource, Spring.Core"); + CreateConfigurerAndTestNewProtcol(typeAliases); + } + private void CreateConfigurerAndTestNewProtcol(IDictionary resourceHandlers) + { + ResourceHandlerConfigurer resourceHandlerConfiguer = new ResourceHandlerConfigurer(); + resourceHandlerConfiguer.ResourceHandlers = resourceHandlers; - IDictionary resourceHandlers = new Hashtable(); - resourceHandlers.Add("httpsss", typeof(UrlResource)); + resourceHandlerConfiguer.Order = 1; - CreateConfigurerAndTestNewProtcol(resourceHandlers); - } + resourceHandlerConfiguer.PostProcessObjectFactory(A.Fake()); - [Test] - public void SunnyDayScenarioUsingTypeString() - { - IDictionary typeAliases = new Hashtable(); - typeAliases.Add("httpsss", "Spring.Core.IO.UrlResource, Spring.Core"); - CreateConfigurerAndTestNewProtcol(typeAliases); + //todo investigate mocking the typeregistry, for now ask the actual one for information. + Assert.IsTrue(ResourceHandlerRegistry.IsHandlerRegistered("httpsss"), + "ResourceHandlerConfigurer did not register a protocol handler with the ResourceHandlerRegistry"); - } - - private void CreateConfigurerAndTestNewProtcol(IDictionary resourceHandlers) - { - ResourceHandlerConfigurer resourceHandlerConfiguer = new ResourceHandlerConfigurer(); - resourceHandlerConfiguer.ResourceHandlers = resourceHandlers; - - resourceHandlerConfiguer.Order = 1; - - - resourceHandlerConfiguer.PostProcessObjectFactory(A.Fake()); - - //todo investigate mocking the typeregistry, for now ask the actual one for information. - Assert.IsTrue(ResourceHandlerRegistry.IsHandlerRegistered("httpsss"), - "ResourceHandlerConfigurer did not register a protocol handler with the ResourceHandlerRegistry"); - - Assert.IsTrue(ResourceHandlerRegistry.IsHandlerRegistered("httpsss"), "Custom IResource not registered."); - Assert.AreEqual(1, resourceHandlerConfiguer.Order); - } + Assert.IsTrue(ResourceHandlerRegistry.IsHandlerRegistered("httpsss"), "Custom IResource not registered."); + Assert.AreEqual(1, resourceHandlerConfiguer.Order); } } diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/ResourceManagerFactoryObjectTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/ResourceManagerFactoryObjectTests.cs index 18b52fff..54c842e1 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/ResourceManagerFactoryObjectTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/ResourceManagerFactoryObjectTests.cs @@ -1,80 +1,81 @@ #region License + /* * Copyright 2002-2010 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.Resources; using NUnit.Framework; -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Unit tests for the ResourceManagerFactoryObject class. +/// +/// Mark Pollack +[TestFixture] +public sealed class ResourceManagerFactoryObjectTests { - /// - /// Unit tests for the ResourceManagerFactoryObject class. - /// - /// Mark Pollack - [TestFixture] - public sealed class ResourceManagerFactoryObjectTests - { - /// - /// Test basic sunny day usage of the ResourceManagerFactoryObject. - /// - [Test] - public void CreateResourceManager() - { - ResourceManagerFactoryObject fac = new ResourceManagerFactoryObject(); - fac.BaseName = "Spring.Resources.SampleResources"; - fac.AssemblyName = "Spring.Core.Tests"; - fac.AfterPropertiesSet(); - Assert.AreEqual( typeof(ResourceManager), fac.ObjectType); - object actual = fac.GetObject(); - Assert.IsNotNull(actual); - Assert.AreEqual( typeof(ResourceManager), actual.GetType()); - ResourceManager rm = (ResourceManager) actual; - string message = rm.GetString("message"); - Assert.AreEqual("Hello {0} {1}", message); - } + /// + /// Test basic sunny day usage of the ResourceManagerFactoryObject. + /// + [Test] + public void CreateResourceManager() + { + ResourceManagerFactoryObject fac = new ResourceManagerFactoryObject(); + fac.BaseName = "Spring.Resources.SampleResources"; + fac.AssemblyName = "Spring.Core.Tests"; + fac.AfterPropertiesSet(); + Assert.AreEqual(typeof(ResourceManager), fac.ObjectType); + object actual = fac.GetObject(); + Assert.IsNotNull(actual); + Assert.AreEqual(typeof(ResourceManager), actual.GetType()); + ResourceManager rm = (ResourceManager) actual; + string message = rm.GetString("message"); + Assert.AreEqual("Hello {0} {1}", message); + } - [Test] - public void MissingBaseName() - { - ResourceManagerFactoryObject fac = new ResourceManagerFactoryObject(); - Assert.Throws(() => fac.AfterPropertiesSet()); - } + [Test] + public void MissingBaseName() + { + ResourceManagerFactoryObject fac = new ResourceManagerFactoryObject(); + Assert.Throws(() => fac.AfterPropertiesSet()); + } - [Test] - public void MissingAssemblyName() - { - ResourceManagerFactoryObject fac = new ResourceManagerFactoryObject(); - fac.BaseName = "Spring.Resources.SampleResources"; - Assert.Throws(() => fac.AfterPropertiesSet()); - } + [Test] + public void MissingAssemblyName() + { + ResourceManagerFactoryObject fac = new ResourceManagerFactoryObject(); + fac.BaseName = "Spring.Resources.SampleResources"; + Assert.Throws(() => fac.AfterPropertiesSet()); + } - [Test] - public void WithRubbishAssemblyName() - { - ResourceManagerFactoryObject fac = new ResourceManagerFactoryObject(); - fac.BaseName = "Spring.Resources.SampleResources"; - fac.AssemblyName = "I'mAJumpedUpPantryBoy"; - Assert.Throws(() => fac.AfterPropertiesSet()); - } + [Test] + public void WithRubbishAssemblyName() + { + ResourceManagerFactoryObject fac = new ResourceManagerFactoryObject(); + fac.BaseName = "Spring.Resources.SampleResources"; + fac.AssemblyName = "I'mAJumpedUpPantryBoy"; + Assert.Throws(() => fac.AfterPropertiesSet()); + } - [Test] - public void ObjectTypeReallyIsResourceManager() - { - Assert.AreEqual(typeof (ResourceManager), new ResourceManagerFactoryObject().ObjectType); - } - } + [Test] + public void ObjectTypeReallyIsResourceManager() + { + Assert.AreEqual(typeof(ResourceManager), new ResourceManagerFactoryObject().ObjectType); + } } diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/RuntimeObjectReferenceTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/RuntimeObjectReferenceTests.cs index 6e7fa437..150c754e 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/RuntimeObjectReferenceTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/RuntimeObjectReferenceTests.cs @@ -24,22 +24,21 @@ using NUnit.Framework; #endregion -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Unit tests for the RuntimeObjectReference class. +/// +/// Rick Evans +[TestFixture] +public sealed class RuntimeObjectReferenceTests { - /// - /// Unit tests for the RuntimeObjectReference class. - /// - /// Rick Evans - [TestFixture] - public sealed class RuntimeObjectReferenceTests + [Test] + public void InstantiationIsImplictlyNotToParent() { - [Test] - public void InstantiationIsImplictlyNotToParent() - { - RuntimeObjectReference ror = new RuntimeObjectReference("foo"); - Assert.IsFalse(ror.IsToParent, - "IsToParent property must default to false if not " + - "using the explicit variant of the ctor."); - } - } + RuntimeObjectReference ror = new RuntimeObjectReference("foo"); + Assert.IsFalse(ror.IsToParent, + "IsToParent property must default to false if not " + + "using the explicit variant of the ctor."); + } } diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/SetFactoryObjectTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/SetFactoryObjectTests.cs index ce5cbca6..16300bf3 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/SetFactoryObjectTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/SetFactoryObjectTests.cs @@ -26,63 +26,62 @@ using NUnit.Framework; #endregion -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Unit tests for the SetFactoryObject class. +/// +/// Rick Evans +[TestFixture] +public sealed class SetFactoryObjectTests { - /// - /// Unit tests for the SetFactoryObject class. - /// - /// Rick Evans - [TestFixture] - public sealed class SetFactoryObjectTests + [Test] + public void SetTargetSetTypeToNonSetType() { - [Test] - public void SetTargetSetTypeToNonSetType() - { - SetFactoryObject lfo = new SetFactoryObject(); - Assert.Throws(() => lfo.TargetSetType = typeof (ICollection), "The Type passed to the TargetSetType property must implement the 'Spring.Collections.ISet' interface."); - } + SetFactoryObject lfo = new SetFactoryObject(); + Assert.Throws(() => lfo.TargetSetType = typeof(ICollection), "The Type passed to the TargetSetType property must implement the 'Spring.Collections.ISet' interface."); + } - [Test] - public void SetTargetSetTypeToDerivedISetInterfaceType() - { - SetFactoryObject lfo = new SetFactoryObject(); - Assert.Throws(() => lfo.TargetSetType = typeof (IExtendedSet), "The Type passed to the TargetSetType property cannot be an interface; it must be a concrete class that implements the 'Spring.Collections.ISet' interface."); - } + [Test] + public void SetTargetSetTypeToDerivedISetInterfaceType() + { + SetFactoryObject lfo = new SetFactoryObject(); + Assert.Throws(() => lfo.TargetSetType = typeof(IExtendedSet), "The Type passed to the TargetSetType property cannot be an interface; it must be a concrete class that implements the 'Spring.Collections.ISet' interface."); + } - [Test] - public void SetTargetSetTypeToAbstractISetInterfaceType() - { - SetFactoryObject lfo = new SetFactoryObject(); - Assert.Throws(() => lfo.TargetSetType = typeof (AbstractSet), "The Type passed to the TargetSetType property cannot be abstract (MustInherit in VisualBasic.NET); it must be a concrete class that implements the 'Spring.Collections.ISet' interface."); - } + [Test] + public void SetTargetSetTypeToAbstractISetInterfaceType() + { + SetFactoryObject lfo = new SetFactoryObject(); + Assert.Throws(() => lfo.TargetSetType = typeof(AbstractSet), "The Type passed to the TargetSetType property cannot be abstract (MustInherit in VisualBasic.NET); it must be a concrete class that implements the 'Spring.Collections.ISet' interface."); + } - private interface IExtendedSet : ISet - { - } + private interface IExtendedSet : ISet + { + } - private abstract class AbstractSet : HybridSet - { - } + private abstract class AbstractSet : HybridSet + { + } - [Test] - public void SetTargetSetTypeToNull() - { - SetFactoryObject lfo = new SetFactoryObject(); - Assert.Throws(() => lfo.TargetSetType = null); - } + [Test] + public void SetTargetSetTypeToNull() + { + SetFactoryObject lfo = new SetFactoryObject(); + Assert.Throws(() => lfo.TargetSetType = null); + } - [Test] - public void GetObjectWithoutSupplyingASourceSet() - { - SetFactoryObject lfo = new SetFactoryObject(); - lfo.IsSingleton = false; - Assert.Throws(() => lfo.GetObject(), "The 'SourceSet' property cannot be null (Nothing in Visual Basic.NET)."); - } + [Test] + public void GetObjectWithoutSupplyingASourceSet() + { + SetFactoryObject lfo = new SetFactoryObject(); + lfo.IsSingleton = false; + Assert.Throws(() => lfo.GetObject(), "The 'SourceSet' property cannot be null (Nothing in Visual Basic.NET)."); + } - [Test] - public void ObjectTypeReallyIsISet() - { - Assert.AreEqual(typeof (ISet), new SetFactoryObject().ObjectType); - } - } + [Test] + public void ObjectTypeReallyIsISet() + { + Assert.AreEqual(typeof(ISet), new SetFactoryObject().ObjectType); + } } diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/SharedStateAwareProcessorTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/SharedStateAwareProcessorTests.cs index 7157bb5f..3a1bcba8 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/SharedStateAwareProcessorTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/SharedStateAwareProcessorTests.cs @@ -21,146 +21,149 @@ #region Imports using System.Collections; - using FakeItEasy; using NUnit.Framework; - using Spring.Objects.Factory.Support; using Spring.Objects.Support; #endregion -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// +/// +/// Erich Eichinger +[TestFixture] +public class SharedStateAwareProcessorTests { - /// - /// - /// - /// Erich Eichinger - [TestFixture] - public class SharedStateAwareProcessorTests + [Test] + public void DoesNotAllowNullOrEmptyFactoryList() { - [Test] - public void DoesNotAllowNullOrEmptyFactoryList() + // check default ctor init + SharedStateAwareProcessor ssap = new SharedStateAwareProcessor(); + Assert.IsNotNull(ssap.SharedStateFactories); + Assert.AreEqual(0, ssap.SharedStateFactories.Length); + + // check we accept a list at all + ssap = new SharedStateAwareProcessor(new ISharedStateFactory[] { new ByTypeSharedStateFactory() }, Int32.MaxValue); + + // now ensure that SharedStateFactories will never be null or empty + ssap = new SharedStateAwareProcessor(); + try + { + ssap.SharedStateFactories = null; + Assert.Fail("should throw ArgumentException"); + } + catch (ArgumentException) { - // check default ctor init - SharedStateAwareProcessor ssap = new SharedStateAwareProcessor(); - Assert.IsNotNull( ssap.SharedStateFactories ); - Assert.AreEqual( 0, ssap.SharedStateFactories.Length ); - - // check we accept a list at all - ssap = new SharedStateAwareProcessor( new ISharedStateFactory[] { new ByTypeSharedStateFactory() }, Int32.MaxValue ); - - // now ensure that SharedStateFactories will never be null or empty - ssap = new SharedStateAwareProcessor(); - try - { - ssap.SharedStateFactories = null; - Assert.Fail( "should throw ArgumentException" ); - } - catch (ArgumentException) - { } - - try - { - ssap.SharedStateFactories = new ISharedStateFactory[0]; - Assert.Fail( "should throw ArgumentException" ); - } - catch (ArgumentException) - { } - - try - { - ssap.SharedStateFactories = new ISharedStateFactory[] { null }; - Assert.Fail( "should throw ArgumentException" ); - } - catch (ArgumentException) - { } - - try - { - ssap = new SharedStateAwareProcessor( null, Int32.MaxValue ); - Assert.Fail( "should throw ArgumentException" ); - } - catch (ArgumentException) - { } - - try - { - ssap = new SharedStateAwareProcessor( new ISharedStateFactory[0], Int32.MaxValue ); - Assert.Fail( "should throw ArgumentException" ); - } - catch (ArgumentException) - { } - - try - { - ssap = new SharedStateAwareProcessor( new ISharedStateFactory[] { null }, Int32.MaxValue ); - Assert.Fail( "should throw ArgumentException" ); - } - catch (ArgumentException) - { } } - [Test] - public void BeforeInitializationIsNoOp() + try + { + ssap.SharedStateFactories = new ISharedStateFactory[0]; + Assert.Fail("should throw ArgumentException"); + } + catch (ArgumentException) { - SharedStateAwareProcessor ssap = new SharedStateAwareProcessor(); - object res = ssap.PostProcessBeforeInitialization( this, null ); - Assert.AreSame( this, res ); } - [Test] - public void IgnoresAlreadyPopulatedState() + try + { + ssap.SharedStateFactories = new ISharedStateFactory[] { null }; + Assert.Fail("should throw ArgumentException"); + } + catch (ArgumentException) { - DefaultListableObjectFactory of = new DefaultListableObjectFactory(); - - ISharedStateFactory ssf1 = A.Fake(); - ISharedStateAware ssa = A.Fake(); - - SharedStateAwareProcessor ssap = new SharedStateAwareProcessor(); - ssap.SharedStateFactories = new ISharedStateFactory[] {ssf1}; - of.RegisterSingleton("ssap", ssap); - - // preset SharedState - ssap must ignore it - A.CallTo(() => ssa.SharedState).Returns(new Hashtable()); - - ssap.PostProcessBeforeInitialization(ssa, "myPage"); - - A.CallTo(ssa).Where(x => x.Method.Name == "set_SharedState").MustNotHaveHappened(); } - [Test] - public void ProbesSharedStateFactories() + try { - DefaultListableObjectFactory of = new DefaultListableObjectFactory(); + ssap = new SharedStateAwareProcessor(null, Int32.MaxValue); + Assert.Fail("should throw ArgumentException"); + } + catch (ArgumentException) + { + } - ISharedStateFactory ssf1 = A.Fake(); - ISharedStateFactory ssf2 = A.Fake(); - ISharedStateFactory ssf3 = A.Fake(); - ISharedStateFactory ssf4 = A.Fake(); - IDictionary ssf3ProvidedState = new Hashtable(); + try + { + ssap = new SharedStateAwareProcessor(new ISharedStateFactory[0], Int32.MaxValue); + Assert.Fail("should throw ArgumentException"); + } + catch (ArgumentException) + { + } - SharedStateAwareProcessor ssap = new SharedStateAwareProcessor(); - ssap.SharedStateFactories = new ISharedStateFactory[] {ssf1, ssf2, ssf3, ssf4}; - of.RegisterSingleton("ssap", ssap); - - ISharedStateAware ssa = A.Fake(); - - // Ensure we iterate over configured SharedStateFactories until - // the first provider is found that - // a) true == provider.CanProvideState( instance, name ) - // b) null != provider.GetSharedState( instance, name ) - - A.CallTo(() => ssa.SharedState).Returns(null).Once(); - A.CallTo(() => ssf1.CanProvideState(ssa, "pageName")).Returns(false).Once(); - A.CallTo(() => ssf2.CanProvideState(ssa, "pageName")).Returns(true).Once(); - A.CallTo(() => ssf2.GetSharedStateFor(ssa, "pageName")).Returns(null); - A.CallTo(() => ssf3.CanProvideState(ssa, "pageName")).Returns(true).Once(); - A.CallTo(() => ssf3.GetSharedStateFor(ssa, "pageName")).Returns(ssf3ProvidedState).Once(); - - ssap.PostProcessBeforeInitialization(ssa, "pageName"); - - Assert.That(Equals(ssa.SharedState, ssf3ProvidedState)); + try + { + ssap = new SharedStateAwareProcessor(new ISharedStateFactory[] { null }, Int32.MaxValue); + Assert.Fail("should throw ArgumentException"); + } + catch (ArgumentException) + { } } -} \ No newline at end of file + + [Test] + public void BeforeInitializationIsNoOp() + { + SharedStateAwareProcessor ssap = new SharedStateAwareProcessor(); + object res = ssap.PostProcessBeforeInitialization(this, null); + Assert.AreSame(this, res); + } + + [Test] + public void IgnoresAlreadyPopulatedState() + { + DefaultListableObjectFactory of = new DefaultListableObjectFactory(); + + ISharedStateFactory ssf1 = A.Fake(); + ISharedStateAware ssa = A.Fake(); + + SharedStateAwareProcessor ssap = new SharedStateAwareProcessor(); + ssap.SharedStateFactories = new ISharedStateFactory[] { ssf1 }; + of.RegisterSingleton("ssap", ssap); + + // preset SharedState - ssap must ignore it + A.CallTo(() => ssa.SharedState).Returns(new Hashtable()); + + ssap.PostProcessBeforeInitialization(ssa, "myPage"); + + A.CallTo(ssa).Where(x => x.Method.Name == "set_SharedState").MustNotHaveHappened(); + } + + [Test] + public void ProbesSharedStateFactories() + { + DefaultListableObjectFactory of = new DefaultListableObjectFactory(); + + ISharedStateFactory ssf1 = A.Fake(); + ISharedStateFactory ssf2 = A.Fake(); + ISharedStateFactory ssf3 = A.Fake(); + ISharedStateFactory ssf4 = A.Fake(); + IDictionary ssf3ProvidedState = new Hashtable(); + + SharedStateAwareProcessor ssap = new SharedStateAwareProcessor(); + ssap.SharedStateFactories = new ISharedStateFactory[] { ssf1, ssf2, ssf3, ssf4 }; + of.RegisterSingleton("ssap", ssap); + + ISharedStateAware ssa = A.Fake(); + + // Ensure we iterate over configured SharedStateFactories until + // the first provider is found that + // a) true == provider.CanProvideState( instance, name ) + // b) null != provider.GetSharedState( instance, name ) + + A.CallTo(() => ssa.SharedState).Returns(null).Once(); + A.CallTo(() => ssf1.CanProvideState(ssa, "pageName")).Returns(false).Once(); + A.CallTo(() => ssf2.CanProvideState(ssa, "pageName")).Returns(true).Once(); + A.CallTo(() => ssf2.GetSharedStateFor(ssa, "pageName")).Returns(null); + A.CallTo(() => ssf3.CanProvideState(ssa, "pageName")).Returns(true).Once(); + A.CallTo(() => ssf3.GetSharedStateFor(ssa, "pageName")).Returns(ssf3ProvidedState).Once(); + + ssap.PostProcessBeforeInitialization(ssa, "pageName"); + + Assert.That(Equals(ssa.SharedState, ssf3ProvidedState)); + } +} diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/SpecialFolderVariableSourceTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/SpecialFolderVariableSourceTests.cs index c555c7a2..238b5ae8 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/SpecialFolderVariableSourceTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/SpecialFolderVariableSourceTests.cs @@ -24,32 +24,31 @@ using NUnit.Framework; #endregion -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Unit tests for the SpecialFolderVariableSource class. +/// +/// Aleksandar Seovic +[TestFixture] +public sealed class SpecialFolderVariableSourceTests { - /// - /// Unit tests for the SpecialFolderVariableSource class. - /// - /// Aleksandar Seovic - [TestFixture] - public sealed class SpecialFolderVariableSourceTests + [Test] + public void TestVariablesResolution() { - [Test] - public void TestVariablesResolution() - { - SpecialFolderVariableSource vs = new SpecialFolderVariableSource(); + SpecialFolderVariableSource vs = new SpecialFolderVariableSource(); - // existing vars - Assert.AreEqual(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), - vs.ResolveVariable("ApplicationData")); - Assert.AreEqual(Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory), - vs.ResolveVariable("desktopDirectory")); - Assert.AreEqual(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), - vs.ResolveVariable("programFiles")); - Assert.AreEqual(Environment.GetFolderPath(Environment.SpecialFolder.Personal), - vs.ResolveVariable("personal")); + // existing vars + Assert.AreEqual(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), + vs.ResolveVariable("ApplicationData")); + Assert.AreEqual(Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory), + vs.ResolveVariable("desktopDirectory")); + Assert.AreEqual(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), + vs.ResolveVariable("programFiles")); + Assert.AreEqual(Environment.GetFolderPath(Environment.SpecialFolder.Personal), + vs.ResolveVariable("personal")); - // non-existant variable - Assert.IsNull(vs.ResolveVariable("dummy")); - } + // non-existant variable + Assert.IsNull(vs.ResolveVariable("dummy")); } -} +} \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/TypeAliasConfigurerTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/TypeAliasConfigurerTests.cs index 8cfc68d8..8e576402 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/TypeAliasConfigurerTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/TypeAliasConfigurerTests.cs @@ -19,9 +19,7 @@ #endregion using System.Collections; - using FakeItEasy; - using NUnit.Framework; using Spring.Collections; using Spring.Context.Support; @@ -29,142 +27,136 @@ using Spring.Core.TypeResolution; using Spring.Util; using Spring.Context; -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Unit tests for the TypeAliasConfigurer class +/// +/// Mark Pollack +[TestFixture] +public class TypeAliasConfigurerTests { - /// - /// Unit tests for the TypeAliasConfigurer class - /// - /// Mark Pollack - [TestFixture] - public class TypeAliasConfigurerTests + private IConfigurableListableObjectFactory factory; + + [SetUp] + public void SetUp() { - private IConfigurableListableObjectFactory factory; + factory = A.Fake(); + } - [SetUp] - public void SetUp() - { - factory = A.Fake(); - } + [Test] + public void Serialization() + { + IDictionary typeAliases = new Hashtable(); + typeAliases.Add("LinkedList", typeof(LinkedList).AssemblyQualifiedName); - [Test] - public void Serialization() - { - IDictionary typeAliases = new Hashtable(); - typeAliases.Add("LinkedList", typeof(LinkedList).AssemblyQualifiedName); + TypeAliasConfigurer typeAliasConfigurer = new TypeAliasConfigurer(); + typeAliasConfigurer.TypeAliases = typeAliases; - TypeAliasConfigurer typeAliasConfigurer = new TypeAliasConfigurer(); - typeAliasConfigurer.TypeAliases = typeAliases; + typeAliasConfigurer.Order = 1; - typeAliasConfigurer.Order = 1; + SerializationTestUtils.SerializeAndDeserialize(typeAliasConfigurer); + } - SerializationTestUtils.SerializeAndDeserialize(typeAliasConfigurer); - } + [Test] + public void UseInvalidTypeForDictionaryValue() + { + IDictionary typeAliases = new Hashtable(); + typeAliases.Add("LinkedList", new LinkedList()); - [Test] - public void UseInvalidTypeForDictionaryValue() - { - IDictionary typeAliases = new Hashtable(); - typeAliases.Add("LinkedList", new LinkedList()); + TypeAliasConfigurer typeAliasConfigurer = new TypeAliasConfigurer(); + typeAliasConfigurer.TypeAliases = typeAliases; - TypeAliasConfigurer typeAliasConfigurer = new TypeAliasConfigurer(); - typeAliasConfigurer.TypeAliases = typeAliases; + Assert.Throws(() => typeAliasConfigurer.PostProcessObjectFactory(factory)); + } - Assert.Throws(() => typeAliasConfigurer.PostProcessObjectFactory(factory)); - } + [Test] + public void UseNonResolvableTypeForDictionaryValue() + { + IDictionary typeAliases = new Hashtable(); + typeAliases.Add("LinkedList", "Spring.Collections.LinkkkedList"); - [Test] - public void UseNonResolvableTypeForDictionaryValue() - { - IDictionary typeAliases = new Hashtable(); - typeAliases.Add("LinkedList", "Spring.Collections.LinkkkedList"); + TypeAliasConfigurer typeAliasConfigurer = new TypeAliasConfigurer(); + typeAliasConfigurer.TypeAliases = typeAliases; - TypeAliasConfigurer typeAliasConfigurer = new TypeAliasConfigurer(); - typeAliasConfigurer.TypeAliases = typeAliases; + Assert.Throws(() => typeAliasConfigurer.PostProcessObjectFactory(factory)); + } - Assert.Throws(() => typeAliasConfigurer.PostProcessObjectFactory(factory)); - } + [Test] + public void SunnyDayScenarioUsingType() + { + IDictionary typeAliases = new Hashtable(); + typeAliases.Add("LinkedList", typeof(LinkedList)); - [Test] - public void SunnyDayScenarioUsingType() - { - IDictionary typeAliases = new Hashtable(); - typeAliases.Add("LinkedList", typeof(LinkedList)); + CreateConfigurerAndTestLinkedList(typeAliases); + } - CreateConfigurerAndTestLinkedList(typeAliases); - } + [Test] + public void SunnyDayScenarioUsingTypeString() + { + IDictionary typeAliases = new Hashtable(); + typeAliases.Add("LinkedList", "Spring.Collections.LinkedList, Spring.Core"); + CreateConfigurerAndTestLinkedList(typeAliases); + } - [Test] - public void SunnyDayScenarioUsingTypeString() - { - IDictionary typeAliases = new Hashtable(); - typeAliases.Add("LinkedList", "Spring.Collections.LinkedList, Spring.Core"); - CreateConfigurerAndTestLinkedList(typeAliases); - } + [Test] + public void WithinApplicationContext() + { + IApplicationContext ctx = new XmlApplicationContext("file://Spring/Objects/Factory/Config/TypeAliases.xml"); - [Test] - public void WithinApplicationContext() - { - IApplicationContext ctx = new XmlApplicationContext("file://Spring/Objects/Factory/Config/TypeAliases.xml"); + object obj1 = ctx.GetObject("testObject1"); + Assert.IsNotNull(obj1); + Assert.AreEqual(typeof(TestObject), obj1.GetType()); - object obj1 = ctx.GetObject("testObject1"); - Assert.IsNotNull(obj1); - Assert.AreEqual(typeof(TestObject), obj1.GetType()); + object obj2 = ctx.GetObject("testObject2"); + Assert.IsNotNull(obj2); + Assert.AreEqual(typeof(TestObject), obj2.GetType()); - object obj2 = ctx.GetObject("testObject2"); - Assert.IsNotNull(obj2); - Assert.AreEqual(typeof(TestObject), obj2.GetType()); + object obj3 = ctx.GetObject("testObject3"); + Assert.IsNotNull(obj3); + Assert.AreEqual(typeof(TestObject), obj3.GetType()); + Assert.AreEqual("Bruno", ((TestObject) obj3).Name); + Assert.AreEqual(26, ((TestObject) obj3).Age); - object obj3 = ctx.GetObject("testObject3"); - Assert.IsNotNull(obj3); - Assert.AreEqual(typeof(TestObject), obj3.GetType()); - Assert.AreEqual("Bruno", ((TestObject)obj3).Name); - Assert.AreEqual(26, ((TestObject)obj3).Age); + // SPRNET-1119 + object obj4 = ctx.GetObject("testObject4"); + Assert.IsNotNull(obj4); + Assert.AreEqual(typeof(TestObject), obj4.GetType()); + Assert.AreEqual("Bruno", ((TestObject) obj4).Name); + Assert.AreEqual(30, ((TestObject) obj4).Age); - // SPRNET-1119 - object obj4 = ctx.GetObject("testObject4"); - Assert.IsNotNull(obj4); - Assert.AreEqual(typeof(TestObject), obj4.GetType()); - Assert.AreEqual("Bruno", ((TestObject)obj4).Name); - Assert.AreEqual(30, ((TestObject)obj4).Age); + object obj6 = ctx.GetObject("testObject6"); + Assert.IsNotNull(obj6); + Assert.AreEqual(typeof(TestObject), obj6.GetType()); + Assert.AreEqual("name from section", ((TestObject) obj6).Name); + Assert.AreEqual(27, ((TestObject) obj6).Age); + object obj5 = ctx.GetObject("testObject5"); + Assert.IsNotNull(obj5); + Assert.AreEqual(typeof(TestObject), obj5.GetType()); + Assert.AreEqual("overide-name", ((TestObject) obj5).Name); + Assert.AreEqual(26, ((TestObject) obj5).Age); - object obj6 = ctx.GetObject("testObject6"); - Assert.IsNotNull(obj6); - Assert.AreEqual(typeof(TestObject), obj6.GetType()); - Assert.AreEqual("name from section", ((TestObject)obj6).Name); - Assert.AreEqual(27, ((TestObject)obj6).Age); + object vpc = ctx.GetObject("vpc"); + Assert.IsNotNull(vpc); + Assert.AreEqual(typeof(VariablePlaceholderConfigurer), vpc.GetType()); + } + private void CreateConfigurerAndTestLinkedList(IDictionary typeAliases) + { + TypeAliasConfigurer typeAliasConfigurer = new TypeAliasConfigurer(); + typeAliasConfigurer.TypeAliases = typeAliases; - object obj5 = ctx.GetObject("testObject5"); - Assert.IsNotNull(obj5); - Assert.AreEqual(typeof(TestObject), obj5.GetType()); - Assert.AreEqual("overide-name", ((TestObject)obj5).Name); - Assert.AreEqual(26, ((TestObject)obj5).Age); + typeAliasConfigurer.Order = 1; - object vpc = ctx.GetObject("vpc"); - Assert.IsNotNull(vpc); - Assert.AreEqual(typeof(VariablePlaceholderConfigurer), vpc.GetType()); + typeAliasConfigurer.PostProcessObjectFactory(factory); + //todo investigate mocking the typeregistry, for now ask the actual one for information. + Assert.IsTrue(TypeRegistry.ContainsAlias("LinkedList"), + "TypeAliasConfigurer did not register a type alias with the TypeRegistry"); - } - - private void CreateConfigurerAndTestLinkedList(IDictionary typeAliases) - { - TypeAliasConfigurer typeAliasConfigurer = new TypeAliasConfigurer(); - typeAliasConfigurer.TypeAliases = typeAliases; - - typeAliasConfigurer.Order = 1; - - - typeAliasConfigurer.PostProcessObjectFactory(factory); - - //todo investigate mocking the typeregistry, for now ask the actual one for information. - Assert.IsTrue(TypeRegistry.ContainsAlias("LinkedList"), - "TypeAliasConfigurer did not register a type alias with the TypeRegistry"); - - Type linkedListType = TypeRegistry.ResolveType("LinkedList"); - Assert.IsTrue(linkedListType.Equals(typeof(LinkedList)), "Incorrect type resolved."); - Assert.AreEqual(1,typeAliasConfigurer.Order); - } + Type linkedListType = TypeRegistry.ResolveType("LinkedList"); + Assert.IsTrue(linkedListType.Equals(typeof(LinkedList)), "Incorrect type resolved."); + Assert.AreEqual(1, typeAliasConfigurer.Order); } } diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/TypedStringValueTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/TypedStringValueTests.cs index 2f4bed8b..b352ac0b 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/TypedStringValueTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/TypedStringValueTests.cs @@ -25,119 +25,117 @@ using Spring.Util; #endregion -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Unit tests for the TypedStringValue class. +/// +/// Juergen Hoeller +/// Rick Evans (.NET) +[TestFixture] +public sealed class TypedStringValueTests { - /// - /// Unit tests for the TypedStringValue class. - /// - /// Juergen Hoeller - /// Rick Evans (.NET) - [TestFixture] - public sealed class TypedStringValueTests - { - [Test] - public void Instantiation() - { - string expectedNow = DateTime.Now.ToShortDateString(); - - TypedStringValue tsv = new TypedStringValue(expectedNow, typeof (DateTime)); - Assert.AreEqual(expectedNow, tsv.Value); - Assert.AreEqual(typeof (DateTime), tsv.TargetType); - - tsv = new TypedStringValue(expectedNow); - Assert.AreEqual(expectedNow, tsv.Value); + [Test] + public void Instantiation() + { + string expectedNow = DateTime.Now.ToShortDateString(); - tsv = new TypedStringValue(expectedNow, typeof(DateTime).FullName); - Assert.AreEqual(expectedNow, tsv.Value); - Assert.AreEqual(typeof(DateTime).FullName, tsv.TargetTypeName); + TypedStringValue tsv = new TypedStringValue(expectedNow, typeof(DateTime)); + Assert.AreEqual(expectedNow, tsv.Value); + Assert.AreEqual(typeof(DateTime), tsv.TargetType); - } + tsv = new TypedStringValue(expectedNow); + Assert.AreEqual(expectedNow, tsv.Value); - [Test] - public void InstantiationWithNullType() - { - Assert.Throws(() => new TypedStringValue(string.Empty, (Type) null)); - } + tsv = new TypedStringValue(expectedNow, typeof(DateTime).FullName); + Assert.AreEqual(expectedNow, tsv.Value); + Assert.AreEqual(typeof(DateTime).FullName, tsv.TargetTypeName); + } - [Test] - public void InstantiationWithNullTypeName() - { - Assert.Throws(() => new TypedStringValue(string.Empty, (string) null)); - } + [Test] + public void InstantiationWithNullType() + { + Assert.Throws(() => new TypedStringValue(string.Empty, (Type) null)); + } - [Test] - public void InstantiationWithEmptyTypeName() - { - Assert.Throws(() => new TypedStringValue(string.Empty, " ")); - } + [Test] + public void InstantiationWithNullTypeName() + { + Assert.Throws(() => new TypedStringValue(string.Empty, (string) null)); + } - [Test] - public void SetTargetTypePropertyToNullType() - { - TypedStringValue tsv = new TypedStringValue(string.Empty, typeof(DateTime)); - Assert.Throws(() => tsv.TargetType = null); - } + [Test] + public void InstantiationWithEmptyTypeName() + { + Assert.Throws(() => new TypedStringValue(string.Empty, " ")); + } - [Test] - public void SetTargetTypeNamePropertyToEmptyString() - { - TypedStringValue tsv = new TypedStringValue(string.Empty, typeof(DateTime)); - Assert.Throws(() => tsv.TargetTypeName = " "); - } + [Test] + public void SetTargetTypePropertyToNullType() + { + TypedStringValue tsv = new TypedStringValue(string.Empty, typeof(DateTime)); + Assert.Throws(() => tsv.TargetType = null); + } - [Test] - public void IsSerializable() - { - Assert.IsTrue(SerializationTestUtils.IsSerializable(new TypedStringValue()), - "Must be marked as [Serializable]."); - } + [Test] + public void SetTargetTypeNamePropertyToEmptyString() + { + TypedStringValue tsv = new TypedStringValue(string.Empty, typeof(DateTime)); + Assert.Throws(() => tsv.TargetTypeName = " "); + } - [Test] - public void Serialization() - { - TypedStringValue value = new TypedStringValue(); - Type expectedType = typeof(string); - value.TargetType = expectedType; - const string expectedValue = "rilo-kiley"; - value.Value = expectedValue; + [Test] + public void IsSerializable() + { + Assert.IsTrue(SerializationTestUtils.IsSerializable(new TypedStringValue()), + "Must be marked as [Serializable]."); + } - object foo = SerializationTestUtils.SerializeAndDeserialize(value); - Assert.IsNotNull(foo, "Serialization roundtrip must never result in null."); - TypedStringValue deser = foo as TypedStringValue; - Assert.IsNotNull(deser, - "Serialization roundtrip yielded the wrong Type of object."); - Assert.AreEqual(expectedType, deser.TargetType, - "Serialization roundtrip yielded the wrong TargetType."); - Assert.AreEqual(expectedValue, deser.Value, - "Serialization roundtrip yielded the wrong Value."); - } + [Test] + public void Serialization() + { + TypedStringValue value = new TypedStringValue(); + Type expectedType = typeof(string); + value.TargetType = expectedType; + const string expectedValue = "rilo-kiley"; + value.Value = expectedValue; - [Test] - public void HasTargetType() - { - TypedStringValue tsv = new TypedStringValue(string.Empty, typeof(DateTime)); - Assert.IsTrue(tsv.HasTargetType); - } + object foo = SerializationTestUtils.SerializeAndDeserialize(value); + Assert.IsNotNull(foo, "Serialization roundtrip must never result in null."); + TypedStringValue deser = foo as TypedStringValue; + Assert.IsNotNull(deser, + "Serialization roundtrip yielded the wrong Type of object."); + Assert.AreEqual(expectedType, deser.TargetType, + "Serialization roundtrip yielded the wrong TargetType."); + Assert.AreEqual(expectedValue, deser.Value, + "Serialization roundtrip yielded the wrong Value."); + } - [Test] - public void HasTargetTypeReturnsFalseWhenTargetTypeNotResolved() - { - TypedStringValue tsv = new TypedStringValue(string.Empty, typeof(DateTime).FullName); - Assert.IsFalse(tsv.HasTargetType); + [Test] + public void HasTargetType() + { + TypedStringValue tsv = new TypedStringValue(string.Empty, typeof(DateTime)); + Assert.IsTrue(tsv.HasTargetType); + } - tsv = new TypedStringValue(string.Empty, typeof(DateTime)); - Assert.IsTrue(tsv.HasTargetType); - tsv.TargetTypeName = typeof(DateTime).FullName; - Assert.IsFalse(tsv.HasTargetType); - } + [Test] + public void HasTargetTypeReturnsFalseWhenTargetTypeNotResolved() + { + TypedStringValue tsv = new TypedStringValue(string.Empty, typeof(DateTime).FullName); + Assert.IsFalse(tsv.HasTargetType); - [Test] - public void ResolveTargetType() - { - TypedStringValue tsv = new TypedStringValue(string.Empty, typeof(DateTime).FullName); - Assert.IsFalse(tsv.HasTargetType); - Assert.AreEqual(typeof(DateTime), tsv.ResolveTargetType()); - Assert.IsTrue(tsv.HasTargetType); - } - } -} \ No newline at end of file + tsv = new TypedStringValue(string.Empty, typeof(DateTime)); + Assert.IsTrue(tsv.HasTargetType); + tsv.TargetTypeName = typeof(DateTime).FullName; + Assert.IsFalse(tsv.HasTargetType); + } + + [Test] + public void ResolveTargetType() + { + TypedStringValue tsv = new TypedStringValue(string.Empty, typeof(DateTime).FullName); + Assert.IsFalse(tsv.HasTargetType); + Assert.AreEqual(typeof(DateTime), tsv.ResolveTargetType()); + Assert.IsTrue(tsv.HasTargetType); + } +} diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/VariableAccessorTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/VariableAccessorTests.cs index 60fb0c97..740c67a6 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/VariableAccessorTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/VariableAccessorTests.cs @@ -21,169 +21,166 @@ #region Imports using System.Globalization; - using NUnit.Framework; #endregion -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// Tests functionality. +/// +/// Erich Eichinger +[TestFixture] +public class VariableAccessorTests { - /// - /// Tests functionality. - /// - /// Erich Eichinger - [TestFixture] - public class VariableAccessorTests + private static readonly Guid TESTGUID = Guid.NewGuid(); + private static readonly Guid TESTGUID_DEFAULT = Guid.NewGuid(); + + private static readonly DateTime TESTDATETIME = new DateTime(2007, 07, 06, 11, 12, 13); + private static readonly DateTime TESTDATETIME_DEFAULT = TESTDATETIME.AddDays(-1); + + private readonly IVariableSource _testVariableSource = new DictionaryVariableSource(null, true) + .Add("ValidString", "String") + .Add("EmptyString", "") + .Add("ValidChar", "c") + .Add("InvalidChar", "12") + .Add("ValidBoolean", "true") + .Add("InvalidBoolean", "") + .Add("ValidByte", "1") + .Add("InvalidByte", "") + .Add("ValidInt16", "1") + .Add("InvalidInt16", "") + .Add("ValidInt32", "1") + .Add("InvalidInt32", "") + .Add("ValidInt64", "1") + .Add("InvalidInt64", "") + .Add("ValidFloat", "1") + .Add("InvalidFloat", "") + .Add("ValidDouble", "1") + .Add("InvalidDouble", "") + .Add("ValidDecimal", "1") + .Add("InvalidDecimal", "") + .Add("ValidGuid", TESTGUID.ToString()) + .Add("InvalidGuid", "") + .Add("ValidDateTime", TESTDATETIME.ToString(CultureInfo.InvariantCulture)) + .Add("InvalidDateTime", "blabla") + .Add("ValidDateTimeUtcRoundtripFormatted", TESTDATETIME.ToUniversalTime().ToString("u")); + + [Test] + public void AcceptsNullVariableSource() { - private static readonly Guid TESTGUID = Guid.NewGuid(); - private static readonly Guid TESTGUID_DEFAULT = Guid.NewGuid(); - - private static readonly DateTime TESTDATETIME = new DateTime(2007, 07, 06, 11, 12, 13); - private static readonly DateTime TESTDATETIME_DEFAULT = TESTDATETIME.AddDays(-1); - - private readonly IVariableSource _testVariableSource = new DictionaryVariableSource(null, true) - .Add("ValidString", "String") - .Add("EmptyString", "") - .Add("ValidChar", "c") - .Add("InvalidChar", "12") - .Add("ValidBoolean", "true") - .Add("InvalidBoolean", "") - .Add("ValidByte", "1") - .Add("InvalidByte", "") - .Add("ValidInt16", "1") - .Add("InvalidInt16", "") - .Add("ValidInt32", "1") - .Add("InvalidInt32", "") - .Add("ValidInt64", "1") - .Add("InvalidInt64", "") - .Add("ValidFloat", "1") - .Add("InvalidFloat", "") - .Add("ValidDouble", "1") - .Add("InvalidDouble", "") - .Add("ValidDecimal", "1") - .Add("InvalidDecimal", "") - .Add("ValidGuid", TESTGUID.ToString()) - .Add("InvalidGuid", "") - .Add("ValidDateTime", TESTDATETIME.ToString(CultureInfo.InvariantCulture)) - .Add("InvalidDateTime", "blabla") - .Add("ValidDateTimeUtcRoundtripFormatted", TESTDATETIME.ToUniversalTime().ToString("u")) - ; - - [Test] - public void AcceptsNullVariableSource() - { - VariableAccessor va = new VariableAccessor(null); - Assert.AreEqual("default", va.GetString("somekey", "default")); - } - - [Test] - public void GetString() - { - VariableAccessor va = new VariableAccessor(_testVariableSource); - Assert.AreEqual("String", va.GetString("ValidString", "DefaultString")); - Assert.AreEqual("DefaultString", va.GetString("NonExistingString", "DefaultString")); - } - - [Test] - public void GetStringIgnoresEmptyString() - { - VariableAccessor va = new VariableAccessor(_testVariableSource); - Assert.AreEqual("DefaultString", va.GetString("EmptyString", "DefaultString")); - } - - [Test] - public void GetChar() - { - VariableAccessor va = new VariableAccessor(_testVariableSource); - Assert.AreEqual('c', va.GetChar("ValidChar", 'a')); - Assert.AreEqual('a', va.GetChar("InvalidChar", 'a', false)); - Assert.Throws(() => va.GetChar("InvalidChar", 'a', true)); - } - - [Test] - public void GetBoolean() - { - VariableAccessor va = new VariableAccessor(_testVariableSource); - Assert.AreEqual(true, va.GetBoolean("ValidBoolean", false)); - Assert.AreEqual(true, va.GetBoolean("InvalidBoolean", true, false)); - } - - [Test] - public void GetByte() - { - VariableAccessor va = new VariableAccessor(_testVariableSource); - Assert.AreEqual((byte) 1, va.GetByte("ValidByte", 2)); - Assert.AreEqual((byte) 2, va.GetByte("InvalidByte", 2, false)); - } - - [Test] - public void GetInt16() - { - VariableAccessor va = new VariableAccessor(_testVariableSource); - Assert.AreEqual((short) 1, va.GetInt16("ValidInt16", 2)); - Assert.AreEqual((short) 2, va.GetInt16("InvalidInt16", 2, false)); - va.GetInt16("InvalidInt16", 2, true); - } - - [Test] - public void GetInt32() - { - VariableAccessor va = new VariableAccessor(_testVariableSource); - Assert.AreEqual((int) 1, va.GetInt32("ValidInt32", 2)); - Assert.AreEqual((int) 2, va.GetInt32("InvalidInt32", 2, false)); - } - - [Test] - public void GetInt64() - { - VariableAccessor va = new VariableAccessor(_testVariableSource); - Assert.AreEqual((long) 1, va.GetInt64("ValidInt64", 2)); - Assert.AreEqual((long) 2, va.GetInt64("InvalidInt64", 2, false)); - } - - [Test] - public void GetFloat() - { - VariableAccessor va = new VariableAccessor(_testVariableSource); - Assert.AreEqual((float) 1, va.GetFloat("ValidFloat", 2.0f)); - Assert.AreEqual((float) 2, va.GetFloat("InvalidFloat", 2.0f, false)); - va.GetFloat("InvalidFloat", 2, true); - } - - [Test] - public void GetDouble() - { - VariableAccessor va = new VariableAccessor(_testVariableSource); - Assert.AreEqual((double)1, va.GetDouble("ValidDouble", 2.0)); - Assert.AreEqual((double)2, va.GetDouble("InvalidDouble", 2.0, false)); - va.GetDouble("InvalidDouble", 2, true); - } - - [Test] - public void GetDecimal() - { - VariableAccessor va = new VariableAccessor(_testVariableSource); - Assert.AreEqual((decimal)1, va.GetDecimal("ValidDecimal", 2.0m)); - Assert.AreEqual((decimal)2, va.GetDecimal("InvalidDecimal", 2.0m, false)); - va.GetDecimal("InvalidDecimal", 2, true); - } - - [Test] - public void GetGuid() - { - VariableAccessor va = new VariableAccessor(_testVariableSource); - Assert.AreEqual(TESTGUID, va.GetGuid("ValidGuid", TESTGUID_DEFAULT)); - Assert.AreEqual(TESTGUID_DEFAULT, va.GetGuid("InvalidGuid", TESTGUID_DEFAULT, false)); - } - - [Test] - public void GetDateTime() - { - VariableAccessor va = new VariableAccessor(_testVariableSource); - Assert.AreEqual(TESTDATETIME, va.GetDateTime("ValidDateTime", null, TESTDATETIME_DEFAULT)); - Assert.AreEqual(TESTDATETIME.ToUniversalTime(), va.GetDateTime("ValidDateTimeUtcRoundtripFormatted", "u", TESTDATETIME_DEFAULT)); - Assert.AreEqual(TESTDATETIME_DEFAULT, va.GetDateTime("InvalidDateTime", null, TESTDATETIME_DEFAULT, false)); - Assert.Throws(() => va.GetDateTime("InvalidDateTime", null, TESTDATETIME_DEFAULT, true)); - } + VariableAccessor va = new VariableAccessor(null); + Assert.AreEqual("default", va.GetString("somekey", "default")); } -} \ No newline at end of file + + [Test] + public void GetString() + { + VariableAccessor va = new VariableAccessor(_testVariableSource); + Assert.AreEqual("String", va.GetString("ValidString", "DefaultString")); + Assert.AreEqual("DefaultString", va.GetString("NonExistingString", "DefaultString")); + } + + [Test] + public void GetStringIgnoresEmptyString() + { + VariableAccessor va = new VariableAccessor(_testVariableSource); + Assert.AreEqual("DefaultString", va.GetString("EmptyString", "DefaultString")); + } + + [Test] + public void GetChar() + { + VariableAccessor va = new VariableAccessor(_testVariableSource); + Assert.AreEqual('c', va.GetChar("ValidChar", 'a')); + Assert.AreEqual('a', va.GetChar("InvalidChar", 'a', false)); + Assert.Throws(() => va.GetChar("InvalidChar", 'a', true)); + } + + [Test] + public void GetBoolean() + { + VariableAccessor va = new VariableAccessor(_testVariableSource); + Assert.AreEqual(true, va.GetBoolean("ValidBoolean", false)); + Assert.AreEqual(true, va.GetBoolean("InvalidBoolean", true, false)); + } + + [Test] + public void GetByte() + { + VariableAccessor va = new VariableAccessor(_testVariableSource); + Assert.AreEqual((byte) 1, va.GetByte("ValidByte", 2)); + Assert.AreEqual((byte) 2, va.GetByte("InvalidByte", 2, false)); + } + + [Test] + public void GetInt16() + { + VariableAccessor va = new VariableAccessor(_testVariableSource); + Assert.AreEqual((short) 1, va.GetInt16("ValidInt16", 2)); + Assert.AreEqual((short) 2, va.GetInt16("InvalidInt16", 2, false)); + va.GetInt16("InvalidInt16", 2, true); + } + + [Test] + public void GetInt32() + { + VariableAccessor va = new VariableAccessor(_testVariableSource); + Assert.AreEqual((int) 1, va.GetInt32("ValidInt32", 2)); + Assert.AreEqual((int) 2, va.GetInt32("InvalidInt32", 2, false)); + } + + [Test] + public void GetInt64() + { + VariableAccessor va = new VariableAccessor(_testVariableSource); + Assert.AreEqual((long) 1, va.GetInt64("ValidInt64", 2)); + Assert.AreEqual((long) 2, va.GetInt64("InvalidInt64", 2, false)); + } + + [Test] + public void GetFloat() + { + VariableAccessor va = new VariableAccessor(_testVariableSource); + Assert.AreEqual((float) 1, va.GetFloat("ValidFloat", 2.0f)); + Assert.AreEqual((float) 2, va.GetFloat("InvalidFloat", 2.0f, false)); + va.GetFloat("InvalidFloat", 2, true); + } + + [Test] + public void GetDouble() + { + VariableAccessor va = new VariableAccessor(_testVariableSource); + Assert.AreEqual((double) 1, va.GetDouble("ValidDouble", 2.0)); + Assert.AreEqual((double) 2, va.GetDouble("InvalidDouble", 2.0, false)); + va.GetDouble("InvalidDouble", 2, true); + } + + [Test] + public void GetDecimal() + { + VariableAccessor va = new VariableAccessor(_testVariableSource); + Assert.AreEqual((decimal) 1, va.GetDecimal("ValidDecimal", 2.0m)); + Assert.AreEqual((decimal) 2, va.GetDecimal("InvalidDecimal", 2.0m, false)); + va.GetDecimal("InvalidDecimal", 2, true); + } + + [Test] + public void GetGuid() + { + VariableAccessor va = new VariableAccessor(_testVariableSource); + Assert.AreEqual(TESTGUID, va.GetGuid("ValidGuid", TESTGUID_DEFAULT)); + Assert.AreEqual(TESTGUID_DEFAULT, va.GetGuid("InvalidGuid", TESTGUID_DEFAULT, false)); + } + + [Test] + public void GetDateTime() + { + VariableAccessor va = new VariableAccessor(_testVariableSource); + Assert.AreEqual(TESTDATETIME, va.GetDateTime("ValidDateTime", null, TESTDATETIME_DEFAULT)); + Assert.AreEqual(TESTDATETIME.ToUniversalTime(), va.GetDateTime("ValidDateTimeUtcRoundtripFormatted", "u", TESTDATETIME_DEFAULT)); + Assert.AreEqual(TESTDATETIME_DEFAULT, va.GetDateTime("InvalidDateTime", null, TESTDATETIME_DEFAULT, false)); + Assert.Throws(() => va.GetDateTime("InvalidDateTime", null, TESTDATETIME_DEFAULT, true)); + } +} diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/VariablePlaceholderConfigurerTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/VariablePlaceholderConfigurerTests.cs index 2054e022..4321a3d0 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/VariablePlaceholderConfigurerTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/VariablePlaceholderConfigurerTests.cs @@ -19,293 +19,283 @@ #endregion using System.Collections; - using FakeItEasy; - using NUnit.Framework; - using Spring.Context.Support; using Spring.Objects.Factory.Support; -namespace Spring.Objects.Factory.Config +namespace Spring.Objects.Factory.Config; + +/// +/// This class contains tests for +/// +/// Mark Pollack +[TestFixture] +public class VariablePlaceholderConfigurerTests { - /// - /// This class contains tests for - /// - /// Mark Pollack - [TestFixture] - public class VariablePlaceholderConfigurerTests + [SetUp] + public void SetUp() { - [SetUp] - public void SetUp() + } + + [Test] + public void ThrowsOnMissingVariableSources() + { + StaticApplicationContext ac = new StaticApplicationContext(); + VariablePlaceholderConfigurer vphc = new VariablePlaceholderConfigurer(); + + try { + vphc.PostProcessObjectFactory(ac.ObjectFactory); + Assert.Fail("Expected ArgumentException not thrown."); } - - [Test] - public void ThrowsOnMissingVariableSources() + catch (ArgumentException) { - StaticApplicationContext ac = new StaticApplicationContext(); - VariablePlaceholderConfigurer vphc = new VariablePlaceholderConfigurer(); - - try - { - vphc.PostProcessObjectFactory(ac.ObjectFactory); - Assert.Fail("Expected ArgumentException not thrown."); - } - catch (ArgumentException) - { - } - } - - - [Test] - public void ThrowsOnInvalidVariableSourcesElement() - { - StaticApplicationContext ac = new StaticApplicationContext(); - VariablePlaceholderConfigurer vphc = new VariablePlaceholderConfigurer(); - vphc.VariableSources = new ArrayList(new object[] { new object() }); - - try - { - vphc.PostProcessObjectFactory(ac.ObjectFactory); - Assert.Fail("Expected ArgumentException not thrown."); - } - catch (ArgumentException) - { - } - } - - - [Test] - public void SunnyDay() - { - StaticApplicationContext ac = new StaticApplicationContext(); - - MutablePropertyValues pvs = new MutablePropertyValues(); - pvs.Add("age", "${maxResults}"); - pvs.Add("name", "${name}"); - ac.RegisterSingleton("tb1", typeof(TestObject), pvs); - - IList variableSources = new ArrayList(); - CommandLineArgsVariableSource vs1 = new CommandLineArgsVariableSource( - new string[] { "program.exe", "file.txt", "/name:Aleks Seovic", "/framework:Spring.NET" }); - variableSources.Add(vs1); - - ConfigSectionVariableSource vs2 = new ConfigSectionVariableSource(); - vs2.SectionName = "DaoConfiguration"; - variableSources.Add(vs2); - - - pvs = new MutablePropertyValues(); - pvs.Add("VariableSources", variableSources); - - ac.RegisterSingleton("configurer", typeof(VariablePlaceholderConfigurer), pvs); - ac.Refresh(); - - TestObject tb1 = (TestObject)ac.GetObject("tb1"); - Assert.AreEqual(1000, tb1.Age); - Assert.AreEqual("Aleks Seovic", tb1.Name); - - } - - [Test] - public void UsesCustomVariablePrefixSuffix() - { - StaticApplicationContext ac = new StaticApplicationContext(); - - MutablePropertyValues pvs = new MutablePropertyValues(); - pvs.Add("age", "%[maxResults]%"); - pvs.Add("name", "%[name]%"); - ac.RegisterSingleton("tb1", typeof(TestObject), pvs); - - IList variableSources = new ArrayList(); - variableSources.Add(new DictionaryVariableSource(new string[] { "maxResults", "35", "name", "Erich" })); - - - pvs = new MutablePropertyValues(); - pvs.Add("VariableSources", variableSources); - pvs.Add("PlaceholderPrefix", "%["); - pvs.Add("PlaceholderSuffix", "]%"); - - ac.RegisterSingleton("configurer", typeof(VariablePlaceholderConfigurer), pvs); - ac.Refresh(); - - TestObject tb1 = (TestObject)ac.GetObject("tb1"); - Assert.AreEqual(35, tb1.Age); - Assert.AreEqual("Erich", tb1.Name); - } - - [Test] - public void MultiResolution() - { - DefaultListableObjectFactory of = new DefaultListableObjectFactory(); - MutablePropertyValues pvs = new MutablePropertyValues(); - pvs.Add("Greeting", "Hello ${firstname} ${lastname}!"); - of.RegisterObjectDefinition("tb1", new RootObjectDefinition("typename", null, pvs)); - - IList variableSources = new ArrayList(); - variableSources.Add(new DictionaryVariableSource(new string[] { "firstname", "FirstName" })); - variableSources.Add(new DictionaryVariableSource(new string[] { "lastname", "LastName" })); - VariablePlaceholderConfigurer vphc = new VariablePlaceholderConfigurer(variableSources); - vphc.PostProcessObjectFactory(of); - - RootObjectDefinition rod = (RootObjectDefinition)of.GetObjectDefinition("tb1"); - Assert.AreEqual("Hello FirstName LastName!", rod.PropertyValues.GetPropertyValue("Greeting").Value); - } - - [Test] - public void NestedResolution() - { - DefaultListableObjectFactory of = new DefaultListableObjectFactory(); - MutablePropertyValues pvs = new MutablePropertyValues(); - pvs.Add("NameProperty", "${name}"); - of.RegisterObjectDefinition("tb1", new RootObjectDefinition("typename", null, pvs)); - - IList variableSources = new ArrayList(); - variableSources.Add(new DictionaryVariableSource(new string[] { "name", "${nickname}" })); - variableSources.Add(new DictionaryVariableSource(new string[] { "nickname", "nickname-value" })); - VariablePlaceholderConfigurer vphc = new VariablePlaceholderConfigurer(variableSources); - vphc.PostProcessObjectFactory(of); - - RootObjectDefinition rod = (RootObjectDefinition)of.GetObjectDefinition("tb1"); - Assert.AreEqual("nickname-value", rod.PropertyValues.GetPropertyValue("NameProperty").Value); - } - - [Test] - public void ChainedResolution() - { - StaticApplicationContext ac = new StaticApplicationContext(); - - MutablePropertyValues pvs = new MutablePropertyValues(); - pvs.Add("name", "${name}"); - pvs.Add("nickname", "${nickname}"); - ac.RegisterSingleton("tb1", typeof(TestObject), pvs); - - IList variableSources = new ArrayList(); - variableSources.Add(new DictionaryVariableSource(new string[] { "name", "name-value" })); - variableSources.Add(new DictionaryVariableSource(new string[] { "nickname", "nickname-value" })); - VariablePlaceholderConfigurer vphc = new VariablePlaceholderConfigurer(variableSources); - ac.AddObjectFactoryPostProcessor(vphc); - ac.Refresh(); - - TestObject tb1 = (TestObject)ac.GetObject("tb1"); - Assert.AreEqual("name-value", tb1.Name); - Assert.AreEqual("nickname-value", tb1.Nickname); - } - - [Test] - public void ChainedResolutionWithNullValues() - { - DefaultListableObjectFactory of = new DefaultListableObjectFactory(); - - MutablePropertyValues pvs = new MutablePropertyValues(); - pvs.Add("NameProperty", "${name}"); - pvs.Add("NickNameProperty", "${nickname}"); - of.RegisterObjectDefinition("tb1", new RootObjectDefinition("typename", null, pvs)); - - IList variableSources = new ArrayList(); - variableSources.Add(new DictionaryVariableSource(new string[] { "name", "name-value", "nickname", null })); - variableSources.Add(new DictionaryVariableSource(new string[] { "nickname", "nickname-value" })); - VariablePlaceholderConfigurer vphc = new VariablePlaceholderConfigurer(variableSources); - - vphc.PostProcessObjectFactory(of); - RootObjectDefinition rod = (RootObjectDefinition)of.GetObjectDefinition("tb1"); - Assert.AreEqual("name-value", rod.PropertyValues.GetPropertyValue("NameProperty").Value); - Assert.AreEqual(null, rod.PropertyValues.GetPropertyValue("NickNameProperty").Value); - } - - [Test] - public void WhitespaceHandling() - { - StaticApplicationContext ac = new StaticApplicationContext(); - - MutablePropertyValues pvs = new MutablePropertyValues(); - pvs.Add("name", "${name}"); - pvs.Add("nickname", "${nickname}"); - ac.RegisterSingleton("tb1", typeof(TestObject), pvs); - - IList variableSources = new ArrayList(); - variableSources.Add(new DictionaryVariableSource(new string[] { "name", string.Empty, "nickname", null })); - pvs = new MutablePropertyValues(); - pvs.Add("VariableSources", variableSources); - ac.RegisterSingleton("configurer", typeof(VariablePlaceholderConfigurer), pvs); - ac.Refresh(); - - TestObject tb1 = (TestObject)ac.GetObject("tb1"); - Assert.AreEqual(string.Empty, tb1.Name); - Assert.AreEqual(null, tb1.Nickname); - } - - [Test] - public void BailsOnUnresolvableVariable() - { - StaticApplicationContext ac = new StaticApplicationContext(); - - MutablePropertyValues pvs = new MutablePropertyValues(); - pvs.Add("nickname", "${nickname}"); - ac.RegisterSingleton("tb1", typeof(TestObject), pvs); - - IList variableSources = new ArrayList(); - variableSources.Add(new DictionaryVariableSource(new string[] { })); - pvs = new MutablePropertyValues(); - pvs.Add("VariableSources", variableSources); - ac.RegisterSingleton("configurer", typeof(VariablePlaceholderConfigurer), pvs); - - try - { - ac.Refresh(); - Assert.Fail("something changed wrt VariablePlaceholder resolution"); - } - catch (ObjectDefinitionStoreException ex) - { - Assert.IsTrue(ex.Message.IndexOf("nickname") > -1); - } - } - - [Test] - public void IgnoresUnresolvableVariable() - { - StaticApplicationContext ac = new StaticApplicationContext(); - - MutablePropertyValues pvs = new MutablePropertyValues(); - pvs.Add("name", "${name}"); - pvs.Add("nickname", "${nickname}"); - ac.RegisterSingleton("tb1", typeof(TestObject), pvs); - - VariablePlaceholderConfigurer vpc = new VariablePlaceholderConfigurer(); - vpc.IgnoreUnresolvablePlaceholders = true; - vpc.VariableSource = new DictionaryVariableSource(new string[] { "name", "Erich" }); - ac.AddObjectFactoryPostProcessor(vpc); - - ac.Refresh(); - - TestObject tb1 = (TestObject)ac.GetObject("tb1"); - Assert.AreEqual("Erich", tb1.Name); - Assert.AreEqual("${nickname}", tb1.Nickname); - } - - [Test] - public void InlcludeAncestors() - { - const string defName = "foo"; - const string placeholder = "${name}"; - MutablePropertyValues pvs = new MutablePropertyValues(); - - - const string theProperty = "name"; - pvs.Add(theProperty, placeholder); - RootObjectDefinition def = new RootObjectDefinition(typeof(TestObject), pvs); - - IConfigurableListableObjectFactory mock = A.Fake(); - A.CallTo(() => mock.GetObjectDefinitionNames(true)).Returns(new string[] { defName }); - A.CallTo(() => mock.GetObjectDefinition(defName, true)).Returns(def); - - VariablePlaceholderConfigurer vpc = new VariablePlaceholderConfigurer(); - vpc.IgnoreUnresolvablePlaceholders = true; - vpc.VariableSource = new DictionaryVariableSource(new string[] { "name", "Erich" }); - vpc.IncludeAncestors = true; - - vpc.PostProcessObjectFactory(mock); } } -} \ No newline at end of file + + [Test] + public void ThrowsOnInvalidVariableSourcesElement() + { + StaticApplicationContext ac = new StaticApplicationContext(); + VariablePlaceholderConfigurer vphc = new VariablePlaceholderConfigurer(); + vphc.VariableSources = new ArrayList(new object[] { new object() }); + + try + { + vphc.PostProcessObjectFactory(ac.ObjectFactory); + Assert.Fail("Expected ArgumentException not thrown."); + } + catch (ArgumentException) + { + } + } + + [Test] + public void SunnyDay() + { + StaticApplicationContext ac = new StaticApplicationContext(); + + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.Add("age", "${maxResults}"); + pvs.Add("name", "${name}"); + ac.RegisterSingleton("tb1", typeof(TestObject), pvs); + + IList variableSources = new ArrayList(); + CommandLineArgsVariableSource vs1 = new CommandLineArgsVariableSource( + new string[] { "program.exe", "file.txt", "/name:Aleks Seovic", "/framework:Spring.NET" }); + variableSources.Add(vs1); + + ConfigSectionVariableSource vs2 = new ConfigSectionVariableSource(); + vs2.SectionName = "DaoConfiguration"; + variableSources.Add(vs2); + + pvs = new MutablePropertyValues(); + pvs.Add("VariableSources", variableSources); + + ac.RegisterSingleton("configurer", typeof(VariablePlaceholderConfigurer), pvs); + ac.Refresh(); + + TestObject tb1 = (TestObject) ac.GetObject("tb1"); + Assert.AreEqual(1000, tb1.Age); + Assert.AreEqual("Aleks Seovic", tb1.Name); + } + + [Test] + public void UsesCustomVariablePrefixSuffix() + { + StaticApplicationContext ac = new StaticApplicationContext(); + + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.Add("age", "%[maxResults]%"); + pvs.Add("name", "%[name]%"); + ac.RegisterSingleton("tb1", typeof(TestObject), pvs); + + IList variableSources = new ArrayList(); + variableSources.Add(new DictionaryVariableSource(new string[] { "maxResults", "35", "name", "Erich" })); + + pvs = new MutablePropertyValues(); + pvs.Add("VariableSources", variableSources); + pvs.Add("PlaceholderPrefix", "%["); + pvs.Add("PlaceholderSuffix", "]%"); + + ac.RegisterSingleton("configurer", typeof(VariablePlaceholderConfigurer), pvs); + ac.Refresh(); + + TestObject tb1 = (TestObject) ac.GetObject("tb1"); + Assert.AreEqual(35, tb1.Age); + Assert.AreEqual("Erich", tb1.Name); + } + + [Test] + public void MultiResolution() + { + DefaultListableObjectFactory of = new DefaultListableObjectFactory(); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.Add("Greeting", "Hello ${firstname} ${lastname}!"); + of.RegisterObjectDefinition("tb1", new RootObjectDefinition("typename", null, pvs)); + + IList variableSources = new ArrayList(); + variableSources.Add(new DictionaryVariableSource(new string[] { "firstname", "FirstName" })); + variableSources.Add(new DictionaryVariableSource(new string[] { "lastname", "LastName" })); + VariablePlaceholderConfigurer vphc = new VariablePlaceholderConfigurer(variableSources); + vphc.PostProcessObjectFactory(of); + + RootObjectDefinition rod = (RootObjectDefinition) of.GetObjectDefinition("tb1"); + Assert.AreEqual("Hello FirstName LastName!", rod.PropertyValues.GetPropertyValue("Greeting").Value); + } + + [Test] + public void NestedResolution() + { + DefaultListableObjectFactory of = new DefaultListableObjectFactory(); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.Add("NameProperty", "${name}"); + of.RegisterObjectDefinition("tb1", new RootObjectDefinition("typename", null, pvs)); + + IList variableSources = new ArrayList(); + variableSources.Add(new DictionaryVariableSource(new string[] { "name", "${nickname}" })); + variableSources.Add(new DictionaryVariableSource(new string[] { "nickname", "nickname-value" })); + VariablePlaceholderConfigurer vphc = new VariablePlaceholderConfigurer(variableSources); + vphc.PostProcessObjectFactory(of); + + RootObjectDefinition rod = (RootObjectDefinition) of.GetObjectDefinition("tb1"); + Assert.AreEqual("nickname-value", rod.PropertyValues.GetPropertyValue("NameProperty").Value); + } + + [Test] + public void ChainedResolution() + { + StaticApplicationContext ac = new StaticApplicationContext(); + + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.Add("name", "${name}"); + pvs.Add("nickname", "${nickname}"); + ac.RegisterSingleton("tb1", typeof(TestObject), pvs); + + IList variableSources = new ArrayList(); + variableSources.Add(new DictionaryVariableSource(new string[] { "name", "name-value" })); + variableSources.Add(new DictionaryVariableSource(new string[] { "nickname", "nickname-value" })); + VariablePlaceholderConfigurer vphc = new VariablePlaceholderConfigurer(variableSources); + ac.AddObjectFactoryPostProcessor(vphc); + ac.Refresh(); + + TestObject tb1 = (TestObject) ac.GetObject("tb1"); + Assert.AreEqual("name-value", tb1.Name); + Assert.AreEqual("nickname-value", tb1.Nickname); + } + + [Test] + public void ChainedResolutionWithNullValues() + { + DefaultListableObjectFactory of = new DefaultListableObjectFactory(); + + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.Add("NameProperty", "${name}"); + pvs.Add("NickNameProperty", "${nickname}"); + of.RegisterObjectDefinition("tb1", new RootObjectDefinition("typename", null, pvs)); + + IList variableSources = new ArrayList(); + variableSources.Add(new DictionaryVariableSource(new string[] { "name", "name-value", "nickname", null })); + variableSources.Add(new DictionaryVariableSource(new string[] { "nickname", "nickname-value" })); + VariablePlaceholderConfigurer vphc = new VariablePlaceholderConfigurer(variableSources); + + vphc.PostProcessObjectFactory(of); + RootObjectDefinition rod = (RootObjectDefinition) of.GetObjectDefinition("tb1"); + Assert.AreEqual("name-value", rod.PropertyValues.GetPropertyValue("NameProperty").Value); + Assert.AreEqual(null, rod.PropertyValues.GetPropertyValue("NickNameProperty").Value); + } + + [Test] + public void WhitespaceHandling() + { + StaticApplicationContext ac = new StaticApplicationContext(); + + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.Add("name", "${name}"); + pvs.Add("nickname", "${nickname}"); + ac.RegisterSingleton("tb1", typeof(TestObject), pvs); + + IList variableSources = new ArrayList(); + variableSources.Add(new DictionaryVariableSource(new string[] { "name", string.Empty, "nickname", null })); + pvs = new MutablePropertyValues(); + pvs.Add("VariableSources", variableSources); + ac.RegisterSingleton("configurer", typeof(VariablePlaceholderConfigurer), pvs); + ac.Refresh(); + + TestObject tb1 = (TestObject) ac.GetObject("tb1"); + Assert.AreEqual(string.Empty, tb1.Name); + Assert.AreEqual(null, tb1.Nickname); + } + + [Test] + public void BailsOnUnresolvableVariable() + { + StaticApplicationContext ac = new StaticApplicationContext(); + + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.Add("nickname", "${nickname}"); + ac.RegisterSingleton("tb1", typeof(TestObject), pvs); + + IList variableSources = new ArrayList(); + variableSources.Add(new DictionaryVariableSource(new string[] { })); + pvs = new MutablePropertyValues(); + pvs.Add("VariableSources", variableSources); + ac.RegisterSingleton("configurer", typeof(VariablePlaceholderConfigurer), pvs); + + try + { + ac.Refresh(); + Assert.Fail("something changed wrt VariablePlaceholder resolution"); + } + catch (ObjectDefinitionStoreException ex) + { + Assert.IsTrue(ex.Message.IndexOf("nickname") > -1); + } + } + + [Test] + public void IgnoresUnresolvableVariable() + { + StaticApplicationContext ac = new StaticApplicationContext(); + + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.Add("name", "${name}"); + pvs.Add("nickname", "${nickname}"); + ac.RegisterSingleton("tb1", typeof(TestObject), pvs); + + VariablePlaceholderConfigurer vpc = new VariablePlaceholderConfigurer(); + vpc.IgnoreUnresolvablePlaceholders = true; + vpc.VariableSource = new DictionaryVariableSource(new string[] { "name", "Erich" }); + ac.AddObjectFactoryPostProcessor(vpc); + + ac.Refresh(); + + TestObject tb1 = (TestObject) ac.GetObject("tb1"); + Assert.AreEqual("Erich", tb1.Name); + Assert.AreEqual("${nickname}", tb1.Nickname); + } + + [Test] + public void InlcludeAncestors() + { + const string defName = "foo"; + const string placeholder = "${name}"; + MutablePropertyValues pvs = new MutablePropertyValues(); + + const string theProperty = "name"; + pvs.Add(theProperty, placeholder); + RootObjectDefinition def = new RootObjectDefinition(typeof(TestObject), pvs); + + IConfigurableListableObjectFactory mock = A.Fake(); + A.CallTo(() => mock.GetObjectDefinitionNames(true)).Returns(new string[] { defName }); + A.CallTo(() => mock.GetObjectDefinition(defName, true)).Returns(def); + + VariablePlaceholderConfigurer vpc = new VariablePlaceholderConfigurer(); + vpc.IgnoreUnresolvablePlaceholders = true; + vpc.VariableSource = new DictionaryVariableSource(new string[] { "name", "Erich" }); + vpc.IncludeAncestors = true; + + vpc.PostProcessObjectFactory(mock); + } +} diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/DefaultListableObjectFactoryPerfTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/DefaultListableObjectFactoryPerfTests.cs index 8726bfab..18999ef7 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/DefaultListableObjectFactoryPerfTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/DefaultListableObjectFactoryPerfTests.cs @@ -28,227 +28,221 @@ using Spring.Threading; #endregion -namespace Spring.Objects.Factory +namespace Spring.Objects.Factory; + +/// +/// This class contains tests related to performance of the object factory implementation and some concurrency test. +/// The performance test are ignored by default. +/// +/// Mark Pollack +[TestFixture] +public class DefaultListableObjectFactoryPerfTests { - /// - /// This class contains tests related to performance of the object factory implementation and some concurrency test. - /// The performance test are ignored by default. - /// - /// Mark Pollack - [TestFixture] - public class DefaultListableObjectFactoryPerfTests + private DateTime start, stop; + + [SetUp] + public void Setup() { - - private DateTime start, stop; - - [SetUp] - public void Setup() - { - } - - [Test] - [Ignore("just a test")] - public void Test() - { - int numIterations = 10000; - start = DateTime.Now; - DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); - InitFactory(factory); - for (int i = 0; i < numIterations; i++) - { - FFoo foo = (FFoo)factory.GetObject("foo"); - } - stop = DateTime.Now; - double timeElapsed = Elapsed; - PrintTest("Creations", numIterations, timeElapsed); - - - } - - private void InitFactory(DefaultListableObjectFactory factory) - { - Console.WriteLine("init factory"); - RootObjectDefinition tee = new RootObjectDefinition(typeof(Tee), true); - tee.IsLazyInit = true; - ConstructorArgumentValues teeValues = new ConstructorArgumentValues(); - teeValues.AddGenericArgumentValue("test"); - tee.ConstructorArgumentValues = teeValues; - - RootObjectDefinition bar = new RootObjectDefinition(typeof(BBar), false); - ConstructorArgumentValues barValues = new ConstructorArgumentValues(); - barValues.AddGenericArgumentValue(new RuntimeObjectReference("tee")); - barValues.AddGenericArgumentValue(5); - bar.ConstructorArgumentValues = barValues; - - RootObjectDefinition foo = new RootObjectDefinition(typeof(FFoo), false); - MutablePropertyValues fooValues = new MutablePropertyValues(); - fooValues.Add("i", 5); - fooValues.Add("bar", new RuntimeObjectReference("bar")); - fooValues.Add("copy", new RuntimeObjectReference("bar")); - fooValues.Add("s", "test"); - foo.PropertyValues = fooValues; - - factory.RegisterObjectDefinition("foo", foo); - factory.RegisterObjectDefinition("bar", bar); - factory.RegisterObjectDefinition("tee", tee); - } - - - private double Elapsed - { - get { return (stop.Ticks - start.Ticks) / 10000000f; } - } - - private static void PrintTest(string name, int iterations, double duration) - { - Debug.WriteLine( - String.Format("{0,-60} {1,12:#,###} {2,12:##0.000} {3,12:#,###}", name, iterations, duration, - iterations / duration)); - } - - [Test] - public void ConcurrencyTest() - { - AsyncTestTask t1 = new BeanFactoryTask(100).Start(); - t1.AssertNoException(); - } - } - public class BeanFactoryTask : AsyncTestTask + [Test] + [Ignore("just a test")] + public void Test() { + int numIterations = 10000; + start = DateTime.Now; DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); - - public BeanFactoryTask(int iterations) - : base(iterations) + InitFactory(factory); + for (int i = 0; i < numIterations; i++) { - InitializeFactory(); - FFoo foo = (FFoo)factory.GetObject("foo"); - Assert.AreEqual(5, foo.i); - Assert.AreEqual("test", foo.s); - Assert.AreSame(foo.bar.tee, foo.copy.tee); - Assert.AreEqual(5, foo.bar.i); - Assert.AreEqual("test", foo.bar.Tee.S); + FFoo foo = (FFoo) factory.GetObject("foo"); } - private void InitializeFactory() - { - Console.WriteLine("init factory"); - RootObjectDefinition tee = new RootObjectDefinition(typeof(Tee), true); - tee.IsLazyInit = true; - ConstructorArgumentValues teeValues = new ConstructorArgumentValues(); - teeValues.AddGenericArgumentValue("test"); - tee.ConstructorArgumentValues = teeValues; - - RootObjectDefinition bar = new RootObjectDefinition(typeof(BBar), false); - ConstructorArgumentValues barValues = new ConstructorArgumentValues(); - barValues.AddGenericArgumentValue(new RuntimeObjectReference("tee")); - barValues.AddGenericArgumentValue(5); - bar.ConstructorArgumentValues = barValues; - - RootObjectDefinition foo = new RootObjectDefinition(typeof(FFoo), false); - MutablePropertyValues fooValues = new MutablePropertyValues(); - fooValues.Add("i", 5); - fooValues.Add("bar", new RuntimeObjectReference("bar")); - fooValues.Add("copy", new RuntimeObjectReference("bar")); - fooValues.Add("s", "test"); - foo.PropertyValues = fooValues; - - factory.RegisterObjectDefinition("foo", foo); - factory.RegisterObjectDefinition("bar", bar); - factory.RegisterObjectDefinition("tee", tee); - - } - - public override void DoExecute() - { - FFoo foo = (FFoo)factory.GetObject("foo"); - } + stop = DateTime.Now; + double timeElapsed = Elapsed; + PrintTest("Creations", numIterations, timeElapsed); } - public interface ITee + private void InitFactory(DefaultListableObjectFactory factory) { - string S - { get; } + Console.WriteLine("init factory"); + RootObjectDefinition tee = new RootObjectDefinition(typeof(Tee), true); + tee.IsLazyInit = true; + ConstructorArgumentValues teeValues = new ConstructorArgumentValues(); + teeValues.AddGenericArgumentValue("test"); + tee.ConstructorArgumentValues = teeValues; + + RootObjectDefinition bar = new RootObjectDefinition(typeof(BBar), false); + ConstructorArgumentValues barValues = new ConstructorArgumentValues(); + barValues.AddGenericArgumentValue(new RuntimeObjectReference("tee")); + barValues.AddGenericArgumentValue(5); + bar.ConstructorArgumentValues = barValues; + + RootObjectDefinition foo = new RootObjectDefinition(typeof(FFoo), false); + MutablePropertyValues fooValues = new MutablePropertyValues(); + fooValues.Add("i", 5); + fooValues.Add("bar", new RuntimeObjectReference("bar")); + fooValues.Add("copy", new RuntimeObjectReference("bar")); + fooValues.Add("s", "test"); + foo.PropertyValues = fooValues; + + factory.RegisterObjectDefinition("foo", foo); + factory.RegisterObjectDefinition("bar", bar); + factory.RegisterObjectDefinition("tee", tee); } - public class Tee : ITee + private double Elapsed { - private string s; - - public Tee(string s) - { - this.s = s; - } - - public string S - { - get { return s; } - } + get { return (stop.Ticks - start.Ticks) / 10000000f; } } - public interface IBBar + private static void PrintTest(string name, int iterations, double duration) { - ITee Tee - { - get; - } - - int I - { - get; - } + Debug.WriteLine( + String.Format("{0,-60} {1,12:#,###} {2,12:##0.000} {3,12:#,###}", name, iterations, duration, + iterations / duration)); } - public class BBar : IBBar + [Test] + public void ConcurrencyTest() { - public Tee tee; - public int i; - - public BBar(Tee tee, int i) - { - this.tee = tee; - this.i = i; - } - - public ITee Tee - { - get { return tee; } - } - - public int I - { - get { return i; } - } - + AsyncTestTask t1 = new BeanFactoryTask(100).Start(); + t1.AssertNoException(); } +} - public class FFoo +public class BeanFactoryTask : AsyncTestTask +{ + DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); + + public BeanFactoryTask(int iterations) + : base(iterations) { - public BBar bar; - public BBar copy; - public string s; - public int i; - - public int I - { - set { i = value; } - } - - - public BBar Bar - { - set { bar = value; } - } - - public BBar Copy - { - set { copy = value; } - } - - public string S - { - set { s = value; } - } + InitializeFactory(); + FFoo foo = (FFoo) factory.GetObject("foo"); + Assert.AreEqual(5, foo.i); + Assert.AreEqual("test", foo.s); + Assert.AreSame(foo.bar.tee, foo.copy.tee); + Assert.AreEqual(5, foo.bar.i); + Assert.AreEqual("test", foo.bar.Tee.S); } -} \ No newline at end of file + + private void InitializeFactory() + { + Console.WriteLine("init factory"); + RootObjectDefinition tee = new RootObjectDefinition(typeof(Tee), true); + tee.IsLazyInit = true; + ConstructorArgumentValues teeValues = new ConstructorArgumentValues(); + teeValues.AddGenericArgumentValue("test"); + tee.ConstructorArgumentValues = teeValues; + + RootObjectDefinition bar = new RootObjectDefinition(typeof(BBar), false); + ConstructorArgumentValues barValues = new ConstructorArgumentValues(); + barValues.AddGenericArgumentValue(new RuntimeObjectReference("tee")); + barValues.AddGenericArgumentValue(5); + bar.ConstructorArgumentValues = barValues; + + RootObjectDefinition foo = new RootObjectDefinition(typeof(FFoo), false); + MutablePropertyValues fooValues = new MutablePropertyValues(); + fooValues.Add("i", 5); + fooValues.Add("bar", new RuntimeObjectReference("bar")); + fooValues.Add("copy", new RuntimeObjectReference("bar")); + fooValues.Add("s", "test"); + foo.PropertyValues = fooValues; + + factory.RegisterObjectDefinition("foo", foo); + factory.RegisterObjectDefinition("bar", bar); + factory.RegisterObjectDefinition("tee", tee); + } + + public override void DoExecute() + { + FFoo foo = (FFoo) factory.GetObject("foo"); + } +} + +public interface ITee +{ + string S + { + get; + } +} + +public class Tee : ITee +{ + private string s; + + public Tee(string s) + { + this.s = s; + } + + public string S + { + get { return s; } + } +} + +public interface IBBar +{ + ITee Tee + { + get; + } + + int I + { + get; + } +} + +public class BBar : IBBar +{ + public Tee tee; + public int i; + + public BBar(Tee tee, int i) + { + this.tee = tee; + this.i = i; + } + + public ITee Tee + { + get { return tee; } + } + + public int I + { + get { return i; } + } +} + +public class FFoo +{ + public BBar bar; + public BBar copy; + public string s; + public int i; + + public int I + { + set { i = value; } + } + + public BBar Bar + { + set { bar = value; } + } + + public BBar Copy + { + set { copy = value; } + } + + public string S + { + set { s = value; } + } +} diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/DefaultListableObjectFactoryTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/DefaultListableObjectFactoryTests.cs index a4353d62..37eff53b 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/DefaultListableObjectFactoryTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/DefaultListableObjectFactoryTests.cs @@ -25,1956 +25,1975 @@ using Spring.Objects.Factory.Support; using Spring.Objects.Factory.Xml; using Spring.Objects.Support; -namespace Spring.Objects.Factory +namespace Spring.Objects.Factory; + +/// +/// Unit tests for the DefaultListableObjectFactory class. +/// +/// Rod Johnson +/// Simon White (.NET) +[TestFixture] +public sealed class DefaultListableObjectFactoryTests { - /// - /// Unit tests for the DefaultListableObjectFactory class. - /// - /// Rod Johnson - /// Simon White (.NET) - [TestFixture] - public sealed class DefaultListableObjectFactoryTests + [SetUp] + public void Setup() { - [SetUp] - public void Setup() + } + + /// + /// The setup logic executed before the execution of this test fixture. + /// + [OneTimeSetUp] + public void FixtureSetUp() + { + // enable (null appender) logging, just to ensure that the logging code is correct :D + //XmlConfigurator.Configure(); + } + + interface ICollaborator + { + } + + interface IStrategy + { + } + + class Collaborator : ICollaborator + { + } + + class Strategy1 : IStrategy + { + } + + class Strategy2 : IStrategy + { + } + + class Class1 + { + public readonly IStrategy TheStrategy; + + public Class1(ICollaborator collaborator, IStrategy strategy) + { + TheStrategy = strategy; + } + } + + class Class2 + { + private IStrategy _strategy; + private ICollaborator _collaborator; + + public Class2() { } - /// - /// The setup logic executed before the execution of this test fixture. - /// - [OneTimeSetUp] - public void FixtureSetUp() + public IStrategy Strategy { - // enable (null appender) logging, just to ensure that the logging code is correct :D - //XmlConfigurator.Configure(); + get { return _strategy; } + set { _strategy = value; } } - interface ICollaborator {} - interface IStrategy {} - - class Collaborator : ICollaborator {} - class Strategy1 : IStrategy {} - class Strategy2 : IStrategy {} - - class Class1 + public ICollaborator Collaborator { - public readonly IStrategy TheStrategy; + get { return _collaborator; } + set { _collaborator = value; } + } + } - public Class1( ICollaborator collaborator, IStrategy strategy) - { - TheStrategy = strategy; - } + [Test(Description = "http://jira.springframework.org/browse/SPRNET-985")] + public void AutowireConstructorHonoresOverridesBeforeThrowingUnsatisfiedDependencyException() + { + RootObjectDefinition def = new RootObjectDefinition(typeof(Class1)); + def.AutowireMode = AutoWiringMode.AutoDetect; + def.ConstructorArgumentValues.AddNamedArgumentValue("strategy", new RuntimeObjectReference("Strategy1")); + + DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); + lof.RegisterObjectDefinition("Class", def); + lof.RegisterObjectDefinition("ICollaborator", new RootObjectDefinition(typeof(Collaborator))); + lof.RegisterObjectDefinition("Strategy1", new RootObjectDefinition(typeof(Strategy1))); + lof.RegisterObjectDefinition("Strategy2", new RootObjectDefinition(typeof(Strategy1))); + + Class1 c1 = (Class1) lof.GetObject("Class"); + Assert.IsNotNull(c1); + Assert.AreEqual(typeof(Strategy1), c1.TheStrategy.GetType()); + } + + [Test(Description = "http://jira.springframework.org/browse/SPRNET-985")] + public void AutowireByTypeHonoresOverridesBeforeThrowingUnsatisfiedDependencyException() + { + RootObjectDefinition def = new RootObjectDefinition(typeof(Class2)); + def.AutowireMode = AutoWiringMode.AutoDetect; + def.PropertyValues.Add("strategy", new RuntimeObjectReference("Strategy1")); + + DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); + lof.RegisterObjectDefinition("Class", def); + lof.RegisterObjectDefinition("ICollaborator", new RootObjectDefinition(typeof(Collaborator))); + lof.RegisterObjectDefinition("Strategy1", new RootObjectDefinition(typeof(Strategy1))); + lof.RegisterObjectDefinition("Strategy2", new RootObjectDefinition(typeof(Strategy1))); + + Class2 c2 = (Class2) lof.GetObject("Class"); + Assert.IsNotNull(c2); + Assert.AreEqual(typeof(Strategy1), c2.Strategy.GetType()); + } + + [Test(Description = "http://jira.springframework.org/browse/SPRNET-112")] + public void ObjectCreatedViaStaticFactoryMethodUsesReturnTypeOfFactoryMethodAsTheObjectType() + { + RootObjectDefinition def + = new RootObjectDefinition(typeof(TestObjectCreator)); + def.FactoryMethodName = "CreateTestObject"; + DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); + lof.RegisterObjectDefinition("factoryObject", def); + var objs = lof.GetObjects(); + Assert.AreEqual(1, objs.Count); + } + + [Test(Description = "http://opensource2.atlassian.com/projects/spring/browse/SPRNET-112")] + public void ObjectCreatedViaInstanceFactoryMethodUsesReturnTypeOfFactoryMethodAsTheObjectType() + { + RootObjectDefinition def + = new RootObjectDefinition(typeof(TestObjectCreator)); + def.FactoryMethodName = "InstanceCreateTestObject"; + def.FactoryObjectName = "target"; + DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); + lof.RegisterObjectDefinition("factoryObject", def); + lof.RegisterObjectDefinition("target", new RootObjectDefinition(typeof(TestObjectCreator))); + var objs = lof.GetObjects(); + Assert.AreEqual(1, objs.Count); + } + + [Test(Description = "http://opensource2.atlassian.com/projects/spring/browse/SPRNET-112")] + public void ObjectCreatedViaStaticGenericFactoryMethodUsesReturnTypeOfGenericFactoryMethodAsTheObjectType() + { + DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); + RootObjectDefinition def + = new RootObjectDefinition(typeof(TestGenericObject)); + def.FactoryMethodName = "CreateList"; + lof.RegisterObjectDefinition("foo", def); + var objs = lof.GetObjectsOfType(typeof(List)); + Assert.AreEqual(1, objs.Count); + } + + [Test(Description = "http://opensource2.atlassian.com/projects/spring/browse/SPRNET-112")] + public void ObjectCreatedViaInstanceGenericFactoryMethodUsesReturnTypeOfGenericFactoryMethodAsTheObjectType() + { + RootObjectDefinition def + = new RootObjectDefinition(typeof(TestObjectCreator)); + def.FactoryMethodName = "CreateInstance"; + def.FactoryObjectName = "target"; + DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); + lof.RegisterObjectDefinition("factoryObject", def); + lof.RegisterObjectDefinition("target", new RootObjectDefinition(typeof(TestGenericObject))); + var objs = lof.GetObjectsOfType(typeof(TestGenericObject)); + Assert.AreEqual(1, objs.Count); + } + + /// + /// Object instantiation through factory method should not require type attribute. + /// + [Test(Description = "http://opensource.atlassian.com/projects/spring/browse/SPRNET-130")] + public void SPRNET_130() + { + const string factoryObjectName = "factoryObject"; + const string exampleObjectName = "exampleObject"; + + RootObjectDefinition factoryObjectDefinition + = new RootObjectDefinition(typeof(TestObjectFactory)); + RootObjectDefinition exampleObjectDefinition = new RootObjectDefinition(); + exampleObjectDefinition.FactoryObjectName = factoryObjectName; + exampleObjectDefinition.FactoryMethodName = "GetObject"; + + DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); + lof.RegisterObjectDefinition(factoryObjectName, factoryObjectDefinition); + lof.RegisterObjectDefinition(exampleObjectName, exampleObjectDefinition); + + object exampleObject = lof.GetObject(exampleObjectName); + Assert.IsNotNull(exampleObject); + object factoryObject = lof.GetObject(factoryObjectName); + Assert.IsNotNull(factoryObject); + } + + [Test(Description = "http://opensource.atlassian.com/projects/spring/browse/SPR-1011")] + public void SPR_1011() + { + DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); + RootObjectDefinition def + = new RootObjectDefinition( + typeof(StaticFactoryMethodObject)); + def.FactoryMethodName = "CreateObject"; + lof.RegisterObjectDefinition("foo", def); + var objs = lof.GetObjectsOfType(typeof(DBNull)); + Assert.AreEqual(1, objs.Count, + "Must be looking at the RETURN TYPE of the factory method, " + + "and hence get one DBNull object back."); + } + + private sealed class StaticFactoryMethodObject + { + private StaticFactoryMethodObject() + { } - class Class2 + public static DBNull CreateObject() { - private IStrategy _strategy; - private ICollaborator _collaborator; + return DBNull.Value; + } + } - public Class2() - {} + [Test(Description = "http://opensource.atlassian.com/projects/spring/browse/SPR-1077")] + public void SPR_1077() + { + DisposableTestObject sing = null; + using (DefaultListableObjectFactory lof = new DefaultListableObjectFactory()) + { + RootObjectDefinition singleton + = new RootObjectDefinition(typeof(DisposableTestObject)); + MutablePropertyValues sprops = new MutablePropertyValues(); + sprops.Add("name", "Rick"); + singleton.PropertyValues = sprops; + lof.RegisterObjectDefinition("singleton", singleton); - public IStrategy Strategy - { - get { return _strategy; } - set { _strategy = value; } - } + RootObjectDefinition prototype + = new RootObjectDefinition(typeof(TestObject)); + MutablePropertyValues pprops = new MutablePropertyValues(); + pprops.Add("name", "Jenny"); + // prototype has dependency on a singleton... + pprops.Add("spouse", new RuntimeObjectReference("singleton")); + prototype.PropertyValues = pprops; + prototype.IsSingleton = false; + lof.RegisterObjectDefinition("prototype", prototype); - public ICollaborator Collaborator - { - get { return _collaborator; } - set { _collaborator = value; } - } + sing = (DisposableTestObject) lof.GetObject("singleton"); + + lof.GetObject("prototype"); + lof.GetObject("prototype"); + lof.GetObject("prototype"); + lof.GetObject("prototype"); } + Assert.AreEqual(1, sing.NumTimesDisposed); + } - [Test(Description = "http://jira.springframework.org/browse/SPRNET-985")] - public void AutowireConstructorHonoresOverridesBeforeThrowingUnsatisfiedDependencyException() + private sealed class DisposableTestObject : TestObject, IDisposable + { + private int _numTimesDisposed; + + public int NumTimesDisposed { - RootObjectDefinition def = new RootObjectDefinition(typeof(Class1)); - def.AutowireMode = AutoWiringMode.AutoDetect; - def.ConstructorArgumentValues.AddNamedArgumentValue("strategy", new RuntimeObjectReference("Strategy1") ); - - DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); - lof.RegisterObjectDefinition("Class", def); - lof.RegisterObjectDefinition("ICollaborator", new RootObjectDefinition(typeof(Collaborator))); - lof.RegisterObjectDefinition("Strategy1", new RootObjectDefinition(typeof(Strategy1))); - lof.RegisterObjectDefinition("Strategy2", new RootObjectDefinition(typeof(Strategy1))); - - Class1 c1 = (Class1) lof.GetObject("Class"); - Assert.IsNotNull(c1); - Assert.AreEqual( typeof(Strategy1), c1.TheStrategy.GetType() ); + get { return _numTimesDisposed; } } - [Test(Description = "http://jira.springframework.org/browse/SPRNET-985")] - public void AutowireByTypeHonoresOverridesBeforeThrowingUnsatisfiedDependencyException() + public void Dispose() { - RootObjectDefinition def = new RootObjectDefinition(typeof(Class2)); - def.AutowireMode = AutoWiringMode.AutoDetect; - def.PropertyValues.Add("strategy", new RuntimeObjectReference("Strategy1") ); + ++_numTimesDisposed; + } + } - DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); - lof.RegisterObjectDefinition("Class", def); - lof.RegisterObjectDefinition("ICollaborator", new RootObjectDefinition(typeof(Collaborator))); - lof.RegisterObjectDefinition("Strategy1", new RootObjectDefinition(typeof(Strategy1))); - lof.RegisterObjectDefinition("Strategy2", new RootObjectDefinition(typeof(Strategy1))); + [Test] + public void GetObjectPostProcessorCount() + { + IObjectPostProcessor proc1 = FakeItEasy.A.Fake(); + IObjectPostProcessor proc2 = FakeItEasy.A.Fake(); - Class2 c2 = (Class2) lof.GetObject("Class"); - Assert.IsNotNull(c2); - Assert.AreEqual( typeof(Strategy1), c2.Strategy.GetType() ); + DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); + + const string errMsg = "Wrong number of IObjectPostProcessors being reported by the ObjectPostProcessorCount property."; + Assert.AreEqual(0, lof.ObjectPostProcessorCount, errMsg); + lof.AddObjectPostProcessor(proc1); + Assert.AreEqual(1, lof.ObjectPostProcessorCount, errMsg); + lof.AddObjectPostProcessor(proc2); + Assert.AreEqual(2, lof.ObjectPostProcessorCount, errMsg); + } + + /// + /// The ObjectPostProcessorCount property must only return the count of + /// processors registered with the current factory, and not + /// surf up any hierarchy. + /// + [Test] + public void GetObjectPostProcessorCountDoesntRespectHierarchy() + { + IObjectPostProcessor proc1 = FakeItEasy.A.Fake(); + IObjectPostProcessor proc2 = FakeItEasy.A.Fake(); + + DefaultListableObjectFactory child = new DefaultListableObjectFactory(); + DefaultListableObjectFactory parent = new DefaultListableObjectFactory(child); + + const string errMsg = "Wrong number of IObjectPostProcessors being reported by the ObjectPostProcessorCount property."; + Assert.AreEqual(0, child.ObjectPostProcessorCount, errMsg); + Assert.AreEqual(0, parent.ObjectPostProcessorCount, errMsg); + child.AddObjectPostProcessor(proc1); + Assert.AreEqual(1, child.ObjectPostProcessorCount, errMsg); + Assert.AreEqual(0, parent.ObjectPostProcessorCount, errMsg); + parent.AddObjectPostProcessor(proc2); + Assert.AreEqual(1, child.ObjectPostProcessorCount, errMsg); + Assert.AreEqual(1, parent.ObjectPostProcessorCount, errMsg); + child.AddObjectPostProcessor(proc2); + Assert.AreEqual(2, child.ObjectPostProcessorCount, errMsg); + Assert.AreEqual(1, parent.ObjectPostProcessorCount, errMsg); + } + + [Test] + public void TestIInstantiationAwareObjectPostProcessorsInterception() + { + ProxyingInstantiationAwareObjectPostProcessorStub proc + = new ProxyingInstantiationAwareObjectPostProcessorStub("TheAgony"); + + MutablePropertyValues props = new MutablePropertyValues(); + props.Add("Name", "Rick"); + RootObjectDefinition toBeProxied + = new RootObjectDefinition(typeof(TestObject), props); + + DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); + lof.AddObjectPostProcessor(proc); + lof.RegisterObjectDefinition("toBeProxied", toBeProxied); + + object proxy = lof["toBeProxied"]; + Assert.IsNotNull(proxy); + Assert.AreEqual("TheAgony", proxy); + } + + [Test] + public void TestIInstantiationAwareObjectPostProcessorsPassThrough() + { + NullInstantiationAwareObjectPostProcessorStub proc + = new NullInstantiationAwareObjectPostProcessorStub(); + + MutablePropertyValues props = new MutablePropertyValues(); + props.Add("Name", "Rick"); + RootObjectDefinition not + = new RootObjectDefinition(typeof(TestObject), props); + + DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); + lof.AddObjectPostProcessor(proc); + lof.RegisterObjectDefinition("notToBeProxied", not); + + object foo = lof["notToBeProxied"]; + Assert.IsNotNull(foo); + Assert.AreEqual(typeof(TestObject), foo.GetType()); + TestObject to = (TestObject) foo; + Assert.AreEqual("Rick", to.Name); + } + + private sealed class NullInstantiationAwareObjectPostProcessorStub + : IInstantiationAwareObjectPostProcessor + { + public NullInstantiationAwareObjectPostProcessorStub() + { } - [Test(Description = "http://jira.springframework.org/browse/SPRNET-112")] - public void ObjectCreatedViaStaticFactoryMethodUsesReturnTypeOfFactoryMethodAsTheObjectType() + public object PostProcessBeforeInitialization(object obj, string name) { - RootObjectDefinition def - = new RootObjectDefinition(typeof(TestObjectCreator)); - def.FactoryMethodName = "CreateTestObject"; - DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); - lof.RegisterObjectDefinition("factoryObject", def); - var objs = lof.GetObjects(); - Assert.AreEqual(1, objs.Count); + return obj; } - [Test(Description = "http://opensource2.atlassian.com/projects/spring/browse/SPRNET-112")] - public void ObjectCreatedViaInstanceFactoryMethodUsesReturnTypeOfFactoryMethodAsTheObjectType() + public object PostProcessBeforeInstantiation(Type objectType, string objectName) { - RootObjectDefinition def - = new RootObjectDefinition(typeof(TestObjectCreator)); - def.FactoryMethodName = "InstanceCreateTestObject"; - def.FactoryObjectName = "target"; - DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); - lof.RegisterObjectDefinition("factoryObject", def); - lof.RegisterObjectDefinition("target", new RootObjectDefinition(typeof(TestObjectCreator))); - var objs = lof.GetObjects(); - Assert.AreEqual(1, objs.Count); + //proceed with default instantiation + return null; } - [Test(Description = "http://opensource2.atlassian.com/projects/spring/browse/SPRNET-112")] - public void ObjectCreatedViaStaticGenericFactoryMethodUsesReturnTypeOfGenericFactoryMethodAsTheObjectType() + public bool PostProcessAfterInstantiation(object objectInstance, string objectName) { - DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); - RootObjectDefinition def - = new RootObjectDefinition(typeof(TestGenericObject)); - def.FactoryMethodName = "CreateList"; - lof.RegisterObjectDefinition("foo", def); - var objs = lof.GetObjectsOfType(typeof(List)); - Assert.AreEqual(1, objs.Count); + //proceed to set properties on the object + return true; } - [Test(Description = "http://opensource2.atlassian.com/projects/spring/browse/SPRNET-112")] - public void ObjectCreatedViaInstanceGenericFactoryMethodUsesReturnTypeOfGenericFactoryMethodAsTheObjectType() + public IPropertyValues PostProcessPropertyValues(IPropertyValues pvs, IList pis, object objectInstance, string objectName) { - RootObjectDefinition def - = new RootObjectDefinition(typeof(TestObjectCreator)); - def.FactoryMethodName = "CreateInstance"; - def.FactoryObjectName = "target"; - DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); - lof.RegisterObjectDefinition("factoryObject", def); - lof.RegisterObjectDefinition("target", new RootObjectDefinition(typeof(TestGenericObject))); - var objs = lof.GetObjectsOfType(typeof(TestGenericObject)); - Assert.AreEqual(1, objs.Count); + return pvs; } - /// - /// Object instantiation through factory method should not require type attribute. - /// - [Test(Description = "http://opensource.atlassian.com/projects/spring/browse/SPRNET-130")] - public void SPRNET_130() + public object PostProcessAfterInitialization(object obj, string objectName) { - const string factoryObjectName = "factoryObject"; - const string exampleObjectName = "exampleObject"; + return obj; + } + } - RootObjectDefinition factoryObjectDefinition - = new RootObjectDefinition(typeof(TestObjectFactory)); - RootObjectDefinition exampleObjectDefinition = new RootObjectDefinition(); - exampleObjectDefinition.FactoryObjectName = factoryObjectName; - exampleObjectDefinition.FactoryMethodName = "GetObject"; - - DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); - lof.RegisterObjectDefinition(factoryObjectName, factoryObjectDefinition); - lof.RegisterObjectDefinition(exampleObjectName, exampleObjectDefinition); - - object exampleObject = lof.GetObject(exampleObjectName); - Assert.IsNotNull(exampleObject); - object factoryObject = lof.GetObject(factoryObjectName); - Assert.IsNotNull(factoryObject); + private sealed class ProxyingInstantiationAwareObjectPostProcessorStub + : IInstantiationAwareObjectPostProcessor + { + public ProxyingInstantiationAwareObjectPostProcessorStub() + { } - [Test(Description = "http://opensource.atlassian.com/projects/spring/browse/SPR-1011")] - public void SPR_1011() + public ProxyingInstantiationAwareObjectPostProcessorStub(object proxy) { - DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); - RootObjectDefinition def - = new RootObjectDefinition( - typeof(StaticFactoryMethodObject)); - def.FactoryMethodName = "CreateObject"; - lof.RegisterObjectDefinition("foo", def); - var objs = lof.GetObjectsOfType(typeof(DBNull)); - Assert.AreEqual(1, objs.Count, - "Must be looking at the RETURN TYPE of the factory method, " + - "and hence get one DBNull object back."); + _proxy = proxy; } - private sealed class StaticFactoryMethodObject - { - private StaticFactoryMethodObject() - { - } + private object _proxy; - public static DBNull CreateObject() - { - return DBNull.Value; - } + public object Proxy + { + get { return _proxy; } + set { _proxy = value; } } - [Test(Description = "http://opensource.atlassian.com/projects/spring/browse/SPR-1077")] - public void SPR_1077() + public object PostProcessBeforeInitialization(object obj, string name) { - DisposableTestObject sing = null; - using (DefaultListableObjectFactory lof = new DefaultListableObjectFactory()) - { - RootObjectDefinition singleton - = new RootObjectDefinition(typeof(DisposableTestObject)); - MutablePropertyValues sprops = new MutablePropertyValues(); - sprops.Add("name", "Rick"); - singleton.PropertyValues = sprops; - lof.RegisterObjectDefinition("singleton", singleton); - - RootObjectDefinition prototype - = new RootObjectDefinition(typeof(TestObject)); - MutablePropertyValues pprops = new MutablePropertyValues(); - pprops.Add("name", "Jenny"); - // prototype has dependency on a singleton... - pprops.Add("spouse", new RuntimeObjectReference("singleton")); - prototype.PropertyValues = pprops; - prototype.IsSingleton = false; - lof.RegisterObjectDefinition("prototype", prototype); - - sing = (DisposableTestObject)lof.GetObject("singleton"); - - lof.GetObject("prototype"); - lof.GetObject("prototype"); - lof.GetObject("prototype"); - lof.GetObject("prototype"); - } - Assert.AreEqual(1, sing.NumTimesDisposed); + throw new NotImplementedException(); } - private sealed class DisposableTestObject : TestObject, IDisposable + public object PostProcessBeforeInstantiation(Type objectType, string objectName) { - private int _numTimesDisposed; - - public int NumTimesDisposed - { - get { return _numTimesDisposed; } - } - - public void Dispose() - { - ++_numTimesDisposed; - } + return _proxy; } - [Test] - public void GetObjectPostProcessorCount() + public bool PostProcessAfterInstantiation(object objectInstance, string objectName) { - IObjectPostProcessor proc1 = FakeItEasy.A.Fake(); - IObjectPostProcessor proc2 = FakeItEasy.A.Fake(); - - DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); - - const string errMsg = "Wrong number of IObjectPostProcessors being reported by the ObjectPostProcessorCount property."; - Assert.AreEqual(0, lof.ObjectPostProcessorCount, errMsg); - lof.AddObjectPostProcessor(proc1); - Assert.AreEqual(1, lof.ObjectPostProcessorCount, errMsg); - lof.AddObjectPostProcessor(proc2); - Assert.AreEqual(2, lof.ObjectPostProcessorCount, errMsg); - + return true; } - /// - /// The ObjectPostProcessorCount property must only return the count of - /// processors registered with the current factory, and not - /// surf up any hierarchy. - /// - [Test] - public void GetObjectPostProcessorCountDoesntRespectHierarchy() + public IPropertyValues PostProcessPropertyValues(IPropertyValues pvs, IList pis, object objectInstance, string objectName) { - IObjectPostProcessor proc1 = FakeItEasy.A.Fake(); - IObjectPostProcessor proc2 = FakeItEasy.A.Fake(); - - DefaultListableObjectFactory child = new DefaultListableObjectFactory(); - DefaultListableObjectFactory parent = new DefaultListableObjectFactory(child); - - const string errMsg = "Wrong number of IObjectPostProcessors being reported by the ObjectPostProcessorCount property."; - Assert.AreEqual(0, child.ObjectPostProcessorCount, errMsg); - Assert.AreEqual(0, parent.ObjectPostProcessorCount, errMsg); - child.AddObjectPostProcessor(proc1); - Assert.AreEqual(1, child.ObjectPostProcessorCount, errMsg); - Assert.AreEqual(0, parent.ObjectPostProcessorCount, errMsg); - parent.AddObjectPostProcessor(proc2); - Assert.AreEqual(1, child.ObjectPostProcessorCount, errMsg); - Assert.AreEqual(1, parent.ObjectPostProcessorCount, errMsg); - child.AddObjectPostProcessor(proc2); - Assert.AreEqual(2, child.ObjectPostProcessorCount, errMsg); - Assert.AreEqual(1, parent.ObjectPostProcessorCount, errMsg); + return pvs; } - [Test] - public void TestIInstantiationAwareObjectPostProcessorsInterception() + public object PostProcessAfterInitialization(object obj, string objectName) { - ProxyingInstantiationAwareObjectPostProcessorStub proc - = new ProxyingInstantiationAwareObjectPostProcessorStub("TheAgony"); - - MutablePropertyValues props = new MutablePropertyValues(); - props.Add("Name", "Rick"); - RootObjectDefinition toBeProxied - = new RootObjectDefinition(typeof(TestObject), props); - - DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); - lof.AddObjectPostProcessor(proc); - lof.RegisterObjectDefinition("toBeProxied", toBeProxied); - - object proxy = lof["toBeProxied"]; - Assert.IsNotNull(proxy); - Assert.AreEqual("TheAgony", proxy); + throw new NotImplementedException(); } + } - [Test] - public void TestIInstantiationAwareObjectPostProcessorsPassThrough() + [Test] + public void PreInstantiateSingletonsMustNotIgnoreObjectsWithUnresolvedObjectTypes() + { + KnowsIfInstantiated.ClearInstantiationRecord(); + DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); + Assert.IsTrue(!KnowsIfInstantiated.WasInstantiated, "Singleton appears to be instantiated before the test is even run."); + RootObjectDefinition def = new RootObjectDefinition(); + def.ObjectTypeName = typeof(KnowsIfInstantiated).FullName; + lof.RegisterObjectDefinition("x1", def); + Assert.IsTrue(!KnowsIfInstantiated.WasInstantiated, "Singleton appears to be instantiated before PreInstantiateSingletons() is invoked."); + lof.PreInstantiateSingletons(); + Assert.IsTrue(KnowsIfInstantiated.WasInstantiated, "Singleton was not instantiated by the container (it must be)."); + } + + [Test] + public void LazyInitialization() + { + KnowsIfInstantiated.ClearInstantiationRecord(); + DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); + + RootObjectDefinition def = new RootObjectDefinition(); + def.ObjectTypeName = typeof(KnowsIfInstantiated).FullName; + def.IsLazyInit = true; + lof.RegisterObjectDefinition("x1", def); + + Assert.IsTrue(!KnowsIfInstantiated.WasInstantiated, "Singleton appears to be instantiated before the test is even run."); + lof.RegisterObjectDefinition("x1", def); + Assert.IsTrue(!KnowsIfInstantiated.WasInstantiated, "Singleton appears to be instantiated before PreInstantiateSingletons() is invoked."); + lof.PreInstantiateSingletons(); + Assert.IsFalse(KnowsIfInstantiated.WasInstantiated, "Singleton was instantiated by the container (it must NOT be 'cos LazyInit was set to TRUE)."); + lof.GetObject("x1"); + Assert.IsTrue(KnowsIfInstantiated.WasInstantiated, "Singleton was not instantiated by the container (it must be)."); + } + + [Test] + public void SingletonFactoryObjectMustNotCreatePrototypeOnPreInstantiateSingletonsCall() + { + DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); + + RootObjectDefinition def = new RootObjectDefinition(); + def.ObjectType = typeof(DummyFactory); + def.IsSingleton = true; + def.PropertyValues.Add("IsSingleton", false); + + DummyFactory.Reset(); + + Assert.IsFalse(DummyFactory.WasPrototypeCreated, + "Prototype appears to be instantiated before the test is even run."); + lof.RegisterObjectDefinition("x1", def); + Assert.IsFalse(DummyFactory.WasPrototypeCreated, + "Prototype instantiated after object definition registration (must NOT be)."); + lof.PreInstantiateSingletons(); + Assert.IsFalse(DummyFactory.WasPrototypeCreated, + "Prototype instantiated after call to PreInstantiateSingletons(); must NOT be."); + lof.GetObject("x1"); + Assert.IsTrue(DummyFactory.WasPrototypeCreated, "Prototype was not instantiated."); + } + + [Test] + public void Empty() + { + IListableObjectFactory lof = new DefaultListableObjectFactory(); + Assert.IsTrue(lof.GetObjectDefinitionNames() != null, "No objects defined --> array != null"); + Assert.IsTrue(lof.GetObjectDefinitionNames().Count == 0, "No objects defined after no arg constructor"); + Assert.IsTrue(lof.ObjectDefinitionCount == 0, "No objects defined after no arg constructor"); + } + + [Test] + public void ObjectDefinitionCountIsZeroBeforeAnythingIsRegistered() + { + DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); + Assert.AreEqual(0, lof.ObjectDefinitionCount, "No objects must be defined straight off the bat."); + } + + [Test] + public void ObjectDefinitionOverriding() + { + DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); + lof.RegisterObjectDefinition("test", new RootObjectDefinition(typeof(TestObject), null)); + lof.RegisterObjectDefinition("test", new RootObjectDefinition(typeof(NestedTestObject), null)); + Assert.IsTrue(lof.GetObject("test") is NestedTestObject); + } + + [Test] + public void ObjectDefinitionOverridingNotAllowed() + { + DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); + lof.AllowObjectDefinitionOverriding = false; + lof.RegisterObjectDefinition("test", new RootObjectDefinition(typeof(TestObject), null)); + Assert.Throws(() => lof.RegisterObjectDefinition("test", new RootObjectDefinition(typeof(NestedTestObject), null))); + } + + [Test] + public void CustomEditor() + { + DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); + NumberFormatInfo nfi = new CultureInfo("en-GB", false).NumberFormat; + lof.RegisterCustomConverter(typeof(Single), new CustomNumberConverter(typeof(Single), nfi, true)); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.Add("myFloat", "1.1"); + lof.RegisterObjectDefinition("testObject", new RootObjectDefinition(typeof(TestObject), pvs)); + TestObject testObject = (TestObject) lof.GetObject("testObject"); + Assert.IsTrue(testObject.MyFloat == 1.1f); + } + + [Test] + public void RegisterExistingSingletonWithReference() + { + DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); + + RootObjectDefinition def = new RootObjectDefinition(); + def.ObjectType = typeof(TestObject); + def.PropertyValues.Add("Name", "Rick"); + def.PropertyValues.Add("Age", 30); + def.PropertyValues.Add("Spouse", new RuntimeObjectReference("singletonObject")); + lof.RegisterObjectDefinition("test", def); + + object singletonObject = new TestObject(); + lof.RegisterSingleton("singletonObject", singletonObject); + Assert.IsTrue(lof.IsSingleton("singletonObject")); + TestObject test = (TestObject) lof.GetObject("test"); + Assert.AreEqual(singletonObject, lof.GetObject("singletonObject")); + Assert.AreEqual(singletonObject, test.Spouse); + var objectsOfType = lof.GetObjectsOfType(typeof(TestObject), false, true); + Assert.AreEqual(2, objectsOfType.Count); + Assert.IsTrue(objectsOfType.Values.Contains(test)); + Assert.IsTrue(objectsOfType.Values.Contains(singletonObject)); + } + + [Test] + public void ApplyPropertyValues() + { + DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); + MutablePropertyValues properties = new MutablePropertyValues(); + properties.Add("age", "99"); + factory.RegisterObjectDefinition("test", new RootObjectDefinition(typeof(TestObject), properties)); + TestObject obj = new TestObject(); + Assert.AreEqual(0, obj.Age); + factory.ApplyObjectPropertyValues(obj, "test"); + Assert.AreEqual(99, obj.Age, "Property values were not applied to the existing instance."); + } + + [Test] + public void ApplyPropertyValuesWithIncompleteDefinition() + { + DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); + MutablePropertyValues properties = new MutablePropertyValues(); + properties.Add("age", "99"); + factory.RegisterObjectDefinition("test", new RootObjectDefinition(null, properties)); + TestObject obj = new TestObject(); + Assert.AreEqual(0, obj.Age); + factory.ApplyObjectPropertyValues(obj, "test"); + Assert.AreEqual(99, obj.Age, "Property values were not applied to the existing instance."); + } + + [Test] + public void RegisterExistingSingletonWithAutowire() + { + DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.Add("name", "Tony"); + pvs.Add("age", "48"); + RootObjectDefinition rod = new RootObjectDefinition(typeof(DependenciesObject), pvs, true); + rod.DependencyCheck = DependencyCheckingMode.Objects; + rod.AutowireMode = AutoWiringMode.ByType; + lof.RegisterObjectDefinition("test", rod); + object singletonObject = new TestObject(); + lof.RegisterSingleton("singletonObject", singletonObject); + Assert.IsTrue(lof.ContainsObject("singletonObject")); + Assert.IsTrue(lof.IsSingleton("singletonObject")); + Assert.AreEqual(0, lof.GetAliases("singletonObject").Count); + DependenciesObject test = (DependenciesObject) lof.GetObject("test"); + Assert.AreEqual(singletonObject, lof.GetObject("singletonObject")); + Assert.AreEqual(singletonObject, test.Spouse); + } + + [Test] + public void RegisterExistingSingletonWithAlreadyBound() + { + DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); + object singletonObject = new TestObject(); + lof.RegisterSingleton("singletonObject", singletonObject); + Assert.Throws(() => lof.RegisterSingleton("singletonObject", singletonObject)); + } + + [Test] + public void AutowireConstructor() + { + DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); + RootObjectDefinition rod = new RootObjectDefinition(typeof(TestObject)); + lof.RegisterObjectDefinition("spouse", rod); + ConstructorDependenciesObject cdo = (ConstructorDependenciesObject) lof.Autowire(typeof(ConstructorDependenciesObject), + AutoWiringMode.Constructor, true); + object spouse = lof.GetObject("spouse"); + Assert.IsTrue(cdo.Spouse1 == spouse); + Assert.IsTrue(ObjectFactoryUtils.ObjectOfType(lof, typeof(TestObject)) == spouse); + } + + [Test] + public void AutowireObjectByName() + { + DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); + RootObjectDefinition rodDefinition = new RootObjectDefinition(typeof(TestObject)); + rodDefinition.PropertyValues.Add("name", "Rod"); + rodDefinition.AutowireMode = AutoWiringMode.ByName; + RootObjectDefinition kerryDefinition = new RootObjectDefinition(typeof(TestObject)); + kerryDefinition.PropertyValues.Add("name", "Kerry"); + lof.RegisterObjectDefinition("rod", rodDefinition); + lof.RegisterObjectDefinition("Spouse", kerryDefinition); + DependenciesObject obj = (DependenciesObject) lof.Autowire(typeof(DependenciesObject), + AutoWiringMode.ByName, true); + TestObject objRod = (TestObject) lof.GetObject("rod"); + Assert.AreEqual(obj.Spouse, objRod.Spouse); + } + + [Test] + public void AutowireObjectByNameIsNotCaseInsensitive() + { + DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); + RootObjectDefinition rodDefinition = new RootObjectDefinition(typeof(TestObject)); + rodDefinition.PropertyValues.Add("name", "Rod"); + rodDefinition.AutowireMode = AutoWiringMode.ByName; + RootObjectDefinition kerryDefinition = new RootObjectDefinition(typeof(TestObject)); + kerryDefinition.PropertyValues.Add("name", "Kerry"); + lof.RegisterObjectDefinition("rod", rodDefinition); + lof.RegisterObjectDefinition("spouse", kerryDefinition); // property name is Spouse (capital S) + TestObject objRod = (TestObject) lof.GetObject("rod"); + Assert.IsNull(objRod.Spouse, "Mmm, Spouse property appears to have been autowired by name, even though there is no object in the factory with a name 'Spouse'."); + } + + [Test] + public void AutowireObjectByNameWithDependencyCheck() + { + DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); + RootObjectDefinition rod = new RootObjectDefinition(typeof(TestObject)); + lof.RegisterObjectDefinition("Spous", rod); + Assert.Throws(() => lof.Autowire(typeof(DependenciesObject), AutoWiringMode.ByName, true)); + } + + [Test] + public void AutowireObjectByNameWithNoDependencyCheck() + { + DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); + RootObjectDefinition rod = new RootObjectDefinition(typeof(TestObject)); + lof.RegisterObjectDefinition("Spous", rod); + DependenciesObject obj = (DependenciesObject) lof.Autowire(typeof(DependenciesObject), AutoWiringMode.ByName, false); + Assert.IsNull(obj.Spouse); + } + + [Test] + public void AutowireObjectByType() + { + DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); + RootObjectDefinition rod = new RootObjectDefinition(typeof(TestObject)); + lof.RegisterObjectDefinition("test", rod); + DependenciesObject obj = (DependenciesObject) lof.Autowire(typeof(DependenciesObject), AutoWiringMode.ByType, true); + TestObject test = (TestObject) lof.GetObject("test"); + Assert.AreEqual(obj.Spouse, test); + } + + [Test] + public void AutowireObjectByTypeWithDependencyCheck() + { + DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); + Assert.Throws(() => lof.Autowire(typeof(DependenciesObject), AutoWiringMode.ByType, true)); + } + + [Test] + public void AutowireObjectByTypeWithNoDependencyCheck() + { + DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); + DependenciesObject obj = (DependenciesObject) lof.Autowire(typeof(DependenciesObject), AutoWiringMode.ByType, false); + Assert.IsNull(obj.Spouse); + } + + [Test] + public void AutowireExistingObjectByName() + { + DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); + RootObjectDefinition rod = new RootObjectDefinition(typeof(TestObject)); + lof.RegisterObjectDefinition("Spouse", rod); + DependenciesObject existingObj = new DependenciesObject(); + lof.AutowireObjectProperties(existingObj, AutoWiringMode.ByName, true); + TestObject spouse = (TestObject) lof.GetObject("Spouse"); + Assert.AreEqual(existingObj.Spouse, spouse); + Assert.IsTrue(ObjectFactoryUtils.ObjectOfType(lof, typeof(TestObject)) == spouse); + } + + [Test] + public void AutowireExistingObjectByNameWithDependencyCheck() + { + DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); + RootObjectDefinition rod = new RootObjectDefinition(typeof(TestObject)); + lof.RegisterObjectDefinition("Spous", rod); + DependenciesObject existingObj = new DependenciesObject(); + Assert.Throws(() => lof.AutowireObjectProperties(existingObj, AutoWiringMode.ByName, true)); + } + + [Test] + public void AutowireExistingObjectByNameWithNoDependencyCheck() + { + DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); + RootObjectDefinition rod = new RootObjectDefinition(typeof(TestObject)); + lof.RegisterObjectDefinition("Spous", rod); + DependenciesObject existingObj = new DependenciesObject(); + lof.AutowireObjectProperties(existingObj, AutoWiringMode.ByName, false); + Assert.IsNull(existingObj.Spouse); + } + + [Test] + public void AutowireExistingObjectByType() + { + DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); + RootObjectDefinition rod = new RootObjectDefinition(typeof(TestObject)); + lof.RegisterObjectDefinition("test", rod); + DependenciesObject existingObj = new DependenciesObject(); + lof.AutowireObjectProperties(existingObj, AutoWiringMode.ByType, true); + TestObject test = (TestObject) lof.GetObject("test"); + Assert.AreEqual(existingObj.Spouse, test); + } + + [Test] + public void AutowireByTypeWithInvalidAutowireMode() + { + DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); + DependenciesObject obj = new DependenciesObject(); + Assert.Throws(() => lof.AutowireObjectProperties(obj, AutoWiringMode.Constructor, true)); + } + + [Test] + public void AutowireExistingObjectByTypeWithDependencyCheck() + { + DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); + DependenciesObject existingObj = new DependenciesObject(); + Assert.Throws(() => lof.AutowireObjectProperties(existingObj, AutoWiringMode.ByType, true)); + } + + [Test] + public void AutowireExistingObjectByTypeWithNoDependencyCheck() + { + DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); + DependenciesObject existingObj = new DependenciesObject(); + lof.AutowireObjectProperties(existingObj, AutoWiringMode.ByType, false); + Assert.IsNull(existingObj.Spouse); + } + + [Test] + public void AutowireWithNoDependencies() + { + DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); + RootObjectDefinition rod = new RootObjectDefinition(typeof(TestObject)); + lof.RegisterObjectDefinition("rod", rod); + Assert.AreEqual(1, lof.ObjectDefinitionCount); + object registered = lof.Autowire(typeof(NoDependencies), AutoWiringMode.AutoDetect, false); + Assert.AreEqual(1, lof.ObjectDefinitionCount); + Assert.IsTrue(registered is NoDependencies); + } + + [Test] + public void AutowireWithSatisfiedObjectDependency() + { + DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.Add(new PropertyValue("name", "Rod")); + RootObjectDefinition rood = new RootObjectDefinition(typeof(TestObject), pvs); + lof.RegisterObjectDefinition("rod", rood); + Assert.AreEqual(1, lof.ObjectDefinitionCount); + // Depends on age, name and spouse (TestObject) + object registered = lof.Autowire(typeof(DependenciesObject), AutoWiringMode.AutoDetect, true); + Assert.AreEqual(1, lof.ObjectDefinitionCount); + DependenciesObject kerry = (DependenciesObject) registered; + TestObject rod = (TestObject) lof.GetObject("rod"); + Assert.AreSame(rod, kerry.Spouse); + } + + [Test] + public void AutowireWithSatisfiedConstructorDependency() + { + DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.Add(new PropertyValue("name", "Rod")); + RootObjectDefinition rood = new RootObjectDefinition(typeof(TestObject), pvs); + lof.RegisterObjectDefinition("rod", rood); + Assert.AreEqual(1, lof.ObjectDefinitionCount); + object registered = lof.Autowire(typeof(ConstructorDependency), AutoWiringMode.AutoDetect, false); + Assert.AreEqual(1, lof.ObjectDefinitionCount); + ConstructorDependency kerry = (ConstructorDependency) registered; + TestObject rod = (TestObject) lof.GetObject("rod"); + Assert.AreSame(rod, kerry._spouse); + } + + [Test] + public void AutowireWithUnsatisfiedConstructorDependency() + { + DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.Add(new PropertyValue("name", "Rod")); + RootObjectDefinition rod = new RootObjectDefinition(typeof(TestObject), pvs); + lof.RegisterObjectDefinition("rod", rod); + Assert.AreEqual(1, lof.ObjectDefinitionCount); + Assert.Throws(() => lof.Autowire(typeof(UnsatisfiedConstructorDependency), AutoWiringMode.AutoDetect, true)); + } + + [Test] + public void ExtensiveCircularReference() + { + DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); + for (int i = 0; i < 1000; i++) { - NullInstantiationAwareObjectPostProcessorStub proc - = new NullInstantiationAwareObjectPostProcessorStub(); - - MutablePropertyValues props = new MutablePropertyValues(); - props.Add("Name", "Rick"); - RootObjectDefinition not - = new RootObjectDefinition(typeof(TestObject), props); - - DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); - lof.AddObjectPostProcessor(proc); - lof.RegisterObjectDefinition("notToBeProxied", not); - - object foo = lof["notToBeProxied"]; - Assert.IsNotNull(foo); - Assert.AreEqual(typeof(TestObject), foo.GetType()); - TestObject to = (TestObject)foo; - Assert.AreEqual("Rick", to.Name); - } - - private sealed class NullInstantiationAwareObjectPostProcessorStub - : IInstantiationAwareObjectPostProcessor - { - public NullInstantiationAwareObjectPostProcessorStub() - { - } - - public object PostProcessBeforeInitialization(object obj, string name) - { - return obj; - } - - public object PostProcessBeforeInstantiation(Type objectType, string objectName) - { - //proceed with default instantiation - return null; - } - - public bool PostProcessAfterInstantiation(object objectInstance, string objectName) - { - //proceed to set properties on the object - return true; - } - - public IPropertyValues PostProcessPropertyValues(IPropertyValues pvs, IList pis, object objectInstance, string objectName) - { - return pvs; - } - - public object PostProcessAfterInitialization(object obj, string objectName) - { - return obj; - } - } - - private sealed class ProxyingInstantiationAwareObjectPostProcessorStub - : IInstantiationAwareObjectPostProcessor - { - public ProxyingInstantiationAwareObjectPostProcessorStub() - { - } - - public ProxyingInstantiationAwareObjectPostProcessorStub(object proxy) - { - _proxy = proxy; - } - - private object _proxy; - - public object Proxy - { - get { return _proxy; } - set { _proxy = value; } - } - - public object PostProcessBeforeInitialization(object obj, string name) - { - throw new NotImplementedException(); - } - - public object PostProcessBeforeInstantiation(Type objectType, string objectName) - { - return _proxy; - } - - public bool PostProcessAfterInstantiation(object objectInstance, string objectName) - { - return true; - } - - public IPropertyValues PostProcessPropertyValues(IPropertyValues pvs, IList pis, object objectInstance, string objectName) - { - return pvs; - } - - public object PostProcessAfterInitialization(object obj, string objectName) - { - throw new NotImplementedException(); - } - } - - [Test] - public void PreInstantiateSingletonsMustNotIgnoreObjectsWithUnresolvedObjectTypes() - { - KnowsIfInstantiated.ClearInstantiationRecord(); - DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); - Assert.IsTrue(!KnowsIfInstantiated.WasInstantiated, "Singleton appears to be instantiated before the test is even run."); - RootObjectDefinition def = new RootObjectDefinition(); - def.ObjectTypeName = typeof(KnowsIfInstantiated).FullName; - lof.RegisterObjectDefinition("x1", def); - Assert.IsTrue(!KnowsIfInstantiated.WasInstantiated, "Singleton appears to be instantiated before PreInstantiateSingletons() is invoked."); - lof.PreInstantiateSingletons(); - Assert.IsTrue(KnowsIfInstantiated.WasInstantiated, "Singleton was not instantiated by the container (it must be)."); - } - - [Test] - public void LazyInitialization() - { - KnowsIfInstantiated.ClearInstantiationRecord(); - DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); - - RootObjectDefinition def = new RootObjectDefinition(); - def.ObjectTypeName = typeof(KnowsIfInstantiated).FullName; - def.IsLazyInit = true; - lof.RegisterObjectDefinition("x1", def); - - Assert.IsTrue(!KnowsIfInstantiated.WasInstantiated, "Singleton appears to be instantiated before the test is even run."); - lof.RegisterObjectDefinition("x1", def); - Assert.IsTrue(!KnowsIfInstantiated.WasInstantiated, "Singleton appears to be instantiated before PreInstantiateSingletons() is invoked."); - lof.PreInstantiateSingletons(); - Assert.IsFalse(KnowsIfInstantiated.WasInstantiated, "Singleton was instantiated by the container (it must NOT be 'cos LazyInit was set to TRUE)."); - lof.GetObject("x1"); - Assert.IsTrue(KnowsIfInstantiated.WasInstantiated, "Singleton was not instantiated by the container (it must be)."); - } - - [Test] - public void SingletonFactoryObjectMustNotCreatePrototypeOnPreInstantiateSingletonsCall() - { - DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); - - RootObjectDefinition def = new RootObjectDefinition(); - def.ObjectType = typeof(DummyFactory); - def.IsSingleton = true; - def.PropertyValues.Add("IsSingleton", false); - - DummyFactory.Reset(); - - Assert.IsFalse(DummyFactory.WasPrototypeCreated, - "Prototype appears to be instantiated before the test is even run."); - lof.RegisterObjectDefinition("x1", def); - Assert.IsFalse(DummyFactory.WasPrototypeCreated, - "Prototype instantiated after object definition registration (must NOT be)."); - lof.PreInstantiateSingletons(); - Assert.IsFalse(DummyFactory.WasPrototypeCreated, - "Prototype instantiated after call to PreInstantiateSingletons(); must NOT be."); - lof.GetObject("x1"); - Assert.IsTrue(DummyFactory.WasPrototypeCreated, "Prototype was not instantiated."); - } - - [Test] - public void Empty() - { - IListableObjectFactory lof = new DefaultListableObjectFactory(); - Assert.IsTrue(lof.GetObjectDefinitionNames() != null, "No objects defined --> array != null"); - Assert.IsTrue(lof.GetObjectDefinitionNames().Count == 0, "No objects defined after no arg constructor"); - Assert.IsTrue(lof.ObjectDefinitionCount == 0, "No objects defined after no arg constructor"); - } - - [Test] - public void ObjectDefinitionCountIsZeroBeforeAnythingIsRegistered() - { - DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); - Assert.AreEqual(0, lof.ObjectDefinitionCount, "No objects must be defined straight off the bat."); - } - - [Test] - public void ObjectDefinitionOverriding() - { - DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); - lof.RegisterObjectDefinition("test", new RootObjectDefinition(typeof(TestObject), null)); - lof.RegisterObjectDefinition("test", new RootObjectDefinition(typeof(NestedTestObject), null)); - Assert.IsTrue(lof.GetObject("test") is NestedTestObject); - } - - [Test] - public void ObjectDefinitionOverridingNotAllowed() - { - DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); - lof.AllowObjectDefinitionOverriding = false; - lof.RegisterObjectDefinition("test", new RootObjectDefinition(typeof(TestObject), null)); - Assert.Throws(() => lof.RegisterObjectDefinition("test", new RootObjectDefinition(typeof(NestedTestObject), null))); - } - - [Test] - public void CustomEditor() - { - DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); - NumberFormatInfo nfi = new CultureInfo("en-GB", false).NumberFormat; - lof.RegisterCustomConverter(typeof(Single), new CustomNumberConverter(typeof(Single), nfi, true)); MutablePropertyValues pvs = new MutablePropertyValues(); - pvs.Add("myFloat", "1.1"); - lof.RegisterObjectDefinition("testObject", new RootObjectDefinition(typeof(TestObject), pvs)); - TestObject testObject = (TestObject)lof.GetObject("testObject"); - Assert.IsTrue(testObject.MyFloat == 1.1f); - } - - [Test] - public void RegisterExistingSingletonWithReference() - { - DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); - - RootObjectDefinition def = new RootObjectDefinition(); - def.ObjectType = typeof(TestObject); - def.PropertyValues.Add("Name", "Rick"); - def.PropertyValues.Add("Age", 30); - def.PropertyValues.Add("Spouse", new RuntimeObjectReference("singletonObject")); - lof.RegisterObjectDefinition("test", def); - - object singletonObject = new TestObject(); - lof.RegisterSingleton("singletonObject", singletonObject); - Assert.IsTrue(lof.IsSingleton("singletonObject")); - TestObject test = (TestObject)lof.GetObject("test"); - Assert.AreEqual(singletonObject, lof.GetObject("singletonObject")); - Assert.AreEqual(singletonObject, test.Spouse); - var objectsOfType = lof.GetObjectsOfType(typeof(TestObject), false, true); - Assert.AreEqual(2, objectsOfType.Count); - Assert.IsTrue(objectsOfType.Values.Contains(test)); - Assert.IsTrue(objectsOfType.Values.Contains(singletonObject)); - } - - [Test] - public void ApplyPropertyValues() - { - DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); - MutablePropertyValues properties = new MutablePropertyValues(); - properties.Add("age", "99"); - factory.RegisterObjectDefinition("test", new RootObjectDefinition(typeof(TestObject), properties)); - TestObject obj = new TestObject(); - Assert.AreEqual(0, obj.Age); - factory.ApplyObjectPropertyValues(obj, "test"); - Assert.AreEqual(99, obj.Age, "Property values were not applied to the existing instance."); - } - - [Test] - public void ApplyPropertyValuesWithIncompleteDefinition() - { - DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); - MutablePropertyValues properties = new MutablePropertyValues(); - properties.Add("age", "99"); - factory.RegisterObjectDefinition("test", new RootObjectDefinition(null, properties)); - TestObject obj = new TestObject(); - Assert.AreEqual(0, obj.Age); - factory.ApplyObjectPropertyValues(obj, "test"); - Assert.AreEqual(99, obj.Age, "Property values were not applied to the existing instance."); - } - - [Test] - public void RegisterExistingSingletonWithAutowire() - { - DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); - MutablePropertyValues pvs = new MutablePropertyValues(); - pvs.Add("name", "Tony"); - pvs.Add("age", "48"); - RootObjectDefinition rod = new RootObjectDefinition(typeof(DependenciesObject), pvs, true); - rod.DependencyCheck = DependencyCheckingMode.Objects; - rod.AutowireMode = AutoWiringMode.ByType; - lof.RegisterObjectDefinition("test", rod); - object singletonObject = new TestObject(); - lof.RegisterSingleton("singletonObject", singletonObject); - Assert.IsTrue(lof.ContainsObject("singletonObject")); - Assert.IsTrue(lof.IsSingleton("singletonObject")); - Assert.AreEqual(0, lof.GetAliases("singletonObject").Count); - DependenciesObject test = (DependenciesObject)lof.GetObject("test"); - Assert.AreEqual(singletonObject, lof.GetObject("singletonObject")); - Assert.AreEqual(singletonObject, test.Spouse); - } - - [Test] - public void RegisterExistingSingletonWithAlreadyBound() - { - DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); - object singletonObject = new TestObject(); - lof.RegisterSingleton("singletonObject", singletonObject); - Assert.Throws(() => lof.RegisterSingleton("singletonObject", singletonObject)); - } - - [Test] - public void AutowireConstructor() - { - DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); - RootObjectDefinition rod = new RootObjectDefinition(typeof(TestObject)); - lof.RegisterObjectDefinition("spouse", rod); - ConstructorDependenciesObject cdo = (ConstructorDependenciesObject)lof.Autowire(typeof(ConstructorDependenciesObject), - AutoWiringMode.Constructor, true); - object spouse = lof.GetObject("spouse"); - Assert.IsTrue(cdo.Spouse1 == spouse); - Assert.IsTrue(ObjectFactoryUtils.ObjectOfType(lof, typeof(TestObject)) == spouse); - } - - [Test] - public void AutowireObjectByName() - { - DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); - RootObjectDefinition rodDefinition = new RootObjectDefinition(typeof(TestObject)); - rodDefinition.PropertyValues.Add("name", "Rod"); - rodDefinition.AutowireMode = AutoWiringMode.ByName; - RootObjectDefinition kerryDefinition = new RootObjectDefinition(typeof(TestObject)); - kerryDefinition.PropertyValues.Add("name", "Kerry"); - lof.RegisterObjectDefinition("rod", rodDefinition); - lof.RegisterObjectDefinition("Spouse", kerryDefinition); - DependenciesObject obj = (DependenciesObject)lof.Autowire(typeof(DependenciesObject), - AutoWiringMode.ByName, true); - TestObject objRod = (TestObject)lof.GetObject("rod"); - Assert.AreEqual(obj.Spouse, objRod.Spouse); - } - - [Test] - public void AutowireObjectByNameIsNotCaseInsensitive() - { - DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); - RootObjectDefinition rodDefinition = new RootObjectDefinition(typeof(TestObject)); - rodDefinition.PropertyValues.Add("name", "Rod"); - rodDefinition.AutowireMode = AutoWiringMode.ByName; - RootObjectDefinition kerryDefinition = new RootObjectDefinition(typeof(TestObject)); - kerryDefinition.PropertyValues.Add("name", "Kerry"); - lof.RegisterObjectDefinition("rod", rodDefinition); - lof.RegisterObjectDefinition("spouse", kerryDefinition); // property name is Spouse (capital S) - TestObject objRod = (TestObject)lof.GetObject("rod"); - Assert.IsNull(objRod.Spouse, "Mmm, Spouse property appears to have been autowired by name, even though there is no object in the factory with a name 'Spouse'."); - } - - [Test] - public void AutowireObjectByNameWithDependencyCheck() - { - DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); - RootObjectDefinition rod = new RootObjectDefinition(typeof(TestObject)); - lof.RegisterObjectDefinition("Spous", rod); - Assert.Throws(() => lof.Autowire(typeof(DependenciesObject), AutoWiringMode.ByName, true)); - } - - [Test] - public void AutowireObjectByNameWithNoDependencyCheck() - { - DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); - RootObjectDefinition rod = new RootObjectDefinition(typeof(TestObject)); - lof.RegisterObjectDefinition("Spous", rod); - DependenciesObject obj = (DependenciesObject)lof.Autowire(typeof(DependenciesObject), AutoWiringMode.ByName, false); - Assert.IsNull(obj.Spouse); - } - - [Test] - public void AutowireObjectByType() - { - DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); - RootObjectDefinition rod = new RootObjectDefinition(typeof(TestObject)); - lof.RegisterObjectDefinition("test", rod); - DependenciesObject obj = (DependenciesObject)lof.Autowire(typeof(DependenciesObject), AutoWiringMode.ByType, true); - TestObject test = (TestObject)lof.GetObject("test"); - Assert.AreEqual(obj.Spouse, test); - } - - [Test] - public void AutowireObjectByTypeWithDependencyCheck() - { - DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); - Assert.Throws(() => lof.Autowire(typeof(DependenciesObject), AutoWiringMode.ByType, true)); - } - - [Test] - public void AutowireObjectByTypeWithNoDependencyCheck() - { - DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); - DependenciesObject obj = (DependenciesObject)lof.Autowire(typeof(DependenciesObject), AutoWiringMode.ByType, false); - Assert.IsNull(obj.Spouse); - } - - [Test] - public void AutowireExistingObjectByName() - { - DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); - RootObjectDefinition rod = new RootObjectDefinition(typeof(TestObject)); - lof.RegisterObjectDefinition("Spouse", rod); - DependenciesObject existingObj = new DependenciesObject(); - lof.AutowireObjectProperties(existingObj, AutoWiringMode.ByName, true); - TestObject spouse = (TestObject)lof.GetObject("Spouse"); - Assert.AreEqual(existingObj.Spouse, spouse); - Assert.IsTrue(ObjectFactoryUtils.ObjectOfType(lof, typeof(TestObject)) == spouse); - } - - [Test] - public void AutowireExistingObjectByNameWithDependencyCheck() - { - DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); - RootObjectDefinition rod = new RootObjectDefinition(typeof(TestObject)); - lof.RegisterObjectDefinition("Spous", rod); - DependenciesObject existingObj = new DependenciesObject(); - Assert.Throws(() => lof.AutowireObjectProperties(existingObj, AutoWiringMode.ByName, true)); - } - - [Test] - public void AutowireExistingObjectByNameWithNoDependencyCheck() - { - DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); - RootObjectDefinition rod = new RootObjectDefinition(typeof(TestObject)); - lof.RegisterObjectDefinition("Spous", rod); - DependenciesObject existingObj = new DependenciesObject(); - lof.AutowireObjectProperties(existingObj, AutoWiringMode.ByName, false); - Assert.IsNull(existingObj.Spouse); - } - - [Test] - public void AutowireExistingObjectByType() - { - DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); - RootObjectDefinition rod = new RootObjectDefinition(typeof(TestObject)); - lof.RegisterObjectDefinition("test", rod); - DependenciesObject existingObj = new DependenciesObject(); - lof.AutowireObjectProperties(existingObj, AutoWiringMode.ByType, true); - TestObject test = (TestObject)lof.GetObject("test"); - Assert.AreEqual(existingObj.Spouse, test); - } - - [Test] - public void AutowireByTypeWithInvalidAutowireMode() - { - DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); - DependenciesObject obj = new DependenciesObject(); - Assert.Throws(() => lof.AutowireObjectProperties(obj, AutoWiringMode.Constructor, true)); - } - - [Test] - public void AutowireExistingObjectByTypeWithDependencyCheck() - { - DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); - DependenciesObject existingObj = new DependenciesObject(); - Assert.Throws(() => lof.AutowireObjectProperties(existingObj, AutoWiringMode.ByType, true)); - } - - [Test] - public void AutowireExistingObjectByTypeWithNoDependencyCheck() - { - DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); - DependenciesObject existingObj = new DependenciesObject(); - lof.AutowireObjectProperties(existingObj, AutoWiringMode.ByType, false); - Assert.IsNull(existingObj.Spouse); - } - - [Test] - public void AutowireWithNoDependencies() - { - DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); - RootObjectDefinition rod = new RootObjectDefinition(typeof(TestObject)); - lof.RegisterObjectDefinition("rod", rod); - Assert.AreEqual(1, lof.ObjectDefinitionCount); - object registered = lof.Autowire(typeof(NoDependencies), AutoWiringMode.AutoDetect, false); - Assert.AreEqual(1, lof.ObjectDefinitionCount); - Assert.IsTrue(registered is NoDependencies); - } - - [Test] - public void AutowireWithSatisfiedObjectDependency() - { - DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); - MutablePropertyValues pvs = new MutablePropertyValues(); - pvs.Add(new PropertyValue("name", "Rod")); - RootObjectDefinition rood = new RootObjectDefinition(typeof(TestObject), pvs); - lof.RegisterObjectDefinition("rod", rood); - Assert.AreEqual(1, lof.ObjectDefinitionCount); - // Depends on age, name and spouse (TestObject) - object registered = lof.Autowire(typeof(DependenciesObject), AutoWiringMode.AutoDetect, true); - Assert.AreEqual(1, lof.ObjectDefinitionCount); - DependenciesObject kerry = (DependenciesObject)registered; - TestObject rod = (TestObject)lof.GetObject("rod"); - Assert.AreSame(rod, kerry.Spouse); - } - - [Test] - public void AutowireWithSatisfiedConstructorDependency() - { - DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); - MutablePropertyValues pvs = new MutablePropertyValues(); - pvs.Add(new PropertyValue("name", "Rod")); - RootObjectDefinition rood = new RootObjectDefinition(typeof(TestObject), pvs); - lof.RegisterObjectDefinition("rod", rood); - Assert.AreEqual(1, lof.ObjectDefinitionCount); - object registered = lof.Autowire(typeof(ConstructorDependency), AutoWiringMode.AutoDetect, false); - Assert.AreEqual(1, lof.ObjectDefinitionCount); - ConstructorDependency kerry = (ConstructorDependency)registered; - TestObject rod = (TestObject)lof.GetObject("rod"); - Assert.AreSame(rod, kerry._spouse); - } - - [Test] - public void AutowireWithUnsatisfiedConstructorDependency() - { - DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); - MutablePropertyValues pvs = new MutablePropertyValues(); - pvs.Add(new PropertyValue("name", "Rod")); + pvs.Add(new PropertyValue("Spouse", new RuntimeObjectReference("object" + (i < 99 ? i + 1 : 0)))); RootObjectDefinition rod = new RootObjectDefinition(typeof(TestObject), pvs); - lof.RegisterObjectDefinition("rod", rod); - Assert.AreEqual(1, lof.ObjectDefinitionCount); - Assert.Throws(() => lof.Autowire(typeof(UnsatisfiedConstructorDependency), AutoWiringMode.AutoDetect, true)); + lof.RegisterObjectDefinition("object" + i, rod); } - [Test] - public void ExtensiveCircularReference() + lof.PreInstantiateSingletons(); + for (int i = 0; i < 1000; i++) { - DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); - for (int i = 0; i < 1000; i++) - { - MutablePropertyValues pvs = new MutablePropertyValues(); - pvs.Add(new PropertyValue("Spouse", new RuntimeObjectReference("object" + (i < 99 ? i + 1 : 0)))); - RootObjectDefinition rod = new RootObjectDefinition(typeof(TestObject), pvs); - lof.RegisterObjectDefinition("object" + i, rod); - } - lof.PreInstantiateSingletons(); - for (int i = 0; i < 1000; i++) - { - TestObject obj = (TestObject)lof.GetObject("object" + i); - TestObject otherObj = (TestObject)lof.GetObject("object" + (i < 99 ? i + 1 : 0)); - Assert.IsTrue(obj.Spouse == otherObj); - } + TestObject obj = (TestObject) lof.GetObject("object" + i); + TestObject otherObj = (TestObject) lof.GetObject("object" + (i < 99 ? i + 1 : 0)); + Assert.IsTrue(obj.Spouse == otherObj); } + } - [Test] - public void PullingObjectWithFactoryMethodAlsoInjectsDependencies() + [Test] + public void PullingObjectWithFactoryMethodAlsoInjectsDependencies() + { + string expectedName = "Terese Raquin"; + MutablePropertyValues props = new MutablePropertyValues(); + props.Add(new PropertyValue("Name", expectedName)); + + RootObjectDefinition def = new RootObjectDefinition(typeof(MySingleton), props); + def.FactoryMethodName = "GetInstance"; + + DefaultListableObjectFactory fac = new DefaultListableObjectFactory(); + fac.RegisterObjectDefinition("foo", def); + + object foo = fac["foo"]; + Assert.IsNotNull(foo, "Couldn't pull manually registered instance out of the factory using factory method instantiation."); + MySingleton sing = (MySingleton) foo; + Assert.AreEqual(expectedName, sing.Name, "Dependency was not resolved pulling manually registered instance out of the factory using factory method instantiation."); + } + + [Test] + public void GetObjectWithArgsOnFactoryObject() + { + using (DefaultListableObjectFactory lof = new DefaultListableObjectFactory()) { - string expectedName = "Terese Raquin"; - MutablePropertyValues props = new MutablePropertyValues(); - props.Add(new PropertyValue("Name", expectedName)); + // DummyFactory produces a TestObject + RootObjectDefinition factoryObjectDef = new RootObjectDefinition(typeof(DummyFactory)); + factoryObjectDef.IsSingleton = true; + lof.RegisterObjectDefinition("factoryObject", factoryObjectDef); - RootObjectDefinition def = new RootObjectDefinition(typeof(MySingleton), props); - def.FactoryMethodName = "GetInstance"; - - DefaultListableObjectFactory fac = new DefaultListableObjectFactory(); - fac.RegisterObjectDefinition("foo", def); - - object foo = fac["foo"]; - Assert.IsNotNull(foo, "Couldn't pull manually registered instance out of the factory using factory method instantiation."); - MySingleton sing = (MySingleton)foo; - Assert.AreEqual(expectedName, sing.Name, "Dependency was not resolved pulling manually registered instance out of the factory using factory method instantiation."); - } - - [Test] - public void GetObjectWithArgsOnFactoryObject() - { - using (DefaultListableObjectFactory lof = new DefaultListableObjectFactory()) - { - // DummyFactory produces a TestObject - RootObjectDefinition factoryObjectDef = new RootObjectDefinition(typeof(DummyFactory)); - factoryObjectDef.IsSingleton = true; - lof.RegisterObjectDefinition("factoryObject", factoryObjectDef); - - // verify preconditions - TestObject to = lof.GetObject("factoryObject", null, null) as TestObject; - Assert.IsNotNull(to); - Assert.AreEqual(25, to.Age); - Assert.AreEqual(DummyFactory.SINGLETON_NAME, to.Name); - - try - { - to = lof.GetObject("factoryObject", new object[] {}) as TestObject; - Assert.Fail("should throw ObjectDefinitionStoreException"); - } - catch (ObjectDefinitionStoreException ex) - { - Assert.IsTrue( ex.Message.IndexOf("Cannot specify arguments in the GetObject () method when referring to a factory object definition") > -1); - } - - try - { - to = lof.GetObject("factoryObject", new object[] { "Mark", "35" }) as TestObject; - Assert.Fail("should throw ObjectDefinitionStoreException"); - } - catch (ObjectDefinitionStoreException ex) - { - Assert.IsTrue( ex.Message.IndexOf("Cannot specify arguments in the GetObject () method when referring to a factory object definition") > -1); - } - } - } - - [Test(Description = "http://opensource.atlassian.com/projects/spring/browse/SPRNET-368")] - public void GetObjectWithCtorArgsAndCtorAutowiring() - { - using (DefaultListableObjectFactory lof = new DefaultListableObjectFactory()) - { - RootObjectDefinition prototype - = new RootObjectDefinition(typeof(TestObject)); - prototype.IsSingleton = false; - lof.RegisterObjectDefinition("prototype", prototype); - - TestObject to = lof.GetObject("prototype", new object[] { "Bruno", 26, new NestedTestObject("Home") }) as TestObject; - Assert.IsNotNull(to); - Assert.AreEqual(26, to.Age); - Assert.AreEqual("Bruno", to.Name); - Assert.AreEqual("Home", to.Doctor.Company); - } - } - - [Test] - public void GetObjectWithCtorArgsOnPrototype() - { - using (DefaultListableObjectFactory lof = new DefaultListableObjectFactory()) - { - RootObjectDefinition prototype - = new RootObjectDefinition(typeof(TestObject)); - prototype.IsSingleton = false; - lof.RegisterObjectDefinition("prototype", prototype); - - TestObject to = lof.GetObject("prototype", new object[] { "Mark", 35 }) as TestObject; - Assert.IsNotNull(to); - Assert.AreEqual(35, to.Age); - Assert.AreEqual("Mark", to.Name); - } - } - - [Test] - [Ignore("Ordering must now be strict when providing array of arguments for ctors")] - public void GetObjectWithCtorArgsOnPrototypeOutOfOrderArgs() - { - using (DefaultListableObjectFactory lof = new DefaultListableObjectFactory()) - { - RootObjectDefinition prototype - = new RootObjectDefinition(typeof(TestObject)); - prototype.IsSingleton = false; - lof.RegisterObjectDefinition("prototype", prototype); - - try - { - TestObject to2 = lof.GetObject("prototype", new object[] { 35, "Mark" }) as TestObject; - Assert.IsNotNull(to2); - Assert.AreEqual(35, to2.Age); - Assert.AreEqual("Mark", to2.Name); - } - catch (ObjectCreationException ex) - { - Assert.IsTrue(ex.Message.IndexOf("'Object of type 'System.Int32' cannot be converted to type 'System.String'") >= 0); - } - } - } - - [Test] - public void GetObjectWithCtorArgsOnSingleton() - { - using (DefaultListableObjectFactory lof = new DefaultListableObjectFactory()) - { - RootObjectDefinition singleton - = new RootObjectDefinition(typeof(TestObject)); - singleton.IsSingleton = true; - lof.RegisterObjectDefinition("singleton", singleton); - - TestObject to = lof.GetObject("singleton", new object[] { "Mark", 35 }) as TestObject; - Assert.IsNotNull(to); - Assert.AreEqual(35, to.Age); - Assert.AreEqual("Mark", to.Name); - } - } - - [Test] - public void GetObjectWithCtorArgsOverrided() - { - using (DefaultListableObjectFactory lof = new DefaultListableObjectFactory()) - { - ConstructorArgumentValues arguments = new ConstructorArgumentValues(); - arguments.AddNamedArgumentValue("age", 27); - arguments.AddNamedArgumentValue("name", "Bruno"); - RootObjectDefinition singleton - = new RootObjectDefinition(typeof(TestObject), arguments, new MutablePropertyValues()); - singleton.IsSingleton = true; - lof.RegisterObjectDefinition("singleton", singleton); - - TestObject to = lof.GetObject("singleton", new object[] { "Mark", 35 }) as TestObject; - Assert.IsNotNull(to); - Assert.AreEqual(35, to.Age); - Assert.AreEqual("Mark", to.Name); - - TestObject to2 = lof.GetObject("singleton") as TestObject; - Assert.IsNotNull(to2); - Assert.AreEqual(27, to2.Age); - Assert.AreEqual("Bruno", to2.Name); - } - } - - [Test(Description = "http://opensource.atlassian.com/projects/spring/browse/SPRNET-368")] - public void CreateObjectWithCtorArgsAndCtorAutowiring() - { - using (DefaultListableObjectFactory lof = new DefaultListableObjectFactory()) - { - RootObjectDefinition prototype = new RootObjectDefinition(typeof(TestObject)); - prototype.IsSingleton = false; - lof.RegisterObjectDefinition("prototype", prototype); - - TestObject to = lof.CreateObject("prototype", typeof(TestObject), new object[] { "Bruno", 26, new NestedTestObject("Home") }) as TestObject; - Assert.IsNotNull(to); - Assert.AreEqual(26, to.Age); - Assert.AreEqual("Bruno", to.Name); - Assert.AreEqual("Home", to.Doctor.Company); - } - } - - [Test] - public void CreateObjectWithCtorArgsOnPrototype() - { - using (DefaultListableObjectFactory lof = new DefaultListableObjectFactory()) - { - RootObjectDefinition prototype = new RootObjectDefinition(typeof(TestObject)); - prototype.IsSingleton = false; - lof.RegisterObjectDefinition("prototype", prototype); - - TestObject to = lof.CreateObject("prototype", typeof(TestObject), new object[] { "Mark", 35 }) as TestObject; - Assert.IsNotNull(to); - Assert.AreEqual(35, to.Age); - Assert.AreEqual("Mark", to.Name); - } - } - - [Test] - [Ignore("Ordering must now be strict when providing array of arguments for ctors")] - public void CreateObjectWithCtorArgsOnPrototypeOutOfOrderArgs() - { - using (DefaultListableObjectFactory lof = new DefaultListableObjectFactory()) - { - RootObjectDefinition prototype - = new RootObjectDefinition(typeof(TestObject)); - prototype.IsSingleton = false; - lof.RegisterObjectDefinition("prototype", prototype); - - try - { - TestObject to2 = lof.CreateObject("prototype", typeof(TestObject), new object[] { 35, "Mark" }) as TestObject; - Assert.IsNotNull(to2); - Assert.AreEqual(35, to2.Age); - Assert.AreEqual("Mark", to2.Name); - } - catch (ObjectCreationException ex) - { - Assert.IsTrue(ex.Message.IndexOf("'Object of type 'System.Int32' cannot be converted to type 'System.String'") >= 0); - } - } - } - - [Test] - public void CreateObjectWithCtorArgsOnSingleton() - { - using (DefaultListableObjectFactory lof = new DefaultListableObjectFactory()) - { - RootObjectDefinition singleton - = new RootObjectDefinition(typeof(TestObject)); - singleton.IsSingleton = true; - lof.RegisterObjectDefinition("singleton", singleton); - - TestObject to = lof.CreateObject("singleton", typeof(TestObject), new object[] { "Mark", 35 }) as TestObject; - Assert.IsNotNull(to); - Assert.AreEqual(35, to.Age); - Assert.AreEqual("Mark", to.Name); - } - } - - [Test] - public void CreateObjectWithCtorArgsOverrided() - { - using (DefaultListableObjectFactory lof = new DefaultListableObjectFactory()) - { - ConstructorArgumentValues arguments = new ConstructorArgumentValues(); - arguments.AddNamedArgumentValue("age", 27); - arguments.AddNamedArgumentValue("name", "Bruno"); - RootObjectDefinition singleton = new RootObjectDefinition(typeof(TestObject), arguments, new MutablePropertyValues()); - singleton.IsSingleton = true; - lof.RegisterObjectDefinition("singleton", singleton); - - TestObject to = lof.CreateObject("singleton", typeof(TestObject), new object[] { "Mark", 35 }) as TestObject; - Assert.IsNotNull(to); - Assert.AreEqual(35, to.Age); - Assert.AreEqual("Mark", to.Name); - - TestObject to2 = lof.CreateObject("singleton", null, null) as TestObject; - Assert.IsNotNull(to2); - Assert.AreEqual(27, to2.Age); - Assert.AreEqual("Bruno", to2.Name); - } - } - - [Test] - public void CreateObjectDoesNotConfigure() - { - using (DefaultListableObjectFactory lof = new DefaultListableObjectFactory()) - { - MutablePropertyValues properties = new MutablePropertyValues(); - properties.Add(new PropertyValue("Age", 27)); - properties.Add(new PropertyValue("Name", "Bruno")); - RootObjectDefinition singleton = new RootObjectDefinition(typeof(TestObject), null, properties); - singleton.IsSingleton = true; - lof.RegisterObjectDefinition("singleton", singleton); - - TestObject to2 = lof.CreateObject("singleton", typeof(TestObject), null) as TestObject; - Assert.IsNotNull(to2); - // no props set - Assert.AreEqual(0, to2.Age); - Assert.AreEqual(null, to2.Name); - // no object postprocessors executed! - Assert.AreEqual(null, to2.ObjectName); - Assert.AreEqual(null, to2.ObjectFactory); - Assert.AreEqual(null, to2.SharedState); - } - } - - [Test] - public void CreateObjectDoesAffectContainerManagedSingletons() - { - using (DefaultListableObjectFactory lof = new DefaultListableObjectFactory()) - { - lof.AddObjectPostProcessor(new SharedStateAwareProcessor(new ISharedStateFactory[] { new ByTypeSharedStateFactory() }, Int32.MaxValue )); - - MutablePropertyValues properties = new MutablePropertyValues(); - properties.Add(new PropertyValue("Age", 27)); - properties.Add(new PropertyValue("Name", "Bruno")); - RootObjectDefinition singleton = new RootObjectDefinition(typeof(TestObject), null, properties); - singleton.IsSingleton = true; - lof.RegisterObjectDefinition("singleton", singleton); - - // a call to GetObject() results in a normally configured instance - TestObject to = lof.GetObject("singleton") as TestObject; - Assert.IsNotNull(to); - // props set - Assert.AreEqual(27, to.Age); - Assert.AreEqual("Bruno", to.Name); - // object postprocessors executed! - Assert.AreEqual("singleton", to.ObjectName); - Assert.AreEqual(lof, to.ObjectFactory); - Assert.IsNotNull(to.SharedState); - - // altough configured as singleton, calling CreateObject prevents the instance from being cached - // otherwise the container could not guarantee the results of calling GetObject() to other clients. - TestObject to2 = lof.CreateObject("singleton", typeof(TestObject), null) as TestObject; - Assert.IsNotNull(to2); - // no props set - Assert.AreEqual(0, to2.Age); - Assert.AreEqual(null, to2.Name); - // no object postprocessors executed! - Assert.AreEqual(null, to2.ObjectName); - Assert.AreEqual(null, to2.ObjectFactory); - Assert.AreEqual(null, to2.SharedState); - - // a call to GetObject() results in a normally configured instance - TestObject to3 = lof.GetObject("singleton") as TestObject; - Assert.IsNotNull(to3); - // props set - Assert.AreEqual(27, to3.Age); - Assert.AreEqual("Bruno", to3.Name); - // object postprocessors executed! - Assert.AreEqual("singleton", to3.ObjectName); - Assert.AreEqual(lof, to3.ObjectFactory); - Assert.IsNotNull(to3.SharedState); - } - } - - [Test] - public void CreateObjectWithAllNamedCtorArguments() - { - string expectedName = "Bingo"; - int expectedAge = 1023; - ConstructorArgumentValues values = new ConstructorArgumentValues(); - values.AddNamedArgumentValue("age", expectedAge); - values.AddNamedArgumentValue("name", expectedName); - RootObjectDefinition def = new RootObjectDefinition(typeof(TestObject), values, new MutablePropertyValues()); - DefaultListableObjectFactory fac = new DefaultListableObjectFactory(); - fac.RegisterObjectDefinition("foo", def); - - ITestObject foo = fac["foo"] as ITestObject; - Assert.IsNotNull(foo, "Couldn't pull manually registered instance out of the factory."); - Assert.AreEqual(expectedName, foo.Name, "Dependency 'name' was not resolved using a named ctor arg."); - Assert.AreEqual(expectedAge, foo.Age, "Dependency 'age' was not resolved using a named ctor arg."); - } - - [Test] - public void CreateObjectWithAllNamedCtorArgumentsIsCaseInsensitive() - { - string expectedName = "Bingo"; - int expectedAge = 1023; - ConstructorArgumentValues values = new ConstructorArgumentValues(); - values.AddNamedArgumentValue("aGe", expectedAge); - values.AddNamedArgumentValue("naME", expectedName); - RootObjectDefinition def = new RootObjectDefinition(typeof(TestObject), values, new MutablePropertyValues()); - DefaultListableObjectFactory fac = new DefaultListableObjectFactory(); - fac.RegisterObjectDefinition("foo", def); - - ITestObject foo = fac["foo"] as ITestObject; - Assert.IsNotNull(foo, "Couldn't pull manually registered instance out of the factory."); - Assert.AreEqual(expectedName, foo.Name, "Dependency 'name' was not resolved using a named ctor arg."); - Assert.AreEqual(expectedAge, foo.Age, "Dependency 'age' was not resolved using a named ctor arg."); - } - - [Test] - public void CreateObjectWithMixOfNamedAndIndexedCtorArguments() - { - string expectedName = "Bingo"; - int expectedAge = 1023; - ConstructorArgumentValues values = new ConstructorArgumentValues(); - values.AddNamedArgumentValue("age", expectedAge); - values.AddIndexedArgumentValue(0, expectedName); - RootObjectDefinition def = new RootObjectDefinition(typeof(TestObject), values, new MutablePropertyValues()); - DefaultListableObjectFactory fac = new DefaultListableObjectFactory(); - fac.RegisterObjectDefinition("foo", def); - - ITestObject foo = fac["foo"] as ITestObject; - Assert.IsNotNull(foo, "Couldn't pull manually registered instance out of the factory."); - Assert.AreEqual(expectedName, foo.Name, "Dependency 'name' was not resolved an indexed ctor arg."); - Assert.AreEqual(expectedAge, foo.Age, "Dependency 'age' was not resolved using a named ctor arg."); - } - - [Test] - public void CreateObjectWithMixOfNamedAndIndexedAndAutowiredCtorArguments() - { - string expectedCompany = "Griffin's Foosball Arcade"; - MutablePropertyValues autoProps = new MutablePropertyValues(); - autoProps.Add(new PropertyValue("Company", expectedCompany)); - RootObjectDefinition autowired = new RootObjectDefinition(typeof(NestedTestObject), autoProps); - - string expectedName = "Bingo"; - int expectedAge = 1023; - ConstructorArgumentValues values = new ConstructorArgumentValues(); - values.AddNamedArgumentValue("age", expectedAge); - values.AddIndexedArgumentValue(0, expectedName); - RootObjectDefinition def = new RootObjectDefinition(typeof(TestObject), values, new MutablePropertyValues()); - def.AutowireMode = AutoWiringMode.Constructor; - DefaultListableObjectFactory fac = new DefaultListableObjectFactory(); - fac.RegisterObjectDefinition("foo", def); - fac.RegisterObjectDefinition("doctor", autowired); - - ITestObject foo = fac["foo"] as ITestObject; - Assert.IsNotNull(foo, "Couldn't pull manually registered instance out of the factory."); - Assert.AreEqual(expectedName, foo.Name, "Dependency 'name' was not resolved an indexed ctor arg."); - Assert.AreEqual(expectedAge, foo.Age, "Dependency 'age' was not resolved using a named ctor arg."); - Assert.AreEqual(expectedCompany, foo.Doctor.Company, "Dependency 'doctor.Company' was not resolved using autowiring."); - } - - [Test] - public void CreateObjectWithMixOfIndexedAndTwoNamedSameTypeCtorArguments() - { - // this object will be passed in as a named constructor argument - string expectedCompany = "Griffin's Foosball Arcade"; - MutablePropertyValues autoProps = new MutablePropertyValues(); - autoProps.Add(new PropertyValue("Company", expectedCompany)); - RootObjectDefinition autowired = new RootObjectDefinition(typeof(NestedTestObject), autoProps); - - // this object will be passed in as a named constructor argument - string expectedLawyersCompany = "Pollack, Pounce, & Pulverise"; - MutablePropertyValues lawyerProps = new MutablePropertyValues(); - lawyerProps.Add(new PropertyValue("Company", expectedLawyersCompany)); - RootObjectDefinition lawyer = new RootObjectDefinition(typeof(NestedTestObject), lawyerProps); - - // this simple string object will be passed in as an indexed constructor argument - string expectedName = "Bingo"; - - // this simple integer object will be passed in as a named constructor argument - int expectedAge = 1023; - - ConstructorArgumentValues values = new ConstructorArgumentValues(); - - // lets mix the order up a little... - values.AddNamedArgumentValue("age", expectedAge); - values.AddIndexedArgumentValue(0, expectedName); - values.AddNamedArgumentValue("doctor", new RuntimeObjectReference("a_doctor")); - values.AddNamedArgumentValue("lawyer", new RuntimeObjectReference("a_lawyer")); - - RootObjectDefinition def = new RootObjectDefinition(typeof(TestObject), values, new MutablePropertyValues()); - - DefaultListableObjectFactory fac = new DefaultListableObjectFactory(); - // the object we're attempting to resolve... - fac.RegisterObjectDefinition("foo", def); - // the object that will be looked up and passed as a named parameter to a ctor call... - fac.RegisterObjectDefinition("a_doctor", autowired); - // another object that will be looked up and passed as a named parameter to a ctor call... - fac.RegisterObjectDefinition("a_lawyer", lawyer); - - ITestObject foo = fac["foo"] as ITestObject; - Assert.IsNotNull(foo, "Couldn't pull manually registered instance out of the factory."); - Assert.AreEqual(expectedName, foo.Name, "Dependency 'name' was not resolved an indexed ctor arg."); - Assert.AreEqual(expectedAge, foo.Age, "Dependency 'age' was not resolved using a named ctor arg."); - Assert.AreEqual(expectedCompany, foo.Doctor.Company, "Dependency 'doctor.Company' was not resolved using autowiring."); - Assert.AreEqual(expectedLawyersCompany, foo.Lawyer.Company, "Dependency 'lawyer.Company' was not resolved using another named ctor arg."); - } - - [Test] - public void CircularDependencyIsCorrectlyDetected() - { - RootObjectDefinition foo = new RootObjectDefinition(typeof(TestObject)); - foo.ConstructorArgumentValues.AddNamedArgumentValue("spouse", new RuntimeObjectReference("bar")); - RootObjectDefinition bar = new RootObjectDefinition(typeof(TestObject)); - bar.ConstructorArgumentValues.AddNamedArgumentValue("spouse", new RuntimeObjectReference("foo")); - - DefaultListableObjectFactory fac = new DefaultListableObjectFactory(); - fac.RegisterObjectDefinition("foo", foo); - fac.RegisterObjectDefinition("bar", bar); + // verify preconditions + TestObject to = lof.GetObject("factoryObject", null, null) as TestObject; + Assert.IsNotNull(to); + Assert.AreEqual(25, to.Age); + Assert.AreEqual(DummyFactory.SINGLETON_NAME, to.Name); try { - fac.GetObject("foo"); + to = lof.GetObject("factoryObject", new object[] { }) as TestObject; + Assert.Fail("should throw ObjectDefinitionStoreException"); + } + catch (ObjectDefinitionStoreException ex) + { + Assert.IsTrue(ex.Message.IndexOf("Cannot specify arguments in the GetObject () method when referring to a factory object definition") > -1); + } + + try + { + to = lof.GetObject("factoryObject", new object[] { "Mark", "35" }) as TestObject; + Assert.Fail("should throw ObjectDefinitionStoreException"); + } + catch (ObjectDefinitionStoreException ex) + { + Assert.IsTrue(ex.Message.IndexOf("Cannot specify arguments in the GetObject () method when referring to a factory object definition") > -1); + } + } + } + + [Test(Description = "http://opensource.atlassian.com/projects/spring/browse/SPRNET-368")] + public void GetObjectWithCtorArgsAndCtorAutowiring() + { + using (DefaultListableObjectFactory lof = new DefaultListableObjectFactory()) + { + RootObjectDefinition prototype + = new RootObjectDefinition(typeof(TestObject)); + prototype.IsSingleton = false; + lof.RegisterObjectDefinition("prototype", prototype); + + TestObject to = lof.GetObject("prototype", new object[] { "Bruno", 26, new NestedTestObject("Home") }) as TestObject; + Assert.IsNotNull(to); + Assert.AreEqual(26, to.Age); + Assert.AreEqual("Bruno", to.Name); + Assert.AreEqual("Home", to.Doctor.Company); + } + } + + [Test] + public void GetObjectWithCtorArgsOnPrototype() + { + using (DefaultListableObjectFactory lof = new DefaultListableObjectFactory()) + { + RootObjectDefinition prototype + = new RootObjectDefinition(typeof(TestObject)); + prototype.IsSingleton = false; + lof.RegisterObjectDefinition("prototype", prototype); + + TestObject to = lof.GetObject("prototype", new object[] { "Mark", 35 }) as TestObject; + Assert.IsNotNull(to); + Assert.AreEqual(35, to.Age); + Assert.AreEqual("Mark", to.Name); + } + } + + [Test] + [Ignore("Ordering must now be strict when providing array of arguments for ctors")] + public void GetObjectWithCtorArgsOnPrototypeOutOfOrderArgs() + { + using (DefaultListableObjectFactory lof = new DefaultListableObjectFactory()) + { + RootObjectDefinition prototype + = new RootObjectDefinition(typeof(TestObject)); + prototype.IsSingleton = false; + lof.RegisterObjectDefinition("prototype", prototype); + + try + { + TestObject to2 = lof.GetObject("prototype", new object[] { 35, "Mark" }) as TestObject; + Assert.IsNotNull(to2); + Assert.AreEqual(35, to2.Age); + Assert.AreEqual("Mark", to2.Name); } catch (ObjectCreationException ex) { - Assert.AreEqual(typeof(ObjectCurrentlyInCreationException), ex.GetBaseException().GetType(), - "Circular dependency was set up; should have caught an ObjectCurrentlyInCreationException instance."); + Assert.IsTrue(ex.Message.IndexOf("'Object of type 'System.Int32' cannot be converted to type 'System.String'") >= 0); } } + } - [Test] - public void ConfigurableFactoryObjectInline() + [Test] + public void GetObjectWithCtorArgsOnSingleton() + { + using (DefaultListableObjectFactory lof = new DefaultListableObjectFactory()) { - DefaultListableObjectFactory dlof = new DefaultListableObjectFactory(); + RootObjectDefinition singleton + = new RootObjectDefinition(typeof(TestObject)); + singleton.IsSingleton = true; + lof.RegisterObjectDefinition("singleton", singleton); - RootObjectDefinition everyman = new RootObjectDefinition(); - everyman.PropertyValues = new MutablePropertyValues(); - everyman.PropertyValues.Add("name", "Noone"); - everyman.PropertyValues.Add("age", 9781); - - RootObjectDefinition factory = new RootObjectDefinition(); - factory.ObjectType = typeof(DummyConfigurableFactory); - factory.PropertyValues = new MutablePropertyValues(); - factory.PropertyValues.Add("ProductTemplate", everyman); - dlof.RegisterObjectDefinition("factory", factory); - - TestObject instance = dlof.GetObject("factory") as TestObject; - Assert.IsNotNull(instance); - - Assert.AreEqual("Noone", instance.Name, "Name dependency injected via IConfigurableObjectFactory (instance) failed (was 'Factory singleton')."); - Assert.AreEqual(9781, instance.Age, "Age dependency injected via IObjectFactory.ConfigureObject(instance) failed (was 25)."); + TestObject to = lof.GetObject("singleton", new object[] { "Mark", 35 }) as TestObject; + Assert.IsNotNull(to); + Assert.AreEqual(35, to.Age); + Assert.AreEqual("Mark", to.Name); } + } - [Test] - public void ConfigurableFactoryObjectReference() + [Test] + public void GetObjectWithCtorArgsOverrided() + { + using (DefaultListableObjectFactory lof = new DefaultListableObjectFactory()) { - DefaultListableObjectFactory dlof = new DefaultListableObjectFactory(); + ConstructorArgumentValues arguments = new ConstructorArgumentValues(); + arguments.AddNamedArgumentValue("age", 27); + arguments.AddNamedArgumentValue("name", "Bruno"); + RootObjectDefinition singleton + = new RootObjectDefinition(typeof(TestObject), arguments, new MutablePropertyValues()); + singleton.IsSingleton = true; + lof.RegisterObjectDefinition("singleton", singleton); - RootObjectDefinition everyman = new RootObjectDefinition(); - everyman.IsAbstract = true; - everyman.PropertyValues = new MutablePropertyValues(); - everyman.PropertyValues.Add("name", "Noone"); - everyman.PropertyValues.Add("age", 9781); - dlof.RegisterObjectDefinition("everyman", everyman); + TestObject to = lof.GetObject("singleton", new object[] { "Mark", 35 }) as TestObject; + Assert.IsNotNull(to); + Assert.AreEqual(35, to.Age); + Assert.AreEqual("Mark", to.Name); - RootObjectDefinition factory = new RootObjectDefinition(); - factory.ObjectType = typeof(DummyConfigurableFactory); - factory.PropertyValues = new MutablePropertyValues(); - factory.PropertyValues.Add("ProductTemplate", new RuntimeObjectReference("everyman")); - dlof.RegisterObjectDefinition("factory", factory); - - TestObject instance = dlof.GetObject("factory") as TestObject; - Assert.IsNotNull(instance); - - Assert.AreEqual("Noone", instance.Name, "Name dependency injected via IConfigurableObjectFactory (instance) failed (was 'Factory singleton')."); - Assert.AreEqual(9781, instance.Age, "Age dependency injected via IObjectFactory.ConfigureObject(instance) failed (was 25)."); + TestObject to2 = lof.GetObject("singleton") as TestObject; + Assert.IsNotNull(to2); + Assert.AreEqual(27, to2.Age); + Assert.AreEqual("Bruno", to2.Name); } + } - [Test] - public void ConfigureObject() + [Test(Description = "http://opensource.atlassian.com/projects/spring/browse/SPRNET-368")] + public void CreateObjectWithCtorArgsAndCtorAutowiring() + { + using (DefaultListableObjectFactory lof = new DefaultListableObjectFactory()) { - TestObject instance = new TestObject(); - RootObjectDefinition everyman = new RootObjectDefinition(); - everyman.IsAbstract = true; - everyman.PropertyValues = new MutablePropertyValues(); - everyman.PropertyValues.Add("name", "Noone"); - everyman.PropertyValues.Add("age", 9781); - DefaultListableObjectFactory fac = new DefaultListableObjectFactory(); - fac.RegisterObjectDefinition(instance.GetType().FullName, everyman); - fac.ConfigureObject(instance, instance.GetType().FullName); - Assert.AreEqual("Noone", instance.Name, "Name dependency injected via IObjectFactory.ConfigureObject(instance) failed (was null)."); - Assert.AreEqual(9781, instance.Age, "Age dependency injected via IObjectFactory.ConfigureObject(instance) failed (was null)."); + RootObjectDefinition prototype = new RootObjectDefinition(typeof(TestObject)); + prototype.IsSingleton = false; + lof.RegisterObjectDefinition("prototype", prototype); + + TestObject to = lof.CreateObject("prototype", typeof(TestObject), new object[] { "Bruno", 26, new NestedTestObject("Home") }) as TestObject; + Assert.IsNotNull(to); + Assert.AreEqual(26, to.Age); + Assert.AreEqual("Bruno", to.Name); + Assert.AreEqual("Home", to.Doctor.Company); } + } - [Test] - public void ConfigureObjectViaExplicitName() + [Test] + public void CreateObjectWithCtorArgsOnPrototype() + { + using (DefaultListableObjectFactory lof = new DefaultListableObjectFactory()) { - TestObject instance = new TestObject(); - RootObjectDefinition everyman = new RootObjectDefinition(); - everyman.IsAbstract = true; - everyman.PropertyValues = new MutablePropertyValues(); - everyman.PropertyValues.Add("name", "Noone"); - everyman.PropertyValues.Add("age", 9781); - DefaultListableObjectFactory fac = new DefaultListableObjectFactory(); - fac.RegisterObjectDefinition("everyman", everyman); - fac.ConfigureObject(instance, "everyman"); - Assert.AreEqual(true, instance.InitCompleted, "AfterPropertiesSet() was not invoked by IObjectFactory.ConfigureObject(instance)."); - Assert.AreEqual("Noone", instance.Name, "Name dependency injected via IObjectFactory.ConfigureObject(instance) failed (was null)."); - Assert.AreEqual(9781, instance.Age, "Age dependency injected via IObjectFactory.ConfigureObject(instance) failed (was null)."); + RootObjectDefinition prototype = new RootObjectDefinition(typeof(TestObject)); + prototype.IsSingleton = false; + lof.RegisterObjectDefinition("prototype", prototype); + + TestObject to = lof.CreateObject("prototype", typeof(TestObject), new object[] { "Mark", 35 }) as TestObject; + Assert.IsNotNull(to); + Assert.AreEqual(35, to.Age); + Assert.AreEqual("Mark", to.Name); } + } - [Test] - public void ConfigureObjectViaNullName() + [Test] + [Ignore("Ordering must now be strict when providing array of arguments for ctors")] + public void CreateObjectWithCtorArgsOnPrototypeOutOfOrderArgs() + { + using (DefaultListableObjectFactory lof = new DefaultListableObjectFactory()) { - TestObject instance = new TestObject(); - DefaultListableObjectFactory fac = new DefaultListableObjectFactory(); - Assert.Throws(() => fac.ConfigureObject(instance, null)); - } + RootObjectDefinition prototype + = new RootObjectDefinition(typeof(TestObject)); + prototype.IsSingleton = false; + lof.RegisterObjectDefinition("prototype", prototype); - [Test] - public void ConfigureObjectViaLoadOfOldWhitespaceName() - { - TestObject instance = new TestObject(); - DefaultListableObjectFactory fac = new DefaultListableObjectFactory(); - Assert.Throws(() => fac.ConfigureObject(instance, " \t")); - } - - [Test] - public void ConfigureObjectViaEmptyName() - { - TestObject instance = new TestObject(); - DefaultListableObjectFactory fac = new DefaultListableObjectFactory(); - Assert.Throws(() => fac.ConfigureObject(instance, string.Empty)); - } - - [Test] - public void DisposeCyclesThroughAllSingletonsEvenIfTheirDisposeThrowsAnException() - { - RootObjectDefinition foo = new RootObjectDefinition(typeof(GoodDisposable)); - foo.IsSingleton = true; - RootObjectDefinition bar = new RootObjectDefinition(typeof(BadDisposable)); - bar.IsSingleton = true; - RootObjectDefinition baz = new RootObjectDefinition(typeof(GoodDisposable)); - baz.IsSingleton = true; - - using (DefaultListableObjectFactory fac = new DefaultListableObjectFactory()) + try { - fac.RegisterObjectDefinition("foo", foo); - fac.RegisterObjectDefinition("bar", bar); - fac.RegisterObjectDefinition("baz", baz); - fac.PreInstantiateSingletons(); + TestObject to2 = lof.CreateObject("prototype", typeof(TestObject), new object[] { 35, "Mark" }) as TestObject; + Assert.IsNotNull(to2); + Assert.AreEqual(35, to2.Age); + Assert.AreEqual("Mark", to2.Name); + } + catch (ObjectCreationException ex) + { + Assert.IsTrue(ex.Message.IndexOf("'Object of type 'System.Int32' cannot be converted to type 'System.String'") >= 0); } - Assert.AreEqual(2, GoodDisposable.DisposeCount, "All IDisposable singletons must have their Dispose() method called... one of them bailed, and as a result the rest were (apparently) not Dispose()d."); - GoodDisposable.DisposeCount = 0; } + } - [Test] - public void StaticInitializationViaDependsOnSingletonMethodInvokingFactoryObject() + [Test] + public void CreateObjectWithCtorArgsOnSingleton() + { + using (DefaultListableObjectFactory lof = new DefaultListableObjectFactory()) { - RootObjectDefinition initializer = new RootObjectDefinition(typeof(MethodInvokingFactoryObject)); - initializer.PropertyValues.Add("TargetMethod", "Init"); - initializer.PropertyValues.Add("TargetType", typeof(StaticInitializer).AssemblyQualifiedName); + RootObjectDefinition singleton + = new RootObjectDefinition(typeof(TestObject)); + singleton.IsSingleton = true; + lof.RegisterObjectDefinition("singleton", singleton); - RootObjectDefinition foo = new RootObjectDefinition(typeof(TestObject)); - foo.DependsOn = new string[] { "force-init" }; + TestObject to = lof.CreateObject("singleton", typeof(TestObject), new object[] { "Mark", 35 }) as TestObject; + Assert.IsNotNull(to); + Assert.AreEqual(35, to.Age); + Assert.AreEqual("Mark", to.Name); + } + } - DefaultListableObjectFactory fac = new DefaultListableObjectFactory(); - fac.RegisterObjectDefinition("foo", foo); - fac.RegisterObjectDefinition("force-init", initializer); + [Test] + public void CreateObjectWithCtorArgsOverrided() + { + using (DefaultListableObjectFactory lof = new DefaultListableObjectFactory()) + { + ConstructorArgumentValues arguments = new ConstructorArgumentValues(); + arguments.AddNamedArgumentValue("age", 27); + arguments.AddNamedArgumentValue("name", "Bruno"); + RootObjectDefinition singleton = new RootObjectDefinition(typeof(TestObject), arguments, new MutablePropertyValues()); + singleton.IsSingleton = true; + lof.RegisterObjectDefinition("singleton", singleton); + TestObject to = lof.CreateObject("singleton", typeof(TestObject), new object[] { "Mark", 35 }) as TestObject; + Assert.IsNotNull(to); + Assert.AreEqual(35, to.Age); + Assert.AreEqual("Mark", to.Name); + + TestObject to2 = lof.CreateObject("singleton", null, null) as TestObject; + Assert.IsNotNull(to2); + Assert.AreEqual(27, to2.Age); + Assert.AreEqual("Bruno", to2.Name); + } + } + + [Test] + public void CreateObjectDoesNotConfigure() + { + using (DefaultListableObjectFactory lof = new DefaultListableObjectFactory()) + { + MutablePropertyValues properties = new MutablePropertyValues(); + properties.Add(new PropertyValue("Age", 27)); + properties.Add(new PropertyValue("Name", "Bruno")); + RootObjectDefinition singleton = new RootObjectDefinition(typeof(TestObject), null, properties); + singleton.IsSingleton = true; + lof.RegisterObjectDefinition("singleton", singleton); + + TestObject to2 = lof.CreateObject("singleton", typeof(TestObject), null) as TestObject; + Assert.IsNotNull(to2); + // no props set + Assert.AreEqual(0, to2.Age); + Assert.AreEqual(null, to2.Name); + // no object postprocessors executed! + Assert.AreEqual(null, to2.ObjectName); + Assert.AreEqual(null, to2.ObjectFactory); + Assert.AreEqual(null, to2.SharedState); + } + } + + [Test] + public void CreateObjectDoesAffectContainerManagedSingletons() + { + using (DefaultListableObjectFactory lof = new DefaultListableObjectFactory()) + { + lof.AddObjectPostProcessor(new SharedStateAwareProcessor(new ISharedStateFactory[] { new ByTypeSharedStateFactory() }, Int32.MaxValue)); + + MutablePropertyValues properties = new MutablePropertyValues(); + properties.Add(new PropertyValue("Age", 27)); + properties.Add(new PropertyValue("Name", "Bruno")); + RootObjectDefinition singleton = new RootObjectDefinition(typeof(TestObject), null, properties); + singleton.IsSingleton = true; + lof.RegisterObjectDefinition("singleton", singleton); + + // a call to GetObject() results in a normally configured instance + TestObject to = lof.GetObject("singleton") as TestObject; + Assert.IsNotNull(to); + // props set + Assert.AreEqual(27, to.Age); + Assert.AreEqual("Bruno", to.Name); + // object postprocessors executed! + Assert.AreEqual("singleton", to.ObjectName); + Assert.AreEqual(lof, to.ObjectFactory); + Assert.IsNotNull(to.SharedState); + + // altough configured as singleton, calling CreateObject prevents the instance from being cached + // otherwise the container could not guarantee the results of calling GetObject() to other clients. + TestObject to2 = lof.CreateObject("singleton", typeof(TestObject), null) as TestObject; + Assert.IsNotNull(to2); + // no props set + Assert.AreEqual(0, to2.Age); + Assert.AreEqual(null, to2.Name); + // no object postprocessors executed! + Assert.AreEqual(null, to2.ObjectName); + Assert.AreEqual(null, to2.ObjectFactory); + Assert.AreEqual(null, to2.SharedState); + + // a call to GetObject() results in a normally configured instance + TestObject to3 = lof.GetObject("singleton") as TestObject; + Assert.IsNotNull(to3); + // props set + Assert.AreEqual(27, to3.Age); + Assert.AreEqual("Bruno", to3.Name); + // object postprocessors executed! + Assert.AreEqual("singleton", to3.ObjectName); + Assert.AreEqual(lof, to3.ObjectFactory); + Assert.IsNotNull(to3.SharedState); + } + } + + [Test] + public void CreateObjectWithAllNamedCtorArguments() + { + string expectedName = "Bingo"; + int expectedAge = 1023; + ConstructorArgumentValues values = new ConstructorArgumentValues(); + values.AddNamedArgumentValue("age", expectedAge); + values.AddNamedArgumentValue("name", expectedName); + RootObjectDefinition def = new RootObjectDefinition(typeof(TestObject), values, new MutablePropertyValues()); + DefaultListableObjectFactory fac = new DefaultListableObjectFactory(); + fac.RegisterObjectDefinition("foo", def); + + ITestObject foo = fac["foo"] as ITestObject; + Assert.IsNotNull(foo, "Couldn't pull manually registered instance out of the factory."); + Assert.AreEqual(expectedName, foo.Name, "Dependency 'name' was not resolved using a named ctor arg."); + Assert.AreEqual(expectedAge, foo.Age, "Dependency 'age' was not resolved using a named ctor arg."); + } + + [Test] + public void CreateObjectWithAllNamedCtorArgumentsIsCaseInsensitive() + { + string expectedName = "Bingo"; + int expectedAge = 1023; + ConstructorArgumentValues values = new ConstructorArgumentValues(); + values.AddNamedArgumentValue("aGe", expectedAge); + values.AddNamedArgumentValue("naME", expectedName); + RootObjectDefinition def = new RootObjectDefinition(typeof(TestObject), values, new MutablePropertyValues()); + DefaultListableObjectFactory fac = new DefaultListableObjectFactory(); + fac.RegisterObjectDefinition("foo", def); + + ITestObject foo = fac["foo"] as ITestObject; + Assert.IsNotNull(foo, "Couldn't pull manually registered instance out of the factory."); + Assert.AreEqual(expectedName, foo.Name, "Dependency 'name' was not resolved using a named ctor arg."); + Assert.AreEqual(expectedAge, foo.Age, "Dependency 'age' was not resolved using a named ctor arg."); + } + + [Test] + public void CreateObjectWithMixOfNamedAndIndexedCtorArguments() + { + string expectedName = "Bingo"; + int expectedAge = 1023; + ConstructorArgumentValues values = new ConstructorArgumentValues(); + values.AddNamedArgumentValue("age", expectedAge); + values.AddIndexedArgumentValue(0, expectedName); + RootObjectDefinition def = new RootObjectDefinition(typeof(TestObject), values, new MutablePropertyValues()); + DefaultListableObjectFactory fac = new DefaultListableObjectFactory(); + fac.RegisterObjectDefinition("foo", def); + + ITestObject foo = fac["foo"] as ITestObject; + Assert.IsNotNull(foo, "Couldn't pull manually registered instance out of the factory."); + Assert.AreEqual(expectedName, foo.Name, "Dependency 'name' was not resolved an indexed ctor arg."); + Assert.AreEqual(expectedAge, foo.Age, "Dependency 'age' was not resolved using a named ctor arg."); + } + + [Test] + public void CreateObjectWithMixOfNamedAndIndexedAndAutowiredCtorArguments() + { + string expectedCompany = "Griffin's Foosball Arcade"; + MutablePropertyValues autoProps = new MutablePropertyValues(); + autoProps.Add(new PropertyValue("Company", expectedCompany)); + RootObjectDefinition autowired = new RootObjectDefinition(typeof(NestedTestObject), autoProps); + + string expectedName = "Bingo"; + int expectedAge = 1023; + ConstructorArgumentValues values = new ConstructorArgumentValues(); + values.AddNamedArgumentValue("age", expectedAge); + values.AddIndexedArgumentValue(0, expectedName); + RootObjectDefinition def = new RootObjectDefinition(typeof(TestObject), values, new MutablePropertyValues()); + def.AutowireMode = AutoWiringMode.Constructor; + DefaultListableObjectFactory fac = new DefaultListableObjectFactory(); + fac.RegisterObjectDefinition("foo", def); + fac.RegisterObjectDefinition("doctor", autowired); + + ITestObject foo = fac["foo"] as ITestObject; + Assert.IsNotNull(foo, "Couldn't pull manually registered instance out of the factory."); + Assert.AreEqual(expectedName, foo.Name, "Dependency 'name' was not resolved an indexed ctor arg."); + Assert.AreEqual(expectedAge, foo.Age, "Dependency 'age' was not resolved using a named ctor arg."); + Assert.AreEqual(expectedCompany, foo.Doctor.Company, "Dependency 'doctor.Company' was not resolved using autowiring."); + } + + [Test] + public void CreateObjectWithMixOfIndexedAndTwoNamedSameTypeCtorArguments() + { + // this object will be passed in as a named constructor argument + string expectedCompany = "Griffin's Foosball Arcade"; + MutablePropertyValues autoProps = new MutablePropertyValues(); + autoProps.Add(new PropertyValue("Company", expectedCompany)); + RootObjectDefinition autowired = new RootObjectDefinition(typeof(NestedTestObject), autoProps); + + // this object will be passed in as a named constructor argument + string expectedLawyersCompany = "Pollack, Pounce, & Pulverise"; + MutablePropertyValues lawyerProps = new MutablePropertyValues(); + lawyerProps.Add(new PropertyValue("Company", expectedLawyersCompany)); + RootObjectDefinition lawyer = new RootObjectDefinition(typeof(NestedTestObject), lawyerProps); + + // this simple string object will be passed in as an indexed constructor argument + string expectedName = "Bingo"; + + // this simple integer object will be passed in as a named constructor argument + int expectedAge = 1023; + + ConstructorArgumentValues values = new ConstructorArgumentValues(); + + // lets mix the order up a little... + values.AddNamedArgumentValue("age", expectedAge); + values.AddIndexedArgumentValue(0, expectedName); + values.AddNamedArgumentValue("doctor", new RuntimeObjectReference("a_doctor")); + values.AddNamedArgumentValue("lawyer", new RuntimeObjectReference("a_lawyer")); + + RootObjectDefinition def = new RootObjectDefinition(typeof(TestObject), values, new MutablePropertyValues()); + + DefaultListableObjectFactory fac = new DefaultListableObjectFactory(); + // the object we're attempting to resolve... + fac.RegisterObjectDefinition("foo", def); + // the object that will be looked up and passed as a named parameter to a ctor call... + fac.RegisterObjectDefinition("a_doctor", autowired); + // another object that will be looked up and passed as a named parameter to a ctor call... + fac.RegisterObjectDefinition("a_lawyer", lawyer); + + ITestObject foo = fac["foo"] as ITestObject; + Assert.IsNotNull(foo, "Couldn't pull manually registered instance out of the factory."); + Assert.AreEqual(expectedName, foo.Name, "Dependency 'name' was not resolved an indexed ctor arg."); + Assert.AreEqual(expectedAge, foo.Age, "Dependency 'age' was not resolved using a named ctor arg."); + Assert.AreEqual(expectedCompany, foo.Doctor.Company, "Dependency 'doctor.Company' was not resolved using autowiring."); + Assert.AreEqual(expectedLawyersCompany, foo.Lawyer.Company, "Dependency 'lawyer.Company' was not resolved using another named ctor arg."); + } + + [Test] + public void CircularDependencyIsCorrectlyDetected() + { + RootObjectDefinition foo = new RootObjectDefinition(typeof(TestObject)); + foo.ConstructorArgumentValues.AddNamedArgumentValue("spouse", new RuntimeObjectReference("bar")); + RootObjectDefinition bar = new RootObjectDefinition(typeof(TestObject)); + bar.ConstructorArgumentValues.AddNamedArgumentValue("spouse", new RuntimeObjectReference("foo")); + + DefaultListableObjectFactory fac = new DefaultListableObjectFactory(); + fac.RegisterObjectDefinition("foo", foo); + fac.RegisterObjectDefinition("bar", bar); + + try + { fac.GetObject("foo"); - Assert.IsTrue(StaticInitializer.InitWasCalled, "Boing"); } - - /// - /// There is a similar test in XmlObjectFactoryTests that actually supplies another boolean - /// object in the factory that is used to autowire the object; this test puts no such second - /// object in the factory, so when the factory tries to autowire the second (missing) argument - /// to the ctor, it should (must) choke. - /// - [Test] - public void DoubleBooleanAutowire() + catch (ObjectCreationException ex) { - RootObjectDefinition def = new RootObjectDefinition(typeof(DoubleBooleanConstructorObject)); - ConstructorArgumentValues args = new ConstructorArgumentValues(); - args.AddGenericArgumentValue(true, "bool"); - def.ConstructorArgumentValues = args; - def.AutowireMode = AutoWiringMode.Constructor; - def.IsSingleton = true; - - DefaultListableObjectFactory fac = new DefaultListableObjectFactory(); - fac.RegisterObjectDefinition("foo", def); - - Assert.Throws(() => fac.GetObject("foo"), - "Error creating object with name 'foo' : Unsatisfied dependency " + - "expressed through constructor argument with index 1 of type [System.Boolean] : " + - "No unique object of type [System.Boolean] is defined : Unsatisfied dependency of type [System.Boolean]: expected at least 1 matching object to wire the [b2] parameter on the constructor of object [foo]"); - } - - [Test] - public void CanSetPropertyThatUsesNewModifierOnDerivedClass() - { - string nick = "Banjo"; - string expectedNickname = DerivedTestObject.NicknamePrefix + nick; - - RootObjectDefinition def = new RootObjectDefinition(typeof(DerivedTestObject)); - def.PropertyValues.Add("Nickname", nick); - - DefaultListableObjectFactory fac = new DefaultListableObjectFactory(); - fac.RegisterObjectDefinition("foo", def); - - DerivedTestObject tob = (DerivedTestObject)fac.GetObject("foo"); - Assert.AreEqual(expectedNickname, tob.Nickname, - "Property is not being set to the NEWed property on the subclass."); - } - - [Test] - public void CanSetPropertyThatUsesOddNewModifierOnDerivedClass() - { - RootObjectDefinition def = new RootObjectDefinition(typeof(DerivedFoo)); - def.PropertyValues.Add("Bar", new DerivedBar()); - DefaultListableObjectFactory fac = new DefaultListableObjectFactory(); - fac.RegisterObjectDefinition("foo", def); - DerivedFoo foo = (DerivedFoo)fac.GetObject("foo"); - Assert.AreEqual(typeof(DerivedBar), foo.Bar.GetType()); - } - - [Test] - public void ChildReferencesParentByAnAliasOfTheParent() - { - const string TheParentsAlias = "theParentsAlias"; - const int ExpectedAge = 31; - const string ExpectedName = "Rick Evans"; - - RootObjectDefinition parentDef = new RootObjectDefinition(typeof(TestObject)); - parentDef.IsAbstract = true; - parentDef.PropertyValues.Add("name", ExpectedName); - parentDef.PropertyValues.Add("age", ExpectedAge); - - ChildObjectDefinition childDef = new ChildObjectDefinition(TheParentsAlias); - - DefaultListableObjectFactory fac = new DefaultListableObjectFactory(); - - fac.RegisterObjectDefinition("parent", parentDef); - fac.RegisterAlias("parent", TheParentsAlias); - fac.RegisterObjectDefinition("child", childDef); - - TestObject child = (TestObject)fac.GetObject("child"); - Assert.AreEqual(ExpectedName, child.Name); - Assert.AreEqual(ExpectedAge, child.Age); - } - - [Test] - public void GetObjectByTypeWithAmbiguity() - { - DefaultListableObjectFactory lbf = new DefaultListableObjectFactory(); - RootObjectDefinition bd1 = new RootObjectDefinition(typeof(TestObject)); - RootObjectDefinition bd2 = new RootObjectDefinition(typeof(TestObject)); - lbf.RegisterObjectDefinition("bd1", bd1); - lbf.RegisterObjectDefinition("bd2", bd2); - - Assert.That(() => lbf.GetObject(), Throws.Exception.TypeOf()); - } - - [Test] - public void GetObjectByTypeFiltersOutNonAutowireCandidates() - { - DefaultListableObjectFactory lbf = new DefaultListableObjectFactory(); - RootObjectDefinition bd1 = new RootObjectDefinition(typeof(TestObject)); - RootObjectDefinition bd2 = new RootObjectDefinition(typeof(TestObject)); - RootObjectDefinition na1 = new RootObjectDefinition(typeof(TestObject)); - na1.IsAutowireCandidate = false; - - lbf.RegisterObjectDefinition("bd1", bd1); - lbf.RegisterObjectDefinition("na1", na1); - TestObject actual = lbf.GetObject(); // na1 was filtered - Assert.That(lbf.GetObject("bd1", typeof(TestObject)), Is.SameAs(actual)); - - lbf.RegisterObjectDefinition("bd2", bd2); - Assert.That(() => lbf.GetObject(), Throws.Exception.TypeOf()); - } - - [Test] - public void GetObjectDefinitionResolvesAliases() - { - const string TheParentsAlias = "theParentsAlias"; - const int ExpectedAge = 31; - const string ExpectedName = "Rick Evans"; - - RootObjectDefinition parentDef = new RootObjectDefinition(typeof(TestObject)); - parentDef.IsAbstract = true; - parentDef.PropertyValues.Add("name", ExpectedName); - parentDef.PropertyValues.Add("age", ExpectedAge); - - ChildObjectDefinition childDef = new ChildObjectDefinition(TheParentsAlias); - - DefaultListableObjectFactory fac = new DefaultListableObjectFactory(); - - fac.RegisterObjectDefinition("parent", parentDef); - fac.RegisterAlias("parent", TheParentsAlias); - - IObjectDefinition od = fac.GetObjectDefinition(TheParentsAlias); - Assert.IsNotNull(od); - } - - [Test] - public void IgnoreObjectPostProcessorDuplicates() - { - IObjectPostProcessor proc1 = FakeItEasy.A.Fake(); - - DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); - - const string errMsg = "Wrong number of IObjectPostProcessors being reported by the ObjectPostProcessorCount property."; - Assert.AreEqual(0, lof.ObjectPostProcessorCount, errMsg); - lof.AddObjectPostProcessor(proc1); - Assert.AreEqual(1, lof.ObjectPostProcessorCount, errMsg); - lof.AddObjectPostProcessor(proc1); - Assert.AreEqual(1, lof.ObjectPostProcessorCount, errMsg); - } - - [Test] - public void ConfigureObjectReturnsOriginalInstanceIfNoDefinitionFound() - { - IConfigurableObjectFactory of = new DefaultListableObjectFactory(); - object testObject = new object(); - object resultObject = of.ConfigureObject(testObject, "non-existing object definition name"); - Assert.AreSame(testObject, resultObject); - } - - private class TestObjectPostProcessor : IObjectPostProcessor - { - private object other; - - public TestObjectPostProcessor(object other) - { - this.other = other; - } - - public object PostProcessBeforeInitialization(object instance, string name) - { - return instance; - } - - public object PostProcessAfterInitialization(object instance, string objectName) - { - return other; - } - } - - [Test] - public void ConfigureObjectAppliesObjectPostProcessorsUsingDefinition() - { - DefaultListableObjectFactory of = new DefaultListableObjectFactory(); - object wrapperObject = "WrapperObject"; - of.AddObjectPostProcessor( new TestObjectPostProcessor(wrapperObject)); - of.RegisterObjectDefinition("myObjectDefinition", new RootObjectDefinition()); - - object testObject = "TestObject"; - object resultObject = of.ConfigureObject(testObject, "myObjectDefinition"); - Assert.AreSame(wrapperObject, resultObject); - } - - [Test] - public void ConfigureObjectDoesNotApplyObjectPostProcessorsIfNoDefinition() - { - DefaultListableObjectFactory of = new DefaultListableObjectFactory(); - object wrapperObject = "WrapperObject"; - of.AddObjectPostProcessor( new TestObjectPostProcessor(wrapperObject)); - - object testObject = "TestObject"; - object resultObject = of.ConfigureObject(testObject, "non-existant definition"); - Assert.AreSame(testObject, resultObject); - } - - [Test] - public void HierarchicalObjectFactoryChildParentResolution() - { - DefaultListableObjectFactory parent = new DefaultListableObjectFactory(); - DefaultListableObjectFactory child = new DefaultListableObjectFactory(parent); - parent.RegisterSingleton("parent", new Parent()); - child.RegisterObjectDefinition("child", new RootObjectDefinition(typeof (Child), AutoWiringMode.AutoDetect)); - Child c = (Child) child.GetObject("child"); - Assert.IsNotNull(c); - } - - private class A : IFactoryObject, ISerializable - { - public object GetObject() - { - throw new NotImplementedException(); - } - - public Type ObjectType - { - get { throw new NotImplementedException(); } - } - - public bool IsSingleton - { - get { throw new NotImplementedException(); } - } - - public void GetObjectData(SerializationInfo info, StreamingContext context) - { - throw new NotImplementedException(); - } - } - - [Test] - public void GetObjectDefinitionNamesOnlyFromChild() - { - DefaultListableObjectFactory parent = new DefaultListableObjectFactory(); - parent.RegisterObjectDefinition("testChild", new RootObjectDefinition(typeof(TestObject), null)); - DefaultListableObjectFactory child = new DefaultListableObjectFactory(parent); - child.RegisterObjectDefinition("testParent", new RootObjectDefinition(typeof(NestedTestObject), null)); - - var names = child.GetObjectDefinitionNames(); - - Assert.That(names, Has.Count.EqualTo(1), "GetObjectDefinitionNames() should only return object definition names from this factory"); - - names = child.GetObjectDefinitionNames(false); - - Assert.That(names, Has.Count.EqualTo(1), "GetObjectDefinitionNames(false) should only return object definition names from this factory"); - } - - [Test] - public void GetObjectDefinitionNamesIncludingParent() - { - DefaultListableObjectFactory parent = new DefaultListableObjectFactory(); - parent.RegisterObjectDefinition("testChild", new RootObjectDefinition(typeof(TestObject), null)); - DefaultListableObjectFactory child = new DefaultListableObjectFactory(parent); - child.RegisterObjectDefinition("testParent", new RootObjectDefinition(typeof(NestedTestObject), null)); - - var names = child.GetObjectDefinitionNames(true); - - Assert.That(names, Has.Count.EqualTo(2), "GetObjectDefinitionNames(true) should return object definition names from this factory and parents"); - } - - [Test] - public void GetObjectDefinitionNamesByTypeExcludingParent() - { - DefaultListableObjectFactory parent = new DefaultListableObjectFactory(); - parent.RegisterObjectDefinition("testChild", new RootObjectDefinition(typeof(TestObject), null)); - DefaultListableObjectFactory child = new DefaultListableObjectFactory(parent); - child.RegisterObjectDefinition("testParent", new RootObjectDefinition(typeof(NestedTestObject), null)); - - var names1 = child.GetObjectDefinitionNames(typeof(NestedTestObject)); - var names2 = child.GetObjectDefinitionNames(typeof(TestObject)); - - Assert.That(names1, Has.Count.EqualTo(1), "Should return only child object definitions"); - Assert.That(names2, Has.Count.EqualTo(0), "Should not return the parent object definitions"); - } - - [Test] - public void GetObjectDefinitionNamesByTypeIncludingParent() - { - DefaultListableObjectFactory parent = new DefaultListableObjectFactory(); - parent.RegisterObjectDefinition("testChild", new RootObjectDefinition(typeof(TestObject), null)); - DefaultListableObjectFactory child = new DefaultListableObjectFactory(parent); - child.RegisterObjectDefinition("testParent", new RootObjectDefinition(typeof(NestedTestObject), null)); - - var names1 = child.GetObjectDefinitionNames(typeof(NestedTestObject), true); - var names2 = child.GetObjectDefinitionNames(typeof(TestObject), true); - - Assert.That(names1, Has.Count.EqualTo(1), "Should return child object definitions"); - Assert.That(names2, Has.Count.EqualTo(1), "Should return the parent object definitions"); - } - - [Test] - public void GetObjectNamesForTypeFindsFactoryObjects() - { - DefaultListableObjectFactory of = new DefaultListableObjectFactory(); - of.RegisterObjectDefinition("mod", new RootObjectDefinition(typeof(A))); - - var names = of.GetObjectNamesForType(typeof (ISerializable), false, false); - Assert.IsNotEmpty((ICollection) names); - Assert.AreEqual("&mod", names[0]); - } - - [Test, MaxTime(1000)] - public void TestRegistrationOfManyBeanDefinitionsIsFastEnough() - { - var bf = new DefaultListableObjectFactory(); - bf.RegisterObjectDefinition("b", new RootObjectDefinition(typeof(B))); - - for (int i = 0; i < 100_000; i++) { - bf.RegisterObjectDefinition("a" + i, new RootObjectDefinition(typeof(A))); - } - } - - [Test, MaxTime(1000)] - public void TestRegistrationOfManySingletonsIsFastEnough() - { - // Assume.group(TestGroup.PERFORMANCE); - var bf = new DefaultListableObjectFactory(); - bf.RegisterObjectDefinition("b", new RootObjectDefinition(typeof(B))); - // bf.getBean("b"); - - for (int i = 0; i < 100000; i++) { - bf.RegisterSingleton("a" + i, new A()); - } - } - - [Test, MaxTime(3000)] - public void TestPrototypeCreationIsFastEnough() - { - var lbf = new DefaultListableObjectFactory(); - var rbd = new RootObjectDefinition(typeof(TestObject)) - { - Scope = "prototype" - }; - lbf.RegisterObjectDefinition("test", rbd); - //lbf.FreezeConfiguration(); - - for (int i = 0; i < 100_000; i++) - { - lbf.GetObject("test"); - } - } - - public class B - { - } - - public interface IParent - { - - } - - public class Parent : IParent - { - - } - - public interface IChild - { - - } - - public class Child : IChild - { - public Child(Parent parent) { } - } - public class GoodDisposable : IDisposable - { - public static int DisposeCount = 0; - - public void Dispose() - { - ++DisposeCount; - } - } - - public class BadDisposable : IDisposable - { - public void Dispose() - { - throw new FormatException(); - } - } - - public sealed class MySingleton - { - private MySingleton() - { - } - - private static MySingleton _instance = new MySingleton(); - - public static MySingleton GetInstance() - { - return _instance; - } - - public string Name - { - get { return _name; } - set { _name = value; } - } - - private string _name; - } - - public class NoDependencies - { - } - - public class ConstructorDependency - { - public TestObject _spouse; - - public ConstructorDependency(TestObject spouse) - { - this._spouse = spouse; - } - } - - public class UnsatisfiedConstructorDependency - { - public UnsatisfiedConstructorDependency(TestObject to, SideEffectObject seo) - { - _to = to; - _seo = seo; - } - - public object Seo - { - get { return _seo; } - } - - public TestObject To - { - get { return _to; } - } - - private object _seo; - private TestObject _to; - } - - private sealed class StaticInitializer - { - public static bool InitWasCalled = false; - - public static void Init() - { - InitWasCalled = true; - } + Assert.AreEqual(typeof(ObjectCurrentlyInCreationException), ex.GetBaseException().GetType(), + "Circular dependency was set up; should have caught an ObjectCurrentlyInCreationException instance."); } } - public class Foo + [Test] + public void ConfigurableFactoryObjectInline() { - private IBar bar; + DefaultListableObjectFactory dlof = new DefaultListableObjectFactory(); - public IBar Bar - { - get { return bar; } - set { bar = value; } - } + RootObjectDefinition everyman = new RootObjectDefinition(); + everyman.PropertyValues = new MutablePropertyValues(); + everyman.PropertyValues.Add("name", "Noone"); + everyman.PropertyValues.Add("age", 9781); + + RootObjectDefinition factory = new RootObjectDefinition(); + factory.ObjectType = typeof(DummyConfigurableFactory); + factory.PropertyValues = new MutablePropertyValues(); + factory.PropertyValues.Add("ProductTemplate", everyman); + dlof.RegisterObjectDefinition("factory", factory); + + TestObject instance = dlof.GetObject("factory") as TestObject; + Assert.IsNotNull(instance); + + Assert.AreEqual("Noone", instance.Name, "Name dependency injected via IConfigurableObjectFactory (instance) failed (was 'Factory singleton')."); + Assert.AreEqual(9781, instance.Age, "Age dependency injected via IObjectFactory.ConfigureObject(instance) failed (was 25)."); } - public class DerivedFoo : Foo + [Test] + public void ConfigurableFactoryObjectReference() { - public new IDerivedBar Bar + DefaultListableObjectFactory dlof = new DefaultListableObjectFactory(); + + RootObjectDefinition everyman = new RootObjectDefinition(); + everyman.IsAbstract = true; + everyman.PropertyValues = new MutablePropertyValues(); + everyman.PropertyValues.Add("name", "Noone"); + everyman.PropertyValues.Add("age", 9781); + dlof.RegisterObjectDefinition("everyman", everyman); + + RootObjectDefinition factory = new RootObjectDefinition(); + factory.ObjectType = typeof(DummyConfigurableFactory); + factory.PropertyValues = new MutablePropertyValues(); + factory.PropertyValues.Add("ProductTemplate", new RuntimeObjectReference("everyman")); + dlof.RegisterObjectDefinition("factory", factory); + + TestObject instance = dlof.GetObject("factory") as TestObject; + Assert.IsNotNull(instance); + + Assert.AreEqual("Noone", instance.Name, "Name dependency injected via IConfigurableObjectFactory (instance) failed (was 'Factory singleton')."); + Assert.AreEqual(9781, instance.Age, "Age dependency injected via IObjectFactory.ConfigureObject(instance) failed (was 25)."); + } + + [Test] + public void ConfigureObject() + { + TestObject instance = new TestObject(); + RootObjectDefinition everyman = new RootObjectDefinition(); + everyman.IsAbstract = true; + everyman.PropertyValues = new MutablePropertyValues(); + everyman.PropertyValues.Add("name", "Noone"); + everyman.PropertyValues.Add("age", 9781); + DefaultListableObjectFactory fac = new DefaultListableObjectFactory(); + fac.RegisterObjectDefinition(instance.GetType().FullName, everyman); + fac.ConfigureObject(instance, instance.GetType().FullName); + Assert.AreEqual("Noone", instance.Name, "Name dependency injected via IObjectFactory.ConfigureObject(instance) failed (was null)."); + Assert.AreEqual(9781, instance.Age, "Age dependency injected via IObjectFactory.ConfigureObject(instance) failed (was null)."); + } + + [Test] + public void ConfigureObjectViaExplicitName() + { + TestObject instance = new TestObject(); + RootObjectDefinition everyman = new RootObjectDefinition(); + everyman.IsAbstract = true; + everyman.PropertyValues = new MutablePropertyValues(); + everyman.PropertyValues.Add("name", "Noone"); + everyman.PropertyValues.Add("age", 9781); + DefaultListableObjectFactory fac = new DefaultListableObjectFactory(); + fac.RegisterObjectDefinition("everyman", everyman); + fac.ConfigureObject(instance, "everyman"); + Assert.AreEqual(true, instance.InitCompleted, "AfterPropertiesSet() was not invoked by IObjectFactory.ConfigureObject(instance)."); + Assert.AreEqual("Noone", instance.Name, "Name dependency injected via IObjectFactory.ConfigureObject(instance) failed (was null)."); + Assert.AreEqual(9781, instance.Age, "Age dependency injected via IObjectFactory.ConfigureObject(instance) failed (was null)."); + } + + [Test] + public void ConfigureObjectViaNullName() + { + TestObject instance = new TestObject(); + DefaultListableObjectFactory fac = new DefaultListableObjectFactory(); + Assert.Throws(() => fac.ConfigureObject(instance, null)); + } + + [Test] + public void ConfigureObjectViaLoadOfOldWhitespaceName() + { + TestObject instance = new TestObject(); + DefaultListableObjectFactory fac = new DefaultListableObjectFactory(); + Assert.Throws(() => fac.ConfigureObject(instance, " \t")); + } + + [Test] + public void ConfigureObjectViaEmptyName() + { + TestObject instance = new TestObject(); + DefaultListableObjectFactory fac = new DefaultListableObjectFactory(); + Assert.Throws(() => fac.ConfigureObject(instance, string.Empty)); + } + + [Test] + public void DisposeCyclesThroughAllSingletonsEvenIfTheirDisposeThrowsAnException() + { + RootObjectDefinition foo = new RootObjectDefinition(typeof(GoodDisposable)); + foo.IsSingleton = true; + RootObjectDefinition bar = new RootObjectDefinition(typeof(BadDisposable)); + bar.IsSingleton = true; + RootObjectDefinition baz = new RootObjectDefinition(typeof(GoodDisposable)); + baz.IsSingleton = true; + + using (DefaultListableObjectFactory fac = new DefaultListableObjectFactory()) { - get { return (IDerivedBar)base.Bar; } - set { base.Bar = value; } + fac.RegisterObjectDefinition("foo", foo); + fac.RegisterObjectDefinition("bar", bar); + fac.RegisterObjectDefinition("baz", baz); + fac.PreInstantiateSingletons(); + } + + Assert.AreEqual(2, GoodDisposable.DisposeCount, "All IDisposable singletons must have their Dispose() method called... one of them bailed, and as a result the rest were (apparently) not Dispose()d."); + GoodDisposable.DisposeCount = 0; + } + + [Test] + public void StaticInitializationViaDependsOnSingletonMethodInvokingFactoryObject() + { + RootObjectDefinition initializer = new RootObjectDefinition(typeof(MethodInvokingFactoryObject)); + initializer.PropertyValues.Add("TargetMethod", "Init"); + initializer.PropertyValues.Add("TargetType", typeof(StaticInitializer).AssemblyQualifiedName); + + RootObjectDefinition foo = new RootObjectDefinition(typeof(TestObject)); + foo.DependsOn = new string[] { "force-init" }; + + DefaultListableObjectFactory fac = new DefaultListableObjectFactory(); + fac.RegisterObjectDefinition("foo", foo); + fac.RegisterObjectDefinition("force-init", initializer); + + fac.GetObject("foo"); + Assert.IsTrue(StaticInitializer.InitWasCalled, "Boing"); + } + + /// + /// There is a similar test in XmlObjectFactoryTests that actually supplies another boolean + /// object in the factory that is used to autowire the object; this test puts no such second + /// object in the factory, so when the factory tries to autowire the second (missing) argument + /// to the ctor, it should (must) choke. + /// + [Test] + public void DoubleBooleanAutowire() + { + RootObjectDefinition def = new RootObjectDefinition(typeof(DoubleBooleanConstructorObject)); + ConstructorArgumentValues args = new ConstructorArgumentValues(); + args.AddGenericArgumentValue(true, "bool"); + def.ConstructorArgumentValues = args; + def.AutowireMode = AutoWiringMode.Constructor; + def.IsSingleton = true; + + DefaultListableObjectFactory fac = new DefaultListableObjectFactory(); + fac.RegisterObjectDefinition("foo", def); + + Assert.Throws(() => fac.GetObject("foo"), + "Error creating object with name 'foo' : Unsatisfied dependency " + + "expressed through constructor argument with index 1 of type [System.Boolean] : " + + "No unique object of type [System.Boolean] is defined : Unsatisfied dependency of type [System.Boolean]: expected at least 1 matching object to wire the [b2] parameter on the constructor of object [foo]"); + } + + [Test] + public void CanSetPropertyThatUsesNewModifierOnDerivedClass() + { + string nick = "Banjo"; + string expectedNickname = DerivedTestObject.NicknamePrefix + nick; + + RootObjectDefinition def = new RootObjectDefinition(typeof(DerivedTestObject)); + def.PropertyValues.Add("Nickname", nick); + + DefaultListableObjectFactory fac = new DefaultListableObjectFactory(); + fac.RegisterObjectDefinition("foo", def); + + DerivedTestObject tob = (DerivedTestObject) fac.GetObject("foo"); + Assert.AreEqual(expectedNickname, tob.Nickname, + "Property is not being set to the NEWed property on the subclass."); + } + + [Test] + public void CanSetPropertyThatUsesOddNewModifierOnDerivedClass() + { + RootObjectDefinition def = new RootObjectDefinition(typeof(DerivedFoo)); + def.PropertyValues.Add("Bar", new DerivedBar()); + DefaultListableObjectFactory fac = new DefaultListableObjectFactory(); + fac.RegisterObjectDefinition("foo", def); + DerivedFoo foo = (DerivedFoo) fac.GetObject("foo"); + Assert.AreEqual(typeof(DerivedBar), foo.Bar.GetType()); + } + + [Test] + public void ChildReferencesParentByAnAliasOfTheParent() + { + const string TheParentsAlias = "theParentsAlias"; + const int ExpectedAge = 31; + const string ExpectedName = "Rick Evans"; + + RootObjectDefinition parentDef = new RootObjectDefinition(typeof(TestObject)); + parentDef.IsAbstract = true; + parentDef.PropertyValues.Add("name", ExpectedName); + parentDef.PropertyValues.Add("age", ExpectedAge); + + ChildObjectDefinition childDef = new ChildObjectDefinition(TheParentsAlias); + + DefaultListableObjectFactory fac = new DefaultListableObjectFactory(); + + fac.RegisterObjectDefinition("parent", parentDef); + fac.RegisterAlias("parent", TheParentsAlias); + fac.RegisterObjectDefinition("child", childDef); + + TestObject child = (TestObject) fac.GetObject("child"); + Assert.AreEqual(ExpectedName, child.Name); + Assert.AreEqual(ExpectedAge, child.Age); + } + + [Test] + public void GetObjectByTypeWithAmbiguity() + { + DefaultListableObjectFactory lbf = new DefaultListableObjectFactory(); + RootObjectDefinition bd1 = new RootObjectDefinition(typeof(TestObject)); + RootObjectDefinition bd2 = new RootObjectDefinition(typeof(TestObject)); + lbf.RegisterObjectDefinition("bd1", bd1); + lbf.RegisterObjectDefinition("bd2", bd2); + + Assert.That(() => lbf.GetObject(), Throws.Exception.TypeOf()); + } + + [Test] + public void GetObjectByTypeFiltersOutNonAutowireCandidates() + { + DefaultListableObjectFactory lbf = new DefaultListableObjectFactory(); + RootObjectDefinition bd1 = new RootObjectDefinition(typeof(TestObject)); + RootObjectDefinition bd2 = new RootObjectDefinition(typeof(TestObject)); + RootObjectDefinition na1 = new RootObjectDefinition(typeof(TestObject)); + na1.IsAutowireCandidate = false; + + lbf.RegisterObjectDefinition("bd1", bd1); + lbf.RegisterObjectDefinition("na1", na1); + TestObject actual = lbf.GetObject(); // na1 was filtered + Assert.That(lbf.GetObject("bd1", typeof(TestObject)), Is.SameAs(actual)); + + lbf.RegisterObjectDefinition("bd2", bd2); + Assert.That(() => lbf.GetObject(), Throws.Exception.TypeOf()); + } + + [Test] + public void GetObjectDefinitionResolvesAliases() + { + const string TheParentsAlias = "theParentsAlias"; + const int ExpectedAge = 31; + const string ExpectedName = "Rick Evans"; + + RootObjectDefinition parentDef = new RootObjectDefinition(typeof(TestObject)); + parentDef.IsAbstract = true; + parentDef.PropertyValues.Add("name", ExpectedName); + parentDef.PropertyValues.Add("age", ExpectedAge); + + ChildObjectDefinition childDef = new ChildObjectDefinition(TheParentsAlias); + + DefaultListableObjectFactory fac = new DefaultListableObjectFactory(); + + fac.RegisterObjectDefinition("parent", parentDef); + fac.RegisterAlias("parent", TheParentsAlias); + + IObjectDefinition od = fac.GetObjectDefinition(TheParentsAlias); + Assert.IsNotNull(od); + } + + [Test] + public void IgnoreObjectPostProcessorDuplicates() + { + IObjectPostProcessor proc1 = FakeItEasy.A.Fake(); + + DefaultListableObjectFactory lof = new DefaultListableObjectFactory(); + + const string errMsg = "Wrong number of IObjectPostProcessors being reported by the ObjectPostProcessorCount property."; + Assert.AreEqual(0, lof.ObjectPostProcessorCount, errMsg); + lof.AddObjectPostProcessor(proc1); + Assert.AreEqual(1, lof.ObjectPostProcessorCount, errMsg); + lof.AddObjectPostProcessor(proc1); + Assert.AreEqual(1, lof.ObjectPostProcessorCount, errMsg); + } + + [Test] + public void ConfigureObjectReturnsOriginalInstanceIfNoDefinitionFound() + { + IConfigurableObjectFactory of = new DefaultListableObjectFactory(); + object testObject = new object(); + object resultObject = of.ConfigureObject(testObject, "non-existing object definition name"); + Assert.AreSame(testObject, resultObject); + } + + private class TestObjectPostProcessor : IObjectPostProcessor + { + private object other; + + public TestObjectPostProcessor(object other) + { + this.other = other; + } + + public object PostProcessBeforeInitialization(object instance, string name) + { + return instance; + } + + public object PostProcessAfterInitialization(object instance, string objectName) + { + return other; } } - public interface IBar { } + [Test] + public void ConfigureObjectAppliesObjectPostProcessorsUsingDefinition() + { + DefaultListableObjectFactory of = new DefaultListableObjectFactory(); + object wrapperObject = "WrapperObject"; + of.AddObjectPostProcessor(new TestObjectPostProcessor(wrapperObject)); + of.RegisterObjectDefinition("myObjectDefinition", new RootObjectDefinition()); - public interface IDerivedBar : IBar { } + object testObject = "TestObject"; + object resultObject = of.ConfigureObject(testObject, "myObjectDefinition"); + Assert.AreSame(wrapperObject, resultObject); + } - public class Bar : IBar { } + [Test] + public void ConfigureObjectDoesNotApplyObjectPostProcessorsIfNoDefinition() + { + DefaultListableObjectFactory of = new DefaultListableObjectFactory(); + object wrapperObject = "WrapperObject"; + of.AddObjectPostProcessor(new TestObjectPostProcessor(wrapperObject)); - public class DerivedBar : IDerivedBar { } -} \ No newline at end of file + object testObject = "TestObject"; + object resultObject = of.ConfigureObject(testObject, "non-existant definition"); + Assert.AreSame(testObject, resultObject); + } + + [Test] + public void HierarchicalObjectFactoryChildParentResolution() + { + DefaultListableObjectFactory parent = new DefaultListableObjectFactory(); + DefaultListableObjectFactory child = new DefaultListableObjectFactory(parent); + parent.RegisterSingleton("parent", new Parent()); + child.RegisterObjectDefinition("child", new RootObjectDefinition(typeof(Child), AutoWiringMode.AutoDetect)); + Child c = (Child) child.GetObject("child"); + Assert.IsNotNull(c); + } + + private class A : IFactoryObject, ISerializable + { + public object GetObject() + { + throw new NotImplementedException(); + } + + public Type ObjectType + { + get { throw new NotImplementedException(); } + } + + public bool IsSingleton + { + get { throw new NotImplementedException(); } + } + + public void GetObjectData(SerializationInfo info, StreamingContext context) + { + throw new NotImplementedException(); + } + } + + [Test] + public void GetObjectDefinitionNamesOnlyFromChild() + { + DefaultListableObjectFactory parent = new DefaultListableObjectFactory(); + parent.RegisterObjectDefinition("testChild", new RootObjectDefinition(typeof(TestObject), null)); + DefaultListableObjectFactory child = new DefaultListableObjectFactory(parent); + child.RegisterObjectDefinition("testParent", new RootObjectDefinition(typeof(NestedTestObject), null)); + + var names = child.GetObjectDefinitionNames(); + + Assert.That(names, Has.Count.EqualTo(1), "GetObjectDefinitionNames() should only return object definition names from this factory"); + + names = child.GetObjectDefinitionNames(false); + + Assert.That(names, Has.Count.EqualTo(1), "GetObjectDefinitionNames(false) should only return object definition names from this factory"); + } + + [Test] + public void GetObjectDefinitionNamesIncludingParent() + { + DefaultListableObjectFactory parent = new DefaultListableObjectFactory(); + parent.RegisterObjectDefinition("testChild", new RootObjectDefinition(typeof(TestObject), null)); + DefaultListableObjectFactory child = new DefaultListableObjectFactory(parent); + child.RegisterObjectDefinition("testParent", new RootObjectDefinition(typeof(NestedTestObject), null)); + + var names = child.GetObjectDefinitionNames(true); + + Assert.That(names, Has.Count.EqualTo(2), "GetObjectDefinitionNames(true) should return object definition names from this factory and parents"); + } + + [Test] + public void GetObjectDefinitionNamesByTypeExcludingParent() + { + DefaultListableObjectFactory parent = new DefaultListableObjectFactory(); + parent.RegisterObjectDefinition("testChild", new RootObjectDefinition(typeof(TestObject), null)); + DefaultListableObjectFactory child = new DefaultListableObjectFactory(parent); + child.RegisterObjectDefinition("testParent", new RootObjectDefinition(typeof(NestedTestObject), null)); + + var names1 = child.GetObjectDefinitionNames(typeof(NestedTestObject)); + var names2 = child.GetObjectDefinitionNames(typeof(TestObject)); + + Assert.That(names1, Has.Count.EqualTo(1), "Should return only child object definitions"); + Assert.That(names2, Has.Count.EqualTo(0), "Should not return the parent object definitions"); + } + + [Test] + public void GetObjectDefinitionNamesByTypeIncludingParent() + { + DefaultListableObjectFactory parent = new DefaultListableObjectFactory(); + parent.RegisterObjectDefinition("testChild", new RootObjectDefinition(typeof(TestObject), null)); + DefaultListableObjectFactory child = new DefaultListableObjectFactory(parent); + child.RegisterObjectDefinition("testParent", new RootObjectDefinition(typeof(NestedTestObject), null)); + + var names1 = child.GetObjectDefinitionNames(typeof(NestedTestObject), true); + var names2 = child.GetObjectDefinitionNames(typeof(TestObject), true); + + Assert.That(names1, Has.Count.EqualTo(1), "Should return child object definitions"); + Assert.That(names2, Has.Count.EqualTo(1), "Should return the parent object definitions"); + } + + [Test] + public void GetObjectNamesForTypeFindsFactoryObjects() + { + DefaultListableObjectFactory of = new DefaultListableObjectFactory(); + of.RegisterObjectDefinition("mod", new RootObjectDefinition(typeof(A))); + + var names = of.GetObjectNamesForType(typeof(ISerializable), false, false); + Assert.IsNotEmpty((ICollection) names); + Assert.AreEqual("&mod", names[0]); + } + + [Test, MaxTime(1000)] + public void TestRegistrationOfManyBeanDefinitionsIsFastEnough() + { + var bf = new DefaultListableObjectFactory(); + bf.RegisterObjectDefinition("b", new RootObjectDefinition(typeof(B))); + + for (int i = 0; i < 100_000; i++) + { + bf.RegisterObjectDefinition("a" + i, new RootObjectDefinition(typeof(A))); + } + } + + [Test, MaxTime(1000)] + public void TestRegistrationOfManySingletonsIsFastEnough() + { + // Assume.group(TestGroup.PERFORMANCE); + var bf = new DefaultListableObjectFactory(); + bf.RegisterObjectDefinition("b", new RootObjectDefinition(typeof(B))); + // bf.getBean("b"); + + for (int i = 0; i < 100000; i++) + { + bf.RegisterSingleton("a" + i, new A()); + } + } + + [Test, MaxTime(3000)] + public void TestPrototypeCreationIsFastEnough() + { + var lbf = new DefaultListableObjectFactory(); + var rbd = new RootObjectDefinition(typeof(TestObject)) { Scope = "prototype" }; + lbf.RegisterObjectDefinition("test", rbd); + //lbf.FreezeConfiguration(); + + for (int i = 0; i < 100_000; i++) + { + lbf.GetObject("test"); + } + } + + public class B + { + } + + public interface IParent + { + } + + public class Parent : IParent + { + } + + public interface IChild + { + } + + public class Child : IChild + { + public Child(Parent parent) { } + } + + public class GoodDisposable : IDisposable + { + public static int DisposeCount = 0; + + public void Dispose() + { + ++DisposeCount; + } + } + + public class BadDisposable : IDisposable + { + public void Dispose() + { + throw new FormatException(); + } + } + + public sealed class MySingleton + { + private MySingleton() + { + } + + private static MySingleton _instance = new MySingleton(); + + public static MySingleton GetInstance() + { + return _instance; + } + + public string Name + { + get { return _name; } + set { _name = value; } + } + + private string _name; + } + + public class NoDependencies + { + } + + public class ConstructorDependency + { + public TestObject _spouse; + + public ConstructorDependency(TestObject spouse) + { + this._spouse = spouse; + } + } + + public class UnsatisfiedConstructorDependency + { + public UnsatisfiedConstructorDependency(TestObject to, SideEffectObject seo) + { + _to = to; + _seo = seo; + } + + public object Seo + { + get { return _seo; } + } + + public TestObject To + { + get { return _to; } + } + + private object _seo; + private TestObject _to; + } + + private sealed class StaticInitializer + { + public static bool InitWasCalled = false; + + public static void Init() + { + InitWasCalled = true; + } + } +} + +public class Foo +{ + private IBar bar; + + public IBar Bar + { + get { return bar; } + set { bar = value; } + } +} + +public class DerivedFoo : Foo +{ + public new IDerivedBar Bar + { + get { return (IDerivedBar) base.Bar; } + set { base.Bar = value; } + } +} + +public interface IBar +{ +} + +public interface IDerivedBar : IBar +{ +} + +public class Bar : IBar +{ +} + +public class DerivedBar : IDerivedBar +{ +} diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/DummyConfigurableFactory.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/DummyConfigurableFactory.cs index 7e8f3e34..6af437bb 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/DummyConfigurableFactory.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/DummyConfigurableFactory.cs @@ -24,29 +24,28 @@ using Spring.Objects.Factory.Config; #endregion -namespace Spring.Objects.Factory +namespace Spring.Objects.Factory; + +/// +/// Simple factory based on DummyFactory to allow testing +/// of IConfigurableFactoryObject support in AbstractObjectFactory. +/// +/// Bruno Baia +public class DummyConfigurableFactory : DummyFactory, IConfigurableFactoryObject { - /// - /// Simple factory based on DummyFactory to allow testing - /// of IConfigurableFactoryObject support in AbstractObjectFactory. - /// - /// Bruno Baia - public class DummyConfigurableFactory : DummyFactory, IConfigurableFactoryObject + #region Fields + + private IObjectDefinition productTemplate; + + #endregion + + #region IConfigurableFactoryObject Members + + public IObjectDefinition ProductTemplate { - #region Fields - - private IObjectDefinition productTemplate; - - #endregion - - #region IConfigurableFactoryObject Members - - public IObjectDefinition ProductTemplate - { - get { return productTemplate; } - set { productTemplate = value; } - } - - #endregion + get { return productTemplate; } + set { productTemplate = value; } } -} \ No newline at end of file + + #endregion +} diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/DummyFactory.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/DummyFactory.cs index 153fcdf9..75b95c60 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/DummyFactory.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/DummyFactory.cs @@ -24,198 +24,198 @@ using Spring.Objects.Factory.Config; #endregion -namespace Spring.Objects.Factory +namespace Spring.Objects.Factory; + +/// +/// Simple factory to allow testing of IFactoryObject support in AbstractObjectFactory. +/// Depending on whether its singleton property is set, it will return a singleton +/// or a prototype instance. +/// Implements the IInitializingObject interface, so we can check that factories get +/// this lifecycle callback if they want. +/// +/// Rod Johnson +/// Rick Evans (.NET) +public class DummyFactory : + IFactoryObject, + IObjectFactoryAware, + IObjectNameAware, + IInitializingObject, + IDisposable { - /// - /// Simple factory to allow testing of IFactoryObject support in AbstractObjectFactory. - /// Depending on whether its singleton property is set, it will return a singleton - /// or a prototype instance. - /// Implements the IInitializingObject interface, so we can check that factories get - /// this lifecycle callback if they want. - /// - /// Rod Johnson - /// Rick Evans (.NET) - public class DummyFactory : - IFactoryObject, - IObjectFactoryAware, - IObjectNameAware, - IInitializingObject, - IDisposable - { - #region Constants + #region Constants - public const string SINGLETON_NAME = "Factory singleton"; + public const string SINGLETON_NAME = "Factory singleton"; - #endregion + #endregion - #region Constructor (s) / Destructor + #region Constructor (s) / Destructor - /// - /// Creates a new instance of the - /// class. - /// - public DummyFactory() - { - testObject = new TestObject(); - testObject.Name = SINGLETON_NAME; - testObject.Age = 25; - } + /// + /// Creates a new instance of the + /// class. + /// + public DummyFactory() + { + testObject = new TestObject(); + testObject.Name = SINGLETON_NAME; + testObject.Age = 25; + } - #endregion + #endregion - #region Properties + #region Properties - /// - /// Was this initialized by invocation of the - /// AfterPropertiesSet() method from the IInitializingObject interface? - /// - public virtual bool WasInitialized - { - get { return initialized; } - } + /// + /// Was this initialized by invocation of the + /// AfterPropertiesSet() method from the IInitializingObject interface? + /// + public virtual bool WasInitialized + { + get { return initialized; } + } - public static bool WasPrototypeCreated - { - get { return prototypeCreated; } - } + public static bool WasPrototypeCreated + { + get { return prototypeCreated; } + } - public virtual bool PostProcessed - { - get { return postProcessed; } + public virtual bool PostProcessed + { + get { return postProcessed; } - set { postProcessed = value; } - } + set { postProcessed = value; } + } - public virtual ITestObject OtherTestObject - { - get { return otherTestObject; } + public virtual ITestObject OtherTestObject + { + get { return otherTestObject; } - set { otherTestObject = value; } - } + set { otherTestObject = value; } + } - #endregion + #endregion - #region Methods + #region Methods - /// - /// Clear static state. - /// - public static void Reset() - { - prototypeCreated = false; - } + /// + /// Clear static state. + /// + public static void Reset() + { + prototypeCreated = false; + } - #endregion + #endregion - #region Fields + #region Fields - /// Default is for factories to return a singleton instance. - private bool singleton = true; + /// Default is for factories to return a singleton instance. + private bool singleton = true; - private String objectName; - private IAutowireCapableObjectFactory objectFactory; - private bool postProcessed; - private bool initialized; - private static bool prototypeCreated; - private TestObject testObject; - private ITestObject otherTestObject; + private String objectName; + private IAutowireCapableObjectFactory objectFactory; + private bool postProcessed; + private bool initialized; + private static bool prototypeCreated; + private TestObject testObject; + private ITestObject otherTestObject; - #endregion + #endregion - #region IFactoryObject Members + #region IFactoryObject Members - public Type ObjectType - { - get - { + public Type ObjectType + { + get + { // if (!initialized) // { // throw new InvalidOperationException("'ObjectType' must not be called before AfterPropertiesSet()"); // } - return testObject.GetType(); - } - } + return testObject.GetType(); + } + } - public object GetObject() - { + public object GetObject() + { // if (!initialized) // { // throw new InvalidOperationException("GetObject() must not be called before AfterPropertiesSet()"); // } - if (IsSingleton) - { - return testObject; - } - else - { - TestObject prototype = new TestObject("Prototype created at " + DateTime.Now.Millisecond, 11); - if (objectFactory != null) - { - objectFactory.ApplyObjectPostProcessorsBeforeInitialization(prototype, objectName); - } - prototypeCreated = true; - return prototype; - } - } + if (IsSingleton) + { + return testObject; + } + else + { + TestObject prototype = new TestObject("Prototype created at " + DateTime.Now.Millisecond, 11); + if (objectFactory != null) + { + objectFactory.ApplyObjectPostProcessorsBeforeInitialization(prototype, objectName); + } - public bool IsSingleton - { - get { return singleton; } - set { singleton = value; } - } + prototypeCreated = true; + return prototype; + } + } - #endregion + public bool IsSingleton + { + get { return singleton; } + set { singleton = value; } + } - #region IObjectFactoryAware Members + #endregion - public IObjectFactory ObjectFactory - { - get { return objectFactory; } - set - { - objectFactory = (IAutowireCapableObjectFactory) value; - objectFactory.ApplyObjectPostProcessorsBeforeInitialization(testObject, objectName); - } - } + #region IObjectFactoryAware Members - #endregion + public IObjectFactory ObjectFactory + { + get { return objectFactory; } + set + { + objectFactory = (IAutowireCapableObjectFactory) value; + objectFactory.ApplyObjectPostProcessorsBeforeInitialization(testObject, objectName); + } + } - #region IObjectNameAware Members + #endregion - public string ObjectName - { - get { return objectName; } - set { objectName = value; } - } + #region IObjectNameAware Members - #endregion + public string ObjectName + { + get { return objectName; } + set { objectName = value; } + } - #region IInitializingObject Members + #endregion - public void AfterPropertiesSet() - { - if (initialized) - { - throw new SystemException( - "Cannot call AfterPropertiesSet twice on the one object."); - } + #region IInitializingObject Members - initialized = true; - } + public void AfterPropertiesSet() + { + if (initialized) + { + throw new SystemException( + "Cannot call AfterPropertiesSet twice on the one object."); + } - #endregion + initialized = true; + } - #region IDisposable Members + #endregion - public void Dispose() - { - if (testObject != null) - { - testObject.Name = null; - } - } + #region IDisposable Members - #endregion - } -} \ No newline at end of file + public void Dispose() + { + if (testObject != null) + { + testObject.Name = null; + } + } + + #endregion +} diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/HasMap.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/HasMap.cs index 492eedbe..a8e41da1 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/HasMap.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/HasMap.cs @@ -22,99 +22,101 @@ using System.Collections; using System.Collections.Specialized; - using Spring.Collections; #endregion -namespace Spring.Objects.Factory { +namespace Spring.Objects.Factory; - /// - /// Object exposing a map. Used for object factory tests. - /// - public class HasMap { +/// +/// Object exposing a map. Used for object factory tests. +/// +public class HasMap +{ + #region Properties - #region Properties - public IDictionary Map + public IDictionary Map + { + get { - get - { - return _map; - } - set - { - _map = value; - } + return _map; } - - public Set Set + set { - get - { - return _set; - } - set - { - _set = value; - } + _map = value; } + } - public NameValueCollection Props + public Set Set + { + get { - get - { - return _props; - } - set - { - _props = value; - } + return _set; } - - public object [] ObjectArray + set { - get - { - return _objectArray; - } - set - { - _objectArray = value; - } + _set = value; } + } - virtual public Type [] ClassArray + public NameValueCollection Props + { + get { - get - { - return _classArray; - } - set - { - _classArray = value; - } + return _props; } - - virtual public int [] IntegerArray + set { - get - { - return _intArray; - } - set - { - _intArray = value; - } + _props = value; } - #endregion + } - #region Fields - private IDictionary _map; - private Set _set; - private NameValueCollection _props; - private object [] _objectArray; - private Type [] _classArray; - private int [] _intArray; - #endregion - } + public object[] ObjectArray + { + get + { + return _objectArray; + } + set + { + _objectArray = value; + } + } + + virtual public Type[] ClassArray + { + get + { + return _classArray; + } + set + { + _classArray = value; + } + } + + virtual public int[] IntegerArray + { + get + { + return _intArray; + } + set + { + _intArray = value; + } + } + + #endregion + + #region Fields + + private IDictionary _map; + private Set _set; + private NameValueCollection _props; + private object[] _objectArray; + private Type[] _classArray; + private int[] _intArray; + + #endregion } diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/ISideEffectObject.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/ISideEffectObject.cs index ca43ae5d..15d6ac7b 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/ISideEffectObject.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/ISideEffectObject.cs @@ -1,27 +1,28 @@ #region License + /* * Copyright 2002-2010 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 -namespace Spring.Objects.Factory -{ - public interface ISideEffectObject - { - int Count { get; set; } +namespace Spring.Objects.Factory; - void doWork(); - } -} \ No newline at end of file +public interface ISideEffectObject +{ + int Count { get; set; } + + void doWork(); +} diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/KnowsIfInstantiated.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/KnowsIfInstantiated.cs index 92f3e3b3..3a36cd73 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/KnowsIfInstantiated.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/KnowsIfInstantiated.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -18,25 +18,24 @@ #endregion -namespace Spring.Objects.Factory +namespace Spring.Objects.Factory; + +internal sealed class KnowsIfInstantiated { - internal sealed class KnowsIfInstantiated - { - private static bool _instantiated; + private static bool _instantiated; - public KnowsIfInstantiated() - { - _instantiated = true; - } + public KnowsIfInstantiated() + { + _instantiated = true; + } - public static void ClearInstantiationRecord() - { - _instantiated = false; - } + public static void ClearInstantiationRecord() + { + _instantiated = false; + } - public static bool WasInstantiated - { - get { return _instantiated; } - } - } + public static bool WasInstantiated + { + get { return _instantiated; } + } } diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/LifecycleObject.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/LifecycleObject.cs index 9f062c25..6952cc70 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/LifecycleObject.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/LifecycleObject.cs @@ -24,170 +24,194 @@ using Spring.Objects.Factory.Config; #endregion -namespace Spring.Objects.Factory { +namespace Spring.Objects.Factory; - /// - /// Simple test of IObjectFactory initialization and lifecycle callbacks. +/// +/// Simple test of IObjectFactory initialization and lifecycle callbacks. +/// +/// Rod Johnson +/// Rick Evans (.NET) +public class LifecycleObject : + IObjectNameAware, + IInitializingObject, + IObjectFactoryAware, + IDisposable +{ + #region Methods + + public virtual void PostProcessBeforeInit() + { + if (inited) + { + throw new ApplicationException("Factory called PostProcessBeforeInit after AfterPropertiesSet"); + } + + if (postProcessedBeforeInit) + { + throw new SystemException("Factory called PostProcessBeforeInit twice"); + } + + postProcessedBeforeInit = true; + } + + /// + /// Dummy business method that will fail unless the factory + /// managed the object's lifecycle correctly /// - /// Rod Johnson - /// Rick Evans (.NET) - public class LifecycleObject : - IObjectNameAware, - IInitializingObject, - IObjectFactoryAware, - IDisposable { - - #region Methods - public virtual void PostProcessBeforeInit () + public virtual void BusinessMethod() + { + if (!inited || !postProcessedAfterInit) { - if (inited) - { - throw new ApplicationException ("Factory called PostProcessBeforeInit after AfterPropertiesSet"); - } - if (postProcessedBeforeInit) - { - throw new SystemException("Factory called PostProcessBeforeInit twice"); - } - postProcessedBeforeInit = true; + throw new SystemException("Factory didn't initialize lifecycle object correctly"); + } + } + + public virtual void PostProcessAfterInit() + { + if (!inited) + { + throw new SystemException("Factory called PostProcessAfterInit before AfterPropertiesSet"); } - /// - /// Dummy business method that will fail unless the factory - /// managed the object's lifecycle correctly - /// - public virtual void BusinessMethod () + if (postProcessedAfterInit) { - if (!inited || !postProcessedAfterInit) - { - throw new SystemException ("Factory didn't initialize lifecycle object correctly"); - } + throw new SystemException("Factory called PostProcessAfterInit twice"); } - - public virtual void PostProcessAfterInit () + + postProcessedAfterInit = true; + } + + #endregion + + #region Properties + + public bool Destroyed + { + get { - if (!inited) - { - throw new SystemException("Factory called PostProcessAfterInit before AfterPropertiesSet"); - } - if (postProcessedAfterInit) - { - throw new SystemException("Factory called PostProcessAfterInit twice"); - } - postProcessedAfterInit = true; + return destroyed; } - #endregion - - #region Properties - public bool Destroyed + set { - get - { - return destroyed; - } - set - { - destroyed = value; - } + destroyed = value; } - #endregion + } - #region Fields - private string objectName; - private IObjectFactory owningFactory; - private bool postProcessedBeforeInit; - private bool inited; - private bool postProcessedAfterInit; - private bool destroyed; - #endregion + #endregion - #region IObjectNameAware Members - public string ObjectName + #region Fields + + private string objectName; + private IObjectFactory owningFactory; + private bool postProcessedBeforeInit; + private bool inited; + private bool postProcessedAfterInit; + private bool destroyed; + + #endregion + + #region IObjectNameAware Members + + public string ObjectName + { + get { - get - { - return objectName; - } - set - { - objectName = value; - } + return objectName; } - #endregion - - #region IInitializingObject Members - public void AfterPropertiesSet () + set { - if (owningFactory == null) - { - throw new SystemException ("Factory didn't call ObjectFactory before AfterPropertiesSet on lifecycle object"); - } - if (!postProcessedBeforeInit) - { - throw new SystemException ("Factory didn't call PostProcessBeforeInit before AfterPropertiesSet on lifecycle object"); - } - if (inited) - { - throw new SystemException ("Factory called AfterPropertiesSet twice"); - } - inited = true; + objectName = value; } - #endregion + } + + #endregion + + #region IInitializingObject Members + + public void AfterPropertiesSet() + { + if (owningFactory == null) + { + throw new SystemException("Factory didn't call ObjectFactory before AfterPropertiesSet on lifecycle object"); + } + + if (!postProcessedBeforeInit) + { + throw new SystemException("Factory didn't call PostProcessBeforeInit before AfterPropertiesSet on lifecycle object"); + } + + if (inited) + { + throw new SystemException("Factory called AfterPropertiesSet twice"); + } + + inited = true; + } + + #endregion + + #region IObjectFactoryAware Members + + public IObjectFactory ObjectFactory + { + get + { + return owningFactory; + } + set + { + owningFactory = value; + } + } + + #endregion + + #region IDisposable Members + + public void Dispose() + { + if (destroyed) + { + throw new SystemException("Already destroyed..."); + } + + destroyed = true; + } + + #endregion + + #region Inner Class : PostProcessor + + public class PostProcessor : IObjectPostProcessor, IObjectFactoryAware + { + public object PostProcessBeforeInitialization(object obj, string name) + { + if (obj is LifecycleObject) + { + ((LifecycleObject) obj).PostProcessBeforeInit(); + } + + return obj; + } + + public object PostProcessAfterInitialization(object obj, string objectName) + { + if (obj is LifecycleObject) + { + ((LifecycleObject) obj).PostProcessAfterInit(); + } + + return obj; + } + + private IObjectFactory objectFactory; - #region IObjectFactoryAware Members public IObjectFactory ObjectFactory { - get - { - return owningFactory; - } - set - { - owningFactory = value; - } + set { objectFactory = value; } + get { return objectFactory; } } - #endregion - - #region IDisposable Members - public void Dispose () - { - if (destroyed) - { - throw new SystemException ("Already destroyed..."); - } - destroyed = true; - } - #endregion - - #region Inner Class : PostProcessor - public class PostProcessor : IObjectPostProcessor, IObjectFactoryAware - { - - public object PostProcessBeforeInitialization (object obj, string name) - { - if (obj is LifecycleObject) - { - ((LifecycleObject) obj).PostProcessBeforeInit (); - } - return obj; - } - - public object PostProcessAfterInitialization (object obj, string objectName) - { - if (obj is LifecycleObject) - { - ((LifecycleObject) obj).PostProcessAfterInit (); - } - return obj; - } - - private IObjectFactory objectFactory; - - public IObjectFactory ObjectFactory - { - set { objectFactory=value; } - get { return objectFactory; } - } - } - #endregion } + + #endregion } diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/MethodReplacerTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/MethodReplacerTests.cs index 69586276..e0ecb4e4 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/MethodReplacerTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/MethodReplacerTests.cs @@ -26,582 +26,580 @@ using Spring.Objects.Factory.Support; #endregion -namespace Spring.Objects.Factory +namespace Spring.Objects.Factory; + +/// +/// Unit tests for the method replacement functionality of the Spring IoC container. +/// +/// +///

+/// This encapsulates both generic method replacement and its specialization, the +/// method lookup variant. +///

+///
+/// Rick Evans +[TestFixture] +public sealed class MethodReplacerTests { - /// - /// Unit tests for the method replacement functionality of the Spring IoC container. - /// - /// - ///

- /// This encapsulates both generic method replacement and its specialization, the - /// method lookup variant. - ///

- ///
- /// Rick Evans - [TestFixture] - public sealed class MethodReplacerTests - { - [Test] - public void SunnyDayReplaceMethod() - { - RootObjectDefinition replacerDef = new RootObjectDefinition(typeof (NewsFeedFactory)); + [Test] + public void SunnyDayReplaceMethod() + { + RootObjectDefinition replacerDef = new RootObjectDefinition(typeof(NewsFeedFactory)); - RootObjectDefinition managerDef = new RootObjectDefinition(typeof (ReturnsNullNewsFeedManager)); - managerDef.MethodOverrides.Add(new ReplacedMethodOverride("CreateNewsFeed", "replacer")); + RootObjectDefinition managerDef = new RootObjectDefinition(typeof(ReturnsNullNewsFeedManager)); + managerDef.MethodOverrides.Add(new ReplacedMethodOverride("CreateNewsFeed", "replacer")); - DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); - factory.RegisterObjectDefinition("manager", managerDef); - factory.RegisterObjectDefinition("replacer", replacerDef); - INewsFeedManager manager = (INewsFeedManager) factory["manager"]; - NewsFeed feed1 = manager.CreateNewsFeed(); - Assert.IsNotNull(feed1, "The CreateNewsFeed() method is not being replaced."); - Assert.AreEqual(NewsFeedFactory.DefaultName, feed1.Name); - NewsFeed feed2 = manager.CreateNewsFeed(); - // NewsFeedFactory always yields a new NewsFeed (see class definition below)... - Assert.IsFalse(ReferenceEquals(feed1, feed2)); - } + DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); + factory.RegisterObjectDefinition("manager", managerDef); + factory.RegisterObjectDefinition("replacer", replacerDef); + INewsFeedManager manager = (INewsFeedManager) factory["manager"]; + NewsFeed feed1 = manager.CreateNewsFeed(); + Assert.IsNotNull(feed1, "The CreateNewsFeed() method is not being replaced."); + Assert.AreEqual(NewsFeedFactory.DefaultName, feed1.Name); + NewsFeed feed2 = manager.CreateNewsFeed(); + // NewsFeedFactory always yields a new NewsFeed (see class definition below)... + Assert.IsFalse(ReferenceEquals(feed1, feed2)); + } - [Test] - public void SunnyDayReplaceMethod_WithProtectedVirtual() + [Test] + public void SunnyDayReplaceMethod_WithProtectedVirtual() + { + RootObjectDefinition replacerDef = new RootObjectDefinition(typeof(NewsFeedFactory)); + + RootObjectDefinition managerDef = new RootObjectDefinition(typeof(ProtectedReturnsNullNewsFeedManagerWithVirtualMethod)); + managerDef.MethodOverrides.Add(new ReplacedMethodOverride("CreateNewsFeed", "replacer")); + + DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); + factory.RegisterObjectDefinition("manager", managerDef); + factory.RegisterObjectDefinition("replacer", replacerDef); + ProtectedReturnsNullNewsFeedManagerWithVirtualMethod manager = (ProtectedReturnsNullNewsFeedManagerWithVirtualMethod) factory["manager"]; + NewsFeed feed1 = manager.GrabNewsFeed(); + Assert.IsNotNull(feed1, "The protected CreateNewsFeed() method is not being replaced."); + Assert.AreEqual(NewsFeedFactory.DefaultName, feed1.Name); + NewsFeed feed2 = manager.GrabNewsFeed(); + // NewsFeedFactory always yields a new NewsFeed (see class definition below)... + Assert.IsFalse(ReferenceEquals(feed1, feed2)); + } + + [Test] + public void SunnyDayReplaceMethod_WithArgumentAcceptingReplacer() + { + RootObjectDefinition replacerDef = new RootObjectDefinition(typeof(NewsFeedFactory)); + + RootObjectDefinition managerDef = new RootObjectDefinition(typeof(NewsFeedManagerWith_Replace_MethodThatTakesArguments)); + ReplacedMethodOverride theOverride = new ReplacedMethodOverride("CreateNewsFeed", "replacer"); + // we must specify parameter type fragments... + theOverride.AddTypeIdentifier(typeof(string).FullName); + managerDef.MethodOverrides.Add(theOverride); + + DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); + factory.RegisterObjectDefinition("manager", managerDef); + factory.RegisterObjectDefinition("replacer", replacerDef); + NewsFeedManagerWith_Replace_MethodThatTakesArguments manager = (NewsFeedManagerWith_Replace_MethodThatTakesArguments) factory["manager"]; + NewsFeed feed1 = manager.CreateNewsFeed("So sad... to be all alone in the world"); + Assert.IsNotNull(feed1, "The CreateNewsFeed() method is not being replaced."); + Assert.AreEqual("So sad... to be all alone in the world", feed1.Name); + NewsFeed feed2 = manager.CreateNewsFeed("Oh Muzzy!"); + // NewsFeedFactory always yields a new NewsFeed (see class definition below)... + Assert.IsFalse(ReferenceEquals(feed1, feed2)); + } + + [Test] + public void SunnyDayReplaceMethod_WithArgumentAcceptingReplacerWithNoOverloadingAndNoTypeFragmentsSpecified() + { + RootObjectDefinition replacerDef = new RootObjectDefinition(typeof(NewsFeedFactory)); + + RootObjectDefinition managerDef = new RootObjectDefinition(typeof(NewsFeedManagerWith_Replace_MethodThatTakesArguments)); + ReplacedMethodOverride theOverride = new ReplacedMethodOverride("CreateNewsFeed", "replacer"); + // no need to specify parameter type fragments if we turn IsOverloaded off (the method is not overloaded)... + theOverride.IsOverloaded = false; + managerDef.MethodOverrides.Add(theOverride); + + DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); + factory.RegisterObjectDefinition("manager", managerDef); + factory.RegisterObjectDefinition("replacer", replacerDef); + NewsFeedManagerWith_Replace_MethodThatTakesArguments manager = (NewsFeedManagerWith_Replace_MethodThatTakesArguments) factory["manager"]; + NewsFeed feed1 = manager.CreateNewsFeed("So sad... to be all alone in the world"); + Assert.IsNotNull(feed1, "The CreateNewsFeed() method is not being replaced."); + Assert.AreEqual("So sad... to be all alone in the world", feed1.Name); + NewsFeed feed2 = manager.CreateNewsFeed("Oh Muzzy!"); + // NewsFeedFactory always yields a new NewsFeed (see class definition below)... + Assert.IsFalse(ReferenceEquals(feed1, feed2)); + } + + [Test] + public void SunnyDayReplaceMethod_WithReplacerThatReturnsVoid() + { + RootObjectDefinition replacerDef = new RootObjectDefinition(typeof(DoNothingReplacer)); + + RootObjectDefinition managerDef = new RootObjectDefinition(typeof(NewsFeedManagerThatReturnsVoid)); + ReplacedMethodOverride theOverride = new ReplacedMethodOverride("DoSomething", "replacer"); + managerDef.MethodOverrides.Add(theOverride); + + DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); + factory.RegisterObjectDefinition("manager", managerDef); + factory.RegisterObjectDefinition("replacer", replacerDef); + NewsFeedManagerThatReturnsVoid manager = (NewsFeedManagerThatReturnsVoid) factory["manager"]; + manager.DoSomething(); + } + + /// + /// We don't specify any type fragments, so the method overload check will never pass. + /// + [Test] + public void SunnyDayReplaceMethod_WithArgumentAcceptingReplacerWithNoTypeFragmentsSpecified() + { + RootObjectDefinition replacerDef = new RootObjectDefinition(typeof(NewsFeedFactory)); + + RootObjectDefinition managerDef = new RootObjectDefinition(typeof(NewsFeedManagerWith_Replace_MethodThatTakesArguments)); + managerDef.MethodOverrides.Add(new ReplacedMethodOverride("CreateNewsFeed", "replacer")); + + DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); + factory.RegisterObjectDefinition("manager", managerDef); + factory.RegisterObjectDefinition("replacer", replacerDef); + NewsFeedManagerWith_Replace_MethodThatTakesArguments manager = (NewsFeedManagerWith_Replace_MethodThatTakesArguments) factory["manager"]; + Assert.Throws(() => manager.CreateNewsFeed("So sad... to be all alone in the world")); + } + + /// + /// A class that requires two lookup method injections. + /// + [Test] + public void LookupMethodMultiple() + { + RootObjectDefinition feedDef = new RootObjectDefinition(typeof(NewsFeed)); + feedDef.IsSingleton = false; + feedDef.PropertyValues.Add("name", "Bingo"); + + RootObjectDefinition testObjectDef = new RootObjectDefinition(typeof(TestObject)); + testObjectDef.IsSingleton = false; + testObjectDef.PropertyValues.Add("name", "Miki Nakatani"); + + RootObjectDefinition managerDef = new RootObjectDefinition(typeof(TestObjectAndNewsFeedFactory)); + managerDef.MethodOverrides.Add(new LookupMethodOverride("CreateNewsFeed", "feed")); + managerDef.MethodOverrides.Add(new LookupMethodOverride("CreateTestObject", "test")); + + DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); + factory.RegisterObjectDefinition("manager", managerDef); + factory.RegisterObjectDefinition("feed", feedDef); + factory.RegisterObjectDefinition("test", testObjectDef); + TestObjectAndNewsFeedFactory manager = (TestObjectAndNewsFeedFactory) factory["manager"]; + + INewsFeedManager newsFeedManager = manager; + NewsFeed feed1 = newsFeedManager.CreateNewsFeed(); + Assert.IsNotNull(feed1, "The CreateNewsFeed() method is not being replaced."); + NewsFeed feed2 = newsFeedManager.CreateNewsFeed(); + // assert that the object (prototype) is definitely being looked up each time... + Assert.IsFalse(ReferenceEquals(feed1, feed2)); + + ITestObjectFactory toFactory = manager; + ITestObject to1 = toFactory.CreateTestObject(); + Assert.IsNotNull(to1, "The CreateTestObject() method is not being replaced."); + ITestObject to2 = toFactory.CreateTestObject(); + // assert that the object (prototype) is definitely being looked up each time... + Assert.IsFalse(ReferenceEquals(to1, to2)); + } + + /// + /// A class that requires both lookup method and replace method injection. + /// + [Test] + public void LookupAndReplaceMethod() + { + RootObjectDefinition replacerDef = new RootObjectDefinition(typeof(NewsFeedFactory)); + + RootObjectDefinition testObjectDef = new RootObjectDefinition(typeof(TestObject)); + testObjectDef.IsSingleton = false; + testObjectDef.PropertyValues.Add("name", "Miki Nakatani"); + + RootObjectDefinition managerDef = new RootObjectDefinition(typeof(TestObjectAndNewsFeedFactory)); + managerDef.MethodOverrides.Add(new ReplacedMethodOverride("CreateNewsFeed", "replacer")); + managerDef.MethodOverrides.Add(new LookupMethodOverride("CreateTestObject", "test")); + + DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); + factory.RegisterObjectDefinition("manager", managerDef); + factory.RegisterObjectDefinition("replacer", replacerDef); + factory.RegisterObjectDefinition("test", testObjectDef); + TestObjectAndNewsFeedFactory manager = (TestObjectAndNewsFeedFactory) factory["manager"]; + + INewsFeedManager newsFeedManager = manager; + NewsFeed feed1 = newsFeedManager.CreateNewsFeed(); + Assert.IsNotNull(feed1, "The CreateNewsFeed() method is not being replaced."); + NewsFeed feed2 = newsFeedManager.CreateNewsFeed(); + // assert that the object (prototype) is definitely being looked up each time... + Assert.IsFalse(ReferenceEquals(feed1, feed2)); + + ITestObjectFactory toFactory = manager; + ITestObject to1 = toFactory.CreateTestObject(); + Assert.IsNotNull(to1, "The CreateTestObject() method is not being replaced."); + ITestObject to2 = toFactory.CreateTestObject(); + // assert that the object (prototype) is definitely being looked up each time... + Assert.IsFalse(ReferenceEquals(to1, to2)); + } + + /// + /// Lookup method injection on an (interface) method that returns null. + /// + [Test] + public void LookupMethodWithNullMethod() + { + try { - RootObjectDefinition replacerDef = new RootObjectDefinition(typeof(NewsFeedFactory)); + RootObjectDefinition feedDef = new RootObjectDefinition(typeof(NewsFeed)); + feedDef.IsSingleton = false; + feedDef.PropertyValues.Add("name", "Bingo"); + + RootObjectDefinition managerDef = new RootObjectDefinition(typeof(ReturnsNullNewsFeedManager)); + managerDef.MethodOverrides.Add(new LookupMethodOverride("CreateNewsFeed", "feed")); - RootObjectDefinition managerDef = new RootObjectDefinition(typeof(ProtectedReturnsNullNewsFeedManagerWithVirtualMethod)); - managerDef.MethodOverrides.Add(new ReplacedMethodOverride("CreateNewsFeed", "replacer")); - DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); factory.RegisterObjectDefinition("manager", managerDef); - factory.RegisterObjectDefinition("replacer", replacerDef); - ProtectedReturnsNullNewsFeedManagerWithVirtualMethod manager = (ProtectedReturnsNullNewsFeedManagerWithVirtualMethod)factory["manager"]; - NewsFeed feed1 = manager.GrabNewsFeed(); - Assert.IsNotNull(feed1, "The protected CreateNewsFeed() method is not being replaced."); - Assert.AreEqual(NewsFeedFactory.DefaultName, feed1.Name); - NewsFeed feed2 = manager.GrabNewsFeed(); - // NewsFeedFactory always yields a new NewsFeed (see class definition below)... + factory.RegisterObjectDefinition("feed", feedDef); + INewsFeedManager manager = (INewsFeedManager) factory["manager"]; + NewsFeed feed1 = manager.CreateNewsFeed(); + Assert.IsNotNull(feed1, "The CreateNewsFeed() method is not being replaced."); + NewsFeed feed2 = manager.CreateNewsFeed(); + // assert that the object (prototype) is definitely being looked up each time... Assert.IsFalse(ReferenceEquals(feed1, feed2)); - + } + catch (Exception ex) + { + Console.Out.WriteLine("ex = {0}", ex); + } + } + + /// + /// Lookup method injection on an (interface) method that returns null. + /// + /// + ///

+ /// The only difference from the previous (similarly named) test is that + /// constructor arguments are passed to the (er) constructor as it (the + /// dynamic subclass) is being instantiated by the container. + ///

+ ///
+ [Test] + public void LookupMethodWithNullMethodInstantiatedWithCtorArg() + { + RootObjectDefinition feedDef = new RootObjectDefinition(typeof(NewsFeed)); + feedDef.IsSingleton = false; + feedDef.PropertyValues.Add("name", "Bingo"); + + RootObjectDefinition managerDef = new RootObjectDefinition(typeof(ReturnsNullNewsFeedManager)); + managerDef.MethodOverrides.Add(new LookupMethodOverride("CreateNewsFeed", "feed")); + managerDef.ConstructorArgumentValues.AddNamedArgumentValue("name", "Bingo"); + + DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); + factory.RegisterObjectDefinition("manager", managerDef); + factory.RegisterObjectDefinition("feed", feedDef); + ReturnsNullNewsFeedManager manager = (ReturnsNullNewsFeedManager) factory["manager"]; + Assert.AreEqual("Bingo", manager.Name); + NewsFeed feed1 = manager.CreateNewsFeed(); + Assert.IsNotNull(feed1, "The CreateNewsFeed() method is not being replaced."); + NewsFeed feed2 = manager.CreateNewsFeed(); + // assert that the object (prototype) is definitely being looked up each time... + Assert.IsFalse(ReferenceEquals(feed1, feed2)); + } + + [Test] + public void LookupMethodWithAbstractMethod() + { + RootObjectDefinition feedDef = new RootObjectDefinition(typeof(NewsFeed)); + feedDef.IsSingleton = false; + feedDef.PropertyValues.Add("name", "Bingo"); + + RootObjectDefinition managerDef = new RootObjectDefinition(typeof(AbstractNewsFeedManager)); + managerDef.MethodOverrides.Add(new LookupMethodOverride("CreateNewsFeed", "feed")); + + DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); + factory.RegisterObjectDefinition("manager", managerDef); + factory.RegisterObjectDefinition("feed", feedDef); + INewsFeedManager manager = (INewsFeedManager) factory["manager"]; + NewsFeed feed1 = manager.CreateNewsFeed(); + Assert.IsNotNull(feed1, "The CreateNewsFeed() method is not being replaced."); + NewsFeed feed2 = manager.CreateNewsFeed(); + // assert that the object (prototype) is definitely being looked up each time... + Assert.IsFalse(ReferenceEquals(feed1, feed2)); + } + + /// + /// Protected methods can also be method injected. + /// + [Test] + public void LookupMethodWithVirtualProtectedMethod() + { + RootObjectDefinition feedDef = new RootObjectDefinition(typeof(NewsFeed)); + feedDef.IsSingleton = false; + feedDef.PropertyValues.Add("name", "Bingo"); + + RootObjectDefinition managerDef = new RootObjectDefinition(typeof(ProtectedReturnsNullNewsFeedManagerWithVirtualMethod)); + managerDef.MethodOverrides.Add(new LookupMethodOverride("CreateNewsFeed", "feed")); + + DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); + factory.RegisterObjectDefinition("manager", managerDef); + factory.RegisterObjectDefinition("feed", feedDef); + ProtectedReturnsNullNewsFeedManagerWithVirtualMethod manager = (ProtectedReturnsNullNewsFeedManagerWithVirtualMethod) factory["manager"]; + NewsFeed feed1 = manager.GrabNewsFeed(); + Assert.IsNotNull(feed1, "The CreateNewsFeed() method is not being replaced."); + NewsFeed feed2 = manager.GrabNewsFeed(); + // assert that the object (prototype) is definitely being looked up each time... + Assert.IsFalse(ReferenceEquals(feed1, feed2)); + } + + #region Rainy Day Scenarios + + [Test] + public void FailWithLookupMethodOnSealedClass() + { + RootObjectDefinition feedDef = new RootObjectDefinition(typeof(NewsFeed)); + feedDef.IsSingleton = false; + feedDef.PropertyValues.Add("name", "Bingo"); + + RootObjectDefinition managerDef = new RootObjectDefinition(typeof(SealedReturnsNullNewsFeedManager)); + managerDef.MethodOverrides.Add(new LookupMethodOverride("CreateNewsFeed", "feed")); + + DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); + factory.RegisterObjectDefinition("manager", managerDef); + factory.RegisterObjectDefinition("feed", feedDef); + Assert.Throws(() => factory.GetObject("manager")); + } + + [Test] + public void FailWithReplaceMethodOnSealedClass() + { + RootObjectDefinition replacerDef = new RootObjectDefinition(typeof(NewsFeedFactory)); + + RootObjectDefinition managerDef = new RootObjectDefinition(typeof(SealedReturnsNullNewsFeedManager)); + managerDef.MethodOverrides.Add(new ReplacedMethodOverride("CreateNewsFeed", "replacer")); + + DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); + factory.RegisterObjectDefinition("manager", managerDef); + factory.RegisterObjectDefinition("replacer", replacerDef); + Assert.Throws(() => factory.GetObject("manager")); + } + + /// + /// Tests that one cannot (obviously) override a protected method that has + /// not been explicitly declared virtual on the original class declaration. + /// + [Test] + public void FailOnNonVirtualProtectedMethod() + { + RootObjectDefinition feedDef = new RootObjectDefinition(typeof(NewsFeed)); + feedDef.IsSingleton = false; + feedDef.PropertyValues.Add("name", "Bingo"); + + RootObjectDefinition managerDef = new RootObjectDefinition(typeof(ProtectedReturnsNullNewsFeedManager)); + managerDef.MethodOverrides.Add(new LookupMethodOverride("CreateNewsFeed", "feed")); + + DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); + factory.RegisterObjectDefinition("manager", managerDef); + factory.RegisterObjectDefinition("feed", feedDef); + Assert.Throws(() => factory.GetObject("manager")); + } + + /// + /// Tests that one cannot (obviously) method inject a method with a void + /// return type. + /// + [Test] + public void FailOnMethodWithVoidReturnType() + { + RootObjectDefinition feedDef = new RootObjectDefinition(typeof(NewsFeed)); + feedDef.IsSingleton = false; + feedDef.PropertyValues.Add("name", "Bingo"); + + RootObjectDefinition managerDef = new RootObjectDefinition(typeof(ReturnsVoidNewsFeedManager)); + managerDef.MethodOverrides.Add(new LookupMethodOverride("CreateNewsFeed", "feed")); + + DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); + factory.RegisterObjectDefinition("manager", managerDef); + factory.RegisterObjectDefinition("feed", feedDef); + Assert.Throws(() => factory.GetObject("manager")); + } + + /// + /// Lookup methods cannot accept any arguments (replace methods can though). + /// + [Test] + public void FailOnLookupMethodThatHasArguments() + { + RootObjectDefinition feedDef = new RootObjectDefinition(typeof(NewsFeed)); + feedDef.IsSingleton = false; + feedDef.PropertyValues.Add("name", "Bingo"); + + RootObjectDefinition managerDef = new RootObjectDefinition(typeof(NewsFeedManagerWithLookupMethodThatTakesArguments)); + managerDef.MethodOverrides.Add(new LookupMethodOverride("CreateNewsFeed", "feed")); + + DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); + factory.RegisterObjectDefinition("manager", managerDef); + factory.RegisterObjectDefinition("feed", feedDef); + Assert.Throws(() => factory.GetObject("manager")); + } + + #endregion +} + +public interface INewsFeedManager +{ + NewsFeed CreateNewsFeed(); +} + +public class ReturnsNullNewsFeedManager : INewsFeedManager +{ + private string name; + + public ReturnsNullNewsFeedManager() + { + } + + public ReturnsNullNewsFeedManager(string name) + { + this.name = name; + } + + public virtual NewsFeed CreateNewsFeed() + { + return null; + } + + public string Name + { + get { return name; } + } +} + +public sealed class SealedReturnsNullNewsFeedManager : INewsFeedManager +{ + public NewsFeed CreateNewsFeed() + { + return null; + } +} + +public class ProtectedReturnsNullNewsFeedManager +{ + public NewsFeed GrabNewsFeed() + { + return CreateNewsFeed(); + } + + protected NewsFeed CreateNewsFeed() + { + return null; + } +} + +public class ProtectedReturnsNullNewsFeedManagerWithVirtualMethod +{ + public NewsFeed GrabNewsFeed() + { + return CreateNewsFeed(); + } + + protected virtual NewsFeed CreateNewsFeed() + { + return null; + } +} + +/// +/// Just why anyone would want to do method injection on a method with a +/// void return type is a question best left for another (earlier) night. +/// +public class ReturnsVoidNewsFeedManager +{ + public virtual void CreateNewsFeed() + { + } +} + +public class NewsFeedManagerWithLookupMethodThatTakesArguments +{ + public virtual NewsFeed CreateNewsFeed(string foo, int bar) + { + return null; + } +} + +public class NewsFeedManagerThatReturnsVoid +{ + public virtual void DoSomething() + { + } +} + +public class DoNothingReplacer : IMethodReplacer +{ + public object Implement(object target, MethodInfo method, params object[] arguments) + { + return null; + } +} + +public class NewsFeedManagerWith_Replace_MethodThatTakesArguments +{ + public virtual NewsFeed CreateNewsFeed(string headline) + { + throw new NotImplementedException(); + } +} + +public abstract class AbstractNewsFeedManager : INewsFeedManager +{ + public abstract NewsFeed CreateNewsFeed(); +} + +public sealed class NewsFeedFactory : IMethodReplacer +{ + public const string DefaultName = "All The News That's Fit To Print"; + + public object Implement(object target, MethodInfo method, params object[] arguments) + { + if (arguments != null && arguments.Length > 0) + { + string headline = (string) arguments[0]; + return new NewsFeed(headline); } - [Test] - public void SunnyDayReplaceMethod_WithArgumentAcceptingReplacer() - { - RootObjectDefinition replacerDef = new RootObjectDefinition(typeof (NewsFeedFactory)); - - RootObjectDefinition managerDef = new RootObjectDefinition(typeof (NewsFeedManagerWith_Replace_MethodThatTakesArguments)); - ReplacedMethodOverride theOverride = new ReplacedMethodOverride("CreateNewsFeed", "replacer"); - // we must specify parameter type fragments... - theOverride.AddTypeIdentifier(typeof(string).FullName); - managerDef.MethodOverrides.Add(theOverride); - - DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); - factory.RegisterObjectDefinition("manager", managerDef); - factory.RegisterObjectDefinition("replacer", replacerDef); - NewsFeedManagerWith_Replace_MethodThatTakesArguments manager = (NewsFeedManagerWith_Replace_MethodThatTakesArguments) factory["manager"]; - NewsFeed feed1 = manager.CreateNewsFeed("So sad... to be all alone in the world"); - Assert.IsNotNull(feed1, "The CreateNewsFeed() method is not being replaced."); - Assert.AreEqual("So sad... to be all alone in the world", feed1.Name); - NewsFeed feed2 = manager.CreateNewsFeed("Oh Muzzy!"); - // NewsFeedFactory always yields a new NewsFeed (see class definition below)... - Assert.IsFalse(ReferenceEquals(feed1, feed2)); - } - - [Test] - public void SunnyDayReplaceMethod_WithArgumentAcceptingReplacerWithNoOverloadingAndNoTypeFragmentsSpecified() - { - RootObjectDefinition replacerDef = new RootObjectDefinition(typeof (NewsFeedFactory)); - - RootObjectDefinition managerDef = new RootObjectDefinition(typeof (NewsFeedManagerWith_Replace_MethodThatTakesArguments)); - ReplacedMethodOverride theOverride = new ReplacedMethodOverride("CreateNewsFeed", "replacer"); - // no need to specify parameter type fragments if we turn IsOverloaded off (the method is not overloaded)... - theOverride.IsOverloaded = false; - managerDef.MethodOverrides.Add(theOverride); - - DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); - factory.RegisterObjectDefinition("manager", managerDef); - factory.RegisterObjectDefinition("replacer", replacerDef); - NewsFeedManagerWith_Replace_MethodThatTakesArguments manager = (NewsFeedManagerWith_Replace_MethodThatTakesArguments) factory["manager"]; - NewsFeed feed1 = manager.CreateNewsFeed("So sad... to be all alone in the world"); - Assert.IsNotNull(feed1, "The CreateNewsFeed() method is not being replaced."); - Assert.AreEqual("So sad... to be all alone in the world", feed1.Name); - NewsFeed feed2 = manager.CreateNewsFeed("Oh Muzzy!"); - // NewsFeedFactory always yields a new NewsFeed (see class definition below)... - Assert.IsFalse(ReferenceEquals(feed1, feed2)); - } - - [Test] - public void SunnyDayReplaceMethod_WithReplacerThatReturnsVoid() - { - RootObjectDefinition replacerDef = new RootObjectDefinition(typeof (DoNothingReplacer)); - - RootObjectDefinition managerDef = new RootObjectDefinition(typeof (NewsFeedManagerThatReturnsVoid)); - ReplacedMethodOverride theOverride = new ReplacedMethodOverride("DoSomething", "replacer"); - managerDef.MethodOverrides.Add(theOverride); - - DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); - factory.RegisterObjectDefinition("manager", managerDef); - factory.RegisterObjectDefinition("replacer", replacerDef); - NewsFeedManagerThatReturnsVoid manager = (NewsFeedManagerThatReturnsVoid) factory["manager"]; - manager.DoSomething(); - } - - /// - /// We don't specify any type fragments, so the method overload check will never pass. - /// - [Test] - public void SunnyDayReplaceMethod_WithArgumentAcceptingReplacerWithNoTypeFragmentsSpecified() - { - RootObjectDefinition replacerDef = new RootObjectDefinition(typeof (NewsFeedFactory)); - - RootObjectDefinition managerDef = new RootObjectDefinition(typeof (NewsFeedManagerWith_Replace_MethodThatTakesArguments)); - managerDef.MethodOverrides.Add(new ReplacedMethodOverride("CreateNewsFeed", "replacer")); - - DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); - factory.RegisterObjectDefinition("manager", managerDef); - factory.RegisterObjectDefinition("replacer", replacerDef); - NewsFeedManagerWith_Replace_MethodThatTakesArguments manager = (NewsFeedManagerWith_Replace_MethodThatTakesArguments) factory["manager"]; - Assert.Throws(() => manager.CreateNewsFeed("So sad... to be all alone in the world")); - } - - /// - /// A class that requires two lookup method injections. - /// - [Test] - public void LookupMethodMultiple() - { - RootObjectDefinition feedDef = new RootObjectDefinition(typeof (NewsFeed)); - feedDef.IsSingleton = false; - feedDef.PropertyValues.Add("name", "Bingo"); - - RootObjectDefinition testObjectDef = new RootObjectDefinition(typeof (TestObject)); - testObjectDef.IsSingleton = false; - testObjectDef.PropertyValues.Add("name", "Miki Nakatani"); - - RootObjectDefinition managerDef = new RootObjectDefinition(typeof (TestObjectAndNewsFeedFactory)); - managerDef.MethodOverrides.Add(new LookupMethodOverride("CreateNewsFeed", "feed")); - managerDef.MethodOverrides.Add(new LookupMethodOverride("CreateTestObject", "test")); - - DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); - factory.RegisterObjectDefinition("manager", managerDef); - factory.RegisterObjectDefinition("feed", feedDef); - factory.RegisterObjectDefinition("test", testObjectDef); - TestObjectAndNewsFeedFactory manager = (TestObjectAndNewsFeedFactory) factory["manager"]; - - INewsFeedManager newsFeedManager = manager; - NewsFeed feed1 = newsFeedManager.CreateNewsFeed(); - Assert.IsNotNull(feed1, "The CreateNewsFeed() method is not being replaced."); - NewsFeed feed2 = newsFeedManager.CreateNewsFeed(); - // assert that the object (prototype) is definitely being looked up each time... - Assert.IsFalse(ReferenceEquals(feed1, feed2)); - - ITestObjectFactory toFactory = manager; - ITestObject to1 = toFactory.CreateTestObject(); - Assert.IsNotNull(to1, "The CreateTestObject() method is not being replaced."); - ITestObject to2 = toFactory.CreateTestObject(); - // assert that the object (prototype) is definitely being looked up each time... - Assert.IsFalse(ReferenceEquals(to1, to2)); - } - - /// - /// A class that requires both lookup method and replace method injection. - /// - [Test] - public void LookupAndReplaceMethod() - { - RootObjectDefinition replacerDef = new RootObjectDefinition(typeof (NewsFeedFactory)); - - RootObjectDefinition testObjectDef = new RootObjectDefinition(typeof (TestObject)); - testObjectDef.IsSingleton = false; - testObjectDef.PropertyValues.Add("name", "Miki Nakatani"); - - RootObjectDefinition managerDef = new RootObjectDefinition(typeof (TestObjectAndNewsFeedFactory)); - managerDef.MethodOverrides.Add(new ReplacedMethodOverride("CreateNewsFeed", "replacer")); - managerDef.MethodOverrides.Add(new LookupMethodOverride("CreateTestObject", "test")); - - DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); - factory.RegisterObjectDefinition("manager", managerDef); - factory.RegisterObjectDefinition("replacer", replacerDef); - factory.RegisterObjectDefinition("test", testObjectDef); - TestObjectAndNewsFeedFactory manager = (TestObjectAndNewsFeedFactory) factory["manager"]; - - INewsFeedManager newsFeedManager = manager; - NewsFeed feed1 = newsFeedManager.CreateNewsFeed(); - Assert.IsNotNull(feed1, "The CreateNewsFeed() method is not being replaced."); - NewsFeed feed2 = newsFeedManager.CreateNewsFeed(); - // assert that the object (prototype) is definitely being looked up each time... - Assert.IsFalse(ReferenceEquals(feed1, feed2)); - - ITestObjectFactory toFactory = manager; - ITestObject to1 = toFactory.CreateTestObject(); - Assert.IsNotNull(to1, "The CreateTestObject() method is not being replaced."); - ITestObject to2 = toFactory.CreateTestObject(); - // assert that the object (prototype) is definitely being looked up each time... - Assert.IsFalse(ReferenceEquals(to1, to2)); - } - - /// - /// Lookup method injection on an (interface) method that returns null. - /// - [Test] - public void LookupMethodWithNullMethod() - { - try - { - RootObjectDefinition feedDef = new RootObjectDefinition(typeof (NewsFeed)); - feedDef.IsSingleton = false; - feedDef.PropertyValues.Add("name", "Bingo"); - - RootObjectDefinition managerDef = new RootObjectDefinition(typeof (ReturnsNullNewsFeedManager)); - managerDef.MethodOverrides.Add(new LookupMethodOverride("CreateNewsFeed", "feed")); - - DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); - factory.RegisterObjectDefinition("manager", managerDef); - factory.RegisterObjectDefinition("feed", feedDef); - INewsFeedManager manager = (INewsFeedManager) factory["manager"]; - NewsFeed feed1 = manager.CreateNewsFeed(); - Assert.IsNotNull(feed1, "The CreateNewsFeed() method is not being replaced."); - NewsFeed feed2 = manager.CreateNewsFeed(); - // assert that the object (prototype) is definitely being looked up each time... - Assert.IsFalse(ReferenceEquals(feed1, feed2)); - } - catch (Exception ex) - { - Console.Out.WriteLine("ex = {0}", ex); - } - } - - /// - /// Lookup method injection on an (interface) method that returns null. - /// - /// - ///

- /// The only difference from the previous (similarly named) test is that - /// constructor arguments are passed to the (er) constructor as it (the - /// dynamic subclass) is being instantiated by the container. - ///

- ///
- [Test] - public void LookupMethodWithNullMethodInstantiatedWithCtorArg() - { - RootObjectDefinition feedDef = new RootObjectDefinition(typeof (NewsFeed)); - feedDef.IsSingleton = false; - feedDef.PropertyValues.Add("name", "Bingo"); - - RootObjectDefinition managerDef = new RootObjectDefinition(typeof (ReturnsNullNewsFeedManager)); - managerDef.MethodOverrides.Add(new LookupMethodOverride("CreateNewsFeed", "feed")); - managerDef.ConstructorArgumentValues.AddNamedArgumentValue("name", "Bingo"); - - DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); - factory.RegisterObjectDefinition("manager", managerDef); - factory.RegisterObjectDefinition("feed", feedDef); - ReturnsNullNewsFeedManager manager = (ReturnsNullNewsFeedManager) factory["manager"]; - Assert.AreEqual("Bingo", manager.Name); - NewsFeed feed1 = manager.CreateNewsFeed(); - Assert.IsNotNull(feed1, "The CreateNewsFeed() method is not being replaced."); - NewsFeed feed2 = manager.CreateNewsFeed(); - // assert that the object (prototype) is definitely being looked up each time... - Assert.IsFalse(ReferenceEquals(feed1, feed2)); - } - - [Test] - public void LookupMethodWithAbstractMethod() - { - RootObjectDefinition feedDef = new RootObjectDefinition(typeof (NewsFeed)); - feedDef.IsSingleton = false; - feedDef.PropertyValues.Add("name", "Bingo"); - - RootObjectDefinition managerDef = new RootObjectDefinition(typeof (AbstractNewsFeedManager)); - managerDef.MethodOverrides.Add(new LookupMethodOverride("CreateNewsFeed", "feed")); - - DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); - factory.RegisterObjectDefinition("manager", managerDef); - factory.RegisterObjectDefinition("feed", feedDef); - INewsFeedManager manager = (INewsFeedManager) factory["manager"]; - NewsFeed feed1 = manager.CreateNewsFeed(); - Assert.IsNotNull(feed1, "The CreateNewsFeed() method is not being replaced."); - NewsFeed feed2 = manager.CreateNewsFeed(); - // assert that the object (prototype) is definitely being looked up each time... - Assert.IsFalse(ReferenceEquals(feed1, feed2)); - } - - /// - /// Protected methods can also be method injected. - /// - [Test] - public void LookupMethodWithVirtualProtectedMethod() - { - RootObjectDefinition feedDef = new RootObjectDefinition(typeof (NewsFeed)); - feedDef.IsSingleton = false; - feedDef.PropertyValues.Add("name", "Bingo"); - - RootObjectDefinition managerDef = new RootObjectDefinition(typeof (ProtectedReturnsNullNewsFeedManagerWithVirtualMethod)); - managerDef.MethodOverrides.Add(new LookupMethodOverride("CreateNewsFeed", "feed")); - - DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); - factory.RegisterObjectDefinition("manager", managerDef); - factory.RegisterObjectDefinition("feed", feedDef); - ProtectedReturnsNullNewsFeedManagerWithVirtualMethod manager = (ProtectedReturnsNullNewsFeedManagerWithVirtualMethod) factory["manager"]; - NewsFeed feed1 = manager.GrabNewsFeed(); - Assert.IsNotNull(feed1, "The CreateNewsFeed() method is not being replaced."); - NewsFeed feed2 = manager.GrabNewsFeed(); - // assert that the object (prototype) is definitely being looked up each time... - Assert.IsFalse(ReferenceEquals(feed1, feed2)); - } - - #region Rainy Day Scenarios - - [Test] - public void FailWithLookupMethodOnSealedClass() - { - RootObjectDefinition feedDef = new RootObjectDefinition(typeof (NewsFeed)); - feedDef.IsSingleton = false; - feedDef.PropertyValues.Add("name", "Bingo"); - - RootObjectDefinition managerDef = new RootObjectDefinition(typeof (SealedReturnsNullNewsFeedManager)); - managerDef.MethodOverrides.Add(new LookupMethodOverride("CreateNewsFeed", "feed")); - - DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); - factory.RegisterObjectDefinition("manager", managerDef); - factory.RegisterObjectDefinition("feed", feedDef); - Assert.Throws(() => factory.GetObject("manager")); - } - - [Test] - public void FailWithReplaceMethodOnSealedClass() - { - RootObjectDefinition replacerDef = new RootObjectDefinition(typeof (NewsFeedFactory)); - - RootObjectDefinition managerDef = new RootObjectDefinition(typeof (SealedReturnsNullNewsFeedManager)); - managerDef.MethodOverrides.Add(new ReplacedMethodOverride("CreateNewsFeed", "replacer")); - - DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); - factory.RegisterObjectDefinition("manager", managerDef); - factory.RegisterObjectDefinition("replacer", replacerDef); - Assert.Throws(() => factory.GetObject("manager")); - } - - /// - /// Tests that one cannot (obviously) override a protected method that has - /// not been explicitly declared virtual on the original class declaration. - /// - [Test] - public void FailOnNonVirtualProtectedMethod() - { - RootObjectDefinition feedDef = new RootObjectDefinition(typeof (NewsFeed)); - feedDef.IsSingleton = false; - feedDef.PropertyValues.Add("name", "Bingo"); - - RootObjectDefinition managerDef = new RootObjectDefinition(typeof (ProtectedReturnsNullNewsFeedManager)); - managerDef.MethodOverrides.Add(new LookupMethodOverride("CreateNewsFeed", "feed")); - - DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); - factory.RegisterObjectDefinition("manager", managerDef); - factory.RegisterObjectDefinition("feed", feedDef); - Assert.Throws(() => factory.GetObject("manager")); - } - - /// - /// Tests that one cannot (obviously) method inject a method with a void - /// return type. - /// - [Test] - public void FailOnMethodWithVoidReturnType() - { - RootObjectDefinition feedDef = new RootObjectDefinition(typeof (NewsFeed)); - feedDef.IsSingleton = false; - feedDef.PropertyValues.Add("name", "Bingo"); - - RootObjectDefinition managerDef = new RootObjectDefinition(typeof (ReturnsVoidNewsFeedManager)); - managerDef.MethodOverrides.Add(new LookupMethodOverride("CreateNewsFeed", "feed")); - - DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); - factory.RegisterObjectDefinition("manager", managerDef); - factory.RegisterObjectDefinition("feed", feedDef); - Assert.Throws(() => factory.GetObject("manager")); - } - - /// - /// Lookup methods cannot accept any arguments (replace methods can though). - /// - [Test] - public void FailOnLookupMethodThatHasArguments() - { - RootObjectDefinition feedDef = new RootObjectDefinition(typeof (NewsFeed)); - feedDef.IsSingleton = false; - feedDef.PropertyValues.Add("name", "Bingo"); - - RootObjectDefinition managerDef = new RootObjectDefinition(typeof (NewsFeedManagerWithLookupMethodThatTakesArguments)); - managerDef.MethodOverrides.Add(new LookupMethodOverride("CreateNewsFeed", "feed")); - - DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); - factory.RegisterObjectDefinition("manager", managerDef); - factory.RegisterObjectDefinition("feed", feedDef); - Assert.Throws(() => factory.GetObject("manager")); - } - - #endregion - } - - - public interface INewsFeedManager - { - NewsFeed CreateNewsFeed(); - } - - public class ReturnsNullNewsFeedManager : INewsFeedManager - { - private string name; - - public ReturnsNullNewsFeedManager() - { - } - - public ReturnsNullNewsFeedManager(string name) - { - this.name = name; - } - - public virtual NewsFeed CreateNewsFeed() - { - return null; - } - - public string Name - { - get { return name; } - } - } - - public sealed class SealedReturnsNullNewsFeedManager : INewsFeedManager - { - public NewsFeed CreateNewsFeed() - { - return null; - } - } - - public class ProtectedReturnsNullNewsFeedManager - { - public NewsFeed GrabNewsFeed() - { - return CreateNewsFeed(); - } - - protected NewsFeed CreateNewsFeed() - { - return null; - } - } - - public class ProtectedReturnsNullNewsFeedManagerWithVirtualMethod - { - public NewsFeed GrabNewsFeed() - { - return CreateNewsFeed(); - } - - protected virtual NewsFeed CreateNewsFeed() - { - return null; - } - } - - /// - /// Just why anyone would want to do method injection on a method with a - /// void return type is a question best left for another (earlier) night. - /// - public class ReturnsVoidNewsFeedManager - { - public virtual void CreateNewsFeed() - { - } - } - - public class NewsFeedManagerWithLookupMethodThatTakesArguments - { - public virtual NewsFeed CreateNewsFeed(string foo, int bar) - { - return null; - } - } - - public class NewsFeedManagerThatReturnsVoid - { - public virtual void DoSomething() - { - } - } - - public class DoNothingReplacer : IMethodReplacer - { - public object Implement(object target, MethodInfo method, params object[] arguments) - { - return null; - } - } - - public class NewsFeedManagerWith_Replace_MethodThatTakesArguments - { - public virtual NewsFeed CreateNewsFeed(string headline) - { - throw new NotImplementedException(); - } - } - - public abstract class AbstractNewsFeedManager : INewsFeedManager - { - public abstract NewsFeed CreateNewsFeed(); - } - - public sealed class NewsFeedFactory : IMethodReplacer - { - public const string DefaultName = "All The News That's Fit To Print"; - - public object Implement(object target, MethodInfo method, params object[] arguments) - { - if (arguments != null && arguments.Length > 0) - { - string headline = (string) arguments[0]; - return new NewsFeed(headline); - } - return new NewsFeed(DefaultName); - } - } - - public sealed class NewsFeed - { - private string name; - - public NewsFeed() - { - } - - public NewsFeed(string name) - { - this.name = name; - } - - public string Name - { - get { return name; } - set { name = value; } - } - } - - public interface ITestObjectFactory - { - ITestObject CreateTestObject(); - } - - public class TestObjectAndNewsFeedFactory : ITestObjectFactory, INewsFeedManager - { - public virtual ITestObject CreateTestObject() - { - throw new NotImplementedException(); - } - - public virtual NewsFeed CreateNewsFeed() - { - throw new NotImplementedException(); - } - } -} \ No newline at end of file + return new NewsFeed(DefaultName); + } +} + +public sealed class NewsFeed +{ + private string name; + + public NewsFeed() + { + } + + public NewsFeed(string name) + { + this.name = name; + } + + public string Name + { + get { return name; } + set { name = value; } + } +} + +public interface ITestObjectFactory +{ + ITestObject CreateTestObject(); +} + +public class TestObjectAndNewsFeedFactory : ITestObjectFactory, INewsFeedManager +{ + public virtual ITestObject CreateTestObject() + { + throw new NotImplementedException(); + } + + public virtual NewsFeed CreateNewsFeed() + { + throw new NotImplementedException(); + } +} diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/MustBeInitialized.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/MustBeInitialized.cs index 08173a02..c9e4799d 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/MustBeInitialized.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/MustBeInitialized.cs @@ -22,45 +22,49 @@ #endregion -namespace Spring.Objects.Factory { +namespace Spring.Objects.Factory; - /// - /// Simple test of IObjectFactory initialization. +/// +/// Simple test of IObjectFactory initialization. +/// +/// Rod Johnson +/// Rick Evans (.NET) +public class MustBeInitialized : IInitializingObject +{ + #region Constructor (s) / Destructor + + /// + /// Creates a new instance of the class. /// - /// Rod Johnson - /// Rick Evans (.NET) - public class MustBeInitialized : IInitializingObject + public MustBeInitialized() { } + + #endregion + + #region Methods + + public void AfterPropertiesSet() { + inited = true; + } - #region Constructor (s) / Destructor - /// - /// Creates a new instance of the class. - /// - public MustBeInitialized() {} - #endregion - - #region Methods - public void AfterPropertiesSet () + /// + /// Dummy business method that will fail unless the factory + /// managed the object's lifecycle correctly. + /// + public virtual void BusinessMethod() + { + if (!inited) { - inited = true; + throw new SystemException( + "Factory didn't call AfterPropertiesSet () on MustBeInitialized object"); } + } - /// - /// Dummy business method that will fail unless the factory - /// managed the object's lifecycle correctly. - /// - public virtual void BusinessMethod () - { - if (!inited) - { - throw new SystemException ( - "Factory didn't call AfterPropertiesSet () on MustBeInitialized object"); - } - } - #endregion + #endregion - #region Fields - private bool inited; - #endregion - } + #region Fields + + private bool inited; + + #endregion } diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/NoSuchObjectDefinitionExceptionTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/NoSuchObjectDefinitionExceptionTests.cs index ed999056..66cc6c57 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/NoSuchObjectDefinitionExceptionTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/NoSuchObjectDefinitionExceptionTests.cs @@ -21,66 +21,66 @@ using System.Runtime.Serialization.Formatters.Binary; using NUnit.Framework; -namespace Spring.Objects.Factory +namespace Spring.Objects.Factory; + +/// +/// Unit tests for the NoSuchObjectDefinitionException class. +/// +/// Rick Evans +[TestFixture] +public sealed class NoSuchObjectDefinitionExceptionTests { - /// - /// Unit tests for the NoSuchObjectDefinitionException class. - /// - /// Rick Evans - [TestFixture] - public sealed class NoSuchObjectDefinitionExceptionTests - { - public const string NotFoundObjectDefinitionName = "myObject"; + public const string NotFoundObjectDefinitionName = "myObject"; - public static readonly Type NotFoundObjectDefinitionType = typeof (TestObject); + public static readonly Type NotFoundObjectDefinitionType = typeof(TestObject); - [Test] - public void SerializesObjectNameFieldCorrectly() - { - NoSuchObjectDefinitionException ex - = new NoSuchObjectDefinitionException(NotFoundObjectDefinitionName, "Cannot dynamically build object key..."); - NoSuchObjectDefinitionException deserializedException = Serialize(ex); - Assert.IsNotNull(deserializedException); - Assert.AreEqual(NotFoundObjectDefinitionName, deserializedException.ObjectName, "'ObjectName' property was not serialized correctly."); - } + [Test] + public void SerializesObjectNameFieldCorrectly() + { + NoSuchObjectDefinitionException ex + = new NoSuchObjectDefinitionException(NotFoundObjectDefinitionName, "Cannot dynamically build object key..."); + NoSuchObjectDefinitionException deserializedException = Serialize(ex); + Assert.IsNotNull(deserializedException); + Assert.AreEqual(NotFoundObjectDefinitionName, deserializedException.ObjectName, "'ObjectName' property was not serialized correctly."); + } - [Test] - public void SerializesObjectTypeFieldCorrectly() - { - NoSuchObjectDefinitionException ex - = new NoSuchObjectDefinitionException(NotFoundObjectDefinitionType, null); - NoSuchObjectDefinitionException deserializedException = Serialize(ex); - Assert.IsNotNull(deserializedException); - Assert.AreEqual(NotFoundObjectDefinitionType, deserializedException.ObjectType, "'ObjectType' property was not serialized correctly."); - } + [Test] + public void SerializesObjectTypeFieldCorrectly() + { + NoSuchObjectDefinitionException ex + = new NoSuchObjectDefinitionException(NotFoundObjectDefinitionType, null); + NoSuchObjectDefinitionException deserializedException = Serialize(ex); + Assert.IsNotNull(deserializedException); + Assert.AreEqual(NotFoundObjectDefinitionType, deserializedException.ObjectType, "'ObjectType' property was not serialized correctly."); + } - private NoSuchObjectDefinitionException Serialize(NoSuchObjectDefinitionException inputException) - { - NoSuchObjectDefinitionException deserializedException = null; - string tempDir = Environment.GetEnvironmentVariable("TEMP"); - string tempFilename = tempDir + @"\foo.dat"; - FileInfo file = new FileInfo(tempFilename); - try - { - Stream outstream = file.OpenWrite(); - new BinaryFormatter().Serialize(outstream, inputException); - outstream.Flush(); - outstream.Close(); - Stream instream = file.OpenRead(); - deserializedException = new BinaryFormatter().Deserialize(instream) as NoSuchObjectDefinitionException; - instream.Close(); - } - finally - { - try - { - file.Delete(); - } - catch - { - } - } - return deserializedException; - } - } -} \ No newline at end of file + private NoSuchObjectDefinitionException Serialize(NoSuchObjectDefinitionException inputException) + { + NoSuchObjectDefinitionException deserializedException = null; + string tempDir = Environment.GetEnvironmentVariable("TEMP"); + string tempFilename = tempDir + @"\foo.dat"; + FileInfo file = new FileInfo(tempFilename); + try + { + Stream outstream = file.OpenWrite(); + new BinaryFormatter().Serialize(outstream, inputException); + outstream.Flush(); + outstream.Close(); + Stream instream = file.OpenRead(); + deserializedException = new BinaryFormatter().Deserialize(instream) as NoSuchObjectDefinitionException; + instream.Close(); + } + finally + { + try + { + file.Delete(); + } + catch + { + } + } + + return deserializedException; + } +} diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/ObjectDefinitionStoreExceptionTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/ObjectDefinitionStoreExceptionTests.cs index d03931d5..e8b017b5 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/ObjectDefinitionStoreExceptionTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/ObjectDefinitionStoreExceptionTests.cs @@ -19,91 +19,89 @@ #endregion using FakeItEasy; - using NUnit.Framework; using Spring.Core.IO; using Spring.Util; -namespace Spring.Objects.Factory +namespace Spring.Objects.Factory; + +/// +/// Unit tests for the ObjectDefinitionStoreException class. +/// +/// Rick Evans +[TestFixture] +public sealed class ObjectDefinitionStoreExceptionTests { - /// - /// Unit tests for the ObjectDefinitionStoreException class. - /// - /// Rick Evans - [TestFixture] - public sealed class ObjectDefinitionStoreExceptionTests - { - [SetUp] - public void Setup() - { - } + [SetUp] + public void Setup() + { + } - [Test] - public void FromResource() - { - string expectedName = "bing"; - string expectedResourceDescription = "mock.resource"; - IResource resource = A.Fake(); - A.CallTo(() => resource.Description).Returns(expectedResourceDescription); + [Test] + public void FromResource() + { + string expectedName = "bing"; + string expectedResourceDescription = "mock.resource"; + IResource resource = A.Fake(); + A.CallTo(() => resource.Description).Returns(expectedResourceDescription); - ObjectDefinitionStoreException inex = new ObjectDefinitionStoreException(resource, expectedName, "mmm..."); - CheckSerialization(inex, expectedName, expectedResourceDescription); - } + ObjectDefinitionStoreException inex = new ObjectDefinitionStoreException(resource, expectedName, "mmm..."); + CheckSerialization(inex, expectedName, expectedResourceDescription); + } - [Test] - public void FromNullResource() - { - string expectedName = "bing"; - string expectedResourceDescription = string.Empty; - ObjectDefinitionStoreException inex - = new ObjectDefinitionStoreException( - (IResource) null, expectedName, "mmm..."); - CheckSerialization(inex, expectedName, - expectedResourceDescription); - } + [Test] + public void FromNullResource() + { + string expectedName = "bing"; + string expectedResourceDescription = string.Empty; + ObjectDefinitionStoreException inex + = new ObjectDefinitionStoreException( + (IResource) null, expectedName, "mmm..."); + CheckSerialization(inex, expectedName, + expectedResourceDescription); + } - [Test] - public void SerializesWithNoState() - { - ObjectDefinitionStoreException inex - = new ObjectDefinitionStoreException(); - CheckSerialization(inex, string.Empty, string.Empty); - } + [Test] + public void SerializesWithNoState() + { + ObjectDefinitionStoreException inex + = new ObjectDefinitionStoreException(); + CheckSerialization(inex, string.Empty, string.Empty); + } - [Test] - public void SerializesWithJustExceptionMessage() - { - string expectedName = string.Empty; - string expectedResourceDescription = string.Empty; - string expectedMessage = "Woppadoosa"; - ObjectDefinitionStoreException inex - = new ObjectDefinitionStoreException(expectedMessage); - CheckSerialization(inex, expectedName, - expectedResourceDescription); - } + [Test] + public void SerializesWithJustExceptionMessage() + { + string expectedName = string.Empty; + string expectedResourceDescription = string.Empty; + string expectedMessage = "Woppadoosa"; + ObjectDefinitionStoreException inex + = new ObjectDefinitionStoreException(expectedMessage); + CheckSerialization(inex, expectedName, + expectedResourceDescription); + } - [Test] - public void SerializesAllState() - { - string expectedName = "bing"; - string expectedResourceDescription = "foo.txt"; - ObjectDefinitionStoreException inex - = new ObjectDefinitionStoreException( - expectedResourceDescription, expectedName, "mmm..."); - CheckSerialization(inex, expectedName, - expectedResourceDescription); - } + [Test] + public void SerializesAllState() + { + string expectedName = "bing"; + string expectedResourceDescription = "foo.txt"; + ObjectDefinitionStoreException inex + = new ObjectDefinitionStoreException( + expectedResourceDescription, expectedName, "mmm..."); + CheckSerialization(inex, expectedName, + expectedResourceDescription); + } - private static void CheckSerialization( - ObjectDefinitionStoreException inex, string expectedName, - string expectedResourceDescription) - { - ObjectDefinitionStoreException outex = (ObjectDefinitionStoreException) - SerializationTestUtils.SerializeAndDeserialize(inex); - Assert.AreEqual(expectedName, outex.ObjectName, - "The 'ObjectName' property was not serialized / deserialized correctly."); - Assert.AreEqual(expectedResourceDescription, outex.ResourceDescription, - "The 'ResourceDescription' property was not serialized / deserialized correctly."); - } - } -} \ No newline at end of file + private static void CheckSerialization( + ObjectDefinitionStoreException inex, string expectedName, + string expectedResourceDescription) + { + ObjectDefinitionStoreException outex = (ObjectDefinitionStoreException) + SerializationTestUtils.SerializeAndDeserialize(inex); + Assert.AreEqual(expectedName, outex.ObjectName, + "The 'ObjectName' property was not serialized / deserialized correctly."); + Assert.AreEqual(expectedResourceDescription, outex.ResourceDescription, + "The 'ResourceDescription' property was not serialized / deserialized correctly."); + } +} diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/ObjectFactoryUtilsTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/ObjectFactoryUtilsTests.cs index 679bf8e1..e5fb48b7 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/ObjectFactoryUtilsTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/ObjectFactoryUtilsTests.cs @@ -2,13 +2,13 @@ /* * Copyright 2002-2010 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. @@ -22,231 +22,229 @@ using System.Collections; using NUnit.Framework; - using Spring.Objects.Factory.Config; using Spring.Objects.Factory.Support; using Spring.Objects.Factory.Xml; #endregion -namespace Spring.Objects.Factory +namespace Spring.Objects.Factory; + +/// +/// Unit tests for the ObjectFactoryUtils class. +/// +/// Rod Johnson +/// Simon White (.NET) +/// Rick Evans (.NET) +[TestFixture] +public sealed class ObjectFactoryUtilsTests { - /// - /// Unit tests for the ObjectFactoryUtils class. - /// - /// Rod Johnson - /// Simon White (.NET) - /// Rick Evans (.NET) - [TestFixture] - public sealed class ObjectFactoryUtilsTests + private IConfigurableListableObjectFactory _factory; + + [SetUp] + public void SetUp() { - private IConfigurableListableObjectFactory _factory; - - [SetUp] - public void SetUp() - { - IObjectFactory grandparent = new XmlObjectFactory(new ReadOnlyXmlTestResource("root.xml", GetType())); - IObjectFactory parent = new XmlObjectFactory(new ReadOnlyXmlTestResource("middle.xml", GetType()), grandparent); - IConfigurableListableObjectFactory child = new XmlObjectFactory(new ReadOnlyXmlTestResource("leaf.xml", GetType()), parent); - _factory = child; - } - - /// - /// Check that override doesn't count as two separate objects. - /// - [Test] - public void CountObjectsIncludingAncestors() - { - // leaf count... - Assert.AreEqual(1, _factory.ObjectDefinitionCount); - // count minus duplicate... - Assert.AreEqual(6, ObjectFactoryUtils.CountObjectsIncludingAncestors(_factory), - "Should count 6 objects, not " + ObjectFactoryUtils.CountObjectsIncludingAncestors(_factory)); - } - - [Test] - public void ObjectNamesIncludingAncestors() - { - var names = ObjectFactoryUtils.ObjectNamesIncludingAncestors(_factory); - Assert.AreEqual(6, names.Count); - } - - [Test] - public void ObjectNamesForTypeIncludingAncestors() - { - var names = ObjectFactoryUtils.ObjectNamesForTypeIncludingAncestors(_factory, typeof(ITestObject)); - // includes 2 TestObjects from IFactoryObjects (DummyFactory definitions) - Assert.AreEqual(4, names.Count); - Assert.IsTrue(names.Contains("test")); - Assert.IsTrue(names.Contains("test3")); - Assert.IsTrue(names.Contains("testFactory1")); - Assert.IsTrue(names.Contains("testFactory2")); - } - - [Test] - public void ObjectNamesForTypeIncludingAncestorsExcludesObjectsFromParentWhenLocalObjectDefined() - { - DefaultListableObjectFactory root = new DefaultListableObjectFactory(); - root.RegisterObjectDefinition("excludeLocalObject", new RootObjectDefinition(typeof(ArrayList))); - DefaultListableObjectFactory child = new DefaultListableObjectFactory(root); - child.RegisterObjectDefinition("excludeLocalObject", new RootObjectDefinition(typeof(Hashtable))); - - var names = ObjectFactoryUtils.ObjectNamesForTypeIncludingAncestors(child, typeof(ArrayList)); - // "excludeLocalObject" matches on the parent, but not the local object definition - Assert.AreEqual(0, names.Count); - - names = ObjectFactoryUtils.ObjectNamesForTypeIncludingAncestors(child, typeof(ArrayList), true, true); - // "excludeLocalObject" matches on the parent, but not the local object definition - Assert.AreEqual(0, names.Count); - } - - [Test] - public void CountObjectsIncludingAncestorsWithNonHierarchicalFactory() - { - StaticListableObjectFactory lof = new StaticListableObjectFactory(); - lof.AddObject("t1", new TestObject()); - lof.AddObject("t2", new TestObject()); - Assert.IsTrue(ObjectFactoryUtils.CountObjectsIncludingAncestors(lof) == 2); - } - - [Test] - public void HierarchicalResolutionWithOverride() - { - object test3 = _factory.GetObject("test3"); - object test = _factory.GetObject("test"); - object testFactory1 = _factory.GetObject("testFactory1"); - - IDictionary objects = ObjectFactoryUtils.ObjectsOfTypeIncludingAncestors(_factory, typeof(ITestObject), true, false); - Assert.AreEqual(3, objects.Count); - Assert.AreEqual(test3, objects["test3"]); - Assert.AreEqual(test, objects["test"]); - Assert.AreEqual(testFactory1, objects["testFactory1"]); - objects = ObjectFactoryUtils.ObjectsOfTypeIncludingAncestors(_factory, typeof(ITestObject), false, false); - Assert.AreEqual(2, objects.Count); - Assert.AreEqual(test, objects["test"]); - Assert.AreEqual(testFactory1, objects["testFactory1"]); - objects = ObjectFactoryUtils.ObjectsOfTypeIncludingAncestors(_factory, typeof(ITestObject), false, true); - Assert.AreEqual(2, objects.Count); - Assert.AreEqual(test, objects["test"]); - Assert.AreEqual(testFactory1, objects["testFactory1"]); - objects = ObjectFactoryUtils.ObjectsOfTypeIncludingAncestors(_factory, typeof(ITestObject), true, true); - Assert.AreEqual(4, objects.Count); - Assert.AreEqual(test3, objects["test3"]); - Assert.AreEqual(test, objects["test"]); - Assert.AreEqual(testFactory1, objects["testFactory1"]); - Assert.IsTrue(objects["testFactory2"] is ITestObject); - objects = ObjectFactoryUtils.ObjectsOfTypeIncludingAncestors(_factory, typeof(DummyFactory), true, true); - Assert.AreEqual(2, objects.Count); - Assert.AreEqual(_factory.GetObject("&testFactory1"), objects["&testFactory1"]); - Assert.AreEqual(_factory.GetObject("&testFactory2"), objects["&testFactory2"]); - objects = ObjectFactoryUtils.ObjectsOfTypeIncludingAncestors(_factory, typeof(IFactoryObject), true, true); - Assert.AreEqual(2, objects.Count); - Assert.AreEqual(_factory.GetObject("&testFactory1"), objects["&testFactory1"]); - Assert.AreEqual(_factory.GetObject("&testFactory2"), objects["&testFactory2"]); - } - - [Test] - public void ObjectOfTypeIncludingAncestorsWithMoreThanOneObjectOfType() - { - Assert.Throws( - () => ObjectFactoryUtils.ObjectOfTypeIncludingAncestors(_factory, typeof(ITestObject), true, true), - "No unique object of type [Spring.Objects.ITestObject] is defined : Expected single object but found 4"); - } - - [Test] - public void ObjectOfTypeIncludingAncestorsExcludesObjectsFromParentWhenLocalObjectDefined() - { - DefaultListableObjectFactory root = new DefaultListableObjectFactory(); - root.RegisterObjectDefinition("excludeLocalObject", new RootObjectDefinition(typeof(ArrayList))); - DefaultListableObjectFactory child = new DefaultListableObjectFactory(root); - child.RegisterObjectDefinition("excludeLocalObject", new RootObjectDefinition(typeof(Hashtable))); - - IDictionary objectEntries = ObjectFactoryUtils.ObjectsOfTypeIncludingAncestors(child, typeof(ArrayList), true, true); - // "excludeLocalObject" matches on the parent, but not the local object definition - Assert.AreEqual(0, objectEntries.Count); - } - - [Test] - public void NoObjectsOfTypeIncludingAncestors() - { - StaticListableObjectFactory lof = new StaticListableObjectFactory(); - lof.AddObject("foo", new object()); - IDictionary objects = ObjectFactoryUtils.ObjectsOfTypeIncludingAncestors(lof, typeof(ITestObject), true, false); - Assert.IsTrue(objects.Count == 0); - } - - [Test] - public void ObjectsOfTypeIncludingAncestorsWithStaticFactory() - { - StaticListableObjectFactory lof = new StaticListableObjectFactory(); - TestObject t1 = new TestObject(); - TestObject t2 = new TestObject(); - DummyFactory t3 = new DummyFactory(); - DummyFactory t4 = new DummyFactory(); - t4.IsSingleton = false; - lof.AddObject("t1", t1); - lof.AddObject("t2", t2); - lof.AddObject("t3", t3); - t3.AfterPropertiesSet(); // StaticListableObjectFactory does support lifecycle calls. - lof.AddObject("t4", t4); - t4.AfterPropertiesSet(); // StaticListableObjectFactory does support lifecycle calls. - IDictionary objects = ObjectFactoryUtils.ObjectsOfTypeIncludingAncestors(lof, typeof(ITestObject), true, false); - Assert.AreEqual(2, objects.Count); - Assert.AreEqual(t1, objects["t1"]); - Assert.AreEqual(t2, objects["t2"]); - objects = ObjectFactoryUtils.ObjectsOfTypeIncludingAncestors(lof, typeof(ITestObject), false, true); - Assert.AreEqual(3, objects.Count); - Assert.AreEqual(t1, objects["t1"]); - Assert.AreEqual(t2, objects["t2"]); - Assert.AreEqual(t3.GetObject(), objects["t3"]); - objects = ObjectFactoryUtils.ObjectsOfTypeIncludingAncestors(lof, typeof(ITestObject), true, true); - Assert.AreEqual(4, objects.Count); - Assert.AreEqual(t1, objects["t1"]); - Assert.AreEqual(t2, objects["t2"]); - Assert.AreEqual(t3.GetObject(), objects["t3"]); - Assert.IsTrue(objects["t4"] is TestObject); - } - - [Test] - public void IsFactoryDereferenceWithNonFactoryObjectName() - { - Assert.IsFalse(ObjectFactoryUtils.IsFactoryDereference("roob"), - "Name that didn't start with the factory object prefix is being reported " + - "(incorrectly) as a factory object dereference."); - } - - [Test] - public void IsFactoryDereferenceWithNullName() - { - Assert.IsFalse(ObjectFactoryUtils.IsFactoryDereference(null), - "Null name that (obviously) didn't start with the factory object prefix is being reported " + - "(incorrectly) as a factory object dereference."); - } - - [Test] - public void IsFactoryDereferenceWithEmptyName() - { - Assert.IsFalse(ObjectFactoryUtils.IsFactoryDereference(string.Empty), - "String.Empty name that (obviously) didn't start with the factory object prefix is being reported " + - "(incorrectly) as a factory object dereference."); - } - - [Test] - public void IsFactoryDereferenceWithJustTheFactoryObjectPrefixCharacter() - { - Assert.IsFalse(ObjectFactoryUtils.IsFactoryDereference( - ObjectFactoryUtils.FactoryObjectPrefix), - "Name that consisted solely of the factory object prefix is being reported " + - "(incorrectly) as a factory object dereference."); - } - - [Test] - public void IsFactoryDereferenceSunnyDay() - { - Assert.IsTrue(ObjectFactoryUtils.IsFactoryDereference( - ObjectFactoryUtils.FactoryObjectPrefix + "roob"), - "Name that did start with the factory object prefix is not being reported " + - "(incorrectly) as a factory object dereference."); - } + IObjectFactory grandparent = new XmlObjectFactory(new ReadOnlyXmlTestResource("root.xml", GetType())); + IObjectFactory parent = new XmlObjectFactory(new ReadOnlyXmlTestResource("middle.xml", GetType()), grandparent); + IConfigurableListableObjectFactory child = new XmlObjectFactory(new ReadOnlyXmlTestResource("leaf.xml", GetType()), parent); + _factory = child; } -} \ No newline at end of file + + /// + /// Check that override doesn't count as two separate objects. + /// + [Test] + public void CountObjectsIncludingAncestors() + { + // leaf count... + Assert.AreEqual(1, _factory.ObjectDefinitionCount); + // count minus duplicate... + Assert.AreEqual(6, ObjectFactoryUtils.CountObjectsIncludingAncestors(_factory), + "Should count 6 objects, not " + ObjectFactoryUtils.CountObjectsIncludingAncestors(_factory)); + } + + [Test] + public void ObjectNamesIncludingAncestors() + { + var names = ObjectFactoryUtils.ObjectNamesIncludingAncestors(_factory); + Assert.AreEqual(6, names.Count); + } + + [Test] + public void ObjectNamesForTypeIncludingAncestors() + { + var names = ObjectFactoryUtils.ObjectNamesForTypeIncludingAncestors(_factory, typeof(ITestObject)); + // includes 2 TestObjects from IFactoryObjects (DummyFactory definitions) + Assert.AreEqual(4, names.Count); + Assert.IsTrue(names.Contains("test")); + Assert.IsTrue(names.Contains("test3")); + Assert.IsTrue(names.Contains("testFactory1")); + Assert.IsTrue(names.Contains("testFactory2")); + } + + [Test] + public void ObjectNamesForTypeIncludingAncestorsExcludesObjectsFromParentWhenLocalObjectDefined() + { + DefaultListableObjectFactory root = new DefaultListableObjectFactory(); + root.RegisterObjectDefinition("excludeLocalObject", new RootObjectDefinition(typeof(ArrayList))); + DefaultListableObjectFactory child = new DefaultListableObjectFactory(root); + child.RegisterObjectDefinition("excludeLocalObject", new RootObjectDefinition(typeof(Hashtable))); + + var names = ObjectFactoryUtils.ObjectNamesForTypeIncludingAncestors(child, typeof(ArrayList)); + // "excludeLocalObject" matches on the parent, but not the local object definition + Assert.AreEqual(0, names.Count); + + names = ObjectFactoryUtils.ObjectNamesForTypeIncludingAncestors(child, typeof(ArrayList), true, true); + // "excludeLocalObject" matches on the parent, but not the local object definition + Assert.AreEqual(0, names.Count); + } + + [Test] + public void CountObjectsIncludingAncestorsWithNonHierarchicalFactory() + { + StaticListableObjectFactory lof = new StaticListableObjectFactory(); + lof.AddObject("t1", new TestObject()); + lof.AddObject("t2", new TestObject()); + Assert.IsTrue(ObjectFactoryUtils.CountObjectsIncludingAncestors(lof) == 2); + } + + [Test] + public void HierarchicalResolutionWithOverride() + { + object test3 = _factory.GetObject("test3"); + object test = _factory.GetObject("test"); + object testFactory1 = _factory.GetObject("testFactory1"); + + IDictionary objects = ObjectFactoryUtils.ObjectsOfTypeIncludingAncestors(_factory, typeof(ITestObject), true, false); + Assert.AreEqual(3, objects.Count); + Assert.AreEqual(test3, objects["test3"]); + Assert.AreEqual(test, objects["test"]); + Assert.AreEqual(testFactory1, objects["testFactory1"]); + objects = ObjectFactoryUtils.ObjectsOfTypeIncludingAncestors(_factory, typeof(ITestObject), false, false); + Assert.AreEqual(2, objects.Count); + Assert.AreEqual(test, objects["test"]); + Assert.AreEqual(testFactory1, objects["testFactory1"]); + objects = ObjectFactoryUtils.ObjectsOfTypeIncludingAncestors(_factory, typeof(ITestObject), false, true); + Assert.AreEqual(2, objects.Count); + Assert.AreEqual(test, objects["test"]); + Assert.AreEqual(testFactory1, objects["testFactory1"]); + objects = ObjectFactoryUtils.ObjectsOfTypeIncludingAncestors(_factory, typeof(ITestObject), true, true); + Assert.AreEqual(4, objects.Count); + Assert.AreEqual(test3, objects["test3"]); + Assert.AreEqual(test, objects["test"]); + Assert.AreEqual(testFactory1, objects["testFactory1"]); + Assert.IsTrue(objects["testFactory2"] is ITestObject); + objects = ObjectFactoryUtils.ObjectsOfTypeIncludingAncestors(_factory, typeof(DummyFactory), true, true); + Assert.AreEqual(2, objects.Count); + Assert.AreEqual(_factory.GetObject("&testFactory1"), objects["&testFactory1"]); + Assert.AreEqual(_factory.GetObject("&testFactory2"), objects["&testFactory2"]); + objects = ObjectFactoryUtils.ObjectsOfTypeIncludingAncestors(_factory, typeof(IFactoryObject), true, true); + Assert.AreEqual(2, objects.Count); + Assert.AreEqual(_factory.GetObject("&testFactory1"), objects["&testFactory1"]); + Assert.AreEqual(_factory.GetObject("&testFactory2"), objects["&testFactory2"]); + } + + [Test] + public void ObjectOfTypeIncludingAncestorsWithMoreThanOneObjectOfType() + { + Assert.Throws( + () => ObjectFactoryUtils.ObjectOfTypeIncludingAncestors(_factory, typeof(ITestObject), true, true), + "No unique object of type [Spring.Objects.ITestObject] is defined : Expected single object but found 4"); + } + + [Test] + public void ObjectOfTypeIncludingAncestorsExcludesObjectsFromParentWhenLocalObjectDefined() + { + DefaultListableObjectFactory root = new DefaultListableObjectFactory(); + root.RegisterObjectDefinition("excludeLocalObject", new RootObjectDefinition(typeof(ArrayList))); + DefaultListableObjectFactory child = new DefaultListableObjectFactory(root); + child.RegisterObjectDefinition("excludeLocalObject", new RootObjectDefinition(typeof(Hashtable))); + + IDictionary objectEntries = ObjectFactoryUtils.ObjectsOfTypeIncludingAncestors(child, typeof(ArrayList), true, true); + // "excludeLocalObject" matches on the parent, but not the local object definition + Assert.AreEqual(0, objectEntries.Count); + } + + [Test] + public void NoObjectsOfTypeIncludingAncestors() + { + StaticListableObjectFactory lof = new StaticListableObjectFactory(); + lof.AddObject("foo", new object()); + IDictionary objects = ObjectFactoryUtils.ObjectsOfTypeIncludingAncestors(lof, typeof(ITestObject), true, false); + Assert.IsTrue(objects.Count == 0); + } + + [Test] + public void ObjectsOfTypeIncludingAncestorsWithStaticFactory() + { + StaticListableObjectFactory lof = new StaticListableObjectFactory(); + TestObject t1 = new TestObject(); + TestObject t2 = new TestObject(); + DummyFactory t3 = new DummyFactory(); + DummyFactory t4 = new DummyFactory(); + t4.IsSingleton = false; + lof.AddObject("t1", t1); + lof.AddObject("t2", t2); + lof.AddObject("t3", t3); + t3.AfterPropertiesSet(); // StaticListableObjectFactory does support lifecycle calls. + lof.AddObject("t4", t4); + t4.AfterPropertiesSet(); // StaticListableObjectFactory does support lifecycle calls. + IDictionary objects = ObjectFactoryUtils.ObjectsOfTypeIncludingAncestors(lof, typeof(ITestObject), true, false); + Assert.AreEqual(2, objects.Count); + Assert.AreEqual(t1, objects["t1"]); + Assert.AreEqual(t2, objects["t2"]); + objects = ObjectFactoryUtils.ObjectsOfTypeIncludingAncestors(lof, typeof(ITestObject), false, true); + Assert.AreEqual(3, objects.Count); + Assert.AreEqual(t1, objects["t1"]); + Assert.AreEqual(t2, objects["t2"]); + Assert.AreEqual(t3.GetObject(), objects["t3"]); + objects = ObjectFactoryUtils.ObjectsOfTypeIncludingAncestors(lof, typeof(ITestObject), true, true); + Assert.AreEqual(4, objects.Count); + Assert.AreEqual(t1, objects["t1"]); + Assert.AreEqual(t2, objects["t2"]); + Assert.AreEqual(t3.GetObject(), objects["t3"]); + Assert.IsTrue(objects["t4"] is TestObject); + } + + [Test] + public void IsFactoryDereferenceWithNonFactoryObjectName() + { + Assert.IsFalse(ObjectFactoryUtils.IsFactoryDereference("roob"), + "Name that didn't start with the factory object prefix is being reported " + + "(incorrectly) as a factory object dereference."); + } + + [Test] + public void IsFactoryDereferenceWithNullName() + { + Assert.IsFalse(ObjectFactoryUtils.IsFactoryDereference(null), + "Null name that (obviously) didn't start with the factory object prefix is being reported " + + "(incorrectly) as a factory object dereference."); + } + + [Test] + public void IsFactoryDereferenceWithEmptyName() + { + Assert.IsFalse(ObjectFactoryUtils.IsFactoryDereference(string.Empty), + "String.Empty name that (obviously) didn't start with the factory object prefix is being reported " + + "(incorrectly) as a factory object dereference."); + } + + [Test] + public void IsFactoryDereferenceWithJustTheFactoryObjectPrefixCharacter() + { + Assert.IsFalse(ObjectFactoryUtils.IsFactoryDereference( + ObjectFactoryUtils.FactoryObjectPrefix), + "Name that consisted solely of the factory object prefix is being reported " + + "(incorrectly) as a factory object dereference."); + } + + [Test] + public void IsFactoryDereferenceSunnyDay() + { + Assert.IsTrue(ObjectFactoryUtils.IsFactoryDereference( + ObjectFactoryUtils.FactoryObjectPrefix + "roob"), + "Name that did start with the factory object prefix is not being reported " + + "(incorrectly) as a factory object dereference."); + } +} diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/ObjectFactoryUtils_PreserveOrderInHierarchy_Tests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/ObjectFactoryUtils_PreserveOrderInHierarchy_Tests.cs index 04c8c1f7..6a5e94a4 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/ObjectFactoryUtils_PreserveOrderInHierarchy_Tests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/ObjectFactoryUtils_PreserveOrderInHierarchy_Tests.cs @@ -1,57 +1,56 @@ using NUnit.Framework; using Spring.Objects.Factory.Support; -namespace Spring.Objects.Factory +namespace Spring.Objects.Factory; + +[TestFixture] +public class ObjectFactoryUtils_PreserveOrderInHierarchy_Tests { - [TestFixture] - public class ObjectFactoryUtils_PreserveOrderInHierarchy_Tests + private readonly Type _expectedtype = typeof(ITestObject); + private DefaultListableObjectFactory _factory; + + [SetUp] + public void _TestSetUp() { - private readonly Type _expectedtype = typeof(ITestObject); - private DefaultListableObjectFactory _factory; + DefaultListableObjectFactory parentFactory = new DefaultListableObjectFactory(); + _factory = new DefaultListableObjectFactory(parentFactory); - [SetUp] - public void _TestSetUp() - { - DefaultListableObjectFactory parentFactory = new DefaultListableObjectFactory(); - _factory = new DefaultListableObjectFactory(parentFactory); + RootObjectDefinition rodA = new RootObjectDefinition(_expectedtype); + RootObjectDefinition rodB = new RootObjectDefinition(_expectedtype); + RootObjectDefinition rodC = new RootObjectDefinition(_expectedtype); + RootObjectDefinition rod2A = new RootObjectDefinition(_expectedtype); + RootObjectDefinition rod2C = new RootObjectDefinition(_expectedtype); - RootObjectDefinition rodA = new RootObjectDefinition(_expectedtype); - RootObjectDefinition rodB = new RootObjectDefinition(_expectedtype); - RootObjectDefinition rodC = new RootObjectDefinition(_expectedtype); - RootObjectDefinition rod2A = new RootObjectDefinition(_expectedtype); - RootObjectDefinition rod2C = new RootObjectDefinition(_expectedtype); + _factory.RegisterObjectDefinition("objA", rodA); + _factory.RegisterObjectDefinition("objB", rodB); + _factory.RegisterObjectDefinition("objC", rodC); - _factory.RegisterObjectDefinition("objA", rodA); - _factory.RegisterObjectDefinition("objB", rodB); - _factory.RegisterObjectDefinition("objC", rodC); + parentFactory.RegisterObjectDefinition("obj2A", rod2A); + parentFactory.RegisterObjectDefinition("objB", rodB); + parentFactory.RegisterObjectDefinition("obj2C", rod2C); + } - parentFactory.RegisterObjectDefinition("obj2A", rod2A); - parentFactory.RegisterObjectDefinition("objB", rodB); - parentFactory.RegisterObjectDefinition("obj2C", rod2C); - } + [Test] + public void ObjectNamesIncludingAncestorsPreserveOrderOfRegistration() + { + var names = ObjectFactoryUtils.ObjectNamesIncludingAncestors(_factory); + Assert.AreEqual(5, names.Count); + Assert.AreEqual(new string[] { "objA", "objB", "objC", "obj2A", "obj2C" }, names); + } - [Test] - public void ObjectNamesIncludingAncestorsPreserveOrderOfRegistration() - { - var names = ObjectFactoryUtils.ObjectNamesIncludingAncestors(_factory); - Assert.AreEqual(5, names.Count); - Assert.AreEqual(new string[] { "objA", "objB", "objC", "obj2A", "obj2C" }, names); - } + [Test] + public void ObjectNamesForTypeIncludingAncestorsPreserveOrderOfRegistration() + { + var names = ObjectFactoryUtils.ObjectNamesForTypeIncludingAncestors(_factory, _expectedtype); + Assert.AreEqual(5, names.Count); + Assert.AreEqual(new string[] { "objA", "objB", "objC", "obj2A", "obj2C" }, names); + } - [Test] - public void ObjectNamesForTypeIncludingAncestorsPreserveOrderOfRegistration() - { - var names = ObjectFactoryUtils.ObjectNamesForTypeIncludingAncestors(_factory, _expectedtype); - Assert.AreEqual(5, names.Count); - Assert.AreEqual(new string[] { "objA", "objB", "objC", "obj2A", "obj2C" }, names); - } - - [Test] - public void ObjectNamesForTypeIncludingAncestorsPrototypesAndFactoryObjectsPreserveOrderOfRegistration() - { - var names = ObjectFactoryUtils.ObjectNamesForTypeIncludingAncestors(_factory, _expectedtype, false, false); - Assert.AreEqual(5, names.Count); - Assert.AreEqual(new string[] { "objA", "objB", "objC", "obj2A", "obj2C" }, names); - } + [Test] + public void ObjectNamesForTypeIncludingAncestorsPrototypesAndFactoryObjectsPreserveOrderOfRegistration() + { + var names = ObjectFactoryUtils.ObjectNamesForTypeIncludingAncestors(_factory, _expectedtype, false, false); + Assert.AreEqual(5, names.Count); + Assert.AreEqual(new string[] { "objA", "objB", "objC", "obj2A", "obj2C" }, names); } } diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/SideEffectObject.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/SideEffectObject.cs index a355aa9e..e706e4a1 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/SideEffectObject.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/SideEffectObject.cs @@ -1,48 +1,49 @@ #region License + /* * Copyright 2002-2010 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 -namespace Spring.Objects.Factory +namespace Spring.Objects.Factory; + +/// +/// Object that changes state on a business invocation, so that +/// we can check whether it's been invoked. +/// +/// Rod Johnson +/// Simon White (.NET) +public class SideEffectObject : ISideEffectObject { - /// - /// Object that changes state on a business invocation, so that - /// we can check whether it's been invoked. - /// - /// Rod Johnson - /// Simon White (.NET) - public class SideEffectObject : ISideEffectObject - { - private int _count; + private int _count; - public int Count - { - get - { - return _count; - } - set - { - this._count = value; - } - } + public int Count + { + get + { + return _count; + } + set + { + this._count = value; + } + } - public void doWork() - { - _count++; - } - } + public void doWork() + { + _count++; + } } diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Support/AutowireUtilsTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Support/AutowireUtilsTests.cs index 5cb8c5e5..90351619 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Support/AutowireUtilsTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Support/AutowireUtilsTests.cs @@ -26,266 +26,252 @@ using Spring.Util; #endregion -namespace Spring.Objects.Factory.Support +namespace Spring.Objects.Factory.Support; + +/// +/// Unit tests for the AutowireUtilsTests class. +/// +/// Rick Evans +[TestFixture] +public sealed class AutowireUtilsTests { - /// - /// Unit tests for the AutowireUtilsTests class. - /// - /// Rick Evans - [TestFixture] - public sealed class AutowireUtilsTests - { - #region GetTypeDifferenceWeight Tests + #region GetTypeDifferenceWeight Tests - [Test] - public void GetTypeDifferenceWeightForZeroArgCtor() - { - int expectedWeight = 0; - int actualWeight = AutowireUtils.GetTypeDifferenceWeight( - ReflectionUtils.GetParameterTypes(typeof(Fable).GetConstructor(Type.EmptyTypes).GetParameters()), new object[] { }); - Assert.AreEqual(expectedWeight, actualWeight, "AutowireUtils.GetTypeDifferenceWeight() was wrong, evidently."); - } + [Test] + public void GetTypeDifferenceWeightForZeroArgCtor() + { + int expectedWeight = 0; + int actualWeight = AutowireUtils.GetTypeDifferenceWeight( + ReflectionUtils.GetParameterTypes(typeof(Fable).GetConstructor(Type.EmptyTypes).GetParameters()), new object[] { }); + Assert.AreEqual(expectedWeight, actualWeight, "AutowireUtils.GetTypeDifferenceWeight() was wrong, evidently."); + } - [Test] - public void GetTypeDifferenceWeightWhenPassingDerivedTypeArgsToBaseTypeCtor() - { - int expectedWeight = 2; - int actualWeight = AutowireUtils.GetTypeDifferenceWeight( - ReflectionUtils.GetParameterTypes(typeof(Fable).GetConstructor( - new Type[] {typeof (NurseryRhymeCharacter)}).GetParameters()), - new object[] {new EnglishCharacter()}); - Assert.AreEqual(expectedWeight, actualWeight, "AutowireUtils.GetTypeDifferenceWeight() was wrong, evidently."); - } + [Test] + public void GetTypeDifferenceWeightWhenPassingDerivedTypeArgsToBaseTypeCtor() + { + int expectedWeight = 2; + int actualWeight = AutowireUtils.GetTypeDifferenceWeight( + ReflectionUtils.GetParameterTypes(typeof(Fable).GetConstructor( + new Type[] { typeof(NurseryRhymeCharacter) }).GetParameters()), + new object[] { new EnglishCharacter() }); + Assert.AreEqual(expectedWeight, actualWeight, "AutowireUtils.GetTypeDifferenceWeight() was wrong, evidently."); + } - [Test] - public void GetTypeDifferenceWeightWhenPassingExactTypeMatch() - { - int expectedWeight = 0; - int actualWeight = AutowireUtils.GetTypeDifferenceWeight( - ReflectionUtils.GetParameterTypes(typeof(Fable).GetConstructor( - new Type[] {typeof (EnglishCharacter)}).GetParameters()), - new object[] {new EnglishCharacter()}); - Assert.AreEqual(expectedWeight, actualWeight, "AutowireUtils.GetTypeDifferenceWeight() was wrong, evidently."); - } + [Test] + public void GetTypeDifferenceWeightWhenPassingExactTypeMatch() + { + int expectedWeight = 0; + int actualWeight = AutowireUtils.GetTypeDifferenceWeight( + ReflectionUtils.GetParameterTypes(typeof(Fable).GetConstructor( + new Type[] { typeof(EnglishCharacter) }).GetParameters()), + new object[] { new EnglishCharacter() }); + Assert.AreEqual(expectedWeight, actualWeight, "AutowireUtils.GetTypeDifferenceWeight() was wrong, evidently."); + } - /// - /// We want to use the ctor with the most specific argument type... so in the case of the test - /// classes used in this test, when we create a new instance of the Fable class using a - /// PeterPumpkinEater instance, we want the Fable(PeterPumpkinEater) ctor to be picked in - /// preference to any of the (still valid) ctors that accept Types that the PeterPumpkinEater - /// class inherits from. - /// - [Test] - public void UsingTypeDifferenceWeightPicksMostSpecificCtor() - { - object[] arguments = new object[] {new EnglishCharacter()}; - ConstructorInfo expectedCtor - = typeof (Fable).GetConstructor(new Type[] {typeof (EnglishCharacter)}); - ConstructorInfo pickedCtor = AssertTypeWeightingPicksCorrectCtor(arguments, typeof (Fable)); - Assert.IsNotNull(pickedCtor); - Assert.AreEqual(expectedCtor, pickedCtor); - } + /// + /// We want to use the ctor with the most specific argument type... so in the case of the test + /// classes used in this test, when we create a new instance of the Fable class using a + /// PeterPumpkinEater instance, we want the Fable(PeterPumpkinEater) ctor to be picked in + /// preference to any of the (still valid) ctors that accept Types that the PeterPumpkinEater + /// class inherits from. + /// + [Test] + public void UsingTypeDifferenceWeightPicksMostSpecificCtor() + { + object[] arguments = new object[] { new EnglishCharacter() }; + ConstructorInfo expectedCtor + = typeof(Fable).GetConstructor(new Type[] { typeof(EnglishCharacter) }); + ConstructorInfo pickedCtor = AssertTypeWeightingPicksCorrectCtor(arguments, typeof(Fable)); + Assert.IsNotNull(pickedCtor); + Assert.AreEqual(expectedCtor, pickedCtor); + } - [Test] - public void UsingTypeDifferenceWeightPicksNothingWhenGivenAnIncompatibleArgument() - { - object[] arguments = new object[] {"This argument is incompatible with any of the Fable ctors."}; - ConstructorInfo pickedCtor = AssertTypeWeightingPicksCorrectCtor(arguments, typeof (Fable)); - Assert.IsNull(pickedCtor); - } + [Test] + public void UsingTypeDifferenceWeightPicksNothingWhenGivenAnIncompatibleArgument() + { + object[] arguments = new object[] { "This argument is incompatible with any of the Fable ctors." }; + ConstructorInfo pickedCtor = AssertTypeWeightingPicksCorrectCtor(arguments, typeof(Fable)); + Assert.IsNull(pickedCtor); + } - [Test] - public void UsingTypeDifferenceWeightPicksMostGenericCtorWhenGivenA_NULL_Argument() - { - // using null means that we can match anything that takes an object as an argument... - object[] arguments = new object[] {null}; - // we'll want to pick the 'least' specific (most generic) ctor that we can find... - ConstructorInfo expectedCtor - = typeof (Fable).GetConstructor(new Type[] {typeof (FableCharacter)}); - ConstructorInfo pickedCtor = AssertTypeWeightingPicksCorrectCtor(arguments, typeof (Fable)); - Assert.IsNotNull(pickedCtor); - Assert.AreEqual(expectedCtor, pickedCtor); - } + [Test] + public void UsingTypeDifferenceWeightPicksMostGenericCtorWhenGivenA_NULL_Argument() + { + // using null means that we can match anything that takes an object as an argument... + object[] arguments = new object[] { null }; + // we'll want to pick the 'least' specific (most generic) ctor that we can find... + ConstructorInfo expectedCtor + = typeof(Fable).GetConstructor(new Type[] { typeof(FableCharacter) }); + ConstructorInfo pickedCtor = AssertTypeWeightingPicksCorrectCtor(arguments, typeof(Fable)); + Assert.IsNotNull(pickedCtor); + Assert.AreEqual(expectedCtor, pickedCtor); + } - private static ConstructorInfo AssertTypeWeightingPicksCorrectCtor(object[] arguments, Type ctorType) - { - ConstructorInfo pickedCtor = null; - // we want to pick the ctor that has the lowest type difference weight... - ConstructorInfo[] ctors = ctorType.GetConstructors(); - int weighting = Int32.MaxValue; - foreach (ConstructorInfo ctor in ctors) - { - ParameterInfo[] parameters = ctor.GetParameters(); - if (parameters.Length == arguments.Length) - { - Type[] paramTypes = ReflectionUtils.GetParameterTypes(parameters); - int weight = AutowireUtils.GetTypeDifferenceWeight(paramTypes, arguments); - if (weight < weighting) - { - pickedCtor = ctor; - weighting = weight; - } - } - } - return pickedCtor; - } + private static ConstructorInfo AssertTypeWeightingPicksCorrectCtor(object[] arguments, Type ctorType) + { + ConstructorInfo pickedCtor = null; + // we want to pick the ctor that has the lowest type difference weight... + ConstructorInfo[] ctors = ctorType.GetConstructors(); + int weighting = Int32.MaxValue; + foreach (ConstructorInfo ctor in ctors) + { + ParameterInfo[] parameters = ctor.GetParameters(); + if (parameters.Length == arguments.Length) + { + Type[] paramTypes = ReflectionUtils.GetParameterTypes(parameters); + int weight = AutowireUtils.GetTypeDifferenceWeight(paramTypes, arguments); + if (weight < weighting) + { + pickedCtor = ctor; + weighting = weight; + } + } + } - [Test] - [Ignore("Investigate details of new type weight algorithm")] - public void GetTypeDifferenceWeightWithMismatchedLengths() - { - Assert.Throws(() => AutowireUtils.GetTypeDifferenceWeight(new Type[] {}, new object[] {1}), "Cannot calculate the type difference weight for argument types and arguments with differing lengths."); - } + return pickedCtor; + } - [Test] - public void GetTypeDifferenceWeightWithNullParameterTypes() - { - Assert.Throws(() => AutowireUtils.GetTypeDifferenceWeight(null, new object[] {})); - } + [Test] + [Ignore("Investigate details of new type weight algorithm")] + public void GetTypeDifferenceWeightWithMismatchedLengths() + { + Assert.Throws(() => AutowireUtils.GetTypeDifferenceWeight(new Type[] { }, new object[] { 1 }), "Cannot calculate the type difference weight for argument types and arguments with differing lengths."); + } - [Test] - public void GetTypeDifferenceWeightWithNullArgumentTypes() - { - Assert.Throws(() => AutowireUtils.GetTypeDifferenceWeight(ReflectionUtils.GetParameterTypes(typeof(Fable).GetConstructor(new Type[] { typeof(FableCharacter) }).GetParameters()), null)); - } + [Test] + public void GetTypeDifferenceWeightWithNullParameterTypes() + { + Assert.Throws(() => AutowireUtils.GetTypeDifferenceWeight(null, new object[] { })); + } - [Test] - public void GetTypeDifferenceWeightWithAllNulls() - { - Assert.Throws(() => AutowireUtils.GetTypeDifferenceWeight(null, null)); - } + [Test] + public void GetTypeDifferenceWeightWithNullArgumentTypes() + { + Assert.Throws(() => AutowireUtils.GetTypeDifferenceWeight(ReflectionUtils.GetParameterTypes(typeof(Fable).GetConstructor(new Type[] { typeof(FableCharacter) }).GetParameters()), null)); + } - [Test] - public void GetTypeDifferenceWeightWithSameTypes() - { - int expectedWeight = 0; - int actualWeight = AutowireUtils.GetTypeDifferenceWeight( - ReflectionUtils.GetParameterTypes(typeof(Fool).GetConstructor(new Type[] { typeof(string) }).GetParameters()), - new object[] {"Noob"}); - Assert.AreEqual(expectedWeight, actualWeight, "AutowireUtils.GetTypeDifferenceWeight() was wrong, evidently."); - } + [Test] + public void GetTypeDifferenceWeightWithAllNulls() + { + Assert.Throws(() => AutowireUtils.GetTypeDifferenceWeight(null, null)); + } - #endregion + [Test] + public void GetTypeDifferenceWeightWithSameTypes() + { + int expectedWeight = 0; + int actualWeight = AutowireUtils.GetTypeDifferenceWeight( + ReflectionUtils.GetParameterTypes(typeof(Fool).GetConstructor(new Type[] { typeof(string) }).GetParameters()), + new object[] { "Noob" }); + Assert.AreEqual(expectedWeight, actualWeight, "AutowireUtils.GetTypeDifferenceWeight() was wrong, evidently."); + } - #region SortConstructors Tests + #endregion - [Test] - public void SortCtorsReallyIsGreedy() - { - BindingFlags flags = BindingFlags.Public | BindingFlags.Instance; - Type foolType = typeof (Fool); - ConstructorInfo[] ctors = foolType.GetConstructors(flags); - AutowireUtils.SortConstructors(ctors); - ConstructorInfo[] expected = new ConstructorInfo[] - { - foolType.GetConstructor(new Type[] {typeof (string), typeof (int), typeof (Double), typeof (Fool)}), - foolType.GetConstructor(new Type[] {typeof (string), typeof (int)}), - foolType.GetConstructor(new Type[] {typeof (string)}), - foolType.GetConstructor(Type.EmptyTypes), - }; - Assert.IsTrue(ArrayUtils.AreEqual(expected, ctors), "AutowireUtils.SortConstructors() did not put the greedy public ctors first."); - } + #region SortConstructors Tests - [Test] - public void SortCtorsReallyDoesFavourPublicOnes() - { - BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance; - Type foolType = typeof (Fool); - ConstructorInfo[] ctors = foolType.GetConstructors(flags); - AutowireUtils.SortConstructors(ctors); - ConstructorInfo[] expected = new ConstructorInfo[] - { - foolType.GetConstructor(new Type[] {typeof (string), typeof (int), typeof (Double), typeof (Fool)}), - foolType.GetConstructor(new Type[] {typeof (string), typeof (int)}), - foolType.GetConstructor(new Type[] {typeof (string)}), - foolType.GetConstructor(Type.EmptyTypes), - foolType.GetConstructor(flags, null, new Type[] {typeof (string), typeof (int), typeof (Double)}, null), - foolType.GetConstructor(flags, null, new Type[] {typeof (string), typeof (Fool)}, null), - }; - Assert.IsTrue(ArrayUtils.AreEqual(expected, ctors), "AutowireUtils.SortConstructors() did not put the greedy public ctors first."); - } + [Test] + public void SortCtorsReallyIsGreedy() + { + BindingFlags flags = BindingFlags.Public | BindingFlags.Instance; + Type foolType = typeof(Fool); + ConstructorInfo[] ctors = foolType.GetConstructors(flags); + AutowireUtils.SortConstructors(ctors); + ConstructorInfo[] expected = new ConstructorInfo[] { foolType.GetConstructor(new Type[] { typeof(string), typeof(int), typeof(Double), typeof(Fool) }), foolType.GetConstructor(new Type[] { typeof(string), typeof(int) }), foolType.GetConstructor(new Type[] { typeof(string) }), foolType.GetConstructor(Type.EmptyTypes), }; + Assert.IsTrue(ArrayUtils.AreEqual(expected, ctors), "AutowireUtils.SortConstructors() did not put the greedy public ctors first."); + } - [Test] - public void SortCtorsBailsSilentlyWhenGivenNull() - { - AutowireUtils.SortConstructors(null); - } + [Test] + public void SortCtorsReallyDoesFavourPublicOnes() + { + BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance; + Type foolType = typeof(Fool); + ConstructorInfo[] ctors = foolType.GetConstructors(flags); + AutowireUtils.SortConstructors(ctors); + ConstructorInfo[] expected = new ConstructorInfo[] { foolType.GetConstructor(new Type[] { typeof(string), typeof(int), typeof(Double), typeof(Fool) }), foolType.GetConstructor(new Type[] { typeof(string), typeof(int) }), foolType.GetConstructor(new Type[] { typeof(string) }), foolType.GetConstructor(Type.EmptyTypes), foolType.GetConstructor(flags, null, new Type[] { typeof(string), typeof(int), typeof(Double) }, null), foolType.GetConstructor(flags, null, new Type[] { typeof(string), typeof(Fool) }, null), }; + Assert.IsTrue(ArrayUtils.AreEqual(expected, ctors), "AutowireUtils.SortConstructors() did not put the greedy public ctors first."); + } - #endregion + [Test] + public void SortCtorsBailsSilentlyWhenGivenNull() + { + AutowireUtils.SortConstructors(null); + } - #region Inner Class used to test ctor sorting + #endregion - private class Fool - { - private string _name; - private int _age; - private Double _money; - private Fool _mate; + #region Inner Class used to test ctor sorting - public Fool() - { - } + private class Fool + { + private string _name; + private int _age; + private Double _money; + private Fool _mate; - public Fool(string name) : this(name, 0) - { - } + public Fool() + { + } - public Fool(string name, int age) : this(name, age, 10.9D) - { - } + public Fool(string name) : this(name, 0) + { + } - protected Fool(string name, int age, Double money) - { - _name = name; - _age = age; - _money = money; - } + public Fool(string name, int age) : this(name, age, 10.9D) + { + } - public Fool(string name, int age, Double money, Fool mate) : this(name, age, money) - { - _mate = mate; - } + protected Fool(string name, int age, Double money) + { + _name = name; + _age = age; + _money = money; + } - private Fool(string name, Fool mate) : this(name, 0, 10.9D, mate) - { - } - } + public Fool(string name, int age, Double money, Fool mate) : this(name, age, money) + { + _mate = mate; + } - #endregion + private Fool(string name, Fool mate) : this(name, 0, 10.9D, mate) + { + } + } - #region Inner Classes (deep inheritance chain) used to test type weighting + #endregion - private sealed class Fable - { - public Fable() - { - } + #region Inner Classes (deep inheritance chain) used to test type weighting - public Fable(FableCharacter character) - { - } + private sealed class Fable + { + public Fable() + { + } - public Fable(NurseryRhymeCharacter character) - { - } + public Fable(FableCharacter character) + { + } - public Fable(EnglishCharacter character) - { - } - } + public Fable(NurseryRhymeCharacter character) + { + } - private class FableCharacter - { - } + public Fable(EnglishCharacter character) + { + } + } - private class NurseryRhymeCharacter : FableCharacter - { - } + private class FableCharacter + { + } - private sealed class EnglishCharacter : NurseryRhymeCharacter - { - } + private class NurseryRhymeCharacter : FableCharacter + { + } - #endregion - } -} \ No newline at end of file + private sealed class EnglishCharacter : NurseryRhymeCharacter + { + } + + #endregion +} diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Support/ChildObjectDefinitionTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Support/ChildObjectDefinitionTests.cs index 428604b2..4421edc0 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Support/ChildObjectDefinitionTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Support/ChildObjectDefinitionTests.cs @@ -24,44 +24,43 @@ using NUnit.Framework; #endregion -namespace Spring.Objects.Factory.Support +namespace Spring.Objects.Factory.Support; + +/// +/// Unit tests for the ChildObjectDefinition class. +/// +/// Rick Evans +[TestFixture] +public sealed class ChildObjectDefinitionTests { - /// - /// Unit tests for the ChildObjectDefinition class. - /// - /// Rick Evans - [TestFixture] - public sealed class ChildObjectDefinitionTests + [Test] + public void ChokesIfParentNamePropertyIsNullAtValidationTime() { - [Test] - public void ChokesIfParentNamePropertyIsNullAtValidationTime() - { - Assert.Throws(() => new ChildObjectDefinition(null, null).Validate()); - } + Assert.Throws(() => new ChildObjectDefinition(null, null).Validate()); + } - [Test] - public void ChokesIfParentNamePropertyIsEmptyAtValidationTime() - { - Assert.Throws(() => new ChildObjectDefinition(String.Empty, null).Validate()); - } + [Test] + public void ChokesIfParentNamePropertyIsEmptyAtValidationTime() + { + Assert.Throws(() => new ChildObjectDefinition(String.Empty, null).Validate()); + } - [Test] - public void ChokesIfParentNamePropertyIsJustWhitespaceAtValidationTime() - { - Assert.Throws(() => new ChildObjectDefinition(" ", null).Validate()); - } + [Test] + public void ChokesIfParentNamePropertyIsJustWhitespaceAtValidationTime() + { + Assert.Throws(() => new ChildObjectDefinition(" ", null).Validate()); + } - [Test] - public void Ctor_ParentNameOnly() - { - const string expectedParentName = "foo"; - ChildObjectDefinition def = new ChildObjectDefinition(expectedParentName); - Assert.AreEqual(expectedParentName, def.ParentName, - "ParentName property not initialized correctly by ctor."); - Assert.IsNotNull(def.PropertyValues, - "PropertyValues must be init'd to a non-null collection if not explicitly supplied."); - Assert.AreEqual(0, def.PropertyValues.PropertyValues.Count, - "PropertyValues must be init'd to an empty collection if not explicitly supplied."); - } - } + [Test] + public void Ctor_ParentNameOnly() + { + const string expectedParentName = "foo"; + ChildObjectDefinition def = new ChildObjectDefinition(expectedParentName); + Assert.AreEqual(expectedParentName, def.ParentName, + "ParentName property not initialized correctly by ctor."); + Assert.IsNotNull(def.PropertyValues, + "PropertyValues must be init'd to a non-null collection if not explicitly supplied."); + Assert.AreEqual(0, def.PropertyValues.PropertyValues.Count, + "PropertyValues must be init'd to an empty collection if not explicitly supplied."); + } } diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Support/DefaultObjectDefinitionFactoryTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Support/DefaultObjectDefinitionFactoryTests.cs index dcc88d6c..8600c700 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Support/DefaultObjectDefinitionFactoryTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Support/DefaultObjectDefinitionFactoryTests.cs @@ -24,58 +24,57 @@ using NUnit.Framework; #endregion -namespace Spring.Objects.Factory.Support +namespace Spring.Objects.Factory.Support; + +/// +/// Unit tests for the DefaultObjectDefinitionFactory class. +/// +/// Rick Evans +[TestFixture] +public sealed class DefaultObjectDefinitionFactoryTests { - /// - /// Unit tests for the DefaultObjectDefinitionFactory class. - /// - /// Rick Evans - [TestFixture] - public sealed class DefaultObjectDefinitionFactoryTests - { - [Test] - public void CreateRootDefinition() - { - DefaultObjectDefinitionFactory factory = new DefaultObjectDefinitionFactory(); - IConfigurableObjectDefinition definition - = factory.CreateObjectDefinition( - typeof (TestObject).FullName, null, AppDomain.CurrentDomain); - Assert.IsNotNull(definition, "CreateObjectDefinition with no parent is returning null (it must never do so)."); - Assert.AreEqual(typeof (TestObject), definition.ObjectType); - Assert.AreEqual(0, definition.PropertyValues.PropertyValues.Count, - "Must not have any property values as none were passed in."); - Assert.AreEqual(0, definition.ConstructorArgumentValues.ArgumentCount, - "Must not have any ctor args as none were passed in."); - } + [Test] + public void CreateRootDefinition() + { + DefaultObjectDefinitionFactory factory = new DefaultObjectDefinitionFactory(); + IConfigurableObjectDefinition definition + = factory.CreateObjectDefinition( + typeof(TestObject).FullName, null, AppDomain.CurrentDomain); + Assert.IsNotNull(definition, "CreateObjectDefinition with no parent is returning null (it must never do so)."); + Assert.AreEqual(typeof(TestObject), definition.ObjectType); + Assert.AreEqual(0, definition.PropertyValues.PropertyValues.Count, + "Must not have any property values as none were passed in."); + Assert.AreEqual(0, definition.ConstructorArgumentValues.ArgumentCount, + "Must not have any ctor args as none were passed in."); + } - [Test] - public void CreateChildDefinition() - { - DefaultObjectDefinitionFactory factory = new DefaultObjectDefinitionFactory(); - IConfigurableObjectDefinition definition - = factory.CreateObjectDefinition( - typeof (TestObject).FullName, "Aimee Mann", AppDomain.CurrentDomain); - Assert.IsNotNull(definition, "CreateObjectDefinition with no parent is returning null (it must never do so)."); - Assert.AreEqual(typeof (TestObject), definition.ObjectType); - Assert.AreEqual(0, definition.PropertyValues.PropertyValues.Count, - "Must not have any property values as none were passed in."); - Assert.AreEqual(0, definition.ConstructorArgumentValues.ArgumentCount, - "Must not have any ctor args as none were passed in."); - } + [Test] + public void CreateChildDefinition() + { + DefaultObjectDefinitionFactory factory = new DefaultObjectDefinitionFactory(); + IConfigurableObjectDefinition definition + = factory.CreateObjectDefinition( + typeof(TestObject).FullName, "Aimee Mann", AppDomain.CurrentDomain); + Assert.IsNotNull(definition, "CreateObjectDefinition with no parent is returning null (it must never do so)."); + Assert.AreEqual(typeof(TestObject), definition.ObjectType); + Assert.AreEqual(0, definition.PropertyValues.PropertyValues.Count, + "Must not have any property values as none were passed in."); + Assert.AreEqual(0, definition.ConstructorArgumentValues.ArgumentCount, + "Must not have any ctor args as none were passed in."); + } - [Test] - public void DoesNotResolveTypeNameToFullTypeInstanceIfAppDomainIsNull() - { - DefaultObjectDefinitionFactory factory = new DefaultObjectDefinitionFactory(); - IConfigurableObjectDefinition definition - = factory.CreateObjectDefinition( - typeof (TestObject).FullName, null, null); - Assert.IsNotNull(definition, "CreateObjectDefinition with no parent is returning null (it must never do so)."); - Assert.AreEqual(typeof (TestObject).FullName, definition.ObjectTypeName); - Assert.AreEqual(0, definition.PropertyValues.PropertyValues.Count, - "Must not have any property values as none were passed in."); - Assert.AreEqual(0, definition.ConstructorArgumentValues.ArgumentCount, - "Must not have any ctor args as none were passed in."); - } - } -} \ No newline at end of file + [Test] + public void DoesNotResolveTypeNameToFullTypeInstanceIfAppDomainIsNull() + { + DefaultObjectDefinitionFactory factory = new DefaultObjectDefinitionFactory(); + IConfigurableObjectDefinition definition + = factory.CreateObjectDefinition( + typeof(TestObject).FullName, null, null); + Assert.IsNotNull(definition, "CreateObjectDefinition with no parent is returning null (it must never do so)."); + Assert.AreEqual(typeof(TestObject).FullName, definition.ObjectTypeName); + Assert.AreEqual(0, definition.PropertyValues.PropertyValues.Count, + "Must not have any property values as none were passed in."); + Assert.AreEqual(0, definition.ConstructorArgumentValues.ArgumentCount, + "Must not have any ctor args as none were passed in."); + } +} diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Support/DelegateInvokingFactoryObjectTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Support/DelegateInvokingFactoryObjectTests.cs index feeda910..bbb9c71c 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Support/DelegateInvokingFactoryObjectTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Support/DelegateInvokingFactoryObjectTests.cs @@ -2,77 +2,75 @@ using Spring.Context; using Spring.Context.Support; -namespace Spring.Objects.Factory.Support +namespace Spring.Objects.Factory.Support; + +[TestFixture] +public class DelegateInvokingFactoryObjectTests { - [TestFixture] - public class DelegateInvokingFactoryObjectTests + [SetUp] + public void _TestSetUp() { - [SetUp] - public void _TestSetUp() - { - var context = new GenericApplicationContext(); - ContextRegistry.Clear(); - ContextRegistry.RegisterContext(context); - } - - private void RegisterDelegatingFactoryWithContext(bool buildSingletonObjectsWhenInvoked) - { - var targetBuilder = new ThingThatBuildsTargets(); - var factory = new DelegateInvokingFactoryObject(targetBuilder.BuildTarget, buildSingletonObjectsWhenInvoked); - - Assume.That(ContextRegistry.GetContext(), Is.InstanceOf(), "test requires a registered context that implements IConfigurableApplicationContext!"); - - var ctx = (IConfigurableApplicationContext)ContextRegistry.GetContext(); - ctx.ObjectFactory.RegisterSingleton("target", factory); - } - - [Test] - public void CanReturnSingletonObjects() - { - RegisterDelegatingFactoryWithContext(true); - - var targetObject1 = ContextRegistry.GetContext().GetObject(); - var targetObject2 = ContextRegistry.GetContext().GetObject(); - - Assert.That(targetObject1, Is.SameAs(targetObject2)); - Assert.That(targetObject1.Counter, Is.EqualTo(targetObject2.Counter)); - } - - [Test] - public void CanReturnProtoypeObjects() - { - RegisterDelegatingFactoryWithContext(false); - - var targetObject1 = ContextRegistry.GetContext().GetObject(); - var targetObject2 = ContextRegistry.GetContext().GetObject(); - - Assert.That(targetObject1, Is.Not.SameAs(targetObject2)); - Assert.That(targetObject1.Counter, Is.Not.EqualTo(targetObject2.Counter)); - } - + var context = new GenericApplicationContext(); + ContextRegistry.Clear(); + ContextRegistry.RegisterContext(context); } - public class ThingThatBuildsTargets + private void RegisterDelegatingFactoryWithContext(bool buildSingletonObjectsWhenInvoked) { - //since the IFactoryObject impl that contains this is registered w context as singleton, - // this counter is effectively static (sort of! ) and will be incremented on each call to build the TARGET instance - private int _counter; + var targetBuilder = new ThingThatBuildsTargets(); + var factory = new DelegateInvokingFactoryObject(targetBuilder.BuildTarget, buildSingletonObjectsWhenInvoked); - public TargetToBuild BuildTarget() - { - //create and return a new TARGET instance with the incremented counter value to show its working - return new TargetToBuild(_counter++); - } + Assume.That(ContextRegistry.GetContext(), Is.InstanceOf(), "test requires a registered context that implements IConfigurableApplicationContext!"); + + var ctx = (IConfigurableApplicationContext) ContextRegistry.GetContext(); + ctx.ObjectFactory.RegisterSingleton("target", factory); } - //the type we're trying to tell the container we want to be in charge of creating - public class TargetToBuild + [Test] + public void CanReturnSingletonObjects() { - public TargetToBuild(int counter) - { - Counter = counter; - } + RegisterDelegatingFactoryWithContext(true); - public int Counter { get; private set; } + var targetObject1 = ContextRegistry.GetContext().GetObject(); + var targetObject2 = ContextRegistry.GetContext().GetObject(); + + Assert.That(targetObject1, Is.SameAs(targetObject2)); + Assert.That(targetObject1.Counter, Is.EqualTo(targetObject2.Counter)); } -} \ No newline at end of file + + [Test] + public void CanReturnProtoypeObjects() + { + RegisterDelegatingFactoryWithContext(false); + + var targetObject1 = ContextRegistry.GetContext().GetObject(); + var targetObject2 = ContextRegistry.GetContext().GetObject(); + + Assert.That(targetObject1, Is.Not.SameAs(targetObject2)); + Assert.That(targetObject1.Counter, Is.Not.EqualTo(targetObject2.Counter)); + } +} + +public class ThingThatBuildsTargets +{ + //since the IFactoryObject impl that contains this is registered w context as singleton, + // this counter is effectively static (sort of! ) and will be incremented on each call to build the TARGET instance + private int _counter; + + public TargetToBuild BuildTarget() + { + //create and return a new TARGET instance with the incremented counter value to show its working + return new TargetToBuild(_counter++); + } +} + +//the type we're trying to tell the container we want to be in charge of creating +public class TargetToBuild +{ + public TargetToBuild(int counter) + { + Counter = counter; + } + + public int Counter { get; private set; } +} diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Support/DelegatingMethodReplacerTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Support/DelegatingMethodReplacerTests.cs index 387791db..87a3bf66 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Support/DelegatingMethodReplacerTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Support/DelegatingMethodReplacerTests.cs @@ -19,60 +19,56 @@ #endregion using System.Reflection; - using FakeItEasy; - using NUnit.Framework; -namespace Spring.Objects.Factory.Support +namespace Spring.Objects.Factory.Support; + +/// +/// Unit tests for the DelegatingMethodReplacer class. +/// +/// Rick Evans +[TestFixture] +public sealed class DelegatingMethodReplacerTests { - /// - /// Unit tests for the DelegatingMethodReplacer class. - /// - /// Rick Evans - [TestFixture] - public sealed class DelegatingMethodReplacerTests - { - [SetUp] - public void SetUp() - { - } + [SetUp] + public void SetUp() + { + } - [Test] - public void InstantiationWithNullDefinition() - { - IObjectFactory factory = A.Fake(); - Assert.Throws(() => new DelegatingMethodReplacer(null, factory)); - } + [Test] + public void InstantiationWithNullDefinition() + { + IObjectFactory factory = A.Fake(); + Assert.Throws(() => new DelegatingMethodReplacer(null, factory)); + } - [Test] - public void InstantiationWithNullFactory() - { - IConfigurableObjectDefinition mock = A.Fake(); - Assert.Throws(() => new DelegatingMethodReplacer(mock, null)); - } + [Test] + public void InstantiationWithNullFactory() + { + IConfigurableObjectDefinition mock = A.Fake(); + Assert.Throws(() => new DelegatingMethodReplacer(mock, null)); + } - [Test] - public void SunnyDayPath() - { - IObjectFactory mockFactory = A.Fake(); - IConfigurableObjectDefinition mockDefinition = A.Fake(); - IMethodReplacer mockReplacer = A.Fake(); + [Test] + public void SunnyDayPath() + { + IObjectFactory mockFactory = A.Fake(); + IConfigurableObjectDefinition mockDefinition = A.Fake(); + IMethodReplacer mockReplacer = A.Fake(); + const string ReplacerObjectName = "replacer"; + A.CallTo(() => mockFactory.GetObject(ReplacerObjectName)).Returns(mockReplacer); - const string ReplacerObjectName = "replacer"; - A.CallTo(() => mockFactory.GetObject(ReplacerObjectName)).Returns(mockReplacer); + ReplacedMethodOverride ovr = new ReplacedMethodOverride("SunnyDayPath", ReplacerObjectName); + MethodOverrides overrides = new MethodOverrides(); + overrides.Add(ovr); + A.CallTo(() => mockDefinition.MethodOverrides).Returns(overrides); - ReplacedMethodOverride ovr = new ReplacedMethodOverride("SunnyDayPath", ReplacerObjectName); - MethodOverrides overrides = new MethodOverrides(); - overrides.Add(ovr); - A.CallTo(() => mockDefinition.MethodOverrides).Returns(overrides); + A.CallTo(() => mockReplacer.Implement(null, null, null)).WithAnyArguments().Returns(null); - A.CallTo(() => mockReplacer.Implement(null, null, null)).WithAnyArguments().Returns(null); - - DelegatingMethodReplacer replacer = new DelegatingMethodReplacer(mockDefinition, mockFactory); - MethodInfo method = (MethodInfo) MethodBase.GetCurrentMethod(); - replacer.Implement(this, method, new object[] {}); - } - } -} \ No newline at end of file + DelegatingMethodReplacer replacer = new DelegatingMethodReplacer(mockDefinition, mockFactory); + MethodInfo method = (MethodInfo) MethodBase.GetCurrentMethod(); + replacer.Implement(this, method, new object[] { }); + } +} diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Support/LookupMethodOverrideTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Support/LookupMethodOverrideTests.cs index c33c986e..9da5f711 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Support/LookupMethodOverrideTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Support/LookupMethodOverrideTests.cs @@ -24,85 +24,84 @@ using NUnit.Framework; #endregion -namespace Spring.Objects.Factory.Support +namespace Spring.Objects.Factory.Support; + +/// +/// Unit tests for the LookupMethodOverride class. +/// +/// Rick Evans +[TestFixture] +public sealed class LookupMethodOverrideTests { - /// - /// Unit tests for the LookupMethodOverride class. - /// - /// Rick Evans - [TestFixture] - public sealed class LookupMethodOverrideTests - { - [Test] - public void InstantiationWithNullMethodName() - { - Assert.Throws(() => new LookupMethodOverride(null, null)); - } + [Test] + public void InstantiationWithNullMethodName() + { + Assert.Throws(() => new LookupMethodOverride(null, null)); + } - [Test] - public void InstantiationWithEmptyMethodName() - { - Assert.Throws(() => new LookupMethodOverride(string.Empty, null)); - } + [Test] + public void InstantiationWithEmptyMethodName() + { + Assert.Throws(() => new LookupMethodOverride(string.Empty, null)); + } - [Test] - public void InstantiationWithWhitespacedMethodName() - { - Assert.Throws(() => new LookupMethodOverride(" ", null)); - } + [Test] + public void InstantiationWithWhitespacedMethodName() + { + Assert.Throws(() => new LookupMethodOverride(" ", null)); + } - [Test] - public void InstantiationWithNullMethodReplacerObjectName() - { - Assert.Throws(() => new LookupMethodOverride("foo", null)); - } + [Test] + public void InstantiationWithNullMethodReplacerObjectName() + { + Assert.Throws(() => new LookupMethodOverride("foo", null)); + } - [Test] - public void InstantiationWithEmptyMethodReplacerObjectName() - { - Assert.Throws(() => new LookupMethodOverride("foo", string.Empty)); - } + [Test] + public void InstantiationWithEmptyMethodReplacerObjectName() + { + Assert.Throws(() => new LookupMethodOverride("foo", string.Empty)); + } - [Test] - public void InstantiationWithWhitespacedMethodReplacerObjectName() - { - Assert.Throws(() => new LookupMethodOverride("foo", " ")); - } + [Test] + public void InstantiationWithWhitespacedMethodReplacerObjectName() + { + Assert.Throws(() => new LookupMethodOverride("foo", " ")); + } - [Test] - public void Matches_TotallyDifferentMethodName() - { - LookupMethodOverride methodOverride = new LookupMethodOverride("Bingo", "foo"); - Assert.IsFalse(methodOverride.Matches(typeof (Feeder).GetMethod("GetGrub"))); - } + [Test] + public void Matches_TotallyDifferentMethodName() + { + LookupMethodOverride methodOverride = new LookupMethodOverride("Bingo", "foo"); + Assert.IsFalse(methodOverride.Matches(typeof(Feeder).GetMethod("GetGrub"))); + } - [Test] - public void Matches_MatchingMethodName() - { - LookupMethodOverride methodOverride = new LookupMethodOverride("GetGrub", "foo"); - Assert.IsTrue(methodOverride.Matches(typeof (Feeder).GetMethod("GetGrub"))); - } + [Test] + public void Matches_MatchingMethodName() + { + LookupMethodOverride methodOverride = new LookupMethodOverride("GetGrub", "foo"); + Assert.IsTrue(methodOverride.Matches(typeof(Feeder).GetMethod("GetGrub"))); + } - [Test] - public void MatchesWithNullMethod() - { - LookupMethodOverride methodOverride = new LookupMethodOverride("Execute", "foo"); - Assert.Throws(() => methodOverride.Matches(null)); - } + [Test] + public void MatchesWithNullMethod() + { + LookupMethodOverride methodOverride = new LookupMethodOverride("Execute", "foo"); + Assert.Throws(() => methodOverride.Matches(null)); + } - [Test] - public void ToStringWorks() - { - LookupMethodOverride methodOverride = new LookupMethodOverride("GetGrub", "foo"); - Assert.AreEqual(typeof (LookupMethodOverride).Name + " for method 'GetGrub'; will return object 'foo'.", methodOverride.ToString()); - } + [Test] + public void ToStringWorks() + { + LookupMethodOverride methodOverride = new LookupMethodOverride("GetGrub", "foo"); + Assert.AreEqual(typeof(LookupMethodOverride).Name + " for method 'GetGrub'; will return object 'foo'.", methodOverride.ToString()); + } - private sealed class Feeder - { - public object GetGrub() - { - return null; - } - } - } -} \ No newline at end of file + private sealed class Feeder + { + public object GetGrub() + { + return null; + } + } +} diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Support/LookupMethodReplacerTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Support/LookupMethodReplacerTests.cs index 38e30209..62198cb6 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Support/LookupMethodReplacerTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Support/LookupMethodReplacerTests.cs @@ -19,60 +19,57 @@ #endregion using System.Reflection; - using FakeItEasy; - using NUnit.Framework; -namespace Spring.Objects.Factory.Support +namespace Spring.Objects.Factory.Support; + +/// +/// Unit tests for the LookupMethodReplacer class. +/// +/// Rick Evans +[TestFixture] +public sealed class LookupMethodReplacerTests { - /// - /// Unit tests for the LookupMethodReplacer class. - /// - /// Rick Evans - [TestFixture] - public sealed class LookupMethodReplacerTests - { - [SetUp] - public void Setup() - { - } + [SetUp] + public void Setup() + { + } - [Test] - public void InstantiationWithNullDefinition() - { - IObjectFactory objectFactory = A.Fake(); - Assert.Throws(() => new LookupMethodReplacer(null, objectFactory)); - } + [Test] + public void InstantiationWithNullDefinition() + { + IObjectFactory objectFactory = A.Fake(); + Assert.Throws(() => new LookupMethodReplacer(null, objectFactory)); + } - [Test] - public void InstantiationWithNullFactory() - { - var configurableObjectDefinition = A.Fake(); - Assert.Throws(() => new LookupMethodReplacer(configurableObjectDefinition, null)); - } + [Test] + public void InstantiationWithNullFactory() + { + var configurableObjectDefinition = A.Fake(); + Assert.Throws(() => new LookupMethodReplacer(configurableObjectDefinition, null)); + } - [Test] - public void SunnyDayPath() - { - var objectFactory = A.Fake(); - var configurableObjectDefinition = A.Fake(); + [Test] + public void SunnyDayPath() + { + var objectFactory = A.Fake(); + var configurableObjectDefinition = A.Fake(); - object expectedLookup = new object(); - const string LookupObjectName = "foo"; + object expectedLookup = new object(); + const string LookupObjectName = "foo"; - A.CallTo(() => objectFactory.GetObject(LookupObjectName)).Returns(expectedLookup); + A.CallTo(() => objectFactory.GetObject(LookupObjectName)).Returns(expectedLookup); - LookupMethodOverride ovr = new LookupMethodOverride("SunnyDayPath", LookupObjectName); - MethodOverrides overrides = new MethodOverrides(); - overrides.Add(ovr); - A.CallTo(() => configurableObjectDefinition.MethodOverrides).Returns(overrides); + LookupMethodOverride ovr = new LookupMethodOverride("SunnyDayPath", LookupObjectName); + MethodOverrides overrides = new MethodOverrides(); + overrides.Add(ovr); + A.CallTo(() => configurableObjectDefinition.MethodOverrides).Returns(overrides); - LookupMethodReplacer replacer = new LookupMethodReplacer(configurableObjectDefinition, objectFactory); - MethodInfo method = (MethodInfo) MethodBase.GetCurrentMethod(); + LookupMethodReplacer replacer = new LookupMethodReplacer(configurableObjectDefinition, objectFactory); + MethodInfo method = (MethodInfo) MethodBase.GetCurrentMethod(); - object lookup = replacer.Implement(this, method, new object[] {}); - Assert.AreSame(expectedLookup, lookup); - } - } -} \ No newline at end of file + object lookup = replacer.Implement(this, method, new object[] { }); + Assert.AreSame(expectedLookup, lookup); + } +} diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Support/ManagedDictionaryTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Support/ManagedDictionaryTests.cs index 52b9333a..a749eff4 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Support/ManagedDictionaryTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Support/ManagedDictionaryTests.cs @@ -20,152 +20,152 @@ using System.Collections; using NUnit.Framework; - using Spring.Objects.Factory.Config; -namespace Spring.Objects.Factory.Support +namespace Spring.Objects.Factory.Support; + +/// +/// Integration tests for ManagedDictionary +/// +/// Erich Eichinger +/// Mark Pollack +[TestFixture] +public class ManagedDictionaryTests { - /// - /// Integration tests for ManagedDictionary - /// - /// Erich Eichinger - /// Mark Pollack - [TestFixture] - public class ManagedDictionaryTests + [Test] + public void MergeSunnyDay() { - [Test] - public void MergeSunnyDay() - { - ManagedDictionary parent = new ManagedDictionary(); - parent.Add("one", "one"); - parent.Add("two", "two"); - ManagedDictionary child = new ManagedDictionary(); - child.Add("three", "three"); - child.MergeEnabled = true; - IDictionary mergedList = (IDictionary)child.Merge(parent); - Assert.AreEqual(3, mergedList.Count); - } + ManagedDictionary parent = new ManagedDictionary(); + parent.Add("one", "one"); + parent.Add("two", "two"); + ManagedDictionary child = new ManagedDictionary(); + child.Add("three", "three"); + child.MergeEnabled = true; + IDictionary mergedList = (IDictionary) child.Merge(parent); + Assert.AreEqual(3, mergedList.Count); + } - [Test] - public void MergeWithNullParent() - { - ManagedDictionary child = new ManagedDictionary(); - child.MergeEnabled = true; - Assert.AreSame(child, child.Merge(null)); - } + [Test] + public void MergeWithNullParent() + { + ManagedDictionary child = new ManagedDictionary(); + child.MergeEnabled = true; + Assert.AreSame(child, child.Merge(null)); + } - [Test] - public void MergeNotAllowedWhenMergeNotEnabled() - { - ManagedDictionary child = new ManagedDictionary(); - Assert.Throws(() => child.Merge(null), "Not allowed to merge when the 'MergeEnabled' property is set to 'false'"); - } + [Test] + public void MergeNotAllowedWhenMergeNotEnabled() + { + ManagedDictionary child = new ManagedDictionary(); + Assert.Throws(() => child.Merge(null), "Not allowed to merge when the 'MergeEnabled' property is set to 'false'"); + } - [Test] - public void MergeWithNonCompatibleParentType() - { - ManagedDictionary child = new ManagedDictionary(); - child.MergeEnabled = true; - Assert.Throws(() => child.Merge("hello")); - } + [Test] + public void MergeWithNonCompatibleParentType() + { + ManagedDictionary child = new ManagedDictionary(); + child.MergeEnabled = true; + Assert.Throws(() => child.Merge("hello")); + } - [Test] - public void MergeEmptyChild() - { - ManagedDictionary parent = new ManagedDictionary(); - parent.Add("one", "one"); - parent.Add("two", "two"); - ManagedDictionary child = new ManagedDictionary(); - child.MergeEnabled = true; - IDictionary mergedMap = (IDictionary)child.Merge(parent); - Assert.AreEqual(2, mergedMap.Count); - } + [Test] + public void MergeEmptyChild() + { + ManagedDictionary parent = new ManagedDictionary(); + parent.Add("one", "one"); + parent.Add("two", "two"); + ManagedDictionary child = new ManagedDictionary(); + child.MergeEnabled = true; + IDictionary mergedMap = (IDictionary) child.Merge(parent); + Assert.AreEqual(2, mergedMap.Count); + } - [Test] - public void MergeChildValueOverrideTheParents() - { - ManagedDictionary parent = new ManagedDictionary(); - parent.Add("one", "one"); - parent.Add("two", "two"); - ManagedDictionary child = new ManagedDictionary(); - child.Add("one", "fork"); - child.MergeEnabled = true; - IDictionary mergedMap = (IDictionary)child.Merge(parent); - Assert.AreEqual(2, mergedMap.Count); - Assert.AreEqual("fork", mergedMap["one"]); - } + [Test] + public void MergeChildValueOverrideTheParents() + { + ManagedDictionary parent = new ManagedDictionary(); + parent.Add("one", "one"); + parent.Add("two", "two"); + ManagedDictionary child = new ManagedDictionary(); + child.Add("one", "fork"); + child.MergeEnabled = true; + IDictionary mergedMap = (IDictionary) child.Merge(parent); + Assert.AreEqual(2, mergedMap.Count); + Assert.AreEqual("fork", mergedMap["one"]); + } - internal class InternalType - { - public string Value = "OK"; - } + internal class InternalType + { + public string Value = "OK"; + } - [Test] - public void ResolvesInternalGenericTypes() - { - ManagedDictionary dict2 = new ManagedDictionary(); - dict2.Add("1", "stringValue"); - dict2.KeyTypeName = "int"; - dict2.ValueTypeName = typeof(InternalType).FullName; + [Test] + public void ResolvesInternalGenericTypes() + { + ManagedDictionary dict2 = new ManagedDictionary(); + dict2.Add("1", "stringValue"); + dict2.KeyTypeName = "int"; + dict2.ValueTypeName = typeof(InternalType).FullName; - IDictionary resolved = (IDictionary) dict2.Resolve("other", new RootObjectDefinition(typeof (object)), "prop", - delegate(string name, IObjectDefinition definition, string argumentName, object element) - { - if ("stringValue".Equals(element)) - { - return new InternalType(); - } - return element; - } - ); - Assert.AreEqual( typeof(InternalType), resolved[1].GetType() ); - } + IDictionary resolved = (IDictionary) dict2.Resolve("other", new RootObjectDefinition(typeof(object)), "prop", + delegate(string name, IObjectDefinition definition, string argumentName, object element) + { + if ("stringValue".Equals(element)) + { + return new InternalType(); + } - [Test] - public void ResolvesGenericTypeNames() - { - ManagedDictionary dict = new ManagedDictionary(); - dict.Add("key", "value"); - dict.KeyTypeName = "string"; + return element; + } + ); + Assert.AreEqual(typeof(InternalType), resolved[1].GetType()); + } - dict.ValueTypeName = "System.Collections.Generic.List<[string]>"; - IDictionary resolved = (IDictionary) dict.Resolve("somename", new RootObjectDefinition(typeof(object)), "prop", - delegate(string name, IObjectDefinition definition, string argumentName, object element) - { - if ("value".Equals(element)) - { - return new List(); - } - return element; - } - ); - Assert.AreEqual(1, resolved.Count); - Assert.AreEqual(typeof(List), resolved["key"].GetType()); - } - - [Test] - public void ResolvesMergedGenericType() - { - ManagedDictionary parent = new ManagedDictionary(); - parent.Add("one", 1); - parent.Add("two", 2); - parent.KeyTypeName = "string"; - parent.ValueTypeName = "int"; - - ManagedDictionary child = new ManagedDictionary(); - child.MergeEnabled = true; - child.Add("one", -1); - child.Add("three", 3); - - ManagedDictionary merged = (ManagedDictionary) child.Merge(parent); + [Test] + public void ResolvesGenericTypeNames() + { + ManagedDictionary dict = new ManagedDictionary(); + dict.Add("key", "value"); + dict.KeyTypeName = "string"; - IDictionary resolved = (IDictionary) merged.Resolve("somename", new RootObjectDefinition(typeof(object)), "prop", - (name, definition, argumentName, element) => element); - - Assert.IsInstanceOf>(resolved); - Assert.AreEqual(3, resolved.Count); - Assert.AreEqual(typeof(int), resolved["two"].GetType()); - Assert.AreEqual(-1, resolved["one"]); - } + dict.ValueTypeName = "System.Collections.Generic.List<[string]>"; + IDictionary resolved = (IDictionary) dict.Resolve("somename", new RootObjectDefinition(typeof(object)), "prop", + delegate(string name, IObjectDefinition definition, string argumentName, object element) + { + if ("value".Equals(element)) + { + return new List(); + } + + return element; + } + ); + Assert.AreEqual(1, resolved.Count); + Assert.AreEqual(typeof(List), resolved["key"].GetType()); + } + + [Test] + public void ResolvesMergedGenericType() + { + ManagedDictionary parent = new ManagedDictionary(); + parent.Add("one", 1); + parent.Add("two", 2); + parent.KeyTypeName = "string"; + parent.ValueTypeName = "int"; + + ManagedDictionary child = new ManagedDictionary(); + child.MergeEnabled = true; + child.Add("one", -1); + child.Add("three", 3); + + ManagedDictionary merged = (ManagedDictionary) child.Merge(parent); + + IDictionary resolved = (IDictionary) merged.Resolve("somename", new RootObjectDefinition(typeof(object)), "prop", + (name, definition, argumentName, element) => element); + + Assert.IsInstanceOf>(resolved); + Assert.AreEqual(3, resolved.Count); + Assert.AreEqual(typeof(int), resolved["two"].GetType()); + Assert.AreEqual(-1, resolved["one"]); } } diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Support/ManagedListTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Support/ManagedListTests.cs index cee7c877..71a925f1 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Support/ManagedListTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Support/ManagedListTests.cs @@ -22,73 +22,72 @@ using System.Collections; using NUnit.Framework; using Spring.Objects.Factory.Config; -namespace Spring.Objects.Factory.Support +namespace Spring.Objects.Factory.Support; + +[TestFixture] +public class ManagedListTests { - [TestFixture] - public class ManagedListTests + [Test] + public void MergeSunnyDay() { - [Test] - public void MergeSunnyDay() - { - ManagedList parent = new ManagedList(); - parent.Add("one"); - parent.Add("two"); - ManagedList child = new ManagedList(); - child.Add("three"); - child.MergeEnabled = true; - IList mergedList = (IList) child.Merge(parent); - Assert.AreEqual(3, mergedList.Count); - } - - [Test] - public void MergeWithNullParent() - { - ManagedList child = new ManagedList(); - child.Add("one"); - child.MergeEnabled = true; - Assert.AreSame(child, child.Merge(null)); - } - - [Test] - public void MergeNotAllowedWhenMergeNotEnabled() - { - ManagedList child = new ManagedList(); - Assert.Throws(() => child.Merge(null), "Not allowed to merge when the 'MergeEnabled' property is set to 'false'"); - } - - [Test] - public void MergeWithNonCompatibleParentType() - { - ManagedList child = new ManagedList(); - child.Add("one"); - child.MergeEnabled = true; - Assert.Throws(() => child.Merge("hello")); - } - - [Test] - public void MergeEmptyChild() - { - ManagedList parent = new ManagedList(); - parent.Add("one"); - parent.Add("two"); - ManagedList child = new ManagedList(); - child.MergeEnabled = true; - IList mergedList = (IList) child.Merge(parent); - Assert.AreEqual(2, mergedList.Count); - } - - [Test] - public void MergeChildValueOverrideTheParents() - { - //doesn't make much sense in the context of a list... - ManagedList parent = new ManagedList(); - parent.Add("one"); - parent.Add("two"); - ManagedList child = new ManagedList(); - child.Add("one"); - child.MergeEnabled = true; - IList mergedList = (IList) child.Merge(parent); - Assert.AreEqual(3, mergedList.Count); - } + ManagedList parent = new ManagedList(); + parent.Add("one"); + parent.Add("two"); + ManagedList child = new ManagedList(); + child.Add("three"); + child.MergeEnabled = true; + IList mergedList = (IList) child.Merge(parent); + Assert.AreEqual(3, mergedList.Count); } -} \ No newline at end of file + + [Test] + public void MergeWithNullParent() + { + ManagedList child = new ManagedList(); + child.Add("one"); + child.MergeEnabled = true; + Assert.AreSame(child, child.Merge(null)); + } + + [Test] + public void MergeNotAllowedWhenMergeNotEnabled() + { + ManagedList child = new ManagedList(); + Assert.Throws(() => child.Merge(null), "Not allowed to merge when the 'MergeEnabled' property is set to 'false'"); + } + + [Test] + public void MergeWithNonCompatibleParentType() + { + ManagedList child = new ManagedList(); + child.Add("one"); + child.MergeEnabled = true; + Assert.Throws(() => child.Merge("hello")); + } + + [Test] + public void MergeEmptyChild() + { + ManagedList parent = new ManagedList(); + parent.Add("one"); + parent.Add("two"); + ManagedList child = new ManagedList(); + child.MergeEnabled = true; + IList mergedList = (IList) child.Merge(parent); + Assert.AreEqual(2, mergedList.Count); + } + + [Test] + public void MergeChildValueOverrideTheParents() + { + //doesn't make much sense in the context of a list... + ManagedList parent = new ManagedList(); + parent.Add("one"); + parent.Add("two"); + ManagedList child = new ManagedList(); + child.Add("one"); + child.MergeEnabled = true; + IList mergedList = (IList) child.Merge(parent); + Assert.AreEqual(3, mergedList.Count); + } +} diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Support/ManagedNameValueCollectionTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Support/ManagedNameValueCollectionTests.cs index 5dc7032f..222ea999 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Support/ManagedNameValueCollectionTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Support/ManagedNameValueCollectionTests.cs @@ -22,75 +22,74 @@ using System.Collections.Specialized; using NUnit.Framework; using Spring.Objects.Factory.Config; -namespace Spring.Objects.Factory.Support +namespace Spring.Objects.Factory.Support; + +/// +/// Integration tests for ManagedNameValueCollectionTests +/// +/// Mark Pollack +[TestFixture] +public class ManagedNameValueCollectionTests { - /// - /// Integration tests for ManagedNameValueCollectionTests - /// - /// Mark Pollack - [TestFixture] - public class ManagedNameValueCollectionTests + [Test] + public void MergeSunnyDay() { - [Test] - public void MergeSunnyDay() - { - ManagedNameValueCollection parent = new ManagedNameValueCollection(); - parent.Add("one", "one"); - parent.Add("two", "two"); - ManagedNameValueCollection child = new ManagedNameValueCollection(); - child.Add("three", "three"); - child.MergeEnabled = true; - NameValueCollection mergedList = (NameValueCollection)child.Merge(parent); - Assert.AreEqual(3, mergedList.Count); - } - - [Test] - public void MergeWithNullParent() - { - ManagedNameValueCollection child = new ManagedNameValueCollection(); - child.MergeEnabled = true; - Assert.AreSame(child, child.Merge(null)); - } - - [Test] - public void MergeNotAllowedWhenMergeNotEnabled() - { - ManagedNameValueCollection child = new ManagedNameValueCollection(); - Assert.Throws(() => child.Merge(null), "Not allowed to merge when the 'MergeEnabled' property is set to 'false'"); - } - - [Test] - public void MergeWithNonCompatibleParentType() - { - ManagedNameValueCollection child = new ManagedNameValueCollection(); - child.MergeEnabled = true; - Assert.Throws(() => child.Merge("hello")); - } - - [Test] - public void MergeEmptyChild() - { - ManagedNameValueCollection parent = new ManagedNameValueCollection(); - parent.Add("one", "one"); - parent.Add("two", "two"); - ManagedNameValueCollection child = new ManagedNameValueCollection(); - child.MergeEnabled = true; - NameValueCollection mergedMap = (NameValueCollection)child.Merge(parent); - Assert.AreEqual(2, mergedMap.Count); - } - - [Test] - public void MergeChildValueOverrideTheParents() - { - ManagedNameValueCollection parent = new ManagedNameValueCollection(); - parent.Add("one", "one"); - parent.Add("two", "two"); - ManagedNameValueCollection child = new ManagedNameValueCollection(); - child.Add("one", "fork"); - child.MergeEnabled = true; - NameValueCollection mergedMap = (NameValueCollection)child.Merge(parent); - Assert.AreEqual(2, mergedMap.Count); - Assert.AreEqual("fork", mergedMap["one"]); - } + ManagedNameValueCollection parent = new ManagedNameValueCollection(); + parent.Add("one", "one"); + parent.Add("two", "two"); + ManagedNameValueCollection child = new ManagedNameValueCollection(); + child.Add("three", "three"); + child.MergeEnabled = true; + NameValueCollection mergedList = (NameValueCollection) child.Merge(parent); + Assert.AreEqual(3, mergedList.Count); } -} \ No newline at end of file + + [Test] + public void MergeWithNullParent() + { + ManagedNameValueCollection child = new ManagedNameValueCollection(); + child.MergeEnabled = true; + Assert.AreSame(child, child.Merge(null)); + } + + [Test] + public void MergeNotAllowedWhenMergeNotEnabled() + { + ManagedNameValueCollection child = new ManagedNameValueCollection(); + Assert.Throws(() => child.Merge(null), "Not allowed to merge when the 'MergeEnabled' property is set to 'false'"); + } + + [Test] + public void MergeWithNonCompatibleParentType() + { + ManagedNameValueCollection child = new ManagedNameValueCollection(); + child.MergeEnabled = true; + Assert.Throws(() => child.Merge("hello")); + } + + [Test] + public void MergeEmptyChild() + { + ManagedNameValueCollection parent = new ManagedNameValueCollection(); + parent.Add("one", "one"); + parent.Add("two", "two"); + ManagedNameValueCollection child = new ManagedNameValueCollection(); + child.MergeEnabled = true; + NameValueCollection mergedMap = (NameValueCollection) child.Merge(parent); + Assert.AreEqual(2, mergedMap.Count); + } + + [Test] + public void MergeChildValueOverrideTheParents() + { + ManagedNameValueCollection parent = new ManagedNameValueCollection(); + parent.Add("one", "one"); + parent.Add("two", "two"); + ManagedNameValueCollection child = new ManagedNameValueCollection(); + child.Add("one", "fork"); + child.MergeEnabled = true; + NameValueCollection mergedMap = (NameValueCollection) child.Merge(parent); + Assert.AreEqual(2, mergedMap.Count); + Assert.AreEqual("fork", mergedMap["one"]); + } +} diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Support/ManagedSetTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Support/ManagedSetTests.cs index 8074b058..4f6b7674 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Support/ManagedSetTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Support/ManagedSetTests.cs @@ -22,72 +22,71 @@ using NUnit.Framework; using Spring.Collections; using Spring.Objects.Factory.Config; -namespace Spring.Objects.Factory.Support +namespace Spring.Objects.Factory.Support; + +[TestFixture] +public class ManagedSetTests { - [TestFixture] - public class ManagedSetTests + [Test] + public void MergeSunnyDay() { - [Test] - public void MergeSunnyDay() - { - ManagedSet parent = new ManagedSet(); - parent.Add("one"); - parent.Add("two"); - ManagedSet child = new ManagedSet(); - child.Add("three"); - child.MergeEnabled = true; - ISet mergedList = (ISet) child.Merge(parent); - Assert.AreEqual(3, mergedList.Count); - } - - [Test] - public void MergeWithNullParent() - { - ManagedSet child = new ManagedSet(); - child.Add("one"); - child.MergeEnabled = true; - Assert.AreSame(child, child.Merge(null)); - } - - [Test] - public void MergeNotAllowedWhenMergeNotEnabled() - { - ManagedSet child = new ManagedSet(); - Assert.Throws(() => child.Merge(null), "Not allowed to merge when the 'MergeEnabled' property is set to 'false'"); - } - - [Test] - public void MergeWithNonCompatibleParentType() - { - ManagedSet child = new ManagedSet(); - child.Add("one"); - child.MergeEnabled = true; - Assert.Throws(() => child.Merge("hello")); - } - - [Test] - public void MergeEmptyChild() - { - ManagedSet parent = new ManagedSet(); - parent.Add("one"); - parent.Add("two"); - ManagedSet child = new ManagedSet(); - child.MergeEnabled = true; - ISet mergedSet = (ISet) child.Merge(parent); - Assert.AreEqual(2, mergedSet.Count); - } - - [Test] - public void MergeChildValueOverrideTheParents() - { - ManagedSet parent = new ManagedSet(); - parent.Add("one"); - parent.Add("two"); - ManagedSet child = new ManagedSet(); - child.Add("one"); - child.MergeEnabled = true; - ISet mergedList = (ISet) child.Merge(parent); - Assert.AreEqual(2, mergedList.Count); - } + ManagedSet parent = new ManagedSet(); + parent.Add("one"); + parent.Add("two"); + ManagedSet child = new ManagedSet(); + child.Add("three"); + child.MergeEnabled = true; + ISet mergedList = (ISet) child.Merge(parent); + Assert.AreEqual(3, mergedList.Count); } -} \ No newline at end of file + + [Test] + public void MergeWithNullParent() + { + ManagedSet child = new ManagedSet(); + child.Add("one"); + child.MergeEnabled = true; + Assert.AreSame(child, child.Merge(null)); + } + + [Test] + public void MergeNotAllowedWhenMergeNotEnabled() + { + ManagedSet child = new ManagedSet(); + Assert.Throws(() => child.Merge(null), "Not allowed to merge when the 'MergeEnabled' property is set to 'false'"); + } + + [Test] + public void MergeWithNonCompatibleParentType() + { + ManagedSet child = new ManagedSet(); + child.Add("one"); + child.MergeEnabled = true; + Assert.Throws(() => child.Merge("hello")); + } + + [Test] + public void MergeEmptyChild() + { + ManagedSet parent = new ManagedSet(); + parent.Add("one"); + parent.Add("two"); + ManagedSet child = new ManagedSet(); + child.MergeEnabled = true; + ISet mergedSet = (ISet) child.Merge(parent); + Assert.AreEqual(2, mergedSet.Count); + } + + [Test] + public void MergeChildValueOverrideTheParents() + { + ManagedSet parent = new ManagedSet(); + parent.Add("one"); + parent.Add("two"); + ManagedSet child = new ManagedSet(); + child.Add("one"); + child.MergeEnabled = true; + ISet mergedList = (ISet) child.Merge(parent); + Assert.AreEqual(2, mergedList.Count); + } +} diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Support/ObjectDefinitionBuilderTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Support/ObjectDefinitionBuilderTests.cs index 4dae97e3..ef98424c 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Support/ObjectDefinitionBuilderTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Support/ObjectDefinitionBuilderTests.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -27,174 +27,161 @@ using Spring.Objects.Factory.Xml; #endregion -namespace Spring.Objects.Factory.Support +namespace Spring.Objects.Factory.Support; + +/// +/// This class contains tests for ObjectDefinitionBuilder +/// +/// Mark Pollack +[TestFixture] +public class ObjectDefinitionBuilderTests { - /// - /// This class contains tests for ObjectDefinitionBuilder - /// - /// Mark Pollack - [TestFixture] - public class ObjectDefinitionBuilderTests + private IObjectDefinitionFactory odf; + + [SetUp] + public void CreateObjectDefinitionBuilder() { - private IObjectDefinitionFactory odf; - - [SetUp] - public void CreateObjectDefinitionBuilder() - { - odf = new DefaultObjectDefinitionFactory(); - } - - - [Test] - public void ObjectName() - { - ObjectDefinitionBuilder odb = - ObjectDefinitionBuilder.RootObjectDefinition(odf, typeof(TestObject).FullName); - RootObjectDefinition rod = odb.ObjectDefinition as RootObjectDefinition; - Assert.IsNotNull(rod); - Assert.IsFalse(rod.HasObjectType); - Assert.AreEqual(typeof(TestObject).FullName, rod.ObjectTypeName); - } - - [Test] - public void ObjectNameWithFactoryMethod() - { - ObjectDefinitionBuilder odb = - ObjectDefinitionBuilder.RootObjectDefinition(odf, typeof(TestObject).FullName, "Create"); - RootObjectDefinition rod = odb.ObjectDefinition as RootObjectDefinition; - Assert.IsNotNull(rod); - Assert.IsFalse(rod.HasObjectType); - Assert.AreEqual(typeof(TestObject).FullName, rod.ObjectTypeName); - Assert.AreEqual("Create", rod.FactoryMethodName); - } - - [Test] - public void ObjectNameChild() - { - ObjectDefinitionBuilder odb = ObjectDefinitionBuilder.ChildObjectDefinition(odf, typeof(TestObject).FullName); - ChildObjectDefinition rod = odb.ObjectDefinition as ChildObjectDefinition; - Assert.IsNotNull(rod); - Assert.IsFalse(rod.HasObjectType); - Assert.AreEqual(typeof(TestObject).FullName, rod.ParentName); - } - - - [Test] - public void ObjectType() - { - ObjectDefinitionBuilder odb = ObjectDefinitionBuilder.RootObjectDefinition(odf, typeof (TestObject)); - RootObjectDefinition rod = odb.ObjectDefinition as RootObjectDefinition; - Assert.IsNotNull(rod); - Assert.IsTrue(rod.HasObjectType); - Assert.AreEqual(typeof (TestObject), rod.ObjectType); - } - - [Test] - public void ObjectTypeWithFactoryMethod() - { - ObjectDefinitionBuilder odb = - ObjectDefinitionBuilder.RootObjectDefinition(odf, typeof (TestObject), "Create"); - RootObjectDefinition rod = odb.ObjectDefinition as RootObjectDefinition; - Assert.IsNotNull(rod); - Assert.IsTrue(rod.HasObjectType); - Assert.AreEqual(typeof (TestObject), rod.ObjectType); - Assert.AreEqual("Create", rod.FactoryMethodName); - } - - [Test] - public void ObjectTypeWithSimpleProperty() - { - string[] dependsOn = new string[] {"A", "B", "C"}; - ObjectDefinitionBuilder odb = ObjectDefinitionBuilder.RootObjectDefinition(odf, typeof (TestObject)); - - odb.SetSingleton(false).AddPropertyReference("Age", "15"); - foreach (string dep in dependsOn) - { - odb.AddDependsOn(dep); - } - - RootObjectDefinition rod = odb.ObjectDefinition as RootObjectDefinition; - Assert.IsNotNull(rod); - Assert.IsFalse(rod.IsSingleton); - Assert.AreEqual(typeof (TestObject), rod.ObjectType); - Assert.AreEqual(dependsOn, rod.DependsOn, "DependsOn not as expected"); - Assert.IsTrue(rod.PropertyValues.Contains("Age")); - } - - [Test] - public void Simple() - { - GenericApplicationContext ctx = new GenericApplicationContext(); - IObjectDefinitionFactory objectDefinitionFactory = new DefaultObjectDefinitionFactory(); - - ObjectDefinitionBuilder builder = ObjectDefinitionBuilder.RootObjectDefinition(objectDefinitionFactory, - typeof (TestObject)); - - builder.AddPropertyValue("Age", 22) - .AddPropertyValue("Name", "Joe") - .AddPropertyReference("Spouse", "Spouse") - .SetSingleton(false); - - ctx.RegisterObjectDefinition("TestObject", builder.ObjectDefinition); - - builder = ObjectDefinitionBuilder.RootObjectDefinition(objectDefinitionFactory, typeof(TestObject)); - - IList friends = new ArrayList(); - friends.Add(new TestObject("Dan", 34)); - friends.Add(new TestObject("Mary", 33)); - builder.AddPropertyValue("Friends", friends) - .AddConstructorArg("Susan") - .AddConstructorArg(23) - .SetSingleton(false); - - ctx.RegisterObjectDefinition("Spouse", builder.ObjectDefinition); - - - - - TestObject to = ctx.GetObject("TestObject") as TestObject; - - Assert.IsNotNull(to); - - Assert.AreEqual("Joe", to.Name); - Assert.AreEqual(22, to.Age); - Assert.AreEqual(2,to.Spouse.Friends.Count); - Assert.AreEqual(23, to.Spouse.Age); - - /* - AbstractApplicationContext ctx = ContextRegistry.GetContext() as AbstractApplicationContext; - - - - //XmlObjectFactory objectFactory = ctx.ObjectFactory as XmlObjectFactory; - - IObjectFactory objectFactory = ctx.ObjectFactory; - - //DefaultListableObjectFactory - if (objectFactory != null) - { - Console.WriteLine("hi"); - } - //objectFactory.RegisterObjectDefinition("TestObject", builder.ObjectDefinition); - */ - - - - - } - - public void SimpleReader() - { - GenericApplicationContext applicationContext = new GenericApplicationContext(); - - - IObjectDefinitionReader objectDefinitionReader = new XmlObjectDefinitionReader(applicationContext); - - objectDefinitionReader.LoadObjectDefinitions("assembly://foo"); - - applicationContext.Refresh(); - - - } + odf = new DefaultObjectDefinitionFactory(); } -} \ No newline at end of file + + [Test] + public void ObjectName() + { + ObjectDefinitionBuilder odb = + ObjectDefinitionBuilder.RootObjectDefinition(odf, typeof(TestObject).FullName); + RootObjectDefinition rod = odb.ObjectDefinition as RootObjectDefinition; + Assert.IsNotNull(rod); + Assert.IsFalse(rod.HasObjectType); + Assert.AreEqual(typeof(TestObject).FullName, rod.ObjectTypeName); + } + + [Test] + public void ObjectNameWithFactoryMethod() + { + ObjectDefinitionBuilder odb = + ObjectDefinitionBuilder.RootObjectDefinition(odf, typeof(TestObject).FullName, "Create"); + RootObjectDefinition rod = odb.ObjectDefinition as RootObjectDefinition; + Assert.IsNotNull(rod); + Assert.IsFalse(rod.HasObjectType); + Assert.AreEqual(typeof(TestObject).FullName, rod.ObjectTypeName); + Assert.AreEqual("Create", rod.FactoryMethodName); + } + + [Test] + public void ObjectNameChild() + { + ObjectDefinitionBuilder odb = ObjectDefinitionBuilder.ChildObjectDefinition(odf, typeof(TestObject).FullName); + ChildObjectDefinition rod = odb.ObjectDefinition as ChildObjectDefinition; + Assert.IsNotNull(rod); + Assert.IsFalse(rod.HasObjectType); + Assert.AreEqual(typeof(TestObject).FullName, rod.ParentName); + } + + [Test] + public void ObjectType() + { + ObjectDefinitionBuilder odb = ObjectDefinitionBuilder.RootObjectDefinition(odf, typeof(TestObject)); + RootObjectDefinition rod = odb.ObjectDefinition as RootObjectDefinition; + Assert.IsNotNull(rod); + Assert.IsTrue(rod.HasObjectType); + Assert.AreEqual(typeof(TestObject), rod.ObjectType); + } + + [Test] + public void ObjectTypeWithFactoryMethod() + { + ObjectDefinitionBuilder odb = + ObjectDefinitionBuilder.RootObjectDefinition(odf, typeof(TestObject), "Create"); + RootObjectDefinition rod = odb.ObjectDefinition as RootObjectDefinition; + Assert.IsNotNull(rod); + Assert.IsTrue(rod.HasObjectType); + Assert.AreEqual(typeof(TestObject), rod.ObjectType); + Assert.AreEqual("Create", rod.FactoryMethodName); + } + + [Test] + public void ObjectTypeWithSimpleProperty() + { + string[] dependsOn = new string[] { "A", "B", "C" }; + ObjectDefinitionBuilder odb = ObjectDefinitionBuilder.RootObjectDefinition(odf, typeof(TestObject)); + + odb.SetSingleton(false).AddPropertyReference("Age", "15"); + foreach (string dep in dependsOn) + { + odb.AddDependsOn(dep); + } + + RootObjectDefinition rod = odb.ObjectDefinition as RootObjectDefinition; + Assert.IsNotNull(rod); + Assert.IsFalse(rod.IsSingleton); + Assert.AreEqual(typeof(TestObject), rod.ObjectType); + Assert.AreEqual(dependsOn, rod.DependsOn, "DependsOn not as expected"); + Assert.IsTrue(rod.PropertyValues.Contains("Age")); + } + + [Test] + public void Simple() + { + GenericApplicationContext ctx = new GenericApplicationContext(); + IObjectDefinitionFactory objectDefinitionFactory = new DefaultObjectDefinitionFactory(); + + ObjectDefinitionBuilder builder = ObjectDefinitionBuilder.RootObjectDefinition(objectDefinitionFactory, + typeof(TestObject)); + + builder.AddPropertyValue("Age", 22) + .AddPropertyValue("Name", "Joe") + .AddPropertyReference("Spouse", "Spouse") + .SetSingleton(false); + + ctx.RegisterObjectDefinition("TestObject", builder.ObjectDefinition); + + builder = ObjectDefinitionBuilder.RootObjectDefinition(objectDefinitionFactory, typeof(TestObject)); + + IList friends = new ArrayList(); + friends.Add(new TestObject("Dan", 34)); + friends.Add(new TestObject("Mary", 33)); + builder.AddPropertyValue("Friends", friends) + .AddConstructorArg("Susan") + .AddConstructorArg(23) + .SetSingleton(false); + + ctx.RegisterObjectDefinition("Spouse", builder.ObjectDefinition); + + TestObject to = ctx.GetObject("TestObject") as TestObject; + + Assert.IsNotNull(to); + + Assert.AreEqual("Joe", to.Name); + Assert.AreEqual(22, to.Age); + Assert.AreEqual(2, to.Spouse.Friends.Count); + Assert.AreEqual(23, to.Spouse.Age); + + /* + AbstractApplicationContext ctx = ContextRegistry.GetContext() as AbstractApplicationContext; + + + + //XmlObjectFactory objectFactory = ctx.ObjectFactory as XmlObjectFactory; + + IObjectFactory objectFactory = ctx.ObjectFactory; + + //DefaultListableObjectFactory + if (objectFactory != null) + { + Console.WriteLine("hi"); + } + //objectFactory.RegisterObjectDefinition("TestObject", builder.ObjectDefinition); + */ + } + + public void SimpleReader() + { + GenericApplicationContext applicationContext = new GenericApplicationContext(); + + IObjectDefinitionReader objectDefinitionReader = new XmlObjectDefinitionReader(applicationContext); + + objectDefinitionReader.LoadObjectDefinitions("assembly://foo"); + + applicationContext.Refresh(); + } +} diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Support/ObjectDefinitionReaderUtilsTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Support/ObjectDefinitionReaderUtilsTests.cs index b77871f3..2c6dadd6 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Support/ObjectDefinitionReaderUtilsTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Support/ObjectDefinitionReaderUtilsTests.cs @@ -19,94 +19,92 @@ #endregion using FakeItEasy; - using NUnit.Framework; using Spring.Objects.Factory.Config; -namespace Spring.Objects.Factory.Support +namespace Spring.Objects.Factory.Support; + +/// +/// Unit tests for the ObjectDefinitionReaderUtils class. +/// +/// Rick Evans +[TestFixture] +public sealed class ObjectDefinitionReaderUtilsTests { - /// - /// Unit tests for the ObjectDefinitionReaderUtils class. - /// - /// Rick Evans - [TestFixture] - public sealed class ObjectDefinitionReaderUtilsTests + private IObjectDefinitionRegistry registry; + private IObjectDefinition definition; + + [SetUp] + public void SetUp() { - private IObjectDefinitionRegistry registry; - private IObjectDefinition definition; - - [SetUp] - public void SetUp() - { - registry = A.Fake(); - definition = A.Fake(); - } - - [Test] - public void RegisterObjectDefinitionSunnyDay() - { - ObjectDefinitionHolder holder = new ObjectDefinitionHolder(definition, "foo"); - - ObjectDefinitionReaderUtils.RegisterObjectDefinition(holder, registry); - - A.CallTo(() => registry.RegisterObjectDefinition(null, null)).WithAnyArguments().MustHaveHappened(); - } - - [Test] - public void RegisterObjectDefinitionSunnyDayWithAliases() - { - ObjectDefinitionHolder holder = new ObjectDefinitionHolder(definition, "foo", new string[] {"bar", "baz"}); - - ObjectDefinitionReaderUtils.RegisterObjectDefinition(holder, registry); - - A.CallTo(() => registry.RegisterObjectDefinition("foo", definition)).MustHaveHappened(); - A.CallTo(() => registry.RegisterAlias("foo", "bar")).MustHaveHappened(); - A.CallTo(() => registry.RegisterAlias("foo", "baz")).MustHaveHappened(); - } - - [Test] - public void RegisterObjectDefinitionWithNullDefinition() - { - Assert.Throws(() => ObjectDefinitionReaderUtils.RegisterObjectDefinition(null, registry)); - } - - [Test] - public void RegisterObjectDefinitionWithNullRegistry() - { - ObjectDefinitionHolder holder = new ObjectDefinitionHolder(definition, "foo"); - Assert.Throws(() => ObjectDefinitionReaderUtils.RegisterObjectDefinition(holder, null)); - } - - [Test] - public void RegisterObjectDefinitionWithAllArgumentsNull() - { - Assert.Throws(() => ObjectDefinitionReaderUtils.RegisterObjectDefinition(null, null)); - } - - [Test] - public void RegisterObjectDefinitionWithDuplicateAlias() - { - registry.RegisterObjectDefinition("foo", definition); - - // we assume that some other object defition has already been associated with this alias... - A.CallTo(() => registry.RegisterAlias(null, null)).WithAnyArguments().Throws(); - - ObjectDefinitionHolder holder - = new ObjectDefinitionHolder(definition, "foo", new string[] {"bing"}); - - Assert.Throws(() => ObjectDefinitionReaderUtils.RegisterObjectDefinition(holder, registry)); - } - - [Test] - public void GenerateObjectNameWithNullDefinition() - { - Assert.Throws(() => ObjectDefinitionReaderUtils.GenerateObjectName(null, registry)); - } - - [Test] - public void GenerateObjectNameWithNullRegistry() - { - Assert.Throws(() => ObjectDefinitionReaderUtils.GenerateObjectName(A.Fake(), null)); - } + registry = A.Fake(); + definition = A.Fake(); } -} \ No newline at end of file + + [Test] + public void RegisterObjectDefinitionSunnyDay() + { + ObjectDefinitionHolder holder = new ObjectDefinitionHolder(definition, "foo"); + + ObjectDefinitionReaderUtils.RegisterObjectDefinition(holder, registry); + + A.CallTo(() => registry.RegisterObjectDefinition(null, null)).WithAnyArguments().MustHaveHappened(); + } + + [Test] + public void RegisterObjectDefinitionSunnyDayWithAliases() + { + ObjectDefinitionHolder holder = new ObjectDefinitionHolder(definition, "foo", new string[] { "bar", "baz" }); + + ObjectDefinitionReaderUtils.RegisterObjectDefinition(holder, registry); + + A.CallTo(() => registry.RegisterObjectDefinition("foo", definition)).MustHaveHappened(); + A.CallTo(() => registry.RegisterAlias("foo", "bar")).MustHaveHappened(); + A.CallTo(() => registry.RegisterAlias("foo", "baz")).MustHaveHappened(); + } + + [Test] + public void RegisterObjectDefinitionWithNullDefinition() + { + Assert.Throws(() => ObjectDefinitionReaderUtils.RegisterObjectDefinition(null, registry)); + } + + [Test] + public void RegisterObjectDefinitionWithNullRegistry() + { + ObjectDefinitionHolder holder = new ObjectDefinitionHolder(definition, "foo"); + Assert.Throws(() => ObjectDefinitionReaderUtils.RegisterObjectDefinition(holder, null)); + } + + [Test] + public void RegisterObjectDefinitionWithAllArgumentsNull() + { + Assert.Throws(() => ObjectDefinitionReaderUtils.RegisterObjectDefinition(null, null)); + } + + [Test] + public void RegisterObjectDefinitionWithDuplicateAlias() + { + registry.RegisterObjectDefinition("foo", definition); + + // we assume that some other object defition has already been associated with this alias... + A.CallTo(() => registry.RegisterAlias(null, null)).WithAnyArguments().Throws(); + + ObjectDefinitionHolder holder + = new ObjectDefinitionHolder(definition, "foo", new string[] { "bing" }); + + Assert.Throws(() => ObjectDefinitionReaderUtils.RegisterObjectDefinition(holder, registry)); + } + + [Test] + public void GenerateObjectNameWithNullDefinition() + { + Assert.Throws(() => ObjectDefinitionReaderUtils.GenerateObjectName(null, registry)); + } + + [Test] + public void GenerateObjectNameWithNullRegistry() + { + Assert.Throws(() => ObjectDefinitionReaderUtils.GenerateObjectName(A.Fake(), null)); + } +} diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Support/ReplacedMethodOverrideTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Support/ReplacedMethodOverrideTests.cs index 1aa7a7dc..1cd5ba43 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Support/ReplacedMethodOverrideTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Support/ReplacedMethodOverrideTests.cs @@ -24,157 +24,156 @@ using NUnit.Framework; #endregion -namespace Spring.Objects.Factory.Support +namespace Spring.Objects.Factory.Support; + +/// +/// Unit tests for the ReplacedMethodOverride class. +/// +/// Rick Evans +[TestFixture] +public sealed class ReplacedMethodOverrideTests { - /// - /// Unit tests for the ReplacedMethodOverride class. - /// - /// Rick Evans - [TestFixture] - public sealed class ReplacedMethodOverrideTests - { - [Test] - public void InstantiationWithNullMethodName() - { - Assert.Throws(() => new ReplacedMethodOverride(null, null)); - } + [Test] + public void InstantiationWithNullMethodName() + { + Assert.Throws(() => new ReplacedMethodOverride(null, null)); + } - [Test] - public void InstantiationWithEmptyMethodName() - { - Assert.Throws(() => new ReplacedMethodOverride(string.Empty, null)); - } + [Test] + public void InstantiationWithEmptyMethodName() + { + Assert.Throws(() => new ReplacedMethodOverride(string.Empty, null)); + } - [Test] - public void InstantiationWithWhitespacedMethodName() - { - Assert.Throws(() => new ReplacedMethodOverride(" ", null)); - } + [Test] + public void InstantiationWithWhitespacedMethodName() + { + Assert.Throws(() => new ReplacedMethodOverride(" ", null)); + } - [Test] - public void InstantiationWithNullMethodReplacerObjectName() - { - Assert.Throws(() => new ReplacedMethodOverride("foo", null)); - } + [Test] + public void InstantiationWithNullMethodReplacerObjectName() + { + Assert.Throws(() => new ReplacedMethodOverride("foo", null)); + } - [Test] - public void InstantiationWithEmptyMethodReplacerObjectName() - { - Assert.Throws(() => new ReplacedMethodOverride("foo", string.Empty)); - } + [Test] + public void InstantiationWithEmptyMethodReplacerObjectName() + { + Assert.Throws(() => new ReplacedMethodOverride("foo", string.Empty)); + } - [Test] - public void InstantiationWithWhitespacedMethodReplacerObjectName() - { - Assert.Throws(() => new ReplacedMethodOverride("foo", " ")); - } + [Test] + public void InstantiationWithWhitespacedMethodReplacerObjectName() + { + Assert.Throws(() => new ReplacedMethodOverride("foo", " ")); + } - [Test] - public void AddNullTypeIdentifier() - { - Assert.Throws(() => new ReplacedMethodOverride("foo", "foo").AddTypeIdentifier(null)); - } + [Test] + public void AddNullTypeIdentifier() + { + Assert.Throws(() => new ReplacedMethodOverride("foo", "foo").AddTypeIdentifier(null)); + } - [Test] - public void AddEmptyTypeIdentifier() - { - Assert.Throws(() => new ReplacedMethodOverride("foo", "foo").AddTypeIdentifier(string.Empty)); - } + [Test] + public void AddEmptyTypeIdentifier() + { + Assert.Throws(() => new ReplacedMethodOverride("foo", "foo").AddTypeIdentifier(string.Empty)); + } - [Test] - public void AddWhitespacedTypeIdentifier() - { - Assert.Throws(() => new ReplacedMethodOverride("foo", "foo").AddTypeIdentifier("\n ")); - } + [Test] + public void AddWhitespacedTypeIdentifier() + { + Assert.Throws(() => new ReplacedMethodOverride("foo", "foo").AddTypeIdentifier("\n ")); + } - [Test] - public void Matches_TotallyDifferentMethodName() - { - ReplacedMethodOverride methodOverride = new ReplacedMethodOverride("Execute", "replacer"); - Assert.IsFalse(methodOverride.Matches(typeof (Executor).GetMethod("Administer"))); - } + [Test] + public void Matches_TotallyDifferentMethodName() + { + ReplacedMethodOverride methodOverride = new ReplacedMethodOverride("Execute", "replacer"); + Assert.IsFalse(methodOverride.Matches(typeof(Executor).GetMethod("Administer"))); + } - [Test] - public void Matches_MatchingMethodNameNoOverload() - { - ReplacedMethodOverride methodOverride = new ReplacedMethodOverride("Administer", "replacer"); - methodOverride.IsOverloaded = false; - Assert.IsTrue(methodOverride.Matches(typeof (Executor).GetMethod("Administer"))); - } + [Test] + public void Matches_MatchingMethodNameNoOverload() + { + ReplacedMethodOverride methodOverride = new ReplacedMethodOverride("Administer", "replacer"); + methodOverride.IsOverloaded = false; + Assert.IsTrue(methodOverride.Matches(typeof(Executor).GetMethod("Administer"))); + } - [Test] - public void Matches_MatchingMethodNameWithOverload() - { - ReplacedMethodOverride methodOverride = new ReplacedMethodOverride("Execute", "replacer"); - Assert.IsTrue(methodOverride.Matches(typeof (Executor).GetMethod("Execute", new Type[] {}))); - } + [Test] + public void Matches_MatchingMethodNameWithOverload() + { + ReplacedMethodOverride methodOverride = new ReplacedMethodOverride("Execute", "replacer"); + Assert.IsTrue(methodOverride.Matches(typeof(Executor).GetMethod("Execute", new Type[] { }))); + } - [Test] - public void Matches_MatchingMethodNameWithOverloadAndTypeIdentifiers() - { - ReplacedMethodOverride methodOverride = new ReplacedMethodOverride("Execute", "replacer"); - methodOverride.AddTypeIdentifier(typeof (object).FullName); - Assert.IsTrue(methodOverride.Matches(typeof (Executor).GetMethod("Execute", new Type[] {typeof (object)}))); - } + [Test] + public void Matches_MatchingMethodNameWithOverloadAndTypeIdentifiers() + { + ReplacedMethodOverride methodOverride = new ReplacedMethodOverride("Execute", "replacer"); + methodOverride.AddTypeIdentifier(typeof(object).FullName); + Assert.IsTrue(methodOverride.Matches(typeof(Executor).GetMethod("Execute", new Type[] { typeof(object) }))); + } - [Test] - public void Matches_MatchingMethodNameWithOverloadAndBadTypeIdentifiers() - { - ReplacedMethodOverride methodOverride = new ReplacedMethodOverride("Execute", "replacer"); - methodOverride.AddTypeIdentifier(GetType().FullName); - Assert.IsFalse(methodOverride.Matches(typeof (Executor).GetMethod("Execute", new Type[] {typeof (object)}))); - } + [Test] + public void Matches_MatchingMethodNameWithOverloadAndBadTypeIdentifiers() + { + ReplacedMethodOverride methodOverride = new ReplacedMethodOverride("Execute", "replacer"); + methodOverride.AddTypeIdentifier(GetType().FullName); + Assert.IsFalse(methodOverride.Matches(typeof(Executor).GetMethod("Execute", new Type[] { typeof(object) }))); + } - [Test] - public void Matches_RequiresAllTypeIdentifiers() - { - ReplacedMethodOverride methodOverride = new ReplacedMethodOverride("Execute", "replacer"); - methodOverride.AddTypeIdentifier(typeof (object).FullName); - Assert.IsFalse(methodOverride.Matches(typeof (Executor).GetMethod("Execute", - new Type[] {typeof (object), typeof (object)}))); - } + [Test] + public void Matches_RequiresAllTypeIdentifiers() + { + ReplacedMethodOverride methodOverride = new ReplacedMethodOverride("Execute", "replacer"); + methodOverride.AddTypeIdentifier(typeof(object).FullName); + Assert.IsFalse(methodOverride.Matches(typeof(Executor).GetMethod("Execute", + new Type[] { typeof(object), typeof(object) }))); + } - [Test] - public void Matches_AllTypeIdentifiers() - { - ReplacedMethodOverride methodOverride = new ReplacedMethodOverride("Execute", "replacer"); - methodOverride.AddTypeIdentifier(typeof (object).FullName); - methodOverride.AddTypeIdentifier(typeof (object).FullName); - Assert.IsTrue(methodOverride.Matches(typeof (Executor).GetMethod("Execute", - new Type[] {typeof (object), typeof (object)}))); - } + [Test] + public void Matches_AllTypeIdentifiers() + { + ReplacedMethodOverride methodOverride = new ReplacedMethodOverride("Execute", "replacer"); + methodOverride.AddTypeIdentifier(typeof(object).FullName); + methodOverride.AddTypeIdentifier(typeof(object).FullName); + Assert.IsTrue(methodOverride.Matches(typeof(Executor).GetMethod("Execute", + new Type[] { typeof(object), typeof(object) }))); + } - [Test] - public void MatchesWithNullMethod() - { - ReplacedMethodOverride methodOverride = new ReplacedMethodOverride("Execute", "replacer"); - Assert.Throws(() => methodOverride.Matches(null)); - } + [Test] + public void MatchesWithNullMethod() + { + ReplacedMethodOverride methodOverride = new ReplacedMethodOverride("Execute", "replacer"); + Assert.Throws(() => methodOverride.Matches(null)); + } - [Test] - public void ToStringWorks() - { - ReplacedMethodOverride methodOverride = new ReplacedMethodOverride("Execute", "replacer"); - Assert.AreEqual(typeof(ReplacedMethodOverride).Name + " for method 'Execute'; will call object 'replacer'.", methodOverride.ToString()); - } + [Test] + public void ToStringWorks() + { + ReplacedMethodOverride methodOverride = new ReplacedMethodOverride("Execute", "replacer"); + Assert.AreEqual(typeof(ReplacedMethodOverride).Name + " for method 'Execute'; will call object 'replacer'.", methodOverride.ToString()); + } - private sealed class Executor - { - public void Administer() - { - } + private sealed class Executor + { + public void Administer() + { + } - public void Execute() - { - } + public void Execute() + { + } - public void Execute(object sender) - { - } + public void Execute(object sender) + { + } - public void Execute(object sender, object context) - { - } - } - } -} \ No newline at end of file + public void Execute(object sender, object context) + { + } + } +} diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Support/RootObjectDefinitionTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Support/RootObjectDefinitionTests.cs index 98dd59b7..d02181d6 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Support/RootObjectDefinitionTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Support/RootObjectDefinitionTests.cs @@ -22,168 +22,166 @@ using Spring.Objects.Support; using Spring.Objects.Factory.Config; - using NUnit.Framework; #endregion -namespace Spring.Objects.Factory.Support +namespace Spring.Objects.Factory.Support; + +/// +/// Unit tests for the RootObjectDefinition class. +/// +/// Rick Evans +[TestFixture] +public sealed class RootObjectDefinitionTests { - /// - /// Unit tests for the RootObjectDefinition class. - /// - /// Rick Evans - [TestFixture] - public sealed class RootObjectDefinitionTests + [Test] + public void InstantiationWithClassName() { - [Test] - public void InstantiationWithClassName() - { - RootObjectDefinition def = new RootObjectDefinition(typeof(TestObject).AssemblyQualifiedName, new ConstructorArgumentValues(), new MutablePropertyValues()); - Assert.IsFalse(def.HasObjectType); - Assert.Throws(() => Assert.IsNull(def.ObjectType)); // must bail... - } - - [Test] - public void InstantiationFromOther() - { - RootObjectDefinition other = new RootObjectDefinition( typeof( TestObject ), AutoWiringMode.Constructor ); - other.IsSingleton = false; - other.InitMethodName = "Umberto Eco"; - other.DestroyMethodName = "Pedulismus"; - other.ConstructorArgumentValues = new ConstructorArgumentValues(); - other.DependencyCheck = DependencyCheckingMode.Objects; - other.DependsOn = new string[] { "Jimmy", "Joyce" }; - other.EventHandlerValues = new EventValues(); - other.IsAbstract = true; - other.IsLazyInit = true; - other.FactoryMethodName = "IfINeedYouIllJustUseYourSimpleName"; - other.FactoryObjectName = "PerspirationShop"; - other.ResourceDescription = "Ohhh"; - other.PropertyValues = new MutablePropertyValues(); - other.PropertyValues.Add( "Age", 100 ); - InstanceEventHandlerValue handler = - new InstanceEventHandlerValue( new TestObject(), "Ping" ); - handler.EventName = "Bing"; - other.EventHandlerValues.AddHandler( handler ); - other.ConstructorArgumentValues.AddGenericArgumentValue( "Wulf", "Sternhammer" ); - - RootObjectDefinition def = new RootObjectDefinition( other ); - - // ... - Assert.AreEqual( typeof( TestObject ), def.ObjectType ); - Assert.AreEqual( AutoWiringMode.Constructor, def.AutowireMode ); - Assert.IsFalse( def.IsSingleton ); - Assert.AreEqual( "Umberto Eco", def.InitMethodName ); - Assert.AreEqual( "Pedulismus", def.DestroyMethodName ); - Assert.AreEqual( DependencyCheckingMode.Objects, def.DependencyCheck ); - Assert.IsTrue( def.IsAbstract ); - Assert.IsTrue( def.IsLazyInit ); - Assert.AreEqual( "IfINeedYouIllJustUseYourSimpleName", def.FactoryMethodName ); - Assert.AreEqual( "PerspirationShop", def.FactoryObjectName ); - Assert.AreEqual( "Ohhh", def.ResourceDescription ); - Assert.IsTrue( def.HasConstructorArgumentValues ); - Assert.AreEqual( other.ConstructorArgumentValues.ArgumentCount, def.ConstructorArgumentValues.ArgumentCount ); - Assert.AreEqual( other.PropertyValues.PropertyValues.Count, def.PropertyValues.PropertyValues.Count ); - Assert.AreEqual( other.EventHandlerValues.Events.Count, def.EventHandlerValues.Events.Count ); - } - - [Test] - public void OverrideFromOther() - { - RootObjectDefinition rod = new RootObjectDefinition( typeof( TestObject ), AutoWiringMode.Constructor ); - rod.IsSingleton = false; - rod.InitMethodName = "Umberto Eco"; - rod.DestroyMethodName = "Pedulismus"; - rod.ConstructorArgumentValues = new ConstructorArgumentValues(); - rod.ConstructorArgumentValues.AddGenericArgumentValue( "Wulf", "Sternhammer" ); - rod.DependencyCheck = DependencyCheckingMode.Objects; - rod.DependsOn = new string[] { "Jimmy", "Joyce" }; - rod.IsAbstract = true; - rod.IsLazyInit = true; - rod.FactoryMethodName = "IfINeedYouIllJustUseYourSimpleName"; - rod.FactoryObjectName = "PerspirationShop"; - rod.ResourceDescription = "Ohhh"; - rod.PropertyValues = new MutablePropertyValues(); - rod.PropertyValues.Add( "Age", 100 ); - rod.EventHandlerValues = new EventValues(); - InstanceEventHandlerValue handler = new InstanceEventHandlerValue( new TestObject(), "Ping" ); - handler.EventName = "Bing"; - rod.EventHandlerValues.AddHandler( handler ); - - ChildObjectDefinition cod = new ChildObjectDefinition( "parent" ); - cod.ObjectTypeName = "ChildObjectTypeName"; - cod.IsSingleton = true; - cod.AutowireMode = AutoWiringMode.ByType; - cod.InitMethodName = "InitChild"; - cod.DestroyMethodName = "DestroyChild"; - cod.ConstructorArgumentValues = new ConstructorArgumentValues(); - cod.ConstructorArgumentValues.AddNamedArgumentValue( "ctorarg", "ctorarg-value" ); - cod.DependencyCheck = DependencyCheckingMode.None; - cod.DependsOn = new string[] { "Aleks", "Mark" }; - cod.IsAbstract = false; - cod.IsLazyInit = false; - cod.FactoryMethodName = "ChildFactoryMethodName"; - cod.FactoryObjectName = "ChildFactoryObjectName"; - cod.ResourceDescription = "ChildResourceDescription"; - cod.PropertyValues = new MutablePropertyValues(); - cod.PropertyValues.Add( "Prop1", "Val1" ); - cod.PropertyValues.Add( "Age", 50 ); - cod.EventHandlerValues = new EventValues(); - handler = new InstanceEventHandlerValue( new TestObject(), "Pong" ); - handler.EventName = "Bong"; - cod.EventHandlerValues.AddHandler( handler ); - - rod.OverrideFrom( cod ); - - // ... - Assert.AreEqual( "ChildObjectTypeName", rod.ObjectTypeName ); - Assert.AreEqual( AutoWiringMode.ByType, rod.AutowireMode ); - Assert.AreEqual( true, rod.IsSingleton ); - Assert.AreEqual( "InitChild", rod.InitMethodName ); - Assert.AreEqual( "DestroyChild", rod.DestroyMethodName ); - Assert.AreEqual( DependencyCheckingMode.None, rod.DependencyCheck ); - Assert.AreEqual( 4, rod.DependsOn.Count); - Assert.AreEqual( false, rod.IsAbstract ); - Assert.AreEqual( false, rod.IsLazyInit ); - Assert.AreEqual( "ChildFactoryMethodName", rod.FactoryMethodName ); - Assert.AreEqual( "ChildFactoryObjectName", rod.FactoryObjectName ); - Assert.AreEqual( "ChildResourceDescription", rod.ResourceDescription ); - Assert.AreEqual( 2, rod.ConstructorArgumentValues.ArgumentCount ); - Assert.AreEqual( 2, rod.PropertyValues.PropertyValues.Count ); - Assert.AreEqual( "Val1", rod.PropertyValues.GetPropertyValue("Prop1").Value); - Assert.AreEqual( 50, rod.PropertyValues.GetPropertyValue("Age").Value); - Assert.AreEqual( 2, rod.EventHandlerValues.Events.Count ); - } - - [Test] - public void ValidateLazyAndPrototypeCausesBail() - { - RootObjectDefinition def - = new RootObjectDefinition( typeof( TestObject ), AutoWiringMode.No ); - def.IsLazyInit = true; - def.IsSingleton = false; - Assert.Throws(() => def.Validate()); - } - - [Test] - public void InstantiationWithNullCtorArgsAndNullPropsDoesNotResultInNullPropertyValues() - { - RootObjectDefinition def - = new RootObjectDefinition( typeof( TestObject ), null, null ); - Assert.IsNotNull( def.ConstructorArgumentValues, - "Must never be null, but rather just empty." ); - Assert.AreEqual( 0, def.ConstructorArgumentValues.ArgumentCount, - "Must be empty if null was passed to the ctor." ); - Assert.IsNotNull( def.PropertyValues, - "Must never be null, but rather just empty." ); - Assert.AreEqual( 0, def.PropertyValues.PropertyValues.Count, - "Must be empty if null was passed to the ctor." ); - } + RootObjectDefinition def = new RootObjectDefinition(typeof(TestObject).AssemblyQualifiedName, new ConstructorArgumentValues(), new MutablePropertyValues()); + Assert.IsFalse(def.HasObjectType); + Assert.Throws(() => Assert.IsNull(def.ObjectType)); // must bail... } - internal class NoPublicCtors + [Test] + public void InstantiationFromOther() { - protected NoPublicCtors() { } + RootObjectDefinition other = new RootObjectDefinition(typeof(TestObject), AutoWiringMode.Constructor); + other.IsSingleton = false; + other.InitMethodName = "Umberto Eco"; + other.DestroyMethodName = "Pedulismus"; + other.ConstructorArgumentValues = new ConstructorArgumentValues(); + other.DependencyCheck = DependencyCheckingMode.Objects; + other.DependsOn = new string[] { "Jimmy", "Joyce" }; + other.EventHandlerValues = new EventValues(); + other.IsAbstract = true; + other.IsLazyInit = true; + other.FactoryMethodName = "IfINeedYouIllJustUseYourSimpleName"; + other.FactoryObjectName = "PerspirationShop"; + other.ResourceDescription = "Ohhh"; + other.PropertyValues = new MutablePropertyValues(); + other.PropertyValues.Add("Age", 100); + InstanceEventHandlerValue handler = + new InstanceEventHandlerValue(new TestObject(), "Ping"); + handler.EventName = "Bing"; + other.EventHandlerValues.AddHandler(handler); + other.ConstructorArgumentValues.AddGenericArgumentValue("Wulf", "Sternhammer"); + + RootObjectDefinition def = new RootObjectDefinition(other); + + // ... + Assert.AreEqual(typeof(TestObject), def.ObjectType); + Assert.AreEqual(AutoWiringMode.Constructor, def.AutowireMode); + Assert.IsFalse(def.IsSingleton); + Assert.AreEqual("Umberto Eco", def.InitMethodName); + Assert.AreEqual("Pedulismus", def.DestroyMethodName); + Assert.AreEqual(DependencyCheckingMode.Objects, def.DependencyCheck); + Assert.IsTrue(def.IsAbstract); + Assert.IsTrue(def.IsLazyInit); + Assert.AreEqual("IfINeedYouIllJustUseYourSimpleName", def.FactoryMethodName); + Assert.AreEqual("PerspirationShop", def.FactoryObjectName); + Assert.AreEqual("Ohhh", def.ResourceDescription); + Assert.IsTrue(def.HasConstructorArgumentValues); + Assert.AreEqual(other.ConstructorArgumentValues.ArgumentCount, def.ConstructorArgumentValues.ArgumentCount); + Assert.AreEqual(other.PropertyValues.PropertyValues.Count, def.PropertyValues.PropertyValues.Count); + Assert.AreEqual(other.EventHandlerValues.Events.Count, def.EventHandlerValues.Events.Count); + } + + [Test] + public void OverrideFromOther() + { + RootObjectDefinition rod = new RootObjectDefinition(typeof(TestObject), AutoWiringMode.Constructor); + rod.IsSingleton = false; + rod.InitMethodName = "Umberto Eco"; + rod.DestroyMethodName = "Pedulismus"; + rod.ConstructorArgumentValues = new ConstructorArgumentValues(); + rod.ConstructorArgumentValues.AddGenericArgumentValue("Wulf", "Sternhammer"); + rod.DependencyCheck = DependencyCheckingMode.Objects; + rod.DependsOn = new string[] { "Jimmy", "Joyce" }; + rod.IsAbstract = true; + rod.IsLazyInit = true; + rod.FactoryMethodName = "IfINeedYouIllJustUseYourSimpleName"; + rod.FactoryObjectName = "PerspirationShop"; + rod.ResourceDescription = "Ohhh"; + rod.PropertyValues = new MutablePropertyValues(); + rod.PropertyValues.Add("Age", 100); + rod.EventHandlerValues = new EventValues(); + InstanceEventHandlerValue handler = new InstanceEventHandlerValue(new TestObject(), "Ping"); + handler.EventName = "Bing"; + rod.EventHandlerValues.AddHandler(handler); + + ChildObjectDefinition cod = new ChildObjectDefinition("parent"); + cod.ObjectTypeName = "ChildObjectTypeName"; + cod.IsSingleton = true; + cod.AutowireMode = AutoWiringMode.ByType; + cod.InitMethodName = "InitChild"; + cod.DestroyMethodName = "DestroyChild"; + cod.ConstructorArgumentValues = new ConstructorArgumentValues(); + cod.ConstructorArgumentValues.AddNamedArgumentValue("ctorarg", "ctorarg-value"); + cod.DependencyCheck = DependencyCheckingMode.None; + cod.DependsOn = new string[] { "Aleks", "Mark" }; + cod.IsAbstract = false; + cod.IsLazyInit = false; + cod.FactoryMethodName = "ChildFactoryMethodName"; + cod.FactoryObjectName = "ChildFactoryObjectName"; + cod.ResourceDescription = "ChildResourceDescription"; + cod.PropertyValues = new MutablePropertyValues(); + cod.PropertyValues.Add("Prop1", "Val1"); + cod.PropertyValues.Add("Age", 50); + cod.EventHandlerValues = new EventValues(); + handler = new InstanceEventHandlerValue(new TestObject(), "Pong"); + handler.EventName = "Bong"; + cod.EventHandlerValues.AddHandler(handler); + + rod.OverrideFrom(cod); + + // ... + Assert.AreEqual("ChildObjectTypeName", rod.ObjectTypeName); + Assert.AreEqual(AutoWiringMode.ByType, rod.AutowireMode); + Assert.AreEqual(true, rod.IsSingleton); + Assert.AreEqual("InitChild", rod.InitMethodName); + Assert.AreEqual("DestroyChild", rod.DestroyMethodName); + Assert.AreEqual(DependencyCheckingMode.None, rod.DependencyCheck); + Assert.AreEqual(4, rod.DependsOn.Count); + Assert.AreEqual(false, rod.IsAbstract); + Assert.AreEqual(false, rod.IsLazyInit); + Assert.AreEqual("ChildFactoryMethodName", rod.FactoryMethodName); + Assert.AreEqual("ChildFactoryObjectName", rod.FactoryObjectName); + Assert.AreEqual("ChildResourceDescription", rod.ResourceDescription); + Assert.AreEqual(2, rod.ConstructorArgumentValues.ArgumentCount); + Assert.AreEqual(2, rod.PropertyValues.PropertyValues.Count); + Assert.AreEqual("Val1", rod.PropertyValues.GetPropertyValue("Prop1").Value); + Assert.AreEqual(50, rod.PropertyValues.GetPropertyValue("Age").Value); + Assert.AreEqual(2, rod.EventHandlerValues.Events.Count); + } + + [Test] + public void ValidateLazyAndPrototypeCausesBail() + { + RootObjectDefinition def + = new RootObjectDefinition(typeof(TestObject), AutoWiringMode.No); + def.IsLazyInit = true; + def.IsSingleton = false; + Assert.Throws(() => def.Validate()); + } + + [Test] + public void InstantiationWithNullCtorArgsAndNullPropsDoesNotResultInNullPropertyValues() + { + RootObjectDefinition def + = new RootObjectDefinition(typeof(TestObject), null, null); + Assert.IsNotNull(def.ConstructorArgumentValues, + "Must never be null, but rather just empty."); + Assert.AreEqual(0, def.ConstructorArgumentValues.ArgumentCount, + "Must be empty if null was passed to the ctor."); + Assert.IsNotNull(def.PropertyValues, + "Must never be null, but rather just empty."); + Assert.AreEqual(0, def.PropertyValues.PropertyValues.Count, + "Must be empty if null was passed to the ctor."); } } + +internal class NoPublicCtors +{ + protected NoPublicCtors() { } +} diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Support/SimpleInstantiationStrategyTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Support/SimpleInstantiationStrategyTests.cs index a4ba09a6..df147de1 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Support/SimpleInstantiationStrategyTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Support/SimpleInstantiationStrategyTests.cs @@ -25,131 +25,130 @@ using Spring.Objects.Factory.Config; #endregion -namespace Spring.Objects.Factory.Support +namespace Spring.Objects.Factory.Support; + +/// +/// Unit tests for the SimpleInstantiationStrategy class. +/// +/// Rick Evans +[TestFixture] +public sealed class SimpleInstantiationStrategyTests { - /// - /// Unit tests for the SimpleInstantiationStrategy class. - /// - /// Rick Evans - [TestFixture] - public sealed class SimpleInstantiationStrategyTests - { - #region SetUp + #region SetUp - /// - /// The setup logic executed before the execution of each individual test. - /// - [SetUp] - public void SetUp() - { - _singletonDefinition = new RootObjectDefinition(typeof (TestObject), AutoWiringMode.No); - _singletonDefinitionWithFactory = new RootObjectDefinition(_singletonDefinition); - _singletonDefinitionWithFactory.FactoryMethodName = "GetObject"; - _singletonDefinitionWithFactory.FactoryObjectName = "TestObjectFactoryDefinition"; - _testObjectFactory = new RootObjectDefinition(typeof (TestObjectFactory), AutoWiringMode.No); - DefaultListableObjectFactory myFactory = new DefaultListableObjectFactory(); - myFactory.RegisterObjectDefinition("SingletonObjectDefinition", SingletonDefinition); - myFactory.RegisterObjectDefinition("SingletonDefinitionWithFactory", SingletonDefinitionWithFactory); - myFactory.RegisterObjectDefinition("TestObjectFactoryDefinition", TestObjectFactoryDefinition); - _factory = myFactory; - } + /// + /// The setup logic executed before the execution of each individual test. + /// + [SetUp] + public void SetUp() + { + _singletonDefinition = new RootObjectDefinition(typeof(TestObject), AutoWiringMode.No); + _singletonDefinitionWithFactory = new RootObjectDefinition(_singletonDefinition); + _singletonDefinitionWithFactory.FactoryMethodName = "GetObject"; + _singletonDefinitionWithFactory.FactoryObjectName = "TestObjectFactoryDefinition"; + _testObjectFactory = new RootObjectDefinition(typeof(TestObjectFactory), AutoWiringMode.No); + DefaultListableObjectFactory myFactory = new DefaultListableObjectFactory(); + myFactory.RegisterObjectDefinition("SingletonObjectDefinition", SingletonDefinition); + myFactory.RegisterObjectDefinition("SingletonDefinitionWithFactory", SingletonDefinitionWithFactory); + myFactory.RegisterObjectDefinition("TestObjectFactoryDefinition", TestObjectFactoryDefinition); + _factory = myFactory; + } - #endregion + #endregion - [Test] - public void InstantiateWithNulls() - { - SimpleInstantiationStrategy strategy = new SimpleInstantiationStrategy(); - Assert.Throws(() => strategy.Instantiate(null, null, null)); - } + [Test] + public void InstantiateWithNulls() + { + SimpleInstantiationStrategy strategy = new SimpleInstantiationStrategy(); + Assert.Throws(() => strategy.Instantiate(null, null, null)); + } - [Test] - public void InstantiateWithNullObjectName() - { - SimpleInstantiationStrategy strategy = new SimpleInstantiationStrategy(); - object obj = strategy.Instantiate(SingletonDefinition, null, Factory); - Assert.IsNotNull(obj); - Assert.IsTrue(obj is ITestObject); - ITestObject actual = (ITestObject) obj; - Assert.IsNull(actual.Name); - Assert.AreEqual(0, actual.Age); - } + [Test] + public void InstantiateWithNullObjectName() + { + SimpleInstantiationStrategy strategy = new SimpleInstantiationStrategy(); + object obj = strategy.Instantiate(SingletonDefinition, null, Factory); + Assert.IsNotNull(obj); + Assert.IsTrue(obj is ITestObject); + ITestObject actual = (ITestObject) obj; + Assert.IsNull(actual.Name); + Assert.AreEqual(0, actual.Age); + } - [Test] - public void InstantiateWithExplicitCtor() - { - SimpleInstantiationStrategy strategy = new SimpleInstantiationStrategy(); - object obj = strategy.Instantiate( - SingletonDefinition, null, Factory, - SingletonDefinition.ObjectType.GetConstructor( - new Type[] {typeof (string), typeof (int)}), - new object[] {"Rick", 19}); - Assert.IsNotNull(obj); - Assert.IsTrue(obj is ITestObject); - ITestObject actual = (ITestObject) obj; - Assert.AreEqual("Rick", actual.Name); - Assert.AreEqual(19, actual.Age); - } + [Test] + public void InstantiateWithExplicitCtor() + { + SimpleInstantiationStrategy strategy = new SimpleInstantiationStrategy(); + object obj = strategy.Instantiate( + SingletonDefinition, null, Factory, + SingletonDefinition.ObjectType.GetConstructor( + new Type[] { typeof(string), typeof(int) }), + new object[] { "Rick", 19 }); + Assert.IsNotNull(obj); + Assert.IsTrue(obj is ITestObject); + ITestObject actual = (ITestObject) obj; + Assert.AreEqual("Rick", actual.Name); + Assert.AreEqual(19, actual.Age); + } - [Test] - public void InstantiateWithFactoryMethod() - { - SimpleInstantiationStrategy strategy = new SimpleInstantiationStrategy(); - object obj = strategy.Instantiate(SingletonDefinitionWithFactory, - string.Empty, Factory, typeof (TestObjectFactory).GetMethod("GetObject"), null); - Assert.IsNotNull(obj); - Assert.IsTrue(obj is ITestObject); - ITestObject actual = (ITestObject) obj; - Assert.AreEqual(TestObjectFactory.TheName, actual.Name); - Assert.AreEqual(TestObjectFactory.TheAge, actual.Age); - } + [Test] + public void InstantiateWithFactoryMethod() + { + SimpleInstantiationStrategy strategy = new SimpleInstantiationStrategy(); + object obj = strategy.Instantiate(SingletonDefinitionWithFactory, + string.Empty, Factory, typeof(TestObjectFactory).GetMethod("GetObject"), null); + Assert.IsNotNull(obj); + Assert.IsTrue(obj is ITestObject); + ITestObject actual = (ITestObject) obj; + Assert.AreEqual(TestObjectFactory.TheName, actual.Name); + Assert.AreEqual(TestObjectFactory.TheAge, actual.Age); + } - [Test] - public void InstantiateWithDefinitionThatDoesNotHaveAResolvedObjectClass() - { - RootObjectDefinition def = new RootObjectDefinition(); - def.ObjectTypeName = typeof(TestObject).FullName; + [Test] + public void InstantiateWithDefinitionThatDoesNotHaveAResolvedObjectClass() + { + RootObjectDefinition def = new RootObjectDefinition(); + def.ObjectTypeName = typeof(TestObject).FullName; - SimpleInstantiationStrategy strategy = new SimpleInstantiationStrategy(); - object foo = strategy.Instantiate(def, "foo", Factory); - Assert.IsNotNull(foo); - Assert.AreEqual(typeof(TestObject), foo.GetType()); - } + SimpleInstantiationStrategy strategy = new SimpleInstantiationStrategy(); + object foo = strategy.Instantiate(def, "foo", Factory); + Assert.IsNotNull(foo); + Assert.AreEqual(typeof(TestObject), foo.GetType()); + } - private RootObjectDefinition SingletonDefinition - { - get { return _singletonDefinition; } - } + private RootObjectDefinition SingletonDefinition + { + get { return _singletonDefinition; } + } - private RootObjectDefinition SingletonDefinitionWithFactory - { - get { return _singletonDefinitionWithFactory; } - } + private RootObjectDefinition SingletonDefinitionWithFactory + { + get { return _singletonDefinitionWithFactory; } + } - private RootObjectDefinition TestObjectFactoryDefinition - { - get { return _testObjectFactory; } - } + private RootObjectDefinition TestObjectFactoryDefinition + { + get { return _testObjectFactory; } + } - private IObjectFactory Factory - { - get { return _factory; } - } + private IObjectFactory Factory + { + get { return _factory; } + } - private RootObjectDefinition _singletonDefinition; - private RootObjectDefinition _testObjectFactory; - private RootObjectDefinition _singletonDefinitionWithFactory; - private IObjectFactory _factory; - } + private RootObjectDefinition _singletonDefinition; + private RootObjectDefinition _testObjectFactory; + private RootObjectDefinition _singletonDefinitionWithFactory; + private IObjectFactory _factory; +} - public class TestObjectFactory - { - public const string TheName = "Old Goriot"; - public const int TheAge = 78; +public class TestObjectFactory +{ + public const string TheName = "Old Goriot"; + public const int TheAge = 78; - public virtual object GetObject() - { - return new TestObject(TheName, TheAge); - } - } -} \ No newline at end of file + public virtual object GetObject() + { + return new TestObject(TheName, TheAge); + } +} diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/UnsupportedObjectDefinitionImplementation.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/UnsupportedObjectDefinitionImplementation.cs index 98ff6b22..a51cf4cf 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/UnsupportedObjectDefinitionImplementation.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/UnsupportedObjectDefinitionImplementation.cs @@ -21,126 +21,125 @@ using Spring.Objects.Factory.Config; using Spring.Objects.Factory.Support; -namespace Spring.Objects.Factory +namespace Spring.Objects.Factory; + +internal class UnsupportedObjectDefinitionImplementation : IObjectDefinition { - internal class UnsupportedObjectDefinitionImplementation : IObjectDefinition + public MutablePropertyValues PropertyValues { - public MutablePropertyValues PropertyValues - { - get { throw new NotImplementedException(); } - } - - public ConstructorArgumentValues ConstructorArgumentValues - { - get { throw new NotImplementedException(); } - } - - public MethodOverrides MethodOverrides - { - get { throw new NotImplementedException(); } - } - - public EventValues EventHandlerValues - { - get { throw new NotImplementedException(); } - } - - public string ResourceDescription - { - get { return "UnsupportedObjectDefinitionImplementation_Resource"; } - } - - public bool IsTemplate - { - get { throw new NotImplementedException(); } - } - - public bool IsAbstract - { - get { return false; } - } - - public bool IsSingleton - { - get { throw new NotImplementedException(); } - } - - public bool IsLazyInit - { - get { return false; } - } - - public bool IsPrimary - { - get { return false; } - } - - public string ParentName - { - get { return null; } - set { throw new NotImplementedException(); } - } - - public string Scope - { - get { return "UnsupportedObjectDefinitionImplementation_Resource"; } - set { throw new System.NotImplementedException(); } - } - - public ObjectRole Role - { - get { throw new NotImplementedException(); } - } - - public Type ObjectType - { - get { throw new NotImplementedException(); } - } - - public string ObjectTypeName - { - get { throw new NotImplementedException(); } - set { throw new NotImplementedException(); } - } - - public AutoWiringMode AutowireMode - { - get { throw new NotImplementedException(); } - } - - public DependencyCheckingMode DependencyCheck - { - get { throw new NotImplementedException(); } - } - - public IReadOnlyList DependsOn - { - get { throw new NotImplementedException(); } - } - - public string InitMethodName - { - get { throw new NotImplementedException(); } - } - - public string DestroyMethodName - { - get { throw new NotImplementedException(); } - } - - public string FactoryMethodName - { - get { throw new NotImplementedException(); } - } - - public string FactoryObjectName - { - get { throw new NotImplementedException(); } - } - - public bool IsAutowireCandidate - { - get { throw new NotImplementedException(); } - } + get { throw new NotImplementedException(); } } -} \ No newline at end of file + + public ConstructorArgumentValues ConstructorArgumentValues + { + get { throw new NotImplementedException(); } + } + + public MethodOverrides MethodOverrides + { + get { throw new NotImplementedException(); } + } + + public EventValues EventHandlerValues + { + get { throw new NotImplementedException(); } + } + + public string ResourceDescription + { + get { return "UnsupportedObjectDefinitionImplementation_Resource"; } + } + + public bool IsTemplate + { + get { throw new NotImplementedException(); } + } + + public bool IsAbstract + { + get { return false; } + } + + public bool IsSingleton + { + get { throw new NotImplementedException(); } + } + + public bool IsLazyInit + { + get { return false; } + } + + public bool IsPrimary + { + get { return false; } + } + + public string ParentName + { + get { return null; } + set { throw new NotImplementedException(); } + } + + public string Scope + { + get { return "UnsupportedObjectDefinitionImplementation_Resource"; } + set { throw new System.NotImplementedException(); } + } + + public ObjectRole Role + { + get { throw new NotImplementedException(); } + } + + public Type ObjectType + { + get { throw new NotImplementedException(); } + } + + public string ObjectTypeName + { + get { throw new NotImplementedException(); } + set { throw new NotImplementedException(); } + } + + public AutoWiringMode AutowireMode + { + get { throw new NotImplementedException(); } + } + + public DependencyCheckingMode DependencyCheck + { + get { throw new NotImplementedException(); } + } + + public IReadOnlyList DependsOn + { + get { throw new NotImplementedException(); } + } + + public string InitMethodName + { + get { throw new NotImplementedException(); } + } + + public string DestroyMethodName + { + get { throw new NotImplementedException(); } + } + + public string FactoryMethodName + { + get { throw new NotImplementedException(); } + } + + public string FactoryObjectName + { + get { throw new NotImplementedException(); } + } + + public bool IsAutowireCandidate + { + get { throw new NotImplementedException(); } + } +} diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/ArrayCtorDependencyObject.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/ArrayCtorDependencyObject.cs index b972cea2..a1f0e29e 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/ArrayCtorDependencyObject.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/ArrayCtorDependencyObject.cs @@ -18,35 +18,33 @@ #endregion -namespace Spring.Objects.Factory.Xml +namespace Spring.Objects.Factory.Xml; + +/// +/// Class used to test array ctor autowiring +/// +/// +/// +/// +/// Mark Pollack +public class ArrayCtorDependencyObject { - /// - /// Class used to test array ctor autowiring - /// - /// - /// - /// - /// Mark Pollack - public class ArrayCtorDependencyObject + private ITestObject spouse1; + private ITestObject spouse2; + + public ArrayCtorDependencyObject(ITestObject[] spouses) { - private ITestObject spouse1; - private ITestObject spouse2; - - - public ArrayCtorDependencyObject(ITestObject[] spouses) - { - this.spouse1 = spouses[0]; - this.spouse2 = spouses[1]; - } - - public ITestObject Spouse1 - { - get { return spouse1; } - } - - public ITestObject Spouse2 - { - get { return spouse2; } - } + this.spouse1 = spouses[0]; + this.spouse2 = spouses[1]; } -} \ No newline at end of file + + public ITestObject Spouse1 + { + get { return spouse1; } + } + + public ITestObject Spouse2 + { + get { return spouse2; } + } +} diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/CollectionConversionGenericTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/CollectionConversionGenericTests.cs index 49ec9cf8..4dfb62ee 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/CollectionConversionGenericTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/CollectionConversionGenericTests.cs @@ -28,103 +28,101 @@ using System.Collections.Specialized; #endregion -namespace Spring.Objects.Factory.Xml +namespace Spring.Objects.Factory.Xml; + +/// +/// Unit and integration tests for collection conversion support +/// +/// Choy Rim +[TestFixture] +[Description("SPRNET-1470 Setting property of type IList using without the @element-type specified fails.")] +public class CollectionConversionGenericTests { - /// - /// Unit and integration tests for collection conversion support - /// - /// Choy Rim - [TestFixture] - [Description("SPRNET-1470 Setting property of type IList using without the @element-type specified fails.")] - public class CollectionConversionGenericTests + private DefaultListableObjectFactory objectFactory; + + [SetUp] + public void SetUp() { - private DefaultListableObjectFactory objectFactory; + this.objectFactory = new DefaultListableObjectFactory(); + IObjectDefinitionReader reader = new XmlObjectDefinitionReader(this.objectFactory); + reader.LoadObjectDefinitions(new ReadOnlyXmlTestResource("collectionConversionGeneric.xml", GetType())); + } - [SetUp] - public void SetUp() + [Test] + public void ShouldConvertListToGenericIList() + { + TestObject to = (TestObject) this.objectFactory.GetObject("HasGenericIListProperty"); + IList list = to.SomeGenericIListInt32; + Assert.That(list.Count, Is.EqualTo(3)); + Assert.That(list[0], Is.EqualTo(123)); + Assert.That(list[1], Is.EqualTo(234)); + Assert.That(list[2], Is.EqualTo(345)); + } + + [Test] + public void ShouldConvertDictionaryToGenericIDictionary() + { + TestObject to = (TestObject) this.objectFactory.GetObject("HasGenericIDictionaryProperty"); + IDictionary dict = to.SomeGenericIDictionaryStringInt32; + Assert.That(dict.Count, Is.EqualTo(3)); + Assert.That(dict["aaa"], Is.EqualTo(111)); + Assert.That(dict["bbb"], Is.EqualTo(222)); + Assert.That(dict["ccc"], Is.EqualTo(333)); + } + + [Test] + public void ShouldConvertListToGenericIEnumerable() + { + TestObject to = (TestObject) this.objectFactory.GetObject("HasGenericIEnumerableProperty"); + IEnumerable enumerable = to.SomeGenericIEnumerableInt32; + int enumerableLength = 0; + int first = 0; + + foreach (int i in enumerable) { - this.objectFactory = new DefaultListableObjectFactory(); - IObjectDefinitionReader reader = new XmlObjectDefinitionReader(this.objectFactory); - reader.LoadObjectDefinitions(new ReadOnlyXmlTestResource("collectionConversionGeneric.xml", GetType())); - } - - [Test] - public void ShouldConvertListToGenericIList() - { - TestObject to = (TestObject)this.objectFactory.GetObject("HasGenericIListProperty"); - IList list = to.SomeGenericIListInt32; - Assert.That(list.Count, Is.EqualTo(3)); - Assert.That(list[0], Is.EqualTo(123)); - Assert.That(list[1], Is.EqualTo(234)); - Assert.That(list[2], Is.EqualTo(345)); - } - - [Test] - public void ShouldConvertDictionaryToGenericIDictionary() - { - TestObject to = (TestObject)this.objectFactory.GetObject("HasGenericIDictionaryProperty"); - IDictionary dict = to.SomeGenericIDictionaryStringInt32; - Assert.That(dict.Count, Is.EqualTo(3)); - Assert.That(dict["aaa"], Is.EqualTo(111)); - Assert.That(dict["bbb"], Is.EqualTo(222)); - Assert.That(dict["ccc"], Is.EqualTo(333)); - } - - [Test] - public void ShouldConvertListToGenericIEnumerable() - { - TestObject to = (TestObject)this.objectFactory.GetObject("HasGenericIEnumerableProperty"); - IEnumerable enumerable = to.SomeGenericIEnumerableInt32; - int enumerableLength = 0; - int first = 0; - - foreach (int i in enumerable) + enumerableLength += 1; + if (enumerableLength == 1) { - enumerableLength += 1; - if (enumerableLength == 1) - { - first = i; - } + first = i; } - - Assert.That(enumerableLength, Is.EqualTo(1)); - Assert.That(first, Is.EqualTo(123)); } - [Test] - public void ConvertArrayListToGenericIList() - { - ArrayList xs = new ArrayList(); - xs.Add("Mark Pollack"); - object ys = TypeConversionUtils.ConvertValueIfNecessary(typeof(IList), xs, "ignored"); - Assert.That(ys as IList, Is.Not.Null); - IList zs = (IList)ys; - Assert.That(zs[0], Is.EqualTo("Mark Pollack")); - } + Assert.That(enumerableLength, Is.EqualTo(1)); + Assert.That(first, Is.EqualTo(123)); + } - [Test] - public void ConvertHybridDictionaryToGenericIDictionary() - { - HybridDictionary xs = new HybridDictionary(); - xs.Add("first", 1); - object ys = TypeConversionUtils.ConvertValueIfNecessary(typeof(IDictionary), xs, "ignored"); - Assert.That(ys as IDictionary, Is.Not.Null); - IDictionary zs = (IDictionary)ys; - Assert.That(zs["first"], Is.EqualTo(1)); - } + [Test] + public void ConvertArrayListToGenericIList() + { + ArrayList xs = new ArrayList(); + xs.Add("Mark Pollack"); + object ys = TypeConversionUtils.ConvertValueIfNecessary(typeof(IList), xs, "ignored"); + Assert.That(ys as IList, Is.Not.Null); + IList zs = (IList) ys; + Assert.That(zs[0], Is.EqualTo("Mark Pollack")); + } - [Test] - public void ConvertArrayListToGenericIEnumerable() - { - ArrayList xs = new ArrayList(); - xs.Add("Mark Pollack"); - object ys = TypeConversionUtils.ConvertValueIfNecessary(typeof(IEnumerable), xs, "ignored"); - Assert.That(ys as IEnumerable, Is.Not.Null); - IEnumerable zs = (IEnumerable)ys; - IEnumerator zse = zs.GetEnumerator(); - Assert.That(zse.MoveNext(), Is.True); - Assert.That(zse.Current, Is.EqualTo("Mark Pollack")); - } + [Test] + public void ConvertHybridDictionaryToGenericIDictionary() + { + HybridDictionary xs = new HybridDictionary(); + xs.Add("first", 1); + object ys = TypeConversionUtils.ConvertValueIfNecessary(typeof(IDictionary), xs, "ignored"); + Assert.That(ys as IDictionary, Is.Not.Null); + IDictionary zs = (IDictionary) ys; + Assert.That(zs["first"], Is.EqualTo(1)); + } + [Test] + public void ConvertArrayListToGenericIEnumerable() + { + ArrayList xs = new ArrayList(); + xs.Add("Mark Pollack"); + object ys = TypeConversionUtils.ConvertValueIfNecessary(typeof(IEnumerable), xs, "ignored"); + Assert.That(ys as IEnumerable, Is.Not.Null); + IEnumerable zs = (IEnumerable) ys; + IEnumerator zse = zs.GetEnumerator(); + Assert.That(zse.MoveNext(), Is.True); + Assert.That(zse.Current, Is.EqualTo("Mark Pollack")); } } diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/CollectionMergingGenericTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/CollectionMergingGenericTests.cs index 418dbc5c..1b71813f 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/CollectionMergingGenericTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/CollectionMergingGenericTests.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -25,38 +25,36 @@ using Spring.Objects.Factory.Support; #endregion -namespace Spring.Objects.Factory.Xml +namespace Spring.Objects.Factory.Xml; + +/// +/// Unit and integration tests for the collection merging support +/// +/// Rod Johnson +/// Rick Evans +/// Mark Pollack (.NET) +[TestFixture] +[Description("SPRNET-1242 Support for collection merging with generic collections")] +public class CollectionMergingGenericTests { - /// - /// Unit and integration tests for the collection merging support - /// - /// Rod Johnson - /// Rick Evans - /// Mark Pollack (.NET) - [TestFixture] - [Description("SPRNET-1242 Support for collection merging with generic collections")] - public class CollectionMergingGenericTests - { - private DefaultListableObjectFactory objectFactory; + private DefaultListableObjectFactory objectFactory; - [SetUp] - public void SetUp() - { - this.objectFactory = new DefaultListableObjectFactory(); - IObjectDefinitionReader reader = new XmlObjectDefinitionReader(this.objectFactory); - reader.LoadObjectDefinitions(new ReadOnlyXmlTestResource("collectionMergingGeneric.xml", GetType())); - } + [SetUp] + public void SetUp() + { + this.objectFactory = new DefaultListableObjectFactory(); + IObjectDefinitionReader reader = new XmlObjectDefinitionReader(this.objectFactory); + reader.LoadObjectDefinitions(new ReadOnlyXmlTestResource("collectionMergingGeneric.xml", GetType())); + } - [Test] - public void MergeList() - { - TestObject to = (TestObject) this.objectFactory.GetObject("childWithList"); - System.Collections.Generic.List list = to.SomeGenericStringList; - Assert.That(3, Is.EqualTo(list.Count)); - Assert.That("Rob Harrop", Is.EqualTo(list[0])); - Assert.That("Rod Johnson", Is.EqualTo(list[1])); - Assert.That("Juergen Hoeller", Is.EqualTo(list[2])); - } - - } + [Test] + public void MergeList() + { + TestObject to = (TestObject) this.objectFactory.GetObject("childWithList"); + System.Collections.Generic.List list = to.SomeGenericStringList; + Assert.That(3, Is.EqualTo(list.Count)); + Assert.That("Rob Harrop", Is.EqualTo(list[0])); + Assert.That("Rod Johnson", Is.EqualTo(list[1])); + Assert.That("Juergen Hoeller", Is.EqualTo(list[2])); + } } diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/CollectionMergingTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/CollectionMergingTests.cs index 5358d70c..0c083a9f 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/CollectionMergingTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/CollectionMergingTests.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -28,191 +28,188 @@ using Spring.Objects.Factory.Support; #endregion -namespace Spring.Objects.Factory.Xml +namespace Spring.Objects.Factory.Xml; + +/// +/// Unit and integration tests for the collection merging support +/// +/// Rod Johnson +/// Rick Evans +/// Mark Pollack (.NET) +[TestFixture] +public class CollectionMergingTests { - /// - /// Unit and integration tests for the collection merging support - /// - /// Rod Johnson - /// Rick Evans - /// Mark Pollack (.NET) - [TestFixture] - public class CollectionMergingTests - { - private DefaultListableObjectFactory objectFactory; + private DefaultListableObjectFactory objectFactory; - [SetUp] - public void SetUp() - { - this.objectFactory = new DefaultListableObjectFactory(); - IObjectDefinitionReader reader = new XmlObjectDefinitionReader(this.objectFactory); - reader.LoadObjectDefinitions(new ReadOnlyXmlTestResource("collectionMerging.xml", GetType())); - } + [SetUp] + public void SetUp() + { + this.objectFactory = new DefaultListableObjectFactory(); + IObjectDefinitionReader reader = new XmlObjectDefinitionReader(this.objectFactory); + reader.LoadObjectDefinitions(new ReadOnlyXmlTestResource("collectionMerging.xml", GetType())); + } - [Test] - public void MergeList() - { - TestObject to = (TestObject) this.objectFactory.GetObject("childWithList"); - IList list = to.SomeList; - Assert.That(3, Is.EqualTo(list.Count)); - Assert.That("Rob Harrop", Is.EqualTo(list[0])); - Assert.That("Rod Johnson", Is.EqualTo(list[1])); - Assert.That("Juergen Hoeller", Is.EqualTo(list[2])); - } + [Test] + public void MergeList() + { + TestObject to = (TestObject) this.objectFactory.GetObject("childWithList"); + IList list = to.SomeList; + Assert.That(3, Is.EqualTo(list.Count)); + Assert.That("Rob Harrop", Is.EqualTo(list[0])); + Assert.That("Rod Johnson", Is.EqualTo(list[1])); + Assert.That("Juergen Hoeller", Is.EqualTo(list[2])); + } - [Test] - public void MergListWithInnerObjectAsListElement() - { - TestObject to = (TestObject)this.objectFactory.GetObject("childWithListOfRefs"); - IList list = to.SomeList; - Assert.IsNotNull(list); - Assert.AreEqual(3, list.Count); - Assert.IsNotNull(list[2]); - Assert.That(list[2], Is.InstanceOf(typeof (TestObject))); - } + [Test] + public void MergListWithInnerObjectAsListElement() + { + TestObject to = (TestObject) this.objectFactory.GetObject("childWithListOfRefs"); + IList list = to.SomeList; + Assert.IsNotNull(list); + Assert.AreEqual(3, list.Count); + Assert.IsNotNull(list[2]); + Assert.That(list[2], Is.InstanceOf(typeof(TestObject))); + } - [Test] - public void MergeSet() - { - TestObject to = (TestObject)this.objectFactory.GetObject("childWithSet"); - ISet set = to.SomeSet; - Assert.AreEqual(2, set.Count); - Assert.IsTrue(set.Contains("Rob Harrop")); - Assert.IsTrue(set.Contains("Sally Greenwood")); - } + [Test] + public void MergeSet() + { + TestObject to = (TestObject) this.objectFactory.GetObject("childWithSet"); + ISet set = to.SomeSet; + Assert.AreEqual(2, set.Count); + Assert.IsTrue(set.Contains("Rob Harrop")); + Assert.IsTrue(set.Contains("Sally Greenwood")); + } - [Test] - public void MergeSetWithInnerObjectAsSetElement() - { - TestObject to = (TestObject)this.objectFactory.GetObject("childWithSetOfRefs"); - ISet set = to.SomeSet; - Assert.IsNotNull(set); - Assert.AreEqual(2, set.Count); - IEnumerator enumerator = set.GetEnumerator(); - enumerator.MoveNext(); - enumerator.MoveNext(); - object o = enumerator.Current; - Assert.IsNotNull(o); - Assert.That(o, Is.InstanceOf(typeof(TestObject))); - Assert.AreEqual("Sally", ((TestObject) o).Name); - } + [Test] + public void MergeSetWithInnerObjectAsSetElement() + { + TestObject to = (TestObject) this.objectFactory.GetObject("childWithSetOfRefs"); + ISet set = to.SomeSet; + Assert.IsNotNull(set); + Assert.AreEqual(2, set.Count); + IEnumerator enumerator = set.GetEnumerator(); + enumerator.MoveNext(); + enumerator.MoveNext(); + object o = enumerator.Current; + Assert.IsNotNull(o); + Assert.That(o, Is.InstanceOf(typeof(TestObject))); + Assert.AreEqual("Sally", ((TestObject) o).Name); + } - [Test] - public void MergeDictionary() - { - TestObject to = (TestObject)this.objectFactory.GetObject("childWithMap"); - IDictionary map = to.SomeMap; - Assert.AreEqual(3, map.Count); - Assert.AreEqual("Sally", map["Rob"]); - Assert.AreEqual("Kerry", map["Rod"]); - Assert.AreEqual("Eva", map["Juergen"]); - } + [Test] + public void MergeDictionary() + { + TestObject to = (TestObject) this.objectFactory.GetObject("childWithMap"); + IDictionary map = to.SomeMap; + Assert.AreEqual(3, map.Count); + Assert.AreEqual("Sally", map["Rob"]); + Assert.AreEqual("Kerry", map["Rod"]); + Assert.AreEqual("Eva", map["Juergen"]); + } - [Test] - public void MergeMapWithInnerObjectAsMapEntryValue() - { - TestObject to = (TestObject)this.objectFactory.GetObject("childWithMapOfRefs"); - IDictionary map = to.SomeMap; - Assert.NotNull(map); - Assert.AreEqual(2, map.Count); - Assert.NotNull(map["Rob"]); - Assert.That(map["Rob"], Is.InstanceOf(typeof(TestObject))); - Assert.AreEqual("Sally", ((TestObject) map["Rob"]).Name); - } + [Test] + public void MergeMapWithInnerObjectAsMapEntryValue() + { + TestObject to = (TestObject) this.objectFactory.GetObject("childWithMapOfRefs"); + IDictionary map = to.SomeMap; + Assert.NotNull(map); + Assert.AreEqual(2, map.Count); + Assert.NotNull(map["Rob"]); + Assert.That(map["Rob"], Is.InstanceOf(typeof(TestObject))); + Assert.AreEqual("Sally", ((TestObject) map["Rob"]).Name); + } - [Test] - public void MergeNameValueCollection() - { - TestObject to = (TestObject)this.objectFactory.GetObject("childWithNameValues"); - NameValueCollection map = to.SomeNameValueCollection; - Assert.AreEqual(3, map.Count); - Assert.AreEqual("Sally", map["Rob"]); - Assert.AreEqual("Kerry", map["Rod"]); - Assert.AreEqual("Eva", map["Juergen"]); - } + [Test] + public void MergeNameValueCollection() + { + TestObject to = (TestObject) this.objectFactory.GetObject("childWithNameValues"); + NameValueCollection map = to.SomeNameValueCollection; + Assert.AreEqual(3, map.Count); + Assert.AreEqual("Sally", map["Rob"]); + Assert.AreEqual("Kerry", map["Rod"]); + Assert.AreEqual("Eva", map["Juergen"]); + } - [Test] - public void MergeListInConstructor() - { - TestObject to = (TestObject)this.objectFactory.GetObject("childWithListInConstructor"); - IList list = to.SomeList; - Assert.AreEqual(3, list.Count); - Assert.AreEqual("Rob Harrop", list[0]); - Assert.AreEqual("Rod Johnson", list[1]); - Assert.AreEqual("Juergen Hoeller", list[2]); - } + [Test] + public void MergeListInConstructor() + { + TestObject to = (TestObject) this.objectFactory.GetObject("childWithListInConstructor"); + IList list = to.SomeList; + Assert.AreEqual(3, list.Count); + Assert.AreEqual("Rob Harrop", list[0]); + Assert.AreEqual("Rod Johnson", list[1]); + Assert.AreEqual("Juergen Hoeller", list[2]); + } - [Test] - public void MergeListWithInnerObjectAsListElementInConstructor() - { - TestObject to = (TestObject)this.objectFactory.GetObject("childWithListOfRefsInConstructor"); - IList list = to.SomeList; - Assert.IsNotNull(list); - Assert.AreEqual(3, list.Count); - Assert.IsNotNull(list[2]); - Assert.That(list[2], Is.InstanceOf(typeof(TestObject))); - } + [Test] + public void MergeListWithInnerObjectAsListElementInConstructor() + { + TestObject to = (TestObject) this.objectFactory.GetObject("childWithListOfRefsInConstructor"); + IList list = to.SomeList; + Assert.IsNotNull(list); + Assert.AreEqual(3, list.Count); + Assert.IsNotNull(list[2]); + Assert.That(list[2], Is.InstanceOf(typeof(TestObject))); + } - [Test] - public void MergeSetInConstructor() - { - TestObject to = (TestObject)this.objectFactory.GetObject("childWithSetInConstructor"); - ISet set = to.SomeSet; - Assert.AreEqual(2, set.Count); - Assert.IsTrue(set.Contains("Rob Harrop")); - Assert.IsTrue(set.Contains("Sally Greenwood")); - } + [Test] + public void MergeSetInConstructor() + { + TestObject to = (TestObject) this.objectFactory.GetObject("childWithSetInConstructor"); + ISet set = to.SomeSet; + Assert.AreEqual(2, set.Count); + Assert.IsTrue(set.Contains("Rob Harrop")); + Assert.IsTrue(set.Contains("Sally Greenwood")); + } - [Test] - public void MergeSetWithInnerObjectAsSetElementInConstructor() - { - TestObject to = (TestObject)this.objectFactory.GetObject("childWithSetOfRefsInConstructor"); - ISet set = to.SomeSet; - Assert.IsNotNull(set); - Assert.AreEqual(2, set.Count); - IEnumerator enumerator = set.GetEnumerator(); - enumerator.MoveNext(); - enumerator.MoveNext(); - object o = enumerator.Current; - Assert.IsNotNull(o); - Assert.That(o, Is.InstanceOf(typeof(TestObject))); - Assert.AreEqual("Sally", ((TestObject)o).Name); - } + [Test] + public void MergeSetWithInnerObjectAsSetElementInConstructor() + { + TestObject to = (TestObject) this.objectFactory.GetObject("childWithSetOfRefsInConstructor"); + ISet set = to.SomeSet; + Assert.IsNotNull(set); + Assert.AreEqual(2, set.Count); + IEnumerator enumerator = set.GetEnumerator(); + enumerator.MoveNext(); + enumerator.MoveNext(); + object o = enumerator.Current; + Assert.IsNotNull(o); + Assert.That(o, Is.InstanceOf(typeof(TestObject))); + Assert.AreEqual("Sally", ((TestObject) o).Name); + } - [Test] - public void MergeMapInConstructor() - { - TestObject to = (TestObject)this.objectFactory.GetObject("childWithMapInConstructor"); - IDictionary map = to.SomeMap; - Assert.AreEqual(3, map.Count); - Assert.AreEqual("Sally", map["Rob"]); - Assert.AreEqual("Kerry", map["Rod"]); - Assert.AreEqual("Eva", map["Juergen"]); - } + [Test] + public void MergeMapInConstructor() + { + TestObject to = (TestObject) this.objectFactory.GetObject("childWithMapInConstructor"); + IDictionary map = to.SomeMap; + Assert.AreEqual(3, map.Count); + Assert.AreEqual("Sally", map["Rob"]); + Assert.AreEqual("Kerry", map["Rod"]); + Assert.AreEqual("Eva", map["Juergen"]); + } - [Test] - public void MergeMapWithInnerObjectgAsMapEntryValueInConstructor() - { - TestObject to = (TestObject)this.objectFactory.GetObject("childWithMapOfRefsInConstructor"); - IDictionary map = to.SomeMap; - Assert.IsNotNull(map); - Assert.AreEqual(2, map.Count); - Assert.IsNotNull(map["Rob"]); - Assert.That(map["Rob"], Is.InstanceOf(typeof(TestObject))); - Assert.AreEqual("Sally", ((TestObject) map["Rob"]).Name); - - } + [Test] + public void MergeMapWithInnerObjectgAsMapEntryValueInConstructor() + { + TestObject to = (TestObject) this.objectFactory.GetObject("childWithMapOfRefsInConstructor"); + IDictionary map = to.SomeMap; + Assert.IsNotNull(map); + Assert.AreEqual(2, map.Count); + Assert.IsNotNull(map["Rob"]); + Assert.That(map["Rob"], Is.InstanceOf(typeof(TestObject))); + Assert.AreEqual("Sally", ((TestObject) map["Rob"]).Name); + } - [Test] - public void MergeNameValueCollectionInConstructor() - { - TestObject to = (TestObject)this.objectFactory.GetObject("childWithPropsInConstructor"); - NameValueCollection props = to.SomeNameValueCollection; - Assert.AreEqual(3, props.Count); - Assert.AreEqual("Sally", props["Rob"]); - Assert.AreEqual("Kerry", props["Rod"]); - Assert.AreEqual("Eva", props["Juergen"]); - - } - } -} \ No newline at end of file + [Test] + public void MergeNameValueCollectionInConstructor() + { + TestObject to = (TestObject) this.objectFactory.GetObject("childWithPropsInConstructor"); + NameValueCollection props = to.SomeNameValueCollection; + Assert.AreEqual(3, props.Count); + Assert.AreEqual("Sally", props["Rob"]); + Assert.AreEqual("Kerry", props["Rod"]); + Assert.AreEqual("Eva", props["Juergen"]); + } +} diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/ConstructorDependenciesObject.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/ConstructorDependenciesObject.cs index 6e70a969..2d1b50de 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/ConstructorDependenciesObject.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/ConstructorDependenciesObject.cs @@ -20,91 +20,88 @@ #region Imports - - #endregion -namespace Spring.Objects.Factory.Xml +namespace Spring.Objects.Factory.Xml; + +/// +/// Simple object used to check constructor dependency checking. +/// +/// Juergen Hoeller +/// Rick Evans (.NET) +public class ConstructorDependenciesObject { - /// - /// Simple object used to check constructor dependency checking. - /// - /// Juergen Hoeller - /// Rick Evans (.NET) - public class ConstructorDependenciesObject - { - #region Constructor (s) / Destructor + #region Constructor (s) / Destructor - public ConstructorDependenciesObject(int age) - { - this.age = age; - } + public ConstructorDependenciesObject(int age) + { + this.age = age; + } - public ConstructorDependenciesObject(string name) - { - this.name = name; - } + public ConstructorDependenciesObject(string name) + { + this.name = name; + } - public ConstructorDependenciesObject(ITestObject spouse1) - { - this.spouse1 = spouse1; - } + public ConstructorDependenciesObject(ITestObject spouse1) + { + this.spouse1 = spouse1; + } - public ConstructorDependenciesObject(ITestObject spouse1, ITestObject spouse2) - { - this.spouse1 = spouse1; - this.spouse2 = spouse2; - } + public ConstructorDependenciesObject(ITestObject spouse1, ITestObject spouse2) + { + this.spouse1 = spouse1; + this.spouse2 = spouse2; + } - public ConstructorDependenciesObject(ITestObject spouse1, ITestObject spouse2, IndexedTestObject other) - { - this.spouse1 = spouse1; - this.spouse2 = spouse2; - this.other = other; - } + public ConstructorDependenciesObject(ITestObject spouse1, ITestObject spouse2, IndexedTestObject other) + { + this.spouse1 = spouse1; + this.spouse2 = spouse2; + this.other = other; + } - #endregion + #endregion - #region Properties + #region Properties - public int Age - { - get { return age; } + public int Age + { + get { return age; } - set { this.age = value; } - } + set { this.age = value; } + } - public string Name - { - get { return name; } - set { this.name = value; } - } + public string Name + { + get { return name; } + set { this.name = value; } + } - public ITestObject Spouse1 - { - get { return spouse1; } - } + public ITestObject Spouse1 + { + get { return spouse1; } + } - public ITestObject Spouse2 - { - get { return spouse2; } - } + public ITestObject Spouse2 + { + get { return spouse2; } + } - public IndexedTestObject Other - { - get { return other; } - } + public IndexedTestObject Other + { + get { return other; } + } - #endregion + #endregion - #region Fields + #region Fields - private int age; - private string name; - private ITestObject spouse1; - private ITestObject spouse2; - private IndexedTestObject other; + private int age; + private string name; + private ITestObject spouse1; + private ITestObject spouse2; + private IndexedTestObject other; - #endregion - } + #endregion } \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/DependenciesObject.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/DependenciesObject.cs index d0a8e9b6..43ea85db 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/DependenciesObject.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/DependenciesObject.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -20,58 +20,55 @@ #region Imports - - #endregion -namespace Spring.Objects.Factory.Xml +namespace Spring.Objects.Factory.Xml; + +/// +/// Simple object used to check dependency checking. +/// +/// Rod Johnson +/// Rick Evans (.NET) +public class DependenciesObject { - /// - /// Simple object used to check dependency checking. - /// - /// Rod Johnson - /// Rick Evans (.NET) - public class DependenciesObject - { - #region Constructor (s) / Destructor + #region Constructor (s) / Destructor - /// - /// Creates a new instance of the DependenciesObject class. - /// - public DependenciesObject() - { - } + /// + /// Creates a new instance of the DependenciesObject class. + /// + public DependenciesObject() + { + } - #endregion + #endregion - #region Properties + #region Properties - public int Age - { - get { return age; } - set { this.age = value; } - } + public int Age + { + get { return age; } + set { this.age = value; } + } - public string Name - { - get { return name; } - set { this.name = value; } - } + public string Name + { + get { return name; } + set { this.name = value; } + } - public ITestObject Spouse - { - get { return spouse; } - set { this.spouse = value; } - } + public ITestObject Spouse + { + get { return spouse; } + set { this.spouse = value; } + } - #endregion + #endregion - #region Fields + #region Fields - private int age; - private string name; - private ITestObject spouse; + private int age; + private string name; + private ITestObject spouse; - #endregion - } -} \ No newline at end of file + #endregion +} diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/DerivedConstructorDependenciesObject.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/DerivedConstructorDependenciesObject.cs index 795ff07a..8e0e6db7 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/DerivedConstructorDependenciesObject.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/DerivedConstructorDependenciesObject.cs @@ -20,44 +20,40 @@ #region Imports - - #endregion -namespace Spring.Objects.Factory.Xml +namespace Spring.Objects.Factory.Xml; + +/// +/// Simple object used to check derived constructor dependency checking. +/// +/// Juergen Hoeller +/// Rick Evans (.NET) +public class DerivedConstructorDependenciesObject : ConstructorDependenciesObject { - /// - /// Simple object used to check derived constructor dependency checking. - /// - /// Juergen Hoeller - /// Rick Evans (.NET) - public class DerivedConstructorDependenciesObject : ConstructorDependenciesObject - { + public DerivedConstructorDependenciesObject( + ITestObject spouse1, ITestObject spouse2, IndexedTestObject other) + : base(spouse1, spouse2, other) + { + } - public DerivedConstructorDependenciesObject( - ITestObject spouse1, ITestObject spouse2, IndexedTestObject other) - : base(spouse1, spouse2, other) - { - } + public DerivedConstructorDependenciesObject( + ITestObject spouse1, object spouse2, IndexedTestObject other) + : base(spouse1, null, other) + { + } - public DerivedConstructorDependenciesObject( - ITestObject spouse1, object spouse2, IndexedTestObject other) - : base(spouse1, null, other) - { - } + public DerivedConstructorDependenciesObject( + ITestObject spouse1, ITestObject spouse2, IndexedTestObject other, int age, int otherAge) + : base(spouse1, spouse2, other) + { + } - public DerivedConstructorDependenciesObject( - ITestObject spouse1, ITestObject spouse2, IndexedTestObject other, int age, int otherAge) - : base(spouse1, spouse2, other) - { - } - - public DerivedConstructorDependenciesObject( - ITestObject spouse1, ITestObject spouse2, IndexedTestObject other, int age, string name) - : base(spouse1, spouse2, other) - { - Age = age; - Name = name; - } - } -} \ No newline at end of file + public DerivedConstructorDependenciesObject( + ITestObject spouse1, ITestObject spouse2, IndexedTestObject other, int age, string name) + : base(spouse1, spouse2, other) + { + Age = age; + Name = name; + } +} diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/DoubleBooleanConstructorObject.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/DoubleBooleanConstructorObject.cs index 9a6ced62..912d69aa 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/DoubleBooleanConstructorObject.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/DoubleBooleanConstructorObject.cs @@ -18,32 +18,31 @@ #endregion -namespace Spring.Objects.Factory.Xml +namespace Spring.Objects.Factory.Xml; + +/// +/// Summary description for DoubleBooleanConstructorObject. +/// +public class DoubleBooleanConstructorObject { - /// - /// Summary description for DoubleBooleanConstructorObject. - /// - public class DoubleBooleanConstructorObject - { - private bool boolean1; - private bool boolean2; + private bool boolean1; + private bool boolean2; - public bool Boolean2 - { - get { return this.boolean2; } - set { this.boolean2 = value; } - } + public bool Boolean2 + { + get { return this.boolean2; } + set { this.boolean2 = value; } + } - public bool Boolean1 - { - get { return this.boolean1; } - set { this.boolean1 = value; } - } + public bool Boolean1 + { + get { return this.boolean1; } + set { this.boolean1 = value; } + } - public DoubleBooleanConstructorObject(bool b1, bool b2) - { - this.boolean1 = b1; - this.boolean2 = b2; - } - } + public DoubleBooleanConstructorObject(bool b1, bool b2) + { + this.boolean1 = b1; + this.boolean2 = b2; + } } \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/DummyBo.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/DummyBo.cs index 4641e9eb..a7f7f1cf 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/DummyBo.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/DummyBo.cs @@ -20,32 +20,28 @@ #region Imports - - #endregion -namespace Spring.Objects.Factory.Xml { +namespace Spring.Objects.Factory.Xml; - /// - /// Summary description for DummyBo. +/// +/// Summary description for DummyBo. +/// +/// Rod Johnson +/// Rick Evans (.NET) +public class DummyBo : IDummyBo +{ + /// + /// Creates a new instance of the DummyBo class. /// - /// Rod Johnson - /// Rick Evans (.NET) - public class DummyBo : IDummyBo + public DummyBo(DummyDao dao) { + this.dao = dao; + } - /// - /// Creates a new instance of the DummyBo class. - /// - public DummyBo (DummyDao dao) { - this.dao = dao; - } + public void DoSomething() + { + } - public void DoSomething () - { - - } - - internal DummyDao dao; - } + internal DummyDao dao; } diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/DummyDao.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/DummyDao.cs index 6c66630e..b3078c7e 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/DummyDao.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/DummyDao.cs @@ -20,24 +20,21 @@ #region Imports - - #endregion -namespace Spring.Objects.Factory.Xml { +namespace Spring.Objects.Factory.Xml; - /// - /// Summary description for DummyDao. +/// +/// Summary description for DummyDao. +/// +/// Rod Johnson +/// Rick Evans (.NET) +public class DummyDao +{ + /// + /// Creates a new instance of the DummyDao class. /// - /// Rod Johnson - /// Rick Evans (.NET) - public class DummyDao + public DummyDao() { - - /// - /// Creates a new instance of the DummyDao class. - /// - public DummyDao () { - } - } + } } diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/DummyReferencer.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/DummyReferencer.cs index 98cba165..1c26550e 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/DummyReferencer.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/DummyReferencer.cs @@ -20,45 +20,41 @@ #region Imports - - #endregion -namespace Spring.Objects.Factory.Xml { +namespace Spring.Objects.Factory.Xml; - /// - /// Summary description for DummyReferencer. - /// - /// Juergen Hoeller - /// Rick Evans (.NET) - public class DummyReferencer +/// +/// Summary description for DummyReferencer. +/// +/// Juergen Hoeller +/// Rick Evans (.NET) +public class DummyReferencer +{ + public ITestObject TestObject1 { - - public ITestObject TestObject1 + get { - get - { - return testObject1; - } - set - { - this.testObject1 = value; - } + return testObject1; } - - public ITestObject TestObject2 + set { - get - { - return testObject2; - } - set - { - this.testObject2 = value; - } + this.testObject1 = value; } - - private ITestObject testObject1; - private ITestObject testObject2; - } + } + + public ITestObject TestObject2 + { + get + { + return testObject2; + } + set + { + this.testObject2 = value; + } + } + + private ITestObject testObject1; + private ITestObject testObject2; } diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/EventWiringTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/EventWiringTests.cs index 17bf2be8..f63491cf 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/EventWiringTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/EventWiringTests.cs @@ -25,79 +25,78 @@ using Spring.Objects.Factory.Support; #endregion -namespace Spring.Objects.Factory.Xml +namespace Spring.Objects.Factory.Xml; + +/// +/// Unit tests that test the event wiring features of the +/// XmlObjectFactory. +/// +/// Juergen Hoeller +/// Rick Evans (.NET) +/// Choy Rim (.NET) +[TestFixture] +public class EventWiringTests { - /// - /// Unit tests that test the event wiring features of the - /// XmlObjectFactory. - /// - /// Juergen Hoeller - /// Rick Evans (.NET) - /// Choy Rim (.NET) - [TestFixture] - public class EventWiringTests + [Ignore("SPRNET-21")] + [Test] + public virtual void EventWiringInstanceSinkToPrototypeSource() { - [Ignore("SPRNET-21")] - [Test] - public virtual void EventWiringInstanceSinkToPrototypeSource() - { - DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); - XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(factory); - reader.LoadObjectDefinitions(new ReadOnlyXmlTestResource("event-wiring-prototypes.xml", GetType())); - TestEventHandler instanceHandler = factory["instanceSink"] as TestEventHandler; - ITestObject source = factory["source"] as ITestObject; - // raise the event... handlers should be notified at this point (obviously) - source.OnClick(); - Assert.IsTrue(instanceHandler.EventWasHandled, - "The instance handler did not get notified when the instance event was raised (and was probably not wired up in the first place)."); - } - - [Test] - public virtual void SingletonSourcePrototypeSink() - { - DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); - XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(factory); - reader.LoadObjectDefinitions(new ReadOnlyXmlTestResource("event-wiring.xml", GetType())); - ITestObject source = factory["source"] as ITestObject; - TestEventHandler prototypeEventHandler = factory["prototypeEventListener"] as TestEventHandler; - // raise the event... handlers should be notified at this point (obviously) - source.OnClick(); - Assert.IsTrue(prototypeEventHandler.EventWasHandled, - "The prototype instance handler did not get notified when the instance event was raised (and was probably not wired up in the first place)."); - } - - [Test] - public virtual void InstanceEventWiring() - { - DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); - XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(factory); - reader.LoadObjectDefinitions(new ReadOnlyXmlTestResource("event-wiring.xml", GetType())); - ITestObject source = factory["source"] as ITestObject; - TestEventHandler instanceHandler = factory["instanceEventListener"] as TestEventHandler; - // raise the event... handlers should be notified at this point (obviously) - source.OnClick(); - Assert.IsTrue(instanceHandler.EventWasHandled, - "The instance handler did not get notified when the instance event was raised (and was probably not wired up in the first place)."); - } - - [Test] - public virtual void StaticEventWiring() - { - DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); - XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(factory); - reader.LoadObjectDefinitions(new ReadOnlyXmlTestResource("event-wiring.xml", GetType())); - TestEventHandler staticHandler = factory["staticEventListener"] as TestEventHandler; - // raise the event... handlers should be notified at this point (obviously) - TestObject.OnStaticClick(); - Assert.IsTrue(staticHandler.EventWasHandled, - "The instance handler did not get notified when the static event was raised (and was probably not wired up in the first place)."); - } - - [OneTimeSetUp] - public void FixtureSetUp() - { - // enable (null appender) logging, to ensure that the logging code is exercised - // XmlConfigurator.Configure (); - } + DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); + XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(factory); + reader.LoadObjectDefinitions(new ReadOnlyXmlTestResource("event-wiring-prototypes.xml", GetType())); + TestEventHandler instanceHandler = factory["instanceSink"] as TestEventHandler; + ITestObject source = factory["source"] as ITestObject; + // raise the event... handlers should be notified at this point (obviously) + source.OnClick(); + Assert.IsTrue(instanceHandler.EventWasHandled, + "The instance handler did not get notified when the instance event was raised (and was probably not wired up in the first place)."); } -} \ No newline at end of file + + [Test] + public virtual void SingletonSourcePrototypeSink() + { + DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); + XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(factory); + reader.LoadObjectDefinitions(new ReadOnlyXmlTestResource("event-wiring.xml", GetType())); + ITestObject source = factory["source"] as ITestObject; + TestEventHandler prototypeEventHandler = factory["prototypeEventListener"] as TestEventHandler; + // raise the event... handlers should be notified at this point (obviously) + source.OnClick(); + Assert.IsTrue(prototypeEventHandler.EventWasHandled, + "The prototype instance handler did not get notified when the instance event was raised (and was probably not wired up in the first place)."); + } + + [Test] + public virtual void InstanceEventWiring() + { + DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); + XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(factory); + reader.LoadObjectDefinitions(new ReadOnlyXmlTestResource("event-wiring.xml", GetType())); + ITestObject source = factory["source"] as ITestObject; + TestEventHandler instanceHandler = factory["instanceEventListener"] as TestEventHandler; + // raise the event... handlers should be notified at this point (obviously) + source.OnClick(); + Assert.IsTrue(instanceHandler.EventWasHandled, + "The instance handler did not get notified when the instance event was raised (and was probably not wired up in the first place)."); + } + + [Test] + public virtual void StaticEventWiring() + { + DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); + XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(factory); + reader.LoadObjectDefinitions(new ReadOnlyXmlTestResource("event-wiring.xml", GetType())); + TestEventHandler staticHandler = factory["staticEventListener"] as TestEventHandler; + // raise the event... handlers should be notified at this point (obviously) + TestObject.OnStaticClick(); + Assert.IsTrue(staticHandler.EventWasHandled, + "The instance handler did not get notified when the static event was raised (and was probably not wired up in the first place)."); + } + + [OneTimeSetUp] + public void FixtureSetUp() + { + // enable (null appender) logging, to ensure that the logging code is exercised + // XmlConfigurator.Configure (); + } +} diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/FactoryMethods.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/FactoryMethods.cs index 36d909ea..bdcdea8a 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/FactoryMethods.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/FactoryMethods.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -20,94 +20,91 @@ #region Imports - - #endregion -namespace Spring.Objects.Factory.Xml +namespace Spring.Objects.Factory.Xml; + +/// +/// Test class for Spring.NET's ability to create objects using static +/// factory methods, rather than constructors. +/// +/// Rod Johnson +/// Rick Evans (.NET) +public class FactoryMethods { - /// - /// Test class for Spring.NET's ability to create objects using static - /// factory methods, rather than constructors. - /// - /// Rod Johnson - /// Rick Evans (.NET) - public class FactoryMethods - { - #region Constructor (s) / Destructor + #region Constructor (s) / Destructor - /// - /// Creates a new instance of the - /// class. - /// - /// - ///

- /// Constructor is private: not for use outside this class, even by the IoC container. - ///

- ///
- private FactoryMethods(TestObject obj, string name, int number) - { - _object = obj; - _name = name; - _number = number; - } + /// + /// Creates a new instance of the + /// class. + /// + /// + ///

+ /// Constructor is private: not for use outside this class, even by the IoC container. + ///

+ ///
+ private FactoryMethods(TestObject obj, string name, int number) + { + _object = obj; + _name = name; + _number = number; + } - #endregion + #endregion - #region Properties + #region Properties - public TestObject Object - { - get { return _object; } - } + public TestObject Object + { + get { return _object; } + } - public string Name - { - get { return _name; } - set { _name = value; } - } + public string Name + { + get { return _name; } + set { _name = value; } + } - public string Value - { - get { return _value; } - set { _value = value; } - } + public string Value + { + get { return _value; } + set { _value = value; } + } - public int Number - { - get { return _number; } - } + public int Number + { + get { return _number; } + } - #endregion + #endregion - #region Methods + #region Methods - public static FactoryMethods DefaultInstance() - { - TestObject obj = new TestObject(); - obj.Name = "defaultInstance"; - return new FactoryMethods(obj, "default", 0); - } + public static FactoryMethods DefaultInstance() + { + TestObject obj = new TestObject(); + obj.Name = "defaultInstance"; + return new FactoryMethods(obj, "default", 0); + } - public static FactoryMethods NewInstance(TestObject obj) - { - return new FactoryMethods(obj, "default", 0); - } + public static FactoryMethods NewInstance(TestObject obj) + { + return new FactoryMethods(obj, "default", 0); + } - public static FactoryMethods NewInstance(TestObject obj, string name, int num) - { - return new FactoryMethods(obj, name, num); - } + public static FactoryMethods NewInstance(TestObject obj, string name, int num) + { + return new FactoryMethods(obj, name, num); + } - #endregion + #endregion - #region Fields + #region Fields - private int _number; - private TestObject _object; - private string _name = "default"; - private string _value; + private int _number; + private TestObject _object; + private string _name = "default"; + private string _value; - #endregion - } -} \ No newline at end of file + #endregion +} diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/IDummyBo.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/IDummyBo.cs index 47541184..c9810c76 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/IDummyBo.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/IDummyBo.cs @@ -20,20 +20,16 @@ #region Imports - - #endregion -namespace Spring.Objects.Factory.Xml { +namespace Spring.Objects.Factory.Xml; - /// - /// A dummy business object interface :D - /// - /// Rod Johnson - /// Rick Evans (.NET) - public interface IDummyBo - { - - void DoSomething (); - } +/// +/// A dummy business object interface :D +/// +/// Rod Johnson +/// Rick Evans (.NET) +public interface IDummyBo +{ + void DoSomething(); } diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/InstanceFactory.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/InstanceFactory.cs index 28aa8435..a42f0eff 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/InstanceFactory.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/InstanceFactory.cs @@ -24,65 +24,62 @@ using System.Data; #endregion -namespace Spring.Objects.Factory.Xml +namespace Spring.Objects.Factory.Xml; + +/// +/// Test class for Spring.NET's ability to create objects using static +/// factory methods, rather than constructors. +/// +/// Rod Johnson +/// Rick Evans +public class InstanceFactory { - /// - /// Test class for Spring.NET's ability to create objects using static - /// factory methods, rather than constructors. - /// - /// Rod Johnson - /// Rick Evans - public class InstanceFactory + private string _factoryObjectProperty; + + public string FactoryObjectProperty { - private string _factoryObjectProperty; - - public string FactoryObjectProperty + get { - get - { - return _factoryObjectProperty; + return _factoryObjectProperty; + } + set + { + _factoryObjectProperty = value; + } + } - } - set - { - _factoryObjectProperty = value; - } - } - - public FactoryMethods DefaultInstance() - { - TestObject to = new TestObject(); - to.Name = FactoryObjectProperty; - return FactoryMethods.NewInstance (to); - } + public FactoryMethods DefaultInstance() + { + TestObject to = new TestObject(); + to.Name = FactoryObjectProperty; + return FactoryMethods.NewInstance(to); + } - /// - /// Note that overloaded methods are supported. - /// - public FactoryMethods NewInstance (TestObject to) - { - return FactoryMethods.NewInstance (to); - } - - public FactoryMethods NewInstance (TestObject to, int num, string name) - { - return FactoryMethods.NewInstance (to, name, num); - } + /// + /// Note that overloaded methods are supported. + /// + public FactoryMethods NewInstance(TestObject to) + { + return FactoryMethods.NewInstance(to); + } - public FactoryMethods CreateInstance() - { - return FactoryMethods.NewInstance(new TestObject(), "DefaultCtor", 0); - } + public FactoryMethods NewInstance(TestObject to, int num, string name) + { + return FactoryMethods.NewInstance(to, name, num); + } - public FactoryMethods CreateInstance(DataRow dr) - { - return FactoryMethods.NewInstance(new TestObject(), "DataRowCtor", 0); - } + public FactoryMethods CreateInstance() + { + return FactoryMethods.NewInstance(new TestObject(), "DefaultCtor", 0); + } - public FactoryMethods CreateInstance(IDataRecord dr) - { - return FactoryMethods.NewInstance(new TestObject(), "DataRecordCtor", 0); - } + public FactoryMethods CreateInstance(DataRow dr) + { + return FactoryMethods.NewInstance(new TestObject(), "DataRowCtor", 0); + } - } + public FactoryMethods CreateInstance(IDataRecord dr) + { + return FactoryMethods.NewInstance(new TestObject(), "DataRecordCtor", 0); + } } diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/LocaleTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/LocaleTests.cs index 5642f68b..fd03fc2a 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/LocaleTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/LocaleTests.cs @@ -26,44 +26,41 @@ using Spring.Core.IO; #endregion -namespace Spring.Objects.Factory.Xml +namespace Spring.Objects.Factory.Xml; + +/// +/// This class contains tests for setting properties that do not parse easily in other locales, such +/// as comma delimited strings. +/// +/// Mark Pollack +[TestFixture] +public class LocaleTests { - /// - /// This class contains tests for setting properties that do not parse easily in other locales, such - /// as comma delimited strings. - /// - /// Mark Pollack - [TestFixture] - public class LocaleTests + [SetUp] + public void Setup() { - [SetUp] - public void Setup() - { - } - - [Test] - public void LocaleTest() - { - CultureInfo oldCulture = Thread.CurrentThread.CurrentCulture; - try - { - Thread.CurrentThread.CurrentCulture = new CultureInfo("fr-FR"); - - IResource resource = new ReadOnlyXmlTestResource("locale.xml", GetType()); - XmlObjectFactory xof = new XmlObjectFactory(resource); - TestObject to = xof.GetObject("jenny") as TestObject; - Assert.IsNotNull(to); - DateTime d = new DateTime(2007, 10, 30); - Assert.AreEqual(d, to.Date); - Assert.AreEqual(30, to.Size.Height); - Assert.AreEqual(30, to.Size.Width); - } - finally - { - Thread.CurrentThread.CurrentCulture = oldCulture; - } - } - - } -} \ No newline at end of file + + [Test] + public void LocaleTest() + { + CultureInfo oldCulture = Thread.CurrentThread.CurrentCulture; + try + { + Thread.CurrentThread.CurrentCulture = new CultureInfo("fr-FR"); + + IResource resource = new ReadOnlyXmlTestResource("locale.xml", GetType()); + XmlObjectFactory xof = new XmlObjectFactory(resource); + TestObject to = xof.GetObject("jenny") as TestObject; + Assert.IsNotNull(to); + DateTime d = new DateTime(2007, 10, 30); + Assert.AreEqual(d, to.Date); + Assert.AreEqual(30, to.Size.Height); + Assert.AreEqual(30, to.Size.Width); + } + finally + { + Thread.CurrentThread.CurrentCulture = oldCulture; + } + } +} diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/MixedCollectionObject.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/MixedCollectionObject.cs index bb67c773..108a6a29 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/MixedCollectionObject.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/MixedCollectionObject.cs @@ -24,40 +24,38 @@ using System.Collections; #endregion -namespace Spring.Objects.Factory.Xml { +namespace Spring.Objects.Factory.Xml; - /// - /// Summary description for MixedCollectionObject. - /// - /// Rod Johnson - /// Rick Evans (.NET) - public class MixedCollectionObject +/// +/// Summary description for MixedCollectionObject. +/// +/// Rod Johnson +/// Rick Evans (.NET) +public class MixedCollectionObject +{ + public MixedCollectionObject() { + ++nrOfInstances; + } - public MixedCollectionObject () + public ICollection Jumble + { + get { - ++nrOfInstances; + return jumble; } + set + { + this.jumble = value; + } + } - public ICollection Jumble - { - get - { - return jumble; - } - set - { - this.jumble = value; - } - } - - protected internal static int nrOfInstances = 0; - - public static void ResetStaticState () - { - nrOfInstances = 0; - } - - private ICollection jumble; - } + protected internal static int nrOfInstances = 0; + + public static void ResetStaticState() + { + nrOfInstances = 0; + } + + private ICollection jumble; } diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/NamespaceParserRegistryTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/NamespaceParserRegistryTests.cs index 5c2f3f4c..179e6b56 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/NamespaceParserRegistryTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/NamespaceParserRegistryTests.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -28,58 +28,57 @@ using Spring.Util; #endregion -namespace Spring.Objects.Factory.Xml +namespace Spring.Objects.Factory.Xml; + +/// +/// +/// +/// Erich Eichinger +[TestFixture] +public class NamespaceParserRegistryTests { - /// - /// - /// - /// Erich Eichinger - [TestFixture] - public class NamespaceParserRegistryTests + private class TestNamespaceParser : INamespaceParser { - private class TestNamespaceParser : INamespaceParser + public void Init() { - public void Init() - { - } - - public IObjectDefinition ParseElement(XmlElement element, ParserContext parserContext) - { - throw new System.NotImplementedException(); - } - - public ObjectDefinitionHolder Decorate(XmlNode node, ObjectDefinitionHolder definition, ParserContext parserContext) - { - throw new System.NotImplementedException(); - } } - [SetUp] - public void SetUp() + public IObjectDefinition ParseElement(XmlElement element, ParserContext parserContext) { - NamespaceParserRegistry.Reset(); + throw new System.NotImplementedException(); } - [TearDown] - public void TearDown() + public ObjectDefinitionHolder Decorate(XmlNode node, ObjectDefinitionHolder definition, ParserContext parserContext) { - NamespaceParserRegistry.Reset(); - } - - /// - /// This test doesn't work on .NET 1.0 because there are no XmlResolvers for schema loading... - /// - [Test] - public void CanLoadSchemaImportingOtherSchemaByRelativePath() - { - string schemaLocation = TestResourceLoader.GetAssemblyResourceUri( this.GetType(), "NamespaceParserRegistryTests_TestSchema.xsd" ); - NamespaceParserRegistry.RegisterParser(new TestNamespaceParser(), "http://www.example.com/brief", schemaLocation); - XmlReader vr = XmlUtils.CreateValidatingReader( new StringResource( - @" - - ").InputStream, NamespaceParserRegistry.GetSchemas(), null); - ConfigXmlDocument newDoc = new ConfigXmlDocument(); - newDoc.Load(vr); + throw new System.NotImplementedException(); } } -} \ No newline at end of file + + [SetUp] + public void SetUp() + { + NamespaceParserRegistry.Reset(); + } + + [TearDown] + public void TearDown() + { + NamespaceParserRegistry.Reset(); + } + + /// + /// This test doesn't work on .NET 1.0 because there are no XmlResolvers for schema loading... + /// + [Test] + public void CanLoadSchemaImportingOtherSchemaByRelativePath() + { + string schemaLocation = TestResourceLoader.GetAssemblyResourceUri(this.GetType(), "NamespaceParserRegistryTests_TestSchema.xsd"); + NamespaceParserRegistry.RegisterParser(new TestNamespaceParser(), "http://www.example.com/brief", schemaLocation); + XmlReader vr = XmlUtils.CreateValidatingReader(new StringResource( + @" + + ").InputStream, NamespaceParserRegistry.GetSchemas(), null); + ConfigXmlDocument newDoc = new ConfigXmlDocument(); + newDoc.Load(vr); + } +} diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/NamespaceParserRegistryTests_TestSchema.xsd b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/NamespaceParserRegistryTests_TestSchema.xsd index 3eb08fdb..1d041e1d 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/NamespaceParserRegistryTests_TestSchema.xsd +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/NamespaceParserRegistryTests_TestSchema.xsd @@ -1,19 +1,20 @@ + xmlns:brief="http://www.example.com/brief" + xmlns:ex="http://www.example.com/common" + xmlns:xsd="http://www.w3.org/2001/XMLSchema" + elementFormDefault="qualified" + attributeFormDefault="unqualified"> - + - - + + - + diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/NamespaceParserRegistryTests_TestSchema_2.xsd b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/NamespaceParserRegistryTests_TestSchema_2.xsd index 650f07f7..d47191d4 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/NamespaceParserRegistryTests_TestSchema_2.xsd +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/NamespaceParserRegistryTests_TestSchema_2.xsd @@ -1,11 +1,11 @@ + xmlns:xsd="http://www.w3.org/2001/XMLSchema" + elementFormDefault="qualified" + attributeFormDefault="unqualified"> - - - - + + + + diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/NullAppender.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/NullAppender.cs index b949dc27..ab2a66ce 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/NullAppender.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/NullAppender.cs @@ -20,23 +20,20 @@ #region Imports - - #endregion -namespace Spring.Objects.Factory.Xml +namespace Spring.Objects.Factory.Xml; + +/// +/// A log4Net appender that does nothing (by intention). +/// +/// Rick Evans +public sealed class NullAppender //: AppenderSkeleton { - /// - /// A log4Net appender that does nothing (by intention). - /// - /// Rick Evans - public sealed class NullAppender //: AppenderSkeleton + /* + protected override void Append(log4net.Core.LoggingEvent loggingEvent) { - /* - protected override void Append(log4net.Core.LoggingEvent loggingEvent) - { - // an explicit no-op - } - */ - } + // an explicit no-op + } + */ } diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/ObjectFactorySectionHandlerTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/ObjectFactorySectionHandlerTests.cs index f018e5d6..d5ee32c1 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/ObjectFactorySectionHandlerTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/ObjectFactorySectionHandlerTests.cs @@ -25,47 +25,45 @@ using NUnit.Framework; #endregion -namespace Spring.Objects.Factory.Xml +namespace Spring.Objects.Factory.Xml; + +/// +/// Test the usage of the ObjectFactorySectionHandler. +/// +[TestFixture] +public class ObjectFactorySectionHandlerTests { + private XmlElement _xmlElement; + + [SetUp] + public void CreateXmlElement() + { + XmlDocument xmlDoc = new XmlDocument(); + string xmlData = ""; + xmlDoc.Load(new StringReader(xmlData)); + _xmlElement = xmlDoc.DocumentElement; + } + /// - /// Test the usage of the ObjectFactorySectionHandler. + /// Test calling the section handler with null values. /// - [TestFixture] - public class ObjectFactorySectionHandlerTests - { - private XmlElement _xmlElement; + [Test] + public void CreateFactoryUnSuccessful() + { + ObjectFactorySectionHandler objHandler = new ObjectFactorySectionHandler(); + Assert.Throws(() => objHandler.Create(null, null, null)); + } - [SetUp] - public void CreateXmlElement() - { - XmlDocument xmlDoc = new XmlDocument(); - string xmlData = ""; - xmlDoc.Load(new StringReader(xmlData)); - _xmlElement = xmlDoc.DocumentElement; - } - - /// - /// Test calling the section handler with null values. - /// - [Test] - public void CreateFactoryUnSuccessful() - { - ObjectFactorySectionHandler objHandler = new ObjectFactorySectionHandler(); - Assert.Throws(() => objHandler.Create(null, null, null)); - } - - /// - /// Test calling the section handler with valid XML and make sure no - /// exception occurs and the factory has the right number of - /// objects. - /// - [Test] - public void CreateFactorySuccessful() - { - ObjectFactorySectionHandler objHandler = new ObjectFactorySectionHandler(); - IListableObjectFactory factory = (IListableObjectFactory)objHandler.Create( null, null, _xmlElement ); - Assert.AreEqual(1, factory.ObjectDefinitionCount); - - } - } + /// + /// Test calling the section handler with valid XML and make sure no + /// exception occurs and the factory has the right number of + /// objects. + /// + [Test] + public void CreateFactorySuccessful() + { + ObjectFactorySectionHandler objHandler = new ObjectFactorySectionHandler(); + IListableObjectFactory factory = (IListableObjectFactory) objHandler.Create(null, null, _xmlElement); + Assert.AreEqual(1, factory.ObjectDefinitionCount); + } } diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/ObjectNameGenerationTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/ObjectNameGenerationTests.cs index 5d1a9065..62c780f4 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/ObjectNameGenerationTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/ObjectNameGenerationTests.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -25,59 +25,55 @@ using Spring.Objects.Factory.Support; #endregion -namespace Spring.Objects.Factory.Xml +namespace Spring.Objects.Factory.Xml; + +/// +/// This class contains tests for the object naming algorithm used when an object name is not specified. +/// +/// Mark Pollack +[TestFixture] +public class ObjectNameGenerationTests { - /// - /// This class contains tests for the object naming algorithm used when an object name is not specified. - /// - /// Mark Pollack - [TestFixture] - public class ObjectNameGenerationTests + private DefaultListableObjectFactory objectFactory; + + [SetUp] + public void Setup() { - - private DefaultListableObjectFactory objectFactory; - - [SetUp] - public void Setup() - { - objectFactory = new DefaultListableObjectFactory(); - XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(objectFactory); - reader.LoadObjectDefinitions(new ReadOnlyXmlTestResource("objectNameGeneration.xml", GetType())); - } - - [Test] - public void AssignObjectNames() - { - string className = typeof (DependenciesObject).FullName; - - string targetName = className + ObjectDefinitionReaderUtils.GENERATED_OBJECT_NAME_SEPARATOR + "0"; - DependenciesObject topLevel1 = (DependenciesObject) objectFactory.GetObject(targetName); - Assert.IsNotNull(topLevel1); - - targetName = className + ObjectDefinitionReaderUtils.GENERATED_OBJECT_NAME_SEPARATOR + "1"; - DependenciesObject topLevel2 = (DependenciesObject)objectFactory.GetObject(targetName); - Assert.IsNotNull(topLevel1); - - targetName = className + ObjectDefinitionReaderUtils.GENERATED_OBJECT_NAME_SEPARATOR + "2"; - DependenciesObject topLevel3 = (DependenciesObject)objectFactory.GetObject(targetName); - Assert.IsNotNull(topLevel1); - - - string childClassName = typeof(TestObject).FullName; - TestObject child1 = (TestObject) topLevel1.Spouse; - Assert.IsNotNull(child1); - Assert.IsTrue(child1.ObjectName.IndexOf(childClassName) != -1); - - TestObject child2 = (TestObject)topLevel2.Spouse; - Assert.IsNotNull(child2); - Assert.IsTrue(child2.ObjectName.IndexOf(childClassName) != -1); - - TestObject child3 = (TestObject)topLevel3.Spouse; - Assert.IsNotNull(child3); - Assert.IsTrue(child3.ObjectName.IndexOf(childClassName) != -1); - - Assert.AreNotEqual(child1.ObjectName, child2.ObjectName); - } - + objectFactory = new DefaultListableObjectFactory(); + XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(objectFactory); + reader.LoadObjectDefinitions(new ReadOnlyXmlTestResource("objectNameGeneration.xml", GetType())); } -} \ No newline at end of file + + [Test] + public void AssignObjectNames() + { + string className = typeof(DependenciesObject).FullName; + + string targetName = className + ObjectDefinitionReaderUtils.GENERATED_OBJECT_NAME_SEPARATOR + "0"; + DependenciesObject topLevel1 = (DependenciesObject) objectFactory.GetObject(targetName); + Assert.IsNotNull(topLevel1); + + targetName = className + ObjectDefinitionReaderUtils.GENERATED_OBJECT_NAME_SEPARATOR + "1"; + DependenciesObject topLevel2 = (DependenciesObject) objectFactory.GetObject(targetName); + Assert.IsNotNull(topLevel1); + + targetName = className + ObjectDefinitionReaderUtils.GENERATED_OBJECT_NAME_SEPARATOR + "2"; + DependenciesObject topLevel3 = (DependenciesObject) objectFactory.GetObject(targetName); + Assert.IsNotNull(topLevel1); + + string childClassName = typeof(TestObject).FullName; + TestObject child1 = (TestObject) topLevel1.Spouse; + Assert.IsNotNull(child1); + Assert.IsTrue(child1.ObjectName.IndexOf(childClassName) != -1); + + TestObject child2 = (TestObject) topLevel2.Spouse; + Assert.IsNotNull(child2); + Assert.IsTrue(child2.ObjectName.IndexOf(childClassName) != -1); + + TestObject child3 = (TestObject) topLevel3.Spouse; + Assert.IsNotNull(child3); + Assert.IsTrue(child3.ObjectName.IndexOf(childClassName) != -1); + + Assert.AreNotEqual(child1.ObjectName, child2.ObjectName); + } +} diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/ReadOnlyXmlTestResource.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/ReadOnlyXmlTestResource.cs index 2f09d3d1..c232ed7f 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/ReadOnlyXmlTestResource.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/ReadOnlyXmlTestResource.cs @@ -21,125 +21,123 @@ #region Imports using System.Text; - using Spring.Core.IO; #endregion -namespace Spring.Objects.Factory.Xml +namespace Spring.Objects.Factory.Xml; + +/// +/// Centralised resource getter for loading all of those XML object +/// definition files used in the XML based object factory tests. +/// +/// Rick Evans (.NET) +/// Erich Eichinger (.NET) +public class ReadOnlyXmlTestResource : IResource { + private readonly IResource underlyingResource; + private const string TestDataFolder = "Data"; + /// - /// Centralised resource getter for loading all of those XML object - /// definition files used in the XML based object factory tests. + /// Creates a new instance of the + /// class. /// - /// Rick Evans (.NET) - /// Erich Eichinger (.NET) - public class ReadOnlyXmlTestResource : IResource + /// + /// The filename/resourcename (e.g. foo.txt) of the XML file containing the object + /// definitions. + /// + public ReadOnlyXmlTestResource(string fileName) { - private readonly IResource underlyingResource; - private const string TestDataFolder = "Data"; - - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The filename/resourcename (e.g. foo.txt) of the XML file containing the object - /// definitions. - /// - public ReadOnlyXmlTestResource (string fileName) + if (ConfigurableResourceLoader.HasProtocol(fileName)) { - if (ConfigurableResourceLoader.HasProtocol(fileName)) - { - ConfigurableResourceLoader loader = new ConfigurableResourceLoader(); - underlyingResource = loader.GetResource(fileName); - } - else - { - underlyingResource = new FileSystemResource(fileName); - } + ConfigurableResourceLoader loader = new ConfigurableResourceLoader(); + underlyingResource = loader.GetResource(fileName); } - - /// - /// Creates a new instance of the - /// class. - /// - /// - /// The filename/resourcename (e.g. foo.txt) of the XML file containing the object - /// definitions. - /// - /// - /// The of the test class utilising said file. - /// - public ReadOnlyXmlTestResource (string fileName, Type associatedTestType) - : this (ReadOnlyXmlTestResource.GetFilePath (fileName, associatedTestType)) + else { - } - - public IResource CreateRelative(string relativePath) - { - return this.underlyingResource.CreateRelative(relativePath); - } - - public bool IsOpen - { - get { return this.underlyingResource.IsOpen; } - } - - public Uri Uri - { - get { return this.underlyingResource.Uri; } - } - - public FileInfo File - { - get { return this.underlyingResource.File; } - } - - public string Description - { - get { return this.underlyingResource.Description; } - } - - public bool Exists - { - get { return this.underlyingResource.Exists; } - } - - public Stream InputStream - { - get { return this.underlyingResource.InputStream; } - } - - public static string GetFilePath (string fileName, Type associatedTestType) - { - if (associatedTestType == null) - { - return fileName; - } - - // check filesystem - StringBuilder path = new StringBuilder (TestDataFolder).Append (Path.DirectorySeparatorChar.ToString()); - path.Append (associatedTestType.Namespace.Replace (".", Path.DirectorySeparatorChar.ToString())); - path.Append (Path.DirectorySeparatorChar.ToString()).Append (fileName); - - FileInfo file = new FileInfo(path.ToString()); - if (file.Exists) - { - return path.ToString (); - } - else - { - // interpret as assembly resource - fileName = "assembly://" + associatedTestType.Assembly.FullName + "/" + associatedTestType.Namespace - + "/" + fileName; - return fileName; - } - } - - public override string ToString() - { - return Description; + underlyingResource = new FileSystemResource(fileName); } } + + /// + /// Creates a new instance of the + /// class. + /// + /// + /// The filename/resourcename (e.g. foo.txt) of the XML file containing the object + /// definitions. + /// + /// + /// The of the test class utilising said file. + /// + public ReadOnlyXmlTestResource(string fileName, Type associatedTestType) + : this(ReadOnlyXmlTestResource.GetFilePath(fileName, associatedTestType)) + { + } + + public IResource CreateRelative(string relativePath) + { + return this.underlyingResource.CreateRelative(relativePath); + } + + public bool IsOpen + { + get { return this.underlyingResource.IsOpen; } + } + + public Uri Uri + { + get { return this.underlyingResource.Uri; } + } + + public FileInfo File + { + get { return this.underlyingResource.File; } + } + + public string Description + { + get { return this.underlyingResource.Description; } + } + + public bool Exists + { + get { return this.underlyingResource.Exists; } + } + + public Stream InputStream + { + get { return this.underlyingResource.InputStream; } + } + + public static string GetFilePath(string fileName, Type associatedTestType) + { + if (associatedTestType == null) + { + return fileName; + } + + // check filesystem + StringBuilder path = new StringBuilder(TestDataFolder).Append(Path.DirectorySeparatorChar.ToString()); + path.Append(associatedTestType.Namespace.Replace(".", Path.DirectorySeparatorChar.ToString())); + path.Append(Path.DirectorySeparatorChar.ToString()).Append(fileName); + + FileInfo file = new FileInfo(path.ToString()); + if (file.Exists) + { + return path.ToString(); + } + else + { + // interpret as assembly resource + fileName = "assembly://" + associatedTestType.Assembly.FullName + "/" + associatedTestType.Namespace + + "/" + fileName; + return fileName; + } + } + + public override string ToString() + { + return Description; + } } diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/SiimpleCtorWiringTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/SiimpleCtorWiringTests.cs index 7f9c18c5..1d831686 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/SiimpleCtorWiringTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/SiimpleCtorWiringTests.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -24,30 +24,26 @@ using NUnit.Framework; #endregion -namespace Spring.Objects.Factory.Xml +namespace Spring.Objects.Factory.Xml; + +/// +/// This class contains tests for +/// +/// Mark Pollack +/// $Id:$ +[TestFixture] +public class SiimpleCtorWiringTests { - /// - /// This class contains tests for - /// - /// Mark Pollack - /// $Id:$ - [TestFixture] - public class SiimpleCtorWiringTests + [SetUp] + public void Setup() { - [SetUp] - public void Setup() - { - } - - - [Test] - public void SimpleCtor() - { - XmlObjectFactory xof = new XmlObjectFactory(new ReadOnlyXmlTestResource("simple-constructor-arg.xml", GetType())); - ConstructorDependenciesObject obj = (ConstructorDependenciesObject)xof.GetObject("rod4"); - Assert.AreEqual("Kerry2", obj.Spouse1.Name); - } - - } -} \ No newline at end of file + + [Test] + public void SimpleCtor() + { + XmlObjectFactory xof = new XmlObjectFactory(new ReadOnlyXmlTestResource("simple-constructor-arg.xml", GetType())); + ConstructorDependenciesObject obj = (ConstructorDependenciesObject) xof.GetObject("rod4"); + Assert.AreEqual("Kerry2", obj.Spouse1.Name); + } +} diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/SingleSimpleTypeConstructorObject.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/SingleSimpleTypeConstructorObject.cs index 468d44cb..816b3f74 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/SingleSimpleTypeConstructorObject.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/SingleSimpleTypeConstructorObject.cs @@ -1,5 +1,3 @@ - - #region License /* @@ -20,67 +18,63 @@ #endregion -namespace Spring.Objects.Factory.Xml +namespace Spring.Objects.Factory.Xml; + +/// +/// Simple object used to test object creation via constuctors with +/// simple types. +/// +/// Jurgen Hoeller +/// Mark Pollack (.NET) +public class SingleSimpleTypeConstructorObject { - /// - /// Simple object used to test object creation via constuctors with - /// simple types. - /// - /// Jurgen Hoeller - /// Mark Pollack (.NET) - public class SingleSimpleTypeConstructorObject - { - private bool singleBoolean; + private bool singleBoolean; - private bool secondBoolean; + private bool secondBoolean; - private string testString; + private string testString; - /// - /// Create an instance using the singleBoolean - /// - /// true or false - public SingleSimpleTypeConstructorObject(bool singleBoolean) - { - this.singleBoolean = singleBoolean; - } + /// + /// Create an instance using the singleBoolean + /// + /// true or false + public SingleSimpleTypeConstructorObject(bool singleBoolean) + { + this.singleBoolean = singleBoolean; + } - /// - /// Create an instance using the second boolean and a string - /// - /// test value - /// true or false - public SingleSimpleTypeConstructorObject(string testString, bool secondBoolean) - { - this.testString = testString; - this.secondBoolean = secondBoolean; - } + /// + /// Create an instance using the second boolean and a string + /// + /// test value + /// true or false + public SingleSimpleTypeConstructorObject(string testString, bool secondBoolean) + { + this.testString = testString; + this.secondBoolean = secondBoolean; + } + /// + /// Property TestString (string) + /// + public string TestString + { + get { return this.testString; } + } - /// - /// Property TestString (string) - /// - public string TestString - { - get { return this.testString; } - } + /// + /// Property SecondBoolean (bool) + /// + public bool SecondBoolean + { + get { return this.secondBoolean; } + } - /// - /// Property SecondBoolean (bool) - /// - public bool SecondBoolean - { - get { return this.secondBoolean; } - } - - /// - /// Property SingleBoolean (bool) - /// - public bool SingleBoolean - { - get { return this.singleBoolean; } - } - - - } -} \ No newline at end of file + /// + /// Property SingleBoolean (bool) + /// + public bool SingleBoolean + { + get { return this.singleBoolean; } + } +} diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/TestObjectCreator.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/TestObjectCreator.cs index dc53edbf..1e9313c1 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/TestObjectCreator.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/TestObjectCreator.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -20,33 +20,30 @@ #region Imports - - #endregion -namespace Spring.Objects.Factory.Xml +namespace Spring.Objects.Factory.Xml; + +/// +/// Test class for Spring's ability to create objects using static factory methods, rather +/// than constructors. +/// +/// Rod Johnson +/// Rick Evans (.NET) +public class TestObjectCreator { - /// - /// Test class for Spring's ability to create objects using static factory methods, rather - /// than constructors. - /// - /// Rod Johnson - /// Rick Evans (.NET) - public class TestObjectCreator + public static TestObject CreateTestObject(string name, int age) { - public static TestObject CreateTestObject(string name, int age) - { - return new TestObject(name, age); - } + return new TestObject(name, age); + } - public static TestObject CreateTestObject() - { - return new TestObject("Tristan", 2); - } + public static TestObject CreateTestObject() + { + return new TestObject("Tristan", 2); + } - public TestObject InstanceCreateTestObject() - { - return CreateTestObject(); - } + public TestObject InstanceCreateTestObject() + { + return CreateTestObject(); } } \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/XmlListableObjectFactoryTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/XmlListableObjectFactoryTests.cs index fe89a0fb..57ef6056 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/XmlListableObjectFactoryTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/XmlListableObjectFactoryTests.cs @@ -49,12 +49,14 @@ namespace Spring.Objects.Factory.Xml { if (obj is TestObject) { - ((TestObject)obj).PostProcessed = true; + ((TestObject) obj).PostProcessed = true; } + if (obj is DummyFactory) { - ((DummyFactory)obj).PostProcessed = true; + ((DummyFactory) obj).PostProcessed = true; } + return obj; } @@ -113,21 +115,21 @@ namespace Spring.Objects.Factory.Xml [Test] public virtual void FactoryNesting() { - ITestObject father = (ITestObject)ObjectFactory.GetObject("father"); + ITestObject father = (ITestObject) ObjectFactory.GetObject("father"); Assert.IsTrue(father != null, "Object from root context"); - ITestObject rod = (ITestObject)ObjectFactory.GetObject("rod"); + ITestObject rod = (ITestObject) ObjectFactory.GetObject("rod"); Assert.IsTrue("Rod".Equals(rod.Name), "Object from child context"); Assert.IsTrue(rod.Spouse == father, "Object has external reference"); - rod = (ITestObject)parent.GetObject("rod"); + rod = (ITestObject) parent.GetObject("rod"); Assert.IsTrue("Roderick".Equals(rod.Name), "Object from root context"); } [Test] public virtual void FactoryReferences() { - DummyReferencer dref = (DummyReferencer)ObjectFactory.GetObject("factoryReferencer"); + DummyReferencer dref = (DummyReferencer) ObjectFactory.GetObject("factoryReferencer"); Assert.IsTrue(dref.TestObject1 == dref.TestObject2); } @@ -135,9 +137,9 @@ namespace Spring.Objects.Factory.Xml public virtual void PrototypeReferences() { // check that not broken by circular reference resolution mechanism - DummyReferencer ref1 = (DummyReferencer)ObjectFactory.GetObject("prototypeReferencer"); + DummyReferencer ref1 = (DummyReferencer) ObjectFactory.GetObject("prototypeReferencer"); Assert.IsTrue(ref1.TestObject1 != ref1.TestObject2, "Not referencing same Object twice"); - DummyReferencer ref2 = (DummyReferencer)ObjectFactory.GetObject("prototypeReferencer"); + DummyReferencer ref2 = (DummyReferencer) ObjectFactory.GetObject("prototypeReferencer"); Assert.IsTrue(ref1 != ref2, "Not the same referencer"); Assert.IsTrue(ref2.TestObject1 != ref2.TestObject2, "Not referencing same Object twice"); Assert.IsTrue(ref1.TestObject1 != ref2.TestObject1, "Not referencing same Object twice"); @@ -148,10 +150,10 @@ namespace Spring.Objects.Factory.Xml [Test] public virtual void ObjectPostProcessor() { - TestObject kerry = (TestObject)ObjectFactory.GetObject("kerry"); - TestObject kathy = (TestObject)ObjectFactory.GetObject("kathy"); - DummyFactory factory = (DummyFactory)ObjectFactory.GetObject("&singletonFactory"); - TestObject factoryCreated = (TestObject)ObjectFactory.GetObject("singletonFactory"); + TestObject kerry = (TestObject) ObjectFactory.GetObject("kerry"); + TestObject kathy = (TestObject) ObjectFactory.GetObject("kathy"); + DummyFactory factory = (DummyFactory) ObjectFactory.GetObject("&singletonFactory"); + TestObject factoryCreated = (TestObject) ObjectFactory.GetObject("singletonFactory"); Assert.IsTrue(kerry.PostProcessed); Assert.IsTrue(kathy.PostProcessed); Assert.IsTrue(factory.PostProcessed); @@ -170,14 +172,14 @@ namespace Spring.Objects.Factory.Xml [Test] public void CanRetrieveByType_Using_GetObjects_T_Method() { - var objsByGenericMethod = ((DefaultListableObjectFactory)ObjectFactory).GetObjects(); + var objsByGenericMethod = ((DefaultListableObjectFactory) ObjectFactory).GetObjects(); Assert.That(objsByGenericMethod.Count, Is.EqualTo(3)); } [Test] public void CanRetrieveByType_Using_GetObjectsOfType_Method() { - var objsByOldMethod = ((DefaultListableObjectFactory)ObjectFactory).GetObjectsOfType(typeof(NameIdTestObject)); + var objsByOldMethod = ((DefaultListableObjectFactory) ObjectFactory).GetObjectsOfType(typeof(NameIdTestObject)); Assert.That(objsByOldMethod.Count, Is.EqualTo(3)); } @@ -188,7 +190,6 @@ namespace Spring.Objects.Factory.Xml Assert.That(ObjectFactory.GetObject("object2-with-same-id-and-name"), Is.Not.Null); Assert.That(ObjectFactory.GetObject("name-id-test-object-name"), Is.Not.Null); } - } } @@ -196,7 +197,5 @@ namespace Spring.Objects { public class NameIdTestObject { - } - -} \ No newline at end of file +} diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/XmlObjectCollectionTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/XmlObjectCollectionTests.cs index f6076f8a..27679cfc 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/XmlObjectCollectionTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/XmlObjectCollectionTests.cs @@ -29,508 +29,509 @@ using Spring.Objects.Factory.Config; using Spring.Objects.Factory.Support; using Spring.Util; -namespace Spring.Objects.Factory.Xml +namespace Spring.Objects.Factory.Xml; + +/// +/// Tests for collections in XML object definitions. +/// +/// Rick Evans +[TestFixture] +public sealed class XmlObjectCollectionTests { /// - /// Tests for collections in XML object definitions. + /// The setup logic executed before the execution of this test fixture. /// - /// Rick Evans - [TestFixture] - public sealed class XmlObjectCollectionTests + [OneTimeSetUp] + public void FixtureSetUp() { - /// - /// The setup logic executed before the execution of this test fixture. - /// - [OneTimeSetUp] - public void FixtureSetUp() + // enable (null appender) logging, to ensure that the logging code is exercised... + LogManager.LoggerFactory = NullLoggerFactory.Instance; + //XmlConfigurator.Configure(); + } + + [Test] + public void CanApplyConstructorArgsToAbstractType() + { + IResource resource = new ReadOnlyXmlTestResource("ctor-args.xml", GetType()); + XmlObjectFactory xof = new XmlObjectFactory(resource); + TestObject rod = (TestObject) xof.GetObject("rod"); + Assert.AreEqual(1, rod.Age); + + RootObjectDefinition def = (RootObjectDefinition) xof.GetObjectDefinition("rod"); + ConstructorResolver resolver = new ConstructorResolver(xof, xof, new SimpleInstantiationStrategy(), + new ObjectDefinitionValueResolver(xof)); + + ConstructorInstantiationInfo ci = resolver.GetConstructorInstantiationInfo("rod", def, null, null); + + AbstractObjectDefinition objDef = (AbstractObjectDefinition) xof.GetObjectDefinition("foo"); + objDef.IsAbstract = false; + + TestObject foo = (TestObject) xof.GetObject("foo"); + + Assert.AreEqual(2, foo.Age); + } + + [Test] + public void RefSubelementsBuildCollection() + { + IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); + XmlObjectFactory xof = new XmlObjectFactory(resource); + //Assert.IsTrue ("5 objects in reftypes, not " + xof.GetObjectDefinitionCount(), xof.GetObjectDefinitionCount() == 5); + TestObject jen = (TestObject) xof.GetObject("jenny"); + TestObject dave = (TestObject) xof.GetObject("david"); + TestObject rod = (TestObject) xof.GetObject("rod"); + + // Must be a list to support ordering + // Our object doesn't modify the collection: + // of course it could be a different copy in a real object + IList friends = (IList) rod.Friends; + Assert.IsTrue(friends.Count == 2); + Assert.IsTrue(friends[0] == jen, "First friend must be jen, not " + friends[0]); + Assert.IsTrue(friends[1] == dave); + // Should be ordered + } + + [Test] + public void RefSubelementsBuildCollectionWithPrototypes() + { + IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); + XmlObjectFactory xof = new XmlObjectFactory(resource); + + TestObject jen = (TestObject) xof.GetObject("pJenny"); + TestObject dave = (TestObject) xof.GetObject("pDavid"); + TestObject rod = (TestObject) xof.GetObject("pRod"); + IList friends = (IList) rod.Friends; + Assert.IsTrue(friends.Count == 2); + Assert.IsTrue(friends[0].ToString().Equals(jen.ToString()), "First friend must be jen, not " + friends[0]); + Assert.IsTrue(friends[0] != jen, "Jen not same instance"); + Assert.IsTrue(friends[1].ToString().Equals(dave.ToString())); + Assert.IsTrue(friends[1] != dave, "Dave not same instance"); + + TestObject rod2 = (TestObject) xof.GetObject("pRod"); + IList friends2 = (IList) rod2.Friends; + Assert.IsTrue(friends2.Count == 2); + Assert.IsTrue(friends2[0].ToString().Equals(jen.ToString()), "First friend must be jen, not " + friends2[0]); + Assert.IsTrue(friends2[0] != friends[0], "Jen not same instance"); + Assert.IsTrue(friends2[1].ToString().Equals(dave.ToString())); + Assert.IsTrue(friends2[1] != friends[1], "Dave not same instance"); + } + + [Test] + public void RefSubelementsBuildCollectionFromSingleElement() + { + IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); + XmlObjectFactory xof = new XmlObjectFactory(resource); + TestObject loner = (TestObject) xof.GetObject("loner"); + TestObject dave = (TestObject) xof.GetObject("david"); + Assert.IsTrue(loner.Friends.Count == 1); + bool contains = false; + foreach (object friend in loner.Friends) { - // enable (null appender) logging, to ensure that the logging code is exercised... - LogManager.LoggerFactory = NullLoggerFactory.Instance; - //XmlConfigurator.Configure(); - } - - [Test] - public void CanApplyConstructorArgsToAbstractType() - { - IResource resource = new ReadOnlyXmlTestResource("ctor-args.xml", GetType()); - XmlObjectFactory xof = new XmlObjectFactory(resource); - TestObject rod = (TestObject)xof.GetObject("rod"); - Assert.AreEqual(1, rod.Age); - - RootObjectDefinition def = (RootObjectDefinition) xof.GetObjectDefinition("rod"); - ConstructorResolver resolver = new ConstructorResolver(xof, xof, new SimpleInstantiationStrategy(), - new ObjectDefinitionValueResolver(xof)); - - ConstructorInstantiationInfo ci = resolver.GetConstructorInstantiationInfo("rod", def, null, null); - - AbstractObjectDefinition objDef = (AbstractObjectDefinition)xof.GetObjectDefinition("foo"); - objDef.IsAbstract = false; - - TestObject foo = (TestObject) xof.GetObject("foo"); - - - Assert.AreEqual(2, foo.Age); - } - - - [Test] - public void RefSubelementsBuildCollection() - { - IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); - XmlObjectFactory xof = new XmlObjectFactory(resource); - //Assert.IsTrue ("5 objects in reftypes, not " + xof.GetObjectDefinitionCount(), xof.GetObjectDefinitionCount() == 5); - TestObject jen = (TestObject) xof.GetObject("jenny"); - TestObject dave = (TestObject) xof.GetObject("david"); - TestObject rod = (TestObject) xof.GetObject("rod"); - - // Must be a list to support ordering - // Our object doesn't modify the collection: - // of course it could be a different copy in a real object - IList friends = (IList) rod.Friends; - Assert.IsTrue(friends.Count == 2); - Assert.IsTrue(friends[0] == jen, "First friend must be jen, not " + friends[0]); - Assert.IsTrue(friends[1] == dave); - // Should be ordered - } - - [Test] - public void RefSubelementsBuildCollectionWithPrototypes() - { - IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); - XmlObjectFactory xof = new XmlObjectFactory(resource); - - TestObject jen = (TestObject) xof.GetObject("pJenny"); - TestObject dave = (TestObject) xof.GetObject("pDavid"); - TestObject rod = (TestObject) xof.GetObject("pRod"); - IList friends = (IList) rod.Friends; - Assert.IsTrue(friends.Count == 2); - Assert.IsTrue(friends[0].ToString().Equals(jen.ToString()), "First friend must be jen, not " + friends[0]); - Assert.IsTrue(friends[0] != jen, "Jen not same instance"); - Assert.IsTrue(friends[1].ToString().Equals(dave.ToString())); - Assert.IsTrue(friends[1] != dave, "Dave not same instance"); - - TestObject rod2 = (TestObject) xof.GetObject("pRod"); - IList friends2 = (IList) rod2.Friends; - Assert.IsTrue(friends2.Count == 2); - Assert.IsTrue(friends2[0].ToString().Equals(jen.ToString()), "First friend must be jen, not " + friends2[0]); - Assert.IsTrue(friends2[0] != friends[0], "Jen not same instance"); - Assert.IsTrue(friends2[1].ToString().Equals(dave.ToString())); - Assert.IsTrue(friends2[1] != friends[1], "Dave not same instance"); - } - - [Test] - public void RefSubelementsBuildCollectionFromSingleElement() - { - IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); - XmlObjectFactory xof = new XmlObjectFactory(resource); - TestObject loner = (TestObject) xof.GetObject("loner"); - TestObject dave = (TestObject) xof.GetObject("david"); - Assert.IsTrue(loner.Friends.Count == 1); - bool contains = false; - foreach (object friend in loner.Friends) + if (friend == dave) { - if (friend == dave) - { - contains = true; - break; - } + contains = true; + break; } - Assert.IsTrue(contains); } - [Test] - public void BuildCollectionFromMixtureOfReferencesAndValues() + Assert.IsTrue(contains); + } + + [Test] + public void BuildCollectionFromMixtureOfReferencesAndValues() + { + MixedCollectionObject.ResetStaticState(); + IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); + XmlObjectFactory xof = new XmlObjectFactory(resource); + MixedCollectionObject jumble = (MixedCollectionObject) xof.GetObject("jumble"); + Assert.AreEqual(1, MixedCollectionObject.nrOfInstances); + xof.GetObject("david", typeof(TestObject)); + Assert.IsTrue(jumble.Jumble.Count == 4, "Expected 3 elements, not " + jumble.Jumble.Count); + IList l = (IList) jumble.Jumble; + Assert.IsTrue(l[0].Equals(xof.GetObject("david"))); + Assert.IsTrue(l[1].Equals("literal")); + Assert.IsTrue(l[2].Equals(xof.GetObject("jenny"))); + Assert.IsTrue(l[3].Equals("rod")); + } + + /// + /// Test to see if a type safe custom collection class can be set using normal + /// list syntax. + /// + [Test] + public void CustomListCollection() + { + IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); + XmlObjectFactory xof = new XmlObjectFactory(resource); + TestObject objectWithTypedFriends = (TestObject) xof.GetObject("objectWithTypedFriends"); + TestObjectList tol = objectWithTypedFriends.TypedFriends; + Assert.AreEqual(1, tol.Count); + Assert.IsTrue(tol[0].Equals(xof.GetObject("david"))); + } + + /// + /// Test to see if we can set values on a collection class that uses indexers + /// + [Test] + public void ObjectWithIndexerProperty() + { + IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); + XmlObjectFactory xof = new XmlObjectFactory(resource); + TestObject testObject = (TestObject) xof.GetObject("objectWithIndexer"); + Assert.IsNotNull(testObject); + Assert.AreEqual("my string value", testObject[0]); + } + + /// + /// Test that properties with name as well as id creating an alias up front. + /// + [Test] + public void AutoAliasing() + { + IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); + XmlObjectFactory xof = new XmlObjectFactory(resource); + var objectNames = xof.GetObjectDefinitionNames(); + TestObject tb1 = (TestObject) xof.GetObject("aliased"); + TestObject alias1 = (TestObject) xof.GetObject("myalias"); + Assert.IsTrue(tb1 == alias1); + + var tb1Aliases = xof.GetAliases("aliased"); + Assert.AreEqual(1, tb1Aliases.Count); + Assert.IsTrue(tb1Aliases.Contains("myalias")); + Assert.IsTrue(objectNames.Contains("aliased")); + Assert.IsFalse(objectNames.Contains("myalias")); + + TestObject tb2 = (TestObject) xof.GetObject("multiAliased"); + TestObject alias2 = (TestObject) xof.GetObject("alias1"); + TestObject alias3 = (TestObject) xof.GetObject("alias2"); + Assert.IsTrue(tb2 == alias2); + Assert.IsTrue(tb2 == alias3); + var tb2Aliases = xof.GetAliases("multiAliased"); + Assert.AreEqual(2, tb2Aliases.Count); + Assert.IsTrue(tb2Aliases.Contains("alias1")); + Assert.IsTrue(tb2Aliases.Contains("alias2")); + Assert.IsTrue(objectNames.Contains("multiAliased")); + Assert.IsFalse(objectNames.Contains("alias1")); + Assert.IsFalse(objectNames.Contains("alias2")); + + TestObject tb3 = (TestObject) xof.GetObject("aliasWithoutId1"); + TestObject alias4 = (TestObject) xof.GetObject("aliasWithoutId2"); + TestObject alias5 = (TestObject) xof.GetObject("aliasWithoutId3"); + Assert.IsTrue(tb3 == alias4); + Assert.IsTrue(tb3 == alias5); + + var tb3Aliases = xof.GetAliases("aliasWithoutId1"); + Assert.AreEqual(2, tb2Aliases.Count); + Assert.IsTrue(tb3Aliases.Contains("aliasWithoutId2")); + Assert.IsTrue(tb3Aliases.Contains("aliasWithoutId3")); + Assert.IsTrue(objectNames.Contains("aliasWithoutId1")); + Assert.IsFalse(objectNames.Contains("aliasWithoutId2")); + Assert.IsFalse(objectNames.Contains("aliasWithoutId3")); + + string className = typeof(TestObject).FullName; + string targetName = className + ObjectDefinitionReaderUtils.GENERATED_OBJECT_NAME_SEPARATOR + "0"; + + TestObject tb4 = (TestObject) xof.GetObject(targetName); + Assert.AreEqual(null, tb4.Name); + } + + /// + /// Test that we can add elements to an IList that is exposed as a + /// read only property. Many classes in the BCL only expose getters to + /// modify the content of collections. + /// + [Test] + public void AddElementsToReadOnlyList() + { + IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); + //Stream stream = new FileSystemResource("file:///w:/collections.xml").InputStream; + XmlObjectFactory xof = new XmlObjectFactory(resource); + + TestObject aleks = (TestObject) xof.GetObject("aleks"); + IList pets = (IList) aleks.Pets; + Assert.IsTrue(pets.Count == 1); + Assert.IsTrue(pets[0].Equals("Nadja")); + } + + /// + /// Test that we can add elements to an IDictionary that is exposed as a + /// read-only property. + /// + public void AddElementsToReadOnlyDictionary() + { + IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); + XmlObjectFactory xof = new XmlObjectFactory(resource); + + TestObject to = (TestObject) xof.GetObject("readOnlyDictionary"); + IDictionary table = to.PeriodicTable; + Assert.IsTrue(table.Count == 2); + Assert.AreEqual("1", table["hydrogen"], "Dictionary Value incorrect"); + Assert.AreEqual("12", table["carbon"], "Dictionary value incorrect"); + } + + /// + /// Test that we can add elements to an ISet that is exposed as a + /// read-only property + /// + public void AddElementsToReadOnlySet() + { + IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); + XmlObjectFactory xof = new XmlObjectFactory(resource); + + TestObject to = (TestObject) xof.GetObject("readOnlySet"); + ISet computers = to.Computers; + Assert.IsTrue(computers.Count == 2); + bool foundDell = false; + bool foundIbm = false; + foreach (string name in computers) { - MixedCollectionObject.ResetStaticState(); - IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); - XmlObjectFactory xof = new XmlObjectFactory(resource); - MixedCollectionObject jumble = (MixedCollectionObject) xof.GetObject("jumble"); - Assert.AreEqual(1, MixedCollectionObject.nrOfInstances); - xof.GetObject("david", typeof (TestObject)); - Assert.IsTrue(jumble.Jumble.Count == 4, "Expected 3 elements, not " + jumble.Jumble.Count); - IList l = (IList) jumble.Jumble; - Assert.IsTrue(l[0].Equals(xof.GetObject("david"))); - Assert.IsTrue(l[1].Equals("literal")); - Assert.IsTrue(l[2].Equals(xof.GetObject("jenny"))); - Assert.IsTrue(l[3].Equals("rod")); - } - - /// - /// Test to see if a type safe custom collection class can be set using normal - /// list syntax. - /// - [Test] - public void CustomListCollection() - { - IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); - XmlObjectFactory xof = new XmlObjectFactory(resource); - TestObject objectWithTypedFriends = (TestObject) xof.GetObject("objectWithTypedFriends"); - TestObjectList tol = objectWithTypedFriends.TypedFriends; - Assert.AreEqual(1, tol.Count); - Assert.IsTrue(tol[0].Equals(xof.GetObject("david"))); - } - - /// - /// Test to see if we can set values on a collection class that uses indexers - /// - [Test] - public void ObjectWithIndexerProperty() - { - IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); - XmlObjectFactory xof = new XmlObjectFactory(resource); - TestObject testObject = (TestObject) xof.GetObject("objectWithIndexer"); - Assert.IsNotNull(testObject); - Assert.AreEqual("my string value", testObject[0]); - - } - /// - /// Test that properties with name as well as id creating an alias up front. - /// - [Test] - public void AutoAliasing() - { - IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); - XmlObjectFactory xof = new XmlObjectFactory(resource); - var objectNames = xof.GetObjectDefinitionNames(); - TestObject tb1 = (TestObject) xof.GetObject("aliased"); - TestObject alias1 = (TestObject) xof.GetObject("myalias"); - Assert.IsTrue(tb1 == alias1); - - var tb1Aliases = xof.GetAliases("aliased"); - Assert.AreEqual(1, tb1Aliases.Count); - Assert.IsTrue(tb1Aliases.Contains("myalias")); - Assert.IsTrue(objectNames.Contains("aliased")); - Assert.IsFalse(objectNames.Contains("myalias")); - - TestObject tb2 = (TestObject) xof.GetObject("multiAliased"); - TestObject alias2 = (TestObject) xof.GetObject("alias1"); - TestObject alias3 = (TestObject) xof.GetObject("alias2"); - Assert.IsTrue(tb2 == alias2); - Assert.IsTrue(tb2 == alias3); - var tb2Aliases = xof.GetAliases("multiAliased"); - Assert.AreEqual(2, tb2Aliases.Count); - Assert.IsTrue(tb2Aliases.Contains("alias1")); - Assert.IsTrue(tb2Aliases.Contains("alias2")); - Assert.IsTrue(objectNames.Contains("multiAliased")); - Assert.IsFalse(objectNames.Contains("alias1")); - Assert.IsFalse(objectNames.Contains("alias2")); - - TestObject tb3 = (TestObject) xof.GetObject("aliasWithoutId1"); - TestObject alias4 = (TestObject) xof.GetObject("aliasWithoutId2"); - TestObject alias5 = (TestObject) xof.GetObject("aliasWithoutId3"); - Assert.IsTrue(tb3 == alias4); - Assert.IsTrue(tb3 == alias5); - - var tb3Aliases = xof.GetAliases("aliasWithoutId1"); - Assert.AreEqual(2, tb2Aliases.Count); - Assert.IsTrue(tb3Aliases.Contains("aliasWithoutId2")); - Assert.IsTrue(tb3Aliases.Contains("aliasWithoutId3")); - Assert.IsTrue(objectNames.Contains("aliasWithoutId1")); - Assert.IsFalse(objectNames.Contains("aliasWithoutId2")); - Assert.IsFalse(objectNames.Contains("aliasWithoutId3")); - - string className = typeof(TestObject).FullName; - string targetName = className + ObjectDefinitionReaderUtils.GENERATED_OBJECT_NAME_SEPARATOR + "0"; - - TestObject tb4 = (TestObject)xof.GetObject(targetName); - Assert.AreEqual(null, tb4.Name); - } - - /// - /// Test that we can add elements to an IList that is exposed as a - /// read only property. Many classes in the BCL only expose getters to - /// modify the content of collections. - /// - [Test] - public void AddElementsToReadOnlyList() - { - IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); - //Stream stream = new FileSystemResource("file:///w:/collections.xml").InputStream; - XmlObjectFactory xof = new XmlObjectFactory(resource); - - TestObject aleks = (TestObject) xof.GetObject("aleks"); - IList pets = (IList) aleks.Pets; - Assert.IsTrue(pets.Count == 1); - Assert.IsTrue(pets[0].Equals("Nadja")); - } - - /// - /// Test that we can add elements to an IDictionary that is exposed as a - /// read-only property. - /// - public void AddElementsToReadOnlyDictionary() - { - IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); - XmlObjectFactory xof = new XmlObjectFactory(resource); - - TestObject to = (TestObject) xof.GetObject("readOnlyDictionary"); - IDictionary table = to.PeriodicTable; - Assert.IsTrue(table.Count == 2); - Assert.AreEqual("1", table["hydrogen"], "Dictionary Value incorrect"); - Assert.AreEqual("12", table["carbon"], "Dictionary value incorrect"); - } - - /// - /// Test that we can add elements to an ISet that is exposed as a - /// read-only property - /// - public void AddElementsToReadOnlySet() - { - IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); - XmlObjectFactory xof = new XmlObjectFactory(resource); - - TestObject to = (TestObject) xof.GetObject("readOnlySet"); - ISet computers = to.Computers; - Assert.IsTrue(computers.Count == 2); - bool foundDell = false; - bool foundIbm = false; - foreach (string name in computers) + if (name.Equals("Dell")) { - if (name.Equals("Dell")) - { - foundDell = true; - } - if (name.Equals("IBM T41")) - { - foundIbm = true; - } + foundDell = true; + } + + if (name.Equals("IBM T41")) + { + foundIbm = true; } - Assert.IsTrue(foundDell, "Dell string not found in ISet"); - Assert.IsTrue(foundIbm, "IBM T41 not found in ISet"); } - [Test] - public void EmptyMap() - { - IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); - XmlObjectFactory xof = new XmlObjectFactory(resource); - HasMap hasMap = (HasMap) xof.GetObject("emptyMap"); - Assert.IsTrue(hasMap.Map.Count == 0); - } + Assert.IsTrue(foundDell, "Dell string not found in ISet"); + Assert.IsTrue(foundIbm, "IBM T41 not found in ISet"); + } - [Test] - public void MapWithLiteralsOnly() - { - IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); - XmlObjectFactory xof = new XmlObjectFactory(resource); - HasMap hasMap = (HasMap) xof.GetObject("literalMap"); - Assert.IsTrue(hasMap.Map.Count == 3); - Assert.IsTrue(hasMap.Map["foo"].Equals("bar")); - Assert.IsTrue(hasMap.Map["fi"].Equals("fum")); - Assert.IsTrue(hasMap.Map["fa"] == null); - } + [Test] + public void EmptyMap() + { + IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); + XmlObjectFactory xof = new XmlObjectFactory(resource); + HasMap hasMap = (HasMap) xof.GetObject("emptyMap"); + Assert.IsTrue(hasMap.Map.Count == 0); + } - [Test] - public void MapWithLiteralsAndReferences() - { - IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); - XmlObjectFactory xof = new XmlObjectFactory(resource); - HasMap hasMap = (HasMap) xof.GetObject("mixedMap"); - Assert.IsTrue(hasMap.Map.Count == 3); - Assert.IsTrue(hasMap.Map["foo"].Equals("bar")); - TestObject jenny = (TestObject) xof.GetObject("jenny"); - Assert.IsTrue(hasMap.Map["jenny"] == jenny); - Assert.IsTrue(hasMap.Map["david"].Equals("david")); - } + [Test] + public void MapWithLiteralsOnly() + { + IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); + XmlObjectFactory xof = new XmlObjectFactory(resource); + HasMap hasMap = (HasMap) xof.GetObject("literalMap"); + Assert.IsTrue(hasMap.Map.Count == 3); + Assert.IsTrue(hasMap.Map["foo"].Equals("bar")); + Assert.IsTrue(hasMap.Map["fi"].Equals("fum")); + Assert.IsTrue(hasMap.Map["fa"] == null); + } - [Test] - public void MapWithLiteralsAndPrototypeReferences() - { - IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); - XmlObjectFactory xof = new XmlObjectFactory(resource); + [Test] + public void MapWithLiteralsAndReferences() + { + IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); + XmlObjectFactory xof = new XmlObjectFactory(resource); + HasMap hasMap = (HasMap) xof.GetObject("mixedMap"); + Assert.IsTrue(hasMap.Map.Count == 3); + Assert.IsTrue(hasMap.Map["foo"].Equals("bar")); + TestObject jenny = (TestObject) xof.GetObject("jenny"); + Assert.IsTrue(hasMap.Map["jenny"] == jenny); + Assert.IsTrue(hasMap.Map["david"].Equals("david")); + } - TestObject jenny = (TestObject) xof.GetObject("pJenny"); - HasMap hasMap = (HasMap) xof.GetObject("pMixedMap"); - Assert.IsTrue(hasMap.Map.Count == 2); - Assert.IsTrue(hasMap.Map["foo"].Equals("bar")); - Assert.IsTrue(hasMap.Map["jenny"].ToString().Equals(jenny.ToString())); - Assert.IsTrue(hasMap.Map["jenny"] != jenny, "Not same instance"); + [Test] + public void MapWithLiteralsAndPrototypeReferences() + { + IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); + XmlObjectFactory xof = new XmlObjectFactory(resource); - HasMap hasMap2 = (HasMap) xof.GetObject("pMixedMap"); - Assert.IsTrue(hasMap2.Map.Count == 2); - Assert.IsTrue(hasMap2.Map["foo"].Equals("bar")); - Assert.IsTrue(hasMap2.Map["jenny"].ToString().Equals(jenny.ToString())); - Assert.IsTrue(hasMap2.Map["jenny"] != hasMap.Map["jenny"], "Not same instance"); - } + TestObject jenny = (TestObject) xof.GetObject("pJenny"); + HasMap hasMap = (HasMap) xof.GetObject("pMixedMap"); + Assert.IsTrue(hasMap.Map.Count == 2); + Assert.IsTrue(hasMap.Map["foo"].Equals("bar")); + Assert.IsTrue(hasMap.Map["jenny"].ToString().Equals(jenny.ToString())); + Assert.IsTrue(hasMap.Map["jenny"] != jenny, "Not same instance"); - [Test] - public void MapWithLiteralsReferencesAndList() - { - IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); - XmlObjectFactory xof = new XmlObjectFactory(resource); - HasMap hasMap = (HasMap) xof.GetObject("mixedMapWithList"); - Assert.IsTrue(hasMap.Map.Count == 4); - Assert.IsTrue(hasMap.Map["foo"].Equals("bar")); - TestObject jenny = (TestObject) xof.GetObject("jenny"); - Assert.IsTrue(hasMap.Map["jenny"].Equals(jenny)); + HasMap hasMap2 = (HasMap) xof.GetObject("pMixedMap"); + Assert.IsTrue(hasMap2.Map.Count == 2); + Assert.IsTrue(hasMap2.Map["foo"].Equals("bar")); + Assert.IsTrue(hasMap2.Map["jenny"].ToString().Equals(jenny.ToString())); + Assert.IsTrue(hasMap2.Map["jenny"] != hasMap.Map["jenny"], "Not same instance"); + } - // Check list - IList l = (IList) hasMap.Map["list"]; - Assert.IsNotNull(l); - Assert.IsTrue(l.Count == 4); - Assert.IsTrue(l[0].Equals("zero")); - Assert.IsTrue(l[3] == null); + [Test] + public void MapWithLiteralsReferencesAndList() + { + IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); + XmlObjectFactory xof = new XmlObjectFactory(resource); + HasMap hasMap = (HasMap) xof.GetObject("mixedMapWithList"); + Assert.IsTrue(hasMap.Map.Count == 4); + Assert.IsTrue(hasMap.Map["foo"].Equals("bar")); + TestObject jenny = (TestObject) xof.GetObject("jenny"); + Assert.IsTrue(hasMap.Map["jenny"].Equals(jenny)); - // Check nested map in list - IDictionary m = (IDictionary) l[1]; - Assert.IsNotNull(m); - Assert.IsTrue(m.Count == 2); - Assert.IsTrue(m["fo"].Equals("bar")); - Assert.IsTrue(m["jen"].Equals(jenny), "Map element 'jenny' should be equal to jenny object, not " + m["jen"]); + // Check list + IList l = (IList) hasMap.Map["list"]; + Assert.IsNotNull(l); + Assert.IsTrue(l.Count == 4); + Assert.IsTrue(l[0].Equals("zero")); + Assert.IsTrue(l[3] == null); - // Check nested list in list - l = (IList) l[2]; - Assert.IsNotNull(l); - Assert.IsTrue(l.Count == 2); - Assert.IsTrue(l[0].Equals(jenny)); - Assert.IsTrue(l[1].Equals("ba")); + // Check nested map in list + IDictionary m = (IDictionary) l[1]; + Assert.IsNotNull(m); + Assert.IsTrue(m.Count == 2); + Assert.IsTrue(m["fo"].Equals("bar")); + Assert.IsTrue(m["jen"].Equals(jenny), "Map element 'jenny' should be equal to jenny object, not " + m["jen"]); - // Check nested map - m = (IDictionary) hasMap.Map["map"]; - Assert.IsNotNull(m); - Assert.IsTrue(m.Count == 2); - Assert.IsTrue(m["foo"].Equals("bar")); - Assert.IsTrue(m["jenny"].Equals(jenny), - "Map element 'jenny' should be equal to jenny object, not " + m["jenny"]); - } + // Check nested list in list + l = (IList) l[2]; + Assert.IsNotNull(l); + Assert.IsTrue(l.Count == 2); + Assert.IsTrue(l[0].Equals(jenny)); + Assert.IsTrue(l[1].Equals("ba")); - [Test] - public void EmptySet() - { - IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); - XmlObjectFactory xof = new XmlObjectFactory(resource); - HasMap hasMap = (HasMap) xof.GetObject("emptySet"); - Assert.IsTrue(hasMap.Set.Count == 0); - } + // Check nested map + m = (IDictionary) hasMap.Map["map"]; + Assert.IsNotNull(m); + Assert.IsTrue(m.Count == 2); + Assert.IsTrue(m["foo"].Equals("bar")); + Assert.IsTrue(m["jenny"].Equals(jenny), + "Map element 'jenny' should be equal to jenny object, not " + m["jenny"]); + } - [Test] - public void PopulatedSet() - { - IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); - XmlObjectFactory xof = new XmlObjectFactory(resource); - HasMap hasMap = (HasMap) xof.GetObject("set"); - Assert.IsTrue(hasMap.Set.Count == 3); - Assert.IsTrue(hasMap.Set.Contains("bar")); - TestObject jenny = (TestObject) xof.GetObject("jenny"); - Assert.IsTrue(hasMap.Set.Contains(jenny)); - Assert.IsTrue(hasMap.Set.Contains(null)); - } + [Test] + public void EmptySet() + { + IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); + XmlObjectFactory xof = new XmlObjectFactory(resource); + HasMap hasMap = (HasMap) xof.GetObject("emptySet"); + Assert.IsTrue(hasMap.Set.Count == 0); + } - [Test] - public void EmptyProps() - { - IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); - XmlObjectFactory xof = new XmlObjectFactory(resource); - HasMap hasMap = (HasMap) xof.GetObject("emptyProps"); - Assert.IsTrue(hasMap.Props.Count == 0); - } + [Test] + public void PopulatedSet() + { + IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); + XmlObjectFactory xof = new XmlObjectFactory(resource); + HasMap hasMap = (HasMap) xof.GetObject("set"); + Assert.IsTrue(hasMap.Set.Count == 3); + Assert.IsTrue(hasMap.Set.Contains("bar")); + TestObject jenny = (TestObject) xof.GetObject("jenny"); + Assert.IsTrue(hasMap.Set.Contains(jenny)); + Assert.IsTrue(hasMap.Set.Contains(null)); + } - /// - /// Test that an empty string value can be placed in a name-value collection - /// - [Test] - public void EmptyValue() - { - IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); - XmlObjectFactory xof = new XmlObjectFactory(resource); - HasMap hasMap = (HasMap) xof.GetObject("emptyValue"); - Assert.AreEqual("", hasMap.Props.Get("foo"), "Expected empty string"); - } + [Test] + public void EmptyProps() + { + IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); + XmlObjectFactory xof = new XmlObjectFactory(resource); + HasMap hasMap = (HasMap) xof.GetObject("emptyProps"); + Assert.IsTrue(hasMap.Props.Count == 0); + } - [Test] - public void PopulatedProps() - { - IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); - XmlObjectFactory xof = new XmlObjectFactory(resource); - HasMap hasMap = (HasMap) xof.GetObject("props"); - Assert.AreEqual(2, hasMap.Props.Count); - Assert.AreEqual("bar", hasMap.Props["foo"]); - Assert.AreEqual("TWO", hasMap.Props["2"]); - } + /// + /// Test that an empty string value can be placed in a name-value collection + /// + [Test] + public void EmptyValue() + { + IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); + XmlObjectFactory xof = new XmlObjectFactory(resource); + HasMap hasMap = (HasMap) xof.GetObject("emptyValue"); + Assert.AreEqual("", hasMap.Props.Get("foo"), "Expected empty string"); + } - [Test] - public void PopulatedPropsWithSameKey() - { - IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); - XmlObjectFactory xof = new XmlObjectFactory(resource); - HasMap hasMap = (HasMap) xof.GetObject("propsWithSameKey"); - Assert.AreEqual(2, hasMap.Props.Count); - Assert.AreEqual("OnE,tWo", hasMap.Props["foo"]); - Assert.AreEqual(2, hasMap.Props.GetValues("bar").Length); - Assert.AreEqual("OnE", hasMap.Props.GetValues("bar")[0]); - Assert.AreEqual("tWo", hasMap.Props.GetValues("bar")[1]); - } + [Test] + public void PopulatedProps() + { + IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); + XmlObjectFactory xof = new XmlObjectFactory(resource); + HasMap hasMap = (HasMap) xof.GetObject("props"); + Assert.AreEqual(2, hasMap.Props.Count); + Assert.AreEqual("bar", hasMap.Props["foo"]); + Assert.AreEqual("TWO", hasMap.Props["2"]); + } - [Test] - public void DelimitedProps() - { - IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); - XmlObjectFactory xof = new XmlObjectFactory(resource); - HasMap hasMap = (HasMap)xof.GetObject("delimitedProps"); - Assert.AreEqual(2, hasMap.Props.Count); - Assert.AreEqual(3, hasMap.Props.GetValues("foo").Length); - Assert.AreEqual(7, hasMap.Props.GetValues("days").Length); - Assert.AreEqual("wednesday", hasMap.Props.GetValues("days")[2]); - } - - [Test] - public void ObjectArray() - { - IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); - XmlObjectFactory xof = new XmlObjectFactory(resource); - HasMap hasMap = (HasMap) xof.GetObject("objectArray"); - Assert.IsTrue(hasMap.ObjectArray.Length == 2); - Assert.IsTrue(hasMap.ObjectArray[0].Equals("one")); - Assert.IsTrue(hasMap.ObjectArray[1].Equals(xof.GetObject("jenny"))); - } + [Test] + public void PopulatedPropsWithSameKey() + { + IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); + XmlObjectFactory xof = new XmlObjectFactory(resource); + HasMap hasMap = (HasMap) xof.GetObject("propsWithSameKey"); + Assert.AreEqual(2, hasMap.Props.Count); + Assert.AreEqual("OnE,tWo", hasMap.Props["foo"]); + Assert.AreEqual(2, hasMap.Props.GetValues("bar").Length); + Assert.AreEqual("OnE", hasMap.Props.GetValues("bar")[0]); + Assert.AreEqual("tWo", hasMap.Props.GetValues("bar")[1]); + } - [Test] - public void ClassArray() - { - IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); - XmlObjectFactory xof = new XmlObjectFactory(resource); - HasMap hasMap = (HasMap) xof.GetObject("classArray"); - Assert.IsTrue(hasMap.ClassArray.Length == 2); - Assert.IsTrue(hasMap.ClassArray[0].Equals(typeof (String))); - Assert.IsTrue(hasMap.ClassArray[1].Equals(typeof (Exception))); - } + [Test] + public void DelimitedProps() + { + IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); + XmlObjectFactory xof = new XmlObjectFactory(resource); + HasMap hasMap = (HasMap) xof.GetObject("delimitedProps"); + Assert.AreEqual(2, hasMap.Props.Count); + Assert.AreEqual(3, hasMap.Props.GetValues("foo").Length); + Assert.AreEqual(7, hasMap.Props.GetValues("days").Length); + Assert.AreEqual("wednesday", hasMap.Props.GetValues("days")[2]); + } - [Test] - public void GetDictionaryThatUsesEntryValueShortcut() - { - XmlObjectFactory xof = new XmlObjectFactory( - new ReadOnlyXmlTestResource("collections.xml", GetType())); - IDictionary map = (IDictionary) xof.GetObject("mapWithEntryValueShortcut"); - Assert.AreEqual(2, map.Count); - string v1 = (string) map["rob"]; - Assert.AreEqual("robert", v1); - string v2 = (string) map["jen"]; - Assert.AreEqual("jenny", v2); - } + [Test] + public void ObjectArray() + { + IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); + XmlObjectFactory xof = new XmlObjectFactory(resource); + HasMap hasMap = (HasMap) xof.GetObject("objectArray"); + Assert.IsTrue(hasMap.ObjectArray.Length == 2); + Assert.IsTrue(hasMap.ObjectArray[0].Equals("one")); + Assert.IsTrue(hasMap.ObjectArray[1].Equals(xof.GetObject("jenny"))); + } - [Test] - public void GetDictionaryThatUsesStringKeysSpecifiedAsElements() - { - XmlObjectFactory xof = new XmlObjectFactory( - new ReadOnlyXmlTestResource("collections.xml", GetType())); - IDictionary map = (IDictionary) xof.GetObject("mapWithStringKeysSpecifiedAsElements"); - Assert.AreEqual(2, map.Count); - string v1 = (string) map["rick"]; - Assert.AreEqual("Rick Evans", v1); - string v2 = (string) map["uncleelvis"]; - Assert.AreEqual("Elvis Orten", v2); - } + [Test] + public void ClassArray() + { + IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); + XmlObjectFactory xof = new XmlObjectFactory(resource); + HasMap hasMap = (HasMap) xof.GetObject("classArray"); + Assert.IsTrue(hasMap.ClassArray.Length == 2); + Assert.IsTrue(hasMap.ClassArray[0].Equals(typeof(String))); + Assert.IsTrue(hasMap.ClassArray[1].Equals(typeof(Exception))); + } - [Test] - public void GetDictionaryThatDoesntSpecifyAnyKeyForAnEntry() - { - Assert.Throws(() => new StreamHelperDecorator(new StreamHelperCallback(_GetDictionaryThatDoesntSpecifyAnyKeyForAnEntry)).Run()); - } + [Test] + public void GetDictionaryThatUsesEntryValueShortcut() + { + XmlObjectFactory xof = new XmlObjectFactory( + new ReadOnlyXmlTestResource("collections.xml", GetType())); + IDictionary map = (IDictionary) xof.GetObject("mapWithEntryValueShortcut"); + Assert.AreEqual(2, map.Count); + string v1 = (string) map["rob"]; + Assert.AreEqual("robert", v1); + string v2 = (string) map["jen"]; + Assert.AreEqual("jenny", v2); + } - private void _GetDictionaryThatDoesntSpecifyAnyKeyForAnEntry(out Stream stream) - { - const string xml = - @" + [Test] + public void GetDictionaryThatUsesStringKeysSpecifiedAsElements() + { + XmlObjectFactory xof = new XmlObjectFactory( + new ReadOnlyXmlTestResource("collections.xml", GetType())); + IDictionary map = (IDictionary) xof.GetObject("mapWithStringKeysSpecifiedAsElements"); + Assert.AreEqual(2, map.Count); + string v1 = (string) map["rick"]; + Assert.AreEqual("Rick Evans", v1); + string v2 = (string) map["uncleelvis"]; + Assert.AreEqual("Elvis Orten", v2); + } + + [Test] + public void GetDictionaryThatDoesntSpecifyAnyKeyForAnEntry() + { + Assert.Throws(() => new StreamHelperDecorator(new StreamHelperCallback(_GetDictionaryThatDoesntSpecifyAnyKeyForAnEntry)).Run()); + } + + private void _GetDictionaryThatDoesntSpecifyAnyKeyForAnEntry(out Stream stream) + { + const string xml = + @" @@ -543,248 +544,247 @@ namespace Spring.Objects.Factory.Xml "; - stream = new MemoryStream(Encoding.UTF8.GetBytes(xml)); - new XmlObjectFactory(new InputStreamResource(stream, "")); - Assert.Fail("Must have failed to parse element with no key."); - } + stream = new MemoryStream(Encoding.UTF8.GetBytes(xml)); + new XmlObjectFactory(new InputStreamResource(stream, "")); + Assert.Fail("Must have failed to parse element with no key."); + } - [Test] - public void GetDictionaryWithKeyRefAttributeShortcuts() - { - XmlObjectFactory xof = new XmlObjectFactory( - new ReadOnlyXmlTestResource("collections.xml", GetType())); - IDictionary map = (IDictionary) xof.GetObject("mapWithKeyRefAttributeShortcuts"); - Assert.AreEqual(2, map.Count); - string v1 = (string) map[new TestObject("Rick Evans", 30)]; - Assert.AreEqual("Rick Evans", v1); - string v2 = (string) map[new TestObject("Uncle Elvis", 47)]; - Assert.AreEqual("Elvis Orten", v2); - } + [Test] + public void GetDictionaryWithKeyRefAttributeShortcuts() + { + XmlObjectFactory xof = new XmlObjectFactory( + new ReadOnlyXmlTestResource("collections.xml", GetType())); + IDictionary map = (IDictionary) xof.GetObject("mapWithKeyRefAttributeShortcuts"); + Assert.AreEqual(2, map.Count); + string v1 = (string) map[new TestObject("Rick Evans", 30)]; + Assert.AreEqual("Rick Evans", v1); + string v2 = (string) map[new TestObject("Uncle Elvis", 47)]; + Assert.AreEqual("Elvis Orten", v2); + } - [Test] - public void GetDictionaryWithValueRefAttributeShortcuts() + [Test] + public void GetDictionaryWithValueRefAttributeShortcuts() + { + XmlObjectFactory xof = new XmlObjectFactory( + new ReadOnlyXmlTestResource("collections.xml", GetType())); + IDictionary map = (IDictionary) xof.GetObject("mapWithValueRefAttributeShortcuts"); + Assert.AreEqual(2, map.Count); + foreach (string key in map.Keys) { - XmlObjectFactory xof = new XmlObjectFactory( - new ReadOnlyXmlTestResource("collections.xml", GetType())); - IDictionary map = (IDictionary) xof.GetObject("mapWithValueRefAttributeShortcuts"); - Assert.AreEqual(2, map.Count); - foreach(string key in map.Keys) + object obj = map[key]; + Assert.IsNotNull(obj); + Assert.AreEqual(typeof(TestObject), obj.GetType(), "Wrong value assigned to value of dictionary."); + TestObject tob = (TestObject) obj; + if (key == "rick") { - object obj = map[key]; - Assert.IsNotNull(obj); - Assert.AreEqual(typeof(TestObject), obj.GetType(), "Wrong value assigned to value of dictionary."); - TestObject tob = (TestObject) obj; - if(key == "rick") - { - Assert.AreEqual("Rick Evans", tob.Name, "Wrong object value assigned to the 'rick' key."); - } - else if(key == "uncleelvis") - { - Assert.AreEqual("Uncle Elvis", tob.Name, "Wrong object value assigned to the 'uncleelvis' key."); - } + Assert.AreEqual("Rick Evans", tob.Name, "Wrong object value assigned to the 'rick' key."); + } + else if (key == "uncleelvis") + { + Assert.AreEqual("Uncle Elvis", tob.Name, "Wrong object value assigned to the 'uncleelvis' key."); } } - - [Test] - public void CollectionFactoryDefaults() - { - ListFactoryObject listFactory = new ListFactoryObject(); - listFactory.SourceList = new ArrayList(); - listFactory.AfterPropertiesSet(); - Assert.IsTrue(listFactory.GetObject() is ArrayList); - - SetFactoryObject setFactory = new SetFactoryObject(); - setFactory.SourceSet = new HybridSet(); - setFactory.AfterPropertiesSet(); - Assert.IsTrue(setFactory.GetObject() is HybridSet); - - DictionaryFactoryObject dictionaryFactory = new DictionaryFactoryObject(); - dictionaryFactory.SourceDictionary = new Hashtable(); - dictionaryFactory.AfterPropertiesSet(); - Assert.IsTrue(dictionaryFactory.GetObject() is Hashtable); - } - - [Test] - public void ListFactory() - { - IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); - XmlObjectFactory xof = new XmlObjectFactory(resource); - IList list = (IList) xof.GetObject("listFactory"); - Assert.IsTrue(list is LinkedList); - Assert.IsTrue(list.Count == 2); - Assert.AreEqual("bar", list[0]); - Assert.AreEqual("jenny", list[1]); - } - - [Test] - public void PrototypeListFactory() - { - IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); - XmlObjectFactory xof = new XmlObjectFactory(resource); - IList list = (IList) xof.GetObject("pListFactory"); - Assert.IsTrue(list is LinkedList); - Assert.IsTrue(list.Count == 2); - Assert.AreEqual("bar", list[0]); - Assert.AreEqual("jenny", list[1]); - } - - [Test] - public void SetFactory() - { - IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); - XmlObjectFactory xof = new XmlObjectFactory(resource); - Set mySet = (Set) xof.GetObject("setFactory"); - Assert.IsTrue(mySet is HybridSet); - Assert.IsTrue(mySet.Count == 2); - Assert.IsTrue(mySet.Contains("bar")); - Assert.IsTrue(mySet.Contains("jenny")); - } - - [Test] - public void PrototypeSetFactory() - { - IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); - XmlObjectFactory xof = new XmlObjectFactory(resource); - Set mySet = (Set) xof.GetObject("pSetFactory"); - Assert.IsTrue(mySet is HybridSet); - Assert.IsTrue(mySet.Count == 2); - Assert.IsTrue(mySet.Contains("bar")); - Assert.IsTrue(mySet.Contains("jenny")); - } - - [Test] - public void DictionaryFactory() - { - IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); - XmlObjectFactory xof = new XmlObjectFactory(resource); - IDictionary map = (IDictionary) xof.GetObject("mapFactory"); - Assert.IsTrue(map.Count == 2); - Assert.AreEqual("bar", map["foo"]); - Assert.AreEqual("jenny", map["jen"]); - } - - [Test] - public void PrototypeDictionaryFactory() - { - IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); - XmlObjectFactory xof = new XmlObjectFactory(resource); - IDictionary map = (IDictionary) xof.GetObject("pMapFactory"); - Assert.IsTrue(map.Count == 2); - Assert.AreEqual("bar", map["foo"]); - Assert.AreEqual("jenny", map["jen"]); - } - - [Test] - public void GetDictionaryThatUsesNonStringKeys() - { - XmlObjectFactory xof = new XmlObjectFactory( - new ReadOnlyXmlTestResource("collections.xml", GetType())); - IDictionary map = (IDictionary) xof.GetObject("mapWithNonStringKeys"); - Assert.AreEqual(2, map.Count); - string v1 = (string) map[new TestObject("Rick Evans", 30)]; - Assert.AreEqual("Rick Evans", v1); - string v2 = (string) map[new TestObject("Uncle Elvis", 47)]; - Assert.AreEqual("Elvis Orten", v2); - } - - [Test] - public void TypedNonGenericList() - { - XmlObjectFactory xof = new XmlObjectFactory(new ReadOnlyXmlTestResource("collections.xml", GetType())); - NonGenericExpressionHolder obj = (NonGenericExpressionHolder) xof.GetObject("nonGenericExpressionHolder"); - Assert.AreEqual(2, obj[0].GetValue()); - Assert.AreEqual(8, obj[1].GetValue()); - Assert.AreEqual("ALEKSANDAR SEOVIC", obj[2].GetValue()); - Assert.IsTrue((bool) obj[3].GetValue()); - } - - [Test] - public void TypedNonGenericDictionary() - { - XmlObjectFactory xof = new XmlObjectFactory(new ReadOnlyXmlTestResource("collections.xml", GetType())); - NonGenericExpressionHolder obj = (NonGenericExpressionHolder)xof.GetObject("nonGenericExpressionHolder"); - Assert.AreEqual(2, obj["0"].GetValue()); - Assert.AreEqual(8, obj["1"].GetValue()); - Assert.AreEqual("ALEKSANDAR SEOVIC", obj["2"].GetValue()); - Assert.IsTrue((bool)obj["3"].GetValue()); - } - - [Test] - public void TypedGenericList() - { - XmlObjectFactory xof = new XmlObjectFactory(new ReadOnlyXmlTestResource("collections.xml", GetType())); - GenericExpressionHolder obj = (GenericExpressionHolder)xof.GetObject("genericExpressionHolder"); - Assert.AreEqual(2, obj[0].GetValue()); - Assert.AreEqual(8, obj[1].GetValue()); - Assert.AreEqual("ALEKSANDAR SEOVIC", obj[2].GetValue()); - Assert.IsTrue((bool)obj[3].GetValue()); - } - - [Test] - public void TypedGenericDictionary() - { - XmlObjectFactory xof = new XmlObjectFactory(new ReadOnlyXmlTestResource("collections.xml", GetType())); - GenericExpressionHolder obj = (GenericExpressionHolder)xof.GetObject("genericExpressionHolder"); - Assert.AreEqual(2, obj["0"].GetValue()); - Assert.AreEqual(8, obj["1"].GetValue()); - Assert.AreEqual("ALEKSANDAR SEOVIC", obj["2"].GetValue()); - Assert.IsTrue((bool)obj["3"].GetValue()); - } } - #region Helper classes - - public class NonGenericExpressionHolder + [Test] + public void CollectionFactoryDefaults() { - private IList expressionsList; - private IDictionary expressionsDictionary; + ListFactoryObject listFactory = new ListFactoryObject(); + listFactory.SourceList = new ArrayList(); + listFactory.AfterPropertiesSet(); + Assert.IsTrue(listFactory.GetObject() is ArrayList); - public IList ExpressionsList - { - set { this.expressionsList = value; } - } + SetFactoryObject setFactory = new SetFactoryObject(); + setFactory.SourceSet = new HybridSet(); + setFactory.AfterPropertiesSet(); + Assert.IsTrue(setFactory.GetObject() is HybridSet); - public IDictionary ExpressionsDictionary - { - set { this.expressionsDictionary = value; } - } - - public IExpression this[int index] - { - get { return (IExpression)this.expressionsList[index]; } - } - - public IExpression this[string key] - { - get { return (IExpression)this.expressionsDictionary[key]; } - } + DictionaryFactoryObject dictionaryFactory = new DictionaryFactoryObject(); + dictionaryFactory.SourceDictionary = new Hashtable(); + dictionaryFactory.AfterPropertiesSet(); + Assert.IsTrue(dictionaryFactory.GetObject() is Hashtable); } - public class GenericExpressionHolder + [Test] + public void ListFactory() { - private System.Collections.Generic.IList expressionsList; - private System.Collections.Generic.IDictionary expressionsDictionary; - - public System.Collections.Generic.IList ExpressionsList - { - set { this.expressionsList = value; } - } - - public System.Collections.Generic.IDictionary ExpressionsDictionary - { - set { this.expressionsDictionary = value; } - } - - public IExpression this[int index] - { - get { return this.expressionsList[index]; } - } - - public IExpression this[string key] - { - get { return this.expressionsDictionary[key]; } - } + IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); + XmlObjectFactory xof = new XmlObjectFactory(resource); + IList list = (IList) xof.GetObject("listFactory"); + Assert.IsTrue(list is LinkedList); + Assert.IsTrue(list.Count == 2); + Assert.AreEqual("bar", list[0]); + Assert.AreEqual("jenny", list[1]); + } + + [Test] + public void PrototypeListFactory() + { + IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); + XmlObjectFactory xof = new XmlObjectFactory(resource); + IList list = (IList) xof.GetObject("pListFactory"); + Assert.IsTrue(list is LinkedList); + Assert.IsTrue(list.Count == 2); + Assert.AreEqual("bar", list[0]); + Assert.AreEqual("jenny", list[1]); + } + + [Test] + public void SetFactory() + { + IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); + XmlObjectFactory xof = new XmlObjectFactory(resource); + Set mySet = (Set) xof.GetObject("setFactory"); + Assert.IsTrue(mySet is HybridSet); + Assert.IsTrue(mySet.Count == 2); + Assert.IsTrue(mySet.Contains("bar")); + Assert.IsTrue(mySet.Contains("jenny")); + } + + [Test] + public void PrototypeSetFactory() + { + IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); + XmlObjectFactory xof = new XmlObjectFactory(resource); + Set mySet = (Set) xof.GetObject("pSetFactory"); + Assert.IsTrue(mySet is HybridSet); + Assert.IsTrue(mySet.Count == 2); + Assert.IsTrue(mySet.Contains("bar")); + Assert.IsTrue(mySet.Contains("jenny")); + } + + [Test] + public void DictionaryFactory() + { + IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); + XmlObjectFactory xof = new XmlObjectFactory(resource); + IDictionary map = (IDictionary) xof.GetObject("mapFactory"); + Assert.IsTrue(map.Count == 2); + Assert.AreEqual("bar", map["foo"]); + Assert.AreEqual("jenny", map["jen"]); + } + + [Test] + public void PrototypeDictionaryFactory() + { + IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); + XmlObjectFactory xof = new XmlObjectFactory(resource); + IDictionary map = (IDictionary) xof.GetObject("pMapFactory"); + Assert.IsTrue(map.Count == 2); + Assert.AreEqual("bar", map["foo"]); + Assert.AreEqual("jenny", map["jen"]); + } + + [Test] + public void GetDictionaryThatUsesNonStringKeys() + { + XmlObjectFactory xof = new XmlObjectFactory( + new ReadOnlyXmlTestResource("collections.xml", GetType())); + IDictionary map = (IDictionary) xof.GetObject("mapWithNonStringKeys"); + Assert.AreEqual(2, map.Count); + string v1 = (string) map[new TestObject("Rick Evans", 30)]; + Assert.AreEqual("Rick Evans", v1); + string v2 = (string) map[new TestObject("Uncle Elvis", 47)]; + Assert.AreEqual("Elvis Orten", v2); + } + + [Test] + public void TypedNonGenericList() + { + XmlObjectFactory xof = new XmlObjectFactory(new ReadOnlyXmlTestResource("collections.xml", GetType())); + NonGenericExpressionHolder obj = (NonGenericExpressionHolder) xof.GetObject("nonGenericExpressionHolder"); + Assert.AreEqual(2, obj[0].GetValue()); + Assert.AreEqual(8, obj[1].GetValue()); + Assert.AreEqual("ALEKSANDAR SEOVIC", obj[2].GetValue()); + Assert.IsTrue((bool) obj[3].GetValue()); + } + + [Test] + public void TypedNonGenericDictionary() + { + XmlObjectFactory xof = new XmlObjectFactory(new ReadOnlyXmlTestResource("collections.xml", GetType())); + NonGenericExpressionHolder obj = (NonGenericExpressionHolder) xof.GetObject("nonGenericExpressionHolder"); + Assert.AreEqual(2, obj["0"].GetValue()); + Assert.AreEqual(8, obj["1"].GetValue()); + Assert.AreEqual("ALEKSANDAR SEOVIC", obj["2"].GetValue()); + Assert.IsTrue((bool) obj["3"].GetValue()); + } + + [Test] + public void TypedGenericList() + { + XmlObjectFactory xof = new XmlObjectFactory(new ReadOnlyXmlTestResource("collections.xml", GetType())); + GenericExpressionHolder obj = (GenericExpressionHolder) xof.GetObject("genericExpressionHolder"); + Assert.AreEqual(2, obj[0].GetValue()); + Assert.AreEqual(8, obj[1].GetValue()); + Assert.AreEqual("ALEKSANDAR SEOVIC", obj[2].GetValue()); + Assert.IsTrue((bool) obj[3].GetValue()); + } + + [Test] + public void TypedGenericDictionary() + { + XmlObjectFactory xof = new XmlObjectFactory(new ReadOnlyXmlTestResource("collections.xml", GetType())); + GenericExpressionHolder obj = (GenericExpressionHolder) xof.GetObject("genericExpressionHolder"); + Assert.AreEqual(2, obj["0"].GetValue()); + Assert.AreEqual(8, obj["1"].GetValue()); + Assert.AreEqual("ALEKSANDAR SEOVIC", obj["2"].GetValue()); + Assert.IsTrue((bool) obj["3"].GetValue()); } - - #endregion } + +#region Helper classes + +public class NonGenericExpressionHolder +{ + private IList expressionsList; + private IDictionary expressionsDictionary; + + public IList ExpressionsList + { + set { this.expressionsList = value; } + } + + public IDictionary ExpressionsDictionary + { + set { this.expressionsDictionary = value; } + } + + public IExpression this[int index] + { + get { return (IExpression) this.expressionsList[index]; } + } + + public IExpression this[string key] + { + get { return (IExpression) this.expressionsDictionary[key]; } + } +} + +public class GenericExpressionHolder +{ + private System.Collections.Generic.IList expressionsList; + private System.Collections.Generic.IDictionary expressionsDictionary; + + public System.Collections.Generic.IList ExpressionsList + { + set { this.expressionsList = value; } + } + + public System.Collections.Generic.IDictionary ExpressionsDictionary + { + set { this.expressionsDictionary = value; } + } + + public IExpression this[int index] + { + get { return this.expressionsList[index]; } + } + + public IExpression this[string key] + { + get { return this.expressionsDictionary[key]; } + } +} + +#endregion diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/XmlObjectDefinitionReaderTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/XmlObjectDefinitionReaderTests.cs index b038cb54..9e16e8a1 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/XmlObjectDefinitionReaderTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/XmlObjectDefinitionReaderTests.cs @@ -30,60 +30,57 @@ using Spring.Objects.Factory.Support; #endregion -namespace Spring.Objects.Factory.Xml +namespace Spring.Objects.Factory.Xml; + +/// +/// Unit tests for the XmlObjectDefinitionReader class. +/// +/// Rick Evans (.NET) +[TestFixture] +public class XmlObjectDefinitionReaderTests { - /// - /// Unit tests for the XmlObjectDefinitionReader class. - /// - /// Rick Evans (.NET) - [TestFixture] - public class XmlObjectDefinitionReaderTests + [Test] + public void Instantiation() { - [Test] - public void Instantiation() - { - XmlObjectDefinitionReader reader - = new XmlObjectDefinitionReader( - new DefaultListableObjectFactory()); - } + XmlObjectDefinitionReader reader + = new XmlObjectDefinitionReader( + new DefaultListableObjectFactory()); + } - [Test] - public void LoadObjectDefinitionsWithNullResource() - { - XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(new DefaultListableObjectFactory()); - Assert.Throws(() => reader.LoadObjectDefinitions((string) null)); - } + [Test] + public void LoadObjectDefinitionsWithNullResource() + { + XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(new DefaultListableObjectFactory()); + Assert.Throws(() => reader.LoadObjectDefinitions((string) null)); + } - [Test] - public void LoadObjectDefinitionsWithNonExistentResource() - { - XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(new DefaultListableObjectFactory()); - Assert.Throws(() => reader.LoadObjectDefinitions(new ReadOnlyXmlTestResource("/dev/null"))); - } + [Test] + public void LoadObjectDefinitionsWithNonExistentResource() + { + XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(new DefaultListableObjectFactory()); + Assert.Throws(() => reader.LoadObjectDefinitions(new ReadOnlyXmlTestResource("/dev/null"))); + } - [Test] - public void AutoRegistersAllWellknownNamespaceParsers_Common() + [Test] + public void AutoRegistersAllWellknownNamespaceParsers_Common() + { + string[] namespaces = { - string[] namespaces = - { - "http://www.springframework.net/tx", - "http://www.springframework.net/aop", - "http://www.springframework.net/db", - "http://www.springframework.net/database", + "http://www.springframework.net/tx", "http://www.springframework.net/aop", "http://www.springframework.net/db", "http://www.springframework.net/database", #if !NETCOREAPP "http://www.springframework.net/remoting", "http://www.springframework.net/nms", "http://www.springframework.net/nvelocity", #endif - "http://www.springframework.net/validation" - }; + "http://www.springframework.net/validation" + }; - foreach (string ns in namespaces) - { - Assert.IsNotNull(NamespaceParserRegistry.GetParser(ns), - string.Format("Parser for Namespace {0} could not be auto-registered.", ns)); - } + foreach (string ns in namespaces) + { + Assert.IsNotNull(NamespaceParserRegistry.GetParser(ns), + string.Format("Parser for Namespace {0} could not be auto-registered.", ns)); } + } #if !NETCOREAPP [Test] @@ -99,81 +96,80 @@ namespace Spring.Objects.Factory.Xml } #endif - [Test] - [Ignore("this test cannot co-exist with AutoRegistersAllWellknownNamespaceParsers b/c that test will have already loaded the Spring.Data ass'y")] - public void AutoRegistersWellknownNamespaceParser() + [Test] + [Ignore("this test cannot co-exist with AutoRegistersAllWellknownNamespaceParsers b/c that test will have already loaded the Spring.Data ass'y")] + public void AutoRegistersWellknownNamespaceParser() + { + try { - try + Assembly[] loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies(); + foreach (Assembly assembly in loadedAssemblies) { - Assembly[] loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies(); - foreach (Assembly assembly in loadedAssemblies) + if (assembly.GetName(true).Name.StartsWith("Spring.Data")) { - if (assembly.GetName(true).Name.StartsWith("Spring.Data")) - { - Assert.Fail("Spring.Data is already loaded - this test checks if it gets loaded during xml parsing"); - } + Assert.Fail("Spring.Data is already loaded - this test checks if it gets loaded during xml parsing"); } + } - NamespaceParserRegistry.Reset(); + NamespaceParserRegistry.Reset(); - DefaultListableObjectFactory of = new DefaultListableObjectFactory(); - XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(of); - reader.LoadObjectDefinitions(new StringResource( - @" + DefaultListableObjectFactory of = new DefaultListableObjectFactory(); + XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(of); + reader.LoadObjectDefinitions(new StringResource( + @" ")); - object apc = of.GetObject(AopNamespaceUtils.AUTO_PROXY_CREATOR_OBJECT_NAME); - Assert.NotNull(apc); - } - finally - { - NamespaceParserRegistry.Reset(); - } + object apc = of.GetObject(AopNamespaceUtils.AUTO_PROXY_CREATOR_OBJECT_NAME); + Assert.NotNull(apc); } - - [Test] - public void ThrowsOnUnknownNamespaceUri() + finally { NamespaceParserRegistry.Reset(); + } + } - DefaultListableObjectFactory of = new DefaultListableObjectFactory(); - XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(of); - Assert.Throws(() => reader.LoadObjectDefinitions(new StringResource( - @" + [Test] + public void ThrowsOnUnknownNamespaceUri() + { + NamespaceParserRegistry.Reset(); + + DefaultListableObjectFactory of = new DefaultListableObjectFactory(); + XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(of); + Assert.Throws(() => reader.LoadObjectDefinitions(new StringResource( + @" "))); - } + } - - [Test] - public void WhitespaceValuesArePreservedForValueAttribute() - { - DefaultListableObjectFactory of = new DefaultListableObjectFactory(); - XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(of); - reader.LoadObjectDefinitions(new StringResource( - @" + [Test] + public void WhitespaceValuesArePreservedForValueAttribute() + { + DefaultListableObjectFactory of = new DefaultListableObjectFactory(); + XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(of); + reader.LoadObjectDefinitions(new StringResource( + @" ")); - Assert.AreEqual(" \n\r\t", ((TestObject)of.GetObject("test")).Name); - } + Assert.AreEqual(" \n\r\t", ((TestObject) of.GetObject("test")).Name); + } - [Test] - public void WhitespaceValuesResultInEmptyStringForValueElement() - { - DefaultListableObjectFactory of = new DefaultListableObjectFactory(); - XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(of); - reader.LoadObjectDefinitions(new StringResource( - @" + [Test] + public void WhitespaceValuesResultInEmptyStringForValueElement() + { + DefaultListableObjectFactory of = new DefaultListableObjectFactory(); + XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(of); + reader.LoadObjectDefinitions(new StringResource( + @" @@ -186,119 +182,118 @@ namespace Spring.Objects.Factory.Xml ")); - Assert.AreEqual(string.Empty, ((TestObject)of.GetObject("test2")).Name); - Assert.AreEqual(string.Empty, ((TestObject)of.GetObject("test3")).Name); - Assert.AreEqual(string.Empty, ((TestObject)of.GetObject("test4")).Name); - } + Assert.AreEqual(string.Empty, ((TestObject) of.GetObject("test2")).Name); + Assert.AreEqual(string.Empty, ((TestObject) of.GetObject("test3")).Name); + Assert.AreEqual(string.Empty, ((TestObject) of.GetObject("test4")).Name); + } - - [Test] - public void WhitespaceValuesArePreservedForValueElementWhenSpaceIsSetToPreserve() - { - DefaultListableObjectFactory of = new DefaultListableObjectFactory(); - XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(of); - reader.LoadObjectDefinitions(new StringResource( - @" + [Test] + public void WhitespaceValuesArePreservedForValueElementWhenSpaceIsSetToPreserve() + { + DefaultListableObjectFactory of = new DefaultListableObjectFactory(); + XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(of); + reader.LoadObjectDefinitions(new StringResource( + @" ")); - Assert.AreEqual(" \n\r\t", ((TestObject)of.GetObject("test4")).Name); - } + Assert.AreEqual(" \n\r\t", ((TestObject) of.GetObject("test4")).Name); + } - [Test] - public void ThrowsObjectDefinitionStoreExceptionOnValidationError() + [Test] + public void ThrowsObjectDefinitionStoreExceptionOnValidationError() + { + try { - try - { - DefaultListableObjectFactory of = new DefaultListableObjectFactory(); - XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(of); - reader.LoadObjectDefinitions(new StringResource( - @" + DefaultListableObjectFactory of = new DefaultListableObjectFactory(); + XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(of); + reader.LoadObjectDefinitions(new StringResource( + @" ")); - Assert.Fail(); - } - catch (ObjectDefinitionStoreException ex) - { - Assert.IsTrue(ex.Message.IndexOf("Line 3 in XML document from violates the schema.") > -1); - } + Assert.Fail(); } - - [Test] - public void ThrowsObjectDefinitionStoreExceptionOnInvalidXml() + catch (ObjectDefinitionStoreException ex) { - try - { - DefaultListableObjectFactory of = new DefaultListableObjectFactory(); - XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(of); - reader.LoadObjectDefinitions(new StringResource( - @" + Assert.IsTrue(ex.Message.IndexOf("Line 3 in XML document from violates the schema.") > -1); + } + } + + [Test] + public void ThrowsObjectDefinitionStoreExceptionOnInvalidXml() + { + try + { + DefaultListableObjectFactory of = new DefaultListableObjectFactory(); + XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(of); + reader.LoadObjectDefinitions(new StringResource( + @" ")); - Assert.Fail(); - } - catch (ObjectDefinitionStoreException ex) + Assert.Fail(); + } + catch (ObjectDefinitionStoreException ex) + { + Assert.IsTrue(ex.Message.IndexOf("Line 4 in XML document from is not well formed.") > -1); + } + } + + #region ThrowsObjectDefinitionStoreExceptionOnErrorDuringObjectDefinitionRegistration Helper + + private class TestXmlObjectDefinitionReader : XmlObjectDefinitionReader + { + public TestXmlObjectDefinitionReader(IObjectDefinitionRegistry registry) + : base(registry) + { + } + + private class ThrowingObjectDefinitionDocumentReader : IObjectDefinitionDocumentReader + { + public void RegisterObjectDefinitions(XmlDocument doc, XmlReaderContext readerContext) { - Assert.IsTrue(ex.Message.IndexOf("Line 4 in XML document from is not well formed.") > -1); + throw new TestException("RegisterObjectDefinitions"); } } - #region ThrowsObjectDefinitionStoreExceptionOnErrorDuringObjectDefinitionRegistration Helper - - private class TestXmlObjectDefinitionReader : XmlObjectDefinitionReader + protected override IObjectDefinitionDocumentReader CreateObjectDefinitionDocumentReader() { - public TestXmlObjectDefinitionReader(IObjectDefinitionRegistry registry) - : base(registry) - { } - - private class ThrowingObjectDefinitionDocumentReader : IObjectDefinitionDocumentReader - { - public void RegisterObjectDefinitions(XmlDocument doc, XmlReaderContext readerContext) - { - throw new TestException("RegisterObjectDefinitions"); - } - } - - protected override IObjectDefinitionDocumentReader CreateObjectDefinitionDocumentReader() - { - return new ThrowingObjectDefinitionDocumentReader(); - } - + return new ThrowingObjectDefinitionDocumentReader(); } + } - #endregion + #endregion - [Test] - public void ThrowsObjectDefinitionStoreExceptionOnErrorDuringObjectDefinitionRegistration() - { - DefaultListableObjectFactory of = new DefaultListableObjectFactory(); - XmlObjectDefinitionReader reader = new TestXmlObjectDefinitionReader(of); - Assert.Throws(() => reader.LoadObjectDefinitions(new StringResource( - @" + [Test] + public void ThrowsObjectDefinitionStoreExceptionOnErrorDuringObjectDefinitionRegistration() + { + DefaultListableObjectFactory of = new DefaultListableObjectFactory(); + XmlObjectDefinitionReader reader = new TestXmlObjectDefinitionReader(of); + Assert.Throws(() => reader.LoadObjectDefinitions(new StringResource( + @" "))); - } + } - [Test] - public void ParsesNonDefaultNamespace() + [Test] + public void ParsesNonDefaultNamespace() + { + try { - try - { - NamespaceParserRegistry.Reset(); + NamespaceParserRegistry.Reset(); - DefaultListableObjectFactory of = new DefaultListableObjectFactory(); - XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(of); - reader.LoadObjectDefinitions(new StringResource( -@" + DefaultListableObjectFactory of = new DefaultListableObjectFactory(); + XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(of); + reader.LoadObjectDefinitions(new StringResource( + @" @@ -307,23 +302,23 @@ namespace Spring.Objects.Factory.Xml ")); - TestObject test2 = (TestObject)of.GetObject("test2"); - Assert.AreEqual(typeof(TestObject), test2.GetType()); - Assert.IsNotNull(test2.Sibling); - } - finally - { - NamespaceParserRegistry.Reset(); - } + TestObject test2 = (TestObject) of.GetObject("test2"); + Assert.AreEqual(typeof(TestObject), test2.GetType()); + Assert.IsNotNull(test2.Sibling); } - - [Test] - public void ParsesObjectAttributes() + finally { - DefaultListableObjectFactory of = new DefaultListableObjectFactory(); - XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(of); - reader.LoadObjectDefinitions(new StringResource( -@" + NamespaceParserRegistry.Reset(); + } + } + + [Test] + public void ParsesObjectAttributes() + { + DefaultListableObjectFactory of = new DefaultListableObjectFactory(); + XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(of); + reader.LoadObjectDefinitions(new StringResource( + @" ")); - AbstractObjectDefinition od1 = (AbstractObjectDefinition)of.GetObjectDefinition("test1"); - Assert.IsFalse(od1.IsSingleton); - Assert.IsTrue(od1.IsAbstract); - Assert.IsFalse(od1.IsLazyInit); + AbstractObjectDefinition od1 = (AbstractObjectDefinition) of.GetObjectDefinition("test1"); + Assert.IsFalse(od1.IsSingleton); + Assert.IsTrue(od1.IsAbstract); + Assert.IsFalse(od1.IsLazyInit); - AbstractObjectDefinition od2 = (AbstractObjectDefinition)of.GetObjectDefinition("test2"); - Assert.IsTrue(od2.IsSingleton); - Assert.IsFalse(od2.IsAbstract); - Assert.IsTrue(od2.IsLazyInit); - Assert.AreEqual(AutoWiringMode.No, od2.AutowireMode); - Assert.AreEqual("init", od2.InitMethodName); - Assert.AreEqual("destroy", od2.DestroyMethodName); - Assert.AreEqual(1, od2.DependsOn.Count); - Assert.AreEqual("test1", od2.DependsOn[0]); - Assert.AreEqual(DependencyCheckingMode.Simple, od2.DependencyCheck); - } + AbstractObjectDefinition od2 = (AbstractObjectDefinition) of.GetObjectDefinition("test2"); + Assert.IsTrue(od2.IsSingleton); + Assert.IsFalse(od2.IsAbstract); + Assert.IsTrue(od2.IsLazyInit); + Assert.AreEqual(AutoWiringMode.No, od2.AutowireMode); + Assert.AreEqual("init", od2.InitMethodName); + Assert.AreEqual("destroy", od2.DestroyMethodName); + Assert.AreEqual(1, od2.DependsOn.Count); + Assert.AreEqual("test1", od2.DependsOn[0]); + Assert.AreEqual(DependencyCheckingMode.Simple, od2.DependencyCheck); + } - [Test] - public void ParsesAutowireCandidate() - { - DefaultListableObjectFactory of = new DefaultListableObjectFactory(); - XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(of); - reader.LoadObjectDefinitions(new StringResource( -@" + [Test] + public void ParsesAutowireCandidate() + { + DefaultListableObjectFactory of = new DefaultListableObjectFactory(); + XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(of); + reader.LoadObjectDefinitions(new StringResource( + @" @@ -366,21 +361,19 @@ namespace Spring.Objects.Factory.Xml ")); - var od = (AbstractObjectDefinition)of.GetObjectDefinition("test1"); - Assert.That(od.IsAutowireCandidate, Is.True, "No attribute set should default to true"); + var od = (AbstractObjectDefinition) of.GetObjectDefinition("test1"); + Assert.That(od.IsAutowireCandidate, Is.True, "No attribute set should default to true"); - od = (AbstractObjectDefinition)of.GetObjectDefinition("test2"); - Assert.That(od.IsAutowireCandidate, Is.False, "Specifically attribute set to false should set to false"); + od = (AbstractObjectDefinition) of.GetObjectDefinition("test2"); + Assert.That(od.IsAutowireCandidate, Is.False, "Specifically attribute set to false should set to false"); - od = (AbstractObjectDefinition)of.GetObjectDefinition("test3"); - Assert.That(od.IsAutowireCandidate, Is.True, "Specifically attribute set to true should set to false"); + od = (AbstractObjectDefinition) of.GetObjectDefinition("test3"); + Assert.That(od.IsAutowireCandidate, Is.True, "Specifically attribute set to true should set to false"); - od = (AbstractObjectDefinition)of.GetObjectDefinition("test4"); - Assert.That(od.IsAutowireCandidate, Is.True, "Attribute set to default should check pattern and return true"); - - od = (AbstractObjectDefinition)of.GetObjectDefinition("test5"); - Assert.That(od.IsAutowireCandidate, Is.False, "Attribute set to default should check pattern and return false"); - } + od = (AbstractObjectDefinition) of.GetObjectDefinition("test4"); + Assert.That(od.IsAutowireCandidate, Is.True, "Attribute set to default should check pattern and return true"); + od = (AbstractObjectDefinition) of.GetObjectDefinition("test5"); + Assert.That(od.IsAutowireCandidate, Is.False, "Attribute set to default should check pattern and return false"); } -} \ No newline at end of file +} diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/XmlObjectDefinitionReaderTests_CustomSchema.xsd b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/XmlObjectDefinitionReaderTests_CustomSchema.xsd index 05cb42c6..29d2edfd 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/XmlObjectDefinitionReaderTests_CustomSchema.xsd +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/XmlObjectDefinitionReaderTests_CustomSchema.xsd @@ -1,21 +1,21 @@ + xmlns:brief="http://www.example.com/brief" + xmlns:xsd="http://www.w3.org/2001/XMLSchema" + elementFormDefault="qualified" + attributeFormDefault="unqualified"> + + + + + - - - - - - - + + - + diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/XmlObjectFactoryTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/XmlObjectFactoryTests.cs index 68cdff81..d03d6c6c 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/XmlObjectFactoryTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/XmlObjectFactoryTests.cs @@ -25,53 +25,52 @@ using System.Web.Services; using FakeItEasy; using Microsoft.Extensions.Logging.Abstractions; using NUnit.Framework; - using Spring.Core.IO; using Spring.Objects.Factory.Config; using Spring.Objects.Factory.Support; using Spring.Util; -namespace Spring.Objects.Factory.Xml +namespace Spring.Objects.Factory.Xml; + +/// +/// Unit tests for the XmlObjectFactory class. +/// +/// +///

+/// There are actually a lot of integration tests in this class too. +///

+///
+/// Juergen Hoeller +/// Rick Evans (.NET) +[TestFixture] +public sealed class XmlObjectFactoryTests { /// - /// Unit tests for the XmlObjectFactory class. + /// The setup logic executed before the execution of this test fixture. /// - /// - ///

- /// There are actually a lot of integration tests in this class too. - ///

- ///
- /// Juergen Hoeller - /// Rick Evans (.NET) - [TestFixture] - public sealed class XmlObjectFactoryTests + [OneTimeSetUp] + public void FixtureSetUp() { - /// - /// The setup logic executed before the execution of this test fixture. - /// - [OneTimeSetUp] - public void FixtureSetUp() - { - // enable (null appender) logging, to ensure that the logging code is exercised... - //XmlConfigurator.Configure(); - LogManager.LoggerFactory = NullLoggerFactory.Instance; - } + // enable (null appender) logging, to ensure that the logging code is exercised... + //XmlConfigurator.Configure(); + LogManager.LoggerFactory = NullLoggerFactory.Instance; + } - [SetUp] - public void SetUp() - { - } + [SetUp] + public void SetUp() + { + } - [Test] - public void ReplacedMethodWithNoReplacerObjectNameSpecified() - { - Assert.Throws(() => new StreamHelperDecorator(new StreamHelperCallback(_ReplacedMethodWithNoReplacerObjectNameSpecified)).Run()); - } + [Test] + public void ReplacedMethodWithNoReplacerObjectNameSpecified() + { + Assert.Throws(() => new StreamHelperDecorator(new StreamHelperCallback(_ReplacedMethodWithNoReplacerObjectNameSpecified)).Run()); + } - private void _ReplacedMethodWithNoReplacerObjectNameSpecified(out Stream stream) - { - const string xml = - @" + private void _ReplacedMethodWithNoReplacerObjectNameSpecified(out Stream stream) + { + const string xml = + @" @@ -79,20 +78,20 @@ namespace Spring.Objects.Factory.Xml "; - stream = new MemoryStream(Encoding.UTF8.GetBytes(xml)); - new XmlObjectFactory(new InputStreamResource(stream, string.Empty)); - } + stream = new MemoryStream(Encoding.UTF8.GetBytes(xml)); + new XmlObjectFactory(new InputStreamResource(stream, string.Empty)); + } - [Test] - public void ReplacedMethodWithNoMethodNameSpecified() - { - Assert.Throws(() => new StreamHelperDecorator(new StreamHelperCallback(_ReplacedMethodWithNoMethodNameSpecified)).Run()); - } + [Test] + public void ReplacedMethodWithNoMethodNameSpecified() + { + Assert.Throws(() => new StreamHelperDecorator(new StreamHelperCallback(_ReplacedMethodWithNoMethodNameSpecified)).Run()); + } - private void _ReplacedMethodWithNoMethodNameSpecified(out Stream stream) - { - const string xml = - @" + private void _ReplacedMethodWithNoMethodNameSpecified(out Stream stream) + { + const string xml = + @" @@ -100,20 +99,20 @@ namespace Spring.Objects.Factory.Xml "; - stream = new MemoryStream(Encoding.UTF8.GetBytes(xml)); - new XmlObjectFactory(new InputStreamResource(stream, string.Empty)); - } + stream = new MemoryStream(Encoding.UTF8.GetBytes(xml)); + new XmlObjectFactory(new InputStreamResource(stream, string.Empty)); + } - [Test] - public void ValidatesReplacedMethodCorrectly() - { - Assert.Throws(() => new StreamHelperDecorator(new StreamHelperCallback(_ValidatesReplacedMethodCorrectly)).Run()); - } + [Test] + public void ValidatesReplacedMethodCorrectly() + { + Assert.Throws(() => new StreamHelperDecorator(new StreamHelperCallback(_ValidatesReplacedMethodCorrectly)).Run()); + } - private void _ValidatesReplacedMethodCorrectly(out Stream stream) - { - const string xml = - @" + private void _ValidatesReplacedMethodCorrectly(out Stream stream) + { + const string xml = + @" @@ -121,20 +120,20 @@ namespace Spring.Objects.Factory.Xml "; - stream = new MemoryStream(Encoding.UTF8.GetBytes(xml)); - new XmlObjectFactory(new InputStreamResource(stream, string.Empty)); - } + stream = new MemoryStream(Encoding.UTF8.GetBytes(xml)); + new XmlObjectFactory(new InputStreamResource(stream, string.Empty)); + } - [Test] - public void LookupMethodIsParsedAndOperatesCorrectly_SunnyDay() - { - new StreamHelperDecorator(new StreamHelperCallback(_LookupMethodIsParsedAndOperatesCorrectly_SunnyDay)).Run(); - } + [Test] + public void LookupMethodIsParsedAndOperatesCorrectly_SunnyDay() + { + new StreamHelperDecorator(new StreamHelperCallback(_LookupMethodIsParsedAndOperatesCorrectly_SunnyDay)).Run(); + } - private void _LookupMethodIsParsedAndOperatesCorrectly_SunnyDay(out Stream stream) - { - const string xml = - @" + private void _LookupMethodIsParsedAndOperatesCorrectly_SunnyDay(out Stream stream) + { + const string xml = + @" @@ -145,30 +144,30 @@ namespace Spring.Objects.Factory.Xml "; - stream = new MemoryStream(Encoding.UTF8.GetBytes(xml)); - IObjectFactory factory = new XmlObjectFactory(new InputStreamResource(stream, string.Empty)); - TestObjectFactory tof = (TestObjectFactory) factory["factory"]; - object to = tof.GetObject(); - Assert.IsNotNull(to); - Assert.AreEqual(typeof(TestObject), to.GetType()); - TestObject target = (TestObject) to; - Assert.AreEqual("Fiona Apple", target.Name); - Assert.AreEqual(47, target.Age); - // pull the prototype out again... - TestObject target2 = (TestObject) tof.GetObject(); - Assert.IsFalse(ReferenceEquals(target, target2)); - } + stream = new MemoryStream(Encoding.UTF8.GetBytes(xml)); + IObjectFactory factory = new XmlObjectFactory(new InputStreamResource(stream, string.Empty)); + TestObjectFactory tof = (TestObjectFactory) factory["factory"]; + object to = tof.GetObject(); + Assert.IsNotNull(to); + Assert.AreEqual(typeof(TestObject), to.GetType()); + TestObject target = (TestObject) to; + Assert.AreEqual("Fiona Apple", target.Name); + Assert.AreEqual(47, target.Age); + // pull the prototype out again... + TestObject target2 = (TestObject) tof.GetObject(); + Assert.IsFalse(ReferenceEquals(target, target2)); + } - [Test] - public void ValidatesLookupMethodCorrectly() - { - Assert.Throws(() => new StreamHelperDecorator(new StreamHelperCallback(_ValidatesLookupMethodCorrectly)).Run()); - } + [Test] + public void ValidatesLookupMethodCorrectly() + { + Assert.Throws(() => new StreamHelperDecorator(new StreamHelperCallback(_ValidatesLookupMethodCorrectly)).Run()); + } - private void _ValidatesLookupMethodCorrectly(out Stream stream) - { - const string xml = - @" + private void _ValidatesLookupMethodCorrectly(out Stream stream) + { + const string xml = + @" @@ -176,20 +175,20 @@ namespace Spring.Objects.Factory.Xml "; - stream = new MemoryStream(Encoding.UTF8.GetBytes(xml)); - new XmlObjectFactory(new InputStreamResource(stream, string.Empty)); - } + stream = new MemoryStream(Encoding.UTF8.GetBytes(xml)); + new XmlObjectFactory(new InputStreamResource(stream, string.Empty)); + } - [Test] - public void LookupMethodWithNoMethodNameSpecified() - { - Assert.Throws(() => new StreamHelperDecorator(new StreamHelperCallback(_LookupMethodWithNoMethodNameSpecified)).Run()); - } + [Test] + public void LookupMethodWithNoMethodNameSpecified() + { + Assert.Throws(() => new StreamHelperDecorator(new StreamHelperCallback(_LookupMethodWithNoMethodNameSpecified)).Run()); + } - private void _LookupMethodWithNoMethodNameSpecified(out Stream stream) - { - const string xml = - @" + private void _LookupMethodWithNoMethodNameSpecified(out Stream stream) + { + const string xml = + @" @@ -197,21 +196,21 @@ namespace Spring.Objects.Factory.Xml "; - stream = new MemoryStream(Encoding.UTF8.GetBytes(xml)); - IObjectFactory factory = new XmlObjectFactory(new InputStreamResource(stream, string.Empty)); - factory.GetObject("foo"); - } + stream = new MemoryStream(Encoding.UTF8.GetBytes(xml)); + IObjectFactory factory = new XmlObjectFactory(new InputStreamResource(stream, string.Empty)); + factory.GetObject("foo"); + } - [Test] - public void LookupMethodWithNoTargetObjectNameSpecified() - { - Assert.Throws(() => new StreamHelperDecorator(new StreamHelperCallback(_LookupMethodWithNoTargetObjectNameSpecified)).Run()); - } + [Test] + public void LookupMethodWithNoTargetObjectNameSpecified() + { + Assert.Throws(() => new StreamHelperDecorator(new StreamHelperCallback(_LookupMethodWithNoTargetObjectNameSpecified)).Run()); + } - private void _LookupMethodWithNoTargetObjectNameSpecified(out Stream stream) - { - const string xml = - @" + private void _LookupMethodWithNoTargetObjectNameSpecified(out Stream stream) + { + const string xml = + @" @@ -219,146 +218,146 @@ namespace Spring.Objects.Factory.Xml "; - stream = new MemoryStream(Encoding.UTF8.GetBytes(xml)); - IObjectFactory factory = new XmlObjectFactory(new InputStreamResource(stream, string.Empty)); - factory.GetObject("foo"); - } + stream = new MemoryStream(Encoding.UTF8.GetBytes(xml)); + IObjectFactory factory = new XmlObjectFactory(new InputStreamResource(stream, string.Empty)); + factory.GetObject("foo"); + } - [Test] - public void NonChildObjectDefinitionWithoutATypeReturnsObjectDefinition() - { - new StreamHelperDecorator(new StreamHelperCallback(_NonChildObjectDefinitionWithoutATypeReturnsObjectDefinition)).Run(); - } + [Test] + public void NonChildObjectDefinitionWithoutATypeReturnsObjectDefinition() + { + new StreamHelperDecorator(new StreamHelperCallback(_NonChildObjectDefinitionWithoutATypeReturnsObjectDefinition)).Run(); + } - private void _NonChildObjectDefinitionWithoutATypeReturnsObjectDefinition(out Stream stream) - { - const string xml = - @" + private void _NonChildObjectDefinitionWithoutATypeReturnsObjectDefinition(out Stream stream) + { + const string xml = + @" "; - stream = new MemoryStream(Encoding.UTF8.GetBytes(xml)); - IObjectFactory factory = new XmlObjectFactory(new InputStreamResource(stream, string.Empty)); - object obj = factory.GetObject("Applicationimpl"); - Assert.IsTrue(obj is IObjectDefinition); - } + stream = new MemoryStream(Encoding.UTF8.GetBytes(xml)); + IObjectFactory factory = new XmlObjectFactory(new InputStreamResource(stream, string.Empty)); + object obj = factory.GetObject("Applicationimpl"); + Assert.IsTrue(obj is IObjectDefinition); + } - [Test] - public void RegisterAliasViaAliasElement() - { - new StreamHelperDecorator(new StreamHelperCallback(_RegisterAliasViaAliasElement)).Run(); - } + [Test] + public void RegisterAliasViaAliasElement() + { + new StreamHelperDecorator(new StreamHelperCallback(_RegisterAliasViaAliasElement)).Run(); + } - private void _RegisterAliasViaAliasElement(out Stream stream) - { - const string xml = - @" + private void _RegisterAliasViaAliasElement(out Stream stream) + { + const string xml = + @" "; - stream = new MemoryStream(Encoding.UTF8.GetBytes(xml)); - IObjectFactory factory = new XmlObjectFactory(new InputStreamResource(stream, string.Empty)); - // pull object out of the factory using the alias name... - object foo = factory.GetObject("fooAlias"); - Assert.IsNotNull(foo, "Alias was obviously not registered otherwise we would not have got a null object back."); - } + stream = new MemoryStream(Encoding.UTF8.GetBytes(xml)); + IObjectFactory factory = new XmlObjectFactory(new InputStreamResource(stream, string.Empty)); + // pull object out of the factory using the alias name... + object foo = factory.GetObject("fooAlias"); + Assert.IsNotNull(foo, "Alias was obviously not registered otherwise we would not have got a null object back."); + } - [Test] - public void RegisterAliasViaAliasElementOrderingIsUnimportant() - { - new StreamHelperDecorator(new StreamHelperCallback(_RegisterAliasViaAliasElementOrderingIsUnimportant)).Run(); - } + [Test] + public void RegisterAliasViaAliasElementOrderingIsUnimportant() + { + new StreamHelperDecorator(new StreamHelperCallback(_RegisterAliasViaAliasElementOrderingIsUnimportant)).Run(); + } - private void _RegisterAliasViaAliasElementOrderingIsUnimportant(out Stream stream) - { - const string xml = - @" + private void _RegisterAliasViaAliasElementOrderingIsUnimportant(out Stream stream) + { + const string xml = + @" "; - stream = new MemoryStream(Encoding.UTF8.GetBytes(xml)); - IObjectFactory factory = new XmlObjectFactory(new InputStreamResource(stream, string.Empty)); - // pull object out of the factory using the alias name... - object foo = factory.GetObject("fooAlias"); - Assert.IsNotNull(foo, "Alias was obviously not registered otherwise we would not have got a null object back."); - } + stream = new MemoryStream(Encoding.UTF8.GetBytes(xml)); + IObjectFactory factory = new XmlObjectFactory(new InputStreamResource(stream, string.Empty)); + // pull object out of the factory using the alias name... + object foo = factory.GetObject("fooAlias"); + Assert.IsNotNull(foo, "Alias was obviously not registered otherwise we would not have got a null object back."); + } - [Test] - public void IfTypeAttributeIsPresentItMustNotBeTheEmptyStringValue() - { - Assert.Throws(() => new StreamHelperDecorator(new StreamHelperCallback(_IfTypeAttributeIsPresentItMustNotBeTheEmptyStringValue)).Run()); - } + [Test] + public void IfTypeAttributeIsPresentItMustNotBeTheEmptyStringValue() + { + Assert.Throws(() => new StreamHelperDecorator(new StreamHelperCallback(_IfTypeAttributeIsPresentItMustNotBeTheEmptyStringValue)).Run()); + } - private void _IfTypeAttributeIsPresentItMustNotBeTheEmptyStringValue(out Stream stream) - { - const string xml = - @" + private void _IfTypeAttributeIsPresentItMustNotBeTheEmptyStringValue(out Stream stream) + { + const string xml = + @" "; - stream = new MemoryStream(Encoding.UTF8.GetBytes(xml)); - IObjectFactory factory = new XmlObjectFactory(new InputStreamResource(stream, string.Empty)); - factory.GetObject("Applicationimpl"); - } + stream = new MemoryStream(Encoding.UTF8.GetBytes(xml)); + IObjectFactory factory = new XmlObjectFactory(new InputStreamResource(stream, string.Empty)); + factory.GetObject("Applicationimpl"); + } - [Test] - public void IfTypeAttributeIsPresentItMustNotBeAnOnlyWhitespaceStringValue() - { - Assert.Throws(() => new StreamHelperDecorator(new StreamHelperCallback(_IfTypeAttributeIsPresentItMustNotBeAnOnlyWhitespaceStringValue)).Run()); - } + [Test] + public void IfTypeAttributeIsPresentItMustNotBeAnOnlyWhitespaceStringValue() + { + Assert.Throws(() => new StreamHelperDecorator(new StreamHelperCallback(_IfTypeAttributeIsPresentItMustNotBeAnOnlyWhitespaceStringValue)).Run()); + } - private void _IfTypeAttributeIsPresentItMustNotBeAnOnlyWhitespaceStringValue(out Stream stream) - { - const string xml = - @" + private void _IfTypeAttributeIsPresentItMustNotBeAnOnlyWhitespaceStringValue(out Stream stream) + { + const string xml = + @" "; - stream = new MemoryStream(Encoding.UTF8.GetBytes(xml)); - IObjectFactory factory = new XmlObjectFactory(new InputStreamResource(stream, string.Empty)); - factory.GetObject("Applicationimpl"); - } + stream = new MemoryStream(Encoding.UTF8.GetBytes(xml)); + IObjectFactory factory = new XmlObjectFactory(new InputStreamResource(stream, string.Empty)); + factory.GetObject("Applicationimpl"); + } - [Test] - public void SimpleStringObject() - { - new StreamHelperDecorator(new StreamHelperCallback(_SimpleStringObject)).Run(); - } + [Test] + public void SimpleStringObject() + { + new StreamHelperDecorator(new StreamHelperCallback(_SimpleStringObject)).Run(); + } - private void _SimpleStringObject(out Stream stream) - { - const string xml = - @" + private void _SimpleStringObject(out Stream stream) + { + const string xml = + @" "; - stream = new MemoryStream(Encoding.UTF8.GetBytes(xml)); - IObjectFactory factory = new XmlObjectFactory(new InputStreamResource(stream, string.Empty)); - string myString = (string) factory["myString"]; - Assert.AreEqual("foo", myString); - } + stream = new MemoryStream(Encoding.UTF8.GetBytes(xml)); + IObjectFactory factory = new XmlObjectFactory(new InputStreamResource(stream, string.Empty)); + string myString = (string) factory["myString"]; + Assert.AreEqual("foo", myString); + } - [Test] - public void MethodInvokingFactoryObjectRefsObject() - { - new StreamHelperDecorator(new StreamHelperCallback(_MethodInvokingFactoryObjectRefsObject)).Run(); - } + [Test] + public void MethodInvokingFactoryObjectRefsObject() + { + new StreamHelperDecorator(new StreamHelperCallback(_MethodInvokingFactoryObjectRefsObject)).Run(); + } - private void _MethodInvokingFactoryObjectRefsObject(out Stream stream) - { - const string xml = - @" + private void _MethodInvokingFactoryObjectRefsObject(out Stream stream) + { + const string xml = + @" @@ -374,976 +373,970 @@ namespace Spring.Objects.Factory.Xml "; - stream = new MemoryStream(Encoding.UTF8.GetBytes(xml)); - IObjectFactory factory = new XmlObjectFactory(new InputStreamResource(stream, string.Empty)); - TestObject foo = (TestObject) factory["foo"]; - Assert.AreEqual("Bingo", foo.Name); - } + stream = new MemoryStream(Encoding.UTF8.GetBytes(xml)); + IObjectFactory factory = new XmlObjectFactory(new InputStreamResource(stream, string.Empty)); + TestObject foo = (TestObject) factory["foo"]; + Assert.AreEqual("Bingo", foo.Name); + } - [Test] - public void BadParentReference() - { - IResource resource = new ReadOnlyXmlTestResource("wellformed-but-bad.xml", GetType()); - XmlObjectFactory xof = new XmlObjectFactory(resource); - Assert.Throws(() => xof.GetObject("no.parent.factory")); - } + [Test] + public void BadParentReference() + { + IResource resource = new ReadOnlyXmlTestResource("wellformed-but-bad.xml", GetType()); + XmlObjectFactory xof = new XmlObjectFactory(resource); + Assert.Throws(() => xof.GetObject("no.parent.factory")); + } - [Test] - public void TypedStringValueIsPickedUp() - { - new StreamHelperDecorator(new StreamHelperCallback(_TypedStringValueIsPickedUp)).Run(); - } + [Test] + public void TypedStringValueIsPickedUp() + { + new StreamHelperDecorator(new StreamHelperCallback(_TypedStringValueIsPickedUp)).Run(); + } - private void _TypedStringValueIsPickedUp(out Stream stream) - { - const string xml = - @" + private void _TypedStringValueIsPickedUp(out Stream stream) + { + const string xml = + @" trilby,fedora "; - stream = new MemoryStream(Encoding.UTF8.GetBytes(xml)); - XmlObjectFactory fac = new XmlObjectFactory(new InputStreamResource(stream, string.Empty)); - IObjectDefinition def = fac.GetObjectDefinition("golyadkin"); - PropertyValue value = def.PropertyValues.GetPropertyValue("Hats"); - Assert.AreEqual(typeof(TypedStringValue), value.Value.GetType()); - TestObject obj = (TestObject) fac.GetObject("golyadkin"); - Assert.IsTrue(ArrayUtils.AreEqual(new string[] {"trilby", "fedora"}, obj.Hats)); - } + stream = new MemoryStream(Encoding.UTF8.GetBytes(xml)); + XmlObjectFactory fac = new XmlObjectFactory(new InputStreamResource(stream, string.Empty)); + IObjectDefinition def = fac.GetObjectDefinition("golyadkin"); + PropertyValue value = def.PropertyValues.GetPropertyValue("Hats"); + Assert.AreEqual(typeof(TypedStringValue), value.Value.GetType()); + TestObject obj = (TestObject) fac.GetObject("golyadkin"); + Assert.IsTrue(ArrayUtils.AreEqual(new string[] { "trilby", "fedora" }, obj.Hats)); + } - [Test] - public void ChildDefinitionWithoutIdOrNameOrALiasGetsOneAutogenerated() - { - new StreamHelperDecorator(new StreamHelperCallback(_ChildDefinitionWithoutIdOrNameOrALiasGetsOneAutogenerated)).Run(); - } + [Test] + public void ChildDefinitionWithoutIdOrNameOrALiasGetsOneAutogenerated() + { + new StreamHelperDecorator(new StreamHelperCallback(_ChildDefinitionWithoutIdOrNameOrALiasGetsOneAutogenerated)).Run(); + } - private void _ChildDefinitionWithoutIdOrNameOrALiasGetsOneAutogenerated(out Stream stream) - { - const string xml = - @" + private void _ChildDefinitionWithoutIdOrNameOrALiasGetsOneAutogenerated(out Stream stream) + { + const string xml = + @" "; - stream = new MemoryStream(Encoding.UTF8.GetBytes(xml)); - XmlObjectFactory factory = new XmlObjectFactory(new InputStreamResource(stream, string.Empty)); - var names = factory.GetObjectDefinitionNames(); - // mmm, how is one to test this? I have no idea what the generated name is... - Assert.AreEqual(2, names.Count, "Should have got two object names, one of which is autogenerated."); - } + stream = new MemoryStream(Encoding.UTF8.GetBytes(xml)); + XmlObjectFactory factory = new XmlObjectFactory(new InputStreamResource(stream, string.Empty)); + var names = factory.GetObjectDefinitionNames(); + // mmm, how is one to test this? I have no idea what the generated name is... + Assert.AreEqual(2, names.Count, "Should have got two object names, one of which is autogenerated."); + } - /// - /// Tests for the issue described at SPRNET-83. Schema modded to allow - /// zero elements (where previously there HAD to be at least one). - /// - [Test] - public void AnObjectsFileWithNoObjectsIsOk() + /// + /// Tests for the issue described at SPRNET-83. Schema modded to allow + /// zero elements (where previously there HAD to be at least one). + /// + [Test] + public void AnObjectsFileWithNoObjectsIsOk() + { + // test just makes sure that no exception is thrown and that + // said container doesn't complain about having no objects. + IResource resource = new ReadOnlyXmlTestResource("no-objects.xml", GetType()); + new XmlObjectFactory(resource); + } + + [Test] + public void ImportsExternalResourcesCorrectly() + { + IResource resource = new ReadOnlyXmlTestResource("external-resources.xml", GetType()); + XmlObjectFactory xof = new XmlObjectFactory(resource); + // object comes from imported file... + ITestObject rick = xof["rick"] as ITestObject; + Assert.IsNotNull(rick); + Assert.AreEqual("Rick", rick.Name); + // object comes from base file... + ITestObject jenny = xof["jenny"] as ITestObject; + Assert.IsNotNull(jenny); + Assert.AreEqual("Jenny", jenny.Name); + } + + [Test] + public void ImportsExternalResourcesBailsOnNonExistentResource() + { + IResource resource = new ReadOnlyXmlTestResource("bad-external-resources.xml", GetType()); + Assert.Throws(() => new XmlObjectFactory(resource)); + } + + [Test] + public void PropertyInvokingFactoryObjectIsWiredCorrectly() + { + IResource resource = new ReadOnlyXmlTestResource("invoke-factory.xml", GetType()); + XmlObjectFactory xof = new XmlObjectFactory(resource); + TestObject actual = xof["culturalObject"] as TestObject; + object expected = CultureInfo.InstalledUICulture; + Assert.AreEqual(expected, actual.MyCulture); + } + + [Test] + public void LoadFromConfig() + { + IObjectFactory factory = ConfigurationUtils.GetSection("objects") as IObjectFactory; + + Assert.IsNotNull(factory, "Factory loaded from config was null."); + Assert.IsTrue(factory is IConfigurableListableObjectFactory); + IConfigurableListableObjectFactory clof + = factory as IConfigurableListableObjectFactory; + Assert.IsTrue(clof.ObjectDefinitionCount == 6); + Assert.IsNotNull(factory["foo"]); + } + + [Test] + public void DescriptionButNoProperties() + { + DefaultListableObjectFactory xof = new DefaultListableObjectFactory(); + XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(xof); + reader.LoadObjectDefinitions( + new ReadOnlyXmlTestResource("collections.xml", GetType())); + TestObject validEmpty + = (TestObject) xof.GetObject("validEmptyWithDescription"); + Assert.AreEqual(0, validEmpty.Age); + } + + /// + /// Uses a separate factory. + /// + [Test] + public void RefToSeparatePrototypeInstances() + { + DefaultListableObjectFactory xof = new DefaultListableObjectFactory(); + XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(xof); + reader.LoadObjectDefinitions(new ReadOnlyXmlTestResource("reftypes.xml", GetType())); + Assert.IsTrue(xof.ObjectDefinitionCount == 9, "9 objects in reftypes, not " + xof.ObjectDefinitionCount); + TestObject emma = (TestObject) xof.GetObject("emma"); + TestObject georgia = (TestObject) xof.GetObject("georgia"); + ITestObject emmasJenks = emma.Spouse; + ITestObject georgiasJenks = georgia.Spouse; + Assert.IsTrue(emmasJenks != georgiasJenks, "Emma and georgia think they have a different boyfriend."); + Assert.IsTrue(emmasJenks.Name.Equals("Andrew"), "Emmas jenks has right name"); + Assert.IsTrue(emmasJenks != xof.GetObject("jenks"), "Emmas doesn't equal new ref."); + Assert.IsTrue(emmasJenks.Name.Equals("Andrew"), "Georgias jenks has right name."); + Assert.IsTrue(emmasJenks.Equals(georgiasJenks), "They are object equal."); + Assert.IsTrue(emmasJenks.Equals(xof.GetObject("jenks")), "They object equal direct ref."); + } + + [Test] + public void RefToSingleton() + { + DefaultListableObjectFactory xof = new DefaultListableObjectFactory(); + XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(xof); + reader.LoadObjectDefinitions(new ReadOnlyXmlTestResource("reftypes.xml", GetType())); + Assert.IsTrue(xof.ObjectDefinitionCount == 9, "9 objects in reftypes, not " + xof.ObjectDefinitionCount); + TestObject jen = (TestObject) xof.GetObject("jenny"); + TestObject dave = (TestObject) xof.GetObject("david"); + TestObject jenks = (TestObject) xof.GetObject("jenks"); + ITestObject davesJen = dave.Spouse; + ITestObject jenksJen = jenks.Spouse; + Assert.IsTrue(davesJen == jenksJen, "1 jen instance"); + Assert.IsTrue(davesJen == jen, "1 jen instance"); + } + + [Test] + public void InnerObjects() + { + DefaultListableObjectFactory xof = new DefaultListableObjectFactory(); + XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(xof); + reader.LoadObjectDefinitions(new ReadOnlyXmlTestResource("reftypes.xml", GetType())); + + // Let's create the outer bean named "innerObject", + // to check whether it doesn't create any conflicts + // with the actual inner object named "innerObject". + xof.GetObject("innerObject"); + + TestObject hasInnerObjects = (TestObject) xof.GetObject("hasInnerObjects"); + Assert.AreEqual(5, hasInnerObjects.Age); + TestObject inner1 = (TestObject) hasInnerObjects.Spouse; + Assert.IsNotNull(inner1); + Assert.AreEqual("Spring.Objects.TestObject#", inner1.ObjectName.Substring(0, inner1.ObjectName.IndexOf("#") + 1)); + Assert.AreEqual("inner1", inner1.Name); + Assert.AreEqual(6, inner1.Age); + + Assert.IsNotNull(hasInnerObjects.Friends); + IList friends = (IList) hasInnerObjects.Friends; + Assert.AreEqual(2, friends.Count); + DerivedTestObject inner2 = (DerivedTestObject) friends[0]; + Assert.AreEqual("inner2", inner2.Name); + Assert.AreEqual(7, inner2.Age); + Assert.AreEqual("Spring.Objects.DerivedTestObject#", inner2.ObjectName.Substring(0, inner2.ObjectName.IndexOf("#") + 1)); + TestObject innerFactory = (TestObject) friends[1]; + Assert.AreEqual(DummyFactory.SINGLETON_NAME, innerFactory.Name); + + Assert.IsNotNull(hasInnerObjects.SomeMap); + Assert.IsFalse((hasInnerObjects.SomeMap.Count == 0)); + TestObject inner3 = (TestObject) hasInnerObjects.SomeMap["someKey"]; + Assert.AreEqual("Jenny", inner3.Name); + Assert.AreEqual(30, inner3.Age); + xof.Dispose(); + Assert.IsTrue(inner2.WasDestroyed()); + Assert.IsTrue(innerFactory.Name == null); + } + + [Test] + public void InnerObjectsInPrototype() + { + DefaultListableObjectFactory xof = new DefaultListableObjectFactory(); + XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(xof); + reader.LoadObjectDefinitions(new ReadOnlyXmlTestResource("reftypes.xml", GetType())); + TestObject hasInnerObjects = (TestObject) xof.GetObject("prototypeHasInnerObjects"); + Assert.AreEqual(5, hasInnerObjects.Age); + + Assert.IsNotNull(hasInnerObjects.Spouse); + Assert.AreEqual("inner1", hasInnerObjects.Spouse.Name); + Assert.AreEqual(6, hasInnerObjects.Spouse.Age); + Assert.IsNotNull(hasInnerObjects.Friends); + IList friends = (IList) hasInnerObjects.Friends; + Assert.AreEqual(2, friends.Count); + DerivedTestObject inner2 = (DerivedTestObject) friends[0]; + Assert.AreEqual("inner2", inner2.Name); + Assert.AreEqual(7, inner2.Age); + + IList friendsOfInner = (IList) inner2.Friends; + Assert.AreEqual(1, friendsOfInner.Count); + DerivedTestObject innerFriendOfAFriend = (DerivedTestObject) friendsOfInner[0]; + Assert.AreEqual("innerFriendOfAFriend", innerFriendOfAFriend.Name); + Assert.AreEqual(7, innerFriendOfAFriend.Age); + TestObject innerFactory = (TestObject) friends[1]; + Assert.AreEqual(DummyFactory.SINGLETON_NAME, innerFactory.Name); + Assert.IsNotNull(hasInnerObjects.SomeMap); + Assert.IsFalse((hasInnerObjects.SomeMap.Count == 0)); + + TestObject inner3 = (TestObject) hasInnerObjects.SomeMap["someKey"]; + Assert.AreEqual("inner3", inner3.Name); + Assert.AreEqual(8, inner3.Age); + xof.Dispose(); + + Assert.IsFalse(inner2.WasDestroyed()); + Assert.IsFalse(innerFactory.Name == null); + Assert.IsFalse(innerFriendOfAFriend.WasDestroyed()); + } + + [Test] + public void SingletonInheritanceFromParentFactorySingleton() + { + XmlObjectFactory parent = new XmlObjectFactory(new ReadOnlyXmlTestResource("parent.xml", GetType())); + XmlObjectFactory child = new XmlObjectFactory(new ReadOnlyXmlTestResource("child.xml", GetType()), parent); + TestObject inherits = (TestObject) child.GetObject("inheritsFromParentFactory"); + // Name property value is overriden + Assert.IsTrue(inherits.Name.Equals("override")); + // Age property is inherited from object in parent factory + Assert.IsTrue(inherits.Age == 1); + TestObject inherits2 = (TestObject) child.GetObject("inheritsFromParentFactory"); + Assert.AreSame(inherits2, inherits); + } + + [Test] + public void SingletonInheritanceFromParentFactorySingletonUsingCtor() + { + XmlObjectFactory parent = new XmlObjectFactory(new ReadOnlyXmlTestResource("parent.xml", GetType())); + XmlObjectFactory child = new XmlObjectFactory(new ReadOnlyXmlTestResource("child.xml", GetType()), parent); + TestObject inherits = (TestObject) child.GetObject("inheritsFromParentFactoryUsingCtor"); + // Name property value is overriden + Assert.IsTrue(inherits.Name.Equals("child-name")); + // Age property is inherited from object in parent factory + Assert.IsTrue(inherits.Age == 1); + TestObject inherits2 = (TestObject) child.GetObject("inheritsFromParentFactoryUsingCtor"); + Assert.AreSame(inherits2, inherits); + } + + [Test] + public void PrototypeInheritanceFromParentFactoryPrototype() + { + XmlObjectFactory parent = new XmlObjectFactory(new ReadOnlyXmlTestResource("parent.xml", GetType())); + XmlObjectFactory child = new XmlObjectFactory(new ReadOnlyXmlTestResource("child.xml", GetType()), parent); + TestObject inherits = (TestObject) child.GetObject("prototypeInheritsFromParentFactoryPrototype"); + // Name property value is overridden + Assert.IsTrue(inherits.Name.Equals("prototype-override")); + // Age property is inherited from object in parent factory + Assert.IsTrue(inherits.Age == 2); + TestObject inherits2 = (TestObject) child.GetObject("prototypeInheritsFromParentFactoryPrototype"); + Assert.AreNotSame(inherits2, inherits); + inherits2.Age = 13; + Assert.IsTrue(inherits2.Age == 13); + // Shouldn't have changed first instance + Assert.IsTrue(inherits.Age == 2); + } + + [Test] + public void PrototypeInheritanceFromParentFactorySingleton() + { + XmlObjectFactory parent = new XmlObjectFactory(new ReadOnlyXmlTestResource("parent.xml", GetType())); + XmlObjectFactory child = new XmlObjectFactory(new ReadOnlyXmlTestResource("child.xml", GetType()), parent); + TestObject inherits = (TestObject) child.GetObject("protoypeInheritsFromParentFactorySingleton"); + // Name property value is overridden + Assert.IsTrue(inherits.Name.Equals("prototypeOverridesInheritedSingleton")); + // Age property is inherited from object in parent factory + Assert.IsTrue(inherits.Age == 1); + TestObject inherits2 = (TestObject) child.GetObject("protoypeInheritsFromParentFactorySingleton"); + Assert.AreNotSame(inherits2, inherits); + inherits2.Age = 13; + Assert.IsTrue(inherits2.Age == 13); + // Shouldn't have changed first instance + Assert.IsTrue(inherits.Age == 1); + } + + [Test] + public void DependenciesMaterializeThis() + { + IResource resource = new ReadOnlyXmlTestResource("dependenciesmaterializethis.xml", GetType()); + XmlObjectFactory bf = new XmlObjectFactory(resource); + DummyBo bos = (DummyBo) bf.GetObject("boSingleton"); + DummyBo bop = (DummyBo) bf.GetObject("boPrototype"); + Assert.IsFalse(bos == bop); + Assert.AreEqual(bos.dao, bop.dao); + } + + [Test] + public void ChildOverridesParentObject() + { + XmlObjectFactory parent = new XmlObjectFactory(new ReadOnlyXmlTestResource("parent.xml", GetType())); + XmlObjectFactory child = new XmlObjectFactory(new ReadOnlyXmlTestResource("child.xml", GetType()), parent); + TestObject inherits = (TestObject) child.GetObject("inheritedTestObject"); + // Name property value is overridden + Assert.IsTrue(inherits.Name.Equals("overrideParentObject")); + // Age property is inherited from object in parent factory + Assert.IsTrue(inherits.Age == 1); + TestObject inherits2 = (TestObject) child.GetObject("inheritedTestObject"); + Assert.IsTrue(inherits2 == inherits); + } + + /// + /// Check that a prototype can't inherit from a bogus parent. + /// If a singleton does this the factory will fail to load. + /// + [Test] + public void BogusParentageFromParentFactory() + { + XmlObjectFactory parent = new XmlObjectFactory(new ReadOnlyXmlTestResource("parent.xml", GetType())); + XmlObjectFactory child = new XmlObjectFactory(new ReadOnlyXmlTestResource("child.xml", GetType()), parent); + Assert.Throws(() => child.GetObject("bogusParent")); + } + + /// + /// Note that prototype/singleton distinction is not inherited. + /// It's possible for a subclass singleton not to return independent + /// instances even if derived from a prototype + /// + [Test] + public void SingletonInheritsFromParentFactoryPrototype() + { + XmlObjectFactory parent = new XmlObjectFactory(new ReadOnlyXmlTestResource("parent.xml", GetType())); + XmlObjectFactory child = new XmlObjectFactory(new ReadOnlyXmlTestResource("child.xml", GetType()), parent); + TestObject inherits = (TestObject) child.GetObject("singletonInheritsFromParentFactoryPrototype"); + // Name property value is overriden + Assert.IsTrue(inherits.Name.Equals("prototype-override")); + // Age property is inherited from object in parent factory + Assert.IsTrue(inherits.Age == 2); + TestObject inherits2 = (TestObject) child.GetObject("singletonInheritsFromParentFactoryPrototype"); + Assert.IsTrue(inherits2 == inherits); + } + + [Test] + public void AbstractParentObjects() + { + XmlObjectFactory parent = new XmlObjectFactory(new ReadOnlyXmlTestResource("parent.xml", GetType())); + parent.PreInstantiateSingletons(); + Assert.IsTrue(parent.IsSingleton("inheritedTestObjectWithoutClass")); + + // abstract objects should not match + //TODO add overloaded GetObjectOfType with 1 arg + var tbs = parent.GetObjectsOfType(typeof(TestObject), true, true); + Assert.AreEqual(2, tbs.Count); + Assert.IsTrue(tbs.ContainsKey("inheritedTestObjectPrototype")); + Assert.IsTrue(tbs.ContainsKey("inheritedTestObjectSingleton")); + + // non-abstract object should work, even if it serves as parent + object o1 = parent.GetObject("inheritedTestObjectPrototype"); + Assert.IsTrue(o1 is TestObject); + + // abstract object should return IObjectInstance itself + object o2 = parent.GetObject("inheritedTestObjectWithoutClass"); + Assert.IsTrue(o2 is IObjectDefinition); + } + + [Test] + public void CircularReferences() + { + DefaultListableObjectFactory xof = new DefaultListableObjectFactory(); + XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(xof); + reader.LoadObjectDefinitions(new ReadOnlyXmlTestResource("reftypes.xml", GetType())); + TestObject jenny = (TestObject) xof.GetObject("jenny"); + TestObject david = (TestObject) xof.GetObject("david"); + TestObject ego = (TestObject) xof.GetObject("ego"); + Assert.IsTrue(jenny.Spouse == david, "Correct circular reference"); + Assert.IsTrue(david.Spouse == jenny, "Correct circular reference"); + Assert.IsTrue(ego.Spouse == ego, "Correct circular reference"); + } + + [Test] + public void FactoryReferenceCircle() + { + IResource resource = new ReadOnlyXmlTestResource("factorycircle.xml", GetType()); + XmlObjectFactory xof = new XmlObjectFactory(resource); + TestObject tb = (TestObject) xof.GetObject("singletonFactory"); + DummyFactory db = (DummyFactory) xof.GetObject("&singletonFactory"); + Assert.IsTrue(tb == db.OtherTestObject); + } + + [Test] + public void RefSubelement() + { + IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); + XmlObjectFactory xof = new XmlObjectFactory(resource); + //Assert.IsTrue ("5 objects in reftypes, not " + xof.GetObjectDefinitionCount(), xof.GetObjectDefinitionCount() == 5); + TestObject jen = (TestObject) xof.GetObject("jenny"); + TestObject dave = (TestObject) xof.GetObject("david"); + Assert.IsTrue(jen.Spouse == dave); + } + + [Test] + public void PropertyWithLiteralValueSubelement() + { + IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); + XmlObjectFactory xof = new XmlObjectFactory(resource); + TestObject verbose = (TestObject) xof.GetObject("verbose"); + Assert.IsTrue(verbose.Name.Equals("verbose")); + } + + [Test] + public void PropertyWithIdRefLocalAttrSubelement() + { + IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); + XmlObjectFactory xof = new XmlObjectFactory(resource); + TestObject verbose = (TestObject) xof.GetObject("verbose2"); + Assert.IsTrue(verbose.Name.Equals("verbose")); + } + + [Test] + public void PropertyWithIdRefObjectAttrSubelement() + { + IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); + XmlObjectFactory xof = new XmlObjectFactory(resource); + TestObject verbose = (TestObject) xof.GetObject("verbose3"); + Assert.IsTrue(verbose.Name.Equals("verbose")); + } + + [Test] + public void EnumProperty() + { + DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); + XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(factory); + reader.LoadObjectDefinitions(new ReadOnlyXmlTestResource("enums.xml", GetType())); + TestObject obj = factory.GetObject("rod", typeof(TestObject)) as TestObject; + Assert.IsNotNull(obj.FileMode); + Assert.AreEqual(FileMode.Create, obj.FileMode); + } + + [Test] + public void InitMethodIsInvoked() + { + IResource resource = new ReadOnlyXmlTestResource("initializers.xml", GetType()); + XmlObjectFactory xof = new XmlObjectFactory(resource); + DoubleInitializer in_Renamed = (DoubleInitializer) xof.GetObject("init-method1"); + // Initializer should have doubled value + Assert.AreEqual(14, in_Renamed.Num); + } + + [Test] + public void DefaultInitMethodIsInvoked() + { + IResource resource = new ReadOnlyXmlTestResource("default-initializers.xml", GetType()); + XmlObjectFactory xof = new XmlObjectFactory(resource); + DoubleInitializer in_Renamed = (DoubleInitializer) xof.GetObject("init-method1"); + // Initializer should have doubled value + Assert.AreEqual(14, in_Renamed.Num); + } + + [Test] + public void DefaultInitMethodDisabled() + { + IResource resource = new ReadOnlyXmlTestResource("default-initializers.xml", GetType()); + XmlObjectFactory xof = new XmlObjectFactory(resource); + DoubleInitializer in_Renamed = (DoubleInitializer) xof.GetObject("init-method2"); + // Initializer should have doubled value + Assert.AreEqual(7, in_Renamed.Num); + } + + /// + /// Test that if a custom initializer throws an exception, it's handled correctly. + /// + [Test] + public void InitMethodThrowsException() + { + IResource resource = new ReadOnlyXmlTestResource("initializers.xml", GetType()); + XmlObjectFactory xof = new XmlObjectFactory(resource); + try { - // test just makes sure that no exception is thrown and that - // said container doesn't complain about having no objects. - IResource resource = new ReadOnlyXmlTestResource("no-objects.xml", GetType()); - new XmlObjectFactory(resource); + xof.GetObject("init-method2"); + Assert.Fail(); } - - [Test] - public void ImportsExternalResourcesCorrectly() + catch (ObjectCreationException ex) { - IResource resource = new ReadOnlyXmlTestResource("external-resources.xml", GetType()); - XmlObjectFactory xof = new XmlObjectFactory(resource); - // object comes from imported file... - ITestObject rick = xof["rick"] as ITestObject; - Assert.IsNotNull(rick); - Assert.AreEqual("Rick", rick.Name); - // object comes from base file... - ITestObject jenny = xof["jenny"] as ITestObject; - Assert.IsNotNull(jenny); - Assert.AreEqual("Jenny", jenny.Name); + Assert.IsTrue(ex.InnerException is FormatException); } + } - [Test] - public void ImportsExternalResourcesBailsOnNonExistentResource() + [Test] + public void NoSuchInitMethod() + { + IResource resource = new ReadOnlyXmlTestResource("initializers.xml", GetType()); + XmlObjectFactory xof = new XmlObjectFactory(resource); + Assert.Throws(() => xof.GetObject("init-method3")); + } + + /// + /// Check that InitializingObject method is called first. + /// + [Test] + public void InitializingObjectAndInitMethod() + { + InitAndIB.constructed = false; + IResource resource = new ReadOnlyXmlTestResource("initializers.xml", GetType()); + XmlObjectFactory xof = new XmlObjectFactory(resource); + Assert.IsFalse(InitAndIB.constructed); + xof.PreInstantiateSingletons(); + Assert.IsFalse(InitAndIB.constructed); + InitAndIB iib = (InitAndIB) xof.GetObject("init-and-ib"); + Assert.IsTrue(InitAndIB.constructed); + Assert.IsTrue(iib.afterPropertiesSetInvoked && iib.initMethodInvoked); + Assert.IsTrue(!iib.destroyed && !iib.customDestroyed); + xof.Dispose(); + Assert.IsTrue(iib.destroyed && iib.customDestroyed); + xof.Dispose(); + Assert.IsTrue(iib.destroyed && iib.customDestroyed); + } + + [Test] + public void DefaultDestroyMethodInvoked() + { + IResource resource = new ReadOnlyXmlTestResource("default-destroy-methods.xml", GetType()); + XmlObjectFactory xof = new XmlObjectFactory(resource); + xof.PreInstantiateSingletons(); + DefaultDestroyer dd = (DefaultDestroyer) xof.GetObject("destroy-method1"); + Assert.IsTrue(!dd.customDestroyed); + xof.Dispose(); + Assert.IsTrue(dd.customDestroyed); + } + + [Test] + public void DefaultDestroyMethodDisabled() + { + IResource resource = new ReadOnlyXmlTestResource("default-destroy-methods.xml", GetType()); + XmlObjectFactory xof = new XmlObjectFactory(resource); + xof.PreInstantiateSingletons(); + DefaultDestroyer dd = (DefaultDestroyer) xof.GetObject("destroy-method2"); + Assert.IsTrue(!dd.customDestroyed); + xof.Dispose(); + Assert.IsTrue(!dd.customDestroyed); + } + + [Test] + public void MultiThreadedLazyInit() + { + IResource resource = new ReadOnlyXmlTestResource("lazy-init-multithreaded.xml", GetType()); + XmlObjectFactory xof = new XmlObjectFactory(resource); + + LazyWorker lw1 = new LazyWorker(xof); + LazyWorker lw2 = new LazyWorker(xof); + Thread thread1 = new Thread(lw1.DoWork); + Thread thread2 = new Thread(lw2.DoWork); + + thread1.Start(); + Thread.Sleep(1000); + thread2.Start(); + thread1.Join(); + thread2.Join(); + Assert.AreEqual(typeof(LazyTestObject), lw1.ObjectFromContext.GetType()); + Assert.AreEqual(typeof(LazyTestObject), lw2.ObjectFromContext.GetType()); + Assert.AreEqual(1, LazyTestObject.Count); + } + + /// + /// Check that InitializingObject method is called first. + /// + [Test] + public void DefaultLazyInit() + { + InitAndIB.constructed = false; + IResource resource = new ReadOnlyXmlTestResource("default-lazy-init.xml", GetType()); + XmlObjectFactory xof = new XmlObjectFactory(resource); + Assert.IsFalse(InitAndIB.constructed); + xof.PreInstantiateSingletons(); + Assert.IsTrue(InitAndIB.constructed); + try { - IResource resource = new ReadOnlyXmlTestResource("bad-external-resources.xml", GetType()); - Assert.Throws(() => new XmlObjectFactory(resource)); + xof.GetObject("lazy-and-bad"); } - - [Test] - public void PropertyInvokingFactoryObjectIsWiredCorrectly() + catch (ObjectCreationException ex) { - IResource resource = new ReadOnlyXmlTestResource("invoke-factory.xml", GetType()); - XmlObjectFactory xof = new XmlObjectFactory(resource); - TestObject actual = xof["culturalObject"] as TestObject; - object expected = CultureInfo.InstalledUICulture; - Assert.AreEqual(expected, actual.MyCulture); + Assert.IsTrue(ex.InnerException is FormatException); } + } - [Test] - public void LoadFromConfig() + /// + /// Check that InitializingObject method is called first. + /// + [Test] + public void DefaultLazyInitNoInObjectDef() + { + InitAndIB.constructed = false; + IResource resource = new ReadOnlyXmlTestResource("default-lazy-init.xml", GetType()); + XmlObjectFactory xof = new XmlObjectFactory(resource); + Assert.IsFalse(InitAndIB.constructed); + xof.PreInstantiateSingletons(); + Assert.IsTrue(InitAndIB.constructed); + try { - IObjectFactory factory = ConfigurationUtils.GetSection("objects") as IObjectFactory; - - Assert.IsNotNull(factory, "Factory loaded from config was null."); - Assert.IsTrue(factory is IConfigurableListableObjectFactory); - IConfigurableListableObjectFactory clof - = factory as IConfigurableListableObjectFactory; - Assert.IsTrue(clof.ObjectDefinitionCount == 6); - Assert.IsNotNull(factory["foo"]); + xof.GetObject("init-and-ib-no-init-in-local-object-def"); } - - [Test] - public void DescriptionButNoProperties() + catch (ObjectCreationException ex) { - DefaultListableObjectFactory xof = new DefaultListableObjectFactory(); - XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(xof); - reader.LoadObjectDefinitions( - new ReadOnlyXmlTestResource("collections.xml", GetType())); - TestObject validEmpty - = (TestObject) xof.GetObject("validEmptyWithDescription"); - Assert.AreEqual(0, validEmpty.Age); + Assert.IsTrue(ex.InnerException is FormatException); } + } - /// - /// Uses a separate factory. - /// - [Test] - public void RefToSeparatePrototypeInstances() + [Test] + public void NoSuchXmlFile() + { + Assert.Throws(() => new XmlObjectFactory(new ReadOnlyXmlTestResource("missing.xml", GetType()))); + } + + [Test] + public void InvalidXmlFile() + { + DefaultListableObjectFactory xof = new DefaultListableObjectFactory(); + XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(xof); + try { - DefaultListableObjectFactory xof = new DefaultListableObjectFactory(); - XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(xof); - reader.LoadObjectDefinitions(new ReadOnlyXmlTestResource("reftypes.xml", GetType())); - Assert.IsTrue(xof.ObjectDefinitionCount == 9, "9 objects in reftypes, not " + xof.ObjectDefinitionCount); - TestObject emma = (TestObject) xof.GetObject("emma"); - TestObject georgia = (TestObject) xof.GetObject("georgia"); - ITestObject emmasJenks = emma.Spouse; - ITestObject georgiasJenks = georgia.Spouse; - Assert.IsTrue(emmasJenks != georgiasJenks, "Emma and georgia think they have a different boyfriend."); - Assert.IsTrue(emmasJenks.Name.Equals("Andrew"), "Emmas jenks has right name"); - Assert.IsTrue(emmasJenks != xof.GetObject("jenks"), "Emmas doesn't equal new ref."); - Assert.IsTrue(emmasJenks.Name.Equals("Andrew"), "Georgias jenks has right name."); - Assert.IsTrue(emmasJenks.Equals(georgiasJenks), "They are object equal."); - Assert.IsTrue(emmasJenks.Equals(xof.GetObject("jenks")), "They object equal direct ref."); + reader.LoadObjectDefinitions(new ReadOnlyXmlTestResource("invalid.xml", GetType())); + Assert.Fail("Should have thrown XmlObjectDefinitionStoreException"); } - - [Test] - public void RefToSingleton() + catch (ObjectDefinitionStoreException e) { - DefaultListableObjectFactory xof = new DefaultListableObjectFactory(); - XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(xof); - reader.LoadObjectDefinitions(new ReadOnlyXmlTestResource("reftypes.xml", GetType())); - Assert.IsTrue(xof.ObjectDefinitionCount == 9, "9 objects in reftypes, not " + xof.ObjectDefinitionCount); - TestObject jen = (TestObject) xof.GetObject("jenny"); - TestObject dave = (TestObject) xof.GetObject("david"); - TestObject jenks = (TestObject) xof.GetObject("jenks"); - ITestObject davesJen = dave.Spouse; - ITestObject jenksJen = jenks.Spouse; - Assert.IsTrue(davesJen == jenksJen, "1 jen instance"); - Assert.IsTrue(davesJen == jen, "1 jen instance"); + Assert.AreEqual(0, e.Message.IndexOf("Line 21 in XML document")); } + } - - [Test] - public void InnerObjects() + [Test] + public void DefaultXmlResolverIsUsedIfNullSuppliedOrSet() + { + DefaultListableObjectFactory xof = new DefaultListableObjectFactory(); + XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(xof, null); + try { - DefaultListableObjectFactory xof = new DefaultListableObjectFactory(); - XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(xof); - reader.LoadObjectDefinitions(new ReadOnlyXmlTestResource("reftypes.xml", GetType())); - - // Let's create the outer bean named "innerObject", - // to check whether it doesn't create any conflicts - // with the actual inner object named "innerObject". - xof.GetObject("innerObject"); - - TestObject hasInnerObjects = (TestObject) xof.GetObject("hasInnerObjects"); - Assert.AreEqual(5, hasInnerObjects.Age); - TestObject inner1 = (TestObject) hasInnerObjects.Spouse; - Assert.IsNotNull(inner1); - Assert.AreEqual("Spring.Objects.TestObject#", inner1.ObjectName.Substring(0, inner1.ObjectName.IndexOf("#")+1)); - Assert.AreEqual("inner1", inner1.Name); - Assert.AreEqual(6, inner1.Age); - - - Assert.IsNotNull(hasInnerObjects.Friends); - IList friends = (IList) hasInnerObjects.Friends; - Assert.AreEqual(2, friends.Count); - DerivedTestObject inner2 = (DerivedTestObject) friends[0]; - Assert.AreEqual("inner2", inner2.Name); - Assert.AreEqual(7, inner2.Age); - Assert.AreEqual("Spring.Objects.DerivedTestObject#", inner2.ObjectName.Substring(0, inner2.ObjectName.IndexOf("#") + 1)); - TestObject innerFactory = (TestObject) friends[1]; - Assert.AreEqual(DummyFactory.SINGLETON_NAME, innerFactory.Name); - - - Assert.IsNotNull(hasInnerObjects.SomeMap); - Assert.IsFalse((hasInnerObjects.SomeMap.Count == 0)); - TestObject inner3 = (TestObject) hasInnerObjects.SomeMap["someKey"]; - Assert.AreEqual("Jenny", inner3.Name); - Assert.AreEqual(30, inner3.Age); - xof.Dispose(); - Assert.IsTrue(inner2.WasDestroyed()); - Assert.IsTrue(innerFactory.Name == null); + reader.LoadObjectDefinitions(new ReadOnlyXmlTestResource("invalid.xml", GetType())); + Assert.Fail("Should have thrown XmlObjectDefinitionStoreException"); } - - [Test] - public void InnerObjectsInPrototype() + catch (ObjectDefinitionStoreException e) { - DefaultListableObjectFactory xof = new DefaultListableObjectFactory(); - XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(xof); - reader.LoadObjectDefinitions(new ReadOnlyXmlTestResource("reftypes.xml", GetType())); - TestObject hasInnerObjects = (TestObject) xof.GetObject("prototypeHasInnerObjects"); - Assert.AreEqual(5, hasInnerObjects.Age); - - Assert.IsNotNull(hasInnerObjects.Spouse); - Assert.AreEqual("inner1", hasInnerObjects.Spouse.Name); - Assert.AreEqual(6, hasInnerObjects.Spouse.Age); - Assert.IsNotNull(hasInnerObjects.Friends); - IList friends = (IList) hasInnerObjects.Friends; - Assert.AreEqual(2, friends.Count); - DerivedTestObject inner2 = (DerivedTestObject) friends[0]; - Assert.AreEqual("inner2", inner2.Name); - Assert.AreEqual(7, inner2.Age); - - - IList friendsOfInner = (IList) inner2.Friends; - Assert.AreEqual(1, friendsOfInner.Count); - DerivedTestObject innerFriendOfAFriend = (DerivedTestObject) friendsOfInner[0]; - Assert.AreEqual("innerFriendOfAFriend", innerFriendOfAFriend.Name); - Assert.AreEqual(7, innerFriendOfAFriend.Age); - TestObject innerFactory = (TestObject) friends[1]; - Assert.AreEqual(DummyFactory.SINGLETON_NAME, innerFactory.Name); - Assert.IsNotNull(hasInnerObjects.SomeMap); - Assert.IsFalse((hasInnerObjects.SomeMap.Count == 0)); - - TestObject inner3 = (TestObject) hasInnerObjects.SomeMap["someKey"]; - Assert.AreEqual("inner3", inner3.Name); - Assert.AreEqual(8, inner3.Age); - xof.Dispose(); - - Assert.IsFalse(inner2.WasDestroyed()); - Assert.IsFalse(innerFactory.Name == null); - Assert.IsFalse(innerFriendOfAFriend.WasDestroyed()); - + Assert.AreEqual(0, e.Message.IndexOf("Line 21 in XML document")); } + } - [Test] - public void SingletonInheritanceFromParentFactorySingleton() + [Test] + public void UnsatisfiedObjectDependencyCheck() + { + XmlObjectFactory xof = new XmlObjectFactory(new ReadOnlyXmlTestResource("unsatisfiedobjectdependencycheck.xml", GetType())); + Assert.Throws(() => xof.GetObject("a", typeof(DependenciesObject))); + } + + [Test] + public void UnsatisfiedSimpleDependencyCheck() + { + XmlObjectFactory xof = new XmlObjectFactory(new ReadOnlyXmlTestResource("unsatisfiedsimpledependencycheck.xml", GetType())); + Assert.Throws(() => xof.GetObject("a", typeof(DependenciesObject))); + } + + [Test] + public void SatisfiedObjectDependencyCheck() + { + XmlObjectFactory xof + = new XmlObjectFactory( + new ReadOnlyXmlTestResource("satisfiedobjectdependencycheck.xml", GetType())); + DependenciesObject a = (DependenciesObject) xof.GetObject("a"); + Assert.IsNotNull(a.Spouse); + } + + [Test] + public void SatisfiedSimpleDependencyCheck() + { + XmlObjectFactory xof = + new XmlObjectFactory( + new ReadOnlyXmlTestResource( + "satisfiedsimpledependencycheck.xml", GetType())); + DependenciesObject a = (DependenciesObject) xof.GetObject("a"); + Assert.AreEqual(a.Age, 33); + } + + [Test] + public void UnsatisfiedAllDependencyCheck() + { + XmlObjectFactory xof = new XmlObjectFactory(new ReadOnlyXmlTestResource("unsatisfiedalldependencycheckmissingobjects.xml", GetType())); + Assert.Throws(() => xof.GetObject("a", typeof(DependenciesObject))); + } + + [Test] + public void SatisfiedAllDependencyCheck() + { + XmlObjectFactory xof + = new XmlObjectFactory( + new ReadOnlyXmlTestResource("satisfiedalldependencycheck.xml", GetType())); + DependenciesObject a = (DependenciesObject) xof.GetObject("a"); + Assert.AreEqual(a.Age, 33); + Assert.IsNotNull(a.Name); + Assert.IsNotNull(a.Spouse); + } + + [Test] + public void Autowire() + { + XmlObjectFactory xof = new XmlObjectFactory(new ReadOnlyXmlTestResource("autowire.xml", GetType())); + TestObject spouse = new TestObject("kerry", 0); + xof.RegisterSingleton("Spouse", spouse); + DoTestAutowire(xof); + } + + [Test] + public void AutowireWithCtorArrayArgs() + { + XmlObjectFactory xof = new XmlObjectFactory(new ReadOnlyXmlTestResource("array-autowire.xml", GetType())); + TestObject spouse = new TestObject("kerry", 0); + xof.RegisterSingleton("spouse", spouse); + + TestObject spouse2 = new TestObject("kerry2", 0); + xof.RegisterSingleton("spouse2", spouse2); + + ITestObject kerry = (ITestObject) xof.GetObject("spouse"); + ITestObject kerry2 = (ITestObject) xof.GetObject("spouse2"); + ArrayCtorDependencyObject rod7 = (ArrayCtorDependencyObject) xof.GetObject("rod7"); + + Assert.AreEqual(kerry, rod7.Spouse1); + Assert.AreEqual(kerry2, rod7.Spouse2); + } + + [Test] + public void AutowireWithParent() + { + XmlObjectFactory xof = new XmlObjectFactory(new ReadOnlyXmlTestResource("autowire.xml", GetType())); + DefaultListableObjectFactory lbf = new DefaultListableObjectFactory(); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.Add("Name", "kerry"); + lbf.RegisterObjectDefinition("Spouse", new RootObjectDefinition(typeof(TestObject), pvs)); + xof.ParentObjectFactory = lbf; + DoTestAutowire(xof); + } + + private void DoTestAutowire(XmlObjectFactory xof) + { + DependenciesObject rod1 = (DependenciesObject) xof.GetObject("rod1"); + TestObject kerry = (TestObject) xof.GetObject("Spouse"); + // Should have been autowired + Assert.AreEqual(kerry, rod1.Spouse); + + DependenciesObject rod1a = (DependenciesObject) xof.GetObject("rod1a"); + // Should have been autowired + Assert.AreEqual(kerry, rod1a.Spouse); + + DependenciesObject rod2 = (DependenciesObject) xof.GetObject("rod2"); + // Should have been autowired + Assert.AreEqual(kerry, rod2.Spouse); + + ConstructorDependenciesObject rod3 = (ConstructorDependenciesObject) xof.GetObject("rod3"); + IndexedTestObject other = (IndexedTestObject) xof.GetObject("other"); + // Should have been autowired + Assert.AreEqual(kerry, rod3.Spouse1); + Assert.AreEqual(kerry, rod3.Spouse2); + Assert.AreEqual(other, rod3.Other); + + ConstructorDependenciesObject rod3a = (ConstructorDependenciesObject) xof.GetObject("rod3a"); + // Should have been autowired + Assert.AreEqual(kerry, rod3a.Spouse1); + Assert.AreEqual(kerry, rod3a.Spouse2); + Assert.AreEqual(other, rod3a.Other); + + try { - XmlObjectFactory parent = new XmlObjectFactory(new ReadOnlyXmlTestResource("parent.xml", GetType())); - XmlObjectFactory child = new XmlObjectFactory(new ReadOnlyXmlTestResource("child.xml", GetType()), parent); - TestObject inherits = (TestObject) child.GetObject("inheritsFromParentFactory"); - // Name property value is overriden - Assert.IsTrue(inherits.Name.Equals("override")); - // Age property is inherited from object in parent factory - Assert.IsTrue(inherits.Age == 1); - TestObject inherits2 = (TestObject) child.GetObject("inheritsFromParentFactory"); - Assert.AreSame(inherits2,inherits); - } - - [Test] - public void SingletonInheritanceFromParentFactorySingletonUsingCtor() - { - XmlObjectFactory parent = new XmlObjectFactory(new ReadOnlyXmlTestResource("parent.xml", GetType())); - XmlObjectFactory child = new XmlObjectFactory(new ReadOnlyXmlTestResource("child.xml", GetType()), parent); - TestObject inherits = (TestObject)child.GetObject("inheritsFromParentFactoryUsingCtor"); - // Name property value is overriden - Assert.IsTrue(inherits.Name.Equals("child-name")); - // Age property is inherited from object in parent factory - Assert.IsTrue(inherits.Age == 1); - TestObject inherits2 = (TestObject)child.GetObject("inheritsFromParentFactoryUsingCtor"); - Assert.AreSame(inherits2,inherits); - } - - [Test] - public void PrototypeInheritanceFromParentFactoryPrototype() - { - XmlObjectFactory parent = new XmlObjectFactory(new ReadOnlyXmlTestResource("parent.xml", GetType())); - XmlObjectFactory child = new XmlObjectFactory(new ReadOnlyXmlTestResource("child.xml", GetType()), parent); - TestObject inherits = (TestObject) child.GetObject("prototypeInheritsFromParentFactoryPrototype"); - // Name property value is overridden - Assert.IsTrue(inherits.Name.Equals("prototype-override")); - // Age property is inherited from object in parent factory - Assert.IsTrue(inherits.Age == 2); - TestObject inherits2 = (TestObject) child.GetObject("prototypeInheritsFromParentFactoryPrototype"); - Assert.AreNotSame(inherits2,inherits); - inherits2.Age = 13; - Assert.IsTrue(inherits2.Age == 13); - // Shouldn't have changed first instance - Assert.IsTrue(inherits.Age == 2); - } - - [Test] - public void PrototypeInheritanceFromParentFactorySingleton() - { - XmlObjectFactory parent = new XmlObjectFactory(new ReadOnlyXmlTestResource("parent.xml", GetType())); - XmlObjectFactory child = new XmlObjectFactory(new ReadOnlyXmlTestResource("child.xml", GetType()), parent); - TestObject inherits = (TestObject) child.GetObject("protoypeInheritsFromParentFactorySingleton"); - // Name property value is overridden - Assert.IsTrue(inherits.Name.Equals("prototypeOverridesInheritedSingleton")); - // Age property is inherited from object in parent factory - Assert.IsTrue(inherits.Age == 1); - TestObject inherits2 = (TestObject) child.GetObject("protoypeInheritsFromParentFactorySingleton"); - Assert.AreNotSame(inherits2,inherits); - inherits2.Age = 13; - Assert.IsTrue(inherits2.Age == 13); - // Shouldn't have changed first instance - Assert.IsTrue(inherits.Age == 1); - } - - [Test] - public void DependenciesMaterializeThis() - { - IResource resource = new ReadOnlyXmlTestResource("dependenciesmaterializethis.xml", GetType()); - XmlObjectFactory bf = new XmlObjectFactory(resource); - DummyBo bos = (DummyBo) bf.GetObject("boSingleton"); - DummyBo bop = (DummyBo) bf.GetObject("boPrototype"); - Assert.IsFalse(bos == bop); - Assert.AreEqual(bos.dao, bop.dao); - } - - [Test] - public void ChildOverridesParentObject() - { - XmlObjectFactory parent = new XmlObjectFactory(new ReadOnlyXmlTestResource("parent.xml", GetType())); - XmlObjectFactory child = new XmlObjectFactory(new ReadOnlyXmlTestResource("child.xml", GetType()), parent); - TestObject inherits = (TestObject) child.GetObject("inheritedTestObject"); - // Name property value is overridden - Assert.IsTrue(inherits.Name.Equals("overrideParentObject")); - // Age property is inherited from object in parent factory - Assert.IsTrue(inherits.Age == 1); - TestObject inherits2 = (TestObject) child.GetObject("inheritedTestObject"); - Assert.IsTrue(inherits2 == inherits); - } - - /// - /// Check that a prototype can't inherit from a bogus parent. - /// If a singleton does this the factory will fail to load. - /// - [Test] - public void BogusParentageFromParentFactory() - { - XmlObjectFactory parent = new XmlObjectFactory(new ReadOnlyXmlTestResource("parent.xml", GetType())); - XmlObjectFactory child = new XmlObjectFactory(new ReadOnlyXmlTestResource("child.xml", GetType()), parent); - Assert.Throws(() => child.GetObject("bogusParent")); - } - - /// - /// Note that prototype/singleton distinction is not inherited. - /// It's possible for a subclass singleton not to return independent - /// instances even if derived from a prototype - /// - [Test] - public void SingletonInheritsFromParentFactoryPrototype() - { - XmlObjectFactory parent = new XmlObjectFactory(new ReadOnlyXmlTestResource("parent.xml", GetType())); - XmlObjectFactory child = new XmlObjectFactory(new ReadOnlyXmlTestResource("child.xml", GetType()), parent); - TestObject inherits = (TestObject) child.GetObject("singletonInheritsFromParentFactoryPrototype"); - // Name property value is overriden - Assert.IsTrue(inherits.Name.Equals("prototype-override")); - // Age property is inherited from object in parent factory - Assert.IsTrue(inherits.Age == 2); - TestObject inherits2 = (TestObject) child.GetObject("singletonInheritsFromParentFactoryPrototype"); - Assert.IsTrue(inherits2 == inherits); - } - - [Test] - public void AbstractParentObjects() - { - XmlObjectFactory parent = new XmlObjectFactory(new ReadOnlyXmlTestResource("parent.xml", GetType())); - parent.PreInstantiateSingletons(); - Assert.IsTrue(parent.IsSingleton("inheritedTestObjectWithoutClass")); - - // abstract objects should not match - //TODO add overloaded GetObjectOfType with 1 arg - var tbs = parent.GetObjectsOfType(typeof(TestObject), true, true); - Assert.AreEqual(2, tbs.Count); - Assert.IsTrue(tbs.ContainsKey("inheritedTestObjectPrototype")); - Assert.IsTrue(tbs.ContainsKey("inheritedTestObjectSingleton")); - - // non-abstract object should work, even if it serves as parent - object o1 = parent.GetObject("inheritedTestObjectPrototype"); - Assert.IsTrue(o1 is TestObject); - - // abstract object should return IObjectInstance itself - object o2 = parent.GetObject("inheritedTestObjectWithoutClass"); - Assert.IsTrue(o2 is IObjectDefinition); - } - - [Test] - public void CircularReferences() - { - DefaultListableObjectFactory xof = new DefaultListableObjectFactory(); - XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(xof); - reader.LoadObjectDefinitions(new ReadOnlyXmlTestResource("reftypes.xml", GetType())); - TestObject jenny = (TestObject) xof.GetObject("jenny"); - TestObject david = (TestObject) xof.GetObject("david"); - TestObject ego = (TestObject) xof.GetObject("ego"); - Assert.IsTrue(jenny.Spouse == david, "Correct circular reference"); - Assert.IsTrue(david.Spouse == jenny, "Correct circular reference"); - Assert.IsTrue(ego.Spouse == ego, "Correct circular reference"); - } - - [Test] - public void FactoryReferenceCircle() - { - IResource resource = new ReadOnlyXmlTestResource("factorycircle.xml", GetType()); - XmlObjectFactory xof = new XmlObjectFactory(resource); - TestObject tb = (TestObject) xof.GetObject("singletonFactory"); - DummyFactory db = (DummyFactory) xof.GetObject("&singletonFactory"); - Assert.IsTrue(tb == db.OtherTestObject); - } - - [Test] - public void RefSubelement() - { - IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); - XmlObjectFactory xof = new XmlObjectFactory(resource); - //Assert.IsTrue ("5 objects in reftypes, not " + xof.GetObjectDefinitionCount(), xof.GetObjectDefinitionCount() == 5); - TestObject jen = (TestObject) xof.GetObject("jenny"); - TestObject dave = (TestObject) xof.GetObject("david"); - Assert.IsTrue(jen.Spouse == dave); - } - - [Test] - public void PropertyWithLiteralValueSubelement() - { - IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); - XmlObjectFactory xof = new XmlObjectFactory(resource); - TestObject verbose = (TestObject) xof.GetObject("verbose"); - Assert.IsTrue(verbose.Name.Equals("verbose")); - } - - [Test] - public void PropertyWithIdRefLocalAttrSubelement() - { - IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); - XmlObjectFactory xof = new XmlObjectFactory(resource); - TestObject verbose = (TestObject) xof.GetObject("verbose2"); - Assert.IsTrue(verbose.Name.Equals("verbose")); - } - - [Test] - public void PropertyWithIdRefObjectAttrSubelement() - { - IResource resource = new ReadOnlyXmlTestResource("collections.xml", GetType()); - XmlObjectFactory xof = new XmlObjectFactory(resource); - TestObject verbose = (TestObject) xof.GetObject("verbose3"); - Assert.IsTrue(verbose.Name.Equals("verbose")); - } - - [Test] - public void EnumProperty() - { - DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); - XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(factory); - reader.LoadObjectDefinitions(new ReadOnlyXmlTestResource("enums.xml", GetType())); - TestObject obj = factory.GetObject("rod", typeof(TestObject)) as TestObject; - Assert.IsNotNull(obj.FileMode); - Assert.AreEqual(FileMode.Create, obj.FileMode); - } - - [Test] - public void InitMethodIsInvoked() - { - IResource resource = new ReadOnlyXmlTestResource("initializers.xml", GetType()); - XmlObjectFactory xof = new XmlObjectFactory(resource); - DoubleInitializer in_Renamed = (DoubleInitializer) xof.GetObject("init-method1"); - // Initializer should have doubled value - Assert.AreEqual(14, in_Renamed.Num); - } - - [Test] - public void DefaultInitMethodIsInvoked() - { - IResource resource = new ReadOnlyXmlTestResource("default-initializers.xml", GetType()); - XmlObjectFactory xof = new XmlObjectFactory(resource); - DoubleInitializer in_Renamed = (DoubleInitializer)xof.GetObject("init-method1"); - // Initializer should have doubled value - Assert.AreEqual(14, in_Renamed.Num); - } - - [Test] - public void DefaultInitMethodDisabled() - { - IResource resource = new ReadOnlyXmlTestResource("default-initializers.xml", GetType()); - XmlObjectFactory xof = new XmlObjectFactory(resource); - DoubleInitializer in_Renamed = (DoubleInitializer)xof.GetObject("init-method2"); - // Initializer should have doubled value - Assert.AreEqual(7, in_Renamed.Num); - } - - /// - /// Test that if a custom initializer throws an exception, it's handled correctly. - /// - [Test] - public void InitMethodThrowsException() - { - IResource resource = new ReadOnlyXmlTestResource("initializers.xml", GetType()); - XmlObjectFactory xof = new XmlObjectFactory(resource); - try - { - xof.GetObject("init-method2"); - Assert.Fail(); - } - catch (ObjectCreationException ex) - { - Assert.IsTrue(ex.InnerException is FormatException); - } - } - - [Test] - public void NoSuchInitMethod() - { - IResource resource = new ReadOnlyXmlTestResource("initializers.xml", GetType()); - XmlObjectFactory xof = new XmlObjectFactory(resource); - Assert.Throws(() => xof.GetObject("init-method3")); - } - - /// - /// Check that InitializingObject method is called first. - /// - [Test] - public void InitializingObjectAndInitMethod() - { - InitAndIB.constructed = false; - IResource resource = new ReadOnlyXmlTestResource("initializers.xml", GetType()); - XmlObjectFactory xof = new XmlObjectFactory(resource); - Assert.IsFalse(InitAndIB.constructed); - xof.PreInstantiateSingletons(); - Assert.IsFalse(InitAndIB.constructed); - InitAndIB iib = (InitAndIB) xof.GetObject("init-and-ib"); - Assert.IsTrue(InitAndIB.constructed); - Assert.IsTrue(iib.afterPropertiesSetInvoked && iib.initMethodInvoked); - Assert.IsTrue(!iib.destroyed && !iib.customDestroyed); - xof.Dispose(); - Assert.IsTrue(iib.destroyed && iib.customDestroyed); - xof.Dispose(); - Assert.IsTrue(iib.destroyed && iib.customDestroyed); - } - - [Test] - public void DefaultDestroyMethodInvoked() - { - IResource resource = new ReadOnlyXmlTestResource("default-destroy-methods.xml", GetType()); - XmlObjectFactory xof = new XmlObjectFactory(resource); - xof.PreInstantiateSingletons(); - DefaultDestroyer dd = (DefaultDestroyer)xof.GetObject("destroy-method1"); - Assert.IsTrue(!dd.customDestroyed); - xof.Dispose(); - Assert.IsTrue(dd.customDestroyed); - } - - [Test] - public void DefaultDestroyMethodDisabled() - { - IResource resource = new ReadOnlyXmlTestResource("default-destroy-methods.xml", GetType()); - XmlObjectFactory xof = new XmlObjectFactory(resource); - xof.PreInstantiateSingletons(); - DefaultDestroyer dd = (DefaultDestroyer)xof.GetObject("destroy-method2"); - Assert.IsTrue(!dd.customDestroyed); - xof.Dispose(); - Assert.IsTrue(!dd.customDestroyed); - } - - [Test] - public void MultiThreadedLazyInit() - { - IResource resource = new ReadOnlyXmlTestResource("lazy-init-multithreaded.xml", GetType()); - XmlObjectFactory xof = new XmlObjectFactory(resource); - - LazyWorker lw1 = new LazyWorker(xof); - LazyWorker lw2 = new LazyWorker(xof); - Thread thread1 = new Thread(lw1.DoWork); - Thread thread2 = new Thread(lw2.DoWork); - - thread1.Start(); - Thread.Sleep(1000); - thread2.Start(); - thread1.Join(); - thread2.Join(); - Assert.AreEqual(typeof(LazyTestObject), lw1.ObjectFromContext.GetType()); - Assert.AreEqual(typeof(LazyTestObject), lw2.ObjectFromContext.GetType()); - Assert.AreEqual(1, LazyTestObject.Count); - } - - /// - /// Check that InitializingObject method is called first. - /// - [Test] - public void DefaultLazyInit() - { - InitAndIB.constructed = false; - IResource resource = new ReadOnlyXmlTestResource("default-lazy-init.xml", GetType()); - XmlObjectFactory xof = new XmlObjectFactory(resource); - Assert.IsFalse(InitAndIB.constructed); - xof.PreInstantiateSingletons(); - Assert.IsTrue(InitAndIB.constructed); - try - { - xof.GetObject("lazy-and-bad"); - } - catch (ObjectCreationException ex) - { - Assert.IsTrue(ex.InnerException is FormatException); - } - } - - - /// - /// Check that InitializingObject method is called first. - /// - [Test] - public void DefaultLazyInitNoInObjectDef() - { - InitAndIB.constructed = false; - IResource resource = new ReadOnlyXmlTestResource("default-lazy-init.xml", GetType()); - XmlObjectFactory xof = new XmlObjectFactory(resource); - Assert.IsFalse(InitAndIB.constructed); - xof.PreInstantiateSingletons(); - Assert.IsTrue(InitAndIB.constructed); - try - { - xof.GetObject("init-and-ib-no-init-in-local-object-def"); - } - catch (ObjectCreationException ex) - { - Assert.IsTrue(ex.InnerException is FormatException); - } - } - - [Test] - public void NoSuchXmlFile() - { - Assert.Throws(() => new XmlObjectFactory(new ReadOnlyXmlTestResource("missing.xml", GetType()))); - } - - [Test] - public void InvalidXmlFile() - { - DefaultListableObjectFactory xof = new DefaultListableObjectFactory(); - XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(xof); - try - { - reader.LoadObjectDefinitions(new ReadOnlyXmlTestResource("invalid.xml", GetType())); - Assert.Fail("Should have thrown XmlObjectDefinitionStoreException"); - } - catch (ObjectDefinitionStoreException e) - { - Assert.AreEqual(0, e.Message.IndexOf("Line 21 in XML document")); - } - } - - [Test] - public void DefaultXmlResolverIsUsedIfNullSuppliedOrSet() - { - DefaultListableObjectFactory xof = new DefaultListableObjectFactory(); - XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(xof, null); - try - { - reader.LoadObjectDefinitions(new ReadOnlyXmlTestResource("invalid.xml", GetType())); - Assert.Fail("Should have thrown XmlObjectDefinitionStoreException"); - } - catch (ObjectDefinitionStoreException e) - { - Assert.AreEqual(0, e.Message.IndexOf("Line 21 in XML document")); - } - } - - [Test] - public void UnsatisfiedObjectDependencyCheck() - { - XmlObjectFactory xof = new XmlObjectFactory(new ReadOnlyXmlTestResource("unsatisfiedobjectdependencycheck.xml", GetType())); - Assert.Throws(() => xof.GetObject("a", typeof(DependenciesObject))); - } - - [Test] - public void UnsatisfiedSimpleDependencyCheck() - { - XmlObjectFactory xof = new XmlObjectFactory(new ReadOnlyXmlTestResource("unsatisfiedsimpledependencycheck.xml", GetType())); - Assert.Throws(() => xof.GetObject("a", typeof(DependenciesObject))); - } - - [Test] - public void SatisfiedObjectDependencyCheck() - { - XmlObjectFactory xof - = new XmlObjectFactory( - new ReadOnlyXmlTestResource("satisfiedobjectdependencycheck.xml", GetType())); - DependenciesObject a = (DependenciesObject) xof.GetObject("a"); - Assert.IsNotNull(a.Spouse); - } - - [Test] - public void SatisfiedSimpleDependencyCheck() - { - XmlObjectFactory xof = - new XmlObjectFactory( - new ReadOnlyXmlTestResource( - "satisfiedsimpledependencycheck.xml", GetType())); - DependenciesObject a = (DependenciesObject) xof.GetObject("a"); - Assert.AreEqual(a.Age, 33); - } - - [Test] - public void UnsatisfiedAllDependencyCheck() - { - XmlObjectFactory xof= new XmlObjectFactory(new ReadOnlyXmlTestResource("unsatisfiedalldependencycheckmissingobjects.xml", GetType())); - Assert.Throws(() => xof.GetObject("a", typeof(DependenciesObject))); - } - - [Test] - public void SatisfiedAllDependencyCheck() - { - XmlObjectFactory xof - = new XmlObjectFactory( - new ReadOnlyXmlTestResource("satisfiedalldependencycheck.xml", GetType())); - DependenciesObject a = (DependenciesObject) xof.GetObject("a"); - Assert.AreEqual(a.Age, 33); - Assert.IsNotNull(a.Name); - Assert.IsNotNull(a.Spouse); - } - - [Test] - public void Autowire() - { - XmlObjectFactory xof = new XmlObjectFactory(new ReadOnlyXmlTestResource("autowire.xml", GetType())); - TestObject spouse = new TestObject("kerry", 0); - xof.RegisterSingleton("Spouse", spouse); - DoTestAutowire(xof); - } - - [Test] - public void AutowireWithCtorArrayArgs() - { - XmlObjectFactory xof = new XmlObjectFactory(new ReadOnlyXmlTestResource("array-autowire.xml", GetType())); - TestObject spouse = new TestObject("kerry", 0); - xof.RegisterSingleton("spouse", spouse); - - TestObject spouse2 = new TestObject("kerry2", 0); - xof.RegisterSingleton("spouse2", spouse2); - - ITestObject kerry = (ITestObject) xof.GetObject("spouse"); - ITestObject kerry2 = (ITestObject)xof.GetObject("spouse2"); - ArrayCtorDependencyObject rod7 = (ArrayCtorDependencyObject) xof.GetObject("rod7"); - - Assert.AreEqual(kerry, rod7.Spouse1); - Assert.AreEqual(kerry2, rod7.Spouse2); - } - - [Test] - public void AutowireWithParent() - { - XmlObjectFactory xof = new XmlObjectFactory(new ReadOnlyXmlTestResource("autowire.xml", GetType())); - DefaultListableObjectFactory lbf = new DefaultListableObjectFactory(); - MutablePropertyValues pvs = new MutablePropertyValues(); - pvs.Add("Name", "kerry"); - lbf.RegisterObjectDefinition("Spouse", new RootObjectDefinition(typeof(TestObject), pvs)); - xof.ParentObjectFactory = lbf; - DoTestAutowire(xof); - } - - private void DoTestAutowire(XmlObjectFactory xof) - { - DependenciesObject rod1 = (DependenciesObject) xof.GetObject("rod1"); - TestObject kerry = (TestObject) xof.GetObject("Spouse"); - // Should have been autowired - Assert.AreEqual(kerry, rod1.Spouse); - - DependenciesObject rod1a = (DependenciesObject) xof.GetObject("rod1a"); - // Should have been autowired - Assert.AreEqual(kerry, rod1a.Spouse); - - DependenciesObject rod2 = (DependenciesObject) xof.GetObject("rod2"); - // Should have been autowired - Assert.AreEqual(kerry, rod2.Spouse); - - ConstructorDependenciesObject rod3 = (ConstructorDependenciesObject) xof.GetObject("rod3"); - IndexedTestObject other = (IndexedTestObject) xof.GetObject("other"); - // Should have been autowired - Assert.AreEqual(kerry, rod3.Spouse1); - Assert.AreEqual(kerry, rod3.Spouse2); - Assert.AreEqual(other, rod3.Other); - - ConstructorDependenciesObject rod3a = (ConstructorDependenciesObject) xof.GetObject("rod3a"); - // Should have been autowired - Assert.AreEqual(kerry, rod3a.Spouse1); - Assert.AreEqual(kerry, rod3a.Spouse2); - Assert.AreEqual(other, rod3a.Other); - - try - { - xof.GetObject("rod4", typeof(ConstructorDependenciesObject)); - Assert.Fail("Should not have thrown FatalObjectException"); - } - catch (FatalObjectException) - { - // expected - } - - DependenciesObject rod5 = (DependenciesObject) xof.GetObject("rod5"); - // Should not have been autowired - Assert.IsNull(rod5.Spouse); - - /* TODO include basc in - IObjectFactory appCtx = (IObjectFactory) xof.GetObject("childAppCtx"); - Assert.IsTrue(appCtx.GetObject("rod1") != null); - Assert.IsTrue(appCtx.GetObject("dependingObject") != null); - Assert.IsTrue(appCtx.GetObject("jenny") != null); - */ - } - - [Test] - public void AutowireWithDefault() - { - XmlObjectFactory xof - = new XmlObjectFactory( - new ReadOnlyXmlTestResource("default-autowire.xml", GetType())); - DependenciesObject rod1 = (DependenciesObject) xof.GetObject("rod1"); - // Should have been autowired - Assert.IsNotNull(rod1.Spouse); - Assert.IsTrue(rod1.Spouse.Name.Equals("Kerry")); - - DependenciesObject rod2 = (DependenciesObject) xof.GetObject("rod2"); - // Should have been autowired - Assert.IsNotNull(rod2.Spouse); - Assert.IsTrue(rod2.Spouse.Name.Equals("Kerry")); - } - - [Test] - public void AutowireByConstructor() - { - XmlObjectFactory xof = new XmlObjectFactory(new ReadOnlyXmlTestResource("constructor-arg.xml", GetType())); - ConstructorDependenciesObject rod1 = (ConstructorDependenciesObject) xof.GetObject("rod1"); - TestObject kerry = (TestObject) xof.GetObject("kerry2"); - // Should have been autowired - Assert.AreEqual(kerry, rod1.Spouse1); - Assert.AreEqual(0, rod1.Age); - Assert.AreEqual(null, rod1.Name); - - ConstructorDependenciesObject rod2 = (ConstructorDependenciesObject) xof.GetObject("rod2"); - TestObject kerry1 = (TestObject) xof.GetObject("kerry1"); - TestObject kerry2 = (TestObject) xof.GetObject("kerry2"); - // Should have been autowired - Assert.AreEqual(kerry2, rod2.Spouse1); - Assert.AreEqual(kerry1, rod2.Spouse2); - Assert.AreEqual(0, rod2.Age); - Assert.AreEqual(null, rod2.Name); - - ConstructorDependenciesObject rod = (ConstructorDependenciesObject) xof.GetObject("rod3"); - IndexedTestObject other = (IndexedTestObject) xof.GetObject("other"); - // Should have been autowired - Assert.AreEqual(kerry, rod.Spouse1); - Assert.AreEqual(kerry, rod.Spouse2); - Assert.AreEqual(other, rod.Other); - Assert.AreEqual(0, rod.Age); - Assert.AreEqual(null, rod.Name); xof.GetObject("rod4", typeof(ConstructorDependenciesObject)); - // Should have been autowired - Assert.AreEqual(kerry, rod.Spouse1); - Assert.AreEqual(kerry, rod.Spouse2); - Assert.AreEqual(other, rod.Other); - Assert.AreEqual(0, rod.Age); - Assert.AreEqual(null, rod.Name); + Assert.Fail("Should not have thrown FatalObjectException"); } - - [Test] - public void AutowireByConstructorWithSimpleValues() + catch (FatalObjectException) { - XmlObjectFactory xof = new XmlObjectFactory(new ReadOnlyXmlTestResource("constructor-arg.xml", GetType())); - ConstructorDependenciesObject rod5 = (ConstructorDependenciesObject) xof.GetObject("rod5"); - TestObject kerry1 = (TestObject) xof.GetObject("kerry1"); - TestObject kerry2 = (TestObject) xof.GetObject("kerry2"); - IndexedTestObject other = (IndexedTestObject) xof.GetObject("other"); - // Should have been autowired - Assert.AreEqual(kerry2, rod5.Spouse1); - Assert.AreEqual(kerry1, rod5.Spouse2); - Assert.AreEqual(other, rod5.Other); - Assert.AreEqual(99, rod5.Age); - Assert.AreEqual("myname", rod5.Name); - ConstructorDependenciesObject rod6 = (ConstructorDependenciesObject) xof.GetObject("rod6"); - // Should have been autowired - Assert.AreEqual(kerry2, rod6.Spouse1); - Assert.AreEqual(kerry1, rod6.Spouse2); - Assert.AreEqual(other, rod6.Other); - Assert.AreEqual(0, rod6.Age); - Assert.AreEqual(null, rod6.Name); + // expected } - [Test] - public void ConstructorArgResolution() + DependenciesObject rod5 = (DependenciesObject) xof.GetObject("rod5"); + // Should not have been autowired + Assert.IsNull(rod5.Spouse); + + /* TODO include basc in + IObjectFactory appCtx = (IObjectFactory) xof.GetObject("childAppCtx"); + Assert.IsTrue(appCtx.GetObject("rod1") != null); + Assert.IsTrue(appCtx.GetObject("dependingObject") != null); + Assert.IsTrue(appCtx.GetObject("jenny") != null); + */ + } + + [Test] + public void AutowireWithDefault() + { + XmlObjectFactory xof + = new XmlObjectFactory( + new ReadOnlyXmlTestResource("default-autowire.xml", GetType())); + DependenciesObject rod1 = (DependenciesObject) xof.GetObject("rod1"); + // Should have been autowired + Assert.IsNotNull(rod1.Spouse); + Assert.IsTrue(rod1.Spouse.Name.Equals("Kerry")); + + DependenciesObject rod2 = (DependenciesObject) xof.GetObject("rod2"); + // Should have been autowired + Assert.IsNotNull(rod2.Spouse); + Assert.IsTrue(rod2.Spouse.Name.Equals("Kerry")); + } + + [Test] + public void AutowireByConstructor() + { + XmlObjectFactory xof = new XmlObjectFactory(new ReadOnlyXmlTestResource("constructor-arg.xml", GetType())); + ConstructorDependenciesObject rod1 = (ConstructorDependenciesObject) xof.GetObject("rod1"); + TestObject kerry = (TestObject) xof.GetObject("kerry2"); + // Should have been autowired + Assert.AreEqual(kerry, rod1.Spouse1); + Assert.AreEqual(0, rod1.Age); + Assert.AreEqual(null, rod1.Name); + + ConstructorDependenciesObject rod2 = (ConstructorDependenciesObject) xof.GetObject("rod2"); + TestObject kerry1 = (TestObject) xof.GetObject("kerry1"); + TestObject kerry2 = (TestObject) xof.GetObject("kerry2"); + // Should have been autowired + Assert.AreEqual(kerry2, rod2.Spouse1); + Assert.AreEqual(kerry1, rod2.Spouse2); + Assert.AreEqual(0, rod2.Age); + Assert.AreEqual(null, rod2.Name); + + ConstructorDependenciesObject rod = (ConstructorDependenciesObject) xof.GetObject("rod3"); + IndexedTestObject other = (IndexedTestObject) xof.GetObject("other"); + // Should have been autowired + Assert.AreEqual(kerry, rod.Spouse1); + Assert.AreEqual(kerry, rod.Spouse2); + Assert.AreEqual(other, rod.Other); + Assert.AreEqual(0, rod.Age); + Assert.AreEqual(null, rod.Name); + xof.GetObject("rod4", typeof(ConstructorDependenciesObject)); + // Should have been autowired + Assert.AreEqual(kerry, rod.Spouse1); + Assert.AreEqual(kerry, rod.Spouse2); + Assert.AreEqual(other, rod.Other); + Assert.AreEqual(0, rod.Age); + Assert.AreEqual(null, rod.Name); + } + + [Test] + public void AutowireByConstructorWithSimpleValues() + { + XmlObjectFactory xof = new XmlObjectFactory(new ReadOnlyXmlTestResource("constructor-arg.xml", GetType())); + ConstructorDependenciesObject rod5 = (ConstructorDependenciesObject) xof.GetObject("rod5"); + TestObject kerry1 = (TestObject) xof.GetObject("kerry1"); + TestObject kerry2 = (TestObject) xof.GetObject("kerry2"); + IndexedTestObject other = (IndexedTestObject) xof.GetObject("other"); + // Should have been autowired + Assert.AreEqual(kerry2, rod5.Spouse1); + Assert.AreEqual(kerry1, rod5.Spouse2); + Assert.AreEqual(other, rod5.Other); + Assert.AreEqual(99, rod5.Age); + Assert.AreEqual("myname", rod5.Name); + ConstructorDependenciesObject rod6 = (ConstructorDependenciesObject) xof.GetObject("rod6"); + // Should have been autowired + Assert.AreEqual(kerry2, rod6.Spouse1); + Assert.AreEqual(kerry1, rod6.Spouse2); + Assert.AreEqual(other, rod6.Other); + Assert.AreEqual(0, rod6.Age); + Assert.AreEqual(null, rod6.Name); + } + + [Test] + public void ConstructorArgResolution() + { + XmlObjectFactory xof = new XmlObjectFactory(new ReadOnlyXmlTestResource("constructor-arg.xml", GetType())); + TestObject kerry1 = (TestObject) xof.GetObject("kerry1"); + TestObject kerry2 = (TestObject) xof.GetObject("kerry2"); + ConstructorDependenciesObject rod9 = (ConstructorDependenciesObject) xof.GetObject("rod9"); + Assert.AreEqual(99, rod9.Age); + ConstructorDependenciesObject rod10 = (ConstructorDependenciesObject) xof.GetObject("rod10"); + Assert.AreEqual(null, rod10.Name); + ConstructorDependenciesObject rod11 = (ConstructorDependenciesObject) xof.GetObject("rod11"); + Assert.AreEqual(kerry2, rod11.Spouse1); + + ConstructorDependenciesObject rod12 = (ConstructorDependenciesObject) xof.GetObject("rod12"); + Assert.AreEqual(kerry1, rod12.Spouse1); + Assert.IsNull(rod12.Spouse2); + + ConstructorDependenciesObject rod13 = (ConstructorDependenciesObject) xof.GetObject("rod13"); + Assert.AreEqual(kerry1, rod13.Spouse1); + Assert.AreEqual(kerry2, rod13.Spouse2); + } + + [Test] + public void ThrowsExceptionOnTooManyArguments() + { + XmlObjectFactory xof = new XmlObjectFactory(new ReadOnlyXmlTestResource("constructor-arg.xml", GetType())); + Assert.Throws(() => xof.GetObject("rod7", typeof(ConstructorDependenciesObject))); + } + + [Test] + public void ThrowsExceptionOnAmbiguousResolution() + { + XmlObjectFactory xof = new XmlObjectFactory(new ReadOnlyXmlTestResource("constructor-arg.xml", GetType())); + Assert.Throws(() => xof.GetObject("rod8", typeof(ConstructorDependenciesObject))); + } + + [Test] + public void FactoryObjectDefinedAsPrototype() + { + Assert.Throws(() => new XmlObjectFactory(new ReadOnlyXmlTestResource("invalid-factory.xml", GetType()))); + } + + [Test] + public void DependsOn() + { + PreparingObject1.prepared = false; + PreparingObject1.destroyed = false; + PreparingObject2.prepared = false; + PreparingObject2.destroyed = false; + DependingObject.destroyed = false; + IResource resource = new ReadOnlyXmlTestResource("initializers.xml", GetType()); + XmlObjectFactory xof = new XmlObjectFactory(resource); + xof.PreInstantiateSingletons(); + xof.Dispose(); + Assert.IsTrue(PreparingObject1.prepared); + Assert.IsTrue(PreparingObject1.destroyed); + Assert.IsTrue(PreparingObject2.prepared); + Assert.IsTrue(PreparingObject2.destroyed); + Assert.IsTrue(DependingObject.destroyed); + } + + [Test] + public void ClassNotFoundWithDefault() + { + try { - XmlObjectFactory xof = new XmlObjectFactory(new ReadOnlyXmlTestResource("constructor-arg.xml", GetType())); - TestObject kerry1 = (TestObject) xof.GetObject("kerry1"); - TestObject kerry2 = (TestObject) xof.GetObject("kerry2"); - ConstructorDependenciesObject rod9 = (ConstructorDependenciesObject) xof.GetObject("rod9"); - Assert.AreEqual(99, rod9.Age); - ConstructorDependenciesObject rod10 = (ConstructorDependenciesObject) xof.GetObject("rod10"); - Assert.AreEqual(null, rod10.Name); - ConstructorDependenciesObject rod11 = (ConstructorDependenciesObject) xof.GetObject("rod11"); - Assert.AreEqual(kerry2, rod11.Spouse1); - - ConstructorDependenciesObject rod12 = (ConstructorDependenciesObject) xof.GetObject("rod12"); - Assert.AreEqual(kerry1, rod12.Spouse1); - Assert.IsNull(rod12.Spouse2); - - ConstructorDependenciesObject rod13 = (ConstructorDependenciesObject) xof.GetObject("rod13"); - Assert.AreEqual(kerry1, rod13.Spouse1); - Assert.AreEqual(kerry2, rod13.Spouse2); + new XmlObjectFactory( + new ReadOnlyXmlTestResource("classnotfound.xml", GetType())); } - - [Test] - public void ThrowsExceptionOnTooManyArguments() + catch (ObjectDefinitionStoreException ex) { - XmlObjectFactory xof = new XmlObjectFactory(new ReadOnlyXmlTestResource("constructor-arg.xml", GetType())); - Assert.Throws(() => xof.GetObject("rod7", typeof(ConstructorDependenciesObject))); - } - - [Test] - public void ThrowsExceptionOnAmbiguousResolution() - { - XmlObjectFactory xof = new XmlObjectFactory(new ReadOnlyXmlTestResource("constructor-arg.xml", GetType())); - Assert.Throws(() => xof.GetObject("rod8", typeof(ConstructorDependenciesObject))); - } - - [Test] - public void FactoryObjectDefinedAsPrototype() - { - Assert.Throws(() => new XmlObjectFactory(new ReadOnlyXmlTestResource("invalid-factory.xml", GetType()))); - } - - [Test] - public void DependsOn() - { - PreparingObject1.prepared = false; - PreparingObject1.destroyed = false; - PreparingObject2.prepared = false; - PreparingObject2.destroyed = false; - DependingObject.destroyed = false; - IResource resource = new ReadOnlyXmlTestResource("initializers.xml", GetType()); - XmlObjectFactory xof = new XmlObjectFactory(resource); - xof.PreInstantiateSingletons(); - xof.Dispose(); - Assert.IsTrue(PreparingObject1.prepared); - Assert.IsTrue(PreparingObject1.destroyed); - Assert.IsTrue(PreparingObject2.prepared); - Assert.IsTrue(PreparingObject2.destroyed); - Assert.IsTrue(DependingObject.destroyed); - } - - [Test] - public void ClassNotFoundWithDefault() - { - try - { - new XmlObjectFactory( - new ReadOnlyXmlTestResource("classnotfound.xml", GetType())); - } - catch (ObjectDefinitionStoreException ex) - { - Assert.IsTrue(ex.InnerException is TypeLoadException); - } + Assert.IsTrue(ex.InnerException is TypeLoadException); } + } #if !NETCOREAPP [Test] @@ -1357,425 +1350,428 @@ namespace Spring.Objects.Factory.Xml } #endif - [Test] - public void ResourceAndInputStream() + [Test] + public void ResourceAndInputStream() + { + string filename = "./temp/spring-test.properties"; + FileInfo file = new FileInfo(filename); + bool tempDirWasCreated = false; + try { - string filename = "./temp/spring-test.properties"; - FileInfo file = new FileInfo(filename); - bool tempDirWasCreated = false; - try + if (file.Exists) { - if (file.Exists) - { - file.Delete(); - } - if (!file.Directory.Exists) - { - file.Directory.Create(); - tempDirWasCreated = true; - } - StreamWriter sw = file.CreateText(); - sw.WriteLine("test"); - sw.Close(); - - IResource resource = new ReadOnlyXmlTestResource("resource.xml", GetType()); - XmlObjectFactory xof = new XmlObjectFactory(resource); - - ResourceTestObject resource1 = (ResourceTestObject) xof.GetObject("resource1"); - Assert.IsTrue(resource1.Resource is FileSystemResource); - using (StreamReader reader = new StreamReader(resource1.Resource.InputStream)) - { - string fileText = reader.ReadLine(); - Assert.AreEqual("test", fileText, "error using IResource to read file contents"); - } - using (StreamReader reader = new StreamReader(resource1.InputStream)) - { - string fileText = reader.ReadLine(); - Assert.AreEqual("test", fileText, "error using Stream to read file contents"); - } + file.Delete(); } - finally + + if (!file.Directory.Exists) { - if (tempDirWasCreated) - { - file.Delete(); - // sure hope another process hasn't created the directory - file.Directory.Delete(); - } + file.Directory.Create(); + tempDirWasCreated = true; + } + + StreamWriter sw = file.CreateText(); + sw.WriteLine("test"); + sw.Close(); + + IResource resource = new ReadOnlyXmlTestResource("resource.xml", GetType()); + XmlObjectFactory xof = new XmlObjectFactory(resource); + + ResourceTestObject resource1 = (ResourceTestObject) xof.GetObject("resource1"); + Assert.IsTrue(resource1.Resource is FileSystemResource); + using (StreamReader reader = new StreamReader(resource1.Resource.InputStream)) + { + string fileText = reader.ReadLine(); + Assert.AreEqual("test", fileText, "error using IResource to read file contents"); + } + + using (StreamReader reader = new StreamReader(resource1.InputStream)) + { + string fileText = reader.ReadLine(); + Assert.AreEqual("test", fileText, "error using Stream to read file contents"); } } - - [Test] - public void FactoryMethodsSingletonOnTargetClass() + finally { - DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); - XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(factory); - reader.LoadObjectDefinitions(new ReadOnlyXmlTestResource("factory-methods.xml", GetType())); - - FactoryMethods fm = (FactoryMethods) factory["default"]; - Assert.AreEqual(0, fm.Number); - Assert.AreEqual("default", fm.Name); - Assert.AreEqual("defaultInstance", fm.Object.Name); - Assert.AreEqual("setterString", fm.Value); - - fm = (FactoryMethods) factory["testObjectOnly"]; - Assert.AreEqual(0, fm.Number); - Assert.AreEqual("default", fm.Name); - // This comes from the test object - Assert.AreEqual("Juergen", fm.Object.Name); - - fm = (FactoryMethods) factory["full"]; - Assert.AreEqual(27, fm.Number); - Assert.AreEqual("gotcha", fm.Name); - Assert.AreEqual("Juergen", fm.Object.Name); - - FactoryMethods fm2 = (FactoryMethods) factory["full"]; - Assert.AreSame(fm, fm2); + if (tempDirWasCreated) + { + file.Delete(); + // sure hope another process hasn't created the directory + file.Directory.Delete(); + } } + } - [Test] - public void FactoryMethodsPrototypeOnTargetClass() - { - DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); - XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(factory); - reader.LoadObjectDefinitions(new ReadOnlyXmlTestResource("factory-methods.xml", GetType())); - FactoryMethods fm = (FactoryMethods) factory["defaultPrototype"]; - FactoryMethods fm2 = (FactoryMethods) factory["defaultPrototype"]; - Assert.AreEqual(0, fm.Number); - Assert.AreEqual("default", fm.Name); - Assert.AreEqual("defaultInstance", fm.Object.Name); - Assert.AreEqual("setterString", fm.Value); - Assert.AreEqual(fm.Number, fm2.Number); - Assert.AreEqual(fm.Value, fm2.Value); - // The TestObject is created separately for each object - Assert.IsFalse(ReferenceEquals(fm.Object, fm2.Object)); - Assert.IsFalse(ReferenceEquals(fm, fm2)); + [Test] + public void FactoryMethodsSingletonOnTargetClass() + { + DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); + XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(factory); + reader.LoadObjectDefinitions(new ReadOnlyXmlTestResource("factory-methods.xml", GetType())); - fm = (FactoryMethods) factory["testObjectOnlyPrototype"]; - fm2 = (FactoryMethods) factory["testObjectOnlyPrototype"]; - Assert.AreEqual(0, fm.Number); - Assert.AreEqual("default", fm.Name); - // This comes from the test object - Assert.AreEqual("Juergen", fm.Object.Name); - Assert.AreEqual(fm.Number, fm2.Number); - Assert.AreEqual(fm.Value, fm2.Value); - // The TestObject reference is resolved to a prototype in the factory - Assert.AreSame(fm.Object, fm2.Object); - Assert.IsFalse(ReferenceEquals(fm, fm2)); + FactoryMethods fm = (FactoryMethods) factory["default"]; + Assert.AreEqual(0, fm.Number); + Assert.AreEqual("default", fm.Name); + Assert.AreEqual("defaultInstance", fm.Object.Name); + Assert.AreEqual("setterString", fm.Value); - fm = (FactoryMethods) factory["fullPrototype"]; - fm2 = (FactoryMethods) factory["fullPrototype"]; - Assert.AreEqual(27, fm.Number); - Assert.AreEqual("gotcha", fm.Name); - Assert.AreEqual("Juergen", fm.Object.Name); - Assert.AreEqual(fm.Number, fm2.Number); - Assert.AreEqual(fm.Value, fm2.Value); - // The TestObject reference is resolved to a prototype in the factory - Assert.AreSame(fm.Object, fm2.Object); - Assert.IsFalse(ReferenceEquals(fm, fm2)); - } + fm = (FactoryMethods) factory["testObjectOnly"]; + Assert.AreEqual(0, fm.Number); + Assert.AreEqual("default", fm.Name); + // This comes from the test object + Assert.AreEqual("Juergen", fm.Object.Name); - /// - /// Tests where the static factory method is on a different class - /// - [Test] - public void FactoryMethodsOnExternalClass() - { - DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); - XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(factory); - reader.LoadObjectDefinitions(new ReadOnlyXmlTestResource("factory-methods.xml", GetType())); - TestObject to = (TestObject) factory["externalFactoryMethodWithoutArgs"]; - Assert.AreEqual(2, to.Age); - Assert.AreEqual("Tristan", to.Name); + fm = (FactoryMethods) factory["full"]; + Assert.AreEqual(27, fm.Number); + Assert.AreEqual("gotcha", fm.Name); + Assert.AreEqual("Juergen", fm.Object.Name); - to = (TestObject) factory["externalFactoryMethodWithArgs"]; - Assert.AreEqual(33, to.Age); - Assert.AreEqual("Rod", to.Name); - } + FactoryMethods fm2 = (FactoryMethods) factory["full"]; + Assert.AreSame(fm, fm2); + } - [Test] - public void InstanceFactoryMethodWithoutArgs() - { - DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); - XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(factory); - reader.LoadObjectDefinitions(new ReadOnlyXmlTestResource("factory-methods.xml", GetType())); - FactoryMethods fm = (FactoryMethods) factory["instanceFactoryMethodWithoutArgs"]; - Assert.AreEqual("instanceFactory", fm.Object.Name); - } + [Test] + public void FactoryMethodsPrototypeOnTargetClass() + { + DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); + XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(factory); + reader.LoadObjectDefinitions(new ReadOnlyXmlTestResource("factory-methods.xml", GetType())); + FactoryMethods fm = (FactoryMethods) factory["defaultPrototype"]; + FactoryMethods fm2 = (FactoryMethods) factory["defaultPrototype"]; + Assert.AreEqual(0, fm.Number); + Assert.AreEqual("default", fm.Name); + Assert.AreEqual("defaultInstance", fm.Object.Name); + Assert.AreEqual("setterString", fm.Value); + Assert.AreEqual(fm.Number, fm2.Number); + Assert.AreEqual(fm.Value, fm2.Value); + // The TestObject is created separately for each object + Assert.IsFalse(ReferenceEquals(fm.Object, fm2.Object)); + Assert.IsFalse(ReferenceEquals(fm, fm2)); - [Test(Description = "http://opensource.atlassian.com/projects/spring/browse/SPRNET-492")] - public void InstanceFactoryMethodWithOverloadedArgs() - { - DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); - XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(factory); - reader.LoadObjectDefinitions(new ReadOnlyXmlTestResource("factory-methods.xml", GetType())); - DataTable table = MakeNamesTable(); - DataRow row = table.NewRow(); - //FactoryMethods fm = (FactoryMethods) factory.GetObject("instanceFactoryMethodOverloads", new object[] {row}); - // Assert.AreEqual("DataRowCtor", fm.Name); + fm = (FactoryMethods) factory["testObjectOnlyPrototype"]; + fm2 = (FactoryMethods) factory["testObjectOnlyPrototype"]; + Assert.AreEqual(0, fm.Number); + Assert.AreEqual("default", fm.Name); + // This comes from the test object + Assert.AreEqual("Juergen", fm.Object.Name); + Assert.AreEqual(fm.Number, fm2.Number); + Assert.AreEqual(fm.Value, fm2.Value); + // The TestObject reference is resolved to a prototype in the factory + Assert.AreSame(fm.Object, fm2.Object); + Assert.IsFalse(ReferenceEquals(fm, fm2)); - IDataRecord dataRecord = A.Fake(); - FactoryMethods fm = (FactoryMethods)factory.GetObject("instanceFactoryMethodOverloads", new object[] { dataRecord }); - Assert.AreEqual("DataRecordCtor", fm.Name); - } + fm = (FactoryMethods) factory["fullPrototype"]; + fm2 = (FactoryMethods) factory["fullPrototype"]; + Assert.AreEqual(27, fm.Number); + Assert.AreEqual("gotcha", fm.Name); + Assert.AreEqual("Juergen", fm.Object.Name); + Assert.AreEqual(fm.Number, fm2.Number); + Assert.AreEqual(fm.Value, fm2.Value); + // The TestObject reference is resolved to a prototype in the factory + Assert.AreSame(fm.Object, fm2.Object); + Assert.IsFalse(ReferenceEquals(fm, fm2)); + } - private DataTable MakeNamesTable() - { - // Create a new DataTable titled 'Names.' - DataTable namesTable = new DataTable("Names"); + /// + /// Tests where the static factory method is on a different class + /// + [Test] + public void FactoryMethodsOnExternalClass() + { + DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); + XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(factory); + reader.LoadObjectDefinitions(new ReadOnlyXmlTestResource("factory-methods.xml", GetType())); + TestObject to = (TestObject) factory["externalFactoryMethodWithoutArgs"]; + Assert.AreEqual(2, to.Age); + Assert.AreEqual("Tristan", to.Name); - // Add three column objects to the table. - DataColumn idColumn = new DataColumn(); - idColumn.DataType = System.Type.GetType("System.Int32"); - idColumn.ColumnName = "id"; - idColumn.AutoIncrement = true; - namesTable.Columns.Add(idColumn); + to = (TestObject) factory["externalFactoryMethodWithArgs"]; + Assert.AreEqual(33, to.Age); + Assert.AreEqual("Rod", to.Name); + } - DataColumn fNameColumn = new DataColumn(); - fNameColumn.DataType = System.Type.GetType("System.String"); - fNameColumn.ColumnName = "Fname"; - fNameColumn.DefaultValue = "Fname"; - namesTable.Columns.Add(fNameColumn); + [Test] + public void InstanceFactoryMethodWithoutArgs() + { + DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); + XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(factory); + reader.LoadObjectDefinitions(new ReadOnlyXmlTestResource("factory-methods.xml", GetType())); + FactoryMethods fm = (FactoryMethods) factory["instanceFactoryMethodWithoutArgs"]; + Assert.AreEqual("instanceFactory", fm.Object.Name); + } - DataColumn lNameColumn = new DataColumn(); - lNameColumn.DataType = System.Type.GetType("System.String"); - lNameColumn.ColumnName = "LName"; - namesTable.Columns.Add(lNameColumn); + [Test(Description = "http://opensource.atlassian.com/projects/spring/browse/SPRNET-492")] + public void InstanceFactoryMethodWithOverloadedArgs() + { + DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); + XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(factory); + reader.LoadObjectDefinitions(new ReadOnlyXmlTestResource("factory-methods.xml", GetType())); + DataTable table = MakeNamesTable(); + DataRow row = table.NewRow(); + //FactoryMethods fm = (FactoryMethods) factory.GetObject("instanceFactoryMethodOverloads", new object[] {row}); + // Assert.AreEqual("DataRowCtor", fm.Name); - // Create an array for DataColumn objects. - DataColumn[] keys = new DataColumn[1]; - keys[0] = idColumn; - namesTable.PrimaryKey = keys; + IDataRecord dataRecord = A.Fake(); + FactoryMethods fm = (FactoryMethods) factory.GetObject("instanceFactoryMethodOverloads", new object[] { dataRecord }); + Assert.AreEqual("DataRecordCtor", fm.Name); + } - // Return the new DataTable. - return namesTable; - } + private DataTable MakeNamesTable() + { + // Create a new DataTable titled 'Names.' + DataTable namesTable = new DataTable("Names"); - [Test] - public void FactoryMethodNoMatchingStaticMethod() - { - DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); - XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(factory); - reader.LoadObjectDefinitions(new ReadOnlyXmlTestResource("factory-methods.xml", GetType())); - Assert.Throws(() => factory.GetObject("noMatchPrototype")); - } + // Add three column objects to the table. + DataColumn idColumn = new DataColumn(); + idColumn.DataType = System.Type.GetType("System.Int32"); + idColumn.ColumnName = "id"; + idColumn.AutoIncrement = true; + namesTable.Columns.Add(idColumn); - [Test] - public void CanSpecifyFactoryMethodArgumentsOnFactoryMethodPrototype() - { - DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); - XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(factory); - reader.LoadObjectDefinitions(new ReadOnlyXmlTestResource("factory-methods.xml", GetType())); - TestObject toArg = new TestObject(); - toArg.Name = "arg1"; - TestObject toArg2 = new TestObject(); - toArg2.Name = "arg2"; - FactoryMethods fm1 = (FactoryMethods) factory.GetObject("testObjectOnlyPrototype", new object[] {toArg}); - FactoryMethods fm2 = (FactoryMethods) factory.GetObject("testObjectOnlyPrototype", new object[] {toArg2}); + DataColumn fNameColumn = new DataColumn(); + fNameColumn.DataType = System.Type.GetType("System.String"); + fNameColumn.ColumnName = "Fname"; + fNameColumn.DefaultValue = "Fname"; + namesTable.Columns.Add(fNameColumn); - Assert.AreEqual(0, fm1.Number); - Assert.AreEqual("default", fm1.Name); - // This comes from the test object - Assert.AreEqual("arg1", fm1.Object.Name); - Assert.AreEqual("arg2", fm2.Object.Name); - Assert.AreEqual(fm1.Number, fm2.Number); - Assert.AreEqual(fm2.Value, "testObjectOnlyPrototypeDISetterString"); - Assert.AreEqual(fm2.Value, fm2.Value); - // The TestObject reference is resolved to a prototype in the factory - Assert.AreSame(fm2.Object, fm2.Object); - Assert.IsFalse(ReferenceEquals(fm1, fm2)); - } + DataColumn lNameColumn = new DataColumn(); + lNameColumn.DataType = System.Type.GetType("System.String"); + lNameColumn.ColumnName = "LName"; + namesTable.Columns.Add(lNameColumn); - //[Test] - //[ExpectedException(typeof(ObjectDefinitionStoreException))] - //public void CannotSpecifyFactoryMethodArgumentsOnSingleton() - //{ - // DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); - // XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(factory); - // reader.LoadObjectDefinitions(new ReadOnlyXmlTestResource("factory-methods.xml", GetType())); - // factory.GetObject("testObjectOnly", new object[] {new TestObject()}); - //} + // Create an array for DataColumn objects. + DataColumn[] keys = new DataColumn[1]; + keys[0] = idColumn; + namesTable.PrimaryKey = keys; - //[Test] - //[ExpectedException(typeof(ObjectDefinitionStoreException))] - //public void CannotSpecifyFactoryMethodArgumentsExceptWithFactoryMethod() - //{ - // DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); - // XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(factory); - // reader.LoadObjectDefinitions(new ReadOnlyXmlTestResource("overrides.xml", GetType())); - // factory.GetObject("overrideOnPrototype", new object[] {new TestObject()}); - //} + // Return the new DataTable. + return namesTable; + } - [Test] - public void StaticPropertyRetrievingFactoryMethod() - { - DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); - XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(factory); - reader.LoadObjectDefinitions(new ReadOnlyXmlTestResource("field-props-factory.xml", GetType())); - MyTestObject obj = factory.GetObject("cultureAware", typeof(MyTestObject)) as MyTestObject; - Assert.IsNotNull(obj.Culture); - Assert.AreEqual(CultureInfo.CurrentUICulture, obj.Culture); - } + [Test] + public void FactoryMethodNoMatchingStaticMethod() + { + DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); + XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(factory); + reader.LoadObjectDefinitions(new ReadOnlyXmlTestResource("factory-methods.xml", GetType())); + Assert.Throws(() => factory.GetObject("noMatchPrototype")); + } - [Test] - public void StaticFieldRetrievingFactoryMethod() - { - DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); - XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(factory); - reader.LoadObjectDefinitions(new ReadOnlyXmlTestResource("field-props-factory.xml", GetType())); - MyTestObject obj = factory.GetObject("withTypesField", typeof(MyTestObject)) as MyTestObject; - Assert.IsNotNull(obj.Types); - Assert.AreEqual(Type.EmptyTypes.Length, obj.Types.Length); - } + [Test] + public void CanSpecifyFactoryMethodArgumentsOnFactoryMethodPrototype() + { + DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); + XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(factory); + reader.LoadObjectDefinitions(new ReadOnlyXmlTestResource("factory-methods.xml", GetType())); + TestObject toArg = new TestObject(); + toArg.Name = "arg1"; + TestObject toArg2 = new TestObject(); + toArg2.Name = "arg2"; + FactoryMethods fm1 = (FactoryMethods) factory.GetObject("testObjectOnlyPrototype", new object[] { toArg }); + FactoryMethods fm2 = (FactoryMethods) factory.GetObject("testObjectOnlyPrototype", new object[] { toArg2 }); - [Test] - public void InstancePropertyRetrievingFactoryMethod() - { - DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); - XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(factory); - reader.LoadObjectDefinitions(new ReadOnlyXmlTestResource("field-props-factory.xml", GetType())); - MyTestObject obj = factory.GetObject("instancePropertyCultureAware", typeof(MyTestObject)) as MyTestObject; - Assert.IsNotNull(obj.Culture); - Assert.AreEqual(new MyTestObject().MyDefaultCulture, obj.Culture); - } + Assert.AreEqual(0, fm1.Number); + Assert.AreEqual("default", fm1.Name); + // This comes from the test object + Assert.AreEqual("arg1", fm1.Object.Name); + Assert.AreEqual("arg2", fm2.Object.Name); + Assert.AreEqual(fm1.Number, fm2.Number); + Assert.AreEqual(fm2.Value, "testObjectOnlyPrototypeDISetterString"); + Assert.AreEqual(fm2.Value, fm2.Value); + // The TestObject reference is resolved to a prototype in the factory + Assert.AreSame(fm2.Object, fm2.Object); + Assert.IsFalse(ReferenceEquals(fm1, fm2)); + } - [Test] - public void InstanceFieldRetrievingFactoryMethod() - { - DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); - XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(factory); - reader.LoadObjectDefinitions(new ReadOnlyXmlTestResource("field-props-factory.xml", GetType())); - MyTestObject obj = factory.GetObject("instanceCultureAware", typeof(MyTestObject)) as MyTestObject; - Assert.IsNotNull(obj.Culture); - Assert.AreEqual(new MyTestObject().Default, obj.Culture); - } + //[Test] + //[ExpectedException(typeof(ObjectDefinitionStoreException))] + //public void CannotSpecifyFactoryMethodArgumentsOnSingleton() + //{ + // DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); + // XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(factory); + // reader.LoadObjectDefinitions(new ReadOnlyXmlTestResource("factory-methods.xml", GetType())); + // factory.GetObject("testObjectOnly", new object[] {new TestObject()}); + //} - [Test] - public void BailsOnRubbishFieldRetrievingFactoryMethod() - { - DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); - XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(factory); - reader.LoadObjectDefinitions(new ReadOnlyXmlTestResource("field-props-factory.xml", GetType())); - Assert.Throws(() => factory.GetObject("rubbishField", typeof(MyTestObject))); - } + //[Test] + //[ExpectedException(typeof(ObjectDefinitionStoreException))] + //public void CannotSpecifyFactoryMethodArgumentsExceptWithFactoryMethod() + //{ + // DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); + // XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(factory); + // reader.LoadObjectDefinitions(new ReadOnlyXmlTestResource("overrides.xml", GetType())); + // factory.GetObject("overrideOnPrototype", new object[] {new TestObject()}); + //} - [Test] - public void BailsOnRubbishPropertyRetrievingFactoryMethod() - { - DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); - XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(factory); - reader.LoadObjectDefinitions(new ReadOnlyXmlTestResource("field-props-factory.xml", GetType())); - Assert.Throws(() => factory.GetObject("rubbishProperty", typeof(MyTestObject))); - } + [Test] + public void StaticPropertyRetrievingFactoryMethod() + { + DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); + XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(factory); + reader.LoadObjectDefinitions(new ReadOnlyXmlTestResource("field-props-factory.xml", GetType())); + MyTestObject obj = factory.GetObject("cultureAware", typeof(MyTestObject)) as MyTestObject; + Assert.IsNotNull(obj.Culture); + Assert.AreEqual(CultureInfo.CurrentUICulture, obj.Culture); + } - /// - /// Test creating an object using its 1 arg boolean constructor (amongst - /// others) by specifying the constructor arguments type and - /// not its index number. - /// - [Test] - public void ConstructorArgWithSimpleTypeMatch() - { - XmlObjectFactory xof - = new XmlObjectFactory( - new ReadOnlyXmlTestResource("constructor-arg.xml", GetType())); - SingleSimpleTypeConstructorObject obj = - (SingleSimpleTypeConstructorObject) xof.GetObject("objectWithBoolean"); - Assert.IsTrue(obj.SingleBoolean); - } + [Test] + public void StaticFieldRetrievingFactoryMethod() + { + DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); + XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(factory); + reader.LoadObjectDefinitions(new ReadOnlyXmlTestResource("field-props-factory.xml", GetType())); + MyTestObject obj = factory.GetObject("withTypesField", typeof(MyTestObject)) as MyTestObject; + Assert.IsNotNull(obj.Types); + Assert.AreEqual(Type.EmptyTypes.Length, obj.Types.Length); + } - /// - /// Test creating an object using its two argument constructor (amongst - /// others) by specifying both ctor arguments type and not their index - /// numbers. - /// - [Test] - public void ConstructorArgWithDoubleSimpleTypeMatch() - { - XmlObjectFactory xof - = new XmlObjectFactory( - new ReadOnlyXmlTestResource("constructor-arg.xml", GetType())); - SingleSimpleTypeConstructorObject obj = - (SingleSimpleTypeConstructorObject) xof.GetObject("objectWithBooleanAndString"); - Assert.IsTrue(obj.SecondBoolean); - Assert.AreEqual("A String", obj.TestString); - } + [Test] + public void InstancePropertyRetrievingFactoryMethod() + { + DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); + XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(factory); + reader.LoadObjectDefinitions(new ReadOnlyXmlTestResource("field-props-factory.xml", GetType())); + MyTestObject obj = factory.GetObject("instancePropertyCultureAware", typeof(MyTestObject)) as MyTestObject; + Assert.IsNotNull(obj.Culture); + Assert.AreEqual(new MyTestObject().MyDefaultCulture, obj.Culture); + } - [Test] - public void DoubleBooleanAutowire() - { - XmlObjectFactory xof - = new XmlObjectFactory( - new ReadOnlyXmlTestResource("constructor-arg.xml", GetType())); - DoubleBooleanConstructorObject obj = - (DoubleBooleanConstructorObject) xof.GetObject("objectWithDoubleBoolean"); - Assert.IsTrue(obj.Boolean1); - Assert.IsFalse(obj.Boolean2); - } + [Test] + public void InstanceFieldRetrievingFactoryMethod() + { + DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); + XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(factory); + reader.LoadObjectDefinitions(new ReadOnlyXmlTestResource("field-props-factory.xml", GetType())); + MyTestObject obj = factory.GetObject("instanceCultureAware", typeof(MyTestObject)) as MyTestObject; + Assert.IsNotNull(obj.Culture); + Assert.AreEqual(new MyTestObject().Default, obj.Culture); + } - [Test] - public void ParsesNamedCtorArgsCorrectly() - { - XmlObjectFactory fac = new XmlObjectFactory( + [Test] + public void BailsOnRubbishFieldRetrievingFactoryMethod() + { + DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); + XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(factory); + reader.LoadObjectDefinitions(new ReadOnlyXmlTestResource("field-props-factory.xml", GetType())); + Assert.Throws(() => factory.GetObject("rubbishField", typeof(MyTestObject))); + } + + [Test] + public void BailsOnRubbishPropertyRetrievingFactoryMethod() + { + DefaultListableObjectFactory factory = new DefaultListableObjectFactory(); + XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(factory); + reader.LoadObjectDefinitions(new ReadOnlyXmlTestResource("field-props-factory.xml", GetType())); + Assert.Throws(() => factory.GetObject("rubbishProperty", typeof(MyTestObject))); + } + + /// + /// Test creating an object using its 1 arg boolean constructor (amongst + /// others) by specifying the constructor arguments type and + /// not its index number. + /// + [Test] + public void ConstructorArgWithSimpleTypeMatch() + { + XmlObjectFactory xof + = new XmlObjectFactory( new ReadOnlyXmlTestResource("constructor-arg.xml", GetType())); - IObjectDefinition obj = fac.GetObjectDefinition("ctorArgsAllNamed"); - Assert.AreEqual(2, obj.ConstructorArgumentValues.NamedArgumentValues.Count, - "Should have parsed 2 named ctor args."); - ConstructorArgumentValues.ValueHolder nameArg = obj.ConstructorArgumentValues.GetNamedArgumentValue("name"); - Assert.IsNotNull(nameArg, "Should have parsed the 'name' ctor arg."); - Assert.AreEqual("Isaac Newton", nameArg.Value); - ConstructorArgumentValues.ValueHolder ageArg = obj.ConstructorArgumentValues.GetNamedArgumentValue("age"); - Assert.IsNotNull(ageArg, "Should have parsed the 'age' ctor arg."); - Assert.AreEqual("87", ageArg.Value); - } + SingleSimpleTypeConstructorObject obj = + (SingleSimpleTypeConstructorObject) xof.GetObject("objectWithBoolean"); + Assert.IsTrue(obj.SingleBoolean); + } - [Test] - public void InstantiateObjectViaNamedArgsToInnerMethodInvokingFactoryObject() - { - XmlObjectFactory fac = new XmlObjectFactory( + /// + /// Test creating an object using its two argument constructor (amongst + /// others) by specifying both ctor arguments type and not their index + /// numbers. + /// + [Test] + public void ConstructorArgWithDoubleSimpleTypeMatch() + { + XmlObjectFactory xof + = new XmlObjectFactory( new ReadOnlyXmlTestResource("constructor-arg.xml", GetType())); - ITestObject obj = (ITestObject) fac.GetObject("grabCtorArgFromMethodInvokingFactoryObject"); - Assert.AreEqual("Mr Isaac Newton Phd PPQ MC DJ", obj.Name); - Assert.AreEqual(198, obj.Age); - } + SingleSimpleTypeConstructorObject obj = + (SingleSimpleTypeConstructorObject) xof.GetObject("objectWithBooleanAndString"); + Assert.IsTrue(obj.SecondBoolean); + Assert.AreEqual("A String", obj.TestString); + } - [Test] - public void BailsWhenBothNameAndIndexAttributesAreAppliedToASingleCtorArg() - { - Assert.Throws(() => new XmlObjectFactory(new ReadOnlyXmlTestResource("bad-named-constructor-arg.xml", GetType()))); - } - - [Test] - public void GetObjectThatUsesCtorArgValueShortcuts() - { - XmlObjectFactory xof = new XmlObjectFactory( + [Test] + public void DoubleBooleanAutowire() + { + XmlObjectFactory xof + = new XmlObjectFactory( new ReadOnlyXmlTestResource("constructor-arg.xml", GetType())); - TestObject to = (TestObject) xof.GetObject("objectWithCtorArgValueShortcuts"); - Assert.AreEqual("Rick", to.Name); - Assert.AreEqual(30, to.Age); - } + DoubleBooleanConstructorObject obj = + (DoubleBooleanConstructorObject) xof.GetObject("objectWithDoubleBoolean"); + Assert.IsTrue(obj.Boolean1); + Assert.IsFalse(obj.Boolean2); + } - [Test] - public void GetObjectThatUsesCtorArgRefShortcuts() - { - XmlObjectFactory xof = new XmlObjectFactory( - new ReadOnlyXmlTestResource("constructor-arg.xml", GetType())); - TestObject to = (TestObject) xof.GetObject("objectWithCtorArgRefShortcuts"); - ITestObject spouse = to.Spouse; - Assert.IsNotNull(spouse, "Dependency not wired in when using 'ref' attribute shortcut."); - Assert.AreEqual("Kerry2", spouse.Name); - } + [Test] + public void ParsesNamedCtorArgsCorrectly() + { + XmlObjectFactory fac = new XmlObjectFactory( + new ReadOnlyXmlTestResource("constructor-arg.xml", GetType())); + IObjectDefinition obj = fac.GetObjectDefinition("ctorArgsAllNamed"); + Assert.AreEqual(2, obj.ConstructorArgumentValues.NamedArgumentValues.Count, + "Should have parsed 2 named ctor args."); + ConstructorArgumentValues.ValueHolder nameArg = obj.ConstructorArgumentValues.GetNamedArgumentValue("name"); + Assert.IsNotNull(nameArg, "Should have parsed the 'name' ctor arg."); + Assert.AreEqual("Isaac Newton", nameArg.Value); + ConstructorArgumentValues.ValueHolder ageArg = obj.ConstructorArgumentValues.GetNamedArgumentValue("age"); + Assert.IsNotNull(ageArg, "Should have parsed the 'age' ctor arg."); + Assert.AreEqual("87", ageArg.Value); + } - [Test(Description="SPR-1313")] - public void UseStaticFactoryMethodInnerObjectDefinition() - { - new StreamHelperDecorator(new StreamHelperCallback(_UseStaticFactoryMethodInnerObjectDefinition)).Run(); - } + [Test] + public void InstantiateObjectViaNamedArgsToInnerMethodInvokingFactoryObject() + { + XmlObjectFactory fac = new XmlObjectFactory( + new ReadOnlyXmlTestResource("constructor-arg.xml", GetType())); + ITestObject obj = (ITestObject) fac.GetObject("grabCtorArgFromMethodInvokingFactoryObject"); + Assert.AreEqual("Mr Isaac Newton Phd PPQ MC DJ", obj.Name); + Assert.AreEqual(198, obj.Age); + } - private void _UseStaticFactoryMethodInnerObjectDefinition(out Stream stream) - { - const string xml = - @" + [Test] + public void BailsWhenBothNameAndIndexAttributesAreAppliedToASingleCtorArg() + { + Assert.Throws(() => new XmlObjectFactory(new ReadOnlyXmlTestResource("bad-named-constructor-arg.xml", GetType()))); + } + + [Test] + public void GetObjectThatUsesCtorArgValueShortcuts() + { + XmlObjectFactory xof = new XmlObjectFactory( + new ReadOnlyXmlTestResource("constructor-arg.xml", GetType())); + TestObject to = (TestObject) xof.GetObject("objectWithCtorArgValueShortcuts"); + Assert.AreEqual("Rick", to.Name); + Assert.AreEqual(30, to.Age); + } + + [Test] + public void GetObjectThatUsesCtorArgRefShortcuts() + { + XmlObjectFactory xof = new XmlObjectFactory( + new ReadOnlyXmlTestResource("constructor-arg.xml", GetType())); + TestObject to = (TestObject) xof.GetObject("objectWithCtorArgRefShortcuts"); + ITestObject spouse = to.Spouse; + Assert.IsNotNull(spouse, "Dependency not wired in when using 'ref' attribute shortcut."); + Assert.AreEqual("Kerry2", spouse.Name); + } + + [Test(Description = "SPR-1313")] + public void UseStaticFactoryMethodInnerObjectDefinition() + { + new StreamHelperDecorator(new StreamHelperCallback(_UseStaticFactoryMethodInnerObjectDefinition)).Run(); + } + + private void _UseStaticFactoryMethodInnerObjectDefinition(out Stream stream) + { + const string xml = + @" @@ -1786,22 +1782,22 @@ namespace Spring.Objects.Factory.Xml "; - stream = new MemoryStream(Encoding.UTF8.GetBytes(xml)); - IObjectFactory factory = new XmlObjectFactory(new InputStreamResource(stream, string.Empty)); - ITestObject to = (ITestObject) factory.GetObject("foo"); - Assert.IsNotNull( to.Spouse ); - } + stream = new MemoryStream(Encoding.UTF8.GetBytes(xml)); + IObjectFactory factory = new XmlObjectFactory(new InputStreamResource(stream, string.Empty)); + ITestObject to = (ITestObject) factory.GetObject("foo"); + Assert.IsNotNull(to.Spouse); + } - [Test(Description="SPR-1313")] - public void UseInstanceFactoryMethodInnerObjectDefinition() - { - new StreamHelperDecorator(new StreamHelperCallback(_UseInstanceFactoryMethodInnerObjectDefinition)).Run(); - } + [Test(Description = "SPR-1313")] + public void UseInstanceFactoryMethodInnerObjectDefinition() + { + new StreamHelperDecorator(new StreamHelperCallback(_UseInstanceFactoryMethodInnerObjectDefinition)).Run(); + } - private void _UseInstanceFactoryMethodInnerObjectDefinition(out Stream stream) - { - const string xml = - @" + private void _UseInstanceFactoryMethodInnerObjectDefinition(out Stream stream) + { + const string xml = + @" @@ -1812,10 +1808,10 @@ namespace Spring.Objects.Factory.Xml "; - stream = new MemoryStream(Encoding.UTF8.GetBytes(xml)); - IObjectFactory factory = new XmlObjectFactory(new InputStreamResource(stream, string.Empty)); - factory.GetObject("foo"); - } + stream = new MemoryStream(Encoding.UTF8.GetBytes(xml)); + IObjectFactory factory = new XmlObjectFactory(new InputStreamResource(stream, string.Empty)); + factory.GetObject("foo"); + } #if !NETCOREAPP [Test] @@ -1861,186 +1857,193 @@ namespace Spring.Objects.Factory.Xml } #endif - public class LazyWorker + public class LazyWorker + { + private XmlObjectFactory xof; + private Object objectFromContext; + + public LazyWorker(XmlObjectFactory xof) { - private XmlObjectFactory xof; - private Object objectFromContext; - public LazyWorker(XmlObjectFactory xof) - { - this.xof = xof; - } - public void DoWork() - { - objectFromContext = xof.GetObject("lazyObject"); - } - - public Object ObjectFromContext => objectFromContext; - } - public sealed class MyTestObject - { - public readonly CultureInfo Default = new CultureInfo("af-ZA"); - - public Type[] Types - { - get => _types; - set => _types = value; - } - - public CultureInfo Culture - { - get => _culture; - set => _culture = value; - } - - public CultureInfo MyDefaultCulture => Default; - - private Type[] _types; - private CultureInfo _culture; + this.xof = xof; } - public class BadInitializer + public void DoWork() { - public void Init2() - { - throw new FormatException(); - } + objectFromContext = xof.GetObject("lazyObject"); } - public class DoubleInitializer + public Object ObjectFromContext => objectFromContext; + } + + public sealed class MyTestObject + { + public readonly CultureInfo Default = new CultureInfo("af-ZA"); + + public Type[] Types { - public int Num - { - get => num; - set => num = value; - } - - private int num; - - public void Init() - { - this.num *= 2; - } + get => _types; + set => _types = value; } - public class DefaultDestroyer + public CultureInfo Culture { - public bool customDestroyed; - - public void CustomDestroy() - { - customDestroyed = true; - } + get => _culture; + set => _culture = value; } - public class InitAndIB : IInitializingObject, IDisposable + public CultureInfo MyDefaultCulture => Default; + + private Type[] _types; + private CultureInfo _culture; + } + + public class BadInitializer + { + public void Init2() { - public static bool constructed; - public bool afterPropertiesSetInvoked, initMethodInvoked, destroyed, customDestroyed; - - public InitAndIB() - { - constructed = true; - } - - public void AfterPropertiesSet() - { - if (this.initMethodInvoked) - { - Assert.Fail(); - } - this.afterPropertiesSetInvoked = true; - } - - public void CustomInit() - { - if (!this.afterPropertiesSetInvoked) - { - Assert.Fail(); - } - this.initMethodInvoked = true; - } - - public void Dispose() - { - if (this.customDestroyed) - { - Assert.Fail(); - } - if (this.destroyed) - { - throw new ApplicationException("Already destroyed"); - } - this.destroyed = true; - } - - public void CustomDestroy() - { - if (!this.destroyed) - { - Assert.Fail(); - } - if (this.customDestroyed) - { - throw new ApplicationException("Already customDestroyed"); - } - this.customDestroyed = true; - } - } - - public class PreparingObject1 : IDisposable - { - public static bool prepared = false; - public static bool destroyed = false; - - public PreparingObject1() - { - prepared = true; - } - - public void Dispose() - { - destroyed = true; - } - } - - public class PreparingObject2 : IDisposable - { - public static bool prepared = false; - public static bool destroyed = false; - - public PreparingObject2() - { - prepared = true; - } - - public void Dispose() - { - destroyed = true; - } - } - - public class DependingObject : IDisposable - { - public static bool destroyed = false; - - public DependingObject() - { - if (!(PreparingObject1.prepared && PreparingObject2.prepared)) - { - throw new ApplicationException("Need prepared PreparedObjects!"); - } - } - - public void Dispose() - { - if (PreparingObject1.destroyed || PreparingObject2.destroyed) - { - throw new ApplicationException("Should not be destroyed before PreparedObjects"); - } - destroyed = true; - } + throw new FormatException(); } } + public class DoubleInitializer + { + public int Num + { + get => num; + set => num = value; + } + private int num; + + public void Init() + { + this.num *= 2; + } + } + + public class DefaultDestroyer + { + public bool customDestroyed; + + public void CustomDestroy() + { + customDestroyed = true; + } + } + + public class InitAndIB : IInitializingObject, IDisposable + { + public static bool constructed; + public bool afterPropertiesSetInvoked, initMethodInvoked, destroyed, customDestroyed; + + public InitAndIB() + { + constructed = true; + } + + public void AfterPropertiesSet() + { + if (this.initMethodInvoked) + { + Assert.Fail(); + } + + this.afterPropertiesSetInvoked = true; + } + + public void CustomInit() + { + if (!this.afterPropertiesSetInvoked) + { + Assert.Fail(); + } + + this.initMethodInvoked = true; + } + + public void Dispose() + { + if (this.customDestroyed) + { + Assert.Fail(); + } + + if (this.destroyed) + { + throw new ApplicationException("Already destroyed"); + } + + this.destroyed = true; + } + + public void CustomDestroy() + { + if (!this.destroyed) + { + Assert.Fail(); + } + + if (this.customDestroyed) + { + throw new ApplicationException("Already customDestroyed"); + } + + this.customDestroyed = true; + } + } + + public class PreparingObject1 : IDisposable + { + public static bool prepared = false; + public static bool destroyed = false; + + public PreparingObject1() + { + prepared = true; + } + + public void Dispose() + { + destroyed = true; + } + } + + public class PreparingObject2 : IDisposable + { + public static bool prepared = false; + public static bool destroyed = false; + + public PreparingObject2() + { + prepared = true; + } + + public void Dispose() + { + destroyed = true; + } + } + + public class DependingObject : IDisposable + { + public static bool destroyed = false; + + public DependingObject() + { + if (!(PreparingObject1.prepared && PreparingObject2.prepared)) + { + throw new ApplicationException("Need prepared PreparedObjects!"); + } + } + + public void Dispose() + { + if (PreparingObject1.destroyed || PreparingObject2.destroyed) + { + throw new ApplicationException("Should not be destroyed before PreparedObjects"); + } + + destroyed = true; + } + } } diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/XmlParserResolverTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/XmlParserResolverTests.cs index 1a300464..ebb9413d 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/XmlParserResolverTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/XmlParserResolverTests.cs @@ -26,70 +26,68 @@ using Spring.Objects.Factory.Config; #endregion -namespace Spring.Objects.Factory.Xml +namespace Spring.Objects.Factory.Xml; + +/// +/// Unit tests for the XmlParserResolver class. +/// +/// Rick Evans +/// Aleksandar Seovic 2006.11.21 +[TestFixture] +public sealed class XmlParserResolverTests { - /// - /// Unit tests for the XmlParserResolver class. - /// - /// Rick Evans - /// Aleksandar Seovic 2006.11.21 - [TestFixture] - public sealed class XmlParserResolverTests - { - [Test] - public void RegisterParserWithNullType() - { - Assert.Throws(() => NamespaceParserRegistry.RegisterParser((Type) null)); - } + [Test] + public void RegisterParserWithNullType() + { + Assert.Throws(() => NamespaceParserRegistry.RegisterParser((Type) null)); + } - [Test] - public void RegisterParserWithBadParserType() - { - Assert.Throws(() => NamespaceParserRegistry.RegisterParser(GetType())); - } + [Test] + public void RegisterParserWithBadParserType() + { + Assert.Throws(() => NamespaceParserRegistry.RegisterParser(GetType())); + } - [Test] - public void RegisterParserWithNullNamespaceWithoutDefaultValues() - { - Assert.Throws(() => NamespaceParserRegistry.RegisterParser(typeof(NotImplementedXmlObjectDefinitionParser), null, null)); - } + [Test] + public void RegisterParserWithNullNamespaceWithoutDefaultValues() + { + Assert.Throws(() => NamespaceParserRegistry.RegisterParser(typeof(NotImplementedXmlObjectDefinitionParser), null, null)); + } - [Test] - public void RegisterParserWithEmptyNamespaceWithoutDefaultValues() - { - Assert.Throws(() => NamespaceParserRegistry.RegisterParser(typeof(NotImplementedXmlObjectDefinitionParser), string.Empty, null)); - } + [Test] + public void RegisterParserWithEmptyNamespaceWithoutDefaultValues() + { + Assert.Throws(() => NamespaceParserRegistry.RegisterParser(typeof(NotImplementedXmlObjectDefinitionParser), string.Empty, null)); + } - #region Inner Class : NotImplementedXmlObjectDefinitionParser + #region Inner Class : NotImplementedXmlObjectDefinitionParser - private sealed class NotImplementedXmlObjectDefinitionParser : INamespaceParser - { - #region IXmlObjectDefinitionParser Members + private sealed class NotImplementedXmlObjectDefinitionParser : INamespaceParser + { + #region IXmlObjectDefinitionParser Members - /// - /// Invoked by after construction but before any - /// elements have been parsed. - /// - public void Init() - { - throw new NotImplementedException(); - } + /// + /// Invoked by after construction but before any + /// elements have been parsed. + /// + public void Init() + { + throw new NotImplementedException(); + } - #endregion + #endregion - public IObjectDefinition ParseElement(XmlElement element, ParserContext parserContext) - { - throw new NotImplementedException(); - } + public IObjectDefinition ParseElement(XmlElement element, ParserContext parserContext) + { + throw new NotImplementedException(); + } - public ObjectDefinitionHolder Decorate(XmlNode node, ObjectDefinitionHolder definition, - ParserContext parserContext) - { - throw new NotImplementedException(); - } - - } + public ObjectDefinitionHolder Decorate(XmlNode node, ObjectDefinitionHolder definition, + ParserContext parserContext) + { + throw new NotImplementedException(); + } + } - #endregion - } -} \ No newline at end of file + #endregion +} diff --git a/test/Spring/Spring.Core.Tests/Objects/INestedTestObject.cs b/test/Spring/Spring.Core.Tests/Objects/INestedTestObject.cs index 83fb40ad..6702e6e3 100644 --- a/test/Spring/Spring.Core.Tests/Objects/INestedTestObject.cs +++ b/test/Spring/Spring.Core.Tests/Objects/INestedTestObject.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -18,10 +18,9 @@ #endregion -namespace Spring.Objects +namespace Spring.Objects; + +public interface INestedTestObject { - public interface INestedTestObject - { - string Company { get; set; } - } + string Company { get; set; } } \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/Objects/IOther.cs b/test/Spring/Spring.Core.Tests/Objects/IOther.cs index 3f329e72..edc8f396 100644 --- a/test/Spring/Spring.Core.Tests/Objects/IOther.cs +++ b/test/Spring/Spring.Core.Tests/Objects/IOther.cs @@ -1,38 +1,38 @@ #region License + /* * Copyright 2002-2010 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 #region Imports + #endregion -namespace Spring.Objects +namespace Spring.Objects; + +/// +/// Alternate nonsense interface used for testing. +/// +/// Spring.Java Folks +/// Choy Rim (.NET) +public interface IOther { - /// - /// Alternate nonsense interface used for testing. - /// - /// Spring.Java Folks - /// Choy Rim (.NET) - public interface IOther - { - - /// - /// Nonsense method - /// - void Absquatulate(); - - } + /// + /// Nonsense method + /// + void Absquatulate(); } diff --git a/test/Spring/Spring.Core.Tests/Objects/IPerson.cs b/test/Spring/Spring.Core.Tests/Objects/IPerson.cs index 6bf70549..2804a009 100644 --- a/test/Spring/Spring.Core.Tests/Objects/IPerson.cs +++ b/test/Spring/Spring.Core.Tests/Objects/IPerson.cs @@ -1,40 +1,41 @@ #region License + /* * Copyright 2002-2010 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 -namespace Spring.Objects -{ - /// - /// Extends the normal test object to provide methods that are - /// useful when testing AOP method interception (hence the Get/Set methods). - /// - /// Rod Johnson - /// Simon White (.NET) - public interface IPerson : ITestObject - { - int GetAge(); - void SetAge(int age); - string GetName(); - void SetName(string name); +namespace Spring.Objects; - /// - /// Test for non-property method matching. - /// If the parameter is an exception, it will be thrown rather than returned. - /// - object Echo(object obj); - } +/// +/// Extends the normal test object to provide methods that are +/// useful when testing AOP method interception (hence the Get/Set methods). +/// +/// Rod Johnson +/// Simon White (.NET) +public interface IPerson : ITestObject +{ + int GetAge(); + void SetAge(int age); + string GetName(); + void SetName(string name); + + /// + /// Test for non-property method matching. + /// If the parameter is an exception, it will be thrown rather than returned. + /// + object Echo(object obj); } diff --git a/test/Spring/Spring.Core.Tests/Objects/ITestObject.cs b/test/Spring/Spring.Core.Tests/Objects/ITestObject.cs index f79cf932..8df8f5cc 100644 --- a/test/Spring/Spring.Core.Tests/Objects/ITestObject.cs +++ b/test/Spring/Spring.Core.Tests/Objects/ITestObject.cs @@ -1,83 +1,83 @@ #region License + /* -* Copyright 2002-2010 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. -*/ + * Copyright 2002-2010 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.Collections; -namespace Spring.Objects +namespace Spring.Objects; + +public interface ITestObject { - public interface ITestObject + event EventHandler Click; + + /// + /// Public method to programmatically raise the Click event + /// while testing. + /// + void OnClick(); + + int Age { - event EventHandler Click; - - /// - /// Public method to programmatically raise the Click event - /// while testing. - /// - void OnClick (); - - int Age - { - get; - set; - } - - ICollection Friends - { - get; - } - - INestedTestObject Doctor - { - get; - } - - INestedTestObject Lawyer - { - get; - } - - string Name - { - get; - set; - } - - ITestObject Spouse - { - get; - set; - } - - - /// - /// Gets the exception method call count. - /// - /// The exception method call count. - int ExceptionMethodCallCount - { - get; - } - - void Exceptional (Exception t); - - int ExceptionalWithReturnValue(Exception t); - - object ReturnsThis (); - string GetDescription(); + get; + set; } + + ICollection Friends + { + get; + } + + INestedTestObject Doctor + { + get; + } + + INestedTestObject Lawyer + { + get; + } + + string Name + { + get; + set; + } + + ITestObject Spouse + { + get; + set; + } + + /// + /// Gets the exception method call count. + /// + /// The exception method call count. + int ExceptionMethodCallCount + { + get; + } + + void Exceptional(Exception t); + + int ExceptionalWithReturnValue(Exception t); + + object ReturnsThis(); + string GetDescription(); } diff --git a/test/Spring/Spring.Core.Tests/Objects/IndexedTestObject.cs b/test/Spring/Spring.Core.Tests/Objects/IndexedTestObject.cs index 9dda72eb..fc5aca6c 100644 --- a/test/Spring/Spring.Core.Tests/Objects/IndexedTestObject.cs +++ b/test/Spring/Spring.Core.Tests/Objects/IndexedTestObject.cs @@ -2,13 +2,13 @@ /* * Copyright 2002-2010 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. @@ -25,62 +25,61 @@ using Spring.Collections; #endregion -namespace Spring.Objects +namespace Spring.Objects; + +/// +/// Another simple object for testing purposes, containing some collection properties. +/// +public class IndexedTestObject { - /// - /// Another simple object for testing purposes, containing some collection properties. - /// - public class IndexedTestObject - { - private TestObject[] array; - private IList list; - private ISet set; - private IDictionary map; + private TestObject[] array; + private IList list; + private ISet set; + private IDictionary map; - public TestObject[] Array - { - get { return array; } - set { array = value; } - } + public TestObject[] Array + { + get { return array; } + set { array = value; } + } - public IList List - { - get { return list; } - set { list = value; } - } + public IList List + { + get { return list; } + set { list = value; } + } - public ISet Set - { - get { return set; } - set { set = value; } - } + public ISet Set + { + get { return set; } + set { set = value; } + } - public IDictionary Map - { - get { return map; } - set { map = value; } - } + public IDictionary Map + { + get { return map; } + set { map = value; } + } - public IndexedTestObject() - { - TestObject to0 = new TestObject("name0", 0); - TestObject to1 = new TestObject("name1", 0); - TestObject to2 = new TestObject("name2", 0); - TestObject to3 = new TestObject("name3", 0); - TestObject to4 = new TestObject("name4", 0); - TestObject to5 = new TestObject("name5", 0); - TestObject to6 = new TestObject("name6", 0); - TestObject to7 = new TestObject("name7", 0); - array = new TestObject[] {to0, to1}; - list = new ArrayList(); - list.Add(to2); - list.Add(to3); - set = new HashedSet(); - set.Add(to6); - set.Add(to7); - map = new Hashtable(); - map["key1"] = to4; - map["key2"] = to5; - } - } -} \ No newline at end of file + public IndexedTestObject() + { + TestObject to0 = new TestObject("name0", 0); + TestObject to1 = new TestObject("name1", 0); + TestObject to2 = new TestObject("name2", 0); + TestObject to3 = new TestObject("name3", 0); + TestObject to4 = new TestObject("name4", 0); + TestObject to5 = new TestObject("name5", 0); + TestObject to6 = new TestObject("name6", 0); + TestObject to7 = new TestObject("name7", 0); + array = new TestObject[] { to0, to1 }; + list = new ArrayList(); + list.Add(to2); + list.Add(to3); + set = new HashedSet(); + set.Add(to6); + set.Add(to7); + map = new Hashtable(); + map["key1"] = to4; + map["key2"] = to5; + } +} diff --git a/test/Spring/Spring.Core.Tests/Objects/LazyTestObject.cs b/test/Spring/Spring.Core.Tests/Objects/LazyTestObject.cs index 5234d38c..84714b73 100644 --- a/test/Spring/Spring.Core.Tests/Objects/LazyTestObject.cs +++ b/test/Spring/Spring.Core.Tests/Objects/LazyTestObject.cs @@ -2,13 +2,13 @@ /* * Copyright � 2002-2011 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. @@ -22,52 +22,52 @@ #endregion -namespace Spring.Objects +namespace Spring.Objects; + +/// +/// Object to help test lazy instantiation of singletons from +/// multiple threads. See MultiThreadedLazyInit in +/// XmlObjectFactoryTests. +/// +/// Mark Pollack (.NET) +public class LazyTestObject { - /// - /// Object to help test lazy instantiation of singletons from - /// multiple threads. See MultiThreadedLazyInit in - /// XmlObjectFactoryTests. - /// - /// Mark Pollack (.NET) - public class LazyTestObject - { - #region Fields + #region Fields - private static int count = 0; + private static int count = 0; - #endregion + #endregion - #region Constructor (s) - /// - /// Initializes a new instance of the class - /// and sleeps for 2 seconds. - /// - public LazyTestObject() - { - count++; - Thread.Sleep(2000); - } + #region Constructor (s) - #endregion + /// + /// Initializes a new instance of the class + /// and sleeps for 2 seconds. + /// + public LazyTestObject() + { + count++; + Thread.Sleep(2000); + } - #region Properties + #endregion - public static int Count - { - get { return count; } - set { count = value; } - } + #region Properties - #endregion + public static int Count + { + get { return count; } + set { count = value; } + } - #region Methods + #endregion - public override string ToString() - { - return String.Format("LazyTestObject, Count = [{0}]", count); - } - #endregion + #region Methods - } + public override string ToString() + { + return String.Format("LazyTestObject, Count = [{0}]", count); + } + + #endregion } diff --git a/test/Spring/Spring.Core.Tests/Objects/MutablePropertyValuesTests.cs b/test/Spring/Spring.Core.Tests/Objects/MutablePropertyValuesTests.cs index 3a2e7f46..b63ffbfb 100644 --- a/test/Spring/Spring.Core.Tests/Objects/MutablePropertyValuesTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/MutablePropertyValuesTests.cs @@ -24,171 +24,173 @@ using NUnit.Framework; #endregion -namespace Spring.Objects +namespace Spring.Objects; + +/// +/// Unit tests for the MutablePropertyValues class. +/// +/// Rick Evans +[TestFixture] +public sealed class MutablePropertyValuesTests { - /// - /// Unit tests for the MutablePropertyValues class. + #region SetUp + + /// + /// The setup logic executed before the execution of this test fixture. /// - /// Rick Evans - [TestFixture] - public sealed class MutablePropertyValuesTests + [OneTimeSetUp] + public void FixtureSetUp() { } + + /// + /// The setup logic executed before the execution of each individual test. + /// + [SetUp] + public void SetUp() { } + + #endregion + + #region TearDown + + /// + /// The tear down logic executed after the execution of each individual test. + /// + [TearDown] + public void TearDown() { } + + /// + /// The tear down logic executed after the entire test fixture has executed. + /// + [OneTimeTearDown] + public void FixtureTearDown() { } + + #endregion + + [Test] + public void Instantiation() { - #region SetUp - /// - /// The setup logic executed before the execution of this test fixture. - /// - [OneTimeSetUp] - public void FixtureSetUp () {} + MutablePropertyValues root = new MutablePropertyValues(); + root.Add(new PropertyValue("Name", "Fiona Apple")); + root.Add(new PropertyValue("Age", 24)); + MutablePropertyValues props = new MutablePropertyValues(root); + Assert.AreEqual(2, props.PropertyValues.Count); + } - /// - /// The setup logic executed before the execution of each individual test. - /// - [SetUp] - public void SetUp () {} - #endregion + [Test] + public void InstantiationWithNulls() + { + MutablePropertyValues props = new MutablePropertyValues((Dictionary) null); + Assert.AreEqual(0, props.PropertyValues.Count); + MutablePropertyValues props2 = new MutablePropertyValues((IPropertyValues) null); + Assert.AreEqual(0, props2.PropertyValues.Count); + } - #region TearDown - /// - /// The tear down logic executed after the execution of each individual test. - /// - [TearDown] - public void TearDown () {} + [Test] + public void AddAllInList() + { + MutablePropertyValues props = new MutablePropertyValues(); + props.AddAll(new PropertyValue[] { new PropertyValue("Name", "Fiona Apple"), new PropertyValue("Age", 24) }); + Assert.AreEqual(2, props.PropertyValues.Count); + } - /// - /// The tear down logic executed after the entire test fixture has executed. - /// - [OneTimeTearDown] - public void FixtureTearDown () {} - #endregion + [Test] + public void AddAllInNullList() + { + MutablePropertyValues props = new MutablePropertyValues(); + props.Add(new PropertyValue("Name", "Fiona Apple")); + props.Add(new PropertyValue("Age", 24)); + props.AddAll((List) null); + Assert.AreEqual(2, props.PropertyValues.Count); + } - [Test] - public void Instantiation () { - MutablePropertyValues root = new MutablePropertyValues (); - root.Add (new PropertyValue ("Name", "Fiona Apple")); - root.Add (new PropertyValue ("Age", 24)); - MutablePropertyValues props = new MutablePropertyValues (root); - Assert.AreEqual (2, props.PropertyValues.Count); - } + [Test] + public void RemoveByName() + { + MutablePropertyValues props = new MutablePropertyValues(); + props.Add(new PropertyValue("Name", "Fiona Apple")); + props.Add(new PropertyValue("Age", 24)); + Assert.AreEqual(2, props.PropertyValues.Count); + props.Remove("name"); + Assert.AreEqual(1, props.PropertyValues.Count); + } - [Test] - public void InstantiationWithNulls () - { - MutablePropertyValues props = new MutablePropertyValues((Dictionary) null); - Assert.AreEqual (0, props.PropertyValues.Count); - MutablePropertyValues props2 = new MutablePropertyValues ((IPropertyValues) null); - Assert.AreEqual (0, props2.PropertyValues.Count); - } + [Test] + public void RemoveByPropertyValue() + { + MutablePropertyValues props = new MutablePropertyValues(); + PropertyValue propName = new PropertyValue("Name", "Fiona Apple"); + props.Add(propName); + props.Add(new PropertyValue("Age", 24)); + Assert.AreEqual(2, props.PropertyValues.Count); + props.Remove(propName); + Assert.AreEqual(1, props.PropertyValues.Count); + } - [Test] - public void AddAllInList () - { - MutablePropertyValues props = new MutablePropertyValues (); - props.AddAll (new PropertyValue [] { - new PropertyValue ("Name", "Fiona Apple"), - new PropertyValue ("Age", 24)}); - Assert.AreEqual (2, props.PropertyValues.Count); - } + [Test] + public void Contains() + { + MutablePropertyValues props = new MutablePropertyValues(); + props.Add(new PropertyValue("Name", "Fiona Apple")); + props.Add(new PropertyValue("Age", 24)); + // must be case insensitive to be CLS compliant... + Assert.IsTrue(props.Contains("nAmE")); + } - [Test] - public void AddAllInNullList () - { - MutablePropertyValues props = new MutablePropertyValues (); - props.Add (new PropertyValue ("Name", "Fiona Apple")); - props.Add (new PropertyValue ("Age", 24)); - props.AddAll((List) null); - Assert.AreEqual (2, props.PropertyValues.Count); - } + [Test] + public void AddAllInMap() + { + MutablePropertyValues props = new MutablePropertyValues(); + IDictionary map = new Dictionary(); + map.Add("Name", "Fiona Apple"); + map.Add("Age", 24); + props.AddAll(map); + Assert.AreEqual(2, props.PropertyValues.Count); + } - [Test] - public void RemoveByName () - { - MutablePropertyValues props = new MutablePropertyValues (); - props.Add (new PropertyValue ("Name", "Fiona Apple")); - props.Add (new PropertyValue ("Age", 24)); - Assert.AreEqual (2, props.PropertyValues.Count); - props.Remove ("name"); - Assert.AreEqual (1, props.PropertyValues.Count); - } + [Test] + public void AddAllInNullMap() + { + MutablePropertyValues props = new MutablePropertyValues(); + props.Add(new PropertyValue("Name", "Fiona Apple")); + props.AddAll((IDictionary) null); + Assert.AreEqual(1, props.PropertyValues.Count); + } - [Test] - public void RemoveByPropertyValue () - { - MutablePropertyValues props = new MutablePropertyValues (); - PropertyValue propName = new PropertyValue ("Name", "Fiona Apple"); - props.Add (propName); - props.Add (new PropertyValue ("Age", 24)); - Assert.AreEqual (2, props.PropertyValues.Count); - props.Remove (propName); - Assert.AreEqual (1, props.PropertyValues.Count); - } + [Test] + public void ChangesSince() + { + Dictionary map = new Dictionary(); + PropertyValue propName = new PropertyValue("Name", "Fiona Apple"); + map.Add(propName.Name, propName.Value); + map.Add("Age", 24); + MutablePropertyValues props = new MutablePropertyValues(map); + MutablePropertyValues newProps = new MutablePropertyValues(map); - [Test] - public void Contains () - { - MutablePropertyValues props = new MutablePropertyValues (); - props.Add (new PropertyValue ("Name", "Fiona Apple")); - props.Add (new PropertyValue ("Age", 24)); - // must be case insensitive to be CLS compliant... - Assert.IsTrue (props.Contains ("nAmE")); - } + // change the name... this is the change we'll be looking for + newProps.SetPropertyValueAt(new PropertyValue(propName.Name, "Naomi Woolf"), 0); + IPropertyValues changes = newProps.ChangesSince(props); + Assert.AreEqual(1, changes.PropertyValues.Count); + // the name was changed, so its the name property that should be in the changed list + Assert.IsTrue(changes.Contains("name")); - [Test] - public void AddAllInMap () - { - MutablePropertyValues props = new MutablePropertyValues (); - IDictionary map = new Dictionary(); - map.Add("Name", "Fiona Apple"); - map.Add ("Age", 24); - props.AddAll (map); - Assert.AreEqual (2, props.PropertyValues.Count); - } + newProps.Add(new PropertyValue("Commentator", "Naomi Woolf")); + changes = newProps.ChangesSince(props); + Assert.AreEqual(2, changes.PropertyValues.Count); + // the Commentator was added, so its the Commentator property that should be in the changed list + Assert.IsTrue(changes.Contains("commentator")); + // the name was changed, so its the name property that should be in the changed list + Assert.IsTrue(changes.Contains("name")); + } - [Test] - public void AddAllInNullMap () - { - MutablePropertyValues props = new MutablePropertyValues (); - props.Add (new PropertyValue ("Name", "Fiona Apple")); - props.AddAll ((IDictionary) null); - Assert.AreEqual (1, props.PropertyValues.Count); - } - - [Test] - public void ChangesSince () - { - Dictionary map = new Dictionary(); - PropertyValue propName = new PropertyValue("Name", "Fiona Apple"); - map.Add (propName.Name, propName.Value); - map.Add ("Age", 24); - MutablePropertyValues props = new MutablePropertyValues (map); - MutablePropertyValues newProps = new MutablePropertyValues (map); - - // change the name... this is the change we'll be looking for - newProps.SetPropertyValueAt (new PropertyValue (propName.Name, "Naomi Woolf"), 0); - IPropertyValues changes = newProps.ChangesSince (props); - Assert.AreEqual (1, changes.PropertyValues.Count); - // the name was changed, so its the name property that should be in the changed list - Assert.IsTrue (changes.Contains ("name")); - - newProps.Add (new PropertyValue ("Commentator", "Naomi Woolf")); - changes = newProps.ChangesSince (props); - Assert.AreEqual (2, changes.PropertyValues.Count); - // the Commentator was added, so its the Commentator property that should be in the changed list - Assert.IsTrue (changes.Contains ("commentator")); - // the name was changed, so its the name property that should be in the changed list - Assert.IsTrue (changes.Contains ("name")); - } - - [Test] - public void ChangesSinceWithSelf () - { - Dictionary map = new Dictionary(); - map.Add("Name", "Fiona Apple"); - map.Add ("Age", 24); - MutablePropertyValues props = new MutablePropertyValues (map); - props.Remove ("name"); - // get all of the changes between self and self again (there should be none); - IPropertyValues changes = props.ChangesSince (props); - Assert.AreEqual (0, changes.PropertyValues.Count); - } - } + [Test] + public void ChangesSinceWithSelf() + { + Dictionary map = new Dictionary(); + map.Add("Name", "Fiona Apple"); + map.Add("Age", 24); + MutablePropertyValues props = new MutablePropertyValues(map); + props.Remove("name"); + // get all of the changes between self and self again (there should be none); + IPropertyValues changes = props.ChangesSince(props); + Assert.AreEqual(0, changes.PropertyValues.Count); + } } diff --git a/test/Spring/Spring.Core.Tests/Objects/NestedTestObject.cs b/test/Spring/Spring.Core.Tests/Objects/NestedTestObject.cs index ada9d7ba..89248c74 100644 --- a/test/Spring/Spring.Core.Tests/Objects/NestedTestObject.cs +++ b/test/Spring/Spring.Core.Tests/Objects/NestedTestObject.cs @@ -1,20 +1,20 @@ #region License /* -* Copyright 2002-2010 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. -*/ + * Copyright 2002-2010 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 @@ -27,98 +27,100 @@ using System.Globalization; #endregion -namespace Spring.Objects +namespace Spring.Objects; + +/// +/// Simple nested test object used for testing object factories, AOP framework etc. +/// +/// Trevor D. Cook +/// Mark Pollack (.NET) +public class NestedTestObject : INestedTestObject { - /// - /// Simple nested test object used for testing object factories, AOP framework etc. - /// - /// Trevor D. Cook - /// Mark Pollack (.NET) - public class NestedTestObject : INestedTestObject - { - internal string company = string.Empty; - private IDictionary _partners = new Hashtable(); + internal string company = string.Empty; + private IDictionary _partners = new Hashtable(); - public NestedTestObject() - { - } + public NestedTestObject() + { + } - public NestedTestObject(string comp) - { - Company = comp; - } + public NestedTestObject(string comp) + { + Company = comp; + } - public NestedTestObject(string comp, IDictionary partners) - { - Company = comp; - Partners = partners; - } + public NestedTestObject(string comp, IDictionary partners) + { + Company = comp; + Partners = partners; + } - public ITestObject this[string partnersSurname] - { - get { return Partners[partnersSurname] as ITestObject; } - set { Partners[partnersSurname] = value; } - } + public ITestObject this[string partnersSurname] + { + get { return Partners[partnersSurname] as ITestObject; } + set { Partners[partnersSurname] = value; } + } - public string Company - { - get { return this.company; } - set { this.company = value; } - } + public string Company + { + get { return this.company; } + set { this.company = value; } + } - /// - /// Maps names (string) to ITestObjects... - /// - public IDictionary Partners - { - get { return _partners; } - set { _partners = value; } - } - } + /// + /// Maps names (string) to ITestObjects... + /// + public IDictionary Partners + { + get { return _partners; } + set { _partners = value; } + } +} - #region Inner Class : NestedTestObjectConverter +#region Inner Class : NestedTestObjectConverter - public class NestedTestObjectConverter : TypeConverter - { - public override bool CanConvertTo( - ITypeDescriptorContext context, Type destinationType) - { - if ((destinationType == typeof (NestedTestObjectConverter)) - || (destinationType == typeof (InstanceDescriptor))) - { - return true; - } - return base.CanConvertTo(context, destinationType); - } +public class NestedTestObjectConverter : TypeConverter +{ + public override bool CanConvertTo( + ITypeDescriptorContext context, Type destinationType) + { + if ((destinationType == typeof(NestedTestObjectConverter)) + || (destinationType == typeof(InstanceDescriptor))) + { + return true; + } - public override bool CanConvertFrom - (ITypeDescriptorContext context, Type sourceType) - { - if (sourceType == typeof (string)) - { - return true; - } - return base.CanConvertFrom(context, sourceType); - } + return base.CanConvertTo(context, destinationType); + } - public override object ConvertFrom - (ITypeDescriptorContext context, CultureInfo culture, object text_obj) - { - if (text_obj is string) - { - string text = (string) text_obj; - NestedTestObject tb = new NestedTestObject(text); - return tb; - } - return base.ConvertFrom(context, culture, text_obj); - } + public override bool CanConvertFrom + (ITypeDescriptorContext context, Type sourceType) + { + if (sourceType == typeof(string)) + { + return true; + } - public override object ConvertTo( - ITypeDescriptorContext context, CultureInfo culture, object param, Type destinationType) - { - return base.ConvertTo(context, culture, param, destinationType); - } - } + return base.CanConvertFrom(context, sourceType); + } - #endregion -} \ No newline at end of file + public override object ConvertFrom + (ITypeDescriptorContext context, CultureInfo culture, object text_obj) + { + if (text_obj is string) + { + string text = (string) text_obj; + NestedTestObject tb = new NestedTestObject(text); + return tb; + } + + return base.ConvertFrom(context, culture, text_obj); + } + + public override object ConvertTo( + ITypeDescriptorContext context, CultureInfo culture, object param, Type destinationType) + { + return base.ConvertTo(context, culture, param, destinationType); + } +} + +#endregion diff --git a/test/Spring/Spring.Core.Tests/Objects/NotWritablePropertyExceptionTests.cs b/test/Spring/Spring.Core.Tests/Objects/NotWritablePropertyExceptionTests.cs index 79462eec..da11073f 100644 --- a/test/Spring/Spring.Core.Tests/Objects/NotWritablePropertyExceptionTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/NotWritablePropertyExceptionTests.cs @@ -21,37 +21,36 @@ using NUnit.Framework; using Spring.Core; -namespace Spring.Objects +namespace Spring.Objects; + +/// +/// Unit tests for the NotWritablePropertyException class. +/// +/// Rick Evans +[TestFixture] +public sealed class NotWritablePropertyExceptionTests { - /// - /// Unit tests for the NotWritablePropertyException class. - /// - /// Rick Evans - [TestFixture] - public sealed class NotWritablePropertyExceptionTests - { - [Test] - public void InstantiationSupplyingPropertyTypeAndRootException() - { - NotWritablePropertyException ex = new NotWritablePropertyException("Doctor", typeof (TestObject), null); - Assert.AreEqual("Doctor", ex.OffendingPropertyName); - Assert.AreEqual(typeof(TestObject), ex.ObjectType); - } + [Test] + public void InstantiationSupplyingPropertyTypeAndRootException() + { + NotWritablePropertyException ex = new NotWritablePropertyException("Doctor", typeof(TestObject), null); + Assert.AreEqual("Doctor", ex.OffendingPropertyName); + Assert.AreEqual(typeof(TestObject), ex.ObjectType); + } - [Test] - public void InstantiationSupplyingNullPropertyTypeAndRootException() - { - NotWritablePropertyException ex = new NotWritablePropertyException(null, typeof (TestObject), null); - Assert.AreEqual(null, ex.OffendingPropertyName); - Assert.AreEqual(typeof(TestObject), ex.ObjectType); - } + [Test] + public void InstantiationSupplyingNullPropertyTypeAndRootException() + { + NotWritablePropertyException ex = new NotWritablePropertyException(null, typeof(TestObject), null); + Assert.AreEqual(null, ex.OffendingPropertyName); + Assert.AreEqual(typeof(TestObject), ex.ObjectType); + } - [Test] - public void InstantiationSupplyingNullPropertyNullTypeAndRootException() - { - NotWritablePropertyException ex = new NotWritablePropertyException(null, null, null); - Assert.AreEqual(null, ex.OffendingPropertyName); - Assert.AreEqual(null, ex.ObjectType); - } - } -} \ No newline at end of file + [Test] + public void InstantiationSupplyingNullPropertyNullTypeAndRootException() + { + NotWritablePropertyException ex = new NotWritablePropertyException(null, null, null); + Assert.AreEqual(null, ex.OffendingPropertyName); + Assert.AreEqual(null, ex.ObjectType); + } +} diff --git a/test/Spring/Spring.Core.Tests/Objects/NumberTestObject.cs b/test/Spring/Spring.Core.Tests/Objects/NumberTestObject.cs index 50df57e2..b5890587 100644 --- a/test/Spring/Spring.Core.Tests/Objects/NumberTestObject.cs +++ b/test/Spring/Spring.Core.Tests/Objects/NumberTestObject.cs @@ -18,49 +18,48 @@ #endregion -namespace Spring.Objects +namespace Spring.Objects; + +/// +/// +/// +/// Juergen Hoeller +public sealed class NumberTestObject { - /// - /// - /// - /// Juergen Hoeller - public sealed class NumberTestObject - { - private short _myShort; - private int _myInt; - private long _myLong; + private short _myShort; + private int _myInt; + private long _myLong; - public short MyShort - { - get { return _myShort; } - set { _myShort = value; } - } + public short MyShort + { + get { return _myShort; } + set { _myShort = value; } + } - public int MyInt - { - get { return _myInt; } - set { _myInt = value; } - } + public int MyInt + { + get { return _myInt; } + set { _myInt = value; } + } - public long MyLong - { - get { return _myLong; } - set { _myLong = value; } - } + public long MyLong + { + get { return _myLong; } + set { _myLong = value; } + } - public float MyFloat - { - get { return _myFloat; } - set { _myFloat = value; } - } + public float MyFloat + { + get { return _myFloat; } + set { _myFloat = value; } + } - public double MyDouble - { - get { return _myDouble; } - set { _myDouble = value; } - } + public double MyDouble + { + get { return _myDouble; } + set { _myDouble = value; } + } - private float _myFloat; - private double _myDouble; - } + private float _myFloat; + private double _myDouble; } \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/Objects/ObjectWrapperTests.cs b/test/Spring/Spring.Core.Tests/Objects/ObjectWrapperTests.cs index 4f48bed6..45c9dd52 100644 --- a/test/Spring/Spring.Core.Tests/Objects/ObjectWrapperTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/ObjectWrapperTests.cs @@ -2,13 +2,13 @@ /* * Copyright 2002-2010 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. @@ -26,7 +26,6 @@ using System.ComponentModel; using System.Globalization; using System.Reflection; using System.Runtime.CompilerServices; - using Microsoft.Extensions.Logging.Abstractions; using NUnit.Framework; using Spring.Collections; @@ -37,1567 +36,1574 @@ using Spring.Util; #endregion -namespace Spring.Objects +namespace Spring.Objects; + +/// +/// Unit tests for the ObjectWrapper class. +/// +/// Rod Johnson +/// Mark Pollack (.NET) +/// Rick Evans (.NET) +[TestFixture] +public sealed class ObjectWrapperTests { - /// - /// Unit tests for the ObjectWrapper class. - /// - /// Rod Johnson - /// Mark Pollack (.NET) - /// Rick Evans (.NET) - [TestFixture] - public sealed class ObjectWrapperTests - { - /// - /// The setup logic executed before the execution of this test fixture. - /// - [OneTimeSetUp] - public void FixtureSetUp() - { - // enable logging (to nowhere), just to exercise the logging code... - LogManager.LoggerFactory = NullLoggerFactory.Instance; - } + /// + /// The setup logic executed before the execution of this test fixture. + /// + [OneTimeSetUp] + public void FixtureSetUp() + { + // enable logging (to nowhere), just to exercise the logging code... + LogManager.LoggerFactory = NullLoggerFactory.Instance; + } - #region Classes Used During Tests - public class Person + #region Classes Used During Tests + + public class Person + { + private IList favoriteNames = new ArrayList(); + private IDictionary properties = new Hashtable(); + private string sillyString; + + public Person() { - private IList favoriteNames = new ArrayList(); - private IDictionary properties = new Hashtable(); - private string sillyString; - - public Person() - { - favoriteNames.Add("p1"); - favoriteNames.Add("p2"); - } - public Person(IList favNums) - { - favoriteNames = favNums; - } - - public string SillyString - { - get { return sillyString; } - } - public IList FavoriteNames - { - get { return favoriteNames; } - } - - public IDictionary Properties - { - get { return properties; } - } - public string this[int index] - { - get { return (string)favoriteNames[index]; } - set { favoriteNames[index] = value; } - } - public string this[string keyName] - { - get { return (string) properties[keyName]; } - set { properties.Add(keyName,value); } - } - public string this[int index, string keyname] - { - get { return sillyString; } - set { sillyString = index + "-" + keyname + ",val=" + value;} - } - + favoriteNames.Add("p1"); + favoriteNames.Add("p2"); } - public class GenericPerson + public Person(IList favNums) { - private List favoriteNames = new List(); - private IDictionary properties = new Dictionary(); - + favoriteNames = favNums; + } - public GenericPerson() + public string SillyString + { + get { return sillyString; } + } + + public IList FavoriteNames + { + get { return favoriteNames; } + } + + public IDictionary Properties + { + get { return properties; } + } + + public string this[int index] + { + get { return (string) favoriteNames[index]; } + set { favoriteNames[index] = value; } + } + + public string this[string keyName] + { + get { return (string) properties[keyName]; } + set { properties.Add(keyName, value); } + } + + public string this[int index, string keyname] + { + get { return sillyString; } + set { sillyString = index + "-" + keyname + ",val=" + value; } + } + } + + public class GenericPerson + { + private List favoriteNames = new List(); + private IDictionary properties = new Dictionary(); + + public GenericPerson() + { + favoriteNames.Add("p1"); + favoriteNames.Add("p2"); + } + + public GenericPerson(List favNums) + { + favoriteNames = favNums; + } + + /* + public string this[int index] + { + get { return (string)favoriteNames[index]; } + set { favoriteNames[index] = value; } + } + */ + public string this[string keyName] + { + get { return properties[keyName]; } + set { properties.Add(keyName, value); } + } + } + + public class AltPerson + { + private IList favoriteNames = new ArrayList(); + + public AltPerson() + { + favoriteNames.Add("ap1"); + favoriteNames.Add("ap2"); + } + + public AltPerson(IList favNums) + { + favoriteNames = favNums; + } + + [IndexerName("FavoriteName")] + public string this[int index] + { + get { return (string) favoriteNames[index]; } + set { favoriteNames[index] = value; } + } + } + + public class NoNullsList : ArrayList + { + public override int Add(object value) + { + if (value == null) { - favoriteNames.Add("p1"); - favoriteNames.Add("p2"); - } - public GenericPerson(List favNums) - { - favoriteNames = favNums; + throw new NullReferenceException("Adding nulls is not supported in this implementation."); } - /* - public string this[int index] + return base.Add(value); + } + } + + private class Honey + { + public Honey(IList akas) + { + _akas = new Aliases(akas); + } + + protected Aliases _akas; + + public Aliases AlsoKnownAs + { + get { return _akas; } + } + + public string this[int index] + { + get { return AlsoKnownAs[index]; } + } + } + + private class NonReadableHoney : Honey + { + public NonReadableHoney(IList akas) : base(akas) + { + } + + new public Aliases AlsoKnownAs + { + set { _akas = value; } + } + } + + private class Milk + { + public Milk(Honey[] honeys) + { + } + + public Honey[] Honeys + { + set { - get { return (string)favoriteNames[index]; } - set { favoriteNames[index] = value; } } - */ - public string this[string keyName] + } + } + + private sealed class Aliases + { + private IList _names; + + public Aliases() : this(new ArrayList()) + { + } + + public Aliases(IList names) + { + _names = names; + } + + public string this[int index] + { + get { return (string) _names[index]; } + set { _names[index] = value; } + } + } + + private sealed class RealNestedTestObject + { + public TestObject Datum + { + get { return _datum; } + set { _datum = value; } + } + + private TestObject _datum; + } + + private sealed class WanPropsClass + { + public bool IsWan + { + get { return true; } + } + } + + private sealed class StringAppenderConverter : TypeConverter + { + public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) + { + if (sourceType == typeof(string)) { - get { return properties[keyName]; } - set { properties.Add(keyName, value); } + return true; } + return base.CanConvertFrom(context, sourceType); } - - public class AltPerson + + public override object ConvertFrom( + ITypeDescriptorContext context, CultureInfo culture, object val) { - private IList favoriteNames = new ArrayList(); - public AltPerson() + if (val is string) { - favoriteNames.Add("ap1"); - favoriteNames.Add("ap2"); - } - - public AltPerson(IList favNums) - { - favoriteNames = favNums; + return "OctopusOil : " + val; } - [IndexerName("FavoriteName")] - public string this[int index] + return base.ConvertFrom(context, culture, val); + } + } + + private sealed class TestStringArrayConverter : TypeConverter + { + public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) + { + if (sourceType == typeof(string[])) { - get { return (string)favoriteNames[index]; } - set { favoriteNames[index] = value; } - + return true; } - } - public class NoNullsList : ArrayList - { - public override int Add(object value) - { - if (value == null) - { - throw new NullReferenceException("Adding nulls is not supported in this implementation."); - } - return base.Add(value); - } - } - - - - private class Honey - { - public Honey(IList akas) - { - _akas = new Aliases(akas); - } - - protected Aliases _akas; - - public Aliases AlsoKnownAs - { - get { return _akas; } - } - - public string this[int index] - { - get { return AlsoKnownAs[index]; } - } - } - - private class NonReadableHoney : Honey - { - public NonReadableHoney(IList akas) : base(akas) - { - } - - new public Aliases AlsoKnownAs - { - set { _akas = value; } - } - } - - private class Milk - { - public Milk(Honey[] honeys) - { - } - - public Honey[] Honeys - { - set - { - } - } - } - - private sealed class Aliases - { - private IList _names; - - public Aliases() : this(new ArrayList()) - { - } - - public Aliases(IList names) - { - _names = names; - } - - public string this[int index] - { - get { return (string) _names[index]; } - set { _names[index] = value; } - } - } - - private sealed class RealNestedTestObject - { - public TestObject Datum - { - get { return _datum; } - set { _datum = value; } - } - - private TestObject _datum; - } - - private sealed class WanPropsClass - { - public bool IsWan - { - get { return true; } - } - } - - private sealed class StringAppenderConverter : TypeConverter - { - public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) - { - if (sourceType == typeof (string)) - { - return true; - } - return base.CanConvertFrom(context, sourceType); - } - - public override object ConvertFrom( - ITypeDescriptorContext context, CultureInfo culture, object val) - { - if (val is string) - { - return "OctopusOil : " + val; - } - return base.ConvertFrom(context, culture, val); - } - } - - private sealed class TestStringArrayConverter : TypeConverter - { - public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) - { - if (sourceType == typeof (string[])) - { - return true; - } - return base.CanConvertFrom(context, sourceType); - } - - public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object val) - { - if (val is string[]) - { - return "-" + StringUtils.CollectionToCommaDelimitedString(val as string[]) + "-"; - } - return base.ConvertFrom(context, culture, val); - } - } - - private sealed class TestObjectArrayConverter : TypeConverter - { - public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) - { - if (sourceType == typeof (string)) - { - return true; - } - return base.CanConvertFrom(context, sourceType); - } - - public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object val) - - { - if (val is string) - { - return new TestObject((string) val, 99); - } - return base.ConvertFrom(context, culture, val); - } - } - - private sealed class ObjectWithTypeProperty - { - private Type _type; - - public Type Type - { - get { return _type; } - set { _type = value; } - } - } - - /// - /// A class for use in testing the object wrapper with read only properties. - /// - private sealed class NoRead - { - public int Age - { - set - { - } - } - } - - private sealed class GetterObject - { - public string Name - { - get - { - if (_name == null) - { - throw new ApplicationException("name property must be set"); - } - return _name; - } - set { _name = value; } - } - - private string _name; - } - - private sealed class ThrowsException - { - public void DoSomething(Exception t) - { - throw t; - } - } - - internal sealed class PrimitiveArrayObject - { - public int[] Array - { - get { return array; } - set { this.array = value; } - } - - private int[] array; - } - - private sealed class PropsTest - { - public NameValueCollection Properties - { - set - { - } - } - - public String Name - { - set - { - } - } - - public String[] StringArray - { - set { this.stringArray = value; } - } - - public int[] IntArray - { - set { this.intArray = value; } - } - - public String[] stringArray; - public int[] intArray; - } - - #endregion - - #region Methods - - /// - /// Factory method for getting an ObjectWrapper instance. - /// - /// A new object wrapper (with no WrappedObject). - private ObjectWrapper GetWrapper() - { - return new ObjectWrapper(); - } - - /// - /// Factory method for getting an ObjectWrapper instance. - /// - /// - /// The object that is to be wrapped by the returned object wrapper. - /// - /// - /// A new object wrapper that wraps the supplied . - /// - private ObjectWrapper GetWrapper(object objectToBeWrapped) - { - return new ObjectWrapper(objectToBeWrapped); - } - - #endregion - - [Test] - public void SetPropertyUsingValueThatNeedsConversionWithNoCustomConverterRegistered() - { - ObjectWrapper wrapper = GetWrapper(new TestObject("Rick", 30)); - // needs conversion to NestedTestObject... - Assert.Throws(() => wrapper.SetPropertyValue("doctor", "Pollack, Pinch, & Pounce")); - } - - [Test] - [Ignore("not used")] - public void GetValueOfCustomIndexerProperty() - { - ObjectWrapper wrapper = GetWrapper(); - Honey darwin = new Honey(new string[] {"dickens", "of gaunt"}); - wrapper.WrappedInstance = darwin; - string alias = (string) wrapper.GetPropertyValue("AlsoKnownAs[1]"); - Assert.AreEqual("of gaunt", alias); - - alias = (string) wrapper.GetPropertyValue("[1]"); - Assert.AreEqual("of gaunt", alias, "indexer on object not working."); - wrapper.SetPropertyValue("Item[1]", "of foobar"); - alias = (string)wrapper.GetPropertyValue("[1]"); - Assert.AreEqual("of foobar", alias, "indexer on object not working."); - - } - - [Test] - [Ignore("not used")] - public void GetSetIndexerProperties() - { - IList favNames = new ArrayList(); - favNames.Add("Master Shake"); - favNames.Add("Meatwad"); - favNames.Add("Frylock"); - Person p = new Person(favNames); - ObjectWrapper wrapper = GetWrapper(); - wrapper.WrappedInstance = p; - - //This is 'new' Spring.Expressions notation, i.e. not "Item[i]" but plain [i]. - string name = (string)wrapper.GetPropertyValue("[0]"); - Assert.AreEqual("Master Shake", name); - wrapper.SetPropertyValue("[0]", "Carl"); - name = (string)wrapper.GetPropertyValue("[0]"); - Assert.AreEqual("Carl", name); - - //Try with Custom Indexer Name. - favNames = new ArrayList(); - favNames.Add("Master Shake"); - favNames.Add("Meatwad"); - favNames.Add("Frylock"); - AltPerson ap = new AltPerson(favNames); - wrapper = GetWrapper(); - wrapper.WrappedInstance = ap; - - name = (string)wrapper.GetPropertyValue("FavoriteName[0]"); - Assert.AreEqual("Master Shake", name); - + return base.CanConvertFrom(context, sourceType); } - [Test] - public void GetValueOfCustomIndexerPropertyWithMalformedIndexer() - { - ObjectWrapper wrapper = GetWrapper(); - Honey darwin = new Honey(new string[] {"dickens", "of gaunt"}); - wrapper.WrappedInstance = darwin; - Assert.Throws(() => wrapper.GetPropertyValue("AlsoKnownAs[1")); - } - - [Test] - public void GetPropertyTypeWithNullPropertyPath() - { - Assert.Throws(() => GetWrapper().GetPropertyType(null)); - } - - [Test] - public void GetPropertyTypeWithEmptyPropertyPath() - { - Assert.Throws(() => GetWrapper().GetPropertyType(string.Empty)); - } - - [Test] - public void GetPropertyTypeWithWhitespacedPropertyPath() - { - Assert.Throws(() => GetWrapper().GetPropertyType(" ")); - } - - [Test] - public void GetPropertyType() - { - ObjectWrapper wrapper = GetWrapper(new TestObject()); - Type propertyType = wrapper.GetPropertyType("name"); - Assert.AreEqual(typeof (string), propertyType); - } - - [Test] - public void GetPropertyTypeFromField_SPRNET502() - { - ObjectWrapper wrapper = GetWrapper(new TestObject()); - Type propertyType = wrapper.GetPropertyType("FileModeEnum"); - Assert.AreEqual(typeof (FileMode), propertyType); - } - - [Test] - public void GetPropertyTypeWithNestedLookup() - { - TestObject target = new TestObject(); - target.Spouse = new TestObject("Fiona", 28); - ObjectWrapper wrapper = GetWrapper(target); - Type propertyType = wrapper.GetPropertyType("spouse.age"); - Assert.AreEqual(typeof (int), propertyType); - } - - [Test] - public void SetValueOfCustomIndexerPropertyWithNonReadablePropertyInIndexedPath() - { - ObjectWrapper wrapper = GetWrapper(); - Honey[] honeys = new NonReadableHoney[] {new NonReadableHoney(new string[] {"hsu", "feng"})}; - wrapper.WrappedInstance = new Milk(honeys); - Assert.Throws(() => wrapper.SetPropertyValue("Honeys[0][0]", "mei")); - } - - [Test] - public void SetPropertyThatRequiresTypeConversionWithNonConvertibleType() - { - ObjectWrapper wrapper = GetWrapper(); - TestObject to = new TestObject(); - wrapper.WrappedInstance = to; - Assert.Throws(() => wrapper.SetPropertyValue("RealLawyer", "Noob")); - } - - /// - /// This test blows up because index is out of range. - /// - [Test] - public void SetIndexedPropertyOnListThatsOutOfRange() - { - TestObject to = new TestObject(); - ObjectWrapper wrapper = GetWrapper(to); - to.Friends = new NoNullsList(); - Assert.Throws(() => wrapper.SetPropertyValue("Friends[5]", "Inheritance Tax")); - } - - /// - /// Tests that a property lookup such as foo[0][1]['ben'][12] is ok - /// Well, rather it tests that its valid... 'cos man, that shoh ain't ok :D - /// - [Test] - public void GetChainedIndexers() - { - Honey to = new Honey(new string[] {"wee", "jakey", "ned"}); - ObjectWrapper wrapper = GetWrapper(to); - Assert.AreEqual('j', wrapper.GetPropertyValue("AlsoKnownAs[1][0]")); - } - - /// - /// Test that passing a null value of the object to manipulate with the ObjectWrapper - /// will throw a FatalPropertyException with the correct exception message. - /// - [Test] - public void NullObject() - { - Assert.Throws(() => new ObjectWrapper((object) null)); - } - - [Test] - public void InstantiateWithInterfaceType() - { - Assert.Throws(() => new ObjectWrapper(typeof (IList))); - } - - [Test] - public void InstantiateWithAbstractType() - { - Assert.Throws(() => new ObjectWrapper(typeof (AbstractObjectFactoryTests))); - } - - [Test] - public void InstantiateWithOkType() - { - IObjectWrapper wrapper = GetWrapper(typeof (TestObject)); - Assert.IsNotNull(wrapper.WrappedInstance); - } - - [Test] - public void NestedProperties() - { - string doctorCompany = ""; - string lawyerCompany = "Dr. Sueem"; - TestObject to = new TestObject(); - IObjectWrapper wrapper = GetWrapper(to); - wrapper.SetPropertyValue("Doctor.Company", doctorCompany); - wrapper.SetPropertyValue("Lawyer.Company", lawyerCompany); - Assert.AreEqual(doctorCompany, to.Doctor.Company); - Assert.AreEqual(lawyerCompany, to.Lawyer.Company); - } - - [Test] - public void GetterThrowsException() - { - GetterObject go = new GetterObject(); - IObjectWrapper wrapper = GetWrapper(go); - wrapper.SetPropertyValue("Name", "tom"); - Assert.IsTrue(go.Name.Equals("tom"), "Expected name to be set to 'tom'"); - } - - [Test] - public void TryToReadTheValueOfAWriteOnlyProperty() - { - NoRead nr = new NoRead(); - ObjectWrapper wrapper = GetWrapper(nr); - Assert.Throws(() => wrapper.GetPropertyValue("Age")); - } - - [Test] - public void TryToReadAnIndexedValueFromANullProperty() - { - TestObject o = new TestObject(); - o.Friends = null; - ObjectWrapper wrapper = GetWrapper(o); - Assert.Throws(() => wrapper.GetPropertyValue("Friends[2]")); - } - - /// - /// Test that applying an empty MutablePropertyValues does not modify the object contents. - /// - [Test] - public void EmptyPropertyValuesSet() - { - TestObject t = new TestObject(); - int age = 50; - string name = "Tony"; - t.Age = age; - t.Name = name; - IObjectWrapper wrapper = GetWrapper(t); - Assert.IsTrue(t.Age.Equals(age), "Age is not set correctly"); - Assert.IsTrue(name.Equals(t.Name), "Name is not set correctly"); - wrapper.SetPropertyValues(new MutablePropertyValues()); - Assert.IsTrue(t.Age.Equals(age), "Age is not set correctly"); - Assert.IsTrue(name.Equals(t.Name), "Name is not set correctly"); - } - - /// - /// Test basic ObjectWrapper functionality by setting properties using MutablePropertyValues. - /// - [Test] - public void AllValid() - { - TestObject t = new TestObject(); - string newName = "tony"; - int newAge = 65; - string newTouchy = "valid"; - IObjectWrapper wrapper = GetWrapper(t); - MutablePropertyValues pvs = new MutablePropertyValues(); - pvs.Add(new PropertyValue("Age", newAge)); - pvs.Add(new PropertyValue("Name", newName)); - pvs.Add(new PropertyValue("Touchy", newTouchy)); - wrapper.SetPropertyValues(pvs); - Assert.IsTrue(t.Name.Equals(newName), "Validly set property must stick"); - Assert.IsTrue(t.Touchy.Equals(newTouchy), "Validly set property must stick"); - Assert.IsTrue(t.Age == newAge, "Validly set property must stick"); - } - - [Test] - public void IndividualAllValid() - { - TestObject t = new TestObject(); - String newName = "tony"; - int newAge = 65; - string newTouchy = "valid"; - IObjectWrapper wrapper = GetWrapper(t); - wrapper.SetPropertyValue("Age", newAge); - wrapper.SetPropertyValue(new PropertyValue("Name", newName)); - wrapper.SetPropertyValue(new PropertyValue("Touchy", newTouchy)); - Assert.IsTrue(t.Name.Equals(newName), "Validly set property must stick"); - Assert.IsTrue(t.Touchy.Equals(newTouchy), "Validly set property must stick"); - Assert.IsTrue(t.Age == newAge, "Validly set property must stick"); - } - - [Test] - public void SettingAnInvalidValue() - { - TestObject t = new TestObject(); - string newName = "tony"; - try - { - IObjectWrapper wrapper = GetWrapper(t); - MutablePropertyValues pvs = new MutablePropertyValues(); - pvs.Add(new PropertyValue("Age", "foobar")); - pvs.Add(new PropertyValue("Name", newName)); - wrapper.SetPropertyValues(pvs); - Assert.Fail("Should throw exception when setting an invalid value"); - } - catch (PropertyAccessExceptionsException ex) - { - Assert.IsTrue(ex.ExceptionCount == 1, "Must contain 2 exceptions"); - // Test validly set property matches - Assert.IsTrue(t.Name.Equals(newName), "Validly set property must stick"); - Assert.IsTrue(t.Age == 0, "Invalidly set property must retain old value"); - } - catch (Exception ex) - { - Assert.Fail( - "Shouldn't throw exception other than PropertyAccessExceptions. Exception Message = " + ex.Message); - } - } - - [Test] - public void ArrayToStringConversion() - { - TestObject t = new TestObject(); - IObjectWrapper wrapper = GetWrapper(t); - TypeConverterRegistry.RegisterConverter(typeof(string), new TestStringArrayConverter()); - wrapper.SetPropertyValue("Name", new string[] {"a", "b"}); - Assert.AreEqual("-a,b-", t.Name); - } - - [Test] - public void ArrayToArrayConversion() - { - IndexedTestObject to = new IndexedTestObject(); - IObjectWrapper wrapper = GetWrapper(to); - TypeConverterRegistry.RegisterConverter(typeof(TestObject), new TestObjectArrayConverter()); - wrapper.SetPropertyValue("Array", new string[] {"a", "b"}); - Assert.AreEqual("a", to.Array[0].Name); - Assert.AreEqual("b", to.Array[1].Name); - } - - [Test] - public void PrimitiveArray() - { - PrimitiveArrayObject to = new PrimitiveArrayObject(); - IObjectWrapper wrapper = GetWrapper(to); - wrapper.SetPropertyValue("Array", new String[] {"1", "2"}); - Assert.AreEqual(2, to.Array.Length); - Assert.AreEqual(1, to.Array[0]); - Assert.AreEqual(2, to.Array[1]); - } - - [Test] - public void PrimitiveArrayFromCommaDelimitedString() - { - PrimitiveArrayObject to = new PrimitiveArrayObject(); - IObjectWrapper wrapper = GetWrapper(to); - wrapper.SetPropertyValue("Array", "1,2"); - Assert.AreEqual(2, to.Array.Length); - Assert.AreEqual(1, to.Array[0]); - Assert.AreEqual(2, to.Array[1]); - } - - [Test] - public void ObjectWrapperUpdates() - { - TestObject to = new TestObject("Rick", 2); - int newAge = 33; - ObjectWrapper wrapper = GetWrapper(to); - to.Age = newAge; - object owAge = wrapper.GetPropertyValue("Age"); - Assert.IsTrue(owAge is Int32, "Age is an integer"); - int owi = (int) owAge; - Assert.IsTrue(owi == newAge, "Object wrapper must pick up changes"); - } - - [Test] - public void SetWrappedInstanceOfSameClass() - { - TestObject to = new TestObject(); - IObjectWrapper wrapper = GetWrapper(to); - to.Age = 11; - - TestObject to2 = new TestObject(); - wrapper.WrappedInstance = to2; - - wrapper.SetPropertyValue("Age", 14); - Assert.IsTrue(to2.Age == 14, "2nd changed"); - Assert.IsTrue(to.Age == 11, "1st didn't change"); - } - - [Test] - public void SetWrappedInstanceOfDifferentClass() - { - ThrowsException tex = new ThrowsException(); - ObjectWrapper wrapper = GetWrapper(tex); - TestObject to2 = new TestObject(); - wrapper.WrappedInstance = to2; - - wrapper.SetPropertyValue("Age", 14); - Assert.IsTrue(to2.Age == 14); - } - - [Test] - public void TypeMismatch() - { - TestObject to = new TestObject(); - IObjectWrapper wrapper = GetWrapper(to); - Assert.Throws(() => wrapper.SetPropertyValue("Age", "foobar")); - } - - [Test] - public void EmptyValueForPrimitiveProperty() - { - TestObject to = new TestObject(); - ObjectWrapper wrapper = GetWrapper(to); - Assert.Throws(() => wrapper.SetPropertyValue("Age", "")); - } - - [Test] - public void GetProtectedPropertyValue() - { - TestObject foo = new TestObject(); - IObjectWrapper wrapper = GetWrapper(foo); - string happyPlace = (string) wrapper.GetPropertyValue("HappyPlace"); - Assert.AreEqual(TestObject.DefaultHappyPlace, happyPlace, - "Failed to read the value of a property with 'protected' access."); - } - - [Test] - public void SetProtectedPropertyValue() - { - TestObject foo = new TestObject(); - IObjectWrapper wrapper = GetWrapper(foo); - const string expectedHappyPlace = "The Rockies! Brrr..."; - wrapper.SetPropertyValue(new PropertyValue("HappyPlace", expectedHappyPlace)); - string happyPlace = (string) wrapper.GetPropertyValue("HappyPlace"); - Assert.AreEqual(expectedHappyPlace, happyPlace, - "Failed to read / write the value of a property with 'protected' access."); - } - - [Test] - public void GetPrivatePropertyValue() - { - TestObject foo = new TestObject(); - IObjectWrapper wrapper = GetWrapper(foo); - string[] contents = (string[]) wrapper.GetPropertyValue("SamsoniteSuitcase"); - Assert.IsTrue(ArrayUtils.AreEqual(TestObject.DefaultContentsOfTheSuitcase, contents), - "Failed to read the value of a property with 'private' access."); - } - - [Test] - public void SetPrivatePropertyValue() - { - TestObject foo = new TestObject(); - IObjectWrapper wrapper = GetWrapper(foo); - string[] expectedContents = new string[] {"Lloyd's Soul", "Harry's John Denver Records"}; - wrapper.SetPropertyValue(new PropertyValue("SamsoniteSuitcase", expectedContents)); - string[] contents = (string[]) wrapper.GetPropertyValue("SamsoniteSuitcase"); - Assert.IsTrue(ArrayUtils.AreEqual(expectedContents, contents), - "Failed to read / write the value of a property with 'private' access."); - } - - [Test] - public void GetNestedProperty() - { - ITestObject rod = new TestObject("rod", 31); - ITestObject kerry = new TestObject("kerry", 35); - rod.Spouse = kerry; - kerry.Spouse = rod; - IObjectWrapper wrapper = GetWrapper(rod); - int KA = (int) wrapper.GetPropertyValue("Spouse.Age"); - Assert.IsTrue(KA == 35, "Expected kerry's age to be 35"); - - int RA = (int) wrapper.GetPropertyValue("Spouse.Spouse.Age"); - Assert.IsTrue(RA == 31, "Expected rod's age to be 31"); - - ITestObject spousesSpouse = (ITestObject) wrapper.GetPropertyValue("Spouse.Spouse"); - Assert.IsTrue(rod == spousesSpouse, "spousesSpouse == initial point"); - } - - [Test] - public void GetNestedPropertyValueNullValue() - { - TestObject rod = new TestObject("rod", 31); - rod.Doctor = new NestedTestObject(null); - Assert.Throws(() => GetWrapper(rod).GetPropertyValue("Doctor.Company.Length")); - } - - [Test] - public void SetNestedProperty() - { - ITestObject rod = new TestObject("rod", 31); - ITestObject kerry = new TestObject("kerry", 0); - IObjectWrapper wrapper = GetWrapper(rod); - wrapper.SetPropertyValue("Spouse", kerry); - - Assert.AreEqual(rod.Spouse, kerry, "nested set did not work"); - wrapper.SetPropertyValue("Spouse.Spouse", rod); - Assert.AreEqual(rod, rod.Spouse.Spouse, "Nested set did not work."); - wrapper.SetPropertyValue("Spouse.Age", 100); - Assert.AreEqual(100, kerry.Age, "Nested setting of primitive property did not work."); - } - - [Test] - public void SetPropertyValue() - { - ITestObject bigby = new TestObject("Bigby", 4500); - ITestObject snow = new TestObject("Snow", 2500); - IObjectWrapper wrapper = GetWrapper(bigby); - wrapper.SetPropertyValue("Spouse", snow); - Assert.AreEqual(snow, bigby.Spouse); - } - - [Test] - public void SetIndexedPropertyValueOnUninitializedPath() - { - TestObject obj = new TestObject("Bill", 4500); - IObjectWrapper wrapper = GetWrapper(obj); - Assert.Throws(() => wrapper.SetPropertyValue("hats [0]", "Hicks & Co")); - } - - [Test] - public void SetIndexedPropertyValueOnNonIndexableType() - { - TestObject obj = new TestObject("Bill", 4500); - IObjectWrapper wrapper = GetWrapper(obj); - Assert.Throws(() => wrapper.SetPropertyValue("doctor [0]", "Hicks & Co")); - } - - [Test] - public void SetPrimitivePropertyToNullReference() - { - TestObject obj = new TestObject("Bill", 4500); - IObjectWrapper wrapper = GetWrapper(obj); - Assert.Throws(() => wrapper.SetPropertyValue("Age", null)); - } - - [Test] - public void SetPropertyValueIgnoresCase() - { - ITestObject bigby = new TestObject("Bigby", 4500); - ITestObject snow = new TestObject("Snow", 2500); - IObjectWrapper wrapper = GetWrapper(bigby); - wrapper.SetPropertyValue("spouse", snow); - Assert.AreEqual(snow, bigby.Spouse, - "Property setting is not case insensitive with regard to the property name (and for CLS compliance it should be)."); - } - - [Test] - public void IntArrayProperty() - { - PropsTest pt = new PropsTest(); - IObjectWrapper wrapper = GetWrapper(pt); - wrapper.SetPropertyValue("IntArray", new int[] {4, 5, 2, 3}); - Assert.IsTrue(pt.intArray.Length == 4, "intArray length = 4"); - Assert.IsTrue(pt.intArray[0] == 4 && pt.intArray[1] == 5 && pt.intArray[2] == 2 && pt.intArray[3] == 3, - "correct values"); - wrapper.SetPropertyValue("IntArray", new String[] {"4", "5", "2", "3"}); - Assert.IsTrue(pt.intArray.Length == 4, "intArray length = 4"); - Assert.IsTrue(pt.intArray[0] == 4 && pt.intArray[1] == 5 && pt.intArray[2] == 2 && pt.intArray[3] == 3, - "correct values"); - wrapper.SetPropertyValue("IntArray", 1); - Assert.IsTrue(pt.intArray.Length == 1, "intArray length = 1"); - Assert.IsTrue(pt.intArray[0] == 1, "correct values"); - wrapper.SetPropertyValue("IntArray", new String[] {"1"}); - Assert.IsTrue(pt.intArray.Length == 1, "intArray length = 1"); - Assert.IsTrue(pt.intArray[0] == 1, "correct values"); - } - - [Test] - public void NewWrappedInstancePropertyValuesGet() - { - ObjectWrapper wrapper = GetWrapper(); - TestObject t = new TestObject("Tony", 50); - wrapper.WrappedInstance = t; - Assert.AreEqual(t.Age, wrapper.GetPropertyValue("Age"), "Object wrapper returns wrong property value"); - - TestObject u = new TestObject("Udo", 30); - wrapper.WrappedInstance = u; - Assert.AreEqual(u.Age, wrapper.GetPropertyValue("Age"), "Object wrapper returns cached property value"); - } - - [Test] - public void NewWrappedInstanceNestedPropertyValuesGet() - { - IObjectWrapper wrapper = GetWrapper(); - TestObject t = new TestObject("Tony", 50); - t.Spouse = new TestObject("Sue", 40); - wrapper.WrappedInstance = t; - Assert.AreEqual(t.Spouse.Age, wrapper.GetPropertyValue("Spouse.Age"), - "Object wrapper returns wrong nested property value"); - - TestObject u = new TestObject("Udo", 30); - u.Spouse = new TestObject("Vera", 20); - wrapper.WrappedInstance = u; - Assert.AreEqual(u.Spouse.Age, wrapper.GetPropertyValue("Spouse.Age"), - "Object wrapper returns cached nested property value"); - } - - [Test] - public void StringArrayProperty() - { - PropsTest pt = new PropsTest(); - ObjectWrapper wrapper = GetWrapper(pt); - - wrapper.SetPropertyValue("StringArray", "foo,fi,fi,fum"); - Assert.IsTrue(pt.stringArray.Length == 4, "StringArray length = 4"); - Assert.IsTrue( - pt.stringArray[0].Equals("foo") && pt.stringArray[1].Equals("fi") && pt.stringArray[2].Equals("fi") && - pt.stringArray[3].Equals("fum"), "in correct values of string array"); - } - - #region Test for DateTime Properties - - internal class DateTimeTestObject - { - private DateTime _dt; - - public DateTime TriggerDateTime - { - get { return _dt; } - set { _dt = value; } - } - } - - [Test] - public void SetDateTimeProperty() - { - DateTimeTestObject o = new DateTimeTestObject(); - ObjectWrapper wrapper = GetWrapper(o); - - wrapper.SetPropertyValue("TriggerDateTime", "1991-10-10"); - - Assert.AreEqual(1991, ((DateTime) wrapper.GetPropertyValue("TriggerDateTime")).Year); - } - - #endregion - - #region Test for CultureInfo Properties - - internal class CultureTestObject - { - private CultureInfo _ci; - - public CultureInfo Cult - { - get { return _ci; } - set { _ci = value; } - } - } - - [Test] - public void SetCultureInfoProperty() - { - CultureTestObject o = new CultureTestObject(); - ObjectWrapper wrapper = GetWrapper(o); - - wrapper.SetPropertyValue("Cult", "es-ES"); - - Assert.AreEqual("es-ES", - ((CultureInfo) wrapper.GetPropertyValue("Cult")).Name); - } - - #endregion - - #region Tests for URI Properties - - internal class URITestObject - { - private Uri _uri; - - public Uri ResourceIdentifier - { - get { return _uri; } - set { _uri = value; } - } - } - - [Test] - public void SetURIProperty() - { - URITestObject o = new URITestObject(); - ObjectWrapper wrapper = GetWrapper(o); - - wrapper.SetPropertyValue("ResourceIdentifier", "http://www.springframework.net"); - Assert.AreEqual("www.springframework.net", - ((Uri) wrapper.GetPropertyValue("ResourceIdentifier")).Host); - } - - #endregion - - #region Tests for Indexed Array Properties - - [Test] - public void GetIndexedFromArrayProperty() - { - PrimitiveArrayObject to = new PrimitiveArrayObject(); - IObjectWrapper wrapper = GetWrapper(to); - to.Array = new int[] {1, 2, 3, 4, 5}; - Assert.AreEqual(1, (int) wrapper.GetPropertyValue("Array[0]")); - } - - [Test] - public void GetIndexOutofRangeFromArrayProperty() - { - PrimitiveArrayObject to = new PrimitiveArrayObject(); - IObjectWrapper wrapper = GetWrapper(to); - to.Array = new int[] {1, 2, 3, 4, 5}; - Assert.Throws(() => wrapper.GetPropertyValue("Array[5]")); - } - - [Test] - public void SetIndexedFromArrayProperty() - { - PrimitiveArrayObject to = new PrimitiveArrayObject(); - IObjectWrapper wrapper = GetWrapper(to); - to.Array = new int[] {1, 2, 3, 4, 5}; - wrapper.SetPropertyValue("Array[2]", 6); - Assert.AreEqual(6, to.Array[2]); - } - - [Test] - public void SetIndexOutOfRangeFromArrayProperty() - { - PrimitiveArrayObject to = new PrimitiveArrayObject(); - IObjectWrapper wrapper = GetWrapper(to); - to.Array = new int[] {1, 2, 3, 4, 5}; - Assert.Throws(() => wrapper.SetPropertyValue("Array[5]", 6)); - } - - /// - /// Test that we bail when attempting to get an indexed property with some guff for the index - /// - [Test] - public void GetIndexedPropertyValueWithGuffIndexFromArrayProperty() - { - PrimitiveArrayObject to = new PrimitiveArrayObject(); - IObjectWrapper wrapper = GetWrapper(to); - to.Array = new int[] {1, 2, 3, 4, 5}; - Assert.Throws(() => wrapper.GetPropertyValue("Array[HungerHurtsButStarvingWorks]")); - } - - /// - /// Test that we bail when attempting to get an indexed property with some guff for the index - /// - [Test] - public void GetIndexedPropertyValueWithMissingIndexFromArrayProperty() - { - PrimitiveArrayObject to = new PrimitiveArrayObject(); - IObjectWrapper wrapper = GetWrapper(to); - to.Array = new int[] {1, 2, 3, 4, 5}; - Assert.Throws(() => wrapper.GetPropertyValue("Array[]")); - } - - #endregion - - #region Tests for Indexed List Properties - - internal class ListTestObject - { - private IList _list; - private ArrayList _arrayList; - - public IList List - { - get { return _list; } - set { _list = value; } - } - - public ArrayList ArrayList - { - get { return _arrayList; } - set { _arrayList = value; } - } - } - - [Test] - public void GetIndexedFromListProperty() - { - ListTestObject to = new ListTestObject(); - IObjectWrapper wrapper = GetWrapper(to); - to.List = new ArrayList(new int[] {1, 2, 3, 4, 5}); - Assert.AreEqual(1, (int) wrapper.GetPropertyValue("List[0]")); - } - - [Test] - public void GetIndexedFromArrayListProperty() - { - ListTestObject to = new ListTestObject(); - IObjectWrapper wrapper = GetWrapper(to); - to.ArrayList = new ArrayList(new int[] {1, 2, 3, 4, 5}); - Assert.AreEqual(1, (int) wrapper.GetPropertyValue("ArrayList[0]")); - } - - [Test] - public void GetIndexOutofRangeFromListProperty() - { - ListTestObject to = new ListTestObject(); - IObjectWrapper wrapper = GetWrapper(to); - to.List = new ArrayList(new int[] {1, 2, 3, 4, 5}); - Assert.Throws(() => wrapper.GetPropertyValue("List[5]")); - } - - [Test] - public void SetIndexedFromListProperty() - { - ListTestObject to = new ListTestObject(); - IObjectWrapper wrapper = GetWrapper(to); - to.List = new ArrayList(new int[] {1, 2, 3, 4, 5}); - wrapper.SetPropertyValue("List[0]", 6); - Assert.AreEqual(6, to.List[0]); - } - - [Test] - public void SetIndexedFromListPropertyUsingMixOfSingleAndDoubleQuotedDelimeters() - { - ListTestObject to = new ListTestObject(); - IObjectWrapper wrapper = GetWrapper(to); - to.List = new ArrayList(new int[] {1, 2, 3, 4, 5}); - Assert.Throws(() => wrapper.SetPropertyValue("List['0\"]", 6)); - } - - [Test] - public void SetIndexedFromListPropertyUsingNonNumericValueForTheIndex() - { - ListTestObject to = new ListTestObject(); - IObjectWrapper wrapper = GetWrapper(to); - to.List = new ArrayList(new int[] {1, 2, 3, 4, 5}); - Assert.Throws(() => wrapper.SetPropertyValue("List[bingo]", 6)); - } - - [Test] - public void SetIndexedFromListPropertyUsingEmptyValueForTheIndex() - { - ListTestObject to = new ListTestObject(); - IObjectWrapper wrapper = GetWrapper(to); - to.List = new ArrayList(new int[] {1, 2, 3, 4, 5}); - Assert.Throws(() => wrapper.SetPropertyValue("List[]", 6)); - } - - [Test] - [Ignore("Addition of elements to the list via index that is out of range is not supported anymore.")] - public void SetIndexOutOfRangeFromListProperty() - { - ListTestObject to = new ListTestObject(); - IObjectWrapper wrapper = GetWrapper(to); - to.List = new ArrayList(new int[] {1, 2, 3, 4, 5}); - wrapper.SetPropertyValue("List[6]", 6); - Assert.AreEqual(6, to.List[6]); - Assert.IsNull(to.List[5]); - wrapper.SetPropertyValue("List[7]", 7); - Assert.AreEqual(7, to.List[7]); - } - - /// - /// Test that we bail when attempting to get an indexed property with some guff for the index - /// - [Test] - public void GetIndexedPropertyValueWithGuffIndexFromListProperty() - { - ListTestObject to = new ListTestObject(); - IObjectWrapper wrapper = GetWrapper(to); - to.List = new ArrayList(new int[] {1, 2, 3, 4, 5}); - Assert.Throws(() => wrapper.GetPropertyValue("List[HungerHurtsButStarvingWorks]")); - } - - [Test] - public void GetIndexedPropertyValueWithMissingIndexFromListProperty() - { - ListTestObject to = new ListTestObject(); - IObjectWrapper wrapper = GetWrapper(to); - to.List = new ArrayList(new int[] {1, 2, 3, 4, 5}); - Assert.Throws(() => wrapper.GetPropertyValue("List[]")); - } - - #endregion - - #region Tests for Indexed Dictionary Properties - - internal class DictionaryTestObject - { - private IDictionary _dictionary; - - public IDictionary Dictionary - { - get { return _dictionary; } - set { _dictionary = value; } - } - } - - [Test] - public void GetIndexedFromDictionaryProperty() - { - DictionaryTestObject to = new DictionaryTestObject(); - IObjectWrapper wrapper = GetWrapper(to); - to.Dictionary = new Hashtable(); - to.Dictionary.Add("key1", "value1"); - Assert.AreEqual("value1", (string) wrapper.GetPropertyValue("Dictionary['key1']")); - } - - [Test] - public void GetIndexMissingFromDictionaryProperty() - { - DictionaryTestObject to = new DictionaryTestObject(); - IObjectWrapper wrapper = GetWrapper(to); - to.Dictionary = new Hashtable(); - Assert.IsNull(wrapper.GetPropertyValue("Dictionary['notthere']")); - } - - [Test] - public void SetIndexedFromDictionaryProperty() - { - DictionaryTestObject to = new DictionaryTestObject(); - IObjectWrapper wrapper = GetWrapper(to); - to.Dictionary = new Hashtable(); - wrapper.SetPropertyValue("Dictionary['key1']", "value1"); - Assert.AreEqual("value1", to.Dictionary["key1"]); - } - - [Test] - public void SettingADictionaryPropertyJustAddsTheValuesToTheExistingDictionary() - { - TestObject to = new TestObject(); - to.AddPeriodicElement("Hsu", "Feng"); - to.AddPeriodicElement("Piao", "Jin"); - ObjectWrapper wrapper = GetWrapper(to); - IDictionary elements = new Hashtable(); - elements.Add("Weekend", "News"); - wrapper.SetPropertyValue("PeriodictabLE", elements); - Assert.AreEqual(3, to.PeriodicTable.Count); - } - - #endregion - - #region Tests for Indexed Set Properties - - internal class SetTestObject - { - private ISet _set; - private HybridSet _aSet; - - public ISet Set - { - get { return _set; } - set { _set = value; } - } - - public HybridSet HybridSet - { - get { return _aSet; } - set { _aSet = value; } - } - } - - [Test] - public void SettingASetPropertyJustAddsTheValuesToTheExistingSet() - { - TestObject to = new TestObject(); - to.AddComputerName("Atari 2900"); - to.AddComputerName("JCN"); - ObjectWrapper wrapper = GetWrapper(to); - wrapper.SetPropertyValue("Computers", new HybridSet(new string[] {"Trusty SNES"})); - Assert.AreEqual(3, to.Computers.Count); - } - - [Test] - public void GetIndexFromSetProperty() + public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object val) { - SetTestObject to = new SetTestObject(); - IObjectWrapper wrapper = GetWrapper(to); - to.Set = new ListSet(new int[] { 1, 2, 3, 4, 5 }); - Assert.Throws(() => wrapper.GetPropertyValue("Set[1]")); + if (val is string[]) + { + return "-" + StringUtils.CollectionToCommaDelimitedString(val as string[]) + "-"; + } + + return base.ConvertFrom(context, culture, val); } - - [Test] - public void GetIndexOutofRangeFromSetProperty() - { - SetTestObject to = new SetTestObject(); - IObjectWrapper wrapper = GetWrapper(to); - to.Set = new ListSet(new int[] {1, 2, 3, 4, 5}); - Assert.Throws(() => wrapper.GetPropertyValue("Set[23]")); - } + } - /// - /// Test that we bail when attempting to get an indexed property with some guff for the index - /// - [Test] - public void GetIndexedPropertyValueWithGuffIndexFromSetProperty() - { - SetTestObject to = new SetTestObject(); - IObjectWrapper wrapper = GetWrapper(to); - to.Set = new ListSet(new int[] {1, 2, 3, 4, 5}); - Assert.Throws(() => wrapper.GetPropertyValue("Set[HungerHurtsButStarvingWorks]")); - } - - [Test] - public void GetIndexedPropertyValueWithMissingIndexFromSetProperty() - { - SetTestObject to = new SetTestObject(); - IObjectWrapper wrapper = GetWrapper(to); - to.Set = new ListSet(new int[] {1, 2, 3, 4, 5}); - Assert.Throws(() => wrapper.GetPropertyValue("Set[]")); - } - - #endregion - - #region Test for Enumeration Properties - - internal class EnumTestObject - { - private FileMode FileModeEnum; - - public FileMode FileMode - { - get { return FileModeEnum; } - set { FileModeEnum = value; } - } - } - - [Test] - public void SetEnumProperty() - { - EnumTestObject o = new EnumTestObject(); - ObjectWrapper wrapper = GetWrapper(o); - wrapper.SetPropertyValue("FileMode", FileMode.Create); - Assert.AreEqual(FileMode.Create, (FileMode) wrapper.GetPropertyValue("FileMode")); - } - - #endregion - - [Test] - public void SetTypePropertyWithString() - { - ObjectWithTypeProperty to = new ObjectWithTypeProperty(); - IObjectWrapper wrapper = GetWrapper(to); - wrapper.SetPropertyValue("Type", "System.DateTime"); - Assert.AreEqual(typeof (DateTime), to.Type); - } - - [Test] - public void GetIndexedPropertyValueWithNonIndexedType() - { - TestObject to = new TestObject(); - IObjectWrapper wrapper = GetWrapper(to); - Assert.Throws(() => wrapper.GetPropertyValue("FileMode[0]")); - } - - [Test] - public void SetPropertyValuesWithUnknownProperty() - { - TestObject to = new TestObject(); - to.Doctor = null; - ObjectWrapper wrapper = GetWrapper(to); - Assert.Throws(() => wrapper.SetPropertyValue("Doctor.Company", "Bingo")); - } - - [Test] - public void SetPropertyValuesFailsWhenSettingNonExistantProperty() + private sealed class TestObjectArrayConverter : TypeConverter + { + public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) { - TestObject to = new TestObject(); - ObjectWrapper wrapper = GetWrapper(to); - MutablePropertyValues values = new MutablePropertyValues(); - values.Add("JeepersCreepersWhereDidYaGetThosePeepers", "OhThisWeirdBatGuySoldEmToMe..."); - values.Add("Age", 19); - // the unknown and ridiculously named property should fail - Assert.Throws(() => wrapper.SetPropertyValues(values, false)); - } - - [Test] - public void SetPropertyValuesDoesNotFailWhenSettingNonExistantPropertyWithIgnorUnknownSetToTrue() - { - TestObject to = new TestObject(); - ObjectWrapper wrapper = GetWrapper(to); - MutablePropertyValues values = new MutablePropertyValues(); - values.Add("Age", 19); - values.Add("JeepersCreepersWhereDidYaGetThosePeepers", "OhThisWeirdBatGuySoldEmToMe..."); - // the unknown and ridiculously named property should fail - wrapper.SetPropertyValues(values, true); - Assert.AreEqual(19, to.Age, "The single good property in the property values should have been set though..."); - } + if (sourceType == typeof(string)) + { + return true; + } - [Test] - public void SetPropertyValuesFailsWhenSettingReadOnlyProperty() - { - TestObject to = new TestObject(); - ObjectWrapper wrapper = GetWrapper(to); - MutablePropertyValues values = new MutablePropertyValues(); - values.Add("ReadOnlyObjectNumber", 123); - Assert.Throws(() => wrapper.SetPropertyValues(values, false)); + return base.CanConvertFrom(context, sourceType); } - [Test] - public void SetPropertyValuesDoesNotFailWhenSettingReadOnlyPropertyWithIgnorUnknownSetToTrue() + public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object val) + { - TestObject to = new TestObject(); - ObjectWrapper wrapper = GetWrapper(to); - MutablePropertyValues values = new MutablePropertyValues(); - values.Add("ObjectNumber", 123); - values.Add("Age", 19); - wrapper.SetPropertyValues(values, true); - Assert.AreEqual(19, to.Age, "The single good property in the property values should have been set though..."); + if (val is string) + { + return new TestObject((string) val, 99); + } + + return base.ConvertFrom(context, culture, val); + } + } + + private sealed class ObjectWithTypeProperty + { + private Type _type; + + public Type Type + { + get { return _type; } + set { _type = value; } + } + } + + /// + /// A class for use in testing the object wrapper with read only properties. + /// + private sealed class NoRead + { + public int Age + { + set + { + } + } + } + + private sealed class GetterObject + { + public string Name + { + get + { + if (_name == null) + { + throw new ApplicationException("name property must be set"); + } + + return _name; + } + set { _name = value; } } - [Test] - public void SetArrayPropertyValue() - { - string[] expected = new string[] {"Fedora", "Gacy", "Banjo"}; - TestObject to = new TestObject(); - ObjectWrapper wrapper = GetWrapper(to); - wrapper.SetPropertyValue("Hats", expected); - Assert.IsNotNull(to.Hats); - Assert.AreEqual(expected.Length, to.Hats.Length); - for (int i = 0; i < expected.Length; ++i) - { - Assert.AreEqual(expected[i], to.Hats[i]); - } - } + private string _name; + } - [Test] - public void TestToString() - { - ObjectWrapper wrapper = GetWrapper(); - Assert.IsTrue(wrapper.ToString().IndexOf("Exception encountered") >= 0); - wrapper.WrappedInstance = new WanPropsClass(); - string expected = string.Format( - "{0}: wrapping class [{1}]; IsWan={2}", - wrapper.GetType().Name, wrapper.WrappedType.FullName, "{True}"); - Assert.AreEqual(expected, wrapper.ToString()); - } - - [Test] - public void GetPropertyInfoWithNullArgument() - { - ObjectWrapper wrapper = GetWrapper(new TestObject()); - Assert.Throws(() => wrapper.GetPropertyInfo(null)); - } - - [Test] - public void GetPropertyInfoWithNonPropertyExpression() + private sealed class ThrowsException + { + public void DoSomething(Exception t) { - ObjectWrapper wrapper = GetWrapper(new TestObject()); - Assert.Throws(() => wrapper.GetPropertyInfo("2 + 2")); + throw t; + } + } + + internal sealed class PrimitiveArrayObject + { + public int[] Array + { + get { return array; } + set { this.array = value; } } - [Test] - public void GetPropertyInfoWithNonParsableExpression() + private int[] array; + } + + private sealed class PropsTest + { + public NameValueCollection Properties { - ObjectWrapper wrapper = GetWrapper(new TestObject()); - Assert.Throws(() => wrapper.GetPropertyInfo("[")); + set + { + } } - [Test] - public void GetNestedPropertyInfo() - { - RealNestedTestObject o = new RealNestedTestObject(); - o.Datum = new TestObject(); - o.Datum.Doctor = new NestedTestObject("Modlin"); - ObjectWrapper wrapper = GetWrapper(o); - PropertyInfo info = wrapper.GetPropertyInfo("Datum.Doctor.Company"); - Assert.IsNotNull(info); - } + public String Name + { + set + { + } + } - [Test(Description="SPRNET-198")] - public void AmbiguousPropertyLookupIsHandledProperlyByLookingAtDerivedClassOnly() - { - ObjectWrapper wrapper = GetWrapper(new DerivedFoo()); - wrapper.GetPropertyInfo("Bar"); - } - } + public String[] StringArray + { + set { this.stringArray = value; } + } + + public int[] IntArray + { + set { this.intArray = value; } + } + + public String[] stringArray; + public int[] intArray; + } + + #endregion + + #region Methods + + /// + /// Factory method for getting an ObjectWrapper instance. + /// + /// A new object wrapper (with no WrappedObject). + private ObjectWrapper GetWrapper() + { + return new ObjectWrapper(); + } + + /// + /// Factory method for getting an ObjectWrapper instance. + /// + /// + /// The object that is to be wrapped by the returned object wrapper. + /// + /// + /// A new object wrapper that wraps the supplied . + /// + private ObjectWrapper GetWrapper(object objectToBeWrapped) + { + return new ObjectWrapper(objectToBeWrapped); + } + + #endregion + + [Test] + public void SetPropertyUsingValueThatNeedsConversionWithNoCustomConverterRegistered() + { + ObjectWrapper wrapper = GetWrapper(new TestObject("Rick", 30)); + // needs conversion to NestedTestObject... + Assert.Throws(() => wrapper.SetPropertyValue("doctor", "Pollack, Pinch, & Pounce")); + } + + [Test] + [Ignore("not used")] + public void GetValueOfCustomIndexerProperty() + { + ObjectWrapper wrapper = GetWrapper(); + Honey darwin = new Honey(new string[] { "dickens", "of gaunt" }); + wrapper.WrappedInstance = darwin; + string alias = (string) wrapper.GetPropertyValue("AlsoKnownAs[1]"); + Assert.AreEqual("of gaunt", alias); + + alias = (string) wrapper.GetPropertyValue("[1]"); + Assert.AreEqual("of gaunt", alias, "indexer on object not working."); + wrapper.SetPropertyValue("Item[1]", "of foobar"); + alias = (string) wrapper.GetPropertyValue("[1]"); + Assert.AreEqual("of foobar", alias, "indexer on object not working."); + } + + [Test] + [Ignore("not used")] + public void GetSetIndexerProperties() + { + IList favNames = new ArrayList(); + favNames.Add("Master Shake"); + favNames.Add("Meatwad"); + favNames.Add("Frylock"); + Person p = new Person(favNames); + ObjectWrapper wrapper = GetWrapper(); + wrapper.WrappedInstance = p; + + //This is 'new' Spring.Expressions notation, i.e. not "Item[i]" but plain [i]. + string name = (string) wrapper.GetPropertyValue("[0]"); + Assert.AreEqual("Master Shake", name); + wrapper.SetPropertyValue("[0]", "Carl"); + name = (string) wrapper.GetPropertyValue("[0]"); + Assert.AreEqual("Carl", name); + + //Try with Custom Indexer Name. + favNames = new ArrayList(); + favNames.Add("Master Shake"); + favNames.Add("Meatwad"); + favNames.Add("Frylock"); + AltPerson ap = new AltPerson(favNames); + wrapper = GetWrapper(); + wrapper.WrappedInstance = ap; + + name = (string) wrapper.GetPropertyValue("FavoriteName[0]"); + Assert.AreEqual("Master Shake", name); + } + + [Test] + public void GetValueOfCustomIndexerPropertyWithMalformedIndexer() + { + ObjectWrapper wrapper = GetWrapper(); + Honey darwin = new Honey(new string[] { "dickens", "of gaunt" }); + wrapper.WrappedInstance = darwin; + Assert.Throws(() => wrapper.GetPropertyValue("AlsoKnownAs[1")); + } + + [Test] + public void GetPropertyTypeWithNullPropertyPath() + { + Assert.Throws(() => GetWrapper().GetPropertyType(null)); + } + + [Test] + public void GetPropertyTypeWithEmptyPropertyPath() + { + Assert.Throws(() => GetWrapper().GetPropertyType(string.Empty)); + } + + [Test] + public void GetPropertyTypeWithWhitespacedPropertyPath() + { + Assert.Throws(() => GetWrapper().GetPropertyType(" ")); + } + + [Test] + public void GetPropertyType() + { + ObjectWrapper wrapper = GetWrapper(new TestObject()); + Type propertyType = wrapper.GetPropertyType("name"); + Assert.AreEqual(typeof(string), propertyType); + } + + [Test] + public void GetPropertyTypeFromField_SPRNET502() + { + ObjectWrapper wrapper = GetWrapper(new TestObject()); + Type propertyType = wrapper.GetPropertyType("FileModeEnum"); + Assert.AreEqual(typeof(FileMode), propertyType); + } + + [Test] + public void GetPropertyTypeWithNestedLookup() + { + TestObject target = new TestObject(); + target.Spouse = new TestObject("Fiona", 28); + ObjectWrapper wrapper = GetWrapper(target); + Type propertyType = wrapper.GetPropertyType("spouse.age"); + Assert.AreEqual(typeof(int), propertyType); + } + + [Test] + public void SetValueOfCustomIndexerPropertyWithNonReadablePropertyInIndexedPath() + { + ObjectWrapper wrapper = GetWrapper(); + Honey[] honeys = new NonReadableHoney[] { new NonReadableHoney(new string[] { "hsu", "feng" }) }; + wrapper.WrappedInstance = new Milk(honeys); + Assert.Throws(() => wrapper.SetPropertyValue("Honeys[0][0]", "mei")); + } + + [Test] + public void SetPropertyThatRequiresTypeConversionWithNonConvertibleType() + { + ObjectWrapper wrapper = GetWrapper(); + TestObject to = new TestObject(); + wrapper.WrappedInstance = to; + Assert.Throws(() => wrapper.SetPropertyValue("RealLawyer", "Noob")); + } + + /// + /// This test blows up because index is out of range. + /// + [Test] + public void SetIndexedPropertyOnListThatsOutOfRange() + { + TestObject to = new TestObject(); + ObjectWrapper wrapper = GetWrapper(to); + to.Friends = new NoNullsList(); + Assert.Throws(() => wrapper.SetPropertyValue("Friends[5]", "Inheritance Tax")); + } + + /// + /// Tests that a property lookup such as foo[0][1]['ben'][12] is ok + /// Well, rather it tests that its valid... 'cos man, that shoh ain't ok :D + /// + [Test] + public void GetChainedIndexers() + { + Honey to = new Honey(new string[] { "wee", "jakey", "ned" }); + ObjectWrapper wrapper = GetWrapper(to); + Assert.AreEqual('j', wrapper.GetPropertyValue("AlsoKnownAs[1][0]")); + } + + /// + /// Test that passing a null value of the object to manipulate with the ObjectWrapper + /// will throw a FatalPropertyException with the correct exception message. + /// + [Test] + public void NullObject() + { + Assert.Throws(() => new ObjectWrapper((object) null)); + } + + [Test] + public void InstantiateWithInterfaceType() + { + Assert.Throws(() => new ObjectWrapper(typeof(IList))); + } + + [Test] + public void InstantiateWithAbstractType() + { + Assert.Throws(() => new ObjectWrapper(typeof(AbstractObjectFactoryTests))); + } + + [Test] + public void InstantiateWithOkType() + { + IObjectWrapper wrapper = GetWrapper(typeof(TestObject)); + Assert.IsNotNull(wrapper.WrappedInstance); + } + + [Test] + public void NestedProperties() + { + string doctorCompany = ""; + string lawyerCompany = "Dr. Sueem"; + TestObject to = new TestObject(); + IObjectWrapper wrapper = GetWrapper(to); + wrapper.SetPropertyValue("Doctor.Company", doctorCompany); + wrapper.SetPropertyValue("Lawyer.Company", lawyerCompany); + Assert.AreEqual(doctorCompany, to.Doctor.Company); + Assert.AreEqual(lawyerCompany, to.Lawyer.Company); + } + + [Test] + public void GetterThrowsException() + { + GetterObject go = new GetterObject(); + IObjectWrapper wrapper = GetWrapper(go); + wrapper.SetPropertyValue("Name", "tom"); + Assert.IsTrue(go.Name.Equals("tom"), "Expected name to be set to 'tom'"); + } + + [Test] + public void TryToReadTheValueOfAWriteOnlyProperty() + { + NoRead nr = new NoRead(); + ObjectWrapper wrapper = GetWrapper(nr); + Assert.Throws(() => wrapper.GetPropertyValue("Age")); + } + + [Test] + public void TryToReadAnIndexedValueFromANullProperty() + { + TestObject o = new TestObject(); + o.Friends = null; + ObjectWrapper wrapper = GetWrapper(o); + Assert.Throws(() => wrapper.GetPropertyValue("Friends[2]")); + } + + /// + /// Test that applying an empty MutablePropertyValues does not modify the object contents. + /// + [Test] + public void EmptyPropertyValuesSet() + { + TestObject t = new TestObject(); + int age = 50; + string name = "Tony"; + t.Age = age; + t.Name = name; + IObjectWrapper wrapper = GetWrapper(t); + Assert.IsTrue(t.Age.Equals(age), "Age is not set correctly"); + Assert.IsTrue(name.Equals(t.Name), "Name is not set correctly"); + wrapper.SetPropertyValues(new MutablePropertyValues()); + Assert.IsTrue(t.Age.Equals(age), "Age is not set correctly"); + Assert.IsTrue(name.Equals(t.Name), "Name is not set correctly"); + } + + /// + /// Test basic ObjectWrapper functionality by setting properties using MutablePropertyValues. + /// + [Test] + public void AllValid() + { + TestObject t = new TestObject(); + string newName = "tony"; + int newAge = 65; + string newTouchy = "valid"; + IObjectWrapper wrapper = GetWrapper(t); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.Add(new PropertyValue("Age", newAge)); + pvs.Add(new PropertyValue("Name", newName)); + pvs.Add(new PropertyValue("Touchy", newTouchy)); + wrapper.SetPropertyValues(pvs); + Assert.IsTrue(t.Name.Equals(newName), "Validly set property must stick"); + Assert.IsTrue(t.Touchy.Equals(newTouchy), "Validly set property must stick"); + Assert.IsTrue(t.Age == newAge, "Validly set property must stick"); + } + + [Test] + public void IndividualAllValid() + { + TestObject t = new TestObject(); + String newName = "tony"; + int newAge = 65; + string newTouchy = "valid"; + IObjectWrapper wrapper = GetWrapper(t); + wrapper.SetPropertyValue("Age", newAge); + wrapper.SetPropertyValue(new PropertyValue("Name", newName)); + wrapper.SetPropertyValue(new PropertyValue("Touchy", newTouchy)); + Assert.IsTrue(t.Name.Equals(newName), "Validly set property must stick"); + Assert.IsTrue(t.Touchy.Equals(newTouchy), "Validly set property must stick"); + Assert.IsTrue(t.Age == newAge, "Validly set property must stick"); + } + + [Test] + public void SettingAnInvalidValue() + { + TestObject t = new TestObject(); + string newName = "tony"; + try + { + IObjectWrapper wrapper = GetWrapper(t); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.Add(new PropertyValue("Age", "foobar")); + pvs.Add(new PropertyValue("Name", newName)); + wrapper.SetPropertyValues(pvs); + Assert.Fail("Should throw exception when setting an invalid value"); + } + catch (PropertyAccessExceptionsException ex) + { + Assert.IsTrue(ex.ExceptionCount == 1, "Must contain 2 exceptions"); + // Test validly set property matches + Assert.IsTrue(t.Name.Equals(newName), "Validly set property must stick"); + Assert.IsTrue(t.Age == 0, "Invalidly set property must retain old value"); + } + catch (Exception ex) + { + Assert.Fail( + "Shouldn't throw exception other than PropertyAccessExceptions. Exception Message = " + ex.Message); + } + } + + [Test] + public void ArrayToStringConversion() + { + TestObject t = new TestObject(); + IObjectWrapper wrapper = GetWrapper(t); + TypeConverterRegistry.RegisterConverter(typeof(string), new TestStringArrayConverter()); + wrapper.SetPropertyValue("Name", new string[] { "a", "b" }); + Assert.AreEqual("-a,b-", t.Name); + } + + [Test] + public void ArrayToArrayConversion() + { + IndexedTestObject to = new IndexedTestObject(); + IObjectWrapper wrapper = GetWrapper(to); + TypeConverterRegistry.RegisterConverter(typeof(TestObject), new TestObjectArrayConverter()); + wrapper.SetPropertyValue("Array", new string[] { "a", "b" }); + Assert.AreEqual("a", to.Array[0].Name); + Assert.AreEqual("b", to.Array[1].Name); + } + + [Test] + public void PrimitiveArray() + { + PrimitiveArrayObject to = new PrimitiveArrayObject(); + IObjectWrapper wrapper = GetWrapper(to); + wrapper.SetPropertyValue("Array", new String[] { "1", "2" }); + Assert.AreEqual(2, to.Array.Length); + Assert.AreEqual(1, to.Array[0]); + Assert.AreEqual(2, to.Array[1]); + } + + [Test] + public void PrimitiveArrayFromCommaDelimitedString() + { + PrimitiveArrayObject to = new PrimitiveArrayObject(); + IObjectWrapper wrapper = GetWrapper(to); + wrapper.SetPropertyValue("Array", "1,2"); + Assert.AreEqual(2, to.Array.Length); + Assert.AreEqual(1, to.Array[0]); + Assert.AreEqual(2, to.Array[1]); + } + + [Test] + public void ObjectWrapperUpdates() + { + TestObject to = new TestObject("Rick", 2); + int newAge = 33; + ObjectWrapper wrapper = GetWrapper(to); + to.Age = newAge; + object owAge = wrapper.GetPropertyValue("Age"); + Assert.IsTrue(owAge is Int32, "Age is an integer"); + int owi = (int) owAge; + Assert.IsTrue(owi == newAge, "Object wrapper must pick up changes"); + } + + [Test] + public void SetWrappedInstanceOfSameClass() + { + TestObject to = new TestObject(); + IObjectWrapper wrapper = GetWrapper(to); + to.Age = 11; + + TestObject to2 = new TestObject(); + wrapper.WrappedInstance = to2; + + wrapper.SetPropertyValue("Age", 14); + Assert.IsTrue(to2.Age == 14, "2nd changed"); + Assert.IsTrue(to.Age == 11, "1st didn't change"); + } + + [Test] + public void SetWrappedInstanceOfDifferentClass() + { + ThrowsException tex = new ThrowsException(); + ObjectWrapper wrapper = GetWrapper(tex); + TestObject to2 = new TestObject(); + wrapper.WrappedInstance = to2; + + wrapper.SetPropertyValue("Age", 14); + Assert.IsTrue(to2.Age == 14); + } + + [Test] + public void TypeMismatch() + { + TestObject to = new TestObject(); + IObjectWrapper wrapper = GetWrapper(to); + Assert.Throws(() => wrapper.SetPropertyValue("Age", "foobar")); + } + + [Test] + public void EmptyValueForPrimitiveProperty() + { + TestObject to = new TestObject(); + ObjectWrapper wrapper = GetWrapper(to); + Assert.Throws(() => wrapper.SetPropertyValue("Age", "")); + } + + [Test] + public void GetProtectedPropertyValue() + { + TestObject foo = new TestObject(); + IObjectWrapper wrapper = GetWrapper(foo); + string happyPlace = (string) wrapper.GetPropertyValue("HappyPlace"); + Assert.AreEqual(TestObject.DefaultHappyPlace, happyPlace, + "Failed to read the value of a property with 'protected' access."); + } + + [Test] + public void SetProtectedPropertyValue() + { + TestObject foo = new TestObject(); + IObjectWrapper wrapper = GetWrapper(foo); + const string expectedHappyPlace = "The Rockies! Brrr..."; + wrapper.SetPropertyValue(new PropertyValue("HappyPlace", expectedHappyPlace)); + string happyPlace = (string) wrapper.GetPropertyValue("HappyPlace"); + Assert.AreEqual(expectedHappyPlace, happyPlace, + "Failed to read / write the value of a property with 'protected' access."); + } + + [Test] + public void GetPrivatePropertyValue() + { + TestObject foo = new TestObject(); + IObjectWrapper wrapper = GetWrapper(foo); + string[] contents = (string[]) wrapper.GetPropertyValue("SamsoniteSuitcase"); + Assert.IsTrue(ArrayUtils.AreEqual(TestObject.DefaultContentsOfTheSuitcase, contents), + "Failed to read the value of a property with 'private' access."); + } + + [Test] + public void SetPrivatePropertyValue() + { + TestObject foo = new TestObject(); + IObjectWrapper wrapper = GetWrapper(foo); + string[] expectedContents = new string[] { "Lloyd's Soul", "Harry's John Denver Records" }; + wrapper.SetPropertyValue(new PropertyValue("SamsoniteSuitcase", expectedContents)); + string[] contents = (string[]) wrapper.GetPropertyValue("SamsoniteSuitcase"); + Assert.IsTrue(ArrayUtils.AreEqual(expectedContents, contents), + "Failed to read / write the value of a property with 'private' access."); + } + + [Test] + public void GetNestedProperty() + { + ITestObject rod = new TestObject("rod", 31); + ITestObject kerry = new TestObject("kerry", 35); + rod.Spouse = kerry; + kerry.Spouse = rod; + IObjectWrapper wrapper = GetWrapper(rod); + int KA = (int) wrapper.GetPropertyValue("Spouse.Age"); + Assert.IsTrue(KA == 35, "Expected kerry's age to be 35"); + + int RA = (int) wrapper.GetPropertyValue("Spouse.Spouse.Age"); + Assert.IsTrue(RA == 31, "Expected rod's age to be 31"); + + ITestObject spousesSpouse = (ITestObject) wrapper.GetPropertyValue("Spouse.Spouse"); + Assert.IsTrue(rod == spousesSpouse, "spousesSpouse == initial point"); + } + + [Test] + public void GetNestedPropertyValueNullValue() + { + TestObject rod = new TestObject("rod", 31); + rod.Doctor = new NestedTestObject(null); + Assert.Throws(() => GetWrapper(rod).GetPropertyValue("Doctor.Company.Length")); + } + + [Test] + public void SetNestedProperty() + { + ITestObject rod = new TestObject("rod", 31); + ITestObject kerry = new TestObject("kerry", 0); + IObjectWrapper wrapper = GetWrapper(rod); + wrapper.SetPropertyValue("Spouse", kerry); + + Assert.AreEqual(rod.Spouse, kerry, "nested set did not work"); + wrapper.SetPropertyValue("Spouse.Spouse", rod); + Assert.AreEqual(rod, rod.Spouse.Spouse, "Nested set did not work."); + wrapper.SetPropertyValue("Spouse.Age", 100); + Assert.AreEqual(100, kerry.Age, "Nested setting of primitive property did not work."); + } + + [Test] + public void SetPropertyValue() + { + ITestObject bigby = new TestObject("Bigby", 4500); + ITestObject snow = new TestObject("Snow", 2500); + IObjectWrapper wrapper = GetWrapper(bigby); + wrapper.SetPropertyValue("Spouse", snow); + Assert.AreEqual(snow, bigby.Spouse); + } + + [Test] + public void SetIndexedPropertyValueOnUninitializedPath() + { + TestObject obj = new TestObject("Bill", 4500); + IObjectWrapper wrapper = GetWrapper(obj); + Assert.Throws(() => wrapper.SetPropertyValue("hats [0]", "Hicks & Co")); + } + + [Test] + public void SetIndexedPropertyValueOnNonIndexableType() + { + TestObject obj = new TestObject("Bill", 4500); + IObjectWrapper wrapper = GetWrapper(obj); + Assert.Throws(() => wrapper.SetPropertyValue("doctor [0]", "Hicks & Co")); + } + + [Test] + public void SetPrimitivePropertyToNullReference() + { + TestObject obj = new TestObject("Bill", 4500); + IObjectWrapper wrapper = GetWrapper(obj); + Assert.Throws(() => wrapper.SetPropertyValue("Age", null)); + } + + [Test] + public void SetPropertyValueIgnoresCase() + { + ITestObject bigby = new TestObject("Bigby", 4500); + ITestObject snow = new TestObject("Snow", 2500); + IObjectWrapper wrapper = GetWrapper(bigby); + wrapper.SetPropertyValue("spouse", snow); + Assert.AreEqual(snow, bigby.Spouse, + "Property setting is not case insensitive with regard to the property name (and for CLS compliance it should be)."); + } + + [Test] + public void IntArrayProperty() + { + PropsTest pt = new PropsTest(); + IObjectWrapper wrapper = GetWrapper(pt); + wrapper.SetPropertyValue("IntArray", new int[] { 4, 5, 2, 3 }); + Assert.IsTrue(pt.intArray.Length == 4, "intArray length = 4"); + Assert.IsTrue(pt.intArray[0] == 4 && pt.intArray[1] == 5 && pt.intArray[2] == 2 && pt.intArray[3] == 3, + "correct values"); + wrapper.SetPropertyValue("IntArray", new String[] { "4", "5", "2", "3" }); + Assert.IsTrue(pt.intArray.Length == 4, "intArray length = 4"); + Assert.IsTrue(pt.intArray[0] == 4 && pt.intArray[1] == 5 && pt.intArray[2] == 2 && pt.intArray[3] == 3, + "correct values"); + wrapper.SetPropertyValue("IntArray", 1); + Assert.IsTrue(pt.intArray.Length == 1, "intArray length = 1"); + Assert.IsTrue(pt.intArray[0] == 1, "correct values"); + wrapper.SetPropertyValue("IntArray", new String[] { "1" }); + Assert.IsTrue(pt.intArray.Length == 1, "intArray length = 1"); + Assert.IsTrue(pt.intArray[0] == 1, "correct values"); + } + + [Test] + public void NewWrappedInstancePropertyValuesGet() + { + ObjectWrapper wrapper = GetWrapper(); + TestObject t = new TestObject("Tony", 50); + wrapper.WrappedInstance = t; + Assert.AreEqual(t.Age, wrapper.GetPropertyValue("Age"), "Object wrapper returns wrong property value"); + + TestObject u = new TestObject("Udo", 30); + wrapper.WrappedInstance = u; + Assert.AreEqual(u.Age, wrapper.GetPropertyValue("Age"), "Object wrapper returns cached property value"); + } + + [Test] + public void NewWrappedInstanceNestedPropertyValuesGet() + { + IObjectWrapper wrapper = GetWrapper(); + TestObject t = new TestObject("Tony", 50); + t.Spouse = new TestObject("Sue", 40); + wrapper.WrappedInstance = t; + Assert.AreEqual(t.Spouse.Age, wrapper.GetPropertyValue("Spouse.Age"), + "Object wrapper returns wrong nested property value"); + + TestObject u = new TestObject("Udo", 30); + u.Spouse = new TestObject("Vera", 20); + wrapper.WrappedInstance = u; + Assert.AreEqual(u.Spouse.Age, wrapper.GetPropertyValue("Spouse.Age"), + "Object wrapper returns cached nested property value"); + } + + [Test] + public void StringArrayProperty() + { + PropsTest pt = new PropsTest(); + ObjectWrapper wrapper = GetWrapper(pt); + + wrapper.SetPropertyValue("StringArray", "foo,fi,fi,fum"); + Assert.IsTrue(pt.stringArray.Length == 4, "StringArray length = 4"); + Assert.IsTrue( + pt.stringArray[0].Equals("foo") && pt.stringArray[1].Equals("fi") && pt.stringArray[2].Equals("fi") && + pt.stringArray[3].Equals("fum"), "in correct values of string array"); + } + + #region Test for DateTime Properties + + internal class DateTimeTestObject + { + private DateTime _dt; + + public DateTime TriggerDateTime + { + get { return _dt; } + set { _dt = value; } + } + } + + [Test] + public void SetDateTimeProperty() + { + DateTimeTestObject o = new DateTimeTestObject(); + ObjectWrapper wrapper = GetWrapper(o); + + wrapper.SetPropertyValue("TriggerDateTime", "1991-10-10"); + + Assert.AreEqual(1991, ((DateTime) wrapper.GetPropertyValue("TriggerDateTime")).Year); + } + + #endregion + + #region Test for CultureInfo Properties + + internal class CultureTestObject + { + private CultureInfo _ci; + + public CultureInfo Cult + { + get { return _ci; } + set { _ci = value; } + } + } + + [Test] + public void SetCultureInfoProperty() + { + CultureTestObject o = new CultureTestObject(); + ObjectWrapper wrapper = GetWrapper(o); + + wrapper.SetPropertyValue("Cult", "es-ES"); + + Assert.AreEqual("es-ES", + ((CultureInfo) wrapper.GetPropertyValue("Cult")).Name); + } + + #endregion + + #region Tests for URI Properties + + internal class URITestObject + { + private Uri _uri; + + public Uri ResourceIdentifier + { + get { return _uri; } + set { _uri = value; } + } + } + + [Test] + public void SetURIProperty() + { + URITestObject o = new URITestObject(); + ObjectWrapper wrapper = GetWrapper(o); + + wrapper.SetPropertyValue("ResourceIdentifier", "http://www.springframework.net"); + Assert.AreEqual("www.springframework.net", + ((Uri) wrapper.GetPropertyValue("ResourceIdentifier")).Host); + } + + #endregion + + #region Tests for Indexed Array Properties + + [Test] + public void GetIndexedFromArrayProperty() + { + PrimitiveArrayObject to = new PrimitiveArrayObject(); + IObjectWrapper wrapper = GetWrapper(to); + to.Array = new int[] { 1, 2, 3, 4, 5 }; + Assert.AreEqual(1, (int) wrapper.GetPropertyValue("Array[0]")); + } + + [Test] + public void GetIndexOutofRangeFromArrayProperty() + { + PrimitiveArrayObject to = new PrimitiveArrayObject(); + IObjectWrapper wrapper = GetWrapper(to); + to.Array = new int[] { 1, 2, 3, 4, 5 }; + Assert.Throws(() => wrapper.GetPropertyValue("Array[5]")); + } + + [Test] + public void SetIndexedFromArrayProperty() + { + PrimitiveArrayObject to = new PrimitiveArrayObject(); + IObjectWrapper wrapper = GetWrapper(to); + to.Array = new int[] { 1, 2, 3, 4, 5 }; + wrapper.SetPropertyValue("Array[2]", 6); + Assert.AreEqual(6, to.Array[2]); + } + + [Test] + public void SetIndexOutOfRangeFromArrayProperty() + { + PrimitiveArrayObject to = new PrimitiveArrayObject(); + IObjectWrapper wrapper = GetWrapper(to); + to.Array = new int[] { 1, 2, 3, 4, 5 }; + Assert.Throws(() => wrapper.SetPropertyValue("Array[5]", 6)); + } + + /// + /// Test that we bail when attempting to get an indexed property with some guff for the index + /// + [Test] + public void GetIndexedPropertyValueWithGuffIndexFromArrayProperty() + { + PrimitiveArrayObject to = new PrimitiveArrayObject(); + IObjectWrapper wrapper = GetWrapper(to); + to.Array = new int[] { 1, 2, 3, 4, 5 }; + Assert.Throws(() => wrapper.GetPropertyValue("Array[HungerHurtsButStarvingWorks]")); + } + + /// + /// Test that we bail when attempting to get an indexed property with some guff for the index + /// + [Test] + public void GetIndexedPropertyValueWithMissingIndexFromArrayProperty() + { + PrimitiveArrayObject to = new PrimitiveArrayObject(); + IObjectWrapper wrapper = GetWrapper(to); + to.Array = new int[] { 1, 2, 3, 4, 5 }; + Assert.Throws(() => wrapper.GetPropertyValue("Array[]")); + } + + #endregion + + #region Tests for Indexed List Properties + + internal class ListTestObject + { + private IList _list; + private ArrayList _arrayList; + + public IList List + { + get { return _list; } + set { _list = value; } + } + + public ArrayList ArrayList + { + get { return _arrayList; } + set { _arrayList = value; } + } + } + + [Test] + public void GetIndexedFromListProperty() + { + ListTestObject to = new ListTestObject(); + IObjectWrapper wrapper = GetWrapper(to); + to.List = new ArrayList(new int[] { 1, 2, 3, 4, 5 }); + Assert.AreEqual(1, (int) wrapper.GetPropertyValue("List[0]")); + } + + [Test] + public void GetIndexedFromArrayListProperty() + { + ListTestObject to = new ListTestObject(); + IObjectWrapper wrapper = GetWrapper(to); + to.ArrayList = new ArrayList(new int[] { 1, 2, 3, 4, 5 }); + Assert.AreEqual(1, (int) wrapper.GetPropertyValue("ArrayList[0]")); + } + + [Test] + public void GetIndexOutofRangeFromListProperty() + { + ListTestObject to = new ListTestObject(); + IObjectWrapper wrapper = GetWrapper(to); + to.List = new ArrayList(new int[] { 1, 2, 3, 4, 5 }); + Assert.Throws(() => wrapper.GetPropertyValue("List[5]")); + } + + [Test] + public void SetIndexedFromListProperty() + { + ListTestObject to = new ListTestObject(); + IObjectWrapper wrapper = GetWrapper(to); + to.List = new ArrayList(new int[] { 1, 2, 3, 4, 5 }); + wrapper.SetPropertyValue("List[0]", 6); + Assert.AreEqual(6, to.List[0]); + } + + [Test] + public void SetIndexedFromListPropertyUsingMixOfSingleAndDoubleQuotedDelimeters() + { + ListTestObject to = new ListTestObject(); + IObjectWrapper wrapper = GetWrapper(to); + to.List = new ArrayList(new int[] { 1, 2, 3, 4, 5 }); + Assert.Throws(() => wrapper.SetPropertyValue("List['0\"]", 6)); + } + + [Test] + public void SetIndexedFromListPropertyUsingNonNumericValueForTheIndex() + { + ListTestObject to = new ListTestObject(); + IObjectWrapper wrapper = GetWrapper(to); + to.List = new ArrayList(new int[] { 1, 2, 3, 4, 5 }); + Assert.Throws(() => wrapper.SetPropertyValue("List[bingo]", 6)); + } + + [Test] + public void SetIndexedFromListPropertyUsingEmptyValueForTheIndex() + { + ListTestObject to = new ListTestObject(); + IObjectWrapper wrapper = GetWrapper(to); + to.List = new ArrayList(new int[] { 1, 2, 3, 4, 5 }); + Assert.Throws(() => wrapper.SetPropertyValue("List[]", 6)); + } + + [Test] + [Ignore("Addition of elements to the list via index that is out of range is not supported anymore.")] + public void SetIndexOutOfRangeFromListProperty() + { + ListTestObject to = new ListTestObject(); + IObjectWrapper wrapper = GetWrapper(to); + to.List = new ArrayList(new int[] { 1, 2, 3, 4, 5 }); + wrapper.SetPropertyValue("List[6]", 6); + Assert.AreEqual(6, to.List[6]); + Assert.IsNull(to.List[5]); + wrapper.SetPropertyValue("List[7]", 7); + Assert.AreEqual(7, to.List[7]); + } + + /// + /// Test that we bail when attempting to get an indexed property with some guff for the index + /// + [Test] + public void GetIndexedPropertyValueWithGuffIndexFromListProperty() + { + ListTestObject to = new ListTestObject(); + IObjectWrapper wrapper = GetWrapper(to); + to.List = new ArrayList(new int[] { 1, 2, 3, 4, 5 }); + Assert.Throws(() => wrapper.GetPropertyValue("List[HungerHurtsButStarvingWorks]")); + } + + [Test] + public void GetIndexedPropertyValueWithMissingIndexFromListProperty() + { + ListTestObject to = new ListTestObject(); + IObjectWrapper wrapper = GetWrapper(to); + to.List = new ArrayList(new int[] { 1, 2, 3, 4, 5 }); + Assert.Throws(() => wrapper.GetPropertyValue("List[]")); + } + + #endregion + + #region Tests for Indexed Dictionary Properties + + internal class DictionaryTestObject + { + private IDictionary _dictionary; + + public IDictionary Dictionary + { + get { return _dictionary; } + set { _dictionary = value; } + } + } + + [Test] + public void GetIndexedFromDictionaryProperty() + { + DictionaryTestObject to = new DictionaryTestObject(); + IObjectWrapper wrapper = GetWrapper(to); + to.Dictionary = new Hashtable(); + to.Dictionary.Add("key1", "value1"); + Assert.AreEqual("value1", (string) wrapper.GetPropertyValue("Dictionary['key1']")); + } + + [Test] + public void GetIndexMissingFromDictionaryProperty() + { + DictionaryTestObject to = new DictionaryTestObject(); + IObjectWrapper wrapper = GetWrapper(to); + to.Dictionary = new Hashtable(); + Assert.IsNull(wrapper.GetPropertyValue("Dictionary['notthere']")); + } + + [Test] + public void SetIndexedFromDictionaryProperty() + { + DictionaryTestObject to = new DictionaryTestObject(); + IObjectWrapper wrapper = GetWrapper(to); + to.Dictionary = new Hashtable(); + wrapper.SetPropertyValue("Dictionary['key1']", "value1"); + Assert.AreEqual("value1", to.Dictionary["key1"]); + } + + [Test] + public void SettingADictionaryPropertyJustAddsTheValuesToTheExistingDictionary() + { + TestObject to = new TestObject(); + to.AddPeriodicElement("Hsu", "Feng"); + to.AddPeriodicElement("Piao", "Jin"); + ObjectWrapper wrapper = GetWrapper(to); + IDictionary elements = new Hashtable(); + elements.Add("Weekend", "News"); + wrapper.SetPropertyValue("PeriodictabLE", elements); + Assert.AreEqual(3, to.PeriodicTable.Count); + } + + #endregion + + #region Tests for Indexed Set Properties + + internal class SetTestObject + { + private ISet _set; + private HybridSet _aSet; + + public ISet Set + { + get { return _set; } + set { _set = value; } + } + + public HybridSet HybridSet + { + get { return _aSet; } + set { _aSet = value; } + } + } + + [Test] + public void SettingASetPropertyJustAddsTheValuesToTheExistingSet() + { + TestObject to = new TestObject(); + to.AddComputerName("Atari 2900"); + to.AddComputerName("JCN"); + ObjectWrapper wrapper = GetWrapper(to); + wrapper.SetPropertyValue("Computers", new HybridSet(new string[] { "Trusty SNES" })); + Assert.AreEqual(3, to.Computers.Count); + } + + [Test] + public void GetIndexFromSetProperty() + { + SetTestObject to = new SetTestObject(); + IObjectWrapper wrapper = GetWrapper(to); + to.Set = new ListSet(new int[] { 1, 2, 3, 4, 5 }); + Assert.Throws(() => wrapper.GetPropertyValue("Set[1]")); + } + + [Test] + public void GetIndexOutofRangeFromSetProperty() + { + SetTestObject to = new SetTestObject(); + IObjectWrapper wrapper = GetWrapper(to); + to.Set = new ListSet(new int[] { 1, 2, 3, 4, 5 }); + Assert.Throws(() => wrapper.GetPropertyValue("Set[23]")); + } + + /// + /// Test that we bail when attempting to get an indexed property with some guff for the index + /// + [Test] + public void GetIndexedPropertyValueWithGuffIndexFromSetProperty() + { + SetTestObject to = new SetTestObject(); + IObjectWrapper wrapper = GetWrapper(to); + to.Set = new ListSet(new int[] { 1, 2, 3, 4, 5 }); + Assert.Throws(() => wrapper.GetPropertyValue("Set[HungerHurtsButStarvingWorks]")); + } + + [Test] + public void GetIndexedPropertyValueWithMissingIndexFromSetProperty() + { + SetTestObject to = new SetTestObject(); + IObjectWrapper wrapper = GetWrapper(to); + to.Set = new ListSet(new int[] { 1, 2, 3, 4, 5 }); + Assert.Throws(() => wrapper.GetPropertyValue("Set[]")); + } + + #endregion + + #region Test for Enumeration Properties + + internal class EnumTestObject + { + private FileMode FileModeEnum; + + public FileMode FileMode + { + get { return FileModeEnum; } + set { FileModeEnum = value; } + } + } + + [Test] + public void SetEnumProperty() + { + EnumTestObject o = new EnumTestObject(); + ObjectWrapper wrapper = GetWrapper(o); + wrapper.SetPropertyValue("FileMode", FileMode.Create); + Assert.AreEqual(FileMode.Create, (FileMode) wrapper.GetPropertyValue("FileMode")); + } + + #endregion + + [Test] + public void SetTypePropertyWithString() + { + ObjectWithTypeProperty to = new ObjectWithTypeProperty(); + IObjectWrapper wrapper = GetWrapper(to); + wrapper.SetPropertyValue("Type", "System.DateTime"); + Assert.AreEqual(typeof(DateTime), to.Type); + } + + [Test] + public void GetIndexedPropertyValueWithNonIndexedType() + { + TestObject to = new TestObject(); + IObjectWrapper wrapper = GetWrapper(to); + Assert.Throws(() => wrapper.GetPropertyValue("FileMode[0]")); + } + + [Test] + public void SetPropertyValuesWithUnknownProperty() + { + TestObject to = new TestObject(); + to.Doctor = null; + ObjectWrapper wrapper = GetWrapper(to); + Assert.Throws(() => wrapper.SetPropertyValue("Doctor.Company", "Bingo")); + } + + [Test] + public void SetPropertyValuesFailsWhenSettingNonExistantProperty() + { + TestObject to = new TestObject(); + ObjectWrapper wrapper = GetWrapper(to); + MutablePropertyValues values = new MutablePropertyValues(); + values.Add("JeepersCreepersWhereDidYaGetThosePeepers", "OhThisWeirdBatGuySoldEmToMe..."); + values.Add("Age", 19); + // the unknown and ridiculously named property should fail + Assert.Throws(() => wrapper.SetPropertyValues(values, false)); + } + + [Test] + public void SetPropertyValuesDoesNotFailWhenSettingNonExistantPropertyWithIgnorUnknownSetToTrue() + { + TestObject to = new TestObject(); + ObjectWrapper wrapper = GetWrapper(to); + MutablePropertyValues values = new MutablePropertyValues(); + values.Add("Age", 19); + values.Add("JeepersCreepersWhereDidYaGetThosePeepers", "OhThisWeirdBatGuySoldEmToMe..."); + // the unknown and ridiculously named property should fail + wrapper.SetPropertyValues(values, true); + Assert.AreEqual(19, to.Age, "The single good property in the property values should have been set though..."); + } + + [Test] + public void SetPropertyValuesFailsWhenSettingReadOnlyProperty() + { + TestObject to = new TestObject(); + ObjectWrapper wrapper = GetWrapper(to); + MutablePropertyValues values = new MutablePropertyValues(); + values.Add("ReadOnlyObjectNumber", 123); + Assert.Throws(() => wrapper.SetPropertyValues(values, false)); + } + + [Test] + public void SetPropertyValuesDoesNotFailWhenSettingReadOnlyPropertyWithIgnorUnknownSetToTrue() + { + TestObject to = new TestObject(); + ObjectWrapper wrapper = GetWrapper(to); + MutablePropertyValues values = new MutablePropertyValues(); + values.Add("ObjectNumber", 123); + values.Add("Age", 19); + wrapper.SetPropertyValues(values, true); + Assert.AreEqual(19, to.Age, "The single good property in the property values should have been set though..."); + } + + [Test] + public void SetArrayPropertyValue() + { + string[] expected = new string[] { "Fedora", "Gacy", "Banjo" }; + TestObject to = new TestObject(); + ObjectWrapper wrapper = GetWrapper(to); + wrapper.SetPropertyValue("Hats", expected); + Assert.IsNotNull(to.Hats); + Assert.AreEqual(expected.Length, to.Hats.Length); + for (int i = 0; i < expected.Length; ++i) + { + Assert.AreEqual(expected[i], to.Hats[i]); + } + } + + [Test] + public void TestToString() + { + ObjectWrapper wrapper = GetWrapper(); + Assert.IsTrue(wrapper.ToString().IndexOf("Exception encountered") >= 0); + wrapper.WrappedInstance = new WanPropsClass(); + string expected = string.Format( + "{0}: wrapping class [{1}]; IsWan={2}", + wrapper.GetType().Name, wrapper.WrappedType.FullName, "{True}"); + Assert.AreEqual(expected, wrapper.ToString()); + } + + [Test] + public void GetPropertyInfoWithNullArgument() + { + ObjectWrapper wrapper = GetWrapper(new TestObject()); + Assert.Throws(() => wrapper.GetPropertyInfo(null)); + } + + [Test] + public void GetPropertyInfoWithNonPropertyExpression() + { + ObjectWrapper wrapper = GetWrapper(new TestObject()); + Assert.Throws(() => wrapper.GetPropertyInfo("2 + 2")); + } + + [Test] + public void GetPropertyInfoWithNonParsableExpression() + { + ObjectWrapper wrapper = GetWrapper(new TestObject()); + Assert.Throws(() => wrapper.GetPropertyInfo("[")); + } + + [Test] + public void GetNestedPropertyInfo() + { + RealNestedTestObject o = new RealNestedTestObject(); + o.Datum = new TestObject(); + o.Datum.Doctor = new NestedTestObject("Modlin"); + ObjectWrapper wrapper = GetWrapper(o); + PropertyInfo info = wrapper.GetPropertyInfo("Datum.Doctor.Company"); + Assert.IsNotNull(info); + } + + [Test(Description = "SPRNET-198")] + public void AmbiguousPropertyLookupIsHandledProperlyByLookingAtDerivedClassOnly() + { + ObjectWrapper wrapper = GetWrapper(new DerivedFoo()); + wrapper.GetPropertyInfo("Bar"); + } } diff --git a/test/Spring/Spring.Core.Tests/Objects/PropertyAccessExceptionsExceptionTests.cs b/test/Spring/Spring.Core.Tests/Objects/PropertyAccessExceptionsExceptionTests.cs index 212c4071..2f2d862c 100644 --- a/test/Spring/Spring.Core.Tests/Objects/PropertyAccessExceptionsExceptionTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/PropertyAccessExceptionsExceptionTests.cs @@ -23,47 +23,39 @@ using System.Reflection; using NUnit.Framework; using Spring.Core; -namespace Spring.Objects +namespace Spring.Objects; + +/// +/// Unit tests for the PropertyAccessExceptionsException class. +/// +[TestFixture] +public sealed class PropertyAccessExceptionsExceptionTests { - /// - /// Unit tests for the PropertyAccessExceptionsException class. - /// - [TestFixture] - public sealed class PropertyAccessExceptionsExceptionTests + [Test] + public void GetNonExistantPropertyException() { - [Test] - public void GetNonExistantPropertyException() - { - ObjectWrapper wrapper = new ObjectWrapper(new TestObject("Rick", 23)); - PropertyAccessExceptionsException ex - = new PropertyAccessExceptionsException(wrapper, new PropertyAccessException[] - { - }); - PropertyAccessException nullException = ex.GetPropertyAccessException("Age"); - Assert.IsNull(nullException); - } + ObjectWrapper wrapper = new ObjectWrapper(new TestObject("Rick", 23)); + PropertyAccessExceptionsException ex + = new PropertyAccessExceptionsException(wrapper, new PropertyAccessException[] { }); + PropertyAccessException nullException = ex.GetPropertyAccessException("Age"); + Assert.IsNull(nullException); + } - [Test] - public void GetPropertyExceptions() - { - ObjectWrapper wrapper = new ObjectWrapper(new TestObject("Rick", 23)); - PropertyAccessExceptionsException ex - = new PropertyAccessExceptionsException(wrapper, new PropertyAccessException[] - { - new TypeMismatchException(new PropertyChangeEventArgs("Doctor", new NestedTestObject("Foo"), "rubbish"), typeof (INestedTestObject)), - new MethodInvocationException(new TargetInvocationException("Bad format", new FormatException("'12' is not a valid argument for 'foo'..")), new PropertyChangeEventArgs("Friends", new ArrayList(), "trash")) - }); - PropertyAccessException doctorPropertyException = ex.GetPropertyAccessException("Doctor"); - Assert.IsNotNull(doctorPropertyException); - Assert.AreEqual("typeMismatch", doctorPropertyException.ErrorCode); - Assert.AreEqual("Foo", ((NestedTestObject) doctorPropertyException.PropertyChangeArgs.OldValue).Company); - PropertyAccessException friendsPropertyException = ex.GetPropertyAccessException("Friends"); - Assert.IsNotNull(friendsPropertyException); - Assert.AreEqual("methodInvocation", friendsPropertyException.ErrorCode); - Assert.AreEqual(wrapper, ex.ObjectWrapper); - Assert.AreEqual(wrapper.WrappedInstance, ex.BindObject); - Assert.AreEqual(ex.Message, ex.ToString()); - - } - } + [Test] + public void GetPropertyExceptions() + { + ObjectWrapper wrapper = new ObjectWrapper(new TestObject("Rick", 23)); + PropertyAccessExceptionsException ex + = new PropertyAccessExceptionsException(wrapper, new PropertyAccessException[] { new TypeMismatchException(new PropertyChangeEventArgs("Doctor", new NestedTestObject("Foo"), "rubbish"), typeof(INestedTestObject)), new MethodInvocationException(new TargetInvocationException("Bad format", new FormatException("'12' is not a valid argument for 'foo'..")), new PropertyChangeEventArgs("Friends", new ArrayList(), "trash")) }); + PropertyAccessException doctorPropertyException = ex.GetPropertyAccessException("Doctor"); + Assert.IsNotNull(doctorPropertyException); + Assert.AreEqual("typeMismatch", doctorPropertyException.ErrorCode); + Assert.AreEqual("Foo", ((NestedTestObject) doctorPropertyException.PropertyChangeArgs.OldValue).Company); + PropertyAccessException friendsPropertyException = ex.GetPropertyAccessException("Friends"); + Assert.IsNotNull(friendsPropertyException); + Assert.AreEqual("methodInvocation", friendsPropertyException.ErrorCode); + Assert.AreEqual(wrapper, ex.ObjectWrapper); + Assert.AreEqual(wrapper.WrappedInstance, ex.BindObject); + Assert.AreEqual(ex.Message, ex.ToString()); + } } diff --git a/test/Spring/Spring.Core.Tests/Objects/PropertyValueTests.cs b/test/Spring/Spring.Core.Tests/Objects/PropertyValueTests.cs index cf277c03..8a4b7082 100644 --- a/test/Spring/Spring.Core.Tests/Objects/PropertyValueTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/PropertyValueTests.cs @@ -2,13 +2,13 @@ /* * Copyright � 2002-2011 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. @@ -24,57 +24,56 @@ using NUnit.Framework; #endregion -namespace Spring.Objects +namespace Spring.Objects; + +/// +/// Unit tests for the PropertyValue class. +/// +/// Rick Evans +[TestFixture] +public sealed class PropertyValueTests { - /// - /// Unit tests for the PropertyValue class. - /// - /// Rick Evans - [TestFixture] - public sealed class PropertyValueTests + [Test] + public void InstantiationWithNulls() { - [Test] - public void InstantiationWithNulls() - { - Assert.Throws(() => new PropertyValue(null, null)); - } - - [Test] - public void Instantiation() - { - PropertyValue val = new PropertyValue("Age", 12); - Assert.AreEqual("Age", val.Name); - Assert.AreEqual(12, val.Value); - } - - [Test] - public void InstantiationWithEmptyStringPropertyName() - { - Assert.Throws(() => new PropertyValue(string.Empty, 12)); - } - - [Test] - public void InstantiationWithWhitespacePropertyName() - { - Assert.Throws(() => new PropertyValue(" ", 12)); - } - - [Test] - public void TestEquals() - { - PropertyValue one = new PropertyValue("Age", 12); - PropertyValue two = new PropertyValue("Age", 12); - Assert.AreEqual(one, two); - Assert.AreEqual(one.GetHashCode(), two.GetHashCode()); - Assert.AreEqual(one, one); - Assert.IsFalse(one.Equals("Foo")); - } - - [Test] - public void TestToString() - { - PropertyValue one = new PropertyValue("Age", 12); - Assert.AreEqual("PropertyValue: name='Age'; value=[12].", one.ToString()); - } + Assert.Throws(() => new PropertyValue(null, null)); } -} \ No newline at end of file + + [Test] + public void Instantiation() + { + PropertyValue val = new PropertyValue("Age", 12); + Assert.AreEqual("Age", val.Name); + Assert.AreEqual(12, val.Value); + } + + [Test] + public void InstantiationWithEmptyStringPropertyName() + { + Assert.Throws(() => new PropertyValue(string.Empty, 12)); + } + + [Test] + public void InstantiationWithWhitespacePropertyName() + { + Assert.Throws(() => new PropertyValue(" ", 12)); + } + + [Test] + public void TestEquals() + { + PropertyValue one = new PropertyValue("Age", 12); + PropertyValue two = new PropertyValue("Age", 12); + Assert.AreEqual(one, two); + Assert.AreEqual(one.GetHashCode(), two.GetHashCode()); + Assert.AreEqual(one, one); + Assert.IsFalse(one.Equals("Foo")); + } + + [Test] + public void TestToString() + { + PropertyValue one = new PropertyValue("Age", 12); + Assert.AreEqual("PropertyValue: name='Age'; value=[12].", one.ToString()); + } +} diff --git a/test/Spring/Spring.Core.Tests/Objects/ResourceTestObject.cs b/test/Spring/Spring.Core.Tests/Objects/ResourceTestObject.cs index 6d924d8d..646f9076 100644 --- a/test/Spring/Spring.Core.Tests/Objects/ResourceTestObject.cs +++ b/test/Spring/Spring.Core.Tests/Objects/ResourceTestObject.cs @@ -1,4 +1,5 @@ #region License + /* * Copyright � 2002-2011 the original author or authors. * @@ -14,43 +15,51 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + #endregion + #region Imports using Spring.Core.IO; + #endregion -namespace Spring.Objects + +namespace Spring.Objects; + +/// +/// Object for testing IResource instances. +/// +/// Juergen Hoeller +/// Mark Pollack (.NET) +public class ResourceTestObject { - /// - /// Object for testing IResource instances. - /// - /// Juergen Hoeller - /// Mark Pollack (.NET) - public class ResourceTestObject + private IResource resource; + private Stream inputStream; + + public ResourceTestObject() { - private IResource resource; - private Stream inputStream; - public ResourceTestObject() - { - } - public ResourceTestObject(IResource resource) - { - this.resource = resource; - } - public ResourceTestObject(IResource resource, Stream inputStream) - { - this.resource = resource; - this.inputStream = inputStream; - } - public IResource Resource - { - get { return this.resource; } - set { this.resource = value; } - } - public Stream InputStream - { - get { return this.inputStream; } - set { this.inputStream = value; } - } } -} \ No newline at end of file + + public ResourceTestObject(IResource resource) + { + this.resource = resource; + } + + public ResourceTestObject(IResource resource, Stream inputStream) + { + this.resource = resource; + this.inputStream = inputStream; + } + + public IResource Resource + { + get { return this.resource; } + set { this.resource = value; } + } + + public Stream InputStream + { + get { return this.inputStream; } + set { this.inputStream = value; } + } +} diff --git a/test/Spring/Spring.Core.Tests/Objects/SerializablePerson.cs b/test/Spring/Spring.Core.Tests/Objects/SerializablePerson.cs index caf6d8b9..d109973b 100644 --- a/test/Spring/Spring.Core.Tests/Objects/SerializablePerson.cs +++ b/test/Spring/Spring.Core.Tests/Objects/SerializablePerson.cs @@ -21,56 +21,57 @@ #region Imports using System.Runtime.Serialization; + #endregion -namespace Spring.Objects +namespace Spring.Objects; + +/// +/// Serializable implementation of the IPerson interface. +/// +/// Rod Johnson +/// Simon White (.NET) +[Serializable] +public class SerializablePerson : TestObject, IPerson, ISerializable { - /// - /// Serializable implementation of the IPerson interface. - /// - /// Rod Johnson - /// Simon White (.NET) - [Serializable] - public class SerializablePerson : TestObject, IPerson, ISerializable - { - public SerializablePerson() - { - } + public SerializablePerson() + { + } - protected SerializablePerson(SerializationInfo info, StreamingContext ctxt) - { - this.Age = (int) info.GetValue("Age", typeof(int)); - this.Name = (string) info.GetValue("Name", typeof(string)); - } + protected SerializablePerson(SerializationInfo info, StreamingContext ctxt) + { + this.Age = (int) info.GetValue("Age", typeof(int)); + this.Name = (string) info.GetValue("Name", typeof(string)); + } - public void GetObjectData(SerializationInfo info, StreamingContext ctxt) - { - info.AddValue("Age", this.Age); - info.AddValue("Name", this.Name); - } + public void GetObjectData(SerializationInfo info, StreamingContext ctxt) + { + info.AddValue("Age", this.Age); + info.AddValue("Name", this.Name); + } - public int GetAge() - { - return this.Age; - } + public int GetAge() + { + return this.Age; + } - public void SetAge(int age) - { - this.Age = age; - } + public void SetAge(int age) + { + this.Age = age; + } - public string GetName() - { - return this.Name; - } + public string GetName() + { + return this.Name; + } - public object Echo(object obj) + public object Echo(object obj) + { + if (obj is Exception) { - if (obj is Exception) - { - throw (Exception)obj; - } - return obj; + throw (Exception) obj; } - } + + return obj; + } } diff --git a/test/Spring/Spring.Core.Tests/Objects/StaticTestEventHandler.cs b/test/Spring/Spring.Core.Tests/Objects/StaticTestEventHandler.cs index 1ba96862..ea197cc1 100644 --- a/test/Spring/Spring.Core.Tests/Objects/StaticTestEventHandler.cs +++ b/test/Spring/Spring.Core.Tests/Objects/StaticTestEventHandler.cs @@ -22,27 +22,26 @@ #endregion -namespace Spring.Objects { +namespace Spring.Objects; - /// - /// Exposes a static method that has a signature compatible with the - /// EventHandler delegate. - /// - public class StaticTestEventHandler +/// +/// Exposes a static method that has a signature compatible with the +/// EventHandler delegate. +/// +public class StaticTestEventHandler +{ + public static void HandleArbitraryEvent(object sender, EventArgs e) { - public static void HandleArbitraryEvent (object sender, EventArgs e) - { - _eventWasHandled = true; - } + _eventWasHandled = true; + } - public static bool EventWasHandled + public static bool EventWasHandled + { + get { - get - { - return _eventWasHandled; - } + return _eventWasHandled; } + } - protected static bool _eventWasHandled; - } + protected static bool _eventWasHandled; } diff --git a/test/Spring/Spring.Core.Tests/Objects/Support/AbstractSharedStateFactoryTests.cs b/test/Spring/Spring.Core.Tests/Objects/Support/AbstractSharedStateFactoryTests.cs index 93a93f45..0526ab0f 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Support/AbstractSharedStateFactoryTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Support/AbstractSharedStateFactoryTests.cs @@ -25,84 +25,83 @@ using NUnit.Framework; #endregion -namespace Spring.Objects.Support +namespace Spring.Objects.Support; + +/// +/// +/// +/// Erich Eichinger +[TestFixture] +public class AbstractSharedStateFactoryTests { - /// - /// - /// - /// Erich Eichinger - [TestFixture] - public class AbstractSharedStateFactoryTests + private class TestSharedStateFactory : AbstractSharedStateFactory { - private class TestSharedStateFactory : AbstractSharedStateFactory + public static readonly object SPECIAL_OBJECT = new object(); + + protected override object GetKey(object instance, string name) { - public static readonly object SPECIAL_OBJECT = new object(); - - protected override object GetKey(object instance, string name) - { - if (instance == SPECIAL_OBJECT) return null; - return name+"|"+instance.GetHashCode(); - } - } - - [Test] - public void DefaultsToCaseInsensitiveState() - { - TestSharedStateFactory p = new TestSharedStateFactory(); - Assert.IsFalse(p.CaseSensitiveState); - IDictionary state = p.GetSharedStateFor(new object(), "no name" ); - state["foo"] = this; - Assert.AreSame(this, state["FOO"]); - } - - [Test] - public void StateDictionaryBehavesAccordingToCaseSensitiveState() - { - TestSharedStateFactory p = new TestSharedStateFactory(); - - // create case-insensitive dict - Assert.IsFalse(p.CaseSensitiveState); - IDictionary state = p.GetSharedStateFor(new object(), "no name" ); - state["foo"] = this; - Assert.AreSame(this, state["FOO"]); - - // create case-sensitive dict - p.CaseSensitiveState = true; - state = p.GetSharedStateFor(new object(), "no name" ); - state["foo"] = this; - Assert.IsFalse(state.Contains("FOO")); - } - - [Test] - public void ThrowsOnNullInstance() - { - TestSharedStateFactory p = new TestSharedStateFactory(); - // allow "null" for name - IDictionary state = p.GetSharedStateFor(new object(), null); - Assert.IsNotNull(state); - // throws on null for instance - Assert.Throws(() => p.GetSharedStateFor(null, "no name")); - } - - [Test] - public void SharedStateCacheIsCaseSensitive() - { - TestSharedStateFactory p = new TestSharedStateFactory(); - // allow "null" for name - IDictionary state = p.GetSharedStateFor(this, "foo"); - IDictionary state2 = p.GetSharedStateFor(this, "FOO"); - Assert.IsNotNull(state); - Assert.IsNotNull(state2); - Assert.AreNotSame(state, state2); - } - - [Test] - public void ReturnsNullStateIfKeyIsNull() - { - TestSharedStateFactory p = new TestSharedStateFactory(); - // force provider to produce a null key - IDictionary state = p.GetSharedStateFor(TestSharedStateFactory.SPECIAL_OBJECT, null); - Assert.IsNull(state); + if (instance == SPECIAL_OBJECT) return null; + return name + "|" + instance.GetHashCode(); } } -} \ No newline at end of file + + [Test] + public void DefaultsToCaseInsensitiveState() + { + TestSharedStateFactory p = new TestSharedStateFactory(); + Assert.IsFalse(p.CaseSensitiveState); + IDictionary state = p.GetSharedStateFor(new object(), "no name"); + state["foo"] = this; + Assert.AreSame(this, state["FOO"]); + } + + [Test] + public void StateDictionaryBehavesAccordingToCaseSensitiveState() + { + TestSharedStateFactory p = new TestSharedStateFactory(); + + // create case-insensitive dict + Assert.IsFalse(p.CaseSensitiveState); + IDictionary state = p.GetSharedStateFor(new object(), "no name"); + state["foo"] = this; + Assert.AreSame(this, state["FOO"]); + + // create case-sensitive dict + p.CaseSensitiveState = true; + state = p.GetSharedStateFor(new object(), "no name"); + state["foo"] = this; + Assert.IsFalse(state.Contains("FOO")); + } + + [Test] + public void ThrowsOnNullInstance() + { + TestSharedStateFactory p = new TestSharedStateFactory(); + // allow "null" for name + IDictionary state = p.GetSharedStateFor(new object(), null); + Assert.IsNotNull(state); + // throws on null for instance + Assert.Throws(() => p.GetSharedStateFor(null, "no name")); + } + + [Test] + public void SharedStateCacheIsCaseSensitive() + { + TestSharedStateFactory p = new TestSharedStateFactory(); + // allow "null" for name + IDictionary state = p.GetSharedStateFor(this, "foo"); + IDictionary state2 = p.GetSharedStateFor(this, "FOO"); + Assert.IsNotNull(state); + Assert.IsNotNull(state2); + Assert.AreNotSame(state, state2); + } + + [Test] + public void ReturnsNullStateIfKeyIsNull() + { + TestSharedStateFactory p = new TestSharedStateFactory(); + // force provider to produce a null key + IDictionary state = p.GetSharedStateFor(TestSharedStateFactory.SPECIAL_OBJECT, null); + Assert.IsNull(state); + } +} diff --git a/test/Spring/Spring.Core.Tests/Objects/Support/ArgumentConvertingMethodInvokerTests.cs b/test/Spring/Spring.Core.Tests/Objects/Support/ArgumentConvertingMethodInvokerTests.cs index 51fffded..afec0a5c 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Support/ArgumentConvertingMethodInvokerTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Support/ArgumentConvertingMethodInvokerTests.cs @@ -24,125 +24,127 @@ using NUnit.Framework; #endregion -namespace Spring.Objects.Support +namespace Spring.Objects.Support; + +/// +/// Unit tests for the ArgumentConvertingMethodInvoker class. +/// +/// Rick Evans +[TestFixture] +public sealed class ArgumentConvertingMethodInvokerTests { - /// - /// Unit tests for the ArgumentConvertingMethodInvoker class. - /// - /// Rick Evans - [TestFixture] - public sealed class ArgumentConvertingMethodInvokerTests + [Test] + public void Invoke() { - [Test] - public void Invoke () { - ArgumentConvertingMethodInvoker vkr = new ArgumentConvertingMethodInvoker (); - vkr.TargetObject = new Voker (); - vkr.TargetMethod = "Hi"; - vkr.Arguments = new object [] {"Rick, Mark, Griffin, Si, Choy, Aleks"}; - vkr.Prepare (); - string actual = vkr.Invoke () as string; - Assert.IsNotNull (actual); - Assert.AreEqual ("Hi Rick, Mark, Griffin, Si, Choy, Aleks", actual); - } - - [Test] - public void InvokeWithConversion () - { - ArgumentConvertingMethodInvoker vkr = new ArgumentConvertingMethodInvoker (); - Voker instance = new Voker (); - vkr.TargetObject = instance; - vkr.TargetMethod = "HiEverybody"; - // CSV string should be converted to string [] - vkr.Arguments = new object [] {"Rick, Mark, Griffin, Federico, Choy, Aleks"}; - vkr.Prepare (); - string actual = vkr.Invoke () as string; - Assert.IsNotNull (actual); - Assert.AreEqual ("Hi ya'll", actual); - Assert.IsNotNull (instance.developers); - } - - [Test] - public void InvokeAllNamedArgumentsWithConversion () - { - ArgumentConvertingMethodInvoker vkr = new ArgumentConvertingMethodInvoker (); - Voker instance = new Voker (); - vkr.TargetObject = instance; - vkr.TargetMethod = "HiEverybody"; - // CSV string should be converted to string [] - vkr.AddNamedArgument("nameS", new object [] {"Rick, Mark, Griffin, Federico, Choy, Aleks"}); - vkr.Prepare (); - string actual = vkr.Invoke () as string; - Assert.IsNotNull (actual); - Assert.AreEqual ("Hi ya'll", actual); - Assert.IsNotNull (instance.developers); - } - - [Test] - public void InvokeWithRegisteredConversion () - { - ArgumentConvertingMethodInvoker vkr = new ArgumentConvertingMethodInvoker (); - // see if custom registration filters thru... - vkr.RegisterCustomConverter (typeof (Voker), new VokerConverter ()); - vkr.TargetType = typeof (Voker); - vkr.TargetMethod = "HiVoker"; - // arg should be converted to Voker - vkr.Arguments = new object [] {"Lebowski"}; - vkr.Prepare (); - string actual = vkr.Invoke () as string; - Assert.IsNotNull (actual); - Assert.AreEqual ("Hi Lebowski", actual); - } + ArgumentConvertingMethodInvoker vkr = new ArgumentConvertingMethodInvoker(); + vkr.TargetObject = new Voker(); + vkr.TargetMethod = "Hi"; + vkr.Arguments = new object[] { "Rick, Mark, Griffin, Si, Choy, Aleks" }; + vkr.Prepare(); + string actual = vkr.Invoke() as string; + Assert.IsNotNull(actual); + Assert.AreEqual("Hi Rick, Mark, Griffin, Si, Choy, Aleks", actual); } - public sealed class Voker + [Test] + public void InvokeWithConversion() { - public Voker () : this ("HiroProtagonist") {} - - public Voker (string name) - { - this.name = name; - } - - public string Hi (string name) - { - return "Hi " + name; - } - - public string HiEverybody (string [] names) - { - developers = names; - return "Hi ya'll"; - } - - public static string HiVoker (Voker buddy) - { - return "Hi " + buddy.name; - } - - public string [] developers; - public string name; + ArgumentConvertingMethodInvoker vkr = new ArgumentConvertingMethodInvoker(); + Voker instance = new Voker(); + vkr.TargetObject = instance; + vkr.TargetMethod = "HiEverybody"; + // CSV string should be converted to string [] + vkr.Arguments = new object[] { "Rick, Mark, Griffin, Federico, Choy, Aleks" }; + vkr.Prepare(); + string actual = vkr.Invoke() as string; + Assert.IsNotNull(actual); + Assert.AreEqual("Hi ya'll", actual); + Assert.IsNotNull(instance.developers); } - public sealed class VokerConverter : System.ComponentModel.TypeConverter + [Test] + public void InvokeAllNamedArgumentsWithConversion() { - public override bool CanConvertFrom ( - System.ComponentModel.ITypeDescriptorContext context, Type sourceType) - { - if (sourceType == typeof (string)) - { - return true; - } - return base.CanConvertFrom (context, sourceType); - } + ArgumentConvertingMethodInvoker vkr = new ArgumentConvertingMethodInvoker(); + Voker instance = new Voker(); + vkr.TargetObject = instance; + vkr.TargetMethod = "HiEverybody"; + // CSV string should be converted to string [] + vkr.AddNamedArgument("nameS", new object[] { "Rick, Mark, Griffin, Federico, Choy, Aleks" }); + vkr.Prepare(); + string actual = vkr.Invoke() as string; + Assert.IsNotNull(actual); + Assert.AreEqual("Hi ya'll", actual); + Assert.IsNotNull(instance.developers); + } - public override object ConvertFrom ( - System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) - { - if (value is string) - { - return new Voker (value as string); - } - return base.ConvertFrom (context, culture, value); - } + [Test] + public void InvokeWithRegisteredConversion() + { + ArgumentConvertingMethodInvoker vkr = new ArgumentConvertingMethodInvoker(); + // see if custom registration filters thru... + vkr.RegisterCustomConverter(typeof(Voker), new VokerConverter()); + vkr.TargetType = typeof(Voker); + vkr.TargetMethod = "HiVoker"; + // arg should be converted to Voker + vkr.Arguments = new object[] { "Lebowski" }; + vkr.Prepare(); + string actual = vkr.Invoke() as string; + Assert.IsNotNull(actual); + Assert.AreEqual("Hi Lebowski", actual); + } +} + +public sealed class Voker +{ + public Voker() : this("HiroProtagonist") { } + + public Voker(string name) + { + this.name = name; + } + + public string Hi(string name) + { + return "Hi " + name; + } + + public string HiEverybody(string[] names) + { + developers = names; + return "Hi ya'll"; + } + + public static string HiVoker(Voker buddy) + { + return "Hi " + buddy.name; + } + + public string[] developers; + public string name; +} + +public sealed class VokerConverter : System.ComponentModel.TypeConverter +{ + public override bool CanConvertFrom( + System.ComponentModel.ITypeDescriptorContext context, Type sourceType) + { + if (sourceType == typeof(string)) + { + return true; + } + + return base.CanConvertFrom(context, sourceType); + } + + public override object ConvertFrom( + System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) + { + if (value is string) + { + return new Voker(value as string); + } + + return base.ConvertFrom(context, culture, value); } } diff --git a/test/Spring/Spring.Core.Tests/Objects/Support/AutoWiringEventHandlerValueTests.cs b/test/Spring/Spring.Core.Tests/Objects/Support/AutoWiringEventHandlerValueTests.cs index fc708919..39cfc1a7 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Support/AutoWiringEventHandlerValueTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Support/AutoWiringEventHandlerValueTests.cs @@ -24,313 +24,312 @@ using NUnit.Framework; #endregion -namespace Spring.Objects.Support +namespace Spring.Objects.Support; + +/// +/// Unit tests for the AutoWiringEventHandlerValue class. +/// +/// Rick Evans +[TestFixture] +public class AutoWiringEventHandlerValueTests { /// - /// Unit tests for the AutoWiringEventHandlerValue class. + /// Kinda defeats the purpose of the AutoWiringEventHandlerValue class, but + /// still a supported and legal option. /// - /// Rick Evans - [TestFixture] - public class AutoWiringEventHandlerValueTests + [Test] + public void AutowireExplicitly() { - /// - /// Kinda defeats the purpose of the AutoWiringEventHandlerValue class, but - /// still a supported and legal option. - /// - [Test] - public void AutowireExplicitly () + // create the event source, and a listener to wire to an event (s) on the source + PingSource source = new PingSource(); + PingListener listener = new PingListener(); + + // wire them up + IEventHandlerValue wirer = new AutoWiringEventHandlerValue(); + wirer.EventName = "Ping"; + wirer.MethodName = "OnPing"; + wirer.Wire(source, listener); + + // raise the event on the source + source.OnPing(); + + // ascertain that the event listener was indeed notified of the raised event + Assert.IsTrue(listener.GotPing, "The listener was not notified of the raised event."); + Assert.IsTrue(listener.PingCount == 1, "The listener was notified more than once for a single raising of the source event (registered to listen more than once?)"); + Assert.IsFalse(listener.GotPinging, "The listener was (incorrectly) notified of an event that wasn't raised."); + Assert.IsFalse(listener.GotPinged, "The listener was (incorrectly) notified of an event that wasn't raised."); + } + + [Test] + public void AutowireExplicitlyWithBadSignatureMethod() + { + // create the event source, and a listener to wire to an event (s) on the source + PingSource source = new PingSource(); + PingListener listener = new PingListener(); + + // wire them up + IEventHandlerValue wirer = new AutoWiringEventHandlerValue(); + wirer.EventName = "Ping"; + wirer.MethodName = "OnPinged"; // signature is incompatible + wirer.Wire(source, listener); + + // raise the event on the source + source.OnPing(); + + // ascertain that the event listener was not notified of the raised event + Assert.IsFalse(listener.GotPing, "The listener was (incorrectly) notified of the raised event."); + Assert.IsFalse(listener.GotPinging, "The listener was (incorrectly) notified of an event that wasn't raised."); + Assert.IsFalse(listener.GotPinged, "The listener was (incorrectly) notified of an event that wasn't raised."); + } + + [Test] + public void AutowireAllHandlersWithCompatibleSignatures() + { + // create the event source, and a listener to wire to an event (s) on the source + PingSource source = new PingSource(); + PingListener listener = new PingListener(); + + // wire them up (any methods on the listener that have a compatible signature will be wired up) + IEventHandlerValue wirer = new AutoWiringEventHandlerValue(); + wirer.EventName = "^Ping$"; + wirer.Wire(source, listener); + + // raise the event on the source + source.OnPing(); + + // ascertain that the event handler was indeed notified of the raised event + Assert.IsTrue(listener.GotPing, "The listener was not notified of the raised event."); + Assert.IsFalse(listener.GotPinging, "The listener was (incorrectly) notified of an event that wasn't raised."); + Assert.IsFalse(listener.GotPinged, "The listener was (incorrectly) notified of an event that wasn't raised."); + } + + [Test] + public void AutowireAllEventsOnSource() + { + // create the event source, and a listener to wire to an event (s) on the source + PingSource source = new PingSource(); + PingListener listener = new PingListener(); + + // wire them up (any methods on the listener that have a signature compatible + // with any event exposed on the source will be wired up) + IEventHandlerValue wirer = new AutoWiringEventHandlerValue(); + wirer.Wire(source, listener); + + // raise the event (s) on the source + source.OnPinging(); + source.OnPing(); + source.OnPinged(); + + // ascertain that the event listener was indeed notified of the raised event + Assert.IsTrue(listener.GotPinging, "The listener was not notified of the raised event."); + Assert.IsTrue(listener.GotPing, "The listener was not notified of the raised event."); + Assert.IsTrue(listener.GotPinged, "The listener was not notified of the raised event."); + } + + [Test] + public void AutowiringIsCaseInsensitive() + { + // create the event source, and a listener to wire to an event (s) on the source + PingSource source = new PingSource(); + PingListener listener = new PingListener(); + + // wire them up + IEventHandlerValue wirer = new AutoWiringEventHandlerValue(); + wirer.EventName = "pInG"; + wirer.MethodName = "onpiNg"; + wirer.Wire(source, listener); + + // raise the event (s) on the source + source.OnPing(); + + // ascertain that the event listener was indeed notified of the raised event + Assert.IsFalse(listener.GotPinging, "The listener was (incorrectly) notified of the raised event."); + Assert.IsTrue(listener.GotPing, "The listener was not notified of the raised event."); + Assert.IsFalse(listener.GotPinged, "The listener was (incorrectly) notified of the raised event."); + } + + [Test] + public void AllCompatibleSignaturesAreWired() + { + // create the event source, and a listener to wire to an event (s) on the source + PingSource source = new PingSource(); + PingListener listener = new PingListener(); + + // wire them up + IEventHandlerValue wirer = new AutoWiringEventHandlerValue(); + wirer.EventName = "Pinging"; + wirer.MethodName = ".+"; // both OnPinging and OnPinged have compatible sigs :'( + wirer.Wire(source, listener); + + // raise the event (s) on the source + source.OnPinging(); + + // ascertain that the event listener was indeed notified of the raised event + Assert.IsTrue(listener.GotPinging, "The listener was not notified of the raised event."); + Assert.IsFalse(listener.GotPing, "The listener was (incorrectly) notified of the raised event."); + // the moral of the story is... + // don't use greedy method name regex's for autowiring, be explicit + Assert.IsTrue(listener.GotPinged, "The listener was not notified of the raised event."); + } + + [Test] + public void TestDefaultMethodMatching() + { + // create the event source, and a listener to wire to an event (s) on the source + PingSource source = new PingSource(); + PingListener listener = new PerversePingListener(); + + // wire them up + IEventHandlerValue wirer = new AutoWiringEventHandlerValue(); + wirer.EventName = "^Ping$"; + wirer.MethodName = ".+${event}.+"; // matches 'WhatClubDoYouUsePingAhGood' + wirer.Wire(source, listener); + + // raise the event on the source + source.OnPing(); + + // ascertain that the event listener was not notified of the raised event + Assert.IsTrue(listener.GotPing, "The listener was not notified of the raised event."); + Assert.IsFalse(listener.GotPinging, "The listener was (incorrectly) notified of an event that wasn't raised."); + Assert.IsFalse(listener.GotPinged, "The listener was (incorrectly) notified of an event that wasn't raised."); + } +} + +internal class PingEventArgs : EventArgs +{ +} + +internal delegate bool PingEventHandler(object sender, PingEventArgs e); + +internal class PingSource +{ + public event EventHandler Pinging; + + public event PingEventHandler Ping; + + public event EventHandler Pinged; + + public void OnPinging() + { + if (Pinging != null) { - // create the event source, and a listener to wire to an event (s) on the source - PingSource source = new PingSource (); - PingListener listener = new PingListener (); - - // wire them up - IEventHandlerValue wirer = new AutoWiringEventHandlerValue (); - wirer.EventName = "Ping"; - wirer.MethodName = "OnPing"; - wirer.Wire (source, listener); - - // raise the event on the source - source.OnPing (); - - // ascertain that the event listener was indeed notified of the raised event - Assert.IsTrue (listener.GotPing, "The listener was not notified of the raised event."); - Assert.IsTrue (listener.PingCount == 1, "The listener was notified more than once for a single raising of the source event (registered to listen more than once?)"); - Assert.IsFalse (listener.GotPinging, "The listener was (incorrectly) notified of an event that wasn't raised."); - Assert.IsFalse (listener.GotPinged, "The listener was (incorrectly) notified of an event that wasn't raised."); - } - - [Test] - public void AutowireExplicitlyWithBadSignatureMethod () - { - // create the event source, and a listener to wire to an event (s) on the source - PingSource source = new PingSource (); - PingListener listener = new PingListener (); - - // wire them up - IEventHandlerValue wirer = new AutoWiringEventHandlerValue (); - wirer.EventName = "Ping"; - wirer.MethodName = "OnPinged"; // signature is incompatible - wirer.Wire (source, listener); - - // raise the event on the source - source.OnPing (); - - // ascertain that the event listener was not notified of the raised event - Assert.IsFalse (listener.GotPing, "The listener was (incorrectly) notified of the raised event."); - Assert.IsFalse (listener.GotPinging, "The listener was (incorrectly) notified of an event that wasn't raised."); - Assert.IsFalse (listener.GotPinged, "The listener was (incorrectly) notified of an event that wasn't raised."); - } - - [Test] - public void AutowireAllHandlersWithCompatibleSignatures () - { - // create the event source, and a listener to wire to an event (s) on the source - PingSource source = new PingSource (); - PingListener listener = new PingListener (); - - // wire them up (any methods on the listener that have a compatible signature will be wired up) - IEventHandlerValue wirer = new AutoWiringEventHandlerValue (); - wirer.EventName = "^Ping$"; - wirer.Wire (source, listener); - - // raise the event on the source - source.OnPing (); - - // ascertain that the event handler was indeed notified of the raised event - Assert.IsTrue (listener.GotPing, "The listener was not notified of the raised event."); - Assert.IsFalse (listener.GotPinging, "The listener was (incorrectly) notified of an event that wasn't raised."); - Assert.IsFalse (listener.GotPinged, "The listener was (incorrectly) notified of an event that wasn't raised."); - } - - [Test] - public void AutowireAllEventsOnSource () - { - // create the event source, and a listener to wire to an event (s) on the source - PingSource source = new PingSource (); - PingListener listener = new PingListener (); - - // wire them up (any methods on the listener that have a signature compatible - // with any event exposed on the source will be wired up) - IEventHandlerValue wirer = new AutoWiringEventHandlerValue (); - wirer.Wire (source, listener); - - // raise the event (s) on the source - source.OnPinging (); - source.OnPing (); - source.OnPinged (); - - // ascertain that the event listener was indeed notified of the raised event - Assert.IsTrue (listener.GotPinging, "The listener was not notified of the raised event."); - Assert.IsTrue (listener.GotPing, "The listener was not notified of the raised event."); - Assert.IsTrue (listener.GotPinged, "The listener was not notified of the raised event."); - } - - [Test] - public void AutowiringIsCaseInsensitive () - { - // create the event source, and a listener to wire to an event (s) on the source - PingSource source = new PingSource (); - PingListener listener = new PingListener (); - - // wire them up - IEventHandlerValue wirer = new AutoWiringEventHandlerValue (); - wirer.EventName = "pInG"; - wirer.MethodName = "onpiNg"; - wirer.Wire (source, listener); - - // raise the event (s) on the source - source.OnPing (); - - // ascertain that the event listener was indeed notified of the raised event - Assert.IsFalse (listener.GotPinging, "The listener was (incorrectly) notified of the raised event."); - Assert.IsTrue (listener.GotPing, "The listener was not notified of the raised event."); - Assert.IsFalse (listener.GotPinged, "The listener was (incorrectly) notified of the raised event."); - } - - [Test] - public void AllCompatibleSignaturesAreWired () - { - // create the event source, and a listener to wire to an event (s) on the source - PingSource source = new PingSource (); - PingListener listener = new PingListener (); - - // wire them up - IEventHandlerValue wirer = new AutoWiringEventHandlerValue (); - wirer.EventName = "Pinging"; - wirer.MethodName = ".+"; // both OnPinging and OnPinged have compatible sigs :'( - wirer.Wire (source, listener); - - // raise the event (s) on the source - source.OnPinging (); - - // ascertain that the event listener was indeed notified of the raised event - Assert.IsTrue (listener.GotPinging, "The listener was not notified of the raised event."); - Assert.IsFalse (listener.GotPing, "The listener was (incorrectly) notified of the raised event."); - // the moral of the story is... - // don't use greedy method name regex's for autowiring, be explicit - Assert.IsTrue (listener.GotPinged, "The listener was not notified of the raised event."); - } - - [Test] - public void TestDefaultMethodMatching () - { - // create the event source, and a listener to wire to an event (s) on the source - PingSource source = new PingSource (); - PingListener listener = new PerversePingListener (); - - // wire them up - IEventHandlerValue wirer = new AutoWiringEventHandlerValue (); - wirer.EventName = "^Ping$"; - wirer.MethodName = ".+${event}.+"; // matches 'WhatClubDoYouUsePingAhGood' - wirer.Wire (source, listener); - - // raise the event on the source - source.OnPing (); - - // ascertain that the event listener was not notified of the raised event - Assert.IsTrue (listener.GotPing, "The listener was not notified of the raised event."); - Assert.IsFalse (listener.GotPinging, "The listener was (incorrectly) notified of an event that wasn't raised."); - Assert.IsFalse (listener.GotPinged, "The listener was (incorrectly) notified of an event that wasn't raised."); + Pinging(this, EventArgs.Empty); } } - internal class PingEventArgs : EventArgs + public void OnPing() { - } - - internal delegate bool PingEventHandler (object sender, PingEventArgs e); - - internal class PingSource - { - public event EventHandler Pinging; - - public event PingEventHandler Ping; - - public event EventHandler Pinged; - - public void OnPinging () + if (Ping != null) { - if (Pinging != null) - { - Pinging (this, EventArgs.Empty); - } - } - - public void OnPing () - { - if (Ping != null) - { - Ping (this, new PingEventArgs ()); - } - } - - public void OnPinged () - { - if (Pinged != null) - { - Pinged (this, EventArgs.Empty); - } + Ping(this, new PingEventArgs()); } } - internal class PingListener + public void OnPinged() { - public void OnPinging (object sender, EventArgs e) + if (Pinged != null) { - _pinging = true; - ++_pingingCount; - } - - private bool OnPing (object sender, PingEventArgs e) - { - _ping = true; - ++_pingCount; - return true; - } - - public void OnPinged (object sender, EventArgs e) - { - _pinged = true; - ++_pingedCount; - } - - public bool GotPinging - { - get - { - return _pinging; - } - } - - public bool GotPing - { - get - { - return _ping; - } - } - - public bool GotPinged - { - get - { - return _pinged; - } - } - - public int PingingCount - { - get - { - return _pingingCount; - } - } - - public int PingCount - { - get - { - return _pingCount; - } - } - - public int PingedCount - { - get - { - return _pingedCount; - } - } - - protected bool _pinging; - protected bool _ping; - protected bool _pinged; - - protected int _pingingCount; - protected int _pingCount; - protected int _pingedCount; - } - - /// - /// Specialisation with obtuse names for listener methods. - /// - internal class PerversePingListener : PingListener - { - public void PingingListener (object sender, EventArgs e) - { - _pinging = true; - } - - public bool WhatClubDoYouUsePingAhGood (object sender, PingEventArgs e) - { - _ping = true; - return true; - } - - public void AHotDogImPingedOnMyLiason (object sender, EventArgs e) - { - _pinged = true; + Pinged(this, EventArgs.Empty); } } } + +internal class PingListener +{ + public void OnPinging(object sender, EventArgs e) + { + _pinging = true; + ++_pingingCount; + } + + private bool OnPing(object sender, PingEventArgs e) + { + _ping = true; + ++_pingCount; + return true; + } + + public void OnPinged(object sender, EventArgs e) + { + _pinged = true; + ++_pingedCount; + } + + public bool GotPinging + { + get + { + return _pinging; + } + } + + public bool GotPing + { + get + { + return _ping; + } + } + + public bool GotPinged + { + get + { + return _pinged; + } + } + + public int PingingCount + { + get + { + return _pingingCount; + } + } + + public int PingCount + { + get + { + return _pingCount; + } + } + + public int PingedCount + { + get + { + return _pingedCount; + } + } + + protected bool _pinging; + protected bool _ping; + protected bool _pinged; + + protected int _pingingCount; + protected int _pingCount; + protected int _pingedCount; +} + +/// +/// Specialisation with obtuse names for listener methods. +/// +internal class PerversePingListener : PingListener +{ + public void PingingListener(object sender, EventArgs e) + { + _pinging = true; + } + + public bool WhatClubDoYouUsePingAhGood(object sender, PingEventArgs e) + { + _ping = true; + return true; + } + + public void AHotDogImPingedOnMyLiason(object sender, EventArgs e) + { + _pinged = true; + } +} diff --git a/test/Spring/Spring.Core.Tests/Objects/Support/ByTypeSharedStateProviderTests.cs b/test/Spring/Spring.Core.Tests/Objects/Support/ByTypeSharedStateProviderTests.cs index 435bd29f..f2f2918b 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Support/ByTypeSharedStateProviderTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Support/ByTypeSharedStateProviderTests.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -24,15 +24,14 @@ using NUnit.Framework; #endregion -namespace Spring.Objects.Support +namespace Spring.Objects.Support; + +/// +/// +/// +/// Erich Eichinger +[TestFixture] +public class ByTypeSharedStateProviderTests { - /// - /// - /// - /// Erich Eichinger - [TestFixture] - public class ByTypeSharedStateProviderTests - { - // TODO - } -} \ No newline at end of file + // TODO +} diff --git a/test/Spring/Spring.Core.Tests/Objects/Support/InstanceEventHandlerValueTests.cs b/test/Spring/Spring.Core.Tests/Objects/Support/InstanceEventHandlerValueTests.cs index 79c48d3c..1f5a1c5c 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Support/InstanceEventHandlerValueTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Support/InstanceEventHandlerValueTests.cs @@ -24,57 +24,57 @@ using NUnit.Framework; #endregion -namespace Spring.Objects.Support +namespace Spring.Objects.Support; + +/// +/// Unit tests for the InstanceEventHandlerValue class. +/// +/// Rick Evans +[TestFixture] +public sealed class InstanceEventHandlerValueTests { - /// - /// Unit tests for the InstanceEventHandlerValue class. - /// - /// Rick Evans - [TestFixture] - public sealed class InstanceEventHandlerValueTests + [Test] + public void Instantiation() { - [Test] - public void Instantiation () - { - PingSource source = new PingSource (); - StaticEventHandlerValue wirer - = new StaticEventHandlerValue (source, "OnPing"); - Assert.IsNotNull (wirer.Source); - Assert.AreEqual ("OnPing", wirer.MethodName); - Assert.IsTrue (wirer.ToString ().IndexOf (wirer.MethodName) > 0); - } + PingSource source = new PingSource(); + StaticEventHandlerValue wirer + = new StaticEventHandlerValue(source, "OnPing"); + Assert.IsNotNull(wirer.Source); + Assert.AreEqual("OnPing", wirer.MethodName); + Assert.IsTrue(wirer.ToString().IndexOf(wirer.MethodName) > 0); + } - [Test] - public void Wire () { - InstanceEventHandlerValue wirer = new InstanceEventHandlerValue (); - wirer.EventName = "Ping"; - wirer.MethodName = "OnPing"; - PingSource source = new PingSource (); - PingListener sink = new PingListener (); - wirer.Wire (source, sink); - source.OnPing (); - Assert.IsTrue (sink.GotPing, "The event handler did not get notified when the event was raised."); - Assert.AreEqual (1, sink.PingCount, "The event handler was not get notified exactly once when the event was raised exactly once."); - } + [Test] + public void Wire() + { + InstanceEventHandlerValue wirer = new InstanceEventHandlerValue(); + wirer.EventName = "Ping"; + wirer.MethodName = "OnPing"; + PingSource source = new PingSource(); + PingListener sink = new PingListener(); + wirer.Wire(source, sink); + source.OnPing(); + Assert.IsTrue(sink.GotPing, "The event handler did not get notified when the event was raised."); + Assert.AreEqual(1, sink.PingCount, "The event handler was not get notified exactly once when the event was raised exactly once."); + } - [Test] - public void WireWithStaticHandler () - { - PingSource source = new PingSource (); - InstanceEventHandlerValue wirer - = new InstanceEventHandlerValue (source, "OnPing"); - wirer.EventName = "Ping"; - wirer.Wire (source, typeof (StaticPingListener)); - } + [Test] + public void WireWithStaticHandler() + { + PingSource source = new PingSource(); + InstanceEventHandlerValue wirer + = new InstanceEventHandlerValue(source, "OnPing"); + wirer.EventName = "Ping"; + wirer.Wire(source, typeof(StaticPingListener)); + } - [Test] - public void BailsIfMethodDoesntExist () - { - PingSource source = new PingSource (); - InstanceEventHandlerValue wirer - = new InstanceEventHandlerValue (source, "Roo"); - wirer.EventName = "Ping"; - Assert.Throws(() => wirer.Wire (source, typeof (StaticPingListener))); - } - } + [Test] + public void BailsIfMethodDoesntExist() + { + PingSource source = new PingSource(); + InstanceEventHandlerValue wirer + = new InstanceEventHandlerValue(source, "Roo"); + wirer.EventName = "Ping"; + Assert.Throws(() => wirer.Wire(source, typeof(StaticPingListener))); + } } diff --git a/test/Spring/Spring.Core.Tests/Objects/Support/MethodInvokerTests.cs b/test/Spring/Spring.Core.Tests/Objects/Support/MethodInvokerTests.cs index 3f42facd..dba238c8 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Support/MethodInvokerTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Support/MethodInvokerTests.cs @@ -25,299 +25,299 @@ using Spring.Core; #endregion -namespace Spring.Objects.Support +namespace Spring.Objects.Support; + +/// +/// Unit tests for the MethodInvoker class. +/// +/// Rick Evans +[TestFixture] +public sealed class MethodInvokerTests { - /// - /// Unit tests for the MethodInvoker class. - /// - /// Rick Evans - [TestFixture] - public sealed class MethodInvokerTests - { - [Test] - public void Instantiation() - { - MethodInvoker vkr = new MethodInvoker(); - Assert.IsNotNull(vkr.Arguments); - } + [Test] + public void Instantiation() + { + MethodInvoker vkr = new MethodInvoker(); + Assert.IsNotNull(vkr.Arguments); + } - [Test] - public void SettingNamedArgumentsToNullJustClearsOutAnyNamedArguments() - { - MethodInvoker vkr = new MethodInvoker(); - vkr.AddNamedArgument("age", 10); - vkr.NamedArguments = null; - Assert.IsNotNull(vkr.NamedArguments); - Assert.AreEqual(0, vkr.NamedArguments.Count); - } + [Test] + public void SettingNamedArgumentsToNullJustClearsOutAnyNamedArguments() + { + MethodInvoker vkr = new MethodInvoker(); + vkr.AddNamedArgument("age", 10); + vkr.NamedArguments = null; + Assert.IsNotNull(vkr.NamedArguments); + Assert.AreEqual(0, vkr.NamedArguments.Count); + } - [Test] - public void PrepareWithOnlyTargetMethodSet() - { - MethodInvoker vkr = new MethodInvoker(); - vkr.TargetMethod = "Foo"; - Assert.Throws(() => vkr.Prepare(), "One of either the 'TargetType' or 'TargetObject' properties is required."); - } + [Test] + public void PrepareWithOnlyTargetMethodSet() + { + MethodInvoker vkr = new MethodInvoker(); + vkr.TargetMethod = "Foo"; + Assert.Throws(() => vkr.Prepare(), "One of either the 'TargetType' or 'TargetObject' properties is required."); + } - [Test] - public void ArgumentsProperty() - { - MethodInvoker vkr = new MethodInvoker(); - vkr.Arguments = null; - Assert.IsNotNull(vkr.Arguments); // should always be the empty object array, never null - Assert.AreEqual(0, vkr.Arguments.Length); - vkr.Arguments = new string[] {"Chank Pop"}; - Assert.AreEqual(1, vkr.Arguments.Length); - } + [Test] + public void ArgumentsProperty() + { + MethodInvoker vkr = new MethodInvoker(); + vkr.Arguments = null; + Assert.IsNotNull(vkr.Arguments); // should always be the empty object array, never null + Assert.AreEqual(0, vkr.Arguments.Length); + vkr.Arguments = new string[] { "Chank Pop" }; + Assert.AreEqual(1, vkr.Arguments.Length); + } - [Test] - public void InvokeWithStaticMethod() + [Test] + public void InvokeWithStaticMethod() + { + MethodInvoker mi = new MethodInvoker(); + mi.TargetType = typeof(Int32); + mi.TargetMethod = "Parse"; + mi.Arguments = new object[] { "27" }; + mi.Prepare(); + object actual = mi.Invoke(); + Assert.IsNotNull(actual); + Assert.AreEqual(typeof(int), actual.GetType()); + Assert.AreEqual(27, (int) actual); + } + + [Test] + public void InvokeWithGenericStaticMethod() + { + MethodInvoker mi = new MethodInvoker(); + mi.TargetType = typeof(Activator); + mi.TargetMethod = "CreateInstance"; + mi.Prepare(); + object actual = mi.Invoke(); + Assert.IsNotNull(actual); + Assert.AreEqual(typeof(TestObject), actual.GetType()); + } + + [Test] + public void InvokeWithOKArguments() + { + Foo foo = new Foo(); + foo.Age = 88; + MethodInvoker vkr = new MethodInvoker(); + vkr.TargetObject = foo; + vkr.TargetMethod = "GrowOlder"; + vkr.Arguments = new object[] { 10 }; + vkr.Prepare(); + object actual = vkr.Invoke(); + Assert.AreEqual(98, actual); + } + + [Test] + public void InvokeWithOKArgumentsAndMixedCaseMethodName() + { + Foo foo = new Foo(); + foo.Age = 88; + MethodInvoker vkr = new MethodInvoker(); + vkr.TargetObject = foo; + vkr.TargetMethod = "growolder"; + vkr.Arguments = new object[] { 10 }; + vkr.Prepare(); + object actual = vkr.Invoke(); + Assert.AreEqual(98, actual); + } + + [Test] + public void InvokeWithNamedArgument() + { + Foo foo = new Foo(); + foo.Age = 88; + MethodInvoker vkr = new MethodInvoker(); + vkr.TargetObject = foo; + vkr.TargetMethod = "growolder"; + vkr.AddNamedArgument("years", 10); + vkr.Prepare(); + object actual = vkr.Invoke(); + Assert.AreEqual(98, actual); + } + + [Test] + public void InvokeWithMixOfNamedAndPlainVanillaArguments() + { + int maximumAge = 95; + Foo foo = new Foo(); + foo.Age = 88; + MethodInvoker vkr = new MethodInvoker(); + vkr.TargetObject = foo; + vkr.TargetMethod = "GrowOlderUntilMaximumAgeReached"; + vkr.AddNamedArgument("years", 10); + vkr.Arguments = new object[] { maximumAge }; + vkr.Prepare(); + object actual = vkr.Invoke(); + Assert.AreEqual(maximumAge, actual); + } + + [Test] + public void InvokeWithMixOfNamedAndPlainVanillaArgumentsOfDifferingTypes() + { + int maximumAge = 95; + string expectedStatus = "Old Age Pensioner"; + Foo foo = new Foo(); + foo.Age = 88; + MethodInvoker vkr = new MethodInvoker(); + vkr.TargetObject = foo; + vkr.TargetMethod = "GrowOlderUntilMaximumAgeReachedAndSetStatusName"; + vkr.AddNamedArgument("years", 10); + vkr.AddNamedArgument("status", expectedStatus); + vkr.Arguments = new object[] { maximumAge }; + vkr.Prepare(); + object actual = vkr.Invoke(); + Assert.AreEqual(maximumAge, actual); + Assert.AreEqual(expectedStatus, foo.Status); + } + + [Test] + public void InvokeWithNamedArgumentThatDoesNotExist() + { + Foo foo = new Foo(); + foo.Age = 88; + MethodInvoker vkr = new MethodInvoker(); + vkr.TargetObject = foo; + vkr.TargetMethod = "growolder"; + vkr.AddNamedArgument("southpaw", 10); + Assert.Throws(() => vkr.Prepare(), "The named argument 'southpaw' could not be found on the 'GrowOlder' method of class [Spring.Objects.Support.MethodInvokerTests+Foo]."); + } + + /// + /// Tests CLS case insensitivity compliance... + /// + [Test] + public void InvokeWithWeIRdLyCasedNamedArgument() + { + Foo foo = new Foo(); + foo.Age = 88; + MethodInvoker vkr = new MethodInvoker(); + vkr.TargetObject = foo; + vkr.TargetMethod = "gROwOldeR"; + vkr.AddNamedArgument("YEarS", 10); + vkr.Prepare(); + object actual = vkr.Invoke(); + Assert.AreEqual(98, actual); + } + + [Test] + public void InvokeWithArgumentOfWrongType() + { + Foo foo = new Foo(); + foo.Age = 88; + MethodInvoker vkr = new MethodInvoker(); + vkr.TargetObject = foo; + vkr.TargetMethod = "growolder"; + vkr.AddNamedArgument("years", "Bingo"); + vkr.Prepare(); + Assert.Throws(() => vkr.Invoke(), "At least one of the arguments passed to this MethodInvoker was incompatible with the signature of the invoked method."); + } + + [Test] + public void NamedArgumentsOverwriteEachOther() + { + Foo foo = new Foo(); + foo.Age = 88; + MethodInvoker vkr = new MethodInvoker(); + vkr.TargetObject = foo; + vkr.TargetMethod = "growolder"; + vkr.AddNamedArgument("years", 10); + // this second setting must overwrite the first... + vkr.AddNamedArgument("years", 200); + vkr.Prepare(); + object actual = vkr.Invoke(); + Assert.IsFalse(98.Equals(actual), "The first named argument setter is sticking; must allow itslf to be overwritten."); + Assert.AreEqual(288, actual, "The second named argument was not applied (it must be)."); + } + + [Test] + public void PreparedArgumentsIsNeverNull() + { + MyMethodInvoker vkr = new MyMethodInvoker(); + Assert.IsNotNull(vkr.GetPreparedArguments(), + "PreparedArguments is null even before Prepare() is called; must NEVER be null."); + vkr.NullOutPreparedArguments(); + Assert.IsNotNull(vkr.GetPreparedArguments(), + "PreparedArguments should revert to the empty object[] when set to null; must NEVER be null."); + } + + #region Inner Class : Foo + + private sealed class Foo + { + public Foo() { - MethodInvoker mi = new MethodInvoker(); - mi.TargetType = typeof(Int32); - mi.TargetMethod = "Parse"; - mi.Arguments = new object[] { "27" }; - mi.Prepare(); - object actual = mi.Invoke(); - Assert.IsNotNull(actual); - Assert.AreEqual(typeof(int), actual.GetType()); - Assert.AreEqual(27, (int)actual); + Age = 0; + Status = "Baby"; } - [Test] - public void InvokeWithGenericStaticMethod() + public int GrowOlder() { - MethodInvoker mi = new MethodInvoker(); - mi.TargetType = typeof(Activator); - mi.TargetMethod = "CreateInstance"; - mi.Prepare(); - object actual = mi.Invoke(); - Assert.IsNotNull(actual); - Assert.AreEqual(typeof(TestObject), actual.GetType()); + return GrowOlder(1); } - [Test] - public void InvokeWithOKArguments() - { - Foo foo = new Foo(); - foo.Age = 88; - MethodInvoker vkr = new MethodInvoker(); - vkr.TargetObject = foo; - vkr.TargetMethod = "GrowOlder"; - vkr.Arguments = new object[] {10}; - vkr.Prepare(); - object actual = vkr.Invoke(); - Assert.AreEqual(98, actual); - } + public int GrowOlder(int years) + { + _age += years; + return _age; + } - [Test] - public void InvokeWithOKArgumentsAndMixedCaseMethodName() - { - Foo foo = new Foo(); - foo.Age = 88; - MethodInvoker vkr = new MethodInvoker(); - vkr.TargetObject = foo; - vkr.TargetMethod = "growolder"; - vkr.Arguments = new object[] {10}; - vkr.Prepare(); - object actual = vkr.Invoke(); - Assert.AreEqual(98, actual); - } + public int GrowOlderUntilMaximumAgeReached(int years, int maximumAge) + { + _age += years; + if (_age > maximumAge) + { + _age = maximumAge; + } - [Test] - public void InvokeWithNamedArgument() - { - Foo foo = new Foo(); - foo.Age = 88; - MethodInvoker vkr = new MethodInvoker(); - vkr.TargetObject = foo; - vkr.TargetMethod = "growolder"; - vkr.AddNamedArgument("years", 10); - vkr.Prepare(); - object actual = vkr.Invoke(); - Assert.AreEqual(98, actual); - } + return _age; + } - [Test] - public void InvokeWithMixOfNamedAndPlainVanillaArguments() - { - int maximumAge = 95; - Foo foo = new Foo(); - foo.Age = 88; - MethodInvoker vkr = new MethodInvoker(); - vkr.TargetObject = foo; - vkr.TargetMethod = "GrowOlderUntilMaximumAgeReached"; - vkr.AddNamedArgument("years", 10); - vkr.Arguments = new object[] {maximumAge}; - vkr.Prepare(); - object actual = vkr.Invoke(); - Assert.AreEqual(maximumAge, actual); - } + public int GrowOlderUntilMaximumAgeReachedAndSetStatusName( + int years, int maximumAge, string status) + { + Status = status; + return GrowOlderUntilMaximumAgeReached(years, maximumAge); + } - [Test] - public void InvokeWithMixOfNamedAndPlainVanillaArgumentsOfDifferingTypes() - { - int maximumAge = 95; - string expectedStatus = "Old Age Pensioner"; - Foo foo = new Foo(); - foo.Age = 88; - MethodInvoker vkr = new MethodInvoker(); - vkr.TargetObject = foo; - vkr.TargetMethod = "GrowOlderUntilMaximumAgeReachedAndSetStatusName"; - vkr.AddNamedArgument("years", 10); - vkr.AddNamedArgument("status", expectedStatus); - vkr.Arguments = new object[] {maximumAge}; - vkr.Prepare(); - object actual = vkr.Invoke(); - Assert.AreEqual(maximumAge, actual); - Assert.AreEqual(expectedStatus, foo.Status); - } + private int _age; + private string _status; - [Test] - public void InvokeWithNamedArgumentThatDoesNotExist() - { - Foo foo = new Foo(); - foo.Age = 88; - MethodInvoker vkr = new MethodInvoker(); - vkr.TargetObject = foo; - vkr.TargetMethod = "growolder"; - vkr.AddNamedArgument("southpaw", 10); - Assert.Throws(() => vkr.Prepare(), "The named argument 'southpaw' could not be found on the 'GrowOlder' method of class [Spring.Objects.Support.MethodInvokerTests+Foo]."); - } + public int Age + { + get { return _age; } + set { _age = value; } + } - /// - /// Tests CLS case insensitivity compliance... - /// - [Test] - public void InvokeWithWeIRdLyCasedNamedArgument() - { - Foo foo = new Foo(); - foo.Age = 88; - MethodInvoker vkr = new MethodInvoker(); - vkr.TargetObject = foo; - vkr.TargetMethod = "gROwOldeR"; - vkr.AddNamedArgument("YEarS", 10); - vkr.Prepare(); - object actual = vkr.Invoke(); - Assert.AreEqual(98, actual); - } + public string Status + { + get { return _status; } + set { _status = value; } + } + } - [Test] - public void InvokeWithArgumentOfWrongType() - { - Foo foo = new Foo(); - foo.Age = 88; - MethodInvoker vkr = new MethodInvoker(); - vkr.TargetObject = foo; - vkr.TargetMethod = "growolder"; - vkr.AddNamedArgument("years", "Bingo"); - vkr.Prepare(); - Assert.Throws(() => vkr.Invoke(), "At least one of the arguments passed to this MethodInvoker was incompatible with the signature of the invoked method."); - } + #endregion - [Test] - public void NamedArgumentsOverwriteEachOther() - { - Foo foo = new Foo(); - foo.Age = 88; - MethodInvoker vkr = new MethodInvoker(); - vkr.TargetObject = foo; - vkr.TargetMethod = "growolder"; - vkr.AddNamedArgument("years", 10); - // this second setting must overwrite the first... - vkr.AddNamedArgument("years", 200); - vkr.Prepare(); - object actual = vkr.Invoke(); - Assert.IsFalse(98.Equals(actual), "The first named argument setter is sticking; must allow itslf to be overwritten."); - Assert.AreEqual(288, actual, "The second named argument was not applied (it must be)."); - } + #region Inner Class : MyMethodInvoker - [Test] - public void PreparedArgumentsIsNeverNull() - { - MyMethodInvoker vkr = new MyMethodInvoker(); - Assert.IsNotNull(vkr.GetPreparedArguments(), - "PreparedArguments is null even before Prepare() is called; must NEVER be null."); - vkr.NullOutPreparedArguments(); - Assert.IsNotNull(vkr.GetPreparedArguments(), - "PreparedArguments should revert to the empty object[] when set to null; must NEVER be null."); - } + private sealed class MyMethodInvoker : MethodInvoker + { + public MyMethodInvoker() + { + } - #region Inner Class : Foo + public void NullOutPreparedArguments() + { + PreparedArguments = null; + } - private sealed class Foo - { - public Foo() - { - Age = 0; - Status = "Baby"; - } + public object[] GetPreparedArguments() + { + return PreparedArguments; + } + } - public int GrowOlder() - { - return GrowOlder(1); - } - - public int GrowOlder(int years) - { - _age += years; - return _age; - } - - public int GrowOlderUntilMaximumAgeReached(int years, int maximumAge) - { - _age += years; - if (_age > maximumAge) - { - _age = maximumAge; - } - return _age; - } - - public int GrowOlderUntilMaximumAgeReachedAndSetStatusName( - int years, int maximumAge, string status) - { - Status = status; - return GrowOlderUntilMaximumAgeReached(years, maximumAge); - } - - private int _age; - private string _status; - - public int Age - { - get { return _age; } - set { _age = value; } - } - - public string Status - { - get { return _status; } - set { _status = value; } - } - } - - #endregion - - #region Inner Class : MyMethodInvoker - - private sealed class MyMethodInvoker : MethodInvoker - { - public MyMethodInvoker() - { - } - - public void NullOutPreparedArguments() - { - PreparedArguments = null; - } - - public object[] GetPreparedArguments() - { - return PreparedArguments; - } - } - - #endregion - } -} \ No newline at end of file + #endregion +} diff --git a/test/Spring/Spring.Core.Tests/Objects/Support/MutableSortDefinitionTests.cs b/test/Spring/Spring.Core.Tests/Objects/Support/MutableSortDefinitionTests.cs index 17666c79..ed198635 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Support/MutableSortDefinitionTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Support/MutableSortDefinitionTests.cs @@ -24,69 +24,72 @@ using NUnit.Framework; #endregion -namespace Spring.Objects.Support +namespace Spring.Objects.Support; + +/// +/// Unit tests for the MutableSortDefinition class. +/// +/// Rick Evans +[TestFixture] +public sealed class MutableSortDefinitionTests { - /// - /// Unit tests for the MutableSortDefinition class. - /// - /// Rick Evans - [TestFixture] - public sealed class MutableSortDefinitionTests + [Test] + public void Instantiation() { - [Test] - public void Instantiation () { - MutableSortDefinition def = new MutableSortDefinition (); - Assert.IsTrue (def.IgnoreCase); - Assert.IsTrue (def.Ascending); - Assert.IsNotNull (def.Property); - } + MutableSortDefinition def = new MutableSortDefinition(); + Assert.IsTrue(def.IgnoreCase); + Assert.IsTrue(def.Ascending); + Assert.IsNotNull(def.Property); + } - [Test] - public void InstantiationWithCopy () { - ISortDefinition copy = new MutableSortDefinition ("Bing!", false, false); - MutableSortDefinition def = new MutableSortDefinition (copy); - Assert.IsFalse (def.IgnoreCase); - Assert.IsFalse (def.Ascending); - Assert.IsNotNull (def.Property); - Assert.AreEqual (copy.Property, def.Property); - } + [Test] + public void InstantiationWithCopy() + { + ISortDefinition copy = new MutableSortDefinition("Bing!", false, false); + MutableSortDefinition def = new MutableSortDefinition(copy); + Assert.IsFalse(def.IgnoreCase); + Assert.IsFalse(def.Ascending); + Assert.IsNotNull(def.Property); + Assert.AreEqual(copy.Property, def.Property); + } - [Test] - public void TestEquals () { - ISortDefinition copy = new MutableSortDefinition ("Rab", false, false); - MutableSortDefinition def = new MutableSortDefinition ("Bing!", false, false); - def.Property = "Rab"; - Assert.AreEqual (copy, def); - Assert.AreEqual (copy.GetHashCode (), def.GetHashCode ()); - Assert.IsFalse (def.Equals (null)); - } + [Test] + public void TestEquals() + { + ISortDefinition copy = new MutableSortDefinition("Rab", false, false); + MutableSortDefinition def = new MutableSortDefinition("Bing!", false, false); + def.Property = "Rab"; + Assert.AreEqual(copy, def); + Assert.AreEqual(copy.GetHashCode(), def.GetHashCode()); + Assert.IsFalse(def.Equals(null)); + } - [Test] - public void PropertySetter () { - MutableSortDefinition def = new MutableSortDefinition (); - def.Property = null; - Assert.IsNotNull (def.Property); - Assert.AreEqual (string.Empty, def.Property); - } + [Test] + public void PropertySetter() + { + MutableSortDefinition def = new MutableSortDefinition(); + def.Property = null; + Assert.IsNotNull(def.Property); + Assert.AreEqual(string.Empty, def.Property); + } - [Test] - public void TogglesOkWhenPropertyIsSetAgain () - { - MutableSortDefinition def = new MutableSortDefinition (true); - bool originalAscendingValue = def.Ascending; - def.Property = "Name"; - def.Property = "Name"; // sort order should (must!) be reversed now... - Assert.IsFalse (def.Ascending == originalAscendingValue); - } + [Test] + public void TogglesOkWhenPropertyIsSetAgain() + { + MutableSortDefinition def = new MutableSortDefinition(true); + bool originalAscendingValue = def.Ascending; + def.Property = "Name"; + def.Property = "Name"; // sort order should (must!) be reversed now... + Assert.IsFalse(def.Ascending == originalAscendingValue); + } - [Test] - public void DoesNotTogglesWhenPropertyIsSetAgain () - { - MutableSortDefinition def = new MutableSortDefinition (true); - bool originalAscendingValue = def.Ascending; - def.Property = "Name"; - def.Property = "Age"; // sort order must not be toggled (different property) - Assert.IsTrue (def.Ascending == originalAscendingValue); - } + [Test] + public void DoesNotTogglesWhenPropertyIsSetAgain() + { + MutableSortDefinition def = new MutableSortDefinition(true); + bool originalAscendingValue = def.Ascending; + def.Property = "Name"; + def.Property = "Age"; // sort order must not be toggled (different property) + Assert.IsTrue(def.Ascending == originalAscendingValue); } } diff --git a/test/Spring/Spring.Core.Tests/Objects/Support/PropertyComparatorTests.cs b/test/Spring/Spring.Core.Tests/Objects/Support/PropertyComparatorTests.cs index 4cef329d..73a5c411 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Support/PropertyComparatorTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Support/PropertyComparatorTests.cs @@ -25,193 +25,191 @@ using Spring.Core; #endregion -namespace Spring.Objects.Support +namespace Spring.Objects.Support; + +/// +/// Unit tests for the PropertyComparator class. +/// +/// +///

+/// The sort algorithm for arrays changed between versions 1.1 and 2.0 of the .NET +/// Framework. Hence there are two batches of tests in this suite, one for versions +/// 1.1 and 2.0 of the .NET Framework respectively. +///

+///
+/// Rick Evans +/// Michael Loll +[TestFixture] +public sealed class PropertyComparatorTests { - /// - /// Unit tests for the PropertyComparator class. - /// - /// - ///

- /// The sort algorithm for arrays changed between versions 1.1 and 2.0 of the .NET - /// Framework. Hence there are two batches of tests in this suite, one for versions - /// 1.1 and 2.0 of the .NET Framework respectively. - ///

- ///
- /// Rick Evans - /// Michael Loll - [TestFixture] - public sealed class PropertyComparatorTests + [Test] + public void InstantiationWithNullArgument() { - [Test] - public void InstantiationWithNullArgument() - { - Assert.Throws(() => new PropertyComparator(null)); - } - - [Test] - public void Compare() - { - ISortDefinition definition = new MutableSortDefinition("Age", false, true); - - PropertyComparator cmp = new PropertyComparator(definition); - TestObject one = new TestObject("Rick", 19); - TestObject two = new TestObject("Balzac", 205); - int actual = cmp.Compare(one, two); - Assert.IsTrue(actual < 0); // 19 is less than 205 - } - - [Test] - public void CompareNestedProperty() - { - ISortDefinition definition = new MutableSortDefinition("Lawyer.Company", true, true); - - PropertyComparator cmp = new PropertyComparator(definition); - TestObject one = new TestObject("Rick", 19); - one.Lawyer = new NestedTestObject("Gizajoab"); - TestObject two = new TestObject("Balzac", 205); - two.Lawyer = new NestedTestObject("Wallpaperer"); - int actual = cmp.Compare(one, two); - Assert.IsTrue(actual < 0); // Gizajoab is less than Wallpaperer - } - - [Test] - public void CompareWithNullProperty() - { - ISortDefinition definition = new MutableSortDefinition("Lawyer.Company", true, true); - - PropertyComparator cmp = new PropertyComparator(definition); - TestObject one = new TestObject("Rick", 19); - one.Lawyer = new NestedTestObject("Gizajoab"); - TestObject two = new TestObject("Balzac", 205); - // no Lawyer.Company property set on object two... - int actual = cmp.Compare(one, two); - Assert.IsTrue(actual > 0); // Gizajoab is greater than null - } - - [Test] - public void CompareWithNonExistantProperty() - { - ISortDefinition definition = new MutableSortDefinition("Deborahs.Banjo", true, true); - - PropertyComparator cmp = new PropertyComparator(definition); - TestObject one = new TestObject("Rick", 19); - TestObject two = new TestObject("Balzac", 205); - Assert.Throws(() => cmp.Compare(one, two)); - } - - [Test] - public void Sort() - { - ISortDefinition definition = new MutableSortDefinition("NAmE", true, true); - - TestObject one = new TestObject("Rick", 19); - TestObject two = new TestObject("Balzac", 205); - TestObject three = new TestObject("Jenny", 89); - TestObject[] actual = new TestObject[] {one, two, three}; - TestObject[] expected = new TestObject[] {two /*Balzac*/, three /*Jenny*/, one /*Rick*/}; - PropertyComparator.Sort(actual, definition); - for (int i = 0; i < actual.Length; ++i) - { - Assert.AreEqual(expected[i].Name, actual[i].Name); - } - } - - [Test] - public void SortInDescendingOrder() - { - ISortDefinition definition = new MutableSortDefinition("NAmE", true, false); - - TestObject one = new TestObject("Rick", 19); - TestObject two = new TestObject("Balzac", 205); - TestObject three = new TestObject("Jenny", 89); - TestObject[] actual = new TestObject[] {one, two, three}; - // Rick comes after Jenny comes after Balzac (descending sort order)... - TestObject[] expected = new TestObject[] {one /*Rick*/, three /*Jenny*/, two /*Balzac*/}; - PropertyComparator.Sort(actual, definition); - for (int i = 0; i < actual.Length; ++i) - { - Assert.AreEqual(expected[i].Name, actual[i].Name); - } - } - - [Test] -// [Ignore("Sort ordering is not preserved (unstable) with equal elements (c.f. System.Array.Sort (Array, IComparer)))")] - public void OrderingIsUnperturbedWithEqualProps() - { - ISortDefinition definition = new MutableSortDefinition("Age", false, true); - - TestObject one = new TestObject("Rick", 19); - TestObject two = new TestObject("Balzac", 19); - TestObject three = new TestObject("Jenny", 19); - TestObject[] actual = new TestObject[] {one, two, three}; - TestObject[] expected = new TestObject[] {one /*Rick*/, two /*Balzac*/, three /*Jenny*/}; - PropertyComparator.Sort(actual, definition); - for (int i = 0; i < actual.Length; ++i) - { - Assert.AreEqual(expected[i].Name, actual[i].Name); - } - } - - [Test] - public void SortWithNullDefinition() - { - Assert.Throws(() => PropertyComparator.Sort(Type.EmptyTypes, null)); - } - - [Test] - public void CompareWithNullArguments() - { - ISortDefinition definition = new MutableSortDefinition("Nails", false, true); - - Funk one = new Funk(1, "long"); - PropertyComparator cmp = new PropertyComparator(definition); - Assert.AreEqual(0, cmp.Compare(null, null)); - // nulls are always last (i.e. greater than) - Assert.AreEqual(1, cmp.Compare(null, one)); - // any non-null instance comes before null (i.e. less than). - Assert.AreEqual(-1, cmp.Compare(one, null)); - } - - /// - /// Validates that a PropertyComparator can return its internal ISortDefinition - /// to a consumer for use. - /// - [Test(Description = "SPRNET-171")] - public void CanGetSortDefinition() - { - ISortDefinition definition = new MutableSortDefinition("Age", false, true); - - PropertyComparator cmp = new PropertyComparator(definition); - ISortDefinition sortDefinition = cmp.SortDefinition; - - Assert.AreSame(definition, sortDefinition); - Assert.AreEqual(definition.Property, sortDefinition.Property); - Assert.AreEqual(definition.Ascending, sortDefinition.Ascending); - Assert.AreEqual(definition.IgnoreCase, sortDefinition.IgnoreCase); - } - - internal sealed class Funk - { - public Funk(int id, string nails) - { - _id = id; - _nails = nails; - } - - private string _nails; - private int _id; - - public string Nails - { - get { return _nails; } - } - - public int Id - { - get { return _id; } - set { _id = value; } - } - } - + Assert.Throws(() => new PropertyComparator(null)); } -} \ No newline at end of file + + [Test] + public void Compare() + { + ISortDefinition definition = new MutableSortDefinition("Age", false, true); + + PropertyComparator cmp = new PropertyComparator(definition); + TestObject one = new TestObject("Rick", 19); + TestObject two = new TestObject("Balzac", 205); + int actual = cmp.Compare(one, two); + Assert.IsTrue(actual < 0); // 19 is less than 205 + } + + [Test] + public void CompareNestedProperty() + { + ISortDefinition definition = new MutableSortDefinition("Lawyer.Company", true, true); + + PropertyComparator cmp = new PropertyComparator(definition); + TestObject one = new TestObject("Rick", 19); + one.Lawyer = new NestedTestObject("Gizajoab"); + TestObject two = new TestObject("Balzac", 205); + two.Lawyer = new NestedTestObject("Wallpaperer"); + int actual = cmp.Compare(one, two); + Assert.IsTrue(actual < 0); // Gizajoab is less than Wallpaperer + } + + [Test] + public void CompareWithNullProperty() + { + ISortDefinition definition = new MutableSortDefinition("Lawyer.Company", true, true); + + PropertyComparator cmp = new PropertyComparator(definition); + TestObject one = new TestObject("Rick", 19); + one.Lawyer = new NestedTestObject("Gizajoab"); + TestObject two = new TestObject("Balzac", 205); + // no Lawyer.Company property set on object two... + int actual = cmp.Compare(one, two); + Assert.IsTrue(actual > 0); // Gizajoab is greater than null + } + + [Test] + public void CompareWithNonExistantProperty() + { + ISortDefinition definition = new MutableSortDefinition("Deborahs.Banjo", true, true); + + PropertyComparator cmp = new PropertyComparator(definition); + TestObject one = new TestObject("Rick", 19); + TestObject two = new TestObject("Balzac", 205); + Assert.Throws(() => cmp.Compare(one, two)); + } + + [Test] + public void Sort() + { + ISortDefinition definition = new MutableSortDefinition("NAmE", true, true); + + TestObject one = new TestObject("Rick", 19); + TestObject two = new TestObject("Balzac", 205); + TestObject three = new TestObject("Jenny", 89); + TestObject[] actual = new TestObject[] { one, two, three }; + TestObject[] expected = new TestObject[] { two /*Balzac*/, three /*Jenny*/, one /*Rick*/ }; + PropertyComparator.Sort(actual, definition); + for (int i = 0; i < actual.Length; ++i) + { + Assert.AreEqual(expected[i].Name, actual[i].Name); + } + } + + [Test] + public void SortInDescendingOrder() + { + ISortDefinition definition = new MutableSortDefinition("NAmE", true, false); + + TestObject one = new TestObject("Rick", 19); + TestObject two = new TestObject("Balzac", 205); + TestObject three = new TestObject("Jenny", 89); + TestObject[] actual = new TestObject[] { one, two, three }; + // Rick comes after Jenny comes after Balzac (descending sort order)... + TestObject[] expected = new TestObject[] { one /*Rick*/, three /*Jenny*/, two /*Balzac*/ }; + PropertyComparator.Sort(actual, definition); + for (int i = 0; i < actual.Length; ++i) + { + Assert.AreEqual(expected[i].Name, actual[i].Name); + } + } + + [Test] +// [Ignore("Sort ordering is not preserved (unstable) with equal elements (c.f. System.Array.Sort (Array, IComparer)))")] + public void OrderingIsUnperturbedWithEqualProps() + { + ISortDefinition definition = new MutableSortDefinition("Age", false, true); + + TestObject one = new TestObject("Rick", 19); + TestObject two = new TestObject("Balzac", 19); + TestObject three = new TestObject("Jenny", 19); + TestObject[] actual = new TestObject[] { one, two, three }; + TestObject[] expected = new TestObject[] { one /*Rick*/, two /*Balzac*/, three /*Jenny*/ }; + PropertyComparator.Sort(actual, definition); + for (int i = 0; i < actual.Length; ++i) + { + Assert.AreEqual(expected[i].Name, actual[i].Name); + } + } + + [Test] + public void SortWithNullDefinition() + { + Assert.Throws(() => PropertyComparator.Sort(Type.EmptyTypes, null)); + } + + [Test] + public void CompareWithNullArguments() + { + ISortDefinition definition = new MutableSortDefinition("Nails", false, true); + + Funk one = new Funk(1, "long"); + PropertyComparator cmp = new PropertyComparator(definition); + Assert.AreEqual(0, cmp.Compare(null, null)); + // nulls are always last (i.e. greater than) + Assert.AreEqual(1, cmp.Compare(null, one)); + // any non-null instance comes before null (i.e. less than). + Assert.AreEqual(-1, cmp.Compare(one, null)); + } + + /// + /// Validates that a PropertyComparator can return its internal ISortDefinition + /// to a consumer for use. + /// + [Test(Description = "SPRNET-171")] + public void CanGetSortDefinition() + { + ISortDefinition definition = new MutableSortDefinition("Age", false, true); + + PropertyComparator cmp = new PropertyComparator(definition); + ISortDefinition sortDefinition = cmp.SortDefinition; + + Assert.AreSame(definition, sortDefinition); + Assert.AreEqual(definition.Property, sortDefinition.Property); + Assert.AreEqual(definition.Ascending, sortDefinition.Ascending); + Assert.AreEqual(definition.IgnoreCase, sortDefinition.IgnoreCase); + } + + internal sealed class Funk + { + public Funk(int id, string nails) + { + _id = id; + _nails = nails; + } + + private string _nails; + private int _id; + + public string Nails + { + get { return _nails; } + } + + public int Id + { + get { return _id; } + set { _id = value; } + } + } +} diff --git a/test/Spring/Spring.Core.Tests/Objects/Support/StaticEventHandlerValueTests.cs b/test/Spring/Spring.Core.Tests/Objects/Support/StaticEventHandlerValueTests.cs index a98af3f0..0a4984a0 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Support/StaticEventHandlerValueTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Support/StaticEventHandlerValueTests.cs @@ -24,72 +24,76 @@ using NUnit.Framework; #endregion -namespace Spring.Objects.Support +namespace Spring.Objects.Support; + +/// +/// Unit tests for the StaticEventHandlerValue class. +/// +/// Rick Evans +[TestFixture] +public sealed class StaticEventHandlerValueTests { - /// - /// Unit tests for the StaticEventHandlerValue class. - /// - /// Rick Evans - [TestFixture] - public sealed class StaticEventHandlerValueTests + [Test] + public void Instantiation() { - [Test] - public void Instantiation () - { - PingSource source = new PingSource (); - StaticEventHandlerValue wirer - = new StaticEventHandlerValue (source, "OnPing"); - Assert.IsNotNull (wirer.Source); - Assert.AreEqual ("OnPing", wirer.MethodName); - Assert.IsTrue (wirer.ToString ().IndexOf (wirer.MethodName) > 0); - } + PingSource source = new PingSource(); + StaticEventHandlerValue wirer + = new StaticEventHandlerValue(source, "OnPing"); + Assert.IsNotNull(wirer.Source); + Assert.AreEqual("OnPing", wirer.MethodName); + Assert.IsTrue(wirer.ToString().IndexOf(wirer.MethodName) > 0); + } - [Test] - public void Wire () - { - PingSource source = new PingSource (); - StaticEventHandlerValue wirer - = new StaticEventHandlerValue (source, "OnPing"); - wirer.EventName = "Ping"; - Type sink = typeof (StaticPingListener); - wirer.Wire (source, sink); - source.OnPing (); - Assert.IsTrue (StaticPingListener.GotPing, "The event handler did not get notified when the event was raised."); - Assert.AreEqual (1, StaticPingListener.PingCount, "The event handler was not get notified exactly once when the event was raised exactly once."); - } + [Test] + public void Wire() + { + PingSource source = new PingSource(); + StaticEventHandlerValue wirer + = new StaticEventHandlerValue(source, "OnPing"); + wirer.EventName = "Ping"; + Type sink = typeof(StaticPingListener); + wirer.Wire(source, sink); + source.OnPing(); + Assert.IsTrue(StaticPingListener.GotPing, "The event handler did not get notified when the event was raised."); + Assert.AreEqual(1, StaticPingListener.PingCount, "The event handler was not get notified exactly once when the event was raised exactly once."); + } - [Test] - public void WireWithInstanceHandler () - { - StaticEventHandlerValue wirer = new StaticEventHandlerValue (); - wirer.EventName = "Ping"; - wirer.MethodName = "OnPing"; - PingSource source = new PingSource (); - Assert.Throws(() => wirer.Wire (source, new PingListener ())); - } - } - - internal class StaticPingListener { - - public static bool OnPing (object sender, PingEventArgs e) { - _ping = true; - ++_pingCount; - return true; - } - - public static bool GotPing { - get { - return _ping; - } - } - - public static int PingCount { - get { - return _pingCount; - } - } - - protected static bool _ping; - protected static int _pingCount; + [Test] + public void WireWithInstanceHandler() + { + StaticEventHandlerValue wirer = new StaticEventHandlerValue(); + wirer.EventName = "Ping"; + wirer.MethodName = "OnPing"; + PingSource source = new PingSource(); + Assert.Throws(() => wirer.Wire(source, new PingListener())); } } + +internal class StaticPingListener +{ + public static bool OnPing(object sender, PingEventArgs e) + { + _ping = true; + ++_pingCount; + return true; + } + + public static bool GotPing + { + get + { + return _ping; + } + } + + public static int PingCount + { + get + { + return _pingCount; + } + } + + protected static bool _ping; + protected static int _pingCount; +} \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/Objects/TestEventHandler.cs b/test/Spring/Spring.Core.Tests/Objects/TestEventHandler.cs index f6b0a102..4cb74aa2 100644 --- a/test/Spring/Spring.Core.Tests/Objects/TestEventHandler.cs +++ b/test/Spring/Spring.Core.Tests/Objects/TestEventHandler.cs @@ -22,23 +22,22 @@ #endregion -namespace Spring.Objects { +namespace Spring.Objects; - internal class TestEventHandler +internal class TestEventHandler +{ + public virtual void HandleEvent(object sender, EventArgs e) { - public virtual void HandleEvent (object sender, EventArgs e) - { - _eventWasHandled = true; - } - - public virtual bool EventWasHandled - { - get - { - return _eventWasHandled; - } - } - - protected bool _eventWasHandled; + _eventWasHandled = true; } + + public virtual bool EventWasHandled + { + get + { + return _eventWasHandled; + } + } + + protected bool _eventWasHandled; } diff --git a/test/Spring/Spring.Core.Tests/Objects/TestGenericObject.cs b/test/Spring/Spring.Core.Tests/Objects/TestGenericObject.cs index a7fff077..d429d4cc 100644 --- a/test/Spring/Spring.Core.Tests/Objects/TestGenericObject.cs +++ b/test/Spring/Spring.Core.Tests/Objects/TestGenericObject.cs @@ -2,13 +2,13 @@ /* * Copyright 2002-2010 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. @@ -22,82 +22,81 @@ #endregion -namespace Spring.Objects +namespace Spring.Objects; + +/// +/// Simple test object used for testing generic objects. +/// +/// Bruno Baia +public class TestGenericObject { - /// - /// Simple test object used for testing generic objects. - /// - /// Bruno Baia - public class TestGenericObject - { - #region Fields + #region Fields - private int _id = 0; - private string _name = string.Empty; - private IList _someGenericList = new List(); - private IDictionary _someGenericDictionary = new Dictionary(); + private int _id = 0; + private string _name = string.Empty; + private IList _someGenericList = new List(); + private IDictionary _someGenericDictionary = new Dictionary(); - #endregion + #endregion - #region Properties + #region Properties - public int ID - { - get { return _id; } - set { _id = value; } - } - - public string Name - { - get { return _name; } - set { this._name = value; } - } - - public IList SomeGenericList - { - get { return _someGenericList; } - set { this._someGenericList = value; } - } - - public IDictionary SomeGenericDictionary - { - get { return _someGenericDictionary; } - set { this._someGenericDictionary = value; } - } - - #endregion - - #region Constructor (s) / Destructor - - public TestGenericObject() - { - } - - public TestGenericObject(int id) - { - this._id = id; - } - - public TestGenericObject(int id, string name) - { - this._id = id; - this._name = name; - } - - #endregion - - #region Methods - - public static List CreateList() - { - return new List(); - } - - public TestGenericObject CreateInstance() - { - return new TestGenericObject(); - } - - #endregion + public int ID + { + get { return _id; } + set { _id = value; } } + + public string Name + { + get { return _name; } + set { this._name = value; } + } + + public IList SomeGenericList + { + get { return _someGenericList; } + set { this._someGenericList = value; } + } + + public IDictionary SomeGenericDictionary + { + get { return _someGenericDictionary; } + set { this._someGenericDictionary = value; } + } + + #endregion + + #region Constructor (s) / Destructor + + public TestGenericObject() + { + } + + public TestGenericObject(int id) + { + this._id = id; + } + + public TestGenericObject(int id, string name) + { + this._id = id; + this._name = name; + } + + #endregion + + #region Methods + + public static List CreateList() + { + return new List(); + } + + public TestGenericObject CreateInstance() + { + return new TestGenericObject(); + } + + #endregion } diff --git a/test/Spring/Spring.Core.Tests/Objects/TestObject.cs b/test/Spring/Spring.Core.Tests/Objects/TestObject.cs index cd855f95..f7e97f1d 100644 --- a/test/Spring/Spring.Core.Tests/Objects/TestObject.cs +++ b/test/Spring/Spring.Core.Tests/Objects/TestObject.cs @@ -1,12 +1,12 @@ /* * Copyright 2002-2010 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. @@ -25,637 +25,646 @@ using Spring.Collections; using Spring.Context; using Spring.Objects.Factory; -namespace Spring.Objects +namespace Spring.Objects; + +/// +/// Simple test object used for testing object factories, AOP framework etc. +/// +/// Rod Johnson +/// Mark Pollack (.NET) +public class TestObject : MarshalByRefObject, ITestObject, IObjectFactoryAware, IComparable, IOther, IApplicationContextAware, IObjectNameAware, IInitializingObject, ISharedStateAware { - /// - /// Simple test object used for testing object factories, AOP framework etc. - /// - /// Rod Johnson - /// Mark Pollack (.NET) - public class TestObject : MarshalByRefObject, ITestObject, IObjectFactoryAware, IComparable, IOther, IApplicationContextAware, IObjectNameAware, IInitializingObject, ISharedStateAware - { - public event EventHandler Click; + public event EventHandler Click; - public static event EventHandler StaticClick; + public static event EventHandler StaticClick; - /// - /// Public method to programmatically raise the Click event - /// while testing. - /// - public void OnClick() - { - if (Click != null) - { - Click(this, EventArgs.Empty); - } - } - - /// - /// Public method to programmatically raise the static - /// Click event while testing. - /// - public static void OnStaticClick() - { - if (TestObject.StaticClick != null) - { - TestObject.StaticClick(typeof (TestObject), EventArgs.Empty); - } - } - - public int ObjectNumber - { - get { return objectNumber; } - set { objectNumber = value; } - } - - // for use in ObjectWrapperTests.SetPropertyValuesFailsWhenSettingReadOnlyProperty - public int ReadOnlyObjectNumber + /// + /// Public method to programmatically raise the Click event + /// while testing. + /// + public void OnClick() + { + if (Click != null) { - get { return objectNumber; } + Click(this, EventArgs.Empty); } + } - public IndexedTestObject NestedIndexedObject - { - get { return nestedIndexedObject; } - set { nestedIndexedObject = value; } - } - - /// - /// Public Enumeration Property for FileMode. - /// - public FileMode FileMode - { - get { return FileModeEnum; } - set { FileModeEnum = value; } - } - - public IObjectFactory ObjectFactory - { - get { return objectFactory; } - set { objectFactory = value; } - } - - public CultureInfo MyCulture - { - get { return myCulture; } - set { myCulture = value; } - } - - public string Touchy - { - get { return touchy; } - set - { - if (value.IndexOf('.') != - 1) - { - throw new Exception("Can't contain a ."); - } - if (value.IndexOf(',') != - 1) - { - throw new FormatException("Number format exception: contains a ,"); - } - this.touchy = value; - } - } - - public bool PostProcessed - { - get { return postProcessed; } - - set { this.postProcessed = value; } - } - - public string Name - { - get { return name; } - set { this.name = value; } - } - - public string Nickname - { - get { return nickname; } - set { this.nickname = value; } - } - - public virtual int Age - { - get { return age; } - - set { this.age = value; } - } - - public virtual DateTime Date - { - get { return date; } - - set { this.date = value; } - } - - public virtual Single MyFloat - { - get { return myFloat; } - set { this.myFloat = value; } - } - - public virtual ITestObject Spouse - { - get { return spouse; } - set { this.spouse = value; } - } - - public virtual ITestObject Sibling - { - get { return sibling; } - set { this.sibling = value; } - } - - public virtual INestedTestObject Doctor - { - get { return doctor; } - set { this.doctor = value; } - } - - public virtual INestedTestObject Lawyer - { - get { return lawyer; } - set { this.lawyer = value; } - } - - public virtual NestedTestObject RealLawyer - { - get { return myRealLawyer; } - set { this.myRealLawyer = value; } - } - - /// - /// A collection of friends. - /// - public virtual ICollection Friends - { - get { return friends; } - set { this.friends = value; } - } - - /// - /// A read-only collection of pets. - /// - public virtual ICollection Pets - { - get { return pets; } - } - - public virtual TestObjectList TypedFriends - { - get { return typedFriends; } - set { typedFriends = value; } - } - - /// - /// A read-only map of periodic table values. - /// - public virtual IDictionary PeriodicTable - { - get { return periodicTable; } - } - - /// - /// A read-only set of computer names - /// - public virtual ISet Computers - { - get { return computers; } - } - - public virtual ISet SomeSet - { - get { return someSet; } - set { this.someSet = value; } - } - - public virtual string[] Hats - { - get { return hats; } - set { hats = value; } - } - - public virtual IDictionary SomeMap - { - get { return someMap; } - set { this.someMap = value; } - } - - public virtual IList SomeList - { - get { return someList; } - set { this.someList = value;} - } - - public virtual List SomeGenericStringList - { - get { return someGenericStringList; } - set { this.someGenericStringList = value; } - } - - private IList someGenericIListInt32; - public virtual IList SomeGenericIListInt32 - { - get { return someGenericIListInt32; } - set { someGenericIListInt32 = value; } - } - - private IDictionary someGenericIDictionaryStringInt32; - public virtual IDictionary SomeGenericIDictionaryStringInt32 - { - get { return someGenericIDictionaryStringInt32; } - set { someGenericIDictionaryStringInt32 = value; } - } - - private IEnumerable someGenericIEnumerableInt32; - public virtual IEnumerable SomeGenericIEnumerableInt32 - { - get { return someGenericIEnumerableInt32; } - set { someGenericIEnumerableInt32 = value; } - } - - public virtual NameValueCollection SomeNameValueCollection - { - get { return someNameValueCollection; } - set { this.someNameValueCollection = value;} - } - - protected virtual string HappyPlace - { - get { return _happyPlace; } - set { _happyPlace = value; } - } - - // used in reflective tests, so don't remove this property... - private string[] SamsoniteSuitcase - { - get { return _samsoniteSuitcase; } - set { _samsoniteSuitcase = value; } - } - - public Type ClassProperty - { - get { return classProperty; } - set { classProperty = value; } - } - - public IApplicationContext ApplicationContext - { - get { return applicationContext; } - set { applicationContext = value; } - } - - public string ObjectName - { - get { return objectName; } - set { objectName = value; } - } - - public int ExceptionMethodCallCount - { - get { return exceptionMethodCallCount; } - } - - public bool InitCompleted - { - get { return initCompleted; } - set { initCompleted = value; } - } - - public Size Size - { - get { return size; } - set { size = value;} - } - - public string this[int index] - { - get - { - if (index < 0 || index >= favoriteQuotes.Length) - { - throw new ArgumentException("Index out of range"); - } - return favoriteQuotes[index]; - } - set - { - if (index < 0 || index >= favoriteQuotes.Length) - { - throw new ArgumentException("index is out of range."); - } - favoriteQuotes[index] = value; - } - } - - private int exceptionMethodCallCount; - private int objectNumber = 0; - public FileMode FileModeEnum; - private IObjectFactory objectFactory; - private bool postProcessed; - private int age; - private string name; - private string nickname; - private ITestObject spouse; - private ITestObject sibling; - private string touchy; - private ICollection friends = new LinkedList(); - private TestObjectList typedFriends = new TestObjectList(); - private ICollection pets = new LinkedList(); - private IDictionary periodicTable = new Hashtable(); - - private string[] favoriteQuotes = new string[] - { - "He who ha-ha ho-ho", - "The quick brown fox jumped over the lazy dogs." - }; - - private Type classProperty; - private ISet computers = new HybridSet(); - private ISet someSet = new HybridSet(); - private IDictionary someMap = new Hashtable(); - private IList someList = new ArrayList(); - private DateTime date = DateTime.Now; - private Single myFloat = (float) 0.0; - private CultureInfo myCulture = CultureInfo.InvariantCulture; - private string[] hats = null; - private INestedTestObject doctor = new NestedTestObject(); - private INestedTestObject lawyer = new NestedTestObject(); - private NestedTestObject myRealLawyer = new NestedTestObject(); - private IndexedTestObject nestedIndexedObject; - private string _happyPlace = DefaultHappyPlace; - private string[] _samsoniteSuitcase = DefaultContentsOfTheSuitcase; - - public const string DefaultHappyPlace = "The_SeaBass_Diner"; - - public static readonly string[] DefaultContentsOfTheSuitcase - = new string[] {"John Pryor's 'Leaving On A Jet Plane' LP"}; - - private IApplicationContext applicationContext; - private string objectName; - private Size size; - private bool initCompleted; - - private IDictionary sharedState; - private NameValueCollection someNameValueCollection; - private List someGenericStringList; - - public TestObject() - { - } - - public TestObject(string name, int age) - { - this.name = name; - this.age = age; - } - - public TestObject(string name, int age, INestedTestObject doctor) - { - this.name = name; - this.age = age; - this.doctor = doctor; - } - - public TestObject(string name, int age, INestedTestObject doctor, INestedTestObject lawyer) - { - this.name = name; - this.age = age; - this.doctor = doctor; - this.lawyer = lawyer; - } - - public TestObject(ITestObject spouse) - { - this.spouse = spouse; - } - - public TestObject(IList someList) + /// + /// Public method to programmatically raise the static + /// Click event while testing. + /// + public static void OnStaticClick() + { + if (TestObject.StaticClick != null) { - this.someList = someList; + TestObject.StaticClick(typeof(TestObject), EventArgs.Empty); } + } - public TestObject(ISet someSet) + public int ObjectNumber + { + get { return objectNumber; } + set { objectNumber = value; } + } + + // for use in ObjectWrapperTests.SetPropertyValuesFailsWhenSettingReadOnlyProperty + public int ReadOnlyObjectNumber + { + get { return objectNumber; } + } + + public IndexedTestObject NestedIndexedObject + { + get { return nestedIndexedObject; } + set { nestedIndexedObject = value; } + } + + /// + /// Public Enumeration Property for FileMode. + /// + public FileMode FileMode + { + get { return FileModeEnum; } + set { FileModeEnum = value; } + } + + public IObjectFactory ObjectFactory + { + get { return objectFactory; } + set { objectFactory = value; } + } + + public CultureInfo MyCulture + { + get { return myCulture; } + set { myCulture = value; } + } + + public string Touchy + { + get { return touchy; } + set { - this.someSet = someSet; - } - - public TestObject(IDictionary someMap) - { - this.someMap = someMap; - } - - public TestObject(NameValueCollection someProps) - { - this.someNameValueCollection = someProps; - } - - public static TestObject Create(string name) - { - return new TestObject(name, 30); - } - - public void AfterPropertiesSet() - { - initCompleted = true; - } - - public void AddComputerName(string name) - { - if (computers == null) - { - computers = new HybridSet(); - } - computers.Add(name); - } - - public void AddPeriodicElement(string name, string element) - { - if (periodicTable == null) - { - periodicTable = new Hashtable(); - } - periodicTable.Add(name, element); - } - - public string GetNameWithHonorific(bool isFemale, params string[] lettersAfterName) - { - StringBuilder buffer = new StringBuilder(); - buffer.Append(isFemale ? "Ms " : "Mr "); - buffer.Append(Name); - buffer.Append(" "); - foreach (string letters in lettersAfterName) - { - buffer.Append(letters); - } - return buffer.ToString(); - } - - public override bool Equals(object other) - { - return Equals(this, other); - } - - new public static bool Equals(object @this, object other) - { - if (other == null || !(other is ITestObject)) - { - return false; - } - ITestObject tb2 = (ITestObject) other; - ITestObject tb1 = (ITestObject) @this; - if (tb2.Age != tb1.Age) - { - return false; - } - - if ((object) tb1.Name == null) - { - return (object) tb2.Name == null; - } - - if (!tb2.Name.Equals(tb1.Name)) - { - return false; - } - - return true; - } - - public override int GetHashCode() - { - return (name != null ? name.GetHashCode() : base.GetHashCode()); - } - - public virtual int CompareTo(object other) - { - if ((object) this.name != null && other is TestObject) - { - return String.CompareOrdinal(this.name, ((TestObject) other).name); - } - else - { - return 1; - } - } - - public virtual string GetDescription() - { - string s = "name=" + name + "; age=" + age + "; touchy=" + touchy; - s += ("; spouse={" + (spouse != null ? spouse.Name : null) + "}"); - return s; - } - - public override string ToString() - { - string s = "name=" + name + "; age=" + age + "; touchy=" + touchy; - s += ("; spouse={" + (spouse != null ? spouse.Name : null) + "}"); - return s; - } - - //Used in testing messaging - public void SetName(string name) - { - this.name = name; - } - - /// - /// Throw the given exception - /// - /// An exception to throw. - public virtual void Exceptional(Exception t) - { - exceptionMethodCallCount++; - if (t != null) - { - throw t; - } - } - - - /// - /// Throw the given exception - /// - /// An exception to throw. - /// 314 if exception is null - public virtual int ExceptionalWithReturnValue(Exception t) - { - exceptionMethodCallCount++; - if (t != null) + if (value.IndexOf('.') != -1) { - throw t; + throw new Exception("Can't contain a ."); } - return 314; + + if (value.IndexOf(',') != -1) + { + throw new FormatException("Number format exception: contains a ,"); + } + + this.touchy = value; + } + } + + public bool PostProcessed + { + get { return postProcessed; } + + set { this.postProcessed = value; } + } + + public string Name + { + get { return name; } + set { this.name = value; } + } + + public string Nickname + { + get { return nickname; } + set { this.nickname = value; } + } + + public virtual int Age + { + get { return age; } + + set { this.age = value; } + } + + public virtual DateTime Date + { + get { return date; } + + set { this.date = value; } + } + + public virtual Single MyFloat + { + get { return myFloat; } + set { this.myFloat = value; } + } + + public virtual ITestObject Spouse + { + get { return spouse; } + set { this.spouse = value; } + } + + public virtual ITestObject Sibling + { + get { return sibling; } + set { this.sibling = value; } + } + + public virtual INestedTestObject Doctor + { + get { return doctor; } + set { this.doctor = value; } + } + + public virtual INestedTestObject Lawyer + { + get { return lawyer; } + set { this.lawyer = value; } + } + + public virtual NestedTestObject RealLawyer + { + get { return myRealLawyer; } + set { this.myRealLawyer = value; } + } + + /// + /// A collection of friends. + /// + public virtual ICollection Friends + { + get { return friends; } + set { this.friends = value; } + } + + /// + /// A read-only collection of pets. + /// + public virtual ICollection Pets + { + get { return pets; } + } + + public virtual TestObjectList TypedFriends + { + get { return typedFriends; } + set { typedFriends = value; } + } + + /// + /// A read-only map of periodic table values. + /// + public virtual IDictionary PeriodicTable + { + get { return periodicTable; } + } + + /// + /// A read-only set of computer names + /// + public virtual ISet Computers + { + get { return computers; } + } + + public virtual ISet SomeSet + { + get { return someSet; } + set { this.someSet = value; } + } + + public virtual string[] Hats + { + get { return hats; } + set { hats = value; } + } + + public virtual IDictionary SomeMap + { + get { return someMap; } + set { this.someMap = value; } + } + + public virtual IList SomeList + { + get { return someList; } + set { this.someList = value; } + } + + public virtual List SomeGenericStringList + { + get { return someGenericStringList; } + set { this.someGenericStringList = value; } + } + + private IList someGenericIListInt32; + + public virtual IList SomeGenericIListInt32 + { + get { return someGenericIListInt32; } + set { someGenericIListInt32 = value; } + } + + private IDictionary someGenericIDictionaryStringInt32; + + public virtual IDictionary SomeGenericIDictionaryStringInt32 + { + get { return someGenericIDictionaryStringInt32; } + set { someGenericIDictionaryStringInt32 = value; } + } + + private IEnumerable someGenericIEnumerableInt32; + + public virtual IEnumerable SomeGenericIEnumerableInt32 + { + get { return someGenericIEnumerableInt32; } + set { someGenericIEnumerableInt32 = value; } + } + + public virtual NameValueCollection SomeNameValueCollection + { + get { return someNameValueCollection; } + set { this.someNameValueCollection = value; } + } + + protected virtual string HappyPlace + { + get { return _happyPlace; } + set { _happyPlace = value; } + } + + // used in reflective tests, so don't remove this property... + private string[] SamsoniteSuitcase + { + get { return _samsoniteSuitcase; } + set { _samsoniteSuitcase = value; } + } + + public Type ClassProperty + { + get { return classProperty; } + set { classProperty = value; } + } + + public IApplicationContext ApplicationContext + { + get { return applicationContext; } + set { applicationContext = value; } + } + + public string ObjectName + { + get { return objectName; } + set { objectName = value; } + } + + public int ExceptionMethodCallCount + { + get { return exceptionMethodCallCount; } + } + + public bool InitCompleted + { + get { return initCompleted; } + set { initCompleted = value; } + } + + public Size Size + { + get { return size; } + set { size = value; } + } + + public string this[int index] + { + get + { + if (index < 0 || index >= favoriteQuotes.Length) + { + throw new ArgumentException("Index out of range"); + } + + return favoriteQuotes[index]; + } + set + { + if (index < 0 || index >= favoriteQuotes.Length) + { + throw new ArgumentException("index is out of range."); + } + + favoriteQuotes[index] = value; + } + } + + private int exceptionMethodCallCount; + private int objectNumber = 0; + public FileMode FileModeEnum; + private IObjectFactory objectFactory; + private bool postProcessed; + private int age; + private string name; + private string nickname; + private ITestObject spouse; + private ITestObject sibling; + private string touchy; + private ICollection friends = new LinkedList(); + private TestObjectList typedFriends = new TestObjectList(); + private ICollection pets = new LinkedList(); + private IDictionary periodicTable = new Hashtable(); + + private string[] favoriteQuotes = new string[] { "He who ha-ha ho-ho", "The quick brown fox jumped over the lazy dogs." }; + + private Type classProperty; + private ISet computers = new HybridSet(); + private ISet someSet = new HybridSet(); + private IDictionary someMap = new Hashtable(); + private IList someList = new ArrayList(); + private DateTime date = DateTime.Now; + private Single myFloat = (float) 0.0; + private CultureInfo myCulture = CultureInfo.InvariantCulture; + private string[] hats = null; + private INestedTestObject doctor = new NestedTestObject(); + private INestedTestObject lawyer = new NestedTestObject(); + private NestedTestObject myRealLawyer = new NestedTestObject(); + private IndexedTestObject nestedIndexedObject; + private string _happyPlace = DefaultHappyPlace; + private string[] _samsoniteSuitcase = DefaultContentsOfTheSuitcase; + + public const string DefaultHappyPlace = "The_SeaBass_Diner"; + + public static readonly string[] DefaultContentsOfTheSuitcase + = new string[] { "John Pryor's 'Leaving On A Jet Plane' LP" }; + + private IApplicationContext applicationContext; + private string objectName; + private Size size; + private bool initCompleted; + + private IDictionary sharedState; + private NameValueCollection someNameValueCollection; + private List someGenericStringList; + + public TestObject() + { + } + + public TestObject(string name, int age) + { + this.name = name; + this.age = age; + } + + public TestObject(string name, int age, INestedTestObject doctor) + { + this.name = name; + this.age = age; + this.doctor = doctor; + } + + public TestObject(string name, int age, INestedTestObject doctor, INestedTestObject lawyer) + { + this.name = name; + this.age = age; + this.doctor = doctor; + this.lawyer = lawyer; + } + + public TestObject(ITestObject spouse) + { + this.spouse = spouse; + } + + public TestObject(IList someList) + { + this.someList = someList; + } + + public TestObject(ISet someSet) + { + this.someSet = someSet; + } + + public TestObject(IDictionary someMap) + { + this.someMap = someMap; + } + + public TestObject(NameValueCollection someProps) + { + this.someNameValueCollection = someProps; + } + + public static TestObject Create(string name) + { + return new TestObject(name, 30); + } + + public void AfterPropertiesSet() + { + initCompleted = true; + } + + public void AddComputerName(string name) + { + if (computers == null) + { + computers = new HybridSet(); } - /// - /// Return a reference to the object itself. 'Return this' - /// - /// a reference to the object itse.f - public virtual object ReturnsThis() - { - return this; - } + computers.Add(name); + } - /// - /// Funny Named method. - /// - public virtual void Absquatulate() - { - } + public void AddPeriodicElement(string name, string element) + { + if (periodicTable == null) + { + periodicTable = new Hashtable(); + } - public IDictionary SharedState - { - get { return sharedState; } - set { sharedState = value; } - } - } + periodicTable.Add(name, element); + } - public class TestObjectConverter : TypeConverter - { - public override bool CanConvertTo( - ITypeDescriptorContext context, Type destinationType) - { - if ((destinationType == typeof (TestObjectConverter)) - || (destinationType == typeof (InstanceDescriptor))) - { - return true; - } - return base.CanConvertTo(context, destinationType); - } + public string GetNameWithHonorific(bool isFemale, params string[] lettersAfterName) + { + StringBuilder buffer = new StringBuilder(); + buffer.Append(isFemale ? "Ms " : "Mr "); + buffer.Append(Name); + buffer.Append(" "); + foreach (string letters in lettersAfterName) + { + buffer.Append(letters); + } - public override bool CanConvertFrom - (ITypeDescriptorContext context, Type sourceType) - { - if (sourceType == typeof (string)) - { - return true; - } - return base.CanConvertFrom(context, sourceType); - } + return buffer.ToString(); + } - public override object ConvertFrom - (ITypeDescriptorContext context, CultureInfo culture, object text_obj) - { - if (text_obj is string) - { - string text = (string) text_obj; - TestObject tb = new TestObject(); - string[] split = text.Split(new char[] {'_'}); - tb.Name = split[0]; - tb.Age = int.Parse(split[1]); - return tb; - } - return base.ConvertFrom(context, culture, text_obj); - } + public override bool Equals(object other) + { + return Equals(this, other); + } - public override object ConvertTo( - ITypeDescriptorContext context, CultureInfo culture, object param, Type destinationType) - { - return base.ConvertTo(context, culture, param, destinationType); - } - } -} \ No newline at end of file + new public static bool Equals(object @this, object other) + { + if (other == null || !(other is ITestObject)) + { + return false; + } + + ITestObject tb2 = (ITestObject) other; + ITestObject tb1 = (ITestObject) @this; + if (tb2.Age != tb1.Age) + { + return false; + } + + if ((object) tb1.Name == null) + { + return (object) tb2.Name == null; + } + + if (!tb2.Name.Equals(tb1.Name)) + { + return false; + } + + return true; + } + + public override int GetHashCode() + { + return (name != null ? name.GetHashCode() : base.GetHashCode()); + } + + public virtual int CompareTo(object other) + { + if ((object) this.name != null && other is TestObject) + { + return String.CompareOrdinal(this.name, ((TestObject) other).name); + } + else + { + return 1; + } + } + + public virtual string GetDescription() + { + string s = "name=" + name + "; age=" + age + "; touchy=" + touchy; + s += ("; spouse={" + (spouse != null ? spouse.Name : null) + "}"); + return s; + } + + public override string ToString() + { + string s = "name=" + name + "; age=" + age + "; touchy=" + touchy; + s += ("; spouse={" + (spouse != null ? spouse.Name : null) + "}"); + return s; + } + + //Used in testing messaging + public void SetName(string name) + { + this.name = name; + } + + /// + /// Throw the given exception + /// + /// An exception to throw. + public virtual void Exceptional(Exception t) + { + exceptionMethodCallCount++; + if (t != null) + { + throw t; + } + } + + /// + /// Throw the given exception + /// + /// An exception to throw. + /// 314 if exception is null + public virtual int ExceptionalWithReturnValue(Exception t) + { + exceptionMethodCallCount++; + if (t != null) + { + throw t; + } + + return 314; + } + + /// + /// Return a reference to the object itself. 'Return this' + /// + /// a reference to the object itse.f + public virtual object ReturnsThis() + { + return this; + } + + /// + /// Funny Named method. + /// + public virtual void Absquatulate() + { + } + + public IDictionary SharedState + { + get { return sharedState; } + set { sharedState = value; } + } +} + +public class TestObjectConverter : TypeConverter +{ + public override bool CanConvertTo( + ITypeDescriptorContext context, Type destinationType) + { + if ((destinationType == typeof(TestObjectConverter)) + || (destinationType == typeof(InstanceDescriptor))) + { + return true; + } + + return base.CanConvertTo(context, destinationType); + } + + public override bool CanConvertFrom + (ITypeDescriptorContext context, Type sourceType) + { + if (sourceType == typeof(string)) + { + return true; + } + + return base.CanConvertFrom(context, sourceType); + } + + public override object ConvertFrom + (ITypeDescriptorContext context, CultureInfo culture, object text_obj) + { + if (text_obj is string) + { + string text = (string) text_obj; + TestObject tb = new TestObject(); + string[] split = text.Split(new char[] { '_' }); + tb.Name = split[0]; + tb.Age = int.Parse(split[1]); + return tb; + } + + return base.ConvertFrom(context, culture, text_obj); + } + + public override object ConvertTo( + ITypeDescriptorContext context, CultureInfo culture, object param, Type destinationType) + { + return base.ConvertTo(context, culture, param, destinationType); + } +} diff --git a/test/Spring/Spring.Core.Tests/Objects/TestObject.resx b/test/Spring/Spring.Core.Tests/Objects/TestObject.resx index 431d10b4..dc1dde6a 100644 --- a/test/Spring/Spring.Core.Tests/Objects/TestObject.resx +++ b/test/Spring/Spring.Core.Tests/Objects/TestObject.resx @@ -1,51 +1,56 @@ - - + + + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + - - - - text/microsoft-resx - - - 1.0.0.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Mark - - - 35 - - - Rick - + + + + + + + + + + + + + + + text/microsoft-resx + + + 1.0.0.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + Mark + + + 35 + + + Rick + \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/Objects/TestObjectDAO.cs b/test/Spring/Spring.Core.Tests/Objects/TestObjectDAO.cs index 8cf81a5f..13a3afc5 100644 --- a/test/Spring/Spring.Core.Tests/Objects/TestObjectDAO.cs +++ b/test/Spring/Spring.Core.Tests/Objects/TestObjectDAO.cs @@ -20,55 +20,51 @@ using System.Data; -namespace Spring.Objects +namespace Spring.Objects; + +/// +/// Test class to help test PropertyPlaceholderConfigurer +/// +public class TestObjectDAO { /// - /// Test class to help test PropertyPlaceholderConfigurer + /// Create an instance of TestObjectDAO /// - public class TestObjectDAO + public TestObjectDAO() { - /// - /// Create an instance of TestObjectDAO - /// - public TestObjectDAO() - { - } - - - private int maxResults = 100; - - private IDbConnection dbConnection; - - /// - /// The database connection property - /// - public IDbConnection DbConnection - { - get - { - return dbConnection; - } - set - { - dbConnection = value; - } - } - - - /// - /// Maximum number of results to return in a query page. - /// - public int MaxResults - { - get - { - return maxResults; - } - set - { - maxResults = value; - } - } - } -} \ No newline at end of file + + private int maxResults = 100; + + private IDbConnection dbConnection; + + /// + /// The database connection property + /// + public IDbConnection DbConnection + { + get + { + return dbConnection; + } + set + { + dbConnection = value; + } + } + + /// + /// Maximum number of results to return in a query page. + /// + public int MaxResults + { + get + { + return maxResults; + } + set + { + maxResults = value; + } + } +} diff --git a/test/Spring/Spring.Core.Tests/Objects/TestObjectList.cs b/test/Spring/Spring.Core.Tests/Objects/TestObjectList.cs index f288406e..e93489e7 100644 --- a/test/Spring/Spring.Core.Tests/Objects/TestObjectList.cs +++ b/test/Spring/Spring.Core.Tests/Objects/TestObjectList.cs @@ -2,13 +2,13 @@ /* * Copyright 2002-2010 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. @@ -24,532 +24,530 @@ using System.Collections; #endregion -namespace Spring.Objects +namespace Spring.Objects; + +public interface ITestObjectCollection { - public interface ITestObjectCollection - { - int Count { get; } + int Count { get; } - bool IsSynchronized { get; } + bool IsSynchronized { get; } - object SyncRoot { get; } + object SyncRoot { get; } - void CopyTo(TestObject[] array, int arrayIndex); + void CopyTo(TestObject[] array, int arrayIndex); - ITestObjectEnumerator GetEnumerator(); - } - - public interface ITestObjectList : ITestObjectCollection - { - bool IsFixedSize { get; } - - bool IsReadOnly { get; } - - TestObject this[int index] { get; set; } - - int Add(TestObject value); - - void Clear(); - - bool Contains(TestObject value); - - int IndexOf(TestObject value); - - void Insert(int index, TestObject value); - - void Remove(TestObject value); - - void RemoveAt(int index); - } - - public interface ITestObjectEnumerator - { - TestObject Current { get; } - - bool MoveNext(); - - void Reset(); - } - - [Serializable] - public class TestObjectList : ITestObjectList, IList, ICloneable - { - private const int _defaultCapacity = 16; - - private TestObject[] _array = null; - private int _count = 0; - - [NonSerialized] private int _version = 0; - - public TestObjectList() - { - this._array = new TestObject[_defaultCapacity]; - } - - public TestObjectList(int capacity) - { - if (capacity < 0) - throw new ArgumentOutOfRangeException("capacity", - capacity, "Argument cannot be negative."); - - this._array = new TestObject[capacity]; - } - - public TestObjectList(TestObjectList collection) - { - if (collection == null) - throw new ArgumentNullException("collection"); - - this._array = new TestObject[collection.Count]; - AddRange(collection); - } - - public TestObjectList(TestObject[] array) - { - if (array == null) - throw new ArgumentNullException("array"); - - this._array = new TestObject[array.Length]; - AddRange(array); - } - - protected virtual TestObject[] InnerArray - { - get { return this._array; } - } - - public virtual int Capacity - { - get { return this._array.Length; } - set - { - if (value == this._array.Length) return; - - if (value < this._count) - throw new ArgumentOutOfRangeException("Capacity", - value, "Value cannot be less than Count."); - - if (value == 0) - { - this._array = new TestObject[_defaultCapacity]; - return; - } - - TestObject[] newArray = new TestObject[value]; - Array.Copy(this._array, newArray, this._count); - this._array = newArray; - } - } - - public virtual int Count - { - get { return this._count; } - } - - public virtual bool IsFixedSize - { - get { return false; } - } - - public virtual bool IsReadOnly - { - get { return false; } - } - - public virtual bool IsSynchronized - { - get { return false; } - } - - public virtual bool IsUnique - { - get { return false; } - } - - public virtual TestObject this[int index] - { - get - { - ValidateIndex(index); - return this._array[index]; - } - set - { - ValidateIndex(index); - ++this._version; - this._array[index] = value; - } - } - - object IList.this[int index] - { - get { return this[index]; } - set { this[index] = (TestObject) value; } - } - - public virtual object SyncRoot - { - get { return this; } - } - - public virtual int Add(TestObject value) - { - if (this._count == this._array.Length) - EnsureCapacity(this._count + 1); - - ++this._version; - this._array[this._count] = value; - return this._count++; - } - - int IList.Add(object value) - { - return Add((TestObject) value); - } - - public virtual void AddRange(TestObjectList collection) - { - if (collection == null) - throw new ArgumentNullException("collection"); - - if (collection.Count == 0) return; - if (this._count + collection.Count > this._array.Length) - EnsureCapacity(this._count + collection.Count); - - ++this._version; - Array.Copy(collection.InnerArray, 0, - this._array, this._count, collection.Count); - this._count += collection.Count; - } - - public virtual void AddRange(TestObject[] array) - { - if (array == null) - throw new ArgumentNullException("array"); - - if (array.Length == 0) return; - if (this._count + array.Length > this._array.Length) - EnsureCapacity(this._count + array.Length); - - ++this._version; - Array.Copy(array, 0, this._array, this._count, array.Length); - this._count += array.Length; - } - - public virtual int BinarySearch(TestObject value) - { - return Array.BinarySearch(this._array, 0, this._count, value); - } - - public virtual void Clear() - { - if (this._count == 0) return; - - ++this._version; - Array.Clear(this._array, 0, this._count); - this._count = 0; - } - - public virtual object Clone() - { - TestObjectList collection = new TestObjectList(this._count); - - Array.Copy(this._array, 0, collection._array, 0, this._count); - collection._count = this._count; - collection._version = this._version; - - return collection; - } - - public bool Contains(TestObject value) - { - return (IndexOf(value) >= 0); - } - - bool IList.Contains(object value) - { - return Contains((TestObject) value); - } - - public virtual void CopyTo(TestObject[] array) - { - CheckTargetArray(array, 0); - Array.Copy(this._array, array, this._count); - } - - public virtual void CopyTo(TestObject[] array, int arrayIndex) - { - CheckTargetArray(array, arrayIndex); - Array.Copy(this._array, 0, array, arrayIndex, this._count); - } - - void ICollection.CopyTo(Array array, int arrayIndex) - { - CheckTargetArray(array, arrayIndex); - CopyTo((TestObject[]) array, arrayIndex); - } - - public virtual ITestObjectEnumerator GetEnumerator() - { - return new Enumerator(this); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return (IEnumerator) GetEnumerator(); - } - - public virtual int IndexOf(TestObject value) - { - return Array.IndexOf(this._array, value, 0, this._count); - } - - int IList.IndexOf(object value) - { - return IndexOf((TestObject) value); - } - - public virtual void Insert(int index, TestObject value) - { - if (index < 0) - throw new ArgumentOutOfRangeException("index", - index, "Argument cannot be negative."); - - if (index > this._count) - throw new ArgumentOutOfRangeException("index", - index, "Argument cannot exceed Count."); - - if (this._count == this._array.Length) - EnsureCapacity(this._count + 1); - - ++this._version; - if (index < this._count) - Array.Copy(this._array, index, - this._array, index + 1, this._count - index); - - this._array[index] = value; - ++this._count; - } - - void IList.Insert(int index, object value) - { - Insert(index, (TestObject) value); - } - - public virtual void Remove(TestObject value) - { - int index = IndexOf(value); - if (index >= 0) RemoveAt(index); - } - - void IList.Remove(object value) - { - Remove((TestObject) value); - } - - public virtual void RemoveAt(int index) - { - ValidateIndex(index); - - ++this._version; - if (index < --this._count) - Array.Copy(this._array, index + 1, - this._array, index, this._count - index); - - this._array[this._count] = null; - } - - public virtual void RemoveRange(int index, int count) - { - if (index < 0) - throw new ArgumentOutOfRangeException("index", - index, "Argument cannot be negative."); - - if (count < 0) - throw new ArgumentOutOfRangeException("count", - count, "Argument cannot be negative."); - - if (index + count > this._count) - throw new ArgumentException( - "Arguments denote invalid range of elements."); - - if (count == 0) return; - - ++this._version; - this._count -= count; - - if (index < this._count) - Array.Copy(this._array, index + count, - this._array, index, this._count - index); - - Array.Clear(this._array, this._count, count); - } - - public virtual void Reverse() - { - if (this._count <= 1) return; - ++this._version; - Array.Reverse(this._array, 0, this._count); - } - - public virtual void Reverse(int index, int count) - { - if (index < 0) - throw new ArgumentOutOfRangeException("index", - index, "Argument cannot be negative."); - - if (count < 0) - throw new ArgumentOutOfRangeException("count", - count, "Argument cannot be negative."); - - if (index + count > this._count) - throw new ArgumentException( - "Arguments denote invalid range of elements."); - - if (count <= 1 || this._count <= 1) return; - ++this._version; - Array.Reverse(this._array, index, count); - } - - public virtual void Sort() - { - if (this._count <= 1) return; - ++this._version; - Array.Sort(this._array, 0, this._count); - } - - public virtual void Sort(IComparer comparer) - { - if (this._count <= 1) return; - ++this._version; - Array.Sort(this._array, 0, this._count, comparer); - } - - public virtual void Sort(int index, int count, IComparer comparer) - { - if (index < 0) - throw new ArgumentOutOfRangeException("index", - index, "Argument cannot be negative."); - - if (count < 0) - throw new ArgumentOutOfRangeException("count", - count, "Argument cannot be negative."); - - if (index + count > this._count) - throw new ArgumentException( - "Arguments denote invalid range of elements."); - - if (count <= 1 || this._count <= 1) return; - ++this._version; - Array.Sort(this._array, index, count, comparer); - } - - public virtual TestObject[] ToArray() - { - TestObject[] array = new TestObject[this._count]; - Array.Copy(this._array, array, this._count); - return array; - } - - public virtual void TrimToSize() - { - Capacity = this._count; - } - - private void CheckEnumIndex(int index) - { - if (index < 0 || index >= this._count) - throw new InvalidOperationException( - "Enumerator is not on a collection element."); - } - - private void CheckEnumVersion(int version) - { - if (version != this._version) - throw new InvalidOperationException( - "Enumerator invalidated by modification to collection."); - } - - private void CheckTargetArray(Array array, int arrayIndex) - { - if (array == null) - throw new ArgumentNullException("array"); - if (array.Rank > 1) - throw new ArgumentException( - "Argument cannot be multidimensional.", "array"); - - if (arrayIndex < 0) - throw new ArgumentOutOfRangeException("arrayIndex", - arrayIndex, "Argument cannot be negative."); - if (arrayIndex >= array.Length) - throw new ArgumentException( - "Argument must be less than array length.", "arrayIndex"); - - if (this._count > array.Length - arrayIndex) - throw new ArgumentException( - "Argument section must be large enough for collection.", "array"); - } - - private void EnsureCapacity(int minimum) - { - int newCapacity = (this._array.Length == 0 ? - _defaultCapacity : this._array.Length*2); - - if (newCapacity < minimum) newCapacity = minimum; - Capacity = newCapacity; - } - - private void ValidateIndex(int index) - { - if (index < 0) - throw new ArgumentOutOfRangeException("index", - index, "Argument cannot be negative."); - - if (index >= this._count) - throw new ArgumentOutOfRangeException("index", - index, "Argument must be less than Count."); - } - - [Serializable] - private sealed class Enumerator : ITestObjectEnumerator, IEnumerator - { - private readonly TestObjectList _collection; - private readonly int _version; - private int _index; - - internal Enumerator(TestObjectList collection) - { - this._collection = collection; - this._version = collection._version; - this._index = -1; - } - - public TestObject Current - { - get - { - this._collection.CheckEnumIndex(this._index); - this._collection.CheckEnumVersion(this._version); - return this._collection[this._index]; - } - } - - object IEnumerator.Current - { - get { return Current; } - } - - public bool MoveNext() - { - this._collection.CheckEnumVersion(this._version); - return (++this._index < this._collection.Count); - } - - public void Reset() - { - this._collection.CheckEnumVersion(this._version); - this._index = -1; - } - } - } + ITestObjectEnumerator GetEnumerator(); +} + +public interface ITestObjectList : ITestObjectCollection +{ + bool IsFixedSize { get; } + + bool IsReadOnly { get; } + + TestObject this[int index] { get; set; } + + int Add(TestObject value); + + void Clear(); + + bool Contains(TestObject value); + + int IndexOf(TestObject value); + + void Insert(int index, TestObject value); + + void Remove(TestObject value); + + void RemoveAt(int index); +} + +public interface ITestObjectEnumerator +{ + TestObject Current { get; } + + bool MoveNext(); + + void Reset(); +} + +[Serializable] +public class TestObjectList : ITestObjectList, IList, ICloneable +{ + private const int _defaultCapacity = 16; + + private TestObject[] _array = null; + private int _count = 0; + + [NonSerialized] private int _version = 0; + + public TestObjectList() + { + this._array = new TestObject[_defaultCapacity]; + } + + public TestObjectList(int capacity) + { + if (capacity < 0) + throw new ArgumentOutOfRangeException("capacity", + capacity, "Argument cannot be negative."); + + this._array = new TestObject[capacity]; + } + + public TestObjectList(TestObjectList collection) + { + if (collection == null) + throw new ArgumentNullException("collection"); + + this._array = new TestObject[collection.Count]; + AddRange(collection); + } + + public TestObjectList(TestObject[] array) + { + if (array == null) + throw new ArgumentNullException("array"); + + this._array = new TestObject[array.Length]; + AddRange(array); + } + + protected virtual TestObject[] InnerArray + { + get { return this._array; } + } + + public virtual int Capacity + { + get { return this._array.Length; } + set + { + if (value == this._array.Length) return; + + if (value < this._count) + throw new ArgumentOutOfRangeException("Capacity", + value, "Value cannot be less than Count."); + + if (value == 0) + { + this._array = new TestObject[_defaultCapacity]; + return; + } + + TestObject[] newArray = new TestObject[value]; + Array.Copy(this._array, newArray, this._count); + this._array = newArray; + } + } + + public virtual int Count + { + get { return this._count; } + } + + public virtual bool IsFixedSize + { + get { return false; } + } + + public virtual bool IsReadOnly + { + get { return false; } + } + + public virtual bool IsSynchronized + { + get { return false; } + } + + public virtual bool IsUnique + { + get { return false; } + } + + public virtual TestObject this[int index] + { + get + { + ValidateIndex(index); + return this._array[index]; + } + set + { + ValidateIndex(index); + ++this._version; + this._array[index] = value; + } + } + + object IList.this[int index] + { + get { return this[index]; } + set { this[index] = (TestObject) value; } + } + + public virtual object SyncRoot + { + get { return this; } + } + + public virtual int Add(TestObject value) + { + if (this._count == this._array.Length) + EnsureCapacity(this._count + 1); + + ++this._version; + this._array[this._count] = value; + return this._count++; + } + + int IList.Add(object value) + { + return Add((TestObject) value); + } + + public virtual void AddRange(TestObjectList collection) + { + if (collection == null) + throw new ArgumentNullException("collection"); + + if (collection.Count == 0) return; + if (this._count + collection.Count > this._array.Length) + EnsureCapacity(this._count + collection.Count); + + ++this._version; + Array.Copy(collection.InnerArray, 0, + this._array, this._count, collection.Count); + this._count += collection.Count; + } + + public virtual void AddRange(TestObject[] array) + { + if (array == null) + throw new ArgumentNullException("array"); + + if (array.Length == 0) return; + if (this._count + array.Length > this._array.Length) + EnsureCapacity(this._count + array.Length); + + ++this._version; + Array.Copy(array, 0, this._array, this._count, array.Length); + this._count += array.Length; + } + + public virtual int BinarySearch(TestObject value) + { + return Array.BinarySearch(this._array, 0, this._count, value); + } + + public virtual void Clear() + { + if (this._count == 0) return; + + ++this._version; + Array.Clear(this._array, 0, this._count); + this._count = 0; + } + + public virtual object Clone() + { + TestObjectList collection = new TestObjectList(this._count); + + Array.Copy(this._array, 0, collection._array, 0, this._count); + collection._count = this._count; + collection._version = this._version; + + return collection; + } + + public bool Contains(TestObject value) + { + return (IndexOf(value) >= 0); + } + + bool IList.Contains(object value) + { + return Contains((TestObject) value); + } + + public virtual void CopyTo(TestObject[] array) + { + CheckTargetArray(array, 0); + Array.Copy(this._array, array, this._count); + } + + public virtual void CopyTo(TestObject[] array, int arrayIndex) + { + CheckTargetArray(array, arrayIndex); + Array.Copy(this._array, 0, array, arrayIndex, this._count); + } + + void ICollection.CopyTo(Array array, int arrayIndex) + { + CheckTargetArray(array, arrayIndex); + CopyTo((TestObject[]) array, arrayIndex); + } + + public virtual ITestObjectEnumerator GetEnumerator() + { + return new Enumerator(this); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return (IEnumerator) GetEnumerator(); + } + + public virtual int IndexOf(TestObject value) + { + return Array.IndexOf(this._array, value, 0, this._count); + } + + int IList.IndexOf(object value) + { + return IndexOf((TestObject) value); + } + + public virtual void Insert(int index, TestObject value) + { + if (index < 0) + throw new ArgumentOutOfRangeException("index", + index, "Argument cannot be negative."); + + if (index > this._count) + throw new ArgumentOutOfRangeException("index", + index, "Argument cannot exceed Count."); + + if (this._count == this._array.Length) + EnsureCapacity(this._count + 1); + + ++this._version; + if (index < this._count) + Array.Copy(this._array, index, + this._array, index + 1, this._count - index); + + this._array[index] = value; + ++this._count; + } + + void IList.Insert(int index, object value) + { + Insert(index, (TestObject) value); + } + + public virtual void Remove(TestObject value) + { + int index = IndexOf(value); + if (index >= 0) RemoveAt(index); + } + + void IList.Remove(object value) + { + Remove((TestObject) value); + } + + public virtual void RemoveAt(int index) + { + ValidateIndex(index); + + ++this._version; + if (index < --this._count) + Array.Copy(this._array, index + 1, + this._array, index, this._count - index); + + this._array[this._count] = null; + } + + public virtual void RemoveRange(int index, int count) + { + if (index < 0) + throw new ArgumentOutOfRangeException("index", + index, "Argument cannot be negative."); + + if (count < 0) + throw new ArgumentOutOfRangeException("count", + count, "Argument cannot be negative."); + + if (index + count > this._count) + throw new ArgumentException( + "Arguments denote invalid range of elements."); + + if (count == 0) return; + + ++this._version; + this._count -= count; + + if (index < this._count) + Array.Copy(this._array, index + count, + this._array, index, this._count - index); + + Array.Clear(this._array, this._count, count); + } + + public virtual void Reverse() + { + if (this._count <= 1) return; + ++this._version; + Array.Reverse(this._array, 0, this._count); + } + + public virtual void Reverse(int index, int count) + { + if (index < 0) + throw new ArgumentOutOfRangeException("index", + index, "Argument cannot be negative."); + + if (count < 0) + throw new ArgumentOutOfRangeException("count", + count, "Argument cannot be negative."); + + if (index + count > this._count) + throw new ArgumentException( + "Arguments denote invalid range of elements."); + + if (count <= 1 || this._count <= 1) return; + ++this._version; + Array.Reverse(this._array, index, count); + } + + public virtual void Sort() + { + if (this._count <= 1) return; + ++this._version; + Array.Sort(this._array, 0, this._count); + } + + public virtual void Sort(IComparer comparer) + { + if (this._count <= 1) return; + ++this._version; + Array.Sort(this._array, 0, this._count, comparer); + } + + public virtual void Sort(int index, int count, IComparer comparer) + { + if (index < 0) + throw new ArgumentOutOfRangeException("index", + index, "Argument cannot be negative."); + + if (count < 0) + throw new ArgumentOutOfRangeException("count", + count, "Argument cannot be negative."); + + if (index + count > this._count) + throw new ArgumentException( + "Arguments denote invalid range of elements."); + + if (count <= 1 || this._count <= 1) return; + ++this._version; + Array.Sort(this._array, index, count, comparer); + } + + public virtual TestObject[] ToArray() + { + TestObject[] array = new TestObject[this._count]; + Array.Copy(this._array, array, this._count); + return array; + } + + public virtual void TrimToSize() + { + Capacity = this._count; + } + + private void CheckEnumIndex(int index) + { + if (index < 0 || index >= this._count) + throw new InvalidOperationException( + "Enumerator is not on a collection element."); + } + + private void CheckEnumVersion(int version) + { + if (version != this._version) + throw new InvalidOperationException( + "Enumerator invalidated by modification to collection."); + } + + private void CheckTargetArray(Array array, int arrayIndex) + { + if (array == null) + throw new ArgumentNullException("array"); + if (array.Rank > 1) + throw new ArgumentException( + "Argument cannot be multidimensional.", "array"); + + if (arrayIndex < 0) + throw new ArgumentOutOfRangeException("arrayIndex", + arrayIndex, "Argument cannot be negative."); + if (arrayIndex >= array.Length) + throw new ArgumentException( + "Argument must be less than array length.", "arrayIndex"); + + if (this._count > array.Length - arrayIndex) + throw new ArgumentException( + "Argument section must be large enough for collection.", "array"); + } + + private void EnsureCapacity(int minimum) + { + int newCapacity = (this._array.Length == 0 ? _defaultCapacity : this._array.Length * 2); + + if (newCapacity < minimum) newCapacity = minimum; + Capacity = newCapacity; + } + + private void ValidateIndex(int index) + { + if (index < 0) + throw new ArgumentOutOfRangeException("index", + index, "Argument cannot be negative."); + + if (index >= this._count) + throw new ArgumentOutOfRangeException("index", + index, "Argument must be less than Count."); + } + + [Serializable] + private sealed class Enumerator : ITestObjectEnumerator, IEnumerator + { + private readonly TestObjectList _collection; + private readonly int _version; + private int _index; + + internal Enumerator(TestObjectList collection) + { + this._collection = collection; + this._version = collection._version; + this._index = -1; + } + + public TestObject Current + { + get + { + this._collection.CheckEnumIndex(this._index); + this._collection.CheckEnumVersion(this._version); + return this._collection[this._index]; + } + } + + object IEnumerator.Current + { + get { return Current; } + } + + public bool MoveNext() + { + this._collection.CheckEnumVersion(this._version); + return (++this._index < this._collection.Count); + } + + public void Reset() + { + this._collection.CheckEnumVersion(this._version); + this._index = -1; + } + } } diff --git a/test/Spring/Spring.Core.Tests/Objects/TestTransparentProxyFactory.cs b/test/Spring/Spring.Core.Tests/Objects/TestTransparentProxyFactory.cs index f1bdca18..a15c80f8 100644 --- a/test/Spring/Spring.Core.Tests/Objects/TestTransparentProxyFactory.cs +++ b/test/Spring/Spring.Core.Tests/Objects/TestTransparentProxyFactory.cs @@ -23,91 +23,91 @@ using System.Runtime.Remoting; using System.Runtime.Remoting.Messaging; using System.Runtime.Remoting.Proxies; -namespace Spring.Objects +namespace Spring.Objects; + +/// +/// +/// Erich Eichinger +public class TestTransparentProxyFactory : RealProxy, IRemotingTypeInfo { - /// - /// - /// Erich Eichinger - public class TestTransparentProxyFactory : RealProxy, IRemotingTypeInfo + public delegate object InvokeCallback(object proxy, object targetInstance, MethodInfo targetMethod, object[] arguments); + + private object targetInstance; + private Type targetType; + private InvokeCallback invokeHandler; + + public object TargetInstance { - public delegate object InvokeCallback(object proxy, object targetInstance, MethodInfo targetMethod, object[] arguments); - - private object targetInstance; - private Type targetType; - private InvokeCallback invokeHandler; - - public object TargetInstance - { - get { return targetInstance; } - set { targetInstance = value; } - } - - public Type TargetType - { - get { return targetType; } - set { targetType = value; } - } - - public InvokeCallback InvokeHandler - { - get { return invokeHandler; } - set { invokeHandler = value; } - } - - public TestTransparentProxyFactory(object targetInstance, Type targetType, InvokeCallback invokeHandler) - : base(typeof(MarshalByRefObject)) - { - this.targetInstance = targetInstance; - this.targetType = targetType; - this.invokeHandler = invokeHandler; - } - - public override IMessage Invoke(IMessage msg) - { - if (msg is IMethodCallMessage) - { - IMethodCallMessage callMsg = (IMethodCallMessage)msg; - - // obtain method with same name & signature from target instance - MethodInfo targetMethod = targetInstance.GetType().GetMethod(callMsg.MethodName, (Type[])callMsg.MethodSignature); - - // invoke - object result; - if (invokeHandler != null) - { - result = invokeHandler(this, targetInstance, targetMethod, callMsg.Args); - } - else - { - result = targetMethod.Invoke(targetInstance, callMsg.Args); - } - - // create result msg - return new ReturnMessage(result, null, 0, null, callMsg); - } - throw new NotSupportedException(); - } - - public virtual bool CanCastTo(Type fromType, object o) - { - // we accept ALL messages... - return fromType.IsAssignableFrom(fromType); - } - - public virtual string TypeName - { - get { return targetInstance.GetType().AssemblyQualifiedName; } - set { throw new System.NotSupportedException(); } - } - - public static TestTransparentProxyFactory GetProxy(object transparentProxy ) - { - return (TestTransparentProxyFactory) RemotingServices.GetRealProxy(transparentProxy); - } - - public static object GetTargetInstance( object transparentProxy ) - { - return GetProxy(transparentProxy).targetInstance; - } + get { return targetInstance; } + set { targetInstance = value; } } -} \ No newline at end of file + + public Type TargetType + { + get { return targetType; } + set { targetType = value; } + } + + public InvokeCallback InvokeHandler + { + get { return invokeHandler; } + set { invokeHandler = value; } + } + + public TestTransparentProxyFactory(object targetInstance, Type targetType, InvokeCallback invokeHandler) + : base(typeof(MarshalByRefObject)) + { + this.targetInstance = targetInstance; + this.targetType = targetType; + this.invokeHandler = invokeHandler; + } + + public override IMessage Invoke(IMessage msg) + { + if (msg is IMethodCallMessage) + { + IMethodCallMessage callMsg = (IMethodCallMessage) msg; + + // obtain method with same name & signature from target instance + MethodInfo targetMethod = targetInstance.GetType().GetMethod(callMsg.MethodName, (Type[]) callMsg.MethodSignature); + + // invoke + object result; + if (invokeHandler != null) + { + result = invokeHandler(this, targetInstance, targetMethod, callMsg.Args); + } + else + { + result = targetMethod.Invoke(targetInstance, callMsg.Args); + } + + // create result msg + return new ReturnMessage(result, null, 0, null, callMsg); + } + + throw new NotSupportedException(); + } + + public virtual bool CanCastTo(Type fromType, object o) + { + // we accept ALL messages... + return fromType.IsAssignableFrom(fromType); + } + + public virtual string TypeName + { + get { return targetInstance.GetType().AssemblyQualifiedName; } + set { throw new System.NotSupportedException(); } + } + + public static TestTransparentProxyFactory GetProxy(object transparentProxy) + { + return (TestTransparentProxyFactory) RemotingServices.GetRealProxy(transparentProxy); + } + + public static object GetTargetInstance(object transparentProxy) + { + return GetProxy(transparentProxy).targetInstance; + } +} diff --git a/test/Spring/Spring.Core.Tests/Objects/TypeMismatchExceptionTests.cs b/test/Spring/Spring.Core.Tests/Objects/TypeMismatchExceptionTests.cs index 36b8fa1c..95d6fe94 100644 --- a/test/Spring/Spring.Core.Tests/Objects/TypeMismatchExceptionTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/TypeMismatchExceptionTests.cs @@ -21,34 +21,33 @@ using NUnit.Framework; using Spring.Core; -namespace Spring.Objects +namespace Spring.Objects; + +/// +/// Unit tests for the TypeMismatchException class. +/// +/// Rick Evans +[TestFixture] +public sealed class TypeMismatchExceptionTests { - /// - /// Unit tests for the TypeMismatchException class. - /// - /// Rick Evans - [TestFixture] - public sealed class TypeMismatchExceptionTests + [Test] + public void InstantiationSupplyingPropertyChangeArgsType() { - [Test] - public void InstantiationSupplyingPropertyChangeArgsType() - { - TypeMismatchException ex = new TypeMismatchException(new PropertyChangeEventArgs("Doctor", new NestedTestObject("Foo"), new TestObject("Hershey", 12)), typeof (INestedTestObject)); - Assert.AreEqual("typeMismatch", ex.ErrorCode); - } + TypeMismatchException ex = new TypeMismatchException(new PropertyChangeEventArgs("Doctor", new NestedTestObject("Foo"), new TestObject("Hershey", 12)), typeof(INestedTestObject)); + Assert.AreEqual("typeMismatch", ex.ErrorCode); + } - [Test] - public void InstantiationSupplyingPropertyChangeArgsTypeAndRootException() - { - TypeMismatchException ex = new TypeMismatchException(new PropertyChangeEventArgs("Doctor", new NestedTestObject("Foo"), new TestObject("Hershey", 12)), typeof (INestedTestObject), null); - Assert.AreEqual("typeMismatch", ex.ErrorCode); - } + [Test] + public void InstantiationSupplyingPropertyChangeArgsTypeAndRootException() + { + TypeMismatchException ex = new TypeMismatchException(new PropertyChangeEventArgs("Doctor", new NestedTestObject("Foo"), new TestObject("Hershey", 12)), typeof(INestedTestObject), null); + Assert.AreEqual("typeMismatch", ex.ErrorCode); + } - [Test] - public void InstantiationSupplyingNullPropertyChangeArgsAndNullType() - { - TypeMismatchException ex = new TypeMismatchException(null, null, null); - Assert.AreEqual("typeMismatch", ex.ErrorCode); - } - } + [Test] + public void InstantiationSupplyingNullPropertyChangeArgsAndNullType() + { + TypeMismatchException ex = new TypeMismatchException(null, null, null); + Assert.AreEqual("typeMismatch", ex.ErrorCode); + } } diff --git a/test/Spring/Spring.Core.Tests/Objects/ValidatorTestObject.cs b/test/Spring/Spring.Core.Tests/Objects/ValidatorTestObject.cs index e8f0c850..86ca9db2 100644 --- a/test/Spring/Spring.Core.Tests/Objects/ValidatorTestObject.cs +++ b/test/Spring/Spring.Core.Tests/Objects/ValidatorTestObject.cs @@ -1,50 +1,48 @@ -namespace Spring.Objects +namespace Spring.Objects; +/// +/// Test class used for Validator tests. +/// +/// Goran Milosavljevic +public class Contact { - /// - /// Test class used for Validator tests. - /// - /// Goran Milosavljevic - public class Contact - { - private String m_name; - private int m_age; - private int m_loan; - private string m_creditcard; + private String m_name; + private int m_age; + private int m_loan; + private string m_creditcard; - public Contact() - { - } + public Contact() + { + } - public Contact(string name, int age, int loan) - { - this.m_name = name; - this.m_age = age; - this.m_loan = loan; - } + public Contact(string name, int age, int loan) + { + this.m_name = name; + this.m_age = age; + this.m_loan = loan; + } - public string Creditcard - { - get { return m_creditcard; } - set { m_creditcard = value; } - } + public string Creditcard + { + get { return m_creditcard; } + set { m_creditcard = value; } + } - public int Age - { - get { return m_age; } - set { m_age = value; } - } + public int Age + { + get { return m_age; } + set { m_age = value; } + } - public int Loan - { - get { return m_loan; } - set { m_loan = value; } - } + public int Loan + { + get { return m_loan; } + set { m_loan = value; } + } - public string Name - { - get { return m_name; } - set { m_name = value; } - } - } -} \ No newline at end of file + public string Name + { + get { return m_name; } + set { m_name = value; } + } +} diff --git a/test/Spring/Spring.Core.Tests/Pool/Support/SimplePoolTest.cs b/test/Spring/Spring.Core.Tests/Pool/Support/SimplePoolTest.cs index 9bfcb1ea..1484e0e5 100644 --- a/test/Spring/Spring.Core.Tests/Pool/Support/SimplePoolTest.cs +++ b/test/Spring/Spring.Core.Tests/Pool/Support/SimplePoolTest.cs @@ -1,431 +1,433 @@ #region License /* -* Copyright � 2002-2011 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. -*/ + * Copyright � 2002-2011 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.Collections; using System.Runtime.InteropServices; using FakeItEasy; - using NUnit.Framework; using Spring.Pool.Support; using Spring.Threading; -namespace Spring.Pool +namespace Spring.Pool; + +#region Inner Class : Helper + +public class Helper { - #region Inner Class : Helper + private Latch latch; + private IObjectPool objectPool; + private ISync sync; - public class Helper - { - private Latch latch; - private IObjectPool objectPool; - private ISync sync; + public bool gone = false; + public object gotFromPool; - public bool gone = false; - public object gotFromPool; + public Helper(ISync sync, Latch latch) + { + Init(latch, sync, null); + } - public Helper(ISync sync, Latch latch) - { - Init(latch, sync, null); - } + public Helper(Latch latch, ISync sync, IObjectPool objectPool) + { + Init(latch, sync, objectPool); + } - public Helper(Latch latch, ISync sync, IObjectPool objectPool) - { - Init(latch, sync, objectPool); - } + public void Init(Latch latch, ISync sync, IObjectPool objectPool) + { + this.sync = sync; + this.latch = latch; + this.objectPool = objectPool; + } - public void Init(Latch latch, ISync sync, IObjectPool objectPool) - { - this.sync = sync; - this.latch = latch; - this.objectPool = objectPool; - } + public void Go() + { + latch.Release(); + sync.Acquire(); + gone = true; + sync.Release(); + } - public void Go() - { - latch.Release(); - sync.Acquire(); - gone = true; - sync.Release(); - } + public void UsePool() + { + gotFromPool = objectPool.BorrowObject(); + latch.Release(); + } +} - public void UsePool() - { - gotFromPool = objectPool.BorrowObject(); - latch.Release(); - } - } +#endregion - #endregion +/// +/// Unit tests for the SimplePool class. +/// +[TestFixture] +public sealed class SimplePoolTests +{ + #region Inner Class : MyFactory (IPoolableObjectFactory implementation) - /// - /// Unit tests for the SimplePool class. - /// - [TestFixture] - public sealed class SimplePoolTests - { - #region Inner Class : MyFactory (IPoolableObjectFactory implementation) - - private sealed class MyFactory : IPoolableObjectFactory - { - public object MakeObject() - { - return new object(); - } - - public void DestroyObject(object o) - { - } - - public bool ValidateObject(object o) - { - return true; - } - - public void ActivateObject(object o) - { - } - - public void PassivateObject(object o) - { - } - } - - #endregion - - private IPoolableObjectFactory factory; - private SimplePool pool; - - [SetUp] - public void SetUp() - { - factory = A.Fake(); - A.CallTo(() => factory.MakeObject()).Returns(new object()); - - pool = new SimplePool(factory, 1); - } - - - [Test] - public void InstantiateWithNullPoolableObjectFactory() - { - Assert.Throws(() => new SimplePool(null, 10)); - } - - [Test] - public void InstantiateSpecifyingZeroPooledItems() - { - Assert.Throws(() => new SimplePool(factory, 0)); - } - - [Test] - public void InstantiateSpecifyingNegativePooledItems() - { - Assert.Throws(() => new SimplePool(factory, -10000)); - } - - [Test] - public void ActivateOnObjectOnBorrow() - { - A.CallTo(() => factory.ValidateObject(null)).WithAnyArguments().Returns(true); - - Assert.AreEqual(0, pool.NumActive, "active wrong"); - Assert.AreEqual(1, pool.NumIdle, "idle wrong"); - pool.BorrowObject(); - Assert.AreEqual(1, pool.NumActive, "active wrong"); - Assert.AreEqual(0, pool.NumIdle, "idle wrong"); - - A.CallTo(() => factory.ActivateObject(null)).WithAnyArguments().MustHaveHappened(); + private sealed class MyFactory : IPoolableObjectFactory + { + public object MakeObject() + { + return new object(); } - [Test] - public void PassivateBusyObjectsBeforeClose() - { - A.CallTo(() => factory.ValidateObject(A._)).WithAnyArguments().Returns(true); - - object o = pool.BorrowObject(); - pool.Close(); - A.CallTo(() => factory.PassivateObject(o)).MustHaveHappened(); + public void DestroyObject(object o) + { } - [Test] - [Ignore("No longer expected behavior per SPRNET-1582 being resolved.")] - public void NoMoreUsableAfterClose() - { - pool.Close(); - Assert.Throws(() => pool.BorrowObject()); - - A.CallTo(() => factory.PassivateObject(null)).WithAnyArguments().MustHaveHappened(); + public bool ValidateObject(object o) + { + return true; } - [Test] - [Ignore("No longer expected behavior per SPRNET-1582 being resolved.")] - public void ThrowsExceptionWhenOutOfItemsBecauseFailedValidation() - { - object o = new object(); - A.CallTo(() => factory.MakeObject()).Returns(o); - A.CallTo(() => factory.ValidateObject(o)).Returns(false); - - pool = new SimplePool(factory, 1); - Assert.Throws(() => pool.BorrowObject()); + public void ActivateObject(object o) + { } - [Test] - public void PassivateObjectOnReturn() - { - A.CallTo(() => factory.ValidateObject(null)).WithAnyArguments().Returns(true); + public void PassivateObject(object o) + { + } + } - pool.ReturnObject(pool.BorrowObject()); - A.CallTo(() => factory.PassivateObject(null)).WithAnyArguments().MustHaveHappened(); + #endregion + + private IPoolableObjectFactory factory; + private SimplePool pool; + + [SetUp] + public void SetUp() + { + factory = A.Fake(); + A.CallTo(() => factory.MakeObject()).Returns(new object()); + + pool = new SimplePool(factory, 1); + } + + [Test] + public void InstantiateWithNullPoolableObjectFactory() + { + Assert.Throws(() => new SimplePool(null, 10)); + } + + [Test] + public void InstantiateSpecifyingZeroPooledItems() + { + Assert.Throws(() => new SimplePool(factory, 0)); + } + + [Test] + public void InstantiateSpecifyingNegativePooledItems() + { + Assert.Throws(() => new SimplePool(factory, -10000)); + } + + [Test] + public void ActivateOnObjectOnBorrow() + { + A.CallTo(() => factory.ValidateObject(null)).WithAnyArguments().Returns(true); + + Assert.AreEqual(0, pool.NumActive, "active wrong"); + Assert.AreEqual(1, pool.NumIdle, "idle wrong"); + pool.BorrowObject(); + Assert.AreEqual(1, pool.NumActive, "active wrong"); + Assert.AreEqual(0, pool.NumIdle, "idle wrong"); + + A.CallTo(() => factory.ActivateObject(null)).WithAnyArguments().MustHaveHappened(); + } + + [Test] + public void PassivateBusyObjectsBeforeClose() + { + A.CallTo(() => factory.ValidateObject(A._)).WithAnyArguments().Returns(true); + + object o = pool.BorrowObject(); + pool.Close(); + A.CallTo(() => factory.PassivateObject(o)).MustHaveHappened(); + } + + [Test] + [Ignore("No longer expected behavior per SPRNET-1582 being resolved.")] + public void NoMoreUsableAfterClose() + { + pool.Close(); + Assert.Throws(() => pool.BorrowObject()); + + A.CallTo(() => factory.PassivateObject(null)).WithAnyArguments().MustHaveHappened(); + } + + [Test] + [Ignore("No longer expected behavior per SPRNET-1582 being resolved.")] + public void ThrowsExceptionWhenOutOfItemsBecauseFailedValidation() + { + object o = new object(); + A.CallTo(() => factory.MakeObject()).Returns(o); + A.CallTo(() => factory.ValidateObject(o)).Returns(false); + + pool = new SimplePool(factory, 1); + Assert.Throws(() => pool.BorrowObject()); + } + + [Test] + public void PassivateObjectOnReturn() + { + A.CallTo(() => factory.ValidateObject(null)).WithAnyArguments().Returns(true); + + pool.ReturnObject(pool.BorrowObject()); + A.CallTo(() => factory.PassivateObject(null)).WithAnyArguments().MustHaveHappened(); + } + + [Test] + public void DestroyObjectOnClose() + { + A.CallTo(() => factory.ValidateObject(null)).WithAnyArguments().Returns(true); + + pool.BorrowObject(); + pool.Close(); + + A.CallTo(() => factory.DestroyObject(null)).WithAnyArguments().MustHaveHappened(); + } + + [Test] + public void WaitOnBorrowWhenExausted() + { + int n = 100; + object[] objects = new object[n]; + pool = new SimplePool(new MyFactory(), n); + for (int i = 0; i < n; i++) + { + objects[i] = pool.BorrowObject(); } - [Test] - public void DestroyObjectOnClose() - { - A.CallTo(() => factory.ValidateObject(null)).WithAnyArguments().Returns(true); + Latch latch = new Latch(); + ISync sync = new Latch(); + Helper helper = new Helper(latch, sync, pool); + Thread thread = new Thread(new ThreadStart(helper.UsePool)); + thread.Start(); + Assert.AreEqual(n, pool.NumActive); + Assert.AreEqual(0, pool.NumIdle); + object released = objects[n - 1]; + pool.ReturnObject(released); + latch.Acquire(); + Assert.AreEqual(n, pool.NumActive); + Assert.AreEqual(0, pool.NumIdle); + Assert.IsNotNull(helper.gotFromPool, "helper did not get from pool"); + Assert.AreSame(released, helper.gotFromPool, "got unexpected object"); + } +} - pool.BorrowObject(); - pool.Close(); - - A.CallTo(() => factory.DestroyObject(null)).WithAnyArguments().MustHaveHappened(); +[TestFixture] +public sealed class StessSimplePool +{ + public sealed class QueryPerformance + { + public interface IQueried + { + void Run(); } - [Test] - public void WaitOnBorrowWhenExausted() - { - int n = 100; - object[] objects = new object[n]; - pool = new SimplePool(new MyFactory(), n); - for (int i = 0; i < n; i++) - { - objects[i] = pool.BorrowObject(); - } - Latch latch = new Latch(); - ISync sync = new Latch(); - Helper helper = new Helper(latch, sync, pool); - Thread thread = new Thread(new ThreadStart(helper.UsePool)); - thread.Start(); - Assert.AreEqual(n, pool.NumActive); - Assert.AreEqual(0, pool.NumIdle); - object released = objects[n - 1]; - pool.ReturnObject(released); - latch.Acquire(); - Assert.AreEqual(n, pool.NumActive); - Assert.AreEqual(0, pool.NumIdle); - Assert.IsNotNull(helper.gotFromPool, "helper did not get from pool"); - Assert.AreSame(released, helper.gotFromPool, "got unexpected object"); - } - } + [DllImport("KERNEL32")] + private static extern bool QueryPerformanceCounter(ref long lpPerformanceCount); - [TestFixture] - public sealed class StessSimplePool - { - public sealed class QueryPerformance - { - public interface IQueried - { - void Run(); - } + [DllImport("KERNEL32")] + private static extern bool QueryPerformanceFrequency(ref long lpFrequency); - [DllImport("KERNEL32")] - private static extern bool QueryPerformanceCounter(ref long lpPerformanceCount); + public static float Query(IQueried queried) + { + long frequency = 0; + QueryPerformanceFrequency(ref frequency); - [DllImport("KERNEL32")] - private static extern bool QueryPerformanceFrequency(ref long lpFrequency); + long startTime = 0; + QueryPerformanceCounter(ref startTime); - public static float Query(IQueried queried) - { - long frequency = 0; - QueryPerformanceFrequency(ref frequency); + queried.Run(); - long startTime = 0; - QueryPerformanceCounter(ref startTime); + long endTime = 0; + QueryPerformanceCounter(ref endTime); - queried.Run(); + float elapsed = (float) (endTime - startTime) / frequency; + // Console.WriteLine("{0:0000.000}ms ", elapsed); + // Console.ReadLine(); + return elapsed; + } + } - long endTime = 0; - QueryPerformanceCounter(ref endTime); + private sealed class Pooled : IPoolableObjectFactory, QueryPerformance.IQueried + { + private int creationTime; + private int executionTime; - float elapsed = (float) (endTime - startTime)/frequency; - // Console.WriteLine("{0:0000.000}ms ", elapsed); - // Console.ReadLine(); - return elapsed; - } - } + public Pooled(int creationTime, int executionTime) + { + this.creationTime = creationTime; + this.executionTime = executionTime; + Thread.Sleep(creationTime); + } - private sealed class Pooled : IPoolableObjectFactory, QueryPerformance.IQueried - { - private int creationTime; - private int executionTime; + public void Run() + { + Thread.Sleep(executionTime); + } - public Pooled(int creationTime, int executionTime) - { - this.creationTime = creationTime; - this.executionTime = executionTime; - Thread.Sleep(creationTime); - } + public object MakeObject() + { + return new Pooled(creationTime, executionTime); + } - public void Run() - { - Thread.Sleep(executionTime); - } + public void DestroyObject(object o) + { + } - public object MakeObject() - { - return new Pooled(creationTime, executionTime); - } + public bool ValidateObject(object o) + { + return true; + } - public void DestroyObject(object o) - { - } + public void ActivateObject(object o) + { + } - public bool ValidateObject(object o) - { - return true; - } + public void PassivateObject(object o) + { + } + } - public void ActivateObject(object o) - { - } + private sealed class Client : QueryPerformance.IQueried + { + private int repeat; + private static int nRun = 0, created = 0; + private int id; + private ISync run; + private SimplePool pool; + public bool runned; - public void PassivateObject(object o) - { - } - } + public Client(int id, ISync run, SimplePool pool, int repeat) + { + this.run = run; + this.pool = pool; + this.id = id; + lock (this.GetType()) + { + created++; + //Console.Out.WriteLine("#{0} created (created/run: {1}/{2})...", id, created, nRun); + } - private sealed class Client : QueryPerformance.IQueried - { - private int repeat; - private static int nRun = 0, created = 0; - private int id; - private ISync run; - private SimplePool pool; - public bool runned; + this.repeat = repeat; + } - public Client(int id, ISync run, SimplePool pool, int repeat) - { - this.run = run; - this.pool = pool; - this.id = id; - lock (this.GetType()) - { - created++; - //Console.Out.WriteLine("#{0} created (created/run: {1}/{2})...", id, created, nRun); - } - this.repeat = repeat; - } + public void Run() + { + lock (this.GetType()) + { + //Console.Out.WriteLine("#{0} running (created/run: {1}/{2})...", id, created, nRun); + nRun++; + } - public void Run() - { - lock (this.GetType()) - { - //Console.Out.WriteLine("#{0} running (created/run: {1}/{2})...", id, created, nRun); - nRun++; - } - for (int i = 0; i < repeat; i++) - { - QueryPerformance.IQueried queried = pool.BorrowObject() as QueryPerformance.IQueried; - queried.Run(); - pool.ReturnObject(queried); - runned = true; - } - run.Release(); - } - } + for (int i = 0; i < repeat; i++) + { + QueryPerformance.IQueried queried = pool.BorrowObject() as QueryPerformance.IQueried; + queried.Run(); + pool.ReturnObject(queried); + runned = true; + } - private sealed class Job : QueryPerformance.IQueried - { - private int repeat; - private IList clients = new ArrayList(); - private int poolSize; - private int creationTime; - private int clientSize; - private ISync run; - private int executionTime; + run.Release(); + } + } - public Job(int size, int creationTime, int clientSize, ISync start, int executionTime, int repeat) - { - this.poolSize = size; - this.creationTime = creationTime; - this.clientSize = clientSize; - this.run = start; - this.executionTime = executionTime; - this.repeat = repeat; - } + private sealed class Job : QueryPerformance.IQueried + { + private int repeat; + private IList clients = new ArrayList(); + private int poolSize; + private int creationTime; + private int clientSize; + private ISync run; + private int executionTime; - public void Run() - { - SimplePool pool = new SimplePool(new Pooled(creationTime, executionTime), poolSize); - for (int i = 0; i < clientSize; i++) - { - Client client = new Client(i, run, pool, repeat); - Thread thread = new Thread(new ThreadStart(client.Run)); - thread.Start(); - clients.Add(client); - } - run.Acquire(); + public Job(int size, int creationTime, int clientSize, ISync start, int executionTime, int repeat) + { + this.poolSize = size; + this.creationTime = creationTime; + this.clientSize = clientSize; + this.run = start; + this.executionTime = executionTime; + this.repeat = repeat; + } - foreach (Client client in clients) - Assert.IsTrue(client.runned, "\nclient " + clients.IndexOf(client) + " not runned"); - } + public void Run() + { + SimplePool pool = new SimplePool(new Pooled(creationTime, executionTime), poolSize); + for (int i = 0; i < clientSize; i++) + { + Client client = new Client(i, run, pool, repeat); + Thread thread = new Thread(new ThreadStart(client.Run)); + thread.Start(); + clients.Add(client); + } - public static string Do(int poolSize, int clientSize, int executionTime, int repeat, int creationTime) - { - ISync start = new Spring.Threading.Semaphore(-(clientSize - 1)); - Job job = new Job(poolSize, creationTime, clientSize, start, executionTime, repeat); - float elapsed = QueryPerformance.Query(job); - return String.Format("{0}\t{1}\t{2}\t{3}\t{4}\t{5:0.000} ", - creationTime, executionTime, poolSize, clientSize, repeat, elapsed); - } - } + run.Acquire(); - [Test, Ignore("a try for a stress")] - public void ScalingAgainstIncreasingNumberOfThreads() - { - Console.Out.WriteLine("creationTime\texecutionTime\tpoolSize\tclientSize\trepeat\telapsed"); + foreach (Client client in clients) + Assert.IsTrue(client.runned, "\nclient " + clients.IndexOf(client) + " not runned"); + } - Console.Out.WriteLine("ramp pools size"); - Console.Out.WriteLine(Job.Do(10, 1000, 100, 1, 1)); - Console.Out.WriteLine(Job.Do(100, 1000, 100, 1, 1)); - Console.Out.WriteLine(Job.Do(200, 1000, 100, 1, 1)); - Console.Out.WriteLine(Job.Do(500, 1000, 100, 1, 1)); - Console.Out.WriteLine(Job.Do(1000, 1000, 100, 1, 1)); + public static string Do(int poolSize, int clientSize, int executionTime, int repeat, int creationTime) + { + ISync start = new Spring.Threading.Semaphore(-(clientSize - 1)); + Job job = new Job(poolSize, creationTime, clientSize, start, executionTime, repeat); + float elapsed = QueryPerformance.Query(job); + return String.Format("{0}\t{1}\t{2}\t{3}\t{4}\t{5:0.000} ", + creationTime, executionTime, poolSize, clientSize, repeat, elapsed); + } + } - Console.Out.WriteLine("ramp client size"); - Console.Out.WriteLine(Job.Do(10, 10, 100, 1, 1)); - Console.Out.WriteLine(Job.Do(10, 100, 100, 1, 1)); - Console.Out.WriteLine(Job.Do(10, 200, 100, 1, 1)); - Console.Out.WriteLine(Job.Do(10, 1000, 100, 1, 1)); + [Test, Ignore("a try for a stress")] + public void ScalingAgainstIncreasingNumberOfThreads() + { + Console.Out.WriteLine("creationTime\texecutionTime\tpoolSize\tclientSize\trepeat\telapsed"); - Console.Out.WriteLine("ramp load"); - Console.Out.WriteLine(Job.Do(10, 10, 100, 1, 1)); - Console.Out.WriteLine(Job.Do(10, 10, 100, 5, 1)); - Console.Out.WriteLine(Job.Do(10, 10, 100, 10, 1)); - Console.Out.WriteLine(Job.Do(10, 10, 100, 50, 1)); - Console.Out.WriteLine(Job.Do(10, 10, 100, 100, 1)); + Console.Out.WriteLine("ramp pools size"); + Console.Out.WriteLine(Job.Do(10, 1000, 100, 1, 1)); + Console.Out.WriteLine(Job.Do(100, 1000, 100, 1, 1)); + Console.Out.WriteLine(Job.Do(200, 1000, 100, 1, 1)); + Console.Out.WriteLine(Job.Do(500, 1000, 100, 1, 1)); + Console.Out.WriteLine(Job.Do(1000, 1000, 100, 1, 1)); - Console.Out.WriteLine("ramp client size - 2"); - Console.Out.WriteLine(Job.Do(10, 1, 100, 1, 1)); - Console.Out.WriteLine(Job.Do(10, 5, 100, 5, 1)); - Console.Out.WriteLine(Job.Do(10, 10, 100, 10, 1)); - Console.Out.WriteLine(Job.Do(10, 50, 100, 50, 1)); - Console.Out.WriteLine(Job.Do(10, 100, 100, 100, 1)); - Console.Out.WriteLine(Job.Do(10, 1000, 100, 100, 1)); - } - } -} \ No newline at end of file + Console.Out.WriteLine("ramp client size"); + Console.Out.WriteLine(Job.Do(10, 10, 100, 1, 1)); + Console.Out.WriteLine(Job.Do(10, 100, 100, 1, 1)); + Console.Out.WriteLine(Job.Do(10, 200, 100, 1, 1)); + Console.Out.WriteLine(Job.Do(10, 1000, 100, 1, 1)); + + Console.Out.WriteLine("ramp load"); + Console.Out.WriteLine(Job.Do(10, 10, 100, 1, 1)); + Console.Out.WriteLine(Job.Do(10, 10, 100, 5, 1)); + Console.Out.WriteLine(Job.Do(10, 10, 100, 10, 1)); + Console.Out.WriteLine(Job.Do(10, 10, 100, 50, 1)); + Console.Out.WriteLine(Job.Do(10, 10, 100, 100, 1)); + + Console.Out.WriteLine("ramp client size - 2"); + Console.Out.WriteLine(Job.Do(10, 1, 100, 1, 1)); + Console.Out.WriteLine(Job.Do(10, 5, 100, 5, 1)); + Console.Out.WriteLine(Job.Do(10, 10, 100, 10, 1)); + Console.Out.WriteLine(Job.Do(10, 50, 100, 50, 1)); + Console.Out.WriteLine(Job.Do(10, 100, 100, 100, 1)); + Console.Out.WriteLine(Job.Do(10, 1000, 100, 100, 1)); + } +} diff --git a/test/Spring/Spring.Core.Tests/Proxy/AbstractProxyTypeBuilderTests.cs b/test/Spring/Spring.Core.Tests/Proxy/AbstractProxyTypeBuilderTests.cs index afed6b5c..73403a5d 100644 --- a/test/Spring/Spring.Core.Tests/Proxy/AbstractProxyTypeBuilderTests.cs +++ b/test/Spring/Spring.Core.Tests/Proxy/AbstractProxyTypeBuilderTests.cs @@ -18,1036 +18,1053 @@ using System.Reflection; using System.Reflection.Emit; using System.Collections; using System.Runtime.InteropServices; - using NUnit.Framework; - using Spring.Objects; using Spring.Util; -namespace Spring.Proxy +namespace Spring.Proxy; + +/// +/// A base set of unit tests for the various AbstractProxyTypeBuilder subclasses. +/// +/// Rick Evans +/// Bruno Baia +public abstract class AbstractProxyTypeBuilderTests { - /// - /// A base set of unit tests for the various AbstractProxyTypeBuilder subclasses. - /// - /// Rick Evans - /// Bruno Baia - public abstract class AbstractProxyTypeBuilderTests + [Test] + public void GeneratesProxyNameIfNoneExplicitlySupplied() { - [Test] - public void GeneratesProxyNameIfNoneExplicitlySupplied() - { - IProxyTypeBuilder builder = GetProxyBuilder(); - Assert.IsNotNull(builder.Name); - } - - [Test] - public void DoesNotGenerateProxyNameIfOneIsExplicitlySupplied() - { - IProxyTypeBuilder builder = GetProxyBuilder(); - builder.Name = "Bing"; - Assert.AreEqual("Bing", builder.Name); - } - - [Test] - public void AppliesAttributeToType() - { - IProxyTypeBuilder builder = GetProxyBuilder(); - builder.TargetType = typeof(MarkerClass); - builder.TypeAttributes = new Attribute[] { new MarkerAttribute() }; - - Type proxy = builder.BuildProxyType(); - Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); - - object[] atts = proxy.GetCustomAttributes(false); - Assert.IsNotNull(atts, "Should have had 1 custom attribute applied to the generated proxy type."); - Assert.AreEqual(1, atts.Length, "Should have had 1 custom attribute applied to the generated proxy type."); - Assert.AreEqual(typeof(MarkerAttribute), atts[0].GetType(), "Wrong System.Type of Attribute applied to the generated proxy type."); - } - - [Test] - public void AppliesStarredMemberAttributesToAllMethods() - { - IProxyTypeBuilder builder = GetProxyBuilder(); - builder.TargetType = typeof(TargetObjectTest); - IDictionary atts = new Hashtable(); - string methodPrefix = typeof(ITargetObjectTest).FullName + "."; - atts.Add("*", new Attribute[] { new MarkerAttribute() }); - builder.MemberAttributes = atts; - Type proxy = builder.BuildProxyType(); - object foo = Activator.CreateInstance(proxy); - - Type fooType = foo.GetType(); - MethodInfo method = ReflectionUtils.GetMethod(fooType, methodPrefix + "InterfaceMethodWithArguments", new Type[] { typeof(string) }); - object[] appliedAttributes = method.GetCustomAttributes(false); - Assert.AreEqual(1, appliedAttributes.Length, - "Custom attribute not applied to member method."); - method = ReflectionUtils.GetMethod(fooType, methodPrefix + "InterfaceVirtualMethodWithNoArguments", Type.EmptyTypes); - appliedAttributes = method.GetCustomAttributes(false); - Assert.AreEqual(1, appliedAttributes.Length, - "Custom attribute not applied to member method."); - } - - [Test] - public void AppliesSpecificMemberAttributesToSpecificMethodOnly() - { - IProxyTypeBuilder builder = GetProxyBuilder(); - builder.TargetType = typeof(TargetObjectTest); - IDictionary atts = new Hashtable(); - atts.Add("InterfaceVirtualMethodWithNoArguments", new Attribute[] { new MarkerAttribute() }); - builder.MemberAttributes = atts; - - Type proxy = builder.BuildProxyType(); - object foo = Activator.CreateInstance(proxy); - - Type fooType = foo.GetType(); - MethodInfo method = ReflectionUtils.GetMethod(fooType, "InterfaceMethodWithArguments", new Type[] { typeof(string) }); - if (method == null) - { - method = ReflectionUtils.GetMethod(fooType, "Spring.Proxy.ITargetObjectTest.InterfaceMethodWithArguments", new Type[] { typeof(string) }); - } - object[] appliedAttributes = method.GetCustomAttributes(false); - Assert.AreEqual(0, appliedAttributes.Length, - "Custom attribute (erroneously) applied to member method."); - method = ReflectionUtils.GetMethod(fooType, "InterfaceVirtualMethodWithNoArguments", Type.EmptyTypes); - if (method == null) - { - method = ReflectionUtils.GetMethod(fooType, "Spring.Proxy.ITargetObjectTest.InterfaceVirtualMethodWithNoArguments", Type.EmptyTypes); - } - appliedAttributes = method.GetCustomAttributes(false); - Assert.AreEqual(1, appliedAttributes.Length, - "Custom attribute not applied to member method."); - } - - [Test] - // SPRNET-1262 - public void AppliesSpecificTypeAttributeWithNoPropertySettersToTargetTypeUsingCustomAttributeBuilder() - { - ConstructorInfo ci = typeof(FakeServiceKnownTypeAttribute).GetConstructor(new Type[] { typeof(Type) }); - CustomAttributeBuilder cab = new CustomAttributeBuilder(ci, new object[] { typeof(TestObject) }); - - IProxyTypeBuilder builder = GetProxyBuilder(); - builder.TargetType = typeof(ClassWithFakeServiceKnownTypeAttribute); - builder.TypeAttributes.Add(cab); - - Type proxy = builder.BuildProxyType(); - Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); - - object[] attrs = proxy.GetCustomAttributes(false); - Assert.IsNotNull(attrs, "Should have had 1 attribute applied to the target type."); - Assert.AreEqual(1, attrs.Length, "Should have had 1 attribute applied to the target type."); - Assert.AreEqual(typeof(FakeServiceKnownTypeAttribute), attrs[0].GetType(), "Wrong System.Type of Attribute applied to the target type."); - - FakeServiceKnownTypeAttribute fgsta = attrs[0] as FakeServiceKnownTypeAttribute; - Assert.AreEqual(typeof(TestObject), fgsta.Type, "Property 'Type' on Target Attribute not set!"); - } - - [Test] - public void ImplementsInterfaceHierarchy() - { - IProxyTypeBuilder builder = GetProxyBuilder(); - builder.TargetType = typeof(MultipleInterfaces); - - Type proxy = builder.BuildProxyType(); - Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); - - object foo = Activator.CreateInstance(proxy); - Assert.IsTrue(foo is IBase); - Assert.IsTrue(foo is IInherited); - - // try to call proxied interface methods - ((IBase)foo).Base(); - ((IInherited)foo).Base(); - ((IInherited)foo).Inherited(); - } - - [Test] - public void ProxySpecificTargetTypeAttributeWithReadOnlyProperty() - { - IProxyTypeBuilder builder = GetProxyBuilder(); - builder.TargetType = typeof(ClassWithGuidAttribute); - - Type proxy = builder.BuildProxyType(); - Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); - - object[] attrs = proxy.GetCustomAttributes(false); - Assert.IsNotNull(attrs, "Should have had 1 attribute applied to the target type."); - Assert.AreEqual(1, attrs.Length, "Should have had 1 attribute applied to the target type."); - Assert.AreEqual(typeof(GuidAttribute), attrs[0].GetType(), "Wrong System.Type of Attribute applied to the target type."); - - GuidAttribute ga = attrs[0] as GuidAttribute; - Assert.AreEqual("7cfc9607-e81a-48ac-a080-bda88193607b", ga.Value); - } - - [Test] - public void ProxySpecificTargetTypeAttributeWithPropertySetterChangingDefaultBehavior() - { - IProxyTypeBuilder builder = GetProxyBuilder(); - builder.TargetType = typeof(ClassWithFakeXmlElementAttribute); - Type proxy = builder.BuildProxyType(); - Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); - MethodInfo method = proxy.GetMethod("Spring.Proxy.ISomeMarkerInterface.MarkerMethod", BindingFlags.NonPublic | BindingFlags.Instance); - if (method == null) - { - method = proxy.GetMethod("MarkerMethod"); - } - Assert.IsNotNull(method); - object[] attrs = method.GetParameters()[0].GetCustomAttributes(false); - Assert.IsNotNull(method); - Assert.IsNotNull(attrs, "Should have 1 attribute applied to the target method."); - Assert.AreEqual(1, attrs.Length, "Should have 1 attribute applied to the target method."); - Assert.AreEqual(typeof(FakeXmlElementAttribute), attrs[0].GetType(), "Wrong System.Type of Attribute applied to the target method."); - - FakeXmlElementAttribute xea = attrs[0] as FakeXmlElementAttribute; - Assert.AreEqual(-1, xea.Order); - } - - [Test] - public void ProxySpecificTargetTypeAttributeNotInstantiableWithDefaultValues() - { - IProxyTypeBuilder builder = GetProxyBuilder(); - builder.TargetType = typeof(ClassWithFakeGenerateScriptTypeAttribute); - - Type proxy = builder.BuildProxyType(); - Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); - - object[] attrs = proxy.GetCustomAttributes(false); - Assert.IsNotNull(attrs, "Should have had 1 attribute applied to the target type."); - Assert.AreEqual(1, attrs.Length, "Should have had 1 attribute applied to the target type."); - Assert.AreEqual(typeof(FakeGenerateScriptTypeAttribute), attrs[0].GetType(), "Wrong System.Type of Attribute applied to the target type."); - - FakeGenerateScriptTypeAttribute fgsta = attrs[0] as FakeGenerateScriptTypeAttribute; - Assert.AreEqual("ScriptName", fgsta.Name); - } - - // http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=296032 - // should not fail - // Not fixed by .NET 2.0 SP1. - [Test] - public void ProxySpecificTargetTypeAttributeWithPublicEnumProperty() - { - IProxyTypeBuilder builder = GetProxyBuilder(); - builder.TargetType = typeof(ClassWithPublicEnumPropertyAttribute); - Type proxy = builder.BuildProxyType(); - Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); - MethodInfo method = proxy.GetMethod("Spring.Proxy.ISomeMarkerInterface.MarkerMethod", BindingFlags.NonPublic | BindingFlags.Instance); - if (method == null) - { - method = proxy.GetMethod("MarkerMethod"); - } - Assert.IsNotNull(method); - object[] attrs = method.GetCustomAttributes(false); - Assert.IsNotNull(attrs, "Should have 1 attribute applied to the target method."); - Assert.AreEqual(1, attrs.Length, "Should have 1 attribute applied to the target method."); - Assert.AreEqual(typeof(PublicEnumPropertyAttribute), attrs[0].GetType(), "Wrong System.Type of Attribute applied to the target method."); - - PublicEnumPropertyAttribute pepa = attrs[0] as PublicEnumPropertyAttribute; - Assert.AreEqual(AttributeTargets.All, pepa.Data); - } - -#if !NETCOREAPP - // http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=161522 - // should not fail - // Use CustomAttributeData if patch applied (.NET 2.0 SP1). - // Use Attribute instance if patch not applied (.NET 2.0 SP1). - [Test] - public void ProxyWebServiceAttribute() - { - IProxyTypeBuilder builder = GetProxyBuilder(); - builder.TargetType = typeof(ClassWithWebServiceAttribute); - - Type proxy = builder.BuildProxyType(); - Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); - - object[] attrs = proxy.GetCustomAttributes(false); - Assert.IsNotNull(attrs, "Should have had 1 attribute applied to the target type."); - Assert.AreEqual(1, attrs.Length, "Should have had 1 attribute applied to the target type."); - Assert.AreEqual(typeof(System.Web.Services.WebServiceAttribute), attrs[0].GetType(), "Wrong System.Type of Attribute applied to the target type."); - - var wsa = attrs[0] as System.Web.Services.WebServiceAttribute; - Assert.AreEqual("blah", wsa.Name); - Assert.AreEqual("http://mynamespace.com", wsa.Namespace); - } -#endif - -#if !MONO && !NETCOREAPP - // http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=94803 - [Test] - [Platform("Win")] - public void ProxySecurityAttribute() - { - IProxyTypeBuilder builder = GetProxyBuilder(); - builder.TargetType = typeof(ClassWithSecurityAttribute); - - Type proxy = builder.BuildProxyType(); - Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); - - object[] attrs = proxy.GetCustomAttributes(false); - Assert.IsNotNull(attrs, "Should have had 2 attribute applied to the target type."); - Assert.AreEqual(2, attrs.Length, "Should have had 2 attribute applied to the target type."); - } -#endif - - [Test] - public void ProxySpecificTargetTypeAttributeWithArrayConstructor() - { - IProxyTypeBuilder builder = GetProxyBuilder(); - builder.TargetType = typeof(ClassWithArrayConstructorAttribute); - Type proxy = builder.BuildProxyType(); - Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); - - MethodInfo method = proxy.GetMethod("Spring.Proxy.ISomeMarkerInterface.MarkerMethod", BindingFlags.NonPublic | BindingFlags.Instance); - if (method == null) - { - method = proxy.GetMethod("MarkerMethod"); - } - Assert.IsNotNull(method); - object[] attrs = method.GetCustomAttributes(false); - Assert.IsNotNull(attrs, "Should have 1 attribute applied to the target method."); - Assert.AreEqual(1, attrs.Length, "Should have 1 attribute applied to the target method."); - Assert.AreEqual(typeof(ArrayConstructorPropertyAttribute), attrs[0].GetType(), "Wrong System.Type of Attribute applied to the target method."); - - ArrayConstructorPropertyAttribute acpa = attrs[0] as ArrayConstructorPropertyAttribute; - Assert.AreEqual(false, acpa.ReadOnly); - Assert.AreEqual(1, acpa.Types.Length); - Assert.AreEqual(typeof(string), acpa.Types[0]); - } - - [Test] - public void ProxySpecificTargetTypeAttributeWithArrayProperty() - { - IProxyTypeBuilder builder = GetProxyBuilder(); - builder.TargetType = typeof(ClassWithArrayPropertyAttribute); - Type proxy = builder.BuildProxyType(); - Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); - - MethodInfo method = proxy.GetMethod("Spring.Proxy.IAnotherMarkerInterface.MarkerMethod", BindingFlags.NonPublic | BindingFlags.Instance); - if (method == null) - { - method = proxy.GetMethod("MarkerMethod"); - } - Assert.IsNotNull(method); - object[] attrs = method.GetCustomAttributes(false); - Assert.IsNotNull(attrs, "Should have 1 attribute applied to the target method."); - Assert.AreEqual(1, attrs.Length, "Should have 1 attribute applied to the target method."); - Assert.AreEqual(typeof(ArrayConstructorPropertyAttribute), attrs[0].GetType(), "Wrong System.Type of Attribute applied to the target method."); - - ArrayConstructorPropertyAttribute acpa = attrs[0] as ArrayConstructorPropertyAttribute; - Assert.AreEqual(true, acpa.ReadOnly); - Assert.AreEqual(2, acpa.Types.Length); - Assert.AreEqual(typeof(int), acpa.Types[0]); - Assert.AreEqual(typeof(string), acpa.Types[1]); - } - - [Test] - public void ProxyTargetTypeAttributes() - { - IProxyTypeBuilder builder = GetProxyBuilder(); - builder.TargetType = typeof(AnotherMarkerClass); - Type proxy = builder.BuildProxyType(); - Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); - object[] attrs = proxy.GetCustomAttributes(false); - Assert.IsNotNull(attrs, "Should have had 1 attribute applied to the target type."); - Assert.AreEqual(1, attrs.Length, "Should have had 1 attribute applied to the target type."); - Assert.AreEqual(typeof(MarkerAttribute), attrs[0].GetType(), "Wrong System.Type of Attribute applied to the target type."); - } - - [Test] - public void DoesNotProxyTargetTypeAttributesWithProxyTargetAttributesEqualsFalse() - { - IProxyTypeBuilder builder = GetProxyBuilder(); - builder.TargetType = typeof(AnotherMarkerClass); - builder.ProxyTargetAttributes = false; - Type proxy = builder.BuildProxyType(); - Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); - object[] attrs = proxy.GetCustomAttributes(false); - Assert.IsNotNull(attrs); - Assert.AreEqual(0, attrs.Length, "Should not have attribute applied to the target type."); - } - - [Test] - public void ProxyTargetMethodAttributes() - { - IProxyTypeBuilder builder = GetProxyBuilder(); - builder.TargetType = typeof(AnotherMarkerClass); - Type proxy = builder.BuildProxyType(); - Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); - MethodInfo method = proxy.GetMethod("Spring.Proxy.IAnotherMarkerInterface.MarkerMethod", BindingFlags.NonPublic | BindingFlags.Instance); - if (method == null) - { - method = proxy.GetMethod("MarkerMethod"); - } - Assert.IsNotNull(method); - object[] attrs = method.GetCustomAttributes(false); - Assert.IsNotNull(attrs, "Should have 1 attribute applied to the target method."); - Assert.AreEqual(1, attrs.Length, "Should have 1 attribute applied to the target method."); - Assert.AreEqual(typeof(MarkerAttribute), attrs[0].GetType(), "Wrong System.Type of Attribute applied to the target method."); - } - - [Test] - public void DoesNotProxyTargetMethodAttributesWithProxyTargetAttributesEqualsFalse() - { - IProxyTypeBuilder builder = GetProxyBuilder(); - builder.TargetType = typeof(AnotherMarkerClass); - builder.ProxyTargetAttributes = false; - Type proxy = builder.BuildProxyType(); - Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); - MethodInfo method = proxy.GetMethod("Spring.Proxy.IAnotherMarkerInterface.MarkerMethod", BindingFlags.NonPublic | BindingFlags.Instance); - if (method == null) - { - method = proxy.GetMethod("MarkerMethod"); - } - Assert.IsNotNull(method); - object[] attrs = method.GetCustomAttributes(false); - Assert.IsNotNull(attrs); - Assert.AreEqual(0, attrs.Length, "Should not have attribute applied to the target method."); - } - - [Test] - public void ProxyTargetMethodParameterAttributes() - { - IProxyTypeBuilder builder = GetProxyBuilder(); - builder.TargetType = typeof(SomeMarkerClass); - Type proxy = builder.BuildProxyType(); - Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); - MethodInfo method = proxy.GetMethod("Spring.Proxy.ISomeMarkerInterface.MarkerMethod", BindingFlags.NonPublic | BindingFlags.Instance); - if (method == null) - { - method = proxy.GetMethod("MarkerMethod"); - } - Assert.IsNotNull(method); - object[] attrs = method.GetParameters()[1].GetCustomAttributes(false); - Assert.IsNotNull(attrs, "Should have had 1 attribute applied to the method's parameter."); - Assert.AreEqual(1, attrs.Length, "Should have had 1 attribute applied to the method's parameter."); - Assert.AreEqual(typeof(MarkerAttribute), attrs[0].GetType(), "Wrong System.Type of Attribute applied to the method's parameter."); - } - - [Test] - [Description("SPRNET-1134")] - public void ProxyTargetMethodParameterMultipleAttributes() - { - IProxyTypeBuilder builder = GetProxyBuilder(); - builder.TargetType = typeof(MultipleMarkerClass); - Type proxy = builder.BuildProxyType(); - Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); - MethodInfo method = proxy.GetMethod("Spring.Proxy.ISomeMarkerInterface.MarkerMethod", BindingFlags.NonPublic | BindingFlags.Instance); - if (method == null) - { - method = proxy.GetMethod("MarkerMethod"); - } - Assert.IsNotNull(method); - object[] attrs = method.GetParameters()[1].GetCustomAttributes(false); - Assert.IsNotNull(attrs, "Should have had 2 attributes applied to the method's parameter."); - Assert.AreEqual(2, attrs.Length, "Should have had 2 attributes applied to the method's parameter."); - Assert.AreEqual(typeof(MarkerAttribute), attrs[0].GetType(), "Wrong System.Type of Attribute applied to the method's parameter."); - Assert.AreEqual(typeof(MarkerAttribute), attrs[1].GetType(), "Wrong System.Type of Attribute applied to the method's parameter."); - } - - [Test] - public void DoesNotProxyTargetMethodParameterAttributesWithProxyTargetAttributesEqualsFalse() - { - IProxyTypeBuilder builder = GetProxyBuilder(); - builder.TargetType = typeof(SomeMarkerClass); - builder.ProxyTargetAttributes = false; - Type proxy = builder.BuildProxyType(); - Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); - MethodInfo method = proxy.GetMethod("Spring.Proxy.ISomeMarkerInterface.MarkerMethod", BindingFlags.NonPublic | BindingFlags.Instance); - if (method == null) - { - method = proxy.GetMethod("MarkerMethod"); - } - Assert.IsNotNull(method); - object[] attrs = method.GetParameters()[1].GetCustomAttributes(false); - Assert.IsNotNull(attrs); - Assert.AreEqual(0, attrs.Length, "Should not have attribute applied to the method's parameter."); - } - - [Test] - public void ProxyTargetMethodReturnValueAttributes() - { - IProxyTypeBuilder builder = GetProxyBuilder(); - builder.TargetType = typeof(SomeMarkerClass); - Type proxy = builder.BuildProxyType(); - Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); - MethodInfo method = proxy.GetMethod("Spring.Proxy.ISomeMarkerInterface.MarkerMethod", BindingFlags.NonPublic | BindingFlags.Instance); - if (method == null) - { - method = proxy.GetMethod("MarkerMethod"); - } - Assert.IsNotNull(method); - object[] attrs = method.ReturnTypeCustomAttributes.GetCustomAttributes(false); - Assert.IsNotNull(attrs, "Should have had 1 attribute applied to the method's return value."); - Assert.AreEqual(1, attrs.Length, "Should have had 1 attribute applied to the method's return value."); - Assert.AreEqual(typeof(MarkerAttribute), attrs[0].GetType(), "Wrong System.Type of Attribute applied to the method's return value."); - } - - [Test] - [Description("SPRNET-1134")] - public void ProxyTargetMethodReturnValueMultipleAttributes() - { - IProxyTypeBuilder builder = GetProxyBuilder(); - builder.TargetType = typeof(MultipleMarkerClass); - Type proxy = builder.BuildProxyType(); - Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); - MethodInfo method = proxy.GetMethod("Spring.Proxy.ISomeMarkerInterface.MarkerMethod", BindingFlags.NonPublic | BindingFlags.Instance); - if (method == null) - { - method = proxy.GetMethod("MarkerMethod"); - } - Assert.IsNotNull(method); - object[] attrs = method.ReturnTypeCustomAttributes.GetCustomAttributes(false); - Assert.IsNotNull(attrs, "Should have had 2 attribute applied to the method's return value."); - Assert.AreEqual(2, attrs.Length, "Should have had 2 attribute applied to the method's return value."); - Assert.AreEqual(typeof(MarkerAttribute), attrs[0].GetType(), "Wrong System.Type of Attribute applied to the method's return value."); - Assert.AreEqual(typeof(MarkerAttribute), attrs[1].GetType(), "Wrong System.Type of Attribute applied to the method's return value."); - } - - [Test] - public void DoesNotProxyTargetMethodReturnValueAttributesWithProxyTargetAttributesEqualsFalse() - { - IProxyTypeBuilder builder = GetProxyBuilder(); - builder.TargetType = typeof(SomeMarkerClass); - builder.ProxyTargetAttributes = false; - Type proxy = builder.BuildProxyType(); - Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); - MethodInfo method = proxy.GetMethod("Spring.Proxy.ISomeMarkerInterface.MarkerMethod", BindingFlags.NonPublic | BindingFlags.Instance); - if (method == null) - { - method = proxy.GetMethod("MarkerMethod"); - } - Assert.IsNotNull(method); - object[] attrs = method.ReturnTypeCustomAttributes.GetCustomAttributes(false); - Assert.IsNotNull(attrs); - Assert.AreEqual(0, attrs.Length, "Should not have attribute applied to the method's return value."); - } - - [Test] - public void ProxyGenericMethod() - { - IProxyTypeBuilder builder = GetProxyBuilder(); - builder.TargetType = typeof(ClassWithGenericMethod); - - Type proxy = builder.BuildProxyType(); - Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); - - InterfaceWithGenericMethod foo = Activator.CreateInstance(proxy) as InterfaceWithGenericMethod; - Assert.IsNotNull(foo); - - foo.PolymorphicMethod(); - - string result1 = foo.PolymorphicMethod("coucou"); - Assert.AreEqual("coucou", result1); - - foo.WithGenericParameter(); - - foo.WithGenericParameterAndGenericArgument("ola"); - - string result2 = foo.WithGenericParameterAndGenericArgumentAndGenericReturnType("ola"); - Assert.AreEqual("ola", result2); - - foo.WithInterfaceConstraint(); - - foo.WithBaseTypeConstraint(); - - foo.WithBaseTypeAndInterfaceConstraints(); - - foo.WithMixedConstraint(); - } - - public interface InterfaceWithGenericMethod - { - void PolymorphicMethod(); - - string PolymorphicMethod(string param); - - void WithGenericParameter(); - - void WithGenericParameterAndGenericArgument(T obj); - - T WithGenericParameterAndGenericArgumentAndGenericReturnType(T obj); - - void WithInterfaceConstraint() where Z : IComparable; - - void WithBaseTypeConstraint() where Z : TestObject; - - void WithBaseTypeAndInterfaceConstraints() where Z : TestObject, IComparable, IDisposable; - - void WithMixedConstraint() - where X : IComparable, new() - where Y : TestObject; - } - - public class ClassWithGenericMethod : InterfaceWithGenericMethod - { - public void PolymorphicMethod() { } - - public string PolymorphicMethod(string param) - { - return param; - } - - public void WithGenericParameter() { } - - public void WithGenericParameterAndGenericArgument(T obj) { } - - public T WithGenericParameterAndGenericArgumentAndGenericReturnType(T obj) - { - return obj; - } - - public void WithInterfaceConstraint() where Z : IComparable { } - - public void WithBaseTypeConstraint() where Z : TestObject { } - - public void WithBaseTypeAndInterfaceConstraints() where Z : TestObject, IComparable, IDisposable { } - - public void WithMixedConstraint() - where X : IComparable, new() - where Y : TestObject - { } - } - - [Test] - public void ProxyGenericInterface() - { - IProxyTypeBuilder builder = GetProxyBuilder(); - builder.TargetType = typeof(ClassThatImplementsGenericInterface); - - Type proxy = builder.BuildProxyType(); - Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); - - GenericInterface foo = Activator.CreateInstance(proxy) as GenericInterface; - Assert.IsNotNull(foo); - - TestObject to1 = foo.Create(); - Assert.IsNotNull(to1); - - TestObject to2 = foo.Populate(new TestObject()); - Assert.IsNotNull(to2); - Assert.AreEqual("Populated", to2.Name); - } - - public interface GenericInterface - where T : ITestObject, new() - { - T Create(); - - T Populate(T testObject); - } - - public class ClassThatImplementsGenericInterface : GenericInterface - where T : ITestObject, new() - { - public T Create() - { - return new T(); - } - - public T Populate(T testObject) - { - testObject.Name = "Populated"; - - return testObject; - } - } - - protected abstract IProxyTypeBuilder GetProxyBuilder(); - - public interface InnerInterface - { - } - - public class InnerClass : InnerInterface - { - } + IProxyTypeBuilder builder = GetProxyBuilder(); + Assert.IsNotNull(builder.Name); } - public class DoesntImplementAnyInterfaces + [Test] + public void DoesNotGenerateProxyNameIfOneIsExplicitlySupplied() { + IProxyTypeBuilder builder = GetProxyBuilder(); + builder.Name = "Bing"; + Assert.AreEqual("Bing", builder.Name); } - public interface IMarkerInterface + [Test] + public void AppliesAttributeToType() { + IProxyTypeBuilder builder = GetProxyBuilder(); + builder.TargetType = typeof(MarkerClass); + builder.TypeAttributes = new Attribute[] { new MarkerAttribute() }; + + Type proxy = builder.BuildProxyType(); + Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); + + object[] atts = proxy.GetCustomAttributes(false); + Assert.IsNotNull(atts, "Should have had 1 custom attribute applied to the generated proxy type."); + Assert.AreEqual(1, atts.Length, "Should have had 1 custom attribute applied to the generated proxy type."); + Assert.AreEqual(typeof(MarkerAttribute), atts[0].GetType(), "Wrong System.Type of Attribute applied to the generated proxy type."); } - public class MarkerClass : IMarkerInterface + [Test] + public void AppliesStarredMemberAttributesToAllMethods() { + IProxyTypeBuilder builder = GetProxyBuilder(); + builder.TargetType = typeof(TargetObjectTest); + IDictionary atts = new Hashtable(); + string methodPrefix = typeof(ITargetObjectTest).FullName + "."; + atts.Add("*", new Attribute[] { new MarkerAttribute() }); + builder.MemberAttributes = atts; + Type proxy = builder.BuildProxyType(); + object foo = Activator.CreateInstance(proxy); + + Type fooType = foo.GetType(); + MethodInfo method = ReflectionUtils.GetMethod(fooType, methodPrefix + "InterfaceMethodWithArguments", new Type[] { typeof(string) }); + object[] appliedAttributes = method.GetCustomAttributes(false); + Assert.AreEqual(1, appliedAttributes.Length, + "Custom attribute not applied to member method."); + method = ReflectionUtils.GetMethod(fooType, methodPrefix + "InterfaceVirtualMethodWithNoArguments", Type.EmptyTypes); + appliedAttributes = method.GetCustomAttributes(false); + Assert.AreEqual(1, appliedAttributes.Length, + "Custom attribute not applied to member method."); } - [GuidAttribute("7cfc9607-e81a-48ac-a080-bda88193607b")] - public class ClassWithGuidAttribute : IMarkerInterface + [Test] + public void AppliesSpecificMemberAttributesToSpecificMethodOnly() { + IProxyTypeBuilder builder = GetProxyBuilder(); + builder.TargetType = typeof(TargetObjectTest); + IDictionary atts = new Hashtable(); + atts.Add("InterfaceVirtualMethodWithNoArguments", new Attribute[] { new MarkerAttribute() }); + builder.MemberAttributes = atts; + + Type proxy = builder.BuildProxyType(); + object foo = Activator.CreateInstance(proxy); + + Type fooType = foo.GetType(); + MethodInfo method = ReflectionUtils.GetMethod(fooType, "InterfaceMethodWithArguments", new Type[] { typeof(string) }); + if (method == null) + { + method = ReflectionUtils.GetMethod(fooType, "Spring.Proxy.ITargetObjectTest.InterfaceMethodWithArguments", new Type[] { typeof(string) }); + } + + object[] appliedAttributes = method.GetCustomAttributes(false); + Assert.AreEqual(0, appliedAttributes.Length, + "Custom attribute (erroneously) applied to member method."); + method = ReflectionUtils.GetMethod(fooType, "InterfaceVirtualMethodWithNoArguments", Type.EmptyTypes); + if (method == null) + { + method = ReflectionUtils.GetMethod(fooType, "Spring.Proxy.ITargetObjectTest.InterfaceVirtualMethodWithNoArguments", Type.EmptyTypes); + } + + appliedAttributes = method.GetCustomAttributes(false); + Assert.AreEqual(1, appliedAttributes.Length, + "Custom attribute not applied to member method."); } - [Marker] - public interface IAnotherMarkerInterface + [Test] + // SPRNET-1262 + public void AppliesSpecificTypeAttributeWithNoPropertySettersToTargetTypeUsingCustomAttributeBuilder() { - [Marker] - void MarkerMethod(); + ConstructorInfo ci = typeof(FakeServiceKnownTypeAttribute).GetConstructor(new Type[] { typeof(Type) }); + CustomAttributeBuilder cab = new CustomAttributeBuilder(ci, new object[] { typeof(TestObject) }); + + IProxyTypeBuilder builder = GetProxyBuilder(); + builder.TargetType = typeof(ClassWithFakeServiceKnownTypeAttribute); + builder.TypeAttributes.Add(cab); + + Type proxy = builder.BuildProxyType(); + Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); + + object[] attrs = proxy.GetCustomAttributes(false); + Assert.IsNotNull(attrs, "Should have had 1 attribute applied to the target type."); + Assert.AreEqual(1, attrs.Length, "Should have had 1 attribute applied to the target type."); + Assert.AreEqual(typeof(FakeServiceKnownTypeAttribute), attrs[0].GetType(), "Wrong System.Type of Attribute applied to the target type."); + + FakeServiceKnownTypeAttribute fgsta = attrs[0] as FakeServiceKnownTypeAttribute; + Assert.AreEqual(typeof(TestObject), fgsta.Type, "Property 'Type' on Target Attribute not set!"); } - public interface ISomeMarkerInterface + [Test] + public void ImplementsInterfaceHierarchy() { - string MarkerMethod(int param1, string param2); + IProxyTypeBuilder builder = GetProxyBuilder(); + builder.TargetType = typeof(MultipleInterfaces); + + Type proxy = builder.BuildProxyType(); + Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); + + object foo = Activator.CreateInstance(proxy); + Assert.IsTrue(foo is IBase); + Assert.IsTrue(foo is IInherited); + + // try to call proxied interface methods + ((IBase) foo).Base(); + ((IInherited) foo).Base(); + ((IInherited) foo).Inherited(); } - // XmlElementAttribute.Order property is only available in .NET 2.0 - public sealed class FakeXmlElementAttribute : Attribute + [Test] + public void ProxySpecificTargetTypeAttributeWithReadOnlyProperty() { - private int _order; - public int Order - { - get - { - return this._order; - } - set - { - if (value < 0) - { - throw new ArgumentException("Negative values are prohibited.", "Order"); - } - this._order = value; - } - } + IProxyTypeBuilder builder = GetProxyBuilder(); + builder.TargetType = typeof(ClassWithGuidAttribute); - private string _elementName; - public string ElementName - { - get { return _elementName; } - set { _elementName = value; } - } + Type proxy = builder.BuildProxyType(); + Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); - public FakeXmlElementAttribute() - { - this._order = -1; - } + object[] attrs = proxy.GetCustomAttributes(false); + Assert.IsNotNull(attrs, "Should have had 1 attribute applied to the target type."); + Assert.AreEqual(1, attrs.Length, "Should have had 1 attribute applied to the target type."); + Assert.AreEqual(typeof(GuidAttribute), attrs[0].GetType(), "Wrong System.Type of Attribute applied to the target type."); - public FakeXmlElementAttribute(string elementName) - { - this._order = -1; - this._elementName = elementName; - } + GuidAttribute ga = attrs[0] as GuidAttribute; + Assert.AreEqual("7cfc9607-e81a-48ac-a080-bda88193607b", ga.Value); } - public sealed class FakeGenerateScriptTypeAttribute : Attribute + [Test] + public void ProxySpecificTargetTypeAttributeWithPropertySetterChangingDefaultBehavior() { - public FakeGenerateScriptTypeAttribute(string name) + IProxyTypeBuilder builder = GetProxyBuilder(); + builder.TargetType = typeof(ClassWithFakeXmlElementAttribute); + Type proxy = builder.BuildProxyType(); + Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); + MethodInfo method = proxy.GetMethod("Spring.Proxy.ISomeMarkerInterface.MarkerMethod", BindingFlags.NonPublic | BindingFlags.Instance); + if (method == null) { - if (name == null) - { - throw new ArgumentNullException("name"); - } - this._name = name; + method = proxy.GetMethod("MarkerMethod"); } - private string _name; - public string Name - { - get - { - return this._name; - } - } + Assert.IsNotNull(method); + object[] attrs = method.GetParameters()[0].GetCustomAttributes(false); + Assert.IsNotNull(method); + Assert.IsNotNull(attrs, "Should have 1 attribute applied to the target method."); + Assert.AreEqual(1, attrs.Length, "Should have 1 attribute applied to the target method."); + Assert.AreEqual(typeof(FakeXmlElementAttribute), attrs[0].GetType(), "Wrong System.Type of Attribute applied to the target method."); + + FakeXmlElementAttribute xea = attrs[0] as FakeXmlElementAttribute; + Assert.AreEqual(-1, xea.Order); } - public sealed class FakeServiceKnownTypeAttribute : Attribute + [Test] + public void ProxySpecificTargetTypeAttributeNotInstantiableWithDefaultValues() { - private Type declaringType; - private string methodName; - private Type type; + IProxyTypeBuilder builder = GetProxyBuilder(); + builder.TargetType = typeof(ClassWithFakeGenerateScriptTypeAttribute); - private FakeServiceKnownTypeAttribute() - { - } + Type proxy = builder.BuildProxyType(); + Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); - public FakeServiceKnownTypeAttribute(string methodName) - { - this.methodName = methodName; - } + object[] attrs = proxy.GetCustomAttributes(false); + Assert.IsNotNull(attrs, "Should have had 1 attribute applied to the target type."); + Assert.AreEqual(1, attrs.Length, "Should have had 1 attribute applied to the target type."); + Assert.AreEqual(typeof(FakeGenerateScriptTypeAttribute), attrs[0].GetType(), "Wrong System.Type of Attribute applied to the target type."); - public FakeServiceKnownTypeAttribute(Type type) - { - this.type = type; - } - - public FakeServiceKnownTypeAttribute(string methodName, Type declaringType) - { - this.methodName = methodName; - this.declaringType = declaringType; - } - - public Type DeclaringType - { - get - { - return this.declaringType; - } - } - - public string MethodName - { - get - { - return this.methodName; - } - } - - public Type Type - { - get - { - return this.type; - } - } + FakeGenerateScriptTypeAttribute fgsta = attrs[0] as FakeGenerateScriptTypeAttribute; + Assert.AreEqual("ScriptName", fgsta.Name); } - public class ClassWithFakeXmlElementAttribute : ISomeMarkerInterface + // http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=296032 + // should not fail + // Not fixed by .NET 2.0 SP1. + [Test] + public void ProxySpecificTargetTypeAttributeWithPublicEnumProperty() { - public string MarkerMethod([FakeXmlElement("parameter1")] int param1, string param2) + IProxyTypeBuilder builder = GetProxyBuilder(); + builder.TargetType = typeof(ClassWithPublicEnumPropertyAttribute); + Type proxy = builder.BuildProxyType(); + Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); + MethodInfo method = proxy.GetMethod("Spring.Proxy.ISomeMarkerInterface.MarkerMethod", BindingFlags.NonPublic | BindingFlags.Instance); + if (method == null) { - return null; + method = proxy.GetMethod("MarkerMethod"); } + + Assert.IsNotNull(method); + object[] attrs = method.GetCustomAttributes(false); + Assert.IsNotNull(attrs, "Should have 1 attribute applied to the target method."); + Assert.AreEqual(1, attrs.Length, "Should have 1 attribute applied to the target method."); + Assert.AreEqual(typeof(PublicEnumPropertyAttribute), attrs[0].GetType(), "Wrong System.Type of Attribute applied to the target method."); + + PublicEnumPropertyAttribute pepa = attrs[0] as PublicEnumPropertyAttribute; + Assert.AreEqual(AttributeTargets.All, pepa.Data); } #if !NETCOREAPP // http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=161522 - [System.Web.Services.WebService(Namespace = "http://mynamespace.com", Name = "blah")] - public class ClassWithWebServiceAttribute : IMarkerInterface + // should not fail + // Use CustomAttributeData if patch applied (.NET 2.0 SP1). + // Use Attribute instance if patch not applied (.NET 2.0 SP1). + [Test] + public void ProxyWebServiceAttribute() { + IProxyTypeBuilder builder = GetProxyBuilder(); + builder.TargetType = typeof(ClassWithWebServiceAttribute); + + Type proxy = builder.BuildProxyType(); + Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); + + object[] attrs = proxy.GetCustomAttributes(false); + Assert.IsNotNull(attrs, "Should have had 1 attribute applied to the target type."); + Assert.AreEqual(1, attrs.Length, "Should have had 1 attribute applied to the target type."); + Assert.AreEqual(typeof(System.Web.Services.WebServiceAttribute), attrs[0].GetType(), "Wrong System.Type of Attribute applied to the target type."); + + var wsa = attrs[0] as System.Web.Services.WebServiceAttribute; + Assert.AreEqual("blah", wsa.Name); + Assert.AreEqual("http://mynamespace.com", wsa.Namespace); } #endif - [FakeGenerateScriptType("ScriptName")] - public class ClassWithFakeGenerateScriptTypeAttribute : IMarkerInterface +#if !MONO && !NETCOREAPP + // http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=94803 + [Test] + [Platform("Win")] + public void ProxySecurityAttribute() { - } + IProxyTypeBuilder builder = GetProxyBuilder(); + builder.TargetType = typeof(ClassWithSecurityAttribute); - //[FakeServiceKnownTypeAttribute(typeof(TestObject))] - public class ClassWithFakeServiceKnownTypeAttribute : IMarkerInterface - { - } + Type proxy = builder.BuildProxyType(); + Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); - // http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=296032 - public class ClassWithPublicEnumPropertyAttribute : ISomeMarkerInterface + object[] attrs = proxy.GetCustomAttributes(false); + Assert.IsNotNull(attrs, "Should have had 2 attribute applied to the target type."); + Assert.AreEqual(2, attrs.Length, "Should have had 2 attribute applied to the target type."); + } +#endif + + [Test] + public void ProxySpecificTargetTypeAttributeWithArrayConstructor() { - [PublicEnumProperty(AttributeTargets.All)] - public string MarkerMethod(int param1, string param2) + IProxyTypeBuilder builder = GetProxyBuilder(); + builder.TargetType = typeof(ClassWithArrayConstructorAttribute); + Type proxy = builder.BuildProxyType(); + Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); + + MethodInfo method = proxy.GetMethod("Spring.Proxy.ISomeMarkerInterface.MarkerMethod", BindingFlags.NonPublic | BindingFlags.Instance); + if (method == null) + { + method = proxy.GetMethod("MarkerMethod"); + } + + Assert.IsNotNull(method); + object[] attrs = method.GetCustomAttributes(false); + Assert.IsNotNull(attrs, "Should have 1 attribute applied to the target method."); + Assert.AreEqual(1, attrs.Length, "Should have 1 attribute applied to the target method."); + Assert.AreEqual(typeof(ArrayConstructorPropertyAttribute), attrs[0].GetType(), "Wrong System.Type of Attribute applied to the target method."); + + ArrayConstructorPropertyAttribute acpa = attrs[0] as ArrayConstructorPropertyAttribute; + Assert.AreEqual(false, acpa.ReadOnly); + Assert.AreEqual(1, acpa.Types.Length); + Assert.AreEqual(typeof(string), acpa.Types[0]); + } + + [Test] + public void ProxySpecificTargetTypeAttributeWithArrayProperty() + { + IProxyTypeBuilder builder = GetProxyBuilder(); + builder.TargetType = typeof(ClassWithArrayPropertyAttribute); + Type proxy = builder.BuildProxyType(); + Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); + + MethodInfo method = proxy.GetMethod("Spring.Proxy.IAnotherMarkerInterface.MarkerMethod", BindingFlags.NonPublic | BindingFlags.Instance); + if (method == null) + { + method = proxy.GetMethod("MarkerMethod"); + } + + Assert.IsNotNull(method); + object[] attrs = method.GetCustomAttributes(false); + Assert.IsNotNull(attrs, "Should have 1 attribute applied to the target method."); + Assert.AreEqual(1, attrs.Length, "Should have 1 attribute applied to the target method."); + Assert.AreEqual(typeof(ArrayConstructorPropertyAttribute), attrs[0].GetType(), "Wrong System.Type of Attribute applied to the target method."); + + ArrayConstructorPropertyAttribute acpa = attrs[0] as ArrayConstructorPropertyAttribute; + Assert.AreEqual(true, acpa.ReadOnly); + Assert.AreEqual(2, acpa.Types.Length); + Assert.AreEqual(typeof(int), acpa.Types[0]); + Assert.AreEqual(typeof(string), acpa.Types[1]); + } + + [Test] + public void ProxyTargetTypeAttributes() + { + IProxyTypeBuilder builder = GetProxyBuilder(); + builder.TargetType = typeof(AnotherMarkerClass); + Type proxy = builder.BuildProxyType(); + Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); + object[] attrs = proxy.GetCustomAttributes(false); + Assert.IsNotNull(attrs, "Should have had 1 attribute applied to the target type."); + Assert.AreEqual(1, attrs.Length, "Should have had 1 attribute applied to the target type."); + Assert.AreEqual(typeof(MarkerAttribute), attrs[0].GetType(), "Wrong System.Type of Attribute applied to the target type."); + } + + [Test] + public void DoesNotProxyTargetTypeAttributesWithProxyTargetAttributesEqualsFalse() + { + IProxyTypeBuilder builder = GetProxyBuilder(); + builder.TargetType = typeof(AnotherMarkerClass); + builder.ProxyTargetAttributes = false; + Type proxy = builder.BuildProxyType(); + Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); + object[] attrs = proxy.GetCustomAttributes(false); + Assert.IsNotNull(attrs); + Assert.AreEqual(0, attrs.Length, "Should not have attribute applied to the target type."); + } + + [Test] + public void ProxyTargetMethodAttributes() + { + IProxyTypeBuilder builder = GetProxyBuilder(); + builder.TargetType = typeof(AnotherMarkerClass); + Type proxy = builder.BuildProxyType(); + Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); + MethodInfo method = proxy.GetMethod("Spring.Proxy.IAnotherMarkerInterface.MarkerMethod", BindingFlags.NonPublic | BindingFlags.Instance); + if (method == null) + { + method = proxy.GetMethod("MarkerMethod"); + } + + Assert.IsNotNull(method); + object[] attrs = method.GetCustomAttributes(false); + Assert.IsNotNull(attrs, "Should have 1 attribute applied to the target method."); + Assert.AreEqual(1, attrs.Length, "Should have 1 attribute applied to the target method."); + Assert.AreEqual(typeof(MarkerAttribute), attrs[0].GetType(), "Wrong System.Type of Attribute applied to the target method."); + } + + [Test] + public void DoesNotProxyTargetMethodAttributesWithProxyTargetAttributesEqualsFalse() + { + IProxyTypeBuilder builder = GetProxyBuilder(); + builder.TargetType = typeof(AnotherMarkerClass); + builder.ProxyTargetAttributes = false; + Type proxy = builder.BuildProxyType(); + Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); + MethodInfo method = proxy.GetMethod("Spring.Proxy.IAnotherMarkerInterface.MarkerMethod", BindingFlags.NonPublic | BindingFlags.Instance); + if (method == null) + { + method = proxy.GetMethod("MarkerMethod"); + } + + Assert.IsNotNull(method); + object[] attrs = method.GetCustomAttributes(false); + Assert.IsNotNull(attrs); + Assert.AreEqual(0, attrs.Length, "Should not have attribute applied to the target method."); + } + + [Test] + public void ProxyTargetMethodParameterAttributes() + { + IProxyTypeBuilder builder = GetProxyBuilder(); + builder.TargetType = typeof(SomeMarkerClass); + Type proxy = builder.BuildProxyType(); + Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); + MethodInfo method = proxy.GetMethod("Spring.Proxy.ISomeMarkerInterface.MarkerMethod", BindingFlags.NonPublic | BindingFlags.Instance); + if (method == null) + { + method = proxy.GetMethod("MarkerMethod"); + } + + Assert.IsNotNull(method); + object[] attrs = method.GetParameters()[1].GetCustomAttributes(false); + Assert.IsNotNull(attrs, "Should have had 1 attribute applied to the method's parameter."); + Assert.AreEqual(1, attrs.Length, "Should have had 1 attribute applied to the method's parameter."); + Assert.AreEqual(typeof(MarkerAttribute), attrs[0].GetType(), "Wrong System.Type of Attribute applied to the method's parameter."); + } + + [Test] + [Description("SPRNET-1134")] + public void ProxyTargetMethodParameterMultipleAttributes() + { + IProxyTypeBuilder builder = GetProxyBuilder(); + builder.TargetType = typeof(MultipleMarkerClass); + Type proxy = builder.BuildProxyType(); + Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); + MethodInfo method = proxy.GetMethod("Spring.Proxy.ISomeMarkerInterface.MarkerMethod", BindingFlags.NonPublic | BindingFlags.Instance); + if (method == null) + { + method = proxy.GetMethod("MarkerMethod"); + } + + Assert.IsNotNull(method); + object[] attrs = method.GetParameters()[1].GetCustomAttributes(false); + Assert.IsNotNull(attrs, "Should have had 2 attributes applied to the method's parameter."); + Assert.AreEqual(2, attrs.Length, "Should have had 2 attributes applied to the method's parameter."); + Assert.AreEqual(typeof(MarkerAttribute), attrs[0].GetType(), "Wrong System.Type of Attribute applied to the method's parameter."); + Assert.AreEqual(typeof(MarkerAttribute), attrs[1].GetType(), "Wrong System.Type of Attribute applied to the method's parameter."); + } + + [Test] + public void DoesNotProxyTargetMethodParameterAttributesWithProxyTargetAttributesEqualsFalse() + { + IProxyTypeBuilder builder = GetProxyBuilder(); + builder.TargetType = typeof(SomeMarkerClass); + builder.ProxyTargetAttributes = false; + Type proxy = builder.BuildProxyType(); + Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); + MethodInfo method = proxy.GetMethod("Spring.Proxy.ISomeMarkerInterface.MarkerMethod", BindingFlags.NonPublic | BindingFlags.Instance); + if (method == null) + { + method = proxy.GetMethod("MarkerMethod"); + } + + Assert.IsNotNull(method); + object[] attrs = method.GetParameters()[1].GetCustomAttributes(false); + Assert.IsNotNull(attrs); + Assert.AreEqual(0, attrs.Length, "Should not have attribute applied to the method's parameter."); + } + + [Test] + public void ProxyTargetMethodReturnValueAttributes() + { + IProxyTypeBuilder builder = GetProxyBuilder(); + builder.TargetType = typeof(SomeMarkerClass); + Type proxy = builder.BuildProxyType(); + Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); + MethodInfo method = proxy.GetMethod("Spring.Proxy.ISomeMarkerInterface.MarkerMethod", BindingFlags.NonPublic | BindingFlags.Instance); + if (method == null) + { + method = proxy.GetMethod("MarkerMethod"); + } + + Assert.IsNotNull(method); + object[] attrs = method.ReturnTypeCustomAttributes.GetCustomAttributes(false); + Assert.IsNotNull(attrs, "Should have had 1 attribute applied to the method's return value."); + Assert.AreEqual(1, attrs.Length, "Should have had 1 attribute applied to the method's return value."); + Assert.AreEqual(typeof(MarkerAttribute), attrs[0].GetType(), "Wrong System.Type of Attribute applied to the method's return value."); + } + + [Test] + [Description("SPRNET-1134")] + public void ProxyTargetMethodReturnValueMultipleAttributes() + { + IProxyTypeBuilder builder = GetProxyBuilder(); + builder.TargetType = typeof(MultipleMarkerClass); + Type proxy = builder.BuildProxyType(); + Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); + MethodInfo method = proxy.GetMethod("Spring.Proxy.ISomeMarkerInterface.MarkerMethod", BindingFlags.NonPublic | BindingFlags.Instance); + if (method == null) + { + method = proxy.GetMethod("MarkerMethod"); + } + + Assert.IsNotNull(method); + object[] attrs = method.ReturnTypeCustomAttributes.GetCustomAttributes(false); + Assert.IsNotNull(attrs, "Should have had 2 attribute applied to the method's return value."); + Assert.AreEqual(2, attrs.Length, "Should have had 2 attribute applied to the method's return value."); + Assert.AreEqual(typeof(MarkerAttribute), attrs[0].GetType(), "Wrong System.Type of Attribute applied to the method's return value."); + Assert.AreEqual(typeof(MarkerAttribute), attrs[1].GetType(), "Wrong System.Type of Attribute applied to the method's return value."); + } + + [Test] + public void DoesNotProxyTargetMethodReturnValueAttributesWithProxyTargetAttributesEqualsFalse() + { + IProxyTypeBuilder builder = GetProxyBuilder(); + builder.TargetType = typeof(SomeMarkerClass); + builder.ProxyTargetAttributes = false; + Type proxy = builder.BuildProxyType(); + Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); + MethodInfo method = proxy.GetMethod("Spring.Proxy.ISomeMarkerInterface.MarkerMethod", BindingFlags.NonPublic | BindingFlags.Instance); + if (method == null) + { + method = proxy.GetMethod("MarkerMethod"); + } + + Assert.IsNotNull(method); + object[] attrs = method.ReturnTypeCustomAttributes.GetCustomAttributes(false); + Assert.IsNotNull(attrs); + Assert.AreEqual(0, attrs.Length, "Should not have attribute applied to the method's return value."); + } + + [Test] + public void ProxyGenericMethod() + { + IProxyTypeBuilder builder = GetProxyBuilder(); + builder.TargetType = typeof(ClassWithGenericMethod); + + Type proxy = builder.BuildProxyType(); + Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); + + InterfaceWithGenericMethod foo = Activator.CreateInstance(proxy) as InterfaceWithGenericMethod; + Assert.IsNotNull(foo); + + foo.PolymorphicMethod(); + + string result1 = foo.PolymorphicMethod("coucou"); + Assert.AreEqual("coucou", result1); + + foo.WithGenericParameter(); + + foo.WithGenericParameterAndGenericArgument("ola"); + + string result2 = foo.WithGenericParameterAndGenericArgumentAndGenericReturnType("ola"); + Assert.AreEqual("ola", result2); + + foo.WithInterfaceConstraint(); + + foo.WithBaseTypeConstraint(); + + foo.WithBaseTypeAndInterfaceConstraints(); + + foo.WithMixedConstraint(); + } + + public interface InterfaceWithGenericMethod + { + void PolymorphicMethod(); + + string PolymorphicMethod(string param); + + void WithGenericParameter(); + + void WithGenericParameterAndGenericArgument(T obj); + + T WithGenericParameterAndGenericArgumentAndGenericReturnType(T obj); + + void WithInterfaceConstraint() where Z : IComparable; + + void WithBaseTypeConstraint() where Z : TestObject; + + void WithBaseTypeAndInterfaceConstraints() where Z : TestObject, IComparable, IDisposable; + + void WithMixedConstraint() + where X : IComparable, new() + where Y : TestObject; + } + + public class ClassWithGenericMethod : InterfaceWithGenericMethod + { + public void PolymorphicMethod() { } + + public string PolymorphicMethod(string param) + { + return param; + } + + public void WithGenericParameter() { } + + public void WithGenericParameterAndGenericArgument(T obj) { } + + public T WithGenericParameterAndGenericArgumentAndGenericReturnType(T obj) + { + return obj; + } + + public void WithInterfaceConstraint() where Z : IComparable { } + + public void WithBaseTypeConstraint() where Z : TestObject { } + + public void WithBaseTypeAndInterfaceConstraints() where Z : TestObject, IComparable, IDisposable { } + + public void WithMixedConstraint() + where X : IComparable, new() + where Y : TestObject { - return null; } } + [Test] + public void ProxyGenericInterface() + { + IProxyTypeBuilder builder = GetProxyBuilder(); + builder.TargetType = typeof(ClassThatImplementsGenericInterface); + + Type proxy = builder.BuildProxyType(); + Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); + + GenericInterface foo = Activator.CreateInstance(proxy) as GenericInterface; + Assert.IsNotNull(foo); + + TestObject to1 = foo.Create(); + Assert.IsNotNull(to1); + + TestObject to2 = foo.Populate(new TestObject()); + Assert.IsNotNull(to2); + Assert.AreEqual("Populated", to2.Name); + } + + public interface GenericInterface + where T : ITestObject, new() + { + T Create(); + + T Populate(T testObject); + } + + public class ClassThatImplementsGenericInterface : GenericInterface + where T : ITestObject, new() + { + public T Create() + { + return new T(); + } + + public T Populate(T testObject) + { + testObject.Name = "Populated"; + + return testObject; + } + } + + protected abstract IProxyTypeBuilder GetProxyBuilder(); + + public interface InnerInterface + { + } + + public class InnerClass : InnerInterface + { + } +} + +public class DoesntImplementAnyInterfaces +{ +} + +public interface IMarkerInterface +{ +} + +public class MarkerClass : IMarkerInterface +{ +} + +[GuidAttribute("7cfc9607-e81a-48ac-a080-bda88193607b")] +public class ClassWithGuidAttribute : IMarkerInterface +{ +} + +[Marker] +public interface IAnotherMarkerInterface +{ + [Marker] + void MarkerMethod(); +} + +public interface ISomeMarkerInterface +{ + string MarkerMethod(int param1, string param2); +} + +// XmlElementAttribute.Order property is only available in .NET 2.0 +public sealed class FakeXmlElementAttribute : Attribute +{ + private int _order; + + public int Order + { + get + { + return this._order; + } + set + { + if (value < 0) + { + throw new ArgumentException("Negative values are prohibited.", "Order"); + } + + this._order = value; + } + } + + private string _elementName; + + public string ElementName + { + get { return _elementName; } + set { _elementName = value; } + } + + public FakeXmlElementAttribute() + { + this._order = -1; + } + + public FakeXmlElementAttribute(string elementName) + { + this._order = -1; + this._elementName = elementName; + } +} + +public sealed class FakeGenerateScriptTypeAttribute : Attribute +{ + public FakeGenerateScriptTypeAttribute(string name) + { + if (name == null) + { + throw new ArgumentNullException("name"); + } + + this._name = name; + } + + private string _name; + + public string Name + { + get + { + return this._name; + } + } +} + +public sealed class FakeServiceKnownTypeAttribute : Attribute +{ + private Type declaringType; + private string methodName; + private Type type; + + private FakeServiceKnownTypeAttribute() + { + } + + public FakeServiceKnownTypeAttribute(string methodName) + { + this.methodName = methodName; + } + + public FakeServiceKnownTypeAttribute(Type type) + { + this.type = type; + } + + public FakeServiceKnownTypeAttribute(string methodName, Type declaringType) + { + this.methodName = methodName; + this.declaringType = declaringType; + } + + public Type DeclaringType + { + get + { + return this.declaringType; + } + } + + public string MethodName + { + get + { + return this.methodName; + } + } + + public Type Type + { + get + { + return this.type; + } + } +} + +public class ClassWithFakeXmlElementAttribute : ISomeMarkerInterface +{ + public string MarkerMethod([FakeXmlElement("parameter1")] int param1, string param2) + { + return null; + } +} + #if !NETCOREAPP - // http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=94803 - [Marker] -#pragma warning disable 618 - [System.Net.WebPermission(System.Security.Permissions.SecurityAction.Deny)] -#pragma warning restore 618 - public class ClassWithSecurityAttribute : IMarkerInterface - { - } +// http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=161522 +[System.Web.Services.WebService(Namespace = "http://mynamespace.com", Name = "blah")] +public class ClassWithWebServiceAttribute : IMarkerInterface +{ +} #endif - public class ClassWithArrayConstructorAttribute : ISomeMarkerInterface +[FakeGenerateScriptType("ScriptName")] +public class ClassWithFakeGenerateScriptTypeAttribute : IMarkerInterface +{ +} + +//[FakeServiceKnownTypeAttribute(typeof(TestObject))] +public class ClassWithFakeServiceKnownTypeAttribute : IMarkerInterface +{ +} + +// http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=296032 +public class ClassWithPublicEnumPropertyAttribute : ISomeMarkerInterface +{ + [PublicEnumProperty(AttributeTargets.All)] + public string MarkerMethod(int param1, string param2) { - [ArrayConstructorPropertyAttribute(false, new Type[1] { typeof(string) })] - public string MarkerMethod(int param1, string param2) - { - return null; - } + return null; + } +} + +#if !NETCOREAPP +// http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=94803 +[Marker] +#pragma warning disable 618 +[System.Net.WebPermission(System.Security.Permissions.SecurityAction.Deny)] +#pragma warning restore 618 +public class ClassWithSecurityAttribute : IMarkerInterface +{ +} +#endif + +public class ClassWithArrayConstructorAttribute : ISomeMarkerInterface +{ + [ArrayConstructorPropertyAttribute(false, new Type[1] { typeof(string) })] + public string MarkerMethod(int param1, string param2) + { + return null; + } +} + +public class ClassWithArrayPropertyAttribute : IAnotherMarkerInterface +{ + [ArrayConstructorPropertyAttribute(ReadOnly = true, Types = new Type[2] { typeof(int), typeof(string) })] + public void MarkerMethod() + { + } +} + +public class SomeMarkerClass : ISomeMarkerInterface +{ + [return: Marker] + public string MarkerMethod(int param1, [Marker] string param2) + { + return string.Empty; } - public class ClassWithArrayPropertyAttribute : IAnotherMarkerInterface + [return: Marker] + public virtual string MarkerVirtualMethod(int param1, [Marker] string param2) { - [ArrayConstructorPropertyAttribute(ReadOnly = true, Types = new Type[2] { typeof(int), typeof(string) })] - public void MarkerMethod() - { - } + return string.Empty; + } +} + +// SPRNET-1134 +public class MultipleMarkerClass : ISomeMarkerInterface +{ + [return: Marker(Count = 0)] + [return: Marker(Count = 1)] + public string MarkerMethod(int param1, [Marker(Count = 0)] [Marker(Count = 1)] string param2) + { + return string.Empty; } - public class SomeMarkerClass : ISomeMarkerInterface + [return: Marker(Count = 0)] + [return: Marker(Count = 1)] + public virtual string MarkerVirtualMethod(int param1, [Marker(Count = 0)] [Marker(Count = 1)] string param2) { - [return: Marker] - public string MarkerMethod(int param1, [Marker]string param2) - { - return string.Empty; - } - - [return: Marker] - public virtual string MarkerVirtualMethod(int param1, [Marker]string param2) - { - return string.Empty; - } + return string.Empty; } +} - // SPRNET-1134 - public class MultipleMarkerClass : ISomeMarkerInterface +[Marker] +public class AnotherMarkerClass : IAnotherMarkerInterface +{ + [Marker] + public void MarkerMethod() { - [return: Marker(Count = 0)] - [return: Marker(Count = 1)] - public string MarkerMethod(int param1, [Marker(Count = 0)][Marker(Count = 1)]string param2) - { - return string.Empty; - } - - [return: Marker(Count = 0)] - [return: Marker(Count = 1)] - public virtual string MarkerVirtualMethod(int param1, [Marker(Count = 0)][Marker(Count = 1)]string param2) - { - return string.Empty; - } } [Marker] - public class AnotherMarkerClass : IAnotherMarkerInterface + public virtual void MarkerVirtualMethod() { - [Marker] - public void MarkerMethod() - { - } + } +} - [Marker] - public virtual void MarkerVirtualMethod() - { - } +public class ArrayConstructorPropertyAttribute : Attribute +{ + private bool _readOnly = false; + private Type[] _types = Type.EmptyTypes; + + public ArrayConstructorPropertyAttribute() + { } - public class ArrayConstructorPropertyAttribute : Attribute + public ArrayConstructorPropertyAttribute(bool readOnly, Type[] types) { - private bool _readOnly = false; - private Type[] _types = Type.EmptyTypes; - - public ArrayConstructorPropertyAttribute() - { - } - - public ArrayConstructorPropertyAttribute(bool readOnly, Type[] types) - { - this._readOnly = readOnly; - this._types = types; - } - - public bool ReadOnly - { - get { return _readOnly; } - set { _readOnly = value; } - } - - public Type[] Types - { - get { return _types; } - set { _types = value; } - } + this._readOnly = readOnly; + this._types = types; } - public class PublicEnumPropertyAttribute : Attribute + public bool ReadOnly { - private Enum _data; - - public PublicEnumPropertyAttribute(AttributeTargets data) - { - _data = data; - } - - public PublicEnumPropertyAttribute(TypeCode data) - { - _data = data; - } - - public Enum Data - { - get { return _data; } - } + get { return _readOnly; } + set { _readOnly = value; } } - [AttributeUsage(AttributeTargets.All, AllowMultiple = true)] - public sealed class MarkerAttribute : Attribute + public Type[] Types { - private int _count; + get { return _types; } + set { _types = value; } + } +} - public int Count - { - get { return _count; } - set { _count = value; } - } +public class PublicEnumPropertyAttribute : Attribute +{ + private Enum _data; + + public PublicEnumPropertyAttribute(AttributeTargets data) + { + _data = data; } - public interface IBase + public PublicEnumPropertyAttribute(TypeCode data) { - void Base(); + _data = data; } - public interface IInherited : IBase + public Enum Data + { + get { return _data; } + } +} + +[AttributeUsage(AttributeTargets.All, AllowMultiple = true)] +public sealed class MarkerAttribute : Attribute +{ + private int _count; + + public int Count + { + get { return _count; } + set { _count = value; } + } +} + +public interface IBase +{ + void Base(); +} + +public interface IInherited : IBase +{ + void Inherited(); +} + +public class MultipleInterfaces : IInherited +{ + public void Inherited() { - void Inherited(); } - public class MultipleInterfaces : IInherited + public void Base() { - public void Inherited() - { - } + } +} - public void Base() - { - } +public interface ITargetObjectTest +{ + string InterfaceProperty { get; set; } + + bool InterfaceMethodWithArguments(string code); + + void InterfaceVirtualMethodWithNoArguments(); +} + +public class TargetObjectTest : ITargetObjectTest +{ + private string _interfaceProperty; + + public TargetObjectTest() { } + + public TargetObjectTest(string interfaceProperty) + { + _interfaceProperty = interfaceProperty; } - public interface ITargetObjectTest + public virtual string InterfaceProperty { - string InterfaceProperty { get; set; } - - bool InterfaceMethodWithArguments(string code); - - void InterfaceVirtualMethodWithNoArguments(); + get { return _interfaceProperty; } + set { _interfaceProperty = value; } } - public class TargetObjectTest : ITargetObjectTest + public bool InterfaceMethodWithArguments(string code) { - private string _interfaceProperty; - - public TargetObjectTest() { } - - public TargetObjectTest(string interfaceProperty) - { - _interfaceProperty = interfaceProperty; - } - - public virtual string InterfaceProperty - { - get { return _interfaceProperty; } - set { _interfaceProperty = value; } - } - - public bool InterfaceMethodWithArguments(string code) - { - return true; - } - - public virtual void InterfaceVirtualMethodWithNoArguments() - { - } - - public void MethodWithArguments(string code) - { - } + return true; } - [ProxyIgnore] - public interface IFrameworkInterface + public virtual void InterfaceVirtualMethodWithNoArguments() { - void FrameworkMethod(); } - public interface IApplicationInterface + public void MethodWithArguments(string code) { - void ApplicationMethod(); } +} - public class ApplicationClass : IApplicationInterface, IFrameworkInterface - { - public void FrameworkMethod() { } +[ProxyIgnore] +public interface IFrameworkInterface +{ + void FrameworkMethod(); +} - public void ApplicationMethod() { } - } -} \ No newline at end of file +public interface IApplicationInterface +{ + void ApplicationMethod(); +} + +public class ApplicationClass : IApplicationInterface, IFrameworkInterface +{ + public void FrameworkMethod() { } + + public void ApplicationMethod() { } +} diff --git a/test/Spring/Spring.Core.Tests/Proxy/CompositionProxyTypeBuilderTests.cs b/test/Spring/Spring.Core.Tests/Proxy/CompositionProxyTypeBuilderTests.cs index e0bb92eb..c9166460 100644 --- a/test/Spring/Spring.Core.Tests/Proxy/CompositionProxyTypeBuilderTests.cs +++ b/test/Spring/Spring.Core.Tests/Proxy/CompositionProxyTypeBuilderTests.cs @@ -21,137 +21,135 @@ #region Imports using System.Reflection; - using NUnit.Framework; #endregion -namespace Spring.Proxy +namespace Spring.Proxy; + +/// +/// Unit tests for the CompositionProxyTypeBuilder class. +/// +/// Rick Evans +/// Bruno Baia +[TestFixture] +public class CompositionProxyTypeBuilderTests : AbstractProxyTypeBuilderTests { - /// - /// Unit tests for the CompositionProxyTypeBuilder class. - /// - /// Rick Evans - /// Bruno Baia - [TestFixture] - public class CompositionProxyTypeBuilderTests : AbstractProxyTypeBuilderTests - { - [Test] - public void OnClassThatDoesntImplementAnyInterfaces() - { - IProxyTypeBuilder builder = GetProxyBuilder(); - builder.TargetType = typeof (DoesntImplementAnyInterfaces); - Assert.Throws(() => builder.BuildProxyType(), "Composition proxy target must implement at least one interface."); - } - - [Test] - public void BuildProxyWithNothingSet() - { - IProxyTypeBuilder builder = GetProxyBuilder(); - Assert.Throws(() => builder.BuildProxyType()); - } - - [Test] - public void ProxyInnerClass() - { - IProxyTypeBuilder builder = GetProxyBuilder(); - builder.TargetType = typeof(InnerClass); - Type proxy = builder.BuildProxyType(); - Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); - object foo = Activator.CreateInstance(proxy); - Assert.IsTrue(foo is InnerInterface); - Assert.IsFalse(foo is InnerClass); - } - - [Test] - public void CheckInterfaceImplementation() - { - IProxyTypeBuilder builder = GetProxyBuilder(); - builder.TargetType = typeof (MarkerClass); - Type proxy = builder.BuildProxyType(); - Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); - object foo = Activator.CreateInstance(proxy); - Assert.IsTrue(foo is IMarkerInterface); - Assert.IsFalse(foo is MarkerClass); - } - - [Test] - public void SetsInterfacesToProxy() - { - IProxyTypeBuilder builder = GetProxyBuilder(); - builder.TargetType = typeof(MultipleInterfaces); - builder.Interfaces = new Type[] { typeof(IBase) }; - - Type proxy = builder.BuildProxyType(); - Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); - - object foo = Activator.CreateInstance(proxy); - Assert.IsTrue(foo is IBase); - Assert.IsFalse(foo is IInherited); - - // try to call proxied interface methods - ((IBase)foo).Base(); - } - - [Test] - public void DoesNotProxyNonProxiableInterface() - { - IProxyTypeBuilder builder = GetProxyBuilder(); - builder.TargetType = typeof(ApplicationClass); - - Type proxy = builder.BuildProxyType(); - Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); - - object foo = Activator.CreateInstance(proxy); - Assert.IsTrue(foo is IApplicationInterface); - Assert.IsFalse(foo is IFrameworkInterface); - - // try to call proxied interface methods - ((IApplicationInterface)foo).ApplicationMethod(); - } - - [Test] - public void ForcesNonProxiableInterfacesToBeProxied() - { - IProxyTypeBuilder builder = GetProxyBuilder(); - builder.TargetType = typeof(ApplicationClass); - builder.Interfaces = new Type[] { typeof(IFrameworkInterface) }; - - Type proxy = builder.BuildProxyType(); - Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); - - object foo = Activator.CreateInstance(proxy); - Assert.IsFalse(foo is IApplicationInterface); - Assert.IsTrue(foo is IFrameworkInterface); - - // try to call proxied interface methods - ((IFrameworkInterface)foo).FrameworkMethod(); - } - - - [Test] // SPRNET-1424 - public void DoesNotProxyInterfaceMethodAttributes() - { - IProxyTypeBuilder builder = GetProxyBuilder(); - builder.TargetType = typeof(object); - builder.Interfaces = new Type[] { typeof(IAnotherMarkerInterface) }; - - Type proxy = builder.BuildProxyType(); - Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); - MethodInfo method = proxy.GetMethod("Spring.Proxy.IAnotherMarkerInterface.MarkerMethod", BindingFlags.NonPublic | BindingFlags.Instance); - if (method == null) - { - method = proxy.GetMethod("MarkerMethod"); - } - Assert.IsNotNull(method); - object[] attrs = method.GetCustomAttributes(false); - Assert.IsNotNull(attrs, "Should have 0 attribute applied to the target method."); - Assert.AreEqual(0, attrs.Length, "Should have 0 attribute applied to the target method."); - } - - protected override IProxyTypeBuilder GetProxyBuilder() - { - return new CompositionProxyTypeBuilder(); - } + [Test] + public void OnClassThatDoesntImplementAnyInterfaces() + { + IProxyTypeBuilder builder = GetProxyBuilder(); + builder.TargetType = typeof(DoesntImplementAnyInterfaces); + Assert.Throws(() => builder.BuildProxyType(), "Composition proxy target must implement at least one interface."); } -} \ No newline at end of file + + [Test] + public void BuildProxyWithNothingSet() + { + IProxyTypeBuilder builder = GetProxyBuilder(); + Assert.Throws(() => builder.BuildProxyType()); + } + + [Test] + public void ProxyInnerClass() + { + IProxyTypeBuilder builder = GetProxyBuilder(); + builder.TargetType = typeof(InnerClass); + Type proxy = builder.BuildProxyType(); + Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); + object foo = Activator.CreateInstance(proxy); + Assert.IsTrue(foo is InnerInterface); + Assert.IsFalse(foo is InnerClass); + } + + [Test] + public void CheckInterfaceImplementation() + { + IProxyTypeBuilder builder = GetProxyBuilder(); + builder.TargetType = typeof(MarkerClass); + Type proxy = builder.BuildProxyType(); + Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); + object foo = Activator.CreateInstance(proxy); + Assert.IsTrue(foo is IMarkerInterface); + Assert.IsFalse(foo is MarkerClass); + } + + [Test] + public void SetsInterfacesToProxy() + { + IProxyTypeBuilder builder = GetProxyBuilder(); + builder.TargetType = typeof(MultipleInterfaces); + builder.Interfaces = new Type[] { typeof(IBase) }; + + Type proxy = builder.BuildProxyType(); + Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); + + object foo = Activator.CreateInstance(proxy); + Assert.IsTrue(foo is IBase); + Assert.IsFalse(foo is IInherited); + + // try to call proxied interface methods + ((IBase) foo).Base(); + } + + [Test] + public void DoesNotProxyNonProxiableInterface() + { + IProxyTypeBuilder builder = GetProxyBuilder(); + builder.TargetType = typeof(ApplicationClass); + + Type proxy = builder.BuildProxyType(); + Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); + + object foo = Activator.CreateInstance(proxy); + Assert.IsTrue(foo is IApplicationInterface); + Assert.IsFalse(foo is IFrameworkInterface); + + // try to call proxied interface methods + ((IApplicationInterface) foo).ApplicationMethod(); + } + + [Test] + public void ForcesNonProxiableInterfacesToBeProxied() + { + IProxyTypeBuilder builder = GetProxyBuilder(); + builder.TargetType = typeof(ApplicationClass); + builder.Interfaces = new Type[] { typeof(IFrameworkInterface) }; + + Type proxy = builder.BuildProxyType(); + Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); + + object foo = Activator.CreateInstance(proxy); + Assert.IsFalse(foo is IApplicationInterface); + Assert.IsTrue(foo is IFrameworkInterface); + + // try to call proxied interface methods + ((IFrameworkInterface) foo).FrameworkMethod(); + } + + [Test] // SPRNET-1424 + public void DoesNotProxyInterfaceMethodAttributes() + { + IProxyTypeBuilder builder = GetProxyBuilder(); + builder.TargetType = typeof(object); + builder.Interfaces = new Type[] { typeof(IAnotherMarkerInterface) }; + + Type proxy = builder.BuildProxyType(); + Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); + MethodInfo method = proxy.GetMethod("Spring.Proxy.IAnotherMarkerInterface.MarkerMethod", BindingFlags.NonPublic | BindingFlags.Instance); + if (method == null) + { + method = proxy.GetMethod("MarkerMethod"); + } + + Assert.IsNotNull(method); + object[] attrs = method.GetCustomAttributes(false); + Assert.IsNotNull(attrs, "Should have 0 attribute applied to the target method."); + Assert.AreEqual(0, attrs.Length, "Should have 0 attribute applied to the target method."); + } + + protected override IProxyTypeBuilder GetProxyBuilder() + { + return new CompositionProxyTypeBuilder(); + } +} diff --git a/test/Spring/Spring.Core.Tests/Proxy/DynamicProxyManagerTests.cs b/test/Spring/Spring.Core.Tests/Proxy/DynamicProxyManagerTests.cs index ffbe8f4d..c1582d2a 100644 --- a/test/Spring/Spring.Core.Tests/Proxy/DynamicProxyManagerTests.cs +++ b/test/Spring/Spring.Core.Tests/Proxy/DynamicProxyManagerTests.cs @@ -25,104 +25,102 @@ using NUnit.Framework; #endregion -namespace Spring.Proxy +namespace Spring.Proxy; + +/// +/// +/// Erich Eichinger +[TestFixture] +public class DynamicProxyManagerTests { - /// - /// - /// Erich Eichinger - [TestFixture] - public class DynamicProxyManagerTests + #region WorkerThread Class + + public class WorkerThread { - #region WorkerThread Class + private Exception _exception; + private Thread _thread; + private WaitCallback _callback; + private object _arg; - public class WorkerThread + public WorkerThread(WaitCallback callback, object arg) { - private Exception _exception; - private Thread _thread; - private WaitCallback _callback; - private object _arg; - - public WorkerThread(WaitCallback callback,object arg) - { - this._arg = arg; - this._callback = callback; - _thread = new Thread( new ThreadStart( Run ) ); - } - - public void Start() - { - _thread.Start(); - } - - public void Join() - { - _thread.Join(); - } - - public Exception Exception - { - get { return this._exception; } - } - - private void Run() - { - try - { - _callback( _arg ); - } - catch(Exception ex) - { - _exception = ex; - } - } + this._arg = arg; + this._callback = callback; + _thread = new Thread(new ThreadStart(Run)); } - #endregion WorkerThread Class - - [Test] - public void CreateTypeBuilderMustNotBeCalledTwiceWithSameArguments() + public void Start() + { + _thread.Start(); + } + + public void Join() + { + _thread.Join(); + } + + public Exception Exception + { + get { return this._exception; } + } + + private void Run() { - TypeBuilder tb1 = DynamicProxyManager.CreateTypeBuilder("testtypename", null); - try { - TypeBuilder tb2 = DynamicProxyManager.CreateTypeBuilder("testtypename", typeof(AbstractProxyTypeBuilder)); - Assert.Fail("Did not throw expected ArgumentException."); + _callback(_arg); } - catch (ArgumentException) + catch (Exception ex) { - } - - } - - [Test] - public void CreateTypeBuilderIsThreadSafe() - { - const int WORKERS = 20; - - WorkerThread[] workers = new WorkerThread[WORKERS]; - for(int i=0;i +/// Unit tests for the CompositionProxyTypeBuilder class. +/// +/// Rick Evans +[TestFixture] +public sealed class ExplicitCompositionProxyTypeBuilderTests : CompositionProxyTypeBuilderTests { - /// - /// Unit tests for the CompositionProxyTypeBuilder class. - /// - /// Rick Evans - [TestFixture] - public sealed class ExplicitCompositionProxyTypeBuilderTests : CompositionProxyTypeBuilderTests - { - [Test] - public void ExplicitInterfaceImplementation() - { - IProxyTypeBuilder builder = GetProxyBuilder(); - builder.TargetType = typeof(MultipleInterfaces); - Type proxy = builder.BuildProxyType(); - Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); - object foo = Activator.CreateInstance(proxy); - Assert.IsTrue(foo is IBase); - Assert.IsTrue(foo is IInherited); + [Test] + public void ExplicitInterfaceImplementation() + { + IProxyTypeBuilder builder = GetProxyBuilder(); + builder.TargetType = typeof(MultipleInterfaces); + Type proxy = builder.BuildProxyType(); + Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); + object foo = Activator.CreateInstance(proxy); + Assert.IsTrue(foo is IBase); + Assert.IsTrue(foo is IInherited); - Type fooType = foo.GetType(); - MethodInfo[] methods = fooType.GetMethods(BindingFlags.DeclaredOnly); - Assert.AreEqual(0, methods.Length, "Methods array should be empty."); + Type fooType = foo.GetType(); + MethodInfo[] methods = fooType.GetMethods(BindingFlags.DeclaredOnly); + Assert.AreEqual(0, methods.Length, "Methods array should be empty."); - methods = fooType.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Instance); - Assert.AreEqual(2, methods.Length, "Methods array should have two elements."); - Assert.IsTrue(methods[0].Name.IndexOf('.') > 0, "Method should have '.' in the name"); - Assert.IsTrue(methods[1].Name.IndexOf('.') > 0, "Method should have '.' in the name"); + methods = fooType.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Instance); + Assert.AreEqual(2, methods.Length, "Methods array should have two elements."); + Assert.IsTrue(methods[0].Name.IndexOf('.') > 0, "Method should have '.' in the name"); + Assert.IsTrue(methods[1].Name.IndexOf('.') > 0, "Method should have '.' in the name"); + } - } - - protected override IProxyTypeBuilder GetProxyBuilder() - { - CompositionProxyTypeBuilder pb = new CompositionProxyTypeBuilder(); - pb.ExplicitInterfaceImplementation = true; - return pb; - } - } -} \ No newline at end of file + protected override IProxyTypeBuilder GetProxyBuilder() + { + CompositionProxyTypeBuilder pb = new CompositionProxyTypeBuilder(); + pb.ExplicitInterfaceImplementation = true; + return pb; + } +} diff --git a/test/Spring/Spring.Core.Tests/Proxy/InheritanceProxyTypeBuilderTests.cs b/test/Spring/Spring.Core.Tests/Proxy/InheritanceProxyTypeBuilderTests.cs index 502c5ef8..0d314d8e 100644 --- a/test/Spring/Spring.Core.Tests/Proxy/InheritanceProxyTypeBuilderTests.cs +++ b/test/Spring/Spring.Core.Tests/Proxy/InheritanceProxyTypeBuilderTests.cs @@ -21,322 +21,319 @@ #region Imports using System.Reflection; - using NUnit.Framework; - using Spring.Util; #endregion -namespace Spring.Proxy +namespace Spring.Proxy; + +/// +/// Unit tests for the InheritanceProxyTypeBuilder class. +/// +/// Rick Evans +/// Bruno Baia +[TestFixture] +public sealed class InheritanceProxyTypeBuilderTests : AbstractProxyTypeBuilderTests { - /// - /// Unit tests for the InheritanceProxyTypeBuilder class. - /// - /// Rick Evans - /// Bruno Baia - [TestFixture] - public sealed class InheritanceProxyTypeBuilderTests : AbstractProxyTypeBuilderTests + [Test] + public void OnClassThatDoesntImplementAnyInterfaces() { - [Test] - public void OnClassThatDoesntImplementAnyInterfaces() - { - IProxyTypeBuilder builder = GetProxyBuilder(); - builder.TargetType = typeof(DoesntImplementAnyInterfaces); - builder.BuildProxyType(); - } - - [Test] - public void WithSealedClass() - { - InheritanceProxyTypeBuilder builder = (InheritanceProxyTypeBuilder) GetProxyBuilder(); - builder.TargetType = typeof(SealedClass); - Assert.Throws(() => builder.BuildProxyType()); - } - - [Test] - public void ProxyInnerClass() - { - IProxyTypeBuilder builder = GetProxyBuilder(); - builder.TargetType = typeof(InnerClass); - Type proxy = builder.BuildProxyType(); - Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); - object foo = Activator.CreateInstance(proxy); - Assert.IsTrue(foo is InnerInterface); - Assert.IsTrue(foo is InnerClass); - } - - [Test] - public void CheckInheritType() - { - IProxyTypeBuilder builder = GetProxyBuilder(); - builder.TargetType = typeof(DoesntImplementAnyInterfaces); - Type proxy = builder.BuildProxyType(); - Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); - object foo = Activator.CreateInstance(proxy); - Assert.IsTrue(foo is DoesntImplementAnyInterfaces, - "Using inheritance proxying, so the proxied object must inherit from the base type."); - } - - [Test] - public void OverrideVirtualMethod() - { - IProxyTypeBuilder builder = GetProxyBuilder(); - builder.TargetType = typeof(TargetObjectTest); - Type proxy = builder.BuildProxyType(); - - MethodInfo method = ReflectionUtils.GetMethod(proxy, "InterfaceVirtualMethodWithNoArguments", Type.EmptyTypes); - - Assert.IsNotNull(method, "Should define this method."); - Assert.AreEqual(proxy, method.DeclaringType, "Method should be overrided in the proxy class."); - - // call overrided method - object foo = Activator.CreateInstance(proxy); - Assert.IsTrue(foo is TargetObjectTest); - ((TargetObjectTest)foo).InterfaceVirtualMethodWithNoArguments(); - } - - [Test] - public void ImplementFinalMethodThatImplementsInterface() - { - IProxyTypeBuilder builder = GetProxyBuilder(); - builder.TargetType = typeof(TargetObjectTest); - Type proxy = builder.BuildProxyType(); - - MethodInfo method = ReflectionUtils.GetMethod(proxy, "Spring.Proxy.ITargetObjectTest.InterfaceMethodWithArguments", new Type[] { typeof(string) }); - - Assert.IsNotNull(method, "Should define this method."); - Assert.AreEqual(proxy, method.DeclaringType, "Method should be defined in the proxy class."); - - // call final interfaced method - object foo = Activator.CreateInstance(proxy); - Assert.IsTrue(foo is ITargetObjectTest); - ((ITargetObjectTest)foo).InterfaceMethodWithArguments("code"); - } - - [Test] - public void DoesNotImplementFinalMethodThatDoesNotImplementInterface() - { - IProxyTypeBuilder builder = GetProxyBuilder(); - builder.TargetType = typeof(TargetObjectTest); - Type proxy = builder.BuildProxyType(); - - MethodInfo method = ReflectionUtils.GetMethod(proxy, "MethodWithArguments", new Type[] { typeof(string) }); - - Assert.IsNotNull(method, "Should define this method."); - Assert.AreNotEqual(proxy, method.DeclaringType, "Method can't be proxied."); - - // call base method - object foo = Activator.CreateInstance(proxy); - Assert.IsTrue(foo is TargetObjectTest); - ((TargetObjectTest)foo).MethodWithArguments("code"); - } - - [Test] - public void SetsInterfacesToProxy() - { - IProxyTypeBuilder builder = GetProxyBuilder(); - builder.TargetType = typeof(MultipleInterfaces); - builder.Interfaces = new Type[] { typeof(IAnotherMarkerInterface) }; - - Type proxy = builder.BuildProxyType(); - Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); - - object foo = Activator.CreateInstance(proxy); - Assert.IsTrue(foo is IBase); - Assert.IsTrue(foo is IInherited); - Assert.IsTrue(foo is IAnotherMarkerInterface); - - // try to call proxied interface methods - ((IBase)foo).Base(); - ((IInherited)foo).Base(); - ((IInherited)foo).Inherited(); - } - - - [Test] - public void DoesNotProxyNonProxiableInterface() - { - IProxyTypeBuilder builder = GetProxyBuilder(); - builder.TargetType = typeof(ApplicationClass); - - Type proxy = builder.BuildProxyType(); - Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); - - object foo = Activator.CreateInstance(proxy); - Assert.IsTrue(foo is IApplicationInterface); - Assert.IsTrue(foo is IFrameworkInterface); - - // proxy implements IApplicationInterface and proxy methods - Assert.IsNotNull(foo.GetType().GetMethod("Spring.Proxy.IApplicationInterface.ApplicationMethod", BindingFlags.Instance | BindingFlags.NonPublic)); - - // proxy implements IFrameworkInterface but should not proxy methods - Assert.IsNull(foo.GetType().GetMethod("Spring.Proxy.IFrameworkInterface.FrameworkMethod", BindingFlags.Instance | BindingFlags.NonPublic)); - } - - [Test] - public void ForcesNonProxiableInterfacesToBeProxied() - { - IProxyTypeBuilder builder = GetProxyBuilder(); - builder.TargetType = typeof(ApplicationClass); - builder.Interfaces = new Type[] { typeof(IFrameworkInterface) }; - - Type proxy = builder.BuildProxyType(); - Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); - - object foo = Activator.CreateInstance(proxy); - Assert.IsTrue(foo is IApplicationInterface); - Assert.IsTrue(foo is IFrameworkInterface); - - // proxy implements IFrameworkInterface and proxy methods - Assert.IsNotNull(foo.GetType().GetMethod("Spring.Proxy.IFrameworkInterface.FrameworkMethod", BindingFlags.Instance | BindingFlags.NonPublic)); - - // proxy implements IApplicationInterface but should not proxy methods - Assert.IsNull(foo.GetType().GetMethod("Spring.Proxy.IApplicationInterface.ApplicationMethod", BindingFlags.Instance | BindingFlags.NonPublic)); - } - - [Test] - public void ProxyTargetVirtualMethodAttributes() - { - IProxyTypeBuilder builder = GetProxyBuilder(); - builder.TargetType = typeof(AnotherMarkerClass); - Type proxy = builder.BuildProxyType(); - Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); - MethodInfo method = proxy.GetMethod("MarkerVirtualMethod"); - Assert.IsNotNull(method); - object[] attrs = method.GetCustomAttributes(false); - Assert.IsNotNull(attrs, "Should have 1 attribute applied to the target method."); - Assert.AreEqual(1, attrs.Length, "Should have 1 attribute applied to the target method."); - Assert.AreEqual(typeof(MarkerAttribute), attrs[0].GetType(), "Wrong System.Type of Attribute applied to the target method."); - } - - [Test] - public void DoesNotProxyTargetVirtualMethodAttributesWithProxyTargetAttributesEqualsFalse() - { - IProxyTypeBuilder builder = GetProxyBuilder(); - builder.TargetType = typeof(AnotherMarkerClass); - builder.ProxyTargetAttributes = false; - Type proxy = builder.BuildProxyType(); - Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); - MethodInfo method = proxy.GetMethod("MarkerVirtualMethod"); - Assert.IsNotNull(method); - object[] attrs = method.GetCustomAttributes(false); - Assert.IsNotNull(attrs); - Assert.AreEqual(0, attrs.Length, "Should not have attribute applied to the target method."); - } - - [Test] - public void ProxyTargetVirtualMethodParameterAttributes() - { - IProxyTypeBuilder builder = GetProxyBuilder(); - builder.TargetType = typeof(SomeMarkerClass); - Type proxy = builder.BuildProxyType(); - Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); - MethodInfo method = proxy.GetMethod("MarkerVirtualMethod"); - Assert.IsNotNull(method); - object[] attrs = method.GetParameters()[1].GetCustomAttributes(false); - Assert.IsNotNull(attrs, "Should have had 1 attribute applied to the method's parameter."); - Assert.AreEqual(1, attrs.Length, "Should have had 1 attribute applied to the method's parameter."); - Assert.AreEqual(typeof(MarkerAttribute), attrs[0].GetType(), "Wrong System.Type of Attribute applied to the method's parameter."); - } - - [Test] - [Description("SPRNET-1134")] - public void ProxyTargetVirtualMethodParameterMultipleAttributes() - { - IProxyTypeBuilder builder = GetProxyBuilder(); - builder.TargetType = typeof(MultipleMarkerClass); - Type proxy = builder.BuildProxyType(); - Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); - MethodInfo method = proxy.GetMethod("MarkerVirtualMethod"); - Assert.IsNotNull(method); - object[] attrs = method.GetParameters()[1].GetCustomAttributes(false); - Assert.IsNotNull(attrs, "Should have had 2 attribute applied to the method's parameter."); - Assert.AreEqual(2, attrs.Length, "Should have had 2 attribute applied to the method's parameter."); - Assert.AreEqual(typeof(MarkerAttribute), attrs[0].GetType(), "Wrong System.Type of Attribute applied to the method's parameter."); - Assert.AreEqual(typeof(MarkerAttribute), attrs[1].GetType(), "Wrong System.Type of Attribute applied to the method's parameter."); - } - - [Test] - public void DoesNotProxyTargetVirtualMethodParameterAttributesWithProxyTargetAttributesEqualsFalse() - { - IProxyTypeBuilder builder = GetProxyBuilder(); - builder.TargetType = typeof(SomeMarkerClass); - builder.ProxyTargetAttributes = false; - Type proxy = builder.BuildProxyType(); - Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); - MethodInfo method = proxy.GetMethod("MarkerVirtualMethod"); - Assert.IsNotNull(method); - object[] attrs = method.GetParameters()[1].GetCustomAttributes(false); - Assert.IsNotNull(attrs); - Assert.AreEqual(0, attrs.Length, "Should not have attribute applied to the method's parameter."); - } - - [Test] - public void ProxyTargetVirtualMethodReturnValueAttributes() - { - IProxyTypeBuilder builder = GetProxyBuilder(); - builder.TargetType = typeof(SomeMarkerClass); - Type proxy = builder.BuildProxyType(); - Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); - MethodInfo method = proxy.GetMethod("MarkerVirtualMethod"); - Assert.IsNotNull(method); - object[] attrs = method.ReturnTypeCustomAttributes.GetCustomAttributes(false); - Assert.IsNotNull(attrs, "Should have had 1 attribute applied to the method's return value."); - Assert.AreEqual(1, attrs.Length, "Should have had 1 attribute applied to the method's return value."); - Assert.AreEqual(typeof(MarkerAttribute), attrs[0].GetType(), "Wrong System.Type of Attribute applied to the method's return value."); - } - - [Test] - [Description("SPRNET-1134")] - public void ProxyTargetVirtualMethodReturnValueMultipleAttributes() - { - IProxyTypeBuilder builder = GetProxyBuilder(); - builder.TargetType = typeof(MultipleMarkerClass); - Type proxy = builder.BuildProxyType(); - Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); - MethodInfo method = proxy.GetMethod("MarkerVirtualMethod"); - Assert.IsNotNull(method); - object[] attrs = method.ReturnTypeCustomAttributes.GetCustomAttributes(false); - Assert.IsNotNull(attrs, "Should have had 2 attribute applied to the method's return value."); - Assert.AreEqual(2, attrs.Length, "Should have had 2 attribute applied to the method's return value."); - Assert.AreEqual(typeof(MarkerAttribute), attrs[0].GetType(), "Wrong System.Type of Attribute applied to the method's return value."); - Assert.AreEqual(typeof(MarkerAttribute), attrs[1].GetType(), "Wrong System.Type of Attribute applied to the method's return value."); - } - - [Test] - public void DoesNotProxyTargetVirtualMethodReturnValueAttributesWithProxyTargetAttributesEqualsFalse() - { - IProxyTypeBuilder builder = GetProxyBuilder(); - builder.TargetType = typeof(SomeMarkerClass); - builder.ProxyTargetAttributes = false; - Type proxy = builder.BuildProxyType(); - Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); - MethodInfo method = proxy.GetMethod("MarkerVirtualMethod"); - Assert.IsNotNull(method); - object[] attrs = method.ReturnTypeCustomAttributes.GetCustomAttributes(false); - Assert.IsNotNull(attrs); - Assert.AreEqual(0, attrs.Length, "Should not have attribute applied to the method's return value."); - } - - protected override IProxyTypeBuilder GetProxyBuilder() - { - return new InheritanceProxyTypeBuilder(); - } + IProxyTypeBuilder builder = GetProxyBuilder(); + builder.TargetType = typeof(DoesntImplementAnyInterfaces); + builder.BuildProxyType(); } - #region Helper Classes - - public class NotSealedClass + [Test] + public void WithSealedClass() { - public bool IsAnyoneThere() - { - return false; - } + InheritanceProxyTypeBuilder builder = (InheritanceProxyTypeBuilder) GetProxyBuilder(); + builder.TargetType = typeof(SealedClass); + Assert.Throws(() => builder.BuildProxyType()); } - public sealed class SealedClass - {} + [Test] + public void ProxyInnerClass() + { + IProxyTypeBuilder builder = GetProxyBuilder(); + builder.TargetType = typeof(InnerClass); + Type proxy = builder.BuildProxyType(); + Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); + object foo = Activator.CreateInstance(proxy); + Assert.IsTrue(foo is InnerInterface); + Assert.IsTrue(foo is InnerClass); + } - #endregion -} \ No newline at end of file + [Test] + public void CheckInheritType() + { + IProxyTypeBuilder builder = GetProxyBuilder(); + builder.TargetType = typeof(DoesntImplementAnyInterfaces); + Type proxy = builder.BuildProxyType(); + Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); + object foo = Activator.CreateInstance(proxy); + Assert.IsTrue(foo is DoesntImplementAnyInterfaces, + "Using inheritance proxying, so the proxied object must inherit from the base type."); + } + + [Test] + public void OverrideVirtualMethod() + { + IProxyTypeBuilder builder = GetProxyBuilder(); + builder.TargetType = typeof(TargetObjectTest); + Type proxy = builder.BuildProxyType(); + + MethodInfo method = ReflectionUtils.GetMethod(proxy, "InterfaceVirtualMethodWithNoArguments", Type.EmptyTypes); + + Assert.IsNotNull(method, "Should define this method."); + Assert.AreEqual(proxy, method.DeclaringType, "Method should be overrided in the proxy class."); + + // call overrided method + object foo = Activator.CreateInstance(proxy); + Assert.IsTrue(foo is TargetObjectTest); + ((TargetObjectTest) foo).InterfaceVirtualMethodWithNoArguments(); + } + + [Test] + public void ImplementFinalMethodThatImplementsInterface() + { + IProxyTypeBuilder builder = GetProxyBuilder(); + builder.TargetType = typeof(TargetObjectTest); + Type proxy = builder.BuildProxyType(); + + MethodInfo method = ReflectionUtils.GetMethod(proxy, "Spring.Proxy.ITargetObjectTest.InterfaceMethodWithArguments", new Type[] { typeof(string) }); + + Assert.IsNotNull(method, "Should define this method."); + Assert.AreEqual(proxy, method.DeclaringType, "Method should be defined in the proxy class."); + + // call final interfaced method + object foo = Activator.CreateInstance(proxy); + Assert.IsTrue(foo is ITargetObjectTest); + ((ITargetObjectTest) foo).InterfaceMethodWithArguments("code"); + } + + [Test] + public void DoesNotImplementFinalMethodThatDoesNotImplementInterface() + { + IProxyTypeBuilder builder = GetProxyBuilder(); + builder.TargetType = typeof(TargetObjectTest); + Type proxy = builder.BuildProxyType(); + + MethodInfo method = ReflectionUtils.GetMethod(proxy, "MethodWithArguments", new Type[] { typeof(string) }); + + Assert.IsNotNull(method, "Should define this method."); + Assert.AreNotEqual(proxy, method.DeclaringType, "Method can't be proxied."); + + // call base method + object foo = Activator.CreateInstance(proxy); + Assert.IsTrue(foo is TargetObjectTest); + ((TargetObjectTest) foo).MethodWithArguments("code"); + } + + [Test] + public void SetsInterfacesToProxy() + { + IProxyTypeBuilder builder = GetProxyBuilder(); + builder.TargetType = typeof(MultipleInterfaces); + builder.Interfaces = new Type[] { typeof(IAnotherMarkerInterface) }; + + Type proxy = builder.BuildProxyType(); + Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); + + object foo = Activator.CreateInstance(proxy); + Assert.IsTrue(foo is IBase); + Assert.IsTrue(foo is IInherited); + Assert.IsTrue(foo is IAnotherMarkerInterface); + + // try to call proxied interface methods + ((IBase) foo).Base(); + ((IInherited) foo).Base(); + ((IInherited) foo).Inherited(); + } + + [Test] + public void DoesNotProxyNonProxiableInterface() + { + IProxyTypeBuilder builder = GetProxyBuilder(); + builder.TargetType = typeof(ApplicationClass); + + Type proxy = builder.BuildProxyType(); + Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); + + object foo = Activator.CreateInstance(proxy); + Assert.IsTrue(foo is IApplicationInterface); + Assert.IsTrue(foo is IFrameworkInterface); + + // proxy implements IApplicationInterface and proxy methods + Assert.IsNotNull(foo.GetType().GetMethod("Spring.Proxy.IApplicationInterface.ApplicationMethod", BindingFlags.Instance | BindingFlags.NonPublic)); + + // proxy implements IFrameworkInterface but should not proxy methods + Assert.IsNull(foo.GetType().GetMethod("Spring.Proxy.IFrameworkInterface.FrameworkMethod", BindingFlags.Instance | BindingFlags.NonPublic)); + } + + [Test] + public void ForcesNonProxiableInterfacesToBeProxied() + { + IProxyTypeBuilder builder = GetProxyBuilder(); + builder.TargetType = typeof(ApplicationClass); + builder.Interfaces = new Type[] { typeof(IFrameworkInterface) }; + + Type proxy = builder.BuildProxyType(); + Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); + + object foo = Activator.CreateInstance(proxy); + Assert.IsTrue(foo is IApplicationInterface); + Assert.IsTrue(foo is IFrameworkInterface); + + // proxy implements IFrameworkInterface and proxy methods + Assert.IsNotNull(foo.GetType().GetMethod("Spring.Proxy.IFrameworkInterface.FrameworkMethod", BindingFlags.Instance | BindingFlags.NonPublic)); + + // proxy implements IApplicationInterface but should not proxy methods + Assert.IsNull(foo.GetType().GetMethod("Spring.Proxy.IApplicationInterface.ApplicationMethod", BindingFlags.Instance | BindingFlags.NonPublic)); + } + + [Test] + public void ProxyTargetVirtualMethodAttributes() + { + IProxyTypeBuilder builder = GetProxyBuilder(); + builder.TargetType = typeof(AnotherMarkerClass); + Type proxy = builder.BuildProxyType(); + Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); + MethodInfo method = proxy.GetMethod("MarkerVirtualMethod"); + Assert.IsNotNull(method); + object[] attrs = method.GetCustomAttributes(false); + Assert.IsNotNull(attrs, "Should have 1 attribute applied to the target method."); + Assert.AreEqual(1, attrs.Length, "Should have 1 attribute applied to the target method."); + Assert.AreEqual(typeof(MarkerAttribute), attrs[0].GetType(), "Wrong System.Type of Attribute applied to the target method."); + } + + [Test] + public void DoesNotProxyTargetVirtualMethodAttributesWithProxyTargetAttributesEqualsFalse() + { + IProxyTypeBuilder builder = GetProxyBuilder(); + builder.TargetType = typeof(AnotherMarkerClass); + builder.ProxyTargetAttributes = false; + Type proxy = builder.BuildProxyType(); + Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); + MethodInfo method = proxy.GetMethod("MarkerVirtualMethod"); + Assert.IsNotNull(method); + object[] attrs = method.GetCustomAttributes(false); + Assert.IsNotNull(attrs); + Assert.AreEqual(0, attrs.Length, "Should not have attribute applied to the target method."); + } + + [Test] + public void ProxyTargetVirtualMethodParameterAttributes() + { + IProxyTypeBuilder builder = GetProxyBuilder(); + builder.TargetType = typeof(SomeMarkerClass); + Type proxy = builder.BuildProxyType(); + Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); + MethodInfo method = proxy.GetMethod("MarkerVirtualMethod"); + Assert.IsNotNull(method); + object[] attrs = method.GetParameters()[1].GetCustomAttributes(false); + Assert.IsNotNull(attrs, "Should have had 1 attribute applied to the method's parameter."); + Assert.AreEqual(1, attrs.Length, "Should have had 1 attribute applied to the method's parameter."); + Assert.AreEqual(typeof(MarkerAttribute), attrs[0].GetType(), "Wrong System.Type of Attribute applied to the method's parameter."); + } + + [Test] + [Description("SPRNET-1134")] + public void ProxyTargetVirtualMethodParameterMultipleAttributes() + { + IProxyTypeBuilder builder = GetProxyBuilder(); + builder.TargetType = typeof(MultipleMarkerClass); + Type proxy = builder.BuildProxyType(); + Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); + MethodInfo method = proxy.GetMethod("MarkerVirtualMethod"); + Assert.IsNotNull(method); + object[] attrs = method.GetParameters()[1].GetCustomAttributes(false); + Assert.IsNotNull(attrs, "Should have had 2 attribute applied to the method's parameter."); + Assert.AreEqual(2, attrs.Length, "Should have had 2 attribute applied to the method's parameter."); + Assert.AreEqual(typeof(MarkerAttribute), attrs[0].GetType(), "Wrong System.Type of Attribute applied to the method's parameter."); + Assert.AreEqual(typeof(MarkerAttribute), attrs[1].GetType(), "Wrong System.Type of Attribute applied to the method's parameter."); + } + + [Test] + public void DoesNotProxyTargetVirtualMethodParameterAttributesWithProxyTargetAttributesEqualsFalse() + { + IProxyTypeBuilder builder = GetProxyBuilder(); + builder.TargetType = typeof(SomeMarkerClass); + builder.ProxyTargetAttributes = false; + Type proxy = builder.BuildProxyType(); + Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); + MethodInfo method = proxy.GetMethod("MarkerVirtualMethod"); + Assert.IsNotNull(method); + object[] attrs = method.GetParameters()[1].GetCustomAttributes(false); + Assert.IsNotNull(attrs); + Assert.AreEqual(0, attrs.Length, "Should not have attribute applied to the method's parameter."); + } + + [Test] + public void ProxyTargetVirtualMethodReturnValueAttributes() + { + IProxyTypeBuilder builder = GetProxyBuilder(); + builder.TargetType = typeof(SomeMarkerClass); + Type proxy = builder.BuildProxyType(); + Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); + MethodInfo method = proxy.GetMethod("MarkerVirtualMethod"); + Assert.IsNotNull(method); + object[] attrs = method.ReturnTypeCustomAttributes.GetCustomAttributes(false); + Assert.IsNotNull(attrs, "Should have had 1 attribute applied to the method's return value."); + Assert.AreEqual(1, attrs.Length, "Should have had 1 attribute applied to the method's return value."); + Assert.AreEqual(typeof(MarkerAttribute), attrs[0].GetType(), "Wrong System.Type of Attribute applied to the method's return value."); + } + + [Test] + [Description("SPRNET-1134")] + public void ProxyTargetVirtualMethodReturnValueMultipleAttributes() + { + IProxyTypeBuilder builder = GetProxyBuilder(); + builder.TargetType = typeof(MultipleMarkerClass); + Type proxy = builder.BuildProxyType(); + Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); + MethodInfo method = proxy.GetMethod("MarkerVirtualMethod"); + Assert.IsNotNull(method); + object[] attrs = method.ReturnTypeCustomAttributes.GetCustomAttributes(false); + Assert.IsNotNull(attrs, "Should have had 2 attribute applied to the method's return value."); + Assert.AreEqual(2, attrs.Length, "Should have had 2 attribute applied to the method's return value."); + Assert.AreEqual(typeof(MarkerAttribute), attrs[0].GetType(), "Wrong System.Type of Attribute applied to the method's return value."); + Assert.AreEqual(typeof(MarkerAttribute), attrs[1].GetType(), "Wrong System.Type of Attribute applied to the method's return value."); + } + + [Test] + public void DoesNotProxyTargetVirtualMethodReturnValueAttributesWithProxyTargetAttributesEqualsFalse() + { + IProxyTypeBuilder builder = GetProxyBuilder(); + builder.TargetType = typeof(SomeMarkerClass); + builder.ProxyTargetAttributes = false; + Type proxy = builder.BuildProxyType(); + Assert.IsNotNull(proxy, "The proxy generated by a (valid) call to BuildProxy() was null."); + MethodInfo method = proxy.GetMethod("MarkerVirtualMethod"); + Assert.IsNotNull(method); + object[] attrs = method.ReturnTypeCustomAttributes.GetCustomAttributes(false); + Assert.IsNotNull(attrs); + Assert.AreEqual(0, attrs.Length, "Should not have attribute applied to the method's return value."); + } + + protected override IProxyTypeBuilder GetProxyBuilder() + { + return new InheritanceProxyTypeBuilder(); + } +} + +#region Helper Classes + +public class NotSealedClass +{ + public bool IsAnyoneThere() + { + return false; + } +} + +public sealed class SealedClass +{ +} + +#endregion diff --git a/test/Spring/Spring.Core.Tests/Reflection/Dynamic/BasePropertyTests.cs b/test/Spring/Spring.Core.Tests/Reflection/Dynamic/BasePropertyTests.cs index 72f336be..949cb9ac 100644 --- a/test/Spring/Spring.Core.Tests/Reflection/Dynamic/BasePropertyTests.cs +++ b/test/Spring/Spring.Core.Tests/Reflection/Dynamic/BasePropertyTests.cs @@ -1,366 +1,362 @@ using System.Diagnostics; using System.Reflection; - using NUnit.Framework; using Spring.Context.Support; -namespace Spring.Reflection.Dynamic +namespace Spring.Reflection.Dynamic; + +/// +/// Unit tests common for all IDynamicProperty implementations. +/// +/// Aleksandar Seovic +/// Erich Eichinger +public abstract class BasePropertyTests { + protected Inventor tesla; + protected Inventor pupin; + protected Society ieee; + + #region SetUp and TearDown + /// - /// Unit tests common for all IDynamicProperty implementations. + /// The setup logic executed before the execution of each individual test. /// - /// Aleksandar Seovic - /// Erich Eichinger - public abstract class BasePropertyTests + [SetUp] + public void SetUp() { - protected Inventor tesla; - protected Inventor pupin; - protected Society ieee; + ContextRegistry.Clear(); + tesla = new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian"); + tesla.Inventions = new string[] { "Telephone repeater", "Rotating magnetic field principle", "Polyphase alternating-current system", "Induction motor", "Alternating-current power transmission", "Tesla coil transformer", "Wireless communication", "Radio", "Fluorescent lights" }; + tesla.PlaceOfBirth.City = "Smiljan"; - #region SetUp and TearDown + pupin = new Inventor("Mihajlo Pupin", new DateTime(1854, 10, 9), "Serbian"); + pupin.Inventions = new string[] { "Long distance telephony & telegraphy", "Secondary X-Ray radiation", "Sonar" }; + pupin.PlaceOfBirth.City = "Idvor"; + pupin.PlaceOfBirth.Country = "Serbia"; - /// - /// The setup logic executed before the execution of each individual test. - /// - [SetUp] - public void SetUp() - { - ContextRegistry.Clear(); - tesla = new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian"); - tesla.Inventions = new string[] - { - "Telephone repeater", "Rotating magnetic field principle", - "Polyphase alternating-current system", "Induction motor", - "Alternating-current power transmission", "Tesla coil transformer", - "Wireless communication", "Radio", "Fluorescent lights" - }; - tesla.PlaceOfBirth.City = "Smiljan"; - - pupin = new Inventor("Mihajlo Pupin", new DateTime(1854, 10, 9), "Serbian"); - pupin.Inventions = new string[] { "Long distance telephony & telegraphy", "Secondary X-Ray radiation", "Sonar" }; - pupin.PlaceOfBirth.City = "Idvor"; - pupin.PlaceOfBirth.Country = "Serbia"; - - ieee = new Society(); - ieee.Members.Add(tesla); - ieee.Members.Add(pupin); - ieee.Officers["president"] = pupin; - ieee.Officers["advisors"] = new Inventor[] { tesla, pupin }; // not historically accurate, but I need an array in the map ;-) - } - - [OneTimeTearDown] - public void TearDown() - { - //DynamicReflectionManager.SaveAssembly(); - } - - #endregion - - protected abstract IDynamicProperty Create(PropertyInfo property); - - [Test] - public void TestInstanceProperties() - { - IDynamicProperty placeOfBirth = Create(typeof(Inventor).GetProperty("PlaceOfBirth")); - Assert.AreEqual(tesla.PlaceOfBirth, placeOfBirth.GetValue(tesla)); - - IDynamicProperty dateOfBirth = Create(typeof(Inventor).GetProperty("DOB")); - Assert.AreEqual(tesla.DOB, dateOfBirth.GetValue(tesla)); - dateOfBirth.SetValue(tesla, new DateTime(2004, 8, 14)); - Assert.AreEqual(new DateTime(2004, 8, 14), dateOfBirth.GetValue(tesla)); - - DateTime mostImportantDayInTheWorldEver = new DateTime(2004, 8, 14); - IDynamicProperty year = Create(typeof(DateTime).GetProperty("Year")); - Assert.AreEqual(mostImportantDayInTheWorldEver.Year, year.GetValue(mostImportantDayInTheWorldEver)); - } - - [Test] - public void AccessInheritedPropertyFromBaseClass() - { - IDynamicProperty p = Create(typeof(ClassWithNonReadableProperty).GetProperty("MyBaseProperty")); - BaseClass baseObject = new BaseClass(); - baseObject.MyBaseProperty = "testtext"; - Assert.AreEqual("testtext", p.GetValue(baseObject)); - } - - [Test] - public void AccessInheritedPropertyFromDerivedClass() - { - IDynamicProperty p = Create(typeof(BaseClass).GetProperty("MyBaseProperty")); - ClassWithNonReadableProperty derivedObject = new ClassWithNonReadableProperty(); - derivedObject.MyBaseProperty = "testtext"; - Assert.AreEqual("testtext", p.GetValue(derivedObject)); - } - - [Test] - public void AccessOverriddenProperty() - { - IDynamicProperty pVirt = Create(typeof(BaseClass).GetProperty("MyVirtualBaseProperty")); - IDynamicProperty pOverridden = Create(typeof(ClassWithNonReadableProperty).GetProperty("MyVirtualBaseProperty")); - - Assert.AreEqual("MyVirtualBasePropertyText", pVirt.GetValue(new BaseClass())); - try - { - Assert.AreEqual("MyVirtualBasePropertyText", pOverridden.GetValue(new BaseClass())); - Assert.Fail(); - } - catch (InvalidCastException) - { - } - Assert.AreEqual("MyOverridenDerivedPropertyText", pVirt.GetValue(new ClassWithNonReadableProperty())); - Assert.AreEqual("MyOverridenDerivedPropertyText", pOverridden.GetValue(new ClassWithNonReadableProperty())); - } - - - [Test] - public void TestStaticProperties() - { - IDynamicProperty today = Create(typeof(DateTime).GetProperty("Today")); - Assert.AreEqual(DateTime.Today, today.GetValue(null)); - - IDynamicProperty myProperty = Create(typeof(MyStaticClass).GetProperty("MyProperty")); - myProperty.SetValue(null, "here we go..."); - Assert.AreEqual("here we go...", myProperty.GetValue(null)); - } - - [Test, Ignore("test N/A anymore due to System.Reflection.Emit.DynamicMethod")] - public void TestForRestrictiveGetter() - { - Something something = new Something(); - - IDynamicProperty third = Create(typeof(Something).GetProperty("Third")); - //this should be ok, because both get and set of the "Third" property are public - third.SetValue(something, 456); - Assert.AreEqual(456, third.GetValue(something)); - - IDynamicProperty first = Create(typeof(Something).GetProperty("First")); - first.SetValue(something, 123); - //this should cause MethodAccessException, because get is private - Assert.Throws(() => first.GetValue(something)); - } - - [Test, Ignore("test N/A anymore due to System.Reflection.Emit.DynamicMethod")] - public void TestForRestrictiveSetter() - { - Something something = new Something(); - - IDynamicProperty third = Create(typeof(Something).GetProperty("Third")); - third.SetValue(something, 456); - //this should be ok, because both get and set of the "Third" property are public - Assert.AreEqual(456, third.GetValue(something)); - - IDynamicProperty second = Create(typeof(Something).GetProperty("Second")); - Assert.AreEqual(2, second.GetValue(something)); - //this should cause MethodAccessException, because set is private in "Second" property - second.SetValue(something, 123); - - //this should never execute - Assert.Throws(() => second.GetValue(something)); - } - - #region Performance tests - - private DateTime start, stop; - - [Test] - [Explicit] - public void PerformanceTests() - { - int n = 10000000; - object x = null; - - // tesla.PlaceOfBirth - start = DateTime.Now; - for (int i = 0; i < n; i++) - { - x = tesla.PlaceOfBirth; - } - stop = DateTime.Now; - PrintTest("tesla.PlaceOfBirth (direct)", n, Elapsed); - - start = DateTime.Now; - IDynamicProperty placeOfBirth = DynamicProperty.Create(typeof(Inventor).GetProperty("PlaceOfBirth")); - for (int i = 0; i < n; i++) - { - x = placeOfBirth.GetValue(tesla); - } - stop = DateTime.Now; - PrintTest("tesla.PlaceOfBirth (dynamic reflection)", n, Elapsed); - - start = DateTime.Now; - PropertyInfo placeOfBirthPi = typeof(Inventor).GetProperty("PlaceOfBirth"); - for (int i = 0; i < n; i++) - { - x = placeOfBirthPi.GetValue(tesla, null); - } - stop = DateTime.Now; - PrintTest("tesla.PlaceOfBirth (standard reflection)", n, Elapsed); - } - - private double Elapsed - { - get { return (stop.Ticks - start.Ticks) / 10000000f; } - } - - private void PrintTest(string name, int iterations, double duration) - { - Debug.WriteLine(String.Format("{0,-60} {1,12:#,###} {2,12:##0.000} {3,12:#,###}", name, iterations, duration, iterations / duration)); - } - - #endregion + ieee = new Society(); + ieee.Members.Add(tesla); + ieee.Members.Add(pupin); + ieee.Officers["president"] = pupin; + ieee.Officers["advisors"] = new Inventor[] { tesla, pupin }; // not historically accurate, but I need an array in the map ;-) } - #region IL generation helper classes (they help if you look at them in Reflector ;-) - - public class ValueTypeProperty //: IDynamicProperty + [OneTimeTearDown] + public void TearDown() { - public object GetValue(object target) - { - return ((Inventor)target).DOB; - } - - public void SetValue(object target, object value) - { - ((Inventor)target).DOB = (DateTime)value; - } - } - - public class ValueTypeTarget //: IDynamicProperty - { - public object GetValue(object target) - { - return ((MyStruct)target).Year; - } - - public void SetValue(object target, object value) - { - MyStruct o = (MyStruct)target; - o.Year = (int)value; - } - } - - public class StaticProperty //: IDynamicProperty - { - public object GetValue(object target) - { - return MyStaticClass.MyProperty; - } - - public void SetValue(object target, object value) - { - MyStaticClass.MyProperty = (string)value; - } + //DynamicReflectionManager.SaveAssembly(); } #endregion - public class MyStaticClass + protected abstract IDynamicProperty Create(PropertyInfo property); + + [Test] + public void TestInstanceProperties() { - public const Int64 MyConst = 3456; - public static readonly string myReadonlyField; - private static readonly string myPrivateReadonlyField; - public static string myField; + IDynamicProperty placeOfBirth = Create(typeof(Inventor).GetProperty("PlaceOfBirth")); + Assert.AreEqual(tesla.PlaceOfBirth, placeOfBirth.GetValue(tesla)); - static MyStaticClass() - { - myReadonlyField = "hohoho"; - myPrivateReadonlyField = "hahaha"; - } + IDynamicProperty dateOfBirth = Create(typeof(Inventor).GetProperty("DOB")); + Assert.AreEqual(tesla.DOB, dateOfBirth.GetValue(tesla)); + dateOfBirth.SetValue(tesla, new DateTime(2004, 8, 14)); + Assert.AreEqual(new DateTime(2004, 8, 14), dateOfBirth.GetValue(tesla)); - public static string MyProperty - { - get { return myField; } - set { myField = value; } - } - - public static string MyPrivateReadOnylFieldAccessor - { - get { return myPrivateReadonlyField; } - } + DateTime mostImportantDayInTheWorldEver = new DateTime(2004, 8, 14); + IDynamicProperty year = Create(typeof(DateTime).GetProperty("Year")); + Assert.AreEqual(mostImportantDayInTheWorldEver.Year, year.GetValue(mostImportantDayInTheWorldEver)); } - public struct MyStaticStruct + [Test] + public void AccessInheritedPropertyFromBaseClass() { - public const int constant = 20; - public static int staticYear; - - public static int StaticYear - { - get { return staticYear; } - set { staticYear = value; } - } + IDynamicProperty p = Create(typeof(ClassWithNonReadableProperty).GetProperty("MyBaseProperty")); + BaseClass baseObject = new BaseClass(); + baseObject.MyBaseProperty = "testtext"; + Assert.AreEqual("testtext", p.GetValue(baseObject)); } - public struct MyStruct + [Test] + public void AccessInheritedPropertyFromDerivedClass() { - public int year; - - public int Year - { - get { return year; } - set { year = value; } - } + IDynamicProperty p = Create(typeof(BaseClass).GetProperty("MyBaseProperty")); + ClassWithNonReadableProperty derivedObject = new ClassWithNonReadableProperty(); + derivedObject.MyBaseProperty = "testtext"; + Assert.AreEqual("testtext", p.GetValue(derivedObject)); } - public class BaseClass + [Test] + public void AccessOverriddenProperty() { - private string myBaseProperty; + IDynamicProperty pVirt = Create(typeof(BaseClass).GetProperty("MyVirtualBaseProperty")); + IDynamicProperty pOverridden = Create(typeof(ClassWithNonReadableProperty).GetProperty("MyVirtualBaseProperty")); - public string MyBaseProperty + Assert.AreEqual("MyVirtualBasePropertyText", pVirt.GetValue(new BaseClass())); + try { - set { myBaseProperty = value; } - get { return myBaseProperty; } - } - - public virtual string MyVirtualBaseProperty - { - get { return "MyVirtualBasePropertyText"; } + Assert.AreEqual("MyVirtualBasePropertyText", pOverridden.GetValue(new BaseClass())); + Assert.Fail(); } + catch (InvalidCastException) + { + } + + Assert.AreEqual("MyOverridenDerivedPropertyText", pVirt.GetValue(new ClassWithNonReadableProperty())); + Assert.AreEqual("MyOverridenDerivedPropertyText", pOverridden.GetValue(new ClassWithNonReadableProperty())); } - public class ClassWithNonReadableProperty : BaseClass + [Test] + public void TestStaticProperties() { - private string myProperty; + IDynamicProperty today = Create(typeof(DateTime).GetProperty("Today")); + Assert.AreEqual(DateTime.Today, today.GetValue(null)); - public string MyProperty - { - set { myProperty = value; } - } - - public override string MyVirtualBaseProperty - { - get { return "MyOverridenDerivedPropertyText"; } - } + IDynamicProperty myProperty = Create(typeof(MyStaticClass).GetProperty("MyProperty")); + myProperty.SetValue(null, "here we go..."); + Assert.AreEqual("here we go...", myProperty.GetValue(null)); } - public class Something + [Test, Ignore("test N/A anymore due to System.Reflection.Emit.DynamicMethod")] + public void TestForRestrictiveGetter() { - public int First + Something something = new Something(); + + IDynamicProperty third = Create(typeof(Something).GetProperty("Third")); + //this should be ok, because both get and set of the "Third" property are public + third.SetValue(something, 456); + Assert.AreEqual(456, third.GetValue(something)); + + IDynamicProperty first = Create(typeof(Something).GetProperty("First")); + first.SetValue(something, 123); + //this should cause MethodAccessException, because get is private + Assert.Throws(() => first.GetValue(something)); + } + + [Test, Ignore("test N/A anymore due to System.Reflection.Emit.DynamicMethod")] + public void TestForRestrictiveSetter() + { + Something something = new Something(); + + IDynamicProperty third = Create(typeof(Something).GetProperty("Third")); + third.SetValue(something, 456); + //this should be ok, because both get and set of the "Third" property are public + Assert.AreEqual(456, third.GetValue(something)); + + IDynamicProperty second = Create(typeof(Something).GetProperty("Second")); + Assert.AreEqual(2, second.GetValue(something)); + //this should cause MethodAccessException, because set is private in "Second" property + second.SetValue(something, 123); + + //this should never execute + Assert.Throws(() => second.GetValue(something)); + } + + #region Performance tests + + private DateTime start, stop; + + [Test] + [Explicit] + public void PerformanceTests() + { + int n = 10000000; + object x = null; + + // tesla.PlaceOfBirth + start = DateTime.Now; + for (int i = 0; i < n; i++) { - private get { return first; } - set { first = value; } + x = tesla.PlaceOfBirth; } - public int Second + stop = DateTime.Now; + PrintTest("tesla.PlaceOfBirth (direct)", n, Elapsed); + + start = DateTime.Now; + IDynamicProperty placeOfBirth = DynamicProperty.Create(typeof(Inventor).GetProperty("PlaceOfBirth")); + for (int i = 0; i < n; i++) { - get { return second; } - private set { second = value; } + x = placeOfBirth.GetValue(tesla); } - public int Third - { - get { return third; } - set { third = value; } - } - public Something() - { - first = 1; - second = 2; - third = 3; - } - private int first; - private int second; - private int third; + stop = DateTime.Now; + PrintTest("tesla.PlaceOfBirth (dynamic reflection)", n, Elapsed); + start = DateTime.Now; + PropertyInfo placeOfBirthPi = typeof(Inventor).GetProperty("PlaceOfBirth"); + for (int i = 0; i < n; i++) + { + x = placeOfBirthPi.GetValue(tesla, null); + } + + stop = DateTime.Now; + PrintTest("tesla.PlaceOfBirth (standard reflection)", n, Elapsed); + } + + private double Elapsed + { + get { return (stop.Ticks - start.Ticks) / 10000000f; } + } + + private void PrintTest(string name, int iterations, double duration) + { + Debug.WriteLine(String.Format("{0,-60} {1,12:#,###} {2,12:##0.000} {3,12:#,###}", name, iterations, duration, iterations / duration)); + } + + #endregion +} + +#region IL generation helper classes (they help if you look at them in Reflector ;-) + +public class ValueTypeProperty //: IDynamicProperty +{ + public object GetValue(object target) + { + return ((Inventor) target).DOB; + } + + public void SetValue(object target, object value) + { + ((Inventor) target).DOB = (DateTime) value; } } + +public class ValueTypeTarget //: IDynamicProperty +{ + public object GetValue(object target) + { + return ((MyStruct) target).Year; + } + + public void SetValue(object target, object value) + { + MyStruct o = (MyStruct) target; + o.Year = (int) value; + } +} + +public class StaticProperty //: IDynamicProperty +{ + public object GetValue(object target) + { + return MyStaticClass.MyProperty; + } + + public void SetValue(object target, object value) + { + MyStaticClass.MyProperty = (string) value; + } +} + +#endregion + +public class MyStaticClass +{ + public const Int64 MyConst = 3456; + public static readonly string myReadonlyField; + private static readonly string myPrivateReadonlyField; + public static string myField; + + static MyStaticClass() + { + myReadonlyField = "hohoho"; + myPrivateReadonlyField = "hahaha"; + } + + public static string MyProperty + { + get { return myField; } + set { myField = value; } + } + + public static string MyPrivateReadOnylFieldAccessor + { + get { return myPrivateReadonlyField; } + } +} + +public struct MyStaticStruct +{ + public const int constant = 20; + public static int staticYear; + + public static int StaticYear + { + get { return staticYear; } + set { staticYear = value; } + } +} + +public struct MyStruct +{ + public int year; + + public int Year + { + get { return year; } + set { year = value; } + } +} + +public class BaseClass +{ + private string myBaseProperty; + + public string MyBaseProperty + { + set { myBaseProperty = value; } + get { return myBaseProperty; } + } + + public virtual string MyVirtualBaseProperty + { + get { return "MyVirtualBasePropertyText"; } + } +} + +public class ClassWithNonReadableProperty : BaseClass +{ + private string myProperty; + + public string MyProperty + { + set { myProperty = value; } + } + + public override string MyVirtualBaseProperty + { + get { return "MyOverridenDerivedPropertyText"; } + } +} + +public class Something +{ + public int First + { + private get { return first; } + set { first = value; } + } + + public int Second + { + get { return second; } + private set { second = value; } + } + + public int Third + { + get { return third; } + set { third = value; } + } + + public Something() + { + first = 1; + second = 2; + third = 3; + } + + private int first; + private int second; + private int third; +} \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/Reflection/Dynamic/DynamicConstructorTests.cs b/test/Spring/Spring.Core.Tests/Reflection/Dynamic/DynamicConstructorTests.cs index ef9b2e9e..9a7443c4 100644 --- a/test/Spring/Spring.Core.Tests/Reflection/Dynamic/DynamicConstructorTests.cs +++ b/test/Spring/Spring.Core.Tests/Reflection/Dynamic/DynamicConstructorTests.cs @@ -27,124 +27,119 @@ using Spring.Context.Support; #endregion -namespace Spring.Reflection.Dynamic +namespace Spring.Reflection.Dynamic; + +/// +/// Unit tests for the DynamicConstructor class. +/// +/// Aleksandar Seovic +[TestFixture] +public sealed class DynamicConstructorTests { - /// - /// Unit tests for the DynamicConstructor class. + private Inventor tesla; + private Inventor pupin; + private Society ieee; + + #region SetUp and TearDown + + /// + /// The setup logic executed before the execution of each individual test. /// - /// Aleksandar Seovic - [TestFixture] - public sealed class DynamicConstructorTests + [SetUp] + public void SetUp() { - private Inventor tesla; - private Inventor pupin; - private Society ieee; + ContextRegistry.Clear(); + tesla = new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian"); + tesla.Inventions = new string[] { "Telephone repeater", "Rotating magnetic field principle", "Polyphase alternating-current system", "Induction motor", "Alternating-current power transmission", "Tesla coil transformer", "Wireless communication", "Radio", "Fluorescent lights" }; + tesla.PlaceOfBirth.City = "Smiljan"; - #region SetUp and TearDown + pupin = new Inventor("Mihajlo Pupin", new DateTime(1854, 10, 9), "Serbian"); + pupin.Inventions = new string[] { "Long distance telephony & telegraphy", "Secondary X-Ray radiation", "Sonar" }; + pupin.PlaceOfBirth.City = "Idvor"; + pupin.PlaceOfBirth.Country = "Serbia"; - /// - /// The setup logic executed before the execution of each individual test. - /// - [SetUp] - public void SetUp() - { - ContextRegistry.Clear(); - tesla = new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian"); - tesla.Inventions = new string[] - { - "Telephone repeater", "Rotating magnetic field principle", - "Polyphase alternating-current system", "Induction motor", - "Alternating-current power transmission", "Tesla coil transformer", - "Wireless communication", "Radio", "Fluorescent lights" - }; - tesla.PlaceOfBirth.City = "Smiljan"; - - pupin = new Inventor("Mihajlo Pupin", new DateTime(1854, 10, 9), "Serbian"); - pupin.Inventions = new string[] { "Long distance telephony & telegraphy", "Secondary X-Ray radiation", "Sonar" }; - pupin.PlaceOfBirth.City = "Idvor"; - pupin.PlaceOfBirth.Country = "Serbia"; - - ieee = new Society(); - ieee.Members.Add(tesla); - ieee.Members.Add(pupin); - ieee.Officers["president"] = pupin; - ieee.Officers["advisors"] = new Inventor[] { tesla, pupin }; // not historically accurate, but I need an array in the map ;-) - } - - [OneTimeTearDown] - public void TearDown() - { - //DynamicReflectionManager.SaveAssembly(); - } - - #endregion - - [Test] - public void TestConstructors() - { - IDynamicConstructor newInventor = DynamicConstructor.Create( - typeof(Inventor).GetConstructor(new Type[] { typeof(string), typeof(DateTime), typeof(string) })); - Inventor ana = (Inventor) newInventor.Invoke(new object[] {"Ana Maria Seovic", new DateTime(2004, 8, 14), "Serbian"}); - Assert.AreEqual("Ana Maria Seovic", ana.Name); - - IDynamicConstructor newDate = DynamicConstructor.Create( - typeof(DateTime).GetConstructor(new Type[] { typeof(int), typeof(int), typeof(int) })); - Assert.AreEqual(DateTime.Today, newDate.Invoke(new object[] { DateTime.Today.Year, DateTime.Today.Month, DateTime.Today.Day })); - } - - #region Performance tests - - private DateTime start, stop; - - //[Test] - public void PerformanceTests() - { - int n = 10000000; - object x = null; - - // new Inventor() - start = DateTime.Now; - for (int i = 0; i < n; i++) - { - x = new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian"); - } - stop = DateTime.Now; - PrintTest("new Inventor() (direct)", n, Elapsed); - - start = DateTime.Now; - IDynamicConstructor newInventor = DynamicConstructor.Create( - typeof(Inventor).GetConstructor(new Type[] { typeof(string), typeof(DateTime), typeof(string) })); - for (int i = 0; i < n; i++) - { - object[] args = new object[] { "Nikola Tesla", new DateTime(1856, 7, 9), "Serbian" }; - x = newInventor.Invoke(args); - } - stop = DateTime.Now; - PrintTest("new Inventor() (dynamic reflection)", n, Elapsed); - - start = DateTime.Now; - ConstructorInfo newInventorCi = - typeof(Inventor).GetConstructor(new Type[] { typeof(string), typeof(DateTime), typeof(string) }); - for (int i = 0; i < n; i++) - { - object[] args = new object[] { "Nikola Tesla", new DateTime(1856, 7, 9), "Serbian" }; - x = newInventorCi.Invoke(args); - } - stop = DateTime.Now; - PrintTest("new Inventor() (standard reflection)", n, Elapsed); - } - - private double Elapsed - { - get { return (stop.Ticks - start.Ticks) / 10000000f; } - } - - private void PrintTest(string name, int iterations, double duration) - { - Debug.WriteLine(String.Format("{0,-60} {1,12:#,###} {2,12:##0.000} {3,12:#,###}", name, iterations, duration, iterations / duration)); - } - - #endregion - + ieee = new Society(); + ieee.Members.Add(tesla); + ieee.Members.Add(pupin); + ieee.Officers["president"] = pupin; + ieee.Officers["advisors"] = new Inventor[] { tesla, pupin }; // not historically accurate, but I need an array in the map ;-) } + + [OneTimeTearDown] + public void TearDown() + { + //DynamicReflectionManager.SaveAssembly(); + } + + #endregion + + [Test] + public void TestConstructors() + { + IDynamicConstructor newInventor = DynamicConstructor.Create( + typeof(Inventor).GetConstructor(new Type[] { typeof(string), typeof(DateTime), typeof(string) })); + Inventor ana = (Inventor) newInventor.Invoke(new object[] { "Ana Maria Seovic", new DateTime(2004, 8, 14), "Serbian" }); + Assert.AreEqual("Ana Maria Seovic", ana.Name); + + IDynamicConstructor newDate = DynamicConstructor.Create( + typeof(DateTime).GetConstructor(new Type[] { typeof(int), typeof(int), typeof(int) })); + Assert.AreEqual(DateTime.Today, newDate.Invoke(new object[] { DateTime.Today.Year, DateTime.Today.Month, DateTime.Today.Day })); + } + + #region Performance tests + + private DateTime start, stop; + + //[Test] + public void PerformanceTests() + { + int n = 10000000; + object x = null; + + // new Inventor() + start = DateTime.Now; + for (int i = 0; i < n; i++) + { + x = new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian"); + } + + stop = DateTime.Now; + PrintTest("new Inventor() (direct)", n, Elapsed); + + start = DateTime.Now; + IDynamicConstructor newInventor = DynamicConstructor.Create( + typeof(Inventor).GetConstructor(new Type[] { typeof(string), typeof(DateTime), typeof(string) })); + for (int i = 0; i < n; i++) + { + object[] args = new object[] { "Nikola Tesla", new DateTime(1856, 7, 9), "Serbian" }; + x = newInventor.Invoke(args); + } + + stop = DateTime.Now; + PrintTest("new Inventor() (dynamic reflection)", n, Elapsed); + + start = DateTime.Now; + ConstructorInfo newInventorCi = + typeof(Inventor).GetConstructor(new Type[] { typeof(string), typeof(DateTime), typeof(string) }); + for (int i = 0; i < n; i++) + { + object[] args = new object[] { "Nikola Tesla", new DateTime(1856, 7, 9), "Serbian" }; + x = newInventorCi.Invoke(args); + } + + stop = DateTime.Now; + PrintTest("new Inventor() (standard reflection)", n, Elapsed); + } + + private double Elapsed + { + get { return (stop.Ticks - start.Ticks) / 10000000f; } + } + + private void PrintTest(string name, int iterations, double duration) + { + Debug.WriteLine(String.Format("{0,-60} {1,12:#,###} {2,12:##0.000} {3,12:#,###}", name, iterations, duration, iterations / duration)); + } + + #endregion } diff --git a/test/Spring/Spring.Core.Tests/Reflection/Dynamic/DynamicFieldTests.cs b/test/Spring/Spring.Core.Tests/Reflection/Dynamic/DynamicFieldTests.cs index 36601487..a4f03e33 100644 --- a/test/Spring/Spring.Core.Tests/Reflection/Dynamic/DynamicFieldTests.cs +++ b/test/Spring/Spring.Core.Tests/Reflection/Dynamic/DynamicFieldTests.cs @@ -20,289 +20,282 @@ using System.Diagnostics; using System.Reflection; - using NUnit.Framework; using Spring.Context.Support; -namespace Spring.Reflection.Dynamic +namespace Spring.Reflection.Dynamic; + +/// +/// Unit tests for the DynamicField class. +/// +/// Aleksandar Seovic +[TestFixture] +public class DynamicFieldTests { + protected const BindingFlags BINDANY = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static; + protected Inventor tesla; + protected Inventor pupin; + protected Society ieee; + + #region SetUp and TearDown + /// - /// Unit tests for the DynamicField class. + /// The setup logic executed before the execution of each individual test. /// - /// Aleksandar Seovic - [TestFixture] - public class DynamicFieldTests + [SetUp] + public void SetUp() { - protected const BindingFlags BINDANY = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static; - protected Inventor tesla; - protected Inventor pupin; - protected Society ieee; + ContextRegistry.Clear(); + tesla = new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian"); + tesla.Inventions = new string[] { "Telephone repeater", "Rotating magnetic field principle", "Polyphase alternating-current system", "Induction motor", "Alternating-current power transmission", "Tesla coil transformer", "Wireless communication", "Radio", "Fluorescent lights" }; + tesla.PlaceOfBirth.City = "Smiljan"; - #region SetUp and TearDown - - /// - /// The setup logic executed before the execution of each individual test. - /// - [SetUp] - public void SetUp() - { - ContextRegistry.Clear(); - tesla = new Inventor( "Nikola Tesla", new DateTime( 1856, 7, 9 ), "Serbian" ); - tesla.Inventions = new string[] - { - "Telephone repeater", "Rotating magnetic field principle", - "Polyphase alternating-current system", "Induction motor", - "Alternating-current power transmission", "Tesla coil transformer", - "Wireless communication", "Radio", "Fluorescent lights" - }; - tesla.PlaceOfBirth.City = "Smiljan"; - - pupin = new Inventor( "Mihajlo Pupin", new DateTime( 1854, 10, 9 ), "Serbian" ); - pupin.Inventions = new string[] { "Long distance telephony & telegraphy", "Secondary X-Ray radiation", "Sonar" }; - pupin.PlaceOfBirth.City = "Idvor"; - pupin.PlaceOfBirth.Country = "Serbia"; - - ieee = new Society(); - ieee.Members.Add( tesla ); - ieee.Members.Add( pupin ); - ieee.Officers["president"] = pupin; - ieee.Officers["advisors"] = new Inventor[] { tesla, pupin }; // not historically accurate, but I need an array in the map ;-) - } - - [OneTimeTearDown] - public void TearDown() - { - //DynamicReflectionManager.SaveAssembly(); - } - - #endregion - - protected virtual IDynamicField Create( FieldInfo field ) - { - return DynamicField.Create( field ); - } - - [Test] - public void TestInstanceFields() - { - IDynamicField name = Create( typeof( Inventor ).GetField( "Name" ) ); - Assert.AreEqual( tesla.Name, name.GetValue( tesla ) ); - name.SetValue( tesla, "Tesla, Nikola" ); - Assert.AreEqual( "Tesla, Nikola", tesla.Name ); - Assert.AreEqual( "Tesla, Nikola", name.GetValue( tesla ) ); - - MyStruct myYearHolder = new MyStruct(); - myYearHolder.Year = 2004; - IDynamicField year = Create( typeof( MyStruct ).GetField( "year", BINDANY ) ); - Assert.AreEqual( 2004, year.GetValue( myYearHolder ) ); - } - - [Test] - public void TestAttemptingToSetFieldOfValueTypeInstance() - { - MyStruct myYearHolder = new MyStruct(); - IDynamicField year = Create( typeof( MyStruct ).GetField( "year" ) ); - Assert.Throws(() => year.SetValue( myYearHolder, 2004 )); - } - - [Test] - public void TestStaticFieldsOfClass() - { - IDynamicField myField = Create( typeof( MyStaticClass ).GetField( "myField" ) ); - myField.SetValue( null, "here we go..." ); - - IDynamicField myConst = Create( typeof( MyStaticClass ).GetField( "MyConst" ) ); - Assert.AreEqual( 3456, myConst.GetValue( null ) ); - try - { - myConst.SetValue( null, 7890 ); - } - catch (InvalidOperationException) { } - - IDynamicField myReadonlyField = Create( typeof( MyStaticClass ).GetField( "myReadonlyField" ) ); - string s2 = (string) myReadonlyField.GetValue(null); - string s1 = MyStaticClass.myReadonlyField; - Assert.AreEqual(s1, s2); - } - - [Test] - public void CanReadPrivateReadOnlyField() - { - IDynamicField myPrivateReadonlyField2 = null; - FieldInfo fieldInfo = typeof(MyStaticClass).GetField("myPrivateReadonlyField", BindingFlags.Static | BindingFlags.NonPublic); - - myPrivateReadonlyField2 = Create(fieldInfo); - - string u2 = (string)myPrivateReadonlyField2.GetValue(null); - string u1 = "hahaha"; - Assert.AreEqual(u1, u2); - } - -#if !NETCOREAPP - [Test, Ignore("TODO: this works as expected when run using TD.NET & R# (in VS2k8), but fails with nant/NET 2.0 ?!?")] - public void CannotReadPrivateReadOnlyFieldIfNoReflectionPermission() - { - FieldInfo fieldInfo = typeof(MyStaticClass).GetField("myPrivateReadonlyField", BindingFlags.Static | BindingFlags.NonPublic); - try - { - SecurityTemplate.MediumTrustInvoke( delegate - { - IDynamicField myPrivateReadonlyField2 = Create(fieldInfo); - }); - Assert.Fail("private field must not be accessible in medium trust: " + fieldInfo); - } - catch (System.Security.SecurityException sex) - { - Assert.IsTrue( sex.Message.IndexOf("ReflectionPermission") > -1 ); - } - } -#endif - - [Test] - public void CannotSetStaticReadOnlyField() - { - IDynamicField myReadonlyField = Create(typeof(MyStaticClass).GetField("myReadonlyField")); - try - { - myReadonlyField.SetValue(null, "some other string"); - Assert.Fail(); - } - catch (InvalidOperationException) { } - } - - [Test] - public void TestStaticFieldsOfStruct() - { - // static readonly - IDynamicField maxValue = Create( typeof( DateTime ).GetField( "MaxValue" ) ); - Assert.AreEqual( DateTime.MaxValue, maxValue.GetValue( null ) ); - try - { - maxValue.SetValue( null, DateTime.Now ); - } - catch (InvalidOperationException) { } - - // const - IDynamicField int64max = Create( typeof( Int64 ).GetField( "MaxValue", BindingFlags.Public | BindingFlags.Static ) ); - Assert.AreEqual( Int64.MaxValue, int64max.GetValue( null ) ); - try - { - int64max.SetValue( null, 0 ); - } - catch (InvalidOperationException) { } - - // pure static - IDynamicField myField = Create( typeof( MyStaticStruct ).GetField( "staticYear" ) ); - myField.SetValue( null, 2008 ); - Assert.AreEqual( 2008, myField.GetValue( null ) ); - } - - #region Performance tests - - private DateTime start, stop; - - //[Test] - public void PerformanceTests() - { - int n = 10000000; - object x = null; - - // tesla.Name - start = DateTime.Now; - for (int i = 0; i < n; i++) - { - x = tesla.Name; - } - stop = DateTime.Now; - PrintTest( "tesla.Name (direct)", n, Elapsed ); - - start = DateTime.Now; - IDynamicField placeOfBirth = Create( typeof( Inventor ).GetField( "Name" ) ); - for (int i = 0; i < n; i++) - { - x = placeOfBirth.GetValue( tesla ); - } - stop = DateTime.Now; - PrintTest( "tesla.Name (dynamic reflection)", n, Elapsed ); - - start = DateTime.Now; - FieldInfo placeOfBirthFi = typeof( Inventor ).GetField( "Name" ); - for (int i = 0; i < n; i++) - { - x = placeOfBirthFi.GetValue( tesla ); - } - stop = DateTime.Now; - PrintTest( "tesla.Name (standard reflection)", n, Elapsed ); - } - - private double Elapsed - { - get { return (stop.Ticks - start.Ticks) / 10000000f; } - } - - private void PrintTest( string name, int iterations, double duration ) - { - Debug.WriteLine( String.Format( "{0,-60} {1,12:#,###} {2,12:##0.000} {3,12:#,###}", name, iterations, duration, iterations / duration ) ); - } - - #endregion + pupin = new Inventor("Mihajlo Pupin", new DateTime(1854, 10, 9), "Serbian"); + pupin.Inventions = new string[] { "Long distance telephony & telegraphy", "Secondary X-Ray radiation", "Sonar" }; + pupin.PlaceOfBirth.City = "Idvor"; + pupin.PlaceOfBirth.Country = "Serbia"; + ieee = new Society(); + ieee.Members.Add(tesla); + ieee.Members.Add(pupin); + ieee.Officers["president"] = pupin; + ieee.Officers["advisors"] = new Inventor[] { tesla, pupin }; // not historically accurate, but I need an array in the map ;-) } - #region IL generation helper classes (they help if you look at them in Reflector ;-) - - public class ValueTypeField : IDynamicField + [OneTimeTearDown] + public void TearDown() { - public object GetValue( object target ) - { - return ((Inventor)target).Name; - } - - public void SetValue( object target, object value ) - { - ((Inventor)target).Name = (string)value; - } - } - - public class ValueTypeTargetField : IDynamicField - { - public object GetValue( object target ) - { - return ((MyStruct)target).year; - } - - public void SetValue( object target, object value ) - { - MyStruct o = (MyStruct)target; - o.Year = (int)value; - } - } - - public class StaticField : IDynamicField - { - public object GetValue( object target ) - { - return MyStaticClass.myField; - } - - public void SetValue( object target, object value ) - { - MyStaticClass.myField = (string)value; - } - } - - public class StaticConst : IDynamicField - { - public object GetValue( object target ) - { - return MyStaticClass.MyConst; - } - - public void SetValue( object target, object value ) - { - } + //DynamicReflectionManager.SaveAssembly(); } #endregion + protected virtual IDynamicField Create(FieldInfo field) + { + return DynamicField.Create(field); + } + + [Test] + public void TestInstanceFields() + { + IDynamicField name = Create(typeof(Inventor).GetField("Name")); + Assert.AreEqual(tesla.Name, name.GetValue(tesla)); + name.SetValue(tesla, "Tesla, Nikola"); + Assert.AreEqual("Tesla, Nikola", tesla.Name); + Assert.AreEqual("Tesla, Nikola", name.GetValue(tesla)); + + MyStruct myYearHolder = new MyStruct(); + myYearHolder.Year = 2004; + IDynamicField year = Create(typeof(MyStruct).GetField("year", BINDANY)); + Assert.AreEqual(2004, year.GetValue(myYearHolder)); + } + + [Test] + public void TestAttemptingToSetFieldOfValueTypeInstance() + { + MyStruct myYearHolder = new MyStruct(); + IDynamicField year = Create(typeof(MyStruct).GetField("year")); + Assert.Throws(() => year.SetValue(myYearHolder, 2004)); + } + + [Test] + public void TestStaticFieldsOfClass() + { + IDynamicField myField = Create(typeof(MyStaticClass).GetField("myField")); + myField.SetValue(null, "here we go..."); + + IDynamicField myConst = Create(typeof(MyStaticClass).GetField("MyConst")); + Assert.AreEqual(3456, myConst.GetValue(null)); + try + { + myConst.SetValue(null, 7890); + } + catch (InvalidOperationException) { } + + IDynamicField myReadonlyField = Create(typeof(MyStaticClass).GetField("myReadonlyField")); + string s2 = (string) myReadonlyField.GetValue(null); + string s1 = MyStaticClass.myReadonlyField; + Assert.AreEqual(s1, s2); + } + + [Test] + public void CanReadPrivateReadOnlyField() + { + IDynamicField myPrivateReadonlyField2 = null; + FieldInfo fieldInfo = typeof(MyStaticClass).GetField("myPrivateReadonlyField", BindingFlags.Static | BindingFlags.NonPublic); + + myPrivateReadonlyField2 = Create(fieldInfo); + + string u2 = (string) myPrivateReadonlyField2.GetValue(null); + string u1 = "hahaha"; + Assert.AreEqual(u1, u2); + } + +#if !NETCOREAPP + [Test, Ignore("TODO: this works as expected when run using TD.NET & R# (in VS2k8), but fails with nant/NET 2.0 ?!?")] + public void CannotReadPrivateReadOnlyFieldIfNoReflectionPermission() + { + FieldInfo fieldInfo = typeof(MyStaticClass).GetField("myPrivateReadonlyField", BindingFlags.Static | BindingFlags.NonPublic); + try + { + SecurityTemplate.MediumTrustInvoke( delegate + { + IDynamicField myPrivateReadonlyField2 = Create(fieldInfo); + }); + Assert.Fail("private field must not be accessible in medium trust: " + fieldInfo); + } + catch (System.Security.SecurityException sex) + { + Assert.IsTrue( sex.Message.IndexOf("ReflectionPermission") > -1 ); + } + } +#endif + + [Test] + public void CannotSetStaticReadOnlyField() + { + IDynamicField myReadonlyField = Create(typeof(MyStaticClass).GetField("myReadonlyField")); + try + { + myReadonlyField.SetValue(null, "some other string"); + Assert.Fail(); + } + catch (InvalidOperationException) { } + } + + [Test] + public void TestStaticFieldsOfStruct() + { + // static readonly + IDynamicField maxValue = Create(typeof(DateTime).GetField("MaxValue")); + Assert.AreEqual(DateTime.MaxValue, maxValue.GetValue(null)); + try + { + maxValue.SetValue(null, DateTime.Now); + } + catch (InvalidOperationException) { } + + // const + IDynamicField int64max = Create(typeof(Int64).GetField("MaxValue", BindingFlags.Public | BindingFlags.Static)); + Assert.AreEqual(Int64.MaxValue, int64max.GetValue(null)); + try + { + int64max.SetValue(null, 0); + } + catch (InvalidOperationException) { } + + // pure static + IDynamicField myField = Create(typeof(MyStaticStruct).GetField("staticYear")); + myField.SetValue(null, 2008); + Assert.AreEqual(2008, myField.GetValue(null)); + } + + #region Performance tests + + private DateTime start, stop; + + //[Test] + public void PerformanceTests() + { + int n = 10000000; + object x = null; + + // tesla.Name + start = DateTime.Now; + for (int i = 0; i < n; i++) + { + x = tesla.Name; + } + + stop = DateTime.Now; + PrintTest("tesla.Name (direct)", n, Elapsed); + + start = DateTime.Now; + IDynamicField placeOfBirth = Create(typeof(Inventor).GetField("Name")); + for (int i = 0; i < n; i++) + { + x = placeOfBirth.GetValue(tesla); + } + + stop = DateTime.Now; + PrintTest("tesla.Name (dynamic reflection)", n, Elapsed); + + start = DateTime.Now; + FieldInfo placeOfBirthFi = typeof(Inventor).GetField("Name"); + for (int i = 0; i < n; i++) + { + x = placeOfBirthFi.GetValue(tesla); + } + + stop = DateTime.Now; + PrintTest("tesla.Name (standard reflection)", n, Elapsed); + } + + private double Elapsed + { + get { return (stop.Ticks - start.Ticks) / 10000000f; } + } + + private void PrintTest(string name, int iterations, double duration) + { + Debug.WriteLine(String.Format("{0,-60} {1,12:#,###} {2,12:##0.000} {3,12:#,###}", name, iterations, duration, iterations / duration)); + } + + #endregion } + +#region IL generation helper classes (they help if you look at them in Reflector ;-) + +public class ValueTypeField : IDynamicField +{ + public object GetValue(object target) + { + return ((Inventor) target).Name; + } + + public void SetValue(object target, object value) + { + ((Inventor) target).Name = (string) value; + } +} + +public class ValueTypeTargetField : IDynamicField +{ + public object GetValue(object target) + { + return ((MyStruct) target).year; + } + + public void SetValue(object target, object value) + { + MyStruct o = (MyStruct) target; + o.Year = (int) value; + } +} + +public class StaticField : IDynamicField +{ + public object GetValue(object target) + { + return MyStaticClass.myField; + } + + public void SetValue(object target, object value) + { + MyStaticClass.myField = (string) value; + } +} + +public class StaticConst : IDynamicField +{ + public object GetValue(object target) + { + return MyStaticClass.MyConst; + } + + public void SetValue(object target, object value) + { + } +} + +#endregion diff --git a/test/Spring/Spring.Core.Tests/Reflection/Dynamic/DynamicMethodTests.cs b/test/Spring/Spring.Core.Tests/Reflection/Dynamic/DynamicMethodTests.cs index 8db20bb8..1483b878 100644 --- a/test/Spring/Spring.Core.Tests/Reflection/Dynamic/DynamicMethodTests.cs +++ b/test/Spring/Spring.Core.Tests/Reflection/Dynamic/DynamicMethodTests.cs @@ -25,426 +25,427 @@ using NUnit.Framework; using Spring.Context.Support; using Spring.Util; -namespace Spring.Reflection.Dynamic +namespace Spring.Reflection.Dynamic; + +/// +/// Unit tests for the DynamicMethod class. +/// +/// Aleksandar Seovic +[TestFixture] +public sealed class DynamicMethodTests { + private Inventor tesla; + private Inventor pupin; + private Society ieee; + + #region SetUp and TearDown + /// - /// Unit tests for the DynamicMethod class. + /// The setup logic executed before the execution of each individual test. /// - /// Aleksandar Seovic - [TestFixture] - public sealed class DynamicMethodTests + [SetUp] + public void SetUp() { - private Inventor tesla; - private Inventor pupin; - private Society ieee; + ContextRegistry.Clear(); + tesla = new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian"); + tesla.Inventions = new string[] { "Telephone repeater", "Rotating magnetic field principle", "Polyphase alternating-current system", "Induction motor", "Alternating-current power transmission", "Tesla coil transformer", "Wireless communication", "Radio", "Fluorescent lights" }; + tesla.PlaceOfBirth.City = "Smiljan"; - #region SetUp and TearDown + pupin = new Inventor("Mihajlo Pupin", new DateTime(1854, 10, 9), "Serbian"); + pupin.Inventions = new string[] { "Long distance telephony & telegraphy", "Secondary X-Ray radiation", "Sonar" }; + pupin.PlaceOfBirth.City = "Idvor"; + pupin.PlaceOfBirth.Country = "Serbia"; - /// - /// The setup logic executed before the execution of each individual test. - /// - [SetUp] - public void SetUp() - { - ContextRegistry.Clear(); - tesla = new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian"); - tesla.Inventions = new string[] - { - "Telephone repeater", "Rotating magnetic field principle", - "Polyphase alternating-current system", "Induction motor", - "Alternating-current power transmission", "Tesla coil transformer", - "Wireless communication", "Radio", "Fluorescent lights" - }; - tesla.PlaceOfBirth.City = "Smiljan"; - - pupin = new Inventor("Mihajlo Pupin", new DateTime(1854, 10, 9), "Serbian"); - pupin.Inventions = new string[] { "Long distance telephony & telegraphy", "Secondary X-Ray radiation", "Sonar" }; - pupin.PlaceOfBirth.City = "Idvor"; - pupin.PlaceOfBirth.Country = "Serbia"; - - ieee = new Society(); - ieee.Members.Add(tesla); - ieee.Members.Add(pupin); - ieee.Officers["president"] = pupin; - ieee.Officers["advisors"] = new Inventor[] { tesla, pupin }; // not historically accurate, but I need an array in the map ;-) - } - - [OneTimeTearDown] - public void TearDown() - { - //DynamicReflectionManager.SaveAssembly(); - } - - #endregion - - private string RespectsPermissionsPrivateMethod() - { - return "Result"; - } - - public void RespectsPermissionsPublicMethod() { } - -#if !NETCOREAPP - [Test] - public void CanCreateWithRestrictedPermissions() - { - SecurityTemplate.MediumTrustInvoke(new System.Threading.ThreadStart(CanCreateWithRestrictedPermissionsImpl)); - } - - private void CanCreateWithRestrictedPermissionsImpl() - { - MethodInfo method = this.GetType().GetMethod("RespectsPermissionsPublicMethod"); - IDynamicMethod m = DynamicMethod.Create(method); - m.Invoke(this, null); - } - - [Test] - public void CanCreatePrivateMethodButThrowsOnInvoke() - { - SecurityTemplate.MediumTrustInvoke(new System.Threading.ThreadStart(CanCreatePrivateMethodButThrowsOnInvokeImpl)); - } - - private void CanCreatePrivateMethodButThrowsOnInvokeImpl() - { - MethodInfo privateMethod = this.GetType().GetMethod("RespectsPermissionsPrivateMethod", BindingFlags.NonPublic | BindingFlags.Instance); - IDynamicMethod m = DynamicMethod.Create(privateMethod); - - try - { - object result = m.Invoke(this, null); - if (SystemUtils.MonoRuntime) - { - Assert.AreEqual("Result", result); - } - else - { - Assert.Fail("shoud throw a security exception"); - } - - } - catch (MethodAccessException) - { } - } -#endif - - [Test] - public void TestInstanceMethods() - { - IDynamicMethod getAge = DynamicMethod.Create(typeof(Inventor).GetMethod("GetAge")); - Assert.AreEqual(tesla.GetAge(DateTime.Today), getAge.Invoke(tesla, new object[] { DateTime.Today })); - - MethodTarget target = new MethodTarget(); - IDynamicMethod test = DynamicMethod.Create(typeof(MethodTarget).GetMethod("MethodReturningString")); - Assert.AreEqual(tesla.Name, test.Invoke(target, new object[] { 5, DateTime.Today, new String[] { "xyz", "abc" }, tesla })); - - ArrayList list = new ArrayList(new string[] { "one", "two", "three" }); - IDynamicMethod removeAt = DynamicMethod.Create(typeof(ArrayList).GetMethod("RemoveAt")); - removeAt.Invoke(list, new object[] { 1 }); - Assert.AreEqual(2, list.Count); - Assert.AreEqual("three", list[1]); - } - - [Test] - public void TestStaticMethods() - { - IDynamicMethod isNullOrEmpty = DynamicMethod.Create(typeof(StringUtils).GetMethod("IsNullOrEmpty")); - Assert.IsTrue((bool)isNullOrEmpty.Invoke(null, new object[] { null })); - Assert.IsTrue((bool)isNullOrEmpty.Invoke(null, new object[] { String.Empty })); - Assert.IsFalse((bool)isNullOrEmpty.Invoke(null, new object[] { "Ana Maria" })); - } - - internal class TheClassAsArgument { } - - internal class TheClassDerivedFromTheArgumentClass : TheClassAsArgument { } - - internal class TheClassWithMethod - { - public bool TheMethod(TheClassAsArgument arg) - { - return true; - } - } - - [Test] - public void CanAcceptImplicitlyConvertedTypesAsSubstitutesForArguments() - { - IDynamicMethod method = DynamicMethod.Create(typeof(TheClassWithMethod).GetMethod("TheMethod")); - - bool ret = (bool)(method.Invoke(new TheClassWithMethod(), new object[] { new TheClassDerivedFromTheArgumentClass() })); - - Assert.IsTrue(ret); - } - - - [Test] - public void PassNullableArguments() - { - IDynamicMethod dm = DynamicMethod.Create(typeof(TestMethods).GetMethod("PassNullableArgumentStatic")); - DateTime dt = DateTime.Now; - - Assert.AreEqual(dt, dm.Invoke(null, dt)); - } - - [Test] - public void PassInvalidNumberOfArguments() - { - IDynamicMethod dm = DynamicMethod.Create(typeof(TestMethods).GetMethod("PassReferenceArgumentStatic")); - DateTime dt = DateTime.Now; - - Assert.IsNull(dm.Invoke(null, null)); // this is ok - try - { - dm.Invoke(null); // this is not ok - Assert.Fail(); - } - catch (ArgumentException) { } - try - { - dm.Invoke(null, null, null); // this is not ok - Assert.Fail(); - } - catch (ArgumentException) { } - } - - [Test] - public void TestArgumentTypeCasts() - { - IDynamicMethod sqrt = DynamicMethod.Create(typeof(Math).GetMethod("Sqrt")); - object result = sqrt.Invoke(null, new object[] { 4 }); - Assert.AreEqual(Math.Sqrt(4), result); - - try - { - sqrt.Invoke(null, new object[] { null }); - Assert.Fail(); - } - catch (InvalidCastException) - { - } - - try - { - sqrt.Invoke(null, new object[] { "4" }); - Assert.Fail(); - } - catch (InvalidCastException) - { } - } - - private void CodeForReflection() - { - object val = 4; - Type argType = typeof(double); - Math.Sqrt((double)Convert.ChangeType(val, argType)); - } - - [Test] - public void TestRefOutMethods() - { - IDynamicMethod refMethod = DynamicMethod.Create(typeof(MethodTarget).GetMethod("MethodWithRefParameter")); - - MethodTarget target = new MethodTarget(); - object[] args = new object[] { "aleks", 5 }; - refMethod.Invoke(target, args); - Assert.AreEqual("ALEKS", args[0]); - Assert.AreEqual(25, args[1]); - - IDynamicMethod outMethod = DynamicMethod.Create(typeof(MethodTarget).GetMethod("MethodWithOutParameter")); - args = new object[] { "aleks", null }; - outMethod.Invoke(target, args); - Assert.AreEqual("ALEKS", args[1]); - - IDynamicMethod refOutMethod = DynamicMethod.Create(typeof(RefOutTestObject).GetMethod("DoIt")); - RefOutTestObject refOutTarget = new RefOutTestObject(); - - args = new object[] { 0, 1, null }; - refOutMethod.Invoke(refOutTarget, args); - Assert.AreEqual(2, args[1]); - Assert.AreEqual("done", args[2]); - refOutMethod.Invoke(refOutTarget, args); - Assert.AreEqual(3, args[1]); - Assert.AreEqual("done", args[2]); - - int count = 0; - string done; - target.DoItCaller(0, ref count, out done); - Assert.AreEqual(1, count); - Assert.AreEqual("done", done); - } - - #region Performance tests - - private DateTime start, stop; - - //[Test] - public void PerformanceTests() - { - int n = 10000000; - object x = null; - - // tesla.GetAge - start = DateTime.Now; - for (int i = 0; i < n; i++) - { - x = tesla.GetAge(DateTime.Today); - } - stop = DateTime.Now; - PrintTest("tesla.GetAge (direct)", n, Elapsed); - - start = DateTime.Now; - IDynamicMethod getAge = DynamicMethod.Create(typeof(Inventor).GetMethod("GetAge")); - for (int i = 0; i < n; i++) - { - object[] args = new object[] { DateTime.Today }; - x = getAge.Invoke(tesla, args); - } - stop = DateTime.Now; - PrintTest("tesla.GetAge (dynamic reflection)", n, Elapsed); - - start = DateTime.Now; - MethodInfo getAgeMi = typeof(Inventor).GetMethod("GetAge"); - for (int i = 0; i < n; i++) - { - object[] args = new object[] { DateTime.Today }; - x = getAgeMi.Invoke(tesla, args); - } - stop = DateTime.Now; - PrintTest("tesla.GetAge (standard reflection)", n, Elapsed); - } - - private double Elapsed - { - get { return (stop.Ticks - start.Ticks) / 10000000f; } - } - - private void PrintTest(string name, int iterations, double duration) - { - Debug.WriteLine(String.Format("{0,-60} {1,12:#,###} {2,12:##0.000} {3,12:#,###}", name, iterations, duration, iterations / duration)); - } - - #endregion - - #region Helper Classes - - public class TestMethods - { - public static object PassReferenceArgumentStatic(object arg) - { - return arg; - } - - public static object Invoke(object target, object[] args) - { - return PassNullableArgumentStatic((DateTime?)(args[0])); - } - - public DateTime? PassNullableArgument(DateTime? arg) - { - return PassNullableArgumentStatic(arg); - } - - public static DateTime? PassNullableArgumentStatic(DateTime? arg) - { - return arg; - } - } - #endregion + ieee = new Society(); + ieee.Members.Add(tesla); + ieee.Members.Add(pupin); + ieee.Officers["president"] = pupin; + ieee.Officers["advisors"] = new Inventor[] { tesla, pupin }; // not historically accurate, but I need an array in the map ;-) } - #region IL generation helper classes (they help if you look at them in Reflector ;-) - - public class InstanceMethod : IDynamicMethod + [OneTimeTearDown] + public void TearDown() { - public object Invoke(object target, object[] args) - { - return ((MethodTarget)target).MethodReturningString( - (int)args[0], (DateTime)args[1], (string[])args[2], (Inventor)args[3]); - } - - public object InvokeVoid(object target, object[] args) - { - ((MethodTarget)target).RemoveAt(5); - return null; - } - - public object InvokeWithOut(object target, object[] args) - { - string outVar = null; - ((MethodTarget)target).MethodWithOutParameter((string)args[0], out outVar); - args[1] = outVar; - return null; - } - - public object InvokeWithRef(object target, object[] args) - { - string refVar1 = (string)args[0]; - int refVar2 = (int)args[0]; - ((MethodTarget)target).MethodWithRefParameter(ref refVar1, ref refVar2); - args[0] = refVar1; - args[1] = refVar2; - return null; - } - - public object InvokeDoIt(object target, object[] args) - { - int reference = (int)args[1]; - string output; - ((RefOutTestObject)target).DoIt((int)args[0], ref reference, out output); - args[1] = reference; - args[2] = output; - return null; - } - } - - public class MethodTarget - { - public string MethodReturningString(int arg1, DateTime arg2, string[] arg3, Inventor arg4) - { - return arg4.Name; - } - - public void RemoveAt(int index) - { } - - public void MethodWithOutParameter(string lower, out string upper) - { - upper = lower.ToUpper(); - } - - public void MethodWithRefParameter(ref string lowerUpper, ref int square) - { - lowerUpper = lowerUpper.ToUpper(); - square = square * square; - } - - public void DoItCaller(int count, ref int reference, out string output) - { - InstanceMethod caller = new InstanceMethod(); - - RefOutTestObject target = new RefOutTestObject(); - object[] args = new object[] { count, reference, null }; - caller.InvokeDoIt(target, args); - - reference = (int)args[1]; - output = (string)args[2]; - } - } - - public interface IRefOutTestObject - { - void DoIt(int count, ref int reference, out string output); - } - - public class RefOutTestObject : IRefOutTestObject - { - public void DoIt(int count, ref int reference, out string output) - { - output = "done"; - reference++; - } + //DynamicReflectionManager.SaveAssembly(); } #endregion + private string RespectsPermissionsPrivateMethod() + { + return "Result"; + } + public void RespectsPermissionsPublicMethod() { } + +#if !NETCOREAPP + [Test] + public void CanCreateWithRestrictedPermissions() + { + SecurityTemplate.MediumTrustInvoke(new System.Threading.ThreadStart(CanCreateWithRestrictedPermissionsImpl)); + } + + private void CanCreateWithRestrictedPermissionsImpl() + { + MethodInfo method = this.GetType().GetMethod("RespectsPermissionsPublicMethod"); + IDynamicMethod m = DynamicMethod.Create(method); + m.Invoke(this, null); + } + + [Test] + public void CanCreatePrivateMethodButThrowsOnInvoke() + { + SecurityTemplate.MediumTrustInvoke(new System.Threading.ThreadStart(CanCreatePrivateMethodButThrowsOnInvokeImpl)); + } + + private void CanCreatePrivateMethodButThrowsOnInvokeImpl() + { + MethodInfo privateMethod = this.GetType().GetMethod("RespectsPermissionsPrivateMethod", BindingFlags.NonPublic | BindingFlags.Instance); + IDynamicMethod m = DynamicMethod.Create(privateMethod); + + try + { + object result = m.Invoke(this, null); + if (SystemUtils.MonoRuntime) + { + Assert.AreEqual("Result", result); + } + else + { + Assert.Fail("shoud throw a security exception"); + } + + } + catch (MethodAccessException) + { } + } +#endif + + [Test] + public void TestInstanceMethods() + { + IDynamicMethod getAge = DynamicMethod.Create(typeof(Inventor).GetMethod("GetAge")); + Assert.AreEqual(tesla.GetAge(DateTime.Today), getAge.Invoke(tesla, new object[] { DateTime.Today })); + + MethodTarget target = new MethodTarget(); + IDynamicMethod test = DynamicMethod.Create(typeof(MethodTarget).GetMethod("MethodReturningString")); + Assert.AreEqual(tesla.Name, test.Invoke(target, new object[] { 5, DateTime.Today, new String[] { "xyz", "abc" }, tesla })); + + ArrayList list = new ArrayList(new string[] { "one", "two", "three" }); + IDynamicMethod removeAt = DynamicMethod.Create(typeof(ArrayList).GetMethod("RemoveAt")); + removeAt.Invoke(list, new object[] { 1 }); + Assert.AreEqual(2, list.Count); + Assert.AreEqual("three", list[1]); + } + + [Test] + public void TestStaticMethods() + { + IDynamicMethod isNullOrEmpty = DynamicMethod.Create(typeof(StringUtils).GetMethod("IsNullOrEmpty")); + Assert.IsTrue((bool) isNullOrEmpty.Invoke(null, new object[] { null })); + Assert.IsTrue((bool) isNullOrEmpty.Invoke(null, new object[] { String.Empty })); + Assert.IsFalse((bool) isNullOrEmpty.Invoke(null, new object[] { "Ana Maria" })); + } + + internal class TheClassAsArgument + { + } + + internal class TheClassDerivedFromTheArgumentClass : TheClassAsArgument + { + } + + internal class TheClassWithMethod + { + public bool TheMethod(TheClassAsArgument arg) + { + return true; + } + } + + [Test] + public void CanAcceptImplicitlyConvertedTypesAsSubstitutesForArguments() + { + IDynamicMethod method = DynamicMethod.Create(typeof(TheClassWithMethod).GetMethod("TheMethod")); + + bool ret = (bool) (method.Invoke(new TheClassWithMethod(), new object[] { new TheClassDerivedFromTheArgumentClass() })); + + Assert.IsTrue(ret); + } + + [Test] + public void PassNullableArguments() + { + IDynamicMethod dm = DynamicMethod.Create(typeof(TestMethods).GetMethod("PassNullableArgumentStatic")); + DateTime dt = DateTime.Now; + + Assert.AreEqual(dt, dm.Invoke(null, dt)); + } + + [Test] + public void PassInvalidNumberOfArguments() + { + IDynamicMethod dm = DynamicMethod.Create(typeof(TestMethods).GetMethod("PassReferenceArgumentStatic")); + DateTime dt = DateTime.Now; + + Assert.IsNull(dm.Invoke(null, null)); // this is ok + try + { + dm.Invoke(null); // this is not ok + Assert.Fail(); + } + catch (ArgumentException) { } + + try + { + dm.Invoke(null, null, null); // this is not ok + Assert.Fail(); + } + catch (ArgumentException) { } + } + + [Test] + public void TestArgumentTypeCasts() + { + IDynamicMethod sqrt = DynamicMethod.Create(typeof(Math).GetMethod("Sqrt")); + object result = sqrt.Invoke(null, new object[] { 4 }); + Assert.AreEqual(Math.Sqrt(4), result); + + try + { + sqrt.Invoke(null, new object[] { null }); + Assert.Fail(); + } + catch (InvalidCastException) + { + } + + try + { + sqrt.Invoke(null, new object[] { "4" }); + Assert.Fail(); + } + catch (InvalidCastException) + { + } + } + + private void CodeForReflection() + { + object val = 4; + Type argType = typeof(double); + Math.Sqrt((double) Convert.ChangeType(val, argType)); + } + + [Test] + public void TestRefOutMethods() + { + IDynamicMethod refMethod = DynamicMethod.Create(typeof(MethodTarget).GetMethod("MethodWithRefParameter")); + + MethodTarget target = new MethodTarget(); + object[] args = new object[] { "aleks", 5 }; + refMethod.Invoke(target, args); + Assert.AreEqual("ALEKS", args[0]); + Assert.AreEqual(25, args[1]); + + IDynamicMethod outMethod = DynamicMethod.Create(typeof(MethodTarget).GetMethod("MethodWithOutParameter")); + args = new object[] { "aleks", null }; + outMethod.Invoke(target, args); + Assert.AreEqual("ALEKS", args[1]); + + IDynamicMethod refOutMethod = DynamicMethod.Create(typeof(RefOutTestObject).GetMethod("DoIt")); + RefOutTestObject refOutTarget = new RefOutTestObject(); + + args = new object[] { 0, 1, null }; + refOutMethod.Invoke(refOutTarget, args); + Assert.AreEqual(2, args[1]); + Assert.AreEqual("done", args[2]); + refOutMethod.Invoke(refOutTarget, args); + Assert.AreEqual(3, args[1]); + Assert.AreEqual("done", args[2]); + + int count = 0; + string done; + target.DoItCaller(0, ref count, out done); + Assert.AreEqual(1, count); + Assert.AreEqual("done", done); + } + + #region Performance tests + + private DateTime start, stop; + + //[Test] + public void PerformanceTests() + { + int n = 10000000; + object x = null; + + // tesla.GetAge + start = DateTime.Now; + for (int i = 0; i < n; i++) + { + x = tesla.GetAge(DateTime.Today); + } + + stop = DateTime.Now; + PrintTest("tesla.GetAge (direct)", n, Elapsed); + + start = DateTime.Now; + IDynamicMethod getAge = DynamicMethod.Create(typeof(Inventor).GetMethod("GetAge")); + for (int i = 0; i < n; i++) + { + object[] args = new object[] { DateTime.Today }; + x = getAge.Invoke(tesla, args); + } + + stop = DateTime.Now; + PrintTest("tesla.GetAge (dynamic reflection)", n, Elapsed); + + start = DateTime.Now; + MethodInfo getAgeMi = typeof(Inventor).GetMethod("GetAge"); + for (int i = 0; i < n; i++) + { + object[] args = new object[] { DateTime.Today }; + x = getAgeMi.Invoke(tesla, args); + } + + stop = DateTime.Now; + PrintTest("tesla.GetAge (standard reflection)", n, Elapsed); + } + + private double Elapsed + { + get { return (stop.Ticks - start.Ticks) / 10000000f; } + } + + private void PrintTest(string name, int iterations, double duration) + { + Debug.WriteLine(String.Format("{0,-60} {1,12:#,###} {2,12:##0.000} {3,12:#,###}", name, iterations, duration, iterations / duration)); + } + + #endregion + + #region Helper Classes + + public class TestMethods + { + public static object PassReferenceArgumentStatic(object arg) + { + return arg; + } + + public static object Invoke(object target, object[] args) + { + return PassNullableArgumentStatic((DateTime?) (args[0])); + } + + public DateTime? PassNullableArgument(DateTime? arg) + { + return PassNullableArgumentStatic(arg); + } + + public static DateTime? PassNullableArgumentStatic(DateTime? arg) + { + return arg; + } + } + + #endregion } + +#region IL generation helper classes (they help if you look at them in Reflector ;-) + +public class InstanceMethod : IDynamicMethod +{ + public object Invoke(object target, object[] args) + { + return ((MethodTarget) target).MethodReturningString( + (int) args[0], (DateTime) args[1], (string[]) args[2], (Inventor) args[3]); + } + + public object InvokeVoid(object target, object[] args) + { + ((MethodTarget) target).RemoveAt(5); + return null; + } + + public object InvokeWithOut(object target, object[] args) + { + string outVar = null; + ((MethodTarget) target).MethodWithOutParameter((string) args[0], out outVar); + args[1] = outVar; + return null; + } + + public object InvokeWithRef(object target, object[] args) + { + string refVar1 = (string) args[0]; + int refVar2 = (int) args[0]; + ((MethodTarget) target).MethodWithRefParameter(ref refVar1, ref refVar2); + args[0] = refVar1; + args[1] = refVar2; + return null; + } + + public object InvokeDoIt(object target, object[] args) + { + int reference = (int) args[1]; + string output; + ((RefOutTestObject) target).DoIt((int) args[0], ref reference, out output); + args[1] = reference; + args[2] = output; + return null; + } +} + +public class MethodTarget +{ + public string MethodReturningString(int arg1, DateTime arg2, string[] arg3, Inventor arg4) + { + return arg4.Name; + } + + public void RemoveAt(int index) + { + } + + public void MethodWithOutParameter(string lower, out string upper) + { + upper = lower.ToUpper(); + } + + public void MethodWithRefParameter(ref string lowerUpper, ref int square) + { + lowerUpper = lowerUpper.ToUpper(); + square = square * square; + } + + public void DoItCaller(int count, ref int reference, out string output) + { + InstanceMethod caller = new InstanceMethod(); + + RefOutTestObject target = new RefOutTestObject(); + object[] args = new object[] { count, reference, null }; + caller.InvokeDoIt(target, args); + + reference = (int) args[1]; + output = (string) args[2]; + } +} + +public interface IRefOutTestObject +{ + void DoIt(int count, ref int reference, out string output); +} + +public class RefOutTestObject : IRefOutTestObject +{ + public void DoIt(int count, ref int reference, out string output) + { + output = "done"; + reference++; + } +} + +#endregion \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/Reflection/Dynamic/DynamicPropertyTests.cs b/test/Spring/Spring.Core.Tests/Reflection/Dynamic/DynamicPropertyTests.cs index 1872c0b8..50eec2e4 100644 --- a/test/Spring/Spring.Core.Tests/Reflection/Dynamic/DynamicPropertyTests.cs +++ b/test/Spring/Spring.Core.Tests/Reflection/Dynamic/DynamicPropertyTests.cs @@ -21,94 +21,94 @@ #region Imports using System.Reflection; - using NUnit.Framework; #endregion -namespace Spring.Reflection.Dynamic +namespace Spring.Reflection.Dynamic; + +/// +/// Unit tests for the DynamicProperty class. +/// +/// Aleksandar Seovic +[TestFixture] +public class DynamicPropertyTests : BasePropertyTests { - /// - /// Unit tests for the DynamicProperty class. - /// - /// Aleksandar Seovic - [TestFixture] - public class DynamicPropertyTests : BasePropertyTests + private const BindingFlags BINDANY = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static; + + protected override IDynamicProperty Create(PropertyInfo property) { - private const BindingFlags BINDANY = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static; + return DynamicProperty.Create(property); + } - protected override IDynamicProperty Create(PropertyInfo property) + [Test] + public void TestNonReadableProperties() + { + IDynamicProperty nonReadableProperty = Create(typeof(ClassWithNonReadableProperty).GetProperty("MyProperty")); + Assert.Throws(() => nonReadableProperty.GetValue(null)); + } + + [Test] + public void TestNonWritableInstanceProperty() + { + IDynamicProperty nonWritableProperty = Create(typeof(Inventor).GetProperty("PlaceOfBirth")); + Assert.Throws(() => nonWritableProperty.SetValue(null, null)); + } + + [Test] + public void TestAttemptingToSetPropertyOfValueTypeInstance() + { + MyStruct myYearHolder = new MyStruct(); + IDynamicProperty year = Create(typeof(MyStruct).GetProperty("Year")); + Assert.Throws(() => year.SetValue(myYearHolder, 2004)); + } + + [Test] + public void TestNonWritableStaticProperty() + { + IDynamicProperty nonWritableProperty = Create(typeof(DateTime).GetProperty("Today")); + Assert.Throws(() => nonWritableProperty.SetValue(null, null)); + } + + [Test] + public void TestSetIncompatibleType() + { + IDynamicProperty inventorPlace = Create(typeof(Inventor).GetProperty("POB")); + try + { + inventorPlace.SetValue(new Inventor(), new object()); + Assert.Fail(); + } + catch (InvalidCastException) { - return DynamicProperty.Create(property); } - [Test] - public void TestNonReadableProperties() + try + { + inventorPlace.SetValue(new Inventor(), new DateTime()); + Assert.Fail(); + } + catch (InvalidCastException) { - IDynamicProperty nonReadableProperty = Create(typeof(ClassWithNonReadableProperty).GetProperty("MyProperty")); - Assert.Throws(() => nonReadableProperty.GetValue(null)); } - [Test] - public void TestNonWritableInstanceProperty() + IDynamicProperty inventorDOB = Create(typeof(Inventor).GetProperty("DOB")); + try + { + inventorDOB.SetValue(new Inventor(), 2); + Assert.Fail(); + } + catch (InvalidCastException) { - IDynamicProperty nonWritableProperty = Create(typeof(Inventor).GetProperty("PlaceOfBirth")); - Assert.Throws(() => nonWritableProperty.SetValue(null, null)); } - [Test] - public void TestAttemptingToSetPropertyOfValueTypeInstance() + try { - MyStruct myYearHolder = new MyStruct(); - IDynamicProperty year = Create(typeof(MyStruct).GetProperty("Year")); - Assert.Throws(() => year.SetValue(myYearHolder, 2004)); + inventorDOB.SetValue(new Inventor(), new Place()); + Assert.Fail(); } - - [Test] - public void TestNonWritableStaticProperty() + catch (InvalidCastException) { - IDynamicProperty nonWritableProperty = Create(typeof(DateTime).GetProperty("Today")); - Assert.Throws(() => nonWritableProperty.SetValue(null, null)); - } - - [Test] - public void TestSetIncompatibleType() - { - IDynamicProperty inventorPlace = Create(typeof(Inventor).GetProperty("POB")); - try - { - inventorPlace.SetValue(new Inventor(), new object()); - Assert.Fail(); - } - catch (InvalidCastException) - { - } - try - { - inventorPlace.SetValue(new Inventor(), new DateTime()); - Assert.Fail(); - } - catch (InvalidCastException) - { - } - - IDynamicProperty inventorDOB = Create(typeof(Inventor).GetProperty("DOB")); - try - { - inventorDOB.SetValue(new Inventor(), 2); - Assert.Fail(); - } - catch (InvalidCastException) - { - } - try - { - inventorDOB.SetValue(new Inventor(), new Place()); - Assert.Fail(); - } - catch (InvalidCastException) - { - } } } -} \ No newline at end of file +} diff --git a/test/Spring/Spring.Core.Tests/Reflection/Dynamic/SafeFieldTests.cs b/test/Spring/Spring.Core.Tests/Reflection/Dynamic/SafeFieldTests.cs index 24a9a671..ec33d1a9 100644 --- a/test/Spring/Spring.Core.Tests/Reflection/Dynamic/SafeFieldTests.cs +++ b/test/Spring/Spring.Core.Tests/Reflection/Dynamic/SafeFieldTests.cs @@ -25,296 +25,312 @@ using NUnit.Framework; #endregion -namespace Spring.Reflection.Dynamic +namespace Spring.Reflection.Dynamic; + +/// +/// Unit tests for the SafeField class. SafeField must pass the same tests +/// as DynamicField plus tests for accessing private members. +/// +/// Erich Eichinger +[TestFixture] +public class SafeFieldTests : DynamicFieldTests { - /// - /// Unit tests for the SafeField class. SafeField must pass the same tests - /// as DynamicField plus tests for accessing private members. - /// - /// Erich Eichinger - [TestFixture] - public class SafeFieldTests : DynamicFieldTests + protected override IDynamicField Create(FieldInfo field) { - protected override IDynamicField Create(FieldInfo field) + return new SafeField(field); + } + + private static FieldInfo IField(Type type, string fieldName) + { + return type.GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); + } + + private static FieldInfo SField(Type t, string fieldName) + { + return t.GetField(fieldName, BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public); + } + + [Test] + public void ThrowsOnNullField() + { + Assert.Throws(() => new SafeField(null)); + } + + [Test] + public void TestStaticMembersOfStruct() + { + TestStaticMembersOf(typeof(MyStructWithPrivateFields), MyStructWithPrivateFields.GetStaticReadonlyRefValue()); + } + + [Test] + public void TestStaticMembersOfClass() + { + TestStaticMembersOf(typeof(MyClassWithPrivateFields), MyClassWithPrivateFields.GetStaticReadonlyRefValue()); + } + + [Test] + public void TestSetIncompatibleType() + { + IDynamicField inventorPlace = Create(typeof(Inventor).GetField("pob", BINDANY)); + try { - return new SafeField(field); + inventorPlace.SetValue(new Inventor(), new object()); + Assert.Fail(); } + catch (InvalidCastException) { } - private static FieldInfo IField(Type type, string fieldName) + try { - return type.GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); + inventorPlace.SetValue(new Inventor(), new DateTime()); + Assert.Fail(); } + catch (InvalidCastException) { } - private static FieldInfo SField(Type t, string fieldName) + IDynamicField inventorDOB = Create(typeof(Inventor).GetField("dob", BINDANY)); + try { - return t.GetField(fieldName, BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public); + inventorDOB.SetValue(new Inventor(), 2); + Assert.Fail(); } + catch (InvalidCastException) { } - [Test] - public void ThrowsOnNullField() + try { - Assert.Throws(() => new SafeField(null)); + inventorDOB.SetValue(new Inventor(), new Place()); + Assert.Fail(); } + catch (InvalidCastException) { } + } - [Test] - public void TestStaticMembersOfStruct() + private void TestStaticMembersOf(Type type, object expectedRoRefValue) + { + // ro const int + SafeField constField = new SafeField(SField(type, "constantValue")); + Assert.AreEqual(5, constField.GetValue(null)); + try { constField.SetValue(null, 3); } + catch (InvalidOperationException) { } + + // ro static readonly int + SafeField roVtField = new SafeField(SField(type, "staticReadonlyVTValue")); + Assert.AreEqual(11, roVtField.GetValue(null)); + try { roVtField.SetValue(null, 10); } + catch (InvalidOperationException) { } + + // ro static readonly object + SafeField roRefField = new SafeField(SField(type, "staticReadonlyRefValue")); + Assert.AreSame(expectedRoRefValue, roRefField.GetValue(null)); + try { roRefField.SetValue(null, new object()); } + catch (InvalidOperationException) { } + + // rw static int + SafeField vtField = new SafeField(SField(type, "staticVTValue")); + vtField.SetValue(null, 10); + Assert.AreEqual(10, vtField.GetValue(null)); + + // rw static object + SafeField refField = new SafeField(SField(type, "staticRefValue")); + object o = new object(); + refField.SetValue(null, o); + Assert.AreSame(o, refField.GetValue(null)); + } + + [Test] + public void TestInstanceMembersOfStruct() + { + object testref1 = new object(); + object testref2 = new object(); + MyStructWithPrivateFields myStruct; + + // ro readonly int + myStruct = new MyStructWithPrivateFields(123, testref1, 456, testref2); + SafeField instanceReadonlyVtField = new SafeField(IField(myStruct.GetType(), "instanceReadonlyVTValue")); + Assert.AreEqual(123, instanceReadonlyVtField.GetValue(myStruct)); + try { instanceReadonlyVtField.SetValue(myStruct, 10); } + catch (InvalidOperationException) { } + + // ro readonly object + myStruct = new MyStructWithPrivateFields(123, testref1, 456, testref2); + SafeField instanceReadonlyRefField = new SafeField(IField(myStruct.GetType(), "instanceReadonlyRefValue")); + Assert.AreSame(testref1, instanceReadonlyRefField.GetValue(myStruct)); + try { instanceReadonlyRefField.SetValue(myStruct, this); } + catch (InvalidOperationException) { } + + // ro int + myStruct = new MyStructWithPrivateFields(123, testref1, 456, testref2); + SafeField instanceVtField = new SafeField(IField(myStruct.GetType(), "instanceVTValue")); + Assert.AreEqual(456, instanceVtField.GetValue(myStruct)); + try { instanceVtField.SetValue(myStruct, 10); } + catch (InvalidOperationException) { } + + // ro object + myStruct = new MyStructWithPrivateFields(123, testref1, 456, testref2); + SafeField instanceRefField = new SafeField(IField(myStruct.GetType(), "instanceRefValue")); + Assert.AreSame(testref2, instanceRefField.GetValue(myStruct)); + try { instanceRefField.SetValue(myStruct, 10); } + catch (InvalidOperationException) { } + } + + [Test] + public void TestInstanceMembersOfClass() + { + object testref1 = new object(); + object testref2 = new object(); + MyClassWithPrivateFields myClass; + + // ro readonly int + myClass = new MyClassWithPrivateFields(123, testref1, 456, testref2); + SafeField instanceReadonlyVtField = new SafeField(IField(myClass.GetType(), "instanceReadonlyVTValue")); + Assert.AreEqual(123, instanceReadonlyVtField.GetValue(myClass)); + try { instanceReadonlyVtField.SetValue(myClass, 10); } + catch (InvalidOperationException) { } + + // ro readonly object + myClass = new MyClassWithPrivateFields(123, testref1, 456, testref2); + SafeField instanceReadonlyRefField = new SafeField(IField(myClass.GetType(), "instanceReadonlyRefValue")); + Assert.AreSame(testref1, instanceReadonlyRefField.GetValue(myClass)); + try { instanceReadonlyRefField.SetValue(myClass, this); } + catch (InvalidOperationException) { } + + // rw int + myClass = new MyClassWithPrivateFields(123, testref1, 456, testref2); + SafeField instanceVtField = new SafeField(IField(myClass.GetType(), "instanceVTValue")); + Assert.AreEqual(456, instanceVtField.GetValue(myClass)); + instanceVtField.SetValue(myClass, 9182); + Assert.AreEqual(9182, instanceVtField.GetValue(myClass)); + + // rw object + myClass = new MyClassWithPrivateFields(123, testref1, 456, testref2); + SafeField instanceRefField = new SafeField(IField(myClass.GetType(), "instanceRefValue")); + Assert.AreSame(testref2, instanceRefField.GetValue(myClass)); + instanceRefField.SetValue(myClass, testref1); + Assert.AreSame(testref1, instanceRefField.GetValue(myClass)); + } + + [Test, Explicit] + public void SafeFieldPerformanceTests() + { + int runs = 10000000; + object myClass = new MyClassWithPrivateFields(123, new object(), 456, new object()); + FieldInfo fieldClassRefValue = IField(myClass.GetType(), "instanceRefValue"); + FieldInfo fieldClassVtValue = IField(myClass.GetType(), "instanceVTValue"); + + StopWatch stopWatch = new StopWatch(); + using (stopWatch.Start("Duration Class Set/Get field value: {0}")) { - TestStaticMembersOf(typeof(MyStructWithPrivateFields), MyStructWithPrivateFields.GetStaticReadonlyRefValue()); - } - - [Test] - public void TestStaticMembersOfClass() - { - TestStaticMembersOf(typeof(MyClassWithPrivateFields), MyClassWithPrivateFields.GetStaticReadonlyRefValue()); - } - - [Test] - public void TestSetIncompatibleType() - { - IDynamicField inventorPlace = Create( typeof( Inventor ).GetField( "pob", BINDANY ) ); - try { inventorPlace.SetValue( new Inventor(), new object() ); Assert.Fail(); } - catch (InvalidCastException) { } - try { inventorPlace.SetValue( new Inventor(), new DateTime() ); Assert.Fail(); } - catch (InvalidCastException) { } - - IDynamicField inventorDOB = Create( typeof( Inventor ).GetField( "dob", BINDANY ) ); - try { inventorDOB.SetValue( new Inventor(), 2 ); Assert.Fail(); } - catch (InvalidCastException) { } - try { inventorDOB.SetValue( new Inventor(), new Place() ); Assert.Fail(); } - catch (InvalidCastException) { } - } - - private void TestStaticMembersOf(Type type, object expectedRoRefValue) - { - // ro const int - SafeField constField = new SafeField(SField(type, "constantValue")); - Assert.AreEqual(5, constField.GetValue(null)); - try { constField.SetValue(null, 3); } - catch (InvalidOperationException) { } - - // ro static readonly int - SafeField roVtField = new SafeField(SField(type, "staticReadonlyVTValue")); - Assert.AreEqual(11, roVtField.GetValue(null)); - try { roVtField.SetValue(null, 10); } - catch (InvalidOperationException) { } - - // ro static readonly object - SafeField roRefField = new SafeField(SField(type, "staticReadonlyRefValue")); - Assert.AreSame(expectedRoRefValue, roRefField.GetValue(null)); - try { roRefField.SetValue(null, new object()); } - catch (InvalidOperationException) { } - - // rw static int - SafeField vtField = new SafeField(SField(type, "staticVTValue")); - vtField.SetValue(null, 10); - Assert.AreEqual(10, vtField.GetValue(null)); - - // rw static object - SafeField refField = new SafeField(SField(type, "staticRefValue")); - object o = new object(); - refField.SetValue(null, o); - Assert.AreSame(o, refField.GetValue(null)); - } - - [Test] - public void TestInstanceMembersOfStruct() - { - object testref1 = new object(); - object testref2 = new object(); - MyStructWithPrivateFields myStruct; - - // ro readonly int - myStruct = new MyStructWithPrivateFields(123, testref1, 456, testref2); - SafeField instanceReadonlyVtField = new SafeField(IField(myStruct.GetType(), "instanceReadonlyVTValue")); - Assert.AreEqual(123, instanceReadonlyVtField.GetValue(myStruct)); - try { instanceReadonlyVtField.SetValue(myStruct, 10); } - catch (InvalidOperationException) { } - - // ro readonly object - myStruct = new MyStructWithPrivateFields(123, testref1, 456, testref2); - SafeField instanceReadonlyRefField = new SafeField(IField(myStruct.GetType(), "instanceReadonlyRefValue")); - Assert.AreSame(testref1, instanceReadonlyRefField.GetValue(myStruct)); - try { instanceReadonlyRefField.SetValue(myStruct, this); } - catch (InvalidOperationException) { } - - // ro int - myStruct = new MyStructWithPrivateFields(123, testref1, 456, testref2); - SafeField instanceVtField = new SafeField(IField(myStruct.GetType(), "instanceVTValue")); - Assert.AreEqual(456, instanceVtField.GetValue(myStruct)); - try { instanceVtField.SetValue(myStruct, 10); } - catch (InvalidOperationException) { } - - // ro object - myStruct = new MyStructWithPrivateFields(123, testref1, 456, testref2); - SafeField instanceRefField = new SafeField(IField(myStruct.GetType(), "instanceRefValue")); - Assert.AreSame(testref2, instanceRefField.GetValue(myStruct)); - try { instanceRefField.SetValue(myStruct, 10); } - catch (InvalidOperationException) { } - } - - [Test] - public void TestInstanceMembersOfClass() - { - object testref1 = new object(); - object testref2 = new object(); - MyClassWithPrivateFields myClass; - - // ro readonly int - myClass = new MyClassWithPrivateFields(123, testref1, 456, testref2); - SafeField instanceReadonlyVtField = new SafeField(IField(myClass.GetType(), "instanceReadonlyVTValue")); - Assert.AreEqual(123, instanceReadonlyVtField.GetValue(myClass)); - try { instanceReadonlyVtField.SetValue(myClass, 10); } - catch (InvalidOperationException) { } - - // ro readonly object - myClass = new MyClassWithPrivateFields(123, testref1, 456, testref2); - SafeField instanceReadonlyRefField = new SafeField(IField(myClass.GetType(), "instanceReadonlyRefValue")); - Assert.AreSame(testref1, instanceReadonlyRefField.GetValue(myClass)); - try { instanceReadonlyRefField.SetValue(myClass, this); } - catch (InvalidOperationException) { } - - // rw int - myClass = new MyClassWithPrivateFields(123, testref1, 456, testref2); - SafeField instanceVtField = new SafeField(IField(myClass.GetType(), "instanceVTValue")); - Assert.AreEqual(456, instanceVtField.GetValue(myClass)); - instanceVtField.SetValue(myClass, 9182); - Assert.AreEqual(9182, instanceVtField.GetValue(myClass)); - - // rw object - myClass = new MyClassWithPrivateFields(123, testref1, 456, testref2); - SafeField instanceRefField = new SafeField(IField(myClass.GetType(), "instanceRefValue")); - Assert.AreSame(testref2, instanceRefField.GetValue(myClass)); - instanceRefField.SetValue(myClass, testref1); - Assert.AreSame(testref1, instanceRefField.GetValue(myClass)); - } - - [Test, Explicit] - public void SafeFieldPerformanceTests() - { - int runs = 10000000; - object myClass = new MyClassWithPrivateFields(123, new object(), 456, new object()); - FieldInfo fieldClassRefValue = IField(myClass.GetType(), "instanceRefValue"); - FieldInfo fieldClassVtValue = IField(myClass.GetType(), "instanceVTValue"); - - StopWatch stopWatch = new StopWatch(); - using (stopWatch.Start("Duration Class Set/Get field value: {0}")) + for (int i = 0; i < runs; i++) { - for(int i=0;i +/// Unit tests for the SafeProperty class. SafeProperty must pass the same tests +/// as DynamicField plus tests for accessing private members. +/// +/// Erich Eichinger +[TestFixture] +public class SafePropertyTests : BasePropertyTests { - /// - /// Unit tests for the SafeProperty class. SafeProperty must pass the same tests - /// as DynamicField plus tests for accessing private members. - /// - /// Erich Eichinger - [TestFixture] - public class SafePropertyTests : BasePropertyTests + protected override IDynamicProperty Create(PropertyInfo property) { - protected override IDynamicProperty Create(PropertyInfo property) - { - return new SafeProperty(property); - } + return new SafeProperty(property); + } #if NETCOREAPP - private bool CanGenerateVisualBasic => false; + private bool CanGenerateVisualBasic => false; #else private bool CanGenerateVisualBasic => Spring.Util.SystemUtils.MonoRuntime; #endif - [Test] - public void CanGetSetSimpleProperty() - { - if (!CanGenerateVisualBasic) - { - // TODO (EE): find solution for Mono - return; - } - object o = GetVisualBasicTestObject(); - IDynamicProperty simpleProperty = Create(o.GetType().GetProperty("SimpleProperty")); - simpleProperty.SetValue(o, "CanGetSimpleText", "args"); - Assert.AreEqual("CanGetSimpleText", ThisLastPropertyValue.GetValue(o)); - Assert.AreEqual("CanGetSimpleText", simpleProperty.GetValue(o)); - } - - [Test] - public void CanGetSetSimpleIndexer() - { - if (!CanGenerateVisualBasic) - { - // TODO (EE): find solution for Mono - return; - } - - object o = GetVisualBasicTestObject(); - IDynamicProperty simpleProperty = Create(o.GetType().GetProperty("SimpleIndexer")); - - // write - simpleProperty.SetValue(o, "CanGetSetSimpleIndexer", 2); - Assert.AreEqual("CanGetSetSimpleIndexer", ThisLastPropertyValue.GetValue(o)); - Assert.AreEqual(2, ThisArg1.GetValue(o)); - - // read - object value = simpleProperty.GetValue(o, 3); - Assert.AreEqual("CanGetSetSimpleIndexer", value); - Assert.AreEqual(3, ThisArg1.GetValue(o)); - } - - [Test] - public void CanGetSetComplexIndexer() - { - if (!CanGenerateVisualBasic) - { - // TODO (EE): find solution for Mono - return; - } - object o = GetVisualBasicTestObject(); - IDynamicProperty property = Create(o.GetType().GetProperty("ComplexIndexer")); - - // write - property.SetValue(o, "CanGetSetComplexIndexer", 2, "Arg2"); - Assert.AreEqual("CanGetSetComplexIndexer", ThisLastPropertyValue.GetValue(o)); - Assert.AreEqual(2.0, (double)ThisArg1.GetValue(o)); - Assert.AreEqual("Arg2", ThisArg2.GetValue(o)); - - // read - object value = property.GetValue(o, 3, "Arg3"); - Assert.AreEqual("CanGetSetComplexIndexer", value); - Assert.AreEqual(3.0, (double)ThisArg1.GetValue(o)); - Assert.AreEqual("Arg3", ThisArg2.GetValue(o)); - } - - [Test] - public void TestForRestrictiveSetterWithSafeWrapper() - { - Something something = new Something(); - - IDynamicProperty third = Create(typeof(Something).GetProperty("Third")); - third.SetValue(something, 456); - //this should be ok, because both get and set of the "Third" property are public - Assert.AreEqual(456, third.GetValue(something)); - - IDynamicProperty second = Create(typeof(Something).GetProperty("Second")); - Assert.AreEqual(2, second.GetValue(something)); - //this should not cause MethodAccessException because "second" is created using "CreateSafe" - second.SetValue(something, 123); - - Assert.AreEqual(123, second.GetValue(something)); - } - - [Test] - public void TestForRestrictiveGetterWithSafeWrapper() - { - Something something = new Something(); - //new SafeProperty() - IDynamicProperty third = Create(typeof(Something).GetProperty("Third")); - //this should be ok, because both get and set of the "Third" property are public - third.SetValue(something, 456); - Assert.AreEqual(456, third.GetValue(something)); - - IDynamicProperty first = Create(typeof(Something).GetProperty("First")); - first.SetValue(something, 123); - //this should not cause MethodAccessException, "first" is createtd using "CreateSafe" - Assert.AreEqual(123, first.GetValue(something)); - } - - #region VB TestClass Code - - private static Type s__visualBasicTestObjectType; - private static IDynamicField ThisLastPropertyValue; - private static IDynamicField ThisArg1; - private static IDynamicField ThisArg2; - private static IDynamicField ThisOptionalArg; - private static IDynamicField ThisParamsArg; - - protected static object GetVisualBasicTestObject() - { - if (s__visualBasicTestObjectType == null) - { - // compile vb test class - string vbSourceCode = new StreamReader( Assembly.GetExecutingAssembly().GetManifestResourceStream( typeof( BasePropertyTests ), "SafePropertyTests_TestObject.vb" ) ).ReadToEnd(); - - CompilerParameters args = new CompilerParameters(); - args.OutputAssembly = "VbTestObject.dll"; - args.GenerateInMemory = true; - args.GenerateExecutable = false; - args.IncludeDebugInformation = true; - - CodeDomProvider provider = CodeDomProvider.CreateProvider( "VisualBasic" ); - CompilerResults results = provider.CompileAssemblyFromSource( args, vbSourceCode ); - - if (results.Errors.HasErrors) - { - StringBuilder sb = new StringBuilder(); - foreach (CompilerError error in results.Errors) - { - sb.Append( error.ToString() ).Append( "\n\r" ); - } - throw new TypeLoadException( "failed compiling test class: " + sb ); - } - s__visualBasicTestObjectType = results.CompiledAssembly.GetType( "VbTestObject" ); - ThisLastPropertyValue = DynamicField.Create( s__visualBasicTestObjectType.GetField("ThisLastPropertyValue") ); - ThisArg1 = DynamicField.Create( s__visualBasicTestObjectType.GetField("ThisArg1") ); - ThisArg2 = DynamicField.Create( s__visualBasicTestObjectType.GetField("ThisArg2") ); - ThisOptionalArg = DynamicField.Create( s__visualBasicTestObjectType.GetField("ThisOptionalArg") ); - ThisParamsArg = DynamicField.Create( s__visualBasicTestObjectType.GetField("ThisParamsArgs") ); - } - - object s__visualBasicTestObject = Activator.CreateInstance(s__visualBasicTestObjectType); - - return s__visualBasicTestObject; - } - - #endregion - } - - #region Test Classes - - public class MyClassWithPrivateProperties + [Test] + public void CanGetSetSimpleProperty() { - public static object s_staticRef; - public static int s_staticVt; - public object _ref; - public int _vt; - - public MyClassWithPrivateProperties(object @ref, int vt) + if (!CanGenerateVisualBasic) { - _ref = @ref; - _vt = vt; + // TODO (EE): find solution for Mono + return; } - private static object StaticRef - { - get { return s_staticRef; } - set { s_staticRef = value; } - } - - private static object StaticRefRo - { - get { return s_staticRef; } - } - - private static object StaticRefWo - { - set { s_staticRef = value; } - } - - private static int StaticVt - { - get { return s_staticVt; } - set { s_staticVt = value; } - } - - private static int StaticVtRo - { - get { return s_staticVt; } - } - - private static int StaticVtWo - { - set { s_staticVt = value; } - } - - private object Ref - { - get { return _ref; } - set { _ref = value; } - } - - private object RefRo - { - get { return _ref; } - } - - private object RefWo - { - set { _ref = value; } - } - - private int Vt - { - get { return _vt; } - set { _vt = value; } - } - - private int VtRo - { - get { return _vt; } - } - - private int VtWo - { - set { _vt = value; } - } + object o = GetVisualBasicTestObject(); + IDynamicProperty simpleProperty = Create(o.GetType().GetProperty("SimpleProperty")); + simpleProperty.SetValue(o, "CanGetSimpleText", "args"); + Assert.AreEqual("CanGetSimpleText", ThisLastPropertyValue.GetValue(o)); + Assert.AreEqual("CanGetSimpleText", simpleProperty.GetValue(o)); } + [Test] + public void CanGetSetSimpleIndexer() + { + if (!CanGenerateVisualBasic) + { + // TODO (EE): find solution for Mono + return; + } + + object o = GetVisualBasicTestObject(); + IDynamicProperty simpleProperty = Create(o.GetType().GetProperty("SimpleIndexer")); + + // write + simpleProperty.SetValue(o, "CanGetSetSimpleIndexer", 2); + Assert.AreEqual("CanGetSetSimpleIndexer", ThisLastPropertyValue.GetValue(o)); + Assert.AreEqual(2, ThisArg1.GetValue(o)); + + // read + object value = simpleProperty.GetValue(o, 3); + Assert.AreEqual("CanGetSetSimpleIndexer", value); + Assert.AreEqual(3, ThisArg1.GetValue(o)); + } + + [Test] + public void CanGetSetComplexIndexer() + { + if (!CanGenerateVisualBasic) + { + // TODO (EE): find solution for Mono + return; + } + + object o = GetVisualBasicTestObject(); + IDynamicProperty property = Create(o.GetType().GetProperty("ComplexIndexer")); + + // write + property.SetValue(o, "CanGetSetComplexIndexer", 2, "Arg2"); + Assert.AreEqual("CanGetSetComplexIndexer", ThisLastPropertyValue.GetValue(o)); + Assert.AreEqual(2.0, (double) ThisArg1.GetValue(o)); + Assert.AreEqual("Arg2", ThisArg2.GetValue(o)); + + // read + object value = property.GetValue(o, 3, "Arg3"); + Assert.AreEqual("CanGetSetComplexIndexer", value); + Assert.AreEqual(3.0, (double) ThisArg1.GetValue(o)); + Assert.AreEqual("Arg3", ThisArg2.GetValue(o)); + } + + [Test] + public void TestForRestrictiveSetterWithSafeWrapper() + { + Something something = new Something(); + + IDynamicProperty third = Create(typeof(Something).GetProperty("Third")); + third.SetValue(something, 456); + //this should be ok, because both get and set of the "Third" property are public + Assert.AreEqual(456, third.GetValue(something)); + + IDynamicProperty second = Create(typeof(Something).GetProperty("Second")); + Assert.AreEqual(2, second.GetValue(something)); + //this should not cause MethodAccessException because "second" is created using "CreateSafe" + second.SetValue(something, 123); + + Assert.AreEqual(123, second.GetValue(something)); + } + + [Test] + public void TestForRestrictiveGetterWithSafeWrapper() + { + Something something = new Something(); + //new SafeProperty() + IDynamicProperty third = Create(typeof(Something).GetProperty("Third")); + //this should be ok, because both get and set of the "Third" property are public + third.SetValue(something, 456); + Assert.AreEqual(456, third.GetValue(something)); + + IDynamicProperty first = Create(typeof(Something).GetProperty("First")); + first.SetValue(something, 123); + //this should not cause MethodAccessException, "first" is createtd using "CreateSafe" + Assert.AreEqual(123, first.GetValue(something)); + } + + #region VB TestClass Code + + private static Type s__visualBasicTestObjectType; + private static IDynamicField ThisLastPropertyValue; + private static IDynamicField ThisArg1; + private static IDynamicField ThisArg2; + private static IDynamicField ThisOptionalArg; + private static IDynamicField ThisParamsArg; + + protected static object GetVisualBasicTestObject() + { + if (s__visualBasicTestObjectType == null) + { + // compile vb test class + string vbSourceCode = new StreamReader(Assembly.GetExecutingAssembly().GetManifestResourceStream(typeof(BasePropertyTests), "SafePropertyTests_TestObject.vb")).ReadToEnd(); + + CompilerParameters args = new CompilerParameters(); + args.OutputAssembly = "VbTestObject.dll"; + args.GenerateInMemory = true; + args.GenerateExecutable = false; + args.IncludeDebugInformation = true; + + CodeDomProvider provider = CodeDomProvider.CreateProvider("VisualBasic"); + CompilerResults results = provider.CompileAssemblyFromSource(args, vbSourceCode); + + if (results.Errors.HasErrors) + { + StringBuilder sb = new StringBuilder(); + foreach (CompilerError error in results.Errors) + { + sb.Append(error.ToString()).Append("\n\r"); + } + + throw new TypeLoadException("failed compiling test class: " + sb); + } + + s__visualBasicTestObjectType = results.CompiledAssembly.GetType("VbTestObject"); + ThisLastPropertyValue = DynamicField.Create(s__visualBasicTestObjectType.GetField("ThisLastPropertyValue")); + ThisArg1 = DynamicField.Create(s__visualBasicTestObjectType.GetField("ThisArg1")); + ThisArg2 = DynamicField.Create(s__visualBasicTestObjectType.GetField("ThisArg2")); + ThisOptionalArg = DynamicField.Create(s__visualBasicTestObjectType.GetField("ThisOptionalArg")); + ThisParamsArg = DynamicField.Create(s__visualBasicTestObjectType.GetField("ThisParamsArgs")); + } + + object s__visualBasicTestObject = Activator.CreateInstance(s__visualBasicTestObjectType); + + return s__visualBasicTestObject; + } #endregion } + +#region Test Classes + +public class MyClassWithPrivateProperties +{ + public static object s_staticRef; + public static int s_staticVt; + public object _ref; + public int _vt; + + public MyClassWithPrivateProperties(object @ref, int vt) + { + _ref = @ref; + _vt = vt; + } + + private static object StaticRef + { + get { return s_staticRef; } + set { s_staticRef = value; } + } + + private static object StaticRefRo + { + get { return s_staticRef; } + } + + private static object StaticRefWo + { + set { s_staticRef = value; } + } + + private static int StaticVt + { + get { return s_staticVt; } + set { s_staticVt = value; } + } + + private static int StaticVtRo + { + get { return s_staticVt; } + } + + private static int StaticVtWo + { + set { s_staticVt = value; } + } + + private object Ref + { + get { return _ref; } + set { _ref = value; } + } + + private object RefRo + { + get { return _ref; } + } + + private object RefWo + { + set { _ref = value; } + } + + private int Vt + { + get { return _vt; } + set { _vt = value; } + } + + private int VtRo + { + get { return _vt; } + } + + private int VtWo + { + set { _vt = value; } + } +} + +#endregion diff --git a/test/Spring/Spring.Core.Tests/Resources/Images.resx b/test/Spring/Spring.Core.Tests/Resources/Images.resx index b725b654..7db48ae7 100644 --- a/test/Spring/Spring.Core.Tests/Resources/Images.resx +++ b/test/Spring/Spring.Core.Tests/Resources/Images.resx @@ -58,7 +58,8 @@ : using a System.ComponentModel.TypeConverter : and then encoded with base64 encoding. --> - + @@ -92,339 +93,345 @@ 1.3 - System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + - + - R0lGODlhkgB3APcAAP///zk5OUJCQjkxMXNaWlpCQoxaWoQ5OaVrY4RSSqVjWueUhNaEc5RaSs6Ea3NC - Ma1jSmMxIbVzWloxId6Ma0o5MTkYCIRSOUIhENaMY6VrSu+ca8Z7Uq1jObVzSlIpEIRrWlpCMe+lc86E - UkIpGIxSKVopCGsxCIRjSu+cWpxjOWM5GK1jKXtCGIxKGIRCEJRrSpRjOWtCIcZ7OaVaGHNaQko5KSEY - EPelWueUSr1rIcZrGJxSEFJKQmtSOWNKMVpCKXNSMb2ESu+cSnNKIZxjKZRaIb1zKc57Ka1jGKVzObV7 - OfelSq1zMb17MeeUOa1rIcZzGNZ7GIRjOXtaMeecQs6MOZRrMb2EOYxjKe+lQpxrKeecOdaMKeeUKYxr - OXtaKfetQv+1Qt6cOe+lOeecMbV7IZRrKfetOf+1Od6cMe+lMfetMf+1MVpKKUo5GEpCMZRrEFJKEFpS - ECEhGEpKMUJKCEJKGCk5EDE5KSE5GBgxEBAhEEJSSilCORgxKUJKSggQEBAhISlaYylKUilCSkJaY1LG - 90JSWiExOTlaa0paY0qt51Jre1Kt5yFKYzlSY0JjeyE5Skql50qt7zlacylKY0Kc3kpzlDlrlEKEvUqc - 3kKU1jlCSkpjezmM1ikxOSEpMUJac0JjhDFKYzFSc0qMzjmEzlJaY1KEvTlrpTlztTl7xlJznEpzpTla - hEJrnDFajDFzxjFCWjlScyE5WjljnDFrvSljtSlrxjlKYzFShDFKcyFSpSFatRghMSlKhDFapSFKlEJS - czlShDFSlDFKhAgQITlKcyE5czlCWjFCcxg5lCExYzlKjBAxpRAxrTE5WiEpShghShAYOQgQMSExhBAh - hAgYlBAYawgQYwgQezk5QlJSYyEhKUJCjDk5ewgIOQgIUggIYwgIazEpe1JKe0I5c0pCazkxWjkpczEh - Y1JCcwgAGEIpa0oxY1o5a2tCe0pCSiEYIQgACJRSjEoxQnNKY6VrjJRSc4xKY61re3NCSqVrc6VjawAA - ACwAAAAAkgB3AAAI/wCPUcvW69MkRpdOCatFLdC8WRhMWDjxgkQFF0ky0uDh4kSeWnz4/CJlidq0aeGq - Cbt06dMnSr6ukdNWLOY1a9vUwbPmK5s+CSPilfOQIoeCR8D8JAJV5IiOHUlexCkzg4OBBCO8aHnihc0T - NmDDejEjqVizFWvWeJHSwo+qab2SYeARwk+tdv/y0vtHTxi1vIAB79VbzRKrSwhxMatFxwKGEzwyRoni - Y0kSH1CkSOnihbPmLIX84OE2LVQgPokSHavW61oza7k+YdOWTdatW8KYXdvmLp6zePr83TPGrsqCFAYe - PUrWLBSJAKD++PEzjceMGQg8gH3SZk0XK2zSqv8FC+aRpUcuvB4RUEpSqWaWLHHjscLPr7+D957ky3dv - fv/TaEIJLrUkQsIKLkCBhBReNOhgF0iE4ESDZXTWoBpqVLEFIQO4QEURNLjwwgp6CDLPL8cE0k4zp/RS - 0Cm44NILLrcks44/FPSjDjm98MNABimwkxQvuyQSQgxFBFBKLXlwI4AAD5TRRlhrjFFGeFWsEZ4XVxix - AjArNNjHI534UYwwGCDRRB15/BFINMf0N1gtcebXH3//TGNJIhaY8EIUXYyRQw6CquFgZz8EceihapTR - RQ5UcEMDGw46oYMUNMyBx4kpJkPJJqx8csotpzhyim7p6MNPNrcAo88CDBj/8I4vwDQzACgRrPGEAYi4 - IAULuijDzQM6PPGVsZSm9URaXXkRRylAIOGFAVQc0QIvyfCwVgR/EEIIKNLgxR898yQTyJ149nfMHzfw - 8N0MagQ6hhVWzIuhF030gEWjDXJRRpVWdNGFFDoAMUAUT1ToAQwOYqqpN95M08xKlFAyCSef3NLLOOKI - k8wtteRTjzvZxGgLKB2w4MMMWjhx5RMzLCGFEZKAIkMXU4ZXxrK6iscGC8CkJwUSLMxQRhAyQOFCHoTE - EskfqE1DDz3n5iXNL3pNLSdgz1VgRBdqWFHF2DlUUUajVTjhgxNqVchFFVz5e0YFAXAzgCQhWFmhrl4w - /+tFFHPQ8Ys37YQTzCeXVHwKK8KsEowswYjzzjqwCSNMMOlQMEQZOYzgwRNacGAFGmwgUQghtUzQFc9a - 6JpD32qxUMoJD/RBSA9sr6EDIKXYgswPYPjghzTNiBPI1HsFAk6cgo079QAT3ApEB2dbkUO9ZhvqAxV9 - l1GFlV78W0YZR/jxRyneTFBLEQnDneUTZISv1hzU/JKINMckk401lFwSzC2mYAQjrGENcVxDIdsQxi2k - oY8MPGFsIBiB6JZFhjU0AQo+mIYRwoMGY+XgCWOYwVe8IINIJIIUtQACg9TyA1tYwgZJcFAS7qALa4Qj - RVRrx36Qd6fByKMbdRhAIv+4UQIkPCEFVvDeGNZggAKoIS3eW9b4uMCVKNQhPgE4QhAGwAKxJWwNVuAK - s8DghxPgIRGWwB89gDGJU5yCEoy4jTCsMarLCaMXwAiAP1KQAgZIwAES6GAH16AFLSChD9KAwhMgBDsZ - umEQsUhEIbzBAi2VAQylIOIS/5UWM+AhGtsQRzvaQbVj1CJ5gzlef8zAggbUIBqJIIQNSjACPuYAQj0I - 5Bp2Nr4p/ssLIQhiKSLgBSREQwY7e0K8RMisQxrhbyu4gSQsIZDEtYQVt4gRLjJWjGI4Yx3LsEQB8iGB - cnKADEMgw1a8spUokMIGO+hBDcCyli3UgRCACIAl9BD/vQcgAQsPAIQlXLCGD5KBC32Tgh0CUQ5yiOMY - pKRHM5rxn+YFDwtI0AAB+lAKS1RAAVUoWw2UoLPx7XJ8DVKLE7qQhEU0wQtP6EAhXKCFMdj0gVxBQh3g - kFIv6EAOdOCFJWohDFMEgxWcuEUuEjKJTzAjG/l4xzKyUYtslMMHutIC3NAQBq8sqwa1MMKEvMCCIBRi - FkFggRSyQIgkGOERtfhBA5CQgFJEYQ1DqAIXyBAeGvyBGPoTxw1JeQxwHM8/yDuXH3ogBUOVQW2xkA8N - pFCEC/xyDRXsGxk4ucuUcsYLZHhCDaQxg11qNUtk8EAhiiCetHSBB3iQxDJ+UY1q/3Cif5fgxCUOwYhe - WCMf+khGMK7BClukqWxP6OBW1MmGIljiAzsogg860Y0rMKhBNQBEFPjBiwlgQVcw0AXC1MCFsmE2DpZw - BiHWwbFqQLQdtZjGPw6LJ0HMghtBAFujuuCEBnSDQwGAQt/Cg9n4VWmEV1pDFfiqlkX2IARlSMGyvrIG - JLihCwkLLfzKEAU7hIIXhKBHMJJ6i9syYhPDXUcBssGKU9iiFNOYwBMGlYOtVGErXnDBI0DhrUQIuG+k - 80EhuMGCLxwhimRYgi6gADd/fREJcviDN6hxDcG24xj0yB9eksefagBhC1M4wqG8N4MSDKISASjCZ8NT - wWSp5f/N8NOssY7AjQ3+a1leMIIPvBJaMtTYWEbwAx9IwQtq3KIY08DFJg5hCoUkw4CX0BhzKgA3Gmvh - OpUdgCVIEQIo2KMIOatQCIoBCCRsR6sVRgQQQMsFLXCBC2qJQh8EvQ6HVmOUEpWa1gYzjySwQQ1jcJBa - blwEOIABEJIIABWc8EQthCdZlAoPQilVyIKCgRs6IDCl6tAAPpMhpN9+AhHgANtEZKIZwKBGMQKIC1ko - RBinCIYqTmGNaYhDHzMYwQdncIFZJOMRQPBDCLoSA1OTga8RisQEylDBKkHgSgYgRCVbDTe+JmEQc7BD - IkJ5a4hWIxnIC3kgJiS68FHIC0f/mAULiumDmskTBXNtVmuz+m3vdWGuP6gATLXghTMUAgloQMPBh5CD - IYygCoC4QOlIVApp0GMawTiEqC4hC0rcwhrCwCYzhJGNCPCDHz3gxSwI0AAPJGEWJWBDGYQ+7OucQREV - kAIZUrAVepWOGBVAQl71qgUp9KATSTDDDdwxjnCE48rtqDfVdv0PLFTobJCvUBCcUVrvqWARAXBBE7oB - iBqMVTxqGNTY4FaGMJouPWjwQh184IWVku7gKRjCDKJRhDAk7AV02IUl/kENTbAkjrLoBdevQapc9MIX - vhBGMvhxBC15IQuziMIgd0mAz7HhCoooRLYPrqWaskHJFeiA/5aegIQelIIGDZLDL0Jp+JRMQxhbvpMV - 1tCos8mvCX4ogVrajIQKdMIISBADtcANgPAFC9IgT5BXE6YWV4AERcANUMAGNEAIS9AGVPADCBhSndMD - SFBxakADe0Bo4uAMweBGj5MLisEMvXAJmoALvsAMpAUzVtAGOoBWBDYEHDACEqAGYEEFflAI/MA6HQQ3 - bKACpUAIIUAEQTAIpMBaahEHeNBQHdN+wKBr5zI1XdBZasBsahF2NeAFaNAFL3UEbmAE3RACNkAIoZAO - DdADcFABRFACLGBqbLAVY3ABPmAEdRAAL1AHU+AVgSYDP6AEYsAAQ+AEPTAG8FM2ZWAEev8wCrswDdaQ - DMBgCi0Rb7KQC7nACqwQDNYgDfxgAEhSArPQB05wh1hQFFqiK2zAD27gBlgFP1riVWiwBt2gC92ACItQ - AzrQN80iB9JQQIJleNkADDx0LmzjKD6ACEhgQT7gAVYAWl3gA28wAEUwBl1QAaXgCaEQJmAgCYRQCZYQ - DZ3wATTQBUPAFU4gD3+gCKEACjrQBvZECokgA03gARDgBEAACgJmLGGwFhPgB5UQC/TQDsBgKpeAYrKA - CyjIDNYADOdgCc2gDITADVQwAxKQAUCxBkJXi5TSA1BwBgNgalrikT1jBSJkKFDEV10RB3wghVMYDsxQ - DSH3D0/kHaj/IABm0AVfAB7aBgWFIAAsYCxdQAWLEAnc8AIvQAiNMAqqoAq2EE6dpwRbUARpWAiiAAqz - 5AM+UAegMAUwUABXMwukAAoBUAAJUAMXIA+gUAiJMAyWUA3TYAq3wAqUoFu3MFzMgQASAAEaoAJYoIhW - oAAZ8EGYJXRgwQKzcARI0AlQ0B0cWUHhxlUcpGDz1yxdYAe6cA3Z0DEdUw7AEAiHRQ+cYQZmEAd1IAUw - wDYGRilTsAVSUAP04mdQ0AOv8AfcIAqYMAu1IA4SEyPJUAukMAuIcEKzQAgkgARhEIZfUAZDEAN+EAmD - EAAPUAIR4A2EYAuqUAy7QAu/8AuZIBB5/xkMk3AIl7AQ2vANGSACTDAEQ8AEscIBQ6AF6ISYOOYDBbAG - UtAHMsAGQyB0fFWYXYEEl4Usz+YsoNBQ5DAOnakNwUANIXcGXrAFcMANQKADE7IGrQZF4NEG3ZECaXF9 - i9AH7hgJkQAK8jALnQAI6NANVBADVBACiDAKsUAKhfABpuYFaTAGI9ACkfAKfEACB1ADPVAIuxALu5AM - klAIihANurAL/1ALpxB8kzAJveCQ2bAPDnAP7AAPEsABVUB06nRwQRd0VtAJoIYEiKAMIxAGZEA6bIAG - MEAFPAAHSNAF8uADJtUVlBIHfwAKMkEO2eBQwGANi0cPcOADDTAHff8gAHXAGfvHfdrGBgsWFjTADXCQ - B4kQYGpwAaHwA0hgKF7QBlLgBp2gDKMwCrMwADIABC1ABGh4nKHQCbPQDQkgAKCAFMBACpIQCoXQLfI1 - EMLwCZzgiQ4pDenADMVwDg3QnoU0nx1JOmmwBAIwA6lXAPJQmAAKFvnyB3kgBU3gC52ABNx3JV1QB7PA - UNtADuzKoMGAZaLpBFYwBYUACiswBZzBWQcHFqsYFmzQBkiACjQQAvIQAGqlAgJwD3wKFucaQ0VAq96Q - CLGgC4RQCqQgDd5QBNeBBBdwK4OwC7xADEvyC0phC1hTDa/BCqbgW8HADKtgDM3ADhLQAFaQTgf/R6Zv - 2gY+ME+u2QNesJxxGrRQ0Afz0QVgkAQFNn8sVAh8UAsyMagcYxa4loUTWgN18AUUYlJpIakElhYzgARI - UAI1EAXFJgAtEKoDphZBwA1NgAX80AmKAAmgEAtnlQmFUAgBEAI1IF2gIAAEUADKYAnf8gNF6pYESQ3B - sAyaoAmr4BL0lg3XAA/6IA9OgAZDsAZhkAN8RTpqIA/M1AYq0AdgWEFBh1nPRwh5cARt0AVl0Do64wU+ - EAB2MA84sa4cIwy2MEqBQLXecQRXUANNwIMhGh7p5K//ugRTMAV9UAAo8AVAoAjKQARf0ABKoAExEAKD - 0ANfoAEz4AFUgAh0/xABLEAE3DAPihAJpAAIpOAtE+AE+FgL76ACI5ABD9AJoTALpfAPzQBAq3AN89ay - 2ZAN7oAOCCACNzafN8aRbbAErJcG3OEBBMCnm8sGZNAGVxACJcA9MzAGXbsGSdAHd0AEeKAO27CuDpUN - b9EOu4tQahC83nEFQVACXaBtNeavaqAEjvUFZrAEM9ABcCAAhTAAwUsvOyUFbYByUeACAUAKJDADXlAC - 3sAN8vABP2APhPAFU8CV8tAMF+ABI6AC3RAKkJAIryAN/wAMc8QKjPAJ2uki+qMO+CACfHRj7MQGBXAF - bSB0WmAGoqtMpAOgXvAFrFcGSwCpmIVQ2OsrwP+IDdsAteIQDM0wSp+1wz11BIAgAGJmvJsLwVWABlWg - AVxAL11cAyXgA0FgamqACCzQBkczC7gaH9JQCyzgBBdBBPYABLP0r54DAvegCz3QA6FACInwB6IQCplA - StbACYfAWy7RaLggDNfADwtAAZ1sBUD3BJbcBWlAOm2gBH3ABlaABWDBzVVgBdDYBjAgAyHwADO8bW1V - Bi5Zuws6gsHgXobSwiqZUlZQBPJwBV0xi2HhBFgwJWugBFpSA6TwNQzjA3UmA3XQFU1QADJwOvJABIrA - Cy1gx0BAAAnQCT0wA2WjBUyQAwywD/zQNJBACqVQCJVACLsQCPzjCIfgCJ//4G6rsArFmg0JYACoYAQt - QAVpwAY/sGdl2s0+O851+G2zWGNRoAjBUAs8UEQlRAjyegUjvBvtmg2rMA3tkIVdsARv1lps0AVTYGwL - qyXMBhYLPIMqEAuesANKUAUe0AdwQAhAgDNXgLVO0AROTAXPFQU1oAyfI7bWkwJhGgawAge8WgqxEAu8 - UAmFQAsmISDLzAic0CLkYA3B8Myg0CTzYARt4AQCoM2bi86xGLQHNzr7SgYdsAjEEAAXUANXoNiTQilz - kAiMzK7ZMA6qkAzVwBlcOHMhOqHyAAZdIZkoAHQCUwbVkgQ2UAQxQFJpQQSEYAnGLdrZVotaUAY+wMR9 - /xsF3P0FmSsC/QADTzAC91AJgvAIkWCxpZAMyMANr3A806AKmyDTh9AinAkM3ZQIeyAJJCAFMnABefym - YJHFcRp0ecwEN/ttZNAALJAER6DNUoAIAyAFadEGZjAP5YDV7FoMwBAOYPN5ws2nXpC8zciRMGCAPjAA - J1DX8qBqX7AsaLCfcEAFAmCABcANP1BJa5AGH1wJN0BkVpDj/rkB8cALF4AFClAK5hZZszANpTAMJ2TG - x5ANwlAM9404n1gAHeADu0AIuDkP3AB0r4cGZdADVPBs9CIEGTACQYdOdBUEQECdSQAEjyAJGT0lXXDV - jcyu1qAK4vAdYJNSz3boYf9xBWsDFliwBFiAvaPADZ0ACvMwAF/IkVfgs0igAl9QAC6gjZ0gBTVeAISQ - fXxQADlwAVMQBlowBPgAzQYwA+hgC7OwC4/gBwMgDZFACHwQDcdTDcBQDqbAC8UQI7XyAOpTseB44X9M - OkgwDICQAAmgAkIgNitJKTXQByGgCKoACt4ACXkwC0ZgQdIyB7/AyCa8DaqQDUewBLAj1j4TbWqABK/J - BmOgBBZGCJhQCJW+CKIwCxegFj6wBWwwA0Jg1Ez6hV0gAIrwy6MwRDOABfOkBTmQAv0ADuBwAX1QJO6h - DAOgDcOJGrvXDiq4CuAADC5iDZbwb5kgCX5QCrQwDTb/AAYzEAZVUGa60JNWwFfbjAahTDpUgCs7oAM2 - UAqu4A1JEAVZ4QNgEAV3QAe1a8KrAAzM9u7CPR7+WtAGbQUhAAckoAuGMACEUAiRAAQ+0ARbwHqkU0hp - YAUtrkhClpzlFwmrNQMFgATt2QHdIA3AsAyFUAGVkAmvUAuSAAyPQAiSIAjDQEqqQAmmACrPUA7ZEA6+ - qQrAIPiZoArBIA104AJEsAJNQgMeGsoMV9RHQAh64FF9qAiWMAskMH+LJAV18Ad6YA27UcLkIG9j1Ugd - TCXGi7xeMAM1MAUxYA+hwA3eMAtF4AUFIMRhEecdFAMCAAcRYAjcAAZk4HeQEABS/6ACPtAFTPADmLAI - ESAPBDADAvALTfcItvAKxjALf3A/9JAMjOsINC0Lll8MmtAMyWAJg5AIANFnFq9avxJJevRrRZs2bITA - QBMRDRswlmDtUvSL1KM9iqa5YOMhhhcwhbhJw7ZN5TZrwbp4KbNG5ho2NNnUvIkz5xolNdS0QdPmSggq - PmB4QSKvhxc2EclMfLqmQKcXA1QtQpImySJFLZAI6HHERSFENC40kCBPWqRXllTtSkaIDh9ego5NK8bJ - 0aZLnIrFsiWpmR8/fw4CW7ZMWiFz024YeTlkHxmgaLygIARs1qhK836VyqTIAg83hXa8IKRHkLWV264F - 21Jzpv/NnFrI5GzjRU1OJ1nKeCHTpQYLpl6uENrSMOIaLmnSrFHhwUOdPyRm5MhRhUgkUCWQ9FDWB1Kn - JA2+OAFF6NUrar5KlZJEAo+kZfToHUt2ixWuYtmaJUvGklJqSSQPG95Y4Y5ODEvGG1AK8MGHK5p4aQ0v - lCCFFFVSIaQTbgYhZZRYBOEGiBf68OONPcpJaSVnBDBDtzXUUEO3I7roQogqvLACCSSaKKIJIZsIwQcn - ZkDiixqKmEEFbpZqao2omkAiBizS0KIOSEJpoYwqUuiih1FIKEOKPhAhhBsZSoBDB36A6COWSGzZpRRS - 5sFgD1rauS8WTljpRRhhbOGFlEr/fjFhhwpromGRWZqhBoMorOgJBXkEIGqFUkZxxZIBbCgqAFFWsSQR - DOoghIYj8JgGm2tUuuaaPlBowgo1rHBCDSUUqcGJI67I4ocQ4LAhAFBIsKHYRAohgkrhlDiijiYqa6qN - LgQYQIk0gushkkWUsQGKESgAAxJSJpBijS368GGKEGYJIQgjCrBllUxGmYYQQiTxg5Bp/plmlVNYOeWT - XHKJJRFu4AiiDDTIgJiMMuq4I5plQnEhDTbaWMOJWVFAoQdACElkggeKYIGHPCCZp49BBsFACi/mkAYa - bFpkRo0ylvDCC5u8cGGFHvr4IYYtzMDRCSTOUAKpJqgAJAAf/8AoQoogfPBioqbKuKIHQwb4AQs0ZnCj - ElEgiYSQASJIpw9Mvi4hiQK6qMmKC8YLIJNdSMnkF0JmKeECPqShJ5BegjHFFFk+ueSWWci8gAqJ0Hji - ih+isMOaWEDh4YkwtNCaizG8KAKIOiIpBRRuOvEDkxv6DWCQN3aIgw5hnrkZm5zZuNWmLraoow8wYmSo - qY23oIKmoNo4gxAbhgXCj+SaeqoMovsIwgku0AgDilAK8QYTNGcphBBEIlHEjwrAiEiL5/owBA5CRrmI - ml0qKCOBPWY5hp5qbgmGI1hxCVMEIxMkQAIHBtCFMDTFCz2Y1hyasQxJcIMI1GtfRGagA/8wlIIbPDhD - EOogCj9AwgUvqIQlTJAEPCTDZjd7xhWcYIUrXCEKcaiDH84gM4bQhAtVYIMSvuCwNaQgDBqbQgWkcAQf - EAIISOAYG8bgAQv94AhAIYMWhECABhTBG25rRCckoQhFLAIUeehDVrQwhDAgoQ8zmMEAIlGIAVgiAilg - gR9CQThvMKMXq1iFJjhxCWeEYgINEAALnhAUJRRCCm2Iwy+KQYcARAMIUQAKG8iwBi3kgHdJmMET1iAF - O+zCEhOIQhJWkL4T2EEavmDGzZhxBSUs4Qp9KMQjSlaEJVDIZ2t4wgxioAQ2NLCIDrBCGh5oAyOYAQk+ - SOQTKFUGNqT/YQlWeBgabJMDCnSgEJAwBCjgwA1CYEIRnrDAA9I4BC1oYQ0NmMEFuDEKbsijFBPAI/hm - cR9rrKIYmggGLj4RDGnIAAICuAAZntAFblzADCXIgh6M4Y0kNAERATCCJp8gTcqoawZDmIEM6gCLX5Dg - DRWYABBKkYc9zAN3uMOGGmQyM0vAAQpNoOUXUFCDKfygAIjgBpPU0AUt3AMbxfDHE2oQiVA4gQ1eyEIA - 6nCFbGohDBG5KveGUIUeQOIC/oiHPy7Alj+QEQMhCIEVhkCGMDzgAdyoRCICYI9X/EEFD5AEJF5xjGOU - AxebuIUsmKE5SfDAm254AhsusBQoECEJ/3pQRyB20AYePOKUWSvD6KRQgln8IKSDsMQuSDCBQZnGCGnq - QzBe2IsuyOQM3AADU3LSszIgoQ6l8AEKCDAFGFwgBujAxS26EYNCvIIWRvBCGpAQhE6EAAnaHAI7bdPO - ITDhCp2tAgP0UYAS2MMTiOADJpRhggr4wAoKRUEiFJG6aMwCl9KYhh9mMQxp/IManODEKXBxDWk0YxDe - IAEhrvAEDxSiCF6IgQzAoIdaTIMHbNgCLyxRiydqcgouU8RoZ1GKP8TCGy4IwC9c0LM59GERznhhTL0Q - Bz9AQTa/tEwXroACLOSADFWISRWsAAJwEAMdInsPQmNQgB/wIABtev8CE7Io3SGgIQ0XqIUPimAPQijC - EnQYQCYQ4YdWgGIes2CBczSQiO8mohaE8MQs/qYISSSCcMcIxiZMgYtsaEMYcpJEKKDgBXl0IitdCAAh - 8GBmEzTFDDSggiIGkAQvfKEPnSBEKQoRghcIIBYBcAEUzuAFLrCBCH/oRDRsdg1sdMEM0pPNbC6DiCZo - 8zbUqwIXcECBfUhACzFIgAoKkAhC1CAL0BxZDWKwBCxYYQxPqEIVnuCDQoCiFrEQRSpSgQo6IKIZJsbE - L2pRgCdk4B6lgMQ0AKQIvY5CbSvYQyH6lx/F9QIXrFAFKXhRiBM8oBMqyI4X3DAIPeghGxZIrhj/lKkB - RBRiAkXYgUpn4YIumIkXBZhhz3pWh0qAIhTPIPU1Th3b2cikC1SARA2Y4k5NZpELt0mBCJgwBghUtwGE - KIEHxJADNUChD9z4gRJggAIYwKAGNfABN0BRCUy0AhOYaMTX7FELahCiFaKoxSwO0IBkYAJtmcgEJiKR - jFhA4gNQIIEiEvGParQjGaaYBCecEQxgGIMXgcB5G27shR/UoQ56iIYgSoClpzzhCItIXQUE8IMklOEJ - KugGGJBQhjI4AQwvOYMfEkGHWJLaD0GQSUxosoYm1EAJL5FNNrO4yXZWYQ3GZoMTelKBDmhyDWnQASEK - QE3mVGEGQlBCDwhh/whPuMIViBAFmhJBimY8ohSp8EQlquENZBw9M8VYxShEISAu5cHN9JCGKZIRjFOs - whrCAEfUJfEDYKrBjaFYAQ3u0IxskEAKEZuRCxSBiUSswAsce0IMOhEFNGzvCITAPDYwAznYA3BwFWao - g3Qpg01agy5QAhSwgoZ4tc2TEikpOTYYASzwAixQgTWoAn5wAtsYAhwQglHgBSNAthvrpDDQgEMhBFcw - Olown0hwBUVQhVJwhVRoBWngBVgYhU7gBVXIhKebk4oLBULgg0SgB2E4hE04hVMQBlwQBlMqhQE4gjby - ARdYhDSxATtIBGEAhgBogSVIgAIYgD4gBEsghP95OAEjOAIpKIAe6IIxiAkv8DWcMIMWwh1mMIMZmREz - mIIasIKbAI6a2KSTyyIpuTEySAEYGAEl+Dw0QIJZ4DYyyIEMoBQ36AQnEAOIsQ2IUQJAWJaTmIZOkIGf - moVpiAVX0ARTWIRRuJdGkMVWWIRCkARbeIVK8INA4ANvaIdq0IRNmARKCIZeKAboIwVvmAEPQIcCmIEm - 8gZC2INQAAZakIbRSgQ7UQRAGIBWcAVRKIVo8IZdcC4rmBErmIFfWgMkeINowLhS44IGLIkQoJHZuAmZ - 4KYFRAMpWSMJoIIawAI1KAAiCIIQ6AErCANMrK5l8wE2+MSHYasZQAEBqID/PiCAJRiDNZCBSJAGScCE - V0iFRoCLXZiGZsiETRkF0MCEUSgVwxCEfwAGUzgERrgEX8AFVegFaZiHGcCCTOiGDJCAApAEYIiFQrAG - asgDoQMCKNgBKHCB6CmFSEgEs6kEAWgADZgBCNAAK7CCCokDPKAFmKKRJXgXN4DAzbsNm+CkBrqJfXQI - QKgBGFgkKCCEAJACfiCA6BqCHNgANOgCOGgC21iD9iGD53iCEaA5hXoCJyAASyiEQSiFoquFUhiGNuMG - SVAGcQANYAgGYXiFRAgFJawGVTCFTcgvWVgFXOgFtXkAI3CCEeAAboCE6JOGZFiGWRAAUKgAGoCJHsiD - /w+wgD8ohUQYhURwg1wZAzVwgiWoJSW4AgHoA2WIpVmagi+goRhwAs1jwHskg06TCZzwgm6Qh+ciA+MI - gR+4Ag6QB3OEmCrQgjb4gh4YTIiMiKbgHtuIiCpIgysohV14hVZIhmKwhVh4BURgSVKgA0KABGMAhlvo - BVHYBUEgHGnghFvQBE1ghVW4BVwIBl5IBmlIB2WQh3R4hEGQSj5ohmkIBBPAAD8oERoIgADIA0S4AVDI - ulk4gTXILGpig5goAyjIg1kAhVjChitoLd6Zgc2Lx3uUDe+EGJmgAmXAAg1ILCuYgpdQgjGoAQ0QTES8 - lsCciIdZgy/AAogJgzC4sf+tCoFRKDpFCIdrOMlSaARboBNnm79S8IViGIZY+IVfoIdawC/TVAWBksLh - DAV+iEN2AAREKAVC8AOL8YM8KAVF+B5v4AYrg4VQoANlwIRMoIMoGAOurEMvcIIVQJF5IFIzKDYrWIKZ - eFLZuIlNipjbcAIf4IAqQIGY0IJFuo0qaAAfsI0q2KQRYIMsuAD7rB4f0JZg8oAl6IAcKII+GAVP6IQ+ - UMVVeIVMiAVVaIVGCAB+4Ib+FMJXKAQ+ULds0As5G5hPkAVhaIZgMIboSAEDOAAb4IYWkIMvPEJIkEE6 - 6IRHeAVbqIQ/4IZlwYRoOAE1kKYZwCkzIAJ9wQM+sIb/m+HKGJiCgJSpnNAJRRw9NlgCAVACHOACURJW - djq9IRACeVCAZOs7MkACODgC0QuDJkMC3aoBkZEHboiEUWiElTSETLiFWMCEWtgFWBgGb+AHzrSGXAgG - WqiFZsMPR+AE0pSFW7iFU5CFYpAGeEAAD9AHc7CHWRgAGcgDP2iGULABDFAEUggEQlgFZCCF8oEDIuiD - 9ZqGEzgCIiCBX6gAIhgAQgiFOdgDYLiZKViCGSoDNZgBYrMCLqCmhojViBiDGAgBAaiCtaoJ01PEThoC - AtCAvWQnYZUKH+Ck9swBLY2BKvAAGyiFV4AERUAG6XubWPAFVkQHS/gPXZjKa4AG/4RxBmCYhlCghmko - TYKRhWC42oESh3V4h3TIBmEIhqQEN2+wBUKwgBWwBENIhFlIBVrY3gfoGa/Bg0iohRv4g32hgxsYBDjg - gRbQg2XAnRqpkTKwgsRlVQ+oJRgISM9hgxlogALoBgfQJojUghRIgehag+rSAALQgg3IAC0QVjZogh5Q - g/q0ghr4gQvggHuoBDb1BE8YBljQhFFAh0fIBFcYhVbIhGSohWYghUigBeR1BVWIhVgoBWTwU2CAPk1w - UGdQBTAsBWDYBaJUBVvQBUAoBMJwBmIABWVwhVKYhkdwhUywhDzgPyRABUBIAhnoF1zQBF5AnT/AgB+4 - gz+ohf/4hQkKTEvGG4PF3Tmg44cDmIVuSIFLzIFdrYIMWIDsGIPLHYECyIAU2IAmgxgn6IHn4p7FLAAg - CNesgwVRaAVLCFBYiAVgUAVn4AVYdAViiARDqBNYgAUh1IVR6GQlHN5qCKRjxAViiAVeKAZFeIQG04aC - MgIZ+ANrUAVRkARYCAZYoAVXCAZnkIYJcAG6mocPyAM+sIRcAAZQcIVXCIREUMNAkIZYqhEuiMfM+04p - 0ZpnWoQAmIXHYQE0GIFAFoIZGAEhEALYvA4rEAAFcIAUcE+rChMlYAKrcrILSIRIiIRWIAVQPsleKIVW - SAVe9j1NwATfE4WDiIViUAVYcIb/ZJgFP5BQmHSEVQiGVTCFT9gEW5iFeXiAHuApAjCEZcAU6kgGZKAF - XVAGWqAFUsCEZRAQyVOEUZCEMcoEEWY7byCFadgFM/uFQrBmzftOWI3cGagBDygBgDWlAAibIpIAH3CA - DbCxNcqADlCGAqAABsiBIUgBd5qCGEiBfWACJCgBEoiERvC9FD46b/Q9TAiGXFAFTWiFWEgFTaCFRRAF - UciE1AQGZqCGP+CDUAAYSriET8BoQOoFamiB7BiCJ8gBJGkCH+iDAACHZBAEYygFYlAFYOAFzSCBFvAD - QqEFHpaFqvUF4B0FVigGDdGFUIglGNCZbabtTaqSJbAetWkB/xkIgFrgBqPgh1pQAQcYgTXCjtSqBX4Y - BXbohwxwMiqQhxmQALDLBEKIBFE4OmJAOlEYhZqmQXgjhlFg02FI6FlosyAWBgEVBD3gg3+ZBkdwBJrM - hWJwBk1IhgBwAAcQAibgAMQsAxqQBEJABmEQBVpoBVXIPrZLhHmoNkuQhH/2hV6wBWlYBlpYBV/Ym1gI - hmmoZmxwgib4JdpLNTa4AkW4gjYogvKxgd0GgyCoBW/4W0uoJ0RIALWaAV0IBkvwhnWIFRQQAzHIAl6w - hwBQhp5VBKIbhWGY62HwhGUABmD4PlWYa2lT69glhVoABmFQw1bmhUQwCHpoB2C4hJnMUP9bUIViSG4F - YIEYOIAvMEM92JQB9wRB4INZIAVNKIZmkAbrTgRp5mVfWAVVWIZXmBNosIZd6IVnwAUpjKlrqoklnQ0n - uAACcIInIIBHCIUbKAZEiAIv8IFSkAZLKAADOIdhKIQEGIEhaIEBaQZruIRcgAfncANLqIT0ecxB8IRG - 2JCVTIWsiwRnqARY8L09R4VOAIVY5gwB0YWSKtuEEIRAaIc4uwRWiEJfKMoWhnJmSAZh6AVgeA9SiIXV - TIQ/4BtWuAVuP22COQVN8IXT7uVkwAtNUE1ocLdgsOYLkSkdpUDm7BkdrexC+AOTYAExaIBBkYYOwAEH - QAB/QAACSID/HsiEdUiGa6hadSgBMJCvPzAINGuESlgGYgBhdBiFQhBvSNAFQ5AGVagLwjCEZqiFUaAF - 8klGBXACKpADPyCcdtCEvfgEXGj3YXjaQtgFeV8Fc78FVygGTCAGayCFVxCFWCBhYWAFW1i7iHYGTLgF - Db0FZwguYUAGXshoZEgGWyiGmJoRJ6DAHl2CGRBTNpgCfpiBL4CEyQuAIhgGj06GHyhgEeD7DEAAFECH - WbCEYrCGbn8EYMBupJPFmoY6Z5iFTgWGRrDpR6CvaZhrWuCGcP4DYBgFUIgEWJCGCIAADgiDLtADP9X5 - TXCEgjl3UvADSQgAbtCF1xkFHhYGXUKH/2II+IBPhBsggUIoBFKYhU4ohD5vYV0w81tQheIXBG8ABnBY - N7M/vYy8CTVYgowdzO/gACYYgiWoAW7gBnFLUTVsgAUQgQXAgQJ2AGRIgAYwh1IoBldAupW8bkjoYE/A - hFRAYbW+F12ISm8ACG/JSu1SxE0UolKSgCmKNiqUEyY5qni5I+hYLVWbHK3q1UtYgBvc8qjogKTICRKE - LMUitAxYIW6JIM0acIJGkRrd/BAiRUjSH2lCecFyVQsUN26xMnmThk3NmjJsrKhho2bJmDVr2Gj14WQI - GTIpylhR8kVdL2vSLKWjsGFDFSspHETzwICCglncIFUiBMlns1qEBv8t8iQq2ShCw2YhghRp1iBXihSR - ChVNEQkV92K1BMViiBYtXfB4o1YsmMZVwJgFQ0RIkbQHT9KQ6VJHkZ9SjTJlm/cAzqBQoGaFkOIlSh9R - pCpVmpVJGilSiWYREyTITyVXr5A9japVyRIrWtmQYcPmyhQ2aMKCZoIDxz1ouFq4ISQhRQoJGnIg2FWD - AwMbMHAPP7pgkskorvg0GSKKlFJLDywowcIFhBCCCCiQLNKKKLrMokgeByhgTzK1JJOOFWFogYQev/zT - jCmrmOLLNdbEYhAJkIByxBNjPDEFKZAMw0001pAghRvcFOEDILUA8gASOizCkyR9uKLJjYLsQYr/JYTw - MUsikjjTnRfmKQGCeVxtZUUNa6ChHhparDfEBvyccosLUUjCTwpvibABCKTAwIQDOeTAgAMEkBJNAPz4 - EIA0s+QBiSeIADFDGvDFUosloBRSCCmNKDLIMIRI00kt1jzYTARTBaEHNYG0UwwrmnTUSymlkJCEAIT0 - YAUaaHghAyl+/EGLkTwg8oMXT3QRAzqxBOBCC7uQAoogiSyTCSl8SFJJKLS8UgodfPByDVRrXKWGFVhU - sRUaXfhQFRtahBHselqk4E8xvhhQBiCFWLEBfhR0IwEOQxg6xBA4xGBhARzMwI8klvwxkg0h+FBDBwFE - UsoslujyQA+qhALJ/yCGCEcEOtaSIskELqwgyC/L7EJNRo7YYkkhA/SARDezFMKCGFqo6wYkecxizTw2 - wHEEV2l4oYMPBQhAgq72DNPCAIrckkklfyTyhy7SCVIINmN4sS4bbYQXxhpe+DAFaOSRsV4OczKRzzf4 - LECAJFAoPBcBDKuIn8I+JDZNAyN0o8gohdjwBQpUPBAAN4Q0MgwgBRTxxAy6+NDAA4QAkg4QD0TziDQg - j/2HQIfcQs00MRJTiwtNePEDKdJUYEVYM7hQx8XWJBJAEWx4gQQLPvTAjwsyFDJIHqC8w08RRCBCDCKz - /CHJKNwoIohTaqjhRBlbqbdEGW004UOZcb6Jxv8YwJs3hAgivHfFIxcwofAoEICDMJCBCSJIwRC4UINo - jG4JLOBGKVChiAi4KS5K8AE3XDMPommBBRWogQSQIAADjCAGPQCGMB7xB0sARRHtmIYjNnGLWkxDFauI - BQl0YIQAjIIUtfjBGrSgBDjIIA+ECEYijICEI4QgAIWAAxAKQQgbvEAUtJBEKZqRAC/EoQ88EUUmamGs - QiQCG0rAQlTSxIYxKMEMP+hCG8yDhjWQgQtkiOObyCCCAKHBCYqQhxVygAJP5IAJZAjDvbSQBjX0oQRu - GUEfStGHTxXAC4YTAxmaMAUCKEMAJZABInrwgxFwABAcCINVvlCJUiTjEYT/uFg72qGJU+TCF8BoBmqk - YQFuWGIUlrCEPVxghS70oQ96kISRvOAFOJTiFYlgQRcmMAtCYKATrhgFKOAAAySsAQlUgINrQuENDPgh - GthwgprUZ54aEOINV1AjGqrABTXebQbKEEIYkNAHUmDABoqAgIpUxAQ0hCENW+hBDhaQghEUQBQ8EcAR - 8NUGNLQhDW0oAxIeILRhCMAGF4iBPEaQA0RWoQM9KMUjWvKLQNBjFZuQBS5ukQxixKJihEjGK4BhDUI0 - QwVS6AM37DCLbLSgDBUKRiwKgZMBjKISgRBfJkBRghJAgQ1l8MIRdtACbsxCS7pgBlTStxX1gYEQ3GjC - /0TbRh45qsc8ORBCBsKghh7EhBRUwIGc7nVIYfVgCmGwwghwYIUmHAEGRXDCE9iwhAQkYApOSAMTxDCG - I1DBENwARSdAUQEpkFQLTMCCMniBjGKAgh7tUMUhGCGLUxTDFqUQBCFoUYxM8OJB3EDCF+DgBzxYYhou - aEMRFMGK25VAHp/CxDQiUYlEIOMYpeCGC6DQBSRk4QUfwEQpgvIUNa21DUfIQx76sIU4qrGt5TFPGPDz - hDKEYBBALQETmKCiOJFBDGYQwAys8AM1ILKgYrAC/L5QgG16oAc1SIFnxeCFAsABFH1ABCBqoIQyPCFY - WqhBMkAxjF8cwxqpcAQjLv9BS1yUYh6/mIUzVLEMUnDjAsP0whT0kIxpJCENZhgGLTrxgCt0IhGIwIQN - k0EEfhDiF8EARiJIgIdH+OEGpWDFMmqBjRaoYQxc2EobtlAAM1BFCWpoA3mDBSc1aoEMZcgCBH3QhUAa - Mlj3IuYWxJCDBlhBvha+1xXUrEkjEKEQHEhDQasAgzLAIBK1+MADJDHVuRVBHsmwxC/acQxTUGITm+BE - MHAhC174pBKZCEYxptGCQIohDU+YQzNCAbUnhEAGTvACFvKQiOduJwIj6AIqLOGNRSjDEqWIBhwgWIpR - 2OIaAzADWbAwhiv0AY5xLEuaxNzWN7GBC0tQQg1qEID/WUihovG9V7B2VwM2hGGgEikoZBXZACKwAFS7 - mIANsIBJNHgABUxgwS5swQ06cOMNfggADGoggNxEIxDL0IQpEr4JVtxCFoQohChiAQtiSEMSF9CCwuaJ - 6nl04U01+IF5rACIPlTAG7OggwqGgIQIZCIULiiBo6DQgRAA4hGCQMY16hCC8XihB18YTxnYOYX2sSEN - FDWP0a0NAiFU4QluAIQayhxfOVF0C5JoQtHslYMRABrQcprBAAKQhwGQgt8zYEIa2EAAGLTBB8nIxKd4 - AgQk0AYJK+AJPSy9Clbg4hSm4Lsl8nA2XhhkHi6OSxgq0gwSdDwMM1CqGpBAhA/A/6ETHyhECSbmKVLM - AwlW8LwVZgCEQSQiGtuwDRjahh7zzLMN7foCFsAs7TfFEcwDXUMPAIGEu8nXAVqwbx+ywIYhxBc/aRCD - hdGQBi4U4Chjh8MXhJCDIYTBByUIQg2KMMlCzEISK6gwRcHwB2okwxmr0ASoccFwVQzABcEGgjx0UYgf - zIAMVYhXHpphAvWA+QoCGAAQKIJZEUIEFIAN/Eb2LBcJyIAPmEQL+EExCAU2rIEZSEIWdMHPcVfbxBEW - cEFardW0DcEatIEXyIM8eEFoTMQaSA03PEAbhAGd7AMmcB0ikYGcaAEXNIEAeIMPzEDRSV8aIEEncEMB - wJE+yf8AFPRANOjAvayBHPxCLZiCK1iDahCDLfTCKjgDCbhABZSAF4zB+xDCD5RBnJhBKDTDCRQdF8Te - EfSBPKBCAbwBdPWAH9RCEHiBC4yCKvxCInzAB8jajAlCM1xD+5iB2CFBG6hTmlzUEpgHHqlRGoAFGkhB - IRTAE9xNFVRBGtjGuNVLBowAOJhDQSGS0a3HenTBFPTAFRzB+fwAGAiAMhQBf4WBGDRABTjBERRAHvgA - FkCBHnhDFCLcKqxCM4ADLvRCUkWDDZRAESZWCRRCADTAGsRBISTDCdwNWbyJsxiHD7gBDfiBKCRCC3QB - FPjBKtyOIPhEMaiCWmTCNkBFzxH/AhiUifqQV9vUT9qNGbXBjdvMQgGMwAhk4hggQQ/Aj9GFgRDcgzUg - AKANgfLhy92A2QzUQAH4gA/IQw+EgBKIwRN4VhgEwSPYwxNUwQ8kwgpMwEUAwyaoAivIwiasQjIIg6oU - AijYgDKUgqutwRg4Qc21gAxIgjDYgBrcTR6hUhyxAAsQASEowyx4wxfsQB5UQi1I0TTMgjGYCC2Awzuy - QRYEQRQEgBt4gT2qketZQSLKCf/p1RqgADCcARlMBBpcgR8EAZyIRT4wgzngTbC0gUM6AT8AARV0gUXR - kRaAIQwAS7lJARRwQzCEAgtkwAz8QB7sQShUAytQgiwIQy+w/8JLAoPrEMIEzEAHxMAUNAAWqMEF+MQe - lINmaQAd2ZFOksEabIEN+JsrOAcwAEEScMMqWAIkwMKn0IIzNANPvaMhdgEbyEsebAFywlPbYAWYOWK9 - mGIREMIRpMEadAEVFEIWlEkOkEEa+MMzOAOmyM96oFINtMQrFEAZdJ3yeYAPjEGcWIEueEMe7MIskABA - FgE3hMIvxMIhmIIsBIMwJEMxmIIteI8UeYYmkoEVLIEKXEEIeBE40MEOVAHTmVlYcIEhqgIi0MEiDMAA - cAMcSAERVMIyCAIv8MEehMwshEIyXAOboJN5rEEW+EEngIGzTRSYkcESuImbtE1YtE0WnP9gF/yAF7FA - RcVJGozANwADFqRBKeILGqgBIIzCKCCEEgAaG5TaRJaiEiRVBJRCMdRCAYgBEtyBJCxDgJ4CK/QCMPzC - OiSDK+wC933MADhBE8hnRa2BFYBBIQDDPLgAVwgBB1iBVHABFHSCJgQADSRBor0BEnCBbSzXLMQCNZQC - L0hDNMRoD8TAeHAFG5hBH+RBBQRBF4wgj47BErTBHQ1p28hNABhBHRTCz0wUGlAfB5iDMBhAHSFSsBid - GGBBCCBCH3glFqjAVCjBGqhADahBFTieIthDB6ACLxTDbbHAHlDDKhxCpjFcMSSDPbiDL7yCJAgAHABC - CawBFlwiUbb/gRkkAjBAAjf4gBIgwRgMAQeggBp0gRtUAihIwRLIgw8oa9vEgSUMgB7EFi1MQyyQQjZc - Q5toBbVlpwAAARRkgShdgRlUhes5QUVdVSKqQRYITRAgwRa4gatqgaEaADgwAwG0DcOIWbAuWxGwQIq0 - QR/oaABEACIUQQcQlBUcVhgYgCTwAigkARAExSaYAjNcQzDcgjAUA/mtQve4QBkIpvKFQRUQJRrMgVD8 - Qc9QQcBdWwHMwBr4gF5owGCdJheYBBTMAqL5AR9YQi2gAyZswzWkKlTMk7qAgQ0UwKtJQQsAAQBOQRCA - QQ9QwRVcwRdMwRd8Ux9EAZjJzRXYkQKg/0MyWIM/oF1/4UsppsESWKQmtoESCID0+IElFMESTF8hhUEO - OAAcmIoF6IE0UMMmFEM5ZIM6MAMzbEoz2AIi/MEPIAEBhUVo4AsXzEEyJEIJOAEcPIAXPCgVXIABFEEF - 0MEE2IPaXNURdMIWQAEhrMAPKIMMMBMpiILedkEXmIGEzRE7/UANTAEKJAAikGgFLKMN/IFZDcAUbMER - 6AAcoAL7WsEYqAAc8FcK7IMz9MNfSV+9GB1tEGUaWEG0NuEkTdI8VoGyEVScjAAzWcwsJAMwAAMuAMM0 - 6EM8WIONCIMAggIoFEGwkAH15ZHU3EEzzMMRVEEXCAARiGUTdAEW/P8AJCjCi/LDESwJEBRBF9AAIcwd - jxyAK0kDC/dBN4BBDTRi2k7BVlyVGjSBE7QL+3TBFQSBKq5ZL85CDZRB+oAZFRQBnTBAP+RAG2jAIpTB - 3RRUsAZLqYVuGyBBCZQVIqKBu4CbGMzASZFCJDRDMphCMchCmfIDA+yDNRRDLGACKQABHGDeDKDBBjik - etgYKNRCC4xkGswAIKSeGswRjClCc4wyN/yCEmGBDVjCCkzvGCRABdguM1iDGbCv+nTBHZJXj6pqHMnm - VIxB7R0BIJjBkrZNGfQAB4hABkSrwlTYlN6LHk+pBKPBF7iAQcYTPnEBIqUADPgBJESDNKhCMDj/Ayfk - AjAMgAeIgDkAAyyMgjQkQQdIxxUYHVGGRhzQUBKgARfc3xF4EpxwgRckQQtgECYk7I5hbylMALTCpxHg - wTpYA7qwrxdsBceOlXnI01hSxZtgwQYGwQ8k4nl53A8YSnr9D0UFKy1SKaA9JKBFcyLUwAsSEApoIhqI - wQggQR0kQiiQwiH0wjQ8gikkQzRAQRgowDuUwjAUggusQQxYQgvU5d2wAfPSgRRwQTyFhQp0QhF4ARcw - ABZEgRR0ARDEAiioQBZYjR9UBgt4wQUMgBzsQYxmg/lUgVTIC1TUKBmMQexZFEURsxWYJRIsyw4EQfuI - 2RVwwxHgqnoQkPJJ/ykfby24Bas+ucLcKUEBIMESLIG9QNYRBMAveIMwUMIqiAM1KIItTAMcgA4gYAcd - hMIFHEEN1EIJiIFlb2IdZMMKkNsYTARZNEGOKoECAEIpAIIUYJs8NAAZSN4sPEQhhMAApCgfZAMzkIP5 - BPYPXEEcjUd5vMv8pF1FgZlfGwEgAMFcRidFrcEUqOxESbC9BKuUdp3X5rcZVMIrcEMFhMAjXEEZfEEp - hoER+MEvJMMmUMIpWAM/TACxSUIL/MAr9IWHsMAc9UAi6IDRHawkTEMc0EbXagF5eAEIAIMMWMFJRUMD - 5IAXdAEKLAGMPcIyfEARgAIvyFQisDA5UMVWyP+L+mgFkRd00eHRHH14E0CCEcSBALgByIpZHAXBeGH2 - QYaule+x8rUBGERCIeRBAUhBE6hBBd8LmupBIjC4I/BdMkDAGADBp3kDU1mCHsxCJ3QymgJCJ0RBGsDA - GchBMnTeh9vg/HRBDfSAEyABFBgBOijBu1zUGjQBi0XBEZSk3RLD05LDlVlFCCCnOoF0FbTNQ4JuG1wB - IZTAFpTJl4UyRcmL1oKunKgBCrSnlk/pFwjAGZG5GJSaFTwWV5NPg8sQMLxDBoigDGRCJhACHLjBAJTC - jsiJGDjBLADCEViBEeSfDLiqDVabSd+REIKCDnQBGQiBFTwBFsDAUIqvDHj/QQ0kQDpIAx9IQzGQwziY - T6lTQY2C9HjYkRzFkdG1gRrIgxGEAKouaX4HqxlQQUV9eNpFex+oAfLVNPIFqxNsqW8TVKApAxScwLFE - 4UcEQzbEwwbEFxIEgCZwAw2wgVBbQgyUYhsQgSKEwg4wL421AdUNNgdcGQYKACl4QycYwXqsAQTMixeE - gCWwQBGsQzOoxR64wzXQe/10QQjQy1gRuVaEheyR+hXUwA70gSXIgKqOWXr7gBl089GpACLAkQd3s9Ed - ppTetxhEhQ/QwR5gginASC9oQywIwzvs0QhEdiSAAhIoHwvkQQh0ZNGZwcPpgYyBAlqFBUEHURVkQQAc - /4EUEMBK8IO466QPRoE/PkEMAMOR/cIfAMM1jIM4VIEZgIF4i+qQT4V4gGeS86gZkHU5KkIhdJvyFV0p - ioG8FN1lv8kXEAIK7DSWE7QS7LSbiYFZlIAfSMM7N4MNlTAwuMM6oIPQ2ACoJAHy5aBnMIGzuIAf6AIh - gMI0fMCL1+VWkEERPEDsdUE3hAIUdC0dkQEW+AAhfE4NDAAtuILYOANAZBsnTg0YH13YrGGTcE1DNmXK - sKmChg2ZhWjQoOhWxguQUrbOtGGTZuRFLWyuXGmDxmIbNU1CzDqShiYammw81JiRJoxNNGHCkEHy5k8z - SsGELftUq1msXsCWGZiBxf+IJRtltKBZg8rejCs9/BDSE2DZsSRcOOSw2aaJDx8PwDRZ6IFWCS9rtJBp - Q8NSIShrLjxIB8gPKWbkBirJc2WhQoaPF1Zhg6YKGZtdAJlxWeBECBVjVqbhIqTNSjFqejhJY3NMDScx - ABWA0WY1zzRH/HQBGiZrzzQ0BCXTdOrar0SssmFYZslevgVDmCDpU8tIGjJhCCSiY2kAjRB6/gCjg2T1 - CCtgHgAqJI8QoR9e1HhB0QlJm6xl4Fia8Jafgn0H8NjFGsTEAeMNLyBzSCE1sGgjh4QWamONOqYozYsl - 4FtjiTVKI4OM1TBq44waaEtDiRrU0ACLNZRAoQwQ25j/YhYpQOypjS9swEMVSjjpRRt78sjklgEOsOSe - DfBJYQgygvCDGzNWm4KQRCTBAIkr9CCkFmlaoK2NC2Lh5oy7nvhiFh8S6qKPHxTqgohBImiiiGhqcMCB - OOgghhxyBJIjCwgBXQOLLlxasTKG2sjCEitKY6O00sbY8NHS0ihtjSC6WE2NBFDA4qYCetBBQjD6IEWG - JjBCQ4s0iOBjFkpWwQWXbOApQRJNpKEBkQJyYEJJiszooQLdSiBkFEkkecEMPbKhY5ZOjrDJiEda8KKN - I2IAYpACrFDIiVmM8IKHUjqRYgwrEHCAgirmCKUYxAbiJg4IFdLqWjfAUIkNIdSQ/3CNJAqhIkKKFlKj - C1KPGEMNhdvgwlEz3HC0Q+toyiIWQGSgwYbCBgDjidrK+EAQVYIRp5dTeoEngwl2uWWCCzpxwteeuGiD - CEKAmKGOXSzhxRI98OBmGgssmIUEHXRQpgIPhmAhHUIUiYUIIThAwgtUAjBhkFlYQKMLCRgIO4o3FBkw - G3LEsWELkRZqmw0z/KgDITasAM0LIrgRgAdCuVhDjSWscKKOAAppQg01rFADDSsYP4ObJkpL1aY0WCgl - kl0GiMCPR4xow7c1TPCjlGCasUcdWazJBwcdBnBEmhJ6qIEJJrQACokA7iAkAh94ISYTYpThoxlBEilk - Ozq4Kf+GhC6q6KaUf14p5UA0OFDhBUIemYWGh8pgwAF8GGABj2W2gVccN8xwiGCXYDAjCC8wqqIhN0qp - hBtQGlyjjIZKM+N+OMoQOUc1pgk2OIITuDC51bABDISohCX01oNM2QR0v3DEKoohDn+4QxjCgEcKmPCC - 0ZngHsuAQK9sIh0eBKEQESjFKjJhiSk14xftIcQsSrGLTCTDBV4gwC7ygAlgzIMFXnBCBeiQCWCcwAtk - qIIVGLAAc3QgDnoYEIHC0S2HuE1iTkDIGqxQhi5wIxZ0cBKhLDIwJWTBDFOIAYdGQhGaxAgMXdgf40Kz - Bh8QAQ4FGAH8LOMFE/zBEZwARjD/1tGBfbAjGODgAA6sQIJVTGMChehBDoZgBSw0qQVE8AMJClEMYkjD - GzQsxA+gMIMLKIMUlkjGBNSAhCz0oRSlSAQGgICB9rgyAl6wQhVyEEUKsMAOidjGQMQhjmrcZQ1eiEhj - GuM3NThBCWswAyHc4IYzQEEJXCwYh9pgBSWshCJsS0MX6uAFklgBBliI4wVYcIExeGAiaPACBn6xiUNY - gxqZsMYBcDCCWFijAUNIAQ8iYQo6dMINToyJHwYhiTq4IA+CsEQikJGIZoCiWk8QwxBqMItazKIQD/CC - F+ZACF7wghC1JMUHeFCHRLxgDcBcAAPIYIY9SCMbyQxHONrR/4WTNoSoHFFCE7qghoZYIQqdqAF8oNk2 - trmtDViwglSlSgUqrCQMbFDDDDCEty+0gQwjeEIULEAIfcqCGvMY3QRyUAV+MIMf+RhBF0jgiGV4AxBI - eEIQBnFDIkhBCn2QBDfykIhlRIMOEXiAD3QyBCMMIiyzEEABAuAHYqhiF9KwZbXeYAlBfAAJKcCHP7zg - gj1YYyA/bccxknoXZyokcU5g5v6K0INuWCshWgkgoCCzEMCJhCQsaYMXgqCQnqBhDE4oQiFq4U6KuOAG - paAEK07BDGnwYxa44MYYxmAAYEwjAVoYwgsMYYoalsBrRahDIZJQBETkoRB6uMMfjOGN6v8OghrTEMAT - 9PiIw3YiGbGAhCpmoYtalOIRJ6DBH2JRjLY6wXtS0AMotuHTY7SDHkk9XHycUIb4KKgMSehEN5DABi5w - AQtLKAMXwPvMNThsDVppyBLU4M00ZKEJxUWDGLxQh0jkKg1eOAEfrJsLpDCjHPrghiZAcQQyPKEbwajF - BTLwhA+sYh0kgIMXqtCGGHCjBCpQAhHAMIs/SCOjhChEIUgRilrQQAxI6EGykLCFCZSCFn/QBSxWsQwS - YEARrgCGM5ZBh7vSYA/LQFs4qtGOQNAjDmowwxac6WGHQAQKgCjFX/S3BoUtZMUyJipRvaqCernNClfR - ihaqQIM8RGL/GidIAgb8YItg5CIWybCGNeLBgBJgIhkskAwMhAGMaORADDrogTO8UQgjoKENS3gfRjjS - wHIUAnvzCEUnQsE1jByBFDYoQg4uEAlYlEISs6AFKOggCVcUAxwC8obV5PCHcogD0hymBz2YaAYPHy4L - W0DcvwphifedWpoDdJtjtki3blIkjWyoAxxyrIUSPKIUU+JDIBQxCVyoQhjTkEQyshEPCsyAG6voSho6 - UIpm8EMCHvDCBKyRjEjYAH5reMASQFTkmxVjS9woRCikEQIEaWEGYEjGAGbgBEQ84qIkaAEPJvCIaQCj - FJagxgHUEAU8SGMckebwpAMhgDN40WBC/wUDKGyQhSRwgxADcEIz8d7M9CWoYCe9wlXZsIQlRMZhbTDD - NKAgoR+0RxCFSEQxKCEMaqzCGhNogDLWkY8MpOADrshGByhXCGtsFxEVmEABgJGIWiS+DF5M1Ui8AAaZ - R0MQ0ljGk8jKBSt0oQe1aEEVCJAMS0TjBDxwwyPcYIQKgMISobDtC/bgDrNPmh6TrsADlLCwpJpBBoXI - wwm4IQ8enEENHBmqGnQABjMwBOJvC8IcBiAFojbBCQvJgQTIsAYwAMGOLQgLIVzBFByhF0DBAjKhF06A - CSCAFNhhBMLABUpBFSZACoKAEGJBGB4BEBogPrrhacCADbSACSojVTsqxQtkgBaIQYYEgAbaYH+eYAye - oAkAQRpcQDp4ARgegRtm4QWkoAsewB4KgRuSQAqKSRyq79+QkB4CAgA7 - + R0lGODlhkgB3APcAAP///zk5OUJCQjkxMXNaWlpCQoxaWoQ5OaVrY4RSSqVjWueUhNaEc5RaSs6Ea3NC + Ma1jSmMxIbVzWloxId6Ma0o5MTkYCIRSOUIhENaMY6VrSu+ca8Z7Uq1jObVzSlIpEIRrWlpCMe+lc86E + UkIpGIxSKVopCGsxCIRjSu+cWpxjOWM5GK1jKXtCGIxKGIRCEJRrSpRjOWtCIcZ7OaVaGHNaQko5KSEY + EPelWueUSr1rIcZrGJxSEFJKQmtSOWNKMVpCKXNSMb2ESu+cSnNKIZxjKZRaIb1zKc57Ka1jGKVzObV7 + OfelSq1zMb17MeeUOa1rIcZzGNZ7GIRjOXtaMeecQs6MOZRrMb2EOYxjKe+lQpxrKeecOdaMKeeUKYxr + OXtaKfetQv+1Qt6cOe+lOeecMbV7IZRrKfetOf+1Od6cMe+lMfetMf+1MVpKKUo5GEpCMZRrEFJKEFpS + ECEhGEpKMUJKCEJKGCk5EDE5KSE5GBgxEBAhEEJSSilCORgxKUJKSggQEBAhISlaYylKUilCSkJaY1LG + 90JSWiExOTlaa0paY0qt51Jre1Kt5yFKYzlSY0JjeyE5Skql50qt7zlacylKY0Kc3kpzlDlrlEKEvUqc + 3kKU1jlCSkpjezmM1ikxOSEpMUJac0JjhDFKYzFSc0qMzjmEzlJaY1KEvTlrpTlztTl7xlJznEpzpTla + hEJrnDFajDFzxjFCWjlScyE5WjljnDFrvSljtSlrxjlKYzFShDFKcyFSpSFatRghMSlKhDFapSFKlEJS + czlShDFSlDFKhAgQITlKcyE5czlCWjFCcxg5lCExYzlKjBAxpRAxrTE5WiEpShghShAYOQgQMSExhBAh + hAgYlBAYawgQYwgQezk5QlJSYyEhKUJCjDk5ewgIOQgIUggIYwgIazEpe1JKe0I5c0pCazkxWjkpczEh + Y1JCcwgAGEIpa0oxY1o5a2tCe0pCSiEYIQgACJRSjEoxQnNKY6VrjJRSc4xKY61re3NCSqVrc6VjawAA + ACwAAAAAkgB3AAAI/wCPUcvW69MkRpdOCatFLdC8WRhMWDjxgkQFF0ky0uDh4kSeWnz4/CJlidq0aeGq + Cbt06dMnSr6ukdNWLOY1a9vUwbPmK5s+CSPilfOQIoeCR8D8JAJV5IiOHUlexCkzg4OBBCO8aHnihc0T + NmDDejEjqVizFWvWeJHSwo+qab2SYeARwk+tdv/y0vtHTxi1vIAB79VbzRKrSwhxMatFxwKGEzwyRoni + Y0kSH1CkSOnihbPmLIX84OE2LVQgPokSHavW61oza7k+YdOWTdatW8KYXdvmLp6zePr83TPGrsqCFAYe + PUrWLBSJAKD++PEzjceMGQg8gH3SZk0XK2zSqv8FC+aRpUcuvB4RUEpSqWaWLHHjscLPr7+D957ky3dv + fv/TaEIJLrUkQsIKLkCBhBReNOhgF0iE4ESDZXTWoBpqVLEFIQO4QEURNLjwwgp6CDLPL8cE0k4zp/RS + 0Cm44NILLrcks44/FPSjDjm98MNABimwkxQvuyQSQgxFBFBKLXlwI4AAD5TRRlhrjFFGeFWsEZ4XVxix + AjArNNjHI534UYwwGCDRRB15/BFINMf0N1gtcebXH3//TGNJIhaY8EIUXYyRQw6CquFgZz8EceihapTR + RQ5UcEMDGw46oYMUNMyBx4kpJkPJJqx8csotpzhyim7p6MNPNrcAo88CDBj/8I4vwDQzACgRrPGEAYi4 + IAULuijDzQM6PPGVsZSm9URaXXkRRylAIOGFAVQc0QIvyfCwVgR/EEIIKNLgxR898yQTyJ149nfMHzfw + 8N0MagQ6hhVWzIuhF030gEWjDXJRRpVWdNGFFDoAMUAUT1ToAQwOYqqpN95M08xKlFAyCSef3NLLOOKI + k8wtteRTjzvZxGgLKB2w4MMMWjhx5RMzLCGFEZKAIkMXU4ZXxrK6iscGC8CkJwUSLMxQRhAyQOFCHoTE + EskfqE1DDz3n5iXNL3pNLSdgz1VgRBdqWFHF2DlUUUajVTjhgxNqVchFFVz5e0YFAXAzgCQhWFmhrl4w + /+tFFHPQ8Ys37YQTzCeXVHwKK8KsEowswYjzzjqwCSNMMOlQMEQZOYzgwRNacGAFGmwgUQghtUzQFc9a + 6JpD32qxUMoJD/RBSA9sr6EDIKXYgswPYPjghzTNiBPI1HsFAk6cgo079QAT3ApEB2dbkUO9ZhvqAxV9 + l1GFlV78W0YZR/jxRyneTFBLEQnDneUTZISv1hzU/JKINMckk401lFwSzC2mYAQjrGENcVxDIdsQxi2k + oY8MPGFsIBiB6JZFhjU0AQo+mIYRwoMGY+XgCWOYwVe8IINIJIIUtQACg9TyA1tYwgZJcFAS7qALa4Qj + RVRrx36Qd6fByKMbdRhAIv+4UQIkPCEFVvDeGNZggAKoIS3eW9b4uMCVKNQhPgE4QhAGwAKxJWwNVuAK + s8DghxPgIRGWwB89gDGJU5yCEoy4jTCsMarLCaMXwAiAP1KQAgZIwAES6GAH16AFLSChD9KAwhMgBDsZ + umEQsUhEIbzBAi2VAQylIOIS/5UWM+AhGtsQRzvaQbVj1CJ5gzlef8zAggbUIBqJIIQNSjACPuYAQj0I + 5Bp2Nr4p/ssLIQhiKSLgBSREQwY7e0K8RMisQxrhbyu4gSQsIZDEtYQVt4gRLjJWjGI4Yx3LsEQB8iGB + cnKADEMgw1a8spUokMIGO+hBDcCyli3UgRCACIAl9BD/vQcgAQsPAIQlXLCGD5KBC32Tgh0CUQ5yiOMY + pKRHM5rxn+YFDwtI0AAB+lAKS1RAAVUoWw2UoLPx7XJ8DVKLE7qQhEU0wQtP6EAhXKCFMdj0gVxBQh3g + kFIv6EAOdOCFJWohDFMEgxWcuEUuEjKJTzAjG/l4xzKyUYtslMMHutIC3NAQBq8sqwa1MMKEvMCCIBRi + FkFggRSyQIgkGOERtfhBA5CQgFJEYQ1DqAIXyBAeGvyBGPoTxw1JeQxwHM8/yDuXH3ogBUOVQW2xkA8N + pFCEC/xyDRXsGxk4ucuUcsYLZHhCDaQxg11qNUtk8EAhiiCetHSBB3iQxDJ+UY1q/3Cif5fgxCUOwYhe + WCMf+khGMK7BClukqWxP6OBW1MmGIljiAzsogg860Y0rMKhBNQBEFPjBiwlgQVcw0AXC1MCFsmE2DpZw + BiHWwbFqQLQdtZjGPw6LJ0HMghtBAFujuuCEBnSDQwGAQt/Cg9n4VWmEV1pDFfiqlkX2IARlSMGyvrIG + JLihCwkLLfzKEAU7hIIXhKBHMJJ6i9syYhPDXUcBssGKU9iiFNOYwBMGlYOtVGErXnDBI0DhrUQIuG+k + 80EhuMGCLxwhimRYgi6gADd/fREJcviDN6hxDcG24xj0yB9eksefagBhC1M4wqG8N4MSDKISASjCZ8NT + wWSp5f/N8NOssY7AjQ3+a1leMIIPvBJaMtTYWEbwAx9IwQtq3KIY08DFJg5hCoUkw4CX0BhzKgA3Gmvh + OpUdgCVIEQIo2KMIOatQCIoBCCRsR6sVRgQQQMsFLXCBC2qJQh8EvQ6HVmOUEpWa1gYzjySwQQ1jcJBa + blwEOIABEJIIABWc8EQthCdZlAoPQilVyIKCgRs6IDCl6tAAPpMhpN9+AhHgANtEZKIZwKBGMQKIC1ko + RBinCIYqTmGNaYhDHzMYwQdncIFZJOMRQPBDCLoSA1OTga8RisQEylDBKkHgSgYgRCVbDTe+JmEQc7BD + IkJ5a4hWIxnIC3kgJiS68FHIC0f/mAULiumDmskTBXNtVmuz+m3vdWGuP6gATLXghTMUAgloQMPBh5CD + IYygCoC4QOlIVApp0GMawTiEqC4hC0rcwhrCwCYzhJGNCPCDHz3gxSwI0AAPJGEWJWBDGYQ+7OucQREV + kAIZUrAVepWOGBVAQl71qgUp9KATSTDDDdwxjnCE48rtqDfVdv0PLFTobJCvUBCcUVrvqWARAXBBE7oB + iBqMVTxqGNTY4FaGMJouPWjwQh184IWVku7gKRjCDKJRhDAk7AV02IUl/kENTbAkjrLoBdevQapc9MIX + vhBGMvhxBC15IQuziMIgd0mAz7HhCoooRLYPrqWaskHJFeiA/5aegIQelIIGDZLDL0Jp+JRMQxhbvpMV + 1tCos8mvCX4ogVrajIQKdMIISBADtcANgPAFC9IgT5BXE6YWV4AERcANUMAGNEAIS9AGVPADCBhSndMD + SFBxakADe0Bo4uAMweBGj5MLisEMvXAJmoALvsAMpAUzVtAGOoBWBDYEHDACEqAGYEEFflAI/MA6HQQ3 + bKACpUAIIUAEQTAIpMBaahEHeNBQHdN+wKBr5zI1XdBZasBsahF2NeAFaNAFL3UEbmAE3RACNkAIoZAO + DdADcFABRFACLGBqbLAVY3ABPmAEdRAAL1AHU+AVgSYDP6AEYsAAQ+AEPTAG8FM2ZWAEev8wCrswDdaQ + DMBgCi0Rb7KQC7nACqwQDNYgDfxgAEhSArPQB05wh1hQFFqiK2zAD27gBlgFP1riVWiwBt2gC92ACItQ + AzrQN80iB9JQQIJleNkADDx0LmzjKD6ACEhgQT7gAVYAWl3gA28wAEUwBl1QAaXgCaEQJmAgCYRQCZYQ + DZ3wATTQBUPAFU4gD3+gCKEACjrQBvZECokgA03gARDgBEAACgJmLGGwFhPgB5UQC/TQDsBgKpeAYrKA + CyjIDNYADOdgCc2gDITADVQwAxKQAUCxBkJXi5TSA1BwBgNgalrikT1jBSJkKFDEV10RB3wghVMYDsxQ + DSH3D0/kHaj/IABm0AVfAB7aBgWFIAAsYCxdQAWLEAnc8AIvQAiNMAqqoAq2EE6dpwRbUARpWAiiAAqz + 5AM+UAegMAUwUABXMwukAAoBUAAJUAMXIA+gUAiJMAyWUA3TYAq3wAqUoFu3MFzMgQASAAEaoAJYoIhW + oAAZ8EGYJXRgwQKzcARI0AlQ0B0cWUHhxlUcpGDz1yxdYAe6cA3Z0DEdUw7AEAiHRQ+cYQZmEAd1IAUw + wDYGRilTsAVSUAP04mdQ0AOv8AfcIAqYMAu1IA4SEyPJUAukMAuIcEKzQAgkgARhEIZfUAZDEAN+EAmD + EAAPUAIR4A2EYAuqUAy7QAu/8AuZIBB5/xkMk3AIl7AQ2vANGSACTDAEQ8AEscIBQ6AF6ISYOOYDBbAG + UtAHMsAGQyB0fFWYXYEEl4Usz+YsoNBQ5DAOnakNwUANIXcGXrAFcMANQKADE7IGrQZF4NEG3ZECaXF9 + i9AH7hgJkQAK8jALnQAI6NANVBADVBACiDAKsUAKhfABpuYFaTAGI9ACkfAKfEACB1ADPVAIuxALu5AM + klAIihANurAL/1ALpxB8kzAJveCQ2bAPDnAP7AAPEsABVUB06nRwQRd0VtAJoIYEiKAMIxAGZEA6bIAG + MEAFPAAHSNAF8uADJtUVlBIHfwAKMkEO2eBQwGANi0cPcOADDTAHff8gAHXAGfvHfdrGBgsWFjTADXCQ + B4kQYGpwAaHwA0hgKF7QBlLgBp2gDKMwCrMwADIABC1ABGh4nKHQCbPQDQkgAKCAFMBACpIQCoXQLfI1 + EMLwCZzgiQ4pDenADMVwDg3QnoU0nx1JOmmwBAIwA6lXAPJQmAAKFvnyB3kgBU3gC52ABNx3JV1QB7PA + UNtADuzKoMGAZaLpBFYwBYUACiswBZzBWQcHFqsYFmzQBkiACjQQAvIQAGqlAgJwD3wKFucaQ0VAq96Q + CLGgC4RQCqQgDd5QBNeBBBdwK4OwC7xADEvyC0phC1hTDa/BCqbgW8HADKtgDM3ADhLQAFaQTgf/R6Zv + 2gY+ME+u2QNesJxxGrRQ0Afz0QVgkAQFNn8sVAh8UAsyMagcYxa4loUTWgN18AUUYlJpIakElhYzgARI + UAI1EAXFJgAtEKoDphZBwA1NgAX80AmKAAmgEAtnlQmFUAgBEAI1IF2gIAAEUADKYAnf8gNF6pYESQ3B + sAyaoAmr4BL0lg3XAA/6IA9OgAZDsAZhkAN8RTpqIA/M1AYq0AdgWEFBh1nPRwh5cARt0AVl0Do64wU+ + EAB2MA84sa4cIwy2MEqBQLXecQRXUANNwIMhGh7p5K//ugRTMAV9UAAo8AVAoAjKQARf0ABKoAExEAKD + 0ANfoAEz4AFUgAh0/xABLEAE3DAPihAJpAAIpOAtE+AE+FgL76ACI5ABD9AJoTALpfAPzQBAq3AN89ay + 2ZAN7oAOCCACNzafN8aRbbAErJcG3OEBBMCnm8sGZNAGVxACJcA9MzAGXbsGSdAHd0AEeKAO27CuDpUN + b9EOu4tQahC83nEFQVACXaBtNeavaqAEjvUFZrAEM9ABcCAAhTAAwUsvOyUFbYByUeACAUAKJDADXlAC + 3sAN8vABP2APhPAFU8CV8tAMF+ABI6AC3RAKkJAIryAN/wAMc8QKjPAJ2uki+qMO+CACfHRj7MQGBXAF + bSB0WmAGoqtMpAOgXvAFrFcGSwCpmIVQ2OsrwP+IDdsAteIQDM0wSp+1wz11BIAgAGJmvJsLwVWABlWg + AVxAL11cAyXgA0FgamqACCzQBkczC7gaH9JQCyzgBBdBBPYABLP0r54DAvegCz3QA6FACInwB6IQCplA + StbACYfAWy7RaLggDNfADwtAAZ1sBUD3BJbcBWlAOm2gBH3ABlaABWDBzVVgBdDYBjAgAyHwADO8bW1V + Bi5Zuws6gsHgXobSwiqZUlZQBPJwBV0xi2HhBFgwJWugBFpSA6TwNQzjA3UmA3XQFU1QADJwOvJABIrA + Cy1gx0BAAAnQCT0wA2WjBUyQAwywD/zQNJBACqVQCJVACLsQCPzjCIfgCJ//4G6rsArFmg0JYACoYAQt + QAVpwAY/sGdl2s0+O851+G2zWGNRoAjBUAs8UEQlRAjyegUjvBvtmg2rMA3tkIVdsARv1lps0AVTYGwL + qyXMBhYLPIMqEAuesANKUAUe0AdwQAhAgDNXgLVO0AROTAXPFQU1oAyfI7bWkwJhGgawAge8WgqxEAu8 + UAmFQAsmISDLzAic0CLkYA3B8Myg0CTzYARt4AQCoM2bi86xGLQHNzr7SgYdsAjEEAAXUANXoNiTQilz + kAiMzK7ZMA6qkAzVwBlcOHMhOqHyAAZdIZkoAHQCUwbVkgQ2UAQxQFJpQQSEYAnGLdrZVotaUAY+wMR9 + /xsF3P0FmSsC/QADTzAC91AJgvAIkWCxpZAMyMANr3A806AKmyDTh9AinAkM3ZQIeyAJJCAFMnABefym + YJHFcRp0ecwEN/ttZNAALJAER6DNUoAIAyAFadEGZjAP5YDV7FoMwBAOYPN5ws2nXpC8zciRMGCAPjAA + J1DX8qBqX7AsaLCfcEAFAmCABcANP1BJa5AGH1wJN0BkVpDj/rkB8cALF4AFClAK5hZZszANpTAMJ2TG + x5ANwlAM9404n1gAHeADu0AIuDkP3AB0r4cGZdADVPBs9CIEGTACQYdOdBUEQECdSQAEjyAJGT0lXXDV + jcyu1qAK4vAdYJNSz3boYf9xBWsDFliwBFiAvaPADZ0ACvMwAF/IkVfgs0igAl9QAC6gjZ0gBTVeAISQ + fXxQADlwAVMQBlowBPgAzQYwA+hgC7OwC4/gBwMgDZFACHwQDcdTDcBQDqbAC8UQI7XyAOpTseB44X9M + OkgwDICQAAmgAkIgNitJKTXQByGgCKoACt4ACXkwC0ZgQdIyB7/AyCa8DaqQDUewBLAj1j4TbWqABK/J + BmOgBBZGCJhQCJW+CKIwCxegFj6wBWwwA0Jg1Ez6hV0gAIrwy6MwRDOABfOkBTmQAv0ADuBwAX1QJO6h + DAOgDcOJGrvXDiq4CuAADC5iDZbwb5kgCX5QCrQwDTb/AAYzEAZVUGa60JNWwFfbjAahTDpUgCs7oAM2 + UAqu4A1JEAVZ4QNgEAV3QAe1a8KrAAzM9u7CPR7+WtAGbQUhAAckoAuGMACEUAiRAAQ+0ARbwHqkU0hp + YAUtrkhClpzlFwmrNQMFgATt2QHdIA3AsAyFUAGVkAmvUAuSAAyPQAiSIAjDQEqqQAmmACrPUA7ZEA6+ + qQrAIPiZoArBIA104AJEsAJNQgMeGsoMV9RHQAh64FF9qAiWMAskMH+LJAV18Ad6YA27UcLkIG9j1Ugd + TCXGi7xeMAM1MAUxYA+hwA3eMAtF4AUFIMRhEecdFAMCAAcRYAjcAAZk4HeQEABS/6ACPtAFTPADmLAI + ESAPBDADAvALTfcItvAKxjALf3A/9JAMjOsINC0Lll8MmtAMyWAJg5AIANFnFq9avxJJevRrRZs2bITA + QBMRDRswlmDtUvSL1KM9iqa5YOMhhhcwhbhJw7ZN5TZrwbp4KbNG5ho2NNnUvIkz5xolNdS0QdPmSggq + PmB4QSKvhxc2EclMfLqmQKcXA1QtQpImySJFLZAI6HHERSFENC40kCBPWqRXllTtSkaIDh9ego5NK8bJ + 0aZLnIrFsiWpmR8/fw4CW7ZMWiFz024YeTlkHxmgaLygIARs1qhK836VyqTIAg83hXa8IKRHkLWV264F + 21Jzpv/NnFrI5GzjRU1OJ1nKeCHTpQYLpl6uENrSMOIaLmnSrFHhwUOdPyRm5MhRhUgkUCWQ9FDWB1Kn + JA2+OAFF6NUrar5KlZJEAo+kZfToHUt2ixWuYtmaJUvGklJqSSQPG95Y4Y5ODEvGG1AK8MGHK5p4aQ0v + lCCFFFVSIaQTbgYhZZRYBOEGiBf68OONPcpJaSVnBDBDtzXUUEO3I7roQogqvLACCSSaKKIJIZsIwQcn + ZkDiixqKmEEFbpZqao2omkAiBizS0KIOSEJpoYwqUuiih1FIKEOKPhAhhBsZSoBDB36A6COWSGzZpRRS + 5sFgD1rauS8WTljpRRhhbOGFlEr/fjFhhwpromGRWZqhBoMorOgJBXkEIGqFUkZxxZIBbCgqAFFWsSQR + DOoghIYj8JgGm2tUuuaaPlBowgo1rHBCDSUUqcGJI67I4ocQ4LAhAFBIsKHYRAohgkrhlDiijiYqa6qN + LgQYQIk0gushkkWUsQGKESgAAxJSJpBijS368GGKEGYJIQgjCrBllUxGmYYQQiTxg5Bp/plmlVNYOeWT + XHKJJRFu4AiiDDTIgJiMMuq4I5plQnEhDTbaWMOJWVFAoQdACElkggeKYIGHPCCZp49BBsFACi/mkAYa + bFpkRo0ylvDCC5u8cGGFHvr4IYYtzMDRCSTOUAKpJqgAJAAf/8AoQoogfPBioqbKuKIHQwb4AQs0ZnCj + ElEgiYSQASJIpw9Mvi4hiQK6qMmKC8YLIJNdSMnkF0JmKeECPqShJ5BegjHFFFk+ueSWWci8gAqJ0Hji + ih+isMOaWEDh4YkwtNCaizG8KAKIOiIpBRRuOvEDkxv6DWCQN3aIgw5hnrkZm5zZuNWmLraoow8wYmSo + qY23oIKmoNo4gxAbhgXCj+SaeqoMovsIwgku0AgDilAK8QYTNGcphBBEIlHEjwrAiEiL5/owBA5CRrmI + ml0qKCOBPWY5hp5qbgmGI1hxCVMEIxMkQAIHBtCFMDTFCz2Y1hyasQxJcIMI1GtfRGagA/8wlIIbPDhD + EOogCj9AwgUvqIQlTJAEPCTDZjd7xhWcYIUrXCEKcaiDH84gM4bQhAtVYIMSvuCwNaQgDBqbQgWkcAQf + EAIISOAYG8bgAQv94AhAIYMWhECABhTBG25rRCckoQhFLAIUeehDVrQwhDAgoQ8zmMEAIlGIAVgiAilg + gR9CQThvMKMXq1iFJjhxCWeEYgINEAALnhAUJRRCCm2Iwy+KQYcARAMIUQAKG8iwBi3kgHdJmMET1iAF + O+zCEhOIQhJWkL4T2EEavmDGzZhxBSUs4Qp9KMQjSlaEJVDIZ2t4wgxioAQ2NLCIDrBCGh5oAyOYAQk+ + SOQTKFUGNqT/YQlWeBgabJMDCnSgEJAwBCjgwA1CYEIRnrDAA9I4BC1oYQ0NmMEFuDEKbsijFBPAI/hm + cR9rrKIYmggGLj4RDGnIAAICuAAZntAFblzADCXIgh6M4Y0kNAERATCCJp8gTcqoawZDmIEM6gCLX5Dg + DRWYABBKkYc9zAN3uMOGGmQyM0vAAQpNoOUXUFCDKfygAIjgBpPU0AUt3AMbxfDHE2oQiVA4gQ1eyEIA + 6nCFbGohDBG5KveGUIUeQOIC/oiHPy7Alj+QEQMhCIEVhkCGMDzgAdyoRCICYI9X/EEFD5AEJF5xjGOU + AxebuIUsmKE5SfDAm254AhsusBQoECEJ/3pQRyB20AYePOKUWSvD6KRQgln8IKSDsMQuSDCBQZnGCGnq + QzBe2IsuyOQM3AADU3LSszIgoQ6l8AEKCDAFGFwgBujAxS26EYNCvIIWRvBCGpAQhE6EAAnaHAI7bdPO + ITDhCp2tAgP0UYAS2MMTiOADJpRhggr4wAoKRUEiFJG6aMwCl9KYhh9mMQxp/IManODEKXBxDWk0YxDe + IAEhrvAEDxSiCF6IgQzAoIdaTIMHbNgCLyxRiydqcgouU8RoZ1GKP8TCGy4IwC9c0LM59GERznhhTL0Q + Bz9AQTa/tEwXroACLOSADFWISRWsAAJwEAMdInsPQmNQgB/wIABtev8CE7Io3SGgIQ0XqIUPimAPQijC + EnQYQCYQ4YdWgGIes2CBczSQiO8mohaE8MQs/qYISSSCcMcIxiZMgYtsaEMYcpJEKKDgBXl0IitdCAAh + 8GBmEzTFDDSggiIGkAQvfKEPnSBEKQoRghcIIBYBcAEUzuAFLrCBCH/oRDRsdg1sdMEM0pPNbC6DiCZo + 8zbUqwIXcECBfUhACzFIgAoKkAhC1CAL0BxZDWKwBCxYYQxPqEIVnuCDQoCiFrEQRSpSgQo6IKIZJsbE + L2pRgCdk4B6lgMQ0AKQIvY5CbSvYQyH6lx/F9QIXrFAFKXhRiBM8oBMqyI4X3DAIPeghGxZIrhj/lKkB + RBRiAkXYgUpn4YIumIkXBZhhz3pWh0qAIhTPIPU1Th3b2cikC1SARA2Y4k5NZpELt0mBCJgwBghUtwGE + KIEHxJADNUChD9z4gRJggAIYwKAGNfABN0BRCUy0AhOYaMTX7FELahCiFaKoxSwO0IBkYAJtmcgEJiKR + jFhA4gNQIIEiEvGParQjGaaYBCecEQxgGIMXgcB5G27shR/UoQ56iIYgSoClpzzhCItIXQUE8IMklOEJ + KugGGJBQhjI4AQwvOYMfEkGHWJLaD0GQSUxosoYm1EAJL5FNNrO4yXZWYQ3GZoMTelKBDmhyDWnQASEK + QE3mVGEGQlBCDwhh/whPuMIViBAFmhJBimY8ohSp8EQlquENZBw9M8VYxShEISAu5cHN9JCGKZIRjFOs + whrCAEfUJfEDYKrBjaFYAQ3u0IxskEAKEZuRCxSBiUSswAsce0IMOhEFNGzvCITAPDYwAznYA3BwFWao + g3Qpg01agy5QAhSwgoZ4tc2TEikpOTYYASzwAixQgTWoAn5wAtsYAhwQglHgBSNAthvrpDDQgEMhBFcw + Olown0hwBUVQhVJwhVRoBWngBVgYhU7gBVXIhKebk4oLBULgg0SgB2E4hE04hVMQBlwQBlMqhQE4gjby + ARdYhDSxATtIBGEAhgBogSVIgAIYgD4gBEsghP95OAEjOAIpKIAe6IIxiAkv8DWcMIMWwh1mMIMZmREz + mIIasIKbAI6a2KSTyyIpuTEySAEYGAEl+Dw0QIJZ4DYyyIEMoBQ36AQnEAOIsQ2IUQJAWJaTmIZOkIGf + moVpiAVX0ARTWIRRuJdGkMVWWIRCkARbeIVK8INA4ANvaIdq0IRNmARKCIZeKAboIwVvmAEPQIcCmIEm + 8gZC2INQAAZakIbRSgQ7UQRAGIBWcAVRKIVo8IZdcC4rmBErmIFfWgMkeINowLhS44IGLIkQoJHZuAmZ + 4KYFRAMpWSMJoIIawAI1KAAiCIIQ6AErCANMrK5l8wE2+MSHYasZQAEBqID/PiCAJRiDNZCBSJAGScCE + V0iFRoCLXZiGZsiETRkF0MCEUSgVwxCEfwAGUzgERrgEX8AFVegFaZiHGcCCTOiGDJCAApAEYIiFQrAG + asgDoQMCKNgBKHCB6CmFSEgEs6kEAWgADZgBCNAAK7CCCokDPKAFmKKRJXgXN4DAzbsNm+CkBrqJfXQI + QKgBGFgkKCCEAJACfiCA6BqCHNgANOgCOGgC21iD9iGD53iCEaA5hXoCJyAASyiEQSiFoquFUhiGNuMG + SVAGcQANYAgGYXiFRAgFJawGVTCFTcgvWVgFXOgFtXkAI3CCEeAAboCE6JOGZFiGWRAAUKgAGoCJHsiD + /w+wgD8ohUQYhURwg1wZAzVwgiWoJSW4AgHoA2WIpVmagi+goRhwAs1jwHskg06TCZzwgm6Qh+ciA+MI + gR+4Ag6QB3OEmCrQgjb4gh4YTIiMiKbgHtuIiCpIgysohV14hVZIhmKwhVh4BURgSVKgA0KABGMAhlvo + BVHYBUEgHGnghFvQBE1ghVW4BVwIBl5IBmlIB2WQh3R4hEGQSj5ohmkIBBPAAD8oERoIgADIA0S4AVDI + ulk4gTXILGpig5goAyjIg1kAhVjChitoLd6Zgc2Lx3uUDe+EGJmgAmXAAg1ILCuYgpdQgjGoAQ0QTES8 + lsCciIdZgy/AAogJgzC4sf+tCoFRKDpFCIdrOMlSaARboBNnm79S8IViGIZY+IVfoIdawC/TVAWBksLh + DAV+iEN2AAREKAVC8AOL8YM8KAVF+B5v4AYrg4VQoANlwIRMoIMoGAOurEMvcIIVQJF5IFIzKDYrWIKZ + eFLZuIlNipjbcAIf4IAqQIGY0IJFuo0qaAAfsI0q2KQRYIMsuAD7rB4f0JZg8oAl6IAcKII+GAVP6IQ+ + UMVVeIVMiAVVaIVGCAB+4Ib+FMJXKAQ+ULds0As5G5hPkAVhaIZgMIboSAEDOAAb4IYWkIMvPEJIkEE6 + 6IRHeAVbqIQ/4IZlwYRoOAE1kKYZwCkzIAJ9wQM+sIb/m+HKGJiCgJSpnNAJRRw9NlgCAVACHOACURJW + djq9IRACeVCAZOs7MkACODgC0QuDJkMC3aoBkZEHboiEUWiElTSETLiFWMCEWtgFWBgGb+AHzrSGXAgG + WqiFZsMPR+AE0pSFW7iFU5CFYpAGeEAAD9AHc7CHWRgAGcgDP2iGULABDFAEUggEQlgFZCCF8oEDIuiD + 9ZqGEzgCIiCBX6gAIhgAQgiFOdgDYLiZKViCGSoDNZgBYrMCLqCmhojViBiDGAgBAaiCtaoJ01PEThoC + AtCAvWQnYZUKH+Ck9swBLY2BKvAAGyiFV4AERUAG6XubWPAFVkQHS/gPXZjKa4AG/4RxBmCYhlCghmko + TYKRhWC42oESh3V4h3TIBmEIhqQEN2+wBUKwgBWwBENIhFlIBVrY3gfoGa/Bg0iohRv4g32hgxsYBDjg + gRbQg2XAnRqpkTKwgsRlVQ+oJRgISM9hgxlogALoBgfQJojUghRIgehag+rSAALQgg3IAC0QVjZogh5Q + g/q0ghr4gQvggHuoBDb1BE8YBljQhFFAh0fIBFcYhVbIhGSohWYghUigBeR1BVWIhVgoBWTwU2CAPk1w + UGdQBTAsBWDYBaJUBVvQBUAoBMJwBmIABWVwhVKYhkdwhUywhDzgPyRABUBIAhnoF1zQBF5AnT/AgB+4 + gz+ohf/4hQkKTEvGG4PF3Tmg44cDmIVuSIFLzIFdrYIMWIDsGIPLHYECyIAU2IAmgxgn6IHn4p7FLAAg + CNesgwVRaAVLCFBYiAVgUAVn4AVYdAViiARDqBNYgAUh1IVR6GQlHN5qCKRjxAViiAVeKAZFeIQG04aC + MgIZ+ANrUAVRkARYCAZYoAVXCAZnkIYJcAG6mocPyAM+sIRcAAZQcIVXCIREUMNAkIZYqhEuiMfM+04p + 0ZpnWoQAmIXHYQE0GIFAFoIZGAEhEALYvA4rEAAFcIAUcE+rChMlYAKrcrILSIRIiIRWIAVQPsleKIVW + SAVe9j1NwATfE4WDiIViUAVYcIb/ZJgFP5BQmHSEVQiGVTCFT9gEW5iFeXiAHuApAjCEZcAU6kgGZKAF + XVAGWqAFUsCEZRAQyVOEUZCEMcoEEWY7byCFadgFM/uFQrBmzftOWI3cGagBDygBgDWlAAibIpIAH3CA + DbCxNcqADlCGAqAABsiBIUgBd5qCGEiBfWACJCgBEoiERvC9FD46b/Q9TAiGXFAFTWiFWEgFTaCFRRAF + UciE1AQGZqCGP+CDUAAYSriET8BoQOoFamiB7BiCJ8gBJGkCH+iDAACHZBAEYygFYlAFYOAFzSCBFvAD + QqEFHpaFqvUF4B0FVigGDdGFUIglGNCZbabtTaqSJbAetWkB/xkIgFrgBqPgh1pQAQcYgTXCjtSqBX4Y + BXbohwxwMiqQhxmQALDLBEKIBFE4OmJAOlEYhZqmQXgjhlFg02FI6FlosyAWBgEVBD3gg3+ZBkdwBJrM + hWJwBk1IhgBwAAcQAibgAMQsAxqQBEJABmEQBVpoBVXIPrZLhHmoNkuQhH/2hV6wBWlYBlpYBV/Ym1gI + hmmoZmxwgib4JdpLNTa4AkW4gjYogvKxgd0GgyCoBW/4W0uoJ0RIALWaAV0IBkvwhnWIFRQQAzHIAl6w + hwBQhp5VBKIbhWGY62HwhGUABmD4PlWYa2lT69glhVoABmFQw1bmhUQwCHpoB2C4hJnMUP9bUIViSG4F + YIEYOIAvMEM92JQB9wRB4INZIAVNKIZmkAbrTgRp5mVfWAVVWIZXmBNosIZd6IVnwAUpjKlrqoklnQ0n + uAACcIInIIBHCIUbKAZEiAIv8IFSkAZLKAADOIdhKIQEGIEhaIEBaQZruIRcgAfncANLqIT0ecxB8IRG + 2JCVTIWsiwRnqARY8L09R4VOAIVY5gwB0YWSKtuEEIRAaIc4uwRWiEJfKMoWhnJmSAZh6AVgeA9SiIXV + TIQ/4BtWuAVuP22COQVN8IXT7uVkwAtNUE1ocLdgsOYLkSkdpUDm7BkdrexC+AOTYAExaIBBkYYOwAEH + QAB/QAACSID/HsiEdUiGa6hadSgBMJCvPzAINGuESlgGYgBhdBiFQhBvSNAFQ5AGVagLwjCEZqiFUaAF + 8klGBXACKpADPyCcdtCEvfgEXGj3YXjaQtgFeV8Fc78FVygGTCAGayCFVxCFWCBhYWAFW1i7iHYGTLgF + Db0FZwguYUAGXshoZEgGWyiGmJoRJ6DAHl2CGRBTNpgCfpiBL4CEyQuAIhgGj06GHyhgEeD7DEAAFECH + WbCEYrCGbn8EYMBupJPFmoY6Z5iFTgWGRrDpR6CvaZhrWuCGcP4DYBgFUIgEWJCGCIAADgiDLtADP9X5 + TXCEgjl3UvADSQgAbtCF1xkFHhYGXUKH/2II+IBPhBsggUIoBFKYhU4ohD5vYV0w81tQheIXBG8ABnBY + N7M/vYy8CTVYgowdzO/gACYYgiWoAW7gBnFLUTVsgAUQgQXAgQJ2AGRIgAYwh1IoBldAupW8bkjoYE/A + hFRAYbW+F12ISm8ACG/JSu1SxE0UolKSgCmKNiqUEyY5qni5I+hYLVWbHK3q1UtYgBvc8qjogKTICRKE + LMUitAxYIW6JIM0acIJGkRrd/BAiRUjSH2lCecFyVQsUN26xMnmThk3NmjJsrKhho2bJmDVr2Gj14WQI + GTIpylhR8kVdL2vSLKWjsGFDFSspHETzwICCglncIFUiBMlns1qEBv8t8iQq2ShCw2YhghRp1iBXihSR + ChVNEQkV92K1BMViiBYtXfB4o1YsmMZVwJgFQ0RIkbQHT9KQ6VJHkZ9SjTJlm/cAzqBQoGaFkOIlSh9R + pCpVmpVJGilSiWYREyTITyVXr5A9japVyRIrWtmQYcPmyhQ2aMKCZoIDxz1ouFq4ISQhRQoJGnIg2FWD + AwMbMHAPP7pgkskorvg0GSKKlFJLDywowcIFhBCCCCiQLNKKKLrMokgeByhgTzK1JJOOFWFogYQev/zT + jCmrmOLLNdbEYhAJkIByxBNjPDEFKZAMw0001pAghRvcFOEDILUA8gASOizCkyR9uKLJjYLsQYr/JYTw + MUsikjjTnRfmKQGCeVxtZUUNa6ChHhparDfEBvyccosLUUjCTwpvibABCKTAwIQDOeTAgAMEkBJNAPz4 + EIA0s+QBiSeIADFDGvDFUosloBRSCCmNKDLIMIRI00kt1jzYTARTBaEHNYG0UwwrmnTUSymlkJCEAIT0 + YAUaaHghAyl+/EGLkTwg8oMXT3QRAzqxBOBCC7uQAoogiSyTCSl8SFJJKLS8UgodfPByDVRrXKWGFVhU + sRUaXfhQFRtahBHselqk4E8xvhhQBiCFWLEBfhR0IwEOQxg6xBA4xGBhARzMwI8klvwxkg0h+FBDBwFE + UsoslujyQA+qhALJ/yCGCEcEOtaSIskELqwgyC/L7EJNRo7YYkkhA/SARDezFMKCGFqo6wYkecxizTw2 + wHEEV2l4oYMPBQhAgq72DNPCAIrckkklfyTyhy7SCVIINmN4sS4bbYQXxhpe+DAFaOSRsV4OczKRzzf4 + LECAJFAoPBcBDKuIn8I+JDZNAyN0o8gohdjwBQpUPBAAN4Q0MgwgBRTxxAy6+NDAA4QAkg4QD0TziDQg + j/2HQIfcQs00MRJTiwtNePEDKdJUYEVYM7hQx8XWJBJAEWx4gQQLPvTAjwsyFDJIHqC8w08RRCBCDCKz + /CHJKNwoIohTaqjhRBlbqbdEGW004UOZcb6Jxv8YwJs3hAgivHfFIxcwofAoEICDMJCBCSJIwRC4UINo + jG4JLOBGKVChiAi4KS5K8AE3XDMPommBBRWogQSQIAADjCAGPQCGMB7xB0sARRHtmIYjNnGLWkxDFauI + BQl0YIQAjIIUtfjBGrSgBDjIIA+ECEYijICEI4QgAIWAAxAKQQgbvEAUtJBEKZqRAC/EoQ88EUUmamGs + QiQCG0rAQlTSxIYxKMEMP+hCG8yDhjWQgQtkiOObyCCCAKHBCYqQhxVygAJP5IAJZAjDvbSQBjX0oQRu + GUEfStGHTxXAC4YTAxmaMAUCKEMAJZABInrwgxFwABAcCINVvlCJUiTjEYT/uFg72qGJU+TCF8BoBmqk + YQFuWGIUlrCEPVxghS70oQ96kISRvOAFOJTiFYlgQRcmMAtCYKATrhgFKOAAAySsAQlUgINrQuENDPgh + GthwgprUZ54aEOINV1AjGqrABTXebQbKEEIYkNAHUmDABoqAgIpUxAQ0hCENW+hBDhaQghEUQBQ8EcAR + 8NUGNLQhDW0oAxIeILRhCMAGF4iBPEaQA0RWoQM9KMUjWvKLQNBjFZuQBS5ukQxixKJihEjGK4BhDUI0 + QwVS6AM37DCLbLSgDBUKRiwKgZMBjKISgRBfJkBRghJAgQ1l8MIRdtACbsxCS7pgBlTStxX1gYEQ3GjC + /0TbRh45qsc8ORBCBsKghh7EhBRUwIGc7nVIYfVgCmGwwghwYIUmHAEGRXDCE9iwhAQkYApOSAMTxDCG + I1DBENwARSdAUQEpkFQLTMCCMniBjGKAgh7tUMUhGCGLUxTDFqUQBCFoUYxM8OJB3EDCF+DgBzxYYhou + aEMRFMGK25VAHp/CxDQiUYlEIOMYpeCGC6DQBSRk4QUfwEQpgvIUNa21DUfIQx76sIU4qrGt5TFPGPDz + hDKEYBBALQETmKCiOJFBDGYQwAys8AM1ILKgYrAC/L5QgG16oAc1SIFnxeCFAsABFH1ABCBqoIQyPCFY + WqhBMkAxjF8cwxqpcAQjLv9BS1yUYh6/mIUzVLEMUnDjAsP0whT0kIxpJCENZhgGLTrxgCt0IhGIwIQN + k0EEfhDiF8EARiJIgIdH+OEGpWDFMmqBjRaoYQxc2EobtlAAM1BFCWpoA3mDBSc1aoEMZcgCBH3QhUAa + Mlj3IuYWxJCDBlhBvha+1xXUrEkjEKEQHEhDQasAgzLAIBK1+MADJDHVuRVBHsmwxC/acQxTUGITm+BE + MHAhC174pBKZCEYxptGCQIohDU+YQzNCAbUnhEAGTvACFvKQiOduJwIj6AIqLOGNRSjDEqWIBhwgWIpR + 2OIaAzADWbAwhiv0AY5xLEuaxNzWN7GBC0tQQg1qEID/WUihovG9V7B2VwM2hGGgEikoZBXZACKwAFS7 + mIANsIBJNHgABUxgwS5swQ06cOMNfggADGoggNxEIxDL0IQpEr4JVtxCFoQohChiAQtiSEMSF9CCwuaJ + 6nl04U01+IF5rACIPlTAG7OggwqGgIQIZCIULiiBo6DQgRAA4hGCQMY16hCC8XihB18YTxnYOYX2sSEN + FDWP0a0NAiFU4QluAIQayhxfOVF0C5JoQtHslYMRABrQcprBAAKQhwGQgt8zYEIa2EAAGLTBB8nIxKd4 + AgQk0AYJK+AJPSy9Clbg4hSm4Lsl8nA2XhhkHi6OSxgq0gwSdDwMM1CqGpBAhA/A/6ETHyhECSbmKVLM + AwlW8LwVZgCEQSQiGtuwDRjahh7zzLMN7foCFsAs7TfFEcwDXUMPAIGEu8nXAVqwbx+ywIYhxBc/aRCD + hdGQBi4U4Chjh8MXhJCDIYTBByUIQg2KMMlCzEISK6gwRcHwB2okwxmr0ASoccFwVQzABcEGgjx0UYgf + zIAMVYhXHpphAvWA+QoCGAAQKIJZEUIEFIAN/Eb2LBcJyIAPmEQL+EExCAU2rIEZSEIWdMHPcVfbxBEW + cEFardW0DcEatIEXyIM8eEFoTMQaSA03PEAbhAGd7AMmcB0ikYGcaAEXNIEAeIMPzEDRSV8aIEEncEMB + wJE+yf8AFPRANOjAvayBHPxCLZiCK1iDahCDLfTCKjgDCbhABZSAF4zB+xDCD5RBnJhBKDTDCRQdF8Te + EfSBPKBCAbwBdPWAH9RCEHiBC4yCKvxCInzAB8jajAlCM1xD+5iB2CFBG6hTmlzUEpgHHqlRGoAFGkhB + IRTAE9xNFVRBGtjGuNVLBowAOJhDQSGS0a3HenTBFPTAFRzB+fwAGAiAMhQBf4WBGDRABTjBERRAHvgA + FkCBHnhDFCLcKqxCM4ADLvRCUkWDDZRAESZWCRRCADTAGsRBISTDCdwNWbyJsxiHD7gBDfiBKCRCC3QB + FPjBKtyOIPhEMaiCWmTCNkBFzxH/AhiUifqQV9vUT9qNGbXBjdvMQgGMwAhk4hggQQ/Aj9GFgRDcgzUg + AKANgfLhy92A2QzUQAH4gA/IQw+EgBKIwRN4VhgEwSPYwxNUwQ8kwgpMwEUAwyaoAivIwiasQjIIg6oU + AijYgDKUgqutwRg4Qc21gAxIgjDYgBrcTR6hUhyxAAsQASEowyx4wxfsQB5UQi1I0TTMgjGYCC2Awzuy + QRYEQRQEgBt4gT2qketZQSLKCf/p1RqgADCcARlMBBpcgR8EAZyIRT4wgzngTbC0gUM6AT8AARV0gUXR + kRaAIQwAS7lJARRwQzCEAgtkwAz8QB7sQShUAytQgiwIQy+w/8JLAoPrEMIEzEAHxMAUNAAWqMEF+MQe + lINmaQAd2ZFOksEabIEN+JsrOAcwAEEScMMqWAIkwMKn0IIzNANPvaMhdgEbyEsebAFywlPbYAWYOWK9 + mGIREMIRpMEadAEVFEIWlEkOkEEa+MMzOAOmyM96oFINtMQrFEAZdJ3yeYAPjEGcWIEueEMe7MIskABA + FgE3hMIvxMIhmIIsBIMwJEMxmIIteI8UeYYmkoEVLIEKXEEIeBE40MEOVAHTmVlYcIEhqgIi0MEiDMAA + cAMcSAERVMIyCAIv8MEehMwshEIyXAOboJN5rEEW+EEngIGzTRSYkcESuImbtE1YtE0WnP9gF/yAF7FA + RcVJGozANwADFqRBKeILGqgBIIzCKCCEEgAaG5TaRJaiEiRVBJRCMdRCAYgBEtyBJCxDgJ4CK/QCMPzC + OiSDK+wC933MADhBE8hnRa2BFYBBIQDDPLgAVwgBB1iBVHABFHSCJgQADSRBor0BEnCBbSzXLMQCNZQC + L0hDNMRoD8TAeHAFG5hBH+RBBQRBF4wgj47BErTBHQ1p28hNABhBHRTCz0wUGlAfB5iDMBhAHSFSsBid + GGBBCCBCH3glFqjAVCjBGqhADahBFTieIthDB6ACLxTDbbHAHlDDKhxCpjFcMSSDPbiDL7yCJAgAHABC + CawBFlwiUbb/gRkkAjBAAjf4gBIgwRgMAQeggBp0gRtUAihIwRLIgw8oa9vEgSUMgB7EFi1MQyyQQjZc + Q5toBbVlpwAAARRkgShdgRlUhes5QUVdVSKqQRYITRAgwRa4gatqgaEaADgwAwG0DcOIWbAuWxGwQIq0 + QR/oaABEACIUQQcQlBUcVhgYgCTwAigkARAExSaYAjNcQzDcgjAUA/mtQve4QBkIpvKFQRUQJRrMgVD8 + Qc9QQcBdWwHMwBr4gF5owGCdJheYBBTMAqL5AR9YQi2gAyZswzWkKlTMk7qAgQ0UwKtJQQsAAQBOQRCA + QQ9QwRVcwRdMwRd8Ux9EAZjJzRXYkQKg/0MyWIM/oF1/4UsppsESWKQmtoESCID0+IElFMESTF8hhUEO + OAAcmIoF6IE0UMMmFEM5ZIM6MAMzbEoz2AIi/MEPIAEBhUVo4AsXzEEyJEIJOAEcPIAXPCgVXIABFEEF + 0MEE2IPaXNURdMIWQAEhrMAPKIMMMBMpiILedkEXmIGEzRE7/UANTAEKJAAikGgFLKMN/IFZDcAUbMER + 6AAcoAL7WsEYqAAc8FcK7IMz9MNfSV+9GB1tEGUaWEG0NuEkTdI8VoGyEVScjAAzWcwsJAMwAAMuAMM0 + 6EM8WIONCIMAggIoFEGwkAH15ZHU3EEzzMMRVEEXCAARiGUTdAEW/P8AJCjCi/LDESwJEBRBF9AAIcwd + jxyAK0kDC/dBN4BBDTRi2k7BVlyVGjSBE7QL+3TBFQSBKq5ZL85CDZRB+oAZFRQBnTBAP+RAG2jAIpTB + 3RRUsAZLqYVuGyBBCZQVIqKBu4CbGMzASZFCJDRDMphCMchCmfIDA+yDNRRDLGACKQABHGDeDKDBBjik + etgYKNRCC4xkGswAIKSeGswRjClCc4wyN/yCEmGBDVjCCkzvGCRABdguM1iDGbCv+nTBHZJXj6pqHMnm + VIxB7R0BIJjBkrZNGfQAB4hABkSrwlTYlN6LHk+pBKPBF7iAQcYTPnEBIqUADPgBJESDNKhCMDj/Ayfk + AjAMgAeIgDkAAyyMgjQkQQdIxxUYHVGGRhzQUBKgARfc3xF4EpxwgRckQQtgECYk7I5hbylMALTCpxHg + wTpYA7qwrxdsBceOlXnI01hSxZtgwQYGwQ8k4nl53A8YSnr9D0UFKy1SKaA9JKBFcyLUwAsSEApoIhqI + wQggQR0kQiiQwiH0wjQ8gikkQzRAQRgowDuUwjAUggusQQxYQgvU5d2wAfPSgRRwQTyFhQp0QhF4ARcw + ABZEgRR0ARDEAiioQBZYjR9UBgt4wQUMgBzsQYxmg/lUgVTIC1TUKBmMQexZFEURsxWYJRIsyw4EQfuI + 2RVwwxHgqnoQkPJJ/ykfby24Bas+ucLcKUEBIMESLIG9QNYRBMAveIMwUMIqiAM1KIItTAMcgA4gYAcd + hMIFHEEN1EIJiIFlb2IdZMMKkNsYTARZNEGOKoECAEIpAIIUYJs8NAAZSN4sPEQhhMAApCgfZAMzkIP5 + BPYPXEEcjUd5vMv8pF1FgZlfGwEgAMFcRidFrcEUqOxESbC9BKuUdp3X5rcZVMIrcEMFhMAjXEEZfEEp + hoER+MEvJMMmUMIpWAM/TACxSUIL/MAr9IWHsMAc9UAi6IDRHawkTEMc0EbXagF5eAEIAIMMWMFJRUMD + 5IAXdAEKLAGMPcIyfEARgAIvyFQisDA5UMVWyP+L+mgFkRd00eHRHH14E0CCEcSBALgByIpZHAXBeGH2 + QYaule+x8rUBGERCIeRBAUhBE6hBBd8LmupBIjC4I/BdMkDAGADBp3kDU1mCHsxCJ3QymgJCJ0RBGsDA + GchBMnTeh9vg/HRBDfSAEyABFBgBOijBu1zUGjQBi0XBEZSk3RLD05LDlVlFCCCnOoF0FbTNQ4JuG1wB + IZTAFpTJl4UyRcmL1oKunKgBCrSnlk/pFwjAGZG5GJSaFTwWV5NPg8sQMLxDBoigDGRCJhACHLjBAJTC + jsiJGDjBLADCEViBEeSfDLiqDVabSd+REIKCDnQBGQiBFTwBFsDAUIqvDHj/QQ0kQDpIAx9IQzGQwziY + T6lTQY2C9HjYkRzFkdG1gRrIgxGEAKouaX4HqxlQQUV9eNpFex+oAfLVNPIFqxNsqW8TVKApAxScwLFE + 4UcEQzbEwwbEFxIEgCZwAw2wgVBbQgyUYhsQgSKEwg4wL421AdUNNgdcGQYKACl4QycYwXqsAQTMixeE + gCWwQBGsQzOoxR64wzXQe/10QQjQy1gRuVaEheyR+hXUwA70gSXIgKqOWXr7gBl089GpACLAkQd3s9Ed + ppTetxhEhQ/QwR5gginASC9oQywIwzvs0QhEdiSAAhIoHwvkQQh0ZNGZwcPpgYyBAlqFBUEHURVkQQAc + /4EUEMBK8IO466QPRoE/PkEMAMOR/cIfAMM1jIM4VIEZgIF4i+qQT4V4gGeS86gZkHU5KkIhdJvyFV0p + ioG8FN1lv8kXEAIK7DSWE7QS7LSbiYFZlIAfSMM7N4MNlTAwuMM6oIPQ2ACoJAHy5aBnMIGzuIAf6AIh + gMI0fMCL1+VWkEERPEDsdUE3hAIUdC0dkQEW+AAhfE4NDAAtuILYOANAZBsnTg0YH13YrGGTcE1DNmXK + sKmChg2ZhWjQoOhWxguQUrbOtGGTZuRFLWyuXGmDxmIbNU1CzDqShiYammw81JiRJoxNNGHCkEHy5k8z + SsGELftUq1msXsCWGZiBxf+IJRtltKBZg8rejCs9/BDSE2DZsSRcOOSw2aaJDx8PwDRZ6IFWCS9rtJBp + Q8NSIShrLjxIB8gPKWbkBirJc2WhQoaPF1Zhg6YKGZtdAJlxWeBECBVjVqbhIqTNSjFqejhJY3NMDScx + ABWA0WY1zzRH/HQBGiZrzzQ0BCXTdOrar0SssmFYZslevgVDmCDpU8tIGjJhCCSiY2kAjRB6/gCjg2T1 + CCtgHgAqJI8QoR9e1HhB0QlJm6xl4Fia8Jafgn0H8NjFGsTEAeMNLyBzSCE1sGgjh4QWamONOqYozYsl + 4FtjiTVKI4OM1TBq44waaEtDiRrU0ACLNZRAoQwQ25j/YhYpQOypjS9swEMVSjjpRRt78sjklgEOsOSe + DfBJYQgygvCDGzNWm4KQRCTBAIkr9CCkFmlaoK2NC2Lh5oy7nvhiFh8S6qKPHxTqgohBImiiiGhqcMCB + OOgghhxyBJIjCwgBXQOLLlxasTKG2sjCEitKY6O00sbY8NHS0ihtjSC6WE2NBFDA4qYCetBBQjD6IEWG + JjBCQ4s0iOBjFkpWwQWXbOApQRJNpKEBkQJyYEJJiszooQLdSiBkFEkkecEMPbKhY5ZOjrDJiEda8KKN + I2IAYpACrFDIiVmM8IKHUjqRYgwrEHCAgirmCKUYxAbiJg4IFdLqWjfAUIkNIdSQ/3CNJAqhIkKKFlKj + C1KPGEMNhdvgwlEz3HC0Q+toyiIWQGSgwYbCBgDjidrK+EAQVYIRp5dTeoEngwl2uWWCCzpxwteeuGiD + CEKAmKGOXSzhxRI98OBmGgssmIUEHXRQpgIPhmAhHUIUiYUIIThAwgtUAjBhkFlYQKMLCRgIO4o3FBkw + G3LEsWELkRZqmw0z/KgDITasAM0LIrgRgAdCuVhDjSWscKKOAAppQg01rFADDSsYP4ObJkpL1aY0WCgl + kl0GiMCPR4xow7c1TPCjlGCasUcdWazJBwcdBnBEmhJ6qIEJJrQACokA7iAkAh94ISYTYpThoxlBEilk + Ozq4Kf+GhC6q6KaUf14p5UA0OFDhBUIemYWGh8pgwAF8GGABj2W2gVccN8xwiGCXYDAjCC8wqqIhN0qp + hBtQGlyjjIZKM+N+OMoQOUc1pgk2OIITuDC51bABDISohCX01oNM2QR0v3DEKoohDn+4QxjCgEcKmPCC + 0ZngHsuAQK9sIh0eBKEQESjFKjJhiSk14xftIcQsSrGLTCTDBV4gwC7ygAlgzIMFXnBCBeiQCWCcwAtk + qIIVGLAAc3QgDnoYEIHC0S2HuE1iTkDIGqxQhi5wIxZ0cBKhLDIwJWTBDFOIAYdGQhGaxAgMXdgf40Kz + Bh8QAQ4FGAH8LOMFE/zBEZwARjD/1tGBfbAjGODgAA6sQIJVTGMChehBDoZgBSw0qQVE8AMJClEMYkjD + GzQsxA+gMIMLKIMUlkjGBNSAhCz0oRSlSAQGgICB9rgyAl6wQhVyEEUKsMAOidjGQMQhjmrcZQ1eiEhj + GuM3NThBCWswAyHc4IYzQEEJXCwYh9pgBSWshCJsS0MX6uAFklgBBliI4wVYcIExeGAiaPACBn6xiUNY + gxqZsMYBcDCCWFijAUNIAQ8iYQo6dMINToyJHwYhiTq4IA+CsEQikJGIZoCiWk8QwxBqMItazKIQD/CC + F+ZACF7wghC1JMUHeFCHRLxgDcBcAAPIYIY9SCMbyQxHONrR/4WTNoSoHFFCE7qghoZYIQqdqAF8oNk2 + trmtDViwglSlSgUqrCQMbFDDDDCEty+0gQwjeEIULEAIfcqCGvMY3QRyUAV+MIMf+RhBF0jgiGV4AxBI + eEIQBnFDIkhBCn2QBDfykIhlRIMOEXiAD3QyBCMMIiyzEEABAuAHYqhiF9KwZbXeYAlBfAAJKcCHP7zg + gj1YYyA/bccxknoXZyokcU5g5v6K0INuWCshWgkgoCCzEMCJhCQsaYMXgqCQnqBhDE4oQiFq4U6KuOAG + paAEK07BDGnwYxa44MYYxmAAYEwjAVoYwgsMYYoalsBrRahDIZJQBETkoRB6uMMfjOGN6v8OghrTEMAT + 9PiIw3YiGbGAhCpmoYtalOIRJ6DBH2JRjLY6wXtS0AMotuHTY7SDHkk9XHycUIb4KKgMSehEN5DABi5w + AQtLKAMXwPvMNThsDVppyBLU4M00ZKEJxUWDGLxQh0jkKg1eOAEfrJsLpDCjHPrghiZAcQQyPKEbwajF + BTLwhA+sYh0kgIMXqtCGGHCjBCpQAhHAMIs/SCOjhChEIUgRilrQQAxI6EGykLCFCZSCFn/QBSxWsQwS + YEARrgCGM5ZBh7vSYA/LQFs4qtGOQNAjDmowwxac6WGHQAQKgCjFX/S3BoUtZMUyJipRvaqCernNClfR + ihaqQIM8RGL/GidIAgb8YItg5CIWybCGNeLBgBJgIhkskAwMhAGMaORADDrogTO8UQgjoKENS3gfRjjS + wHIUAnvzCEUnQsE1jByBFDYoQg4uEAlYlEISs6AFKOggCVcUAxwC8obV5PCHcogD0hymBz2YaAYPHy4L + W0DcvwphifedWpoDdJtjtki3blIkjWyoAxxyrIUSPKIUU+JDIBQxCVyoQhjTkEQyshEPCsyAG6voSho6 + UIpm8EMCHvDCBKyRjEjYAH5reMASQFTkmxVjS9woRCikEQIEaWEGYEjGAGbgBEQ84qIkaAEPJvCIaQCj + FJagxgHUEAU8SGMckebwpAMhgDN40WBC/wUDKGyQhSRwgxADcEIz8d7M9CWoYCe9wlXZsIQlRMZhbTDD + NKAgoR+0RxCFSEQxKCEMaqzCGhNogDLWkY8MpOADrshGByhXCGtsFxEVmEABgJGIWiS+DF5M1Ui8AAaZ + R0MQ0ljGk8jKBSt0oQe1aEEVCJAMS0TjBDxwwyPcYIQKgMISobDtC/bgDrNPmh6TrsADlLCwpJpBBoXI + wwm4IQ8enEENHBmqGnQABjMwBOJvC8IcBiAFojbBCQvJgQTIsAYwAMGOLQgLIVzBFByhF0DBAjKhF06A + CSCAFNhhBMLABUpBFSZACoKAEGJBGB4BEBogPrrhacCADbSACSojVTsqxQtkgBaIQYYEgAbaYH+eYAye + oAkAQRpcQDp4ARgegRtm4QWkoAsewB4KgRuSQAqKSRyq79+QkB4CAgA7 + \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/Resources/SampleResources.resx b/test/Spring/Spring.Core.Tests/Resources/SampleResources.resx index 0efe8412..f4c06516 100644 --- a/test/Spring/Spring.Core.Tests/Resources/SampleResources.resx +++ b/test/Spring/Spring.Core.Tests/Resources/SampleResources.resx @@ -1,6 +1,7 @@ - + @@ -34,10 +35,14 @@ 1.0.0.0 - System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + Hello {0} {1} diff --git a/test/Spring/Spring.Core.Tests/Resources/SimpleAppContext.xml b/test/Spring/Spring.Core.Tests/Resources/SimpleAppContext.xml index 035c87ea..83dbedb2 100644 --- a/test/Spring/Spring.Core.Tests/Resources/SimpleAppContext.xml +++ b/test/Spring/Spring.Core.Tests/Resources/SimpleAppContext.xml @@ -1,14 +1,14 @@  - - - George - - - 25 - - - + + + George + + + 25 + + + diff --git a/test/Spring/Spring.Core.Tests/Resources/Spring.Context.Tests.de-AT.resx b/test/Spring/Spring.Core.Tests/Resources/Spring.Context.Tests.de-AT.resx index c16e09c4..5d836885 100644 --- a/test/Spring/Spring.Core.Tests/Resources/Spring.Context.Tests.de-AT.resx +++ b/test/Spring/Spring.Core.Tests/Resources/Spring.Context.Tests.de-AT.resx @@ -59,7 +59,8 @@ : using a System.ComponentModel.TypeConverter : and then encoded with base64 encoding. --> - + @@ -112,10 +113,14 @@ 2.0 - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + Des is {0}{1} diff --git a/test/Spring/Spring.Core.Tests/Resources/Spring.Context.Tests.de.resx b/test/Spring/Spring.Core.Tests/Resources/Spring.Context.Tests.de.resx index 57f3ccf2..b6d60247 100644 --- a/test/Spring/Spring.Core.Tests/Resources/Spring.Context.Tests.de.resx +++ b/test/Spring/Spring.Core.Tests/Resources/Spring.Context.Tests.de.resx @@ -59,7 +59,8 @@ : using a System.ComponentModel.TypeConverter : and then encoded with base64 encoding. --> - + @@ -112,10 +113,14 @@ 2.0 - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + Dies ist {0}{1} diff --git a/test/Spring/Spring.Core.Tests/Resources/Spring.Context.Tests.pt-BR.resx b/test/Spring/Spring.Core.Tests/Resources/Spring.Context.Tests.pt-BR.resx index 8114e529..b7d5e152 100644 --- a/test/Spring/Spring.Core.Tests/Resources/Spring.Context.Tests.pt-BR.resx +++ b/test/Spring/Spring.Core.Tests/Resources/Spring.Context.Tests.pt-BR.resx @@ -1,45 +1,50 @@ - - + + + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + - - - - text/microsoft-resx - - - 1.0.0.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Isso e {0}{1} - + + + + + + + + + + + + + + + text/microsoft-resx + + + 1.0.0.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + Isso e {0}{1} + \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/Resources/Spring.Context.Tests.resx b/test/Spring/Spring.Core.Tests/Resources/Spring.Context.Tests.resx index 955d5a01..6b453b1d 100644 --- a/test/Spring/Spring.Core.Tests/Resources/Spring.Context.Tests.resx +++ b/test/Spring/Spring.Core.Tests/Resources/Spring.Context.Tests.resx @@ -59,7 +59,8 @@ : using a System.ComponentModel.TypeConverter : and then encoded with base64 encoding. --> - + @@ -112,10 +113,14 @@ 2.0 - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + This is {0}{1} diff --git a/test/Spring/Spring.Core.Tests/Resources/Spring.Context.Tests.sr-Cyrl-CS.resx b/test/Spring/Spring.Core.Tests/Resources/Spring.Context.Tests.sr-Cyrl-CS.resx index fd7e371b..44a21ce5 100644 --- a/test/Spring/Spring.Core.Tests/Resources/Spring.Context.Tests.sr-Cyrl-CS.resx +++ b/test/Spring/Spring.Core.Tests/Resources/Spring.Context.Tests.sr-Cyrl-CS.resx @@ -1,6 +1,7 @@ - + @@ -34,10 +35,14 @@ 1.0.0.0 - System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + Ово је {0}{1} diff --git a/test/Spring/Spring.Core.Tests/Resources/Spring.Context.Tests.sr-Cyrl-RS.resx b/test/Spring/Spring.Core.Tests/Resources/Spring.Context.Tests.sr-Cyrl-RS.resx index 444f4280..1dfd4ee0 100644 --- a/test/Spring/Spring.Core.Tests/Resources/Spring.Context.Tests.sr-Cyrl-RS.resx +++ b/test/Spring/Spring.Core.Tests/Resources/Spring.Context.Tests.sr-Cyrl-RS.resx @@ -1,6 +1,7 @@ - + @@ -34,10 +35,14 @@ 1.0.0.0 - System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + Ово је {0}{1} diff --git a/test/Spring/Spring.Core.Tests/Resources/Spring.Context.Tests.sr-SP-Cyrl.resx b/test/Spring/Spring.Core.Tests/Resources/Spring.Context.Tests.sr-SP-Cyrl.resx index fd7e371b..44a21ce5 100644 --- a/test/Spring/Spring.Core.Tests/Resources/Spring.Context.Tests.sr-SP-Cyrl.resx +++ b/test/Spring/Spring.Core.Tests/Resources/Spring.Context.Tests.sr-SP-Cyrl.resx @@ -1,6 +1,7 @@ - + @@ -34,10 +35,14 @@ 1.0.0.0 - System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + Ово је {0}{1} diff --git a/test/Spring/Spring.Core.Tests/Resources/Spring.Context.Tests.sr.resx b/test/Spring/Spring.Core.Tests/Resources/Spring.Context.Tests.sr.resx index b3290dff..7e02d0a3 100644 --- a/test/Spring/Spring.Core.Tests/Resources/Spring.Context.Tests.sr.resx +++ b/test/Spring/Spring.Core.Tests/Resources/Spring.Context.Tests.sr.resx @@ -1,6 +1,7 @@ - + @@ -34,10 +35,14 @@ 1.0.0.0 - System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + Ovo je {0}{1} diff --git a/test/Spring/Spring.Core.Tests/Resources/Tesla.resx b/test/Spring/Spring.Core.Tests/Resources/Tesla.resx index 4c327d8d..6a76c552 100644 --- a/test/Spring/Spring.Core.Tests/Resources/Tesla.resx +++ b/test/Spring/Spring.Core.Tests/Resources/Tesla.resx @@ -58,7 +58,8 @@ : using a System.ComponentModel.TypeConverter : and then encoded with base64 encoding. --> - + @@ -92,15 +93,21 @@ 1.3 - System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + - + True - + Private diff --git a/test/Spring/Spring.Core.Tests/Resources/Tesla.sr-Cyrl-CS.resx b/test/Spring/Spring.Core.Tests/Resources/Tesla.sr-Cyrl-CS.resx index 54318df6..188fa7d3 100644 --- a/test/Spring/Spring.Core.Tests/Resources/Tesla.sr-Cyrl-CS.resx +++ b/test/Spring/Spring.Core.Tests/Resources/Tesla.sr-Cyrl-CS.resx @@ -58,7 +58,8 @@ : using a System.ComponentModel.TypeConverter : and then encoded with base64 encoding. --> - + @@ -92,15 +93,21 @@ 1.3 - System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + - + True - + Private diff --git a/test/Spring/Spring.Core.Tests/Resources/Tesla.sr-Cyrl-RS.resx b/test/Spring/Spring.Core.Tests/Resources/Tesla.sr-Cyrl-RS.resx index 14f720e0..fddf2bd4 100644 --- a/test/Spring/Spring.Core.Tests/Resources/Tesla.sr-Cyrl-RS.resx +++ b/test/Spring/Spring.Core.Tests/Resources/Tesla.sr-Cyrl-RS.resx @@ -58,7 +58,8 @@ : using a System.ComponentModel.TypeConverter : and then encoded with base64 encoding. --> - + @@ -92,15 +93,21 @@ 1.3 - System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + - + True - + Private diff --git a/test/Spring/Spring.Core.Tests/Resources/Tesla.sr-SP-Cyrl.resx b/test/Spring/Spring.Core.Tests/Resources/Tesla.sr-SP-Cyrl.resx index 54318df6..188fa7d3 100644 --- a/test/Spring/Spring.Core.Tests/Resources/Tesla.sr-SP-Cyrl.resx +++ b/test/Spring/Spring.Core.Tests/Resources/Tesla.sr-SP-Cyrl.resx @@ -58,7 +58,8 @@ : using a System.ComponentModel.TypeConverter : and then encoded with base64 encoding. --> - + @@ -92,15 +93,21 @@ 1.3 - System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + - + True - + Private diff --git a/test/Spring/Spring.Core.Tests/Resources/Tesla.sr.resx b/test/Spring/Spring.Core.Tests/Resources/Tesla.sr.resx index f8a2665c..e1f61409 100644 --- a/test/Spring/Spring.Core.Tests/Resources/Tesla.sr.resx +++ b/test/Spring/Spring.Core.Tests/Resources/Tesla.sr.resx @@ -58,7 +58,8 @@ : using a System.ComponentModel.TypeConverter : and then encoded with base64 encoding. --> - + @@ -92,15 +93,21 @@ 1.3 - System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + - + True - + Private diff --git a/test/Spring/Spring.Core.Tests/SecurityTemplate.cs b/test/Spring/Spring.Core.Tests/SecurityTemplate.cs index b45d139d..440e0f93 100644 --- a/test/Spring/Spring.Core.Tests/SecurityTemplate.cs +++ b/test/Spring/Spring.Core.Tests/SecurityTemplate.cs @@ -32,475 +32,497 @@ using System.Web.Configuration; #pragma warning disable 618 -namespace Spring +namespace Spring; + +/// +/// Allows to invoke parts of your code within the context of a certain PermissionSet. +/// +/// +/// +/// You may also use the static method and +/// to load a instance +/// yourself and apply it on your application domain using . Note, +/// that you must set the policy *before* an assembly gets loaded to apply that policy on that assembly! +/// +/// +/// The policy file format is the one used by . +/// You get good examples from your %FrameworkDir%/CONFIG/ directory (e.g. 'web_mediumtrust.config'). +/// +/// +/// Erich Eichinger +public class SecurityTemplate { /// - /// Allows to invoke parts of your code within the context of a certain PermissionSet. + /// The default full trust permission set name ("FullTrust") /// - /// - /// - /// You may also use the static method and - /// to load a instance - /// yourself and apply it on your application domain using . Note, - /// that you must set the policy *before* an assembly gets loaded to apply that policy on that assembly! - /// - /// - /// The policy file format is the one used by . - /// You get good examples from your %FrameworkDir%/CONFIG/ directory (e.g. 'web_mediumtrust.config'). - /// - /// - /// Erich Eichinger - public class SecurityTemplate - { - /// - /// The default full trust permission set name ("FullTrust") - /// - public static readonly string PERMISSIONSET_FULLTRUST = "FullTrust"; - /// - /// The default no trust permission set name ("Nothing") - /// - public static readonly string PERMISSIONSET_NOTHING = "Nothing"; - /// - /// The default medium trust permission set name ("MediumTrust") - /// - public static readonly string PERMISSIONSET_MEDIUMTRUST = "MediumTrust"; - /// - /// The default low trust permission set name ("LowTrust") - /// - public static readonly string PERMISSIONSET_LOWTRUST = "LowTrust"; - /// - /// The default asp.net permission set name ("ASP.NET") - /// - public static readonly string PERMISSIONSET_ASPNET = "ASP.Net"; + public static readonly string PERMISSIONSET_FULLTRUST = "FullTrust"; + + /// + /// The default no trust permission set name ("Nothing") + /// + public static readonly string PERMISSIONSET_NOTHING = "Nothing"; + + /// + /// The default medium trust permission set name ("MediumTrust") + /// + public static readonly string PERMISSIONSET_MEDIUMTRUST = "MediumTrust"; + + /// + /// The default low trust permission set name ("LowTrust") + /// + public static readonly string PERMISSIONSET_LOWTRUST = "LowTrust"; + + /// + /// The default asp.net permission set name ("ASP.NET") + /// + public static readonly string PERMISSIONSET_ASPNET = "ASP.Net"; + + private readonly PolicyLevel _domainPolicy; - private readonly PolicyLevel _domainPolicy; // private readonly Dictionary securityContextCache = new Dictionary(); - private bool throwOnUnknownPermissionSet = true; + private bool throwOnUnknownPermissionSet = true; - /// - /// Avoid beforeFieldInit - /// - static SecurityTemplate() - {} + /// + /// Avoid beforeFieldInit + /// + static SecurityTemplate() + { + } - /// - /// Invoke the specified callback in a medium trusted context - /// - public static void MediumTrustInvoke( ThreadStart callback ) + /// + /// Invoke the specified callback in a medium trusted context + /// + public static void MediumTrustInvoke(ThreadStart callback) + { + SecurityTemplate template = new SecurityTemplate(true); + template.PartialTrustInvoke(PERMISSIONSET_MEDIUMTRUST, callback); + } + + /// + /// Access the domain of this instance. + /// + public PolicyLevel DomainPolicy + { + get { return _domainPolicy; } + } + + /// + /// Whether to throw an in case + /// the permission set name is not found when invoking . + /// Defaults to true. + /// + public bool ThrowOnUnknownPermissionSet + { + get { return throwOnUnknownPermissionSet; } + set { - SecurityTemplate template = new SecurityTemplate(true); - template.PartialTrustInvoke(PERMISSIONSET_MEDIUMTRUST, callback); - } - - /// - /// Access the domain of this instance. - /// - public PolicyLevel DomainPolicy - { - get { return _domainPolicy; } - } - - /// - /// Whether to throw an in case - /// the permission set name is not found when invoking . - /// Defaults to true. - /// - public bool ThrowOnUnknownPermissionSet - { - get { return throwOnUnknownPermissionSet; } - set - { - throwOnUnknownPermissionSet = value; + throwOnUnknownPermissionSet = value; // securityContextCache.Clear(); // clear cache - } + } + } + + /// + /// Creates a new instance providing default "FullTrust", "Nothing", "MediumTrust" and "LowTrust" permissionsets + /// + /// NCover requires unmangaged code permissions, set this flag true in this case. + public SecurityTemplate(bool allowUnmanagedCode) + { + PolicyLevel pLevel = PolicyLevel.CreateAppDomainLevel(); + + // NOTHING permissionset + if (null == pLevel.GetNamedPermissionSet(PERMISSIONSET_NOTHING)) + { + NamedPermissionSet noPermissionSet = new NamedPermissionSet(PERMISSIONSET_NOTHING, PermissionState.None); + noPermissionSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.NoFlags)); + pLevel.AddNamedPermissionSet(noPermissionSet); } - /// - /// Creates a new instance providing default "FullTrust", "Nothing", "MediumTrust" and "LowTrust" permissionsets - /// - /// NCover requires unmangaged code permissions, set this flag true in this case. - public SecurityTemplate(bool allowUnmanagedCode) + // FULLTRUST permissionset + if (null == pLevel.GetNamedPermissionSet(PERMISSIONSET_FULLTRUST)) { - PolicyLevel pLevel = PolicyLevel.CreateAppDomainLevel(); + NamedPermissionSet fulltrustPermissionSet = new NamedPermissionSet(PERMISSIONSET_FULLTRUST, PermissionState.Unrestricted); + pLevel.AddNamedPermissionSet(fulltrustPermissionSet); + } - // NOTHING permissionset - if (null == pLevel.GetNamedPermissionSet(PERMISSIONSET_NOTHING) ) - { - NamedPermissionSet noPermissionSet = new NamedPermissionSet(PERMISSIONSET_NOTHING, PermissionState.None); - noPermissionSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.NoFlags)); - pLevel.AddNamedPermissionSet(noPermissionSet); - } + // MEDIUMTRUST permissionset (corresponds to ASP.Net permission set in web_mediumtrust.config) + NamedPermissionSet mediumTrustPermissionSet = new NamedPermissionSet(PERMISSIONSET_MEDIUMTRUST, PermissionState.None); + mediumTrustPermissionSet.AddPermission(new AspNetHostingPermission(AspNetHostingPermissionLevel.Medium)); + mediumTrustPermissionSet.AddPermission(new DnsPermission(PermissionState.Unrestricted)); + mediumTrustPermissionSet.AddPermission(new EnvironmentPermission(EnvironmentPermissionAccess.Read, + "TEMP;TMP;USERNAME;OS;COMPUTERNAME")); + mediumTrustPermissionSet.AddPermission(new FileIOPermission(FileIOPermissionAccess.AllAccess, + AppDomain.CurrentDomain.BaseDirectory)); + IsolatedStorageFilePermission isolatedStorageFilePermission = new IsolatedStorageFilePermission(PermissionState.None); + isolatedStorageFilePermission.UsageAllowed = IsolatedStorageContainment.AssemblyIsolationByUser; + isolatedStorageFilePermission.UserQuota = 9223372036854775807; + mediumTrustPermissionSet.AddPermission(isolatedStorageFilePermission); + mediumTrustPermissionSet.AddPermission(new PrintingPermission(PrintingPermissionLevel.DefaultPrinting)); + SecurityPermissionFlag securityPermissionFlag = SecurityPermissionFlag.Assertion | SecurityPermissionFlag.Execution | + SecurityPermissionFlag.ControlThread | SecurityPermissionFlag.ControlPrincipal | + SecurityPermissionFlag.RemotingConfiguration; + if (allowUnmanagedCode) + { + securityPermissionFlag |= SecurityPermissionFlag.UnmanagedCode; + } - // FULLTRUST permissionset - if (null == pLevel.GetNamedPermissionSet(PERMISSIONSET_FULLTRUST)) - { - NamedPermissionSet fulltrustPermissionSet = new NamedPermissionSet(PERMISSIONSET_FULLTRUST, PermissionState.Unrestricted); - pLevel.AddNamedPermissionSet(fulltrustPermissionSet); - } - // MEDIUMTRUST permissionset (corresponds to ASP.Net permission set in web_mediumtrust.config) - NamedPermissionSet mediumTrustPermissionSet = new NamedPermissionSet(PERMISSIONSET_MEDIUMTRUST, PermissionState.None); - mediumTrustPermissionSet.AddPermission(new AspNetHostingPermission(AspNetHostingPermissionLevel.Medium)); - mediumTrustPermissionSet.AddPermission(new DnsPermission(PermissionState.Unrestricted)); - mediumTrustPermissionSet.AddPermission(new EnvironmentPermission(EnvironmentPermissionAccess.Read, - "TEMP;TMP;USERNAME;OS;COMPUTERNAME")); - mediumTrustPermissionSet.AddPermission(new FileIOPermission(FileIOPermissionAccess.AllAccess, - AppDomain.CurrentDomain.BaseDirectory)); - IsolatedStorageFilePermission isolatedStorageFilePermission = new IsolatedStorageFilePermission(PermissionState.None); - isolatedStorageFilePermission.UsageAllowed = IsolatedStorageContainment.AssemblyIsolationByUser; - isolatedStorageFilePermission.UserQuota = 9223372036854775807; - mediumTrustPermissionSet.AddPermission(isolatedStorageFilePermission); - mediumTrustPermissionSet.AddPermission(new PrintingPermission(PrintingPermissionLevel.DefaultPrinting)); - SecurityPermissionFlag securityPermissionFlag = SecurityPermissionFlag.Assertion | SecurityPermissionFlag.Execution | - SecurityPermissionFlag.ControlThread | SecurityPermissionFlag.ControlPrincipal | - SecurityPermissionFlag.RemotingConfiguration; - if (allowUnmanagedCode) - { - securityPermissionFlag |= SecurityPermissionFlag.UnmanagedCode; - } - mediumTrustPermissionSet.AddPermission(new SecurityPermission(securityPermissionFlag)); - mediumTrustPermissionSet.AddPermission(new System.Net.Mail.SmtpPermission(System.Net.Mail.SmtpAccess.Connect)); - mediumTrustPermissionSet.AddPermission(new SqlClientPermission(PermissionState.Unrestricted)); - mediumTrustPermissionSet.AddPermission(new WebPermission()); - pLevel.AddNamedPermissionSet(mediumTrustPermissionSet); + mediumTrustPermissionSet.AddPermission(new SecurityPermission(securityPermissionFlag)); + mediumTrustPermissionSet.AddPermission(new System.Net.Mail.SmtpPermission(System.Net.Mail.SmtpAccess.Connect)); + mediumTrustPermissionSet.AddPermission(new SqlClientPermission(PermissionState.Unrestricted)); + mediumTrustPermissionSet.AddPermission(new WebPermission()); + pLevel.AddNamedPermissionSet(mediumTrustPermissionSet); - // LOWTRUST permissionset (corresponds to ASP.Net permission set in web_mediumtrust.config) - NamedPermissionSet lowTrustPermissionSet = new NamedPermissionSet(PERMISSIONSET_LOWTRUST, PermissionState.None); - lowTrustPermissionSet.AddPermission(new AspNetHostingPermission(AspNetHostingPermissionLevel.Low)); - lowTrustPermissionSet.AddPermission(new FileIOPermission(FileIOPermissionAccess.Read|FileIOPermissionAccess.PathDiscovery, - AppDomain.CurrentDomain.BaseDirectory)); - IsolatedStorageFilePermission isolatedStorageFilePermissionLow = new IsolatedStorageFilePermission(PermissionState.None); - isolatedStorageFilePermissionLow.UsageAllowed = IsolatedStorageContainment.AssemblyIsolationByUser; - isolatedStorageFilePermissionLow.UserQuota = 1048576; - lowTrustPermissionSet.AddPermission(isolatedStorageFilePermissionLow); - SecurityPermissionFlag securityPermissionFlagLow = SecurityPermissionFlag.Execution; - if (allowUnmanagedCode) - { - securityPermissionFlagLow |= SecurityPermissionFlag.UnmanagedCode; - } - lowTrustPermissionSet.AddPermission(new SecurityPermission(securityPermissionFlagLow)); - pLevel.AddNamedPermissionSet(lowTrustPermissionSet); + // LOWTRUST permissionset (corresponds to ASP.Net permission set in web_mediumtrust.config) + NamedPermissionSet lowTrustPermissionSet = new NamedPermissionSet(PERMISSIONSET_LOWTRUST, PermissionState.None); + lowTrustPermissionSet.AddPermission(new AspNetHostingPermission(AspNetHostingPermissionLevel.Low)); + lowTrustPermissionSet.AddPermission(new FileIOPermission(FileIOPermissionAccess.Read | FileIOPermissionAccess.PathDiscovery, + AppDomain.CurrentDomain.BaseDirectory)); + IsolatedStorageFilePermission isolatedStorageFilePermissionLow = new IsolatedStorageFilePermission(PermissionState.None); + isolatedStorageFilePermissionLow.UsageAllowed = IsolatedStorageContainment.AssemblyIsolationByUser; + isolatedStorageFilePermissionLow.UserQuota = 1048576; + lowTrustPermissionSet.AddPermission(isolatedStorageFilePermissionLow); + SecurityPermissionFlag securityPermissionFlagLow = SecurityPermissionFlag.Execution; + if (allowUnmanagedCode) + { + securityPermissionFlagLow |= SecurityPermissionFlag.UnmanagedCode; + } + + lowTrustPermissionSet.AddPermission(new SecurityPermission(securityPermissionFlagLow)); + pLevel.AddNamedPermissionSet(lowTrustPermissionSet); // UnionCodeGroup rootCodeGroup = new UnionCodeGroup(new AllMembershipCondition(), new PolicyStatement(noPermissionSet, PolicyStatementAttribute.Nothing)); // pLevel.RootCodeGroup = rootCodeGroup; - _domainPolicy = pLevel; - } + _domainPolicy = pLevel; + } - /// - /// Loads domain policy from specified file - /// - /// - public SecurityTemplate(FileInfo securityConfigurationFile) - { - string appDirectory = AppDomain.CurrentDomain.BaseDirectory; - _domainPolicy = LoadDomainPolicyFromUri(new Uri(securityConfigurationFile.FullName), appDirectory, string.Empty); - } + /// + /// Loads domain policy from specified file + /// + /// + public SecurityTemplate(FileInfo securityConfigurationFile) + { + string appDirectory = AppDomain.CurrentDomain.BaseDirectory; + _domainPolicy = LoadDomainPolicyFromUri(new Uri(securityConfigurationFile.FullName), appDirectory, string.Empty); + } - /// - /// Create a security tool from the specified domainPolicy - /// - public SecurityTemplate(PolicyLevel domainPolicy) - { - this._domainPolicy = domainPolicy; - } + /// + /// Create a security tool from the specified domainPolicy + /// + public SecurityTemplate(PolicyLevel domainPolicy) + { + this._domainPolicy = domainPolicy; + } - /// - /// Invokes the given callback using the policy's default - /// partial trust permissionset ("ASP.Net" ). - /// + /// + /// Invokes the given callback using the policy's default + /// partial trust permissionset ("ASP.Net" ). + /// // [SecurityTreatAsSafe, SecurityCritical] - public void PartialTrustInvoke(ThreadStart callback) + public void PartialTrustInvoke(ThreadStart callback) + { + string defaultPermissionSetName = PERMISSIONSET_MEDIUMTRUST; + if (null != GetNamedPermissionSet(PERMISSIONSET_ASPNET)) { - string defaultPermissionSetName = PERMISSIONSET_MEDIUMTRUST; - if (null != GetNamedPermissionSet(PERMISSIONSET_ASPNET)) - { - defaultPermissionSetName = PERMISSIONSET_ASPNET; - } - - PartialTrustInvoke(defaultPermissionSetName, callback); + defaultPermissionSetName = PERMISSIONSET_ASPNET; } - /// - /// Invokes the given callback using the specified permissionset. - /// + PartialTrustInvoke(defaultPermissionSetName, callback); + } + + /// + /// Invokes the given callback using the specified permissionset. + /// // [SecurityTreatAsSafe, SecurityCritical] - public void PartialTrustInvoke(string permissionSetName, ThreadStart callback) + public void PartialTrustInvoke(string permissionSetName, ThreadStart callback) + { + PermissionSet ps = null; + ps = GetNamedPermissionSet(permissionSetName); + if (ps == null && throwOnUnknownPermissionSet) { - PermissionSet ps = null; - ps = GetNamedPermissionSet(permissionSetName); - if (ps == null && throwOnUnknownPermissionSet) - { - throw new ArgumentOutOfRangeException("permissionSetName", permissionSetName, - string.Format("unknown PermissionSet name '{0}'", - permissionSetName)); - } - - if (!IsFullTrust(ps)) - { - ps.PermitOnly(); - callback(); - CodeAccessPermission.RevertPermitOnly(); - } - else - { - callback(); - } + throw new ArgumentOutOfRangeException("permissionSetName", permissionSetName, + string.Format("unknown PermissionSet name '{0}'", + permissionSetName)); } - private PermissionSet GetNamedPermissionSet(string name) + if (!IsFullTrust(ps)) + { + ps.PermitOnly(); + callback(); + CodeAccessPermission.RevertPermitOnly(); + } + else + { + callback(); + } + } + + private PermissionSet GetNamedPermissionSet(string name) + { + if (_domainPolicy != null) + { + return _domainPolicy.GetNamedPermissionSet(name); + } + + return null; + } + +#if !MONO + /// + /// Loads the policy configuration from app.config configuration section + /// + /// + /// Configuration is identical to web.config: + /// + /// <configuration> + /// <system.web> + /// <securityPolicy> + /// <trustLevel name="Full" policyFile="internal"/> + /// <trustLevel name="High" policyFile="web_hightrust.config"/> + /// <trustLevel name="Medium" policyFile="web_mediumtrust.config"/> + /// <trustLevel name="Low" policyFile="web_lowtrust.config"/> + /// <trustLevel name="Minimal" policyFile="web_minimaltrust.config"/> + /// </securityPolicy> + /// <trust level="Medium" originUrl=""/> + /// </system.web> + /// </configuration> + /// + /// + /// + /// + public static PolicyLevel LoadDomainPolicyFromAppConfig(bool throwOnError) + { + TrustSection trustSection = (TrustSection) ConfigurationManager.GetSection("system.web/trust"); + SecurityPolicySection securityPolicySection = (SecurityPolicySection) ConfigurationManager.GetSection("system.web/securityPolicy"); + + if ((trustSection == null) || string.IsNullOrEmpty(trustSection.Level)) + { + if (!throwOnError) return null; + throw new ConfigurationErrorsException("Configuration section not found "); + } + + if (trustSection.Level == "Full") { - if (_domainPolicy != null) - { - return _domainPolicy.GetNamedPermissionSet(name); - } return null; } -#if !MONO - /// - /// Loads the policy configuration from app.config configuration section - /// - /// - /// Configuration is identical to web.config: - /// - /// <configuration> - /// <system.web> - /// <securityPolicy> - /// <trustLevel name="Full" policyFile="internal"/> - /// <trustLevel name="High" policyFile="web_hightrust.config"/> - /// <trustLevel name="Medium" policyFile="web_mediumtrust.config"/> - /// <trustLevel name="Low" policyFile="web_lowtrust.config"/> - /// <trustLevel name="Minimal" policyFile="web_minimaltrust.config"/> - /// </securityPolicy> - /// <trust level="Medium" originUrl=""/> - /// </system.web> - /// </configuration> - /// - /// - /// - /// - public static PolicyLevel LoadDomainPolicyFromAppConfig(bool throwOnError) + if ((securityPolicySection == null) || (securityPolicySection.TrustLevels[trustSection.Level] == null)) { - TrustSection trustSection = (TrustSection)ConfigurationManager.GetSection("system.web/trust"); - SecurityPolicySection securityPolicySection = (SecurityPolicySection)ConfigurationManager.GetSection("system.web/securityPolicy"); + if (!throwOnError) return null; + throw new ConfigurationErrorsException(string.Format("configuration not found", trustSection.Level)); + } - if ((trustSection == null) || string.IsNullOrEmpty(trustSection.Level)) + string policyFileExpanded = GetPolicyFilenameExpanded(securityPolicySection.TrustLevels[trustSection.Level]); + string appDirectory = AppDomain.CurrentDomain.BaseDirectory; + PolicyLevel domainPolicy = LoadDomainPolicyFromUri(new Uri(policyFileExpanded), appDirectory, trustSection.OriginUrl); + return domainPolicy; + } +#endif + /// + /// Loads a policy from a file (), + /// replacing placeholders + /// + /// $AppDir$, $AppDirUrl$ => + /// $CodeGen$ => (TODO) + /// $OriginHost$ => + /// $Gac$ => the current machine's GAC path + /// + /// + /// + /// + /// + /// + public static PolicyLevel LoadDomainPolicyFromUri(Uri policyFileLocation, string appDirectory, string originUrl) + { + bool foundGacToken = false; + PolicyLevel domainPolicy = CreatePolicyLevel(policyFileLocation, appDirectory, appDirectory, originUrl, out foundGacToken); + if (foundGacToken) + { + CodeGroup rootCodeGroup = domainPolicy.RootCodeGroup; + bool hasGacMembershipCondition = false; + foreach (CodeGroup childCodeGroup in rootCodeGroup.Children) { - if (!throwOnError) return null; - throw new ConfigurationErrorsException("Configuration section not found "); + if (childCodeGroup.MembershipCondition is GacMembershipCondition) + { + hasGacMembershipCondition = true; + break; + } } - if (trustSection.Level == "Full") - { + if (!hasGacMembershipCondition && (rootCodeGroup is FirstMatchCodeGroup)) + { + FirstMatchCodeGroup firstMatchCodeGroup = (FirstMatchCodeGroup) rootCodeGroup; + if ((firstMatchCodeGroup.MembershipCondition is AllMembershipCondition) && (firstMatchCodeGroup.PermissionSetName == PERMISSIONSET_NOTHING)) + { + PermissionSet unrestrictedPermissionSet = new PermissionSet(PermissionState.Unrestricted); + CodeGroup gacGroup = new UnionCodeGroup(new GacMembershipCondition(), new PolicyStatement(unrestrictedPermissionSet)); + CodeGroup rootGroup = new FirstMatchCodeGroup(rootCodeGroup.MembershipCondition, rootCodeGroup.PolicyStatement); + foreach (CodeGroup childGroup in rootCodeGroup.Children) + { + if (((childGroup is UnionCodeGroup) && (childGroup.MembershipCondition is UrlMembershipCondition)) && (childGroup.PolicyStatement.PermissionSet.IsUnrestricted() && (gacGroup != null))) + { + rootGroup.AddChild(gacGroup); + gacGroup = null; + } + + rootGroup.AddChild(childGroup); + } + + domainPolicy.RootCodeGroup = rootGroup; + } + } + } + + return domainPolicy; + } + + private static PolicyLevel CreatePolicyLevel(Uri configFile, string appDir, string binDir, string strOriginUrl, out bool foundGacToken) + { + WebClient webClient = new WebClient(); + string strXmlPolicy = webClient.DownloadString(configFile); + appDir = FileUtil.RemoveTrailingDirectoryBackSlash(appDir); + binDir = FileUtil.RemoveTrailingDirectoryBackSlash(binDir); + strXmlPolicy = strXmlPolicy.Replace("$AppDir$", appDir).Replace("$AppDirUrl$", MakeFileUrl(appDir)).Replace("$CodeGen$", MakeFileUrl(binDir)); + if (strOriginUrl == null) + { + strOriginUrl = string.Empty; + } + + strXmlPolicy = strXmlPolicy.Replace("$OriginHost$", strOriginUrl); + if (strXmlPolicy.IndexOf("$Gac$", StringComparison.Ordinal) != -1) + { + string gacLocation = GetGacLocation(); + if (gacLocation != null) + { + gacLocation = MakeFileUrl(gacLocation); + } + + if (gacLocation == null) + { + gacLocation = string.Empty; + } + + strXmlPolicy = strXmlPolicy.Replace("$Gac$", gacLocation); + foundGacToken = true; + } + else + { + foundGacToken = false; + } + + return SecurityManager.LoadPolicyLevelFromString(strXmlPolicy, PolicyLevelType.AppDomain); + } +#if !MONO + private static string GetPolicyFilenameExpanded(TrustLevel trustLevel) + { + bool isRelative = true; + if (trustLevel.PolicyFile.Length > 1) + { + char ch = trustLevel.PolicyFile[1]; + char ch2 = trustLevel.PolicyFile[0]; + if (ch == ':') + { + isRelative = false; + } + else if ((ch2 == '\\') && (ch == '\\')) + { + isRelative = false; + } + } + + if (isRelative) + { + string configurationElementFileSource = trustLevel.ElementInformation.Properties["policyFile"].Source; + string path = configurationElementFileSource.Substring(0, configurationElementFileSource.LastIndexOf('\\') + 1); + return path + trustLevel.PolicyFile; + } + + return trustLevel.PolicyFile; + } +#endif + [DllImport("mscorwks.dll", CharSet = CharSet.Unicode)] + private static extern int GetCachePath(int dwCacheFlags, StringBuilder pwzCachePath, ref int pcchPath); + + private static string GetGacLocation() + { + int capacity = 0x106; + StringBuilder pwzCachePath = new StringBuilder(capacity); + int pcchPath = capacity - 2; + int hRes = GetCachePath(2, pwzCachePath, ref pcchPath); + if (hRes < 0) + { + throw new HttpException("failed obtaining GAC path", hRes); + } + + return pwzCachePath.ToString(); + } + + private static string MakeFileUrl(string path) + { + Uri uri = new Uri(path); + return uri.ToString(); + } + + private class FileUtil + { + internal static string RemoveTrailingDirectoryBackSlash(string path) + { + if (path == null) + { return null; } - if ((securityPolicySection == null) || (securityPolicySection.TrustLevels[trustSection.Level] == null)) + int length = path.Length; + if ((length > 3) && (path[length - 1] == '\\')) { - if (!throwOnError) return null; - throw new ConfigurationErrorsException(string.Format("configuration not found", trustSection.Level)); + path = path.Substring(0, length - 1); } - string policyFileExpanded = GetPolicyFilenameExpanded(securityPolicySection.TrustLevels[trustSection.Level]); - string appDirectory = AppDomain.CurrentDomain.BaseDirectory; - PolicyLevel domainPolicy = LoadDomainPolicyFromUri(new Uri(policyFileExpanded), appDirectory, trustSection.OriginUrl); - return domainPolicy; + return path; } -#endif - /// - /// Loads a policy from a file (), - /// replacing placeholders - /// - /// $AppDir$, $AppDirUrl$ => - /// $CodeGen$ => (TODO) - /// $OriginHost$ => - /// $Gac$ => the current machine's GAC path - /// - /// - /// - /// - /// - /// - public static PolicyLevel LoadDomainPolicyFromUri(Uri policyFileLocation, string appDirectory, string originUrl) + } + + private static bool IsFullTrust(PermissionSet perms) + { + if (perms != null) { - bool foundGacToken = false; - PolicyLevel domainPolicy = CreatePolicyLevel(policyFileLocation, appDirectory, appDirectory, originUrl, out foundGacToken); - if (foundGacToken) - { - CodeGroup rootCodeGroup = domainPolicy.RootCodeGroup; - bool hasGacMembershipCondition = false; - foreach (CodeGroup childCodeGroup in rootCodeGroup.Children) - { - if (childCodeGroup.MembershipCondition is GacMembershipCondition) - { - hasGacMembershipCondition = true; - break; - } - } - if (!hasGacMembershipCondition && (rootCodeGroup is FirstMatchCodeGroup)) - { - FirstMatchCodeGroup firstMatchCodeGroup = (FirstMatchCodeGroup)rootCodeGroup; - if ((firstMatchCodeGroup.MembershipCondition is AllMembershipCondition) && (firstMatchCodeGroup.PermissionSetName == PERMISSIONSET_NOTHING)) - { - PermissionSet unrestrictedPermissionSet = new PermissionSet(PermissionState.Unrestricted); - CodeGroup gacGroup = new UnionCodeGroup(new GacMembershipCondition(), new PolicyStatement(unrestrictedPermissionSet)); - CodeGroup rootGroup = new FirstMatchCodeGroup(rootCodeGroup.MembershipCondition, rootCodeGroup.PolicyStatement); - foreach (CodeGroup childGroup in rootCodeGroup.Children) - { - if (((childGroup is UnionCodeGroup) && (childGroup.MembershipCondition is UrlMembershipCondition)) && (childGroup.PolicyStatement.PermissionSet.IsUnrestricted() && (gacGroup != null))) - { - rootGroup.AddChild(gacGroup); - gacGroup = null; - } - rootGroup.AddChild(childGroup); - } - domainPolicy.RootCodeGroup = rootGroup; - } - } - } - return domainPolicy; + return perms.IsUnrestricted(); } - private static PolicyLevel CreatePolicyLevel(Uri configFile, string appDir, string binDir, string strOriginUrl, out bool foundGacToken) - { - WebClient webClient = new WebClient(); - string strXmlPolicy = webClient.DownloadString(configFile); - appDir = FileUtil.RemoveTrailingDirectoryBackSlash(appDir); - binDir = FileUtil.RemoveTrailingDirectoryBackSlash(binDir); - strXmlPolicy = strXmlPolicy.Replace("$AppDir$", appDir).Replace("$AppDirUrl$", MakeFileUrl(appDir)).Replace("$CodeGen$", MakeFileUrl(binDir)); - if (strOriginUrl == null) - { - strOriginUrl = string.Empty; - } - strXmlPolicy = strXmlPolicy.Replace("$OriginHost$", strOriginUrl); - if (strXmlPolicy.IndexOf("$Gac$", StringComparison.Ordinal) != -1) - { - string gacLocation = GetGacLocation(); - if (gacLocation != null) - { - gacLocation = MakeFileUrl(gacLocation); - } - if (gacLocation == null) - { - gacLocation = string.Empty; - } - strXmlPolicy = strXmlPolicy.Replace("$Gac$", gacLocation); - foundGacToken = true; - } - else - { - foundGacToken = false; - } - return SecurityManager.LoadPolicyLevelFromString(strXmlPolicy, PolicyLevelType.AppDomain); - } -#if !MONO - private static string GetPolicyFilenameExpanded(TrustLevel trustLevel) - { - bool isRelative = true; - if (trustLevel.PolicyFile.Length > 1) - { - char ch = trustLevel.PolicyFile[1]; - char ch2 = trustLevel.PolicyFile[0]; - if (ch == ':') - { - isRelative = false; - } - else if ((ch2 == '\\') && (ch == '\\')) - { - isRelative = false; - } - } - - if (isRelative) - { - string configurationElementFileSource = trustLevel.ElementInformation.Properties["policyFile"].Source; - string path = configurationElementFileSource.Substring(0, configurationElementFileSource.LastIndexOf('\\') + 1); - return path + trustLevel.PolicyFile; - } - return trustLevel.PolicyFile; - } -#endif - [DllImport("mscorwks.dll", CharSet = CharSet.Unicode)] - private static extern int GetCachePath(int dwCacheFlags, StringBuilder pwzCachePath, ref int pcchPath); - - private static string GetGacLocation() - { - int capacity = 0x106; - StringBuilder pwzCachePath = new StringBuilder(capacity); - int pcchPath = capacity - 2; - int hRes = GetCachePath(2, pwzCachePath, ref pcchPath); - if (hRes < 0) - { - throw new HttpException("failed obtaining GAC path", hRes); - } - return pwzCachePath.ToString(); - } - - private static string MakeFileUrl(string path) - { - Uri uri = new Uri(path); - return uri.ToString(); - } - - private class FileUtil - { - internal static string RemoveTrailingDirectoryBackSlash(string path) - { - if (path == null) - { - return null; - } - int length = path.Length; - if ((length > 3) && (path[length - 1] == '\\')) - { - path = path.Substring(0, length - 1); - } - return path; - } - } - - private static bool IsFullTrust(PermissionSet perms) - { - if (perms != null) - { - return perms.IsUnrestricted(); - } - return true; - } - - // [SecurityTreatAsSafe, SecurityCritical] - // private bool NeedPartialTrustInvoke(string permissionSetName) - // { - // if (_domainPolicy == null) return false; - // - // SecurityContext securityContext = null; - // if (!securityContextCache.ContainsKey(permissionSetName)) - // { - // NamedPermissionSet permissionSet = _domainPolicy.GetNamedPermissionSet(permissionSetName); - // if (permissionSet == null && throwOnUnknownPermissionSet) - // { - // throw new ArgumentOutOfRangeException("permissionSetName", permissionSetName, "Undefined permission set"); - // } - // if (!IsFullTrust(permissionSet)) - // { - // try - // { - // permissionSet.PermitOnly(); - // securityContext = CaptureSecurityContextNoIdentityFlow(); - // } - // finally - // { - // CodeAccessPermission.RevertPermitOnly(); - // } - // } - // securityContextCache[permissionSetName] = securityContext; - // } - // else - // { - // securityContext = securityContextCache[permissionSetName]; - // } - // return (securityContext != null); - // } + return true; + } + // [SecurityTreatAsSafe, SecurityCritical] + // private bool NeedPartialTrustInvoke(string permissionSetName) + // { + // if (_domainPolicy == null) return false; + // + // SecurityContext securityContext = null; + // if (!securityContextCache.ContainsKey(permissionSetName)) + // { + // NamedPermissionSet permissionSet = _domainPolicy.GetNamedPermissionSet(permissionSetName); + // if (permissionSet == null && throwOnUnknownPermissionSet) + // { + // throw new ArgumentOutOfRangeException("permissionSetName", permissionSetName, "Undefined permission set"); + // } + // if (!IsFullTrust(permissionSet)) + // { + // try + // { + // permissionSet.PermitOnly(); + // securityContext = CaptureSecurityContextNoIdentityFlow(); + // } + // finally + // { + // CodeAccessPermission.RevertPermitOnly(); + // } + // } + // securityContextCache[permissionSetName] = securityContext; + // } + // else + // { + // securityContext = securityContextCache[permissionSetName]; + // } + // return (securityContext != null); + // } // [SecurityCritical] // private static SecurityContext CaptureSecurityContextNoIdentityFlow() @@ -514,6 +536,5 @@ namespace Spring // return SecurityContext.Capture(); // } // } - } } #pragma warning restore 618 diff --git a/test/Spring/Spring.Core.Tests/StandardsComplianceTest.cs b/test/Spring/Spring.Core.Tests/StandardsComplianceTest.cs index f3a53747..bd745bc4 100644 --- a/test/Spring/Spring.Core.Tests/StandardsComplianceTest.cs +++ b/test/Spring/Spring.Core.Tests/StandardsComplianceTest.cs @@ -24,71 +24,89 @@ using System.Reflection; #endregion -namespace Spring +namespace Spring; + +/// +/// Base class for tests that check standards compliance. +/// +public abstract class StandardsComplianceTest { - /// - /// Base class for tests that check standards compliance. - /// - public abstract class StandardsComplianceTest + #region Constructor (s) / Destructor + + /// + /// Creates a new instance of the + /// class. + /// + /// + /// + /// This is an class, and as such has no publicly visible + /// constructors. + /// + /// + protected StandardsComplianceTest() { } + + #endregion + + #region Properties + + protected Type CheckedType { - #region Constructor (s) / Destructor - /// - /// Creates a new instance of the - /// class. - /// - /// - /// - /// This is an class, and as such has no publicly visible - /// constructors. - /// - /// - protected StandardsComplianceTest () {} - #endregion - - #region Properties - protected Type CheckedType { - get { - return checkedType; - } - set { - checkedType = value; - } + get + { + return checkedType; } - #endregion + set + { + checkedType = value; + } + } - private bool IsCheckedType (Type type) { - if (CheckedType.IsInterface) { - Type iface = type.GetInterface (CheckedType.Name, false); - return iface != null; - } else { - Type baseType = null; - while ((baseType = type.BaseType) != null) { - if (baseType == CheckedType) { - return true; - } - type = baseType; + #endregion + + private bool IsCheckedType(Type type) + { + if (CheckedType.IsInterface) + { + Type iface = type.GetInterface(CheckedType.Name, false); + return iface != null; + } + else + { + Type baseType = null; + while ((baseType = type.BaseType) != null) + { + if (baseType == CheckedType) + { + return true; } - } - return false; - } - protected void ProcessAssembly (Assembly a) { - foreach (Type t in a.GetTypes ()) { - - // TODO: make antlr compliant - if (t.FullName.IndexOf(".antlr.")>-1) continue; - - if ( (t.IsPublic||t.IsNestedPublic) - && IsCheckedType (t)) { - CheckStandardsCompliance (a, t); - } + type = baseType; } } - protected abstract void CheckStandardsCompliance (Assembly assembly, Type t); + return false; + } - #region Fields - private Type checkedType; - #endregion - } + protected void ProcessAssembly(Assembly a) + { + foreach (Type t in a.GetTypes()) + { + // TODO: make antlr compliant + if (t.FullName.IndexOf(".antlr.") > -1) continue; + + if ((t.IsPublic || t.IsNestedPublic) + && IsCheckedType(t)) + { + CheckStandardsCompliance(a, t); + } + } + } + + protected abstract void CheckStandardsCompliance(Assembly assembly, Type t); + + #region Fields + + private Type checkedType; + + #endregion } diff --git a/test/Spring/Spring.Core.Tests/StopWatch.cs b/test/Spring/Spring.Core.Tests/StopWatch.cs index 842e3f02..f0ff9af6 100644 --- a/test/Spring/Spring.Core.Tests/StopWatch.cs +++ b/test/Spring/Spring.Core.Tests/StopWatch.cs @@ -22,76 +22,75 @@ #endregion -namespace Spring +namespace Spring; + +/// +/// A simple StopWatch implemetion for use in Performance Tests +/// +/// +/// The following example shows the usage: +/// +/// StopWatch watch = new StopWatch(); +/// using (watch.Start("Duration: {0}")) +/// { +/// // do some work... +/// } +/// +/// The format string passed to the start method is used to print the result message. +/// The example above will print Duration: 0.123s. +/// +/// Erich Eichinger +public class StopWatch { - /// - /// A simple StopWatch implemetion for use in Performance Tests - /// - /// - /// The following example shows the usage: - /// - /// StopWatch watch = new StopWatch(); - /// using (watch.Start("Duration: {0}")) - /// { - /// // do some work... - /// } - /// - /// The format string passed to the start method is used to print the result message. - /// The example above will print Duration: 0.123s. - /// - /// Erich Eichinger - public class StopWatch + private DateTime _startTime; + private TimeSpan _elapsed; + + private class Stopper : IDisposable { - private DateTime _startTime; - private TimeSpan _elapsed; + private readonly StopWatch _owner; + private readonly string _format; - private class Stopper : IDisposable + public Stopper(StopWatch owner, string format) { - private readonly StopWatch _owner; - private readonly string _format; - - public Stopper(StopWatch owner, string format) - { - _owner = owner; - _format = format; - } - - public void Dispose() - { - _owner.Stop(_format); - GC.SuppressFinalize(this); - } + _owner = owner; + _format = format; } - /// - /// Starts the timer and returns and "handle" that must be disposed to stop the timer. - /// - /// the output format string, that is used to render the result message. Use '{0}' to print the elapsed timespan. - /// the handle to dispose for stopping the timer - public IDisposable Start(string outputFormat) + public void Dispose() { - Stopper stopper = new Stopper(this, outputFormat); - _startTime = DateTime.Now; - return stopper; - } - - private void Stop(string outputFormat) - { - _elapsed = DateTime.Now.Subtract(_startTime); - if (outputFormat != null) - { - Console.WriteLine(outputFormat, _elapsed); - } - } - - public DateTime StartTime - { - get { return _startTime; } - } - - public TimeSpan Elapsed - { - get { return _elapsed; } + _owner.Stop(_format); + GC.SuppressFinalize(this); } } -} \ No newline at end of file + + /// + /// Starts the timer and returns and "handle" that must be disposed to stop the timer. + /// + /// the output format string, that is used to render the result message. Use '{0}' to print the elapsed timespan. + /// the handle to dispose for stopping the timer + public IDisposable Start(string outputFormat) + { + Stopper stopper = new Stopper(this, outputFormat); + _startTime = DateTime.Now; + return stopper; + } + + private void Stop(string outputFormat) + { + _elapsed = DateTime.Now.Subtract(_startTime); + if (outputFormat != null) + { + Console.WriteLine(outputFormat, _elapsed); + } + } + + public DateTime StartTime + { + get { return _startTime; } + } + + public TimeSpan Elapsed + { + get { return _elapsed; } + } +} diff --git a/test/Spring/Spring.Core.Tests/StreamHelperDecorator.cs b/test/Spring/Spring.Core.Tests/StreamHelperDecorator.cs index 8b5d9e82..589acce3 100644 --- a/test/Spring/Spring.Core.Tests/StreamHelperDecorator.cs +++ b/test/Spring/Spring.Core.Tests/StreamHelperDecorator.cs @@ -18,43 +18,42 @@ #endregion -namespace Spring +namespace Spring; + +public delegate void StreamHelperCallback(out Stream stream); + +/// +/// Helper class for template style Stream usage. +/// +/// Rick Evans +public class StreamHelperDecorator { - public delegate void StreamHelperCallback(out Stream stream); + private StreamHelperCallback callback; - /// - /// Helper class for template style Stream usage. - /// - /// Rick Evans - public class StreamHelperDecorator + public StreamHelperDecorator(StreamHelperCallback callback) { - private StreamHelperCallback callback; + this.callback = callback; + } - public StreamHelperDecorator(StreamHelperCallback callback) + public void Run() + { + Stream stream = null; + try { - this.callback = callback; + this.callback(out stream); } - - public void Run() + finally { - Stream stream = null; - try + if (stream != null) { - this.callback(out stream); - } - finally - { - if (stream != null) + try + { + stream.Close(); + } + catch { - try - { - stream.Close(); - } - catch - { - } } } } } -} \ No newline at end of file +} diff --git a/test/Spring/Spring.Core.Tests/TestAssemblySetup.cs b/test/Spring/Spring.Core.Tests/TestAssemblySetup.cs index be8691a0..4123b970 100644 --- a/test/Spring/Spring.Core.Tests/TestAssemblySetup.cs +++ b/test/Spring/Spring.Core.Tests/TestAssemblySetup.cs @@ -24,4 +24,4 @@ namespace Spring } } } -} \ No newline at end of file +} diff --git a/test/Spring/Spring.Core.Tests/TestResourceLoader.cs b/test/Spring/Spring.Core.Tests/TestResourceLoader.cs index 674466f1..120b034d 100644 --- a/test/Spring/Spring.Core.Tests/TestResourceLoader.cs +++ b/test/Spring/Spring.Core.Tests/TestResourceLoader.cs @@ -6,192 +6,195 @@ using System.Xml.Schema; using NUnit.Framework; using Spring.Core.IO; -namespace Spring +namespace Spring; + +/// +/// Supports obtaining embedded resources from assembly. +/// +/// +/// +/// The first context argument is always the namespace scope to be used for resolving resource names. +/// +/// +/// Upon first usage, TestResourceLoader registers the "testres://" protocol prefix for loading embedded resources. +/// A testres:// Url must be of the form "testres://./<context-typename>#<ext" - . +/// +/// +public class TestResourceLoader { - /// - /// Supports obtaining embedded resources from assembly. - /// - /// - /// - /// The first context argument is always the namespace scope to be used for resolving resource names. - /// - /// - /// Upon first usage, TestResourceLoader registers the "testres://" protocol prefix for loading embedded resources. - /// A testres:// Url must be of the form "testres://./<context-typename>#<ext" - . - /// - /// - public class TestResourceLoader + #region WebRequest + + public class TestResourceWebResponse : WebResponse { - #region WebRequest + private Type resourceType; + private string resourceName; - public class TestResourceWebResponse : WebResponse + public TestResourceWebResponse(Uri requestUri) { - private Type resourceType; - private string resourceName; - - public TestResourceWebResponse(Uri requestUri) - { - string typeName = HttpUtility.UrlDecode(requestUri.AbsolutePath.Substring(1)); // strip leading '/' - resourceType = Type.GetType(typeName, true); - resourceName = HttpUtility.UrlDecode(requestUri.Fragment.Substring(1)); // strip leading '#' - } - - public override System.IO.Stream GetResponseStream() - { - Stream stm = TestResourceLoader.GetStream(resourceType, resourceName); - return stm; - } + string typeName = HttpUtility.UrlDecode(requestUri.AbsolutePath.Substring(1)); // strip leading '/' + resourceType = Type.GetType(typeName, true); + resourceName = HttpUtility.UrlDecode(requestUri.Fragment.Substring(1)); // strip leading '#' } - #pragma warning disable SYSLIB0014 // WebRequest is obsolete - public class TestResourceWebRequest : WebRequest + public override System.IO.Stream GetResponseStream() { - private Uri requestUri; - - public TestResourceWebRequest(Uri requestUri) - { - this.requestUri = requestUri; - } - - public override WebResponse GetResponse() - { - return new TestResourceWebResponse(requestUri); - } - } - #pragma warning restore SYSLIB0014 // WebRequest is obsolete - - public class TestResourceWebRequestFactory : IWebRequestCreate - { - public WebRequest Create(Uri uri) - { - return new TestResourceWebRequest(uri); - } - } - - #endregion - - static TestResourceLoader() - { - WebRequest.RegisterPrefix("testres", new TestResourceWebRequestFactory()); - } - - private TestResourceLoader() - { } - - /// - /// Returns an Uri of the form "testres://./resourcname" that may be passed into etc. - /// - /// - /// - /// - public static Uri GetUri(object context, string ext) - { - string resname = context.GetType().AssemblyQualifiedName + "#" + ext; - Uri uri = new Uri("testres://inline/" + resname); - return uri; - } - - public static string GetText(object context, string ext) - { - Stream stm = GetStream(context, ext); - return new StreamReader(stm).ReadToEnd(); - } - - public static XmlDocument GetXml(object context, string ext) - { - Stream stm = GetStream(context, ext); - XmlDocument xmlDoc = new XmlDocument(); - xmlDoc.Load(stm); - return xmlDoc; - } - - public static XmlDocument GetXmlValidated(object context, string ext, params IResource[] schemaResources) - { - using (Stream stm = GetStream(context, ext)) - { - - XmlReaderSettings settings = new XmlReaderSettings(); - settings.ValidationType = ValidationType.Schema; - XmlSchemaSet schemas = settings.Schemas; - - foreach (IResource schemaResource in schemaResources) - { - XmlDocument schemaDoc = new XmlDocument(); - using (Stream inputStream = schemaResource.InputStream) - { - schemaDoc.Load(inputStream); - } - XmlElement root = schemaDoc.DocumentElement; - string targetNamespace = root.GetAttribute("targetNamespace", string.Empty); - schemas.Add(targetNamespace, new XmlNodeReader(schemaDoc)); - } - - XmlReader validatingReader = XmlReader.Create(stm, settings); - XmlDocument xmlDoc = new XmlDocument(); - xmlDoc.Load(validatingReader); - validatingReader.Close(); - return xmlDoc; - } - } - - /// - /// Returns an embedded assembly resource, who's name is constructed from the given parameters as - /// context.GetType().FullName + ext - /// - public static Stream GetStream(object context, string ext) - { - Type contextType = (context is Type) ? (Type)context : context.GetType(); - string resname = contextType.FullName + ext; - Stream stm = contextType.Assembly.GetManifestResourceStream(resname); - Assert.IsNotNull(stm, "Resource '{0}' in assembly '{1}' not found", resname, contextType.Assembly.FullName); + Stream stm = TestResourceLoader.GetStream(resourceType, resourceName); return stm; } + } - /// - /// Exports a resource obtained via to the specified destination. - /// - public static FileInfo ExportResource(object context, string ext, FileInfo destination) +#pragma warning disable SYSLIB0014 // WebRequest is obsolete + public class TestResourceWebRequest : WebRequest + { + private Uri requestUri; + + public TestResourceWebRequest(Uri requestUri) { - Stream istm = GetStream(context, ext); - using(istm) - { - FileStream ostm = destination.OpenWrite(); - using (ostm) - { - byte[] buffer = new byte[2048]; - int bytesRead = istm.Read(buffer, 0, buffer.Length); - while (bytesRead > 0) - { - ostm.Write(buffer, 0, bytesRead); - bytesRead = istm.Read(buffer, 0, buffer.Length); - } - ostm.Flush(); - ostm.Close(); - } - istm.Close(); - } - return destination; + this.requestUri = requestUri; } - /// - /// returns an "assembly://" uri for the specified manifest resource, scoped by the namespace of the specified type. - /// ("assembly://hint.assemblyname_without_version/hint.Namespace/name") - /// - /// - public static string GetAssemblyResourceUri(Type hint, string name) + public override WebResponse GetResponse() { - return "assembly://" + hint.Assembly.FullName.Split(',')[0].Trim() + "/" + hint.Namespace + ((name.IndexOf('/')>-1)?".":"/") + name; - } - - /// - /// returns an "assembly://" uri for the specified manifest resource, scoped by the namespace of the specified instance's type. - /// ("assembly://hint.assemblyname_without_version/hint.Namespace/name") - /// - /// - public static string GetAssemblyResourceUri(object hint, string name) - { - Type hintType = hint.GetType(); - return GetAssemblyResourceUri(hintType, name); + return new TestResourceWebResponse(requestUri); } } +#pragma warning restore SYSLIB0014 // WebRequest is obsolete + + public class TestResourceWebRequestFactory : IWebRequestCreate + { + public WebRequest Create(Uri uri) + { + return new TestResourceWebRequest(uri); + } + } + + #endregion + + static TestResourceLoader() + { + WebRequest.RegisterPrefix("testres", new TestResourceWebRequestFactory()); + } + + private TestResourceLoader() + { + } + + /// + /// Returns an Uri of the form "testres://./resourcname" that may be passed into etc. + /// + /// + /// + /// + public static Uri GetUri(object context, string ext) + { + string resname = context.GetType().AssemblyQualifiedName + "#" + ext; + Uri uri = new Uri("testres://inline/" + resname); + return uri; + } + + public static string GetText(object context, string ext) + { + Stream stm = GetStream(context, ext); + return new StreamReader(stm).ReadToEnd(); + } + + public static XmlDocument GetXml(object context, string ext) + { + Stream stm = GetStream(context, ext); + XmlDocument xmlDoc = new XmlDocument(); + xmlDoc.Load(stm); + return xmlDoc; + } + + public static XmlDocument GetXmlValidated(object context, string ext, params IResource[] schemaResources) + { + using (Stream stm = GetStream(context, ext)) + { + XmlReaderSettings settings = new XmlReaderSettings(); + settings.ValidationType = ValidationType.Schema; + XmlSchemaSet schemas = settings.Schemas; + + foreach (IResource schemaResource in schemaResources) + { + XmlDocument schemaDoc = new XmlDocument(); + using (Stream inputStream = schemaResource.InputStream) + { + schemaDoc.Load(inputStream); + } + + XmlElement root = schemaDoc.DocumentElement; + string targetNamespace = root.GetAttribute("targetNamespace", string.Empty); + schemas.Add(targetNamespace, new XmlNodeReader(schemaDoc)); + } + + XmlReader validatingReader = XmlReader.Create(stm, settings); + XmlDocument xmlDoc = new XmlDocument(); + xmlDoc.Load(validatingReader); + validatingReader.Close(); + return xmlDoc; + } + } + + /// + /// Returns an embedded assembly resource, who's name is constructed from the given parameters as + /// context.GetType().FullName + ext + /// + public static Stream GetStream(object context, string ext) + { + Type contextType = (context is Type) ? (Type) context : context.GetType(); + string resname = contextType.FullName + ext; + Stream stm = contextType.Assembly.GetManifestResourceStream(resname); + Assert.IsNotNull(stm, "Resource '{0}' in assembly '{1}' not found", resname, contextType.Assembly.FullName); + return stm; + } + + /// + /// Exports a resource obtained via to the specified destination. + /// + public static FileInfo ExportResource(object context, string ext, FileInfo destination) + { + Stream istm = GetStream(context, ext); + using (istm) + { + FileStream ostm = destination.OpenWrite(); + using (ostm) + { + byte[] buffer = new byte[2048]; + int bytesRead = istm.Read(buffer, 0, buffer.Length); + while (bytesRead > 0) + { + ostm.Write(buffer, 0, bytesRead); + bytesRead = istm.Read(buffer, 0, buffer.Length); + } + + ostm.Flush(); + ostm.Close(); + } + + istm.Close(); + } + + return destination; + } + + /// + /// returns an "assembly://" uri for the specified manifest resource, scoped by the namespace of the specified type. + /// ("assembly://hint.assemblyname_without_version/hint.Namespace/name") + /// + /// + public static string GetAssemblyResourceUri(Type hint, string name) + { + return "assembly://" + hint.Assembly.FullName.Split(',')[0].Trim() + "/" + hint.Namespace + ((name.IndexOf('/') > -1) ? "." : "/") + name; + } + + /// + /// returns an "assembly://" uri for the specified manifest resource, scoped by the namespace of the specified instance's type. + /// ("assembly://hint.assemblyname_without_version/hint.Namespace/name") + /// + /// + public static string GetAssemblyResourceUri(object hint, string name) + { + Type hintType = hint.GetType(); + return GetAssemblyResourceUri(hintType, name); + } } diff --git a/test/Spring/Spring.Core.Tests/Threading/AsyncTestMethod.cs b/test/Spring/Spring.Core.Tests/Threading/AsyncTestMethod.cs index 0fc06f0a..9c261dac 100644 --- a/test/Spring/Spring.Core.Tests/Threading/AsyncTestMethod.cs +++ b/test/Spring/Spring.Core.Tests/Threading/AsyncTestMethod.cs @@ -24,58 +24,56 @@ using NUnit.Framework; #endregion -namespace Spring.Threading +namespace Spring.Threading; + +/// +/// +/// +/// Erich Eichinger +public class AsyncTestMethod : AsyncTestTask { - /// - /// - /// - /// Erich Eichinger - public class AsyncTestMethod : AsyncTestTask + public delegate object TestMethod(object[] args); + + private readonly TestMethod callback; + private readonly object[] args; + private object result; + + private class ThreadStartTestMethodAdapter { - public delegate object TestMethod(object[] args); + private readonly ThreadStart threadStart; - private readonly TestMethod callback; - private readonly object[] args; - private object result; - - private class ThreadStartTestMethodAdapter + public ThreadStartTestMethodAdapter(ThreadStart threadStart) { - private readonly ThreadStart threadStart; - - public ThreadStartTestMethodAdapter(ThreadStart threadStart) - { - Assert.IsNotNull(threadStart); - this.threadStart = threadStart; - } - - public object Execute(object[] args) - { - threadStart(); - return null; - } + Assert.IsNotNull(threadStart); + this.threadStart = threadStart; } - public AsyncTestMethod(int iterations, ThreadStart callback, params object[] args) - : this(iterations, new TestMethod(new ThreadStartTestMethodAdapter(callback).Execute), args) + public object Execute(object[] args) { - } - - - public AsyncTestMethod(int iterations, TestMethod callback, params object[] args) : base(iterations) - { - Assert.IsNotNull(callback); - this.args = args; - this.callback = callback; - } - - public override void DoExecute() - { - result = callback(args); - } - - public object Result - { - get { return result; } + threadStart(); + return null; } } -} \ No newline at end of file + + public AsyncTestMethod(int iterations, ThreadStart callback, params object[] args) + : this(iterations, new TestMethod(new ThreadStartTestMethodAdapter(callback).Execute), args) + { + } + + public AsyncTestMethod(int iterations, TestMethod callback, params object[] args) : base(iterations) + { + Assert.IsNotNull(callback); + this.args = args; + this.callback = callback; + } + + public override void DoExecute() + { + result = callback(args); + } + + public object Result + { + get { return result; } + } +} diff --git a/test/Spring/Spring.Core.Tests/Threading/AsyncTestTask.cs b/test/Spring/Spring.Core.Tests/Threading/AsyncTestTask.cs index d6e9f0fd..0933e390 100644 --- a/test/Spring/Spring.Core.Tests/Threading/AsyncTestTask.cs +++ b/test/Spring/Spring.Core.Tests/Threading/AsyncTestTask.cs @@ -22,60 +22,59 @@ #endregion -namespace Spring.Threading +namespace Spring.Threading; + +/// +/// Base class for async test operations +/// +/// Erich Eichinger +public abstract class AsyncTestTask { - /// - /// Base class for async test operations - /// - /// Erich Eichinger - public abstract class AsyncTestTask + private Exception exception; + private Thread t; + private readonly int iterations; + private int iterationno; + + public AsyncTestTask(int iterations) { - private Exception exception; - private Thread t; - private readonly int iterations; - private int iterationno; + this.iterations = iterations; + t = new Thread(new ThreadStart(Run)); + t.IsBackground = true; + } - public AsyncTestTask(int iterations) + public abstract void DoExecute(); + + public AsyncTestTask Start() + { + t.Start(); + return this; + } + + public void Run() + { + int loop = 0; + try { - this.iterations = iterations; - t = new Thread(new ThreadStart(Run)); - t.IsBackground = true; - } - - public abstract void DoExecute(); - - public AsyncTestTask Start() - { - t.Start(); - return this; - } - - public void Run() - { - int loop = 0; - try + iterationno = 0; + for (loop = 0; loop < iterations; loop++) { - iterationno = 0; - for(loop = 0; loop < iterations; loop++) - { - DoExecute(); - Thread.Sleep(0); - } - } - catch(Exception ex) - { - iterationno = loop; - exception = ex; + DoExecute(); + Thread.Sleep(0); } } - - public void AssertNoException() + catch (Exception ex) { - t.Join(); - if(exception != null) - { - throw new Exception("Exception occured in testtask on iteration " + iterationno, exception); - } + iterationno = loop; + exception = ex; } } -} \ No newline at end of file + + public void AssertNoException() + { + t.Join(); + if (exception != null) + { + throw new Exception("Exception occured in testtask on iteration " + iterationno, exception); + } + } +} diff --git a/test/Spring/Spring.Core.Tests/Threading/CallContextStorageTests.cs b/test/Spring/Spring.Core.Tests/Threading/CallContextStorageTests.cs index 34647abc..ae77cdbf 100644 --- a/test/Spring/Spring.Core.Tests/Threading/CallContextStorageTests.cs +++ b/test/Spring/Spring.Core.Tests/Threading/CallContextStorageTests.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -24,18 +24,17 @@ using NUnit.Framework; #endregion -namespace Spring.Threading +namespace Spring.Threading; + +/// +/// Apply common thread-storage tests for +/// +/// Erich Eichinger +[TestFixture] +public class CallContextStorageTests : CommonThreadStorageTests { - /// - /// Apply common thread-storage tests for - /// - /// Erich Eichinger - [TestFixture] - public class CallContextStorageTests : CommonThreadStorageTests + protected override IThreadStorage CreateStorage() { - protected override IThreadStorage CreateStorage() - { - return new CallContextStorage(); - } + return new CallContextStorage(); } } diff --git a/test/Spring/Spring.Core.Tests/Threading/CommonThreadStorageTests.cs b/test/Spring/Spring.Core.Tests/Threading/CommonThreadStorageTests.cs index 2cd39e65..7f07c11f 100644 --- a/test/Spring/Spring.Core.Tests/Threading/CommonThreadStorageTests.cs +++ b/test/Spring/Spring.Core.Tests/Threading/CommonThreadStorageTests.cs @@ -24,140 +24,139 @@ using NUnit.Framework; #endregion -namespace Spring.Threading +namespace Spring.Threading; + +/// +/// Any implementation must pass these tests. +/// +/// Erich Eichinger +public abstract class CommonThreadStorageTests { - /// - /// Any implementation must pass these tests. - /// - /// Erich Eichinger - public abstract class CommonThreadStorageTests + protected abstract IThreadStorage CreateStorage(); + + protected virtual void ThreadSetup() { - protected abstract IThreadStorage CreateStorage(); - - protected virtual void ThreadSetup() - { - } - - protected virtual void ThreadCleanup() - { - } - - [SetUp] - public void SetUp() - { - ThreadSetup(); - } - - [TearDown] - public void TearDown() - { - // cleanup storage - var storage = CreateStorage(); - storage.FreeNamedDataSlot("key"); - storage.FreeNamedDataSlot("KEY"); - storage.FreeNamedDataSlot("KeY"); - - ThreadCleanup(); - } - - [Test] - public void IsCaseSensitive() - { - var storage = CreateStorage(); - - var value1 = new object(); - var value2 = new object(); - var value3 = new object(); - - storage.SetData("key", value1); - storage.SetData("KEY", value2); - storage.SetData("KeY", value3); - - Assert.AreSame(value1, storage.GetData("key")); - Assert.AreSame(value2, storage.GetData("KEY")); - Assert.AreSame(value3, storage.GetData("KeY")); - } - - [Test] - public void AllowReplaceData() - { - var storage = CreateStorage(); - - var value1 = new object(); - var value2 = new object(); - - storage.SetData("key", value1); - Assert.AreSame(value1, storage.GetData("key")); - storage.SetData("key", value2); - Assert.AreSame(value2, storage.GetData("key")); - storage.SetData("key", null); - Assert.AreSame(null, storage.GetData("key")); - } - - [Test] - public void UnknownKeyReturnsNull() - { - var storage = CreateStorage(); - - Assert.AreSame(null, storage.GetData("key")); - } - - [Test] - public void FreeNamedDataSlotRemovesData() - { - var storage = CreateStorage(); - - var value1 = new object(); - storage.SetData("key", value1); - Assert.AreSame(value1, storage.GetData("key")); - storage.FreeNamedDataSlot("key"); - Assert.AreSame(null, storage.GetData("key")); - } - - [Test] - public void UsesDistinguishedStorageOnDifferentThreads() - { - var storage = CreateStorage(); - - var value1 = new object(); - storage.SetData("key", value1); - - var helper = new ThreadTestHelper(this, storage); - helper.Execute(); - - Assert.AreNotSame(value1, helper.value); - Assert.IsNull(helper.value); - } - - #region Test Utility Classes - - private class ThreadTestHelper - { - private CommonThreadStorageTests outer; - private IThreadStorage storage; - - public object value; - - public ThreadTestHelper(CommonThreadStorageTests outer, IThreadStorage storage) - { - this.outer = outer; - this.storage = storage; - } - - public void Execute() - { - var t = new Thread(new ThreadStart(Run)); - t.Start(); - t.Join(); - } - - private void Run() - { - outer.ThreadSetup(); - value = storage.GetData("key"); - } - } - - #endregion Test Utility Classes } -} \ No newline at end of file + + protected virtual void ThreadCleanup() + { + } + + [SetUp] + public void SetUp() + { + ThreadSetup(); + } + + [TearDown] + public void TearDown() + { + // cleanup storage + var storage = CreateStorage(); + storage.FreeNamedDataSlot("key"); + storage.FreeNamedDataSlot("KEY"); + storage.FreeNamedDataSlot("KeY"); + + ThreadCleanup(); + } + + [Test] + public void IsCaseSensitive() + { + var storage = CreateStorage(); + + var value1 = new object(); + var value2 = new object(); + var value3 = new object(); + + storage.SetData("key", value1); + storage.SetData("KEY", value2); + storage.SetData("KeY", value3); + + Assert.AreSame(value1, storage.GetData("key")); + Assert.AreSame(value2, storage.GetData("KEY")); + Assert.AreSame(value3, storage.GetData("KeY")); + } + + [Test] + public void AllowReplaceData() + { + var storage = CreateStorage(); + + var value1 = new object(); + var value2 = new object(); + + storage.SetData("key", value1); + Assert.AreSame(value1, storage.GetData("key")); + storage.SetData("key", value2); + Assert.AreSame(value2, storage.GetData("key")); + storage.SetData("key", null); + Assert.AreSame(null, storage.GetData("key")); + } + + [Test] + public void UnknownKeyReturnsNull() + { + var storage = CreateStorage(); + + Assert.AreSame(null, storage.GetData("key")); + } + + [Test] + public void FreeNamedDataSlotRemovesData() + { + var storage = CreateStorage(); + + var value1 = new object(); + storage.SetData("key", value1); + Assert.AreSame(value1, storage.GetData("key")); + storage.FreeNamedDataSlot("key"); + Assert.AreSame(null, storage.GetData("key")); + } + + [Test] + public void UsesDistinguishedStorageOnDifferentThreads() + { + var storage = CreateStorage(); + + var value1 = new object(); + storage.SetData("key", value1); + + var helper = new ThreadTestHelper(this, storage); + helper.Execute(); + + Assert.AreNotSame(value1, helper.value); + Assert.IsNull(helper.value); + } + + #region Test Utility Classes + + private class ThreadTestHelper + { + private CommonThreadStorageTests outer; + private IThreadStorage storage; + + public object value; + + public ThreadTestHelper(CommonThreadStorageTests outer, IThreadStorage storage) + { + this.outer = outer; + this.storage = storage; + } + + public void Execute() + { + var t = new Thread(new ThreadStart(Run)); + t.Start(); + t.Join(); + } + + private void Run() + { + outer.ThreadSetup(); + value = storage.GetData("key"); + } + } + + #endregion Test Utility Classes +} diff --git a/test/Spring/Spring.Core.Tests/Threading/LatchTest.cs b/test/Spring/Spring.Core.Tests/Threading/LatchTest.cs index 1022d002..06a00659 100644 --- a/test/Spring/Spring.Core.Tests/Threading/LatchTest.cs +++ b/test/Spring/Spring.Core.Tests/Threading/LatchTest.cs @@ -4,77 +4,77 @@ using NUnit.Framework; /* * Copyright 2002-2010 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 -namespace Spring.Threading +namespace Spring.Threading; + +[TestFixture] +public class LatchTest { - [TestFixture] - public class LatchTest + class Worker { + public bool worked; + ISync startPermit; + ISync workedSync; - class Worker + public Worker(ISync startPermit, ISync workedSync) { - public bool worked; - ISync startPermit; - ISync workedSync; - - public Worker (ISync startPermit, ISync workedSync) - { - this.startPermit = startPermit; - this.workedSync = workedSync; - } - - public void Work() - { - // very slow worker initialization ... - // ... attach to messaging system - // ... connect to database - startPermit.Acquire(); - // ... use resources initialized in Mush - // ... do real work - worked = true; - // ... we are finished - workedSync.Release(); - } + this.startPermit = startPermit; + this.workedSync = workedSync; } - [Test] - public void BossWorkerDemo() + public void Work() { - int n = 10; - - Latch startPermit = new Latch(); - Semaphore wait = new Semaphore(-(n - 1)); - - Worker [] workers = new Worker[n]; - for (int i=0; i +/// Test behaviour of LogicalThreadContext +/// +/// Erich Eichinger +[TestFixture] +public class LogicalThreadContextTest { - /// - /// Test behaviour of LogicalThreadContext - /// - /// Erich Eichinger - [TestFixture] - public class LogicalThreadContextTest + private class MockStorage : IThreadStorage { - private class MockStorage : IThreadStorage + internal Hashtable data = new Hashtable(); + + public object GetData(string name) { - internal Hashtable data = new Hashtable(); - - public object GetData(string name) - { - return data[name]; - } - - public void SetData(string name, object value) - { - data[name] = value; - } - - public void FreeNamedDataSlot(string name) - { - data.Remove(name); - } + return data[name]; } - [Test] - public void StorageMustNotBeNull() + public void SetData(string name, object value) { - Assert.Throws(() => LogicalThreadContext.SetStorage(null)); + data[name] = value; } - [Test] - public void StorageMayBeSetMoreThanOnce() + public void FreeNamedDataSlot(string name) { - LogicalThreadContext.SetStorage(new MockStorage()); - LogicalThreadContext.SetStorage(new MockStorage()); - LogicalThreadContext.SetStorage(new MockStorage()); - } - - [Test] - public void StorageIsUsedByFacadeMethods() - { - MockStorage storage = new MockStorage(); - LogicalThreadContext.SetStorage(storage); - - object value = new object(); - - LogicalThreadContext.SetData("key", value); - Assert.AreSame( value, storage.data["key"] ); - - object data = LogicalThreadContext.GetData("key"); - Assert.AreSame(value, data); - - LogicalThreadContext.FreeNamedDataSlot("key"); - - Assert.IsFalse( storage.data.ContainsKey("key") ); + data.Remove(name); } } + + [Test] + public void StorageMustNotBeNull() + { + Assert.Throws(() => LogicalThreadContext.SetStorage(null)); + } + + [Test] + public void StorageMayBeSetMoreThanOnce() + { + LogicalThreadContext.SetStorage(new MockStorage()); + LogicalThreadContext.SetStorage(new MockStorage()); + LogicalThreadContext.SetStorage(new MockStorage()); + } + + [Test] + public void StorageIsUsedByFacadeMethods() + { + MockStorage storage = new MockStorage(); + LogicalThreadContext.SetStorage(storage); + + object value = new object(); + + LogicalThreadContext.SetData("key", value); + Assert.AreSame(value, storage.data["key"]); + + object data = LogicalThreadContext.GetData("key"); + Assert.AreSame(value, data); + + LogicalThreadContext.FreeNamedDataSlot("key"); + + Assert.IsFalse(storage.data.ContainsKey("key")); + } } diff --git a/test/Spring/Spring.Core.Tests/Threading/SemaphoreTest.cs b/test/Spring/Spring.Core.Tests/Threading/SemaphoreTest.cs index c05e607f..7750c1ea 100644 --- a/test/Spring/Spring.Core.Tests/Threading/SemaphoreTest.cs +++ b/test/Spring/Spring.Core.Tests/Threading/SemaphoreTest.cs @@ -2,213 +2,210 @@ /* * Copyright 2002-2010 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 Spring.Pool; using NUnit.Framework; +namespace Spring.Threading; -namespace Spring.Threading +[TestFixture] +public class SemaphoreTest { - [TestFixture] - public class SemaphoreTest - { - private static long SHORT_DELAY_MS = 300; - [Test] - public void UsingLikeAMutex () - { - - Semaphore semaphore = new Semaphore (1); - Latch latch = new Latch (); - Helper helper = new Helper (semaphore, latch); - Thread thread = new Thread (new ThreadStart (helper.Go)); - semaphore.Acquire (); - thread.Start (); - latch.Acquire (); - Assert.IsFalse (helper.gone); - semaphore.Release (); - thread.Join (); - Assert.IsTrue (helper.gone, "not gone"); - - } - [Test] - public void AquireInSameThrad() - { - Semaphore s = new Semaphore(2); - Assert.AreEqual(2, s.Permits); - s.Acquire(); - s.Acquire(); - Assert.AreEqual(0, s.Permits); - - } - - [Test] - public void ReleaseMultipleTimesInSameThread() - { - Semaphore s = new Semaphore(2); - Assert.AreEqual(2, s.Permits); - s.Acquire(); - s.Acquire(); - s.Release(2); - Assert.AreEqual(2, s.Permits); - } - - [Test] - public void AttemptWithNegativeMillisInSameThread() - { - Semaphore s = new Semaphore(2); - Assert.AreEqual(2, s.Permits); - s.Acquire(); - Assert.IsTrue(s.Attempt(-400)); - s.Release(2); - Assert.AreEqual(2, s.Permits); - } - - [Test] - public void ReleaseMultipleBadArgument() - { - Semaphore s = new Semaphore(2); - Assert.AreEqual(2, s.Permits); - s.Acquire(); - s.Acquire(); - Assert.Throws(() => s.Release(-2)); - } - - [Test] - public void AttemptInSameThread() - { - Semaphore s = new Semaphore(1); - Assert.IsTrue(s.Attempt(SHORT_DELAY_MS)); - s.Release(); - Assert.IsTrue(s.Attempt(SHORT_DELAY_MS)); - s.Release(); - Assert.IsTrue(s.Attempt(SHORT_DELAY_MS)); - s.Release(); - Assert.IsTrue(s.Attempt(SHORT_DELAY_MS)); - s.Release(); - Assert.IsTrue(s.Attempt(SHORT_DELAY_MS)); - s.Release(); - Assert.AreEqual(1, s.Permits); + private static long SHORT_DELAY_MS = 300; - } - - //TODO tests that interrupt a thread. - - [Test] - public void AquireReleaseInSameThread() - { - Semaphore s = new Semaphore(1); - s.Acquire(); - s.Release(); - s.Acquire(); - s.Release(); - s.Acquire(); - s.Release(); - s.Acquire(); - s.Release(); - s.Acquire(); - s.Release(); - s.Acquire(); - s.Release(); - Assert.AreEqual(1, s.Permits); - } - - [Test] - public void AcquireReleaseInDifferentThreads() - { - Semaphore s = new Semaphore(0); - AcquireReleaseWorker worker1 = new AcquireReleaseWorker(s); - Thread thread1 = new Thread(new ThreadStart(worker1.DoWork)); - - thread1.Start(); - Thread.Sleep(300); - s.Release(); - s.Release(); - s.Acquire(); - s.Acquire(); - s.Release(); - thread1.Join(); - - } - - [Test] - public void AttemptReleaseInDifferentThreads() - { - Semaphore s = new Semaphore(0); - AttemptReleaseWorker worker1 = new AttemptReleaseWorker(s); - Thread thread1 = new Thread(new ThreadStart(worker1.DoWork)); - - thread1.Start(); - //TODO investigate... - //Assert.IsTrue(s.Attempt(SHORT_DELAY_MS)); - s.Attempt(SHORT_DELAY_MS); - s.Release(); - //Assert.IsTrue(s.Attempt(SHORT_DELAY_MS)); - s.Attempt(SHORT_DELAY_MS); - s.Release(); - s.Release(); - thread1.Join(); - } - - [Test] - public void TimetoMillis() - { - long millis = Utils.CurrentTimeMillis; - //hmm should be using UtcNow, the impl in CurrentTimeMillis doesn't use UTC. - long epochTime = ((DateTime.Now-new DateTime (1970, 1, 1)).Ticks)/TimeSpan.TicksPerMillisecond; - long delta = epochTime-millis; - Assert.IsTrue(delta < 500); - } - } - - public class AcquireReleaseWorker + [Test] + public void UsingLikeAMutex() { - private Semaphore sem; - public AcquireReleaseWorker(Semaphore s) - { - sem = s; - } - - public void DoWork() - { - sem.Acquire(); - sem.Release(); - sem.Release(); - sem.Acquire(); - } + Semaphore semaphore = new Semaphore(1); + Latch latch = new Latch(); + Helper helper = new Helper(semaphore, latch); + Thread thread = new Thread(new ThreadStart(helper.Go)); + semaphore.Acquire(); + thread.Start(); + latch.Acquire(); + Assert.IsFalse(helper.gone); + semaphore.Release(); + thread.Join(); + Assert.IsTrue(helper.gone, "not gone"); } - - public class AttemptReleaseWorker + + [Test] + public void AquireInSameThrad() { - private Semaphore sem; - public AttemptReleaseWorker(Semaphore s) - { - sem = s; - } - - public void DoWork() - { - long SHORT_DELAY_MS = 300; - sem.Release(); - - //TODO can we do Assert.IsTrue here? - sem.Attempt(SHORT_DELAY_MS); - sem.Release(); - sem.Attempt(SHORT_DELAY_MS); - } + Semaphore s = new Semaphore(2); + Assert.AreEqual(2, s.Permits); + s.Acquire(); + s.Acquire(); + Assert.AreEqual(0, s.Permits); + } + + [Test] + public void ReleaseMultipleTimesInSameThread() + { + Semaphore s = new Semaphore(2); + Assert.AreEqual(2, s.Permits); + s.Acquire(); + s.Acquire(); + s.Release(2); + Assert.AreEqual(2, s.Permits); + } + + [Test] + public void AttemptWithNegativeMillisInSameThread() + { + Semaphore s = new Semaphore(2); + Assert.AreEqual(2, s.Permits); + s.Acquire(); + Assert.IsTrue(s.Attempt(-400)); + s.Release(2); + Assert.AreEqual(2, s.Permits); + } + + [Test] + public void ReleaseMultipleBadArgument() + { + Semaphore s = new Semaphore(2); + Assert.AreEqual(2, s.Permits); + s.Acquire(); + s.Acquire(); + Assert.Throws(() => s.Release(-2)); + } + + [Test] + public void AttemptInSameThread() + { + Semaphore s = new Semaphore(1); + Assert.IsTrue(s.Attempt(SHORT_DELAY_MS)); + s.Release(); + Assert.IsTrue(s.Attempt(SHORT_DELAY_MS)); + s.Release(); + Assert.IsTrue(s.Attempt(SHORT_DELAY_MS)); + s.Release(); + Assert.IsTrue(s.Attempt(SHORT_DELAY_MS)); + s.Release(); + Assert.IsTrue(s.Attempt(SHORT_DELAY_MS)); + s.Release(); + Assert.AreEqual(1, s.Permits); + } + + //TODO tests that interrupt a thread. + + [Test] + public void AquireReleaseInSameThread() + { + Semaphore s = new Semaphore(1); + s.Acquire(); + s.Release(); + s.Acquire(); + s.Release(); + s.Acquire(); + s.Release(); + s.Acquire(); + s.Release(); + s.Acquire(); + s.Release(); + s.Acquire(); + s.Release(); + Assert.AreEqual(1, s.Permits); + } + + [Test] + public void AcquireReleaseInDifferentThreads() + { + Semaphore s = new Semaphore(0); + AcquireReleaseWorker worker1 = new AcquireReleaseWorker(s); + Thread thread1 = new Thread(new ThreadStart(worker1.DoWork)); + + thread1.Start(); + Thread.Sleep(300); + s.Release(); + s.Release(); + s.Acquire(); + s.Acquire(); + s.Release(); + thread1.Join(); + } + + [Test] + public void AttemptReleaseInDifferentThreads() + { + Semaphore s = new Semaphore(0); + AttemptReleaseWorker worker1 = new AttemptReleaseWorker(s); + Thread thread1 = new Thread(new ThreadStart(worker1.DoWork)); + + thread1.Start(); + //TODO investigate... + //Assert.IsTrue(s.Attempt(SHORT_DELAY_MS)); + s.Attempt(SHORT_DELAY_MS); + s.Release(); + //Assert.IsTrue(s.Attempt(SHORT_DELAY_MS)); + s.Attempt(SHORT_DELAY_MS); + s.Release(); + s.Release(); + thread1.Join(); + } + + [Test] + public void TimetoMillis() + { + long millis = Utils.CurrentTimeMillis; + //hmm should be using UtcNow, the impl in CurrentTimeMillis doesn't use UTC. + long epochTime = ((DateTime.Now - new DateTime(1970, 1, 1)).Ticks) / TimeSpan.TicksPerMillisecond; + long delta = epochTime - millis; + Assert.IsTrue(delta < 500); + } +} + +public class AcquireReleaseWorker +{ + private Semaphore sem; + + public AcquireReleaseWorker(Semaphore s) + { + sem = s; + } + + public void DoWork() + { + sem.Acquire(); + sem.Release(); + sem.Release(); + sem.Acquire(); + } +} + +public class AttemptReleaseWorker +{ + private Semaphore sem; + + public AttemptReleaseWorker(Semaphore s) + { + sem = s; + } + + public void DoWork() + { + long SHORT_DELAY_MS = 300; + sem.Release(); + + //TODO can we do Assert.IsTrue here? + sem.Attempt(SHORT_DELAY_MS); + sem.Release(); + sem.Attempt(SHORT_DELAY_MS); } - } diff --git a/test/Spring/Spring.Core.Tests/Threading/SyncHolderTest.cs b/test/Spring/Spring.Core.Tests/Threading/SyncHolderTest.cs index af38ade4..4cab37bc 100644 --- a/test/Spring/Spring.Core.Tests/Threading/SyncHolderTest.cs +++ b/test/Spring/Spring.Core.Tests/Threading/SyncHolderTest.cs @@ -1,69 +1,68 @@ using FakeItEasy; - using NUnit.Framework; -namespace Spring.Threading +namespace Spring.Threading; + +[TestFixture] +public class SyncHolderTest { - [TestFixture] - public class SyncHolderTest + ISync sync; + + [SetUp] + public void SetUp() { - ISync sync; + sync = A.Fake(); + } - [SetUp] - public void SetUp() + [TearDown] + public void TearDown() + { + } + + class MySemaphore : Semaphore + { + public MySemaphore(long initialPermits) : base(initialPermits) { - sync = A.Fake(); - } - - [TearDown] - public void TearDown() - { - } - - class MySemaphore : Semaphore - { - public MySemaphore(long initialPermits) : base(initialPermits) - { - } - } - - [Test] - public void CanBeUsedWithTheUsingCSharpIdiomToAttemptOnAnISync() - { - MySemaphore sync = new MySemaphore(1); - using (new SyncHolder(sync, 100)) - { - Assert.AreEqual(0, sync.Permits); - } - Assert.AreEqual(1, sync.Permits); - - sync = new MySemaphore(0); - try - { - using (new SyncHolder(sync, 100)) - { - Assert.IsTrue(false, "wrongly entered sync block"); - } - } - catch (TimeoutException) - { - Assert.AreEqual(0, sync.Permits); - } - } - - [Test] - public void CanBeUsedWithTheUsingCSharpIdiomToAcquireAnIsync() - { - sync.Acquire(); - sync.Release(); - - Assert.Throws(() => - { - using (new SyncHolder(sync)) - { - throw new ThreadStateException(); - } - }); } } -} \ No newline at end of file + + [Test] + public void CanBeUsedWithTheUsingCSharpIdiomToAttemptOnAnISync() + { + MySemaphore sync = new MySemaphore(1); + using (new SyncHolder(sync, 100)) + { + Assert.AreEqual(0, sync.Permits); + } + + Assert.AreEqual(1, sync.Permits); + + sync = new MySemaphore(0); + try + { + using (new SyncHolder(sync, 100)) + { + Assert.IsTrue(false, "wrongly entered sync block"); + } + } + catch (TimeoutException) + { + Assert.AreEqual(0, sync.Permits); + } + } + + [Test] + public void CanBeUsedWithTheUsingCSharpIdiomToAcquireAnIsync() + { + sync.Acquire(); + sync.Release(); + + Assert.Throws(() => + { + using (new SyncHolder(sync)) + { + throw new ThreadStateException(); + } + }); + } +} diff --git a/test/Spring/Spring.Core.Tests/Threading/ThreadStaticStorageTests.cs b/test/Spring/Spring.Core.Tests/Threading/ThreadStaticStorageTests.cs index da5ac3a7..481ff930 100644 --- a/test/Spring/Spring.Core.Tests/Threading/ThreadStaticStorageTests.cs +++ b/test/Spring/Spring.Core.Tests/Threading/ThreadStaticStorageTests.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -24,18 +24,17 @@ using NUnit.Framework; #endregion -namespace Spring.Threading +namespace Spring.Threading; + +/// +/// Apply common thread-storage tests for +/// +/// Erich Eichinger +[TestFixture] +public class ThreadStaticStorageTests : CommonThreadStorageTests { - /// - /// Apply common thread-storage tests for - /// - /// Erich Eichinger - [TestFixture] - public class ThreadStaticStorageTests : CommonThreadStorageTests + protected override IThreadStorage CreateStorage() { - protected override IThreadStorage CreateStorage() - { - return new ThreadStaticStorage(); - } + return new ThreadStaticStorage(); } -} \ No newline at end of file +} diff --git a/test/Spring/Spring.Core.Tests/Util/ArrayUtilsTests.cs b/test/Spring/Spring.Core.Tests/Util/ArrayUtilsTests.cs index 9ba630a1..60b50169 100644 --- a/test/Spring/Spring.Core.Tests/Util/ArrayUtilsTests.cs +++ b/test/Spring/Spring.Core.Tests/Util/ArrayUtilsTests.cs @@ -24,59 +24,58 @@ using NUnit.Framework; #endregion -namespace Spring.Util +namespace Spring.Util; + +/// +/// Unit tests for the ArrayUtils class. +/// +/// Rick Evans +[TestFixture] +public sealed class ArrayUtilsTests { - /// - /// Unit tests for the ArrayUtils class. - /// - /// Rick Evans - [TestFixture] - public sealed class ArrayUtilsTests + [Test] + public void AreEqual() { - [Test] - public void AreEqual () - { - object [] one = new string [] {"Foo", "Bar", "Baz"}; - object [] two = new string [] {"Foo", "Bar", "Baz"}; - Assert.IsTrue (ArrayUtils.AreEqual (one, two)); - object [] three = new string [] {"Foo", "Ben", "Baz"}; - Assert.IsFalse (ArrayUtils.AreEqual (one, three)); - } + object[] one = new string[] { "Foo", "Bar", "Baz" }; + object[] two = new string[] { "Foo", "Bar", "Baz" }; + Assert.IsTrue(ArrayUtils.AreEqual(one, two)); + object[] three = new string[] { "Foo", "Ben", "Baz" }; + Assert.IsFalse(ArrayUtils.AreEqual(one, three)); + } - [Test] - public void AreEqualWithBadArguments () - { - Assert.IsTrue (ArrayUtils.AreEqual (null, null)); - object [] one = new string [] {"Foo", "Bar", "Baz"}; - object [] two = null; - Assert.IsFalse (ArrayUtils.AreEqual (one, two)); - object [] three = new string [] {"Foo", "Bar"}; - Assert.IsFalse (ArrayUtils.AreEqual (one, three)); - } + [Test] + public void AreEqualWithBadArguments() + { + Assert.IsTrue(ArrayUtils.AreEqual(null, null)); + object[] one = new string[] { "Foo", "Bar", "Baz" }; + object[] two = null; + Assert.IsFalse(ArrayUtils.AreEqual(one, two)); + object[] three = new string[] { "Foo", "Bar" }; + Assert.IsFalse(ArrayUtils.AreEqual(one, three)); + } - [Test] - public void HasLengthTests() - { - Assert.IsFalse(ArrayUtils.HasLength(null)); - Assert.IsFalse(ArrayUtils.HasLength(new byte[0])); - Assert.IsTrue(ArrayUtils.HasLength(new byte[1])); - } + [Test] + public void HasLengthTests() + { + Assert.IsFalse(ArrayUtils.HasLength(null)); + Assert.IsFalse(ArrayUtils.HasLength(new byte[0])); + Assert.IsTrue(ArrayUtils.HasLength(new byte[1])); + } - [Test] - public void ConcatsArrays() - { - byte[] array1 = new byte[] { 0, 1, 2, 3}; - byte[] array2 = new byte[] { 4, 5, 6, 7}; - byte[] result = (byte[])ArrayUtils.Concat(array1, array2); - Assert.AreEqual( new byte[] { 0,1,2,3,4,5,6,7 }, result ); - } + [Test] + public void ConcatsArrays() + { + byte[] array1 = new byte[] { 0, 1, 2, 3 }; + byte[] array2 = new byte[] { 4, 5, 6, 7 }; + byte[] result = (byte[]) ArrayUtils.Concat(array1, array2); + Assert.AreEqual(new byte[] { 0, 1, 2, 3, 4, 5, 6, 7 }, result); + } - [Test] - public void ConcatsNullArrays() - { - byte[] array = new byte[] { 0, 1, 2, 3}; - Assert.AreEqual(new byte[] { 0, 1, 2, 3 }, ArrayUtils.Concat(array, null)); - Assert.AreEqual(new byte[] { 0, 1, 2, 3 }, ArrayUtils.Concat(null, array)); - } - } + [Test] + public void ConcatsNullArrays() + { + byte[] array = new byte[] { 0, 1, 2, 3 }; + Assert.AreEqual(new byte[] { 0, 1, 2, 3 }, ArrayUtils.Concat(array, null)); + Assert.AreEqual(new byte[] { 0, 1, 2, 3 }, ArrayUtils.Concat(null, array)); + } } diff --git a/test/Spring/Spring.Core.Tests/Util/AssertUtilsTests.cs b/test/Spring/Spring.Core.Tests/Util/AssertUtilsTests.cs index cb6fc448..5d7c9e5a 100644 --- a/test/Spring/Spring.Core.Tests/Util/AssertUtilsTests.cs +++ b/test/Spring/Spring.Core.Tests/Util/AssertUtilsTests.cs @@ -31,173 +31,173 @@ using Spring.Objects; #endregion -namespace Spring.Util +namespace Spring.Util; + +/// +/// Unit tests for the AssertUtils class. +/// +/// Rick Evans +[TestFixture] +public sealed class AssertUtilsTests { - /// - /// Unit tests for the AssertUtils class. - /// - /// Rick Evans - [TestFixture] - public sealed class AssertUtilsTests + [Test] + public void IsTrueWithMesssage() { - [Test] - public void IsTrueWithMesssage() + Assert.Throws(() => AssertUtils.IsTrue(false, "foo"), "foo"); + } + + [Test] + public void IsTrueWithMessageValidExpression() + { + AssertUtils.IsTrue(true, "foo"); + } + + [Test] + public void IsTrue() + { + Assert.Throws(() => AssertUtils.IsTrue(false), "[Assertion failed] - this expression must be true"); + } + + [Test] + public void IsTrueValidExpression() + { + AssertUtils.IsTrue(true); + } + + [Test] + public void StateTrue() + { + Assert.Throws(() => AssertUtils.State(false, "foo")); + } + + [Test] + public void ArgumentNotNull() + { + Assert.Throws(() => AssertUtils.ArgumentNotNull(null, "foo")); + } + + [Test] + public void ArgumentNotNullWithMessage() + { + Assert.Throws(() => AssertUtils.ArgumentNotNull(null, "foo", "Bang!")); + } + + [Test] + public void ArgumentHasTextWithValidText() + { + AssertUtils.ArgumentHasText("... and no-one's getting fat 'cept Mama Cas!", "foo"); + } + + [Test] + public void ArgumentHasTextWithValidTextAndMessage() + { + AssertUtils.ArgumentHasText("... and no-one's getting fat 'cept Mama Cas!", "foo", "Bang!"); + } + + [Test] + public void ArgumentHasText() + { + Assert.Throws(() => AssertUtils.ArgumentHasText(null, "foo")); + } + + [Test] + public void ArgumentHasTextWithMessage() + { + Assert.Throws(() => AssertUtils.ArgumentHasText(null, "foo", "Bang!")); + } + + [Test] + public void ArgumentHasLengthArgumentIsNull() + { + Assert.Throws(() => AssertUtils.ArgumentHasLength(null, "foo")); + } + + [Test] + public void ArgumentHasLengthArgumentIsNullWithMessage() + { + Assert.Throws(() => AssertUtils.ArgumentHasLength(null, "foo", "Bang!")); + } + + [Test] + public void ArgumentHasLengthArgumentIsEmpty() + { + Assert.Throws(() => AssertUtils.ArgumentHasLength(new byte[0], "foo")); + } + + [Test] + public void ArgumentHasLengthArgumentIsEmptyWithMessage() + { + Assert.Throws(() => AssertUtils.ArgumentHasLength(new byte[0], "foo", "Bang!")); + } + + [Test] + public void ArgumentHasLengthArgumentHasElements() + { + AssertUtils.ArgumentHasLength(new byte[1], "foo"); + } + + [Test] + public void ArgumentHasLengthArgumentHasElementsWithMessage() + { + AssertUtils.ArgumentHasLength(new byte[1], "foo", "Bang!"); + } + + [Test] + public void ArgumentHasElementsArgumentIsNull() + { + Assert.Throws(() => AssertUtils.ArgumentHasElements(null, "foo")); + } + + [Test] + public void ArgumentHasElementsArgumentIsEmpty() + { + Assert.Throws(() => AssertUtils.ArgumentHasElements(new object[0], "foo")); + } + + [Test] + public void ArgumentHasElementsArgumentContainsNull() + { + Assert.Throws(() => AssertUtils.ArgumentHasElements(new object[] { new object(), null, new object() }, "foo")); + } + + [Test] + public void ArgumentHasElementsArgumentContainsNonNullsOnly() + { + AssertUtils.ArgumentHasElements(new object[] { new object(), new object(), new object() }, "foo"); + } + + [Test] + public void UnderstandsType() + { + MethodInfo getDescriptionMethod = typeof(ITestObject).GetMethod("GetDescription", new Type[0]); + MethodInfo understandsMethod = typeof(AssertUtils).GetMethod("Understands", BindingFlags.Public | BindingFlags.Static, null, new Type[] { typeof(object), typeof(string), typeof(MethodBase) }, null); + + // null target, any type + AssertNotUnderstandsType(null, "target", typeof(object), typeof(NotSupportedException), "Target 'target' is null."); + // any target, null type + AssertNotUnderstandsType(new object(), "target", null, typeof(ArgumentNullException), "Argument 'requiredType' cannot be null."); + } + + private void AssertNotUnderstandsType(object target, string targetName, Type requiredType, Type exceptionType, string partialMessage) + { + try { - Assert.Throws(() => AssertUtils.IsTrue(false, "foo"), "foo"); + AssertUtils.Understands(target, targetName, requiredType); + Assert.Fail(); } - - [Test] - public void IsTrueWithMessageValidExpression() + catch (Exception ex) { - AssertUtils.IsTrue(true, "foo"); - } - - [Test] - public void IsTrue() - { - Assert.Throws(() => AssertUtils.IsTrue(false), "[Assertion failed] - this expression must be true"); - } - - [Test] - public void IsTrueValidExpression() - { - AssertUtils.IsTrue(true); - } - - [Test] - public void StateTrue() - { - Assert.Throws(() => AssertUtils.State(false, "foo")); - } - - [Test] - public void ArgumentNotNull() - { - Assert.Throws(() => AssertUtils.ArgumentNotNull(null, "foo")); - } - - [Test] - public void ArgumentNotNullWithMessage() - { - Assert.Throws(() => AssertUtils.ArgumentNotNull(null, "foo", "Bang!")); - } - - [Test] - public void ArgumentHasTextWithValidText() - { - AssertUtils.ArgumentHasText("... and no-one's getting fat 'cept Mama Cas!", "foo"); - } - - [Test] - public void ArgumentHasTextWithValidTextAndMessage() - { - AssertUtils.ArgumentHasText("... and no-one's getting fat 'cept Mama Cas!", "foo", "Bang!"); - } - - [Test] - public void ArgumentHasText() - { - Assert.Throws(() => AssertUtils.ArgumentHasText(null, "foo")); - } - - [Test] - public void ArgumentHasTextWithMessage() - { - Assert.Throws(() => AssertUtils.ArgumentHasText(null, "foo", "Bang!")); - } - - [Test] - public void ArgumentHasLengthArgumentIsNull() - { - Assert.Throws(() => AssertUtils.ArgumentHasLength(null, "foo")); - } - - [Test] - public void ArgumentHasLengthArgumentIsNullWithMessage() - { - Assert.Throws(() => AssertUtils.ArgumentHasLength(null, "foo", "Bang!")); - } - - [Test] - public void ArgumentHasLengthArgumentIsEmpty() - { - Assert.Throws(() => AssertUtils.ArgumentHasLength(new byte[0], "foo")); - } - - [Test] - public void ArgumentHasLengthArgumentIsEmptyWithMessage() - { - Assert.Throws(() => AssertUtils.ArgumentHasLength(new byte[0], "foo", "Bang!")); - } - - [Test] - public void ArgumentHasLengthArgumentHasElements() - { - AssertUtils.ArgumentHasLength(new byte[1], "foo"); - } - - [Test] - public void ArgumentHasLengthArgumentHasElementsWithMessage() - { - AssertUtils.ArgumentHasLength(new byte[1], "foo", "Bang!"); - } - - [Test] - public void ArgumentHasElementsArgumentIsNull() - { - Assert.Throws(() => AssertUtils.ArgumentHasElements(null, "foo")); - } - - [Test] - public void ArgumentHasElementsArgumentIsEmpty() - { - Assert.Throws(() => AssertUtils.ArgumentHasElements(new object[0], "foo")); - } - - [Test] - public void ArgumentHasElementsArgumentContainsNull() - { - Assert.Throws(() => AssertUtils.ArgumentHasElements(new object[] { new object(), null, new object() }, "foo")); - } - - [Test] - public void ArgumentHasElementsArgumentContainsNonNullsOnly() - { - AssertUtils.ArgumentHasElements(new object[] { new object(), new object(), new object() }, "foo"); - } - - [Test] - public void UnderstandsType() - { - MethodInfo getDescriptionMethod = typeof(ITestObject).GetMethod("GetDescription", new Type[0]); - MethodInfo understandsMethod = typeof(AssertUtils).GetMethod("Understands", BindingFlags.Public|BindingFlags.Static, null, new Type[] {typeof (object), typeof(string), typeof (MethodBase)}, null); - - // null target, any type - AssertNotUnderstandsType(null, "target", typeof(object), typeof(NotSupportedException), "Target 'target' is null."); - // any target, null type - AssertNotUnderstandsType(new object(), "target", null, typeof(ArgumentNullException), "Argument 'requiredType' cannot be null."); - } - - private void AssertNotUnderstandsType(object target, string targetName, Type requiredType, Type exceptionType, string partialMessage) - { - try + if (ex.GetType() != exceptionType) { - AssertUtils.Understands(target, targetName, requiredType); - Assert.Fail(); + Assert.Fail("Expected Exception of type {0}, but was {1}", exceptionType, ex.GetType()); } - catch(Exception ex) - { - if (ex.GetType() != exceptionType) - { - Assert.Fail("Expected Exception of type {0}, but was {1}", exceptionType, ex.GetType()); - } - if (-1 == ex.Message.IndexOf(partialMessage)) - { - Assert.Fail("Expected Message '{0}', but got '{1}'", partialMessage, ex.Message); - } + if (-1 == ex.Message.IndexOf(partialMessage)) + { + Assert.Fail("Expected Message '{0}', but got '{1}'", partialMessage, ex.Message); } } + } #if !NETCOREAPP [Test] @@ -247,7 +247,7 @@ namespace Spring.Util { private readonly object targetInstance; - public TestProxy(object targetInstance) + public TestProxy(object targetInstance) : base(typeof(MarshalByRefObject)) { this.targetInstance = targetInstance; @@ -272,5 +272,4 @@ namespace Spring.Util } } #endif - } } diff --git a/test/Spring/Spring.Core.Tests/Util/CollectionUtilsTests.cs b/test/Spring/Spring.Core.Tests/Util/CollectionUtilsTests.cs index 9d2e0d44..3e521d63 100644 --- a/test/Spring/Spring.Core.Tests/Util/CollectionUtilsTests.cs +++ b/test/Spring/Spring.Core.Tests/Util/CollectionUtilsTests.cs @@ -2,433 +2,427 @@ using System.Collections; using NUnit.Framework; using Spring.Objects; -namespace Spring.Util +namespace Spring.Util; + +[TestFixture] +public class CollectionUtilsTests { - [TestFixture] - public class CollectionUtilsTests + internal class NoContainsNoAddCollection : ICollection { - internal class NoContainsNoAddCollection : ICollection + internal class Iterator : IEnumerator { - internal class Iterator : IEnumerator - { - #region IEnumerator Members + #region IEnumerator Members - public void Reset() + public void Reset() + { + // TODO: Add Iterator.Reset implementation + } + + public object Current + { + get { - // TODO: Add Iterator.Reset implementation + // TODO: Add Iterator.Current getter implementation + return null; } - - public object Current - { - get - { - // TODO: Add Iterator.Current getter implementation - return null; - } - } - - public bool MoveNext() - { - // TODO: Add Iterator.MoveNext implementation - return false; - } - - #endregion - } - public void CopyTo(Array array, int index) + public bool MoveNext() { - return; + // TODO: Add Iterator.MoveNext implementation + return false; } - public int Count - { - get { return 0; } - } - - public object SyncRoot - { - get { return this; } - } - - public bool IsSynchronized - { - get { throw new NotImplementedException(); } - } - - public IEnumerator GetEnumerator() - { - return new Iterator(); - } - } - [Test] - public void ContainsNullCollection() - { - CollectionUtils.Contains(null, null); - } - [Test] - public void ContainsNullObject() - { - ArrayList list = new ArrayList(); - list.Add(null); - Assert.IsTrue(CollectionUtils.Contains(list, null)); - } - [Test] - public void ContainsCollectionThatDoesNotImplementContains() - { - NoContainsNoAddCollection noAddCollection = new NoContainsNoAddCollection(); - CollectionUtils.Contains(noAddCollection, new object()); + #endregion } - [Test] - public void ContainsValidElement() + public void CopyTo(Array array, int index) { - ArrayList list = new ArrayList(); - list.Add(1); - list.Add(2); - list.Add(3); - list.Add(4); - - Assert.IsTrue(CollectionUtils.Contains(list, 3)); + return; } - [Test] - public void ContainsDoesNotContainElement() + public int Count { - ArrayList list = new ArrayList(); - list.Add(1); - list.Add(2); - list.Add(3); - list.Add(4); - - Assert.IsFalse(CollectionUtils.Contains(list, 5)); + get { return 0; } } - [Test] - public void AddNullCollection() + public object SyncRoot { - Assert.Throws(() => CollectionUtils.Add(null, null)); + get { return this; } } - [Test] - public void AddNullObject() + public bool IsSynchronized { - ArrayList list = new ArrayList(); - CollectionUtils.Add(list, null); - Assert.IsTrue(list.Count == 1); + get { throw new NotImplementedException(); } } - [Test] - public void AddCollectionDoesNotImplementAdd() + public IEnumerator GetEnumerator() { - NoContainsNoAddCollection noAddCollection = new NoContainsNoAddCollection(); - Assert.Throws(() => CollectionUtils.Add(noAddCollection, null)); - } - - [Test] - public void AddValidElement() - { - ArrayList list = new ArrayList(); - object obj1 = new object(); - CollectionUtils.Add(list, obj1); - Assert.IsTrue(list.Count == 1); - } - - [Test] - public void ContainsAllNullTargetCollection() - { - Assert.Throws(() => CollectionUtils.ContainsAll(null, new ArrayList())); - } - - [Test] - public void ContainsAllSourceNullCollection() - { - Assert.Throws(() => CollectionUtils.ContainsAll(new ArrayList(), null)); - } - - [Test] - public void ContainsAllDoesNotImplementContains() - { - Assert.Throws(() => CollectionUtils.ContainsAll(new NoContainsNoAddCollection(), new ArrayList())); - } - - [Test] - public void DoesNotContainAllElements() - { - ArrayList target = new ArrayList(); - target.Add(1); - target.Add(2); - target.Add(3); - - ArrayList source = new ArrayList(); - source.Add(1); - - Assert.IsTrue(CollectionUtils.ContainsAll(target, source)); - } - - [Test] - public void ContainsAllElements() - { - ArrayList target = new ArrayList(); - target.Add(1); - target.Add(2); - target.Add(3); - - ArrayList source = new ArrayList(); - source.Add(1); - source.Add(2); - source.Add(3); - - Assert.IsTrue(CollectionUtils.ContainsAll(target, source)); - } - [Test] - public void ContainsAllElementsWithNoElementsInSourceCollection() - { - ArrayList target = new ArrayList(); - target.Add(1); - target.Add(2); - target.Add(3); - - ArrayList source = new ArrayList(); - Assert.IsTrue(CollectionUtils.ContainsAll(target, source)); - } - - [Test] - public void ContainsAllElementsWithNoElementsEitherCollection() - { - ArrayList target = new ArrayList(); - ArrayList source = new ArrayList(); - Assert.IsFalse(CollectionUtils.ContainsAll(target, source)); - } - - [Test] - public void ToArrayNullTargetCollection() - { - Assert.Throws(() => CollectionUtils.ToArrayList(null)); - } - - [Test] - public void ToArrayAllElements() - { - ArrayList target = new ArrayList(); - target.Add(1); - target.Add(2); - target.Add(3); - - ArrayList source = CollectionUtils.ToArrayList(target); - - Assert.AreEqual(target.Count, source.Count); - } - - [Test] - public void EmptyArrayElements() - { - ArrayList source = CollectionUtils.ToArrayList(new NoContainsNoAddCollection()); - Assert.AreEqual(0, source.Count); - } - - [Test] - public void RemoveAllTargetNullCollection() - { - Assert.Throws(() => CollectionUtils.RemoveAll(null, new ArrayList())); - } - - [Test] - public void RemoveAllSourceNullCollection() - { - Assert.Throws(() => CollectionUtils.RemoveAll(new ArrayList(), null)); - } - - [Test] - public void RemoveAllTargetCollectionDoesNotImplementContains() - { - Assert.Throws(() => CollectionUtils.RemoveAll(new NoContainsNoAddCollection(), new ArrayList())); - } - - [Test] - public void RemoveAllTargetCollectionDoesNotImplementRemove() - { - Assert.Throws(() => CollectionUtils.RemoveAll(new NoContainsNoAddCollection(), new ArrayList())); - } - - [Test] - public void RemoveAllNoElements() - { - ArrayList target = new ArrayList(); - target.Add(1); - target.Add(2); - target.Add(3); - - ArrayList source = new ArrayList(); - source.Add(4); - source.Add(5); - source.Add(6); - - CollectionUtils.RemoveAll(target, source); - Assert.IsTrue(3 == target.Count); - } - - [Test] - public void RemoveAllSomeElements() - { - ArrayList target = new ArrayList(); - target.Add(1); - target.Add(2); - target.Add(3); - target.Add(4); - target.Add(5); - - ArrayList source = new ArrayList(); - source.Add(4); - source.Add(5); - source.Add(6); - - CollectionUtils.RemoveAll(target, source); - Assert.IsTrue(3 == target.Count); - } - - [Test] - public void RemoveAllAllElements() - { - ArrayList target = new ArrayList(); - target.Add(1); - target.Add(2); - target.Add(3); - target.Add(4); - target.Add(5); - - ArrayList source = new ArrayList(); - source.Add(1); - source.Add(2); - source.Add(3); - source.Add(4); - source.Add(5); - source.Add(6); - - CollectionUtils.RemoveAll(target, source); - Assert.IsTrue(0 == target.Count); - } - - [Test] - public void IsCollectionEmptyOrNull() - { - ArrayList list = new ArrayList(); - Assert.IsTrue(CollectionUtils.IsEmpty(list)); - list.Add("foo"); - Assert.IsFalse(CollectionUtils.IsEmpty(list)); - list = null; - Assert.IsTrue(CollectionUtils.IsEmpty(list)); - } - - [Test] - public void IsDictionaryEmptyOrNull() - { - Hashtable t = new Hashtable(); - Assert.IsTrue(CollectionUtils.IsEmpty(t)); - t["foo"] = "bar"; - Assert.IsFalse(CollectionUtils.IsEmpty(t)); - t = null; - Assert.IsTrue(CollectionUtils.IsEmpty(t)); - } - - [Test] - public void FindValueOfType() - { - ArrayList list = new ArrayList(); - Assert.IsNull(CollectionUtils.FindValueOfType(list, typeof(String))); - list.Add("foo"); - object obj = CollectionUtils.FindValueOfType(list, typeof(String)); - Assert.IsNotNull(obj); - Assert.IsNotNull(obj as string); - string val = obj as string; - Assert.AreEqual("foo", val); - - list.Add(new TestObject("Joe", 34)); - obj = CollectionUtils.FindValueOfType(list, typeof(TestObject)); - Assert.IsNotNull(obj); - TestObject to = obj as TestObject; - Assert.IsNotNull(to); - Assert.AreEqual("Joe", to.Name); - - list.Add(new TestObject("Mary", 33)); - try - { - obj = CollectionUtils.FindValueOfType(list, typeof(TestObject)); - Assert.Fail("Should have thrown exception"); - } - catch (ArgumentException) - { - //ok - } - } - - [Test] - public void ToArray() - { - ArrayList list = new ArrayList(); - list.Add("mystring"); - string[] strList = (string[]) CollectionUtils.ToArray(list, typeof(string)); - Assert.AreEqual(1, strList.Length); - - try - { - CollectionUtils.ToArray(list, typeof(Type)); - Assert.Fail("should fail"); - } - catch (InvalidCastException) - { - } - } - - [Test] - public void StableSorting() - { - DictionaryEntry[] entries = new DictionaryEntry[] - { - new DictionaryEntry(5, 4), - new DictionaryEntry(5, 5), - new DictionaryEntry(3, 2), - new DictionaryEntry(3, 3), - new DictionaryEntry(1, 0), - new DictionaryEntry(1, 1), - }; - - ICollection resultList = CollectionUtils.StableSort(entries, new CollectionUtils.CompareCallback(CompareEntries)); - DictionaryEntry[] resultEntries = (DictionaryEntry[]) CollectionUtils.ToArray(resultList, typeof(DictionaryEntry)); - - Assert.AreEqual(0, resultEntries[0].Value); - Assert.AreEqual(1, resultEntries[1].Value); - Assert.AreEqual(2, resultEntries[2].Value); - Assert.AreEqual(3, resultEntries[3].Value); - Assert.AreEqual(4, resultEntries[4].Value); - Assert.AreEqual(5, resultEntries[5].Value); - } - - private int CompareEntries(object x, object y) - { - DictionaryEntry dex = (DictionaryEntry) x; - DictionaryEntry dey = (DictionaryEntry) y; - - return ((int) dex.Key).CompareTo(dey.Key); - } - - [Test] - public void FindFirstMatchReturnsNullIfAnyInputIsEmpty() - { - Assert.IsNull(CollectionUtils.FindFirstMatch(null, null)); - Assert.IsNull(CollectionUtils.FindFirstMatch(new string[0], new string[0])); - Assert.IsNull(CollectionUtils.FindFirstMatch(null, new string[] {"x"})); - Assert.IsNull(CollectionUtils.FindFirstMatch(new string[] {"x"}, null)); - } - - [Test] - public void FindFirstMatchReturnsFirstMatch() - { - ArrayList source = new ArrayList(); - string[] candidates = new string[] { "G", "B", "H" }; - source.AddRange( new string[] { "A", "B", "C" } ); - Assert.AreEqual( "B" , CollectionUtils.FindFirstMatch(source, candidates)); + return new Iterator(); } } + + [Test] + public void ContainsNullCollection() + { + CollectionUtils.Contains(null, null); + } + + [Test] + public void ContainsNullObject() + { + ArrayList list = new ArrayList(); + list.Add(null); + Assert.IsTrue(CollectionUtils.Contains(list, null)); + } + + [Test] + public void ContainsCollectionThatDoesNotImplementContains() + { + NoContainsNoAddCollection noAddCollection = new NoContainsNoAddCollection(); + CollectionUtils.Contains(noAddCollection, new object()); + } + + [Test] + public void ContainsValidElement() + { + ArrayList list = new ArrayList(); + list.Add(1); + list.Add(2); + list.Add(3); + list.Add(4); + + Assert.IsTrue(CollectionUtils.Contains(list, 3)); + } + + [Test] + public void ContainsDoesNotContainElement() + { + ArrayList list = new ArrayList(); + list.Add(1); + list.Add(2); + list.Add(3); + list.Add(4); + + Assert.IsFalse(CollectionUtils.Contains(list, 5)); + } + + [Test] + public void AddNullCollection() + { + Assert.Throws(() => CollectionUtils.Add(null, null)); + } + + [Test] + public void AddNullObject() + { + ArrayList list = new ArrayList(); + CollectionUtils.Add(list, null); + Assert.IsTrue(list.Count == 1); + } + + [Test] + public void AddCollectionDoesNotImplementAdd() + { + NoContainsNoAddCollection noAddCollection = new NoContainsNoAddCollection(); + Assert.Throws(() => CollectionUtils.Add(noAddCollection, null)); + } + + [Test] + public void AddValidElement() + { + ArrayList list = new ArrayList(); + object obj1 = new object(); + CollectionUtils.Add(list, obj1); + Assert.IsTrue(list.Count == 1); + } + + [Test] + public void ContainsAllNullTargetCollection() + { + Assert.Throws(() => CollectionUtils.ContainsAll(null, new ArrayList())); + } + + [Test] + public void ContainsAllSourceNullCollection() + { + Assert.Throws(() => CollectionUtils.ContainsAll(new ArrayList(), null)); + } + + [Test] + public void ContainsAllDoesNotImplementContains() + { + Assert.Throws(() => CollectionUtils.ContainsAll(new NoContainsNoAddCollection(), new ArrayList())); + } + + [Test] + public void DoesNotContainAllElements() + { + ArrayList target = new ArrayList(); + target.Add(1); + target.Add(2); + target.Add(3); + + ArrayList source = new ArrayList(); + source.Add(1); + + Assert.IsTrue(CollectionUtils.ContainsAll(target, source)); + } + + [Test] + public void ContainsAllElements() + { + ArrayList target = new ArrayList(); + target.Add(1); + target.Add(2); + target.Add(3); + + ArrayList source = new ArrayList(); + source.Add(1); + source.Add(2); + source.Add(3); + + Assert.IsTrue(CollectionUtils.ContainsAll(target, source)); + } + + [Test] + public void ContainsAllElementsWithNoElementsInSourceCollection() + { + ArrayList target = new ArrayList(); + target.Add(1); + target.Add(2); + target.Add(3); + + ArrayList source = new ArrayList(); + Assert.IsTrue(CollectionUtils.ContainsAll(target, source)); + } + + [Test] + public void ContainsAllElementsWithNoElementsEitherCollection() + { + ArrayList target = new ArrayList(); + ArrayList source = new ArrayList(); + Assert.IsFalse(CollectionUtils.ContainsAll(target, source)); + } + + [Test] + public void ToArrayNullTargetCollection() + { + Assert.Throws(() => CollectionUtils.ToArrayList(null)); + } + + [Test] + public void ToArrayAllElements() + { + ArrayList target = new ArrayList(); + target.Add(1); + target.Add(2); + target.Add(3); + + ArrayList source = CollectionUtils.ToArrayList(target); + + Assert.AreEqual(target.Count, source.Count); + } + + [Test] + public void EmptyArrayElements() + { + ArrayList source = CollectionUtils.ToArrayList(new NoContainsNoAddCollection()); + Assert.AreEqual(0, source.Count); + } + + [Test] + public void RemoveAllTargetNullCollection() + { + Assert.Throws(() => CollectionUtils.RemoveAll(null, new ArrayList())); + } + + [Test] + public void RemoveAllSourceNullCollection() + { + Assert.Throws(() => CollectionUtils.RemoveAll(new ArrayList(), null)); + } + + [Test] + public void RemoveAllTargetCollectionDoesNotImplementContains() + { + Assert.Throws(() => CollectionUtils.RemoveAll(new NoContainsNoAddCollection(), new ArrayList())); + } + + [Test] + public void RemoveAllTargetCollectionDoesNotImplementRemove() + { + Assert.Throws(() => CollectionUtils.RemoveAll(new NoContainsNoAddCollection(), new ArrayList())); + } + + [Test] + public void RemoveAllNoElements() + { + ArrayList target = new ArrayList(); + target.Add(1); + target.Add(2); + target.Add(3); + + ArrayList source = new ArrayList(); + source.Add(4); + source.Add(5); + source.Add(6); + + CollectionUtils.RemoveAll(target, source); + Assert.IsTrue(3 == target.Count); + } + + [Test] + public void RemoveAllSomeElements() + { + ArrayList target = new ArrayList(); + target.Add(1); + target.Add(2); + target.Add(3); + target.Add(4); + target.Add(5); + + ArrayList source = new ArrayList(); + source.Add(4); + source.Add(5); + source.Add(6); + + CollectionUtils.RemoveAll(target, source); + Assert.IsTrue(3 == target.Count); + } + + [Test] + public void RemoveAllAllElements() + { + ArrayList target = new ArrayList(); + target.Add(1); + target.Add(2); + target.Add(3); + target.Add(4); + target.Add(5); + + ArrayList source = new ArrayList(); + source.Add(1); + source.Add(2); + source.Add(3); + source.Add(4); + source.Add(5); + source.Add(6); + + CollectionUtils.RemoveAll(target, source); + Assert.IsTrue(0 == target.Count); + } + + [Test] + public void IsCollectionEmptyOrNull() + { + ArrayList list = new ArrayList(); + Assert.IsTrue(CollectionUtils.IsEmpty(list)); + list.Add("foo"); + Assert.IsFalse(CollectionUtils.IsEmpty(list)); + list = null; + Assert.IsTrue(CollectionUtils.IsEmpty(list)); + } + + [Test] + public void IsDictionaryEmptyOrNull() + { + Hashtable t = new Hashtable(); + Assert.IsTrue(CollectionUtils.IsEmpty(t)); + t["foo"] = "bar"; + Assert.IsFalse(CollectionUtils.IsEmpty(t)); + t = null; + Assert.IsTrue(CollectionUtils.IsEmpty(t)); + } + + [Test] + public void FindValueOfType() + { + ArrayList list = new ArrayList(); + Assert.IsNull(CollectionUtils.FindValueOfType(list, typeof(String))); + list.Add("foo"); + object obj = CollectionUtils.FindValueOfType(list, typeof(String)); + Assert.IsNotNull(obj); + Assert.IsNotNull(obj as string); + string val = obj as string; + Assert.AreEqual("foo", val); + + list.Add(new TestObject("Joe", 34)); + obj = CollectionUtils.FindValueOfType(list, typeof(TestObject)); + Assert.IsNotNull(obj); + TestObject to = obj as TestObject; + Assert.IsNotNull(to); + Assert.AreEqual("Joe", to.Name); + + list.Add(new TestObject("Mary", 33)); + try + { + obj = CollectionUtils.FindValueOfType(list, typeof(TestObject)); + Assert.Fail("Should have thrown exception"); + } + catch (ArgumentException) + { + //ok + } + } + + [Test] + public void ToArray() + { + ArrayList list = new ArrayList(); + list.Add("mystring"); + string[] strList = (string[]) CollectionUtils.ToArray(list, typeof(string)); + Assert.AreEqual(1, strList.Length); + + try + { + CollectionUtils.ToArray(list, typeof(Type)); + Assert.Fail("should fail"); + } + catch (InvalidCastException) + { + } + } + + [Test] + public void StableSorting() + { + DictionaryEntry[] entries = new DictionaryEntry[] { new DictionaryEntry(5, 4), new DictionaryEntry(5, 5), new DictionaryEntry(3, 2), new DictionaryEntry(3, 3), new DictionaryEntry(1, 0), new DictionaryEntry(1, 1), }; + + ICollection resultList = CollectionUtils.StableSort(entries, new CollectionUtils.CompareCallback(CompareEntries)); + DictionaryEntry[] resultEntries = (DictionaryEntry[]) CollectionUtils.ToArray(resultList, typeof(DictionaryEntry)); + + Assert.AreEqual(0, resultEntries[0].Value); + Assert.AreEqual(1, resultEntries[1].Value); + Assert.AreEqual(2, resultEntries[2].Value); + Assert.AreEqual(3, resultEntries[3].Value); + Assert.AreEqual(4, resultEntries[4].Value); + Assert.AreEqual(5, resultEntries[5].Value); + } + + private int CompareEntries(object x, object y) + { + DictionaryEntry dex = (DictionaryEntry) x; + DictionaryEntry dey = (DictionaryEntry) y; + + return ((int) dex.Key).CompareTo(dey.Key); + } + + [Test] + public void FindFirstMatchReturnsNullIfAnyInputIsEmpty() + { + Assert.IsNull(CollectionUtils.FindFirstMatch(null, null)); + Assert.IsNull(CollectionUtils.FindFirstMatch(new string[0], new string[0])); + Assert.IsNull(CollectionUtils.FindFirstMatch(null, new string[] { "x" })); + Assert.IsNull(CollectionUtils.FindFirstMatch(new string[] { "x" }, null)); + } + + [Test] + public void FindFirstMatchReturnsFirstMatch() + { + ArrayList source = new ArrayList(); + string[] candidates = new string[] { "G", "B", "H" }; + source.AddRange(new string[] { "A", "B", "C" }); + Assert.AreEqual("B", CollectionUtils.FindFirstMatch(source, candidates)); + } } diff --git a/test/Spring/Spring.Core.Tests/Util/ConfigXmlDocumentTests.cs b/test/Spring/Spring.Core.Tests/Util/ConfigXmlDocumentTests.cs index dca65307..7aa97af6 100644 --- a/test/Spring/Spring.Core.Tests/Util/ConfigXmlDocumentTests.cs +++ b/test/Spring/Spring.Core.Tests/Util/ConfigXmlDocumentTests.cs @@ -25,73 +25,72 @@ using NUnit.Framework; #endregion -namespace Spring.Util +namespace Spring.Util; + +/// +/// +/// +/// Erich Eichinger +[TestFixture] +public class ConfigXmlDocumentTests { - /// - /// - /// - /// Erich Eichinger - [TestFixture] - public class ConfigXmlDocumentTests + [Test] + public void LoadXmlStoresTextPosition() { - [Test] - public void LoadXmlStoresTextPosition() - { - ConfigXmlDocument xmlDoc = new ConfigXmlDocument(); - string xmlText = TestResourceLoader.GetText( this, "_SampleConfig.xml" ); - xmlDoc.LoadXml( "MYXML", xmlText ); - ITextPosition pos = ((ITextPosition)xmlDoc.SelectSingleNode("//property")); - Assert.AreEqual("MYXML", pos.Filename); - Assert.AreEqual(5, pos.LineNumber); - Assert.AreEqual(14, pos.LinePosition); - } - - [Test] - public void LoadReaderStoresTextPosition() - { - ConfigXmlDocument xmlDoc = new ConfigXmlDocument(); - Stream istm = TestResourceLoader.GetStream( this, "_SampleConfig.xml" ); - xmlDoc.Load( "MYXML", new XmlTextReader( istm ) ); - ITextPosition pos = ((ITextPosition)xmlDoc.SelectSingleNode("//property")); - Assert.AreEqual("MYXML", pos.Filename); - Assert.AreEqual(5, pos.LineNumber); - Assert.AreEqual(14, pos.LinePosition); - } - - [Test] - public void LoadStreamStoresTextPosition() - { - ConfigXmlDocument xmlDoc = new ConfigXmlDocument(); - Stream istm = TestResourceLoader.GetStream( this, "_SampleConfig.xml" ); - xmlDoc.Load( "MYXML", istm ); - ITextPosition pos = ((ITextPosition)xmlDoc.SelectSingleNode("//property")); - Assert.AreEqual("MYXML", pos.Filename); - Assert.AreEqual(5, pos.LineNumber); - Assert.AreEqual(14, pos.LinePosition); - } - - [Test] - public void LoadTextReaderStoresTextPosition() - { - ConfigXmlDocument xmlDoc = new ConfigXmlDocument(); - Stream istm = TestResourceLoader.GetStream( this, "_SampleConfig.xml" ); - xmlDoc.Load( "MYXML", new StreamReader(istm) ); - ITextPosition pos = ((ITextPosition)xmlDoc.SelectSingleNode("//property")); - Assert.AreEqual("MYXML", pos.Filename); - Assert.AreEqual(5, pos.LineNumber); - Assert.AreEqual(14, pos.LinePosition); - } - - [Test] - public void CanConfigFilenameAndLine() - { - ConfigXmlDocument xmlDoc = new ConfigXmlDocument(); - Stream istm = TestResourceLoader.GetStream( this, "_SampleConfig.xml" ); - xmlDoc.Load( "MYXML", new StreamReader(istm) ); - XmlNode node = xmlDoc.SelectSingleNode("//property"); - Assert.AreEqual("MYXML", ConfigurationUtils.GetFileName(node) ); - Assert.AreEqual(5, ConfigurationUtils.GetLineNumber(node) ); - //Assert.AreEqual(14, pos.LinePosition); <- IConfigErrorInfo/IConfigXmlNode do not support LinePosition - } + ConfigXmlDocument xmlDoc = new ConfigXmlDocument(); + string xmlText = TestResourceLoader.GetText(this, "_SampleConfig.xml"); + xmlDoc.LoadXml("MYXML", xmlText); + ITextPosition pos = ((ITextPosition) xmlDoc.SelectSingleNode("//property")); + Assert.AreEqual("MYXML", pos.Filename); + Assert.AreEqual(5, pos.LineNumber); + Assert.AreEqual(14, pos.LinePosition); } -} \ No newline at end of file + + [Test] + public void LoadReaderStoresTextPosition() + { + ConfigXmlDocument xmlDoc = new ConfigXmlDocument(); + Stream istm = TestResourceLoader.GetStream(this, "_SampleConfig.xml"); + xmlDoc.Load("MYXML", new XmlTextReader(istm)); + ITextPosition pos = ((ITextPosition) xmlDoc.SelectSingleNode("//property")); + Assert.AreEqual("MYXML", pos.Filename); + Assert.AreEqual(5, pos.LineNumber); + Assert.AreEqual(14, pos.LinePosition); + } + + [Test] + public void LoadStreamStoresTextPosition() + { + ConfigXmlDocument xmlDoc = new ConfigXmlDocument(); + Stream istm = TestResourceLoader.GetStream(this, "_SampleConfig.xml"); + xmlDoc.Load("MYXML", istm); + ITextPosition pos = ((ITextPosition) xmlDoc.SelectSingleNode("//property")); + Assert.AreEqual("MYXML", pos.Filename); + Assert.AreEqual(5, pos.LineNumber); + Assert.AreEqual(14, pos.LinePosition); + } + + [Test] + public void LoadTextReaderStoresTextPosition() + { + ConfigXmlDocument xmlDoc = new ConfigXmlDocument(); + Stream istm = TestResourceLoader.GetStream(this, "_SampleConfig.xml"); + xmlDoc.Load("MYXML", new StreamReader(istm)); + ITextPosition pos = ((ITextPosition) xmlDoc.SelectSingleNode("//property")); + Assert.AreEqual("MYXML", pos.Filename); + Assert.AreEqual(5, pos.LineNumber); + Assert.AreEqual(14, pos.LinePosition); + } + + [Test] + public void CanConfigFilenameAndLine() + { + ConfigXmlDocument xmlDoc = new ConfigXmlDocument(); + Stream istm = TestResourceLoader.GetStream(this, "_SampleConfig.xml"); + xmlDoc.Load("MYXML", new StreamReader(istm)); + XmlNode node = xmlDoc.SelectSingleNode("//property"); + Assert.AreEqual("MYXML", ConfigurationUtils.GetFileName(node)); + Assert.AreEqual(5, ConfigurationUtils.GetLineNumber(node)); + //Assert.AreEqual(14, pos.LinePosition); <- IConfigErrorInfo/IConfigXmlNode do not support LinePosition + } +} diff --git a/test/Spring/Spring.Core.Tests/Util/DefensiveEventRaiserTests.cs b/test/Spring/Spring.Core.Tests/Util/DefensiveEventRaiserTests.cs index 829f5a5f..2ab90e01 100644 --- a/test/Spring/Spring.Core.Tests/Util/DefensiveEventRaiserTests.cs +++ b/test/Spring/Spring.Core.Tests/Util/DefensiveEventRaiserTests.cs @@ -24,46 +24,49 @@ using NUnit.Framework; #endregion -namespace Spring.Util +namespace Spring.Util; + +/// +/// Unit tests for the DefensiveEventRaiser class. +/// +/// Rick Evans +[TestFixture] +public sealed class DefensiveEventRaiserTests { - /// - /// Unit tests for the DefensiveEventRaiser class. - /// - /// Rick Evans - [TestFixture] - public sealed class DefensiveEventRaiserTests + [Test] + public void RaiseSwallowsExceptionRaisedByHandlers() { - [Test] - public void RaiseSwallowsExceptionRaisedByHandlers() + OneThirstyDude dude = new OneThirstyDude(); + Soda bru = new Soda(); + bru.Pop += new PopHandler(dude.HandlePopWithException); + bru.OnPop("Iron Brew", new DefensiveEventRaiser()); + Assert.AreEqual("Iron Brew", dude.Soda); // should have got through before exception was thrown + } + + [Test] + public void RaiseSwallowsExceptionRaisedByHandlerButCallsAllOtherHandlers() + { + bool firstCall = false; + bool secondCall = false; + bool thirdCall = false; + + OneThirstyDude dude = new OneThirstyDude(); + Soda bru = new Soda(); + bru.Pop += (sender, soda) => firstCall = true; + bru.Pop += (sender, soda) => { - OneThirstyDude dude = new OneThirstyDude(); - Soda bru = new Soda(); - bru.Pop += new PopHandler(dude.HandlePopWithException); - bru.OnPop("Iron Brew", new DefensiveEventRaiser()); - Assert.AreEqual("Iron Brew", dude.Soda); // should have got through before exception was thrown - } + secondCall = true; + throw new Exception(); + }; + bru.Pop += (sender, soda) => { thirdCall = true; }; - [Test] - public void RaiseSwallowsExceptionRaisedByHandlerButCallsAllOtherHandlers() - { - bool firstCall = false; - bool secondCall = false; - bool thirdCall = false; + DefensiveEventRaiser eventRaiser = new DefensiveEventRaiser(); - OneThirstyDude dude = new OneThirstyDude(); - Soda bru = new Soda(); - bru.Pop += (sender, soda) => firstCall = true; - bru.Pop += (sender, soda) => { secondCall = true; throw new Exception(); }; - bru.Pop += (sender, soda) => { thirdCall = true; }; + IEventExceptionsCollector exceptions = bru.OnPop("Iron Brew", eventRaiser); - DefensiveEventRaiser eventRaiser = new DefensiveEventRaiser(); - - IEventExceptionsCollector exceptions = bru.OnPop( "Iron Brew", eventRaiser ); - - Assert.AreEqual(1, exceptions.Exceptions.Count); - Assert.IsTrue(firstCall); - Assert.IsTrue(secondCall); - Assert.IsTrue(thirdCall); - } + Assert.AreEqual(1, exceptions.Exceptions.Count); + Assert.IsTrue(firstCall); + Assert.IsTrue(secondCall); + Assert.IsTrue(thirdCall); } } diff --git a/test/Spring/Spring.Core.Tests/Util/DelegateInfoTests.cs b/test/Spring/Spring.Core.Tests/Util/DelegateInfoTests.cs index 1c75f5cb..6ecb8aee 100644 --- a/test/Spring/Spring.Core.Tests/Util/DelegateInfoTests.cs +++ b/test/Spring/Spring.Core.Tests/Util/DelegateInfoTests.cs @@ -25,159 +25,158 @@ using NUnit.Framework; #endregion -namespace Spring.Util +namespace Spring.Util; + +/// +/// Unit tests for the DelegateInfo class. +/// +/// Rick Evans +[TestFixture] +public sealed class DelegateInfoTests { - /// - /// Unit tests for the DelegateInfo class. - /// - /// Rick Evans - [TestFixture] - public sealed class DelegateInfoTests - { - [Test] - public void Instantiation() - { - new DelegateInfo(typeof (EventHandler)); - } + [Test] + public void Instantiation() + { + new DelegateInfo(typeof(EventHandler)); + } - [Test] - public void InstantiationWithBadType() - { - Assert.Throws(() => new DelegateInfo(typeof (string))); - } + [Test] + public void InstantiationWithBadType() + { + Assert.Throws(() => new DelegateInfo(typeof(string))); + } - [Test] - public void IsDelegateWithBadType() - { - Assert.IsFalse(DelegateInfo.IsDelegate(typeof (string))); - } + [Test] + public void IsDelegateWithBadType() + { + Assert.IsFalse(DelegateInfo.IsDelegate(typeof(string))); + } - [Test] - public void IsDelegateWithNullType() - { - Assert.IsFalse(DelegateInfo.IsDelegate(null)); - } + [Test] + public void IsDelegateWithNullType() + { + Assert.IsFalse(DelegateInfo.IsDelegate(null)); + } - [Test] - public void IsDelegate() - { - Assert.IsTrue(DelegateInfo.IsDelegate(typeof (EventHandler))); - } + [Test] + public void IsDelegate() + { + Assert.IsTrue(DelegateInfo.IsDelegate(typeof(EventHandler))); + } - [Test] - public void GetReturnType() - { - DelegateInfo del = new DelegateInfo(typeof (EventHandler)); - Assert.AreEqual(typeof (void), del.GetReturnType()); - } + [Test] + public void GetReturnType() + { + DelegateInfo del = new DelegateInfo(typeof(EventHandler)); + Assert.AreEqual(typeof(void), del.GetReturnType()); + } - [Test] - public void GetReturnTypeWithNonVoidReturningDelegate() - { - DelegateInfo del = new DelegateInfo(typeof (FooHandler)); - Assert.AreEqual(typeof (string), del.GetReturnType()); - } + [Test] + public void GetReturnTypeWithNonVoidReturningDelegate() + { + DelegateInfo del = new DelegateInfo(typeof(FooHandler)); + Assert.AreEqual(typeof(string), del.GetReturnType()); + } - [Test] - public void GetParameterTypesWithNoArgHandler() - { - DelegateInfo del = new DelegateInfo(typeof (NoParametersHandler)); - Type[] types = del.GetParameterTypes(); - Assert.IsNotNull(types); - Assert.AreEqual(0, types.Length); - } + [Test] + public void GetParameterTypesWithNoArgHandler() + { + DelegateInfo del = new DelegateInfo(typeof(NoParametersHandler)); + Type[] types = del.GetParameterTypes(); + Assert.IsNotNull(types); + Assert.AreEqual(0, types.Length); + } - [Test] - public void GetParameterTypes() - { - DelegateInfo del = new DelegateInfo(typeof (FooHandler)); - Type[] types = del.GetParameterTypes(); - Assert.IsNotNull(types); - Assert.AreEqual(3, types.Length); - } + [Test] + public void GetParameterTypes() + { + DelegateInfo del = new DelegateInfo(typeof(FooHandler)); + Type[] types = del.GetParameterTypes(); + Assert.IsNotNull(types); + Assert.AreEqual(3, types.Length); + } - [Test] - public void IsSignatureCompatibleWithBadMethods() - { - DelegateInfo del = new DelegateInfo(typeof (FooHandler)); + [Test] + public void IsSignatureCompatibleWithBadMethods() + { + DelegateInfo del = new DelegateInfo(typeof(FooHandler)); - // null method... - MethodInfo method = GetType().GetMethod("SeaBass said that? Well, if that guy over there is SeaBass..."); - Assert.IsFalse(del.IsSignatureCompatible(method)); + // null method... + MethodInfo method = GetType().GetMethod("SeaBass said that? Well, if that guy over there is SeaBass..."); + Assert.IsFalse(del.IsSignatureCompatible(method)); - // method that doesn;t have the required number of parameters... - method = GetType().GetMethod("OddNumberOfParametersForFooHandler"); - Assert.IsFalse(del.IsSignatureCompatible(method)); + // method that doesn;t have the required number of parameters... + method = GetType().GetMethod("OddNumberOfParametersForFooHandler"); + Assert.IsFalse(del.IsSignatureCompatible(method)); - // method that doesn't have the required number of parameters... - method = GetType().GetMethod("IncompatibleParametersForFooHandler"); - Assert.IsFalse(del.IsSignatureCompatible(method)); - } + // method that doesn't have the required number of parameters... + method = GetType().GetMethod("IncompatibleParametersForFooHandler"); + Assert.IsFalse(del.IsSignatureCompatible(method)); + } - public string OddNumberOfParametersForFooHandler(string bar, int x) - { - return string.Empty; - } + public string OddNumberOfParametersForFooHandler(string bar, int x) + { + return string.Empty; + } - public string IncompatibleParametersForFooHandler(string bar, int x, string nope) - { - return string.Empty; - } + public string IncompatibleParametersForFooHandler(string bar, int x, string nope) + { + return string.Empty; + } - [Test] - public void IsSignatureCompatibleWithInnerClassStaticMethod() - { - DelegateInfo del = new DelegateInfo(typeof (FooHandler)); - MethodInfo method = - typeof (Yossarian).GetMethod( - "DoFoo", - BindingFlags.Public | BindingFlags.Static); - Assert.IsTrue(del.IsSignatureCompatible(method)); - } + [Test] + public void IsSignatureCompatibleWithInnerClassStaticMethod() + { + DelegateInfo del = new DelegateInfo(typeof(FooHandler)); + MethodInfo method = + typeof(Yossarian).GetMethod( + "DoFoo", + BindingFlags.Public | BindingFlags.Static); + Assert.IsTrue(del.IsSignatureCompatible(method)); + } - [Test] - public void IsSignatureCompatible() - { - DelegateInfo del = new DelegateInfo(typeof (FooHandler)); - MethodInfo method = GetType().GetMethod("DoFoo"); - Assert.IsFalse(del.IsSignatureCompatible(method)); - } + [Test] + public void IsSignatureCompatible() + { + DelegateInfo del = new DelegateInfo(typeof(FooHandler)); + MethodInfo method = GetType().GetMethod("DoFoo"); + Assert.IsFalse(del.IsSignatureCompatible(method)); + } - [Test] - public void IsSignatureCompatibleStaticVersion() - { - EventInfo evt = typeof (Assembly).GetEvent("ModuleResolve"); + [Test] + public void IsSignatureCompatibleStaticVersion() + { + EventInfo evt = typeof(Assembly).GetEvent("ModuleResolve"); - MethodInfo rubbishMethod = GetType().GetMethod("MethodSignatureIsCompatibleStatic"); - Assert.IsFalse(DelegateInfo.IsSignatureCompatible(evt, rubbishMethod)); + MethodInfo rubbishMethod = GetType().GetMethod("MethodSignatureIsCompatibleStatic"); + Assert.IsFalse(DelegateInfo.IsSignatureCompatible(evt, rubbishMethod)); - MethodInfo compatibleMethod = typeof (Yossarian).GetMethod("Resolve"); - Assert.IsTrue(DelegateInfo.IsSignatureCompatible(evt, compatibleMethod)); + MethodInfo compatibleMethod = typeof(Yossarian).GetMethod("Resolve"); + Assert.IsTrue(DelegateInfo.IsSignatureCompatible(evt, compatibleMethod)); - Assert.IsFalse(DelegateInfo.IsSignatureCompatible(null, compatibleMethod)); - Assert.IsFalse(DelegateInfo.IsSignatureCompatible(evt, null)); - } + Assert.IsFalse(DelegateInfo.IsSignatureCompatible(null, compatibleMethod)); + Assert.IsFalse(DelegateInfo.IsSignatureCompatible(evt, null)); + } - private string DoFoo(string bar, int x, EventArgs e) - { - return bar; - } + private string DoFoo(string bar, int x, EventArgs e) + { + return bar; + } - internal sealed class Yossarian - { - public static string DoFoo(string bar, int x, EventArgs e) - { - return bar; - } + internal sealed class Yossarian + { + public static string DoFoo(string bar, int x, EventArgs e) + { + return bar; + } - public Module Resolve(object sender, ResolveEventArgs e) - { - return null; - } - } - } + public Module Resolve(object sender, ResolveEventArgs e) + { + return null; + } + } +} - internal delegate string FooHandler(string bar, int x, EventArgs e); +internal delegate string FooHandler(string bar, int x, EventArgs e); - internal delegate void NoParametersHandler(); -} \ No newline at end of file +internal delegate void NoParametersHandler(); diff --git a/test/Spring/Spring.Core.Tests/Util/EventRaiserTests.cs b/test/Spring/Spring.Core.Tests/Util/EventRaiserTests.cs index 49310ff9..b2e6feb7 100644 --- a/test/Spring/Spring.Core.Tests/Util/EventRaiserTests.cs +++ b/test/Spring/Spring.Core.Tests/Util/EventRaiserTests.cs @@ -25,100 +25,99 @@ using NUnit.Framework; #endregion -namespace Spring.Util +namespace Spring.Util; + +/// +/// Unit tests for the EventRaiser class. +/// +/// Rick Evans +[TestFixture] +public sealed class EventRaiserTests { - /// - /// Unit tests for the EventRaiser class. - /// - /// Rick Evans - [TestFixture] - public sealed class EventRaiserTests + [Test] + public void Raise() { - [Test] - public void Raise () - { - OneThirstyDude dude = new OneThirstyDude (); - Soda bru = new Soda (); - bru.Pop += new PopHandler (dude.HandlePop); - bru.OnPop ("Iron Brew", new EventRaiser ()); - Assert.AreEqual ("Iron Brew", dude.Soda); - } - - [Test] - public void RaiseWithBadNumberOfArguments () - { - OneThirstyDude dude = new OneThirstyDude (); - Soda bru = new Soda (); - bru.Pop += new PopHandler (dude.HandlePop); - Assert.Throws(() => bru.OnPopWithBadNumberOfArguments ("Iron Brew", new EventRaiser ())); - } - - [Test] - public void RaiseWithNullEvent () - { - OneThirstyDude dude = new OneThirstyDude (); - Soda bru = new Soda (); - bru.Pop += new PopHandler (dude.HandlePop); - bru.OnPopWithNullEvent ("Iron Brew", new EventRaiser ()); - Assert.AreEqual (string.Empty, dude.Soda); - } - - public void RaiseWithAnEventHandlerThatThrowsAnException () - { - OneThirstyDude dude = new OneThirstyDude (); - Soda bru = new Soda (); - bru.Pop += new PopHandler (dude.HandlePopWithException); - Assert.Throws(() => bru.OnPop ("Iron Brew", new EventRaiser ()), "Iron Brew"); - } - } - - internal delegate void PopHandler (object sender, string soda); - - internal sealed class Soda - { - public event PopHandler Pop; - - public IEventExceptionsCollector OnPop (string soda, EventRaiser raiser) - { - return raiser.Raise (Pop, this, soda); - } - - public void OnPopWithBadNumberOfArguments (string soda, EventRaiser raiser) - { - raiser.Raise (Pop, /*this,*/ soda); // wrong number of args to the event - } - - public void OnPopWithNullEvent (string soda, EventRaiser raiser) - { - raiser.Raise (null, this, soda); // no event... - } + OneThirstyDude dude = new OneThirstyDude(); + Soda bru = new Soda(); + bru.Pop += new PopHandler(dude.HandlePop); + bru.OnPop("Iron Brew", new EventRaiser()); + Assert.AreEqual("Iron Brew", dude.Soda); } - internal sealed class OneThirstyDude + [Test] + public void RaiseWithBadNumberOfArguments() { - public void HandlePop (object sender, string soda) - { - _soda = soda; - } + OneThirstyDude dude = new OneThirstyDude(); + Soda bru = new Soda(); + bru.Pop += new PopHandler(dude.HandlePop); + Assert.Throws(() => bru.OnPopWithBadNumberOfArguments("Iron Brew", new EventRaiser())); + } - public void HandlePopWithException (object sender, string soda) - { - _soda = soda; - throw new FormatException (soda); - } + [Test] + public void RaiseWithNullEvent() + { + OneThirstyDude dude = new OneThirstyDude(); + Soda bru = new Soda(); + bru.Pop += new PopHandler(dude.HandlePop); + bru.OnPopWithNullEvent("Iron Brew", new EventRaiser()); + Assert.AreEqual(string.Empty, dude.Soda); + } - public static void StaticHandlePop(object sender, string soda) - { - } - - public string Soda - { - get - { - return _soda; - } - } - - private string _soda = string.Empty; + public void RaiseWithAnEventHandlerThatThrowsAnException() + { + OneThirstyDude dude = new OneThirstyDude(); + Soda bru = new Soda(); + bru.Pop += new PopHandler(dude.HandlePopWithException); + Assert.Throws(() => bru.OnPop("Iron Brew", new EventRaiser()), "Iron Brew"); } } + +internal delegate void PopHandler(object sender, string soda); + +internal sealed class Soda +{ + public event PopHandler Pop; + + public IEventExceptionsCollector OnPop(string soda, EventRaiser raiser) + { + return raiser.Raise(Pop, this, soda); + } + + public void OnPopWithBadNumberOfArguments(string soda, EventRaiser raiser) + { + raiser.Raise(Pop, /*this,*/ soda); // wrong number of args to the event + } + + public void OnPopWithNullEvent(string soda, EventRaiser raiser) + { + raiser.Raise(null, this, soda); // no event... + } +} + +internal sealed class OneThirstyDude +{ + public void HandlePop(object sender, string soda) + { + _soda = soda; + } + + public void HandlePopWithException(object sender, string soda) + { + _soda = soda; + throw new FormatException(soda); + } + + public static void StaticHandlePop(object sender, string soda) + { + } + + public string Soda + { + get + { + return _soda; + } + } + + private string _soda = string.Empty; +} diff --git a/test/Spring/Spring.Core.Tests/Util/NumberUtilsTests.cs b/test/Spring/Spring.Core.Tests/Util/NumberUtilsTests.cs index 0b033bfa..2184b2f4 100644 --- a/test/Spring/Spring.Core.Tests/Util/NumberUtilsTests.cs +++ b/test/Spring/Spring.Core.Tests/Util/NumberUtilsTests.cs @@ -24,226 +24,225 @@ using NUnit.Framework; #endregion -namespace Spring.Util +namespace Spring.Util; + +/// +/// Unit tests for the NumberUtils class. +/// +/// Rick Evans +[TestFixture] +public sealed class NumberUtilsTests { - /// - /// Unit tests for the NumberUtils class. - /// - /// Rick Evans - [TestFixture] - public sealed class NumberUtilsTests + [Test] + public void IsInteger() { - [Test] - public void IsInteger() + Assert.IsTrue(NumberUtils.IsInteger(10)); + Assert.IsTrue(NumberUtils.IsInteger(10L)); + Assert.IsTrue(NumberUtils.IsInteger((short) 10)); + Assert.IsFalse(NumberUtils.IsInteger('e')); + Assert.IsFalse(NumberUtils.IsInteger(null)); + Assert.IsFalse(NumberUtils.IsInteger(9.5D)); + Assert.IsFalse(NumberUtils.IsInteger(9.5F)); + Assert.IsFalse(NumberUtils.IsInteger(this)); + Assert.IsFalse(NumberUtils.IsInteger(null)); + Assert.IsFalse(NumberUtils.IsInteger(string.Empty)); + } + + [Test] + public void IsDecimal() + { + Assert.IsFalse(NumberUtils.IsDecimal(10)); + Assert.IsFalse(NumberUtils.IsDecimal(10L)); + Assert.IsFalse(NumberUtils.IsDecimal((short) 10)); + Assert.IsFalse(NumberUtils.IsDecimal('e')); + Assert.IsFalse(NumberUtils.IsDecimal(null)); + Assert.IsTrue(NumberUtils.IsDecimal(9.5D)); + Assert.IsTrue(NumberUtils.IsDecimal(9.5F)); + Assert.IsFalse(NumberUtils.IsDecimal(this)); + Assert.IsFalse(NumberUtils.IsDecimal(null)); + Assert.IsFalse(NumberUtils.IsDecimal(string.Empty)); + } + + [Test] + public void IsNumber() + { + Assert.IsTrue(NumberUtils.IsNumber(10)); + Assert.IsTrue(NumberUtils.IsNumber(10L)); + Assert.IsTrue(NumberUtils.IsNumber((short) 10)); + Assert.IsFalse(NumberUtils.IsNumber('e')); + Assert.IsFalse(NumberUtils.IsNumber(null)); + Assert.IsTrue(NumberUtils.IsNumber(9.5D)); + Assert.IsTrue(NumberUtils.IsNumber(9.5F)); + Assert.IsFalse(NumberUtils.IsNumber(this)); + Assert.IsFalse(NumberUtils.IsNumber(null)); + Assert.IsFalse(NumberUtils.IsNumber(string.Empty)); + } + + [Test] + public void IsZero() + { + Assert.IsFalse(NumberUtils.IsZero((short) 2)); + Assert.IsTrue(NumberUtils.IsZero((short) 0)); + + Assert.IsFalse(NumberUtils.IsZero(2)); + Assert.IsTrue(NumberUtils.IsZero(0)); + + Assert.IsFalse(NumberUtils.IsZero((long) 2)); + Assert.IsTrue(NumberUtils.IsZero((long) 0)); + + Assert.IsFalse(NumberUtils.IsZero((ushort) 2)); + Assert.IsTrue(NumberUtils.IsZero((ushort) 0)); + + Assert.IsFalse(NumberUtils.IsZero((uint) 2)); + Assert.IsTrue(NumberUtils.IsZero((uint) 0)); + + Assert.IsFalse(NumberUtils.IsZero((ulong) 2)); + Assert.IsTrue(NumberUtils.IsZero((ulong) 0)); + + Assert.IsFalse(NumberUtils.IsZero((decimal) 2)); + Assert.IsTrue(NumberUtils.IsZero((decimal) 0)); + + Assert.IsTrue(NumberUtils.IsZero((byte?) 0)); + Assert.IsFalse(NumberUtils.IsZero((byte) 2)); + + Assert.IsTrue(NumberUtils.IsZero((sbyte?) 0)); + Assert.IsFalse(NumberUtils.IsZero((sbyte) 2)); + } + + [Test] + public void NegateNull() + { + Assert.Throws(() => NumberUtils.Negate(null)); + } + + [Test] + public void NegateString() + { + Assert.Throws(() => NumberUtils.Negate(string.Empty)); + } + + [Test] + public void Negate() + { + Assert.AreEqual(-10, NumberUtils.Negate(10)); + } + + [Test] + public void CoercesTypes() + { + object x = (int) 1; + object y = (double) 2; + NumberUtils.CoerceTypes(ref x, ref y); + Assert.AreEqual(typeof(double), x.GetType()); + } + + [Test] + public void Add() + { + Assert.AreEqual(5, NumberUtils.Add(2, 3)); + try { - Assert.IsTrue(NumberUtils.IsInteger(10)); - Assert.IsTrue(NumberUtils.IsInteger(10L)); - Assert.IsTrue(NumberUtils.IsInteger((short) 10)); - Assert.IsFalse(NumberUtils.IsInteger('e')); - Assert.IsFalse(NumberUtils.IsInteger(null)); - Assert.IsFalse(NumberUtils.IsInteger(9.5D)); - Assert.IsFalse(NumberUtils.IsInteger(9.5F)); - Assert.IsFalse(NumberUtils.IsInteger(this)); - Assert.IsFalse(NumberUtils.IsInteger(null)); - Assert.IsFalse(NumberUtils.IsInteger(string.Empty)); + NumberUtils.Add(2, "3"); + Assert.Fail(); } - - [Test] - public void IsDecimal() + catch (ArgumentException) { - Assert.IsFalse(NumberUtils.IsDecimal(10)); - Assert.IsFalse(NumberUtils.IsDecimal(10L)); - Assert.IsFalse(NumberUtils.IsDecimal((short) 10)); - Assert.IsFalse(NumberUtils.IsDecimal('e')); - Assert.IsFalse(NumberUtils.IsDecimal(null)); - Assert.IsTrue(NumberUtils.IsDecimal(9.5D)); - Assert.IsTrue(NumberUtils.IsDecimal(9.5F)); - Assert.IsFalse(NumberUtils.IsDecimal(this)); - Assert.IsFalse(NumberUtils.IsDecimal(null)); - Assert.IsFalse(NumberUtils.IsDecimal(string.Empty)); - } - - [Test] - public void IsNumber() - { - Assert.IsTrue(NumberUtils.IsNumber(10)); - Assert.IsTrue(NumberUtils.IsNumber(10L)); - Assert.IsTrue(NumberUtils.IsNumber((short) 10)); - Assert.IsFalse(NumberUtils.IsNumber('e')); - Assert.IsFalse(NumberUtils.IsNumber(null)); - Assert.IsTrue(NumberUtils.IsNumber(9.5D)); - Assert.IsTrue(NumberUtils.IsNumber(9.5F)); - Assert.IsFalse(NumberUtils.IsNumber(this)); - Assert.IsFalse(NumberUtils.IsNumber(null)); - Assert.IsFalse(NumberUtils.IsNumber(string.Empty)); - } - - [Test] - public void IsZero() - { - Assert.IsFalse(NumberUtils.IsZero((short) 2)); - Assert.IsTrue(NumberUtils.IsZero((short) 0)); - - Assert.IsFalse(NumberUtils.IsZero(2)); - Assert.IsTrue(NumberUtils.IsZero(0)); - - Assert.IsFalse(NumberUtils.IsZero((long) 2)); - Assert.IsTrue(NumberUtils.IsZero((long) 0)); - - Assert.IsFalse(NumberUtils.IsZero((ushort) 2)); - Assert.IsTrue(NumberUtils.IsZero((ushort) 0)); - - Assert.IsFalse(NumberUtils.IsZero((uint) 2)); - Assert.IsTrue(NumberUtils.IsZero((uint) 0)); - - Assert.IsFalse(NumberUtils.IsZero((ulong) 2)); - Assert.IsTrue(NumberUtils.IsZero((ulong) 0)); - - Assert.IsFalse(NumberUtils.IsZero((decimal) 2)); - Assert.IsTrue(NumberUtils.IsZero((decimal) 0)); - - Assert.IsTrue(NumberUtils.IsZero((byte?) 0)); - Assert.IsFalse(NumberUtils.IsZero((byte) 2)); - - Assert.IsTrue(NumberUtils.IsZero((sbyte?) 0)); - Assert.IsFalse(NumberUtils.IsZero((sbyte) 2)); - } - - [Test] - public void NegateNull() - { - Assert.Throws(() => NumberUtils.Negate(null)); - } - - [Test] - public void NegateString() - { - Assert.Throws(() => NumberUtils.Negate(string.Empty)); - } - - [Test] - public void Negate() - { - Assert.AreEqual(-10, NumberUtils.Negate(10)); - } - - [Test] - public void CoercesTypes() - { - object x = (int) 1; - object y = (double) 2; - NumberUtils.CoerceTypes(ref x, ref y); - Assert.AreEqual(typeof(double), x.GetType()); - } - - [Test] - public void Add() - { - Assert.AreEqual(5, NumberUtils.Add(2, 3)); - try - { - NumberUtils.Add(2, "3"); - Assert.Fail(); - } - catch (ArgumentException) - { - } - } - - [Test] - public void BitwiseNot() - { - Assert.AreEqual(~(byte) 2, NumberUtils.BitwiseNot((byte) 2)); - Assert.AreEqual(~(sbyte) 2, NumberUtils.BitwiseNot((sbyte) 2)); - Assert.AreEqual(~(short) 2, NumberUtils.BitwiseNot((short) 2)); - Assert.AreEqual(~(ushort) 2, NumberUtils.BitwiseNot((ushort) 2)); - Assert.AreEqual(~(int) 2, NumberUtils.BitwiseNot((int) 2)); - Assert.AreEqual(~(uint) 2, NumberUtils.BitwiseNot((uint) 2)); - Assert.AreEqual(~(long) 2, NumberUtils.BitwiseNot((long) 2)); - Assert.AreEqual(~(ulong) 2, NumberUtils.BitwiseNot((ulong) 2)); - Assert.AreEqual(false, NumberUtils.BitwiseNot(true)); - try - { - NumberUtils.BitwiseNot((double) 2.0); - Assert.Fail(); - } - catch (ArgumentException) - { - } - } - - [Test] - public void BitwiseAnd() - { - Assert.AreEqual((byte) 2 & (byte) 3, NumberUtils.BitwiseAnd((byte) 2, (byte) 3)); - Assert.AreEqual((sbyte) 2 & (sbyte) 3, NumberUtils.BitwiseAnd((sbyte) 2, (sbyte) 3)); - Assert.AreEqual((short) 2 & (short) 3, NumberUtils.BitwiseAnd((short) 2, (short) 3)); - Assert.AreEqual((ushort) 2 & (ushort) 3, NumberUtils.BitwiseAnd((ushort) 2, (ushort) 3)); - Assert.AreEqual((int) 2 & (int) 3, NumberUtils.BitwiseAnd((int) 2, (int) 3)); - Assert.AreEqual((uint) 2 & (uint) 3, NumberUtils.BitwiseAnd((uint) 2, (uint) 3)); - Assert.AreEqual((long) 2 & (long) 3, NumberUtils.BitwiseAnd((long) 2, (long) 3)); - Assert.AreEqual((ulong) 2 & (ulong) 3, NumberUtils.BitwiseAnd((ulong) 2, (ulong) 3)); - Assert.AreEqual((ulong) 2 & (byte) 3, NumberUtils.BitwiseAnd((ulong) 2, (byte) 3)); - Assert.AreEqual(true, NumberUtils.BitwiseAnd(true, true)); - Assert.AreEqual(false, NumberUtils.BitwiseAnd(false, true)); - try - { - NumberUtils.BitwiseAnd((double) 2.0, 3); - Assert.Fail(); - } - catch (ArgumentException) - { - } - } - - [Test] - public void BitwiseOr() - { - Assert.AreEqual((byte) 2 | (byte) 3, NumberUtils.BitwiseOr((byte) 2, (byte) 3)); - Assert.AreEqual((sbyte) 2 | (sbyte) 3, NumberUtils.BitwiseOr((sbyte) 2, (sbyte) 3)); - Assert.AreEqual((short) 2 | (short) 3, NumberUtils.BitwiseOr((short) 2, (short) 3)); - Assert.AreEqual((ushort) 2 | (ushort) 3, NumberUtils.BitwiseOr((ushort) 2, (ushort) 3)); - Assert.AreEqual((int) 2 | (int) 3, NumberUtils.BitwiseOr((int) 2, (int) 3)); - Assert.AreEqual((uint) 2 | (uint) 3, NumberUtils.BitwiseOr((uint) 2, (uint) 3)); - Assert.AreEqual((long) 2 | (long) 3, NumberUtils.BitwiseOr((long) 2, (long) 3)); - Assert.AreEqual((ulong) 2 | (ulong) 3, NumberUtils.BitwiseOr((ulong) 2, (ulong) 3)); - Assert.AreEqual((ulong) 2 | (byte) 3, NumberUtils.BitwiseOr((ulong) 2, (byte) 3)); - Assert.AreEqual(false, NumberUtils.BitwiseOr(false, false)); - Assert.AreEqual(true, NumberUtils.BitwiseOr(false, true)); - try - { - NumberUtils.BitwiseAnd((double) 2.0, 3); - Assert.Fail(); - } - catch (ArgumentException) - { - } - } - - [Test] - public void BitwiseXor() - { - Assert.AreEqual((byte) 2 ^ (byte) 3, NumberUtils.BitwiseXor((byte) 2, (byte) 3)); - Assert.AreEqual((sbyte) 2 ^ (sbyte) 3, NumberUtils.BitwiseXor((sbyte) 2, (sbyte) 3)); - Assert.AreEqual((short) 2 ^ (short) 3, NumberUtils.BitwiseXor((short) 2, (short) 3)); - Assert.AreEqual((ushort) 2 ^ (ushort) 3, NumberUtils.BitwiseXor((ushort) 2, (ushort) 3)); - Assert.AreEqual((int) 2 ^ (int) 3, NumberUtils.BitwiseXor((int) 2, (int) 3)); - Assert.AreEqual((uint) 2 ^ (uint) 3, NumberUtils.BitwiseXor((uint) 2, (uint) 3)); - Assert.AreEqual((long) 2 ^ (long) 3, NumberUtils.BitwiseXor((long) 2, (long) 3)); - Assert.AreEqual((ulong) 2 ^ (ulong) 3, NumberUtils.BitwiseXor((ulong) 2, (ulong) 3)); - Assert.AreEqual((ulong) 2 ^ (byte) 3, NumberUtils.BitwiseXor((ulong) 2, (byte) 3)); - Assert.AreEqual(false, NumberUtils.BitwiseXor(false, false)); - Assert.AreEqual(false, NumberUtils.BitwiseXor(true, true)); - Assert.AreEqual(true, NumberUtils.BitwiseXor(false, true)); - Assert.AreEqual(true, NumberUtils.BitwiseXor(true, false)); - try - { - NumberUtils.BitwiseAnd((double) 2.0, 3); - Assert.Fail(); - } - catch (ArgumentException) - { - } } } -} \ No newline at end of file + + [Test] + public void BitwiseNot() + { + Assert.AreEqual(~(byte) 2, NumberUtils.BitwiseNot((byte) 2)); + Assert.AreEqual(~(sbyte) 2, NumberUtils.BitwiseNot((sbyte) 2)); + Assert.AreEqual(~(short) 2, NumberUtils.BitwiseNot((short) 2)); + Assert.AreEqual(~(ushort) 2, NumberUtils.BitwiseNot((ushort) 2)); + Assert.AreEqual(~(int) 2, NumberUtils.BitwiseNot((int) 2)); + Assert.AreEqual(~(uint) 2, NumberUtils.BitwiseNot((uint) 2)); + Assert.AreEqual(~(long) 2, NumberUtils.BitwiseNot((long) 2)); + Assert.AreEqual(~(ulong) 2, NumberUtils.BitwiseNot((ulong) 2)); + Assert.AreEqual(false, NumberUtils.BitwiseNot(true)); + try + { + NumberUtils.BitwiseNot((double) 2.0); + Assert.Fail(); + } + catch (ArgumentException) + { + } + } + + [Test] + public void BitwiseAnd() + { + Assert.AreEqual((byte) 2 & (byte) 3, NumberUtils.BitwiseAnd((byte) 2, (byte) 3)); + Assert.AreEqual((sbyte) 2 & (sbyte) 3, NumberUtils.BitwiseAnd((sbyte) 2, (sbyte) 3)); + Assert.AreEqual((short) 2 & (short) 3, NumberUtils.BitwiseAnd((short) 2, (short) 3)); + Assert.AreEqual((ushort) 2 & (ushort) 3, NumberUtils.BitwiseAnd((ushort) 2, (ushort) 3)); + Assert.AreEqual((int) 2 & (int) 3, NumberUtils.BitwiseAnd((int) 2, (int) 3)); + Assert.AreEqual((uint) 2 & (uint) 3, NumberUtils.BitwiseAnd((uint) 2, (uint) 3)); + Assert.AreEqual((long) 2 & (long) 3, NumberUtils.BitwiseAnd((long) 2, (long) 3)); + Assert.AreEqual((ulong) 2 & (ulong) 3, NumberUtils.BitwiseAnd((ulong) 2, (ulong) 3)); + Assert.AreEqual((ulong) 2 & (byte) 3, NumberUtils.BitwiseAnd((ulong) 2, (byte) 3)); + Assert.AreEqual(true, NumberUtils.BitwiseAnd(true, true)); + Assert.AreEqual(false, NumberUtils.BitwiseAnd(false, true)); + try + { + NumberUtils.BitwiseAnd((double) 2.0, 3); + Assert.Fail(); + } + catch (ArgumentException) + { + } + } + + [Test] + public void BitwiseOr() + { + Assert.AreEqual((byte) 2 | (byte) 3, NumberUtils.BitwiseOr((byte) 2, (byte) 3)); + Assert.AreEqual((sbyte) 2 | (sbyte) 3, NumberUtils.BitwiseOr((sbyte) 2, (sbyte) 3)); + Assert.AreEqual((short) 2 | (short) 3, NumberUtils.BitwiseOr((short) 2, (short) 3)); + Assert.AreEqual((ushort) 2 | (ushort) 3, NumberUtils.BitwiseOr((ushort) 2, (ushort) 3)); + Assert.AreEqual((int) 2 | (int) 3, NumberUtils.BitwiseOr((int) 2, (int) 3)); + Assert.AreEqual((uint) 2 | (uint) 3, NumberUtils.BitwiseOr((uint) 2, (uint) 3)); + Assert.AreEqual((long) 2 | (long) 3, NumberUtils.BitwiseOr((long) 2, (long) 3)); + Assert.AreEqual((ulong) 2 | (ulong) 3, NumberUtils.BitwiseOr((ulong) 2, (ulong) 3)); + Assert.AreEqual((ulong) 2 | (byte) 3, NumberUtils.BitwiseOr((ulong) 2, (byte) 3)); + Assert.AreEqual(false, NumberUtils.BitwiseOr(false, false)); + Assert.AreEqual(true, NumberUtils.BitwiseOr(false, true)); + try + { + NumberUtils.BitwiseAnd((double) 2.0, 3); + Assert.Fail(); + } + catch (ArgumentException) + { + } + } + + [Test] + public void BitwiseXor() + { + Assert.AreEqual((byte) 2 ^ (byte) 3, NumberUtils.BitwiseXor((byte) 2, (byte) 3)); + Assert.AreEqual((sbyte) 2 ^ (sbyte) 3, NumberUtils.BitwiseXor((sbyte) 2, (sbyte) 3)); + Assert.AreEqual((short) 2 ^ (short) 3, NumberUtils.BitwiseXor((short) 2, (short) 3)); + Assert.AreEqual((ushort) 2 ^ (ushort) 3, NumberUtils.BitwiseXor((ushort) 2, (ushort) 3)); + Assert.AreEqual((int) 2 ^ (int) 3, NumberUtils.BitwiseXor((int) 2, (int) 3)); + Assert.AreEqual((uint) 2 ^ (uint) 3, NumberUtils.BitwiseXor((uint) 2, (uint) 3)); + Assert.AreEqual((long) 2 ^ (long) 3, NumberUtils.BitwiseXor((long) 2, (long) 3)); + Assert.AreEqual((ulong) 2 ^ (ulong) 3, NumberUtils.BitwiseXor((ulong) 2, (ulong) 3)); + Assert.AreEqual((ulong) 2 ^ (byte) 3, NumberUtils.BitwiseXor((ulong) 2, (byte) 3)); + Assert.AreEqual(false, NumberUtils.BitwiseXor(false, false)); + Assert.AreEqual(false, NumberUtils.BitwiseXor(true, true)); + Assert.AreEqual(true, NumberUtils.BitwiseXor(false, true)); + Assert.AreEqual(true, NumberUtils.BitwiseXor(true, false)); + try + { + NumberUtils.BitwiseAnd((double) 2.0, 3); + Assert.Fail(); + } + catch (ArgumentException) + { + } + } +} diff --git a/test/Spring/Spring.Core.Tests/Util/ObjectUtilsTests.cs b/test/Spring/Spring.Core.Tests/Util/ObjectUtilsTests.cs index a1d1f9f7..434adb6c 100644 --- a/test/Spring/Spring.Core.Tests/Util/ObjectUtilsTests.cs +++ b/test/Spring/Spring.Core.Tests/Util/ObjectUtilsTests.cs @@ -29,350 +29,354 @@ using Spring.Objects; #endregion -namespace Spring.Util +namespace Spring.Util; + +/// +/// Unit tests for the ObjectUtils class. +/// +/// Rick Evans (.NET) +[TestFixture] +public class ObjectUtilsTests { - /// - /// Unit tests for the ObjectUtils class. - /// - /// Rick Evans (.NET) - [TestFixture] - public class ObjectUtilsTests + [Test] + public void NullSafeEqualsWithBothNull() { - [Test] - public void NullSafeEqualsWithBothNull() - { - string first = null; - string second = null; - Assert.IsTrue(ObjectUtils.NullSafeEquals(first, second)); - } - - [Test] - public void NullSafeEqualsWithFirstNull() - { - string first = null; - string second = ""; - Assert.IsFalse(ObjectUtils.NullSafeEquals(first, second)); - } - - [Test] - public void NullSafeEqualsWithSecondNull() - { - string first = ""; - string second = null; - Assert.IsFalse(ObjectUtils.NullSafeEquals(first, second)); - } - - [Test] - public void NullSafeEqualsBothEquals() - { - string first = "this is it"; - string second = "this is it"; - Assert.IsTrue(ObjectUtils.NullSafeEquals(first, second)); - } - - [Test] - public void NullSafeEqualsNotEqual() - { - string first = "this is it"; - int second = 12; - Assert.IsFalse(ObjectUtils.NullSafeEquals(first, second)); - } - - [Test] - public void IsAssignableAndNotTransparentProxyWithProxy() - { - AppDomain domain = null; - try - { - AppDomainSetup setup = new AppDomainSetup(); - setup.ApplicationBase = Environment.CurrentDirectory; - domain = AppDomain.CreateDomain("Spring", new Evidence(AppDomain.CurrentDomain.Evidence), setup); - object foo = domain.CreateInstanceAndUnwrap(GetType().Assembly.FullName, typeof(Foo).FullName); - // the instance is definitely assignable to the supplied interface type... - bool isAssignable = ObjectUtils.IsAssignableAndNotTransparentProxy(typeof (IFoo), foo); - Assert.IsFalse(isAssignable, "Proxied instance was not recognized as such."); - } - finally - { - AppDomain.Unload(domain); - } - } - - [Test] - public void InstantiateTypeWithNullType() - { - Assert.Throws(() => ObjectUtils.InstantiateType(null)); - } - - [Test] - public void InstantiateType() - { - object foo = ObjectUtils.InstantiateType(typeof (TestObject)); - Assert.IsNotNull(foo, "Failed to instantiate an instance of a valid Type."); - Assert.IsTrue(foo is TestObject, "The instantiated instance was not an instance of the type that was passed in."); - } - - [Test] - public void InstantiateTypeThrowingWithinPublicConstructor() - { - try - { - ObjectUtils.InstantiateType(typeof(ThrowingWithinConstructor)); - Assert.Fail(); - } - catch(FatalReflectionException ex) - { - // no nasty "TargetInvocationException" is in between! - Assert.AreEqual( typeof(ThrowingWithinConstructorException), ex.InnerException.GetType() ); - } - } - - [Test] - public void InstantiateTypeWithOpenGenericType() - { - Assert.Throws(() => ObjectUtils.InstantiateType(typeof(Dictionary<,>))); - } - - [Test] - public void InstantiateGenericTypeWithArguments() - { -// ObjectUtils.InstantiateType(typeof(Dictionary), new object[] { new object() } ); - } - - [Test] - public void InstantiateTypeWithAbstractType() - { - Assert.Throws(() => ObjectUtils.InstantiateType(typeof (AbstractType))); - } - - [Test] - public void InstantiateTypeWithInterfaceType() - { - Assert.Throws(() => ObjectUtils.InstantiateType(typeof (IList))); - } - - [Test] - public void InstantiateTypeWithTypeExposingNoZeroArgCtor() - { - Assert.Throws(() => ObjectUtils.InstantiateType(typeof(NoZeroArgConstructorType))); - } - - [Test] - public void InstantiateTypeWithPrivateCtor() - { - ConstructorInfo ctor = typeof (OnlyPrivateCtor).GetConstructor( - BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[] {typeof (string)}, - null); - object foo = ObjectUtils.InstantiateType(ctor, new object[] {"Chungking Express"}); - Assert.IsNotNull(foo, "Failed to instantiate an instance of a valid Type."); - Assert.IsTrue(foo is OnlyPrivateCtor, "The instantiated instance was not an instance of the type that was passed in."); - Assert.AreEqual("Chungking Express", ((OnlyPrivateCtor) foo).Name); - } - - [Test] - public void InstantiateTypeWithNullCtor() - { - Assert.Throws(() => ObjectUtils.InstantiateType(typeof(IList).GetConstructor(Type.EmptyTypes), new object[] { })); - } - - [Test] - public void InstantiateTypeWithCtorWithNoArgs() - { - Type type = typeof (TestObject); - ConstructorInfo ctor = type.GetConstructor(Type.EmptyTypes); - object foo = ObjectUtils.InstantiateType(ctor, ObjectUtils.EmptyObjects); - Assert.IsNotNull(foo, "Failed to instantiate an instance of a valid Type."); - Assert.IsTrue(foo is TestObject, "The instantiated instance was not an instance of the Type that was passed in."); - } - - [Test] - public void InstantiateTypeWithCtorArgs() - { - Type type = typeof (TestObject); - ConstructorInfo ctor = type.GetConstructor(new Type[] {typeof (string), typeof (int)}); - object foo = ObjectUtils.InstantiateType(ctor, new object[] {"Yakov Petrovich Golyadkin", 39}); - Assert.IsNotNull(foo, "Failed to instantiate an instance of a valid Type."); - Assert.IsTrue(foo is TestObject, "The instantiated instance was not an instance of the Type that was passed in."); - TestObject obj = foo as TestObject; - Assert.AreEqual("Yakov Petrovich Golyadkin", obj.Name); - Assert.AreEqual(39, obj.Age); - } - - [Test] - public void InstantiateTypeWithBadCtorArgs() - { - Type type = typeof (TestObject); - ConstructorInfo ctor = type.GetConstructor(new Type[] {typeof(string), typeof(int)}); - try - { - ObjectUtils.InstantiateType(ctor, new object[] { 39, "Yakov Petrovich Golyadkin" }); - Assert.Fail("Should throw an error"); - } - catch - { - // ok... - } - } - - [Test] - public void IsSimpleProperty() - { - Assert.IsTrue(ObjectUtils.IsSimpleProperty(typeof (string))); - Assert.IsTrue(ObjectUtils.IsSimpleProperty(typeof (long))); - Assert.IsTrue(ObjectUtils.IsSimpleProperty(typeof (bool))); - Assert.IsTrue(ObjectUtils.IsSimpleProperty(typeof (int))); - Assert.IsTrue(ObjectUtils.IsSimpleProperty(typeof (float))); - Assert.IsTrue(ObjectUtils.IsSimpleProperty(typeof (ushort))); - Assert.IsTrue(ObjectUtils.IsSimpleProperty(typeof (double))); - Assert.IsTrue(ObjectUtils.IsSimpleProperty(typeof (ulong))); - Assert.IsTrue(ObjectUtils.IsSimpleProperty(typeof (char))); - Assert.IsTrue(ObjectUtils.IsSimpleProperty(typeof (uint))); - Assert.IsTrue(ObjectUtils.IsSimpleProperty(typeof (string[]))); - Assert.IsTrue(ObjectUtils.IsSimpleProperty(typeof (Type))); - - Assert.IsFalse(ObjectUtils.IsSimpleProperty(typeof (TestObject))); - Assert.IsFalse(ObjectUtils.IsSimpleProperty(typeof (IList[]))); - } - - [Test] - public void EnumerateFirstElement() - { - string expected = "Hiya"; - IList list = new string[] {expected, "Aw!", "Man!"}; - IEnumerator enumerator = list.GetEnumerator(); - object actual = ObjectUtils.EnumerateFirstElement(enumerator); - Assert.AreEqual(expected, actual); - } - - [Test] - public void EnumerateElementAtIndex() - { - string expected = "Mmm..."; - IList list = new string[] {"Aw!", "Man!", expected}; - IEnumerator enumerator = list.GetEnumerator(); - object actual = ObjectUtils.EnumerateElementAtIndex(enumerator, 2); - Assert.AreEqual(expected, actual); - } - - [Test] - public void EnumerateElementAtIndexViaIEnumerable() - { - string expected = "Mmm..."; - IList list = new string[] {"Aw!", "Man!", expected}; - object actual = ObjectUtils.EnumerateElementAtIndex(list, 2); - Assert.AreEqual(expected, actual); - } - - [Test] - public void EnumerateElementAtOutOfRangeIndex() - { - string expected = "Mmm..."; - IList list = new string[] {"Aw!", "Man!", expected}; - IEnumerator enumerator = list.GetEnumerator(); - Assert.Throws(() => ObjectUtils.EnumerateElementAtIndex(enumerator, 12)); - } - - [Test] - public void EnumerateElementAtOutOfRangeIndexViaIEnumerable() - { - string expected = "Mmm..."; - IList list = new string[] {"Aw!", "Man!", expected}; - Assert.Throws(() => ObjectUtils.EnumerateElementAtIndex(list, 12)); - } - - [Test] - public void EnumerateElementAtNegativeIndex() - { - string expected = "Mmm..."; - IList list = new string[] {"Aw!", "Man!", expected}; - IEnumerator enumerator = list.GetEnumerator(); - Assert.Throws(() => ObjectUtils.EnumerateElementAtIndex(enumerator, -10)); - } - - [Test] - public void EnumerateElementAtNegativeIndexViaIEnumerable() - { - string expected = "Mmm..."; - IList list = new string[] {"Aw!", "Man!", expected}; - Assert.Throws(() => ObjectUtils.EnumerateElementAtIndex(list, -10)); - } - - #region Helper Classes - - private interface IFoo - { - } - - private sealed class Foo : MarshalByRefObject, IFoo - { - } - - /// - /// A class that doesn't have a parameterless constructor. - /// - private class NoZeroArgConstructorType - { - /// - /// Creates a new instance of the NoZeroArgConstructorType class. - /// - /// A spurious argument (ignored). - public NoZeroArgConstructorType(string foo) - { - } - } - - /// - /// An abstract class. Doh! - /// - private abstract class AbstractType - { - /// - /// Creates a new instance of the AbstractType class. - /// - public AbstractType() - { - } - } - - private class OnlyPrivateCtor - { - private OnlyPrivateCtor(string name) - { - _name = name; - } - - public string Name - { - get { return _name; } - set { _name = value; } - } - - private string _name; - } - - [Serializable] - private class ThrowingWithinConstructorException : TestException - { - public ThrowingWithinConstructorException() - {} - - public ThrowingWithinConstructorException(string message) : base(message) - {} - - public ThrowingWithinConstructorException(string message, Exception inner) : base(message, inner) - {} - - protected ThrowingWithinConstructorException(SerializationInfo info, StreamingContext context) : base(info, context) - {} - } - - public class ThrowingWithinConstructor - { - public ThrowingWithinConstructor() - { - throw new ThrowingWithinConstructorException(); - } - } - #endregion + string first = null; + string second = null; + Assert.IsTrue(ObjectUtils.NullSafeEquals(first, second)); } -} \ No newline at end of file + + [Test] + public void NullSafeEqualsWithFirstNull() + { + string first = null; + string second = ""; + Assert.IsFalse(ObjectUtils.NullSafeEquals(first, second)); + } + + [Test] + public void NullSafeEqualsWithSecondNull() + { + string first = ""; + string second = null; + Assert.IsFalse(ObjectUtils.NullSafeEquals(first, second)); + } + + [Test] + public void NullSafeEqualsBothEquals() + { + string first = "this is it"; + string second = "this is it"; + Assert.IsTrue(ObjectUtils.NullSafeEquals(first, second)); + } + + [Test] + public void NullSafeEqualsNotEqual() + { + string first = "this is it"; + int second = 12; + Assert.IsFalse(ObjectUtils.NullSafeEquals(first, second)); + } + + [Test] + public void IsAssignableAndNotTransparentProxyWithProxy() + { + AppDomain domain = null; + try + { + AppDomainSetup setup = new AppDomainSetup(); + setup.ApplicationBase = Environment.CurrentDirectory; + domain = AppDomain.CreateDomain("Spring", new Evidence(AppDomain.CurrentDomain.Evidence), setup); + object foo = domain.CreateInstanceAndUnwrap(GetType().Assembly.FullName, typeof(Foo).FullName); + // the instance is definitely assignable to the supplied interface type... + bool isAssignable = ObjectUtils.IsAssignableAndNotTransparentProxy(typeof(IFoo), foo); + Assert.IsFalse(isAssignable, "Proxied instance was not recognized as such."); + } + finally + { + AppDomain.Unload(domain); + } + } + + [Test] + public void InstantiateTypeWithNullType() + { + Assert.Throws(() => ObjectUtils.InstantiateType(null)); + } + + [Test] + public void InstantiateType() + { + object foo = ObjectUtils.InstantiateType(typeof(TestObject)); + Assert.IsNotNull(foo, "Failed to instantiate an instance of a valid Type."); + Assert.IsTrue(foo is TestObject, "The instantiated instance was not an instance of the type that was passed in."); + } + + [Test] + public void InstantiateTypeThrowingWithinPublicConstructor() + { + try + { + ObjectUtils.InstantiateType(typeof(ThrowingWithinConstructor)); + Assert.Fail(); + } + catch (FatalReflectionException ex) + { + // no nasty "TargetInvocationException" is in between! + Assert.AreEqual(typeof(ThrowingWithinConstructorException), ex.InnerException.GetType()); + } + } + + [Test] + public void InstantiateTypeWithOpenGenericType() + { + Assert.Throws(() => ObjectUtils.InstantiateType(typeof(Dictionary<,>))); + } + + [Test] + public void InstantiateGenericTypeWithArguments() + { +// ObjectUtils.InstantiateType(typeof(Dictionary), new object[] { new object() } ); + } + + [Test] + public void InstantiateTypeWithAbstractType() + { + Assert.Throws(() => ObjectUtils.InstantiateType(typeof(AbstractType))); + } + + [Test] + public void InstantiateTypeWithInterfaceType() + { + Assert.Throws(() => ObjectUtils.InstantiateType(typeof(IList))); + } + + [Test] + public void InstantiateTypeWithTypeExposingNoZeroArgCtor() + { + Assert.Throws(() => ObjectUtils.InstantiateType(typeof(NoZeroArgConstructorType))); + } + + [Test] + public void InstantiateTypeWithPrivateCtor() + { + ConstructorInfo ctor = typeof(OnlyPrivateCtor).GetConstructor( + BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[] { typeof(string) }, + null); + object foo = ObjectUtils.InstantiateType(ctor, new object[] { "Chungking Express" }); + Assert.IsNotNull(foo, "Failed to instantiate an instance of a valid Type."); + Assert.IsTrue(foo is OnlyPrivateCtor, "The instantiated instance was not an instance of the type that was passed in."); + Assert.AreEqual("Chungking Express", ((OnlyPrivateCtor) foo).Name); + } + + [Test] + public void InstantiateTypeWithNullCtor() + { + Assert.Throws(() => ObjectUtils.InstantiateType(typeof(IList).GetConstructor(Type.EmptyTypes), new object[] { })); + } + + [Test] + public void InstantiateTypeWithCtorWithNoArgs() + { + Type type = typeof(TestObject); + ConstructorInfo ctor = type.GetConstructor(Type.EmptyTypes); + object foo = ObjectUtils.InstantiateType(ctor, ObjectUtils.EmptyObjects); + Assert.IsNotNull(foo, "Failed to instantiate an instance of a valid Type."); + Assert.IsTrue(foo is TestObject, "The instantiated instance was not an instance of the Type that was passed in."); + } + + [Test] + public void InstantiateTypeWithCtorArgs() + { + Type type = typeof(TestObject); + ConstructorInfo ctor = type.GetConstructor(new Type[] { typeof(string), typeof(int) }); + object foo = ObjectUtils.InstantiateType(ctor, new object[] { "Yakov Petrovich Golyadkin", 39 }); + Assert.IsNotNull(foo, "Failed to instantiate an instance of a valid Type."); + Assert.IsTrue(foo is TestObject, "The instantiated instance was not an instance of the Type that was passed in."); + TestObject obj = foo as TestObject; + Assert.AreEqual("Yakov Petrovich Golyadkin", obj.Name); + Assert.AreEqual(39, obj.Age); + } + + [Test] + public void InstantiateTypeWithBadCtorArgs() + { + Type type = typeof(TestObject); + ConstructorInfo ctor = type.GetConstructor(new Type[] { typeof(string), typeof(int) }); + try + { + ObjectUtils.InstantiateType(ctor, new object[] { 39, "Yakov Petrovich Golyadkin" }); + Assert.Fail("Should throw an error"); + } + catch + { + // ok... + } + } + + [Test] + public void IsSimpleProperty() + { + Assert.IsTrue(ObjectUtils.IsSimpleProperty(typeof(string))); + Assert.IsTrue(ObjectUtils.IsSimpleProperty(typeof(long))); + Assert.IsTrue(ObjectUtils.IsSimpleProperty(typeof(bool))); + Assert.IsTrue(ObjectUtils.IsSimpleProperty(typeof(int))); + Assert.IsTrue(ObjectUtils.IsSimpleProperty(typeof(float))); + Assert.IsTrue(ObjectUtils.IsSimpleProperty(typeof(ushort))); + Assert.IsTrue(ObjectUtils.IsSimpleProperty(typeof(double))); + Assert.IsTrue(ObjectUtils.IsSimpleProperty(typeof(ulong))); + Assert.IsTrue(ObjectUtils.IsSimpleProperty(typeof(char))); + Assert.IsTrue(ObjectUtils.IsSimpleProperty(typeof(uint))); + Assert.IsTrue(ObjectUtils.IsSimpleProperty(typeof(string[]))); + Assert.IsTrue(ObjectUtils.IsSimpleProperty(typeof(Type))); + + Assert.IsFalse(ObjectUtils.IsSimpleProperty(typeof(TestObject))); + Assert.IsFalse(ObjectUtils.IsSimpleProperty(typeof(IList[]))); + } + + [Test] + public void EnumerateFirstElement() + { + string expected = "Hiya"; + IList list = new string[] { expected, "Aw!", "Man!" }; + IEnumerator enumerator = list.GetEnumerator(); + object actual = ObjectUtils.EnumerateFirstElement(enumerator); + Assert.AreEqual(expected, actual); + } + + [Test] + public void EnumerateElementAtIndex() + { + string expected = "Mmm..."; + IList list = new string[] { "Aw!", "Man!", expected }; + IEnumerator enumerator = list.GetEnumerator(); + object actual = ObjectUtils.EnumerateElementAtIndex(enumerator, 2); + Assert.AreEqual(expected, actual); + } + + [Test] + public void EnumerateElementAtIndexViaIEnumerable() + { + string expected = "Mmm..."; + IList list = new string[] { "Aw!", "Man!", expected }; + object actual = ObjectUtils.EnumerateElementAtIndex(list, 2); + Assert.AreEqual(expected, actual); + } + + [Test] + public void EnumerateElementAtOutOfRangeIndex() + { + string expected = "Mmm..."; + IList list = new string[] { "Aw!", "Man!", expected }; + IEnumerator enumerator = list.GetEnumerator(); + Assert.Throws(() => ObjectUtils.EnumerateElementAtIndex(enumerator, 12)); + } + + [Test] + public void EnumerateElementAtOutOfRangeIndexViaIEnumerable() + { + string expected = "Mmm..."; + IList list = new string[] { "Aw!", "Man!", expected }; + Assert.Throws(() => ObjectUtils.EnumerateElementAtIndex(list, 12)); + } + + [Test] + public void EnumerateElementAtNegativeIndex() + { + string expected = "Mmm..."; + IList list = new string[] { "Aw!", "Man!", expected }; + IEnumerator enumerator = list.GetEnumerator(); + Assert.Throws(() => ObjectUtils.EnumerateElementAtIndex(enumerator, -10)); + } + + [Test] + public void EnumerateElementAtNegativeIndexViaIEnumerable() + { + string expected = "Mmm..."; + IList list = new string[] { "Aw!", "Man!", expected }; + Assert.Throws(() => ObjectUtils.EnumerateElementAtIndex(list, -10)); + } + + #region Helper Classes + + private interface IFoo + { + } + + private sealed class Foo : MarshalByRefObject, IFoo + { + } + + /// + /// A class that doesn't have a parameterless constructor. + /// + private class NoZeroArgConstructorType + { + /// + /// Creates a new instance of the NoZeroArgConstructorType class. + /// + /// A spurious argument (ignored). + public NoZeroArgConstructorType(string foo) + { + } + } + + /// + /// An abstract class. Doh! + /// + private abstract class AbstractType + { + /// + /// Creates a new instance of the AbstractType class. + /// + public AbstractType() + { + } + } + + private class OnlyPrivateCtor + { + private OnlyPrivateCtor(string name) + { + _name = name; + } + + public string Name + { + get { return _name; } + set { _name = value; } + } + + private string _name; + } + + [Serializable] + private class ThrowingWithinConstructorException : TestException + { + public ThrowingWithinConstructorException() + { + } + + public ThrowingWithinConstructorException(string message) : base(message) + { + } + + public ThrowingWithinConstructorException(string message, Exception inner) : base(message, inner) + { + } + + protected ThrowingWithinConstructorException(SerializationInfo info, StreamingContext context) : base(info, context) + { + } + } + + public class ThrowingWithinConstructor + { + public ThrowingWithinConstructor() + { + throw new ThrowingWithinConstructorException(); + } + } + + #endregion +} diff --git a/test/Spring/Spring.Core.Tests/Util/PathMatcherTest.cs b/test/Spring/Spring.Core.Tests/Util/PathMatcherTest.cs index 58d04abc..c46f67a4 100644 --- a/test/Spring/Spring.Core.Tests/Util/PathMatcherTest.cs +++ b/test/Spring/Spring.Core.Tests/Util/PathMatcherTest.cs @@ -1,108 +1,111 @@ #region License + /* -* Copyright 2002-2010 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. -*/ + * Copyright 2002-2010 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 NUnit.Framework; -namespace Spring.Util +namespace Spring.Util; + +[TestFixture] +public class PathMatcherTest { - [TestFixture] - public class PathMatcherTest - { - private static readonly string dir = Path.Combine("Data", "PathMatcher"); + private static readonly string dir = Path.Combine("Data", "PathMatcher"); - [Test] - public void TestFilesInDataPathMatcher () + [Test] + public void TestFilesInDataPathMatcher() + { + DirectoryInfo info = new DirectoryInfo(dir); + foreach (FileInfo file in info.GetFiles("*.test")) { - DirectoryInfo info = new DirectoryInfo(dir); - foreach (FileInfo file in info.GetFiles("*.test")) - { - ProcessFile (file); - } - + ProcessFile(file); } + } - [Test, Explicit] - public void ThisIsATestForDebuggingPurposes () - { - ProcessFile(new FileInfo(dir + "/Examples.test")); - } + [Test, Explicit] + public void ThisIsATestForDebuggingPurposes() + { + ProcessFile(new FileInfo(dir + "/Examples.test")); + } - private static void ProcessFile (FileInfo file) + private static void ProcessFile(FileInfo file) + { + bool trueness = true; + using (StreamReader r = file.OpenText()) { - bool trueness = true; - using (StreamReader r = file.OpenText()) - { - string pattern = null; - string line; - int nline = 0; + string pattern = null; + string line; + int nline = 0; - bool expectingPattern = false; - while ((line = r.ReadLine()) != null) + bool expectingPattern = false; + while ((line = r.ReadLine()) != null) + { + nline++; + switch (line) { - nline++; - switch (line) - { - case "": - if (expectingPattern) - { - pattern = line; - expectingPattern = false; - continue; - } - break; - case "--match--": - case "# ": - trueness = true; - break; - case "--dont-match--": - case "# ": - trueness = false; - break; - case "--pattern--": - case "# ": - expectingPattern = true; - nline++; - break; - default: - if (line.StartsWith("#")) - { - continue; - } - if (expectingPattern) - { - pattern = line; - expectingPattern = false; - continue; - } - AssertMatches(file, nline, trueness, line, pattern); - AssertMatches(file, nline, trueness, line.Replace("/", "\\"), pattern); - break; - } + case "": + if (expectingPattern) + { + pattern = line; + expectingPattern = false; + continue; + } + + break; + case "--match--": + case "# ": + trueness = true; + break; + case "--dont-match--": + case "# ": + trueness = false; + break; + case "--pattern--": + case "# ": + expectingPattern = true; + nline++; + break; + default: + if (line.StartsWith("#")) + { + continue; + } + + if (expectingPattern) + { + pattern = line; + expectingPattern = false; + continue; + } + + AssertMatches(file, nline, trueness, line, pattern); + AssertMatches(file, nline, trueness, line.Replace("/", "\\"), pattern); + break; } } } + } - private static void AssertMatches (FileInfo file, int nline, bool trueness, string path, string pattern) - { - Assert.AreEqual(trueness, - PathMatcher.Match(pattern, path), - String.Format("\ntest file '{0}', line {1}:\npath '{2}' does {3} match '{4}' (translated to {5})", - file.Name, nline, path, trueness ? "not" : "", pattern, PathMatcher.BuildRegex(pattern))) ; - } - } + private static void AssertMatches(FileInfo file, int nline, bool trueness, string path, string pattern) + { + Assert.AreEqual(trueness, + PathMatcher.Match(pattern, path), + String.Format("\ntest file '{0}', line {1}:\npath '{2}' does {3} match '{4}' (translated to {5})", + file.Name, nline, path, trueness ? "not" : "", pattern, PathMatcher.BuildRegex(pattern))); + } } diff --git a/test/Spring/Spring.Core.Tests/Util/PatternMatchUtilsTests.cs b/test/Spring/Spring.Core.Tests/Util/PatternMatchUtilsTests.cs index 54214bae..57352017 100644 --- a/test/Spring/Spring.Core.Tests/Util/PatternMatchUtilsTests.cs +++ b/test/Spring/Spring.Core.Tests/Util/PatternMatchUtilsTests.cs @@ -24,13 +24,12 @@ using NUnit.Framework; #endregion -namespace Spring.Util +namespace Spring.Util; + +/// +/// Unit tests for the PatternMatchUtils class. +/// +[TestFixture] +public sealed class PatternMatchUtilsTests { - /// - /// Unit tests for the PatternMatchUtils class. - /// - [TestFixture] - public sealed class PatternMatchUtilsTests - { - } -} \ No newline at end of file +} diff --git a/test/Spring/Spring.Core.Tests/Util/PropertiesTests.cs b/test/Spring/Spring.Core.Tests/Util/PropertiesTests.cs index 452bb760..47146b51 100644 --- a/test/Spring/Spring.Core.Tests/Util/PropertiesTests.cs +++ b/test/Spring/Spring.Core.Tests/Util/PropertiesTests.cs @@ -2,13 +2,13 @@ /* * Copyright 2002-2010 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. @@ -21,182 +21,180 @@ #region Imports using System.Text; - using NUnit.Framework; #endregion -namespace Spring.Util +namespace Spring.Util; + +/// +/// Unit tests for Spring.Util.Properties. +/// +[TestFixture] +public class PropertiesTests { - /// - /// Unit tests for Spring.Util.Properties. - /// - [TestFixture] - public class PropertiesTests - { - [Test] - public void Instantiation () - { - Properties root = new Properties(); - root.Add ("foo", "this"); - root.Add ("bar", "is"); - Properties props = new Properties(root); - props.SetProperty("myPropertyKey", "myPropertyValue"); - Assert.AreEqual (3, props.Count); - Assert.AreEqual ("this", props.GetProperty ("foo")); - Assert.AreEqual ("is", props.GetProperty ("bar")); - Assert.AreEqual ("myPropertyValue", props.GetProperty ("myPropertyKey")); - } + [Test] + public void Instantiation() + { + Properties root = new Properties(); + root.Add("foo", "this"); + root.Add("bar", "is"); + Properties props = new Properties(root); + props.SetProperty("myPropertyKey", "myPropertyValue"); + Assert.AreEqual(3, props.Count); + Assert.AreEqual("this", props.GetProperty("foo")); + Assert.AreEqual("is", props.GetProperty("bar")); + Assert.AreEqual("myPropertyValue", props.GetProperty("myPropertyKey")); + } - [Test] - public void GetPropertyWithDefault () - { - Properties props = new Properties(); - props.Add ("foo", "this"); - props.Add ("bar", "is"); - Assert.AreEqual ("this", props.GetProperty ("foo")); - Assert.AreEqual ("is", props.GetProperty ("bar")); - Assert.AreEqual ("it", props.GetProperty ("baz", "it")); - } + [Test] + public void GetPropertyWithDefault() + { + Properties props = new Properties(); + props.Add("foo", "this"); + props.Add("bar", "is"); + Assert.AreEqual("this", props.GetProperty("foo")); + Assert.AreEqual("is", props.GetProperty("bar")); + Assert.AreEqual("it", props.GetProperty("baz", "it")); + } - [Test] - public void Remove () - { - Properties props = new Properties(); - props.Add ("foo", "this"); - props.Add ("bar", "is"); - Assert.AreEqual (2, props.Count); - props.Remove ("foo"); - Assert.AreEqual (1, props.Count); - Assert.IsFalse (props.ContainsKey ("foo")); - } + [Test] + public void Remove() + { + Properties props = new Properties(); + props.Add("foo", "this"); + props.Add("bar", "is"); + Assert.AreEqual(2, props.Count); + props.Remove("foo"); + Assert.AreEqual(1, props.Count); + Assert.IsFalse(props.ContainsKey("foo")); + } - [Test] - public void Store () + [Test] + public void Store() + { + Properties props = new Properties(); + props.Add("foo", "this"); + props.Add("bar", "is"); + props.Add("baz", "it"); + FileInfo file = new FileInfo("properties.test"); + try { - Properties props = new Properties(); - props.Add ("foo", "this"); - props.Add ("bar", "is"); - props.Add ("baz", "it"); - FileInfo file = new FileInfo ("properties.test"); - try + // write 'em out with the specified header... + using (Stream cout = file.OpenWrite()) { - // write 'em out with the specified header... - using (Stream cout = file.OpenWrite ()) - { - props.Store (cout, "My Properties"); - } - } - finally - { - try - { - file.Delete (); - } - catch (IOException) - { - } + props.Store(cout, "My Properties"); } } - - [Test] - public void ListAndLoad() + finally { - Properties props = new Properties(); - props.Add ("foo", "this"); - props.Add ("bar", "is"); - props.Add ("baz", "it"); - FileInfo file = new FileInfo ("properties.test"); - try + try { - // write 'em out... - using (Stream cout = file.OpenWrite ()) - { - props.List (cout); - } - // read 'em back in... - using (Stream cin = file.OpenRead ()) - { - props = new Properties (); - props.Load (cin); - Assert.AreEqual (3, props.Count); - Assert.AreEqual ("this", props.GetProperty ("foo")); - Assert.AreEqual ("is", props.GetProperty ("bar")); - Assert.AreEqual ("it", props.GetProperty ("baz", "it")); - } + file.Delete(); } - finally + catch (IOException) { - try - { - file.Delete (); - } - catch (IOException) - { - } } } + } - [Test] - public void SimpleProperties() - { - string input = "key1=value1\r\nkey2:value2\r\n\r\n# a comment line\r\n leadingspace : true"; - Stream s = new MemoryStream(Encoding.ASCII.GetBytes(input)); - Properties props = new Properties(); - props.Load(s); - - Assert.IsTrue("value1".Equals(props["key1"])); - Assert.IsTrue("value2".Equals(props["key2"])); - Assert.IsTrue("true".Equals(props["leadingspace"])); - } - - [Test] - public void WhitespaceProperties() + [Test] + public void ListAndLoad() + { + Properties props = new Properties(); + props.Add("foo", "this"); + props.Add("bar", "is"); + props.Add("baz", "it"); + FileInfo file = new FileInfo("properties.test"); + try { - string input = "key1 =\t\nkey2:\nkey3"; + // write 'em out... + using (Stream cout = file.OpenWrite()) + { + props.List(cout); + } - Stream s = new MemoryStream(Encoding.ASCII.GetBytes(input)); - Properties props = new Properties(); - props.Load(s); - - Assert.AreEqual(string.Empty, props["key1"], "key1 should have empty value"); - Assert.AreEqual(string.Empty, props["key2"], "key2 should have empty value"); - Assert.IsTrue(props.ContainsKey("key3")); - Assert.IsNull(props["key3"]); + // read 'em back in... + using (Stream cin = file.OpenRead()) + { + props = new Properties(); + props.Load(cin); + Assert.AreEqual(3, props.Count); + Assert.AreEqual("this", props.GetProperty("foo")); + Assert.AreEqual("is", props.GetProperty("bar")); + Assert.AreEqual("it", props.GetProperty("baz", "it")); + } } + finally + { + try + { + file.Delete(); + } + catch (IOException) + { + } + } + } - [Test] - public void Continuation() - { - string input = "continued = this is a long value element \\\r\nthat uses continuation \\\r\n xxx"; - Stream s = new MemoryStream(Encoding.ASCII.GetBytes(input)); - Properties props = new Properties(); - props.Load(s); + [Test] + public void SimpleProperties() + { + string input = "key1=value1\r\nkey2:value2\r\n\r\n# a comment line\r\n leadingspace : true"; + Stream s = new MemoryStream(Encoding.ASCII.GetBytes(input)); + Properties props = new Properties(); + props.Load(s); - Assert.IsTrue("this is a long value element that uses continuation xxx".Equals(props["continued"])); - } + Assert.IsTrue("value1".Equals(props["key1"])); + Assert.IsTrue("value2".Equals(props["key2"])); + Assert.IsTrue("true".Equals(props["leadingspace"])); + } - [Test] - public void SeperatorEscapedWithinKey() - { - string input = "\\" + ":key:newvalue"; - Stream s = new MemoryStream(Encoding.ASCII.GetBytes(input)); - Properties props = new Properties(); - props.Load(s); + [Test] + public void WhitespaceProperties() + { + string input = "key1 =\t\nkey2:\nkey3"; - Assert.IsTrue("newvalue".Equals(props[":key"])); - } + Stream s = new MemoryStream(Encoding.ASCII.GetBytes(input)); + Properties props = new Properties(); + props.Load(s); - [Test] - public void EscapedCharactersInValue() - { - string input = "escaped=test\\ttest"; - Stream s = new MemoryStream(Encoding.ASCII.GetBytes(input)); - Properties props = new Properties(); - props.Load(s); + Assert.AreEqual(string.Empty, props["key1"], "key1 should have empty value"); + Assert.AreEqual(string.Empty, props["key2"], "key2 should have empty value"); + Assert.IsTrue(props.ContainsKey("key3")); + Assert.IsNull(props["key3"]); + } - Assert.IsTrue("test\ttest".Equals(props["escaped"])); - } + [Test] + public void Continuation() + { + string input = "continued = this is a long value element \\\r\nthat uses continuation \\\r\n xxx"; + Stream s = new MemoryStream(Encoding.ASCII.GetBytes(input)); + Properties props = new Properties(); + props.Load(s); - } + Assert.IsTrue("this is a long value element that uses continuation xxx".Equals(props["continued"])); + } + + [Test] + public void SeperatorEscapedWithinKey() + { + string input = "\\" + ":key:newvalue"; + Stream s = new MemoryStream(Encoding.ASCII.GetBytes(input)); + Properties props = new Properties(); + props.Load(s); + + Assert.IsTrue("newvalue".Equals(props[":key"])); + } + + [Test] + public void EscapedCharactersInValue() + { + string input = "escaped=test\\ttest"; + Stream s = new MemoryStream(Encoding.ASCII.GetBytes(input)); + Properties props = new Properties(); + props.Load(s); + + Assert.IsTrue("test\ttest".Equals(props["escaped"])); + } } diff --git a/test/Spring/Spring.Core.Tests/Util/ReflectionUtilsMemberwiseCopyTests.cs b/test/Spring/Spring.Core.Tests/Util/ReflectionUtilsMemberwiseCopyTests.cs index 1a659124..885d61ed 100644 --- a/test/Spring/Spring.Core.Tests/Util/ReflectionUtilsMemberwiseCopyTests.cs +++ b/test/Spring/Spring.Core.Tests/Util/ReflectionUtilsMemberwiseCopyTests.cs @@ -1,165 +1,164 @@ using NUnit.Framework; -namespace Spring.Util +namespace Spring.Util; + +/// +/// Summary description for TestMemberwiseCopy. +/// +[TestFixture] +public class ReflectionUtilsMemberwiseCopyTests { - /// - /// Summary description for TestMemberwiseCopy. - /// - [TestFixture] - public class ReflectionUtilsMemberwiseCopyTests - { - [Test] - public void TestSameType() - { - SampleBaseClass i1 = new SampleDerivedClass("1st config val"); - SampleBaseClass i2 = new SampleDerivedClass("2nd config val"); + [Test] + public void TestSameType() + { + SampleBaseClass i1 = new SampleDerivedClass("1st config val"); + SampleBaseClass i2 = new SampleDerivedClass("2nd config val"); - ReflectionUtils.MemberwiseCopy(i1, i2); + ReflectionUtils.MemberwiseCopy(i1, i2); - Assert.AreEqual(i1, i2); - } - - [Test] - public void DifferentTypesForbidden() - { - Assert.Throws(() => ReflectionUtils.MemberwiseCopy("test", 2), "object types are not related"); - } - - [Test] - public void TestDerivedTypeAllowed() - { - SampleBaseClass i1 = new SampleDerivedClass("1st config val"); - SampleBaseClass i2 = new SampleFurtherDerivedClass("2nd config val"); - - ReflectionUtils.MemberwiseCopy(i1, i2); - - Assert.AreEqual(i1, i2); - } - - [Test] - public void TestBaseTypeAllowed() - { - SampleBaseClass i1 = new SampleDerivedClass("1st config val"); - SampleBaseClass i2 = new SampleFurtherDerivedClass("2nd config val"); - - ReflectionUtils.MemberwiseCopy(i2, i1); - - Assert.AreEqual(i1, i2); - } - -#if !NETCOREAPP - [Test] - public void MediumTrustAllowsCopyingBetweenTypesFromSameModule() - { - SampleBaseClass i1 = new SampleDerivedClass("1st config val"); - SampleBaseClass i2 = new SampleFurtherDerivedClass("2nd config val"); - - SecurityTemplate.MediumTrustInvoke(new System.Threading.ThreadStart(new CopyCommand(i2, i1).Execute)); - Assert.AreEqual(i1, i2); - } - - [Test] - public void MediumTrustThrowsSecurityExceptionWhenCopyingBetweenTypesFromDifferentModules() - { - Exception e1 = new Exception("my name is e1"); - var e2 = new System.Web.HttpException("my name is e2"); - // I know, I am a bit paranoid about that basic assumption - Assert.AreNotEqual( e1.GetType().Assembly, e2.GetType().Assembly ); - - SecurityTemplate.MediumTrustInvoke(new System.Threading.ThreadStart(new CopyCommand(e2, e1).Execute)); - Assert.AreEqual(e1.Message, e2.Message); - } -#endif - - class CopyCommand - { - private object a; - private object b; - - public CopyCommand(object a, object b) - { - this.a = a; - this.b = b; - } - - public void Execute() - { - ReflectionUtils.MemberwiseCopy(a, b); - } - } + Assert.AreEqual(i1, i2); } - #region Test Support Classes + [Test] + public void DifferentTypesForbidden() + { + Assert.Throws(() => ReflectionUtils.MemberwiseCopy("test", 2), "object types are not related"); + } - public class SampleBaseClass - { - private const string MyConstant = "SampleBaseClass.MyConstant"; - private readonly string _someReadOnlyVal = "SampleBaseClass.SomeReadOnlyVal"; - protected readonly string _someProtectedReadOnlyVal = "SampleBaseClass.SomeProtectedReadOnlyVal"; - private string _someConfigVal; + [Test] + public void TestDerivedTypeAllowed() + { + SampleBaseClass i1 = new SampleDerivedClass("1st config val"); + SampleBaseClass i2 = new SampleFurtherDerivedClass("2nd config val"); - public SampleBaseClass(string someConfigVal) - { - if (someConfigVal == null) throw new ArgumentNullException("someConfigVal must not be null"); - _someConfigVal = someConfigVal; - _someProtectedReadOnlyVal = "Protected" + someConfigVal; - } + ReflectionUtils.MemberwiseCopy(i1, i2); - public override int GetHashCode() - { - int result = _someReadOnlyVal != null ? _someReadOnlyVal.GetHashCode() : 0; - result = 29*result + (_someProtectedReadOnlyVal != null ? _someProtectedReadOnlyVal.GetHashCode() : 0); - result = 29*result + (_someConfigVal != null ? _someConfigVal.GetHashCode() : 0); - return result; - } + Assert.AreEqual(i1, i2); + } - public override bool Equals(object obj) - { - if (ReferenceEquals(obj, null) || (!this.GetType().IsAssignableFrom(obj.GetType()))) - return false; - if (ReferenceEquals(this , obj)) - return true; + [Test] + public void TestBaseTypeAllowed() + { + SampleBaseClass i1 = new SampleDerivedClass("1st config val"); + SampleBaseClass i2 = new SampleFurtherDerivedClass("2nd config val"); - SampleBaseClass sampleBaseClass = (SampleBaseClass) obj; - if (!Equals(_someReadOnlyVal, sampleBaseClass._someReadOnlyVal)) return false; - if (!Equals(_someProtectedReadOnlyVal, sampleBaseClass._someProtectedReadOnlyVal)) return false; - if (!Equals(_someConfigVal, sampleBaseClass._someConfigVal)) return false; - return true; - } - } + ReflectionUtils.MemberwiseCopy(i2, i1); - public class SampleDerivedClass : SampleBaseClass - { - private string _someConfigVal = "SampleDerivedClass.SomeConfigVal"; + Assert.AreEqual(i1, i2); + } - public SampleDerivedClass(string someConfigVal) : base(someConfigVal) - { - _someConfigVal = "SampleDerivedClass." + someConfigVal; - } +#if !NETCOREAPP + [Test] + public void MediumTrustAllowsCopyingBetweenTypesFromSameModule() + { + SampleBaseClass i1 = new SampleDerivedClass("1st config val"); + SampleBaseClass i2 = new SampleFurtherDerivedClass("2nd config val"); - public override int GetHashCode() - { - return base.GetHashCode() + 29*(_someConfigVal != null ? _someConfigVal.GetHashCode() : 0); - } + SecurityTemplate.MediumTrustInvoke(new System.Threading.ThreadStart(new CopyCommand(i2, i1).Execute)); + Assert.AreEqual(i1, i2); + } - public override bool Equals(object obj) - { - if (!base.Equals(obj)) - return false; + [Test] + public void MediumTrustThrowsSecurityExceptionWhenCopyingBetweenTypesFromDifferentModules() + { + Exception e1 = new Exception("my name is e1"); + var e2 = new System.Web.HttpException("my name is e2"); + // I know, I am a bit paranoid about that basic assumption + Assert.AreNotEqual( e1.GetType().Assembly, e2.GetType().Assembly ); - SampleDerivedClass sampleDerivedClass = (SampleDerivedClass)obj; - if (!Equals(_someConfigVal, sampleDerivedClass._someConfigVal)) - return false; - return true; - } - } + SecurityTemplate.MediumTrustInvoke(new System.Threading.ThreadStart(new CopyCommand(e2, e1).Execute)); + Assert.AreEqual(e1.Message, e2.Message); + } +#endif - public class SampleFurtherDerivedClass : SampleDerivedClass - { - public SampleFurtherDerivedClass(string someConfigVal) : base(someConfigVal) - { - } - } + class CopyCommand + { + private object a; + private object b; - #endregion + public CopyCommand(object a, object b) + { + this.a = a; + this.b = b; + } + + public void Execute() + { + ReflectionUtils.MemberwiseCopy(a, b); + } + } } + +#region Test Support Classes + +public class SampleBaseClass +{ + private const string MyConstant = "SampleBaseClass.MyConstant"; + private readonly string _someReadOnlyVal = "SampleBaseClass.SomeReadOnlyVal"; + protected readonly string _someProtectedReadOnlyVal = "SampleBaseClass.SomeProtectedReadOnlyVal"; + private string _someConfigVal; + + public SampleBaseClass(string someConfigVal) + { + if (someConfigVal == null) throw new ArgumentNullException("someConfigVal must not be null"); + _someConfigVal = someConfigVal; + _someProtectedReadOnlyVal = "Protected" + someConfigVal; + } + + public override int GetHashCode() + { + int result = _someReadOnlyVal != null ? _someReadOnlyVal.GetHashCode() : 0; + result = 29 * result + (_someProtectedReadOnlyVal != null ? _someProtectedReadOnlyVal.GetHashCode() : 0); + result = 29 * result + (_someConfigVal != null ? _someConfigVal.GetHashCode() : 0); + return result; + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(obj, null) || (!this.GetType().IsAssignableFrom(obj.GetType()))) + return false; + if (ReferenceEquals(this, obj)) + return true; + + SampleBaseClass sampleBaseClass = (SampleBaseClass) obj; + if (!Equals(_someReadOnlyVal, sampleBaseClass._someReadOnlyVal)) return false; + if (!Equals(_someProtectedReadOnlyVal, sampleBaseClass._someProtectedReadOnlyVal)) return false; + if (!Equals(_someConfigVal, sampleBaseClass._someConfigVal)) return false; + return true; + } +} + +public class SampleDerivedClass : SampleBaseClass +{ + private string _someConfigVal = "SampleDerivedClass.SomeConfigVal"; + + public SampleDerivedClass(string someConfigVal) : base(someConfigVal) + { + _someConfigVal = "SampleDerivedClass." + someConfigVal; + } + + public override int GetHashCode() + { + return base.GetHashCode() + 29 * (_someConfigVal != null ? _someConfigVal.GetHashCode() : 0); + } + + public override bool Equals(object obj) + { + if (!base.Equals(obj)) + return false; + + SampleDerivedClass sampleDerivedClass = (SampleDerivedClass) obj; + if (!Equals(_someConfigVal, sampleDerivedClass._someConfigVal)) + return false; + return true; + } +} + +public class SampleFurtherDerivedClass : SampleDerivedClass +{ + public SampleFurtherDerivedClass(string someConfigVal) : base(someConfigVal) + { + } +} + +#endregion diff --git a/test/Spring/Spring.Core.Tests/Util/ReflectionUtilsTests.cs b/test/Spring/Spring.Core.Tests/Util/ReflectionUtilsTests.cs index 5d114edb..fcd66470 100644 --- a/test/Spring/Spring.Core.Tests/Util/ReflectionUtilsTests.cs +++ b/test/Spring/Spring.Core.Tests/Util/ReflectionUtilsTests.cs @@ -23,1617 +23,1578 @@ using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using NUnit.Framework; - using Spring.Objects; using Spring.Objects.Factory; using Spring.Objects.Factory.Attributes; [assembly: InternalsVisibleTo("ReflectionUtils.IsTypeVisible.AssemblyTestName")] -namespace Spring.Util +namespace Spring.Util; + +/// +/// Unit tests for the ReflectionUtils class. +/// +[TestFixture] +public sealed class ReflectionUtilsTests { - /// - /// Unit tests for the ReflectionUtils class. - /// - [TestFixture] - public sealed class ReflectionUtilsTests + #region MapsInterfaceMethodsToImplementation utility classes + + interface IMapsInterfaceMethodInterface { - #region MapsInterfaceMethodsToImplementation utility classes - - interface IMapsInterfaceMethodInterface - { - void SomeMethodA(); - void SomeMethodB(); - object SomeProperty { get; } - } - - public class MapsInterfaceMethodClass : IMapsInterfaceMethodInterface - { - public MethodInfo MethodAInfo; - public MethodInfo MethodBInfo; - public MethodInfo PropGetterInfo; - - public MapsInterfaceMethodClass() - { - SomeMethodA(); - ((IMapsInterfaceMethodInterface)this).SomeMethodB(); - object o = ((IMapsInterfaceMethodInterface)this).SomeProperty; - } - - public void SomeMethodA() - { - MethodAInfo = (MethodInfo)MethodInfo.GetCurrentMethod(); - } - - void IMapsInterfaceMethodInterface.SomeMethodB() - { - MethodBInfo = (MethodInfo)MethodInfo.GetCurrentMethod(); - } - - object IMapsInterfaceMethodInterface.SomeProperty - { - get - { - PropGetterInfo = (MethodInfo)MethodInfo.GetCurrentMethod(); - return null; - } - } - } - - #endregion - - private class DummyException : ApplicationException - { - public DummyException() - : base("dummy message") - { - } - } - - public static void ThrowDummyException() - { - throw new DummyException(); - } - - public delegate void VoidAction(); - - [Test] - public void UnwrapsTargetInvocationException() - { - if (SystemUtils.MonoRuntime) - { -#if DEBUG - // TODO (EE): find solution for Mono - return; -#endif - } - - MethodInfo mi = new VoidAction(ThrowDummyException).Method; - try - { - try - { - mi.Invoke(null, null); - Assert.Fail(); - } - catch (TargetInvocationException tie) - { - // Console.WriteLine(tie); - throw ReflectionUtils.UnwrapTargetInvocationException(tie); - } - Assert.Fail(); - } - catch (DummyException e) - { - // Console.WriteLine(e); - string[] stackFrames = e.StackTrace.Split('\n'); -#if !MONO - // TODO: mono includes the invoke() call in inner stackframe does not include the outer stackframes - either remove or document it - string firstFrameMethodName = mi.DeclaringType.FullName + "." + mi.Name; - AssertStringContains(firstFrameMethodName, stackFrames[0]); - string lastFrameMethodName = MethodBase.GetCurrentMethod().DeclaringType.FullName + "." + MethodBase.GetCurrentMethod().Name; - AssertStringContains(lastFrameMethodName, stackFrames[stackFrames.Length - 1]); - -#endif - } - } - - private void AssertStringContains(string toSearch, string source) - { - if (source.IndexOf(toSearch) == -1) - { - Assert.Fail("Expected '{0}' contained in source, but not found. Source was {1}", toSearch, source); - } - } - - [Test] - public void MapsInterfaceMethodsToImplementation() - { - MapsInterfaceMethodClass instance = new MapsInterfaceMethodClass(); - MethodInfo method = null; - - try - { - method = ReflectionUtils.MapInterfaceMethodToImplementationIfNecessary(null, typeof(MapsInterfaceMethodClass)); - Assert.Fail(); - } - catch (ArgumentNullException ex) - { - Assert.AreEqual("methodInfo", ex.ParamName); - } - - try - { - method = ReflectionUtils.MapInterfaceMethodToImplementationIfNecessary((MethodInfo)MethodInfo.GetCurrentMethod(), null); - Assert.Fail(); - } - catch (ArgumentNullException ex) - { - Assert.AreEqual("implementingType", ex.ParamName); - } - - try - { - // unrelated types - method = ReflectionUtils.MapInterfaceMethodToImplementationIfNecessary((MethodInfo)MethodInfo.GetCurrentMethod(), typeof(MapsInterfaceMethodClass)); - Assert.Fail(); - } - catch (ArgumentException ex) - { - Assert.AreEqual("methodInfo and implementingType are unrelated", ex.Message); - } - - method = ReflectionUtils.MapInterfaceMethodToImplementationIfNecessary(typeof(MapsInterfaceMethodClass).GetMethod("SomeMethodA"), typeof(MapsInterfaceMethodClass)); - Assert.AreSame(instance.MethodAInfo, method); - method = ReflectionUtils.MapInterfaceMethodToImplementationIfNecessary(typeof(IMapsInterfaceMethodInterface).GetMethod("SomeMethodA"), typeof(MapsInterfaceMethodClass)); - Assert.AreSame(instance.MethodAInfo, method); - method = ReflectionUtils.MapInterfaceMethodToImplementationIfNecessary(typeof(IMapsInterfaceMethodInterface).GetMethod("SomeMethodB"), typeof(MapsInterfaceMethodClass)); - Assert.AreSame(instance.MethodBInfo, method); - method = ReflectionUtils.MapInterfaceMethodToImplementationIfNecessary(typeof(IMapsInterfaceMethodInterface).GetProperty("SomeProperty").GetGetMethod(), typeof(MapsInterfaceMethodClass)); - Assert.AreSame(instance.PropGetterInfo, method); - } - - #region Helper class for http://jira.springframework.org/browse/SPRNET-992 tests - - public class Foo - { - public readonly string a = ""; - public readonly int b = -1; - public readonly char c = '0'; - - public Foo(string a, int b, char c) - { - this.a = a; - this.b = b; - this.c = c; - } - - public Foo(string a) - { - this.a = a; - } - - public Foo() - { - } - - public void MethodWithNullableIntegerArg(int? nullableInteger) - { - } - } - - #endregion - - [Test(Description = "http://jira.springframework.org/browse/SPRNET-992")] - public void ShouldPickDefaultConstructorWithoutArgs() - { - object[] args = new object[] { }; - ConstructorInfo best = ReflectionUtils.GetConstructorByArgumentValues(typeof(Foo).GetConstructors(), null); - Foo foo = (Foo)best.Invoke(args); - - Assert.AreEqual("", foo.a); - Assert.AreEqual(-1, foo.b); - Assert.AreEqual('0', foo.c); - } - - [Test(Description = "http://jira.springframework.org/browse/SPRNET-992")] - public void ShouldPickDefaultConstructor() - { - object[] args = new object[] { }; - ConstructorInfo best = ReflectionUtils.GetConstructorByArgumentValues(typeof(Foo).GetConstructors(), args); - Foo foo = (Foo)best.Invoke(args); - - Assert.AreEqual("", foo.a); - Assert.AreEqual(-1, foo.b); - Assert.AreEqual('0', foo.c); - } - - [Test(Description = "http://jira.springframework.org/browse/SPRNET-992")] - public void ShouldPickSingleArgConstructor() - { - object[] args = new object[] { "b" }; - ConstructorInfo best = ReflectionUtils.GetConstructorByArgumentValues(typeof(Foo).GetConstructors(), args); - Foo foo = (Foo)best.Invoke(args); - - Assert.AreEqual("b", foo.a); - Assert.AreEqual(-1, foo.b); - Assert.AreEqual('0', foo.c); - } - - [Test] - public void GetParameterTypes() - { - Type[] expectedParameterTypes = new Type[] { typeof(string) }; - MethodInfo method = typeof(ReflectionUtilsObject).GetMethod("BadSpanglish"); - Type[] parameterTypes = ReflectionUtils.GetParameterTypes(method); - Assert.IsTrue(ArrayUtils.AreEqual(expectedParameterTypes, parameterTypes)); - } - - [Test] - public void GetParameterTypesWithNullMethodInfo() - { - Assert.Throws(() => ReflectionUtils.GetParameterTypes((MethodInfo) null)); - } - - [Test] - public void GetParameterTypesWithNullParametersArgs() - { - Assert.Throws(() => ReflectionUtils.GetParameterTypes((ParameterInfo[]) null)); - } - - [Test] - public void GetMatchingMethodsWithNullTypeToFindOn() - { - Assert.Throws(() => ReflectionUtils.GetMatchingMethods(null, new MethodInfo[] { }, true)); - } - - [Test] - public void GetMatchingMethodsWithNullMethodsToFind() - { - Assert.Throws(() => ReflectionUtils.GetMatchingMethods(GetType(), null, true)); - } - - [Test] - public void GetMatchingMethodsWithPerfectMatch() - { - MethodInfo[] clonesMethods = typeof(ReflectionUtilsObjectClone).GetMethods(BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance); - MethodInfo[] foundMethods = ReflectionUtils.GetMatchingMethods(typeof(ReflectionUtilsObject), clonesMethods, true); - Assert.AreEqual(clonesMethods.Length, foundMethods.Length); - } - - [Test] - public void GetMatchingMethodsWithBadMatchStrict() - { - // lets include a protected method that ain't declared on the ReflectionUtilsObject class... - MethodInfo[] clonesMethods = typeof(ReflectionUtilsObjectClone).GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly | BindingFlags.Instance); - Assert.Throws(() => ReflectionUtils.GetMatchingMethods(typeof(ReflectionUtilsObject), clonesMethods, true)); - } - - [Test] - public void GetMatchingMethodsWithBadMatchNotStrict() - { - // lets include a protected method that ain't declared on the ReflectionUtilsObject class... - MethodInfo[] clonesMethods = typeof(ReflectionUtilsObjectClone).GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly | BindingFlags.Instance); - MethodInfo[] foundMethods = ReflectionUtils.GetMatchingMethods(typeof(ReflectionUtilsObject), clonesMethods, false); - // obviously is not strict, 'cos we got here without throwing an exception... - Assert.AreEqual(clonesMethods.Length, foundMethods.Length); - } - - [Test] - public void GetMatchingMethodsWithBadReturnTypeMatchStrict() - { - // lets include a method that return type is different... - MethodInfo[] clonesMethods = typeof(ReflectionUtilsObjectBadClone).GetMethods(BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance); - Assert.Throws(() => ReflectionUtils.GetMatchingMethods(typeof(ReflectionUtilsObject), clonesMethods, true)); - } - - [Test] - public void GetMatchingMethodsWithBadReturnTypeMatchNotStrict() - { - // lets include a method that return type is different... - MethodInfo[] clonesMethods = typeof(ReflectionUtilsObjectBadClone).GetMethods(BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance); - MethodInfo[] foundMethods = ReflectionUtils.GetMatchingMethods(typeof(ReflectionUtilsObject), clonesMethods, false); - // obviously is not strict, 'cos we got here without throwing an exception... - Assert.AreEqual(clonesMethods.Length, foundMethods.Length); - } - - [Test] - public void ParameterTypesMatch() - { - MethodInfo method = typeof(ReflectionUtilsObject).GetMethod("Spanglish"); - Type[] types = new Type[] { typeof(string), typeof(object[]) }; - Assert.IsTrue(ReflectionUtils.ParameterTypesMatch(method, types)); - } - - [Test] - public void ParameterTypesDontMatchWithNonMatchingArgs() - { - Type[] types = new Type[] { typeof(string), typeof(object[]) }; - - MethodInfo method = typeof(ReflectionUtilsObject).GetMethod("BadSpanglish"); - Assert.IsFalse(ReflectionUtils.ParameterTypesMatch(method, types)); - method = typeof(ReflectionUtilsObject).GetMethod("WickedSpanglish"); - Assert.IsFalse(ReflectionUtils.ParameterTypesMatch(method, types)); - } - - [Test] - public void GetDefaultValue() - { - Assert.IsNull(ReflectionUtils.GetDefaultValue(GetType())); - Assert.AreEqual(Cuts.Superficial, ReflectionUtils.GetDefaultValue(typeof(Cuts))); - Assert.AreEqual(false, ReflectionUtils.GetDefaultValue(typeof(bool))); - Assert.AreEqual(DateTime.MinValue, ReflectionUtils.GetDefaultValue(typeof(DateTime))); - Assert.AreEqual(Char.MinValue, ReflectionUtils.GetDefaultValue(typeof(char))); - Assert.AreEqual(0, ReflectionUtils.GetDefaultValue(typeof(long))); - Assert.AreEqual(0, ReflectionUtils.GetDefaultValue(typeof(int))); - Assert.AreEqual(0, ReflectionUtils.GetDefaultValue(typeof(short))); - } - - [Test] - public void PropertyIsIndexer() - { - Assert.IsTrue(ReflectionUtils.PropertyIsIndexer("Item", typeof(TestObject))); - Assert.IsFalse(ReflectionUtils.PropertyIsIndexer("Item", typeof(SideEffectObject))); - Assert.IsFalse(ReflectionUtils.PropertyIsIndexer("Count", typeof(SideEffectObject))); - Assert.IsTrue(ReflectionUtils.PropertyIsIndexer("MyItem", typeof(ObjectWithNonDefaultIndexerName))); - } - - [Test] - public void MethodIsOnOneOfTheseInterfaces() - { - MethodInfo method = typeof(ReflectionUtilsObject).GetMethod("Spanglish"); - Assert.IsTrue(ReflectionUtils.MethodIsOnOneOfTheseInterfaces(method, new Type[] { typeof(IFoo) })); - } - - [Test] - public void MethodIsOnOneOfTheseInterfacesWithNonInterfaceType() - { - MethodInfo method = typeof(ReflectionUtilsObject).GetMethod("Spanglish"); - Assert.Throws(() => ReflectionUtils.MethodIsOnOneOfTheseInterfaces(method, new Type[] { GetType() })); - } - - [Test] - public void MethodIsOnOneOfTheseInterfacesWithNullMethod() - { - MethodInfo method = null; - Assert.Throws(() => ReflectionUtils.MethodIsOnOneOfTheseInterfaces(method, new Type[] { GetType() })); - } - - [Test] - public void MethodIsOnOneOfTheseInterfacesWithNullTypes() - { - MethodInfo method = typeof(ReflectionUtilsObject).GetMethod("Spanglish"); - Assert.IsFalse(ReflectionUtils.MethodIsOnOneOfTheseInterfaces(method, null)); - } - - [Test] - public void MethodIsOnOneOfTheseInterfacesMultiple() - { - MethodInfo method = typeof(RequiredTestObject).GetMethod("set_ObjectFactory"); - Assert.IsNotNull(method, "Could not get setter property for ObjectFactory"); - Assert.IsTrue(ReflectionUtils.MethodIsOnOneOfTheseInterfaces(method, new Type[] { typeof(IObjectNameAware), typeof(IObjectFactoryAware) })); - } - - - [Test] - public void ParameterTypesMatchWithNullArgs() - { - Assert.Throws(() => ReflectionUtils.ParameterTypesMatch(null, null)); - } - - [Test] - public void GetSignature() - { - MethodInfo method = typeof(ReflectionUtilsObject).GetMethod("Spanglish"); - ArrayList list = new ArrayList(); - foreach (ParameterInfo p in method.GetParameters()) - { - list.Add(p.ParameterType); - } - string expected = "Spring.Util.ReflectionUtilsObject::Spanglish(System.String,System.Object[])"; - Type[] pTypes = (Type[])list.ToArray(typeof(Type)); - string actual = ReflectionUtils.GetSignature(method.DeclaringType, method.Name, pTypes); - Assert.AreEqual(expected, actual); - } - - [Test] - public void ToInterfaceArrayFromType() - { - Type[] expected = new Type[] { typeof(IFoo), typeof(IBar) }; - IList actual = ReflectionUtils.ToInterfaceArray(typeof(IBar)); - Assert.AreEqual(expected.Length, actual.Count); - Assert.AreEqual(expected[0], actual[0]); - Assert.AreEqual(expected[1], actual[1]); - } - - [Test] - public void ToInterfaceArrayFromTypeWithNonInterface() - { - Assert.Throws(() => ReflectionUtils.ToInterfaceArray(typeof(ExplicitFoo))); - } - - [Test] - public void GetMethod() - { - MethodInfo actual = ReflectionUtils.GetMethod( - typeof(ReflectionUtilsObject), - "Spanglish", - new Type[] { typeof(string), typeof(object[]) }); - Assert.IsNotNull(actual); - } - - [Test] - public void GetMethodWithExplicitInterfaceMethod() - { - MethodInfo actual = ReflectionUtils.GetMethod( - typeof(ExplicitFoo), - "Spring.Util.IFoo.Spanglish", - new Type[] { typeof(string), typeof(object[]) }); - Assert.IsNotNull(actual); - } - - [Test] - public void GetMethodIsCaseInsensitive() - { - MethodInfo actual = ReflectionUtils.GetMethod( - typeof(ReflectionUtilsObject), - "spAngLISh", - new Type[] { typeof(string), typeof(object[]) }); - Assert.IsNotNull(actual, "ReflectionUtils.GetMethod would appear to be case sensitive."); - } - - [Test] - public void CreateCustomAttributeForNonAttributeType() - { - Assert.Throws(() => ReflectionUtils.CreateCustomAttribute(GetType()), "[Spring.Util.ReflectionUtilsTests] does not derive from the [System.Attribute] class."); - } - - [Test] - public void CreateCustomAttributeWithNullType() - { - Assert.Throws(() => ReflectionUtils.CreateCustomAttribute((Type) null)); - } - - [Test] - public void CreateCustomAttributeSunnyDayScenarios() - { - CustomAttributeBuilder builder = null; - - builder = ReflectionUtils.CreateCustomAttribute(typeof(MyCustomAttribute)); - Assert.IsNotNull(builder); - - builder = ReflectionUtils.CreateCustomAttribute(typeof(MyCustomAttribute), "Rick"); - Assert.IsNotNull(builder); - - builder = ReflectionUtils.CreateCustomAttribute(typeof(MyCustomAttribute), "Rick"); - Assert.IsNotNull(builder); - - builder = ReflectionUtils.CreateCustomAttribute(new MyCustomAttribute("Rick")); - Assert.IsNotNull(builder); - - builder = ReflectionUtils.CreateCustomAttribute(typeof(MyCustomAttribute), new MyCustomAttribute("Rick")); - Assert.IsNotNull(builder); - - builder = ReflectionUtils.CreateCustomAttribute(typeof(MyCustomAttribute), new object[] { "Rick" }, new MyCustomAttribute("Evans")); - Assert.IsNotNull(builder); - - // TODO : actually emit the attribute and check it... - } - -#if !NETCOREAPP - [Test] - public void CreatCustomAttriubtesFromCustomAttributeData() - { - Type control = typeof(System.Windows.Forms.Control); - MethodInfo mi = control.GetMethod("get_Font"); - System.Collections.Generic.IList attributes = CustomAttributeData.GetCustomAttributes(mi.ReturnParameter); - CustomAttributeBuilder builder = null; - foreach (CustomAttributeData customAttributeData in attributes) - { - builder = ReflectionUtils.CreateCustomAttribute(customAttributeData); - Assert.IsNotNull(builder); - } - } -#endif - - [Test] - public void CreatCustomAttriubtesFromCustomAttributeDataWithSingleEnum() - { - MethodInfo mi = typeof(TestClassHavingAttributeWithEnum).GetMethod("SomeMethod"); - System.Collections.Generic.IList attributes = CustomAttributeData.GetCustomAttributes(mi); - CustomAttributeBuilder builder = null; - foreach (CustomAttributeData customAttributeData in attributes) - { - builder = ReflectionUtils.CreateCustomAttribute(customAttributeData); - Assert.IsNotNull(builder); - } - } - - [Test] - public void CreatCustomAttriubtesFromCustomAttributeDataWithArrayOfEnumsSetOnProperty() - { - MethodInfo mi = typeof(TestClassHavingAttributeWithEnumArraySetOnProperty).GetMethod("SomeMethod"); - System.Collections.Generic.IList attributes = CustomAttributeData.GetCustomAttributes(mi); - CustomAttributeBuilder builder = null; - foreach (CustomAttributeData customAttributeData in attributes) - { - builder = ReflectionUtils.CreateCustomAttribute(customAttributeData); - Assert.IsNotNull(builder); - } - } - - [Test] - public void CreatCustomAttriubtesFromCustomAttributeDataWithArrayOfEnumsSetInConstructor() - { - MethodInfo mi = typeof(TestClassHavingAttributeWithEnumArraySetInConstructor).GetMethod("SomeMethod"); - System.Collections.Generic.IList attributes = CustomAttributeData.GetCustomAttributes(mi); - CustomAttributeBuilder builder = null; - foreach (CustomAttributeData customAttributeData in attributes) - { - builder = ReflectionUtils.CreateCustomAttribute(customAttributeData); - Assert.IsNotNull(builder); - } - } - - [Test] - public void CreatCustomAttriubtesFromCustomAttributeDataWithSimpleTypeSetInConstructor() - { - MethodInfo mi = typeof(TestClassHavingAttributeWithSimpleTypeSetInConstructor).GetMethod("SomeMethod"); - System.Collections.Generic.IList attributes = CustomAttributeData.GetCustomAttributes(mi); - CustomAttributeBuilder builder = null; - foreach (CustomAttributeData customAttributeData in attributes) - { - builder = ReflectionUtils.CreateCustomAttribute(customAttributeData); - Assert.IsNotNull(builder); - } - } - - [Test] - public void CreatCustomAttriubtesFromCustomAttributeDataWithGenericCollectionTypeSetInConstructor() - { - MethodInfo mi = typeof(TestClassHavingAttributeWithGenericCollectionTypeSetInConstructor).GetMethod("SomeMethod"); - System.Collections.Generic.IList attributes = CustomAttributeData.GetCustomAttributes(mi); - CustomAttributeBuilder builder = null; - foreach (CustomAttributeData customAttributeData in attributes) - { - builder = ReflectionUtils.CreateCustomAttribute(customAttributeData); - Assert.IsNotNull(builder); - } - } - - internal interface IHaveSomeMethod - { - void SomeMethod(); - } - - internal class TestClassHavingAttributeWithEnum : IHaveSomeMethod - { - [AttributeWithEnum(SomeProperty = TheTestEnumThing.One)] - public void SomeMethod() - { - - } - } - - internal class TestClassHavingAttributeWithEnumArraySetInConstructor : IHaveSomeMethod - { - - [AttributeWithEnumArraySetInConstructor(new TheTestEnumThing[] { TheTestEnumThing.One, TheTestEnumThing.Two })] - public void SomeMethod() - { - - } - } - - internal class TestClassHavingAttributeWithSimpleTypeSetInConstructor : IHaveSomeMethod - { - [AttributeWithType(typeof(int))] - public void SomeMethod() - { - - } - } - - internal class TestClassHavingAttributeWithGenericCollectionTypeSetInConstructor : IHaveSomeMethod - { - [AttributeWithType(typeof(System.Collections.Generic.List))] - public void SomeMethod() - { - - } - } - - internal class TestClassHavingAttributeWithEnumArraySetOnProperty : IHaveSomeMethod - { - [AttributeWithEnumArray(SomeProperty = new TheTestEnumThing[] { TheTestEnumThing.One, TheTestEnumThing.Three })] - public void SomeMethod() - { - - } - } - - internal enum TheTestEnumThing - { - One, Two, Three - } - - internal class AttributeWithTypeAttribute : Attribute - { - public AttributeWithTypeAttribute(Type T) - { - - - - } - - } - - - internal class AttributeWithEnumArrayAttribute : Attribute - { - private TheTestEnumThing[] _someProperty; - public TheTestEnumThing[] SomeProperty - { - get { return _someProperty; } - set - { - _someProperty = value; - } - } - - } - - internal class AttributeWithEnumArraySetInConstructorAttribute : Attribute - { - /// - /// Initializes a new instance of the AttributeWithEnumArraySetInConstructorAttribute class. - /// - public AttributeWithEnumArraySetInConstructorAttribute(TheTestEnumThing[] things) - { - - } - - } - - class AttributeWithEnumAttribute : Attribute - { - private TheTestEnumThing _someProperty; - public TheTestEnumThing SomeProperty - { - get { return _someProperty; } - set - { - _someProperty = value; - } - } - - } - -#if !NETCOREAPP - [Test] - public void CreateCustomAttributeUsingDefaultValuesForTheConstructor() - { - CustomAttributeBuilder builder = null; - builder = ReflectionUtils.CreateCustomAttribute(typeof(AnotherCustomAttribute)); - Assert.IsNotNull(builder); - - AnotherCustomAttribute att - = (AnotherCustomAttribute)CheckForPresenceOfCustomAttribute(builder, typeof(AnotherCustomAttribute)); - Assert.IsNull(att.Name); - Assert.AreEqual(0, att.Age); - Assert.IsFalse(att.HasSwallowedExplosives); - } - - [Test] - public void CreateCustomAttributeFromSourceAttribute() - { - CustomAttributeBuilder builder = null; - AnotherCustomAttribute source = new AnotherCustomAttribute("Rick", 30, true); - builder = ReflectionUtils.CreateCustomAttribute(source); - Assert.IsNotNull(builder); - - AnotherCustomAttribute att - = (AnotherCustomAttribute)CheckForPresenceOfCustomAttribute(builder, typeof(AnotherCustomAttribute)); - Assert.AreEqual(source.Name, att.Name); - Assert.AreEqual(source.Age, att.Age); - Assert.AreEqual(source.HasSwallowedExplosives, att.HasSwallowedExplosives); - } - - [Test] - public void CreateCustomAttributeUsingExplicitValuesForTheConstructor() - { - CustomAttributeBuilder builder = null; - const string expectedName = "Rick"; - const int expectedAge = 30; - builder = ReflectionUtils.CreateCustomAttribute(typeof(AnotherCustomAttribute), new object[] - { - expectedName, expectedAge, true - }); - Assert.IsNotNull(builder); - - AnotherCustomAttribute att - = (AnotherCustomAttribute)CheckForPresenceOfCustomAttribute(builder, typeof(AnotherCustomAttribute)); - Assert.AreEqual(expectedName, att.Name); - Assert.AreEqual(expectedAge, att.Age); - Assert.IsTrue(att.HasSwallowedExplosives); - } - - [Test] - public void CreateCustomAttributeUsingExplicitValuesForTheConstructorAndASourceAttribute() - { - CustomAttributeBuilder builder = null; - const string expectedName = "Rick"; - const int expectedAge = 30; - AnotherCustomAttribute source = new AnotherCustomAttribute(expectedName, expectedAge, false); - builder = ReflectionUtils.CreateCustomAttribute(typeof(AnotherCustomAttribute), new object[] - { - "Hoop", 2, true - }, source); - Assert.IsNotNull(builder); - - AnotherCustomAttribute att - = (AnotherCustomAttribute)CheckForPresenceOfCustomAttribute(builder, typeof(AnotherCustomAttribute)); - Assert.AreEqual(expectedName, att.Name); - Assert.AreEqual(expectedAge, att.Age); - Assert.IsFalse(att.HasSwallowedExplosives); - } -#endif - - [Test] - public void HasAtLeastOneMethodWithName() - { - Type testType = typeof(ExtendedReflectionUtilsObject); - // declared method... - Assert.IsTrue(ReflectionUtils.HasAtLeastOneMethodWithName(testType, "Declared")); - // case insensitive method... - Assert.IsTrue(ReflectionUtils.HasAtLeastOneMethodWithName(testType, "deCLAReD")); - // superclass method... - Assert.IsTrue(ReflectionUtils.HasAtLeastOneMethodWithName(testType, "Spanglish")); - // static method... - Assert.IsTrue(ReflectionUtils.HasAtLeastOneMethodWithName(testType, "Static")); - // protected method... - Assert.IsTrue(ReflectionUtils.HasAtLeastOneMethodWithName(testType, "Protected")); - // non existent method... - Assert.IsFalse(ReflectionUtils.HasAtLeastOneMethodWithName(testType, "Sponglish")); - // null type... - Assert.IsFalse(ReflectionUtils.HasAtLeastOneMethodWithName(null, "Spanglish")); - // null method name... - Assert.IsFalse(ReflectionUtils.HasAtLeastOneMethodWithName(testType, null)); - // empty method name... - Assert.IsFalse(ReflectionUtils.HasAtLeastOneMethodWithName(testType, "")); - // all nulls... - Assert.IsFalse(ReflectionUtils.HasAtLeastOneMethodWithName(null, null)); - } - - [Test] - public void GetTypeOfOrTypeWithNull() - { - Assert.Throws(() => ReflectionUtils.TypeOfOrType(null)); - } - - [Test] - public void GetTypeOfOrType() - { - Assert.AreEqual(typeof(string), ReflectionUtils.TypeOfOrType(typeof(string))); - } - - [Test] - public void GetTypeOfOrTypeWithNonNullType() - { - Assert.AreEqual(typeof(string), ReflectionUtils.TypeOfOrType(string.Empty)); - } - - [Test] - public void GetTypes() - { - Type[] actual = ReflectionUtils.GetTypes( - new object[] { 1, "I've never been to Taco Bell (sighs).", new ReflectionUtilsObject() }); - Type[] expected = new Type[] - { - typeof (int), - typeof (string), - typeof (ReflectionUtilsObject), - }; - Assert.IsTrue(ArrayUtils.AreEqual(expected, actual), "The ReflectionUtils.GetTypes method did not return a correct Type [] array. Yep, that's as helpful as it gets."); - } - - [Test] - public void GetTypesWithEmptyArrayArgument() - { - Type[] actual = ReflectionUtils.GetTypes(new object[] { }); - Assert.IsNotNull(actual, "The ReflectionUtils.GetTypes method returned null when given an empty array. Must return an empty Type [] array."); - Assert.IsTrue(actual.Length == 0, "The ReflectionUtils.GetTypes method returned a Type [] that had some elements in it when given an empty array. Must return an empty Type [] array."); - } - - [Test] - public void GetTypesWithNullArrayArgument() - { - Type[] actual = ReflectionUtils.GetTypes(null); - Assert.IsNotNull(actual, "The ReflectionUtils.GetTypes method returned null when given null. Must return an empty Type [] array."); - Assert.IsTrue(actual.Length == 0, "The ReflectionUtils.GetTypes method returned a Type [] that had some elements in it when given null. Must return an empty Type [] array."); - } - - [Test] - public void GetDefaultValueWithZeroValueEnumType() - { - Assert.Throws(() => ReflectionUtils.GetDefaultValue(typeof(EnumWithNoValues))); - } - - [Test] - public void GetParameterTypesWithMethodThatHasRefParameters() - { - MethodInfo method = GetType().GetMethod("Add"); - Type[] types = ReflectionUtils.GetParameterTypes(method); - Assert.IsNotNull(types); - Assert.AreEqual(2, types.Length); - // first method parameter is byRef, so type name must end in '&' - Assert.AreEqual("System.Int32&", types[0].FullName); - Assert.AreEqual("System.Int32", types[1].FullName); - } - - [Test] - public void GetMethodByArgumentValuesCanResolveWhenAmbiguousMatchIsOnlyDifferentiatedByParams() - { - GetMethodByArgumentValuesTarget.DummyArgumentType[] typedArg = new GetMethodByArgumentValuesTarget.DummyArgumentType[] { }; - GetMethodByArgumentValuesTarget foo = new GetMethodByArgumentValuesTarget(1, typedArg); - - Type type = typeof(GetMethodByArgumentValuesTarget); - MethodInfo[] candidateMethods = new MethodInfo[] - { - type.GetMethod("ParamOverloadedMethod", new Type[] {typeof(string), typeof(string), typeof(string)}) - ,type.GetMethod("ParamOverloadedMethod", new Type[] {typeof(string), typeof(string), typeof(bool)}) - ,type.GetMethod("ParamOverloadedMethod", new Type[] {typeof(string), typeof(string), typeof(string), typeof(string), typeof(object[])}) - }; - - // ensure no one changed our test class - Assert.IsNotNull(candidateMethods[0]); - Assert.IsNotNull(candidateMethods[1]); - Assert.IsNotNull(candidateMethods[2]); - Assert.AreEqual("ThreeStringsOverload", foo.ParamOverloadedMethod(string.Empty, string.Empty, string.Empty)); - Assert.AreEqual("TwoStringsAndABoolOverload", foo.ParamOverloadedMethod(string.Empty, string.Empty, default(bool))); - Assert.AreEqual("FourStringsAndAParamsCollectionOverload", foo.ParamOverloadedMethod(string.Empty, string.Empty, string.Empty, string.Empty, typedArg)); - - MethodInfo resolvedMethod = ReflectionUtils.GetMethodByArgumentValues(candidateMethods, new object[] { string.Empty, string.Empty, string.Empty, string.Empty, typedArg }); - Assert.AreSame(candidateMethods[2], resolvedMethod); - } - - - [Test] - public void GetMethodByArgumentValuesResolvesToExactMatchIfAvailable() - { - GetMethodByArgumentValuesTarget.DummyArgumentType[] typedArg = new GetMethodByArgumentValuesTarget.DummyArgumentType[] { }; - GetMethodByArgumentValuesTarget foo = new GetMethodByArgumentValuesTarget(1, typedArg); - - Type type = typeof(GetMethodByArgumentValuesTarget); - MethodInfo[] candidateMethods = new MethodInfo[] - { - type.GetMethod("MethodWithSimilarArguments", new Type[] {typeof(int), typeof(ICollection)}) - , type.GetMethod("MethodWithSimilarArguments", new Type[] {typeof(int), typeof(GetMethodByArgumentValuesTarget.DummyArgumentType[])}) - , type.GetMethod("MethodWithSimilarArguments", new Type[] {typeof(int), typeof(object[])}) - }; - - // ensure no one changed our test class - Assert.IsNotNull(candidateMethods[0]); - Assert.IsNotNull(candidateMethods[1]); - Assert.IsNotNull(candidateMethods[2]); - Assert.AreEqual("ParamArrayMatch", foo.MethodWithSimilarArguments(1, new object())); - Assert.AreEqual("ExactMatch", foo.MethodWithSimilarArguments(1, typedArg)); - Assert.AreEqual("AssignableMatch", foo.MethodWithSimilarArguments(1, (ICollection)typedArg)); - - MethodInfo resolvedMethod = ReflectionUtils.GetMethodByArgumentValues(candidateMethods, new object[] { 1, typedArg }); - Assert.AreSame(candidateMethods[1], resolvedMethod); - } - - [Test] - public void GetMethodByArgumentValuesMatchesNullableArgs() - { - GetMethodByArgumentValuesTarget.DummyArgumentType[] typedArg = new GetMethodByArgumentValuesTarget.DummyArgumentType[] { }; - GetMethodByArgumentValuesTarget foo = new GetMethodByArgumentValuesTarget(1, typedArg); - - Type type = typeof(GetMethodByArgumentValuesTarget); - MethodInfo[] candidateMethods = new MethodInfo[] - { - type.GetMethod("MethodWithSimilarArguments", new Type[] {typeof(int), typeof(ICollection)}) - , type.GetMethod("MethodWithSimilarArguments", new Type[] {typeof(int), typeof(GetMethodByArgumentValuesTarget.DummyArgumentType[])}) - , type.GetMethod("MethodWithSimilarArguments", new Type[] {typeof(int), typeof(object[])}) - , type.GetMethod("MethodWithNullableArgument", new Type[] {typeof(int?)}) - }; - - // ensure no one changed our test class - Assert.IsNotNull(candidateMethods[0]); - Assert.IsNotNull(candidateMethods[1]); - Assert.IsNotNull(candidateMethods[2]); - Assert.IsNotNull(candidateMethods[3]); - Assert.AreEqual("ParamArrayMatch", foo.MethodWithSimilarArguments(1, new object())); - Assert.AreEqual("ExactMatch", foo.MethodWithSimilarArguments(1, typedArg)); - Assert.AreEqual("AssignableMatch", foo.MethodWithSimilarArguments(1, (ICollection)typedArg)); - Assert.AreEqual("NullableArgumentMatch", foo.MethodWithNullableArgument(null)); - - MethodInfo resolvedMethod = ReflectionUtils.GetMethodByArgumentValues(candidateMethods, new object[] { null }); - Assert.AreSame(candidateMethods[3], resolvedMethod); - } - - [Test] - public void GetConstructorByArgumentValuesResolvesToExactMatchIfAvailable() - { - GetMethodByArgumentValuesTarget.DummyArgumentType[] typedArg = new GetMethodByArgumentValuesTarget.DummyArgumentType[] { }; - Type type = typeof(GetMethodByArgumentValuesTarget); - ConstructorInfo[] candidateConstructors = new ConstructorInfo[] - { - type.GetConstructor(new Type[] {typeof(int), typeof(ICollection)}) - , type.GetConstructor(new Type[] {typeof(int), typeof(GetMethodByArgumentValuesTarget.DummyArgumentType[])}) - , type.GetConstructor(new Type[] {typeof(int), typeof(object[])}) - }; - - // ensure noone changed our test class - Assert.IsNotNull(candidateConstructors[0]); - Assert.IsNotNull(candidateConstructors[1]); - Assert.IsNotNull(candidateConstructors[2]); - Assert.AreEqual("ParamArrayMatch", new GetMethodByArgumentValuesTarget(1, new object()).SelectedConstructor); - Assert.AreEqual("ExactMatch", new GetMethodByArgumentValuesTarget(1, typedArg).SelectedConstructor); - Assert.AreEqual("AssignableMatch", new GetMethodByArgumentValuesTarget(1, (ICollection)typedArg).SelectedConstructor); - - ConstructorInfo resolvedConstructor = ReflectionUtils.GetConstructorByArgumentValues(candidateConstructors, new object[] { 1, typedArg }); - Assert.AreSame(candidateConstructors[1], resolvedConstructor); - } - - #region GetInterfaces - - [Test] - public void GetInterfaces() - { - Assert.AreEqual( - typeof(TestObject).GetInterfaces().Length, - ReflectionUtils.GetInterfaces(typeof(TestObject)).Length); - - Assert.AreEqual(1, ReflectionUtils.GetInterfaces(typeof(IInterface1)).Length); - Assert.AreEqual(4, ReflectionUtils.GetInterfaces(typeof(IInterface2)).Length); - } - - public interface IInterface1 - { - } - - public interface IInterface2 : IInterface3 - { - } - - public interface IInterface3 : IInterface4, IInterface5 - { - } - - public interface IInterface4 - { - } - - public interface IInterface5 - { - } - - #endregion - - #region IsTypeVisible Tests - - [Test] - public void IsTypeVisibleWithInternalType() - { - Type type = typeof(InternalType); - Assert.IsFalse(ReflectionUtils.IsTypeVisible(type)); - } - - [Test] - public void IsTypeVisibleWithPublicNestedTypeOnInternalType() - { - Type type = typeof(InternalType.PublicNestedType); - Assert.IsFalse(ReflectionUtils.IsTypeVisible(type)); - } - - [Test] - public void IsTypeVisibleWithInternalNestedTypeOnInternalType() - { - Type type = typeof(InternalType.InternalNestedType); - Assert.IsFalse(ReflectionUtils.IsTypeVisible(type)); - } - - [Test] - public void IsTypeVisibleWithProtectedInternalNestedTypeOnInternalType() - { - Type type = typeof(InternalType.ProtectedInternalNestedType); - Assert.IsFalse(ReflectionUtils.IsTypeVisible(type)); - } - - [Test] - public void IsTypeVisibleWithProtectedNestedTypeOnInternalType() - { - Type type = typeof(InternalType).GetNestedType("ProtectedNestedType", BindingFlags.NonPublic); - Assert.IsFalse(ReflectionUtils.IsTypeVisible(type)); - } - - [Test] - public void IsTypeVisibleWithPrivateNestedTypeOnInternalType() - { - Type type = typeof(InternalType).GetNestedType("PrivateNestedType", BindingFlags.NonPublic); - Assert.IsFalse(ReflectionUtils.IsTypeVisible(type)); - } - - [Test] - public void IsTypeVisibleWithPublicType() - { - Type type = typeof(PublicType); - Assert.IsTrue(ReflectionUtils.IsTypeVisible(type)); - } - - [Test] - public void IsTypeVisibleWithPublicNestedTypeOnPublicType() - { - Type type = typeof(PublicType.PublicNestedType); - Assert.IsTrue(ReflectionUtils.IsTypeVisible(type)); - } - - [Test] - public void IsTypeVisibleWithInternalNestedTypeOnPublicType() - { - Type type = typeof(PublicType.InternalNestedType); - Assert.IsFalse(ReflectionUtils.IsTypeVisible(type)); - } - - [Test] - public void IsTypeVisibleWithProtectedInternalNestedTypeOnPublicType() - { - Type type = typeof(PublicType.ProtectedInternalNestedType); - Assert.IsFalse(ReflectionUtils.IsTypeVisible(type)); - } - - [Test] - public void IsTypeVisibleWithProtectedNestedTypeOnPublicType() - { - Type type = typeof(PublicType).GetNestedType("ProtectedNestedType", BindingFlags.NonPublic); - Assert.IsFalse(ReflectionUtils.IsTypeVisible(type)); - } - - [Test] - public void IsTypeVisibleWithPrivateNestedTypeOnPublicType() - { - Type type = typeof(PublicType).GetNestedType("PrivateNestedType", BindingFlags.NonPublic); - Assert.IsFalse(ReflectionUtils.IsTypeVisible(type)); - } - - private static readonly string FRIENDLY_ASSEMBLY_NAME = "ReflectionUtils.IsTypeVisible.AssemblyTestName"; - - [Test] - public void IsTypeVisibleFromFriendlyAssemblyWithInternalType() - { - Type type = typeof(InternalType); - Assert.IsTrue(ReflectionUtils.IsTypeVisible(type, FRIENDLY_ASSEMBLY_NAME)); - } - - [Test] - public void IsTypeVisibleFromFriendlyAssemblyWithPublicNestedTypeOnInternalType() - { - Type type = typeof(InternalType.PublicNestedType); - Assert.IsTrue(ReflectionUtils.IsTypeVisible(type, FRIENDLY_ASSEMBLY_NAME)); - } - - [Test] - public void IsTypeVisibleFromFriendlyAssemblyWithInternalNestedTypeOnInternalType() - { - Type type = typeof(InternalType.InternalNestedType); - Assert.IsTrue(ReflectionUtils.IsTypeVisible(type, FRIENDLY_ASSEMBLY_NAME)); - } - - [Test] - public void IsTypeVisibleFromFriendlyAssemblyWithProtectedInternalNestedTypeOnInternalType() - { - Type type = typeof(InternalType.ProtectedInternalNestedType); - Assert.IsTrue(ReflectionUtils.IsTypeVisible(type, FRIENDLY_ASSEMBLY_NAME)); - } - - [Test] - public void IsTypeVisibleFromFriendlyAssemblyWithProtectedNestedTypeOnInternalType() - { - Type type = typeof(InternalType).GetNestedType("ProtectedNestedType", BindingFlags.NonPublic); - Assert.IsFalse(ReflectionUtils.IsTypeVisible(type, FRIENDLY_ASSEMBLY_NAME)); - } - - [Test] - public void IsTypeVisibleFromFriendlyAssemblyWithPrivateNestedTypeOnInternalType() - { - Type type = typeof(InternalType).GetNestedType("PrivateNestedType", BindingFlags.NonPublic); - Assert.IsFalse(ReflectionUtils.IsTypeVisible(type, FRIENDLY_ASSEMBLY_NAME)); - } - - [Test] - public void IsTypeVisibleFromFriendlyAssemblyWithPublicType() - { - Type type = typeof(PublicType); - Assert.IsTrue(ReflectionUtils.IsTypeVisible(type, FRIENDLY_ASSEMBLY_NAME)); - } - - [Test] - public void IsTypeVisibleFromFriendlyAssemblyWithPublicNestedTypeOnPublicType() - { - Type type = typeof(PublicType.PublicNestedType); - Assert.IsTrue(ReflectionUtils.IsTypeVisible(type, FRIENDLY_ASSEMBLY_NAME)); - } - - [Test] - public void IsTypeVisibleFromFriendlyAssemblyWithInternalNestedTypeOnPublicType() - { - Type type = typeof(PublicType.InternalNestedType); - Assert.IsTrue(ReflectionUtils.IsTypeVisible(type, FRIENDLY_ASSEMBLY_NAME)); - } - - [Test] - public void IsTypeVisibleFromFriendlyAssemblyWithProtectedInternalNestedTypeOnPublicType() - { - Type type = typeof(PublicType.ProtectedInternalNestedType); - Assert.IsTrue(ReflectionUtils.IsTypeVisible(type, FRIENDLY_ASSEMBLY_NAME)); - } - - [Test] - public void IsTypeVisibleFromFriendlyAssemblyWithProtectedNestedTypeOnPublicType() - { - Type type = typeof(PublicType).GetNestedType("ProtectedNestedType", BindingFlags.NonPublic); - Assert.IsFalse(ReflectionUtils.IsTypeVisible(type, FRIENDLY_ASSEMBLY_NAME)); - } - - [Test] - public void IsTypeVisibleFromFriendlyAssemblyWithPrivateNestedTypeOnPublicType() - { - Type type = typeof(PublicType).GetNestedType("PrivateNestedType", BindingFlags.NonPublic); - Assert.IsFalse(ReflectionUtils.IsTypeVisible(type, FRIENDLY_ASSEMBLY_NAME)); - } - - [Test] - public void IsTypeNullable_WhenTrue() - { - Type type = typeof(int?); - Assert.That(ReflectionUtils.IsNullableType(type), Is.True); - } - - [Test] - public void IsTypeNullable_WhenFalse() - { - Type type = typeof(int); - Assert.That(ReflectionUtils.IsNullableType(type), Is.False); - } - - [Test] - public void GetCustomAttributesOnType() - { - IList attrs = ReflectionUtils.GetCustomAttributes(typeof(ClassWithAttributes)); - -#if NETCOREAPP - Assert.AreEqual(1, attrs.Count); -#else - Assert.AreEqual(2, attrs.Count); -#endif - } - - [Test] - public void GetCustomAttributesOnMethod() - { - IList attrs = ReflectionUtils.GetCustomAttributes(typeof(ClassWithAttributes).GetMethod("MethodWithAttributes")); - -#if NETCOREAPP - Assert.AreEqual(1, attrs.Count); -#else - Assert.AreEqual(2, attrs.Count); -#endif - } - - #endregion - - #region GetExplicitBaseException - - [Test] - public void GetExplicitBaseExceptionWithNoInnerException() - { - Exception appEx = new ApplicationException(); - Exception ex = ReflectionUtils.GetExplicitBaseException(appEx); - - Assert.AreEqual(ex, appEx); - } - - [Test] - public void GetExplicitBaseExceptionWithInnerException() - { - Exception dbzEx = new DivideByZeroException(); - Exception appEx = new ApplicationException("Test message", dbzEx); - Exception ex = ReflectionUtils.GetExplicitBaseException(appEx); - - Assert.AreEqual(ex, dbzEx); - } - - [Test] - public void GetExplicitBaseExceptionWithInnerExceptions() - { - Exception dbzEx = new DivideByZeroException(); - Exception sEx = new SystemException("Test message", dbzEx); - Exception appEx = new ApplicationException("Test message", sEx); - Exception ex = ReflectionUtils.GetExplicitBaseException(appEx); - - Assert.AreEqual(ex, dbzEx); - } - - [Test] - public void GetExplicitBaseExceptionWithNullReferenceExceptionAsRootException() - { - Exception nrEx = new NullReferenceException(); - Exception appEx = new ApplicationException("Test message", nrEx); - Exception ex = ReflectionUtils.GetExplicitBaseException(appEx); - - Assert.AreEqual(ex, appEx); - } - - [Test] - public void CanGetFriendlyNamesForGenericTypes() - { - Type t = typeof(System.Collections.Generic.List>); - - Assert.AreEqual("System.Collections.Generic.List>", ReflectionUtils.GetTypeFriendlyName(t)); - } - - #endregion - - #region Helper Methods - - public int Add(ref int one, int two) - { - return one + two; - } - -#if !NETCOREAPP - private Attribute CheckForPresenceOfCustomAttribute( - CustomAttributeBuilder attBuilder, Type attType) - { - Attribute[] atts = ApplyAndGetCustomAttributes(attBuilder); - Assert.IsNotNull(atts); - Assert.IsTrue(atts.Length == 1); - Attribute att = atts[0]; - Assert.IsNotNull(att); - Assert.AreEqual(attType, att.GetType(), "Wrong Attribute applied to the class."); - return att; - } - - private static Attribute[] ApplyAndGetCustomAttributes(CustomAttributeBuilder attBuilder) - { - Type type = BuildTypeWithThisCustomAttribute(attBuilder); - object[] attributes = type.GetCustomAttributes(true); - return (Attribute[])ArrayList.Adapter(attributes).ToArray(typeof(Attribute)); - } - - private static Type BuildTypeWithThisCustomAttribute(CustomAttributeBuilder attBuilder) - { - AssemblyName assemblyName = new AssemblyName(); - assemblyName.Name = "AnAssembly"; - AssemblyBuilder asmBuilder = System.Threading.Thread.GetDomain().DefineDynamicAssembly( - assemblyName, AssemblyBuilderAccess.Run); - ModuleBuilder modBuilder = asmBuilder.DefineDynamicModule("AModule"); - TypeBuilder classBuilder = modBuilder.DefineType("AClass", TypeAttributes.Public); - classBuilder.SetCustomAttribute(attBuilder); - return classBuilder.CreateType(); - } -#endif - #endregion + void SomeMethodA(); + void SomeMethodB(); + object SomeProperty { get; } } - #region Simple Helper Classes - - public class PublicType + public class MapsInterfaceMethodClass : IMapsInterfaceMethodInterface { - public class PublicNestedType + public MethodInfo MethodAInfo; + public MethodInfo MethodBInfo; + public MethodInfo PropGetterInfo; + + public MapsInterfaceMethodClass() { + SomeMethodA(); + ((IMapsInterfaceMethodInterface) this).SomeMethodB(); + object o = ((IMapsInterfaceMethodInterface) this).SomeProperty; } - internal class InternalNestedType + public void SomeMethodA() { + MethodAInfo = (MethodInfo) MethodInfo.GetCurrentMethod(); } - protected internal class ProtectedInternalNestedType + void IMapsInterfaceMethodInterface.SomeMethodB() { + MethodBInfo = (MethodInfo) MethodInfo.GetCurrentMethod(); } - protected class ProtectedNestedType - { - } - - private class PrivateNestedType - { - } - } - - internal class InternalType - { - public class PublicNestedType - { - } - - internal class InternalNestedType - { - } - - protected internal class ProtectedInternalNestedType - { - } - - protected class ProtectedNestedType - { - } - - private class PrivateNestedType - { - } - } - - internal enum EnumWithNoValues { } - - internal enum Cuts - { - Superficial, - Deep, - Severing - } - - internal interface IBar : IFoo - { - } - - internal interface IFoo - { - bool Spanglish(string foo, object[] args); - } - - internal sealed class ExplicitFoo : IFoo - { - bool IFoo.Spanglish(string foo, object[] args) - { - return false; - } - } - - internal class ReflectionUtilsObject : IComparable - { - public bool Spanglish(string foo, object[] args) - { - return false; - } - - public bool BadSpanglish(string foo) - { - return false; - } - - public bool WickedSpanglish(string foo, string bar) - { - return false; - } - - /// - /// Explicit interface implementation for ReflectionUtils.GetMethod tests - /// - /// - /// - int IComparable.CompareTo(object obj) - { - return 0; - } - } - - internal sealed class ExtendedReflectionUtilsObject : ReflectionUtilsObject - { - public void Declared(string name) - { - } - - public void Protected() - { - } - - public static void Static() - { - } - } - - /// - /// Exposes methods with the same names as the ReflectionUtilsObject, used in - /// the tests for the GetMatchingMethods method. - /// - internal class ReflectionUtilsObjectClone - { - public bool Spanglish(string foo, object[] args) - { - return false; - } - - public bool BadSpanglish(string foo) - { - return false; - } - - public bool WickedSpanglish(string foo, string bar) - { - return false; - } - - protected void Bingo() - { - } - } - - /// - /// Exposes methods with the same names as the ReflectionUtilsObject, used in - /// the tests for the GetMatchingMethods method. - /// - internal class ReflectionUtilsObjectBadClone - { - public bool Spanglish(string foo, object[] args) - { - return false; - } - - public string BadSpanglish(string foo) - { - return foo; - } - - public bool WickedSpanglish(string foo, string bar) - { - return false; - } - } - - internal class GetMethodByArgumentValuesTarget - { - public class DummyArgumentType { } - - public string SelectedConstructor; - - public GetMethodByArgumentValuesTarget(int flag, params object[] values) - { - SelectedConstructor = "ParamArrayMatch"; - } - - public GetMethodByArgumentValuesTarget(int flag, DummyArgumentType[] bars) - { - SelectedConstructor = "ExactMatch"; - } - - public GetMethodByArgumentValuesTarget(int flag, ICollection bars) - { - SelectedConstructor = "AssignableMatch"; - } - - public string MethodWithSimilarArguments(int flags, params object[] args) - { - return "ParamArrayMatch"; - } - - public string MethodWithSimilarArguments(int flags, DummyArgumentType[] bars) - { - return "ExactMatch"; - } - - public string MethodWithSimilarArguments(int flags, ICollection bar) - { - return "AssignableMatch"; - } - - public string MethodWithNullableArgument(int? nullableInteger) - { - return "NullableArgumentMatch"; - } - - public string ParamOverloadedMethod(string s1, string s2, string s3) - { - return "ThreeStringsOverload"; - } - - public string ParamOverloadedMethod(string s1, string s2, bool b1) - { - return "TwoStringsAndABoolOverload"; - } - - public string ParamOverloadedMethod(string s1, string s2, string s3, string s4, params object[] args) - { - return "FourStringsAndAParamsCollectionOverload"; - } - - - } - - public sealed class MyCustomAttribute : Attribute - { - public MyCustomAttribute() - { - } - - public MyCustomAttribute(string name) - { - _name = name; - } - - public string Name - { - get { return _name; } - } - - private string _name; - } - - /// - /// Used for testing that default values are supplied for the ctor args. - /// - public sealed class AnotherCustomAttribute : Attribute - { - public AnotherCustomAttribute(string name, int age, bool hasSwallowedExplosives) - { - _name = name; - _age = age; - _hasSwallowedExplosives = hasSwallowedExplosives; - } - - public string Name - { - get { return _name; } - set { _name = value; } - } - - public int Age - { - get { return _age; } - set { _age = value; } - } - - public bool HasSwallowedExplosives - { - get { return _hasSwallowedExplosives; } - set { _hasSwallowedExplosives = value; } - } - - private string _name; - private int _age; - private bool _hasSwallowedExplosives; - } - - public sealed class ObjectWithNonDefaultIndexerName - { - private string[] favoriteQuotes = new string[10]; - - [IndexerName("MyItem")] - public string this[int index] + object IMapsInterfaceMethodInterface.SomeProperty { get { - if (index < 0 || index >= favoriteQuotes.Length) - { - throw new ArgumentException("Index out of range"); - } - return favoriteQuotes[index]; + PropGetterInfo = (MethodInfo) MethodInfo.GetCurrentMethod(); + return null; } - - set - { - if (index < 0 || index >= favoriteQuotes.Length) - { - throw new ArgumentException("index is out of range."); - } - favoriteQuotes[index] = value; - } - } } - [MyCustom] - [System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand)] - public sealed class ClassWithAttributes + #endregion + + private class DummyException : ApplicationException { - [MyCustom] - [System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand)] - public void MethodWithAttributes() + public DummyException() + : base("dummy message") + { + } + } + + public static void ThrowDummyException() + { + throw new DummyException(); + } + + public delegate void VoidAction(); + + [Test] + public void UnwrapsTargetInvocationException() + { + if (SystemUtils.MonoRuntime) + { +#if DEBUG + // TODO (EE): find solution for Mono + return; +#endif + } + + MethodInfo mi = new VoidAction(ThrowDummyException).Method; + try + { + try + { + mi.Invoke(null, null); + Assert.Fail(); + } + catch (TargetInvocationException tie) + { + // Console.WriteLine(tie); + throw ReflectionUtils.UnwrapTargetInvocationException(tie); + } + + Assert.Fail(); + } + catch (DummyException e) + { + // Console.WriteLine(e); + string[] stackFrames = e.StackTrace.Split('\n'); +#if !MONO + // TODO: mono includes the invoke() call in inner stackframe does not include the outer stackframes - either remove or document it + string firstFrameMethodName = mi.DeclaringType.FullName + "." + mi.Name; + AssertStringContains(firstFrameMethodName, stackFrames[0]); + string lastFrameMethodName = MethodBase.GetCurrentMethod().DeclaringType.FullName + "." + MethodBase.GetCurrentMethod().Name; + AssertStringContains(lastFrameMethodName, stackFrames[stackFrames.Length - 1]); + +#endif + } + } + + private void AssertStringContains(string toSearch, string source) + { + if (source.IndexOf(toSearch) == -1) + { + Assert.Fail("Expected '{0}' contained in source, but not found. Source was {1}", toSearch, source); + } + } + + [Test] + public void MapsInterfaceMethodsToImplementation() + { + MapsInterfaceMethodClass instance = new MapsInterfaceMethodClass(); + MethodInfo method = null; + + try + { + method = ReflectionUtils.MapInterfaceMethodToImplementationIfNecessary(null, typeof(MapsInterfaceMethodClass)); + Assert.Fail(); + } + catch (ArgumentNullException ex) + { + Assert.AreEqual("methodInfo", ex.ParamName); + } + + try + { + method = ReflectionUtils.MapInterfaceMethodToImplementationIfNecessary((MethodInfo) MethodInfo.GetCurrentMethod(), null); + Assert.Fail(); + } + catch (ArgumentNullException ex) + { + Assert.AreEqual("implementingType", ex.ParamName); + } + + try + { + // unrelated types + method = ReflectionUtils.MapInterfaceMethodToImplementationIfNecessary((MethodInfo) MethodInfo.GetCurrentMethod(), typeof(MapsInterfaceMethodClass)); + Assert.Fail(); + } + catch (ArgumentException ex) + { + Assert.AreEqual("methodInfo and implementingType are unrelated", ex.Message); + } + + method = ReflectionUtils.MapInterfaceMethodToImplementationIfNecessary(typeof(MapsInterfaceMethodClass).GetMethod("SomeMethodA"), typeof(MapsInterfaceMethodClass)); + Assert.AreSame(instance.MethodAInfo, method); + method = ReflectionUtils.MapInterfaceMethodToImplementationIfNecessary(typeof(IMapsInterfaceMethodInterface).GetMethod("SomeMethodA"), typeof(MapsInterfaceMethodClass)); + Assert.AreSame(instance.MethodAInfo, method); + method = ReflectionUtils.MapInterfaceMethodToImplementationIfNecessary(typeof(IMapsInterfaceMethodInterface).GetMethod("SomeMethodB"), typeof(MapsInterfaceMethodClass)); + Assert.AreSame(instance.MethodBInfo, method); + method = ReflectionUtils.MapInterfaceMethodToImplementationIfNecessary(typeof(IMapsInterfaceMethodInterface).GetProperty("SomeProperty").GetGetMethod(), typeof(MapsInterfaceMethodClass)); + Assert.AreSame(instance.PropGetterInfo, method); + } + + #region Helper class for http: //jira.springframework.org/browse/SPRNET-992 tests + + public class Foo + { + public readonly string a = ""; + public readonly int b = -1; + public readonly char c = '0'; + + public Foo(string a, int b, char c) + { + this.a = a; + this.b = b; + this.c = c; + } + + public Foo(string a) + { + this.a = a; + } + + public Foo() + { + } + + public void MethodWithNullableIntegerArg(int? nullableInteger) { } } #endregion + + [Test(Description = "http://jira.springframework.org/browse/SPRNET-992")] + public void ShouldPickDefaultConstructorWithoutArgs() + { + object[] args = new object[] { }; + ConstructorInfo best = ReflectionUtils.GetConstructorByArgumentValues(typeof(Foo).GetConstructors(), null); + Foo foo = (Foo) best.Invoke(args); + + Assert.AreEqual("", foo.a); + Assert.AreEqual(-1, foo.b); + Assert.AreEqual('0', foo.c); + } + + [Test(Description = "http://jira.springframework.org/browse/SPRNET-992")] + public void ShouldPickDefaultConstructor() + { + object[] args = new object[] { }; + ConstructorInfo best = ReflectionUtils.GetConstructorByArgumentValues(typeof(Foo).GetConstructors(), args); + Foo foo = (Foo) best.Invoke(args); + + Assert.AreEqual("", foo.a); + Assert.AreEqual(-1, foo.b); + Assert.AreEqual('0', foo.c); + } + + [Test(Description = "http://jira.springframework.org/browse/SPRNET-992")] + public void ShouldPickSingleArgConstructor() + { + object[] args = new object[] { "b" }; + ConstructorInfo best = ReflectionUtils.GetConstructorByArgumentValues(typeof(Foo).GetConstructors(), args); + Foo foo = (Foo) best.Invoke(args); + + Assert.AreEqual("b", foo.a); + Assert.AreEqual(-1, foo.b); + Assert.AreEqual('0', foo.c); + } + + [Test] + public void GetParameterTypes() + { + Type[] expectedParameterTypes = new Type[] { typeof(string) }; + MethodInfo method = typeof(ReflectionUtilsObject).GetMethod("BadSpanglish"); + Type[] parameterTypes = ReflectionUtils.GetParameterTypes(method); + Assert.IsTrue(ArrayUtils.AreEqual(expectedParameterTypes, parameterTypes)); + } + + [Test] + public void GetParameterTypesWithNullMethodInfo() + { + Assert.Throws(() => ReflectionUtils.GetParameterTypes((MethodInfo) null)); + } + + [Test] + public void GetParameterTypesWithNullParametersArgs() + { + Assert.Throws(() => ReflectionUtils.GetParameterTypes((ParameterInfo[]) null)); + } + + [Test] + public void GetMatchingMethodsWithNullTypeToFindOn() + { + Assert.Throws(() => ReflectionUtils.GetMatchingMethods(null, new MethodInfo[] { }, true)); + } + + [Test] + public void GetMatchingMethodsWithNullMethodsToFind() + { + Assert.Throws(() => ReflectionUtils.GetMatchingMethods(GetType(), null, true)); + } + + [Test] + public void GetMatchingMethodsWithPerfectMatch() + { + MethodInfo[] clonesMethods = typeof(ReflectionUtilsObjectClone).GetMethods(BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance); + MethodInfo[] foundMethods = ReflectionUtils.GetMatchingMethods(typeof(ReflectionUtilsObject), clonesMethods, true); + Assert.AreEqual(clonesMethods.Length, foundMethods.Length); + } + + [Test] + public void GetMatchingMethodsWithBadMatchStrict() + { + // lets include a protected method that ain't declared on the ReflectionUtilsObject class... + MethodInfo[] clonesMethods = typeof(ReflectionUtilsObjectClone).GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly | BindingFlags.Instance); + Assert.Throws(() => ReflectionUtils.GetMatchingMethods(typeof(ReflectionUtilsObject), clonesMethods, true)); + } + + [Test] + public void GetMatchingMethodsWithBadMatchNotStrict() + { + // lets include a protected method that ain't declared on the ReflectionUtilsObject class... + MethodInfo[] clonesMethods = typeof(ReflectionUtilsObjectClone).GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly | BindingFlags.Instance); + MethodInfo[] foundMethods = ReflectionUtils.GetMatchingMethods(typeof(ReflectionUtilsObject), clonesMethods, false); + // obviously is not strict, 'cos we got here without throwing an exception... + Assert.AreEqual(clonesMethods.Length, foundMethods.Length); + } + + [Test] + public void GetMatchingMethodsWithBadReturnTypeMatchStrict() + { + // lets include a method that return type is different... + MethodInfo[] clonesMethods = typeof(ReflectionUtilsObjectBadClone).GetMethods(BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance); + Assert.Throws(() => ReflectionUtils.GetMatchingMethods(typeof(ReflectionUtilsObject), clonesMethods, true)); + } + + [Test] + public void GetMatchingMethodsWithBadReturnTypeMatchNotStrict() + { + // lets include a method that return type is different... + MethodInfo[] clonesMethods = typeof(ReflectionUtilsObjectBadClone).GetMethods(BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance); + MethodInfo[] foundMethods = ReflectionUtils.GetMatchingMethods(typeof(ReflectionUtilsObject), clonesMethods, false); + // obviously is not strict, 'cos we got here without throwing an exception... + Assert.AreEqual(clonesMethods.Length, foundMethods.Length); + } + + [Test] + public void ParameterTypesMatch() + { + MethodInfo method = typeof(ReflectionUtilsObject).GetMethod("Spanglish"); + Type[] types = new Type[] { typeof(string), typeof(object[]) }; + Assert.IsTrue(ReflectionUtils.ParameterTypesMatch(method, types)); + } + + [Test] + public void ParameterTypesDontMatchWithNonMatchingArgs() + { + Type[] types = new Type[] { typeof(string), typeof(object[]) }; + + MethodInfo method = typeof(ReflectionUtilsObject).GetMethod("BadSpanglish"); + Assert.IsFalse(ReflectionUtils.ParameterTypesMatch(method, types)); + method = typeof(ReflectionUtilsObject).GetMethod("WickedSpanglish"); + Assert.IsFalse(ReflectionUtils.ParameterTypesMatch(method, types)); + } + + [Test] + public void GetDefaultValue() + { + Assert.IsNull(ReflectionUtils.GetDefaultValue(GetType())); + Assert.AreEqual(Cuts.Superficial, ReflectionUtils.GetDefaultValue(typeof(Cuts))); + Assert.AreEqual(false, ReflectionUtils.GetDefaultValue(typeof(bool))); + Assert.AreEqual(DateTime.MinValue, ReflectionUtils.GetDefaultValue(typeof(DateTime))); + Assert.AreEqual(Char.MinValue, ReflectionUtils.GetDefaultValue(typeof(char))); + Assert.AreEqual(0, ReflectionUtils.GetDefaultValue(typeof(long))); + Assert.AreEqual(0, ReflectionUtils.GetDefaultValue(typeof(int))); + Assert.AreEqual(0, ReflectionUtils.GetDefaultValue(typeof(short))); + } + + [Test] + public void PropertyIsIndexer() + { + Assert.IsTrue(ReflectionUtils.PropertyIsIndexer("Item", typeof(TestObject))); + Assert.IsFalse(ReflectionUtils.PropertyIsIndexer("Item", typeof(SideEffectObject))); + Assert.IsFalse(ReflectionUtils.PropertyIsIndexer("Count", typeof(SideEffectObject))); + Assert.IsTrue(ReflectionUtils.PropertyIsIndexer("MyItem", typeof(ObjectWithNonDefaultIndexerName))); + } + + [Test] + public void MethodIsOnOneOfTheseInterfaces() + { + MethodInfo method = typeof(ReflectionUtilsObject).GetMethod("Spanglish"); + Assert.IsTrue(ReflectionUtils.MethodIsOnOneOfTheseInterfaces(method, new Type[] { typeof(IFoo) })); + } + + [Test] + public void MethodIsOnOneOfTheseInterfacesWithNonInterfaceType() + { + MethodInfo method = typeof(ReflectionUtilsObject).GetMethod("Spanglish"); + Assert.Throws(() => ReflectionUtils.MethodIsOnOneOfTheseInterfaces(method, new Type[] { GetType() })); + } + + [Test] + public void MethodIsOnOneOfTheseInterfacesWithNullMethod() + { + MethodInfo method = null; + Assert.Throws(() => ReflectionUtils.MethodIsOnOneOfTheseInterfaces(method, new Type[] { GetType() })); + } + + [Test] + public void MethodIsOnOneOfTheseInterfacesWithNullTypes() + { + MethodInfo method = typeof(ReflectionUtilsObject).GetMethod("Spanglish"); + Assert.IsFalse(ReflectionUtils.MethodIsOnOneOfTheseInterfaces(method, null)); + } + + [Test] + public void MethodIsOnOneOfTheseInterfacesMultiple() + { + MethodInfo method = typeof(RequiredTestObject).GetMethod("set_ObjectFactory"); + Assert.IsNotNull(method, "Could not get setter property for ObjectFactory"); + Assert.IsTrue(ReflectionUtils.MethodIsOnOneOfTheseInterfaces(method, new Type[] { typeof(IObjectNameAware), typeof(IObjectFactoryAware) })); + } + + [Test] + public void ParameterTypesMatchWithNullArgs() + { + Assert.Throws(() => ReflectionUtils.ParameterTypesMatch(null, null)); + } + + [Test] + public void GetSignature() + { + MethodInfo method = typeof(ReflectionUtilsObject).GetMethod("Spanglish"); + ArrayList list = new ArrayList(); + foreach (ParameterInfo p in method.GetParameters()) + { + list.Add(p.ParameterType); + } + + string expected = "Spring.Util.ReflectionUtilsObject::Spanglish(System.String,System.Object[])"; + Type[] pTypes = (Type[]) list.ToArray(typeof(Type)); + string actual = ReflectionUtils.GetSignature(method.DeclaringType, method.Name, pTypes); + Assert.AreEqual(expected, actual); + } + + [Test] + public void ToInterfaceArrayFromType() + { + Type[] expected = new Type[] { typeof(IFoo), typeof(IBar) }; + IList actual = ReflectionUtils.ToInterfaceArray(typeof(IBar)); + Assert.AreEqual(expected.Length, actual.Count); + Assert.AreEqual(expected[0], actual[0]); + Assert.AreEqual(expected[1], actual[1]); + } + + [Test] + public void ToInterfaceArrayFromTypeWithNonInterface() + { + Assert.Throws(() => ReflectionUtils.ToInterfaceArray(typeof(ExplicitFoo))); + } + + [Test] + public void GetMethod() + { + MethodInfo actual = ReflectionUtils.GetMethod( + typeof(ReflectionUtilsObject), + "Spanglish", + new Type[] { typeof(string), typeof(object[]) }); + Assert.IsNotNull(actual); + } + + [Test] + public void GetMethodWithExplicitInterfaceMethod() + { + MethodInfo actual = ReflectionUtils.GetMethod( + typeof(ExplicitFoo), + "Spring.Util.IFoo.Spanglish", + new Type[] { typeof(string), typeof(object[]) }); + Assert.IsNotNull(actual); + } + + [Test] + public void GetMethodIsCaseInsensitive() + { + MethodInfo actual = ReflectionUtils.GetMethod( + typeof(ReflectionUtilsObject), + "spAngLISh", + new Type[] { typeof(string), typeof(object[]) }); + Assert.IsNotNull(actual, "ReflectionUtils.GetMethod would appear to be case sensitive."); + } + + [Test] + public void CreateCustomAttributeForNonAttributeType() + { + Assert.Throws(() => ReflectionUtils.CreateCustomAttribute(GetType()), "[Spring.Util.ReflectionUtilsTests] does not derive from the [System.Attribute] class."); + } + + [Test] + public void CreateCustomAttributeWithNullType() + { + Assert.Throws(() => ReflectionUtils.CreateCustomAttribute((Type) null)); + } + + [Test] + public void CreateCustomAttributeSunnyDayScenarios() + { + CustomAttributeBuilder builder = null; + + builder = ReflectionUtils.CreateCustomAttribute(typeof(MyCustomAttribute)); + Assert.IsNotNull(builder); + + builder = ReflectionUtils.CreateCustomAttribute(typeof(MyCustomAttribute), "Rick"); + Assert.IsNotNull(builder); + + builder = ReflectionUtils.CreateCustomAttribute(typeof(MyCustomAttribute), "Rick"); + Assert.IsNotNull(builder); + + builder = ReflectionUtils.CreateCustomAttribute(new MyCustomAttribute("Rick")); + Assert.IsNotNull(builder); + + builder = ReflectionUtils.CreateCustomAttribute(typeof(MyCustomAttribute), new MyCustomAttribute("Rick")); + Assert.IsNotNull(builder); + + builder = ReflectionUtils.CreateCustomAttribute(typeof(MyCustomAttribute), new object[] { "Rick" }, new MyCustomAttribute("Evans")); + Assert.IsNotNull(builder); + + // TODO : actually emit the attribute and check it... + } + +#if !NETCOREAPP + [Test] + public void CreatCustomAttriubtesFromCustomAttributeData() + { + Type control = typeof(System.Windows.Forms.Control); + MethodInfo mi = control.GetMethod("get_Font"); + System.Collections.Generic.IList attributes = CustomAttributeData.GetCustomAttributes(mi.ReturnParameter); + CustomAttributeBuilder builder = null; + foreach (CustomAttributeData customAttributeData in attributes) + { + builder = ReflectionUtils.CreateCustomAttribute(customAttributeData); + Assert.IsNotNull(builder); + } + } +#endif + + [Test] + public void CreatCustomAttriubtesFromCustomAttributeDataWithSingleEnum() + { + MethodInfo mi = typeof(TestClassHavingAttributeWithEnum).GetMethod("SomeMethod"); + System.Collections.Generic.IList attributes = CustomAttributeData.GetCustomAttributes(mi); + CustomAttributeBuilder builder = null; + foreach (CustomAttributeData customAttributeData in attributes) + { + builder = ReflectionUtils.CreateCustomAttribute(customAttributeData); + Assert.IsNotNull(builder); + } + } + + [Test] + public void CreatCustomAttriubtesFromCustomAttributeDataWithArrayOfEnumsSetOnProperty() + { + MethodInfo mi = typeof(TestClassHavingAttributeWithEnumArraySetOnProperty).GetMethod("SomeMethod"); + System.Collections.Generic.IList attributes = CustomAttributeData.GetCustomAttributes(mi); + CustomAttributeBuilder builder = null; + foreach (CustomAttributeData customAttributeData in attributes) + { + builder = ReflectionUtils.CreateCustomAttribute(customAttributeData); + Assert.IsNotNull(builder); + } + } + + [Test] + public void CreatCustomAttriubtesFromCustomAttributeDataWithArrayOfEnumsSetInConstructor() + { + MethodInfo mi = typeof(TestClassHavingAttributeWithEnumArraySetInConstructor).GetMethod("SomeMethod"); + System.Collections.Generic.IList attributes = CustomAttributeData.GetCustomAttributes(mi); + CustomAttributeBuilder builder = null; + foreach (CustomAttributeData customAttributeData in attributes) + { + builder = ReflectionUtils.CreateCustomAttribute(customAttributeData); + Assert.IsNotNull(builder); + } + } + + [Test] + public void CreatCustomAttriubtesFromCustomAttributeDataWithSimpleTypeSetInConstructor() + { + MethodInfo mi = typeof(TestClassHavingAttributeWithSimpleTypeSetInConstructor).GetMethod("SomeMethod"); + System.Collections.Generic.IList attributes = CustomAttributeData.GetCustomAttributes(mi); + CustomAttributeBuilder builder = null; + foreach (CustomAttributeData customAttributeData in attributes) + { + builder = ReflectionUtils.CreateCustomAttribute(customAttributeData); + Assert.IsNotNull(builder); + } + } + + [Test] + public void CreatCustomAttriubtesFromCustomAttributeDataWithGenericCollectionTypeSetInConstructor() + { + MethodInfo mi = typeof(TestClassHavingAttributeWithGenericCollectionTypeSetInConstructor).GetMethod("SomeMethod"); + System.Collections.Generic.IList attributes = CustomAttributeData.GetCustomAttributes(mi); + CustomAttributeBuilder builder = null; + foreach (CustomAttributeData customAttributeData in attributes) + { + builder = ReflectionUtils.CreateCustomAttribute(customAttributeData); + Assert.IsNotNull(builder); + } + } + + internal interface IHaveSomeMethod + { + void SomeMethod(); + } + + internal class TestClassHavingAttributeWithEnum : IHaveSomeMethod + { + [AttributeWithEnum(SomeProperty = TheTestEnumThing.One)] + public void SomeMethod() + { + } + } + + internal class TestClassHavingAttributeWithEnumArraySetInConstructor : IHaveSomeMethod + { + [AttributeWithEnumArraySetInConstructor(new TheTestEnumThing[] { TheTestEnumThing.One, TheTestEnumThing.Two })] + public void SomeMethod() + { + } + } + + internal class TestClassHavingAttributeWithSimpleTypeSetInConstructor : IHaveSomeMethod + { + [AttributeWithType(typeof(int))] + public void SomeMethod() + { + } + } + + internal class TestClassHavingAttributeWithGenericCollectionTypeSetInConstructor : IHaveSomeMethod + { + [AttributeWithType(typeof(System.Collections.Generic.List))] + public void SomeMethod() + { + } + } + + internal class TestClassHavingAttributeWithEnumArraySetOnProperty : IHaveSomeMethod + { + [AttributeWithEnumArray(SomeProperty = new TheTestEnumThing[] { TheTestEnumThing.One, TheTestEnumThing.Three })] + public void SomeMethod() + { + } + } + + internal enum TheTestEnumThing + { + One, Two, Three + } + + internal class AttributeWithTypeAttribute : Attribute + { + public AttributeWithTypeAttribute(Type T) + { + } + } + + internal class AttributeWithEnumArrayAttribute : Attribute + { + private TheTestEnumThing[] _someProperty; + + public TheTestEnumThing[] SomeProperty + { + get { return _someProperty; } + set + { + _someProperty = value; + } + } + } + + internal class AttributeWithEnumArraySetInConstructorAttribute : Attribute + { + /// + /// Initializes a new instance of the AttributeWithEnumArraySetInConstructorAttribute class. + /// + public AttributeWithEnumArraySetInConstructorAttribute(TheTestEnumThing[] things) + { + } + } + + class AttributeWithEnumAttribute : Attribute + { + private TheTestEnumThing _someProperty; + + public TheTestEnumThing SomeProperty + { + get { return _someProperty; } + set + { + _someProperty = value; + } + } + } + +#if !NETCOREAPP + [Test] + public void CreateCustomAttributeUsingDefaultValuesForTheConstructor() + { + CustomAttributeBuilder builder = null; + builder = ReflectionUtils.CreateCustomAttribute(typeof(AnotherCustomAttribute)); + Assert.IsNotNull(builder); + + AnotherCustomAttribute att + = (AnotherCustomAttribute)CheckForPresenceOfCustomAttribute(builder, typeof(AnotherCustomAttribute)); + Assert.IsNull(att.Name); + Assert.AreEqual(0, att.Age); + Assert.IsFalse(att.HasSwallowedExplosives); + } + + [Test] + public void CreateCustomAttributeFromSourceAttribute() + { + CustomAttributeBuilder builder = null; + AnotherCustomAttribute source = new AnotherCustomAttribute("Rick", 30, true); + builder = ReflectionUtils.CreateCustomAttribute(source); + Assert.IsNotNull(builder); + + AnotherCustomAttribute att + = (AnotherCustomAttribute)CheckForPresenceOfCustomAttribute(builder, typeof(AnotherCustomAttribute)); + Assert.AreEqual(source.Name, att.Name); + Assert.AreEqual(source.Age, att.Age); + Assert.AreEqual(source.HasSwallowedExplosives, att.HasSwallowedExplosives); + } + + [Test] + public void CreateCustomAttributeUsingExplicitValuesForTheConstructor() + { + CustomAttributeBuilder builder = null; + const string expectedName = "Rick"; + const int expectedAge = 30; + builder = ReflectionUtils.CreateCustomAttribute(typeof(AnotherCustomAttribute), new object[] + { + expectedName, expectedAge, true + }); + Assert.IsNotNull(builder); + + AnotherCustomAttribute att + = (AnotherCustomAttribute)CheckForPresenceOfCustomAttribute(builder, typeof(AnotherCustomAttribute)); + Assert.AreEqual(expectedName, att.Name); + Assert.AreEqual(expectedAge, att.Age); + Assert.IsTrue(att.HasSwallowedExplosives); + } + + [Test] + public void CreateCustomAttributeUsingExplicitValuesForTheConstructorAndASourceAttribute() + { + CustomAttributeBuilder builder = null; + const string expectedName = "Rick"; + const int expectedAge = 30; + AnotherCustomAttribute source = new AnotherCustomAttribute(expectedName, expectedAge, false); + builder = ReflectionUtils.CreateCustomAttribute(typeof(AnotherCustomAttribute), new object[] + { + "Hoop", 2, true + }, source); + Assert.IsNotNull(builder); + + AnotherCustomAttribute att + = (AnotherCustomAttribute)CheckForPresenceOfCustomAttribute(builder, typeof(AnotherCustomAttribute)); + Assert.AreEqual(expectedName, att.Name); + Assert.AreEqual(expectedAge, att.Age); + Assert.IsFalse(att.HasSwallowedExplosives); + } +#endif + + [Test] + public void HasAtLeastOneMethodWithName() + { + Type testType = typeof(ExtendedReflectionUtilsObject); + // declared method... + Assert.IsTrue(ReflectionUtils.HasAtLeastOneMethodWithName(testType, "Declared")); + // case insensitive method... + Assert.IsTrue(ReflectionUtils.HasAtLeastOneMethodWithName(testType, "deCLAReD")); + // superclass method... + Assert.IsTrue(ReflectionUtils.HasAtLeastOneMethodWithName(testType, "Spanglish")); + // static method... + Assert.IsTrue(ReflectionUtils.HasAtLeastOneMethodWithName(testType, "Static")); + // protected method... + Assert.IsTrue(ReflectionUtils.HasAtLeastOneMethodWithName(testType, "Protected")); + // non existent method... + Assert.IsFalse(ReflectionUtils.HasAtLeastOneMethodWithName(testType, "Sponglish")); + // null type... + Assert.IsFalse(ReflectionUtils.HasAtLeastOneMethodWithName(null, "Spanglish")); + // null method name... + Assert.IsFalse(ReflectionUtils.HasAtLeastOneMethodWithName(testType, null)); + // empty method name... + Assert.IsFalse(ReflectionUtils.HasAtLeastOneMethodWithName(testType, "")); + // all nulls... + Assert.IsFalse(ReflectionUtils.HasAtLeastOneMethodWithName(null, null)); + } + + [Test] + public void GetTypeOfOrTypeWithNull() + { + Assert.Throws(() => ReflectionUtils.TypeOfOrType(null)); + } + + [Test] + public void GetTypeOfOrType() + { + Assert.AreEqual(typeof(string), ReflectionUtils.TypeOfOrType(typeof(string))); + } + + [Test] + public void GetTypeOfOrTypeWithNonNullType() + { + Assert.AreEqual(typeof(string), ReflectionUtils.TypeOfOrType(string.Empty)); + } + + [Test] + public void GetTypes() + { + Type[] actual = ReflectionUtils.GetTypes( + new object[] { 1, "I've never been to Taco Bell (sighs).", new ReflectionUtilsObject() }); + Type[] expected = new Type[] { typeof(int), typeof(string), typeof(ReflectionUtilsObject), }; + Assert.IsTrue(ArrayUtils.AreEqual(expected, actual), "The ReflectionUtils.GetTypes method did not return a correct Type [] array. Yep, that's as helpful as it gets."); + } + + [Test] + public void GetTypesWithEmptyArrayArgument() + { + Type[] actual = ReflectionUtils.GetTypes(new object[] { }); + Assert.IsNotNull(actual, "The ReflectionUtils.GetTypes method returned null when given an empty array. Must return an empty Type [] array."); + Assert.IsTrue(actual.Length == 0, "The ReflectionUtils.GetTypes method returned a Type [] that had some elements in it when given an empty array. Must return an empty Type [] array."); + } + + [Test] + public void GetTypesWithNullArrayArgument() + { + Type[] actual = ReflectionUtils.GetTypes(null); + Assert.IsNotNull(actual, "The ReflectionUtils.GetTypes method returned null when given null. Must return an empty Type [] array."); + Assert.IsTrue(actual.Length == 0, "The ReflectionUtils.GetTypes method returned a Type [] that had some elements in it when given null. Must return an empty Type [] array."); + } + + [Test] + public void GetDefaultValueWithZeroValueEnumType() + { + Assert.Throws(() => ReflectionUtils.GetDefaultValue(typeof(EnumWithNoValues))); + } + + [Test] + public void GetParameterTypesWithMethodThatHasRefParameters() + { + MethodInfo method = GetType().GetMethod("Add"); + Type[] types = ReflectionUtils.GetParameterTypes(method); + Assert.IsNotNull(types); + Assert.AreEqual(2, types.Length); + // first method parameter is byRef, so type name must end in '&' + Assert.AreEqual("System.Int32&", types[0].FullName); + Assert.AreEqual("System.Int32", types[1].FullName); + } + + [Test] + public void GetMethodByArgumentValuesCanResolveWhenAmbiguousMatchIsOnlyDifferentiatedByParams() + { + GetMethodByArgumentValuesTarget.DummyArgumentType[] typedArg = new GetMethodByArgumentValuesTarget.DummyArgumentType[] { }; + GetMethodByArgumentValuesTarget foo = new GetMethodByArgumentValuesTarget(1, typedArg); + + Type type = typeof(GetMethodByArgumentValuesTarget); + MethodInfo[] candidateMethods = new MethodInfo[] { type.GetMethod("ParamOverloadedMethod", new Type[] { typeof(string), typeof(string), typeof(string) }), type.GetMethod("ParamOverloadedMethod", new Type[] { typeof(string), typeof(string), typeof(bool) }), type.GetMethod("ParamOverloadedMethod", new Type[] { typeof(string), typeof(string), typeof(string), typeof(string), typeof(object[]) }) }; + + // ensure no one changed our test class + Assert.IsNotNull(candidateMethods[0]); + Assert.IsNotNull(candidateMethods[1]); + Assert.IsNotNull(candidateMethods[2]); + Assert.AreEqual("ThreeStringsOverload", foo.ParamOverloadedMethod(string.Empty, string.Empty, string.Empty)); + Assert.AreEqual("TwoStringsAndABoolOverload", foo.ParamOverloadedMethod(string.Empty, string.Empty, default(bool))); + Assert.AreEqual("FourStringsAndAParamsCollectionOverload", foo.ParamOverloadedMethod(string.Empty, string.Empty, string.Empty, string.Empty, typedArg)); + + MethodInfo resolvedMethod = ReflectionUtils.GetMethodByArgumentValues(candidateMethods, new object[] { string.Empty, string.Empty, string.Empty, string.Empty, typedArg }); + Assert.AreSame(candidateMethods[2], resolvedMethod); + } + + [Test] + public void GetMethodByArgumentValuesResolvesToExactMatchIfAvailable() + { + GetMethodByArgumentValuesTarget.DummyArgumentType[] typedArg = new GetMethodByArgumentValuesTarget.DummyArgumentType[] { }; + GetMethodByArgumentValuesTarget foo = new GetMethodByArgumentValuesTarget(1, typedArg); + + Type type = typeof(GetMethodByArgumentValuesTarget); + MethodInfo[] candidateMethods = new MethodInfo[] { type.GetMethod("MethodWithSimilarArguments", new Type[] { typeof(int), typeof(ICollection) }), type.GetMethod("MethodWithSimilarArguments", new Type[] { typeof(int), typeof(GetMethodByArgumentValuesTarget.DummyArgumentType[]) }), type.GetMethod("MethodWithSimilarArguments", new Type[] { typeof(int), typeof(object[]) }) }; + + // ensure no one changed our test class + Assert.IsNotNull(candidateMethods[0]); + Assert.IsNotNull(candidateMethods[1]); + Assert.IsNotNull(candidateMethods[2]); + Assert.AreEqual("ParamArrayMatch", foo.MethodWithSimilarArguments(1, new object())); + Assert.AreEqual("ExactMatch", foo.MethodWithSimilarArguments(1, typedArg)); + Assert.AreEqual("AssignableMatch", foo.MethodWithSimilarArguments(1, (ICollection) typedArg)); + + MethodInfo resolvedMethod = ReflectionUtils.GetMethodByArgumentValues(candidateMethods, new object[] { 1, typedArg }); + Assert.AreSame(candidateMethods[1], resolvedMethod); + } + + [Test] + public void GetMethodByArgumentValuesMatchesNullableArgs() + { + GetMethodByArgumentValuesTarget.DummyArgumentType[] typedArg = new GetMethodByArgumentValuesTarget.DummyArgumentType[] { }; + GetMethodByArgumentValuesTarget foo = new GetMethodByArgumentValuesTarget(1, typedArg); + + Type type = typeof(GetMethodByArgumentValuesTarget); + MethodInfo[] candidateMethods = new MethodInfo[] { type.GetMethod("MethodWithSimilarArguments", new Type[] { typeof(int), typeof(ICollection) }), type.GetMethod("MethodWithSimilarArguments", new Type[] { typeof(int), typeof(GetMethodByArgumentValuesTarget.DummyArgumentType[]) }), type.GetMethod("MethodWithSimilarArguments", new Type[] { typeof(int), typeof(object[]) }), type.GetMethod("MethodWithNullableArgument", new Type[] { typeof(int?) }) }; + + // ensure no one changed our test class + Assert.IsNotNull(candidateMethods[0]); + Assert.IsNotNull(candidateMethods[1]); + Assert.IsNotNull(candidateMethods[2]); + Assert.IsNotNull(candidateMethods[3]); + Assert.AreEqual("ParamArrayMatch", foo.MethodWithSimilarArguments(1, new object())); + Assert.AreEqual("ExactMatch", foo.MethodWithSimilarArguments(1, typedArg)); + Assert.AreEqual("AssignableMatch", foo.MethodWithSimilarArguments(1, (ICollection) typedArg)); + Assert.AreEqual("NullableArgumentMatch", foo.MethodWithNullableArgument(null)); + + MethodInfo resolvedMethod = ReflectionUtils.GetMethodByArgumentValues(candidateMethods, new object[] { null }); + Assert.AreSame(candidateMethods[3], resolvedMethod); + } + + [Test] + public void GetConstructorByArgumentValuesResolvesToExactMatchIfAvailable() + { + GetMethodByArgumentValuesTarget.DummyArgumentType[] typedArg = new GetMethodByArgumentValuesTarget.DummyArgumentType[] { }; + Type type = typeof(GetMethodByArgumentValuesTarget); + ConstructorInfo[] candidateConstructors = new ConstructorInfo[] { type.GetConstructor(new Type[] { typeof(int), typeof(ICollection) }), type.GetConstructor(new Type[] { typeof(int), typeof(GetMethodByArgumentValuesTarget.DummyArgumentType[]) }), type.GetConstructor(new Type[] { typeof(int), typeof(object[]) }) }; + + // ensure noone changed our test class + Assert.IsNotNull(candidateConstructors[0]); + Assert.IsNotNull(candidateConstructors[1]); + Assert.IsNotNull(candidateConstructors[2]); + Assert.AreEqual("ParamArrayMatch", new GetMethodByArgumentValuesTarget(1, new object()).SelectedConstructor); + Assert.AreEqual("ExactMatch", new GetMethodByArgumentValuesTarget(1, typedArg).SelectedConstructor); + Assert.AreEqual("AssignableMatch", new GetMethodByArgumentValuesTarget(1, (ICollection) typedArg).SelectedConstructor); + + ConstructorInfo resolvedConstructor = ReflectionUtils.GetConstructorByArgumentValues(candidateConstructors, new object[] { 1, typedArg }); + Assert.AreSame(candidateConstructors[1], resolvedConstructor); + } + + #region GetInterfaces + + [Test] + public void GetInterfaces() + { + Assert.AreEqual( + typeof(TestObject).GetInterfaces().Length, + ReflectionUtils.GetInterfaces(typeof(TestObject)).Length); + + Assert.AreEqual(1, ReflectionUtils.GetInterfaces(typeof(IInterface1)).Length); + Assert.AreEqual(4, ReflectionUtils.GetInterfaces(typeof(IInterface2)).Length); + } + + public interface IInterface1 + { + } + + public interface IInterface2 : IInterface3 + { + } + + public interface IInterface3 : IInterface4, IInterface5 + { + } + + public interface IInterface4 + { + } + + public interface IInterface5 + { + } + + #endregion + + #region IsTypeVisible Tests + + [Test] + public void IsTypeVisibleWithInternalType() + { + Type type = typeof(InternalType); + Assert.IsFalse(ReflectionUtils.IsTypeVisible(type)); + } + + [Test] + public void IsTypeVisibleWithPublicNestedTypeOnInternalType() + { + Type type = typeof(InternalType.PublicNestedType); + Assert.IsFalse(ReflectionUtils.IsTypeVisible(type)); + } + + [Test] + public void IsTypeVisibleWithInternalNestedTypeOnInternalType() + { + Type type = typeof(InternalType.InternalNestedType); + Assert.IsFalse(ReflectionUtils.IsTypeVisible(type)); + } + + [Test] + public void IsTypeVisibleWithProtectedInternalNestedTypeOnInternalType() + { + Type type = typeof(InternalType.ProtectedInternalNestedType); + Assert.IsFalse(ReflectionUtils.IsTypeVisible(type)); + } + + [Test] + public void IsTypeVisibleWithProtectedNestedTypeOnInternalType() + { + Type type = typeof(InternalType).GetNestedType("ProtectedNestedType", BindingFlags.NonPublic); + Assert.IsFalse(ReflectionUtils.IsTypeVisible(type)); + } + + [Test] + public void IsTypeVisibleWithPrivateNestedTypeOnInternalType() + { + Type type = typeof(InternalType).GetNestedType("PrivateNestedType", BindingFlags.NonPublic); + Assert.IsFalse(ReflectionUtils.IsTypeVisible(type)); + } + + [Test] + public void IsTypeVisibleWithPublicType() + { + Type type = typeof(PublicType); + Assert.IsTrue(ReflectionUtils.IsTypeVisible(type)); + } + + [Test] + public void IsTypeVisibleWithPublicNestedTypeOnPublicType() + { + Type type = typeof(PublicType.PublicNestedType); + Assert.IsTrue(ReflectionUtils.IsTypeVisible(type)); + } + + [Test] + public void IsTypeVisibleWithInternalNestedTypeOnPublicType() + { + Type type = typeof(PublicType.InternalNestedType); + Assert.IsFalse(ReflectionUtils.IsTypeVisible(type)); + } + + [Test] + public void IsTypeVisibleWithProtectedInternalNestedTypeOnPublicType() + { + Type type = typeof(PublicType.ProtectedInternalNestedType); + Assert.IsFalse(ReflectionUtils.IsTypeVisible(type)); + } + + [Test] + public void IsTypeVisibleWithProtectedNestedTypeOnPublicType() + { + Type type = typeof(PublicType).GetNestedType("ProtectedNestedType", BindingFlags.NonPublic); + Assert.IsFalse(ReflectionUtils.IsTypeVisible(type)); + } + + [Test] + public void IsTypeVisibleWithPrivateNestedTypeOnPublicType() + { + Type type = typeof(PublicType).GetNestedType("PrivateNestedType", BindingFlags.NonPublic); + Assert.IsFalse(ReflectionUtils.IsTypeVisible(type)); + } + + private static readonly string FRIENDLY_ASSEMBLY_NAME = "ReflectionUtils.IsTypeVisible.AssemblyTestName"; + + [Test] + public void IsTypeVisibleFromFriendlyAssemblyWithInternalType() + { + Type type = typeof(InternalType); + Assert.IsTrue(ReflectionUtils.IsTypeVisible(type, FRIENDLY_ASSEMBLY_NAME)); + } + + [Test] + public void IsTypeVisibleFromFriendlyAssemblyWithPublicNestedTypeOnInternalType() + { + Type type = typeof(InternalType.PublicNestedType); + Assert.IsTrue(ReflectionUtils.IsTypeVisible(type, FRIENDLY_ASSEMBLY_NAME)); + } + + [Test] + public void IsTypeVisibleFromFriendlyAssemblyWithInternalNestedTypeOnInternalType() + { + Type type = typeof(InternalType.InternalNestedType); + Assert.IsTrue(ReflectionUtils.IsTypeVisible(type, FRIENDLY_ASSEMBLY_NAME)); + } + + [Test] + public void IsTypeVisibleFromFriendlyAssemblyWithProtectedInternalNestedTypeOnInternalType() + { + Type type = typeof(InternalType.ProtectedInternalNestedType); + Assert.IsTrue(ReflectionUtils.IsTypeVisible(type, FRIENDLY_ASSEMBLY_NAME)); + } + + [Test] + public void IsTypeVisibleFromFriendlyAssemblyWithProtectedNestedTypeOnInternalType() + { + Type type = typeof(InternalType).GetNestedType("ProtectedNestedType", BindingFlags.NonPublic); + Assert.IsFalse(ReflectionUtils.IsTypeVisible(type, FRIENDLY_ASSEMBLY_NAME)); + } + + [Test] + public void IsTypeVisibleFromFriendlyAssemblyWithPrivateNestedTypeOnInternalType() + { + Type type = typeof(InternalType).GetNestedType("PrivateNestedType", BindingFlags.NonPublic); + Assert.IsFalse(ReflectionUtils.IsTypeVisible(type, FRIENDLY_ASSEMBLY_NAME)); + } + + [Test] + public void IsTypeVisibleFromFriendlyAssemblyWithPublicType() + { + Type type = typeof(PublicType); + Assert.IsTrue(ReflectionUtils.IsTypeVisible(type, FRIENDLY_ASSEMBLY_NAME)); + } + + [Test] + public void IsTypeVisibleFromFriendlyAssemblyWithPublicNestedTypeOnPublicType() + { + Type type = typeof(PublicType.PublicNestedType); + Assert.IsTrue(ReflectionUtils.IsTypeVisible(type, FRIENDLY_ASSEMBLY_NAME)); + } + + [Test] + public void IsTypeVisibleFromFriendlyAssemblyWithInternalNestedTypeOnPublicType() + { + Type type = typeof(PublicType.InternalNestedType); + Assert.IsTrue(ReflectionUtils.IsTypeVisible(type, FRIENDLY_ASSEMBLY_NAME)); + } + + [Test] + public void IsTypeVisibleFromFriendlyAssemblyWithProtectedInternalNestedTypeOnPublicType() + { + Type type = typeof(PublicType.ProtectedInternalNestedType); + Assert.IsTrue(ReflectionUtils.IsTypeVisible(type, FRIENDLY_ASSEMBLY_NAME)); + } + + [Test] + public void IsTypeVisibleFromFriendlyAssemblyWithProtectedNestedTypeOnPublicType() + { + Type type = typeof(PublicType).GetNestedType("ProtectedNestedType", BindingFlags.NonPublic); + Assert.IsFalse(ReflectionUtils.IsTypeVisible(type, FRIENDLY_ASSEMBLY_NAME)); + } + + [Test] + public void IsTypeVisibleFromFriendlyAssemblyWithPrivateNestedTypeOnPublicType() + { + Type type = typeof(PublicType).GetNestedType("PrivateNestedType", BindingFlags.NonPublic); + Assert.IsFalse(ReflectionUtils.IsTypeVisible(type, FRIENDLY_ASSEMBLY_NAME)); + } + + [Test] + public void IsTypeNullable_WhenTrue() + { + Type type = typeof(int?); + Assert.That(ReflectionUtils.IsNullableType(type), Is.True); + } + + [Test] + public void IsTypeNullable_WhenFalse() + { + Type type = typeof(int); + Assert.That(ReflectionUtils.IsNullableType(type), Is.False); + } + + [Test] + public void GetCustomAttributesOnType() + { + IList attrs = ReflectionUtils.GetCustomAttributes(typeof(ClassWithAttributes)); + +#if NETCOREAPP + Assert.AreEqual(1, attrs.Count); +#else + Assert.AreEqual(2, attrs.Count); +#endif + } + + [Test] + public void GetCustomAttributesOnMethod() + { + IList attrs = ReflectionUtils.GetCustomAttributes(typeof(ClassWithAttributes).GetMethod("MethodWithAttributes")); + +#if NETCOREAPP + Assert.AreEqual(1, attrs.Count); +#else + Assert.AreEqual(2, attrs.Count); +#endif + } + + #endregion + + #region GetExplicitBaseException + + [Test] + public void GetExplicitBaseExceptionWithNoInnerException() + { + Exception appEx = new ApplicationException(); + Exception ex = ReflectionUtils.GetExplicitBaseException(appEx); + + Assert.AreEqual(ex, appEx); + } + + [Test] + public void GetExplicitBaseExceptionWithInnerException() + { + Exception dbzEx = new DivideByZeroException(); + Exception appEx = new ApplicationException("Test message", dbzEx); + Exception ex = ReflectionUtils.GetExplicitBaseException(appEx); + + Assert.AreEqual(ex, dbzEx); + } + + [Test] + public void GetExplicitBaseExceptionWithInnerExceptions() + { + Exception dbzEx = new DivideByZeroException(); + Exception sEx = new SystemException("Test message", dbzEx); + Exception appEx = new ApplicationException("Test message", sEx); + Exception ex = ReflectionUtils.GetExplicitBaseException(appEx); + + Assert.AreEqual(ex, dbzEx); + } + + [Test] + public void GetExplicitBaseExceptionWithNullReferenceExceptionAsRootException() + { + Exception nrEx = new NullReferenceException(); + Exception appEx = new ApplicationException("Test message", nrEx); + Exception ex = ReflectionUtils.GetExplicitBaseException(appEx); + + Assert.AreEqual(ex, appEx); + } + + [Test] + public void CanGetFriendlyNamesForGenericTypes() + { + Type t = typeof(System.Collections.Generic.List>); + + Assert.AreEqual("System.Collections.Generic.List>", ReflectionUtils.GetTypeFriendlyName(t)); + } + + #endregion + + #region Helper Methods + + public int Add(ref int one, int two) + { + return one + two; + } + +#if !NETCOREAPP + private Attribute CheckForPresenceOfCustomAttribute( + CustomAttributeBuilder attBuilder, Type attType) + { + Attribute[] atts = ApplyAndGetCustomAttributes(attBuilder); + Assert.IsNotNull(atts); + Assert.IsTrue(atts.Length == 1); + Attribute att = atts[0]; + Assert.IsNotNull(att); + Assert.AreEqual(attType, att.GetType(), "Wrong Attribute applied to the class."); + return att; + } + + private static Attribute[] ApplyAndGetCustomAttributes(CustomAttributeBuilder attBuilder) + { + Type type = BuildTypeWithThisCustomAttribute(attBuilder); + object[] attributes = type.GetCustomAttributes(true); + return (Attribute[])ArrayList.Adapter(attributes).ToArray(typeof(Attribute)); + } + + private static Type BuildTypeWithThisCustomAttribute(CustomAttributeBuilder attBuilder) + { + AssemblyName assemblyName = new AssemblyName(); + assemblyName.Name = "AnAssembly"; + AssemblyBuilder asmBuilder = System.Threading.Thread.GetDomain().DefineDynamicAssembly( + assemblyName, AssemblyBuilderAccess.Run); + ModuleBuilder modBuilder = asmBuilder.DefineDynamicModule("AModule"); + TypeBuilder classBuilder = modBuilder.DefineType("AClass", TypeAttributes.Public); + classBuilder.SetCustomAttribute(attBuilder); + return classBuilder.CreateType(); + } +#endif + + #endregion } + +#region Simple Helper Classes + +public class PublicType +{ + public class PublicNestedType + { + } + + internal class InternalNestedType + { + } + + protected internal class ProtectedInternalNestedType + { + } + + protected class ProtectedNestedType + { + } + + private class PrivateNestedType + { + } +} + +internal class InternalType +{ + public class PublicNestedType + { + } + + internal class InternalNestedType + { + } + + protected internal class ProtectedInternalNestedType + { + } + + protected class ProtectedNestedType + { + } + + private class PrivateNestedType + { + } +} + +internal enum EnumWithNoValues { } + +internal enum Cuts +{ + Superficial, + Deep, + Severing +} + +internal interface IBar : IFoo +{ +} + +internal interface IFoo +{ + bool Spanglish(string foo, object[] args); +} + +internal sealed class ExplicitFoo : IFoo +{ + bool IFoo.Spanglish(string foo, object[] args) + { + return false; + } +} + +internal class ReflectionUtilsObject : IComparable +{ + public bool Spanglish(string foo, object[] args) + { + return false; + } + + public bool BadSpanglish(string foo) + { + return false; + } + + public bool WickedSpanglish(string foo, string bar) + { + return false; + } + + /// + /// Explicit interface implementation for ReflectionUtils.GetMethod tests + /// + /// + /// + int IComparable.CompareTo(object obj) + { + return 0; + } +} + +internal sealed class ExtendedReflectionUtilsObject : ReflectionUtilsObject +{ + public void Declared(string name) + { + } + + public void Protected() + { + } + + public static void Static() + { + } +} + +/// +/// Exposes methods with the same names as the ReflectionUtilsObject, used in +/// the tests for the GetMatchingMethods method. +/// +internal class ReflectionUtilsObjectClone +{ + public bool Spanglish(string foo, object[] args) + { + return false; + } + + public bool BadSpanglish(string foo) + { + return false; + } + + public bool WickedSpanglish(string foo, string bar) + { + return false; + } + + protected void Bingo() + { + } +} + +/// +/// Exposes methods with the same names as the ReflectionUtilsObject, used in +/// the tests for the GetMatchingMethods method. +/// +internal class ReflectionUtilsObjectBadClone +{ + public bool Spanglish(string foo, object[] args) + { + return false; + } + + public string BadSpanglish(string foo) + { + return foo; + } + + public bool WickedSpanglish(string foo, string bar) + { + return false; + } +} + +internal class GetMethodByArgumentValuesTarget +{ + public class DummyArgumentType + { + } + + public string SelectedConstructor; + + public GetMethodByArgumentValuesTarget(int flag, params object[] values) + { + SelectedConstructor = "ParamArrayMatch"; + } + + public GetMethodByArgumentValuesTarget(int flag, DummyArgumentType[] bars) + { + SelectedConstructor = "ExactMatch"; + } + + public GetMethodByArgumentValuesTarget(int flag, ICollection bars) + { + SelectedConstructor = "AssignableMatch"; + } + + public string MethodWithSimilarArguments(int flags, params object[] args) + { + return "ParamArrayMatch"; + } + + public string MethodWithSimilarArguments(int flags, DummyArgumentType[] bars) + { + return "ExactMatch"; + } + + public string MethodWithSimilarArguments(int flags, ICollection bar) + { + return "AssignableMatch"; + } + + public string MethodWithNullableArgument(int? nullableInteger) + { + return "NullableArgumentMatch"; + } + + public string ParamOverloadedMethod(string s1, string s2, string s3) + { + return "ThreeStringsOverload"; + } + + public string ParamOverloadedMethod(string s1, string s2, bool b1) + { + return "TwoStringsAndABoolOverload"; + } + + public string ParamOverloadedMethod(string s1, string s2, string s3, string s4, params object[] args) + { + return "FourStringsAndAParamsCollectionOverload"; + } +} + +public sealed class MyCustomAttribute : Attribute +{ + public MyCustomAttribute() + { + } + + public MyCustomAttribute(string name) + { + _name = name; + } + + public string Name + { + get { return _name; } + } + + private string _name; +} + +/// +/// Used for testing that default values are supplied for the ctor args. +/// +public sealed class AnotherCustomAttribute : Attribute +{ + public AnotherCustomAttribute(string name, int age, bool hasSwallowedExplosives) + { + _name = name; + _age = age; + _hasSwallowedExplosives = hasSwallowedExplosives; + } + + public string Name + { + get { return _name; } + set { _name = value; } + } + + public int Age + { + get { return _age; } + set { _age = value; } + } + + public bool HasSwallowedExplosives + { + get { return _hasSwallowedExplosives; } + set { _hasSwallowedExplosives = value; } + } + + private string _name; + private int _age; + private bool _hasSwallowedExplosives; +} + +public sealed class ObjectWithNonDefaultIndexerName +{ + private string[] favoriteQuotes = new string[10]; + + [IndexerName("MyItem")] + public string this[int index] + { + get + { + if (index < 0 || index >= favoriteQuotes.Length) + { + throw new ArgumentException("Index out of range"); + } + + return favoriteQuotes[index]; + } + + set + { + if (index < 0 || index >= favoriteQuotes.Length) + { + throw new ArgumentException("index is out of range."); + } + + favoriteQuotes[index] = value; + } + } +} + +[MyCustom] +[System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand)] +public sealed class ClassWithAttributes +{ + [MyCustom] + [System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand)] + public void MethodWithAttributes() + { + } +} + +#endregion diff --git a/test/Spring/Spring.Core.Tests/Util/SerializationTestUtils.cs b/test/Spring/Spring.Core.Tests/Util/SerializationTestUtils.cs index 6db8674c..89af6e8f 100644 --- a/test/Spring/Spring.Core.Tests/Util/SerializationTestUtils.cs +++ b/test/Spring/Spring.Core.Tests/Util/SerializationTestUtils.cs @@ -2,13 +2,13 @@ /* * Copyright 2002-2010 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. @@ -23,85 +23,83 @@ using System.Runtime.Serialization.Formatters.Binary; using NUnit.Framework; using Spring.Objects; -namespace Spring.Util +namespace Spring.Util; + +/// +/// Utilities for testing serializability of objects. +/// +/// +/// Exposes static methods for use in other test cases. +/// +/// Rod Johnson +/// Simon White (.NET) +[TestFixture] +public sealed class SerializationTestUtils { - /// - /// Utilities for testing serializability of objects. - /// - /// - /// Exposes static methods for use in other test cases. - /// - /// Rod Johnson - /// Simon White (.NET) - [TestFixture] - public sealed class SerializationTestUtils - { - [Test] - public void WithNonSerializableObject() - { - TestObject o = new TestObject(); - Assert.IsFalse(o is ISerializable); - Assert.IsFalse(IsSerializable(o)); - Assert.Throws(() => TrySerialization(o)); - } + [Test] + public void WithNonSerializableObject() + { + TestObject o = new TestObject(); + Assert.IsFalse(o is ISerializable); + Assert.IsFalse(IsSerializable(o)); + Assert.Throws(() => TrySerialization(o)); + } - [Test] - public void WithSerializableObject() - { - IPerson p = new SerializablePerson(); - p.Age = 12; - Assert.IsTrue(p is ISerializable); - TrySerialization(p); - Assert.IsTrue(IsSerializable(p)); - IPerson p2 = (IPerson) SerializeAndDeserialize(p); - Assert.IsTrue(p != p2); - Assert.AreEqual(12, p2.Age); - } + [Test] + public void WithSerializableObject() + { + IPerson p = new SerializablePerson(); + p.Age = 12; + Assert.IsTrue(p is ISerializable); + TrySerialization(p); + Assert.IsTrue(IsSerializable(p)); + IPerson p2 = (IPerson) SerializeAndDeserialize(p); + Assert.IsTrue(p != p2); + Assert.AreEqual(12, p2.Age); + } - /// - /// Attempts to serialize the specified object to an in-memory stream. - /// - /// the object to serialize - public static void TrySerialization(object o) - { - using (Stream stream = new MemoryStream()) - { - BinaryFormatter bformatter = new BinaryFormatter(); - bformatter.Serialize(stream, o); - } - } + /// + /// Attempts to serialize the specified object to an in-memory stream. + /// + /// the object to serialize + public static void TrySerialization(object o) + { + using (Stream stream = new MemoryStream()) + { + BinaryFormatter bformatter = new BinaryFormatter(); + bformatter.Serialize(stream, o); + } + } - /// - /// Tests whether the specified object is serializable. - /// - /// the object to test. - /// true if the object is serializable, otherwise false. - public static bool IsSerializable(object o) - { + /// + /// Tests whether the specified object is serializable. + /// + /// the object to test. + /// true if the object is serializable, otherwise false. + public static bool IsSerializable(object o) + { #pragma warning disable SYSLIB0050 // Type or member is obsolete - return o == null ? true : o.GetType().IsSerializable; + return o == null ? true : o.GetType().IsSerializable; #pragma warning restore SYSLIB0050 - } + } - /// - /// Serializes the specified object to an in-memory stream, and returns - /// the result of deserializing the object stream. - /// - /// the object to use. - /// the deserialized object. - public static object SerializeAndDeserialize(object o) - { - using (Stream stream = new MemoryStream()) - { - BinaryFormatter bformatter = new BinaryFormatter(); - bformatter.Serialize(stream, o); - stream.Flush(); + /// + /// Serializes the specified object to an in-memory stream, and returns + /// the result of deserializing the object stream. + /// + /// the object to use. + /// the deserialized object. + public static object SerializeAndDeserialize(object o) + { + using (Stream stream = new MemoryStream()) + { + BinaryFormatter bformatter = new BinaryFormatter(); + bformatter.Serialize(stream, o); + stream.Flush(); - stream.Seek(0, SeekOrigin.Begin); - object o2 = bformatter.Deserialize(stream); - return o2; - } - } - - } + stream.Seek(0, SeekOrigin.Begin); + object o2 = bformatter.Deserialize(stream); + return o2; + } + } } diff --git a/test/Spring/Spring.Core.Tests/Util/StringUtilsTests.cs b/test/Spring/Spring.Core.Tests/Util/StringUtilsTests.cs index ce37863e..15eb1467 100644 --- a/test/Spring/Spring.Core.Tests/Util/StringUtilsTests.cs +++ b/test/Spring/Spring.Core.Tests/Util/StringUtilsTests.cs @@ -24,433 +24,432 @@ using NUnit.Framework; #endregion -namespace Spring.Util +namespace Spring.Util; + +/// +/// Unit tests for the StringUtils class. +/// +/// Aleksandar Seovic +/// Rick Evans +/// Griffin Caprio +[TestFixture] +public sealed class StringUtilsTests { - /// - /// Unit tests for the StringUtils class. - /// - /// Aleksandar Seovic - /// Rick Evans - /// Griffin Caprio - [TestFixture] - public sealed class StringUtilsTests - { - [Test] - public void SplitTests() - { - string testString = " a,b,, c ,d\n:e "; - string delim = ",\n"; - string[] res; - string[] res1 = new string[] {" a", "b", "", " c ", "d", ":e "}; - string[] res2 = new string[] {" a", "b", " c ", "d", ":e "}; - string[] res3 = new string[] {"a", "b", "", "c", "d", ":e"}; - string[] res4 = new string[] {"a", "b", "c", "d", ":e"}; + [Test] + public void SplitTests() + { + string testString = " a,b,, c ,d\n:e "; + string delim = ",\n"; + string[] res; + string[] res1 = new string[] { " a", "b", "", " c ", "d", ":e " }; + string[] res2 = new string[] { " a", "b", " c ", "d", ":e " }; + string[] res3 = new string[] { "a", "b", "", "c", "d", ":e" }; + string[] res4 = new string[] { "a", "b", "c", "d", ":e" }; - Assert.AreEqual(0, StringUtils.Split(null, null, false, false).Length); - Assert.AreEqual(testString, StringUtils.Split(testString, null, false, false)[0]); - Assert.IsTrue(ArrayUtils.AreEqual(res1, res = StringUtils.Split(testString, delim, false, false)), "Received '" + String.Join(",", res) + "'"); - Assert.IsTrue(ArrayUtils.AreEqual(res2, res = StringUtils.Split(testString, delim, false, true)), "Received '" + String.Join(",", res) + "'"); - Assert.IsTrue(ArrayUtils.AreEqual(res3, res = StringUtils.Split(testString, delim, true, false)), "Received '" + String.Join(",", res) + "'"); - Assert.IsTrue(ArrayUtils.AreEqual(res4, res = StringUtils.Split(testString, delim, true, true)), "Received '" + String.Join(",", res) + "'"); + Assert.AreEqual(0, StringUtils.Split(null, null, false, false).Length); + Assert.AreEqual(testString, StringUtils.Split(testString, null, false, false)[0]); + Assert.IsTrue(ArrayUtils.AreEqual(res1, res = StringUtils.Split(testString, delim, false, false)), "Received '" + String.Join(",", res) + "'"); + Assert.IsTrue(ArrayUtils.AreEqual(res2, res = StringUtils.Split(testString, delim, false, true)), "Received '" + String.Join(",", res) + "'"); + Assert.IsTrue(ArrayUtils.AreEqual(res3, res = StringUtils.Split(testString, delim, true, false)), "Received '" + String.Join(",", res) + "'"); + Assert.IsTrue(ArrayUtils.AreEqual(res4, res = StringUtils.Split(testString, delim, true, true)), "Received '" + String.Join(",", res) + "'"); - Assert.IsTrue(ArrayUtils.AreEqual(new string[] {"one"}, res = StringUtils.Split("one", delim, true, true)), "Received '" + String.Join(",", res) + "'"); - } + Assert.IsTrue(ArrayUtils.AreEqual(new string[] { "one" }, res = StringUtils.Split("one", delim, true, true)), "Received '" + String.Join(",", res) + "'"); + } - [Test] - public void SplitWithQuotedStrings() + [Test] + public void SplitWithQuotedStrings() + { + string[] expectedParts = new string[] { "a", "[test,<,>>[]]]", "asdf<,<,>,>aa" }; + string testString = string.Join(",", expectedParts); + string[] result = StringUtils.Split(testString, ",", false, false, "[]<>"); + Assert.AreEqual(expectedParts, result); + } + + [Test] + public void SplitAddsEmptyStrings() + { + string testString = ","; + string[] result = StringUtils.Split(testString, ",", true, false, null); + Assert.AreEqual(new string[] { "", "" }, result); + } + + [Test] + public void SplitAcceptsWhitespaceDelimiters() + { + string testString = "a\nb\tc d"; + string[] result = StringUtils.Split(testString, "\n\t ", true, false, null); + Assert.AreEqual(new string[] { "a", "b", "c", "d" }, result); + } + + [Test] + public void HasLengthTests() + { + Assert.IsFalse(StringUtils.HasLength(null)); + Assert.IsFalse(StringUtils.HasLength("")); + Assert.IsTrue(StringUtils.HasLength(" ")); + Assert.IsTrue(StringUtils.HasLength("Hello")); + } + + [Test] + public void HasTextTests() + { + Assert.IsFalse(StringUtils.HasText(null)); + Assert.IsFalse(StringUtils.HasText("")); + Assert.IsFalse(StringUtils.HasText(" ")); + Assert.IsTrue(StringUtils.HasText("12345")); + Assert.IsTrue(StringUtils.HasText(" 12345 ")); + } + + [Test] + public void IsNullOrEmptyTests() + { + Assert.IsTrue(StringUtils.IsNullOrEmpty(null)); + Assert.IsTrue(StringUtils.IsNullOrEmpty("")); + Assert.IsTrue(StringUtils.IsNullOrEmpty(" ")); + Assert.IsFalse(StringUtils.IsNullOrEmpty("12345")); + Assert.IsFalse(StringUtils.IsNullOrEmpty(" 12345 ")); + } + + [Test] + public void CollectionToDelimitedString() + { + Foo[] arr = new Foo[] { new Foo("Foo"), new Foo("Bar") }; + Assert.AreEqual( + ":Foo,:Bar", StringUtils.CollectionToCommaDelimitedString(arr)); + + Assert.AreEqual("null", StringUtils.CollectionToCommaDelimitedString(null)); + } + + [Test] + public void ArrayToDelimitedString() + { + Foo[] arr = new Foo[] { new Foo("Foo"), new Foo("Bar") }; + Assert.AreEqual( + ":Foo,:Bar", StringUtils.CollectionToCommaDelimitedString(arr)); + Assert.AreEqual("null", StringUtils.CollectionToCommaDelimitedString(null)); + } + + [Test] + public void DelimitedListToStringArray() + { + string[] expected = new string[] { "Foo", "", "Bar" }; + string input = "Foo,,Bar"; + string[] actual = StringUtils.DelimitedListToStringArray(input, ","); + Assert.IsNotNull(actual); + Assert.AreEqual(expected.Length, actual.Length); + for (int i = 0; i < actual.Length; ++i) { - string[] expectedParts = new string[] { "a", "[test,<,>>[]]]", "asdf<,<,>,>aa" }; - string testString = string.Join(",", expectedParts); - string[] result = StringUtils.Split(testString, ",", false, false, "[]<>"); - Assert.AreEqual( expectedParts, result ); + Assert.AreEqual(expected[i], actual[i]); + } + } + + [Test] + public void DelimitedListToStringArrayWithEmptyStringDelimiter() + { + string input = "Foo,,Bar"; + string[] expected = new string[] { input }; + string[] actual = StringUtils.DelimitedListToStringArray(input, string.Empty); + Assert.IsNotNull(actual); + Assert.AreEqual(expected.Length, actual.Length); + for (int i = 0; i < actual.Length; ++i) + { + Assert.AreEqual(expected[i], actual[i]); + } + } + + [Test] + public void DelimitedListToStringArrayWithGuff() + { + string[] expected = new string[] { }; + string[] actual = StringUtils.DelimitedListToStringArray(null, null); + Assert.IsNotNull(actual); + Assert.AreEqual(expected.Length, actual.Length); + + string aString = "HungerHurtsButStarvingWorks..."; + expected = new string[] { aString }; + actual = StringUtils.DelimitedListToStringArray(aString, null); + Assert.IsNotNull(actual); + Assert.AreEqual(expected.Length, actual.Length); + Assert.AreEqual(aString, actual[0]); + } + + [Test] + public void StripFirstAndLastCharacterWithNull() + { + string actual = StringUtils.StripFirstAndLastCharacter(null); + Assert.IsNotNull(actual, "StringUtils.StripFirstAndLastCharacter(null) should return String.Empty."); + Assert.AreEqual(String.Empty, actual, "StringUtils.StripFirstAndLastCharacter(null) should return String.Empty."); + } + + [Test] + public void StripFirstAndLastCharacterWithEmptyString() + { + string actual = StringUtils.StripFirstAndLastCharacter(String.Empty); + Assert.IsNotNull(actual, "StringUtils.StripFirstAndLastCharacter(String.Empty) should return String.Empty."); + Assert.AreEqual(String.Empty, actual, "StringUtils.StripFirstAndLastCharacter(String.Empty) should return String.Empty."); + } + + [Test] + public void StripFirstAndLastCharacterWithReallyShortStrings() + { + string actual = StringUtils.StripFirstAndLastCharacter("B"); + Assert.IsNotNull(actual, "StringUtils.StripFirstAndLastCharacter(\"B\") should return String.Empty."); + Assert.AreEqual(String.Empty, actual, "StringUtils.StripFirstAndLastCharacter(\"B\") should return String.Empty."); + + actual = StringUtils.StripFirstAndLastCharacter("BF"); + Assert.IsNotNull(actual, "StringUtils.StripFirstAndLastCharacter(\"BF\") should return String.Empty."); + Assert.AreEqual(String.Empty, actual, "StringUtils.StripFirstAndLastCharacter(\"BF\") should return String.Empty."); + } + + [Test] + public void StripFirstAndLastCharacterWorksLikeACharm() + { + string actual = StringUtils.StripFirstAndLastCharacter("There are 17 steps to winding up a bird chronicle correctly"); + Assert.IsNotNull(actual); + Assert.AreEqual("here are 17 steps to winding up a bird chronicle correctl", actual); + } + + [Test] + public void GetAntExpressionsWithNull() + { + IList actual = StringUtils.GetAntExpressions(null); + Assert.IsNotNull(actual); + string[] expected = new string[] { }; + Assert.IsTrue(ArrayUtils.AreEqual(expected, new List(actual).ToArray())); + } + + [Test] + public void GetAntExpressionsWithEmptyString() + { + IList actual = StringUtils.GetAntExpressions(String.Empty); + Assert.IsNotNull(actual); + string[] expected = new string[] { }; + Assert.IsTrue(ArrayUtils.AreEqual(expected, new List(actual).ToArray())); + } + + [Test] + public void GetAntExpressionsWithAStringThatDoesntHaveAnyExpressions() + { + IList actual = StringUtils.GetAntExpressions("I could really go a cup of tea right now... in fact I think I'll go get one."); + Assert.IsNotNull(actual); + string[] expected = new string[] { }; + Assert.IsTrue(ArrayUtils.AreEqual(expected, new List(actual).ToArray())); + } + + [Test] + public void GetAntExpressionsWithAValidExpression() + { + IList actual = StringUtils.GetAntExpressions("${slurp}. Ah! That is one good cup of tea. That agent Cooper and his coffee... he sure was missing out on a good thing."); + CheckGetAntExpressions(actual, "slurp"); + } + + [Test] + public void GetAntExpressionsWithANestedExpression() + { + IList actual = StringUtils.GetAntExpressions("And yeah, I've never been a fan of the doughnut... ${blechh${shudder}}"); + CheckGetAntExpressions(actual, "blechh${shudder"); + } + + [Test] + public void GetAntExpressionsWithACoupleOfDuplicatedValidExpressions() + { + IList actual = StringUtils.GetAntExpressions("${sigh}. Laura Palmer though... man, that sure was a tragedy. ${sigh}"); + CheckGetAntExpressions(actual, "sigh"); + } + + [Test] + public void GetAntExpressionsWithACoupleOfUniqueValidExpressions() + { + IList actual = StringUtils.GetAntExpressions("${Mmm}. Has there been any good telly since then... ${thinks}"); + CheckGetAntExpressions(actual, "Mmm", "thinks"); + } + + [Test] + public void GetAntExpressionsWithMalformedExpression() + { + IList actual = StringUtils.GetAntExpressions("Mmm... just what counts as ${a malformed{ expression?"); + CheckGetAntExpressions(actual, new string[] { }); + } + + private static void CheckGetAntExpressions(IList actual, params string[] expected) + { + Assert.IsNotNull(actual); + Assert.IsTrue(ArrayUtils.AreEqual( + expected, + new List(actual).ToArray())); + } + + [Test] + public void GetAntExpressionsIgnoresEmptyExpression() + { + Assert.Throws(() => StringUtils.GetAntExpressions("This is an empty expression ${}...")); + } + + [Test] + public void SetAntExpressionWithNullText() + { + string expected = String.Empty; + string actual = StringUtils.SetAntExpression(null, "foo", "bar"); + Assert.IsNotNull(actual); + Assert.AreEqual(expected, actual); + } + + [Test] + public void SetAntExpressionWithEmptyStringExpression() + { + string expected = String.Empty; + string actual = StringUtils.SetAntExpression(" ", "foo", "bar"); + Assert.IsNotNull(actual); + Assert.AreEqual(expected, actual); + } + + [Test] + public void SetAntExpressionWithMultipleEvaluations() + { + string expected = "Hey, do you want to hear the most annoying sound in the world? Mehhh! Mehhh!"; + string actual = StringUtils.SetAntExpression("Hey, do you want to hear the most annoying sound in the world? ${foo}! ${foo}!", "foo", "Mehhh"); + Assert.IsNotNull(actual); + Assert.AreEqual(expected, actual); + } + + [Test] + public void SetAntExpressionWithNullReplacementValue() + { + string expected = "That John Denver... he's full of ."; + string actual = StringUtils.SetAntExpression("That John Denver... he's full of ${bleep}.", "bleep", null); + Assert.IsNotNull(actual); + Assert.AreEqual(expected, actual); + } + + [Test] + public void FullSurroundWithNulls() + { + Assert.AreEqual("Hi", StringUtils.Surround(null, "Hi", null)); + } + + [Test] + public void FullSurroundWithEmptyStrings() + { + Assert.AreEqual("Hi", StringUtils.Surround(string.Empty, "Hi", string.Empty)); + } + + [Test] + public void FullSurround() + { + Assert.AreEqual("[Hi]", StringUtils.Surround("[", "Hi", "]")); + } + + [Test] + public void FullSurroundNullWithEmptyStrings() + { + Assert.AreEqual(string.Empty, StringUtils.Surround(string.Empty, null, string.Empty)); + } + + [Test] + public void FullSurroundEmptyStringWithEmptyStrings() + { + Assert.AreEqual(string.Empty, StringUtils.Surround(string.Empty, string.Empty, string.Empty)); + } + + [Test] + public void FullSurroundNullWithNulls() + { + Assert.AreEqual(string.Empty, StringUtils.Surround(null, null, null)); + } + + [Test] + public void SurroundWithEmptyStrings() + { + Assert.AreEqual("Hi", StringUtils.Surround(string.Empty, "Hi")); + } + + [Test] + public void Surround() + { + Assert.AreEqual("-Hi-", StringUtils.Surround("-", "Hi")); + } + + [Test] + public void SurroundNullWithEmptyStrings() + { + Assert.AreEqual(string.Empty, StringUtils.Surround(string.Empty, null)); + } + + [Test] + public void SurroundEmptyStringWithEmptyStrings() + { + Assert.AreEqual(string.Empty, StringUtils.Surround(string.Empty, string.Empty)); + } + + [Test] + public void SurroundNullWithNulls() + { + Assert.AreEqual(string.Empty, StringUtils.Surround(null, null)); + } + + [Test] + public void FullSurroundObjectWithNulls() + { + Assert.AreEqual(":Hi", StringUtils.Surround(null, new Foo("Hi"), null)); + } + + [Test] + public void FullSurroundObjectWithEmptyStrings() + { + Assert.AreEqual(":Hi", StringUtils.Surround(string.Empty, new Foo("Hi"), string.Empty)); + } + + [Test] + public void FullSurroundObject() + { + Assert.AreEqual("[:Hi]", StringUtils.Surround("[", new Foo("Hi"), "]")); + } + + [Test] + public void SurroundObjectWithEmptyStrings() + { + Assert.AreEqual(":Hi", StringUtils.Surround(string.Empty, new Foo("Hi"), string.Empty)); + } + + [Test] + public void SurroundObject() + { + Assert.AreEqual("[:Hi]", StringUtils.Surround("[", new Foo("Hi"), "]")); + } + + [Test] + public void ConvertEscapedCharactersNoEscapedCharacters() + { + string inputString = "foo bar is a funny term"; + Assert.AreEqual(inputString, StringUtils.ConvertEscapedCharacters(inputString)); + } + + [Test] + public void ConvertEscapedCharactersAll() + { + string inputString = "newline\\n tab\\t return\\r"; + Assert.AreEqual("newline\n tab\t return\r", StringUtils.ConvertEscapedCharacters(inputString)); + } + + [Test] + public void ConvertUnsupportedEscapedCharacters() + { + string inputString = "what is this\\g"; + Assert.AreEqual(inputString, StringUtils.ConvertEscapedCharacters(inputString)); + } + + private sealed class Foo + { + public Foo(string bar) + { + this.bar = bar; } - [Test] - public void SplitAddsEmptyStrings() + public override string ToString() { - string testString = ","; - string[] result = StringUtils.Split(testString, ",", true, false, null); - Assert.AreEqual( new string[] { "", "" }, result ); + return ":" + bar; } - [Test] - public void SplitAcceptsWhitespaceDelimiters() - { - string testString = "a\nb\tc d"; - string[] result = StringUtils.Split(testString, "\n\t ", true, false, null); - Assert.AreEqual( new string[] { "a", "b", "c", "d" }, result ); - } - - [Test] - public void HasLengthTests() - { - Assert.IsFalse(StringUtils.HasLength(null)); - Assert.IsFalse(StringUtils.HasLength("")); - Assert.IsTrue(StringUtils.HasLength(" ")); - Assert.IsTrue(StringUtils.HasLength("Hello")); - } - - [Test] - public void HasTextTests() - { - Assert.IsFalse(StringUtils.HasText(null)); - Assert.IsFalse(StringUtils.HasText("")); - Assert.IsFalse(StringUtils.HasText(" ")); - Assert.IsTrue(StringUtils.HasText("12345")); - Assert.IsTrue(StringUtils.HasText(" 12345 ")); - } - - [Test] - public void IsNullOrEmptyTests() - { - Assert.IsTrue(StringUtils.IsNullOrEmpty(null)); - Assert.IsTrue(StringUtils.IsNullOrEmpty("")); - Assert.IsTrue(StringUtils.IsNullOrEmpty(" ")); - Assert.IsFalse(StringUtils.IsNullOrEmpty("12345")); - Assert.IsFalse(StringUtils.IsNullOrEmpty(" 12345 ")); - } - - [Test] - public void CollectionToDelimitedString() - { - Foo[] arr = new Foo[] {new Foo("Foo"), new Foo("Bar")}; - Assert.AreEqual( - ":Foo,:Bar", StringUtils.CollectionToCommaDelimitedString(arr)); - - Assert.AreEqual("null", StringUtils.CollectionToCommaDelimitedString(null)); - } - - [Test] - public void ArrayToDelimitedString() - { - Foo[] arr = new Foo[] {new Foo("Foo"), new Foo("Bar")}; - Assert.AreEqual( - ":Foo,:Bar", StringUtils.CollectionToCommaDelimitedString(arr)); - Assert.AreEqual("null", StringUtils.CollectionToCommaDelimitedString(null)); - } - - [Test] - public void DelimitedListToStringArray() - { - string[] expected = new string[] {"Foo", "", "Bar"}; - string input = "Foo,,Bar"; - string[] actual = StringUtils.DelimitedListToStringArray(input, ","); - Assert.IsNotNull(actual); - Assert.AreEqual(expected.Length, actual.Length); - for (int i = 0; i < actual.Length; ++i) - { - Assert.AreEqual(expected[i], actual[i]); - } - } - - [Test] - public void DelimitedListToStringArrayWithEmptyStringDelimiter() - { - string input = "Foo,,Bar"; - string[] expected = new string[] {input}; - string[] actual = StringUtils.DelimitedListToStringArray(input, string.Empty); - Assert.IsNotNull(actual); - Assert.AreEqual(expected.Length, actual.Length); - for (int i = 0; i < actual.Length; ++i) - { - Assert.AreEqual(expected[i], actual[i]); - } - } - - [Test] - public void DelimitedListToStringArrayWithGuff() - { - string[] expected = new string[] {}; - string[] actual = StringUtils.DelimitedListToStringArray(null, null); - Assert.IsNotNull(actual); - Assert.AreEqual(expected.Length, actual.Length); - - string aString = "HungerHurtsButStarvingWorks..."; - expected = new string[] {aString}; - actual = StringUtils.DelimitedListToStringArray(aString, null); - Assert.IsNotNull(actual); - Assert.AreEqual(expected.Length, actual.Length); - Assert.AreEqual(aString, actual[0]); - } - - [Test] - public void StripFirstAndLastCharacterWithNull() - { - string actual = StringUtils.StripFirstAndLastCharacter(null); - Assert.IsNotNull(actual, "StringUtils.StripFirstAndLastCharacter(null) should return String.Empty."); - Assert.AreEqual(String.Empty, actual, "StringUtils.StripFirstAndLastCharacter(null) should return String.Empty."); - } - - [Test] - public void StripFirstAndLastCharacterWithEmptyString() - { - string actual = StringUtils.StripFirstAndLastCharacter(String.Empty); - Assert.IsNotNull(actual, "StringUtils.StripFirstAndLastCharacter(String.Empty) should return String.Empty."); - Assert.AreEqual(String.Empty, actual, "StringUtils.StripFirstAndLastCharacter(String.Empty) should return String.Empty."); - } - - [Test] - public void StripFirstAndLastCharacterWithReallyShortStrings() - { - string actual = StringUtils.StripFirstAndLastCharacter("B"); - Assert.IsNotNull(actual, "StringUtils.StripFirstAndLastCharacter(\"B\") should return String.Empty."); - Assert.AreEqual(String.Empty, actual, "StringUtils.StripFirstAndLastCharacter(\"B\") should return String.Empty."); - - actual = StringUtils.StripFirstAndLastCharacter("BF"); - Assert.IsNotNull(actual, "StringUtils.StripFirstAndLastCharacter(\"BF\") should return String.Empty."); - Assert.AreEqual(String.Empty, actual, "StringUtils.StripFirstAndLastCharacter(\"BF\") should return String.Empty."); - } - - [Test] - public void StripFirstAndLastCharacterWorksLikeACharm() - { - string actual = StringUtils.StripFirstAndLastCharacter("There are 17 steps to winding up a bird chronicle correctly"); - Assert.IsNotNull(actual); - Assert.AreEqual("here are 17 steps to winding up a bird chronicle correctl", actual); - } - - [Test] - public void GetAntExpressionsWithNull() - { - IList actual = StringUtils.GetAntExpressions(null); - Assert.IsNotNull(actual); - string[] expected = new string[] {}; - Assert.IsTrue(ArrayUtils.AreEqual(expected, new List(actual).ToArray())); - } - - [Test] - public void GetAntExpressionsWithEmptyString() - { - IList actual = StringUtils.GetAntExpressions(String.Empty); - Assert.IsNotNull(actual); - string[] expected = new string[] {}; - Assert.IsTrue(ArrayUtils.AreEqual(expected, new List(actual).ToArray())); - } - - [Test] - public void GetAntExpressionsWithAStringThatDoesntHaveAnyExpressions() - { - IList actual = StringUtils.GetAntExpressions("I could really go a cup of tea right now... in fact I think I'll go get one."); - Assert.IsNotNull(actual); - string[] expected = new string[] {}; - Assert.IsTrue(ArrayUtils.AreEqual(expected, new List(actual).ToArray())); - } - - [Test] - public void GetAntExpressionsWithAValidExpression() - { - IList actual = StringUtils.GetAntExpressions("${slurp}. Ah! That is one good cup of tea. That agent Cooper and his coffee... he sure was missing out on a good thing."); - CheckGetAntExpressions(actual, "slurp"); - } - - [Test] - public void GetAntExpressionsWithANestedExpression() - { - IList actual = StringUtils.GetAntExpressions("And yeah, I've never been a fan of the doughnut... ${blechh${shudder}}"); - CheckGetAntExpressions(actual, "blechh${shudder"); - } - - [Test] - public void GetAntExpressionsWithACoupleOfDuplicatedValidExpressions() - { - IList actual = StringUtils.GetAntExpressions("${sigh}. Laura Palmer though... man, that sure was a tragedy. ${sigh}"); - CheckGetAntExpressions(actual, "sigh"); - } - - [Test] - public void GetAntExpressionsWithACoupleOfUniqueValidExpressions() - { - IList actual = StringUtils.GetAntExpressions("${Mmm}. Has there been any good telly since then... ${thinks}"); - CheckGetAntExpressions(actual, "Mmm", "thinks"); - } - - [Test] - public void GetAntExpressionsWithMalformedExpression() - { - IList actual = StringUtils.GetAntExpressions("Mmm... just what counts as ${a malformed{ expression?"); - CheckGetAntExpressions(actual, new string[] {}); - } - - private static void CheckGetAntExpressions(IList actual, params string[] expected) - { - Assert.IsNotNull(actual); - Assert.IsTrue(ArrayUtils.AreEqual( - expected, - new List(actual).ToArray())); - } - - [Test] - public void GetAntExpressionsIgnoresEmptyExpression() - { - Assert.Throws(() => StringUtils.GetAntExpressions("This is an empty expression ${}...")); - } - - [Test] - public void SetAntExpressionWithNullText() - { - string expected = String.Empty; - string actual = StringUtils.SetAntExpression(null, "foo", "bar"); - Assert.IsNotNull(actual); - Assert.AreEqual(expected, actual); - } - - [Test] - public void SetAntExpressionWithEmptyStringExpression() - { - string expected = String.Empty; - string actual = StringUtils.SetAntExpression(" ", "foo", "bar"); - Assert.IsNotNull(actual); - Assert.AreEqual(expected, actual); - } - - [Test] - public void SetAntExpressionWithMultipleEvaluations() - { - string expected = "Hey, do you want to hear the most annoying sound in the world? Mehhh! Mehhh!"; - string actual = StringUtils.SetAntExpression("Hey, do you want to hear the most annoying sound in the world? ${foo}! ${foo}!", "foo", "Mehhh"); - Assert.IsNotNull(actual); - Assert.AreEqual(expected, actual); - } - - [Test] - public void SetAntExpressionWithNullReplacementValue() - { - string expected = "That John Denver... he's full of ."; - string actual = StringUtils.SetAntExpression("That John Denver... he's full of ${bleep}.", "bleep", null); - Assert.IsNotNull(actual); - Assert.AreEqual(expected, actual); - } - - [Test] - public void FullSurroundWithNulls() - { - Assert.AreEqual("Hi", StringUtils.Surround(null, "Hi", null)); - } - - [Test] - public void FullSurroundWithEmptyStrings() - { - Assert.AreEqual("Hi", StringUtils.Surround(string.Empty, "Hi", string.Empty)); - } - - [Test] - public void FullSurround() - { - Assert.AreEqual("[Hi]", StringUtils.Surround("[", "Hi", "]")); - } - - [Test] - public void FullSurroundNullWithEmptyStrings() - { - Assert.AreEqual(string.Empty, StringUtils.Surround(string.Empty, null, string.Empty)); - } - - [Test] - public void FullSurroundEmptyStringWithEmptyStrings() - { - Assert.AreEqual(string.Empty, StringUtils.Surround(string.Empty, string.Empty, string.Empty)); - } - - [Test] - public void FullSurroundNullWithNulls() - { - Assert.AreEqual(string.Empty, StringUtils.Surround(null, null, null)); - } - - [Test] - public void SurroundWithEmptyStrings() - { - Assert.AreEqual("Hi", StringUtils.Surround(string.Empty, "Hi")); - } - - [Test] - public void Surround() - { - Assert.AreEqual("-Hi-", StringUtils.Surround("-", "Hi")); - } - - [Test] - public void SurroundNullWithEmptyStrings() - { - Assert.AreEqual(string.Empty, StringUtils.Surround(string.Empty, null)); - } - - [Test] - public void SurroundEmptyStringWithEmptyStrings() - { - Assert.AreEqual(string.Empty, StringUtils.Surround(string.Empty, string.Empty)); - } - - [Test] - public void SurroundNullWithNulls() - { - Assert.AreEqual(string.Empty, StringUtils.Surround(null, null)); - } - - [Test] - public void FullSurroundObjectWithNulls() - { - Assert.AreEqual(":Hi", StringUtils.Surround(null, new Foo("Hi"), null)); - } - - [Test] - public void FullSurroundObjectWithEmptyStrings() - { - Assert.AreEqual(":Hi", StringUtils.Surround(string.Empty, new Foo("Hi"), string.Empty)); - } - - [Test] - public void FullSurroundObject() - { - Assert.AreEqual("[:Hi]", StringUtils.Surround("[", new Foo("Hi"), "]")); - } - - [Test] - public void SurroundObjectWithEmptyStrings() - { - Assert.AreEqual(":Hi", StringUtils.Surround(string.Empty, new Foo("Hi"), string.Empty)); - } - - [Test] - public void SurroundObject() - { - Assert.AreEqual("[:Hi]", StringUtils.Surround("[", new Foo("Hi"), "]")); - } - - [Test] - public void ConvertEscapedCharactersNoEscapedCharacters() - { - string inputString = "foo bar is a funny term"; - Assert.AreEqual(inputString, StringUtils.ConvertEscapedCharacters(inputString)); - } - - [Test] - public void ConvertEscapedCharactersAll() - { - string inputString = "newline\\n tab\\t return\\r"; - Assert.AreEqual("newline\n tab\t return\r", StringUtils.ConvertEscapedCharacters(inputString)); - } - - [Test] - public void ConvertUnsupportedEscapedCharacters() - { - string inputString = "what is this\\g"; - Assert.AreEqual(inputString, StringUtils.ConvertEscapedCharacters(inputString)); - } - - private sealed class Foo - { - public Foo(string bar) - { - this.bar = bar; - } - - public override string ToString() - { - return ":" + bar; - } - - private string bar; - } - } -} \ No newline at end of file + private string bar; + } +} diff --git a/test/Spring/Spring.Core.Tests/Util/SystemUtilsTests.cs b/test/Spring/Spring.Core.Tests/Util/SystemUtilsTests.cs index fdf81ab7..7ebad7cf 100644 --- a/test/Spring/Spring.Core.Tests/Util/SystemUtilsTests.cs +++ b/test/Spring/Spring.Core.Tests/Util/SystemUtilsTests.cs @@ -24,52 +24,48 @@ using NUnit.Framework; #endregion -namespace Spring.Util +namespace Spring.Util; + +/// +/// This class contains tests for SystemUtils +/// +/// Mark Pollack +[TestFixture] +public class SystemUtilsTests { - /// - /// This class contains tests for SystemUtils - /// - /// Mark Pollack - [TestFixture] - public class SystemUtilsTests + private static string threadName = "TestingThread"; + + [Test] + public void ThreadIdIsName() { - private static string threadName = "TestingThread"; + Thread t = new Thread(new ThreadStart(AssertThreadName)); + t.Name = threadName; + t.Start(); + t.Join(); + } + public void AssertThreadName() + { + Assert.AreEqual(threadName, SystemUtils.ThreadId); + } - [Test] - public void ThreadIdIsName() + [Test] + public void ThreadIdIsInt() + { + Thread t = new Thread(new ThreadStart(AssertThreadIsInt)); + t.Start(); + t.Join(); + } + + public void AssertThreadIsInt() + { + try { - Thread t = new Thread(new ThreadStart(AssertThreadName)); - t.Name = threadName; - t.Start(); - t.Join(); + int.Parse(SystemUtils.ThreadId); } - - - public void AssertThreadName() + catch (Exception) { - Assert.AreEqual(threadName, SystemUtils.ThreadId); - } - - [Test] - public void ThreadIdIsInt() - { - Thread t = new Thread(new ThreadStart(AssertThreadIsInt)); - t.Start(); - t.Join(); - - } - - public void AssertThreadIsInt() - { - try - { - int.Parse(SystemUtils.ThreadId); - } - catch (Exception) - { - Assert.Fail("ThreadId should be an integer"); - } + Assert.Fail("ThreadId should be an integer"); } } -} \ No newline at end of file +} diff --git a/test/Spring/Spring.Core.Tests/Util/UniqueKeyTests.cs b/test/Spring/Spring.Core.Tests/Util/UniqueKeyTests.cs index 1470c9d9..d2132342 100644 --- a/test/Spring/Spring.Core.Tests/Util/UniqueKeyTests.cs +++ b/test/Spring/Spring.Core.Tests/Util/UniqueKeyTests.cs @@ -24,81 +24,81 @@ using NUnit.Framework; #endregion -namespace Spring.Util +namespace Spring.Util; + +/// +/// Tests functionality. +/// +/// Erich Eichinger +[TestFixture] +public class UniqueKeyTests { - /// - /// Tests functionality. - /// - /// Erich Eichinger - [TestFixture] - public class UniqueKeyTests + private class TestObject { - private class TestObject - {} - - [Test] - public void MustNotCallObjectSignatureWithType() - { - Type myType = typeof(TestObject); - Assert.Throws(() => UniqueKey.GetInstanceScopedString( myType, "PartialKey")); - } - - [Test] - public void CreateTypeScopedKeyString() - { - string typeScopedKey = UniqueKey.GetTypeScopedString(typeof(TestObject), "PartialKey"); - string expectedKey = string.Format("{0}.{1}", typeof(TestObject).FullName, "PartialKey"); - Assert.AreEqual(expectedKey, typeScopedKey); - } - - [Test] - public void CreateTypeScopedKey() - { - UniqueKey typeScopedKey = UniqueKey.GetTypeScoped(typeof(TestObject), "PartialKey"); - UniqueKey expectedKey = UniqueKey.GetTypeScoped(typeof(TestObject), "PartialKey"); - - string expectedKeyString = string.Format("{0}.{1}", typeof(TestObject).FullName, "PartialKey"); - - // I know testing implementation details is not the best strategy, - // but I want to receive an error if this fails (oakinger) - Assert.AreEqual(expectedKeyString, expectedKey.ToString()); - Assert.AreEqual(expectedKeyString.GetHashCode(), expectedKey.GetHashCode()); - - // different instances... - Assert.AreNotSame(expectedKey, typeScopedKey); - // but equal - Assert.AreEqual(expectedKey, typeScopedKey); - Assert.AreEqual(expectedKey.GetHashCode(), typeScopedKey.GetHashCode()); - } - - [Test] - public void CreateInstanceScopedKeyString() - { - TestObject testObject = new TestObject(); - string typeScopedKey = UniqueKey.GetInstanceScopedString(testObject, "PartialKey"); - string expectedKey = string.Format("{0}[{1}].{2}", typeof(TestObject).FullName, testObject.GetHashCode(), "PartialKey"); - Assert.AreEqual(expectedKey, typeScopedKey); - } - - [Test] - public void CreateInstanceScopedKey() - { - TestObject testObject = new TestObject(); - UniqueKey instanceScopedKey = UniqueKey.GetInstanceScoped(testObject, "PartialKey"); - UniqueKey expectedKey = UniqueKey.GetInstanceScoped(testObject, "PartialKey"); - - string expectedKeyString = string.Format("{0}[{1}].{2}", typeof(TestObject).FullName, testObject.GetHashCode(), "PartialKey"); - - // I know testing implementation details is not the best strategy, - // but I want to receive an error if this fails (oakinger) - Assert.AreEqual(expectedKeyString, expectedKey.ToString()); - Assert.AreEqual(expectedKeyString.GetHashCode(), expectedKey.GetHashCode()); - - // different instances... - Assert.AreNotSame(expectedKey, instanceScopedKey); - // but equal - Assert.AreEqual(expectedKey, instanceScopedKey); - Assert.AreEqual(expectedKey.GetHashCode(), instanceScopedKey.GetHashCode()); - } } -} \ No newline at end of file + + [Test] + public void MustNotCallObjectSignatureWithType() + { + Type myType = typeof(TestObject); + Assert.Throws(() => UniqueKey.GetInstanceScopedString(myType, "PartialKey")); + } + + [Test] + public void CreateTypeScopedKeyString() + { + string typeScopedKey = UniqueKey.GetTypeScopedString(typeof(TestObject), "PartialKey"); + string expectedKey = string.Format("{0}.{1}", typeof(TestObject).FullName, "PartialKey"); + Assert.AreEqual(expectedKey, typeScopedKey); + } + + [Test] + public void CreateTypeScopedKey() + { + UniqueKey typeScopedKey = UniqueKey.GetTypeScoped(typeof(TestObject), "PartialKey"); + UniqueKey expectedKey = UniqueKey.GetTypeScoped(typeof(TestObject), "PartialKey"); + + string expectedKeyString = string.Format("{0}.{1}", typeof(TestObject).FullName, "PartialKey"); + + // I know testing implementation details is not the best strategy, + // but I want to receive an error if this fails (oakinger) + Assert.AreEqual(expectedKeyString, expectedKey.ToString()); + Assert.AreEqual(expectedKeyString.GetHashCode(), expectedKey.GetHashCode()); + + // different instances... + Assert.AreNotSame(expectedKey, typeScopedKey); + // but equal + Assert.AreEqual(expectedKey, typeScopedKey); + Assert.AreEqual(expectedKey.GetHashCode(), typeScopedKey.GetHashCode()); + } + + [Test] + public void CreateInstanceScopedKeyString() + { + TestObject testObject = new TestObject(); + string typeScopedKey = UniqueKey.GetInstanceScopedString(testObject, "PartialKey"); + string expectedKey = string.Format("{0}[{1}].{2}", typeof(TestObject).FullName, testObject.GetHashCode(), "PartialKey"); + Assert.AreEqual(expectedKey, typeScopedKey); + } + + [Test] + public void CreateInstanceScopedKey() + { + TestObject testObject = new TestObject(); + UniqueKey instanceScopedKey = UniqueKey.GetInstanceScoped(testObject, "PartialKey"); + UniqueKey expectedKey = UniqueKey.GetInstanceScoped(testObject, "PartialKey"); + + string expectedKeyString = string.Format("{0}[{1}].{2}", typeof(TestObject).FullName, testObject.GetHashCode(), "PartialKey"); + + // I know testing implementation details is not the best strategy, + // but I want to receive an error if this fails (oakinger) + Assert.AreEqual(expectedKeyString, expectedKey.ToString()); + Assert.AreEqual(expectedKeyString.GetHashCode(), expectedKey.GetHashCode()); + + // different instances... + Assert.AreNotSame(expectedKey, instanceScopedKey); + // but equal + Assert.AreEqual(expectedKey, instanceScopedKey); + Assert.AreEqual(expectedKey.GetHashCode(), instanceScopedKey.GetHashCode()); + } +} diff --git a/test/Spring/Spring.Core.Tests/Validation/Actions/ErrorMessageActionTests.cs b/test/Spring/Spring.Core.Tests/Validation/Actions/ErrorMessageActionTests.cs index 42f34bf9..2d631070 100644 --- a/test/Spring/Spring.Core.Tests/Validation/Actions/ErrorMessageActionTests.cs +++ b/test/Spring/Spring.Core.Tests/Validation/Actions/ErrorMessageActionTests.cs @@ -19,86 +19,83 @@ #endregion using NUnit.Framework; - using Spring.Context.Support; using Spring.Expressions; -namespace Spring.Validation.Actions +namespace Spring.Validation.Actions; + +/// +/// Unit tests for the ErrorMessageAction class. +/// +/// Aleksandar Seovic +[TestFixture] +public class ErrorMessageActionTests { - /// - /// Unit tests for the ErrorMessageAction class. - /// - /// Aleksandar Seovic - [TestFixture] - public class ErrorMessageActionTests + [Test] + public void WithNullMesageId() { - [Test] - public void WithNullMesageId() - { - Assert.Throws(() => new ErrorMessageAction(null, "errors")); - } - - [Test] - public void WithEmptyMesageId() - { - Assert.Throws(() => new ErrorMessageAction("", "errors")); - } - - [Test] - public void WithWhitespaceMesageId() - { - Assert.Throws(() => new ErrorMessageAction("\t ", "errors")); - } - - [Test] - public void WithNullProviders() - { - Assert.Throws(() => new ErrorMessageAction("error", null)); - } - - [Test] - public void WithEmptyProviders() - { - Assert.Throws(() => new ErrorMessageAction("error", new string[0])); - } - - [Test] - public void WhenValid() - { - Inventor context = new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian"); - IValidationErrors errors = new ValidationErrors(); - ErrorMessageAction action = new ErrorMessageAction("error", "errors"); - - action.Execute(true, context, null, errors); - Assert.IsTrue(errors.IsEmpty); - } - - [Test] - public void WhenInvalid() - { - Inventor context = new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian"); - IValidationErrors errors = new ValidationErrors(); - - ErrorMessageAction action = new ErrorMessageAction("{0}, {1}", "errors"); - action.Parameters = new IExpression[] {Expression.Parse("Name"), Expression.Parse("Nationality")}; - - action.Execute(false, context, null, errors); - Assert.IsFalse(errors.IsEmpty); - Assert.AreEqual(1, errors.GetErrors("errors").Count); - Assert.AreEqual(context.Name + ", " + context.Nationality, errors.GetResolvedErrors("errors", new NullMessageSource())[0]); - } - - [Test] - public void WhenActionIsNotExecutedBecauseWhenExpressionReturnsFalse() - { - Inventor context = new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian"); - IValidationErrors errors = new ValidationErrors(); - - ErrorMessageAction action = new ErrorMessageAction("{0}, {1}", "errors"); - action.When = Expression.Parse("false"); - action.Execute(false, context, null, errors); - Assert.IsTrue(errors.IsEmpty); - } - + Assert.Throws(() => new ErrorMessageAction(null, "errors")); } -} \ No newline at end of file + + [Test] + public void WithEmptyMesageId() + { + Assert.Throws(() => new ErrorMessageAction("", "errors")); + } + + [Test] + public void WithWhitespaceMesageId() + { + Assert.Throws(() => new ErrorMessageAction("\t ", "errors")); + } + + [Test] + public void WithNullProviders() + { + Assert.Throws(() => new ErrorMessageAction("error", null)); + } + + [Test] + public void WithEmptyProviders() + { + Assert.Throws(() => new ErrorMessageAction("error", new string[0])); + } + + [Test] + public void WhenValid() + { + Inventor context = new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian"); + IValidationErrors errors = new ValidationErrors(); + ErrorMessageAction action = new ErrorMessageAction("error", "errors"); + + action.Execute(true, context, null, errors); + Assert.IsTrue(errors.IsEmpty); + } + + [Test] + public void WhenInvalid() + { + Inventor context = new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian"); + IValidationErrors errors = new ValidationErrors(); + + ErrorMessageAction action = new ErrorMessageAction("{0}, {1}", "errors"); + action.Parameters = new IExpression[] { Expression.Parse("Name"), Expression.Parse("Nationality") }; + + action.Execute(false, context, null, errors); + Assert.IsFalse(errors.IsEmpty); + Assert.AreEqual(1, errors.GetErrors("errors").Count); + Assert.AreEqual(context.Name + ", " + context.Nationality, errors.GetResolvedErrors("errors", new NullMessageSource())[0]); + } + + [Test] + public void WhenActionIsNotExecutedBecauseWhenExpressionReturnsFalse() + { + Inventor context = new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian"); + IValidationErrors errors = new ValidationErrors(); + + ErrorMessageAction action = new ErrorMessageAction("{0}, {1}", "errors"); + action.When = Expression.Parse("false"); + action.Execute(false, context, null, errors); + Assert.IsTrue(errors.IsEmpty); + } +} diff --git a/test/Spring/Spring.Core.Tests/Validation/Actions/ExceptionActionTests.cs b/test/Spring/Spring.Core.Tests/Validation/Actions/ExceptionActionTests.cs index 5afae15c..5a97fedd 100644 --- a/test/Spring/Spring.Core.Tests/Validation/Actions/ExceptionActionTests.cs +++ b/test/Spring/Spring.Core.Tests/Validation/Actions/ExceptionActionTests.cs @@ -19,88 +19,82 @@ #endregion using NUnit.Framework; - using Spring.Expressions; -namespace Spring.Validation.Actions +namespace Spring.Validation.Actions; + +/// +/// Tests for the ExceptionAction class. +/// +/// Mark Pollack +[TestFixture] +public class ExceptionActionTests { - /// - /// Tests for the ExceptionAction class. - /// - /// Mark Pollack - [TestFixture] - public class ExceptionActionTests + [Test] + public void WhenInvalidThrowDefaultException() { - - [Test] - public void WhenInvalidThrowDefaultException() + Inventor context = new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian"); + Dictionary vars = new Dictionary(); + ExceptionAction action = new ExceptionAction(); + try { - Inventor context = new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian"); - Dictionary vars = new Dictionary(); - ExceptionAction action = new ExceptionAction(); - try - { - action.Execute(false, context, vars, null); - Assert.Fail("Should have thrown exception"); - } - catch (ValidationException) - { - - } + action.Execute(false, context, vars, null); + Assert.Fail("Should have thrown exception"); } - - [Test] - public void WhenInvalidThrowCustomException() + catch (ValidationException) { - Inventor context = new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian"); - Dictionary vars = new Dictionary(); - ExceptionAction action = new ExceptionAction("new System.InvalidOperationException('invalid')"); - try - { - action.Execute(false, context, vars, null); - Assert.Fail("Should have thrown exception"); - } - catch (InvalidOperationException e) - { - Assert.AreEqual("invalid", e.Message); - } } - - [Test] - public void WhenInvalidThrowCustomExceptionUsingSetter() - { - Inventor context = new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian"); - Dictionary vars = new Dictionary(); - ExceptionAction action = new ExceptionAction(); - IExpression expression = Expression.Parse("new System.InvalidOperationException('invalid')"); - action.ThrowsExpression = expression; - try - { - action.Execute(false, context, vars, null); - Assert.Fail("Should have thrown exception"); - } - catch (InvalidOperationException e) - { - Assert.AreEqual("invalid", e.Message); - } - } - - - [Test] - public void WhenValid() - { - Inventor context = new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian"); - Dictionary vars = new Dictionary(); - ExceptionAction action = new ExceptionAction(); - try - { - action.Execute(true, context, vars, null); - } - catch (Exception) - { - Assert.Fail("Should not have thrown exception"); - } - } - } -} \ No newline at end of file + + [Test] + public void WhenInvalidThrowCustomException() + { + Inventor context = new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian"); + Dictionary vars = new Dictionary(); + ExceptionAction action = new ExceptionAction("new System.InvalidOperationException('invalid')"); + try + { + action.Execute(false, context, vars, null); + Assert.Fail("Should have thrown exception"); + } + catch (InvalidOperationException e) + { + Assert.AreEqual("invalid", e.Message); + } + } + + [Test] + public void WhenInvalidThrowCustomExceptionUsingSetter() + { + Inventor context = new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian"); + Dictionary vars = new Dictionary(); + ExceptionAction action = new ExceptionAction(); + IExpression expression = Expression.Parse("new System.InvalidOperationException('invalid')"); + action.ThrowsExpression = expression; + try + { + action.Execute(false, context, vars, null); + Assert.Fail("Should have thrown exception"); + } + catch (InvalidOperationException e) + { + Assert.AreEqual("invalid", e.Message); + } + } + + [Test] + public void WhenValid() + { + Inventor context = new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian"); + Dictionary vars = new Dictionary(); + ExceptionAction action = new ExceptionAction(); + try + { + action.Execute(true, context, vars, null); + } + catch (Exception) + { + Assert.Fail("Should not have thrown exception"); + } + } +} diff --git a/test/Spring/Spring.Core.Tests/Validation/Actions/ExpressionActionTests.cs b/test/Spring/Spring.Core.Tests/Validation/Actions/ExpressionActionTests.cs index f4bcd255..1e431fd1 100644 --- a/test/Spring/Spring.Core.Tests/Validation/Actions/ExpressionActionTests.cs +++ b/test/Spring/Spring.Core.Tests/Validation/Actions/ExpressionActionTests.cs @@ -19,81 +19,78 @@ #endregion using NUnit.Framework; - using Spring.Expressions; -namespace Spring.Validation.Actions +namespace Spring.Validation.Actions; + +/// +/// Unit tests for the ExpressionAction class. +/// +/// Aleksandar Seovic +[TestFixture] +public class ExpressionActionTests { - /// - /// Unit tests for the ExpressionAction class. - /// - /// Aleksandar Seovic - [TestFixture] - public class ExpressionActionTests + [Test] + public void WhenValid() { - [Test] - public void WhenValid() - { - Inventor context = new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian"); - Dictionary vars = new Dictionary(); + Inventor context = new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian"); + Dictionary vars = new Dictionary(); - ExpressionAction action = new ExpressionAction("#result = 'valid'", "#result = 'invalid'"); - action.Execute(true, context, vars, null); - Assert.AreEqual("valid", vars["result"]); + ExpressionAction action = new ExpressionAction("#result = 'valid'", "#result = 'invalid'"); + action.Execute(true, context, vars, null); + Assert.AreEqual("valid", vars["result"]); - action = new ExpressionAction(Expression.Parse("#result = Name"), Expression.Parse("#result = Nationality")); - action.Execute(true, context, vars, null); - Assert.AreEqual(context.Name, vars["result"]); + action = new ExpressionAction(Expression.Parse("#result = Name"), Expression.Parse("#result = Nationality")); + action.Execute(true, context, vars, null); + Assert.AreEqual(context.Name, vars["result"]); - action = new ExpressionAction(); - action.Valid = Expression.Parse("#result = DOB.Year"); - action.Invalid = Expression.Parse("#result = DOB.Month"); - action.Execute(true, context, vars, null); - Assert.AreEqual(context.DOB.Year, vars["result"]); - - vars.Clear(); - action = new ExpressionAction(null, "#result = 'invalid'"); - action.Execute(true, context, vars, null); - Assert.IsFalse(vars.ContainsKey("result"), "Result should not exist when valid expression is null."); - } - - [Test] - public void WhenInvalid() - { - Inventor context = new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian"); - Dictionary vars = new Dictionary(); - - ExpressionAction action = new ExpressionAction("#result = 'valid'", "#result = 'invalid'"); - action.Execute(false, context, vars, null); - Assert.AreEqual("invalid", vars["result"]); - - action = new ExpressionAction(Expression.Parse("#result = Name"), Expression.Parse("#result = Nationality")); - action.Execute(false, context, vars, null); - Assert.AreEqual(context.Nationality, vars["result"]); - - action = new ExpressionAction(); - action.Valid = Expression.Parse("#result = DOB.Year"); - action.Invalid = Expression.Parse("#result = DOB.Month"); - action.Execute(false, context, vars, null); - Assert.AreEqual(context.DOB.Month, vars["result"]); - - vars.Clear(); - action = new ExpressionAction("#result = 'valid'", null); - action.Execute(false, context, vars, null); - Assert.IsFalse(vars.ContainsKey("result"), "Result should not exist when invalid expression is null."); - } - - [Test] - public void WhenActionIsNotExecutedBecauseWhenExpressionReturnsFalse() - { - Inventor context = new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian"); - Dictionary vars = new Dictionary(); - - ExpressionAction action = new ExpressionAction("#result = 'valid'", "#result = 'invalid'"); - action.When = Expression.Parse("false"); - action.Execute(true, context, vars, null); - Assert.IsFalse(vars.ContainsKey("result")); - } + action = new ExpressionAction(); + action.Valid = Expression.Parse("#result = DOB.Year"); + action.Invalid = Expression.Parse("#result = DOB.Month"); + action.Execute(true, context, vars, null); + Assert.AreEqual(context.DOB.Year, vars["result"]); + vars.Clear(); + action = new ExpressionAction(null, "#result = 'invalid'"); + action.Execute(true, context, vars, null); + Assert.IsFalse(vars.ContainsKey("result"), "Result should not exist when valid expression is null."); } -} \ No newline at end of file + + [Test] + public void WhenInvalid() + { + Inventor context = new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian"); + Dictionary vars = new Dictionary(); + + ExpressionAction action = new ExpressionAction("#result = 'valid'", "#result = 'invalid'"); + action.Execute(false, context, vars, null); + Assert.AreEqual("invalid", vars["result"]); + + action = new ExpressionAction(Expression.Parse("#result = Name"), Expression.Parse("#result = Nationality")); + action.Execute(false, context, vars, null); + Assert.AreEqual(context.Nationality, vars["result"]); + + action = new ExpressionAction(); + action.Valid = Expression.Parse("#result = DOB.Year"); + action.Invalid = Expression.Parse("#result = DOB.Month"); + action.Execute(false, context, vars, null); + Assert.AreEqual(context.DOB.Month, vars["result"]); + + vars.Clear(); + action = new ExpressionAction("#result = 'valid'", null); + action.Execute(false, context, vars, null); + Assert.IsFalse(vars.ContainsKey("result"), "Result should not exist when invalid expression is null."); + } + + [Test] + public void WhenActionIsNotExecutedBecauseWhenExpressionReturnsFalse() + { + Inventor context = new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian"); + Dictionary vars = new Dictionary(); + + ExpressionAction action = new ExpressionAction("#result = 'valid'", "#result = 'invalid'"); + action.When = Expression.Parse("false"); + action.Execute(true, context, vars, null); + Assert.IsFalse(vars.ContainsKey("result")); + } +} diff --git a/test/Spring/Spring.Core.Tests/Validation/AnyValidatorGroupTests.cs b/test/Spring/Spring.Core.Tests/Validation/AnyValidatorGroupTests.cs index 8709106a..4c6da903 100644 --- a/test/Spring/Spring.Core.Tests/Validation/AnyValidatorGroupTests.cs +++ b/test/Spring/Spring.Core.Tests/Validation/AnyValidatorGroupTests.cs @@ -21,121 +21,118 @@ #region Imports using NUnit.Framework; - using Spring.Expressions; #endregion -namespace Spring.Validation +namespace Spring.Validation; + +/// +/// Unit tests for the AnyValidatorGroup class. +/// +/// Aleksandar Seovic +[TestFixture] +public sealed class AnyValidatorGroupTests { - /// - /// Unit tests for the AnyValidatorGroup class. - /// - /// Aleksandar Seovic - [TestFixture] - public sealed class AnyValidatorGroupTests + [Test] + public void DefaultsToFastValidate() { - [Test] - public void DefaultsToFastValidate() - { - AnyValidatorGroup vg = new AnyValidatorGroup(); - Assert.IsTrue(vg.FastValidate); - } - - [Test] - public void WhenAllValidatorsReturnFalse() - { - AnyValidatorGroup vg = new AnyValidatorGroup(); - vg.Validators.Add(new FalseValidator()); - vg.Validators.Add(new FalseValidator()); - vg.Validators.Add(new FalseValidator()); - - IValidationErrors errors = new ValidationErrors(); - errors.AddError("existingErrors", new ErrorMessage("error", null)); - - bool valid = vg.Validate(new object(), errors); - - Assert.IsFalse(valid, "Validation should fail when all inner validators return false."); - Assert.AreEqual(3, errors.GetErrors("errors").Count); - Assert.AreEqual(1, errors.GetErrors("existingErrors").Count); - } - - [Test] - public void WhenAllValidatorsReturnTrue() - { - AnyValidatorGroup vg = new AnyValidatorGroup("true"); - vg.Validators.Add(new TrueValidator()); - vg.Validators.Add(new TrueValidator()); - vg.Validators.Add(new TrueValidator()); - - IValidationErrors errors = new ValidationErrors(); - errors.AddError("existingErrors", new ErrorMessage("error", null)); - - bool valid = vg.Validate(new object(), errors); - - Assert.IsTrue(valid, "Validation should succeed when all inner validators return true."); - Assert.AreEqual(0, errors.GetErrors("errors").Count); - Assert.AreEqual(1, errors.GetErrors("existingErrors").Count); - } - - [Test] - public void WhenSingleValidatorReturnsTrueFastAndFastValidateIsTrue() - { - AnyValidatorGroup vg = new AnyValidatorGroup(Expression.Parse("true")); - vg.FastValidate = true; - - WhenSingleValidatorReturnsTrue(vg); - // validators are called only until validation result is known - Assert.IsTrue( ((BaseTestValidator)vg.Validators[0]).WasCalled ); - Assert.IsTrue( ((BaseTestValidator)vg.Validators[1]).WasCalled ); - Assert.IsFalse( ((BaseTestValidator)vg.Validators[2]).WasCalled ); - } - - [Test] - public void WhenSingleValidatorReturnsTrueAndFastValidateIsFalse() - { - AnyValidatorGroup vg = new AnyValidatorGroup(Expression.Parse("true")); - vg.FastValidate = false; - - WhenSingleValidatorReturnsTrue(vg); - // ALL validators are called - Assert.IsTrue( ((BaseTestValidator)vg.Validators[0]).WasCalled ); - Assert.IsTrue( ((BaseTestValidator)vg.Validators[1]).WasCalled ); - Assert.IsTrue( ((BaseTestValidator)vg.Validators[2]).WasCalled ); - } - - private static void WhenSingleValidatorReturnsTrue(AnyValidatorGroup vg) - { - vg.Validators.Add(new FalseValidator()); - vg.Validators.Add(new TrueValidator()); - vg.Validators.Add(new FalseValidator()); - - IValidationErrors errors = new ValidationErrors(); - errors.AddError("existingErrors", new ErrorMessage("error", null)); - - bool valid = vg.Validate(new object(), errors); - - Assert.IsTrue(valid, "Validation should succeed when single inner validator returns true."); - Assert.AreEqual(0, errors.GetErrors("errors").Count); - Assert.AreEqual(1, errors.GetErrors("existingErrors").Count); - } - - [Test] - public void WhenGroupIsNotValidatedBecauseWhenExpressionReturnsFalse() - { - AnyValidatorGroup vg = new AnyValidatorGroup("false"); - vg.Validators.Add(new FalseValidator()); - vg.Validators.Add(new FalseValidator()); - - IValidationErrors errors = new ValidationErrors(); - errors.AddError("existingErrors", new ErrorMessage("error", null)); - - bool valid = vg.Validate(new object(), errors); - - Assert.IsTrue(valid, "Validation should succeed when group validator is not evaluated."); - Assert.AreEqual(0, errors.GetErrors("errors").Count); - Assert.AreEqual(1, errors.GetErrors("existingErrors").Count); - } - + AnyValidatorGroup vg = new AnyValidatorGroup(); + Assert.IsTrue(vg.FastValidate); } -} \ No newline at end of file + + [Test] + public void WhenAllValidatorsReturnFalse() + { + AnyValidatorGroup vg = new AnyValidatorGroup(); + vg.Validators.Add(new FalseValidator()); + vg.Validators.Add(new FalseValidator()); + vg.Validators.Add(new FalseValidator()); + + IValidationErrors errors = new ValidationErrors(); + errors.AddError("existingErrors", new ErrorMessage("error", null)); + + bool valid = vg.Validate(new object(), errors); + + Assert.IsFalse(valid, "Validation should fail when all inner validators return false."); + Assert.AreEqual(3, errors.GetErrors("errors").Count); + Assert.AreEqual(1, errors.GetErrors("existingErrors").Count); + } + + [Test] + public void WhenAllValidatorsReturnTrue() + { + AnyValidatorGroup vg = new AnyValidatorGroup("true"); + vg.Validators.Add(new TrueValidator()); + vg.Validators.Add(new TrueValidator()); + vg.Validators.Add(new TrueValidator()); + + IValidationErrors errors = new ValidationErrors(); + errors.AddError("existingErrors", new ErrorMessage("error", null)); + + bool valid = vg.Validate(new object(), errors); + + Assert.IsTrue(valid, "Validation should succeed when all inner validators return true."); + Assert.AreEqual(0, errors.GetErrors("errors").Count); + Assert.AreEqual(1, errors.GetErrors("existingErrors").Count); + } + + [Test] + public void WhenSingleValidatorReturnsTrueFastAndFastValidateIsTrue() + { + AnyValidatorGroup vg = new AnyValidatorGroup(Expression.Parse("true")); + vg.FastValidate = true; + + WhenSingleValidatorReturnsTrue(vg); + // validators are called only until validation result is known + Assert.IsTrue(((BaseTestValidator) vg.Validators[0]).WasCalled); + Assert.IsTrue(((BaseTestValidator) vg.Validators[1]).WasCalled); + Assert.IsFalse(((BaseTestValidator) vg.Validators[2]).WasCalled); + } + + [Test] + public void WhenSingleValidatorReturnsTrueAndFastValidateIsFalse() + { + AnyValidatorGroup vg = new AnyValidatorGroup(Expression.Parse("true")); + vg.FastValidate = false; + + WhenSingleValidatorReturnsTrue(vg); + // ALL validators are called + Assert.IsTrue(((BaseTestValidator) vg.Validators[0]).WasCalled); + Assert.IsTrue(((BaseTestValidator) vg.Validators[1]).WasCalled); + Assert.IsTrue(((BaseTestValidator) vg.Validators[2]).WasCalled); + } + + private static void WhenSingleValidatorReturnsTrue(AnyValidatorGroup vg) + { + vg.Validators.Add(new FalseValidator()); + vg.Validators.Add(new TrueValidator()); + vg.Validators.Add(new FalseValidator()); + + IValidationErrors errors = new ValidationErrors(); + errors.AddError("existingErrors", new ErrorMessage("error", null)); + + bool valid = vg.Validate(new object(), errors); + + Assert.IsTrue(valid, "Validation should succeed when single inner validator returns true."); + Assert.AreEqual(0, errors.GetErrors("errors").Count); + Assert.AreEqual(1, errors.GetErrors("existingErrors").Count); + } + + [Test] + public void WhenGroupIsNotValidatedBecauseWhenExpressionReturnsFalse() + { + AnyValidatorGroup vg = new AnyValidatorGroup("false"); + vg.Validators.Add(new FalseValidator()); + vg.Validators.Add(new FalseValidator()); + + IValidationErrors errors = new ValidationErrors(); + errors.AddError("existingErrors", new ErrorMessage("error", null)); + + bool valid = vg.Validate(new object(), errors); + + Assert.IsTrue(valid, "Validation should succeed when group validator is not evaluated."); + Assert.AreEqual(0, errors.GetErrors("errors").Count); + Assert.AreEqual(1, errors.GetErrors("existingErrors").Count); + } +} diff --git a/test/Spring/Spring.Core.Tests/Validation/CollectionValidatorTests.cs b/test/Spring/Spring.Core.Tests/Validation/CollectionValidatorTests.cs index ce64765a..5b56b0e1 100644 --- a/test/Spring/Spring.Core.Tests/Validation/CollectionValidatorTests.cs +++ b/test/Spring/Spring.Core.Tests/Validation/CollectionValidatorTests.cs @@ -9,47 +9,47 @@ using Spring.Objects; using Spring.Objects.Factory.Xml; using Spring.Validation.Actions; -namespace Spring.Validation +namespace Spring.Validation; + +/// +/// Unit tests for the CollectionValidator class. +/// +/// Damjan Tomic +[TestFixture] +public class CollectionValidatorTests { - /// - /// Unit tests for the CollectionValidator class. - /// - /// Damjan Tomic - [TestFixture] - public class CollectionValidatorTests + [Test] + public void DefaultsToFastValidateIsFalse() { - [Test] - public void DefaultsToFastValidateIsFalse() - { - CollectionValidator cg = new CollectionValidator(); - Assert.IsFalse(cg.FastValidate); - } + CollectionValidator cg = new CollectionValidator(); + Assert.IsFalse(cg.FastValidate); + } - [Test] - public void TestCollection() - { - IList persons = new ArrayList(); + [Test] + public void TestCollection() + { + IList persons = new ArrayList(); - persons.Add(new TestObject("Damjan Tomic", 24)); - persons.Add(new TestObject("Goran Milosavljevic", 24)); - persons.Add(new TestObject("Ivan Cikic", 28)); - - RequiredValidator req = new RequiredValidator("Name", "true"); + persons.Add(new TestObject("Damjan Tomic", 24)); + persons.Add(new TestObject("Goran Milosavljevic", 24)); + persons.Add(new TestObject("Ivan Cikic", 28)); - RegularExpressionValidator reg = new RegularExpressionValidator("Name", "true", @"[a-z]*\s[a-z]*"); - reg.Options = RegexOptions.IgnoreCase; - - CollectionValidator validator = new CollectionValidator(); - validator.Validators.Add(req); - validator.Validators.Add(reg); - - Assert.IsTrue(validator.Validate(persons, new ValidationErrors())); - } + RequiredValidator req = new RequiredValidator("Name", "true"); - [Test] - public void TestDifferentCollectionTypes() - { - const string xml = @" + RegularExpressionValidator reg = new RegularExpressionValidator("Name", "true", @"[a-z]*\s[a-z]*"); + reg.Options = RegexOptions.IgnoreCase; + + CollectionValidator validator = new CollectionValidator(); + validator.Validators.Add(req); + validator.Validators.Add(reg); + + Assert.IsTrue(validator.Validate(persons, new ValidationErrors())); + } + + [Test] + public void TestDifferentCollectionTypes() + { + const string xml = @" @@ -66,110 +66,107 @@ namespace Spring.Validation "; - MemoryStream stream = new MemoryStream(new UTF8Encoding().GetBytes(xml)); - IResource resource = new InputStreamResource(stream, "collectionValidator"); + MemoryStream stream = new MemoryStream(new UTF8Encoding().GetBytes(xml)); + IResource resource = new InputStreamResource(stream, "collectionValidator"); - XmlObjectFactory objectFactory = new XmlObjectFactory(resource, null); - CollectionValidator validator = (CollectionValidator) objectFactory.GetObject("collectionValidator"); - - IList listPersons = new ArrayList(); - IDictionary dictPersons = new Hashtable(); - ISet setPersons = new ListSet(); + XmlObjectFactory objectFactory = new XmlObjectFactory(resource, null); + CollectionValidator validator = (CollectionValidator) objectFactory.GetObject("collectionValidator"); - listPersons.Add(new TestObject("DAMJAN Tomic", 24)); - listPersons.Add(new TestObject("Goran Milosavljevic", 24)); - listPersons.Add(new TestObject("Ivan CIKIC", 28)); + IList listPersons = new ArrayList(); + IDictionary dictPersons = new Hashtable(); + ISet setPersons = new ListSet(); - dictPersons.Add(1, listPersons[0]); - dictPersons.Add(2, listPersons[1]); - dictPersons.Add(3, listPersons[2]); + listPersons.Add(new TestObject("DAMJAN Tomic", 24)); + listPersons.Add(new TestObject("Goran Milosavljevic", 24)); + listPersons.Add(new TestObject("Ivan CIKIC", 28)); - setPersons.AddAll(listPersons); - IValidationErrors ve = new ValidationErrors(); + dictPersons.Add(1, listPersons[0]); + dictPersons.Add(2, listPersons[1]); + dictPersons.Add(3, listPersons[2]); - Assert.IsTrue(validator.Validate(listPersons, ve)); - Assert.IsTrue(ve.IsEmpty); - Assert.IsTrue(validator.Validate(dictPersons, ve)); - Assert.IsTrue(ve.IsEmpty); - Assert.IsTrue(validator.Validate(setPersons, ve)); - Assert.IsTrue(ve.IsEmpty); - } + setPersons.AddAll(listPersons); + IValidationErrors ve = new ValidationErrors(); + Assert.IsTrue(validator.Validate(listPersons, ve)); + Assert.IsTrue(ve.IsEmpty); + Assert.IsTrue(validator.Validate(dictPersons, ve)); + Assert.IsTrue(ve.IsEmpty); + Assert.IsTrue(validator.Validate(setPersons, ve)); + Assert.IsTrue(ve.IsEmpty); + } - [Test] - public void TestWithWrongArgumentType() - { - RequiredValidator req = new RequiredValidator("Name", "true"); - CollectionValidator validator = new CollectionValidator(); - validator.Validators.Add(req); - - TestObject tObj = new TestObject("Damjan Tomic", 24); + [Test] + public void TestWithWrongArgumentType() + { + RequiredValidator req = new RequiredValidator("Name", "true"); + CollectionValidator validator = new CollectionValidator(); + validator.Validators.Add(req); - //This should cause the ArgumentException because tObj is not a Collection - Assert.Throws(() => validator.Validate(tObj, new ValidationErrors())); - } + TestObject tObj = new TestObject("Damjan Tomic", 24); - [Test] - public void TestValidationErrorsAreCollected() - { - IList persons = new ArrayList(); + //This should cause the ArgumentException because tObj is not a Collection + Assert.Throws(() => validator.Validate(tObj, new ValidationErrors())); + } - persons.Add(new TestObject(null, 24)); - persons.Add(new TestObject("Goran Milosavljevic", 24)); - persons.Add(new TestObject("Ivan Cikic", 28)); - persons.Add(new TestObject(null, 20)); + [Test] + public void TestValidationErrorsAreCollected() + { + IList persons = new ArrayList(); - RequiredValidator req = new RequiredValidator("Name", "true"); - req.Actions.Add(new ErrorMessageAction("1", new string[] { "firstProvider", "secondProvider" })); + persons.Add(new TestObject(null, 24)); + persons.Add(new TestObject("Goran Milosavljevic", 24)); + persons.Add(new TestObject("Ivan Cikic", 28)); + persons.Add(new TestObject(null, 20)); - CollectionValidator validator = new CollectionValidator(true,true); - - validator.Validators.Add(req); + RequiredValidator req = new RequiredValidator("Name", "true"); + req.Actions.Add(new ErrorMessageAction("1", new string[] { "firstProvider", "secondProvider" })); - IValidationErrors ve = new ValidationErrors(); + CollectionValidator validator = new CollectionValidator(true, true); - Assert.IsFalse(validator.Validate(persons, ve)); - Assert.IsFalse(ve.IsEmpty); - - } - - [Test] - public void TestWithNull() - { - CollectionValidator validator = new CollectionValidator(); - //This should cause the ArgumentException because we passed null into Validate method - Assert.Throws(() => validator.Validate(null, new ValidationErrors())); - } - - [Test] - public void TestNestingCollectionValidator() - { - Society soc = new Society(); - soc.Members.Add(new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian")); - soc.Members.Add(new Inventor("Mihajlo Pupin", new DateTime(1854, 10, 9), "Serbian")); - - - RequiredValidator req = new RequiredValidator("Name", "true"); + validator.Validators.Add(req); - RegularExpressionValidator reg = new RegularExpressionValidator("Name", "true", @"[a-z]*\s[a-z]*"); - reg.Options = RegexOptions.IgnoreCase; - - CollectionValidator validator = new CollectionValidator(); - validator.Validators.Add(req); - validator.Validators.Add(reg); - - validator.Context = Expression.Parse("Members"); - - Assert.IsTrue(validator.Validate(soc, new ValidationErrors())); - - validator.Context = null; - Assert.IsTrue(validator.Validate(soc.Members, new ValidationErrors())); - } - - [Test] - public void TestNestingCollectionValidatorWithXMLDescription() - { - const string xml = @" + IValidationErrors ve = new ValidationErrors(); + + Assert.IsFalse(validator.Validate(persons, ve)); + Assert.IsFalse(ve.IsEmpty); + } + + [Test] + public void TestWithNull() + { + CollectionValidator validator = new CollectionValidator(); + //This should cause the ArgumentException because we passed null into Validate method + Assert.Throws(() => validator.Validate(null, new ValidationErrors())); + } + + [Test] + public void TestNestingCollectionValidator() + { + Society soc = new Society(); + soc.Members.Add(new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian")); + soc.Members.Add(new Inventor("Mihajlo Pupin", new DateTime(1854, 10, 9), "Serbian")); + + RequiredValidator req = new RequiredValidator("Name", "true"); + + RegularExpressionValidator reg = new RegularExpressionValidator("Name", "true", @"[a-z]*\s[a-z]*"); + reg.Options = RegexOptions.IgnoreCase; + + CollectionValidator validator = new CollectionValidator(); + validator.Validators.Add(req); + validator.Validators.Add(reg); + + validator.Context = Expression.Parse("Members"); + + Assert.IsTrue(validator.Validate(soc, new ValidationErrors())); + + validator.Context = null; + Assert.IsTrue(validator.Validate(soc.Members, new ValidationErrors())); + } + + [Test] + public void TestNestingCollectionValidatorWithXMLDescription() + { + const string xml = @" @@ -192,26 +189,24 @@ namespace Spring.Validation "; - MemoryStream stream = new MemoryStream(new UTF8Encoding().GetBytes(xml)); - IResource resource = new InputStreamResource(stream, "collection validator test"); + MemoryStream stream = new MemoryStream(new UTF8Encoding().GetBytes(xml)); + IResource resource = new InputStreamResource(stream, "collection validator test"); - XmlObjectFactory objectFactory = new XmlObjectFactory(resource, null); - - ValidatorGroup validator = (ValidatorGroup) objectFactory.GetObject("validator"); - Society soc = new Society(); - - soc.Members.Add(new TestObject("Damjan Tomic", 24)); - soc.Members.Add(new TestObject("Goran Milosavljevic", 24)); - soc.Members.Add(new TestObject("Ivan Cikic", 28)); - - IValidationErrors err1 = new ValidationErrors(); - - Assert.IsTrue(validator.Validate(soc, err1)); - - soc.Members.Add(new TestObject("foo", 30)); - soc.Members.Add(new TestObject("bar", 30)); - Assert.IsFalse(validator.Validate(soc, err1)); - - } - } + XmlObjectFactory objectFactory = new XmlObjectFactory(resource, null); + + ValidatorGroup validator = (ValidatorGroup) objectFactory.GetObject("validator"); + Society soc = new Society(); + + soc.Members.Add(new TestObject("Damjan Tomic", 24)); + soc.Members.Add(new TestObject("Goran Milosavljevic", 24)); + soc.Members.Add(new TestObject("Ivan Cikic", 28)); + + IValidationErrors err1 = new ValidationErrors(); + + Assert.IsTrue(validator.Validate(soc, err1)); + + soc.Members.Add(new TestObject("foo", 30)); + soc.Members.Add(new TestObject("bar", 30)); + Assert.IsFalse(validator.Validate(soc, err1)); + } } diff --git a/test/Spring/Spring.Core.Tests/Validation/ExclusiveValidatorGroupTests.cs b/test/Spring/Spring.Core.Tests/Validation/ExclusiveValidatorGroupTests.cs index 83419944..b8d74ab0 100644 --- a/test/Spring/Spring.Core.Tests/Validation/ExclusiveValidatorGroupTests.cs +++ b/test/Spring/Spring.Core.Tests/Validation/ExclusiveValidatorGroupTests.cs @@ -21,160 +21,157 @@ #region Imports using NUnit.Framework; - using Spring.Expressions; using Spring.Validation.Actions; #endregion -namespace Spring.Validation +namespace Spring.Validation; + +/// +/// Unit tests for the ExclusiveValidatorGroup class. +/// +/// Aleksandar Seovic +[TestFixture] +public sealed class ExclusiveValidatorGroupTests { - /// - /// Unit tests for the ExclusiveValidatorGroup class. - /// - /// Aleksandar Seovic - [TestFixture] - public sealed class ExclusiveValidatorGroupTests + [Test] + public void DefaultsToFastValidate() { - [Test] - public void DefaultsToFastValidate() - { - ExclusiveValidatorGroup evg = new ExclusiveValidatorGroup(); - Assert.IsTrue(evg.FastValidate); - } - - [Test] - public void WhenAllValidatorsReturnFalse() - { - ExclusiveValidatorGroup vg = new ExclusiveValidatorGroup(); - vg.Actions.Add(new ErrorMessageAction("exclusiveError", "exclusiveErrors")); - - vg.Validators.Add(new FalseValidator()); - vg.Validators.Add(new FalseValidator()); - vg.Validators.Add(new FalseValidator()); - - IValidationErrors errors = new ValidationErrors(); - errors.AddError("existingErrors", new ErrorMessage("error", null)); - - bool valid = vg.Validate(new object(), errors); - - Assert.IsFalse(valid, "Validation should fail when all inner validators return false."); - Assert.AreEqual(3, errors.GetErrors("errors").Count); - Assert.AreEqual(1, errors.GetErrors("exclusiveErrors").Count); - Assert.AreEqual(1, errors.GetErrors("existingErrors").Count); - } - - [Test] - public void WhenAllValidatorsReturnTrue() - { - ExclusiveValidatorGroup vg = new ExclusiveValidatorGroup("true"); - vg.Actions.Add(new ErrorMessageAction("exclusiveError", "exclusiveErrors")); - - vg.Validators.Add(new TrueValidator()); - vg.Validators.Add(new TrueValidator()); - vg.Validators.Add(new TrueValidator()); - - IValidationErrors errors = new ValidationErrors(); - errors.AddError("existingErrors", new ErrorMessage("error", null)); - - bool valid = vg.Validate(new object(), errors); - - Assert.IsFalse(valid, "Validation should fail when all inner validators return true."); - Assert.AreEqual(0, errors.GetErrors("errors").Count); - Assert.AreEqual(1, errors.GetErrors("exclusiveErrors").Count); - Assert.AreEqual(1, errors.GetErrors("existingErrors").Count); - } - - [Test] - public void WhenSingleValidatorReturnsTrue() - { - ExclusiveValidatorGroup vg = new ExclusiveValidatorGroup(Expression.Parse("true")); - vg.Actions.Add(new ErrorMessageAction("exclusiveError", "exclusiveErrors")); - - vg.Validators.Add(new FalseValidator()); - vg.Validators.Add(new TrueValidator()); - vg.Validators.Add(new FalseValidator()); - - IValidationErrors errors = new ValidationErrors(); - errors.AddError("existingErrors", new ErrorMessage("error", null)); - - bool valid = vg.Validate(new object(), errors); - - Assert.IsTrue(valid, "Validation should succeed when single inner validator returns true."); - Assert.AreEqual(0, errors.GetErrors("errors").Count); - Assert.AreEqual(0, errors.GetErrors("exclusiveErrors").Count); - Assert.AreEqual(1, errors.GetErrors("existingErrors").Count); - - // ALL validators are called - Assert.IsTrue( ((BaseTestValidator)vg.Validators[0]).WasCalled ); - Assert.IsTrue( ((BaseTestValidator)vg.Validators[1]).WasCalled ); - Assert.IsTrue( ((BaseTestValidator)vg.Validators[2]).WasCalled ); - } - - [Test] - public void WhenMultipleValidatorsReturnTrueAndFastValidate() - { - ExclusiveValidatorGroup vg = new ExclusiveValidatorGroup(Expression.Parse("true")); - vg.FastValidate = true; - IValidationErrors errors = new ValidationErrors(); - WhenMultipleValidatorsReturnTrue(vg, errors); - // validators are called only until validation result is known - Assert.AreEqual(1, errors.GetErrors("errors").Count); - Assert.IsTrue( ((BaseTestValidator)vg.Validators[0]).WasCalled ); - Assert.IsTrue( ((BaseTestValidator)vg.Validators[1]).WasCalled ); - Assert.IsTrue( ((BaseTestValidator)vg.Validators[2]).WasCalled ); - Assert.IsFalse( ((BaseTestValidator)vg.Validators[3]).WasCalled ); - } - - [Test] - public void WhenMultipleValidatorsReturnTrueAndNotFastValidate() - { - ExclusiveValidatorGroup vg = new ExclusiveValidatorGroup(Expression.Parse("true")); - vg.FastValidate = false; - IValidationErrors errors = new ValidationErrors(); - WhenMultipleValidatorsReturnTrue(vg, errors); - // ALL validators are called - Assert.AreEqual(2, errors.GetErrors("errors").Count); - Assert.IsTrue( ((BaseTestValidator)vg.Validators[0]).WasCalled ); - Assert.IsTrue( ((BaseTestValidator)vg.Validators[1]).WasCalled ); - Assert.IsTrue( ((BaseTestValidator)vg.Validators[2]).WasCalled ); - Assert.IsTrue( ((BaseTestValidator)vg.Validators[3]).WasCalled ); - } - - private void WhenMultipleValidatorsReturnTrue(ExclusiveValidatorGroup vg, IValidationErrors errors) - { - vg.Actions.Add(new ErrorMessageAction("exclusiveError", "exclusiveErrors")); - - vg.Validators.Add(new FalseValidator()); - vg.Validators.Add(new TrueValidator()); - vg.Validators.Add(new TrueValidator()); - vg.Validators.Add(new FalseValidator()); - - errors.AddError("existingErrors", new ErrorMessage("error", null)); - - bool valid = vg.Validate(new object(), errors); - - Assert.IsFalse(valid, "Validation should not succeed when multiple inner validators return true."); - Assert.AreEqual(1, errors.GetErrors("exclusiveErrors").Count); - Assert.AreEqual(1, errors.GetErrors("existingErrors").Count); - } - - [Test] - public void WhenGroupIsNotValidatedBecauseWhenExpressionReturnsFalse() - { - ExclusiveValidatorGroup vg = new ExclusiveValidatorGroup("false"); - vg.Validators.Add(new FalseValidator()); - vg.Validators.Add(new FalseValidator()); - - IValidationErrors errors = new ValidationErrors(); - errors.AddError("existingErrors", new ErrorMessage("error", null)); - - bool valid = vg.Validate(new object(), errors); - - Assert.IsTrue(valid, "Validation should succeed when group validator is not evaluated."); - Assert.AreEqual(0, errors.GetErrors("errors").Count); - Assert.AreEqual(1, errors.GetErrors("existingErrors").Count); - } - + ExclusiveValidatorGroup evg = new ExclusiveValidatorGroup(); + Assert.IsTrue(evg.FastValidate); } -} \ No newline at end of file + + [Test] + public void WhenAllValidatorsReturnFalse() + { + ExclusiveValidatorGroup vg = new ExclusiveValidatorGroup(); + vg.Actions.Add(new ErrorMessageAction("exclusiveError", "exclusiveErrors")); + + vg.Validators.Add(new FalseValidator()); + vg.Validators.Add(new FalseValidator()); + vg.Validators.Add(new FalseValidator()); + + IValidationErrors errors = new ValidationErrors(); + errors.AddError("existingErrors", new ErrorMessage("error", null)); + + bool valid = vg.Validate(new object(), errors); + + Assert.IsFalse(valid, "Validation should fail when all inner validators return false."); + Assert.AreEqual(3, errors.GetErrors("errors").Count); + Assert.AreEqual(1, errors.GetErrors("exclusiveErrors").Count); + Assert.AreEqual(1, errors.GetErrors("existingErrors").Count); + } + + [Test] + public void WhenAllValidatorsReturnTrue() + { + ExclusiveValidatorGroup vg = new ExclusiveValidatorGroup("true"); + vg.Actions.Add(new ErrorMessageAction("exclusiveError", "exclusiveErrors")); + + vg.Validators.Add(new TrueValidator()); + vg.Validators.Add(new TrueValidator()); + vg.Validators.Add(new TrueValidator()); + + IValidationErrors errors = new ValidationErrors(); + errors.AddError("existingErrors", new ErrorMessage("error", null)); + + bool valid = vg.Validate(new object(), errors); + + Assert.IsFalse(valid, "Validation should fail when all inner validators return true."); + Assert.AreEqual(0, errors.GetErrors("errors").Count); + Assert.AreEqual(1, errors.GetErrors("exclusiveErrors").Count); + Assert.AreEqual(1, errors.GetErrors("existingErrors").Count); + } + + [Test] + public void WhenSingleValidatorReturnsTrue() + { + ExclusiveValidatorGroup vg = new ExclusiveValidatorGroup(Expression.Parse("true")); + vg.Actions.Add(new ErrorMessageAction("exclusiveError", "exclusiveErrors")); + + vg.Validators.Add(new FalseValidator()); + vg.Validators.Add(new TrueValidator()); + vg.Validators.Add(new FalseValidator()); + + IValidationErrors errors = new ValidationErrors(); + errors.AddError("existingErrors", new ErrorMessage("error", null)); + + bool valid = vg.Validate(new object(), errors); + + Assert.IsTrue(valid, "Validation should succeed when single inner validator returns true."); + Assert.AreEqual(0, errors.GetErrors("errors").Count); + Assert.AreEqual(0, errors.GetErrors("exclusiveErrors").Count); + Assert.AreEqual(1, errors.GetErrors("existingErrors").Count); + + // ALL validators are called + Assert.IsTrue(((BaseTestValidator) vg.Validators[0]).WasCalled); + Assert.IsTrue(((BaseTestValidator) vg.Validators[1]).WasCalled); + Assert.IsTrue(((BaseTestValidator) vg.Validators[2]).WasCalled); + } + + [Test] + public void WhenMultipleValidatorsReturnTrueAndFastValidate() + { + ExclusiveValidatorGroup vg = new ExclusiveValidatorGroup(Expression.Parse("true")); + vg.FastValidate = true; + IValidationErrors errors = new ValidationErrors(); + WhenMultipleValidatorsReturnTrue(vg, errors); + // validators are called only until validation result is known + Assert.AreEqual(1, errors.GetErrors("errors").Count); + Assert.IsTrue(((BaseTestValidator) vg.Validators[0]).WasCalled); + Assert.IsTrue(((BaseTestValidator) vg.Validators[1]).WasCalled); + Assert.IsTrue(((BaseTestValidator) vg.Validators[2]).WasCalled); + Assert.IsFalse(((BaseTestValidator) vg.Validators[3]).WasCalled); + } + + [Test] + public void WhenMultipleValidatorsReturnTrueAndNotFastValidate() + { + ExclusiveValidatorGroup vg = new ExclusiveValidatorGroup(Expression.Parse("true")); + vg.FastValidate = false; + IValidationErrors errors = new ValidationErrors(); + WhenMultipleValidatorsReturnTrue(vg, errors); + // ALL validators are called + Assert.AreEqual(2, errors.GetErrors("errors").Count); + Assert.IsTrue(((BaseTestValidator) vg.Validators[0]).WasCalled); + Assert.IsTrue(((BaseTestValidator) vg.Validators[1]).WasCalled); + Assert.IsTrue(((BaseTestValidator) vg.Validators[2]).WasCalled); + Assert.IsTrue(((BaseTestValidator) vg.Validators[3]).WasCalled); + } + + private void WhenMultipleValidatorsReturnTrue(ExclusiveValidatorGroup vg, IValidationErrors errors) + { + vg.Actions.Add(new ErrorMessageAction("exclusiveError", "exclusiveErrors")); + + vg.Validators.Add(new FalseValidator()); + vg.Validators.Add(new TrueValidator()); + vg.Validators.Add(new TrueValidator()); + vg.Validators.Add(new FalseValidator()); + + errors.AddError("existingErrors", new ErrorMessage("error", null)); + + bool valid = vg.Validate(new object(), errors); + + Assert.IsFalse(valid, "Validation should not succeed when multiple inner validators return true."); + Assert.AreEqual(1, errors.GetErrors("exclusiveErrors").Count); + Assert.AreEqual(1, errors.GetErrors("existingErrors").Count); + } + + [Test] + public void WhenGroupIsNotValidatedBecauseWhenExpressionReturnsFalse() + { + ExclusiveValidatorGroup vg = new ExclusiveValidatorGroup("false"); + vg.Validators.Add(new FalseValidator()); + vg.Validators.Add(new FalseValidator()); + + IValidationErrors errors = new ValidationErrors(); + errors.AddError("existingErrors", new ErrorMessage("error", null)); + + bool valid = vg.Validate(new object(), errors); + + Assert.IsTrue(valid, "Validation should succeed when group validator is not evaluated."); + Assert.AreEqual(0, errors.GetErrors("errors").Count); + Assert.AreEqual(1, errors.GetErrors("existingErrors").Count); + } +} diff --git a/test/Spring/Spring.Core.Tests/Validation/HelperClasses.cs b/test/Spring/Spring.Core.Tests/Validation/HelperClasses.cs index f025c04c..1038d478 100644 --- a/test/Spring/Spring.Core.Tests/Validation/HelperClasses.cs +++ b/test/Spring/Spring.Core.Tests/Validation/HelperClasses.cs @@ -22,111 +22,110 @@ using Spring.Objects.Factory.Config; using Spring.Objects.Factory.Support; using Spring.Validation.Actions; -namespace Spring.Validation +namespace Spring.Validation; + +public abstract class BaseTestValidator : BaseSimpleValidator { - public abstract class BaseTestValidator : BaseSimpleValidator + private bool _wasCalled; + + public bool WasCalled => _wasCalled; + + public override bool Validate(object validationContext, IDictionary contextParams, + IValidationErrors errors) { - private bool _wasCalled; + _wasCalled = true; + return base.Validate(validationContext, contextParams, errors); + } +} - public bool WasCalled => _wasCalled; - - public override bool Validate(object validationContext, IDictionary contextParams, - IValidationErrors errors) - { - _wasCalled = true; - return base.Validate(validationContext, contextParams, errors); - } +/// +/// Helper classes for validation tests. +/// +/// Aleksandar Seovic +public class TrueValidator : BaseTestValidator +{ + public TrueValidator() + { } /// - /// Helper classes for validation tests. + /// Validates test object. /// - /// Aleksandar Seovic - public class TrueValidator : BaseTestValidator + /// Object to validate. + /// True if specified object is valid, False otherwise. + protected override bool Validate(object objectToValidate) { - public TrueValidator() - { - } + return true; + } +} - /// - /// Validates test object. - /// - /// Object to validate. - /// True if specified object is valid, False otherwise. - protected override bool Validate(object objectToValidate) - { - return true; - } +public class FalseValidator : BaseTestValidator +{ + public FalseValidator() + { + Actions.Add(new ErrorMessageAction("error", "errors")); } - public class FalseValidator : BaseTestValidator + /// + /// Validates test object. + /// + /// Object to validate. + /// True if specified object is valid, False otherwise. + protected override bool Validate(object objectToValidate) { - public FalseValidator() - { - Actions.Add(new ErrorMessageAction("error", "errors")); - } + return false; + } +} - /// - /// Validates test object. - /// - /// Object to validate. - /// True if specified object is valid, False otherwise. - protected override bool Validate(object objectToValidate) - { - return false; - } +public sealed class MockObjectDefinitionRegistry : IObjectDefinitionRegistry +{ + private readonly IDictionary objects = new Dictionary(); + + public int ObjectDefinitionCount => objects.Count; + + public IReadOnlyList GetObjectDefinitionNames() + { + return new List(objects.Keys); } - public sealed class MockObjectDefinitionRegistry : IObjectDefinitionRegistry + public IReadOnlyList GetObjectDefinitionNames(bool includeAncestor) { - private readonly IDictionary objects = new Dictionary(); - - public int ObjectDefinitionCount => objects.Count; - - public IReadOnlyList GetObjectDefinitionNames() - { - return new List(objects.Keys); - } - - public IReadOnlyList GetObjectDefinitionNames(bool includeAncestor) - { - return new List(objects.Keys); - } - - public IList GetObjectDefinitions() - { - return new List(objects.Values); - } - - public bool ContainsObjectDefinition(string name) - { - return objects.ContainsKey(name); - } - - public IObjectDefinition GetObjectDefinition(string name) - { - objects.TryGetValue(name, out var definition); - return definition; - } - - public void RegisterObjectDefinition(string name, IObjectDefinition definition) - { - objects[name] = definition; - } - - public IReadOnlyList GetAliases(string name) - { - throw new NotImplementedException(); - } - - public void RegisterAlias(string name, string theAlias) - { - throw new NotImplementedException(); - } - - public bool IsObjectNameInUse(string objectName) - { - return objects[objectName] != null; - } + return new List(objects.Keys); } -} \ No newline at end of file + + public IList GetObjectDefinitions() + { + return new List(objects.Values); + } + + public bool ContainsObjectDefinition(string name) + { + return objects.ContainsKey(name); + } + + public IObjectDefinition GetObjectDefinition(string name) + { + objects.TryGetValue(name, out var definition); + return definition; + } + + public void RegisterObjectDefinition(string name, IObjectDefinition definition) + { + objects[name] = definition; + } + + public IReadOnlyList GetAliases(string name) + { + throw new NotImplementedException(); + } + + public void RegisterAlias(string name, string theAlias) + { + throw new NotImplementedException(); + } + + public bool IsObjectNameInUse(string objectName) + { + return objects[objectName] != null; + } +} diff --git a/test/Spring/Spring.Core.Tests/Validation/ValidationErrorsTests.cs b/test/Spring/Spring.Core.Tests/Validation/ValidationErrorsTests.cs index f1dcbe78..838544f8 100644 --- a/test/Spring/Spring.Core.Tests/Validation/ValidationErrorsTests.cs +++ b/test/Spring/Spring.Core.Tests/Validation/ValidationErrorsTests.cs @@ -22,168 +22,166 @@ using System.Xml.Serialization; using NUnit.Framework; - using Spring.Context.Support; #endregion -namespace Spring.Validation +namespace Spring.Validation; + +/// +/// Unit tests for the ValidationErrors class. +/// +/// Rick Evans +/// Goran Milosavljevic +[TestFixture] +public sealed class ValidationErrorsTests { - /// - /// Unit tests for the ValidationErrors class. - /// - /// Rick Evans - /// Goran Milosavljevic - [TestFixture] - public sealed class ValidationErrorsTests - { - private const string GoodErrorKey = "key"; - private ErrorMessage ErrorMessageTwo = new ErrorMessage("This Is Eva Green", null); - private ErrorMessage ErrorMessageOne = new ErrorMessage("Kissing Leads To Brain Disease", null); + private const string GoodErrorKey = "key"; + private ErrorMessage ErrorMessageTwo = new ErrorMessage("This Is Eva Green", null); + private ErrorMessage ErrorMessageOne = new ErrorMessage("Kissing Leads To Brain Disease", null); - [Test] - public void ResolveErrorsWithoutMessageSource() - { - ValidationErrors errors = new ValidationErrors(); - errors.AddError(string.Empty, ErrorMessageOne); - IList resolvedErrors = errors.GetResolvedErrors(string.Empty, null); - Assert.AreEqual(ErrorMessageOne.Id, (string)resolvedErrors[0]); - } - [Test] - public void ContainsNoErrorsDirectlyAfterInstantiation() - { - IValidationErrors errors = new ValidationErrors(); - Assert.IsTrue(errors.IsEmpty); - Assert.IsNotNull(errors.GetErrors(GoodErrorKey)); - } + [Test] + public void ResolveErrorsWithoutMessageSource() + { + ValidationErrors errors = new ValidationErrors(); + errors.AddError(string.Empty, ErrorMessageOne); + IList resolvedErrors = errors.GetResolvedErrors(string.Empty, null); + Assert.AreEqual(ErrorMessageOne.Id, (string) resolvedErrors[0]); + } - [Test] - public void AddErrorWithNullMessage() - { - Assert.Throws(() => new ValidationErrors().AddError(GoodErrorKey, null)); - } + [Test] + public void ContainsNoErrorsDirectlyAfterInstantiation() + { + IValidationErrors errors = new ValidationErrors(); + Assert.IsTrue(errors.IsEmpty); + Assert.IsNotNull(errors.GetErrors(GoodErrorKey)); + } - [Test] - public void AddErrorWithNullKey() - { - IValidationErrors errors = new ValidationErrors(); - Assert.Throws(() => errors.AddError(null, ErrorMessageOne)); - } + [Test] + public void AddErrorWithNullMessage() + { + Assert.Throws(() => new ValidationErrors().AddError(GoodErrorKey, null)); + } - [Test] - public void AddErrorSunnyDay() - { - IValidationErrors errors = new ValidationErrors(); - errors.AddError(GoodErrorKey, ErrorMessageOne); - Assert.IsFalse(errors.IsEmpty); - Assert.IsNotNull(errors.GetErrors(GoodErrorKey)); - Assert.AreEqual(1, errors.GetErrors(GoodErrorKey).Count); - } + [Test] + public void AddErrorWithNullKey() + { + IValidationErrors errors = new ValidationErrors(); + Assert.Throws(() => errors.AddError(null, ErrorMessageOne)); + } - [Test] - public void AddTwoErrorsSameKey() - { - IValidationErrors errors = new ValidationErrors(); - errors.AddError(GoodErrorKey, ErrorMessageOne); - errors.AddError(GoodErrorKey, ErrorMessageTwo); - Assert.IsFalse(errors.IsEmpty); - Assert.IsNotNull(errors.GetErrors(GoodErrorKey)); - Assert.AreEqual(2, errors.GetErrors(GoodErrorKey).Count); - } + [Test] + public void AddErrorSunnyDay() + { + IValidationErrors errors = new ValidationErrors(); + errors.AddError(GoodErrorKey, ErrorMessageOne); + Assert.IsFalse(errors.IsEmpty); + Assert.IsNotNull(errors.GetErrors(GoodErrorKey)); + Assert.AreEqual(1, errors.GetErrors(GoodErrorKey).Count); + } - [Test] - public void EmptyErrorsReturnEmptyCollections() - { - IValidationErrors errors = new ValidationErrors(); + [Test] + public void AddTwoErrorsSameKey() + { + IValidationErrors errors = new ValidationErrors(); + errors.AddError(GoodErrorKey, ErrorMessageOne); + errors.AddError(GoodErrorKey, ErrorMessageTwo); + Assert.IsFalse(errors.IsEmpty); + Assert.IsNotNull(errors.GetErrors(GoodErrorKey)); + Assert.AreEqual(2, errors.GetErrors(GoodErrorKey).Count); + } - IList typedErrors = errors.GetErrors("xyz"); - Assert.IsNotNull(typedErrors); - Assert.AreEqual(0, typedErrors.Count); + [Test] + public void EmptyErrorsReturnEmptyCollections() + { + IValidationErrors errors = new ValidationErrors(); - IList resolvedErrors = errors.GetResolvedErrors("xyz", new NullMessageSource()); - Assert.IsNotNull(resolvedErrors); - Assert.AreEqual(0, resolvedErrors.Count); - } + IList typedErrors = errors.GetErrors("xyz"); + Assert.IsNotNull(typedErrors); + Assert.AreEqual(0, typedErrors.Count); - [Test] - public void MergeErrorsWithNull() - { - IValidationErrors errors = new ValidationErrors(); - errors.AddError(GoodErrorKey, ErrorMessageOne); - errors.AddError(GoodErrorKey, ErrorMessageTwo); - errors.MergeErrors(null); + IList resolvedErrors = errors.GetResolvedErrors("xyz", new NullMessageSource()); + Assert.IsNotNull(resolvedErrors); + Assert.AreEqual(0, resolvedErrors.Count); + } - // must be unchanged with no Exception thrown... - Assert.IsFalse(errors.IsEmpty); - Assert.IsNotNull(errors.GetErrors(GoodErrorKey)); - Assert.AreEqual(2, errors.GetErrors(GoodErrorKey).Count); - } + [Test] + public void MergeErrorsWithNull() + { + IValidationErrors errors = new ValidationErrors(); + errors.AddError(GoodErrorKey, ErrorMessageOne); + errors.AddError(GoodErrorKey, ErrorMessageTwo); + errors.MergeErrors(null); - [Test] - public void MergeErrors() - { - ValidationErrors otherErrors = new ValidationErrors(); - const string anotherKey = "anotherKey"; - otherErrors.AddError(anotherKey, ErrorMessageTwo); - otherErrors.AddError(GoodErrorKey, ErrorMessageTwo); + // must be unchanged with no Exception thrown... + Assert.IsFalse(errors.IsEmpty); + Assert.IsNotNull(errors.GetErrors(GoodErrorKey)); + Assert.AreEqual(2, errors.GetErrors(GoodErrorKey).Count); + } + [Test] + public void MergeErrors() + { + ValidationErrors otherErrors = new ValidationErrors(); + const string anotherKey = "anotherKey"; + otherErrors.AddError(anotherKey, ErrorMessageTwo); + otherErrors.AddError(GoodErrorKey, ErrorMessageTwo); - IValidationErrors errors = new ValidationErrors(); - errors.AddError(GoodErrorKey, ErrorMessageOne); - errors.MergeErrors(otherErrors); + IValidationErrors errors = new ValidationErrors(); + errors.AddError(GoodErrorKey, ErrorMessageOne); + errors.MergeErrors(otherErrors); - Assert.IsFalse(errors.IsEmpty); - IList mergedErrors = errors.GetErrors(GoodErrorKey); - Assert.IsNotNull(mergedErrors); - Assert.AreEqual(2, mergedErrors.Count); - Assert.AreEqual(ErrorMessageOne, mergedErrors[0]); - Assert.AreEqual(ErrorMessageTwo, mergedErrors[1]); + Assert.IsFalse(errors.IsEmpty); + IList mergedErrors = errors.GetErrors(GoodErrorKey); + Assert.IsNotNull(mergedErrors); + Assert.AreEqual(2, mergedErrors.Count); + Assert.AreEqual(ErrorMessageOne, mergedErrors[0]); + Assert.AreEqual(ErrorMessageTwo, mergedErrors[1]); - IList otherErrorsForKey = errors.GetErrors(anotherKey); - Assert.IsNotNull(otherErrorsForKey); - Assert.AreEqual(1, otherErrorsForKey.Count); - Assert.AreEqual(ErrorMessageTwo, otherErrorsForKey[0]); - } + IList otherErrorsForKey = errors.GetErrors(anotherKey); + Assert.IsNotNull(otherErrorsForKey); + Assert.AreEqual(1, otherErrorsForKey.Count); + Assert.AreEqual(ErrorMessageTwo, otherErrorsForKey[0]); + } - [Test] - public void SerializeErrors() - { - ValidationErrors errors = new ValidationErrors(); - ErrorMessageOne = new ErrorMessage("Kissing Leads To Brain Disease", new object[] {"Param11", 5, "Param13"}); - ErrorMessageTwo = new ErrorMessage("This Is Eva Green", new object[] { "Param21", 'g' , new object[] {"Goran", "Milosavljevic"} }); - ErrorMessage ErrorMessageThree = new ErrorMessage("Third error message", null); - ErrorMessage ErrorMessageFour = new ErrorMessage("Fourth error message", new object[]{}); - errors.AddError("key1", ErrorMessageOne); - errors.AddError("key1", ErrorMessageTwo); - errors.AddError("key2", ErrorMessageThree); - errors.AddError("key3", ErrorMessageFour); + [Test] + public void SerializeErrors() + { + ValidationErrors errors = new ValidationErrors(); + ErrorMessageOne = new ErrorMessage("Kissing Leads To Brain Disease", new object[] { "Param11", 5, "Param13" }); + ErrorMessageTwo = new ErrorMessage("This Is Eva Green", new object[] { "Param21", 'g', new object[] { "Goran", "Milosavljevic" } }); + ErrorMessage ErrorMessageThree = new ErrorMessage("Third error message", null); + ErrorMessage ErrorMessageFour = new ErrorMessage("Fourth error message", new object[] { }); + errors.AddError("key1", ErrorMessageOne); + errors.AddError("key1", ErrorMessageTwo); + errors.AddError("key2", ErrorMessageThree); + errors.AddError("key3", ErrorMessageFour); - Stream streamBefore = new MemoryStream(); - Stream streamAfter = new MemoryStream(); + Stream streamBefore = new MemoryStream(); + Stream streamAfter = new MemoryStream(); - // serialize ValidationErrors - XmlSerializer serializer = new XmlSerializer(typeof(ValidationErrors)); - serializer.Serialize(streamBefore, errors); - streamBefore.Position = 0; + // serialize ValidationErrors + XmlSerializer serializer = new XmlSerializer(typeof(ValidationErrors)); + serializer.Serialize(streamBefore, errors); + streamBefore.Position = 0; - // deserialize ValidationErrors - ValidationErrors result = (ValidationErrors) serializer.Deserialize(streamBefore); - - // serialize ValidationErrors - serializer.Serialize(streamAfter, result); - - // compare ValidationErrors instances - byte[] byteBefore = new byte[streamBefore.Length]; - byte[] byteAfter = new byte[streamAfter.Length]; - - Assert.AreEqual(byteAfter.Length, byteBefore.Length); - - streamBefore.Position = 0; - streamAfter.Position = 0; - streamBefore.Read(byteBefore, 0, (int) streamBefore.Length); - streamAfter.Read(byteAfter, 0, (int) streamAfter.Length); - - Assert.AreEqual(byteBefore, byteAfter); - } - } -} + // deserialize ValidationErrors + ValidationErrors result = (ValidationErrors) serializer.Deserialize(streamBefore); + + // serialize ValidationErrors + serializer.Serialize(streamAfter, result); + + // compare ValidationErrors instances + byte[] byteBefore = new byte[streamBefore.Length]; + byte[] byteAfter = new byte[streamAfter.Length]; + + Assert.AreEqual(byteAfter.Length, byteBefore.Length); + + streamBefore.Position = 0; + streamAfter.Position = 0; + streamBefore.Read(byteBefore, 0, (int) streamBefore.Length); + streamAfter.Read(byteAfter, 0, (int) streamAfter.Length); + + Assert.AreEqual(byteBefore, byteAfter); + } +} \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/Validation/ValidationExceptionTests.cs b/test/Spring/Spring.Core.Tests/Validation/ValidationExceptionTests.cs index d4f41fba..af6b97f8 100644 --- a/test/Spring/Spring.Core.Tests/Validation/ValidationExceptionTests.cs +++ b/test/Spring/Spring.Core.Tests/Validation/ValidationExceptionTests.cs @@ -21,63 +21,62 @@ using System.Runtime.Serialization.Formatters.Binary; using NUnit.Framework; -namespace Spring.Validation +namespace Spring.Validation; + +/// +/// Unit tests for the ValidationException class. +/// +/// Aleksandar Seovic +[TestFixture] +public sealed class ValidationExceptionTests { - /// - /// Unit tests for the ValidationException class. - /// - /// Aleksandar Seovic - [TestFixture] - public sealed class ValidationExceptionTests - { - [Test] - public void InstantiationUsingDefaultConstructor() - { - ValidationException ex = new ValidationException(); - Assert.IsNull(ex.ValidationErrors); - } - - [Test] - public void InstantiationSupplyingValidationErrors() - { - ValidationException ex = new ValidationException(new ValidationErrors()); - Assert.IsTrue(ex.ValidationErrors.IsEmpty); - } + [Test] + public void InstantiationUsingDefaultConstructor() + { + ValidationException ex = new ValidationException(); + Assert.IsNull(ex.ValidationErrors); + } - [Test] - public void InstantiationSupplyingMessageAndValidationErrors() - { - ValidationException ex = new ValidationException("my message", new ValidationErrors()); - Assert.AreEqual("my message", ex.Message); - Assert.IsTrue(ex.ValidationErrors.IsEmpty); - } - - [Test] - public void InstantiationSupplyingMessageValidationErrorsAndRootCause() - { - Exception rootCause = new Exception("root cause"); - ValidationException ex = new ValidationException("my message", rootCause, new ValidationErrors()); - Assert.AreEqual("my message", ex.Message); - Assert.IsTrue(ex.ValidationErrors.IsEmpty); - Assert.AreEqual(rootCause, ex.InnerException); - Assert.AreEqual("root cause", ex.InnerException.Message); - } + [Test] + public void InstantiationSupplyingValidationErrors() + { + ValidationException ex = new ValidationException(new ValidationErrors()); + Assert.IsTrue(ex.ValidationErrors.IsEmpty); + } - [Test] - public void TestExceptionSerialization() - { - MemoryStream buffer = new MemoryStream(); - BinaryFormatter serializer = new BinaryFormatter(); + [Test] + public void InstantiationSupplyingMessageAndValidationErrors() + { + ValidationException ex = new ValidationException("my message", new ValidationErrors()); + Assert.AreEqual("my message", ex.Message); + Assert.IsTrue(ex.ValidationErrors.IsEmpty); + } - Exception rootCause = new Exception("root cause"); - ValidationException e1 = new ValidationException("my message", rootCause, new ValidationErrors()); - serializer.Serialize(buffer, e1); - buffer.Position = 0; - ValidationException e2 = (ValidationException)serializer.Deserialize(buffer); + [Test] + public void InstantiationSupplyingMessageValidationErrorsAndRootCause() + { + Exception rootCause = new Exception("root cause"); + ValidationException ex = new ValidationException("my message", rootCause, new ValidationErrors()); + Assert.AreEqual("my message", ex.Message); + Assert.IsTrue(ex.ValidationErrors.IsEmpty); + Assert.AreEqual(rootCause, ex.InnerException); + Assert.AreEqual("root cause", ex.InnerException.Message); + } - Assert.AreEqual("my message", e2.Message); - Assert.IsTrue(e2.ValidationErrors.IsEmpty); - Assert.AreEqual("root cause", e2.InnerException.Message); - } - } -} \ No newline at end of file + [Test] + public void TestExceptionSerialization() + { + MemoryStream buffer = new MemoryStream(); + BinaryFormatter serializer = new BinaryFormatter(); + + Exception rootCause = new Exception("root cause"); + ValidationException e1 = new ValidationException("my message", rootCause, new ValidationErrors()); + serializer.Serialize(buffer, e1); + buffer.Position = 0; + ValidationException e2 = (ValidationException) serializer.Deserialize(buffer); + + Assert.AreEqual("my message", e2.Message); + Assert.IsTrue(e2.ValidationErrors.IsEmpty); + Assert.AreEqual("root cause", e2.InnerException.Message); + } +} diff --git a/test/Spring/Spring.Core.Tests/Validation/ValidationNamespaceParserTests.cs b/test/Spring/Spring.Core.Tests/Validation/ValidationNamespaceParserTests.cs index b6f6c60c..8874667b 100644 --- a/test/Spring/Spring.Core.Tests/Validation/ValidationNamespaceParserTests.cs +++ b/test/Spring/Spring.Core.Tests/Validation/ValidationNamespaceParserTests.cs @@ -21,9 +21,7 @@ #region Imports using System.Xml; - using NUnit.Framework; - using Spring.Core.IO; using Spring.Objects; using Spring.Objects.Factory; @@ -34,115 +32,115 @@ using Spring.Validation.Config; #endregion -namespace Spring.Validation +namespace Spring.Validation; + +/// +/// Unit tests for the ValidationNamespaceParser class. +/// +/// Rick Evans +[TestFixture] +public sealed class ValidationNamespaceParserTests { - /// - /// Unit tests for the ValidationNamespaceParser class. - /// - /// Rick Evans - [TestFixture] - public sealed class ValidationNamespaceParserTests + [Test] + public void WhenConfigFileIsValid() { - [Test] - public void WhenConfigFileIsValid() + XmlDocument doc = GetValidatedXmlResource("_WhenConfigFileIsValid.xml"); + + MockObjectDefinitionRegistry registry = new MockObjectDefinitionRegistry(); + + XmlReaderContext readerContext = new XmlReaderContext(null, new XmlObjectDefinitionReader(registry)); + ObjectDefinitionParserHelper helper = new ObjectDefinitionParserHelper(readerContext); + helper.InitDefaults(doc.DocumentElement); + ParserContext parserContext = new ParserContext(helper); + + ValidationNamespaceParser parser = new ValidationNamespaceParser(); + foreach (XmlElement element in doc.DocumentElement.ChildNodes) { - XmlDocument doc = GetValidatedXmlResource("_WhenConfigFileIsValid.xml"); - - MockObjectDefinitionRegistry registry = new MockObjectDefinitionRegistry(); - - XmlReaderContext readerContext = new XmlReaderContext(null, new XmlObjectDefinitionReader(registry)); - ObjectDefinitionParserHelper helper = new ObjectDefinitionParserHelper(readerContext); - helper.InitDefaults(doc.DocumentElement); - ParserContext parserContext = new ParserContext(helper); - - ValidationNamespaceParser parser = new ValidationNamespaceParser(); - foreach (XmlElement element in doc.DocumentElement.ChildNodes) + if (element.NamespaceURI == "http://www.springframework.net/validation") { - if (element.NamespaceURI == "http://www.springframework.net/validation") - { - parser.ParseElement(element, parserContext); - } + parser.ParseElement(element, parserContext); } - IList defs = registry.GetObjectDefinitions(); - Assert.AreEqual(9, defs.Count); - - IObjectDefinition def = registry.GetObjectDefinition("destinationAirportValidator"); - Assert.IsTrue(def.IsSingleton); - Assert.IsTrue(def.IsLazyInit); - Assert.IsTrue(typeof(IValidator).IsAssignableFrom(def.ObjectType)); - - PropertyValue fastValidateProperty = def.PropertyValues.GetPropertyValue("FastValidate"); - Assert.IsNotNull(fastValidateProperty); - Assert.AreEqual("true", fastValidateProperty.Value); - - PropertyValue validatorsProperty = def.PropertyValues.GetPropertyValue("Validators"); - Assert.IsNotNull(validatorsProperty); - object validatorsObject = validatorsProperty.Value; - Assert.AreEqual(typeof(ManagedList), validatorsObject.GetType()); - ManagedList validators = (ManagedList)validatorsObject; - Assert.AreEqual(4, validators.Count); - - def = (IObjectDefinition)validators[3]; - Assert.IsTrue(def.IsSingleton); - Assert.IsTrue(def.IsLazyInit); - Assert.AreEqual(typeof(RegularExpressionValidator), def.ObjectType); - Assert.AreEqual("[A-Z]*", def.PropertyValues.GetPropertyValue("Expression").Value); - - - def = registry.GetObjectDefinition("simpleAirportValidator"); - Assert.IsTrue(def.IsSingleton); - Assert.IsTrue(def.IsLazyInit); - Assert.IsTrue(typeof(IValidator).IsAssignableFrom(def.ObjectType)); - PropertyValue actionsProperty = def.PropertyValues.GetPropertyValue("Actions"); - Assert.IsNotNull(actionsProperty); - object actionsObject = actionsProperty.Value; - Assert.AreEqual(typeof(ManagedList), actionsObject.GetType()); - ManagedList actions = (ManagedList)actionsObject; - Assert.AreEqual(1, actions.Count); - - IObjectDefinition exceptionActionDefinition = (IObjectDefinition)actions[0]; - Assert.AreEqual(typeof(ExceptionAction), exceptionActionDefinition.ObjectType); - Assert.AreEqual("'new System.InvalidOperationException(\"invalid\")' []", exceptionActionDefinition.ConstructorArgumentValues.GenericArgumentValues[0].ToString()); - // - - def = registry.GetObjectDefinition("airportCodeValidator"); - Assert.IsTrue(def.IsSingleton); - Assert.IsTrue(def.IsLazyInit); - Assert.IsTrue(typeof(IValidator).IsAssignableFrom(def.ObjectType)); - actionsProperty = def.PropertyValues.GetPropertyValue("Actions"); - Assert.IsNotNull(actionsProperty); - actionsObject = actionsProperty.Value; - Assert.AreEqual(typeof(ManagedList), actionsObject.GetType()); - actions = (ManagedList)actionsObject; - Assert.AreEqual(4, actions.Count); - - IObjectDefinition messageDefinition = (IObjectDefinition)actions[1]; - Assert.AreEqual(typeof(ErrorMessageAction), messageDefinition.ObjectType); - - IObjectDefinition actionDefinition = (IObjectDefinition)actions[2]; - Assert.AreEqual(typeof(ExpressionAction), actionDefinition.ObjectType); - Assert.AreEqual("#now = DateTime.Now", actionDefinition.PropertyValues.GetPropertyValue("Valid").Value); - - def = registry.GetObjectDefinition("regex"); - Assert.IsTrue(def.IsSingleton); - Assert.IsTrue(def.IsLazyInit); - Assert.IsTrue(typeof(IValidator).IsAssignableFrom(def.ObjectType)); - PropertyValue expressionProperty = def.PropertyValues.GetPropertyValue("Expression"); - Assert.IsNotNull(expressionProperty); - Assert.AreEqual("RegExp", expressionProperty.Value); } - private XmlDocument GetValidatedXmlResource(string resourceExtension) - { - AssemblyResource validationSchema = new AssemblyResource("assembly://Spring.Core/Spring.Validation.Config/spring-validation-1.3.xsd"); - AssemblyResource objectsSchema = new AssemblyResource("assembly://Spring.Core/Spring.Objects.Factory.Xml/spring-objects-1.3.xsd"); + IList defs = registry.GetObjectDefinitions(); + Assert.AreEqual(9, defs.Count); - return TestResourceLoader.GetXmlValidated(this, resourceExtension, objectsSchema, validationSchema); - } + IObjectDefinition def = registry.GetObjectDefinition("destinationAirportValidator"); + Assert.IsTrue(def.IsSingleton); + Assert.IsTrue(def.IsLazyInit); + Assert.IsTrue(typeof(IValidator).IsAssignableFrom(def.ObjectType)); - [Test] - public void WhenConfigFileIsNotValid() - { + PropertyValue fastValidateProperty = def.PropertyValues.GetPropertyValue("FastValidate"); + Assert.IsNotNull(fastValidateProperty); + Assert.AreEqual("true", fastValidateProperty.Value); + + PropertyValue validatorsProperty = def.PropertyValues.GetPropertyValue("Validators"); + Assert.IsNotNull(validatorsProperty); + object validatorsObject = validatorsProperty.Value; + Assert.AreEqual(typeof(ManagedList), validatorsObject.GetType()); + ManagedList validators = (ManagedList) validatorsObject; + Assert.AreEqual(4, validators.Count); + + def = (IObjectDefinition) validators[3]; + Assert.IsTrue(def.IsSingleton); + Assert.IsTrue(def.IsLazyInit); + Assert.AreEqual(typeof(RegularExpressionValidator), def.ObjectType); + Assert.AreEqual("[A-Z]*", def.PropertyValues.GetPropertyValue("Expression").Value); + + def = registry.GetObjectDefinition("simpleAirportValidator"); + Assert.IsTrue(def.IsSingleton); + Assert.IsTrue(def.IsLazyInit); + Assert.IsTrue(typeof(IValidator).IsAssignableFrom(def.ObjectType)); + PropertyValue actionsProperty = def.PropertyValues.GetPropertyValue("Actions"); + Assert.IsNotNull(actionsProperty); + object actionsObject = actionsProperty.Value; + Assert.AreEqual(typeof(ManagedList), actionsObject.GetType()); + ManagedList actions = (ManagedList) actionsObject; + Assert.AreEqual(1, actions.Count); + + IObjectDefinition exceptionActionDefinition = (IObjectDefinition) actions[0]; + Assert.AreEqual(typeof(ExceptionAction), exceptionActionDefinition.ObjectType); + Assert.AreEqual("'new System.InvalidOperationException(\"invalid\")' []", exceptionActionDefinition.ConstructorArgumentValues.GenericArgumentValues[0].ToString()); + // + + def = registry.GetObjectDefinition("airportCodeValidator"); + Assert.IsTrue(def.IsSingleton); + Assert.IsTrue(def.IsLazyInit); + Assert.IsTrue(typeof(IValidator).IsAssignableFrom(def.ObjectType)); + actionsProperty = def.PropertyValues.GetPropertyValue("Actions"); + Assert.IsNotNull(actionsProperty); + actionsObject = actionsProperty.Value; + Assert.AreEqual(typeof(ManagedList), actionsObject.GetType()); + actions = (ManagedList) actionsObject; + Assert.AreEqual(4, actions.Count); + + IObjectDefinition messageDefinition = (IObjectDefinition) actions[1]; + Assert.AreEqual(typeof(ErrorMessageAction), messageDefinition.ObjectType); + + IObjectDefinition actionDefinition = (IObjectDefinition) actions[2]; + Assert.AreEqual(typeof(ExpressionAction), actionDefinition.ObjectType); + Assert.AreEqual("#now = DateTime.Now", actionDefinition.PropertyValues.GetPropertyValue("Valid").Value); + + def = registry.GetObjectDefinition("regex"); + Assert.IsTrue(def.IsSingleton); + Assert.IsTrue(def.IsLazyInit); + Assert.IsTrue(typeof(IValidator).IsAssignableFrom(def.ObjectType)); + PropertyValue expressionProperty = def.PropertyValues.GetPropertyValue("Expression"); + Assert.IsNotNull(expressionProperty); + Assert.AreEqual("RegExp", expressionProperty.Value); + } + + private XmlDocument GetValidatedXmlResource(string resourceExtension) + { + AssemblyResource validationSchema = new AssemblyResource("assembly://Spring.Core/Spring.Validation.Config/spring-validation-1.3.xsd"); + AssemblyResource objectsSchema = new AssemblyResource("assembly://Spring.Core/Spring.Objects.Factory.Xml/spring-objects-1.3.xsd"); + + return TestResourceLoader.GetXmlValidated(this, resourceExtension, objectsSchema, validationSchema); + } + + [Test] + public void WhenConfigFileIsNotValid() + { // const string xml = @" // // @@ -151,26 +149,25 @@ namespace Spring.Validation // // //"; - XmlDocument doc = GetValidatedXmlResource("_WhenConfigFileIsNotValid.xml"); + XmlDocument doc = GetValidatedXmlResource("_WhenConfigFileIsNotValid.xml"); - MockObjectDefinitionRegistry registry = new MockObjectDefinitionRegistry(); + MockObjectDefinitionRegistry registry = new MockObjectDefinitionRegistry(); - XmlReaderContext readerContext = new XmlReaderContext(null, new XmlObjectDefinitionReader(registry)); - ObjectDefinitionParserHelper helper = new ObjectDefinitionParserHelper(readerContext); - helper.InitDefaults(doc.DocumentElement); - ParserContext parserContext = new ParserContext(helper); + XmlReaderContext readerContext = new XmlReaderContext(null, new XmlObjectDefinitionReader(registry)); + ObjectDefinitionParserHelper helper = new ObjectDefinitionParserHelper(readerContext); + helper.InitDefaults(doc.DocumentElement); + ParserContext parserContext = new ParserContext(helper); - ValidationNamespaceParser parser = new ValidationNamespaceParser(); - Assert.Throws(() => + ValidationNamespaceParser parser = new ValidationNamespaceParser(); + Assert.Throws(() => + { + foreach (XmlElement element in doc.DocumentElement.ChildNodes) { - foreach (XmlElement element in doc.DocumentElement.ChildNodes) + if (element.NamespaceURI == "http://www.springframework.net/validation") { - if (element.NamespaceURI == "http://www.springframework.net/validation") - { - parser.ParseElement(element, parserContext); - } + parser.ParseElement(element, parserContext); } - }); - } + } + }); } -} \ No newline at end of file +} diff --git a/test/Spring/Spring.Core.Tests/Validation/ValidationNamespaceParserTests_WhenConfigFileIsNotValid.xml b/test/Spring/Spring.Core.Tests/Validation/ValidationNamespaceParserTests_WhenConfigFileIsNotValid.xml index cc1b5b08..f971e90a 100644 --- a/test/Spring/Spring.Core.Tests/Validation/ValidationNamespaceParserTests_WhenConfigFileIsNotValid.xml +++ b/test/Spring/Spring.Core.Tests/Validation/ValidationNamespaceParserTests_WhenConfigFileIsNotValid.xml @@ -1,7 +1,7 @@  - - + + \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/Validation/ValidationNamespaceParserTests_WhenConfigFileIsValid.xml b/test/Spring/Spring.Core.Tests/Validation/ValidationNamespaceParserTests_WhenConfigFileIsValid.xml index fa4512c2..f82a0833 100644 --- a/test/Spring/Spring.Core.Tests/Validation/ValidationNamespaceParserTests_WhenConfigFileIsValid.xml +++ b/test/Spring/Spring.Core.Tests/Validation/ValidationNamespaceParserTests_WhenConfigFileIsValid.xml @@ -2,68 +2,69 @@ - - + + - - - + + + - + - - - + + + - + - + - + - + - - + + - + - - - + + + - - - + + + - - - + + + - - + + - + \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/Validation/ValidatorGroupTests.cs b/test/Spring/Spring.Core.Tests/Validation/ValidatorGroupTests.cs index f259f692..f57972ba 100644 --- a/test/Spring/Spring.Core.Tests/Validation/ValidatorGroupTests.cs +++ b/test/Spring/Spring.Core.Tests/Validation/ValidatorGroupTests.cs @@ -21,112 +21,109 @@ #region Imports using System.Collections; - using NUnit.Framework; - using Spring.Expressions; #endregion -namespace Spring.Validation +namespace Spring.Validation; + +/// +/// Unit tests for the ValidatorGroup class. +/// +/// Aleksandar Seovic +[TestFixture] +public sealed class ValidatorGroupTests : ValidatorGroup { - /// - /// Unit tests for the ValidatorGroup class. - /// - /// Aleksandar Seovic - [TestFixture] - public sealed class ValidatorGroupTests : ValidatorGroup + [Test] + public void WhenAllValidatorsReturnFalse() { - [Test] - public void WhenAllValidatorsReturnFalse() - { - ValidatorGroup vg = new ValidatorGroup(); - vg.Validators.Add(new FalseValidator()); - vg.Validators.Add(new FalseValidator()); - vg.Validators.Add(new FalseValidator()); + ValidatorGroup vg = new ValidatorGroup(); + vg.Validators.Add(new FalseValidator()); + vg.Validators.Add(new FalseValidator()); + vg.Validators.Add(new FalseValidator()); - IValidationErrors errors = new ValidationErrors(); - errors.AddError("existingErrors", new ErrorMessage("error", null)); + IValidationErrors errors = new ValidationErrors(); + errors.AddError("existingErrors", new ErrorMessage("error", null)); - bool valid = vg.Validate(new object(), errors); + bool valid = vg.Validate(new object(), errors); - Assert.IsFalse(valid, "Validation should fail when all inner validators return false."); - Assert.AreEqual(3, errors.GetErrors("errors").Count); - Assert.AreEqual(1, errors.GetErrors("existingErrors").Count); - } - - [Test] - public void WhenAllValidatorsReturnFalseFast() - { - ValidatorGroup vg = new ValidatorGroup(); - vg.FastValidate = true; - vg.Validators.Add(new FalseValidator()); - vg.Validators.Add(new FalseValidator()); - vg.Validators.Add(new FalseValidator()); - - IValidationErrors errors = new ValidationErrors(); - errors.AddError("existingErrors", new ErrorMessage("error", null)); - - bool valid = vg.Validate(new object(), errors); - - Assert.IsFalse(valid, "Validation should fail when all inner validators return false."); - Assert.AreEqual(1, errors.GetErrors("errors").Count); - Assert.AreEqual(1, errors.GetErrors("existingErrors").Count); - } - - [Test] - public void WhenAllValidatorsReturnTrue() - { - ValidatorGroup vg = new ValidatorGroup("true"); - vg.Validators.Add(new TrueValidator()); - vg.Validators.Add(new TrueValidator()); - vg.Validators.Add(new TrueValidator()); - - IValidationErrors errors = new ValidationErrors(); - errors.AddError("existingErrors", new ErrorMessage("error", null)); - - bool valid = vg.Validate(new object(), errors); - - Assert.IsTrue(valid, "Validation should succeed when all inner validators return true."); - Assert.AreEqual(0, errors.GetErrors("errors").Count); - Assert.AreEqual(1, errors.GetErrors("existingErrors").Count); - } - - [Test] - public void WhenSingleValidatorReturnsTrue() - { - ValidatorGroup vg = new ValidatorGroup(Expression.Parse("true")); - vg.Validators.Add(new FalseValidator()); - vg.Validators.Add(new TrueValidator()); - vg.Validators.Add(new FalseValidator()); - - IValidationErrors errors = new ValidationErrors(); - errors.AddError("existingErrors", new ErrorMessage("error", null)); - - bool valid = vg.Validate(new object(), errors); - - Assert.IsFalse(valid, "Validation should fail when single inner validator returns true."); - Assert.AreEqual(2, errors.GetErrors("errors").Count); - Assert.AreEqual(1, errors.GetErrors("existingErrors").Count); - } - - [Test] - public void WhenGroupIsNotValidatedBecauseWhenExpressionReturnsFalse() - { - ValidatorGroup vg = new ValidatorGroup("false"); - IList validators = new ArrayList(); - validators.Add(new FalseValidator()); - validators.Add(new FalseValidator()); - vg.Validators = validators; - - IValidationErrors errors = new ValidationErrors(); - errors.AddError("existingErrors", new ErrorMessage("error", null)); - - bool valid = vg.Validate(new object(), errors); - - Assert.IsTrue(valid, "Validation should succeed when group validator is not evaluated."); - Assert.AreEqual(0, errors.GetErrors("errors").Count); - Assert.AreEqual(1, errors.GetErrors("existingErrors").Count); - } + Assert.IsFalse(valid, "Validation should fail when all inner validators return false."); + Assert.AreEqual(3, errors.GetErrors("errors").Count); + Assert.AreEqual(1, errors.GetErrors("existingErrors").Count); } -} \ No newline at end of file + + [Test] + public void WhenAllValidatorsReturnFalseFast() + { + ValidatorGroup vg = new ValidatorGroup(); + vg.FastValidate = true; + vg.Validators.Add(new FalseValidator()); + vg.Validators.Add(new FalseValidator()); + vg.Validators.Add(new FalseValidator()); + + IValidationErrors errors = new ValidationErrors(); + errors.AddError("existingErrors", new ErrorMessage("error", null)); + + bool valid = vg.Validate(new object(), errors); + + Assert.IsFalse(valid, "Validation should fail when all inner validators return false."); + Assert.AreEqual(1, errors.GetErrors("errors").Count); + Assert.AreEqual(1, errors.GetErrors("existingErrors").Count); + } + + [Test] + public void WhenAllValidatorsReturnTrue() + { + ValidatorGroup vg = new ValidatorGroup("true"); + vg.Validators.Add(new TrueValidator()); + vg.Validators.Add(new TrueValidator()); + vg.Validators.Add(new TrueValidator()); + + IValidationErrors errors = new ValidationErrors(); + errors.AddError("existingErrors", new ErrorMessage("error", null)); + + bool valid = vg.Validate(new object(), errors); + + Assert.IsTrue(valid, "Validation should succeed when all inner validators return true."); + Assert.AreEqual(0, errors.GetErrors("errors").Count); + Assert.AreEqual(1, errors.GetErrors("existingErrors").Count); + } + + [Test] + public void WhenSingleValidatorReturnsTrue() + { + ValidatorGroup vg = new ValidatorGroup(Expression.Parse("true")); + vg.Validators.Add(new FalseValidator()); + vg.Validators.Add(new TrueValidator()); + vg.Validators.Add(new FalseValidator()); + + IValidationErrors errors = new ValidationErrors(); + errors.AddError("existingErrors", new ErrorMessage("error", null)); + + bool valid = vg.Validate(new object(), errors); + + Assert.IsFalse(valid, "Validation should fail when single inner validator returns true."); + Assert.AreEqual(2, errors.GetErrors("errors").Count); + Assert.AreEqual(1, errors.GetErrors("existingErrors").Count); + } + + [Test] + public void WhenGroupIsNotValidatedBecauseWhenExpressionReturnsFalse() + { + ValidatorGroup vg = new ValidatorGroup("false"); + IList validators = new ArrayList(); + validators.Add(new FalseValidator()); + validators.Add(new FalseValidator()); + vg.Validators = validators; + + IValidationErrors errors = new ValidationErrors(); + errors.AddError("existingErrors", new ErrorMessage("error", null)); + + bool valid = vg.Validate(new object(), errors); + + Assert.IsTrue(valid, "Validation should succeed when group validator is not evaluated."); + Assert.AreEqual(0, errors.GetErrors("errors").Count); + Assert.AreEqual(1, errors.GetErrors("existingErrors").Count); + } +} diff --git a/test/Spring/Spring.Core.Tests/Validation/ValidatorReferenceTests.cs b/test/Spring/Spring.Core.Tests/Validation/ValidatorReferenceTests.cs index d436a42c..d7d79c48 100644 --- a/test/Spring/Spring.Core.Tests/Validation/ValidatorReferenceTests.cs +++ b/test/Spring/Spring.Core.Tests/Validation/ValidatorReferenceTests.cs @@ -19,100 +19,98 @@ #endregion using NUnit.Framework; - using Spring.Expressions; using Spring.Objects.Factory.Support; -namespace Spring.Validation +namespace Spring.Validation; + +/// +/// Unit tests for ValidatorReference class. +/// +/// Aleksandar Seovic +[TestFixture] +public class ValidatorReferenceTests { - /// - /// Unit tests for ValidatorReference class. - /// - /// Aleksandar Seovic - [TestFixture] - public class ValidatorReferenceTests + [Test] + public void TrueValidatorReference() { - [Test] - public void TrueValidatorReference() - { - StaticListableObjectFactory factory = new StaticListableObjectFactory(); - factory.AddObject("validator", new TrueValidator()); + StaticListableObjectFactory factory = new StaticListableObjectFactory(); + factory.AddObject("validator", new TrueValidator()); - ValidatorReference v = new ValidatorReference("true"); - v.ObjectFactory = factory; - v.Name = "validator"; + ValidatorReference v = new ValidatorReference("true"); + v.ObjectFactory = factory; + v.Name = "validator"; - IValidationErrors errors = new ValidationErrors(); + IValidationErrors errors = new ValidationErrors(); - Assert.IsTrue(v.Validate(null, null, errors)); - Assert.IsTrue(v.Validate(null, errors)); - } - - [Test] - public void FalseValidatorReference() - { - StaticListableObjectFactory factory = new StaticListableObjectFactory(); - factory.AddObject("validator", new FalseValidator()); - - ValidatorReference v = new ValidatorReference(); - v.ObjectFactory = factory; - v.Name = "validator"; - - IValidationErrors errors = new ValidationErrors(); - Assert.IsFalse(v.Validate(null, null, errors)); - Assert.IsFalse(v.Validate(null, errors)); - } - - [Test] - public void FalseValidatorReferenceNotEvaluatedBecauseWhenExpressionReturnsFalse() - { - StaticListableObjectFactory factory = new StaticListableObjectFactory(); - factory.AddObject("validator", new FalseValidator()); - - ValidatorReference v = new ValidatorReference("false"); - v.ObjectFactory = factory; - v.Name = "validator"; - - IValidationErrors errors = new ValidationErrors(); - Assert.IsTrue(v.Validate(null, null, errors)); - Assert.IsTrue(v.Validate(null, errors)); - } - - [Test] - public void ContextNarrowing() - { - Inventor context = new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian"); - - ConditionValidator cv1 = new ConditionValidator("DOB.Year == 1856", null); - ConditionValidator cv2 = new ConditionValidator("Year == 1856", null); - - StaticListableObjectFactory factory = new StaticListableObjectFactory(); - factory.AddObject("cv1", cv1); - factory.AddObject("cv2", cv2); - - ValidatorReference v1 = new ValidatorReference(); - v1.ObjectFactory = factory; - v1.Name = "cv1"; - - IValidationErrors errors = new ValidationErrors(); - - Assert.IsTrue(v1.Validate(context, null, errors)); - Assert.IsTrue(v1.Validate(context, errors)); - - ValidatorReference v2 = new ValidatorReference(); - v2.ObjectFactory = factory; - v2.Name = "cv2"; - v2.Context = Expression.Parse("DOB"); - - Assert.IsTrue(v2.Validate(context, null, errors)); - Assert.IsTrue(v2.Validate(context, errors)); - - ValidatorReference v3 = new ValidatorReference("false"); - v3.ObjectFactory = factory; - v3.Name = "cv2"; - v3.Context = Expression.Parse("DOB"); - - Assert.IsTrue(v3.Validate(null, errors)); - } + Assert.IsTrue(v.Validate(null, null, errors)); + Assert.IsTrue(v.Validate(null, errors)); } -} \ No newline at end of file + + [Test] + public void FalseValidatorReference() + { + StaticListableObjectFactory factory = new StaticListableObjectFactory(); + factory.AddObject("validator", new FalseValidator()); + + ValidatorReference v = new ValidatorReference(); + v.ObjectFactory = factory; + v.Name = "validator"; + + IValidationErrors errors = new ValidationErrors(); + Assert.IsFalse(v.Validate(null, null, errors)); + Assert.IsFalse(v.Validate(null, errors)); + } + + [Test] + public void FalseValidatorReferenceNotEvaluatedBecauseWhenExpressionReturnsFalse() + { + StaticListableObjectFactory factory = new StaticListableObjectFactory(); + factory.AddObject("validator", new FalseValidator()); + + ValidatorReference v = new ValidatorReference("false"); + v.ObjectFactory = factory; + v.Name = "validator"; + + IValidationErrors errors = new ValidationErrors(); + Assert.IsTrue(v.Validate(null, null, errors)); + Assert.IsTrue(v.Validate(null, errors)); + } + + [Test] + public void ContextNarrowing() + { + Inventor context = new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian"); + + ConditionValidator cv1 = new ConditionValidator("DOB.Year == 1856", null); + ConditionValidator cv2 = new ConditionValidator("Year == 1856", null); + + StaticListableObjectFactory factory = new StaticListableObjectFactory(); + factory.AddObject("cv1", cv1); + factory.AddObject("cv2", cv2); + + ValidatorReference v1 = new ValidatorReference(); + v1.ObjectFactory = factory; + v1.Name = "cv1"; + + IValidationErrors errors = new ValidationErrors(); + + Assert.IsTrue(v1.Validate(context, null, errors)); + Assert.IsTrue(v1.Validate(context, errors)); + + ValidatorReference v2 = new ValidatorReference(); + v2.ObjectFactory = factory; + v2.Name = "cv2"; + v2.Context = Expression.Parse("DOB"); + + Assert.IsTrue(v2.Validate(context, null, errors)); + Assert.IsTrue(v2.Validate(context, errors)); + + ValidatorReference v3 = new ValidatorReference("false"); + v3.ObjectFactory = factory; + v3.Name = "cv2"; + v3.Context = Expression.Parse("DOB"); + + Assert.IsTrue(v3.Validate(null, errors)); + } +} diff --git a/test/Spring/Spring.Core.Tests/Validation/Validators/ConditionValidatorTests.cs b/test/Spring/Spring.Core.Tests/Validation/Validators/ConditionValidatorTests.cs index 2ab311df..5aa33f69 100644 --- a/test/Spring/Spring.Core.Tests/Validation/Validators/ConditionValidatorTests.cs +++ b/test/Spring/Spring.Core.Tests/Validation/Validators/ConditionValidatorTests.cs @@ -21,77 +21,74 @@ #region Imports using NUnit.Framework; - using Spring.Context.Support; using Spring.Expressions; using Spring.Validation.Actions; #endregion -namespace Spring.Validation.Validators +namespace Spring.Validation.Validators; + +/// +/// Unit tests for the ConditionValidator class. +/// +/// Rick Evans +[TestFixture] +public sealed class ConditionValidatorTests { - /// - /// Unit tests for the ConditionValidator class. - /// - /// Rick Evans - [TestFixture] - public sealed class ConditionValidatorTests + [Test] + public void StraightTrue() { - [Test] - public void StraightTrue() - { - ConditionValidator validator = new ConditionValidator(); - validator.Test = Expression.Parse("true"); - Assert.IsTrue(validator.Validate(null, new ValidationErrors())); - } - - [Test] - public void StraightFalse() - { - ConditionValidator validator = new ConditionValidator("false", null); - Assert.IsFalse(validator.Validate(null, new ValidationErrors())); - } - - [Test] - public void TrueScalarExpression() - { - Inventor tesla = new Inventor(); - tesla.Name = "Nikola Tesla"; - - ConditionValidator validator = new ConditionValidator(Expression.Parse("Name == 'Nikola Tesla'"), null); - Assert.IsTrue(validator.Validate(tesla, new ValidationErrors())); - } - - [Test] - public void FalseScalarExpression() - { - Inventor tesla = new Inventor(); - tesla.Name = "Soltan Gris"; - - ConditionValidator validator = new ConditionValidator(Expression.Parse("Name == 'Nikola Tesla'"), null); - validator.Actions = new ErrorMessageAction[] {new ErrorMessageAction("Wrong name", "InventorValidator") }; - IValidationErrors errors = new ValidationErrors(); - Assert.IsFalse(validator.Validate(tesla, errors)); - Assert.IsFalse(errors.IsEmpty); - IList namedErrors = errors.GetResolvedErrors("InventorValidator", new NullMessageSource()); - Assert.AreEqual(1, namedErrors.Count); - string error = (string) namedErrors[0]; - Assert.AreEqual("Wrong name", error); - } - - [Test] - public void WhenValidatorIsNotEvaluatedBecauseWhenExpressionReturnsFalse() - { - ConditionValidator validator = new ConditionValidator(); - validator.Test = Expression.Parse("false"); - validator.When = Expression.Parse("false"); - IValidationErrors errors = new ValidationErrors(); - - bool valid = validator.Validate(new object(), null, errors); - - Assert.IsTrue(valid, "Validation should succeed when condition validator is not evaluated."); - Assert.AreEqual(0, errors.GetErrors("errors").Count); - } - + ConditionValidator validator = new ConditionValidator(); + validator.Test = Expression.Parse("true"); + Assert.IsTrue(validator.Validate(null, new ValidationErrors())); } -} \ No newline at end of file + + [Test] + public void StraightFalse() + { + ConditionValidator validator = new ConditionValidator("false", null); + Assert.IsFalse(validator.Validate(null, new ValidationErrors())); + } + + [Test] + public void TrueScalarExpression() + { + Inventor tesla = new Inventor(); + tesla.Name = "Nikola Tesla"; + + ConditionValidator validator = new ConditionValidator(Expression.Parse("Name == 'Nikola Tesla'"), null); + Assert.IsTrue(validator.Validate(tesla, new ValidationErrors())); + } + + [Test] + public void FalseScalarExpression() + { + Inventor tesla = new Inventor(); + tesla.Name = "Soltan Gris"; + + ConditionValidator validator = new ConditionValidator(Expression.Parse("Name == 'Nikola Tesla'"), null); + validator.Actions = new ErrorMessageAction[] { new ErrorMessageAction("Wrong name", "InventorValidator") }; + IValidationErrors errors = new ValidationErrors(); + Assert.IsFalse(validator.Validate(tesla, errors)); + Assert.IsFalse(errors.IsEmpty); + IList namedErrors = errors.GetResolvedErrors("InventorValidator", new NullMessageSource()); + Assert.AreEqual(1, namedErrors.Count); + string error = (string) namedErrors[0]; + Assert.AreEqual("Wrong name", error); + } + + [Test] + public void WhenValidatorIsNotEvaluatedBecauseWhenExpressionReturnsFalse() + { + ConditionValidator validator = new ConditionValidator(); + validator.Test = Expression.Parse("false"); + validator.When = Expression.Parse("false"); + IValidationErrors errors = new ValidationErrors(); + + bool valid = validator.Validate(new object(), null, errors); + + Assert.IsTrue(valid, "Validation should succeed when condition validator is not evaluated."); + Assert.AreEqual(0, errors.GetErrors("errors").Count); + } +} diff --git a/test/Spring/Spring.Core.Tests/Validation/Validators/CreditCardValidatorTests.cs b/test/Spring/Spring.Core.Tests/Validation/Validators/CreditCardValidatorTests.cs index 14e99d8d..73d28108 100644 --- a/test/Spring/Spring.Core.Tests/Validation/Validators/CreditCardValidatorTests.cs +++ b/test/Spring/Spring.Core.Tests/Validation/Validators/CreditCardValidatorTests.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -24,25 +24,24 @@ using NUnit.Framework; #endregion -namespace Spring.Validation.Validators +namespace Spring.Validation.Validators; + +/// +/// Unit tests for the UrlValidator class. +/// +/// Goran Milosavljevic +[TestFixture] +public sealed class CreditCardValidatorTests { - /// - /// Unit tests for the UrlValidator class. - /// - /// Goran Milosavljevic - [TestFixture] - public sealed class CreditCardValidatorTests - { - [Test] - public void Validate() - { - CreditCardValidator validator = new CreditCardValidator(); - validator.CardType = new Amex(); - Assert.IsTrue(validator.Validate("378282246310005", new ValidationErrors())); - Assert.IsFalse(validator.Validate("444444444", new ValidationErrors())); - Assert.IsTrue(validator.Validate(" ", new ValidationErrors())); - Assert.IsTrue(validator.Validate("", new ValidationErrors())); - Assert.IsTrue(validator.Validate(null, new ValidationErrors())); - } + [Test] + public void Validate() + { + CreditCardValidator validator = new CreditCardValidator(); + validator.CardType = new Amex(); + Assert.IsTrue(validator.Validate("378282246310005", new ValidationErrors())); + Assert.IsFalse(validator.Validate("444444444", new ValidationErrors())); + Assert.IsTrue(validator.Validate(" ", new ValidationErrors())); + Assert.IsTrue(validator.Validate("", new ValidationErrors())); + Assert.IsTrue(validator.Validate(null, new ValidationErrors())); } } diff --git a/test/Spring/Spring.Core.Tests/Validation/Validators/EmailValidatorTests.cs b/test/Spring/Spring.Core.Tests/Validation/Validators/EmailValidatorTests.cs index 4a9f789c..017966bd 100644 --- a/test/Spring/Spring.Core.Tests/Validation/Validators/EmailValidatorTests.cs +++ b/test/Spring/Spring.Core.Tests/Validation/Validators/EmailValidatorTests.cs @@ -24,32 +24,31 @@ using NUnit.Framework; #endregion -namespace Spring.Validation.Validators -{ - /// - /// Unit tests for the EmailValidator class. - /// - /// Goran Milosavljevic - [TestFixture] - public sealed class EmailValidatorTests - { - [Test] - public void Validate() - { - EmailValidator validator = new EmailValidator(); - Assert.IsTrue(validator.Validate("goran@eu.s4hc.com", new ValidationErrors())); - Assert.IsTrue(validator.Validate("goran.milosavljevic@s4hc.com", new ValidationErrors())); - Assert.IsTrue(validator.Validate("g.m.m@web_ask.com", new ValidationErrors())); +namespace Spring.Validation.Validators; - Assert.IsFalse(validator.Validate("@eu.s4hc.com", new ValidationErrors())); - Assert.IsFalse(validator.Validate("g @s4hc.com", new ValidationErrors())); - Assert.IsFalse(validator.Validate("g&@s", new ValidationErrors())); - Assert.IsFalse(validator.Validate("goran@s", new ValidationErrors())); - Assert.IsFalse(validator.Validate("goran@@", new ValidationErrors())); - Assert.IsFalse(validator.Validate("goran@eu s4hc.com", new ValidationErrors())); - Assert.IsTrue(validator.Validate(" ", new ValidationErrors())); - Assert.IsTrue(validator.Validate("", new ValidationErrors())); - Assert.IsTrue(validator.Validate(null, new ValidationErrors())); - } +/// +/// Unit tests for the EmailValidator class. +/// +/// Goran Milosavljevic +[TestFixture] +public sealed class EmailValidatorTests +{ + [Test] + public void Validate() + { + EmailValidator validator = new EmailValidator(); + Assert.IsTrue(validator.Validate("goran@eu.s4hc.com", new ValidationErrors())); + Assert.IsTrue(validator.Validate("goran.milosavljevic@s4hc.com", new ValidationErrors())); + Assert.IsTrue(validator.Validate("g.m.m@web_ask.com", new ValidationErrors())); + + Assert.IsFalse(validator.Validate("@eu.s4hc.com", new ValidationErrors())); + Assert.IsFalse(validator.Validate("g @s4hc.com", new ValidationErrors())); + Assert.IsFalse(validator.Validate("g&@s", new ValidationErrors())); + Assert.IsFalse(validator.Validate("goran@s", new ValidationErrors())); + Assert.IsFalse(validator.Validate("goran@@", new ValidationErrors())); + Assert.IsFalse(validator.Validate("goran@eu s4hc.com", new ValidationErrors())); + Assert.IsTrue(validator.Validate(" ", new ValidationErrors())); + Assert.IsTrue(validator.Validate("", new ValidationErrors())); + Assert.IsTrue(validator.Validate(null, new ValidationErrors())); } } diff --git a/test/Spring/Spring.Core.Tests/Validation/Validators/ISBNValidatorTests.cs b/test/Spring/Spring.Core.Tests/Validation/Validators/ISBNValidatorTests.cs index fe91c5f2..0eacd834 100644 --- a/test/Spring/Spring.Core.Tests/Validation/Validators/ISBNValidatorTests.cs +++ b/test/Spring/Spring.Core.Tests/Validation/Validators/ISBNValidatorTests.cs @@ -24,39 +24,38 @@ using NUnit.Framework; #endregion -namespace Spring.Validation.Validators +namespace Spring.Validation.Validators; + +/// +/// Unit tests for the ISBNValidator class. +/// +/// Goran Milosavljevic +[TestFixture] +public sealed class ISBNValidatorTests { - /// - /// Unit tests for the ISBNValidator class. - /// - /// Goran Milosavljevic - [TestFixture] - public sealed class ISBNValidatorTests - { - [Test] - public void Validate() - { - ISBNValidator validator = new ISBNValidator(); - // validate ISBN10 - Assert.IsTrue(validator.Validate("90-70002-34-5", new ValidationErrors())); - Assert.IsTrue(validator.Validate("1575843013", new ValidationErrors())); - Assert.IsTrue(validator.Validate("81-7525-766-0", new ValidationErrors())); - Assert.IsTrue(validator.Validate("1905158793", new ValidationErrors())); + [Test] + public void Validate() + { + ISBNValidator validator = new ISBNValidator(); + // validate ISBN10 + Assert.IsTrue(validator.Validate("90-70002-34-5", new ValidationErrors())); + Assert.IsTrue(validator.Validate("1575843013", new ValidationErrors())); + Assert.IsTrue(validator.Validate("81-7525-766-0", new ValidationErrors())); + Assert.IsTrue(validator.Validate("1905158793", new ValidationErrors())); - // validate ISBN13 - Assert.IsTrue(validator.Validate("978-1-905158-79-9", new ValidationErrors())); - Assert.IsTrue(validator.Validate("978-81-7525-766-5", new ValidationErrors())); - Assert.IsTrue(validator.Validate("978-90-70002-34-3", new ValidationErrors())); - Assert.IsTrue(validator.Validate("9789070002343", new ValidationErrors())); - Assert.IsTrue(validator.Validate("978907000234-3", new ValidationErrors())); - Assert.IsTrue(validator.Validate("9789070002-34-3", new ValidationErrors())); + // validate ISBN13 + Assert.IsTrue(validator.Validate("978-1-905158-79-9", new ValidationErrors())); + Assert.IsTrue(validator.Validate("978-81-7525-766-5", new ValidationErrors())); + Assert.IsTrue(validator.Validate("978-90-70002-34-3", new ValidationErrors())); + Assert.IsTrue(validator.Validate("9789070002343", new ValidationErrors())); + Assert.IsTrue(validator.Validate("978907000234-3", new ValidationErrors())); + Assert.IsTrue(validator.Validate("9789070002-34-3", new ValidationErrors())); - Assert.IsFalse(validator.Validate("9789g70002-34-3", new ValidationErrors())); - Assert.IsFalse(validator.Validate("a789g70002343", new ValidationErrors())); - Assert.IsFalse(validator.Validate("978907000234x", new ValidationErrors())); - Assert.IsTrue(validator.Validate("", new ValidationErrors())); - Assert.IsTrue(validator.Validate(" ", new ValidationErrors())); - Assert.IsTrue(validator.Validate(null, new ValidationErrors())); - } + Assert.IsFalse(validator.Validate("9789g70002-34-3", new ValidationErrors())); + Assert.IsFalse(validator.Validate("a789g70002343", new ValidationErrors())); + Assert.IsFalse(validator.Validate("978907000234x", new ValidationErrors())); + Assert.IsTrue(validator.Validate("", new ValidationErrors())); + Assert.IsTrue(validator.Validate(" ", new ValidationErrors())); + Assert.IsTrue(validator.Validate(null, new ValidationErrors())); } } diff --git a/test/Spring/Spring.Core.Tests/Validation/Validators/Integration/CreditCardValidatorIntegrationTests.cs b/test/Spring/Spring.Core.Tests/Validation/Validators/Integration/CreditCardValidatorIntegrationTests.cs index c6aac290..1cdf18a1 100644 --- a/test/Spring/Spring.Core.Tests/Validation/Validators/Integration/CreditCardValidatorIntegrationTests.cs +++ b/test/Spring/Spring.Core.Tests/Validation/Validators/Integration/CreditCardValidatorIntegrationTests.cs @@ -28,19 +28,19 @@ using Spring.Objects.Factory.Xml; #endregion -namespace Spring.Validation.Validators +namespace Spring.Validation.Validators; + +/// +/// CreditCardValidator integration tests. +/// +/// Goran Milosavljevic +[TestFixture] +public class CreditCardValidatorIntegrationTests { - /// - /// CreditCardValidator integration tests. - /// - /// Goran Milosavljevic - [TestFixture] - public class CreditCardValidatorIntegrationTests + [Test] + public void CreditCardValidatorTests() { - [Test] - public void CreditCardValidatorTests() - { - const string xml = @" + const string xml = @" @@ -48,46 +48,46 @@ namespace Spring.Validation.Validators "; - - MemoryStream stream = new MemoryStream(new UTF8Encoding().GetBytes(xml)); - IResource resource = new InputStreamResource(stream, "ccValidator"); - - XmlObjectFactory objectFactory = new XmlObjectFactory(resource, null); - object obj = objectFactory.GetObject("ccValidator"); - - Assert.IsTrue(obj is CreditCardValidator); - CreditCardValidator validator = obj as CreditCardValidator; - Assert.IsNotNull(validator.CardType); - Assert.IsTrue(validator.CardType is Amex); - Assert.IsTrue(validator.Validate("378282246310005", new ValidationErrors())); - } - [Test] - public void WithNullCardType() - { - const string xml = @" + MemoryStream stream = new MemoryStream(new UTF8Encoding().GetBytes(xml)); + IResource resource = new InputStreamResource(stream, "ccValidator"); + + XmlObjectFactory objectFactory = new XmlObjectFactory(resource, null); + object obj = objectFactory.GetObject("ccValidator"); + + Assert.IsTrue(obj is CreditCardValidator); + CreditCardValidator validator = obj as CreditCardValidator; + Assert.IsNotNull(validator.CardType); + Assert.IsTrue(validator.CardType is Amex); + Assert.IsTrue(validator.Validate("378282246310005", new ValidationErrors())); + } + + [Test] + public void WithNullCardType() + { + const string xml = @" "; - MemoryStream stream = new MemoryStream(new UTF8Encoding().GetBytes(xml)); - IResource resource = new InputStreamResource(stream, "ccValidator"); + MemoryStream stream = new MemoryStream(new UTF8Encoding().GetBytes(xml)); + IResource resource = new InputStreamResource(stream, "ccValidator"); - XmlObjectFactory objectFactory = new XmlObjectFactory(resource, null); - object obj = objectFactory.GetObject("ccValidator"); + XmlObjectFactory objectFactory = new XmlObjectFactory(resource, null); + object obj = objectFactory.GetObject("ccValidator"); - Assert.IsTrue(obj is CreditCardValidator); - CreditCardValidator validator = obj as CreditCardValidator; - Assert.IsNull(validator.CardType); - Assert.Throws(() => validator.Validate("378282246310005", new ValidationErrors())); - } + Assert.IsTrue(obj is CreditCardValidator); + CreditCardValidator validator = obj as CreditCardValidator; + Assert.IsNull(validator.CardType); + Assert.Throws(() => validator.Validate("378282246310005", new ValidationErrors())); + } - [Test] - public void ErrorTests() - { - const string xml = @" + [Test] + public void ErrorTests() + { + const string xml = @" @@ -96,20 +96,19 @@ namespace Spring.Validation.Validators "; - MemoryStream stream = new MemoryStream(new UTF8Encoding().GetBytes(xml)); - IResource resource = new InputStreamResource(stream, "ccValidator"); + MemoryStream stream = new MemoryStream(new UTF8Encoding().GetBytes(xml)); + IResource resource = new InputStreamResource(stream, "ccValidator"); - XmlObjectFactory objectFactory = new XmlObjectFactory(resource, null); + XmlObjectFactory objectFactory = new XmlObjectFactory(resource, null); - IValidationErrors errors = new ValidationErrors(); - Contact contact = new Contact(); - IValidator validator = (IValidator)objectFactory.GetObject("ccValidator"); + IValidationErrors errors = new ValidationErrors(); + Contact contact = new Contact(); + IValidator validator = (IValidator) objectFactory.GetObject("ccValidator"); - contact.Creditcard = "378282246310"; - bool result = validator.Validate(contact, errors); - - Assert.IsNotNull(errors.GetErrors("validationSummary")); - Assert.IsFalse(result); - } + contact.Creditcard = "378282246310"; + bool result = validator.Validate(contact, errors); + + Assert.IsNotNull(errors.GetErrors("validationSummary")); + Assert.IsFalse(result); } } diff --git a/test/Spring/Spring.Core.Tests/Validation/Validators/Integration/EmailValidatorIntegrationTests.cs b/test/Spring/Spring.Core.Tests/Validation/Validators/Integration/EmailValidatorIntegrationTests.cs index fe7046c8..18cfc254 100644 --- a/test/Spring/Spring.Core.Tests/Validation/Validators/Integration/EmailValidatorIntegrationTests.cs +++ b/test/Spring/Spring.Core.Tests/Validation/Validators/Integration/EmailValidatorIntegrationTests.cs @@ -27,32 +27,31 @@ using Spring.Objects.Factory.Xml; #endregion -namespace Spring.Validation.Validators +namespace Spring.Validation.Validators; + +/// +/// EmailValidatorIntegration integration tests. +/// +/// Goran Milosavljevic +[TestFixture] +public class EmailValidatorIntegrationTests { - /// - /// EmailValidatorIntegration integration tests. - /// - /// Goran Milosavljevic - [TestFixture] - public class EmailValidatorIntegrationTests + [Test] + public void EmailValidatorTests() { - [Test] - public void EmailValidatorTests() - { - const string xml = @" + const string xml = @" "; - - MemoryStream stream = new MemoryStream(new UTF8Encoding().GetBytes(xml)); - IResource resource = new InputStreamResource(stream, "emailValidator"); - XmlObjectFactory objectFactory = new XmlObjectFactory(resource, null); - object obj = objectFactory.GetObject("emailValidator"); - - Assert.IsTrue(obj is IValidator); - IValidator validator = obj as IValidator; - Assert.IsTrue(validator.Validate("goran@goran.com", new ValidationErrors())); - } + MemoryStream stream = new MemoryStream(new UTF8Encoding().GetBytes(xml)); + IResource resource = new InputStreamResource(stream, "emailValidator"); + + XmlObjectFactory objectFactory = new XmlObjectFactory(resource, null); + object obj = objectFactory.GetObject("emailValidator"); + + Assert.IsTrue(obj is IValidator); + IValidator validator = obj as IValidator; + Assert.IsTrue(validator.Validate("goran@goran.com", new ValidationErrors())); } -} +} \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/Validation/Validators/Integration/ISBNValidatorIntegrationTests.cs b/test/Spring/Spring.Core.Tests/Validation/Validators/Integration/ISBNValidatorIntegrationTests.cs index 6f22b4ce..d5d63455 100644 --- a/test/Spring/Spring.Core.Tests/Validation/Validators/Integration/ISBNValidatorIntegrationTests.cs +++ b/test/Spring/Spring.Core.Tests/Validation/Validators/Integration/ISBNValidatorIntegrationTests.cs @@ -27,34 +27,33 @@ using Spring.Objects.Factory.Xml; #endregion -namespace Spring.Validation.Validators +namespace Spring.Validation.Validators; + +/// +/// ISBNValidatorIntegration integration tests. +/// +/// Goran Milosavljevic +[TestFixture] +public class ISBNValidatorIntegrationTests { - /// - /// ISBNValidatorIntegration integration tests. - /// - /// Goran Milosavljevic - [TestFixture] - public class ISBNValidatorIntegrationTests + [Test] + public void ISBNValidatorTests() { - [Test] - public void ISBNValidatorTests() - { - const string xml = @" + const string xml = @" "; - - MemoryStream stream = new MemoryStream(new UTF8Encoding().GetBytes(xml)); - IResource resource = new InputStreamResource(stream, "isbnValidator"); - XmlObjectFactory objectFactory = new XmlObjectFactory(resource, null); - object obj = objectFactory.GetObject("isbnValidator"); - - Assert.IsTrue(obj is IValidator); - IValidator validator = obj as IValidator; - Assert.IsTrue(validator.Validate("978-1-905158-79-9", new ValidationErrors())); - } + MemoryStream stream = new MemoryStream(new UTF8Encoding().GetBytes(xml)); + IResource resource = new InputStreamResource(stream, "isbnValidator"); + + XmlObjectFactory objectFactory = new XmlObjectFactory(resource, null); + object obj = objectFactory.GetObject("isbnValidator"); + + Assert.IsTrue(obj is IValidator); + IValidator validator = obj as IValidator; + Assert.IsTrue(validator.Validate("978-1-905158-79-9", new ValidationErrors())); } } diff --git a/test/Spring/Spring.Core.Tests/Validation/Validators/Integration/UrlValidatorIntegrationTests.cs b/test/Spring/Spring.Core.Tests/Validation/Validators/Integration/UrlValidatorIntegrationTests.cs index 21370d4b..deb62fda 100644 --- a/test/Spring/Spring.Core.Tests/Validation/Validators/Integration/UrlValidatorIntegrationTests.cs +++ b/test/Spring/Spring.Core.Tests/Validation/Validators/Integration/UrlValidatorIntegrationTests.cs @@ -27,32 +27,31 @@ using Spring.Objects.Factory.Xml; #endregion -namespace Spring.Validation.Validators +namespace Spring.Validation.Validators; + +/// +/// UrlValidatorIntegration integration tests. +/// +/// Goran Milosavljevic +[TestFixture] +public class UrlValidatorIntegrationTests { - /// - /// UrlValidatorIntegration integration tests. - /// - /// Goran Milosavljevic - [TestFixture] - public class UrlValidatorIntegrationTests + [Test] + public void ISBNValidatorTests() { - [Test] - public void ISBNValidatorTests() - { - const string xml = @" + const string xml = @" "; - - MemoryStream stream = new MemoryStream(new UTF8Encoding().GetBytes(xml)); - IResource resource = new InputStreamResource(stream, "urlValidator"); - XmlObjectFactory objectFactory = new XmlObjectFactory(resource, null); - object obj = objectFactory.GetObject("urlValidator"); - - Assert.IsTrue(obj is IValidator); - IValidator validator = obj as IValidator; - Assert.IsTrue(validator.Validate("http://www.springframework.net", new ValidationErrors())); - } + MemoryStream stream = new MemoryStream(new UTF8Encoding().GetBytes(xml)); + IResource resource = new InputStreamResource(stream, "urlValidator"); + + XmlObjectFactory objectFactory = new XmlObjectFactory(resource, null); + object obj = objectFactory.GetObject("urlValidator"); + + Assert.IsTrue(obj is IValidator); + IValidator validator = obj as IValidator; + Assert.IsTrue(validator.Validate("http://www.springframework.net", new ValidationErrors())); } } diff --git a/test/Spring/Spring.Core.Tests/Validation/Validators/RegularExpressionValidatorTests.cs b/test/Spring/Spring.Core.Tests/Validation/Validators/RegularExpressionValidatorTests.cs index 1f34e63c..1a815b09 100644 --- a/test/Spring/Spring.Core.Tests/Validation/Validators/RegularExpressionValidatorTests.cs +++ b/test/Spring/Spring.Core.Tests/Validation/Validators/RegularExpressionValidatorTests.cs @@ -21,107 +21,104 @@ #region Imports using System.Text.RegularExpressions; - using NUnit.Framework; - using Spring.Expressions; #endregion -namespace Spring.Validation.Validators +namespace Spring.Validation.Validators; + +/// +/// Unit tests for the RegularExpressionValidator class. +/// +/// Rick Evans +[TestFixture] +public sealed class RegularExpressionValidatorTests { - /// - /// Unit tests for the RegularExpressionValidator class. - /// - /// Rick Evans - [TestFixture] - public sealed class RegularExpressionValidatorTests - { - [Test] - public void WithNonString() - { - RegularExpressionValidator validator = new RegularExpressionValidator(); - Assert.Throws(() => validator.Validate(this, new ValidationErrors())); - } + [Test] + public void WithNonString() + { + RegularExpressionValidator validator = new RegularExpressionValidator(); + Assert.Throws(() => validator.Validate(this, new ValidationErrors())); + } - [Test] - public void WithNull() - { - RegularExpressionValidator validator = new RegularExpressionValidator(); - Assert.Throws(() => validator.Validate(null, new ValidationErrors())); - } + [Test] + public void WithNull() + { + RegularExpressionValidator validator = new RegularExpressionValidator(); + Assert.Throws(() => validator.Validate(null, new ValidationErrors())); + } - [Test] - public void EmptyStringValidatesToTrue() - { - RegularExpressionValidator validator = new RegularExpressionValidator(); - Assert.IsTrue(validator.Validate(string.Empty, new ValidationErrors())); - } + [Test] + public void EmptyStringValidatesToTrue() + { + RegularExpressionValidator validator = new RegularExpressionValidator(); + Assert.IsTrue(validator.Validate(string.Empty, new ValidationErrors())); + } - [Test] - public void WhitespaceStringDoesntEvaluateToTrueByDefault() - { - RegularExpressionValidator validator = new RegularExpressionValidator(); - Assert.IsFalse(validator.Validate(" ", new ValidationErrors())); - } + [Test] + public void WhitespaceStringDoesntEvaluateToTrueByDefault() + { + RegularExpressionValidator validator = new RegularExpressionValidator(); + Assert.IsFalse(validator.Validate(" ", new ValidationErrors())); + } - [Test] - public void WhitespaceStringOnlyValidatesToTrueWhenGivenMatchingRegex() - { - RegularExpressionValidator validator = new RegularExpressionValidator(); - validator.Expression = @"\s*"; - Assert.IsTrue(validator.Validate(" ", new ValidationErrors())); - } + [Test] + public void WhitespaceStringOnlyValidatesToTrueWhenGivenMatchingRegex() + { + RegularExpressionValidator validator = new RegularExpressionValidator(); + validator.Expression = @"\s*"; + Assert.IsTrue(validator.Validate(" ", new ValidationErrors())); + } - [Test] - public void CaseSensitiveStringMatching() - { - RegularExpressionValidator validator = new RegularExpressionValidator("ToString()", "true", @"[A-Z][a-z]*"); - Assert.IsTrue(validator.Validate("Aleksandar", new ValidationErrors())); - Assert.IsFalse(validator.Validate("ALEKSANDAR", new ValidationErrors())); - Assert.IsFalse(validator.Validate("aleksandar", new ValidationErrors())); - } + [Test] + public void CaseSensitiveStringMatching() + { + RegularExpressionValidator validator = new RegularExpressionValidator("ToString()", "true", @"[A-Z][a-z]*"); + Assert.IsTrue(validator.Validate("Aleksandar", new ValidationErrors())); + Assert.IsFalse(validator.Validate("ALEKSANDAR", new ValidationErrors())); + Assert.IsFalse(validator.Validate("aleksandar", new ValidationErrors())); + } - [Test] - public void CaseInsensitiveStringMatching() - { - RegularExpressionValidator validator = new RegularExpressionValidator("ToString()", "true", @"[A-Z][a-z]*"); - validator.Options = RegexOptions.IgnoreCase; - Assert.IsTrue(validator.Validate("Aleksandar", new ValidationErrors())); - Assert.IsTrue(validator.Validate("ALEKSANDAR", new ValidationErrors())); - Assert.IsTrue(validator.Validate("aleksandar", new ValidationErrors())); - } + [Test] + public void CaseInsensitiveStringMatching() + { + RegularExpressionValidator validator = new RegularExpressionValidator("ToString()", "true", @"[A-Z][a-z]*"); + validator.Options = RegexOptions.IgnoreCase; + Assert.IsTrue(validator.Validate("Aleksandar", new ValidationErrors())); + Assert.IsTrue(validator.Validate("ALEKSANDAR", new ValidationErrors())); + Assert.IsTrue(validator.Validate("aleksandar", new ValidationErrors())); + } - [Test] - public void SunnyDayFailure_Invalid() - { - RegularExpressionValidator validator = new RegularExpressionValidator(Expression.Parse("'ljwdf87cwbh'"), Expression.Parse("true"), @"((\d{1,2}\.\d{1,3}\.\d{1,3}\.\d{1,3}))"); - Assert.IsFalse(validator.Validate("ljwdf87cwbh", new ValidationErrors())); - } + [Test] + public void SunnyDayFailure_Invalid() + { + RegularExpressionValidator validator = new RegularExpressionValidator(Expression.Parse("'ljwdf87cwbh'"), Expression.Parse("true"), @"((\d{1,2}\.\d{1,3}\.\d{1,3}\.\d{1,3}))"); + Assert.IsFalse(validator.Validate("ljwdf87cwbh", new ValidationErrors())); + } - [Test] - public void SunnyDay_Valid() - { - RegularExpressionValidator validator = new RegularExpressionValidator(); - validator.Expression = @"((\d{1,2}\.\d{1,3}\.\d{1,3}\.\d{1,3}))"; - Assert.IsTrue(validator.Validate("11.222.333.444", new ValidationErrors())); - } + [Test] + public void SunnyDay_Valid() + { + RegularExpressionValidator validator = new RegularExpressionValidator(); + validator.Expression = @"((\d{1,2}\.\d{1,3}\.\d{1,3}\.\d{1,3}))"; + Assert.IsTrue(validator.Validate("11.222.333.444", new ValidationErrors())); + } - [Test] - public void WhenValidatorIsNotEvaluatedBecauseWhenExpressionReturnsFalse() - { - RegularExpressionValidator validator = new RegularExpressionValidator("'ljwdf87cwbh'", "false", @"((\d{1,2}\.\d{1,3}\.\d{1,3}\.\d{1,3}))"); - bool valid = validator.Validate(null, new ValidationErrors()); - Assert.IsTrue(valid, "Validation should succeed when regex validator is not evaluated."); - } + [Test] + public void WhenValidatorIsNotEvaluatedBecauseWhenExpressionReturnsFalse() + { + RegularExpressionValidator validator = new RegularExpressionValidator("'ljwdf87cwbh'", "false", @"((\d{1,2}\.\d{1,3}\.\d{1,3}\.\d{1,3}))"); + bool valid = validator.Validate(null, new ValidationErrors()); + Assert.IsTrue(valid, "Validation should succeed when regex validator is not evaluated."); + } - [Test] - public void AllowPartialMatching() - { - RegularExpressionValidator validator = new RegularExpressionValidator(); - validator.Expression = "[A-Za-z]"; - validator.AllowPartialMatching = true; - Assert.True(validator.Validate("123a456", new ValidationErrors())); - } - } -} \ No newline at end of file + [Test] + public void AllowPartialMatching() + { + RegularExpressionValidator validator = new RegularExpressionValidator(); + validator.Expression = "[A-Za-z]"; + validator.AllowPartialMatching = true; + Assert.True(validator.Validate("123a456", new ValidationErrors())); + } +} diff --git a/test/Spring/Spring.Core.Tests/Validation/Validators/RequiredValidatorTests.cs b/test/Spring/Spring.Core.Tests/Validation/Validators/RequiredValidatorTests.cs index 992cab38..fade07b1 100644 --- a/test/Spring/Spring.Core.Tests/Validation/Validators/RequiredValidatorTests.cs +++ b/test/Spring/Spring.Core.Tests/Validation/Validators/RequiredValidatorTests.cs @@ -21,174 +21,171 @@ #region Imports using NUnit.Framework; - using Spring.Expressions; #endregion -namespace Spring.Validation.Validators +namespace Spring.Validation.Validators; + +/// +/// Unit tests for the RequiredValidator class. +/// +/// Rick Evans +[TestFixture] +public sealed class RequiredValidatorTests { - /// - /// Unit tests for the RequiredValidator class. - /// - /// Rick Evans - [TestFixture] - public sealed class RequiredValidatorTests + [Test] + public void WithNull() { - [Test] - public void WithNull() - { - RequiredValidator validator = new RequiredValidator(); - validator.Test = Expression.Parse("null"); - IValidationErrors errors = new ValidationErrors(); - Assert.IsFalse(validator.Validate(null, errors)); - } + RequiredValidator validator = new RequiredValidator(); + validator.Test = Expression.Parse("null"); + IValidationErrors errors = new ValidationErrors(); + Assert.IsFalse(validator.Validate(null, errors)); + } - [Test] - public void WithZeroNumber() - { - RequiredValidator validator = new RequiredValidator("0", null); - IValidationErrors errors = new ValidationErrors(); - Assert.IsFalse(validator.Validate(null, errors)); - } + [Test] + public void WithZeroNumber() + { + RequiredValidator validator = new RequiredValidator("0", null); + IValidationErrors errors = new ValidationErrors(); + Assert.IsFalse(validator.Validate(null, errors)); + } - [Test] - public void WithPositiveNumber() - { - RequiredValidator validator = new RequiredValidator(Expression.Parse("100"), null); - IValidationErrors errors = new ValidationErrors(); - Assert.IsTrue(validator.Validate(null, errors)); - } + [Test] + public void WithPositiveNumber() + { + RequiredValidator validator = new RequiredValidator(Expression.Parse("100"), null); + IValidationErrors errors = new ValidationErrors(); + Assert.IsTrue(validator.Validate(null, errors)); + } - [Test] - public void WithNegativeNumber() - { - RequiredValidator validator = new RequiredValidator(); - validator.Test = Expression.Parse("-100"); - IValidationErrors errors = new ValidationErrors(); - Assert.IsTrue(validator.Validate(null, errors)); - } + [Test] + public void WithNegativeNumber() + { + RequiredValidator validator = new RequiredValidator(); + validator.Test = Expression.Parse("-100"); + IValidationErrors errors = new ValidationErrors(); + Assert.IsTrue(validator.Validate(null, errors)); + } - [Test] - public void WithEmptyString() - { - RequiredValidator validator = new RequiredValidator("''", null); - IValidationErrors errors = new ValidationErrors(); - Assert.IsFalse(validator.Validate(null, errors)); - } + [Test] + public void WithEmptyString() + { + RequiredValidator validator = new RequiredValidator("''", null); + IValidationErrors errors = new ValidationErrors(); + Assert.IsFalse(validator.Validate(null, errors)); + } - [Test] - public void WithWhitespaceOnlyString() - { - RequiredValidator validator = new RequiredValidator(Expression.Parse("' '"), null); - IValidationErrors errors = new ValidationErrors(); - Assert.IsFalse(validator.Validate(null, errors)); - } + [Test] + public void WithWhitespaceOnlyString() + { + RequiredValidator validator = new RequiredValidator(Expression.Parse("' '"), null); + IValidationErrors errors = new ValidationErrors(); + Assert.IsFalse(validator.Validate(null, errors)); + } - [Test] - public void WithKosherString() - { - RequiredValidator validator = new RequiredValidator(); - validator.Test = Expression.Parse("'some non-empty string'"); - IValidationErrors errors = new ValidationErrors(); - Assert.IsTrue(validator.Validate(null, errors)); - } + [Test] + public void WithKosherString() + { + RequiredValidator validator = new RequiredValidator(); + validator.Test = Expression.Parse("'some non-empty string'"); + IValidationErrors errors = new ValidationErrors(); + Assert.IsTrue(validator.Validate(null, errors)); + } - [Test] - public void WithKosherDate() - { - RequiredValidator validator = new RequiredValidator("DateTime.Today", null); - IValidationErrors errors = new ValidationErrors(); - Assert.IsTrue(validator.Validate(null, errors)); - } + [Test] + public void WithKosherDate() + { + RequiredValidator validator = new RequiredValidator("DateTime.Today", null); + IValidationErrors errors = new ValidationErrors(); + Assert.IsTrue(validator.Validate(null, errors)); + } - [Test] - public void WithMinDate() - { - RequiredValidator validator = new RequiredValidator(Expression.Parse("DateTime.MinValue"), null); - IValidationErrors errors = new ValidationErrors(); - Assert.IsFalse(validator.Validate(null, errors)); - } + [Test] + public void WithMinDate() + { + RequiredValidator validator = new RequiredValidator(Expression.Parse("DateTime.MinValue"), null); + IValidationErrors errors = new ValidationErrors(); + Assert.IsFalse(validator.Validate(null, errors)); + } - [Test] - public void WithMaxDate() - { - RequiredValidator validator = new RequiredValidator(); - validator.Test = Expression.Parse("DateTime.MaxValue"); - IValidationErrors errors = new ValidationErrors(); - Assert.IsFalse(validator.Validate(null, errors)); - } + [Test] + public void WithMaxDate() + { + RequiredValidator validator = new RequiredValidator(); + validator.Test = Expression.Parse("DateTime.MaxValue"); + IValidationErrors errors = new ValidationErrors(); + Assert.IsFalse(validator.Validate(null, errors)); + } - [Test] - public void WithZeroFloat() - { - RequiredValidator validator = new RequiredValidator("0.00F", null); - IValidationErrors errors = new ValidationErrors(); - Assert.IsFalse(validator.Validate(null, errors)); - } + [Test] + public void WithZeroFloat() + { + RequiredValidator validator = new RequiredValidator("0.00F", null); + IValidationErrors errors = new ValidationErrors(); + Assert.IsFalse(validator.Validate(null, errors)); + } - [Test] - public void WithKosherFloat() - { - RequiredValidator validator = new RequiredValidator(Expression.Parse("5.25F"), null); - IValidationErrors errors = new ValidationErrors(); - Assert.IsTrue(validator.Validate(null, errors)); - } + [Test] + public void WithKosherFloat() + { + RequiredValidator validator = new RequiredValidator(Expression.Parse("5.25F"), null); + IValidationErrors errors = new ValidationErrors(); + Assert.IsTrue(validator.Validate(null, errors)); + } - [Test] - public void WithZeroDouble() - { - RequiredValidator validator = new RequiredValidator("0.00D", null); - IValidationErrors errors = new ValidationErrors(); - Assert.IsFalse(validator.Validate(null, errors)); - } + [Test] + public void WithZeroDouble() + { + RequiredValidator validator = new RequiredValidator("0.00D", null); + IValidationErrors errors = new ValidationErrors(); + Assert.IsFalse(validator.Validate(null, errors)); + } - [Test] - public void WithKosherDouble() - { - RequiredValidator validator = new RequiredValidator("5.25D", null); - IValidationErrors errors = new ValidationErrors(); - Assert.IsTrue(validator.Validate(null, errors)); - } + [Test] + public void WithKosherDouble() + { + RequiredValidator validator = new RequiredValidator("5.25D", null); + IValidationErrors errors = new ValidationErrors(); + Assert.IsTrue(validator.Validate(null, errors)); + } - [Test] - public void WithMinChar() - { - RequiredValidator validator = new RequiredValidator(); - validator.Test = Expression.Parse("char.MinValue"); - IValidationErrors errors = new ValidationErrors(); - Assert.IsFalse(validator.Validate(null, errors)); - } + [Test] + public void WithMinChar() + { + RequiredValidator validator = new RequiredValidator(); + validator.Test = Expression.Parse("char.MinValue"); + IValidationErrors errors = new ValidationErrors(); + Assert.IsFalse(validator.Validate(null, errors)); + } - [Test] - public void WithWhitespaceChar() - { - RequiredValidator validator = new RequiredValidator(); - validator.Test = Expression.Parse("' '.ToCharArray()[0]"); - IValidationErrors errors = new ValidationErrors(); - Assert.IsFalse(validator.Validate(null, errors)); - } + [Test] + public void WithWhitespaceChar() + { + RequiredValidator validator = new RequiredValidator(); + validator.Test = Expression.Parse("' '.ToCharArray()[0]"); + IValidationErrors errors = new ValidationErrors(); + Assert.IsFalse(validator.Validate(null, errors)); + } - [Test] - public void WithKosherChar() - { - RequiredValidator validator = new RequiredValidator(); - validator.Test = Expression.Parse("'xyz'.ToCharArray()[1]"); - IValidationErrors errors = new ValidationErrors(); - Assert.IsTrue(validator.Validate(null, errors)); - } + [Test] + public void WithKosherChar() + { + RequiredValidator validator = new RequiredValidator(); + validator.Test = Expression.Parse("'xyz'.ToCharArray()[1]"); + IValidationErrors errors = new ValidationErrors(); + Assert.IsTrue(validator.Validate(null, errors)); + } - [Test] - public void WhenValidatorIsNotEvaluatedBecauseWhenExpressionReturnsFalse() - { - RequiredValidator validator = new RequiredValidator("DateTime.MinValue", "false"); - IValidationErrors errors = new ValidationErrors(); + [Test] + public void WhenValidatorIsNotEvaluatedBecauseWhenExpressionReturnsFalse() + { + RequiredValidator validator = new RequiredValidator("DateTime.MinValue", "false"); + IValidationErrors errors = new ValidationErrors(); - bool valid = validator.Validate(new object(), null, errors); - - Assert.IsTrue(valid, "Validation should succeed when required validator is not evaluated."); - Assert.AreEqual(0, errors.GetErrors("errors").Count); - } + bool valid = validator.Validate(new object(), null, errors); + Assert.IsTrue(valid, "Validation should succeed when required validator is not evaluated."); + Assert.AreEqual(0, errors.GetErrors("errors").Count); } } \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/Validation/Validators/UrlValidatorTests.cs b/test/Spring/Spring.Core.Tests/Validation/Validators/UrlValidatorTests.cs index ad108186..a9ba3b3f 100644 --- a/test/Spring/Spring.Core.Tests/Validation/Validators/UrlValidatorTests.cs +++ b/test/Spring/Spring.Core.Tests/Validation/Validators/UrlValidatorTests.cs @@ -24,37 +24,36 @@ using NUnit.Framework; #endregion -namespace Spring.Validation.Validators -{ - /// - /// Unit tests for the UrlValidator class. - /// - /// Goran Milosavljevic - [TestFixture] - public sealed class UrlValidatorTests - { - [Test] - public void Validate() - { - UrlValidator validator = new UrlValidator(); - Assert.IsTrue(validator.Validate("http://puzzle.com", new ValidationErrors())); - Assert.IsTrue(validator.Validate("http://www.com", new ValidationErrors())); - Assert.IsTrue(validator.Validate("www.1.org", new ValidationErrors())); - Assert.IsTrue(validator.Validate("ww.1.com", new ValidationErrors())); - Assert.IsTrue(validator.Validate("http://www.google-com.123.com", new ValidationErrors())); - Assert.IsTrue(validator.Validate("https://www.google-com.com", new ValidationErrors())); - Assert.IsTrue(validator.Validate("http://google-com.com", new ValidationErrors())); - // just to make sure that we are ready for the Japanese market :) - Assert.IsTrue(validator.Validate("www.amazon.co.jp/C-ã«ã‚ˆã‚‹ãƒ—ログラミングWindows-上-Charles-Petzold/dp/4891002921", new ValidationErrors())); +namespace Spring.Validation.Validators; - Assert.IsFalse(validator.Validate("http://.com", new ValidationErrors())); - Assert.IsFalse(validator.Validate("http://www.google-com.123", new ValidationErrors())); - Assert.IsFalse(validator.Validate("http://1.1", new ValidationErrors())); - Assert.IsFalse(validator.Validate("ht:1.1", new ValidationErrors())); - Assert.IsFalse(validator.Validate("/:www.1.com", new ValidationErrors())); - Assert.IsTrue(validator.Validate("", new ValidationErrors())); - Assert.IsTrue(validator.Validate(" ", new ValidationErrors())); - Assert.IsTrue(validator.Validate(null, new ValidationErrors())); - } +/// +/// Unit tests for the UrlValidator class. +/// +/// Goran Milosavljevic +[TestFixture] +public sealed class UrlValidatorTests +{ + [Test] + public void Validate() + { + UrlValidator validator = new UrlValidator(); + Assert.IsTrue(validator.Validate("http://puzzle.com", new ValidationErrors())); + Assert.IsTrue(validator.Validate("http://www.com", new ValidationErrors())); + Assert.IsTrue(validator.Validate("www.1.org", new ValidationErrors())); + Assert.IsTrue(validator.Validate("ww.1.com", new ValidationErrors())); + Assert.IsTrue(validator.Validate("http://www.google-com.123.com", new ValidationErrors())); + Assert.IsTrue(validator.Validate("https://www.google-com.com", new ValidationErrors())); + Assert.IsTrue(validator.Validate("http://google-com.com", new ValidationErrors())); + // just to make sure that we are ready for the Japanese market :) + Assert.IsTrue(validator.Validate("www.amazon.co.jp/C-ã«ã‚ˆã‚‹ãƒ—ログラミングWindows-上-Charles-Petzold/dp/4891002921", new ValidationErrors())); + + Assert.IsFalse(validator.Validate("http://.com", new ValidationErrors())); + Assert.IsFalse(validator.Validate("http://www.google-com.123", new ValidationErrors())); + Assert.IsFalse(validator.Validate("http://1.1", new ValidationErrors())); + Assert.IsFalse(validator.Validate("ht:1.1", new ValidationErrors())); + Assert.IsFalse(validator.Validate("/:www.1.com", new ValidationErrors())); + Assert.IsTrue(validator.Validate("", new ValidationErrors())); + Assert.IsTrue(validator.Validate(" ", new ValidationErrors())); + Assert.IsTrue(validator.Validate(null, new ValidationErrors())); } } diff --git a/test/Spring/Spring.Data.Integration.Tests/App.config b/test/Spring/Spring.Data.Integration.Tests/App.config index 316e504f..78a84902 100644 --- a/test/Spring/Spring.Data.Integration.Tests/App.config +++ b/test/Spring/Spring.Data.Integration.Tests/App.config @@ -5,7 +5,7 @@
- +
@@ -18,10 +18,10 @@ - + - + diff --git a/test/Spring/Spring.Data.Integration.Tests/Data/AccountCreditDao.cs b/test/Spring/Spring.Data.Integration.Tests/Data/AccountCreditDao.cs index 2d9f8521..fcf8ddc9 100644 --- a/test/Spring/Spring.Data.Integration.Tests/Data/AccountCreditDao.cs +++ b/test/Spring/Spring.Data.Integration.Tests/Data/AccountCreditDao.cs @@ -2,22 +2,19 @@ using System.Data; using Spring.Data.Core; using Spring.Transaction.Interceptor; -namespace Spring.Data +namespace Spring.Data; + +public class AccountCreditDao : AdoDaoSupport, IAccountCreditDao { - public class AccountCreditDao : AdoDaoSupport, IAccountCreditDao + public AccountCreditDao() { - - public AccountCreditDao() - { - } - - [Transaction()] - public void CreateCredit(float creditAmount) - { - AdoTemplate.ExecuteNonQuery(CommandType.Text, - String.Format("insert into Credits (CreditAmount) VALUES ({0})", - creditAmount)); - } + } + [Transaction()] + public void CreateCredit(float creditAmount) + { + AdoTemplate.ExecuteNonQuery(CommandType.Text, + String.Format("insert into Credits (CreditAmount) VALUES ({0})", + creditAmount)); } } diff --git a/test/Spring/Spring.Data.Integration.Tests/Data/AccountDebitDao.cs b/test/Spring/Spring.Data.Integration.Tests/Data/AccountDebitDao.cs index 8dfcca91..5c16dfeb 100644 --- a/test/Spring/Spring.Data.Integration.Tests/Data/AccountDebitDao.cs +++ b/test/Spring/Spring.Data.Integration.Tests/Data/AccountDebitDao.cs @@ -1,21 +1,17 @@ using System.Data; using Spring.Data.Core; -namespace Spring.Data +namespace Spring.Data; + +public class AccountDebitDao : AdoDaoSupport, IAccountDebitDao { - public class AccountDebitDao : AdoDaoSupport, IAccountDebitDao + public AccountDebitDao() { + } - public AccountDebitDao() - { - } - - public void DebitAccount(float debitAmount) - { - AdoTemplate.ExecuteNonQuery(CommandType.Text, String.Format("insert into dbo.Debits (DebitAmount) VALUES ({0})", - debitAmount)); - } - - + public void DebitAccount(float debitAmount) + { + AdoTemplate.ExecuteNonQuery(CommandType.Text, String.Format("insert into dbo.Debits (DebitAmount) VALUES ({0})", + debitAmount)); } } diff --git a/test/Spring/Spring.Data.Integration.Tests/Data/AccountManager.cs b/test/Spring/Spring.Data.Integration.Tests/Data/AccountManager.cs index 8f115db0..f7ec4f5e 100644 --- a/test/Spring/Spring.Data.Integration.Tests/Data/AccountManager.cs +++ b/test/Spring/Spring.Data.Integration.Tests/Data/AccountManager.cs @@ -1,37 +1,32 @@ using Spring.Transaction.Interceptor; -namespace Spring.Data +namespace Spring.Data; + +public class AccountManager : IAccountManager { - public class AccountManager : IAccountManager + private IAccountCreditDao creditDao; + private IAccountDebitDao debitDao; + + public AccountManager() { - private IAccountCreditDao creditDao; - private IAccountDebitDao debitDao; - - public AccountManager() - { - } - - public IAccountCreditDao AccountCreditDao - { - get { return creditDao; } - set { creditDao = value; } - } - - public IAccountDebitDao AccountDebitDao - { - get { return debitDao; } - set { debitDao = value; } - } - - [Transaction] - public void DoTransfer(float creditAmount, float debitAmount) - { - creditDao.CreateCredit(creditAmount); - debitDao.DebitAccount(debitAmount); - - } - } + public IAccountCreditDao AccountCreditDao + { + get { return creditDao; } + set { creditDao = value; } + } + public IAccountDebitDao AccountDebitDao + { + get { return debitDao; } + set { debitDao = value; } + } + + [Transaction] + public void DoTransfer(float creditAmount, float debitAmount) + { + creditDao.CreateCredit(creditAmount); + debitDao.DebitAccount(debitAmount); + } } diff --git a/test/Spring/Spring.Data.Integration.Tests/Data/AdoDaoTests.cs b/test/Spring/Spring.Data.Integration.Tests/Data/AdoDaoTests.cs index ad95cb9b..77d75b09 100644 --- a/test/Spring/Spring.Data.Integration.Tests/Data/AdoDaoTests.cs +++ b/test/Spring/Spring.Data.Integration.Tests/Data/AdoDaoTests.cs @@ -4,149 +4,141 @@ using Spring.Context.Support; using Spring.Objects; using Spring.Testing.NUnit; -namespace Spring.Data +namespace Spring.Data; + +/// +/// Test AdoTemplate based DAO object. +/// +[TestFixture] +public class AdoDaoTests : AbstractTransactionalSpringContextTests { - /// - /// Test AdoTemplate based DAO object. - /// - [TestFixture] - public class AdoDaoTests : AbstractTransactionalSpringContextTests - { + private TestObjectDao dao; - private TestObjectDao dao; + public TestObjectDao TestObjectDao + { + get { return dao; } + set { dao = value; } + } - public TestObjectDao TestObjectDao - { - get { return dao; } - set { dao = value; } - } - - [Test] - public void ExerciseDao() + [Test] + public void ExerciseDao() + { + Assert.AreEqual(0, dao.GetCount()); + dao.Create("John", 44); + Assert.AreEqual(1, dao.GetCountByDelegate()); + dao.Create("Mary", 44); + dao.Create("Steve", 44); + dao.Create("George", 33); + Assert.AreEqual(4, dao.GetCount(), "GetCount()"); + Assert.AreEqual(3, dao.GetCount(33), "GetCount(33)"); + Assert.AreEqual(3, dao.GetCountByAltMethod(33), "GetCountByAltMethod(33)"); + Assert.AreEqual(3, dao.GetCountByCommandSetter(33), "GetCountByCommandSetter(33)"); + Assert.AreEqual(1, dao.GetCount(32, "George"), "GetCount(32, 'George')"); + + TestObject to = dao.FindByName("George"); + Assert.IsNotNull(to); + Assert.AreEqual("George", to.Name); + Assert.AreEqual(33, to.Age); + + to.Age = 34; + dao.Update(to); + + TestObject to2 = dao.FindByName("George"); + Assert.AreEqual(34, to2.Age); + + dao.Delete("George"); + + TestObject to3 = dao.FindByName("George"); + Assert.IsNull(to3); + } + + [Ignore("Sanity-Check tests intended for verification of base-class behavior only")] + [Test] + public void SimpleCreate() + { + IApplicationContext ctx = + new XmlApplicationContext("assembly://Spring.Data.Integration.Tests/Spring.Data/nativeAdoTests.xml"); + Assert.IsNotNull(ctx); + ITestObjectDao dao = (ITestObjectDao) ctx["testObjectDao"]; + Assert.IsNotNull(dao); + dao.Create("John", 44); + } + + [Ignore("Sanity-Check tests intended for verification of base-class behavior only")] + [Test] + public void SimpleDao() + { + IApplicationContext ctx = + new XmlApplicationContext("assembly://Spring.Data.Integration.Tests/Spring.Data/templateTests.xml"); + Assert.IsNotNull(ctx); + TestObjectDao dao = (TestObjectDao) ctx["testObjectDao"]; + Assert.IsNotNull(dao); + Assert.AreEqual(10, dao.GetCount()); + + Assert.AreEqual(3, dao.GetCount(33)); + Assert.AreEqual(3, dao.GetCountByAltMethod(33)); + Assert.AreEqual(3, dao.GetCountByCommandSetter(33)); + Assert.AreEqual(2, dao.GetCount(33, "George")); + } + + [Ignore("Sanity-Check tests intended for verification of base-class behavior only")] + [Test] + public void SimpleDao2() + { + IApplicationContext ctx = + new XmlApplicationContext("assembly://Spring.Data.Integration.Tests/Spring.Data/templateTests.xml"); + Assert.IsNotNull(ctx); + TestObjectDao dao = (TestObjectDao) ctx["testObjectDao"]; + Assert.IsNotNull(dao); + Assert.AreEqual(1, dao.GetCountByDelegate()); + } + + [Ignore("Sanity-Check tests intended for verification of base-class behavior only")] + [Test] + public void DaoOperations() + { + IApplicationContext ctx = + new XmlApplicationContext("assembly://Spring.Data.Integration.Tests/Spring.Data/templateTests.xml"); + Assert.IsNotNull(ctx); + TestObjectDao dao = (TestObjectDao) ctx["testObjectDao"]; + dao.Create("George", 33); + TestObject to = dao.FindByName("George"); + Assert.IsNotNull(to); + Assert.AreEqual("George", to.Name); + Assert.AreEqual(33, to.Age); + + to.Age = 34; + dao.Update(to); + + TestObject to2 = dao.FindByName("George"); + Assert.AreEqual(34, to2.Age); + + dao.Delete("George"); + + TestObject to3 = dao.FindByName("George"); + Assert.IsNull(to3); + } + + #region Overrides of AbstractDependencyInjectionSpringContextTests + + /// + /// Subclasses must implement this property to return the locations of their + /// config files. A plain path will be treated as a file system location. + /// + /// An array of config locations + protected override string[] ConfigLocations + { + get { - Assert.AreEqual(0, dao.GetCount()); - dao.Create("John", 44); - Assert.AreEqual(1, dao.GetCountByDelegate()); - dao.Create("Mary", 44); - dao.Create("Steve", 44); - dao.Create("George", 33); - Assert.AreEqual(4, dao.GetCount(), "GetCount()"); - Assert.AreEqual(3, dao.GetCount(33), "GetCount(33)"); - Assert.AreEqual(3, dao.GetCountByAltMethod(33), "GetCountByAltMethod(33)"); - Assert.AreEqual(3, dao.GetCountByCommandSetter(33), "GetCountByCommandSetter(33)"); - Assert.AreEqual(1, dao.GetCount(32, "George"), "GetCount(32, 'George')"); - - TestObject to = dao.FindByName("George"); - Assert.IsNotNull(to); - Assert.AreEqual("George", to.Name); - Assert.AreEqual(33, to.Age); - - to.Age = 34; - dao.Update(to); - - TestObject to2 = dao.FindByName("George"); - Assert.AreEqual(34, to2.Age); - - dao.Delete("George"); - - TestObject to3 = dao.FindByName("George"); - Assert.IsNull(to3); - + return new string[] { "assembly://Spring.Data.Integration.Tests/Spring.Data/templateTests.xml" }; } + } - [Ignore("Sanity-Check tests intended for verification of base-class behavior only")] - [Test] - public void SimpleCreate() - { - IApplicationContext ctx = - new XmlApplicationContext("assembly://Spring.Data.Integration.Tests/Spring.Data/nativeAdoTests.xml"); - Assert.IsNotNull(ctx); - ITestObjectDao dao = (ITestObjectDao)ctx["testObjectDao"]; - Assert.IsNotNull(dao); - dao.Create("John", 44); - } + protected override void OnSetUp() + { + TestObjectDao.Cleanup(); + base.OnSetUp(); + } - [Ignore("Sanity-Check tests intended for verification of base-class behavior only")] - [Test] - public void SimpleDao() - { - IApplicationContext ctx = - new XmlApplicationContext("assembly://Spring.Data.Integration.Tests/Spring.Data/templateTests.xml"); - Assert.IsNotNull(ctx); - TestObjectDao dao = (TestObjectDao)ctx["testObjectDao"]; - Assert.IsNotNull(dao); - Assert.AreEqual(10, dao.GetCount()); - - Assert.AreEqual(3, dao.GetCount(33)); - Assert.AreEqual(3, dao.GetCountByAltMethod(33)); - Assert.AreEqual(3, dao.GetCountByCommandSetter(33)); - Assert.AreEqual(2, dao.GetCount(33,"George")); - - - } - - [Ignore("Sanity-Check tests intended for verification of base-class behavior only")] - [Test] - public void SimpleDao2() - { - IApplicationContext ctx = - new XmlApplicationContext("assembly://Spring.Data.Integration.Tests/Spring.Data/templateTests.xml"); - Assert.IsNotNull(ctx); - TestObjectDao dao = (TestObjectDao)ctx["testObjectDao"]; - Assert.IsNotNull(dao); - Assert.AreEqual(1, dao.GetCountByDelegate()); - } - - [Ignore("Sanity-Check tests intended for verification of base-class behavior only")] - [Test] - public void DaoOperations() - { - IApplicationContext ctx = - new XmlApplicationContext("assembly://Spring.Data.Integration.Tests/Spring.Data/templateTests.xml"); - Assert.IsNotNull(ctx); - TestObjectDao dao = (TestObjectDao)ctx["testObjectDao"]; - dao.Create("George", 33); - TestObject to = dao.FindByName("George"); - Assert.IsNotNull(to); - Assert.AreEqual("George", to.Name); - Assert.AreEqual(33, to.Age); - - to.Age=34; - dao.Update(to); - - TestObject to2 = dao.FindByName("George"); - Assert.AreEqual(34, to2.Age); - - dao.Delete("George"); - - TestObject to3 = dao.FindByName("George"); - Assert.IsNull(to3); - - - - } - - #region Overrides of AbstractDependencyInjectionSpringContextTests - - /// - /// Subclasses must implement this property to return the locations of their - /// config files. A plain path will be treated as a file system location. - /// - /// An array of config locations - protected override string[] ConfigLocations - { - get - { - return new string[] { "assembly://Spring.Data.Integration.Tests/Spring.Data/templateTests.xml" }; - } - } - - protected override void OnSetUp() - { - TestObjectDao.Cleanup(); - base.OnSetUp(); - } - - #endregion - } -} + #endregion +} \ No newline at end of file diff --git a/test/Spring/Spring.Data.Integration.Tests/Data/AdoTemplatePerformanceTests.cs b/test/Spring/Spring.Data.Integration.Tests/Data/AdoTemplatePerformanceTests.cs index da02f17d..0160709c 100644 --- a/test/Spring/Spring.Data.Integration.Tests/Data/AdoTemplatePerformanceTests.cs +++ b/test/Spring/Spring.Data.Integration.Tests/Data/AdoTemplatePerformanceTests.cs @@ -33,231 +33,235 @@ using Spring.Util; #endregion -namespace Spring.Data +namespace Spring.Data; + +/// +/// This calss contains tests for +/// +/// Mark Pollack +[TestFixture, Explicit] +public class AdoTemplatePerformanceTests { - /// - /// This calss contains tests for - /// - /// Mark Pollack - [TestFixture, Explicit] - public class AdoTemplatePerformanceTests + private AdoTemplate adoTemplate; + private string cmdText = "insert into TestObjects(Age, Name) VALUES (24, 'John')"; + private DateTime start, stop; + + [SetUp] + public void CreateAdoTemplate() { - private AdoTemplate adoTemplate; - private string cmdText = "insert into TestObjects(Age, Name) VALUES (24, 'John')"; - private DateTime start, stop; + IApplicationContext ctx = + new XmlApplicationContext("assembly://Spring.Data.Integration.Tests/Spring.Data/adoTemplateTests.xml"); + Assert.IsNotNull(ctx); + adoTemplate = ctx["adoTemplate"] as AdoTemplate; + Assert.IsNotNull(adoTemplate); + //CleanDb(); + } - [SetUp] - public void CreateAdoTemplate() + private void CleanDb() + { + adoTemplate.ExecuteNonQuery(CommandType.Text, "truncate table TestObjects"); + } + + [Test] + public void PerformanceWithOneTxTests() + { + UseAdoTemplateApiOneTx(1000); + CleanDb(); + } + + [Test] + public void PerformanceTests() + { + for (int i = 0; i < 10; i++) + DoTest(10000, true, 5000, true); + } + + [Test] + public void ObjectInstantiatonTests() + { + int numIterations = 1000000; + + start = DateTime.Now; + Type t = typeof(AccountCreditDao); + for (int i = 0; i < numIterations; i++) { - IApplicationContext ctx = - new XmlApplicationContext("assembly://Spring.Data.Integration.Tests/Spring.Data/adoTemplateTests.xml"); - Assert.IsNotNull(ctx); - adoTemplate = ctx["adoTemplate"] as AdoTemplate; - Assert.IsNotNull(adoTemplate); - //CleanDb(); + //ObjectUtils.IsInstantiable(t); + IDynamicConstructor dc = DynamicConstructor.Create(t.GetConstructor(Type.EmptyTypes)); + dc.Invoke(ObjectUtils.EmptyObjects); } - private void CleanDb() + stop = DateTime.Now; + double timeElapsed = Elapsed; + PrintTest("SafeConstructor", numIterations, timeElapsed); + + start = DateTime.Now; + for (int i = 0; i < numIterations; i++) { - adoTemplate.ExecuteNonQuery(CommandType.Text, "truncate table TestObjects"); + ObjectUtils.InstantiateType(typeof(AccountCreditDao)); } - [Test] - public void PerformanceWithOneTxTests() + stop = DateTime.Now; + timeElapsed = Elapsed; + PrintTest("InstantiateType", numIterations, timeElapsed); + } + + private void DoTest(int numIterations, bool standardApiFirst, int sleepTimeMs, bool oneTx) + { + Console.WriteLine("sleeping for " + sleepTimeMs); + Thread.Sleep(sleepTimeMs); + double stdTime; + double templateTime; + if (standardApiFirst) { - UseAdoTemplateApiOneTx(1000); - CleanDb(); - } - - [Test] - public void PerformanceTests() - { - for (int i = 0; i < 10; i++) - DoTest(10000, true, 5000, true); - } - - [Test] - public void ObjectInstantiatonTests() - { - int numIterations = 1000000; - - - start = DateTime.Now; - Type t = typeof (AccountCreditDao); - for (int i = 0; i < numIterations; i++) + if (oneTx) { - //ObjectUtils.IsInstantiable(t); - IDynamicConstructor dc = DynamicConstructor.Create(t.GetConstructor(Type.EmptyTypes)); - dc.Invoke(ObjectUtils.EmptyObjects); - } - stop = DateTime.Now; - double timeElapsed = Elapsed; - PrintTest("SafeConstructor", numIterations, timeElapsed); - - start = DateTime.Now; - for (int i = 0; i < numIterations; i++) - { - ObjectUtils.InstantiateType(typeof (AccountCreditDao)); - } - stop = DateTime.Now; - timeElapsed = Elapsed; - PrintTest("InstantiateType", numIterations, timeElapsed); - - } - - private void DoTest(int numIterations, bool standardApiFirst, int sleepTimeMs, bool oneTx) - { - Console.WriteLine("sleeping for " + sleepTimeMs); - Thread.Sleep(sleepTimeMs); - double stdTime; - double templateTime; - if (standardApiFirst) - { - if (oneTx) - { - stdTime = UseStandardApiOneTx(numIterations); - } - else - { - stdTime = UseStandardApi(numIterations); - } - - CleanDb(); - Console.WriteLine("sleeping for " + sleepTimeMs); - Thread.Sleep(sleepTimeMs); - - if (oneTx) - { - templateTime = UseAdoTemplateApiOneTx(numIterations); - } - else - { - templateTime = UseAdoTemplateApi(numIterations); - } - - CleanDb(); + stdTime = UseStandardApiOneTx(numIterations); } else { - if (oneTx) - { - templateTime = UseAdoTemplateApiOneTx(numIterations); - } - else - { - templateTime = UseAdoTemplateApi(numIterations); - } - - CleanDb(); - Console.WriteLine("sleeping for " + sleepTimeMs); - Thread.Sleep(sleepTimeMs); - - if (oneTx) - { - stdTime = UseStandardApiOneTx(numIterations); - } - else - { - stdTime = UseStandardApi(numIterations); - } - - CleanDb(); + stdTime = UseStandardApi(numIterations); } - Console.WriteLine("stdTime = " + stdTime + ", templateTime = " + templateTime); - double percentDiff = ((2*Math.Abs(stdTime - templateTime))/(stdTime + templateTime))*100; - Console.WriteLine("stdTime-templateTime=" + (stdTime - templateTime)); - Console.WriteLine("% diff = " + percentDiff); - } - private double UseAdoTemplateApiOneTx(int numIterations) + CleanDb(); + Console.WriteLine("sleeping for " + sleepTimeMs); + Thread.Sleep(sleepTimeMs); + + if (oneTx) + { + templateTime = UseAdoTemplateApiOneTx(numIterations); + } + else + { + templateTime = UseAdoTemplateApi(numIterations); + } + + CleanDb(); + } + else { - AdoPlatformTransactionManager tm = new AdoPlatformTransactionManager(adoTemplate.DbProvider); + if (oneTx) + { + templateTime = UseAdoTemplateApiOneTx(numIterations); + } + else + { + templateTime = UseAdoTemplateApi(numIterations); + } - TransactionTemplate tt = new TransactionTemplate(tm); - double timeElapsed = 0; - tt.Execute(status => - { - start = DateTime.Now; - for (int i = 0; i < numIterations; i++) - { - adoTemplate.ExecuteNonQuery(CommandType.Text, cmdText); - } - stop = DateTime.Now; - timeElapsed = Elapsed; - PrintTest("AdoTemplateApi", numIterations, timeElapsed); - return null; - }); - return timeElapsed; + CleanDb(); + Console.WriteLine("sleeping for " + sleepTimeMs); + Thread.Sleep(sleepTimeMs); + + if (oneTx) + { + stdTime = UseStandardApiOneTx(numIterations); + } + else + { + stdTime = UseStandardApi(numIterations); + } + + CleanDb(); } - private double UseAdoTemplateApi(int numIterations) + Console.WriteLine("stdTime = " + stdTime + ", templateTime = " + templateTime); + double percentDiff = ((2 * Math.Abs(stdTime - templateTime)) / (stdTime + templateTime)) * 100; + Console.WriteLine("stdTime-templateTime=" + (stdTime - templateTime)); + Console.WriteLine("% diff = " + percentDiff); + } + + private double UseAdoTemplateApiOneTx(int numIterations) + { + AdoPlatformTransactionManager tm = new AdoPlatformTransactionManager(adoTemplate.DbProvider); + + TransactionTemplate tt = new TransactionTemplate(tm); + double timeElapsed = 0; + tt.Execute(status => { start = DateTime.Now; for (int i = 0; i < numIterations; i++) { adoTemplate.ExecuteNonQuery(CommandType.Text, cmdText); } + stop = DateTime.Now; - double timeElapsed = Elapsed; + timeElapsed = Elapsed; PrintTest("AdoTemplateApi", numIterations, timeElapsed); - return timeElapsed; + return null; + }); + return timeElapsed; + } + + private double UseAdoTemplateApi(int numIterations) + { + start = DateTime.Now; + for (int i = 0; i < numIterations; i++) + { + adoTemplate.ExecuteNonQuery(CommandType.Text, cmdText); } - private double UseStandardApiOneTx(int numIterations) + stop = DateTime.Now; + double timeElapsed = Elapsed; + PrintTest("AdoTemplateApi", numIterations, timeElapsed); + return timeElapsed; + } + + private double UseStandardApiOneTx(int numIterations) + { + start = DateTime.Now; + using (SqlConnection connection = new SqlConnection(adoTemplate.DbProvider.ConnectionString)) + { + using (SqlCommand command = new SqlCommand(cmdText, connection)) + { + connection.Open(); + SqlTransaction transaction = connection.BeginTransaction(); + command.Transaction = transaction; + for (int i = 0; i < numIterations; i++) + { + command.ExecuteNonQuery(); + } + + // no error handling.... + transaction.Commit(); + } + } + + stop = DateTime.Now; + double timeElapsed = Elapsed; + PrintTest("StandardAPI", numIterations, timeElapsed); + return timeElapsed; + } + + private double UseStandardApi(int numIterations) + { + start = DateTime.Now; + for (int i = 0; i < numIterations; i++) { - start = DateTime.Now; using (SqlConnection connection = new SqlConnection(adoTemplate.DbProvider.ConnectionString)) { using (SqlCommand command = new SqlCommand(cmdText, connection)) { connection.Open(); - SqlTransaction transaction = connection.BeginTransaction(); - command.Transaction = transaction; - for (int i = 0; i < numIterations; i++) - { - command.ExecuteNonQuery(); - } - // no error handling.... - transaction.Commit(); + command.ExecuteNonQuery(); } } - stop = DateTime.Now; - double timeElapsed = Elapsed; - PrintTest("StandardAPI", numIterations, timeElapsed); - return timeElapsed; } - private double UseStandardApi(int numIterations) - { - start = DateTime.Now; - for (int i = 0; i < numIterations; i++) - { - using (SqlConnection connection = new SqlConnection(adoTemplate.DbProvider.ConnectionString)) - { - using (SqlCommand command = new SqlCommand(cmdText, connection)) - { - connection.Open(); - command.ExecuteNonQuery(); - } - } - } - stop = DateTime.Now; - double timeElapsed = Elapsed; - PrintTest("StandardAPI", numIterations, timeElapsed); - return timeElapsed; - } + stop = DateTime.Now; + double timeElapsed = Elapsed; + PrintTest("StandardAPI", numIterations, timeElapsed); + return timeElapsed; + } + private double Elapsed + { + get { return (stop.Ticks - start.Ticks) / 10000000f; } + } - private double Elapsed - { - get { return (stop.Ticks - start.Ticks)/10000000f; } - } - - private static void PrintTest(string name, int iterations, double duration) - { - Debug.WriteLine( - String.Format("{0,-60} {1,12:#,###} {2,12:##0.000} {3,12:#,###}", name, iterations, duration, - iterations/duration)); - } + private static void PrintTest(string name, int iterations, double duration) + { + Debug.WriteLine( + String.Format("{0,-60} {1,12:#,###} {2,12:##0.000} {3,12:#,###}", name, iterations, duration, + iterations / duration)); } } diff --git a/test/Spring/Spring.Data.Integration.Tests/Data/AdoTemplateTests.cs b/test/Spring/Spring.Data.Integration.Tests/Data/AdoTemplateTests.cs index 8803c2b7..75cb6322 100644 --- a/test/Spring/Spring.Data.Integration.Tests/Data/AdoTemplateTests.cs +++ b/test/Spring/Spring.Data.Integration.Tests/Data/AdoTemplateTests.cs @@ -2,13 +2,13 @@ /* * Copyright � 2002-2011 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. @@ -35,348 +35,333 @@ using Spring.Transaction.Support; #endregion -namespace Spring.Data +namespace Spring.Data; + +/// +/// Simple exercising of the AdoTemplate +/// +/// Mark Pollack (.NET) +[TestFixture] +public class AdoTemplateTests { - /// - /// Simple exercising of the AdoTemplate - /// - /// Mark Pollack (.NET) - [TestFixture] - public class AdoTemplateTests - { - #region Fields - - IAdoOperations adoOperations; - IDbProvider dbProvider; - private IPlatformTransactionManager transactionManager; - - #endregion + #region Fields - #region Constructor (s) - /// - /// Initializes a new instance of the class. - /// - public AdoTemplateTests() - { + IAdoOperations adoOperations; + IDbProvider dbProvider; + private IPlatformTransactionManager transactionManager; - } + #endregion - #endregion + #region Constructor (s) - #region Methods - - [SetUp] - public void CreateAdoTemplate() - { - IApplicationContext ctx = - new XmlApplicationContext("assembly://Spring.Data.Integration.Tests/Spring.Data/adoTemplateTests.xml"); - Assert.IsNotNull(ctx); - dbProvider = ctx["DbProvider"] as IDbProvider; - Assert.IsNotNull(dbProvider); - adoOperations = new AdoTemplate(dbProvider); - transactionManager = new AdoPlatformTransactionManager(dbProvider); - - } - - [Test] - public void FillDataSetWithTwoDataTables() - { - PopulateTestObjectsTable(); - PopulateCreditObjectsTable(); - string testObjectsql = ValidateTestObjects(4); - string creditObjectsql = ValidateCreditObjects(4); - - DataSet dataSet; - - dataSet = new DataSet(); - adoOperations.DataSetFill(dataSet, CommandType.Text, testObjectsql + ";" + creditObjectsql, new string[] { "TestObjects", "CreditObjects" }); - Assert.AreEqual(2, dataSet.Tables.Count); - Assert.AreEqual(4, dataSet.Tables["TestObjects"].Rows.Count); - Assert.AreEqual(4, dataSet.Tables["CreditObjects"].Rows.Count); - } - - [Test] - public void FillDataSetNoParams() - { - PopulateTestObjectsTable(); - string sql = ValidateTestObjects(4); - DataSet dataSet; - - dataSet = new DataSet(); - adoOperations.DataSetFill(dataSet, CommandType.Text, sql, new string[] {"TestObjects"}); - Assert.AreEqual(1, dataSet.Tables.Count); - Assert.AreEqual(4, dataSet.Tables["TestObjects"].Rows.Count); - - dataSet = new DataSet(); - DataTableMappingCollection mappingCollection = - new DataTableMappingCollection(); - DataTableMapping testObjectsMapping = mappingCollection.Add("Table", "TestObjects"); - testObjectsMapping.ColumnMappings.Add("TestObjectNo", "UserID"); - testObjectsMapping.ColumnMappings.Add("Name", "UserName"); - adoOperations.DataSetFill(dataSet, CommandType.Text, sql, mappingCollection); - Assert.AreEqual(1, dataSet.Tables.Count); - Assert.AreEqual(4, dataSet.Tables["TestObjects"].Rows.Count); - foreach (DataRow testObjectRow in dataSet.Tables["TestObjects"].Rows) - { - Assert.IsNotNull(testObjectRow["UserID"]); - Assert.IsNotNull(testObjectRow["Age"]); - Assert.IsNotNull(testObjectRow["UserName"]); - } - - } - - [Test] - public void UpdateDataSet() - { - PopulateTestObjectsTable(); - ValidateTestObjects(4); - DoUpdateDataSet(); - ValidateTestObjects(5); - - } - - [Test] - public void UpdateDataSetTxRollback() - { - - PopulateTestObjectsTable(); - ValidateTestObjects(4); - TransactionTemplate tt = new TransactionTemplate(transactionManager); - try - { - object result = tt.Execute(new DataSetUpdateTransactionCallback(this, true)); - Assert.Fail("Should have thrown exception to rollback transaction."); - } catch (Exception) - { - ValidateTestObjects(4); - } - } - - private void PopulateTestObjectsTable() - { - adoOperations.ExecuteNonQuery(CommandType.Text, "truncate table TestObjects"); - int age = 18; - int counter = 0; - for (int i=0;i<4;i++) - { - String sql = - String.Format("insert into TestObjects(Age, Name) VALUES ({0}, '{1}')", age++, "George" + counter++); - adoOperations.ExecuteNonQuery(CommandType.Text, sql); - } - } - - private void PopulateCreditObjectsTable() - { - adoOperations.ExecuteNonQuery(CommandType.Text, "truncate table Credits"); - for (int i=0; i<4; i++) - { - String sql = String.Format("insert into Credits(CreditAmount) VALUES ('{0}')", i+10); - adoOperations.ExecuteNonQuery(CommandType.Text, sql); - } - } - - private string ValidateTestObjects(int count) - { - String sql = "select TestObjectNo, Age, Name from TestObjects"; - DataSet dataSet = new DataSet(); - adoOperations.DataSetFill(dataSet, CommandType.Text, sql); - Assert.AreEqual(1, dataSet.Tables.Count); - Assert.AreEqual(count, dataSet.Tables["Table"].Rows.Count); - return sql; - } - - private string ValidateCreditObjects(int count) - { - String sql = "select CreditID, CreditAmount from Credits"; - DataSet dataSet = new DataSet(); - adoOperations.DataSetFill(dataSet, CommandType.Text, sql); - Assert.AreEqual(1, dataSet.Tables.Count); - Assert.AreEqual(count, dataSet.Tables["Table"].Rows.Count); - return sql; - } - - - - public void DoUpdateDataSet() - { - String sql = "select TestObjectNo, Age, Name from TestObjects"; - DataSet dataSet = new DataSet(); - adoOperations.DataSetFill(dataSet, CommandType.Text, sql, new string[] { "TestObjects" }); - - //Create and add new row. - DataRow myDataRow = dataSet.Tables["TestObjects"].NewRow(); - myDataRow["Age"] = 101; - myDataRow["Name"] = "OldManWinter"; - dataSet.Tables["TestObjects"].Rows.Add(myDataRow); - - - IDbCommand insertCommand = dbProvider.CreateCommand(); - insertCommand.CommandText = "insert into TestObjects(Age,Name) values (@Age,@Name)"; - IDbParameters parameters = adoOperations.CreateDbParameters(); - parameters.Add("Name", DbType.String, 12, "Name"); - //TODO - remembering the -1 isn't all that natural... add string name, dbtype, string sourceCol) - //or AddSourceCol("Age", SqlDbType.Int); would copy into source col? - parameters.Add("Age", SqlDbType.Int, -1, "Age"); - - //TODO - this isn't all that natural... - ParameterUtils.CopyParameters(insertCommand, parameters); - - //insertCommand.Parameters.Add() - - adoOperations.DataSetUpdate(dataSet, "TestObjects", - insertCommand, - null, - null); - - //TODO avoid param Utils copy by adding argument... - - //adoOperations.DataSetUpdate(dataSet, "TestObjects", - // insertCommand, parameters, - // null, null, - // null, null); - - //adoOperations.DataSetUpdate(dataSet, "TestObjects", - // CommandType type, string sql, parameters, - // null, null, - // null, null); - - //TODO how about breaking up the operations... - } - - [Test] - public void ExecuteQueryWithResultSetExtractor() - { - PopulateTestObjectsTable(); - IResultSetExtractor rse = new TestObjectExtractor(); - String sql = "select TestObjectNo, Age, Name from TestObjects"; - IList testObjectList = (IList)adoOperations.QueryWithResultSetExtractor(CommandType.Text, sql, rse); - Assert.AreEqual(4, testObjectList.Count); - } - - - [Test] - public void ExecuteNonQueryText() - { - int age = 18; - int counter = 0; - String sql = String.Format("insert into TestObjects(Age, Name) VALUES ({0}, '{1}')", - age++, "George" + counter++); - adoOperations.ExecuteNonQuery(CommandType.Text, sql); - - - sql = "insert into TestObjects(Age,Name) values (@Age,@Name)"; - - //One liners are hard due to no standard 'fallback' to use of '?' for property - //placeholders. Providers that use named parameters must always use named - //parameters in SQL string. - - //NamedParameterAdoOperations ... - - - //More portable IDbDataParameterCollection implemenation. - // -> IDbParameters - //Functionality of .NET 2.0 DbParameterCollection + common helper methods that - //are commonly found (still) in subclasses. - - //How to create parameter collections? - //1. Get as much milage/portabiliyt out of basic provider interface and - // IDbDataParameter/IDataParameterCollection - // DbParameter/DbParameterCollection - // a. Must use only base DbType (can't cast as no shared base enumeration) - // b. Must use parameter prefix - // c. CLR null and DBNull.Value mapping. - // c. IsNullable is not writable in IDbDataParameter interface (1.1 only) - // c2. SourceColumnNullMapping? - // d. No convenient Add( parameter data ) methods in - // base Parameter Collection classes - // despite prevalence in provider implementations. - // d1. re-use of parameters - parameters are aware if they have been added to - // a collection of another command object. - // e. verbose - - - IDbParameters parametersCreated = new DbParameters(dbProvider); - - IDbDataParameter p = dbProvider.CreateParameter(); - p.ParameterName = "@Name"; - p.DbType = DbType.String; - p.Size = 12; - p.Value = "George" + counter++; - parametersCreated.AddParameter(p); - - IDbDataParameter p2 = dbProvider.CreateParameter(); - p2.ParameterName = "@Age"; - p2.DbType = DbType.Int32; - p2.Value = age++; - parametersCreated.AddParameter(p2); - - - - adoOperations.ExecuteNonQuery(CommandType.Text, sql, parametersCreated); - - //2. Use IDbParameters abstraction. - // e. less verbose... - IDbParameters parameters = adoOperations.CreateDbParameters(); - parameters.Add("Name", DbType.String, 12).Value = "George" + counter++; - parameters.Add("Age", SqlDbType.Int).Value = age++; - - //Better to use date example...people like to pick provider specific subtype.. - //parameters.AddWithValue("Age", age++); - - //parameters get 'cloned' before association with command, output values - //are re-associated, and so the parameter collection is re-usable. - adoOperations.ExecuteNonQuery(CommandType.Text, sql, parameters); - - } - - - - #endregion - - private class TestObjectExtractor : IResultSetExtractor - { - public object ExtractData(IDataReader reader) - { - IList testObjects = new ArrayList(); - while(reader.Read()) - { - TestObject to = new TestObject(); - to.ObjectNumber = reader.GetInt32(0); - to.Age = reader.GetInt32(1); - to.Name = reader.GetString(2); - testObjects.Add(to); - } - return testObjects; - } - } - - } - - internal class DataSetUpdateTransactionCallback : ITransactionCallback + /// + /// Initializes a new instance of the class. + /// + public AdoTemplateTests() { - private bool throwException; - private AdoTemplateTests adoTemplateTests; + } - public DataSetUpdateTransactionCallback(AdoTemplateTests adoTemplateTests, bool throwException) + #endregion + + #region Methods + + [SetUp] + public void CreateAdoTemplate() + { + IApplicationContext ctx = + new XmlApplicationContext("assembly://Spring.Data.Integration.Tests/Spring.Data/adoTemplateTests.xml"); + Assert.IsNotNull(ctx); + dbProvider = ctx["DbProvider"] as IDbProvider; + Assert.IsNotNull(dbProvider); + adoOperations = new AdoTemplate(dbProvider); + transactionManager = new AdoPlatformTransactionManager(dbProvider); + } + + [Test] + public void FillDataSetWithTwoDataTables() + { + PopulateTestObjectsTable(); + PopulateCreditObjectsTable(); + string testObjectsql = ValidateTestObjects(4); + string creditObjectsql = ValidateCreditObjects(4); + + DataSet dataSet; + + dataSet = new DataSet(); + adoOperations.DataSetFill(dataSet, CommandType.Text, testObjectsql + ";" + creditObjectsql, new string[] { "TestObjects", "CreditObjects" }); + Assert.AreEqual(2, dataSet.Tables.Count); + Assert.AreEqual(4, dataSet.Tables["TestObjects"].Rows.Count); + Assert.AreEqual(4, dataSet.Tables["CreditObjects"].Rows.Count); + } + + [Test] + public void FillDataSetNoParams() + { + PopulateTestObjectsTable(); + string sql = ValidateTestObjects(4); + DataSet dataSet; + + dataSet = new DataSet(); + adoOperations.DataSetFill(dataSet, CommandType.Text, sql, new string[] { "TestObjects" }); + Assert.AreEqual(1, dataSet.Tables.Count); + Assert.AreEqual(4, dataSet.Tables["TestObjects"].Rows.Count); + + dataSet = new DataSet(); + DataTableMappingCollection mappingCollection = + new DataTableMappingCollection(); + DataTableMapping testObjectsMapping = mappingCollection.Add("Table", "TestObjects"); + testObjectsMapping.ColumnMappings.Add("TestObjectNo", "UserID"); + testObjectsMapping.ColumnMappings.Add("Name", "UserName"); + adoOperations.DataSetFill(dataSet, CommandType.Text, sql, mappingCollection); + Assert.AreEqual(1, dataSet.Tables.Count); + Assert.AreEqual(4, dataSet.Tables["TestObjects"].Rows.Count); + foreach (DataRow testObjectRow in dataSet.Tables["TestObjects"].Rows) { - this.throwException = throwException; - this.adoTemplateTests = adoTemplateTests; + Assert.IsNotNull(testObjectRow["UserID"]); + Assert.IsNotNull(testObjectRow["Age"]); + Assert.IsNotNull(testObjectRow["UserName"]); } + } - /// - /// Gets called by TransactionTemplate.Execute within a - /// transaction context. - /// - /// The associated transaction status. - /// A result object or null. - public object DoInTransaction(ITransactionStatus status) + [Test] + public void UpdateDataSet() + { + PopulateTestObjectsTable(); + ValidateTestObjects(4); + DoUpdateDataSet(); + ValidateTestObjects(5); + } + + [Test] + public void UpdateDataSetTxRollback() + { + PopulateTestObjectsTable(); + ValidateTestObjects(4); + TransactionTemplate tt = new TransactionTemplate(transactionManager); + try { - if (throwException) + object result = tt.Execute(new DataSetUpdateTransactionCallback(this, true)); + Assert.Fail("Should have thrown exception to rollback transaction."); + } + catch (Exception) + { + ValidateTestObjects(4); + } + } + + private void PopulateTestObjectsTable() + { + adoOperations.ExecuteNonQuery(CommandType.Text, "truncate table TestObjects"); + int age = 18; + int counter = 0; + for (int i = 0; i < 4; i++) + { + String sql = + String.Format("insert into TestObjects(Age, Name) VALUES ({0}, '{1}')", age++, "George" + counter++); + adoOperations.ExecuteNonQuery(CommandType.Text, sql); + } + } + + private void PopulateCreditObjectsTable() + { + adoOperations.ExecuteNonQuery(CommandType.Text, "truncate table Credits"); + for (int i = 0; i < 4; i++) + { + String sql = String.Format("insert into Credits(CreditAmount) VALUES ('{0}')", i + 10); + adoOperations.ExecuteNonQuery(CommandType.Text, sql); + } + } + + private string ValidateTestObjects(int count) + { + String sql = "select TestObjectNo, Age, Name from TestObjects"; + DataSet dataSet = new DataSet(); + adoOperations.DataSetFill(dataSet, CommandType.Text, sql); + Assert.AreEqual(1, dataSet.Tables.Count); + Assert.AreEqual(count, dataSet.Tables["Table"].Rows.Count); + return sql; + } + + private string ValidateCreditObjects(int count) + { + String sql = "select CreditID, CreditAmount from Credits"; + DataSet dataSet = new DataSet(); + adoOperations.DataSetFill(dataSet, CommandType.Text, sql); + Assert.AreEqual(1, dataSet.Tables.Count); + Assert.AreEqual(count, dataSet.Tables["Table"].Rows.Count); + return sql; + } + + public void DoUpdateDataSet() + { + String sql = "select TestObjectNo, Age, Name from TestObjects"; + DataSet dataSet = new DataSet(); + adoOperations.DataSetFill(dataSet, CommandType.Text, sql, new string[] { "TestObjects" }); + + //Create and add new row. + DataRow myDataRow = dataSet.Tables["TestObjects"].NewRow(); + myDataRow["Age"] = 101; + myDataRow["Name"] = "OldManWinter"; + dataSet.Tables["TestObjects"].Rows.Add(myDataRow); + + IDbCommand insertCommand = dbProvider.CreateCommand(); + insertCommand.CommandText = "insert into TestObjects(Age,Name) values (@Age,@Name)"; + IDbParameters parameters = adoOperations.CreateDbParameters(); + parameters.Add("Name", DbType.String, 12, "Name"); + //TODO - remembering the -1 isn't all that natural... add string name, dbtype, string sourceCol) + //or AddSourceCol("Age", SqlDbType.Int); would copy into source col? + parameters.Add("Age", SqlDbType.Int, -1, "Age"); + + //TODO - this isn't all that natural... + ParameterUtils.CopyParameters(insertCommand, parameters); + + //insertCommand.Parameters.Add() + + adoOperations.DataSetUpdate(dataSet, "TestObjects", + insertCommand, + null, + null); + + //TODO avoid param Utils copy by adding argument... + + //adoOperations.DataSetUpdate(dataSet, "TestObjects", + // insertCommand, parameters, + // null, null, + // null, null); + + //adoOperations.DataSetUpdate(dataSet, "TestObjects", + // CommandType type, string sql, parameters, + // null, null, + // null, null); + + //TODO how about breaking up the operations... + } + + [Test] + public void ExecuteQueryWithResultSetExtractor() + { + PopulateTestObjectsTable(); + IResultSetExtractor rse = new TestObjectExtractor(); + String sql = "select TestObjectNo, Age, Name from TestObjects"; + IList testObjectList = (IList) adoOperations.QueryWithResultSetExtractor(CommandType.Text, sql, rse); + Assert.AreEqual(4, testObjectList.Count); + } + + [Test] + public void ExecuteNonQueryText() + { + int age = 18; + int counter = 0; + String sql = String.Format("insert into TestObjects(Age, Name) VALUES ({0}, '{1}')", + age++, "George" + counter++); + adoOperations.ExecuteNonQuery(CommandType.Text, sql); + + sql = "insert into TestObjects(Age,Name) values (@Age,@Name)"; + + //One liners are hard due to no standard 'fallback' to use of '?' for property + //placeholders. Providers that use named parameters must always use named + //parameters in SQL string. + + //NamedParameterAdoOperations ... + + //More portable IDbDataParameterCollection implemenation. + // -> IDbParameters + //Functionality of .NET 2.0 DbParameterCollection + common helper methods that + //are commonly found (still) in subclasses. + + //How to create parameter collections? + //1. Get as much milage/portabiliyt out of basic provider interface and + // IDbDataParameter/IDataParameterCollection + // DbParameter/DbParameterCollection + // a. Must use only base DbType (can't cast as no shared base enumeration) + // b. Must use parameter prefix + // c. CLR null and DBNull.Value mapping. + // c. IsNullable is not writable in IDbDataParameter interface (1.1 only) + // c2. SourceColumnNullMapping? + // d. No convenient Add( parameter data ) methods in + // base Parameter Collection classes + // despite prevalence in provider implementations. + // d1. re-use of parameters - parameters are aware if they have been added to + // a collection of another command object. + // e. verbose + + IDbParameters parametersCreated = new DbParameters(dbProvider); + + IDbDataParameter p = dbProvider.CreateParameter(); + p.ParameterName = "@Name"; + p.DbType = DbType.String; + p.Size = 12; + p.Value = "George" + counter++; + parametersCreated.AddParameter(p); + + IDbDataParameter p2 = dbProvider.CreateParameter(); + p2.ParameterName = "@Age"; + p2.DbType = DbType.Int32; + p2.Value = age++; + parametersCreated.AddParameter(p2); + + adoOperations.ExecuteNonQuery(CommandType.Text, sql, parametersCreated); + + //2. Use IDbParameters abstraction. + // e. less verbose... + IDbParameters parameters = adoOperations.CreateDbParameters(); + parameters.Add("Name", DbType.String, 12).Value = "George" + counter++; + parameters.Add("Age", SqlDbType.Int).Value = age++; + + //Better to use date example...people like to pick provider specific subtype.. + //parameters.AddWithValue("Age", age++); + + //parameters get 'cloned' before association with command, output values + //are re-associated, and so the parameter collection is re-usable. + adoOperations.ExecuteNonQuery(CommandType.Text, sql, parameters); + } + + #endregion + + private class TestObjectExtractor : IResultSetExtractor + { + public object ExtractData(IDataReader reader) + { + IList testObjects = new ArrayList(); + while (reader.Read()) { - throw new ArgumentException("Explicitly thrown exception"); + TestObject to = new TestObject(); + to.ObjectNumber = reader.GetInt32(0); + to.Age = reader.GetInt32(1); + to.Name = reader.GetString(2); + testObjects.Add(to); } - adoTemplateTests.DoUpdateDataSet(); - return null; + + return testObjects; } } } + +internal class DataSetUpdateTransactionCallback : ITransactionCallback +{ + private bool throwException; + private AdoTemplateTests adoTemplateTests; + + public DataSetUpdateTransactionCallback(AdoTemplateTests adoTemplateTests, bool throwException) + { + this.throwException = throwException; + this.adoTemplateTests = adoTemplateTests; + } + + /// + /// Gets called by TransactionTemplate.Execute within a + /// transaction context. + /// + /// The associated transaction status. + /// A result object or null. + public object DoInTransaction(ITransactionStatus status) + { + if (throwException) + { + throw new ArgumentException("Explicitly thrown exception"); + } + + adoTemplateTests.DoUpdateDataSet(); + return null; + } +} diff --git a/test/Spring/Spring.Data.Integration.Tests/Data/AutoDeclarativeTxTests.cs b/test/Spring/Spring.Data.Integration.Tests/Data/AutoDeclarativeTxTests.cs index 9011c619..33f17608 100644 --- a/test/Spring/Spring.Data.Integration.Tests/Data/AutoDeclarativeTxTests.cs +++ b/test/Spring/Spring.Data.Integration.Tests/Data/AutoDeclarativeTxTests.cs @@ -1,14 +1,14 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. - * + * Copyright � 2002-2011 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. @@ -28,48 +28,45 @@ using Spring.Transaction; #endregion -namespace Spring.Data +namespace Spring.Data; + +/// +/// Test case that uses the approach of automatically creating +/// declarative transaction interceptors for objects identified via means +/// of transaction attributes. +/// +/// Mark Pollack (.NET) +[TestFixture] +public class AutoDeclarativeTxTests { - /// - /// Test case that uses the approach of automatically creating - /// declarative transaction interceptors for objects identified via means - /// of transaction attributes. - /// - /// Mark Pollack (.NET) - [TestFixture] - public class AutoDeclarativeTxTests - { - private IDbProvider dbProvider; + private IDbProvider dbProvider; - private IPlatformTransactionManager transactionManager; + private IPlatformTransactionManager transactionManager; - private IApplicationContext ctx; + private IApplicationContext ctx; - [SetUp] - public void SetUp() - { - ctx = - new XmlApplicationContext("assembly://Spring.Data.Integration.Tests/Spring.Data/autoDeclarativeServices.xml"); - dbProvider = ctx["DbProvider"] as IDbProvider; - transactionManager = ctx["adoTransactionManager"] as IPlatformTransactionManager; - - } + [SetUp] + public void SetUp() + { + ctx = + new XmlApplicationContext("assembly://Spring.Data.Integration.Tests/Spring.Data/autoDeclarativeServices.xml"); + dbProvider = ctx["DbProvider"] as IDbProvider; + transactionManager = ctx["adoTransactionManager"] as IPlatformTransactionManager; + } - [Test] - public void DeclarativeWithAttributes() - { - ITestObjectManager mgr = ctx["testObjectManager"] as ITestObjectManager; - TestObjectDao dao = (TestObjectDao)ctx["testObjectDao"]; - TransactionTemplateTests.PerformOperations(mgr, dao); - } + [Test] + public void DeclarativeWithAttributes() + { + ITestObjectManager mgr = ctx["testObjectManager"] as ITestObjectManager; + TestObjectDao dao = (TestObjectDao) ctx["testObjectDao"]; + TransactionTemplateTests.PerformOperations(mgr, dao); + } - [Test] - public void CoordinatorDeclarativeWithAttributes() - { - ITestCoordinator coord = ctx["testCoordinator"] as ITestCoordinator; - TestObjectDao dao = (TestObjectDao)ctx["testObjectDao"]; - TransactionTemplateTests.PerformOperations(coord, dao); - } - - } + [Test] + public void CoordinatorDeclarativeWithAttributes() + { + ITestCoordinator coord = ctx["testCoordinator"] as ITestCoordinator; + TestObjectDao dao = (TestObjectDao) ctx["testObjectDao"]; + TransactionTemplateTests.PerformOperations(coord, dao); + } } diff --git a/test/Spring/Spring.Data.Integration.Tests/Data/CallCreateTestObject.cs b/test/Spring/Spring.Data.Integration.Tests/Data/CallCreateTestObject.cs index a80ca0cc..04ad32b8 100644 --- a/test/Spring/Spring.Data.Integration.Tests/Data/CallCreateTestObject.cs +++ b/test/Spring/Spring.Data.Integration.Tests/Data/CallCreateTestObject.cs @@ -1,14 +1,14 @@ #region Licence /* - * Copyright © 2002-2011 the original author or authors. - * + * Copyright � 2002-2011 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. @@ -25,35 +25,33 @@ using Spring.Data.Objects; #endregion -namespace Spring.Data +namespace Spring.Data; + +/// +/// Simple stored procedure with only 'in' args to create a testobject record +/// +/// Mark Pollack (.NET) +public class CallCreateTestObject : StoredProcedure { - /// - /// Simple stored procedure with only 'in' args to create a testobject record - /// - /// Mark Pollack (.NET) - public class CallCreateTestObject : StoredProcedure - { - private static string procedureName = "CreateTestObject"; - - public CallCreateTestObject(IDbProvider dbProvider) : base(dbProvider, procedureName) - { - DeriveParameters(); - Compile(); - } + private static string procedureName = "CreateTestObject"; - public void Create(string name, int age) - { - //if know the ordering of input parameters for the SP - ExecuteNonQuery(name, age); - - //if want to use named params - /* - IDictionary inParams = new Hashtable(); - inParams["@name"] = name; - inParams["@age"] = age; - IDictionary outParams = ExecuteNonQuery(inParams); - */ - } + public CallCreateTestObject(IDbProvider dbProvider) : base(dbProvider, procedureName) + { + DeriveParameters(); + Compile(); + } - } + public void Create(string name, int age) + { + //if know the ordering of input parameters for the SP + ExecuteNonQuery(name, age); + + //if want to use named params + /* + IDictionary inParams = new Hashtable(); + inParams["@name"] = name; + inParams["@age"] = age; + IDictionary outParams = ExecuteNonQuery(inParams); + */ + } } diff --git a/test/Spring/Spring.Data.Integration.Tests/Data/ConsoleLoggingAroundAdvice.cs b/test/Spring/Spring.Data.Integration.Tests/Data/ConsoleLoggingAroundAdvice.cs index 51447399..51f018f1 100644 --- a/test/Spring/Spring.Data.Integration.Tests/Data/ConsoleLoggingAroundAdvice.cs +++ b/test/Spring/Spring.Data.Integration.Tests/Data/ConsoleLoggingAroundAdvice.cs @@ -1,17 +1,17 @@ using AopAlliance.Intercept; using Microsoft.Extensions.Logging; -namespace Spring.Data +namespace Spring.Data; + +public class ConsoleLoggingAroundAdvice : IMethodInterceptor { - public class ConsoleLoggingAroundAdvice : IMethodInterceptor + private static readonly ILog LOG = LogManager.GetLogger(); + + public object Invoke(IMethodInvocation invocation) { - private static readonly ILog LOG = LogManager.GetLogger(); - public object Invoke(IMethodInvocation invocation) - { - LOG.LogDebug("Advice executing; calling the advised method [" + invocation.Method.Name + "]"); - object returnValue = invocation.Proceed(); - LOG.LogDebug("Advice executed; advised method [" + invocation.Method.Name + "] returned " + returnValue); - return returnValue; - } + LOG.LogDebug("Advice executing; calling the advised method [" + invocation.Method.Name + "]"); + object returnValue = invocation.Proceed(); + LOG.LogDebug("Advice executed; advised method [" + invocation.Method.Name + "] returned " + returnValue); + return returnValue; } } diff --git a/test/Spring/Spring.Data.Integration.Tests/Data/CreateTestObjectNonQuery.cs b/test/Spring/Spring.Data.Integration.Tests/Data/CreateTestObjectNonQuery.cs index 58392e95..8a1564f3 100644 --- a/test/Spring/Spring.Data.Integration.Tests/Data/CreateTestObjectNonQuery.cs +++ b/test/Spring/Spring.Data.Integration.Tests/Data/CreateTestObjectNonQuery.cs @@ -1,14 +1,14 @@ #region Licence /* - * Copyright © 2002-2011 the original author or authors. - * + * Copyright � 2002-2011 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. @@ -26,27 +26,25 @@ using Spring.Data.Objects; #endregion -namespace Spring.Data +namespace Spring.Data; + +/// +/// Simple insert non query object with 'in' args to create a testobject. +/// +/// Mark Pollack (.NET) +public class CreateTestObjectNonQuery : AdoNonQuery { - /// - /// Simple insert non query object with 'in' args to create a testobject. - /// - /// Mark Pollack (.NET) - public class CreateTestObjectNonQuery : AdoNonQuery - { - private static string sql = "insert into TestObjects(Age,Name) values (@Age,@Name)"; - - public CreateTestObjectNonQuery(IDbProvider dbProvider) : base(dbProvider, sql) - { - DeclaredParameters.Add("Age", DbType.Int32); - DeclaredParameters.Add("Name", SqlDbType.NVarChar, 16); - Compile(); - } + private static string sql = "insert into TestObjects(Age,Name) values (@Age,@Name)"; - public void Create(string name, int age) - { - ExecuteNonQuery(name, age); - } + public CreateTestObjectNonQuery(IDbProvider dbProvider) : base(dbProvider, sql) + { + DeclaredParameters.Add("Age", DbType.Int32); + DeclaredParameters.Add("Name", SqlDbType.NVarChar, 16); + Compile(); + } - } + public void Create(string name, int age) + { + ExecuteNonQuery(name, age); + } } diff --git a/test/Spring/Spring.Data.Integration.Tests/Data/DTC1.1AppContext.xml b/test/Spring/Spring.Data.Integration.Tests/Data/DTC1.1AppContext.xml index 0e5c4140..87a22c5c 100644 --- a/test/Spring/Spring.Data.Integration.Tests/Data/DTC1.1AppContext.xml +++ b/test/Spring/Spring.Data.Integration.Tests/Data/DTC1.1AppContext.xml @@ -1,26 +1,26 @@ - + - + - + - + - + - + - - + + - - + - - - - - + --> - - - + + + + - - - - + + + - - - + + + + + + + + + + - - - - - + + - - - - + + Spring.Data.IAccountManager transactionInterceptor - - + + - - - - - - + + + + + + - - + + \ No newline at end of file diff --git a/test/Spring/Spring.Data.Integration.Tests/Data/DTCAppContext.xml b/test/Spring/Spring.Data.Integration.Tests/Data/DTCAppContext.xml index a9af1df9..2a0b4b6d 100644 --- a/test/Spring/Spring.Data.Integration.Tests/Data/DTCAppContext.xml +++ b/test/Spring/Spring.Data.Integration.Tests/Data/DTCAppContext.xml @@ -5,127 +5,125 @@ xmlns:aop="http://www.springframework.net/aop"> - + - + - - - - - + connectionString="Data Source=SPRINGQA;Initial Catalog=Debits;Persist Security Info=True;User ID=springqa;Password=springqa" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - - - - + + + + + + + - - + + + - - + + + + + \ No newline at end of file diff --git a/test/Spring/Spring.Data.Integration.Tests/Data/DTCAppContextNoInterfaces.xml b/test/Spring/Spring.Data.Integration.Tests/Data/DTCAppContextNoInterfaces.xml index e6bb7419..131fc6db 100644 --- a/test/Spring/Spring.Data.Integration.Tests/Data/DTCAppContextNoInterfaces.xml +++ b/test/Spring/Spring.Data.Integration.Tests/Data/DTCAppContextNoInterfaces.xml @@ -1,16 +1,16 @@ - + - - - + + + - + @@ -20,67 +20,65 @@
--> - + - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + - - - - - + + - - + + + + + - - - - - - + + + + + + - - + +
\ No newline at end of file diff --git a/test/Spring/Spring.Data.Integration.Tests/Data/DTCTests.cs b/test/Spring/Spring.Data.Integration.Tests/Data/DTCTests.cs index 3a3759b8..ac0d3d62 100644 --- a/test/Spring/Spring.Data.Integration.Tests/Data/DTCTests.cs +++ b/test/Spring/Spring.Data.Integration.Tests/Data/DTCTests.cs @@ -2,13 +2,13 @@ /* * Copyright © 2002-2011 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. @@ -21,43 +21,40 @@ #region Imports using NUnit.Framework; - using Spring.Context; using Spring.Context.Support; #endregion -namespace Spring.Data +namespace Spring.Data; + +[TestFixture] +public class DTCTests { - [TestFixture] - public class DTCTests - { - private IApplicationContext ctx; + private IApplicationContext ctx; - [SetUp] - public void SetUp() - { - //BasicConfigurator.Configure(); - //Console.WriteLine("Hello"); - //LogManager.Adapter = new ConsoleOutLoggerFactoryAdapter(new NameValueCollection()); + [SetUp] + public void SetUp() + { + //BasicConfigurator.Configure(); + //Console.WriteLine("Hello"); + //LogManager.Adapter = new ConsoleOutLoggerFactoryAdapter(new NameValueCollection()); - //WELLKNOWN: NamespaceParserRegistry.RegisterParser(typeof(TxNamespaceParser)); - //WELLKNOWN: 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.Data.Integration.Tests/Spring.Data/" + ctxName); - } + //WELLKNOWN: NamespaceParserRegistry.RegisterParser(typeof(TxNamespaceParser)); + //WELLKNOWN: 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.Data.Integration.Tests/Spring.Data/" + ctxName); + } - [Test] + [Test] #if NETCOREAPP [Ignore("Not supported on .NET Core")] #endif - public void DeclarativeWithAttributes() - { - IAccountManager mgr = ctx["accountManager"] as IAccountManager; - mgr.DoTransfer(100, 100); - } - - } + public void DeclarativeWithAttributes() + { + IAccountManager mgr = ctx["accountManager"] as IAccountManager; + mgr.DoTransfer(100, 100); + } } diff --git a/test/Spring/Spring.Data.Integration.Tests/Data/DTCTestsNoInterfaces.cs b/test/Spring/Spring.Data.Integration.Tests/Data/DTCTestsNoInterfaces.cs index c8e2d11f..e574f197 100644 --- a/test/Spring/Spring.Data.Integration.Tests/Data/DTCTestsNoInterfaces.cs +++ b/test/Spring/Spring.Data.Integration.Tests/Data/DTCTestsNoInterfaces.cs @@ -1,14 +1,14 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. - * + * Copyright � 2002-2011 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. @@ -26,32 +26,30 @@ using Spring.Context.Support; #endregion -namespace Spring.Data +namespace Spring.Data; + +[TestFixture] +public class DTCTestsNoInterfaces { - [TestFixture] - public class DTCTestsNoInterfaces - { - private IApplicationContext ctx; + private IApplicationContext ctx; - [SetUp] - public void SetUp() - { - //BasicConfigurator.Configure(); - string ctxName = "DTCAppContextNoInterfaces.xml"; // for .NET 2.0 - //string ctxName = "DTC1.1AppContextNoInterfaces.xml"; // for .NET 1.1 - ctx = - new XmlApplicationContext("assembly://Spring.Data.Integration.Tests/Spring.Data/" + ctxName); - } + [SetUp] + public void SetUp() + { + //BasicConfigurator.Configure(); + string ctxName = "DTCAppContextNoInterfaces.xml"; // for .NET 2.0 + //string ctxName = "DTC1.1AppContextNoInterfaces.xml"; // for .NET 1.1 + ctx = + new XmlApplicationContext("assembly://Spring.Data.Integration.Tests/Spring.Data/" + ctxName); + } - [Test] + [Test] #if NETCOREAPP [Ignore("Not supported on .NET Core")] #endif - public void DeclarativeWithAttributes() - { - SimpleAccountManager mgr = ctx["accountManager"] as SimpleAccountManager; - mgr.DoTransfer(115, 115); - } - - } + public void DeclarativeWithAttributes() + { + SimpleAccountManager mgr = ctx["accountManager"] as SimpleAccountManager; + mgr.DoTransfer(115, 115); + } } diff --git a/test/Spring/Spring.Data.Integration.Tests/Data/DeclarativeTxTests.cs b/test/Spring/Spring.Data.Integration.Tests/Data/DeclarativeTxTests.cs index 6bc7b5a9..f7372b12 100644 --- a/test/Spring/Spring.Data.Integration.Tests/Data/DeclarativeTxTests.cs +++ b/test/Spring/Spring.Data.Integration.Tests/Data/DeclarativeTxTests.cs @@ -1,14 +1,14 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. - * + * Copyright � 2002-2011 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. @@ -28,38 +28,35 @@ using Spring.Transaction; #endregion -namespace Spring.Data +namespace Spring.Data; + +/// +/// Test for declarative transaction management +/// +/// Mark Pollack (.NET) +[TestFixture] +public class DeclarativeTxTests { - /// - /// Test for declarative transaction management - /// - /// Mark Pollack (.NET) - [TestFixture] - public class DeclarativeTxTests - { - private IDbProvider dbProvider; + private IDbProvider dbProvider; - private IPlatformTransactionManager transactionManager; + private IPlatformTransactionManager transactionManager; - private IApplicationContext ctx; + private IApplicationContext ctx; - [SetUp] - public void SetUp() - { - ctx = - new XmlApplicationContext("assembly://Spring.Data.Integration.Tests/Spring.Data/declarativeServices.xml"); - dbProvider = ctx["DbProvider"] as IDbProvider; - transactionManager = ctx["adoTransactionManager"] as IPlatformTransactionManager; - - } + [SetUp] + public void SetUp() + { + ctx = + new XmlApplicationContext("assembly://Spring.Data.Integration.Tests/Spring.Data/declarativeServices.xml"); + dbProvider = ctx["DbProvider"] as IDbProvider; + transactionManager = ctx["adoTransactionManager"] as IPlatformTransactionManager; + } - [Test] - public void DeclarativeWithAttributes() - { - ITestObjectManager mgr = ctx["testObjectManager"] as ITestObjectManager; - TestObjectDao dao = (TestObjectDao)ctx["testObjectDao"]; - TransactionTemplateTests.PerformOperations(mgr, dao); - } - - } + [Test] + public void DeclarativeWithAttributes() + { + ITestObjectManager mgr = ctx["testObjectManager"] as ITestObjectManager; + TestObjectDao dao = (TestObjectDao) ctx["testObjectDao"]; + TransactionTemplateTests.PerformOperations(mgr, dao); + } } diff --git a/test/Spring/Spring.Data.Integration.Tests/Data/Generic/GenericAdoTemplateTests.cs b/test/Spring/Spring.Data.Integration.Tests/Data/Generic/GenericAdoTemplateTests.cs index 8ffee052..cc50c7b1 100644 --- a/test/Spring/Spring.Data.Integration.Tests/Data/Generic/GenericAdoTemplateTests.cs +++ b/test/Spring/Spring.Data.Integration.Tests/Data/Generic/GenericAdoTemplateTests.cs @@ -2,13 +2,13 @@ /* * Copyright � 2002-2011 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. @@ -26,119 +26,118 @@ using Spring.Context; using Spring.Context.Support; using Spring.Objects; -namespace Spring.Data.Generic +namespace Spring.Data.Generic; + +[TestFixture] +public class GenericAdoTemplateTests { - [TestFixture] - public class GenericAdoTemplateTests + private AdoTemplate adoTemplate; + + [SetUp] + public void SetUp() { - private AdoTemplate adoTemplate; + IApplicationContext ctx = + new XmlApplicationContext( + "assembly://Spring.Data.Integration.Tests/Spring.Data.Generic/GenericAdoTemplateTests.xml"); - [SetUp] - public void SetUp() - { - IApplicationContext ctx = - new XmlApplicationContext( - "assembly://Spring.Data.Integration.Tests/Spring.Data.Generic/GenericAdoTemplateTests.xml"); + adoTemplate = ctx["adoTemplate"] as AdoTemplate; - adoTemplate = ctx["adoTemplate"] as AdoTemplate; - - RemoveTestData(); - PopulateTestData(); - } - - private void PopulateTestData() - { - adoTemplate.ExecuteScalar(CommandType.Text, "insert into TestObjects values (10, 'Jack')"); - adoTemplate.ExecuteScalar(CommandType.Text, "insert into TestObjects values (20, 'Jill')"); - } - - [TearDown] - public void TearDown() - { - RemoveTestData(); - } - - private void RemoveTestData() - { - adoTemplate.ExecuteNonQuery(CommandType.Text, "delete TestObjects"); - } - - - [Test] - public void CommandDelegateUsage() - { - string name = "Jack"; - int count = adoTemplate.Execute(command => - { - command.CommandText = - "select count(*) from TestObjects where Name = @Name"; - - DbParameter p = command.CreateParameter(); - p.ParameterName = "@Name"; - p.Value = name; - command.Parameters.Add(p); - - return (int) command.ExecuteScalar(); - }); - Assert.AreEqual(1, count); - } - - [Test] - public void CommandDelegateUsageDownCast() - { - string name = "Jack"; - int count = adoTemplate.Execute((DbCommand command) => - { - SqlCommand sqlCommand = command as SqlCommand; - command.CommandText = - "select count(*) from TestObjects where Name = @Name"; - - sqlCommand.Parameters.AddWithValue("@Name", name); - - return (int) command.ExecuteScalar(); - }); - Assert.AreEqual(1, count); - } - - [Test] - public void TestCallbacks() - { - TestObjectDao testDao = new TestObjectDao(); - testDao.AdoTemplate = adoTemplate; - IList testObjects = testDao.FindAll(); - Assert.IsNotNull(testObjects); - } - - [Test] - public void TestQueryWithCommandCreators() - { - IDbCommandCreatorFactory ccf = new IDbCommandCreatorFactory(adoTemplate.DbProvider, CommandType.Text, "select TestObjectNo, Age, Name from TestObjects", null); - IDbCommandCreator cc = ccf.NewDbCommandCreator(null); - IList testObjects = adoTemplate.QueryWithCommandCreator(cc, - new TestObjectResultSetExtractor>()); - Assert.IsNotNull(testObjects); - Assert.AreEqual(2, testObjects.Count); - foreach (TestObject o in testObjects) - { - Console.WriteLine(o); - } - } + RemoveTestData(); + PopulateTestData(); } - internal class TestObjectResultSetExtractor : IResultSetExtractor where T : IList, new() + private void PopulateTestData() { - public T ExtractData(IDataReader reader) + adoTemplate.ExecuteScalar(CommandType.Text, "insert into TestObjects values (10, 'Jack')"); + adoTemplate.ExecuteScalar(CommandType.Text, "insert into TestObjects values (20, 'Jill')"); + } + + [TearDown] + public void TearDown() + { + RemoveTestData(); + } + + private void RemoveTestData() + { + adoTemplate.ExecuteNonQuery(CommandType.Text, "delete TestObjects"); + } + + [Test] + public void CommandDelegateUsage() + { + string name = "Jack"; + int count = adoTemplate.Execute(command => { - T testObjectList = new T(); - while(reader.Read()) - { - TestObject to = new TestObject(); - to.ObjectNumber = reader.GetInt32(0); - to.Age = reader.GetInt32(1); - to.Name = reader.GetString(2); - testObjectList.Add(to); - } - return testObjectList; + command.CommandText = + "select count(*) from TestObjects where Name = @Name"; + + DbParameter p = command.CreateParameter(); + p.ParameterName = "@Name"; + p.Value = name; + command.Parameters.Add(p); + + return (int) command.ExecuteScalar(); + }); + Assert.AreEqual(1, count); + } + + [Test] + public void CommandDelegateUsageDownCast() + { + string name = "Jack"; + int count = adoTemplate.Execute((DbCommand command) => + { + SqlCommand sqlCommand = command as SqlCommand; + command.CommandText = + "select count(*) from TestObjects where Name = @Name"; + + sqlCommand.Parameters.AddWithValue("@Name", name); + + return (int) command.ExecuteScalar(); + }); + Assert.AreEqual(1, count); + } + + [Test] + public void TestCallbacks() + { + TestObjectDao testDao = new TestObjectDao(); + testDao.AdoTemplate = adoTemplate; + IList testObjects = testDao.FindAll(); + Assert.IsNotNull(testObjects); + } + + [Test] + public void TestQueryWithCommandCreators() + { + IDbCommandCreatorFactory ccf = new IDbCommandCreatorFactory(adoTemplate.DbProvider, CommandType.Text, "select TestObjectNo, Age, Name from TestObjects", null); + IDbCommandCreator cc = ccf.NewDbCommandCreator(null); + IList testObjects = adoTemplate.QueryWithCommandCreator(cc, + new TestObjectResultSetExtractor>()); + Assert.IsNotNull(testObjects); + Assert.AreEqual(2, testObjects.Count); + foreach (TestObject o in testObjects) + { + Console.WriteLine(o); } } } + +internal class TestObjectResultSetExtractor : IResultSetExtractor where T : IList, new() +{ + public T ExtractData(IDataReader reader) + { + T testObjectList = new T(); + while (reader.Read()) + { + TestObject to = new TestObject(); + to.ObjectNumber = reader.GetInt32(0); + to.Age = reader.GetInt32(1); + to.Name = reader.GetString(2); + testObjectList.Add(to); + } + + return testObjectList; + } +} \ No newline at end of file diff --git a/test/Spring/Spring.Data.Integration.Tests/Data/Generic/GenericAdoTemplateTests.xml b/test/Spring/Spring.Data.Integration.Tests/Data/Generic/GenericAdoTemplateTests.xml index f3317929..725cb425 100644 --- a/test/Spring/Spring.Data.Integration.Tests/Data/Generic/GenericAdoTemplateTests.xml +++ b/test/Spring/Spring.Data.Integration.Tests/Data/Generic/GenericAdoTemplateTests.xml @@ -2,18 +2,18 @@ - + - - - - - - - - + + + + + + + + \ No newline at end of file diff --git a/test/Spring/Spring.Data.Integration.Tests/Data/Generic/ITestObjectDao.cs b/test/Spring/Spring.Data.Integration.Tests/Data/Generic/ITestObjectDao.cs index 6fa6a55d..9d0673b7 100644 --- a/test/Spring/Spring.Data.Integration.Tests/Data/Generic/ITestObjectDao.cs +++ b/test/Spring/Spring.Data.Integration.Tests/Data/Generic/ITestObjectDao.cs @@ -2,13 +2,13 @@ /* * Copyright � 2002-2011 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. @@ -20,10 +20,9 @@ using Spring.Objects; -namespace Spring.Data.Generic +namespace Spring.Data.Generic; + +public interface ITestObjectDao { - public interface ITestObjectDao - { - IList FindAll(); - } + IList FindAll(); } diff --git a/test/Spring/Spring.Data.Integration.Tests/Data/Generic/TestObjectDao.cs b/test/Spring/Spring.Data.Integration.Tests/Data/Generic/TestObjectDao.cs index ba81cd3e..2a0f5e5b 100644 --- a/test/Spring/Spring.Data.Integration.Tests/Data/Generic/TestObjectDao.cs +++ b/test/Spring/Spring.Data.Integration.Tests/Data/Generic/TestObjectDao.cs @@ -2,13 +2,13 @@ /* * Copyright � 2002-2011 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. @@ -21,29 +21,28 @@ using System.Data; using Spring.Objects; -namespace Spring.Data.Generic -{ - /// - /// This is - /// - /// - /// - /// - /// Mark Pollack - public class TestObjectDao : AdoDaoSupport, ITestObjectDao - { - public IList FindAll() - { - return AdoTemplate.QueryWithRowMapper(CommandType.Text, - "select TestObjectNo, Age, Name from TestObjects", - new TestObjectRowMapper()); - } +namespace Spring.Data.Generic; - public TestObject FindOne() - { - return AdoTemplate.QueryForObject(CommandType.Text, - "", - new TestObjectRowMapper()); - } +/// +/// This is +/// +/// +/// +/// +/// Mark Pollack +public class TestObjectDao : AdoDaoSupport, ITestObjectDao +{ + public IList FindAll() + { + return AdoTemplate.QueryWithRowMapper(CommandType.Text, + "select TestObjectNo, Age, Name from TestObjects", + new TestObjectRowMapper()); + } + + public TestObject FindOne() + { + return AdoTemplate.QueryForObject(CommandType.Text, + "", + new TestObjectRowMapper()); } } diff --git a/test/Spring/Spring.Data.Integration.Tests/Data/Generic/TestObjectRowMapper.cs b/test/Spring/Spring.Data.Integration.Tests/Data/Generic/TestObjectRowMapper.cs index 189c09fa..f44d15d8 100644 --- a/test/Spring/Spring.Data.Integration.Tests/Data/Generic/TestObjectRowMapper.cs +++ b/test/Spring/Spring.Data.Integration.Tests/Data/Generic/TestObjectRowMapper.cs @@ -1,14 +1,14 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. - * + * Copyright � 2002-2011 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. @@ -18,29 +18,27 @@ #endregion - using System.Data; using Spring.Objects; -namespace Spring.Data.Generic +namespace Spring.Data.Generic; + +/// +/// This is +/// +/// +/// +/// +/// Mark Pollack +public class TestObjectRowMapper : IRowMapper { - /// - /// This is - /// - /// - /// - /// - /// Mark Pollack - public class TestObjectRowMapper : IRowMapper + public TestObject MapRow(IDataReader reader, int rowNum) { - public TestObject MapRow(IDataReader reader, int rowNum) - { - if (reader == null) return new TestObject(); - TestObject to = new TestObject(); - to.ObjectNumber = reader.GetInt32(0); - to.Age = reader.GetInt32(1); - to.Name = reader.GetString(2); - return to; - } + if (reader == null) return new TestObject(); + TestObject to = new TestObject(); + to.ObjectNumber = reader.GetInt32(0); + to.Age = reader.GetInt32(1); + to.Name = reader.GetString(2); + return to; } } diff --git a/test/Spring/Spring.Data.Integration.Tests/Data/IAccountCreditDao.cs b/test/Spring/Spring.Data.Integration.Tests/Data/IAccountCreditDao.cs index 098cb67c..f9559d4f 100644 --- a/test/Spring/Spring.Data.Integration.Tests/Data/IAccountCreditDao.cs +++ b/test/Spring/Spring.Data.Integration.Tests/Data/IAccountCreditDao.cs @@ -1,9 +1,6 @@ +namespace Spring.Data; - -namespace Spring.Data +public interface IAccountCreditDao { - public interface IAccountCreditDao - { - void CreateCredit(float creditAmount); - } + void CreateCredit(float creditAmount); } diff --git a/test/Spring/Spring.Data.Integration.Tests/Data/IAccountDebitDao.cs b/test/Spring/Spring.Data.Integration.Tests/Data/IAccountDebitDao.cs index 1ae6cc46..9a05a397 100644 --- a/test/Spring/Spring.Data.Integration.Tests/Data/IAccountDebitDao.cs +++ b/test/Spring/Spring.Data.Integration.Tests/Data/IAccountDebitDao.cs @@ -1,8 +1,6 @@ +namespace Spring.Data; -namespace Spring.Data +public interface IAccountDebitDao { - public interface IAccountDebitDao - { - void DebitAccount(float debitAmount); - } + void DebitAccount(float debitAmount); } diff --git a/test/Spring/Spring.Data.Integration.Tests/Data/IAccountManager.cs b/test/Spring/Spring.Data.Integration.Tests/Data/IAccountManager.cs index 9fb9daec..7546102b 100644 --- a/test/Spring/Spring.Data.Integration.Tests/Data/IAccountManager.cs +++ b/test/Spring/Spring.Data.Integration.Tests/Data/IAccountManager.cs @@ -1,8 +1,6 @@ +namespace Spring.Data; -namespace Spring.Data +public interface IAccountManager { - public interface IAccountManager - { - void DoTransfer(float creditAmount, float debitAmount); - } -} + void DoTransfer(float creditAmount, float debitAmount); +} \ No newline at end of file diff --git a/test/Spring/Spring.Data.Integration.Tests/Data/ITestCoordinator.cs b/test/Spring/Spring.Data.Integration.Tests/Data/ITestCoordinator.cs index c2700fa4..fc21ee41 100644 --- a/test/Spring/Spring.Data.Integration.Tests/Data/ITestCoordinator.cs +++ b/test/Spring/Spring.Data.Integration.Tests/Data/ITestCoordinator.cs @@ -1,15 +1,14 @@ - using Spring.Objects; -namespace Spring.Data -{ - public interface ITestCoordinator - { - ITestObjectManager TestObjectManager - { - get; set; - } +namespace Spring.Data; - void WorkOn(TestObject to1, TestObject to2); +public interface ITestCoordinator +{ + ITestObjectManager TestObjectManager + { + get; + set; } + + void WorkOn(TestObject to1, TestObject to2); } diff --git a/test/Spring/Spring.Data.Integration.Tests/Data/ITestObjectDao.cs b/test/Spring/Spring.Data.Integration.Tests/Data/ITestObjectDao.cs index cc4b71e5..b973f569 100644 --- a/test/Spring/Spring.Data.Integration.Tests/Data/ITestObjectDao.cs +++ b/test/Spring/Spring.Data.Integration.Tests/Data/ITestObjectDao.cs @@ -1,24 +1,23 @@ using System.Collections; using Spring.Objects; -namespace Spring.Data -{ - public interface ITestObjectDao - { - void Create(string name, int age); - void Update(TestObject to); - void Delete(string name); - TestObject FindByName(string name); - IList FindAll(); - int GetCount(); - int GetCountByDelegate(); +namespace Spring.Data; - int GetCount(int lowerAgeLimit); - int GetCount(int lowerAgeLimit, string name); - - // - int GetCountByAltMethod(int lowerAgeLimit); - int GetCountByCommandSetter(int lowerAgeLimit); - void Cleanup(); - } -} \ No newline at end of file +public interface ITestObjectDao +{ + void Create(string name, int age); + void Update(TestObject to); + void Delete(string name); + TestObject FindByName(string name); + IList FindAll(); + int GetCount(); + int GetCountByDelegate(); + + int GetCount(int lowerAgeLimit); + int GetCount(int lowerAgeLimit, string name); + + // + int GetCountByAltMethod(int lowerAgeLimit); + int GetCountByCommandSetter(int lowerAgeLimit); + void Cleanup(); +} diff --git a/test/Spring/Spring.Data.Integration.Tests/Data/ITestObjectManager.cs b/test/Spring/Spring.Data.Integration.Tests/Data/ITestObjectManager.cs index 40a4f4eb..fbcc37d9 100644 --- a/test/Spring/Spring.Data.Integration.Tests/Data/ITestObjectManager.cs +++ b/test/Spring/Spring.Data.Integration.Tests/Data/ITestObjectManager.cs @@ -1,13 +1,12 @@ using Spring.Objects; -namespace Spring.Data +namespace Spring.Data; + +public interface ITestObjectManager { - public interface ITestObjectManager - { - void SaveTwoTestObjects(TestObject to1, TestObject to2); + void SaveTwoTestObjects(TestObject to1, TestObject to2); - void DeleteTwoTestObjects(string name1, string name2); + void DeleteTwoTestObjects(string name1, string name2); - void DeleteAllTestObjects(); - } -} \ No newline at end of file + void DeleteAllTestObjects(); +} diff --git a/test/Spring/Spring.Data.Integration.Tests/Data/MappingAdoQueryTests.cs b/test/Spring/Spring.Data.Integration.Tests/Data/MappingAdoQueryTests.cs index d1127450..6a363c92 100644 --- a/test/Spring/Spring.Data.Integration.Tests/Data/MappingAdoQueryTests.cs +++ b/test/Spring/Spring.Data.Integration.Tests/Data/MappingAdoQueryTests.cs @@ -2,13 +2,13 @@ /* * Copyright � 2002-2011 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. @@ -29,87 +29,83 @@ using Spring.Objects; #endregion -namespace Spring.Data +namespace Spring.Data; + +/// +/// Test a MappingAdoQuery implementation +/// +/// Mark Pollack (.NET) +[TestFixture] +public class MappingAdoQueryTests { + #region Fields + + IDbProvider dbProvider; + + #endregion + + #region Constants + + private IApplicationContext ctx; + + #endregion + + #region Constructor (s) + /// - /// Test a MappingAdoQuery implementation + /// Initializes a new instance of the class. /// - /// Mark Pollack (.NET) - [TestFixture] - public class MappingAdoQueryTests + public MappingAdoQueryTests() { - #region Fields - IDbProvider dbProvider; - #endregion - - #region Constants - - private IApplicationContext ctx; - - #endregion - - #region Constructor (s) - /// - /// Initializes a new instance of the class. - /// - public MappingAdoQueryTests() - { - - } - - #endregion - - #region Properties - - #endregion - - #region Methods - [SetUp] - public void CreateDbProvider() - { - ctx = new XmlApplicationContext("assembly://Spring.Data.Integration.Tests/Spring.Data/adoTemplateTests.xml"); - Assert.IsNotNull(ctx); - dbProvider = ctx["DbProvider"] as IDbProvider; - Assert.IsNotNull(dbProvider); - - DeleteTestData(); - PopulateTestData(); - } - - private void PopulateTestData() - { - ITestObjectManager testObjectManager = ctx["testObjectManager"] as ITestObjectManager; - testObjectManager.SaveTwoTestObjects(new TestObject("Jack", 10), new TestObject("Jill", 20)); - } - - [TearDown] - public void _TestTearDown() - { - DeleteTestData(); - } - - private void DeleteTestData() - { - ITestObjectManager testObjectManager = ctx["testObjectManager"] as ITestObjectManager; - testObjectManager.DeleteAllTestObjects(); - } - - - [Test] - public void MappingAdoQuery() - { - TestObjectQuery testObjectQuery = new TestObjectQuery(dbProvider); - IDictionary inParams = new Hashtable(); - inParams.Add("@Name", "Jack"); - IList testObjectList = testObjectQuery.QueryByNamedParam(inParams); - Assert.AreEqual(1, testObjectList.Count); - } - - - - #endregion - - - } + + #endregion + + #region Properties + + #endregion + + #region Methods + + [SetUp] + public void CreateDbProvider() + { + ctx = new XmlApplicationContext("assembly://Spring.Data.Integration.Tests/Spring.Data/adoTemplateTests.xml"); + Assert.IsNotNull(ctx); + dbProvider = ctx["DbProvider"] as IDbProvider; + Assert.IsNotNull(dbProvider); + + DeleteTestData(); + PopulateTestData(); + } + + private void PopulateTestData() + { + ITestObjectManager testObjectManager = ctx["testObjectManager"] as ITestObjectManager; + testObjectManager.SaveTwoTestObjects(new TestObject("Jack", 10), new TestObject("Jill", 20)); + } + + [TearDown] + public void _TestTearDown() + { + DeleteTestData(); + } + + private void DeleteTestData() + { + ITestObjectManager testObjectManager = ctx["testObjectManager"] as ITestObjectManager; + testObjectManager.DeleteAllTestObjects(); + } + + [Test] + public void MappingAdoQuery() + { + TestObjectQuery testObjectQuery = new TestObjectQuery(dbProvider); + IDictionary inParams = new Hashtable(); + inParams.Add("@Name", "Jack"); + IList testObjectList = testObjectQuery.QueryByNamedParam(inParams); + Assert.AreEqual(1, testObjectList.Count); + } + + #endregion } diff --git a/test/Spring/Spring.Data.Integration.Tests/Data/NativeAdoTestObjectDao.cs b/test/Spring/Spring.Data.Integration.Tests/Data/NativeAdoTestObjectDao.cs index 95733b2e..f9125858 100644 --- a/test/Spring/Spring.Data.Integration.Tests/Data/NativeAdoTestObjectDao.cs +++ b/test/Spring/Spring.Data.Integration.Tests/Data/NativeAdoTestObjectDao.cs @@ -8,202 +8,202 @@ using Spring.Objects; #endregion -namespace Spring.Data +namespace Spring.Data; + +public class NativeAdoTestObjectDao : ITestObjectDao { - public class NativeAdoTestObjectDao : ITestObjectDao + private String connectionString; + + public string ConnectionString { - private String connectionString; + get { return connectionString; } + set { connectionString = value; } + } - public string ConnectionString + public IList ExplicitTx() + { + try { - get { return connectionString; } - set { connectionString = value; } - } - - - public IList ExplicitTx() - { - try + using (SqlConnection connection = new SqlConnection(connectionString)) { - using (SqlConnection connection = new SqlConnection(connectionString)) + connection.Open(); + + using (SqlTransaction transaction = connection.BeginTransaction()) { - connection.Open(); - - using (SqlTransaction transaction = connection.BeginTransaction()) + using (SqlCommand command = new SqlCommand("sql")) { - using (SqlCommand command = new SqlCommand("sql")) - { - command.Connection = connection; - command.Transaction = transaction; + command.Connection = connection; + command.Transaction = transaction; - /* - * dbParameters.Add("savings", DbType.Decimal).Value = b.Savings.AsDecimal(); - dbParameters.Add("accountId", DbType.Int).Value = account.EntityId; - dbParameters.Add("name", DbType.String).Value = b.Name; - */ - command.Parameters.Add("@savings", SqlDbType.Decimal).Value = 1;// = b.Savings.AsDecimal(); - command.Parameters.Add("@accountId", SqlDbType.Int).Value = 2; - command.Parameters.Add("@name", SqlDbType.NVarChar, 40).Value = 3; - command.ExecuteNonQuery(); - //foreach (Benificiary b in Account.Beneficiaries) - //{ - - //} + /* + * dbParameters.Add("savings", DbType.Decimal).Value = b.Savings.AsDecimal(); +dbParameters.Add("accountId", DbType.Int).Value = account.EntityId; +dbParameters.Add("name", DbType.String).Value = b.Name; + */ + command.Parameters.Add("@savings", SqlDbType.Decimal).Value = 1; // = b.Savings.AsDecimal(); + command.Parameters.Add("@accountId", SqlDbType.Int).Value = 2; + command.Parameters.Add("@name", SqlDbType.NVarChar, 40).Value = 3; + command.ExecuteNonQuery(); + //foreach (Benificiary b in Account.Beneficiaries) + //{ - transaction.Commit(); - } + //} + + transaction.Commit(); } } - } catch (Exception) - { - //log exception and rethrow } - return null; + } + catch (Exception) + { + //log exception and rethrow } - public IList FindAllPeople() - { - IList results = new ArrayList(); - try - { - using (SqlConnection connection = new SqlConnection(connectionString)) - { - string sql = "select Name, Age from ..."; + return null; + } - using (SqlCommand command = new SqlCommand(sql, connection)) + public IList FindAllPeople() + { + IList results = new ArrayList(); + try + { + using (SqlConnection connection = new SqlConnection(connectionString)) + { + string sql = "select Name, Age from ..."; + + using (SqlCommand command = new SqlCommand(sql, connection)) + { + connection.Open(); + using (SqlDataReader reader = command.ExecuteReader()) { - connection.Open(); - using (SqlDataReader reader = command.ExecuteReader()) + while (reader.Read()) { - while (reader.Read()) - { - //process the result set - populate Person object, add to array - } + //process the result set - populate Person object, add to array } } } } - catch (Exception) - { - //throw application exception - } - return results; + } + catch (Exception) + { + //throw application exception } - public void Create2(string name, int age) + return results; + } + + public void Create2(string name, int age) + { + using (SqlConnection connection = new SqlConnection(connectionString)) { - using (SqlConnection connection = new SqlConnection(connectionString)) - { - String sql = - String.Format("insert into TestObjects(Age, Name) " + - "VALUES ({0}, '{1}')", - age, name); - - using (SqlCommand cmd = new SqlCommand(sql, connection)) - { - connection.Open(); - cmd.ExecuteNonQuery(); - } - } - } - - public void Create(string name, int age) - { - using (SqlConnection connection = new SqlConnection(connectionString)) - { - SqlParameter p1 = new SqlParameter("name", SqlDbType.NVarChar); - p1.Value = "asdf"; - - /* - string strSql = "insert into TestObjects(Age,Name) values (@Age,@Name)"; - - - SqlCommand comm = connection.CreateCommand(); - comm.CommandText = strSql; - SqlParameter p1 = new SqlParameter(); - p1.ParameterName = "@Age"; - p1.Value = age; - - SqlParameter p2 = new SqlParameter(); - p2.ParameterName = "@Name"; - p2.Value = name; - - comm.Parameters.Add(p1); - comm.Parameters.Add(p2); - - */ - - StringBuilder sb = new StringBuilder(); - sb.AppendFormat( - "insert into TestObjects(Age, Name) VALUES ({0}, '{1}')", + String sql = + String.Format("insert into TestObjects(Age, Name) " + + "VALUES ({0}, '{1}')", age, name); - SqlCommand comm = connection.CreateCommand(); - comm.CommandText = sb.ToString(); - - + using (SqlCommand cmd = new SqlCommand(sql, connection)) + { connection.Open(); - comm.ExecuteNonQuery(); + cmd.ExecuteNonQuery(); } } + } - public void Update(TestObject to) + public void Create(string name, int age) + { + using (SqlConnection connection = new SqlConnection(connectionString)) { - // TODO: Add NativeAdoTestObjectDao.Update implementation - } + SqlParameter p1 = new SqlParameter("name", SqlDbType.NVarChar); + p1.Value = "asdf"; - public void Delete(string name) - { - // TODO: Add NativeAdoTestObjectDao.Delete implementation - } + /* + string strSql = "insert into TestObjects(Age,Name) values (@Age,@Name)"; - public TestObject FindByName(string name) - { - // TODO: Add NativeAdoTestObjectDao.FindByName implementation - return null; - } - public System.Collections.IList FindAll() - { - // TODO: Add NativeAdoTestObjectDao.FindAll implementation - return null; - } + SqlCommand comm = connection.CreateCommand(); + comm.CommandText = strSql; + SqlParameter p1 = new SqlParameter(); + p1.ParameterName = "@Age"; + p1.Value = age; - public int GetCount() - { - // TODO: Add NativeAdoTestObjectDao.GetCount implementation - return 0; - } + SqlParameter p2 = new SqlParameter(); + p2.ParameterName = "@Name"; + p2.Value = name; - public int GetCountByDelegate() - { - // TODO: Add NativeAdoTestObjectDao.GetCountByDelegate implementation - return 0; - } + comm.Parameters.Add(p1); + comm.Parameters.Add(p2); - public int GetCount(int lowerAgeLimit) - { - throw new NotImplementedException(); - } + */ - public int GetCount(int lowerAgeLimit, string name) - { - throw new NotImplementedException(); - } + StringBuilder sb = new StringBuilder(); + sb.AppendFormat( + "insert into TestObjects(Age, Name) VALUES ({0}, '{1}')", + age, name); - public int GetCountByAltMethod(int lowerAgeLimit) - { - throw new NotImplementedException(); - } + SqlCommand comm = connection.CreateCommand(); + comm.CommandText = sb.ToString(); - public int GetCountByCommandSetter(int lowerAgeLimit) - { - throw new NotImplementedException(); - } - - public void Cleanup() - { - throw new NotImplementedException(); + connection.Open(); + comm.ExecuteNonQuery(); } } -} + + public void Update(TestObject to) + { + // TODO: Add NativeAdoTestObjectDao.Update implementation + } + + public void Delete(string name) + { + // TODO: Add NativeAdoTestObjectDao.Delete implementation + } + + public TestObject FindByName(string name) + { + // TODO: Add NativeAdoTestObjectDao.FindByName implementation + return null; + } + + public System.Collections.IList FindAll() + { + // TODO: Add NativeAdoTestObjectDao.FindAll implementation + return null; + } + + public int GetCount() + { + // TODO: Add NativeAdoTestObjectDao.GetCount implementation + return 0; + } + + public int GetCountByDelegate() + { + // TODO: Add NativeAdoTestObjectDao.GetCountByDelegate implementation + return 0; + } + + public int GetCount(int lowerAgeLimit) + { + throw new NotImplementedException(); + } + + public int GetCount(int lowerAgeLimit, string name) + { + throw new NotImplementedException(); + } + + public int GetCountByAltMethod(int lowerAgeLimit) + { + throw new NotImplementedException(); + } + + public int GetCountByCommandSetter(int lowerAgeLimit) + { + throw new NotImplementedException(); + } + + public void Cleanup() + { + throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/test/Spring/Spring.Data.Integration.Tests/Data/NativeAdoTests.cs b/test/Spring/Spring.Data.Integration.Tests/Data/NativeAdoTests.cs index 1fbc9210..135004a2 100644 --- a/test/Spring/Spring.Data.Integration.Tests/Data/NativeAdoTests.cs +++ b/test/Spring/Spring.Data.Integration.Tests/Data/NativeAdoTests.cs @@ -1,14 +1,14 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. - * + * Copyright � 2002-2011 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. @@ -28,34 +28,33 @@ using Spring.Context.Support; #endregion -namespace Spring.Data +namespace Spring.Data; + +[TestFixture] +public class NativeAdoTests { - [TestFixture] - public class NativeAdoTests + [Test] + public void SimpleUsage() { - [Test] - public void SimpleUsage() - { - IApplicationContext ctx = - new XmlApplicationContext("assembly://Spring.Data.Integration.Tests/Spring.Data/nativeAdoTests.xml"); - Assert.IsNotNull(ctx); - ITestObjectDao dao = (ITestObjectDao)ctx["testObjectDao"]; - Assert.IsNotNull(dao); - dao.Create("John", 45); - } + IApplicationContext ctx = + new XmlApplicationContext("assembly://Spring.Data.Integration.Tests/Spring.Data/nativeAdoTests.xml"); + Assert.IsNotNull(ctx); + ITestObjectDao dao = (ITestObjectDao) ctx["testObjectDao"]; + Assert.IsNotNull(dao); + dao.Create("John", 45); + } - [Test] - public void Helloworld() - { - string connString = - @"Data Source=SPRINGQA;Initial Catalog=Spring;User ID=springqa;Password=springqa;Trusted_Connection=False"; + [Test] + public void Helloworld() + { + string connString = + @"Data Source=SPRINGQA;Initial Catalog=Spring;User ID=springqa;Password=springqa;Trusted_Connection=False"; - SqlConnection conn = new SqlConnection(connString); - conn.Open(); - //conn.BeginTransaction(IsolationLevel.Unspecified); - SqlTransaction trans = conn.BeginTransaction(); + SqlConnection conn = new SqlConnection(connString); + conn.Open(); + //conn.BeginTransaction(IsolationLevel.Unspecified); + SqlTransaction trans = conn.BeginTransaction(); - Assert.That(trans.IsolationLevel, Is.EqualTo(IsolationLevel.ReadCommitted)); - } + Assert.That(trans.IsolationLevel, Is.EqualTo(IsolationLevel.ReadCommitted)); } } diff --git a/test/Spring/Spring.Data.Integration.Tests/Data/NestedTxScopeTests.cs b/test/Spring/Spring.Data.Integration.Tests/Data/NestedTxScopeTests.cs index 10a7df6e..cbf53d09 100644 --- a/test/Spring/Spring.Data.Integration.Tests/Data/NestedTxScopeTests.cs +++ b/test/Spring/Spring.Data.Integration.Tests/Data/NestedTxScopeTests.cs @@ -31,140 +31,141 @@ using Spring.Transaction.Support; #endregion -namespace Spring.Data +namespace Spring.Data; + +/// +/// This class contains tests for nesting transaction scopes. +/// +/// Mark Pollack +[TestFixture] +public class NestedTxScopeTests { - /// - /// This class contains tests for nesting transaction scopes. - /// - /// Mark Pollack - [TestFixture] - public class NestedTxScopeTests + [Test] + public void TxTemplate() { - + IDbProvider dbProvider = DbProviderFactory.GetDbProvider("System.Data.SqlClient"); + dbProvider.ConnectionString = @"Data Source=SPRINGQA;Initial Catalog=CreditsAndDebits;User ID=springqa; Password=springqa"; + //IPlatformTransactionManager tm = new ServiceDomainPlatformTransactionManager(); + //IPlatformTransactionManager tm = new TxScopeTransactionManager(); + IPlatformTransactionManager tm = new AdoPlatformTransactionManager(dbProvider); + AdoTemplate adoTemplate = new AdoTemplate(dbProvider); - - [Test] - public void TxTemplate() + TransactionTemplate tt = new TransactionTemplate(tm); + tt.PropagationBehavior = TransactionPropagation.Required; + tt.Execute(status => { - IDbProvider dbProvider = DbProviderFactory.GetDbProvider("System.Data.SqlClient"); - dbProvider.ConnectionString = @"Data Source=SPRINGQA;Initial Catalog=CreditsAndDebits;User ID=springqa; Password=springqa"; - //IPlatformTransactionManager tm = new ServiceDomainPlatformTransactionManager(); - //IPlatformTransactionManager tm = new TxScopeTransactionManager(); - IPlatformTransactionManager tm = new AdoPlatformTransactionManager(dbProvider); - AdoTemplate adoTemplate = new AdoTemplate(dbProvider); + if (System.Transactions.Transaction.Current != null) Console.WriteLine("tx 1 id = " + System.Transactions.Transaction.Current.TransactionInformation.LocalIdentifier); + Console.WriteLine("tx 1 'IsNewTransaction' = " + status.IsNewTransaction); + adoTemplate.ExecuteNonQuery(CommandType.Text, "insert into Credits (CreditAmount) VALUES (@amount)", "amount", DbType.Decimal, 0, 444); + TransactionTemplate tt2 = new TransactionTemplate(tm); + tt2.PropagationBehavior = TransactionPropagation.RequiresNew; - TransactionTemplate tt = new TransactionTemplate(tm); - tt.PropagationBehavior = TransactionPropagation.Required; - tt.Execute(status => - { - if (System.Transactions.Transaction.Current != null) Console.WriteLine("tx 1 id = " + System.Transactions.Transaction.Current.TransactionInformation.LocalIdentifier); - Console.WriteLine("tx 1 'IsNewTransaction' = " + status.IsNewTransaction); - adoTemplate.ExecuteNonQuery(CommandType.Text, "insert into Credits (CreditAmount) VALUES (@amount)", "amount", DbType.Decimal, 0,444); - TransactionTemplate tt2 = new TransactionTemplate(tm); - tt2.PropagationBehavior = TransactionPropagation.RequiresNew; - - tt2.Execute(status2 => - { - if (System.Transactions.Transaction.Current != null) Console.WriteLine("tx 2 = " + System.Transactions.Transaction.Current.TransactionInformation.LocalIdentifier); - Console.WriteLine("tx 2 'IsNewTransaction' = " + status2.IsNewTransaction); - adoTemplate.ExecuteNonQuery(CommandType.Text, "insert into dbo.Debits (DebitAmount) VALUES (@amount)", "amount", DbType.Decimal, 0,555); - //throw new ArithmeticException("can't do the math."); - status2.SetRollbackOnly(); - return null; - }); - - if (System.Transactions.Transaction.Current != null) Console.WriteLine("tx id1 = " + System.Transactions.Transaction.Current.TransactionInformation.LocalIdentifier); - return null; - }); - } - - [Test] - public void TxScope() - { - Method1(); - } - private void Method1() - { - string updateSql1 = "insert into Credits (CreditAmount) VALUES (333)"; - using (TransactionScope ts = - new TransactionScope(TransactionScopeOption.Required)) + tt2.Execute(status2 => { - Console.WriteLine("tx id1 = " + - System.Transactions.Transaction.Current.TransactionInformation.LocalIdentifier); - using (SqlConnection cn2005 = new SqlConnection()) - { - cn2005.ConnectionString = - @"Data Source=SPRINGQA;Initial Catalog=CreditsAndDebits;User ID=springqa; Password=springqa"; - SqlCommand cmd = new SqlCommand(updateSql1, cn2005); - cn2005.Open(); - cmd.ExecuteNonQuery(); - } - Method2(); - Console.WriteLine("tx id1 = " + - System.Transactions.Transaction.Current.TransactionInformation.LocalIdentifier); - ts.Complete(); - } - } + if (System.Transactions.Transaction.Current != null) Console.WriteLine("tx 2 = " + System.Transactions.Transaction.Current.TransactionInformation.LocalIdentifier); + Console.WriteLine("tx 2 'IsNewTransaction' = " + status2.IsNewTransaction); + adoTemplate.ExecuteNonQuery(CommandType.Text, "insert into dbo.Debits (DebitAmount) VALUES (@amount)", "amount", DbType.Decimal, 0, 555); + //throw new ArithmeticException("can't do the math."); + status2.SetRollbackOnly(); + return null; + }); - private void Method2() + if (System.Transactions.Transaction.Current != null) Console.WriteLine("tx id1 = " + System.Transactions.Transaction.Current.TransactionInformation.LocalIdentifier); + return null; + }); + } + + [Test] + public void TxScope() + { + Method1(); + } + + private void Method1() + { + string updateSql1 = "insert into Credits (CreditAmount) VALUES (333)"; + using (TransactionScope ts = + new TransactionScope(TransactionScopeOption.Required)) { - bool rollback = true; - string updateSql2 = "insert into Debits (DebitAmount) VALUES (222)"; - using (TransactionScope ts = - new TransactionScope(TransactionScopeOption.RequiresNew)) + Console.WriteLine("tx id1 = " + + System.Transactions.Transaction.Current.TransactionInformation.LocalIdentifier); + using (SqlConnection cn2005 = new SqlConnection()) { - Console.WriteLine("tx id2 = " + - System.Transactions.Transaction.Current.TransactionInformation.LocalIdentifier); - using (SqlConnection cn2005 = new SqlConnection()) - { - cn2005.ConnectionString = @"Data Source=SPRINGQA;Initial Catalog=CreditsAndDebits;User ID=springqa; Password=springqa"; - SqlCommand cmd = new SqlCommand(updateSql2, cn2005); - cn2005.Open(); - cmd.ExecuteNonQuery(); - } - if (rollback) - { - System.Transactions.Transaction.Current.Rollback(); - } - else - { - ts.Complete(); - } - Console.WriteLine("end of 2nd data access operation"); - + cn2005.ConnectionString = + @"Data Source=SPRINGQA;Initial Catalog=CreditsAndDebits;User ID=springqa; Password=springqa"; + SqlCommand cmd = new SqlCommand(updateSql1, cn2005); + cn2005.Open(); + cmd.ExecuteNonQuery(); } + + Method2(); + Console.WriteLine("tx id1 = " + + System.Transactions.Transaction.Current.TransactionInformation.LocalIdentifier); + ts.Complete(); } + } - [Test] - public void UnwantedPromotion() + private void Method2() + { + bool rollback = true; + string updateSql2 = "insert into Debits (DebitAmount) VALUES (222)"; + using (TransactionScope ts = + new TransactionScope(TransactionScopeOption.RequiresNew)) { - using (TransactionScope ts = new TransactionScope()) - { - InnerMethod(); - InnerMethod(); - ts.Complete(); - } - } - - private void InnerMethod() - { - string updateSql2 = "insert into Debits (DebitAmount) VALUES (222)"; - + Console.WriteLine("tx id2 = " + + System.Transactions.Transaction.Current.TransactionInformation.LocalIdentifier); using (SqlConnection cn2005 = new SqlConnection()) { cn2005.ConnectionString = @"Data Source=SPRINGQA;Initial Catalog=CreditsAndDebits;User ID=springqa; Password=springqa"; SqlCommand cmd = new SqlCommand(updateSql2, cn2005); cn2005.Open(); cmd.ExecuteNonQuery(); - - #region logging - Console.WriteLine("TransactionSynchronizationManager.CurrentTransactionIsolationLevel = " + - TransactionSynchronizationManager.CurrentTransactionIsolationLevel); - Console.WriteLine("System.Transactions.Transaction.Current.IsolationLevel = " + System.Transactions.Transaction.Current.IsolationLevel); - string name = TransactionSynchronizationManager.CurrentTransactionName; - bool read = TransactionSynchronizationManager.CurrentTransactionReadOnly; - #endregion } + + if (rollback) + { + System.Transactions.Transaction.Current.Rollback(); + } + else + { + ts.Complete(); + } + + Console.WriteLine("end of 2nd data access operation"); + } + } + + [Test] + public void UnwantedPromotion() + { + using (TransactionScope ts = new TransactionScope()) + { + InnerMethod(); + InnerMethod(); + ts.Complete(); + } + } + + private void InnerMethod() + { + string updateSql2 = "insert into Debits (DebitAmount) VALUES (222)"; + + using (SqlConnection cn2005 = new SqlConnection()) + { + cn2005.ConnectionString = @"Data Source=SPRINGQA;Initial Catalog=CreditsAndDebits;User ID=springqa; Password=springqa"; + SqlCommand cmd = new SqlCommand(updateSql2, cn2005); + cn2005.Open(); + cmd.ExecuteNonQuery(); + + #region logging + + Console.WriteLine("TransactionSynchronizationManager.CurrentTransactionIsolationLevel = " + + TransactionSynchronizationManager.CurrentTransactionIsolationLevel); + Console.WriteLine("System.Transactions.Transaction.Current.IsolationLevel = " + System.Transactions.Transaction.Current.IsolationLevel); + string name = TransactionSynchronizationManager.CurrentTransactionName; + bool read = TransactionSynchronizationManager.CurrentTransactionReadOnly; + + #endregion } } } diff --git a/test/Spring/Spring.Data.Integration.Tests/Data/Northwind/AdoTemplateShipperDao.cs b/test/Spring/Spring.Data.Integration.Tests/Data/Northwind/AdoTemplateShipperDao.cs index 7fba824b..c4181a8a 100644 --- a/test/Spring/Spring.Data.Integration.Tests/Data/Northwind/AdoTemplateShipperDao.cs +++ b/test/Spring/Spring.Data.Integration.Tests/Data/Northwind/AdoTemplateShipperDao.cs @@ -2,13 +2,13 @@ /* * Copyright � 2002-2011 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. @@ -26,35 +26,34 @@ using Spring.Data.Core; #endregion -namespace Spring.Data.Northwind +namespace Spring.Data.Northwind; + +/// +/// AdoTemplate based implementation of IShipperDao +/// +/// Mark Pollack (.NET) +public class AdoTemplateShipperDao : AdoDaoSupport, IShipperDao { - /// - /// AdoTemplate based implementation of IShipperDao - /// - /// Mark Pollack (.NET) - public class AdoTemplateShipperDao : AdoDaoSupport, IShipperDao + #region IShipperDao Members + + public Shipper Create(string name, string phone) { - #region IShipperDao Members + string sql = "INSERT INTO Shippers (CompanyName, Phone) VALUES (@CompanyName, @Phone) SET @ShipperID = SCOPE_IDENTITY()"; + IDbParameters dbParameters = AdoTemplate.CreateDbParameters(); + dbParameters.Add("CompanyName", SqlDbType.NVarChar, 40).Value = name; - public Shipper Create(string name, string phone) - { - string sql = "INSERT INTO Shippers (CompanyName, Phone) VALUES (@CompanyName, @Phone) SET @ShipperID = SCOPE_IDENTITY()"; - IDbParameters dbParameters = AdoTemplate.CreateDbParameters(); - dbParameters.Add("CompanyName", SqlDbType.NVarChar, 40).Value = name; - - //Can we add automatic nullable support? - if (phone.Length == 0) - dbParameters.Add("Phone", SqlDbType.NVarChar, 24).Value = DBNull.Value; - else - dbParameters.Add("Phone", SqlDbType.NVarChar, 24).Value = phone; - - dbParameters.AddOut("ShipperID", SqlDbType.Int); - - int id = AdoTemplate.ExecuteNonQuery(CommandType.Text, sql, dbParameters); - - return new Shipper(id, name, phone); //10 - } + //Can we add automatic nullable support? + if (phone.Length == 0) + dbParameters.Add("Phone", SqlDbType.NVarChar, 24).Value = DBNull.Value; + else + dbParameters.Add("Phone", SqlDbType.NVarChar, 24).Value = phone; - #endregion + dbParameters.AddOut("ShipperID", SqlDbType.Int); + + int id = AdoTemplate.ExecuteNonQuery(CommandType.Text, sql, dbParameters); + + return new Shipper(id, name, phone); //10 } + + #endregion } diff --git a/test/Spring/Spring.Data.Integration.Tests/Data/Northwind/IShipperDao.cs b/test/Spring/Spring.Data.Integration.Tests/Data/Northwind/IShipperDao.cs index 27bb87b9..43375e2c 100644 --- a/test/Spring/Spring.Data.Integration.Tests/Data/Northwind/IShipperDao.cs +++ b/test/Spring/Spring.Data.Integration.Tests/Data/Northwind/IShipperDao.cs @@ -1,14 +1,14 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. - * + * Copyright � 2002-2011 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. @@ -20,18 +20,15 @@ #region Imports - - #endregion -namespace Spring.Data.Northwind +namespace Spring.Data.Northwind; + +/// +/// ShipperDao interface +/// +/// Mark Pollack (.NET) +public interface IShipperDao { - /// - /// ShipperDao interface - /// - /// Mark Pollack (.NET) - public interface IShipperDao - { - Shipper Create(string name, string phone); - } + Shipper Create(string name, string phone); } diff --git a/test/Spring/Spring.Data.Integration.Tests/Data/Northwind/NativeAdoShipperDao.cs b/test/Spring/Spring.Data.Integration.Tests/Data/Northwind/NativeAdoShipperDao.cs index 4d532c2b..7f251ef6 100644 --- a/test/Spring/Spring.Data.Integration.Tests/Data/Northwind/NativeAdoShipperDao.cs +++ b/test/Spring/Spring.Data.Integration.Tests/Data/Northwind/NativeAdoShipperDao.cs @@ -2,13 +2,13 @@ /* * Copyright � 2002-2011 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. @@ -25,68 +25,68 @@ using System.Data.SqlClient; #endregion -namespace Spring.Data.Northwind +namespace Spring.Data.Northwind; + +/// Mark Pollack (.NET) +public class NativeAdoShipperDao : IShipperDao { - /// Mark Pollack (.NET) - public class NativeAdoShipperDao : IShipperDao + #region IShipperDao Members + + public Shipper Create(string name, string phone) { - #region IShipperDao Members - - public Shipper Create(string name, string phone) + string connectionString = "Data Source=SPRINGQA;Initial Catalog=Northwind;Persist Security Info=True;User ID=springqa;Password=springqa"; + int id = 0; + using (SqlConnection connection = new SqlConnection(connectionString)) { - string connectionString = "Data Source=SPRINGQA;Initial Catalog=Northwind;Persist Security Info=True;User ID=springqa;Password=springqa"; - int id = 0; - using (SqlConnection connection = new SqlConnection(connectionString)) + using (SqlCommand insertCommand = connection.CreateCommand()) { - using (SqlCommand insertCommand = connection.CreateCommand()) - { - insertCommand.CommandText = - "INSERT INTO Shippers (CompanyName, Phone) VALUES (@CompanyName, @Phone) SET @ShipperID = SCOPE_IDENTITY()"; - SqlParameter companyNameParameter = new SqlParameter("@CompanyName", SqlDbType.NVarChar, 40); - companyNameParameter.Value = name; - insertCommand.Parameters.Add(companyNameParameter); - SqlParameter phoneParameter = new SqlParameter("@Phone", SqlDbType.NVarChar, 24); - if (phone.Length == 0) - phoneParameter.Value = DBNull.Value; - else - phoneParameter.Value = phone; - insertCommand.Parameters.Add(phoneParameter); - SqlParameter shipperIDParameter = new SqlParameter("@ShipperID", SqlDbType.Int); - shipperIDParameter.Direction = ParameterDirection.Output; - insertCommand.Parameters.Add(shipperIDParameter); - insertCommand.Connection.Open(); - insertCommand.ExecuteNonQuery(); - id = (int) shipperIDParameter.Value; - } + insertCommand.CommandText = + "INSERT INTO Shippers (CompanyName, Phone) VALUES (@CompanyName, @Phone) SET @ShipperID = SCOPE_IDENTITY()"; + SqlParameter companyNameParameter = new SqlParameter("@CompanyName", SqlDbType.NVarChar, 40); + companyNameParameter.Value = name; + insertCommand.Parameters.Add(companyNameParameter); + SqlParameter phoneParameter = new SqlParameter("@Phone", SqlDbType.NVarChar, 24); + if (phone.Length == 0) + phoneParameter.Value = DBNull.Value; + else + phoneParameter.Value = phone; + insertCommand.Parameters.Add(phoneParameter); + SqlParameter shipperIDParameter = new SqlParameter("@ShipperID", SqlDbType.Int); + shipperIDParameter.Direction = ParameterDirection.Output; + insertCommand.Parameters.Add(shipperIDParameter); + insertCommand.Connection.Open(); + insertCommand.ExecuteNonQuery(); + id = (int) shipperIDParameter.Value; } - return new Shipper(id, name, phone); //24 } - - public Shipper CreateShorter(string name, string phone) - { - string connectionString = "Data Source=SPRINGQA;Initial Catalog=Northwind;Persist Security Info=True;User ID=springqa"; - int id = 0; - using (SqlConnection connection = new SqlConnection(connectionString)) - { - using (SqlCommand insertCommand = connection.CreateCommand()) - { - insertCommand.CommandText = - "INSERT INTO Shippers (CompanyName, Phone) VALUES (@CompanyName, @Phone) SET @ShipperID = SCOPE_IDENTITY()"; - insertCommand.Parameters.Add("@CompanyName", SqlDbType.NVarChar, 40).Value = name; - if (phone.Length == 0) - insertCommand.Parameters.Add("Phone", SqlDbType.NVarChar, 24).Value = DBNull.Value; - else - insertCommand.Parameters.Add("Phone", SqlDbType.NVarChar, 24).Value = phone; - insertCommand.Parameters.Add("@ShipperID", SqlDbType.Int).Direction = ParameterDirection.Output; - insertCommand.Connection.Open(); - insertCommand.ExecuteNonQuery(); - id = (int) insertCommand.Parameters["@ShipperID"].Value; - } - } - return new Shipper(id, name, phone); //17 - } - - #endregion + return new Shipper(id, name, phone); //24 } + + public Shipper CreateShorter(string name, string phone) + { + string connectionString = "Data Source=SPRINGQA;Initial Catalog=Northwind;Persist Security Info=True;User ID=springqa"; + int id = 0; + using (SqlConnection connection = new SqlConnection(connectionString)) + { + using (SqlCommand insertCommand = connection.CreateCommand()) + { + insertCommand.CommandText = + "INSERT INTO Shippers (CompanyName, Phone) VALUES (@CompanyName, @Phone) SET @ShipperID = SCOPE_IDENTITY()"; + insertCommand.Parameters.Add("@CompanyName", SqlDbType.NVarChar, 40).Value = name; + if (phone.Length == 0) + insertCommand.Parameters.Add("Phone", SqlDbType.NVarChar, 24).Value = DBNull.Value; + else + insertCommand.Parameters.Add("Phone", SqlDbType.NVarChar, 24).Value = phone; + insertCommand.Parameters.Add("@ShipperID", SqlDbType.Int).Direction = ParameterDirection.Output; + insertCommand.Connection.Open(); + insertCommand.ExecuteNonQuery(); + id = (int) insertCommand.Parameters["@ShipperID"].Value; + } + } + + return new Shipper(id, name, phone); //17 + } + + #endregion } diff --git a/test/Spring/Spring.Data.Integration.Tests/Data/Northwind/Shipper.cs b/test/Spring/Spring.Data.Integration.Tests/Data/Northwind/Shipper.cs index db7f2e24..43ea3e84 100644 --- a/test/Spring/Spring.Data.Integration.Tests/Data/Northwind/Shipper.cs +++ b/test/Spring/Spring.Data.Integration.Tests/Data/Northwind/Shipper.cs @@ -1,14 +1,14 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. - * + * Copyright � 2002-2011 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. @@ -20,65 +20,62 @@ #region Imports - - #endregion -namespace Spring.Data.Northwind +namespace Spring.Data.Northwind; + +/// Mark Pollack (.NET) +public class Shipper { - /// Mark Pollack (.NET) - public class Shipper - { - #region Fields + #region Fields - public int Id - { - get { return id; } - set { id = value; } - } + public int Id + { + get { return id; } + set { id = value; } + } - public string Name - { - get { return name; } - set { name = value; } - } + public string Name + { + get { return name; } + set { name = value; } + } - public string Phone - { - get { return phone; } - set { phone = value; } - } + public string Phone + { + get { return phone; } + set { phone = value; } + } - private int id; - private string name; - private string phone; - #endregion + private int id; + private string name; + private string phone; - #region Constructor (s) - /// - /// Initializes a new instance of the class. - /// - public Shipper() - { + #endregion - } + #region Constructor (s) - public Shipper(int id, string name, string phone) - { - this.id = id; - this.name = name; - this.phone = phone; - } + /// + /// Initializes a new instance of the class. + /// + public Shipper() + { + } - #endregion + public Shipper(int id, string name, string phone) + { + this.id = id; + this.name = name; + this.phone = phone; + } - #region Properties + #endregion - #endregion + #region Properties - #region Methods + #endregion - #endregion + #region Methods - } + #endregion } diff --git a/test/Spring/Spring.Data.Integration.Tests/Data/Objects/Generic/StoredProcedureTests.cs b/test/Spring/Spring.Data.Integration.Tests/Data/Objects/Generic/StoredProcedureTests.cs index d2f1a0cd..d1263c59 100644 --- a/test/Spring/Spring.Data.Integration.Tests/Data/Objects/Generic/StoredProcedureTests.cs +++ b/test/Spring/Spring.Data.Integration.Tests/Data/Objects/Generic/StoredProcedureTests.cs @@ -2,13 +2,13 @@ /* * Copyright � 2002-2011 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. @@ -18,7 +18,6 @@ #endregion - #region Imports using System.Collections; @@ -31,198 +30,189 @@ using Spring.Objects; #endregion -namespace Spring.Data.Objects.Generic +namespace Spring.Data.Objects.Generic; + +/// +/// This calss contains tests for +/// +/// Mark Pollack +[TestFixture] +public class StoredProcedureTests { - /// - /// This calss contains tests for - /// - /// Mark Pollack - [TestFixture] - public class StoredProcedureTests + private IDbProvider _dbProvider; + + [SetUp] + public void Setup() { - private IDbProvider _dbProvider; + _dbProvider = DbProviderFactory.GetDbProvider("System.Data.SqlClient"); + _dbProvider.ConnectionString = + @"Data Source=SPRINGQA;Database=Spring;User ID=springqa;Password=springqa;Trusted_Connection=False"; - [SetUp] - public void Setup() - { - _dbProvider = DbProviderFactory.GetDbProvider("System.Data.SqlClient"); - _dbProvider.ConnectionString = - @"Data Source=SPRINGQA;Database=Spring;User ID=springqa;Password=springqa;Trusted_Connection=False"; - - IDbCommand command = _dbProvider.CreateCommand(); - command.Connection = _dbProvider.CreateConnection(); - - ClearTestData(command); - CreateTestData(command); - } - - [TearDown] - public void TearDown() - { - IDbCommand command = _dbProvider.CreateCommand(); - command.Connection = _dbProvider.CreateConnection(); - - ClearTestData(command); - } - - private void CreateTestData(IDbCommand command) - { - command.Connection.Open(); - - command.CommandText = "insert into TestObjects(Name,Age) values ('Jack', 10)"; - command.ExecuteNonQuery(); - - command.CommandText = "insert into TestObjects(Name,Age) values ('Jill', 20)"; - command.ExecuteNonQuery(); - - command.CommandText = "insert into Vacations(FirstName,LastName,EmployeeId,StartDate,EndDate) values ('Jack', 'Doe', 200, '1/1/2010', '1/15/2010')"; - command.ExecuteNonQuery(); - - command.CommandText = "insert into Vacations(FirstName,LastName,EmployeeId,StartDate,EndDate) values ('Jack', 'Doe', 200, '2/1/2010', '2/15/2010')"; - command.ExecuteNonQuery(); - - command.Connection.Close(); - } - - private void ClearTestData(IDbCommand command) - { - command.Connection.Open(); - - command.CommandText = "truncate table TestObjects"; - command.ExecuteNonQuery(); - - command.CommandText = "truncate table Vacations"; - command.ExecuteNonQuery(); - - command.Connection.Close(); - } - - - [Test] - public void TestReflection() - { - IRowMapper rm = new TestObjectRowMapper(); - - NamedResultSetProcessor rsp = new NamedResultSetProcessor("Test", rm); - - IDictionary dict = new Hashtable(); - dict.Add("Test", rsp); - DoWork(dict); - - } - - private void DoWork(IDictionary dict) - { - BindingFlags BINDING_FLAGS = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | - BindingFlags.IgnoreCase; - object rsp = dict["Test"]; - Assert.IsNotNull(rsp); - - Type closedType = rsp.GetType(); - foreach (Type parameter in closedType.GetGenericArguments()) - { - Console.WriteLine("closed type param = " + parameter.ToString()); - } - - Console.WriteLine("closed type = " + closedType); - - // typeof(NamedResultSetProcessor<>); - Type[] genericArgumentType = closedType.GetGenericArguments(); - foreach (Type type in genericArgumentType) - { - Console.WriteLine("arg type= " + type); - } - Assert.AreEqual(1, genericArgumentType.Length); - //Type closedGenericType = openType.MakeGenericType(genericArgumentType); - - PropertyInfo propertyInfo = closedType.GetProperty("Name", BINDING_FLAGS); - Assert.IsNotNull(propertyInfo); - object returnValue = propertyInfo.GetValue(rsp, null); - - Assert.AreEqual("Test", returnValue.ToString()); - - PropertyInfo extractorPropInfo = closedType.GetProperty("RowMapper", BINDING_FLAGS); - - Assert.IsNotNull(extractorPropInfo); - - object rowmapper = extractorPropInfo.GetValue(rsp, null); - - Type rowMapperclosedType = rowmapper.GetType(); - - Console.WriteLine("rowmapper closed type= " + rowMapperclosedType); - - MethodInfo methodInfo = rowMapperclosedType.GetMethod("MapRow", BINDING_FLAGS); - - //MethodInfo genMethodInfo = methodInfo.MakeGenericMethod(genericArgumentType); - object retVal = methodInfo.Invoke(rowmapper, new object[] { null, null }); - Console.WriteLine("return val = " + retVal); - - - } - - [Test] - public void SingleTableStoredProcedure_ReturnsResult() - { - TestObjectStoredProc sp = new TestObjectStoredProc(_dbProvider); - IList testObjectList = sp.GetByName("Jack"); - - Assert.That(testObjectList, Is.Not.Null); - Assert.That(testObjectList, Has.Count.EqualTo(1)); - } - - - [Test] - public void MultipleTableStoredProcedure_ReturnsResult() - { - TestObjectandVacationStoredProc vsp = new TestObjectandVacationStoredProc(_dbProvider); - - IDictionary outParams = vsp.ExecStoreProc("Jack"); - - IList testObjectList = testObjectList = outParams["testObjectRowMapper"] as IList; - Assert.IsNotNull(testObjectList); - Assert.AreEqual(1, testObjectList.Count); - - IList vacationList = outParams["vacationRowMapper"] as IList; - Assert.IsNotNull(vacationList); - Assert.AreEqual(2, vacationList.Count); - - } + IDbCommand command = _dbProvider.CreateCommand(); + command.Connection = _dbProvider.CreateConnection(); + ClearTestData(command); + CreateTestData(command); } - public class TestObjectandVacationStoredProc : StoredProcedure + [TearDown] + public void TearDown() { - public TestObjectandVacationStoredProc(IDbProvider dbProvider) - : base(dbProvider, "SelectTestObjectAndVacations") - { - DeriveParameters(); - AddRowMapper("testObjectRowMapper", new TestObjectRowMapper()); - AddRowMapper("vacationRowMapper", new VacationRowMapper()); - Compile(); - } + IDbCommand command = _dbProvider.CreateCommand(); + command.Connection = _dbProvider.CreateConnection(); - public System.Collections.IDictionary ExecStoreProc(string name) - { - return Query(name); - } + ClearTestData(command); } - - public class TestObjectStoredProc : StoredProcedure + private void CreateTestData(IDbCommand command) { - public TestObjectStoredProc(IDbProvider dbProvider) - : base(dbProvider, "SelectByName") + command.Connection.Open(); + + command.CommandText = "insert into TestObjects(Name,Age) values ('Jack', 10)"; + command.ExecuteNonQuery(); + + command.CommandText = "insert into TestObjects(Name,Age) values ('Jill', 20)"; + command.ExecuteNonQuery(); + + command.CommandText = "insert into Vacations(FirstName,LastName,EmployeeId,StartDate,EndDate) values ('Jack', 'Doe', 200, '1/1/2010', '1/15/2010')"; + command.ExecuteNonQuery(); + + command.CommandText = "insert into Vacations(FirstName,LastName,EmployeeId,StartDate,EndDate) values ('Jack', 'Doe', 200, '2/1/2010', '2/15/2010')"; + command.ExecuteNonQuery(); + + command.Connection.Close(); + } + + private void ClearTestData(IDbCommand command) + { + command.Connection.Open(); + + command.CommandText = "truncate table TestObjects"; + command.ExecuteNonQuery(); + + command.CommandText = "truncate table Vacations"; + command.ExecuteNonQuery(); + + command.Connection.Close(); + } + + [Test] + public void TestReflection() + { + IRowMapper rm = new TestObjectRowMapper(); + + NamedResultSetProcessor rsp = new NamedResultSetProcessor("Test", rm); + + IDictionary dict = new Hashtable(); + dict.Add("Test", rsp); + DoWork(dict); + } + + private void DoWork(IDictionary dict) + { + BindingFlags BINDING_FLAGS = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | + BindingFlags.IgnoreCase; + object rsp = dict["Test"]; + Assert.IsNotNull(rsp); + + Type closedType = rsp.GetType(); + foreach (Type parameter in closedType.GetGenericArguments()) { - DeriveParameters(); - AddRowMapper("testObjectRowMapper", new TestObjectRowMapper()); - Compile(); + Console.WriteLine("closed type param = " + parameter.ToString()); } - public IList GetByName(string name) + Console.WriteLine("closed type = " + closedType); + + // typeof(NamedResultSetProcessor<>); + Type[] genericArgumentType = closedType.GetGenericArguments(); + foreach (Type type in genericArgumentType) { - System.Collections.IDictionary outParams = Query(name); - return outParams["testObjectRowMapper"] as IList; + Console.WriteLine("arg type= " + type); } + Assert.AreEqual(1, genericArgumentType.Length); + //Type closedGenericType = openType.MakeGenericType(genericArgumentType); + + PropertyInfo propertyInfo = closedType.GetProperty("Name", BINDING_FLAGS); + Assert.IsNotNull(propertyInfo); + object returnValue = propertyInfo.GetValue(rsp, null); + + Assert.AreEqual("Test", returnValue.ToString()); + + PropertyInfo extractorPropInfo = closedType.GetProperty("RowMapper", BINDING_FLAGS); + + Assert.IsNotNull(extractorPropInfo); + + object rowmapper = extractorPropInfo.GetValue(rsp, null); + + Type rowMapperclosedType = rowmapper.GetType(); + + Console.WriteLine("rowmapper closed type= " + rowMapperclosedType); + + MethodInfo methodInfo = rowMapperclosedType.GetMethod("MapRow", BINDING_FLAGS); + + //MethodInfo genMethodInfo = methodInfo.MakeGenericMethod(genericArgumentType); + object retVal = methodInfo.Invoke(rowmapper, new object[] { null, null }); + Console.WriteLine("return val = " + retVal); + } + + [Test] + public void SingleTableStoredProcedure_ReturnsResult() + { + TestObjectStoredProc sp = new TestObjectStoredProc(_dbProvider); + IList testObjectList = sp.GetByName("Jack"); + + Assert.That(testObjectList, Is.Not.Null); + Assert.That(testObjectList, Has.Count.EqualTo(1)); + } + + [Test] + public void MultipleTableStoredProcedure_ReturnsResult() + { + TestObjectandVacationStoredProc vsp = new TestObjectandVacationStoredProc(_dbProvider); + + IDictionary outParams = vsp.ExecStoreProc("Jack"); + + IList testObjectList = testObjectList = outParams["testObjectRowMapper"] as IList; + Assert.IsNotNull(testObjectList); + Assert.AreEqual(1, testObjectList.Count); + + IList vacationList = outParams["vacationRowMapper"] as IList; + Assert.IsNotNull(vacationList); + Assert.AreEqual(2, vacationList.Count); + } +} + +public class TestObjectandVacationStoredProc : StoredProcedure +{ + public TestObjectandVacationStoredProc(IDbProvider dbProvider) + : base(dbProvider, "SelectTestObjectAndVacations") + { + DeriveParameters(); + AddRowMapper("testObjectRowMapper", new TestObjectRowMapper()); + AddRowMapper("vacationRowMapper", new VacationRowMapper()); + Compile(); + } + + public System.Collections.IDictionary ExecStoreProc(string name) + { + return Query(name); + } +} + +public class TestObjectStoredProc : StoredProcedure +{ + public TestObjectStoredProc(IDbProvider dbProvider) + : base(dbProvider, "SelectByName") + { + DeriveParameters(); + AddRowMapper("testObjectRowMapper", new TestObjectRowMapper()); + Compile(); + } + + public IList GetByName(string name) + { + System.Collections.IDictionary outParams = Query(name); + return outParams["testObjectRowMapper"] as IList; } } diff --git a/test/Spring/Spring.Data.Integration.Tests/Data/Objects/Generic/Vacation.cs b/test/Spring/Spring.Data.Integration.Tests/Data/Objects/Generic/Vacation.cs index 9c390f46..9aa08dd6 100644 --- a/test/Spring/Spring.Data.Integration.Tests/Data/Objects/Generic/Vacation.cs +++ b/test/Spring/Spring.Data.Integration.Tests/Data/Objects/Generic/Vacation.cs @@ -18,67 +18,63 @@ #endregion -namespace Spring.Data.Objects.Generic +namespace Spring.Data.Objects.Generic; + +public class Vacation { + private int id; + private string firstName; + private string lastName; + private int employeeId; + private DateTime startDate; + private DateTime endDate; - public class Vacation + public int Id { - private int id; - private string firstName; - private string lastName; - private int employeeId; - private DateTime startDate; - private DateTime endDate; + get { return id; } + set { id = value; } + } + public string FirstName + { + get { return firstName; } + set { firstName = value; } + } - public int Id - { - get { return id; } - set { id = value; } - } + public string LastName + { + get { return lastName; } + set { lastName = value; } + } - public string FirstName - { - get { return firstName; } - set { firstName = value; } - } + public int EmployeeId + { + get { return employeeId; } + set { employeeId = value; } + } - public string LastName - { - get { return lastName; } - set { lastName = value; } - } + public DateTime StartDate + { + get { return startDate; } + set { startDate = value; } + } - public int EmployeeId - { - get { return employeeId; } - set { employeeId = value; } - } + public DateTime EndDate + { + get { return endDate; } + set { endDate = value; } + } - public DateTime StartDate - { - get { return startDate; } - set { startDate = value; } - } + public override bool Equals(object obj) + { + if (this == obj) return true; + Vacation vacation = obj as Vacation; + if (vacation == null) return false; + return employeeId == vacation.employeeId && Equals(startDate, vacation.startDate); + } - public DateTime EndDate - { - get { return endDate; } - set { endDate = value; } - } - - - public override bool Equals(object obj) - { - if (this == obj) return true; - Vacation vacation = obj as Vacation; - if (vacation == null) return false; - return employeeId == vacation.employeeId && Equals(startDate, vacation.startDate); - } - - public override int GetHashCode() - { - return employeeId + 29 * startDate.GetHashCode(); - } + public override int GetHashCode() + { + return employeeId + 29 * startDate.GetHashCode(); } } diff --git a/test/Spring/Spring.Data.Integration.Tests/Data/Objects/Generic/VacationRowMapper.cs b/test/Spring/Spring.Data.Integration.Tests/Data/Objects/Generic/VacationRowMapper.cs index ae4869a7..1f50b833 100644 --- a/test/Spring/Spring.Data.Integration.Tests/Data/Objects/Generic/VacationRowMapper.cs +++ b/test/Spring/Spring.Data.Integration.Tests/Data/Objects/Generic/VacationRowMapper.cs @@ -2,13 +2,13 @@ /* * Copyright � 2002-2011 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. @@ -21,27 +21,26 @@ using System.Data; using Spring.Data.Generic; -namespace Spring.Data.Objects.Generic +namespace Spring.Data.Objects.Generic; + +/// +/// This is +/// +/// +/// +/// +/// Mark Pollack +public class VacationRowMapper : IRowMapper where T : Vacation, new() { - /// - /// This is - /// - /// - /// - /// - /// Mark Pollack - public class VacationRowMapper : IRowMapper where T : Vacation, new() + public T MapRow(IDataReader reader, int rowNum) { - public T MapRow(IDataReader reader, int rowNum) - { - T vacation = new T(); - vacation.Id = Decimal.ToInt32(reader.GetDecimal(0)); - vacation.FirstName = reader.GetString(1); - vacation.LastName = reader.GetString(2); - vacation.EmployeeId = Decimal.ToInt32(reader.GetDecimal(3)); - vacation.StartDate = reader.GetDateTime(4); - vacation.EndDate = reader.GetDateTime(5); - return vacation; - } + T vacation = new T(); + vacation.Id = Decimal.ToInt32(reader.GetDecimal(0)); + vacation.FirstName = reader.GetString(1); + vacation.LastName = reader.GetString(2); + vacation.EmployeeId = Decimal.ToInt32(reader.GetDecimal(3)); + vacation.StartDate = reader.GetDateTime(4); + vacation.EndDate = reader.GetDateTime(5); + return vacation; } } diff --git a/test/Spring/Spring.Data.Integration.Tests/Data/OracleAdoTemplateTests.cs b/test/Spring/Spring.Data.Integration.Tests/Data/OracleAdoTemplateTests.cs index 660afa1c..3fad7b12 100644 --- a/test/Spring/Spring.Data.Integration.Tests/Data/OracleAdoTemplateTests.cs +++ b/test/Spring/Spring.Data.Integration.Tests/Data/OracleAdoTemplateTests.cs @@ -33,226 +33,222 @@ using Spring.Objects; #endregion -namespace Spring.Data -{ - /// - /// - /// - /// Mark Pollack (.NET) - [TestFixture] - [Ignore("ORACLE-dependent tests disabled for integration runs")] - public class OracleAdoTemplateTests - { - #region Setup/Teardown +namespace Spring.Data; - [SetUp] - public void CreateAdoTemplate() +/// +/// +/// +/// Mark Pollack (.NET) +[TestFixture] +[Ignore("ORACLE-dependent tests disabled for integration runs")] +public class OracleAdoTemplateTests +{ + #region Setup/Teardown + + [SetUp] + public void CreateAdoTemplate() + { + IApplicationContext ctx = + new XmlApplicationContext( + "assembly://Spring.Data.Integration.Tests/Spring.Data/oracleAdoTemplateTests.xml"); + Assert.IsNotNull(ctx); + dbProvider = ctx["DbProvider"] as IDbProvider; + Assert.IsNotNull(dbProvider); + adoOperations = new AdoTemplate(dbProvider); + } + + #endregion + + private IAdoOperations adoOperations; + private IDbProvider dbProvider; + + /// + /// The shared ILog instance for this class (and derived classes). + /// + protected static readonly ILog log = LogManager.GetLogger(); + + private class TestObjectExtractor : IResultSetExtractor + { + #region IResultSetExtractor Members + + public object ExtractData(IDataReader reader) { - IApplicationContext ctx = - new XmlApplicationContext( - "assembly://Spring.Data.Integration.Tests/Spring.Data/oracleAdoTemplateTests.xml"); - Assert.IsNotNull(ctx); - dbProvider = ctx["DbProvider"] as IDbProvider; - Assert.IsNotNull(dbProvider); - adoOperations = new AdoTemplate(dbProvider); + IList testObjects = new ArrayList(); + while (reader.Read()) + { + TestObject to = new TestObject(); + //object foo = reader.GetDataTypeName(0); + to.ObjectNumber = (int) reader.GetInt64(0); + to.Name = reader.GetString(1); + testObjects.Add(to); + } + + return testObjects; } #endregion + } - private IAdoOperations adoOperations; - private IDbProvider dbProvider; + [Test] + public void DataSetFillNoParams() + { + String sql = "select USER_ID, USER_NAME from USER_TABLE"; + DataSet dataSet = new DataSet(); + adoOperations.DataSetFill(dataSet, CommandType.Text, sql); + Assert.AreEqual(1, dataSet.Tables.Count); + Assert.AreEqual(18, dataSet.Tables["Table"].Rows.Count); - /// - /// The shared ILog instance for this class (and derived classes). - /// - protected static readonly ILog log = LogManager.GetLogger(); + dataSet = new DataSet(); + adoOperations.DataSetFill(dataSet, CommandType.Text, sql, new string[] { "TestObjects" }); + Assert.AreEqual(1, dataSet.Tables.Count); + Assert.AreEqual(18, dataSet.Tables["TestObjects"].Rows.Count); - private class TestObjectExtractor : IResultSetExtractor + dataSet = new DataSet(); + DataTableMappingCollection mappingCollection = + new DataTableMappingCollection(); + DataTableMapping testObjectsMapping = mappingCollection.Add("Table", "TestObjects"); + testObjectsMapping.ColumnMappings.Add("USER_ID", "UserID"); + testObjectsMapping.ColumnMappings.Add("USER_NAME", "UserName"); + adoOperations.DataSetFill(dataSet, CommandType.Text, sql, mappingCollection); + Assert.AreEqual(1, dataSet.Tables.Count); + Assert.AreEqual(18, dataSet.Tables["TestObjects"].Rows.Count); + foreach (DataRow testObjectRow in dataSet.Tables["TestObjects"].Rows) { - #region IResultSetExtractor Members - - public object ExtractData(IDataReader reader) - { - IList testObjects = new ArrayList(); - while (reader.Read()) - { - TestObject to = new TestObject(); - //object foo = reader.GetDataTypeName(0); - to.ObjectNumber = (int) reader.GetInt64(0); - to.Name = reader.GetString(1); - testObjects.Add(to); - } - return testObjects; - } - - #endregion - } - - [Test] - public void DataSetFillNoParams() - { - String sql = "select USER_ID, USER_NAME from USER_TABLE"; - DataSet dataSet = new DataSet(); - adoOperations.DataSetFill(dataSet, CommandType.Text, sql); - Assert.AreEqual(1, dataSet.Tables.Count); - Assert.AreEqual(18, dataSet.Tables["Table"].Rows.Count); - - dataSet = new DataSet(); - adoOperations.DataSetFill(dataSet, CommandType.Text, sql, new string[] {"TestObjects"}); - Assert.AreEqual(1, dataSet.Tables.Count); - Assert.AreEqual(18, dataSet.Tables["TestObjects"].Rows.Count); - - dataSet = new DataSet(); - DataTableMappingCollection mappingCollection = - new DataTableMappingCollection(); - DataTableMapping testObjectsMapping = mappingCollection.Add("Table", "TestObjects"); - testObjectsMapping.ColumnMappings.Add("USER_ID", "UserID"); - testObjectsMapping.ColumnMappings.Add("USER_NAME", "UserName"); - adoOperations.DataSetFill(dataSet, CommandType.Text, sql, mappingCollection); - Assert.AreEqual(1, dataSet.Tables.Count); - Assert.AreEqual(18, dataSet.Tables["TestObjects"].Rows.Count); - foreach (DataRow testObjectRow in dataSet.Tables["TestObjects"].Rows) - { - Assert.IsNotNull(testObjectRow["UserID"]); - Assert.IsNotNull(testObjectRow["UserName"]); - } - } - - [Test] - public void DataSetFillWithParameters() - { - String sql = "select USER_ID, USER_NAME from USER_TABLE where USER_ID < :maxId"; - DataSet dataSet = new DataSet(); - IDbParameters parameters = adoOperations.CreateDbParameters(); - parameters.Add("maxId", OracleType.Int32).Value = 10; - adoOperations.DataSetFillWithParameters(dataSet, CommandType.Text, sql, - parameters, - new string[] {"TestObjects"}); - Assert.AreEqual(1, dataSet.Tables.Count); - Assert.AreEqual(6, dataSet.Tables["TestObjects"].Rows.Count); - } - - [Test] - public void DataSetUpdate() - { - //'pretend' unique key is the age... - String sql = "select USER_ID, USER_NAME from USER_TABLE"; - DataSet dataSet = new DataSet(); - adoOperations.DataSetFill(dataSet, CommandType.Text, sql, new string[] {"TestObjects"}); - - //Create and add new row. - DataRow myDataRow = dataSet.Tables["TestObjects"].NewRow(); - myDataRow["USER_ID"] = 101; - myDataRow["USER_NAME"] = "OldManWinter"; - dataSet.Tables["TestObjects"].Rows.Add(myDataRow); - - IDbParameters parameters = adoOperations.CreateDbParameters(); - //TODO - remembering the -1 isn't all that natural... add string name, dbtype, string sourceCol) - //or AddSourceCol("age", SqlDbType.Int); would copy into source col? - parameters.Add("id", OracleType.Int32, -1, "USER_ID"); - parameters.Add("name", DbType.String, 12, "USER_NAME"); - - - //Extanious CommandTypes.... - adoOperations.DataSetUpdate(dataSet, "TestObjects", - CommandType.Text, - "insert into USER_TABLE(USER_ID, USER_NAME) values (:id,:name)", parameters, - CommandType.Text, null, null, - CommandType.Text, null, null); - - - //TODO - think about api... - /* - IDbCommand insertCommand = dbProvider.CreateCommand(); - insertCommand.CommandText = "insert into USER_TABLE(USER_ID, USER_NAME) values (:id,:name)"; - parameters = adoOperations.NewDbParameters(); - //TODO - remembering the -1 isn't all that natural... add string name, dbtype, string sourceCol) - //or AddSourceCol("age", SqlDbType.Int); would copy into source col? - parameters.Add("id", OracleType.Int32, -1, "USER_ID"); - parameters.Add("name", DbType.String, 12, "USER_NAME"); - - //TODO - this isn't all that natural... - ParameterUtils.CopyParameters(insertCommand, parameters); - - - adoOperations.DataSetUpdate(dataSet, "TestObjects", - insertCommand, - null, - null); - - */ - - //TODO avoid param Utils copy by adding argument... - - //adoOperations.DataSetUpdate(dataSet, "TestObjects", - // insertCommand, parameters, - // null, null, - // null, null); - - // or avoid all ref to command object.... - - //adoOperations.DataSetUpdate(dataSet, "TestObjects", - // CommandType type, string sql, parameters, - // null, null, - // null, null); - - //TODO how about breaking up the operations... - } - - [Test] - public void ExceptionTranslation() - { - try - { - adoOperations.ExecuteNonQuery(CommandType.Text, "select foo from bar"); - } - catch (BadSqlGrammarException) - { - // should execute in here in sunny day scenario... - } - catch (Exception) - { - Assert.Fail("Exception translation not working."); - } - } - - - [Test] - public void ExecuteNonQueryText() - { - int user_id = 100; - - string user_name = "George0"; - - String sql = String.Format("insert into USER_TABLE(USER_ID, USER_NAME) VALUES ({0}, '{1}')", - user_id, user_name); - adoOperations.ExecuteNonQuery(CommandType.Text, sql); - - - sql = "insert into USER_TABLE(USER_ID, USER_NAME) values (:id,:name)"; - IDbParameters parameters = adoOperations.CreateDbParameters(); - - int user_id1 = 101; - string user_name1 = "George1"; - parameters.Add("id", OracleType.Int32).Value = user_id1; - parameters.Add("name", DbType.String, 12).Value = user_name1; - - adoOperations.ExecuteNonQuery(CommandType.Text, sql, parameters); - } - - [Test] - public void ExecuteQueryWithResultSetExtractor() - { - IResultSetExtractor rse = new TestObjectExtractor(); - String sql = "select USER_ID, USER_NAME from USER_TABLE"; - IList testObjectList = (IList) adoOperations.QueryWithResultSetExtractor(CommandType.Text, sql, rse); - Assert.AreEqual(18, testObjectList.Count); - } - - [Test] - public void SanityCheck() - { - adoOperations.ExecuteNonQuery(CommandType.Text, "select * from DUAL"); + Assert.IsNotNull(testObjectRow["UserID"]); + Assert.IsNotNull(testObjectRow["UserName"]); } } + + [Test] + public void DataSetFillWithParameters() + { + String sql = "select USER_ID, USER_NAME from USER_TABLE where USER_ID < :maxId"; + DataSet dataSet = new DataSet(); + IDbParameters parameters = adoOperations.CreateDbParameters(); + parameters.Add("maxId", OracleType.Int32).Value = 10; + adoOperations.DataSetFillWithParameters(dataSet, CommandType.Text, sql, + parameters, + new string[] { "TestObjects" }); + Assert.AreEqual(1, dataSet.Tables.Count); + Assert.AreEqual(6, dataSet.Tables["TestObjects"].Rows.Count); + } + + [Test] + public void DataSetUpdate() + { + //'pretend' unique key is the age... + String sql = "select USER_ID, USER_NAME from USER_TABLE"; + DataSet dataSet = new DataSet(); + adoOperations.DataSetFill(dataSet, CommandType.Text, sql, new string[] { "TestObjects" }); + + //Create and add new row. + DataRow myDataRow = dataSet.Tables["TestObjects"].NewRow(); + myDataRow["USER_ID"] = 101; + myDataRow["USER_NAME"] = "OldManWinter"; + dataSet.Tables["TestObjects"].Rows.Add(myDataRow); + + IDbParameters parameters = adoOperations.CreateDbParameters(); + //TODO - remembering the -1 isn't all that natural... add string name, dbtype, string sourceCol) + //or AddSourceCol("age", SqlDbType.Int); would copy into source col? + parameters.Add("id", OracleType.Int32, -1, "USER_ID"); + parameters.Add("name", DbType.String, 12, "USER_NAME"); + + //Extanious CommandTypes.... + adoOperations.DataSetUpdate(dataSet, "TestObjects", + CommandType.Text, + "insert into USER_TABLE(USER_ID, USER_NAME) values (:id,:name)", parameters, + CommandType.Text, null, null, + CommandType.Text, null, null); + + //TODO - think about api... + /* + IDbCommand insertCommand = dbProvider.CreateCommand(); + insertCommand.CommandText = "insert into USER_TABLE(USER_ID, USER_NAME) values (:id,:name)"; + parameters = adoOperations.NewDbParameters(); + //TODO - remembering the -1 isn't all that natural... add string name, dbtype, string sourceCol) + //or AddSourceCol("age", SqlDbType.Int); would copy into source col? + parameters.Add("id", OracleType.Int32, -1, "USER_ID"); + parameters.Add("name", DbType.String, 12, "USER_NAME"); + + //TODO - this isn't all that natural... + ParameterUtils.CopyParameters(insertCommand, parameters); + + + adoOperations.DataSetUpdate(dataSet, "TestObjects", + insertCommand, + null, + null); + + */ + + //TODO avoid param Utils copy by adding argument... + + //adoOperations.DataSetUpdate(dataSet, "TestObjects", + // insertCommand, parameters, + // null, null, + // null, null); + + // or avoid all ref to command object.... + + //adoOperations.DataSetUpdate(dataSet, "TestObjects", + // CommandType type, string sql, parameters, + // null, null, + // null, null); + + //TODO how about breaking up the operations... + } + + [Test] + public void ExceptionTranslation() + { + try + { + adoOperations.ExecuteNonQuery(CommandType.Text, "select foo from bar"); + } + catch (BadSqlGrammarException) + { + // should execute in here in sunny day scenario... + } + catch (Exception) + { + Assert.Fail("Exception translation not working."); + } + } + + [Test] + public void ExecuteNonQueryText() + { + int user_id = 100; + + string user_name = "George0"; + + String sql = String.Format("insert into USER_TABLE(USER_ID, USER_NAME) VALUES ({0}, '{1}')", + user_id, user_name); + adoOperations.ExecuteNonQuery(CommandType.Text, sql); + + sql = "insert into USER_TABLE(USER_ID, USER_NAME) values (:id,:name)"; + IDbParameters parameters = adoOperations.CreateDbParameters(); + + int user_id1 = 101; + string user_name1 = "George1"; + parameters.Add("id", OracleType.Int32).Value = user_id1; + parameters.Add("name", DbType.String, 12).Value = user_name1; + + adoOperations.ExecuteNonQuery(CommandType.Text, sql, parameters); + } + + [Test] + public void ExecuteQueryWithResultSetExtractor() + { + IResultSetExtractor rse = new TestObjectExtractor(); + String sql = "select USER_ID, USER_NAME from USER_TABLE"; + IList testObjectList = (IList) adoOperations.QueryWithResultSetExtractor(CommandType.Text, sql, rse); + Assert.AreEqual(18, testObjectList.Count); + } + + [Test] + public void SanityCheck() + { + adoOperations.ExecuteNonQuery(CommandType.Text, "select * from DUAL"); + } } diff --git a/test/Spring/Spring.Data.Integration.Tests/Data/SQLiteTests.cs b/test/Spring/Spring.Data.Integration.Tests/Data/SQLiteTests.cs index 155731d5..83d1c59f 100644 --- a/test/Spring/Spring.Data.Integration.Tests/Data/SQLiteTests.cs +++ b/test/Spring/Spring.Data.Integration.Tests/Data/SQLiteTests.cs @@ -31,383 +31,389 @@ using Spring.Data.Objects; #endregion -namespace Spring.Data +namespace Spring.Data; + +/// +/// This class contains misc tests for specific providers +/// +/// Mark Pollack +[TestFixture] +public class SQLiteTests { - /// - /// This class contains misc tests for specific providers - /// - /// Mark Pollack - [TestFixture] - public class SQLiteTests + [SetUp] + public void Setup() { - [SetUp] - public void Setup() + } + + [Test] + public void SqlServerTest() + { + string errorCode = "544"; + string[] errorCodes = new string[4] { "544", "2627", "8114", "8115" }; + //Array.IndexOf() + //Array.Sort(errorCodes); + foreach (string code in errorCodes) { + Console.WriteLine(code); } - [Test] - public void SqlServerTest() + //if (Array.BinarySearch(errorCodes, errorCode) >= 0) + if (Array.IndexOf(errorCodes, errorCode) >= 0) { - string errorCode = "544"; - string[] errorCodes = new string[4] { "544", "2627", "8114", "8115" }; - //Array.IndexOf() - //Array.Sort(errorCodes); - foreach (string code in errorCodes) - { - Console.WriteLine(code); - } - //if (Array.BinarySearch(errorCodes, errorCode) >= 0) - if (Array.IndexOf(errorCodes, errorCode) >= 0) - { - Console.WriteLine("yes"); - } - else - { - Assert.Fail("did not find error code"); - } - IDbProvider dbProvider = DbProviderFactory.GetDbProvider("System.Data.SqlClient"); - dbProvider.ConnectionString = - @"Data Source=SPRINGQA;Initial Catalog=Spring;Persist Security Info=True;User ID=springqa;Password=springqa"; - AdoTemplate adoTemplate = new AdoTemplate(dbProvider); - try - { - adoTemplate.ExecuteNonQuery(CommandType.Text, "insert into Vacations (FirstName,LastName) values ('Jack','Doe')"); - } - catch (Exception e) - { - Console.Write(e); - throw; - } + Console.WriteLine("yes"); } - [Test] - [Ignore("ORACLE-dependent tests disabled for integration runs")] - public void OracleTest() + else { - //Data Source=XE;User ID=hr;Unicode=True - IDbProvider dbProvider = DbProviderFactory.GetDbProvider("System.Data.OracleClient"); - dbProvider.ConnectionString = "Data Source=XE;User ID=hr;Password=hr;Unicode=True"; - AdoTemplate adoTemplate = new AdoTemplate(dbProvider); - decimal count = (decimal)adoTemplate.ExecuteScalar(CommandType.Text, "select count(*) from emp"); - Assert.AreEqual(14, count); - - EmpProc empProc = new EmpProc(dbProvider); - IDictionary dict = empProc.GetEmployees(); - foreach (DictionaryEntry entry in dict) - { - Console.WriteLine("Key = " + entry.Key + ", Value = " + entry.Value); - } - IList employeeList = dict["employees"] as IList; - foreach (Employee employee in employeeList) - { - Console.WriteLine(employee); - } - + Assert.Fail("did not find error code"); } - [Test] - [Ignore("ODBC-dependent tests disabled for integration runs")] - public void Test() + IDbProvider dbProvider = DbProviderFactory.GetDbProvider("System.Data.SqlClient"); + dbProvider.ConnectionString = + @"Data Source=SPRINGQA;Initial Catalog=Spring;Persist Security Info=True;User ID=springqa;Password=springqa"; + AdoTemplate adoTemplate = new AdoTemplate(dbProvider); + try { - //IDbProvider dbProvider = DbProviderFactory.GetDbProvider("SybaseAse1.15"); - // dbProvider.ConnectionString = "Data Source='MARKT60';Port='5000';UID='sa';PWD='';Database='pubs2';"; - - - IDbProvider dbProvider = DbProviderFactory.GetDbProvider("Odbc-2.0"); - dbProvider.ConnectionString = - "Driver={Adaptive Server Enterprise};server=MARKT60;port=5000;Database=pubs2;uid=sa;pwd=;"; - Assert.IsNotNull(dbProvider); - AdoTemplate adoTemplate = new AdoTemplate(dbProvider); - IList authorList = - adoTemplate.QueryWithRowMapperDelegate(CommandType.Text, "select au_lname from authors", - delegate(IDataReader dataReader, int rowNum) { return dataReader.GetString(0); }); - foreach (string s in authorList) - { - Console.WriteLine(s); - } - Assert.IsTrue(authorList.Count > 0); + adoTemplate.ExecuteNonQuery(CommandType.Text, "insert into Vacations (FirstName,LastName) values ('Jack','Doe')"); } - /* - [Test] - public void StoredProc() - { - //IDbProvider dbProvider = DbProviderFactory.GetDbProvider("SybaseAse1.15"); - //dbProvider.ConnectionString = "Data Source='MARKT60';Port='5000';UID='sa';PWD='';Database='pubs2';"; - - - //IDbProvider dbProvider = DbProviderFactory.GetDbProvider("Odbc-2.0"); - //dbProvider.ConnectionString = - // "Driver={Adaptive Server Enterprise};server=MARKT60;port=5000;Database=pubs2;uid=sa;pwd=;"; - - IDbProvider dbProvider = DbProviderFactory.GetDbProvider("SybaseAse-15"); - dbProvider.ConnectionString = "Data Source='MARKT60';Port='5000';UID='sa';PWD='';Database='pubs2';"; - HelloProc proc = new HelloProc(dbProvider); - IDictionary dict = proc.GetResults(); - - Assert.AreEqual("Go Sybase", dict["@inoutParam"]); - Assert.AreEqual("Hello mango", dict["@outParam"]); - Assert.AreEqual(101, (int) dict["RETURN_VALUE"]); - foreach (DictionaryEntry entry in dict) - { - Console.WriteLine("Key = " + entry.Key + ", Value = " + entry.Value); - } - } - - [Test] - public void StordProcAdoTemplate() - { - IDbProvider dbProvider = DbProviderFactory.GetDbProvider("SybaseAse-15"); - dbProvider.ConnectionString = "Data Source='MARKT60';Port='5000';UID='sa';PWD='';Database='pubs2';"; - AdoTemplate adoTemplate = new AdoTemplate(dbProvider); - IDbParameters parameters = new DbParameters(dbProvider); - parameters.Add("inParam", AseDbType.VarChar, 32).Value = "mango"; - parameters.AddInOut("inoutParam", AseDbType.VarChar, 64).Value = "Sybase"; - parameters.AddOut("outParam", AseDbType.VarChar, 64); - parameters.AddReturn("retValue", AseDbType.Integer); - adoTemplate.ExecuteNonQuery(CommandType.StoredProcedure, "sp_hello", parameters); - - - Assert.AreEqual("Go Sybase", parameters["@inoutParam"].Value); - Assert.AreEqual("Hello mango", parameters[2].Value); - Assert.AreEqual(101, (int) parameters[3].Value); - } - */ - [Test] - [Ignore("SYBASE-ASE-dependent tests disabled for integration runs")] - public void DeriveParams() + catch (Exception e) { - IDbProvider dbProvider = DbProviderFactory.GetDbProvider("SybaseAse-15"); - dbProvider.ConnectionString = "Data Source='MARKT60';Port='5000';UID='sa';PWD='';Database='pubs2';"; - AdoTemplate adoTemplate = new AdoTemplate(dbProvider); - IDataParameter[] derivedParameters = adoTemplate.DeriveParameters("@sp_hello", true); - if (derivedParameters.Length == 0) - { - Console.WriteLine("Derived Parameters = 0!!!!"); - } - for (int i = 0; i < derivedParameters.Length; i++) - { - Console.WriteLine("Parameter " + i + ", Name = " + derivedParameters[i].ParameterName + ", Value = " + - derivedParameters[i].Value); - } - } - - /* - [Test] - public void RawDeriveParams() - { - using ( - AseConnection conn = - new AseConnection("Data Source='MARKT60';Port='5000';UID='sa';PWD='';Database='pubs2';")) - { - using (AseCommand cmd = new AseCommand("@sp_hello", conn)) - { - conn.Open(); - cmd.CommandType = CommandType.StoredProcedure; - AseCommandBuilder.DeriveParameters(cmd); - Console.WriteLine("Number of parameters = " + cmd.Parameters.Count); - } - } - } - */ - [Test] - [Ignore("SYBASE-ASE-dependent tests disabled for integration runs")] - public void QueryWithMapper() - { - IDbProvider dbProvider = DbProviderFactory.GetDbProvider("SybaseAse-15"); - dbProvider.ConnectionString = "Data Source='MARKT60';Port='5000';UID='sa';PWD='';Database='pubs2';"; - PubDao pubDao = new PubDao(dbProvider); - IList sales = pubDao.GetSales("5023"); - Assert.AreEqual(50, sales.Count); - } - - [Test] - [Ignore("ODBC-dependent tests disabled for integration runs")] - public void QueryWithMapperODBC() - { - IDbProvider dbProvider = DbProviderFactory.GetDbProvider("Odbc-2.0"); - dbProvider.ConnectionString = - "Driver={Adaptive Server Enterprise};server=MARKT60;port=5000;Database=pubs2;uid=sa;pwd=;"; - PubDao pubDao = new PubDao(dbProvider); - IList sales = pubDao.GetSales("5023"); - Assert.AreEqual(50, sales.Count); - } - - [Test] - [Ignore("SYBASE-ASE-dependent tests disabled for integration runs")] - public void QueryRawODBC() - { - using ( - OdbcConnection conn = - new OdbcConnection( - "Driver={Adaptive Server Enterprise};server=MARKT60;port=5000;Database=pubs2;uid=sa;pwd=;")) - { - using (OdbcCommand cmd = new OdbcCommand("history_proc @stor_id", conn)) - { - conn.Open(); - cmd.CommandType = CommandType.StoredProcedure; - cmd.Parameters.Add("stor_id", OdbcType.NVarChar).Value = "5023"; - int i = 0; - using (IDataReader reader = cmd.ExecuteReader()) - { - while (reader.Read()) - { - i++; - } - } - Assert.AreEqual(50, i); - } - } + Console.Write(e); + throw; } } - public class PubDao : AdoDaoSupport + [Test] + [Ignore("ORACLE-dependent tests disabled for integration runs")] + public void OracleTest() { - public PubDao(IDbProvider provider) + //Data Source=XE;User ID=hr;Unicode=True + IDbProvider dbProvider = DbProviderFactory.GetDbProvider("System.Data.OracleClient"); + dbProvider.ConnectionString = "Data Source=XE;User ID=hr;Password=hr;Unicode=True"; + AdoTemplate adoTemplate = new AdoTemplate(dbProvider); + decimal count = (decimal) adoTemplate.ExecuteScalar(CommandType.Text, "select count(*) from emp"); + Assert.AreEqual(14, count); + + EmpProc empProc = new EmpProc(dbProvider); + IDictionary dict = empProc.GetEmployees(); + foreach (DictionaryEntry entry in dict) { - DbProvider = provider; + Console.WriteLine("Key = " + entry.Key + ", Value = " + entry.Value); } - public IList GetSales(string storeId) + IList employeeList = dict["employees"] as IList; + foreach (Employee employee in employeeList) { - return AdoTemplate.QueryWithRowMapperDelegate(CommandType.StoredProcedure, "history_proc", - delegate(IDataReader dataReader, int rowNum) - { - Sale sale = new Sale(); - sale.Date = dataReader.GetDateTime(0); - sale.OrderNumber = dataReader.GetString(1); - sale.Quantity = dataReader.GetInt32(2); - sale.Title = dataReader.GetString(3); - sale.Discount = dataReader.GetFloat(4); - sale.Price = dataReader.GetFloat(5); - sale.Total = dataReader.GetFloat(6); - return sale; - }, "stor_id", - DbType.String, 0, storeId); + Console.WriteLine(employee); } } - public class Sale + [Test] + [Ignore("ODBC-dependent tests disabled for integration runs")] + public void Test() { - private DateTime date; - private string orderNumber; - private int quantity; - private string title; - private float discount; - private float price; - private float total; + //IDbProvider dbProvider = DbProviderFactory.GetDbProvider("SybaseAse1.15"); + // dbProvider.ConnectionString = "Data Source='MARKT60';Port='5000';UID='sa';PWD='';Database='pubs2';"; - - public DateTime Date + IDbProvider dbProvider = DbProviderFactory.GetDbProvider("Odbc-2.0"); + dbProvider.ConnectionString = + "Driver={Adaptive Server Enterprise};server=MARKT60;port=5000;Database=pubs2;uid=sa;pwd=;"; + Assert.IsNotNull(dbProvider); + AdoTemplate adoTemplate = new AdoTemplate(dbProvider); + IList authorList = + adoTemplate.QueryWithRowMapperDelegate(CommandType.Text, "select au_lname from authors", + delegate(IDataReader dataReader, int rowNum) { return dataReader.GetString(0); }); + foreach (string s in authorList) { - get { return date; } - set { date = value; } + Console.WriteLine(s); } - public float Discount - { - get { return discount; } - set { discount = value; } - } - - public string OrderNumber - { - get { return orderNumber; } - set { orderNumber = value; } - } - - public int Quantity - { - get { return quantity; } - set { quantity = value; } - } - - public string Title - { - get { return title; } - set { title = value; } - } - - public float Price - { - get { return price; } - set { price = value; } - } - - public float Total - { - get { return total; } - set { total = value; } - } + Assert.IsTrue(authorList.Count > 0); } + /* - public class HelloProc : StoredProcedure - { - public HelloProc(IDbProvider provider) : base(provider, "sp_hello") + [Test] + public void StoredProc() { - DeclaredParameters.Add("inParam", AseDbType.VarChar, 32).Value = "mango"; - DeclaredParameters.AddInOut("inoutParam", AseDbType.VarChar, 64).Value = "Sybase"; - DeclaredParameters.AddOut("outParam", AseDbType.VarChar, 64); - DeclaredParameters.AddReturn("retValue", AseDbType.Integer); - Compile(); + //IDbProvider dbProvider = DbProviderFactory.GetDbProvider("SybaseAse1.15"); + //dbProvider.ConnectionString = "Data Source='MARKT60';Port='5000';UID='sa';PWD='';Database='pubs2';"; + + + //IDbProvider dbProvider = DbProviderFactory.GetDbProvider("Odbc-2.0"); + //dbProvider.ConnectionString = + // "Driver={Adaptive Server Enterprise};server=MARKT60;port=5000;Database=pubs2;uid=sa;pwd=;"; + + IDbProvider dbProvider = DbProviderFactory.GetDbProvider("SybaseAse-15"); + dbProvider.ConnectionString = "Data Source='MARKT60';Port='5000';UID='sa';PWD='';Database='pubs2';"; + HelloProc proc = new HelloProc(dbProvider); + IDictionary dict = proc.GetResults(); + + Assert.AreEqual("Go Sybase", dict["@inoutParam"]); + Assert.AreEqual("Hello mango", dict["@outParam"]); + Assert.AreEqual(101, (int) dict["RETURN_VALUE"]); + foreach (DictionaryEntry entry in dict) + { + Console.WriteLine("Key = " + entry.Key + ", Value = " + entry.Value); + } } - public IDictionary GetResults() + [Test] + public void StordProcAdoTemplate() { - return Query("mango", "Sybase"); + IDbProvider dbProvider = DbProviderFactory.GetDbProvider("SybaseAse-15"); + dbProvider.ConnectionString = "Data Source='MARKT60';Port='5000';UID='sa';PWD='';Database='pubs2';"; + AdoTemplate adoTemplate = new AdoTemplate(dbProvider); + IDbParameters parameters = new DbParameters(dbProvider); + parameters.Add("inParam", AseDbType.VarChar, 32).Value = "mango"; + parameters.AddInOut("inoutParam", AseDbType.VarChar, 64).Value = "Sybase"; + parameters.AddOut("outParam", AseDbType.VarChar, 64); + parameters.AddReturn("retValue", AseDbType.Integer); + adoTemplate.ExecuteNonQuery(CommandType.StoredProcedure, "sp_hello", parameters); + + + Assert.AreEqual("Go Sybase", parameters["@inoutParam"].Value); + Assert.AreEqual("Hello mango", parameters[2].Value); + Assert.AreEqual(101, (int) parameters[3].Value); } - } */ - public class EmpProc : StoredProcedure + [Test] + [Ignore("SYBASE-ASE-dependent tests disabled for integration runs")] + public void DeriveParams() { - public EmpProc(IDbProvider provider) - : base(provider, "TEST.Get1CurOut") + IDbProvider dbProvider = DbProviderFactory.GetDbProvider("SybaseAse-15"); + dbProvider.ConnectionString = "Data Source='MARKT60';Port='5000';UID='sa';PWD='';Database='pubs2';"; + AdoTemplate adoTemplate = new AdoTemplate(dbProvider); + IDataParameter[] derivedParameters = adoTemplate.DeriveParameters("@sp_hello", true); + if (derivedParameters.Length == 0) { - //DeriveParameters(); - DeclaredParameters.AddOut("P_CURSOR1", OracleType.Cursor); - AddRowMapper("employees", new EmployeeRowMapper()); - Compile(); + Console.WriteLine("Derived Parameters = 0!!!!"); } - public IDictionary GetEmployees() + for (int i = 0; i < derivedParameters.Length; i++) { - for (int i = 0; i < DeclaredParameters.Count; i++) + Console.WriteLine("Parameter " + i + ", Name = " + derivedParameters[i].ParameterName + ", Value = " + + derivedParameters[i].Value); + } + } + + /* + [Test] + public void RawDeriveParams() { - Console.WriteLine("decarled parameter name = " + DeclaredParameters[i].ParameterName + ", type = " + DeclaredParameters[i].DbType); + using ( + AseConnection conn = + new AseConnection("Data Source='MARKT60';Port='5000';UID='sa';PWD='';Database='pubs2';")) + { + using (AseCommand cmd = new AseCommand("@sp_hello", conn)) + { + conn.Open(); + cmd.CommandType = CommandType.StoredProcedure; + AseCommandBuilder.DeriveParameters(cmd); + Console.WriteLine("Number of parameters = " + cmd.Parameters.Count); + } + } } - return Query(); - } + */ + [Test] + [Ignore("SYBASE-ASE-dependent tests disabled for integration runs")] + public void QueryWithMapper() + { + IDbProvider dbProvider = DbProviderFactory.GetDbProvider("SybaseAse-15"); + dbProvider.ConnectionString = "Data Source='MARKT60';Port='5000';UID='sa';PWD='';Database='pubs2';"; + PubDao pubDao = new PubDao(dbProvider); + IList sales = pubDao.GetSales("5023"); + Assert.AreEqual(50, sales.Count); } - internal class EmployeeRowMapper : IRowMapper + [Test] + [Ignore("ODBC-dependent tests disabled for integration runs")] + public void QueryWithMapperODBC() { - public object MapRow(IDataReader reader, int rowNum) - { - Employee emp = new Employee(); - emp.Number = reader.GetDecimal(0); - emp.Name = reader.GetString(1); - return emp; - } + IDbProvider dbProvider = DbProviderFactory.GetDbProvider("Odbc-2.0"); + dbProvider.ConnectionString = + "Driver={Adaptive Server Enterprise};server=MARKT60;port=5000;Database=pubs2;uid=sa;pwd=;"; + PubDao pubDao = new PubDao(dbProvider); + IList sales = pubDao.GetSales("5023"); + Assert.AreEqual(50, sales.Count); } - internal class Employee + [Test] + [Ignore("SYBASE-ASE-dependent tests disabled for integration runs")] + public void QueryRawODBC() { - private decimal number; - private string name; - - public decimal Number + using ( + OdbcConnection conn = + new OdbcConnection( + "Driver={Adaptive Server Enterprise};server=MARKT60;port=5000;Database=pubs2;uid=sa;pwd=;")) { - get { return number; } - set { number = value; } - } + using (OdbcCommand cmd = new OdbcCommand("history_proc @stor_id", conn)) + { + conn.Open(); + cmd.CommandType = CommandType.StoredProcedure; + cmd.Parameters.Add("stor_id", OdbcType.NVarChar).Value = "5023"; + int i = 0; + using (IDataReader reader = cmd.ExecuteReader()) + { + while (reader.Read()) + { + i++; + } + } - public string Name - { - get { return name; } - set { name = value; } - } - - public override string ToString() - { - return "Number = " + number + ", Name = " + name; + Assert.AreEqual(50, i); + } } } } + +public class PubDao : AdoDaoSupport +{ + public PubDao(IDbProvider provider) + { + DbProvider = provider; + } + + public IList GetSales(string storeId) + { + return AdoTemplate.QueryWithRowMapperDelegate(CommandType.StoredProcedure, "history_proc", + delegate(IDataReader dataReader, int rowNum) + { + Sale sale = new Sale(); + sale.Date = dataReader.GetDateTime(0); + sale.OrderNumber = dataReader.GetString(1); + sale.Quantity = dataReader.GetInt32(2); + sale.Title = dataReader.GetString(3); + sale.Discount = dataReader.GetFloat(4); + sale.Price = dataReader.GetFloat(5); + sale.Total = dataReader.GetFloat(6); + return sale; + }, "stor_id", + DbType.String, 0, storeId); + } +} + +public class Sale +{ + private DateTime date; + private string orderNumber; + private int quantity; + private string title; + private float discount; + private float price; + private float total; + + public DateTime Date + { + get { return date; } + set { date = value; } + } + + public float Discount + { + get { return discount; } + set { discount = value; } + } + + public string OrderNumber + { + get { return orderNumber; } + set { orderNumber = value; } + } + + public int Quantity + { + get { return quantity; } + set { quantity = value; } + } + + public string Title + { + get { return title; } + set { title = value; } + } + + public float Price + { + get { return price; } + set { price = value; } + } + + public float Total + { + get { return total; } + set { total = value; } + } +} + +/* + public class HelloProc : StoredProcedure + { + public HelloProc(IDbProvider provider) : base(provider, "sp_hello") + { + DeclaredParameters.Add("inParam", AseDbType.VarChar, 32).Value = "mango"; + DeclaredParameters.AddInOut("inoutParam", AseDbType.VarChar, 64).Value = "Sybase"; + DeclaredParameters.AddOut("outParam", AseDbType.VarChar, 64); + DeclaredParameters.AddReturn("retValue", AseDbType.Integer); + Compile(); + } + + public IDictionary GetResults() + { + return Query("mango", "Sybase"); + } + } +*/ +public class EmpProc : StoredProcedure +{ + public EmpProc(IDbProvider provider) + : base(provider, "TEST.Get1CurOut") + { + //DeriveParameters(); + DeclaredParameters.AddOut("P_CURSOR1", OracleType.Cursor); + AddRowMapper("employees", new EmployeeRowMapper()); + Compile(); + } + + public IDictionary GetEmployees() + { + for (int i = 0; i < DeclaredParameters.Count; i++) + { + Console.WriteLine("decarled parameter name = " + DeclaredParameters[i].ParameterName + ", type = " + DeclaredParameters[i].DbType); + } + + return Query(); + } +} + +internal class EmployeeRowMapper : IRowMapper +{ + public object MapRow(IDataReader reader, int rowNum) + { + Employee emp = new Employee(); + emp.Number = reader.GetDecimal(0); + emp.Name = reader.GetString(1); + return emp; + } +} + +internal class Employee +{ + private decimal number; + private string name; + + public decimal Number + { + get { return number; } + set { number = value; } + } + + public string Name + { + get { return name; } + set { name = value; } + } + + public override string ToString() + { + return "Number = " + number + ", Name = " + name; + } +} \ No newline at end of file diff --git a/test/Spring/Spring.Data.Integration.Tests/Data/SimpleAccountCreditDao.cs b/test/Spring/Spring.Data.Integration.Tests/Data/SimpleAccountCreditDao.cs index ccf59cc0..e268a3eb 100644 --- a/test/Spring/Spring.Data.Integration.Tests/Data/SimpleAccountCreditDao.cs +++ b/test/Spring/Spring.Data.Integration.Tests/Data/SimpleAccountCreditDao.cs @@ -1,35 +1,32 @@ using System.Data; using Spring.Data.Core; -namespace Spring.Data +namespace Spring.Data; + +public class SimpleAccountCreditDao : AdoDaoSupport { - public class SimpleAccountCreditDao : AdoDaoSupport + public SimpleAccountCreditDao() { - - public SimpleAccountCreditDao() - { - } - - /// - /// Insert into the credits table a credit amount - /// - /// - /// Note that this method is not declared as virtual since - /// the transaction demarcation is done in the SimpleAccountManager - /// class and does not need to have a transactional proxy created for - /// it. If one was not using a higher level class to - /// demarcate transactions and instead wanted to demarcate at the DAO - /// directly, the method would be declared as virtual and the - /// transaction attributes (or corresponding XML declarations) would - /// be applied to this method. - /// - /// the credit amount - public void CreateCredit(float creditAmount) - { - AdoTemplate.ExecuteNonQuery(CommandType.Text, - String.Format("insert into Credits(creditAmount) VALUES ({0})", - creditAmount)); - } + } + /// + /// Insert into the credits table a credit amount + /// + /// + /// Note that this method is not declared as virtual since + /// the transaction demarcation is done in the SimpleAccountManager + /// class and does not need to have a transactional proxy created for + /// it. If one was not using a higher level class to + /// demarcate transactions and instead wanted to demarcate at the DAO + /// directly, the method would be declared as virtual and the + /// transaction attributes (or corresponding XML declarations) would + /// be applied to this method. + /// + /// the credit amount + public void CreateCredit(float creditAmount) + { + AdoTemplate.ExecuteNonQuery(CommandType.Text, + String.Format("insert into Credits(creditAmount) VALUES ({0})", + creditAmount)); } } diff --git a/test/Spring/Spring.Data.Integration.Tests/Data/SimpleAccountDebitDao.cs b/test/Spring/Spring.Data.Integration.Tests/Data/SimpleAccountDebitDao.cs index 3b4b71af..eba5db87 100644 --- a/test/Spring/Spring.Data.Integration.Tests/Data/SimpleAccountDebitDao.cs +++ b/test/Spring/Spring.Data.Integration.Tests/Data/SimpleAccountDebitDao.cs @@ -1,35 +1,31 @@ using System.Data; using Spring.Data.Core; -namespace Spring.Data +namespace Spring.Data; + +public class SimpleAccountDebitDao : AdoDaoSupport { - public class SimpleAccountDebitDao : AdoDaoSupport + public SimpleAccountDebitDao() { + } - public SimpleAccountDebitDao() - { - } - - /// - /// Insert into the debits table a debit amount - /// - /// - /// Note that this method is not declared as virtual since - /// the transaction demarcation is done in the SimpleAccountManager - /// class and does not need to have a transactional proxy created for - /// it. If one was not using a higher level class to - /// demarcate transactions and instead wanted to demarcate at the DAO - /// directly, the method would be declared as virtual and the - /// transaction attributes (or corresponding XML declarations) would - /// be applied to this method. - /// - /// the debit amount - public void DebitAccount(float debitAmount) - { - AdoTemplate.ExecuteNonQuery(CommandType.Text, String.Format("insert into dbo.Debits (DebitAmount) VALUES ({0})", - debitAmount)); - } - - + /// + /// Insert into the debits table a debit amount + /// + /// + /// Note that this method is not declared as virtual since + /// the transaction demarcation is done in the SimpleAccountManager + /// class and does not need to have a transactional proxy created for + /// it. If one was not using a higher level class to + /// demarcate transactions and instead wanted to demarcate at the DAO + /// directly, the method would be declared as virtual and the + /// transaction attributes (or corresponding XML declarations) would + /// be applied to this method. + /// + /// the debit amount + public void DebitAccount(float debitAmount) + { + AdoTemplate.ExecuteNonQuery(CommandType.Text, String.Format("insert into dbo.Debits (DebitAmount) VALUES ({0})", + debitAmount)); } } diff --git a/test/Spring/Spring.Data.Integration.Tests/Data/SimpleAccountManager.cs b/test/Spring/Spring.Data.Integration.Tests/Data/SimpleAccountManager.cs index 23544c7a..cfb5f80a 100644 --- a/test/Spring/Spring.Data.Integration.Tests/Data/SimpleAccountManager.cs +++ b/test/Spring/Spring.Data.Integration.Tests/Data/SimpleAccountManager.cs @@ -1,48 +1,42 @@ - using Spring.Transaction.Interceptor; -namespace Spring.Data +namespace Spring.Data; + +public class SimpleAccountManager { - - public class SimpleAccountManager + private SimpleAccountCreditDao creditDao; + private SimpleAccountDebitDao debitDao; + + public SimpleAccountManager() { - private SimpleAccountCreditDao creditDao; - private SimpleAccountDebitDao debitDao; - - public SimpleAccountManager() - { - } - - public SimpleAccountCreditDao AccountCreditDao - { - get { return creditDao; } - set { creditDao = value; } - } - - public SimpleAccountDebitDao AccountDebitDao - { - get { return debitDao; } - set { debitDao = value; } - } - - /// - /// Transfer money, performing both credit and debit database operations - /// within one transaction. - /// - /// - /// The method is marked as virtual so that a transactional AOP proxy - /// can be created for it. - /// - /// the credit amount. - /// the debit amount. - [Transaction()] - public virtual void DoTransfer(float creditAmount, float debitAmount) - { - creditDao.CreateCredit(creditAmount); - debitDao.DebitAccount(debitAmount); - } - } + public SimpleAccountCreditDao AccountCreditDao + { + get { return creditDao; } + set { creditDao = value; } + } + public SimpleAccountDebitDao AccountDebitDao + { + get { return debitDao; } + set { debitDao = value; } + } + + /// + /// Transfer money, performing both credit and debit database operations + /// within one transaction. + /// + /// + /// The method is marked as virtual so that a transactional AOP proxy + /// can be created for it. + /// + /// the credit amount. + /// the debit amount. + [Transaction()] + public virtual void DoTransfer(float creditAmount, float debitAmount) + { + creditDao.CreateCredit(creditAmount); + debitDao.DebitAccount(debitAmount); + } } diff --git a/test/Spring/Spring.Data.Integration.Tests/Data/Spring.Data.Integration.Tests_CreditsAndDebits_database.sql b/test/Spring/Spring.Data.Integration.Tests/Data/Spring.Data.Integration.Tests_CreditsAndDebits_database.sql index b0ade120..078ed39c 100644 Binary files a/test/Spring/Spring.Data.Integration.Tests/Data/Spring.Data.Integration.Tests_CreditsAndDebits_database.sql and b/test/Spring/Spring.Data.Integration.Tests/Data/Spring.Data.Integration.Tests_CreditsAndDebits_database.sql differ diff --git a/test/Spring/Spring.Data.Integration.Tests/Data/Spring.Data.Integration.Tests_Credits_database.sql b/test/Spring/Spring.Data.Integration.Tests/Data/Spring.Data.Integration.Tests_Credits_database.sql index cdd7dffe..a056f117 100644 Binary files a/test/Spring/Spring.Data.Integration.Tests/Data/Spring.Data.Integration.Tests_Credits_database.sql and b/test/Spring/Spring.Data.Integration.Tests/Data/Spring.Data.Integration.Tests_Credits_database.sql differ diff --git a/test/Spring/Spring.Data.Integration.Tests/Data/Spring.Data.Integration.Tests_Debits_database.sql b/test/Spring/Spring.Data.Integration.Tests/Data/Spring.Data.Integration.Tests_Debits_database.sql index 5c7b2e6f..7a831901 100644 Binary files a/test/Spring/Spring.Data.Integration.Tests/Data/Spring.Data.Integration.Tests_Debits_database.sql and b/test/Spring/Spring.Data.Integration.Tests/Data/Spring.Data.Integration.Tests_Debits_database.sql differ diff --git a/test/Spring/Spring.Data.Integration.Tests/Data/Spring.Data.Integration.Tests_Spring_database.sql b/test/Spring/Spring.Data.Integration.Tests/Data/Spring.Data.Integration.Tests_Spring_database.sql index c5464272..ec8f916c 100644 Binary files a/test/Spring/Spring.Data.Integration.Tests/Data/Spring.Data.Integration.Tests_Spring_database.sql and b/test/Spring/Spring.Data.Integration.Tests/Data/Spring.Data.Integration.Tests_Spring_database.sql differ diff --git a/test/Spring/Spring.Data.Integration.Tests/Data/StoredProcedureTests.cs b/test/Spring/Spring.Data.Integration.Tests/Data/StoredProcedureTests.cs index 0c4a97e6..247e9837 100644 --- a/test/Spring/Spring.Data.Integration.Tests/Data/StoredProcedureTests.cs +++ b/test/Spring/Spring.Data.Integration.Tests/Data/StoredProcedureTests.cs @@ -2,13 +2,13 @@ /* * Copyright � 2002-2011 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. @@ -30,100 +30,96 @@ using Spring.Data.Core; #endregion -namespace Spring.Data +namespace Spring.Data; + +/// +/// Integration tests for StoredProcedure support. +/// +/// Mark Pollack (.NET) +[TestFixture] +public class StoredProcedureTests { - /// - /// Integration tests for StoredProcedure support. - /// - /// Mark Pollack (.NET) - [TestFixture] - public class StoredProcedureTests - { - - #region Fields - - IAdoOperations adoOperations; - IDbProvider dbProvider; - - #endregion - - [SetUp] - public void CreateAdoTemplate() - { - IApplicationContext ctx = - new XmlApplicationContext("assembly://Spring.Data.Integration.Tests/Spring.Data/adoTemplateTests.xml"); - Assert.IsNotNull(ctx); - dbProvider = ctx["DbProvider"] as IDbProvider; - Assert.IsNotNull(dbProvider); - adoOperations = new AdoTemplate(dbProvider); - - } - - [Test] - public void ExecuteNonQueryTest() - { - CallCreateTestObject createTestObjectProcedure = - new CallCreateTestObject(dbProvider); - - createTestObjectProcedure.Create("Gabriel", 1); - } + #region Fields - [Test] - public void OutParamTest() - { - TestObjectStoredProcedure sproc = new TestObjectStoredProcedure(dbProvider); - IDbParameters parameters = sproc.DeclaredParameters; - Console.WriteLine("\n\n\n"); - for (int i = 0; i < parameters.Count; i++) - { - Console.WriteLine("- Declared Parameter " + parameters[i].ParameterName); - } - IDictionary results = sproc.GetResults("George"); - foreach (DictionaryEntry entry in results) - { - Console.WriteLine(entry.Key + - ", " + entry.Value); - } + IAdoOperations adoOperations; + IDbProvider dbProvider; - IDictionary inParams = new Hashtable(); - inParams.Add("@Name", "George"); - results = sproc.GetResultsUsingInDictionary(inParams); - Console.WriteLine("\n\n\n"); - foreach (DictionaryEntry entry in results) - { - Console.WriteLine(entry.Key + - ", " + entry.Value); - } + #endregion - } - - [Test] - public void OutReturnValueTestWithAdoTemplate() - { - IDbParameters parameters = adoOperations.CreateDbParameters(); - parameters.AddOut("Count", DbType.Int32); - parameters.AddReturn("RETURN_VALUE", DbType.Int32); - parameters.AddWithValue("Name", "George"); - IList queryResults = adoOperations.QueryWithRowMapper(CommandType.StoredProcedure, "SelectByNameWithReturnAndOutValue", - new SimpleRowMapper(), - parameters); - for (int i = 0; i < parameters.Count;i++ ) - { - Console.WriteLine("parameter " + i - + " name = " + parameters[i].ParameterName - + " value = " + parameters[i].Value); - } - // Console.WriteLine("out parameter 'count' = " + parameters["count"]); - //Console.WriteLine("RETURN_VALE = " + parameters["RETURN_VALUE"]); - - } - } - - internal class SimpleRowMapper : IRowMapper + [SetUp] + public void CreateAdoTemplate() { - public object MapRow(IDataReader reader, int rowNum) + IApplicationContext ctx = + new XmlApplicationContext("assembly://Spring.Data.Integration.Tests/Spring.Data/adoTemplateTests.xml"); + Assert.IsNotNull(ctx); + dbProvider = ctx["DbProvider"] as IDbProvider; + Assert.IsNotNull(dbProvider); + adoOperations = new AdoTemplate(dbProvider); + } + + [Test] + public void ExecuteNonQueryTest() + { + CallCreateTestObject createTestObjectProcedure = + new CallCreateTestObject(dbProvider); + + createTestObjectProcedure.Create("Gabriel", 1); + } + + [Test] + public void OutParamTest() + { + TestObjectStoredProcedure sproc = new TestObjectStoredProcedure(dbProvider); + IDbParameters parameters = sproc.DeclaredParameters; + Console.WriteLine("\n\n\n"); + for (int i = 0; i < parameters.Count; i++) { - return "hello"; + Console.WriteLine("- Declared Parameter " + parameters[i].ParameterName); + } + + IDictionary results = sproc.GetResults("George"); + foreach (DictionaryEntry entry in results) + { + Console.WriteLine(entry.Key + + ", " + entry.Value); + } + + IDictionary inParams = new Hashtable(); + inParams.Add("@Name", "George"); + results = sproc.GetResultsUsingInDictionary(inParams); + Console.WriteLine("\n\n\n"); + foreach (DictionaryEntry entry in results) + { + Console.WriteLine(entry.Key + + ", " + entry.Value); } } + + [Test] + public void OutReturnValueTestWithAdoTemplate() + { + IDbParameters parameters = adoOperations.CreateDbParameters(); + parameters.AddOut("Count", DbType.Int32); + parameters.AddReturn("RETURN_VALUE", DbType.Int32); + parameters.AddWithValue("Name", "George"); + IList queryResults = adoOperations.QueryWithRowMapper(CommandType.StoredProcedure, "SelectByNameWithReturnAndOutValue", + new SimpleRowMapper(), + parameters); + for (int i = 0; i < parameters.Count; i++) + { + Console.WriteLine("parameter " + i + + " name = " + parameters[i].ParameterName + + " value = " + parameters[i].Value); + } + // Console.WriteLine("out parameter 'count' = " + parameters["count"]); + //Console.WriteLine("RETURN_VALE = " + parameters["RETURN_VALUE"]); + } +} + +internal class SimpleRowMapper : IRowMapper +{ + public object MapRow(IDataReader reader, int rowNum) + { + return "hello"; + } } diff --git a/test/Spring/Spring.Data.Integration.Tests/Data/Support/SimpleExceptionTranslationTests.cs b/test/Spring/Spring.Data.Integration.Tests/Data/Support/SimpleExceptionTranslationTests.cs index 64c6464a..3838d79c 100644 --- a/test/Spring/Spring.Data.Integration.Tests/Data/Support/SimpleExceptionTranslationTests.cs +++ b/test/Spring/Spring.Data.Integration.Tests/Data/Support/SimpleExceptionTranslationTests.cs @@ -2,13 +2,13 @@ /* * Copyright � 2002-2011 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. @@ -30,61 +30,59 @@ using Spring.Data.Core; #endregion -namespace Spring.Data.Support +namespace Spring.Data.Support; + +[TestFixture] +public class SimpleExceptionTranslationTests { - [TestFixture] - public class SimpleExceptionTranslationTests + #region Fields + + private IDbProvider dbProvider; + private IAdoOperations adoOperations; + + #endregion + + #region Constants + + /// + /// The shared ILog instance for this class (and derived classes). + /// + protected static readonly ILog log = LogManager.GetLogger(); + + #endregion + + #region Methods + + [SetUp] + public void CreateAdoTemplate() { - #region Fields - private IDbProvider dbProvider; - private IAdoOperations adoOperations; - #endregion - - #region Constants - - /// - /// The shared ILog instance for this class (and derived classes). - /// - protected static readonly ILog log = LogManager.GetLogger(); - - #endregion - - #region Methods - - [SetUp] - public void CreateAdoTemplate() - { - IApplicationContext ctx = - new XmlApplicationContext("assembly://Spring.Data.Integration.Tests/Spring.Data/adoTemplateTests.xml"); - Assert.IsNotNull(ctx); - dbProvider = ctx["DbProvider"] as IDbProvider; - Assert.IsNotNull(dbProvider); - adoOperations = new AdoTemplate(dbProvider); - } - - [Test] - public void ExecuteNonQueryText() - { - - string badSql = "insert into TestObjects(Age, Name) VALS (33, 'foo')"; - try - { - adoOperations.ExecuteNonQuery(CommandType.Text, badSql); - } - catch (BadSqlGrammarException e) - { - - log.LogError(e, "caught correct exception"); - } - catch (Exception e) - { - log.LogError(e, "caught incorrect exception "); - - Assert.Fail("did not throw exception of type BadSqlGrammerException"); - } - - } - #endregion - + IApplicationContext ctx = + new XmlApplicationContext("assembly://Spring.Data.Integration.Tests/Spring.Data/adoTemplateTests.xml"); + Assert.IsNotNull(ctx); + dbProvider = ctx["DbProvider"] as IDbProvider; + Assert.IsNotNull(dbProvider); + adoOperations = new AdoTemplate(dbProvider); } + + [Test] + public void ExecuteNonQueryText() + { + string badSql = "insert into TestObjects(Age, Name) VALS (33, 'foo')"; + try + { + adoOperations.ExecuteNonQuery(CommandType.Text, badSql); + } + catch (BadSqlGrammarException e) + { + log.LogError(e, "caught correct exception"); + } + catch (Exception e) + { + log.LogError(e, "caught incorrect exception "); + + Assert.Fail("did not throw exception of type BadSqlGrammerException"); + } + } + + #endregion } diff --git a/test/Spring/Spring.Data.Integration.Tests/Data/TestCoordinator.cs b/test/Spring/Spring.Data.Integration.Tests/Data/TestCoordinator.cs index 71a83c1d..8e2d5767 100644 --- a/test/Spring/Spring.Data.Integration.Tests/Data/TestCoordinator.cs +++ b/test/Spring/Spring.Data.Integration.Tests/Data/TestCoordinator.cs @@ -1,27 +1,23 @@ - - using Spring.Objects; -namespace Spring.Data +namespace Spring.Data; + +public class TestCoordinator : ITestCoordinator { - public class TestCoordinator : ITestCoordinator + private ITestObjectManager testObjectManager; + + public ITestObjectManager TestObjectManager { - private ITestObjectManager testObjectManager; - - - public ITestObjectManager TestObjectManager - { - get { return testObjectManager; } - set { testObjectManager = value; } - } - - #region ITestCoordinator Members - - public void WorkOn(TestObject to1, TestObject to2) - { - testObjectManager.SaveTwoTestObjects(to1,to2); - } - - #endregion + get { return testObjectManager; } + set { testObjectManager = value; } } + + #region ITestCoordinator Members + + public void WorkOn(TestObject to1, TestObject to2) + { + testObjectManager.SaveTwoTestObjects(to1, to2); + } + + #endregion } diff --git a/test/Spring/Spring.Data.Integration.Tests/Data/TestObjectDao.cs b/test/Spring/Spring.Data.Integration.Tests/Data/TestObjectDao.cs index 42d4693f..80931b09 100644 --- a/test/Spring/Spring.Data.Integration.Tests/Data/TestObjectDao.cs +++ b/test/Spring/Spring.Data.Integration.Tests/Data/TestObjectDao.cs @@ -4,150 +4,143 @@ using Spring.Data.Common; using Spring.Data.Core; using Spring.Objects; -namespace Spring.Data +namespace Spring.Data; + +/// +/// AdoTemplate based implementation of ITestObjectDao data access layer. +/// +public class TestObjectDao : AdoDaoSupport, ITestObjectDao { - /// - /// AdoTemplate based implementation of ITestObjectDao data access layer. - /// - public class TestObjectDao : AdoDaoSupport, ITestObjectDao - { - - public void Create(string name, int age) - { - AdoTemplate.ExecuteNonQuery(CommandType.Text, - String.Format("insert into TestObjects(Age, Name) VALUES ({0}, '{1}')", + public void Create(string name, int age) + { + AdoTemplate.ExecuteNonQuery(CommandType.Text, + String.Format("insert into TestObjects(Age, Name) VALUES ({0}, '{1}')", age, name)); - } + } - public void Update(TestObject to) - { - AdoTemplate.ExecuteNonQuery(CommandType.Text, - String.Format("UPDATE TestObjects SET Age={0}, Name='{1}' where TestObjectNo = {2}", + public void Update(TestObject to) + { + AdoTemplate.ExecuteNonQuery(CommandType.Text, + String.Format("UPDATE TestObjects SET Age={0}, Name='{1}' where TestObjectNo = {2}", to.Age, to.Name, to.ObjectNumber)); - } + } - public void Delete(string name) - { - AdoTemplate.ExecuteNonQuery(CommandType.Text, - String.Format("delete from TestObjects where Name = '{0}'", + public void Delete(string name) + { + AdoTemplate.ExecuteNonQuery(CommandType.Text, + String.Format("delete from TestObjects where Name = '{0}'", name)); - } + } - public TestObject FindByName(string name) + public TestObject FindByName(string name) + { + IList toList = AdoTemplate.QueryWithRowMapper(CommandType.Text, + "select TestObjectNo, Age, Name from TestObjects where Name='" + name + "'", + new TestObjectRowMapper()); + if (toList.Count > 0) { - IList toList = AdoTemplate.QueryWithRowMapper(CommandType.Text, - "select TestObjectNo, Age, Name from TestObjects where Name='"+name+"'", - new TestObjectRowMapper()); - if (toList.Count > 0) - { - return (TestObject)toList[0]; - } - else - { - return null; - } + return (TestObject) toList[0]; } - - public IList FindAll() + else { - return AdoTemplate.QueryWithRowMapper(CommandType.Text, - "select TestObjectNo, Age, Name from TestObjects", - new TestObjectRowMapper()); - } - - public int GetCount() - { - return (int)AdoTemplate.ExecuteScalar(CommandType.Text, "SELECT COUNT(*) FROM TestObjects"); - } - - public int GetCountByDelegate() - { - - return (int)AdoTemplate.Execute(new CommandDelegate(MyDelegate)); - } - - public int GetCount(int lowerAgeLimit) - { - return (int) AdoTemplate.ExecuteScalar(CommandType.Text, - "SELECT COUNT(*) FROM TestObjects where age > @age","age",DbType.Int32, 0, lowerAgeLimit); - } - - public int GetCount(int lowerAgeLimit, string name) - { - IDbParameters dbParameters = AdoTemplate.CreateDbParameters(); - dbParameters.Add("age", DbType.Int32).Value = lowerAgeLimit; - dbParameters.Add("name", DbType.String).Value = name; - return (int)AdoTemplate.ExecuteScalar(CommandType.Text, "SELECT COUNT(*) FROM TestObjects where age > @age and name = @name", dbParameters); - - } - - public int GetCountByAltMethod(int lowerAgeLimit) - { - return (int)AdoTemplate.ExecuteScalar(CommandType.Text, - "SELECT COUNT(*) FROM TestObjects where age > @age", - "age", DbType.Int32, 0, lowerAgeLimit); - - } - - public int GetCountByCommandSetter(int lowerAgeLimit) - { - return (int) AdoTemplate.ExecuteScalar(CommandType.Text, - "SELECT COUNT(*) FROM TestObjects where age > @age", - new SimpleCommandSetter(lowerAgeLimit)); - } - - private class SimpleCommandSetter : ICommandSetter - { - private int lowerLimit; - public SimpleCommandSetter(int limit) - { - lowerLimit = limit; - } - - public void SetValues(IDbCommand dbCommand) - { - //wouldn't typically set param values this way....intended to set other IDbCommand props - dbCommand.CommandTimeout = 999999; - - IDbDataParameter parameter = dbCommand.CreateParameter(); - parameter.ParameterName = "age"; - parameter.DbType = DbType.Int32; - parameter.Value = lowerLimit; - dbCommand.Parameters.Add(parameter); - } - } - - - private Object MyDelegate(IDbCommand command) - { - command.CommandType = CommandType.Text; - command.CommandText = "SELECT COUNT(*) FROM TestObjects"; - return command.ExecuteScalar(); - } - - - private class TestObjectRowMapper : IRowMapper - { - #region IRowMapper Members - - public object MapRow(IDataReader dataReader, int rowNum) - { - TestObject to = new TestObject(); - to.ObjectNumber = dataReader.GetInt32(0); - to.Age = dataReader.GetInt32(1); - to.Name = dataReader.GetString(2); - return to; - } - - #endregion - - } - - public void Cleanup() - { - AdoTemplate.ExecuteNonQuery(CommandType.Text, "delete from TestObjects "); + return null; } } + + public IList FindAll() + { + return AdoTemplate.QueryWithRowMapper(CommandType.Text, + "select TestObjectNo, Age, Name from TestObjects", + new TestObjectRowMapper()); + } + + public int GetCount() + { + return (int) AdoTemplate.ExecuteScalar(CommandType.Text, "SELECT COUNT(*) FROM TestObjects"); + } + + public int GetCountByDelegate() + { + return (int) AdoTemplate.Execute(new CommandDelegate(MyDelegate)); + } + + public int GetCount(int lowerAgeLimit) + { + return (int) AdoTemplate.ExecuteScalar(CommandType.Text, + "SELECT COUNT(*) FROM TestObjects where age > @age", "age", DbType.Int32, 0, lowerAgeLimit); + } + + public int GetCount(int lowerAgeLimit, string name) + { + IDbParameters dbParameters = AdoTemplate.CreateDbParameters(); + dbParameters.Add("age", DbType.Int32).Value = lowerAgeLimit; + dbParameters.Add("name", DbType.String).Value = name; + return (int) AdoTemplate.ExecuteScalar(CommandType.Text, "SELECT COUNT(*) FROM TestObjects where age > @age and name = @name", dbParameters); + } + + public int GetCountByAltMethod(int lowerAgeLimit) + { + return (int) AdoTemplate.ExecuteScalar(CommandType.Text, + "SELECT COUNT(*) FROM TestObjects where age > @age", + "age", DbType.Int32, 0, lowerAgeLimit); + } + + public int GetCountByCommandSetter(int lowerAgeLimit) + { + return (int) AdoTemplate.ExecuteScalar(CommandType.Text, + "SELECT COUNT(*) FROM TestObjects where age > @age", + new SimpleCommandSetter(lowerAgeLimit)); + } + + private class SimpleCommandSetter : ICommandSetter + { + private int lowerLimit; + + public SimpleCommandSetter(int limit) + { + lowerLimit = limit; + } + + public void SetValues(IDbCommand dbCommand) + { + //wouldn't typically set param values this way....intended to set other IDbCommand props + dbCommand.CommandTimeout = 999999; + + IDbDataParameter parameter = dbCommand.CreateParameter(); + parameter.ParameterName = "age"; + parameter.DbType = DbType.Int32; + parameter.Value = lowerLimit; + dbCommand.Parameters.Add(parameter); + } + } + + private Object MyDelegate(IDbCommand command) + { + command.CommandType = CommandType.Text; + command.CommandText = "SELECT COUNT(*) FROM TestObjects"; + return command.ExecuteScalar(); + } + + private class TestObjectRowMapper : IRowMapper + { + #region IRowMapper Members + + public object MapRow(IDataReader dataReader, int rowNum) + { + TestObject to = new TestObject(); + to.ObjectNumber = dataReader.GetInt32(0); + to.Age = dataReader.GetInt32(1); + to.Name = dataReader.GetString(2); + return to; + } + + #endregion + } + + public void Cleanup() + { + AdoTemplate.ExecuteNonQuery(CommandType.Text, "delete from TestObjects "); + } } diff --git a/test/Spring/Spring.Data.Integration.Tests/Data/TestObjectManager.cs b/test/Spring/Spring.Data.Integration.Tests/Data/TestObjectManager.cs index 27f7f118..b7c13595 100644 --- a/test/Spring/Spring.Data.Integration.Tests/Data/TestObjectManager.cs +++ b/test/Spring/Spring.Data.Integration.Tests/Data/TestObjectManager.cs @@ -2,13 +2,13 @@ /* * Copyright � 2002-2011 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. @@ -28,75 +28,74 @@ using Spring.Transaction.Support; #endregion -namespace Spring.Data +namespace Spring.Data; + +/// +/// Group together multiple ITestObjectDao operations. +/// +/// Mark Pollack (.NET) +public class TestObjectManager : ITestObjectManager { - /// - /// Group together multiple ITestObjectDao operations. - /// - /// Mark Pollack (.NET) - public class TestObjectManager : ITestObjectManager - { - #region Fields - ITestObjectDao testObjectDao; - private static readonly ILogger LOG = LogManager.GetLogger(); - #endregion + #region Fields - #region Constructor (s) - /// - /// Initializes a new instance of the class. - /// - public TestObjectManager() - { + ITestObjectDao testObjectDao; + private static readonly ILogger LOG = LogManager.GetLogger(); - } + #endregion - #endregion + #region Constructor (s) - #region Properties + /// + /// Initializes a new instance of the class. + /// + public TestObjectManager() + { + } - public ITestObjectDao TestObjectDao - { - get { return testObjectDao; } - set { testObjectDao = value; } - } + #endregion - #endregion + #region Properties - #region Methods + public ITestObjectDao TestObjectDao + { + get { return testObjectDao; } + set { testObjectDao = value; } + } - [Transaction] - public void SaveTwoTestObjects(TestObject to1, TestObject to2) + #endregion + + #region Methods + + [Transaction] + public void SaveTwoTestObjects(TestObject to1, TestObject to2) + { + LOG.LogDebug("TransactionActive = " + TransactionSynchronizationManager.ActualTransactionActive); + //Console.WriteLine("TransactionSynchronizationManager.CurrentTransactionIsolationLevel = " + + // TransactionSynchronizationManager.CurrentTransactionIsolationLevel); + //Console.WriteLine("System.Transactions.Transaction.Current.IsolationLevel = " + System.Transactions.Transaction.Current.IsolationLevel); + testObjectDao.Create(to1.Name, to1.Age); + testObjectDao.Create(to2.Name, to2.Age); + } + + [Transaction()] + public void DeleteTwoTestObjects(string name1, string name2) + { + testObjectDao.Delete(name1); + testObjectDao.Delete(name2); + } + + public void DeleteAllTestObjects() + { + IList objects = testObjectDao.FindAll(); + + foreach (object testObject in objects) { - LOG.LogDebug("TransactionActive = " + TransactionSynchronizationManager.ActualTransactionActive); - //Console.WriteLine("TransactionSynchronizationManager.CurrentTransactionIsolationLevel = " + - // TransactionSynchronizationManager.CurrentTransactionIsolationLevel); - //Console.WriteLine("System.Transactions.Transaction.Current.IsolationLevel = " + System.Transactions.Transaction.Current.IsolationLevel); - testObjectDao.Create(to1.Name, to1.Age); - testObjectDao.Create(to2.Name, to2.Age); + if (testObject is ITestObject) + { + testObjectDao.Delete(((ITestObject) testObject).Name); + } } + } - [Transaction()] - public void DeleteTwoTestObjects(string name1, string name2) - { - testObjectDao.Delete(name1); - testObjectDao.Delete(name2); - } - - public void DeleteAllTestObjects() - { - IList objects = testObjectDao.FindAll(); - - foreach (object testObject in objects) - { - if (testObject is ITestObject) - { - testObjectDao.Delete(((ITestObject)testObject).Name); - } - } - } - - #endregion - } - - -} + #endregion +} \ No newline at end of file diff --git a/test/Spring/Spring.Data.Integration.Tests/Data/TestObjectQuery.cs b/test/Spring/Spring.Data.Integration.Tests/Data/TestObjectQuery.cs index e6e34256..d82bdd28 100644 --- a/test/Spring/Spring.Data.Integration.Tests/Data/TestObjectQuery.cs +++ b/test/Spring/Spring.Data.Integration.Tests/Data/TestObjectQuery.cs @@ -2,13 +2,13 @@ /* * Copyright � 2002-2011 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. @@ -27,38 +27,39 @@ using Spring.Objects; #endregion -namespace Spring.Data +namespace Spring.Data; + +/// +/// Simple MappingAdoQuery implementation +/// +/// Mark Pollack (.NET) +public class TestObjectQuery : MappingAdoQuery { - /// - /// Simple MappingAdoQuery implementation - /// - /// Mark Pollack (.NET) - public class TestObjectQuery : MappingAdoQuery + private static string sql = "select TestObjectNo, Age, Name from TestObjects where Name = @Name"; + + public TestObjectQuery(IDbProvider dbProvider) + : base(dbProvider, sql) { - private static string sql = "select TestObjectNo, Age, Name from TestObjects where Name = @Name"; - - public TestObjectQuery(IDbProvider dbProvider) - : base(dbProvider, sql) + //DeclaredParameters = new DbParameters(dbProvider); + try { - //DeclaredParameters = new DbParameters(dbProvider); - try - { - DeclaredParameters.Add("Name", SqlDbType.VarChar, 50); - } catch (Exception e) - { - Console.WriteLine(e); - } - CommandType = CommandType.Text; - Compile(); + DeclaredParameters.Add("Name", SqlDbType.VarChar, 50); } - - protected override object MapRow(IDataReader reader, int num) - { - TestObject to = new TestObject(); - to.ObjectNumber = reader.GetInt32(0); - to.Age = reader.GetInt32(1); - to.Name = reader.GetString(2); - return to; - } + catch (Exception e) + { + Console.WriteLine(e); + } + + CommandType = CommandType.Text; + Compile(); + } + + protected override object MapRow(IDataReader reader, int num) + { + TestObject to = new TestObject(); + to.ObjectNumber = reader.GetInt32(0); + to.Age = reader.GetInt32(1); + to.Name = reader.GetString(2); + return to; } } diff --git a/test/Spring/Spring.Data.Integration.Tests/Data/TestObjectStoredProcedure.cs b/test/Spring/Spring.Data.Integration.Tests/Data/TestObjectStoredProcedure.cs index 8a0b4fa5..23920dc5 100644 --- a/test/Spring/Spring.Data.Integration.Tests/Data/TestObjectStoredProcedure.cs +++ b/test/Spring/Spring.Data.Integration.Tests/Data/TestObjectStoredProcedure.cs @@ -1,14 +1,14 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. - * + * Copyright � 2002-2011 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. @@ -26,36 +26,31 @@ using Spring.Data.Objects; #endregion -namespace Spring.Data +namespace Spring.Data; + +/// +/// Simple StoredProcedure implementation +/// +/// Mark Pollack (.NET) +public class TestObjectStoredProcedure : StoredProcedure { - /// - /// Simple StoredProcedure implementation - /// - /// Mark Pollack (.NET) - public class TestObjectStoredProcedure : StoredProcedure - { - private static string procedureName = "SelectByNameWithReturnAndOutValue"; - - public TestObjectStoredProcedure(IDbProvider dbProvider) : base(dbProvider, procedureName) - { - //include return value - DeriveParameters(true); - Compile(); - } - - public IDictionary GetResults(string name) - { - //the 100 is for the out parameter that is incorrectly classified as input-output - return Query(name); + private static string procedureName = "SelectByNameWithReturnAndOutValue"; - } + public TestObjectStoredProcedure(IDbProvider dbProvider) : base(dbProvider, procedureName) + { + //include return value + DeriveParameters(true); + Compile(); + } - public IDictionary GetResultsUsingInDictionary(IDictionary inParams) - { - return ExecuteNonQueryByNamedParam(inParams); - } + public IDictionary GetResults(string name) + { + //the 100 is for the out parameter that is incorrectly classified as input-output + return Query(name); + } - - - } + public IDictionary GetResultsUsingInDictionary(IDictionary inParams) + { + return ExecuteNonQueryByNamedParam(inParams); + } } diff --git a/test/Spring/Spring.Data.Integration.Tests/Data/TestTxIsolationLevel.xml b/test/Spring/Spring.Data.Integration.Tests/Data/TestTxIsolationLevel.xml index 9456206b..70d60ceb 100644 --- a/test/Spring/Spring.Data.Integration.Tests/Data/TestTxIsolationLevel.xml +++ b/test/Spring/Spring.Data.Integration.Tests/Data/TestTxIsolationLevel.xml @@ -1,64 +1,64 @@ - + - - - - - - - + + + + + + + - + - - - + + + - - - + + + - - - - - - - - - - + + + - - - - - + + + + + + + + + + + + + + + + + TestObjectManager + + + + + + + - - - - TestObjectManager - - - - - - - - diff --git a/test/Spring/Spring.Data.Integration.Tests/Data/TestTxIsolationLevelTests.cs b/test/Spring/Spring.Data.Integration.Tests/Data/TestTxIsolationLevelTests.cs index 66eb4030..17333bb6 100644 --- a/test/Spring/Spring.Data.Integration.Tests/Data/TestTxIsolationLevelTests.cs +++ b/test/Spring/Spring.Data.Integration.Tests/Data/TestTxIsolationLevelTests.cs @@ -2,13 +2,13 @@ /* * Copyright � 2002-2011 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. @@ -29,61 +29,60 @@ using Spring.Objects; #endregion -namespace Spring.Data -{ - /// - /// Simple exercising of the AdoTemplate - /// - /// Mark Pollack (.NET) - [TestFixture] - public class TestTxIsolationLevelTests - { - //investigate - //1. matching against methods in adotemplate when the pointcut for type should already exclude it? - //2. is isolaiton level applied correctly - // a) TxScope w/ attributes - // b) TxScope w/ xml - // c) ado w/ attriutes - // d) ado w/ xml - private ITestObjectManager testObjectManager; +namespace Spring.Data; - [SetUp] - public void RollbackTestSetup() - { - // WELLKNOWN +/// +/// Simple exercising of the AdoTemplate +/// +/// Mark Pollack (.NET) +[TestFixture] +public class TestTxIsolationLevelTests +{ + //investigate + //1. matching against methods in adotemplate when the pointcut for type should already exclude it? + //2. is isolaiton level applied correctly + // a) TxScope w/ attributes + // b) TxScope w/ xml + // c) ado w/ attriutes + // d) ado w/ xml + private ITestObjectManager testObjectManager; + + [SetUp] + public void RollbackTestSetup() + { + // WELLKNOWN // NamespaceParserRegistry.RegisterParser(typeof (DatabaseNamespaceParser)); // NamespaceParserRegistry.RegisterParser(typeof (TxNamespaceParser)); // NamespaceParserRegistry.RegisterParser(typeof (AopNamespaceParser)); - IApplicationContext ctx = - new XmlApplicationContext( - "assembly://Spring.Data.Integration.Tests/Spring.Data/TestTxIsolationLevel.xml"); - Assert.IsNotNull(ctx); - testObjectManager = ctx["testObjectManager"] as ITestObjectManager; - Assert.IsNotNull(testObjectManager); - } + IApplicationContext ctx = + new XmlApplicationContext( + "assembly://Spring.Data.Integration.Tests/Spring.Data/TestTxIsolationLevel.xml"); + Assert.IsNotNull(ctx); + testObjectManager = ctx["testObjectManager"] as ITestObjectManager; + Assert.IsNotNull(testObjectManager); + } - [Test] - public void DoWork() - { - TestObject to1 = new TestObject("joe", 32); - TestObject to2 = new TestObject("mary", 35); - testObjectManager.SaveTwoTestObjects(to1, to2); - } + [Test] + public void DoWork() + { + TestObject to1 = new TestObject("joe", 32); + TestObject to2 = new TestObject("mary", 35); + testObjectManager.SaveTwoTestObjects(to1, to2); + } - [Test] - public void Dowork2() + [Test] + public void Dowork2() + { + using (TransactionScope txScope = new TransactionScope()) { - using (TransactionScope txScope = new TransactionScope()) + string updateSql2 = "insert into Debits (DebitAmount) VALUES (222)"; + using (SqlConnection cn2005 = new SqlConnection()) { - string updateSql2 = "insert into Debits (DebitAmount) VALUES (222)"; - using (SqlConnection cn2005 = new SqlConnection()) - { - cn2005.ConnectionString = - @"Data Source=SPRINGQA;Initial Catalog=CreditsAndDebits;User ID=springqa; Password=springqa"; - SqlCommand cmd = new SqlCommand(updateSql2, cn2005); - cn2005.Open(); - Console.WriteLine("Isolation level = " + System.Transactions.Transaction.Current.IsolationLevel); - } + cn2005.ConnectionString = + @"Data Source=SPRINGQA;Initial Catalog=CreditsAndDebits;User ID=springqa; Password=springqa"; + SqlCommand cmd = new SqlCommand(updateSql2, cn2005); + cn2005.Open(); + Console.WriteLine("Isolation level = " + System.Transactions.Transaction.Current.IsolationLevel); } } } diff --git a/test/Spring/Spring.Data.Integration.Tests/Data/TransactionTemplateTests.cs b/test/Spring/Spring.Data.Integration.Tests/Data/TransactionTemplateTests.cs index 3f1c7e21..7ac0b6c9 100644 --- a/test/Spring/Spring.Data.Integration.Tests/Data/TransactionTemplateTests.cs +++ b/test/Spring/Spring.Data.Integration.Tests/Data/TransactionTemplateTests.cs @@ -2,13 +2,13 @@ /* * Copyright � 2002-2011 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. @@ -32,207 +32,202 @@ using Spring.Transaction.Support; #endregion -namespace Spring.Data -{ - /// - /// Integration tests for transaction template functionality - /// - /// Mark Pollack - [TestFixture] - public class TransactionTemplateTests - { +namespace Spring.Data; +/// +/// Integration tests for transaction template functionality +/// +/// Mark Pollack +[TestFixture] +public class TransactionTemplateTests +{ + private IDbProvider dbProvider; + + private IPlatformTransactionManager transactionManager; + + private IApplicationContext ctx; + + private IAdoOperations adoOperations; + + [SetUp] + public void SetUp() + { + ctx = + new XmlApplicationContext("assembly://Spring.Data.Integration.Tests/Spring.Data/templateTests.xml"); + dbProvider = ctx["DbProvider"] as IDbProvider; + transactionManager = ctx["transactionManager"] as IPlatformTransactionManager; + adoOperations = ctx["adoTemplate"] as IAdoOperations; + + ITestObjectManager testObjectManager = ctx["testObjectManager"] as ITestObjectManager; + testObjectManager.DeleteAllTestObjects(); + testObjectManager.SaveTwoTestObjects(new TestObject("Jack", 10), new TestObject("Jill", 20)); + } + + [TearDown] + public void TearDown() + { + ITestObjectManager testObjectManager = ctx["testObjectManager"] as ITestObjectManager; + testObjectManager.DeleteTwoTestObjects("Jack", "Jill"); + testObjectManager.DeleteAllTestObjects(); + } + + /// + /// Test using ObjectNameAutoProxyCreator for declarative tx mgmt. + /// + /// Note asserts to not actually check if same tx is used + /// for the multiple save and delete operations in TestObjectManager. + /// Useful for stepping through w/ debugger. + /// + [Test] + public void DeclarativeViaAutoProxyCreator() + { + ITestObjectManager mgr = ctx["testObjectManager"] as ITestObjectManager; + TestObjectDao dao = (TestObjectDao) ctx["testObjectDao"]; + PerformOperations(mgr, dao); + } + + /// + /// Test using TransactionProxyFactoryObject for declarative tx mgmt. + /// + /// Note asserts to not actually check if same tx is used + /// for the multiple save and delete operations in TestObjectManager. + /// Useful for stepping through w/ debugger. + /// + [Test] + public void DeclarativeViaTransactionProxyFactoryObject() + { + ITestObjectManager mgr = ctx["testObjectManagerTP"] as ITestObjectManager; + ITestObjectDao dao = (ITestObjectDao) ctx["testObjectDao"]; + PerformOperations(mgr, dao); + } + + /// + /// Test using ProxyFactory with a transaction interceptor for declarative tx mgmt. + /// + /// Note asserts to not actually check if same tx is used + /// for the multiple save and delete operations in TestObjectManager. + /// Useful for stepping through w/ debugger. + [Test] + public void DeclarativeViaProxyFactoryObject() + { + ITestObjectManager mgr = ctx["testObjectManagerPF"] as ITestObjectManager; + TestObjectDao dao = (TestObjectDao) ctx["testObjectDao"]; + PerformOperations(mgr, dao); + } + + public static void PerformOperations(ITestCoordinator coordinator, ITestObjectDao dao) + { + TestObject to1 = new TestObject(); + to1.Name = "Jack"; + to1.Age = 7; + TestObject to2 = new TestObject(); + to2.Name = "Jill"; + to2.Age = 8; + + coordinator.WorkOn(to1, to2); + + coordinator.TestObjectManager.DeleteTwoTestObjects("Jack", "Jill"); + } + + public static void PerformOperations(ITestObjectManager mgr, + ITestObjectDao dao) + { + Assert.IsNotNull(mgr); + TestObject to1 = new TestObject(); + to1.Name = "Jack"; + to1.Age = 7; + TestObject to2 = new TestObject(); + to2.Name = "Jill"; + to2.Age = 8; + mgr.SaveTwoTestObjects(to1, to2); + + TestObject to = dao.FindByName("Jack"); + Assert.IsNotNull(to); + + to = dao.FindByName("Jill"); + Assert.IsNotNull(to); + Assert.AreEqual("Jill", to.Name); + + mgr.DeleteTwoTestObjects("Jack", "Jill"); + + to = dao.FindByName("Jack"); + Assert.IsNull(to); + + to = dao.FindByName("Jill"); + Assert.IsNull(to); + } + + [Test] + public void ExecuteTemplate() + { + TransactionTemplate tt = new TransactionTemplate(transactionManager); + object result = tt.Execute(new SimpleTransactionCallback(dbProvider)); + Assert.AreEqual(2, (int) result); + } + + [Test] + public void ExecuteTransactionManager() + { + DefaultTransactionDefinition def = new DefaultTransactionDefinition(); + def.PropagationBehavior = TransactionPropagation.Required; + + ITransactionStatus status = transactionManager.GetTransaction(def); + + int iCount = 0; + try + { + iCount = (int) adoOperations.ExecuteScalar(CommandType.Text, "SELECT COUNT(*) FROM TestObjects"); + /* + IAdoCommand cmd = new AdoCommand(dbProvider, CommandType.Text); + cmd.CommandText = "SELECT COUNT(*) FROM TestObjects"; + iCount = (int)cmd.ExecuteScalar(); + */ + + //other AdoCommands can be executed within same tx. + } + catch (Exception) + { + transactionManager.Rollback(status); + throw; + } + + transactionManager.Commit(status); + Assert.AreEqual(2, iCount); + } + + private class SimpleTransactionCallback : ITransactionCallback + { private IDbProvider dbProvider; - private IPlatformTransactionManager transactionManager; - - private IApplicationContext ctx; - - private IAdoOperations adoOperations; - - [SetUp] - public void SetUp() + public SimpleTransactionCallback(IDbProvider dbp) { - ctx = - new XmlApplicationContext("assembly://Spring.Data.Integration.Tests/Spring.Data/templateTests.xml"); - dbProvider = ctx["DbProvider"] as IDbProvider; - transactionManager = ctx["transactionManager"] as IPlatformTransactionManager; - adoOperations = ctx["adoTemplate"] as IAdoOperations; - - ITestObjectManager testObjectManager = ctx["testObjectManager"] as ITestObjectManager; - testObjectManager.DeleteAllTestObjects(); - testObjectManager.SaveTwoTestObjects(new TestObject("Jack", 10), new TestObject("Jill", 20)); - } - - [TearDown] - public void TearDown() - { - ITestObjectManager testObjectManager = ctx["testObjectManager"] as ITestObjectManager; - testObjectManager.DeleteTwoTestObjects("Jack", "Jill"); - testObjectManager.DeleteAllTestObjects(); - } - - - /// - /// Test using ObjectNameAutoProxyCreator for declarative tx mgmt. - /// - /// Note asserts to not actually check if same tx is used - /// for the multiple save and delete operations in TestObjectManager. - /// Useful for stepping through w/ debugger. - /// - [Test] - public void DeclarativeViaAutoProxyCreator() - { - ITestObjectManager mgr = ctx["testObjectManager"] as ITestObjectManager; - TestObjectDao dao = (TestObjectDao)ctx["testObjectDao"]; - PerformOperations(mgr, dao); + dbProvider = dbp; } /// - /// Test using TransactionProxyFactoryObject for declarative tx mgmt. + /// Gets called by TransactionTemplate.Execute within a + /// transaction context. /// - /// Note asserts to not actually check if same tx is used - /// for the multiple save and delete operations in TestObjectManager. - /// Useful for stepping through w/ debugger. - /// - [Test] - public void DeclarativeViaTransactionProxyFactoryObject() + /// The associated transaction status. + /// a result object or null + public object DoInTransaction(ITransactionStatus status) { - ITestObjectManager mgr = ctx["testObjectManagerTP"] as ITestObjectManager; - ITestObjectDao dao = (ITestObjectDao)ctx["testObjectDao"]; - PerformOperations(mgr, dao); + AdoTemplate adoTemplate = new AdoTemplate(dbProvider); + return adoTemplate.Execute(new TestCommandCallback()); } - /// - /// Test using ProxyFactory with a transaction interceptor for declarative tx mgmt. - /// - /// Note asserts to not actually check if same tx is used - /// for the multiple save and delete operations in TestObjectManager. - /// Useful for stepping through w/ debugger. - [Test] - public void DeclarativeViaProxyFactoryObject() + } + + private class TestCommandCallback : ICommandCallback + { + public Object DoInCommand(IDbCommand cmd) { - ITestObjectManager mgr = ctx["testObjectManagerPF"] as ITestObjectManager; - TestObjectDao dao = (TestObjectDao)ctx["testObjectDao"]; - PerformOperations(mgr, dao); + cmd.CommandText = "SELECT COUNT(*) FROM TestObjects"; + int count = (int) cmd.ExecuteScalar(); - } + cmd.CommandText = "SELECT COUNT(*) FROM TestObjects"; + count = (int) cmd.ExecuteScalar(); - public static void PerformOperations(ITestCoordinator coordinator, ITestObjectDao dao) - { - TestObject to1 = new TestObject(); - to1.Name = "Jack"; - to1.Age = 7; - TestObject to2 = new TestObject(); - to2.Name = "Jill"; - to2.Age = 8; - - coordinator.WorkOn(to1, to2); - - coordinator.TestObjectManager.DeleteTwoTestObjects("Jack", "Jill"); - } - - public static void PerformOperations(ITestObjectManager mgr, - ITestObjectDao dao) - { - Assert.IsNotNull(mgr); - TestObject to1 = new TestObject(); - to1.Name = "Jack"; - to1.Age = 7; - TestObject to2 = new TestObject(); - to2.Name = "Jill"; - to2.Age = 8; - mgr.SaveTwoTestObjects(to1, to2); - - TestObject to = dao.FindByName("Jack"); - Assert.IsNotNull(to); - - to = dao.FindByName("Jill"); - Assert.IsNotNull(to); - Assert.AreEqual("Jill", to.Name); - - mgr.DeleteTwoTestObjects("Jack", "Jill"); - - to = dao.FindByName("Jack"); - Assert.IsNull(to); - - to = dao.FindByName("Jill"); - Assert.IsNull(to); - } - - [Test] - public void ExecuteTemplate() - { - TransactionTemplate tt = new TransactionTemplate(transactionManager); - object result = tt.Execute(new SimpleTransactionCallback(dbProvider)); - Assert.AreEqual(2, (int)result); - } - - [Test] - public void ExecuteTransactionManager() - { - DefaultTransactionDefinition def = new DefaultTransactionDefinition(); - def.PropagationBehavior = TransactionPropagation.Required; - - ITransactionStatus status = transactionManager.GetTransaction(def); - - int iCount = 0; - try - { - iCount = (int)adoOperations.ExecuteScalar(CommandType.Text, "SELECT COUNT(*) FROM TestObjects"); - /* - IAdoCommand cmd = new AdoCommand(dbProvider, CommandType.Text); - cmd.CommandText = "SELECT COUNT(*) FROM TestObjects"; - iCount = (int)cmd.ExecuteScalar(); - */ - - //other AdoCommands can be executed within same tx. - } - catch (Exception) - { - transactionManager.Rollback(status); - throw; - } - transactionManager.Commit(status); - Assert.AreEqual(2, iCount); - - } - - - private class SimpleTransactionCallback : ITransactionCallback - { - private IDbProvider dbProvider; - - public SimpleTransactionCallback(IDbProvider dbp) - { - dbProvider = dbp; - } - /// - /// Gets called by TransactionTemplate.Execute within a - /// transaction context. - /// - /// The associated transaction status. - /// a result object or null - public object DoInTransaction(ITransactionStatus status) - { - AdoTemplate adoTemplate = new AdoTemplate(dbProvider); - return adoTemplate.Execute(new TestCommandCallback()); - } - } - - private class TestCommandCallback : ICommandCallback - { - - public Object DoInCommand(IDbCommand cmd) - { - cmd.CommandText = "SELECT COUNT(*) FROM TestObjects"; - int count = (int)cmd.ExecuteScalar(); - - cmd.CommandText = "SELECT COUNT(*) FROM TestObjects"; - count = (int)cmd.ExecuteScalar(); - - return count; - - } + return count; } } } diff --git a/test/Spring/Spring.Data.Integration.Tests/Data/adoTemplateTests.xml b/test/Spring/Spring.Data.Integration.Tests/Data/adoTemplateTests.xml index d66975ef..f6eb6e45 100644 --- a/test/Spring/Spring.Data.Integration.Tests/Data/adoTemplateTests.xml +++ b/test/Spring/Spring.Data.Integration.Tests/Data/adoTemplateTests.xml @@ -3,32 +3,32 @@ xmlns:db="http://www.springframework.net/database"> - - - - - - - + + + + + + + - + - - - + + + - - - + + - - - + + \ No newline at end of file diff --git a/test/Spring/Spring.Data.Integration.Tests/Data/autoDeclarativeServices.xml b/test/Spring/Spring.Data.Integration.Tests/Data/autoDeclarativeServices.xml index 4219bde1..b30297d1 100644 --- a/test/Spring/Spring.Data.Integration.Tests/Data/autoDeclarativeServices.xml +++ b/test/Spring/Spring.Data.Integration.Tests/Data/autoDeclarativeServices.xml @@ -1,33 +1,33 @@ - + - - - - + --> + + + - - + + - + - + - + - - + + - + - - + + - + - + - - - - aroundAdvisor - - + + + + aroundAdvisor + + - - + + - - - - + + + - + - - - - - + + - - - - Spring.Data.TestCoordinator.Work* - - + + + + Spring.Data.TestCoordinator.Work* + + - + diff --git a/test/Spring/Spring.Data.Integration.Tests/Data/declarativeServices.xml b/test/Spring/Spring.Data.Integration.Tests/Data/declarativeServices.xml index 6442a628..9b0e15bc 100644 --- a/test/Spring/Spring.Data.Integration.Tests/Data/declarativeServices.xml +++ b/test/Spring/Spring.Data.Integration.Tests/Data/declarativeServices.xml @@ -1,48 +1,48 @@ - + - - - - - - - + + + + + + + - + - + - + - - - - - + + - + - - - + + Spring.Data.ITestObjectManager transactionInterceptor - - + + - + + type="Spring.Transaction.Interceptor.TransactionAttributeSourceAdvisor, Spring.Data" + autowire="constructor"> - - + + - - + - + - + + type="Spring.Transaction.Interceptor.AttributesTransactionAttributeSource, Spring.Data"> - - + - - + + \ No newline at end of file diff --git a/test/Spring/Spring.Data.Integration.Tests/Data/nativeAdoTests.xml b/test/Spring/Spring.Data.Integration.Tests/Data/nativeAdoTests.xml index 493416cc..190d7c9b 100644 --- a/test/Spring/Spring.Data.Integration.Tests/Data/nativeAdoTests.xml +++ b/test/Spring/Spring.Data.Integration.Tests/Data/nativeAdoTests.xml @@ -1,10 +1,11 @@ - + - - - - + + + + \ No newline at end of file diff --git a/test/Spring/Spring.Data.Integration.Tests/Data/oracleAdoTemplateTests.xml b/test/Spring/Spring.Data.Integration.Tests/Data/oracleAdoTemplateTests.xml index c968500b..6e31e074 100644 --- a/test/Spring/Spring.Data.Integration.Tests/Data/oracleAdoTemplateTests.xml +++ b/test/Spring/Spring.Data.Integration.Tests/Data/oracleAdoTemplateTests.xml @@ -1,17 +1,17 @@ - + - - + + - - - + + - - + + diff --git a/test/Spring/Spring.Data.Integration.Tests/Data/templateTests.xml b/test/Spring/Spring.Data.Integration.Tests/Data/templateTests.xml index 215d3b73..359a4ecc 100644 --- a/test/Spring/Spring.Data.Integration.Tests/Data/templateTests.xml +++ b/test/Spring/Spring.Data.Integration.Tests/Data/templateTests.xml @@ -1,140 +1,137 @@ - + - + - - - - + + + + - - + + - - - + + + - - - - - - - - + + + + + + + + - - - + + - - - + + - - - - - + + - + - - - SetterAndMethodLoggingAdvisor - transactionInterceptor - - - + + + SetterAndMethodLoggingAdvisor + transactionInterceptor + + + - + - - - - + + - + - - - + + - + - + - - + + - + - - - + + Spring.Data.ITestObjectManager transactionInterceptor - - + + - + - - + - + - - - - - - - + + + + + - + - + - - - - \ No newline at end of file diff --git a/test/Spring/Spring.Data.Integration.Tests/ProviderNameSource.cs b/test/Spring/Spring.Data.Integration.Tests/ProviderNameSource.cs index 914b21c4..c4f8fab2 100644 --- a/test/Spring/Spring.Data.Integration.Tests/ProviderNameSource.cs +++ b/test/Spring/Spring.Data.Integration.Tests/ProviderNameSource.cs @@ -24,26 +24,25 @@ using Spring.Objects.Factory.Config; #endregion -namespace Spring -{ - public class ProviderNameSource : IVariableSource - { - public bool CanResolveVariable(string name) - { - return name.ToLower() == "providername"; - } +namespace Spring; - public string ResolveVariable(string name) +public class ProviderNameSource : IVariableSource +{ + public bool CanResolveVariable(string name) + { + return name.ToLower() == "providername"; + } + + public string ResolveVariable(string name) + { + if (name.ToLower() != "providername") { - if (name.ToLower() != "providername") - { - return null; - } + return null; + } #if NETCOREAPP return "SqlServer"; #else - return "SqlServer-2.0"; + return "SqlServer-2.0"; #endif - } } -} \ No newline at end of file +} diff --git a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Config/Log4Net.xml b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Config/Log4Net.xml index cd8bab69..0e77aba1 100644 --- a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Config/Log4Net.xml +++ b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Config/Log4Net.xml @@ -1,64 +1,64 @@  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/AccountController.cs b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/AccountController.cs index 0e73f7d0..97f04b6f 100644 --- a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/AccountController.cs +++ b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/AccountController.cs @@ -14,9 +14,9 @@ namespace Spring.Data.NHibernate public void DoWork() { - accountManager.DoTransfer(30,30); + accountManager.DoTransfer(30, 30); } #endregion } -} \ No newline at end of file +} diff --git a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/AccountCreditDao.cs b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/AccountCreditDao.cs index 92e19a9f..da61f0e5 100644 --- a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/AccountCreditDao.cs +++ b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/AccountCreditDao.cs @@ -11,4 +11,4 @@ namespace Spring.Data.NHibernate HibernateTemplate.Save(c); } } -} \ No newline at end of file +} diff --git a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/AccountDebitDao.cs b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/AccountDebitDao.cs index b38092ce..b22ede86 100644 --- a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/AccountDebitDao.cs +++ b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/AccountDebitDao.cs @@ -11,4 +11,4 @@ namespace Spring.Data.NHibernate HibernateTemplate.Save(d); } } -} \ No newline at end of file +} diff --git a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/AccountManager.cs b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/AccountManager.cs index b6733497..ed3f142e 100644 --- a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/AccountManager.cs +++ b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/AccountManager.cs @@ -2,13 +2,13 @@ /* * Copyright � 2002-2011 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. @@ -24,7 +24,6 @@ namespace Spring.Data.NHibernate { public class AccountManager : IAccountManager { - private IAccountCreditDao creditDao; private IAccountDebitDao debitDao; private IAuditDao auditDao; @@ -54,7 +53,6 @@ namespace Spring.Data.NHibernate set { auditDao = value; } } - public bool ThrowException { get { return throwException; } @@ -67,7 +65,6 @@ namespace Spring.Data.NHibernate set { throwExceptionAtEnd = value; } } - [Transaction()] public void DoTransfer(float creditAmount, float debitAmount) { @@ -76,18 +73,17 @@ namespace Spring.Data.NHibernate { throw new ArithmeticException("Couldn't do the math...."); } + debitDao.DebitAccount(debitAmount); if (AuditDao != null) { AuditDao.AuditOperation(DateTime.Now.ToString()); } + if (ThrowExceptionAtEnd) { throw new ArgumentException("Almost there...but not quite."); } } - } - - } diff --git a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/AuditDao.cs b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/AuditDao.cs index 3f9c0370..d353f024 100644 --- a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/AuditDao.cs +++ b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/AuditDao.cs @@ -7,12 +7,13 @@ namespace Spring.Data.NHibernate public class AuditDao : AdoDaoSupport, IAuditDao { protected static readonly ILog logger = LogManager.GetLogger(); + public void AuditOperation(string operationIdenfitier) { logger.LogDebug("Executing AUDIT operation."); AdoTemplate.ExecuteNonQuery(CommandType.Text, - "insert into AuditTable (AuditId) values (@AuditId)", - "AuditId", DbType.String, 100, operationIdenfitier); + "insert into AuditTable (AuditId) values (@AuditId)", + "AuditId", DbType.String, 100, operationIdenfitier); logger.LogDebug("AUDIT operation done."); } } diff --git a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/Bytecode/AbstractInjectableUserTypeFixture.cs b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/Bytecode/AbstractInjectableUserTypeFixture.cs index 0484b2ad..6bf5b414 100644 --- a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/Bytecode/AbstractInjectableUserTypeFixture.cs +++ b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/Bytecode/AbstractInjectableUserTypeFixture.cs @@ -3,7 +3,6 @@ using NHibernate.Bytecode; using NHibernate.Cfg; using NHibernate.Engine; using NHibernate.Tool.hbm2ddl; - using NUnit.Framework; using Environment = NHibernate.Cfg.Environment; @@ -42,9 +41,9 @@ namespace Spring.Data.NHibernate.Bytecode Environment.BytecodeProvider = GetBytecodeProvider(); cfg.Configure(); cfg.AddResource("uNhAddIns.Adapters.CommonTests.EnhancedBytecodeProvider.Foo.Spechbm.xml", - typeof(AbstractInjectableUserTypeFixture).Assembly); + typeof(AbstractInjectableUserTypeFixture).Assembly); new SchemaExport(cfg).Create(false, true); - sessions = (ISessionFactoryImplementor)cfg.BuildSessionFactory(); + sessions = (ISessionFactoryImplementor) cfg.BuildSessionFactory(); } [Ignore("Work in progress")] @@ -55,6 +54,7 @@ namespace Spring.Data.NHibernate.Bytecode { sessions.Dispose(); } + sessions = null; } @@ -101,6 +101,5 @@ namespace Spring.Data.NHibernate.Bytecode Assert.IsNull(upperFoo.Description); } } - } } diff --git a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/Bytecode/Foo.Spechbm.xml b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/Bytecode/Foo.Spechbm.xml index 38faa3e6..ff64ca37 100644 --- a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/Bytecode/Foo.Spechbm.xml +++ b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/Bytecode/Foo.Spechbm.xml @@ -1,15 +1,15 @@  - - - - - - - - - + assembly="uNhAddIns.Adapters.CommonTests" + namespace="uNhAddIns.Adapters.CommonTests.EnhancedBytecodeProvider"> + + + + + + + + + \ No newline at end of file diff --git a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/Bytecode/IDelimiter.cs b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/Bytecode/IDelimiter.cs index e7f867f3..15ce57fe 100644 --- a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/Bytecode/IDelimiter.cs +++ b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/Bytecode/IDelimiter.cs @@ -5,7 +5,7 @@ namespace Spring.Data.NHibernate.Bytecode string Delimit(string source); } - public class ParenDelimiter: IDelimiter + public class ParenDelimiter : IDelimiter { public string Delimit(string source) { @@ -13,7 +13,7 @@ namespace Spring.Data.NHibernate.Bytecode } } - public class NoOpDelimiter: IDelimiter + public class NoOpDelimiter : IDelimiter { public string Delimit(string source) { diff --git a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/Bytecode/InjectableStringUserType.cs b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/Bytecode/InjectableStringUserType.cs index 36966821..2808796d 100644 --- a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/Bytecode/InjectableStringUserType.cs +++ b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/Bytecode/InjectableStringUserType.cs @@ -58,7 +58,7 @@ namespace Spring.Data.NHibernate.Bytecode return DeepCopy(value); } - public SqlType[] SqlTypes => new[] {new SqlType(DbType.String)}; + public SqlType[] SqlTypes => new[] { new SqlType(DbType.String) }; public System.Type ReturnedType => typeof(string); @@ -75,4 +75,4 @@ namespace Spring.Data.NHibernate.Bytecode return x.GetHashCode(); } } -} \ No newline at end of file +} diff --git a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/Bytecode/InjectableUserTypeFixture.cs b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/Bytecode/InjectableUserTypeFixture.cs index 266e5111..2692fef1 100644 --- a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/Bytecode/InjectableUserTypeFixture.cs +++ b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/Bytecode/InjectableUserTypeFixture.cs @@ -1,7 +1,5 @@ using NHibernate.Bytecode; - using NUnit.Framework; - using Spring.Context; using Spring.Context.Support; using Spring.Objects.Factory.Config; @@ -31,16 +29,15 @@ namespace Spring.Data.NHibernate.Bytecode private static void Register(IConfigurableListableObjectFactory confObjFactory) { - ObjectDefinitionBuilder odb = ObjectDefinitionBuilder.RootObjectDefinition(objectDefinitionFactory, typeof(TImplementation)). - SetAutowireMode(AutoWiringMode.Constructor); - confObjFactory.RegisterObjectDefinition(typeof (TSerivice).FullName, odb.ObjectDefinition); + ObjectDefinitionBuilder odb = ObjectDefinitionBuilder.RootObjectDefinition(objectDefinitionFactory, typeof(TImplementation)).SetAutowireMode(AutoWiringMode.Constructor); + confObjFactory.RegisterObjectDefinition(typeof(TSerivice).FullName, odb.ObjectDefinition); } private static void RegisterPrototype(IConfigurableListableObjectFactory confObjFactory) - { + { ObjectDefinitionBuilder odb = ObjectDefinitionBuilder.RootObjectDefinition(objectDefinitionFactory, typeof(TImplementation)) - .SetSingleton(false).SetAutowireMode(AutoWiringMode.AutoDetect); - confObjFactory.RegisterObjectDefinition(typeof(TImplementation).FullName, odb.ObjectDefinition); - } + .SetSingleton(false).SetAutowireMode(AutoWiringMode.AutoDetect); + confObjFactory.RegisterObjectDefinition(typeof(TImplementation).FullName, odb.ObjectDefinition); + } } } diff --git a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/Controllers.xml b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/Controllers.xml index 424efd1c..18b75adb 100644 --- a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/Controllers.xml +++ b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/Controllers.xml @@ -4,8 +4,8 @@ xmlns:tx="http://www.springframework.net/tx"> - - - - + + + + \ No newline at end of file diff --git a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/Credit.cs b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/Credit.cs index 5c712c4a..cab4a18a 100644 --- a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/Credit.cs +++ b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/Credit.cs @@ -1,14 +1,14 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. - * + * Copyright � 2002-2011 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. @@ -20,27 +20,27 @@ namespace Spring.Data.NHibernate { - public class Credit - { - #region Fields + public class Credit + { + #region Fields - private int creditId; - private float amount; - - #endregion + private int creditId; + private float amount; - #region Constructor (s) - /// - /// Initializes a new instance of the class. - /// - public Credit() - { + #endregion - } + #region Constructor (s) - #endregion + /// + /// Initializes a new instance of the class. + /// + public Credit() + { + } - #region Properties + #endregion + + #region Properties public int CreditID { @@ -53,11 +53,11 @@ namespace Spring.Data.NHibernate get { return amount; } set { amount = value; } } - #endregion - #region Methods + #endregion - #endregion + #region Methods - } + #endregion + } } diff --git a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/Credit.hbm.xml b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/Credit.hbm.xml index 4aa9c9be..490985f6 100644 --- a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/Credit.hbm.xml +++ b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/Credit.hbm.xml @@ -1,10 +1,10 @@ - + - - - - - + + + + diff --git a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/Dao.xml b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/Dao.xml index 482061d5..f0785a8a 100644 --- a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/Dao.xml +++ b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/Dao.xml @@ -3,26 +3,26 @@ xmlns:db="http://www.springframework.net/database" xmlns:tx="http://www.springframework.net/tx"> - - - - - + + + + + - - - + + + - + @@ -31,33 +31,33 @@ - + + value="NHibernate.Connection.DriverConnectionProvider" /> + value="NHibernate.Dialect.MsSql2000Dialect" /> + value="NHibernate.Driver.SqlClientDriver" /> - + - + - + - + - + \ No newline at end of file diff --git a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/DbProviderTemplateTests.cs b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/DbProviderTemplateTests.cs index 8ccb5733..cc522753 100644 --- a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/DbProviderTemplateTests.cs +++ b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/DbProviderTemplateTests.cs @@ -54,7 +54,7 @@ namespace Spring.Data.NHibernate [Ignore("Trouble running on Appveyor")] public void UserCredentialsDbProvider() { - ITestObjectDao dao = (ITestObjectDao)ctx["testObjectDaoTransProxy"]; + ITestObjectDao dao = (ITestObjectDao) ctx["testObjectDaoTransProxy"]; userCredentialsDbProvider.SetCredentialsForCurrentThread("User ID=springqa", "Password=springqa"); TestObject toGeorge = new TestObject(); @@ -69,9 +69,5 @@ namespace Spring.Data.NHibernate toMary.Age = 34; dao.Create(toMary); } - - - - } -} \ No newline at end of file +} diff --git a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/Debit.cs b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/Debit.cs index b8f92f35..3ee2a9e0 100644 --- a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/Debit.cs +++ b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/Debit.cs @@ -1,14 +1,14 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. - * + * Copyright � 2002-2011 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. @@ -20,27 +20,27 @@ namespace Spring.Data.NHibernate { - public class Debit - { - #region Fields + public class Debit + { + #region Fields - private int debitId; - private float amount; - - #endregion + private int debitId; + private float amount; - #region Constructor (s) - /// - /// Initializes a new instance of the class. - /// - public Debit() - { + #endregion - } + #region Constructor (s) - #endregion + /// + /// Initializes a new instance of the class. + /// + public Debit() + { + } - #region Properties + #endregion + + #region Properties public int DebitID { @@ -53,11 +53,11 @@ namespace Spring.Data.NHibernate get { return amount; } set { amount = value; } } - #endregion - #region Methods + #endregion - #endregion + #region Methods - } + #endregion + } } diff --git a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/Debit.hbm.xml b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/Debit.hbm.xml index ecdd0cc8..2299abc1 100644 --- a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/Debit.hbm.xml +++ b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/Debit.hbm.xml @@ -1,10 +1,10 @@ - + - - - - - + + + + diff --git a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/HibernateTxScopeTransactionManagerTests.cs b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/HibernateTxScopeTransactionManagerTests.cs index 2bd82025..b3625aff 100644 --- a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/HibernateTxScopeTransactionManagerTests.cs +++ b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/HibernateTxScopeTransactionManagerTests.cs @@ -2,13 +2,13 @@ /* * Copyright © 2002-2011 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. @@ -115,19 +115,16 @@ namespace Spring.Data.NHibernate for (int i = 0; i < counter; i++) { - using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required)) { - using (ISession session = ((ISessionFactory)ctx["SessionFactory"]).OpenSession()) + using (ISession session = ((ISessionFactory) ctx["SessionFactory"]).OpenSession()) { IList to = session.CreateCriteria().List(); } //because scope.Complete() is never called, the Transaction is rolled back and this results in the orpahned connections } - } - } /// @@ -140,10 +137,9 @@ namespace Spring.Data.NHibernate for (int i = 0; i < counter; i++) { - using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required)) { - using (ISession session = ((ISessionFactory)ctx["SessionFactory"]).OpenSession()) + using (ISession session = ((ISessionFactory) ctx["SessionFactory"]).OpenSession()) { using (ITransaction tx = session.BeginTransaction()) { @@ -151,7 +147,6 @@ namespace Spring.Data.NHibernate { IList to = session.CreateCriteria().List(); throw new Exception("this exception simulates something going wrong!"); - } catch (Exception) { @@ -171,7 +166,7 @@ namespace Spring.Data.NHibernate { using (TransactionScope tx = new TransactionScope()) { - ISession s = ((ISessionFactory)ctx["SessionFactory"]).OpenSession(); + ISession s = ((ISessionFactory) ctx["SessionFactory"]).OpenSession(); TestObject to = new TestObject(); to.Name = "George"; @@ -183,7 +178,6 @@ namespace Spring.Data.NHibernate tx.Complete(); } - } private static void ExecuteSql(IDbConnection conn, string sql) @@ -206,14 +200,13 @@ namespace Spring.Data.NHibernate } catch (Exception) { - } } } private void zzzExecuteDaoOperations() { - ITestObjectDao dao = (ITestObjectDao)ctx["SimpleTestDao"]; + ITestObjectDao dao = (ITestObjectDao) ctx["SimpleTestDao"]; TestObject toGeorge = new TestObject(); toGeorge.Name = "George"; @@ -221,7 +214,6 @@ namespace Spring.Data.NHibernate dao.Create(toGeorge); } - //private void MethodForThread() //{ // @@ -230,7 +222,7 @@ namespace Spring.Data.NHibernate private void MethodForThread(object taskCounter) { - int counter = (int)taskCounter; + int counter = (int) taskCounter; for (int i = 0; i < 200; i++) { @@ -241,14 +233,12 @@ namespace Spring.Data.NHibernate } catch (Exception) { - } } Debug.WriteLine(String.Format("\n---------\nCompleting Task Number {0}\n---------\n", taskCounter)); } - [Test] public void Test() { @@ -270,7 +260,6 @@ namespace Spring.Data.NHibernate Thread t = new Thread(MethodForThread); threads.Add(t); t.Start(taskCounter); - } foreach (Thread thread in threads) @@ -289,20 +278,16 @@ namespace Spring.Data.NHibernate ISessionFactory sf = c.BuildSessionFactory(); } - - [Test] public void LeaksConnectionSampleCodeFromBlogPost() { - int counter = 200; for (int i = 0; i < counter; i++) { - using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required)) { - using (ISession session = ((ISessionFactory)ctx["SessionFactory"]).OpenSession()) + using (ISession session = ((ISessionFactory) ctx["SessionFactory"]).OpenSession()) { /* IQuery q = session.CreateQuery("from Spring.Data.NHibernate.TestObject"); @@ -315,14 +300,9 @@ namespace Spring.Data.NHibernate q.List(); //transaction.Rollback(); } - } } - } - } - } - } diff --git a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/HibernateTxScopeTransactionManagerTests.xml b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/HibernateTxScopeTransactionManagerTests.xml index 953a4391..d15f90e1 100644 --- a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/HibernateTxScopeTransactionManagerTests.xml +++ b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/HibernateTxScopeTransactionManagerTests.xml @@ -1,35 +1,37 @@ + xmlns:db="http://www.springframework.net/database" + xmlns:tx="http://www.springframework.net/tx"> - - + + connectionString="Data Source=SPRINGQA;Database=Spring;User ID=springqa;Password=springqa;Trusted_Connection=False;Max Pool Size=10;" /> - - - - - assembly://Spring.Data.NHibernate21.Integration.Tests/Spring.Data.NHibernate/TestObject.hbm.xml - - + + + + + assembly://Spring.Data.NHibernate21.Integration.Tests/Spring.Data.NHibernate/TestObject.hbm.xml + + + - - - - - - + + + + + + - + - - - - + + + + - + diff --git a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/IAccountController.cs b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/IAccountController.cs index dc5079ea..9c52a3d9 100644 --- a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/IAccountController.cs +++ b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/IAccountController.cs @@ -4,4 +4,4 @@ namespace Spring.Data.NHibernate { void DoWork(); } -} \ No newline at end of file +} diff --git a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/IAccountCreditDao.cs b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/IAccountCreditDao.cs index c3df5083..62de3b78 100644 --- a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/IAccountCreditDao.cs +++ b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/IAccountCreditDao.cs @@ -1,5 +1,3 @@ - - namespace Spring.Data.NHibernate { public interface IAccountCreditDao diff --git a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/IAccountDebitDao.cs b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/IAccountDebitDao.cs index 02c5030e..130f290c 100644 --- a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/IAccountDebitDao.cs +++ b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/IAccountDebitDao.cs @@ -1,4 +1,3 @@ - namespace Spring.Data.NHibernate { public interface IAccountDebitDao diff --git a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/IAccountManager.cs b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/IAccountManager.cs index 2a7794d3..968b819c 100644 --- a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/IAccountManager.cs +++ b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/IAccountManager.cs @@ -1,16 +1,15 @@ - namespace Spring.Data.NHibernate { public interface IAccountManager { void DoTransfer(float creditAmount, float debitAmount); - + /// /// For testing purposes... /// bool ThrowException - { - get; + { + get; set; } } diff --git a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/IAuditDao.cs b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/IAuditDao.cs index f819bd3a..63349547 100644 --- a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/IAuditDao.cs +++ b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/IAuditDao.cs @@ -1,14 +1,14 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. - * + * Copyright � 2002-2011 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. @@ -18,7 +18,6 @@ #endregion - namespace Spring.Data.NHibernate { public interface IAuditDao diff --git a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/ITestObjectDao.cs b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/ITestObjectDao.cs index 5cbb6d02..d0d14a2b 100644 --- a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/ITestObjectDao.cs +++ b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/ITestObjectDao.cs @@ -1,14 +1,14 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. - * + * Copyright � 2002-2011 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. @@ -18,24 +18,23 @@ #endregion - - namespace Spring.Data.NHibernate { - /// - /// TODO: - /// - /// Mark Pollack (.NET) - public interface ITestObjectDao - { + /// + /// TODO: + /// + /// Mark Pollack (.NET) + public interface ITestObjectDao + { void Create(TestObject to); void Update(TestObject to); void Delete(TestObject to); - TestObject FindByName(string name); - //IList FindAll(); - //int GetCount(); - //int GetCountByDelegate(); + + TestObject FindByName(string name); + + //IList FindAll(); + //int GetCount(); + //int GetCountByDelegate(); void CreateUpdateRollback(TestObject to); - - } + } } diff --git a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/MultipleDbTests.cs b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/MultipleDbTests.cs index fe3ff8df..a9adfebd 100644 --- a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/MultipleDbTests.cs +++ b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/MultipleDbTests.cs @@ -2,13 +2,13 @@ /* * Copyright © 2002-2011 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. @@ -51,7 +51,6 @@ namespace Spring.Data.NHibernate /// public MultipleDbTests() { - } #endregion @@ -80,8 +79,8 @@ namespace Spring.Data.NHibernate [Test] public void MultipleDBAccessUsingMultipleSessionScopes() { - SessionScope scope1 = new SessionScope( (ISessionFactory) ctx["SessionFactory1"], false ); - SessionScope scope2 = new SessionScope( (ISessionFactory) ctx["SessionFactory2"], false ); + SessionScope scope1 = new SessionScope((ISessionFactory) ctx["SessionFactory1"], false); + SessionScope scope2 = new SessionScope((ISessionFactory) ctx["SessionFactory2"], false); scope1.Open(); scope2.Open(); @@ -92,6 +91,5 @@ namespace Spring.Data.NHibernate scope1.Close(); scope2.Close(); } - } } diff --git a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/MultipleDbTests.xml b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/MultipleDbTests.xml index 1a24c20f..4015da6f 100644 --- a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/MultipleDbTests.xml +++ b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/MultipleDbTests.xml @@ -2,128 +2,130 @@ - + - + - + - - - - Spring.Data.NHibernate5.Integration.Tests - - - - + + + + Spring.Data.NHibernate5.Integration.Tests + + + + - + - + - + - - + + - + - + - - - - Spring.Data.NHibernate5.Integration.Tests - - - - + + + + Spring.Data.NHibernate5.Integration.Tests + + + + - + - + - + - - + + - + - - + + - - - - - - + + + + + + - - - - - + + + + + + + + + + + + + + + + + + + - + - + + transactionInterceptor + - + - - - - - - - - - - - - transactionInterceptor - - - - - - - - - - - - + + + + + + + + \ No newline at end of file diff --git a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/NHDAOTests.cs b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/NHDAOTests.cs index e72d5fd4..13ec80c9 100644 --- a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/NHDAOTests.cs +++ b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/NHDAOTests.cs @@ -2,13 +2,13 @@ /* * Copyright © 2002-2011 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. @@ -31,24 +31,18 @@ using Spring.Data.NHibernate.Support; namespace Spring.Data.NHibernate { - [TestFixture] - public class NHDAOTests - { - private IApplicationContext ctx; + [TestFixture] + public class NHDAOTests + { + private IApplicationContext ctx; - [SetUp] + [SetUp] public void SetUp() { //BasicConfigurator.Configure(); string assemblyName = GetType().Assembly.GetName().Name; //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" - - }; + 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; @@ -87,12 +81,13 @@ namespace Spring.Data.NHibernate IAccountManager mgr = null; try { - Assert.IsNotNull(ctx,"Application Context is null"); + Assert.IsNotNull(ctx, "Application Context is null"); mgr = ctx["accountManager"] as IAccountManager; - Assert.IsNotNull(mgr,"accountManager not of expected type. Type = " + ctx["accountManager"].GetType().ToString()); + Assert.IsNotNull(mgr, "accountManager not of expected type. Type = " + ctx["accountManager"].GetType().ToString()); mgr.DoTransfer(transferAmount, transferAmount); Assert.IsTrue(ContainsNewData(transferAmount)); - } catch (Exception e) + } + catch (Exception e) { if (mgr.ThrowException) { @@ -103,16 +98,16 @@ namespace Spring.Data.NHibernate } } - private bool ContainsNewData(float amount) - { - //to be done - return true; - } + private bool ContainsNewData(float amount) + { + //to be done + return true; + } - private bool DoesNotContainNewData(float amount) - { - //to be done - return true; - } - } + private bool DoesNotContainNewData(float amount) + { + //to be done + return true; + } + } } diff --git a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/NHDAOTests.xml b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/NHDAOTests.xml index 42efc820..50007156 100644 --- a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/NHDAOTests.xml +++ b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/NHDAOTests.xml @@ -1,93 +1,95 @@ - + - + - + - - - + + + Spring.Data.NHibernate5.Integration.Tests - + + value="NHibernate.Connection.DriverConnectionProvider" /> - + value="NHibernate.Dialect.MsSql2000Dialect" /> + + value="NHibernate.Driver.SqlClientDriver" /> - + - + - + - - + + - - + + - + - - + - - - - - - - - - - - - - + + + + + + + + + + + + - - + + - + - + - - - + + transactionInterceptor - - + + - + - - + - - - - + + + + \ No newline at end of file diff --git a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/NHTestObjectDao.cs b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/NHTestObjectDao.cs index df39c17f..cfaedf8e 100644 --- a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/NHTestObjectDao.cs +++ b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/NHTestObjectDao.cs @@ -2,13 +2,13 @@ /* * Copyright � 2002-2011 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. @@ -21,9 +21,7 @@ #region Imports using System.Collections; - using NHibernate.Type; - using Spring.Data.NHibernate.Support; using Spring.Transaction.Interceptor; @@ -70,7 +68,7 @@ namespace Spring.Data.NHibernate "from TestObject to where to.Name=?", name, TypeFactory.GetStringType(50) - ); + ); if (result.Count > 0) { diff --git a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/NativeNHTestObjectDao.cs b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/NativeNHTestObjectDao.cs index 19cdad98..4a37c39a 100644 --- a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/NativeNHTestObjectDao.cs +++ b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/NativeNHTestObjectDao.cs @@ -1,14 +1,14 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. - * + * Copyright � 2002-2011 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. @@ -26,31 +26,30 @@ using NHibernate; namespace Spring.Data.NHibernate { - public class NativeNHTestObjectDao : ITestObjectDao - { - public ISessionFactory SessionFactory - { - get { return sessionFactory; } - set { sessionFactory = value; } - } + public class NativeNHTestObjectDao : ITestObjectDao + { + public ISessionFactory SessionFactory + { + get { return sessionFactory; } + set { sessionFactory = value; } + } - private ISessionFactory sessionFactory; + private ISessionFactory sessionFactory; - #region Constructor (s) - /// - /// Initializes a new instance of the class. - /// - public NativeNHTestObjectDao() - { + #region Constructor (s) - } + /// + /// Initializes a new instance of the class. + /// + public NativeNHTestObjectDao() + { + } - #endregion + #endregion + #region Methods - #region Methods - - #endregion + #endregion #region ITestObjectDao Members @@ -58,29 +57,28 @@ namespace Spring.Data.NHibernate { ISession session = null; ITransaction transaction = null; - + try { session = SessionFactory.OpenSession(); - + transaction = session.BeginTransaction(); - + session.Save(to); transaction.Commit(); } catch { - if(transaction != null) - transaction.Rollback(); - throw; + if (transaction != null) + transaction.Rollback(); + throw; } finally { - if(session != null) + if (session != null) session.Close(); } - } public void Update(TestObject to) diff --git a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/NativeNHTests.cs b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/NativeNHTests.cs index 2fb65479..3fec34e4 100644 --- a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/NativeNHTests.cs +++ b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/NativeNHTests.cs @@ -1,14 +1,14 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. - * + * Copyright � 2002-2011 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. @@ -28,40 +28,37 @@ using Spring.Context.Support; namespace Spring.Data.NHibernate { - [TestFixture] - public class NativeNHTests - { + [TestFixture] + public class NativeNHTests + { + #region Constructor (s) - #region Constructor (s) - /// - /// Initializes a new instance of the class. - /// - public NativeNHTests() - { + /// + /// Initializes a new instance of the class. + /// + public NativeNHTests() + { + } - } + #endregion - #endregion + #region Methods - - #region Methods - - [Test] - public void CreateNative() - { + [Test] + public void CreateNative() + { IApplicationContext ctx; string assemblyName = GetType().Assembly.GetName().Name; ctx = new XmlApplicationContext("assembly://" + assemblyName + "/Spring.Data.NHibernate/templateTests.xml"); - ITestObjectDao dao = (ITestObjectDao)ctx.GetObject("nativeNHTestObjectDao"); - + ITestObjectDao dao = (ITestObjectDao) ctx.GetObject("nativeNHTestObjectDao"); + TestObject toGeorge = new TestObject(); toGeorge.Name = "George"; toGeorge.Age = 34; dao.Create(toGeorge); - } - #endregion + #endregion } } diff --git a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/Services.xml b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/Services.xml index c4154bba..dc21a39a 100644 --- a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/Services.xml +++ b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/Services.xml @@ -3,50 +3,44 @@ xmlns:db="http://www.springframework.net/database" xmlns:tx="http://www.springframework.net/tx"> - + - + - - + + - - - - - - - + + --> - - - + + + \ No newline at end of file diff --git a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/SimpleTestDao.cs b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/SimpleTestDao.cs index 426eaa22..09756500 100644 --- a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/SimpleTestDao.cs +++ b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/SimpleTestDao.cs @@ -6,8 +6,8 @@ namespace Spring.Data.NHibernate [Transaction] public class SimpleTestDao : ITestObjectDao { - private int _secondsToSleepBeforeException; + public int SecondsToSleepBeforeException { get { return _secondsToSleepBeforeException; } @@ -16,7 +16,6 @@ namespace Spring.Data.NHibernate _secondsToSleepBeforeException = value * 1000; } } - public ISessionFactory SessionFactory { diff --git a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/TemplateTests.cs b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/TemplateTests.cs index f371cbcc..83f1be27 100644 --- a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/TemplateTests.cs +++ b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/TemplateTests.cs @@ -2,13 +2,13 @@ /* * Copyright � 2002-2011 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. @@ -34,44 +34,46 @@ using Spring.Transaction.Support; namespace Spring.Data.NHibernate { - /// - /// Use of Hibernate Template against database. - /// - /// Mark Pollack (.NET) - [TestFixture] - public class TemplateTests - { - #region Fields + /// + /// Use of Hibernate Template against database. + /// + /// Mark Pollack (.NET) + [TestFixture] + public class TemplateTests + { + #region Fields + private IDbProvider dbProvider; private IPlatformTransactionManager transactionManager; private IApplicationContext ctx; - #endregion - #region Constants + #endregion - /// - /// The shared instance for this class (and derived classes). - /// - protected static readonly ILog log = - LogManager.GetLogger(typeof (TemplateTests)); + #region Constants + + /// + /// The shared instance for this class (and derived classes). + /// + protected static readonly ILog log = + LogManager.GetLogger(typeof(TemplateTests)); // force Spring.Data.NHibernate to be preloaded by runtime - private Type TLocalSessionFactoryObject = typeof (LocalSessionFactoryObject); + private Type TLocalSessionFactoryObject = typeof(LocalSessionFactoryObject); - #endregion + #endregion - #region Constructor (s) - /// - /// Initializes a new instance of the class. - /// - public TemplateTests() - { + #region Constructor (s) - } + /// + /// Initializes a new instance of the class. + /// + public TemplateTests() + { + } - #endregion + #endregion [SetUp] public void SetUp() @@ -86,108 +88,100 @@ namespace Spring.Data.NHibernate CleanupDatabase(dbProvider.CreateConnection()); } - private static void CleanupDatabase(IDbConnection conn) - { - conn.Open(); - using(conn) - { + private static void CleanupDatabase(IDbConnection conn) + { + conn.Open(); + using (conn) + { ExecuteSql(conn, "delete credits"); ExecuteSql(conn, "delete debits"); ExecuteSql(conn, "delete TestObjects"); ExecuteSql(conn, "insert TestObjects(Age,Name) Values(5, 'Gabriel')"); - } - } + } + } - private static void ExecuteSql(IDbConnection conn, string sql) - { - IDbCommand cmd; - cmd = conn.CreateCommand(); - cmd.CommandText = sql; - cmd.ExecuteNonQuery(); - } + private static void ExecuteSql(IDbConnection conn, string sql) + { + IDbCommand cmd; + cmd = conn.CreateCommand(); + cmd.CommandText = sql; + cmd.ExecuteNonQuery(); + } - [Test] + [Test] public void ExceptionTranslator() { - ISessionFactory sessionFactory = ctx["SessionFactory"] as ISessionFactory; - HibernateTemplate template = new HibernateTemplate(sessionFactory); + ISessionFactory sessionFactory = ctx["SessionFactory"] as ISessionFactory; + HibernateTemplate template = new HibernateTemplate(sessionFactory); IAdoExceptionTranslator translator = template.AdoExceptionTranslator; - Assert.IsNotNull(translator, "ADO.NET exception translator should not be null"); - - Assert.That(translator, Is.InstanceOf(typeof(ErrorCodeExceptionTranslator))); + Assert.IsNotNull(translator, "ADO.NET exception translator should not be null"); + + Assert.That(translator, Is.InstanceOf(typeof(ErrorCodeExceptionTranslator))); } - - [Test] + + [Test] [Ignore("what's the purpose of this test?")] // TODO: what's the purpose of this test? - public void FallbackExceptionTranslator() - { + public void FallbackExceptionTranslator() + { //ISessionFactory sessionFactory = ctx["SessionFactory"] as ISessionFactory; //HibernateTemplate template = new HibernateTemplate(sessionFactory); IAdoExceptionTranslator fallbackTranslator = new FallbackExceptionTranslator(); fallbackTranslator.Translate("test", "sql", new Exception("foo")); - - } - + } + [Test] [Ignore("Just for demo purposes")] public void DemoDao() { - - ITestObjectDao dao = (ITestObjectDao)ctx["testObjectDaoViaTxAttributes"]; + ITestObjectDao dao = (ITestObjectDao) ctx["testObjectDaoViaTxAttributes"]; TestObject toGeorge = new TestObject(); toGeorge.Name = "George"; toGeorge.Age = 33; dao.Create(toGeorge); - } [Test] [Ignore("Just for demo purposes")] public void SimpleDao() { - ITestObjectDao dao = (ITestObjectDao)ctx["NHTestObjectDao"]; + ITestObjectDao dao = (ITestObjectDao) ctx["NHTestObjectDao"]; Assert.IsNotNull(dao); TestObject to = dao.FindByName("Gabriel"); Assert.IsNotNull(to); Assert.AreEqual("Gabriel", to.Name); - } - /// - /// Test simple data base operations using attributes for - /// declarative transaction demarcation. - /// + /// + /// Test simple data base operations using attributes for + /// declarative transaction demarcation. + /// [Test] public void DaoOperationsViaProxyFactoryWithTxAttributes() { - - ITestObjectDao dao = (ITestObjectDao)ctx["testObjectDaoViaTxAttributes"]; + ITestObjectDao dao = (ITestObjectDao) ctx["testObjectDaoViaTxAttributes"]; ExecuteDaoOperations(dao); - } - [Test] public void DaoOperationsViaTransactionProxy() { - - ITestObjectDao dao = (ITestObjectDao)ctx["testObjectDaoTransProxy"]; + ITestObjectDao dao = (ITestObjectDao) ctx["testObjectDaoTransProxy"]; ExecuteDaoOperations(dao); - } [Test] public void DaoOperationsWithRollback() { - ITestObjectDao dao = (ITestObjectDao)ctx["testObjectDaoTransProxy"]; - try + ITestObjectDao dao = (ITestObjectDao) ctx["testObjectDaoTransProxy"]; + try { ExecuteAndRollbackDaoOperations(dao); - } catch (Exception e) + } + catch (Exception e) { TestObject to = dao.FindByName("Bugs"); Assert.IsNull(to); - + //just to get rid of compiler warning... Assert.IsNotNull(e); } @@ -199,40 +193,39 @@ namespace Spring.Data.NHibernate toBugs.Name = "Bugs"; toBugs.Age = 33; dao.CreateUpdateRollback(toBugs); - } - private static void ExecuteDaoOperations(ITestObjectDao dao) - { - TestObject toGeorge = new TestObject(); - toGeorge.Name = "George"; - toGeorge.Age = 33; - dao.Create(toGeorge); - TestObject to = dao.FindByName("George"); - Assert.IsNotNull(to, "FindByName for George should not return null"); - Assert.AreEqual("George", to.Name); - Assert.AreEqual(33, to.Age); - - to.Age=34; - dao.Update(to); - - TestObject to2 = dao.FindByName("George"); - Assert.AreEqual(34, to2.Age); - - dao.Delete(to); - - TestObject to3 = dao.FindByName("George"); - Assert.IsNull(to3, "Should not have found TestObject with name George. TestObject = " + to.ToString() ); - } + private static void ExecuteDaoOperations(ITestObjectDao dao) + { + TestObject toGeorge = new TestObject(); + toGeorge.Name = "George"; + toGeorge.Age = 33; + dao.Create(toGeorge); + TestObject to = dao.FindByName("George"); + Assert.IsNotNull(to, "FindByName for George should not return null"); + Assert.AreEqual("George", to.Name); + Assert.AreEqual(33, to.Age); - [Test] + to.Age = 34; + dao.Update(to); + + TestObject to2 = dao.FindByName("George"); + Assert.AreEqual(34, to2.Age); + + dao.Delete(to); + + TestObject to3 = dao.FindByName("George"); + Assert.IsNull(to3, "Should not have found TestObject with name George. TestObject = " + to.ToString()); + } + + [Test] public void ExecuteTemplate() { - ITestObjectDao dao = (ITestObjectDao)ctx["NHTestObjectDao"]; + ITestObjectDao dao = (ITestObjectDao) ctx["NHTestObjectDao"]; TransactionTemplate tt = new TransactionTemplate(transactionManager); object result = tt.Execute(new SimpleTransactionCallback(dbProvider, dao)); TestObject to = result as TestObject; - Assert.IsNotNull(to,"FindByName for Gabriel should not return null"); + Assert.IsNotNull(to, "FindByName for Gabriel should not return null"); Assert.AreEqual("Gabriel", to.Name); } @@ -244,19 +237,20 @@ namespace Spring.Data.NHibernate ITransactionStatus status = transactionManager.GetTransaction(def); - ITestObjectDao dao = (ITestObjectDao)ctx["NHTestObjectDao"]; + ITestObjectDao dao = (ITestObjectDao) ctx["NHTestObjectDao"]; TestObject to; try { - to = dao.FindByName("Gabriel"); - } + to = dao.FindByName("Gabriel"); + } catch (Exception) { transactionManager.Rollback(status); throw; } + transactionManager.Commit(status); - Assert.IsNotNull(to,"FindByName for Gabriel should not return null"); + Assert.IsNotNull(to, "FindByName for Gabriel should not return null"); Assert.AreEqual("Gabriel", to.Name); } @@ -270,6 +264,7 @@ namespace Spring.Data.NHibernate dbProvider = dbp; this.dao = dao; } + /// /// Gets called by TransactionTemplate.Execute within a /// transaction context. @@ -281,7 +276,5 @@ namespace Spring.Data.NHibernate return dao.FindByName("Gabriel"); } } - - } } diff --git a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/TestObject.cs b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/TestObject.cs index 6015632a..4a3ae518 100644 --- a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/TestObject.cs +++ b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/TestObject.cs @@ -1,14 +1,14 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. - * + * Copyright � 2002-2011 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. @@ -18,58 +18,57 @@ #endregion - namespace Spring.Data.NHibernate { - /// - /// TODO: - /// - /// Mark Pollack (.NET) - public class TestObject - { - #region Fields + /// + /// TODO: + /// + /// Mark Pollack (.NET) + public class TestObject + { + #region Fields + private int age; private string name; private int objectNumber; - - #endregion - #region Constructor (s) - /// - /// Initializes a new instance of the class. + #endregion + + #region Constructor (s) + + /// + /// Initializes a new instance of the class. /// - public TestObject() - { + public TestObject() + { + } - } + #endregion - #endregion + #region Properties - #region Properties + public virtual int Age + { + get { return age; } + set { age = value; } + } - public virtual int Age - { - get { return age; } - set { age = value; } - } + public virtual string Name + { + get { return name; } + set { name = value; } + } - public virtual string Name - { - get { return name; } - set { name = value; } - } + public virtual int ObjectNumber + { + get { return objectNumber; } + set { objectNumber = value; } + } - public virtual int ObjectNumber - { - get { return objectNumber; } - set { objectNumber = value; } - } + #endregion - #endregion + #region Methods - #region Methods - - #endregion - - } + #endregion + } } diff --git a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/TestObject.hbm.xml b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/TestObject.hbm.xml index b7ce0425..81ba7d0f 100644 --- a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/TestObject.hbm.xml +++ b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/TestObject.hbm.xml @@ -1,17 +1,17 @@ - + - - - - + + - - - + + + + + diff --git a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/creditdebit.sql b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/creditdebit.sql index 903360e1..b0a03660 100644 --- a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/creditdebit.sql +++ b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/creditdebit.sql @@ -1,20 +1,51 @@ - -CREATE TABLE [Credits]( - [CreditID] [int] IDENTITY NOT NULL, - [CreditAmount] [float] NOT NULL, - CONSTRAINT [PK_CreditID] PRIMARY KEY CLUSTERED +CREATE TABLE [Credits] ( - [CreditID] ASC -) ON [PRIMARY] + [ + CreditID] [ + int] + IDENTITY + NOT + NULL, [ + CreditAmount] [ + float] + NOT + NULL, + CONSTRAINT [ + PK_CreditID] + PRIMARY + KEY + CLUSTERED + ( +[ + CreditID] + ASC ) ON [PRIMARY] + ) + ON [PRIMARY] ; -CREATE TABLE [Debits]( - [DebitID] [int] IDENTITY NOT NULL, - [DebitAmount] [float] NOT NULL, - CONSTRAINT [PK_DebitID] PRIMARY KEY CLUSTERED +CREATE TABLE [Debits] ( - [DebitID] ASC -) ON [PRIMARY] + [ + DebitID] [ + int] + IDENTITY + NOT + NULL, [ + DebitAmount] [ + float] + NOT + NULL, + CONSTRAINT [ + PK_DebitID] + PRIMARY + KEY + CLUSTERED + ( +[ + DebitID] + ASC ) ON [PRIMARY] + ) + ON [PRIMARY] ; \ No newline at end of file diff --git a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/dbProviderTemplateTests.xml b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/dbProviderTemplateTests.xml index 0e8dfa48..9025c80a 100644 --- a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/dbProviderTemplateTests.xml +++ b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/dbProviderTemplateTests.xml @@ -1,36 +1,36 @@ - + - + + + + + + + + ---> - - - - - - - - + connectionString="Data Source=(local);Database=Spring;Trusted_Connection=False" /> - + - - - + + - - assembly://Spring.Data.NHibernate5.Integration.Tests/Spring.Data.NHibernate/TestObject.hbm.xml - + + assembly://Spring.Data.NHibernate5.Integration.Tests/Spring.Data.NHibernate/TestObject.hbm.xml + + - - - - - + + + - - - + + + + + - + - - - + + + + + + + --> + + - - - + + + - - + - - + - - + + - - - + + + - - - - + + + + - - + + \ No newline at end of file diff --git a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/templateTests.xml b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/templateTests.xml index abca45e4..2fd66fd4 100644 --- a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/templateTests.xml +++ b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/templateTests.xml @@ -1,124 +1,127 @@ + xmlns:db="http://www.springframework.net/database"> - - - - - - - - - - - assembly://Spring.Data.NHibernate5.Integration.Tests/Spring.Data.NHibernate/TestObject.hbm.xml - - + connectionString="Data Source=(local);Database=Spring;User ID=springqa;Password=springqa;Trusted_Connection=False" /> + + + + + + + - Spring.Data.NHibernate.Integration.Tests + assembly://Spring.Data.NHibernate5.Integration.Tests/Spring.Data.NHibernate/TestObject.hbm.xml + - --> - - - + + - - --> + - + - + - + - - + + - + - - - + + + - - - + + + - + - - + + - + - - + + - - - - - - + + + + + + - + - - - - + + + + - - + + - - - - - - + + + + + + - + - - - - - - - - - + + + + + + + + + \ No newline at end of file diff --git a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/testObject.sql b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/testObject.sql index 76631ddd..7cc24eff 100644 --- a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/testObject.sql +++ b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/testObject.sql @@ -1,10 +1,24 @@ - -CREATE TABLE [TestObjects] ( - [TestObjectNo] int IDENTITY NOT NULL, - [Age] int NOT NULL, - [Name] nvarchar(1024), - CONSTRAINT [TestObjectNo] PRIMARY KEY CLUSTERED - ( - [TestObjectNo] ASC - ) -); \ No newline at end of file +CREATE TABLE [TestObjects] +( + [ + TestObjectNo] + int + IDENTITY + NOT + NULL, [ + Age] + int + NOT + NULL, [ + Name] + nvarchar +( + 1024 +), + CONSTRAINT [TestObjectNo] PRIMARY KEY CLUSTERED +( +[ + TestObjectNo] + ASC +) + ); \ No newline at end of file diff --git a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/txScopeBugTests.xml b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/txScopeBugTests.xml index c829404f..d94e25f0 100644 --- a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/txScopeBugTests.xml +++ b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Data/NHibernate/txScopeBugTests.xml @@ -1,63 +1,64 @@ + xmlns:db="http://www.springframework.net/database" + xmlns:tx="http://www.springframework.net/tx"> - + + --> + connectionString="Data Source=(local)\sql2005;Initial Catalog=rewards;user id=sa;password=password" /> - + - + + + - - - + + + assembly://Spring.Data.NHibernate21.Integration.Tests/Spring.Data.NHibernate/TestObject.hbm.xml + + + + + + - - - assembly://Spring.Data.NHibernate21.Integration.Tests/Spring.Data.NHibernate/TestObject.hbm.xml - - - - - + - + + + - - - + + + + - - - - - - + - - + - - - - - - - - + + + + + + + + \ No newline at end of file diff --git a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/RecreateDatabases.sql b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/RecreateDatabases.sql index bf16ee2a..d9c8e651 100644 --- a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/RecreateDatabases.sql +++ b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/RecreateDatabases.sql @@ -1,38 +1,48 @@ -IF EXISTS (SELECT name FROM sys.databases WHERE name = N'Spring') +IF +EXISTS (SELECT name FROM sys.databases WHERE name = N'Spring') BEGIN - ALTER DATABASE Spring + ALTER +DATABASE Spring SET SINGLE_USER WITH ROLLBACK IMMEDIATE - DROP DATABASE Spring + DROP +DATABASE Spring END GO IF EXISTS (SELECT name FROM sys.databases WHERE name = N'NHibernate') BEGIN - ALTER DATABASE NHibernate + ALTER +DATABASE NHibernate SET SINGLE_USER WITH ROLLBACK IMMEDIATE - DROP DATABASE NHibernate + DROP +DATABASE NHibernate END GO IF EXISTS (SELECT * FROM sys.server_principals WHERE name = N'springqa2') - DROP LOGIN [springqa2] + DROP +LOGIN [springqa2] GO -CREATE DATABASE Spring +CREATE +DATABASE Spring GO -CREATE DATABASE NHibernate +CREATE +DATABASE NHibernate GO -CREATE LOGIN [springqa2] WITH PASSWORD=N'springqa2', DEFAULT_DATABASE=[Spring], DEFAULT_LANGUAGE=[us_english], CHECK_EXPIRATION = OFF, CHECK_POLICY = OFF +CREATE +LOGIN [springqa2] WITH PASSWORD=N'springqa2', DEFAULT_DATABASE=[Spring], DEFAULT_LANGUAGE=[us_english], CHECK_EXPIRATION = OFF, CHECK_POLICY = OFF GO USE Spring -CREATE USER [springqa2] FOR LOGIN [springqa2] WITH DEFAULT_SCHEMA=[dbo] +CREATE +USER [springqa2] FOR LOGIN [springqa2] WITH DEFAULT_SCHEMA=[dbo] EXEC sp_addrolemember 'db_owner', 'springqa2' GO diff --git a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/TestEnbeddedConfig.cfg.xml b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/TestEnbeddedConfig.cfg.xml index d5bce2e5..5e3db34b 100644 --- a/test/Spring/Spring.Data.NHibernate5.Integration.Tests/TestEnbeddedConfig.cfg.xml +++ b/test/Spring/Spring.Data.NHibernate5.Integration.Tests/TestEnbeddedConfig.cfg.xml @@ -1,11 +1,12 @@  - - - NHibernate.Test.DebugConnectionProvider, NHibernate.Test - NHibernate.Cache.HashtableCacheProvider, NHibernate - NHibernate.Driver.SqlClientDriver - Server=localhost;initial catalog=nhibernate;User Id=;Password= - true 1, false 0, yes 1, no 0 - NHibernate.Dialect.MsSql2000Dialect - + + + NHibernate.Test.DebugConnectionProvider, NHibernate.Test + NHibernate.Cache.HashtableCacheProvider, NHibernate + NHibernate.Driver.SqlClientDriver + Server=localhost;initial catalog=nhibernate;User Id=;Password= + + true 1, false 0, yes 1, no 0 + NHibernate.Dialect.MsSql2000Dialect + \ No newline at end of file diff --git a/test/Spring/Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests/App.config b/test/Spring/Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests/App.config index 030b0708..a9beed49 100644 --- a/test/Spring/Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests/App.config +++ b/test/Spring/Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests/App.config @@ -2,43 +2,47 @@ -
-
-
+
+
+
-
-
+
+
- - - + + + - - - + + + - - + + - - + + - + @@ -49,9 +53,9 @@ - + - + @@ -59,6 +63,6 @@ - + \ No newline at end of file diff --git a/test/Spring/Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests/Container.cs b/test/Spring/Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests/Container.cs index 315a4baf..dbdbe191 100644 --- a/test/Spring/Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests/Container.cs +++ b/test/Spring/Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests/Container.cs @@ -1,8 +1,7 @@ -namespace Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests +namespace Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests; + +public class Container : IContainer { - public class Container : IContainer - { - public Guid Id { get; set; } - public string Name { get; set; } - } + public Guid Id { get; set; } + public string Name { get; set; } } diff --git a/test/Spring/Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests/HibernateTxScopeTransactionManagerNestedTransactionSuspensionTests.cs b/test/Spring/Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests/HibernateTxScopeTransactionManagerNestedTransactionSuspensionTests.cs index c9bfb0b2..babe9c16 100644 --- a/test/Spring/Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests/HibernateTxScopeTransactionManagerNestedTransactionSuspensionTests.cs +++ b/test/Spring/Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests/HibernateTxScopeTransactionManagerNestedTransactionSuspensionTests.cs @@ -1,49 +1,41 @@ using NUnit.Framework; - using Spring.Testing.NUnit; -namespace Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests +namespace Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests; + +[TestFixture] +public class HibernateTxScopeTransactionManagerNestedTransactionSuspensionTests : AbstractTransactionalSpringContextTests { - [TestFixture] - public class HibernateTxScopeTransactionManagerNestedTransactionSuspensionTests : AbstractTransactionalSpringContextTests + #region DI + + public IService1 Service1 { get; set; } + public IService2 Service2 { get; set; } + + #endregion + + protected override string[] ConfigLocations { - #region DI - - public IService1 Service1 { get; set; } - public IService2 Service2 { get; set; } - - #endregion - - protected override string[] ConfigLocations + get { - get - { - return new[] - { - "config://spring/objects", - "assembly://Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests/Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests/Spring.Configuration.xml", - "assembly://Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests/Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests/Spring.NHibernate.xml", - "assembly://Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests/Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests/Spring.HibernateTxScopeTransactionManager.xml" - }; - } - } - - [Test] - public void CanSuspendTransactionOnNotSupported() - { - Service1.ServiceMethodWithNotSupported1(); - } - - [Test] - public void CanSuspendTransactionOnNotSupportedWithNestedRequiresNew() - { - Service2.ServiceMethodWithNotSupported(); - } - - [Test] - public void CanSuspendTransactionOnNotSupportedWithNestedRequired() - { - Service1.ServiceMethodWithNotSupported3(); + return new[] { "config://spring/objects", "assembly://Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests/Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests/Spring.Configuration.xml", "assembly://Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests/Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests/Spring.NHibernate.xml", "assembly://Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests/Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests/Spring.HibernateTxScopeTransactionManager.xml" }; } } + + [Test] + public void CanSuspendTransactionOnNotSupported() + { + Service1.ServiceMethodWithNotSupported1(); + } + + [Test] + public void CanSuspendTransactionOnNotSupportedWithNestedRequiresNew() + { + Service2.ServiceMethodWithNotSupported(); + } + + [Test] + public void CanSuspendTransactionOnNotSupportedWithNestedRequired() + { + Service1.ServiceMethodWithNotSupported3(); + } } diff --git a/test/Spring/Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests/IContainer.cs b/test/Spring/Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests/IContainer.cs index 0061cc14..963f7b4b 100644 --- a/test/Spring/Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests/IContainer.cs +++ b/test/Spring/Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests/IContainer.cs @@ -1,8 +1,7 @@ -namespace Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests +namespace Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests; + +public interface IContainer { - public interface IContainer - { - Guid Id { get; set; } - string Name { get; set; } - } + Guid Id { get; set; } + string Name { get; set; } } diff --git a/test/Spring/Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests/IService1.cs b/test/Spring/Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests/IService1.cs index 5a2160bf..07821aed 100644 --- a/test/Spring/Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests/IService1.cs +++ b/test/Spring/Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests/IService1.cs @@ -1,15 +1,14 @@ -namespace Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests +namespace Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests; + +public interface IService1 { - public interface IService1 - { - void ServiceMethodWithNotSupported1(); + void ServiceMethodWithNotSupported1(); - void ServiceMethodWithNotSupported2(); + void ServiceMethodWithNotSupported2(); - void ServiceMethodWithNotSupported3(); + void ServiceMethodWithNotSupported3(); - void ServiceMethodWithNotSupported4(); + void ServiceMethodWithNotSupported4(); - void ServiceMethodWithRequired(); - } + void ServiceMethodWithRequired(); } diff --git a/test/Spring/Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests/IService2.cs b/test/Spring/Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests/IService2.cs index d16ce8b2..8cd792ed 100644 --- a/test/Spring/Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests/IService2.cs +++ b/test/Spring/Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests/IService2.cs @@ -1,9 +1,8 @@ -namespace Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests -{ - public interface IService2 - { - void ServiceMethodWithNotSupported(); +namespace Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests; - void ServiceMethodWithRequiresNew(); - } +public interface IService2 +{ + void ServiceMethodWithNotSupported(); + + void ServiceMethodWithRequiresNew(); } diff --git a/test/Spring/Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests/Mappings.hbm.xml b/test/Spring/Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests/Mappings.hbm.xml index 9c059361..a98d74cb 100644 --- a/test/Spring/Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests/Mappings.hbm.xml +++ b/test/Spring/Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests/Mappings.hbm.xml @@ -1,12 +1,14 @@  - + - - - - - + + + + + - + \ No newline at end of file diff --git a/test/Spring/Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests/Service1.cs b/test/Spring/Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests/Service1.cs index 7d3cbd32..c7451379 100644 --- a/test/Spring/Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests/Service1.cs +++ b/test/Spring/Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests/Service1.cs @@ -1,45 +1,44 @@ using Spring.Data.NHibernate.Generic; using Spring.Transaction; -namespace Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests +namespace Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests; + +[Transaction.Interceptor.Transaction(TransactionPropagation.Supports, ReadOnly = true)] +public class Service1 : IService1 { - [Transaction.Interceptor.Transaction(TransactionPropagation.Supports, ReadOnly = true)] - public class Service1 : IService1 + #region DI + + public HibernateTemplate HibernateTemplate { get; set; } + + #endregion + + [Transaction.Interceptor.Transaction(TransactionPropagation.NotSupported)] + public virtual void ServiceMethodWithNotSupported1() { - #region DI + ServiceMethodWithNotSupported2(); + } - public HibernateTemplate HibernateTemplate { get; set; } + [Transaction.Interceptor.Transaction(TransactionPropagation.NotSupported)] + public virtual void ServiceMethodWithNotSupported2() + { + // do some stuff + } - #endregion + [Transaction.Interceptor.Transaction(TransactionPropagation.NotSupported)] + public virtual void ServiceMethodWithNotSupported3() + { + ServiceMethodWithNotSupported4(); + } - [Transaction.Interceptor.Transaction(TransactionPropagation.NotSupported)] - public virtual void ServiceMethodWithNotSupported1() - { - ServiceMethodWithNotSupported2(); - } + [Transaction.Interceptor.Transaction(TransactionPropagation.NotSupported)] + public virtual void ServiceMethodWithNotSupported4() + { + ServiceMethodWithRequired(); + } - [Transaction.Interceptor.Transaction(TransactionPropagation.NotSupported)] - public virtual void ServiceMethodWithNotSupported2() - { - // do some stuff - } - - [Transaction.Interceptor.Transaction(TransactionPropagation.NotSupported)] - public virtual void ServiceMethodWithNotSupported3() - { - ServiceMethodWithNotSupported4(); - } - - [Transaction.Interceptor.Transaction(TransactionPropagation.NotSupported)] - public virtual void ServiceMethodWithNotSupported4() - { - ServiceMethodWithRequired(); - } - - [Transaction.Interceptor.Transaction(TransactionPropagation.Required)] - public virtual void ServiceMethodWithRequired() - { - // do some stuff - } + [Transaction.Interceptor.Transaction(TransactionPropagation.Required)] + public virtual void ServiceMethodWithRequired() + { + // do some stuff } } diff --git a/test/Spring/Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests/Service2.cs b/test/Spring/Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests/Service2.cs index eab46786..dc5e191e 100644 --- a/test/Spring/Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests/Service2.cs +++ b/test/Spring/Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests/Service2.cs @@ -1,27 +1,26 @@ using Spring.Data.NHibernate.Generic; using Spring.Transaction; -namespace Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests +namespace Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests; + +[Transaction.Interceptor.Transaction(TransactionPropagation.Supports, ReadOnly = true)] +public class Service2 : IService2 { - [Transaction.Interceptor.Transaction(TransactionPropagation.Supports, ReadOnly = true)] - public class Service2 : IService2 + #region DI + + public HibernateTemplate HibernateTemplate { get; set; } + + #endregion + + [Transaction.Interceptor.Transaction(TransactionPropagation.NotSupported)] + public virtual void ServiceMethodWithNotSupported() { - #region DI + ServiceMethodWithRequiresNew(); + } - public HibernateTemplate HibernateTemplate { get; set; } - - #endregion - - [Transaction.Interceptor.Transaction(TransactionPropagation.NotSupported)] - public virtual void ServiceMethodWithNotSupported() - { - ServiceMethodWithRequiresNew(); - } - - [Transaction.Interceptor.Transaction(TransactionPropagation.RequiresNew)] - public virtual void ServiceMethodWithRequiresNew() - { - // do stuff - } + [Transaction.Interceptor.Transaction(TransactionPropagation.RequiresNew)] + public virtual void ServiceMethodWithRequiresNew() + { + // do stuff } } diff --git a/test/Spring/Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests/Spring.Configuration.xml b/test/Spring/Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests/Spring.Configuration.xml index 4a5943c5..98a49e9e 100644 --- a/test/Spring/Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests/Spring.Configuration.xml +++ b/test/Spring/Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests/Spring.Configuration.xml @@ -1,36 +1,40 @@  - + - + - - - - - - - + + + + + - - - - - - *Service* - - - - - transactionAdvice - - - + - - - + + + + + + *Service* + + + + + transactionAdvice + + + - - - + + + + + + + diff --git a/test/Spring/Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests/Spring.HibernateTxScopeTransactionManager.xml b/test/Spring/Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests/Spring.HibernateTxScopeTransactionManager.xml index 4b19ee45..38e4ea37 100644 --- a/test/Spring/Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests/Spring.HibernateTxScopeTransactionManager.xml +++ b/test/Spring/Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests/Spring.HibernateTxScopeTransactionManager.xml @@ -1,11 +1,13 @@  - + - - - - + + + + diff --git a/test/Spring/Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests/Spring.NHibernate.xml b/test/Spring/Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests/Spring.NHibernate.xml index 8708b8ae..4bdc7376 100644 --- a/test/Spring/Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests/Spring.NHibernate.xml +++ b/test/Spring/Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests/Spring.NHibernate.xml @@ -1,41 +1,47 @@  - Dependency Injection for NHibernate Session + Dependency Injection for NHibernate Session - - - - - - - - - - - - - - - - - - - - - - + + - - - assembly://Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests/Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests/Mappings.hbm.xml - - + + + + + + + + + + + + + + + + + - + - - - - + + + + assembly://Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests/Spring.Data.NHibernate5.NestedTxSuspension.Integration.Tests/Mappings.hbm.xml + + + + + + + + + + \ No newline at end of file diff --git a/test/Spring/Spring.Data.NHibernate5.Tests/App.config b/test/Spring/Spring.Data.NHibernate5.Tests/App.config index 00e338fd..8aed812a 100644 --- a/test/Spring/Spring.Data.NHibernate5.Tests/App.config +++ b/test/Spring/Spring.Data.NHibernate5.Tests/App.config @@ -9,19 +9,19 @@ - - + + - + diff --git a/test/Spring/Spring.Data.NHibernate5.Tests/Data/NHibernate/Config/AopConfiguration.cs b/test/Spring/Spring.Data.NHibernate5.Tests/Data/NHibernate/Config/AopConfiguration.cs index cfcd552f..feeaf94a 100644 --- a/test/Spring/Spring.Data.NHibernate5.Tests/Data/NHibernate/Config/AopConfiguration.cs +++ b/test/Spring/Spring.Data.NHibernate5.Tests/Data/NHibernate/Config/AopConfiguration.cs @@ -53,8 +53,8 @@ namespace Spring.Data.NHibernate.Config [Ignore("TODO Connects to database")] public void ProxyDataAccessAndServiceLayer() { - Assert.IsFalse(AopUtils.IsAopProxy( ctx["DbProvider"] )); - Assert.IsFalse(AopUtils.IsAopProxy( ctx["SessionFactory"] )); + Assert.IsFalse(AopUtils.IsAopProxy(ctx["DbProvider"])); + Assert.IsFalse(AopUtils.IsAopProxy(ctx["SessionFactory"])); Assert.IsFalse(AopUtils.IsAopProxy(ctx["hibernateTransactionManager"])); Assert.IsFalse(AopUtils.IsAopProxy(ctx["transactionManager"])); //Assert.IsTrue(AopUtils.IsAopProxy(ctx["testObjectDaoTransProxy"])); @@ -69,7 +69,7 @@ namespace Spring.Data.NHibernate.Config LoggingAroundAdvice caa = ctx["loggingAroundAdvice"] as LoggingAroundAdvice; Assert.IsNotNull(caa); Assert.AreEqual(0, caa.numInvoked); - + ISimpleService simpleService = ctx["SimpleService"] as ISimpleService; Assert.IsNotNull(simpleService); simpleService.DoWork(new TestObject()); @@ -77,7 +77,5 @@ namespace Spring.Data.NHibernate.Config Assert.AreEqual(1, ccm.commits); Assert.AreEqual(1, caa.numInvoked); } - - } -} \ No newline at end of file +} diff --git a/test/Spring/Spring.Data.NHibernate5.Tests/Data/NHibernate/Config/AopConfiguration.xml b/test/Spring/Spring.Data.NHibernate5.Tests/Data/NHibernate/Config/AopConfiguration.xml index e5821310..dcf13d13 100644 --- a/test/Spring/Spring.Data.NHibernate5.Tests/Data/NHibernate/Config/AopConfiguration.xml +++ b/test/Spring/Spring.Data.NHibernate5.Tests/Data/NHibernate/Config/AopConfiguration.xml @@ -4,99 +4,99 @@ xmlns:tx="http://www.springframework.net/tx"> - + - + + + + + + assembly://Spring.Data.NHibernate5.Tests/Spring.Data.NHibernate/TestObject.hbm.xml + + + + + - - - - - assembly://Spring.Data.NHibernate5.Tests/Spring.Data.NHibernate/TestObject.hbm.xml - - - - - - - + - + - - + + - + - - - + + + - + - - + + - + - + - - - + + + - - - + - - - loggingAroundAdvice - - - - - - + - - - TestObjectDao - - - + + + loggingAroundAdvice + + - - - - + + \ No newline at end of file diff --git a/test/Spring/Spring.Data.NHibernate5.Tests/Data/NHibernate/Config/AopConfigurationTxPointcut.xml b/test/Spring/Spring.Data.NHibernate5.Tests/Data/NHibernate/Config/AopConfigurationTxPointcut.xml index 055fac12..31c5f1b8 100644 --- a/test/Spring/Spring.Data.NHibernate5.Tests/Data/NHibernate/Config/AopConfigurationTxPointcut.xml +++ b/test/Spring/Spring.Data.NHibernate5.Tests/Data/NHibernate/Config/AopConfigurationTxPointcut.xml @@ -5,96 +5,95 @@ xmlns:aop="http://www.springframework.net/aop"> - + - + + + + + + assembly://Spring.Data.NHibernate5.Tests/Spring.Data.NHibernate/TestObject.hbm.xml + + + + + - - - - - assembly://Spring.Data.NHibernate5.Tests/Spring.Data.NHibernate/TestObject.hbm.xml - - - - - - - + - + - - + + - + - - - + + + - + - - + + - + - - - + + + - - - - - - + + + - - - - - - - 12341234asdf* - - - + + - + + + + + + + 12341234asdf* + + + - - - loggingAdvisor - - - - - - + - - - TestObjectDao - - - + + + loggingAdvisor + + - - + + + + + + + TestObjectDao + + + + + + \ No newline at end of file diff --git a/test/Spring/Spring.Data.NHibernate5.Tests/Data/NHibernate/DelegatingLocalSessionFactoryObjectTests.cs b/test/Spring/Spring.Data.NHibernate5.Tests/Data/NHibernate/DelegatingLocalSessionFactoryObjectTests.cs index 8f8b7281..9e61ee15 100644 --- a/test/Spring/Spring.Data.NHibernate5.Tests/Data/NHibernate/DelegatingLocalSessionFactoryObjectTests.cs +++ b/test/Spring/Spring.Data.NHibernate5.Tests/Data/NHibernate/DelegatingLocalSessionFactoryObjectTests.cs @@ -1,12 +1,8 @@ using NUnit.Framework; - using NhCfg = NHibernate.Cfg; using Spring.Data.Common; - using NHibernate.Dialect; - using Spring.Context.Support; - using NHibernate.Connection; using NHibernate.Driver; diff --git a/test/Spring/Spring.Data.NHibernate5.Tests/Data/NHibernate/HibernateTransactionManagerTests.cs b/test/Spring/Spring.Data.NHibernate5.Tests/Data/NHibernate/HibernateTransactionManagerTests.cs index eb0c2ade..96686223 100644 --- a/test/Spring/Spring.Data.NHibernate5.Tests/Data/NHibernate/HibernateTransactionManagerTests.cs +++ b/test/Spring/Spring.Data.NHibernate5.Tests/Data/NHibernate/HibernateTransactionManagerTests.cs @@ -17,14 +17,10 @@ using System.Collections; using System.Data; using System.Data.Common; - using FakeItEasy; - using NHibernate; using NHibernate.Cfg; - using NUnit.Framework; - using Spring.Dao; using Spring.Data.Common; using Spring.Data.Support; @@ -116,7 +112,6 @@ namespace Spring.Data.NHibernate A.CallTo(() => session.Close()).MustHaveHappenedOnceExactly(); } - [Test] public void TransactionRollback() { @@ -517,7 +512,6 @@ namespace Spring.Data.NHibernate } } - public class TransactionCommitTxCallback : ITransactionCallback { private ISessionFactory sfProxy; @@ -529,7 +523,6 @@ namespace Spring.Data.NHibernate this.provider = provider; } - public object DoInTransaction(ITransactionStatus status) { Assert.IsTrue(TransactionSynchronizationManager.HasResource(sfProxy), "Has thread session"); @@ -590,7 +583,6 @@ namespace Spring.Data.NHibernate this.sf = sf; } - public object DoInTransaction(ITransactionStatus status) { Assert.IsTrue(TransactionSynchronizationManager.HasResource(sf), "Has thread session"); @@ -618,7 +610,6 @@ namespace Spring.Data.NHibernate this.list = list; } - public object DoInTransaction(ITransactionStatus status) { Assert.IsTrue(TransactionSynchronizationManager.HasResource(sf), "Has thread session"); @@ -748,7 +739,6 @@ namespace Spring.Data.NHibernate } } - public class ParticipatingTransactionWithWithNotSupportedTxCallback : ITransactionCallback { private TransactionTemplate tt; @@ -835,7 +825,6 @@ namespace Spring.Data.NHibernate } } - public class TransactionWithPropagationSupportsAndInnerTransactionTxCallback : ITransactionCallback { private TransactionTemplate tt; diff --git a/test/Spring/Spring.Data.NHibernate5.Tests/Data/NHibernate/ISimpleService.cs b/test/Spring/Spring.Data.NHibernate5.Tests/Data/NHibernate/ISimpleService.cs index ce00b58b..070ed14d 100644 --- a/test/Spring/Spring.Data.NHibernate5.Tests/Data/NHibernate/ISimpleService.cs +++ b/test/Spring/Spring.Data.NHibernate5.Tests/Data/NHibernate/ISimpleService.cs @@ -1,5 +1,5 @@ /* - * Created by: + * Created by: * Created: Monday, July 16, 2007 */ @@ -9,4 +9,4 @@ namespace Spring.Data.NHibernate { void DoWork(TestObject testObject); } -} \ No newline at end of file +} diff --git a/test/Spring/Spring.Data.NHibernate5.Tests/Data/NHibernate/ITestObjectDao.cs b/test/Spring/Spring.Data.NHibernate5.Tests/Data/NHibernate/ITestObjectDao.cs index 906e9aaf..d0d14a2b 100644 --- a/test/Spring/Spring.Data.NHibernate5.Tests/Data/NHibernate/ITestObjectDao.cs +++ b/test/Spring/Spring.Data.NHibernate5.Tests/Data/NHibernate/ITestObjectDao.cs @@ -2,13 +2,13 @@ /* * Copyright � 2002-2011 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. @@ -18,23 +18,23 @@ #endregion - namespace Spring.Data.NHibernate { /// /// TODO: /// /// Mark Pollack (.NET) - public interface ITestObjectDao + public interface ITestObjectDao { void Create(TestObject to); void Update(TestObject to); void Delete(TestObject to); + TestObject FindByName(string name); + //IList FindAll(); //int GetCount(); //int GetCountByDelegate(); void CreateUpdateRollback(TestObject to); - } -} \ No newline at end of file +} diff --git a/test/Spring/Spring.Data.NHibernate5.Tests/Data/NHibernate/LocalSessionFactoryObjectTests.cs b/test/Spring/Spring.Data.NHibernate5.Tests/Data/NHibernate/LocalSessionFactoryObjectTests.cs index 98b2e28c..f30658e2 100644 --- a/test/Spring/Spring.Data.NHibernate5.Tests/Data/NHibernate/LocalSessionFactoryObjectTests.cs +++ b/test/Spring/Spring.Data.NHibernate5.Tests/Data/NHibernate/LocalSessionFactoryObjectTests.cs @@ -22,11 +22,9 @@ using NHibernate; using NHibernate.Connection; using NHibernate.Dialect; using NHibernate.Driver; - using Spring.Context.Support; using Spring.Data.Common; using Spring.Data.NHibernate.Bytecode; - using NUnit.Framework; using Environment = NHibernate.Cfg.Environment; @@ -39,7 +37,6 @@ namespace Spring.Data.NHibernate [TestFixture] public class LocalSessionFactoryObjectTests { - [Test] public void LocalSessionFactoryObjectWithDbProviderAndProperties() { @@ -66,11 +63,11 @@ namespace Spring.Data.NHibernate Assert.AreEqual(sfo.Configuration.Properties[Environment.Dialect], typeof(MsSql2000Dialect).AssemblyQualifiedName); Assert.Throws(() => - { - var x = - sfo.Configuration.Properties[Environment.ProxyFactoryFactoryClass]; - }, "ProxyFactoryFactory should not be explicitly set!"); - + { + var x = + sfo.Configuration.Properties[Environment.ProxyFactoryFactoryClass]; + }, "ProxyFactoryFactory should not be explicitly set!"); + Assert.AreNotEqual(typeof(BytecodeProvider), Environment.BytecodeProvider.GetType(), "default IBytecodeProvider should not be Spring's BytecodeProvider!"); } @@ -80,7 +77,6 @@ namespace Spring.Data.NHibernate LocalSessionFactoryObject sfo = new LocalSessionFactoryObject(); sfo.MappingResources = new string[] { "mapping.hbm.xml" }; Assert.Throws(() => sfo.AfterPropertiesSet()); - } [Test] diff --git a/test/Spring/Spring.Data.NHibernate5.Tests/Data/NHibernate/NHTestObjectDao.cs b/test/Spring/Spring.Data.NHibernate5.Tests/Data/NHibernate/NHTestObjectDao.cs index 50dd950d..3fa2988f 100644 --- a/test/Spring/Spring.Data.NHibernate5.Tests/Data/NHibernate/NHTestObjectDao.cs +++ b/test/Spring/Spring.Data.NHibernate5.Tests/Data/NHibernate/NHTestObjectDao.cs @@ -2,13 +2,13 @@ /* * Copyright � 2002-2011 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. @@ -21,9 +21,7 @@ #region Imports using System.Collections; - using NHibernate.Type; - using Spring.Data.NHibernate.Support; #endregion @@ -70,7 +68,7 @@ namespace Spring.Data.NHibernate "select from TestObject as to where to.Name=?", name, TypeFactory.GetStringType(50) - ); + ); if (result.Count > 0) { diff --git a/test/Spring/Spring.Data.NHibernate5.Tests/Data/NHibernate/SessionFactoryUtilsTests.cs b/test/Spring/Spring.Data.NHibernate5.Tests/Data/NHibernate/SessionFactoryUtilsTests.cs index 796bec1e..99df40b9 100644 --- a/test/Spring/Spring.Data.NHibernate5.Tests/Data/NHibernate/SessionFactoryUtilsTests.cs +++ b/test/Spring/Spring.Data.NHibernate5.Tests/Data/NHibernate/SessionFactoryUtilsTests.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2010 the original author or authors. + * Copyright � 2002-2010 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. @@ -19,15 +19,11 @@ #endregion using System.Data.SqlClient; - using FakeItEasy; - using NHibernate.Connection; using NHibernate.Driver; using NHibernate.Engine; - using NUnit.Framework; - using Spring.Data.Common; namespace Spring.Data.NHibernate @@ -57,4 +53,4 @@ namespace Spring.Data.NHibernate Assert.AreEqual(typeof(SqlCommand), provider.DbMetadata.CommandType); } } -} \ No newline at end of file +} diff --git a/test/Spring/Spring.Data.NHibernate5.Tests/Data/NHibernate/SimpleService.cs b/test/Spring/Spring.Data.NHibernate5.Tests/Data/NHibernate/SimpleService.cs index be82530d..fcb39653 100644 --- a/test/Spring/Spring.Data.NHibernate5.Tests/Data/NHibernate/SimpleService.cs +++ b/test/Spring/Spring.Data.NHibernate5.Tests/Data/NHibernate/SimpleService.cs @@ -18,7 +18,6 @@ #endregion - using Spring.Transaction.Interceptor; namespace Spring.Data.NHibernate @@ -27,7 +26,6 @@ namespace Spring.Data.NHibernate { private ITestObjectDao testObjectDao; - public ITestObjectDao TestObjectDao { get { return testObjectDao; } @@ -40,4 +38,4 @@ namespace Spring.Data.NHibernate testObjectDao.Create(testObject); } } -} \ No newline at end of file +} diff --git a/test/Spring/Spring.Data.NHibernate5.Tests/Data/NHibernate/Support/ConfigSectionSessionScopeSettingsTests.cs b/test/Spring/Spring.Data.NHibernate5.Tests/Data/NHibernate/Support/ConfigSectionSessionScopeSettingsTests.cs index c1b34f19..f338e500 100644 --- a/test/Spring/Spring.Data.NHibernate5.Tests/Data/NHibernate/Support/ConfigSectionSessionScopeSettingsTests.cs +++ b/test/Spring/Spring.Data.NHibernate5.Tests/Data/NHibernate/Support/ConfigSectionSessionScopeSettingsTests.cs @@ -21,10 +21,8 @@ #region Imports using FakeItEasy; - using NHibernate; using NUnit.Framework; - using Spring.Context.Support; using Spring.Objects.Factory.Config; @@ -57,7 +55,7 @@ namespace Spring.Data.NHibernate.Support ContextRegistry.Clear(); ContextRegistry.RegisterContext(appCtx); - ConfigSectionSessionScopeSettings settings = new ConfigSectionSessionScopeSettings(this.GetType(), (IVariableSource)null); + ConfigSectionSessionScopeSettings settings = new ConfigSectionSessionScopeSettings(this.GetType(), (IVariableSource) null); Assert.AreEqual(expectedSessionFactory, settings.SessionFactory); Assert.AreEqual(expectedEntityInterceptor, settings.EntityInterceptor); @@ -71,7 +69,7 @@ namespace Spring.Data.NHibernate.Support string SESSIONFACTORY_OBJECTNAME = "SessionFactory"; string ENTITYINTERCEPTOR_OBJECTNAME = "EntityInterceptor"; - ISessionFactory expectedSessionFactory = A.Fake(); + ISessionFactory expectedSessionFactory = A.Fake(); IInterceptor expectedEntityInterceptor = A.Fake(); bool expectedSingleSession = false; FlushMode expectedDefaultFlushMode = FlushMode.Auto; @@ -87,19 +85,18 @@ namespace Spring.Data.NHibernate.Support // simulate config section string thisTypeName = this.GetType().FullName; DictionaryVariableSource variableSource = new DictionaryVariableSource() - .Add(thisTypeName + ".SessionFactoryObjectName", SESSIONFACTORY_OBJECTNAME) - .Add(thisTypeName + ".EntityInterceptorObjectName", ENTITYINTERCEPTOR_OBJECTNAME) - .Add(thisTypeName + ".SingleSession", expectedSingleSession.ToString().ToLower() ) // case insensitive! - .Add(thisTypeName + ".DefaultFlushMode", expectedDefaultFlushMode.ToString().ToLower() ) // case insensitive! + .Add(thisTypeName + ".SessionFactoryObjectName", SESSIONFACTORY_OBJECTNAME) + .Add(thisTypeName + ".EntityInterceptorObjectName", ENTITYINTERCEPTOR_OBJECTNAME) + .Add(thisTypeName + ".SingleSession", expectedSingleSession.ToString().ToLower()) // case insensitive! + .Add(thisTypeName + ".DefaultFlushMode", expectedDefaultFlushMode.ToString().ToLower()) // case insensitive! ; - ConfigSectionSessionScopeSettings settings = new ConfigSectionSessionScopeSettings(this.GetType(), variableSource); - Assert.AreEqual( expectedSessionFactory, settings.SessionFactory ); - Assert.AreEqual( expectedEntityInterceptor, settings.EntityInterceptor ); - Assert.AreEqual( expectedSingleSession, settings.SingleSession ); - Assert.AreEqual( expectedDefaultFlushMode, settings.DefaultFlushMode ); + Assert.AreEqual(expectedSessionFactory, settings.SessionFactory); + Assert.AreEqual(expectedEntityInterceptor, settings.EntityInterceptor); + Assert.AreEqual(expectedSingleSession, settings.SingleSession); + Assert.AreEqual(expectedDefaultFlushMode, settings.DefaultFlushMode); } } -} \ No newline at end of file +} diff --git a/test/Spring/Spring.Data.NHibernate5.Tests/Data/NHibernate/Support/SessionScopeSettingsTests.cs b/test/Spring/Spring.Data.NHibernate5.Tests/Data/NHibernate/Support/SessionScopeSettingsTests.cs index 4c12f5dd..93e210c8 100644 --- a/test/Spring/Spring.Data.NHibernate5.Tests/Data/NHibernate/Support/SessionScopeSettingsTests.cs +++ b/test/Spring/Spring.Data.NHibernate5.Tests/Data/NHibernate/Support/SessionScopeSettingsTests.cs @@ -19,9 +19,7 @@ #endregion using FakeItEasy; - using NHibernate; - using NUnit.Framework; namespace Spring.Data.NHibernate.Support @@ -46,7 +44,6 @@ namespace Spring.Data.NHibernate.Support private readonly ISessionFactory sessionFactory; private readonly IInterceptor entityInterceptor; - public LazyResolvingSessionScopeSettings(ISessionFactory sessionFactory, IInterceptor entityInterceptor) : base() // note, that we're calling default ctor here { diff --git a/test/Spring/Spring.Data.NHibernate5.Tests/Data/NHibernate/Support/SessionScopeTests.cs b/test/Spring/Spring.Data.NHibernate5.Tests/Data/NHibernate/Support/SessionScopeTests.cs index aaa6f954..0de49231 100644 --- a/test/Spring/Spring.Data.NHibernate5.Tests/Data/NHibernate/Support/SessionScopeTests.cs +++ b/test/Spring/Spring.Data.NHibernate5.Tests/Data/NHibernate/Support/SessionScopeTests.cs @@ -21,12 +21,9 @@ #region Imports using FakeItEasy; - using NHibernate; using NUnit.Framework; - using Spring.Transaction.Support; - using static FakeItEasy.A; #endregion @@ -146,6 +143,7 @@ namespace Spring.Data.NHibernate.Support Assert.IsFalse(scope.IsOpen); Assert.IsFalse(scope.IsParticipating); } + Assert.IsFalse(scope.IsOpen); Assert.IsFalse(scope.IsParticipating); @@ -155,6 +153,7 @@ namespace Spring.Data.NHibernate.Support Assert.IsTrue(scope.IsOpen); Assert.IsFalse(scope.IsParticipating); } + // ensure dispose closes scope Assert.IsFalse(scope.IsOpen); Assert.IsFalse(scope.IsParticipating); @@ -179,6 +178,7 @@ namespace Spring.Data.NHibernate.Support Assert.IsFalse(scope.IsOpen); Assert.IsFalse(scope.IsParticipating); } + // ensure is closed Assert.IsFalse(scope.IsOpen); Assert.IsFalse(scope.IsParticipating); @@ -200,6 +200,7 @@ namespace Spring.Data.NHibernate.Support SessionHolder sessionHolder = TransactionSynchronizationManager.GetResource(expectedSessionFactory) as SessionHolder; Assert.IsNotNull(sessionHolder); } + // ensure scope is closed and sessionHolder is unregistered from TSM Assert.IsFalse(scope.IsOpen); Assert.IsFalse(TransactionSynchronizationManager.HasResource(expectedSessionFactory)); @@ -215,9 +216,10 @@ namespace Spring.Data.NHibernate.Support SessionScope scope = null; using (scope = new SessionScope(expectedSessionFactory, null, true, FlushMode.Auto, true)) { - SessionHolder sessionHolder = (SessionHolder)TransactionSynchronizationManager.GetResource(expectedSessionFactory); + SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager.GetResource(expectedSessionFactory); Assert.IsTrue(sessionHolder.ContainsSession(expectedSession)); } + // ensure scope is closed and sessionHolder is unregistered from TSM Assert.IsFalse(scope.IsOpen); Assert.IsFalse(TransactionSynchronizationManager.HasResource(expectedSessionFactory)); @@ -285,7 +287,7 @@ namespace Spring.Data.NHibernate.Support { TestSessionScopeSettings sss = Fake(options => options .CallsBaseMethods() - .WithArgumentsForConstructor(new[] {expectedSessionFactory}) + .WithArgumentsForConstructor(new[] { expectedSessionFactory }) ); ISession expectedSession = Fake(); sss.DefaultFlushMode = FlushMode.Never; diff --git a/test/Spring/Spring.Data.NHibernate5.Tests/Data/NHibernate/TestObject.cs b/test/Spring/Spring.Data.NHibernate5.Tests/Data/NHibernate/TestObject.cs index 855bf418..4a3ae518 100644 --- a/test/Spring/Spring.Data.NHibernate5.Tests/Data/NHibernate/TestObject.cs +++ b/test/Spring/Spring.Data.NHibernate5.Tests/Data/NHibernate/TestObject.cs @@ -2,13 +2,13 @@ /* * Copyright � 2002-2011 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. @@ -18,29 +18,29 @@ #endregion - namespace Spring.Data.NHibernate { /// /// TODO: /// /// Mark Pollack (.NET) - public class TestObject + public class TestObject { #region Fields + private int age; private string name; private int objectNumber; - + #endregion #region Constructor (s) + /// /// Initializes a new instance of the class. /// - public TestObject() + public TestObject() { - } #endregion @@ -70,6 +70,5 @@ namespace Spring.Data.NHibernate #region Methods #endregion - } -} \ No newline at end of file +} diff --git a/test/Spring/Spring.Data.NHibernate5.Tests/Data/NHibernate/TestObject.hbm.xml b/test/Spring/Spring.Data.NHibernate5.Tests/Data/NHibernate/TestObject.hbm.xml index 16395eea..08d86e5d 100644 --- a/test/Spring/Spring.Data.NHibernate5.Tests/Data/NHibernate/TestObject.hbm.xml +++ b/test/Spring/Spring.Data.NHibernate5.Tests/Data/NHibernate/TestObject.hbm.xml @@ -1,17 +1,17 @@ - + - - - - + + - - - + + + + + diff --git a/test/Spring/Spring.Data.NHibernate5.Tests/HibernateCompilerOptionsTests.cs b/test/Spring/Spring.Data.NHibernate5.Tests/HibernateCompilerOptionsTests.cs index 11427061..e180c7d5 100644 --- a/test/Spring/Spring.Data.NHibernate5.Tests/HibernateCompilerOptionsTests.cs +++ b/test/Spring/Spring.Data.NHibernate5.Tests/HibernateCompilerOptionsTests.cs @@ -26,18 +26,17 @@ using Spring.Data.NHibernate; #endregion -namespace Spring +namespace Spring; + +/// Test that the assembly is built with the correct DebugAttributes in release and debug builds. +/// +/// Mark Pollack +[TestFixture] +public sealed class HibernateCompilerOptionTests : CompilerOptionsTests { - /// Test that the assembly is built with the correct DebugAttributes in release and debug builds. - /// - /// Mark Pollack - [TestFixture] - public sealed class HibernateCompilerOptionTests : CompilerOptionsTests + [OneTimeSetUp] + public void FixtureSetUp() { - [OneTimeSetUp] - public void FixtureSetUp() - { - AssemblyToCheck = Assembly.GetAssembly(typeof (HibernateObjectRetrievalFailureException)); - } + AssemblyToCheck = Assembly.GetAssembly(typeof(HibernateObjectRetrievalFailureException)); } -} \ No newline at end of file +} diff --git a/test/Spring/Spring.Data.NHibernate5.Tests/HibernateExceptionTests.cs b/test/Spring/Spring.Data.NHibernate5.Tests/HibernateExceptionTests.cs index 152debdb..36174f67 100644 --- a/test/Spring/Spring.Data.NHibernate5.Tests/HibernateExceptionTests.cs +++ b/test/Spring/Spring.Data.NHibernate5.Tests/HibernateExceptionTests.cs @@ -21,25 +21,23 @@ #region Imports using System.Reflection; - using NUnit.Framework; using Spring.Data.NHibernate; #endregion -namespace Spring +namespace Spring; + +/// +/// Unit tests for all of the exception classes in the Spring.Data.Hibernernate20 library... +/// +/// Rick Evans +[TestFixture] +public sealed class HibernateExceptionTests : ExceptionsTest { - /// - /// Unit tests for all of the exception classes in the Spring.Data.Hibernernate20 library... - /// - /// Rick Evans - [TestFixture] - public sealed class HibernateExceptionTests : ExceptionsTest + [OneTimeSetUp] + public void FixtureSetUp() { - [OneTimeSetUp] - public void FixtureSetUp () - { - AssemblyToCheck = Assembly.GetAssembly(typeof(HibernateObjectRetrievalFailureException)); - } + AssemblyToCheck = Assembly.GetAssembly(typeof(HibernateObjectRetrievalFailureException)); } } diff --git a/test/Spring/Spring.Data.Tests/App.config b/test/Spring/Spring.Data.Tests/App.config index 8f29c517..737705bc 100644 --- a/test/Spring/Spring.Data.Tests/App.config +++ b/test/Spring/Spring.Data.Tests/App.config @@ -21,31 +21,31 @@ limitations under the License.
- + -
+
- -
+ +
- + - + - + @@ -62,17 +62,17 @@ limitations under the License. - + - + diff --git a/test/Spring/Spring.Data.Tests/Dao/Attributes/PersistenceExceptionTranslationAdvisorTests.cs b/test/Spring/Spring.Data.Tests/Dao/Attributes/PersistenceExceptionTranslationAdvisorTests.cs index 67758758..ee331ad9 100644 --- a/test/Spring/Spring.Data.Tests/Dao/Attributes/PersistenceExceptionTranslationAdvisorTests.cs +++ b/test/Spring/Spring.Data.Tests/Dao/Attributes/PersistenceExceptionTranslationAdvisorTests.cs @@ -26,201 +26,200 @@ using Spring.Stereotype; #pragma warning disable SYSLIB0051 -namespace Spring.Dao.Attributes +namespace Spring.Dao.Attributes; + +/// +/// This class contains tests for +/// +/// Mark Pollack +/// $Id:$ +[TestFixture] +public class PersistenceExceptionTranslationAdvisorTests { - /// - /// This class contains tests for - /// - /// Mark Pollack - /// $Id:$ - [TestFixture] - public class PersistenceExceptionTranslationAdvisorTests + private IndexOutOfRangeException doNotTranslate = new IndexOutOfRangeException(); + + private PersistenceException persistenceException = new PersistenceException(); + + [SetUp] + public void Setup() { + } - private IndexOutOfRangeException doNotTranslate = new IndexOutOfRangeException(); + [Test] + public void NoTranslationNeeded() + { + RepositoryInterfaceImpl target = new RepositoryInterfaceImpl(); + IRepositoryInterface ri = CreateProxy(target); - private PersistenceException persistenceException = new PersistenceException(); + ri.Throws(); - [SetUp] - public void Setup() + target.Behavior = persistenceException; + + try { - } - - [Test] - public void NoTranslationNeeded() - { - RepositoryInterfaceImpl target = new RepositoryInterfaceImpl(); - IRepositoryInterface ri = CreateProxy(target); - ri.Throws(); - - target.Behavior = persistenceException; - - try - { - ri.Throws(); - Assert.Fail(); - } catch (Exception ex) - { - Assert.AreSame(persistenceException, ex); - } + Assert.Fail(); } - - [Test] - public void TranslationNotNeededForTheseExceptions() + catch (Exception ex) { - RepositoryInterfaceImpl target = new StereotypedRepositoryInterfaceImpl(); - IRepositoryInterface ri = CreateProxy(target); + Assert.AreSame(persistenceException, ex); + } + } + [Test] + public void TranslationNotNeededForTheseExceptions() + { + RepositoryInterfaceImpl target = new StereotypedRepositoryInterfaceImpl(); + IRepositoryInterface ri = CreateProxy(target); + + ri.Throws(); + + target.Behavior = doNotTranslate; + try + { ri.Throws(); - - target.Behavior = doNotTranslate; - try - { - ri.Throws(); - Assert.Fail(); - } catch (Exception ex) - { - Assert.AreSame(doNotTranslate, ex); - } + Assert.Fail(); } - - [Test] - public void TranslationNeededForTheseExceptions() + catch (Exception ex) { - DoTestTranslationNeededForTheseExceptions((new StereotypedRepositoryInterfaceImpl())); - } - - [Test] - public void TranslationNeededForTheseExceptionsOnSuperclass() - { - DoTestTranslationNeededForTheseExceptions((new MyStereotypedRepositoryInterfaceImpl())); - } - - [Test] - public void TranslationNeededForTheseExceptionsOnInterface() - { - DoTestTranslationNeededForTheseExceptions((new MyInterfaceStereotypedRepositoryInterfaceImpl())); - } - - [Test] - public void TranslationNeededForTheseExceptionsOnInheritedInterface() - { - DoTestTranslationNeededForTheseExceptions((new MyInterfaceInheritedStereotypedRepositoryInterfaceImpl())); - } - - private void DoTestTranslationNeededForTheseExceptions(RepositoryInterfaceImpl target) - { - IRepositoryInterface ri = CreateProxy(target); - target.Behavior = persistenceException; - try - { - ri.Throws(); - Assert.Fail(); - } catch (DataAccessException ex) - { - //Expected - Assert.AreSame(persistenceException, ex.InnerException); - } catch (PersistenceException) - { - Assert.Fail("Should have been translated"); - } - } - - - private IRepositoryInterface CreateProxy(RepositoryInterfaceImpl target) - { - MapPersistenceExceptionTranslator mpet = new MapPersistenceExceptionTranslator(); - mpet.AddTranslation(persistenceException, new InvalidDataAccessApiUsageException("", persistenceException)); - ProxyFactory pf = new ProxyFactory(target); - pf.AddInterface(typeof(IRepositoryInterface)); - AddPersistenceExceptionTranslation(pf, mpet); - return (IRepositoryInterface) pf.GetProxy(); - } - - protected virtual void AddPersistenceExceptionTranslation(ProxyFactory pf, IPersistenceExceptionTranslator pet) - { - pf.AddAdvisor(new PersistenceExceptionTranslationAdvisor(pet, typeof(RepositoryAttribute))); + Assert.AreSame(doNotTranslate, ex); } } - - - - - [Repository] - public class StereotypedRepositoryInterfaceImpl : RepositoryInterfaceImpl + [Test] + public void TranslationNeededForTheseExceptions() { - // Extends above class just to add repository annotation + DoTestTranslationNeededForTheseExceptions((new StereotypedRepositoryInterfaceImpl())); } - public class MyStereotypedRepositoryInterfaceImpl : StereotypedRepositoryInterfaceImpl { - } - - [Repository] - public interface IStereotypedInterface + [Test] + public void TranslationNeededForTheseExceptionsOnSuperclass() { - + DoTestTranslationNeededForTheseExceptions((new MyStereotypedRepositoryInterfaceImpl())); } - public class MyInterfaceStereotypedRepositoryInterfaceImpl : RepositoryInterfaceImpl, IStereotypedInterface + + [Test] + public void TranslationNeededForTheseExceptionsOnInterface() { + DoTestTranslationNeededForTheseExceptions((new MyInterfaceStereotypedRepositoryInterfaceImpl())); } - public interface IStereotypedInheritingInterface : IStereotypedInterface { - } - - public class MyInterfaceInheritedStereotypedRepositoryInterfaceImpl : RepositoryInterfaceImpl, IStereotypedInheritingInterface { - } - - public class RepositoryInterfaceImpl : IRepositoryInterface + [Test] + public void TranslationNeededForTheseExceptionsOnInheritedInterface() { - private Exception ex; - - - public Exception Behavior - { - set { ex = value; } - } - - public void Throws() - { - if (ex != null) - { - throw ex; - } - } + DoTestTranslationNeededForTheseExceptions((new MyInterfaceInheritedStereotypedRepositoryInterfaceImpl())); } - public interface IRepositoryInterface + private void DoTestTranslationNeededForTheseExceptions(RepositoryInterfaceImpl target) { - void Throws(); + IRepositoryInterface ri = CreateProxy(target); + target.Behavior = persistenceException; + try + { + ri.Throws(); + Assert.Fail(); + } + catch (DataAccessException ex) + { + //Expected + Assert.AreSame(persistenceException, ex.InnerException); + } + catch (PersistenceException) + { + Assert.Fail("Should have been translated"); + } } - [Serializable] - public class PersistenceException : ApplicationException + private IRepositoryInterface CreateProxy(RepositoryInterfaceImpl target) { - #region Constructor (s) / Destructor - - public PersistenceException() - { - } - - public PersistenceException(string message) - : base(message) - { - } - - public PersistenceException(string message, Exception rootCause) - : base(message, rootCause) - { - } - - protected PersistenceException( - SerializationInfo info, StreamingContext context) - : base(info, context) - { - } - #endregion + MapPersistenceExceptionTranslator mpet = new MapPersistenceExceptionTranslator(); + mpet.AddTranslation(persistenceException, new InvalidDataAccessApiUsageException("", persistenceException)); + ProxyFactory pf = new ProxyFactory(target); + pf.AddInterface(typeof(IRepositoryInterface)); + AddPersistenceExceptionTranslation(pf, mpet); + return (IRepositoryInterface) pf.GetProxy(); } + protected virtual void AddPersistenceExceptionTranslation(ProxyFactory pf, IPersistenceExceptionTranslator pet) + { + pf.AddAdvisor(new PersistenceExceptionTranslationAdvisor(pet, typeof(RepositoryAttribute))); + } +} + +[Repository] +public class StereotypedRepositoryInterfaceImpl : RepositoryInterfaceImpl +{ + // Extends above class just to add repository annotation +} + +public class MyStereotypedRepositoryInterfaceImpl : StereotypedRepositoryInterfaceImpl +{ +} + +[Repository] +public interface IStereotypedInterface +{ +} + +public class MyInterfaceStereotypedRepositoryInterfaceImpl : RepositoryInterfaceImpl, IStereotypedInterface +{ +} + +public interface IStereotypedInheritingInterface : IStereotypedInterface +{ +} + +public class MyInterfaceInheritedStereotypedRepositoryInterfaceImpl : RepositoryInterfaceImpl, IStereotypedInheritingInterface +{ +} + +public class RepositoryInterfaceImpl : IRepositoryInterface +{ + private Exception ex; + + public Exception Behavior + { + set { ex = value; } + } + + public void Throws() + { + if (ex != null) + { + throw ex; + } + } +} + +public interface IRepositoryInterface +{ + void Throws(); +} + +[Serializable] +public class PersistenceException : ApplicationException +{ + #region Constructor (s) / Destructor + + public PersistenceException() + { + } + + public PersistenceException(string message) + : base(message) + { + } + + public PersistenceException(string message, Exception rootCause) + : base(message, rootCause) + { + } + + protected PersistenceException( + SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + + #endregion } diff --git a/test/Spring/Spring.Data.Tests/Dao/Attributes/PersistenceExceptionTranslationInterceptorTests.cs b/test/Spring/Spring.Data.Tests/Dao/Attributes/PersistenceExceptionTranslationInterceptorTests.cs index c36ff0ba..8c0b6ce9 100644 --- a/test/Spring/Spring.Data.Tests/Dao/Attributes/PersistenceExceptionTranslationInterceptorTests.cs +++ b/test/Spring/Spring.Data.Tests/Dao/Attributes/PersistenceExceptionTranslationInterceptorTests.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -28,28 +28,25 @@ using Spring.Util; #endregion -namespace Spring.Dao.Attributes +namespace Spring.Dao.Attributes; + +/// +/// Tests for standalone usage of a PersistenceExceptionTranslationInterceptor, +/// as explicit advice bean in a BeanFactory rather than applied as part of +/// as explicit advice bean in a BeanFactory rather than applied as part of +/// +/// Mark Pollack +/// Mark Pollack (.NET) +public class PersistenceExceptionTranslationInterceptorTests : PersistenceExceptionTranslationAdvisorTests { - /// - /// Tests for standalone usage of a PersistenceExceptionTranslationInterceptor, - /// as explicit advice bean in a BeanFactory rather than applied as part of - /// as explicit advice bean in a BeanFactory rather than applied as part of - /// - /// Mark Pollack - /// Mark Pollack (.NET) - public class PersistenceExceptionTranslationInterceptorTests : PersistenceExceptionTranslationAdvisorTests + protected override void AddPersistenceExceptionTranslation(ProxyFactory pf, IPersistenceExceptionTranslator pet) { - - protected override void AddPersistenceExceptionTranslation(ProxyFactory pf, IPersistenceExceptionTranslator pet) + if (AttributeUtils.FindAttribute(pf.TargetType, typeof(RepositoryAttribute)) != null) { - if (AttributeUtils.FindAttribute(pf.TargetType, typeof(RepositoryAttribute)) != null) - { - DefaultListableObjectFactory of = new DefaultListableObjectFactory(); - of.RegisterObjectDefinition("peti", new RootObjectDefinition(typeof(PersistenceExceptionTranslationInterceptor))); - of.RegisterSingleton("pet", pet); - pf.AddAdvice((PersistenceExceptionTranslationInterceptor) of.GetObject("peti")); - - } + DefaultListableObjectFactory of = new DefaultListableObjectFactory(); + of.RegisterObjectDefinition("peti", new RootObjectDefinition(typeof(PersistenceExceptionTranslationInterceptor))); + of.RegisterSingleton("pet", pet); + pf.AddAdvice((PersistenceExceptionTranslationInterceptor) of.GetObject("peti")); } } } diff --git a/test/Spring/Spring.Data.Tests/Dao/Attributes/PersistenceExceptionTranslationPostProcessorTests.cs b/test/Spring/Spring.Data.Tests/Dao/Attributes/PersistenceExceptionTranslationPostProcessorTests.cs index 5beba1da..d45b7ccb 100644 --- a/test/Spring/Spring.Data.Tests/Dao/Attributes/PersistenceExceptionTranslationPostProcessorTests.cs +++ b/test/Spring/Spring.Data.Tests/Dao/Attributes/PersistenceExceptionTranslationPostProcessorTests.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -30,72 +30,72 @@ using Spring.Objects.Factory.Support; #endregion -namespace Spring.Dao.Attributes +namespace Spring.Dao.Attributes; + +/// +/// Unit tests for PersistenceExceptionTranslationPostProcessor. Does not test +/// translation; there are separate unit tests for the Spring AOP Advisor. +/// Just checks whether proxying occurs correctly, +/// +/// Rod Johnson +/// Mark Pollack (.NET) +/// $Id:$ +[TestFixture] +public class PersistenceExceptionTranslationPostProcessorTests { - /// - /// Unit tests for PersistenceExceptionTranslationPostProcessor. Does not test - /// translation; there are separate unit tests for the Spring AOP Advisor. - /// Just checks whether proxying occurs correctly, - /// - /// Rod Johnson - /// Mark Pollack (.NET) - /// $Id:$ - [TestFixture] - public class PersistenceExceptionTranslationPostProcessorTests + [SetUp] + public void Setup() { - [SetUp] - public void Setup() - { - } + } - [Test] - public void FailsWithNoPersistenceExceptionTranslators() + [Test] + public void FailsWithNoPersistenceExceptionTranslators() + { + GenericApplicationContext gac = new GenericApplicationContext(); + gac.RegisterObjectDefinition("translator", new RootObjectDefinition(typeof(PersistenceExceptionTranslationPostProcessor))); + gac.RegisterObjectDefinition("proxied", new RootObjectDefinition(typeof(StereotypedRepositoryInterfaceImpl))); + try { - GenericApplicationContext gac = new GenericApplicationContext(); - gac.RegisterObjectDefinition("translator", new RootObjectDefinition(typeof(PersistenceExceptionTranslationPostProcessor))); - gac.RegisterObjectDefinition("proxied", new RootObjectDefinition(typeof(StereotypedRepositoryInterfaceImpl))); - try - { - gac.Refresh(); - Assert.Fail("Should fail with no translators"); - } catch (ObjectsException) - { - // expected. - } - } - - [Test] - public void ProxiesCorrectly() - { - GenericApplicationContext gac = new GenericApplicationContext(); - gac.RegisterObjectDefinition("translator", new RootObjectDefinition(typeof(PersistenceExceptionTranslationPostProcessor))); - gac.RegisterObjectDefinition("notProxied", new RootObjectDefinition(typeof(RepositoryInterfaceImpl))); - gac.RegisterObjectDefinition("proxied", - new RootObjectDefinition(typeof (StereotypedRepositoryInterfaceImpl))); - gac.RegisterObjectDefinition("chainedTranslator", - new RootObjectDefinition(typeof (ChainedPersistenceExceptionTranslator))); gac.Refresh(); - - IRepositoryInterface shouldNotBeProxied = (IRepositoryInterface) gac.GetObject("notProxied"); - Assert.IsFalse(AopUtils.IsAopProxy(shouldNotBeProxied)); - - IRepositoryInterface shouldBeProxied = (IRepositoryInterface) gac.GetObject("proxied"); - Assert.IsTrue(AopUtils.IsAopProxy(shouldBeProxied)); - - CheckWillTranslateExceptions(shouldBeProxied); - + Assert.Fail("Should fail with no translators"); } - - private void CheckWillTranslateExceptions(object o) + catch (ObjectsException) { - IAdvised advised = o as IAdvised; - Assert.IsNotNull(advised); - foreach (IAdvisor advisor in advised.Advisors) - { - PersistenceExceptionTranslationAdvisor peta = advisor as PersistenceExceptionTranslationAdvisor; - if (peta != null) return; - } - Assert.Fail("No translation"); + // expected. } } + + [Test] + public void ProxiesCorrectly() + { + GenericApplicationContext gac = new GenericApplicationContext(); + gac.RegisterObjectDefinition("translator", new RootObjectDefinition(typeof(PersistenceExceptionTranslationPostProcessor))); + gac.RegisterObjectDefinition("notProxied", new RootObjectDefinition(typeof(RepositoryInterfaceImpl))); + gac.RegisterObjectDefinition("proxied", + new RootObjectDefinition(typeof(StereotypedRepositoryInterfaceImpl))); + gac.RegisterObjectDefinition("chainedTranslator", + new RootObjectDefinition(typeof(ChainedPersistenceExceptionTranslator))); + gac.Refresh(); + + IRepositoryInterface shouldNotBeProxied = (IRepositoryInterface) gac.GetObject("notProxied"); + Assert.IsFalse(AopUtils.IsAopProxy(shouldNotBeProxied)); + + IRepositoryInterface shouldBeProxied = (IRepositoryInterface) gac.GetObject("proxied"); + Assert.IsTrue(AopUtils.IsAopProxy(shouldBeProxied)); + + CheckWillTranslateExceptions(shouldBeProxied); + } + + private void CheckWillTranslateExceptions(object o) + { + IAdvised advised = o as IAdvised; + Assert.IsNotNull(advised); + foreach (IAdvisor advisor in advised.Advisors) + { + PersistenceExceptionTranslationAdvisor peta = advisor as PersistenceExceptionTranslationAdvisor; + if (peta != null) return; + } + + Assert.Fail("No translation"); + } } diff --git a/test/Spring/Spring.Data.Tests/Dao/IncorrectResultSizeDataAccessExceptionTests.cs b/test/Spring/Spring.Data.Tests/Dao/IncorrectResultSizeDataAccessExceptionTests.cs index 25645794..4445b36c 100644 --- a/test/Spring/Spring.Data.Tests/Dao/IncorrectResultSizeDataAccessExceptionTests.cs +++ b/test/Spring/Spring.Data.Tests/Dao/IncorrectResultSizeDataAccessExceptionTests.cs @@ -1,15 +1,15 @@ using NUnit.Framework; -namespace Spring.Dao + +namespace Spring.Dao; + +[TestFixture] +public class IncorrectResultSizeDataAccessExceptionTests { - [TestFixture] - public class IncorrectResultSizeDataAccessExceptionTests - { - [Test] - public void SizeGetter( ) - { - IncorrectResultSizeDataAccessException ex = new IncorrectResultSizeDataAccessException( 1, 4 ); - Assert.AreEqual( 1, ex.ExpectedSize ); - Assert.AreEqual( 4, ex.ActualSize ); - } - } -} \ No newline at end of file + [Test] + public void SizeGetter() + { + IncorrectResultSizeDataAccessException ex = new IncorrectResultSizeDataAccessException(1, 4); + Assert.AreEqual(1, ex.ExpectedSize); + Assert.AreEqual(4, ex.ActualSize); + } +} diff --git a/test/Spring/Spring.Data.Tests/Dao/IncorrectUpdateSemanticsDataAccessExceptionTests.cs b/test/Spring/Spring.Data.Tests/Dao/IncorrectUpdateSemanticsDataAccessExceptionTests.cs index 514d8d10..e878ee32 100644 --- a/test/Spring/Spring.Data.Tests/Dao/IncorrectUpdateSemanticsDataAccessExceptionTests.cs +++ b/test/Spring/Spring.Data.Tests/Dao/IncorrectUpdateSemanticsDataAccessExceptionTests.cs @@ -1,24 +1,25 @@ using System.Runtime.Serialization; using NUnit.Framework; -namespace Spring.Dao + +namespace Spring.Dao; + +[TestFixture] +public class IncorrectUpdateSemanticsDataAccessExceptionTests { - [TestFixture] - public class IncorrectUpdateSemanticsDataAccessExceptionTests - { - [Serializable] - public class SampleException : IncorrectUpdateSemanticsDataAccessException - { - public SampleException() : base() {} - public SampleException( string message ) : base( message ) {} - public SampleException( string message, Exception inner ) : base( message, inner ) {} - protected SampleException( SerializationInfo info, StreamingContext context ) : base( info, context ) {} - public override bool DataWasUpdated - { - get - { - return true; - } - } - } - } + [Serializable] + public class SampleException : IncorrectUpdateSemanticsDataAccessException + { + public SampleException() : base() { } + public SampleException(string message) : base(message) { } + public SampleException(string message, Exception inner) : base(message, inner) { } + protected SampleException(SerializationInfo info, StreamingContext context) : base(info, context) { } + + public override bool DataWasUpdated + { + get + { + return true; + } + } + } } diff --git a/test/Spring/Spring.Data.Tests/Dao/Support/DataAccessUtilsTests.cs b/test/Spring/Spring.Data.Tests/Dao/Support/DataAccessUtilsTests.cs index 50413371..e5591b69 100644 --- a/test/Spring/Spring.Data.Tests/Dao/Support/DataAccessUtilsTests.cs +++ b/test/Spring/Spring.Data.Tests/Dao/Support/DataAccessUtilsTests.cs @@ -25,44 +25,42 @@ using NUnit.Framework; #endregion -namespace Spring.Dao.Support +namespace Spring.Dao.Support; + +/// +/// This class contains tests for +/// +/// Mark Pollack +/// $Id:$ +[TestFixture] +public class DataAccessUtilsTests { - /// - /// This class contains tests for - /// - /// Mark Pollack - /// $Id:$ - [TestFixture] - public class DataAccessUtilsTests + [SetUp] + public void Setup() { - [SetUp] - public void Setup() - { - } - - [Test] - public void Test() - { - } - - } - public class MapPersistenceExceptionTranslator : IPersistenceExceptionTranslator + [Test] + public void Test() { - #region IPersistenceExceptionTranslator Members - - private IDictionary translations = new Hashtable(); - - public void AddTranslation(Exception inException, Exception outException) - { - this.translations.Add(inException, outException); - } - public DataAccessException TranslateExceptionIfPossible(Exception ex) - { - return (DataAccessException)translations[ex]; - } - - #endregion } } + +public class MapPersistenceExceptionTranslator : IPersistenceExceptionTranslator +{ + #region IPersistenceExceptionTranslator Members + + private IDictionary translations = new Hashtable(); + + public void AddTranslation(Exception inException, Exception outException) + { + this.translations.Add(inException, outException); + } + + public DataAccessException TranslateExceptionIfPossible(Exception ex) + { + return (DataAccessException) translations[ex]; + } + + #endregion +} diff --git a/test/Spring/Spring.Data.Tests/Dao/UncategorizedDataAccessExceptionTests.cs b/test/Spring/Spring.Data.Tests/Dao/UncategorizedDataAccessExceptionTests.cs index 874d36d8..a26621ae 100644 --- a/test/Spring/Spring.Data.Tests/Dao/UncategorizedDataAccessExceptionTests.cs +++ b/test/Spring/Spring.Data.Tests/Dao/UncategorizedDataAccessExceptionTests.cs @@ -1,17 +1,17 @@ using System.Runtime.Serialization; using NUnit.Framework; -namespace Spring.Dao + +namespace Spring.Dao; + +[TestFixture] +public class UncategorizedDataAccessExceptionTests { - [TestFixture] - public class UncategorizedDataAccessExceptionTests - { - [Serializable] - public class SampleException : UncategorizedDataAccessException - { - public SampleException() : base() {} - public SampleException( string message ) : base( message ) {} - public SampleException( string message, Exception inner ) : base( message, inner ) {} - protected SampleException( SerializationInfo info, StreamingContext context ) : base( info, context ) {} - } - } + [Serializable] + public class SampleException : UncategorizedDataAccessException + { + public SampleException() : base() { } + public SampleException(string message) : base(message) { } + public SampleException(string message, Exception inner) : base(message, inner) { } + protected SampleException(SerializationInfo info, StreamingContext context) : base(info, context) { } + } } diff --git a/test/Spring/Spring.Data.Tests/Data/AdoPlatformTransactionManagerTests.cs b/test/Spring/Spring.Data.Tests/Data/AdoPlatformTransactionManagerTests.cs index 6a9cc1e6..8248b9a5 100644 --- a/test/Spring/Spring.Data.Tests/Data/AdoPlatformTransactionManagerTests.cs +++ b/test/Spring/Spring.Data.Tests/Data/AdoPlatformTransactionManagerTests.cs @@ -16,9 +16,7 @@ using System.Data; using FakeItEasy; - using NUnit.Framework; - using Spring.Dao; using Spring.Data.Common; using Spring.Data.Core; @@ -27,1227 +25,1212 @@ using Spring.Support; using Spring.Transaction; using Spring.Transaction.Support; -namespace Spring.Data +namespace Spring.Data; + +/// +/// This class contains tests for AdoPlatformTransactionManager +/// +/// Mark Pollack +[TestFixture] +public class AdoPlatformTransactionManagerTests { - /// - /// This class contains tests for AdoPlatformTransactionManager - /// - /// Mark Pollack - [TestFixture] - public class AdoPlatformTransactionManagerTests + private const IsolationLevel DefaultIsolationLevel = IsolationLevel.ReadCommitted; + + [TearDown] + public void TearDown() { - private const IsolationLevel DefaultIsolationLevel = IsolationLevel.ReadCommitted; + Assert.IsTrue(TransactionSynchronizationManager.ResourceDictionary.Count == 0); + Assert.IsFalse(TransactionSynchronizationManager.SynchronizationActive); + Assert.IsFalse(TransactionSynchronizationManager.CurrentTransactionReadOnly); + Assert.IsFalse(TransactionSynchronizationManager.ActualTransactionActive); + } - [TearDown] - public void TearDown() + [Test] + public void TransactionCommit() + { + IDbProvider dbProvider = A.Fake(); + IDbConnection connection = A.Fake(); + IDbTransaction transaction = A.Fake(); + + A.CallTo(() => dbProvider.CreateConnection()).Returns(connection); + A.CallTo(() => connection.BeginTransaction(DefaultIsolationLevel)).Returns(transaction); + + AdoPlatformTransactionManager tm = new AdoPlatformTransactionManager(dbProvider); + tm.TransactionSynchronization = TransactionSynchronizationState.Always; + + TransactionTemplate tt = new TransactionTemplate(tm); + + Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); + Assert.IsTrue(!TransactionSynchronizationManager.SynchronizationActive, "Synchronizations not active"); + + tt.Execute(new TransactionCommitTxCallback(dbProvider)); + + Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); + Assert.IsTrue(!TransactionSynchronizationManager.SynchronizationActive, "Synchronizations not active"); + + A.CallTo(() => connection.Open()).MustHaveHappenedOnceExactly(); + //standard tx timeout. + A.CallTo(() => transaction.Commit()).MustHaveHappenedOnceExactly(); + A.CallTo(() => connection.Dispose()).MustHaveHappenedOnceExactly(); + } + + [Test] + public void TransactionRollback() + { + IDbProvider dbProvider = A.Fake(); + IDbConnection connection = A.Fake(); + IDbTransaction transaction = A.Fake(); + + A.CallTo(() => dbProvider.CreateConnection()).Returns(connection); + A.CallTo(() => connection.BeginTransaction(DefaultIsolationLevel)).Returns(transaction); + + AdoPlatformTransactionManager tm = new AdoPlatformTransactionManager(dbProvider); + tm.TransactionSynchronization = TransactionSynchronizationState.Always; + + TransactionTemplate tt = new TransactionTemplate(tm); + + Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); + Assert.IsTrue(!TransactionSynchronizationManager.SynchronizationActive, "Synchronizations not active"); + + Exception ex = new ArgumentException("test exception"); + try { - Assert.IsTrue(TransactionSynchronizationManager.ResourceDictionary.Count == 0); - Assert.IsFalse(TransactionSynchronizationManager.SynchronizationActive); - Assert.IsFalse(TransactionSynchronizationManager.CurrentTransactionReadOnly); - Assert.IsFalse(TransactionSynchronizationManager.ActualTransactionActive); + tt.Execute(new TransactionRollbackTxCallback(dbProvider, ex)); + Assert.Fail("Should have thrown exception"); + } + catch (ArgumentException e) + { + Assert.AreEqual(ex, e); } - [Test] - public void TransactionCommit() + Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); + Assert.IsTrue(!TransactionSynchronizationManager.SynchronizationActive, "Synchronizations not active"); + + //standard tx timeout. + A.CallTo(() => connection.Open()).MustHaveHappenedOnceExactly(); + A.CallTo(() => transaction.Rollback()).MustHaveHappenedOnceExactly(); + A.CallTo(() => connection.Dispose()).MustHaveHappenedOnceExactly(); + } + + [Test] + public void ParticipatingTransactionWithRollbackOnly() + { + IDbProvider dbProvider = A.Fake(); + IDbConnection connection = A.Fake(); + IDbTransaction transaction = A.Fake(); + + A.CallTo(() => dbProvider.CreateConnection()).Returns(connection); + A.CallTo(() => connection.BeginTransaction(DefaultIsolationLevel)).Returns(transaction); + + AdoPlatformTransactionManager tm = new AdoPlatformTransactionManager(dbProvider); + tm.TransactionSynchronization = TransactionSynchronizationState.Always; + + Assert.IsFalse(TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); + Assert.IsFalse(TransactionSynchronizationManager.SynchronizationActive, "Synchronizations not active"); + + ITransactionStatus ts = tm.GetTransaction(new DefaultTransactionDefinition()); + TestTransactionSynchronization synch = + new TestTransactionSynchronization(dbProvider, TransactionSynchronizationStatus.Rolledback); + TransactionSynchronizationManager.RegisterSynchronization(synch); + + bool outerTransactionBoundaryReached = false; + try { - IDbProvider dbProvider = A.Fake(); - IDbConnection connection = A.Fake(); - IDbTransaction transaction = A.Fake(); - - A.CallTo(() => dbProvider.CreateConnection()).Returns(connection); - A.CallTo(() => connection.BeginTransaction(DefaultIsolationLevel)).Returns(transaction); - - AdoPlatformTransactionManager tm = new AdoPlatformTransactionManager(dbProvider); - tm.TransactionSynchronization = TransactionSynchronizationState.Always; - + Assert.IsTrue(ts.IsNewTransaction); TransactionTemplate tt = new TransactionTemplate(tm); - - Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); - Assert.IsTrue(!TransactionSynchronizationManager.SynchronizationActive, "Synchronizations not active"); - - tt.Execute(new TransactionCommitTxCallback(dbProvider)); - - Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); - Assert.IsTrue(!TransactionSynchronizationManager.SynchronizationActive, "Synchronizations not active"); - - A.CallTo(() => connection.Open()).MustHaveHappenedOnceExactly(); - //standard tx timeout. - A.CallTo(() => transaction.Commit()).MustHaveHappenedOnceExactly(); - A.CallTo(() => connection.Dispose()).MustHaveHappenedOnceExactly(); + TransactionTemplate tt2 = new TransactionTemplate(tm); + tt.Execute(new ParticipatingTxWithRollbackOnlyTxCallback(tt2, dbProvider)); + outerTransactionBoundaryReached = true; + tm.Commit(ts); + Assert.Fail("Should have thrown UnexpectedRollbackException"); } - - [Test] - public void TransactionRollback() + catch (UnexpectedRollbackException) { - IDbProvider dbProvider = A.Fake(); - IDbConnection connection = A.Fake(); - IDbTransaction transaction = A.Fake(); - - A.CallTo(() => dbProvider.CreateConnection()).Returns(connection); - A.CallTo(() => connection.BeginTransaction(DefaultIsolationLevel)).Returns(transaction); - - AdoPlatformTransactionManager tm = new AdoPlatformTransactionManager(dbProvider); - tm.TransactionSynchronization = TransactionSynchronizationState.Always; - - TransactionTemplate tt = new TransactionTemplate(tm); - - Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); - Assert.IsTrue(!TransactionSynchronizationManager.SynchronizationActive, "Synchronizations not active"); - - Exception ex = new ArgumentException("test exception"); - try + // expected + if (!outerTransactionBoundaryReached) { - tt.Execute(new TransactionRollbackTxCallback(dbProvider, ex)); - Assert.Fail("Should have thrown exception"); - } - catch (ArgumentException e) - { - Assert.AreEqual(ex, e); + tm.Rollback(ts); } - Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); - Assert.IsTrue(!TransactionSynchronizationManager.SynchronizationActive, "Synchronizations not active"); - - //standard tx timeout. - A.CallTo(() => connection.Open()).MustHaveHappenedOnceExactly(); - A.CallTo(() => transaction.Rollback()).MustHaveHappenedOnceExactly(); - A.CallTo(() => connection.Dispose()).MustHaveHappenedOnceExactly(); + Assert.IsTrue(outerTransactionBoundaryReached); } - [Test] - public void ParticipatingTransactionWithRollbackOnly() + Assert.IsFalse(TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); + Assert.IsFalse(synch.beforeCommitCalled); + Assert.IsTrue(synch.beforeCompletionCalled); + Assert.IsFalse(synch.afterCommitCalled); + Assert.IsTrue(synch.afterCompletionCalled); + + //standard tx timeout. + A.CallTo(() => connection.Open()).MustHaveHappenedOnceExactly(); + A.CallTo(() => transaction.Rollback()).MustHaveHappenedOnceExactly(); + A.CallTo(() => connection.Dispose()).MustHaveHappenedOnceExactly(); + } + + [Test] + public void ParticipatingTransactionWithTransactionStartedFromSynch() + { + } + + [Test] + public void ParticipatingTransactionWithRollbackOnlyAndInnerSynch() + { + } + + [Test] + public void PropagationRequiresNewWithExistingTransaction() + { + IDbProvider dbProvider = A.Fake(); + IDbConnection connection = A.Fake(); + IDbTransaction transaction = A.Fake(); + + A.CallTo(() => dbProvider.CreateConnection()).Returns(connection); + A.CallTo(() => connection.BeginTransaction(DefaultIsolationLevel)).Returns(transaction); + + AdoPlatformTransactionManager tm = new AdoPlatformTransactionManager(dbProvider); + tm.TransactionSynchronization = TransactionSynchronizationState.Always; + + TransactionTemplate tt = new TransactionTemplate(tm); + tt.PropagationBehavior = TransactionPropagation.RequiresNew; + + Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); + Assert.IsTrue(!TransactionSynchronizationManager.SynchronizationActive, "Synchronizations not active"); + + tt.Execute(new PropagationRequiresNewWithExistingTransactionCallback(tt, dbProvider)); + + Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); + + A.CallTo(() => connection.Open()).MustHaveHappenedTwiceExactly(); + A.CallTo(() => transaction.Rollback()).MustHaveHappenedOnceExactly(); + A.CallTo(() => connection.Dispose()).MustHaveHappenedTwiceExactly(); + } + + [Test] + public void PropagationRequiresNewWithExistingTransactionAndUnrelatedDataSource() + { + IDbProvider dbProvider = A.Fake(); + IDbConnection connection = A.Fake(); + IDbTransaction transaction = A.Fake(); + + A.CallTo(() => dbProvider.CreateConnection()).Returns(connection); + A.CallTo(() => connection.BeginTransaction(DefaultIsolationLevel)).Returns(transaction); + + IDbProvider dbProvider2 = A.Fake(); + IDbConnection connection2 = A.Fake(); + IDbTransaction transaction2 = A.Fake(); + + A.CallTo(() => dbProvider2.CreateConnection()).Returns(connection2); + A.CallTo(() => connection2.BeginTransaction(DefaultIsolationLevel)).Returns(transaction2); + + AdoPlatformTransactionManager tm = new AdoPlatformTransactionManager(dbProvider); + tm.TransactionSynchronization = TransactionSynchronizationState.Always; + + TransactionTemplate tt = new TransactionTemplate(tm); + tt.PropagationBehavior = TransactionPropagation.RequiresNew; + + AdoPlatformTransactionManager tm2 = new AdoPlatformTransactionManager(dbProvider2); + tm2.TransactionSynchronization = TransactionSynchronizationState.Always; + + TransactionTemplate tt2 = new TransactionTemplate(tm2); + tt2.PropagationBehavior = TransactionPropagation.RequiresNew; + + Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); + Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider2), "Hasn't thread db provider"); + Assert.IsTrue(!TransactionSynchronizationManager.SynchronizationActive, "Synchronizations not active"); + + tt.Execute(new PropagationRequiresNewWithExistingTransactionCallback(tt2, dbProvider)); + + Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); + Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider2), "Hasn't thread db provider"); + + A.CallTo(() => connection.Open()).MustHaveHappenedOnceExactly(); + A.CallTo(() => transaction.Commit()).MustHaveHappenedOnceExactly(); + A.CallTo(() => connection.Dispose()).MustHaveHappenedOnceExactly(); + + A.CallTo(() => connection2.Open()).MustHaveHappenedOnceExactly(); + A.CallTo(() => transaction2.Rollback()).MustHaveHappenedOnceExactly(); + A.CallTo(() => connection2.Dispose()).MustHaveHappenedOnceExactly(); + } + + [Test] + public void PropagationRequiresNewWithExistingTransactionAndUnrelatedFailingDataSource() + { + IDbProvider dbProvider = A.Fake(); + IDbConnection connection = A.Fake(); + IDbTransaction transaction = A.Fake(); + + A.CallTo(() => dbProvider.CreateConnection()).Returns(connection); + A.CallTo(() => connection.BeginTransaction(DefaultIsolationLevel)).Returns(transaction); + + IDbProvider dbProvider2 = A.Fake(); + IDbConnection connection2 = A.Fake(); + + A.CallTo(() => dbProvider2.CreateConnection()).Returns(connection2); + Exception failure = new Exception("can't open connection"); + A.CallTo(() => connection2.Open()).Throws(failure); + + AdoPlatformTransactionManager tm = new AdoPlatformTransactionManager(dbProvider); + tm.TransactionSynchronization = TransactionSynchronizationState.Always; + + TransactionTemplate tt = new TransactionTemplate(tm); + tt.PropagationBehavior = TransactionPropagation.RequiresNew; + + AdoPlatformTransactionManager tm2 = new AdoPlatformTransactionManager(dbProvider2); + tm2.TransactionSynchronization = TransactionSynchronizationState.Never; + TransactionTemplate tt2 = new TransactionTemplate(tm2); + tt2.PropagationBehavior = TransactionPropagation.RequiresNew; + + Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); + Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider2), "Hasn't thread db provider"); + Assert.IsTrue(!TransactionSynchronizationManager.SynchronizationActive, "Synchronizations not active"); + + try { - IDbProvider dbProvider = A.Fake(); - IDbConnection connection = A.Fake(); - IDbTransaction transaction = A.Fake(); + tt.Execute( + new PropagationRequiresNewWithExistingTransactionAndUnrelatedFailingDataSourceCallback(tt2)); + Assert.Fail("Should have thrown CannotCreateTransactionException"); + } + catch (CannotCreateTransactionException ex) + { + Assert.AreSame(failure, ex.InnerException); + } - A.CallTo(() => dbProvider.CreateConnection()).Returns(connection); - A.CallTo(() => connection.BeginTransaction(DefaultIsolationLevel)).Returns(transaction); + Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); + Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider2), "Hasn't thread db provider"); - AdoPlatformTransactionManager tm = new AdoPlatformTransactionManager(dbProvider); - tm.TransactionSynchronization = TransactionSynchronizationState.Always; + A.CallTo(() => connection.Open()).MustHaveHappenedOnceExactly(); + A.CallTo(() => transaction.Rollback()).MustHaveHappenedOnceExactly(); + A.CallTo(() => connection.Dispose()).MustHaveHappenedOnceExactly(); + } - Assert.IsFalse(TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); - Assert.IsFalse(TransactionSynchronizationManager.SynchronizationActive, "Synchronizations not active"); + [Test] + public void PropagationNotSupportedWithExistingTransaction() + { + IDbProvider dbProvider = A.Fake(); + IDbConnection connection = A.Fake(); + IDbTransaction transaction = A.Fake(); - ITransactionStatus ts = tm.GetTransaction(new DefaultTransactionDefinition()); - TestTransactionSynchronization synch = - new TestTransactionSynchronization(dbProvider, TransactionSynchronizationStatus.Rolledback); - TransactionSynchronizationManager.RegisterSynchronization(synch); + A.CallTo(() => dbProvider.CreateConnection()).Returns(connection); + A.CallTo(() => connection.BeginTransaction(DefaultIsolationLevel)).Returns(transaction); - bool outerTransactionBoundaryReached = false; - try + AdoPlatformTransactionManager tm = new AdoPlatformTransactionManager(dbProvider); + tm.TransactionSynchronization = TransactionSynchronizationState.Always; + + TransactionTemplate tt = new TransactionTemplate(tm); + tt.PropagationBehavior = TransactionPropagation.RequiresNew; + Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); + Assert.IsTrue(!TransactionSynchronizationManager.SynchronizationActive, "Synchronizations not active"); + + tt.Execute(new PropagationNotSupportedWithExistingTransactionCallback(tt, dbProvider)); + + A.CallTo(() => connection.Open()).MustHaveHappenedOnceExactly(); + A.CallTo(() => transaction.Commit()).MustHaveHappenedOnceExactly(); + A.CallTo(() => connection.Dispose()).MustHaveHappenedOnceExactly(); + } + + [Test] + public void PropagationNeverWithExistingTransaction() + { + IDbProvider dbProvider = A.Fake(); + IDbConnection connection = A.Fake(); + IDbTransaction transaction = A.Fake(); + + A.CallTo(() => dbProvider.CreateConnection()).Returns(connection); + A.CallTo(() => connection.BeginTransaction(DefaultIsolationLevel)).Returns(transaction); + + AdoPlatformTransactionManager tm = new AdoPlatformTransactionManager(dbProvider); + tm.TransactionSynchronization = TransactionSynchronizationState.Always; + + TransactionTemplate tt = new TransactionTemplate(tm); + tt.PropagationBehavior = TransactionPropagation.RequiresNew; + Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); + Assert.IsTrue(!TransactionSynchronizationManager.SynchronizationActive, "Synchronizations not active"); + + try + { + tt.Execute(new PropagationNeverWithExistingTransactionCallback(tt)); + Assert.Fail("Should have thrown IllegalTransactionStateException"); + } + catch (IllegalTransactionStateException) + { + //expected. + } + + Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); + + A.CallTo(() => connection.Open()).MustHaveHappenedOnceExactly(); + A.CallTo(() => transaction.Rollback()).MustHaveHappenedOnceExactly(); + A.CallTo(() => connection.Dispose()).MustHaveHappenedOnceExactly(); + } + + [Test] + public void PropagationRequiresNewWithExistingConnection() + { + IDbProvider dbProvider = A.Fake(); + IDbConnection connection = A.Fake(); + IDbConnection connection2 = A.Fake(); + IDbTransaction transaction2 = A.Fake(); + + A.CallTo(() => dbProvider.CreateConnection()).Returns(connection).Once() + .Then.Returns(connection2).Once(); + + A.CallTo(() => connection2.BeginTransaction(DefaultIsolationLevel)).Returns(transaction2); + + AdoPlatformTransactionManager tm = new AdoPlatformTransactionManager(dbProvider); + tm.TransactionSynchronization = TransactionSynchronizationState.Always; + + TransactionTemplate tt = new TransactionTemplate(tm); + tt.PropagationBehavior = TransactionPropagation.Supports; + Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); + Assert.IsTrue(!TransactionSynchronizationManager.SynchronizationActive, "Synchronizations not active"); + + tt.Execute(new PropagationRequiresNewWithExistingConnectionCallback(tt, connection, connection2, dbProvider)); + + Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); + + A.CallTo(() => connection.Open()).MustHaveHappenedOnceExactly(); + A.CallTo(() => connection.Dispose()).MustHaveHappenedOnceExactly(); + A.CallTo(() => connection2.Open()).MustHaveHappenedOnceExactly(); + A.CallTo(() => connection2.Dispose()).MustHaveHappenedOnceExactly(); + } + + [Test] + public void TransactionWithIsolation() + { + IDbProvider dbProvider = A.Fake(); + IDbConnection connection = A.Fake(); + IDbTransaction transaction = A.Fake(); + A.CallTo(() => dbProvider.CreateConnection()).Returns(connection); + A.CallTo(() => connection.BeginTransaction(IsolationLevel.Serializable)).Returns(transaction); + + AdoPlatformTransactionManager tm = new AdoPlatformTransactionManager(dbProvider); + tm.TransactionSynchronization = TransactionSynchronizationState.Always; + + TransactionTemplate tt = new TransactionTemplate(tm); + tt.PropagationBehavior = TransactionPropagation.RequiresNew; + tt.TransactionIsolationLevel = IsolationLevel.Serializable; + Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); + + tt.Execute(new TransactionCommitTxCallback(dbProvider)); + + Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); + + A.CallTo(() => connection.Open()).MustHaveHappenedOnceExactly(); + A.CallTo(() => transaction.Commit()).MustHaveHappenedOnceExactly(); + A.CallTo(() => connection.Dispose()).MustHaveHappenedOnceExactly(); + } + + [Test] + public void TransactionWithLongTimeout() + { + DoTransactionWithTimeout(10); + } + + [Test] + public void TransactionWithShortTimeout() + { + DoTransactionWithTimeout(1); + } + + private void DoTransactionWithTimeout(int timeout) + { + IDbProvider dbProvider = A.Fake(); + IDbConnection connection = A.Fake(); + IDbTransaction transaction = A.Fake(); + IDbCommand command = A.Fake(); + A.CallTo(() => dbProvider.CreateConnection()).Returns(connection); + A.CallTo(() => connection.BeginTransaction(DefaultIsolationLevel)).Returns(transaction); + A.CallTo(() => connection.CreateCommand()).Returns(command); + + AdoPlatformTransactionManager tm = new AdoPlatformTransactionManager(dbProvider); + tm.TransactionSynchronization = TransactionSynchronizationState.Always; + + TransactionTemplate tt = new TransactionTemplate(tm); + tt.TransactionTimeout = timeout; + + Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); + + try + { + tt.Execute(new TransactionWithTimeoutCallback(dbProvider)); + if (timeout <= 1) { - Assert.IsTrue(ts.IsNewTransaction); - TransactionTemplate tt = new TransactionTemplate(tm); - TransactionTemplate tt2 = new TransactionTemplate(tm); - tt.Execute(new ParticipatingTxWithRollbackOnlyTxCallback(tt2, dbProvider)); - outerTransactionBoundaryReached = true; - tm.Commit(ts); - Assert.Fail("Should have thrown UnexpectedRollbackException"); + Assert.Fail("Should have thrown TransactionTimedOutException"); } - catch (UnexpectedRollbackException) + } + catch (TransactionTimedOutException) + { + if (timeout <= 1) { - // expected - if (!outerTransactionBoundaryReached) - { - tm.Rollback(ts); - } - - Assert.IsTrue(outerTransactionBoundaryReached); - } - - Assert.IsFalse(TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); - Assert.IsFalse(synch.beforeCommitCalled); - Assert.IsTrue(synch.beforeCompletionCalled); - Assert.IsFalse(synch.afterCommitCalled); - Assert.IsTrue(synch.afterCompletionCalled); - - //standard tx timeout. - A.CallTo(() => connection.Open()).MustHaveHappenedOnceExactly(); - A.CallTo(() => transaction.Rollback()).MustHaveHappenedOnceExactly(); - A.CallTo(() => connection.Dispose()).MustHaveHappenedOnceExactly(); - } - - [Test] - public void ParticipatingTransactionWithTransactionStartedFromSynch() - { - } - - [Test] - public void ParticipatingTransactionWithRollbackOnlyAndInnerSynch() - { - } - - [Test] - public void PropagationRequiresNewWithExistingTransaction() - { - IDbProvider dbProvider = A.Fake(); - IDbConnection connection = A.Fake(); - IDbTransaction transaction = A.Fake(); - - A.CallTo(() => dbProvider.CreateConnection()).Returns(connection); - A.CallTo(() => connection.BeginTransaction(DefaultIsolationLevel)).Returns(transaction); - - AdoPlatformTransactionManager tm = new AdoPlatformTransactionManager(dbProvider); - tm.TransactionSynchronization = TransactionSynchronizationState.Always; - - - TransactionTemplate tt = new TransactionTemplate(tm); - tt.PropagationBehavior = TransactionPropagation.RequiresNew; - - Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); - Assert.IsTrue(!TransactionSynchronizationManager.SynchronizationActive, "Synchronizations not active"); - - tt.Execute(new PropagationRequiresNewWithExistingTransactionCallback(tt, dbProvider)); - - Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); - - A.CallTo(() => connection.Open()).MustHaveHappenedTwiceExactly(); - A.CallTo(() => transaction.Rollback()).MustHaveHappenedOnceExactly(); - A.CallTo(() => connection.Dispose()).MustHaveHappenedTwiceExactly(); - } - - [Test] - public void PropagationRequiresNewWithExistingTransactionAndUnrelatedDataSource() - { - IDbProvider dbProvider = A.Fake(); - IDbConnection connection = A.Fake(); - IDbTransaction transaction = A.Fake(); - - A.CallTo(() => dbProvider.CreateConnection()).Returns(connection); - A.CallTo(() => connection.BeginTransaction(DefaultIsolationLevel)).Returns(transaction); - - - IDbProvider dbProvider2 = A.Fake(); - IDbConnection connection2 = A.Fake(); - IDbTransaction transaction2 = A.Fake(); - - A.CallTo(() => dbProvider2.CreateConnection()).Returns(connection2); - A.CallTo(() => connection2.BeginTransaction(DefaultIsolationLevel)).Returns(transaction2); - - AdoPlatformTransactionManager tm = new AdoPlatformTransactionManager(dbProvider); - tm.TransactionSynchronization = TransactionSynchronizationState.Always; - - TransactionTemplate tt = new TransactionTemplate(tm); - tt.PropagationBehavior = TransactionPropagation.RequiresNew; - - AdoPlatformTransactionManager tm2 = new AdoPlatformTransactionManager(dbProvider2); - tm2.TransactionSynchronization = TransactionSynchronizationState.Always; - - TransactionTemplate tt2 = new TransactionTemplate(tm2); - tt2.PropagationBehavior = TransactionPropagation.RequiresNew; - - Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); - Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider2), "Hasn't thread db provider"); - Assert.IsTrue(!TransactionSynchronizationManager.SynchronizationActive, "Synchronizations not active"); - - - tt.Execute(new PropagationRequiresNewWithExistingTransactionCallback(tt2, dbProvider)); - - Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); - Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider2), "Hasn't thread db provider"); - - A.CallTo(() => connection.Open()).MustHaveHappenedOnceExactly(); - A.CallTo(() => transaction.Commit()).MustHaveHappenedOnceExactly(); - A.CallTo(() => connection.Dispose()).MustHaveHappenedOnceExactly(); - - A.CallTo(() => connection2.Open()).MustHaveHappenedOnceExactly(); - A.CallTo(() => transaction2.Rollback()).MustHaveHappenedOnceExactly(); - A.CallTo(() => connection2.Dispose()).MustHaveHappenedOnceExactly(); - } - - [Test] - public void PropagationRequiresNewWithExistingTransactionAndUnrelatedFailingDataSource() - { - IDbProvider dbProvider = A.Fake(); - IDbConnection connection = A.Fake(); - IDbTransaction transaction = A.Fake(); - - A.CallTo(() => dbProvider.CreateConnection()).Returns(connection); - A.CallTo(() => connection.BeginTransaction(DefaultIsolationLevel)).Returns(transaction); - - IDbProvider dbProvider2 = A.Fake(); - IDbConnection connection2 = A.Fake(); - - A.CallTo(() => dbProvider2.CreateConnection()).Returns(connection2); - Exception failure = new Exception("can't open connection"); - A.CallTo(() => connection2.Open()).Throws(failure); - - AdoPlatformTransactionManager tm = new AdoPlatformTransactionManager(dbProvider); - tm.TransactionSynchronization = TransactionSynchronizationState.Always; - - TransactionTemplate tt = new TransactionTemplate(tm); - tt.PropagationBehavior = TransactionPropagation.RequiresNew; - - AdoPlatformTransactionManager tm2 = new AdoPlatformTransactionManager(dbProvider2); - tm2.TransactionSynchronization = TransactionSynchronizationState.Never; - TransactionTemplate tt2 = new TransactionTemplate(tm2); - tt2.PropagationBehavior = TransactionPropagation.RequiresNew; - - Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); - Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider2), "Hasn't thread db provider"); - Assert.IsTrue(!TransactionSynchronizationManager.SynchronizationActive, "Synchronizations not active"); - - try - { - tt.Execute( - new PropagationRequiresNewWithExistingTransactionAndUnrelatedFailingDataSourceCallback(tt2)); - Assert.Fail("Should have thrown CannotCreateTransactionException"); - } - catch (CannotCreateTransactionException ex) - { - Assert.AreSame(failure, ex.InnerException); - } - - Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); - Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider2), "Hasn't thread db provider"); - - A.CallTo(() => connection.Open()).MustHaveHappenedOnceExactly(); - A.CallTo(() => transaction.Rollback()).MustHaveHappenedOnceExactly(); - A.CallTo(() => connection.Dispose()).MustHaveHappenedOnceExactly(); - } - - [Test] - public void PropagationNotSupportedWithExistingTransaction() - { - IDbProvider dbProvider = A.Fake(); - IDbConnection connection = A.Fake(); - IDbTransaction transaction = A.Fake(); - - A.CallTo(() => dbProvider.CreateConnection()).Returns(connection); - A.CallTo(() => connection.BeginTransaction(DefaultIsolationLevel)).Returns(transaction); - - AdoPlatformTransactionManager tm = new AdoPlatformTransactionManager(dbProvider); - tm.TransactionSynchronization = TransactionSynchronizationState.Always; - - TransactionTemplate tt = new TransactionTemplate(tm); - tt.PropagationBehavior = TransactionPropagation.RequiresNew; - Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); - Assert.IsTrue(!TransactionSynchronizationManager.SynchronizationActive, "Synchronizations not active"); - - tt.Execute(new PropagationNotSupportedWithExistingTransactionCallback(tt, dbProvider)); - - A.CallTo(() => connection.Open()).MustHaveHappenedOnceExactly(); - A.CallTo(() => transaction.Commit()).MustHaveHappenedOnceExactly(); - A.CallTo(() => connection.Dispose()).MustHaveHappenedOnceExactly(); - } - - [Test] - public void PropagationNeverWithExistingTransaction() - { - IDbProvider dbProvider = A.Fake(); - IDbConnection connection = A.Fake(); - IDbTransaction transaction = A.Fake(); - - A.CallTo(() => dbProvider.CreateConnection()).Returns(connection); - A.CallTo(() => connection.BeginTransaction(DefaultIsolationLevel)).Returns(transaction); - - AdoPlatformTransactionManager tm = new AdoPlatformTransactionManager(dbProvider); - tm.TransactionSynchronization = TransactionSynchronizationState.Always; - - TransactionTemplate tt = new TransactionTemplate(tm); - tt.PropagationBehavior = TransactionPropagation.RequiresNew; - Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); - Assert.IsTrue(!TransactionSynchronizationManager.SynchronizationActive, "Synchronizations not active"); - - try - { - tt.Execute(new PropagationNeverWithExistingTransactionCallback(tt)); - Assert.Fail("Should have thrown IllegalTransactionStateException"); - } - catch (IllegalTransactionStateException) - { - //expected. - } - - Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); - - A.CallTo(() => connection.Open()).MustHaveHappenedOnceExactly(); - A.CallTo(() => transaction.Rollback()).MustHaveHappenedOnceExactly(); - A.CallTo(() => connection.Dispose()).MustHaveHappenedOnceExactly(); - } - - [Test] - public void PropagationRequiresNewWithExistingConnection() - { - IDbProvider dbProvider = A.Fake(); - IDbConnection connection = A.Fake(); - IDbConnection connection2 = A.Fake(); - IDbTransaction transaction2 = A.Fake(); - - A.CallTo(() => dbProvider.CreateConnection()).Returns(connection).Once() - .Then.Returns(connection2).Once(); - - A.CallTo(() => connection2.BeginTransaction(DefaultIsolationLevel)).Returns(transaction2); - - AdoPlatformTransactionManager tm = new AdoPlatformTransactionManager(dbProvider); - tm.TransactionSynchronization = TransactionSynchronizationState.Always; - - TransactionTemplate tt = new TransactionTemplate(tm); - tt.PropagationBehavior = TransactionPropagation.Supports; - Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); - Assert.IsTrue(!TransactionSynchronizationManager.SynchronizationActive, "Synchronizations not active"); - - tt.Execute(new PropagationRequiresNewWithExistingConnectionCallback(tt, connection, connection2, dbProvider)); - - Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); - - A.CallTo(() => connection.Open()).MustHaveHappenedOnceExactly(); - A.CallTo(() => connection.Dispose()).MustHaveHappenedOnceExactly(); - A.CallTo(() => connection2.Open()).MustHaveHappenedOnceExactly(); - A.CallTo(() => connection2.Dispose()).MustHaveHappenedOnceExactly(); - } - - [Test] - public void TransactionWithIsolation() - { - IDbProvider dbProvider = A.Fake(); - IDbConnection connection = A.Fake(); - IDbTransaction transaction = A.Fake(); - A.CallTo(() => dbProvider.CreateConnection()).Returns(connection); - A.CallTo(() => connection.BeginTransaction(IsolationLevel.Serializable)).Returns(transaction); - - AdoPlatformTransactionManager tm = new AdoPlatformTransactionManager(dbProvider); - tm.TransactionSynchronization = TransactionSynchronizationState.Always; - - TransactionTemplate tt = new TransactionTemplate(tm); - tt.PropagationBehavior = TransactionPropagation.RequiresNew; - tt.TransactionIsolationLevel = IsolationLevel.Serializable; - Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); - - tt.Execute(new TransactionCommitTxCallback(dbProvider)); - - Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); - - A.CallTo(() => connection.Open()).MustHaveHappenedOnceExactly(); - A.CallTo(() => transaction.Commit()).MustHaveHappenedOnceExactly(); - A.CallTo(() => connection.Dispose()).MustHaveHappenedOnceExactly(); - } - - [Test] - public void TransactionWithLongTimeout() - { - DoTransactionWithTimeout(10); - } - - [Test] - public void TransactionWithShortTimeout() - { - DoTransactionWithTimeout(1); - } - - private void DoTransactionWithTimeout(int timeout) - { - IDbProvider dbProvider = A.Fake(); - IDbConnection connection = A.Fake(); - IDbTransaction transaction = A.Fake(); - IDbCommand command = A.Fake(); - A.CallTo(() => dbProvider.CreateConnection()).Returns(connection); - A.CallTo(() => connection.BeginTransaction(DefaultIsolationLevel)).Returns(transaction); - A.CallTo(() => connection.CreateCommand()).Returns(command); - - AdoPlatformTransactionManager tm = new AdoPlatformTransactionManager(dbProvider); - tm.TransactionSynchronization = TransactionSynchronizationState.Always; - - TransactionTemplate tt = new TransactionTemplate(tm); - tt.TransactionTimeout = timeout; - - Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); - - try - { - tt.Execute(new TransactionWithTimeoutCallback(dbProvider)); - if (timeout <= 1) - { - Assert.Fail("Should have thrown TransactionTimedOutException"); - } - } - catch (TransactionTimedOutException) - { - if (timeout <= 1) - { - //expected - } - else - { - throw; - } - } - - Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); - - A.CallTo(() => connection.Open()).MustHaveHappenedOnceExactly(); - A.CallTo(() => connection.Dispose()).MustHaveHappenedOnceExactly(); - A.CallToSet(() => command.CommandText).WhenArgumentsMatch(x => x.Get(0) == "some SQL statement").MustHaveHappenedOnceExactly(); - - if (timeout > 1) - { - A.CallToSet(() => command.CommandTimeout).WhenArgumentsMatch(x => (int) x[0] == (timeout - 1)).MustHaveHappenedOnceExactly(); - A.CallTo(() => transaction.Commit()).MustHaveHappenedOnceExactly(); + //expected } else { - A.CallTo(() => transaction.Rollback()).MustHaveHappenedOnceExactly(); - } - } - - [Test] - public void TransactionWithExceptionOnBegin() - { - IDbProvider dbProvider = A.Fake(); - - // CreateConnection is called in AdoPlatformTransactionManager.DoBegin - A.CallTo(() => dbProvider.CreateConnection()).Throws(new TestSqlException("Cannot begin", "314")); - - AdoPlatformTransactionManager tm = new AdoPlatformTransactionManager(dbProvider); - tm.TransactionSynchronization = TransactionSynchronizationState.Always; - - TransactionTemplate tt = new TransactionTemplate(tm); - try - { - tt.Execute(TransactionWithExceptionNoOp); - } - catch (CannotCreateTransactionException) - { - // expected - } - - Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); - } - - private object TransactionWithExceptionNoOp(ITransactionStatus status) - { - return null; - } - - [Test] - public void TransactionWithExceptionOnCommit() - { - IDbProvider dbProvider = A.Fake(); - IDbConnection connection = A.Fake(); - IDbTransaction transaction = A.Fake(); - A.CallTo(() => dbProvider.CreateConnection()).Returns(connection); - A.CallTo(() => connection.BeginTransaction(DefaultIsolationLevel)).Returns(transaction); - A.CallTo(() => transaction.Commit()).Throws(new TestSqlException("Cannot commit", "314")); - - AdoPlatformTransactionManager tm = new AdoPlatformTransactionManager(dbProvider); - tm.TransactionSynchronization = TransactionSynchronizationState.Always; - - TransactionTemplate tt = new TransactionTemplate(tm); - - try - { - tt.Execute(TransactionWithExceptionNoOp); - } - catch (TransactionSystemException) - { - //expected - } - - - Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); - A.CallTo(() => connection.Open()).MustHaveHappenedOnceExactly(); - A.CallTo(() => transaction.Commit()).MustHaveHappenedOnceExactly(); - A.CallTo(() => connection.Dispose()).MustHaveHappenedOnceExactly(); - } - - - [Test] - public void TransactionWithExceptionOnCommitAndRollbackOnCommitFailure() - { - IDbProvider dbProvider = A.Fake(); - IDbConnection connection = A.Fake(); - IDbTransaction transaction = A.Fake(); - A.CallTo(() => dbProvider.CreateConnection()).Returns(connection); - A.CallTo(() => connection.BeginTransaction(DefaultIsolationLevel)).Returns(transaction); - A.CallTo(() => transaction.Commit()).Throws(new TestSqlException("Cannot commit", "314")); - - AdoPlatformTransactionManager tm = new AdoPlatformTransactionManager(dbProvider); - tm.TransactionSynchronization = TransactionSynchronizationState.Always; - - tm.RollbackOnCommitFailure = true; - TransactionTemplate tt = new TransactionTemplate(tm); - - try - { - tt.Execute(TransactionWithExceptionNoOp); - } - catch (TransactionSystemException) - { - //expected - } - - Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); - - A.CallTo(() => connection.Open()).MustHaveHappenedOnceExactly(); - A.CallTo(() => transaction.Rollback()).MustHaveHappenedOnceExactly(); - A.CallTo(() => connection.Dispose()).MustHaveHappenedOnceExactly(); - } - - [Test] - public void TransactionWithExceptionOnRollback() - { - IDbProvider dbProvider = A.Fake(); - IDbConnection connection = A.Fake(); - IDbTransaction transaction = A.Fake(); - A.CallTo(() => dbProvider.CreateConnection()).Returns(connection); - A.CallTo(() => connection.BeginTransaction(DefaultIsolationLevel)).Returns(transaction); - A.CallTo(() => transaction.Rollback()).Throws(new TestSqlException("Cannot commit", "314")); - - AdoPlatformTransactionManager tm = new AdoPlatformTransactionManager(dbProvider); - tm.TransactionSynchronization = TransactionSynchronizationState.Always; - - TransactionTemplate tt = new TransactionTemplate(tm); - - try - { - tt.Execute(TransactionWithExceptionOnRollbackMethod); - } - catch (TransactionSystemException) - { - //expected - } - - Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); - - A.CallTo(() => connection.Open()).MustHaveHappenedOnceExactly(); - A.CallTo(() => transaction.Rollback()).MustHaveHappenedOnceExactly(); - A.CallTo(() => connection.Dispose()).MustHaveHappenedOnceExactly(); - } - - private object TransactionWithExceptionOnRollbackMethod(ITransactionStatus status) - { - status.SetRollbackOnly(); - return null; - } - - [Test] - public void TransactionWithPropagationSupports() - { - IDbProvider dbProvider = A.Fake(); - - AdoPlatformTransactionManager tm = new AdoPlatformTransactionManager(dbProvider); - tm.TransactionSynchronization = TransactionSynchronizationState.Always; - - TransactionTemplate tt = new TransactionTemplate(tm); - tt.PropagationBehavior = TransactionPropagation.Supports; - - Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); - - tt.Execute(new TransactionWithPropagationSupportsCallback(dbProvider)); - - Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); - } - - [Test] - public void TransactionWithPropagationNotSupported() - { - IDbProvider dbProvider = A.Fake(); - - AdoPlatformTransactionManager tm = new AdoPlatformTransactionManager(dbProvider); - tm.TransactionSynchronization = TransactionSynchronizationState.Always; - - TransactionTemplate tt = new TransactionTemplate(tm); - tt.PropagationBehavior = TransactionPropagation.NotSupported; - - Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); - - tt.Execute(new TransactionWithPropagationNotSupportedCallback(dbProvider)); - - Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); - } - - [Test] - public void TransactionWithPropagationNever() - { - IDbProvider dbProvider = A.Fake(); - - AdoPlatformTransactionManager tm = new AdoPlatformTransactionManager(dbProvider); - tm.TransactionSynchronization = TransactionSynchronizationState.Always; - - TransactionTemplate tt = new TransactionTemplate(tm); - tt.PropagationBehavior = TransactionPropagation.Never; - - Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); - - tt.Execute(new TransactionWithPropagationNotSupportedCallback(dbProvider)); - - Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); - } - - [Test] - public void ExistingTransactionWithPropagationNestedNotSupported() - { - IDbProvider dbProvider = A.Fake(); - IDbConnection connection = A.Fake(); - IDbTransaction transaction = A.Fake(); - A.CallTo(() => dbProvider.CreateConnection()).Returns(connection); - A.CallTo(() => connection.BeginTransaction(DefaultIsolationLevel)).Returns(transaction); - - AdoPlatformTransactionManager tm = new AdoPlatformTransactionManager(dbProvider); - tm.TransactionSynchronization = TransactionSynchronizationState.Always; - - TransactionTemplate tt = new TransactionTemplate(tm); - tt.PropagationBehavior = TransactionPropagation.Nested; - - Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); - Assert.IsTrue(!TransactionSynchronizationManager.SynchronizationActive, "Synchronizations not active"); - - try - { - tt.Execute(new ExistingTransactionWithPropagationNestedCallback(dbProvider, tt)); - Assert.Fail("Should have thrown NestedTransactionNotSupportedException"); - } - catch (NestedTransactionNotSupportedException) - { - // expected - } - - Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); - A.CallTo(() => connection.Open()).MustHaveHappenedOnceExactly(); - A.CallTo(() => transaction.Rollback()).MustHaveHappenedOnceExactly(); - A.CallTo(() => connection.Dispose()).MustHaveHappenedOnceExactly(); - } - - [Test] - public void TransactionWithPropagationNested() - { - IDbProvider dbProvider = A.Fake(); - IDbConnection connection = A.Fake(); - IDbTransaction transaction = A.Fake(); - A.CallTo(() => dbProvider.CreateConnection()).Returns(connection); - A.CallTo(() => connection.BeginTransaction(DefaultIsolationLevel)).Returns(transaction); - - AdoPlatformTransactionManager tm = new AdoPlatformTransactionManager(dbProvider); - tm.TransactionSynchronization = TransactionSynchronizationState.Always; - - TransactionTemplate tt = new TransactionTemplate(tm); - tt.PropagationBehavior = TransactionPropagation.Nested; - - Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); - Assert.IsTrue(!TransactionSynchronizationManager.SynchronizationActive, "Synchronizations not active"); - - - tt.Execute(TransactionWithPropagationNestedMethod); - - Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); - - A.CallTo(() => connection.Open()).MustHaveHappenedOnceExactly(); - A.CallTo(() => transaction.Commit()).MustHaveHappenedOnceExactly(); - A.CallTo(() => connection.Dispose()).MustHaveHappenedOnceExactly(); - } - - private object TransactionWithPropagationNestedMethod(ITransactionStatus status) - { - Assert.IsTrue(status.IsNewTransaction, "Is new transaction"); - return null; - } - - [Test] - public void TransactionWithPropagationNestedAndRollback() - { - IDbProvider dbProvider = A.Fake(); - IDbConnection connection = A.Fake(); - IDbTransaction transaction = A.Fake(); - A.CallTo(() => dbProvider.CreateConnection()).Returns(connection); - A.CallTo(() => connection.BeginTransaction(DefaultIsolationLevel)).Returns(transaction); - - AdoPlatformTransactionManager tm = new AdoPlatformTransactionManager(dbProvider); - tm.TransactionSynchronization = TransactionSynchronizationState.Always; - - TransactionTemplate tt = new TransactionTemplate(tm); - tt.PropagationBehavior = TransactionPropagation.Nested; - - Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); - Assert.IsTrue(!TransactionSynchronizationManager.SynchronizationActive, "Synchronizations not active"); - - - tt.Execute(TransactionWithPropagationNestedAndRollbackMethod); - - Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); - - A.CallTo(() => connection.Open()).MustHaveHappenedOnceExactly(); - A.CallTo(() => transaction.Rollback()).MustHaveHappenedOnceExactly(); - A.CallTo(() => connection.Dispose()).MustHaveHappenedOnceExactly(); - } - - private object TransactionWithPropagationNestedAndRollbackMethod(ITransactionStatus status) - { - Assert.IsTrue(status.IsNewTransaction, "Is new transaction"); - status.SetRollbackOnly(); - return null; - } - } - - internal class ExistingTransactionWithPropagationNestedCallback : ITransactionCallback - { - private IDbProvider dbProvider; - private TransactionTemplate tt; - - public ExistingTransactionWithPropagationNestedCallback(IDbProvider dbProvider, TransactionTemplate transactionTemplate) - { - this.dbProvider = dbProvider; - tt = transactionTemplate; - } - - public object DoInTransaction(ITransactionStatus status) - { - Assert.IsTrue(status.IsNewTransaction, "Is new transaction"); - //TODO: Note no support for savepoints at this time (1.1), so can't check that a savepoint isn't present. - - tt.Execute(new ExistingTransactionWithPropagationNestedCallback2(dbProvider)); - - Assert.IsTrue(status.IsNewTransaction, "Is new transaction"); - //TODO: Note no support for savepoints at this time (1.1), so can't check that a savepoint isn't present. - return null; - } - } - - internal class ExistingTransactionWithPropagationNestedCallback2 : ITransactionCallback - { - private IDbProvider dbProvider; - - public ExistingTransactionWithPropagationNestedCallback2(IDbProvider provider) - { - dbProvider = provider; - } - - public object DoInTransaction(ITransactionStatus status) - { - Assert.IsTrue(TransactionSynchronizationManager.HasResource(dbProvider), "Has thread db provider"); - Assert.IsTrue(TransactionSynchronizationManager.SynchronizationActive, "Synchronizations active"); - Assert.IsTrue(!status.IsNewTransaction, "Isn't new transaction"); - //TODO: Note no support for savepoints at this time (1.1), so can't check that a savepoint is present. - return null; - } - } - - internal class TransactionWithPropagationNotSupportedCallback : ITransactionCallback - { - private IDbProvider provider; - - public TransactionWithPropagationNotSupportedCallback(IDbProvider provider) - { - this.provider = provider; - } - - public object DoInTransaction(ITransactionStatus status) - { - Assert.IsTrue(!TransactionSynchronizationManager.HasResource(provider), "Hasn't thread db provider"); - Assert.IsTrue(!status.IsNewTransaction, "Is not new transaction"); - return null; - } - } - - internal class TransactionWithPropagationSupportsCallback : ITransactionCallback - { - private IDbProvider provider; - - public TransactionWithPropagationSupportsCallback(IDbProvider provider) - { - this.provider = provider; - } - - public object DoInTransaction(ITransactionStatus status) - { - Assert.IsTrue(!TransactionSynchronizationManager.HasResource(provider), "Hasn't thread db provider"); - Assert.IsTrue(!status.IsNewTransaction, "Is not new transaction"); - Assert.IsFalse(TransactionSynchronizationManager.CurrentTransactionReadOnly); - Assert.IsFalse(TransactionSynchronizationManager.ActualTransactionActive); - return null; - } - } - - - internal class TransactionWithTimeoutCallback : ITransactionCallback - { - private IDbProvider provider; - - public TransactionWithTimeoutCallback(IDbProvider provider) - { - this.provider = provider; - } - - public object DoInTransaction(ITransactionStatus status) - { - try - { - Thread.Sleep(1500); - } - catch (Exception) - { - } - - try - { - IDbConnection con = ConnectionUtils.GetConnection(provider); - IDbCommand cmd = con.CreateCommand(); - cmd.CommandText = "some SQL statement"; - ConnectionUtils.ApplyTransactionTimeout(cmd, provider); - } - catch (Exception e) - { - if (e.GetType() != typeof(TransactionTimedOutException)) - { - throw new DataAccessResourceFailureException("", e); - } - throw; } + } - return null; + Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); + + A.CallTo(() => connection.Open()).MustHaveHappenedOnceExactly(); + A.CallTo(() => connection.Dispose()).MustHaveHappenedOnceExactly(); + A.CallToSet(() => command.CommandText).WhenArgumentsMatch(x => x.Get(0) == "some SQL statement").MustHaveHappenedOnceExactly(); + + if (timeout > 1) + { + A.CallToSet(() => command.CommandTimeout).WhenArgumentsMatch(x => (int) x[0] == (timeout - 1)).MustHaveHappenedOnceExactly(); + A.CallTo(() => transaction.Commit()).MustHaveHappenedOnceExactly(); + } + else + { + A.CallTo(() => transaction.Rollback()).MustHaveHappenedOnceExactly(); } } - internal class PropagationRequiresNewWithExistingConnectionCallback : ITransactionCallback + [Test] + public void TransactionWithExceptionOnBegin() { - private TransactionTemplate tt; - private IDbProvider dbProvider; - private IDbConnection connection; - private IDbConnection connection2; + IDbProvider dbProvider = A.Fake(); - public PropagationRequiresNewWithExistingConnectionCallback(TransactionTemplate transactionTemplate, IDbConnection connection, IDbConnection connection2, IDbProvider provider) + // CreateConnection is called in AdoPlatformTransactionManager.DoBegin + A.CallTo(() => dbProvider.CreateConnection()).Throws(new TestSqlException("Cannot begin", "314")); + + AdoPlatformTransactionManager tm = new AdoPlatformTransactionManager(dbProvider); + tm.TransactionSynchronization = TransactionSynchronizationState.Always; + + TransactionTemplate tt = new TransactionTemplate(tm); + try { - tt = transactionTemplate; - this.connection = connection; - this.connection2 = connection2; - dbProvider = provider; + tt.Execute(TransactionWithExceptionNoOp); + } + catch (CannotCreateTransactionException) + { + // expected } - public object DoInTransaction(ITransactionStatus status) - { - Assert.IsTrue(TransactionSynchronizationManager.SynchronizationActive, "Synchronizations active"); - Assert.AreSame(connection, ConnectionUtils.GetConnection(dbProvider)); - Assert.AreSame(connection, ConnectionUtils.GetConnection(dbProvider)); - tt.PropagationBehavior = TransactionPropagation.RequiresNew; - tt.ReadOnly = true; - tt.Execute(new PropagationRequiresNewWithExistingConnectionCallback2(dbProvider, connection2)); - Assert.AreSame(connection, ConnectionUtils.GetConnection(dbProvider)); - return null; - } + Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); } - internal class PropagationRequiresNewWithExistingConnectionCallback2 : ITransactionCallback + private object TransactionWithExceptionNoOp(ITransactionStatus status) { - private IDbProvider dbProvider; - private IDbConnection connection2; - - - public PropagationRequiresNewWithExistingConnectionCallback2(IDbProvider dbProvider, IDbConnection connection2) - { - this.dbProvider = dbProvider; - this.connection2 = connection2; - } - - public object DoInTransaction(ITransactionStatus status) - { - Assert.IsTrue(TransactionSynchronizationManager.HasResource(dbProvider), "Has thread db provider"); - Assert.IsTrue(TransactionSynchronizationManager.SynchronizationActive, "Synchronizations active"); - Assert.IsTrue(status.IsNewTransaction, "Is new transaction"); - Assert.AreSame(connection2, ConnectionUtils.GetConnection(dbProvider)); - Assert.AreSame(connection2, ConnectionUtils.GetConnection(dbProvider)); - - return null; - } + return null; } - internal class PropagationNeverWithExistingTransactionCallback : ITransactionCallback + [Test] + public void TransactionWithExceptionOnCommit() { - private TransactionTemplate innerTxTemplate; + IDbProvider dbProvider = A.Fake(); + IDbConnection connection = A.Fake(); + IDbTransaction transaction = A.Fake(); + A.CallTo(() => dbProvider.CreateConnection()).Returns(connection); + A.CallTo(() => connection.BeginTransaction(DefaultIsolationLevel)).Returns(transaction); + A.CallTo(() => transaction.Commit()).Throws(new TestSqlException("Cannot commit", "314")); - public PropagationNeverWithExistingTransactionCallback(TransactionTemplate transactionTemplate) + AdoPlatformTransactionManager tm = new AdoPlatformTransactionManager(dbProvider); + tm.TransactionSynchronization = TransactionSynchronizationState.Always; + + TransactionTemplate tt = new TransactionTemplate(tm); + + try { - innerTxTemplate = transactionTemplate; + tt.Execute(TransactionWithExceptionNoOp); + } + catch (TransactionSystemException) + { + //expected } - - public object DoInTransaction(ITransactionStatus status) - { - Assert.IsTrue(status.IsNewTransaction, "Is new transaction"); - innerTxTemplate.PropagationBehavior = TransactionPropagation.Never; - innerTxTemplate.Execute(new PropagationNeverWithExistingTransactionCallback2()); - Assert.Fail("Should have thrown IllegalTransactionStateException"); - return null; - } + Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); + A.CallTo(() => connection.Open()).MustHaveHappenedOnceExactly(); + A.CallTo(() => transaction.Commit()).MustHaveHappenedOnceExactly(); + A.CallTo(() => connection.Dispose()).MustHaveHappenedOnceExactly(); } - internal class PropagationNeverWithExistingTransactionCallback2 : ITransactionCallback + [Test] + public void TransactionWithExceptionOnCommitAndRollbackOnCommitFailure() { - public object DoInTransaction(ITransactionStatus status) + IDbProvider dbProvider = A.Fake(); + IDbConnection connection = A.Fake(); + IDbTransaction transaction = A.Fake(); + A.CallTo(() => dbProvider.CreateConnection()).Returns(connection); + A.CallTo(() => connection.BeginTransaction(DefaultIsolationLevel)).Returns(transaction); + A.CallTo(() => transaction.Commit()).Throws(new TestSqlException("Cannot commit", "314")); + + AdoPlatformTransactionManager tm = new AdoPlatformTransactionManager(dbProvider); + tm.TransactionSynchronization = TransactionSynchronizationState.Always; + + tm.RollbackOnCommitFailure = true; + TransactionTemplate tt = new TransactionTemplate(tm); + + try { - Assert.Fail("Should have thrown IllegalTransactionStateException"); - return null; + tt.Execute(TransactionWithExceptionNoOp); } + catch (TransactionSystemException) + { + //expected + } + + Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); + + A.CallTo(() => connection.Open()).MustHaveHappenedOnceExactly(); + A.CallTo(() => transaction.Rollback()).MustHaveHappenedOnceExactly(); + A.CallTo(() => connection.Dispose()).MustHaveHappenedOnceExactly(); } - internal class PropagationNotSupportedWithExistingTransactionCallback : ITransactionCallback + [Test] + public void TransactionWithExceptionOnRollback() { - private TransactionTemplate innerTxTemplate; - private IDbProvider dbProvider; + IDbProvider dbProvider = A.Fake(); + IDbConnection connection = A.Fake(); + IDbTransaction transaction = A.Fake(); + A.CallTo(() => dbProvider.CreateConnection()).Returns(connection); + A.CallTo(() => connection.BeginTransaction(DefaultIsolationLevel)).Returns(transaction); + A.CallTo(() => transaction.Rollback()).Throws(new TestSqlException("Cannot commit", "314")); - public PropagationNotSupportedWithExistingTransactionCallback(TransactionTemplate transactionTemplate, IDbProvider provider) + AdoPlatformTransactionManager tm = new AdoPlatformTransactionManager(dbProvider); + tm.TransactionSynchronization = TransactionSynchronizationState.Always; + + TransactionTemplate tt = new TransactionTemplate(tm); + + try { - innerTxTemplate = transactionTemplate; - dbProvider = provider; + tt.Execute(TransactionWithExceptionOnRollbackMethod); + } + catch (TransactionSystemException) + { + //expected } - public object DoInTransaction(ITransactionStatus status) - { - Assert.IsTrue(status.IsNewTransaction, "Is new transaction"); - Assert.IsTrue(TransactionSynchronizationManager.SynchronizationActive, "Synchronization active"); - Assert.IsFalse(TransactionSynchronizationManager.CurrentTransactionReadOnly); - innerTxTemplate.PropagationBehavior = TransactionPropagation.NotSupported; - innerTxTemplate.Execute(new PropagationNotSupportedWithExistingTransactionCallback2(dbProvider)); - Assert.IsTrue(status.IsNewTransaction, "Is new transaction"); - Assert.IsFalse(TransactionSynchronizationManager.CurrentTransactionReadOnly); - Assert.IsTrue(TransactionSynchronizationManager.ActualTransactionActive); - return null; - } + Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); + + A.CallTo(() => connection.Open()).MustHaveHappenedOnceExactly(); + A.CallTo(() => transaction.Rollback()).MustHaveHappenedOnceExactly(); + A.CallTo(() => connection.Dispose()).MustHaveHappenedOnceExactly(); } - internal class PropagationNotSupportedWithExistingTransactionCallback2 : ITransactionCallback + private object TransactionWithExceptionOnRollbackMethod(ITransactionStatus status) { - private IDbProvider provider; - - public PropagationNotSupportedWithExistingTransactionCallback2(IDbProvider provider) - { - this.provider = provider; - } - - public object DoInTransaction(ITransactionStatus status) - { - Assert.IsTrue(!TransactionSynchronizationManager.HasResource(provider), "Hasn't thread db provider"); - Assert.IsTrue(TransactionSynchronizationManager.SynchronizationActive); - Assert.IsTrue(!status.IsNewTransaction, "Isn't new transaction"); - Assert.IsFalse(TransactionSynchronizationManager.CurrentTransactionReadOnly); - Assert.IsFalse(TransactionSynchronizationManager.ActualTransactionActive); - status.SetRollbackOnly(); - return null; - } + status.SetRollbackOnly(); + return null; } - internal class PropagationRequiresNewWithExistingTransactionAndUnrelatedFailingDataSourceCallback : ITransactionCallback + [Test] + public void TransactionWithPropagationSupports() { - private TransactionTemplate innerTxTemplate; + IDbProvider dbProvider = A.Fake(); + AdoPlatformTransactionManager tm = new AdoPlatformTransactionManager(dbProvider); + tm.TransactionSynchronization = TransactionSynchronizationState.Always; - public PropagationRequiresNewWithExistingTransactionAndUnrelatedFailingDataSourceCallback(TransactionTemplate transactionTemplate) - { - innerTxTemplate = transactionTemplate; - } + TransactionTemplate tt = new TransactionTemplate(tm); + tt.PropagationBehavior = TransactionPropagation.Supports; - public object DoInTransaction(ITransactionStatus status) - { - Assert.IsTrue(status.IsNewTransaction, "Is new transaction"); - Assert.IsTrue(TransactionSynchronizationManager.SynchronizationActive, "Synchronization active"); - Assert.IsFalse(TransactionSynchronizationManager.CurrentTransactionReadOnly); - Assert.IsTrue(TransactionSynchronizationManager.ActualTransactionActive); - innerTxTemplate.Execute(new PropagationRequiresNewWithExistingTransactionAndUnrelatedFailingDataSourceCallback2()); - return null; - } + Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); + + tt.Execute(new TransactionWithPropagationSupportsCallback(dbProvider)); + + Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); } - internal class PropagationRequiresNewWithExistingTransactionAndUnrelatedFailingDataSourceCallback2 : ITransactionCallback + [Test] + public void TransactionWithPropagationNotSupported() { - public object DoInTransaction(ITransactionStatus status) - { - status.SetRollbackOnly(); - return null; - } + IDbProvider dbProvider = A.Fake(); + + AdoPlatformTransactionManager tm = new AdoPlatformTransactionManager(dbProvider); + tm.TransactionSynchronization = TransactionSynchronizationState.Always; + + TransactionTemplate tt = new TransactionTemplate(tm); + tt.PropagationBehavior = TransactionPropagation.NotSupported; + + Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); + + tt.Execute(new TransactionWithPropagationNotSupportedCallback(dbProvider)); + + Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); } - internal class PropagationRequiresNewWithExistingTransactionCallback : ITransactionCallback + [Test] + public void TransactionWithPropagationNever() { - private TransactionTemplate innerTxTemplate; - private IDbProvider dbProvider; + IDbProvider dbProvider = A.Fake(); - public PropagationRequiresNewWithExistingTransactionCallback(TransactionTemplate transactionTemplate, - IDbProvider provider) - { - innerTxTemplate = transactionTemplate; - dbProvider = provider; - } + AdoPlatformTransactionManager tm = new AdoPlatformTransactionManager(dbProvider); + tm.TransactionSynchronization = TransactionSynchronizationState.Always; - public object DoInTransaction(ITransactionStatus status) - { - Assert.IsTrue(status.IsNewTransaction, "Is new transaction"); - Assert.IsTrue(TransactionSynchronizationManager.SynchronizationActive, "Synchronization active"); - Assert.IsFalse(TransactionSynchronizationManager.CurrentTransactionReadOnly); - Assert.IsTrue(TransactionSynchronizationManager.ActualTransactionActive); - innerTxTemplate.Execute(new PropagationRequiresNewWithExistingTransactionCallback2(dbProvider)); + TransactionTemplate tt = new TransactionTemplate(tm); + tt.PropagationBehavior = TransactionPropagation.Never; - Assert.IsTrue(status.IsNewTransaction, "Is new transaction"); - Assert.IsFalse(TransactionSynchronizationManager.CurrentTransactionReadOnly); - Assert.IsTrue(TransactionSynchronizationManager.ActualTransactionActive); - return null; - } + Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); + + tt.Execute(new TransactionWithPropagationNotSupportedCallback(dbProvider)); + + Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); } - internal class PropagationRequiresNewWithExistingTransactionCallback2 : ITransactionCallback + [Test] + public void ExistingTransactionWithPropagationNestedNotSupported() { - private IDbProvider dbProvider; + IDbProvider dbProvider = A.Fake(); + IDbConnection connection = A.Fake(); + IDbTransaction transaction = A.Fake(); + A.CallTo(() => dbProvider.CreateConnection()).Returns(connection); + A.CallTo(() => connection.BeginTransaction(DefaultIsolationLevel)).Returns(transaction); - public PropagationRequiresNewWithExistingTransactionCallback2(IDbProvider dbProvider) + AdoPlatformTransactionManager tm = new AdoPlatformTransactionManager(dbProvider); + tm.TransactionSynchronization = TransactionSynchronizationState.Always; + + TransactionTemplate tt = new TransactionTemplate(tm); + tt.PropagationBehavior = TransactionPropagation.Nested; + + Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); + Assert.IsTrue(!TransactionSynchronizationManager.SynchronizationActive, "Synchronizations not active"); + + try { - this.dbProvider = dbProvider; + tt.Execute(new ExistingTransactionWithPropagationNestedCallback(dbProvider, tt)); + Assert.Fail("Should have thrown NestedTransactionNotSupportedException"); + } + catch (NestedTransactionNotSupportedException) + { + // expected } - public object DoInTransaction(ITransactionStatus status) - { - Assert.IsTrue(TransactionSynchronizationManager.HasResource(dbProvider), "Has thread connection"); - Assert.IsTrue(TransactionSynchronizationManager.SynchronizationActive, "Synchronization active"); - Assert.IsTrue(status.IsNewTransaction, "Is new transaction"); - Assert.IsFalse(TransactionSynchronizationManager.CurrentTransactionReadOnly); - Assert.IsTrue(TransactionSynchronizationManager.ActualTransactionActive); - status.SetRollbackOnly(); - return null; - } + Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); + A.CallTo(() => connection.Open()).MustHaveHappenedOnceExactly(); + A.CallTo(() => transaction.Rollback()).MustHaveHappenedOnceExactly(); + A.CallTo(() => connection.Dispose()).MustHaveHappenedOnceExactly(); } - internal class TransactionCommitTxCallback : ITransactionCallback + [Test] + public void TransactionWithPropagationNested() { - private IDbProvider provider; + IDbProvider dbProvider = A.Fake(); + IDbConnection connection = A.Fake(); + IDbTransaction transaction = A.Fake(); + A.CallTo(() => dbProvider.CreateConnection()).Returns(connection); + A.CallTo(() => connection.BeginTransaction(DefaultIsolationLevel)).Returns(transaction); - public TransactionCommitTxCallback(IDbProvider provider) - { - this.provider = provider; - } + AdoPlatformTransactionManager tm = new AdoPlatformTransactionManager(dbProvider); + tm.TransactionSynchronization = TransactionSynchronizationState.Always; - public object DoInTransaction(ITransactionStatus status) - { - Assert.IsTrue(TransactionSynchronizationManager.HasResource(provider), "Has thread db provider"); - Assert.IsTrue(TransactionSynchronizationManager.SynchronizationActive); - Assert.IsTrue(status.IsNewTransaction, "Is new transaction"); - Assert.IsTrue(TransactionSynchronizationManager.ActualTransactionActive); - Assert.IsFalse(TransactionSynchronizationManager.CurrentTransactionReadOnly); - return null; - } + TransactionTemplate tt = new TransactionTemplate(tm); + tt.PropagationBehavior = TransactionPropagation.Nested; + + Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); + Assert.IsTrue(!TransactionSynchronizationManager.SynchronizationActive, "Synchronizations not active"); + + tt.Execute(TransactionWithPropagationNestedMethod); + + Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); + + A.CallTo(() => connection.Open()).MustHaveHappenedOnceExactly(); + A.CallTo(() => transaction.Commit()).MustHaveHappenedOnceExactly(); + A.CallTo(() => connection.Dispose()).MustHaveHappenedOnceExactly(); } - internal class TransactionRollbackTxCallback : ITransactionCallback + private object TransactionWithPropagationNestedMethod(ITransactionStatus status) { - private IDbProvider provider; - private Exception exception; - - public TransactionRollbackTxCallback(IDbProvider provider, Exception exception) - { - this.provider = provider; - this.exception = exception; - } - - public object DoInTransaction(ITransactionStatus status) - { - Assert.IsTrue(TransactionSynchronizationManager.HasResource(provider), "Hasn't thread db provider"); - Assert.IsTrue(TransactionSynchronizationManager.SynchronizationActive); - Assert.IsTrue(status.IsNewTransaction, "Is new transaction"); - throw exception; - } + Assert.IsTrue(status.IsNewTransaction, "Is new transaction"); + return null; } - internal class ParticipatingTxWithRollbackOnlyTxCallback : ITransactionCallback + [Test] + public void TransactionWithPropagationNestedAndRollback() { - private TransactionTemplate innerTxTemplate; - private IDbProvider dbProvider; + IDbProvider dbProvider = A.Fake(); + IDbConnection connection = A.Fake(); + IDbTransaction transaction = A.Fake(); + A.CallTo(() => dbProvider.CreateConnection()).Returns(connection); + A.CallTo(() => connection.BeginTransaction(DefaultIsolationLevel)).Returns(transaction); + AdoPlatformTransactionManager tm = new AdoPlatformTransactionManager(dbProvider); + tm.TransactionSynchronization = TransactionSynchronizationState.Always; - public ParticipatingTxWithRollbackOnlyTxCallback(TransactionTemplate transactionTemplate, IDbProvider dbProvider) - { - innerTxTemplate = transactionTemplate; - this.dbProvider = dbProvider; - } + TransactionTemplate tt = new TransactionTemplate(tm); + tt.PropagationBehavior = TransactionPropagation.Nested; - public object DoInTransaction(ITransactionStatus status) - { - Assert.IsTrue(!status.IsNewTransaction, "Is existing transaction"); - Assert.IsFalse(status.RollbackOnly, "Is not rollback-only"); - innerTxTemplate.Execute(new ParticipatingTxWithRollbackOnlyTxCallback2(dbProvider)); - Assert.IsTrue(!status.IsNewTransaction, "Is existing transaction"); - Assert.IsTrue(status.RollbackOnly, "Is rollback-only"); - return null; - } + Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); + Assert.IsTrue(!TransactionSynchronizationManager.SynchronizationActive, "Synchronizations not active"); + + tt.Execute(TransactionWithPropagationNestedAndRollbackMethod); + + Assert.IsTrue(!TransactionSynchronizationManager.HasResource(dbProvider), "Hasn't thread db provider"); + + A.CallTo(() => connection.Open()).MustHaveHappenedOnceExactly(); + A.CallTo(() => transaction.Rollback()).MustHaveHappenedOnceExactly(); + A.CallTo(() => connection.Dispose()).MustHaveHappenedOnceExactly(); } - internal class ParticipatingTxWithRollbackOnlyTxCallback2 : ITransactionCallback + private object TransactionWithPropagationNestedAndRollbackMethod(ITransactionStatus status) { - private IDbProvider dbProvider; - - public ParticipatingTxWithRollbackOnlyTxCallback2(IDbProvider dbProvider) - { - this.dbProvider = dbProvider; - } - - public object DoInTransaction(ITransactionStatus status) - { - Assert.IsTrue(TransactionSynchronizationManager.HasResource(dbProvider), "Has thread connection"); - Assert.IsTrue(TransactionSynchronizationManager.SynchronizationActive, "Synchronization active"); - Assert.IsTrue(!status.IsNewTransaction, "Is existing transaction"); - status.SetRollbackOnly(); - return null; - } - } - - - internal class TestTransactionSynchronization : ITransactionSynchronization - { - private IDbProvider provider; - private TransactionSynchronizationStatus status; - - public bool beforeCommitCalled; - public bool beforeCompletionCalled; - public bool afterCommitCalled; - public bool afterCompletionCalled; - - public TestTransactionSynchronization(IDbProvider provider, - TransactionSynchronizationStatus synchronizationStatus) - { - this.provider = provider; - status = synchronizationStatus; - } - - - public void Suspend() - { - } - - public void Resume() - { - } - - public void BeforeCommit(bool readOnly) - { - if (status == TransactionSynchronizationStatus.Committed) - { - Assert.Fail("Should never be called"); - } - - Assert.IsFalse(beforeCommitCalled); - beforeCommitCalled = true; - } - - public void AfterCommit() - { - if (status != TransactionSynchronizationStatus.Committed) - { - Assert.Fail("Should never be called"); - } - - Assert.IsFalse(afterCommitCalled); - afterCommitCalled = true; - } - - public void BeforeCompletion() - { - Assert.IsFalse(beforeCompletionCalled); - beforeCompletionCalled = true; - } - - public void AfterCompletion(TransactionSynchronizationStatus syncStatus) - { - Assert.IsFalse(afterCompletionCalled); - afterCompletionCalled = true; - Assert.IsTrue(syncStatus == status); - Assert.IsTrue(TransactionSynchronizationManager.HasResource(provider)); - } + Assert.IsTrue(status.IsNewTransaction, "Is new transaction"); + status.SetRollbackOnly(); + return null; + } +} + +internal class ExistingTransactionWithPropagationNestedCallback : ITransactionCallback +{ + private IDbProvider dbProvider; + private TransactionTemplate tt; + + public ExistingTransactionWithPropagationNestedCallback(IDbProvider dbProvider, TransactionTemplate transactionTemplate) + { + this.dbProvider = dbProvider; + tt = transactionTemplate; + } + + public object DoInTransaction(ITransactionStatus status) + { + Assert.IsTrue(status.IsNewTransaction, "Is new transaction"); + //TODO: Note no support for savepoints at this time (1.1), so can't check that a savepoint isn't present. + + tt.Execute(new ExistingTransactionWithPropagationNestedCallback2(dbProvider)); + + Assert.IsTrue(status.IsNewTransaction, "Is new transaction"); + //TODO: Note no support for savepoints at this time (1.1), so can't check that a savepoint isn't present. + return null; + } +} + +internal class ExistingTransactionWithPropagationNestedCallback2 : ITransactionCallback +{ + private IDbProvider dbProvider; + + public ExistingTransactionWithPropagationNestedCallback2(IDbProvider provider) + { + dbProvider = provider; + } + + public object DoInTransaction(ITransactionStatus status) + { + Assert.IsTrue(TransactionSynchronizationManager.HasResource(dbProvider), "Has thread db provider"); + Assert.IsTrue(TransactionSynchronizationManager.SynchronizationActive, "Synchronizations active"); + Assert.IsTrue(!status.IsNewTransaction, "Isn't new transaction"); + //TODO: Note no support for savepoints at this time (1.1), so can't check that a savepoint is present. + return null; + } +} + +internal class TransactionWithPropagationNotSupportedCallback : ITransactionCallback +{ + private IDbProvider provider; + + public TransactionWithPropagationNotSupportedCallback(IDbProvider provider) + { + this.provider = provider; + } + + public object DoInTransaction(ITransactionStatus status) + { + Assert.IsTrue(!TransactionSynchronizationManager.HasResource(provider), "Hasn't thread db provider"); + Assert.IsTrue(!status.IsNewTransaction, "Is not new transaction"); + return null; + } +} + +internal class TransactionWithPropagationSupportsCallback : ITransactionCallback +{ + private IDbProvider provider; + + public TransactionWithPropagationSupportsCallback(IDbProvider provider) + { + this.provider = provider; + } + + public object DoInTransaction(ITransactionStatus status) + { + Assert.IsTrue(!TransactionSynchronizationManager.HasResource(provider), "Hasn't thread db provider"); + Assert.IsTrue(!status.IsNewTransaction, "Is not new transaction"); + Assert.IsFalse(TransactionSynchronizationManager.CurrentTransactionReadOnly); + Assert.IsFalse(TransactionSynchronizationManager.ActualTransactionActive); + return null; + } +} + +internal class TransactionWithTimeoutCallback : ITransactionCallback +{ + private IDbProvider provider; + + public TransactionWithTimeoutCallback(IDbProvider provider) + { + this.provider = provider; + } + + public object DoInTransaction(ITransactionStatus status) + { + try + { + Thread.Sleep(1500); + } + catch (Exception) + { + } + + try + { + IDbConnection con = ConnectionUtils.GetConnection(provider); + IDbCommand cmd = con.CreateCommand(); + cmd.CommandText = "some SQL statement"; + ConnectionUtils.ApplyTransactionTimeout(cmd, provider); + } + catch (Exception e) + { + if (e.GetType() != typeof(TransactionTimedOutException)) + { + throw new DataAccessResourceFailureException("", e); + } + + throw; + } + + return null; + } +} + +internal class PropagationRequiresNewWithExistingConnectionCallback : ITransactionCallback +{ + private TransactionTemplate tt; + private IDbProvider dbProvider; + private IDbConnection connection; + private IDbConnection connection2; + + public PropagationRequiresNewWithExistingConnectionCallback(TransactionTemplate transactionTemplate, IDbConnection connection, IDbConnection connection2, IDbProvider provider) + { + tt = transactionTemplate; + this.connection = connection; + this.connection2 = connection2; + dbProvider = provider; + } + + public object DoInTransaction(ITransactionStatus status) + { + Assert.IsTrue(TransactionSynchronizationManager.SynchronizationActive, "Synchronizations active"); + Assert.AreSame(connection, ConnectionUtils.GetConnection(dbProvider)); + Assert.AreSame(connection, ConnectionUtils.GetConnection(dbProvider)); + tt.PropagationBehavior = TransactionPropagation.RequiresNew; + tt.ReadOnly = true; + tt.Execute(new PropagationRequiresNewWithExistingConnectionCallback2(dbProvider, connection2)); + Assert.AreSame(connection, ConnectionUtils.GetConnection(dbProvider)); + return null; + } +} + +internal class PropagationRequiresNewWithExistingConnectionCallback2 : ITransactionCallback +{ + private IDbProvider dbProvider; + private IDbConnection connection2; + + public PropagationRequiresNewWithExistingConnectionCallback2(IDbProvider dbProvider, IDbConnection connection2) + { + this.dbProvider = dbProvider; + this.connection2 = connection2; + } + + public object DoInTransaction(ITransactionStatus status) + { + Assert.IsTrue(TransactionSynchronizationManager.HasResource(dbProvider), "Has thread db provider"); + Assert.IsTrue(TransactionSynchronizationManager.SynchronizationActive, "Synchronizations active"); + Assert.IsTrue(status.IsNewTransaction, "Is new transaction"); + Assert.AreSame(connection2, ConnectionUtils.GetConnection(dbProvider)); + Assert.AreSame(connection2, ConnectionUtils.GetConnection(dbProvider)); + + return null; + } +} + +internal class PropagationNeverWithExistingTransactionCallback : ITransactionCallback +{ + private TransactionTemplate innerTxTemplate; + + public PropagationNeverWithExistingTransactionCallback(TransactionTemplate transactionTemplate) + { + innerTxTemplate = transactionTemplate; + } + + public object DoInTransaction(ITransactionStatus status) + { + Assert.IsTrue(status.IsNewTransaction, "Is new transaction"); + innerTxTemplate.PropagationBehavior = TransactionPropagation.Never; + innerTxTemplate.Execute(new PropagationNeverWithExistingTransactionCallback2()); + Assert.Fail("Should have thrown IllegalTransactionStateException"); + return null; + } +} + +internal class PropagationNeverWithExistingTransactionCallback2 : ITransactionCallback +{ + public object DoInTransaction(ITransactionStatus status) + { + Assert.Fail("Should have thrown IllegalTransactionStateException"); + return null; + } +} + +internal class PropagationNotSupportedWithExistingTransactionCallback : ITransactionCallback +{ + private TransactionTemplate innerTxTemplate; + private IDbProvider dbProvider; + + public PropagationNotSupportedWithExistingTransactionCallback(TransactionTemplate transactionTemplate, IDbProvider provider) + { + innerTxTemplate = transactionTemplate; + dbProvider = provider; + } + + public object DoInTransaction(ITransactionStatus status) + { + Assert.IsTrue(status.IsNewTransaction, "Is new transaction"); + Assert.IsTrue(TransactionSynchronizationManager.SynchronizationActive, "Synchronization active"); + Assert.IsFalse(TransactionSynchronizationManager.CurrentTransactionReadOnly); + innerTxTemplate.PropagationBehavior = TransactionPropagation.NotSupported; + innerTxTemplate.Execute(new PropagationNotSupportedWithExistingTransactionCallback2(dbProvider)); + Assert.IsTrue(status.IsNewTransaction, "Is new transaction"); + Assert.IsFalse(TransactionSynchronizationManager.CurrentTransactionReadOnly); + Assert.IsTrue(TransactionSynchronizationManager.ActualTransactionActive); + return null; + } +} + +internal class PropagationNotSupportedWithExistingTransactionCallback2 : ITransactionCallback +{ + private IDbProvider provider; + + public PropagationNotSupportedWithExistingTransactionCallback2(IDbProvider provider) + { + this.provider = provider; + } + + public object DoInTransaction(ITransactionStatus status) + { + Assert.IsTrue(!TransactionSynchronizationManager.HasResource(provider), "Hasn't thread db provider"); + Assert.IsTrue(TransactionSynchronizationManager.SynchronizationActive); + Assert.IsTrue(!status.IsNewTransaction, "Isn't new transaction"); + Assert.IsFalse(TransactionSynchronizationManager.CurrentTransactionReadOnly); + Assert.IsFalse(TransactionSynchronizationManager.ActualTransactionActive); + status.SetRollbackOnly(); + return null; + } +} + +internal class PropagationRequiresNewWithExistingTransactionAndUnrelatedFailingDataSourceCallback : ITransactionCallback +{ + private TransactionTemplate innerTxTemplate; + + public PropagationRequiresNewWithExistingTransactionAndUnrelatedFailingDataSourceCallback(TransactionTemplate transactionTemplate) + { + innerTxTemplate = transactionTemplate; + } + + public object DoInTransaction(ITransactionStatus status) + { + Assert.IsTrue(status.IsNewTransaction, "Is new transaction"); + Assert.IsTrue(TransactionSynchronizationManager.SynchronizationActive, "Synchronization active"); + Assert.IsFalse(TransactionSynchronizationManager.CurrentTransactionReadOnly); + Assert.IsTrue(TransactionSynchronizationManager.ActualTransactionActive); + innerTxTemplate.Execute(new PropagationRequiresNewWithExistingTransactionAndUnrelatedFailingDataSourceCallback2()); + return null; + } +} + +internal class PropagationRequiresNewWithExistingTransactionAndUnrelatedFailingDataSourceCallback2 : ITransactionCallback +{ + public object DoInTransaction(ITransactionStatus status) + { + status.SetRollbackOnly(); + return null; + } +} + +internal class PropagationRequiresNewWithExistingTransactionCallback : ITransactionCallback +{ + private TransactionTemplate innerTxTemplate; + private IDbProvider dbProvider; + + public PropagationRequiresNewWithExistingTransactionCallback(TransactionTemplate transactionTemplate, + IDbProvider provider) + { + innerTxTemplate = transactionTemplate; + dbProvider = provider; + } + + public object DoInTransaction(ITransactionStatus status) + { + Assert.IsTrue(status.IsNewTransaction, "Is new transaction"); + Assert.IsTrue(TransactionSynchronizationManager.SynchronizationActive, "Synchronization active"); + Assert.IsFalse(TransactionSynchronizationManager.CurrentTransactionReadOnly); + Assert.IsTrue(TransactionSynchronizationManager.ActualTransactionActive); + innerTxTemplate.Execute(new PropagationRequiresNewWithExistingTransactionCallback2(dbProvider)); + + Assert.IsTrue(status.IsNewTransaction, "Is new transaction"); + Assert.IsFalse(TransactionSynchronizationManager.CurrentTransactionReadOnly); + Assert.IsTrue(TransactionSynchronizationManager.ActualTransactionActive); + return null; + } +} + +internal class PropagationRequiresNewWithExistingTransactionCallback2 : ITransactionCallback +{ + private IDbProvider dbProvider; + + public PropagationRequiresNewWithExistingTransactionCallback2(IDbProvider dbProvider) + { + this.dbProvider = dbProvider; + } + + public object DoInTransaction(ITransactionStatus status) + { + Assert.IsTrue(TransactionSynchronizationManager.HasResource(dbProvider), "Has thread connection"); + Assert.IsTrue(TransactionSynchronizationManager.SynchronizationActive, "Synchronization active"); + Assert.IsTrue(status.IsNewTransaction, "Is new transaction"); + Assert.IsFalse(TransactionSynchronizationManager.CurrentTransactionReadOnly); + Assert.IsTrue(TransactionSynchronizationManager.ActualTransactionActive); + status.SetRollbackOnly(); + return null; + } +} + +internal class TransactionCommitTxCallback : ITransactionCallback +{ + private IDbProvider provider; + + public TransactionCommitTxCallback(IDbProvider provider) + { + this.provider = provider; + } + + public object DoInTransaction(ITransactionStatus status) + { + Assert.IsTrue(TransactionSynchronizationManager.HasResource(provider), "Has thread db provider"); + Assert.IsTrue(TransactionSynchronizationManager.SynchronizationActive); + Assert.IsTrue(status.IsNewTransaction, "Is new transaction"); + Assert.IsTrue(TransactionSynchronizationManager.ActualTransactionActive); + Assert.IsFalse(TransactionSynchronizationManager.CurrentTransactionReadOnly); + return null; + } +} + +internal class TransactionRollbackTxCallback : ITransactionCallback +{ + private IDbProvider provider; + private Exception exception; + + public TransactionRollbackTxCallback(IDbProvider provider, Exception exception) + { + this.provider = provider; + this.exception = exception; + } + + public object DoInTransaction(ITransactionStatus status) + { + Assert.IsTrue(TransactionSynchronizationManager.HasResource(provider), "Hasn't thread db provider"); + Assert.IsTrue(TransactionSynchronizationManager.SynchronizationActive); + Assert.IsTrue(status.IsNewTransaction, "Is new transaction"); + throw exception; + } +} + +internal class ParticipatingTxWithRollbackOnlyTxCallback : ITransactionCallback +{ + private TransactionTemplate innerTxTemplate; + private IDbProvider dbProvider; + + public ParticipatingTxWithRollbackOnlyTxCallback(TransactionTemplate transactionTemplate, IDbProvider dbProvider) + { + innerTxTemplate = transactionTemplate; + this.dbProvider = dbProvider; + } + + public object DoInTransaction(ITransactionStatus status) + { + Assert.IsTrue(!status.IsNewTransaction, "Is existing transaction"); + Assert.IsFalse(status.RollbackOnly, "Is not rollback-only"); + innerTxTemplate.Execute(new ParticipatingTxWithRollbackOnlyTxCallback2(dbProvider)); + Assert.IsTrue(!status.IsNewTransaction, "Is existing transaction"); + Assert.IsTrue(status.RollbackOnly, "Is rollback-only"); + return null; + } +} + +internal class ParticipatingTxWithRollbackOnlyTxCallback2 : ITransactionCallback +{ + private IDbProvider dbProvider; + + public ParticipatingTxWithRollbackOnlyTxCallback2(IDbProvider dbProvider) + { + this.dbProvider = dbProvider; + } + + public object DoInTransaction(ITransactionStatus status) + { + Assert.IsTrue(TransactionSynchronizationManager.HasResource(dbProvider), "Has thread connection"); + Assert.IsTrue(TransactionSynchronizationManager.SynchronizationActive, "Synchronization active"); + Assert.IsTrue(!status.IsNewTransaction, "Is existing transaction"); + status.SetRollbackOnly(); + return null; + } +} + +internal class TestTransactionSynchronization : ITransactionSynchronization +{ + private IDbProvider provider; + private TransactionSynchronizationStatus status; + + public bool beforeCommitCalled; + public bool beforeCompletionCalled; + public bool afterCommitCalled; + public bool afterCompletionCalled; + + public TestTransactionSynchronization(IDbProvider provider, + TransactionSynchronizationStatus synchronizationStatus) + { + this.provider = provider; + status = synchronizationStatus; + } + + public void Suspend() + { + } + + public void Resume() + { + } + + public void BeforeCommit(bool readOnly) + { + if (status == TransactionSynchronizationStatus.Committed) + { + Assert.Fail("Should never be called"); + } + + Assert.IsFalse(beforeCommitCalled); + beforeCommitCalled = true; + } + + public void AfterCommit() + { + if (status != TransactionSynchronizationStatus.Committed) + { + Assert.Fail("Should never be called"); + } + + Assert.IsFalse(afterCommitCalled); + afterCommitCalled = true; + } + + public void BeforeCompletion() + { + Assert.IsFalse(beforeCompletionCalled); + beforeCompletionCalled = true; + } + + public void AfterCompletion(TransactionSynchronizationStatus syncStatus) + { + Assert.IsFalse(afterCompletionCalled); + afterCompletionCalled = true; + Assert.IsTrue(syncStatus == status); + Assert.IsTrue(TransactionSynchronizationManager.HasResource(provider)); } } diff --git a/test/Spring/Spring.Data.Tests/Data/AutoDeclarativeTxTests.cs b/test/Spring/Spring.Data.Tests/Data/AutoDeclarativeTxTests.cs index 62639aa8..5155d97f 100644 --- a/test/Spring/Spring.Data.Tests/Data/AutoDeclarativeTxTests.cs +++ b/test/Spring/Spring.Data.Tests/Data/AutoDeclarativeTxTests.cs @@ -1,14 +1,14 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. - * + * Copyright � 2002-2011 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. @@ -29,62 +29,56 @@ using Spring.Transaction; #endregion -namespace Spring.Data +namespace Spring.Data; + +/// +/// Test case that uses the approach of automatically creating +/// declarative transaction interceptors for objects identified via means +/// of transaction attributes. +/// +/// Mark Pollack (.NET) +[TestFixture] +public class AutoDeclarativeTxTests { - /// - /// Test case that uses the approach of automatically creating - /// declarative transaction interceptors for objects identified via means - /// of transaction attributes. - /// - /// Mark Pollack (.NET) - [TestFixture] - public class AutoDeclarativeTxTests - { - private IApplicationContext ctx; + private IApplicationContext ctx; - [SetUp] - public void SetUp() - { - //LogManager.Adapter = new ConsoleOutLoggerFactoryAdapter(); - ctx = - new XmlApplicationContext("assembly://Spring.Data.Tests/Spring.Data/AutoDeclarativeTxTests.xml"); - - } + [SetUp] + public void SetUp() + { + //LogManager.Adapter = new ConsoleOutLoggerFactoryAdapter(); + ctx = + new XmlApplicationContext("assembly://Spring.Data.Tests/Spring.Data/AutoDeclarativeTxTests.xml"); + } + [Test] + public void CoordinatorDeclarativeWithAttributes() + { + ITestCoord coord = ctx["testCoordinator"] as ITestCoord; + Assert.IsNotNull(coord); + CallCountingTransactionManager ccm = ctx["transactionManager"] as CallCountingTransactionManager; + Assert.IsNotNull(ccm); + LoggingAroundAdvice advice = (LoggingAroundAdvice) ctx["consoleLoggingAroundAdvice"]; + Assert.IsNotNull(advice); + ITestObjectMgr testObjectMgr = ctx["testObjectManager"] as ITestObjectMgr; + Assert.IsNotNull(testObjectMgr); + //Proxied due to NameMatchMethodPointcutAdvisor + Assert.IsTrue(AopUtils.IsAopProxy(coord)); - [Test] - public void CoordinatorDeclarativeWithAttributes() - { - ITestCoord coord = ctx["testCoordinator"] as ITestCoord; - Assert.IsNotNull(coord); - CallCountingTransactionManager ccm = ctx["transactionManager"] as CallCountingTransactionManager; - Assert.IsNotNull(ccm); - LoggingAroundAdvice advice = (LoggingAroundAdvice)ctx["consoleLoggingAroundAdvice"]; - Assert.IsNotNull(advice); + //Proxied due to DefaultAdvisorAutoProxyCreator + Assert.IsTrue(AopUtils.IsAopProxy(testObjectMgr)); - ITestObjectMgr testObjectMgr = ctx["testObjectManager"] as ITestObjectMgr; - Assert.IsNotNull(testObjectMgr); - //Proxied due to NameMatchMethodPointcutAdvisor - Assert.IsTrue(AopUtils.IsAopProxy(coord)); + TestObject to1 = new TestObject("Jack", 7); + TestObject to2 = new TestObject("Jill", 6); - //Proxied due to DefaultAdvisorAutoProxyCreator - Assert.IsTrue(AopUtils.IsAopProxy(testObjectMgr)); + Assert.AreEqual(0, ccm.begun); + Assert.AreEqual(0, ccm.commits); + Assert.AreEqual(0, advice.numInvoked); + coord.WorkOn(to1, to2); - TestObject to1 = new TestObject("Jack", 7); - TestObject to2 = new TestObject("Jill", 6); - - Assert.AreEqual(0, ccm.begun); - Assert.AreEqual(0, ccm.commits); - Assert.AreEqual(0, advice.numInvoked); - - coord.WorkOn(to1,to2); - - Assert.AreEqual(1, ccm.begun); - Assert.AreEqual(1, ccm.commits); - Assert.AreEqual(1, advice.numInvoked); - } - - } + Assert.AreEqual(1, ccm.begun); + Assert.AreEqual(1, ccm.commits); + Assert.AreEqual(1, advice.numInvoked); + } } diff --git a/test/Spring/Spring.Data.Tests/Data/AutoDeclarativeTxTests.xml b/test/Spring/Spring.Data.Tests/Data/AutoDeclarativeTxTests.xml index c53a6496..e3dec234 100644 --- a/test/Spring/Spring.Data.Tests/Data/AutoDeclarativeTxTests.xml +++ b/test/Spring/Spring.Data.Tests/Data/AutoDeclarativeTxTests.xml @@ -1,73 +1,68 @@ - + - - - + + - + - - + + - + - - - + + + + WorkOn + + + + + - + + - - + + - - - - - + + - - - - - + + + + + - - - diff --git a/test/Spring/Spring.Data.Tests/Data/Common/AdditionalProviders.xml b/test/Spring/Spring.Data.Tests/Data/Common/AdditionalProviders.xml index 8252971e..74dbcbd8 100644 --- a/test/Spring/Spring.Data.Tests/Data/Common/AdditionalProviders.xml +++ b/test/Spring/Spring.Data.Tests/Data/Common/AdditionalProviders.xml @@ -1,86 +1,105 @@  - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - 156,170,207,208 - - - 229 - - - 544,2627,8114,8115 - - - 1205 - - - + + + 156,170,207,208 + + + 229 + + + 544,2627,8114,8115 + + + 1205 + + + - + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - 156,170,207,208 - - - 229 - - - 544,2627,8114,8115 - - - 1205 - - - + + + 156,170,207,208 + + + 229 + + + 544,2627,8114,8115 + + + 1205 + + + + + - - \ No newline at end of file diff --git a/test/Spring/Spring.Data.Tests/Data/Common/DbParametersTests.cs b/test/Spring/Spring.Data.Tests/Data/Common/DbParametersTests.cs index 8992376a..d1b6a6d6 100644 --- a/test/Spring/Spring.Data.Tests/Data/Common/DbParametersTests.cs +++ b/test/Spring/Spring.Data.Tests/Data/Common/DbParametersTests.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -21,54 +21,52 @@ #region Imports using System.Data; - using NUnit.Framework; #endregion -namespace Spring.Data.Common -{ - /// - /// This class contains tests for DbParameters - /// - /// Mark Pollack - [TestFixture] - public class DbParametersTests - { - [SetUp] - public void Setup() - { - } +namespace Spring.Data.Common; - // TODO separate providers for OracleClient +/// +/// This class contains tests for DbParameters +/// +/// Mark Pollack +[TestFixture] +public class DbParametersTests +{ + [SetUp] + public void Setup() + { + } + + // TODO separate providers for OracleClient #if !NETCOREAPP - [Test] - public void OracleClient() - { - IDbProvider dbProvider = DbProviderFactory.GetDbProvider("System.Data.OracleClient"); - DbParameters dbParameters = new DbParameters(dbProvider); - dbParameters.Add("p1", DbType.String); - IDataParameter parameter = dbParameters[0]; - Assert.AreEqual("p1", parameter.ParameterName); - dbParameters.SetValue("p1", "foo"); - object springParameter = dbParameters.GetValue("p1"); - Assert.IsNotNull(springParameter); - Assert.AreEqual("foo", springParameter); - } + [Test] + public void OracleClient() + { + IDbProvider dbProvider = DbProviderFactory.GetDbProvider("System.Data.OracleClient"); + DbParameters dbParameters = new DbParameters(dbProvider); + dbParameters.Add("p1", DbType.String); + IDataParameter parameter = dbParameters[0]; + Assert.AreEqual("p1", parameter.ParameterName); + dbParameters.SetValue("p1", "foo"); + object springParameter = dbParameters.GetValue("p1"); + Assert.IsNotNull(springParameter); + Assert.AreEqual("foo", springParameter); + } #endif - [Test] - public void SqlClient() - { - IDbProvider dbProvider = DbProviderFactory.GetDbProvider("System.Data.SqlClient"); - DbParameters dbParameters = new DbParameters(dbProvider); - dbParameters.Add("p1", DbType.String); - IDataParameter parameter = dbParameters[0]; - Assert.AreEqual("@p1", parameter.ParameterName); - dbParameters.SetValue("p1", "foo"); - object springParameter = dbParameters.GetValue("p1"); - Assert.IsNotNull(springParameter); - Assert.AreEqual("foo", springParameter); - } + [Test] + public void SqlClient() + { + IDbProvider dbProvider = DbProviderFactory.GetDbProvider("System.Data.SqlClient"); + DbParameters dbParameters = new DbParameters(dbProvider); + dbParameters.Add("p1", DbType.String); + IDataParameter parameter = dbParameters[0]; + Assert.AreEqual("@p1", parameter.ParameterName); + dbParameters.SetValue("p1", "foo"); + object springParameter = dbParameters.GetValue("p1"); + Assert.IsNotNull(springParameter); + Assert.AreEqual("foo", springParameter); } -} \ No newline at end of file +} diff --git a/test/Spring/Spring.Data.Tests/Data/Common/DbProviderFactoryTests.cs b/test/Spring/Spring.Data.Tests/Data/Common/DbProviderFactoryTests.cs index 3293c299..3bbf0aa5 100644 --- a/test/Spring/Spring.Data.Tests/Data/Common/DbProviderFactoryTests.cs +++ b/test/Spring/Spring.Data.Tests/Data/Common/DbProviderFactoryTests.cs @@ -19,295 +19,293 @@ #endregion using System.Reflection; - using NUnit.Framework; - using Spring.Context; using Spring.Context.Support; using Spring.Threading; -namespace Spring.Data.Common +namespace Spring.Data.Common; + +/// +/// Test for loading of DbProviders +/// +/// Mark Pollack (.NET) +[TestFixture] +public class DbProviderFactoryTests { - /// - /// Test for loading of DbProviders - /// - /// Mark Pollack (.NET) - [TestFixture] - public class DbProviderFactoryTests + #region Helper classes for threading tests + + public class AsyncTestDbProviderFactory : AsyncTestTask { - #region Helper classes for threading tests + private readonly string providerName; - public class AsyncTestDbProviderFactory : AsyncTestTask + public AsyncTestDbProviderFactory(int iterations, string providerName) + : base(iterations) { - private readonly string providerName; - - public AsyncTestDbProviderFactory(int iterations, string providerName) - : base(iterations) - { - this.providerName = providerName; - } - - public override void DoExecute() - { - object result = DbProviderFactory.GetDbProvider(providerName); - Assert.IsNotNull(result); - } + this.providerName = providerName; } - #endregion - - private IApplicationContext ctx; - - [SetUp] - public void SetUp() + public override void DoExecute() { - //Other tests in this assembly will have already initialized the internal context that is part of DbProviderFactory - //Reset it back to null so that tests for specifying additional database providers will be able 're-initialize' - //the internal Context of DbProviderFactory. - //Spring.Objects.Factory.Xml.NamespaceParserRegistry.RegisterParser(typeof(Spring.Data.Config.DatabaseNamespaceParser)); - if (DbProviderFactory.ApplicationContext != null) - { - FieldInfo fieldInfo = typeof (DbProviderFactory).GetField("ctx", BindingFlags.NonPublic | BindingFlags.Static); - fieldInfo.SetValue(null, null); - } - ctx = new XmlApplicationContext("assembly://Spring.Data.Tests/Spring.Data.Common/DbProviderFactoryTests.xml"); + object result = DbProviderFactory.GetDbProvider(providerName); + Assert.IsNotNull(result); + } + } + + #endregion + + private IApplicationContext ctx; + + [SetUp] + public void SetUp() + { + //Other tests in this assembly will have already initialized the internal context that is part of DbProviderFactory + //Reset it back to null so that tests for specifying additional database providers will be able 're-initialize' + //the internal Context of DbProviderFactory. + //Spring.Objects.Factory.Xml.NamespaceParserRegistry.RegisterParser(typeof(Spring.Data.Config.DatabaseNamespaceParser)); + if (DbProviderFactory.ApplicationContext != null) + { + FieldInfo fieldInfo = typeof(DbProviderFactory).GetField("ctx", BindingFlags.NonPublic | BindingFlags.Static); + fieldInfo.SetValue(null, null); } - [Test] - public void ThreadSafety() - { + ctx = new XmlApplicationContext("assembly://Spring.Data.Tests/Spring.Data.Common/DbProviderFactoryTests.xml"); + } + + [Test] + public void ThreadSafety() + { #if NETCOREAPP const string providerName = "SqlServer"; #else - const string providerName = "SqlServer-2.0"; + const string providerName = "SqlServer-2.0"; #endif - AsyncTestTask t1 = new AsyncTestDbProviderFactory(1000, providerName).Start(); - AsyncTestTask t2 = new AsyncTestDbProviderFactory(1000, providerName).Start(); - AsyncTestTask t3 = new AsyncTestDbProviderFactory(1000, providerName).Start(); - AsyncTestTask t4 = new AsyncTestDbProviderFactory(1000, providerName).Start(); + AsyncTestTask t1 = new AsyncTestDbProviderFactory(1000, providerName).Start(); + AsyncTestTask t2 = new AsyncTestDbProviderFactory(1000, providerName).Start(); + AsyncTestTask t3 = new AsyncTestDbProviderFactory(1000, providerName).Start(); + AsyncTestTask t4 = new AsyncTestDbProviderFactory(1000, providerName).Start(); - t1.AssertNoException(); - t2.AssertNoException(); - t3.AssertNoException(); - t4.AssertNoException(); - } + t1.AssertNoException(); + t2.AssertNoException(); + t3.AssertNoException(); + t4.AssertNoException(); + } - [Test] - public void AdditionalResourceName() - { - IDbProvider provider = DbProviderFactory.GetDbProvider("Test-SqlServer-2.0"); - Assert.IsNotNull(provider); - } + [Test] + public void AdditionalResourceName() + { + IDbProvider provider = DbProviderFactory.GetDbProvider("Test-SqlServer-2.0"); + Assert.IsNotNull(provider); + } - [Test] - public void BadErrorExpression() - { - IDbProvider provider = DbProviderFactory.GetDbProvider("Test-SqlServer-2.0-BadErrorCodeExpression"); - Assert.IsNotNull(provider); - string errorCode = provider.ExtractError(new Exception("foo")); - Assert.AreEqual("156", errorCode); - } + [Test] + public void BadErrorExpression() + { + IDbProvider provider = DbProviderFactory.GetDbProvider("Test-SqlServer-2.0-BadErrorCodeExpression"); + Assert.IsNotNull(provider); + string errorCode = provider.ExtractError(new Exception("foo")); + Assert.AreEqual("156", errorCode); + } #if !NETCOREAPP - [Test] - public void DefaultInstanceWithSqlServer20() - { - System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("en-US", false); - //IApplicationContext ctx = DbProviderFactory.ApplicationContext; - //Assert.IsNotNull(ctx); - System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("tr-TR", false); - IDbProvider provider = DbProviderFactory.GetDbProvider("SqlServer-2.0"); - AssertIsSqlServer2005(provider); - provider = DbProviderFactory.GetDbProvider("System.Data.SqlClient"); - AssertIsSqlServer2005(provider); - Assert.IsNull(provider.ConnectionString); - Assert.IsNotNull(provider.CreateCommand()); - Assert.IsNotNull(provider.CreateCommandBuilder()); - Assert.IsNotNull(provider.CreateConnection()); - Assert.IsNotNull(provider.CreateDataAdapter()); - Assert.IsNotNull(provider.CreateParameter()); - Assert.AreEqual("@Foo", provider.CreateParameterName("Foo")); - } + [Test] + public void DefaultInstanceWithSqlServer20() + { + System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("en-US", false); + //IApplicationContext ctx = DbProviderFactory.ApplicationContext; + //Assert.IsNotNull(ctx); + System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("tr-TR", false); + IDbProvider provider = DbProviderFactory.GetDbProvider("SqlServer-2.0"); + AssertIsSqlServer2005(provider); + provider = DbProviderFactory.GetDbProvider("System.Data.SqlClient"); + AssertIsSqlServer2005(provider); + Assert.IsNull(provider.ConnectionString); + Assert.IsNotNull(provider.CreateCommand()); + Assert.IsNotNull(provider.CreateCommandBuilder()); + Assert.IsNotNull(provider.CreateConnection()); + Assert.IsNotNull(provider.CreateDataAdapter()); + Assert.IsNotNull(provider.CreateParameter()); + Assert.AreEqual("@Foo", provider.CreateParameterName("Foo")); + } - [Test] - public void DefaultInstanceWithOleDb20() - { - IDbProvider provider = DbProviderFactory.GetDbProvider("OleDb-2.0"); - Assert.AreEqual("OleDb, provider V2.0.0.0 in framework .NET V2", provider.DbMetadata.ProductName); - Assert.IsNotNull(provider.CreateCommand()); - Assert.IsNotNull(provider.CreateCommandBuilder()); - Assert.IsNotNull(provider.CreateConnection()); - Assert.IsNotNull(provider.CreateDataAdapter()); - Assert.IsNotNull(provider.CreateParameter()); - Assert.AreEqual("?", provider.CreateParameterName("Foo")); - } + [Test] + public void DefaultInstanceWithOleDb20() + { + IDbProvider provider = DbProviderFactory.GetDbProvider("OleDb-2.0"); + Assert.AreEqual("OleDb, provider V2.0.0.0 in framework .NET V2", provider.DbMetadata.ProductName); + Assert.IsNotNull(provider.CreateCommand()); + Assert.IsNotNull(provider.CreateCommandBuilder()); + Assert.IsNotNull(provider.CreateConnection()); + Assert.IsNotNull(provider.CreateDataAdapter()); + Assert.IsNotNull(provider.CreateParameter()); + Assert.AreEqual("?", provider.CreateParameterName("Foo")); + } - [Test] - public void DefaultInstanceWithMicrosoftOracleClient20() - { - IDbProvider provider = DbProviderFactory.GetDbProvider("OracleClient-2.0"); - Assert.AreEqual("Oracle, Microsoft provider V2.0.0.0", provider.DbMetadata.ProductName); - Assert.IsNotNull(provider.CreateCommand()); - Assert.IsNotNull(provider.CreateCommandBuilder()); - Assert.IsNotNull(provider.CreateConnection()); - Assert.IsNotNull(provider.CreateDataAdapter()); - Assert.IsNotNull(provider.CreateParameter()); - Assert.AreEqual(":Foo", provider.CreateParameterName("Foo")); - } + [Test] + public void DefaultInstanceWithMicrosoftOracleClient20() + { + IDbProvider provider = DbProviderFactory.GetDbProvider("OracleClient-2.0"); + Assert.AreEqual("Oracle, Microsoft provider V2.0.0.0", provider.DbMetadata.ProductName); + Assert.IsNotNull(provider.CreateCommand()); + Assert.IsNotNull(provider.CreateCommandBuilder()); + Assert.IsNotNull(provider.CreateConnection()); + Assert.IsNotNull(provider.CreateDataAdapter()); + Assert.IsNotNull(provider.CreateParameter()); + Assert.AreEqual(":Foo", provider.CreateParameterName("Foo")); + } - [Test] - public void DefaultInstanceWithOleDb40() - { - IDbProvider provider = DbProviderFactory.GetDbProvider("OleDb-4.0"); - Assert.AreEqual("OleDb, provider V4.0.0.0 in framework .NET V4", provider.DbMetadata.ProductName); - Assert.IsNotNull(provider.CreateCommand()); - Assert.IsNotNull(provider.CreateCommandBuilder()); - Assert.IsNotNull(provider.CreateConnection()); - Assert.IsNotNull(provider.CreateDataAdapter()); - Assert.IsNotNull(provider.CreateParameter()); - Assert.AreEqual("?", provider.CreateParameterName("Foo")); - } + [Test] + public void DefaultInstanceWithOleDb40() + { + IDbProvider provider = DbProviderFactory.GetDbProvider("OleDb-4.0"); + Assert.AreEqual("OleDb, provider V4.0.0.0 in framework .NET V4", provider.DbMetadata.ProductName); + Assert.IsNotNull(provider.CreateCommand()); + Assert.IsNotNull(provider.CreateCommandBuilder()); + Assert.IsNotNull(provider.CreateConnection()); + Assert.IsNotNull(provider.CreateDataAdapter()); + Assert.IsNotNull(provider.CreateParameter()); + Assert.AreEqual("?", provider.CreateParameterName("Foo")); + } - [Test] - public void DefaultInstanceWithSqlServer40() - { - IDbProvider provider = DbProviderFactory.GetDbProvider("SqlServer-4.0"); - AssertIsSqlServer40(provider); - Assert.IsNull(provider.ConnectionString); - Assert.IsNotNull(provider.CreateCommand()); - Assert.IsNotNull(provider.CreateCommandBuilder()); - Assert.IsNotNull(provider.CreateConnection()); - Assert.IsNotNull(provider.CreateDataAdapter()); - Assert.IsNotNull(provider.CreateParameter()); - Assert.AreEqual("@Foo", provider.CreateParameterName("Foo")); - } + [Test] + public void DefaultInstanceWithSqlServer40() + { + IDbProvider provider = DbProviderFactory.GetDbProvider("SqlServer-4.0"); + AssertIsSqlServer40(provider); + Assert.IsNull(provider.ConnectionString); + Assert.IsNotNull(provider.CreateCommand()); + Assert.IsNotNull(provider.CreateCommandBuilder()); + Assert.IsNotNull(provider.CreateConnection()); + Assert.IsNotNull(provider.CreateDataAdapter()); + Assert.IsNotNull(provider.CreateParameter()); + Assert.AreEqual("@Foo", provider.CreateParameterName("Foo")); + } - [Test] - public void TestSqlServer20Names() - { - //Initialize internal application context. factory - DbProviderFactory.GetDbProvider("SqlServer-2.0"); - IApplicationContext ctx = DbProviderFactory.ApplicationContext; - var dbProviderNames = ctx.GetObjectNamesForType(typeof (IDbProvider)); - Assert.IsTrue(dbProviderNames.Count > 0); - } + [Test] + public void TestSqlServer20Names() + { + //Initialize internal application context. factory + DbProviderFactory.GetDbProvider("SqlServer-2.0"); + IApplicationContext ctx = DbProviderFactory.ApplicationContext; + var dbProviderNames = ctx.GetObjectNamesForType(typeof (IDbProvider)); + Assert.IsTrue(dbProviderNames.Count > 0); + } #endif - [Test] - public void DefaultInstanceWithOracleClient10_20() + [Test] + public void DefaultInstanceWithOracleClient10_20() + { + if (Type.GetType("Oracle.DataAccess.Client.OracleConnection, Oracle.DataAccess, Version=2.102.2.20, Culture=neutral, PublicKeyToken=89b483f429c47342") == null) { - if (Type.GetType("Oracle.DataAccess.Client.OracleConnection, Oracle.DataAccess, Version=2.102.2.20, Culture=neutral, PublicKeyToken=89b483f429c47342") == null) - { - Assert.Inconclusive("oracle data access libs not found, skipping test"); - } - - AssertOracleProvider("OracleODP-2.0", "Oracle, Oracle provider V2.102.2.20"); + Assert.Inconclusive("oracle data access libs not found, skipping test"); } - [Test] - public void DefaultInstanceWithOracleClient11_20() - { - if (Type.GetType("Oracle.DataAccess.Client.OracleConnection, Oracle.DataAccess, Version=2.112.3.0, Culture=neutral, PublicKeyToken=89b483f429c47342") == null) - { - Assert.Inconclusive("oracle data access libs not found, skipping test"); - } + AssertOracleProvider("OracleODP-2.0", "Oracle, Oracle provider V2.102.2.20"); + } - AssertOracleProvider("OracleODP-11-2.0", "Oracle, Oracle provider V2.112.3.0"); + [Test] + public void DefaultInstanceWithOracleClient11_20() + { + if (Type.GetType("Oracle.DataAccess.Client.OracleConnection, Oracle.DataAccess, Version=2.112.3.0, Culture=neutral, PublicKeyToken=89b483f429c47342") == null) + { + Assert.Inconclusive("oracle data access libs not found, skipping test"); } - [Test] - public void DefaultInstanceWithOracleClient12_20() - { - if (Type.GetType("Oracle.DataAccess.Client.OracleConnection, Oracle.DataAccess, Version=2.121.1.0, Culture=neutral, PublicKeyToken=89b483f429c47342") == null) - { - Assert.Inconclusive("oracle data access libs not found, skipping test"); - } + AssertOracleProvider("OracleODP-11-2.0", "Oracle, Oracle provider V2.112.3.0"); + } - AssertOracleProvider("OracleODP-12-2.0", "Oracle, Oracle provider V2.121.1.0"); + [Test] + public void DefaultInstanceWithOracleClient12_20() + { + if (Type.GetType("Oracle.DataAccess.Client.OracleConnection, Oracle.DataAccess, Version=2.121.1.0, Culture=neutral, PublicKeyToken=89b483f429c47342") == null) + { + Assert.Inconclusive("oracle data access libs not found, skipping test"); } - [Test] - public void DefaultInstanceWithOracleClient12_40() - { - if (Type.GetType("Oracle.DataAccess.Client.OracleConnection, Oracle.DataAccess, Version=4.121.1.0, Culture=neutral, PublicKeyToken=89b483f429c47342") == null) - { - Assert.Inconclusive("oracle data access libs not found, skipping test"); - } + AssertOracleProvider("OracleODP-12-2.0", "Oracle, Oracle provider V2.121.1.0"); + } - AssertOracleProvider("OracleODP-12-4.0", "Oracle, Oracle provider V4.121.1.0"); + [Test] + public void DefaultInstanceWithOracleClient12_40() + { + if (Type.GetType("Oracle.DataAccess.Client.OracleConnection, Oracle.DataAccess, Version=4.121.1.0, Culture=neutral, PublicKeyToken=89b483f429c47342") == null) + { + Assert.Inconclusive("oracle data access libs not found, skipping test"); } - [Test] - public void DefaultInstanceWithOracleManagedClient11_40() - { - if (Type.GetType("Oracle.ManagedDataAccess.Client.OracleConnection, Oracle.ManagedDataAccess, Version=4.121.1.0, Culture=neutral, PublicKeyToken=89b483f429c47342") == null) - { - Assert.Inconclusive("oracle data access libs not found, skipping test"); - } + AssertOracleProvider("OracleODP-12-4.0", "Oracle, Oracle provider V4.121.1.0"); + } - AssertOracleProvider("OracleODP-Managed-12-4.0", "Oracle, Oracle Managed provider V4.121.1.0"); + [Test] + public void DefaultInstanceWithOracleManagedClient11_40() + { + if (Type.GetType("Oracle.ManagedDataAccess.Client.OracleConnection, Oracle.ManagedDataAccess, Version=4.121.1.0, Culture=neutral, PublicKeyToken=89b483f429c47342") == null) + { + Assert.Inconclusive("oracle data access libs not found, skipping test"); } - private static void AssertOracleProvider(string providerName, string productName) + AssertOracleProvider("OracleODP-Managed-12-4.0", "Oracle, Oracle Managed provider V4.121.1.0"); + } + + private static void AssertOracleProvider(string providerName, string productName) + { + IDbProvider provider = DbProviderFactory.GetDbProvider(providerName); + Assert.AreEqual(productName, provider.DbMetadata.ProductName); + + var command = provider.CreateCommand(); + Assert.IsNotNull(command); + + // check if parameter has readable BindByName property + var property = command.GetType().GetProperty("BindByName"); + if (property != null) { - IDbProvider provider = DbProviderFactory.GetDbProvider(providerName); - Assert.AreEqual(productName, provider.DbMetadata.ProductName); - - var command = provider.CreateCommand(); - Assert.IsNotNull(command); - - // check if parameter has readable BindByName property - var property = command.GetType().GetProperty("BindByName"); - if (property != null) - { - var bindByNameValue = property.GetValue(command, null); - Assert.That(bindByNameValue, Is.EqualTo(provider.DbMetadata.BindByName), "BindByName had wrong value"); - } - - Assert.IsNotNull(provider.CreateCommandBuilder()); - Assert.IsNotNull(provider.CreateConnection()); - Assert.IsNotNull(provider.CreateDataAdapter()); - Assert.IsNotNull(provider.CreateParameter()); - Assert.AreEqual(":Foo", provider.CreateParameterName("Foo")); + var bindByNameValue = property.GetValue(command, null); + Assert.That(bindByNameValue, Is.EqualTo(provider.DbMetadata.BindByName), "BindByName had wrong value"); } - /* - [Test] - public void DefaultInstanceWithMySql() - { - DbProviderFactory.DBPROVIDER_ADDITIONAL_RESOURCE_NAME = - "assembly://Spring.Data.Tests/Spring.Data.Common/AdditionalProviders.xml"; - IDbProvider provider = DbProviderFactory.GetDbProvider("MySqlPersonal"); - Assert.AreEqual("MySQL, MySQL provider 1.0.7.30072", provider.DbMetadata.ProductName); + Assert.IsNotNull(provider.CreateCommandBuilder()); + Assert.IsNotNull(provider.CreateConnection()); + Assert.IsNotNull(provider.CreateDataAdapter()); + Assert.IsNotNull(provider.CreateParameter()); + Assert.AreEqual(":Foo", provider.CreateParameterName("Foo")); + } - } + /* + [Test] + public void DefaultInstanceWithMySql() + { + DbProviderFactory.DBPROVIDER_ADDITIONAL_RESOURCE_NAME = + "assembly://Spring.Data.Tests/Spring.Data.Common/AdditionalProviders.xml"; + IDbProvider provider = DbProviderFactory.GetDbProvider("MySqlPersonal"); + Assert.AreEqual("MySQL, MySQL provider 1.0.7.30072", provider.DbMetadata.ProductName); - */ + } - private void AssertIsSqlServer2005(IDbProvider provider) - { - Assert.AreEqual("Microsoft SQL Server, provider V2.0.0.0 in framework .NET V2.0", - provider.DbMetadata.ProductName); - AssertCommonSqlServerErrorCodes(provider); - } + */ - private void AssertIsSqlServer40(IDbProvider provider) - { - Assert.AreEqual("Microsoft SQL Server, provider V4.0.0.0 in framework .NET V4.0", - provider.DbMetadata.ProductName); - AssertCommonSqlServerErrorCodes(provider); - } + private void AssertIsSqlServer2005(IDbProvider provider) + { + Assert.AreEqual("Microsoft SQL Server, provider V2.0.0.0 in framework .NET V2.0", + provider.DbMetadata.ProductName); + AssertCommonSqlServerErrorCodes(provider); + } - private static void AssertCommonSqlServerErrorCodes(IDbProvider provider) - { - ErrorCodes codes = provider.DbMetadata.ErrorCodes; - Assert.IsTrue(codes.BadSqlGrammarCodes.Length > 0); - Assert.IsTrue(codes.DataIntegrityViolationCodes.Length > 0); - // This had better be a Bad SQL Grammar code - Assert.IsTrue(Array.IndexOf(codes.BadSqlGrammarCodes, "156") >= 0); - // This had better NOT be - Assert.IsFalse(Array.IndexOf(codes.BadSqlGrammarCodes, "1xx56") >= 0); - } + private void AssertIsSqlServer40(IDbProvider provider) + { + Assert.AreEqual("Microsoft SQL Server, provider V4.0.0.0 in framework .NET V4.0", + provider.DbMetadata.ProductName); + AssertCommonSqlServerErrorCodes(provider); + } + + private static void AssertCommonSqlServerErrorCodes(IDbProvider provider) + { + ErrorCodes codes = provider.DbMetadata.ErrorCodes; + Assert.IsTrue(codes.BadSqlGrammarCodes.Length > 0); + Assert.IsTrue(codes.DataIntegrityViolationCodes.Length > 0); + // This had better be a Bad SQL Grammar code + Assert.IsTrue(Array.IndexOf(codes.BadSqlGrammarCodes, "156") >= 0); + // This had better NOT be + Assert.IsFalse(Array.IndexOf(codes.BadSqlGrammarCodes, "1xx56") >= 0); } } diff --git a/test/Spring/Spring.Data.Tests/Data/Common/DbProviderFactoryTests.xml b/test/Spring/Spring.Data.Tests/Data/Common/DbProviderFactoryTests.xml index 16bdd921..d57d46b3 100644 --- a/test/Spring/Spring.Data.Tests/Data/Common/DbProviderFactoryTests.xml +++ b/test/Spring/Spring.Data.Tests/Data/Common/DbProviderFactoryTests.xml @@ -1,15 +1,15 @@ - + - - - - - - + + + + + + diff --git a/test/Spring/Spring.Data.Tests/Data/Common/MultiDelegatingDbProviderTests.cs b/test/Spring/Spring.Data.Tests/Data/Common/MultiDelegatingDbProviderTests.cs index 61bdd5b3..ee083020 100644 --- a/test/Spring/Spring.Data.Tests/Data/Common/MultiDelegatingDbProviderTests.cs +++ b/test/Spring/Spring.Data.Tests/Data/Common/MultiDelegatingDbProviderTests.cs @@ -21,221 +21,216 @@ using System.Collections; using System.Data; using System.Data.Common; - using FakeItEasy; - using NUnit.Framework; - using Spring.Dao; using Spring.Threading; -namespace Spring.Data.Common +namespace Spring.Data.Common; + +/// +/// Test for MultiDelegatingDbProvider +/// +/// Mark Pollack (.NET) +[TestFixture] +public class MultiDelegatingDbProviderTests { - /// - /// Test for MultiDelegatingDbProvider - /// - /// Mark Pollack (.NET) - [TestFixture] - public class MultiDelegatingDbProviderTests + [Test] + public void CreationWhenNoRequiredPropertiesSet() { - [Test] - public void CreationWhenNoRequiredPropertiesSet() + MultiDelegatingDbProvider dbProvider = new MultiDelegatingDbProvider(); + Assert.Throws(() => dbProvider.AfterPropertiesSet()); + } + + [Test] + public void CreationWithWrongTypeDictionaryKeys() + { + try { MultiDelegatingDbProvider dbProvider = new MultiDelegatingDbProvider(); - Assert.Throws(() => dbProvider.AfterPropertiesSet()); - } - - [Test] - public void CreationWithWrongTypeDictionaryKeys() - { - try - { - MultiDelegatingDbProvider dbProvider = new MultiDelegatingDbProvider(); - IDictionary targetDbProviders = new Hashtable(); - targetDbProviders.Add(1, "bar"); - dbProvider.TargetDbProviders = targetDbProviders; - dbProvider.AfterPropertiesSet(); - Assert.Fail("Should have thrown ArgumentException"); - } - catch (ArgumentException ex) - { - Assert.AreEqual("Key identifying target IDbProvider in TargetDbProviders dictionary property is required to be of type string. Key = [1], type = [System.Int32]", ex.Message); - } - } - - [Test] - public void CreationWithWrongTypeDictionaryValues() - { - try - { - IDictionary targetDbProviders = new Hashtable(); - targetDbProviders.Add("foo", 1); - //Exercise the constructor - MultiDelegatingDbProvider dbProvider = new MultiDelegatingDbProvider(targetDbProviders); - dbProvider.AfterPropertiesSet(); - Assert.Fail("Should have thrown ArgumentException"); - } - catch (ArgumentException ex) - { - Assert.AreEqual("Value in TargetDbProviders dictionary is not of type IDbProvider. Type = [System.Int32]", ex.Message); - } - } - - [Test] - public void NoDefaultProvided() - { - IDbProvider provider = DbProviderFactory.GetDbProvider("System.Data.SqlClient"); - provider.ConnectionString = "connString1"; - MultiDelegatingDbProvider multiDbProvider = new MultiDelegatingDbProvider(); IDictionary targetDbProviders = new Hashtable(); - targetDbProviders.Add("db1", provider); - multiDbProvider.TargetDbProviders = targetDbProviders; - multiDbProvider.AfterPropertiesSet(); - try - { - Assert.AreEqual("connString1", multiDbProvider.ConnectionString); - Assert.Fail("InvalidDataAccessApiUsageException should have been thrown"); - } - catch (InvalidDataAccessApiUsageException exception) - { - Assert.AreEqual("No provider name found in thread local storage. Consider setting the property DefaultDbProvider to fallback to a default value.", exception.Message); - } - finally - { - LogicalThreadContext.FreeNamedDataSlot(MultiDelegatingDbProvider.CURRENT_DBPROVIDER_SLOTNAME); - } + targetDbProviders.Add(1, "bar"); + dbProvider.TargetDbProviders = targetDbProviders; + dbProvider.AfterPropertiesSet(); + Assert.Fail("Should have thrown ArgumentException"); } - - [Test] - public void NoMatchingProviderDefinedInThreadLocalStorage() + catch (ArgumentException ex) { - IDbProvider provider = DbProviderFactory.GetDbProvider("System.Data.SqlClient"); - provider.ConnectionString = "connString1"; - MultiDelegatingDbProvider multiDbProvider = new MultiDelegatingDbProvider(); - IDictionary targetDbProviders = new Hashtable(); - targetDbProviders.Add("db1", provider); - multiDbProvider.TargetDbProviders = targetDbProviders; - multiDbProvider.AfterPropertiesSet(); - try - { - MultiDelegatingDbProvider.CurrentDbProviderName = "db2"; - Assert.AreEqual("connString1", multiDbProvider.ConnectionString); - Assert.Fail("InvalidDataAccessApiUsageException should have been thrown"); - } - catch (InvalidDataAccessApiUsageException exception) - { - Assert.AreEqual("'db2' was not under the thread local key 'dbProviderName' and no default IDbProvider was set.", exception.Message); - } - finally - { - LogicalThreadContext.FreeNamedDataSlot(MultiDelegatingDbProvider.CURRENT_DBPROVIDER_SLOTNAME); - } - } - - [Test] - public void MatchingProviderDefinedInThreadLocalStorage() - { - IDbProvider provider1 = DbProviderFactory.GetDbProvider("System.Data.SqlClient"); - provider1.ConnectionString = "connString1"; - IDbProvider provider2 = DbProviderFactory.GetDbProvider("System.Data.SqlClient"); - provider2.ConnectionString = "connString2"; - MultiDelegatingDbProvider multiDbProvider = new MultiDelegatingDbProvider(); - IDictionary targetDbProviders = new Hashtable(); - targetDbProviders.Add("db1", provider1); - targetDbProviders.Add("db2", provider2); - multiDbProvider.DefaultDbProvider = provider1; - multiDbProvider.TargetDbProviders = targetDbProviders; - multiDbProvider.AfterPropertiesSet(); - - //an aside, set setter for connection string - multiDbProvider.ConnectionString = "connString1Reset"; - Assert.AreEqual("connString1Reset", multiDbProvider.ConnectionString); - - MultiDelegatingDbProvider.CurrentDbProviderName = "db2"; - try - { - Assert.AreEqual("connString2", multiDbProvider.ConnectionString); - } - finally - { - LogicalThreadContext.FreeNamedDataSlot(MultiDelegatingDbProvider.CURRENT_DBPROVIDER_SLOTNAME); - } - } - - [Test] - public void FallbackToDefault() - { - IDbProvider provider1 = DbProviderFactory.GetDbProvider("System.Data.SqlClient"); - provider1.ConnectionString = "connString1"; - IDbProvider provider2 = DbProviderFactory.GetDbProvider("System.Data.SqlClient"); - provider2.ConnectionString = "connString2"; - MultiDelegatingDbProvider multiDbProvider = new MultiDelegatingDbProvider(); - IDictionary targetDbProviders = new Hashtable(); - targetDbProviders.Add("db1", provider1); - targetDbProviders.Add("db2", provider2); - multiDbProvider.DefaultDbProvider = provider1; - multiDbProvider.TargetDbProviders = targetDbProviders; - multiDbProvider.AfterPropertiesSet(); - - MultiDelegatingDbProvider.CurrentDbProviderName = "db314"; - try - { - Assert.AreEqual("connString1", multiDbProvider.ConnectionString); - } - finally - { - LogicalThreadContext.FreeNamedDataSlot(MultiDelegatingDbProvider.CURRENT_DBPROVIDER_SLOTNAME); - } - } - - [Test] - public void CreateOperations() - { - IDbProvider dbProvider = A.Fake(); - IDbConnection mockConnection = A.Fake(); - A.CallTo(() => dbProvider.CreateConnection()).Returns(mockConnection).Once(); - - IDbCommand mockCommand = A.Fake(); - A.CallTo(() => dbProvider.CreateCommand()).Returns(mockCommand).Once(); - - IDbDataParameter mockParameter = A.Fake(); - A.CallTo(() => dbProvider.CreateParameter()).Returns(mockParameter).Once(); - - IDbDataAdapter mockDataAdapter = A.Fake(); - A.CallTo(() => dbProvider.CreateDataAdapter()).Returns(mockDataAdapter).Once(); - - DbCommandBuilder mockDbCommandBuilder = A.Fake(); - A.CallTo(() => dbProvider.CreateCommandBuilder()).Returns(mockDbCommandBuilder).Once(); - - A.CallTo(() => dbProvider.CreateParameterName("p1")).Returns("@p1").Once(); - A.CallTo(() => dbProvider.CreateParameterNameForCollection("c1")).Returns("cc1"); - - IDbMetadata mockDbMetaData = A.Fake(); - A.CallTo(() => dbProvider.DbMetadata).Returns(mockDbMetaData); - - Exception e = new Exception("foo"); - A.CallTo(() => dbProvider.ExtractError(e)).Returns("badsql").Once(); - DbException dbException = A.Fake(); - - - MultiDelegatingDbProvider multiDbProvider = new MultiDelegatingDbProvider(); - IDictionary targetDbProviders = new Hashtable(); - targetDbProviders.Add("db1", dbProvider); - multiDbProvider.DefaultDbProvider = dbProvider; - multiDbProvider.TargetDbProviders = targetDbProviders; - multiDbProvider.AfterPropertiesSet(); - - Assert.IsNotNull(multiDbProvider.CreateConnection()); - Assert.IsNotNull(multiDbProvider.CreateCommand()); - Assert.IsNotNull(multiDbProvider.CreateParameter()); - Assert.IsNotNull(multiDbProvider.CreateDataAdapter()); - Assert.IsNotNull(multiDbProvider.CreateCommandBuilder() as DbCommandBuilder); - Assert.AreEqual("@p1", multiDbProvider.CreateParameterName("p1")); - Assert.AreEqual("cc1", multiDbProvider.CreateParameterNameForCollection("c1")); - Assert.IsNotNull(multiDbProvider.DbMetadata); - Assert.AreEqual("badsql", multiDbProvider.ExtractError(e)); - Assert.IsTrue(multiDbProvider.IsDataAccessException(dbException)); - Assert.IsFalse(multiDbProvider.IsDataAccessException(e)); + Assert.AreEqual("Key identifying target IDbProvider in TargetDbProviders dictionary property is required to be of type string. Key = [1], type = [System.Int32]", ex.Message); } } + + [Test] + public void CreationWithWrongTypeDictionaryValues() + { + try + { + IDictionary targetDbProviders = new Hashtable(); + targetDbProviders.Add("foo", 1); + //Exercise the constructor + MultiDelegatingDbProvider dbProvider = new MultiDelegatingDbProvider(targetDbProviders); + dbProvider.AfterPropertiesSet(); + Assert.Fail("Should have thrown ArgumentException"); + } + catch (ArgumentException ex) + { + Assert.AreEqual("Value in TargetDbProviders dictionary is not of type IDbProvider. Type = [System.Int32]", ex.Message); + } + } + + [Test] + public void NoDefaultProvided() + { + IDbProvider provider = DbProviderFactory.GetDbProvider("System.Data.SqlClient"); + provider.ConnectionString = "connString1"; + MultiDelegatingDbProvider multiDbProvider = new MultiDelegatingDbProvider(); + IDictionary targetDbProviders = new Hashtable(); + targetDbProviders.Add("db1", provider); + multiDbProvider.TargetDbProviders = targetDbProviders; + multiDbProvider.AfterPropertiesSet(); + try + { + Assert.AreEqual("connString1", multiDbProvider.ConnectionString); + Assert.Fail("InvalidDataAccessApiUsageException should have been thrown"); + } + catch (InvalidDataAccessApiUsageException exception) + { + Assert.AreEqual("No provider name found in thread local storage. Consider setting the property DefaultDbProvider to fallback to a default value.", exception.Message); + } + finally + { + LogicalThreadContext.FreeNamedDataSlot(MultiDelegatingDbProvider.CURRENT_DBPROVIDER_SLOTNAME); + } + } + + [Test] + public void NoMatchingProviderDefinedInThreadLocalStorage() + { + IDbProvider provider = DbProviderFactory.GetDbProvider("System.Data.SqlClient"); + provider.ConnectionString = "connString1"; + MultiDelegatingDbProvider multiDbProvider = new MultiDelegatingDbProvider(); + IDictionary targetDbProviders = new Hashtable(); + targetDbProviders.Add("db1", provider); + multiDbProvider.TargetDbProviders = targetDbProviders; + multiDbProvider.AfterPropertiesSet(); + try + { + MultiDelegatingDbProvider.CurrentDbProviderName = "db2"; + Assert.AreEqual("connString1", multiDbProvider.ConnectionString); + Assert.Fail("InvalidDataAccessApiUsageException should have been thrown"); + } + catch (InvalidDataAccessApiUsageException exception) + { + Assert.AreEqual("'db2' was not under the thread local key 'dbProviderName' and no default IDbProvider was set.", exception.Message); + } + finally + { + LogicalThreadContext.FreeNamedDataSlot(MultiDelegatingDbProvider.CURRENT_DBPROVIDER_SLOTNAME); + } + } + + [Test] + public void MatchingProviderDefinedInThreadLocalStorage() + { + IDbProvider provider1 = DbProviderFactory.GetDbProvider("System.Data.SqlClient"); + provider1.ConnectionString = "connString1"; + IDbProvider provider2 = DbProviderFactory.GetDbProvider("System.Data.SqlClient"); + provider2.ConnectionString = "connString2"; + MultiDelegatingDbProvider multiDbProvider = new MultiDelegatingDbProvider(); + IDictionary targetDbProviders = new Hashtable(); + targetDbProviders.Add("db1", provider1); + targetDbProviders.Add("db2", provider2); + multiDbProvider.DefaultDbProvider = provider1; + multiDbProvider.TargetDbProviders = targetDbProviders; + multiDbProvider.AfterPropertiesSet(); + + //an aside, set setter for connection string + multiDbProvider.ConnectionString = "connString1Reset"; + Assert.AreEqual("connString1Reset", multiDbProvider.ConnectionString); + + MultiDelegatingDbProvider.CurrentDbProviderName = "db2"; + try + { + Assert.AreEqual("connString2", multiDbProvider.ConnectionString); + } + finally + { + LogicalThreadContext.FreeNamedDataSlot(MultiDelegatingDbProvider.CURRENT_DBPROVIDER_SLOTNAME); + } + } + + [Test] + public void FallbackToDefault() + { + IDbProvider provider1 = DbProviderFactory.GetDbProvider("System.Data.SqlClient"); + provider1.ConnectionString = "connString1"; + IDbProvider provider2 = DbProviderFactory.GetDbProvider("System.Data.SqlClient"); + provider2.ConnectionString = "connString2"; + MultiDelegatingDbProvider multiDbProvider = new MultiDelegatingDbProvider(); + IDictionary targetDbProviders = new Hashtable(); + targetDbProviders.Add("db1", provider1); + targetDbProviders.Add("db2", provider2); + multiDbProvider.DefaultDbProvider = provider1; + multiDbProvider.TargetDbProviders = targetDbProviders; + multiDbProvider.AfterPropertiesSet(); + + MultiDelegatingDbProvider.CurrentDbProviderName = "db314"; + try + { + Assert.AreEqual("connString1", multiDbProvider.ConnectionString); + } + finally + { + LogicalThreadContext.FreeNamedDataSlot(MultiDelegatingDbProvider.CURRENT_DBPROVIDER_SLOTNAME); + } + } + + [Test] + public void CreateOperations() + { + IDbProvider dbProvider = A.Fake(); + IDbConnection mockConnection = A.Fake(); + A.CallTo(() => dbProvider.CreateConnection()).Returns(mockConnection).Once(); + + IDbCommand mockCommand = A.Fake(); + A.CallTo(() => dbProvider.CreateCommand()).Returns(mockCommand).Once(); + + IDbDataParameter mockParameter = A.Fake(); + A.CallTo(() => dbProvider.CreateParameter()).Returns(mockParameter).Once(); + + IDbDataAdapter mockDataAdapter = A.Fake(); + A.CallTo(() => dbProvider.CreateDataAdapter()).Returns(mockDataAdapter).Once(); + + DbCommandBuilder mockDbCommandBuilder = A.Fake(); + A.CallTo(() => dbProvider.CreateCommandBuilder()).Returns(mockDbCommandBuilder).Once(); + + A.CallTo(() => dbProvider.CreateParameterName("p1")).Returns("@p1").Once(); + A.CallTo(() => dbProvider.CreateParameterNameForCollection("c1")).Returns("cc1"); + + IDbMetadata mockDbMetaData = A.Fake(); + A.CallTo(() => dbProvider.DbMetadata).Returns(mockDbMetaData); + + Exception e = new Exception("foo"); + A.CallTo(() => dbProvider.ExtractError(e)).Returns("badsql").Once(); + DbException dbException = A.Fake(); + + MultiDelegatingDbProvider multiDbProvider = new MultiDelegatingDbProvider(); + IDictionary targetDbProviders = new Hashtable(); + targetDbProviders.Add("db1", dbProvider); + multiDbProvider.DefaultDbProvider = dbProvider; + multiDbProvider.TargetDbProviders = targetDbProviders; + multiDbProvider.AfterPropertiesSet(); + + Assert.IsNotNull(multiDbProvider.CreateConnection()); + Assert.IsNotNull(multiDbProvider.CreateCommand()); + Assert.IsNotNull(multiDbProvider.CreateParameter()); + Assert.IsNotNull(multiDbProvider.CreateDataAdapter()); + Assert.IsNotNull(multiDbProvider.CreateCommandBuilder() as DbCommandBuilder); + Assert.AreEqual("@p1", multiDbProvider.CreateParameterName("p1")); + Assert.AreEqual("cc1", multiDbProvider.CreateParameterNameForCollection("c1")); + Assert.IsNotNull(multiDbProvider.DbMetadata); + Assert.AreEqual("badsql", multiDbProvider.ExtractError(e)); + Assert.IsTrue(multiDbProvider.IsDataAccessException(dbException)); + Assert.IsFalse(multiDbProvider.IsDataAccessException(e)); + } } diff --git a/test/Spring/Spring.Data.Tests/Data/Common/UserCredentialsDbProviderTests.cs b/test/Spring/Spring.Data.Tests/Data/Common/UserCredentialsDbProviderTests.cs index 6d4eb734..cc07bd31 100644 --- a/test/Spring/Spring.Data.Tests/Data/Common/UserCredentialsDbProviderTests.cs +++ b/test/Spring/Spring.Data.Tests/Data/Common/UserCredentialsDbProviderTests.cs @@ -19,67 +19,64 @@ #endregion using System.Data; - using FakeItEasy; - using NUnit.Framework; -namespace Spring.Data.Common +namespace Spring.Data.Common; + +/// +/// This class contains tests for UserCredentialsDbProvider +/// +/// Mark Pollack +[TestFixture] +public class UserCredentialsDbProviderTests { - /// - /// This class contains tests for UserCredentialsDbProvider - /// - /// Mark Pollack - [TestFixture] - public class UserCredentialsDbProviderTests + [Test] + public void StaticCredentials() { - [Test] - public void StaticCredentials() - { - IDbProvider dbProvider = A.Fake(); - IDbConnection connection = A.Fake(); - A.CallTo(() => dbProvider.CreateConnection()).Returns(connection); - A.CallTo(() => dbProvider.ConnectionString).Returns(@"Data Source=MARKT60\SQL2005;Database=Spring;Trusted_Connection=False"); + IDbProvider dbProvider = A.Fake(); + IDbConnection connection = A.Fake(); + A.CallTo(() => dbProvider.CreateConnection()).Returns(connection); + A.CallTo(() => dbProvider.ConnectionString).Returns(@"Data Source=MARKT60\SQL2005;Database=Spring;Trusted_Connection=False"); - UserCredentialsDbProvider provider = new UserCredentialsDbProvider(); - provider.TargetDbProvider = dbProvider; - provider.Username = "User ID=springqa"; - provider.Password = "Password=springqa"; - Assert.AreEqual(connection, provider.CreateConnection()); + UserCredentialsDbProvider provider = new UserCredentialsDbProvider(); + provider.TargetDbProvider = dbProvider; + provider.Username = "User ID=springqa"; + provider.Password = "Password=springqa"; + Assert.AreEqual(connection, provider.CreateConnection()); - A.CallToSet(() => connection.ConnectionString) - .WhenArgumentsMatch(x => (string) x[0] == "Data Source=MARKT60\\SQL2005;Database=Spring;Trusted_Connection=False;User ID=springqa;Password=springqa") - .MustHaveHappenedOnceExactly(); - } - - [Test] - public void NoCredentials() - { - IDbProvider dbProvider = A.Fake(); - IDbConnection connection = A.Fake(); - A.CallTo(() => dbProvider.CreateConnection()).Returns(connection); - - UserCredentialsDbProvider provider = new UserCredentialsDbProvider(); - provider.TargetDbProvider = dbProvider; - Assert.AreEqual(connection, provider.CreateConnection()); - } - - [Test] - public void ThreadBoundCredentials() - { - IDbProvider dbProvider = A.Fake(); - IDbConnection connection = A.Fake(); - A.CallTo(() => dbProvider.CreateConnection()).Returns(connection); - A.CallTo(() => dbProvider.ConnectionString).Returns(@"Data Source=MARKT60\SQL2005;Database=Spring;Trusted_Connection=False"); - - UserCredentialsDbProvider provider = new UserCredentialsDbProvider(); - provider.TargetDbProvider = dbProvider; - provider.SetCredentialsForCurrentThread("User ID=springqa", "Password=springqa"); - Assert.AreEqual(connection, provider.CreateConnection()); - - A.CallToSet(() => connection.ConnectionString) - .WhenArgumentsMatch(x => (string) x[0] == "Data Source=MARKT60\\SQL2005;Database=Spring;Trusted_Connection=False;User ID=springqa;Password=springqa") - .MustHaveHappenedOnceExactly(); - } + A.CallToSet(() => connection.ConnectionString) + .WhenArgumentsMatch(x => (string) x[0] == "Data Source=MARKT60\\SQL2005;Database=Spring;Trusted_Connection=False;User ID=springqa;Password=springqa") + .MustHaveHappenedOnceExactly(); } -} \ No newline at end of file + + [Test] + public void NoCredentials() + { + IDbProvider dbProvider = A.Fake(); + IDbConnection connection = A.Fake(); + A.CallTo(() => dbProvider.CreateConnection()).Returns(connection); + + UserCredentialsDbProvider provider = new UserCredentialsDbProvider(); + provider.TargetDbProvider = dbProvider; + Assert.AreEqual(connection, provider.CreateConnection()); + } + + [Test] + public void ThreadBoundCredentials() + { + IDbProvider dbProvider = A.Fake(); + IDbConnection connection = A.Fake(); + A.CallTo(() => dbProvider.CreateConnection()).Returns(connection); + A.CallTo(() => dbProvider.ConnectionString).Returns(@"Data Source=MARKT60\SQL2005;Database=Spring;Trusted_Connection=False"); + + UserCredentialsDbProvider provider = new UserCredentialsDbProvider(); + provider.TargetDbProvider = dbProvider; + provider.SetCredentialsForCurrentThread("User ID=springqa", "Password=springqa"); + Assert.AreEqual(connection, provider.CreateConnection()); + + A.CallToSet(() => connection.ConnectionString) + .WhenArgumentsMatch(x => (string) x[0] == "Data Source=MARKT60\\SQL2005;Database=Spring;Trusted_Connection=False;User ID=springqa;Password=springqa") + .MustHaveHappenedOnceExactly(); + } +} diff --git a/test/Spring/Spring.Data.Tests/Data/Core/ServiceDomainTransactionManagerTests.cs b/test/Spring/Spring.Data.Tests/Data/Core/ServiceDomainTransactionManagerTests.cs index cb5f2a2f..1f3a9162 100644 --- a/test/Spring/Spring.Data.Tests/Data/Core/ServiceDomainTransactionManagerTests.cs +++ b/test/Spring/Spring.Data.Tests/Data/Core/ServiceDomainTransactionManagerTests.cs @@ -15,199 +15,192 @@ */ using System.EnterpriseServices; - using FakeItEasy; - using NUnit.Framework; - using Spring.Data.Support; using Spring.Transaction; using Spring.Transaction.Support; -namespace Spring.Data.Core +namespace Spring.Data.Core; + +/// +/// This class contains tests for ServiceDomainTransactionManager +/// +/// Mark Pollack +[TestFixture] +public class ServiceDomainTransactionManagerTests { - /// - /// This class contains tests for ServiceDomainTransactionManager - /// - /// Mark Pollack - [TestFixture] - public class ServiceDomainTransactionManagerTests + [Test] + public void TransactionCommit() { - [Test] - public void TransactionCommit() + IServiceDomainAdapter txAdapter = A.Fake(); + + A.CallTo(() => txAdapter.IsInTransaction).Returns(false).Once().Then.Returns(true).Once(); + + //ProcessCommit - status.GlobalRollbackOnly check + //DoCommit - status.GlobalRollbackOnly check + //DoCommit - check to call SetComplete or SetAbort + A.CallTo(() => txAdapter.MyTransactionVote).Returns(TransactionVote.Commit).NumberOfTimes(3); + + A.CallTo(() => txAdapter.Leave()).Returns(TransactionStatus.Commited).Once(); + + ServiceDomainPlatformTransactionManager tm = new ServiceDomainPlatformTransactionManager(txAdapter); + TransactionTemplate tt = new TransactionTemplate(tm); + tm.TransactionSynchronization = TransactionSynchronizationState.Always; + + tt.Execute(TransactionCommitMethod); + + Assert.IsFalse(TransactionSynchronizationManager.SynchronizationActive); + Assert.IsFalse(TransactionSynchronizationManager.CurrentTransactionReadOnly); + + SimpleServiceConfig serviceConfig = new SimpleServiceConfig(); + ConfigureServiceConfig(serviceConfig, true); + A.CallTo(() => txAdapter.Enter(serviceConfig)).MustHaveHappenedOnceExactly(); + A.CallTo(() => txAdapter.SetComplete()).MustHaveHappenedOnceExactly(); + } + + private object TransactionCommitMethod(ITransactionStatus status) + { + Assert.IsTrue(TransactionSynchronizationManager.SynchronizationActive); + Assert.IsFalse(TransactionSynchronizationManager.CurrentTransactionReadOnly); + return null; + } + + [Test] + public void TransactionRollback() + { + SimpleServiceConfig serviceConfig = new SimpleServiceConfig(); + ConfigureServiceConfig(serviceConfig, standardIsolationAndProp: true); + + IServiceDomainAdapter txAdapter = A.Fake(); + A.CallTo(() => txAdapter.IsInTransaction).Returns(false).Once().Then.Returns(true); + A.CallTo(() => txAdapter.Leave()).Returns(TransactionStatus.Commited); + + ServiceDomainPlatformTransactionManager tm = new ServiceDomainPlatformTransactionManager(txAdapter); + tm.TransactionSynchronization = TransactionSynchronizationState.Always; + + TransactionTemplate tt = new TransactionTemplate(tm); + + Assert.IsTrue(!TransactionSynchronizationManager.SynchronizationActive, "Synchronizations not active"); + + Exception ex = new ArgumentException("test exception"); + try { - IServiceDomainAdapter txAdapter = A.Fake(); - - A.CallTo(() => txAdapter.IsInTransaction).Returns(false).Once().Then.Returns(true).Once(); - - //ProcessCommit - status.GlobalRollbackOnly check - //DoCommit - status.GlobalRollbackOnly check - //DoCommit - check to call SetComplete or SetAbort - A.CallTo(() => txAdapter.MyTransactionVote).Returns(TransactionVote.Commit).NumberOfTimes(3); - - A.CallTo(() => txAdapter.Leave()).Returns(TransactionStatus.Commited).Once(); - - ServiceDomainPlatformTransactionManager tm = new ServiceDomainPlatformTransactionManager(txAdapter); - TransactionTemplate tt = new TransactionTemplate(tm); - tm.TransactionSynchronization = TransactionSynchronizationState.Always; - - tt.Execute(TransactionCommitMethod); - - Assert.IsFalse(TransactionSynchronizationManager.SynchronizationActive); - Assert.IsFalse(TransactionSynchronizationManager.CurrentTransactionReadOnly); - - SimpleServiceConfig serviceConfig = new SimpleServiceConfig(); - ConfigureServiceConfig(serviceConfig, true); - A.CallTo(() => txAdapter.Enter(serviceConfig)).MustHaveHappenedOnceExactly(); - A.CallTo(() => txAdapter.SetComplete()).MustHaveHappenedOnceExactly(); + tt.Execute(new TransactionRollbackTxCallback(ex)); + Assert.Fail("Should have thrown exception"); + } + catch (ArgumentException e) + { + Assert.AreEqual(ex, e); } - private object TransactionCommitMethod(ITransactionStatus status) + Assert.IsTrue(!TransactionSynchronizationManager.SynchronizationActive, "Synchronizations not active"); + + A.CallTo(() => txAdapter.SetAbort()).MustHaveHappenedOnceExactly(); + A.CallTo(() => txAdapter.Enter(serviceConfig)).MustHaveHappenedOnceExactly(); + } + + [Test] + public void PropagationRequiresNewWithExistingTransaction() + { + IServiceDomainAdapter txAdapter = A.Fake(); + + A.CallTo(() => txAdapter.IsInTransaction) + .Returns(false).Once() + .Then.Returns(true).NumberOfTimes(3); + + A.CallTo(() => txAdapter.Leave()) + .Returns(TransactionStatus.Aborted).Once() + .Then.Returns(TransactionStatus.Commited).Once(); + + A.CallTo(() => txAdapter.MyTransactionVote).Returns(TransactionVote.Commit).NumberOfTimes(3); + + ServiceDomainPlatformTransactionManager tm = new ServiceDomainPlatformTransactionManager(txAdapter); + tm.TransactionSynchronization = TransactionSynchronizationState.Always; + + TransactionTemplate tt = new TransactionTemplate(tm); + tt.PropagationBehavior = TransactionPropagation.RequiresNew; + tt.Execute(new PropagationRequiresNewWithExistingTransactionCallbackSD(tt)); + + SimpleServiceConfig serviceConfig = new SimpleServiceConfig(); + ConfigureServiceConfig(serviceConfig, false); + serviceConfig.TransactionOption = TransactionOption.RequiresNew; + serviceConfig.IsolationLevel = TransactionIsolationLevel.ReadCommitted; + A.CallTo(() => txAdapter.Enter(serviceConfig)).MustHaveHappened(); + + ConfigureServiceConfig(serviceConfig, false); + serviceConfig.TransactionOption = TransactionOption.RequiresNew; + serviceConfig.IsolationLevel = TransactionIsolationLevel.ReadCommitted; + A.CallTo(() => txAdapter.Enter(serviceConfig)).MustHaveHappened(); + + A.CallTo(() => txAdapter.SetAbort()).MustHaveHappenedOnceExactly(); + A.CallTo(() => txAdapter.SetComplete()).MustHaveHappenedOnceExactly(); + } + + private SimpleServiceConfig ConfigureServiceConfig(SimpleServiceConfig serviceConfig, bool standardIsolationAndProp) + { + serviceConfig.TransactionDescription = null; + + serviceConfig.TrackingEnabled = true; + serviceConfig.TrackingAppName = "Spring.NET"; + serviceConfig.TrackingComponentName = "ServiceDomainPlatformTransactionManager"; + if (standardIsolationAndProp) + { + serviceConfig.TransactionOption = TransactionOption.Required; + serviceConfig.IsolationLevel = TransactionIsolationLevel.ReadCommitted; + } + + return serviceConfig; + } + + internal class TransactionRollbackTxCallback : ITransactionCallback + { + private Exception exception; + + public TransactionRollbackTxCallback(Exception exception) + { + this.exception = exception; + } + + public object DoInTransaction(ITransactionStatus status) { Assert.IsTrue(TransactionSynchronizationManager.SynchronizationActive); Assert.IsFalse(TransactionSynchronizationManager.CurrentTransactionReadOnly); + Assert.IsTrue(status.IsNewTransaction, "Is new transaction"); + throw exception; + } + } + + internal class PropagationRequiresNewWithExistingTransactionCallbackSD : ITransactionCallback + { + private TransactionTemplate tt; + + public PropagationRequiresNewWithExistingTransactionCallbackSD(TransactionTemplate tt) + { + this.tt = tt; + } + + public object DoInTransaction(ITransactionStatus status) + { + Assert.IsTrue(status.IsNewTransaction, "Is new transaction"); + Assert.IsTrue(TransactionSynchronizationManager.SynchronizationActive, "Synchronization active"); + Assert.IsFalse(TransactionSynchronizationManager.CurrentTransactionReadOnly); + Assert.IsTrue(TransactionSynchronizationManager.ActualTransactionActive); + tt.Execute(new TransactionDelegate(TransactionMethod)); + Assert.IsTrue(status.IsNewTransaction, "Is new transaction"); + Assert.IsFalse(TransactionSynchronizationManager.CurrentTransactionReadOnly); + Assert.IsTrue(TransactionSynchronizationManager.ActualTransactionActive); return null; } - [Test] - public void TransactionRollback() + private object TransactionMethod(ITransactionStatus status) { - - SimpleServiceConfig serviceConfig = new SimpleServiceConfig(); - ConfigureServiceConfig(serviceConfig, standardIsolationAndProp: true); - - IServiceDomainAdapter txAdapter = A.Fake(); - A.CallTo(() => txAdapter.IsInTransaction).Returns(false).Once().Then.Returns(true); - A.CallTo(() => txAdapter.Leave()).Returns(TransactionStatus.Commited); - - ServiceDomainPlatformTransactionManager tm = new ServiceDomainPlatformTransactionManager(txAdapter); - tm.TransactionSynchronization = TransactionSynchronizationState.Always; - - TransactionTemplate tt = new TransactionTemplate(tm); - - Assert.IsTrue(!TransactionSynchronizationManager.SynchronizationActive, "Synchronizations not active"); - - Exception ex = new ArgumentException("test exception"); - try - { - tt.Execute(new TransactionRollbackTxCallback(ex)); - Assert.Fail("Should have thrown exception"); - } - catch (ArgumentException e) - { - Assert.AreEqual(ex, e); - } - - Assert.IsTrue(!TransactionSynchronizationManager.SynchronizationActive, "Synchronizations not active"); - - A.CallTo(() => txAdapter.SetAbort()).MustHaveHappenedOnceExactly(); - A.CallTo(() => txAdapter.Enter(serviceConfig)).MustHaveHappenedOnceExactly(); - } - - - [Test] - public void PropagationRequiresNewWithExistingTransaction() - { - IServiceDomainAdapter txAdapter = A.Fake(); - - A.CallTo(() => txAdapter.IsInTransaction) - .Returns(false).Once() - .Then.Returns(true).NumberOfTimes(3); - - A.CallTo(() => txAdapter.Leave()) - .Returns(TransactionStatus.Aborted).Once() - .Then.Returns(TransactionStatus.Commited).Once(); - - A.CallTo(() => txAdapter.MyTransactionVote).Returns(TransactionVote.Commit).NumberOfTimes(3); - - ServiceDomainPlatformTransactionManager tm = new ServiceDomainPlatformTransactionManager(txAdapter); - tm.TransactionSynchronization = TransactionSynchronizationState.Always; - - TransactionTemplate tt = new TransactionTemplate(tm); - tt.PropagationBehavior = TransactionPropagation.RequiresNew; - tt.Execute(new PropagationRequiresNewWithExistingTransactionCallbackSD(tt)); - - SimpleServiceConfig serviceConfig = new SimpleServiceConfig(); - ConfigureServiceConfig(serviceConfig, false); - serviceConfig.TransactionOption = TransactionOption.RequiresNew; - serviceConfig.IsolationLevel = TransactionIsolationLevel.ReadCommitted; - A.CallTo(() => txAdapter.Enter(serviceConfig)).MustHaveHappened(); - - ConfigureServiceConfig(serviceConfig, false); - serviceConfig.TransactionOption = TransactionOption.RequiresNew; - serviceConfig.IsolationLevel = TransactionIsolationLevel.ReadCommitted; - A.CallTo(() => txAdapter.Enter(serviceConfig)).MustHaveHappened(); - - A.CallTo(() => txAdapter.SetAbort()).MustHaveHappenedOnceExactly(); - A.CallTo(() => txAdapter.SetComplete()).MustHaveHappenedOnceExactly(); - } - - private SimpleServiceConfig ConfigureServiceConfig(SimpleServiceConfig serviceConfig, bool standardIsolationAndProp) - { - serviceConfig.TransactionDescription = null; - - serviceConfig.TrackingEnabled = true; - serviceConfig.TrackingAppName = "Spring.NET"; - serviceConfig.TrackingComponentName = "ServiceDomainPlatformTransactionManager"; - if (standardIsolationAndProp) - { - serviceConfig.TransactionOption = TransactionOption.Required; - serviceConfig.IsolationLevel = TransactionIsolationLevel.ReadCommitted; - } - - return serviceConfig; - } - - - internal class TransactionRollbackTxCallback : ITransactionCallback - { - private Exception exception; - - public TransactionRollbackTxCallback(Exception exception) - { - this.exception = exception; - } - - public object DoInTransaction(ITransactionStatus status) - { - Assert.IsTrue(TransactionSynchronizationManager.SynchronizationActive); - Assert.IsFalse(TransactionSynchronizationManager.CurrentTransactionReadOnly); - Assert.IsTrue(status.IsNewTransaction, "Is new transaction"); - throw exception; - } - } - - internal class PropagationRequiresNewWithExistingTransactionCallbackSD : ITransactionCallback - { - private TransactionTemplate tt; - - public PropagationRequiresNewWithExistingTransactionCallbackSD(TransactionTemplate tt) - { - this.tt = tt; - } - - public object DoInTransaction(ITransactionStatus status) - { - Assert.IsTrue(status.IsNewTransaction, "Is new transaction"); - Assert.IsTrue(TransactionSynchronizationManager.SynchronizationActive, "Synchronization active"); - Assert.IsFalse(TransactionSynchronizationManager.CurrentTransactionReadOnly); - Assert.IsTrue(TransactionSynchronizationManager.ActualTransactionActive); - tt.Execute(new TransactionDelegate(TransactionMethod)); - Assert.IsTrue(status.IsNewTransaction, "Is new transaction"); - Assert.IsFalse(TransactionSynchronizationManager.CurrentTransactionReadOnly); - Assert.IsTrue(TransactionSynchronizationManager.ActualTransactionActive); - return null; - } - - private object TransactionMethod(ITransactionStatus status) - { - Assert.IsTrue(TransactionSynchronizationManager.SynchronizationActive, "Synchronization active"); - Assert.IsTrue(status.IsNewTransaction, "Is new transaction"); - Assert.IsFalse(TransactionSynchronizationManager.CurrentTransactionReadOnly); - Assert.IsTrue(TransactionSynchronizationManager.ActualTransactionActive); - status.SetRollbackOnly(); - return null; - } + Assert.IsTrue(TransactionSynchronizationManager.SynchronizationActive, "Synchronization active"); + Assert.IsTrue(status.IsNewTransaction, "Is new transaction"); + Assert.IsFalse(TransactionSynchronizationManager.CurrentTransactionReadOnly); + Assert.IsTrue(TransactionSynchronizationManager.ActualTransactionActive); + status.SetRollbackOnly(); + return null; } } -} +} \ No newline at end of file diff --git a/test/Spring/Spring.Data.Tests/Data/Core/TxScopeTransactionManagerIntegrationTests.cs b/test/Spring/Spring.Data.Tests/Data/Core/TxScopeTransactionManagerIntegrationTests.cs index 3435a9db..da657b5d 100644 --- a/test/Spring/Spring.Data.Tests/Data/Core/TxScopeTransactionManagerIntegrationTests.cs +++ b/test/Spring/Spring.Data.Tests/Data/Core/TxScopeTransactionManagerIntegrationTests.cs @@ -19,111 +19,107 @@ #endregion using FakeItEasy; - using NUnit.Framework; - using Spring.Transaction; using Spring.Transaction.Support; -namespace Spring.Data.Core +namespace Spring.Data.Core; + +/// +/// This class contains tests for TxScopeTransactionManager and will directly a real TransactionScope object +/// but does not access any database +/// +/// Mark Pollack +[TestFixture] +public class TxScopeTransactionManagerIntegrationTests { - /// - /// This class contains tests for TxScopeTransactionManager and will directly a real TransactionScope object - /// but does not access any database - /// - /// Mark Pollack - [TestFixture] - public class TxScopeTransactionManagerIntegrationTests + [TearDown] + public void TearDown() { - [TearDown] - public void TearDown() - { - Assert.IsTrue(TransactionSynchronizationManager.ResourceDictionary.Count == 0); - Assert.IsFalse(TransactionSynchronizationManager.SynchronizationActive); - Assert.IsNull(TransactionSynchronizationManager.CurrentTransactionName); - Assert.IsFalse(TransactionSynchronizationManager.CurrentTransactionReadOnly); - Assert.AreEqual(System.Data.IsolationLevel.Unspecified, TransactionSynchronizationManager.CurrentTransactionIsolationLevel); - Assert.IsFalse(TransactionSynchronizationManager.ActualTransactionActive); - } - - [Test] - public void Commit() - { - TxScopeTransactionManager tm = new TxScopeTransactionManager(); - tm.TransactionSynchronization = TransactionSynchronizationState.Always; - - TransactionTemplate tt = new TransactionTemplate(tm); - - //tt.Name = "txName"; - - Assert.AreEqual(TransactionSynchronizationState.Always, tm.TransactionSynchronization); - Assert.IsFalse(TransactionSynchronizationManager.SynchronizationActive); - Assert.IsNull(TransactionSynchronizationManager.CurrentTransactionName); - Assert.IsFalse(TransactionSynchronizationManager.CurrentTransactionReadOnly); - tt.Execute(CommitTxDelegate); - Assert.IsFalse(TransactionSynchronizationManager.SynchronizationActive); - Assert.IsNull(TransactionSynchronizationManager.CurrentTransactionName); - Assert.IsFalse(TransactionSynchronizationManager.CurrentTransactionReadOnly); - } - - public object CommitTxDelegate(ITransactionStatus status) - { - Assert.IsTrue(TransactionSynchronizationManager.SynchronizationActive); - Assert.IsFalse(TransactionSynchronizationManager.CurrentTransactionReadOnly); - - return null; - } - - [Test] - public void TransactionInformation() - { - TxScopeTransactionManager tm = new TxScopeTransactionManager(); - tm.TransactionSynchronization = TransactionSynchronizationState.Always; - - TransactionTemplate tt = new TransactionTemplate(tm); - tt.TransactionIsolationLevel = System.Data.IsolationLevel.ReadUncommitted; - tt.Execute(TransactionInformationTxDelegate); - } - - public object TransactionInformationTxDelegate(ITransactionStatus status) - { - Assert.AreEqual(System.Transactions.IsolationLevel.ReadUncommitted, - System.Transactions.Transaction.Current.IsolationLevel); - - Assert.AreEqual(System.Data.IsolationLevel.ReadUncommitted, - TransactionSynchronizationManager.CurrentTransactionIsolationLevel); - return null; - } - - - [Test] - public void Rollback() - { - ITransactionSynchronization sync = A.Fake(); - - TxScopeTransactionManager tm = new TxScopeTransactionManager(); - tm.TransactionSynchronization = TransactionSynchronizationState.Always; - - TransactionTemplate tt = new TransactionTemplate(tm); - tt.TransactionTimeout = 10; - tt.Name = "txName"; - - Assert.IsFalse(TransactionSynchronizationManager.SynchronizationActive); - Assert.IsNull(TransactionSynchronizationManager.CurrentTransactionName); - Assert.IsFalse(TransactionSynchronizationManager.CurrentTransactionReadOnly); - tt.Execute(status => - { - Assert.IsTrue(TransactionSynchronizationManager.SynchronizationActive); - TransactionSynchronizationManager.RegisterSynchronization(sync); - Assert.AreEqual("txName", TransactionSynchronizationManager.CurrentTransactionName); - Assert.IsFalse(TransactionSynchronizationManager.CurrentTransactionReadOnly); - status.SetRollbackOnly(); - return null; - } - ); - - A.CallTo(() => sync.BeforeCompletion()).MustHaveHappenedOnceExactly(); - A.CallTo(() => sync.AfterCompletion(TransactionSynchronizationStatus.Rolledback)).MustHaveHappenedOnceExactly(); - } + Assert.IsTrue(TransactionSynchronizationManager.ResourceDictionary.Count == 0); + Assert.IsFalse(TransactionSynchronizationManager.SynchronizationActive); + Assert.IsNull(TransactionSynchronizationManager.CurrentTransactionName); + Assert.IsFalse(TransactionSynchronizationManager.CurrentTransactionReadOnly); + Assert.AreEqual(System.Data.IsolationLevel.Unspecified, TransactionSynchronizationManager.CurrentTransactionIsolationLevel); + Assert.IsFalse(TransactionSynchronizationManager.ActualTransactionActive); } -} \ No newline at end of file + + [Test] + public void Commit() + { + TxScopeTransactionManager tm = new TxScopeTransactionManager(); + tm.TransactionSynchronization = TransactionSynchronizationState.Always; + + TransactionTemplate tt = new TransactionTemplate(tm); + + //tt.Name = "txName"; + + Assert.AreEqual(TransactionSynchronizationState.Always, tm.TransactionSynchronization); + Assert.IsFalse(TransactionSynchronizationManager.SynchronizationActive); + Assert.IsNull(TransactionSynchronizationManager.CurrentTransactionName); + Assert.IsFalse(TransactionSynchronizationManager.CurrentTransactionReadOnly); + tt.Execute(CommitTxDelegate); + Assert.IsFalse(TransactionSynchronizationManager.SynchronizationActive); + Assert.IsNull(TransactionSynchronizationManager.CurrentTransactionName); + Assert.IsFalse(TransactionSynchronizationManager.CurrentTransactionReadOnly); + } + + public object CommitTxDelegate(ITransactionStatus status) + { + Assert.IsTrue(TransactionSynchronizationManager.SynchronizationActive); + Assert.IsFalse(TransactionSynchronizationManager.CurrentTransactionReadOnly); + + return null; + } + + [Test] + public void TransactionInformation() + { + TxScopeTransactionManager tm = new TxScopeTransactionManager(); + tm.TransactionSynchronization = TransactionSynchronizationState.Always; + + TransactionTemplate tt = new TransactionTemplate(tm); + tt.TransactionIsolationLevel = System.Data.IsolationLevel.ReadUncommitted; + tt.Execute(TransactionInformationTxDelegate); + } + + public object TransactionInformationTxDelegate(ITransactionStatus status) + { + Assert.AreEqual(System.Transactions.IsolationLevel.ReadUncommitted, + System.Transactions.Transaction.Current.IsolationLevel); + + Assert.AreEqual(System.Data.IsolationLevel.ReadUncommitted, + TransactionSynchronizationManager.CurrentTransactionIsolationLevel); + return null; + } + + [Test] + public void Rollback() + { + ITransactionSynchronization sync = A.Fake(); + + TxScopeTransactionManager tm = new TxScopeTransactionManager(); + tm.TransactionSynchronization = TransactionSynchronizationState.Always; + + TransactionTemplate tt = new TransactionTemplate(tm); + tt.TransactionTimeout = 10; + tt.Name = "txName"; + + Assert.IsFalse(TransactionSynchronizationManager.SynchronizationActive); + Assert.IsNull(TransactionSynchronizationManager.CurrentTransactionName); + Assert.IsFalse(TransactionSynchronizationManager.CurrentTransactionReadOnly); + tt.Execute(status => + { + Assert.IsTrue(TransactionSynchronizationManager.SynchronizationActive); + TransactionSynchronizationManager.RegisterSynchronization(sync); + Assert.AreEqual("txName", TransactionSynchronizationManager.CurrentTransactionName); + Assert.IsFalse(TransactionSynchronizationManager.CurrentTransactionReadOnly); + status.SetRollbackOnly(); + return null; + } + ); + + A.CallTo(() => sync.BeforeCompletion()).MustHaveHappenedOnceExactly(); + A.CallTo(() => sync.AfterCompletion(TransactionSynchronizationStatus.Rolledback)).MustHaveHappenedOnceExactly(); + } +} diff --git a/test/Spring/Spring.Data.Tests/Data/Core/TxScopeTransactionManagerTests.cs b/test/Spring/Spring.Data.Tests/Data/Core/TxScopeTransactionManagerTests.cs index c894c477..d5a97077 100644 --- a/test/Spring/Spring.Data.Tests/Data/Core/TxScopeTransactionManagerTests.cs +++ b/test/Spring/Spring.Data.Tests/Data/Core/TxScopeTransactionManagerTests.cs @@ -19,140 +19,134 @@ #endregion using System.Transactions; - using FakeItEasy; - using NUnit.Framework; - using Spring.Data.Support; using Spring.Transaction; using Spring.Transaction.Support; -namespace Spring.Data.Core +namespace Spring.Data.Core; + +/// +/// This calss contains tests for +/// +/// Mark Pollack +[TestFixture] +public class TxScopeTransactionManagerTests { - /// - /// This calss contains tests for - /// - /// Mark Pollack - [TestFixture] - public class TxScopeTransactionManagerTests + [Test] + public void TransactionCommit() { + ITransactionScopeAdapter txAdapter = A.Fake(); + A.CallTo(() => txAdapter.IsExistingTransaction).Returns(false); - [Test] - public void TransactionCommit() + A.CallTo(() => txAdapter.RollbackOnly).Returns(false); + + TxScopeTransactionManager tm = new TxScopeTransactionManager(txAdapter); + tm.TransactionSynchronization = TransactionSynchronizationState.Always; + + TransactionTemplate tt = new TransactionTemplate(tm); + tt.Execute(status => { - ITransactionScopeAdapter txAdapter = A.Fake(); - A.CallTo(() => txAdapter.IsExistingTransaction).Returns(false); + Assert.IsTrue(TransactionSynchronizationManager.SynchronizationActive); + Assert.IsFalse(TransactionSynchronizationManager.CurrentTransactionReadOnly); + return null; + }); - A.CallTo(() => txAdapter.RollbackOnly).Returns(false); + Assert.IsFalse(TransactionSynchronizationManager.SynchronizationActive); + Assert.IsFalse(TransactionSynchronizationManager.CurrentTransactionReadOnly); - TxScopeTransactionManager tm = new TxScopeTransactionManager(txAdapter); - tm.TransactionSynchronization = TransactionSynchronizationState.Always; + TransactionOptions txOptions = new TransactionOptions(); + txOptions.IsolationLevel = IsolationLevel.ReadCommitted; + txAdapter.CreateTransactionScope(TransactionScopeOption.Required, txOptions, TransactionScopeAsyncFlowOption.Enabled); + txAdapter.Complete(); + txAdapter.Dispose(); + } - TransactionTemplate tt = new TransactionTemplate(tm); + [Test] + public void TransactionRollback() + { + ITransactionScopeAdapter txAdapter = A.Fake(); + + A.CallTo(() => txAdapter.IsExistingTransaction).Returns(false); + TransactionOptions txOptions = new TransactionOptions(); + txOptions.IsolationLevel = IsolationLevel.ReadCommitted; + + TxScopeTransactionManager tm = new TxScopeTransactionManager(txAdapter); + tm.TransactionSynchronization = TransactionSynchronizationState.Always; + + TransactionTemplate tt = new TransactionTemplate(tm); + + Assert.IsTrue(!TransactionSynchronizationManager.SynchronizationActive, "Synchronizations not active"); + + Exception ex = new ArgumentException("test exception"); + try + { tt.Execute(status => { Assert.IsTrue(TransactionSynchronizationManager.SynchronizationActive); Assert.IsFalse(TransactionSynchronizationManager.CurrentTransactionReadOnly); + Assert.IsTrue(status.IsNewTransaction, "Is new transaction"); + if (ex != null) throw ex; return null; }); + Assert.Fail("Should have thrown exception"); + } + catch (ArgumentException e) + { + Assert.AreEqual(ex, e); + } - Assert.IsFalse(TransactionSynchronizationManager.SynchronizationActive); + Assert.IsTrue(!TransactionSynchronizationManager.SynchronizationActive, "Synchronizations not active"); + A.CallTo(() => txAdapter.CreateTransactionScope(TransactionScopeOption.Required, txOptions, TransactionScopeAsyncFlowOption.Enabled)).MustHaveHappenedOnceExactly(); + A.CallTo(() => txAdapter.Dispose()).MustHaveHappenedOnceExactly(); + } + + [Test] + public void PropagationRequiresNewWithExistingTransaction() + { + ITransactionScopeAdapter txAdapter = A.Fake(); + A.CallTo(() => txAdapter.IsExistingTransaction).Returns(false).Once(); + + TransactionOptions txOptions = new TransactionOptions(); + txOptions.IsolationLevel = IsolationLevel.ReadCommitted; + + //inner tx actions + A.CallTo(() => txAdapter.IsExistingTransaction).Returns(true).Once(); + //end inner tx actions + + A.CallTo(() => txAdapter.RollbackOnly).Returns(false); + + TxScopeTransactionManager tm = new TxScopeTransactionManager(txAdapter); + tm.TransactionSynchronization = TransactionSynchronizationState.Always; + + TransactionTemplate tt = new TransactionTemplate(tm); + tt.PropagationBehavior = TransactionPropagation.RequiresNew; + tt.Execute(status => + { + Assert.IsTrue(status.IsNewTransaction, "Is new transaction"); + Assert.IsTrue(TransactionSynchronizationManager.SynchronizationActive, "Synchronization active"); Assert.IsFalse(TransactionSynchronizationManager.CurrentTransactionReadOnly); + Assert.IsTrue(TransactionSynchronizationManager.ActualTransactionActive); - TransactionOptions txOptions = new TransactionOptions(); - txOptions.IsolationLevel = IsolationLevel.ReadCommitted; - txAdapter.CreateTransactionScope(TransactionScopeOption.Required, txOptions, TransactionScopeAsyncFlowOption.Enabled); - txAdapter.Complete(); - txAdapter.Dispose(); - } - - [Test] - public void TransactionRollback() - { - ITransactionScopeAdapter txAdapter = A.Fake(); - - A.CallTo(() => txAdapter.IsExistingTransaction).Returns(false); - TransactionOptions txOptions = new TransactionOptions(); - txOptions.IsolationLevel = IsolationLevel.ReadCommitted; - - TxScopeTransactionManager tm = new TxScopeTransactionManager(txAdapter); - tm.TransactionSynchronization = TransactionSynchronizationState.Always; - - TransactionTemplate tt = new TransactionTemplate(tm); - - Assert.IsTrue(!TransactionSynchronizationManager.SynchronizationActive, "Synchronizations not active"); - - Exception ex = new ArgumentException("test exception"); - try + tt.Execute(status2 => { - tt.Execute(status => - { - Assert.IsTrue(TransactionSynchronizationManager.SynchronizationActive); - Assert.IsFalse(TransactionSynchronizationManager.CurrentTransactionReadOnly); - Assert.IsTrue(status.IsNewTransaction, "Is new transaction"); - if (ex != null) throw ex; - return null; - }); - Assert.Fail("Should have thrown exception"); - } - catch (ArgumentException e) - { - Assert.AreEqual(ex, e); - } - - Assert.IsTrue(!TransactionSynchronizationManager.SynchronizationActive, "Synchronizations not active"); - A.CallTo(() => txAdapter.CreateTransactionScope(TransactionScopeOption.Required, txOptions, TransactionScopeAsyncFlowOption.Enabled)).MustHaveHappenedOnceExactly(); - A.CallTo(() => txAdapter.Dispose()).MustHaveHappenedOnceExactly(); - } - - [Test] - public void PropagationRequiresNewWithExistingTransaction() - { - ITransactionScopeAdapter txAdapter = A.Fake(); - A.CallTo(() => txAdapter.IsExistingTransaction).Returns(false).Once(); - - TransactionOptions txOptions = new TransactionOptions(); - txOptions.IsolationLevel = IsolationLevel.ReadCommitted; - - //inner tx actions - A.CallTo(() => txAdapter.IsExistingTransaction).Returns(true).Once(); - //end inner tx actions - - A.CallTo(() => txAdapter.RollbackOnly).Returns(false); - - TxScopeTransactionManager tm = new TxScopeTransactionManager(txAdapter); - tm.TransactionSynchronization = TransactionSynchronizationState.Always; - - TransactionTemplate tt = new TransactionTemplate(tm); - tt.PropagationBehavior = TransactionPropagation.RequiresNew; - tt.Execute(status => - { - Assert.IsTrue(status.IsNewTransaction, "Is new transaction"); Assert.IsTrue(TransactionSynchronizationManager.SynchronizationActive, "Synchronization active"); + Assert.IsTrue(status2.IsNewTransaction, "Is new transaction"); Assert.IsFalse(TransactionSynchronizationManager.CurrentTransactionReadOnly); Assert.IsTrue(TransactionSynchronizationManager.ActualTransactionActive); - - tt.Execute(status2 => - { - Assert.IsTrue(TransactionSynchronizationManager.SynchronizationActive, "Synchronization active"); - Assert.IsTrue(status2.IsNewTransaction, "Is new transaction"); - Assert.IsFalse(TransactionSynchronizationManager.CurrentTransactionReadOnly); - Assert.IsTrue(TransactionSynchronizationManager.ActualTransactionActive); - status2.SetRollbackOnly(); - return null; - }); - - - Assert.IsTrue(status.IsNewTransaction, "Is new transaction"); - Assert.IsFalse(TransactionSynchronizationManager.CurrentTransactionReadOnly); - Assert.IsTrue(TransactionSynchronizationManager.ActualTransactionActive); + status2.SetRollbackOnly(); return null; }); - A.CallTo(() => txAdapter.CreateTransactionScope(TransactionScopeOption.RequiresNew, txOptions, TransactionScopeAsyncFlowOption.Enabled)).MustHaveHappenedTwiceExactly(); - A.CallTo(() => txAdapter.Dispose()).MustHaveHappenedTwiceExactly(); - A.CallTo(() => txAdapter.Complete()).MustHaveHappenedOnceExactly(); - } + Assert.IsTrue(status.IsNewTransaction, "Is new transaction"); + Assert.IsFalse(TransactionSynchronizationManager.CurrentTransactionReadOnly); + Assert.IsTrue(TransactionSynchronizationManager.ActualTransactionActive); + return null; + }); + + A.CallTo(() => txAdapter.CreateTransactionScope(TransactionScopeOption.RequiresNew, txOptions, TransactionScopeAsyncFlowOption.Enabled)).MustHaveHappenedTwiceExactly(); + A.CallTo(() => txAdapter.Dispose()).MustHaveHappenedTwiceExactly(); + A.CallTo(() => txAdapter.Complete()).MustHaveHappenedOnceExactly(); } } diff --git a/test/Spring/Spring.Data.Tests/Data/ITestCoord.cs b/test/Spring/Spring.Data.Tests/Data/ITestCoord.cs index 4d895fc8..ba4f551d 100644 --- a/test/Spring/Spring.Data.Tests/Data/ITestCoord.cs +++ b/test/Spring/Spring.Data.Tests/Data/ITestCoord.cs @@ -1,15 +1,14 @@ - using Spring.Objects; -namespace Spring.Data -{ - public interface ITestCoord - { - ITestObjectMgr TestObjectMgr - { - get; set; - } +namespace Spring.Data; - void WorkOn(TestObject to1, TestObject to2); +public interface ITestCoord +{ + ITestObjectMgr TestObjectMgr + { + get; + set; } + + void WorkOn(TestObject to1, TestObject to2); } diff --git a/test/Spring/Spring.Data.Tests/Data/ITestObjectMgr.cs b/test/Spring/Spring.Data.Tests/Data/ITestObjectMgr.cs index 93dd5d5d..596a45d2 100644 --- a/test/Spring/Spring.Data.Tests/Data/ITestObjectMgr.cs +++ b/test/Spring/Spring.Data.Tests/Data/ITestObjectMgr.cs @@ -1,11 +1,10 @@ using Spring.Objects; -namespace Spring.Data -{ - public interface ITestObjectMgr - { - void SaveTwoTestObjects(TestObject to1, TestObject to2); +namespace Spring.Data; - void DeleteTwoTestObjects(string name1, string name2); - } -} \ No newline at end of file +public interface ITestObjectMgr +{ + void SaveTwoTestObjects(TestObject to1, TestObject to2); + + void DeleteTwoTestObjects(string name1, string name2); +} diff --git a/test/Spring/Spring.Data.Tests/Data/LoggingAroundAdvice.cs b/test/Spring/Spring.Data.Tests/Data/LoggingAroundAdvice.cs index 2b3676be..65fe9ac0 100644 --- a/test/Spring/Spring.Data.Tests/Data/LoggingAroundAdvice.cs +++ b/test/Spring/Spring.Data.Tests/Data/LoggingAroundAdvice.cs @@ -1,25 +1,25 @@ - using AopAlliance.Intercept; using Microsoft.Extensions.Logging; -namespace Spring.Data +namespace Spring.Data; + +public class LoggingAroundAdvice : IMethodInterceptor { - public class LoggingAroundAdvice : IMethodInterceptor + public int numInvoked; + private static readonly ILogger LOG = LogManager.GetLogger(); + + public object Invoke(IMethodInvocation invocation) { - public int numInvoked; - private static readonly ILogger LOG = LogManager.GetLogger(); - public object Invoke(IMethodInvocation invocation) + try { - try - { - LOG.LogDebug("Advice executing; calling the advised method [" + invocation.Method.Name + "]"); - object returnValue = invocation.Proceed(); - LOG.LogDebug("Advice executed; advised method [" + invocation.Method.Name + "] returned " + returnValue); - return returnValue; - } finally - { - numInvoked++; - } + LOG.LogDebug("Advice executing; calling the advised method [" + invocation.Method.Name + "]"); + object returnValue = invocation.Proceed(); + LOG.LogDebug("Advice executed; advised method [" + invocation.Method.Name + "] returned " + returnValue); + return returnValue; + } + finally + { + numInvoked++; } } } diff --git a/test/Spring/Spring.Data.Tests/Data/Objects/AbstractAdoQueryTests.cs b/test/Spring/Spring.Data.Tests/Data/Objects/AbstractAdoQueryTests.cs index 3ac2445a..80ef6949 100644 --- a/test/Spring/Spring.Data.Tests/Data/Objects/AbstractAdoQueryTests.cs +++ b/test/Spring/Spring.Data.Tests/Data/Objects/AbstractAdoQueryTests.cs @@ -1,14 +1,14 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. - * + * Copyright � 2002-2011 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. @@ -19,45 +19,42 @@ #endregion using System.Data; - using FakeItEasy; - using Spring.Data.Common; -namespace Spring.Data.Objects +namespace Spring.Data.Objects; + +/// +/// Contains shared mocking calls for performing tests on AdoQuery and subclasses. +/// +public abstract class AbstractAdoQueryTests { - /// - /// Contains shared mocking calls for performing tests on AdoQuery and subclasses. - /// - public abstract class AbstractAdoQueryTests + protected IDbProvider provider; + protected IDbCommand command; + + public void SetUpMocks() { - protected IDbProvider provider; - protected IDbCommand command; + provider = A.Fake(); + IDbConnection connection = A.Fake(); - public void SetUpMocks() - { - provider = A.Fake(); - IDbConnection connection = A.Fake(); + A.CallTo(() => provider.CreateConnection()).Returns(connection).Once(); - A.CallTo(() => provider.CreateConnection()).Returns(connection).Once(); + // Creating a query (setting DbProvider property) + // will call new DbParameters(IDbProvider), which is a real pain to mock. + // to store the declared parameters. - // Creating a query (setting DbProvider property) - // will call new DbParameters(IDbProvider), which is a real pain to mock. - // to store the declared parameters. + command = A.Fake(); + //This IDbCommand is used as a container for the underlying parameter collection. + A.CallTo(() => provider.CreateCommand()).Returns(command).Once(); - command = A.Fake(); - //This IDbCommand is used as a container for the underlying parameter collection. - A.CallTo(() => provider.CreateCommand()).Returns(command).Once(); + //Create a real instance of IDbParameters to stored the declared parameters + IDbProvider realDbProvider = DbProviderFactory.GetDbProvider("System.Data.SqlClient"); + IDbParameters dbParameters = new DbParameters(realDbProvider); - //Create a real instance of IDbParameters to stored the declared parameters - IDbProvider realDbProvider = DbProviderFactory.GetDbProvider("System.Data.SqlClient"); - IDbParameters dbParameters = new DbParameters(realDbProvider); + //Pass real instance into mock instance. + A.CallTo(() => command.Parameters).Returns(dbParameters.DataParameterCollection).Once(); + A.CallTo(() => provider.CreateCommand()).Returns(command).Once(); - //Pass real instance into mock instance. - A.CallTo(() => command.Parameters).Returns(dbParameters.DataParameterCollection).Once(); - A.CallTo(() => provider.CreateCommand()).Returns(command).Once(); - - // done with init of DbParameters mock/stubbing - } + // done with init of DbParameters mock/stubbing } -} \ No newline at end of file +} diff --git a/test/Spring/Spring.Data.Tests/Data/Objects/AdoOperationTests.cs b/test/Spring/Spring.Data.Tests/Data/Objects/AdoOperationTests.cs index 82052121..0334720d 100644 --- a/test/Spring/Spring.Data.Tests/Data/Objects/AdoOperationTests.cs +++ b/test/Spring/Spring.Data.Tests/Data/Objects/AdoOperationTests.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -17,17 +17,18 @@ */ #endregion + #region License /* - * Copyright © 2002-2011 the original author or authors. - * + * Copyright � 2002-2011 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. @@ -45,63 +46,60 @@ using Spring.Data.Common; #endregion -namespace Spring.Data.Objects +namespace Spring.Data.Objects; + +/// +/// Tests for AdoOperation +/// +/// Mark Pollack +[TestFixture] +public class AdoOperationTests { - /// - /// Tests for AdoOperation - /// - /// Mark Pollack - [TestFixture] - public class AdoOperationTests + [SetUp] + public void Setup() { - [SetUp] - public void Setup() - { - } - - [Test] - public void EmptySql() - { - TestAdoOperation operation = new TestAdoOperation(); - Assert.Throws(() => operation.Compile()); - } - - [Test] - public void DeclareParameterAfterCompile() - { - TestAdoOperation operation = new TestAdoOperation(); - operation.DbProvider = DbProviderFactory.GetDbProvider("System.Data.SqlClient"); - operation.Sql = "select * from table"; - operation.Compile(); - IDbParameters parameters = new DbParameters(operation.DbProvider); - Assert.Throws(() => operation.DeclaredParameters = parameters); - } - - [Test] - public void TooFewParameters() - { - TestAdoOperation operation = new TestAdoOperation(); - operation.DbProvider = DbProviderFactory.GetDbProvider("System.Data.SqlClient"); - operation.Sql = "select * from table"; - IDbParameters parameters = new DbParameters(operation.DbProvider); - parameters.Add("name"); - operation.DeclaredParameters = parameters; - operation.Compile(); - Assert.Throws(() => operation.ValidateParams(null)); - } - } - internal class TestAdoOperation : AdoOperation + [Test] + public void EmptySql() { - protected override void CompileInternal() - { - - } - - public void ValidateParams(params object[] inParamValues) - { - ValidateParameters(inParamValues); - } + TestAdoOperation operation = new TestAdoOperation(); + Assert.Throws(() => operation.Compile()); } -} \ No newline at end of file + + [Test] + public void DeclareParameterAfterCompile() + { + TestAdoOperation operation = new TestAdoOperation(); + operation.DbProvider = DbProviderFactory.GetDbProvider("System.Data.SqlClient"); + operation.Sql = "select * from table"; + operation.Compile(); + IDbParameters parameters = new DbParameters(operation.DbProvider); + Assert.Throws(() => operation.DeclaredParameters = parameters); + } + + [Test] + public void TooFewParameters() + { + TestAdoOperation operation = new TestAdoOperation(); + operation.DbProvider = DbProviderFactory.GetDbProvider("System.Data.SqlClient"); + operation.Sql = "select * from table"; + IDbParameters parameters = new DbParameters(operation.DbProvider); + parameters.Add("name"); + operation.DeclaredParameters = parameters; + operation.Compile(); + Assert.Throws(() => operation.ValidateParams(null)); + } +} + +internal class TestAdoOperation : AdoOperation +{ + protected override void CompileInternal() + { + } + + public void ValidateParams(params object[] inParamValues) + { + ValidateParameters(inParamValues); + } +} diff --git a/test/Spring/Spring.Data.Tests/Data/Objects/AdoQueryTests.cs b/test/Spring/Spring.Data.Tests/Data/Objects/AdoQueryTests.cs index 6abb0c75..ea72ae77 100644 --- a/test/Spring/Spring.Data.Tests/Data/Objects/AdoQueryTests.cs +++ b/test/Spring/Spring.Data.Tests/Data/Objects/AdoQueryTests.cs @@ -43,96 +43,92 @@ using System.Collections; using System.Data; using System.Data.SqlClient; - using FakeItEasy; - using NUnit.Framework; - using Spring.Dao; using Spring.Data.Common; #endregion -namespace Spring.Data.Objects +namespace Spring.Data.Objects; + +/// +/// Tests for AdoQuery +/// +/// Mark Pollack +[TestFixture] +public class AdoQueryTests : AbstractAdoQueryTests { - /// - /// Tests for AdoQuery - /// - /// Mark Pollack - [TestFixture] - public class AdoQueryTests : AbstractAdoQueryTests + private static string SELECT_ID_WHERE = "select id from custmr"; + private static string[] COLUMN_NAMES = new string[] { "id", "forename" }; + private static DbType[] COLUMN_TYPES = new DbType[] { DbType.Int32, DbType.String }; + + [SetUp] + public void Setup() { - private static string SELECT_ID_WHERE = "select id from custmr"; - private static string[] COLUMN_NAMES = new string[] {"id", "forename"}; - private static DbType[] COLUMN_TYPES = new DbType[] {DbType.Int32, DbType.String}; + SetUpMocks(); + } - [SetUp] - public void Setup() + [Test] + public void MappingAdoQueryWithContextWithoutParams() + { + IDataReader reader = A.Fake(); + A.CallTo(() => reader.Read()).Returns(true).Once().Then.Returns(false); + A.CallTo(() => reader.GetInt32(0)).Returns(1).Once(); + + A.CallTo(() => command.ExecuteReader()).Returns(reader); + + IntMappingQueryWithContext queryWithNoContext = new IntMappingQueryWithContext(provider); + queryWithNoContext.Compile(); + IList list = queryWithNoContext.QueryByNamedParam(null, null); + Assert.IsTrue(list.Count != 0); + foreach (int count in list) { - SetUpMocks(); - } - - [Test] - public void MappingAdoQueryWithContextWithoutParams() - { - IDataReader reader = A.Fake(); - A.CallTo(() => reader.Read()).Returns(true).Once().Then.Returns(false); - A.CallTo(() => reader.GetInt32(0)).Returns(1).Once(); - - A.CallTo(() => command.ExecuteReader()).Returns(reader); - - IntMappingQueryWithContext queryWithNoContext = new IntMappingQueryWithContext(provider); - queryWithNoContext.Compile(); - IList list = queryWithNoContext.QueryByNamedParam(null, null); - Assert.IsTrue(list.Count != 0); - foreach (int count in list) - { - Assert.AreEqual(1, count); - } - } - - [Test] - public void QueryWithoutEnoughParams() - { - A.CallTo(() => command.CreateParameter()).ReturnsLazily(() => new SqlParameter()); - - A.CallTo(() => provider.CreateParameterNameForCollection(COLUMN_NAMES[0])).Returns("@" + COLUMN_NAMES[0]).Once(); - A.CallTo(() => provider.CreateParameterNameForCollection(COLUMN_NAMES[1])).Returns("@" + COLUMN_NAMES[1]); - - IntMappingAdoQuery query = new IntMappingAdoQuery(); - query.DbProvider = provider; - query.Sql = SELECT_ID_WHERE; - query.DeclaredParameters.Add(COLUMN_NAMES[0], COLUMN_TYPES[0]); - query.DeclaredParameters.Add(COLUMN_NAMES[1], COLUMN_TYPES[1]); - query.Compile(); - Assert.Throws(() => query.Query()); - } - - public class IntMappingQueryWithContext : MappingAdoQueryWithContext - { - private static string sql = "select id from custmr"; - - public IntMappingQueryWithContext(IDbProvider dbProvider) - : base(dbProvider, sql) - { - CommandType = CommandType.Text; - } - - protected override object MapRow(IDataReader reader, int rowNum, IDictionary inParams, - IDictionary callingContext) - { - Assert.IsNull(inParams); - Assert.IsNull(callingContext); - return reader.GetInt32(0); - } - } - - public class IntMappingAdoQuery : MappingAdoQuery - { - protected override object MapRow(IDataReader reader, int rowNum) - { - return reader.GetInt32(0); - } + Assert.AreEqual(1, count); } } -} \ No newline at end of file + + [Test] + public void QueryWithoutEnoughParams() + { + A.CallTo(() => command.CreateParameter()).ReturnsLazily(() => new SqlParameter()); + + A.CallTo(() => provider.CreateParameterNameForCollection(COLUMN_NAMES[0])).Returns("@" + COLUMN_NAMES[0]).Once(); + A.CallTo(() => provider.CreateParameterNameForCollection(COLUMN_NAMES[1])).Returns("@" + COLUMN_NAMES[1]); + + IntMappingAdoQuery query = new IntMappingAdoQuery(); + query.DbProvider = provider; + query.Sql = SELECT_ID_WHERE; + query.DeclaredParameters.Add(COLUMN_NAMES[0], COLUMN_TYPES[0]); + query.DeclaredParameters.Add(COLUMN_NAMES[1], COLUMN_TYPES[1]); + query.Compile(); + Assert.Throws(() => query.Query()); + } + + public class IntMappingQueryWithContext : MappingAdoQueryWithContext + { + private static string sql = "select id from custmr"; + + public IntMappingQueryWithContext(IDbProvider dbProvider) + : base(dbProvider, sql) + { + CommandType = CommandType.Text; + } + + protected override object MapRow(IDataReader reader, int rowNum, IDictionary inParams, + IDictionary callingContext) + { + Assert.IsNull(inParams); + Assert.IsNull(callingContext); + return reader.GetInt32(0); + } + } + + public class IntMappingAdoQuery : MappingAdoQuery + { + protected override object MapRow(IDataReader reader, int rowNum) + { + return reader.GetInt32(0); + } + } +} diff --git a/test/Spring/Spring.Data.Tests/Data/Objects/StoredProcedureTests.cs b/test/Spring/Spring.Data.Tests/Data/Objects/StoredProcedureTests.cs index e340d009..fe663044 100644 --- a/test/Spring/Spring.Data.Tests/Data/Objects/StoredProcedureTests.cs +++ b/test/Spring/Spring.Data.Tests/Data/Objects/StoredProcedureTests.cs @@ -40,58 +40,54 @@ using System.Data; using System.Data.SqlClient; - using FakeItEasy; - using NUnit.Framework; - using Spring.Data.Common; -namespace Spring.Data.Objects +namespace Spring.Data.Objects; + +/// +/// Tests for StoredProcedure +/// +/// Mark Pollack +[TestFixture] +public class StoredProcedureTests : AbstractAdoQueryTests { - /// - /// Tests for StoredProcedure - /// - /// Mark Pollack - [TestFixture] - public class StoredProcedureTests : AbstractAdoQueryTests + [SetUp] + public void Setup() { - [SetUp] - public void Setup() - { - SetUpMocks(); - } - - [Test] - public void NullArg() - { - SqlParameter sqlParameter1 = new SqlParameter(); - A.CallTo(() => command.CreateParameter()).Returns(sqlParameter1); - A.CallTo(() => provider.CreateParameterNameForCollection("ptest")).Returns("@ptest"); - - //Create a real instance of IDbParameters to store the executable parameters - //IDbProvider realDbProvider = DbProviderFactory.GetDbProvider("System.Data.SqlClient"); - //IDbParameters dbParameters = new DbParameters(realDbProvider); - //provide the same instance to another call to extract output params - A.CallTo(() => command.Parameters).ReturnsLazily(() => new SqlCommand().Parameters).Twice(); - - NullArg na = new NullArg(provider); - na.Execute(null); - } + SetUpMocks(); } - internal class NullArg : StoredProcedure + [Test] + public void NullArg() { - public NullArg(IDbProvider provider) - : base(provider, "takes_null") - { - DeclaredParameters.Add("ptest", DbType.String); - Compile(); - } + SqlParameter sqlParameter1 = new SqlParameter(); + A.CallTo(() => command.CreateParameter()).Returns(sqlParameter1); + A.CallTo(() => provider.CreateParameterNameForCollection("ptest")).Returns("@ptest"); - public void Execute(string s) - { - ExecuteNonQuery(s); - } + //Create a real instance of IDbParameters to store the executable parameters + //IDbProvider realDbProvider = DbProviderFactory.GetDbProvider("System.Data.SqlClient"); + //IDbParameters dbParameters = new DbParameters(realDbProvider); + //provide the same instance to another call to extract output params + A.CallTo(() => command.Parameters).ReturnsLazily(() => new SqlCommand().Parameters).Twice(); + + NullArg na = new NullArg(provider); + na.Execute(null); } -} \ No newline at end of file +} + +internal class NullArg : StoredProcedure +{ + public NullArg(IDbProvider provider) + : base(provider, "takes_null") + { + DeclaredParameters.Add("ptest", DbType.String); + Compile(); + } + + public void Execute(string s) + { + ExecuteNonQuery(s); + } +} diff --git a/test/Spring/Spring.Data.Tests/Data/TestCoord.cs b/test/Spring/Spring.Data.Tests/Data/TestCoord.cs index 97d0b69f..99236d5f 100644 --- a/test/Spring/Spring.Data.Tests/Data/TestCoord.cs +++ b/test/Spring/Spring.Data.Tests/Data/TestCoord.cs @@ -1,27 +1,23 @@ - - using Spring.Objects; -namespace Spring.Data +namespace Spring.Data; + +public class TestCoord : ITestCoord { - public class TestCoord : ITestCoord + private ITestObjectMgr testObjectMgr; + + public ITestObjectMgr TestObjectMgr { - private ITestObjectMgr testObjectMgr; - - - public ITestObjectMgr TestObjectMgr - { - get { return testObjectMgr; } - set { testObjectMgr = value; } - } - - #region ITestCoordinator Members - - public void WorkOn(TestObject to1, TestObject to2) - { - testObjectMgr.SaveTwoTestObjects(to1,to2); - } - - #endregion + get { return testObjectMgr; } + set { testObjectMgr = value; } } + + #region ITestCoordinator Members + + public void WorkOn(TestObject to1, TestObject to2) + { + testObjectMgr.SaveTwoTestObjects(to1, to2); + } + + #endregion } diff --git a/test/Spring/Spring.Data.Tests/Data/TestObjectMgr.cs b/test/Spring/Spring.Data.Tests/Data/TestObjectMgr.cs index c5de13fd..cd848a6b 100644 --- a/test/Spring/Spring.Data.Tests/Data/TestObjectMgr.cs +++ b/test/Spring/Spring.Data.Tests/Data/TestObjectMgr.cs @@ -1,12 +1,12 @@ /* * Copyright � 2002-2011 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. @@ -22,36 +22,35 @@ using Spring.Transaction.Interceptor; using Spring.Transaction.Support; using IsolationLevel = System.Data.IsolationLevel; -namespace Spring.Data +namespace Spring.Data; + +/// +/// Group together multiple ITestObjectDao operations. +/// +/// Mark Pollack (.NET) +public class TestObjectMgr : ITestObjectMgr { + private static readonly ILogger LOG = LogManager.GetLogger(); + /// - /// Group together multiple ITestObjectDao operations. + /// Initializes a new instance of the class. /// - /// Mark Pollack (.NET) - public class TestObjectMgr : ITestObjectMgr + public TestObjectMgr() { - private static readonly ILogger LOG = LogManager.GetLogger(); + } - /// - /// Initializes a new instance of the class. - /// - public TestObjectMgr() - { - } + [Transaction()] + public void SaveTwoTestObjects(TestObject to1, TestObject to2) + { + LOG.LogDebug("TransactionActive = " + TransactionSynchronizationManager.ActualTransactionActive); + } - [Transaction()] - public void SaveTwoTestObjects(TestObject to1, TestObject to2) - { - LOG.LogDebug("TransactionActive = " + TransactionSynchronizationManager.ActualTransactionActive); - } - - [Transaction(TransactionPropagation.Required, IsolationLevel.Unspecified, Timeout = 50, - RollbackFor = new Type[] {typeof(ArgumentNullException)}, - ReadOnly = false, - AsyncFlowOption = TransactionScopeAsyncFlowOption.Enabled, - NoRollbackFor = new Type[] {typeof(ArithmeticException), typeof(NotSupportedException)})] - public void DeleteTwoTestObjects(string name1, string name2) - { - } + [Transaction(TransactionPropagation.Required, IsolationLevel.Unspecified, Timeout = 50, + RollbackFor = new Type[] { typeof(ArgumentNullException) }, + ReadOnly = false, + AsyncFlowOption = TransactionScopeAsyncFlowOption.Enabled, + NoRollbackFor = new Type[] { typeof(ArithmeticException), typeof(NotSupportedException) })] + public void DeleteTwoTestObjects(string name1, string name2) + { } } diff --git a/test/Spring/Spring.Data.Tests/DataCompilerOptionsTests.cs b/test/Spring/Spring.Data.Tests/DataCompilerOptionsTests.cs index a8744f4c..ea488947 100644 --- a/test/Spring/Spring.Data.Tests/DataCompilerOptionsTests.cs +++ b/test/Spring/Spring.Data.Tests/DataCompilerOptionsTests.cs @@ -26,18 +26,17 @@ using Spring.Transaction; #endregion -namespace Spring +namespace Spring; + +/// Test that the assembly is built with the correct DebugAttributes in release and debug builds. +/// +/// Mark Pollack +[TestFixture] +public sealed class DataCompilerOptionTests : CompilerOptionsTests { - /// Test that the assembly is built with the correct DebugAttributes in release and debug builds. - /// - /// Mark Pollack - [TestFixture] - public sealed class DataCompilerOptionTests : CompilerOptionsTests + [OneTimeSetUp] + public void FixtureSetUp() { - [OneTimeSetUp] - public void FixtureSetUp() - { - AssemblyToCheck = Assembly.GetAssembly(typeof (CannotCreateTransactionException)); - } + AssemblyToCheck = Assembly.GetAssembly(typeof(CannotCreateTransactionException)); } -} \ No newline at end of file +} diff --git a/test/Spring/Spring.Data.Tests/DataExceptionTests.cs b/test/Spring/Spring.Data.Tests/DataExceptionTests.cs index 57d6dd23..6ae8bb3f 100644 --- a/test/Spring/Spring.Data.Tests/DataExceptionTests.cs +++ b/test/Spring/Spring.Data.Tests/DataExceptionTests.cs @@ -21,24 +21,22 @@ #region Imports using System.Reflection; - using NUnit.Framework; #endregion -namespace Spring +namespace Spring; + +/// +/// Unit tests for all of the exception classes in the Spring.Data library... +/// +/// Rick Evans +[TestFixture] +public sealed class DataExceptionTests : ExceptionsTest { - /// - /// Unit tests for all of the exception classes in the Spring.Data library... - /// - /// Rick Evans - [TestFixture] - public sealed class DataExceptionTests : ExceptionsTest + [OneTimeSetUp] + public void FixtureSetUp() { - [OneTimeSetUp] - public void FixtureSetUp () - { - AssemblyToCheck = Assembly.GetAssembly (typeof (Spring.Transaction.CannotCreateTransactionException)); - } + AssemblyToCheck = Assembly.GetAssembly(typeof(Spring.Transaction.CannotCreateTransactionException)); } } diff --git a/test/Spring/Spring.Data.Tests/Support/ErrorCodeExceptionTranslatorTests.cs b/test/Spring/Spring.Data.Tests/Support/ErrorCodeExceptionTranslatorTests.cs index c44f9c68..5b4b63dd 100644 --- a/test/Spring/Spring.Data.Tests/Support/ErrorCodeExceptionTranslatorTests.cs +++ b/test/Spring/Spring.Data.Tests/Support/ErrorCodeExceptionTranslatorTests.cs @@ -1,12 +1,12 @@ /* * Copyright © 2002-2011 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. @@ -20,67 +20,65 @@ using Spring.Data; using Spring.Data.Common; using Spring.Data.Support; -namespace Spring.Support +namespace Spring.Support; + +/// +/// Test the database exception translation. +/// +/// Mark Pollack (.NET) +[TestFixture] +public class ErrorCodeExceptionTranslatorTests { - /// - /// Test the database exception translation. - /// - /// Mark Pollack (.NET) - [TestFixture] - public class ErrorCodeExceptionTranslatorTests - { - private static ErrorCodes ERROR_CODES = new ErrorCodes(); - - private IDbProvider dbProvider = new TestDbProvider(); + private static ErrorCodes ERROR_CODES = new ErrorCodes(); - /// - /// Initializes a new instance of the class. - /// - public ErrorCodeExceptionTranslatorTests() - { + private IDbProvider dbProvider = new TestDbProvider(); - } + /// + /// Initializes a new instance of the class. + /// + public ErrorCodeExceptionTranslatorTests() + { + } - [SetUp] - public void SetUp() - { - ERROR_CODES.BadSqlGrammarCodes = (new String[] { "1", "2" }); - ERROR_CODES.InvalidResultSetAccessCodes = (new String[] { "3", "4" }); - ERROR_CODES.DataAccessResourceFailureCodes = (new String[] { "5" }); - ERROR_CODES.DataIntegrityViolationCodes = (new String[] { "544", "2627", "8114", "8115" }); - ERROR_CODES.CannotAcquireLockCodes = (new String[] { "7" }); - ERROR_CODES.DeadlockLoserCodes = (new String[] { "8" }); - ERROR_CODES.CannotSerializeTransactionCodes = (new String[] { "9" }); - } - - [Test] - public void ErrorCodeTransation() - { - IAdoExceptionTranslator exceptionTranslator = new ErrorCodeExceptionTranslator(dbProvider, ERROR_CODES); - TestSqlException badSqlEx = new TestSqlException("", "1"); - - BadSqlGrammarException bsgex = (BadSqlGrammarException)exceptionTranslator.Translate("task","SQL", badSqlEx); - Assert.AreEqual("SQL", bsgex.Sql); - Assert.AreEqual(badSqlEx, bsgex.InnerException); + [SetUp] + public void SetUp() + { + ERROR_CODES.BadSqlGrammarCodes = (new String[] { "1", "2" }); + ERROR_CODES.InvalidResultSetAccessCodes = (new String[] { "3", "4" }); + ERROR_CODES.DataAccessResourceFailureCodes = (new String[] { "5" }); + ERROR_CODES.DataIntegrityViolationCodes = (new String[] { "544", "2627", "8114", "8115" }); + ERROR_CODES.CannotAcquireLockCodes = (new String[] { "7" }); + ERROR_CODES.DeadlockLoserCodes = (new String[] { "8" }); + ERROR_CODES.CannotSerializeTransactionCodes = (new String[] { "9" }); + } - TestSqlException invResEx = new TestSqlException("", "4"); - InvalidResultSetAccessException irsex = (InvalidResultSetAccessException) exceptionTranslator.Translate("task", "SQL", invResEx); - Assert.AreEqual("SQL", irsex.Sql); - Assert.AreEqual(invResEx, irsex.InnerException); - - CheckTranslation(exceptionTranslator, "5", typeof(DataAccessResourceFailureException)); - CheckTranslation(exceptionTranslator, "544", typeof(DataIntegrityViolationException)); - CheckTranslation(exceptionTranslator, "7", typeof(CannotAcquireLockException)); - CheckTranslation(exceptionTranslator, "8", typeof(DeadlockLoserDataAccessException)); - CheckTranslation(exceptionTranslator, "9", typeof(CannotSerializeTransactionException)); - } + [Test] + public void ErrorCodeTransation() + { + IAdoExceptionTranslator exceptionTranslator = new ErrorCodeExceptionTranslator(dbProvider, ERROR_CODES); + TestSqlException badSqlEx = new TestSqlException("", "1"); - private void CheckTranslation(IAdoExceptionTranslator translator, string errorCode, Type exType) - { - TestSqlException sex = new TestSqlException("", errorCode); - DataAccessException ex = translator.Translate("", "", sex); - Assert.IsTrue(exType.IsAssignableFrom(ex.GetType())); - Assert.IsTrue(ex.InnerException == sex); - } - } + BadSqlGrammarException bsgex = (BadSqlGrammarException) exceptionTranslator.Translate("task", "SQL", badSqlEx); + Assert.AreEqual("SQL", bsgex.Sql); + Assert.AreEqual(badSqlEx, bsgex.InnerException); + + TestSqlException invResEx = new TestSqlException("", "4"); + InvalidResultSetAccessException irsex = (InvalidResultSetAccessException) exceptionTranslator.Translate("task", "SQL", invResEx); + Assert.AreEqual("SQL", irsex.Sql); + Assert.AreEqual(invResEx, irsex.InnerException); + + CheckTranslation(exceptionTranslator, "5", typeof(DataAccessResourceFailureException)); + CheckTranslation(exceptionTranslator, "544", typeof(DataIntegrityViolationException)); + CheckTranslation(exceptionTranslator, "7", typeof(CannotAcquireLockException)); + CheckTranslation(exceptionTranslator, "8", typeof(DeadlockLoserDataAccessException)); + CheckTranslation(exceptionTranslator, "9", typeof(CannotSerializeTransactionException)); + } + + private void CheckTranslation(IAdoExceptionTranslator translator, string errorCode, Type exType) + { + TestSqlException sex = new TestSqlException("", errorCode); + DataAccessException ex = translator.Translate("", "", sex); + Assert.IsTrue(exType.IsAssignableFrom(ex.GetType())); + Assert.IsTrue(ex.InnerException == sex); + } } diff --git a/test/Spring/Spring.Data.Tests/Support/TestDbProvider.cs b/test/Spring/Spring.Data.Tests/Support/TestDbProvider.cs index 2b49c9ed..7250bb9e 100644 --- a/test/Spring/Spring.Data.Tests/Support/TestDbProvider.cs +++ b/test/Spring/Spring.Data.Tests/Support/TestDbProvider.cs @@ -2,13 +2,13 @@ /* * Copyright © 2002-2011 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. @@ -25,136 +25,137 @@ using Spring.Data.Common; #endregion -namespace Spring.Support +namespace Spring.Support; + +/// +/// A fake provider class used to test exception translation functionality +/// +/// Mark Pollack (.NET) +public class TestDbProvider : IDbProvider { - /// - /// A fake provider class used to test exception translation functionality - /// - /// Mark Pollack (.NET) - public class TestDbProvider : IDbProvider - { - private string connectionString; - private IDbConnection connection; + private string connectionString; + private IDbConnection connection; - protected IDbMetadata dbMetadata; - - public TestDbProvider() - { - IDbProvider provider = DbProviderFactory.GetDbProvider("System.Data.SqlClient"); - dbMetadata = provider.DbMetadata; - } + protected IDbMetadata dbMetadata; - /// - /// Return metadata information about the database. - /// - public IDbMetadata DbMetadata - { - get - { - return dbMetadata; - } - } - /// - /// Connection string used to create connections. - /// - public string ConnectionString - { - set { connectionString = value; } - get { return connectionString; } - } - public IDbCommand CreateCommand() - { - throw new NotImplementedException(); - } - - public IDbConnection CreateConnection() - { - return connection; - } - - public IDbDataParameter CreateParameter() - { - throw new NotImplementedException(); - } - - - public IDbDataAdapter CreateDataAdapter() - { - throw new NotImplementedException(); - } - - public object CreateCommandBuilder() - { - throw new NotImplementedException(); - } - - public string ExtractError(Exception e) - { - TestSqlException testSqlException = (TestSqlException)e; - return testSqlException.ErrorNumber; - } - - public bool IsDataAccessException(Exception e) - { - if (e is System.Data.Common.DbException) - { - return true; - } - else - { - return false; - } - } - - public bool IsDataAccessExceptionBCL11(Exception e) - { - return true; - } - - public string CreateParameterName(string name) - { - if (dbMetadata.BindByName) - { - if (DbMetadata.UseParameterPrefixInSql) - { - return DbMetadata.ParameterNamePrefix + name; - } - else - { - return name; - } - } - else - { - return DbMetadata.ParameterNamePrefix; - } - } - - public string CreateParameterNameForCollection(string name) - { - if (dbMetadata.BindByName) - { - if (DbMetadata.UseParameterNamePrefixInParameterCollection) - { - return DbMetadata.ParameterNamePrefix + name; - } - else - { - return name; - } - } - else - { - return DbMetadata.ParameterNamePrefix; - } - } - - #region Stub method to set behavior - - public IDbConnection ConnectionToCreate - { - set { connection = value;} - } - #endregion + public TestDbProvider() + { + IDbProvider provider = DbProviderFactory.GetDbProvider("System.Data.SqlClient"); + dbMetadata = provider.DbMetadata; } + + /// + /// Return metadata information about the database. + /// + public IDbMetadata DbMetadata + { + get + { + return dbMetadata; + } + } + + /// + /// Connection string used to create connections. + /// + public string ConnectionString + { + set { connectionString = value; } + get { return connectionString; } + } + + public IDbCommand CreateCommand() + { + throw new NotImplementedException(); + } + + public IDbConnection CreateConnection() + { + return connection; + } + + public IDbDataParameter CreateParameter() + { + throw new NotImplementedException(); + } + + public IDbDataAdapter CreateDataAdapter() + { + throw new NotImplementedException(); + } + + public object CreateCommandBuilder() + { + throw new NotImplementedException(); + } + + public string ExtractError(Exception e) + { + TestSqlException testSqlException = (TestSqlException) e; + return testSqlException.ErrorNumber; + } + + public bool IsDataAccessException(Exception e) + { + if (e is System.Data.Common.DbException) + { + return true; + } + else + { + return false; + } + } + + public bool IsDataAccessExceptionBCL11(Exception e) + { + return true; + } + + public string CreateParameterName(string name) + { + if (dbMetadata.BindByName) + { + if (DbMetadata.UseParameterPrefixInSql) + { + return DbMetadata.ParameterNamePrefix + name; + } + else + { + return name; + } + } + else + { + return DbMetadata.ParameterNamePrefix; + } + } + + public string CreateParameterNameForCollection(string name) + { + if (dbMetadata.BindByName) + { + if (DbMetadata.UseParameterNamePrefixInParameterCollection) + { + return DbMetadata.ParameterNamePrefix + name; + } + else + { + return name; + } + } + else + { + return DbMetadata.ParameterNamePrefix; + } + } + + #region Stub method to set behavior + + public IDbConnection ConnectionToCreate + { + set { connection = value; } + } + + #endregion } diff --git a/test/Spring/Spring.Data.Tests/Support/TestSqlException.cs b/test/Spring/Spring.Data.Tests/Support/TestSqlException.cs index 554e2151..d890010d 100644 --- a/test/Spring/Spring.Data.Tests/Support/TestSqlException.cs +++ b/test/Spring/Spring.Data.Tests/Support/TestSqlException.cs @@ -2,13 +2,13 @@ /* * Copyright � 2002-2011 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. @@ -24,59 +24,58 @@ using System.Runtime.Serialization; #pragma warning disable SYSLIB0050 #pragma warning disable SYSLIB0051 -namespace Spring.Support +namespace Spring.Support; + +/// +/// A simple exception class to test exception translation functionality +/// +/// Mark Pollack (.NET) +[Serializable] +public class TestSqlException : Exception { - /// - /// A simple exception class to test exception translation functionality - /// - /// Mark Pollack (.NET) - [Serializable] - public class TestSqlException : Exception + private string errorNumber; + + public TestSqlException() { } + + public TestSqlException(string message) : base(message) { } + + public TestSqlException(string message, string errorNumber) : base(message) { + ErrorNumber = errorNumber; + } + public TestSqlException(string message, Exception rootCause) + : base(message, rootCause) + { + } - private string errorNumber; - - public TestSqlException() {} - - - public TestSqlException( string message ) : base( message ) {} - - public TestSqlException(string message, string errorNumber) :base (message) - { - ErrorNumber = errorNumber; - } + protected TestSqlException( + SerializationInfo info, StreamingContext context) : base(info, context) + { + errorNumber = info.GetString("errorNumber"); + } - public TestSqlException( string message, Exception rootCause) - : base( message , rootCause ) {} + public string ErrorNumber + { + get { return errorNumber; } + set { errorNumber = value; } + } - protected TestSqlException( - SerializationInfo info, StreamingContext context ) : base( info, context ) - { - errorNumber = info.GetString( "errorNumber" ); - } - - public string ErrorNumber - { - get { return errorNumber; } - set { errorNumber = value; } - } - /// - /// Override of - /// to allow for private serialization. - /// - /// - /// The - /// that holds the serialized object data about the exception. - /// - /// - /// The - /// that contains contextual information about the source or destination. - /// - public override void GetObjectData(SerializationInfo info, StreamingContext context) - { - info.AddValue( "errorNumber", errorNumber ); - base.GetObjectData( info, context ); - } + /// + /// Override of + /// to allow for private serialization. + /// + /// + /// The + /// that holds the serialized object data about the exception. + /// + /// + /// The + /// that contains contextual information about the source or destination. + /// + public override void GetObjectData(SerializationInfo info, StreamingContext context) + { + info.AddValue("errorNumber", errorNumber); + base.GetObjectData(info, context); } } diff --git a/test/Spring/Spring.Data.Tests/Transaction/CallCountingTransactionManager.cs b/test/Spring/Spring.Data.Tests/Transaction/CallCountingTransactionManager.cs index aa810f10..710bd9a2 100644 --- a/test/Spring/Spring.Data.Tests/Transaction/CallCountingTransactionManager.cs +++ b/test/Spring/Spring.Data.Tests/Transaction/CallCountingTransactionManager.cs @@ -20,48 +20,45 @@ using Spring.Transaction.Support; -namespace Spring.Transaction +namespace Spring.Transaction; + +/// +/// This is a test implementation to count the number of times PlatformTransactionManager methods +/// have been called. +/// +/// Mark Pollack +public class CallCountingTransactionManager : AbstractPlatformTransactionManager { - /// - /// This is a test implementation to count the number of times PlatformTransactionManager methods - /// have been called. - /// - /// Mark Pollack - public class CallCountingTransactionManager : AbstractPlatformTransactionManager + public int begun; + public int commits; + public int rollbacks; + public int inflight; + + protected override object DoGetTransaction() { - - public int begun; - public int commits; - public int rollbacks; - public int inflight; - - - protected override object DoGetTransaction() - { - return new object(); - } - - protected override void DoBegin(object transaction, ITransactionDefinition definition) - { - ++begun; - ++inflight; - } - - protected override void DoCommit(DefaultTransactionStatus status) - { - ++commits; - --inflight; - } - - protected override void DoRollback(DefaultTransactionStatus status) - { - ++rollbacks; - --inflight; - } - - public void Clear() - { - begun = commits = rollbacks = inflight = 0; - } + return new object(); } -} \ No newline at end of file + + protected override void DoBegin(object transaction, ITransactionDefinition definition) + { + ++begun; + ++inflight; + } + + protected override void DoCommit(DefaultTransactionStatus status) + { + ++commits; + --inflight; + } + + protected override void DoRollback(DefaultTransactionStatus status) + { + ++rollbacks; + --inflight; + } + + public void Clear() + { + begun = commits = rollbacks = inflight = 0; + } +} diff --git a/test/Spring/Spring.Data.Tests/Transaction/CommonTypes.cs b/test/Spring/Spring.Data.Tests/Transaction/CommonTypes.cs index 477048c9..e367ad3f 100644 --- a/test/Spring/Spring.Data.Tests/Transaction/CommonTypes.cs +++ b/test/Spring/Spring.Data.Tests/Transaction/CommonTypes.cs @@ -1,102 +1,100 @@ using System.Data; using Spring.Transaction.Support; -namespace Spring.Transaction +namespace Spring.Transaction; + +public class MockTxnDefinition : ITransactionDefinition { - public class MockTxnDefinition : ITransactionDefinition + public bool ReadOnly { get; set; } + + public int TransactionTimeout { get; set; } = DefaultTransactionDefinition.TIMEOUT_DEFAULT; + + public IsolationLevel TransactionIsolationLevel => IsolationLevel.Unspecified; + + public TransactionPropagation PropagationBehavior { get; set; } = TransactionPropagation.NotSupported; + + public string Name { get; } = null; + + public System.Transactions.TransactionScopeAsyncFlowOption AsyncFlowOption { get; set; } +} + +public class MockTxnPlatformMgrAbstract : AbstractPlatformTransactionManager +{ + private object _transaction; + private bool _isExistingTransaction; + + private int _doBeginCalls; + private int _doGetTxnCalls; + private int _isExistingTxnCalls; + + private bool _useSavepointForNestedTransaction; + + public void SetTransaction(object transaction) { - public bool ReadOnly { get; set; } - - public int TransactionTimeout { get; set; } = DefaultTransactionDefinition.TIMEOUT_DEFAULT; - - public IsolationLevel TransactionIsolationLevel => IsolationLevel.Unspecified; - - public TransactionPropagation PropagationBehavior { get; set; } = TransactionPropagation.NotSupported; - - public string Name { get; } = null; - - public System.Transactions.TransactionScopeAsyncFlowOption AsyncFlowOption { get; set; } + _transaction = transaction; + _isExistingTransaction = true; } - public class MockTxnPlatformMgrAbstract : AbstractPlatformTransactionManager + public object Transaction => _transaction; + + public bool Savepoints { - private object _transaction; - private bool _isExistingTransaction; + set => _useSavepointForNestedTransaction = value; + } - private int _doBeginCalls; - private int _doGetTxnCalls; - private int _isExistingTxnCalls; + public int DoBeginCallCount => _doBeginCalls; + public int DoGetTransactionCallCount => _doGetTxnCalls; - private bool _useSavepointForNestedTransaction; + public int IsExistingTransactionCallCount => _isExistingTxnCalls; - public void SetTransaction(object transaction) + protected override void DoResume(object transaction, object suspendedResources) + { + } + + protected override void DoCommit(DefaultTransactionStatus status) + { + } + + protected override object DoGetTransaction() + { + _doGetTxnCalls++; + if (null == _transaction) { - _transaction = transaction; - _isExistingTransaction = true; + return new object(); } - - public object Transaction => _transaction; - - public bool Savepoints + else { - set => _useSavepointForNestedTransaction = value; - } - - public int DoBeginCallCount => _doBeginCalls; - - public int DoGetTransactionCallCount => _doGetTxnCalls; - - public int IsExistingTransactionCallCount => _isExistingTxnCalls; - - protected override void DoResume(object transaction, object suspendedResources) - { - } - - protected override void DoCommit(DefaultTransactionStatus status) - { - } - - protected override object DoGetTransaction() - { - _doGetTxnCalls++; - if (null == _transaction) - { - return new object(); - } - else - { - return _transaction; - } - } - - protected override object DoSuspend(object transaction) - { - return null; - } - - protected override void DoBegin(object transaction, ITransactionDefinition definition) - { - _doBeginCalls++; - } - - protected override void DoSetRollbackOnly(DefaultTransactionStatus status) - { - } - - protected override void DoRollback(DefaultTransactionStatus status) - { - } - - protected override bool IsExistingTransaction(object transaction) - { - _isExistingTxnCalls++; - return _isExistingTransaction; - } - - protected override bool UseSavepointForNestedTransaction() - { - return _useSavepointForNestedTransaction; + return _transaction; } } -} \ No newline at end of file + + protected override object DoSuspend(object transaction) + { + return null; + } + + protected override void DoBegin(object transaction, ITransactionDefinition definition) + { + _doBeginCalls++; + } + + protected override void DoSetRollbackOnly(DefaultTransactionStatus status) + { + } + + protected override void DoRollback(DefaultTransactionStatus status) + { + } + + protected override bool IsExistingTransaction(object transaction) + { + _isExistingTxnCalls++; + return _isExistingTransaction; + } + + protected override bool UseSavepointForNestedTransaction() + { + return _useSavepointForNestedTransaction; + } +} diff --git a/test/Spring/Spring.Data.Tests/Transaction/Config/TxNamespaceParserTests.cs b/test/Spring/Spring.Data.Tests/Transaction/Config/TxNamespaceParserTests.cs index 64e786c5..b3dd9d1e 100644 --- a/test/Spring/Spring.Data.Tests/Transaction/Config/TxNamespaceParserTests.cs +++ b/test/Spring/Spring.Data.Tests/Transaction/Config/TxNamespaceParserTests.cs @@ -21,9 +21,7 @@ #region Imports using System.Reflection; - using NUnit.Framework; - using Spring.Aop.Config; using Spring.Context; using Spring.Context.Support; @@ -35,131 +33,131 @@ using Spring.Transaction.Interceptor; #endregion -namespace Spring.Transaction.Config +namespace Spring.Transaction.Config; + +[TestFixture] +public class TxNamespaceParserTests { - [TestFixture] - public class TxNamespaceParserTests + private class ResourceXmlApplicationContext : AbstractXmlApplicationContext { - private class ResourceXmlApplicationContext : AbstractXmlApplicationContext + private readonly IResource[] configurationResources; + + public ResourceXmlApplicationContext(params IResource[] configurationResources) + : base() { - private readonly IResource[] configurationResources; - public ResourceXmlApplicationContext(params IResource[] configurationResources) - : base() - { - this.configurationResources = configurationResources; - } - - protected override void LoadObjectDefinitions(XmlObjectDefinitionReader objectDefinitionReader) - { - base.LoadObjectDefinitions(objectDefinitionReader); - objectDefinitionReader.LoadObjectDefinitions(configurationResources); - } - - protected override string[] ConfigurationLocations - { - get { return null; } - } - - protected override IResource[] ConfigurationResources - { - get { return null; } - } + this.configurationResources = configurationResources; } - private const string APPCTXCFG_PROLOG = @""; - private const string APPCTXCFG_START = APPCTXCFG_PROLOG + @""; - private const string APPCTXCFG_END = @""; - - private IApplicationContext ctx; - - [SetUp] - public void SetUp() + protected override void LoadObjectDefinitions(XmlObjectDefinitionReader objectDefinitionReader) { - //WELLKNOWN: NamespaceParserRegistry.RegisterParser(typeof(TxNamespaceParser)); - //WELLKNOWN: NamespaceParserRegistry.RegisterParser(typeof(AopNamespaceParser)); - ctx = new XmlApplicationContext("assembly://Spring.Data.Tests/Spring.Transaction.Config/TxNamespaceParserTests.xml"); + base.LoadObjectDefinitions(objectDefinitionReader); + objectDefinitionReader.LoadObjectDefinitions(configurationResources); } - // TODO (EE) - [Test] - public void AppliesTxAttributeDrivenAttributes() + protected override string[] ConfigurationLocations { - StringResource appCtxCfg = new StringResource( - APPCTXCFG_START - + "" - + APPCTXCFG_END); - - IApplicationContext appCtx = new ResourceXmlApplicationContext(appCtxCfg); -// DefaultAdvisorAutoProxyCreator daapc = (DefaultAdvisorAutoProxyCreator) appCtx.GetObject(AopNamespaceUtils.AUTO_PROXY_CREATOR_OBJECT_NAME); -// Assert.AreEqual(2, daapc.Order); + get { return null; } } - [Test] - public void Registered() + protected override IResource[] ConfigurationResources { - Assert.IsNotNull(NamespaceParserRegistry.GetParser("http://www.springframework.net/tx")); - Assert.IsTrue(ctx.ContainsObjectDefinition(AopNamespaceUtils.AUTO_PROXY_CREATOR_OBJECT_NAME)); - - string className = typeof(ObjectFactoryTransactionAttributeSourceAdvisor).FullName; - string targetName = className + ObjectDefinitionReaderUtils.GENERATED_OBJECT_NAME_SEPARATOR + "0"; - - Assert.IsTrue(ctx.ContainsObjectDefinition(targetName)); - } - - - [Test] - public void InvokeTransactional() - { - ITestObject testObject = TestObject; - CallCountingTransactionManager ptm = ctx["transactionManager"] as CallCountingTransactionManager; - Assert.IsNotNull(ptm); - - // try with transactional - Assert.AreEqual(0, ptm.begun,"Should not have started any transactions"); - testObject.GetDescription(); - Assert.AreEqual(1, ptm.begun, "Should have 1 started transaction"); - Assert.AreEqual(1, ptm.commits, "Should have 1 committed transaction"); - - // try with non-transaction - int i = testObject.Age; - Assert.IsNotNull(i); - Assert.AreEqual(1, ptm.begun, "Should not have started another transaction"); - - // try with exceptional - try - { - testObject.Exceptional(new ArgumentNullException()); - Assert.Fail("Should not get here"); - } catch (Exception) - { - Assert.AreEqual(2, ptm.begun, "Should have another started transaction"); - Assert.AreEqual(1, ptm.rollbacks, "Should have 1 rolled back transaction"); - } - } - - private ITestObject TestObject - { - get - { - return ctx["testObject"] as - ITestObject; - } - } - - [Test] - public void RollbackRules() - { - TransactionInterceptor txInterceptor = ctx.GetObject("txRollbackAdvice") as TransactionInterceptor; - Assert.IsNotNull(txInterceptor); - - MethodInfo getDescriptionMethod = typeof(ITestObject).GetMethod("GetDescription"); - MethodInfo exceptionalMethod = typeof (ITestObject).GetMethod("Exceptional"); - ITransactionAttributeSource txAttrSource = txInterceptor.TransactionAttributeSource; - ITransactionAttribute txAttr = txAttrSource.ReturnTransactionAttribute(getDescriptionMethod, typeof (ITestObject)); - Assert.IsTrue(txAttr.RollbackOn(new System.ApplicationException())); - - txAttr = txAttrSource.ReturnTransactionAttribute(exceptionalMethod, typeof (ITestObject)); - Assert.IsFalse(txAttr.RollbackOn(new System.ArithmeticException())); + get { return null; } } } + + private const string APPCTXCFG_PROLOG = @""; + private const string APPCTXCFG_START = APPCTXCFG_PROLOG + @""; + private const string APPCTXCFG_END = @""; + + private IApplicationContext ctx; + + [SetUp] + public void SetUp() + { + //WELLKNOWN: NamespaceParserRegistry.RegisterParser(typeof(TxNamespaceParser)); + //WELLKNOWN: NamespaceParserRegistry.RegisterParser(typeof(AopNamespaceParser)); + ctx = new XmlApplicationContext("assembly://Spring.Data.Tests/Spring.Transaction.Config/TxNamespaceParserTests.xml"); + } + + // TODO (EE) + [Test] + public void AppliesTxAttributeDrivenAttributes() + { + StringResource appCtxCfg = new StringResource( + APPCTXCFG_START + + "" + + APPCTXCFG_END); + + IApplicationContext appCtx = new ResourceXmlApplicationContext(appCtxCfg); +// DefaultAdvisorAutoProxyCreator daapc = (DefaultAdvisorAutoProxyCreator) appCtx.GetObject(AopNamespaceUtils.AUTO_PROXY_CREATOR_OBJECT_NAME); +// Assert.AreEqual(2, daapc.Order); + } + + [Test] + public void Registered() + { + Assert.IsNotNull(NamespaceParserRegistry.GetParser("http://www.springframework.net/tx")); + Assert.IsTrue(ctx.ContainsObjectDefinition(AopNamespaceUtils.AUTO_PROXY_CREATOR_OBJECT_NAME)); + + string className = typeof(ObjectFactoryTransactionAttributeSourceAdvisor).FullName; + string targetName = className + ObjectDefinitionReaderUtils.GENERATED_OBJECT_NAME_SEPARATOR + "0"; + + Assert.IsTrue(ctx.ContainsObjectDefinition(targetName)); + } + + [Test] + public void InvokeTransactional() + { + ITestObject testObject = TestObject; + CallCountingTransactionManager ptm = ctx["transactionManager"] as CallCountingTransactionManager; + Assert.IsNotNull(ptm); + + // try with transactional + Assert.AreEqual(0, ptm.begun, "Should not have started any transactions"); + testObject.GetDescription(); + Assert.AreEqual(1, ptm.begun, "Should have 1 started transaction"); + Assert.AreEqual(1, ptm.commits, "Should have 1 committed transaction"); + + // try with non-transaction + int i = testObject.Age; + Assert.IsNotNull(i); + Assert.AreEqual(1, ptm.begun, "Should not have started another transaction"); + + // try with exceptional + try + { + testObject.Exceptional(new ArgumentNullException()); + Assert.Fail("Should not get here"); + } + catch (Exception) + { + Assert.AreEqual(2, ptm.begun, "Should have another started transaction"); + Assert.AreEqual(1, ptm.rollbacks, "Should have 1 rolled back transaction"); + } + } + + private ITestObject TestObject + { + get + { + return ctx["testObject"] as + ITestObject; + } + } + + [Test] + public void RollbackRules() + { + TransactionInterceptor txInterceptor = ctx.GetObject("txRollbackAdvice") as TransactionInterceptor; + Assert.IsNotNull(txInterceptor); + + MethodInfo getDescriptionMethod = typeof(ITestObject).GetMethod("GetDescription"); + MethodInfo exceptionalMethod = typeof(ITestObject).GetMethod("Exceptional"); + ITransactionAttributeSource txAttrSource = txInterceptor.TransactionAttributeSource; + ITransactionAttribute txAttr = txAttrSource.ReturnTransactionAttribute(getDescriptionMethod, typeof(ITestObject)); + Assert.IsTrue(txAttr.RollbackOn(new System.ApplicationException())); + + txAttr = txAttrSource.ReturnTransactionAttribute(exceptionalMethod, typeof(ITestObject)); + Assert.IsFalse(txAttr.RollbackOn(new System.ArithmeticException())); + } } diff --git a/test/Spring/Spring.Data.Tests/Transaction/Config/TxNamespaceParserTests.xml b/test/Spring/Spring.Data.Tests/Transaction/Config/TxNamespaceParserTests.xml index 78bda4d5..4730f558 100644 --- a/test/Spring/Spring.Data.Tests/Transaction/Config/TxNamespaceParserTests.xml +++ b/test/Spring/Spring.Data.Tests/Transaction/Config/TxNamespaceParserTests.xml @@ -1,43 +1,43 @@ - - - - - - - - - - + + + - - - - - - - - - - + + + + + + + + + + + + + + + + + - + - + - + - + - + diff --git a/test/Spring/Spring.Data.Tests/Transaction/Config/TxNamespaceParserTests_TxAttributeDriven.xml b/test/Spring/Spring.Data.Tests/Transaction/Config/TxNamespaceParserTests_TxAttributeDriven.xml index 90123b20..59cb0a9b 100644 --- a/test/Spring/Spring.Data.Tests/Transaction/Config/TxNamespaceParserTests_TxAttributeDriven.xml +++ b/test/Spring/Spring.Data.Tests/Transaction/Config/TxNamespaceParserTests_TxAttributeDriven.xml @@ -1,4 +1,4 @@  - + diff --git a/test/Spring/Spring.Data.Tests/Transaction/HeuristicCompletionExceptionTests.cs b/test/Spring/Spring.Data.Tests/Transaction/HeuristicCompletionExceptionTests.cs index f5679202..1487bbaa 100644 --- a/test/Spring/Spring.Data.Tests/Transaction/HeuristicCompletionExceptionTests.cs +++ b/test/Spring/Spring.Data.Tests/Transaction/HeuristicCompletionExceptionTests.cs @@ -1,33 +1,35 @@ using NUnit.Framework; -namespace Spring.Transaction +namespace Spring.Transaction; + +[TestFixture] +public class HeuristicCompletionExceptionTests { - [TestFixture] - public class HeuristicCompletionExceptionTests - { - [Test] - public void TransactionOutcomeStateGetter() - { - HeuristicCompletionException ex = new HeuristicCompletionException( TransactionOutcomeState.Unknown, new Exception() ); - Assert.IsTrue( TransactionOutcomeState.Unknown == ex.OutcomeState ); - } - [Test] - public void TransactionOutcomeStateGetterCommittted() - { - HeuristicCompletionException ex = new HeuristicCompletionException( TransactionOutcomeState.Committed, new Exception() ); - Assert.IsTrue( TransactionOutcomeState.Committed == ex.OutcomeState ); - } - [Test] - public void TransactionOutcomeStateGetterMixed() - { - HeuristicCompletionException ex = new HeuristicCompletionException( TransactionOutcomeState.Mixed, new Exception() ); - Assert.IsTrue( TransactionOutcomeState.Mixed == ex.OutcomeState ); - } - [Test] - public void TransactionOutcomeStateGetterRolledback() - { - HeuristicCompletionException ex = new HeuristicCompletionException( TransactionOutcomeState.Rolledback, new Exception() ); - Assert.IsTrue( TransactionOutcomeState.Rolledback == ex.OutcomeState ); - } - } + [Test] + public void TransactionOutcomeStateGetter() + { + HeuristicCompletionException ex = new HeuristicCompletionException(TransactionOutcomeState.Unknown, new Exception()); + Assert.IsTrue(TransactionOutcomeState.Unknown == ex.OutcomeState); + } + + [Test] + public void TransactionOutcomeStateGetterCommittted() + { + HeuristicCompletionException ex = new HeuristicCompletionException(TransactionOutcomeState.Committed, new Exception()); + Assert.IsTrue(TransactionOutcomeState.Committed == ex.OutcomeState); + } + + [Test] + public void TransactionOutcomeStateGetterMixed() + { + HeuristicCompletionException ex = new HeuristicCompletionException(TransactionOutcomeState.Mixed, new Exception()); + Assert.IsTrue(TransactionOutcomeState.Mixed == ex.OutcomeState); + } + + [Test] + public void TransactionOutcomeStateGetterRolledback() + { + HeuristicCompletionException ex = new HeuristicCompletionException(TransactionOutcomeState.Rolledback, new Exception()); + Assert.IsTrue(TransactionOutcomeState.Rolledback == ex.OutcomeState); + } } diff --git a/test/Spring/Spring.Data.Tests/Transaction/Interceptor/AbstractTransactionAspectTests.cs b/test/Spring/Spring.Data.Tests/Transaction/Interceptor/AbstractTransactionAspectTests.cs index 51d9cdb0..3b52eb6a 100644 --- a/test/Spring/Spring.Data.Tests/Transaction/Interceptor/AbstractTransactionAspectTests.cs +++ b/test/Spring/Spring.Data.Tests/Transaction/Interceptor/AbstractTransactionAspectTests.cs @@ -19,189 +19,182 @@ #endregion using System.Reflection; - using FakeItEasy; - using NUnit.Framework; - using Spring.Data; using Spring.Objects; -namespace Spring.Transaction.Interceptor +namespace Spring.Transaction.Interceptor; + +/// +/// Mock object based tests for transaction aspects. +/// +/// Mark Pollack +[TestFixture] +public abstract class AbstractTransactionAspectTests { - /// - /// Mock object based tests for transaction aspects. - /// - /// Mark Pollack - [TestFixture] - public abstract class AbstractTransactionAspectTests + [Test] + public void CopyAttributes() { - [Test] - public void CopyAttributes() - { - IPlatformTransactionManager ptm = A.Fake(); - AttributesTransactionAttributeSource tas = new AttributesTransactionAttributeSource(); - TestObjectMgr to = new TestObjectMgr(); - ITestObjectMgr ito = (ITestObjectMgr) Advised(to, ptm, tas); + IPlatformTransactionManager ptm = A.Fake(); + AttributesTransactionAttributeSource tas = new AttributesTransactionAttributeSource(); + TestObjectMgr to = new TestObjectMgr(); + ITestObjectMgr ito = (ITestObjectMgr) Advised(to, ptm, tas); - ito.DeleteTwoTestObjects("foo", "bar"); + ito.DeleteTwoTestObjects("foo", "bar"); + } + + [Test] + public void CannotCommitTransaction() + { + ITransactionAttribute txatt = new DefaultTransactionAttribute(); + MethodInfo m = typeof(ITestObject).GetMethod("GetDescription"); + MethodMapTransactionAttributeSource tas = new MethodMapTransactionAttributeSource(); + tas.AddTransactionalMethod(m, txatt); + + IPlatformTransactionManager ptm = A.Fake(); + ITransactionStatus status = A.Fake(); + + A.CallTo(() => ptm.GetTransaction(txatt)).Returns(status); + UnexpectedRollbackException ex = new UnexpectedRollbackException("foobar", null); + A.CallTo(() => ptm.Commit(status)).Throws(ex); + + TestObject to = new TestObject(); + ITestObject ito = (ITestObject) Advised(to, ptm, tas); + + try + { + ito.GetDescription(); + Assert.Fail("Shouldn't have succeeded"); + } + catch (UnexpectedRollbackException thrown) + { + Assert.IsTrue(thrown == ex); + } + } + + [Test] + public void ProgrammaticRollback() + { + ITransactionAttribute txatt = new DefaultTransactionAttribute(); + MethodInfo m = typeof(RollbackTestObject).GetMethod("GetDescription"); + + MethodMapTransactionAttributeSource tas = new MethodMapTransactionAttributeSource(); + tas.AddTransactionalMethod(m, txatt); + + ITransactionStatus status = A.Fake(); + + IPlatformTransactionManager ptm = A.Fake(); + + A.CallTo(() => ptm.GetTransaction(txatt)).Returns(status).Once(); + + RollbackTestObject to = new RollbackTestObject(); + + ITestObject ito = (ITestObject) Advised(to, ptm, tas); + + Assert.AreEqual("test description", ito.GetDescription()); + + A.CallTo(() => ptm.Commit(status)).MustHaveHappenedOnceExactly(); + } + + [Test] + public void RollbackOnException() + { + DoTestRollbackOnException(new Exception(), true, false); + } + + [Test] + public void NoRollbackOnException() + { + DoTestRollbackOnException(new Exception(), false, false); + } + + [Test] + public void RollbackOnExceptionWithRollbackException() + { + DoTestRollbackOnException(new Exception(), true, true); + } + + [Test] + public void NoRollbackOnExceptionWithRollbackException() + { + DoTestRollbackOnException(new Exception(), false, true); + } + + private void DoTestRollbackOnException(Exception exception, bool shouldRollback, bool rollbackException) + { + ITransactionAttribute txatt = new ConfigurableTransactionAttribute(shouldRollback); + + MethodInfo mi = typeof(ITestObject).GetMethod("Exceptional"); + + MethodMapTransactionAttributeSource tas = new MethodMapTransactionAttributeSource(); + tas.AddTransactionalMethod(mi, txatt); + ITransactionStatus status = A.Fake(); + + IPlatformTransactionManager ptm = A.Fake(); + A.CallTo(() => ptm.GetTransaction(txatt)).Returns(status); + + TransactionSystemException tex = new TransactionSystemException("system exception"); + if (rollbackException) + { + A.CallTo(() => ptm.Rollback(A._)).Throws(tex); } - [Test] - public void CannotCommitTransaction() + TestObject to = new TestObject(); + ITestObject ito = (ITestObject) Advised(to, ptm, tas); + + try { - ITransactionAttribute txatt = new DefaultTransactionAttribute(); - MethodInfo m = typeof(ITestObject).GetMethod("GetDescription"); - MethodMapTransactionAttributeSource tas = new MethodMapTransactionAttributeSource(); - tas.AddTransactionalMethod(m, txatt); - - IPlatformTransactionManager ptm = A.Fake(); - ITransactionStatus status = A.Fake(); - - A.CallTo(() => ptm.GetTransaction(txatt)).Returns(status); - UnexpectedRollbackException ex = new UnexpectedRollbackException("foobar", null); - A.CallTo(() => ptm.Commit(status)).Throws(ex); - - TestObject to = new TestObject(); - ITestObject ito = (ITestObject) Advised(to, ptm, tas); - - try + ito.Exceptional(exception); + Assert.Fail("Should have thrown exception"); + } + catch (Exception e) + { + if (rollbackException && shouldRollback) { - ito.GetDescription(); - Assert.Fail("Shouldn't have succeeded"); - } - catch (UnexpectedRollbackException thrown) - { - Assert.IsTrue(thrown == ex); - } - } - - - [Test] - public void ProgrammaticRollback() - { - ITransactionAttribute txatt = new DefaultTransactionAttribute(); - MethodInfo m = typeof(RollbackTestObject).GetMethod("GetDescription"); - - MethodMapTransactionAttributeSource tas = new MethodMapTransactionAttributeSource(); - tas.AddTransactionalMethod(m, txatt); - - ITransactionStatus status = A.Fake(); - - IPlatformTransactionManager ptm = A.Fake(); - - A.CallTo(() => ptm.GetTransaction(txatt)).Returns(status).Once(); - - RollbackTestObject to = new RollbackTestObject(); - - ITestObject ito = (ITestObject) Advised(to, ptm, tas); - - Assert.AreEqual("test description", ito.GetDescription()); - - A.CallTo(() => ptm.Commit(status)).MustHaveHappenedOnceExactly(); - } - - [Test] - public void RollbackOnException() - { - DoTestRollbackOnException(new Exception(), true, false); - } - - [Test] - public void NoRollbackOnException() - { - DoTestRollbackOnException(new Exception(), false, false); - } - - [Test] - public void RollbackOnExceptionWithRollbackException() - { - DoTestRollbackOnException(new Exception(), true, true); - } - - [Test] - public void NoRollbackOnExceptionWithRollbackException() - { - DoTestRollbackOnException(new Exception(), false, true); - } - - private void DoTestRollbackOnException(Exception exception, bool shouldRollback, bool rollbackException) - { - ITransactionAttribute txatt = new ConfigurableTransactionAttribute(shouldRollback); - - - MethodInfo mi = typeof(ITestObject).GetMethod("Exceptional"); - - MethodMapTransactionAttributeSource tas = new MethodMapTransactionAttributeSource(); - tas.AddTransactionalMethod(mi, txatt); - ITransactionStatus status = A.Fake(); - - IPlatformTransactionManager ptm = A.Fake(); - A.CallTo(() => ptm.GetTransaction(txatt)).Returns(status); - - - TransactionSystemException tex = new TransactionSystemException("system exception"); - if (rollbackException) - { - A.CallTo(() => ptm.Rollback(A._)).Throws(tex); - } - - TestObject to = new TestObject(); - ITestObject ito = (ITestObject) Advised(to, ptm, tas); - - try - { - ito.Exceptional(exception); - Assert.Fail("Should have thrown exception"); - } - catch (Exception e) - { - if (rollbackException && shouldRollback) - { - Assert.AreEqual(tex, e); - } - else - { - Assert.AreEqual(exception, e); - } - } - - if (shouldRollback) - { - A.CallTo(() => ptm.Rollback(status)).MustHaveHappenedOnceExactly(); + Assert.AreEqual(tex, e); } else { - A.CallTo(() => ptm.Commit(status)).MustHaveHappenedOnceExactly(); + Assert.AreEqual(exception, e); } } - protected abstract object Advised(object target, IPlatformTransactionManager ptm, - ITransactionAttributeSource tas); - } - - internal class RollbackTestObject : TestObject - { - public override string GetDescription() + if (shouldRollback) { - ITransactionStatus txStatus = TransactionInterceptor.CurrentTransactionStatus; - txStatus.SetRollbackOnly(); - return "test description"; + A.CallTo(() => ptm.Rollback(status)).MustHaveHappenedOnceExactly(); + } + else + { + A.CallTo(() => ptm.Commit(status)).MustHaveHappenedOnceExactly(); } } - internal class ConfigurableTransactionAttribute : DefaultTransactionAttribute + protected abstract object Advised(object target, IPlatformTransactionManager ptm, + ITransactionAttributeSource tas); +} + +internal class RollbackTestObject : TestObject +{ + public override string GetDescription() { - private bool shouldRollback; - - public ConfigurableTransactionAttribute(bool shouldRollback) - { - this.shouldRollback = shouldRollback; - } - - public override bool RollbackOn(Exception exception) - { - return shouldRollback; - } + ITransactionStatus txStatus = TransactionInterceptor.CurrentTransactionStatus; + txStatus.SetRollbackOnly(); + return "test description"; + } +} + +internal class ConfigurableTransactionAttribute : DefaultTransactionAttribute +{ + private bool shouldRollback; + + public ConfigurableTransactionAttribute(bool shouldRollback) + { + this.shouldRollback = shouldRollback; + } + + public override bool RollbackOn(Exception exception) + { + return shouldRollback; } } diff --git a/test/Spring/Spring.Data.Tests/Transaction/Interceptor/DefaultTransactionAttributeTests.cs b/test/Spring/Spring.Data.Tests/Transaction/Interceptor/DefaultTransactionAttributeTests.cs index 4ce8fd78..fdc5bd51 100644 --- a/test/Spring/Spring.Data.Tests/Transaction/Interceptor/DefaultTransactionAttributeTests.cs +++ b/test/Spring/Spring.Data.Tests/Transaction/Interceptor/DefaultTransactionAttributeTests.cs @@ -1,23 +1,23 @@ using NUnit.Framework; -namespace Spring.Transaction.Interceptor +namespace Spring.Transaction.Interceptor; + +[TestFixture] +public class DefaultTransactionAttributeTests { - [TestFixture] - public class DefaultTransactionAttributeTests - { - [Test] - public void RollbackOnTests() - { - DefaultTransactionAttribute dta = new DefaultTransactionAttribute(); - Assert.IsTrue( dta.RollbackOn( new SystemException())); - //mlp 3/17 changed rollback to rollback on all exceptions. - Assert.IsTrue( dta.RollbackOn( new TransactionSystemException())); - } - [Test] - public void ToStringTests() - { - DefaultTransactionAttribute dta = new DefaultTransactionAttribute(); - Assert.AreEqual( "PROPAGATION_Required,ISOLATION_ReadCommitted,-System.Exception", dta.ToString()); - } - } + [Test] + public void RollbackOnTests() + { + DefaultTransactionAttribute dta = new DefaultTransactionAttribute(); + Assert.IsTrue(dta.RollbackOn(new SystemException())); + //mlp 3/17 changed rollback to rollback on all exceptions. + Assert.IsTrue(dta.RollbackOn(new TransactionSystemException())); + } + + [Test] + public void ToStringTests() + { + DefaultTransactionAttribute dta = new DefaultTransactionAttribute(); + Assert.AreEqual("PROPAGATION_Required,ISOLATION_ReadCommitted,-System.Exception", dta.ToString()); + } } diff --git a/test/Spring/Spring.Data.Tests/Transaction/Interceptor/MatchAlwaysTransactionAttributeSourceTests.cs b/test/Spring/Spring.Data.Tests/Transaction/Interceptor/MatchAlwaysTransactionAttributeSourceTests.cs index c4748f3a..7e988de7 100644 --- a/test/Spring/Spring.Data.Tests/Transaction/Interceptor/MatchAlwaysTransactionAttributeSourceTests.cs +++ b/test/Spring/Spring.Data.Tests/Transaction/Interceptor/MatchAlwaysTransactionAttributeSourceTests.cs @@ -4,42 +4,40 @@ using Spring.Context; using Spring.Context.Support; using Spring.Core.TypeResolution; -namespace Spring.Transaction.Interceptor +namespace Spring.Transaction.Interceptor; + +/// +/// Test MatchAlwaysTransactionAttributeSourceTests +/// +/// Mark Pollack +[TestFixture] +public class MatchAlwaysTransactionAttributeSourceTests { - /// - /// Test MatchAlwaysTransactionAttributeSourceTests - /// - /// Mark Pollack - [TestFixture] - public class MatchAlwaysTransactionAttributeSourceTests + [Test] + public void GetTransactionAttribute() { - [Test] - public void GetTransactionAttribute() - { - MatchAlwaysTransactionAttributeSource tas = new MatchAlwaysTransactionAttributeSource(); - ITransactionAttribute ta = tas.ReturnTransactionAttribute(typeof (Object).GetMethod("GetHashCode"), null); - Assert.IsNotNull(ta); - Assert.IsTrue(TransactionPropagation.Required == ta.PropagationBehavior); - tas.TransactionAttribute = new DefaultTransactionAttribute(TransactionPropagation.Supports); - ta = - tas.ReturnTransactionAttribute(typeof (DataException).GetType().GetMethod("GetHashCode"), - typeof (DataException)); - Assert.IsNotNull(ta); - Assert.IsTrue(TransactionPropagation.Supports == ta.PropagationBehavior); - } + MatchAlwaysTransactionAttributeSource tas = new MatchAlwaysTransactionAttributeSource(); + ITransactionAttribute ta = tas.ReturnTransactionAttribute(typeof(Object).GetMethod("GetHashCode"), null); + Assert.IsNotNull(ta); + Assert.IsTrue(TransactionPropagation.Required == ta.PropagationBehavior); + tas.TransactionAttribute = new DefaultTransactionAttribute(TransactionPropagation.Supports); + ta = + tas.ReturnTransactionAttribute(typeof(DataException).GetType().GetMethod("GetHashCode"), + typeof(DataException)); + Assert.IsNotNull(ta); + Assert.IsTrue(TransactionPropagation.Supports == ta.PropagationBehavior); + } - - [Test] - public void CanConfigureInAppContext() - { - TypeRegistry.RegisterType("TransactionPropagation", typeof(TransactionPropagation)); - IApplicationContext ctx = - new XmlApplicationContext( - "assembly://Spring.Data.Tests/Spring.Transaction.Interceptor/MatchAlwaysTransactionAttributeSourceTests.xml"); - MatchAlwaysTransactionAttributeSource tas = - (MatchAlwaysTransactionAttributeSource) ctx.GetObject("MatchAlwaysTransactionAttributeSource"); - Assert.AreEqual(TransactionPropagation.RequiresNew, - tas.ReturnTransactionAttribute(null, null).PropagationBehavior); - } + [Test] + public void CanConfigureInAppContext() + { + TypeRegistry.RegisterType("TransactionPropagation", typeof(TransactionPropagation)); + IApplicationContext ctx = + new XmlApplicationContext( + "assembly://Spring.Data.Tests/Spring.Transaction.Interceptor/MatchAlwaysTransactionAttributeSourceTests.xml"); + MatchAlwaysTransactionAttributeSource tas = + (MatchAlwaysTransactionAttributeSource) ctx.GetObject("MatchAlwaysTransactionAttributeSource"); + Assert.AreEqual(TransactionPropagation.RequiresNew, + tas.ReturnTransactionAttribute(null, null).PropagationBehavior); } } diff --git a/test/Spring/Spring.Data.Tests/Transaction/Interceptor/MatchAlwaysTransactionAttributeSourceTests.xml b/test/Spring/Spring.Data.Tests/Transaction/Interceptor/MatchAlwaysTransactionAttributeSourceTests.xml index c1df9f7b..bc632b28 100644 --- a/test/Spring/Spring.Data.Tests/Transaction/Interceptor/MatchAlwaysTransactionAttributeSourceTests.xml +++ b/test/Spring/Spring.Data.Tests/Transaction/Interceptor/MatchAlwaysTransactionAttributeSourceTests.xml @@ -1,9 +1,9 @@  - + - - - + + + diff --git a/test/Spring/Spring.Data.Tests/Transaction/Interceptor/NoRollbackRuleAttributeTests.cs b/test/Spring/Spring.Data.Tests/Transaction/Interceptor/NoRollbackRuleAttributeTests.cs index 4b6284b4..a480bd83 100644 --- a/test/Spring/Spring.Data.Tests/Transaction/Interceptor/NoRollbackRuleAttributeTests.cs +++ b/test/Spring/Spring.Data.Tests/Transaction/Interceptor/NoRollbackRuleAttributeTests.cs @@ -2,53 +2,52 @@ using System.Data; using System.Text; using NUnit.Framework; -namespace Spring.Transaction.Interceptor +namespace Spring.Transaction.Interceptor; + +[TestFixture] +public class NoNoRollbackRuleAttributeTests { - [TestFixture] - public class NoNoRollbackRuleAttributeTests - { - [Test] - public void FoundImmediatelyWithString() - { - NoRollbackRuleAttribute rr = new NoRollbackRuleAttribute("System.Exception"); - Assert.IsTrue(rr.GetDepth(typeof(Exception)) == 0); - } + [Test] + public void FoundImmediatelyWithString() + { + NoRollbackRuleAttribute rr = new NoRollbackRuleAttribute("System.Exception"); + Assert.IsTrue(rr.GetDepth(typeof(Exception)) == 0); + } - [Test] - public void FoundImmediatelyWithClass() - { - NoRollbackRuleAttribute rr = new NoRollbackRuleAttribute(typeof(Exception)); - Assert.IsTrue(rr.GetDepth(typeof(Exception)) == 0); - } + [Test] + public void FoundImmediatelyWithClass() + { + NoRollbackRuleAttribute rr = new NoRollbackRuleAttribute(typeof(Exception)); + Assert.IsTrue(rr.GetDepth(typeof(Exception)) == 0); + } - [Test] - public void NotFound() - { - NoRollbackRuleAttribute rr = new NoRollbackRuleAttribute("System.Data.DataException"); - Assert.IsTrue(rr.GetDepth(typeof(ApplicationException)) == -1); - } + [Test] + public void NotFound() + { + NoRollbackRuleAttribute rr = new NoRollbackRuleAttribute("System.Data.DataException"); + Assert.IsTrue(rr.GetDepth(typeof(ApplicationException)) == -1); + } - [Test] - public void Ancestry() - { - NoRollbackRuleAttribute rr = new NoRollbackRuleAttribute("System.Exception"); - Assert.IsTrue(rr.GetDepth(typeof(DataException)) == 2); - } + [Test] + public void Ancestry() + { + NoRollbackRuleAttribute rr = new NoRollbackRuleAttribute("System.Exception"); + Assert.IsTrue(rr.GetDepth(typeof(DataException)) == 2); + } - [Test] - public void AlwaysTrue() - { - NoRollbackRuleAttribute rr = new NoRollbackRuleAttribute("System.Exception"); - Assert.IsTrue(rr.GetDepth(typeof(SystemException)) > 0); - Assert.IsTrue(rr.GetDepth(typeof(ApplicationException)) > 0); - Assert.IsTrue(rr.GetDepth(typeof(DataException)) > 0); - Assert.IsTrue(rr.GetDepth(typeof(TransactionSystemException)) > 0); - } + [Test] + public void AlwaysTrue() + { + NoRollbackRuleAttribute rr = new NoRollbackRuleAttribute("System.Exception"); + Assert.IsTrue(rr.GetDepth(typeof(SystemException)) > 0); + Assert.IsTrue(rr.GetDepth(typeof(ApplicationException)) > 0); + Assert.IsTrue(rr.GetDepth(typeof(DataException)) > 0); + Assert.IsTrue(rr.GetDepth(typeof(TransactionSystemException)) > 0); + } - [Test] - public void ConstructorArgMustBeAExceptionClass() - { - Assert.Throws(() => new NoRollbackRuleAttribute(typeof(StringBuilder))); - } - } + [Test] + public void ConstructorArgMustBeAExceptionClass() + { + Assert.Throws(() => new NoRollbackRuleAttribute(typeof(StringBuilder))); + } } diff --git a/test/Spring/Spring.Data.Tests/Transaction/Interceptor/RollbackRuleAttributeTests.cs b/test/Spring/Spring.Data.Tests/Transaction/Interceptor/RollbackRuleAttributeTests.cs index 5bd60d76..439f19af 100644 --- a/test/Spring/Spring.Data.Tests/Transaction/Interceptor/RollbackRuleAttributeTests.cs +++ b/test/Spring/Spring.Data.Tests/Transaction/Interceptor/RollbackRuleAttributeTests.cs @@ -22,72 +22,71 @@ using System.Data; using System.Text; using NUnit.Framework; -namespace Spring.Transaction.Interceptor +namespace Spring.Transaction.Interceptor; + +[TestFixture] +public class RollbackRuleAttributeTests { - [TestFixture] - public class RollbackRuleAttributeTests + [Test] + public void FoundImmediatelyWithString() { - [Test] - public void FoundImmediatelyWithString() - { - RollbackRuleAttribute rr = new RollbackRuleAttribute("System.Exception"); - Assert.IsTrue(rr.GetDepth(typeof (Exception)) == 0); - } + RollbackRuleAttribute rr = new RollbackRuleAttribute("System.Exception"); + Assert.IsTrue(rr.GetDepth(typeof(Exception)) == 0); + } - [Test] - public void FoundImmediatelyWithClass() - { - RollbackRuleAttribute rr = new RollbackRuleAttribute(typeof (Exception)); - Assert.IsTrue(rr.GetDepth(new Exception()) == 0); - } + [Test] + public void FoundImmediatelyWithClass() + { + RollbackRuleAttribute rr = new RollbackRuleAttribute(typeof(Exception)); + Assert.IsTrue(rr.GetDepth(new Exception()) == 0); + } - [Test] - public void FoundImmediatelyWithType() - { - RollbackRuleAttribute rr = new RollbackRuleAttribute(typeof (Exception)); - Assert.IsTrue(rr.GetDepth(typeof (Exception)) == 0); - } + [Test] + public void FoundImmediatelyWithType() + { + RollbackRuleAttribute rr = new RollbackRuleAttribute(typeof(Exception)); + Assert.IsTrue(rr.GetDepth(typeof(Exception)) == 0); + } - [Test] - public void NotFound() - { - RollbackRuleAttribute rr = new RollbackRuleAttribute("System.Data.DataException"); - Assert.IsTrue(rr.GetDepth(typeof (ApplicationException)) == -1); - } + [Test] + public void NotFound() + { + RollbackRuleAttribute rr = new RollbackRuleAttribute("System.Data.DataException"); + Assert.IsTrue(rr.GetDepth(typeof(ApplicationException)) == -1); + } - [Test] - public void Ancestry() - { - RollbackRuleAttribute rr = new RollbackRuleAttribute("System.Exception"); - Assert.IsTrue(rr.GetDepth(typeof (DataException)) == 2); - } + [Test] + public void Ancestry() + { + RollbackRuleAttribute rr = new RollbackRuleAttribute("System.Exception"); + Assert.IsTrue(rr.GetDepth(typeof(DataException)) == 2); + } - [Test] - public void AlwaysTrue() - { - RollbackRuleAttribute rr = new RollbackRuleAttribute("System.Exception"); - Assert.IsTrue(rr.GetDepth(typeof (SystemException)) > 0); - Assert.IsTrue(rr.GetDepth(typeof (ApplicationException)) > 0); - Assert.IsTrue(rr.GetDepth(typeof (DataException)) > 0); - Assert.IsTrue(rr.GetDepth(typeof (TransactionSystemException)) > 0); - } + [Test] + public void AlwaysTrue() + { + RollbackRuleAttribute rr = new RollbackRuleAttribute("System.Exception"); + Assert.IsTrue(rr.GetDepth(typeof(SystemException)) > 0); + Assert.IsTrue(rr.GetDepth(typeof(ApplicationException)) > 0); + Assert.IsTrue(rr.GetDepth(typeof(DataException)) > 0); + Assert.IsTrue(rr.GetDepth(typeof(TransactionSystemException)) > 0); + } - [Test] - public void ConstructorArgMustBeAExceptionClass() - { - Assert.Throws(() => new RollbackRuleAttribute(typeof(StringBuilder))); - } + [Test] + public void ConstructorArgMustBeAExceptionClass() + { + Assert.Throws(() => new RollbackRuleAttribute(typeof(StringBuilder))); + } - [Test] - public void ConstructorArgMustBeAExceptionClassWithNullThrowableType() - { - Assert.Throws(() => new RollbackRuleAttribute((Type) null)); - } + [Test] + public void ConstructorArgMustBeAExceptionClassWithNullThrowableType() + { + Assert.Throws(() => new RollbackRuleAttribute((Type) null)); + } - [Test] - public void ConstructorArgExceptionStringNameVersionWithNull() - { - Assert.Throws(() => new RollbackRuleAttribute((String) null)); - } + [Test] + public void ConstructorArgExceptionStringNameVersionWithNull() + { + Assert.Throws(() => new RollbackRuleAttribute((String) null)); } } diff --git a/test/Spring/Spring.Data.Tests/Transaction/Interceptor/RuleBasedTransactionAttributeTests.cs b/test/Spring/Spring.Data.Tests/Transaction/Interceptor/RuleBasedTransactionAttributeTests.cs index 4865c71e..602015dc 100644 --- a/test/Spring/Spring.Data.Tests/Transaction/Interceptor/RuleBasedTransactionAttributeTests.cs +++ b/test/Spring/Spring.Data.Tests/Transaction/Interceptor/RuleBasedTransactionAttributeTests.cs @@ -1,94 +1,93 @@ using System.Data; using NUnit.Framework; -namespace Spring.Transaction.Interceptor +namespace Spring.Transaction.Interceptor; + +[TestFixture] +public class RuleBasedTransactionAttributeTests { - [TestFixture] - public class RuleBasedTransactionAttributeTests - { - [Test] - public void DefaultRule() - { - var rta = new RuleBasedTransactionAttribute(); - Assert.IsTrue(rta.RollbackOn(new SystemException())); - //mlp 3/17 changed rollback to rollback on all exceptions. - Assert.IsTrue(rta.RollbackOn(new ApplicationException())); - Assert.IsTrue(rta.RollbackOn(new TransactionSystemException())); - } + [Test] + public void DefaultRule() + { + var rta = new RuleBasedTransactionAttribute(); + Assert.IsTrue(rta.RollbackOn(new SystemException())); + //mlp 3/17 changed rollback to rollback on all exceptions. + Assert.IsTrue(rta.RollbackOn(new ApplicationException())); + Assert.IsTrue(rta.RollbackOn(new TransactionSystemException())); + } - [Test] - public void RuleForRollbackOnApplicationException() - { - var list = new List(); - list.Add(new RollbackRuleAttribute("Spring.Transaction.TransactionSystemException")); - RuleBasedTransactionAttribute - rta = new RuleBasedTransactionAttribute(TransactionPropagation.Required, list); + [Test] + public void RuleForRollbackOnApplicationException() + { + var list = new List(); + list.Add(new RollbackRuleAttribute("Spring.Transaction.TransactionSystemException")); + RuleBasedTransactionAttribute + rta = new RuleBasedTransactionAttribute(TransactionPropagation.Required, list); - Assert.IsTrue(rta.RollbackOn(new SystemException())); - //mlp 3/17 changed rollback to rollback on all exceptions. - Assert.IsTrue(rta.RollbackOn(new ApplicationException())); - Assert.IsTrue((rta.RollbackOn(new TransactionSystemException()))); - } + Assert.IsTrue(rta.RollbackOn(new SystemException())); + //mlp 3/17 changed rollback to rollback on all exceptions. + Assert.IsTrue(rta.RollbackOn(new ApplicationException())); + Assert.IsTrue((rta.RollbackOn(new TransactionSystemException()))); + } - [Test] - public void RuleForCommitOnUnchecked() - { - var list = new List(); - list.Add(new NoRollbackRuleAttribute("System.SystemException")); - list.Add(new RollbackRuleAttribute("Spring.Transaction.TransactionSystemException")); + [Test] + public void RuleForCommitOnUnchecked() + { + var list = new List(); + list.Add(new NoRollbackRuleAttribute("System.SystemException")); + list.Add(new RollbackRuleAttribute("Spring.Transaction.TransactionSystemException")); - var rta = new RuleBasedTransactionAttribute(TransactionPropagation.Required, list); - Assert.IsFalse(rta.RollbackOn(new SystemException())); - Assert.IsTrue(rta.RollbackOn(new TransactionSystemException())); - } + var rta = new RuleBasedTransactionAttribute(TransactionPropagation.Required, list); + Assert.IsFalse(rta.RollbackOn(new SystemException())); + Assert.IsTrue(rta.RollbackOn(new TransactionSystemException())); + } - [Test] - public void RuleForSelectiveRollbackOnCheckedWithString() - { - IList list = new List(); - list.Add(new RollbackRuleAttribute("Spring.Transaction.TransactionSystemException")); - var rta = new RuleBasedTransactionAttribute(TransactionPropagation.Required, list); - ruleForSelectionRollbackOnChecked(rta); - } + [Test] + public void RuleForSelectiveRollbackOnCheckedWithString() + { + IList list = new List(); + list.Add(new RollbackRuleAttribute("Spring.Transaction.TransactionSystemException")); + var rta = new RuleBasedTransactionAttribute(TransactionPropagation.Required, list); + ruleForSelectionRollbackOnChecked(rta); + } - [Test] - public void RuleForSelectiveRollbackOnCheckedWithClass() - { - var list = new List(); - list.Add(new RollbackRuleAttribute(typeof(TransactionSystemException))); - var rta = new RuleBasedTransactionAttribute(TransactionPropagation.Required, list); - ruleForSelectionRollbackOnChecked(rta); - } + [Test] + public void RuleForSelectiveRollbackOnCheckedWithClass() + { + var list = new List(); + list.Add(new RollbackRuleAttribute(typeof(TransactionSystemException))); + var rta = new RuleBasedTransactionAttribute(TransactionPropagation.Required, list); + ruleForSelectionRollbackOnChecked(rta); + } - private void ruleForSelectionRollbackOnChecked(RuleBasedTransactionAttribute rta) - { - Assert.IsTrue(rta.RollbackOn(new SystemException())); - Assert.IsTrue(rta.RollbackOn(new TransactionSystemException())); - } + private void ruleForSelectionRollbackOnChecked(RuleBasedTransactionAttribute rta) + { + Assert.IsTrue(rta.RollbackOn(new SystemException())); + Assert.IsTrue(rta.RollbackOn(new TransactionSystemException())); + } - [Test] - public void RuleForCommitOnSubclassOfChecked() - { - var list = new List(); - list.Add(new RollbackRuleAttribute("System.Data.DataException")); - list.Add(new NoRollbackRuleAttribute("Spring.Transaction.TransactionSystemException")); - var rta = new RuleBasedTransactionAttribute(TransactionPropagation.Required, list); + [Test] + public void RuleForCommitOnSubclassOfChecked() + { + var list = new List(); + list.Add(new RollbackRuleAttribute("System.Data.DataException")); + list.Add(new NoRollbackRuleAttribute("Spring.Transaction.TransactionSystemException")); + var rta = new RuleBasedTransactionAttribute(TransactionPropagation.Required, list); - Assert.IsTrue(rta.RollbackOn(new SystemException())); - Assert.IsFalse(rta.RollbackOn(new TransactionSystemException())); - } + Assert.IsTrue(rta.RollbackOn(new SystemException())); + Assert.IsFalse(rta.RollbackOn(new TransactionSystemException())); + } - [Test] - public void RollbackNever() - { - var list = new List(); - list.Add(new NoRollbackRuleAttribute("System.Exception")); - var rta = new RuleBasedTransactionAttribute(TransactionPropagation.Required, list); + [Test] + public void RollbackNever() + { + var list = new List(); + list.Add(new NoRollbackRuleAttribute("System.Exception")); + var rta = new RuleBasedTransactionAttribute(TransactionPropagation.Required, list); - Assert.IsFalse(rta.RollbackOn(new SystemException())); - Assert.IsFalse(rta.RollbackOn(new DataException())); - Assert.IsFalse(rta.RollbackOn(new ApplicationException())); - Assert.IsFalse(rta.RollbackOn(new TransactionSystemException())); - } - } + Assert.IsFalse(rta.RollbackOn(new SystemException())); + Assert.IsFalse(rta.RollbackOn(new DataException())); + Assert.IsFalse(rta.RollbackOn(new ApplicationException())); + Assert.IsFalse(rta.RollbackOn(new TransactionSystemException())); + } } diff --git a/test/Spring/Spring.Data.Tests/Transaction/Interceptor/TransactionAttributeEditorTests.cs b/test/Spring/Spring.Data.Tests/Transaction/Interceptor/TransactionAttributeEditorTests.cs index 0e4b6b60..92ceca5e 100644 --- a/test/Spring/Spring.Data.Tests/Transaction/Interceptor/TransactionAttributeEditorTests.cs +++ b/test/Spring/Spring.Data.Tests/Transaction/Interceptor/TransactionAttributeEditorTests.cs @@ -1,156 +1,155 @@ using System.Data; using NUnit.Framework; -namespace Spring.Transaction.Interceptor +namespace Spring.Transaction.Interceptor; + +[TestFixture] +public class TransactionAttributeEditorTests { - [TestFixture] - public class TransactionAttributeEditorTests - { - [Test] - public void NullTest() - { - TransactionAttributeEditor editor = new TransactionAttributeEditor( ); - editor.SetAsText( null ); - ITransactionAttribute ta = editor.Value; - Assert.IsNull( ta ); - } + [Test] + public void NullTest() + { + TransactionAttributeEditor editor = new TransactionAttributeEditor(); + editor.SetAsText(null); + ITransactionAttribute ta = editor.Value; + Assert.IsNull(ta); + } - [Test] - public void EmptyStringTest() - { - TransactionAttributeEditor editor = new TransactionAttributeEditor( ); - editor.SetAsText( String.Empty ); - ITransactionAttribute ta = editor.Value; - Assert.IsNull( ta ); - } + [Test] + public void EmptyStringTest() + { + TransactionAttributeEditor editor = new TransactionAttributeEditor(); + editor.SetAsText(String.Empty); + ITransactionAttribute ta = editor.Value; + Assert.IsNull(ta); + } - [Test] - public void ValidPropagationCodeOnly() - { - TransactionAttributeEditor editor = new TransactionAttributeEditor( ); - editor.SetAsText( "PROPAGATION_REQUIRED" ); - ITransactionAttribute ta = editor.Value; - Assert.IsTrue( ta != null ); - Assert.IsTrue( ta.PropagationBehavior == TransactionPropagation.Required ); - Assert.IsTrue( ta.TransactionIsolationLevel == IsolationLevel.ReadCommitted ); - Assert.IsFalse( ta.ReadOnly ); - } + [Test] + public void ValidPropagationCodeOnly() + { + TransactionAttributeEditor editor = new TransactionAttributeEditor(); + editor.SetAsText("PROPAGATION_REQUIRED"); + ITransactionAttribute ta = editor.Value; + Assert.IsTrue(ta != null); + Assert.IsTrue(ta.PropagationBehavior == TransactionPropagation.Required); + Assert.IsTrue(ta.TransactionIsolationLevel == IsolationLevel.ReadCommitted); + Assert.IsFalse(ta.ReadOnly); + } - [Test] - public void InvalidPropagationCodeOnly() - { - TransactionAttributeEditor editor = new TransactionAttributeEditor( ); - Assert.Throws(() => editor.SetAsText( "INVALIDPROPAGATIONCODE" )); - } + [Test] + public void InvalidPropagationCodeOnly() + { + TransactionAttributeEditor editor = new TransactionAttributeEditor(); + Assert.Throws(() => editor.SetAsText("INVALIDPROPAGATIONCODE")); + } - [Test] - public void ValidPropagationCodeAndIsolationCode() - { - TransactionAttributeEditor editor = new TransactionAttributeEditor( ); - editor.SetAsText( "PROPAGATION_REQUIRED, ISOLATION_READUNCOMMITTED" ); - ITransactionAttribute ta = editor.Value; - Assert.IsTrue( ta != null ); - Assert.IsTrue( ta.PropagationBehavior == TransactionPropagation.Required ); - Assert.IsTrue( ta.TransactionIsolationLevel == IsolationLevel.ReadUncommitted ); - } + [Test] + public void ValidPropagationCodeAndIsolationCode() + { + TransactionAttributeEditor editor = new TransactionAttributeEditor(); + editor.SetAsText("PROPAGATION_REQUIRED, ISOLATION_READUNCOMMITTED"); + ITransactionAttribute ta = editor.Value; + Assert.IsTrue(ta != null); + Assert.IsTrue(ta.PropagationBehavior == TransactionPropagation.Required); + Assert.IsTrue(ta.TransactionIsolationLevel == IsolationLevel.ReadUncommitted); + } - [Test] - public void ValidPropagationAndIsolationCodeAndInvalidRollbackRule() - { - TransactionAttributeEditor editor = new TransactionAttributeEditor( ); - Assert.Throws(() => editor.SetAsText( "PROPAGATION_REQUIRED,ISOLATION_READUNCOMMITTED,XXX" )); - } + [Test] + public void ValidPropagationAndIsolationCodeAndInvalidRollbackRule() + { + TransactionAttributeEditor editor = new TransactionAttributeEditor(); + Assert.Throws(() => editor.SetAsText("PROPAGATION_REQUIRED,ISOLATION_READUNCOMMITTED,XXX")); + } #if !NETCOREAPP - [Test] - public void ValidPropagationCodeAndIsolationCodeAndRollbackRules1() - { - TransactionAttributeEditor editor = new TransactionAttributeEditor( ); - editor.SetAsText( "PROPAGATION_MANDATORY,ISOLATION_REPEATABLEREAD,timeout_10,-DataException,+RemotingException" ); - ITransactionAttribute ta = editor.Value; - Assert.IsNotNull( ta ); - Assert.IsTrue( ta.PropagationBehavior == TransactionPropagation.Mandatory ); - Assert.IsTrue( ta.TransactionIsolationLevel == IsolationLevel.RepeatableRead ); - Assert.IsTrue( ta.TransactionTimeout == 10 ); - Assert.IsFalse( ta.ReadOnly ); - Assert.IsTrue( ta.RollbackOn(new SystemException( ) ) ); - // Check for our bizarre customized rollback rules - Assert.IsTrue( ta.RollbackOn(new DataException( ) ) ); - Assert.IsTrue( !ta.RollbackOn(new System.Runtime.Remoting.RemotingException( ) ) ); - } + [Test] + public void ValidPropagationCodeAndIsolationCodeAndRollbackRules1() + { + TransactionAttributeEditor editor = new TransactionAttributeEditor( ); + editor.SetAsText( "PROPAGATION_MANDATORY,ISOLATION_REPEATABLEREAD,timeout_10,-DataException,+RemotingException" ); + ITransactionAttribute ta = editor.Value; + Assert.IsNotNull( ta ); + Assert.IsTrue( ta.PropagationBehavior == TransactionPropagation.Mandatory ); + Assert.IsTrue( ta.TransactionIsolationLevel == IsolationLevel.RepeatableRead ); + Assert.IsTrue( ta.TransactionTimeout == 10 ); + Assert.IsFalse( ta.ReadOnly ); + Assert.IsTrue( ta.RollbackOn(new SystemException( ) ) ); + // Check for our bizarre customized rollback rules + Assert.IsTrue( ta.RollbackOn(new DataException( ) ) ); + Assert.IsTrue( !ta.RollbackOn(new System.Runtime.Remoting.RemotingException( ) ) ); + } - [Test] - public void ValidPropagationCodeAndIsolationCodeAndRollbackRules2() - { - TransactionAttributeEditor editor = new TransactionAttributeEditor( ); - editor.SetAsText( "+DataException,readOnly,ISOLATION_READCOMMITTED,-RemotingException,PROPAGATION_SUPPORTS" ); - ITransactionAttribute ta = editor.Value; - Assert.IsNotNull( ta ); - Assert.IsTrue( ta.PropagationBehavior == TransactionPropagation.Supports ); - Assert.IsTrue( ta.TransactionIsolationLevel == IsolationLevel.ReadCommitted ); - Assert.IsTrue( ta.TransactionTimeout == -1 ); - Assert.IsTrue( ta.ReadOnly ); - Assert.IsTrue( ta.RollbackOn( new SystemException( ) ) ); - // Check for our bizarre customized rollback rules - Assert.IsFalse( ta.RollbackOn(new DataException( ) ) ); - Assert.IsTrue( ta.RollbackOn(new System.Runtime.Remoting.RemotingException( ) ) ); - } + [Test] + public void ValidPropagationCodeAndIsolationCodeAndRollbackRules2() + { + TransactionAttributeEditor editor = new TransactionAttributeEditor( ); + editor.SetAsText( "+DataException,readOnly,ISOLATION_READCOMMITTED,-RemotingException,PROPAGATION_SUPPORTS" ); + ITransactionAttribute ta = editor.Value; + Assert.IsNotNull( ta ); + Assert.IsTrue( ta.PropagationBehavior == TransactionPropagation.Supports ); + Assert.IsTrue( ta.TransactionIsolationLevel == IsolationLevel.ReadCommitted ); + Assert.IsTrue( ta.TransactionTimeout == -1 ); + Assert.IsTrue( ta.ReadOnly ); + Assert.IsTrue( ta.RollbackOn( new SystemException( ) ) ); + // Check for our bizarre customized rollback rules + Assert.IsFalse( ta.RollbackOn(new DataException( ) ) ); + Assert.IsTrue( ta.RollbackOn(new System.Runtime.Remoting.RemotingException( ) ) ); + } #endif - [Test] - public void DefaultTransactionAttributeToString() - { - DefaultTransactionAttribute source = new DefaultTransactionAttribute( ); - source.PropagationBehavior = TransactionPropagation.Supports; - source.TransactionIsolationLevel = IsolationLevel.RepeatableRead; - source.TransactionTimeout = 10; - source.ReadOnly = true; + [Test] + public void DefaultTransactionAttributeToString() + { + DefaultTransactionAttribute source = new DefaultTransactionAttribute(); + source.PropagationBehavior = TransactionPropagation.Supports; + source.TransactionIsolationLevel = IsolationLevel.RepeatableRead; + source.TransactionTimeout = 10; + source.ReadOnly = true; - TransactionAttributeEditor editor = new TransactionAttributeEditor( ); - editor.SetAsText( source.ToString( ) ); - ITransactionAttribute ta = editor.Value; - Assert.AreEqual( source, ta ); - Assert.AreEqual( ta.PropagationBehavior, TransactionPropagation.Supports ); - Assert.AreEqual( ta.TransactionIsolationLevel, IsolationLevel.RepeatableRead ); - Assert.AreEqual( ta.TransactionTimeout, 10 ); - Assert.IsTrue( ta.ReadOnly ); - Assert.IsTrue( ta.RollbackOn( new SystemException( ) ) ); - //mlp 3/17 changed rollback to rollback on all exceptions. - Assert.IsTrue( ta.RollbackOn( new ApplicationException( ) ) ); + TransactionAttributeEditor editor = new TransactionAttributeEditor(); + editor.SetAsText(source.ToString()); + ITransactionAttribute ta = editor.Value; + Assert.AreEqual(source, ta); + Assert.AreEqual(ta.PropagationBehavior, TransactionPropagation.Supports); + Assert.AreEqual(ta.TransactionIsolationLevel, IsolationLevel.RepeatableRead); + Assert.AreEqual(ta.TransactionTimeout, 10); + Assert.IsTrue(ta.ReadOnly); + Assert.IsTrue(ta.RollbackOn(new SystemException())); + //mlp 3/17 changed rollback to rollback on all exceptions. + Assert.IsTrue(ta.RollbackOn(new ApplicationException())); - source.TransactionTimeout = 9; - Assert.IsFalse( ta == source ); - source.TransactionTimeout = 10; - Assert.AreEqual( ta, source ); - } + source.TransactionTimeout = 9; + Assert.IsFalse(ta == source); + source.TransactionTimeout = 10; + Assert.AreEqual(ta, source); + } - [Test] - public void RuleBasedTransactionAttributeToString() - { - RuleBasedTransactionAttribute source = new RuleBasedTransactionAttribute(); - source.PropagationBehavior = TransactionPropagation.Supports; - source.TransactionIsolationLevel = IsolationLevel.RepeatableRead; - source.TransactionTimeout = 10; - source.ReadOnly = true; - source.AddRollbackRule( new RollbackRuleAttribute("ArgumentException")); - source.AddRollbackRule( new NoRollbackRuleAttribute("IllegalTransactionStateException")); + [Test] + public void RuleBasedTransactionAttributeToString() + { + RuleBasedTransactionAttribute source = new RuleBasedTransactionAttribute(); + source.PropagationBehavior = TransactionPropagation.Supports; + source.TransactionIsolationLevel = IsolationLevel.RepeatableRead; + source.TransactionTimeout = 10; + source.ReadOnly = true; + source.AddRollbackRule(new RollbackRuleAttribute("ArgumentException")); + source.AddRollbackRule(new NoRollbackRuleAttribute("IllegalTransactionStateException")); - TransactionAttributeEditor editor = new TransactionAttributeEditor(); - editor.SetAsText( source.ToString() ); - ITransactionAttribute ta = editor.Value; - Assert.AreEqual( source, ta ); - Assert.AreEqual( ta.PropagationBehavior, TransactionPropagation.Supports ); - Assert.AreEqual( ta.TransactionIsolationLevel, IsolationLevel.RepeatableRead ); - Assert.AreEqual( ta.TransactionTimeout, 10 ); - Assert.IsTrue( ta.ReadOnly ); - Assert.IsTrue(ta.RollbackOn(new ArgumentException())); - Assert.IsFalse( ta.RollbackOn(new IllegalTransactionStateException())); + TransactionAttributeEditor editor = new TransactionAttributeEditor(); + editor.SetAsText(source.ToString()); + ITransactionAttribute ta = editor.Value; + Assert.AreEqual(source, ta); + Assert.AreEqual(ta.PropagationBehavior, TransactionPropagation.Supports); + Assert.AreEqual(ta.TransactionIsolationLevel, IsolationLevel.RepeatableRead); + Assert.AreEqual(ta.TransactionTimeout, 10); + Assert.IsTrue(ta.ReadOnly); + Assert.IsTrue(ta.RollbackOn(new ArgumentException())); + Assert.IsFalse(ta.RollbackOn(new IllegalTransactionStateException())); - source.ClearRollbackRules(); - Assert.IsFalse( ta == source ); - source.AddRollbackRule( new RollbackRuleAttribute("ArgumentException")); - source.AddRollbackRule( new NoRollbackRuleAttribute("IllegalTransactionStateException")); - Assert.AreEqual( ta, source ); - } - } + source.ClearRollbackRules(); + Assert.IsFalse(ta == source); + source.AddRollbackRule(new RollbackRuleAttribute("ArgumentException")); + source.AddRollbackRule(new NoRollbackRuleAttribute("IllegalTransactionStateException")); + Assert.AreEqual(ta, source); + } } diff --git a/test/Spring/Spring.Data.Tests/Transaction/Interceptor/TransactionAttributeSourceAdvisorTests.cs b/test/Spring/Spring.Data.Tests/Transaction/Interceptor/TransactionAttributeSourceAdvisorTests.cs index 657834a8..4a41a4b5 100644 --- a/test/Spring/Spring.Data.Tests/Transaction/Interceptor/TransactionAttributeSourceAdvisorTests.cs +++ b/test/Spring/Spring.Data.Tests/Transaction/Interceptor/TransactionAttributeSourceAdvisorTests.cs @@ -2,18 +2,17 @@ using System.Collections.Specialized; using NUnit.Framework; using Spring.Util; -namespace Spring.Transaction.Interceptor +namespace Spring.Transaction.Interceptor; + +[TestFixture] +public class TransactionAttributeSourceAdvisorTests { - [TestFixture] - public class TransactionAttributeSourceAdvisorTests - { - [Test] - public void Serializability() - { - TransactionInterceptor ti = new TransactionInterceptor(); - ti.TransactionAttributes = new NameValueCollection(); - TransactionAttributeSourceAdvisor tas = new TransactionAttributeSourceAdvisor(ti); - SerializationTestUtils.SerializeAndDeserialize(tas); - } - } -} \ No newline at end of file + [Test] + public void Serializability() + { + TransactionInterceptor ti = new TransactionInterceptor(); + ti.TransactionAttributes = new NameValueCollection(); + TransactionAttributeSourceAdvisor tas = new TransactionAttributeSourceAdvisor(ti); + SerializationTestUtils.SerializeAndDeserialize(tas); + } +} diff --git a/test/Spring/Spring.Data.Tests/Transaction/Interceptor/TransactionAttributeSourceEditorTests.cs b/test/Spring/Spring.Data.Tests/Transaction/Interceptor/TransactionAttributeSourceEditorTests.cs index fa59b25b..20e6cb27 100644 --- a/test/Spring/Spring.Data.Tests/Transaction/Interceptor/TransactionAttributeSourceEditorTests.cs +++ b/test/Spring/Spring.Data.Tests/Transaction/Interceptor/TransactionAttributeSourceEditorTests.cs @@ -1,70 +1,68 @@ using System.Data; using System.Reflection; - using NUnit.Framework; -namespace Spring.Transaction.Interceptor +namespace Spring.Transaction.Interceptor; + +[TestFixture] +public class TransactionAttributeSourceEditorTests { - [TestFixture] - public class TransactionAttributeSourceEditorTests + [Test] + public void Null() { - [Test] - public void Null() - { - TransactionAttributeSourceEditor pe = new TransactionAttributeSourceEditor(); - pe.SetAsText(null); - ITransactionAttributeSource tas = pe.Value; - MethodInfo m = typeof(object).GetMethod("GetHashCode"); - Assert.IsTrue(tas.ReturnTransactionAttribute(m, null) == null); - } - - [Test] - public void Invalid() - { - TransactionAttributeSourceEditor pe = new TransactionAttributeSourceEditor(); - Assert.Throws(() => pe.SetAsText("foo=bar")); - } - - [Test] - public void MatchesSpecific() - { - TransactionAttributeSourceEditor pe = new TransactionAttributeSourceEditor(); - pe.SetAsText("System.Object.GetHashCode, Mscorlib =PROPAGATION_REQUIRED\n" + - "System.Object.Equals, Mscorlib =PROPAGATION_MANDATORY\n" + - "System.Object.*pe, Mscorlib=PROPAGATION_SUPPORTS"); - ITransactionAttributeSource tas = pe.Value; - - checkTransactionProperties(tas, typeof(object).GetMethod("GetHashCode"), TransactionPropagation.Required); - checkTransactionProperties(tas, typeof(object).GetMethod("Equals", new Type[] {typeof(object)}), TransactionPropagation.Mandatory); - checkTransactionProperties(tas, typeof(object).GetMethod("GetType"), TransactionPropagation.Supports); - checkTransactionProperties(tas, typeof(object).GetMethod("ToString")); - } - - [Test] - public void MatchesAll() - { - TransactionAttributeSourceEditor pe = new TransactionAttributeSourceEditor(); - pe.SetAsText("System.Object.*, Mscorlib=PROPAGATION_REQUIRED"); - ITransactionAttributeSource tas = pe.Value; - - checkTransactionProperties(tas, typeof(object).GetMethod("GetHashCode"), TransactionPropagation.Required); - checkTransactionProperties(tas, typeof(object).GetMethod("Equals", new Type[] {typeof(object)}), TransactionPropagation.Required); - checkTransactionProperties(tas, typeof(object).GetMethod("GetType"), TransactionPropagation.Required); - checkTransactionProperties(tas, typeof(object).GetMethod("ToString"), TransactionPropagation.Required); - } - - private void checkTransactionProperties(ITransactionAttributeSource tas, MethodInfo method) - { - ITransactionAttribute ta = tas.ReturnTransactionAttribute(method, null); - Assert.IsNull(ta); - } - - private void checkTransactionProperties(ITransactionAttributeSource tas, MethodInfo method, TransactionPropagation transactionPropagation) - { - ITransactionAttribute ta = tas.ReturnTransactionAttribute(method, null); - Assert.IsTrue(ta != null); - Assert.IsTrue(ta.TransactionIsolationLevel == IsolationLevel.ReadCommitted); - Assert.IsTrue(ta.PropagationBehavior == transactionPropagation); - } + TransactionAttributeSourceEditor pe = new TransactionAttributeSourceEditor(); + pe.SetAsText(null); + ITransactionAttributeSource tas = pe.Value; + MethodInfo m = typeof(object).GetMethod("GetHashCode"); + Assert.IsTrue(tas.ReturnTransactionAttribute(m, null) == null); } -} + + [Test] + public void Invalid() + { + TransactionAttributeSourceEditor pe = new TransactionAttributeSourceEditor(); + Assert.Throws(() => pe.SetAsText("foo=bar")); + } + + [Test] + public void MatchesSpecific() + { + TransactionAttributeSourceEditor pe = new TransactionAttributeSourceEditor(); + pe.SetAsText("System.Object.GetHashCode, Mscorlib =PROPAGATION_REQUIRED\n" + + "System.Object.Equals, Mscorlib =PROPAGATION_MANDATORY\n" + + "System.Object.*pe, Mscorlib=PROPAGATION_SUPPORTS"); + ITransactionAttributeSource tas = pe.Value; + + checkTransactionProperties(tas, typeof(object).GetMethod("GetHashCode"), TransactionPropagation.Required); + checkTransactionProperties(tas, typeof(object).GetMethod("Equals", new Type[] { typeof(object) }), TransactionPropagation.Mandatory); + checkTransactionProperties(tas, typeof(object).GetMethod("GetType"), TransactionPropagation.Supports); + checkTransactionProperties(tas, typeof(object).GetMethod("ToString")); + } + + [Test] + public void MatchesAll() + { + TransactionAttributeSourceEditor pe = new TransactionAttributeSourceEditor(); + pe.SetAsText("System.Object.*, Mscorlib=PROPAGATION_REQUIRED"); + ITransactionAttributeSource tas = pe.Value; + + checkTransactionProperties(tas, typeof(object).GetMethod("GetHashCode"), TransactionPropagation.Required); + checkTransactionProperties(tas, typeof(object).GetMethod("Equals", new Type[] { typeof(object) }), TransactionPropagation.Required); + checkTransactionProperties(tas, typeof(object).GetMethod("GetType"), TransactionPropagation.Required); + checkTransactionProperties(tas, typeof(object).GetMethod("ToString"), TransactionPropagation.Required); + } + + private void checkTransactionProperties(ITransactionAttributeSource tas, MethodInfo method) + { + ITransactionAttribute ta = tas.ReturnTransactionAttribute(method, null); + Assert.IsNull(ta); + } + + private void checkTransactionProperties(ITransactionAttributeSource tas, MethodInfo method, TransactionPropagation transactionPropagation) + { + ITransactionAttribute ta = tas.ReturnTransactionAttribute(method, null); + Assert.IsTrue(ta != null); + Assert.IsTrue(ta.TransactionIsolationLevel == IsolationLevel.ReadCommitted); + Assert.IsTrue(ta.PropagationBehavior == transactionPropagation); + } +} \ No newline at end of file diff --git a/test/Spring/Spring.Data.Tests/Transaction/Interceptor/TransactionAttributeSourceTests.cs b/test/Spring/Spring.Data.Tests/Transaction/Interceptor/TransactionAttributeSourceTests.cs index f428e382..aac95f60 100644 --- a/test/Spring/Spring.Data.Tests/Transaction/Interceptor/TransactionAttributeSourceTests.cs +++ b/test/Spring/Spring.Data.Tests/Transaction/Interceptor/TransactionAttributeSourceTests.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -26,102 +26,100 @@ using NUnit.Framework; #endregion -namespace Spring.Transaction.Interceptor +namespace Spring.Transaction.Interceptor; + +/// +/// This class contains tests for the various +/// implementations. +/// +/// Mark Pollack +[TestFixture] +public class TransactionAttributeSourceTests { - /// - /// This class contains tests for the various - /// implementations. - /// - /// Mark Pollack - [TestFixture] - public class TransactionAttributeSourceTests + [Test] + public void MethodMapTransactionAttributeSource() { - [Test] - public void MethodMapTransactionAttributeSource() - { - MethodMapTransactionAttributeSource tas = new MethodMapTransactionAttributeSource(); - IDictionary methodMap = new Hashtable(); - methodMap.Add("System.Object.GetHashCode, mscorlib", "PROPAGATION_REQUIRED"); - methodMap.Add("System.Object.ToString, mscorlib", - new DefaultTransactionAttribute(TransactionPropagation.Supports)); - tas.MethodMap = methodMap; + MethodMapTransactionAttributeSource tas = new MethodMapTransactionAttributeSource(); + IDictionary methodMap = new Hashtable(); + methodMap.Add("System.Object.GetHashCode, mscorlib", "PROPAGATION_REQUIRED"); + methodMap.Add("System.Object.ToString, mscorlib", + new DefaultTransactionAttribute(TransactionPropagation.Supports)); + tas.MethodMap = methodMap; - ITransactionAttribute ta = tas.ReturnTransactionAttribute(typeof(object).GetMethod("GetHashCode"), null); - Assert.IsNotNull(ta); - Assert.AreEqual(TransactionPropagation.Required, ta.PropagationBehavior); + ITransactionAttribute ta = tas.ReturnTransactionAttribute(typeof(object).GetMethod("GetHashCode"), null); + Assert.IsNotNull(ta); + Assert.AreEqual(TransactionPropagation.Required, ta.PropagationBehavior); - ta = tas.ReturnTransactionAttribute(typeof(object).GetMethod("ToString"), null); - Assert.IsNotNull(ta); - Assert.AreEqual(TransactionPropagation.Supports, ta.PropagationBehavior); - } - - - /// - /// Test that configuration of the IDictionary baesd map supports transaction attribute information - /// set via object (i.e. DefaultTransactionAttribute) as well as strings. - /// - [Test] - public void NameMatchTransactionAttributeSource() - { - NameMatchTransactionAttributeSource tas = new NameMatchTransactionAttributeSource(); - IDictionary methodMap = new Hashtable(); - methodMap.Add("GetHashCode", "PROPAGATION_REQUIRED"); - methodMap.Add("ToString", new DefaultTransactionAttribute(TransactionPropagation.Supports)); - tas.NameMap = methodMap; - ITransactionAttribute ta = tas.ReturnTransactionAttribute(typeof (object).GetMethod("GetHashCode"), null); - Assert.IsNotNull(ta); - Assert.AreEqual(TransactionPropagation.Required, ta.PropagationBehavior); - ta = tas.ReturnTransactionAttribute(typeof (object).GetMethod("ToString"), null); - Assert.IsNotNull(ta); - Assert.AreEqual(TransactionPropagation.Supports, ta.PropagationBehavior); - } - - [Test] - public void NameMatchTransactionAttributeSourceWithStarAtStartOfMethodName() - { - NameMatchTransactionAttributeSource tas = new NameMatchTransactionAttributeSource(); - NameValueCollection attributes = new NameValueCollection(); - attributes.Add("*ashCode", "PROPAGATION_REQUIRED"); - tas.NameProperties = attributes; - ITransactionAttribute ta = tas.ReturnTransactionAttribute(typeof (object).GetMethod("GetHashCode"), null); - Assert.IsNotNull(ta); - Assert.AreEqual(TransactionPropagation.Required, ta.PropagationBehavior); - } - - [Test] - public void NameMatchTransactionAttributeSourceWithStarAtEndOfMethodName() - { - NameMatchTransactionAttributeSource tas = new NameMatchTransactionAttributeSource(); - NameValueCollection attributes = new NameValueCollection(); - attributes.Add("GetHashCod*", "PROPAGATION_REQUIRED"); - tas.NameProperties = attributes; - ITransactionAttribute ta = tas.ReturnTransactionAttribute(typeof(object).GetMethod("GetHashCode"), null); - Assert.IsNotNull(ta); - Assert.AreEqual(TransactionPropagation.Required, ta.PropagationBehavior); - } - - [Test] - public void NameMatchTransactionAttributeSourceMostSpecificMethodNameIsDefinitelyMatched() - { - NameMatchTransactionAttributeSource tas = new NameMatchTransactionAttributeSource(); - NameValueCollection attributes = new NameValueCollection(); - attributes.Add("*", "PROPAGATION_REQUIRED"); - attributes.Add("GetHashCode", "PROPAGATION_MANDATORY"); - tas.NameProperties = attributes; - ITransactionAttribute ta = tas.ReturnTransactionAttribute(typeof(object).GetMethod("GetHashCode"), null); - Assert.IsNotNull(ta); - Assert.AreEqual(TransactionPropagation.Mandatory, ta.PropagationBehavior); - } - - [Test] - public void NameMatchTransactionAttributeSourceWithEmptyMethodName() - { - NameMatchTransactionAttributeSource tas = new NameMatchTransactionAttributeSource(); - NameValueCollection attributes = new NameValueCollection(); - attributes.Add("", "PROPAGATION_MANDATORY"); - tas.NameProperties = attributes; - ITransactionAttribute ta = tas.ReturnTransactionAttribute(typeof(object).GetMethod("GetHashCode"), null); - Assert.IsNull(ta); - } + ta = tas.ReturnTransactionAttribute(typeof(object).GetMethod("ToString"), null); + Assert.IsNotNull(ta); + Assert.AreEqual(TransactionPropagation.Supports, ta.PropagationBehavior); } -} \ No newline at end of file + + /// + /// Test that configuration of the IDictionary baesd map supports transaction attribute information + /// set via object (i.e. DefaultTransactionAttribute) as well as strings. + /// + [Test] + public void NameMatchTransactionAttributeSource() + { + NameMatchTransactionAttributeSource tas = new NameMatchTransactionAttributeSource(); + IDictionary methodMap = new Hashtable(); + methodMap.Add("GetHashCode", "PROPAGATION_REQUIRED"); + methodMap.Add("ToString", new DefaultTransactionAttribute(TransactionPropagation.Supports)); + tas.NameMap = methodMap; + ITransactionAttribute ta = tas.ReturnTransactionAttribute(typeof(object).GetMethod("GetHashCode"), null); + Assert.IsNotNull(ta); + Assert.AreEqual(TransactionPropagation.Required, ta.PropagationBehavior); + ta = tas.ReturnTransactionAttribute(typeof(object).GetMethod("ToString"), null); + Assert.IsNotNull(ta); + Assert.AreEqual(TransactionPropagation.Supports, ta.PropagationBehavior); + } + + [Test] + public void NameMatchTransactionAttributeSourceWithStarAtStartOfMethodName() + { + NameMatchTransactionAttributeSource tas = new NameMatchTransactionAttributeSource(); + NameValueCollection attributes = new NameValueCollection(); + attributes.Add("*ashCode", "PROPAGATION_REQUIRED"); + tas.NameProperties = attributes; + ITransactionAttribute ta = tas.ReturnTransactionAttribute(typeof(object).GetMethod("GetHashCode"), null); + Assert.IsNotNull(ta); + Assert.AreEqual(TransactionPropagation.Required, ta.PropagationBehavior); + } + + [Test] + public void NameMatchTransactionAttributeSourceWithStarAtEndOfMethodName() + { + NameMatchTransactionAttributeSource tas = new NameMatchTransactionAttributeSource(); + NameValueCollection attributes = new NameValueCollection(); + attributes.Add("GetHashCod*", "PROPAGATION_REQUIRED"); + tas.NameProperties = attributes; + ITransactionAttribute ta = tas.ReturnTransactionAttribute(typeof(object).GetMethod("GetHashCode"), null); + Assert.IsNotNull(ta); + Assert.AreEqual(TransactionPropagation.Required, ta.PropagationBehavior); + } + + [Test] + public void NameMatchTransactionAttributeSourceMostSpecificMethodNameIsDefinitelyMatched() + { + NameMatchTransactionAttributeSource tas = new NameMatchTransactionAttributeSource(); + NameValueCollection attributes = new NameValueCollection(); + attributes.Add("*", "PROPAGATION_REQUIRED"); + attributes.Add("GetHashCode", "PROPAGATION_MANDATORY"); + tas.NameProperties = attributes; + ITransactionAttribute ta = tas.ReturnTransactionAttribute(typeof(object).GetMethod("GetHashCode"), null); + Assert.IsNotNull(ta); + Assert.AreEqual(TransactionPropagation.Mandatory, ta.PropagationBehavior); + } + + [Test] + public void NameMatchTransactionAttributeSourceWithEmptyMethodName() + { + NameMatchTransactionAttributeSource tas = new NameMatchTransactionAttributeSource(); + NameValueCollection attributes = new NameValueCollection(); + attributes.Add("", "PROPAGATION_MANDATORY"); + tas.NameProperties = attributes; + ITransactionAttribute ta = tas.ReturnTransactionAttribute(typeof(object).GetMethod("GetHashCode"), null); + Assert.IsNull(ta); + } +} diff --git a/test/Spring/Spring.Data.Tests/Transaction/Interceptor/TransactionInterceptorTests.cs b/test/Spring/Spring.Data.Tests/Transaction/Interceptor/TransactionInterceptorTests.cs index 7dd261fc..05f83c55 100644 --- a/test/Spring/Spring.Data.Tests/Transaction/Interceptor/TransactionInterceptorTests.cs +++ b/test/Spring/Spring.Data.Tests/Transaction/Interceptor/TransactionInterceptorTests.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -25,28 +25,25 @@ using Spring.Aop.Framework; #endregion -namespace Spring.Transaction.Interceptor -{ - /// - /// This class contains mock objects tests the TransactionInterceptor - /// - /// Mark Pollack - [TestFixture] - public class TransactionInterceptorTests : AbstractTransactionAspectTests - { - +namespace Spring.Transaction.Interceptor; - protected override object Advised(object target, IPlatformTransactionManager ptm, - ITransactionAttributeSource tas) - { - TransactionInterceptor ti = new TransactionInterceptor(); - ti.TransactionManager = ptm; - Assert.AreEqual(ptm, ti.TransactionManager); - ti.TransactionAttributeSource = tas; - Assert.AreEqual(tas, ti.TransactionAttributeSource); - ProxyFactory pf = new ProxyFactory(target); - pf.AddAdvice(0, ti); - return pf.GetProxy(); - } +/// +/// This class contains mock objects tests the TransactionInterceptor +/// +/// Mark Pollack +[TestFixture] +public class TransactionInterceptorTests : AbstractTransactionAspectTests +{ + protected override object Advised(object target, IPlatformTransactionManager ptm, + ITransactionAttributeSource tas) + { + TransactionInterceptor ti = new TransactionInterceptor(); + ti.TransactionManager = ptm; + Assert.AreEqual(ptm, ti.TransactionManager); + ti.TransactionAttributeSource = tas; + Assert.AreEqual(tas, ti.TransactionAttributeSource); + ProxyFactory pf = new ProxyFactory(target); + pf.AddAdvice(0, ti); + return pf.GetProxy(); } -} \ No newline at end of file +} diff --git a/test/Spring/Spring.Data.Tests/Transaction/InvalidTimeoutExceptionTests.cs b/test/Spring/Spring.Data.Tests/Transaction/InvalidTimeoutExceptionTests.cs index a72f4b04..3dc5f05e 100644 --- a/test/Spring/Spring.Data.Tests/Transaction/InvalidTimeoutExceptionTests.cs +++ b/test/Spring/Spring.Data.Tests/Transaction/InvalidTimeoutExceptionTests.cs @@ -1,15 +1,14 @@ using NUnit.Framework; -namespace Spring.Transaction +namespace Spring.Transaction; + +[TestFixture] +public class InvalidTimeoutExceptionTests { - [TestFixture] - public class InvalidTimeoutExceptionTests - { - [Test] - public void TimeoutGetter() - { - InvalidTimeoutException ex = new InvalidTimeoutException( "bad timeout", 2000 ); - Assert.IsTrue( 2000 == ex.Timeout ); - } - } + [Test] + public void TimeoutGetter() + { + InvalidTimeoutException ex = new InvalidTimeoutException("bad timeout", 2000); + Assert.IsTrue(2000 == ex.Timeout); + } } diff --git a/test/Spring/Spring.Data.Tests/Transaction/Support/AbstractPlatformTransactionManagerTests.cs b/test/Spring/Spring.Data.Tests/Transaction/Support/AbstractPlatformTransactionManagerTests.cs index 3ebe68ac..9c26c4e5 100644 --- a/test/Spring/Spring.Data.Tests/Transaction/Support/AbstractPlatformTransactionManagerTests.cs +++ b/test/Spring/Spring.Data.Tests/Transaction/Support/AbstractPlatformTransactionManagerTests.cs @@ -1,238 +1,236 @@ using FakeItEasy; - using NUnit.Framework; -namespace Spring.Transaction.Support +namespace Spring.Transaction.Support; + +[TestFixture] +public class AbstractPlatformTransactionManagerTests { - [TestFixture] - public class AbstractPlatformTransactionManagerTests + private MockTxnPlatformMgrAbstract _mockTxnMgr; + + [SetUp] + public void Init() { - private MockTxnPlatformMgrAbstract _mockTxnMgr; - - [SetUp] - public void Init() + _mockTxnMgr = new MockTxnPlatformMgrAbstract(); + _mockTxnMgr.TransactionSynchronization = TransactionSynchronizationState.Always; + if (TransactionSynchronizationManager.SynchronizationActive) { - _mockTxnMgr = new MockTxnPlatformMgrAbstract(); - _mockTxnMgr.TransactionSynchronization = TransactionSynchronizationState.Always; - if (TransactionSynchronizationManager.SynchronizationActive) - { - TransactionSynchronizationManager.ClearSynchronization(); - } - } - - [TearDown] - public void Destroy() - { - _mockTxnMgr = null; - if (TransactionSynchronizationManager.SynchronizationActive) - { - TransactionSynchronizationManager.Clear(); - } - } - - [Test] - public void VanillaProperties() - { - Assert.AreEqual(TransactionSynchronizationState.Always, _mockTxnMgr.TransactionSynchronization); - Assert.IsTrue(!_mockTxnMgr.NestedTransactionsAllowed); - Assert.IsTrue(!_mockTxnMgr.RollbackOnCommitFailure); - - _mockTxnMgr.NestedTransactionsAllowed = true; - _mockTxnMgr.RollbackOnCommitFailure = true; - _mockTxnMgr.TransactionSynchronization = TransactionSynchronizationState.OnActualTransaction; - - Assert.AreEqual(TransactionSynchronizationState.OnActualTransaction, _mockTxnMgr.TransactionSynchronization); - Assert.IsTrue(_mockTxnMgr.NestedTransactionsAllowed); - Assert.IsTrue(_mockTxnMgr.RollbackOnCommitFailure); - } - - [Test] - public void DefinitionInvalidTimeoutException() - { - MockTxnDefinition def = new MockTxnDefinition(); - def.TransactionTimeout = -1000; - Assert.Throws(() => _mockTxnMgr.GetTransaction(def), "Invalid transaction timeout"); - } - - [Test] - public void DefinitionInvalidPropagationState() - { - MockTxnDefinition def = new MockTxnDefinition(); - def.PropagationBehavior = TransactionPropagation.Mandatory; - Assert.Throws(() => _mockTxnMgr.GetTransaction(def), "Transaction propagation 'mandatory' but no existing transaction found"); - } - - [Test] - public void NeverPropagateState() - { - MockTxnDefinition def = new MockTxnDefinition(); - def.PropagationBehavior = TransactionPropagation.Never; - SetGeneralGetTransactionExpectations(); - - Assert.Throws(() => _mockTxnMgr.GetTransaction(def), "Transaction propagation 'never' but existing transaction found."); - } - - [Test] - public void NoNestedTransactionsAllowed() - { - MockTxnDefinition def = new MockTxnDefinition(); - def.PropagationBehavior = TransactionPropagation.Nested; - SetGeneralGetTransactionExpectations(); - - Assert.Throws(() => _mockTxnMgr.GetTransaction(def), "Transaction manager does not allow nested transactions by default - specify 'NestedTransactionsAllowed' property with value 'true'"); - } - - [Test] - public void TransactionSuspendedSuccessfully() - { - MockTxnDefinition def = new MockTxnDefinition(); - def.PropagationBehavior = TransactionPropagation.NotSupported; - def.ReadOnly = false; - SetGeneralGetTransactionExpectations(); - - DefaultTransactionStatus status = (DefaultTransactionStatus) _mockTxnMgr.GetTransaction(def); - Assert.IsNull(status.Transaction); - Assert.IsTrue(!status.IsNewTransaction); - Assert.IsTrue(status.NewSynchronization); - Assert.IsTrue(!status.ReadOnly); - Assert.IsNotNull(status.SuspendedResources); - AssertVanillaGetTransactionExpectations(); - } - - [Test] - public void TransactionCreatedSuccessfully() - { - MockTxnDefinition def = new MockTxnDefinition(); - def.PropagationBehavior = TransactionPropagation.RequiresNew; - def.ReadOnly = false; - - SetGeneralGetTransactionExpectations(); - - DefaultTransactionStatus status = (DefaultTransactionStatus) _mockTxnMgr.GetTransaction(def); - Assert.AreEqual(_mockTxnMgr.Transaction, status.Transaction); - Assert.IsTrue(status.IsNewTransaction); - Assert.IsTrue(status.NewSynchronization); - Assert.IsTrue(!status.ReadOnly); - Assert.IsNotNull(status.SuspendedResources); - AssertVanillaGetTransactionExpectations(); - } - - [Test] - public void NestedTransactionSuccessfully() - { - MockTxnDefinition def = new MockTxnDefinition(); - def.PropagationBehavior = TransactionPropagation.Nested; - def.ReadOnly = false; - - SetGeneralGetTransactionExpectations(); - _mockTxnMgr.Savepoints = false; - _mockTxnMgr.NestedTransactionsAllowed = true; - - DefaultTransactionStatus status = (DefaultTransactionStatus) _mockTxnMgr.GetTransaction(def); - Assert.AreEqual(_mockTxnMgr.Transaction, status.Transaction); - Assert.IsTrue(status.IsNewTransaction); - Assert.AreEqual(true, status.NewSynchronization); - Assert.IsTrue(!status.ReadOnly); - Assert.IsNull(status.SuspendedResources); - - AssertVanillaGetTransactionExpectations(); - Assert.AreEqual(1, _mockTxnMgr.DoBeginCallCount); - } - - [Test] - public void NestedTransactionWithSavepoint() - { - MockTxnDefinition def = new MockTxnDefinition(); - def.PropagationBehavior = TransactionPropagation.Nested; - def.ReadOnly = false; - ISavepointManager saveMgr = A.Fake(); - _mockTxnMgr.SetTransaction(saveMgr); - _mockTxnMgr.Savepoints = true; - _mockTxnMgr.NestedTransactionsAllowed = true; - - DefaultTransactionStatus status = (DefaultTransactionStatus) _mockTxnMgr.GetTransaction(def); - Assert.AreEqual(_mockTxnMgr.Transaction, status.Transaction); - Assert.IsFalse(status.IsNewTransaction); - Assert.IsFalse(status.NewSynchronization); - Assert.IsTrue(!status.ReadOnly); - Assert.IsNull(status.SuspendedResources); - - AssertVanillaGetTransactionExpectations(); - Assert.AreEqual(0, _mockTxnMgr.DoBeginCallCount); - } - - [Test] - public void DefaultPropagationBehavior() - { - MockTxnDefinition def = new MockTxnDefinition(); - def.PropagationBehavior = TransactionPropagation.Required; - def.ReadOnly = true; - SetGeneralGetTransactionExpectations(); - - DefaultTransactionStatus status = (DefaultTransactionStatus) _mockTxnMgr.GetTransaction(def); - Assert.AreEqual(_mockTxnMgr.Transaction, status.Transaction); - Assert.IsTrue(!status.IsNewTransaction); - Assert.IsTrue(status.NewSynchronization); - Assert.IsTrue(status.ReadOnly); - Assert.IsNull(status.SuspendedResources); - AssertVanillaGetTransactionExpectations(); - } - - [Test] - public void DefaultPropagationBehaviorWithNullDefinition() - { - SetGeneralGetTransactionExpectations(); - - DefaultTransactionStatus status = (DefaultTransactionStatus) _mockTxnMgr.GetTransaction(null); - Assert.AreEqual(_mockTxnMgr.Transaction, status.Transaction); - Assert.IsFalse(status.IsNewTransaction); - Assert.IsTrue(status.NewSynchronization); - Assert.IsFalse(status.ReadOnly); - Assert.IsNull(status.SuspendedResources); - AssertVanillaGetTransactionExpectations(); - } - - [Test] - public void DefaultNoExistingTransaction() - { - DefaultTransactionStatus status = (DefaultTransactionStatus) _mockTxnMgr.GetTransaction(null); - Assert.IsNotNull(status.Transaction); - Assert.IsTrue(status.IsNewTransaction); - Assert.IsTrue(status.NewSynchronization); - Assert.IsTrue(!status.ReadOnly); - Assert.IsNull(status.SuspendedResources); - Assert.AreEqual(1, _mockTxnMgr.DoBeginCallCount); - - AssertVanillaGetTransactionExpectations(); - } - - [Test] - public void DefaultBehaviorDefaultPropagationNoExistingTransaction() - { - MockTxnDefinition def = new MockTxnDefinition(); - def.PropagationBehavior = TransactionPropagation.Never; - def.ReadOnly = true; - - DefaultTransactionStatus status = (DefaultTransactionStatus) _mockTxnMgr.GetTransaction(def); - Assert.IsNull(status.Transaction); - Assert.IsTrue(!status.IsNewTransaction); - Assert.IsTrue(status.NewSynchronization); - Assert.IsTrue(status.ReadOnly); - Assert.IsNull(status.SuspendedResources); - Assert.AreEqual(0, _mockTxnMgr.DoBeginCallCount); - - AssertVanillaGetTransactionExpectations(); - } - - private void SetGeneralGetTransactionExpectations() - { - _mockTxnMgr.SetTransaction(new object()); - } - - private void AssertVanillaGetTransactionExpectations() - { - Assert.AreEqual(1, _mockTxnMgr.DoGetTransactionCallCount); - Assert.AreEqual(1, _mockTxnMgr.IsExistingTransactionCallCount); + TransactionSynchronizationManager.ClearSynchronization(); } } -} \ No newline at end of file + + [TearDown] + public void Destroy() + { + _mockTxnMgr = null; + if (TransactionSynchronizationManager.SynchronizationActive) + { + TransactionSynchronizationManager.Clear(); + } + } + + [Test] + public void VanillaProperties() + { + Assert.AreEqual(TransactionSynchronizationState.Always, _mockTxnMgr.TransactionSynchronization); + Assert.IsTrue(!_mockTxnMgr.NestedTransactionsAllowed); + Assert.IsTrue(!_mockTxnMgr.RollbackOnCommitFailure); + + _mockTxnMgr.NestedTransactionsAllowed = true; + _mockTxnMgr.RollbackOnCommitFailure = true; + _mockTxnMgr.TransactionSynchronization = TransactionSynchronizationState.OnActualTransaction; + + Assert.AreEqual(TransactionSynchronizationState.OnActualTransaction, _mockTxnMgr.TransactionSynchronization); + Assert.IsTrue(_mockTxnMgr.NestedTransactionsAllowed); + Assert.IsTrue(_mockTxnMgr.RollbackOnCommitFailure); + } + + [Test] + public void DefinitionInvalidTimeoutException() + { + MockTxnDefinition def = new MockTxnDefinition(); + def.TransactionTimeout = -1000; + Assert.Throws(() => _mockTxnMgr.GetTransaction(def), "Invalid transaction timeout"); + } + + [Test] + public void DefinitionInvalidPropagationState() + { + MockTxnDefinition def = new MockTxnDefinition(); + def.PropagationBehavior = TransactionPropagation.Mandatory; + Assert.Throws(() => _mockTxnMgr.GetTransaction(def), "Transaction propagation 'mandatory' but no existing transaction found"); + } + + [Test] + public void NeverPropagateState() + { + MockTxnDefinition def = new MockTxnDefinition(); + def.PropagationBehavior = TransactionPropagation.Never; + SetGeneralGetTransactionExpectations(); + + Assert.Throws(() => _mockTxnMgr.GetTransaction(def), "Transaction propagation 'never' but existing transaction found."); + } + + [Test] + public void NoNestedTransactionsAllowed() + { + MockTxnDefinition def = new MockTxnDefinition(); + def.PropagationBehavior = TransactionPropagation.Nested; + SetGeneralGetTransactionExpectations(); + + Assert.Throws(() => _mockTxnMgr.GetTransaction(def), "Transaction manager does not allow nested transactions by default - specify 'NestedTransactionsAllowed' property with value 'true'"); + } + + [Test] + public void TransactionSuspendedSuccessfully() + { + MockTxnDefinition def = new MockTxnDefinition(); + def.PropagationBehavior = TransactionPropagation.NotSupported; + def.ReadOnly = false; + SetGeneralGetTransactionExpectations(); + + DefaultTransactionStatus status = (DefaultTransactionStatus) _mockTxnMgr.GetTransaction(def); + Assert.IsNull(status.Transaction); + Assert.IsTrue(!status.IsNewTransaction); + Assert.IsTrue(status.NewSynchronization); + Assert.IsTrue(!status.ReadOnly); + Assert.IsNotNull(status.SuspendedResources); + AssertVanillaGetTransactionExpectations(); + } + + [Test] + public void TransactionCreatedSuccessfully() + { + MockTxnDefinition def = new MockTxnDefinition(); + def.PropagationBehavior = TransactionPropagation.RequiresNew; + def.ReadOnly = false; + + SetGeneralGetTransactionExpectations(); + + DefaultTransactionStatus status = (DefaultTransactionStatus) _mockTxnMgr.GetTransaction(def); + Assert.AreEqual(_mockTxnMgr.Transaction, status.Transaction); + Assert.IsTrue(status.IsNewTransaction); + Assert.IsTrue(status.NewSynchronization); + Assert.IsTrue(!status.ReadOnly); + Assert.IsNotNull(status.SuspendedResources); + AssertVanillaGetTransactionExpectations(); + } + + [Test] + public void NestedTransactionSuccessfully() + { + MockTxnDefinition def = new MockTxnDefinition(); + def.PropagationBehavior = TransactionPropagation.Nested; + def.ReadOnly = false; + + SetGeneralGetTransactionExpectations(); + _mockTxnMgr.Savepoints = false; + _mockTxnMgr.NestedTransactionsAllowed = true; + + DefaultTransactionStatus status = (DefaultTransactionStatus) _mockTxnMgr.GetTransaction(def); + Assert.AreEqual(_mockTxnMgr.Transaction, status.Transaction); + Assert.IsTrue(status.IsNewTransaction); + Assert.AreEqual(true, status.NewSynchronization); + Assert.IsTrue(!status.ReadOnly); + Assert.IsNull(status.SuspendedResources); + + AssertVanillaGetTransactionExpectations(); + Assert.AreEqual(1, _mockTxnMgr.DoBeginCallCount); + } + + [Test] + public void NestedTransactionWithSavepoint() + { + MockTxnDefinition def = new MockTxnDefinition(); + def.PropagationBehavior = TransactionPropagation.Nested; + def.ReadOnly = false; + ISavepointManager saveMgr = A.Fake(); + _mockTxnMgr.SetTransaction(saveMgr); + _mockTxnMgr.Savepoints = true; + _mockTxnMgr.NestedTransactionsAllowed = true; + + DefaultTransactionStatus status = (DefaultTransactionStatus) _mockTxnMgr.GetTransaction(def); + Assert.AreEqual(_mockTxnMgr.Transaction, status.Transaction); + Assert.IsFalse(status.IsNewTransaction); + Assert.IsFalse(status.NewSynchronization); + Assert.IsTrue(!status.ReadOnly); + Assert.IsNull(status.SuspendedResources); + + AssertVanillaGetTransactionExpectations(); + Assert.AreEqual(0, _mockTxnMgr.DoBeginCallCount); + } + + [Test] + public void DefaultPropagationBehavior() + { + MockTxnDefinition def = new MockTxnDefinition(); + def.PropagationBehavior = TransactionPropagation.Required; + def.ReadOnly = true; + SetGeneralGetTransactionExpectations(); + + DefaultTransactionStatus status = (DefaultTransactionStatus) _mockTxnMgr.GetTransaction(def); + Assert.AreEqual(_mockTxnMgr.Transaction, status.Transaction); + Assert.IsTrue(!status.IsNewTransaction); + Assert.IsTrue(status.NewSynchronization); + Assert.IsTrue(status.ReadOnly); + Assert.IsNull(status.SuspendedResources); + AssertVanillaGetTransactionExpectations(); + } + + [Test] + public void DefaultPropagationBehaviorWithNullDefinition() + { + SetGeneralGetTransactionExpectations(); + + DefaultTransactionStatus status = (DefaultTransactionStatus) _mockTxnMgr.GetTransaction(null); + Assert.AreEqual(_mockTxnMgr.Transaction, status.Transaction); + Assert.IsFalse(status.IsNewTransaction); + Assert.IsTrue(status.NewSynchronization); + Assert.IsFalse(status.ReadOnly); + Assert.IsNull(status.SuspendedResources); + AssertVanillaGetTransactionExpectations(); + } + + [Test] + public void DefaultNoExistingTransaction() + { + DefaultTransactionStatus status = (DefaultTransactionStatus) _mockTxnMgr.GetTransaction(null); + Assert.IsNotNull(status.Transaction); + Assert.IsTrue(status.IsNewTransaction); + Assert.IsTrue(status.NewSynchronization); + Assert.IsTrue(!status.ReadOnly); + Assert.IsNull(status.SuspendedResources); + Assert.AreEqual(1, _mockTxnMgr.DoBeginCallCount); + + AssertVanillaGetTransactionExpectations(); + } + + [Test] + public void DefaultBehaviorDefaultPropagationNoExistingTransaction() + { + MockTxnDefinition def = new MockTxnDefinition(); + def.PropagationBehavior = TransactionPropagation.Never; + def.ReadOnly = true; + + DefaultTransactionStatus status = (DefaultTransactionStatus) _mockTxnMgr.GetTransaction(def); + Assert.IsNull(status.Transaction); + Assert.IsTrue(!status.IsNewTransaction); + Assert.IsTrue(status.NewSynchronization); + Assert.IsTrue(status.ReadOnly); + Assert.IsNull(status.SuspendedResources); + Assert.AreEqual(0, _mockTxnMgr.DoBeginCallCount); + + AssertVanillaGetTransactionExpectations(); + } + + private void SetGeneralGetTransactionExpectations() + { + _mockTxnMgr.SetTransaction(new object()); + } + + private void AssertVanillaGetTransactionExpectations() + { + Assert.AreEqual(1, _mockTxnMgr.DoGetTransactionCallCount); + Assert.AreEqual(1, _mockTxnMgr.IsExistingTransactionCallCount); + } +} diff --git a/test/Spring/Spring.Data.Tests/Transaction/Support/DefaultTransactionDefinitionTests.cs b/test/Spring/Spring.Data.Tests/Transaction/Support/DefaultTransactionDefinitionTests.cs index 5dcfe3e7..ed6b913e 100644 --- a/test/Spring/Spring.Data.Tests/Transaction/Support/DefaultTransactionDefinitionTests.cs +++ b/test/Spring/Spring.Data.Tests/Transaction/Support/DefaultTransactionDefinitionTests.cs @@ -1,69 +1,73 @@ using System.Data; using NUnit.Framework; -namespace Spring.Transaction.Support +namespace Spring.Transaction.Support; + +[TestFixture] +public class DefaultTransactionDefinitionTests { - [TestFixture] - public class DefaultTransactionDefinitionTests - { - [Test] - public void VanillaTest() - { - DefaultTransactionDefinition def = new DefaultTransactionDefinition( TransactionPropagation.NotSupported); - Assert.IsTrue( def.PropagationBehavior == TransactionPropagation.NotSupported ); - def.PropagationBehavior = TransactionPropagation.Nested; - Assert.IsTrue( def.PropagationBehavior == TransactionPropagation.Nested ); - def.TransactionIsolationLevel = IsolationLevel.ReadCommitted; - Assert.IsTrue( def.TransactionIsolationLevel == IsolationLevel.ReadCommitted); - def.TransactionTimeout = 1000; - Assert.IsTrue( 1000 == def.TransactionTimeout ); - Assert.IsTrue( false == def.ReadOnly ); - def.ReadOnly = true; - Assert.IsTrue( def.ReadOnly ); - } - [Test] - public void PropogationBehaviorDefault() - { - DefaultTransactionDefinition def = new DefaultTransactionDefinition(); - Assert.IsTrue( def.PropagationBehavior == TransactionPropagation.Required ); - } - [Test] - public void IsolationLevelDefault() - { - DefaultTransactionDefinition def = new DefaultTransactionDefinition(); - Assert.IsTrue(def.TransactionIsolationLevel == IsolationLevel.ReadCommitted); - } - [Test] - public void InvalidTimeout() - { - DefaultTransactionDefinition def = new DefaultTransactionDefinition(); - Assert.Throws(() => def.TransactionTimeout = -1000); - } - [Test] - public void DefinitionString() - { - DefaultTransactionDefinition def = new DefaultTransactionDefinition(); - DefaultTransactionDefinition def2 = new DefaultTransactionDefinition(); + [Test] + public void VanillaTest() + { + DefaultTransactionDefinition def = new DefaultTransactionDefinition(TransactionPropagation.NotSupported); + Assert.IsTrue(def.PropagationBehavior == TransactionPropagation.NotSupported); + def.PropagationBehavior = TransactionPropagation.Nested; + Assert.IsTrue(def.PropagationBehavior == TransactionPropagation.Nested); + def.TransactionIsolationLevel = IsolationLevel.ReadCommitted; + Assert.IsTrue(def.TransactionIsolationLevel == IsolationLevel.ReadCommitted); + def.TransactionTimeout = 1000; + Assert.IsTrue(1000 == def.TransactionTimeout); + Assert.IsTrue(false == def.ReadOnly); + def.ReadOnly = true; + Assert.IsTrue(def.ReadOnly); + } - Assert.IsTrue( def.ToString() == def2.ToString()); - def.Equals(def2); - } - [Test] - public void DefinitionStringFilled() - { - DefaultTransactionDefinition def = new DefaultTransactionDefinition( TransactionPropagation.Never ); - def.TransactionIsolationLevel = IsolationLevel.Chaos; - def.TransactionTimeout = 1000; - def.ReadOnly = true; - Assert.AreEqual( "PROPAGATION_Never,ISOLATION_Chaos,timeout_1000,readOnly", def.ToString()); - - DefaultTransactionDefinition def2 = new DefaultTransactionDefinition( TransactionPropagation.Never ); - def2.TransactionIsolationLevel = IsolationLevel.Chaos; - def2.TransactionTimeout = 1000; - def2.ReadOnly = true; + [Test] + public void PropogationBehaviorDefault() + { + DefaultTransactionDefinition def = new DefaultTransactionDefinition(); + Assert.IsTrue(def.PropagationBehavior == TransactionPropagation.Required); + } - Assert.IsTrue( def2.Equals(def)); - Assert.IsTrue( def.GetHashCode() == def2.GetHashCode()); - } - } + [Test] + public void IsolationLevelDefault() + { + DefaultTransactionDefinition def = new DefaultTransactionDefinition(); + Assert.IsTrue(def.TransactionIsolationLevel == IsolationLevel.ReadCommitted); + } + + [Test] + public void InvalidTimeout() + { + DefaultTransactionDefinition def = new DefaultTransactionDefinition(); + Assert.Throws(() => def.TransactionTimeout = -1000); + } + + [Test] + public void DefinitionString() + { + DefaultTransactionDefinition def = new DefaultTransactionDefinition(); + DefaultTransactionDefinition def2 = new DefaultTransactionDefinition(); + + Assert.IsTrue(def.ToString() == def2.ToString()); + def.Equals(def2); + } + + [Test] + public void DefinitionStringFilled() + { + DefaultTransactionDefinition def = new DefaultTransactionDefinition(TransactionPropagation.Never); + def.TransactionIsolationLevel = IsolationLevel.Chaos; + def.TransactionTimeout = 1000; + def.ReadOnly = true; + Assert.AreEqual("PROPAGATION_Never,ISOLATION_Chaos,timeout_1000,readOnly", def.ToString()); + + DefaultTransactionDefinition def2 = new DefaultTransactionDefinition(TransactionPropagation.Never); + def2.TransactionIsolationLevel = IsolationLevel.Chaos; + def2.TransactionTimeout = 1000; + def2.ReadOnly = true; + + Assert.IsTrue(def2.Equals(def)); + Assert.IsTrue(def.GetHashCode() == def2.GetHashCode()); + } } diff --git a/test/Spring/Spring.Data.Tests/Transaction/Support/DefaultTransactionStatusTests.cs b/test/Spring/Spring.Data.Tests/Transaction/Support/DefaultTransactionStatusTests.cs index cb38f62d..1f2cb08e 100644 --- a/test/Spring/Spring.Data.Tests/Transaction/Support/DefaultTransactionStatusTests.cs +++ b/test/Spring/Spring.Data.Tests/Transaction/Support/DefaultTransactionStatusTests.cs @@ -1,105 +1,103 @@ using FakeItEasy; - using NUnit.Framework; -namespace Spring.Transaction.Support +namespace Spring.Transaction.Support; + +[TestFixture] +public class DefaultTransactionStatusTests { - [TestFixture] - public class DefaultTransactionStatusTests + [Test] + public void DefaultConstructorTests() { - [Test] - public void DefaultConstructorTests() - { - ISmartTransactionObject txn = A.Fake(); + ISmartTransactionObject txn = A.Fake(); - DefaultTransactionStatus stat = new DefaultTransactionStatus(txn, true, false, false, true, new object()); - Assert.IsNotNull(stat.Transaction); - Assert.IsTrue(!stat.ReadOnly); - Assert.IsTrue(!stat.NewSynchronization); - Assert.IsNotNull(stat.SuspendedResources); - Assert.IsTrue(stat.IsNewTransaction); - Assert.IsTrue(! stat.RollbackOnly); - stat.SetRollbackOnly(); - Assert.IsTrue(stat.RollbackOnly); - } - - [Test] - public void CreateSavepointException() - { - ISmartTransactionObject transaction = A.Fake(); - DefaultTransactionStatus stat = new DefaultTransactionStatus(transaction, true, false, false, true, new object()); - Assert.Throws(() => stat.CreateSavepoint("mySavePoint")); - } - - [Test] - public void RollbackSavepointException() - { - ISmartTransactionObject transaction = A.Fake(); - DefaultTransactionStatus stat = new DefaultTransactionStatus(transaction, true, false, false, true, new object()); - Assert.Throws(() => stat.RollbackToSavepoint(null)); - } - - [Test] - public void ReleaseSavepointException() - { - ISmartTransactionObject transaction = A.Fake(); - DefaultTransactionStatus stat = new DefaultTransactionStatus(transaction, true, false, false, true, new object()); - Assert.Throws(() => stat.ReleaseSavepoint(null)); - } - - [Test] - public void CreateSaveAndHoldValidSavepoint() - { - ISavepointManager saveMgr = A.Fake(); - DefaultTransactionStatus status = new DefaultTransactionStatus(saveMgr, true, false, false, true, new object()); - status.CreateAndHoldSavepoint("savepoint"); - Assert.IsTrue(status.HasSavepoint); - Assert.AreEqual("savepoint", status.Savepoint); - } - - [Test] - public void RollbackHeldSavepointException() - { - ISmartTransactionObject transaction = A.Fake(); - DefaultTransactionStatus stat = new DefaultTransactionStatus(transaction, true, false, false, true, new object()); - Assert.Throws(() => stat.RollbackToHeldSavepoint()); - } - - [Test] - public void RollbackHeldSavepointSuccess() - { - ISavepointManager saveMgr = A.Fake(); - string savepoint = "savepoint"; - DefaultTransactionStatus status = new DefaultTransactionStatus(saveMgr, true, false, false, true, new object()); - status.CreateAndHoldSavepoint(savepoint); - Assert.IsTrue(status.HasSavepoint); - Assert.AreEqual(savepoint, status.Savepoint); - - status.RollbackToHeldSavepoint(); - A.CallTo(() => saveMgr.RollbackToSavepoint(savepoint)).MustHaveHappened(); - } - - [Test] - public void ReleaseHeldSavepointException() - { - ISmartTransactionObject transaction = A.Fake(); - DefaultTransactionStatus stat = new DefaultTransactionStatus(transaction, true, false, false, true, new object()); - Assert.Throws(() => stat.ReleaseHeldSavepoint()); - } - - [Test] - public void ReleaseHeldSavepointSuccess() - { - ISavepointManager saveMgr = A.Fake(); - string savepoint = "savepoint"; - DefaultTransactionStatus status = new DefaultTransactionStatus(saveMgr, true, false, false, true, new object()); - status.CreateAndHoldSavepoint(savepoint); - Assert.IsTrue(status.HasSavepoint); - Assert.AreEqual(savepoint, status.Savepoint); - - status.ReleaseHeldSavepoint(); - A.CallTo(() => saveMgr.CreateSavepoint(savepoint)).MustHaveHappened(); - A.CallTo(() => saveMgr.ReleaseSavepoint(savepoint)).MustHaveHappened(); - } + DefaultTransactionStatus stat = new DefaultTransactionStatus(txn, true, false, false, true, new object()); + Assert.IsNotNull(stat.Transaction); + Assert.IsTrue(!stat.ReadOnly); + Assert.IsTrue(!stat.NewSynchronization); + Assert.IsNotNull(stat.SuspendedResources); + Assert.IsTrue(stat.IsNewTransaction); + Assert.IsTrue(!stat.RollbackOnly); + stat.SetRollbackOnly(); + Assert.IsTrue(stat.RollbackOnly); } -} \ No newline at end of file + + [Test] + public void CreateSavepointException() + { + ISmartTransactionObject transaction = A.Fake(); + DefaultTransactionStatus stat = new DefaultTransactionStatus(transaction, true, false, false, true, new object()); + Assert.Throws(() => stat.CreateSavepoint("mySavePoint")); + } + + [Test] + public void RollbackSavepointException() + { + ISmartTransactionObject transaction = A.Fake(); + DefaultTransactionStatus stat = new DefaultTransactionStatus(transaction, true, false, false, true, new object()); + Assert.Throws(() => stat.RollbackToSavepoint(null)); + } + + [Test] + public void ReleaseSavepointException() + { + ISmartTransactionObject transaction = A.Fake(); + DefaultTransactionStatus stat = new DefaultTransactionStatus(transaction, true, false, false, true, new object()); + Assert.Throws(() => stat.ReleaseSavepoint(null)); + } + + [Test] + public void CreateSaveAndHoldValidSavepoint() + { + ISavepointManager saveMgr = A.Fake(); + DefaultTransactionStatus status = new DefaultTransactionStatus(saveMgr, true, false, false, true, new object()); + status.CreateAndHoldSavepoint("savepoint"); + Assert.IsTrue(status.HasSavepoint); + Assert.AreEqual("savepoint", status.Savepoint); + } + + [Test] + public void RollbackHeldSavepointException() + { + ISmartTransactionObject transaction = A.Fake(); + DefaultTransactionStatus stat = new DefaultTransactionStatus(transaction, true, false, false, true, new object()); + Assert.Throws(() => stat.RollbackToHeldSavepoint()); + } + + [Test] + public void RollbackHeldSavepointSuccess() + { + ISavepointManager saveMgr = A.Fake(); + string savepoint = "savepoint"; + DefaultTransactionStatus status = new DefaultTransactionStatus(saveMgr, true, false, false, true, new object()); + status.CreateAndHoldSavepoint(savepoint); + Assert.IsTrue(status.HasSavepoint); + Assert.AreEqual(savepoint, status.Savepoint); + + status.RollbackToHeldSavepoint(); + A.CallTo(() => saveMgr.RollbackToSavepoint(savepoint)).MustHaveHappened(); + } + + [Test] + public void ReleaseHeldSavepointException() + { + ISmartTransactionObject transaction = A.Fake(); + DefaultTransactionStatus stat = new DefaultTransactionStatus(transaction, true, false, false, true, new object()); + Assert.Throws(() => stat.ReleaseHeldSavepoint()); + } + + [Test] + public void ReleaseHeldSavepointSuccess() + { + ISavepointManager saveMgr = A.Fake(); + string savepoint = "savepoint"; + DefaultTransactionStatus status = new DefaultTransactionStatus(saveMgr, true, false, false, true, new object()); + status.CreateAndHoldSavepoint(savepoint); + Assert.IsTrue(status.HasSavepoint); + Assert.AreEqual(savepoint, status.Savepoint); + + status.ReleaseHeldSavepoint(); + A.CallTo(() => saveMgr.CreateSavepoint(savepoint)).MustHaveHappened(); + A.CallTo(() => saveMgr.ReleaseSavepoint(savepoint)).MustHaveHappened(); + } +} diff --git a/test/Spring/Spring.Data.Tests/Transaction/Support/ResourceHolderSupportTests.cs b/test/Spring/Spring.Data.Tests/Transaction/Support/ResourceHolderSupportTests.cs index ca2def20..09c078aa 100644 --- a/test/Spring/Spring.Data.Tests/Transaction/Support/ResourceHolderSupportTests.cs +++ b/test/Spring/Spring.Data.Tests/Transaction/Support/ResourceHolderSupportTests.cs @@ -1,74 +1,75 @@ using NUnit.Framework; -namespace Spring.Transaction.Support +namespace Spring.Transaction.Support; + +[TestFixture] +public class ResourceHolderSupportTests : ResourceHolderSupport { - [TestFixture] - public class ResourceHolderSupportTests : ResourceHolderSupport - { - [TearDown] - public void Destroy() - { - Clear(); - } - [Test] - public void PropertiesTest() - { - Assert.AreEqual( DateTime.MinValue, Deadline); - Assert.IsTrue( !SynchronizedWithTransaction ); - Assert.IsTrue( !RollbackOnly); - - //TODO investigate - /* - Deadline = DateTime.Now.AddDays(2); - Assert.IsTrue( HasDeadline ); - Assert.AreEqual( DateTime.Now.AddDays(2).Date, Deadline.Date ); - */ + [TearDown] + public void Destroy() + { + Clear(); + } - SynchronizedWithTransaction = true; - Assert.IsTrue( SynchronizedWithTransaction ); + [Test] + public void PropertiesTest() + { + Assert.AreEqual(DateTime.MinValue, Deadline); + Assert.IsTrue(!SynchronizedWithTransaction); + Assert.IsTrue(!RollbackOnly); - RollbackOnly = true; - Assert.IsTrue( RollbackOnly); - } - [Test] - public void InvalidDeadline() - { - int temp; - Assert.Throws(() => temp = TimeToLiveInSeconds); - } + //TODO investigate + /* + Deadline = DateTime.Now.AddDays(2); + Assert.IsTrue( HasDeadline ); + Assert.AreEqual( DateTime.Now.AddDays(2).Date, Deadline.Date ); + */ - /* - [Ignore("investigate...")] - [Test] - public void ZeroMilliseconds() - { - Deadline = DateTime.Now.AddDays(-1); - Assert.AreEqual( 0, TimeToLiveInMilliseconds ); - } - */ - /* - [Test] - public void MillisecondToLive() - { - Deadline = DateTime.Now.AddDays(1); - Assert.IsTrue( TimeToLiveInMilliseconds >= 0); - } - */ - /* - [Test] - public void SetDeadline() - { - SetDeadlineInSeconds( 10 ); - Assert.IsTrue( TimeToLiveInSeconds >= 0); - } - */ - /* - [Test] - public void SetDeadlineMillis() - { - SetDeadlineInMilliseconds(1000); - Assert.IsTrue( TimeToLiveInMilliseconds >= 0); - } - */ - } + SynchronizedWithTransaction = true; + Assert.IsTrue(SynchronizedWithTransaction); + + RollbackOnly = true; + Assert.IsTrue(RollbackOnly); + } + + [Test] + public void InvalidDeadline() + { + int temp; + Assert.Throws(() => temp = TimeToLiveInSeconds); + } + + /* + [Ignore("investigate...")] + [Test] + public void ZeroMilliseconds() + { + Deadline = DateTime.Now.AddDays(-1); + Assert.AreEqual( 0, TimeToLiveInMilliseconds ); + } + */ + /* + [Test] + public void MillisecondToLive() + { + Deadline = DateTime.Now.AddDays(1); + Assert.IsTrue( TimeToLiveInMilliseconds >= 0); + } + */ + /* + [Test] + public void SetDeadline() + { + SetDeadlineInSeconds( 10 ); + Assert.IsTrue( TimeToLiveInSeconds >= 0); + } + */ + /* + [Test] + public void SetDeadlineMillis() + { + SetDeadlineInMilliseconds(1000); + Assert.IsTrue( TimeToLiveInMilliseconds >= 0); + } + */ } diff --git a/test/Spring/Spring.Data.Tests/Transaction/Support/TransactionSynchronizationAdapterTests.cs b/test/Spring/Spring.Data.Tests/Transaction/Support/TransactionSynchronizationAdapterTests.cs index 624960de..e0a68440 100644 --- a/test/Spring/Spring.Data.Tests/Transaction/Support/TransactionSynchronizationAdapterTests.cs +++ b/test/Spring/Spring.Data.Tests/Transaction/Support/TransactionSynchronizationAdapterTests.cs @@ -1,18 +1,17 @@ using NUnit.Framework; -namespace Spring.Transaction.Support +namespace Spring.Transaction.Support; + +[TestFixture] +public class TransactionSynchronizationAdapterTests : TransactionSynchronizationAdapter { - [TestFixture] - public class TransactionSynchronizationAdapterTests : TransactionSynchronizationAdapter - { - [Test] - public void CoverageTests() - { - AfterCompletion( TransactionSynchronizationStatus.Committed ); - BeforeCommit(false); - BeforeCompletion(); - Resume(); - Suspend(); - } - } + [Test] + public void CoverageTests() + { + AfterCompletion(TransactionSynchronizationStatus.Committed); + BeforeCommit(false); + BeforeCompletion(); + Resume(); + Suspend(); + } } diff --git a/test/Spring/Spring.Data.Tests/Transaction/Support/TransactionSynchronizationManagerTests.cs b/test/Spring/Spring.Data.Tests/Transaction/Support/TransactionSynchronizationManagerTests.cs index 0d4146ee..438a7d2f 100644 --- a/test/Spring/Spring.Data.Tests/Transaction/Support/TransactionSynchronizationManagerTests.cs +++ b/test/Spring/Spring.Data.Tests/Transaction/Support/TransactionSynchronizationManagerTests.cs @@ -1,126 +1,122 @@ using System.Collections; - using FakeItEasy; - using NUnit.Framework; - using Spring.Core; using Spring.Util; -namespace Spring.Transaction.Support +namespace Spring.Transaction.Support; + +[TestFixture] +public class TransactionSynchronizationManagerTests { - [TestFixture] - public class TransactionSynchronizationManagerTests + [SetUp] + public void Init() { - [SetUp] - public void Init() + if (TransactionSynchronizationManager.SynchronizationActive) { - if (TransactionSynchronizationManager.SynchronizationActive) - { - TransactionSynchronizationManager.ClearSynchronization(); - } - } - - [TearDown] - public void Destory() - { - if (TransactionSynchronizationManager.SynchronizationActive) - { - TransactionSynchronizationManager.ClearSynchronization(); - } - } - - [Test] - public void SynchronizationsInvalid() - { - IList temp; - Assert.Throws(() => temp = TransactionSynchronizationManager.Synchronizations); - } - - [Test] - public void InitSynchronizationsInvalid() - { - TransactionSynchronizationManager.InitSynchronization(); - Assert.Throws(() => TransactionSynchronizationManager.InitSynchronization()); - } - - [Test] - public void SynchronizationsClearInvalid() - { - Assert.Throws(() => TransactionSynchronizationManager.ClearSynchronization()); - } - - [Test] - public void RegisterSyncsInvalid() - { - Assert.Throws(() => TransactionSynchronizationManager.RegisterSynchronization(A.Fake())); - } - - [Test] - public void SynchronizationsLifeCycle() - { - TransactionSynchronizationManager.InitSynchronization(); - IList syncs = TransactionSynchronizationManager.Synchronizations; - Assert.AreEqual(0, syncs.Count); - TransactionSynchronizationManager.RegisterSynchronization(A.Fake()); - syncs = TransactionSynchronizationManager.Synchronizations; - Assert.AreEqual(1, syncs.Count); TransactionSynchronizationManager.ClearSynchronization(); } + } - [Test(Description = "http://jira.springframework.org/browse/SPRNET-1160")] - public void SynchronizationsExecuteInOrderOfRegistration() + [TearDown] + public void Destory() + { + if (TransactionSynchronizationManager.SynchronizationActive) { - TransactionSynchronizationManager.InitSynchronization(); + TransactionSynchronizationManager.ClearSynchronization(); + } + } - try - { - // expect syncs to be run A, B, C, D, E since all have order '1' - TransactionSynchronizationManager.RegisterSynchronization(new Sync("A", 1)); - TransactionSynchronizationManager.RegisterSynchronization(new Sync("B", 1)); - TransactionSynchronizationManager.RegisterSynchronization(new Sync("C", 1)); - TransactionSynchronizationManager.RegisterSynchronization(new Sync("D", 1)); - TransactionSynchronizationManager.RegisterSynchronization(new Sync("E", 1)); + [Test] + public void SynchronizationsInvalid() + { + IList temp; + Assert.Throws(() => temp = TransactionSynchronizationManager.Synchronizations); + } - // simulate what APTM does - Sync[] syncs = (Sync[]) CollectionUtils.ToArray(TransactionSynchronizationManager.Synchronizations, typeof(Sync)); - Assert.AreEqual("A", syncs[0].Name); - Assert.AreEqual("B", syncs[1].Name); - Assert.AreEqual("C", syncs[2].Name); - Assert.AreEqual("D", syncs[3].Name); - Assert.AreEqual("E", syncs[4].Name); - } - finally - { - TransactionSynchronizationManager.ClearSynchronization(); - } + [Test] + public void InitSynchronizationsInvalid() + { + TransactionSynchronizationManager.InitSynchronization(); + Assert.Throws(() => TransactionSynchronizationManager.InitSynchronization()); + } + + [Test] + public void SynchronizationsClearInvalid() + { + Assert.Throws(() => TransactionSynchronizationManager.ClearSynchronization()); + } + + [Test] + public void RegisterSyncsInvalid() + { + Assert.Throws(() => TransactionSynchronizationManager.RegisterSynchronization(A.Fake())); + } + + [Test] + public void SynchronizationsLifeCycle() + { + TransactionSynchronizationManager.InitSynchronization(); + IList syncs = TransactionSynchronizationManager.Synchronizations; + Assert.AreEqual(0, syncs.Count); + TransactionSynchronizationManager.RegisterSynchronization(A.Fake()); + syncs = TransactionSynchronizationManager.Synchronizations; + Assert.AreEqual(1, syncs.Count); + TransactionSynchronizationManager.ClearSynchronization(); + } + + [Test(Description = "http://jira.springframework.org/browse/SPRNET-1160")] + public void SynchronizationsExecuteInOrderOfRegistration() + { + TransactionSynchronizationManager.InitSynchronization(); + + try + { + // expect syncs to be run A, B, C, D, E since all have order '1' + TransactionSynchronizationManager.RegisterSynchronization(new Sync("A", 1)); + TransactionSynchronizationManager.RegisterSynchronization(new Sync("B", 1)); + TransactionSynchronizationManager.RegisterSynchronization(new Sync("C", 1)); + TransactionSynchronizationManager.RegisterSynchronization(new Sync("D", 1)); + TransactionSynchronizationManager.RegisterSynchronization(new Sync("E", 1)); + + // simulate what APTM does + Sync[] syncs = (Sync[]) CollectionUtils.ToArray(TransactionSynchronizationManager.Synchronizations, typeof(Sync)); + Assert.AreEqual("A", syncs[0].Name); + Assert.AreEqual("B", syncs[1].Name); + Assert.AreEqual("C", syncs[2].Name); + Assert.AreEqual("D", syncs[3].Name); + Assert.AreEqual("E", syncs[4].Name); + } + finally + { + TransactionSynchronizationManager.ClearSynchronization(); + } + } + + private class Sync : TransactionSynchronizationAdapter, IOrdered + { + private readonly string name; + private readonly int order; + + public Sync(string name, int order) + { + this.name = name; + this.order = order; } - private class Sync : TransactionSynchronizationAdapter, IOrdered + public int Order { - private readonly string name; - private readonly int order; + get { return order; } + } - public Sync(string name, int order) - { - this.name = name; - this.order = order; - } + public string Name + { + get { return name; } + } - public int Order - { - get { return order; } - } - - public string Name - { - get { return name; } - } - - public override string ToString() - { - return name; - } + public override string ToString() + { + return name; } } } diff --git a/test/Spring/Spring.Data.Tests/Transaction/Support/TransactionTemplateTests.cs b/test/Spring/Spring.Data.Tests/Transaction/Support/TransactionTemplateTests.cs index 47b28e04..d0c21727 100644 --- a/test/Spring/Spring.Data.Tests/Transaction/Support/TransactionTemplateTests.cs +++ b/test/Spring/Spring.Data.Tests/Transaction/Support/TransactionTemplateTests.cs @@ -1,87 +1,85 @@ using FakeItEasy; - using NUnit.Framework; -namespace Spring.Transaction.Support +namespace Spring.Transaction.Support; + +[TestFixture] +public class TransactionTemplateTests { - [TestFixture] - public class TransactionTemplateTests + [Test] + public void NoTxnMgr() { - [Test] - public void NoTxnMgr() + TransactionTemplate temp = new TransactionTemplate(); + Assert.Throws(() => temp.AfterPropertiesSet()); + } + + [Test] + public void TxnMgr() + { + TransactionTemplate temp = new TransactionTemplate(); + temp.PlatformTransactionManager = A.Fake(); + temp.AfterPropertiesSet(); + } + + [Test] + public void ExecuteException() + { + IPlatformTransactionManager mock = A.Fake(); + + TransactionTemplate temp = new TransactionTemplate(mock); + try + { + temp.Execute(DummyExceptionMethod); + } + catch { - TransactionTemplate temp = new TransactionTemplate(); - Assert.Throws(() => temp.AfterPropertiesSet()); } - [Test] - public void TxnMgr() + A.CallTo(() => mock.GetTransaction(A._)).MustHaveHappenedOnceExactly(); + A.CallTo(() => mock.Rollback(A._)).MustHaveHappenedOnceExactly(); + } + + [Test] + public void ExecuteExceptionRollbackException() + { + IPlatformTransactionManager mock = A.Fake(); + A.CallTo(() => mock.Rollback(A._)).Throws(new Exception("Rollback")); + + TransactionTemplate temp = new TransactionTemplate(mock); + try + { + temp.Execute(DummyExceptionMethod); + } + catch { - TransactionTemplate temp = new TransactionTemplate(); - temp.PlatformTransactionManager = A.Fake(); - temp.AfterPropertiesSet(); } - [Test] - public void ExecuteException() - { - IPlatformTransactionManager mock = A.Fake(); + A.CallTo(() => mock.GetTransaction(A._)).MustHaveHappenedOnceExactly(); + A.CallTo(() => mock.Rollback(A._)).MustHaveHappenedOnceExactly(); + } - TransactionTemplate temp = new TransactionTemplate(mock); - try - { - temp.Execute(DummyExceptionMethod); - } - catch - { - } + [Test] + public void NullResult() + { + IPlatformTransactionManager mock = A.Fake(); + A.CallTo(() => mock.GetTransaction(A._)).Returns(null); - A.CallTo(() => mock.GetTransaction(A._)).MustHaveHappenedOnceExactly(); - A.CallTo(() => mock.Rollback(A._)).MustHaveHappenedOnceExactly(); - } + TransactionTemplate temp = new TransactionTemplate(mock); + temp.AfterPropertiesSet(); + Assert.AreEqual(mock, temp.PlatformTransactionManager); + Assert.IsNull(temp.Execute(DummyTransactionMethod)); - [Test] - public void ExecuteExceptionRollbackException() - { - IPlatformTransactionManager mock = A.Fake(); - A.CallTo(() => mock.Rollback(A._)).Throws(new Exception("Rollback")); + A.CallTo(() => mock.GetTransaction(A._)).MustHaveHappenedOnceExactly(); + A.CallTo(() => mock.Commit(A._)).MustHaveHappenedOnceExactly(); + } - TransactionTemplate temp = new TransactionTemplate(mock); - try - { - temp.Execute(DummyExceptionMethod); - } - catch - { - } + public object DummyTransactionMethod(ITransactionStatus status) + { + return status; + } - A.CallTo(() => mock.GetTransaction(A._)).MustHaveHappenedOnceExactly(); - A.CallTo(() => mock.Rollback(A._)).MustHaveHappenedOnceExactly(); - } - - [Test] - public void NullResult() - { - IPlatformTransactionManager mock = A.Fake(); - A.CallTo(() => mock.GetTransaction(A._)).Returns(null); - - TransactionTemplate temp = new TransactionTemplate(mock); - temp.AfterPropertiesSet(); - Assert.AreEqual(mock, temp.PlatformTransactionManager); - Assert.IsNull(temp.Execute(DummyTransactionMethod)); - - A.CallTo(() => mock.GetTransaction(A._)).MustHaveHappenedOnceExactly(); - A.CallTo(() => mock.Commit(A._)).MustHaveHappenedOnceExactly(); - } - - public object DummyTransactionMethod(ITransactionStatus status) - { - return status; - } - - public object DummyExceptionMethod(ITransactionStatus status) - { - throw new Exception("Bad Error"); - } + public object DummyExceptionMethod(ITransactionStatus status) + { + throw new Exception("Bad Error"); } } diff --git a/test/Spring/Spring.Messaging.Ems.Integration.Tests/App.config b/test/Spring/Spring.Messaging.Ems.Integration.Tests/App.config index c464766b..fd62543d 100644 --- a/test/Spring/Spring.Messaging.Ems.Integration.Tests/App.config +++ b/test/Spring/Spring.Messaging.Ems.Integration.Tests/App.config @@ -2,10 +2,10 @@ -
+
+ type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" /> - + @@ -44,18 +45,18 @@ + type="log4net.Appender.TraceAppender, log4net"> + value="%d{ABSOLUTE} %-5p %c{1}:%L - %m%n" /> + type="log4net.Appender.ConsoleAppender, log4net"> + value="%d{ABSOLUTE} %-5p %c{1}:%L - %m%n" /> diff --git a/test/Spring/Spring.Messaging.Ems.Integration.Tests/Messaging/Ems/Config/EmsNamespaceHandlerTests.cs b/test/Spring/Spring.Messaging.Ems.Integration.Tests/Messaging/Ems/Config/EmsNamespaceHandlerTests.cs index 77d17bc1..ea46bcf1 100644 --- a/test/Spring/Spring.Messaging.Ems.Integration.Tests/Messaging/Ems/Config/EmsNamespaceHandlerTests.cs +++ b/test/Spring/Spring.Messaging.Ems.Integration.Tests/Messaging/Ems/Config/EmsNamespaceHandlerTests.cs @@ -29,75 +29,66 @@ using Spring.Objects.Factory.Xml; #endregion -namespace Spring.Messaging.Ems.Config +namespace Spring.Messaging.Ems.Config; + +/// +/// This class contains tests for +/// +/// Mark Pollack +[TestFixture] +public class EmsNamespaceHandlerTests { - /// - /// This class contains tests for - /// - /// Mark Pollack - [TestFixture] - public class EmsNamespaceHandlerTests + private static string DEFAULT_CONNECTION_FACTORY = "ConnectionFactory"; + + private static string EXPLICIT_CONNECTION_FACTORY = "testConnectionFactory"; + + private IApplicationContext ctx; + + [SetUp] + public void Setup() { - - private static string DEFAULT_CONNECTION_FACTORY = "ConnectionFactory"; - - private static string EXPLICIT_CONNECTION_FACTORY = "testConnectionFactory"; - - - private IApplicationContext ctx; - - - [SetUp] - public void Setup() - { - NamespaceParserRegistry.RegisterParser(typeof(EmsNamespaceParser)); - ctx = new XmlApplicationContext(ReadOnlyXmlTestResource.GetFilePath("EmsNamespaceHandlerTests.xml", GetType())); - } - - [Test] - public void Registered() - { - Assert.IsNotNull(NamespaceParserRegistry.GetParser("http://www.springframework.net/ems")); - } - - [Test] - public void ObjectsCreated() - { - IDictionary containers = ctx.GetObjectsOfType(typeof(SimpleMessageListenerContainer)); - Assert.AreEqual(3, containers.Count); - } - - [Test] - public void ContainerConfiguration() - { - IDictionary containers = ctx.GetObjectsOfType(typeof (SimpleMessageListenerContainer)); - EmsConnectionFactory defaultConnectionFactory = (EmsConnectionFactory)ctx.GetObject(DEFAULT_CONNECTION_FACTORY); - defaultConnectionFactory = (EmsConnectionFactory)ctx.GetObject(DEFAULT_CONNECTION_FACTORY); - EmsConnectionFactory explicitConnectionFactory = (EmsConnectionFactory)ctx.GetObject(EXPLICIT_CONNECTION_FACTORY); - - - int defaultConnectionFactoryCount = 0; - int explicitConnectionFactoryCount = 0; - foreach (KeyValuePair dictionaryEntry in containers) - { - SimpleMessageListenerContainer container = (SimpleMessageListenerContainer) dictionaryEntry.Value; - if (container.ConnectionFactory.Equals(defaultConnectionFactory)) - { - defaultConnectionFactoryCount++; - } - else if (container.ConnectionFactory.Equals(explicitConnectionFactory)) - { - explicitConnectionFactoryCount++; - Assert.AreEqual(4, container.ConcurrentConsumers); - } - } - - Assert.AreEqual(1, defaultConnectionFactoryCount, "1 container should have the default connectionFactory"); - Assert.AreEqual(2, explicitConnectionFactoryCount, "2 containers should have the explicit connectionFactory"); - - } - - - + NamespaceParserRegistry.RegisterParser(typeof(EmsNamespaceParser)); + ctx = new XmlApplicationContext(ReadOnlyXmlTestResource.GetFilePath("EmsNamespaceHandlerTests.xml", GetType())); } -} + + [Test] + public void Registered() + { + Assert.IsNotNull(NamespaceParserRegistry.GetParser("http://www.springframework.net/ems")); + } + + [Test] + public void ObjectsCreated() + { + IDictionary containers = ctx.GetObjectsOfType(typeof(SimpleMessageListenerContainer)); + Assert.AreEqual(3, containers.Count); + } + + [Test] + public void ContainerConfiguration() + { + IDictionary containers = ctx.GetObjectsOfType(typeof(SimpleMessageListenerContainer)); + EmsConnectionFactory defaultConnectionFactory = (EmsConnectionFactory) ctx.GetObject(DEFAULT_CONNECTION_FACTORY); + defaultConnectionFactory = (EmsConnectionFactory) ctx.GetObject(DEFAULT_CONNECTION_FACTORY); + EmsConnectionFactory explicitConnectionFactory = (EmsConnectionFactory) ctx.GetObject(EXPLICIT_CONNECTION_FACTORY); + + int defaultConnectionFactoryCount = 0; + int explicitConnectionFactoryCount = 0; + foreach (KeyValuePair dictionaryEntry in containers) + { + SimpleMessageListenerContainer container = (SimpleMessageListenerContainer) dictionaryEntry.Value; + if (container.ConnectionFactory.Equals(defaultConnectionFactory)) + { + defaultConnectionFactoryCount++; + } + else if (container.ConnectionFactory.Equals(explicitConnectionFactory)) + { + explicitConnectionFactoryCount++; + Assert.AreEqual(4, container.ConcurrentConsumers); + } + } + + Assert.AreEqual(1, defaultConnectionFactoryCount, "1 container should have the default connectionFactory"); + Assert.AreEqual(2, explicitConnectionFactoryCount, "2 containers should have the explicit connectionFactory"); + } +} \ No newline at end of file diff --git a/test/Spring/Spring.Messaging.Ems.Integration.Tests/Messaging/Ems/Config/EmsNamespaceHandlerTests.xml b/test/Spring/Spring.Messaging.Ems.Integration.Tests/Messaging/Ems/Config/EmsNamespaceHandlerTests.xml index 8fa14ae4..013580d8 100644 --- a/test/Spring/Spring.Messaging.Ems.Integration.Tests/Messaging/Ems/Config/EmsNamespaceHandlerTests.xml +++ b/test/Spring/Spring.Messaging.Ems.Integration.Tests/Messaging/Ems/Config/EmsNamespaceHandlerTests.xml @@ -1,54 +1,57 @@  + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:ems="http://www.springframework.net/ems"> - - - - + + + + - - - + + + - - - - - - - - + + + + - + + + - + - + + + - + - + - + - - - - - - - - - + + + + + + + + + diff --git a/test/Spring/Spring.Messaging.Ems.Integration.Tests/Messaging/Ems/Connections/TestMessageListener.cs b/test/Spring/Spring.Messaging.Ems.Integration.Tests/Messaging/Ems/Connections/TestMessageListener.cs index eb95191a..ab607875 100644 --- a/test/Spring/Spring.Messaging.Ems.Integration.Tests/Messaging/Ems/Connections/TestMessageListener.cs +++ b/test/Spring/Spring.Messaging.Ems.Integration.Tests/Messaging/Ems/Connections/TestMessageListener.cs @@ -18,33 +18,31 @@ #endregion -namespace Spring.Messaging.Ems.Connections +namespace Spring.Messaging.Ems.Connections; + +/// +/// +/// +/// +/// +/// +/// Mark Pollack +public class TestMessageListener : IMessageListener { - /// - /// - /// - /// - /// - /// - /// Mark Pollack - public class TestMessageListener : IMessageListener + private string message; + + public string Message { - private string message; - - - public string Message - { - get { return message; } - set { message = value; } - } - - #region IMessageListener Members - - public void OnMessage(Message message) - { - this.message = "Test1"; - } - - #endregion + get { return message; } + set { message = value; } } -} \ No newline at end of file + + #region IMessageListener Members + + public void OnMessage(Message message) + { + this.message = "Test1"; + } + + #endregion +} diff --git a/test/Spring/Spring.Messaging.Ems.Integration.Tests/Messaging/Ems/Core/EmsTemplateTests.cs b/test/Spring/Spring.Messaging.Ems.Integration.Tests/Messaging/Ems/Core/EmsTemplateTests.cs index 0fc6971d..730f1670 100644 --- a/test/Spring/Spring.Messaging.Ems.Integration.Tests/Messaging/Ems/Core/EmsTemplateTests.cs +++ b/test/Spring/Spring.Messaging.Ems.Integration.Tests/Messaging/Ems/Core/EmsTemplateTests.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2010 the original author or authors. + * Copyright � 2002-2010 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. @@ -18,122 +18,118 @@ #endregion - #region Imports using System.Collections; using NUnit.Framework; - using Spring.Messaging.Ems.Common; using Spring.Testing.NUnit; #endregion -namespace Spring.Messaging.Ems.Core +namespace Spring.Messaging.Ems.Core; + +[TestFixture] +public class EmsTemplateTests : AbstractDependencyInjectionSpringContextTests { - [TestFixture] - public class EmsTemplateTests : AbstractDependencyInjectionSpringContextTests + protected IConnectionFactory emsConnectionFactory; + + protected IConnectionFactory connectionFactory; + + //This is the 'raw' TIBCO type + protected ConnectionFactory jndiEmsConnectionFactory; + + protected IConnectionFactory cachingJndiConnectionFactory; + + protected EmsTemplate emsTemplate; + + protected SimpleGateway simpleGateway; + + private Admin admin; + + private string queueName = "INT_TEST_QUEUE"; + + private Hashtable env = new Hashtable(); + + private LookupContext lookupContext; + + /// + /// Default constructor for EmsTemplateTests. + /// + public EmsTemplateTests() { - protected IConnectionFactory emsConnectionFactory; + this.PopulateProtectedVariables = true; - protected IConnectionFactory connectionFactory; - - //This is the 'raw' TIBCO type - protected ConnectionFactory jndiEmsConnectionFactory; - - protected IConnectionFactory cachingJndiConnectionFactory; - - protected EmsTemplate emsTemplate; - - protected SimpleGateway simpleGateway; - - - private Admin admin; - - private string queueName = "INT_TEST_QUEUE"; - - private Hashtable env = new Hashtable(); - - private LookupContext lookupContext; - - /// - /// Default constructor for EmsTemplateTests. - /// - public EmsTemplateTests() - { - this.PopulateProtectedVariables = true; - - env.Add(LookupContext.PROVIDER_URL, "tibjmsnaming://localhost:7222"); - env.Add(LookupContext.SECURITY_PRINCIPAL, "admin"); - env.Add(LookupContext.SECURITY_CREDENTIALS, ""); - lookupContext = new LookupContext(env); - } - - protected override void OnSetUp() - { - admin = new Admin("tcp://localhost:7222", "admin", ""); - Destination destination = null; - try - { - destination = (Destination) lookupContext.Lookup(queueName); - if (destination != null) admin.DestroyQueue(queueName); - } catch (NameNotFoundException) - {} - admin.CreateQueue(new QueueInfo(queueName)); - admin.BindQueue(queueName, queueName); - admin.PurgeQueue(queueName); - } - - - - - [Test] - public void ConvertAndSend() - { - Assert.NotNull(emsConnectionFactory); - Assert.NotNull(connectionFactory); - Assert.NotNull(jndiEmsConnectionFactory); - Assert.NotNull(cachingJndiConnectionFactory); - Assert.NotNull(emsTemplate); - - string msgText = "Hello World"; - - //Use with destination set at runtime - emsTemplate.ConvertAndSend("APP.TESTING", msgText); - AssertRecievedHelloWorldMessage(msgText, emsTemplate.ReceiveAndConvert("APP.TESTING")); - - //Now using default destination set via property - emsTemplate.DefaultDestinationName = "APP.TESTING"; - emsTemplate.ConvertAndSend(msgText); - AssertRecievedHelloWorldMessage(msgText, emsTemplate.ReceiveAndConvert()); - - //Now using destination oject - Destination destination = (Destination)lookupContext.Lookup(queueName); - - emsTemplate.ConvertAndSend(destination, msgText); - AssertRecievedHelloWorldMessage(msgText, emsTemplate.ReceiveAndConvert(destination)); - } - - private void AssertRecievedHelloWorldMessage(string msgText, object message) - { - Assert.NotNull(message); - string text = message as string; - Assert.NotNull(text); - Assert.AreEqual(msgText, text); - } - - #region Overrides of AbstractDependencyInjectionSpringContextTests - - /// - /// Subclasses must implement this property to return the locations of their - /// config files. A plain path will be treated as a file system location. - /// - /// An array of config locations - protected override string[] ConfigLocations - { - get { return new string[] { "assembly://Spring.Messaging.Ems.Integration.Tests/Spring.Messaging.Ems.Core/EmsTemplateTests.xml" }; } - } - - #endregion + env.Add(LookupContext.PROVIDER_URL, "tibjmsnaming://localhost:7222"); + env.Add(LookupContext.SECURITY_PRINCIPAL, "admin"); + env.Add(LookupContext.SECURITY_CREDENTIALS, ""); + lookupContext = new LookupContext(env); } -} \ No newline at end of file + + protected override void OnSetUp() + { + admin = new Admin("tcp://localhost:7222", "admin", ""); + Destination destination = null; + try + { + destination = (Destination) lookupContext.Lookup(queueName); + if (destination != null) admin.DestroyQueue(queueName); + } + catch (NameNotFoundException) + { + } + + admin.CreateQueue(new QueueInfo(queueName)); + admin.BindQueue(queueName, queueName); + admin.PurgeQueue(queueName); + } + + [Test] + public void ConvertAndSend() + { + Assert.NotNull(emsConnectionFactory); + Assert.NotNull(connectionFactory); + Assert.NotNull(jndiEmsConnectionFactory); + Assert.NotNull(cachingJndiConnectionFactory); + Assert.NotNull(emsTemplate); + + string msgText = "Hello World"; + + //Use with destination set at runtime + emsTemplate.ConvertAndSend("APP.TESTING", msgText); + AssertRecievedHelloWorldMessage(msgText, emsTemplate.ReceiveAndConvert("APP.TESTING")); + + //Now using default destination set via property + emsTemplate.DefaultDestinationName = "APP.TESTING"; + emsTemplate.ConvertAndSend(msgText); + AssertRecievedHelloWorldMessage(msgText, emsTemplate.ReceiveAndConvert()); + + //Now using destination oject + Destination destination = (Destination) lookupContext.Lookup(queueName); + + emsTemplate.ConvertAndSend(destination, msgText); + AssertRecievedHelloWorldMessage(msgText, emsTemplate.ReceiveAndConvert(destination)); + } + + private void AssertRecievedHelloWorldMessage(string msgText, object message) + { + Assert.NotNull(message); + string text = message as string; + Assert.NotNull(text); + Assert.AreEqual(msgText, text); + } + + #region Overrides of AbstractDependencyInjectionSpringContextTests + + /// + /// Subclasses must implement this property to return the locations of their + /// config files. A plain path will be treated as a file system location. + /// + /// An array of config locations + protected override string[] ConfigLocations + { + get { return new string[] { "assembly://Spring.Messaging.Ems.Integration.Tests/Spring.Messaging.Ems.Core/EmsTemplateTests.xml" }; } + } + + #endregion +} diff --git a/test/Spring/Spring.Messaging.Ems.Integration.Tests/Messaging/Ems/Core/EmsTemplateTests.xml b/test/Spring/Spring.Messaging.Ems.Integration.Tests/Messaging/Ems/Core/EmsTemplateTests.xml index 3c2d056e..a0f71248 100644 --- a/test/Spring/Spring.Messaging.Ems.Integration.Tests/Messaging/Ems/Core/EmsTemplateTests.xml +++ b/test/Spring/Spring.Messaging.Ems.Integration.Tests/Messaging/Ems/Core/EmsTemplateTests.xml @@ -1,74 +1,75 @@  + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:ems="http://www.springframework.net/ems"> - - - - - - - - - - + - - - - - - + + + - - - - - - - - - - - - - - - - - - + - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - diff --git a/test/Spring/Spring.Messaging.Ems.Integration.Tests/Messaging/Ems/Core/SimpleGateway.cs b/test/Spring/Spring.Messaging.Ems.Integration.Tests/Messaging/Ems/Core/SimpleGateway.cs index 075ec1e9..9ab4c7fd 100644 --- a/test/Spring/Spring.Messaging.Ems.Integration.Tests/Messaging/Ems/Core/SimpleGateway.cs +++ b/test/Spring/Spring.Messaging.Ems.Integration.Tests/Messaging/Ems/Core/SimpleGateway.cs @@ -1,35 +1,34 @@ using System.Collections; using Spring.Messaging.Ems.Common; -namespace Spring.Messaging.Ems.Core -{ - public class SimpleGateway : EmsGatewaySupport - { - public void Publish(string ticker, double price) - { - EmsTemplate.SendWithDelegate("APP.STOCK.MARKETDATA", - delegate(ISession session) - { - MapMessage message = session.CreateMapMessage(); - message.SetString("TICKER", ticker); - message.SetDouble("PRICE", price); - message.Priority = 5; - return message; - }); - } +namespace Spring.Messaging.Ems.Core; - public void PublishUsingDict(string ticker, double price) - { - IDictionary marketData = new Hashtable(); - marketData.Add("TICKER", ticker); - marketData.Add("PRICE", price); - EmsTemplate.ConvertAndSendWithDelegate("APP.STOCK.MARKETDATA", marketData, - delegate(Message message) - { - message.Priority = 5; - message.CorrelationID = new Guid().ToString(); - return message; - }); - } +public class SimpleGateway : EmsGatewaySupport +{ + public void Publish(string ticker, double price) + { + EmsTemplate.SendWithDelegate("APP.STOCK.MARKETDATA", + delegate(ISession session) + { + MapMessage message = session.CreateMapMessage(); + message.SetString("TICKER", ticker); + message.SetDouble("PRICE", price); + message.Priority = 5; + return message; + }); } -} + + public void PublishUsingDict(string ticker, double price) + { + IDictionary marketData = new Hashtable(); + marketData.Add("TICKER", ticker); + marketData.Add("PRICE", price); + EmsTemplate.ConvertAndSendWithDelegate("APP.STOCK.MARKETDATA", marketData, + delegate(Message message) + { + message.Priority = 5; + message.CorrelationID = new Guid().ToString(); + return message; + }); + } +} \ No newline at end of file diff --git a/test/Spring/Spring.Messaging.Ems.Integration.Tests/Messaging/Ems/Core/SimpleMessageListener.cs b/test/Spring/Spring.Messaging.Ems.Integration.Tests/Messaging/Ems/Core/SimpleMessageListener.cs index 322e3858..9da7ffe6 100644 --- a/test/Spring/Spring.Messaging.Ems.Integration.Tests/Messaging/Ems/Core/SimpleMessageListener.cs +++ b/test/Spring/Spring.Messaging.Ems.Integration.Tests/Messaging/Ems/Core/SimpleMessageListener.cs @@ -1,31 +1,30 @@ - using Microsoft.Extensions.Logging; -namespace Spring.Messaging.Ems.Core +namespace Spring.Messaging.Ems.Core; + +public class SimpleMessageListener : IMessageListener { - public class SimpleMessageListener : IMessageListener + private static readonly ILogger LOG = LogManager.GetLogger(); + + private int messageCount; + + public int MessageCount { - private static readonly ILogger LOG = LogManager.GetLogger(); + get { return messageCount; } + } - private int messageCount; - - public int MessageCount + public void OnMessage(Message message) + { + messageCount++; + LOG.LogDebug("Message listener count = " + messageCount); + TextMessage textMessage = message as TextMessage; + if (textMessage != null) { - get { return messageCount; } + LOG.LogInformation("Message Text = " + textMessage.Text); } - - public void OnMessage(Message message) - { - messageCount++; - LOG.LogDebug("Message listener count = " + messageCount); - TextMessage textMessage = message as TextMessage; - if (textMessage != null) - { - LOG.LogInformation("Message Text = " + textMessage.Text); - } else - { - LOG.LogWarning("Can not process message of type " + message.GetType()); - } + else + { + LOG.LogWarning("Can not process message of type " + message.GetType()); } } } diff --git a/test/Spring/Spring.Messaging.Ems.Integration.Tests/Messaging/Ems/Core/SimplePublisher.cs b/test/Spring/Spring.Messaging.Ems.Integration.Tests/Messaging/Ems/Core/SimplePublisher.cs index 251b1738..7fddc00c 100644 --- a/test/Spring/Spring.Messaging.Ems.Integration.Tests/Messaging/Ems/Core/SimplePublisher.cs +++ b/test/Spring/Spring.Messaging.Ems.Integration.Tests/Messaging/Ems/Core/SimplePublisher.cs @@ -1,27 +1,26 @@ using Spring.Messaging.Ems.Common; -namespace Spring.Messaging.Ems.Core +namespace Spring.Messaging.Ems.Core; + +public class SimplePublisher { - public class SimplePublisher + private EmsTemplate emsTemplate; + + public SimplePublisher() { - private EmsTemplate emsTemplate; + emsTemplate = new EmsTemplate(new EmsConnectionFactory("tcp://localhost:7222")); + } - public SimplePublisher() - { - emsTemplate = new EmsTemplate(new EmsConnectionFactory("tcp://localhost:7222")); - } - - public void Publish(string ticker, double price) - { - emsTemplate.SendWithDelegate("APP.STOCK.MARKETDATA", - delegate(ISession session) - { - MapMessage message = session.CreateMapMessage(); - message.SetString("TICKER", ticker); - message.SetDouble("PRICE", price); - message.Priority = 5; - return message; - }); - } + public void Publish(string ticker, double price) + { + emsTemplate.SendWithDelegate("APP.STOCK.MARKETDATA", + delegate(ISession session) + { + MapMessage message = session.CreateMapMessage(); + message.SetString("TICKER", ticker); + message.SetDouble("PRICE", price); + message.Priority = 5; + return message; + }); } } \ No newline at end of file diff --git a/test/Spring/Spring.Messaging.Ems.Integration.Tests/Messaging/Ems/Listener/SimpleMessageListenerContainerTests.cs b/test/Spring/Spring.Messaging.Ems.Integration.Tests/Messaging/Ems/Listener/SimpleMessageListenerContainerTests.cs index d392ee37..103f1c39 100644 --- a/test/Spring/Spring.Messaging.Ems.Integration.Tests/Messaging/Ems/Listener/SimpleMessageListenerContainerTests.cs +++ b/test/Spring/Spring.Messaging.Ems.Integration.Tests/Messaging/Ems/Listener/SimpleMessageListenerContainerTests.cs @@ -22,47 +22,42 @@ using NUnit.Framework; using Spring.Messaging.Ems.Core; using Spring.Testing.NUnit; -namespace Spring.Messaging.Ems.Listener +namespace Spring.Messaging.Ems.Listener; + +/// +/// Integration tests for SimpleMessageListenerContainer +/// +/// Mark Pollack +[TestFixture] +public class SimpleMessageListenerContainerTests : AbstractDependencyInjectionSpringContextTests { + protected SimpleGateway simpleGateway; + + protected SimpleMessageListener simpleMessageListener; + /// - /// Integration tests for SimpleMessageListenerContainer + /// Enable DI based on protected field names /// - /// Mark Pollack - [TestFixture] - public class SimpleMessageListenerContainerTests : AbstractDependencyInjectionSpringContextTests + public SimpleMessageListenerContainerTests() { - protected SimpleGateway simpleGateway; - - protected SimpleMessageListener simpleMessageListener; - - - /// - /// Enable DI based on protected field names - /// - public SimpleMessageListenerContainerTests() - { - this.PopulateProtectedVariables = true; - } - - [Test] - public void SendAndRecieveAsync() - { - Assert.AreEqual(0, simpleMessageListener.MessageCount); - simpleGateway.Publish("CSCO", 123.45); - Thread.Sleep(1000); - Assert.AreEqual(1, simpleMessageListener.MessageCount); - - } - - #region Overrides of AbstractDependencyInjectionSpringContextTests - - protected override string[] ConfigLocations - { - get { return new string[] { "assembly://Spring.Messaging.Ems.Integration.Tests/Spring.Messaging.Ems.Listener/SimpleMessageListenerContainerTests.xml" }; } - - } - - #endregion + this.PopulateProtectedVariables = true; } + [Test] + public void SendAndRecieveAsync() + { + Assert.AreEqual(0, simpleMessageListener.MessageCount); + simpleGateway.Publish("CSCO", 123.45); + Thread.Sleep(1000); + Assert.AreEqual(1, simpleMessageListener.MessageCount); + } + + #region Overrides of AbstractDependencyInjectionSpringContextTests + + protected override string[] ConfigLocations + { + get { return new string[] { "assembly://Spring.Messaging.Ems.Integration.Tests/Spring.Messaging.Ems.Listener/SimpleMessageListenerContainerTests.xml" }; } + } + + #endregion } diff --git a/test/Spring/Spring.Messaging.Ems.Integration.Tests/Messaging/Ems/Listener/SimpleMessageListenerContainerTests.xml b/test/Spring/Spring.Messaging.Ems.Integration.Tests/Messaging/Ems/Listener/SimpleMessageListenerContainerTests.xml index 07e9e6bb..0528275e 100644 --- a/test/Spring/Spring.Messaging.Ems.Integration.Tests/Messaging/Ems/Listener/SimpleMessageListenerContainerTests.xml +++ b/test/Spring/Spring.Messaging.Ems.Integration.Tests/Messaging/Ems/Listener/SimpleMessageListenerContainerTests.xml @@ -1,33 +1,34 @@  + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:ems="http://www.springframework.net/ems"> - - - - - - - - - - - - - - - - + - - - - + + + + + + + + + - - + + + + + + + + + + + + diff --git a/test/Spring/Spring.Messaging.Nms.Integration.Tests/Messaging/Nms/Core/NmsTemplateTests.cs b/test/Spring/Spring.Messaging.Nms.Integration.Tests/Messaging/Nms/Core/NmsTemplateTests.cs index 29f9a55d..ef32e2ca 100644 --- a/test/Spring/Spring.Messaging.Nms.Integration.Tests/Messaging/Nms/Core/NmsTemplateTests.cs +++ b/test/Spring/Spring.Messaging.Nms.Integration.Tests/Messaging/Nms/Core/NmsTemplateTests.cs @@ -20,78 +20,75 @@ using Apache.NMS; using NUnit.Framework; - using Spring.Testing.NUnit; -namespace Spring.Messaging.Nms.Core +namespace Spring.Messaging.Nms.Core; + +[TestFixture] +public class NmsTemplateTests : AbstractDependencyInjectionSpringContextTests { - [TestFixture] - public class NmsTemplateTests : AbstractDependencyInjectionSpringContextTests + protected IConnectionFactory nmsConnectionFactory; + + protected IConnectionFactory connectionFactory; + + protected NmsTemplate nmsTemplate; + + /// + /// Default constructor for NmsTemplateTests. + /// + public NmsTemplateTests() { - protected IConnectionFactory nmsConnectionFactory; - - protected IConnectionFactory connectionFactory; - - protected NmsTemplate nmsTemplate; - - /// - /// Default constructor for NmsTemplateTests. - /// - public NmsTemplateTests() - { - this.PopulateProtectedVariables = true; - } + this.PopulateProtectedVariables = true; + } #if NETFRAMEWORK - [Test] - public void ConnectionThrowException() - { - var cf = new Apache.NMS.ActiveMQ.ConnectionFactory(); - cf.BrokerUri = new Uri("tcp://localaaahost:61616"); - Assert.Throws(() => cf.CreateConnection()); - } + [Test] + public void ConnectionThrowException() + { + var cf = new Apache.NMS.ActiveMQ.ConnectionFactory(); + cf.BrokerUri = new Uri("tcp://localaaahost:61616"); + Assert.Throws(() => cf.CreateConnection()); + } #endif - [Test] - public void ConvertAndSend() - { - Assert.NotNull(connectionFactory); - Assert.NotNull(nmsTemplate); + [Test] + public void ConvertAndSend() + { + Assert.NotNull(connectionFactory); + Assert.NotNull(nmsTemplate); - string msgText = "Hello World"; + string msgText = "Hello World"; - //Use with destination set at runtime - nmsTemplate.ConvertAndSend("APP.TESTING", msgText); + //Use with destination set at runtime + nmsTemplate.ConvertAndSend("APP.TESTING", msgText); - AssertRecievedHelloWorldMessage(msgText, nmsTemplate.ReceiveAndConvert("APP.TESTING")); + AssertRecievedHelloWorldMessage(msgText, nmsTemplate.ReceiveAndConvert("APP.TESTING")); - //Now using default destination set via property - nmsTemplate.DefaultDestinationName = "APP.TESTING"; - nmsTemplate.ConvertAndSend(msgText); - AssertRecievedHelloWorldMessage(msgText, nmsTemplate.ReceiveAndConvert()); - } - - - private void AssertRecievedHelloWorldMessage(string msgText, object message) - { - Assert.NotNull(message); - string text = message as string; - Assert.NotNull(text); - Assert.AreEqual(msgText, text); - } - - #region Overrides of AbstractDependencyInjectionSpringContextTests - - /// - /// Subclasses must implement this property to return the locations of their - /// config files. A plain path will be treated as a file system location. - /// - /// An array of config locations - protected override string[] ConfigLocations - { - get { return new string[] {"assembly://Spring.Messaging.Nms.Integration.Tests/Spring.Messaging.Nms.Core/NmsTemplateTests.xml"}; } - } - - #endregion + //Now using default destination set via property + nmsTemplate.DefaultDestinationName = "APP.TESTING"; + nmsTemplate.ConvertAndSend(msgText); + AssertRecievedHelloWorldMessage(msgText, nmsTemplate.ReceiveAndConvert()); } + + private void AssertRecievedHelloWorldMessage(string msgText, object message) + { + Assert.NotNull(message); + string text = message as string; + Assert.NotNull(text); + Assert.AreEqual(msgText, text); + } + + #region Overrides of AbstractDependencyInjectionSpringContextTests + + /// + /// Subclasses must implement this property to return the locations of their + /// config files. A plain path will be treated as a file system location. + /// + /// An array of config locations + protected override string[] ConfigLocations + { + get { return new string[] { "assembly://Spring.Messaging.Nms.Integration.Tests/Spring.Messaging.Nms.Core/NmsTemplateTests.xml" }; } + } + + #endregion } diff --git a/test/Spring/Spring.Messaging.Nms.Integration.Tests/Messaging/Nms/Core/NmsTemplateTests.xml b/test/Spring/Spring.Messaging.Nms.Integration.Tests/Messaging/Nms/Core/NmsTemplateTests.xml index 4b766b64..0dd5bb22 100644 --- a/test/Spring/Spring.Messaging.Nms.Integration.Tests/Messaging/Nms/Core/NmsTemplateTests.xml +++ b/test/Spring/Spring.Messaging.Nms.Integration.Tests/Messaging/Nms/Core/NmsTemplateTests.xml @@ -1,25 +1,26 @@  + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:nms="http://www.springframework.net/nms"> - - - - + + + + - - - - - - - - + + + + + + + + - - - + + + diff --git a/test/Spring/Spring.Messaging.Nms.Integration.Tests/Messaging/Nms/Core/SimpleGateway.cs b/test/Spring/Spring.Messaging.Nms.Integration.Tests/Messaging/Nms/Core/SimpleGateway.cs index 8397e081..e55018da 100644 --- a/test/Spring/Spring.Messaging.Nms.Integration.Tests/Messaging/Nms/Core/SimpleGateway.cs +++ b/test/Spring/Spring.Messaging.Nms.Integration.Tests/Messaging/Nms/Core/SimpleGateway.cs @@ -21,36 +21,34 @@ using System.Collections; using Apache.NMS; -namespace Spring.Messaging.Nms.Core -{ - public class SimpleGateway: NmsGatewaySupport - { - public void Publish(string ticker, double price) - { - NmsTemplate.SendWithDelegate("APP.STOCK.MARKETDATA", - delegate(ISession session) - { - IMapMessage message = session.CreateMapMessage(); - message.Body.SetString("TICKER", ticker); - message.Body.SetDouble("PRICE", price); - message.NMSPriority = MsgPriority.Normal; - return message; - }); - } +namespace Spring.Messaging.Nms.Core; - public void PublishUsingDict(string ticker, double price) - { - IDictionary marketData = new Hashtable(); - marketData.Add("TICKER", ticker); - marketData.Add("PRICE", price); - NmsTemplate.ConvertAndSendWithDelegate("APP.STOCK.MARKETDATA", marketData, - delegate(IMessage message) - { - message.NMSPriority = MsgPriority.Normal; - message.NMSCorrelationID = new Guid().ToString(); - return message; - }); - } +public class SimpleGateway : NmsGatewaySupport +{ + public void Publish(string ticker, double price) + { + NmsTemplate.SendWithDelegate("APP.STOCK.MARKETDATA", + delegate(ISession session) + { + IMapMessage message = session.CreateMapMessage(); + message.Body.SetString("TICKER", ticker); + message.Body.SetDouble("PRICE", price); + message.NMSPriority = MsgPriority.Normal; + return message; + }); } + public void PublishUsingDict(string ticker, double price) + { + IDictionary marketData = new Hashtable(); + marketData.Add("TICKER", ticker); + marketData.Add("PRICE", price); + NmsTemplate.ConvertAndSendWithDelegate("APP.STOCK.MARKETDATA", marketData, + delegate(IMessage message) + { + message.NMSPriority = MsgPriority.Normal; + message.NMSCorrelationID = new Guid().ToString(); + return message; + }); + } } diff --git a/test/Spring/Spring.Messaging.Nms.Integration.Tests/Messaging/Nms/Core/SimpleMessageListener.cs b/test/Spring/Spring.Messaging.Nms.Integration.Tests/Messaging/Nms/Core/SimpleMessageListener.cs index 4f589e58..66374fac 100644 --- a/test/Spring/Spring.Messaging.Nms.Integration.Tests/Messaging/Nms/Core/SimpleMessageListener.cs +++ b/test/Spring/Spring.Messaging.Nms.Integration.Tests/Messaging/Nms/Core/SimpleMessageListener.cs @@ -21,37 +21,35 @@ using Apache.NMS; using Microsoft.Extensions.Logging; -namespace Spring.Messaging.Nms.Core +namespace Spring.Messaging.Nms.Core; + +public class SimpleMessageListener : IMessageListener { + private static readonly ILogger LOG = LogManager.GetLogger(); - public class SimpleMessageListener : IMessageListener + private int messageCount; + + public int MessageCount { - private static readonly ILogger LOG = LogManager.GetLogger(); - - private int messageCount; - - public int MessageCount - { - get { return messageCount; } - } - #region Implementation of IMessageListener - - public void OnMessage(IMessage message) - { - messageCount++; - LOG.LogDebug("Message listener count = " + messageCount); - ITextMessage textMessage = message as ITextMessage; - if (textMessage != null) - { - LOG.LogInformation("Message Text = " + textMessage.Text); - } - else - { - LOG.LogWarning("Can not process message of type " + message.GetType()); - } - } - - #endregion + get { return messageCount; } } + #region Implementation of IMessageListener + + public void OnMessage(IMessage message) + { + messageCount++; + LOG.LogDebug("Message listener count = " + messageCount); + ITextMessage textMessage = message as ITextMessage; + if (textMessage != null) + { + LOG.LogInformation("Message Text = " + textMessage.Text); + } + else + { + LOG.LogWarning("Can not process message of type " + message.GetType()); + } + } + + #endregion } diff --git a/test/Spring/Spring.Messaging.Nms.Integration.Tests/Messaging/Nms/Listener/SimpleMessageListenerContainerTests.cs b/test/Spring/Spring.Messaging.Nms.Integration.Tests/Messaging/Nms/Listener/SimpleMessageListenerContainerTests.cs index 7f9b8e28..7f57f49b 100644 --- a/test/Spring/Spring.Messaging.Nms.Integration.Tests/Messaging/Nms/Listener/SimpleMessageListenerContainerTests.cs +++ b/test/Spring/Spring.Messaging.Nms.Integration.Tests/Messaging/Nms/Listener/SimpleMessageListenerContainerTests.cs @@ -22,46 +22,40 @@ using NUnit.Framework; using Spring.Messaging.Nms.Core; using Spring.Testing.NUnit; -namespace Spring.Messaging.Nms.Listener +namespace Spring.Messaging.Nms.Listener; + +[TestFixture] +public class SimpleMessageListenerContainerTests : AbstractDependencyInjectionSpringContextTests { - [TestFixture] - public class SimpleMessageListenerContainerTests : AbstractDependencyInjectionSpringContextTests + protected SimpleGateway simpleGateway; + + protected SimpleMessageListener simpleMessageListener; + + /// + /// Enable DI based on protected field names + /// + public SimpleMessageListenerContainerTests() { - protected SimpleGateway simpleGateway; - - protected SimpleMessageListener simpleMessageListener; - - - /// - /// Enable DI based on protected field names - /// - public SimpleMessageListenerContainerTests() - { - this.PopulateProtectedVariables = true; - } - - [Test] - public void SendAndRecieveAsync() - { - Assert.NotNull(simpleGateway); - Assert.NotNull(simpleMessageListener); - Assert.AreEqual(0, simpleMessageListener.MessageCount); - simpleGateway.Publish("CSCO", 123.45); - Thread.Sleep(1000); - Assert.AreEqual(1, simpleMessageListener.MessageCount); - - } - - #region Overrides of AbstractDependencyInjectionSpringContextTests - - protected override string[] ConfigLocations - { - get { return new string[] { "assembly://Spring.Messaging.Nms.Integration.Tests/Spring.Messaging.Nms.Listener/SimpleMessageListenerContainerTests.xml" }; } - - } - - #endregion + this.PopulateProtectedVariables = true; } + [Test] + public void SendAndRecieveAsync() + { + Assert.NotNull(simpleGateway); + Assert.NotNull(simpleMessageListener); + Assert.AreEqual(0, simpleMessageListener.MessageCount); + simpleGateway.Publish("CSCO", 123.45); + Thread.Sleep(1000); + Assert.AreEqual(1, simpleMessageListener.MessageCount); + } + #region Overrides of AbstractDependencyInjectionSpringContextTests + + protected override string[] ConfigLocations + { + get { return new string[] { "assembly://Spring.Messaging.Nms.Integration.Tests/Spring.Messaging.Nms.Listener/SimpleMessageListenerContainerTests.xml" }; } + } + + #endregion } diff --git a/test/Spring/Spring.Messaging.Nms.Integration.Tests/Messaging/Nms/Listener/SimpleMessageListenerContainerTests.xml b/test/Spring/Spring.Messaging.Nms.Integration.Tests/Messaging/Nms/Listener/SimpleMessageListenerContainerTests.xml index ebad523b..68e1e8bf 100644 --- a/test/Spring/Spring.Messaging.Nms.Integration.Tests/Messaging/Nms/Listener/SimpleMessageListenerContainerTests.xml +++ b/test/Spring/Spring.Messaging.Nms.Integration.Tests/Messaging/Nms/Listener/SimpleMessageListenerContainerTests.xml @@ -1,35 +1,36 @@  + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:nms="http://www.springframework.net/nms"> - - - - + + + + - - - - - - - - + + + + + + + + - - - - + + + + - - - - + + + + - - + + diff --git a/test/Spring/Spring.Messaging.Nms.Tests/App.config b/test/Spring/Spring.Messaging.Nms.Tests/App.config index 60dedd5f..4ad359bf 100644 --- a/test/Spring/Spring.Messaging.Nms.Tests/App.config +++ b/test/Spring/Spring.Messaging.Nms.Tests/App.config @@ -15,9 +15,9 @@ See the License for the specific language governing permissions and limitations under the License. --> - + -
+
@@ -26,24 +26,24 @@ limitations under the License. - + - + - + diff --git a/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Config/NmsNamespaceHandlerTests.cs b/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Config/NmsNamespaceHandlerTests.cs index 67c92dfd..fb893fdf 100644 --- a/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Config/NmsNamespaceHandlerTests.cs +++ b/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Config/NmsNamespaceHandlerTests.cs @@ -21,9 +21,7 @@ #region Imports using Apache.NMS; - using FakeItEasy; - using NUnit.Framework; using Spring.Context; using Spring.Context.Support; @@ -36,111 +34,106 @@ using Spring.Objects.Factory.Xml; #endregion -namespace Spring.Messaging.Nms.Config +namespace Spring.Messaging.Nms.Config; + +/// +/// This class contains tests for +/// +/// Mark Pollack +/// $Id:$ +[TestFixture] +public class NmsNamespaceHandlerTests { - /// - /// This class contains tests for - /// - /// Mark Pollack - /// $Id:$ - [TestFixture] - public class NmsNamespaceHandlerTests + private static string DEFAULT_CONNECTION_FACTORY = "ConnectionFactory"; + private static string EXPLICIT_CONNECTION_FACTORY = "testConnectionFactory"; + private IApplicationContext ctx; + + [SetUp] + public void Setup() { - private static string DEFAULT_CONNECTION_FACTORY = "ConnectionFactory"; - private static string EXPLICIT_CONNECTION_FACTORY = "testConnectionFactory"; - private IApplicationContext ctx; + // WELLKNOWN + //NamespaceParserRegistry.RegisterParser(typeof(NmsNamespaceParser)); + ctx = new XmlApplicationContext(ReadOnlyXmlTestResource.GetFilePath("NmsNamespaceHandlerTests.xml", GetType())); + } - [SetUp] - public void Setup() + [Test] + public void Registered() + { + Assert.IsNotNull(NamespaceParserRegistry.GetParser("http://www.springframework.net/nms")); + } + + [Test] + public void ObjectsCreated() + { + var containers = ctx.GetObjects(); + Assert.AreEqual(3, containers.Count); + } + + [Test] + public void ContainerConfiguration() + { + var containers = ctx.GetObjects(); + IConnectionFactory defaultConnectionFactory = (IConnectionFactory) ctx.GetObject(DEFAULT_CONNECTION_FACTORY); + IConnectionFactory explicitConnectionFactory = (IConnectionFactory) ctx.GetObject(EXPLICIT_CONNECTION_FACTORY); + + int defaultConnectionFactoryCount = 0; + int explicitConnectionFactoryCount = 0; + foreach (KeyValuePair dictionaryEntry in containers) { - // WELLKNOWN - //NamespaceParserRegistry.RegisterParser(typeof(NmsNamespaceParser)); - ctx = new XmlApplicationContext(ReadOnlyXmlTestResource.GetFilePath("NmsNamespaceHandlerTests.xml", GetType())); - } - - [Test] - public void Registered() - { - Assert.IsNotNull(NamespaceParserRegistry.GetParser("http://www.springframework.net/nms")); - } - - [Test] - public void ObjectsCreated() - { - var containers = ctx.GetObjects(); - Assert.AreEqual(3, containers.Count); - } - - [Test] - public void ContainerConfiguration() - { - var containers = ctx.GetObjects(); - IConnectionFactory defaultConnectionFactory = (IConnectionFactory) ctx.GetObject(DEFAULT_CONNECTION_FACTORY); - IConnectionFactory explicitConnectionFactory = (IConnectionFactory) ctx.GetObject(EXPLICIT_CONNECTION_FACTORY); - - - int defaultConnectionFactoryCount = 0; - int explicitConnectionFactoryCount = 0; - foreach (KeyValuePair dictionaryEntry in containers) + SimpleMessageListenerContainer container = dictionaryEntry.Value; + if (container.ConnectionFactory.Equals(defaultConnectionFactory)) { - SimpleMessageListenerContainer container = dictionaryEntry.Value; - if (container.ConnectionFactory.Equals(defaultConnectionFactory)) - { - defaultConnectionFactoryCount++; - } - else if (container.ConnectionFactory.Equals(explicitConnectionFactory)) - { - explicitConnectionFactoryCount++; - } + defaultConnectionFactoryCount++; + } + else if (container.ConnectionFactory.Equals(explicitConnectionFactory)) + { + explicitConnectionFactoryCount++; } - - Assert.AreEqual(1, defaultConnectionFactoryCount, "1 container should have the default connectionFactory"); - Assert.AreEqual(2, explicitConnectionFactoryCount, "2 containers should have the explicit connectionFactory"); - } - [Test] - public void Listeners() - { - TestObject testObject1 = (TestObject) ctx.GetObject("testObject1"); - TestObject testObject2 = (TestObject) ctx.GetObject("testObject2"); - TestMessageListener testObject3 = (TestMessageListener) ctx.GetObject("testObject3"); + Assert.AreEqual(1, defaultConnectionFactoryCount, "1 container should have the default connectionFactory"); + Assert.AreEqual(2, explicitConnectionFactoryCount, "2 containers should have the explicit connectionFactory"); + } - Assert.IsNull(testObject1.Name); - Assert.IsNull(testObject2.Name); - Assert.IsNull(testObject3.Message); + [Test] + public void Listeners() + { + TestObject testObject1 = (TestObject) ctx.GetObject("testObject1"); + TestObject testObject2 = (TestObject) ctx.GetObject("testObject2"); + TestMessageListener testObject3 = (TestMessageListener) ctx.GetObject("testObject3"); + Assert.IsNull(testObject1.Name); + Assert.IsNull(testObject2.Name); + Assert.IsNull(testObject3.Message); - ITextMessage message1 = A.Fake(); - A.CallTo(() => message1.Text).Returns("Test1"); + ITextMessage message1 = A.Fake(); + A.CallTo(() => message1.Text).Returns("Test1"); - IMessageListener listener1 = GetListener("listener1"); - listener1.OnMessage(message1); - Assert.AreEqual("Test1", testObject1.Name); + IMessageListener listener1 = GetListener("listener1"); + listener1.OnMessage(message1); + Assert.AreEqual("Test1", testObject1.Name); + ITextMessage message2 = A.Fake(); + A.CallTo(() => message2.Text).Returns("Test1"); - ITextMessage message2 = A.Fake(); - A.CallTo(() => message2.Text).Returns("Test1"); + IMessageListener listener2 = GetListener("listener2"); + listener2.OnMessage(message2); + A.CallTo(() => message2.Text).MustHaveHappened(); - IMessageListener listener2 = GetListener("listener2"); - listener2.OnMessage(message2); - A.CallTo(() => message2.Text).MustHaveHappened(); + ITextMessage message3 = A.Fake(); - ITextMessage message3 = A.Fake(); + //Default naming strategy is to use full type name + # + number + string className = typeof(SimpleMessageListenerContainer).FullName; + string targetName = className + ObjectDefinitionReaderUtils.GENERATED_OBJECT_NAME_SEPARATOR + "0"; + IMessageListener listener3 = GetListener(targetName); + listener3.OnMessage(message3); + Assert.AreSame(message3, testObject3.Message); + } - //Default naming strategy is to use full type name + # + number - string className = typeof(SimpleMessageListenerContainer).FullName; - string targetName = className + ObjectDefinitionReaderUtils.GENERATED_OBJECT_NAME_SEPARATOR + "0"; - IMessageListener listener3 = GetListener(targetName); - listener3.OnMessage(message3); - Assert.AreSame(message3, testObject3.Message); - } - - private IMessageListener GetListener(string containerObjectName) - { - SimpleMessageListenerContainer container = - (SimpleMessageListenerContainer) ctx.GetObject(containerObjectName); - return (IMessageListener) container.MessageListener; - } + private IMessageListener GetListener(string containerObjectName) + { + SimpleMessageListenerContainer container = + (SimpleMessageListenerContainer) ctx.GetObject(containerObjectName); + return (IMessageListener) container.MessageListener; } } diff --git a/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Config/NmsNamespaceHandlerTests.xml b/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Config/NmsNamespaceHandlerTests.xml index 54d89e41..a4ed0973 100644 --- a/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Config/NmsNamespaceHandlerTests.xml +++ b/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Config/NmsNamespaceHandlerTests.xml @@ -1,51 +1,55 @@  + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:nms="http://www.springframework.net/nms"> - - - - + + + + - - - + + + - - + + - + - + - + - + - + - + - + - - - - - - - - - + + + + + + + + + diff --git a/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Connections/CachedSessionTests.cs b/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Connections/CachedSessionTests.cs index b2b3799d..255fa260 100644 --- a/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Connections/CachedSessionTests.cs +++ b/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Connections/CachedSessionTests.cs @@ -21,44 +21,43 @@ using Apache.NMS; using NUnit.Framework; -namespace Spring.Messaging.Nms.Connections +namespace Spring.Messaging.Nms.Connections; + +/// +/// Test suite for . +/// +/// Andreas Kluth +[TestFixture] +public class CachedSessionTests { /// - /// Test suite for . + /// Validates that events raised by the session cached are propagated to a registered consumer. /// - /// Andreas Kluth - [TestFixture] - public class CachedSessionTests + [Test] + public void EventsArePropagated() { - /// - /// Validates that events raised by the session cached are propagated to a registered consumer. - /// - [Test] - public void EventsArePropagated() - { - TestSession targetSession = new TestSession(); - CachedSession session = CreateCachedSession(targetSession); + TestSession targetSession = new TestSession(); + CachedSession session = CreateCachedSession(targetSession); - bool committedWasRaised = false; - bool rolledBackWasRaised = false; - bool startedWasRaised = false; + bool committedWasRaised = false; + bool rolledBackWasRaised = false; + bool startedWasRaised = false; - session.TransactionCommittedListener += _ => committedWasRaised = true; - session.TransactionRolledBackListener += _ => rolledBackWasRaised = true; - session.TransactionStartedListener += _ => startedWasRaised = true; + session.TransactionCommittedListener += _ => committedWasRaised = true; + session.TransactionRolledBackListener += _ => rolledBackWasRaised = true; + session.TransactionStartedListener += _ => startedWasRaised = true; - targetSession.TransactionCommitted(); - targetSession.TransactionRolledBack(); - targetSession.TransactionStarted(); + targetSession.TransactionCommitted(); + targetSession.TransactionRolledBack(); + targetSession.TransactionStarted(); - Assert.IsTrue(committedWasRaised); - Assert.IsTrue(rolledBackWasRaised); - Assert.IsTrue(startedWasRaised); - } + Assert.IsTrue(committedWasRaised); + Assert.IsTrue(rolledBackWasRaised); + Assert.IsTrue(startedWasRaised); + } - private CachedSession CreateCachedSession(ISession targetSession) - { - return new CachedSession(targetSession, new List(), new CachingConnectionFactory()); - } + private CachedSession CreateCachedSession(ISession targetSession) + { + return new CachedSession(targetSession, new List(), new CachingConnectionFactory()); } } diff --git a/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Connections/CachingConnectionFactoryTests.cs b/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Connections/CachingConnectionFactoryTests.cs index 82a7a94e..cb495d4e 100644 --- a/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Connections/CachingConnectionFactoryTests.cs +++ b/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Connections/CachingConnectionFactoryTests.cs @@ -22,203 +22,197 @@ using Apache.NMS; using FakeItEasy; using NUnit.Framework; -namespace Spring.Messaging.Nms.Connections +namespace Spring.Messaging.Nms.Connections; + +/// +/// This class contains tests for CachingConnectionFactory +/// +/// Mark Pollack +[TestFixture] +public class CachingConnectionFactoryTests { - /// - /// This class contains tests for CachingConnectionFactory - /// - /// Mark Pollack - [TestFixture] - public class CachingConnectionFactoryTests + [Test] + public void CachedSession() { - [Test] - public void CachedSession() - { - IConnectionFactory connectionFactory = CreateConnectionFactory(); + IConnectionFactory connectionFactory = CreateConnectionFactory(); - CachingConnectionFactory cachingConnectionFactory = new CachingConnectionFactory(); - cachingConnectionFactory.TargetConnectionFactory = connectionFactory; + CachingConnectionFactory cachingConnectionFactory = new CachingConnectionFactory(); + cachingConnectionFactory.TargetConnectionFactory = connectionFactory; - IConnection con1 = cachingConnectionFactory.CreateConnection(); + IConnection con1 = cachingConnectionFactory.CreateConnection(); - ISession session1 = con1.CreateSession(AcknowledgementMode.Transactional); - TestSession testSession = GetTestSession(session1); - Assert.AreEqual(1, testSession.CreatedCount); - Assert.AreEqual(0, testSession.CloseCount); + ISession session1 = con1.CreateSession(AcknowledgementMode.Transactional); + TestSession testSession = GetTestSession(session1); + Assert.AreEqual(1, testSession.CreatedCount); + Assert.AreEqual(0, testSession.CloseCount); + session1.Close(); // won't close, will put in session cache. + Assert.AreEqual(0, testSession.CloseCount); - session1.Close(); // won't close, will put in session cache. - Assert.AreEqual(0, testSession.CloseCount); - - ISession session2 = con1.CreateSession(AcknowledgementMode.Transactional); + ISession session2 = con1.CreateSession(AcknowledgementMode.Transactional); + TestSession testSession2 = GetTestSession(session2); - TestSession testSession2 = GetTestSession(session2); - + Assert.AreSame(testSession, testSession2); - Assert.AreSame(testSession, testSession2); + Assert.AreEqual(1, testSession.CreatedCount); + Assert.AreEqual(0, testSession.CloseCount); - Assert.AreEqual(1, testSession.CreatedCount); - Assert.AreEqual(0, testSession.CloseCount); + //don't explicitly call close on + } - //don't explicitly call close on - } + private static TestSession GetTestSession(ISession session1) + { + CachedSession cachedSession = session1 as CachedSession; + Assert.IsNotNull(cachedSession); + TestSession testSession = cachedSession.TargetSession as TestSession; + Assert.IsNotNull(testSession); + return testSession; + } - private static TestSession GetTestSession(ISession session1) - { - CachedSession cachedSession = session1 as CachedSession; - Assert.IsNotNull(cachedSession); - TestSession testSession = cachedSession.TargetSession as TestSession; - Assert.IsNotNull(testSession); - return testSession; - } + [Test] + public void CachedSessionTwoRequests() + { + IConnectionFactory connectionFactory = CreateConnectionFactory(); - [Test] - public void CachedSessionTwoRequests() - { - IConnectionFactory connectionFactory = CreateConnectionFactory(); + CachingConnectionFactory cachingConnectionFactory = new CachingConnectionFactory(); + cachingConnectionFactory.TargetConnectionFactory = connectionFactory; + IConnection con1 = cachingConnectionFactory.CreateConnection(); - CachingConnectionFactory cachingConnectionFactory = new CachingConnectionFactory(); - cachingConnectionFactory.TargetConnectionFactory = connectionFactory; - IConnection con1 = cachingConnectionFactory.CreateConnection(); + ISession session1 = con1.CreateSession(AcknowledgementMode.Transactional); + TestSession testSession1 = GetTestSession(session1); + Assert.AreEqual(1, testSession1.CreatedCount); + Assert.AreEqual(0, testSession1.CloseCount); - ISession session1 = con1.CreateSession(AcknowledgementMode.Transactional); - TestSession testSession1 = GetTestSession(session1); - Assert.AreEqual(1, testSession1.CreatedCount); - Assert.AreEqual(0, testSession1.CloseCount); + //will create a new one, not in the cache. + ISession session2 = con1.CreateSession(AcknowledgementMode.Transactional); + TestSession testSession2 = GetTestSession(session2); + Assert.AreEqual(1, testSession2.CreatedCount); + Assert.AreEqual(0, testSession2.CloseCount); + Assert.AreNotSame(testSession1, testSession2); - //will create a new one, not in the cache. - ISession session2 = con1.CreateSession(AcknowledgementMode.Transactional); - TestSession testSession2 = GetTestSession(session2); - Assert.AreEqual(1, testSession2.CreatedCount); - Assert.AreEqual(0, testSession2.CloseCount); + Assert.AreNotSame(session1, session2); - Assert.AreNotSame(testSession1, testSession2); + session1.Close(); // will be put in the cache - Assert.AreNotSame(session1, session2); + ISession session3 = con1.CreateSession(AcknowledgementMode.Transactional); + TestSession testSession3 = GetTestSession(session3); + Assert.AreSame(testSession1, testSession3); + Assert.AreSame(session1, session3); + Assert.AreEqual(1, testSession1.CreatedCount); + Assert.AreEqual(0, testSession1.CloseCount); + } - session1.Close(); // will be put in the cache + /// + /// Tests that the same underlying instance of the message producer is returned after + /// creating a session, creating the producer (A), closing the session, and creating another + /// producer (B). Assert that (A)=(B). + /// + [Test] + public void CachedMessageProducer() + { + IConnectionFactory connectionFactory = CreateConnectionFactory(); - ISession session3 = con1.CreateSession(AcknowledgementMode.Transactional); - TestSession testSession3 = GetTestSession(session3); - Assert.AreSame(testSession1, testSession3); - Assert.AreSame(session1, session3); - Assert.AreEqual(1, testSession1.CreatedCount); - Assert.AreEqual(0, testSession1.CloseCount); - } + CachingConnectionFactory cachingConnectionFactory = new CachingConnectionFactory(); + cachingConnectionFactory.TargetConnectionFactory = connectionFactory; + IConnection con1 = cachingConnectionFactory.CreateConnection(); - /// - /// Tests that the same underlying instance of the message producer is returned after - /// creating a session, creating the producer (A), closing the session, and creating another - /// producer (B). Assert that (A)=(B). - /// - [Test] - public void CachedMessageProducer() - { - IConnectionFactory connectionFactory = CreateConnectionFactory(); - - CachingConnectionFactory cachingConnectionFactory = new CachingConnectionFactory(); - cachingConnectionFactory.TargetConnectionFactory = connectionFactory; - IConnection con1 = cachingConnectionFactory.CreateConnection(); + ISession sessionA = con1.CreateSession(AcknowledgementMode.Transactional); + IMessageProducer producerA = sessionA.CreateProducer(); + TestMessageProducer tmpA = GetTestMessageProducer(producerA); - ISession sessionA = con1.CreateSession(AcknowledgementMode.Transactional); - IMessageProducer producerA = sessionA.CreateProducer(); - TestMessageProducer tmpA = GetTestMessageProducer(producerA); + sessionA.Close(); - sessionA.Close(); + ISession sessionB = con1.CreateSession(AcknowledgementMode.Transactional); + IMessageProducer producerB = sessionB.CreateProducer(); + TestMessageProducer tmpB = GetTestMessageProducer(producerB); - ISession sessionB = con1.CreateSession(AcknowledgementMode.Transactional); - IMessageProducer producerB = sessionB.CreateProducer(); - TestMessageProducer tmpB = GetTestMessageProducer(producerB); - - Assert.AreSame(tmpA, tmpB); - } + Assert.AreSame(tmpA, tmpB); + } - [Test] - public void CachedMessageProducerTwoRequests() - { - IConnectionFactory connectionFactory = CreateConnectionFactory(); + [Test] + public void CachedMessageProducerTwoRequests() + { + IConnectionFactory connectionFactory = CreateConnectionFactory(); - CachingConnectionFactory cachingConnectionFactory = new CachingConnectionFactory(); - cachingConnectionFactory.TargetConnectionFactory = connectionFactory; - IConnection con1 = cachingConnectionFactory.CreateConnection(); + CachingConnectionFactory cachingConnectionFactory = new CachingConnectionFactory(); + cachingConnectionFactory.TargetConnectionFactory = connectionFactory; + IConnection con1 = cachingConnectionFactory.CreateConnection(); - ISession sessionA = con1.CreateSession(AcknowledgementMode.Transactional); - IMessageProducer producerA = sessionA.CreateProducer(); - TestMessageProducer tmpA = GetTestMessageProducer(producerA); + ISession sessionA = con1.CreateSession(AcknowledgementMode.Transactional); + IMessageProducer producerA = sessionA.CreateProducer(); + TestMessageProducer tmpA = GetTestMessageProducer(producerA); - - ISession sessionB = con1.CreateSession(AcknowledgementMode.Transactional); - IMessageProducer producerB = sessionB.CreateProducer(); - TestMessageProducer tmpB = GetTestMessageProducer(producerB); - - Assert.AreNotSame(tmpA, tmpB); + ISession sessionB = con1.CreateSession(AcknowledgementMode.Transactional); + IMessageProducer producerB = sessionB.CreateProducer(); + TestMessageProducer tmpB = GetTestMessageProducer(producerB); - sessionA.Close(); + Assert.AreNotSame(tmpA, tmpB); - ISession sessionC = con1.CreateSession(AcknowledgementMode.Transactional); - IMessageProducer producerC = sessionC.CreateProducer(); - TestMessageProducer tmpC = GetTestMessageProducer(producerC); + sessionA.Close(); - Assert.AreSame(tmpA, tmpC); - } + ISession sessionC = con1.CreateSession(AcknowledgementMode.Transactional); + IMessageProducer producerC = sessionC.CreateProducer(); + TestMessageProducer tmpC = GetTestMessageProducer(producerC); + + Assert.AreSame(tmpA, tmpC); + } #if NETFRAMEWORK - /// - /// Tests that the same underlying instance of the message consumer is returned after - /// creating a session, creating the consumer (A), closing the session, and creating another - /// consumer (B). Assert that (A)=(B). - /// - [Test] - public void CachedMessageConsumer() - { - IConnectionFactory connectionFactory = CreateConnectionFactory(); + /// + /// Tests that the same underlying instance of the message consumer is returned after + /// creating a session, creating the consumer (A), closing the session, and creating another + /// consumer (B). Assert that (A)=(B). + /// + [Test] + public void CachedMessageConsumer() + { + IConnectionFactory connectionFactory = CreateConnectionFactory(); - CachingConnectionFactory cachingConnectionFactory = new CachingConnectionFactory(); - cachingConnectionFactory.TargetConnectionFactory = connectionFactory; - IConnection con1 = cachingConnectionFactory.CreateConnection(); + CachingConnectionFactory cachingConnectionFactory = new CachingConnectionFactory(); + cachingConnectionFactory.TargetConnectionFactory = connectionFactory; + IConnection con1 = cachingConnectionFactory.CreateConnection(); - ISession sessionA = con1.CreateSession(AcknowledgementMode.Transactional); - IDestination destination = new Apache.NMS.ActiveMQ.Commands.ActiveMQQueue("test.dest"); - IMessageConsumer consumerA = sessionA.CreateConsumer(destination); - TestMessageConsumer tmpA = GetTestMessageConsumer(consumerA); + ISession sessionA = con1.CreateSession(AcknowledgementMode.Transactional); + IDestination destination = new Apache.NMS.ActiveMQ.Commands.ActiveMQQueue("test.dest"); + IMessageConsumer consumerA = sessionA.CreateConsumer(destination); + TestMessageConsumer tmpA = GetTestMessageConsumer(consumerA); - sessionA.Close(); + sessionA.Close(); - ISession sessionB = con1.CreateSession(AcknowledgementMode.Transactional); - IMessageConsumer consumerB = sessionB.CreateConsumer(destination); - TestMessageConsumer tmpB = GetTestMessageConsumer(consumerB); + ISession sessionB = con1.CreateSession(AcknowledgementMode.Transactional); + IMessageConsumer consumerB = sessionB.CreateConsumer(destination); + TestMessageConsumer tmpB = GetTestMessageConsumer(consumerB); - Assert.AreSame(tmpA, tmpB); - } + Assert.AreSame(tmpA, tmpB); + } #endif - private IConnectionFactory CreateConnectionFactory() - { - IConnectionFactory connectionFactory = A.Fake(); - IConnection connection = new TestConnection(); + private IConnectionFactory CreateConnectionFactory() + { + IConnectionFactory connectionFactory = A.Fake(); + IConnection connection = new TestConnection(); - A.CallTo(() => connectionFactory.CreateConnection()).Returns(connection).Once(); - return connectionFactory; - } - - private static TestMessageConsumer GetTestMessageConsumer(IMessageConsumer consumer) - { - CachedMessageConsumer cmp1 = consumer as CachedMessageConsumer; - Assert.IsNotNull(cmp1); - TestMessageConsumer tmp1 = cmp1.Target as TestMessageConsumer; - Assert.IsNotNull(tmp1); - return tmp1; - } - - private static TestMessageProducer GetTestMessageProducer(IMessageProducer producer1) - { - CachedMessageProducer cmp1 = producer1 as CachedMessageProducer; - Assert.IsNotNull(cmp1); - TestMessageProducer tmp1 = cmp1.Target as TestMessageProducer; - Assert.IsNotNull(tmp1); - return tmp1; - } + A.CallTo(() => connectionFactory.CreateConnection()).Returns(connection).Once(); + return connectionFactory; } -} \ No newline at end of file + + private static TestMessageConsumer GetTestMessageConsumer(IMessageConsumer consumer) + { + CachedMessageConsumer cmp1 = consumer as CachedMessageConsumer; + Assert.IsNotNull(cmp1); + TestMessageConsumer tmp1 = cmp1.Target as TestMessageConsumer; + Assert.IsNotNull(tmp1); + return tmp1; + } + + private static TestMessageProducer GetTestMessageProducer(IMessageProducer producer1) + { + CachedMessageProducer cmp1 = producer1 as CachedMessageProducer; + Assert.IsNotNull(cmp1); + TestMessageProducer tmp1 = cmp1.Target as TestMessageProducer; + Assert.IsNotNull(tmp1); + return tmp1; + } +} diff --git a/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Connections/MessageTransactionManagerTests.cs b/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Connections/MessageTransactionManagerTests.cs index f77fb5a7..bd843c06 100644 --- a/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Connections/MessageTransactionManagerTests.cs +++ b/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Connections/MessageTransactionManagerTests.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -21,9 +21,7 @@ #region Imports using Apache.NMS; - using FakeItEasy; - using NUnit.Framework; using Spring.Messaging.Nms.Core; using Spring.Transaction; @@ -31,253 +29,252 @@ using Spring.Transaction.Support; #endregion -namespace Spring.Messaging.Nms.Connections +namespace Spring.Messaging.Nms.Connections; + +/// +/// This class contains tests for +/// +/// Mark Pollack +/// $Id:$ +[TestFixture] +public class NmsTransactionManagerTests { - /// - /// This class contains tests for - /// - /// Mark Pollack - /// $Id:$ - [TestFixture] - public class NmsTransactionManagerTests - { - [Test] - public void TransactionCommit() - { - IConnectionFactory connectionFactory = A.Fake(); - IConnection connection = A.Fake(); - ISession session = A.Fake(); - - SetupCreateSession(connection, connectionFactory, session); - - NmsTransactionManager tm = new NmsTransactionManager(connectionFactory); - ITransactionStatus ts = tm.GetTransaction(new DefaultTransactionDefinition()); - NmsTemplate nt = new NmsTemplate(connectionFactory); - nt.Execute(new AssertSessionCallback(session)); - tm.Commit(ts); - - AssertCommitExpectations(connection, connectionFactory, session); - } - - [Test] - public void TransactionRollback() - { - IConnectionFactory connectionFactory = A.Fake(); - IConnection connection = A.Fake(); - ISession session = A.Fake(); - - SetupCreateSession(connection, connectionFactory, session); - - NmsTransactionManager tm = new NmsTransactionManager(connectionFactory); - ITransactionStatus ts = tm.GetTransaction(new DefaultTransactionDefinition()); - NmsTemplate nt = new NmsTemplate(connectionFactory); - nt.Execute(new AssertSessionCallback(session)); - tm.Rollback(ts); - - AssertRollbackExpectations(connection, connectionFactory, session); - } - - [Test] - public void ParticipatingTransactionWithCommit() - { - IConnectionFactory connectionFactory = A.Fake(); - IConnection connection = A.Fake(); - ISession session = A.Fake(); - - SetupCreateSession(connection, connectionFactory, session); - - NmsTransactionManager tm = new NmsTransactionManager(connectionFactory); - ITransactionStatus ts = tm.GetTransaction(new DefaultTransactionDefinition()); - NmsTemplate nt = new NmsTemplate(connectionFactory); - nt.Execute(new AssertSessionCallback(session)); - - TransactionTemplate tt = new TransactionTemplate(tm); - tt.Execute(status => - { - nt.Execute(new AssertSessionCallback(session)); - return null; - }); - - tm.Commit(ts); - - AssertCommitExpectations(connection, connectionFactory, session); - } - - [Test] - public void ParticipatingTransactionWithRollback() - { - IConnectionFactory connectionFactory = A.Fake(); - IConnection connection = A.Fake(); - ISession session = A.Fake(); - - SetupCreateSession(connection, connectionFactory, session); - - NmsTransactionManager tm = new NmsTransactionManager(connectionFactory); - ITransactionStatus ts = tm.GetTransaction(new DefaultTransactionDefinition()); - NmsTemplate nt = new NmsTemplate(connectionFactory); - nt.Execute(new AssertSessionCallback(session)); - - TransactionTemplate tt = new TransactionTemplate(tm); - tt.Execute(status => - { - nt.Execute(new AssertSessionCallback(session)); - status.SetRollbackOnly(); - return null; - }); - try - { - tm.Commit(ts); - Assert.Fail("Should have thrown UnexpectedRollbackException"); - } catch (UnexpectedRollbackException) - { - - } - - AssertRollbackExpectations(connection, connectionFactory, session); - } - - [Test] - public void SuspendedTransaction() - { - IConnectionFactory connectionFactory = A.Fake(); - IConnection connection = A.Fake(); - ISession session = A.Fake(); - ISession session2 = A.Fake(); - - A.CallTo(() => connectionFactory.CreateConnection()).Returns(connection).Twice(); - A.CallTo(() => connection.CreateSession(AcknowledgementMode.Transactional)).Returns(session).Once(); - A.CallTo(() => connection.CreateSession(AcknowledgementMode.AutoAcknowledge)).Returns(session2).Once(); - - NmsTransactionManager tm = new NmsTransactionManager(connectionFactory); - ITransactionStatus ts = tm.GetTransaction(new DefaultTransactionDefinition()); - NmsTemplate nt = new NmsTemplate(connectionFactory); - nt.Execute(new AssertSessionCallback(session)); - - TransactionTemplate tt = new TransactionTemplate(tm); - tt.PropagationBehavior = TransactionPropagation.NotSupported; - tt.Execute(status => - { - nt.Execute(new AssertNotSameSessionCallback(session)); - return null; - }); - - nt.Execute(new AssertSessionCallback(session)); - - tm.Commit(ts); - - A.CallTo(() => session.Commit()).MustHaveHappenedOnceExactly(); - A.CallTo(() => session.Close()).MustHaveHappenedOnceExactly(); - A.CallTo(() => session2.Close()).MustHaveHappenedOnceExactly(); - A.CallTo(() => connection.Close()).MustHaveHappenedTwiceExactly(); - } - - [Test] - public void TransactionSuspension() - { - IConnectionFactory connectionFactory = A.Fake(); - IConnection connection = A.Fake(); - ISession session = A.Fake(); - ISession session2 = A.Fake(); - - A.CallTo(() => connectionFactory.CreateConnection()).Returns(connection).Twice(); - A.CallTo(() => connection.CreateSession(AcknowledgementMode.Transactional)) - .Returns(session).Once() - .Then.Returns(session2).Once(); - - NmsTransactionManager tm = new NmsTransactionManager(connectionFactory); - ITransactionStatus ts = tm.GetTransaction(new DefaultTransactionDefinition()); - NmsTemplate nt = new NmsTemplate(connectionFactory); - - TransactionTemplate tt = new TransactionTemplate(tm); - tt.PropagationBehavior = TransactionPropagation.RequiresNew; - tt.Execute(status => - { - nt.Execute(new AssertNotSameSessionCallback(session)); - return null; - }); - - nt.Execute(new AssertSessionCallback(session)); - - tm.Commit(ts); - - A.CallTo(() => session.Commit()).MustHaveHappenedOnceExactly(); - A.CallTo(() => session2.Commit()).MustHaveHappenedOnceExactly(); - A.CallTo(() => session.Close()).MustHaveHappenedOnceExactly(); - A.CallTo(() => session2.Close()).MustHaveHappenedOnceExactly(); - A.CallTo(() => connection.Close()).MustHaveHappenedTwiceExactly(); - } - - private static void AssertRollbackExpectations(IConnection connection, IConnectionFactory connectionFactory, ISession session) - { - A.CallTo(() => session.Rollback()).MustHaveHappenedOnceExactly(); - A.CallTo(() => session.Close()).MustHaveHappenedOnceExactly(); - A.CallTo(() => connection.Close()).MustHaveHappenedOnceExactly(); - } - - private static void SetupCreateSession( - IConnection connection, - IConnectionFactory connectionFactory, - ISession session) - { - A.CallTo(() => connectionFactory.CreateConnection()).Returns(connection).Once(); - A.CallTo(() => connection.CreateSession(AcknowledgementMode.Transactional)).Returns(session).Once(); - } - - - private static void AssertCommitExpectations( - IConnection connection, - IConnectionFactory connectionFactory, - ISession session) - { - A.CallTo(() => session.Commit()).MustHaveHappenedOnceExactly(); - A.CallTo(() => session.Close()).MustHaveHappenedOnceExactly(); - A.CallTo(() => connection.Close()).MustHaveHappenedOnceExactly(); - } - - [TearDown] - public void TearDown() - { - Assert.IsTrue(TransactionSynchronizationManager.ResourceDictionary.Count == 0); - Assert.IsFalse(TransactionSynchronizationManager.SynchronizationActive); - - } - } - - internal class AssertSessionCallback : ISessionCallback + [Test] + public void TransactionCommit() { - private ISession session; - public AssertSessionCallback(ISession session) - { - this.session = session; - } + IConnectionFactory connectionFactory = A.Fake(); + IConnection connection = A.Fake(); + ISession session = A.Fake(); - #region ISessionCallback Members + SetupCreateSession(connection, connectionFactory, session); - public object DoInNms(ISession session) - { - Assert.IsTrue(this.session == session); - return null; - } + NmsTransactionManager tm = new NmsTransactionManager(connectionFactory); + ITransactionStatus ts = tm.GetTransaction(new DefaultTransactionDefinition()); + NmsTemplate nt = new NmsTemplate(connectionFactory); + nt.Execute(new AssertSessionCallback(session)); + tm.Commit(ts); - #endregion + AssertCommitExpectations(connection, connectionFactory, session); } - internal class AssertNotSameSessionCallback : ISessionCallback + [Test] + public void TransactionRollback() { - private ISession session; - public AssertNotSameSessionCallback(ISession session) - { - this.session = session; - } + IConnectionFactory connectionFactory = A.Fake(); + IConnection connection = A.Fake(); + ISession session = A.Fake(); - #region ISessionCallback Members + SetupCreateSession(connection, connectionFactory, session); - public object DoInNms(ISession session) - { - Assert.IsTrue(this.session != session); - return null; - } + NmsTransactionManager tm = new NmsTransactionManager(connectionFactory); + ITransactionStatus ts = tm.GetTransaction(new DefaultTransactionDefinition()); + NmsTemplate nt = new NmsTemplate(connectionFactory); + nt.Execute(new AssertSessionCallback(session)); + tm.Rollback(ts); - #endregion + AssertRollbackExpectations(connection, connectionFactory, session); } -} \ No newline at end of file + + [Test] + public void ParticipatingTransactionWithCommit() + { + IConnectionFactory connectionFactory = A.Fake(); + IConnection connection = A.Fake(); + ISession session = A.Fake(); + + SetupCreateSession(connection, connectionFactory, session); + + NmsTransactionManager tm = new NmsTransactionManager(connectionFactory); + ITransactionStatus ts = tm.GetTransaction(new DefaultTransactionDefinition()); + NmsTemplate nt = new NmsTemplate(connectionFactory); + nt.Execute(new AssertSessionCallback(session)); + + TransactionTemplate tt = new TransactionTemplate(tm); + tt.Execute(status => + { + nt.Execute(new AssertSessionCallback(session)); + return null; + }); + + tm.Commit(ts); + + AssertCommitExpectations(connection, connectionFactory, session); + } + + [Test] + public void ParticipatingTransactionWithRollback() + { + IConnectionFactory connectionFactory = A.Fake(); + IConnection connection = A.Fake(); + ISession session = A.Fake(); + + SetupCreateSession(connection, connectionFactory, session); + + NmsTransactionManager tm = new NmsTransactionManager(connectionFactory); + ITransactionStatus ts = tm.GetTransaction(new DefaultTransactionDefinition()); + NmsTemplate nt = new NmsTemplate(connectionFactory); + nt.Execute(new AssertSessionCallback(session)); + + TransactionTemplate tt = new TransactionTemplate(tm); + tt.Execute(status => + { + nt.Execute(new AssertSessionCallback(session)); + status.SetRollbackOnly(); + return null; + }); + try + { + tm.Commit(ts); + Assert.Fail("Should have thrown UnexpectedRollbackException"); + } + catch (UnexpectedRollbackException) + { + } + + AssertRollbackExpectations(connection, connectionFactory, session); + } + + [Test] + public void SuspendedTransaction() + { + IConnectionFactory connectionFactory = A.Fake(); + IConnection connection = A.Fake(); + ISession session = A.Fake(); + ISession session2 = A.Fake(); + + A.CallTo(() => connectionFactory.CreateConnection()).Returns(connection).Twice(); + A.CallTo(() => connection.CreateSession(AcknowledgementMode.Transactional)).Returns(session).Once(); + A.CallTo(() => connection.CreateSession(AcknowledgementMode.AutoAcknowledge)).Returns(session2).Once(); + + NmsTransactionManager tm = new NmsTransactionManager(connectionFactory); + ITransactionStatus ts = tm.GetTransaction(new DefaultTransactionDefinition()); + NmsTemplate nt = new NmsTemplate(connectionFactory); + nt.Execute(new AssertSessionCallback(session)); + + TransactionTemplate tt = new TransactionTemplate(tm); + tt.PropagationBehavior = TransactionPropagation.NotSupported; + tt.Execute(status => + { + nt.Execute(new AssertNotSameSessionCallback(session)); + return null; + }); + + nt.Execute(new AssertSessionCallback(session)); + + tm.Commit(ts); + + A.CallTo(() => session.Commit()).MustHaveHappenedOnceExactly(); + A.CallTo(() => session.Close()).MustHaveHappenedOnceExactly(); + A.CallTo(() => session2.Close()).MustHaveHappenedOnceExactly(); + A.CallTo(() => connection.Close()).MustHaveHappenedTwiceExactly(); + } + + [Test] + public void TransactionSuspension() + { + IConnectionFactory connectionFactory = A.Fake(); + IConnection connection = A.Fake(); + ISession session = A.Fake(); + ISession session2 = A.Fake(); + + A.CallTo(() => connectionFactory.CreateConnection()).Returns(connection).Twice(); + A.CallTo(() => connection.CreateSession(AcknowledgementMode.Transactional)) + .Returns(session).Once() + .Then.Returns(session2).Once(); + + NmsTransactionManager tm = new NmsTransactionManager(connectionFactory); + ITransactionStatus ts = tm.GetTransaction(new DefaultTransactionDefinition()); + NmsTemplate nt = new NmsTemplate(connectionFactory); + + TransactionTemplate tt = new TransactionTemplate(tm); + tt.PropagationBehavior = TransactionPropagation.RequiresNew; + tt.Execute(status => + { + nt.Execute(new AssertNotSameSessionCallback(session)); + return null; + }); + + nt.Execute(new AssertSessionCallback(session)); + + tm.Commit(ts); + + A.CallTo(() => session.Commit()).MustHaveHappenedOnceExactly(); + A.CallTo(() => session2.Commit()).MustHaveHappenedOnceExactly(); + A.CallTo(() => session.Close()).MustHaveHappenedOnceExactly(); + A.CallTo(() => session2.Close()).MustHaveHappenedOnceExactly(); + A.CallTo(() => connection.Close()).MustHaveHappenedTwiceExactly(); + } + + private static void AssertRollbackExpectations(IConnection connection, IConnectionFactory connectionFactory, ISession session) + { + A.CallTo(() => session.Rollback()).MustHaveHappenedOnceExactly(); + A.CallTo(() => session.Close()).MustHaveHappenedOnceExactly(); + A.CallTo(() => connection.Close()).MustHaveHappenedOnceExactly(); + } + + private static void SetupCreateSession( + IConnection connection, + IConnectionFactory connectionFactory, + ISession session) + { + A.CallTo(() => connectionFactory.CreateConnection()).Returns(connection).Once(); + A.CallTo(() => connection.CreateSession(AcknowledgementMode.Transactional)).Returns(session).Once(); + } + + private static void AssertCommitExpectations( + IConnection connection, + IConnectionFactory connectionFactory, + ISession session) + { + A.CallTo(() => session.Commit()).MustHaveHappenedOnceExactly(); + A.CallTo(() => session.Close()).MustHaveHappenedOnceExactly(); + A.CallTo(() => connection.Close()).MustHaveHappenedOnceExactly(); + } + + [TearDown] + public void TearDown() + { + Assert.IsTrue(TransactionSynchronizationManager.ResourceDictionary.Count == 0); + Assert.IsFalse(TransactionSynchronizationManager.SynchronizationActive); + } +} + +internal class AssertSessionCallback : ISessionCallback +{ + private ISession session; + + public AssertSessionCallback(ISession session) + { + this.session = session; + } + + #region ISessionCallback Members + + public object DoInNms(ISession session) + { + Assert.IsTrue(this.session == session); + return null; + } + + #endregion +} + +internal class AssertNotSameSessionCallback : ISessionCallback +{ + private ISession session; + + public AssertNotSameSessionCallback(ISession session) + { + this.session = session; + } + + #region ISessionCallback Members + + public object DoInNms(ISession session) + { + Assert.IsTrue(this.session != session); + return null; + } + + #endregion +} diff --git a/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Connections/MultithreadingTestHelper.cs b/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Connections/MultithreadingTestHelper.cs index 75056a85..5ed30980 100644 --- a/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Connections/MultithreadingTestHelper.cs +++ b/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Connections/MultithreadingTestHelper.cs @@ -1,50 +1,49 @@ using System.Diagnostics; -namespace Spring.Messaging.Nms.Connections -{ - public class MultithreadingTestHelper - { - [DebuggerStepThrough] - public static TestThreadHandler RunOnSeparateThread(Action action) - { - Exception exception = null; - var thread1 = new Thread(() => - { - try - { - action(); - } - catch (Exception e) - { - exception = e; - } - }); - thread1.Start(); +namespace Spring.Messaging.Nms.Connections; - return new TestThreadHandler(() => +public class MultithreadingTestHelper +{ + [DebuggerStepThrough] + public static TestThreadHandler RunOnSeparateThread(Action action) + { + Exception exception = null; + var thread1 = new Thread(() => + { + try { - thread1.Join(); - if (exception != null) - { - throw exception; - } - }); + action(); + } + catch (Exception e) + { + exception = e; + } + }); + thread1.Start(); + + return new TestThreadHandler(() => + { + thread1.Join(); + if (exception != null) + { + throw exception; + } + }); + } + + public class TestThreadHandler + { + private readonly Action _waitAction; + + public TestThreadHandler(Action waitAction) + { + _waitAction = waitAction; } - public class TestThreadHandler + [DebuggerStepThrough] + public void Wait() { - private readonly Action _waitAction; - - public TestThreadHandler(Action waitAction) - { - _waitAction = waitAction; - } - - [DebuggerStepThrough] - public void Wait() - { - _waitAction(); - } + _waitAction(); } } } diff --git a/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Connections/NMSContextSingleConnectionFactoryTests.cs b/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Connections/NMSContextSingleConnectionFactoryTests.cs index 791ae99c..e08e9dac 100644 --- a/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Connections/NMSContextSingleConnectionFactoryTests.cs +++ b/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Connections/NMSContextSingleConnectionFactoryTests.cs @@ -1,4 +1,5 @@ #region License + // /* // * Copyright 2022 the original author or authors. // * @@ -14,144 +15,140 @@ // * See the License for the specific language governing permissions and // * limitations under the License. // */ + #endregion #region Imports using Apache.NMS; - using FakeItEasy; - using NUnit.Framework; #endregion -namespace Spring.Messaging.Nms.Connections +namespace Spring.Messaging.Nms.Connections; + +/// +/// Adapted NMSContext based version of SingleConnectionFactoryTest +/// +/// +[TestFixture] +public class NMSContextSingleConnectionFactoryTests { - /// - /// Adapted NMSContext based version of SingleConnectionFactoryTest - /// - /// - [TestFixture] - public class NMSContextSingleConnectionFactoryTests + [Test] + public void UsingConnection() { - [Test] - public void UsingConnection() - { - IConnection connection = A.Fake(); + IConnection connection = A.Fake(); - SingleConnectionFactory scf = new SingleConnectionFactory(connection); - INMSContext con1 = scf.CreateContext(); - con1.Start(); - con1.PurgeTempDestinations(); - con1.Stop(); // should be ignored - con1.Close(); // should be ignored - INMSContext con2 = scf.CreateContext(); - con2.Start(); - con1.PurgeTempDestinations(); - con2.Stop(); // should be ignored - con2.Close(); // should be ignored. - scf.Dispose(); + SingleConnectionFactory scf = new SingleConnectionFactory(connection); + INMSContext con1 = scf.CreateContext(); + con1.Start(); + con1.PurgeTempDestinations(); + con1.Stop(); // should be ignored + con1.Close(); // should be ignored + INMSContext con2 = scf.CreateContext(); + con2.Start(); + con1.PurgeTempDestinations(); + con2.Stop(); // should be ignored + con2.Close(); // should be ignored. + scf.Dispose(); - A.CallTo(() => connection.StartAsync()).MustHaveHappenedTwiceExactly(); - A.CallTo(() => connection.PurgeTempDestinations()).MustHaveHappenedTwiceExactly(); - A.CallTo(() => connection.Stop()).MustHaveHappenedOnceExactly(); - A.CallTo(() => connection.Close()).MustHaveHappenedOnceExactly(); - } + A.CallTo(() => connection.StartAsync()).MustHaveHappenedTwiceExactly(); + A.CallTo(() => connection.PurgeTempDestinations()).MustHaveHappenedTwiceExactly(); + A.CallTo(() => connection.Stop()).MustHaveHappenedOnceExactly(); + A.CallTo(() => connection.Close()).MustHaveHappenedOnceExactly(); + } - [Test] - public void UsingConnectionFactory() - { - IConnectionFactory connectionFactory = A.Fake(); - IConnection connection = A.Fake(); + [Test] + public void UsingConnectionFactory() + { + IConnectionFactory connectionFactory = A.Fake(); + IConnection connection = A.Fake(); - A.CallTo(() => connectionFactory.CreateConnection()).Returns(connection).Once(); + A.CallTo(() => connectionFactory.CreateConnection()).Returns(connection).Once(); - SingleConnectionFactory scf = new SingleConnectionFactory(connectionFactory); - INMSContext con1 = scf.CreateContext(); - con1.Start(); - con1.Close(); // should be ignored - INMSContext con2 = scf.CreateContext(); - con2.Start(); - con2.Close(); //should be ignored - scf.Dispose(); //should trigger actual close + SingleConnectionFactory scf = new SingleConnectionFactory(connectionFactory); + INMSContext con1 = scf.CreateContext(); + con1.Start(); + con1.Close(); // should be ignored + INMSContext con2 = scf.CreateContext(); + con2.Start(); + con2.Close(); //should be ignored + scf.Dispose(); //should trigger actual close - A.CallTo(() => connection.StartAsync()).MustHaveHappenedTwiceExactly(); - A.CallTo(() => connection.Stop()).MustHaveHappenedOnceExactly(); - A.CallTo(() => connection.Close()).MustHaveHappenedOnceExactly(); - } + A.CallTo(() => connection.StartAsync()).MustHaveHappenedTwiceExactly(); + A.CallTo(() => connection.Stop()).MustHaveHappenedOnceExactly(); + A.CallTo(() => connection.Close()).MustHaveHappenedOnceExactly(); + } - [Test] - public void UsingConnectionFactoryAndClientId() - { - IConnectionFactory connectionFactory = A.Fake(); - IConnection connection = A.Fake(); + [Test] + public void UsingConnectionFactoryAndClientId() + { + IConnectionFactory connectionFactory = A.Fake(); + IConnection connection = A.Fake(); - A.CallTo(() => connectionFactory.CreateConnection()).Returns(connection).Once(); + A.CallTo(() => connectionFactory.CreateConnection()).Returns(connection).Once(); - SingleConnectionFactory scf = new SingleConnectionFactory(connectionFactory); - scf.ClientId = "MyId"; - INMSContext con1 = scf.CreateContext(); - con1.Start(); - con1.Close(); // should be ignored - INMSContext con2 = scf.CreateContext(); - con2.Start(); - con2.Close(); // should be ignored - scf.Dispose(); // should trigger actual close + SingleConnectionFactory scf = new SingleConnectionFactory(connectionFactory); + scf.ClientId = "MyId"; + INMSContext con1 = scf.CreateContext(); + con1.Start(); + con1.Close(); // should be ignored + INMSContext con2 = scf.CreateContext(); + con2.Start(); + con2.Close(); // should be ignored + scf.Dispose(); // should trigger actual close - A.CallToSet(() => connection.ClientId).WhenArgumentsMatch(x => x.Get(0) == "MyId").MustHaveHappenedOnceExactly(); - A.CallTo(() => connection.StartAsync()).MustHaveHappenedTwiceExactly(); - A.CallTo(() => connection.Stop()).MustHaveHappenedOnceExactly(); - A.CallTo(() => connection.Close()).MustHaveHappenedOnceExactly(); - } + A.CallToSet(() => connection.ClientId).WhenArgumentsMatch(x => x.Get(0) == "MyId").MustHaveHappenedOnceExactly(); + A.CallTo(() => connection.StartAsync()).MustHaveHappenedTwiceExactly(); + A.CallTo(() => connection.Stop()).MustHaveHappenedOnceExactly(); + A.CallTo(() => connection.Close()).MustHaveHappenedOnceExactly(); + } + [Test] + public void UsingConnectionFactoryAndReconnectOnException() + { + IConnectionFactory connectionFactory = A.Fake(); + TestConnection con = new TestConnection(); - [Test] - public void UsingConnectionFactoryAndReconnectOnException() - { - IConnectionFactory connectionFactory = A.Fake(); - TestConnection con = new TestConnection(); + A.CallTo(() => connectionFactory.CreateConnection()).Returns(con).Twice(); - A.CallTo(() => connectionFactory.CreateConnection()).Returns(con).Twice(); + SingleConnectionFactory scf = new SingleConnectionFactory(connectionFactory); + scf.ReconnectOnException = true; + INMSContext con1 = scf.CreateContext(); - SingleConnectionFactory scf = new SingleConnectionFactory(connectionFactory); - scf.ReconnectOnException = true; - INMSContext con1 = scf.CreateContext(); + con1.Start(); + con.FireExcpetionEvent(new NMSException("")); + INMSContext con2 = scf.CreateContext(); + con2.Start(); + scf.Dispose(); - con1.Start(); - con.FireExcpetionEvent(new NMSException("")); - INMSContext con2 = scf.CreateContext(); - con2.Start(); - scf.Dispose(); + Assert.AreEqual(2, con.StartCount); + Assert.AreEqual(2, con.CloseCount); + } - Assert.AreEqual(2, con.StartCount); - Assert.AreEqual(2, con.CloseCount); - } + [Test] + public void UsingConnectionFactoryAndExceptionListenerAndReconnectOnException() + { + IConnectionFactory connectionFactory = A.Fake(); + TestConnection con = new TestConnection(); + TestExceptionListener listener = new TestExceptionListener(); - [Test] - public void UsingConnectionFactoryAndExceptionListenerAndReconnectOnException() - { - IConnectionFactory connectionFactory = A.Fake(); - TestConnection con = new TestConnection(); - TestExceptionListener listener = new TestExceptionListener(); + A.CallTo(() => connectionFactory.CreateConnection()).Returns(con).Twice(); - A.CallTo(() => connectionFactory.CreateConnection()).Returns(con).Twice(); - - SingleConnectionFactory scf = new SingleConnectionFactory(connectionFactory); - scf.ExceptionListener = listener; - scf.ReconnectOnException = true; - INMSContext con1 = scf.CreateContext(); - //Assert.AreSame(listener, ); - con1.Start(); - con.FireExcpetionEvent(new NMSException("")); - INMSContext con2 = scf.CreateContext(); - con2.Start(); - scf.Dispose(); - - Assert.AreEqual(2, con.StartCount); - Assert.AreEqual(2, con.CloseCount); - Assert.AreEqual(1, listener.Count); - } + SingleConnectionFactory scf = new SingleConnectionFactory(connectionFactory); + scf.ExceptionListener = listener; + scf.ReconnectOnException = true; + INMSContext con1 = scf.CreateContext(); + //Assert.AreSame(listener, ); + con1.Start(); + con.FireExcpetionEvent(new NMSException("")); + INMSContext con2 = scf.CreateContext(); + con2.Start(); + scf.Dispose(); + Assert.AreEqual(2, con.StartCount); + Assert.AreEqual(2, con.CloseCount); + Assert.AreEqual(1, listener.Count); } } diff --git a/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Connections/SingleConnectionFactoryTests.cs b/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Connections/SingleConnectionFactoryTests.cs index 09351e7a..84f5275c 100644 --- a/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Connections/SingleConnectionFactoryTests.cs +++ b/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Connections/SingleConnectionFactoryTests.cs @@ -21,224 +21,217 @@ #region Imports using Apache.NMS; - using FakeItEasy; - using NUnit.Framework; - using Spring.Messaging.Nms.Core; #endregion -namespace Spring.Messaging.Nms.Connections +namespace Spring.Messaging.Nms.Connections; + +/// +/// This class contains tests for the SingleConnectionFactory +/// +/// Mark Pollack +[TestFixture] +public class SingleConnectionFactoryTests { - /// - /// This class contains tests for the SingleConnectionFactory - /// - /// Mark Pollack - [TestFixture] - public class SingleConnectionFactoryTests + [Test] + public void UsingConnection() { - [Test] - public void UsingConnection() - { - IConnection connection = A.Fake(); + IConnection connection = A.Fake(); - SingleConnectionFactory scf = new SingleConnectionFactory(connection); - IConnection con1 = scf.CreateConnection(); - con1.Start(); - con1.PurgeTempDestinations(); - con1.Stop(); // should be ignored - con1.Close(); // should be ignored - IConnection con2 = scf.CreateConnection(); - con2.Start(); - con1.PurgeTempDestinations(); - con2.Stop(); // should be ignored - con2.Close(); // should be ignored. - scf.Dispose(); + SingleConnectionFactory scf = new SingleConnectionFactory(connection); + IConnection con1 = scf.CreateConnection(); + con1.Start(); + con1.PurgeTempDestinations(); + con1.Stop(); // should be ignored + con1.Close(); // should be ignored + IConnection con2 = scf.CreateConnection(); + con2.Start(); + con1.PurgeTempDestinations(); + con2.Stop(); // should be ignored + con2.Close(); // should be ignored. + scf.Dispose(); - A.CallTo(() => connection.Start()).MustHaveHappenedTwiceExactly(); - A.CallTo(() => connection.PurgeTempDestinations()).MustHaveHappenedTwiceExactly(); - A.CallTo(() => connection.Stop()).MustHaveHappenedOnceExactly(); - A.CallTo(() => connection.Close()).MustHaveHappenedOnceExactly(); - } - - [Test] - public void UsingConnectionFactory() - { - IConnectionFactory connectionFactory = A.Fake(); - IConnection connection = A.Fake(); - - A.CallTo(() => connectionFactory.CreateConnection()).Returns(connection).Once(); - - SingleConnectionFactory scf = new SingleConnectionFactory(connectionFactory); - IConnection con1 = scf.CreateConnection(); - con1.Start(); - con1.Close(); // should be ignored - IConnection con2 = scf.CreateConnection(); - con2.Start(); - con2.Close(); //should be ignored - scf.Dispose(); //should trigger actual close - - A.CallTo(() => connection.Start()).MustHaveHappenedTwiceExactly(); - A.CallTo(() => connection.Stop()).MustHaveHappenedOnceExactly(); - A.CallTo(() => connection.Close()).MustHaveHappenedOnceExactly(); - } - - [Test] - public void UsingConnectionFactoryAndClientId() - { - IConnectionFactory connectionFactory = A.Fake(); - IConnection connection = A.Fake(); - - A.CallTo(() => connectionFactory.CreateConnection()).Returns(connection).Once(); - - SingleConnectionFactory scf = new SingleConnectionFactory(connectionFactory); - scf.ClientId = "MyId"; - IConnection con1 = scf.CreateConnection(); - con1.Start(); - con1.Close(); // should be ignored - IConnection con2 = scf.CreateConnection(); - con2.Start(); - con2.Close(); // should be ignored - scf.Dispose(); // should trigger actual close - - A.CallToSet(() => connection.ClientId).WhenArgumentsMatch(x => x.Get(0) == "MyId").MustHaveHappenedOnceExactly(); - A.CallTo(() => connection.Start()).MustHaveHappenedTwiceExactly(); - A.CallTo(() => connection.Stop()).MustHaveHappenedOnceExactly(); - A.CallTo(() => connection.Close()).MustHaveHappenedOnceExactly(); - } - - - [Test] - public void UsingConnectionFactoryAndExceptionListener() - { - IConnectionFactory connectionFactory = A.Fake(); - IConnection connection = A.Fake(); - - - IExceptionListener listener = new ChainedExceptionListener(); - A.CallTo(() => connectionFactory.CreateConnection()).Returns(connection).Once(); - - SingleConnectionFactory scf = new SingleConnectionFactory(connectionFactory); - scf.ExceptionListener = listener; - IConnection con1 = scf.CreateConnection(); - - //can't look at invocation list on event ...grrr. - - con1.Start(); - con1.Stop(); // should be ignored - con1.Close(); // should be ignored - IConnection con2 = scf.CreateConnection(); - con2.Start(); - con2.Stop(); - con2.Close(); - scf.Dispose(); - - // TODO - //connection.ExceptionListener += listener.OnException; - // LastCall.On(connection).IgnoreArguments(); - - - A.CallTo(() => connection.Start()).MustHaveHappenedTwiceExactly(); - A.CallTo(() => connection.Stop()).MustHaveHappenedOnceExactly(); - A.CallTo(() => connection.Close()).MustHaveHappenedOnceExactly(); - } - - [Test] - public void UsingConnectionFactoryAndReconnectOnException() - { - IConnectionFactory connectionFactory = A.Fake(); - TestConnection con = new TestConnection(); - - A.CallTo(() => connectionFactory.CreateConnection()).Returns(con).Twice(); - - SingleConnectionFactory scf = new SingleConnectionFactory(connectionFactory); - scf.ReconnectOnException = true; - IConnection con1 = scf.CreateConnection(); - - con1.Start(); - con.FireExcpetionEvent(new NMSException("")); - IConnection con2 = scf.CreateConnection(); - con2.Start(); - scf.Dispose(); - - Assert.AreEqual(2, con.StartCount); - Assert.AreEqual(2, con.CloseCount); - } - - [Test] - public void UsingConnectionFactoryAndExceptionListenerAndReconnectOnException() - { - IConnectionFactory connectionFactory = A.Fake(); - TestConnection con = new TestConnection(); - TestExceptionListener listener = new TestExceptionListener(); - - A.CallTo(() => connectionFactory.CreateConnection()).Returns(con).Twice(); - - SingleConnectionFactory scf = new SingleConnectionFactory(connectionFactory); - scf.ExceptionListener = listener; - scf.ReconnectOnException = true; - IConnection con1 = scf.CreateConnection(); - //Assert.AreSame(listener, ); - con1.Start(); - con.FireExcpetionEvent(new NMSException("")); - IConnection con2 = scf.CreateConnection(); - con2.Start(); - scf.Dispose(); - - Assert.AreEqual(2, con.StartCount); - Assert.AreEqual(2, con.CloseCount); - Assert.AreEqual(1, listener.Count); - } - - [Test] - public void CachingConnectionFactory() - { - IConnectionFactory connectionFactory = A.Fake(); - IConnection connection = A.Fake(); - ISession txSession = A.Fake(); - ISession nonTxSession = A.Fake(); - A.CallTo(() => connectionFactory.CreateConnection()).Returns(connection).Once(); - A.CallTo(() => connectionFactory.CreateConnectionAsync()).Returns(connection).Once(); - - A.CallTo(() => connection.CreateSession(AcknowledgementMode.Transactional)).Returns(txSession).Once(); - A.CallTo(() => connection.CreateSessionAsync(AcknowledgementMode.Transactional)).Returns(txSession).Once(); - - A.CallTo(() => txSession.Transacted).Returns(true).Twice(); - - A.CallTo(() => connection.CreateSession(AcknowledgementMode.ClientAcknowledge)).Returns(nonTxSession).Once(); - A.CallTo(() => connection.CreateSessionAsync(AcknowledgementMode.ClientAcknowledge)).Returns(nonTxSession).Once(); - - CachingConnectionFactory scf = new CachingConnectionFactory(connectionFactory); - scf.ReconnectOnException = false; - - IConnection con1 = scf.CreateConnection(); - ISession session1 = con1.CreateSession(AcknowledgementMode.Transactional); - bool b = session1.Transacted; - session1.Close(); // should be ignored - session1 = con1.CreateSession(AcknowledgementMode.ClientAcknowledge); - session1.Close(); // should be ignored - con1.Start(); - con1.Close(); // should be ignored - IConnection con2 = scf.CreateConnection(); - ISession session2 = con2.CreateSession(AcknowledgementMode.ClientAcknowledge); - session2.Close(); // should be ignored - session2 = con2.CreateSession(AcknowledgementMode.Transactional); - session2.Commit(); - session2.Close(); // should be ignored - con2.Start(); - con2.Close(); - scf.Dispose(); - - A.CallTo(() => txSession.RollbackAsync()).MustHaveHappenedOnceExactly(); - A.CallTo(() => txSession.Commit()).MustHaveHappenedOnceExactly(); - A.CallTo(() => txSession.CloseAsync()).MustHaveHappenedOnceExactly(); - - A.CallTo(() => nonTxSession.CloseAsync()).MustHaveHappenedOnceExactly(); - A.CallTo(() => connection.Start()).MustHaveHappenedTwiceExactly(); - A.CallTo(() => connection.Stop()).MustHaveHappenedOnceExactly(); - A.CallTo(() => connection.Close()).MustHaveHappenedOnceExactly(); - } + A.CallTo(() => connection.Start()).MustHaveHappenedTwiceExactly(); + A.CallTo(() => connection.PurgeTempDestinations()).MustHaveHappenedTwiceExactly(); + A.CallTo(() => connection.Stop()).MustHaveHappenedOnceExactly(); + A.CallTo(() => connection.Close()).MustHaveHappenedOnceExactly(); } -} \ No newline at end of file + + [Test] + public void UsingConnectionFactory() + { + IConnectionFactory connectionFactory = A.Fake(); + IConnection connection = A.Fake(); + + A.CallTo(() => connectionFactory.CreateConnection()).Returns(connection).Once(); + + SingleConnectionFactory scf = new SingleConnectionFactory(connectionFactory); + IConnection con1 = scf.CreateConnection(); + con1.Start(); + con1.Close(); // should be ignored + IConnection con2 = scf.CreateConnection(); + con2.Start(); + con2.Close(); //should be ignored + scf.Dispose(); //should trigger actual close + + A.CallTo(() => connection.Start()).MustHaveHappenedTwiceExactly(); + A.CallTo(() => connection.Stop()).MustHaveHappenedOnceExactly(); + A.CallTo(() => connection.Close()).MustHaveHappenedOnceExactly(); + } + + [Test] + public void UsingConnectionFactoryAndClientId() + { + IConnectionFactory connectionFactory = A.Fake(); + IConnection connection = A.Fake(); + + A.CallTo(() => connectionFactory.CreateConnection()).Returns(connection).Once(); + + SingleConnectionFactory scf = new SingleConnectionFactory(connectionFactory); + scf.ClientId = "MyId"; + IConnection con1 = scf.CreateConnection(); + con1.Start(); + con1.Close(); // should be ignored + IConnection con2 = scf.CreateConnection(); + con2.Start(); + con2.Close(); // should be ignored + scf.Dispose(); // should trigger actual close + + A.CallToSet(() => connection.ClientId).WhenArgumentsMatch(x => x.Get(0) == "MyId").MustHaveHappenedOnceExactly(); + A.CallTo(() => connection.Start()).MustHaveHappenedTwiceExactly(); + A.CallTo(() => connection.Stop()).MustHaveHappenedOnceExactly(); + A.CallTo(() => connection.Close()).MustHaveHappenedOnceExactly(); + } + + [Test] + public void UsingConnectionFactoryAndExceptionListener() + { + IConnectionFactory connectionFactory = A.Fake(); + IConnection connection = A.Fake(); + + IExceptionListener listener = new ChainedExceptionListener(); + A.CallTo(() => connectionFactory.CreateConnection()).Returns(connection).Once(); + + SingleConnectionFactory scf = new SingleConnectionFactory(connectionFactory); + scf.ExceptionListener = listener; + IConnection con1 = scf.CreateConnection(); + + //can't look at invocation list on event ...grrr. + + con1.Start(); + con1.Stop(); // should be ignored + con1.Close(); // should be ignored + IConnection con2 = scf.CreateConnection(); + con2.Start(); + con2.Stop(); + con2.Close(); + scf.Dispose(); + + // TODO + //connection.ExceptionListener += listener.OnException; + // LastCall.On(connection).IgnoreArguments(); + + A.CallTo(() => connection.Start()).MustHaveHappenedTwiceExactly(); + A.CallTo(() => connection.Stop()).MustHaveHappenedOnceExactly(); + A.CallTo(() => connection.Close()).MustHaveHappenedOnceExactly(); + } + + [Test] + public void UsingConnectionFactoryAndReconnectOnException() + { + IConnectionFactory connectionFactory = A.Fake(); + TestConnection con = new TestConnection(); + + A.CallTo(() => connectionFactory.CreateConnection()).Returns(con).Twice(); + + SingleConnectionFactory scf = new SingleConnectionFactory(connectionFactory); + scf.ReconnectOnException = true; + IConnection con1 = scf.CreateConnection(); + + con1.Start(); + con.FireExcpetionEvent(new NMSException("")); + IConnection con2 = scf.CreateConnection(); + con2.Start(); + scf.Dispose(); + + Assert.AreEqual(2, con.StartCount); + Assert.AreEqual(2, con.CloseCount); + } + + [Test] + public void UsingConnectionFactoryAndExceptionListenerAndReconnectOnException() + { + IConnectionFactory connectionFactory = A.Fake(); + TestConnection con = new TestConnection(); + TestExceptionListener listener = new TestExceptionListener(); + + A.CallTo(() => connectionFactory.CreateConnection()).Returns(con).Twice(); + + SingleConnectionFactory scf = new SingleConnectionFactory(connectionFactory); + scf.ExceptionListener = listener; + scf.ReconnectOnException = true; + IConnection con1 = scf.CreateConnection(); + //Assert.AreSame(listener, ); + con1.Start(); + con.FireExcpetionEvent(new NMSException("")); + IConnection con2 = scf.CreateConnection(); + con2.Start(); + scf.Dispose(); + + Assert.AreEqual(2, con.StartCount); + Assert.AreEqual(2, con.CloseCount); + Assert.AreEqual(1, listener.Count); + } + + [Test] + public void CachingConnectionFactory() + { + IConnectionFactory connectionFactory = A.Fake(); + IConnection connection = A.Fake(); + ISession txSession = A.Fake(); + ISession nonTxSession = A.Fake(); + A.CallTo(() => connectionFactory.CreateConnection()).Returns(connection).Once(); + A.CallTo(() => connectionFactory.CreateConnectionAsync()).Returns(connection).Once(); + + A.CallTo(() => connection.CreateSession(AcknowledgementMode.Transactional)).Returns(txSession).Once(); + A.CallTo(() => connection.CreateSessionAsync(AcknowledgementMode.Transactional)).Returns(txSession).Once(); + + A.CallTo(() => txSession.Transacted).Returns(true).Twice(); + + A.CallTo(() => connection.CreateSession(AcknowledgementMode.ClientAcknowledge)).Returns(nonTxSession).Once(); + A.CallTo(() => connection.CreateSessionAsync(AcknowledgementMode.ClientAcknowledge)).Returns(nonTxSession).Once(); + + CachingConnectionFactory scf = new CachingConnectionFactory(connectionFactory); + scf.ReconnectOnException = false; + + IConnection con1 = scf.CreateConnection(); + ISession session1 = con1.CreateSession(AcknowledgementMode.Transactional); + bool b = session1.Transacted; + session1.Close(); // should be ignored + session1 = con1.CreateSession(AcknowledgementMode.ClientAcknowledge); + session1.Close(); // should be ignored + con1.Start(); + con1.Close(); // should be ignored + IConnection con2 = scf.CreateConnection(); + ISession session2 = con2.CreateSession(AcknowledgementMode.ClientAcknowledge); + session2.Close(); // should be ignored + session2 = con2.CreateSession(AcknowledgementMode.Transactional); + session2.Commit(); + session2.Close(); // should be ignored + con2.Start(); + con2.Close(); + scf.Dispose(); + + A.CallTo(() => txSession.RollbackAsync()).MustHaveHappenedOnceExactly(); + A.CallTo(() => txSession.Commit()).MustHaveHappenedOnceExactly(); + A.CallTo(() => txSession.CloseAsync()).MustHaveHappenedOnceExactly(); + + A.CallTo(() => nonTxSession.CloseAsync()).MustHaveHappenedOnceExactly(); + A.CallTo(() => connection.Start()).MustHaveHappenedTwiceExactly(); + A.CallTo(() => connection.Stop()).MustHaveHappenedOnceExactly(); + A.CallTo(() => connection.Close()).MustHaveHappenedOnceExactly(); + } +} diff --git a/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Connections/TestConnection.cs b/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Connections/TestConnection.cs index d294bf2f..523fdb71 100644 --- a/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Connections/TestConnection.cs +++ b/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Connections/TestConnection.cs @@ -1,148 +1,146 @@ using Apache.NMS; -namespace Spring.Messaging.Nms.Connections +namespace Spring.Messaging.Nms.Connections; + +public class TestConnection : IConnection { - public class TestConnection : IConnection + private int startCount; + private int closeCount; + private int createSessionCount; + + public int StartCount { - private int startCount; - private int closeCount; - private int createSessionCount; + get { return startCount; } + } - public int StartCount - { - get { return startCount; } - } + public int CloseCount + { + get { return closeCount; } + } - public int CloseCount - { - get { return closeCount; } - } - - public IConnectionMetaData MetaData - { - get { throw new NotImplementedException(); } - } + public IConnectionMetaData MetaData + { + get { throw new NotImplementedException(); } + } #pragma warning disable 67 - public event ExceptionListener ExceptionListener; - public event ConnectionInterruptedListener ConnectionInterruptedListener; - public event ConnectionResumedListener ConnectionResumedListener; + public event ExceptionListener ExceptionListener; + public event ConnectionInterruptedListener ConnectionInterruptedListener; + public event ConnectionResumedListener ConnectionResumedListener; #pragma warning restore 67 - public ISession CreateSession() + public ISession CreateSession() + { + createSessionCount++; + return new TestSession(); + } + + public ISession CreateSession(AcknowledgementMode acknowledgementMode) + { + createSessionCount++; + return new TestSession(); + } + + public Task CreateSessionAsync() + { + return Task.FromResult(CreateSession()); + } + + public Task CreateSessionAsync(AcknowledgementMode acknowledgementMode) + { + return Task.FromResult(CreateSession(acknowledgementMode)); + } + + public ISession CreateSession(AcknowledgementMode acknowledgementMode, TimeSpan requestTimeout) + { + throw new NotImplementedException(); + } + + public void Close() + { + closeCount++; + } + + public Task CloseAsync() + { + throw new NotImplementedException(); + } + + public void PurgeTempDestinations() + { + } + + public ConsumerTransformerDelegate ConsumerTransformer + { + get { throw new NotImplementedException(); } + set { throw new NotImplementedException(); } + } + + public ProducerTransformerDelegate ProducerTransformer + { + get { throw new NotImplementedException(); } + set { throw new NotImplementedException(); } + } + + public TimeSpan RequestTimeout + { + get { throw new NotImplementedException(); } + set { throw new NotImplementedException(); } + } + + public AcknowledgementMode AcknowledgementMode + { + get { return AcknowledgementMode.ClientAcknowledge; } + set { } + } + + public string ClientId + { + get { return null; } + set { } + } + + public IRedeliveryPolicy RedeliveryPolicy + { + get { throw new NotImplementedException(); } + set { throw new NotImplementedException(); } + } + + public void Dispose() + { + } + + public void Start() + { + startCount++; + } + + public Task StartAsync() + { + startCount++; + return Task.CompletedTask; + } + + public bool IsStarted + { + get { - createSessionCount++; - return new TestSession(); - } - - public ISession CreateSession(AcknowledgementMode acknowledgementMode) - { - createSessionCount++; - return new TestSession(); - } - - public Task CreateSessionAsync() - { - return Task.FromResult(CreateSession()); - } - - public Task CreateSessionAsync(AcknowledgementMode acknowledgementMode) - { - return Task.FromResult(CreateSession(acknowledgementMode)); - } - - public ISession CreateSession(AcknowledgementMode acknowledgementMode, TimeSpan requestTimeout) - { - throw new NotImplementedException(); - } - - public void Close() - { - closeCount++; - } - - public Task CloseAsync() - { - throw new NotImplementedException(); - } - - public void PurgeTempDestinations() - { - - } - - public ConsumerTransformerDelegate ConsumerTransformer - { - get { throw new NotImplementedException(); } - set { throw new NotImplementedException(); } - } - - public ProducerTransformerDelegate ProducerTransformer - { - get { throw new NotImplementedException(); } - set { throw new NotImplementedException(); } - } - - public TimeSpan RequestTimeout - { - get { throw new NotImplementedException(); } - set { throw new NotImplementedException(); } - } - - public AcknowledgementMode AcknowledgementMode - { - get { return AcknowledgementMode.ClientAcknowledge; } - set { } - } - - public string ClientId - { - get { return null; } - set { } - } - - public IRedeliveryPolicy RedeliveryPolicy - { - get { throw new NotImplementedException(); } - set { throw new NotImplementedException(); } - } - - public void Dispose() - { - } - - public void Start() - { - startCount++; - } - - public Task StartAsync() - { - startCount++; - return Task.CompletedTask; - } - - public bool IsStarted - { - get - { - if (startCount > 0) return true; - return false; - } - } - - public void Stop() - { - } - - public Task StopAsync() - { - throw new NotImplementedException(); - } - - public void FireExcpetionEvent(Exception e) - { - ExceptionListener(e); + if (startCount > 0) return true; + return false; } } + + public void Stop() + { + } + + public Task StopAsync() + { + throw new NotImplementedException(); + } + + public void FireExcpetionEvent(Exception e) + { + ExceptionListener(e); + } } diff --git a/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Connections/TestConnectionFactory.cs b/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Connections/TestConnectionFactory.cs index 1c237a21..70e97e66 100644 --- a/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Connections/TestConnectionFactory.cs +++ b/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Connections/TestConnectionFactory.cs @@ -1,95 +1,94 @@ using Apache.NMS; -namespace Spring.Messaging.Nms.Connections +namespace Spring.Messaging.Nms.Connections; + +public class TestConnectionFactory : IConnectionFactory { - public class TestConnectionFactory : IConnectionFactory + #region IConnectionFactory Members + + public IConnection CreateConnection() { - #region IConnectionFactory Members - - public IConnection CreateConnection() - { - return new TestConnection(); - } - - public IConnection CreateConnection(string userName, string password) - { - return new TestConnection(); - } - - public Task CreateConnectionAsync() - { - throw new NotImplementedException(); - } - - public Task CreateConnectionAsync(string userName, string password) - { - throw new NotImplementedException(); - } - - public INMSContext CreateContext() - { - throw new NotImplementedException(); - } - - public INMSContext CreateContext(AcknowledgementMode acknowledgementMode) - { - throw new NotImplementedException(); - } - - public INMSContext CreateContext(string userName, string password) - { - throw new NotImplementedException(); - } - - public INMSContext CreateContext(string userName, string password, AcknowledgementMode acknowledgementMode) - { - throw new NotImplementedException(); - } - - public Task CreateContextAsync() - { - throw new NotImplementedException(); - } - - public Task CreateContextAsync(AcknowledgementMode acknowledgementMode) - { - throw new NotImplementedException(); - } - - public Task CreateContextAsync(string userName, string password) - { - throw new NotImplementedException(); - } - - public Task CreateContextAsync(string userName, string password, AcknowledgementMode acknowledgementMode) - { - throw new NotImplementedException(); - } - - public Uri BrokerUri - { - get { throw new NotImplementedException(); } - set { throw new NotImplementedException(); } - } - - public IRedeliveryPolicy RedeliveryPolicy - { - get { throw new NotImplementedException(); } - set { throw new NotImplementedException(); } - } - - public ConsumerTransformerDelegate ConsumerTransformer - { - get { throw new NotImplementedException(); } - set { throw new NotImplementedException(); } - } - - public ProducerTransformerDelegate ProducerTransformer - { - get { throw new NotImplementedException(); } - set { throw new NotImplementedException(); } - } - - #endregion + return new TestConnection(); } -} + + public IConnection CreateConnection(string userName, string password) + { + return new TestConnection(); + } + + public Task CreateConnectionAsync() + { + throw new NotImplementedException(); + } + + public Task CreateConnectionAsync(string userName, string password) + { + throw new NotImplementedException(); + } + + public INMSContext CreateContext() + { + throw new NotImplementedException(); + } + + public INMSContext CreateContext(AcknowledgementMode acknowledgementMode) + { + throw new NotImplementedException(); + } + + public INMSContext CreateContext(string userName, string password) + { + throw new NotImplementedException(); + } + + public INMSContext CreateContext(string userName, string password, AcknowledgementMode acknowledgementMode) + { + throw new NotImplementedException(); + } + + public Task CreateContextAsync() + { + throw new NotImplementedException(); + } + + public Task CreateContextAsync(AcknowledgementMode acknowledgementMode) + { + throw new NotImplementedException(); + } + + public Task CreateContextAsync(string userName, string password) + { + throw new NotImplementedException(); + } + + public Task CreateContextAsync(string userName, string password, AcknowledgementMode acknowledgementMode) + { + throw new NotImplementedException(); + } + + public Uri BrokerUri + { + get { throw new NotImplementedException(); } + set { throw new NotImplementedException(); } + } + + public IRedeliveryPolicy RedeliveryPolicy + { + get { throw new NotImplementedException(); } + set { throw new NotImplementedException(); } + } + + public ConsumerTransformerDelegate ConsumerTransformer + { + get { throw new NotImplementedException(); } + set { throw new NotImplementedException(); } + } + + public ProducerTransformerDelegate ProducerTransformer + { + get { throw new NotImplementedException(); } + set { throw new NotImplementedException(); } + } + + #endregion +} \ No newline at end of file diff --git a/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Connections/TestExceptionListener.cs b/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Connections/TestExceptionListener.cs index 026fd9f5..025e7e75 100644 --- a/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Connections/TestExceptionListener.cs +++ b/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Connections/TestExceptionListener.cs @@ -20,21 +20,19 @@ using Spring.Messaging.Nms.Core; -namespace Spring.Messaging.Nms.Connections +namespace Spring.Messaging.Nms.Connections; + +public class TestExceptionListener : IExceptionListener { - public class TestExceptionListener : IExceptionListener + private int count = 0; + + public void OnException(Exception exception) { - private int count = 0; + count++; + } - public void OnException(Exception exception) - { - count++; - } - - - public int Count - { - get { return count; } - } + public int Count + { + get { return count; } } } diff --git a/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Connections/TestMessageConsumer.cs b/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Connections/TestMessageConsumer.cs index 4b539303..2ce8b279 100644 --- a/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Connections/TestMessageConsumer.cs +++ b/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Connections/TestMessageConsumer.cs @@ -20,63 +20,62 @@ using Apache.NMS; -namespace Spring.Messaging.Nms.Connections +namespace Spring.Messaging.Nms.Connections; + +public class TestMessageConsumer : IMessageConsumer { - public class TestMessageConsumer : IMessageConsumer + public string MessageSelector { get; } + public event MessageListener Listener; + + private void InvokeListener(IMessage message) { - public string MessageSelector { get; } - public event MessageListener Listener; + MessageListener listener = Listener; + if (listener != null) listener(message); + } - private void InvokeListener(IMessage message) - { - MessageListener listener = Listener; - if (listener != null) listener(message); - } + public IMessage Receive() + { + throw new NotImplementedException(); + } - public IMessage Receive() - { - throw new NotImplementedException(); - } + public Task ReceiveAsync() + { + throw new NotImplementedException(); + } - public Task ReceiveAsync() - { - throw new NotImplementedException(); - } + public IMessage Receive(TimeSpan timeout) + { + throw new NotImplementedException(); + } - public IMessage Receive(TimeSpan timeout) - { - throw new NotImplementedException(); - } + public Task ReceiveAsync(TimeSpan timeout) + { + throw new NotImplementedException(); + } - public Task ReceiveAsync(TimeSpan timeout) - { - throw new NotImplementedException(); - } + public IMessage ReceiveNoWait() + { + throw new NotImplementedException(); + } - public IMessage ReceiveNoWait() - { - throw new NotImplementedException(); - } + public void Close() + { + throw new NotImplementedException(); + } - public void Close() - { - throw new NotImplementedException(); - } + public Task CloseAsync() + { + throw new NotImplementedException(); + } - public Task CloseAsync() - { - throw new NotImplementedException(); - } + public ConsumerTransformerDelegate ConsumerTransformer + { + get { throw new NotImplementedException(); } + set { throw new NotImplementedException(); } + } - public ConsumerTransformerDelegate ConsumerTransformer - { - get { throw new NotImplementedException(); } - set { throw new NotImplementedException(); } - } - - public void Dispose() - { - throw new NotImplementedException(); - } + public void Dispose() + { + throw new NotImplementedException(); } } diff --git a/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Connections/TestMessageListener.cs b/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Connections/TestMessageListener.cs index 87e50b5b..9cb6a77b 100644 --- a/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Connections/TestMessageListener.cs +++ b/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Connections/TestMessageListener.cs @@ -21,33 +21,31 @@ using Apache.NMS; using Spring.Messaging.Nms.Core; -namespace Spring.Messaging.Nms.Connections +namespace Spring.Messaging.Nms.Connections; + +/// +/// +/// +/// +/// +/// +/// Mark Pollack +public class TestMessageListener : IMessageListener { - /// - /// - /// - /// - /// - /// - /// Mark Pollack - public class TestMessageListener : IMessageListener + private IMessage message; + + public IMessage Message { - private IMessage message; - - - public IMessage Message - { - get { return message; } - set { message = value; } - } - - #region IMessageListener Members - - public void OnMessage(IMessage message) - { - this.message = message; - } - - #endregion + get { return message; } + set { message = value; } } -} \ No newline at end of file + + #region IMessageListener Members + + public void OnMessage(IMessage message) + { + this.message = message; + } + + #endregion +} diff --git a/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Connections/TestMessageProducer.cs b/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Connections/TestMessageProducer.cs index 0c8e86f6..46bf05f6 100644 --- a/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Connections/TestMessageProducer.cs +++ b/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Connections/TestMessageProducer.cs @@ -20,192 +20,190 @@ using Apache.NMS; -namespace Spring.Messaging.Nms.Connections +namespace Spring.Messaging.Nms.Connections; + +public class TestMessageProducer : IMessageProducer { + private MsgDeliveryMode msgDeliveryMode; + private TimeSpan timeToLive = new TimeSpan(0, 0, 0, 60, 0); + private TimeSpan requestTimeout; - public class TestMessageProducer : IMessageProducer + public void Send(IMessage message) { - private MsgDeliveryMode msgDeliveryMode; - private TimeSpan timeToLive = new TimeSpan(0,0,0,60,0); - private TimeSpan requestTimeout; + throw new NotImplementedException(); + } - public void Send(IMessage message) - { - throw new NotImplementedException(); - } + public void Send(IMessage message, MsgDeliveryMode deliveryMode, MsgPriority priority, TimeSpan timeToLive) + { + throw new NotImplementedException(); + } - public void Send(IMessage message, MsgDeliveryMode deliveryMode, MsgPriority priority, TimeSpan timeToLive) - { - throw new NotImplementedException(); - } + public void Send(IDestination destination, IMessage message) + { + throw new NotImplementedException(); + } - public void Send(IDestination destination, IMessage message) - { - throw new NotImplementedException(); - } + public void Send(IDestination destination, IMessage message, MsgDeliveryMode deliveryMode, MsgPriority priority, TimeSpan timeToLive) + { + throw new NotImplementedException(); + } - public void Send(IDestination destination, IMessage message, MsgDeliveryMode deliveryMode, MsgPriority priority, TimeSpan timeToLive) - { - throw new NotImplementedException(); - } + public Task SendAsync(IMessage message) + { + throw new NotImplementedException(); + } - public Task SendAsync(IMessage message) - { - throw new NotImplementedException(); - } + public Task SendAsync(IMessage message, MsgDeliveryMode deliveryMode, MsgPriority priority, TimeSpan timeToLive) + { + throw new NotImplementedException(); + } - public Task SendAsync(IMessage message, MsgDeliveryMode deliveryMode, MsgPriority priority, TimeSpan timeToLive) - { - throw new NotImplementedException(); - } + public Task SendAsync(IDestination destination, IMessage message) + { + throw new NotImplementedException(); + } - public Task SendAsync(IDestination destination, IMessage message) - { - throw new NotImplementedException(); - } + public Task SendAsync(IDestination destination, IMessage message, MsgDeliveryMode deliveryMode, MsgPriority priority, TimeSpan timeToLive) + { + throw new NotImplementedException(); + } - public Task SendAsync(IDestination destination, IMessage message, MsgDeliveryMode deliveryMode, MsgPriority priority, TimeSpan timeToLive) - { - throw new NotImplementedException(); - } + public void Close() + { + throw new NotImplementedException(); + } - public void Close() - { - throw new NotImplementedException(); - } + public Task CloseAsync() + { + throw new NotImplementedException(); + } - public Task CloseAsync() - { - throw new NotImplementedException(); - } + public IMessage CreateMessage() + { + throw new NotImplementedException(); + } - public IMessage CreateMessage() - { - throw new NotImplementedException(); - } + public Task CreateMessageAsync() + { + throw new NotImplementedException(); + } - public Task CreateMessageAsync() - { - throw new NotImplementedException(); - } + public ITextMessage CreateTextMessage() + { + throw new NotImplementedException(); + } - public ITextMessage CreateTextMessage() - { - throw new NotImplementedException(); - } + public Task CreateTextMessageAsync() + { + throw new NotImplementedException(); + } - public Task CreateTextMessageAsync() - { - throw new NotImplementedException(); - } + public ITextMessage CreateTextMessage(string text) + { + throw new NotImplementedException(); + } - public ITextMessage CreateTextMessage(string text) - { - throw new NotImplementedException(); - } + public Task CreateTextMessageAsync(string text) + { + throw new NotImplementedException(); + } - public Task CreateTextMessageAsync(string text) - { - throw new NotImplementedException(); - } + public IMapMessage CreateMapMessage() + { + throw new NotImplementedException(); + } - public IMapMessage CreateMapMessage() - { - throw new NotImplementedException(); - } + public Task CreateMapMessageAsync() + { + throw new NotImplementedException(); + } - public Task CreateMapMessageAsync() - { - throw new NotImplementedException(); - } + public IObjectMessage CreateObjectMessage(object body) + { + throw new NotImplementedException(); + } - public IObjectMessage CreateObjectMessage(object body) - { - throw new NotImplementedException(); - } + public Task CreateObjectMessageAsync(object body) + { + throw new NotImplementedException(); + } - public Task CreateObjectMessageAsync(object body) - { - throw new NotImplementedException(); - } + public IBytesMessage CreateBytesMessage() + { + throw new NotImplementedException(); + } - public IBytesMessage CreateBytesMessage() - { - throw new NotImplementedException(); - } + public Task CreateBytesMessageAsync() + { + throw new NotImplementedException(); + } - public Task CreateBytesMessageAsync() - { - throw new NotImplementedException(); - } + public IBytesMessage CreateBytesMessage(byte[] body) + { + throw new NotImplementedException(); + } - public IBytesMessage CreateBytesMessage(byte[] body) - { - throw new NotImplementedException(); - } + public Task CreateBytesMessageAsync(byte[] body) + { + throw new NotImplementedException(); + } - public Task CreateBytesMessageAsync(byte[] body) - { - throw new NotImplementedException(); - } + public IStreamMessage CreateStreamMessage() + { + throw new NotImplementedException(); + } - public IStreamMessage CreateStreamMessage() - { - throw new NotImplementedException(); - } + public Task CreateStreamMessageAsync() + { + throw new NotImplementedException(); + } - public Task CreateStreamMessageAsync() - { - throw new NotImplementedException(); - } + public ProducerTransformerDelegate ProducerTransformer + { + get { throw new NotImplementedException(); } + set { throw new NotImplementedException(); } + } - public ProducerTransformerDelegate ProducerTransformer - { - get { throw new NotImplementedException(); } - set { throw new NotImplementedException(); } - } + public MsgDeliveryMode DeliveryMode + { + get { return msgDeliveryMode; } + set { msgDeliveryMode = value; } + } - public MsgDeliveryMode DeliveryMode - { - get { return msgDeliveryMode; } - set { msgDeliveryMode = value; } - } + public TimeSpan TimeToLive + { + get { return timeToLive; } + set { timeToLive = value; } + } - public TimeSpan TimeToLive - { - get { return timeToLive; } - set { timeToLive = value; } - } + public TimeSpan RequestTimeout + { + get { return requestTimeout; } + set { requestTimeout = value; } + } - public TimeSpan RequestTimeout - { - get { return requestTimeout; } - set { requestTimeout = value; } - } + public MsgPriority Priority + { + get { return MsgPriority.Normal; } + set { } + } - public MsgPriority Priority - { - get { return MsgPriority.Normal; } - set { } - } + public bool DisableMessageID + { + get { throw new NotImplementedException(); } + set { throw new NotImplementedException(); } + } - public bool DisableMessageID - { - get { throw new NotImplementedException(); } - set { throw new NotImplementedException(); } - } + public bool DisableMessageTimestamp + { + get { throw new NotImplementedException(); } + set { throw new NotImplementedException(); } + } - public bool DisableMessageTimestamp - { - get { throw new NotImplementedException(); } - set { throw new NotImplementedException(); } - } + public TimeSpan DeliveryDelay { get; set; } - public TimeSpan DeliveryDelay { get; set; } - - public void Dispose() - { - throw new NotImplementedException(); - } + public void Dispose() + { + throw new NotImplementedException(); } } diff --git a/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Connections/TestSession.cs b/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Connections/TestSession.cs index 6ebc3f60..ef0907f6 100644 --- a/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Connections/TestSession.cs +++ b/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Connections/TestSession.cs @@ -21,461 +21,458 @@ using Apache.NMS; using FakeItEasy; -namespace Spring.Messaging.Nms.Connections +namespace Spring.Messaging.Nms.Connections; + +public class TestSession : ISession { - public class TestSession : ISession + private int closeCount; + private int createdCount; + + public TestSession() { - private int closeCount; - private int createdCount; - - - public TestSession() - { - createdCount++; - } - - public int CloseCount - { - get { return closeCount; } - } - - - public int CreatedCount - { - get { return createdCount; } - } - - public IMessageProducer CreateProducer() - { - return new TestMessageProducer(); - } - - public Task CreateProducerAsync() - { - return Task.FromResult(CreateProducer()); - } - - public IMessageProducer CreateProducer(IDestination destination) - { - return new TestMessageProducer(); - } - - public Task CreateProducerAsync(IDestination destination) - { - return Task.FromResult(CreateProducer()); - } - - public IMessageProducer CreateProducer(IDestination destination, TimeSpan requestTimeout) - { - return new TestMessageProducer(); - } - - public IMessageConsumer CreateConsumer(IDestination destination) - { - return new TestMessageConsumer(); - } - - public Task CreateConsumerAsync(IDestination destination) - { - return Task.FromResult(CreateConsumer(destination)); - } - - public IMessageConsumer CreateConsumer(IDestination destination, TimeSpan requestTimeout) - { - return new TestMessageConsumer(); - } - - public IMessageConsumer CreateConsumer(IDestination destination, string selector) - { - return new TestMessageConsumer(); - } - - public Task CreateConsumerAsync(IDestination destination, string selector) - { - return Task.FromResult(CreateConsumer(destination, selector)); - } - - public IMessageConsumer CreateConsumer(IDestination destination, string selector, TimeSpan requestTimeout) - { - return new TestMessageConsumer(); - } - - public IMessageConsumer CreateConsumer(IDestination destination, string selector, bool noLocal) - { - return new TestMessageConsumer(); - } - - public Task CreateConsumerAsync(IDestination destination, string selector, bool noLocal) - { - return Task.FromResult(CreateConsumer(destination, selector, noLocal)); - } - - public IMessageConsumer CreateDurableConsumer(ITopic destination, string name) - { - return new TestMessageConsumer(); - } - - public Task CreateDurableConsumerAsync(ITopic destination, string name) - { - return Task.FromResult(CreateConsumer(destination)); - } - - public IMessageConsumer CreateDurableConsumer(ITopic destination, string name, string selector) - { - throw new NotImplementedException(); - } - - public Task CreateDurableConsumerAsync(ITopic destination, string name, string selector) - { - throw new NotImplementedException(); - } - - public IMessageConsumer CreateConsumer( - IDestination destination, string selector, bool noLocal, - TimeSpan requestTimeout) - { - return new TestMessageConsumer(); - } - - public IMessageConsumer CreateDurableConsumer(ITopic destination, string name, string selector, bool noLocal) - { - return new TestMessageConsumer(); - } - - public Task CreateDurableConsumerAsync(ITopic destination, string name, string selector, bool noLocal) - { - throw new NotImplementedException(); - } - - public IMessageConsumer CreateSharedConsumer(ITopic destination, string name) - { - throw new NotImplementedException(); - } - - public Task CreateSharedConsumerAsync(ITopic destination, string name) - { - throw new NotImplementedException(); - } - - public IMessageConsumer CreateSharedConsumer(ITopic destination, string name, string selector) - { - throw new NotImplementedException(); - } - - public Task CreateSharedConsumerAsync(ITopic destination, string name, string selector) - { - throw new NotImplementedException(); - } - - public IMessageConsumer CreateSharedDurableConsumer(ITopic destination, string name) - { - throw new NotImplementedException(); - } - - public Task CreateSharedDurableConsumerAsync(ITopic destination, string name) - { - throw new NotImplementedException(); - } - - public IMessageConsumer CreateSharedDurableConsumer(ITopic destination, string name, string selector) - { - throw new NotImplementedException(); - } - - public Task CreateSharedDurableConsumerAsync(ITopic destination, string name, string selector) - { - throw new NotImplementedException(); - } - - public IMessageConsumer CreateDurableConsumer( - ITopic destination, string name, string selector, bool noLocal, - TimeSpan requestTimeout) - { - return new TestMessageConsumer(); - } - - public void DeleteDurableConsumer(string name) - { - throw new NotImplementedException(); - } - - public void Unsubscribe(string name) - { - throw new NotImplementedException(); - } - - public Task UnsubscribeAsync(string name) - { - throw new NotImplementedException(); - } - - public IQueueBrowser CreateBrowser(IQueue queue) - { - throw new NotImplementedException(); - } - - public Task CreateBrowserAsync(IQueue queue) - { - throw new NotImplementedException(); - } - - public IQueueBrowser CreateBrowser(IQueue queue, string selector) - { - throw new NotImplementedException(); - } - - public Task CreateBrowserAsync(IQueue queue, string selector) - { - throw new NotImplementedException(); - } - - public void DeleteDurableConsumer(string name, TimeSpan requestTimeout) - { - throw new NotImplementedException(); - } - - public Task GetQueueAsync(string name) - { - throw new NotImplementedException(); - } - - public IQueue GetQueue(string name) - { - return A.Fake(); - } - - public ITopic GetTopic(string name) - { - throw new NotImplementedException(); - } - - public Task GetTopicAsync(string name) - { - throw new NotImplementedException(); - } - - public ITemporaryQueue CreateTemporaryQueue() - { - throw new NotImplementedException(); - } - - public Task CreateTemporaryQueueAsync() - { - throw new NotImplementedException(); - } - - public ITemporaryTopic CreateTemporaryTopic() - { - throw new NotImplementedException(); - } - - public Task CreateTemporaryTopicAsync() - { - throw new NotImplementedException(); - } - - public void DeleteDestination(IDestination destination) - { - throw new NotImplementedException(); - } - - public Task DeleteDestinationAsync(IDestination destination) - { - throw new NotImplementedException(); - } - - public IMessage CreateMessage() - { - throw new NotImplementedException(); - } - - public Task CreateMessageAsync() - { - throw new NotImplementedException(); - } - - public ITextMessage CreateTextMessage() - { - throw new NotImplementedException(); - } - - public Task CreateTextMessageAsync() - { - throw new NotImplementedException(); - } - - public ITextMessage CreateTextMessage(string text) - { - throw new NotImplementedException(); - } - - public Task CreateTextMessageAsync(string text) - { - throw new NotImplementedException(); - } - - public IMapMessage CreateMapMessage() - { - throw new NotImplementedException(); - } - - public Task CreateMapMessageAsync() - { - throw new NotImplementedException(); - } - - public IObjectMessage CreateObjectMessage(object body) - { - throw new NotImplementedException(); - } - - public Task CreateObjectMessageAsync(object body) - { - throw new NotImplementedException(); - } - - public IBytesMessage CreateBytesMessage() - { - throw new NotImplementedException(); - } - - public Task CreateBytesMessageAsync() - { - throw new NotImplementedException(); - } - - public IBytesMessage CreateBytesMessage(byte[] body) - { - throw new NotImplementedException(); - } - - public Task CreateBytesMessageAsync(byte[] body) - { - throw new NotImplementedException(); - } - - public IStreamMessage CreateStreamMessage() - { - throw new NotImplementedException(); - } - - public Task CreateStreamMessageAsync() - { - throw new NotImplementedException(); - } - - public void Close() - { - closeCount++; - } - - public Task CloseAsync() - { - throw new NotImplementedException(); - } - - public void Recover() - { - } - - public Task RecoverAsync() - { - throw new NotImplementedException(); - } - - public void Acknowledge() - { - throw new NotImplementedException(); - } - - public Task AcknowledgeAsync() - { - throw new NotImplementedException(); - } - - public void Commit() - { - } - - public Task CommitAsync() - { - throw new NotImplementedException(); - } - - public void Rollback() - { - } - - public Task RollbackAsync() - { - return Task.CompletedTask; - } - - public ConsumerTransformerDelegate ConsumerTransformer - { - get { throw new NotImplementedException(); } - set { throw new NotImplementedException(); } - } - - public ProducerTransformerDelegate ProducerTransformer - { - get { throw new NotImplementedException(); } - set { throw new NotImplementedException(); } - } - - public TimeSpan RequestTimeout - { - get { throw new NotImplementedException(); } - set { throw new NotImplementedException(); } - } - - public bool Transacted - { - get { return true; } - } - - public AcknowledgementMode AcknowledgementMode - { - get { throw new NotImplementedException(); } - } - - #region Transaction State Events - - public void TransactionStarted() - { - if (TransactionStartedListener != null) - { - TransactionStartedListener(this); - } - } - - public void TransactionCommitted() - { - if (TransactionCommittedListener != null) - { - TransactionCommittedListener(this); - } - } - - public void TransactionRolledBack() - { - if (TransactionRolledBackListener != null) - { - TransactionRolledBackListener(this); - } - } - - public event SessionTxEventDelegate TransactionStartedListener; - - public event SessionTxEventDelegate TransactionCommittedListener; - - public event SessionTxEventDelegate TransactionRolledBackListener; - - #endregion - - public void Dispose() - { - throw new NotImplementedException(); + createdCount++; + } + + public int CloseCount + { + get { return closeCount; } + } + + public int CreatedCount + { + get { return createdCount; } + } + + public IMessageProducer CreateProducer() + { + return new TestMessageProducer(); + } + + public Task CreateProducerAsync() + { + return Task.FromResult(CreateProducer()); + } + + public IMessageProducer CreateProducer(IDestination destination) + { + return new TestMessageProducer(); + } + + public Task CreateProducerAsync(IDestination destination) + { + return Task.FromResult(CreateProducer()); + } + + public IMessageProducer CreateProducer(IDestination destination, TimeSpan requestTimeout) + { + return new TestMessageProducer(); + } + + public IMessageConsumer CreateConsumer(IDestination destination) + { + return new TestMessageConsumer(); + } + + public Task CreateConsumerAsync(IDestination destination) + { + return Task.FromResult(CreateConsumer(destination)); + } + + public IMessageConsumer CreateConsumer(IDestination destination, TimeSpan requestTimeout) + { + return new TestMessageConsumer(); + } + + public IMessageConsumer CreateConsumer(IDestination destination, string selector) + { + return new TestMessageConsumer(); + } + + public Task CreateConsumerAsync(IDestination destination, string selector) + { + return Task.FromResult(CreateConsumer(destination, selector)); + } + + public IMessageConsumer CreateConsumer(IDestination destination, string selector, TimeSpan requestTimeout) + { + return new TestMessageConsumer(); + } + + public IMessageConsumer CreateConsumer(IDestination destination, string selector, bool noLocal) + { + return new TestMessageConsumer(); + } + + public Task CreateConsumerAsync(IDestination destination, string selector, bool noLocal) + { + return Task.FromResult(CreateConsumer(destination, selector, noLocal)); + } + + public IMessageConsumer CreateDurableConsumer(ITopic destination, string name) + { + return new TestMessageConsumer(); + } + + public Task CreateDurableConsumerAsync(ITopic destination, string name) + { + return Task.FromResult(CreateConsumer(destination)); + } + + public IMessageConsumer CreateDurableConsumer(ITopic destination, string name, string selector) + { + throw new NotImplementedException(); + } + + public Task CreateDurableConsumerAsync(ITopic destination, string name, string selector) + { + throw new NotImplementedException(); + } + + public IMessageConsumer CreateConsumer( + IDestination destination, string selector, bool noLocal, + TimeSpan requestTimeout) + { + return new TestMessageConsumer(); + } + + public IMessageConsumer CreateDurableConsumer(ITopic destination, string name, string selector, bool noLocal) + { + return new TestMessageConsumer(); + } + + public Task CreateDurableConsumerAsync(ITopic destination, string name, string selector, bool noLocal) + { + throw new NotImplementedException(); + } + + public IMessageConsumer CreateSharedConsumer(ITopic destination, string name) + { + throw new NotImplementedException(); + } + + public Task CreateSharedConsumerAsync(ITopic destination, string name) + { + throw new NotImplementedException(); + } + + public IMessageConsumer CreateSharedConsumer(ITopic destination, string name, string selector) + { + throw new NotImplementedException(); + } + + public Task CreateSharedConsumerAsync(ITopic destination, string name, string selector) + { + throw new NotImplementedException(); + } + + public IMessageConsumer CreateSharedDurableConsumer(ITopic destination, string name) + { + throw new NotImplementedException(); + } + + public Task CreateSharedDurableConsumerAsync(ITopic destination, string name) + { + throw new NotImplementedException(); + } + + public IMessageConsumer CreateSharedDurableConsumer(ITopic destination, string name, string selector) + { + throw new NotImplementedException(); + } + + public Task CreateSharedDurableConsumerAsync(ITopic destination, string name, string selector) + { + throw new NotImplementedException(); + } + + public IMessageConsumer CreateDurableConsumer( + ITopic destination, string name, string selector, bool noLocal, + TimeSpan requestTimeout) + { + return new TestMessageConsumer(); + } + + public void DeleteDurableConsumer(string name) + { + throw new NotImplementedException(); + } + + public void Unsubscribe(string name) + { + throw new NotImplementedException(); + } + + public Task UnsubscribeAsync(string name) + { + throw new NotImplementedException(); + } + + public IQueueBrowser CreateBrowser(IQueue queue) + { + throw new NotImplementedException(); + } + + public Task CreateBrowserAsync(IQueue queue) + { + throw new NotImplementedException(); + } + + public IQueueBrowser CreateBrowser(IQueue queue, string selector) + { + throw new NotImplementedException(); + } + + public Task CreateBrowserAsync(IQueue queue, string selector) + { + throw new NotImplementedException(); + } + + public void DeleteDurableConsumer(string name, TimeSpan requestTimeout) + { + throw new NotImplementedException(); + } + + public Task GetQueueAsync(string name) + { + throw new NotImplementedException(); + } + + public IQueue GetQueue(string name) + { + return A.Fake(); + } + + public ITopic GetTopic(string name) + { + throw new NotImplementedException(); + } + + public Task GetTopicAsync(string name) + { + throw new NotImplementedException(); + } + + public ITemporaryQueue CreateTemporaryQueue() + { + throw new NotImplementedException(); + } + + public Task CreateTemporaryQueueAsync() + { + throw new NotImplementedException(); + } + + public ITemporaryTopic CreateTemporaryTopic() + { + throw new NotImplementedException(); + } + + public Task CreateTemporaryTopicAsync() + { + throw new NotImplementedException(); + } + + public void DeleteDestination(IDestination destination) + { + throw new NotImplementedException(); + } + + public Task DeleteDestinationAsync(IDestination destination) + { + throw new NotImplementedException(); + } + + public IMessage CreateMessage() + { + throw new NotImplementedException(); + } + + public Task CreateMessageAsync() + { + throw new NotImplementedException(); + } + + public ITextMessage CreateTextMessage() + { + throw new NotImplementedException(); + } + + public Task CreateTextMessageAsync() + { + throw new NotImplementedException(); + } + + public ITextMessage CreateTextMessage(string text) + { + throw new NotImplementedException(); + } + + public Task CreateTextMessageAsync(string text) + { + throw new NotImplementedException(); + } + + public IMapMessage CreateMapMessage() + { + throw new NotImplementedException(); + } + + public Task CreateMapMessageAsync() + { + throw new NotImplementedException(); + } + + public IObjectMessage CreateObjectMessage(object body) + { + throw new NotImplementedException(); + } + + public Task CreateObjectMessageAsync(object body) + { + throw new NotImplementedException(); + } + + public IBytesMessage CreateBytesMessage() + { + throw new NotImplementedException(); + } + + public Task CreateBytesMessageAsync() + { + throw new NotImplementedException(); + } + + public IBytesMessage CreateBytesMessage(byte[] body) + { + throw new NotImplementedException(); + } + + public Task CreateBytesMessageAsync(byte[] body) + { + throw new NotImplementedException(); + } + + public IStreamMessage CreateStreamMessage() + { + throw new NotImplementedException(); + } + + public Task CreateStreamMessageAsync() + { + throw new NotImplementedException(); + } + + public void Close() + { + closeCount++; + } + + public Task CloseAsync() + { + throw new NotImplementedException(); + } + + public void Recover() + { + } + + public Task RecoverAsync() + { + throw new NotImplementedException(); + } + + public void Acknowledge() + { + throw new NotImplementedException(); + } + + public Task AcknowledgeAsync() + { + throw new NotImplementedException(); + } + + public void Commit() + { + } + + public Task CommitAsync() + { + throw new NotImplementedException(); + } + + public void Rollback() + { + } + + public Task RollbackAsync() + { + return Task.CompletedTask; + } + + public ConsumerTransformerDelegate ConsumerTransformer + { + get { throw new NotImplementedException(); } + set { throw new NotImplementedException(); } + } + + public ProducerTransformerDelegate ProducerTransformer + { + get { throw new NotImplementedException(); } + set { throw new NotImplementedException(); } + } + + public TimeSpan RequestTimeout + { + get { throw new NotImplementedException(); } + set { throw new NotImplementedException(); } + } + + public bool Transacted + { + get { return true; } + } + + public AcknowledgementMode AcknowledgementMode + { + get { throw new NotImplementedException(); } + } + + #region Transaction State Events + + public void TransactionStarted() + { + if (TransactionStartedListener != null) + { + TransactionStartedListener(this); } } + + public void TransactionCommitted() + { + if (TransactionCommittedListener != null) + { + TransactionCommittedListener(this); + } + } + + public void TransactionRolledBack() + { + if (TransactionRolledBackListener != null) + { + TransactionRolledBackListener(this); + } + } + + public event SessionTxEventDelegate TransactionStartedListener; + + public event SessionTxEventDelegate TransactionCommittedListener; + + public event SessionTxEventDelegate TransactionRolledBackListener; + + #endregion + + public void Dispose() + { + throw new NotImplementedException(); + } } diff --git a/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Connections/UserCredentialsConnectionFactoryAdapterTests.cs b/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Connections/UserCredentialsConnectionFactoryAdapterTests.cs index c04fd218..0fbda818 100644 --- a/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Connections/UserCredentialsConnectionFactoryAdapterTests.cs +++ b/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Connections/UserCredentialsConnectionFactoryAdapterTests.cs @@ -2,158 +2,150 @@ using FakeItEasy; using NUnit.Framework; -namespace Spring.Messaging.Nms.Connections +namespace Spring.Messaging.Nms.Connections; + +[TestFixture] +public class UserCredentialsConnectionFactoryAdapterTests { - [TestFixture] - public class UserCredentialsConnectionFactoryAdapterTests + [Test] + public void CreateConnectionWithoutCredentialsWhenTheyAreNotSet() { + var underlyingConnectionFactory = A.Fake(); + var connectionFactory = new UserCredentialsConnectionFactoryAdapter(underlyingConnectionFactory); - [Test] - public void CreateConnectionWithoutCredentialsWhenTheyAreNotSet() + connectionFactory.CreateConnection(); + + A.CallTo(() => underlyingConnectionFactory.CreateConnection()).MustHaveHappenedOnceExactly(); + A.CallTo(() => underlyingConnectionFactory.CreateConnection(A._, A._)).MustHaveHappened(0, Times.Exactly); + } + + [Test] + public void CreateConnectionWithoutCredentialsWhenLoginIsNotSet() + { + var underlyingConnectionFactory = A.Fake(); + var connectionFactory = new UserCredentialsConnectionFactoryAdapter(underlyingConnectionFactory); + connectionFactory.Password = "Secret"; + connectionFactory.CreateConnection(); + + A.CallTo(() => underlyingConnectionFactory.CreateConnection()).MustHaveHappenedOnceExactly(); + A.CallTo(() => underlyingConnectionFactory.CreateConnection(A._, A._)).MustHaveHappened(0, Times.Exactly); + } + + [Test] + public void CreateConnectionWithCredentialsWhenTheyAreSet() + { + var underlyingConnectionFactory = A.Fake(); + var connectionFactory = new UserCredentialsConnectionFactoryAdapter(underlyingConnectionFactory); + connectionFactory.UserName = "SampleUser"; + connectionFactory.Password = "Secret"; + connectionFactory.CreateConnection(); + + A.CallTo(() => underlyingConnectionFactory.CreateConnection()).MustHaveHappened(0, Times.Exactly); + A.CallTo(() => underlyingConnectionFactory.CreateConnection("SampleUser", "Secret")).MustHaveHappenedOnceExactly(); + } + + [Test] + public void SetConnectionCredentialsOnlyForCurrentThread() + { + var underlyingConnectionFactory = A.Fake(); + var connectionFactory = new UserCredentialsConnectionFactoryAdapter(underlyingConnectionFactory); + + // Call CreateConnection on thread that also called SetCredentialsForCurrentThread + MultithreadingTestHelper.RunOnSeparateThread(() => { - var underlyingConnectionFactory = A.Fake(); - var connectionFactory = new UserCredentialsConnectionFactoryAdapter(underlyingConnectionFactory); - - connectionFactory.CreateConnection(); - - A.CallTo(() => underlyingConnectionFactory.CreateConnection()).MustHaveHappenedOnceExactly(); - A.CallTo(() => underlyingConnectionFactory.CreateConnection(A._, A._)).MustHaveHappened(0, Times.Exactly); - } - - - [Test] - public void CreateConnectionWithoutCredentialsWhenLoginIsNotSet() - { - var underlyingConnectionFactory = A.Fake(); - var connectionFactory = new UserCredentialsConnectionFactoryAdapter(underlyingConnectionFactory); - connectionFactory.Password = "Secret"; - connectionFactory.CreateConnection(); - - A.CallTo(() => underlyingConnectionFactory.CreateConnection()).MustHaveHappenedOnceExactly(); - A.CallTo(() => underlyingConnectionFactory.CreateConnection(A._, A._)).MustHaveHappened(0, Times.Exactly); - } - - [Test] - public void CreateConnectionWithCredentialsWhenTheyAreSet() - { - var underlyingConnectionFactory = A.Fake(); - var connectionFactory = new UserCredentialsConnectionFactoryAdapter(underlyingConnectionFactory); - connectionFactory.UserName = "SampleUser"; - connectionFactory.Password = "Secret"; + connectionFactory.SetCredentialsForCurrentThread("SampleUser", "Password"); connectionFactory.CreateConnection(); A.CallTo(() => underlyingConnectionFactory.CreateConnection()).MustHaveHappened(0, Times.Exactly); - A.CallTo(() => underlyingConnectionFactory.CreateConnection("SampleUser", "Secret")).MustHaveHappenedOnceExactly(); - } + A.CallTo(() => underlyingConnectionFactory.CreateConnection("SampleUser", "Password")).MustHaveHappenedOnceExactly(); + }).Wait(); - - [Test] - public void SetConnectionCredentialsOnlyForCurrentThread() + // Call CreateConnection on thread that didn't callSetCredentialsForCurrentThread + MultithreadingTestHelper.RunOnSeparateThread(() => { - var underlyingConnectionFactory = A.Fake(); - var connectionFactory = new UserCredentialsConnectionFactoryAdapter(underlyingConnectionFactory); - - // Call CreateConnection on thread that also called SetCredentialsForCurrentThread - MultithreadingTestHelper.RunOnSeparateThread(() => - { - connectionFactory.SetCredentialsForCurrentThread("SampleUser", "Password"); - connectionFactory.CreateConnection(); - - A.CallTo(() => underlyingConnectionFactory.CreateConnection()).MustHaveHappened(0, Times.Exactly); - A.CallTo(() => underlyingConnectionFactory.CreateConnection("SampleUser", "Password")).MustHaveHappenedOnceExactly(); - }).Wait(); - - // Call CreateConnection on thread that didn't callSetCredentialsForCurrentThread - MultithreadingTestHelper.RunOnSeparateThread(() => - { - connectionFactory.CreateConnection(); - - A.CallTo(() => underlyingConnectionFactory.CreateConnection()).MustHaveHappenedOnceExactly(); - A.CallTo(() => underlyingConnectionFactory.CreateConnection(A._, A._)).MustHaveHappenedOnceExactly(); - }).Wait(); - - - // Call CreateConnection on the main thread connectionFactory.CreateConnection(); - A.CallTo(() => underlyingConnectionFactory.CreateConnection()).MustHaveHappened(2, Times.Exactly); + A.CallTo(() => underlyingConnectionFactory.CreateConnection()).MustHaveHappenedOnceExactly(); A.CallTo(() => underlyingConnectionFactory.CreateConnection(A._, A._)).MustHaveHappenedOnceExactly(); - } + }).Wait(); - [Test] - public void InheritCredentialsIfTheyAreNotSetForSpecificThread() + // Call CreateConnection on the main thread + connectionFactory.CreateConnection(); + + A.CallTo(() => underlyingConnectionFactory.CreateConnection()).MustHaveHappened(2, Times.Exactly); + A.CallTo(() => underlyingConnectionFactory.CreateConnection(A._, A._)).MustHaveHappenedOnceExactly(); + } + + [Test] + public void InheritCredentialsIfTheyAreNotSetForSpecificThread() + { + var underlyingConnectionFactory = A.Fake(); + var connectionFactory = new UserCredentialsConnectionFactoryAdapter(underlyingConnectionFactory); + + connectionFactory.UserName = "SampleUser"; + connectionFactory.Password = "Secret"; + + // Call CreateConnection on thread that also called SetCredentialsForCurrentThread + MultithreadingTestHelper.RunOnSeparateThread(() => { - var underlyingConnectionFactory = A.Fake(); - var connectionFactory = new UserCredentialsConnectionFactoryAdapter(underlyingConnectionFactory); - - - connectionFactory.UserName = "SampleUser"; - connectionFactory.Password = "Secret"; - - // Call CreateConnection on thread that also called SetCredentialsForCurrentThread - MultithreadingTestHelper.RunOnSeparateThread(() => - { - connectionFactory.CreateConnection(); - A.CallTo(() => underlyingConnectionFactory.CreateConnection()).MustHaveHappened(0, Times.Exactly); - A.CallTo(() => underlyingConnectionFactory.CreateConnection("SampleUser", "Secret")).MustHaveHappenedOnceExactly(); - - - connectionFactory.SetCredentialsForCurrentThread("ThreadSampleUser", "ThreadPassword"); - connectionFactory.CreateConnection(); - A.CallTo(() => underlyingConnectionFactory.CreateConnection()).MustHaveHappened(0, Times.Exactly); - A.CallTo(() => underlyingConnectionFactory.CreateConnection("ThreadSampleUser", "ThreadPassword")).MustHaveHappenedOnceExactly(); - - connectionFactory.RemoveCredentialsFromCurrentThread(); - connectionFactory.CreateConnection(); - A.CallTo(() => underlyingConnectionFactory.CreateConnection()).MustHaveHappened(0, Times.Exactly); - A.CallTo(() => underlyingConnectionFactory.CreateConnection("SampleUser", "Secret")).MustHaveHappened(2, Times.Exactly); - }).Wait(); - - connectionFactory.CreateConnection(); - A.CallTo(() => underlyingConnectionFactory.CreateConnection()).MustHaveHappened(0, Times.Exactly); - A.CallTo(() => underlyingConnectionFactory.CreateConnection("SampleUser", "Secret")).MustHaveHappened(3, Times.Exactly); - } - - [Test] - public void SetDifferentCredentialsOnDifferentThreads() - { - var underlyingConnectionFactory = A.Fake(); - var connectionFactory = new UserCredentialsConnectionFactoryAdapter(underlyingConnectionFactory); - - connectionFactory.UserName = "SampleUser"; - connectionFactory.Password = "Secret"; - - var barrier = new Barrier(2); - - // Call CreateConnection on thread that also called SetCredentialsForCurrentThread - var thread1 = MultithreadingTestHelper.RunOnSeparateThread(() => - { - connectionFactory.SetCredentialsForCurrentThread("Thread1SampleUser", "Password"); - barrier.SignalAndWait(); - - connectionFactory.CreateConnection(); - A.CallTo(() => underlyingConnectionFactory.CreateConnection()).MustHaveHappened(0, Times.Exactly); - A.CallTo(() => underlyingConnectionFactory.CreateConnection("Thread1SampleUser", "Password")).MustHaveHappenedOnceExactly(); - }); - - // Call CreateConnection on thread that didn't callSetCredentialsForCurrentThread - var thread2 = MultithreadingTestHelper.RunOnSeparateThread(() => - { - connectionFactory.SetCredentialsForCurrentThread("Thread2SampleUser", "Password"); - barrier.SignalAndWait(); - - connectionFactory.CreateConnection(); - A.CallTo(() => underlyingConnectionFactory.CreateConnection()).MustHaveHappened(0, Times.Exactly); - A.CallTo(() => underlyingConnectionFactory.CreateConnection("Thread2SampleUser", "Password")).MustHaveHappenedOnceExactly(); - }); - - connectionFactory.CreateConnection(); A.CallTo(() => underlyingConnectionFactory.CreateConnection()).MustHaveHappened(0, Times.Exactly); A.CallTo(() => underlyingConnectionFactory.CreateConnection("SampleUser", "Secret")).MustHaveHappenedOnceExactly(); - thread1.Wait(); - thread2.Wait(); - } + connectionFactory.SetCredentialsForCurrentThread("ThreadSampleUser", "ThreadPassword"); + connectionFactory.CreateConnection(); + A.CallTo(() => underlyingConnectionFactory.CreateConnection()).MustHaveHappened(0, Times.Exactly); + A.CallTo(() => underlyingConnectionFactory.CreateConnection("ThreadSampleUser", "ThreadPassword")).MustHaveHappenedOnceExactly(); + + connectionFactory.RemoveCredentialsFromCurrentThread(); + connectionFactory.CreateConnection(); + A.CallTo(() => underlyingConnectionFactory.CreateConnection()).MustHaveHappened(0, Times.Exactly); + A.CallTo(() => underlyingConnectionFactory.CreateConnection("SampleUser", "Secret")).MustHaveHappened(2, Times.Exactly); + }).Wait(); + + connectionFactory.CreateConnection(); + A.CallTo(() => underlyingConnectionFactory.CreateConnection()).MustHaveHappened(0, Times.Exactly); + A.CallTo(() => underlyingConnectionFactory.CreateConnection("SampleUser", "Secret")).MustHaveHappened(3, Times.Exactly); + } + + [Test] + public void SetDifferentCredentialsOnDifferentThreads() + { + var underlyingConnectionFactory = A.Fake(); + var connectionFactory = new UserCredentialsConnectionFactoryAdapter(underlyingConnectionFactory); + + connectionFactory.UserName = "SampleUser"; + connectionFactory.Password = "Secret"; + + var barrier = new Barrier(2); + + // Call CreateConnection on thread that also called SetCredentialsForCurrentThread + var thread1 = MultithreadingTestHelper.RunOnSeparateThread(() => + { + connectionFactory.SetCredentialsForCurrentThread("Thread1SampleUser", "Password"); + barrier.SignalAndWait(); + + connectionFactory.CreateConnection(); + A.CallTo(() => underlyingConnectionFactory.CreateConnection()).MustHaveHappened(0, Times.Exactly); + A.CallTo(() => underlyingConnectionFactory.CreateConnection("Thread1SampleUser", "Password")).MustHaveHappenedOnceExactly(); + }); + + // Call CreateConnection on thread that didn't callSetCredentialsForCurrentThread + var thread2 = MultithreadingTestHelper.RunOnSeparateThread(() => + { + connectionFactory.SetCredentialsForCurrentThread("Thread2SampleUser", "Password"); + barrier.SignalAndWait(); + + connectionFactory.CreateConnection(); + A.CallTo(() => underlyingConnectionFactory.CreateConnection()).MustHaveHappened(0, Times.Exactly); + A.CallTo(() => underlyingConnectionFactory.CreateConnection("Thread2SampleUser", "Password")).MustHaveHappenedOnceExactly(); + }); + + connectionFactory.CreateConnection(); + A.CallTo(() => underlyingConnectionFactory.CreateConnection()).MustHaveHappened(0, Times.Exactly); + A.CallTo(() => underlyingConnectionFactory.CreateConnection("SampleUser", "Secret")).MustHaveHappenedOnceExactly(); + + thread1.Wait(); + thread2.Wait(); } } diff --git a/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Core/MessageTemplateTests.cs b/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Core/MessageTemplateTests.cs index a0b0e771..95fd2333 100644 --- a/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Core/MessageTemplateTests.cs +++ b/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Core/MessageTemplateTests.cs @@ -30,210 +30,208 @@ using Spring.Transaction.Support; #endregion -namespace Spring.Messaging.Nms.Core +namespace Spring.Messaging.Nms.Core; + +/// +/// This class contains tests for NmsTemplate +/// +/// Mark Pollack +[TestFixture] +public class MessageTemplateTests { - /// - /// This class contains tests for NmsTemplate - /// - /// Mark Pollack - [TestFixture] - public class MessageTemplateTests + private IDestinationResolver mockDestinationResolver; + private IConnectionFactory mockConnectionFactory; + private IConnection mockConnection; + + private ISession mockSession; + + [SetUp] + public void Setup() { - private IDestinationResolver mockDestinationResolver; - private IConnectionFactory mockConnectionFactory; - private IConnection mockConnection; + CreateMocks(); + } - private ISession mockSession; + private NmsTemplate CreateTemplate() + { + NmsTemplate template = new NmsTemplate(); + template.DestinationResolver = mockDestinationResolver; + template.SessionTransacted = UseTransactedTemplate; + return template; + } - [SetUp] - public void Setup() + protected virtual bool UseTransactedSession + { + get { return false; } + } + + protected virtual bool UseTransactedTemplate + { + get { return false; } + } + + private void CreateMocks() + { + mockConnectionFactory = A.Fake(); + mockConnection = A.Fake(); + mockSession = A.Fake(); + + IQueue queue = A.Fake(); + + A.CallTo(() => mockConnectionFactory.CreateConnection()).Returns(mockConnection).Once(); + A.CallTo(() => mockConnectionFactory.CreateConnectionAsync()).Returns(Task.FromResult(mockConnection)).Once(); + if (UseTransactedTemplate) { - CreateMocks(); + A.CallTo(() => mockConnection.CreateSession(AcknowledgementMode.Transactional)).Returns(mockSession).Once(); + A.CallTo(() => mockConnection.CreateSessionAsync(AcknowledgementMode.Transactional)).Returns(Task.FromResult(mockSession)).Once(); + } + else + { + A.CallTo(() => mockConnection.CreateSession(AcknowledgementMode.AutoAcknowledge)).Returns(mockSession).Once(); + A.CallTo(() => mockConnection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge)).Returns(Task.FromResult(mockSession)).Once(); } - private NmsTemplate CreateTemplate() + A.CallTo(() => mockSession.Transacted).Returns(true); + + mockDestinationResolver = A.Fake(); + A.CallTo(() => mockDestinationResolver.ResolveDestinationName(mockSession, "testDestination", false)).Returns(queue); + } + + [Test] + public void ProducerCallback() + { + NmsTemplate template = CreateTemplate(); + template.ConnectionFactory = mockConnectionFactory; + + IMessageProducer mockProducer = A.Fake(); + A.CallTo(() => mockSession.CreateProducer(null)).Returns(mockProducer); + A.CallTo(() => mockProducer.Priority).Returns(MsgPriority.Normal); + + MsgPriority priority = MsgPriority.Highest; + template.Execute((session, producer) => { - NmsTemplate template = new NmsTemplate(); - template.DestinationResolver = mockDestinationResolver; - template.SessionTransacted = UseTransactedTemplate; - return template; - } + bool b = session.Transacted; + priority = producer.Priority; + return null; + }); + Assert.AreEqual(priority, MsgPriority.Normal); + AssertCloseProducerSessionConnection(mockProducer); + } - protected virtual bool UseTransactedSession + [Test] + public void ProducerCallbackWithIdAndTimestampDisabled() + { + NmsTemplate template = CreateTemplate(); + template.ConnectionFactory = mockConnectionFactory; + template.MessageIdEnabled = false; + template.MessageTimestampEnabled = false; + + IMessageProducer mockProducer = A.Fake(); + A.CallTo(() => mockSession.CreateProducer(null)).Returns(mockProducer); + + A.CallTo(() => mockProducer.Priority).Returns(MsgPriority.Normal); + + template.Execute((session, producer) => { - get { return false; } - } + bool b = session.Transacted; + MsgPriority priority = producer.Priority; + return null; + }); - protected virtual bool UseTransactedTemplate + AssertCloseProducerSessionConnection(mockProducer); + A.CallToSet(() => mockProducer.DisableMessageID).WhenArgumentsMatch(x => x.Get(0) == true).MustHaveHappenedOnceExactly(); + A.CallToSet(() => mockProducer.DisableMessageTimestamp).WhenArgumentsMatch(x => x.Get(0) == true).MustHaveHappenedOnceExactly(); + } + + private void AssertCloseProducerSessionConnection(IMessageProducer mockProducer) + { + A.CallTo(() => mockProducer.Close()).MustHaveHappenedOnceExactly(); + A.CallTo(() => mockSession.Close()).MustHaveHappenedOnceExactly(); + A.CallTo(() => mockConnection.Close()).MustHaveHappenedOnceExactly(); + } + + [Test] + public void SessionCallback() + { + NmsTemplate template = CreateTemplate(); + template.ConnectionFactory = mockConnectionFactory; + + template.Execute(session => { - get { return false; } - } + bool b = session.Transacted; + return null; + }); - private void CreateMocks() + A.CallTo(() => mockSession.Close()).MustHaveHappenedOnceExactly(); + A.CallTo(() => mockConnection.Close()).MustHaveHappenedOnceExactly(); + } + + [Ignore("TODO Fix / Investigate")] + [Test] + public void SessionCallbackWithinSynchronizedTransaction() + { + SingleConnectionFactory scf = new SingleConnectionFactory(mockConnectionFactory); + NmsTemplate template = CreateTemplate(); + template.ConnectionFactory = scf; + + // We're gonna call getTransacted 3 times, i.e. 2 more times. + A.CallTo(() => mockSession.Transacted).Returns(UseTransactedSession); + + TransactionSynchronizationManager.InitSynchronization(); + + try { - mockConnectionFactory = A.Fake(); - mockConnection = A.Fake(); - mockSession = A.Fake(); - - IQueue queue = A.Fake(); - - A.CallTo(() => mockConnectionFactory.CreateConnection()).Returns(mockConnection).Once(); - A.CallTo(() => mockConnectionFactory.CreateConnectionAsync()).Returns( Task.FromResult(mockConnection)).Once(); - if (UseTransactedTemplate) - { - A.CallTo(() => mockConnection.CreateSession(AcknowledgementMode.Transactional)).Returns(mockSession).Once(); - A.CallTo(() => mockConnection.CreateSessionAsync(AcknowledgementMode.Transactional)).Returns( Task.FromResult(mockSession)).Once(); - } - else - { - A.CallTo(() => mockConnection.CreateSession(AcknowledgementMode.AutoAcknowledge)).Returns(mockSession).Once(); - A.CallTo(() => mockConnection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge)).Returns( Task.FromResult(mockSession)).Once(); - } - - A.CallTo(() => mockSession.Transacted).Returns(true); - - mockDestinationResolver = A.Fake(); - A.CallTo(() => mockDestinationResolver.ResolveDestinationName(mockSession, "testDestination", false)).Returns(queue); - } - - [Test] - public void ProducerCallback() - { - NmsTemplate template = CreateTemplate(); - template.ConnectionFactory = mockConnectionFactory; - - IMessageProducer mockProducer = A.Fake(); - A.CallTo(() => mockSession.CreateProducer(null)).Returns(mockProducer); - A.CallTo(() => mockProducer.Priority).Returns(MsgPriority.Normal); - - MsgPriority priority = MsgPriority.Highest; - template.Execute((session, producer) => + template.Execute(session => { bool b = session.Transacted; - priority = producer.Priority; return null; - }); - - Assert.AreEqual(priority, MsgPriority.Normal); - AssertCloseProducerSessionConnection(mockProducer); - } - - [Test] - public void ProducerCallbackWithIdAndTimestampDisabled() - { - NmsTemplate template = CreateTemplate(); - template.ConnectionFactory = mockConnectionFactory; - template.MessageIdEnabled = false; - template.MessageTimestampEnabled = false; - - IMessageProducer mockProducer = A.Fake(); - A.CallTo(() => mockSession.CreateProducer(null)).Returns(mockProducer); - - A.CallTo(() => mockProducer.Priority).Returns(MsgPriority.Normal); - - template.Execute((session, producer) => + template.Execute(session => { bool b = session.Transacted; - MsgPriority priority = producer.Priority; return null; }); - AssertCloseProducerSessionConnection(mockProducer); - A.CallToSet(() => mockProducer.DisableMessageID).WhenArgumentsMatch(x => x.Get(0) == true).MustHaveHappenedOnceExactly(); - A.CallToSet(() => mockProducer.DisableMessageTimestamp).WhenArgumentsMatch(x => x.Get(0) == true).MustHaveHappenedOnceExactly(); - } + Assert.AreSame(mockSession, ConnectionFactoryUtils.GetTransactionalSession(scf, null, false)); + var session = ConnectionFactoryUtils.GetTransactionalSession(scf, scf.CreateConnection(), false); + Assert.AreSame(mockSession, session); - private void AssertCloseProducerSessionConnection(IMessageProducer mockProducer) - { - A.CallTo(() => mockProducer.Close()).MustHaveHappenedOnceExactly(); - A.CallTo(() => mockSession.Close()).MustHaveHappenedOnceExactly(); - A.CallTo(() => mockConnection.Close()).MustHaveHappenedOnceExactly(); - } - - [Test] - public void SessionCallback() - { - NmsTemplate template = CreateTemplate(); - template.ConnectionFactory = mockConnectionFactory; + //In Java this test was doing 'double-duty' and testing TransactionAwareConnectionFactoryProxy, which has + //not been implemented in .NET template.Execute(session => - { - bool b = session.Transacted; - return null; - }); + { + bool b = session.Transacted; + return null; + }); - A.CallTo(() => mockSession.Close()).MustHaveHappenedOnceExactly(); - A.CallTo(() => mockConnection.Close()).MustHaveHappenedOnceExactly(); + IList synchs = TransactionSynchronizationManager.Synchronizations; + Assert.AreEqual(1, synchs.Count); + ITransactionSynchronization synch = (ITransactionSynchronization) synchs[0]; + synch.BeforeCommit(false); + synch.BeforeCompletion(); + synch.AfterCommit(); + synch.AfterCompletion(TransactionSynchronizationStatus.Unknown); } - - [Ignore("TODO Fix / Investigate")] - [Test] - public void SessionCallbackWithinSynchronizedTransaction() + finally { - SingleConnectionFactory scf = new SingleConnectionFactory(mockConnectionFactory); - NmsTemplate template = CreateTemplate(); - template.ConnectionFactory = scf; - - // We're gonna call getTransacted 3 times, i.e. 2 more times. - A.CallTo(() => mockSession.Transacted).Returns(UseTransactedSession); - - TransactionSynchronizationManager.InitSynchronization(); - - try - { - template.Execute(session => - { - bool b = session.Transacted; - return null; - }); - template.Execute(session => - { - bool b = session.Transacted; - return null; - }); - - Assert.AreSame(mockSession, ConnectionFactoryUtils.GetTransactionalSession(scf, null, false)); - var session = ConnectionFactoryUtils.GetTransactionalSession(scf, scf.CreateConnection(), false); - Assert.AreSame(mockSession,session); - - //In Java this test was doing 'double-duty' and testing TransactionAwareConnectionFactoryProxy, which has - //not been implemented in .NET - - template.Execute(session => - { - bool b = session.Transacted; - return null; - }); - - IList synchs = TransactionSynchronizationManager.Synchronizations; - Assert.AreEqual(1, synchs.Count); - ITransactionSynchronization synch = (ITransactionSynchronization) synchs[0]; - synch.BeforeCommit(false); - synch.BeforeCompletion(); - synch.AfterCommit(); - synch.AfterCompletion(TransactionSynchronizationStatus.Unknown); - } - finally - { - TransactionSynchronizationManager.ClearSynchronization(); - //Assert.IsTrue(TransactionSynchronizationManager.ResourceDictionary.Count == 0); - //Assert.IsFalse(TransactionSynchronizationManager.SynchronizationActive); - scf.Dispose(); - } - Assert.IsTrue(TransactionSynchronizationManager.ResourceDictionary.Count == 0); - - A.CallTo(() => mockConnection.Start()).MustHaveHappenedTwiceExactly(); - - if (UseTransactedTemplate) - { - A.CallTo(() => mockSession.Commit()).MustHaveHappenedOnceExactly(); - } - - A.CallTo(() => mockSession.Close()).MustHaveHappenedOnceExactly(); - A.CallTo(() => mockConnection.Stop()).MustHaveHappenedOnceExactly(); - A.CallTo(() => mockConnection.Close()).MustHaveHappenedOnceExactly(); + TransactionSynchronizationManager.ClearSynchronization(); + //Assert.IsTrue(TransactionSynchronizationManager.ResourceDictionary.Count == 0); + //Assert.IsFalse(TransactionSynchronizationManager.SynchronizationActive); + scf.Dispose(); } + + Assert.IsTrue(TransactionSynchronizationManager.ResourceDictionary.Count == 0); + + A.CallTo(() => mockConnection.Start()).MustHaveHappenedTwiceExactly(); + + if (UseTransactedTemplate) + { + A.CallTo(() => mockSession.Commit()).MustHaveHappenedOnceExactly(); + } + + A.CallTo(() => mockSession.Close()).MustHaveHappenedOnceExactly(); + A.CallTo(() => mockConnection.Stop()).MustHaveHappenedOnceExactly(); + A.CallTo(() => mockConnection.Close()).MustHaveHappenedOnceExactly(); } } diff --git a/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Core/SimpleMessageConverterTests.cs b/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Core/SimpleMessageConverterTests.cs index 32674351..30c5efcc 100644 --- a/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Core/SimpleMessageConverterTests.cs +++ b/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Core/SimpleMessageConverterTests.cs @@ -22,145 +22,139 @@ using System.Collections; using System.Text; - using Apache.NMS; using Apache.NMS.Util; - using FakeItEasy; - using NUnit.Framework; - using Spring.Messaging.Nms.Support.Converter; #endregion -namespace Spring.Messaging.Nms.Core +namespace Spring.Messaging.Nms.Core; + +/// +/// This class contains tests for SimpleMessageConverer +/// +/// Mark Pollack +[TestFixture] +public class SimpleMessageConverterTests { - /// - /// This class contains tests for SimpleMessageConverer - /// - /// Mark Pollack - [TestFixture] - public class SimpleMessageConverterTests + private SimpleMessageConverter converter; + private ISession session; + + [SetUp] + public void Setup() { - private SimpleMessageConverter converter; - private ISession session; + session = A.Fake(); + converter = new SimpleMessageConverter(); + } - [SetUp] - public void Setup() - { - session = A.Fake(); - converter = new SimpleMessageConverter(); - } + [Test] + public void StringConversion() + { + ITextMessage message = A.Fake(); + string content = "test"; - [Test] - public void StringConversion() - { - ITextMessage message = A.Fake(); - string content = "test"; + A.CallTo(() => session.CreateTextMessage(content)).Returns(message).Once(); + A.CallTo(() => message.Text).Returns(content).Once(); - A.CallTo(() => session.CreateTextMessage(content)).Returns(message).Once(); - A.CallTo(() => message.Text).Returns(content).Once(); + IMessage msg = converter.ToMessage(content, session); + Assert.AreEqual(content, converter.FromMessage(msg)); + } - IMessage msg = converter.ToMessage(content, session); - Assert.AreEqual(content, converter.FromMessage(msg)); - } + [Test] + public void ByteArrayConversion() + { + IBytesMessage message = A.Fake(); + ASCIIEncoding encoding = new ASCIIEncoding(); + byte[] content = encoding.GetBytes("test"); - [Test] - public void ByteArrayConversion() - { - IBytesMessage message = A.Fake(); - ASCIIEncoding encoding = new ASCIIEncoding(); - byte[] content = encoding.GetBytes("test"); + A.CallTo(() => session.CreateBytesMessage()).Returns(message); + A.CallTo(() => message.Content).Returns(content).Once(); - A.CallTo(() => session.CreateBytesMessage()).Returns(message); - A.CallTo(() => message.Content).Returns(content).Once(); - - IMessage msg = converter.ToMessage(content, session); - Assert.AreEqual(content.Length, ((byte[])converter.FromMessage(msg)).Length); - A.CallTo(() => message.Content).WithAnyArguments().MustHaveHappened(); - } + IMessage msg = converter.ToMessage(content, session); + Assert.AreEqual(content.Length, ((byte[]) converter.FromMessage(msg)).Length); + A.CallTo(() => message.Content).WithAnyArguments().MustHaveHappened(); + } - [Test] - public void MapConversion() - { - IMapMessage message = A.Fake(); - IPrimitiveMap primitiveMap = new PrimitiveMap(); - IDictionary content = new Hashtable(); - content["key1"] = "value1"; - content["key2"] = "value2"; + [Test] + public void MapConversion() + { + IMapMessage message = A.Fake(); + IPrimitiveMap primitiveMap = new PrimitiveMap(); + IDictionary content = new Hashtable(); + content["key1"] = "value1"; + content["key2"] = "value2"; - A.CallTo(() => session.CreateMapMessage()).Returns(message).Once(); - A.CallTo(() => message.Body).Returns(primitiveMap); - //can't seem to mock indexer... - - IMessage msg = converter.ToMessage(content, session); - Assert.AreEqual(content, converter.FromMessage(msg)); - } + A.CallTo(() => session.CreateMapMessage()).Returns(message).Once(); + A.CallTo(() => message.Body).Returns(primitiveMap); + //can't seem to mock indexer... - [Test] - public void Serializable() - { - IObjectMessage message = A.Fake(); + IMessage msg = converter.ToMessage(content, session); + Assert.AreEqual(content, converter.FromMessage(msg)); + } - SerializableWithAttribute content = new SerializableWithAttribute(); + [Test] + public void Serializable() + { + IObjectMessage message = A.Fake(); - A.CallTo(() => session.CreateObjectMessage(content)).Returns(message).Once(); - A.CallTo(() => message.Body).Returns(content).Once(); + SerializableWithAttribute content = new SerializableWithAttribute(); - IMessage msg = converter.ToMessage(content, session); - Assert.AreEqual(content, converter.FromMessage(message)); - } + A.CallTo(() => session.CreateObjectMessage(content)).Returns(message).Once(); + A.CallTo(() => message.Body).Returns(content).Once(); - [Test] - public void ToMessageThrowsExceptionIfGivenNullObjectToConvert() - { - Assert.Throws(() => converter.ToMessage(null, null)); - } + IMessage msg = converter.ToMessage(content, session); + Assert.AreEqual(content, converter.FromMessage(message)); + } - [Test] - public void ToMessageThrowsExceptionIfGivenIncompatibleObjectToConvert() - { - Assert.Throws(() => converter.ToMessage(new Cafe(), null)); - } + [Test] + public void ToMessageThrowsExceptionIfGivenNullObjectToConvert() + { + Assert.Throws(() => converter.ToMessage(null, null)); + } - [Test] - public void ToMessageSimplyReturnsMessageAsIsIfSuppliedWithMessage() - { - IObjectMessage message = A.Fake(); - IMessage msg = converter.ToMessage(message, session); - Assert.AreSame(message, msg); - } + [Test] + public void ToMessageThrowsExceptionIfGivenIncompatibleObjectToConvert() + { + Assert.Throws(() => converter.ToMessage(new Cafe(), null)); + } - [Test] - public void FromMessageSimplyReturnsMessageAsIsIfSuppliedWithMessage() - { - IMessage message = A.Fake(); - Object msg = converter.FromMessage(message); - Assert.AreSame(message, msg); - } + [Test] + public void ToMessageSimplyReturnsMessageAsIsIfSuppliedWithMessage() + { + IObjectMessage message = A.Fake(); + IMessage msg = converter.ToMessage(message, session); + Assert.AreSame(message, msg); + } - [Test] - public void DictionaryConversionWhereMapHasNonStringTypesForKeys() - { - IMapMessage message = A.Fake(); + [Test] + public void FromMessageSimplyReturnsMessageAsIsIfSuppliedWithMessage() + { + IMessage message = A.Fake(); + Object msg = converter.FromMessage(message); + Assert.AreSame(message, msg); + } - A.CallTo(() => session.CreateMapMessage()).Returns(message); + [Test] + public void DictionaryConversionWhereMapHasNonStringTypesForKeys() + { + IMapMessage message = A.Fake(); - var content = new Hashtable(); - content.Add(new Cafe(), "value1"); + A.CallTo(() => session.CreateMapMessage()).Returns(message); - Assert.Throws(() => converter.ToMessage(content, session)); - } + var content = new Hashtable(); + content.Add(new Cafe(), "value1"); - [Serializable] - public class SerializableWithAttribute - { - } + Assert.Throws(() => converter.ToMessage(content, session)); + } - public class Cafe - { - - } + [Serializable] + public class SerializableWithAttribute + { + } + + public class Cafe + { } } diff --git a/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Core/SimpleMessageListenerContainerTests.cs b/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Core/SimpleMessageListenerContainerTests.cs index 2a08c4fb..1b9fa91b 100644 --- a/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Core/SimpleMessageListenerContainerTests.cs +++ b/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Core/SimpleMessageListenerContainerTests.cs @@ -21,178 +21,174 @@ #region Imports using Apache.NMS; - using FakeItEasy; - using NUnit.Framework; - using Spring.Messaging.Nms.Listener; using Spring.Util; #endregion -namespace Spring.Messaging.Nms.Core +namespace Spring.Messaging.Nms.Core; + +/// +/// This class contains tests for SimpleMessageListenerContainer +/// +/// Mark Pollack +[TestFixture] +public class SimpleMessageListenerContainerTests { - /// - /// This class contains tests for SimpleMessageListenerContainer - /// - /// Mark Pollack - [TestFixture] - public class SimpleMessageListenerContainerTests + private static string DESTINATION_NAME = "foo"; + private static StubQueue QUEUE_DESTINATION = new StubQueue(); + private static string EXCEPTION_MESSAGE = "This.Is.It"; + private SimpleMessageListenerContainer container; + + [SetUp] + public void Setup() { - private static string DESTINATION_NAME = "foo"; - private static StubQueue QUEUE_DESTINATION = new StubQueue(); - private static string EXCEPTION_MESSAGE = "This.Is.It"; - private SimpleMessageListenerContainer container; + container = new SimpleMessageListenerContainer(); + } - [SetUp] - public void Setup() + [Test] + public void RegisteredExceptionListenerIsInvokedOnException() + { + SimpleMessageConsumer messageConsumer = new SimpleMessageConsumer(); + + ISession session = A.Fake(); + A.CallTo(() => session.GetQueue(DESTINATION_NAME)).Returns(QUEUE_DESTINATION); + A.CallTo(() => session.CreateConsumer(QUEUE_DESTINATION, null)).Returns(messageConsumer); + // an exception is thrown, so the rollback logic is being applied here... + A.CallTo(() => session.Transacted).Returns(false); + + IConnection connection = A.Fake(); + connection.ExceptionListener += container.OnException; + A.CallTo(() => connection.CreateSession(container.SessionAcknowledgeMode)).Returns(session); + connection.Start(); + + IConnectionFactory connectionFactory = A.Fake(); + A.CallTo(() => connectionFactory.CreateConnection()).Returns(connection); + + NMSException theException = new NMSException(EXCEPTION_MESSAGE); + + IExceptionListener exceptionListener = A.Fake(); + exceptionListener.OnException(theException); + + IMessage message = A.Fake(); + + container.ConnectionFactory = connectionFactory; + container.DestinationName = DESTINATION_NAME; + container.MessageListener = new BadSessionAwareMessageListener(theException); + container.ExceptionListener = exceptionListener; + container.AfterPropertiesSet(); + + // manually trigger an Exception with the above bad MessageListener... + messageConsumer.SendMessage(message); + } + + [Test] + public void RegisteredErrorHandlerIsInvokedOnException() + { + SimpleMessageConsumer messageConsumer = new SimpleMessageConsumer(); + + ISession session = A.Fake(); + A.CallTo((() => session.GetQueue(DESTINATION_NAME))).Returns(QUEUE_DESTINATION); + A.CallTo((() => session.CreateConsumer(QUEUE_DESTINATION, null))).Returns(messageConsumer); + // an exception is thrown, so the rollback logic is being applied here... + A.CallTo((() => session.Transacted)).Returns(false); + + IConnection connection = A.Fake(); + connection.ExceptionListener += container.OnException; + A.CallTo((() => connection.CreateSession(container.SessionAcknowledgeMode))).Returns(session); + connection.Start(); + + IConnectionFactory connectionFactory = A.Fake(); + A.CallTo((() => connectionFactory.CreateConnection())).Returns(connection); + + IllegalStateException theException = new IllegalStateException(EXCEPTION_MESSAGE); + + IErrorHandler errorHandler = A.Fake(); + errorHandler.HandleError(theException); + + IMessage message = A.Fake(); + + container.ConnectionFactory = connectionFactory; + container.DestinationName = DESTINATION_NAME; + container.MessageListener = new BadSessionAwareMessageListener(theException); + container.ErrorHandler = errorHandler; + container.AfterPropertiesSet(); + + // manually trigger an Exception with the above bad MessageListener... + messageConsumer.SendMessage(message); + } + + internal class BadSessionAwareMessageListener : ISessionAwareMessageListener + { + private NMSException exception; + + public BadSessionAwareMessageListener(NMSException exception) { - container = new SimpleMessageListenerContainer(); + this.exception = exception; } - [Test] - public void RegisteredExceptionListenerIsInvokedOnException() + public void OnMessage(IMessage message, ISession session) { - SimpleMessageConsumer messageConsumer = new SimpleMessageConsumer(); + throw exception; + } + } - ISession session = A.Fake(); - A.CallTo(() => session.GetQueue(DESTINATION_NAME)).Returns(QUEUE_DESTINATION); - A.CallTo(() => session.CreateConsumer(QUEUE_DESTINATION, null)).Returns(messageConsumer); - // an exception is thrown, so the rollback logic is being applied here... - A.CallTo(() => session.Transacted).Returns(false); + internal class SimpleMessageConsumer : IMessageConsumer + { + public string MessageSelector { get; } + public event MessageListener Listener; - IConnection connection = A.Fake(); - connection.ExceptionListener += container.OnException; - A.CallTo(() => connection.CreateSession(container.SessionAcknowledgeMode)).Returns(session); - connection.Start(); - - IConnectionFactory connectionFactory = A.Fake(); - A.CallTo(() => connectionFactory.CreateConnection()).Returns(connection); - - NMSException theException = new NMSException(EXCEPTION_MESSAGE); - - IExceptionListener exceptionListener = A.Fake(); - exceptionListener.OnException(theException); - - IMessage message = A.Fake(); - - container.ConnectionFactory = connectionFactory; - container.DestinationName = DESTINATION_NAME; - container.MessageListener = new BadSessionAwareMessageListener(theException); - container.ExceptionListener = exceptionListener; - container.AfterPropertiesSet(); - - // manually trigger an Exception with the above bad MessageListener... - messageConsumer.SendMessage(message); + public void SendMessage(IMessage message) + { + Listener(message); } - [Test] - public void RegisteredErrorHandlerIsInvokedOnException() + public IMessage Receive() { - SimpleMessageConsumer messageConsumer = new SimpleMessageConsumer(); - - ISession session = A.Fake(); - A.CallTo((() => session.GetQueue(DESTINATION_NAME))).Returns(QUEUE_DESTINATION); - A.CallTo((() => session.CreateConsumer(QUEUE_DESTINATION, null))).Returns(messageConsumer); - // an exception is thrown, so the rollback logic is being applied here... - A.CallTo((() => session.Transacted)).Returns(false); - - IConnection connection = A.Fake(); - connection.ExceptionListener += container.OnException; - A.CallTo((() => connection.CreateSession(container.SessionAcknowledgeMode))).Returns(session); - connection.Start(); - - IConnectionFactory connectionFactory = A.Fake(); - A.CallTo((() => connectionFactory.CreateConnection())).Returns(connection); - - IllegalStateException theException = new IllegalStateException(EXCEPTION_MESSAGE); - - IErrorHandler errorHandler = A.Fake(); - errorHandler.HandleError(theException); - - IMessage message = A.Fake(); - - container.ConnectionFactory = connectionFactory; - container.DestinationName = DESTINATION_NAME; - container.MessageListener = new BadSessionAwareMessageListener(theException); - container.ErrorHandler = errorHandler; - container.AfterPropertiesSet(); - - // manually trigger an Exception with the above bad MessageListener... - messageConsumer.SendMessage(message); + throw new NotImplementedException(); } - internal class BadSessionAwareMessageListener : ISessionAwareMessageListener + public Task ReceiveAsync() { - private NMSException exception; - - public BadSessionAwareMessageListener(NMSException exception) - { - this.exception = exception; - } - - public void OnMessage(IMessage message, ISession session) - { - throw exception; - } + throw new NotImplementedException(); } - internal class SimpleMessageConsumer : IMessageConsumer + public IMessage Receive(TimeSpan timeout) { - public string MessageSelector { get; } - public event MessageListener Listener; + throw new NotImplementedException(); + } - public void SendMessage(IMessage message) - { - Listener(message); - } + public Task ReceiveAsync(TimeSpan timeout) + { + throw new NotImplementedException(); + } - public IMessage Receive() - { - throw new NotImplementedException(); - } + public IMessage ReceiveNoWait() + { + throw new NotImplementedException(); + } - public Task ReceiveAsync() - { - throw new NotImplementedException(); - } + public void Close() + { + throw new NotImplementedException(); + } - public IMessage Receive(TimeSpan timeout) - { - throw new NotImplementedException(); - } + public Task CloseAsync() + { + throw new NotImplementedException(); + } - public Task ReceiveAsync(TimeSpan timeout) - { - throw new NotImplementedException(); - } + public ConsumerTransformerDelegate ConsumerTransformer + { + get { throw new NotImplementedException(); } + set { throw new NotImplementedException(); } + } - public IMessage ReceiveNoWait() - { - throw new NotImplementedException(); - } - - public void Close() - { - throw new NotImplementedException(); - } - - public Task CloseAsync() - { - throw new NotImplementedException(); - } - - public ConsumerTransformerDelegate ConsumerTransformer - { - get { throw new NotImplementedException(); } - set { throw new NotImplementedException(); } - } - - public void Dispose() - { - throw new NotImplementedException(); - } + public void Dispose() + { + throw new NotImplementedException(); } } } diff --git a/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Integration/LoggingExceptionHandler.cs b/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Integration/LoggingExceptionHandler.cs index d1bd23aa..1943a815 100644 --- a/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Integration/LoggingExceptionHandler.cs +++ b/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Integration/LoggingExceptionHandler.cs @@ -1,27 +1,25 @@ using Microsoft.Extensions.Logging; using Spring.Messaging.Nms.Core; -namespace Spring.Messaging.Nms.Integration +namespace Spring.Messaging.Nms.Integration; + +/// +/// +/// +public class LoggingExceptionHandler : IExceptionListener { - /// - /// - /// - public class LoggingExceptionHandler : IExceptionListener + #region Logging Definition + + private static readonly ILog LOG = LogManager.GetLogger(typeof(LoggingExceptionHandler)); + + #endregion + + #region IExceptionListener Members + + public void OnException(Exception e) { - #region Logging Definition - - private static readonly ILog LOG = LogManager.GetLogger(typeof (LoggingExceptionHandler)); - - #endregion - - - #region IExceptionListener Members - - public void OnException(Exception e) - { - LOG.LogError(e, "Exception processing message"); - } - - #endregion + LOG.LogError(e, "Exception processing message"); } + + #endregion } diff --git a/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Integration/SimpleMessageListener.cs b/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Integration/SimpleMessageListener.cs index 971712d2..d441a22c 100644 --- a/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Integration/SimpleMessageListener.cs +++ b/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Integration/SimpleMessageListener.cs @@ -1,41 +1,38 @@ - - using Spring.Messaging.Nms.Core; using Apache.NMS; using Microsoft.Extensions.Logging; -namespace Spring.Messaging.Nms.Integration +namespace Spring.Messaging.Nms.Integration; + +public class SimpleMessageListener : IMessageListener { - public class SimpleMessageListener : IMessageListener + #region Logging Definition + + private static readonly ILogger LOG = LogManager.GetLogger(); + + #endregion + + private IMessage lastReceivedMessage; + private int messageCount; + + public IMessage LastReceivedMessage { - #region Logging Definition - - private static readonly ILogger LOG = LogManager.GetLogger(); - #endregion - - private IMessage lastReceivedMessage; - private int messageCount; - - public IMessage LastReceivedMessage - { - get { return lastReceivedMessage; } - } - - - public int MessageCount - { - get { return messageCount; } - } - - #region IMessageListener Members - - public void OnMessage(IMessage message) - { - lastReceivedMessage = message; - messageCount++; - LOG.LogDebug("Message listener count = " + messageCount); - } - - #endregion + get { return lastReceivedMessage; } } + + public int MessageCount + { + get { return messageCount; } + } + + #region IMessageListener Members + + public void OnMessage(IMessage message) + { + lastReceivedMessage = message; + messageCount++; + LOG.LogDebug("Message listener count = " + messageCount); + } + + #endregion } diff --git a/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Integration/SimpleMessageListenerContainerTests.cs b/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Integration/SimpleMessageListenerContainerTests.cs index 9491bcd8..f4357dc2 100644 --- a/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Integration/SimpleMessageListenerContainerTests.cs +++ b/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Integration/SimpleMessageListenerContainerTests.cs @@ -27,62 +27,54 @@ using Spring.Testing.NUnit; #endregion -namespace Spring.Messaging.Nms.Integration +namespace Spring.Messaging.Nms.Integration; + +/// +/// This class contains integration tests for the SimpleMessageListenerContainer +/// +/// Mark Pollack +/// $Id:$ +[TestFixture] +public class SimpleMessageListenerContainerTests : AbstractDependencyInjectionSpringContextTests { - /// - /// This class contains integration tests for the SimpleMessageListenerContainer - /// - /// Mark Pollack - /// $Id:$ - [TestFixture] - public class SimpleMessageListenerContainerTests : AbstractDependencyInjectionSpringContextTests + [Test] + [Explicit] + public void SendAndAsyncReceive() { + SimpleMessageListenerContainer container = + (SimpleMessageListenerContainer) applicationContext["SimpleMessageListenerContainer"]; + SimpleMessageListener listener = applicationContext["SimpleMessageListener"] as SimpleMessageListener; + Assert.IsNotNull(container); + Assert.IsNotNull(listener); - [Test] - [Explicit] - public void SendAndAsyncReceive() - { - SimpleMessageListenerContainer container = - (SimpleMessageListenerContainer) applicationContext["SimpleMessageListenerContainer"]; - SimpleMessageListener listener = applicationContext["SimpleMessageListener"] as SimpleMessageListener; - Assert.IsNotNull(container); - Assert.IsNotNull(listener); - + NmsTemplate nmsTemplate = (NmsTemplate) applicationContext["NmsTemplate"] as NmsTemplate; + Assert.IsNotNull(nmsTemplate); - NmsTemplate nmsTemplate = (NmsTemplate) applicationContext["NmsTemplate"] as NmsTemplate; - Assert.IsNotNull(nmsTemplate); + Assert.AreEqual(0, listener.MessageCount); + nmsTemplate.ConvertAndSend("Hello World 1"); - Assert.AreEqual(0, listener.MessageCount); - nmsTemplate.ConvertAndSend("Hello World 1"); + int waitInMillis = 2000; + Thread.Sleep(waitInMillis); + Assert.AreEqual(1, listener.MessageCount); - int waitInMillis = 2000; - Thread.Sleep(waitInMillis); - Assert.AreEqual(1,listener.MessageCount); + container.Stop(); + Console.WriteLine("container stopped."); + nmsTemplate.ConvertAndSend("Hello World 2"); + Thread.Sleep(waitInMillis); + Assert.AreEqual(1, listener.MessageCount); - container.Stop(); - Console.WriteLine("container stopped."); - nmsTemplate.ConvertAndSend("Hello World 2"); - Thread.Sleep(waitInMillis); - Assert.AreEqual(1, listener.MessageCount); + container.Start(); + Console.WriteLine("container started."); + Thread.Sleep(waitInMillis); + Assert.AreEqual(2, listener.MessageCount); - container.Start(); - Console.WriteLine("container started."); - Thread.Sleep(waitInMillis); - Assert.AreEqual(2, listener.MessageCount); - - container.Shutdown(); + container.Shutdown(); - Thread.Sleep(waitInMillis); + Thread.Sleep(waitInMillis); + } - - } - - - protected override string[] ConfigLocations - { - get { return new string[] { "assembly://Spring.Messaging.Nms.Tests/Spring.Messaging.Nms.Integration/SimpleMessageListenerContainerTests.xml" }; } - } - - + protected override string[] ConfigLocations + { + get { return new string[] { "assembly://Spring.Messaging.Nms.Tests/Spring.Messaging.Nms.Integration/SimpleMessageListenerContainerTests.xml" }; } } } diff --git a/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Integration/SimpleMessageListenerContainerTests.xml b/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Integration/SimpleMessageListenerContainerTests.xml index cf8de992..39726629 100644 --- a/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Integration/SimpleMessageListenerContainerTests.xml +++ b/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Integration/SimpleMessageListenerContainerTests.xml @@ -2,29 +2,31 @@ - - - - - - - - - - - - - + + + + - + + + + + + + + + + - - - - + + + + \ No newline at end of file diff --git a/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Listener/Adapter/IMessageContentsHandler.cs b/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Listener/Adapter/IMessageContentsHandler.cs index 33c4724e..6c2c9173 100644 --- a/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Listener/Adapter/IMessageContentsHandler.cs +++ b/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Listener/Adapter/IMessageContentsHandler.cs @@ -1,5 +1,3 @@ - - #region License /* @@ -22,22 +20,21 @@ using System.Collections; -namespace Spring.Messaging.Nms.Listener.Adapter +namespace Spring.Messaging.Nms.Listener.Adapter; + +/// +/// Used in MessageListenerAdapterTests +/// +/// Mark Pollack +public interface IMessageContentsHandler { - /// - /// Used in MessageListenerAdapterTests - /// - /// Mark Pollack - public interface IMessageContentsHandler - { - void HandleMessage(IDictionary message); + void HandleMessage(IDictionary message); - void HandleMessage(byte[] message); + void HandleMessage(byte[] message); - void HandleMessage(int message); + void HandleMessage(int message); - void HandleMessage(object message); + void HandleMessage(object message); - void HandleMessage(string message); - } -} \ No newline at end of file + void HandleMessage(string message); +} diff --git a/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Listener/Adapter/MessageContentsHandler.cs b/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Listener/Adapter/MessageContentsHandler.cs index 424c7139..eb7b0a10 100644 --- a/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Listener/Adapter/MessageContentsHandler.cs +++ b/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Listener/Adapter/MessageContentsHandler.cs @@ -20,44 +20,43 @@ using System.Collections; -namespace Spring.Messaging.Nms.Listener.Adapter +namespace Spring.Messaging.Nms.Listener.Adapter; + +/// +/// +/// +/// +/// +/// +/// Mark Pollack +public class MessageContentsHandler : IMessageContentsHandler { - /// - /// - /// - /// - /// - /// - /// Mark Pollack - public class MessageContentsHandler : IMessageContentsHandler + public int HandledStringCount; + + public int HandledByteArrayCount; + + public void HandleMessage(IDictionary message) { - public int HandledStringCount; - - public int HandledByteArrayCount; - - public void HandleMessage(IDictionary message) - { - throw new System.NotImplementedException(); - } - - public void HandleMessage(byte[] message) - { - HandledByteArrayCount++; - } - - public void HandleMessage(int message) - { - throw new System.NotImplementedException(); - } - - public void HandleMessage(object message) - { - throw new System.NotImplementedException(); - } - - public void HandleMessage(string message) - { - HandledStringCount++; - } + throw new System.NotImplementedException(); } -} \ No newline at end of file + + public void HandleMessage(byte[] message) + { + HandledByteArrayCount++; + } + + public void HandleMessage(int message) + { + throw new System.NotImplementedException(); + } + + public void HandleMessage(object message) + { + throw new System.NotImplementedException(); + } + + public void HandleMessage(string message) + { + HandledStringCount++; + } +} diff --git a/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Listener/Adapter/MessageListenerAdapterTests.cs b/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Listener/Adapter/MessageListenerAdapterTests.cs index 37fb4ce3..1835cd24 100644 --- a/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Listener/Adapter/MessageListenerAdapterTests.cs +++ b/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Listener/Adapter/MessageListenerAdapterTests.cs @@ -21,86 +21,82 @@ #region Imports using System.Text; - using Apache.NMS; - using FakeItEasy; - using NUnit.Framework; #endregion -namespace Spring.Messaging.Nms.Listener.Adapter +namespace Spring.Messaging.Nms.Listener.Adapter; + +/// +/// This class contains tests for MessageListenerAdapter +/// +/// Mark Pollack +/// $Id:$ +[TestFixture] +public class MessageListenerAdapterTests { - /// - /// This class contains tests for MessageListenerAdapter - /// - /// Mark Pollack - /// $Id:$ - [TestFixture] - public class MessageListenerAdapterTests + private static string TEXT = "I fancy a good cuppa right now"; + + [Test] + public void MessageContentsHandlerForTextMessage() { - private static string TEXT = "I fancy a good cuppa right now"; + int numIterations = 10; + ITextMessage message = A.Fake(); + A.CallTo(() => message.Text).Returns(TEXT).NumberOfTimes(numIterations); + MessageContentsHandler handler = new MessageContentsHandler(); - [Test] - public void MessageContentsHandlerForTextMessage() + MessageListenerAdapter adapter = new MessageListenerAdapter(handler); + for (int i = 0; i < numIterations; i++) { - int numIterations = 10; - ITextMessage message = A.Fake(); - A.CallTo(() => message.Text).Returns(TEXT).NumberOfTimes(numIterations); - MessageContentsHandler handler = new MessageContentsHandler(); - - MessageListenerAdapter adapter = new MessageListenerAdapter(handler); - for (int i = 0; i < numIterations; i++) - { - adapter.OnMessage(message); - } - - Assert.AreEqual(numIterations, handler.HandledStringCount); + adapter.OnMessage(message); } - [Test] - public void MessageContentsHandlerForBytesMessage() - { - int numIterations = 10; - IBytesMessage message = A.Fake(); - ASCIIEncoding encoding = new ASCIIEncoding(); - byte[] content = encoding.GetBytes("test"); - A.CallTo(() => message.Content).Returns(content).NumberOfTimes(numIterations); - MessageContentsHandler handler = new MessageContentsHandler(); - - MessageListenerAdapter adapter = new MessageListenerAdapter(handler); - for (int i = 0; i < numIterations; i++) - { - adapter.OnMessage(message); - } - - Assert.AreEqual(numIterations, handler.HandledByteArrayCount); - } - - [Test] - public void MessageContentsHandlerOverloadCalls() - { - int numIterations = 10; - IBytesMessage bytesMessage = A.Fake(); - ASCIIEncoding encoding = new ASCIIEncoding(); - byte[] content = encoding.GetBytes("test"); - A.CallTo(() => bytesMessage.Content).Returns(content).NumberOfTimes(numIterations / 2); - - ITextMessage textMessage = A.Fake(); - A.CallTo(() => textMessage.Text).Returns(TEXT).NumberOfTimes(numIterations / 2); - - MessageContentsHandler handler = new MessageContentsHandler(); - - MessageListenerAdapter adapter = new MessageListenerAdapter(handler); - for (int i = 0; i < numIterations / 2; i++) - { - adapter.OnMessage(textMessage); - adapter.OnMessage(bytesMessage); - } - - Assert.AreEqual(numIterations / 2, handler.HandledByteArrayCount); - Assert.AreEqual(numIterations / 2, handler.HandledStringCount); - } + Assert.AreEqual(numIterations, handler.HandledStringCount); } -} \ No newline at end of file + + [Test] + public void MessageContentsHandlerForBytesMessage() + { + int numIterations = 10; + IBytesMessage message = A.Fake(); + ASCIIEncoding encoding = new ASCIIEncoding(); + byte[] content = encoding.GetBytes("test"); + A.CallTo(() => message.Content).Returns(content).NumberOfTimes(numIterations); + MessageContentsHandler handler = new MessageContentsHandler(); + + MessageListenerAdapter adapter = new MessageListenerAdapter(handler); + for (int i = 0; i < numIterations; i++) + { + adapter.OnMessage(message); + } + + Assert.AreEqual(numIterations, handler.HandledByteArrayCount); + } + + [Test] + public void MessageContentsHandlerOverloadCalls() + { + int numIterations = 10; + IBytesMessage bytesMessage = A.Fake(); + ASCIIEncoding encoding = new ASCIIEncoding(); + byte[] content = encoding.GetBytes("test"); + A.CallTo(() => bytesMessage.Content).Returns(content).NumberOfTimes(numIterations / 2); + + ITextMessage textMessage = A.Fake(); + A.CallTo(() => textMessage.Text).Returns(TEXT).NumberOfTimes(numIterations / 2); + + MessageContentsHandler handler = new MessageContentsHandler(); + + MessageListenerAdapter adapter = new MessageListenerAdapter(handler); + for (int i = 0; i < numIterations / 2; i++) + { + adapter.OnMessage(textMessage); + adapter.OnMessage(bytesMessage); + } + + Assert.AreEqual(numIterations / 2, handler.HandledByteArrayCount); + Assert.AreEqual(numIterations / 2, handler.HandledStringCount); + } +} diff --git a/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/StubQueue.cs b/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/StubQueue.cs index 8ab9fa6a..06dfe5b0 100644 --- a/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/StubQueue.cs +++ b/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/StubQueue.cs @@ -20,49 +20,47 @@ using Apache.NMS; -namespace Spring.Messaging.Nms +namespace Spring.Messaging.Nms; + +/// +/// +/// +/// +/// +/// +/// Mark Pollack +public class StubQueue : IQueue { - /// - /// - /// - /// - /// - /// - /// Mark Pollack - public class StubQueue : IQueue + public static string DEFAULT_QUEUE_NAME = "banjo"; + + private string queueName = DEFAULT_QUEUE_NAME; + + public string QueueName { - public static string DEFAULT_QUEUE_NAME = "banjo"; - - - private string queueName = DEFAULT_QUEUE_NAME; - - public string QueueName - { - get { return queueName; } - } - - public DestinationType DestinationType - { - get { return DestinationType.Queue; } - } - - public bool IsTopic - { - get { return false; } - } - - public bool IsQueue - { - get { return true; } - } - - public bool IsTemporary - { - get { return false; } - } - - public void Dispose() - { - } + get { return queueName; } } -} \ No newline at end of file + + public DestinationType DestinationType + { + get { return DestinationType.Queue; } + } + + public bool IsTopic + { + get { return false; } + } + + public bool IsQueue + { + get { return true; } + } + + public bool IsTemporary + { + get { return false; } + } + + public void Dispose() + { + } +} diff --git a/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Support/Converter/TypeMapperTests.cs b/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Support/Converter/TypeMapperTests.cs index b556fd5f..3ba53803 100644 --- a/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Support/Converter/TypeMapperTests.cs +++ b/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Support/Converter/TypeMapperTests.cs @@ -22,81 +22,80 @@ using System.Collections; using NUnit.Framework; using Spring.Objects; -namespace Spring.Messaging.Nms.Support.Converter +namespace Spring.Messaging.Nms.Support.Converter; + +/// +/// Test the TypeMapper +/// +/// Mark Pollack +[TestFixture] +public class TypeMapperTests { - /// - /// Test the TypeMapper - /// - /// Mark Pollack - [TestFixture] - public class TypeMapperTests + private TypeMapper tm; + + [SetUp] + public void SetUp() { - private TypeMapper tm; + tm = new TypeMapper(); + } - [SetUp] - public void SetUp() - { - tm = new TypeMapper(); - } + [Test] + public void ConfigurationNamespaceTests() + { + tm.DefaultAssemblyName = "Spring.Objects"; + Assert.Throws(() => tm.AfterPropertiesSet()); + } - [Test] - public void ConfigurationNamespaceTests() - { - tm.DefaultAssemblyName = "Spring.Objects"; - Assert.Throws(() => tm.AfterPropertiesSet()); - } + [Test] + public void FromTypeTestsForDictionary() + { + Assert.AreEqual("Hashtable", tm.FromType(typeof(Hashtable))); + } - [Test] - public void FromTypeTestsForDictionary() - { - Assert.AreEqual("Hashtable", tm.FromType(typeof(Hashtable))); - } + [Test] + public void ToTypeForDictionary() + { + Assert.AreEqual(typeof(Hashtable), tm.ToType("Hashtable")); + } - [Test] - public void ToTypeForDictionary() - { - Assert.AreEqual(typeof (Hashtable), tm.ToType("Hashtable")); - } + [Test] + public void FromTypeForNonRegisteredType() + { + Assert.AreEqual("TestObject", tm.FromType(typeof(TestObject))); + } - [Test] - public void FromTypeForNonRegisteredType() - { - Assert.AreEqual("TestObject", tm.FromType(typeof(TestObject))); - } + [Test] + public void ToTypeForNonRegisteredTypeSettingDefaults() + { + tm.DefaultNamespace = "Spring.Objects"; + tm.DefaultAssemblyName = "Spring.Core.Tests"; + Type resolvedTyped = tm.ToType("TestObject"); + Assert.AreEqual(typeof(TestObject), resolvedTyped); + } - [Test] - public void ToTypeForNonRegisteredTypeSettingDefaults() - { - tm.DefaultNamespace = "Spring.Objects"; - tm.DefaultAssemblyName = "Spring.Core.Tests"; - Type resolvedTyped = tm.ToType("TestObject"); - Assert.AreEqual(typeof(TestObject), resolvedTyped); - } + [Test] + public void ToTypeForUnresolvableType() + { + Assert.Throws(() => tm.ToType("TestObject")); + } - [Test] - public void ToTypeForUnresolvableType() - { - Assert.Throws(() => tm.ToType("TestObject")); - } + [Test] + public void MarhsalUsingAssemblyQualifiedName() + { + tm.UseAssemblyQualifiedName = true; + string typeAsString = tm.FromType(typeof(TestObject)); + Type resolvedTyped = tm.ToType(typeAsString); + Assert.AreEqual(typeof(TestObject), resolvedTyped); + } - [Test] - public void MarhsalUsingAssemblyQualifiedName() - { - tm.UseAssemblyQualifiedName = true; - string typeAsString = tm.FromType(typeof (TestObject)); - Type resolvedTyped = tm.ToType(typeAsString); - Assert.AreEqual(typeof(TestObject), resolvedTyped); - } - - [Test] - public void UsingTypeMappings() - { - tm.IdTypeMapping.Add("1", typeof (TestObject)); - tm.AfterPropertiesSet(); - string typeAsString = tm.FromType(typeof (TestObject)); - Assert.AreEqual("1", typeAsString); - Type resolvedType = tm.ToType("1"); - Assert.AreEqual(typeof(TestObject), resolvedType); - } + [Test] + public void UsingTypeMappings() + { + tm.IdTypeMapping.Add("1", typeof(TestObject)); + tm.AfterPropertiesSet(); + string typeAsString = tm.FromType(typeof(TestObject)); + Assert.AreEqual("1", typeAsString); + Type resolvedType = tm.ToType("1"); + Assert.AreEqual(typeof(TestObject), resolvedType); } } diff --git a/test/Spring/Spring.Messaging.Nms.Tests/NmsCompilerOptionsTests.cs b/test/Spring/Spring.Messaging.Nms.Tests/NmsCompilerOptionsTests.cs index 4f1ce935..582f4f89 100644 --- a/test/Spring/Spring.Messaging.Nms.Tests/NmsCompilerOptionsTests.cs +++ b/test/Spring/Spring.Messaging.Nms.Tests/NmsCompilerOptionsTests.cs @@ -26,18 +26,17 @@ using Spring.Messaging.Nms.Listener.Adapter; #endregion -namespace Spring +namespace Spring; + +/// Test that the assembly is built with the correct DebugAttributes in release and debug builds. +/// +/// Mark Pollack +[TestFixture] +public sealed class NmsCompilerOptionTests : CompilerOptionsTests { - /// Test that the assembly is built with the correct DebugAttributes in release and debug builds. - /// - /// Mark Pollack - [TestFixture] - public sealed class NmsCompilerOptionTests : CompilerOptionsTests + [OneTimeSetUp] + public void FixtureSetUp() { - [OneTimeSetUp] - public void FixtureSetUp() - { - AssemblyToCheck = Assembly.GetAssembly(typeof (ListenerExecutionFailedException)); - } + AssemblyToCheck = Assembly.GetAssembly(typeof(ListenerExecutionFailedException)); } -} \ No newline at end of file +} diff --git a/test/Spring/Spring.Messaging.Nms.Tests/NmsExceptionTests.cs b/test/Spring/Spring.Messaging.Nms.Tests/NmsExceptionTests.cs index d7fad857..90a58107 100644 --- a/test/Spring/Spring.Messaging.Nms.Tests/NmsExceptionTests.cs +++ b/test/Spring/Spring.Messaging.Nms.Tests/NmsExceptionTests.cs @@ -26,20 +26,19 @@ using Spring.Messaging.Nms.Connections; #endregion -namespace Spring +namespace Spring; + +/// +/// Unit tests for all of the exception classes in the Spring.Data library... +/// +/// Rick Evans +[TestFixture] +//[Ignore("Spring inherits from NMS Exceptions which do not ")] +public sealed class NmsExceptionTests : ExceptionsTest { - /// - /// Unit tests for all of the exception classes in the Spring.Data library... - /// - /// Rick Evans - [TestFixture] - //[Ignore("Spring inherits from NMS Exceptions which do not ")] - public sealed class NmsExceptionTests : ExceptionsTest + [OneTimeSetUp] + public void FixtureSetUp() { - [OneTimeSetUp] - public void FixtureSetUp() - { - AssemblyToCheck = Assembly.GetAssembly(typeof (SynchedLocalTransactionFailedException)); - } + AssemblyToCheck = Assembly.GetAssembly(typeof(SynchedLocalTransactionFailedException)); } -} \ No newline at end of file +} diff --git a/test/Spring/Spring.Messaging.Tests/App.config b/test/Spring/Spring.Messaging.Tests/App.config index 2d384190..04a9c35a 100644 --- a/test/Spring/Spring.Messaging.Tests/App.config +++ b/test/Spring/Spring.Messaging.Tests/App.config @@ -25,53 +25,53 @@ limitations under the License.
- + - + - - ---> - - + diff --git a/test/Spring/Spring.Messaging.Tests/Messaging/Core/MessageQueueMetadataCacheTests.cs b/test/Spring/Spring.Messaging.Tests/Messaging/Core/MessageQueueMetadataCacheTests.cs index 21c30fb8..706eb50f 100644 --- a/test/Spring/Spring.Messaging.Tests/Messaging/Core/MessageQueueMetadataCacheTests.cs +++ b/test/Spring/Spring.Messaging.Tests/Messaging/Core/MessageQueueMetadataCacheTests.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -25,46 +25,40 @@ using Spring.Testing.NUnit; #endregion -namespace Spring.Messaging.Core +namespace Spring.Messaging.Core; + +/// +/// This class contains tests for MessageQueueTemplate +/// +/// Mark Pollack +[TestFixture] +public class MessageQueueMetadataCacheTests : AbstractDependencyInjectionSpringContextTests { - /// - /// This class contains tests for MessageQueueTemplate - /// - /// Mark Pollack - [TestFixture] - public class MessageQueueMetadataCacheTests : AbstractDependencyInjectionSpringContextTests + protected override string[] ConfigLocations { - protected override string[] ConfigLocations - { - get { return new string[] {"assembly://Spring.Messaging.Tests/Spring.Messaging.Core/MessageQueueMetadataCacheTests.xml"}; } - } - - [Test] - public void InitialzeMessageQueueMetadata() - { - MessageQueueMetadataCache cache = new MessageQueueMetadataCache(applicationContext); - Assert.AreEqual(0, cache.Count); - cache.Initialize(); - Assert.IsTrue(cache.Initalized); - Assert.AreEqual(4, cache.Count); - MessageQueueMetadata md = cache.Get(@".\Private$\testqueue"); - cache.Remove(@".\Private$\testqueue"); - Assert.AreEqual(3, cache.Count); - Assert.IsNull(cache.Get(@".\Private$\testqueue")); - - string[] paths = new string[] - { - @".\Private$\testtxqueue", - @"FormatName:Direct=TCP:192.168.1.105\Private$\testtxqueue", - @"FormatName:Direct=TCP:192.168.1.105\Private$\testqueue" - }; - - Assert.That(paths, Is.EquivalentTo(cache.Paths)); - paths = new string[] {@".\Private$\testtxqueue", @"FormatName:Direct=TCP:192.168.1.105\Private$\testtxqueue"}; - cache.RemoveAll(paths); - Assert.AreEqual(1, cache.Count); - cache.Clear(); - Assert.AreEqual(0, cache.Count); - } + get { return new string[] { "assembly://Spring.Messaging.Tests/Spring.Messaging.Core/MessageQueueMetadataCacheTests.xml" }; } } -} \ No newline at end of file + + [Test] + public void InitialzeMessageQueueMetadata() + { + MessageQueueMetadataCache cache = new MessageQueueMetadataCache(applicationContext); + Assert.AreEqual(0, cache.Count); + cache.Initialize(); + Assert.IsTrue(cache.Initalized); + Assert.AreEqual(4, cache.Count); + MessageQueueMetadata md = cache.Get(@".\Private$\testqueue"); + cache.Remove(@".\Private$\testqueue"); + Assert.AreEqual(3, cache.Count); + Assert.IsNull(cache.Get(@".\Private$\testqueue")); + + string[] paths = new string[] { @".\Private$\testtxqueue", @"FormatName:Direct=TCP:192.168.1.105\Private$\testtxqueue", @"FormatName:Direct=TCP:192.168.1.105\Private$\testqueue" }; + + Assert.That(paths, Is.EquivalentTo(cache.Paths)); + paths = new string[] { @".\Private$\testtxqueue", @"FormatName:Direct=TCP:192.168.1.105\Private$\testtxqueue" }; + cache.RemoveAll(paths); + Assert.AreEqual(1, cache.Count); + cache.Clear(); + Assert.AreEqual(0, cache.Count); + } +} diff --git a/test/Spring/Spring.Messaging.Tests/Messaging/Core/MessageQueueMetadataCacheTests.xml b/test/Spring/Spring.Messaging.Tests/Messaging/Core/MessageQueueMetadataCacheTests.xml index 5108625e..4d79c126 100644 --- a/test/Spring/Spring.Messaging.Tests/Messaging/Core/MessageQueueMetadataCacheTests.xml +++ b/test/Spring/Spring.Messaging.Tests/Messaging/Core/MessageQueueMetadataCacheTests.xml @@ -2,38 +2,38 @@ - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - + + + + + - - - - + + + + \ No newline at end of file diff --git a/test/Spring/Spring.Messaging.Tests/Messaging/Core/MessageQueueTemplateTests.cs b/test/Spring/Spring.Messaging.Tests/Messaging/Core/MessageQueueTemplateTests.cs index 86ca2b71..ddd8a488 100644 --- a/test/Spring/Spring.Messaging.Tests/Messaging/Core/MessageQueueTemplateTests.cs +++ b/test/Spring/Spring.Messaging.Tests/Messaging/Core/MessageQueueTemplateTests.cs @@ -21,7 +21,6 @@ #region Imports using System.Messaging; - using NUnit.Framework; using Spring.Data.Core; using Spring.Testing.NUnit; @@ -30,233 +29,233 @@ using Spring.Transaction.Support; #endregion -namespace Spring.Messaging.Core +namespace Spring.Messaging.Core; + +/// +/// This class contains tests for MessageQueueTemplate +/// +/// Mark Pollack +[TestFixture] +public class MessageQueueTemplateTests : AbstractDependencyInjectionSpringContextTests { - /// - /// This class contains tests for MessageQueueTemplate - /// - /// Mark Pollack - [TestFixture] - public class MessageQueueTemplateTests : AbstractDependencyInjectionSpringContextTests + [SetUp] + public override void SetUp() { - [SetUp] - public override void SetUp() + MessageQueueUtils.RecreateMessageQueue(@".\Private$\testqueue", false); + MessageQueueUtils.RecreateMessageQueue(@".\Private$\testtxqueue", true); + base.SetUp(); + } + + [Test] + public void MessageCreator() + { + MessageQueueTemplate mqt = applicationContext["txqueue"] as MessageQueueTemplate; + Assert.IsNotNull(mqt); + string path = @".\Private$\mlptestqueue"; + if (MessageQueue.Exists(path)) { - MessageQueueUtils.RecreateMessageQueue(@".\Private$\testqueue", false); - MessageQueueUtils.RecreateMessageQueue(@".\Private$\testtxqueue", true); - base.SetUp(); + MessageQueue.Delete(path); } - [Test] - public void MessageCreator() + MessageQueue.Create(path, true); + mqt.MessageQueueFactory.RegisterMessageQueue("newQueueDefinition", delegate { - MessageQueueTemplate mqt = applicationContext["txqueue"] as MessageQueueTemplate; - Assert.IsNotNull(mqt); - string path = @".\Private$\mlptestqueue"; - if (MessageQueue.Exists(path)) - { - MessageQueue.Delete(path); - } - MessageQueue.Create(path, true); - mqt.MessageQueueFactory.RegisterMessageQueue("newQueueDefinition", delegate - { - MessageQueue mq = new MessageQueue(); - mq.Path = path; - // other properties - return mq; - }); + MessageQueue mq = new MessageQueue(); + mq.Path = path; + // other properties + return mq; + }); - Assert.IsTrue(mqt.MessageQueueFactory.ContainsMessageQueue("newQueueDefinition")); + Assert.IsTrue(mqt.MessageQueueFactory.ContainsMessageQueue("newQueueDefinition")); - SendAndReceive("newQueueDefinition",mqt); + SendAndReceive("newQueueDefinition", mqt); - SimpleCreator sc = new SimpleCreator(); - mqt.MessageQueueFactory.RegisterMessageQueue("fooQueueDefinition", sc.CreateQueue ); + SimpleCreator sc = new SimpleCreator(); + mqt.MessageQueueFactory.RegisterMessageQueue("fooQueueDefinition", sc.CreateQueue); + } + public class SimpleCreator + { + public MessageQueue CreateQueue() + { + return new MessageQueue(); + } + } + + [Test] + public void NoMessageQueueNameSpecified() + { + MessageQueueTemplate mqt = new MessageQueueTemplate(); + Assert.Throws(() => mqt.AfterPropertiesSet()); + } + + [Test, Ignore("obsolete test, defaultMessageQueueName is used to obtain a queue from MessageQueueFactory")] + public void MessageQueueNameNotInContext() + { + MessageQueueTemplate q = new MessageQueueTemplate("noqueuename"); + q.ApplicationContext = applicationContext; + Assert.Throws(() => q.AfterPropertiesSet(), "No object named noqueuename is defined in the Spring container"); + } + + [Test] + public void MessageQueueCreatedinThreadLocalStorage() + { + MessageQueueTemplate q = applicationContext["queue"] as MessageQueueTemplate; + Assert.IsNotNull(q); + Assert.AreEqual(q.DefaultMessageQueue, q.MessageQueueFactory.CreateMessageQueue(q.DefaultMessageQueueObjectName)); + } + + #region Integration Tests - to be moved to another test assembly + + [Test] + public void SendAndReceiveNonTransactional() + { + MessageQueueTemplate q = applicationContext["queue"] as MessageQueueTemplate; + Assert.IsNotNull(q); + q.ConvertAndSend("Hello World 1"); + ReceiveHelloWorld(null, q, 1); + } + + [Test] + public void SendAndReceiveNonTransactionalRemotePrivateQueue() + { + MessageQueueTemplate q = applicationContext["queueTemplate-remote"] as MessageQueueTemplate; + Assert.IsNotNull(q); + q.ConvertAndSend("Hello World 1"); + //ReceiveHelloWorld(null, q, 1); + } + + private static void ReceiveHelloWorld(string messageQueueObjectName, MessageQueueTemplate q, int index) + { + object o = null; + if (messageQueueObjectName == null) + { + o = q.ReceiveAndConvert(); + } + else + { + o = q.ReceiveAndConvert(messageQueueObjectName); } - public class SimpleCreator - { - public MessageQueue CreateQueue() - { - return new MessageQueue(); - } - } - - [Test] - public void NoMessageQueueNameSpecified() - { - MessageQueueTemplate mqt = new MessageQueueTemplate(); - Assert.Throws(() => mqt.AfterPropertiesSet()); - } + Assert.IsNotNull(o); + string data = o as string; + Assert.IsNotNull(data); + Assert.AreEqual("Hello World " + index, data); + } - [Test, Ignore("obsolete test, defaultMessageQueueName is used to obtain a queue from MessageQueueFactory")] - public void MessageQueueNameNotInContext() - { - MessageQueueTemplate q = new MessageQueueTemplate("noqueuename"); - q.ApplicationContext = applicationContext; - Assert.Throws(() => q.AfterPropertiesSet(), "No object named noqueuename is defined in the Spring container"); - } + [Test] + public void SendNonTxMessageQueueUsingMessageTx() + { + MessageQueueTemplate q = applicationContext["queue"] as MessageQueueTemplate; + Assert.IsNotNull(q); + SendAndReceive(q); + } - [Test] - public void MessageQueueCreatedinThreadLocalStorage() - { - MessageQueueTemplate q = applicationContext["queue"] as MessageQueueTemplate; - Assert.IsNotNull(q); - Assert.AreEqual(q.DefaultMessageQueue, q.MessageQueueFactory.CreateMessageQueue(q.DefaultMessageQueueObjectName)); - } + [Test] + public void SendTxMessageQueueUsingMessageTx() + { + MessageQueueTemplate q = applicationContext["txqueue"] as MessageQueueTemplate; + Assert.IsNotNull(q); + SendAndReceive(q); + } - #region Integration Tests - to be moved to another test assembly + [Test] + public void SendTxMessageQueueUsingTxScope() + { + MessageQueueTemplate q = applicationContext["txqueue"] as MessageQueueTemplate; + Assert.IsNotNull(q); + SendUsingMessageTxScope(q); + Receive(null, q); + } - [Test] - public void SendAndReceiveNonTransactional() - { - MessageQueueTemplate q = applicationContext["queue"] as MessageQueueTemplate; - Assert.IsNotNull(q); - q.ConvertAndSend("Hello World 1"); - ReceiveHelloWorld(null,q,1); - } + private static void SendAndReceive(MessageQueueTemplate q) + { + SendAndReceive(null, q); + } - [Test] - public void SendAndReceiveNonTransactionalRemotePrivateQueue() - { - MessageQueueTemplate q = applicationContext["queueTemplate-remote"] as MessageQueueTemplate; - Assert.IsNotNull(q); - q.ConvertAndSend("Hello World 1"); - //ReceiveHelloWorld(null, q, 1); - } + private static void SendAndReceive(string messageQueueObjectName, MessageQueueTemplate q) + { + SendUsingMessageTx(messageQueueObjectName, q); + Receive(messageQueueObjectName, q); + } - private static void ReceiveHelloWorld(string messageQueueObjectName, MessageQueueTemplate q, int index) + private static void Receive(string messageQueueObjectName, MessageQueueTemplate q) + { + ReceiveHelloWorld(messageQueueObjectName, q, 1); + ReceiveHelloWorld(messageQueueObjectName, q, 2); + ReceiveHelloWorld(messageQueueObjectName, q, 3); + } + + private static void SendUsingMessageTx(string messageQueueObjectName, MessageQueueTemplate q) + { + IPlatformTransactionManager txManager = new MessageQueueTransactionManager(); + TransactionTemplate transactionTemplate = new TransactionTemplate(txManager); + transactionTemplate.Execute(status => { - object o = null; if (messageQueueObjectName == null) { - o = q.ReceiveAndConvert(); - } else - { - o = q.ReceiveAndConvert(messageQueueObjectName); + q.ConvertAndSend("Hello World 1"); + q.ConvertAndSend("Hello World 2"); + q.ConvertAndSend("Hello World 3"); + } + else + { + q.ConvertAndSend(messageQueueObjectName, "Hello World 1"); + q.ConvertAndSend(messageQueueObjectName, "Hello World 2"); + q.ConvertAndSend(messageQueueObjectName, "Hello World 3"); } - Assert.IsNotNull(o); - string data = o as string; - Assert.IsNotNull(data); - Assert.AreEqual("Hello World " + index, data); - } - [Test] - public void SendNonTxMessageQueueUsingMessageTx() + return null; + }); + } + + private static void SendUsingMessageTxScope(MessageQueueTemplate q) + { + IPlatformTransactionManager txManager = new TxScopeTransactionManager(); + TransactionTemplate transactionTemplate = new TransactionTemplate(txManager); + transactionTemplate.Execute(status => { - MessageQueueTemplate q = applicationContext["queue"] as MessageQueueTemplate; - Assert.IsNotNull(q); - SendAndReceive(q); - } + q.ConvertAndSend("Hello World 1"); + q.ConvertAndSend("Hello World 2"); + q.ConvertAndSend("Hello World 3"); + return null; + }); + } - [Test] - public void SendTxMessageQueueUsingMessageTx() - { - MessageQueueTemplate q = applicationContext["txqueue"] as MessageQueueTemplate; - Assert.IsNotNull(q); - SendAndReceive(q); - } + #endregion - [Test] - public void SendTxMessageQueueUsingTxScope() - { - MessageQueueTemplate q = applicationContext["txqueue"] as MessageQueueTemplate; - Assert.IsNotNull(q); - SendUsingMessageTxScope(q); - Receive(null,q); - } + protected override string[] ConfigLocations + { + get { return new string[] { "assembly://Spring.Messaging.Tests/Spring.Messaging.Core/MessageQueueTemplateTests.xml" }; } + } + #region Some simple driver code for debugging - private static void SendAndReceive(MessageQueueTemplate q) - { - SendAndReceive(null, q); - } - - private static void SendAndReceive(string messageQueueObjectName, MessageQueueTemplate q) - { - SendUsingMessageTx(messageQueueObjectName, q); - Receive(messageQueueObjectName, q); - } - - private static void Receive(string messageQueueObjectName, MessageQueueTemplate q) - { - ReceiveHelloWorld(messageQueueObjectName, q, 1); - ReceiveHelloWorld(messageQueueObjectName, q, 2); - ReceiveHelloWorld(messageQueueObjectName, q, 3); - } - - private static void SendUsingMessageTx(string messageQueueObjectName, MessageQueueTemplate q) - { - IPlatformTransactionManager txManager = new MessageQueueTransactionManager(); - TransactionTemplate transactionTemplate = new TransactionTemplate(txManager); - transactionTemplate.Execute(status => - { - if (messageQueueObjectName == null) - { - q.ConvertAndSend("Hello World 1"); - q.ConvertAndSend("Hello World 2"); - q.ConvertAndSend("Hello World 3"); - } else - { - q.ConvertAndSend(messageQueueObjectName, "Hello World 1"); - q.ConvertAndSend(messageQueueObjectName, "Hello World 2"); - q.ConvertAndSend(messageQueueObjectName, "Hello World 3"); - } - return null; - }); - } - - private static void SendUsingMessageTxScope(MessageQueueTemplate q) - { - IPlatformTransactionManager txManager = new TxScopeTransactionManager(); - TransactionTemplate transactionTemplate = new TransactionTemplate(txManager); - transactionTemplate.Execute(status => - { - q.ConvertAndSend("Hello World 1"); - q.ConvertAndSend("Hello World 2"); - q.ConvertAndSend("Hello World 3"); - return null; - }); - } - - #endregion - - protected override string[] ConfigLocations - { - get { return new string[] { "assembly://Spring.Messaging.Tests/Spring.Messaging.Core/MessageQueueTemplateTests.xml" }; } - } - - - #region Some simple driver code for debugging - public void SimpleRemoteConsumption() - { + public void SimpleRemoteConsumption() + { // string connectionWorking = @"FormatName:Direct=OS:MARKT60\Private$\testqueue"; - //TCP:IP doesn't work... - MessageQueue rmQ = new MessageQueue(@"FormatName:Direct=TCP:192.168.1.105\Private$\testqueue"); + //TCP:IP doesn't work... + MessageQueue rmQ = new MessageQueue(@"FormatName:Direct=TCP:192.168.1.105\Private$\testqueue"); - rmQ.Send("Hello Simple"); + rmQ.Send("Hello Simple"); - rmQ.Formatter = new XmlMessageFormatter(new Type[] { typeof(string) }); + rmQ.Formatter = new XmlMessageFormatter(new Type[] { typeof(string) }); - Message msg = rmQ.Receive(); - - Assert.IsNotNull(msg); - - - } - - public void GetAllFromQueue() - { - MessageQueueTemplate q = applicationContext["queue"] as MessageQueueTemplate; - Assert.IsNotNull(q); - for (int i = 0; i < 5; i++) - { - Console.WriteLine(q.ReceiveAndConvert()); - } - } - #endregion + Message msg = rmQ.Receive(); + Assert.IsNotNull(msg); } + + public void GetAllFromQueue() + { + MessageQueueTemplate q = applicationContext["queue"] as MessageQueueTemplate; + Assert.IsNotNull(q); + for (int i = 0; i < 5; i++) + { + Console.WriteLine(q.ReceiveAndConvert()); + } + } + + #endregion } diff --git a/test/Spring/Spring.Messaging.Tests/Messaging/Core/MessageQueueTemplateTests.xml b/test/Spring/Spring.Messaging.Tests/Messaging/Core/MessageQueueTemplateTests.xml index 873708c3..9dd3b96e 100644 --- a/test/Spring/Spring.Messaging.Tests/Messaging/Core/MessageQueueTemplateTests.xml +++ b/test/Spring/Spring.Messaging.Tests/Messaging/Core/MessageQueueTemplateTests.xml @@ -2,82 +2,82 @@ - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - + + + + + - - - - + + + + - + - - - - + + + + - - - + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - + + + - - - - - - - - - + + + + + + + + + \ No newline at end of file diff --git a/test/Spring/Spring.Messaging.Tests/Messaging/Core/MessageQueueUtils.cs b/test/Spring/Spring.Messaging.Tests/Messaging/Core/MessageQueueUtils.cs index 2fdca74b..21dbea32 100644 --- a/test/Spring/Spring.Messaging.Tests/Messaging/Core/MessageQueueUtils.cs +++ b/test/Spring/Spring.Messaging.Tests/Messaging/Core/MessageQueueUtils.cs @@ -20,46 +20,44 @@ using System.Messaging; -namespace Spring.Messaging.Core -{ - /// - /// Utility class to recreate message queues if they do not exist. - /// - /// Mark Pollack - public class MessageQueueUtils - { - public static void RecreateMessageQueue(string path, bool transactional) - { - bool defaultCacheEnabled = MessageQueue.EnableConnectionCache; - MessageQueue.ClearConnectionCache(); - MessageQueue.EnableConnectionCache = false; - if (MessageQueue.Exists(path)) - { - // TODO (EE): delete/create doesn't work for some reason - // MessageQueue.Delete(path); - // queue = MessageQueue.Create(path, transactional); - using (MessageQueue queue = new MessageQueue(path)) - { - queue.Purge(); - } - } - else - { - /* - * MSDN docs indicate that calls to the static .Create() method should include - * an explicit call to .Dispose() b/c unmanaged resources are involved - * Here this req'ment is handled implicitly with the using() statement - * even though the empty using() block seems odd at first glance b/c it - * encloses a static method call - */ - using (MessageQueue.Create(path, transactional)) - { - - } - } - MessageQueue.ClearConnectionCache(); - MessageQueue.EnableConnectionCache = defaultCacheEnabled; // set to default - } - } +namespace Spring.Messaging.Core; +/// +/// Utility class to recreate message queues if they do not exist. +/// +/// Mark Pollack +public class MessageQueueUtils +{ + public static void RecreateMessageQueue(string path, bool transactional) + { + bool defaultCacheEnabled = MessageQueue.EnableConnectionCache; + MessageQueue.ClearConnectionCache(); + MessageQueue.EnableConnectionCache = false; + if (MessageQueue.Exists(path)) + { + // TODO (EE): delete/create doesn't work for some reason + // MessageQueue.Delete(path); + // queue = MessageQueue.Create(path, transactional); + using (MessageQueue queue = new MessageQueue(path)) + { + queue.Purge(); + } + } + else + { + /* + * MSDN docs indicate that calls to the static .Create() method should include + * an explicit call to .Dispose() b/c unmanaged resources are involved + * Here this req'ment is handled implicitly with the using() statement + * even though the empty using() block seems odd at first glance b/c it + * encloses a static method call + */ + using (MessageQueue.Create(path, transactional)) + { + } + } + + MessageQueue.ClearConnectionCache(); + MessageQueue.EnableConnectionCache = defaultCacheEnabled; // set to default + } } \ No newline at end of file diff --git a/test/Spring/Spring.Messaging.Tests/Messaging/Core/ThreadingTests.cs b/test/Spring/Spring.Messaging.Tests/Messaging/Core/ThreadingTests.cs index f24ab863..0a6a8385 100644 --- a/test/Spring/Spring.Messaging.Tests/Messaging/Core/ThreadingTests.cs +++ b/test/Spring/Spring.Messaging.Tests/Messaging/Core/ThreadingTests.cs @@ -24,31 +24,28 @@ using NUnit.Framework; #endregion -namespace Spring.Messaging.Core +namespace Spring.Messaging.Core; + +/// +/// This class contains tests for +/// +/// Mark Pollack +[TestFixture] +public class ThreadingTests { - /// - /// This class contains tests for - /// - /// Mark Pollack - [TestFixture] - public class ThreadingTests + private int activeListenerCount = 0; + + [SetUp] + public void Setup() { - private int activeListenerCount = 0; - [SetUp] - public void Setup() - { - } + } - [Test] - public void Test() - { - Interlocked.Increment(ref activeListenerCount); - // just gets the current value... - int count = Interlocked.CompareExchange(ref activeListenerCount, -1, -1); - Assert.AreEqual(1, count); - - } - - + [Test] + public void Test() + { + Interlocked.Increment(ref activeListenerCount); + // just gets the current value... + int count = Interlocked.CompareExchange(ref activeListenerCount, -1, -1); + Assert.AreEqual(1, count); } } diff --git a/test/Spring/Spring.Messaging.Tests/Messaging/Listener/Adapter/MessageListenerAdapterTests.cs b/test/Spring/Spring.Messaging.Tests/Messaging/Listener/Adapter/MessageListenerAdapterTests.cs index 9d7011ab..2ca62a17 100644 --- a/test/Spring/Spring.Messaging.Tests/Messaging/Listener/Adapter/MessageListenerAdapterTests.cs +++ b/test/Spring/Spring.Messaging.Tests/Messaging/Listener/Adapter/MessageListenerAdapterTests.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -24,28 +24,26 @@ using NUnit.Framework; #endregion -namespace Spring.Messaging.Listener.Adapter +namespace Spring.Messaging.Listener.Adapter; + +/// +/// To properly test the MessageListnerAdapter one needs to use TypeMock as MessageQueue and Message are not +/// interface based. +/// +[TestFixture] +public class MessageListenerAdapterTests { - /// - /// To properly test the MessageListnerAdapter one needs to use TypeMock as MessageQueue and Message are not - /// interface based. - /// - [TestFixture] - public class MessageListenerAdapterTests + [Test] + public void DefaultMessageHandlerMethodNameIsTheConstantDefault() { - [Test] - public void DefaultMessageHandlerMethodNameIsTheConstantDefault() - { - MessageListenerAdapter adapter = new MessageListenerAdapter(); - Assert.AreSame(MessageListenerAdapter.ORIGINAL_DEFAULT_LISTENER_METHOD, adapter.DefaultHandlerMethod); - } - - [Test] - public void WhenNoHandlerMethodIsSuppliedTheHandlerIsAssumedToBeTheMessageListenerAdapterItself() - { - MessageListenerAdapter adapter = new MessageListenerAdapter(); - Assert.AreSame(adapter, adapter.HandlerObject); - - } + MessageListenerAdapter adapter = new MessageListenerAdapter(); + Assert.AreSame(MessageListenerAdapter.ORIGINAL_DEFAULT_LISTENER_METHOD, adapter.DefaultHandlerMethod); } -} \ No newline at end of file + + [Test] + public void WhenNoHandlerMethodIsSuppliedTheHandlerIsAssumedToBeTheMessageListenerAdapterItself() + { + MessageListenerAdapter adapter = new MessageListenerAdapter(); + Assert.AreSame(adapter, adapter.HandlerObject); + } +} diff --git a/test/Spring/Spring.Messaging.Tests/Messaging/Listener/Adapter/StandardReflectionMessageListenerAdapter.cs b/test/Spring/Spring.Messaging.Tests/Messaging/Listener/Adapter/StandardReflectionMessageListenerAdapter.cs index 9f716f93..ae5ac830 100644 --- a/test/Spring/Spring.Messaging.Tests/Messaging/Listener/Adapter/StandardReflectionMessageListenerAdapter.cs +++ b/test/Spring/Spring.Messaging.Tests/Messaging/Listener/Adapter/StandardReflectionMessageListenerAdapter.cs @@ -26,43 +26,45 @@ using Spring.Util; #endregion -namespace Spring.Messaging.Listener.Adapter -{ - /// - /// POC for a standard reflection based listener method invoker. - /// - /// Mark Pollack - public class StandardReflectionMessageListenerAdapter : MessageListenerAdapter - { - private const BindingFlags BINDING_FLAGS - = BindingFlags.Public | BindingFlags.NonPublic - | BindingFlags.Instance | BindingFlags.Static - | BindingFlags.IgnoreCase; +namespace Spring.Messaging.Listener.Adapter; - protected override object InvokeListenerMethod(string methodName, object[] arguments) +/// +/// POC for a standard reflection based listener method invoker. +/// +/// Mark Pollack +public class StandardReflectionMessageListenerAdapter : MessageListenerAdapter +{ + private const BindingFlags BINDING_FLAGS + = BindingFlags.Public | BindingFlags.NonPublic + | BindingFlags.Instance | BindingFlags.Static + | BindingFlags.IgnoreCase; + + protected override object InvokeListenerMethod(string methodName, object[] arguments) + { + try { - try - { - MethodInfo mi = MethodNode.GetBestMethod(HandlerObject.GetType(), methodName, BINDING_FLAGS, arguments); - if (mi == null) - { - throw new ListenerExecutionFailedException("Failed to invoke the target method '" + methodName + - "' with arguments " + - StringUtils.CollectionToCommaDelimitedString(arguments)); - } - try - { - return mi.Invoke(HandlerObject, arguments); - } catch (Exception e) - { - throw new ListenerExecutionFailedException("Listener method '" + methodName + "' threw exception.", e); - } - } catch (Exception e) + MethodInfo mi = MethodNode.GetBestMethod(HandlerObject.GetType(), methodName, BINDING_FLAGS, arguments); + if (mi == null) { throw new ListenerExecutionFailedException("Failed to invoke the target method '" + methodName + - "' with arguments " + - StringUtils.CollectionToCommaDelimitedString(arguments), e); + "' with arguments " + + StringUtils.CollectionToCommaDelimitedString(arguments)); + } + + try + { + return mi.Invoke(HandlerObject, arguments); + } + catch (Exception e) + { + throw new ListenerExecutionFailedException("Listener method '" + methodName + "' threw exception.", e); } } + catch (Exception e) + { + throw new ListenerExecutionFailedException("Failed to invoke the target method '" + methodName + + "' with arguments " + + StringUtils.CollectionToCommaDelimitedString(arguments), e); + } } -} +} \ No newline at end of file diff --git a/test/Spring/Spring.Messaging.Tests/Messaging/Listener/DistributedTxMessageListenerContainerTests.cs b/test/Spring/Spring.Messaging.Tests/Messaging/Listener/DistributedTxMessageListenerContainerTests.cs index c01d97c3..9bcdb8ae 100644 --- a/test/Spring/Spring.Messaging.Tests/Messaging/Listener/DistributedTxMessageListenerContainerTests.cs +++ b/test/Spring/Spring.Messaging.Tests/Messaging/Listener/DistributedTxMessageListenerContainerTests.cs @@ -26,137 +26,130 @@ using Spring.Testing.NUnit; #endregion -namespace Spring.Messaging.Listener +namespace Spring.Messaging.Listener; + +/// +/// This class contains tests for DistributedTxMessageListenerContainer +/// +/// Mark Pollack +[TestFixture] +public class DistributedTxMessageListenerContainerTests : AbstractDependencyInjectionSpringContextTests { - /// - /// This class contains tests for DistributedTxMessageListenerContainer - /// - /// Mark Pollack - [TestFixture] - public class DistributedTxMessageListenerContainerTests : AbstractDependencyInjectionSpringContextTests + private int waitInMillis = 20000; + private DistributedTxMessageListenerContainer distributedTxMessageListenerContainer; + private SimpleHandler listener; + + [SetUp] + public override void SetUp() { + MessageQueueUtils.RecreateMessageQueue(@".\Private$\testtxqueue", true); + MessageQueueUtils.RecreateMessageQueue(@".\Private$\testtxretryqueue", true); + MessageQueueUtils.RecreateMessageQueue(@".\Private$\testtxresponsequeue", true); + if (listener != null) + listener.MessageCount = 0; //reset the property between tests b/c the object lifecycle is singleton! - private int waitInMillis = 20000; - private DistributedTxMessageListenerContainer distributedTxMessageListenerContainer; - private SimpleHandler listener; + base.SetUp(); + } - [SetUp] - public override void SetUp() + public DistributedTxMessageListenerContainer DistributedTxMessageListenerContainer + { + set { distributedTxMessageListenerContainer = value; } + } + + public SimpleHandler Listener + { + set { listener = value; } + } + + [Test] + public void SendAndAsyncReceiveWithExceptionHandling() + { + MessageQueueTemplate q = applicationContext["queueTemplate"] as MessageQueueTemplate; + Assert.IsNotNull(q); + + MessageQueueTemplate retryQ = applicationContext["retryQueueTemplate"] as MessageQueueTemplate; + Assert.IsNotNull(retryQ); + + q.ConvertAndSend("Goodbye World 1"); + + Assert.AreEqual(0, listener.MessageCount, "PRECONDITION FAILURE: Unable to send the message!"); + + distributedTxMessageListenerContainer.Start(); + + Thread.Sleep(waitInMillis); + + distributedTxMessageListenerContainer.Stop(); + distributedTxMessageListenerContainer.Shutdown(); + Thread.Sleep(2500); + + object msg = retryQ.ReceiveAndConvert(); + Assert.IsNotNull(msg); + string textMsg = msg as string; + Assert.IsNotNull(textMsg); + Assert.AreEqual("Goodbye World 1", textMsg); + } + + [Test] + public void SendAndAsyncReceive() + { + const int MESSAGE_COUNT = 5; + + //must match the retry count in the object registration for test to pass! + //const int EXCEPTION_QUEUE_RETRY_COUNT = 2; + + int expectedMessageCount = MESSAGE_COUNT; // +(MESSAGE_COUNT * EXCEPTION_QUEUE_RETRY_COUNT); + + MessageQueueTemplate q = applicationContext["queueTemplate"] as MessageQueueTemplate; + Assert.IsNotNull(q); + + for (int i = 0; i < MESSAGE_COUNT; i++) { - MessageQueueUtils.RecreateMessageQueue(@".\Private$\testtxqueue", true); - MessageQueueUtils.RecreateMessageQueue(@".\Private$\testtxretryqueue", true); - MessageQueueUtils.RecreateMessageQueue(@".\Private$\testtxresponsequeue", true); - - - if (listener != null) - listener.MessageCount = 0; //reset the property between tests b/c the object lifecycle is singleton! - - base.SetUp(); + q.ConvertAndSend(String.Format("Hello World {0}", (i + 1))); } + Assert.AreEqual(0, listener.MessageCount); - public DistributedTxMessageListenerContainer DistributedTxMessageListenerContainer + distributedTxMessageListenerContainer.Start(); + + Thread.Sleep(10000); + /* + System.Diagnostics.Stopwatch timer = new System.Diagnostics.Stopwatch(); + timer.Start(); + + while (listener.MessageCount < expectedMessageCount) { - set { distributedTxMessageListenerContainer = value; } - } - - - public SimpleHandler Listener - { - set { listener = value; } - } - - [Test] - public void SendAndAsyncReceiveWithExceptionHandling() - { - MessageQueueTemplate q = applicationContext["queueTemplate"] as MessageQueueTemplate; - Assert.IsNotNull(q); - - MessageQueueTemplate retryQ = applicationContext["retryQueueTemplate"] as MessageQueueTemplate; - Assert.IsNotNull(retryQ); - - q.ConvertAndSend("Goodbye World 1"); - - Assert.AreEqual(0, listener.MessageCount, "PRECONDITION FAILURE: Unable to send the message!"); - - distributedTxMessageListenerContainer.Start(); - - Thread.Sleep(waitInMillis); - - distributedTxMessageListenerContainer.Stop(); - distributedTxMessageListenerContainer.Shutdown(); - Thread.Sleep(2500); - - object msg = retryQ.ReceiveAndConvert(); - Assert.IsNotNull(msg); - string textMsg = msg as string; - Assert.IsNotNull(textMsg); - Assert.AreEqual("Goodbye World 1", textMsg); - } - - [Test] - public void SendAndAsyncReceive() - { - const int MESSAGE_COUNT = 5; - - //must match the retry count in the object registration for test to pass! - //const int EXCEPTION_QUEUE_RETRY_COUNT = 2; - - int expectedMessageCount = MESSAGE_COUNT; // +(MESSAGE_COUNT * EXCEPTION_QUEUE_RETRY_COUNT); - - MessageQueueTemplate q = applicationContext["queueTemplate"] as MessageQueueTemplate; - Assert.IsNotNull(q); - - for (int i = 0; i < MESSAGE_COUNT; i++) + if (timer.ElapsedMilliseconds > 10000) { - q.ConvertAndSend(String.Format("Hello World {0}", (i + 1))); + break; } - - Assert.AreEqual(0, listener.MessageCount); - - distributedTxMessageListenerContainer.Start(); - - Thread.Sleep(10000); - /* - System.Diagnostics.Stopwatch timer = new System.Diagnostics.Stopwatch(); - timer.Start(); - - while (listener.MessageCount < expectedMessageCount) - { - if (timer.ElapsedMilliseconds > 10000) - { - break; - } - //Assert.Fail("Did not receive expected number of messages within the permitted time limit."); - Thread.Sleep(1000); - } - - timer.Stop(); - - System.Diagnostics.Debug.WriteLine("elapsed time = " + timer.ElapsedMilliseconds); - */ - - Assert.AreEqual(expectedMessageCount, listener.MessageCount); - - distributedTxMessageListenerContainer.Stop(); - distributedTxMessageListenerContainer.Shutdown(); - Thread.Sleep(2500); - - MessageQueueTemplate responseQ = applicationContext["responseQueueTemplate"] as MessageQueueTemplate; - responseQ.ReceiveTimeout = new System.TimeSpan(0, 0, 2); - - Assert.IsNotNull(responseQ); - for (int i = 0; i < MESSAGE_COUNT; i++) - { - Assert.IsNotNull(responseQ.ReceiveAndConvert()); - } - + //Assert.Fail("Did not receive expected number of messages within the permitted time limit."); + Thread.Sleep(1000); } - protected override string[] ConfigLocations + timer.Stop(); + + System.Diagnostics.Debug.WriteLine("elapsed time = " + timer.ElapsedMilliseconds); + */ + + Assert.AreEqual(expectedMessageCount, listener.MessageCount); + + distributedTxMessageListenerContainer.Stop(); + distributedTxMessageListenerContainer.Shutdown(); + Thread.Sleep(2500); + + MessageQueueTemplate responseQ = applicationContext["responseQueueTemplate"] as MessageQueueTemplate; + responseQ.ReceiveTimeout = new System.TimeSpan(0, 0, 2); + + Assert.IsNotNull(responseQ); + for (int i = 0; i < MESSAGE_COUNT; i++) { - get { return new string[] { "assembly://Spring.Messaging.Tests/Spring.Messaging.Listener/DistributedTxMessageListenerContainerTests.xml" }; } + Assert.IsNotNull(responseQ.ReceiveAndConvert()); } } + + protected override string[] ConfigLocations + { + get { return new string[] { "assembly://Spring.Messaging.Tests/Spring.Messaging.Listener/DistributedTxMessageListenerContainerTests.xml" }; } + } } diff --git a/test/Spring/Spring.Messaging.Tests/Messaging/Listener/DistributedTxMessageListenerContainerTests.xml b/test/Spring/Spring.Messaging.Tests/Messaging/Listener/DistributedTxMessageListenerContainerTests.xml index e832af71..195bd14c 100644 --- a/test/Spring/Spring.Messaging.Tests/Messaging/Listener/DistributedTxMessageListenerContainerTests.xml +++ b/test/Spring/Spring.Messaging.Tests/Messaging/Listener/DistributedTxMessageListenerContainerTests.xml @@ -2,90 +2,92 @@ - - - - - - - - - - - - - - + - - - - - - - - - + + - - - - - - - - - + + + + + + + + + - - - - + + + + + + + + + - - - - + + + + + + + + + - - - - - - - - + + + + - - - - - - - - - + + + + - - - - - + + + + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - \ No newline at end of file diff --git a/test/Spring/Spring.Messaging.Tests/Messaging/Listener/LoggingExceptionHandler.cs b/test/Spring/Spring.Messaging.Tests/Messaging/Listener/LoggingExceptionHandler.cs index 2a3fb751..e09faf83 100644 --- a/test/Spring/Spring.Messaging.Tests/Messaging/Listener/LoggingExceptionHandler.cs +++ b/test/Spring/Spring.Messaging.Tests/Messaging/Listener/LoggingExceptionHandler.cs @@ -1,66 +1,65 @@ using System.Messaging; using Microsoft.Extensions.Logging; -namespace Spring.Messaging.Listener +namespace Spring.Messaging.Listener; + +/// +/// +/// +public class LoggingExceptionHandler : IExceptionHandler { + private TimeSpan recoveryTimeSpan; + + #region Logging Definition + + private static readonly ILog LOG = LogManager.GetLogger(typeof(LoggingExceptionHandler)); + + #endregion + /// - /// + /// Initializes a new instance of the class with + /// a default recovery time span of 5 seconds. /// - public class LoggingExceptionHandler : IExceptionHandler + public LoggingExceptionHandler() { - private TimeSpan recoveryTimeSpan; - - #region Logging Definition - - private static readonly ILog LOG = LogManager.GetLogger(typeof (LoggingExceptionHandler)); - - #endregion - - /// - /// Initializes a new instance of the class with - /// a default recovery time span of 5 seconds. - /// - public LoggingExceptionHandler() - { - recoveryTimeSpan = new TimeSpan(0, 0, 0, 5); - } - - public LoggingExceptionHandler(TimeSpan recoveryTimeSpan) - { - this.recoveryTimeSpan = recoveryTimeSpan; - } - - public TimeSpan RecoveryTimeSpan - { - set { recoveryTimeSpan = value; } - } - - #region IExceptionListener Members - - public void OnException(Exception exception, Message message) - { - //TODO other exception handling - MessageQueueException e = exception as MessageQueueException; - if (e != null) - { - switch ((int) e.MessageQueueErrorCode) - { - case (int) MessageQueueErrorCode.IOTimeout: - case -1073741536: - Console.WriteLine("Msmq Error -1073741536 or IOTimeout : Sleeping, and then ReListening"); - Thread.Sleep(recoveryTimeSpan); - break; - default: - LOG.LogError(e, "Exception Receiving Message"); - break; - } - } - else - { - LOG.LogError(exception, "got exception"); - } - } - - #endregion + recoveryTimeSpan = new TimeSpan(0, 0, 0, 5); } + + public LoggingExceptionHandler(TimeSpan recoveryTimeSpan) + { + this.recoveryTimeSpan = recoveryTimeSpan; + } + + public TimeSpan RecoveryTimeSpan + { + set { recoveryTimeSpan = value; } + } + + #region IExceptionListener Members + + public void OnException(Exception exception, Message message) + { + //TODO other exception handling + MessageQueueException e = exception as MessageQueueException; + if (e != null) + { + switch ((int) e.MessageQueueErrorCode) + { + case (int) MessageQueueErrorCode.IOTimeout: + case -1073741536: + Console.WriteLine("Msmq Error -1073741536 or IOTimeout : Sleeping, and then ReListening"); + Thread.Sleep(recoveryTimeSpan); + break; + default: + LOG.LogError(e, "Exception Receiving Message"); + break; + } + } + else + { + LOG.LogError(exception, "got exception"); + } + } + + #endregion } diff --git a/test/Spring/Spring.Messaging.Tests/Messaging/Listener/MultiThreadedNonTransactionalMessageListenerContainerTests.cs b/test/Spring/Spring.Messaging.Tests/Messaging/Listener/MultiThreadedNonTransactionalMessageListenerContainerTests.cs index 1c96fe37..b9d55256 100644 --- a/test/Spring/Spring.Messaging.Tests/Messaging/Listener/MultiThreadedNonTransactionalMessageListenerContainerTests.cs +++ b/test/Spring/Spring.Messaging.Tests/Messaging/Listener/MultiThreadedNonTransactionalMessageListenerContainerTests.cs @@ -27,93 +27,90 @@ using System.Diagnostics; #endregion -namespace Spring.Messaging.Listener +namespace Spring.Messaging.Listener; + +/// +/// This class contains tests for +/// +/// Mark Pollack +/// $Id:$ +[TestFixture] +public class MultiThreadedNonTransactionalMessageListenerContainerTests : AbstractDependencyInjectionSpringContextTests { - /// - /// This class contains tests for - /// - /// Mark Pollack - /// $Id:$ - [TestFixture] - public class MultiThreadedNonTransactionalMessageListenerContainerTests : AbstractDependencyInjectionSpringContextTests + private NonTransactionalMessageListenerContainer container; + private WaitingHandler listener; + private SimpleExceptionHandler exceptionHandler; + + [SetUp] + public override void SetUp() { + MessageQueueUtils.RecreateMessageQueue(@".\Private$\testqueue", false); + MessageQueueUtils.RecreateMessageQueue(@".\Private$\testresponsequeue", false); + base.SetUp(); + } - private NonTransactionalMessageListenerContainer container; - private WaitingHandler listener; - private SimpleExceptionHandler exceptionHandler; + public SimpleExceptionHandler ExceptionHandler + { + set { exceptionHandler = value; } + } - [SetUp] - public override void SetUp() + public NonTransactionalMessageListenerContainer Container + { + get { return container; } + set { container = value; } + } + + public WaitingHandler Listener + { + get { return listener; } + set { listener = value; } + } + + [Test] + [Ignore("Appveyor problems")] + public void Test() + { + System.Diagnostics.Stopwatch timer = new System.Diagnostics.Stopwatch(); + + MessageQueueTemplate q = applicationContext["testQueueTemplate"] as MessageQueueTemplate; + Assert.IsNotNull(q); + + q.ConvertAndSend("Hello World 1"); + q.ConvertAndSend("Hello World 2"); + q.ConvertAndSend("Hello World 3"); + q.ConvertAndSend("Hello World 4"); + q.ConvertAndSend("Hello World 5"); + + //Reset the state so that running all tests together will succeed. + exceptionHandler.MessageCount = 0; + + Assert.AreEqual(0, listener.MessageCount); + + timer.Start(); + + container.Start(); + + while (listener.MessageCount < 5) { - MessageQueueUtils.RecreateMessageQueue(@".\Private$\testqueue", false); - MessageQueueUtils.RecreateMessageQueue(@".\Private$\testresponsequeue", false); - base.SetUp(); + //provide an exit if the test is completely over-length + if (timer.ElapsedMilliseconds > 120000) + Assert.Fail("Did not receive expected number of messages with the expected time-limit!"); } - public SimpleExceptionHandler ExceptionHandler - { - set { exceptionHandler = value; } - } + timer.Stop(); - public NonTransactionalMessageListenerContainer Container - { - get { return container; } - set { container = value; } - } + container.Stop(); + container.Shutdown(); - public WaitingHandler Listener - { - get { return listener; } - set { listener = value; } - } + Debug.WriteLine(String.Format("Elapsed Milliseconds: {0}", timer.ElapsedMilliseconds)); + Assert.Less(timer.ElapsedMilliseconds, 50000); + Assert.AreEqual(5, listener.MessageCount); + Assert.AreEqual(0, exceptionHandler.MessageCount); + } - [Test] - [Ignore("Appveyor problems")] - public void Test() - { - System.Diagnostics.Stopwatch timer = new System.Diagnostics.Stopwatch(); - - MessageQueueTemplate q = applicationContext["testQueueTemplate"] as MessageQueueTemplate; - Assert.IsNotNull(q); - - q.ConvertAndSend("Hello World 1"); - q.ConvertAndSend("Hello World 2"); - q.ConvertAndSend("Hello World 3"); - q.ConvertAndSend("Hello World 4"); - q.ConvertAndSend("Hello World 5"); - - //Reset the state so that running all tests together will succeed. - exceptionHandler.MessageCount = 0; - - Assert.AreEqual(0, listener.MessageCount); - - timer.Start(); - - container.Start(); - - while (listener.MessageCount < 5) - { - //provide an exit if the test is completely over-length - if (timer.ElapsedMilliseconds > 120000) - Assert.Fail("Did not receive expected number of messages with the expected time-limit!"); - } - - timer.Stop(); - - container.Stop(); - container.Shutdown(); - - Debug.WriteLine(String.Format("Elapsed Milliseconds: {0}", timer.ElapsedMilliseconds)); - - Assert.Less(timer.ElapsedMilliseconds, 50000); - Assert.AreEqual(5, listener.MessageCount); - Assert.AreEqual(0, exceptionHandler.MessageCount); - } - - protected override string[] ConfigLocations - { - get { return new string[] { "assembly://Spring.Messaging.Tests/Spring.Messaging.Listener/MultiThreadedNonTransactionalMessageListenerContainerTests.xml" }; } - } + protected override string[] ConfigLocations + { + get { return new string[] { "assembly://Spring.Messaging.Tests/Spring.Messaging.Listener/MultiThreadedNonTransactionalMessageListenerContainerTests.xml" }; } } } diff --git a/test/Spring/Spring.Messaging.Tests/Messaging/Listener/MultiThreadedNonTransactionalMessageListenerContainerTests.xml b/test/Spring/Spring.Messaging.Tests/Messaging/Listener/MultiThreadedNonTransactionalMessageListenerContainerTests.xml index a3c9980a..bc745fa9 100644 --- a/test/Spring/Spring.Messaging.Tests/Messaging/Listener/MultiThreadedNonTransactionalMessageListenerContainerTests.xml +++ b/test/Spring/Spring.Messaging.Tests/Messaging/Listener/MultiThreadedNonTransactionalMessageListenerContainerTests.xml @@ -3,88 +3,90 @@ xmlns:db="http://www.springframework.net/database"> - - - - - - - + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - + + + + + - - - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - \ No newline at end of file diff --git a/test/Spring/Spring.Messaging.Tests/Messaging/Listener/NonTransactionalMessageListenerContainerTests.cs b/test/Spring/Spring.Messaging.Tests/Messaging/Listener/NonTransactionalMessageListenerContainerTests.cs index f78bbf9d..cdd48f10 100644 --- a/test/Spring/Spring.Messaging.Tests/Messaging/Listener/NonTransactionalMessageListenerContainerTests.cs +++ b/test/Spring/Spring.Messaging.Tests/Messaging/Listener/NonTransactionalMessageListenerContainerTests.cs @@ -26,105 +26,101 @@ using Spring.Testing.NUnit; #endregion -namespace Spring.Messaging.Listener +namespace Spring.Messaging.Listener; + +/// +/// This class contains tests for +/// +/// Mark Pollack +/// $Id:$ +[TestFixture] +public class NonTransactionalMessageListenerContainerTests : AbstractDependencyInjectionSpringContextTests { - /// - /// This class contains tests for - /// - /// Mark Pollack - /// $Id:$ - [TestFixture] - public class NonTransactionalMessageListenerContainerTests : AbstractDependencyInjectionSpringContextTests + private int waitInMillis = 20000; + private NonTransactionalMessageListenerContainer container; + private SimpleHandler listener; + private SimpleExceptionHandler exceptionHandler; + + [SetUp] + public override void SetUp() { + MessageQueueUtils.RecreateMessageQueue(@".\Private$\testqueue", false); + MessageQueueUtils.RecreateMessageQueue(@".\Private$\testresponsequeue", false); - private int waitInMillis = 20000; - private NonTransactionalMessageListenerContainer container; - private SimpleHandler listener; - private SimpleExceptionHandler exceptionHandler; + base.SetUp(); - [SetUp] - public override void SetUp() - { - MessageQueueUtils.RecreateMessageQueue(@".\Private$\testqueue", false); - MessageQueueUtils.RecreateMessageQueue(@".\Private$\testresponsequeue", false); - - base.SetUp(); - - //Reset the state so that running all tests together will succeed. - exceptionHandler.MessageCount = 0; - listener.MessageCount = 0; - } - - public SimpleExceptionHandler ExceptionHandler - { - set { exceptionHandler = value; } - } - - public NonTransactionalMessageListenerContainer Container - { - get { return container; } - set { container = value; } - } - - public SimpleHandler Listener - { - get { return listener; } - set { listener = value; } - } - - [Test] - [Ignore("Appveyor problems")] - public void SendAndAsyncReceiveWithExceptionHandling() - { - MessageQueueTemplate q = applicationContext["testQueueTemplate"] as MessageQueueTemplate; - Assert.IsNotNull(q); - q.ConvertAndSend("Goodbye World 1"); - Assert.AreEqual(0, listener.MessageCount); - container.Start(); - Thread.Sleep(waitInMillis); - Assert.AreEqual(0, listener.MessageCount); - Assert.AreEqual(1, exceptionHandler.MessageCount); - container.Stop(); - container.Shutdown(); - Thread.Sleep(2500); - } - - [Test] - [Ignore("Appveyor problems")] - public void SendAndAsyncReceive() - { - - //MessageQueueTemplate q = applicationContext["testQueueTemplate"] as MessageQueueTemplate; - - MessageQueueTemplate q = applicationContext["testRemoteTemplate"] as MessageQueueTemplate; - Assert.IsNotNull(q); - - q.ConvertAndSend("Hello World 1"); - q.ConvertAndSend("Hello World 2"); - q.ConvertAndSend("Hello World 3"); - q.ConvertAndSend("Hello World 4"); - q.ConvertAndSend("Hello World 5"); - - //Reset the state so that running all tests together will succeed. - exceptionHandler.MessageCount = 0; - - Assert.AreEqual(0, listener.MessageCount); - - container.Start(); - - Thread.Sleep(waitInMillis); - Assert.AreEqual(5, listener.MessageCount); - Assert.AreEqual(0, exceptionHandler.MessageCount); - - container.Stop(); - container.Shutdown(); - Thread.Sleep(2500); - - } - - protected override string[] ConfigLocations - { - get { return new string[] { "assembly://Spring.Messaging.Tests/Spring.Messaging.Listener/NonTransactionalMessageListenerContainerTests.xml" }; } - } + //Reset the state so that running all tests together will succeed. + exceptionHandler.MessageCount = 0; + listener.MessageCount = 0; } -} + + public SimpleExceptionHandler ExceptionHandler + { + set { exceptionHandler = value; } + } + + public NonTransactionalMessageListenerContainer Container + { + get { return container; } + set { container = value; } + } + + public SimpleHandler Listener + { + get { return listener; } + set { listener = value; } + } + + [Test] + [Ignore("Appveyor problems")] + public void SendAndAsyncReceiveWithExceptionHandling() + { + MessageQueueTemplate q = applicationContext["testQueueTemplate"] as MessageQueueTemplate; + Assert.IsNotNull(q); + q.ConvertAndSend("Goodbye World 1"); + Assert.AreEqual(0, listener.MessageCount); + container.Start(); + Thread.Sleep(waitInMillis); + Assert.AreEqual(0, listener.MessageCount); + Assert.AreEqual(1, exceptionHandler.MessageCount); + container.Stop(); + container.Shutdown(); + Thread.Sleep(2500); + } + + [Test] + [Ignore("Appveyor problems")] + public void SendAndAsyncReceive() + { + //MessageQueueTemplate q = applicationContext["testQueueTemplate"] as MessageQueueTemplate; + + MessageQueueTemplate q = applicationContext["testRemoteTemplate"] as MessageQueueTemplate; + Assert.IsNotNull(q); + + q.ConvertAndSend("Hello World 1"); + q.ConvertAndSend("Hello World 2"); + q.ConvertAndSend("Hello World 3"); + q.ConvertAndSend("Hello World 4"); + q.ConvertAndSend("Hello World 5"); + + //Reset the state so that running all tests together will succeed. + exceptionHandler.MessageCount = 0; + + Assert.AreEqual(0, listener.MessageCount); + + container.Start(); + + Thread.Sleep(waitInMillis); + Assert.AreEqual(5, listener.MessageCount); + Assert.AreEqual(0, exceptionHandler.MessageCount); + + container.Stop(); + container.Shutdown(); + Thread.Sleep(2500); + } + + protected override string[] ConfigLocations + { + get { return new string[] { "assembly://Spring.Messaging.Tests/Spring.Messaging.Listener/NonTransactionalMessageListenerContainerTests.xml" }; } + } +} \ No newline at end of file diff --git a/test/Spring/Spring.Messaging.Tests/Messaging/Listener/NonTransactionalMessageListenerContainerTests.xml b/test/Spring/Spring.Messaging.Tests/Messaging/Listener/NonTransactionalMessageListenerContainerTests.xml index 75cdd012..adad9a61 100644 --- a/test/Spring/Spring.Messaging.Tests/Messaging/Listener/NonTransactionalMessageListenerContainerTests.xml +++ b/test/Spring/Spring.Messaging.Tests/Messaging/Listener/NonTransactionalMessageListenerContainerTests.xml @@ -2,91 +2,94 @@ - - - - - - - + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - + + + + + - - - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - \ No newline at end of file diff --git a/test/Spring/Spring.Messaging.Tests/Messaging/Listener/SimpleExceptionHandler.cs b/test/Spring/Spring.Messaging.Tests/Messaging/Listener/SimpleExceptionHandler.cs index 4c66dc17..159d7a2f 100644 --- a/test/Spring/Spring.Messaging.Tests/Messaging/Listener/SimpleExceptionHandler.cs +++ b/test/Spring/Spring.Messaging.Tests/Messaging/Listener/SimpleExceptionHandler.cs @@ -1,34 +1,32 @@ using System.Messaging; using Microsoft.Extensions.Logging; -namespace Spring.Messaging.Listener +namespace Spring.Messaging.Listener; + +public class SimpleExceptionHandler : IExceptionHandler { - public class SimpleExceptionHandler : IExceptionHandler + #region Logging + + private static readonly ILogger LOG = LogManager.GetLogger(); + + #endregion + + private int messageCount; + + public int MessageCount { - #region Logging - - private static readonly ILogger LOG = LogManager.GetLogger(); - - #endregion - - private int messageCount; - - - public int MessageCount - { - get { return messageCount; } - set { messageCount = value; } - } - - #region IExceptionHandler Members - - public void OnException(Exception exception, Message message) - { - LOG.LogError("Exception Handler processing message id = [" + message.Id + "]"); - LOG.LogError(exception, "Exception = "); - messageCount++; - } - - #endregion + get { return messageCount; } + set { messageCount = value; } } + + #region IExceptionHandler Members + + public void OnException(Exception exception, Message message) + { + LOG.LogError("Exception Handler processing message id = [" + message.Id + "]"); + LOG.LogError(exception, "Exception = "); + messageCount++; + } + + #endregion } diff --git a/test/Spring/Spring.Messaging.Tests/Messaging/Listener/SimpleHandler.cs b/test/Spring/Spring.Messaging.Tests/Messaging/Listener/SimpleHandler.cs index 8944d313..2a4e6ba0 100644 --- a/test/Spring/Spring.Messaging.Tests/Messaging/Listener/SimpleHandler.cs +++ b/test/Spring/Spring.Messaging.Tests/Messaging/Listener/SimpleHandler.cs @@ -1,46 +1,46 @@ using Microsoft.Extensions.Logging; -namespace Spring.Messaging.Listener +namespace Spring.Messaging.Listener; + +public class SimpleHandler { - public class SimpleHandler + #region Logging + + private static readonly ILogger LOG = LogManager.GetLogger(); + + #endregion + + private int messageCount; + + private string stateVariable; + + public SimpleHandler() { - #region Logging + this.stateVariable = "hello"; + } - private static readonly ILogger LOG = LogManager.GetLogger(); + public SimpleHandler(string stateVariable) + { + this.stateVariable = stateVariable; + } - #endregion + public int MessageCount + { + get { return messageCount; } + set { messageCount = value; } + } - private int messageCount; - - private string stateVariable; - - public SimpleHandler() + public string HandleMessage(string msgTxt) + { + LOG.LogDebug("Received text = [" + msgTxt + "]"); + LOG.LogDebug("constructor set state string = " + stateVariable); + if (msgTxt.Contains("Goodbye")) { - this.stateVariable = "hello"; - } - public SimpleHandler(string stateVariable) - { - this.stateVariable = stateVariable; + throw new ArgumentException("Don't like saying goodbye!"); } - - public int MessageCount - { - get { return messageCount; } - set { messageCount = value; } - } - - public string HandleMessage(string msgTxt) - { - LOG.LogDebug("Received text = [" + msgTxt + "]"); - LOG.LogDebug("constructor set state string = " + stateVariable); - if (msgTxt.Contains("Goodbye")) - { - throw new ArgumentException("Don't like saying goodbye!"); - } - messageCount++; - LOG.LogDebug("Message listener count = " + messageCount); - return msgTxt + " - processed!"; - } + messageCount++; + LOG.LogDebug("Message listener count = " + messageCount); + return msgTxt + " - processed!"; } } diff --git a/test/Spring/Spring.Messaging.Tests/Messaging/Listener/SimpleMessageListener.cs b/test/Spring/Spring.Messaging.Tests/Messaging/Listener/SimpleMessageListener.cs index 1b9dc81d..1dd15711 100644 --- a/test/Spring/Spring.Messaging.Tests/Messaging/Listener/SimpleMessageListener.cs +++ b/test/Spring/Spring.Messaging.Tests/Messaging/Listener/SimpleMessageListener.cs @@ -1,40 +1,37 @@ - - using System.Messaging; using Microsoft.Extensions.Logging; -namespace Spring.Messaging.Listener +namespace Spring.Messaging.Listener; + +public class SimpleMessageListener : IMessageListener { - public class SimpleMessageListener : IMessageListener + #region Logging Definition + + private static readonly ILogger LOG = LogManager.GetLogger(); + + #endregion + + private Message lastReceivedMessage; + private int messageCount; + + public Message LastReceivedMessage { - #region Logging Definition - - private static readonly ILogger LOG = LogManager.GetLogger(); - #endregion - - private Message lastReceivedMessage; - private int messageCount; - - public Message LastReceivedMessage - { - get { return lastReceivedMessage; } - } - - - public int MessageCount - { - get { return messageCount; } - } - - #region IMessageListener Members - - public void OnMessage(Message message) - { - lastReceivedMessage = message; - messageCount++; - LOG.LogDebug("Message listener count = " + messageCount); - } - - #endregion + get { return lastReceivedMessage; } } -} + + public int MessageCount + { + get { return messageCount; } + } + + #region IMessageListener Members + + public void OnMessage(Message message) + { + lastReceivedMessage = message; + messageCount++; + LOG.LogDebug("Message listener count = " + messageCount); + } + + #endregion +} \ No newline at end of file diff --git a/test/Spring/Spring.Messaging.Tests/Messaging/Listener/TransactionalMessageListenerContainerTests.cs b/test/Spring/Spring.Messaging.Tests/Messaging/Listener/TransactionalMessageListenerContainerTests.cs index a13c8188..81100ed7 100644 --- a/test/Spring/Spring.Messaging.Tests/Messaging/Listener/TransactionalMessageListenerContainerTests.cs +++ b/test/Spring/Spring.Messaging.Tests/Messaging/Listener/TransactionalMessageListenerContainerTests.cs @@ -26,130 +26,121 @@ using Spring.Testing.NUnit; #endregion -namespace Spring.Messaging.Listener +namespace Spring.Messaging.Listener; + +/// +/// This class contains integration tests for the TransactionalMessageListenerContainer +/// +/// Mark Pollack +[TestFixture] +public class TransactionalMessageListenerContainerTests : AbstractDependencyInjectionSpringContextTests { - /// - /// This class contains integration tests for the TransactionalMessageListenerContainer - /// - /// Mark Pollack - [TestFixture] - public class TransactionalMessageListenerContainerTests : AbstractDependencyInjectionSpringContextTests + private int waitInMillis = 20000; + private TransactionalMessageListenerContainer transactionalMessageListenerContainer; + private SimpleHandler listener; + + [SetUp] + public override void SetUp() { - private int waitInMillis = 20000; - private TransactionalMessageListenerContainer transactionalMessageListenerContainer; - private SimpleHandler listener; + MessageQueueUtils.RecreateMessageQueue(@".\Private$\testtxqueue", true); + MessageQueueUtils.RecreateMessageQueue(@".\Private$\testtxretryqueue", true); + MessageQueueUtils.RecreateMessageQueue(@".\Private$\testtxresponsequeue", true); + if (listener != null) + listener.MessageCount = 0; //reset the property between tests b/c the object lifecycle is singleton! + base.SetUp(); + } + public TransactionalMessageListenerContainer TransactionalMessageListenerContainer + { + set { transactionalMessageListenerContainer = value; } + } - [SetUp] - public override void SetUp() + public SimpleHandler SimpleHandler + { + set { listener = value; } + } + + [Test] + public void EnsureMessageQueuePropertyIsSet() + { + TransactionalMessageListenerContainer container = new TransactionalMessageListenerContainer(); + + try { - MessageQueueUtils.RecreateMessageQueue(@".\Private$\testtxqueue", true); - MessageQueueUtils.RecreateMessageQueue(@".\Private$\testtxretryqueue", true); - MessageQueueUtils.RecreateMessageQueue(@".\Private$\testtxresponsequeue", true); - if (listener != null) - listener.MessageCount = 0; //reset the property between tests b/c the object lifecycle is singleton! - base.SetUp(); + container.AfterPropertiesSet(); + Assert.Fail("Expected ArgumentException not thrown."); } - - public TransactionalMessageListenerContainer TransactionalMessageListenerContainer + catch (ArgumentException ex) { - set { transactionalMessageListenerContainer = value; } - } - - - public SimpleHandler SimpleHandler - { - set { listener = value; } - } - - [Test] - public void EnsureMessageQueuePropertyIsSet() - { - TransactionalMessageListenerContainer container = new TransactionalMessageListenerContainer(); - - try - { - container.AfterPropertiesSet(); - Assert.Fail("Expected ArgumentException not thrown."); - } - catch (ArgumentException ex) - { - Assert.AreEqual("Property 'MessageQueueObjectName' is required", ex.Message); - } - } - - [Test] - public void EnsureuseContainerManagedMessageQueueTransactionIsSetCorrectly() - { - TransactionalMessageListenerContainer container = applicationContext["transactionalMessageListenerContainer"] as TransactionalMessageListenerContainer; - Assert.IsNotNull(container); - Assert.AreEqual(true, container.UseContainerManagedMessageQueueTransaction); - } - - [Test] - public void SendAndAsyncReceiveWithExceptionHandling() - { - listener.MessageCount = 0; - - MessageQueueTemplate q = applicationContext["queueTemplate"] as MessageQueueTemplate; - Assert.IsNotNull(q); - - MessageQueueTemplate retryQ = applicationContext["retryQueueTemplate"] as MessageQueueTemplate; - Assert.IsNotNull(retryQ); - - q.ConvertAndSend("Goodbye World 1"); - - Assert.AreEqual(0, listener.MessageCount); - transactionalMessageListenerContainer.Start(); - - Thread.Sleep(waitInMillis); - - - transactionalMessageListenerContainer.Stop(); - transactionalMessageListenerContainer.Shutdown(); - Thread.Sleep(2500); - - object msg = retryQ.ReceiveAndConvert(); - Assert.IsNotNull(msg); - string textMsg = msg as string; - Assert.IsNotNull(textMsg); - Assert.AreEqual("Goodbye World 1", textMsg); - } - - - [Test] - public void SendAndAsyncReceive() - { - listener.MessageCount = 0; - - MessageQueueTemplate q = applicationContext["queueTemplate"] as MessageQueueTemplate; - Assert.IsNotNull(q); - - q.ConvertAndSend("Hello World 1"); - q.ConvertAndSend("Hello World 2"); - q.ConvertAndSend("Hello World 3"); - q.ConvertAndSend("Hello World 4"); - q.ConvertAndSend("Hello World 5"); - - Assert.AreEqual(0, listener.MessageCount); - - transactionalMessageListenerContainer.Start(); - - Thread.Sleep(waitInMillis * 2); - Assert.AreEqual(5, listener.MessageCount); - - transactionalMessageListenerContainer.Stop(); - transactionalMessageListenerContainer.Shutdown(); - Thread.Sleep(2500); - - } - - - protected override string[] ConfigLocations - { - get { return new string[] { "assembly://Spring.Messaging.Tests/Spring.Messaging.Listener/TransactionalMessageListenerContainerTests.xml" }; } + Assert.AreEqual("Property 'MessageQueueObjectName' is required", ex.Message); } } + [Test] + public void EnsureuseContainerManagedMessageQueueTransactionIsSetCorrectly() + { + TransactionalMessageListenerContainer container = applicationContext["transactionalMessageListenerContainer"] as TransactionalMessageListenerContainer; + Assert.IsNotNull(container); + Assert.AreEqual(true, container.UseContainerManagedMessageQueueTransaction); + } + [Test] + public void SendAndAsyncReceiveWithExceptionHandling() + { + listener.MessageCount = 0; + + MessageQueueTemplate q = applicationContext["queueTemplate"] as MessageQueueTemplate; + Assert.IsNotNull(q); + + MessageQueueTemplate retryQ = applicationContext["retryQueueTemplate"] as MessageQueueTemplate; + Assert.IsNotNull(retryQ); + + q.ConvertAndSend("Goodbye World 1"); + + Assert.AreEqual(0, listener.MessageCount); + transactionalMessageListenerContainer.Start(); + + Thread.Sleep(waitInMillis); + + transactionalMessageListenerContainer.Stop(); + transactionalMessageListenerContainer.Shutdown(); + Thread.Sleep(2500); + + object msg = retryQ.ReceiveAndConvert(); + Assert.IsNotNull(msg); + string textMsg = msg as string; + Assert.IsNotNull(textMsg); + Assert.AreEqual("Goodbye World 1", textMsg); + } + + [Test] + public void SendAndAsyncReceive() + { + listener.MessageCount = 0; + + MessageQueueTemplate q = applicationContext["queueTemplate"] as MessageQueueTemplate; + Assert.IsNotNull(q); + + q.ConvertAndSend("Hello World 1"); + q.ConvertAndSend("Hello World 2"); + q.ConvertAndSend("Hello World 3"); + q.ConvertAndSend("Hello World 4"); + q.ConvertAndSend("Hello World 5"); + + Assert.AreEqual(0, listener.MessageCount); + + transactionalMessageListenerContainer.Start(); + + Thread.Sleep(waitInMillis * 2); + Assert.AreEqual(5, listener.MessageCount); + + transactionalMessageListenerContainer.Stop(); + transactionalMessageListenerContainer.Shutdown(); + Thread.Sleep(2500); + } + + protected override string[] ConfigLocations + { + get { return new string[] { "assembly://Spring.Messaging.Tests/Spring.Messaging.Listener/TransactionalMessageListenerContainerTests.xml" }; } + } } diff --git a/test/Spring/Spring.Messaging.Tests/Messaging/Listener/TransactionalMessageListenerContainerTests.xml b/test/Spring/Spring.Messaging.Tests/Messaging/Listener/TransactionalMessageListenerContainerTests.xml index f7bff80b..15cd6f19 100644 --- a/test/Spring/Spring.Messaging.Tests/Messaging/Listener/TransactionalMessageListenerContainerTests.xml +++ b/test/Spring/Spring.Messaging.Tests/Messaging/Listener/TransactionalMessageListenerContainerTests.xml @@ -3,89 +3,91 @@ xmlns:db="http://www.springframework.net/database"> - + - - - - + - - - - - - - - - + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - + + + + + + + + + - - - - - - - - + + + + - - - - - - - - - + + + + - - - - - + + + - - - + + + + + + + + + - - - - + + + + + + + + + + + + + + + + + + - - - - \ No newline at end of file diff --git a/test/Spring/Spring.Messaging.Tests/Messaging/Listener/WaitingHandler.cs b/test/Spring/Spring.Messaging.Tests/Messaging/Listener/WaitingHandler.cs index 253fb4fc..18f21416 100644 --- a/test/Spring/Spring.Messaging.Tests/Messaging/Listener/WaitingHandler.cs +++ b/test/Spring/Spring.Messaging.Tests/Messaging/Listener/WaitingHandler.cs @@ -1,45 +1,44 @@ using Microsoft.Extensions.Logging; -namespace Spring.Messaging.Listener +namespace Spring.Messaging.Listener; + +public class WaitingHandler { - public class WaitingHandler + #region Logging + + private static readonly ILogger LOG = LogManager.GetLogger(); + + #endregion + + private int messageCount; + + private string stateVariable; + + public WaitingHandler() { - #region Logging - - private static readonly ILogger LOG = LogManager.GetLogger(); - - #endregion - - private int messageCount; - - private string stateVariable; - - public WaitingHandler() - { - this.stateVariable = "hello"; - } - public WaitingHandler(string stateVariable) - { - this.stateVariable = stateVariable; - } - - - public int MessageCount - { - get { return messageCount; } - set { messageCount = value; } - } - - public string HandleMessage(string msgTxt) - { - LOG.LogDebug(String.Format("Received text = [{0}]", msgTxt)); - LOG.LogDebug("constructor set state string = " + stateVariable); - - Thread.Sleep(10000); - - messageCount++; - LOG.LogDebug("Message listener count = " + messageCount); - return msgTxt + " - processed!"; - } + this.stateVariable = "hello"; } -} + + public WaitingHandler(string stateVariable) + { + this.stateVariable = stateVariable; + } + + public int MessageCount + { + get { return messageCount; } + set { messageCount = value; } + } + + public string HandleMessage(string msgTxt) + { + LOG.LogDebug(String.Format("Received text = [{0}]", msgTxt)); + LOG.LogDebug("constructor set state string = " + stateVariable); + + Thread.Sleep(10000); + + messageCount++; + LOG.LogDebug("Message listener count = " + messageCount); + return msgTxt + " - processed!"; + } +} \ No newline at end of file diff --git a/test/Spring/Spring.Messaging.Tests/Messaging/Support/MessageAlreadyProcessedException.cs b/test/Spring/Spring.Messaging.Tests/Messaging/Support/MessageAlreadyProcessedException.cs index f9c9de19..58c1f853 100644 --- a/test/Spring/Spring.Messaging.Tests/Messaging/Support/MessageAlreadyProcessedException.cs +++ b/test/Spring/Spring.Messaging.Tests/Messaging/Support/MessageAlreadyProcessedException.cs @@ -1,65 +1,64 @@ using System.Runtime.Serialization; -namespace Spring.Messaging +namespace Spring.Messaging; + +/// +/// Indicates that the received message has already been processed. Will typically be used +/// in an IMessageTransactionExceptionHandler to commit (i.e. remove from the queue) a +/// message that has been processed by the database but not acknowledged to MSMQ +/// due to an application failure. +/// +[Serializable] +public class MessageAlreadyProcessedException : MessagingException { - /// - /// Indicates that the received message has already been processed. Will typically be used - /// in an IMessageTransactionExceptionHandler to commit (i.e. remove from the queue) a - /// message that has been processed by the database but not acknowledged to MSMQ - /// due to an application failure. - /// - [Serializable] - public class MessageAlreadyProcessedException : MessagingException + #region Constructor (s) / Destructor + + /// Creates a new instance of the MessageAlreadyProcessedException class. + public MessageAlreadyProcessedException() { - #region Constructor (s) / Destructor - - /// Creates a new instance of the MessageAlreadyProcessedException class. - public MessageAlreadyProcessedException() - { - } - - /// - /// Creates a new instance of the MessageAlreadyProcessedException class. with the specified message. - /// - /// - /// A message about the exception. - /// - public MessageAlreadyProcessedException(string message) : base(message) - { - } - - /// - /// Creates a new instance of the MessageAlreadyProcessedException class with the specified message - /// and root cause. - /// - /// - /// A message about the exception. - /// - /// - /// The root exception that is being wrapped. - /// - public MessageAlreadyProcessedException(string message, Exception rootCause) - : base(message, rootCause) - { - } - - /// - /// Creates a new instance of the MessageAlreadyProcessedException class. - /// - /// - /// The - /// that holds the serialized object data about the exception being thrown. - /// - /// - /// The - /// that contains contextual information about the source or destination. - /// - protected MessageAlreadyProcessedException( - SerializationInfo info, StreamingContext context) - : base(info, context) - { - } - - #endregion } + + /// + /// Creates a new instance of the MessageAlreadyProcessedException class. with the specified message. + /// + /// + /// A message about the exception. + /// + public MessageAlreadyProcessedException(string message) : base(message) + { + } + + /// + /// Creates a new instance of the MessageAlreadyProcessedException class with the specified message + /// and root cause. + /// + /// + /// A message about the exception. + /// + /// + /// The root exception that is being wrapped. + /// + public MessageAlreadyProcessedException(string message, Exception rootCause) + : base(message, rootCause) + { + } + + /// + /// Creates a new instance of the MessageAlreadyProcessedException class. + /// + /// + /// The + /// that holds the serialized object data about the exception being thrown. + /// + /// + /// The + /// that contains contextual information about the source or destination. + /// + protected MessageAlreadyProcessedException( + SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + + #endregion } diff --git a/test/Spring/Spring.Messaging.Tests/Messaging/Support/MessageQueueFactoryObjectTests.cs b/test/Spring/Spring.Messaging.Tests/Messaging/Support/MessageQueueFactoryObjectTests.cs index 4a3e96c8..3093199f 100644 --- a/test/Spring/Spring.Messaging.Tests/Messaging/Support/MessageQueueFactoryObjectTests.cs +++ b/test/Spring/Spring.Messaging.Tests/Messaging/Support/MessageQueueFactoryObjectTests.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -22,67 +22,64 @@ using System.Messaging; using NUnit.Framework; - using Spring.Testing.NUnit; #endregion -namespace Spring.Messaging.Support +namespace Spring.Messaging.Support; + +/// +/// This class contains tests for the MessageQueueFactory +/// +/// Mark Pollack +[TestFixture] +public class MessageQueueFactoryObjectTests : AbstractDependencyInjectionSpringContextTests { - /// - /// This class contains tests for the MessageQueueFactory - /// - /// Mark Pollack - [TestFixture] - public class MessageQueueFactoryObjectTests : AbstractDependencyInjectionSpringContextTests + [Test] + public void CheckDefaultConstructorValues() { - [Test] - public void CheckDefaultConstructorValues() - { - MessageQueueFactoryObject mqFactoryObject = new MessageQueueFactoryObject(); - MessageQueue queue = mqFactoryObject.GetObject() as MessageQueue; - Assert.IsNotNull(queue); - Assert.AreEqual(string.Empty, queue.Path); - Assert.AreEqual(false, queue.DenySharedReceive); - Assert.AreEqual(QueueAccessMode.SendAndReceive, queue.AccessMode); - //EnableCache property not on queue. - } + MessageQueueFactoryObject mqFactoryObject = new MessageQueueFactoryObject(); + MessageQueue queue = mqFactoryObject.GetObject() as MessageQueue; + Assert.IsNotNull(queue); + Assert.AreEqual(string.Empty, queue.Path); + Assert.AreEqual(false, queue.DenySharedReceive); + Assert.AreEqual(QueueAccessMode.SendAndReceive, queue.AccessMode); + //EnableCache property not on queue. + } - [Test] - public void CheckSimpleProperties() - { - MessageQueueFactoryObject mqFactoryObject = (MessageQueueFactoryObject) applicationContext["&testqueue"]; - Assert.AreEqual(@".\Private$\testqueue", mqFactoryObject.Path); - Assert.AreEqual(true, mqFactoryObject.DenySharedReceive); - Assert.AreEqual(QueueAccessMode.Receive, mqFactoryObject.AccessMode); - Assert.AreEqual(true, mqFactoryObject.EnableCache); - MessageQueue mq = (MessageQueue) applicationContext["testqueue"]; - Assert.AreEqual("MyLabel", mq.Label); - } + [Test] + public void CheckSimpleProperties() + { + MessageQueueFactoryObject mqFactoryObject = (MessageQueueFactoryObject) applicationContext["&testqueue"]; + Assert.AreEqual(@".\Private$\testqueue", mqFactoryObject.Path); + Assert.AreEqual(true, mqFactoryObject.DenySharedReceive); + Assert.AreEqual(QueueAccessMode.Receive, mqFactoryObject.AccessMode); + Assert.AreEqual(true, mqFactoryObject.EnableCache); + MessageQueue mq = (MessageQueue) applicationContext["testqueue"]; + Assert.AreEqual("MyLabel", mq.Label); + } + [Test] + public void CheckGetObjectReturnsNewInstance() + { + MessageQueueFactoryObject mqFactoryObject = new MessageQueueFactoryObject(); + MessageQueue queue = mqFactoryObject.GetObject() as MessageQueue; + MessageQueue anotherQueue = mqFactoryObject.GetObject() as MessageQueue; + Assert.IsFalse(queue == anotherQueue, "Should be returning new instances"); + Assert.IsFalse(mqFactoryObject.IsSingleton, + "The MessageQueueFactoryObject class must be configured to return shared instances."); + } - [Test] - public void CheckGetObjectReturnsNewInstance() - { - MessageQueueFactoryObject mqFactoryObject = new MessageQueueFactoryObject(); - MessageQueue queue = mqFactoryObject.GetObject() as MessageQueue; - MessageQueue anotherQueue = mqFactoryObject.GetObject() as MessageQueue; - Assert.IsFalse(queue == anotherQueue, "Should be returning new instances"); - Assert.IsFalse(mqFactoryObject.IsSingleton, - "The MessageQueueFactoryObject class must be configured to return shared instances."); - } + [Test] + public void ObjectTypePropertyYieldsTheCorrectType() + { + MessageQueueFactoryObject mqFactoryObject = new MessageQueueFactoryObject(); + Assert.AreEqual(typeof(MessageQueue), mqFactoryObject.ObjectType, + "The MessageQueueFactoryObject class ain't giving back DefaultMessageQueue types (it must)."); + } - [Test] - public void ObjectTypePropertyYieldsTheCorrectType() - { - MessageQueueFactoryObject mqFactoryObject = new MessageQueueFactoryObject(); - Assert.AreEqual(typeof (MessageQueue), mqFactoryObject.ObjectType, - "The MessageQueueFactoryObject class ain't giving back DefaultMessageQueue types (it must)."); - } - - protected override string[] ConfigLocations - { - get { return new string[] {"assembly://Spring.Messaging.Tests/Spring.Messaging/queue-context.xml"}; } - } + protected override string[] ConfigLocations + { + get { return new string[] { "assembly://Spring.Messaging.Tests/Spring.Messaging/queue-context.xml" }; } } } \ No newline at end of file diff --git a/test/Spring/Spring.Messaging.Tests/Messaging/queue-context.xml b/test/Spring/Spring.Messaging.Tests/Messaging/queue-context.xml index 85497d65..79082f15 100644 --- a/test/Spring/Spring.Messaging.Tests/Messaging/queue-context.xml +++ b/test/Spring/Spring.Messaging.Tests/Messaging/queue-context.xml @@ -2,16 +2,16 @@ - - - - - - - - - - - - + + + + + + + + + + + + \ No newline at end of file diff --git a/test/Spring/Spring.Messaging.Tests/MessagingCompilerOptionsTests.cs b/test/Spring/Spring.Messaging.Tests/MessagingCompilerOptionsTests.cs index 502f969c..89b68636 100644 --- a/test/Spring/Spring.Messaging.Tests/MessagingCompilerOptionsTests.cs +++ b/test/Spring/Spring.Messaging.Tests/MessagingCompilerOptionsTests.cs @@ -26,18 +26,17 @@ using Spring.Messaging; #endregion -namespace Spring +namespace Spring; + +/// Test that the Messaging assembly is built with the correct DebugAttributes in release and debug builds. +/// +/// Mark Pollack +[TestFixture] +public sealed class MessagingCompilerOptionTests : CompilerOptionsTests { - /// Test that the Messaging assembly is built with the correct DebugAttributes in release and debug builds. - /// - /// Mark Pollack - [TestFixture] - public sealed class MessagingCompilerOptionTests : CompilerOptionsTests + [OneTimeSetUp] + public void FixtureSetUp() { - [OneTimeSetUp] - public void FixtureSetUp() - { - AssemblyToCheck = Assembly.GetAssembly(typeof (MessagingException)); - } + AssemblyToCheck = Assembly.GetAssembly(typeof(MessagingException)); } } \ No newline at end of file diff --git a/test/Spring/Spring.Messaging.Tests/MessagingExceptionTests.cs b/test/Spring/Spring.Messaging.Tests/MessagingExceptionTests.cs index b1f0cea9..92c0cc88 100644 --- a/test/Spring/Spring.Messaging.Tests/MessagingExceptionTests.cs +++ b/test/Spring/Spring.Messaging.Tests/MessagingExceptionTests.cs @@ -21,25 +21,23 @@ #region Imports using System.Reflection; - using NUnit.Framework; using Spring.Messaging; #endregion -namespace Spring +namespace Spring; + +/// +/// Unit tests for all of the exception classes in the Spring.Data library... +/// +/// Rick Evans +[TestFixture] +public sealed class MessagingExceptionTests : ExceptionsTest { - /// - /// Unit tests for all of the exception classes in the Spring.Data library... - /// - /// Rick Evans - [TestFixture] - public sealed class MessagingExceptionTests : ExceptionsTest + [OneTimeSetUp] + public void FixtureSetUp() { - [OneTimeSetUp] - public void FixtureSetUp () - { - AssemblyToCheck = Assembly.GetAssembly(typeof(MessagingException)); - } + AssemblyToCheck = Assembly.GetAssembly(typeof(MessagingException)); } } diff --git a/test/Spring/Spring.Scheduling.Quartz3.Integration.Tests/App.config b/test/Spring/Spring.Scheduling.Quartz3.Integration.Tests/App.config index 86f47619..bd8b6fbf 100644 --- a/test/Spring/Spring.Scheduling.Quartz3.Integration.Tests/App.config +++ b/test/Spring/Spring.Scheduling.Quartz3.Integration.Tests/App.config @@ -1,40 +1,40 @@ - - -
- - -
-
-
-
- - + + +
+ + +
+
+
+
+ + - - + + - - - + + + - - + + - - - - - - - + + + + + + + - - - + + + \ No newline at end of file diff --git a/test/Spring/Spring.Scheduling.Quartz3.Integration.Tests/Scheduling/Quartz/LocalDataSourceJobStoreTest.cs b/test/Spring/Spring.Scheduling.Quartz3.Integration.Tests/Scheduling/Quartz/LocalDataSourceJobStoreTest.cs index 8f3c6712..cda8c3b9 100644 --- a/test/Spring/Spring.Scheduling.Quartz3.Integration.Tests/Scheduling/Quartz/LocalDataSourceJobStoreTest.cs +++ b/test/Spring/Spring.Scheduling.Quartz3.Integration.Tests/Scheduling/Quartz/LocalDataSourceJobStoreTest.cs @@ -26,26 +26,25 @@ using Spring.Context.Support; #endregion -namespace Spring.Scheduling.Quartz.Integration.Tests +namespace Spring.Scheduling.Quartz.Integration.Tests; + +[TestFixture] +public class LocalDataSourceJobStoreTest { - [TestFixture] - public class LocalDataSourceJobStoreTest + private IApplicationContext ctx; + + [SetUp] + public void SetUp() { - private IApplicationContext ctx; + ctx = new XmlApplicationContext( + "assembly://Spring.Scheduling.Quartz3.Integration.Tests/Spring.Scheduling.Quartz/LocalDataSourceJobStoreTest.xml"); + } - [SetUp] - public void SetUp() - { - ctx = new XmlApplicationContext( - "assembly://Spring.Scheduling.Quartz3.Integration.Tests/Spring.Scheduling.Quartz/LocalDataSourceJobStoreTest.xml"); - } - - [Test] - [Explicit("Appveyor problems")] - public void TestLocalDataSourceJobStore() - { - // sleep 20 seconds - Thread.Sleep(20000); - } + [Test] + [Explicit("Appveyor problems")] + public void TestLocalDataSourceJobStore() + { + // sleep 20 seconds + Thread.Sleep(20000); } } diff --git a/test/Spring/Spring.Scheduling.Quartz3.Integration.Tests/Scheduling/Quartz/LocalDataSourceJobStoreTest.xml b/test/Spring/Spring.Scheduling.Quartz3.Integration.Tests/Scheduling/Quartz/LocalDataSourceJobStoreTest.xml index de7bd6be..db5a8005 100644 --- a/test/Spring/Spring.Scheduling.Quartz3.Integration.Tests/Scheduling/Quartz/LocalDataSourceJobStoreTest.xml +++ b/test/Spring/Spring.Scheduling.Quartz3.Integration.Tests/Scheduling/Quartz/LocalDataSourceJobStoreTest.xml @@ -6,60 +6,63 @@ xmlns:tx="http://www.springframework.net/tx"> - + - - - + + + - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + - - - - - - - - + + + + + + + + \ No newline at end of file diff --git a/test/Spring/Spring.Scheduling.Quartz3.Integration.Tests/Scheduling/Quartz/TestJob.cs b/test/Spring/Spring.Scheduling.Quartz3.Integration.Tests/Scheduling/Quartz/TestJob.cs index 80409598..3896b33a 100644 --- a/test/Spring/Spring.Scheduling.Quartz3.Integration.Tests/Scheduling/Quartz/TestJob.cs +++ b/test/Spring/Spring.Scheduling.Quartz3.Integration.Tests/Scheduling/Quartz/TestJob.cs @@ -1,19 +1,17 @@ using Quartz; -namespace Spring.Scheduling.Quartz.Integration.Tests +namespace Spring.Scheduling.Quartz.Integration.Tests; + +public class TestJob : IJob { - public class TestJob : IJob + public Task Execute(IJobExecutionContext context) { - public Task Execute(IJobExecutionContext context) - { - Console.WriteLine("Executing Execute!"); - return Task.FromResult(true); - } - - public void DoIt() - { - Console.WriteLine("Executing DoIt!"); - } + Console.WriteLine("Executing Execute!"); + return Task.FromResult(true); + } + public void DoIt() + { + Console.WriteLine("Executing DoIt!"); } } diff --git a/test/Spring/Spring.Scheduling.Quartz3.Tests/QuartzCompilerOptionsTests.cs b/test/Spring/Spring.Scheduling.Quartz3.Tests/QuartzCompilerOptionsTests.cs index d81862ff..88e92dda 100644 --- a/test/Spring/Spring.Scheduling.Quartz3.Tests/QuartzCompilerOptionsTests.cs +++ b/test/Spring/Spring.Scheduling.Quartz3.Tests/QuartzCompilerOptionsTests.cs @@ -26,18 +26,17 @@ using Spring.Scheduling.Quartz; #endregion -namespace Spring +namespace Spring; + +/// Test that the assembly is built with the correct DebugAttributes in release and debug builds. +/// +/// Mark Pollack +[TestFixture] +public sealed class QuartzCompilerOptionTests : CompilerOptionsTests { - /// Test that the assembly is built with the correct DebugAttributes in release and debug builds. - /// - /// Mark Pollack - [TestFixture] - public sealed class QuartzCompilerOptionTests : CompilerOptionsTests + [OneTimeSetUp] + public void FixtureSetUp() { - [OneTimeSetUp] - public void FixtureSetUp() - { - AssemblyToCheck = Assembly.GetAssembly(typeof (SchedulingException)); - } + AssemblyToCheck = Assembly.GetAssembly(typeof(SchedulingException)); } -} \ No newline at end of file +} diff --git a/test/Spring/Spring.Scheduling.Quartz3.Tests/Scheduling/Quartz/AdaptableJobFactoryTest.cs b/test/Spring/Spring.Scheduling.Quartz3.Tests/Scheduling/Quartz/AdaptableJobFactoryTest.cs index 5bd4cd7c..812f18a6 100644 --- a/test/Spring/Spring.Scheduling.Quartz3.Tests/Scheduling/Quartz/AdaptableJobFactoryTest.cs +++ b/test/Spring/Spring.Scheduling.Quartz3.Tests/Scheduling/Quartz/AdaptableJobFactoryTest.cs @@ -1,98 +1,96 @@ /* -* Copyright 2002-2010 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. -*/ + * Copyright 2002-2010 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. + */ using NUnit.Framework; - using Quartz; using Quartz.Spi; -namespace Spring.Scheduling.Quartz +namespace Spring.Scheduling.Quartz; + +/// +/// Tests for . +/// +/// Marko Lahma (.NET) +[TestFixture] +public class AdaptableJobFactoryTest { + private AdaptableJobFactory jobFactory; + /// - /// Tests for . + /// Test setup. /// - /// Marko Lahma (.NET) - [TestFixture] - public class AdaptableJobFactoryTest + [SetUp] + public void SetUp() { - private AdaptableJobFactory jobFactory; + jobFactory = new AdaptableJobFactory(); + } - /// - /// Test setup. - /// - [SetUp] - public void SetUp() + /// + /// Tests job creation. + /// + [Test] + public void TestNewJob_IncompatibleJob() + { + try { - jobFactory = new AdaptableJobFactory(); + // this actually fails already in Quartz level + TriggerFiredBundle bundle = TestUtil.CreateMinimalFiredBundleWithTypedJobDetail(typeof(object)); + jobFactory.NewJob(bundle, null); + Assert.Fail("Created job which was not an IJob"); } - - /// - /// Tests job creation. - /// - [Test] - public void TestNewJob_IncompatibleJob() + catch (ArgumentException) { - try - { - // this actually fails already in Quartz level - TriggerFiredBundle bundle = TestUtil.CreateMinimalFiredBundleWithTypedJobDetail(typeof (object)); - jobFactory.NewJob(bundle, null); - Assert.Fail("Created job which was not an IJob"); - } - catch (ArgumentException) - { - // ok - } - catch (SchedulerException) - { - // ok - } - catch (Exception) - { - Assert.Fail("Got exception that was not instance of SchedulerException or ArgumentException"); - } + // ok } - - /// - /// Tests job creation. - /// - [Test] - public void TestNewJob_ThreadStartJob() + catch (SchedulerException) { - // TODO ThreadStart is not the way to go + // ok } - - /// - /// Tests job creation. - /// - [Test] - public void TestNewJob_NormalIJob() + catch (Exception) { - TriggerFiredBundle bundle = TestUtil.CreateMinimalFiredBundleWithTypedJobDetail(typeof (NoOpJob)); - IJob job = jobFactory.NewJob(bundle, null); - - Assert.IsNotNull(job, "Returned job was null"); + Assert.Fail("Got exception that was not instance of SchedulerException or ArgumentException"); } } - internal class NoOpThreadStartJob : NoOpJob + /// + /// Tests job creation. + /// + [Test] + public void TestNewJob_ThreadStartJob() { - public void Execute() - { - Execute(null); - } + // TODO ThreadStart is not the way to go + } + + /// + /// Tests job creation. + /// + [Test] + public void TestNewJob_NormalIJob() + { + TriggerFiredBundle bundle = TestUtil.CreateMinimalFiredBundleWithTypedJobDetail(typeof(NoOpJob)); + IJob job = jobFactory.NewJob(bundle, null); + + Assert.IsNotNull(job, "Returned job was null"); + } +} + +internal class NoOpThreadStartJob : NoOpJob +{ + public void Execute() + { + Execute(null); } } diff --git a/test/Spring/Spring.Scheduling.Quartz3.Tests/Scheduling/Quartz/CronTriggerObjectTest.cs b/test/Spring/Spring.Scheduling.Quartz3.Tests/Scheduling/Quartz/CronTriggerObjectTest.cs index fd18901f..32ada23e 100644 --- a/test/Spring/Spring.Scheduling.Quartz3.Tests/Scheduling/Quartz/CronTriggerObjectTest.cs +++ b/test/Spring/Spring.Scheduling.Quartz3.Tests/Scheduling/Quartz/CronTriggerObjectTest.cs @@ -1,108 +1,104 @@ /* -* Copyright 2002-2010 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. -*/ + * Copyright 2002-2010 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. + */ using System.Collections; using NUnit.Framework; - using Quartz; using Quartz.Impl; -namespace Spring.Scheduling.Quartz +namespace Spring.Scheduling.Quartz; + +/// +/// Tests for . +/// +/// Marko Lahma (.NET) +[TestFixture] +public class CronTriggerObjectTest : TriggerObjectTest { + private CronTriggerObject cronTrigger; + /// - /// Tests for . + /// Test setup. /// - /// Marko Lahma (.NET) - [TestFixture] - public class CronTriggerObjectTest : TriggerObjectTest + [SetUp] + public void SetUp() { - private CronTriggerObject cronTrigger; - - /// - /// Test setup. - /// - [SetUp] - public void SetUp() - { - cronTrigger = new CronTriggerObject(); - cronTrigger.ObjectName = TRIGGER_NAME; - Trigger = cronTrigger; - } - - /// - /// Tests all possible misfire instructions for cron trigger - /// from strings to int. - /// - [Test] - public void TestMisfireInstructionNames() - { - string[] names = new string[] { "DoNothing", "FireOnceNow", "SmartPolicy" }; - foreach (string name in names) - { - cronTrigger.MisfireInstructionName = name; - } - } - - /// - /// Tests that JobDetail defaults values as expected in AfterPropertiesSet. - /// - [Test] - public override void TestAfterPropertiesSet_JobDetailGiven() - { - const string jobName = "jobName"; - const string jobGroup = "jobGroup"; - IJobDetail jd = new JobDetailImpl(jobName, jobGroup, typeof(NoOpJob)); - cronTrigger.JobDetail = jd; - cronTrigger.AfterPropertiesSet(); - base.TestAfterPropertiesSet_JobDetailGiven(); - Assert.AreSame(jd, cronTrigger.JobDetail, "job details weren't same"); - } - - /// - /// Tests that JobDetail maps job data map as expected. - /// - [Test] - public void TestJobDataAsMap() - { - IDictionary data = new Dictionary(); - data["foo"] = "bar"; - data["number"] = 123; - cronTrigger.JobDataAsMap = data; - CollectionAssert.AreEquivalent(data, cronTrigger.JobDataMap, "Data differed"); - } - - /// - /// Tests that StartDelay is respected. - /// - [Test] - public void TestStartDelay() - { - TimeSpan expectedDelay = TimeSpan.FromMinutes(10); - cronTrigger.StartDelay = expectedDelay; - Assert.AreEqual(expectedDelay, cronTrigger.StartDelay); - - cronTrigger.AfterPropertiesSet(); - DateTime now = DateTime.UtcNow; - TimeSpan delay = cronTrigger.StartTimeUtc - now; - - // check roughly - Assert.IsTrue(delay > TimeSpan.FromMinutes(9).Add(TimeSpan.FromSeconds(55))); - Assert.IsTrue(delay < TimeSpan.FromMinutes(10).Add(TimeSpan.FromSeconds(5))); - } - + cronTrigger = new CronTriggerObject(); + cronTrigger.ObjectName = TRIGGER_NAME; + Trigger = cronTrigger; } + /// + /// Tests all possible misfire instructions for cron trigger + /// from strings to int. + /// + [Test] + public void TestMisfireInstructionNames() + { + string[] names = new string[] { "DoNothing", "FireOnceNow", "SmartPolicy" }; + foreach (string name in names) + { + cronTrigger.MisfireInstructionName = name; + } + } + + /// + /// Tests that JobDetail defaults values as expected in AfterPropertiesSet. + /// + [Test] + public override void TestAfterPropertiesSet_JobDetailGiven() + { + const string jobName = "jobName"; + const string jobGroup = "jobGroup"; + IJobDetail jd = new JobDetailImpl(jobName, jobGroup, typeof(NoOpJob)); + cronTrigger.JobDetail = jd; + cronTrigger.AfterPropertiesSet(); + base.TestAfterPropertiesSet_JobDetailGiven(); + Assert.AreSame(jd, cronTrigger.JobDetail, "job details weren't same"); + } + + /// + /// Tests that JobDetail maps job data map as expected. + /// + [Test] + public void TestJobDataAsMap() + { + IDictionary data = new Dictionary(); + data["foo"] = "bar"; + data["number"] = 123; + cronTrigger.JobDataAsMap = data; + CollectionAssert.AreEquivalent(data, cronTrigger.JobDataMap, "Data differed"); + } + + /// + /// Tests that StartDelay is respected. + /// + [Test] + public void TestStartDelay() + { + TimeSpan expectedDelay = TimeSpan.FromMinutes(10); + cronTrigger.StartDelay = expectedDelay; + Assert.AreEqual(expectedDelay, cronTrigger.StartDelay); + + cronTrigger.AfterPropertiesSet(); + DateTime now = DateTime.UtcNow; + TimeSpan delay = cronTrigger.StartTimeUtc - now; + + // check roughly + Assert.IsTrue(delay > TimeSpan.FromMinutes(9).Add(TimeSpan.FromSeconds(55))); + Assert.IsTrue(delay < TimeSpan.FromMinutes(10).Add(TimeSpan.FromSeconds(5))); + } } diff --git a/test/Spring/Spring.Scheduling.Quartz3.Tests/Scheduling/Quartz/JobDetailObjectTest.cs b/test/Spring/Spring.Scheduling.Quartz3.Tests/Scheduling/Quartz/JobDetailObjectTest.cs index 27f739cf..42c02ccb 100644 --- a/test/Spring/Spring.Scheduling.Quartz3.Tests/Scheduling/Quartz/JobDetailObjectTest.cs +++ b/test/Spring/Spring.Scheduling.Quartz3.Tests/Scheduling/Quartz/JobDetailObjectTest.cs @@ -1,159 +1,155 @@ /* -* Copyright 2002-2010 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. -*/ + * Copyright 2002-2010 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. + */ using System.Collections; - using NUnit.Framework; - using Quartz; - using Spring.Context.Support; -namespace Spring.Scheduling.Quartz +namespace Spring.Scheduling.Quartz; + +/// +/// Tests for . +/// +/// Marko Lahma (.NET) +[TestFixture] +public class JobDetailObjectTest { + private JobDetailObject jobDetail; + /// - /// Tests for . + /// Test setup. /// - /// Marko Lahma (.NET) - [TestFixture] - public class JobDetailObjectTest + [SetUp] + public void SetUp() { - private JobDetailObject jobDetail; + jobDetail = new JobDetailObject(); + } - /// - /// Test setup. - /// - [SetUp] - public void SetUp() - { - jobDetail = new JobDetailObject(); - } + /// + /// Tests job detail's property behavior. + /// + [Test] + public void TestJobType_Null() + { + Assert.Throws(() => jobDetail.JobType = null); + } - /// - /// Tests job detail's property behavior. - /// - [Test] - public void TestJobType_Null() - { - Assert.Throws(() => jobDetail.JobType = null); - } + /// + /// Tests job detail's property behavior. + /// + [Test] + public void TestJobType_NonIJob() + { + jobDetail.JobType = typeof(object); + Assert.AreEqual(typeof(object), jobDetail.JobType, "JobDetail did not create same type as expected"); + } - /// - /// Tests job detail's property behavior. - /// - [Test] - public void TestJobType_NonIJob() - { - jobDetail.JobType = typeof(object); - Assert.AreEqual(typeof(object), jobDetail.JobType, "JobDetail did not create same type as expected"); - } + /// + /// Tests job detail's property behavior. + /// + [Test] + public void TestJobType_IJob() + { + Type CORRECT_IJOB = typeof(NoOpJob); + jobDetail.JobType = CORRECT_IJOB; + Assert.AreEqual(jobDetail.JobType, CORRECT_IJOB, "JobDetail did not register correct job type"); + } - /// - /// Tests job detail's property behavior. - /// - [Test] - public void TestJobType_IJob() - { - Type CORRECT_IJOB = typeof(NoOpJob); - jobDetail.JobType = CORRECT_IJOB; - Assert.AreEqual(jobDetail.JobType, CORRECT_IJOB, "JobDetail did not register correct job type"); - } + /// + /// Tests job detail's property behavior. + /// + [Test] + public void TestJobDataAsMap_Null() + { + Assert.Throws(() => jobDetail.JobDataAsMap = null); + } - /// - /// Tests job detail's property behavior. - /// - [Test] - public void TestJobDataAsMap_Null() - { - Assert.Throws(() => jobDetail.JobDataAsMap = null); - } + /// + /// Tests job detail's property behavior. + /// + [Test] + public void TestJobDataAsMap_ProperValues() + { + IDictionary values = new Hashtable(); + values["baz"] = "foo"; + values["foo"] = 123; + values["bar"] = null; + jobDetail.JobDataAsMap = values; + Assert.AreEqual(values.Count, jobDetail.JobDataMap.Count, "Data of inequal size"); + CollectionAssert.AreEquivalent(values.Keys, jobDetail.JobDataMap.Keys, "JobDataMap values not equal"); + } - /// - /// Tests job detail's property behavior. - /// - [Test] - public void TestJobDataAsMap_ProperValues() - { - IDictionary values = new Hashtable(); - values["baz"] = "foo"; - values["foo"] = 123; - values["bar"] = null; - jobDetail.JobDataAsMap = values; - Assert.AreEqual(values.Count, jobDetail.JobDataMap.Count, "Data of inequal size"); - CollectionAssert.AreEquivalent(values.Keys, jobDetail.JobDataMap.Keys, "JobDataMap values not equal"); - } + /// + /// Tests job detail's property behavior. + /// + [Test] + public void TestAfterPropertiesSet_Defaults() + { + const string objectName = "springJobDetailObject"; + jobDetail.ObjectName = objectName; + jobDetail.Group = null; + jobDetail.AfterPropertiesSet(); + Assert.AreEqual(SchedulerConstants.DefaultGroup, jobDetail.Group, "Groups differ"); + Assert.AreEqual(objectName, jobDetail.Name, "Names differ"); + } - /// - /// Tests job detail's property behavior. - /// - [Test] - public void TestAfterPropertiesSet_Defaults() - { - const string objectName = "springJobDetailObject"; - jobDetail.ObjectName = objectName; - jobDetail.Group = null; - jobDetail.AfterPropertiesSet(); - Assert.AreEqual(SchedulerConstants.DefaultGroup, jobDetail.Group, "Groups differ"); - Assert.AreEqual(objectName, jobDetail.Name, "Names differ"); - } + /// + /// Tests job detail's property behavior. + /// + [Test] + public void TestAfterPropertiesSet_CustomNameAndGroup() + { + const string objectName = "springJobDetailObject"; + const string jobDetailName = "jobDetailName"; + const string jobDetailGroup = "jobDetailGroup"; + jobDetail.ObjectName = objectName; + jobDetail.Name = jobDetailName; + jobDetail.Group = jobDetailGroup; + jobDetail.AfterPropertiesSet(); + Assert.AreEqual(jobDetailGroup, jobDetail.Group, "Groups differ"); + Assert.AreEqual(jobDetailName, jobDetail.Name, "Names differ"); + } - /// - /// Tests job detail's property behavior. - /// - [Test] - public void TestAfterPropertiesSet_CustomNameAndGroup() - { - const string objectName = "springJobDetailObject"; - const string jobDetailName = "jobDetailName"; - const string jobDetailGroup = "jobDetailGroup"; - jobDetail.ObjectName = objectName; - jobDetail.Name = jobDetailName; - jobDetail.Group = jobDetailGroup; - jobDetail.AfterPropertiesSet(); - Assert.AreEqual(jobDetailGroup, jobDetail.Group, "Groups differ"); - Assert.AreEqual(jobDetailName, jobDetail.Name, "Names differ"); - } + /// + /// Tests job detail's property behavior. + /// + [Test] + public void TestAfterPropertiesSet_ApplicationContextJobDataKeySetWithApplicationContext() + { + const string objectName = "springJobDetailObject"; + jobDetail.ObjectName = objectName; + StaticApplicationContext ctx = new StaticApplicationContext(); + jobDetail.ApplicationContext = ctx; + string key = "applicationContextJobDataKey"; + jobDetail.ApplicationContextJobDataKey = key; + jobDetail.AfterPropertiesSet(); + Assert.AreSame(ctx, jobDetail.ApplicationContext, "ApplicationContext was not set correctly"); + Assert.AreSame(ctx, jobDetail.JobDataMap[key], "ApplicationContext was not set to job data map"); + } - /// - /// Tests job detail's property behavior. - /// - [Test] - public void TestAfterPropertiesSet_ApplicationContextJobDataKeySetWithApplicationContext() - { - const string objectName = "springJobDetailObject"; - jobDetail.ObjectName = objectName; - StaticApplicationContext ctx = new StaticApplicationContext(); - jobDetail.ApplicationContext = ctx; - string key = "applicationContextJobDataKey"; - jobDetail.ApplicationContextJobDataKey = key; - jobDetail.AfterPropertiesSet(); - Assert.AreSame(ctx, jobDetail.ApplicationContext, "ApplicationContext was not set correctly"); - Assert.AreSame(ctx, jobDetail.JobDataMap[key], "ApplicationContext was not set to job data map"); - } - - /// - /// Tests job detail's property behavior. - /// - [Test] - public void TestAfterPropertiesSet_ApplicationContextJobDataKeySetWithoutApplicationContext() - { - const string objectName = "springJobDetailObject"; - jobDetail.ObjectName = objectName; - jobDetail.ApplicationContextJobDataKey = "applicationContextJobDataKey"; - Assert.Throws(() => jobDetail.AfterPropertiesSet()); - } + /// + /// Tests job detail's property behavior. + /// + [Test] + public void TestAfterPropertiesSet_ApplicationContextJobDataKeySetWithoutApplicationContext() + { + const string objectName = "springJobDetailObject"; + jobDetail.ObjectName = objectName; + jobDetail.ApplicationContextJobDataKey = "applicationContextJobDataKey"; + Assert.Throws(() => jobDetail.AfterPropertiesSet()); } } diff --git a/test/Spring/Spring.Scheduling.Quartz3.Tests/Scheduling/Quartz/MethodInvokingJobDetailFactoryObjectTest.cs b/test/Spring/Spring.Scheduling.Quartz3.Tests/Scheduling/Quartz/MethodInvokingJobDetailFactoryObjectTest.cs index c1ea4acb..f132c79b 100644 --- a/test/Spring/Spring.Scheduling.Quartz3.Tests/Scheduling/Quartz/MethodInvokingJobDetailFactoryObjectTest.cs +++ b/test/Spring/Spring.Scheduling.Quartz3.Tests/Scheduling/Quartz/MethodInvokingJobDetailFactoryObjectTest.cs @@ -1,73 +1,70 @@ /* -* Copyright 2002-2010 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. -*/ + * Copyright 2002-2010 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. + */ using NUnit.Framework; - using Quartz; +namespace Spring.Scheduling.Quartz; -namespace Spring.Scheduling.Quartz +/// +/// Unit tests for MethodInvokingJobDetailFactoryObject. +/// +/// Marko Lahma (.NET) +[TestFixture] +public class MethodInvokingJobDetailFactoryObjectTest { + private const string FACTORY_NAME = "springObjectFactory"; + private MethodInvokingJobDetailFactoryObject factory; + /// - /// Unit tests for MethodInvokingJobDetailFactoryObject. + /// Setup for the test. /// - /// Marko Lahma (.NET) - [TestFixture] - public class MethodInvokingJobDetailFactoryObjectTest + [SetUp] + public void SetUp() { - private const string FACTORY_NAME = "springObjectFactory"; - private MethodInvokingJobDetailFactoryObject factory; + factory = new MethodInvokingJobDetailFactoryObject(); + factory.ObjectName = FACTORY_NAME; + factory.TargetMethod = "Invoke"; + factory.TargetObject = new InvocationCountingJob(); + } - /// - /// Setup for the test. - /// - [SetUp] - public void SetUp() - { - factory = new MethodInvokingJobDetailFactoryObject(); - factory.ObjectName = FACTORY_NAME; - factory.TargetMethod = "Invoke"; - factory.TargetObject = new InvocationCountingJob(); - } + /// + /// Tests JobDetail retrieval and it's set properties. + /// + [Test] + public void TestGetObject_MinimalDefaults() + { + factory.AfterPropertiesSet(); + IJobDetail jd = (IJobDetail) factory.GetObject(); + Assert.IsNotNull(jd, "job detail was null"); + Assert.AreEqual(FACTORY_NAME, jd.Key.Name, "job name did not default to factory name"); + Assert.AreEqual(jd.JobType, typeof(MethodInvokingJob), "factory did not create method invoking job"); + Assert.IsTrue(jd.Durable, "job was not durable"); + } - /// - /// Tests JobDetail retrieval and it's set properties. - /// - [Test] - public void TestGetObject_MinimalDefaults() - { - factory.AfterPropertiesSet(); - IJobDetail jd = (IJobDetail) factory.GetObject(); - Assert.IsNotNull(jd, "job detail was null"); - Assert.AreEqual(FACTORY_NAME, jd.Key.Name, "job name did not default to factory name"); - Assert.AreEqual(jd.JobType, typeof(MethodInvokingJob), "factory did not create method invoking job"); - Assert.IsTrue(jd.Durable, "job was not durable"); - } - - /// - /// Tests JobDetail retrieval and it's set properties. - /// - [Test] - public void TestGetObject_ConcurrentJob() - { - factory.Concurrent = false; - factory.AfterPropertiesSet(); - IJobDetail jd = (IJobDetail)factory.GetObject(); - Assert.IsNotNull(jd, "job detail was null"); - Assert.AreEqual(jd.JobType, typeof(StatefulMethodInvokingJob), "factory did not create stateful method invoking job"); - } + /// + /// Tests JobDetail retrieval and it's set properties. + /// + [Test] + public void TestGetObject_ConcurrentJob() + { + factory.Concurrent = false; + factory.AfterPropertiesSet(); + IJobDetail jd = (IJobDetail) factory.GetObject(); + Assert.IsNotNull(jd, "job detail was null"); + Assert.AreEqual(jd.JobType, typeof(StatefulMethodInvokingJob), "factory did not create stateful method invoking job"); } } diff --git a/test/Spring/Spring.Scheduling.Quartz3.Tests/Scheduling/Quartz/MethodInvokingJobTest.cs b/test/Spring/Spring.Scheduling.Quartz3.Tests/Scheduling/Quartz/MethodInvokingJobTest.cs index cd4b2796..676666ee 100644 --- a/test/Spring/Spring.Scheduling.Quartz3.Tests/Scheduling/Quartz/MethodInvokingJobTest.cs +++ b/test/Spring/Spring.Scheduling.Quartz3.Tests/Scheduling/Quartz/MethodInvokingJobTest.cs @@ -1,210 +1,206 @@ /* -* Copyright 2002-2010 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. -*/ + * Copyright 2002-2010 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. + */ using FakeItEasy; - using NUnit.Framework; - using Quartz; using Quartz.Impl; using Quartz.Impl.Triggers; using Quartz.Spi; - using Spring.Objects.Support; -namespace Spring.Scheduling.Quartz +namespace Spring.Scheduling.Quartz; + +/// +/// Tests for MethodInvokingJob. +/// +/// Marko Lahma (.NET) +[TestFixture] +public class MethodInvokingJobTest { + private MethodInvokingJob methodInvokingJob; + /// - /// Tests for MethodInvokingJob. + /// Test setup. /// - /// Marko Lahma (.NET) - [TestFixture] - public class MethodInvokingJobTest + [SetUp] + public void SetUp() { - private MethodInvokingJob methodInvokingJob; - - /// - /// Test setup. - /// - [SetUp] - public void SetUp() - { - methodInvokingJob = new MethodInvokingJob(); - } - - /// - /// Test method invoke via execute. - /// - [Test] - public void TestMethodInvoker_SetWithNull() - { - Assert.Throws(() => methodInvokingJob.MethodInvoker = null); - } - - /// - /// Test method invoke via execute. - /// - [Test] - public void TestMethodInvocation_NullMethodInvokder() - { - Assert.Throws(() => methodInvokingJob.Execute(CreateMinimalJobExecutionContext())); - } - - /// - /// Test method invoke via execute. - /// - [Test] - public void TestMethodInvoker_MethodSetCorrectly() - { - InvocationCountingJob job = new InvocationCountingJob(); - MethodInvoker mi = new MethodInvoker(); - mi.TargetObject = job; - mi.TargetMethod = "Invoke"; - mi.Prepare(); - methodInvokingJob.MethodInvoker = mi; - methodInvokingJob.Execute(CreateMinimalJobExecutionContext()); - Assert.AreEqual(1, job.CounterValue, "Job was not invoked once"); - } - - /// - /// Test that invocation result is set to execution context (SPRNET-1340). - /// - [Test] - public void TestMethodInvoker_ShouldSetResultToExecutionContext() - { - InvocationCountingJob job = new InvocationCountingJob(); - MethodInvoker mi = new MethodInvoker(); - mi.TargetObject = job; - mi.TargetMethod = "InvokeWithReturnValue"; - mi.Prepare(); - methodInvokingJob.MethodInvoker = mi; - IJobExecutionContext context = CreateMinimalJobExecutionContext(); - methodInvokingJob.Execute(context); - - Assert.AreEqual(InvocationCountingJob.DefaultReturnValue, context.Result, "result value was not set to context"); - } - - /// - /// Test method invoke via execute. - /// - [Test] - public void TestMethodInvoker_MethodSetCorrectlyThrowsException() - { - InvocationCountingJob job = new InvocationCountingJob(); - MethodInvoker mi = new MethodInvoker(); - mi.TargetObject = job; - mi.TargetMethod = "InvokeAndThrowException"; - mi.Prepare(); - methodInvokingJob.MethodInvoker = mi; - try - { - methodInvokingJob.Execute(CreateMinimalJobExecutionContext()); - Assert.Fail("Successful invoke when method threw exception"); - } - catch (JobMethodInvocationFailedException) - { - // ok - } - Assert.AreEqual(1, job.CounterValue, "Job was not invoked once"); - } - - /// - /// Test method invoke via execute. - /// - [Test] - public void TestMethodInvoker_PrivateMethod() - { - InvocationCountingJob job = new InvocationCountingJob(); - MethodInvoker mi = new MethodInvoker(); - mi.TargetObject = job; - mi.TargetMethod = "PrivateMethod"; - mi.Prepare(); - methodInvokingJob.MethodInvoker = mi; - methodInvokingJob.Execute(CreateMinimalJobExecutionContext()); - } - - private static IJobExecutionContext CreateMinimalJobExecutionContext() - { - IScheduler sched = A.Fake(); - IJobExecutionContext ctx = new JobExecutionContextImpl(sched, ConstructMinimalTriggerFiredBundle(), null); - return ctx; - } - - private static TriggerFiredBundle ConstructMinimalTriggerFiredBundle() - { - IJobDetail jd = new JobDetailImpl("jobName", "jobGroup", typeof(NoOpJob)); - IOperableTrigger trigger = new SimpleTriggerImpl("triggerName", "triggerGroup"); - TriggerFiredBundle retValue = new TriggerFiredBundle( - jd, - trigger, - null, - false, - DateTimeOffset.UtcNow, - null, - null, - null); - - return retValue; - } - + methodInvokingJob = new MethodInvokingJob(); } /// - /// Test class for method invoker. + /// Test method invoke via execute. /// - public class InvocationCountingJob + [Test] + public void TestMethodInvoker_SetWithNull() { - private int counter; - internal const string DefaultReturnValue = "return value"; + Assert.Throws(() => methodInvokingJob.MethodInvoker = null); + } - /// - /// Increments method invoke counter. - /// - public void Invoke() + /// + /// Test method invoke via execute. + /// + [Test] + public void TestMethodInvocation_NullMethodInvokder() + { + Assert.Throws(() => methodInvokingJob.Execute(CreateMinimalJobExecutionContext())); + } + + /// + /// Test method invoke via execute. + /// + [Test] + public void TestMethodInvoker_MethodSetCorrectly() + { + InvocationCountingJob job = new InvocationCountingJob(); + MethodInvoker mi = new MethodInvoker(); + mi.TargetObject = job; + mi.TargetMethod = "Invoke"; + mi.Prepare(); + methodInvokingJob.MethodInvoker = mi; + methodInvokingJob.Execute(CreateMinimalJobExecutionContext()); + Assert.AreEqual(1, job.CounterValue, "Job was not invoked once"); + } + + /// + /// Test that invocation result is set to execution context (SPRNET-1340). + /// + [Test] + public void TestMethodInvoker_ShouldSetResultToExecutionContext() + { + InvocationCountingJob job = new InvocationCountingJob(); + MethodInvoker mi = new MethodInvoker(); + mi.TargetObject = job; + mi.TargetMethod = "InvokeWithReturnValue"; + mi.Prepare(); + methodInvokingJob.MethodInvoker = mi; + IJobExecutionContext context = CreateMinimalJobExecutionContext(); + methodInvokingJob.Execute(context); + + Assert.AreEqual(InvocationCountingJob.DefaultReturnValue, context.Result, "result value was not set to context"); + } + + /// + /// Test method invoke via execute. + /// + [Test] + public void TestMethodInvoker_MethodSetCorrectlyThrowsException() + { + InvocationCountingJob job = new InvocationCountingJob(); + MethodInvoker mi = new MethodInvoker(); + mi.TargetObject = job; + mi.TargetMethod = "InvokeAndThrowException"; + mi.Prepare(); + methodInvokingJob.MethodInvoker = mi; + try { - Interlocked.Increment(ref counter); + methodInvokingJob.Execute(CreateMinimalJobExecutionContext()); + Assert.Fail("Successful invoke when method threw exception"); + } + catch (JobMethodInvocationFailedException) + { + // ok } - /// - /// Throws exception after incrementing counter. - /// - public void InvokeAndThrowException() - { - Interlocked.Increment(ref counter); - throw new Exception(); - } + Assert.AreEqual(1, job.CounterValue, "Job was not invoked once"); + } - private void PrivateMethod() - { - } + /// + /// Test method invoke via execute. + /// + [Test] + public void TestMethodInvoker_PrivateMethod() + { + InvocationCountingJob job = new InvocationCountingJob(); + MethodInvoker mi = new MethodInvoker(); + mi.TargetObject = job; + mi.TargetMethod = "PrivateMethod"; + mi.Prepare(); + methodInvokingJob.MethodInvoker = mi; + methodInvokingJob.Execute(CreateMinimalJobExecutionContext()); + } - /// - /// Returns as return value. - /// - public string InvokeWithReturnValue() - { - return DefaultReturnValue; - } + private static IJobExecutionContext CreateMinimalJobExecutionContext() + { + IScheduler sched = A.Fake(); + IJobExecutionContext ctx = new JobExecutionContextImpl(sched, ConstructMinimalTriggerFiredBundle(), null); + return ctx; + } - /// - /// Invocation count. - /// - public int CounterValue - { - get { return counter; } - } + private static TriggerFiredBundle ConstructMinimalTriggerFiredBundle() + { + IJobDetail jd = new JobDetailImpl("jobName", "jobGroup", typeof(NoOpJob)); + IOperableTrigger trigger = new SimpleTriggerImpl("triggerName", "triggerGroup"); + TriggerFiredBundle retValue = new TriggerFiredBundle( + jd, + trigger, + null, + false, + DateTimeOffset.UtcNow, + null, + null, + null); + + return retValue; + } +} + +/// +/// Test class for method invoker. +/// +public class InvocationCountingJob +{ + private int counter; + internal const string DefaultReturnValue = "return value"; + + /// + /// Increments method invoke counter. + /// + public void Invoke() + { + Interlocked.Increment(ref counter); + } + + /// + /// Throws exception after incrementing counter. + /// + public void InvokeAndThrowException() + { + Interlocked.Increment(ref counter); + throw new Exception(); + } + + private void PrivateMethod() + { + } + + /// + /// Returns as return value. + /// + public string InvokeWithReturnValue() + { + return DefaultReturnValue; + } + + /// + /// Invocation count. + /// + public int CounterValue + { + get { return counter; } } } diff --git a/test/Spring/Spring.Scheduling.Quartz3.Tests/Scheduling/Quartz/QuartzSupportTests.cs b/test/Spring/Spring.Scheduling.Quartz3.Tests/Scheduling/Quartz/QuartzSupportTests.cs index 7d9ab092..2c2894d3 100644 --- a/test/Spring/Spring.Scheduling.Quartz3.Tests/Scheduling/Quartz/QuartzSupportTests.cs +++ b/test/Spring/Spring.Scheduling.Quartz3.Tests/Scheduling/Quartz/QuartzSupportTests.cs @@ -16,1001 +16,946 @@ using System.Collections; using FakeItEasy; - using NUnit.Framework; - using Quartz; using Quartz.Impl; using Quartz.Impl.Triggers; using Quartz.Spi; - using Spring.Context.Support; using Spring.Objects; using Spring.Objects.Factory.Support; -namespace Spring.Scheduling.Quartz +namespace Spring.Scheduling.Quartz; + +/// +/// +/// Juergen Hoeller +/// Alef Arendsen +/// Rob Harrop +/// Marko Lahma (.NET) +[TestFixture] +public class QuartzSupportTests { /// + /// Executes parametrized test. /// - /// Juergen Hoeller - /// Alef Arendsen - /// Rob Harrop - /// Marko Lahma (.NET) - [TestFixture] - public class QuartzSupportTests + [Test] + public async Task TestSchedulerFactoryObject() { - /// - /// Executes parametrized test. - /// - [Test] - public async Task TestSchedulerFactoryObject() + await DoTestSchedulerFactoryObject(false, false); + } + + /// + /// Executes parametrized test. + /// + [Test] + public async Task TestSchedulerFactoryObjectWithExplicitJobDetail() + { + await DoTestSchedulerFactoryObject(true, false); + } + + /// + /// Executes parametrized test. + /// + [Test] + [Ignore("Requires change to MethodInvoker for overriding target object and type")] + public async Task TestSchedulerFactoryObjectWithPrototypeJob() + { + await DoTestSchedulerFactoryObject(false, true); + } + + private async Task DoTestSchedulerFactoryObject(bool explicitJobDetail, bool prototypeJob) + { + TestObject tb = new TestObject("tb", 99); + JobDetailObject jobDetail0 = new JobDetailObject(); + jobDetail0.JobType = typeof(IJob); + jobDetail0.ObjectName = "myJob0"; + IDictionary jobData = new Hashtable(); + jobData.Add("testObject", tb); + jobDetail0.JobDataAsMap = jobData; + jobDetail0.AfterPropertiesSet(); + Assert.AreEqual(tb, jobDetail0.JobDataMap.Get("testObject")); + + CronTriggerObject trigger0 = new CronTriggerObject(); + trigger0.ObjectName = "myTrigger0"; + trigger0.JobDetail = jobDetail0; + trigger0.CronExpressionString = "0/1 * * * * ?"; + trigger0.AfterPropertiesSet(); + + TestMethodInvokingTask task1 = new TestMethodInvokingTask(); + MethodInvokingJobDetailFactoryObject mijdfb = new MethodInvokingJobDetailFactoryObject(); + mijdfb.ObjectName = "myJob1"; + if (prototypeJob) { - await DoTestSchedulerFactoryObject(false, false); + StaticListableObjectFactory objectFactory = new StaticListableObjectFactory(); + objectFactory.AddObject("task", task1); + mijdfb.TargetObjectName = "task"; + mijdfb.ObjectFactory = objectFactory; } - - /// - /// Executes parametrized test. - /// - [Test] - public async Task TestSchedulerFactoryObjectWithExplicitJobDetail() + else { - await DoTestSchedulerFactoryObject(true, false); - } - - /// - /// Executes parametrized test. - /// - [Test] - [Ignore("Requires change to MethodInvoker for overriding target object and type")] - public async Task TestSchedulerFactoryObjectWithPrototypeJob() - { - await DoTestSchedulerFactoryObject(false, true); - } - - private async Task DoTestSchedulerFactoryObject(bool explicitJobDetail, bool prototypeJob) - { - TestObject tb = new TestObject("tb", 99); - JobDetailObject jobDetail0 = new JobDetailObject(); - jobDetail0.JobType = typeof (IJob); - jobDetail0.ObjectName = "myJob0"; - IDictionary jobData = new Hashtable(); - jobData.Add("testObject", tb); - jobDetail0.JobDataAsMap = jobData; - jobDetail0.AfterPropertiesSet(); - Assert.AreEqual(tb, jobDetail0.JobDataMap.Get("testObject")); - - CronTriggerObject trigger0 = new CronTriggerObject(); - trigger0.ObjectName = "myTrigger0"; - trigger0.JobDetail = jobDetail0; - trigger0.CronExpressionString = "0/1 * * * * ?"; - trigger0.AfterPropertiesSet(); - - TestMethodInvokingTask task1 = new TestMethodInvokingTask(); - MethodInvokingJobDetailFactoryObject mijdfb = new MethodInvokingJobDetailFactoryObject(); - mijdfb.ObjectName = "myJob1"; - if (prototypeJob) - { - StaticListableObjectFactory objectFactory = new StaticListableObjectFactory(); - objectFactory.AddObject("task", task1); - mijdfb.TargetObjectName = "task"; - mijdfb.ObjectFactory = objectFactory; - } - else - { - mijdfb.TargetObject = task1; - } - mijdfb.TargetMethod = "doSomething"; - mijdfb.AfterPropertiesSet(); - IJobDetail jobDetail1 = (IJobDetail) mijdfb.GetObject(); - - SimpleTriggerObject trigger1 = new SimpleTriggerObject(); - trigger1.ObjectName = "myTrigger1"; - trigger1.JobDetail = jobDetail1; - trigger1.StartDelay = TimeSpan.FromMilliseconds(0); - trigger1.RepeatInterval = TimeSpan.FromMilliseconds(20); - trigger1.AfterPropertiesSet(); - - IScheduler scheduler = A.Fake(); - - A.CallTo(() => scheduler.Context).Returns(new SchedulerContext()); - A.CallTo(() => scheduler.GetTrigger(A._, A._)).Returns(Task.FromResult(null)); - A.CallTo(() => scheduler.GetJobDetail(A._, A._)).Returns(Task.FromResult(null)); - - SchedulerFactoryObject schedulerFactoryObject = new TestSchedulerFactoryObject(scheduler); - schedulerFactoryObject.JobFactory = null; - IDictionary schedulerContext = new Hashtable(); - schedulerContext.Add("otherTestObject", tb); - schedulerFactoryObject.SchedulerContextAsMap = schedulerContext; - if (explicitJobDetail) - { - schedulerFactoryObject.JobDetails = new IJobDetail[] {jobDetail0}; - } - schedulerFactoryObject.Triggers = new ITrigger[] {trigger0, trigger1}; - try - { - schedulerFactoryObject.AfterPropertiesSet(); - await schedulerFactoryObject.Start(); - } - finally - { - schedulerFactoryObject.Dispose(); - } - - A.CallTo(() => scheduler.ScheduleJob(trigger0, A._)).MustHaveHappened(); - A.CallTo(() => scheduler.ScheduleJob(trigger1, A._)).MustHaveHappened(); - - A.CallTo(() => scheduler.AddJob(jobDetail0, true, true, A._)).MustHaveHappened(); - A.CallTo(() => scheduler.AddJob(jobDetail0, true, true, A._)).MustHaveHappened(); - - A.CallTo(() => scheduler.Start(A._)).MustHaveHappened(); - A.CallTo(() => scheduler.Shutdown(false, A._)).MustHaveHappened(); - } - - /// - /// Executes parametrized test. - /// - [Test] - public async Task TestSchedulerFactoryObjectWithExistingJobs() - { - await DoTestSchedulerFactoryObjectWithExistingJobs(false); - } - - /// - /// Executes parametrized test. - /// - [Test] - public async Task TestSchedulerFactoryObjectWithOverwriteExistingJobs() - { - await DoTestSchedulerFactoryObjectWithExistingJobs(true); - } - - private async Task DoTestSchedulerFactoryObjectWithExistingJobs(bool overwrite) - { - TestObject tb = new TestObject("tb", 99); - JobDetailObject jobDetail0 = new JobDetailObject(); - jobDetail0.JobType = typeof (IJob); - jobDetail0.ObjectName = "myJob0"; - IDictionary jobData = new Hashtable(); - jobData.Add("testObject", tb); - jobDetail0.JobDataAsMap = jobData; - jobDetail0.AfterPropertiesSet(); - Assert.AreEqual(tb, jobDetail0.JobDataMap.Get("testObject")); - - CronTriggerObject trigger0 = new CronTriggerObject(); - trigger0.ObjectName = "myTrigger0"; - trigger0.JobDetail = jobDetail0; - trigger0.CronExpressionString = "0/1 * * * * ?"; - trigger0.AfterPropertiesSet(); - - TestMethodInvokingTask task1 = new TestMethodInvokingTask(); - MethodInvokingJobDetailFactoryObject mijdfb = new MethodInvokingJobDetailFactoryObject(); - mijdfb.ObjectName = "myJob1"; mijdfb.TargetObject = task1; - mijdfb.TargetMethod = "doSomething"; - mijdfb.AfterPropertiesSet(); - IJobDetail jobDetail1 = (IJobDetail) mijdfb.GetObject(); - - SimpleTriggerObject trigger1 = new SimpleTriggerObject(); - trigger1.ObjectName = "myTrigger1"; - trigger1.JobDetail = jobDetail1; - trigger1.StartDelay = TimeSpan.FromMilliseconds(0); - trigger1.RepeatInterval = TimeSpan.FromMilliseconds(20); - trigger1.AfterPropertiesSet(); - - IScheduler scheduler = A.Fake(); - A.CallTo(() => scheduler.Context).Returns(new SchedulerContext()); - A.CallTo(() => scheduler.GetJobDetail(A._, A._)).Returns(Task.FromResult(null)); - A.CallTo(() => scheduler.GetTrigger(new TriggerKey("myTrigger0", SchedulerConstants.DefaultGroup), A._)).Returns(Task.FromResult(null)); - A.CallTo(() => scheduler.GetTrigger(new TriggerKey("myTrigger1", SchedulerConstants.DefaultGroup), A._)).Returns(Task.FromResult(new SimpleTriggerImpl())); - - if (overwrite) - { - A.CallTo(() => scheduler.RescheduleJob(new TriggerKey("myTrigger1", SchedulerConstants.DefaultGroup), trigger1, A._)).Returns(DateTime.UtcNow); - } - - SchedulerFactoryObject schedulerFactoryObject = new TestSchedulerFactoryObject(scheduler); - schedulerFactoryObject.JobFactory = null; - IDictionary schedulerContext = new Hashtable(); - schedulerContext.Add("otherTestObject", tb); - schedulerFactoryObject.SchedulerContextAsMap = schedulerContext; - schedulerFactoryObject.Triggers = new ITrigger[] {trigger0, trigger1}; - if (overwrite) - { - schedulerFactoryObject.OverwriteExistingJobs = true; - } - try - { - schedulerFactoryObject.AfterPropertiesSet(); - await schedulerFactoryObject.Start(); - } - finally - { - schedulerFactoryObject.Dispose(); - } - - A.CallTo(() => scheduler.AddJob(jobDetail0, true, true, A._)).MustHaveHappened(); - A.CallTo(() => scheduler.ScheduleJob(trigger0, A._)).MustHaveHappened(); - A.CallTo(() => scheduler.Start(A._)).MustHaveHappened(); - A.CallTo(() => scheduler.Shutdown(false, A._)).MustHaveHappened(); } - /// - /// Executes parametrized test. - /// - [Test] - public async Task TestSchedulerFactoryObjectWithExistingJobsAndRaceCondition() + mijdfb.TargetMethod = "doSomething"; + mijdfb.AfterPropertiesSet(); + IJobDetail jobDetail1 = (IJobDetail) mijdfb.GetObject(); + + SimpleTriggerObject trigger1 = new SimpleTriggerObject(); + trigger1.ObjectName = "myTrigger1"; + trigger1.JobDetail = jobDetail1; + trigger1.StartDelay = TimeSpan.FromMilliseconds(0); + trigger1.RepeatInterval = TimeSpan.FromMilliseconds(20); + trigger1.AfterPropertiesSet(); + + IScheduler scheduler = A.Fake(); + + A.CallTo(() => scheduler.Context).Returns(new SchedulerContext()); + A.CallTo(() => scheduler.GetTrigger(A._, A._)).Returns(Task.FromResult(null)); + A.CallTo(() => scheduler.GetJobDetail(A._, A._)).Returns(Task.FromResult(null)); + + SchedulerFactoryObject schedulerFactoryObject = new TestSchedulerFactoryObject(scheduler); + schedulerFactoryObject.JobFactory = null; + IDictionary schedulerContext = new Hashtable(); + schedulerContext.Add("otherTestObject", tb); + schedulerFactoryObject.SchedulerContextAsMap = schedulerContext; + if (explicitJobDetail) { - await DoTestSchedulerFactoryObjectWithExistingJobsAndRaceCondition(false); + schedulerFactoryObject.JobDetails = new IJobDetail[] { jobDetail0 }; } - /// - /// Executes parametrized test. - /// - [Test] - public async Task TestSchedulerFactoryObjectWithOverwriteExistingJobsAndRaceCondition() + schedulerFactoryObject.Triggers = new ITrigger[] { trigger0, trigger1 }; + try { - await DoTestSchedulerFactoryObjectWithExistingJobsAndRaceCondition(true); - } - - private async Task DoTestSchedulerFactoryObjectWithExistingJobsAndRaceCondition(bool overwrite) - { - TestObject tb = new TestObject("tb", 99); - JobDetailObject jobDetail0 = new JobDetailObject(); - jobDetail0.JobType = typeof (IJob); - jobDetail0.ObjectName = "myJob0"; - IDictionary jobData = new Hashtable(); - jobData.Add("testObject", tb); - jobDetail0.JobDataAsMap = jobData; - jobDetail0.AfterPropertiesSet(); - Assert.AreEqual(tb, jobDetail0.JobDataMap.Get("testObject")); - - CronTriggerObject trigger0 = new CronTriggerObject(); - trigger0.ObjectName = "myTrigger0"; - trigger0.JobDetail = jobDetail0; - trigger0.CronExpressionString = "0/1 * * * * ?"; - trigger0.AfterPropertiesSet(); - - TestMethodInvokingTask task1 = new TestMethodInvokingTask(); - MethodInvokingJobDetailFactoryObject mijdfb = new MethodInvokingJobDetailFactoryObject(); - mijdfb.ObjectName = "myJob1"; - mijdfb.TargetObject = task1; - mijdfb.TargetMethod = "doSomething"; - mijdfb.AfterPropertiesSet(); - IJobDetail jobDetail1 = (IJobDetail) mijdfb.GetObject(); - - SimpleTriggerObject trigger1 = new SimpleTriggerObject(); - trigger1.ObjectName = "myTrigger1"; - trigger1.JobDetail = jobDetail1; - trigger1.StartDelay = TimeSpan.FromMilliseconds(0); - trigger1.RepeatInterval = TimeSpan.FromMilliseconds(20); - trigger1.AfterPropertiesSet(); - - IScheduler scheduler = A.Fake(); - A.CallTo(() => scheduler.Context).Returns(new SchedulerContext()); - A.CallTo(() => scheduler.GetJobDetail(A._, A._)).Returns(Task.FromResult(null)); - A.CallTo(() => scheduler.GetTrigger(new TriggerKey("myTrigger0", SchedulerConstants.DefaultGroup), A._)).Returns(Task.FromResult(null)); - A.CallTo(() => scheduler.GetTrigger(new TriggerKey("myTrigger1", SchedulerConstants.DefaultGroup), A._)).Returns(Task.FromResult(new SimpleTriggerImpl())); - if (overwrite) - { - await scheduler.AddJob(jobDetail1, true); - A.CallTo(() => scheduler.RescheduleJob(new TriggerKey("myTrigger1", SchedulerConstants.DefaultGroup), trigger1, A._)).Returns(DateTime.UtcNow); - } - - A.CallTo(() => scheduler.ScheduleJob(trigger0, A._)).Throws(new ObjectAlreadyExistsException("")); - - if (overwrite) - { - A.CallTo(() => scheduler.RescheduleJob(new TriggerKey("myTrigger0", SchedulerConstants.DefaultGroup), trigger0, A._)).Returns(DateTime.UtcNow); - } - - await scheduler.Start(); - await scheduler.Shutdown(false); - - SchedulerFactoryObject schedulerFactoryObject = new TestSchedulerFactoryObject(scheduler); - - schedulerFactoryObject.JobFactory = null; - IDictionary schedulerContext = new Hashtable(); - schedulerContext.Add("otherTestObject", tb); - schedulerFactoryObject.SchedulerContextAsMap = schedulerContext; - schedulerFactoryObject.Triggers = new ITrigger[] {trigger0, trigger1}; - if (overwrite) - { - schedulerFactoryObject.OverwriteExistingJobs = true; - } - try - { - schedulerFactoryObject.AfterPropertiesSet(); - await schedulerFactoryObject.Start(); - } - finally - { - schedulerFactoryObject.Dispose(); - } - - A.CallTo(() => scheduler.AddJob(jobDetail0, true, true, A._)).MustHaveHappened(); - - } - - private void MethodInvokingConcurrency(bool concurrent) - { - // Test the concurrency flag. - // Method invoking job with two triggers. - // If the concurrent flag is false, the triggers are NOT allowed - // to interfere with each other. - - TestMethodInvokingTask task1 = new TestMethodInvokingTask(); - MethodInvokingJobDetailFactoryObject mijdfb = new MethodInvokingJobDetailFactoryObject(); - // set the concurrency flag! - mijdfb.Concurrent = concurrent; - mijdfb.ObjectName = "myJob1"; - mijdfb.TargetObject = task1; - mijdfb.TargetMethod = "doWait"; - mijdfb.AfterPropertiesSet(); - IJobDetail jobDetail1 = (IJobDetail) mijdfb.GetObject(); - - SimpleTriggerObject trigger0 = new SimpleTriggerObject(); - trigger0.ObjectName = "myTrigger1"; - trigger0.JobDetail = jobDetail1; - trigger0.StartDelay = TimeSpan.FromMilliseconds(0); - trigger0.RepeatInterval = TimeSpan.FromMilliseconds(1); - trigger0.RepeatCount = 1; - trigger0.AfterPropertiesSet(); - - SimpleTriggerObject trigger1 = new SimpleTriggerObject(); - trigger1.ObjectName = "myTrigger1"; - trigger1.JobDetail = jobDetail1; - trigger1.StartDelay = TimeSpan.FromMilliseconds(1000L); - trigger1.RepeatInterval = TimeSpan.FromMilliseconds(1); - trigger1.RepeatCount = 1; - trigger1.AfterPropertiesSet(); - - SchedulerFactoryObject schedulerFactoryObject = new SchedulerFactoryObject(); - schedulerFactoryObject.JobDetails = new IJobDetail[] {jobDetail1}; - schedulerFactoryObject.Triggers = new ITrigger[] {trigger1, trigger0}; schedulerFactoryObject.AfterPropertiesSet(); - - // ok scheduler is set up... let's wait for like 4 seconds - try - { - Thread.Sleep(4000); - } - catch (ThreadInterruptedException) - { - // fall through - } - - if (concurrent) - { - Assert.AreEqual(2, task1.counter); - task1.Stop(); - // we're done, both jobs have ran, let's call it a day - return; - } - else - { - Assert.AreEqual(1, task1.counter); - task1.Stop(); - // we need to check whether or not the test succeed with non-concurrent jobs - } - - try - { - Thread.Sleep(4000); - } - catch (ThreadInterruptedException) - { - // fall through - } - - task1.Stop(); - Assert.AreEqual(2, task1.counter); - - // Although we're destroying the scheduler, it does seem to keep things in memory: - // When executing both tests (concurrent and non-concurrent), the second test always - // fails. + await schedulerFactoryObject.Start(); + } + finally + { schedulerFactoryObject.Dispose(); } - /// - /// - [Test] - public async Task TestSchedulerFactoryObjectWithPlainQuartzObjects() + A.CallTo(() => scheduler.ScheduleJob(trigger0, A._)).MustHaveHappened(); + A.CallTo(() => scheduler.ScheduleJob(trigger1, A._)).MustHaveHappened(); + + A.CallTo(() => scheduler.AddJob(jobDetail0, true, true, A._)).MustHaveHappened(); + A.CallTo(() => scheduler.AddJob(jobDetail0, true, true, A._)).MustHaveHappened(); + + A.CallTo(() => scheduler.Start(A._)).MustHaveHappened(); + A.CallTo(() => scheduler.Shutdown(false, A._)).MustHaveHappened(); + } + + /// + /// Executes parametrized test. + /// + [Test] + public async Task TestSchedulerFactoryObjectWithExistingJobs() + { + await DoTestSchedulerFactoryObjectWithExistingJobs(false); + } + + /// + /// Executes parametrized test. + /// + [Test] + public async Task TestSchedulerFactoryObjectWithOverwriteExistingJobs() + { + await DoTestSchedulerFactoryObjectWithExistingJobs(true); + } + + private async Task DoTestSchedulerFactoryObjectWithExistingJobs(bool overwrite) + { + TestObject tb = new TestObject("tb", 99); + JobDetailObject jobDetail0 = new JobDetailObject(); + jobDetail0.JobType = typeof(IJob); + jobDetail0.ObjectName = "myJob0"; + IDictionary jobData = new Hashtable(); + jobData.Add("testObject", tb); + jobDetail0.JobDataAsMap = jobData; + jobDetail0.AfterPropertiesSet(); + Assert.AreEqual(tb, jobDetail0.JobDataMap.Get("testObject")); + + CronTriggerObject trigger0 = new CronTriggerObject(); + trigger0.ObjectName = "myTrigger0"; + trigger0.JobDetail = jobDetail0; + trigger0.CronExpressionString = "0/1 * * * * ?"; + trigger0.AfterPropertiesSet(); + + TestMethodInvokingTask task1 = new TestMethodInvokingTask(); + MethodInvokingJobDetailFactoryObject mijdfb = new MethodInvokingJobDetailFactoryObject(); + mijdfb.ObjectName = "myJob1"; + mijdfb.TargetObject = task1; + mijdfb.TargetMethod = "doSomething"; + mijdfb.AfterPropertiesSet(); + IJobDetail jobDetail1 = (IJobDetail) mijdfb.GetObject(); + + SimpleTriggerObject trigger1 = new SimpleTriggerObject(); + trigger1.ObjectName = "myTrigger1"; + trigger1.JobDetail = jobDetail1; + trigger1.StartDelay = TimeSpan.FromMilliseconds(0); + trigger1.RepeatInterval = TimeSpan.FromMilliseconds(20); + trigger1.AfterPropertiesSet(); + + IScheduler scheduler = A.Fake(); + A.CallTo(() => scheduler.Context).Returns(new SchedulerContext()); + A.CallTo(() => scheduler.GetJobDetail(A._, A._)).Returns(Task.FromResult(null)); + A.CallTo(() => scheduler.GetTrigger(new TriggerKey("myTrigger0", SchedulerConstants.DefaultGroup), A._)).Returns(Task.FromResult(null)); + A.CallTo(() => scheduler.GetTrigger(new TriggerKey("myTrigger1", SchedulerConstants.DefaultGroup), A._)).Returns(Task.FromResult(new SimpleTriggerImpl())); + + if (overwrite) { - IJobFactory jobFactory = new AdaptableJobFactory(); - - TestObject tb = new TestObject("tb", 99); - JobDetailImpl jobDetail0 = new JobDetailImpl(); - jobDetail0.JobType = typeof (IJob); - jobDetail0.Name = "myJob0"; - jobDetail0.Group = SchedulerConstants.DefaultGroup; - jobDetail0.JobDataMap.Add("testObject", tb); - Assert.AreEqual(tb, jobDetail0.JobDataMap.Get("testObject")); - - CronTriggerImpl trigger0 = new CronTriggerImpl(); - trigger0.Name = "myTrigger0"; - trigger0.Group = SchedulerConstants.DefaultGroup; - trigger0.JobName = "myJob0"; - trigger0.JobGroup = SchedulerConstants.DefaultGroup; - trigger0.StartTimeUtc = DateTime.UtcNow; - trigger0.CronExpressionString = "0/1 * * * * ?"; - - TestMethodInvokingTask task1 = new TestMethodInvokingTask(); - MethodInvokingJobDetailFactoryObject mijdfb = new MethodInvokingJobDetailFactoryObject(); - mijdfb.Name = "myJob1"; - mijdfb.Group = SchedulerConstants.DefaultGroup; - mijdfb.TargetObject = task1; - mijdfb.TargetMethod = "doSomething"; - mijdfb.AfterPropertiesSet(); - IJobDetail jobDetail1 = (IJobDetail) mijdfb.GetObject(); - - SimpleTriggerImpl trigger1 = new SimpleTriggerImpl(); - trigger1.Name = "myTrigger1"; - trigger1.Group = SchedulerConstants.DefaultGroup; - trigger1.JobName = "myJob1"; - trigger1.JobGroup = SchedulerConstants.DefaultGroup; - trigger1.StartTimeUtc = DateTime.UtcNow; - trigger1.RepeatCount = SimpleTriggerImpl.RepeatIndefinitely; - trigger1.RepeatInterval = TimeSpan.FromMilliseconds(20); - - IScheduler scheduler = A.Fake(); - A.CallTo(() => scheduler.GetTrigger(A._, A._)).Returns(Task.FromResult(null)); - A.CallTo(() => scheduler.GetJobDetail(A._, A._)).Returns(Task.FromResult(null)); - - SchedulerFactoryObject schedulerFactoryObject = new TestSchedulerFactoryObject(scheduler); - - schedulerFactoryObject.JobFactory = jobFactory; - schedulerFactoryObject.JobDetails = new IJobDetail[] {jobDetail0, jobDetail1}; - schedulerFactoryObject.Triggers = new ITrigger[] {trigger0, trigger1}; - try - { - schedulerFactoryObject.AfterPropertiesSet(); - await schedulerFactoryObject.Start(); - } - finally - { - schedulerFactoryObject.Dispose(); - } - - A.CallTo(scheduler) - .Where(x => x.Method.Name.Equals("set_JobFactory")) - .WhenArgumentsMatch(x => x.Get(0) == jobFactory) - .MustHaveHappened(); - - A.CallTo(() => scheduler.AddJob(jobDetail0, true, true, A._)).MustHaveHappened(); - A.CallTo(() => scheduler.AddJob(jobDetail1, true, true, A._)).MustHaveHappened(); - A.CallTo(() => scheduler.GetJobDetail(new JobKey("myJob0", SchedulerConstants.DefaultGroup), A._)).MustHaveHappened(); - A.CallTo(() => scheduler.GetJobDetail(new JobKey("myJob1", SchedulerConstants.DefaultGroup), A._)).MustHaveHappened(); - A.CallTo(() => scheduler.GetTrigger(new TriggerKey("myTrigger0", SchedulerConstants.DefaultGroup), A._)).MustHaveHappened(); - A.CallTo(() => scheduler.GetTrigger(new TriggerKey("myTrigger1", SchedulerConstants.DefaultGroup), A._)).MustHaveHappened(); + A.CallTo(() => scheduler.RescheduleJob(new TriggerKey("myTrigger1", SchedulerConstants.DefaultGroup), trigger1, A._)).Returns(DateTime.UtcNow); } - /// - /// - [Test] - public async Task TestSchedulerFactoryObjectWithApplicationContext() + SchedulerFactoryObject schedulerFactoryObject = new TestSchedulerFactoryObject(scheduler); + schedulerFactoryObject.JobFactory = null; + IDictionary schedulerContext = new Hashtable(); + schedulerContext.Add("otherTestObject", tb); + schedulerFactoryObject.SchedulerContextAsMap = schedulerContext; + schedulerFactoryObject.Triggers = new ITrigger[] { trigger0, trigger1 }; + if (overwrite) { - TestObject tb = new TestObject("tb", 99); - StaticApplicationContext ac = new StaticApplicationContext(); - - IScheduler scheduler = A.Fake(); - SchedulerContext schedulerContext = new SchedulerContext(); - A.CallTo(() => scheduler.Context).Returns(schedulerContext).NumberOfTimes(4); - - SchedulerFactoryObject schedulerFactoryObject = new TestSchedulerFactoryObject(scheduler); - schedulerFactoryObject.JobFactory = null; - IDictionary schedulerContextMap = new Hashtable(); - schedulerContextMap.Add("testObject", tb); - schedulerFactoryObject.SchedulerContextAsMap = schedulerContextMap; - schedulerFactoryObject.ApplicationContext = ac; - schedulerFactoryObject.ApplicationContextSchedulerContextKey = "appCtx"; - try - { - schedulerFactoryObject.AfterPropertiesSet(); - await schedulerFactoryObject.Start(); - IScheduler returnedScheduler = (IScheduler) schedulerFactoryObject.GetObject(); - Assert.AreEqual(tb, returnedScheduler.Context["testObject"]); - Assert.AreEqual(ac, returnedScheduler.Context["appCtx"]); - } - finally - { - schedulerFactoryObject.Dispose(); - } + schedulerFactoryObject.OverwriteExistingJobs = true; } - /// - /// - [Test] - public void TestJobDetailObjectWithApplicationContext() + try { - TestObject tb = new TestObject("tb", 99); - StaticApplicationContext ac = new StaticApplicationContext(); - - JobDetailObject jobDetail = new JobDetailObject(); - jobDetail.JobType = typeof (IJob); - jobDetail.ObjectName = "myJob0"; - IDictionary jobData = new Hashtable(); - jobData.Add("testObject", tb); - jobDetail.JobDataAsMap = jobData; - jobDetail.ApplicationContext = ac; - jobDetail.ApplicationContextJobDataKey = "appCtx"; - jobDetail.AfterPropertiesSet(); - - Assert.AreEqual(tb, jobDetail.JobDataMap.Get("testObject")); - Assert.AreEqual(ac, jobDetail.JobDataMap.Get("appCtx")); + schedulerFactoryObject.AfterPropertiesSet(); + await schedulerFactoryObject.Start(); + } + finally + { + schedulerFactoryObject.Dispose(); } - /// - /// - [Test] - public async Task TestSchedulerWithTaskExecutor() + A.CallTo(() => scheduler.AddJob(jobDetail0, true, true, A._)).MustHaveHappened(); + A.CallTo(() => scheduler.ScheduleJob(trigger0, A._)).MustHaveHappened(); + A.CallTo(() => scheduler.Start(A._)).MustHaveHappened(); + A.CallTo(() => scheduler.Shutdown(false, A._)).MustHaveHappened(); + } + + /// + /// Executes parametrized test. + /// + [Test] + public async Task TestSchedulerFactoryObjectWithExistingJobsAndRaceCondition() + { + await DoTestSchedulerFactoryObjectWithExistingJobsAndRaceCondition(false); + } + + /// + /// Executes parametrized test. + /// + [Test] + public async Task TestSchedulerFactoryObjectWithOverwriteExistingJobsAndRaceCondition() + { + await DoTestSchedulerFactoryObjectWithExistingJobsAndRaceCondition(true); + } + + private async Task DoTestSchedulerFactoryObjectWithExistingJobsAndRaceCondition(bool overwrite) + { + TestObject tb = new TestObject("tb", 99); + JobDetailObject jobDetail0 = new JobDetailObject(); + jobDetail0.JobType = typeof(IJob); + jobDetail0.ObjectName = "myJob0"; + IDictionary jobData = new Hashtable(); + jobData.Add("testObject", tb); + jobDetail0.JobDataAsMap = jobData; + jobDetail0.AfterPropertiesSet(); + Assert.AreEqual(tb, jobDetail0.JobDataMap.Get("testObject")); + + CronTriggerObject trigger0 = new CronTriggerObject(); + trigger0.ObjectName = "myTrigger0"; + trigger0.JobDetail = jobDetail0; + trigger0.CronExpressionString = "0/1 * * * * ?"; + trigger0.AfterPropertiesSet(); + + TestMethodInvokingTask task1 = new TestMethodInvokingTask(); + MethodInvokingJobDetailFactoryObject mijdfb = new MethodInvokingJobDetailFactoryObject(); + mijdfb.ObjectName = "myJob1"; + mijdfb.TargetObject = task1; + mijdfb.TargetMethod = "doSomething"; + mijdfb.AfterPropertiesSet(); + IJobDetail jobDetail1 = (IJobDetail) mijdfb.GetObject(); + + SimpleTriggerObject trigger1 = new SimpleTriggerObject(); + trigger1.ObjectName = "myTrigger1"; + trigger1.JobDetail = jobDetail1; + trigger1.StartDelay = TimeSpan.FromMilliseconds(0); + trigger1.RepeatInterval = TimeSpan.FromMilliseconds(20); + trigger1.AfterPropertiesSet(); + + IScheduler scheduler = A.Fake(); + A.CallTo(() => scheduler.Context).Returns(new SchedulerContext()); + A.CallTo(() => scheduler.GetJobDetail(A._, A._)).Returns(Task.FromResult(null)); + A.CallTo(() => scheduler.GetTrigger(new TriggerKey("myTrigger0", SchedulerConstants.DefaultGroup), A._)).Returns(Task.FromResult(null)); + A.CallTo(() => scheduler.GetTrigger(new TriggerKey("myTrigger1", SchedulerConstants.DefaultGroup), A._)).Returns(Task.FromResult(new SimpleTriggerImpl())); + if (overwrite) { - CountingTaskExecutor taskExecutor = new CountingTaskExecutor(); - DummyJob.count = 0; - - JobDetailImpl jobDetail = new JobDetailImpl(); - jobDetail.JobType = typeof (DummyJob); - jobDetail.Name = "myJob"; - - SimpleTriggerObject trigger = new SimpleTriggerObject(); - trigger.Name = "myTrigger"; - trigger.JobDetail = jobDetail; - trigger.StartDelay = TimeSpan.FromMilliseconds(1); - trigger.RepeatInterval = TimeSpan.FromMilliseconds(500); - trigger.RepeatCount = 1; - trigger.AfterPropertiesSet(); - - SchedulerFactoryObject factoryObject = new SchedulerFactoryObject(); - factoryObject.TaskExecutor = taskExecutor; - factoryObject.Triggers = new ITrigger[] {trigger}; - factoryObject.JobDetails = new IJobDetail[] {jobDetail}; - factoryObject.AfterPropertiesSet(); - await factoryObject.Start(); - - await Task.Delay(TimeSpan.FromSeconds(1)); - Assert.IsTrue(DummyJob.count > 0); - Assert.AreEqual(DummyJob.count, taskExecutor.count); - - factoryObject.Dispose(); + await scheduler.AddJob(jobDetail1, true); + A.CallTo(() => scheduler.RescheduleJob(new TriggerKey("myTrigger1", SchedulerConstants.DefaultGroup), trigger1, A._)).Returns(DateTime.UtcNow); } - /// - /// - [Test] - public async Task TestSchedulerWithRunnable() + A.CallTo(() => scheduler.ScheduleJob(trigger0, A._)).Throws(new ObjectAlreadyExistsException("")); + + if (overwrite) { - DummyRunnable.count = 0; - - JobDetailImpl jobDetail = new JobDetailObject(); - jobDetail.JobType = typeof (DummyRunnable); - jobDetail.Name = "myJob"; - - SimpleTriggerObject trigger = new SimpleTriggerObject(); - trigger.Name = "myTrigger"; - trigger.JobDetail = jobDetail; - trigger.StartDelay = TimeSpan.FromMilliseconds(1); - trigger.RepeatInterval = TimeSpan.FromMilliseconds(500); - trigger.RepeatCount = 1; - trigger.AfterPropertiesSet(); - - SchedulerFactoryObject factoryObject = new SchedulerFactoryObject(); - factoryObject.Triggers = new ITrigger[] {trigger}; - factoryObject.JobDetails = new IJobDetail[] {jobDetail}; - factoryObject.AfterPropertiesSet(); - await factoryObject.Start(); - - DummyRunnable.runEvent.WaitOne(TimeSpan.FromSeconds(5)); - Assert.IsTrue(DummyRunnable.count > 0); - - factoryObject.Dispose(); + A.CallTo(() => scheduler.RescheduleJob(new TriggerKey("myTrigger0", SchedulerConstants.DefaultGroup), trigger0, A._)).Returns(DateTime.UtcNow); } - /// - /// - [Test] - public async Task TestSchedulerWithQuartzJobObject() + await scheduler.Start(); + await scheduler.Shutdown(false); + + SchedulerFactoryObject schedulerFactoryObject = new TestSchedulerFactoryObject(scheduler); + + schedulerFactoryObject.JobFactory = null; + IDictionary schedulerContext = new Hashtable(); + schedulerContext.Add("otherTestObject", tb); + schedulerFactoryObject.SchedulerContextAsMap = schedulerContext; + schedulerFactoryObject.Triggers = new ITrigger[] { trigger0, trigger1 }; + if (overwrite) { - DummyJob.param = 0; - DummyJob.count = 0; - - JobDetailImpl jobDetail = new JobDetailImpl(); - jobDetail.JobType = typeof (DummyJobObject); - jobDetail.Name = "myJob"; - jobDetail.JobDataMap.Put("param", "10"); - - SimpleTriggerObject trigger = new SimpleTriggerObject(); - trigger.Name = "myTrigger"; - trigger.JobDetail = jobDetail; - trigger.StartDelay = TimeSpan.FromMilliseconds(1); - trigger.RepeatInterval = TimeSpan.FromMilliseconds(500); - trigger.RepeatCount = 1; - trigger.AfterPropertiesSet(); - - SchedulerFactoryObject factoryObject = new SchedulerFactoryObject(); - factoryObject.Triggers = new ITrigger[] {trigger}; - factoryObject.JobDetails = new IJobDetail[] {jobDetail}; - factoryObject.AfterPropertiesSet(); - await factoryObject.Start(); - - await Task.Delay(TimeSpan.FromSeconds(1)); - Assert.AreEqual(10, DummyJobObject.param); - Assert.IsTrue(DummyJobObject.count > 0); - - factoryObject.Dispose(); + schedulerFactoryObject.OverwriteExistingJobs = true; } - /// - /// - [Test] - public async Task TestSchedulerWithSpringObjectJobFactory() + try { - DummyJob.param = 0; - DummyJob.count = 0; - - JobDetailImpl jobDetail = new JobDetailImpl(); - jobDetail.JobType = typeof(DummyJob); - jobDetail.Name = "myJob"; - jobDetail.JobDataMap.Add("param", "10"); - jobDetail.JobDataMap.Add("ignoredParam", "10"); - - SimpleTriggerObject trigger = new SimpleTriggerObject(); - trigger.Name = "myTrigger"; - trigger.JobDetail = jobDetail; - trigger.StartDelay = TimeSpan.FromMilliseconds(1); - trigger.RepeatInterval = TimeSpan.FromMilliseconds(500); - trigger.RepeatCount = 1; - trigger.AfterPropertiesSet(); - - SchedulerFactoryObject factoryObject = new SchedulerFactoryObject(); - factoryObject.JobFactory = new SpringObjectJobFactory(); - factoryObject.Triggers = new ITrigger[] {trigger}; - factoryObject.JobDetails = new IJobDetail[] {jobDetail}; - factoryObject.AfterPropertiesSet(); - await factoryObject.Start(); - - await Task.Delay(TimeSpan.FromSeconds(1)); - Assert.AreEqual(10, DummyJob.param); - Assert.IsTrue(DummyJob.count > 0); - - factoryObject.Dispose(); + schedulerFactoryObject.AfterPropertiesSet(); + await schedulerFactoryObject.Start(); + } + finally + { + schedulerFactoryObject.Dispose(); } - /// - /// - [Test] - public async Task TestSchedulerWithSpringObjectJobFactoryAndParamMismatchNotIgnored() + A.CallTo(() => scheduler.AddJob(jobDetail0, true, true, A._)).MustHaveHappened(); + } + + private void MethodInvokingConcurrency(bool concurrent) + { + // Test the concurrency flag. + // Method invoking job with two triggers. + // If the concurrent flag is false, the triggers are NOT allowed + // to interfere with each other. + + TestMethodInvokingTask task1 = new TestMethodInvokingTask(); + MethodInvokingJobDetailFactoryObject mijdfb = new MethodInvokingJobDetailFactoryObject(); + // set the concurrency flag! + mijdfb.Concurrent = concurrent; + mijdfb.ObjectName = "myJob1"; + mijdfb.TargetObject = task1; + mijdfb.TargetMethod = "doWait"; + mijdfb.AfterPropertiesSet(); + IJobDetail jobDetail1 = (IJobDetail) mijdfb.GetObject(); + + SimpleTriggerObject trigger0 = new SimpleTriggerObject(); + trigger0.ObjectName = "myTrigger1"; + trigger0.JobDetail = jobDetail1; + trigger0.StartDelay = TimeSpan.FromMilliseconds(0); + trigger0.RepeatInterval = TimeSpan.FromMilliseconds(1); + trigger0.RepeatCount = 1; + trigger0.AfterPropertiesSet(); + + SimpleTriggerObject trigger1 = new SimpleTriggerObject(); + trigger1.ObjectName = "myTrigger1"; + trigger1.JobDetail = jobDetail1; + trigger1.StartDelay = TimeSpan.FromMilliseconds(1000L); + trigger1.RepeatInterval = TimeSpan.FromMilliseconds(1); + trigger1.RepeatCount = 1; + trigger1.AfterPropertiesSet(); + + SchedulerFactoryObject schedulerFactoryObject = new SchedulerFactoryObject(); + schedulerFactoryObject.JobDetails = new IJobDetail[] { jobDetail1 }; + schedulerFactoryObject.Triggers = new ITrigger[] { trigger1, trigger0 }; + schedulerFactoryObject.AfterPropertiesSet(); + + // ok scheduler is set up... let's wait for like 4 seconds + try { - DummyJob.param = 0; - DummyJob.count = 0; - - JobDetailImpl jobDetail = new JobDetailImpl(); - jobDetail.JobType = typeof(DummyJob); - jobDetail.Name = "myJob"; - jobDetail.JobDataMap.Add("para", "10"); - jobDetail.JobDataMap.Add("ignoredParam", "10"); - - SimpleTriggerObject trigger = new SimpleTriggerObject(); - trigger.Name = "myTrigger"; - trigger.JobDetail = jobDetail; - trigger.StartDelay = TimeSpan.FromMilliseconds(1); - trigger.RepeatInterval = TimeSpan.FromMilliseconds(500); - trigger.RepeatCount = 1; - trigger.AfterPropertiesSet(); - - SchedulerFactoryObject bean = new SchedulerFactoryObject(); - SpringObjectJobFactory jobFactory = new SpringObjectJobFactory(); - jobFactory.IgnoredUnknownProperties = new String[] {"ignoredParam"}; - bean.JobFactory = jobFactory; - bean.Triggers = new ITrigger[] {trigger}; - bean.JobDetails = new IJobDetail[] {jobDetail}; - bean.AfterPropertiesSet(); - - await Task.Delay(TimeSpan.FromSeconds(1)); - Assert.AreEqual(0, DummyJob.param); - Assert.IsTrue(DummyJob.count == 0); - - bean.Dispose(); + Thread.Sleep(4000); + } + catch (ThreadInterruptedException) + { + // fall through } - /// - /// - [Test] - public async Task TestSchedulerWithSpringObjectJobFactoryAndRunnable() + if (concurrent) { - DummyRunnable.param = 0; - DummyRunnable.count = 0; - - JobDetailObject jobDetail = new JobDetailObject(); - jobDetail.JobType = typeof (DummyRunnable); - jobDetail.Name = "myJob"; - jobDetail.JobDataMap.Add("param", "10"); - - SimpleTriggerObject trigger = new SimpleTriggerObject(); - trigger.Name = "myTrigger"; - trigger.JobDetail = jobDetail; - trigger.StartDelay = TimeSpan.FromMilliseconds(1); - trigger.RepeatInterval = TimeSpan.FromMilliseconds(500); - trigger.RepeatCount = 1; - trigger.AfterPropertiesSet(); - - SchedulerFactoryObject factoryObject = new SchedulerFactoryObject(); - factoryObject.JobFactory = new SpringObjectJobFactory(); - factoryObject.Triggers = new ITrigger[] {trigger}; - factoryObject.JobDetails = new IJobDetail[] {jobDetail}; - factoryObject.AfterPropertiesSet(); - await factoryObject.Start(); - - await Task.Delay(TimeSpan.FromSeconds(1)); - Assert.AreEqual(10, DummyRunnable.param); - Assert.IsTrue(DummyRunnable.count > 0); - - factoryObject.Dispose(); + Assert.AreEqual(2, task1.counter); + task1.Stop(); + // we're done, both jobs have ran, let's call it a day + return; + } + else + { + Assert.AreEqual(1, task1.counter); + task1.Stop(); + // we need to check whether or not the test succeed with non-concurrent jobs } - /// - /// - [Test] - public async Task TestSchedulerWithSpringObjectJobFactoryAndQuartzJobObject() + try { - DummyJobObject.param = 0; - DummyJobObject.count = 0; - - JobDetailImpl jobDetail = new JobDetailImpl(); - jobDetail.JobType = typeof (DummyJobObject); - jobDetail.Name = "myJob"; - jobDetail.JobDataMap.Add("param", "10"); - - SimpleTriggerObject trigger = new SimpleTriggerObject(); - trigger.Name = "myTrigger"; - trigger.JobDetail = jobDetail; - trigger.StartDelay = TimeSpan.FromMilliseconds(1); - trigger.RepeatInterval = TimeSpan.FromMilliseconds(500); - trigger.RepeatCount = 1; - trigger.AfterPropertiesSet(); - - SchedulerFactoryObject factoryObject = new SchedulerFactoryObject(); - factoryObject.JobFactory = new SpringObjectJobFactory(); - factoryObject.Triggers = new ITrigger[] {trigger}; - factoryObject.JobDetails = new IJobDetail[] {jobDetail}; - factoryObject.AfterPropertiesSet(); - await factoryObject.Start(); - - await Task.Delay(TimeSpan.FromSeconds(1)); - Assert.AreEqual(10, DummyJobObject.param); - Assert.IsTrue(DummyJobObject.count > 0); - - factoryObject.Dispose(); + Thread.Sleep(4000); + } + catch (ThreadInterruptedException) + { + // fall through } - /// - /// - /// - [Test] - public async Task TestSchedulerWithSpringObjectJobFactoryAndJobSchedulingData() + task1.Stop(); + Assert.AreEqual(2, task1.counter); + + // Although we're destroying the scheduler, it does seem to keep things in memory: + // When executing both tests (concurrent and non-concurrent), the second test always + // fails. + schedulerFactoryObject.Dispose(); + } + + /// + /// + [Test] + public async Task TestSchedulerFactoryObjectWithPlainQuartzObjects() + { + IJobFactory jobFactory = new AdaptableJobFactory(); + + TestObject tb = new TestObject("tb", 99); + JobDetailImpl jobDetail0 = new JobDetailImpl(); + jobDetail0.JobType = typeof(IJob); + jobDetail0.Name = "myJob0"; + jobDetail0.Group = SchedulerConstants.DefaultGroup; + jobDetail0.JobDataMap.Add("testObject", tb); + Assert.AreEqual(tb, jobDetail0.JobDataMap.Get("testObject")); + + CronTriggerImpl trigger0 = new CronTriggerImpl(); + trigger0.Name = "myTrigger0"; + trigger0.Group = SchedulerConstants.DefaultGroup; + trigger0.JobName = "myJob0"; + trigger0.JobGroup = SchedulerConstants.DefaultGroup; + trigger0.StartTimeUtc = DateTime.UtcNow; + trigger0.CronExpressionString = "0/1 * * * * ?"; + + TestMethodInvokingTask task1 = new TestMethodInvokingTask(); + MethodInvokingJobDetailFactoryObject mijdfb = new MethodInvokingJobDetailFactoryObject(); + mijdfb.Name = "myJob1"; + mijdfb.Group = SchedulerConstants.DefaultGroup; + mijdfb.TargetObject = task1; + mijdfb.TargetMethod = "doSomething"; + mijdfb.AfterPropertiesSet(); + IJobDetail jobDetail1 = (IJobDetail) mijdfb.GetObject(); + + SimpleTriggerImpl trigger1 = new SimpleTriggerImpl(); + trigger1.Name = "myTrigger1"; + trigger1.Group = SchedulerConstants.DefaultGroup; + trigger1.JobName = "myJob1"; + trigger1.JobGroup = SchedulerConstants.DefaultGroup; + trigger1.StartTimeUtc = DateTime.UtcNow; + trigger1.RepeatCount = SimpleTriggerImpl.RepeatIndefinitely; + trigger1.RepeatInterval = TimeSpan.FromMilliseconds(20); + + IScheduler scheduler = A.Fake(); + A.CallTo(() => scheduler.GetTrigger(A._, A._)).Returns(Task.FromResult(null)); + A.CallTo(() => scheduler.GetJobDetail(A._, A._)).Returns(Task.FromResult(null)); + + SchedulerFactoryObject schedulerFactoryObject = new TestSchedulerFactoryObject(scheduler); + + schedulerFactoryObject.JobFactory = jobFactory; + schedulerFactoryObject.JobDetails = new IJobDetail[] { jobDetail0, jobDetail1 }; + schedulerFactoryObject.Triggers = new ITrigger[] { trigger0, trigger1 }; + try { - DummyJob.param = 0; - DummyJob.count = 0; - - SchedulerFactoryObject factoryObject = new SchedulerFactoryObject(); - factoryObject.JobFactory = new SpringObjectJobFactory(); - factoryObject.JobSchedulingDataLocation = "job-scheduling-data.xml"; - // TODO bean.ResourceLoader = (new FileSystemResourceLoader()); - factoryObject.AfterPropertiesSet(); - await factoryObject.Start(); - - await Task.Delay(TimeSpan.FromSeconds(1)); - Assert.AreEqual(10, DummyJob.param); - Assert.IsTrue(DummyJob.count > 0); - - factoryObject.Dispose(); + schedulerFactoryObject.AfterPropertiesSet(); + await schedulerFactoryObject.Start(); + } + finally + { + schedulerFactoryObject.Dispose(); } + A.CallTo(scheduler) + .Where(x => x.Method.Name.Equals("set_JobFactory")) + .WhenArgumentsMatch(x => x.Get(0) == jobFactory) + .MustHaveHappened(); - /// - /// Tests the creation of multiple schedulers (SPR-772) - /// - [Test] - public void TestMultipleSchedulers() + A.CallTo(() => scheduler.AddJob(jobDetail0, true, true, A._)).MustHaveHappened(); + A.CallTo(() => scheduler.AddJob(jobDetail1, true, true, A._)).MustHaveHappened(); + A.CallTo(() => scheduler.GetJobDetail(new JobKey("myJob0", SchedulerConstants.DefaultGroup), A._)).MustHaveHappened(); + A.CallTo(() => scheduler.GetJobDetail(new JobKey("myJob1", SchedulerConstants.DefaultGroup), A._)).MustHaveHappened(); + A.CallTo(() => scheduler.GetTrigger(new TriggerKey("myTrigger0", SchedulerConstants.DefaultGroup), A._)).MustHaveHappened(); + A.CallTo(() => scheduler.GetTrigger(new TriggerKey("myTrigger1", SchedulerConstants.DefaultGroup), A._)).MustHaveHappened(); + } + + /// + /// + [Test] + public async Task TestSchedulerFactoryObjectWithApplicationContext() + { + TestObject tb = new TestObject("tb", 99); + StaticApplicationContext ac = new StaticApplicationContext(); + + IScheduler scheduler = A.Fake(); + SchedulerContext schedulerContext = new SchedulerContext(); + A.CallTo(() => scheduler.Context).Returns(schedulerContext).NumberOfTimes(4); + + SchedulerFactoryObject schedulerFactoryObject = new TestSchedulerFactoryObject(scheduler); + schedulerFactoryObject.JobFactory = null; + IDictionary schedulerContextMap = new Hashtable(); + schedulerContextMap.Add("testObject", tb); + schedulerFactoryObject.SchedulerContextAsMap = schedulerContextMap; + schedulerFactoryObject.ApplicationContext = ac; + schedulerFactoryObject.ApplicationContextSchedulerContextKey = "appCtx"; + try { - XmlApplicationContext ctx = new XmlApplicationContext("multipleSchedulers.xml"); - try - { - IScheduler scheduler1 = (IScheduler) ctx.GetObject("scheduler1"); - IScheduler scheduler2 = (IScheduler) ctx.GetObject("scheduler2"); - Assert.AreNotSame(scheduler1, scheduler2); - Assert.AreEqual("quartz1", scheduler1.SchedulerName); - Assert.AreEqual("quartz2", scheduler2.SchedulerName); - - XmlApplicationContext ctx2 = new XmlApplicationContext("multipleSchedulers.xml"); - try - { - IScheduler scheduler1a = (IScheduler) ctx2.GetObject("scheduler1"); - IScheduler scheduler2a = (IScheduler) ctx2.GetObject("scheduler2"); - Assert.AreNotSame(scheduler1a, scheduler2a); - Assert.AreNotSame(scheduler1a, scheduler1); - Assert.AreNotSame(scheduler2a, scheduler2); - Assert.AreEqual("quartz1", scheduler1a.SchedulerName); - Assert.AreEqual("quartz2", scheduler2a.SchedulerName); - } - finally - { - ctx2.Dispose(); - } - } - finally - { - ctx.Dispose(); - } + schedulerFactoryObject.AfterPropertiesSet(); + await schedulerFactoryObject.Start(); + IScheduler returnedScheduler = (IScheduler) schedulerFactoryObject.GetObject(); + Assert.AreEqual(tb, returnedScheduler.Context["testObject"]); + Assert.AreEqual(ac, returnedScheduler.Context["appCtx"]); } - - /// - /// Tests calling of services with method invoke. - /// - [Test] - public void TestWithTwoAnonymousMethodInvokingJobDetailFactoryObjects() + finally { - XmlApplicationContext ctx = new XmlApplicationContext("multipleAnonymousMethodInvokingJobDetailFB.xml"); - Thread.Sleep(3000); - try - { - QuartzTestObject exportService = (QuartzTestObject) ctx.GetObject("exportService"); - QuartzTestObject importService = (QuartzTestObject) ctx.GetObject("importService"); - - Assert.AreEqual(0, exportService.ImportCount, "doImport called exportService"); - Assert.AreEqual(2, exportService.ExportCount, "doExport not called on exportService"); - Assert.AreEqual(2, importService.ImportCount, "doImport not called on importService"); - Assert.AreEqual(0, importService.ExportCount, "doExport called on importService"); - } - finally - { - ctx.Dispose(); - } - } - - /// - /// Tests how quartz triggers and services interact. - /// - [Test] - public void TestSchedulerAccessorObject() - { - XmlApplicationContext ctx = new XmlApplicationContext("schedulerAccessorObject.xml"); - Thread.Sleep(3000); - try - { - QuartzTestObject exportService = (QuartzTestObject) ctx.GetObject("exportService"); - QuartzTestObject importService = (QuartzTestObject) ctx.GetObject("importService"); - - Assert.AreEqual(0, exportService.ImportCount, "doImport called exportService"); - Assert.AreEqual(2, exportService.ExportCount, "doExport not called on exportService"); - Assert.AreEqual(2, importService.ImportCount, "doImport not called on importService"); - Assert.AreEqual(0, importService.ExportCount, "doExport called on importService"); - } - finally - { - ctx.Dispose(); - } - } - - [Test] - public void TestSchedulerAutoStartsOnContextRefreshedEventByDefault() - { - StaticApplicationContext context = new StaticApplicationContext(); - context.RegisterObjectDefinition("scheduler", new RootObjectDefinition(typeof (SchedulerFactoryObject))); - IScheduler scheduler = (IScheduler) context.GetObject("scheduler", typeof (IScheduler)); - Assert.IsFalse(scheduler.IsStarted); - context.Refresh(); - Assert.IsTrue(scheduler.IsStarted); - } - - [Test] - public void TestSchedulerAutoStartupFalse() - { - StaticApplicationContext context = new StaticApplicationContext(); - ObjectDefinitionBuilder beanDefinition = ObjectDefinitionBuilder - .GenericObjectDefinition(typeof(SchedulerFactoryObject)) - .AddPropertyValue("autoStartup", false); - - context.RegisterObjectDefinition("scheduler", beanDefinition.ObjectDefinition); - IScheduler scheduler = (IScheduler) context.GetObject("scheduler", typeof(IScheduler)); - - Assert.IsFalse(scheduler.IsStarted); - context.Refresh(); - Assert.IsFalse(scheduler.IsStarted); - } - - /// - /// Tests how scheduler is exposed to application context. - /// - [Test] - public async Task TestSchedulerRepositoryExposure() - { - XmlApplicationContext ctx = new XmlApplicationContext("schedulerRepositoryExposure.xml"); - var expected = await SchedulerRepository.Instance.Lookup("myScheduler"); - Assert.AreSame(expected, ctx.GetObject("scheduler")); - ctx.Dispose(); - } - - /// - /// Simple task executor that tracks invocation count. - /// - public class CountingTaskExecutor : ITaskExecutor - { - internal int count; - - /// - /// Executes task instance. - /// - /// - public void Execute(ThreadStart task) - { - count++; - task.Invoke(); - } - } - - /// - /// Simple test job object. - /// - public class DummyJobObject : QuartzJobObject - { - internal static int param; - internal static int count; - - /// - /// Sets parameter value. - /// - /// - public void SetParam(int value) - { - if (param > 0) - { - throw new NotSupportedException("Param already set"); - } - param = value; - } - - /// - /// Execute the actual job. The job data map will already have been - /// applied as object property values by execute. The contract is - /// exactly the same as for the standard Quartz execute method. - /// - protected override Task ExecuteInternal(IJobExecutionContext jobExecutionContext) - { - count++; - return Task.FromResult(true); - } - } - - /// - /// Simple thread runnable. - /// - public class DummyRunnable : IThreadRunnable - { - internal static int param; - internal static int count; - internal static readonly ManualResetEvent runEvent = new ManualResetEvent(false); - - /// - /// Runs thread runnable. - /// - public Task Run() - { - count++; - runEvent.Set(); - return Task.FromResult(true); - } + schedulerFactoryObject.Dispose(); } } /// - /// A simple job that tracks invocation count and allows setting of a simple parameter. /// - public class DummyJob : IJob + [Test] + public void TestJobDetailObjectWithApplicationContext() + { + TestObject tb = new TestObject("tb", 99); + StaticApplicationContext ac = new StaticApplicationContext(); + + JobDetailObject jobDetail = new JobDetailObject(); + jobDetail.JobType = typeof(IJob); + jobDetail.ObjectName = "myJob0"; + IDictionary jobData = new Hashtable(); + jobData.Add("testObject", tb); + jobDetail.JobDataAsMap = jobData; + jobDetail.ApplicationContext = ac; + jobDetail.ApplicationContextJobDataKey = "appCtx"; + jobDetail.AfterPropertiesSet(); + + Assert.AreEqual(tb, jobDetail.JobDataMap.Get("testObject")); + Assert.AreEqual(ac, jobDetail.JobDataMap.Get("appCtx")); + } + + /// + /// + [Test] + public async Task TestSchedulerWithTaskExecutor() + { + CountingTaskExecutor taskExecutor = new CountingTaskExecutor(); + DummyJob.count = 0; + + JobDetailImpl jobDetail = new JobDetailImpl(); + jobDetail.JobType = typeof(DummyJob); + jobDetail.Name = "myJob"; + + SimpleTriggerObject trigger = new SimpleTriggerObject(); + trigger.Name = "myTrigger"; + trigger.JobDetail = jobDetail; + trigger.StartDelay = TimeSpan.FromMilliseconds(1); + trigger.RepeatInterval = TimeSpan.FromMilliseconds(500); + trigger.RepeatCount = 1; + trigger.AfterPropertiesSet(); + + SchedulerFactoryObject factoryObject = new SchedulerFactoryObject(); + factoryObject.TaskExecutor = taskExecutor; + factoryObject.Triggers = new ITrigger[] { trigger }; + factoryObject.JobDetails = new IJobDetail[] { jobDetail }; + factoryObject.AfterPropertiesSet(); + await factoryObject.Start(); + + await Task.Delay(TimeSpan.FromSeconds(1)); + Assert.IsTrue(DummyJob.count > 0); + Assert.AreEqual(DummyJob.count, taskExecutor.count); + + factoryObject.Dispose(); + } + + /// + /// + [Test] + public async Task TestSchedulerWithRunnable() + { + DummyRunnable.count = 0; + + JobDetailImpl jobDetail = new JobDetailObject(); + jobDetail.JobType = typeof(DummyRunnable); + jobDetail.Name = "myJob"; + + SimpleTriggerObject trigger = new SimpleTriggerObject(); + trigger.Name = "myTrigger"; + trigger.JobDetail = jobDetail; + trigger.StartDelay = TimeSpan.FromMilliseconds(1); + trigger.RepeatInterval = TimeSpan.FromMilliseconds(500); + trigger.RepeatCount = 1; + trigger.AfterPropertiesSet(); + + SchedulerFactoryObject factoryObject = new SchedulerFactoryObject(); + factoryObject.Triggers = new ITrigger[] { trigger }; + factoryObject.JobDetails = new IJobDetail[] { jobDetail }; + factoryObject.AfterPropertiesSet(); + await factoryObject.Start(); + + DummyRunnable.runEvent.WaitOne(TimeSpan.FromSeconds(5)); + Assert.IsTrue(DummyRunnable.count > 0); + + factoryObject.Dispose(); + } + + /// + /// + [Test] + public async Task TestSchedulerWithQuartzJobObject() + { + DummyJob.param = 0; + DummyJob.count = 0; + + JobDetailImpl jobDetail = new JobDetailImpl(); + jobDetail.JobType = typeof(DummyJobObject); + jobDetail.Name = "myJob"; + jobDetail.JobDataMap.Put("param", "10"); + + SimpleTriggerObject trigger = new SimpleTriggerObject(); + trigger.Name = "myTrigger"; + trigger.JobDetail = jobDetail; + trigger.StartDelay = TimeSpan.FromMilliseconds(1); + trigger.RepeatInterval = TimeSpan.FromMilliseconds(500); + trigger.RepeatCount = 1; + trigger.AfterPropertiesSet(); + + SchedulerFactoryObject factoryObject = new SchedulerFactoryObject(); + factoryObject.Triggers = new ITrigger[] { trigger }; + factoryObject.JobDetails = new IJobDetail[] { jobDetail }; + factoryObject.AfterPropertiesSet(); + await factoryObject.Start(); + + await Task.Delay(TimeSpan.FromSeconds(1)); + Assert.AreEqual(10, DummyJobObject.param); + Assert.IsTrue(DummyJobObject.count > 0); + + factoryObject.Dispose(); + } + + /// + /// + [Test] + public async Task TestSchedulerWithSpringObjectJobFactory() + { + DummyJob.param = 0; + DummyJob.count = 0; + + JobDetailImpl jobDetail = new JobDetailImpl(); + jobDetail.JobType = typeof(DummyJob); + jobDetail.Name = "myJob"; + jobDetail.JobDataMap.Add("param", "10"); + jobDetail.JobDataMap.Add("ignoredParam", "10"); + + SimpleTriggerObject trigger = new SimpleTriggerObject(); + trigger.Name = "myTrigger"; + trigger.JobDetail = jobDetail; + trigger.StartDelay = TimeSpan.FromMilliseconds(1); + trigger.RepeatInterval = TimeSpan.FromMilliseconds(500); + trigger.RepeatCount = 1; + trigger.AfterPropertiesSet(); + + SchedulerFactoryObject factoryObject = new SchedulerFactoryObject(); + factoryObject.JobFactory = new SpringObjectJobFactory(); + factoryObject.Triggers = new ITrigger[] { trigger }; + factoryObject.JobDetails = new IJobDetail[] { jobDetail }; + factoryObject.AfterPropertiesSet(); + await factoryObject.Start(); + + await Task.Delay(TimeSpan.FromSeconds(1)); + Assert.AreEqual(10, DummyJob.param); + Assert.IsTrue(DummyJob.count > 0); + + factoryObject.Dispose(); + } + + /// + /// + [Test] + public async Task TestSchedulerWithSpringObjectJobFactoryAndParamMismatchNotIgnored() + { + DummyJob.param = 0; + DummyJob.count = 0; + + JobDetailImpl jobDetail = new JobDetailImpl(); + jobDetail.JobType = typeof(DummyJob); + jobDetail.Name = "myJob"; + jobDetail.JobDataMap.Add("para", "10"); + jobDetail.JobDataMap.Add("ignoredParam", "10"); + + SimpleTriggerObject trigger = new SimpleTriggerObject(); + trigger.Name = "myTrigger"; + trigger.JobDetail = jobDetail; + trigger.StartDelay = TimeSpan.FromMilliseconds(1); + trigger.RepeatInterval = TimeSpan.FromMilliseconds(500); + trigger.RepeatCount = 1; + trigger.AfterPropertiesSet(); + + SchedulerFactoryObject bean = new SchedulerFactoryObject(); + SpringObjectJobFactory jobFactory = new SpringObjectJobFactory(); + jobFactory.IgnoredUnknownProperties = new String[] { "ignoredParam" }; + bean.JobFactory = jobFactory; + bean.Triggers = new ITrigger[] { trigger }; + bean.JobDetails = new IJobDetail[] { jobDetail }; + bean.AfterPropertiesSet(); + + await Task.Delay(TimeSpan.FromSeconds(1)); + Assert.AreEqual(0, DummyJob.param); + Assert.IsTrue(DummyJob.count == 0); + + bean.Dispose(); + } + + /// + /// + [Test] + public async Task TestSchedulerWithSpringObjectJobFactoryAndRunnable() + { + DummyRunnable.param = 0; + DummyRunnable.count = 0; + + JobDetailObject jobDetail = new JobDetailObject(); + jobDetail.JobType = typeof(DummyRunnable); + jobDetail.Name = "myJob"; + jobDetail.JobDataMap.Add("param", "10"); + + SimpleTriggerObject trigger = new SimpleTriggerObject(); + trigger.Name = "myTrigger"; + trigger.JobDetail = jobDetail; + trigger.StartDelay = TimeSpan.FromMilliseconds(1); + trigger.RepeatInterval = TimeSpan.FromMilliseconds(500); + trigger.RepeatCount = 1; + trigger.AfterPropertiesSet(); + + SchedulerFactoryObject factoryObject = new SchedulerFactoryObject(); + factoryObject.JobFactory = new SpringObjectJobFactory(); + factoryObject.Triggers = new ITrigger[] { trigger }; + factoryObject.JobDetails = new IJobDetail[] { jobDetail }; + factoryObject.AfterPropertiesSet(); + await factoryObject.Start(); + + await Task.Delay(TimeSpan.FromSeconds(1)); + Assert.AreEqual(10, DummyRunnable.param); + Assert.IsTrue(DummyRunnable.count > 0); + + factoryObject.Dispose(); + } + + /// + /// + [Test] + public async Task TestSchedulerWithSpringObjectJobFactoryAndQuartzJobObject() + { + DummyJobObject.param = 0; + DummyJobObject.count = 0; + + JobDetailImpl jobDetail = new JobDetailImpl(); + jobDetail.JobType = typeof(DummyJobObject); + jobDetail.Name = "myJob"; + jobDetail.JobDataMap.Add("param", "10"); + + SimpleTriggerObject trigger = new SimpleTriggerObject(); + trigger.Name = "myTrigger"; + trigger.JobDetail = jobDetail; + trigger.StartDelay = TimeSpan.FromMilliseconds(1); + trigger.RepeatInterval = TimeSpan.FromMilliseconds(500); + trigger.RepeatCount = 1; + trigger.AfterPropertiesSet(); + + SchedulerFactoryObject factoryObject = new SchedulerFactoryObject(); + factoryObject.JobFactory = new SpringObjectJobFactory(); + factoryObject.Triggers = new ITrigger[] { trigger }; + factoryObject.JobDetails = new IJobDetail[] { jobDetail }; + factoryObject.AfterPropertiesSet(); + await factoryObject.Start(); + + await Task.Delay(TimeSpan.FromSeconds(1)); + Assert.AreEqual(10, DummyJobObject.param); + Assert.IsTrue(DummyJobObject.count > 0); + + factoryObject.Dispose(); + } + + /// + /// + /// + [Test] + public async Task TestSchedulerWithSpringObjectJobFactoryAndJobSchedulingData() + { + DummyJob.param = 0; + DummyJob.count = 0; + + SchedulerFactoryObject factoryObject = new SchedulerFactoryObject(); + factoryObject.JobFactory = new SpringObjectJobFactory(); + factoryObject.JobSchedulingDataLocation = "job-scheduling-data.xml"; + // TODO bean.ResourceLoader = (new FileSystemResourceLoader()); + factoryObject.AfterPropertiesSet(); + await factoryObject.Start(); + + await Task.Delay(TimeSpan.FromSeconds(1)); + Assert.AreEqual(10, DummyJob.param); + Assert.IsTrue(DummyJob.count > 0); + + factoryObject.Dispose(); + } + + /// + /// Tests the creation of multiple schedulers (SPR-772) + /// + [Test] + public void TestMultipleSchedulers() + { + XmlApplicationContext ctx = new XmlApplicationContext("multipleSchedulers.xml"); + try + { + IScheduler scheduler1 = (IScheduler) ctx.GetObject("scheduler1"); + IScheduler scheduler2 = (IScheduler) ctx.GetObject("scheduler2"); + Assert.AreNotSame(scheduler1, scheduler2); + Assert.AreEqual("quartz1", scheduler1.SchedulerName); + Assert.AreEqual("quartz2", scheduler2.SchedulerName); + + XmlApplicationContext ctx2 = new XmlApplicationContext("multipleSchedulers.xml"); + try + { + IScheduler scheduler1a = (IScheduler) ctx2.GetObject("scheduler1"); + IScheduler scheduler2a = (IScheduler) ctx2.GetObject("scheduler2"); + Assert.AreNotSame(scheduler1a, scheduler2a); + Assert.AreNotSame(scheduler1a, scheduler1); + Assert.AreNotSame(scheduler2a, scheduler2); + Assert.AreEqual("quartz1", scheduler1a.SchedulerName); + Assert.AreEqual("quartz2", scheduler2a.SchedulerName); + } + finally + { + ctx2.Dispose(); + } + } + finally + { + ctx.Dispose(); + } + } + + /// + /// Tests calling of services with method invoke. + /// + [Test] + public void TestWithTwoAnonymousMethodInvokingJobDetailFactoryObjects() + { + XmlApplicationContext ctx = new XmlApplicationContext("multipleAnonymousMethodInvokingJobDetailFB.xml"); + Thread.Sleep(3000); + try + { + QuartzTestObject exportService = (QuartzTestObject) ctx.GetObject("exportService"); + QuartzTestObject importService = (QuartzTestObject) ctx.GetObject("importService"); + + Assert.AreEqual(0, exportService.ImportCount, "doImport called exportService"); + Assert.AreEqual(2, exportService.ExportCount, "doExport not called on exportService"); + Assert.AreEqual(2, importService.ImportCount, "doImport not called on importService"); + Assert.AreEqual(0, importService.ExportCount, "doExport called on importService"); + } + finally + { + ctx.Dispose(); + } + } + + /// + /// Tests how quartz triggers and services interact. + /// + [Test] + public void TestSchedulerAccessorObject() + { + XmlApplicationContext ctx = new XmlApplicationContext("schedulerAccessorObject.xml"); + Thread.Sleep(3000); + try + { + QuartzTestObject exportService = (QuartzTestObject) ctx.GetObject("exportService"); + QuartzTestObject importService = (QuartzTestObject) ctx.GetObject("importService"); + + Assert.AreEqual(0, exportService.ImportCount, "doImport called exportService"); + Assert.AreEqual(2, exportService.ExportCount, "doExport not called on exportService"); + Assert.AreEqual(2, importService.ImportCount, "doImport not called on importService"); + Assert.AreEqual(0, importService.ExportCount, "doExport called on importService"); + } + finally + { + ctx.Dispose(); + } + } + + [Test] + public void TestSchedulerAutoStartsOnContextRefreshedEventByDefault() + { + StaticApplicationContext context = new StaticApplicationContext(); + context.RegisterObjectDefinition("scheduler", new RootObjectDefinition(typeof(SchedulerFactoryObject))); + IScheduler scheduler = (IScheduler) context.GetObject("scheduler", typeof(IScheduler)); + Assert.IsFalse(scheduler.IsStarted); + context.Refresh(); + Assert.IsTrue(scheduler.IsStarted); + } + + [Test] + public void TestSchedulerAutoStartupFalse() + { + StaticApplicationContext context = new StaticApplicationContext(); + ObjectDefinitionBuilder beanDefinition = ObjectDefinitionBuilder + .GenericObjectDefinition(typeof(SchedulerFactoryObject)) + .AddPropertyValue("autoStartup", false); + + context.RegisterObjectDefinition("scheduler", beanDefinition.ObjectDefinition); + IScheduler scheduler = (IScheduler) context.GetObject("scheduler", typeof(IScheduler)); + + Assert.IsFalse(scheduler.IsStarted); + context.Refresh(); + Assert.IsFalse(scheduler.IsStarted); + } + + /// + /// Tests how scheduler is exposed to application context. + /// + [Test] + public async Task TestSchedulerRepositoryExposure() + { + XmlApplicationContext ctx = new XmlApplicationContext("schedulerRepositoryExposure.xml"); + var expected = await SchedulerRepository.Instance.Lookup("myScheduler"); + Assert.AreSame(expected, ctx.GetObject("scheduler")); + ctx.Dispose(); + } + + /// + /// Simple task executor that tracks invocation count. + /// + public class CountingTaskExecutor : ITaskExecutor + { + internal int count; + + /// + /// Executes task instance. + /// + /// + public void Execute(ThreadStart task) + { + count++; + task.Invoke(); + } + } + + /// + /// Simple test job object. + /// + public class DummyJobObject : QuartzJobObject { internal static int param; internal static int count; /// - /// Sets param value. + /// Sets parameter value. /// /// public void SetParam(int value) @@ -1019,14 +964,16 @@ namespace Spring.Scheduling.Quartz { throw new NotSupportedException("Param already set"); } + param = value; } - /// - /// Executes this job instance. - /// - /// - public Task Execute(IJobExecutionContext jobExecutionContext) + /// + /// Execute the actual job. The job data map will already have been + /// applied as object property values by execute. The contract is + /// exactly the same as for the standard Quartz execute method. + /// + protected override Task ExecuteInternal(IJobExecutionContext jobExecutionContext) { count++; return Task.FromResult(true); @@ -1034,31 +981,84 @@ namespace Spring.Scheduling.Quartz } /// - /// Subclass of SchedulerFactoryObject for testing purposes. + /// Simple thread runnable. /// - public class TestSchedulerFactoryObject : SchedulerFactoryObject + public class DummyRunnable : IThreadRunnable { - private readonly IScheduler sched; + internal static int param; + internal static int count; + internal static readonly ManualResetEvent runEvent = new ManualResetEvent(false); /// - /// Creates new instance of this class. + /// Runs thread runnable. /// - /// - public TestSchedulerFactoryObject(IScheduler sched) + public Task Run() { - this.sched = sched; - } - - /// - /// Creates a scheduler actually returning the scheduler this intance - /// was instantiated with. - /// - /// - /// - /// - protected override IScheduler CreateScheduler(ISchedulerFactory schedulerFactory, String schedulerName) - { - return sched; + count++; + runEvent.Set(); + return Task.FromResult(true); } } } + +/// +/// A simple job that tracks invocation count and allows setting of a simple parameter. +/// +public class DummyJob : IJob +{ + internal static int param; + internal static int count; + + /// + /// Sets param value. + /// + /// + public void SetParam(int value) + { + if (param > 0) + { + throw new NotSupportedException("Param already set"); + } + + param = value; + } + + /// + /// Executes this job instance. + /// + /// + public Task Execute(IJobExecutionContext jobExecutionContext) + { + count++; + return Task.FromResult(true); + } +} + +/// +/// Subclass of SchedulerFactoryObject for testing purposes. +/// +public class TestSchedulerFactoryObject : SchedulerFactoryObject +{ + private readonly IScheduler sched; + + /// + /// Creates new instance of this class. + /// + /// + public TestSchedulerFactoryObject(IScheduler sched) + { + this.sched = sched; + } + + /// + /// Creates a scheduler actually returning the scheduler this intance + /// was instantiated with. + /// + /// + /// + /// + protected override IScheduler CreateScheduler(ISchedulerFactory schedulerFactory, String schedulerName) + { + return sched; + } +} diff --git a/test/Spring/Spring.Scheduling.Quartz3.Tests/Scheduling/Quartz/QuartzTestObject.cs b/test/Spring/Spring.Scheduling.Quartz3.Tests/Scheduling/Quartz/QuartzTestObject.cs index 2d1e1346..bfd00e55 100644 --- a/test/Spring/Spring.Scheduling.Quartz3.Tests/Scheduling/Quartz/QuartzTestObject.cs +++ b/test/Spring/Spring.Scheduling.Quartz3.Tests/Scheduling/Quartz/QuartzTestObject.cs @@ -1,45 +1,44 @@ -namespace Spring.Scheduling.Quartz +namespace Spring.Scheduling.Quartz; + +/// +/// A simple test object for Quartz.NET to run +/// that simulates imports and exports. +/// +/// Rob Harrop +public class QuartzTestObject { + private int exportCount; + private int importCount; + /// - /// A simple test object for Quartz.NET to run - /// that simulates imports and exports. + /// Executes a fake import and increments counter. /// - /// Rob Harrop - public class QuartzTestObject + public void DoImport() { - private int exportCount; - private int importCount; - - /// - /// Executes a fake import and increments counter. - /// - public void DoImport() - { - ++importCount; - } - - /// - /// Executes a fake export and increments counter. - /// - public void DoExport() - { - ++exportCount; - } - - /// - /// Tells how many times import has been done. - /// - public int ImportCount - { - get { return importCount; } - } - - /// - /// Tells how many times export has been done. - /// - public int ExportCount - { - get { return exportCount; } - } + ++importCount; } -} \ No newline at end of file + + /// + /// Executes a fake export and increments counter. + /// + public void DoExport() + { + ++exportCount; + } + + /// + /// Tells how many times import has been done. + /// + public int ImportCount + { + get { return importCount; } + } + + /// + /// Tells how many times export has been done. + /// + public int ExportCount + { + get { return exportCount; } + } +} diff --git a/test/Spring/Spring.Scheduling.Quartz3.Tests/Scheduling/Quartz/SchedulerFactoryObjectTest.cs b/test/Spring/Spring.Scheduling.Quartz3.Tests/Scheduling/Quartz/SchedulerFactoryObjectTest.cs index ad2299f5..982d19bb 100644 --- a/test/Spring/Spring.Scheduling.Quartz3.Tests/Scheduling/Quartz/SchedulerFactoryObjectTest.cs +++ b/test/Spring/Spring.Scheduling.Quartz3.Tests/Scheduling/Quartz/SchedulerFactoryObjectTest.cs @@ -1,325 +1,320 @@ /* -* Copyright 2002-2010 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. -*/ + * Copyright 2002-2010 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. + */ using System.Collections; using System.Collections.Specialized; using System.Reflection; using System.Text; using FakeItEasy; - using NUnit.Framework; - using Quartz; using Quartz.Impl; using Quartz.Impl.Triggers; using Quartz.Spi; - using Spring.Core.IO; -namespace Spring.Scheduling.Quartz +namespace Spring.Scheduling.Quartz; + +/// +/// Tests for SchedulerFactoryObject. +/// +/// Marko Lahma (.NET) +[TestFixture] +public class SchedulerFactoryObjectTest { + private static readonly MethodInfo m_InitSchedulerFactory = typeof(SchedulerFactoryObject).GetMethod("InitSchedulerFactory", + BindingFlags.Instance | BindingFlags.NonPublic); + + private SchedulerFactoryObject factory; + /// - /// Tests for SchedulerFactoryObject. + /// Test setup. /// - /// Marko Lahma (.NET) - [TestFixture] - public class SchedulerFactoryObjectTest + [SetUp] + public void SetUp() { - private static readonly MethodInfo m_InitSchedulerFactory = typeof(SchedulerFactoryObject).GetMethod("InitSchedulerFactory", - BindingFlags.Instance | BindingFlags.NonPublic); - private SchedulerFactoryObject factory; + factory = new SchedulerFactoryObject(); - /// - /// Test setup. - /// - [SetUp] - public void SetUp() - { - factory = new SchedulerFactoryObject(); + TestSchedulerFactory.Initialize(); + A.CallTo(() => TestSchedulerFactory.MockScheduler.SchedulerName).Returns("scheduler"); + } - TestSchedulerFactory.Initialize(); - A.CallTo(() => TestSchedulerFactory.MockScheduler.SchedulerName).Returns("scheduler"); - } + /// + /// Tests AfterPropertiesSet behavior. + /// + [Test] + public void TestAfterPropertiesSet_Defaults() + { + factory.AfterPropertiesSet(); + } - /// - /// Tests AfterPropertiesSet behavior. - /// - [Test] - public void TestAfterPropertiesSet_Defaults() - { - factory.AfterPropertiesSet(); - } + /// + /// Tests AfterPropertiesSet behavior. + /// + [Test] + public void TestAfterPropertiesSet_NullJobFactory() + { + factory.JobFactory = null; + factory.AfterPropertiesSet(); + } - /// - /// Tests AfterPropertiesSet behavior. - /// - [Test] - public void TestAfterPropertiesSet_NullJobFactory() - { - factory.JobFactory = null; - factory.AfterPropertiesSet(); - } + /// + /// Tests AfterPropertiesSet behavior. + /// + [Test] + public void TestAfterPropertiesSet_NoAutoStartup() + { + factory.SchedulerFactoryType = typeof(TestSchedulerFactory); + factory.AutoStartup = false; + factory.AfterPropertiesSet(); - /// - /// Tests AfterPropertiesSet behavior. - /// - [Test] - public void TestAfterPropertiesSet_NoAutoStartup() - { - factory.SchedulerFactoryType = typeof(TestSchedulerFactory); - factory.AutoStartup = false; - factory.AfterPropertiesSet(); + A.CallTo(() => TestSchedulerFactory.MockScheduler.Start(A._)).MustNotHaveHappened(); + } - A.CallTo(() => TestSchedulerFactory.MockScheduler.Start(A._)).MustNotHaveHappened(); - } + /// + /// Tests AfterPropertiesSet behavior. + /// + [Test] + public void TestAfterPropertiesSet_Calendars() + { + InitForAfterPropertiesSetTest(); - /// - /// Tests AfterPropertiesSet behavior. - /// - [Test] - public void TestAfterPropertiesSet_Calendars() - { - InitForAfterPropertiesSetTest(); + const string calendarName = "calendar"; + ICalendar cal = A.Fake(); + Hashtable calTable = new Hashtable(); + calTable[calendarName] = cal; + factory.Calendars = calTable; - const string calendarName = "calendar"; - ICalendar cal = A.Fake(); - Hashtable calTable = new Hashtable(); - calTable[calendarName] = cal; - factory.Calendars = calTable; + factory.AfterPropertiesSet(); - factory.AfterPropertiesSet(); + A.CallTo(() => TestSchedulerFactory.MockScheduler.AddCalendar(calendarName, cal, true, true, A._)).MustHaveHappened(); + } - A.CallTo(() => TestSchedulerFactory.MockScheduler.AddCalendar(calendarName, cal, true, true, A._)).MustHaveHappened(); - } + /// + /// Tests AfterPropertiesSet behavior. + /// + [Test] + public void TestAfterPropertiesSet_Trigger_TriggerExists() + { + InitForAfterPropertiesSetTest(); - /// - /// Tests AfterPropertiesSet behavior. - /// - [Test] - public void TestAfterPropertiesSet_Trigger_TriggerExists() - { - InitForAfterPropertiesSetTest(); + const string TRIGGER_NAME = "trigName"; + const string TRIGGER_GROUP = "trigGroup"; + SimpleTriggerImpl trigger = new SimpleTriggerImpl(TRIGGER_NAME, TRIGGER_GROUP); + factory.Triggers = new ITrigger[] { trigger }; - const string TRIGGER_NAME = "trigName"; - const string TRIGGER_GROUP = "trigGroup"; - SimpleTriggerImpl trigger = new SimpleTriggerImpl(TRIGGER_NAME, TRIGGER_GROUP); - factory.Triggers = new ITrigger[] { trigger }; + A.CallTo(() => TestSchedulerFactory.MockScheduler.GetTrigger(new TriggerKey(TRIGGER_NAME, TRIGGER_GROUP), A._)).Returns(trigger); - A.CallTo(() => TestSchedulerFactory.MockScheduler.GetTrigger(new TriggerKey(TRIGGER_NAME, TRIGGER_GROUP), A._)).Returns(trigger); + factory.AfterPropertiesSet(); + } - factory.AfterPropertiesSet(); - } + /// + /// Tests AfterPropertiesSet behavior. + /// + [Test] + public void TestAfterPropertiesSet_Trigger_TriggerDoesntExist() + { + InitForAfterPropertiesSetTest(); + A.CallTo(() => TestSchedulerFactory.MockScheduler.GetTrigger(A._, A._)).Returns(Task.FromResult(null)); - /// - /// Tests AfterPropertiesSet behavior. - /// - [Test] - public void TestAfterPropertiesSet_Trigger_TriggerDoesntExist() - { - InitForAfterPropertiesSetTest(); - A.CallTo(() => TestSchedulerFactory.MockScheduler.GetTrigger(A._, A._)).Returns(Task.FromResult(null)); + const string TRIGGER_NAME = "trigName"; + const string TRIGGER_GROUP = "trigGroup"; + SimpleTriggerImpl trigger = new SimpleTriggerImpl(TRIGGER_NAME, TRIGGER_GROUP); + factory.Triggers = new ITrigger[] { trigger }; - const string TRIGGER_NAME = "trigName"; - const string TRIGGER_GROUP = "trigGroup"; - SimpleTriggerImpl trigger = new SimpleTriggerImpl(TRIGGER_NAME, TRIGGER_GROUP); - factory.Triggers = new ITrigger[] { trigger }; + factory.AfterPropertiesSet(); - factory.AfterPropertiesSet(); + A.CallTo(() => TestSchedulerFactory.MockScheduler.ScheduleJob(trigger, A._)).MustHaveHappened(); + } - A.CallTo(() => TestSchedulerFactory.MockScheduler.ScheduleJob(trigger, A._)).MustHaveHappened(); - } + private void InitForAfterPropertiesSetTest() + { + factory.AutoStartup = false; + // set expectations + factory.SchedulerFactoryType = typeof(TestSchedulerFactory); + TestSchedulerFactory.MockScheduler.JobFactory = null; + } + /// + /// Tests AfterPropertiesSet behavior. + /// + [Test] + public async Task TestStart() + { + factory.SchedulerFactoryType = typeof(TestSchedulerFactory); + factory.AutoStartup = false; + factory.AfterPropertiesSet(); + await factory.Start(); - private void InitForAfterPropertiesSetTest() - { - factory.AutoStartup = false; - // set expectations - factory.SchedulerFactoryType = typeof(TestSchedulerFactory); - TestSchedulerFactory.MockScheduler.JobFactory = null; - } + A.CallTo(TestSchedulerFactory.MockScheduler) + .Where(x => x.Method.Name.Equals("set_JobFactory")) + .WhenArgumentsMatch(x => x.Get(0) != null) + .MustHaveHappened(); - /// - /// Tests AfterPropertiesSet behavior. - /// - [Test] - public async Task TestStart() - { - factory.SchedulerFactoryType = typeof(TestSchedulerFactory); - factory.AutoStartup = false; - factory.AfterPropertiesSet(); - await factory.Start(); + A.CallTo(() => TestSchedulerFactory.MockScheduler.Start(A._)).MustHaveHappened(); + } - A.CallTo(TestSchedulerFactory.MockScheduler) - .Where(x => x.Method.Name.Equals("set_JobFactory")) - .WhenArgumentsMatch(x => x.Get(0) != null) - .MustHaveHappened(); + /// + /// Tests AfterPropertiesSet behavior. + /// + [Test] + public async Task TestStop() + { + factory.SchedulerFactoryType = typeof(TestSchedulerFactory); + factory.AutoStartup = false; + factory.AfterPropertiesSet(); + await factory.Stop(); - A.CallTo(() => TestSchedulerFactory.MockScheduler.Start(A._)).MustHaveHappened(); - } + A.CallTo(TestSchedulerFactory.MockScheduler) + .Where(x => x.Method.Name.Equals("set_JobFactory")) + .WhenArgumentsMatch(x => x.Get(0) != null) + .MustHaveHappened(); - /// - /// Tests AfterPropertiesSet behavior. - /// - [Test] - public async Task TestStop() - { - factory.SchedulerFactoryType = typeof(TestSchedulerFactory); - factory.AutoStartup = false; - factory.AfterPropertiesSet(); - await factory.Stop(); + A.CallTo(() => TestSchedulerFactory.MockScheduler.Standby(A._)).MustHaveHappened(); + } - A.CallTo(TestSchedulerFactory.MockScheduler) - .Where(x => x.Method.Name.Equals("set_JobFactory")) - .WhenArgumentsMatch(x => x.Get(0) != null) - .MustHaveHappened(); + /// + /// Tests AfterPropertiesSet behavior. + /// + [Test] + public void TestGetObject() + { + factory.AfterPropertiesSet(); + IScheduler sched = (IScheduler) factory.GetObject(); + Assert.IsNotNull(sched, "scheduler was null"); + } - A.CallTo(() => TestSchedulerFactory.MockScheduler.Standby(A._)).MustHaveHappened(); - } + /// + /// Tests AfterPropertiesSet behavior. + /// + [Test] + public void TestSchedulerFactoryType_InvalidType() + { + Assert.Throws(() => factory.SchedulerFactoryType = typeof(SchedulerFactoryObjectTest)); + } - /// - /// Tests AfterPropertiesSet behavior. - /// - [Test] - public void TestGetObject() - { - factory.AfterPropertiesSet(); - IScheduler sched = (IScheduler)factory.GetObject(); - Assert.IsNotNull(sched, "scheduler was null"); - } + /// + /// Tests AfterPropertiesSet behavior. + /// + [Test] + public void TestSchedulerFactoryType_ValidType() + { + factory.SchedulerFactoryType = typeof(StdSchedulerFactory); + } - /// - /// Tests AfterPropertiesSet behavior. - /// - [Test] - public void TestSchedulerFactoryType_InvalidType() - { - Assert.Throws(() => factory.SchedulerFactoryType = typeof(SchedulerFactoryObjectTest)); - } + /// + /// Tests AfterPropertiesSet behavior. + /// + [Test] + public void TestInitSchedulerFactory_MinimalDefaults() + { + factory.SchedulerName = "testFactoryObject"; + StdSchedulerFactory factoryToPass = new StdSchedulerFactory(); + m_InitSchedulerFactory.Invoke(factory, new object[] { factoryToPass }); + } - /// - /// Tests AfterPropertiesSet behavior. - /// - [Test] - public void TestSchedulerFactoryType_ValidType() - { - factory.SchedulerFactoryType = typeof(StdSchedulerFactory); - } - - /// - /// Tests AfterPropertiesSet behavior. - /// - [Test] - public void TestInitSchedulerFactory_MinimalDefaults() - { - factory.SchedulerName = "testFactoryObject"; - StdSchedulerFactory factoryToPass = new StdSchedulerFactory(); - m_InitSchedulerFactory.Invoke(factory, new object[] { factoryToPass }); - } - - /// - /// Tests AfterPropertiesSet behavior. - /// - [Test] - public void TestInitSchedulerFactory_ConfigLocationReadingShouldPreserverExtraEqualsMarksAndTrimKeysAndValues() - { - const string ConnectionStringValue = "Server=(local);Database=quartz;Trusted_Connection=True;"; - const string ConnectionStringKey = "quartz.dataSource.default.connectionString"; - string configuration = - @"quartz.jobStore.type = Quartz.Impl.AdoJobStore.JobStoreTX, Quartz + /// + /// Tests AfterPropertiesSet behavior. + /// + [Test] + public void TestInitSchedulerFactory_ConfigLocationReadingShouldPreserverExtraEqualsMarksAndTrimKeysAndValues() + { + const string ConnectionStringValue = "Server=(local);Database=quartz;Trusted_Connection=True;"; + const string ConnectionStringKey = "quartz.dataSource.default.connectionString"; + string configuration = + @"quartz.jobStore.type = Quartz.Impl.AdoJobStore.JobStoreTX, Quartz quartz.jobStore.useProperties = false quartz.jobStore.dataSource = default" + Environment.NewLine + -ConnectionStringKey+ " = " + ConnectionStringValue + Environment.NewLine + -"quartz.dataSource.default.provider = SqlServer-20"; + ConnectionStringKey + " = " + ConnectionStringValue + Environment.NewLine + + "quartz.dataSource.default.provider = SqlServer-20"; - // initialize data - MemoryStream ms = new MemoryStream(); - byte[] data = Encoding.UTF8.GetBytes(configuration); - ms.Write(data, 0, data.Length); - ms.Seek(0, SeekOrigin.Begin); - ms.Position = 0; + // initialize data + MemoryStream ms = new MemoryStream(); + byte[] data = Encoding.UTF8.GetBytes(configuration); + ms.Write(data, 0, data.Length); + ms.Seek(0, SeekOrigin.Begin); + ms.Position = 0; - // intercept call - InterceptingStdSChedulerFactory factoryToPass = new InterceptingStdSChedulerFactory(); + // intercept call + InterceptingStdSChedulerFactory factoryToPass = new InterceptingStdSChedulerFactory(); - factory.ConfigLocation = new TestConfigLocation(ms, "description"); + factory.ConfigLocation = new TestConfigLocation(ms, "description"); - m_InitSchedulerFactory.Invoke(factory, new object[] { factoryToPass }); + m_InitSchedulerFactory.Invoke(factory, new object[] { factoryToPass }); - Assert.AreEqual(ConnectionStringValue, factoryToPass.Properties[ConnectionStringKey]); + Assert.AreEqual(ConnectionStringValue, factoryToPass.Properties[ConnectionStringKey]); + } +} - } +internal class TestConfigLocation : InputStreamResource +{ + public TestConfigLocation(Stream inputStream, string description) : base(inputStream, description) + { + } +} + +/// +/// ISchedulerFactory implementation for testing purposes. +/// +public class TestSchedulerFactory : ISchedulerFactory +{ + private static IScheduler mockScheduler; + + /// + /// The mocked scheduler. + /// + public static IScheduler MockScheduler => mockScheduler; + + /// + public Task GetScheduler(CancellationToken _) + { + return Task.FromResult(mockScheduler); } - internal class TestConfigLocation : InputStreamResource + /// + public Task GetScheduler(string schedName, CancellationToken _) { - public TestConfigLocation(Stream inputStream, string description) : base(inputStream, description) - { - } + return Task.FromResult(mockScheduler); + } + + /// + public Task> GetAllSchedulers(CancellationToken _) + => Task.FromResult>(new List()); + + public static void Initialize() + { + mockScheduler = A.Fake(); + } +} + +/// +/// Scheduler factory that supports property interception. +/// +public class InterceptingStdSChedulerFactory : StdSchedulerFactory +{ + private NameValueCollection properties; + + /// + public override void Initialize(NameValueCollection props) + { + properties = props; } /// - /// ISchedulerFactory implementation for testing purposes. + /// Return propeties given to this factory at initialization time. /// - public class TestSchedulerFactory : ISchedulerFactory - { - private static IScheduler mockScheduler; - - /// - /// The mocked scheduler. - /// - public static IScheduler MockScheduler => mockScheduler; - - /// - public Task GetScheduler(CancellationToken _) - { - return Task.FromResult(mockScheduler); - } - - /// - public Task GetScheduler(string schedName, CancellationToken _) - { - return Task.FromResult(mockScheduler); - } - - /// - public Task> GetAllSchedulers(CancellationToken _) - => Task.FromResult>(new List()); - - public static void Initialize() - { - mockScheduler = A.Fake(); - } - } - - /// - /// Scheduler factory that supports property interception. - /// - public class InterceptingStdSChedulerFactory : StdSchedulerFactory - { - private NameValueCollection properties; - - /// - public override void Initialize(NameValueCollection props) - { - properties = props; - } - - /// - /// Return propeties given to this factory at initialization time. - /// - public NameValueCollection Properties => properties; - } + public NameValueCollection Properties => properties; } diff --git a/test/Spring/Spring.Scheduling.Quartz3.Tests/Scheduling/Quartz/SimpleTriggerObjectTest.cs b/test/Spring/Spring.Scheduling.Quartz3.Tests/Scheduling/Quartz/SimpleTriggerObjectTest.cs index 53954d0f..3589c9ca 100644 --- a/test/Spring/Spring.Scheduling.Quartz3.Tests/Scheduling/Quartz/SimpleTriggerObjectTest.cs +++ b/test/Spring/Spring.Scheduling.Quartz3.Tests/Scheduling/Quartz/SimpleTriggerObjectTest.cs @@ -1,120 +1,118 @@ /* -* Copyright 2002-2010 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. -*/ + * Copyright 2002-2010 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. + */ using System.Collections; using NUnit.Framework; - using Quartz.Impl; -namespace Spring.Scheduling.Quartz +namespace Spring.Scheduling.Quartz; + +/// +/// Tests for . +/// +/// Marko Lahma (.NET) +[TestFixture] +public class SimpleTriggerObjectTest : TriggerObjectTest { + private SimpleTriggerObject simpleTrigger; + /// - /// Tests for . + /// Test setup. /// - /// Marko Lahma (.NET) - [TestFixture] - public class SimpleTriggerObjectTest : TriggerObjectTest + [SetUp] + public void SetUp() { - private SimpleTriggerObject simpleTrigger; + simpleTrigger = new SimpleTriggerObject(); + simpleTrigger.ObjectName = TRIGGER_NAME; + Trigger = simpleTrigger; + } - /// - /// Test setup. - /// - [SetUp] - public void SetUp() + /// + /// Tests all possible misfire instructions for cron trigger + /// from strings to int. + /// + [Test] + public void TestMisfireInstructionNames() + { + string[] names = new string[] { "FireNow", "RescheduleNextWithExistingCount", "RescheduleNextWithRemainingCount", "RescheduleNowWithExistingRepeatCount", "RescheduleNowWithRemainingRepeatCount", "SmartPolicy" }; + foreach (string name in names) { - simpleTrigger = new SimpleTriggerObject(); - simpleTrigger.ObjectName = TRIGGER_NAME; - Trigger = simpleTrigger; - } - - /// - /// Tests all possible misfire instructions for cron trigger - /// from strings to int. - /// - [Test] - public void TestMisfireInstructionNames() - { - string[] names = new string[] { "FireNow", "RescheduleNextWithExistingCount", "RescheduleNextWithRemainingCount", "RescheduleNowWithExistingRepeatCount", "RescheduleNowWithRemainingRepeatCount", "SmartPolicy" }; - foreach (string name in names) - { - simpleTrigger.MisfireInstructionName = name; - } - } - - /// - /// Tests AfterPropertiesSet behavior. - /// - [Test] - public override void TestAfterPropertiesSet_Defaults() - { - simpleTrigger.AfterPropertiesSet(); - base.TestAfterPropertiesSet_Defaults(); - } - - /// - /// Tests AfterPropertiesSet behavior. - /// - [Test] - public override void TestAfterPropertiesSet_ValuesGiven() - { - simpleTrigger.StartDelay = TimeSpan.FromMilliseconds(100); - simpleTrigger.AfterPropertiesSet(); - base.TestAfterPropertiesSet_ValuesGiven(); - } - - /// - /// Tests AfterPropertiesSet behavior. - /// - [Test] - public void TestAfterPropertiesSet_StartDelayGiven() - { - const int START_DELAY = 100000; - simpleTrigger.StartDelay = TimeSpan.FromMilliseconds(START_DELAY); - DateTime startTime = DateTime.UtcNow; - simpleTrigger.AfterPropertiesSet(); - AssertDateTimesEqualityWithAllowedDelta(startTime.AddMilliseconds(START_DELAY), simpleTrigger.StartTimeUtc, 1500); - } - - /// - /// Tests AfterPropertiesSet behavior. - /// - [Test] - public override void TestAfterPropertiesSet_JobDetailGiven() - { - const string jobName = "jobName"; - const string jobGroup = "jobGroup"; - JobDetailImpl jd = new JobDetailImpl(jobName, jobGroup, typeof(NoOpJob)); - simpleTrigger.JobDetail = jd; - simpleTrigger.AfterPropertiesSet(); - base.TestAfterPropertiesSet_JobDetailGiven(); - Assert.AreSame(jd, simpleTrigger.JobDetail, "job details weren't same"); - } - - /// - /// Tests AfterPropertiesSet behavior. - /// - [Test] - public void TestJobDataAsMap() - { - IDictionary data = new Dictionary(); - data["foo"] = "bar"; - data["number"] = 123; - simpleTrigger.JobDataAsMap = data; - CollectionAssert.AreEquivalent(data, simpleTrigger.JobDataMap, "Data differed"); + simpleTrigger.MisfireInstructionName = name; } } + + /// + /// Tests AfterPropertiesSet behavior. + /// + [Test] + public override void TestAfterPropertiesSet_Defaults() + { + simpleTrigger.AfterPropertiesSet(); + base.TestAfterPropertiesSet_Defaults(); + } + + /// + /// Tests AfterPropertiesSet behavior. + /// + [Test] + public override void TestAfterPropertiesSet_ValuesGiven() + { + simpleTrigger.StartDelay = TimeSpan.FromMilliseconds(100); + simpleTrigger.AfterPropertiesSet(); + base.TestAfterPropertiesSet_ValuesGiven(); + } + + /// + /// Tests AfterPropertiesSet behavior. + /// + [Test] + public void TestAfterPropertiesSet_StartDelayGiven() + { + const int START_DELAY = 100000; + simpleTrigger.StartDelay = TimeSpan.FromMilliseconds(START_DELAY); + DateTime startTime = DateTime.UtcNow; + simpleTrigger.AfterPropertiesSet(); + AssertDateTimesEqualityWithAllowedDelta(startTime.AddMilliseconds(START_DELAY), simpleTrigger.StartTimeUtc, 1500); + } + + /// + /// Tests AfterPropertiesSet behavior. + /// + [Test] + public override void TestAfterPropertiesSet_JobDetailGiven() + { + const string jobName = "jobName"; + const string jobGroup = "jobGroup"; + JobDetailImpl jd = new JobDetailImpl(jobName, jobGroup, typeof(NoOpJob)); + simpleTrigger.JobDetail = jd; + simpleTrigger.AfterPropertiesSet(); + base.TestAfterPropertiesSet_JobDetailGiven(); + Assert.AreSame(jd, simpleTrigger.JobDetail, "job details weren't same"); + } + + /// + /// Tests AfterPropertiesSet behavior. + /// + [Test] + public void TestJobDataAsMap() + { + IDictionary data = new Dictionary(); + data["foo"] = "bar"; + data["number"] = 123; + simpleTrigger.JobDataAsMap = data; + CollectionAssert.AreEquivalent(data, simpleTrigger.JobDataMap, "Data differed"); + } } diff --git a/test/Spring/Spring.Scheduling.Quartz3.Tests/Scheduling/Quartz/SpringObjectJobFactoryTest.cs b/test/Spring/Spring.Scheduling.Quartz3.Tests/Scheduling/Quartz/SpringObjectJobFactoryTest.cs index a8fdeb6e..cf5b84b8 100644 --- a/test/Spring/Spring.Scheduling.Quartz3.Tests/Scheduling/Quartz/SpringObjectJobFactoryTest.cs +++ b/test/Spring/Spring.Scheduling.Quartz3.Tests/Scheduling/Quartz/SpringObjectJobFactoryTest.cs @@ -1,119 +1,116 @@ /* -* Copyright 2002-2010 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. -*/ + * Copyright 2002-2010 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. + */ using NUnit.Framework; - using Quartz; using Quartz.Impl.Triggers; using Quartz.Spi; -namespace Spring.Scheduling.Quartz +namespace Spring.Scheduling.Quartz; + +/// +/// Unit tests for SpringObjectJobFactory. +/// +/// Marko Lahma (.NET) +[TestFixture] +public class SpringObjectJobFactoryTest { + private SpringObjectJobFactory factory; + /// - /// Unit tests for SpringObjectJobFactory. + /// Test setup. /// - /// Marko Lahma (.NET) - [TestFixture] - public class SpringObjectJobFactoryTest + [SetUp] + public void SetUp() { - private SpringObjectJobFactory factory; - - /// - /// Test setup. - /// - [SetUp] - public void SetUp() - { - factory = new SpringObjectJobFactory(); - } - - /// - /// Tests job instane creation. - /// - [Test] - public void TestCreateJobInstance_SimpleDefaults() - { - IOperableTrigger trigger = new SimpleTriggerImpl(); - TriggerFiredBundle bundle = TestUtil.CreateMinimalFiredBundleWithTypedJobDetail(typeof (NoOpJob), trigger); - - IJob job = factory.NewJob(bundle, null); - Assert.IsNotNull(job, "Created job was null"); - } - - /// - /// Tests job instane creation. - /// - [Test] - public void TestCreateJobInstance_SchedulerContextGiven() - { - IOperableTrigger trigger = new SimpleTriggerImpl(); - TriggerFiredBundle bundle = TestUtil.CreateMinimalFiredBundleWithTypedJobDetail(typeof(InjectableJob), trigger); - - IDictionary items = new Dictionary(); - items["foo"] = "bar"; - items["number"] = 123; - factory.SchedulerContext = new SchedulerContext(items); - InjectableJob job = (InjectableJob)factory.NewJob(bundle, null); - - Assert.IsNotNull(job, "Created job was null"); - Assert.AreEqual("bar", job.Foo, "string injection failed"); - Assert.AreEqual(123, job.Number, "integer injection failed"); - } - - /// - /// Tests job instane creation. - /// - [Test] - public void TestCreateJobInstance_IgnoredProperties() - { - factory.IgnoredUnknownProperties = new string[] {"foo", "baz"}; - IOperableTrigger trigger = new SimpleTriggerImpl(); - trigger.JobDataMap["foo"] = "should not be injected"; - trigger.JobDataMap["number"] = 123; - TriggerFiredBundle bundle = TestUtil.CreateMinimalFiredBundleWithTypedJobDetail(typeof(InjectableJob), trigger); - - InjectableJob job = (InjectableJob)factory.NewJob(bundle, null); - Assert.IsNotNull(job, "Created job was null"); - Assert.AreEqual(123, job.Number, "integer injection failed"); - Assert.IsNull(job.Foo, "foo was injected when it was not supposed to "); - } - - } - - public class NoOpJob : IJob - { - public Task Execute(IJobExecutionContext context) - { - return Task.FromResult(true); - } + factory = new SpringObjectJobFactory(); } /// - /// Test job object that has injectable properties + /// Tests job instane creation. /// - public class InjectableJob : NoOpJob + [Test] + public void TestCreateJobInstance_SimpleDefaults() { - /// - /// Simple int property. - /// - public int Number { get; set; } + IOperableTrigger trigger = new SimpleTriggerImpl(); + TriggerFiredBundle bundle = TestUtil.CreateMinimalFiredBundleWithTypedJobDetail(typeof(NoOpJob), trigger); - /// - /// Simple string property. - /// - public string Foo { get; set; } + IJob job = factory.NewJob(bundle, null); + Assert.IsNotNull(job, "Created job was null"); + } + + /// + /// Tests job instane creation. + /// + [Test] + public void TestCreateJobInstance_SchedulerContextGiven() + { + IOperableTrigger trigger = new SimpleTriggerImpl(); + TriggerFiredBundle bundle = TestUtil.CreateMinimalFiredBundleWithTypedJobDetail(typeof(InjectableJob), trigger); + + IDictionary items = new Dictionary(); + items["foo"] = "bar"; + items["number"] = 123; + factory.SchedulerContext = new SchedulerContext(items); + InjectableJob job = (InjectableJob) factory.NewJob(bundle, null); + + Assert.IsNotNull(job, "Created job was null"); + Assert.AreEqual("bar", job.Foo, "string injection failed"); + Assert.AreEqual(123, job.Number, "integer injection failed"); + } + + /// + /// Tests job instane creation. + /// + [Test] + public void TestCreateJobInstance_IgnoredProperties() + { + factory.IgnoredUnknownProperties = new string[] { "foo", "baz" }; + IOperableTrigger trigger = new SimpleTriggerImpl(); + trigger.JobDataMap["foo"] = "should not be injected"; + trigger.JobDataMap["number"] = 123; + TriggerFiredBundle bundle = TestUtil.CreateMinimalFiredBundleWithTypedJobDetail(typeof(InjectableJob), trigger); + + InjectableJob job = (InjectableJob) factory.NewJob(bundle, null); + Assert.IsNotNull(job, "Created job was null"); + Assert.AreEqual(123, job.Number, "integer injection failed"); + Assert.IsNull(job.Foo, "foo was injected when it was not supposed to "); } } + +public class NoOpJob : IJob +{ + public Task Execute(IJobExecutionContext context) + { + return Task.FromResult(true); + } +} + +/// +/// Test job object that has injectable properties +/// +public class InjectableJob : NoOpJob +{ + /// + /// Simple int property. + /// + public int Number { get; set; } + + /// + /// Simple string property. + /// + public string Foo { get; set; } +} diff --git a/test/Spring/Spring.Scheduling.Quartz3.Tests/Scheduling/Quartz/TestMethodInvokingTask.cs b/test/Spring/Spring.Scheduling.Quartz3.Tests/Scheduling/Quartz/TestMethodInvokingTask.cs index d3811a3d..05b0126e 100644 --- a/test/Spring/Spring.Scheduling.Quartz3.Tests/Scheduling/Quartz/TestMethodInvokingTask.cs +++ b/test/Spring/Spring.Scheduling.Quartz3.Tests/Scheduling/Quartz/TestMethodInvokingTask.cs @@ -14,59 +14,57 @@ * limitations under the License. */ -namespace Spring.Scheduling.Quartz +namespace Spring.Scheduling.Quartz; + +/// +/// Simple test task. +/// +/// Juergen Hoeller +public class TestMethodInvokingTask { + /// + /// Counter for DoSomething and DoWait calls. + /// + public int counter; + + private readonly object lockObject = new object(); /// - /// Simple test task. + /// Simple test method. /// - /// Juergen Hoeller - public class TestMethodInvokingTask + public void DoSomething() { - /// - /// Counter for DoSomething and DoWait calls. - /// - public int counter; - private readonly object lockObject = new object(); + counter++; + } - /// - /// Simple test method. - /// - public void DoSomething() + /// + /// Waits until stop is called. + /// + public void DoWait() + { + counter++; + // wait until stop is called + lock (lockObject) { - counter++; - } - - /// - /// Waits until stop is called. - /// - public void DoWait() - { - counter++; - // wait until stop is called - lock (lockObject) + try { - try - { - Monitor.Wait(lockObject); - } - catch (ThreadInterruptedException) - { - // fall through - } + Monitor.Wait(lockObject); + } + catch (ThreadInterruptedException) + { + // fall through } } + } - /// - /// Informs test object that stop should be called. - /// - public void Stop() + /// + /// Informs test object that stop should be called. + /// + public void Stop() + { + lock (lockObject) { - lock (lockObject) - { - Monitor.Pulse(lockObject); - } + Monitor.Pulse(lockObject); } - } } diff --git a/test/Spring/Spring.Scheduling.Quartz3.Tests/Scheduling/Quartz/TestUtil.cs b/test/Spring/Spring.Scheduling.Quartz3.Tests/Scheduling/Quartz/TestUtil.cs index 091f5725..0dd79e25 100644 --- a/test/Spring/Spring.Scheduling.Quartz3.Tests/Scheduling/Quartz/TestUtil.cs +++ b/test/Spring/Spring.Scheduling.Quartz3.Tests/Scheduling/Quartz/TestUtil.cs @@ -1,54 +1,53 @@ /* -* Copyright 2002-2010 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. -*/ + * Copyright 2002-2010 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. + */ using Quartz; using Quartz.Impl; using Quartz.Spi; -namespace Spring.Scheduling.Quartz +namespace Spring.Scheduling.Quartz; + +/// +/// Quartz.NET integration testing helpers. +/// +/// Marko Lahma (.NET) +public class TestUtil { /// - /// Quartz.NET integration testing helpers. + /// Creates the minimal fired bundle with job detail that has + /// given job type. /// - /// Marko Lahma (.NET) - public class TestUtil + /// Type of the job. + /// Minimal TriggerFiredBundle + public static TriggerFiredBundle CreateMinimalFiredBundleWithTypedJobDetail(Type jobType) { - /// - /// Creates the minimal fired bundle with job detail that has - /// given job type. - /// - /// Type of the job. - /// Minimal TriggerFiredBundle - public static TriggerFiredBundle CreateMinimalFiredBundleWithTypedJobDetail(Type jobType) - { - return CreateMinimalFiredBundleWithTypedJobDetail(jobType, null); - } + return CreateMinimalFiredBundleWithTypedJobDetail(jobType, null); + } - /// - /// Creates the minimal fired bundle with job detail that has - /// given job type. - /// - /// Type of the job. - /// The trigger. - /// Minimal TriggerFiredBundle - public static TriggerFiredBundle CreateMinimalFiredBundleWithTypedJobDetail(Type jobType, IOperableTrigger trigger) - { - IJobDetail jd = new JobDetailImpl("jobName", "jobGroup", jobType); - TriggerFiredBundle bundle = new TriggerFiredBundle(jd, trigger, null, false, DateTimeOffset.UtcNow, null, null, null); - return bundle; - } + /// + /// Creates the minimal fired bundle with job detail that has + /// given job type. + /// + /// Type of the job. + /// The trigger. + /// Minimal TriggerFiredBundle + public static TriggerFiredBundle CreateMinimalFiredBundleWithTypedJobDetail(Type jobType, IOperableTrigger trigger) + { + IJobDetail jd = new JobDetailImpl("jobName", "jobGroup", jobType); + TriggerFiredBundle bundle = new TriggerFiredBundle(jd, trigger, null, false, DateTimeOffset.UtcNow, null, null, null); + return bundle; } } diff --git a/test/Spring/Spring.Scheduling.Quartz3.Tests/Scheduling/Quartz/TriggerObjectTest.cs b/test/Spring/Spring.Scheduling.Quartz3.Tests/Scheduling/Quartz/TriggerObjectTest.cs index b9cbd8e8..5847399a 100644 --- a/test/Spring/Spring.Scheduling.Quartz3.Tests/Scheduling/Quartz/TriggerObjectTest.cs +++ b/test/Spring/Spring.Scheduling.Quartz3.Tests/Scheduling/Quartz/TriggerObjectTest.cs @@ -1,106 +1,103 @@ /* -* Copyright 2002-2010 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. -*/ + * Copyright 2002-2010 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. + */ using NUnit.Framework; - using Quartz; using Quartz.Spi; - using Spring.Objects.Factory; -namespace Spring.Scheduling.Quartz +namespace Spring.Scheduling.Quartz; + +/// +/// Base class for testing triggers. Contains common functionality. +/// +[TestFixture] +public abstract class TriggerObjectTest { + private IOperableTrigger trigger; + /// - /// Base class for testing triggers. Contains common functionality. + /// Constant name for tested triggers. /// - [TestFixture] - public abstract class TriggerObjectTest + protected const string TRIGGER_NAME = "trigger"; + + /// + /// TriggerObject under test. + /// + protected IOperableTrigger Trigger { - private IOperableTrigger trigger; + set { trigger = value; } + } - /// - /// Constant name for tested triggers. - /// - protected const string TRIGGER_NAME = "trigger"; + /// + /// Tests that TriggerObject defaults values as expected in AfterPropertiesSet. + /// + [Test] + public virtual void TestAfterPropertiesSet_Defaults() + { + ((IInitializingObject) trigger).AfterPropertiesSet(); - /// - /// TriggerObject under test. - /// - protected IOperableTrigger Trigger - { - set { trigger = value; } - } + Assert.AreEqual(TRIGGER_NAME, trigger.Key.Name, "trigger name mismatch"); + Assert.AreEqual(SchedulerConstants.DefaultGroup, trigger.Key.Group, "trigger group name mismatch"); + Assert.IsNull(trigger.JobKey, "trigger job name not null"); + AssertDateTimesEqualityWithAllowedDelta(DateTime.UtcNow, trigger.StartTimeUtc, 1500); + } - /// - /// Tests that TriggerObject defaults values as expected in AfterPropertiesSet. - /// - [Test] - public virtual void TestAfterPropertiesSet_Defaults() - { - ((IInitializingObject) trigger).AfterPropertiesSet(); + /// + /// Tests that TriggerObject defaults values as expected in AfterPropertiesSet. + /// + [Test] + public virtual void TestAfterPropertiesSet_ValuesGiven() + { + ((IInitializingObject) trigger).AfterPropertiesSet(); - Assert.AreEqual(TRIGGER_NAME, trigger.Key.Name, "trigger name mismatch"); - Assert.AreEqual(SchedulerConstants.DefaultGroup, trigger.Key.Group, "trigger group name mismatch"); - Assert.IsNull(trigger.JobKey, "trigger job name not null"); - AssertDateTimesEqualityWithAllowedDelta(DateTime.UtcNow, trigger.StartTimeUtc, 1500); - } + const string NAME = "newName"; + const string GROUP = "newGroup"; + DateTime START_TIME = new DateTime(1982, 6, 28, 13, 10, 0); + trigger.StartTimeUtc = START_TIME; + trigger.Key = new TriggerKey(NAME, GROUP); + Assert.AreEqual(NAME, trigger.Key.Name, "trigger name mismatch"); + Assert.AreEqual(GROUP, trigger.Key.Group, "trigger group name mismatch"); + AssertDateTimesEqualityWithAllowedDelta(START_TIME, trigger.StartTimeUtc, 1500); + } - /// - /// Tests that TriggerObject defaults values as expected in AfterPropertiesSet. - /// - [Test] - public virtual void TestAfterPropertiesSet_ValuesGiven() - { - ((IInitializingObject)trigger).AfterPropertiesSet(); + /// + /// Tests that TriggerObject defaults values as expected in AfterPropertiesSet. + /// + [Test] + public virtual void TestAfterPropertiesSet_JobDetailGiven() + { + ((IInitializingObject) trigger).AfterPropertiesSet(); - const string NAME = "newName"; - const string GROUP = "newGroup"; - DateTime START_TIME = new DateTime(1982, 6, 28, 13, 10, 0); - trigger.StartTimeUtc = START_TIME; - trigger.Key = new TriggerKey(NAME, GROUP); - Assert.AreEqual(NAME, trigger.Key.Name, "trigger name mismatch"); - Assert.AreEqual(GROUP, trigger.Key.Group, "trigger group name mismatch"); - AssertDateTimesEqualityWithAllowedDelta(START_TIME, trigger.StartTimeUtc, 1500); - } + const string jobName = "jobName"; + const string jobGroup = "jobGroup"; - /// - /// Tests that TriggerObject defaults values as expected in AfterPropertiesSet. - /// - [Test] - public virtual void TestAfterPropertiesSet_JobDetailGiven() - { - ((IInitializingObject)trigger).AfterPropertiesSet(); - - const string jobName = "jobName"; - const string jobGroup = "jobGroup"; + Assert.AreEqual(jobName, trigger.JobKey.Name, "trigger job name was not from job detail"); + Assert.AreEqual(jobGroup, trigger.JobKey.Group, "trigger job group was not from job detail"); + } - Assert.AreEqual(jobName, trigger.JobKey.Name, "trigger job name was not from job detail"); - Assert.AreEqual(jobGroup, trigger.JobKey.Group, "trigger job group was not from job detail"); - } - - /// - /// Tests whether two datetimes are close enough. - /// - /// - /// - /// - protected static void AssertDateTimesEqualityWithAllowedDelta(DateTimeOffset d1, DateTimeOffset d2, int allowedDeltaInMilliseconds) - { - int diffInMillis = (int) Math.Abs((d1 - d2).TotalMilliseconds); - Assert.LessOrEqual(diffInMillis, allowedDeltaInMilliseconds, "too much difference in times"); - } + /// + /// Tests whether two datetimes are close enough. + /// + /// + /// + /// + protected static void AssertDateTimesEqualityWithAllowedDelta(DateTimeOffset d1, DateTimeOffset d2, int allowedDeltaInMilliseconds) + { + int diffInMillis = (int) Math.Abs((d1 - d2).TotalMilliseconds); + Assert.LessOrEqual(diffInMillis, allowedDeltaInMilliseconds, "too much difference in times"); } } diff --git a/test/Spring/Spring.Scheduling.Quartz3.Tests/job-scheduling-data.xml b/test/Spring/Spring.Scheduling.Quartz3.Tests/job-scheduling-data.xml index 42bedecc..18ab1417 100644 --- a/test/Spring/Spring.Scheduling.Quartz3.Tests/job-scheduling-data.xml +++ b/test/Spring/Spring.Scheduling.Quartz3.Tests/job-scheduling-data.xml @@ -1,39 +1,39 @@  + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + version="2.0"> - - true - - - + + true + - - myJob - myGroup - Spring.Scheduling.Quartz.DummyJob, Spring.Scheduling.Quartz3.Tests - true - false - - - param - 10 - - - + - - - myTrigger - myGroup - myJob - myGroup - 1 - 500 - - + + myJob + myGroup + Spring.Scheduling.Quartz.DummyJob, Spring.Scheduling.Quartz3.Tests + true + false + + + param + 10 + + + - + + + myTrigger + myGroup + myJob + myGroup + 1 + 500 + + + + diff --git a/test/Spring/Spring.Scheduling.Quartz3.Tests/multipleAnonymousMethodInvokingJobDetailFB.xml b/test/Spring/Spring.Scheduling.Quartz3.Tests/multipleAnonymousMethodInvokingJobDetailFB.xml index b9ee8e4a..14c050be 100644 --- a/test/Spring/Spring.Scheduling.Quartz3.Tests/multipleAnonymousMethodInvokingJobDetailFB.xml +++ b/test/Spring/Spring.Scheduling.Quartz3.Tests/multipleAnonymousMethodInvokingJobDetailFB.xml @@ -1,45 +1,45 @@  + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.springframework.net http://www.springframework.net/xsd/spring-objects.xsd"> - - - - - - + + + + + + - - + + - - - - - - + + + + + + - - - - + + + + - - - - + + + + - - - - - - + + + + + + - + - + diff --git a/test/Spring/Spring.Scheduling.Quartz3.Tests/multipleSchedulers.xml b/test/Spring/Spring.Scheduling.Quartz3.Tests/multipleSchedulers.xml index 011fbff5..def4d1a6 100644 --- a/test/Spring/Spring.Scheduling.Quartz3.Tests/multipleSchedulers.xml +++ b/test/Spring/Spring.Scheduling.Quartz3.Tests/multipleSchedulers.xml @@ -1,16 +1,16 @@  + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.springframework.net http://www.springframework.net/xsd/spring-objects.xsd"> - - - + + + - - - + + + diff --git a/test/Spring/Spring.Scheduling.Quartz3.Tests/schedulerAccessorObject.xml b/test/Spring/Spring.Scheduling.Quartz3.Tests/schedulerAccessorObject.xml index 87a74cf5..a047d1ae 100644 --- a/test/Spring/Spring.Scheduling.Quartz3.Tests/schedulerAccessorObject.xml +++ b/test/Spring/Spring.Scheduling.Quartz3.Tests/schedulerAccessorObject.xml @@ -1,48 +1,48 @@  + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.springframework.net http://www.springframework.net/xsd/spring-objects.xsd"> - + - - - - - + + + + + - - - - + + + + - - - - - - - - - - + + + + + + + + + + - - + + - - - - - - - - + + + + + + + + - + - + diff --git a/test/Spring/Spring.Scheduling.Quartz3.Tests/schedulerRepositoryExposure.xml b/test/Spring/Spring.Scheduling.Quartz3.Tests/schedulerRepositoryExposure.xml index 1342c5d0..6e19db2a 100644 --- a/test/Spring/Spring.Scheduling.Quartz3.Tests/schedulerRepositoryExposure.xml +++ b/test/Spring/Spring.Scheduling.Quartz3.Tests/schedulerRepositoryExposure.xml @@ -1,52 +1,52 @@  + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.springframework.net http://www.springframework.net/xsd/spring-objects.xsd"> - - - - + + + + - - + + - - - - - - - + + + + + + + - + - - - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + - - + + - + - + diff --git a/test/Spring/Spring.Services.Tests/App.config b/test/Spring/Spring.Services.Tests/App.config index 2f93110c..8131d2cb 100644 --- a/test/Spring/Spring.Services.Tests/App.config +++ b/test/Spring/Spring.Services.Tests/App.config @@ -15,7 +15,7 @@ See the License for the specific language governing permissions and limitations under the License. --> - +
@@ -24,9 +24,9 @@ limitations under the License.
- + - + @@ -35,13 +35,13 @@ limitations under the License. - + - + - + @@ -54,5 +54,5 @@ limitations under the License. --> - + \ No newline at end of file diff --git a/test/Spring/Spring.Services.Tests/Data/Spring/Remoting/autowire.xml b/test/Spring/Spring.Services.Tests/Data/Spring/Remoting/autowire.xml index fc872c1e..4b9d3a39 100644 --- a/test/Spring/Spring.Services.Tests/Data/Spring/Remoting/autowire.xml +++ b/test/Spring/Spring.Services.Tests/Data/Spring/Remoting/autowire.xml @@ -1,39 +1,39 @@ - + - + - - - - + + + + - + - - - + + + - - - - - - - - + + + + + + + + - - - - + + + + - - - - + + + + \ No newline at end of file diff --git a/test/Spring/Spring.Services.Tests/Data/Spring/Remoting/cao.xml b/test/Spring/Spring.Services.Tests/Data/Spring/Remoting/cao.xml index 29610b35..41db9df2 100644 --- a/test/Spring/Spring.Services.Tests/Data/Spring/Remoting/cao.xml +++ b/test/Spring/Spring.Services.Tests/Data/Spring/Remoting/cao.xml @@ -1,43 +1,43 @@ - + - + - - - + + + - + - - + - - - - 7 - - + - + + + 7 + + + + \ No newline at end of file diff --git a/test/Spring/Spring.Services.Tests/Data/Spring/Remoting/caoLifetimeService.xml b/test/Spring/Spring.Services.Tests/Data/Spring/Remoting/caoLifetimeService.xml index a4ef8145..b457b1da 100644 --- a/test/Spring/Spring.Services.Tests/Data/Spring/Remoting/caoLifetimeService.xml +++ b/test/Spring/Spring.Services.Tests/Data/Spring/Remoting/caoLifetimeService.xml @@ -1,40 +1,40 @@ - + - + - - - + + + - - - + + + - - + - - - - + + + + + \ No newline at end of file diff --git a/test/Spring/Spring.Services.Tests/Data/Spring/Remoting/remotingConfigurer.xml b/test/Spring/Spring.Services.Tests/Data/Spring/Remoting/remotingConfigurer.xml index 951a60a4..36258706 100644 --- a/test/Spring/Spring.Services.Tests/Data/Spring/Remoting/remotingConfigurer.xml +++ b/test/Spring/Spring.Services.Tests/Data/Spring/Remoting/remotingConfigurer.xml @@ -1,15 +1,15 @@ - + - + - + \ No newline at end of file diff --git a/test/Spring/Spring.Services.Tests/Data/Spring/Remoting/saoLifetimeService.xml b/test/Spring/Spring.Services.Tests/Data/Spring/Remoting/saoLifetimeService.xml index 2b9d795c..ddf31f03 100644 --- a/test/Spring/Spring.Services.Tests/Data/Spring/Remoting/saoLifetimeService.xml +++ b/test/Spring/Spring.Services.Tests/Data/Spring/Remoting/saoLifetimeService.xml @@ -1,43 +1,43 @@ - + - + - - - + + + - - - + + + - + - - - - - + + + + + \ No newline at end of file diff --git a/test/Spring/Spring.Services.Tests/Data/Spring/Remoting/saoSingleCall.xml b/test/Spring/Spring.Services.Tests/Data/Spring/Remoting/saoSingleCall.xml index 3b728479..a62a705c 100644 --- a/test/Spring/Spring.Services.Tests/Data/Spring/Remoting/saoSingleCall.xml +++ b/test/Spring/Spring.Services.Tests/Data/Spring/Remoting/saoSingleCall.xml @@ -1,37 +1,37 @@ - + - + - - - + + + - + - - + - - + - + + + \ No newline at end of file diff --git a/test/Spring/Spring.Services.Tests/Data/Spring/Remoting/saoSingleton-aop.xml b/test/Spring/Spring.Services.Tests/Data/Spring/Remoting/saoSingleton-aop.xml index e3514d39..324556bc 100644 --- a/test/Spring/Spring.Services.Tests/Data/Spring/Remoting/saoSingleton-aop.xml +++ b/test/Spring/Spring.Services.Tests/Data/Spring/Remoting/saoSingleton-aop.xml @@ -1,81 +1,79 @@ - + - + - - - + + + - + - + - - - - - - - - - - - - - - - - countAdvisor - - - - - Spring.Remoting.ISimpleCounter, Spring.Services.Tests - - - - - - - - + + + - - - - - + + + + + + + + + + countAdvisor + + + + + Spring.Remoting.ISimpleCounter, Spring.Services.Tests + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/Spring/Spring.Services.Tests/Data/Spring/Remoting/saoSingleton-autowired.xml b/test/Spring/Spring.Services.Tests/Data/Spring/Remoting/saoSingleton-autowired.xml index 5c6b3dbd..12a9eead 100644 --- a/test/Spring/Spring.Services.Tests/Data/Spring/Remoting/saoSingleton-autowired.xml +++ b/test/Spring/Spring.Services.Tests/Data/Spring/Remoting/saoSingleton-autowired.xml @@ -1,16 +1,16 @@ + xmlns="http://www.springframework.net" + xmlns:r="http://www.springframework.net/remoting"> - + + --> + - - - + + + - + - + - - - + - + + + \ No newline at end of file diff --git a/test/Spring/Spring.Services.Tests/Data/Spring/Web/Services/configurableFactory.xml b/test/Spring/Spring.Services.Tests/Data/Spring/Web/Services/configurableFactory.xml index d87dd47c..2ba7d031 100644 --- a/test/Spring/Spring.Services.Tests/Data/Spring/Web/Services/configurableFactory.xml +++ b/test/Spring/Spring.Services.Tests/Data/Spring/Web/Services/configurableFactory.xml @@ -1,26 +1,30 @@ - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - + + + + + + + + + + \ No newline at end of file diff --git a/test/Spring/Spring.Services.Tests/Data/Spring/Web/Services/document-literal.wsdl b/test/Spring/Spring.Services.Tests/Data/Spring/Web/Services/document-literal.wsdl index 859f280a..df469023 100644 --- a/test/Spring/Spring.Services.Tests/Data/Spring/Web/Services/document-literal.wsdl +++ b/test/Spring/Spring.Services.Tests/Data/Spring/Web/Services/document-literal.wsdl @@ -1,209 +1,215 @@  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/Spring/Spring.Services.Tests/Data/Spring/Web/Services/nestedSchema.wsdl b/test/Spring/Spring.Services.Tests/Data/Spring/Web/Services/nestedSchema.wsdl index c0163225..09ba57bc 100644 --- a/test/Spring/Spring.Services.Tests/Data/Spring/Web/Services/nestedSchema.wsdl +++ b/test/Spring/Spring.Services.Tests/Data/Spring/Web/Services/nestedSchema.wsdl @@ -1,62 +1,71 @@  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/Spring/Spring.Services.Tests/Data/Spring/Web/Services/nestedSchema.xsd b/test/Spring/Spring.Services.Tests/Data/Spring/Web/Services/nestedSchema.xsd index 475746d9..87dc070f 100644 --- a/test/Spring/Spring.Services.Tests/Data/Spring/Web/Services/nestedSchema.xsd +++ b/test/Spring/Spring.Services.Tests/Data/Spring/Web/Services/nestedSchema.xsd @@ -1,18 +1,18 @@  - - - - - - - - - - - - + xmlns="http://myns" + targetNamespace="http://myns" + elementFormDefault="qualified" attributeFormDefault="unqualified"> + + + + + + + + + + + + \ No newline at end of file diff --git a/test/Spring/Spring.Services.Tests/Data/Spring/Web/Services/rpc-literal.wsdl b/test/Spring/Spring.Services.Tests/Data/Spring/Web/Services/rpc-literal.wsdl index 6fdab5a4..347aa73d 100644 --- a/test/Spring/Spring.Services.Tests/Data/Spring/Web/Services/rpc-literal.wsdl +++ b/test/Spring/Spring.Services.Tests/Data/Spring/Web/Services/rpc-literal.wsdl @@ -1,152 +1,158 @@  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/Spring/Spring.Services.Tests/Data/Spring/WindowsService/Cassini/localizer.xml b/test/Spring/Spring.Services.Tests/Data/Spring/WindowsService/Cassini/localizer.xml index e8875505..20d5caa4 100644 --- a/test/Spring/Spring.Services.Tests/Data/Spring/WindowsService/Cassini/localizer.xml +++ b/test/Spring/Spring.Services.Tests/Data/Spring/WindowsService/Cassini/localizer.xml @@ -1,6 +1,6 @@ - - + + \ No newline at end of file diff --git a/test/Spring/Spring.Services.Tests/Data/Spring/WindowsService/Cassini/service.config b/test/Spring/Spring.Services.Tests/Data/Spring/WindowsService/Cassini/service.config index 89a442fa..4a6c94e2 100644 --- a/test/Spring/Spring.Services.Tests/Data/Spring/WindowsService/Cassini/service.config +++ b/test/Spring/Spring.Services.Tests/Data/Spring/WindowsService/Cassini/service.config @@ -1,22 +1,22 @@ - - -
-
- - - - - - - - + + +
+
+ + - - - - - + + + + + + + + + + + diff --git a/test/Spring/Spring.Services.Tests/Data/Spring/WindowsService/Cassini/service.xml b/test/Spring/Spring.Services.Tests/Data/Spring/WindowsService/Cassini/service.xml index f42b3f2c..096804a6 100644 --- a/test/Spring/Spring.Services.Tests/Data/Spring/WindowsService/Cassini/service.xml +++ b/test/Spring/Spring.Services.Tests/Data/Spring/WindowsService/Cassini/service.xml @@ -1,6 +1,6 @@ - - + + - - - + + + diff --git a/test/Spring/Spring.Services.Tests/Data/Spring/WindowsService/Cassini/watcher.xml b/test/Spring/Spring.Services.Tests/Data/Spring/WindowsService/Cassini/watcher.xml index 16c4f45a..03c3a561 100644 --- a/test/Spring/Spring.Services.Tests/Data/Spring/WindowsService/Cassini/watcher.xml +++ b/test/Spring/Spring.Services.Tests/Data/Spring/WindowsService/Cassini/watcher.xml @@ -2,40 +2,40 @@ - - - + + + - + + + + + wwwroot/bin/*.* + service.config + service.xml + + + + - - - wwwroot/bin/*.* - service.config - service.xml - - - - - - + - \ No newline at end of file + \ No newline at end of file diff --git a/test/Spring/Spring.Services.Tests/Data/Spring/WindowsService/Echo/service.config b/test/Spring/Spring.Services.Tests/Data/Spring/WindowsService/Echo/service.config index 714332af..362433d4 100644 --- a/test/Spring/Spring.Services.Tests/Data/Spring/WindowsService/Echo/service.config +++ b/test/Spring/Spring.Services.Tests/Data/Spring/WindowsService/Echo/service.config @@ -2,22 +2,22 @@ - - -
-
- - - - - - + + +
+
+ + + + + + + + + + + + - - - - - - - \ No newline at end of file + \ No newline at end of file diff --git a/test/Spring/Spring.Services.Tests/Data/Spring/WindowsService/Echo/service.xml b/test/Spring/Spring.Services.Tests/Data/Spring/WindowsService/Echo/service.xml index 8a9ca1d7..67c243da 100644 --- a/test/Spring/Spring.Services.Tests/Data/Spring/WindowsService/Echo/service.xml +++ b/test/Spring/Spring.Services.Tests/Data/Spring/WindowsService/Echo/service.xml @@ -1,27 +1,29 @@ - - - - ${port} + + + + + ${port} + - - - file://~/service.config - - - - - appSettings - - - + + + file://~/service.config + + + + + appSettings + + + - + diff --git a/test/Spring/Spring.Services.Tests/Data/Spring/WindowsService/Echo/watcher.xml b/test/Spring/Spring.Services.Tests/Data/Spring/WindowsService/Echo/watcher.xml index 686e969c..e6ff0ab2 100644 --- a/test/Spring/Spring.Services.Tests/Data/Spring/WindowsService/Echo/watcher.xml +++ b/test/Spring/Spring.Services.Tests/Data/Spring/WindowsService/Echo/watcher.xml @@ -1,38 +1,38 @@ - + - - - + + + - + + + + + **/** + + + + - - - **/** - - - - - diff --git a/test/Spring/Spring.Services.Tests/Data/Spring/WindowsService/Simple/service.config b/test/Spring/Spring.Services.Tests/Data/Spring/WindowsService/Simple/service.config index d76f9bae..0c2febe3 100644 --- a/test/Spring/Spring.Services.Tests/Data/Spring/WindowsService/Simple/service.config +++ b/test/Spring/Spring.Services.Tests/Data/Spring/WindowsService/Simple/service.config @@ -1,19 +1,19 @@ - - -
-
- - - - - - - - - - + + +
+
+ + + + + + + + + + \ No newline at end of file diff --git a/test/Spring/Spring.Services.Tests/Data/Spring/WindowsService/Simple/service.xml b/test/Spring/Spring.Services.Tests/Data/Spring/WindowsService/Simple/service.xml index 0b0a5406..e4584e6a 100644 --- a/test/Spring/Spring.Services.Tests/Data/Spring/WindowsService/Simple/service.xml +++ b/test/Spring/Spring.Services.Tests/Data/Spring/WindowsService/Simple/service.xml @@ -1,33 +1,33 @@ - + - - - - - - - - - - - - - ${myPrefix.application.name} - - - ${myPrefix.application.fullpath} - + + + + + - - + + + + + + + ${myPrefix.application.name} + + + ${myPrefix.application.fullpath} + + + + - \ No newline at end of file + \ No newline at end of file diff --git a/test/Spring/Spring.Services.Tests/Data/Spring/WindowsService/Simple/watcher.xml b/test/Spring/Spring.Services.Tests/Data/Spring/WindowsService/Simple/watcher.xml index 686e969c..e6ff0ab2 100644 --- a/test/Spring/Spring.Services.Tests/Data/Spring/WindowsService/Simple/watcher.xml +++ b/test/Spring/Spring.Services.Tests/Data/Spring/WindowsService/Simple/watcher.xml @@ -1,38 +1,38 @@ - + - - - + + + - + + + + + **/** + + + + - - - **/** - - - - - diff --git a/test/Spring/Spring.Services.Tests/Data/Xml/watcher-0.xml b/test/Spring/Spring.Services.Tests/Data/Xml/watcher-0.xml index 268467c4..d750c1fb 100644 --- a/test/Spring/Spring.Services.Tests/Data/Xml/watcher-0.xml +++ b/test/Spring/Spring.Services.Tests/Data/Xml/watcher-0.xml @@ -1,4 +1,4 @@ - + diff --git a/test/Spring/Spring.Services.Tests/Data/Xml/watcher-1.xml b/test/Spring/Spring.Services.Tests/Data/Xml/watcher-1.xml index 325a405d..a7a5656e 100644 --- a/test/Spring/Spring.Services.Tests/Data/Xml/watcher-1.xml +++ b/test/Spring/Spring.Services.Tests/Data/Xml/watcher-1.xml @@ -1,23 +1,27 @@ - - - - - + + + + + + + + + - + - - **/** - - + + **/** + + - + diff --git a/test/Spring/Spring.Services.Tests/Data/Xml/watcher-simple.xml b/test/Spring/Spring.Services.Tests/Data/Xml/watcher-simple.xml index eedce295..ef49db70 100644 --- a/test/Spring/Spring.Services.Tests/Data/Xml/watcher-simple.xml +++ b/test/Spring/Spring.Services.Tests/Data/Xml/watcher-simple.xml @@ -1,26 +1,26 @@ - - - - - - - - foo/foo.bar - - - - - *.* - - + + + + + + + + foo/foo.bar + + + + + *.* + + - + diff --git a/test/Spring/Spring.Services.Tests/EnterpriseServices/ExeConfigurationSystemTests.config b/test/Spring/Spring.Services.Tests/EnterpriseServices/ExeConfigurationSystemTests.config index 05f4782e..27d90bac 100644 --- a/test/Spring/Spring.Services.Tests/EnterpriseServices/ExeConfigurationSystemTests.config +++ b/test/Spring/Spring.Services.Tests/EnterpriseServices/ExeConfigurationSystemTests.config @@ -4,7 +4,7 @@ -
+
@@ -12,12 +12,12 @@ - + - + diff --git a/test/Spring/Spring.Services.Tests/EnterpriseServices/ExeConfigurationSystemTests.cs b/test/Spring/Spring.Services.Tests/EnterpriseServices/ExeConfigurationSystemTests.cs index 7d378027..4e4ce798 100644 --- a/test/Spring/Spring.Services.Tests/EnterpriseServices/ExeConfigurationSystemTests.cs +++ b/test/Spring/Spring.Services.Tests/EnterpriseServices/ExeConfigurationSystemTests.cs @@ -23,34 +23,34 @@ using System.Configuration.Internal; using NUnit.Framework; using Spring.Util; -namespace Spring.EnterpriseServices -{ - [TestFixture] - public class ExeConfigurationSystemTests - { - [Test] - public void SunnyDay() - { - FileInfo resFile = TestResourceLoader.ExportResource(this, ".config", new FileInfo(Path.GetTempFileName()+".config")); - string exePath = resFile.FullName.Substring(0, resFile.FullName.Length - ".config".Length); - Assert.IsTrue(resFile.Exists); - IInternalConfigSystem prevConfig = null; - try - { - ExeConfigurationSystem ccs = new ExeConfigurationSystem(exePath); - prevConfig = ConfigurationUtils.SetConfigurationSystem(ccs, true); - Assert.AreEqual("from custom config!", ConfigurationManager.AppSettings["key"]); +namespace Spring.EnterpriseServices; - Assert.IsNull(ConfigurationManager.GetSection("spring/context")); - } - finally +[TestFixture] +public class ExeConfigurationSystemTests +{ + [Test] + public void SunnyDay() + { + FileInfo resFile = TestResourceLoader.ExportResource(this, ".config", new FileInfo(Path.GetTempFileName() + ".config")); + string exePath = resFile.FullName.Substring(0, resFile.FullName.Length - ".config".Length); + Assert.IsTrue(resFile.Exists); + IInternalConfigSystem prevConfig = null; + try + { + ExeConfigurationSystem ccs = new ExeConfigurationSystem(exePath); + prevConfig = ConfigurationUtils.SetConfigurationSystem(ccs, true); + Assert.AreEqual("from custom config!", ConfigurationManager.AppSettings["key"]); + + Assert.IsNull(ConfigurationManager.GetSection("spring/context")); + } + finally + { + if (prevConfig != null) { - if (prevConfig != null) - { - ConfigurationUtils.SetConfigurationSystem(prevConfig, true); - } - resFile.Delete(); + ConfigurationUtils.SetConfigurationSystem(prevConfig, true); } + + resFile.Delete(); } } } diff --git a/test/Spring/Spring.Services.Tests/EnterpriseServices/ExportedServicedComponentSample.cs b/test/Spring/Spring.Services.Tests/EnterpriseServices/ExportedServicedComponentSample.cs index db807436..e95d598f 100644 --- a/test/Spring/Spring.Services.Tests/EnterpriseServices/ExportedServicedComponentSample.cs +++ b/test/Spring/Spring.Services.Tests/EnterpriseServices/ExportedServicedComponentSample.cs @@ -25,45 +25,44 @@ using System.Reflection; /* The code below is only for reverse engineering generated code in reflector */ -namespace Spring.EnterpriseServices +namespace Spring.EnterpriseServices; + +internal interface ITestInterface { - internal interface ITestInterface - { - void Method(); - } - - internal delegate object GetObjectHandler(ServicedComponent component, string targetName); - - - internal class ExportedServicedComponentSample : ServicedComponent, ITestInterface - { - protected static GetObjectHandler getObject; - - static ExportedServicedComponentSample() - { - try - { - // in case we're dealing w/ unsigned assemblies, that is the way to go... - string path = Path.Combine( new FileInfo(Assembly.GetExecutingAssembly().Location).DirectoryName, "Spring.Services.dll"); - Assembly a = Assembly.LoadFrom(path); - if (a == null) - { - a = Assembly.Load("Spring.Services, Version=1.2.0.20001, Culture=neutral, PublicKeyToken=null"); - } - Type t = a.GetType("Spring.EnterpriseServices.ServicedComponentHelper", true); - getObject = (GetObjectHandler) Delegate.CreateDelegate(typeof(GetObjectHandler), t.GetMethod("GetObject")); - } - catch(Exception ex) - { - Trace.WriteLine(ex); - throw; - } - } - - public void Method() - { - ITestInterface targetInstance = (ITestInterface) getObject(null, "name"); - targetInstance.Method(); - } - } + void Method(); } + +internal delegate object GetObjectHandler(ServicedComponent component, string targetName); + +internal class ExportedServicedComponentSample : ServicedComponent, ITestInterface +{ + protected static GetObjectHandler getObject; + + static ExportedServicedComponentSample() + { + try + { + // in case we're dealing w/ unsigned assemblies, that is the way to go... + string path = Path.Combine(new FileInfo(Assembly.GetExecutingAssembly().Location).DirectoryName, "Spring.Services.dll"); + Assembly a = Assembly.LoadFrom(path); + if (a == null) + { + a = Assembly.Load("Spring.Services, Version=1.2.0.20001, Culture=neutral, PublicKeyToken=null"); + } + + Type t = a.GetType("Spring.EnterpriseServices.ServicedComponentHelper", true); + getObject = (GetObjectHandler) Delegate.CreateDelegate(typeof(GetObjectHandler), t.GetMethod("GetObject")); + } + catch (Exception ex) + { + Trace.WriteLine(ex); + throw; + } + } + + public void Method() + { + ITestInterface targetInstance = (ITestInterface) getObject(null, "name"); + targetInstance.Method(); + } +} \ No newline at end of file diff --git a/test/Spring/Spring.Services.Tests/EnterpriseServices/ServicedComponentExporterTests.cs b/test/Spring/Spring.Services.Tests/EnterpriseServices/ServicedComponentExporterTests.cs index a607023c..ad98cdcf 100644 --- a/test/Spring/Spring.Services.Tests/EnterpriseServices/ServicedComponentExporterTests.cs +++ b/test/Spring/Spring.Services.Tests/EnterpriseServices/ServicedComponentExporterTests.cs @@ -24,187 +24,182 @@ using System.Collections; using System.EnterpriseServices; using System.Reflection; using System.Reflection.Emit; - using AopAlliance.Intercept; using NUnit.Framework; - using Spring.Context; using Spring.Context.Support; using Spring.Objects; #endregion -namespace Spring.EnterpriseServices +namespace Spring.EnterpriseServices; + +/// +/// Unit tests for the ServicedComponentExporter class. +/// +/// Bruno Baia +[TestFixture] +public class ServicedComponentExporterTests { - /// - /// Unit tests for the ServicedComponentExporter class. - /// - /// Bruno Baia - [TestFixture] - public class ServicedComponentExporterTests + [TearDown] + public void TearDown() { - [TearDown] - public void TearDown() - { - ContextRegistry.Clear(); - } + ContextRegistry.Clear(); + } - [Test] - public void BailsWhenNotConfigured() + [Test] + public void BailsWhenNotConfigured() + { + ServicedComponentExporter exp = new ServicedComponentExporter(); + try { - ServicedComponentExporter exp = new ServicedComponentExporter(); - try - { - exp.AfterPropertiesSet(); - Assert.Fail("Did not throw expected ArgumentException!"); - } - catch (ArgumentException) - { - - } - - } - - [Test] - public void RegistersSimpleObjectWithNonDefaultTransactionOption() - { - ServicedComponentExporter exp = new ServicedComponentExporter(); - exp.TargetName = "objectTest"; - exp.ObjectName = "objectTestProxy"; - exp.TypeAttributes = new ArrayList(); - exp.TypeAttributes.Add(new TransactionAttribute(TransactionOption.RequiresNew)); exp.AfterPropertiesSet(); - - Type type = CreateWrapperType(exp, typeof(TestObject), false); - - TransactionAttribute[] attrs = (TransactionAttribute[])type.GetCustomAttributes(typeof(TransactionAttribute), false); - Assert.AreEqual(1, attrs.Length); - Assert.AreEqual(TransactionOption.RequiresNew, attrs[0].Value); + Assert.Fail("Did not throw expected ArgumentException!"); } - - [Test] - public void RegistersManagedObjectWithNonDefaultTransactionOption() + catch (ArgumentException) { - ServicedComponentExporter exp = new ServicedComponentExporter(); - exp.TargetName = "objectTest"; - exp.ObjectName = "objectTestProxy"; - exp.TypeAttributes = new ArrayList(); - exp.TypeAttributes.Add(new TransactionAttribute(TransactionOption.RequiresNew)); - exp.AfterPropertiesSet(); - - Type type = CreateWrapperType(exp, typeof(TestObject), true); - - TransactionAttribute[] attrs = (TransactionAttribute[])type.GetCustomAttributes(typeof(TransactionAttribute), false); - Assert.AreEqual(1, attrs.Length); - Assert.AreEqual(TransactionOption.RequiresNew, attrs[0].Value); } + } - [Test] - [Explicit("causes troubles due to registry pollution by COM registration")] - public void CanExportAopProxyToLibrary() + [Test] + public void RegistersSimpleObjectWithNonDefaultTransactionOption() + { + ServicedComponentExporter exp = new ServicedComponentExporter(); + exp.TargetName = "objectTest"; + exp.ObjectName = "objectTestProxy"; + exp.TypeAttributes = new ArrayList(); + exp.TypeAttributes.Add(new TransactionAttribute(TransactionOption.RequiresNew)); + exp.AfterPropertiesSet(); + + Type type = CreateWrapperType(exp, typeof(TestObject), false); + + TransactionAttribute[] attrs = (TransactionAttribute[]) type.GetCustomAttributes(typeof(TransactionAttribute), false); + Assert.AreEqual(1, attrs.Length); + Assert.AreEqual(TransactionOption.RequiresNew, attrs[0].Value); + } + + [Test] + public void RegistersManagedObjectWithNonDefaultTransactionOption() + { + ServicedComponentExporter exp = new ServicedComponentExporter(); + exp.TargetName = "objectTest"; + exp.ObjectName = "objectTestProxy"; + exp.TypeAttributes = new ArrayList(); + exp.TypeAttributes.Add(new TransactionAttribute(TransactionOption.RequiresNew)); + exp.AfterPropertiesSet(); + + Type type = CreateWrapperType(exp, typeof(TestObject), true); + + TransactionAttribute[] attrs = (TransactionAttribute[]) type.GetCustomAttributes(typeof(TransactionAttribute), false); + Assert.AreEqual(1, attrs.Length); + Assert.AreEqual(TransactionOption.RequiresNew, attrs[0].Value); + } + + [Test] + [Explicit("causes troubles due to registry pollution by COM registration")] + public void CanExportAopProxyToLibrary() + { + // NOTE: the method interceptor will return the number of method calls intercepted + FileInfo assemblyFile = new FileInfo("ServiceComponentExporterTests.TestServicedComponents.dll"); + XmlApplicationContext appCtx = new XmlApplicationContext("ServiceComponentExporterTests.TestServicedComponents.Services.xml"); + EnterpriseServicesExporter exporter = new EnterpriseServicesExporter(); + exporter.ActivationMode = ActivationOption.Library; + Type serviceType = ExportObject(exporter, assemblyFile, appCtx, "objectTest"); + try { - // NOTE: the method interceptor will return the number of method calls intercepted - FileInfo assemblyFile = new FileInfo("ServiceComponentExporterTests.TestServicedComponents.dll"); - XmlApplicationContext appCtx = new XmlApplicationContext("ServiceComponentExporterTests.TestServicedComponents.Services.xml"); - EnterpriseServicesExporter exporter = new EnterpriseServicesExporter(); - exporter.ActivationMode = ActivationOption.Library; - Type serviceType = ExportObject(exporter, assemblyFile, appCtx, "objectTest"); - try - { - // ServiceComponent will obtain its target from root context + // ServiceComponent will obtain its target from root context // ContextRegistry.RegisterContext(appCtx); - IComparable testObject; - testObject = (IComparable)Activator.CreateInstance(serviceType); - Assert.AreEqual(1, testObject.CompareTo(null)); - testObject = (IComparable)Activator.CreateInstance(serviceType); - Assert.AreEqual(2, testObject.CompareTo(null)); - } - finally - { - exporter.UnregisterServicedComponents(assemblyFile); - ContextRegistry.Clear(); - } + IComparable testObject; + testObject = (IComparable) Activator.CreateInstance(serviceType); + Assert.AreEqual(1, testObject.CompareTo(null)); + testObject = (IComparable) Activator.CreateInstance(serviceType); + Assert.AreEqual(2, testObject.CompareTo(null)); } - - [Test, Explicit("causes troubles due to registry pollution by COM registration")] - public void CanExportAopProxyToServer() + finally { - FileInfo assemblyFile = new FileInfo("ServiceComponentExporterTests.TestServicedComponents.exe"); - XmlApplicationContext appCtx = new XmlApplicationContext("ServiceComponentExporterTests.TestServicedComponents.Services.xml"); - EnterpriseServicesExporter exporter = new EnterpriseServicesExporter(); - exporter.ActivationMode = ActivationOption.Server; - Type serviceType = ExportObject(exporter, assemblyFile, appCtx, "objectTest"); - try - { - // ServiceComponent will obtain its target from root context - IComparable testObject; - testObject = (IComparable)Activator.CreateInstance(serviceType); - Assert.AreEqual(1, testObject.CompareTo(null)); - testObject = (IComparable)Activator.CreateInstance(serviceType); - Assert.AreEqual(2, testObject.CompareTo(null)); - } - finally - { - exporter.UnregisterServicedComponents(assemblyFile); - } + exporter.UnregisterServicedComponents(assemblyFile); + ContextRegistry.Clear(); } - - private Type ExportObject(EnterpriseServicesExporter exporter, FileInfo assemblyFile, IConfigurableApplicationContext appCtx, string objectName) - { - exporter.ObjectFactory = appCtx.ObjectFactory; - exporter.Assembly = Path.GetFileNameWithoutExtension(assemblyFile.Name); - exporter.ApplicationName = exporter.Assembly; - exporter.AccessControl = new ApplicationAccessControlAttribute(false); - exporter.UseSpring = true; - - ServicedComponentExporter exp = new ServicedComponentExporter(); - exp.TargetName = objectName; - exp.ObjectName = objectName + "Service"; - exp.TypeAttributes = new ArrayList(); - exp.TypeAttributes.Add(new TransactionAttribute(TransactionOption.RequiresNew)); - exp.AfterPropertiesSet(); - - exporter.Components.Add(exp); - - Assembly assembly = exporter.GenerateComponentAssembly(assemblyFile); - exporter.RegisterServicedComponents(assemblyFile); - return assembly.GetType(objectName + "Service"); - } - - #region Private helpers & classes - - public class CountingMethodInterceptor : IMethodInterceptor - { - private int Calls = 0; - - public object Invoke(IMethodInvocation invocation) - { - Calls++; - return Calls; - } - } - - private Type CreateWrapperType(ServicedComponentExporter exporter, Type targetType, bool useSpring) - { - AssemblyName an = new AssemblyName(); - an.Name = "Spring.EnterpriseServices.Tests"; - AssemblyBuilder proxyAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.RunAndSave); - ModuleBuilder module = proxyAssembly.DefineDynamicModule(an.Name, an.Name + ".dll", true); - - Type baseType = typeof(ServicedComponent); - if (useSpring) - { - baseType = EnterpriseServicesExporter.CreateSpringServicedComponentType(module, baseType); - } - - object result = exporter.CreateWrapperType(module, baseType, targetType, useSpring); - Assert.IsNotNull(result); - Assert.IsTrue(result is Type); - - return (Type)result; - } - - #endregion } + + [Test, Explicit("causes troubles due to registry pollution by COM registration")] + public void CanExportAopProxyToServer() + { + FileInfo assemblyFile = new FileInfo("ServiceComponentExporterTests.TestServicedComponents.exe"); + XmlApplicationContext appCtx = new XmlApplicationContext("ServiceComponentExporterTests.TestServicedComponents.Services.xml"); + EnterpriseServicesExporter exporter = new EnterpriseServicesExporter(); + exporter.ActivationMode = ActivationOption.Server; + Type serviceType = ExportObject(exporter, assemblyFile, appCtx, "objectTest"); + try + { + // ServiceComponent will obtain its target from root context + IComparable testObject; + testObject = (IComparable) Activator.CreateInstance(serviceType); + Assert.AreEqual(1, testObject.CompareTo(null)); + testObject = (IComparable) Activator.CreateInstance(serviceType); + Assert.AreEqual(2, testObject.CompareTo(null)); + } + finally + { + exporter.UnregisterServicedComponents(assemblyFile); + } + } + + private Type ExportObject(EnterpriseServicesExporter exporter, FileInfo assemblyFile, IConfigurableApplicationContext appCtx, string objectName) + { + exporter.ObjectFactory = appCtx.ObjectFactory; + exporter.Assembly = Path.GetFileNameWithoutExtension(assemblyFile.Name); + exporter.ApplicationName = exporter.Assembly; + exporter.AccessControl = new ApplicationAccessControlAttribute(false); + exporter.UseSpring = true; + + ServicedComponentExporter exp = new ServicedComponentExporter(); + exp.TargetName = objectName; + exp.ObjectName = objectName + "Service"; + exp.TypeAttributes = new ArrayList(); + exp.TypeAttributes.Add(new TransactionAttribute(TransactionOption.RequiresNew)); + exp.AfterPropertiesSet(); + + exporter.Components.Add(exp); + + Assembly assembly = exporter.GenerateComponentAssembly(assemblyFile); + exporter.RegisterServicedComponents(assemblyFile); + return assembly.GetType(objectName + "Service"); + } + + #region Private helpers & classes + + public class CountingMethodInterceptor : IMethodInterceptor + { + private int Calls = 0; + + public object Invoke(IMethodInvocation invocation) + { + Calls++; + return Calls; + } + } + + private Type CreateWrapperType(ServicedComponentExporter exporter, Type targetType, bool useSpring) + { + AssemblyName an = new AssemblyName(); + an.Name = "Spring.EnterpriseServices.Tests"; + AssemblyBuilder proxyAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.RunAndSave); + ModuleBuilder module = proxyAssembly.DefineDynamicModule(an.Name, an.Name + ".dll", true); + + Type baseType = typeof(ServicedComponent); + if (useSpring) + { + baseType = EnterpriseServicesExporter.CreateSpringServicedComponentType(module, baseType); + } + + object result = exporter.CreateWrapperType(module, baseType, targetType, useSpring); + Assert.IsNotNull(result); + Assert.IsTrue(result is Type); + + return (Type) result; + } + + #endregion } diff --git a/test/Spring/Spring.Services.Tests/Remoting/BaseRemotingTestFixture.cs b/test/Spring/Spring.Services.Tests/Remoting/BaseRemotingTestFixture.cs index 2987e2cd..c4898752 100644 --- a/test/Spring/Spring.Services.Tests/Remoting/BaseRemotingTestFixture.cs +++ b/test/Spring/Spring.Services.Tests/Remoting/BaseRemotingTestFixture.cs @@ -3,46 +3,46 @@ using System.Runtime.Remoting.Channels.Tcp; using NUnit.Framework; using Spring.Context.Support; -namespace Spring.Remoting -{ - public class BaseRemotingTestFixture - { - protected static TcpChannel channel; - private static object lockObject = new object(); +namespace Spring.Remoting; - [OneTimeSetUp] - public virtual void FixtureSetUp() +public class BaseRemotingTestFixture +{ + protected static TcpChannel channel; + private static object lockObject = new object(); + + [OneTimeSetUp] + public virtual void FixtureSetUp() + { + lock (lockObject) { - lock (lockObject) + if (channel == null) { - if (channel == null) + try { - try + foreach (IChannel registeredChannel in ChannelServices.RegisteredChannels) { - foreach (IChannel registeredChannel in ChannelServices.RegisteredChannels) + if (registeredChannel is TcpChannel) { - if (registeredChannel is TcpChannel) - { - ((TcpChannel) registeredChannel).StopListening(null); - } - ChannelServices.UnregisterChannel(registeredChannel); + ((TcpChannel) registeredChannel).StopListening(null); } - channel = new TcpChannel(8005); - ChannelServices.RegisterChannel(channel, false); - } - catch - { - // ignore duplicate registration exception if it occurs... + ChannelServices.UnregisterChannel(registeredChannel); } + + channel = new TcpChannel(8005); + ChannelServices.RegisterChannel(channel, false); + } + catch + { + // ignore duplicate registration exception if it occurs... } } } + } - [TearDown] - public virtual void TearDown() - { - ContextRegistry.Clear(); - } + [TearDown] + public virtual void TearDown() + { + ContextRegistry.Clear(); } } \ No newline at end of file diff --git a/test/Spring/Spring.Services.Tests/Remoting/CaoExporterTests.cs b/test/Spring/Spring.Services.Tests/Remoting/CaoExporterTests.cs index bb475f1a..b468a479 100644 --- a/test/Spring/Spring.Services.Tests/Remoting/CaoExporterTests.cs +++ b/test/Spring/Spring.Services.Tests/Remoting/CaoExporterTests.cs @@ -21,60 +21,57 @@ #region Imports using System.Runtime.Remoting.Lifetime; - using NUnit.Framework; - using Spring.Context; using Spring.Context.Support; using Spring.Remoting.Support; #endregion -namespace Spring.Remoting +namespace Spring.Remoting; + +/// +/// Unit tests for the CaoExporter class. +/// +/// Bruno Baia +[TestFixture] +public class CaoExporterTests : BaseRemotingTestFixture { - /// - /// Unit tests for the CaoExporter class. - /// - /// Bruno Baia - [TestFixture] - public class CaoExporterTests : BaseRemotingTestFixture + [Test] + public void BailsWhenNotConfigured() { - [Test] - public void BailsWhenNotConfigured() - { - CaoExporter exp = new CaoExporter(); - Assert.Throws(() => exp.AfterPropertiesSet()); - } + CaoExporter exp = new CaoExporter(); + Assert.Throws(() => exp.AfterPropertiesSet()); + } - [Test] - public void RegistersSimpleObject() - { - IApplicationContext ctx = new XmlApplicationContext("assembly://Spring.Services.Tests/Spring.Data.Spring.Remoting/caoLifetimeService.xml"); - ContextRegistry.RegisterContext(ctx); + [Test] + public void RegistersSimpleObject() + { + IApplicationContext ctx = new XmlApplicationContext("assembly://Spring.Services.Tests/Spring.Data.Spring.Remoting/caoLifetimeService.xml"); + ContextRegistry.RegisterContext(ctx); - ICaoRemoteFactory caoFactory = Activator.GetObject(typeof(ICaoRemoteFactory), "tcp://localhost:8005/counter2") as ICaoRemoteFactory; - Assert.IsNotNull(caoFactory, "Cao factory is null even though it has been registered."); + ICaoRemoteFactory caoFactory = Activator.GetObject(typeof(ICaoRemoteFactory), "tcp://localhost:8005/counter2") as ICaoRemoteFactory; + Assert.IsNotNull(caoFactory, "Cao factory is null even though it has been registered."); - MarshalByRefObject cao = caoFactory.GetObject() as MarshalByRefObject; - Assert.IsNotNull(cao); - } + MarshalByRefObject cao = caoFactory.GetObject() as MarshalByRefObject; + Assert.IsNotNull(cao); + } - [Test] - public void RegistersWithLifetimeService() - { - IApplicationContext ctx = new XmlApplicationContext("assembly://Spring.Services.Tests/Spring.Data.Spring.Remoting/caoLifetimeService.xml"); - ContextRegistry.RegisterContext(ctx); + [Test] + public void RegistersWithLifetimeService() + { + IApplicationContext ctx = new XmlApplicationContext("assembly://Spring.Services.Tests/Spring.Data.Spring.Remoting/caoLifetimeService.xml"); + ContextRegistry.RegisterContext(ctx); - ICaoRemoteFactory caoFactory = Activator.GetObject(typeof(ICaoRemoteFactory), "tcp://localhost:8005/counter2") as ICaoRemoteFactory; - Assert.IsNotNull(caoFactory, "Cao factory is null even though it has been registered."); + ICaoRemoteFactory caoFactory = Activator.GetObject(typeof(ICaoRemoteFactory), "tcp://localhost:8005/counter2") as ICaoRemoteFactory; + Assert.IsNotNull(caoFactory, "Cao factory is null even though it has been registered."); - MarshalByRefObject cao = caoFactory.GetObject() as MarshalByRefObject; - Assert.IsNotNull(cao); + MarshalByRefObject cao = caoFactory.GetObject() as MarshalByRefObject; + Assert.IsNotNull(cao); - ILease lease = (ILease) cao.GetLifetimeService(); - Assert.AreEqual(TimeSpan.FromMilliseconds(10000), lease.InitialLeaseTime, "InitialLeaseTime"); - Assert.AreEqual(TimeSpan.FromMilliseconds(1000), lease.RenewOnCallTime, "RenewOnCallTime"); - Assert.AreEqual(TimeSpan.FromMilliseconds(100), lease.SponsorshipTimeout, "SponsorshipTimeout"); - } + ILease lease = (ILease) cao.GetLifetimeService(); + Assert.AreEqual(TimeSpan.FromMilliseconds(10000), lease.InitialLeaseTime, "InitialLeaseTime"); + Assert.AreEqual(TimeSpan.FromMilliseconds(1000), lease.RenewOnCallTime, "RenewOnCallTime"); + Assert.AreEqual(TimeSpan.FromMilliseconds(100), lease.SponsorshipTimeout, "SponsorshipTimeout"); } } diff --git a/test/Spring/Spring.Services.Tests/Remoting/CaoFactoryObjectTests.cs b/test/Spring/Spring.Services.Tests/Remoting/CaoFactoryObjectTests.cs index 71c9b4ab..7b2feb4a 100644 --- a/test/Spring/Spring.Services.Tests/Remoting/CaoFactoryObjectTests.cs +++ b/test/Spring/Spring.Services.Tests/Remoting/CaoFactoryObjectTests.cs @@ -21,56 +21,54 @@ #region Imports using NUnit.Framework; - using Spring.Context; using Spring.Context.Support; #endregion -namespace Spring.Remoting +namespace Spring.Remoting; + +/// +/// Unit tests for the CaoFactoryObject class. +/// +/// Bruno Baia +[TestFixture] +public class CaoFactoryObjectTests : BaseRemotingTestFixture { - /// - /// Unit tests for the CaoFactoryObject class. - /// - /// Bruno Baia - [TestFixture] - public class CaoFactoryObjectTests : BaseRemotingTestFixture + [Test] + public void BailsWhenNotConfigured() { - [Test] - public void BailsWhenNotConfigured() - { - CaoFactoryObject cfo = new CaoFactoryObject(); - Assert.Throws(() => cfo.AfterPropertiesSet()); - } + CaoFactoryObject cfo = new CaoFactoryObject(); + Assert.Throws(() => cfo.AfterPropertiesSet()); + } - [Test] - public void GetSimpleObject() - { - IApplicationContext ctx = new XmlApplicationContext("assembly://Spring.Services.Tests/Spring.Data.Spring.Remoting/cao.xml"); - ContextRegistry.RegisterContext(ctx); + [Test] + public void GetSimpleObject() + { + IApplicationContext ctx = new XmlApplicationContext("assembly://Spring.Services.Tests/Spring.Data.Spring.Remoting/cao.xml"); + ContextRegistry.RegisterContext(ctx); - object obj = ctx.GetObject("remoteCaoCounter1"); + object obj = ctx.GetObject("remoteCaoCounter1"); - Assert.IsNotNull(obj, "Object is null even though a object has been registered."); - Assert.IsTrue((obj is ISimpleCounter), "Object should implement 'ISimpleCounter' interface."); + Assert.IsNotNull(obj, "Object is null even though a object has been registered."); + Assert.IsTrue((obj is ISimpleCounter), "Object should implement 'ISimpleCounter' interface."); - ISimpleCounter sc = (ISimpleCounter) obj; - Assert.AreEqual(7, sc.Counter, "Remote object hasn't been activated by the client."); - sc.Count(); - Assert.AreEqual(8, sc.Counter); - } + ISimpleCounter sc = (ISimpleCounter) obj; + Assert.AreEqual(7, sc.Counter, "Remote object hasn't been activated by the client."); + sc.Count(); + Assert.AreEqual(8, sc.Counter); + } - [Test] - public void DisconnectFromClient() - { - IApplicationContext ctx = new XmlApplicationContext("assembly://Spring.Services.Tests/Spring.Data.Spring.Remoting/cao.xml"); - ContextRegistry.RegisterContext(ctx); + [Test] + public void DisconnectFromClient() + { + IApplicationContext ctx = new XmlApplicationContext("assembly://Spring.Services.Tests/Spring.Data.Spring.Remoting/cao.xml"); + ContextRegistry.RegisterContext(ctx); - object obj = ctx.GetObject("remoteCaoCounter1"); - Assert.IsNotNull(obj, "CAO is null even though a CAO has been registered."); + object obj = ctx.GetObject("remoteCaoCounter1"); + Assert.IsNotNull(obj, "CAO is null even though a CAO has been registered."); - IDisposable cao = obj as IDisposable; - Assert.IsNotNull(cao, "CAO should implement 'IDisposable' interface."); - } + IDisposable cao = obj as IDisposable; + Assert.IsNotNull(cao, "CAO should implement 'IDisposable' interface."); } } diff --git a/test/Spring/Spring.Services.Tests/Remoting/ISimpleCounter.cs b/test/Spring/Spring.Services.Tests/Remoting/ISimpleCounter.cs index 2033f6a8..6d08ab0b 100644 --- a/test/Spring/Spring.Services.Tests/Remoting/ISimpleCounter.cs +++ b/test/Spring/Spring.Services.Tests/Remoting/ISimpleCounter.cs @@ -20,21 +20,19 @@ #region Imports - #endregion -namespace Spring.Remoting -{ - public interface ISimpleCounter - { - /// - /// Gets or Sets the Counter's value. - /// - int Counter { get; set; } +namespace Spring.Remoting; - /// - /// Increments the counter by one. - /// - void Count(); - } +public interface ISimpleCounter +{ + /// + /// Gets or Sets the Counter's value. + /// + int Counter { get; set; } + + /// + /// Increments the counter by one. + /// + void Count(); } \ No newline at end of file diff --git a/test/Spring/Spring.Services.Tests/Remoting/RemoteObjectFactoryTests.cs b/test/Spring/Spring.Services.Tests/Remoting/RemoteObjectFactoryTests.cs index 6afe2958..00c56e64 100644 --- a/test/Spring/Spring.Services.Tests/Remoting/RemoteObjectFactoryTests.cs +++ b/test/Spring/Spring.Services.Tests/Remoting/RemoteObjectFactoryTests.cs @@ -21,66 +21,64 @@ #region Imports using System.Runtime.Remoting.Lifetime; - using NUnit.Framework; #endregion -namespace Spring.Remoting +namespace Spring.Remoting; + +/// +/// Unit tests for the RemoteObjectFactory class. +/// +/// Bruno Baia +[TestFixture] +public class RemoteObjectFactoryTests { - /// - /// Unit tests for the RemoteObjectFactory class. - /// - /// Bruno Baia - [TestFixture] - public class RemoteObjectFactoryTests + [Test] + public void BailsWhenNotConfigured() { - [Test] - public void BailsWhenNotConfigured() - { - RemoteObjectFactory factory = new RemoteObjectFactory(); - Assert.Throws(() => factory.AfterPropertiesSet(), "The Target property is required."); - } + RemoteObjectFactory factory = new RemoteObjectFactory(); + Assert.Throws(() => factory.AfterPropertiesSet(), "The Target property is required."); + } - [Test] - public void CreateRemoteObject() - { - RemoteObjectFactory factory = new RemoteObjectFactory(); - factory.Target = new SimpleCounter(); - factory.AfterPropertiesSet(); + [Test] + public void CreateRemoteObject() + { + RemoteObjectFactory factory = new RemoteObjectFactory(); + factory.Target = new SimpleCounter(); + factory.AfterPropertiesSet(); - object obj = factory.GetObject(); + object obj = factory.GetObject(); - Assert.IsTrue((obj is MarshalByRefObject), "Object should derive from MarshalByRefObject."); - } + Assert.IsTrue((obj is MarshalByRefObject), "Object should derive from MarshalByRefObject."); + } - [Test] - public void ReturnsInterfaceImplementation() - { - RemoteObjectFactory factory = new RemoteObjectFactory(); - factory.Target = new SimpleCounter(); - factory.AfterPropertiesSet(); + [Test] + public void ReturnsInterfaceImplementation() + { + RemoteObjectFactory factory = new RemoteObjectFactory(); + factory.Target = new SimpleCounter(); + factory.AfterPropertiesSet(); - object obj = factory.GetObject(); + object obj = factory.GetObject(); - Assert.IsTrue((obj is ISimpleCounter), "Object should implement an interface."); - } + Assert.IsTrue((obj is ISimpleCounter), "Object should implement an interface."); + } - [Test] - public void CreateRemoteObjectWithLeaseInfo() - { - RemoteObjectFactory factory = new RemoteObjectFactory(); - factory.Target = new SimpleCounter(); - factory.Infinite = false; - factory.InitialLeaseTime = TimeSpan.FromMilliseconds(10000); - factory.RenewOnCallTime = TimeSpan.FromMilliseconds(1000); - factory.SponsorshipTimeout = TimeSpan.FromMilliseconds(100); - MarshalByRefObject remoteObject = (MarshalByRefObject) factory.GetObject(); + [Test] + public void CreateRemoteObjectWithLeaseInfo() + { + RemoteObjectFactory factory = new RemoteObjectFactory(); + factory.Target = new SimpleCounter(); + factory.Infinite = false; + factory.InitialLeaseTime = TimeSpan.FromMilliseconds(10000); + factory.RenewOnCallTime = TimeSpan.FromMilliseconds(1000); + factory.SponsorshipTimeout = TimeSpan.FromMilliseconds(100); + MarshalByRefObject remoteObject = (MarshalByRefObject) factory.GetObject(); - ILease lease = (ILease) remoteObject.InitializeLifetimeService(); - Assert.AreEqual(TimeSpan.FromMilliseconds(10000), lease.InitialLeaseTime, "InitialLeaseTime"); - Assert.AreEqual(TimeSpan.FromMilliseconds(1000), lease.RenewOnCallTime, "RenewOnCallTime"); - Assert.AreEqual(TimeSpan.FromMilliseconds(100), lease.SponsorshipTimeout, "SponsorshipTimeout"); - } + ILease lease = (ILease) remoteObject.InitializeLifetimeService(); + Assert.AreEqual(TimeSpan.FromMilliseconds(10000), lease.InitialLeaseTime, "InitialLeaseTime"); + Assert.AreEqual(TimeSpan.FromMilliseconds(1000), lease.RenewOnCallTime, "RenewOnCallTime"); + Assert.AreEqual(TimeSpan.FromMilliseconds(100), lease.SponsorshipTimeout, "SponsorshipTimeout"); } } diff --git a/test/Spring/Spring.Services.Tests/Remoting/RemotingConfigParserTests.cs b/test/Spring/Spring.Services.Tests/Remoting/RemotingConfigParserTests.cs index d068d81f..30bcfc9a 100644 --- a/test/Spring/Spring.Services.Tests/Remoting/RemotingConfigParserTests.cs +++ b/test/Spring/Spring.Services.Tests/Remoting/RemotingConfigParserTests.cs @@ -24,14 +24,13 @@ using NUnit.Framework; #endregion -namespace Spring.Remoting +namespace Spring.Remoting; + +/// +/// Unit tests for the RemotingConfigParserTests class. +/// +/// Bruno Baia +[TestFixture] +public class RemotingConfigParserTests { - /// - /// Unit tests for the RemotingConfigParserTests class. - /// - /// Bruno Baia - [TestFixture] - public class RemotingConfigParserTests - { - } } diff --git a/test/Spring/Spring.Services.Tests/Remoting/RemotingConfigurerTests.cs b/test/Spring/Spring.Services.Tests/Remoting/RemotingConfigurerTests.cs index ebce1dcf..9302bf52 100644 --- a/test/Spring/Spring.Services.Tests/Remoting/RemotingConfigurerTests.cs +++ b/test/Spring/Spring.Services.Tests/Remoting/RemotingConfigurerTests.cs @@ -27,29 +27,28 @@ using Spring.Context.Support; #endregion -namespace Spring.Remoting +namespace Spring.Remoting; + +/// +/// Unit tests for the RemotingConfigurerTests class. +/// +/// Bruno Baia +[TestFixture] +public class RemotingConfigurerTests : BaseRemotingTestFixture { - /// - /// Unit tests for the RemotingConfigurerTests class. - /// - /// Bruno Baia - [TestFixture] - public class RemotingConfigurerTests : BaseRemotingTestFixture - { - [Test] - [Explicit] - public void ConfiguresUsingFilename() - { - Assert.AreEqual(1, ChannelServices.RegisteredChannels.Length); - Assert.AreEqual(channel, ChannelServices.RegisteredChannels[0]); - ChannelServices.UnregisterChannel(channel); - Assert.AreEqual(0, ChannelServices.RegisteredChannels.Length); + [Test] + [Explicit] + public void ConfiguresUsingFilename() + { + Assert.AreEqual(1, ChannelServices.RegisteredChannels.Length); + Assert.AreEqual(channel, ChannelServices.RegisteredChannels[0]); + ChannelServices.UnregisterChannel(channel); + Assert.AreEqual(0, ChannelServices.RegisteredChannels.Length); - IApplicationContext ctx = new XmlApplicationContext("assembly://Spring.Services.Tests/Spring.Data.Spring.Remoting/remotingConfigurer.xml"); - ContextRegistry.RegisterContext(ctx); + IApplicationContext ctx = new XmlApplicationContext("assembly://Spring.Services.Tests/Spring.Data.Spring.Remoting/remotingConfigurer.xml"); + ContextRegistry.RegisterContext(ctx); - Assert.AreEqual(1, ChannelServices.RegisteredChannels.Length); - Assert.AreEqual("tcp", ChannelServices.RegisteredChannels[0].ChannelName); - } - } + Assert.AreEqual(1, ChannelServices.RegisteredChannels.Length); + Assert.AreEqual("tcp", ChannelServices.RegisteredChannels[0].ChannelName); + } } diff --git a/test/Spring/Spring.Services.Tests/Remoting/SaoExporterTests.cs b/test/Spring/Spring.Services.Tests/Remoting/SaoExporterTests.cs index b8559b84..d2de28d9 100644 --- a/test/Spring/Spring.Services.Tests/Remoting/SaoExporterTests.cs +++ b/test/Spring/Spring.Services.Tests/Remoting/SaoExporterTests.cs @@ -21,9 +21,7 @@ #region Imports using FakeItEasy; - using NUnit.Framework; - using Spring.Core.IO; using Spring.Objects.Factory; using Spring.Objects.Factory.Support; @@ -31,107 +29,106 @@ using Spring.Objects.Factory.Xml; #endregion -namespace Spring.Remoting +namespace Spring.Remoting; + +/// +/// Unit tests for the SaoExporter class. +/// +/// Bruno Baia +/// Mark Pollack +[TestFixture] +public class SaoExporterTests : BaseRemotingTestFixture { - /// - /// Unit tests for the SaoExporter class. - /// - /// Bruno Baia - /// Mark Pollack - [TestFixture] - public class SaoExporterTests : BaseRemotingTestFixture + [Test] + public void BailsWhenNotConfigured() { - [Test] - public void BailsWhenNotConfigured() + SaoExporter exp = new SaoExporter(); + Assert.Throws(() => exp.AfterPropertiesSet()); + } + + [Test] + public void BailsIfTargetNotFound() + { + using (DefaultListableObjectFactory of = new DefaultListableObjectFactory()) { - SaoExporter exp = new SaoExporter(); - Assert.Throws(() => exp.AfterPropertiesSet()); + SaoExporter saoExporter = new SaoExporter(); + saoExporter.ObjectFactory = of; + saoExporter.TargetName = "DOESNOTEXIST"; + saoExporter.ServiceName = "RemotedSaoSingletonCounter"; + Assert.Throws(() => saoExporter.AfterPropertiesSet()); } + } - [Test] - public void BailsIfTargetNotFound() + [Test] + public void ExportSingleton() + { + using (DefaultListableObjectFactory of = new DefaultListableObjectFactory()) { - using (DefaultListableObjectFactory of = new DefaultListableObjectFactory()) - { - SaoExporter saoExporter = new SaoExporter(); - saoExporter.ObjectFactory = of; - saoExporter.TargetName = "DOESNOTEXIST"; - saoExporter.ServiceName = "RemotedSaoSingletonCounter"; - Assert.Throws(() => saoExporter.AfterPropertiesSet()); - } + of.RegisterSingleton("simpleCounter", new SimpleCounter()); + SaoExporter saoExporter = new SaoExporter(); + saoExporter.ObjectFactory = of; + saoExporter.TargetName = "simpleCounter"; + saoExporter.ServiceName = "RemotedSaoSingletonCounter"; + saoExporter.AfterPropertiesSet(); + of.RegisterSingleton("simpleCounterExporter", saoExporter); // also tests SaoExporter.Dispose()! + + AssertExportedService(saoExporter.ServiceName, 2); } + } - [Test] - public void ExportSingleton() + [Test] + public void ExportSingleCall() + { + using (DefaultListableObjectFactory of = new DefaultListableObjectFactory()) { - using (DefaultListableObjectFactory of = new DefaultListableObjectFactory()) - { - of.RegisterSingleton("simpleCounter", new SimpleCounter()); - SaoExporter saoExporter = new SaoExporter(); - saoExporter.ObjectFactory = of; - saoExporter.TargetName = "simpleCounter"; - saoExporter.ServiceName = "RemotedSaoSingletonCounter"; - saoExporter.AfterPropertiesSet(); - of.RegisterSingleton("simpleCounterExporter", saoExporter); // also tests SaoExporter.Dispose()! + of.RegisterObjectDefinition("simpleCounter", new RootObjectDefinition(typeof(SimpleCounter), false)); + SaoExporter saoExporter = new SaoExporter(); + saoExporter.ObjectFactory = of; + saoExporter.TargetName = "simpleCounter"; + saoExporter.ServiceName = "RemotedSaoSingleCallCounter"; + saoExporter.AfterPropertiesSet(); + of.RegisterSingleton("simpleCounterExporter", saoExporter); // also tests SaoExporter.Dispose()! - AssertExportedService(saoExporter.ServiceName, 2); - } + AssertExportedService(saoExporter.ServiceName, 0); } + } - [Test] - public void ExportSingleCall() + /// + /// Checks that we can also export if IFactoryObject.ObjectType returns an interface type, + /// + [Test(Description = "http://jira.springframework.org/browse/SPRNET-1251")] + public void CanExportFromFactoryObjectIfObjectTypeIsInterface() + { + using (DefaultListableObjectFactory of = new DefaultListableObjectFactory()) { - using (DefaultListableObjectFactory of = new DefaultListableObjectFactory()) - { - of.RegisterObjectDefinition("simpleCounter", new RootObjectDefinition(typeof(SimpleCounter), false)); - SaoExporter saoExporter = new SaoExporter(); - saoExporter.ObjectFactory = of; - saoExporter.TargetName = "simpleCounter"; - saoExporter.ServiceName = "RemotedSaoSingleCallCounter"; - saoExporter.AfterPropertiesSet(); - of.RegisterSingleton("simpleCounterExporter", saoExporter); // also tests SaoExporter.Dispose()! + IFactoryObject simpleCounterFactory = A.Fake(); + A.CallTo(() => simpleCounterFactory.ObjectType).Returns(typeof(ISimpleCounter)); + A.CallTo(() => simpleCounterFactory.IsSingleton).Returns(true); + A.CallTo(() => simpleCounterFactory.GetObject()).Returns(new SimpleCounter()); - AssertExportedService(saoExporter.ServiceName, 0); - } + of.RegisterSingleton("simpleCounter", simpleCounterFactory); + SaoExporter saoExporter = new SaoExporter(); + saoExporter.ObjectFactory = of; + saoExporter.TargetName = "simpleCounter"; + saoExporter.ServiceName = "RemotedSaoCallCounter"; + saoExporter.AfterPropertiesSet(); + of.RegisterSingleton("simpleCounterExporter", saoExporter); // also tests SaoExporter.Dispose()! + + AssertExportedService(saoExporter.ServiceName, 2); } + } - /// - /// Checks that we can also export if IFactoryObject.ObjectType returns an interface type, - /// - [Test(Description = "http://jira.springframework.org/browse/SPRNET-1251")] - public void CanExportFromFactoryObjectIfObjectTypeIsInterface() + /// + /// Checks that exp an IFactoryObject.ObjectType returns an interface type, + /// + [Test(Description = "http://jira.springframework.org/browse/SPRNET-1251")] + public void ThrowsTypeLoadExceptionIfProxyInterfacesValueIsSpecifiedInsteadOfListElement() + { + using (DefaultListableObjectFactory of = new DefaultListableObjectFactory()) { - using (DefaultListableObjectFactory of = new DefaultListableObjectFactory()) - { - IFactoryObject simpleCounterFactory = A.Fake(); - A.CallTo(() => simpleCounterFactory.ObjectType).Returns(typeof (ISimpleCounter)); - A.CallTo(() => simpleCounterFactory.IsSingleton).Returns(true); - A.CallTo(() => simpleCounterFactory.GetObject()).Returns(new SimpleCounter()); - - - of.RegisterSingleton("simpleCounter", simpleCounterFactory); - SaoExporter saoExporter = new SaoExporter(); - saoExporter.ObjectFactory = of; - saoExporter.TargetName = "simpleCounter"; - saoExporter.ServiceName = "RemotedSaoCallCounter"; - saoExporter.AfterPropertiesSet(); - of.RegisterSingleton("simpleCounterExporter", saoExporter); // also tests SaoExporter.Dispose()! - - AssertExportedService(saoExporter.ServiceName, 2); - } - } - - /// - /// Checks that exp an IFactoryObject.ObjectType returns an interface type, - /// - [Test(Description = "http://jira.springframework.org/browse/SPRNET-1251")] - public void ThrowsTypeLoadExceptionIfProxyInterfacesValueIsSpecifiedInsteadOfListElement() - { - using (DefaultListableObjectFactory of = new DefaultListableObjectFactory()) - { - XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(of); - reader.LoadObjectDefinitions(new StringResource( - @" + XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(of); + reader.LoadObjectDefinitions(new StringResource( + @" @@ -144,26 +141,25 @@ namespace Spring.Remoting
")); - try - { - SaoExporter saoExporter = (SaoExporter) of.GetObject("ISimpleCounterExporter"); - Assert.Fail(); - } - catch (ObjectCreationException oce) - { - TypeLoadException tle = (TypeLoadException) oce.GetBaseException(); - Assert.AreEqual("Could not load type from string value ' Spring.Services.Tests'.", tle.Message); - } + try + { + SaoExporter saoExporter = (SaoExporter) of.GetObject("ISimpleCounterExporter"); + Assert.Fail(); + } + catch (ObjectCreationException oce) + { + TypeLoadException tle = (TypeLoadException) oce.GetBaseException(); + Assert.AreEqual("Could not load type from string value ' Spring.Services.Tests'.", tle.Message); } } + } - private void AssertExportedService(string serviceName, int expectedCount) - { - ISimpleCounter client = (ISimpleCounter)Activator.GetObject(typeof(ISimpleCounter), "tcp://localhost:8005/" + serviceName); - client.Count(); - client.Count(); + private void AssertExportedService(string serviceName, int expectedCount) + { + ISimpleCounter client = (ISimpleCounter) Activator.GetObject(typeof(ISimpleCounter), "tcp://localhost:8005/" + serviceName); + client.Count(); + client.Count(); - Assert.AreEqual(expectedCount, client.Counter); - } + Assert.AreEqual(expectedCount, client.Counter); } } diff --git a/test/Spring/Spring.Services.Tests/Remoting/SaoFactoryObjectTests.cs b/test/Spring/Spring.Services.Tests/Remoting/SaoFactoryObjectTests.cs index 06c36721..268b4840 100644 --- a/test/Spring/Spring.Services.Tests/Remoting/SaoFactoryObjectTests.cs +++ b/test/Spring/Spring.Services.Tests/Remoting/SaoFactoryObjectTests.cs @@ -31,203 +31,203 @@ using Spring.Objects.Factory.Xml; #endregion -namespace Spring.Remoting +namespace Spring.Remoting; + +/// +/// Unit tests for the SaoFactoryObject class. +/// +/// Mark Pollack +/// Bruno Baia +[TestFixture] +public class SaoFactoryObjectTests : BaseRemotingTestFixture { - /// - /// Unit tests for the SaoFactoryObject class. - /// - /// Mark Pollack - /// Bruno Baia - [TestFixture] - public class SaoFactoryObjectTests : BaseRemotingTestFixture - { - [Test] - public void BailsWhenNotConfigured () - { - SaoFactoryObject sfo = new SaoFactoryObject(); - Assert.Throws(() => sfo.AfterPropertiesSet()); - } + [Test] + public void BailsWhenNotConfigured() + { + SaoFactoryObject sfo = new SaoFactoryObject(); + Assert.Throws(() => sfo.AfterPropertiesSet()); + } - /// - /// Make sure that transparent proxies are recognized - /// correctly by the core object factory. - /// - /// - /// This is a test for SPRNET-200 - /// - [Test] - public void WiringWithTransparentProxy() - { - IApplicationContext ctx = new XmlApplicationContext("assembly://Spring.Services.Tests/Spring.Data.Spring.Remoting/autowire.xml"); - ContextRegistry.RegisterContext(ctx); + /// + /// Make sure that transparent proxies are recognized + /// correctly by the core object factory. + /// + /// + /// This is a test for SPRNET-200 + /// + [Test] + public void WiringWithTransparentProxy() + { + IApplicationContext ctx = new XmlApplicationContext("assembly://Spring.Services.Tests/Spring.Data.Spring.Remoting/autowire.xml"); + ContextRegistry.RegisterContext(ctx); - TestObject to = (TestObject) ctx.GetObject("kerry3"); - Assert.IsNotNull(to, "Object is null even though a object has been configured."); - Assert.IsTrue(RemotingServices.IsTransparentProxy(to.Sibling), "IsTransparentProxy"); - Assert.AreEqual("Kerry3", to.Name, "Name"); + TestObject to = (TestObject) ctx.GetObject("kerry3"); + Assert.IsNotNull(to, "Object is null even though a object has been configured."); + Assert.IsTrue(RemotingServices.IsTransparentProxy(to.Sibling), "IsTransparentProxy"); + Assert.AreEqual("Kerry3", to.Name, "Name"); - to = (TestObject) ctx.GetObject("objectWithCtorArgRefShortcuts"); - Assert.IsTrue(RemotingServices.IsTransparentProxy(to.Spouse), "IsTransparentProxy"); + to = (TestObject) ctx.GetObject("objectWithCtorArgRefShortcuts"); + Assert.IsTrue(RemotingServices.IsTransparentProxy(to.Spouse), "IsTransparentProxy"); - ConstructorDependenciesObject cdo = (ConstructorDependenciesObject) ctx.GetObject("rod2"); - Assert.IsTrue(RemotingServices.IsTransparentProxy(cdo.Spouse1), "IsTransparentProxy"); - Assert.IsTrue(RemotingServices.IsTransparentProxy(cdo.Spouse2), "IsTransparentProxy"); - } + ConstructorDependenciesObject cdo = (ConstructorDependenciesObject) ctx.GetObject("rod2"); + Assert.IsTrue(RemotingServices.IsTransparentProxy(cdo.Spouse1), "IsTransparentProxy"); + Assert.IsTrue(RemotingServices.IsTransparentProxy(cdo.Spouse2), "IsTransparentProxy"); + } - [Test] - public void GetSaoWithSingletonMode() - { - IApplicationContext ctx = new XmlApplicationContext("assembly://Spring.Services.Tests/Spring.Data.Spring.Remoting/saoSingleton.xml"); - ContextRegistry.RegisterContext(ctx); + [Test] + public void GetSaoWithSingletonMode() + { + IApplicationContext ctx = new XmlApplicationContext("assembly://Spring.Services.Tests/Spring.Data.Spring.Remoting/saoSingleton.xml"); + ContextRegistry.RegisterContext(ctx); - object obj = ctx.GetObject("remoteSaoSingletonCounter"); + object obj = ctx.GetObject("remoteSaoSingletonCounter"); - Assert.IsNotNull(obj, "Object is null even though a object has been exported."); - Assert.IsTrue((obj is ISimpleCounter), "Object should implement 'ISimpleCounter' interface."); + Assert.IsNotNull(obj, "Object is null even though a object has been exported."); + Assert.IsTrue((obj is ISimpleCounter), "Object should implement 'ISimpleCounter' interface."); - ISimpleCounter sc = (ISimpleCounter) obj; - Assert.AreEqual(1, sc.Counter, "Remote object hasn't been activated by the server."); - sc.Count(); - Assert.AreEqual(2, sc.Counter, "Remote object doesn't work in a 'Singleton' mode."); - } - - public class SPRNET967_SimpleCounterWrapper : MarshalByRefObject, ISimpleCounter + ISimpleCounter sc = (ISimpleCounter) obj; + Assert.AreEqual(1, sc.Counter, "Remote object hasn't been activated by the server."); + sc.Count(); + Assert.AreEqual(2, sc.Counter, "Remote object doesn't work in a 'Singleton' mode."); + } + + public class SPRNET967_SimpleCounterWrapper : MarshalByRefObject, ISimpleCounter + { + private ISimpleCounter service; + + public SPRNET967_SimpleCounterWrapper() { - private ISimpleCounter service; - - public SPRNET967_SimpleCounterWrapper() - {} - - public SPRNET967_SimpleCounterWrapper(ISimpleCounter service) - { - this.service = service; - } - - public ISimpleCounter Service - { - get { return service; } - set { service = value; } - } - - public int Counter - { - get { return service.Counter; } - set { service.Counter = value; } - } - - public void Count() - { - service.Count(); - } } - public class SPRNET967_SimpleCounterClient + public SPRNET967_SimpleCounterWrapper(ISimpleCounter service) { - private ISimpleCounter service; - - public SPRNET967_SimpleCounterClient() - {} - - public SPRNET967_SimpleCounterClient(ISimpleCounter service) - { - this.service = service; - } - - public ISimpleCounter Service - { - get { return service; } - set { service = value; } - } - - public int Counter - { - get { return service.Counter; } - set { service.Counter = value; } - } - - public void Count() - { - service.Count(); - } + this.service = service; } - [Test] - public void GetSaoWithSingletonModeAutowired_SPRNET967() - { - // register server by hand to avoid duplicate interfaces - SPRNET967_SimpleCounterWrapper svr = new SPRNET967_SimpleCounterWrapper( new SimpleCounter(1) ); - RemotingServices.Marshal(svr, "RemotedSaoSingletonCounter"); + public ISimpleCounter Service + { + get { return service; } + set { service = value; } + } + + public int Counter + { + get { return service.Counter; } + set { service.Counter = value; } + } + + public void Count() + { + service.Count(); + } + } + + public class SPRNET967_SimpleCounterClient + { + private ISimpleCounter service; + + public SPRNET967_SimpleCounterClient() + { + } + + public SPRNET967_SimpleCounterClient(ISimpleCounter service) + { + this.service = service; + } + + public ISimpleCounter Service + { + get { return service; } + set { service = value; } + } + + public int Counter + { + get { return service.Counter; } + set { service.Counter = value; } + } + + public void Count() + { + service.Count(); + } + } + + [Test] + public void GetSaoWithSingletonModeAutowired_SPRNET967() + { + // register server by hand to avoid duplicate interfaces + SPRNET967_SimpleCounterWrapper svr = new SPRNET967_SimpleCounterWrapper(new SimpleCounter(1)); + RemotingServices.Marshal(svr, "RemotedSaoSingletonCounter"); // object svc = Activator.GetObject(typeof(ISimpleCounter), "tcp://localhost:8005/RemotedSaoSingletonCounter"); // Assert.IsTrue( svc is IObjectDefinition ); // Assert.IsTrue( svc is ISimpleCounter ); - IApplicationContext ctx = new XmlApplicationContext("assembly://Spring.Services.Tests/Spring.Data.Spring.Remoting/saoSingleton-autowired.xml"); - ContextRegistry.RegisterContext(ctx); - SPRNET967_SimpleCounterClient client = (SPRNET967_SimpleCounterClient) ctx.GetObject("counterClient"); - client.Count(); - Assert.AreEqual(2, client.Counter); - } + IApplicationContext ctx = new XmlApplicationContext("assembly://Spring.Services.Tests/Spring.Data.Spring.Remoting/saoSingleton-autowired.xml"); + ContextRegistry.RegisterContext(ctx); + SPRNET967_SimpleCounterClient client = (SPRNET967_SimpleCounterClient) ctx.GetObject("counterClient"); + client.Count(); + Assert.AreEqual(2, client.Counter); + } - [Test] - public void GetSaoWithSingletonModeAndAop() - { - IApplicationContext ctx = new XmlApplicationContext("assembly://Spring.Services.Tests/Spring.Data.Spring.Remoting/saoSingleton-aop.xml"); - ContextRegistry.RegisterContext(ctx); + [Test] + public void GetSaoWithSingletonModeAndAop() + { + IApplicationContext ctx = new XmlApplicationContext("assembly://Spring.Services.Tests/Spring.Data.Spring.Remoting/saoSingleton-aop.xml"); + ContextRegistry.RegisterContext(ctx); - //object saoFactory = ctx.GetObject("&remoteCounter"); - //Assert.IsNotNull(saoFactory); + //object saoFactory = ctx.GetObject("&remoteCounter"); + //Assert.IsNotNull(saoFactory); - object obj = ctx.GetObject("remoteCounter"); + object obj = ctx.GetObject("remoteCounter"); - Assert.IsNotNull(obj, "Object is null even though a object has been exported."); - Assert.IsTrue(AopUtils.IsAopProxy(obj)); - Assert.IsTrue((obj is ISimpleCounter), "Object should implement 'ISimpleCounter' interface."); - + Assert.IsNotNull(obj, "Object is null even though a object has been exported."); + Assert.IsTrue(AopUtils.IsAopProxy(obj)); + Assert.IsTrue((obj is ISimpleCounter), "Object should implement 'ISimpleCounter' interface."); - MethodCounter aopCounter = ctx.GetObject("countingBeforeAdvice") as MethodCounter; - Assert.IsNotNull(aopCounter); + MethodCounter aopCounter = ctx.GetObject("countingBeforeAdvice") as MethodCounter; + Assert.IsNotNull(aopCounter); - int aopCount = aopCounter.GetCalls("Count"); - Assert.AreEqual(0, aopCount); + int aopCount = aopCounter.GetCalls("Count"); + Assert.AreEqual(0, aopCount); - ISimpleCounter sc = (ISimpleCounter)obj; - Assert.AreEqual(1, sc.Counter, "Remote object hasn't been activated by the server."); - sc.Count(); - Assert.AreEqual(2, sc.Counter, "Remote object doesn't work in a 'Singleton' mode."); - Assert.AreEqual(1, aopCounter.GetCalls("Count")); - } + ISimpleCounter sc = (ISimpleCounter) obj; + Assert.AreEqual(1, sc.Counter, "Remote object hasn't been activated by the server."); + sc.Count(); + Assert.AreEqual(2, sc.Counter, "Remote object doesn't work in a 'Singleton' mode."); + Assert.AreEqual(1, aopCounter.GetCalls("Count")); + } - [Test] - public void GetSaoWithSingleCallMode() - { - IApplicationContext ctx = new XmlApplicationContext("assembly://Spring.Services.Tests/Spring.Data.Spring.Remoting/saoSingleCall.xml"); - ContextRegistry.RegisterContext(ctx); + [Test] + public void GetSaoWithSingleCallMode() + { + IApplicationContext ctx = new XmlApplicationContext("assembly://Spring.Services.Tests/Spring.Data.Spring.Remoting/saoSingleCall.xml"); + ContextRegistry.RegisterContext(ctx); - object obj = ctx.GetObject("remoteSaoSingleCallCounter"); + object obj = ctx.GetObject("remoteSaoSingleCallCounter"); - Assert.IsNotNull(obj, "Object is null even though a object has been exported."); - Assert.IsTrue((obj is ISimpleCounter), "Object should implement 'ISimpleCounter' interface."); + Assert.IsNotNull(obj, "Object is null even though a object has been exported."); + Assert.IsTrue((obj is ISimpleCounter), "Object should implement 'ISimpleCounter' interface."); - ISimpleCounter sc = (ISimpleCounter) obj; - Assert.IsNotNull(sc, "Object is null even though a object has been exported."); - Assert.AreEqual(1, sc.Counter, "Remote object hasn't been activated by the server."); - sc.Count(); - Assert.AreEqual(1, sc.Counter, "Remote object don't works in a 'SingleCall' mode."); - } + ISimpleCounter sc = (ISimpleCounter) obj; + Assert.IsNotNull(sc, "Object is null even though a object has been exported."); + Assert.AreEqual(1, sc.Counter, "Remote object hasn't been activated by the server."); + sc.Count(); + Assert.AreEqual(1, sc.Counter, "Remote object don't works in a 'SingleCall' mode."); + } - [Test] - public void GetSaoWithLifetimeService() - { - IApplicationContext ctx = new XmlApplicationContext("assembly://Spring.Services.Tests/Spring.Data.Spring.Remoting/saoLifetimeService.xml"); - ContextRegistry.RegisterContext(ctx); + [Test] + public void GetSaoWithLifetimeService() + { + IApplicationContext ctx = new XmlApplicationContext("assembly://Spring.Services.Tests/Spring.Data.Spring.Remoting/saoLifetimeService.xml"); + ContextRegistry.RegisterContext(ctx); - MarshalByRefObject obj = (MarshalByRefObject) ctx.GetObject("remoteSaoCounter"); - ILease lease = (ILease) obj.GetLifetimeService(); + MarshalByRefObject obj = (MarshalByRefObject) ctx.GetObject("remoteSaoCounter"); + ILease lease = (ILease) obj.GetLifetimeService(); - Assert.AreEqual(TimeSpan.FromMilliseconds(10000), lease.InitialLeaseTime, "InitialLeaseTime"); - Assert.AreEqual(TimeSpan.FromMilliseconds(1000), lease.RenewOnCallTime, "RenewOnCallTime"); - Assert.AreEqual(TimeSpan.FromMilliseconds(100), lease.SponsorshipTimeout, "SponsorshipTimeout"); - } - } + Assert.AreEqual(TimeSpan.FromMilliseconds(10000), lease.InitialLeaseTime, "InitialLeaseTime"); + Assert.AreEqual(TimeSpan.FromMilliseconds(1000), lease.RenewOnCallTime, "RenewOnCallTime"); + Assert.AreEqual(TimeSpan.FromMilliseconds(100), lease.SponsorshipTimeout, "SponsorshipTimeout"); + } } diff --git a/test/Spring/Spring.Services.Tests/Remoting/SimpleCounter.cs b/test/Spring/Spring.Services.Tests/Remoting/SimpleCounter.cs index 0142d181..d7fdf5ed 100644 --- a/test/Spring/Spring.Services.Tests/Remoting/SimpleCounter.cs +++ b/test/Spring/Spring.Services.Tests/Remoting/SimpleCounter.cs @@ -20,49 +20,48 @@ #region Imports - #endregion -namespace Spring.Remoting +namespace Spring.Remoting; + +/// +/// A simple remote class. +/// +public class SimpleCounter : ISimpleCounter { - /// - /// A simple remote class. - /// - public class SimpleCounter : ISimpleCounter - { - protected int _counter; + protected int _counter; - /// - /// Create an instance of the Counter class. - /// - public SimpleCounter() - { - _counter = 0; - } + /// + /// Create an instance of the Counter class. + /// + public SimpleCounter() + { + _counter = 0; + } - /// - /// Create an instance of the Counter class. - /// - /// Initial counter value. - public SimpleCounter(int initialCounter) - { - _counter = initialCounter; - } + /// + /// Create an instance of the Counter class. + /// + /// Initial counter value. + public SimpleCounter(int initialCounter) + { + _counter = initialCounter; + } - /// - /// Get or Set the Counter's value. - /// - public int Counter - { - get { return _counter; } - set { _counter = value; } - } - /// - /// Increment the counter by one. - /// - public void Count() - { - _counter++; - } - } + /// + /// Get or Set the Counter's value. + /// + public int Counter + { + get { return _counter; } + set { _counter = value; } + } + + /// + /// Increment the counter by one. + /// + public void Count() + { + _counter++; + } } diff --git a/test/Spring/Spring.Services.Tests/ServiceComponentExporterTests.TestServicedComponents.Services.xml b/test/Spring/Spring.Services.Tests/ServiceComponentExporterTests.TestServicedComponents.Services.xml index d0c85ace..777f71b5 100644 --- a/test/Spring/Spring.Services.Tests/ServiceComponentExporterTests.TestServicedComponents.Services.xml +++ b/test/Spring/Spring.Services.Tests/ServiceComponentExporterTests.TestServicedComponents.Services.xml @@ -1,18 +1,19 @@  - + - - - - System.IComparable - - - - - - - - + + + + System.IComparable + + + + + + + + \ No newline at end of file diff --git a/test/Spring/Spring.Services.Tests/ServiceComponentExporterTests.TestServicedComponents.dll.config b/test/Spring/Spring.Services.Tests/ServiceComponentExporterTests.TestServicedComponents.dll.config index b7fc23cf..a7812591 100644 --- a/test/Spring/Spring.Services.Tests/ServiceComponentExporterTests.TestServicedComponents.dll.config +++ b/test/Spring/Spring.Services.Tests/ServiceComponentExporterTests.TestServicedComponents.dll.config @@ -3,7 +3,7 @@ -
+
diff --git a/test/Spring/Spring.Services.Tests/ServiceComponentExporterTests.TestServicedComponents.exe.config b/test/Spring/Spring.Services.Tests/ServiceComponentExporterTests.TestServicedComponents.exe.config index 4b8a7b34..ecc2f648 100644 --- a/test/Spring/Spring.Services.Tests/ServiceComponentExporterTests.TestServicedComponents.exe.config +++ b/test/Spring/Spring.Services.Tests/ServiceComponentExporterTests.TestServicedComponents.exe.config @@ -3,7 +3,7 @@ -
+
@@ -15,7 +15,7 @@ - + @@ -26,7 +26,8 @@ - + @@ -36,7 +37,7 @@ - + diff --git a/test/Spring/Spring.Services.Tests/ServiceModel/Config/ChannelFactoryObjectDefinitionParserTests.BasicConfig.xml b/test/Spring/Spring.Services.Tests/ServiceModel/Config/ChannelFactoryObjectDefinitionParserTests.BasicConfig.xml index d596056b..54603e37 100644 --- a/test/Spring/Spring.Services.Tests/ServiceModel/Config/ChannelFactoryObjectDefinitionParserTests.BasicConfig.xml +++ b/test/Spring/Spring.Services.Tests/ServiceModel/Config/ChannelFactoryObjectDefinitionParserTests.BasicConfig.xml @@ -1,9 +1,9 @@ - - + diff --git a/test/Spring/Spring.Services.Tests/ServiceModel/Config/ChannelFactoryObjectDefinitionParserTests.CustomProperties.xml b/test/Spring/Spring.Services.Tests/ServiceModel/Config/ChannelFactoryObjectDefinitionParserTests.CustomProperties.xml index d48acccf..00c6455b 100644 --- a/test/Spring/Spring.Services.Tests/ServiceModel/Config/ChannelFactoryObjectDefinitionParserTests.CustomProperties.xml +++ b/test/Spring/Spring.Services.Tests/ServiceModel/Config/ChannelFactoryObjectDefinitionParserTests.CustomProperties.xml @@ -1,11 +1,11 @@ - - - - + + + diff --git a/test/Spring/Spring.Services.Tests/ServiceModel/Config/ChannelFactoryObjectDefinitionParserTests.WithTypeAlias.xml b/test/Spring/Spring.Services.Tests/ServiceModel/Config/ChannelFactoryObjectDefinitionParserTests.WithTypeAlias.xml index 5d8f81ad..ee1dba31 100644 --- a/test/Spring/Spring.Services.Tests/ServiceModel/Config/ChannelFactoryObjectDefinitionParserTests.WithTypeAlias.xml +++ b/test/Spring/Spring.Services.Tests/ServiceModel/Config/ChannelFactoryObjectDefinitionParserTests.WithTypeAlias.xml @@ -1,17 +1,18 @@ - - - - - - - - - - + + + + + + + + + diff --git a/test/Spring/Spring.Services.Tests/ServiceModel/Config/ChannelFactoryObjectDefinitionParserTests.WithoutId.xml b/test/Spring/Spring.Services.Tests/ServiceModel/Config/ChannelFactoryObjectDefinitionParserTests.WithoutId.xml index 855bc444..4ebb045b 100644 --- a/test/Spring/Spring.Services.Tests/ServiceModel/Config/ChannelFactoryObjectDefinitionParserTests.WithoutId.xml +++ b/test/Spring/Spring.Services.Tests/ServiceModel/Config/ChannelFactoryObjectDefinitionParserTests.WithoutId.xml @@ -1,8 +1,9 @@ - - + diff --git a/test/Spring/Spring.Services.Tests/ServiceModel/Config/ChannelFactoryObjectDefinitionParserTests.cs b/test/Spring/Spring.Services.Tests/ServiceModel/Config/ChannelFactoryObjectDefinitionParserTests.cs index 1dcce588..e0d7d465 100644 --- a/test/Spring/Spring.Services.Tests/ServiceModel/Config/ChannelFactoryObjectDefinitionParserTests.cs +++ b/test/Spring/Spring.Services.Tests/ServiceModel/Config/ChannelFactoryObjectDefinitionParserTests.cs @@ -21,126 +21,122 @@ #region Imports using System.ServiceModel; - using Spring.Context; using Spring.Context.Support; using Spring.Objects.Factory.Xml; using Spring.Objects.Factory.Support; - using NUnit.Framework; #endregion -namespace Spring.ServiceModel.Config +namespace Spring.ServiceModel.Config; + +/// +/// Unit tests for the class. +/// +/// Bruno Baia +[TestFixture] +public class ChannelFactoryObjectDefinitionParserTests { - /// - /// Unit tests for the class. - /// - /// Bruno Baia - [TestFixture] - public class ChannelFactoryObjectDefinitionParserTests + //[Test] + public void BasicConfig() { - //[Test] - public void BasicConfig() - { - NamespaceParserRegistry.RegisterParser(typeof(WcfNamespaceParser)); - IApplicationContext ctx = new XmlApplicationContext( - ReadOnlyXmlTestResource.GetFilePath("ChannelFactoryObjectDefinitionParserTests.BasicConfig.xml", this.GetType())); + NamespaceParserRegistry.RegisterParser(typeof(WcfNamespaceParser)); + IApplicationContext ctx = new XmlApplicationContext( + ReadOnlyXmlTestResource.GetFilePath("ChannelFactoryObjectDefinitionParserTests.BasicConfig.xml", this.GetType())); - Assert.IsTrue(ctx.ContainsObjectDefinition("channel")); + Assert.IsTrue(ctx.ContainsObjectDefinition("channel")); - RootObjectDefinition rod = ((IObjectDefinitionRegistry)ctx).GetObjectDefinition("channel") as RootObjectDefinition; - Assert.IsNotNull(rod); + RootObjectDefinition rod = ((IObjectDefinitionRegistry) ctx).GetObjectDefinition("channel") as RootObjectDefinition; + Assert.IsNotNull(rod); - Assert.IsTrue(rod.HasObjectType); - Assert.AreEqual(typeof(ChannelFactoryObject), rod.ObjectType); - Assert.AreEqual(1, rod.ConstructorArgumentValues.NamedArgumentValues.Count); - Assert.AreEqual("ecn", rod.ConstructorArgumentValues.GetNamedArgumentValue("endpointConfigurationName").Value); + Assert.IsTrue(rod.HasObjectType); + Assert.AreEqual(typeof(ChannelFactoryObject), rod.ObjectType); + Assert.AreEqual(1, rod.ConstructorArgumentValues.NamedArgumentValues.Count); + Assert.AreEqual("ecn", rod.ConstructorArgumentValues.GetNamedArgumentValue("endpointConfigurationName").Value); - ChannelFactoryObject cfo = ctx.GetObject("&channel") as ChannelFactoryObject; - Assert.IsNotNull(cfo); - Assert.AreEqual(typeof(IContract), cfo.ObjectType); + ChannelFactoryObject cfo = ctx.GetObject("&channel") as ChannelFactoryObject; + Assert.IsNotNull(cfo); + Assert.AreEqual(typeof(IContract), cfo.ObjectType); - IContract contract = ctx.GetObject("channel") as IContract; - Assert.IsNotNull(contract); - } - - //[Test] - public void CustomProperties() - { - NamespaceParserRegistry.RegisterParser(typeof(WcfNamespaceParser)); - IApplicationContext ctx = new XmlApplicationContext( - ReadOnlyXmlTestResource.GetFilePath("ChannelFactoryObjectDefinitionParserTests.CustomProperties.xml", this.GetType())); - - Assert.IsTrue(ctx.ContainsObjectDefinition("channel")); - - RootObjectDefinition rod = ((IObjectDefinitionRegistry)ctx).GetObjectDefinition("channel") as RootObjectDefinition; - Assert.IsNotNull(rod); - - Assert.IsTrue(rod.HasObjectType); - Assert.AreEqual(typeof(ChannelFactoryObject), rod.ObjectType); - Assert.AreEqual(1, rod.ConstructorArgumentValues.NamedArgumentValues.Count); - Assert.AreEqual("ecn", rod.ConstructorArgumentValues.GetNamedArgumentValue("endpointConfigurationName").Value); - Assert.IsTrue(rod.PropertyValues.Contains("Credentials.Windows.ClientCredential")); - Assert.AreEqual("Spring\\Bruno:gnirpS", rod.PropertyValues.GetPropertyValue("Credentials.Windows.ClientCredential").Value); - - ChannelFactoryObject cfo = ctx.GetObject("&channel") as ChannelFactoryObject; - Assert.IsNotNull(cfo); - Assert.AreEqual(typeof(IContract), cfo.ObjectType); - Assert.AreEqual("Spring", cfo.Credentials.Windows.ClientCredential.Domain); - Assert.AreEqual("Bruno", cfo.Credentials.Windows.ClientCredential.UserName); - Assert.AreEqual("gnirpS", cfo.Credentials.Windows.ClientCredential.Password); - - IContract contract = ctx.GetObject("channel") as IContract; - Assert.IsNotNull(contract); - } - - //[Test] - public void WithoutId() - { - NamespaceParserRegistry.RegisterParser(typeof(WcfNamespaceParser)); - IApplicationContext ctx = new XmlApplicationContext( - ReadOnlyXmlTestResource.GetFilePath("ChannelFactoryObjectDefinitionParserTests.WithoutId.xml", this.GetType())); - - var channels = ctx.GetObjects(); - Assert.AreEqual(1, channels.Count); - } - - //[Test] - public void WithTypeAlias() - { - NamespaceParserRegistry.RegisterParser(typeof(WcfNamespaceParser)); - IApplicationContext ctx = new XmlApplicationContext( - ReadOnlyXmlTestResource.GetFilePath("ChannelFactoryObjectDefinitionParserTests.WithTypeAlias.xml", this.GetType())); - - Assert.IsTrue(ctx.ContainsObjectDefinition("channel")); - - RootObjectDefinition rod = ((IObjectDefinitionRegistry)ctx).GetObjectDefinition("channel") as RootObjectDefinition; - Assert.IsNotNull(rod); - - Assert.IsFalse(rod.HasObjectType); - Assert.AreEqual("Spring.ServiceModel.ChannelFactoryObject, Spring.Services", rod.ObjectTypeName); - Assert.AreEqual(1, rod.ConstructorArgumentValues.NamedArgumentValues.Count); - Assert.AreEqual("ecn", rod.ConstructorArgumentValues.GetNamedArgumentValue("endpointConfigurationName").Value); - - ChannelFactoryObject cfo = ctx.GetObject("&channel") as ChannelFactoryObject; - Assert.IsNotNull(cfo); - Assert.AreEqual(typeof(IContract), cfo.ObjectType); - - IContract contract = ctx.GetObject("channel") as IContract; - Assert.IsNotNull(contract); - } - - - #region Test classes - - [ServiceContract(Namespace = "http://Spring.Services.Tests")] - public interface IContract - { - [OperationContract(Name = "MySomeMethod")] - string SomeMethod(int param); - } - - #endregion + IContract contract = ctx.GetObject("channel") as IContract; + Assert.IsNotNull(contract); } + + //[Test] + public void CustomProperties() + { + NamespaceParserRegistry.RegisterParser(typeof(WcfNamespaceParser)); + IApplicationContext ctx = new XmlApplicationContext( + ReadOnlyXmlTestResource.GetFilePath("ChannelFactoryObjectDefinitionParserTests.CustomProperties.xml", this.GetType())); + + Assert.IsTrue(ctx.ContainsObjectDefinition("channel")); + + RootObjectDefinition rod = ((IObjectDefinitionRegistry) ctx).GetObjectDefinition("channel") as RootObjectDefinition; + Assert.IsNotNull(rod); + + Assert.IsTrue(rod.HasObjectType); + Assert.AreEqual(typeof(ChannelFactoryObject), rod.ObjectType); + Assert.AreEqual(1, rod.ConstructorArgumentValues.NamedArgumentValues.Count); + Assert.AreEqual("ecn", rod.ConstructorArgumentValues.GetNamedArgumentValue("endpointConfigurationName").Value); + Assert.IsTrue(rod.PropertyValues.Contains("Credentials.Windows.ClientCredential")); + Assert.AreEqual("Spring\\Bruno:gnirpS", rod.PropertyValues.GetPropertyValue("Credentials.Windows.ClientCredential").Value); + + ChannelFactoryObject cfo = ctx.GetObject("&channel") as ChannelFactoryObject; + Assert.IsNotNull(cfo); + Assert.AreEqual(typeof(IContract), cfo.ObjectType); + Assert.AreEqual("Spring", cfo.Credentials.Windows.ClientCredential.Domain); + Assert.AreEqual("Bruno", cfo.Credentials.Windows.ClientCredential.UserName); + Assert.AreEqual("gnirpS", cfo.Credentials.Windows.ClientCredential.Password); + + IContract contract = ctx.GetObject("channel") as IContract; + Assert.IsNotNull(contract); + } + + //[Test] + public void WithoutId() + { + NamespaceParserRegistry.RegisterParser(typeof(WcfNamespaceParser)); + IApplicationContext ctx = new XmlApplicationContext( + ReadOnlyXmlTestResource.GetFilePath("ChannelFactoryObjectDefinitionParserTests.WithoutId.xml", this.GetType())); + + var channels = ctx.GetObjects(); + Assert.AreEqual(1, channels.Count); + } + + //[Test] + public void WithTypeAlias() + { + NamespaceParserRegistry.RegisterParser(typeof(WcfNamespaceParser)); + IApplicationContext ctx = new XmlApplicationContext( + ReadOnlyXmlTestResource.GetFilePath("ChannelFactoryObjectDefinitionParserTests.WithTypeAlias.xml", this.GetType())); + + Assert.IsTrue(ctx.ContainsObjectDefinition("channel")); + + RootObjectDefinition rod = ((IObjectDefinitionRegistry) ctx).GetObjectDefinition("channel") as RootObjectDefinition; + Assert.IsNotNull(rod); + + Assert.IsFalse(rod.HasObjectType); + Assert.AreEqual("Spring.ServiceModel.ChannelFactoryObject, Spring.Services", rod.ObjectTypeName); + Assert.AreEqual(1, rod.ConstructorArgumentValues.NamedArgumentValues.Count); + Assert.AreEqual("ecn", rod.ConstructorArgumentValues.GetNamedArgumentValue("endpointConfigurationName").Value); + + ChannelFactoryObject cfo = ctx.GetObject("&channel") as ChannelFactoryObject; + Assert.IsNotNull(cfo); + Assert.AreEqual(typeof(IContract), cfo.ObjectType); + + IContract contract = ctx.GetObject("channel") as IContract; + Assert.IsNotNull(contract); + } + + #region Test classes + + [ServiceContract(Namespace = "http://Spring.Services.Tests")] + public interface IContract + { + [OperationContract(Name = "MySomeMethod")] + string SomeMethod(int param); + } + + #endregion } diff --git a/test/Spring/Spring.Services.Tests/ServiceModel/Config/WcfNamespaceParserTests.cs b/test/Spring/Spring.Services.Tests/ServiceModel/Config/WcfNamespaceParserTests.cs index a2f62e4b..2e085ee6 100644 --- a/test/Spring/Spring.Services.Tests/ServiceModel/Config/WcfNamespaceParserTests.cs +++ b/test/Spring/Spring.Services.Tests/ServiceModel/Config/WcfNamespaceParserTests.cs @@ -25,23 +25,22 @@ using NUnit.Framework; #endregion -namespace Spring.ServiceModel.Config +namespace Spring.ServiceModel.Config; + +/// +/// Unit tests for the class. +/// +/// Bruno Baia +[TestFixture] +public class WcfNamespaceParserTests { - /// - /// Unit tests for the class. - /// - /// Bruno Baia - [TestFixture] - public class WcfNamespaceParserTests + [Test] + public void Registered() { - [Test] - public void Registered() - { - NamespaceParserRegistry.RegisterParser(typeof(WcfNamespaceParser)); - INamespaceParser namespaceParser = NamespaceParserRegistry.GetParser("http://www.springframework.net/wcf"); - - Assert.IsNotNull(namespaceParser); - Assert.IsTrue(namespaceParser is WcfNamespaceParser); - } + NamespaceParserRegistry.RegisterParser(typeof(WcfNamespaceParser)); + INamespaceParser namespaceParser = NamespaceParserRegistry.GetParser("http://www.springframework.net/wcf"); + + Assert.IsNotNull(namespaceParser); + Assert.IsTrue(namespaceParser is WcfNamespaceParser); } } diff --git a/test/Spring/Spring.Services.Tests/ServiceModel/ServiceExporterTests.cs b/test/Spring/Spring.Services.Tests/ServiceModel/ServiceExporterTests.cs index 947bb432..58d24b4c 100644 --- a/test/Spring/Spring.Services.Tests/ServiceModel/ServiceExporterTests.cs +++ b/test/Spring/Spring.Services.Tests/ServiceModel/ServiceExporterTests.cs @@ -24,7 +24,6 @@ using System.Text; using System.Reflection; using System.Net.Security; using System.ServiceModel; - using NUnit.Framework; using Spring.Core.IO; using Spring.Objects.Factory; @@ -32,22 +31,22 @@ using Spring.Objects.Factory.Xml; #endregion -namespace Spring.ServiceModel -{ - /// - /// Unit tests for the ServiceExporter class. - /// - /// Bruno Baia - [TestFixture] - public sealed class ServiceExporterTests - { - ServiceExporter se = null; +namespace Spring.ServiceModel; - [SetUp] - public void SetUp() - { - const string xml = - @" +/// +/// Unit tests for the ServiceExporter class. +/// +/// Bruno Baia +[TestFixture] +public sealed class ServiceExporterTests +{ + ServiceExporter se = null; + + [SetUp] + public void SetUp() + { + const string xml = + @" @@ -55,22 +54,22 @@ namespace Spring.ServiceModel "; - using (Stream stream = new MemoryStream(Encoding.UTF8.GetBytes(xml))) - { - IObjectFactory objectFactory = new XmlObjectFactory(new InputStreamResource(stream, string.Empty)); - se = new ServiceExporter(); - se.ObjectFactory = objectFactory; - } - } - - [Test] - //SPRNET-1262 - public void ProxiesDeclarativeAttributeWithConstructorArguments() + using (Stream stream = new MemoryStream(Encoding.UTF8.GetBytes(xml))) { - XmlObjectFactory objectFactory = null; + IObjectFactory objectFactory = new XmlObjectFactory(new InputStreamResource(stream, string.Empty)); + se = new ServiceExporter(); + se.ObjectFactory = objectFactory; + } + } - const string xml = - @" + [Test] + //SPRNET-1262 + public void ProxiesDeclarativeAttributeWithConstructorArguments() + { + XmlObjectFactory objectFactory = null; + + const string xml = + @" @@ -85,304 +84,304 @@ namespace Spring.ServiceModel "; - using (Stream stream = new MemoryStream(Encoding.UTF8.GetBytes(xml))) - { - objectFactory = new XmlObjectFactory(new InputStreamResource(stream, string.Empty)); - } - - Type proxyType = (Type)objectFactory.GetObject("service"); - object[] attrs = proxyType.GetCustomAttributes(false); - - ServiceKnownTypeAttribute attrib = null; - - //loop thru all retreived attributes, attempting to find the one that is of the expected type - for (int i = 0; i < attrs.Length; i++) - { - attrib = attrs[i] as ServiceKnownTypeAttribute; - - //break out of the loop once we find the one we want - if (attrib != null) - break; - } - - Assert.NotNull(attrib, String.Format("No attributes of the expecte type {0} were found.", typeof(ServiceKnownTypeAttribute))); - Assert.AreEqual(typeof(List), attrib.Type, "Property 'Type' on Target Attribute not set!"); - } - - [Test] - public void NullConfig() + using (Stream stream = new MemoryStream(Encoding.UTF8.GetBytes(xml))) { - se.ObjectName = "NullConfig"; - Assert.Throws(() => se.AfterPropertiesSet(), "The TargetName property is required."); + objectFactory = new XmlObjectFactory(new InputStreamResource(stream, string.Empty)); } - [Test] // SPRNET-1416 - public void CallProxy() + Type proxyType = (Type) objectFactory.GetObject("service"); + object[] attrs = proxyType.GetCustomAttributes(false); + + ServiceKnownTypeAttribute attrib = null; + + //loop thru all retreived attributes, attempting to find the one that is of the expected type + for (int i = 0; i < attrs.Length; i++) { - se.ObjectName = "ProxiesContractInterface"; - se.TargetName = "service"; - se.AfterPropertiesSet(); + attrib = attrs[i] as ServiceKnownTypeAttribute; - Type proxyType = se.GetObject() as Type; - Assert.IsNotNull(proxyType); - IContract proxy = Activator.CreateInstance(proxyType) as IContract; - Assert.IsNotNull(proxyType); - Assert.AreEqual("1979", proxy.SomeMethod(1979)); + //break out of the loop once we find the one we want + if (attrib != null) + break; } - [Test] - public void ProxiesContractInterface() - { - se.ObjectName = "ProxiesContractInterface"; - se.TargetName = "service"; - se.AfterPropertiesSet(); - - Type proxyType = se.GetObject() as Type; - Assert.IsNotNull(proxyType); - Assert.IsTrue(typeof(IContract).IsAssignableFrom(proxyType)); - } - - [Test(Description = "http://jira.springframework.org/browse/SPRNET-1179")] - public void ProxiesOnlyContractInterface() - { - se.ObjectName = "ProxiesOnlyContractInterface"; - se.TargetName = "serviceWithMultipleInterfaces"; - se.ContractInterface = typeof(IContract); - se.AfterPropertiesSet(); - - Type proxyType = se.GetObject() as Type; - Assert.IsNotNull(proxyType); - Assert.IsTrue(typeof(IContract).IsAssignableFrom(proxyType)); - } - - [Test(Description = "https://jira.springsource.org/browse/SPRNET-1464")] - public void ProxiesInheritedContractInterface() - { - se.ObjectName = "ProxiesInheritedContractInterface"; - se.TargetName = "anotherService"; - se.ContractInterface = typeof(IInheritedContract); - se.AfterPropertiesSet(); - - Type proxyType = se.GetObject() as Type; - Assert.IsNotNull(proxyType); - Assert.IsTrue(typeof(IInheritedContract).IsAssignableFrom(proxyType)); - } - - [Test(Description = "http://jira.springframework.org/browse/SPRNET-1179")] - public void ProxiesOnlyContractInterfaceFailsIfNoContractInterface() - { - se.ObjectName = "ProxiesOnlyContractInterface"; - se.TargetName = "serviceWithMultipleInterfaces"; - // se.ContractInterface = typeof (IContract); - Assert.Throws(() => se.AfterPropertiesSet(), "ServiceExporter cannot export service type 'Spring.ServiceModel.ServiceExporterTests+ServiceWithMultipleInterfaces' as a WCF service because it implements multiple interfaces. Specify the contract interface to expose via the ContractInterface property."); - } - - [Test] - public void ProxyTypeEqualsObjectName() - { - se.ObjectName = "ProxyTypeEqualsObjectName"; - se.TargetName = "service"; - se.AfterPropertiesSet(); - - Type proxyType = se.GetObject() as Type; - Assert.IsNotNull(proxyType); - Assert.AreEqual("ProxyTypeEqualsObjectName", proxyType.FullName); - } - - [Test] - public void CreatesServiceContractAttributeWithNoDecoratedClassAndMinimalConfig() - { - se.ObjectName = "CreatesServiceContractAttributeWithNoDecoratedClassAndMinimalConfig"; - se.TargetName = "service"; - se.AfterPropertiesSet(); - - Type proxyType = se.GetObject() as Type; - Assert.IsNotNull(proxyType); - object[] attrs = proxyType.GetCustomAttributes(typeof(ServiceContractAttribute), true); - Assert.IsNotEmpty(attrs); - Assert.AreEqual(1, attrs.Length); - - ServiceContractAttribute sca = attrs[0] as ServiceContractAttribute; - Assert.IsNull(sca.CallbackContract); - Assert.AreEqual(typeof(IContract).FullName, sca.ConfigurationName); - Assert.AreEqual(typeof(IContract).Name, sca.Name); - Assert.IsNull(sca.Namespace); - Assert.AreEqual(ProtectionLevel.None, sca.ProtectionLevel); - Assert.AreEqual(SessionMode.Allowed, sca.SessionMode); - } - - [Test] - public void CreatesServiceContractAttributeWithNoDecoratedClassAndFullConfig() - { - se.ObjectName = "CreatesServiceContractAttributeWithNoDecoratedClassAndFullConfig"; - se.TargetName = "service"; - se.CallbackContract = typeof(IDisposable); - se.ConfigurationName = "CustomConfigName"; - se.Name = "serviceName"; - se.Namespace = "http://Spring.Services.Tests"; - se.ProtectionLevel = ProtectionLevel.Sign; - se.SessionMode = SessionMode.Required; - - se.AfterPropertiesSet(); - - Type proxyType = se.GetObject() as Type; - Assert.IsNotNull(proxyType); - object[] attrs = proxyType.GetCustomAttributes(typeof(ServiceContractAttribute), true); - Assert.IsNotEmpty(attrs); - Assert.AreEqual(1, attrs.Length); - - ServiceContractAttribute sca = attrs[0] as ServiceContractAttribute; - Assert.AreEqual(se.CallbackContract, sca.CallbackContract); - Assert.AreEqual(se.ConfigurationName, sca.ConfigurationName); - Assert.AreEqual(se.Name, sca.Name); - Assert.AreEqual(se.Namespace, sca.Namespace); - Assert.AreEqual(se.ProtectionLevel, sca.ProtectionLevel); - Assert.AreEqual(se.SessionMode, sca.SessionMode); - } - - [Test] - public void CreatesDefaultOperationContractAttributeWithNoDecoratedMethod() - { - se.ObjectName = "CreatesDefaultOperationContractAttributeWithNoDecoratedMethod"; - se.TargetName = "service"; - se.AfterPropertiesSet(); - - Type proxyType = se.GetObject() as Type; - Assert.IsNotNull(proxyType); - MethodInfo method = proxyType.GetMethod("SomeMethod"); - Assert.IsNotNull(method); - - object[] attrs = method.GetCustomAttributes(typeof(OperationContractAttribute), true); - Assert.IsNotEmpty(attrs); - Assert.AreEqual(1, attrs.Length); - } - - [Test] - public void CreatesCustomOperationContractAttributeWithNoDecoratedMethod() - { - OperationContractAttribute oca1 = new OperationContractAttribute(); - oca1.Name = "MySomeMethod"; - - se.ObjectName = "CreatesCustomOperationContractAttributeWithNoDecoratedMethod"; - se.TargetName = "service"; - se.MemberAttributes.Add("SomeMethod", oca1); - se.AfterPropertiesSet(); - - Type proxyType = se.GetObject() as Type; - Assert.IsNotNull(proxyType); - MethodInfo method = proxyType.GetMethod("SomeMethod"); - Assert.IsNotNull(method); - - object[] attrs = method.GetCustomAttributes(typeof(OperationContractAttribute), true); - Assert.IsNotEmpty(attrs); - Assert.AreEqual(1, attrs.Length); - - OperationContractAttribute oca2 = attrs[0] as OperationContractAttribute; - Assert.AreEqual(oca1.Name, oca2.Name); - } - - [Test] - public void OverridesExistingServiceContractAttributeWithDecoratedClass() - { - se.ObjectName = "OverridesExistingServiceContractAttributeWithDecoratedClass"; - se.TargetName = "decoratedService"; - se.AfterPropertiesSet(); - - Type proxyType = se.GetObject() as Type; - Assert.IsNotNull(proxyType); - object[] attrs = proxyType.GetCustomAttributes(typeof(ServiceContractAttribute), true); - Assert.IsNotEmpty(attrs); - Assert.AreEqual(1, attrs.Length); - - ServiceContractAttribute sca = attrs[0] as ServiceContractAttribute; - Assert.IsNull(sca.Namespace); - } - - [Test] - public void UsesExistingOperationContractAttributeWithDecoratedMethod() - { - se.ObjectName = "UsesExistingOperationContractAttributeWithDecoratedMethod"; - se.TargetName = "decoratedService"; - se.AfterPropertiesSet(); - - Type proxyType = se.GetObject() as Type; - Assert.IsNotNull(proxyType); - MethodInfo method = proxyType.GetMethod("SomeMethod"); - Assert.IsNotNull(method); - - object[] attrs = method.GetCustomAttributes(typeof(OperationContractAttribute), true); - Assert.IsNotEmpty(attrs); - Assert.AreEqual(1, attrs.Length); - - OperationContractAttribute oca = attrs[0] as OperationContractAttribute; - Assert.AreEqual("MySomeMethod", oca.Name); - } - - #region Test classes - - public interface IContract - { - string SomeMethod(int param); - } - - public interface IOtherContract - { } - - public class Service : IContract - { - public string SomeMethod(int param) - { - return param.ToString(); - } - } - - public class ServiceWithMultipleInterfaces : Service, IOtherContract - { - } - - [ServiceContract(Namespace = "http://Spring.Services.Tests")] - public class DecoratedService : IContract - { - [OperationContract(Name = "MySomeMethod")] - public string SomeMethod(int param) - { - return param.ToString(); - } - } - - public interface IInheritedContract : IContract - { - string AnotherMethod(int param); - } - - public class AnotherService : IInheritedContract - { - public string SomeMethod(int param) - { - return param.ToString(); - } - - public string AnotherMethod(int param) - { - return param.ToString(); - } - } - - //[ServiceContract(Namespace = "http://Spring.Services.Tests")] - //public interface IDecoratedContract - //{ - // [OperationContract] - // string SomeMethod(int param); - //} - - //public class AnotherService : IDecoratedContract - //{ - // public string SomeMethod(int param) - // { - // return param.ToString(); - // } - //} - - #endregion + Assert.NotNull(attrib, String.Format("No attributes of the expecte type {0} were found.", typeof(ServiceKnownTypeAttribute))); + Assert.AreEqual(typeof(List), attrib.Type, "Property 'Type' on Target Attribute not set!"); } + + [Test] + public void NullConfig() + { + se.ObjectName = "NullConfig"; + Assert.Throws(() => se.AfterPropertiesSet(), "The TargetName property is required."); + } + + [Test] // SPRNET-1416 + public void CallProxy() + { + se.ObjectName = "ProxiesContractInterface"; + se.TargetName = "service"; + se.AfterPropertiesSet(); + + Type proxyType = se.GetObject() as Type; + Assert.IsNotNull(proxyType); + IContract proxy = Activator.CreateInstance(proxyType) as IContract; + Assert.IsNotNull(proxyType); + Assert.AreEqual("1979", proxy.SomeMethod(1979)); + } + + [Test] + public void ProxiesContractInterface() + { + se.ObjectName = "ProxiesContractInterface"; + se.TargetName = "service"; + se.AfterPropertiesSet(); + + Type proxyType = se.GetObject() as Type; + Assert.IsNotNull(proxyType); + Assert.IsTrue(typeof(IContract).IsAssignableFrom(proxyType)); + } + + [Test(Description = "http://jira.springframework.org/browse/SPRNET-1179")] + public void ProxiesOnlyContractInterface() + { + se.ObjectName = "ProxiesOnlyContractInterface"; + se.TargetName = "serviceWithMultipleInterfaces"; + se.ContractInterface = typeof(IContract); + se.AfterPropertiesSet(); + + Type proxyType = se.GetObject() as Type; + Assert.IsNotNull(proxyType); + Assert.IsTrue(typeof(IContract).IsAssignableFrom(proxyType)); + } + + [Test(Description = "https://jira.springsource.org/browse/SPRNET-1464")] + public void ProxiesInheritedContractInterface() + { + se.ObjectName = "ProxiesInheritedContractInterface"; + se.TargetName = "anotherService"; + se.ContractInterface = typeof(IInheritedContract); + se.AfterPropertiesSet(); + + Type proxyType = se.GetObject() as Type; + Assert.IsNotNull(proxyType); + Assert.IsTrue(typeof(IInheritedContract).IsAssignableFrom(proxyType)); + } + + [Test(Description = "http://jira.springframework.org/browse/SPRNET-1179")] + public void ProxiesOnlyContractInterfaceFailsIfNoContractInterface() + { + se.ObjectName = "ProxiesOnlyContractInterface"; + se.TargetName = "serviceWithMultipleInterfaces"; + // se.ContractInterface = typeof (IContract); + Assert.Throws(() => se.AfterPropertiesSet(), "ServiceExporter cannot export service type 'Spring.ServiceModel.ServiceExporterTests+ServiceWithMultipleInterfaces' as a WCF service because it implements multiple interfaces. Specify the contract interface to expose via the ContractInterface property."); + } + + [Test] + public void ProxyTypeEqualsObjectName() + { + se.ObjectName = "ProxyTypeEqualsObjectName"; + se.TargetName = "service"; + se.AfterPropertiesSet(); + + Type proxyType = se.GetObject() as Type; + Assert.IsNotNull(proxyType); + Assert.AreEqual("ProxyTypeEqualsObjectName", proxyType.FullName); + } + + [Test] + public void CreatesServiceContractAttributeWithNoDecoratedClassAndMinimalConfig() + { + se.ObjectName = "CreatesServiceContractAttributeWithNoDecoratedClassAndMinimalConfig"; + se.TargetName = "service"; + se.AfterPropertiesSet(); + + Type proxyType = se.GetObject() as Type; + Assert.IsNotNull(proxyType); + object[] attrs = proxyType.GetCustomAttributes(typeof(ServiceContractAttribute), true); + Assert.IsNotEmpty(attrs); + Assert.AreEqual(1, attrs.Length); + + ServiceContractAttribute sca = attrs[0] as ServiceContractAttribute; + Assert.IsNull(sca.CallbackContract); + Assert.AreEqual(typeof(IContract).FullName, sca.ConfigurationName); + Assert.AreEqual(typeof(IContract).Name, sca.Name); + Assert.IsNull(sca.Namespace); + Assert.AreEqual(ProtectionLevel.None, sca.ProtectionLevel); + Assert.AreEqual(SessionMode.Allowed, sca.SessionMode); + } + + [Test] + public void CreatesServiceContractAttributeWithNoDecoratedClassAndFullConfig() + { + se.ObjectName = "CreatesServiceContractAttributeWithNoDecoratedClassAndFullConfig"; + se.TargetName = "service"; + se.CallbackContract = typeof(IDisposable); + se.ConfigurationName = "CustomConfigName"; + se.Name = "serviceName"; + se.Namespace = "http://Spring.Services.Tests"; + se.ProtectionLevel = ProtectionLevel.Sign; + se.SessionMode = SessionMode.Required; + + se.AfterPropertiesSet(); + + Type proxyType = se.GetObject() as Type; + Assert.IsNotNull(proxyType); + object[] attrs = proxyType.GetCustomAttributes(typeof(ServiceContractAttribute), true); + Assert.IsNotEmpty(attrs); + Assert.AreEqual(1, attrs.Length); + + ServiceContractAttribute sca = attrs[0] as ServiceContractAttribute; + Assert.AreEqual(se.CallbackContract, sca.CallbackContract); + Assert.AreEqual(se.ConfigurationName, sca.ConfigurationName); + Assert.AreEqual(se.Name, sca.Name); + Assert.AreEqual(se.Namespace, sca.Namespace); + Assert.AreEqual(se.ProtectionLevel, sca.ProtectionLevel); + Assert.AreEqual(se.SessionMode, sca.SessionMode); + } + + [Test] + public void CreatesDefaultOperationContractAttributeWithNoDecoratedMethod() + { + se.ObjectName = "CreatesDefaultOperationContractAttributeWithNoDecoratedMethod"; + se.TargetName = "service"; + se.AfterPropertiesSet(); + + Type proxyType = se.GetObject() as Type; + Assert.IsNotNull(proxyType); + MethodInfo method = proxyType.GetMethod("SomeMethod"); + Assert.IsNotNull(method); + + object[] attrs = method.GetCustomAttributes(typeof(OperationContractAttribute), true); + Assert.IsNotEmpty(attrs); + Assert.AreEqual(1, attrs.Length); + } + + [Test] + public void CreatesCustomOperationContractAttributeWithNoDecoratedMethod() + { + OperationContractAttribute oca1 = new OperationContractAttribute(); + oca1.Name = "MySomeMethod"; + + se.ObjectName = "CreatesCustomOperationContractAttributeWithNoDecoratedMethod"; + se.TargetName = "service"; + se.MemberAttributes.Add("SomeMethod", oca1); + se.AfterPropertiesSet(); + + Type proxyType = se.GetObject() as Type; + Assert.IsNotNull(proxyType); + MethodInfo method = proxyType.GetMethod("SomeMethod"); + Assert.IsNotNull(method); + + object[] attrs = method.GetCustomAttributes(typeof(OperationContractAttribute), true); + Assert.IsNotEmpty(attrs); + Assert.AreEqual(1, attrs.Length); + + OperationContractAttribute oca2 = attrs[0] as OperationContractAttribute; + Assert.AreEqual(oca1.Name, oca2.Name); + } + + [Test] + public void OverridesExistingServiceContractAttributeWithDecoratedClass() + { + se.ObjectName = "OverridesExistingServiceContractAttributeWithDecoratedClass"; + se.TargetName = "decoratedService"; + se.AfterPropertiesSet(); + + Type proxyType = se.GetObject() as Type; + Assert.IsNotNull(proxyType); + object[] attrs = proxyType.GetCustomAttributes(typeof(ServiceContractAttribute), true); + Assert.IsNotEmpty(attrs); + Assert.AreEqual(1, attrs.Length); + + ServiceContractAttribute sca = attrs[0] as ServiceContractAttribute; + Assert.IsNull(sca.Namespace); + } + + [Test] + public void UsesExistingOperationContractAttributeWithDecoratedMethod() + { + se.ObjectName = "UsesExistingOperationContractAttributeWithDecoratedMethod"; + se.TargetName = "decoratedService"; + se.AfterPropertiesSet(); + + Type proxyType = se.GetObject() as Type; + Assert.IsNotNull(proxyType); + MethodInfo method = proxyType.GetMethod("SomeMethod"); + Assert.IsNotNull(method); + + object[] attrs = method.GetCustomAttributes(typeof(OperationContractAttribute), true); + Assert.IsNotEmpty(attrs); + Assert.AreEqual(1, attrs.Length); + + OperationContractAttribute oca = attrs[0] as OperationContractAttribute; + Assert.AreEqual("MySomeMethod", oca.Name); + } + + #region Test classes + + public interface IContract + { + string SomeMethod(int param); + } + + public interface IOtherContract + { + } + + public class Service : IContract + { + public string SomeMethod(int param) + { + return param.ToString(); + } + } + + public class ServiceWithMultipleInterfaces : Service, IOtherContract + { + } + + [ServiceContract(Namespace = "http://Spring.Services.Tests")] + public class DecoratedService : IContract + { + [OperationContract(Name = "MySomeMethod")] + public string SomeMethod(int param) + { + return param.ToString(); + } + } + + public interface IInheritedContract : IContract + { + string AnotherMethod(int param); + } + + public class AnotherService : IInheritedContract + { + public string SomeMethod(int param) + { + return param.ToString(); + } + + public string AnotherMethod(int param) + { + return param.ToString(); + } + } + + //[ServiceContract(Namespace = "http://Spring.Services.Tests")] + //public interface IDecoratedContract + //{ + // [OperationContract] + // string SomeMethod(int param); + //} + + //public class AnotherService : IDecoratedContract + //{ + // public string SomeMethod(int param) + // { + // return param.ToString(); + // } + //} + + #endregion } diff --git a/test/Spring/Spring.Services.Tests/ServiceModel/SpringServiceHostTests.cs b/test/Spring/Spring.Services.Tests/ServiceModel/SpringServiceHostTests.cs index f556da4b..7a87dfb7 100644 --- a/test/Spring/Spring.Services.Tests/ServiceModel/SpringServiceHostTests.cs +++ b/test/Spring/Spring.Services.Tests/ServiceModel/SpringServiceHostTests.cs @@ -1,19 +1,19 @@ #region License -/* - * Copyright 2002-2010 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. +/* + * Copyright 2002-2010 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 @@ -22,39 +22,38 @@ using System.ServiceModel; using NUnit.Framework; using Spring.Objects.Factory.Support; -namespace Spring.ServiceModel +namespace Spring.ServiceModel; + +/// +/// +/// Erich Eichinger +[TestFixture] +public class SpringServiceHostTests { - /// - /// - /// Erich Eichinger - [TestFixture] - public class SpringServiceHostTests + [ServiceContract] + public interface IService { - [ServiceContract] - public interface IService + [OperationContract] + int Add(int a, int b); + } + + internal class Service : IService + { + public int Add(int a, int b) { - [OperationContract] - int Add(int a, int b); - } - - internal class Service : IService - { - public int Add(int a, int b) - { - return (a + b); - } - } - - [Test] - public void CanCreateHostTwice() - { - DefaultListableObjectFactory of = new DefaultListableObjectFactory(); - - string svcRegisteredName = System.Guid.NewGuid().ToString(); - - of.RegisterObjectDefinition(svcRegisteredName, new RootObjectDefinition(new RootObjectDefinition(typeof(Service)))); - SpringServiceHost ssh = new SpringServiceHost(svcRegisteredName, of, true); - SpringServiceHost ssh1 = new SpringServiceHost(svcRegisteredName, of, true); + return (a + b); } } + + [Test] + public void CanCreateHostTwice() + { + DefaultListableObjectFactory of = new DefaultListableObjectFactory(); + + string svcRegisteredName = System.Guid.NewGuid().ToString(); + + of.RegisterObjectDefinition(svcRegisteredName, new RootObjectDefinition(new RootObjectDefinition(typeof(Service)))); + SpringServiceHost ssh = new SpringServiceHost(svcRegisteredName, of, true); + SpringServiceHost ssh1 = new SpringServiceHost(svcRegisteredName, of, true); + } } diff --git a/test/Spring/Spring.Services.Tests/ServicesCompilerOptionsTests.cs b/test/Spring/Spring.Services.Tests/ServicesCompilerOptionsTests.cs index f9805f53..31d1f417 100644 --- a/test/Spring/Spring.Services.Tests/ServicesCompilerOptionsTests.cs +++ b/test/Spring/Spring.Services.Tests/ServicesCompilerOptionsTests.cs @@ -26,18 +26,17 @@ using Spring.Remoting; #endregion -namespace Spring +namespace Spring; + +/// Test that the assembly is built with the correct DebugAttributes in release and debug builds. +/// +/// Mark Pollack +[TestFixture] +public sealed class ServicesCompilerOptionTests : CompilerOptionsTests { - /// Test that the assembly is built with the correct DebugAttributes in release and debug builds. - /// - /// Mark Pollack - [TestFixture] - public sealed class ServicesCompilerOptionTests : CompilerOptionsTests + [OneTimeSetUp] + public void FixtureSetUp() { - [OneTimeSetUp] - public void FixtureSetUp() - { - AssemblyToCheck = Assembly.GetAssembly(typeof (CaoExporter)); - } + AssemblyToCheck = Assembly.GetAssembly(typeof(CaoExporter)); } } \ No newline at end of file diff --git a/test/Spring/Spring.Services.Tests/Web/Services/WebServiceProxyFactoryTests.cs b/test/Spring/Spring.Services.Tests/Web/Services/WebServiceProxyFactoryTests.cs index 35b2d65a..70f252b9 100644 --- a/test/Spring/Spring.Services.Tests/Web/Services/WebServiceProxyFactoryTests.cs +++ b/test/Spring/Spring.Services.Tests/Web/Services/WebServiceProxyFactoryTests.cs @@ -35,629 +35,628 @@ using Spring.Util; #endregion -namespace Spring.Web.Services +namespace Spring.Web.Services; + +/// +/// Unit tests for the WebServiceProxyFactory class. +/// +/// Bruno Baia +[TestFixture] +public class WebServiceProxyFactoryTests { - /// - /// Unit tests for the WebServiceProxyFactory class. - /// - /// Bruno Baia - [TestFixture] - public class WebServiceProxyFactoryTests + [Test] + public void BailsWhenNotConfigured() { - [Test] - public void BailsWhenNotConfigured() - { - WebServiceProxyFactory wspf = new WebServiceProxyFactory(); - Assert.Throws(() => wspf.AfterPropertiesSet()); - } - - [Test] - public void DocumentLiteralWithDefaultConfig() - { - WebServiceProxyFactory wspf = new WebServiceProxyFactory(); - wspf.ServiceUri = new AssemblyResource("assembly://Spring.Services.Tests/Spring.Data.Spring.Web.Services/document-literal.wsdl"); - wspf.ServiceInterface = typeof(IHelloWorld); - wspf.AfterPropertiesSet(); - - object proxy = wspf.GetObject(); - Assert.IsNotNull(proxy); - - Type proxyType = proxy.GetType(); - Assert.IsTrue(proxy is IHelloWorld); - Assert.IsTrue(proxy is SoapHttpClientProtocol); - - object[] typeAttrs = proxyType.GetCustomAttributes(typeof(WebServiceBindingAttribute), false); - Assert.IsTrue(typeAttrs.Length > 0); - - WebServiceBindingAttribute wsba = (WebServiceBindingAttribute)typeAttrs[0]; - Assert.AreEqual("HelloWorldServiceSoap", wsba.Name); - Assert.AreEqual("http://www.springframwework.net", wsba.Namespace); - - MethodInfo sayHelloWorldMethod = proxyType.GetMethod("SayHelloWorld"); - Assert.IsNotNull(sayHelloWorldMethod); - - object[] sdmaAttrs = sayHelloWorldMethod.GetCustomAttributes(typeof(SoapDocumentMethodAttribute), false); - Assert.IsTrue(sdmaAttrs.Length > 0); - - SoapDocumentMethodAttribute sdma = (SoapDocumentMethodAttribute)sdmaAttrs[0]; - Assert.AreEqual("http://www.springframwework.net/SayHelloWorld", sdma.Action); - Assert.AreEqual(SoapParameterStyle.Wrapped, sdma.ParameterStyle); - Assert.AreEqual(string.Empty, sdma.Binding); - Assert.AreEqual(false, sdma.OneWay); - Assert.AreEqual(string.Empty, sdma.RequestElementName); - Assert.AreEqual("http://www.springframwework.net", sdma.RequestNamespace); - Assert.AreEqual(string.Empty, sdma.ResponseElementName); - Assert.AreEqual("http://www.springframwework.net", sdma.ResponseNamespace); - Assert.AreEqual(SoapBindingUse.Literal, sdma.Use); - - // Try to instantiate the proxy type - ObjectUtils.InstantiateType(proxyType); - } - - [Test] - public void DocumentLiteralWithOneWay() - { - WebServiceProxyFactory wspf = new WebServiceProxyFactory(); - wspf.ServiceUri = new AssemblyResource("assembly://Spring.Services.Tests/Spring.Data.Spring.Web.Services/document-literal.wsdl"); - wspf.ServiceInterface = typeof(IHelloWorld); - wspf.AfterPropertiesSet(); - - object proxy = wspf.GetObject(); - Assert.IsNotNull(proxy); - - Type proxyType = proxy.GetType(); - Assert.IsTrue(proxy is IHelloWorld); - Assert.IsTrue(proxy is SoapHttpClientProtocol); - - MethodInfo logHelloWorldMethod = proxyType.GetMethod("LogHelloWorld"); - Assert.IsNotNull(logHelloWorldMethod); - - object[] methodAttrs = logHelloWorldMethod.GetCustomAttributes(typeof(SoapDocumentMethodAttribute), false); - Assert.IsTrue(methodAttrs.Length > 0); - - SoapDocumentMethodAttribute sdma = (SoapDocumentMethodAttribute)methodAttrs[0]; - Assert.AreEqual("http://www.springframwework.net/LogHelloWorld", sdma.Action); - Assert.AreEqual(SoapParameterStyle.Wrapped, sdma.ParameterStyle); - Assert.AreEqual(string.Empty, sdma.Binding); - Assert.AreEqual(true, sdma.OneWay); - Assert.AreEqual(string.Empty, sdma.RequestElementName); - Assert.AreEqual("http://www.springframwework.net", sdma.RequestNamespace); - Assert.AreEqual(string.Empty, sdma.ResponseElementName); - Assert.AreEqual(null, sdma.ResponseNamespace); - Assert.AreEqual(SoapBindingUse.Literal, sdma.Use); - - // Try to instantiate the proxy type - ObjectUtils.InstantiateType(proxyType); - } - - [Test] - public void DocumentLiteralWithMessageName() - { - WebServiceProxyFactory wspf = new WebServiceProxyFactory(); - wspf.ServiceUri = new AssemblyResource("assembly://Spring.Services.Tests/Spring.Data.Spring.Web.Services/document-literal.wsdl"); - wspf.ServiceInterface = typeof(IHelloWorld); - wspf.AfterPropertiesSet(); - - object proxy = wspf.GetObject(); - Assert.IsNotNull(proxy); - - Type proxyType = proxy.GetType(); - Assert.IsTrue(proxy is IHelloWorld); - Assert.IsTrue(proxy is SoapHttpClientProtocol); - - MethodInfo logHelloMethod = proxyType.GetMethod("LogHello"); - Assert.IsNotNull(logHelloMethod); - - object[] methodAttrs = logHelloMethod.GetCustomAttributes(typeof(SoapDocumentMethodAttribute), false); - Assert.IsTrue(methodAttrs.Length > 0); - - SoapDocumentMethodAttribute sdma = (SoapDocumentMethodAttribute)methodAttrs[0]; - Assert.AreEqual("http://www.springframwework.net/MyLogHello", sdma.Action); - Assert.AreEqual(SoapParameterStyle.Wrapped, sdma.ParameterStyle); - Assert.AreEqual(string.Empty, sdma.Binding); - Assert.AreEqual(false, sdma.OneWay); - Assert.AreEqual("MyLogHello", sdma.RequestElementName); - Assert.AreEqual("http://www.springframwework.net", sdma.RequestNamespace); - Assert.AreEqual("MyLogHelloResponse", sdma.ResponseElementName); - Assert.AreEqual("http://www.springframwework.net", sdma.ResponseNamespace); - Assert.AreEqual(SoapBindingUse.Literal, sdma.Use); - - // Try to instantiate the proxy type - ObjectUtils.InstantiateType(proxyType); - } - - [Test] - public void DocumentLiteralWithNamedOutParameter() - { - WebServiceProxyFactory wspf = new WebServiceProxyFactory(); - wspf.ServiceUri = new AssemblyResource("assembly://Spring.Services.Tests/Spring.Data.Spring.Web.Services/document-literal.wsdl"); - wspf.ServiceInterface = typeof(IHelloWorld); - wspf.AfterPropertiesSet(); - - object proxy = wspf.GetObject(); - Assert.IsNotNull(proxy); - - Type proxyType = proxy.GetType(); - Assert.IsTrue(proxy is IHelloWorld); - Assert.IsTrue(proxy is SoapHttpClientProtocol); - - MethodInfo sayHelloMethod = proxyType.GetMethod("SayHello"); - Assert.IsNotNull(sayHelloMethod); - - object[] sdmaAttrs = sayHelloMethod.GetCustomAttributes(typeof(SoapDocumentMethodAttribute), false); - Assert.IsTrue(sdmaAttrs.Length > 0); - - SoapDocumentMethodAttribute sdma = (SoapDocumentMethodAttribute)sdmaAttrs[0]; - Assert.AreEqual("http://www.springframwework.net/SayHello", sdma.Action); - Assert.AreEqual(SoapParameterStyle.Wrapped, sdma.ParameterStyle); - Assert.AreEqual(string.Empty, sdma.Binding); - Assert.AreEqual(false, sdma.OneWay); - Assert.AreEqual(string.Empty, sdma.RequestElementName); - Assert.AreEqual("http://www.springframwework.net", sdma.RequestNamespace); - Assert.AreEqual(string.Empty, sdma.ResponseElementName); - Assert.AreEqual("http://www.springframwework.net", sdma.ResponseNamespace); - Assert.AreEqual(SoapBindingUse.Literal, sdma.Use); - - object[] xeAttrs = sayHelloMethod.ReturnTypeCustomAttributes.GetCustomAttributes(typeof(XmlElementAttribute), false); - Assert.IsTrue(xeAttrs.Length > 0); - - XmlElementAttribute xea = (XmlElementAttribute)xeAttrs[0]; - Assert.AreEqual("out", xea.ElementName); - - // Try to instantiate the proxy type - ObjectUtils.InstantiateType(proxyType); - } - - [Test] - public void DocumentLiteralWithNamedOutArrayParameter() - { - WebServiceProxyFactory wspf = new WebServiceProxyFactory(); - wspf.ServiceUri = new AssemblyResource("assembly://Spring.Services.Tests/Spring.Data.Spring.Web.Services/document-literal.wsdl"); - wspf.ServiceInterface = typeof(IHelloWorld); - wspf.AfterPropertiesSet(); - - object proxy = wspf.GetObject(); - Assert.IsNotNull(proxy); - - Type proxyType = proxy.GetType(); - Assert.IsTrue(proxy is IHelloWorld); - Assert.IsTrue(proxy is SoapHttpClientProtocol); - - MethodInfo sayHelloArrayMethod = proxyType.GetMethod("SayHelloArray"); - Assert.IsNotNull(sayHelloArrayMethod); - - object[] sdmaAttrs = sayHelloArrayMethod.GetCustomAttributes(typeof(SoapDocumentMethodAttribute), false); - Assert.IsTrue(sdmaAttrs.Length > 0); - - SoapDocumentMethodAttribute sdma = (SoapDocumentMethodAttribute)sdmaAttrs[0]; - Assert.AreEqual("http://www.springframwework.net/SayHelloArray", sdma.Action); - Assert.AreEqual(SoapParameterStyle.Wrapped, sdma.ParameterStyle); - Assert.AreEqual(string.Empty, sdma.Binding); - Assert.AreEqual(false, sdma.OneWay); - Assert.AreEqual(string.Empty, sdma.RequestElementName); - Assert.AreEqual("http://www.springframwework.net", sdma.RequestNamespace); - Assert.AreEqual(string.Empty, sdma.ResponseElementName); - Assert.AreEqual("http://www.springframwework.net", sdma.ResponseNamespace); - Assert.AreEqual(SoapBindingUse.Literal, sdma.Use); - - object[] xaAttrs = sayHelloArrayMethod.ReturnTypeCustomAttributes.GetCustomAttributes(typeof(XmlArrayAttribute), false); - Assert.IsTrue(xaAttrs.Length > 0); - - XmlArrayAttribute xaa = (XmlArrayAttribute)xaAttrs[0]; - Assert.AreEqual("out", xaa.ElementName); - - // Try to instantiate the proxy type - ObjectUtils.InstantiateType(proxyType); - } - - [Test] - public void RpcLiteralWithNamedOutParameter() - { - WebServiceProxyFactory wspf = new WebServiceProxyFactory(); - wspf.ServiceUri = new AssemblyResource("assembly://Spring.Services.Tests/Spring.Data.Spring.Web.Services/rpc-literal.wsdl"); - wspf.ServiceInterface = typeof(IHelloWorld); - wspf.AfterPropertiesSet(); - - object proxy = wspf.GetObject(); - Assert.IsNotNull(proxy); - - Type proxyType = proxy.GetType(); - Assert.IsTrue(proxy is IHelloWorld); - Assert.IsTrue(proxy is SoapHttpClientProtocol); - - MethodInfo sayHelloMethod = proxyType.GetMethod("SayHello"); - Assert.IsNotNull(sayHelloMethod); - - object[] srmaAttrs = sayHelloMethod.GetCustomAttributes(typeof(SoapRpcMethodAttribute), false); - Assert.IsTrue(srmaAttrs.Length > 0); - - SoapRpcMethodAttribute srma = (SoapRpcMethodAttribute)srmaAttrs[0]; - Assert.AreEqual("http://www.springframwework.net/SayHello", srma.Action); - Assert.AreEqual(string.Empty, srma.Binding); - Assert.AreEqual(false, srma.OneWay); - Assert.AreEqual(string.Empty, srma.RequestElementName); - Assert.AreEqual("http://www.springframwework.net", srma.RequestNamespace); - Assert.AreEqual(string.Empty, srma.ResponseElementName); - Assert.AreEqual("http://www.springframwework.net", srma.ResponseNamespace); - Assert.AreEqual(SoapBindingUse.Literal, srma.Use); - - object[] xeAttrs = sayHelloMethod.ReturnTypeCustomAttributes.GetCustomAttributes(typeof(XmlElementAttribute), false); - Assert.IsTrue(xeAttrs.Length > 0); - - XmlElementAttribute xea = (XmlElementAttribute)xeAttrs[0]; - Assert.AreEqual("out", xea.ElementName); - - // Try to instantiate the proxy type - ObjectUtils.InstantiateType(proxyType); - } - - [Test] - public void RpcLiteralWithNamedOutArrayParameter() - { - WebServiceProxyFactory wspf = new WebServiceProxyFactory(); - wspf.ServiceUri = new AssemblyResource("assembly://Spring.Services.Tests/Spring.Data.Spring.Web.Services/rpc-literal.wsdl"); - wspf.ServiceInterface = typeof(IHelloWorld); - wspf.AfterPropertiesSet(); - - object proxy = wspf.GetObject(); - Assert.IsNotNull(proxy); - - Type proxyType = proxy.GetType(); - Assert.IsTrue(proxy is IHelloWorld); - Assert.IsTrue(proxy is SoapHttpClientProtocol); - - MethodInfo sayHelloArrayMethod = proxyType.GetMethod("SayHelloArray"); - Assert.IsNotNull(sayHelloArrayMethod); - - object[] srmaAttrs = sayHelloArrayMethod.GetCustomAttributes(typeof(SoapRpcMethodAttribute), false); - Assert.IsTrue(srmaAttrs.Length > 0); - - SoapRpcMethodAttribute srma = (SoapRpcMethodAttribute)srmaAttrs[0]; - Assert.AreEqual("http://www.springframwework.net/SayHelloArray", srma.Action); - Assert.AreEqual(string.Empty, srma.Binding); - Assert.AreEqual(false, srma.OneWay); - Assert.AreEqual(string.Empty, srma.RequestElementName); - Assert.AreEqual("http://www.springframwework.net", srma.RequestNamespace); - Assert.AreEqual(string.Empty, srma.ResponseElementName); - Assert.AreEqual("http://www.springframwework.net", srma.ResponseNamespace); - Assert.AreEqual(SoapBindingUse.Literal, srma.Use); - - object[] xaAttrs = sayHelloArrayMethod.ReturnTypeCustomAttributes.GetCustomAttributes(typeof(XmlArrayAttribute), false); - Assert.IsTrue(xaAttrs.Length > 0); - - XmlArrayAttribute xaa = (XmlArrayAttribute)xaAttrs[0]; - Assert.AreEqual("out", xaa.ElementName); - - // Try to instantiate the proxy type - ObjectUtils.InstantiateType(proxyType); - } - - [Test] - public void RpcLiteralWithDefaultConfig() - { - WebServiceProxyFactory wspf = new WebServiceProxyFactory(); - wspf.ServiceUri = new AssemblyResource("assembly://Spring.Services.Tests/Spring.Data.Spring.Web.Services/rpc-literal.wsdl"); - wspf.ServiceInterface = typeof(IHelloWorld); - wspf.AfterPropertiesSet(); - - object proxy = wspf.GetObject(); - Assert.IsNotNull(proxy); - - Type proxyType = proxy.GetType(); - Assert.IsTrue(proxy is IHelloWorld); - Assert.IsTrue(proxy is SoapHttpClientProtocol); - - object[] typeAttrs = proxyType.GetCustomAttributes(typeof(WebServiceBindingAttribute), false); - Assert.IsTrue(typeAttrs.Length > 0); - - WebServiceBindingAttribute wsba = (WebServiceBindingAttribute)typeAttrs[0]; - Assert.AreEqual("HelloWorldServiceSoap", wsba.Name); - Assert.AreEqual("http://www.springframwework.net", wsba.Namespace); - - MethodInfo sayHelloWorldMethod = proxyType.GetMethod("SayHelloWorld"); - Assert.IsNotNull(sayHelloWorldMethod); - - object[] srmaAttrs = sayHelloWorldMethod.GetCustomAttributes(typeof(SoapRpcMethodAttribute), false); - Assert.IsTrue(srmaAttrs.Length > 0); - - SoapRpcMethodAttribute srma = (SoapRpcMethodAttribute)srmaAttrs[0]; - Assert.AreEqual("http://www.springframwework.net/SayHelloWorld", srma.Action); - Assert.AreEqual(string.Empty, srma.Binding); - Assert.AreEqual(false, srma.OneWay); - Assert.AreEqual(string.Empty, srma.RequestElementName); - Assert.AreEqual("http://www.springframwework.net", srma.RequestNamespace); - Assert.AreEqual(string.Empty, srma.ResponseElementName); - Assert.AreEqual("http://www.springframwework.net", srma.ResponseNamespace); - Assert.AreEqual(SoapBindingUse.Literal, srma.Use); - - // Try to instantiate the proxy type - ObjectUtils.InstantiateType(proxyType); - } - - [Test] - public void RpcLiteralWithOneWay() - { - WebServiceProxyFactory wspf = new WebServiceProxyFactory(); - wspf.ServiceUri = new AssemblyResource("assembly://Spring.Services.Tests/Spring.Data.Spring.Web.Services/rpc-literal.wsdl"); - wspf.ServiceInterface = typeof(IHelloWorld); - wspf.AfterPropertiesSet(); - - object proxy = wspf.GetObject(); - Assert.IsNotNull(proxy); - - Type proxyType = proxy.GetType(); - Assert.IsTrue(proxy is IHelloWorld); - Assert.IsTrue(proxy is SoapHttpClientProtocol); - - MethodInfo logHelloWorldMethod = proxyType.GetMethod("LogHelloWorld"); - Assert.IsNotNull(logHelloWorldMethod); - - object[] methodAttrs = logHelloWorldMethod.GetCustomAttributes(typeof(SoapRpcMethodAttribute), false); - Assert.IsTrue(methodAttrs.Length > 0); - - SoapRpcMethodAttribute srma = (SoapRpcMethodAttribute)methodAttrs[0]; - Assert.AreEqual("http://www.springframwework.net/LogHelloWorld", srma.Action); - Assert.AreEqual(string.Empty, srma.Binding); - Assert.AreEqual(true, srma.OneWay); - Assert.AreEqual(string.Empty, srma.RequestElementName); - Assert.AreEqual("http://www.springframwework.net", srma.RequestNamespace); - Assert.AreEqual(string.Empty, srma.ResponseElementName); - Assert.AreEqual(null, srma.ResponseNamespace); - Assert.AreEqual(SoapBindingUse.Literal, srma.Use); - - // Try to instantiate the proxy type - ObjectUtils.InstantiateType(proxyType); - } - - [Test] - public void RpcLiteralWithMessageName() - { - WebServiceProxyFactory wspf = new WebServiceProxyFactory(); - wspf.ServiceUri = new AssemblyResource("assembly://Spring.Services.Tests/Spring.Data.Spring.Web.Services/rpc-literal.wsdl"); - wspf.ServiceInterface = typeof(IHelloWorld); - wspf.AfterPropertiesSet(); - - object proxy = wspf.GetObject(); - Assert.IsNotNull(proxy); - - Type proxyType = proxy.GetType(); - Assert.IsTrue(proxy is IHelloWorld); - Assert.IsTrue(proxy is SoapHttpClientProtocol); - - MethodInfo logHelloMethod = proxyType.GetMethod("LogHello"); - Assert.IsNotNull(logHelloMethod); - - object[] methodAttrs = logHelloMethod.GetCustomAttributes(typeof(SoapRpcMethodAttribute), false); - Assert.IsTrue(methodAttrs.Length > 0); - - SoapRpcMethodAttribute srma = (SoapRpcMethodAttribute)methodAttrs[0]; - Assert.AreEqual("http://www.springframwework.net/MyLogHello", srma.Action); - Assert.AreEqual(string.Empty, srma.Binding); - Assert.AreEqual(false, srma.OneWay); - Assert.AreEqual(string.Empty, srma.RequestElementName); - Assert.AreEqual("http://www.springframwework.net", srma.RequestNamespace); - Assert.AreEqual(string.Empty, srma.ResponseElementName); - Assert.AreEqual("http://www.springframwework.net", srma.ResponseNamespace); - Assert.AreEqual(SoapBindingUse.Literal, srma.Use); - - // Try to instantiate the proxy type - ObjectUtils.InstantiateType(proxyType); - } - - [Test] - public void WrapProxyType() - { - WebServiceProxyFactory wspf = new WebServiceProxyFactory(); - wspf.ProxyType = typeof(FakeProxyClass); - wspf.ServiceInterface = typeof(IHelloWorld); - wspf.AfterPropertiesSet(); - - object proxy = wspf.GetObject(); - Assert.IsNotNull(proxy); - - Type proxyType = proxy.GetType(); - Assert.IsTrue(proxy is IHelloWorld); - Assert.IsTrue(proxy is SoapHttpClientProtocol); - - // Try to instantiate the proxy type - ObjectUtils.InstantiateType(proxyType); - } - - [Test] - public void ConfigureSoapHttpClientProtocolWithServiceUri() - { - IApplicationContext ctx = new XmlApplicationContext("assembly://Spring.Services.Tests/Spring.Data.Spring.Web.Services/configurableFactory.xml"); - ContextRegistry.Clear(); - ContextRegistry.RegisterContext(ctx); - - object proxy = ctx.GetObject("withServiceUri"); - Assert.IsNotNull(proxy); - - Type proxyType = proxy.GetType(); - Assert.IsTrue(proxy is IHelloWorld); - Assert.IsTrue(proxy is SoapHttpClientProtocol); - - SoapHttpClientProtocol shcp = proxy as SoapHttpClientProtocol; - Assert.AreEqual("http://www.springframework.org/", shcp.Url); - Assert.AreEqual(10000, shcp.Timeout); - - // Try to instantiate the proxy type - ObjectUtils.InstantiateType(proxyType); - } - - [Test] - public void ConfigureSoapHttpClientProtocolWithProxyType() - { - IApplicationContext ctx = new XmlApplicationContext("assembly://Spring.Services.Tests/Spring.Data.Spring.Web.Services/configurableFactory.xml"); - ContextRegistry.Clear(); - ContextRegistry.RegisterContext(ctx); - - object proxy = ctx.GetObject("withProxyType"); - Assert.IsNotNull(proxy); - - Type proxyType = proxy.GetType(); - Assert.IsTrue(proxy is IHelloWorld); - Assert.IsTrue(proxy is SoapHttpClientProtocol); - - SoapHttpClientProtocol shcp = proxy as SoapHttpClientProtocol; - Assert.AreEqual("http://www.springframework.org/", shcp.Url); - Assert.AreEqual(10000, shcp.Timeout); - - // Try to instantiate the proxy type - ObjectUtils.InstantiateType(proxyType); - } - - [Test] - public void UseCustomClientProtocolType() - { - WebServiceProxyFactory wspf = new WebServiceProxyFactory(); - wspf.ServiceUri = new AssemblyResource("assembly://Spring.Services.Tests/Spring.Data.Spring.Web.Services/document-literal.wsdl"); - wspf.ServiceInterface = typeof(IHelloWorld); - wspf.WebServiceProxyBaseType = typeof(CustomClientProtocol); - wspf.AfterPropertiesSet(); - - object proxy = wspf.GetObject(); - Assert.IsNotNull(proxy); - - Type proxyType = proxy.GetType(); - Assert.IsTrue(proxy is IHelloWorld); - Assert.IsTrue(proxy is SoapHttpClientProtocol); - Assert.IsTrue(proxy is CustomClientProtocol); - - // Try to instantiate the proxy type - ObjectUtils.InstantiateType(proxyType); - } - - #region NestedSchema - - [Test] - public void NestedSchema() - { - WebServiceProxyFactory wspf = new WebServiceProxyFactory(); - // cf Post Build Events - wspf.ServiceUri = new FileSystemResource("file://~/Spring/Web/Services/nestedSchema.wsdl"); - wspf.ServiceInterface = typeof(INestedSchema); - wspf.AfterPropertiesSet(); - - object proxy = wspf.GetObject(); - Assert.IsNotNull(proxy); - - Type proxyType = proxy.GetType(); - Assert.IsTrue(proxy is INestedSchema); - Assert.IsTrue(proxy is SoapHttpClientProtocol); - - // Try to instantiate the proxy type - ObjectUtils.InstantiateType(proxyType); - } - - public interface INestedSchema - { - string testMethod(UserCredentials userCredentials); - } - - public class UserCredentials - { - } - - #endregion - - public void WcfBasicHttpBinding() - { - using (ServiceHost host = new ServiceHost(typeof(WcfServiceImpl), new Uri("http://localhost:8000/WcfBasicHttpBinding/Service"))) - { - host.AddServiceEndpoint(typeof(IWcfService), new BasicHttpBinding(), string.Empty); - - ServiceMetadataBehavior smb = new ServiceMetadataBehavior(); - smb.HttpGetEnabled = true; - host.Description.Behaviors.Add(smb); - - host.Open(); - - WebServiceProxyFactory wspf = new WebServiceProxyFactory(); - wspf.ServiceUri = new UrlResource("http://localhost:8000/WcfBasicHttpBinding/Service"); - wspf.ServiceInterface = typeof(IWcfService); - wspf.AfterPropertiesSet(); - - object proxy = wspf.GetObject(); - Assert.IsNotNull(proxy); - - Type proxyType = proxy.GetType(); - Assert.IsTrue(proxy is IWcfService); - Assert.IsTrue(proxy is SoapHttpClientProtocol); - - IWcfService srv = proxy as IWcfService; - Assert.AreEqual("5", srv.WcfMethod(5)); - } - } - - [ServiceContract(Namespace="http://www.springframework.net/")] - public interface IWcfService - { - [OperationContract] - string WcfMethod(int count); - } - - public class WcfServiceImpl : IWcfService - { - public string WcfMethod(int count) - { - return count.ToString(); - } - } - - #region Test Classes - - public interface IHelloWorld - { - string SayHelloWorld(); - string SayHello(string name); - string[] SayHelloArray(string name); - void LogHelloWorld(); - void LogHello(string name); - } - - /// - /// Fake Web Service proxy that does not implement any interface. - /// - /// - /// Note that methods matchs IHelloWorld interface methods. - /// - [WebServiceBinding(Name="FakeWebService")] - public class FakeProxyClass : SoapHttpClientProtocol - { - public FakeProxyClass() - { - this.Url = "http://www.fcporto.pt/"; - } - - public string SayHelloWorld() - { - return "Hello World !"; - } - - public string SayHello(string name) - { - return String.Format("Hello {0} !", name); - } - - public string[] SayHelloArray(string name) - { - return new string[] { "Hello ", name, " !" }; - } - - public void LogHelloWorld() - { - } - - public void LogHello(string name) - { - } - } - - public class CustomClientProtocol : SoapHttpClientProtocol - { - } - - #endregion + WebServiceProxyFactory wspf = new WebServiceProxyFactory(); + Assert.Throws(() => wspf.AfterPropertiesSet()); } -} + + [Test] + public void DocumentLiteralWithDefaultConfig() + { + WebServiceProxyFactory wspf = new WebServiceProxyFactory(); + wspf.ServiceUri = new AssemblyResource("assembly://Spring.Services.Tests/Spring.Data.Spring.Web.Services/document-literal.wsdl"); + wspf.ServiceInterface = typeof(IHelloWorld); + wspf.AfterPropertiesSet(); + + object proxy = wspf.GetObject(); + Assert.IsNotNull(proxy); + + Type proxyType = proxy.GetType(); + Assert.IsTrue(proxy is IHelloWorld); + Assert.IsTrue(proxy is SoapHttpClientProtocol); + + object[] typeAttrs = proxyType.GetCustomAttributes(typeof(WebServiceBindingAttribute), false); + Assert.IsTrue(typeAttrs.Length > 0); + + WebServiceBindingAttribute wsba = (WebServiceBindingAttribute) typeAttrs[0]; + Assert.AreEqual("HelloWorldServiceSoap", wsba.Name); + Assert.AreEqual("http://www.springframwework.net", wsba.Namespace); + + MethodInfo sayHelloWorldMethod = proxyType.GetMethod("SayHelloWorld"); + Assert.IsNotNull(sayHelloWorldMethod); + + object[] sdmaAttrs = sayHelloWorldMethod.GetCustomAttributes(typeof(SoapDocumentMethodAttribute), false); + Assert.IsTrue(sdmaAttrs.Length > 0); + + SoapDocumentMethodAttribute sdma = (SoapDocumentMethodAttribute) sdmaAttrs[0]; + Assert.AreEqual("http://www.springframwework.net/SayHelloWorld", sdma.Action); + Assert.AreEqual(SoapParameterStyle.Wrapped, sdma.ParameterStyle); + Assert.AreEqual(string.Empty, sdma.Binding); + Assert.AreEqual(false, sdma.OneWay); + Assert.AreEqual(string.Empty, sdma.RequestElementName); + Assert.AreEqual("http://www.springframwework.net", sdma.RequestNamespace); + Assert.AreEqual(string.Empty, sdma.ResponseElementName); + Assert.AreEqual("http://www.springframwework.net", sdma.ResponseNamespace); + Assert.AreEqual(SoapBindingUse.Literal, sdma.Use); + + // Try to instantiate the proxy type + ObjectUtils.InstantiateType(proxyType); + } + + [Test] + public void DocumentLiteralWithOneWay() + { + WebServiceProxyFactory wspf = new WebServiceProxyFactory(); + wspf.ServiceUri = new AssemblyResource("assembly://Spring.Services.Tests/Spring.Data.Spring.Web.Services/document-literal.wsdl"); + wspf.ServiceInterface = typeof(IHelloWorld); + wspf.AfterPropertiesSet(); + + object proxy = wspf.GetObject(); + Assert.IsNotNull(proxy); + + Type proxyType = proxy.GetType(); + Assert.IsTrue(proxy is IHelloWorld); + Assert.IsTrue(proxy is SoapHttpClientProtocol); + + MethodInfo logHelloWorldMethod = proxyType.GetMethod("LogHelloWorld"); + Assert.IsNotNull(logHelloWorldMethod); + + object[] methodAttrs = logHelloWorldMethod.GetCustomAttributes(typeof(SoapDocumentMethodAttribute), false); + Assert.IsTrue(methodAttrs.Length > 0); + + SoapDocumentMethodAttribute sdma = (SoapDocumentMethodAttribute) methodAttrs[0]; + Assert.AreEqual("http://www.springframwework.net/LogHelloWorld", sdma.Action); + Assert.AreEqual(SoapParameterStyle.Wrapped, sdma.ParameterStyle); + Assert.AreEqual(string.Empty, sdma.Binding); + Assert.AreEqual(true, sdma.OneWay); + Assert.AreEqual(string.Empty, sdma.RequestElementName); + Assert.AreEqual("http://www.springframwework.net", sdma.RequestNamespace); + Assert.AreEqual(string.Empty, sdma.ResponseElementName); + Assert.AreEqual(null, sdma.ResponseNamespace); + Assert.AreEqual(SoapBindingUse.Literal, sdma.Use); + + // Try to instantiate the proxy type + ObjectUtils.InstantiateType(proxyType); + } + + [Test] + public void DocumentLiteralWithMessageName() + { + WebServiceProxyFactory wspf = new WebServiceProxyFactory(); + wspf.ServiceUri = new AssemblyResource("assembly://Spring.Services.Tests/Spring.Data.Spring.Web.Services/document-literal.wsdl"); + wspf.ServiceInterface = typeof(IHelloWorld); + wspf.AfterPropertiesSet(); + + object proxy = wspf.GetObject(); + Assert.IsNotNull(proxy); + + Type proxyType = proxy.GetType(); + Assert.IsTrue(proxy is IHelloWorld); + Assert.IsTrue(proxy is SoapHttpClientProtocol); + + MethodInfo logHelloMethod = proxyType.GetMethod("LogHello"); + Assert.IsNotNull(logHelloMethod); + + object[] methodAttrs = logHelloMethod.GetCustomAttributes(typeof(SoapDocumentMethodAttribute), false); + Assert.IsTrue(methodAttrs.Length > 0); + + SoapDocumentMethodAttribute sdma = (SoapDocumentMethodAttribute) methodAttrs[0]; + Assert.AreEqual("http://www.springframwework.net/MyLogHello", sdma.Action); + Assert.AreEqual(SoapParameterStyle.Wrapped, sdma.ParameterStyle); + Assert.AreEqual(string.Empty, sdma.Binding); + Assert.AreEqual(false, sdma.OneWay); + Assert.AreEqual("MyLogHello", sdma.RequestElementName); + Assert.AreEqual("http://www.springframwework.net", sdma.RequestNamespace); + Assert.AreEqual("MyLogHelloResponse", sdma.ResponseElementName); + Assert.AreEqual("http://www.springframwework.net", sdma.ResponseNamespace); + Assert.AreEqual(SoapBindingUse.Literal, sdma.Use); + + // Try to instantiate the proxy type + ObjectUtils.InstantiateType(proxyType); + } + + [Test] + public void DocumentLiteralWithNamedOutParameter() + { + WebServiceProxyFactory wspf = new WebServiceProxyFactory(); + wspf.ServiceUri = new AssemblyResource("assembly://Spring.Services.Tests/Spring.Data.Spring.Web.Services/document-literal.wsdl"); + wspf.ServiceInterface = typeof(IHelloWorld); + wspf.AfterPropertiesSet(); + + object proxy = wspf.GetObject(); + Assert.IsNotNull(proxy); + + Type proxyType = proxy.GetType(); + Assert.IsTrue(proxy is IHelloWorld); + Assert.IsTrue(proxy is SoapHttpClientProtocol); + + MethodInfo sayHelloMethod = proxyType.GetMethod("SayHello"); + Assert.IsNotNull(sayHelloMethod); + + object[] sdmaAttrs = sayHelloMethod.GetCustomAttributes(typeof(SoapDocumentMethodAttribute), false); + Assert.IsTrue(sdmaAttrs.Length > 0); + + SoapDocumentMethodAttribute sdma = (SoapDocumentMethodAttribute) sdmaAttrs[0]; + Assert.AreEqual("http://www.springframwework.net/SayHello", sdma.Action); + Assert.AreEqual(SoapParameterStyle.Wrapped, sdma.ParameterStyle); + Assert.AreEqual(string.Empty, sdma.Binding); + Assert.AreEqual(false, sdma.OneWay); + Assert.AreEqual(string.Empty, sdma.RequestElementName); + Assert.AreEqual("http://www.springframwework.net", sdma.RequestNamespace); + Assert.AreEqual(string.Empty, sdma.ResponseElementName); + Assert.AreEqual("http://www.springframwework.net", sdma.ResponseNamespace); + Assert.AreEqual(SoapBindingUse.Literal, sdma.Use); + + object[] xeAttrs = sayHelloMethod.ReturnTypeCustomAttributes.GetCustomAttributes(typeof(XmlElementAttribute), false); + Assert.IsTrue(xeAttrs.Length > 0); + + XmlElementAttribute xea = (XmlElementAttribute) xeAttrs[0]; + Assert.AreEqual("out", xea.ElementName); + + // Try to instantiate the proxy type + ObjectUtils.InstantiateType(proxyType); + } + + [Test] + public void DocumentLiteralWithNamedOutArrayParameter() + { + WebServiceProxyFactory wspf = new WebServiceProxyFactory(); + wspf.ServiceUri = new AssemblyResource("assembly://Spring.Services.Tests/Spring.Data.Spring.Web.Services/document-literal.wsdl"); + wspf.ServiceInterface = typeof(IHelloWorld); + wspf.AfterPropertiesSet(); + + object proxy = wspf.GetObject(); + Assert.IsNotNull(proxy); + + Type proxyType = proxy.GetType(); + Assert.IsTrue(proxy is IHelloWorld); + Assert.IsTrue(proxy is SoapHttpClientProtocol); + + MethodInfo sayHelloArrayMethod = proxyType.GetMethod("SayHelloArray"); + Assert.IsNotNull(sayHelloArrayMethod); + + object[] sdmaAttrs = sayHelloArrayMethod.GetCustomAttributes(typeof(SoapDocumentMethodAttribute), false); + Assert.IsTrue(sdmaAttrs.Length > 0); + + SoapDocumentMethodAttribute sdma = (SoapDocumentMethodAttribute) sdmaAttrs[0]; + Assert.AreEqual("http://www.springframwework.net/SayHelloArray", sdma.Action); + Assert.AreEqual(SoapParameterStyle.Wrapped, sdma.ParameterStyle); + Assert.AreEqual(string.Empty, sdma.Binding); + Assert.AreEqual(false, sdma.OneWay); + Assert.AreEqual(string.Empty, sdma.RequestElementName); + Assert.AreEqual("http://www.springframwework.net", sdma.RequestNamespace); + Assert.AreEqual(string.Empty, sdma.ResponseElementName); + Assert.AreEqual("http://www.springframwework.net", sdma.ResponseNamespace); + Assert.AreEqual(SoapBindingUse.Literal, sdma.Use); + + object[] xaAttrs = sayHelloArrayMethod.ReturnTypeCustomAttributes.GetCustomAttributes(typeof(XmlArrayAttribute), false); + Assert.IsTrue(xaAttrs.Length > 0); + + XmlArrayAttribute xaa = (XmlArrayAttribute) xaAttrs[0]; + Assert.AreEqual("out", xaa.ElementName); + + // Try to instantiate the proxy type + ObjectUtils.InstantiateType(proxyType); + } + + [Test] + public void RpcLiteralWithNamedOutParameter() + { + WebServiceProxyFactory wspf = new WebServiceProxyFactory(); + wspf.ServiceUri = new AssemblyResource("assembly://Spring.Services.Tests/Spring.Data.Spring.Web.Services/rpc-literal.wsdl"); + wspf.ServiceInterface = typeof(IHelloWorld); + wspf.AfterPropertiesSet(); + + object proxy = wspf.GetObject(); + Assert.IsNotNull(proxy); + + Type proxyType = proxy.GetType(); + Assert.IsTrue(proxy is IHelloWorld); + Assert.IsTrue(proxy is SoapHttpClientProtocol); + + MethodInfo sayHelloMethod = proxyType.GetMethod("SayHello"); + Assert.IsNotNull(sayHelloMethod); + + object[] srmaAttrs = sayHelloMethod.GetCustomAttributes(typeof(SoapRpcMethodAttribute), false); + Assert.IsTrue(srmaAttrs.Length > 0); + + SoapRpcMethodAttribute srma = (SoapRpcMethodAttribute) srmaAttrs[0]; + Assert.AreEqual("http://www.springframwework.net/SayHello", srma.Action); + Assert.AreEqual(string.Empty, srma.Binding); + Assert.AreEqual(false, srma.OneWay); + Assert.AreEqual(string.Empty, srma.RequestElementName); + Assert.AreEqual("http://www.springframwework.net", srma.RequestNamespace); + Assert.AreEqual(string.Empty, srma.ResponseElementName); + Assert.AreEqual("http://www.springframwework.net", srma.ResponseNamespace); + Assert.AreEqual(SoapBindingUse.Literal, srma.Use); + + object[] xeAttrs = sayHelloMethod.ReturnTypeCustomAttributes.GetCustomAttributes(typeof(XmlElementAttribute), false); + Assert.IsTrue(xeAttrs.Length > 0); + + XmlElementAttribute xea = (XmlElementAttribute) xeAttrs[0]; + Assert.AreEqual("out", xea.ElementName); + + // Try to instantiate the proxy type + ObjectUtils.InstantiateType(proxyType); + } + + [Test] + public void RpcLiteralWithNamedOutArrayParameter() + { + WebServiceProxyFactory wspf = new WebServiceProxyFactory(); + wspf.ServiceUri = new AssemblyResource("assembly://Spring.Services.Tests/Spring.Data.Spring.Web.Services/rpc-literal.wsdl"); + wspf.ServiceInterface = typeof(IHelloWorld); + wspf.AfterPropertiesSet(); + + object proxy = wspf.GetObject(); + Assert.IsNotNull(proxy); + + Type proxyType = proxy.GetType(); + Assert.IsTrue(proxy is IHelloWorld); + Assert.IsTrue(proxy is SoapHttpClientProtocol); + + MethodInfo sayHelloArrayMethod = proxyType.GetMethod("SayHelloArray"); + Assert.IsNotNull(sayHelloArrayMethod); + + object[] srmaAttrs = sayHelloArrayMethod.GetCustomAttributes(typeof(SoapRpcMethodAttribute), false); + Assert.IsTrue(srmaAttrs.Length > 0); + + SoapRpcMethodAttribute srma = (SoapRpcMethodAttribute) srmaAttrs[0]; + Assert.AreEqual("http://www.springframwework.net/SayHelloArray", srma.Action); + Assert.AreEqual(string.Empty, srma.Binding); + Assert.AreEqual(false, srma.OneWay); + Assert.AreEqual(string.Empty, srma.RequestElementName); + Assert.AreEqual("http://www.springframwework.net", srma.RequestNamespace); + Assert.AreEqual(string.Empty, srma.ResponseElementName); + Assert.AreEqual("http://www.springframwework.net", srma.ResponseNamespace); + Assert.AreEqual(SoapBindingUse.Literal, srma.Use); + + object[] xaAttrs = sayHelloArrayMethod.ReturnTypeCustomAttributes.GetCustomAttributes(typeof(XmlArrayAttribute), false); + Assert.IsTrue(xaAttrs.Length > 0); + + XmlArrayAttribute xaa = (XmlArrayAttribute) xaAttrs[0]; + Assert.AreEqual("out", xaa.ElementName); + + // Try to instantiate the proxy type + ObjectUtils.InstantiateType(proxyType); + } + + [Test] + public void RpcLiteralWithDefaultConfig() + { + WebServiceProxyFactory wspf = new WebServiceProxyFactory(); + wspf.ServiceUri = new AssemblyResource("assembly://Spring.Services.Tests/Spring.Data.Spring.Web.Services/rpc-literal.wsdl"); + wspf.ServiceInterface = typeof(IHelloWorld); + wspf.AfterPropertiesSet(); + + object proxy = wspf.GetObject(); + Assert.IsNotNull(proxy); + + Type proxyType = proxy.GetType(); + Assert.IsTrue(proxy is IHelloWorld); + Assert.IsTrue(proxy is SoapHttpClientProtocol); + + object[] typeAttrs = proxyType.GetCustomAttributes(typeof(WebServiceBindingAttribute), false); + Assert.IsTrue(typeAttrs.Length > 0); + + WebServiceBindingAttribute wsba = (WebServiceBindingAttribute) typeAttrs[0]; + Assert.AreEqual("HelloWorldServiceSoap", wsba.Name); + Assert.AreEqual("http://www.springframwework.net", wsba.Namespace); + + MethodInfo sayHelloWorldMethod = proxyType.GetMethod("SayHelloWorld"); + Assert.IsNotNull(sayHelloWorldMethod); + + object[] srmaAttrs = sayHelloWorldMethod.GetCustomAttributes(typeof(SoapRpcMethodAttribute), false); + Assert.IsTrue(srmaAttrs.Length > 0); + + SoapRpcMethodAttribute srma = (SoapRpcMethodAttribute) srmaAttrs[0]; + Assert.AreEqual("http://www.springframwework.net/SayHelloWorld", srma.Action); + Assert.AreEqual(string.Empty, srma.Binding); + Assert.AreEqual(false, srma.OneWay); + Assert.AreEqual(string.Empty, srma.RequestElementName); + Assert.AreEqual("http://www.springframwework.net", srma.RequestNamespace); + Assert.AreEqual(string.Empty, srma.ResponseElementName); + Assert.AreEqual("http://www.springframwework.net", srma.ResponseNamespace); + Assert.AreEqual(SoapBindingUse.Literal, srma.Use); + + // Try to instantiate the proxy type + ObjectUtils.InstantiateType(proxyType); + } + + [Test] + public void RpcLiteralWithOneWay() + { + WebServiceProxyFactory wspf = new WebServiceProxyFactory(); + wspf.ServiceUri = new AssemblyResource("assembly://Spring.Services.Tests/Spring.Data.Spring.Web.Services/rpc-literal.wsdl"); + wspf.ServiceInterface = typeof(IHelloWorld); + wspf.AfterPropertiesSet(); + + object proxy = wspf.GetObject(); + Assert.IsNotNull(proxy); + + Type proxyType = proxy.GetType(); + Assert.IsTrue(proxy is IHelloWorld); + Assert.IsTrue(proxy is SoapHttpClientProtocol); + + MethodInfo logHelloWorldMethod = proxyType.GetMethod("LogHelloWorld"); + Assert.IsNotNull(logHelloWorldMethod); + + object[] methodAttrs = logHelloWorldMethod.GetCustomAttributes(typeof(SoapRpcMethodAttribute), false); + Assert.IsTrue(methodAttrs.Length > 0); + + SoapRpcMethodAttribute srma = (SoapRpcMethodAttribute) methodAttrs[0]; + Assert.AreEqual("http://www.springframwework.net/LogHelloWorld", srma.Action); + Assert.AreEqual(string.Empty, srma.Binding); + Assert.AreEqual(true, srma.OneWay); + Assert.AreEqual(string.Empty, srma.RequestElementName); + Assert.AreEqual("http://www.springframwework.net", srma.RequestNamespace); + Assert.AreEqual(string.Empty, srma.ResponseElementName); + Assert.AreEqual(null, srma.ResponseNamespace); + Assert.AreEqual(SoapBindingUse.Literal, srma.Use); + + // Try to instantiate the proxy type + ObjectUtils.InstantiateType(proxyType); + } + + [Test] + public void RpcLiteralWithMessageName() + { + WebServiceProxyFactory wspf = new WebServiceProxyFactory(); + wspf.ServiceUri = new AssemblyResource("assembly://Spring.Services.Tests/Spring.Data.Spring.Web.Services/rpc-literal.wsdl"); + wspf.ServiceInterface = typeof(IHelloWorld); + wspf.AfterPropertiesSet(); + + object proxy = wspf.GetObject(); + Assert.IsNotNull(proxy); + + Type proxyType = proxy.GetType(); + Assert.IsTrue(proxy is IHelloWorld); + Assert.IsTrue(proxy is SoapHttpClientProtocol); + + MethodInfo logHelloMethod = proxyType.GetMethod("LogHello"); + Assert.IsNotNull(logHelloMethod); + + object[] methodAttrs = logHelloMethod.GetCustomAttributes(typeof(SoapRpcMethodAttribute), false); + Assert.IsTrue(methodAttrs.Length > 0); + + SoapRpcMethodAttribute srma = (SoapRpcMethodAttribute) methodAttrs[0]; + Assert.AreEqual("http://www.springframwework.net/MyLogHello", srma.Action); + Assert.AreEqual(string.Empty, srma.Binding); + Assert.AreEqual(false, srma.OneWay); + Assert.AreEqual(string.Empty, srma.RequestElementName); + Assert.AreEqual("http://www.springframwework.net", srma.RequestNamespace); + Assert.AreEqual(string.Empty, srma.ResponseElementName); + Assert.AreEqual("http://www.springframwework.net", srma.ResponseNamespace); + Assert.AreEqual(SoapBindingUse.Literal, srma.Use); + + // Try to instantiate the proxy type + ObjectUtils.InstantiateType(proxyType); + } + + [Test] + public void WrapProxyType() + { + WebServiceProxyFactory wspf = new WebServiceProxyFactory(); + wspf.ProxyType = typeof(FakeProxyClass); + wspf.ServiceInterface = typeof(IHelloWorld); + wspf.AfterPropertiesSet(); + + object proxy = wspf.GetObject(); + Assert.IsNotNull(proxy); + + Type proxyType = proxy.GetType(); + Assert.IsTrue(proxy is IHelloWorld); + Assert.IsTrue(proxy is SoapHttpClientProtocol); + + // Try to instantiate the proxy type + ObjectUtils.InstantiateType(proxyType); + } + + [Test] + public void ConfigureSoapHttpClientProtocolWithServiceUri() + { + IApplicationContext ctx = new XmlApplicationContext("assembly://Spring.Services.Tests/Spring.Data.Spring.Web.Services/configurableFactory.xml"); + ContextRegistry.Clear(); + ContextRegistry.RegisterContext(ctx); + + object proxy = ctx.GetObject("withServiceUri"); + Assert.IsNotNull(proxy); + + Type proxyType = proxy.GetType(); + Assert.IsTrue(proxy is IHelloWorld); + Assert.IsTrue(proxy is SoapHttpClientProtocol); + + SoapHttpClientProtocol shcp = proxy as SoapHttpClientProtocol; + Assert.AreEqual("http://www.springframework.org/", shcp.Url); + Assert.AreEqual(10000, shcp.Timeout); + + // Try to instantiate the proxy type + ObjectUtils.InstantiateType(proxyType); + } + + [Test] + public void ConfigureSoapHttpClientProtocolWithProxyType() + { + IApplicationContext ctx = new XmlApplicationContext("assembly://Spring.Services.Tests/Spring.Data.Spring.Web.Services/configurableFactory.xml"); + ContextRegistry.Clear(); + ContextRegistry.RegisterContext(ctx); + + object proxy = ctx.GetObject("withProxyType"); + Assert.IsNotNull(proxy); + + Type proxyType = proxy.GetType(); + Assert.IsTrue(proxy is IHelloWorld); + Assert.IsTrue(proxy is SoapHttpClientProtocol); + + SoapHttpClientProtocol shcp = proxy as SoapHttpClientProtocol; + Assert.AreEqual("http://www.springframework.org/", shcp.Url); + Assert.AreEqual(10000, shcp.Timeout); + + // Try to instantiate the proxy type + ObjectUtils.InstantiateType(proxyType); + } + + [Test] + public void UseCustomClientProtocolType() + { + WebServiceProxyFactory wspf = new WebServiceProxyFactory(); + wspf.ServiceUri = new AssemblyResource("assembly://Spring.Services.Tests/Spring.Data.Spring.Web.Services/document-literal.wsdl"); + wspf.ServiceInterface = typeof(IHelloWorld); + wspf.WebServiceProxyBaseType = typeof(CustomClientProtocol); + wspf.AfterPropertiesSet(); + + object proxy = wspf.GetObject(); + Assert.IsNotNull(proxy); + + Type proxyType = proxy.GetType(); + Assert.IsTrue(proxy is IHelloWorld); + Assert.IsTrue(proxy is SoapHttpClientProtocol); + Assert.IsTrue(proxy is CustomClientProtocol); + + // Try to instantiate the proxy type + ObjectUtils.InstantiateType(proxyType); + } + + #region NestedSchema + + [Test] + public void NestedSchema() + { + WebServiceProxyFactory wspf = new WebServiceProxyFactory(); + // cf Post Build Events + wspf.ServiceUri = new FileSystemResource("file://~/Spring/Web/Services/nestedSchema.wsdl"); + wspf.ServiceInterface = typeof(INestedSchema); + wspf.AfterPropertiesSet(); + + object proxy = wspf.GetObject(); + Assert.IsNotNull(proxy); + + Type proxyType = proxy.GetType(); + Assert.IsTrue(proxy is INestedSchema); + Assert.IsTrue(proxy is SoapHttpClientProtocol); + + // Try to instantiate the proxy type + ObjectUtils.InstantiateType(proxyType); + } + + public interface INestedSchema + { + string testMethod(UserCredentials userCredentials); + } + + public class UserCredentials + { + } + + #endregion + + public void WcfBasicHttpBinding() + { + using (ServiceHost host = new ServiceHost(typeof(WcfServiceImpl), new Uri("http://localhost:8000/WcfBasicHttpBinding/Service"))) + { + host.AddServiceEndpoint(typeof(IWcfService), new BasicHttpBinding(), string.Empty); + + ServiceMetadataBehavior smb = new ServiceMetadataBehavior(); + smb.HttpGetEnabled = true; + host.Description.Behaviors.Add(smb); + + host.Open(); + + WebServiceProxyFactory wspf = new WebServiceProxyFactory(); + wspf.ServiceUri = new UrlResource("http://localhost:8000/WcfBasicHttpBinding/Service"); + wspf.ServiceInterface = typeof(IWcfService); + wspf.AfterPropertiesSet(); + + object proxy = wspf.GetObject(); + Assert.IsNotNull(proxy); + + Type proxyType = proxy.GetType(); + Assert.IsTrue(proxy is IWcfService); + Assert.IsTrue(proxy is SoapHttpClientProtocol); + + IWcfService srv = proxy as IWcfService; + Assert.AreEqual("5", srv.WcfMethod(5)); + } + } + + [ServiceContract(Namespace = "http://www.springframework.net/")] + public interface IWcfService + { + [OperationContract] + string WcfMethod(int count); + } + + public class WcfServiceImpl : IWcfService + { + public string WcfMethod(int count) + { + return count.ToString(); + } + } + + #region Test Classes + + public interface IHelloWorld + { + string SayHelloWorld(); + string SayHello(string name); + string[] SayHelloArray(string name); + void LogHelloWorld(); + void LogHello(string name); + } + + /// + /// Fake Web Service proxy that does not implement any interface. + /// + /// + /// Note that methods matchs IHelloWorld interface methods. + /// + [WebServiceBinding(Name = "FakeWebService")] + public class FakeProxyClass : SoapHttpClientProtocol + { + public FakeProxyClass() + { + this.Url = "http://www.fcporto.pt/"; + } + + public string SayHelloWorld() + { + return "Hello World !"; + } + + public string SayHello(string name) + { + return String.Format("Hello {0} !", name); + } + + public string[] SayHelloArray(string name) + { + return new string[] { "Hello ", name, " !" }; + } + + public void LogHelloWorld() + { + } + + public void LogHello(string name) + { + } + } + + public class CustomClientProtocol : SoapHttpClientProtocol + { + } + + #endregion +} \ No newline at end of file diff --git a/test/Spring/Spring.Services.Tests/tests.config b/test/Spring/Spring.Services.Tests/tests.config index 264c25a6..049f0646 100644 --- a/test/Spring/Spring.Services.Tests/tests.config +++ b/test/Spring/Spring.Services.Tests/tests.config @@ -1,48 +1,48 @@ - -
- - + +
+ + - - - - - + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - + + + + - - - + + --> + diff --git a/test/Spring/Spring.Template.Velocity.Castle.Tests/App.config b/test/Spring/Spring.Template.Velocity.Castle.Tests/App.config index d3d2ad3e..94c45c6a 100644 --- a/test/Spring/Spring.Template.Velocity.Castle.Tests/App.config +++ b/test/Spring/Spring.Template.Velocity.Castle.Tests/App.config @@ -3,7 +3,7 @@ -
+
@@ -12,5 +12,5 @@ - + \ No newline at end of file diff --git a/test/Spring/Spring.Template.Velocity.Castle.Tests/Template/Velocity/Config/TemplateNamespaceParserTests.cs b/test/Spring/Spring.Template.Velocity.Castle.Tests/Template/Velocity/Config/TemplateNamespaceParserTests.cs index 9117df72..42c469df 100644 --- a/test/Spring/Spring.Template.Velocity.Castle.Tests/Template/Velocity/Config/TemplateNamespaceParserTests.cs +++ b/test/Spring/Spring.Template.Velocity.Castle.Tests/Template/Velocity/Config/TemplateNamespaceParserTests.cs @@ -32,172 +32,196 @@ using Spring.Core.IO; #endregion -namespace Spring.Template.Velocity.Config { +namespace Spring.Template.Velocity.Config; + +/// +/// This class contains tests for the template namespace configuration parser +/// +/// Erez Mazor +[TestFixture] +public class TemplateNamespaceParserTests : VelocityEngineTestBase +{ + #region convinience properties aliases + + private const string PropertyModificationCheck = + TemplateDefinitionConstants.PropertyResourceLoaderModificationCheckInterval; + + private const string PropertyResourceLoaderCachce = + TemplateDefinitionConstants.PropertyResourceLoaderCaching; + + #endregion + + #region test constants + + private const int DEFAULT_CACHE_SIZE = 200; + private const int DEFAULT_MOD_CHECK = 30; + private const bool DEFAULT_CACHE_FLAG = true; + + #endregion + /// - /// This class contains tests for the template namespace configuration parser + /// Test a full file-base configuration /// - /// Erez Mazor - [TestFixture] - public class TemplateNamespaceParserTests : VelocityEngineTestBase { - #region convinience properties aliases - private const string PropertyModificationCheck = - TemplateDefinitionConstants.PropertyResourceLoaderModificationCheckInterval; - private const string PropertyResourceLoaderCachce = - TemplateDefinitionConstants.PropertyResourceLoaderCaching; - #endregion + [Test] + public void TestFileBasedConfig() + { + VelocityEngine velocityEngine = appContext.GetObject("cnFileVelocityEngine") as VelocityEngine; + Assert.IsNotNull(velocityEngine, "velocity engine is null"); + Assert.AreEqual(VelocityConstants.File, getSingleProperty(velocityEngine, RuntimeConstants.RESOURCE_LOADER), "incorrect resource loader"); + Assert.AreEqual(TemplateDefinitionConstants.FileResourceLoaderClass, getSingleProperty(velocityEngine, + TemplateNamespaceParser.getResourceLoaderProperty(VelocityConstants.File, VelocityConstants.Class)), "incorrect resource loader type"); + Assert.AreEqual(new string[] { "Template/Velocity/", "Template/" }, velocityEngine.GetProperty( + TemplateNamespaceParser.getResourceLoaderProperty(VelocityConstants.File, VelocityConstants.Path)), "incorrect resource loader path"); + Assert.AreEqual(DEFAULT_CACHE_SIZE, velocityEngine.GetProperty(RuntimeConstants.RESOURCE_MANAGER_DEFAULTCACHE_SIZE), "incorrect default cache size"); + Assert.AreEqual(DEFAULT_MOD_CHECK, velocityEngine.GetProperty( + VelocityConstants.File + VelocityConstants.Separator + PropertyModificationCheck), "incorrect mod check interval"); + Assert.AreEqual(DEFAULT_CACHE_FLAG, velocityEngine.GetProperty(VelocityConstants.File + VelocityConstants.Separator + PropertyResourceLoaderCachce), + "incorrect caching flag"); - #region test constants - private const int DEFAULT_CACHE_SIZE = 200; - private const int DEFAULT_MOD_CHECK = 30; - private const bool DEFAULT_CACHE_FLAG = true; - #endregion - - /// - /// Test a full file-base configuration - /// - [Test] - public void TestFileBasedConfig() { - VelocityEngine velocityEngine = appContext.GetObject("cnFileVelocityEngine") as VelocityEngine; - Assert.IsNotNull(velocityEngine, "velocity engine is null"); - Assert.AreEqual(VelocityConstants.File, getSingleProperty(velocityEngine, RuntimeConstants.RESOURCE_LOADER), "incorrect resource loader"); - Assert.AreEqual(TemplateDefinitionConstants.FileResourceLoaderClass, getSingleProperty(velocityEngine, - TemplateNamespaceParser.getResourceLoaderProperty(VelocityConstants.File, VelocityConstants.Class)), "incorrect resource loader type"); - Assert.AreEqual(new string[]{"Template/Velocity/", "Template/"}, velocityEngine.GetProperty( - TemplateNamespaceParser.getResourceLoaderProperty(VelocityConstants.File, VelocityConstants.Path)), "incorrect resource loader path"); - Assert.AreEqual(DEFAULT_CACHE_SIZE, velocityEngine.GetProperty(RuntimeConstants.RESOURCE_MANAGER_DEFAULTCACHE_SIZE), "incorrect default cache size"); - Assert.AreEqual(DEFAULT_MOD_CHECK, velocityEngine.GetProperty( - VelocityConstants.File + VelocityConstants.Separator + PropertyModificationCheck), "incorrect mod check interval"); - Assert.AreEqual(DEFAULT_CACHE_FLAG, velocityEngine.GetProperty(VelocityConstants.File + VelocityConstants.Separator + PropertyResourceLoaderCachce), - "incorrect caching flag"); - - AssertMergedValue(velocityEngine, "SimpleTemplate.vm"); - } - - /// - /// Test a full aaembly-based configuration - /// - [Test] - public void TestAssemblyBasedConfig() { - VelocityEngine velocityEngine = appContext.GetObject("cnAssemblyVelocityEngine") as VelocityEngine; - Assert.IsNotNull(velocityEngine, "velocity engine is null"); - Assert.AreEqual(VelocityConstants.Assembly, getSingleProperty(velocityEngine, RuntimeConstants.RESOURCE_LOADER), "incorrect resource loader"); - Assert.AreEqual(TemplateDefinitionConstants.AssemblyResourceLoaderClass, getSingleProperty(velocityEngine, - TemplateNamespaceParser.getResourceLoaderProperty(VelocityConstants.Assembly, VelocityConstants.Class)), "incorrect resource loader type"); - Assert.AreEqual("Spring.Template.Velocity.Castle.Tests", getSingleProperty(velocityEngine, - TemplateNamespaceParser.getResourceLoaderProperty(VelocityConstants.Assembly,VelocityConstants.Assembly)), "incorrect resource loader path"); - Assert.AreEqual(DEFAULT_CACHE_SIZE, velocityEngine.GetProperty(RuntimeConstants.RESOURCE_MANAGER_DEFAULTCACHE_SIZE), "incorrect default cache size"); - Assert.AreEqual(DEFAULT_CACHE_FLAG, velocityEngine.GetProperty(VelocityConstants.Assembly + VelocityConstants.Separator + PropertyResourceLoaderCachce), - "incorrect caching flag"); - AssertMergedValue(velocityEngine, "Spring.Template.Velocity.SimpleTemplate.vm"); - } - - /// - /// Test a full aaembly-based configuration - /// - [Test] - public void TestSpringBasedConfig() { - VelocityEngine velocityEngine = appContext.GetObject("cnSpringVelocityEngine") as VelocityEngine; - Assert.IsNotNull(velocityEngine, "velocity engine is null"); - const string PropertySpring = TemplateDefinitionConstants.Spring; - Assert.AreEqual(PropertySpring, getSingleProperty(velocityEngine, RuntimeConstants.RESOURCE_LOADER), "incorrect resource loader"); - Assert.AreEqual(TemplateDefinitionConstants.SpringResourceLoaderClass, getSingleProperty(velocityEngine, - TemplateNamespaceParser.getResourceLoaderProperty(PropertySpring, VelocityConstants.Class)), "incorrect resource loader type"); - // no way to test the path property other than trying to actually perform a merge (it is set in velocity engine as an application attribute which is not exposed) - Assert.AreEqual(DEFAULT_CACHE_SIZE, velocityEngine.GetProperty(RuntimeConstants.RESOURCE_MANAGER_DEFAULTCACHE_SIZE), "incorrect default cache size"); - Assert.AreEqual(DEFAULT_CACHE_FLAG, velocityEngine.GetProperty(PropertySpring + VelocityConstants.Separator + PropertyResourceLoaderCachce), - "incorrect caching flag"); - - AssertMergedValue(velocityEngine, "SimpleTemplate.vm"); - AssertMergedValue(velocityEngine, "EmbeddedTemplate.vm"); - } - - /// - /// Test using an external configuration properties definition - /// - [Test] - public void TestGlobalConfig() { - VelocityEngine velocityEngine = appContext.GetObject("cnVelocityEngineConfig") as VelocityEngine; - Assert.IsNotNull(velocityEngine, "velocity engine is null"); - - string classProp = TemplateNamespaceParser.getResourceLoaderProperty(VelocityConstants.Assembly, VelocityConstants.Class); - string descProp = TemplateNamespaceParser.getResourceLoaderProperty(VelocityConstants.Assembly, VelocityConstants.Description); - - Assert.AreEqual(VelocityConstants.Assembly, getSingleProperty(velocityEngine, RuntimeConstants.RESOURCE_LOADER), "incorrect resource loader"); - Assert.AreEqual("NVelocity.Runtime.Resource.Loader.AssemblyResourceLoader", - getSingleProperty(velocityEngine,classProp), "incorrect resource loader type"); - Assert.AreEqual("TestDescription", getSingleProperty(velocityEngine, descProp), "incorrect description"); - } - - /// - /// Test using local config. - /// - [Test] - public void TestLocalConfig() { - VelocityEngine velocityEngine = appContext.GetObject("cnVelocityEngineLocalConfig") as VelocityEngine; - Assert.IsNotNull(velocityEngine, "velocity engine is null"); - - Assert.AreEqual(Encoding.UTF8.WebName.ToUpper(), getSingleProperty(velocityEngine, RuntimeConstants.INPUT_ENCODING), "incorrect input encoding value"); - Assert.AreEqual(TEST_VALUE, getSingleProperty(velocityEngine, "myproperty.mysubproperty"), "incorrect custom property value"); - } - - /// - /// Test a custom resource loader definition - /// - [Test] - public void TestCustomResourceLoader() { - VelocityEngine velocityEngine = appContext.GetObject("cnVelocityEngingCustomResourceLoader") as VelocityEngine; - Assert.IsNotNull(velocityEngine, "velocity engine is null"); - const string PropertyMyResourceLoader = "myResourceLoader"; - string classProp = TemplateNamespaceParser.getResourceLoaderProperty(PropertyMyResourceLoader, VelocityConstants.Class); - string descProp = TemplateNamespaceParser.getResourceLoaderProperty(PropertyMyResourceLoader, VelocityConstants.Description); - - Assert.AreEqual(PropertyMyResourceLoader, getSingleProperty(velocityEngine, RuntimeConstants.RESOURCE_LOADER), "incorrect resource loader"); - - Assert.AreEqual("Spring.Template.Velocity.Config.TestCustomResourceLoader; Spring.Template.Velocity.Castle.Tests", - getSingleProperty(velocityEngine, classProp), "incorrect resource loader type"); - Assert.AreEqual(PropertyMyResourceLoader, getSingleProperty(velocityEngine, RuntimeConstants.RESOURCE_LOADER), "incorrect resource loader"); - Assert.AreEqual("A custom resource loader", - getSingleProperty(velocityEngine, descProp), "incorrect resource loader description"); - Assert.AreEqual("Template/Velocity/", getSingleProperty(velocityEngine, - TemplateNamespaceParser.getResourceLoaderProperty(PropertyMyResourceLoader, VelocityConstants.Path)), "incorrect resource loader path"); - - AssertMergedValue(velocityEngine, "Template/Velocity/SimpleTemplate.vm"); - } - - #region internal test methods - /// - /// Grab a single property from (if it's an array return the first value) from the velocityEngine - /// - private string getSingleProperty(VelocityEngine velocityEngine, string prop) { - object property = velocityEngine.GetProperty(prop); - if (property is ArrayList) { - ArrayList list = (ArrayList)property; - return (string)list[0]; - } - return (string)property; - } - #endregion + AssertMergedValue(velocityEngine, "SimpleTemplate.vm"); } - #region test classes /// - /// Test class for a custom resource loader class + /// Test a full aaembly-based configuration /// - internal sealed class TestCustomResourceLoader : ResourceLoader { - public override void Init(ExtendedProperties configuration) { - } - - public override Stream GetResourceStream(string source) { - return new ConfigurableResourceLoader().GetResource(source).InputStream; - } - - public override bool IsSourceModified(Resource resource) { - return false; - } - - public override long GetLastModified(Resource resource) { - return resource.LastModified; - } + [Test] + public void TestAssemblyBasedConfig() + { + VelocityEngine velocityEngine = appContext.GetObject("cnAssemblyVelocityEngine") as VelocityEngine; + Assert.IsNotNull(velocityEngine, "velocity engine is null"); + Assert.AreEqual(VelocityConstants.Assembly, getSingleProperty(velocityEngine, RuntimeConstants.RESOURCE_LOADER), "incorrect resource loader"); + Assert.AreEqual(TemplateDefinitionConstants.AssemblyResourceLoaderClass, getSingleProperty(velocityEngine, + TemplateNamespaceParser.getResourceLoaderProperty(VelocityConstants.Assembly, VelocityConstants.Class)), "incorrect resource loader type"); + Assert.AreEqual("Spring.Template.Velocity.Castle.Tests", getSingleProperty(velocityEngine, + TemplateNamespaceParser.getResourceLoaderProperty(VelocityConstants.Assembly, VelocityConstants.Assembly)), "incorrect resource loader path"); + Assert.AreEqual(DEFAULT_CACHE_SIZE, velocityEngine.GetProperty(RuntimeConstants.RESOURCE_MANAGER_DEFAULTCACHE_SIZE), "incorrect default cache size"); + Assert.AreEqual(DEFAULT_CACHE_FLAG, velocityEngine.GetProperty(VelocityConstants.Assembly + VelocityConstants.Separator + PropertyResourceLoaderCachce), + "incorrect caching flag"); + AssertMergedValue(velocityEngine, "Spring.Template.Velocity.SimpleTemplate.vm"); } + + /// + /// Test a full aaembly-based configuration + /// + [Test] + public void TestSpringBasedConfig() + { + VelocityEngine velocityEngine = appContext.GetObject("cnSpringVelocityEngine") as VelocityEngine; + Assert.IsNotNull(velocityEngine, "velocity engine is null"); + const string PropertySpring = TemplateDefinitionConstants.Spring; + Assert.AreEqual(PropertySpring, getSingleProperty(velocityEngine, RuntimeConstants.RESOURCE_LOADER), "incorrect resource loader"); + Assert.AreEqual(TemplateDefinitionConstants.SpringResourceLoaderClass, getSingleProperty(velocityEngine, + TemplateNamespaceParser.getResourceLoaderProperty(PropertySpring, VelocityConstants.Class)), "incorrect resource loader type"); + // no way to test the path property other than trying to actually perform a merge (it is set in velocity engine as an application attribute which is not exposed) + Assert.AreEqual(DEFAULT_CACHE_SIZE, velocityEngine.GetProperty(RuntimeConstants.RESOURCE_MANAGER_DEFAULTCACHE_SIZE), "incorrect default cache size"); + Assert.AreEqual(DEFAULT_CACHE_FLAG, velocityEngine.GetProperty(PropertySpring + VelocityConstants.Separator + PropertyResourceLoaderCachce), + "incorrect caching flag"); + + AssertMergedValue(velocityEngine, "SimpleTemplate.vm"); + AssertMergedValue(velocityEngine, "EmbeddedTemplate.vm"); + } + + /// + /// Test using an external configuration properties definition + /// + [Test] + public void TestGlobalConfig() + { + VelocityEngine velocityEngine = appContext.GetObject("cnVelocityEngineConfig") as VelocityEngine; + Assert.IsNotNull(velocityEngine, "velocity engine is null"); + + string classProp = TemplateNamespaceParser.getResourceLoaderProperty(VelocityConstants.Assembly, VelocityConstants.Class); + string descProp = TemplateNamespaceParser.getResourceLoaderProperty(VelocityConstants.Assembly, VelocityConstants.Description); + + Assert.AreEqual(VelocityConstants.Assembly, getSingleProperty(velocityEngine, RuntimeConstants.RESOURCE_LOADER), "incorrect resource loader"); + Assert.AreEqual("NVelocity.Runtime.Resource.Loader.AssemblyResourceLoader", + getSingleProperty(velocityEngine, classProp), "incorrect resource loader type"); + Assert.AreEqual("TestDescription", getSingleProperty(velocityEngine, descProp), "incorrect description"); + } + + /// + /// Test using local config. + /// + [Test] + public void TestLocalConfig() + { + VelocityEngine velocityEngine = appContext.GetObject("cnVelocityEngineLocalConfig") as VelocityEngine; + Assert.IsNotNull(velocityEngine, "velocity engine is null"); + + Assert.AreEqual(Encoding.UTF8.WebName.ToUpper(), getSingleProperty(velocityEngine, RuntimeConstants.INPUT_ENCODING), "incorrect input encoding value"); + Assert.AreEqual(TEST_VALUE, getSingleProperty(velocityEngine, "myproperty.mysubproperty"), "incorrect custom property value"); + } + + /// + /// Test a custom resource loader definition + /// + [Test] + public void TestCustomResourceLoader() + { + VelocityEngine velocityEngine = appContext.GetObject("cnVelocityEngingCustomResourceLoader") as VelocityEngine; + Assert.IsNotNull(velocityEngine, "velocity engine is null"); + const string PropertyMyResourceLoader = "myResourceLoader"; + string classProp = TemplateNamespaceParser.getResourceLoaderProperty(PropertyMyResourceLoader, VelocityConstants.Class); + string descProp = TemplateNamespaceParser.getResourceLoaderProperty(PropertyMyResourceLoader, VelocityConstants.Description); + + Assert.AreEqual(PropertyMyResourceLoader, getSingleProperty(velocityEngine, RuntimeConstants.RESOURCE_LOADER), "incorrect resource loader"); + + Assert.AreEqual("Spring.Template.Velocity.Config.TestCustomResourceLoader; Spring.Template.Velocity.Castle.Tests", + getSingleProperty(velocityEngine, classProp), "incorrect resource loader type"); + Assert.AreEqual(PropertyMyResourceLoader, getSingleProperty(velocityEngine, RuntimeConstants.RESOURCE_LOADER), "incorrect resource loader"); + Assert.AreEqual("A custom resource loader", + getSingleProperty(velocityEngine, descProp), "incorrect resource loader description"); + Assert.AreEqual("Template/Velocity/", getSingleProperty(velocityEngine, + TemplateNamespaceParser.getResourceLoaderProperty(PropertyMyResourceLoader, VelocityConstants.Path)), "incorrect resource loader path"); + + AssertMergedValue(velocityEngine, "Template/Velocity/SimpleTemplate.vm"); + } + + #region internal test methods + + /// + /// Grab a single property from (if it's an array return the first value) from the velocityEngine + /// + private string getSingleProperty(VelocityEngine velocityEngine, string prop) + { + object property = velocityEngine.GetProperty(prop); + if (property is ArrayList) + { + ArrayList list = (ArrayList) property; + return (string) list[0]; + } + + return (string) property; + } + #endregion } + +#region test classes + +/// +/// Test class for a custom resource loader class +/// +internal sealed class TestCustomResourceLoader : ResourceLoader +{ + public override void Init(ExtendedProperties configuration) + { + } + + public override Stream GetResourceStream(string source) + { + return new ConfigurableResourceLoader().GetResource(source).InputStream; + } + + public override bool IsSourceModified(Resource resource) + { + return false; + } + + public override long GetLastModified(Resource resource) + { + return resource.LastModified; + } +} + +#endregion diff --git a/test/Spring/Spring.Template.Velocity.Castle.Tests/Template/Velocity/VelocityEngineFactoryObjectTests.xml b/test/Spring/Spring.Template.Velocity.Castle.Tests/Template/Velocity/VelocityEngineFactoryObjectTests.xml index d961fc76..155208c1 100644 --- a/test/Spring/Spring.Template.Velocity.Castle.Tests/Template/Velocity/VelocityEngineFactoryObjectTests.xml +++ b/test/Spring/Spring.Template.Velocity.Castle.Tests/Template/Velocity/VelocityEngineFactoryObjectTests.xml @@ -1,14 +1,14 @@  - + - + @@ -16,17 +16,18 @@ - - + + - + - + - - + + @@ -35,26 +36,30 @@ + path="Template/Velocity/" /> - + - - - + + + - + - + - - + + - + - + diff --git a/test/Spring/Spring.Template.Velocity.Tests/Template/Velocity/Config/TemplateNamespaceParserTests.cs b/test/Spring/Spring.Template.Velocity.Tests/Template/Velocity/Config/TemplateNamespaceParserTests.cs index cdf91f67..2d46b63a 100644 --- a/test/Spring/Spring.Template.Velocity.Tests/Template/Velocity/Config/TemplateNamespaceParserTests.cs +++ b/test/Spring/Spring.Template.Velocity.Tests/Template/Velocity/Config/TemplateNamespaceParserTests.cs @@ -32,172 +32,196 @@ using Spring.Core.IO; #endregion -namespace Spring.Template.Velocity.Config { +namespace Spring.Template.Velocity.Config; + +/// +/// This class contains tests for the template namespace configuration parser +/// +/// Erez Mazor +[TestFixture] +public class TemplateNamespaceParserTests : VelocityEngineTestBase +{ + #region convinience properties aliases + + private const string PropertyModificationCheck = + TemplateDefinitionConstants.PropertyResourceLoaderModificationCheckInterval; + + private const string PropertyResourceLoaderCachce = + TemplateDefinitionConstants.PropertyResourceLoaderCaching; + + #endregion + + #region test constants + + private const int DEFAULT_CACHE_SIZE = 200; + private const int DEFAULT_MOD_CHECK = 30; + private const bool DEFAULT_CACHE_FLAG = true; + + #endregion + /// - /// This class contains tests for the template namespace configuration parser + /// Test a full file-base configuration /// - /// Erez Mazor - [TestFixture] - public class TemplateNamespaceParserTests : VelocityEngineTestBase { - #region convinience properties aliases - private const string PropertyModificationCheck = - TemplateDefinitionConstants.PropertyResourceLoaderModificationCheckInterval; - private const string PropertyResourceLoaderCachce = - TemplateDefinitionConstants.PropertyResourceLoaderCaching; - #endregion + [Test] + public void TestFileBasedConfig() + { + VelocityEngine velocityEngine = appContext.GetObject("cnFileVelocityEngine") as VelocityEngine; + Assert.IsNotNull(velocityEngine, "velocity engine is null"); + Assert.AreEqual(VelocityConstants.File, getSingleProperty(velocityEngine, RuntimeConstants.RESOURCE_LOADER), "incorrect resource loader"); + Assert.AreEqual(TemplateDefinitionConstants.FileResourceLoaderClass, getSingleProperty(velocityEngine, + TemplateNamespaceParser.getResourceLoaderProperty(VelocityConstants.File, VelocityConstants.Class)), "incorrect resource loader type"); + Assert.AreEqual(new string[] { "Template/Velocity/", "Template/" }, velocityEngine.GetProperty( + TemplateNamespaceParser.getResourceLoaderProperty(VelocityConstants.File, VelocityConstants.Path)), "incorrect resource loader path"); + Assert.AreEqual(DEFAULT_CACHE_SIZE, velocityEngine.GetProperty(RuntimeConstants.RESOURCE_MANAGER_DEFAULTCACHE_SIZE), "incorrect default cache size"); + Assert.AreEqual(DEFAULT_MOD_CHECK, velocityEngine.GetProperty( + VelocityConstants.File + VelocityConstants.Separator + PropertyModificationCheck), "incorrect mod check interval"); + Assert.AreEqual(DEFAULT_CACHE_FLAG, velocityEngine.GetProperty(VelocityConstants.File + VelocityConstants.Separator + PropertyResourceLoaderCachce), + "incorrect caching flag"); - #region test constants - private const int DEFAULT_CACHE_SIZE = 200; - private const int DEFAULT_MOD_CHECK = 30; - private const bool DEFAULT_CACHE_FLAG = true; - #endregion - - /// - /// Test a full file-base configuration - /// - [Test] - public void TestFileBasedConfig() { - VelocityEngine velocityEngine = appContext.GetObject("cnFileVelocityEngine") as VelocityEngine; - Assert.IsNotNull(velocityEngine, "velocity engine is null"); - Assert.AreEqual(VelocityConstants.File, getSingleProperty(velocityEngine, RuntimeConstants.RESOURCE_LOADER), "incorrect resource loader"); - Assert.AreEqual(TemplateDefinitionConstants.FileResourceLoaderClass, getSingleProperty(velocityEngine, - TemplateNamespaceParser.getResourceLoaderProperty(VelocityConstants.File, VelocityConstants.Class)), "incorrect resource loader type"); - Assert.AreEqual(new string[]{"Template/Velocity/", "Template/"}, velocityEngine.GetProperty( - TemplateNamespaceParser.getResourceLoaderProperty(VelocityConstants.File, VelocityConstants.Path)), "incorrect resource loader path"); - Assert.AreEqual(DEFAULT_CACHE_SIZE, velocityEngine.GetProperty(RuntimeConstants.RESOURCE_MANAGER_DEFAULTCACHE_SIZE), "incorrect default cache size"); - Assert.AreEqual(DEFAULT_MOD_CHECK, velocityEngine.GetProperty( - VelocityConstants.File + VelocityConstants.Separator + PropertyModificationCheck), "incorrect mod check interval"); - Assert.AreEqual(DEFAULT_CACHE_FLAG, velocityEngine.GetProperty(VelocityConstants.File + VelocityConstants.Separator + PropertyResourceLoaderCachce), - "incorrect caching flag"); - - AssertMergedValue(velocityEngine, "SimpleTemplate.vm"); - } - - /// - /// Test a full aaembly-based configuration - /// - [Test] - public void TestAssemblyBasedConfig() { - VelocityEngine velocityEngine = appContext.GetObject("cnAssemblyVelocityEngine") as VelocityEngine; - Assert.IsNotNull(velocityEngine, "velocity engine is null"); - Assert.AreEqual(VelocityConstants.Assembly, getSingleProperty(velocityEngine, RuntimeConstants.RESOURCE_LOADER), "incorrect resource loader"); - Assert.AreEqual(TemplateDefinitionConstants.AssemblyResourceLoaderClass, getSingleProperty(velocityEngine, - TemplateNamespaceParser.getResourceLoaderProperty(VelocityConstants.Assembly, VelocityConstants.Class)), "incorrect resource loader type"); - Assert.AreEqual("Spring.Template.Velocity.Tests", getSingleProperty(velocityEngine, - TemplateNamespaceParser.getResourceLoaderProperty(VelocityConstants.Assembly,VelocityConstants.Assembly)), "incorrect resource loader path"); - Assert.AreEqual(DEFAULT_CACHE_SIZE, velocityEngine.GetProperty(RuntimeConstants.RESOURCE_MANAGER_DEFAULTCACHE_SIZE), "incorrect default cache size"); - Assert.AreEqual(DEFAULT_CACHE_FLAG, velocityEngine.GetProperty(VelocityConstants.Assembly + VelocityConstants.Separator + PropertyResourceLoaderCachce), - "incorrect caching flag"); - AssertMergedValue(velocityEngine, "Spring.Template.Velocity.SimpleTemplate.vm"); - } - - /// - /// Test a full aaembly-based configuration - /// - [Test] - public void TestSpringBasedConfig() { - VelocityEngine velocityEngine = appContext.GetObject("cnSpringVelocityEngine") as VelocityEngine; - Assert.IsNotNull(velocityEngine, "velocity engine is null"); - const string PropertySpring = TemplateDefinitionConstants.Spring; - Assert.AreEqual(PropertySpring, getSingleProperty(velocityEngine, RuntimeConstants.RESOURCE_LOADER), "incorrect resource loader"); - Assert.AreEqual(TemplateDefinitionConstants.SpringResourceLoaderClass, getSingleProperty(velocityEngine, - TemplateNamespaceParser.getResourceLoaderProperty(PropertySpring, VelocityConstants.Class)), "incorrect resource loader type"); - // no way to test the path property other than trying to actually perform a merge (it is set in velocity engine as an application attribute which is not exposed) - Assert.AreEqual(DEFAULT_CACHE_SIZE, velocityEngine.GetProperty(RuntimeConstants.RESOURCE_MANAGER_DEFAULTCACHE_SIZE), "incorrect default cache size"); - Assert.AreEqual(DEFAULT_CACHE_FLAG, velocityEngine.GetProperty(PropertySpring + VelocityConstants.Separator + PropertyResourceLoaderCachce), - "incorrect caching flag"); - - AssertMergedValue(velocityEngine, "SimpleTemplate.vm"); - AssertMergedValue(velocityEngine, "EmbeddedTemplate.vm"); - } - - /// - /// Test using an external configuration properties definition - /// - [Test] - public void TestGlobalConfig() { - VelocityEngine velocityEngine = appContext.GetObject("cnVelocityEngineConfig") as VelocityEngine; - Assert.IsNotNull(velocityEngine, "velocity engine is null"); - - string classProp = TemplateNamespaceParser.getResourceLoaderProperty(VelocityConstants.Assembly, VelocityConstants.Class); - string descProp = TemplateNamespaceParser.getResourceLoaderProperty(VelocityConstants.Assembly, VelocityConstants.Description); - - Assert.AreEqual(VelocityConstants.Assembly, getSingleProperty(velocityEngine, RuntimeConstants.RESOURCE_LOADER), "incorrect resource loader"); - Assert.AreEqual("NVelocity.Runtime.Resource.Loader.AssemblyResourceLoader", - getSingleProperty(velocityEngine,classProp), "incorrect resource loader type"); - Assert.AreEqual("TestDescription", getSingleProperty(velocityEngine, descProp), "incorrect description"); - } - - /// - /// Test using local config. - /// - [Test] - public void TestLocalConfig() { - VelocityEngine velocityEngine = appContext.GetObject("cnVelocityEngineLocalConfig") as VelocityEngine; - Assert.IsNotNull(velocityEngine, "velocity engine is null"); - - Assert.AreEqual(Encoding.UTF8.WebName.ToUpper(), getSingleProperty(velocityEngine, RuntimeConstants.INPUT_ENCODING), "incorrect input encoding value"); - Assert.AreEqual(TEST_VALUE, getSingleProperty(velocityEngine, "myproperty.mysubproperty"), "incorrect custom property value"); - } - - /// - /// Test a custom resource loader definition - /// - [Test] - public void TestCustomResourceLoader() { - VelocityEngine velocityEngine = appContext.GetObject("cnVelocityEngingCustomResourceLoader") as VelocityEngine; - Assert.IsNotNull(velocityEngine, "velocity engine is null"); - const string PropertyMyResourceLoader = "myResourceLoader"; - string classProp = TemplateNamespaceParser.getResourceLoaderProperty(PropertyMyResourceLoader, VelocityConstants.Class); - string descProp = TemplateNamespaceParser.getResourceLoaderProperty(PropertyMyResourceLoader, VelocityConstants.Description); - - Assert.AreEqual(PropertyMyResourceLoader, getSingleProperty(velocityEngine, RuntimeConstants.RESOURCE_LOADER), "incorrect resource loader"); - - Assert.AreEqual("Spring.Template.Velocity.Config.TestCustomResourceLoader; Spring.Template.Velocity.Tests", - getSingleProperty(velocityEngine, classProp), "incorrect resource loader type"); - Assert.AreEqual(PropertyMyResourceLoader, getSingleProperty(velocityEngine, RuntimeConstants.RESOURCE_LOADER), "incorrect resource loader"); - Assert.AreEqual("A custom resource loader", - getSingleProperty(velocityEngine, descProp), "incorrect resource loader description"); - Assert.AreEqual("Template/Velocity/", getSingleProperty(velocityEngine, - TemplateNamespaceParser.getResourceLoaderProperty(PropertyMyResourceLoader, VelocityConstants.Path)), "incorrect resource loader path"); - - AssertMergedValue(velocityEngine, "Template/Velocity/SimpleTemplate.vm"); - } - - #region internal test methods - /// - /// Grab a single property from (if it's an array return the first value) from the velocityEngine - /// - private string getSingleProperty(VelocityEngine velocityEngine, string prop) { - object property = velocityEngine.GetProperty(prop); - if (property is ArrayList) { - ArrayList list = (ArrayList)property; - return (string)list[0]; - } - return (string)property; - } - #endregion + AssertMergedValue(velocityEngine, "SimpleTemplate.vm"); } - #region test classes /// - /// Test class for a custom resource loader class + /// Test a full aaembly-based configuration /// - internal sealed class TestCustomResourceLoader : ResourceLoader { - public override void Init(ExtendedProperties configuration) { - } - - public override Stream GetResourceStream(string source) { - return new ConfigurableResourceLoader().GetResource(source).InputStream; - } - - public override bool IsSourceModified(Resource resource) { - return false; - } - - public override long GetLastModified(Resource resource) { - return resource.LastModified; - } + [Test] + public void TestAssemblyBasedConfig() + { + VelocityEngine velocityEngine = appContext.GetObject("cnAssemblyVelocityEngine") as VelocityEngine; + Assert.IsNotNull(velocityEngine, "velocity engine is null"); + Assert.AreEqual(VelocityConstants.Assembly, getSingleProperty(velocityEngine, RuntimeConstants.RESOURCE_LOADER), "incorrect resource loader"); + Assert.AreEqual(TemplateDefinitionConstants.AssemblyResourceLoaderClass, getSingleProperty(velocityEngine, + TemplateNamespaceParser.getResourceLoaderProperty(VelocityConstants.Assembly, VelocityConstants.Class)), "incorrect resource loader type"); + Assert.AreEqual("Spring.Template.Velocity.Tests", getSingleProperty(velocityEngine, + TemplateNamespaceParser.getResourceLoaderProperty(VelocityConstants.Assembly, VelocityConstants.Assembly)), "incorrect resource loader path"); + Assert.AreEqual(DEFAULT_CACHE_SIZE, velocityEngine.GetProperty(RuntimeConstants.RESOURCE_MANAGER_DEFAULTCACHE_SIZE), "incorrect default cache size"); + Assert.AreEqual(DEFAULT_CACHE_FLAG, velocityEngine.GetProperty(VelocityConstants.Assembly + VelocityConstants.Separator + PropertyResourceLoaderCachce), + "incorrect caching flag"); + AssertMergedValue(velocityEngine, "Spring.Template.Velocity.SimpleTemplate.vm"); } + + /// + /// Test a full aaembly-based configuration + /// + [Test] + public void TestSpringBasedConfig() + { + VelocityEngine velocityEngine = appContext.GetObject("cnSpringVelocityEngine") as VelocityEngine; + Assert.IsNotNull(velocityEngine, "velocity engine is null"); + const string PropertySpring = TemplateDefinitionConstants.Spring; + Assert.AreEqual(PropertySpring, getSingleProperty(velocityEngine, RuntimeConstants.RESOURCE_LOADER), "incorrect resource loader"); + Assert.AreEqual(TemplateDefinitionConstants.SpringResourceLoaderClass, getSingleProperty(velocityEngine, + TemplateNamespaceParser.getResourceLoaderProperty(PropertySpring, VelocityConstants.Class)), "incorrect resource loader type"); + // no way to test the path property other than trying to actually perform a merge (it is set in velocity engine as an application attribute which is not exposed) + Assert.AreEqual(DEFAULT_CACHE_SIZE, velocityEngine.GetProperty(RuntimeConstants.RESOURCE_MANAGER_DEFAULTCACHE_SIZE), "incorrect default cache size"); + Assert.AreEqual(DEFAULT_CACHE_FLAG, velocityEngine.GetProperty(PropertySpring + VelocityConstants.Separator + PropertyResourceLoaderCachce), + "incorrect caching flag"); + + AssertMergedValue(velocityEngine, "SimpleTemplate.vm"); + AssertMergedValue(velocityEngine, "EmbeddedTemplate.vm"); + } + + /// + /// Test using an external configuration properties definition + /// + [Test] + public void TestGlobalConfig() + { + VelocityEngine velocityEngine = appContext.GetObject("cnVelocityEngineConfig") as VelocityEngine; + Assert.IsNotNull(velocityEngine, "velocity engine is null"); + + string classProp = TemplateNamespaceParser.getResourceLoaderProperty(VelocityConstants.Assembly, VelocityConstants.Class); + string descProp = TemplateNamespaceParser.getResourceLoaderProperty(VelocityConstants.Assembly, VelocityConstants.Description); + + Assert.AreEqual(VelocityConstants.Assembly, getSingleProperty(velocityEngine, RuntimeConstants.RESOURCE_LOADER), "incorrect resource loader"); + Assert.AreEqual("NVelocity.Runtime.Resource.Loader.AssemblyResourceLoader", + getSingleProperty(velocityEngine, classProp), "incorrect resource loader type"); + Assert.AreEqual("TestDescription", getSingleProperty(velocityEngine, descProp), "incorrect description"); + } + + /// + /// Test using local config. + /// + [Test] + public void TestLocalConfig() + { + VelocityEngine velocityEngine = appContext.GetObject("cnVelocityEngineLocalConfig") as VelocityEngine; + Assert.IsNotNull(velocityEngine, "velocity engine is null"); + + Assert.AreEqual(Encoding.UTF8.WebName.ToUpper(), getSingleProperty(velocityEngine, RuntimeConstants.INPUT_ENCODING), "incorrect input encoding value"); + Assert.AreEqual(TEST_VALUE, getSingleProperty(velocityEngine, "myproperty.mysubproperty"), "incorrect custom property value"); + } + + /// + /// Test a custom resource loader definition + /// + [Test] + public void TestCustomResourceLoader() + { + VelocityEngine velocityEngine = appContext.GetObject("cnVelocityEngingCustomResourceLoader") as VelocityEngine; + Assert.IsNotNull(velocityEngine, "velocity engine is null"); + const string PropertyMyResourceLoader = "myResourceLoader"; + string classProp = TemplateNamespaceParser.getResourceLoaderProperty(PropertyMyResourceLoader, VelocityConstants.Class); + string descProp = TemplateNamespaceParser.getResourceLoaderProperty(PropertyMyResourceLoader, VelocityConstants.Description); + + Assert.AreEqual(PropertyMyResourceLoader, getSingleProperty(velocityEngine, RuntimeConstants.RESOURCE_LOADER), "incorrect resource loader"); + + Assert.AreEqual("Spring.Template.Velocity.Config.TestCustomResourceLoader; Spring.Template.Velocity.Tests", + getSingleProperty(velocityEngine, classProp), "incorrect resource loader type"); + Assert.AreEqual(PropertyMyResourceLoader, getSingleProperty(velocityEngine, RuntimeConstants.RESOURCE_LOADER), "incorrect resource loader"); + Assert.AreEqual("A custom resource loader", + getSingleProperty(velocityEngine, descProp), "incorrect resource loader description"); + Assert.AreEqual("Template/Velocity/", getSingleProperty(velocityEngine, + TemplateNamespaceParser.getResourceLoaderProperty(PropertyMyResourceLoader, VelocityConstants.Path)), "incorrect resource loader path"); + + AssertMergedValue(velocityEngine, "Template/Velocity/SimpleTemplate.vm"); + } + + #region internal test methods + + /// + /// Grab a single property from (if it's an array return the first value) from the velocityEngine + /// + private string getSingleProperty(VelocityEngine velocityEngine, string prop) + { + object property = velocityEngine.GetProperty(prop); + if (property is ArrayList) + { + ArrayList list = (ArrayList) property; + return (string) list[0]; + } + + return (string) property; + } + #endregion } + +#region test classes + +/// +/// Test class for a custom resource loader class +/// +internal sealed class TestCustomResourceLoader : ResourceLoader +{ + public override void Init(ExtendedProperties configuration) + { + } + + public override Stream GetResourceStream(string source) + { + return new ConfigurableResourceLoader().GetResource(source).InputStream; + } + + public override bool IsSourceModified(Resource resource) + { + return false; + } + + public override long GetLastModified(Resource resource) + { + return resource.LastModified; + } +} + +#endregion \ No newline at end of file diff --git a/test/Spring/Spring.Template.Velocity.Tests/Template/Velocity/VelocityEngineFactoryObjectTests.cs b/test/Spring/Spring.Template.Velocity.Tests/Template/Velocity/VelocityEngineFactoryObjectTests.cs index 99e64eb5..45100408 100644 --- a/test/Spring/Spring.Template.Velocity.Tests/Template/Velocity/VelocityEngineFactoryObjectTests.cs +++ b/test/Spring/Spring.Template.Velocity.Tests/Template/Velocity/VelocityEngineFactoryObjectTests.cs @@ -27,153 +27,171 @@ using NVelocity.Exception; #endregion -namespace Spring.Template.Velocity { +namespace Spring.Template.Velocity; + +/// +/// This class contains tests for VelocityEngineFactoryObject +/// +/// Mark Pollack +/// Erez Mazor +[TestFixture] +public class VelocityEngineFactoryObjectTests : VelocityEngineTestBase +{ + /// + /// Test the assemblyBasedVelocityEngine bean configuration from VelocityEngineFactoryObjectTests.xml + /// + [Test] + public void TestMergeUsingAssembly() + { + VelocityEngine velocityEngine = appContext.GetObject("assemblyBasedVelocityEngine") as VelocityEngine; + Assert.IsNotNull(velocityEngine, "velocityEngine is null"); + AssertMergedValue(velocityEngine, "Spring.Template.Velocity.SimpleTemplate.vm"); + } /// - /// This class contains tests for VelocityEngineFactoryObject + /// Test the fileBasedVelocityEngine bean configuration from VelocityEngineFactoryObjectTests.xml /// - /// Mark Pollack - /// Erez Mazor - [TestFixture] - public class VelocityEngineFactoryObjectTests : VelocityEngineTestBase { - /// - /// Test the assemblyBasedVelocityEngine bean configuration from VelocityEngineFactoryObjectTests.xml - /// - [Test] - public void TestMergeUsingAssembly() { - VelocityEngine velocityEngine = appContext.GetObject("assemblyBasedVelocityEngine") as VelocityEngine; - Assert.IsNotNull(velocityEngine, "velocityEngine is null"); - AssertMergedValue(velocityEngine, "Spring.Template.Velocity.SimpleTemplate.vm"); - } + [Test] + public void TestMergeUsingFile() + { + VelocityEngine velocityEngine = appContext.GetObject("fileBasedVelocityEngine") as VelocityEngine; + Assert.IsNotNull(velocityEngine, "velocityEngine is null"); + AssertMergedValue(velocityEngine, "Template/Velocity/SimpleTemplate.vm"); - /// - /// Test the fileBasedVelocityEngine bean configuration from VelocityEngineFactoryObjectTests.xml - /// - [Test] - public void TestMergeUsingFile() { - VelocityEngine velocityEngine = appContext.GetObject("fileBasedVelocityEngine") as VelocityEngine; - Assert.IsNotNull(velocityEngine, "velocityEngine is null"); - AssertMergedValue(velocityEngine, "Template/Velocity/SimpleTemplate.vm"); + try + { + VelocityEngineUtils.MergeTemplateIntoString(velocityEngine, "NoneExistingFile", Encoding.UTF8.WebName, model); + throw new TestException( + "Merge using non existing file should throw exception"); + } + catch (Exception ex) + { + Assert.IsTrue(ex is VelocityException, "Illegal merge should throw VelocityException"); + } + } - try { - VelocityEngineUtils.MergeTemplateIntoString(velocityEngine, "NoneExistingFile", Encoding.UTF8.WebName, model); - throw new TestException( - "Merge using non existing file should throw exception"); - } catch (Exception ex) { - Assert.IsTrue(ex is VelocityException, "Illegal merge should throw VelocityException"); - } + /// + /// Test the fileBasedVelocityEngine bean configuration from VelocityEngineFactoryObjectTests.xml + /// + [Test] + public void TestMergeUsingCustomNamespaceDefinition() + { + VelocityEngine velocityEngine = + appContext.GetObject("cnFileVelocityEngine") as VelocityEngine; + Assert.IsNotNull(velocityEngine, "velocityEngine is null"); + AssertMergedValue(velocityEngine, "SimpleTemplate.vm"); + } + + /// + /// Test using definition of ResourceLoaderPath (file-based configuration) referencing just the template name + /// + [Test] + public void TestMergeUsingResourceLoaderPath() + { + VelocityEngine velocityEngine = + appContext.GetObject("pathBasedVelocityEngine") as VelocityEngine; + Assert.IsNotNull(velocityEngine, "velocityEngine is null"); + AssertMergedValue(velocityEngine, "SimpleTemplate.vm"); + } + + /// + /// Test using definition of ResourceLoaderPath (file-based configuration) falling back from velocity + /// file-base to spring-based (prefer-file-system-access one but resource path is string compliant) + /// + [Test] + public void TestMergeUsingResourceLoaderPathFallback() + { + VelocityEngine velocityEngine = + appContext.GetObject("springFallbackVelocityEngine") as VelocityEngine; + Assert.IsNotNull(velocityEngine, "velocityEngine is null"); + AssertMergedValue(velocityEngine, "SimpleTemplate.vm"); + } + + /// + /// Test using a custom properties file (assembly-based configuration) + /// + [Test] + public void TestMergeUsingConfigPropertiesFile() + { + VelocityEngine velocityEngine = + appContext.GetObject("propertiesFileBasedVelocityEngine") as VelocityEngine; + Assert.IsNotNull(velocityEngine, "velocityEngine is null"); + AssertMergedValue(velocityEngine, "Spring.Template.Velocity.SimpleTemplate.vm"); + } + + /// + /// Test using spring resource loader + /// + [Test] + public void TestMergeUsingSpringResourceLoader() + { + VelocityEngine velocityEngine = + appContext.GetObject("springResourceLoaderBasedVelocityEngine") as VelocityEngine; + Assert.IsNotNull(velocityEngine, "velocityEngine is null"); + AssertMergedValue(velocityEngine, "SimpleTemplate.vm"); + } + + /// + /// Test using invalid configuration + /// + [Test] + public void TestInvalidConfiguration() + { + VelocityEngineFactory velocityEngineFactory = new VelocityEngineFactory(); + velocityEngineFactory.PreferFileSystemAccess = false; + VelocityEngine velocityEngine = null; + try + { + velocityEngineFactory.CreateVelocityEngine(); + throw new TestException( + "Should not be able to construct VelocityEngineFactory with SpringResourceLoader and no path"); + } + catch (ArgumentException) + { + Assert.IsNull(velocityEngine, "velocityEngine should be null"); } - /// - /// Test the fileBasedVelocityEngine bean configuration from VelocityEngineFactoryObjectTests.xml - /// - [Test] - public void TestMergeUsingCustomNamespaceDefinition() { - VelocityEngine velocityEngine = - appContext.GetObject("cnFileVelocityEngine") as VelocityEngine; - Assert.IsNotNull(velocityEngine, "velocityEngine is null"); - AssertMergedValue(velocityEngine, "SimpleTemplate.vm"); + // no resource loader with spring + velocityEngineFactory = new VelocityEngineFactory(); + velocityEngineFactory.ResourceLoader = null; + velocityEngineFactory.PreferFileSystemAccess = false; + try + { + velocityEngineFactory.CreateVelocityEngine(); + throw new TestException( + "Should not be able to construct VelocityEngineFactory with null ResourceLoader"); + } + catch (ArgumentException) + { + Assert.IsNull(velocityEngine, "velocityEngine should be null"); } - /// - /// Test using definition of ResourceLoaderPath (file-based configuration) referencing just the template name - /// - [Test] - public void TestMergeUsingResourceLoaderPath() { - VelocityEngine velocityEngine = - appContext.GetObject("pathBasedVelocityEngine") as VelocityEngine; - Assert.IsNotNull(velocityEngine, "velocityEngine is null"); - AssertMergedValue(velocityEngine, "SimpleTemplate.vm"); - } - - /// - /// Test using definition of ResourceLoaderPath (file-based configuration) falling back from velocity - /// file-base to spring-based (prefer-file-system-access one but resource path is string compliant) - /// - [Test] - public void TestMergeUsingResourceLoaderPathFallback() { - VelocityEngine velocityEngine = - appContext.GetObject("springFallbackVelocityEngine") as VelocityEngine; - Assert.IsNotNull(velocityEngine, "velocityEngine is null"); - AssertMergedValue(velocityEngine, "SimpleTemplate.vm"); + // no resource loader path with spring + velocityEngineFactory = new VelocityEngineFactory(); + velocityEngineFactory.ResourceLoaderPaths = new List(); + velocityEngineFactory.PreferFileSystemAccess = false; + try + { + velocityEngineFactory.CreateVelocityEngine(); + throw new TestException( + "Should not be able to construct VelocityEngineFactory with empty resource loader path list"); } - - /// - /// Test using a custom properties file (assembly-based configuration) - /// - [Test] - public void TestMergeUsingConfigPropertiesFile() { - VelocityEngine velocityEngine = - appContext.GetObject("propertiesFileBasedVelocityEngine") as VelocityEngine; - Assert.IsNotNull(velocityEngine, "velocityEngine is null"); - AssertMergedValue(velocityEngine, "Spring.Template.Velocity.SimpleTemplate.vm"); + catch (ArgumentException) + { + Assert.IsNull(velocityEngine, "velocityEngine should be null"); } + } - /// - /// Test using spring resource loader - /// - [Test] - public void TestMergeUsingSpringResourceLoader() { - VelocityEngine velocityEngine = - appContext.GetObject("springResourceLoaderBasedVelocityEngine") as VelocityEngine; - Assert.IsNotNull(velocityEngine, "velocityEngine is null"); - AssertMergedValue(velocityEngine, "SimpleTemplate.vm"); - } - - - /// - /// Test using invalid configuration - /// - [Test] - public void TestInvalidConfiguration() { - VelocityEngineFactory velocityEngineFactory = new VelocityEngineFactory(); - velocityEngineFactory.PreferFileSystemAccess = false; - VelocityEngine velocityEngine = null; - try { - velocityEngineFactory.CreateVelocityEngine(); - throw new TestException( - "Should not be able to construct VelocityEngineFactory with SpringResourceLoader and no path"); - } catch (ArgumentException) { - Assert.IsNull(velocityEngine, "velocityEngine should be null"); - } - - // no resource loader with spring - velocityEngineFactory = new VelocityEngineFactory(); - velocityEngineFactory.ResourceLoader = null; - velocityEngineFactory.PreferFileSystemAccess = false; - try { - velocityEngineFactory.CreateVelocityEngine(); - throw new TestException( - "Should not be able to construct VelocityEngineFactory with null ResourceLoader"); - } catch (ArgumentException) { - Assert.IsNull(velocityEngine, "velocityEngine should be null"); - } - - // no resource loader path with spring - velocityEngineFactory = new VelocityEngineFactory(); - velocityEngineFactory.ResourceLoaderPaths = new List(); - velocityEngineFactory.PreferFileSystemAccess = false; - try { - velocityEngineFactory.CreateVelocityEngine(); - throw new TestException( - "Should not be able to construct VelocityEngineFactory with empty resource loader path list"); - } catch (ArgumentException) { - Assert.IsNull(velocityEngine, "velocityEngine should be null"); - } - } - - /// - /// Test engine's logging capabilities. - /// - [Test] - public void TestLogging(){ - VelocityEngine velocityEngine = new VelocityEngineFactoryObject().CreateVelocityEngine(); - velocityEngine.Info("test"); - velocityEngine.Debug("test"); - velocityEngine.Warn("test"); - velocityEngine.Error("test"); - } - - + /// + /// Test engine's logging capabilities. + /// + [Test] + public void TestLogging() + { + VelocityEngine velocityEngine = new VelocityEngineFactoryObject().CreateVelocityEngine(); + velocityEngine.Info("test"); + velocityEngine.Debug("test"); + velocityEngine.Warn("test"); + velocityEngine.Error("test"); } } diff --git a/test/Spring/Spring.Template.Velocity.Tests/Template/Velocity/VelocityEngineFactoryObjectTests.xml b/test/Spring/Spring.Template.Velocity.Tests/Template/Velocity/VelocityEngineFactoryObjectTests.xml index 28cc9f91..15b04c75 100644 --- a/test/Spring/Spring.Template.Velocity.Tests/Template/Velocity/VelocityEngineFactoryObjectTests.xml +++ b/test/Spring/Spring.Template.Velocity.Tests/Template/Velocity/VelocityEngineFactoryObjectTests.xml @@ -1,14 +1,14 @@  - + - + @@ -16,17 +16,18 @@ - - + + - + - + - - + + @@ -35,26 +36,30 @@ + path="Template/Velocity/" /> - + - - - + + + - + - + - - + + - + - + diff --git a/test/Spring/Spring.Template.Velocity.Tests/Template/Velocity/VelocityEngineTestBase.cs b/test/Spring/Spring.Template.Velocity.Tests/Template/Velocity/VelocityEngineTestBase.cs index b91619c2..dfdd2cfa 100644 --- a/test/Spring/Spring.Template.Velocity.Tests/Template/Velocity/VelocityEngineTestBase.cs +++ b/test/Spring/Spring.Template.Velocity.Tests/Template/Velocity/VelocityEngineTestBase.cs @@ -29,60 +29,69 @@ using Spring.Objects.Factory.Xml; #endregion -namespace Spring.Template.Velocity { +namespace Spring.Template.Velocity; + +/// +/// Base class for Velocity engine tests. +/// +public class VelocityEngineTestBase +{ + /// + /// Shared application context instance. + /// + protected XmlApplicationContext appContext; /// - /// Base class for Velocity engine tests. + /// Model used in templating. /// - public class VelocityEngineTestBase { - - /// - /// Shared application context instance. - /// - protected XmlApplicationContext appContext; - /// - /// Model used in templating. - /// - protected readonly Hashtable model = new Hashtable(); - /// - /// Simple test value. - /// - protected const string TEST_VALUE = "TEST_VALUE"; + protected readonly Hashtable model = new Hashtable(); - #region setup - /// - /// Test setup. - /// - [SetUp] - public void Setup() { - appContext = new XmlApplicationContext(false, - ReadOnlyXmlTestResource.GetFilePath( - "VelocityEngineFactoryObjectTests.xml", - typeof(VelocityEngineFactoryObjectTests))); - model.Add("var1", TEST_VALUE); - } - #endregion + /// + /// Simple test value. + /// + protected const string TEST_VALUE = "TEST_VALUE"; - #region teardown - /// - /// Test cleanup. - /// - [TearDown] - public void TearDown() { - appContext.Dispose(); - model.Clear(); - } - #endregion + #region setup - #region base helper methods - /// - /// Basic method for asserting the expected TEST_VALUE in the merged template - /// - protected void AssertMergedValue(VelocityEngine velocityEngine, string template){ - string mergedTemplate = VelocityEngineUtils.MergeTemplateIntoString(velocityEngine, template, Encoding.UTF8.WebName, model); - Assert.AreEqual(string.Format("value={0}", TEST_VALUE), mergedTemplate); - } - #endregion + /// + /// Test setup. + /// + [SetUp] + public void Setup() + { + appContext = new XmlApplicationContext(false, + ReadOnlyXmlTestResource.GetFilePath( + "VelocityEngineFactoryObjectTests.xml", + typeof(VelocityEngineFactoryObjectTests))); + model.Add("var1", TEST_VALUE); } + #endregion + + #region teardown + + /// + /// Test cleanup. + /// + [TearDown] + public void TearDown() + { + appContext.Dispose(); + model.Clear(); + } + + #endregion + + #region base helper methods + + /// + /// Basic method for asserting the expected TEST_VALUE in the merged template + /// + protected void AssertMergedValue(VelocityEngine velocityEngine, string template) + { + string mergedTemplate = VelocityEngineUtils.MergeTemplateIntoString(velocityEngine, template, Encoding.UTF8.WebName, model); + Assert.AreEqual(string.Format("value={0}", TEST_VALUE), mergedTemplate); + } + + #endregion } diff --git a/test/Spring/Spring.Template.Velocity.Tests/VelocityCompilerOptionsTests.cs b/test/Spring/Spring.Template.Velocity.Tests/VelocityCompilerOptionsTests.cs index 87fd276f..b4f48eb5 100644 --- a/test/Spring/Spring.Template.Velocity.Tests/VelocityCompilerOptionsTests.cs +++ b/test/Spring/Spring.Template.Velocity.Tests/VelocityCompilerOptionsTests.cs @@ -26,21 +26,20 @@ using Spring.Template.Velocity; #endregion -namespace Spring +namespace Spring; + +/// Test that the assembly is built with the correct DebugAttributes in release and debug builds. +/// +/// Mark Pollack +[TestFixture] +public sealed class VelocityCompilerOptionTests : CompilerOptionsTests { - /// Test that the assembly is built with the correct DebugAttributes in release and debug builds. + /// + /// Setup for entiry test fixture. /// - /// Mark Pollack - [TestFixture] - public sealed class VelocityCompilerOptionTests : CompilerOptionsTests + [OneTimeSetUp] + public void FixtureSetUp() { - /// - /// Setup for entiry test fixture. - /// - [OneTimeSetUp] - public void FixtureSetUp() - { - AssemblyToCheck = Assembly.GetAssembly(typeof (VelocityEngineFactory)); - } + AssemblyToCheck = Assembly.GetAssembly(typeof(VelocityEngineFactory)); } -} \ No newline at end of file +} diff --git a/test/Spring/Spring.Testing.Microsoft.Tests/AssemblyInfo.cs b/test/Spring/Spring.Testing.Microsoft.Tests/AssemblyInfo.cs index 500d59f7..fc75e5a1 100644 --- a/test/Spring/Spring.Testing.Microsoft.Tests/AssemblyInfo.cs +++ b/test/Spring/Spring.Testing.Microsoft.Tests/AssemblyInfo.cs @@ -6,4 +6,4 @@ using System.Reflection; // associated with an assembly. // [assembly: AssemblyTitle("Spring.Testing.Microsoft Tests")] -[assembly: AssemblyDescription("Unit tests for Spring.Testing.Microsoft assembly")] \ No newline at end of file +[assembly: AssemblyDescription("Unit tests for Spring.Testing.Microsoft assembly")] diff --git a/test/Spring/Spring.Testing.Microsoft.Tests/Spring.Testing.Microsoft.Tests.csproj b/test/Spring/Spring.Testing.Microsoft.Tests/Spring.Testing.Microsoft.Tests.csproj index 249720ba..8e9d385d 100644 --- a/test/Spring/Spring.Testing.Microsoft.Tests/Spring.Testing.Microsoft.Tests.csproj +++ b/test/Spring/Spring.Testing.Microsoft.Tests/Spring.Testing.Microsoft.Tests.csproj @@ -1,7 +1,7 @@  net8.0;$(TargetFullFrameworkVersion) - + @@ -13,10 +13,10 @@ - + - + \ No newline at end of file diff --git a/test/Spring/Spring.Testing.Microsoft.Tests/Testing/Microsoft/AbstractDependencyInjectionSpringContextTestsTests.cs b/test/Spring/Spring.Testing.Microsoft.Tests/Testing/Microsoft/AbstractDependencyInjectionSpringContextTestsTests.cs index d51edd8b..bcef6433 100644 --- a/test/Spring/Spring.Testing.Microsoft.Tests/Testing/Microsoft/AbstractDependencyInjectionSpringContextTestsTests.cs +++ b/test/Spring/Spring.Testing.Microsoft.Tests/Testing/Microsoft/AbstractDependencyInjectionSpringContextTestsTests.cs @@ -19,124 +19,122 @@ #endregion using Microsoft.VisualStudio.TestTools.UnitTesting; - using Spring.Context; using Spring.Context.Support; using Spring.Objects; using Spring.Transaction; -namespace Spring.Testing.Microsoft +namespace Spring.Testing.Microsoft; + +/// +/// Summary description for AbstractDependencyInjectionSpringContextTestsTests. +/// +[TestClass] +public class AbstractDependencyInjectionSpringContextTestsTests { - /// - /// Summary description for AbstractDependencyInjectionSpringContextTestsTests. - /// - [TestClass] - public class AbstractDependencyInjectionSpringContextTestsTests - { - //Force loading of this assembly since MsTest runner doesn't run in the 'working' directory and find - //dynamically loaded assemblies... (you have *got* to be kidding!!!) - //Investigate use of [DeploymentItem(...)] - private Type t = typeof (CallCountingTransactionManager); - private Type t2 = typeof (TestObject); + //Force loading of this assembly since MsTest runner doesn't run in the 'working' directory and find + //dynamically loaded assemblies... (you have *got* to be kidding!!!) + //Investigate use of [DeploymentItem(...)] + private Type t = typeof(CallCountingTransactionManager); + private Type t2 = typeof(TestObject); - private class TestAbstractDependencyInjectionSpringContextTests : AbstractDependencyInjectionSpringContextTests + private class TestAbstractDependencyInjectionSpringContextTests : AbstractDependencyInjectionSpringContextTests + { + public static readonly string[] CONFIGLOCATIONS = new string[] { "assembly://Spring.Testing.Microsoft.Tests/Spring.Testing.Microsoft/TestApplicationContext.xml" }; + + public TestAbstractDependencyInjectionSpringContextTests() { - public static readonly string[] CONFIGLOCATIONS = new string[] {"assembly://Spring.Testing.Microsoft.Tests/Spring.Testing.Microsoft/TestApplicationContext.xml"}; - - public TestAbstractDependencyInjectionSpringContextTests() - {} - - public TestAbstractDependencyInjectionSpringContextTests(bool registerWithContextRegistry) - { - base.RegisterContextWithContextRegistry = registerWithContextRegistry; - } - - public IConfigurableApplicationContext ApplicationContext - { - get { return base.applicationContext; } - } - - protected override string[] ConfigLocations - { - get { return CONFIGLOCATIONS; } - } - - public new bool HasCachedContext(object key) - { - return base.HasCachedContext(key); - } } - private TestAbstractDependencyInjectionSpringContextTests fixtureInstance ; - - [TestCleanup] - public void TearDown() + public TestAbstractDependencyInjectionSpringContextTests(bool registerWithContextRegistry) { - AbstractSpringContextTests.ClearContextCache(); + base.RegisterContextWithContextRegistry = registerWithContextRegistry; } - [TestMethod] - public void RegistersWithContextRegistryByDefault() - { - fixtureInstance = new TestAbstractDependencyInjectionSpringContextTests(); - Assert.IsTrue(fixtureInstance.RegisterContextWithContextRegistry); - Assert.AreEqual(typeof(CallCountingTransactionManager), t); - Assert.AreEqual(typeof(TestObject), t2); - - } - - [TestMethod] - public void UnregistersFromContextRegistryWhenDirty() - { - fixtureInstance = new TestAbstractDependencyInjectionSpringContextTests(); - Assert.IsTrue(fixtureInstance.RegisterContextWithContextRegistry); - fixtureInstance.TestInitialize(); - Assert.IsTrue( ContextRegistry.IsContextRegistered(fixtureInstance.ApplicationContext.Name) ); - fixtureInstance.TestCleanup(); - Assert.IsTrue(ContextRegistry.IsContextRegistered(fixtureInstance.ApplicationContext.Name)); - fixtureInstance.TestInitialize(); - Assert.IsTrue(ContextRegistry.IsContextRegistered(fixtureInstance.ApplicationContext.Name)); - fixtureInstance.SetDirty(); - fixtureInstance.TestCleanup(); - Assert.IsFalse(ContextRegistry.IsContextRegistered(fixtureInstance.ApplicationContext.Name)); - } - - [TestMethod] - public void DoesNotRegisterContextWithContextRegistry() - { - fixtureInstance = new TestAbstractDependencyInjectionSpringContextTests(); - Assert.IsTrue(fixtureInstance.RegisterContextWithContextRegistry); - fixtureInstance.RegisterContextWithContextRegistry = false; - fixtureInstance.TestInitialize(); - Assert.IsFalse( ContextRegistry.IsContextRegistered(fixtureInstance.ApplicationContext.Name) ); - fixtureInstance.TestCleanup(); - Assert.IsFalse( ContextRegistry.IsContextRegistered(fixtureInstance.ApplicationContext.Name) ); - } - - [TestMethod] - public void CachesApplicationContexts() + public IConfigurableApplicationContext ApplicationContext { - fixtureInstance = new TestAbstractDependencyInjectionSpringContextTests(false); - fixtureInstance.TestInitialize(); - Assert.IsNotNull(fixtureInstance.ApplicationContext); - Assert.AreEqual(1, fixtureInstance.LoadCount); // context has been loaded - Assert.IsTrue(fixtureInstance.HasCachedContext(TestAbstractDependencyInjectionSpringContextTests.CONFIGLOCATIONS)); - fixtureInstance.TestCleanup(); - - TestAbstractDependencyInjectionSpringContextTests otherFixtureInstance = new TestAbstractDependencyInjectionSpringContextTests(false); - otherFixtureInstance.TestInitialize(); - Assert.IsNotNull(otherFixtureInstance.ApplicationContext); - Assert.AreEqual(0, otherFixtureInstance.LoadCount); // context was obtained from cache - Assert.AreSame(fixtureInstance.ApplicationContext, otherFixtureInstance.ApplicationContext); - otherFixtureInstance.SetDirty(); // purge cache and dispose cached instances - Assert.IsFalse(fixtureInstance.HasCachedContext(TestAbstractDependencyInjectionSpringContextTests.CONFIGLOCATIONS)); - otherFixtureInstance.TestCleanup(); - otherFixtureInstance = new TestAbstractDependencyInjectionSpringContextTests(false); - otherFixtureInstance.TestInitialize(); - Assert.IsNotNull(otherFixtureInstance.ApplicationContext); - Assert.AreEqual(1, otherFixtureInstance.LoadCount); // context was reloaded because of SetDirty() above - Assert.AreNotSame(fixtureInstance.ApplicationContext, otherFixtureInstance.ApplicationContext); - otherFixtureInstance.TestCleanup(); + get { return base.applicationContext; } } - } + + protected override string[] ConfigLocations + { + get { return CONFIGLOCATIONS; } + } + + public new bool HasCachedContext(object key) + { + return base.HasCachedContext(key); + } + } + + private TestAbstractDependencyInjectionSpringContextTests fixtureInstance; + + [TestCleanup] + public void TearDown() + { + AbstractSpringContextTests.ClearContextCache(); + } + + [TestMethod] + public void RegistersWithContextRegistryByDefault() + { + fixtureInstance = new TestAbstractDependencyInjectionSpringContextTests(); + Assert.IsTrue(fixtureInstance.RegisterContextWithContextRegistry); + Assert.AreEqual(typeof(CallCountingTransactionManager), t); + Assert.AreEqual(typeof(TestObject), t2); + } + + [TestMethod] + public void UnregistersFromContextRegistryWhenDirty() + { + fixtureInstance = new TestAbstractDependencyInjectionSpringContextTests(); + Assert.IsTrue(fixtureInstance.RegisterContextWithContextRegistry); + fixtureInstance.TestInitialize(); + Assert.IsTrue(ContextRegistry.IsContextRegistered(fixtureInstance.ApplicationContext.Name)); + fixtureInstance.TestCleanup(); + Assert.IsTrue(ContextRegistry.IsContextRegistered(fixtureInstance.ApplicationContext.Name)); + fixtureInstance.TestInitialize(); + Assert.IsTrue(ContextRegistry.IsContextRegistered(fixtureInstance.ApplicationContext.Name)); + fixtureInstance.SetDirty(); + fixtureInstance.TestCleanup(); + Assert.IsFalse(ContextRegistry.IsContextRegistered(fixtureInstance.ApplicationContext.Name)); + } + + [TestMethod] + public void DoesNotRegisterContextWithContextRegistry() + { + fixtureInstance = new TestAbstractDependencyInjectionSpringContextTests(); + Assert.IsTrue(fixtureInstance.RegisterContextWithContextRegistry); + fixtureInstance.RegisterContextWithContextRegistry = false; + fixtureInstance.TestInitialize(); + Assert.IsFalse(ContextRegistry.IsContextRegistered(fixtureInstance.ApplicationContext.Name)); + fixtureInstance.TestCleanup(); + Assert.IsFalse(ContextRegistry.IsContextRegistered(fixtureInstance.ApplicationContext.Name)); + } + + [TestMethod] + public void CachesApplicationContexts() + { + fixtureInstance = new TestAbstractDependencyInjectionSpringContextTests(false); + fixtureInstance.TestInitialize(); + Assert.IsNotNull(fixtureInstance.ApplicationContext); + Assert.AreEqual(1, fixtureInstance.LoadCount); // context has been loaded + Assert.IsTrue(fixtureInstance.HasCachedContext(TestAbstractDependencyInjectionSpringContextTests.CONFIGLOCATIONS)); + fixtureInstance.TestCleanup(); + + TestAbstractDependencyInjectionSpringContextTests otherFixtureInstance = new TestAbstractDependencyInjectionSpringContextTests(false); + otherFixtureInstance.TestInitialize(); + Assert.IsNotNull(otherFixtureInstance.ApplicationContext); + Assert.AreEqual(0, otherFixtureInstance.LoadCount); // context was obtained from cache + Assert.AreSame(fixtureInstance.ApplicationContext, otherFixtureInstance.ApplicationContext); + otherFixtureInstance.SetDirty(); // purge cache and dispose cached instances + Assert.IsFalse(fixtureInstance.HasCachedContext(TestAbstractDependencyInjectionSpringContextTests.CONFIGLOCATIONS)); + otherFixtureInstance.TestCleanup(); + otherFixtureInstance = new TestAbstractDependencyInjectionSpringContextTests(false); + otherFixtureInstance.TestInitialize(); + Assert.IsNotNull(otherFixtureInstance.ApplicationContext); + Assert.AreEqual(1, otherFixtureInstance.LoadCount); // context was reloaded because of SetDirty() above + Assert.AreNotSame(fixtureInstance.ApplicationContext, otherFixtureInstance.ApplicationContext); + otherFixtureInstance.TestCleanup(); + } } diff --git a/test/Spring/Spring.Testing.Microsoft.Tests/Testing/Microsoft/TestApplicationContext.xml b/test/Spring/Spring.Testing.Microsoft.Tests/Testing/Microsoft/TestApplicationContext.xml index a5702f11..cfa52804 100644 --- a/test/Spring/Spring.Testing.Microsoft.Tests/Testing/Microsoft/TestApplicationContext.xml +++ b/test/Spring/Spring.Testing.Microsoft.Tests/Testing/Microsoft/TestApplicationContext.xml @@ -2,18 +2,18 @@ - + - + + + + + + + + - - - - - - - \ No newline at end of file diff --git a/test/Spring/Spring.Testing.Microsoft.Tests/Testing/Microsoft/TestApplicationContext_netcore.xml b/test/Spring/Spring.Testing.Microsoft.Tests/Testing/Microsoft/TestApplicationContext_netcore.xml index 33e20e66..169dca00 100644 --- a/test/Spring/Spring.Testing.Microsoft.Tests/Testing/Microsoft/TestApplicationContext_netcore.xml +++ b/test/Spring/Spring.Testing.Microsoft.Tests/Testing/Microsoft/TestApplicationContext_netcore.xml @@ -2,18 +2,18 @@ - + - + + + + + + + + - - - - - - - \ No newline at end of file diff --git a/test/Spring/Spring.Testing.Microsoft.Tests/app.config b/test/Spring/Spring.Testing.Microsoft.Tests/app.config index c451bbd3..469f16f6 100644 --- a/test/Spring/Spring.Testing.Microsoft.Tests/app.config +++ b/test/Spring/Spring.Testing.Microsoft.Tests/app.config @@ -21,19 +21,19 @@ limitations under the License.
- + -
+
- + - + @@ -41,6 +41,4 @@ limitations under the License. - - diff --git a/test/Spring/Spring.Testing.NUnit.Tests/App.config b/test/Spring/Spring.Testing.NUnit.Tests/App.config index 07a607d5..8e7d2548 100644 --- a/test/Spring/Spring.Testing.NUnit.Tests/App.config +++ b/test/Spring/Spring.Testing.NUnit.Tests/App.config @@ -21,19 +21,19 @@ limitations under the License.
- + -
+
- + - + @@ -41,6 +41,4 @@ limitations under the License. - - diff --git a/test/Spring/Spring.Testing.NUnit.Tests/AssemblyInfo.cs b/test/Spring/Spring.Testing.NUnit.Tests/AssemblyInfo.cs index 3ae95d85..495b05e8 100644 --- a/test/Spring/Spring.Testing.NUnit.Tests/AssemblyInfo.cs +++ b/test/Spring/Spring.Testing.NUnit.Tests/AssemblyInfo.cs @@ -6,4 +6,4 @@ using System.Reflection; // associated with an assembly. // [assembly: AssemblyTitle("Spring.Testing.NUnit Tests")] -[assembly: AssemblyDescription("Unit tests for Spring.Testing.NUnit assembly")] \ No newline at end of file +[assembly: AssemblyDescription("Unit tests for Spring.Testing.NUnit assembly")] diff --git a/test/Spring/Spring.Testing.NUnit.Tests/NUnitCompilerOptionsTests.cs b/test/Spring/Spring.Testing.NUnit.Tests/NUnitCompilerOptionsTests.cs index 5562f206..abee0f03 100644 --- a/test/Spring/Spring.Testing.NUnit.Tests/NUnitCompilerOptionsTests.cs +++ b/test/Spring/Spring.Testing.NUnit.Tests/NUnitCompilerOptionsTests.cs @@ -26,18 +26,17 @@ using Spring.Testing.NUnit; #endregion -namespace Spring +namespace Spring; + +/// Test that the assembly is built with the correct DebugAttributes in release and debug builds. +/// +/// Mark Pollack +[TestFixture] +public sealed class NUnitCompilerOptionTests : CompilerOptionsTests { - /// Test that the assembly is built with the correct DebugAttributes in release and debug builds. - /// - /// Mark Pollack - [TestFixture] - public sealed class NUnitCompilerOptionTests : CompilerOptionsTests + [OneTimeSetUp] + public void FixtureSetUp() { - [OneTimeSetUp] - public void FixtureSetUp() - { - AssemblyToCheck = Assembly.GetAssembly(typeof (AbstractSpringContextTests)); - } + AssemblyToCheck = Assembly.GetAssembly(typeof(AbstractSpringContextTests)); } -} \ No newline at end of file +} diff --git a/test/Spring/Spring.Testing.NUnit.Tests/Testing/Ado/SimpleAdoTestUtilsTests.cs b/test/Spring/Spring.Testing.NUnit.Tests/Testing/Ado/SimpleAdoTestUtilsTests.cs index 8ff11eeb..40f7ffc1 100644 --- a/test/Spring/Spring.Testing.NUnit.Tests/Testing/Ado/SimpleAdoTestUtilsTests.cs +++ b/test/Spring/Spring.Testing.NUnit.Tests/Testing/Ado/SimpleAdoTestUtilsTests.cs @@ -19,134 +19,129 @@ #endregion using System.Data; - using FakeItEasy; - using NUnit.Framework; - using Spring.Core.IO; using Spring.Data; using Spring.Data.Common; using Spring.Data.Core; using Spring.Transaction.Support; -namespace Spring.Testing.Ado +namespace Spring.Testing.Ado; + +/// +/// +/// Erich Eichinger +[TestFixture] +public class SimpleAdoTestUtilsTests { - /// - /// - /// Erich Eichinger - [TestFixture] - public class SimpleAdoTestUtilsTests + private IAdoOperations adoTemplate; + + [SetUp] + public void SetUp() { - private IAdoOperations adoTemplate; - - [SetUp] - public void SetUp() - { - adoTemplate = A.Fake(); - } - - [Test] - public void ExecuteEmptyScript() - { - IResource scriptResource = new StringResource(""); - - SimpleAdoTestUtils.ExecuteSqlScript(adoTemplate, scriptResource, false, SimpleAdoTestUtils.BLOCKDELIM_GO_EXP); - } - - [Test] - public void ExecuteSingleStatement() - { - IResource scriptResource = new StringResource("statement 1"); - - SimpleAdoTestUtils.ExecuteSqlScript(adoTemplate, scriptResource, false, SimpleAdoTestUtils.BLOCKDELIM_GO_EXP); - A.CallTo(() => adoTemplate.ExecuteNonQuery(CommandType.Text, "statement 1")).MustHaveHappened(); - } - - [Test] - public void ExecuteScriptWithMissingSeparatorOnLastBlock() - { - IResource scriptResource = new StringResource("\tstatement 1 \n\n\t GO\t \n statement 2"); - - SimpleAdoTestUtils.ExecuteSqlScript(adoTemplate, scriptResource, false, SimpleAdoTestUtils.BLOCKDELIM_GO_EXP); - - A.CallTo(() => adoTemplate.ExecuteNonQuery(CommandType.Text, "\tstatement 1 \n")).MustHaveHappened(); - A.CallTo(() => adoTemplate.ExecuteNonQuery(CommandType.Text, "\n statement 2")). MustHaveHappened(); - - } - - [Test] - public void ExecuteScriptWithGOBlocks() - { - IResource scriptResource = new StringResource("\tstatement 1 \n\n\t GO\t \n statement 2\nGO"); - - A.CallTo(() => adoTemplate.ExecuteNonQuery(CommandType.Text, "\tstatement 1 \n")).Returns(0); - A.CallTo(() => adoTemplate.ExecuteNonQuery(CommandType.Text, "\n statement 2\n")).Returns(0); - - SimpleAdoTestUtils.ExecuteSqlScript(adoTemplate, scriptResource, false, SimpleAdoTestUtils.BLOCKDELIM_GO_EXP); - } - - [Test] - public void ExecuteScriptWithSemicolonSeparatedStatements() - { - IResource scriptResource = new StringResource("\tstatement 1 ;\nGO\n statement 2;"); - - A.CallTo(() => adoTemplate.ExecuteNonQuery(CommandType.Text, "\tstatement 1 ")).Returns(0); - A.CallTo(() => adoTemplate.ExecuteNonQuery(CommandType.Text, "\nGO\n statement 2")).Returns(0); - - SimpleAdoTestUtils.ExecuteSqlScript(adoTemplate, scriptResource, false, SimpleAdoTestUtils.BLOCKDELIM_SEMICOLON_EXP); - } - - [Test] - public void ExecuteScriptTransactedSuccess() - { - IDbProvider dbProvider = A.Fake(); - IDbConnection dbConnection = A.Fake(); - IDbTransaction dbTx = A.Fake(); - IDbCommand dbCommand = A.Fake(); - DefaultTransactionDefinition txDefinition = new DefaultTransactionDefinition(); - - A.CallTo(() => dbProvider.CreateConnection()).Returns(dbConnection); - A.CallTo(() => dbConnection.BeginTransaction(txDefinition.TransactionIsolationLevel)).Returns(dbTx); - A.CallTo(() => dbProvider.CreateCommand()).Returns(dbCommand); - A.CallTo(() => dbCommand.ExecuteNonQuery()).Returns(0); - - AdoTemplate adoOps = new AdoTemplate(dbProvider); - IPlatformTransaction tx = SimpleAdoTestUtils.CreateTransaction(dbProvider, txDefinition); - - SimpleAdoTestUtils.ExecuteSqlScript(adoOps, "simple sql cmd"); - tx.Commit(); - tx.Dispose(); - - A.CallTo(() => dbConnection.Open()).MustHaveHappenedOnceExactly(); - A.CallTo(() => dbTx.Commit()).MustHaveHappenedOnceExactly(); - A.CallTo(() => dbCommand.Dispose()).MustHaveHappenedOnceExactly(); - A.CallTo(() => dbConnection.Dispose()).MustHaveHappenedOnceExactly(); - - A.CallToSet(() => dbCommand.Connection).WhenArgumentsMatch(x => x[0] == dbConnection).MustHaveHappenedOnceExactly(); - A.CallToSet(() => dbCommand.Transaction).WhenArgumentsMatch(x => x[0] == dbTx).MustHaveHappenedOnceExactly(); - A.CallToSet(() => dbCommand.CommandText).WhenArgumentsMatch(x => (string) x[0] == "simple sql cmd").MustHaveHappenedOnceExactly(); - A.CallToSet(() => dbCommand.CommandType).WhenArgumentsMatch(x => (CommandType) x[0] == CommandType.Text).MustHaveHappenedOnceExactly(); - } - - [Test] - public void ExecuteScriptTransactedRollsbackIfNoCommit() - { - IDbProvider dbProvider = A.Fake(); - IDbConnection dbConnection = A.Fake(); - IDbTransaction dbTx = A.Fake(); - DefaultTransactionDefinition txDefinition = new DefaultTransactionDefinition(); - - A.CallTo(() => dbProvider.CreateConnection()).Returns(dbConnection); - A.CallTo(() => dbConnection.BeginTransaction(txDefinition.TransactionIsolationLevel)).Returns(dbTx); - - AdoTemplate adoOps = new AdoTemplate(dbProvider); - IPlatformTransaction tx = SimpleAdoTestUtils.CreateTransaction(dbProvider, txDefinition); - tx.Dispose(); - - A.CallTo(() => dbConnection.Open()).MustHaveHappenedOnceExactly(); - A.CallTo(() => dbTx.Rollback()).MustHaveHappenedOnceExactly(); - A.CallTo(() => dbConnection.Dispose()).MustHaveHappenedOnceExactly(); - } + adoTemplate = A.Fake(); } -} \ No newline at end of file + + [Test] + public void ExecuteEmptyScript() + { + IResource scriptResource = new StringResource(""); + + SimpleAdoTestUtils.ExecuteSqlScript(adoTemplate, scriptResource, false, SimpleAdoTestUtils.BLOCKDELIM_GO_EXP); + } + + [Test] + public void ExecuteSingleStatement() + { + IResource scriptResource = new StringResource("statement 1"); + + SimpleAdoTestUtils.ExecuteSqlScript(adoTemplate, scriptResource, false, SimpleAdoTestUtils.BLOCKDELIM_GO_EXP); + A.CallTo(() => adoTemplate.ExecuteNonQuery(CommandType.Text, "statement 1")).MustHaveHappened(); + } + + [Test] + public void ExecuteScriptWithMissingSeparatorOnLastBlock() + { + IResource scriptResource = new StringResource("\tstatement 1 \n\n\t GO\t \n statement 2"); + + SimpleAdoTestUtils.ExecuteSqlScript(adoTemplate, scriptResource, false, SimpleAdoTestUtils.BLOCKDELIM_GO_EXP); + + A.CallTo(() => adoTemplate.ExecuteNonQuery(CommandType.Text, "\tstatement 1 \n")).MustHaveHappened(); + A.CallTo(() => adoTemplate.ExecuteNonQuery(CommandType.Text, "\n statement 2")).MustHaveHappened(); + } + + [Test] + public void ExecuteScriptWithGOBlocks() + { + IResource scriptResource = new StringResource("\tstatement 1 \n\n\t GO\t \n statement 2\nGO"); + + A.CallTo(() => adoTemplate.ExecuteNonQuery(CommandType.Text, "\tstatement 1 \n")).Returns(0); + A.CallTo(() => adoTemplate.ExecuteNonQuery(CommandType.Text, "\n statement 2\n")).Returns(0); + + SimpleAdoTestUtils.ExecuteSqlScript(adoTemplate, scriptResource, false, SimpleAdoTestUtils.BLOCKDELIM_GO_EXP); + } + + [Test] + public void ExecuteScriptWithSemicolonSeparatedStatements() + { + IResource scriptResource = new StringResource("\tstatement 1 ;\nGO\n statement 2;"); + + A.CallTo(() => adoTemplate.ExecuteNonQuery(CommandType.Text, "\tstatement 1 ")).Returns(0); + A.CallTo(() => adoTemplate.ExecuteNonQuery(CommandType.Text, "\nGO\n statement 2")).Returns(0); + + SimpleAdoTestUtils.ExecuteSqlScript(adoTemplate, scriptResource, false, SimpleAdoTestUtils.BLOCKDELIM_SEMICOLON_EXP); + } + + [Test] + public void ExecuteScriptTransactedSuccess() + { + IDbProvider dbProvider = A.Fake(); + IDbConnection dbConnection = A.Fake(); + IDbTransaction dbTx = A.Fake(); + IDbCommand dbCommand = A.Fake(); + DefaultTransactionDefinition txDefinition = new DefaultTransactionDefinition(); + + A.CallTo(() => dbProvider.CreateConnection()).Returns(dbConnection); + A.CallTo(() => dbConnection.BeginTransaction(txDefinition.TransactionIsolationLevel)).Returns(dbTx); + A.CallTo(() => dbProvider.CreateCommand()).Returns(dbCommand); + A.CallTo(() => dbCommand.ExecuteNonQuery()).Returns(0); + + AdoTemplate adoOps = new AdoTemplate(dbProvider); + IPlatformTransaction tx = SimpleAdoTestUtils.CreateTransaction(dbProvider, txDefinition); + + SimpleAdoTestUtils.ExecuteSqlScript(adoOps, "simple sql cmd"); + tx.Commit(); + tx.Dispose(); + + A.CallTo(() => dbConnection.Open()).MustHaveHappenedOnceExactly(); + A.CallTo(() => dbTx.Commit()).MustHaveHappenedOnceExactly(); + A.CallTo(() => dbCommand.Dispose()).MustHaveHappenedOnceExactly(); + A.CallTo(() => dbConnection.Dispose()).MustHaveHappenedOnceExactly(); + + A.CallToSet(() => dbCommand.Connection).WhenArgumentsMatch(x => x[0] == dbConnection).MustHaveHappenedOnceExactly(); + A.CallToSet(() => dbCommand.Transaction).WhenArgumentsMatch(x => x[0] == dbTx).MustHaveHappenedOnceExactly(); + A.CallToSet(() => dbCommand.CommandText).WhenArgumentsMatch(x => (string) x[0] == "simple sql cmd").MustHaveHappenedOnceExactly(); + A.CallToSet(() => dbCommand.CommandType).WhenArgumentsMatch(x => (CommandType) x[0] == CommandType.Text).MustHaveHappenedOnceExactly(); + } + + [Test] + public void ExecuteScriptTransactedRollsbackIfNoCommit() + { + IDbProvider dbProvider = A.Fake(); + IDbConnection dbConnection = A.Fake(); + IDbTransaction dbTx = A.Fake(); + DefaultTransactionDefinition txDefinition = new DefaultTransactionDefinition(); + + A.CallTo(() => dbProvider.CreateConnection()).Returns(dbConnection); + A.CallTo(() => dbConnection.BeginTransaction(txDefinition.TransactionIsolationLevel)).Returns(dbTx); + + AdoTemplate adoOps = new AdoTemplate(dbProvider); + IPlatformTransaction tx = SimpleAdoTestUtils.CreateTransaction(dbProvider, txDefinition); + tx.Dispose(); + + A.CallTo(() => dbConnection.Open()).MustHaveHappenedOnceExactly(); + A.CallTo(() => dbTx.Rollback()).MustHaveHappenedOnceExactly(); + A.CallTo(() => dbConnection.Dispose()).MustHaveHappenedOnceExactly(); + } +} diff --git a/test/Spring/Spring.Testing.NUnit.Tests/Testing/NUnit/AbstractDependencyInjectionSpringContextTestsTests.cs b/test/Spring/Spring.Testing.NUnit.Tests/Testing/NUnit/AbstractDependencyInjectionSpringContextTestsTests.cs index 3fc1bc8f..5545a44d 100644 --- a/test/Spring/Spring.Testing.NUnit.Tests/Testing/NUnit/AbstractDependencyInjectionSpringContextTestsTests.cs +++ b/test/Spring/Spring.Testing.NUnit.Tests/Testing/NUnit/AbstractDependencyInjectionSpringContextTestsTests.cs @@ -19,163 +19,158 @@ #endregion using NUnit.Framework; - using Spring.Context; using Spring.Context.Support; -namespace Spring.Testing.NUnit +namespace Spring.Testing.NUnit; + +/// +/// Summary description for AbstractDependencyInjectionSpringContextTestsTests. +/// +[TestFixture] +public class AbstractDependencyInjectionSpringContextTestsTests { - /// - /// Summary description for AbstractDependencyInjectionSpringContextTestsTests. - /// - [TestFixture] - public class AbstractDependencyInjectionSpringContextTestsTests + private class TestAbstractDependencyInjectionSpringContextTests : AbstractDependencyInjectionSpringContextTests { - private class TestAbstractDependencyInjectionSpringContextTests : AbstractDependencyInjectionSpringContextTests + public static readonly string[] CONFIGLOCATIONS = new string[] { - public static readonly string[] CONFIGLOCATIONS = new string[] - { #if NUNIT_3 "assembly://Spring.Testing.NUnit3.Tests/Spring.Testing.NUnit/TestApplicationContext.xml" #else - "assembly://Spring.Testing.NUnit.Tests/Spring.Testing.NUnit/TestApplicationContext.xml" + "assembly://Spring.Testing.NUnit.Tests/Spring.Testing.NUnit/TestApplicationContext.xml" #endif - }; + }; - public TestAbstractDependencyInjectionSpringContextTests() - { - } - - public TestAbstractDependencyInjectionSpringContextTests(bool registerWithContextRegistry) - { - base.RegisterContextWithContextRegistry = registerWithContextRegistry; - } - - public IConfigurableApplicationContext ApplicationContext - { - get { return base.applicationContext; } - } - - protected override string[] ConfigLocations - { - get { return CONFIGLOCATIONS; } - } - - public new bool HasCachedContext(object key) - { - return base.HasCachedContext(key); - } + public TestAbstractDependencyInjectionSpringContextTests() + { } - private TestAbstractDependencyInjectionSpringContextTests fixtureInstance; - - [TearDown] - public void TearDown() + public TestAbstractDependencyInjectionSpringContextTests(bool registerWithContextRegistry) { - AbstractSpringContextTests.ClearContextCache(); + base.RegisterContextWithContextRegistry = registerWithContextRegistry; } - [Test] - public void RegistersWithContextRegistryByDefault() + public IConfigurableApplicationContext ApplicationContext { - fixtureInstance = new TestAbstractDependencyInjectionSpringContextTests(); - Assert.IsTrue(fixtureInstance.RegisterContextWithContextRegistry); + get { return base.applicationContext; } } - [Test] - public void UnregistersFromContextRegistryWhenDirty() + protected override string[] ConfigLocations { - fixtureInstance = new TestAbstractDependencyInjectionSpringContextTests(); - Assert.IsTrue(fixtureInstance.RegisterContextWithContextRegistry); - fixtureInstance.SetUp(); - Assert.IsTrue(ContextRegistry.IsContextRegistered(fixtureInstance.ApplicationContext.Name)); - fixtureInstance.TearDown(); - Assert.IsTrue(ContextRegistry.IsContextRegistered(fixtureInstance.ApplicationContext.Name)); - fixtureInstance.SetUp(); - Assert.IsTrue(ContextRegistry.IsContextRegistered(fixtureInstance.ApplicationContext.Name)); - fixtureInstance.SetDirty(); - fixtureInstance.TearDown(); - Assert.IsFalse(ContextRegistry.IsContextRegistered(fixtureInstance.ApplicationContext.Name)); + get { return CONFIGLOCATIONS; } } - [Test] - public void DoesNotRegisterContextWithContextRegistry() + public new bool HasCachedContext(object key) { - fixtureInstance = new TestAbstractDependencyInjectionSpringContextTests(); - Assert.IsTrue(fixtureInstance.RegisterContextWithContextRegistry); - fixtureInstance.RegisterContextWithContextRegistry = false; - fixtureInstance.SetUp(); - Assert.IsFalse(ContextRegistry.IsContextRegistered(fixtureInstance.ApplicationContext.Name)); - fixtureInstance.TearDown(); - Assert.IsFalse(ContextRegistry.IsContextRegistered(fixtureInstance.ApplicationContext.Name)); - } - - [Test] - public void CachesApplicationContexts() - { - fixtureInstance = new TestAbstractDependencyInjectionSpringContextTests(false); - fixtureInstance.SetUp(); - Assert.IsNotNull(fixtureInstance.ApplicationContext); - Assert.AreEqual(1, fixtureInstance.LoadCount); // context has been loaded - Assert.IsTrue(fixtureInstance.HasCachedContext(TestAbstractDependencyInjectionSpringContextTests.CONFIGLOCATIONS)); - fixtureInstance.TearDown(); - - TestAbstractDependencyInjectionSpringContextTests otherFixtureInstance = new TestAbstractDependencyInjectionSpringContextTests(false); - otherFixtureInstance.SetUp(); - Assert.IsNotNull(otherFixtureInstance.ApplicationContext); - Assert.AreEqual(0, otherFixtureInstance.LoadCount); // context was obtained from cache - Assert.AreSame(fixtureInstance.ApplicationContext, otherFixtureInstance.ApplicationContext); - otherFixtureInstance.SetDirty(); // purge cache and dispose cached instances - Assert.IsFalse(fixtureInstance.HasCachedContext(TestAbstractDependencyInjectionSpringContextTests.CONFIGLOCATIONS)); - otherFixtureInstance.TearDown(); - - otherFixtureInstance = new TestAbstractDependencyInjectionSpringContextTests(false); - otherFixtureInstance.SetUp(); - Assert.IsNotNull(otherFixtureInstance.ApplicationContext); - Assert.AreEqual(1, otherFixtureInstance.LoadCount); // context was reloaded because of SetDirty() above - Assert.AreNotSame(fixtureInstance.ApplicationContext, otherFixtureInstance.ApplicationContext); - otherFixtureInstance.TearDown(); - } - - private class TestAbstractDependencyInjectionSpringContextTestsExceptions : AbstractDependencyInjectionSpringContextTests - { - private static readonly string[] CONFIGLOCATIONS = new string[] - { - "assembly://Spring.Testing.NUnit.Tests/Spring.Testing.NUnit/TestApplicationContext.xml" - }; - - public TestAbstractDependencyInjectionSpringContextTestsExceptions() - { - } - - protected override string[] ConfigLocations - { - get { return CONFIGLOCATIONS; } - } - - protected override void OnSetUp() - { - throw new Exception("SetUp Exception"); - } - - protected override void OnTearDown() - { - throw new Exception("TearDown Exception"); - } - } - - [Test] - public void ThrowsSetUpException() - { - var testFixture = new TestAbstractDependencyInjectionSpringContextTestsExceptions(); - Assert.Throws(() => testFixture.SetUp()); - } - - [Test] - public void ThrowsTearDownException() - { - var testFixture = new TestAbstractDependencyInjectionSpringContextTestsExceptions(); - Assert.Throws(() => testFixture.TearDown()); + return base.HasCachedContext(key); } } + + private TestAbstractDependencyInjectionSpringContextTests fixtureInstance; + + [TearDown] + public void TearDown() + { + AbstractSpringContextTests.ClearContextCache(); + } + + [Test] + public void RegistersWithContextRegistryByDefault() + { + fixtureInstance = new TestAbstractDependencyInjectionSpringContextTests(); + Assert.IsTrue(fixtureInstance.RegisterContextWithContextRegistry); + } + + [Test] + public void UnregistersFromContextRegistryWhenDirty() + { + fixtureInstance = new TestAbstractDependencyInjectionSpringContextTests(); + Assert.IsTrue(fixtureInstance.RegisterContextWithContextRegistry); + fixtureInstance.SetUp(); + Assert.IsTrue(ContextRegistry.IsContextRegistered(fixtureInstance.ApplicationContext.Name)); + fixtureInstance.TearDown(); + Assert.IsTrue(ContextRegistry.IsContextRegistered(fixtureInstance.ApplicationContext.Name)); + fixtureInstance.SetUp(); + Assert.IsTrue(ContextRegistry.IsContextRegistered(fixtureInstance.ApplicationContext.Name)); + fixtureInstance.SetDirty(); + fixtureInstance.TearDown(); + Assert.IsFalse(ContextRegistry.IsContextRegistered(fixtureInstance.ApplicationContext.Name)); + } + + [Test] + public void DoesNotRegisterContextWithContextRegistry() + { + fixtureInstance = new TestAbstractDependencyInjectionSpringContextTests(); + Assert.IsTrue(fixtureInstance.RegisterContextWithContextRegistry); + fixtureInstance.RegisterContextWithContextRegistry = false; + fixtureInstance.SetUp(); + Assert.IsFalse(ContextRegistry.IsContextRegistered(fixtureInstance.ApplicationContext.Name)); + fixtureInstance.TearDown(); + Assert.IsFalse(ContextRegistry.IsContextRegistered(fixtureInstance.ApplicationContext.Name)); + } + + [Test] + public void CachesApplicationContexts() + { + fixtureInstance = new TestAbstractDependencyInjectionSpringContextTests(false); + fixtureInstance.SetUp(); + Assert.IsNotNull(fixtureInstance.ApplicationContext); + Assert.AreEqual(1, fixtureInstance.LoadCount); // context has been loaded + Assert.IsTrue(fixtureInstance.HasCachedContext(TestAbstractDependencyInjectionSpringContextTests.CONFIGLOCATIONS)); + fixtureInstance.TearDown(); + + TestAbstractDependencyInjectionSpringContextTests otherFixtureInstance = new TestAbstractDependencyInjectionSpringContextTests(false); + otherFixtureInstance.SetUp(); + Assert.IsNotNull(otherFixtureInstance.ApplicationContext); + Assert.AreEqual(0, otherFixtureInstance.LoadCount); // context was obtained from cache + Assert.AreSame(fixtureInstance.ApplicationContext, otherFixtureInstance.ApplicationContext); + otherFixtureInstance.SetDirty(); // purge cache and dispose cached instances + Assert.IsFalse(fixtureInstance.HasCachedContext(TestAbstractDependencyInjectionSpringContextTests.CONFIGLOCATIONS)); + otherFixtureInstance.TearDown(); + + otherFixtureInstance = new TestAbstractDependencyInjectionSpringContextTests(false); + otherFixtureInstance.SetUp(); + Assert.IsNotNull(otherFixtureInstance.ApplicationContext); + Assert.AreEqual(1, otherFixtureInstance.LoadCount); // context was reloaded because of SetDirty() above + Assert.AreNotSame(fixtureInstance.ApplicationContext, otherFixtureInstance.ApplicationContext); + otherFixtureInstance.TearDown(); + } + + private class TestAbstractDependencyInjectionSpringContextTestsExceptions : AbstractDependencyInjectionSpringContextTests + { + private static readonly string[] CONFIGLOCATIONS = new string[] { "assembly://Spring.Testing.NUnit.Tests/Spring.Testing.NUnit/TestApplicationContext.xml" }; + + public TestAbstractDependencyInjectionSpringContextTestsExceptions() + { + } + + protected override string[] ConfigLocations + { + get { return CONFIGLOCATIONS; } + } + + protected override void OnSetUp() + { + throw new Exception("SetUp Exception"); + } + + protected override void OnTearDown() + { + throw new Exception("TearDown Exception"); + } + } + + [Test] + public void ThrowsSetUpException() + { + var testFixture = new TestAbstractDependencyInjectionSpringContextTestsExceptions(); + Assert.Throws(() => testFixture.SetUp()); + } + + [Test] + public void ThrowsTearDownException() + { + var testFixture = new TestAbstractDependencyInjectionSpringContextTestsExceptions(); + Assert.Throws(() => testFixture.TearDown()); + } } diff --git a/test/Spring/Spring.Testing.NUnit.Tests/Testing/NUnit/TestApplicationContext.xml b/test/Spring/Spring.Testing.NUnit.Tests/Testing/NUnit/TestApplicationContext.xml index 405b503c..16398d50 100644 --- a/test/Spring/Spring.Testing.NUnit.Tests/Testing/NUnit/TestApplicationContext.xml +++ b/test/Spring/Spring.Testing.NUnit.Tests/Testing/NUnit/TestApplicationContext.xml @@ -2,18 +2,18 @@ - + - + + + + + + + + - - - - - - - \ No newline at end of file diff --git a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Bsn/ConversationEvidenceBsnImpl.cs b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Bsn/ConversationEvidenceBsnImpl.cs index ea64ef69..bd7bc0e7 100644 --- a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Bsn/ConversationEvidenceBsnImpl.cs +++ b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Bsn/ConversationEvidenceBsnImpl.cs @@ -18,34 +18,33 @@ #endregion -namespace Spring.Bsn +namespace Spring.Bsn; + +/// +/// +/// +public class ConversationEvidenceBsnImpl : IConversationEvidenceBsn { + private String uniqueId = ""; + + /// + /// Create instance with unique id. + /// + public ConversationEvidenceBsnImpl() + { + uniqueId = Guid.NewGuid().ToString(); + } + + #region IConversationEvidenceBsn Members + /// /// /// - public class ConversationEvidenceBsnImpl: IConversationEvidenceBsn + /// + public String UniqueId() { - private String uniqueId = ""; - - /// - /// Create instance with unique id. - /// - public ConversationEvidenceBsnImpl() - { - uniqueId = Guid.NewGuid().ToString(); - } - - #region IConversationEvidenceBsn Members - - /// - /// - /// - /// - public String UniqueId() - { - return this.uniqueId; - } - - #endregion + return this.uniqueId; } + + #endregion } diff --git a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Bsn/IConversationEvidenceBsn.cs b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Bsn/IConversationEvidenceBsn.cs index d4e2e093..c30db499 100644 --- a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Bsn/IConversationEvidenceBsn.cs +++ b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Bsn/IConversationEvidenceBsn.cs @@ -18,18 +18,17 @@ #endregion -namespace Spring.Bsn +namespace Spring.Bsn; + +/// +/// Simulates a business infrastructure in order to demonstrate the end of +/// the conversation. +/// +public interface IConversationEvidenceBsn { /// - /// Simulates a business infrastructure in order to demonstrate the end of - /// the conversation. + /// Return a unique id per instance. /// - public interface IConversationEvidenceBsn - { - /// - /// Return a unique id per instance. - /// - /// - String UniqueId(); - } + /// + String UniqueId(); } diff --git a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Bsn/INoDeferedErrorBsn.cs b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Bsn/INoDeferedErrorBsn.cs index d790ee76..c6231d9c 100644 --- a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Bsn/INoDeferedErrorBsn.cs +++ b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Bsn/INoDeferedErrorBsn.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -18,16 +18,15 @@ #endregion -namespace Spring.Bsn +namespace Spring.Bsn; + +/// +/// TODO: +/// +public interface IConnectionReleaseModeIssueBsn { /// - /// TODO: + /// TODO /// - public interface IConnectionReleaseModeIssueBsn - { - /// - /// TODO - /// - void Test(); - } + void Test(); } diff --git a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Bsn/NoDeferedErrorBsnImpl.cs b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Bsn/NoDeferedErrorBsnImpl.cs index 8ab430f6..821c3cf8 100644 --- a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Bsn/NoDeferedErrorBsnImpl.cs +++ b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Bsn/NoDeferedErrorBsnImpl.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -23,58 +23,58 @@ using Spring.Entities; using NUnit.Framework; using Spring.Spring.Data.Common; -namespace Spring.Bsn +namespace Spring.Bsn; + +/// +/// Outside the "transaction boundaries", each statement +/// execution (lazy loads) was being made a call to +/// "IDbProvider.CreateConnection()". This would +/// cause a large over-reading because most of the "lazy loads" tend to +/// occur outside the "transaction boundaries". +/// The solution to this is to use "connection.release_mode" with "on_close" +/// in "HibernateProperties." +/// This test was created to show how the connection openings +/// occur in the following scenarios: +/// *Test with conversation and "connection.release_mode" +/// "auto"(ConnectionReleaseMode.AfterTransaction). +/// *Test with NO conversation and "connection.release_mode" +/// "auto"(ConnectionReleaseMode.AfterTransaction) +/// on block within the scope of "transaction boundary". +/// *Test with NO conversation and "connection.release_mode" +/// "auto"(ConnectionReleaseMode.AfterTransaction). +/// *Test with conversation and "connection.release_mode" +/// "on_close"(ConnectionReleaseMode.OnClose). +/// +public class ConnectionReleaseModeIssueBsnImpl : IConnectionReleaseModeIssueBsn { + private ISessionFactory sessionFactory; + /// - /// Outside the "transaction boundaries", each statement - /// execution (lazy loads) was being made a call to - /// "IDbProvider.CreateConnection()". This would - /// cause a large over-reading because most of the "lazy loads" tend to - /// occur outside the "transaction boundaries". - /// The solution to this is to use "connection.release_mode" with "on_close" - /// in "HibernateProperties." - /// This test was created to show how the connection openings - /// occur in the following scenarios: - /// *Test with conversation and "connection.release_mode" - /// "auto"(ConnectionReleaseMode.AfterTransaction). - /// *Test with NO conversation and "connection.release_mode" - /// "auto"(ConnectionReleaseMode.AfterTransaction) - /// on block within the scope of "transaction boundary". - /// *Test with NO conversation and "connection.release_mode" - /// "auto"(ConnectionReleaseMode.AfterTransaction). - /// *Test with conversation and "connection.release_mode" - /// "on_close"(ConnectionReleaseMode.OnClose). + /// SessionFactory. /// - public class ConnectionReleaseModeIssueBsnImpl : IConnectionReleaseModeIssueBsn + public ISessionFactory SessionFactory { - private ISessionFactory sessionFactory; - /// - /// SessionFactory. - /// - public ISessionFactory SessionFactory - { - get { return sessionFactory; } - set { sessionFactory = value; } - } - - #region IConnectionReleaseModeIssueBsn Members - - /// - /// Test. - /// - [Transaction.Interceptor.Transaction(ReadOnly=true)] - public void Test() - { - ISession sessionNoConv = this.SessionFactory.GetCurrentSession(); - SPCMasterEnt masterEnt2 = sessionNoConv.Get(2); - Assert.AreEqual(1, masterEnt2.SPCDetailEntList.Count, "masterEnt2.SPCDetailEntList.Count"); - - SPCMasterEnt masterEnt3 = sessionNoConv.Get(3); - Assert.AreEqual(1, masterEnt3.SPCDetailEntList.Count, "masterEnt3.SPCDetailEntList.Count"); - - Assert.AreEqual(1, ConnectionCreationTrackingDbProvider.Count, "ConnectionCreationTrackingDbProvider.Count"); - } - - #endregion + get { return sessionFactory; } + set { sessionFactory = value; } } + + #region IConnectionReleaseModeIssueBsn Members + + /// + /// Test. + /// + [Transaction.Interceptor.Transaction(ReadOnly = true)] + public void Test() + { + ISession sessionNoConv = this.SessionFactory.GetCurrentSession(); + SPCMasterEnt masterEnt2 = sessionNoConv.Get(2); + Assert.AreEqual(1, masterEnt2.SPCDetailEntList.Count, "masterEnt2.SPCDetailEntList.Count"); + + SPCMasterEnt masterEnt3 = sessionNoConv.Get(3); + Assert.AreEqual(1, masterEnt3.SPCDetailEntList.Count, "masterEnt3.SPCDetailEntList.Count"); + + Assert.AreEqual(1, ConnectionCreationTrackingDbProvider.Count, "ConnectionCreationTrackingDbProvider.Count"); + } + + #endregion } diff --git a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Conversation/HttpWebclientExtensions.cs b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Conversation/HttpWebclientExtensions.cs index 3434c14d..78f36ca7 100644 --- a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Conversation/HttpWebclientExtensions.cs +++ b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Conversation/HttpWebclientExtensions.cs @@ -1,4 +1,5 @@ #region License + // /* // * Copyright 2018 the original author or authors. // * @@ -14,22 +15,21 @@ // * See the License for the specific language governing permissions and // * limitations under the License. // */ + #endregion using NUnitAspEx; using NUnitAspEx.Client; -namespace Spring.Web.Conversation +namespace Spring.Web.Conversation; + +public static class HttpWebclientExtensions { - public static class HttpWebclientExtensions + public static HttpWebClient CreateClientWithDefaultPort(this IAspFixtureHost host) { - - public static HttpWebClient CreateClientWithDefaultPort(this IAspFixtureHost host) - { - HttpWebClient clnt = host.CreateWebClient(); - // fix port which otherwise defaults to -1 breaking everything - clnt.BaseAddress = clnt.BaseAddress.Replace("aspfixturehost/", "aspfixturehost:80/"); - return clnt; - } + HttpWebClient clnt = host.CreateWebClient(); + // fix port which otherwise defaults to -1 breaking everything + clnt.BaseAddress = clnt.BaseAddress.Replace("aspfixturehost/", "aspfixturehost:80/"); + return clnt; } } \ No newline at end of file diff --git a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Conversation/PatialEndConvBeginBasePage.cs b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Conversation/PatialEndConvBeginBasePage.cs index 16991eaa..10b77a1b 100644 --- a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Conversation/PatialEndConvBeginBasePage.cs +++ b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Conversation/PatialEndConvBeginBasePage.cs @@ -20,34 +20,34 @@ using Spring.Web.UI; -namespace Spring.Web.Conversation +namespace Spring.Web.Conversation; + +/// +/// Base class for test pages for test +/// . +/// +public class PatialEndConvBeginBasePage : Page { + private IConversationState conversation; + /// - /// Base class for test pages for test - /// . + /// /// - public class PatialEndConvBeginBasePage: Page + public IConversationState Conversation { - private IConversationState conversation; - /// - /// - /// - public IConversationState Conversation - { - get { return conversation; } - set { conversation = value; } - } + get { return conversation; } + set { conversation = value; } + } - /// - /// Common Begin. - /// - /// - /// - protected virtual void Page_Load(object sender, EventArgs e) - { - this.Conversation.StartResumeConversation(); + /// + /// Common Begin. + /// + /// + /// + protected virtual void Page_Load(object sender, EventArgs e) + { + this.Conversation.StartResumeConversation(); - Session["ConversationStr"] = this.Conversation.ToString(); - } + Session["ConversationStr"] = this.Conversation.ToString(); } } diff --git a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Conversation/PatialEndConvEndBasePage.cs b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Conversation/PatialEndConvEndBasePage.cs index 9f2fa063..ee22caa7 100644 --- a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Conversation/PatialEndConvEndBasePage.cs +++ b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Conversation/PatialEndConvEndBasePage.cs @@ -20,32 +20,32 @@ using Spring.Web.UI; -namespace Spring.Web.Conversation -{ - /// - /// Base class for test pages for test - /// . - /// - public abstract class PatialEndConvEndBasePage: Page - { - private IConversationState conversation; - /// - /// - /// - public IConversationState Conversation - { - get { return conversation; } - set { conversation = value; } - } +namespace Spring.Web.Conversation; - /// - /// Common End. - /// - /// - /// - public virtual void Page_Load(object sender, EventArgs e) - { - this.Conversation.EndConversation(); - } +/// +/// Base class for test pages for test +/// . +/// +public abstract class PatialEndConvEndBasePage : Page +{ + private IConversationState conversation; + + /// + /// + /// + public IConversationState Conversation + { + get { return conversation; } + set { conversation = value; } + } + + /// + /// Common End. + /// + /// + /// + public virtual void Page_Load(object sender, EventArgs e) + { + this.Conversation.EndConversation(); } } diff --git a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Conversation/SerializeConversationTestModule.cs b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Conversation/SerializeConversationTestModule.cs index 74be852e..752ca028 100644 --- a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Conversation/SerializeConversationTestModule.cs +++ b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Conversation/SerializeConversationTestModule.cs @@ -24,232 +24,233 @@ using System.Runtime.Serialization; using System.Reflection; using Microsoft.Extensions.Logging; -namespace Spring.Web.Conversation +namespace Spring.Web.Conversation; + +/// +/// Module that forces the serialization and deserialization of the session content to simulate a clustered server for +/// . +/// +public class SerializeConversationTestModule : IHttpModule { + #region Logging + + private static readonly ILogger LOG = LogManager.GetLogger(); + + #endregion + /// - /// Module that forces the serialization and deserialization of the session content to simulate a clustered server for - /// . + /// Serialized Session Content. /// - public class SerializeConversationTestModule: IHttpModule + private static MemoryStream SerializedSessionContentStream = new MemoryStream(); + + #region IHttpModule Members + + /// + /// TODO: + /// + public void Dispose() { - #region Logging + // + } - private static readonly ILogger LOG = LogManager.GetLogger(); + /// + /// TODO: + /// + /// + public void Init(HttpApplication context) + { + context.PreRequestHandlerExecute += context_PreRequestHandlerExecute; + context.PostRequestHandlerExecute += context_PostRequestHandlerExecute; + } - #endregion - - /// - /// Serialized Session Content. - /// - private static MemoryStream SerializedSessionContentStream = new MemoryStream(); - - #region IHttpModule Members - - /// - /// TODO: - /// - public void Dispose() + /// + /// Repopulates the session from the previously serialized content. + /// + /// + /// + void context_PreRequestHandlerExecute(object sender, EventArgs e) + { + if (HttpContext.Current.Session != null) { - // - } - - /// - /// TODO: - /// - /// - public void Init(HttpApplication context) - { - context.PreRequestHandlerExecute += context_PreRequestHandlerExecute; - context.PostRequestHandlerExecute += context_PostRequestHandlerExecute; - } - - /// - /// Repopulates the session from the previously serialized content. - /// - /// - /// - void context_PreRequestHandlerExecute(object sender, EventArgs e) - { - if (HttpContext.Current.Session != null) + if (HttpContext.Current.Request.AppRelativeCurrentExecutionFilePath == "~/SerializeConversationTest.aspx") { - if (HttpContext.Current.Request.AppRelativeCurrentExecutionFilePath == "~/SerializeConversationTest.aspx") + if (SerializedSessionContentStream.Length > 0) { - if (SerializedSessionContentStream.Length > 0) - { - BinaryFormatter bf = new BinaryFormatter(); - bf.Binder = new MyBinder(); - //SurrogateSelector surrogateSelector = new SurrogateSelector(); - //surrogateSelector.AddSurrogate( - // typeof(Object), - // new StreamingContext(StreamingContextStates.All), - // new MySerializationSurrogate()); - //bf.SurrogateSelector = surrogateSelector; - - SerializedSessionContentStream.Seek(0, SeekOrigin.Begin); - Dictionary sessionConttent = - (Dictionary)bf.Deserialize(SerializedSessionContentStream); - - HttpContext.Current.Session.Clear(); - foreach (String keyItem in sessionConttent.Keys) - { - HttpContext.Current.Session[keyItem] = sessionConttent[keyItem]; - } - } - } - } - } - - /// - /// Serializes and clears the session. - /// - /// - /// - void context_PostRequestHandlerExecute(object sender, EventArgs e) - { - if (HttpContext.Current.Session != null) - { - //NHibernate.ISession ss; - if (HttpContext.Current.Request.AppRelativeCurrentExecutionFilePath == "~/SerializeConversationTest.aspx") - { - Dictionary sessionConttent = new Dictionary(); - foreach (String keyItem in HttpContext.Current.Session.Keys) - { - sessionConttent[keyItem] = HttpContext.Current.Session[keyItem]; - } - BinaryFormatter bf = new BinaryFormatter(); bf.Binder = new MyBinder(); //SurrogateSelector surrogateSelector = new SurrogateSelector(); //surrogateSelector.AddSurrogate( - // typeof(Object), + // typeof(Object), // new StreamingContext(StreamingContextStates.All), // new MySerializationSurrogate()); //bf.SurrogateSelector = surrogateSelector; - SerializedSessionContentStream = new MemoryStream(); - bf.Serialize(SerializedSessionContentStream, sessionConttent); + SerializedSessionContentStream.Seek(0, SeekOrigin.Begin); + Dictionary sessionConttent = + (Dictionary) bf.Deserialize(SerializedSessionContentStream); HttpContext.Current.Session.Clear(); - } - } - } - #endregion - } - - public class MyBinder : SerializationBinder - { - #region Logging - - private ILog LOG - { - get - { - return LogManager.GetLogger(typeof(SerializeConversationTestModule)); - } - } - - #endregion - - public override Type BindToType(string assemblyName, string typeName) - { - if (LOG.IsEnabled(LogLevel.Debug)) - LOG.LogDebug(String.Format("MyBinder.BindToType: {0}, {1}", typeName, assemblyName)); - return Type.GetType(typeName + ", " + assemblyName); - } - } - - ///// - ///// For debugging purpose. - ///// - //public class MySurrogateSelectorWrapper : ISurrogateSelector - //{ - - // ISurrogateSelector wrapped; - // public MySurrogateSelectorWrapper(ISurrogateSelector wrapped) - // { - // this.wrapped = wrapped; - // } - // #region ISurrogateSelector Members - - // public void ChainSelector(ISurrogateSelector selector) - // { - // this.wrapped.ChainSelector(selector); - // } - - // public ISurrogateSelector GetNextSelector() - // { - // ISurrogateSelector selector = this.wrapped.GetNextSelector(); - // if (!(selector is MySurrogateSelectorWrapper)) - // selector = new MySurrogateSelectorWrapper(selector); - // return selector; - // } - - // public ISerializationSurrogate GetSurrogate(Type type, StreamingContext context, out ISurrogateSelector selector) - // { - // ISerializationSurrogate surrogate = new MySerializationSurrogate(this.wrapped.GetSurrogate(type, context, out selector)); - // if (!(selector is MySurrogateSelectorWrapper)) - // selector = new MySurrogateSelectorWrapper(selector); - // return surrogate; - // } - - // #endregion - //} - - /// - /// For debugging purpose. - /// - public class MySerializationSurrogate : ISerializationSurrogate - { - #region Logging - - private static readonly ILogger LOG = LogManager.GetLogger(); - - #endregion - - #region ISerializationSurrogate Members - - public void GetObjectData(object obj, SerializationInfo info, StreamingContext context) - { - if (LOG.IsEnabled(LogLevel.Debug)) - LOG.LogDebug(String.Format("MySerializationSurrogateWrapper.GetObjectData({0},...", obj.GetType())); - - FieldInfo[] fields = obj.GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.FlattenHierarchy); - if (obj is ISerializable) - { - ((ISerializable)obj).GetObjectData(info, context); - } - else - { - for (int i = 0; i < fields.Length; i++) - { - if ((fields[i].Attributes & FieldAttributes.NotSerialized) == 0) + foreach (String keyItem in sessionConttent.Keys) { - info.AddValue(fields[i].Name, fields[i].GetValue(obj), fields[i].FieldType); + HttpContext.Current.Session[keyItem] = sessionConttent[keyItem]; } } } } + } - public object SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector) + /// + /// Serializes and clears the session. + /// + /// + /// + void context_PostRequestHandlerExecute(object sender, EventArgs e) + { + if (HttpContext.Current.Session != null) { - if (LOG.IsEnabled(LogLevel.Debug)) - LOG.LogDebug(String.Format("MySerializationSurrogateWrapper.SetObjectData({0},...", obj.GetType())); + //NHibernate.ISession ss; + if (HttpContext.Current.Request.AppRelativeCurrentExecutionFilePath == "~/SerializeConversationTest.aspx") + { + Dictionary sessionConttent = new Dictionary(); + foreach (String keyItem in HttpContext.Current.Session.Keys) + { + sessionConttent[keyItem] = HttpContext.Current.Session[keyItem]; + } - FieldInfo[] fields = obj.GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); + BinaryFormatter bf = new BinaryFormatter(); + bf.Binder = new MyBinder(); + //SurrogateSelector surrogateSelector = new SurrogateSelector(); + //surrogateSelector.AddSurrogate( + // typeof(Object), + // new StreamingContext(StreamingContextStates.All), + // new MySerializationSurrogate()); + //bf.SurrogateSelector = surrogateSelector; + SerializedSessionContentStream = new MemoryStream(); + bf.Serialize(SerializedSessionContentStream, sessionConttent); + + HttpContext.Current.Session.Clear(); + } + } + } + + #endregion +} + +public class MyBinder : SerializationBinder +{ + #region Logging + + private ILog LOG + { + get + { + return LogManager.GetLogger(typeof(SerializeConversationTestModule)); + } + } + + #endregion + + public override Type BindToType(string assemblyName, string typeName) + { + if (LOG.IsEnabled(LogLevel.Debug)) + LOG.LogDebug(String.Format("MyBinder.BindToType: {0}, {1}", typeName, assemblyName)); + return Type.GetType(typeName + ", " + assemblyName); + } +} + +///// +///// For debugging purpose. +///// +//public class MySurrogateSelectorWrapper : ISurrogateSelector +//{ + +// ISurrogateSelector wrapped; +// public MySurrogateSelectorWrapper(ISurrogateSelector wrapped) +// { +// this.wrapped = wrapped; +// } +// #region ISurrogateSelector Members + +// public void ChainSelector(ISurrogateSelector selector) +// { +// this.wrapped.ChainSelector(selector); +// } + +// public ISurrogateSelector GetNextSelector() +// { +// ISurrogateSelector selector = this.wrapped.GetNextSelector(); +// if (!(selector is MySurrogateSelectorWrapper)) +// selector = new MySurrogateSelectorWrapper(selector); +// return selector; +// } + +// public ISerializationSurrogate GetSurrogate(Type type, StreamingContext context, out ISurrogateSelector selector) +// { +// ISerializationSurrogate surrogate = new MySerializationSurrogate(this.wrapped.GetSurrogate(type, context, out selector)); +// if (!(selector is MySurrogateSelectorWrapper)) +// selector = new MySurrogateSelectorWrapper(selector); +// return surrogate; +// } + +// #endregion +//} + +/// +/// For debugging purpose. +/// +public class MySerializationSurrogate : ISerializationSurrogate +{ + #region Logging + + private static readonly ILogger LOG = LogManager.GetLogger(); + + #endregion + + #region ISerializationSurrogate Members + + public void GetObjectData(object obj, SerializationInfo info, StreamingContext context) + { + if (LOG.IsEnabled(LogLevel.Debug)) + LOG.LogDebug(String.Format("MySerializationSurrogateWrapper.GetObjectData({0},...", obj.GetType())); + + FieldInfo[] fields = obj.GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.FlattenHierarchy); + if (obj is ISerializable) + { + ((ISerializable) obj).GetObjectData(info, context); + } + else + { for (int i = 0; i < fields.Length; i++) { if ((fields[i].Attributes & FieldAttributes.NotSerialized) == 0) { - fields[i].SetValue(obj, info.GetValue(fields[i].Name, fields[i].FieldType)); + info.AddValue(fields[i].Name, fields[i].GetValue(obj), fields[i].FieldType); } } - if (obj is IDeserializationCallback) - ((IDeserializationCallback)obj).OnDeserialization(obj); + } + } - return obj; + public object SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector) + { + if (LOG.IsEnabled(LogLevel.Debug)) + LOG.LogDebug(String.Format("MySerializationSurrogateWrapper.SetObjectData({0},...", obj.GetType())); + + FieldInfo[] fields = obj.GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); + + for (int i = 0; i < fields.Length; i++) + { + if ((fields[i].Attributes & FieldAttributes.NotSerialized) == 0) + { + fields[i].SetValue(obj, info.GetValue(fields[i].Name, fields[i].FieldType)); + } } - #endregion + if (obj is IDeserializationCallback) + ((IDeserializationCallback) obj).OnDeserialization(obj); + + return obj; } + + #endregion } diff --git a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Conversation/SimpleTest.cs b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Conversation/SimpleTest.cs index 638449cd..49b3db14 100644 --- a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Conversation/SimpleTest.cs +++ b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Conversation/SimpleTest.cs @@ -20,15 +20,14 @@ using NUnit.Framework; -namespace Spring.Web.Conversation +namespace Spring.Web.Conversation; + +[TestFixture] +public class SimpleTest { - [TestFixture] - public class SimpleTest + [Test] + public void Test() { - [Test] - public void Test() - { - Assert.AreEqual(2, 1 + 1, "2 == 1 + 1"); - } + Assert.AreEqual(2, 1 + 1, "2 == 1 + 1"); } } diff --git a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Conversation/WebConversationStateTest.cs b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Conversation/WebConversationStateTest.cs index 77c4a700..176cd4ee 100644 Binary files a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Conversation/WebConversationStateTest.cs and b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Conversation/WebConversationStateTest.cs differ diff --git a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/CircularDependenceTest.aspx b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/CircularDependenceTest.aspx index 462b28e6..2740b041 100644 --- a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/CircularDependenceTest.aspx +++ b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/CircularDependenceTest.aspx @@ -1,3 +1,3 @@ <%@ Page Language="C#" AutoEventWireup="true" CodeFile="CircularDependenceTest.aspx.cs" Inherits="CircularDependenceTest" %><% -Response.Write("OK"); -%> \ No newline at end of file + Response.Write("OK"); + %> \ No newline at end of file diff --git a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/CircularDependenceTest.aspx.cs b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/CircularDependenceTest.aspx.cs index eef5876a..87ec253c 100644 --- a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/CircularDependenceTest.aspx.cs +++ b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/CircularDependenceTest.aspx.cs @@ -4,15 +4,14 @@ using Spring; using Spring.Context; using Spring.Web.Conversation; - public partial class CircularDependenceTest : System.Web.UI.Page, IApplicationContextAware { private static readonly ILogger LOG = LogManager.GetLogger(); protected void Page_Load(object sender, EventArgs e) { - IConversationState convCircularDependenceTest_A = (IConversationState)this.applicationContext.GetObject("convCircularDependenceTest_A"); - IConversationState convCircularDependenceTest_A_A_A = (IConversationState)this.applicationContext.GetObject("convCircularDependenceTest_A_A_A"); + IConversationState convCircularDependenceTest_A = (IConversationState) this.applicationContext.GetObject("convCircularDependenceTest_A"); + IConversationState convCircularDependenceTest_A_A_A = (IConversationState) this.applicationContext.GetObject("convCircularDependenceTest_A_A_A"); StringBuilder sbErrors = new StringBuilder(); try { @@ -37,10 +36,13 @@ public partial class CircularDependenceTest : System.Web.UI.Page, IApplicationCo } #region IApplicationContextAware Members + private IApplicationContext applicationContext; + public IApplicationContext ApplicationContext { set { this.applicationContext = value; } } + #endregion } diff --git a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/ConnectionReleaseModeIssue.aspx.cs b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/ConnectionReleaseModeIssue.aspx.cs index d9095954..3d700005 100644 --- a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/ConnectionReleaseModeIssue.aspx.cs +++ b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/ConnectionReleaseModeIssue.aspx.cs @@ -1,16 +1,13 @@ using System.Reflection; - using Spring.Data.NHibernate.Support; using Spring.Bsn; using Spring.Entities; using Spring.Spring.Data.Common; using Spring.Context; using Spring.Web.Conversation; - using NHibernate; using NHibernate.Cfg; using NHibernate.Impl; - using NUnit.Framework; /// diff --git a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/EndConversationTestBegin.aspx b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/EndConversationTestBegin.aspx index 6bae8f3e..89226bbf 100644 --- a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/EndConversationTestBegin.aspx +++ b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/EndConversationTestBegin.aspx @@ -1,3 +1,3 @@ <%@ Page Language="C#" AutoEventWireup="true" CodeFile="EndConversationTestBegin.aspx.cs" Inherits="EndConversationTestBegin" %><% -Response.Write("OK"); -%> \ No newline at end of file + Response.Write("OK"); + %> \ No newline at end of file diff --git a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/EndConversationTestBegin.aspx.cs b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/EndConversationTestBegin.aspx.cs index e1494ca2..f95f6564 100644 --- a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/EndConversationTestBegin.aspx.cs +++ b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/EndConversationTestBegin.aspx.cs @@ -4,14 +4,15 @@ using Spring.Bsn; public partial class EndConversationTestBegin : System.Web.UI.Page { private IConversationEvidenceBsn conversationEvidenceBsn; + public IConversationEvidenceBsn ConversationEvidenceBsn { get { return conversationEvidenceBsn; } set { conversationEvidenceBsn = value; } } - private IConversationState conversation; + public IConversationState Conversation { get { return conversation; } diff --git a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/EndConversationTestEnd.aspx b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/EndConversationTestEnd.aspx index 37f7a37f..b5d3e899 100644 --- a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/EndConversationTestEnd.aspx +++ b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/EndConversationTestEnd.aspx @@ -1,3 +1,3 @@ <%@ Page Language="C#" AutoEventWireup="true" CodeFile="EndConversationTestEnd.aspx.cs" Inherits="EndConversationTestEnd" %><% -Response.Write("OK"); -%> \ No newline at end of file + Response.Write("OK"); + %> \ No newline at end of file diff --git a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/EndConversationTestEnd.aspx.cs b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/EndConversationTestEnd.aspx.cs index 2630edad..c31e6962 100644 --- a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/EndConversationTestEnd.aspx.cs +++ b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/EndConversationTestEnd.aspx.cs @@ -4,14 +4,15 @@ using Spring.Web.Conversation; public partial class EndConversationTestEnd : System.Web.UI.Page { private IConversationEvidenceBsn conversationEvidenceBsn; + public IConversationEvidenceBsn ConversationEvidenceBsn { get { return conversationEvidenceBsn; } set { conversationEvidenceBsn = value; } } - private IConversationState conversation; + public IConversationState Conversation { get { return conversation; } diff --git a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/EndPausedSessionIsClosedA.aspx.cs b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/EndPausedSessionIsClosedA.aspx.cs index 876ebce4..a0867146 100644 --- a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/EndPausedSessionIsClosedA.aspx.cs +++ b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/EndPausedSessionIsClosedA.aspx.cs @@ -4,8 +4,8 @@ using NHibernate; public partial class EndPausedSessionIsClosedA : System.Web.UI.Page { - private IConversationState conversation; + /// /// /// diff --git a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/EndPausedSessionIsClosedB.aspx.cs b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/EndPausedSessionIsClosedB.aspx.cs index 106d8a01..5d006a20 100644 --- a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/EndPausedSessionIsClosedB.aspx.cs +++ b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/EndPausedSessionIsClosedB.aspx.cs @@ -5,6 +5,7 @@ using Spring.Entities; public partial class EndPausedSessionIsClosedB : System.Web.UI.Page { private IConversationState conversation; + /// /// /// @@ -25,7 +26,7 @@ public partial class EndPausedSessionIsClosedB : System.Web.UI.Page //database access ISession session = this.Conversation.SessionFactory.GetCurrentSession(); SPCMasterEnt sPCMasterEnt = session.Get(1); - + this.Session["result"] = "OK"; } catch (Exception ex) diff --git a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/EndPausedTest.aspx.cs b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/EndPausedTest.aspx.cs index 9d3be558..baeecab1 100644 --- a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/EndPausedTest.aspx.cs +++ b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/EndPausedTest.aspx.cs @@ -9,6 +9,7 @@ public partial class EndPausedTest : System.Web.UI.Page get { return convA; } set { convA = value; } } + private IConversationState convB; public IConversationState ConvB diff --git a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/GetParentObjetFromChild.aspx b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/GetParentObjetFromChild.aspx index bf7bc398..e8dbc198 100644 --- a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/GetParentObjetFromChild.aspx +++ b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/GetParentObjetFromChild.aspx @@ -1,3 +1,3 @@ <%@ Page Language="C#" AutoEventWireup="true" CodeFile="GetParentObjetFromChild.aspx.cs" Inherits="GetParentObjetFromChild" %><% -Response.Write("OK"); -%> \ No newline at end of file + Response.Write("OK"); + %> \ No newline at end of file diff --git a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/GetParentObjetFromChild.aspx.cs b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/GetParentObjetFromChild.aspx.cs index 828cc9de..ba8c09cb 100644 --- a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/GetParentObjetFromChild.aspx.cs +++ b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/GetParentObjetFromChild.aspx.cs @@ -3,6 +3,7 @@ using Spring.Web.Conversation; public partial class GetParentObjetFromChild : System.Web.UI.Page { private IConversationState conversation; + public IConversationState Conversation { get { return conversation; } diff --git a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/IoeTests.aspx b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/IoeTests.aspx index c7e497f8..6f195284 100644 --- a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/IoeTests.aspx +++ b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/IoeTests.aspx @@ -1,3 +1,3 @@ <%@ Page Language="C#" AutoEventWireup="true" CodeFile="IoeTests.aspx.cs" Inherits="IoeTests" %><% -Response.Write("OK"); -%> \ No newline at end of file + Response.Write("OK"); + %> \ No newline at end of file diff --git a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/IoeTests.aspx.cs b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/IoeTests.aspx.cs index 87db9117..8a7ac7dd 100644 --- a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/IoeTests.aspx.cs +++ b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/IoeTests.aspx.cs @@ -7,12 +7,15 @@ using Spring.Objects.Factory; public partial class IoeTests : System.Web.UI.Page { private IConversationState conversationA; + public IConversationState ConversationA { get { return conversationA; } set { conversationA = value; } } + private IConversationState conversationAA; + public IConversationState ConversationAA { get { return conversationAA; } @@ -20,6 +23,7 @@ public partial class IoeTests : System.Web.UI.Page } private IConversationManager conversationManager; + public IConversationManager ConversationManager { get { return conversationManager; } @@ -27,6 +31,7 @@ public partial class IoeTests : System.Web.UI.Page } private ISessionFactory sessionFactory; + public ISessionFactory SessionFactory { get { return sessionFactory; } @@ -349,7 +354,7 @@ public partial class IoeTests : System.Web.UI.Page } //END: NO Raise error } - + private void participatingHibernateNotAlowed() { Regex msgErrorRx = new Regex(".*Participating.*Hibernate.*NOT.*ALLOWED.*"); @@ -382,6 +387,7 @@ public partial class IoeTests : System.Web.UI.Page ISession session = this.SessionFactory.GetCurrentSession(); this.ConversationA.StartResumeConversation(); } + throw new Exception("NOT OK: No raise for 'this.ConversationA.StartResumeConversation()'"); } catch (InvalidOperationException ioe) @@ -400,7 +406,6 @@ public partial class IoeTests : System.Web.UI.Page this.ConversationManager.FreeEnded(); this.ConversationManager.PauseConversations(); } - } private void idIsDifferentFromSpringName() @@ -413,7 +418,7 @@ public partial class IoeTests : System.Web.UI.Page otherConversationState = new WebConversationSpringState(); otherConversationState.Id = "otherConversationState"; // different name - ((IObjectNameAware)otherConversationState).ObjectName = "different_name"; + ((IObjectNameAware) otherConversationState).ObjectName = "different_name"; throw new Exception("NOT OK: No raise for '((IObjectNameAware)otherConversationState).ObjectName ='"); } catch (InvalidOperationException ioe) @@ -440,7 +445,7 @@ public partial class IoeTests : System.Web.UI.Page otherConversationState.Id = "otherConversationState"; // make not new // different name - ((IObjectNameAware)otherConversationState).ObjectName = "otherConversationState"; + ((IObjectNameAware) otherConversationState).ObjectName = "otherConversationState"; this.Session["testResult"] = "OK"; } finally diff --git a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/PatialEndConv_A_B_Begin.aspx b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/PatialEndConv_A_B_Begin.aspx index 01d8ddd1..15761d65 100644 --- a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/PatialEndConv_A_B_Begin.aspx +++ b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/PatialEndConv_A_B_Begin.aspx @@ -1,3 +1,3 @@ <%@ Page Language="C#" AutoEventWireup="true" CodeFile="PatialEndConv_A_B_Begin.aspx.cs" Inherits="PatialEndConv_A_B_Begin" %><% -Response.Write("OK"); -%> \ No newline at end of file + Response.Write("OK"); + %> \ No newline at end of file diff --git a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/PatialEndConv_A_B_End.aspx b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/PatialEndConv_A_B_End.aspx index 1b017af5..7d4f9634 100644 --- a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/PatialEndConv_A_B_End.aspx +++ b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/PatialEndConv_A_B_End.aspx @@ -1,3 +1,3 @@ <%@ Page Language="C#" AutoEventWireup="true" CodeFile="PatialEndConv_A_B_End.aspx.cs" Inherits="PatialEndConv_A_B_End" %><% -Response.Write("OK"); -%> \ No newline at end of file + Response.Write("OK"); + %> \ No newline at end of file diff --git a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/PatialEndConv_A_Begin.aspx b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/PatialEndConv_A_Begin.aspx index 08e19b07..81a395f4 100644 --- a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/PatialEndConv_A_Begin.aspx +++ b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/PatialEndConv_A_Begin.aspx @@ -1,3 +1,3 @@ <%@ Page Language="C#" AutoEventWireup="true" CodeFile="PatialEndConv_A_Begin.aspx.cs" Inherits="PatialEndConv_A_Begin" %><% -Response.Write("OK"); -%> \ No newline at end of file + Response.Write("OK"); + %> \ No newline at end of file diff --git a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/PatialEndConv_A_End.aspx b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/PatialEndConv_A_End.aspx index 1a85836f..d04a2ced 100644 --- a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/PatialEndConv_A_End.aspx +++ b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/PatialEndConv_A_End.aspx @@ -1,3 +1,3 @@ <%@ Page Language="C#" AutoEventWireup="true" CodeFile="PatialEndConv_A_End.aspx.cs" Inherits="PatialEndConv_A_End" %><% -Response.Write("OK"); -%> \ No newline at end of file + Response.Write("OK"); + %> \ No newline at end of file diff --git a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/RedirectErrorNoPauseConversation.aspx b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/RedirectErrorNoPauseConversation.aspx index 73beaf72..0d78bbb5 100644 --- a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/RedirectErrorNoPauseConversation.aspx +++ b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/RedirectErrorNoPauseConversation.aspx @@ -1,3 +1,3 @@ <%@ Page Language="C#" AutoEventWireup="true" CodeFile="RedirectErrorNoPauseConversation.aspx.cs" Inherits="RedirectErrorNoPauseConversation" %><% -Response.Write("OK"); -%> \ No newline at end of file + Response.Write("OK"); + %> \ No newline at end of file diff --git a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/RedirectErrorNoPauseConversation.aspx.cs b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/RedirectErrorNoPauseConversation.aspx.cs index 16af48ad..7d299f98 100644 --- a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/RedirectErrorNoPauseConversation.aspx.cs +++ b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/RedirectErrorNoPauseConversation.aspx.cs @@ -1,10 +1,10 @@ using Spring.Web.Conversation; - using NHibernate; public partial class RedirectErrorNoPauseConversation : System.Web.UI.Page { private IConversationState conversation; + public IConversationState Conversation { get { return conversation; } @@ -17,6 +17,7 @@ public partial class RedirectErrorNoPauseConversation : System.Web.UI.Page { //nothing, only for obtain session cookie } + if (this.Request.Params["step"].Equals("step_01")) { this.Conversation.StartResumeConversation(); diff --git a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/SPCLazyLoadTest_A_Begin.aspx b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/SPCLazyLoadTest_A_Begin.aspx index 9d89725e..8dc896cd 100644 --- a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/SPCLazyLoadTest_A_Begin.aspx +++ b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/SPCLazyLoadTest_A_Begin.aspx @@ -1,3 +1,3 @@ <%@ Page Language="C#" AutoEventWireup="true" CodeFile="SPCLazyLoadTest_A_Begin.aspx.cs" Inherits="SPCLazyLoadTest_A_Begin" %><% -Response.Write("OK"); -%> \ No newline at end of file + Response.Write("OK"); + %> \ No newline at end of file diff --git a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/SPCLazyLoadTest_A_Begin.aspx.cs b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/SPCLazyLoadTest_A_Begin.aspx.cs index e50dae18..387f1707 100644 --- a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/SPCLazyLoadTest_A_Begin.aspx.cs +++ b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/SPCLazyLoadTest_A_Begin.aspx.cs @@ -5,17 +5,21 @@ using Spring.Entities; public partial class SPCLazyLoadTest_A_Begin : System.Web.UI.Page { private IConversationState conversation; + public IConversationState Conversation { get { return conversation; } set { conversation = value; } } + private ISessionFactory sessionFactory; + public ISessionFactory SessionFactory { get { return sessionFactory; } set { sessionFactory = value; } } + protected void Page_Load(object sender, EventArgs e) { if (this.Request["endConversation"] != null && bool.Parse(this.Request["endConversation"])) diff --git a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/SPCLazyLoadTest_A_Status.aspx b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/SPCLazyLoadTest_A_Status.aspx index 8f1e9f95..082ab325 100644 --- a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/SPCLazyLoadTest_A_Status.aspx +++ b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/SPCLazyLoadTest_A_Status.aspx @@ -1,3 +1,3 @@ <%@ Page Language="C#" AutoEventWireup="true" CodeFile="SPCLazyLoadTest_A_Status.aspx.cs" Inherits="SPCLazyLoadTest_A_Status" %><% -Response.Write("OK"); -%> \ No newline at end of file + Response.Write("OK"); + %> \ No newline at end of file diff --git a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/SPCLazyLoadTest_A_Status.aspx.cs b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/SPCLazyLoadTest_A_Status.aspx.cs index 1a7f56d7..efb7ab09 100644 --- a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/SPCLazyLoadTest_A_Status.aspx.cs +++ b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/SPCLazyLoadTest_A_Status.aspx.cs @@ -9,22 +9,25 @@ public partial class SPCLazyLoadTest_A_Status : System.Web.UI.Page private static readonly ILogger LOG = LogManager.GetLogger(); private IConversationState conversation; + public IConversationState Conversation { get { return conversation; } set { conversation = value; } } + protected void Page_Load(object sender, EventArgs e) { try { this.Conversation.StartResumeConversation(); - SPCMasterEnt sPCMasterEnt = (SPCMasterEnt)this.Session["sPCMasterEnt"]; + SPCMasterEnt sPCMasterEnt = (SPCMasterEnt) this.Session["sPCMasterEnt"]; foreach (SPCDetailEnt sPCDetailEntItem in sPCMasterEnt.SPCDetailEntList) { LOG.LogDebug(String.Format("Page_Load: sPCDetailEntItem.Description={0}", sPCDetailEntItem.Description)); } + this.Session["messageTest"] = "no lazy error"; } catch (LazyInitializationException lex) diff --git a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/SPCSwitchConversationSameRequest.aspx b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/SPCSwitchConversationSameRequest.aspx index d848cae5..180a7579 100644 --- a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/SPCSwitchConversationSameRequest.aspx +++ b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/SPCSwitchConversationSameRequest.aspx @@ -1,3 +1,3 @@ <%@ Page Language="C#" AutoEventWireup="true" CodeFile="SPCSwitchConversationSameRequest.aspx.cs" Inherits="SPCSwitchConversationSameRequest" %><% -Response.Write("OK"); -%> \ No newline at end of file + Response.Write("OK"); + %> \ No newline at end of file diff --git a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/SPCSwitchConversationSameRequest.aspx.cs b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/SPCSwitchConversationSameRequest.aspx.cs index b1d1a79f..cdfeb505 100644 --- a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/SPCSwitchConversationSameRequest.aspx.cs +++ b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/SPCSwitchConversationSameRequest.aspx.cs @@ -9,12 +9,15 @@ public partial class SPCSwitchConversationSameRequest : System.Web.UI.Page private static readonly ILogger LOG = LogManager.GetLogger(); private IConversationState conversationA; + public IConversationState ConversationA { get { return conversationA; } set { conversationA = value; } } + private IConversationState conversationB; + public IConversationState ConversationB { get { return conversationB; } @@ -22,6 +25,7 @@ public partial class SPCSwitchConversationSameRequest : System.Web.UI.Page } private ISessionFactory sessionFactory; + public ISessionFactory SessionFactory { get { return sessionFactory; } diff --git a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/SerializeConversationTest.aspx.cs b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/SerializeConversationTest.aspx.cs index ffad529e..6e5f5585 100644 --- a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/SerializeConversationTest.aspx.cs +++ b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/SerializeConversationTest.aspx.cs @@ -1,16 +1,15 @@ using System.Runtime.Serialization.Formatters.Binary; using Spring.Web.Conversation; - using NHibernate; using Spring.Entities; - /// /// Page for . /// public partial class SerializeConversationTest : System.Web.UI.Page { private IConversationState conversation; + /// /// /// @@ -41,7 +40,6 @@ public partial class SerializeConversationTest : System.Web.UI.Page bf.Serialize(ms, sessionContent); - if (this.Session["SPCDetailEnt#1"] == null) { //at the first time diff --git a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/SessionIsClosedA.aspx.cs b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/SessionIsClosedA.aspx.cs index d16c0dc5..a68bae68 100644 --- a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/SessionIsClosedA.aspx.cs +++ b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/SessionIsClosedA.aspx.cs @@ -5,6 +5,7 @@ using NHibernate; public partial class SessionIsClosedA : System.Web.UI.Page { private IConversationState conversation; + /// /// /// diff --git a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/SessionIsClosedB.aspx.cs b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/SessionIsClosedB.aspx.cs index 4c0bd77e..cd96669d 100644 --- a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/SessionIsClosedB.aspx.cs +++ b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/SessionIsClosedB.aspx.cs @@ -5,6 +5,7 @@ using NHibernate; public partial class SessionIsClosedB : System.Web.UI.Page { private IConversationState conversation; + /// /// /// @@ -15,6 +16,7 @@ public partial class SessionIsClosedB : System.Web.UI.Page } private IConversationState conversationA; + /// /// "convASessionIsClosed" /// @@ -35,9 +37,9 @@ public partial class SessionIsClosedB : System.Web.UI.Page this.Conversation.StartResumeConversation(); /* - * Producing the error "HibernateException: Session is closed..." This is because in - * "SessionPerConversationScope.LazySessionPerConversationHolder.CloseConversation(IConversationState)" - * we are closing the "SessionPerConversationScope.LazySessionPerConversationHolder.activeConversation" + * Producing the error "HibernateException: Session is closed..." This is because in + * "SessionPerConversationScope.LazySessionPerConversationHolder.CloseConversation(IConversationState)" + * we are closing the "SessionPerConversationScope.LazySessionPerConversationHolder.activeConversation" * instead of parameter "conversation" (BUG). */ this.ConversationA.EndConversation(); diff --git a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/TimeOut_NoTimeOut.aspx b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/TimeOut_NoTimeOut.aspx index 34b064c2..b744740a 100644 --- a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/TimeOut_NoTimeOut.aspx +++ b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/TimeOut_NoTimeOut.aspx @@ -1,3 +1,3 @@ <%@ Page Language="C#" AutoEventWireup="true" CodeFile="TimeOut_NoTimeOut.aspx.cs" Inherits="TimeOut_NoTimeOut" %><% -Response.Write("OK"); -%> \ No newline at end of file + Response.Write("OK"); + %> \ No newline at end of file diff --git a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/TimeOut_NoTimeOut.aspx.cs b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/TimeOut_NoTimeOut.aspx.cs index 5ffb879f..457f495c 100644 --- a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/TimeOut_NoTimeOut.aspx.cs +++ b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/TimeOut_NoTimeOut.aspx.cs @@ -3,11 +3,13 @@ using Spring.Web.Conversation; public partial class TimeOut_NoTimeOut : System.Web.UI.Page { private IConversationState conversation; + public IConversationState Conversation { get { return conversation; } set { conversation = value; } } + protected void Page_Load(object sender, EventArgs e) { this.Conversation.StartResumeConversation(); diff --git a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/TimeOut_WithTimeOut.aspx b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/TimeOut_WithTimeOut.aspx index dc7d4b69..b5eb3f85 100644 --- a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/TimeOut_WithTimeOut.aspx +++ b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/TimeOut_WithTimeOut.aspx @@ -1,3 +1,3 @@ <%@ Page Language="C#" AutoEventWireup="true" CodeFile="TimeOut_WithTimeOut.aspx.cs" Inherits="TimeOut_WithTimeOut" %><% -Response.Write("OK"); -%> \ No newline at end of file + Response.Write("OK"); + %> \ No newline at end of file diff --git a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/TimeOut_WithTimeOut.aspx.cs b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/TimeOut_WithTimeOut.aspx.cs index e7588cf3..f7ce7c16 100644 --- a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/TimeOut_WithTimeOut.aspx.cs +++ b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/TimeOut_WithTimeOut.aspx.cs @@ -3,6 +3,7 @@ using Spring.Web.Conversation; public partial class TimeOut_WithTimeOut : System.Web.UI.Page { private IConversationState conversation; + public IConversationState Conversation { get { return conversation; } diff --git a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/Web.Config b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/Web.Config index dbca6374..5b1c5eb8 100644 --- a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/Web.Config +++ b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/Web.Config @@ -1,99 +1,108 @@ - - -
-
- - -
- - - - - - - - - - + + +
+
+ + +
+ + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - + + + - - - - - - + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/log4net.config b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/log4net.config index c683e949..20ef64d4 100644 --- a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/log4net.config +++ b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/log4net.config @@ -24,18 +24,18 @@ + type="log4net.Appender.TraceAppender, log4net"> + value="%d{ABSOLUTE} %-5p %c{1}:%L - %m%n" /> + type="log4net.Appender.ConsoleAppender, log4net"> + value="%d{ABSOLUTE} %-5p %c{1}:%L - %m%n" /> @@ -47,7 +47,8 @@ - + @@ -59,7 +60,7 @@ - + diff --git a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/services.xml.config b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/services.xml.config index 28b492b8..48ae473c 100644 --- a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/services.xml.config +++ b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Data/Spring/Conversation/WebConversationStateTest/services.xml.config @@ -6,38 +6,49 @@ - + - + - + - + - + - + - + - + - + @@ -52,52 +63,68 @@ - + - - - + + + - + - + - - + + - + - + - + - + - + - + @@ -110,7 +137,9 @@ - + @@ -142,37 +171,43 @@ - + - + - - + + - + - + - - + + - + - - + + @@ -180,12 +215,14 @@ - + - - + + @@ -197,14 +234,18 @@ - + - - + + - + @@ -217,15 +258,20 @@ - + - + - + @@ -238,19 +284,23 @@ - + - - + + - + - - + + @@ -261,68 +311,80 @@ - + - - + + - + - - + + - - - + + + - - - + + + - + - - + + - - + + - + - + - - + + - - + + - - + + - + Spring.Web.Conversation.NHibernate5.Tests @@ -331,23 +393,26 @@ - - - + + + - - - - - - + + + + + + - - + + - - + + \ No newline at end of file diff --git a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Entities/SPCDetailEnt.cs b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Entities/SPCDetailEnt.cs index 9857ac29..9ceba846 100644 --- a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Entities/SPCDetailEnt.cs +++ b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Entities/SPCDetailEnt.cs @@ -20,35 +20,36 @@ using Spring.Web.Conversation; -namespace Spring.Entities -{ - /// - /// Detail Entity for 'session-per-conversation' tests: - /// , - /// - /// - /// Hailton de Castro - [Serializable] - public class SPCDetailEnt - { - private Int32? id; - /// - /// Entity key - /// - public virtual Int32? Id - { - get { return id; } - set { id = value; } - } +namespace Spring.Entities; - private String description; - /// - /// Description - /// - public virtual String Description - { - get { return description; } - set { description = value; } - } +/// +/// Detail Entity for 'session-per-conversation' tests: +/// , +/// +/// +/// Hailton de Castro +[Serializable] +public class SPCDetailEnt +{ + private Int32? id; + + /// + /// Entity key + /// + public virtual Int32? Id + { + get { return id; } + set { id = value; } + } + + private String description; + + /// + /// Description + /// + public virtual String Description + { + get { return description; } + set { description = value; } } } diff --git a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Entities/SPCDetailEnt.hbm.xml b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Entities/SPCDetailEnt.hbm.xml index c1348e59..c5012e78 100644 --- a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Entities/SPCDetailEnt.hbm.xml +++ b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Entities/SPCDetailEnt.hbm.xml @@ -1,9 +1,10 @@  - - - - - - - + + + + + + + diff --git a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Entities/SPCMasterEnt.cs b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Entities/SPCMasterEnt.cs index 0dc890f6..a4f0a4e4 100644 --- a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Entities/SPCMasterEnt.cs +++ b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Entities/SPCMasterEnt.cs @@ -20,45 +20,47 @@ using Spring.Web.Conversation; -namespace Spring.Entities +namespace Spring.Entities; + +/// +/// Master Entity for 'session-per-conversation' tests: +/// , +/// +/// +/// Hailton de Castro +[Serializable] +public class SPCMasterEnt { + private Int32? id; + /// - /// Master Entity for 'session-per-conversation' tests: - /// , - /// + /// Entity key /// - /// Hailton de Castro - [Serializable] - public class SPCMasterEnt + public virtual Int32? Id { - private Int32? id; - /// - /// Entity key - /// - public virtual Int32? Id - { - get { return id; } - set { id = value; } - } - - private String description; - /// - /// Description - /// - public virtual String Description - { - get { return description; } - set { description = value; } - } - - private IList sPCDetailEntList; - /// - /// one-to-many relationship. - /// - public virtual IList SPCDetailEntList - { - get { return sPCDetailEntList; } - set { sPCDetailEntList = value; } - } + get { return id; } + set { id = value; } } -} + + private String description; + + /// + /// Description + /// + public virtual String Description + { + get { return description; } + set { description = value; } + } + + private IList sPCDetailEntList; + + /// + /// one-to-many relationship. + /// + public virtual IList SPCDetailEntList + { + get { return sPCDetailEntList; } + set { sPCDetailEntList = value; } + } +} \ No newline at end of file diff --git a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Entities/SPCMasterEnt.hbm.xml b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Entities/SPCMasterEnt.hbm.xml index 3ae5b576..bf620efa 100644 --- a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Entities/SPCMasterEnt.hbm.xml +++ b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Entities/SPCMasterEnt.hbm.xml @@ -1,13 +1,14 @@  - - - - - - - - - - - + + + + + + + + + + + diff --git a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Spring/Data/Common/ConnectionCreationTrackingDbProvider.cs b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Spring/Data/Common/ConnectionCreationTrackingDbProvider.cs index 24a450fd..a27525a1 100644 --- a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Spring/Data/Common/ConnectionCreationTrackingDbProvider.cs +++ b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/Spring/Data/Common/ConnectionCreationTrackingDbProvider.cs @@ -21,26 +21,25 @@ using Spring.Data.Common; using System.Data; -namespace Spring.Spring.Data.Common +namespace Spring.Spring.Data.Common; + +/// +/// Count the number of calls to "CreateConnection()". +/// +public class ConnectionCreationTrackingDbProvider : DelegatingDbProvider { /// - /// Count the number of calls to "CreateConnection()". + /// Count of calls to /// - public class ConnectionCreationTrackingDbProvider : DelegatingDbProvider - { - /// - /// Count of calls to - /// - public static Int32 Count = 0; + public static Int32 Count = 0; - /// - /// Count. - /// - /// - public override IDbConnection CreateConnection() - { - Count++; - return this.TargetDbProvider.CreateConnection(); - } + /// + /// Count. + /// + /// + public override IDbConnection CreateConnection() + { + Count++; + return this.TargetDbProvider.CreateConnection(); } -} +} \ No newline at end of file diff --git a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/TestAssemblySetup.cs b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/TestAssemblySetup.cs index fefb1642..7eb9be54 100644 --- a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/TestAssemblySetup.cs +++ b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/TestAssemblySetup.cs @@ -1,20 +1,19 @@ using NUnit.Framework; -namespace Spring +namespace Spring; + +[SetUpFixture] +public class TestAssemblySetup { - [SetUpFixture] - public class TestAssemblySetup + [OneTimeSetUp] + public void SetUp() { - [OneTimeSetUp] - public void SetUp() + // work around getting interop assembly to correct directory + var requiredFile = Path.Combine(Environment.CurrentDirectory, "SQLite.Interop.dll"); + var fileToUse = Path.Combine(Environment.CurrentDirectory, "x86", "SQLite.Interop.dll"); + if (!File.Exists(requiredFile) && File.Exists(fileToUse)) { - // work around getting interop assembly to correct directory - var requiredFile = Path.Combine(Environment.CurrentDirectory, "SQLite.Interop.dll"); - var fileToUse = Path.Combine(Environment.CurrentDirectory, "x86", "SQLite.Interop.dll"); - if (!File.Exists(requiredFile) && File.Exists(fileToUse)) - { - File.Copy(fileToUse, requiredFile); - } + File.Copy(fileToUse, requiredFile); } } } diff --git a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/app.config b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/app.config index f57ca185..f63fd47e 100644 --- a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/app.config +++ b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/app.config @@ -1,11 +1,13 @@ - - - - - - - - + + + + + + + + diff --git a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/nhibernate-mapping.xsd b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/nhibernate-mapping.xsd index db25ca17..594d5763 100644 --- a/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/nhibernate-mapping.xsd +++ b/test/Spring/Spring.Web.Conversation.NHibernate5.Tests/nhibernate-mapping.xsd @@ -1,1695 +1,1699 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - A composite key may be modelled by a .NET class with a property for each key column. The class must be Serializable and override equals() and hashCode() - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Namespace used to find not-Fully Qualified Type Names - - - - - Assembly used to find not-Fully Qualified Type Names - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - undefined|any|none|null|0|-1|... - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - The concrete collection should use a generic version or an object-based version. - - - - - - - - - - - - - - Types of polymorphism - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + A composite key may be modelled by a .NET class with a property for each key column. The + class must be Serializable and override equals() and hashCode() + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Namespace used to find not-Fully Qualified Type Names + + + + + Assembly used to find not-Fully Qualified Type Names + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + undefined|any|none|null|0|-1|... + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The concrete collection should use a generic version or an object-based version. + + + + + + + + + + + + + + + Types of polymorphism + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/Spring/Spring.Web.Mvc5.Tests/ControllerFactoryTestExtension.cs b/test/Spring/Spring.Web.Mvc5.Tests/ControllerFactoryTestExtension.cs index 8b39b8fa..232a2a0a 100644 --- a/test/Spring/Spring.Web.Mvc5.Tests/ControllerFactoryTestExtension.cs +++ b/test/Spring/Spring.Web.Mvc5.Tests/ControllerFactoryTestExtension.cs @@ -21,32 +21,31 @@ using System.Web.Mvc; using System.Reflection; -namespace Spring.Web.Mvc.Tests +namespace Spring.Web.Mvc.Tests; + +public static class ControllerFactoryTestExtension { - public static class ControllerFactoryTestExtension + private static readonly PropertyInfo _typeCacheProperty; + private static readonly FieldInfo _cacheField; + + static ControllerFactoryTestExtension() { - private static readonly PropertyInfo _typeCacheProperty; - private static readonly FieldInfo _cacheField; - - static ControllerFactoryTestExtension() - { - _typeCacheProperty = typeof(DefaultControllerFactory).GetProperty("ControllerTypeCache", BindingFlags.Instance | BindingFlags.NonPublic); - _cacheField = _typeCacheProperty.PropertyType.GetField("_cache", BindingFlags.NonPublic | BindingFlags.Instance); - } - - /// - /// Replaces the cache field of a the DefaultControllerFactory's ControllerTypeCache. - /// This ensures that only the specified controller types will be searched when instantiating a controller. - /// As the ControllerTypeCache is internal, this uses some reflection hackery. - /// - public static void InitializeWithControllerTypes(this IControllerFactory factory, params Type[] controllerTypes) - { - var cache = controllerTypes - .GroupBy(t => t.Name.Substring(0, t.Name.Length - "Controller".Length), StringComparer.OrdinalIgnoreCase) - .ToDictionary(g => g.Key, g => g.ToLookup(t => t.Namespace ?? string.Empty, StringComparer.OrdinalIgnoreCase), StringComparer.OrdinalIgnoreCase); - - var buildManager = _typeCacheProperty.GetValue(factory, null); - _cacheField.SetValue(buildManager, cache); - } + _typeCacheProperty = typeof(DefaultControllerFactory).GetProperty("ControllerTypeCache", BindingFlags.Instance | BindingFlags.NonPublic); + _cacheField = _typeCacheProperty.PropertyType.GetField("_cache", BindingFlags.NonPublic | BindingFlags.Instance); } -} + + /// + /// Replaces the cache field of a the DefaultControllerFactory's ControllerTypeCache. + /// This ensures that only the specified controller types will be searched when instantiating a controller. + /// As the ControllerTypeCache is internal, this uses some reflection hackery. + /// + public static void InitializeWithControllerTypes(this IControllerFactory factory, params Type[] controllerTypes) + { + var cache = controllerTypes + .GroupBy(t => t.Name.Substring(0, t.Name.Length - "Controller".Length), StringComparer.OrdinalIgnoreCase) + .ToDictionary(g => g.Key, g => g.ToLookup(t => t.Namespace ?? string.Empty, StringComparer.OrdinalIgnoreCase), StringComparer.OrdinalIgnoreCase); + + var buildManager = _typeCacheProperty.GetValue(factory, null); + _cacheField.SetValue(buildManager, cache); + } +} \ No newline at end of file diff --git a/test/Spring/Spring.Web.Mvc5.Tests/Controllers/FirstContainerRegisteredController.cs b/test/Spring/Spring.Web.Mvc5.Tests/Controllers/FirstContainerRegisteredController.cs index 5b50e7cf..2cb346e1 100644 --- a/test/Spring/Spring.Web.Mvc5.Tests/Controllers/FirstContainerRegisteredController.cs +++ b/test/Spring/Spring.Web.Mvc5.Tests/Controllers/FirstContainerRegisteredController.cs @@ -20,10 +20,9 @@ using System.Web.Mvc; -namespace Spring.Web.Mvc.Tests.Controllers +namespace Spring.Web.Mvc.Tests.Controllers; + +public class FirstContainerRegisteredController : Controller { - public class FirstContainerRegisteredController : Controller - { - public string TestValue { get; set; } - } + public string TestValue { get; set; } } \ No newline at end of file diff --git a/test/Spring/Spring.Web.Mvc5.Tests/Controllers/NamedContextController.cs b/test/Spring/Spring.Web.Mvc5.Tests/Controllers/NamedContextController.cs index 35c482f7..6140e692 100644 --- a/test/Spring/Spring.Web.Mvc5.Tests/Controllers/NamedContextController.cs +++ b/test/Spring/Spring.Web.Mvc5.Tests/Controllers/NamedContextController.cs @@ -20,10 +20,8 @@ using System.Web.Mvc; -namespace Spring.Web.Mvc.Tests.Controllers -{ - public class NamedContextController : Controller - { +namespace Spring.Web.Mvc.Tests.Controllers; - } -} \ No newline at end of file +public class NamedContextController : Controller +{ +} diff --git a/test/Spring/Spring.Web.Mvc5.Tests/Controllers/NotInContainerController.cs b/test/Spring/Spring.Web.Mvc5.Tests/Controllers/NotInContainerController.cs index 0dabb2cb..e822a84f 100644 --- a/test/Spring/Spring.Web.Mvc5.Tests/Controllers/NotInContainerController.cs +++ b/test/Spring/Spring.Web.Mvc5.Tests/Controllers/NotInContainerController.cs @@ -20,10 +20,8 @@ using System.Web.Mvc; -namespace Spring.Web.Mvc.Tests.Controllers -{ - public class NotInContainerController : Controller - { +namespace Spring.Web.Mvc.Tests.Controllers; - } +public class NotInContainerController : Controller +{ } diff --git a/test/Spring/Spring.Web.Mvc5.Tests/Controllers/SecondContainerRegisteredController.cs b/test/Spring/Spring.Web.Mvc5.Tests/Controllers/SecondContainerRegisteredController.cs index c674ca39..4edbf428 100644 --- a/test/Spring/Spring.Web.Mvc5.Tests/Controllers/SecondContainerRegisteredController.cs +++ b/test/Spring/Spring.Web.Mvc5.Tests/Controllers/SecondContainerRegisteredController.cs @@ -20,10 +20,8 @@ using System.Web.Mvc; -namespace Spring.Web.Mvc.Tests.Controllers -{ - public class SecondContainerRegisteredController : Controller - { +namespace Spring.Web.Mvc.Tests.Controllers; - } +public class SecondContainerRegisteredController : Controller +{ } diff --git a/test/Spring/Spring.Web.Mvc5.Tests/SpringMvcDependencyResolverTests.cs b/test/Spring/Spring.Web.Mvc5.Tests/SpringMvcDependencyResolverTests.cs index 442bb090..b7185e4d 100644 --- a/test/Spring/Spring.Web.Mvc5.Tests/SpringMvcDependencyResolverTests.cs +++ b/test/Spring/Spring.Web.Mvc5.Tests/SpringMvcDependencyResolverTests.cs @@ -19,96 +19,93 @@ #endregion using System.Web.Mvc; - using NUnit.Framework; using Spring.Context.Support; using Spring.Web.Mvc.Tests.Controllers; -namespace Spring.Web.Mvc.Tests +namespace Spring.Web.Mvc.Tests; + +[TestFixture] +public class SpringMvcDependencyResolverTests { - [TestFixture] - public class SpringMvcDependencyResolverTests + #region Setup/Teardown + + [SetUp] + public void _TestSetup() { - #region Setup/Teardown + ContextRegistry.Clear(); + _context = new MvcApplicationContext("file://objectsMvc.xml"); + _mvcNamedContext = new MvcApplicationContext("named", false, "file://namedContextObjectsMvc.xml"); - [SetUp] - public void _TestSetup() + ContextRegistry.RegisterContext(_context); + ContextRegistry.RegisterContext(_mvcNamedContext); + + _resolver = new SpringMvcDependencyResolver(_context); + + _resolver.ApplicationContextName = string.Empty; + } + + #endregion + + private MvcApplicationContext _context; + private MvcApplicationContext _mvcNamedContext; + private SpringMvcDependencyResolver _resolver; + + [Test] + public void CanUseNamedContextToResolveType() + { + _resolver.ApplicationContextName = "named"; + var service = _resolver.GetService(typeof(NamedContextController)); + + Assert.NotNull(service); + } + + [Test] + public void CanUseUnnamedContextToResolveType() + { + Assume.That(_resolver.ApplicationContextName, Is.Empty, "Resolver should not have a named-context set for this test!"); + + var service = _resolver.GetService(); + Assert.NotNull(service); + } + + [Test] + public void RequestForNullTypeReturnsNull() + { + var service = _resolver.GetService(null); + Assert.That(service, Is.Null); + } + + [Test] + public void CanReturnCollectionOfTypes() + { + var services = _resolver.GetServices(); + Assert.That(services.Count(), Is.EqualTo(2)); + + foreach (var service in services) { - ContextRegistry.Clear(); - _context = new MvcApplicationContext("file://objectsMvc.xml"); - _mvcNamedContext = new MvcApplicationContext("named", false, "file://namedContextObjectsMvc.xml"); - - ContextRegistry.RegisterContext(_context); - ContextRegistry.RegisterContext(_mvcNamedContext); - - _resolver = new SpringMvcDependencyResolver(_context); - - _resolver.ApplicationContextName = string.Empty; + Assert.That(service, Is.TypeOf(typeof(FirstContainerRegisteredController)), "Service Returned was not of the expected Type."); } + } - #endregion + [Test] + public void RequestForSingleInstanceOfMultiplyRegisteredTypeReturnsFirstDefinition() + { + var service = _resolver.GetService(); + Assert.That(service.TestValue, Is.EqualTo("First Definition of Type")); + } - private MvcApplicationContext _context; - private MvcApplicationContext _mvcNamedContext; - private SpringMvcDependencyResolver _resolver; + [Test] + public void RequestForSingleUndefinedTypeReturnsNull() + { + var service = _resolver.GetService(); + Assert.That(service, Is.Null); + } - [Test] - public void CanUseNamedContextToResolveType() - { - _resolver.ApplicationContextName = "named"; - var service = _resolver.GetService(typeof (NamedContextController)); - - Assert.NotNull(service); - } - - [Test] - public void CanUseUnnamedContextToResolveType() - { - Assume.That(_resolver.ApplicationContextName, Is.Empty, "Resolver should not have a named-context set for this test!"); - - var service = _resolver.GetService(); - Assert.NotNull(service); - } - - [Test] - public void RequestForNullTypeReturnsNull() - { - var service = _resolver.GetService(null); - Assert.That(service, Is.Null); - } - - [Test] - public void CanReturnCollectionOfTypes() - { - var services = _resolver.GetServices(); - Assert.That(services.Count(), Is.EqualTo(2)); - - foreach (var service in services) - { - Assert.That(service, Is.TypeOf(typeof(FirstContainerRegisteredController)), "Service Returned was not of the expected Type."); - } - } - - [Test] - public void RequestForSingleInstanceOfMultiplyRegisteredTypeReturnsFirstDefinition() - { - var service = _resolver.GetService(); - Assert.That(service.TestValue, Is.EqualTo("First Definition of Type")); - } - - [Test] - public void RequestForSingleUndefinedTypeReturnsNull() - { - var service = _resolver.GetService(); - Assert.That(service, Is.Null); - } - - [Test] - public void RequestForCollectionOfUndefinedTypesReturnsEmptyCollection() - { - var services = _resolver.GetServices(); - Assert.That(services, Is.Empty); - } - + [Test] + public void RequestForCollectionOfUndefinedTypesReturnsEmptyCollection() + { + var services = _resolver.GetServices(); + Assert.That(services, Is.Empty); } } diff --git a/test/Spring/Spring.Web.Mvc5.Tests/namedContextObjectsMvc.xml b/test/Spring/Spring.Web.Mvc5.Tests/namedContextObjectsMvc.xml index bc6db784..8aa929ac 100644 --- a/test/Spring/Spring.Web.Mvc5.Tests/namedContextObjectsMvc.xml +++ b/test/Spring/Spring.Web.Mvc5.Tests/namedContextObjectsMvc.xml @@ -1,7 +1,8 @@ - + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.springframework.net http://www.springframework.net/xsd/spring-objects.xsd"> + diff --git a/test/Spring/Spring.Web.Mvc5.Tests/objectsMvc.xml b/test/Spring/Spring.Web.Mvc5.Tests/objectsMvc.xml index 54df1978..446861cb 100644 --- a/test/Spring/Spring.Web.Mvc5.Tests/objectsMvc.xml +++ b/test/Spring/Spring.Web.Mvc5.Tests/objectsMvc.xml @@ -1,19 +1,21 @@ - - - - - + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.springframework.net http://www.springframework.net/xsd/spring-objects.xsd"> + + + + + + + + + + + + - - - - - - - diff --git a/test/Spring/Spring.Web.Tests/Caching/AspNetCacheTests.cs b/test/Spring/Spring.Web.Tests/Caching/AspNetCacheTests.cs index a4fcf0b2..012d8e9e 100644 --- a/test/Spring/Spring.Web.Tests/Caching/AspNetCacheTests.cs +++ b/test/Spring/Spring.Web.Tests/Caching/AspNetCacheTests.cs @@ -21,170 +21,161 @@ using System.Collections; using System.Web; using System.Web.Caching; - using FakeItEasy; - using NUnit.Framework; -namespace Spring.Caching +namespace Spring.Caching; + +/// +/// Test AspNetCache behaviour. +/// +/// Erich Eichinger +[TestFixture] +public class AspNetCacheTests { - /// - /// Test AspNetCache behaviour. - /// - /// Erich Eichinger - [TestFixture] - public class AspNetCacheTests + private AspNetCache thisCache; + private AspNetCache otherCache; + private readonly Cache aspCache = HttpRuntime.Cache; + private readonly TimeSpan ttl10Seconds = new TimeSpan(0, 0, 10); + + AspNetCache.IRuntimeCache mockedRuntimeCache; + AspNetCache mockedCache; + + [SetUp] + public void SetUp() { - private AspNetCache thisCache; - private AspNetCache otherCache; - private readonly Cache aspCache = HttpRuntime.Cache; - private readonly TimeSpan ttl10Seconds = new TimeSpan(0, 0, 10); - - AspNetCache.IRuntimeCache mockedRuntimeCache; - AspNetCache mockedCache; - - [SetUp] - public void SetUp() + // cleanup underlying static asp.net cache + foreach (DictionaryEntry entry in HttpRuntime.Cache) { - // cleanup underlying static asp.net cache - foreach (DictionaryEntry entry in HttpRuntime.Cache) - { - aspCache.Remove((string)entry.Key); - } - - thisCache = new AspNetCache(); - otherCache = new AspNetCache(); - - mockedRuntimeCache = A.Fake(); - mockedCache = new AspNetCache(mockedRuntimeCache); + aspCache.Remove((string) entry.Key); } - [Test] - public void Get() - { - mockedCache.Get("key"); + thisCache = new AspNetCache(); + otherCache = new AspNetCache(); - A.CallTo(() => mockedRuntimeCache.Get(mockedCache.GenerateKey("key"))).MustHaveHappened(); - } + mockedRuntimeCache = A.Fake(); + mockedCache = new AspNetCache(mockedRuntimeCache); + } - [Test] - public void Remove() - { - mockedCache.Remove("key"); + [Test] + public void Get() + { + mockedCache.Get("key"); - A.CallTo(() => mockedRuntimeCache.Remove(mockedCache.GenerateKey("key"))).MustHaveHappened(); - } + A.CallTo(() => mockedRuntimeCache.Get(mockedCache.GenerateKey("key"))).MustHaveHappened(); + } - [Test] - public void DoesNotAcceptNullKeysOnInsert() - { - Assert.Throws(() => thisCache.Insert(null, "value", TimeSpan.Zero, true)); - } + [Test] + public void Remove() + { + mockedCache.Remove("key"); - [Test] - public void GetNullKeysReturnsNull() - { - Assert.IsNull(thisCache.Get(null)); - } + A.CallTo(() => mockedRuntimeCache.Remove(mockedCache.GenerateKey("key"))).MustHaveHappened(); + } - [Test] - public void IgnoreNullKeysOnRemove() - { - thisCache.Remove(null); - } + [Test] + public void DoesNotAcceptNullKeysOnInsert() + { + Assert.Throws(() => thisCache.Insert(null, "value", TimeSpan.Zero, true)); + } - [Test] - public void ReturnsOnlyKeysOwnedByCache() - { - DictionaryEntry[] mockedRuntimeCacheEntries = - { - new DictionaryEntry(mockedCache.GenerateKey("keyA"), null) - , new DictionaryEntry(mockedCache.GenerateKey("keyB"), null) - , new DictionaryEntry(thisCache.GenerateKey("keyC"), null) - , new DictionaryEntry(otherCache.GenerateKey("keyD"), null) - }; + [Test] + public void GetNullKeysReturnsNull() + { + Assert.IsNull(thisCache.Get(null)); + } - A.CallTo(() => mockedRuntimeCache.GetEnumerator()).Returns(mockedRuntimeCacheEntries.GetEnumerator()); + [Test] + public void IgnoreNullKeysOnRemove() + { + thisCache.Remove(null); + } - ICollection keys = mockedCache.Keys; - CollectionAssert.AreEqual(new string[] { "keyA", "keyB" }, keys); - } + [Test] + public void ReturnsOnlyKeysOwnedByCache() + { + DictionaryEntry[] mockedRuntimeCacheEntries = { new DictionaryEntry(mockedCache.GenerateKey("keyA"), null), new DictionaryEntry(mockedCache.GenerateKey("keyB"), null), new DictionaryEntry(thisCache.GenerateKey("keyC"), null), new DictionaryEntry(otherCache.GenerateKey("keyD"), null) }; - [Test] - public void AddItemToCacheNoExpiration() - { - thisCache.Insert( "key", "thisValue", TimeSpan.Zero, false ); - Assert.AreEqual(1, thisCache.Count); - Assert.AreEqual("thisValue", aspCache.Get(thisCache.GenerateKey("key"))); + A.CallTo(() => mockedRuntimeCache.GetEnumerator()).Returns(mockedRuntimeCacheEntries.GetEnumerator()); - otherCache.Insert("key", "otherValue", TimeSpan.Zero, false); - Assert.AreEqual(1, otherCache.Count); - Assert.AreEqual("otherValue", aspCache.Get(otherCache.GenerateKey("key"))); - } + ICollection keys = mockedCache.Keys; + CollectionAssert.AreEqual(new string[] { "keyA", "keyB" }, keys); + } - [Test] - public void AddItemToCacheAbsoluteExpiration() - { - thisCache.Insert("key", "thisValue", ttl10Seconds, false); - Assert.AreEqual(1, thisCache.Count); - Assert.AreEqual("thisValue", aspCache.Get(thisCache.GenerateKey("key"))); + [Test] + public void AddItemToCacheNoExpiration() + { + thisCache.Insert("key", "thisValue", TimeSpan.Zero, false); + Assert.AreEqual(1, thisCache.Count); + Assert.AreEqual("thisValue", aspCache.Get(thisCache.GenerateKey("key"))); - otherCache.Insert("key", "otherValue", ttl10Seconds, false); - Assert.AreEqual(1, otherCache.Count); - Assert.AreEqual("otherValue", aspCache.Get(otherCache.GenerateKey("key"))); - } + otherCache.Insert("key", "otherValue", TimeSpan.Zero, false); + Assert.AreEqual(1, otherCache.Count); + Assert.AreEqual("otherValue", aspCache.Get(otherCache.GenerateKey("key"))); + } - [Test] - public void AddItemToCacheSlidingExpiration() - { - thisCache.Insert("key", "thisValue", ttl10Seconds, true); - Assert.AreEqual(1, thisCache.Count); - Assert.AreEqual("thisValue", aspCache.Get(thisCache.GenerateKey("key"))); + [Test] + public void AddItemToCacheAbsoluteExpiration() + { + thisCache.Insert("key", "thisValue", ttl10Seconds, false); + Assert.AreEqual(1, thisCache.Count); + Assert.AreEqual("thisValue", aspCache.Get(thisCache.GenerateKey("key"))); - otherCache.Insert("key", "otherValue", ttl10Seconds, true); - Assert.AreEqual(1, otherCache.Count); - Assert.AreEqual("otherValue", aspCache.Get(otherCache.GenerateKey("key"))); - } + otherCache.Insert("key", "otherValue", ttl10Seconds, false); + Assert.AreEqual(1, otherCache.Count); + Assert.AreEqual("otherValue", aspCache.Get(otherCache.GenerateKey("key"))); + } - [Test] - public void DifferentCacheNamesCauseSameKeyToBeDifferent() - { - Assert.AreNotEqual("key", thisCache.GenerateKey("key")); - Assert.AreNotEqual(thisCache.GenerateKey("key"), otherCache.GenerateKey("key")); - } + [Test] + public void AddItemToCacheSlidingExpiration() + { + thisCache.Insert("key", "thisValue", ttl10Seconds, true); + Assert.AreEqual(1, thisCache.Count); + Assert.AreEqual("thisValue", aspCache.Get(thisCache.GenerateKey("key"))); - [Test] - public void PassesParametersToRuntimeCache() - { - AspNetCache.IRuntimeCache runtimeCache = A.Fake(); - AspNetCache cache = new AspNetCache(runtimeCache); + otherCache.Insert("key", "otherValue", ttl10Seconds, true); + Assert.AreEqual(1, otherCache.Count); + Assert.AreEqual("otherValue", aspCache.Get(otherCache.GenerateKey("key"))); + } - DateTime expectedAbsoluteExpiration = DateTime.Now; - TimeSpan expectedSlidingExpiration = ttl10Seconds; - CacheItemPriority expectedPriority = CacheItemPriority.Low; + [Test] + public void DifferentCacheNamesCauseSameKeyToBeDifferent() + { + Assert.AreNotEqual("key", thisCache.GenerateKey("key")); + Assert.AreNotEqual(thisCache.GenerateKey("key"), otherCache.GenerateKey("key")); + } + + [Test] + public void PassesParametersToRuntimeCache() + { + AspNetCache.IRuntimeCache runtimeCache = A.Fake(); + AspNetCache cache = new AspNetCache(runtimeCache); + + DateTime expectedAbsoluteExpiration = DateTime.Now; + TimeSpan expectedSlidingExpiration = ttl10Seconds; + CacheItemPriority expectedPriority = CacheItemPriority.Low; // TODO: find way to test non-sliding expiration case // runtimeCache.Insert(cache.GenerateKey("key"), "value", null, DateTime.Now.Add(ttl10Seconds), Cache.NoSlidingExpiration, expectedPriority, null); // cache.Insert( "key", "value", ttl10Seconds, false, expectedPriority ); - cache.Insert("key", "value", ttl10Seconds, true, expectedPriority); + cache.Insert("key", "value", ttl10Seconds, true, expectedPriority); - A.CallTo(() => runtimeCache.Insert(cache.GenerateKey("key"), "value", null, Cache.NoAbsoluteExpiration, ttl10Seconds, expectedPriority, null)).MustHaveHappened(); - } + A.CallTo(() => runtimeCache.Insert(cache.GenerateKey("key"), "value", null, Cache.NoAbsoluteExpiration, ttl10Seconds, expectedPriority, null)).MustHaveHappened(); + } - [Test] - public void ZeroTTLCausesNoExpiration() - { - AspNetCache.IRuntimeCache runtimeCache = A.Fake(); - AspNetCache cache = new AspNetCache(runtimeCache); + [Test] + public void ZeroTTLCausesNoExpiration() + { + AspNetCache.IRuntimeCache runtimeCache = A.Fake(); + AspNetCache cache = new AspNetCache(runtimeCache); - CacheItemPriority expectedPriority = CacheItemPriority.Low; + CacheItemPriority expectedPriority = CacheItemPriority.Low; - cache.Insert("key", "value", TimeSpan.Zero, true, expectedPriority); - A.CallTo(() => runtimeCache.Insert(cache.GenerateKey("key"), "value", null, Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, expectedPriority, null)).MustHaveHappened(); + cache.Insert("key", "value", TimeSpan.Zero, true, expectedPriority); + A.CallTo(() => runtimeCache.Insert(cache.GenerateKey("key"), "value", null, Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, expectedPriority, null)).MustHaveHappened(); - cache.Insert("key", "value", TimeSpan.Zero, false, expectedPriority); - A.CallTo(() => runtimeCache.Insert(cache.GenerateKey("key"), "value", null, Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, expectedPriority, null)).MustHaveHappened(); - } + cache.Insert("key", "value", TimeSpan.Zero, false, expectedPriority); + A.CallTo(() => runtimeCache.Insert(cache.GenerateKey("key"), "value", null, Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, expectedPriority, null)).MustHaveHappened(); } } diff --git a/test/Spring/Spring.Web.Tests/Context/Support/HttpApplicationConfigurerMergablePropertiesTests.xml b/test/Spring/Spring.Web.Tests/Context/Support/HttpApplicationConfigurerMergablePropertiesTests.xml index d70df103..f1aca0b0 100644 --- a/test/Spring/Spring.Web.Tests/Context/Support/HttpApplicationConfigurerMergablePropertiesTests.xml +++ b/test/Spring/Spring.Web.Tests/Context/Support/HttpApplicationConfigurerMergablePropertiesTests.xml @@ -7,38 +7,38 @@ http://www.springframework.net/database http://www.springframework.net/schema/db/spring-database-1.1.xsd http://www.springframework.net/tx http://www.springframework.net/schema/tx/spring-tx-1.1.xsd"> - - - - GrandParentValue1 - - - + + + + GrandParentValue1 + + + - - - - ParentValue1 - ParentValue2 - ParentValue3 - ParentValue4 - - - + + + + ParentValue1 + ParentValue2 + ParentValue3 + ParentValue4 + + + - - - - - - - - MergedValueToFind - - - - - - - + + + + + + + + MergedValueToFind + + + + + + + diff --git a/test/Spring/Spring.Web.Tests/Context/Support/HttpApplicationConfigurerTests.cs b/test/Spring/Spring.Web.Tests/Context/Support/HttpApplicationConfigurerTests.cs index e9eed3c0..7a091eb0 100644 --- a/test/Spring/Spring.Web.Tests/Context/Support/HttpApplicationConfigurerTests.cs +++ b/test/Spring/Spring.Web.Tests/Context/Support/HttpApplicationConfigurerTests.cs @@ -30,287 +30,272 @@ using Spring.Objects.Factory.Xml; #endregion -namespace Spring.Context.Support +namespace Spring.Context.Support; + +/// +/// +/// +/// Erich Eichinger +[TestFixture] +public class HttpApplicationConfigurerTests { - /// - /// - /// - /// Erich Eichinger - [TestFixture] - public class HttpApplicationConfigurerTests + [SetUp] + public void SetUp() { - [SetUp] - public void SetUp() - { - HttpApplicationConfigurer h1 = new HttpApplicationConfigurer(); - h1.ApplicationTemplate = null; - h1.ModuleTemplates.Clear(); - } - - /// - /// All instances share the same underlying ApplicationTemplate - /// - [Test] - public void ShareApplicationTemplate() - { - RootObjectDefinition rod = new RootObjectDefinition(); - - HttpApplicationConfigurer h1 = new HttpApplicationConfigurer(); - h1.ApplicationTemplate = rod; - Assert.AreEqual(rod, h1.ApplicationTemplate); - - // h2 returns same template as h1 - HttpApplicationConfigurer h2 = new HttpApplicationConfigurer(); - Assert.AreEqual(rod, h2.ApplicationTemplate); - Assert.AreEqual(h2.ApplicationTemplate, h1.ApplicationTemplate); - - // allows overriding - rod = new RootObjectDefinition(); - h2.ApplicationTemplate = rod; - Assert.AreEqual(rod, h1.ApplicationTemplate); - } - - /// - /// All instances share the same underlying ModuleTemplates table - /// - [Test] - public void ShareModuleTemplates() - { - // is never null - HttpApplicationConfigurer h1; - HttpApplicationConfigurer h2; - RootObjectDefinition rod; - - // is shared - h1 = new HttpApplicationConfigurer(); - Assert.IsNotNull(h1.ModuleTemplates); - h2 = new HttpApplicationConfigurer(); - Assert.AreEqual(h1.ModuleTemplates, h2.ModuleTemplates); - - // allows overriding - rod = new RootObjectDefinition(); - h1.ModuleTemplates.Add("test", rod); - Assert.AreEqual(rod, h1.ModuleTemplates["test"]); - h2.ModuleTemplates.Add("test", rod); - Assert.AreEqual(1, h2.ModuleTemplates.Count); - Assert.AreEqual(rod, h2.ModuleTemplates["test"]); - } - - [Test] - public void ConfiguresApplicationAndModulesFromTemplate() - { - StaticApplicationContext appContext = CreateTestContext(); - - HttpApplicationConfigurer h; - RootObjectDefinition rod; - - h = new HttpApplicationConfigurer(); - rod = new RootObjectDefinition(); - rod.PropertyValues.Add("TestObject", new RuntimeObjectReference("testObject")); - h.ApplicationTemplate = rod; - rod = new RootObjectDefinition(); - rod.PropertyValues.Add("TestObject", new RuntimeObjectReference("testObject1")); - h.ModuleTemplates.Add("TestModule1", rod); - rod = new RootObjectDefinition(); - rod.PropertyValues.Add("TestObject", new RuntimeObjectReference("testObject2")); - h.ModuleTemplates.Add("TestModule2", rod); - - TestModule m1 = new TestModule(); - TestModule m2 = new TestModule(); - - TestApplication appObject = new TestApplication(new ModuleEntry[] - { - new ModuleEntry("TestModule1", m1) - , new ModuleEntry("TestModule2", m2), - }); - HttpApplicationConfigurer.Configure(appContext, appObject); - // app configured - Assert.AreEqual(appContext.GetObject("testObject"), appObject.TestObject); - // modules configured - Assert.AreEqual(appContext.GetObject("testObject1"), m1.TestObject); - Assert.AreEqual(appContext.GetObject("testObject2"), m2.TestObject); - } - - [Test] - public void ThrowsOnUnapplicableModuleTemplate() - { - StaticApplicationContext appContext = CreateTestContext(); - - HttpApplicationConfigurer h; - RootObjectDefinition rod; - - h = new HttpApplicationConfigurer(); - rod = new RootObjectDefinition(); - rod.PropertyValues.Add("TestObject", new RuntimeObjectReference("testObject1")); - h.ModuleTemplates.Add("TestModule1", rod); - - TestApplication appObject = new TestApplication(null); - Assert.Throws(() => HttpApplicationConfigurer.Configure(appContext, appObject)); - } - - //////////////////////////////////////////////////// - - public class GrandParentHttpModule : IHttpModule - { - - private string[] _grandParentProperty; - public string[] GrandParentProperty - { - get { return _grandParentProperty; } - set - { - _grandParentProperty = value; - } - } - - - public void Dispose() - { - - } - - public void Init(HttpApplication context) - { - - } - } - - public class ParentHttpModule : GrandParentHttpModule - { - private string[] _parentProperty; - public string[] ParentProperty - { - get { return _parentProperty; } - set - { - _parentProperty = value; - } - } - - } - - [Test] - public void ConfigureUsingXmlApplicationContext_CanMergePropertyValues() - { - XmlApplicationContext appContext = new XmlApplicationContext(false, ReadOnlyXmlTestResource.GetFilePath("HttpApplicationConfigurerMergablePropertiesTests.xml", typeof(HttpApplicationConfigurerTests))); - - ParentHttpModule module = new ParentHttpModule(); - - TestApplication appObject = new TestApplication(new ModuleEntry[] - { - new ModuleEntry("DirectoryServicesAuthentication", module) - }); - HttpApplicationConfigurer.Configure(appContext, appObject); - - //base class property has carried through successfully - Assert.Contains("GrandParentValue1", module.GrandParentProperty); - - //parent property values remain in the final instance - Assert.Contains("ParentValue1", module.ParentProperty); - Assert.Contains("ParentValue2", module.ParentProperty); - Assert.Contains("ParentValue3", module.ParentProperty); - Assert.Contains("ParentValue4", module.ParentProperty); - - //the new additional value has been merged into the property - Assert.Contains("MergedValueToFind", module.ParentProperty); - } - - [Test] - public void ConfigureUsingXmlApplicationContext() - { - XmlApplicationContext appContext = new XmlApplicationContext(false, ReadOnlyXmlTestResource.GetFilePath("HttpApplicationConfigurerTests.xml", typeof(HttpApplicationConfigurerTests))); - - TestModule m1 = new TestModule(); - TestModule m2 = new TestModule(); - - TestApplication appObject = new TestApplication(new ModuleEntry[] - { - new ModuleEntry("TestModule1", m1) - , new ModuleEntry("TestModule2", m2), - }); - HttpApplicationConfigurer.Configure(appContext, appObject); - // app configured - Assert.AreEqual(appContext.GetObject("testObject"), appObject.TestObject); - // modules configured - Assert.AreEqual(appContext.GetObject("testObject1"), m1.TestObject); - Assert.AreEqual(null, m2.TestObject); - } - - private static StaticApplicationContext CreateTestContext() - { - object testObject; - StaticApplicationContext appContext = new StaticApplicationContext(); - appContext.RegisterSingleton("testObject", typeof(object), null); - appContext.RegisterSingleton("testObject1", typeof(object), null); - appContext.RegisterSingleton("testObject2", typeof(object), null); - appContext.Refresh(); - testObject = appContext.GetObject("testObject"); - Assert.IsNotNull(testObject); - return appContext; - } - - #region Test Classes - - public class ModuleEntry - { - // Fields - public readonly string Name; - public readonly IHttpModule Module; - - public ModuleEntry(string name, IHttpModule module) - { - Name = name; - Module = module; - } - } - - public class TestApplication : HttpApplication - { - private static readonly MethodInfo miAddModule = - typeof(HttpModuleCollection).GetMethod("AddModule", BindingFlags.Instance | BindingFlags.NonPublic); - - private object testObject; - - public TestApplication(ModuleEntry[] testModule) - { - HttpModuleCollection modules = this.Modules; - if (testModule != null) - { - ModuleEntry moduleEntry = null; - for (int i = 0; i < testModule.Length; i++) - { - moduleEntry = testModule[i]; - miAddModule.Invoke(modules, new object[] { moduleEntry.Name, moduleEntry.Module }); - } - } - } - - public object TestObject - { - get { return this.testObject; } - set { this.testObject = value; } - } - } - - public class TestModule : IHttpModule - { - private object testObject; - - public object TestObject - { - get { return this.testObject; } - set { this.testObject = value; } - } - - public void Init(HttpApplication context) - { - } - - public void Dispose() - { - } - } - - #endregion + HttpApplicationConfigurer h1 = new HttpApplicationConfigurer(); + h1.ApplicationTemplate = null; + h1.ModuleTemplates.Clear(); } + + /// + /// All instances share the same underlying ApplicationTemplate + /// + [Test] + public void ShareApplicationTemplate() + { + RootObjectDefinition rod = new RootObjectDefinition(); + + HttpApplicationConfigurer h1 = new HttpApplicationConfigurer(); + h1.ApplicationTemplate = rod; + Assert.AreEqual(rod, h1.ApplicationTemplate); + + // h2 returns same template as h1 + HttpApplicationConfigurer h2 = new HttpApplicationConfigurer(); + Assert.AreEqual(rod, h2.ApplicationTemplate); + Assert.AreEqual(h2.ApplicationTemplate, h1.ApplicationTemplate); + + // allows overriding + rod = new RootObjectDefinition(); + h2.ApplicationTemplate = rod; + Assert.AreEqual(rod, h1.ApplicationTemplate); + } + + /// + /// All instances share the same underlying ModuleTemplates table + /// + [Test] + public void ShareModuleTemplates() + { + // is never null + HttpApplicationConfigurer h1; + HttpApplicationConfigurer h2; + RootObjectDefinition rod; + + // is shared + h1 = new HttpApplicationConfigurer(); + Assert.IsNotNull(h1.ModuleTemplates); + h2 = new HttpApplicationConfigurer(); + Assert.AreEqual(h1.ModuleTemplates, h2.ModuleTemplates); + + // allows overriding + rod = new RootObjectDefinition(); + h1.ModuleTemplates.Add("test", rod); + Assert.AreEqual(rod, h1.ModuleTemplates["test"]); + h2.ModuleTemplates.Add("test", rod); + Assert.AreEqual(1, h2.ModuleTemplates.Count); + Assert.AreEqual(rod, h2.ModuleTemplates["test"]); + } + + [Test] + public void ConfiguresApplicationAndModulesFromTemplate() + { + StaticApplicationContext appContext = CreateTestContext(); + + HttpApplicationConfigurer h; + RootObjectDefinition rod; + + h = new HttpApplicationConfigurer(); + rod = new RootObjectDefinition(); + rod.PropertyValues.Add("TestObject", new RuntimeObjectReference("testObject")); + h.ApplicationTemplate = rod; + rod = new RootObjectDefinition(); + rod.PropertyValues.Add("TestObject", new RuntimeObjectReference("testObject1")); + h.ModuleTemplates.Add("TestModule1", rod); + rod = new RootObjectDefinition(); + rod.PropertyValues.Add("TestObject", new RuntimeObjectReference("testObject2")); + h.ModuleTemplates.Add("TestModule2", rod); + + TestModule m1 = new TestModule(); + TestModule m2 = new TestModule(); + + TestApplication appObject = new TestApplication(new ModuleEntry[] { new ModuleEntry("TestModule1", m1), new ModuleEntry("TestModule2", m2), }); + HttpApplicationConfigurer.Configure(appContext, appObject); + // app configured + Assert.AreEqual(appContext.GetObject("testObject"), appObject.TestObject); + // modules configured + Assert.AreEqual(appContext.GetObject("testObject1"), m1.TestObject); + Assert.AreEqual(appContext.GetObject("testObject2"), m2.TestObject); + } + + [Test] + public void ThrowsOnUnapplicableModuleTemplate() + { + StaticApplicationContext appContext = CreateTestContext(); + + HttpApplicationConfigurer h; + RootObjectDefinition rod; + + h = new HttpApplicationConfigurer(); + rod = new RootObjectDefinition(); + rod.PropertyValues.Add("TestObject", new RuntimeObjectReference("testObject1")); + h.ModuleTemplates.Add("TestModule1", rod); + + TestApplication appObject = new TestApplication(null); + Assert.Throws(() => HttpApplicationConfigurer.Configure(appContext, appObject)); + } + + //////////////////////////////////////////////////// + + public class GrandParentHttpModule : IHttpModule + { + private string[] _grandParentProperty; + + public string[] GrandParentProperty + { + get { return _grandParentProperty; } + set + { + _grandParentProperty = value; + } + } + + public void Dispose() + { + } + + public void Init(HttpApplication context) + { + } + } + + public class ParentHttpModule : GrandParentHttpModule + { + private string[] _parentProperty; + + public string[] ParentProperty + { + get { return _parentProperty; } + set + { + _parentProperty = value; + } + } + } + + [Test] + public void ConfigureUsingXmlApplicationContext_CanMergePropertyValues() + { + XmlApplicationContext appContext = new XmlApplicationContext(false, ReadOnlyXmlTestResource.GetFilePath("HttpApplicationConfigurerMergablePropertiesTests.xml", typeof(HttpApplicationConfigurerTests))); + + ParentHttpModule module = new ParentHttpModule(); + + TestApplication appObject = new TestApplication(new ModuleEntry[] { new ModuleEntry("DirectoryServicesAuthentication", module) }); + HttpApplicationConfigurer.Configure(appContext, appObject); + + //base class property has carried through successfully + Assert.Contains("GrandParentValue1", module.GrandParentProperty); + + //parent property values remain in the final instance + Assert.Contains("ParentValue1", module.ParentProperty); + Assert.Contains("ParentValue2", module.ParentProperty); + Assert.Contains("ParentValue3", module.ParentProperty); + Assert.Contains("ParentValue4", module.ParentProperty); + + //the new additional value has been merged into the property + Assert.Contains("MergedValueToFind", module.ParentProperty); + } + + [Test] + public void ConfigureUsingXmlApplicationContext() + { + XmlApplicationContext appContext = new XmlApplicationContext(false, ReadOnlyXmlTestResource.GetFilePath("HttpApplicationConfigurerTests.xml", typeof(HttpApplicationConfigurerTests))); + + TestModule m1 = new TestModule(); + TestModule m2 = new TestModule(); + + TestApplication appObject = new TestApplication(new ModuleEntry[] { new ModuleEntry("TestModule1", m1), new ModuleEntry("TestModule2", m2), }); + HttpApplicationConfigurer.Configure(appContext, appObject); + // app configured + Assert.AreEqual(appContext.GetObject("testObject"), appObject.TestObject); + // modules configured + Assert.AreEqual(appContext.GetObject("testObject1"), m1.TestObject); + Assert.AreEqual(null, m2.TestObject); + } + + private static StaticApplicationContext CreateTestContext() + { + object testObject; + StaticApplicationContext appContext = new StaticApplicationContext(); + appContext.RegisterSingleton("testObject", typeof(object), null); + appContext.RegisterSingleton("testObject1", typeof(object), null); + appContext.RegisterSingleton("testObject2", typeof(object), null); + appContext.Refresh(); + testObject = appContext.GetObject("testObject"); + Assert.IsNotNull(testObject); + return appContext; + } + + #region Test Classes + + public class ModuleEntry + { + // Fields + public readonly string Name; + public readonly IHttpModule Module; + + public ModuleEntry(string name, IHttpModule module) + { + Name = name; + Module = module; + } + } + + public class TestApplication : HttpApplication + { + private static readonly MethodInfo miAddModule = + typeof(HttpModuleCollection).GetMethod("AddModule", BindingFlags.Instance | BindingFlags.NonPublic); + + private object testObject; + + public TestApplication(ModuleEntry[] testModule) + { + HttpModuleCollection modules = this.Modules; + if (testModule != null) + { + ModuleEntry moduleEntry = null; + for (int i = 0; i < testModule.Length; i++) + { + moduleEntry = testModule[i]; + miAddModule.Invoke(modules, new object[] { moduleEntry.Name, moduleEntry.Module }); + } + } + } + + public object TestObject + { + get { return this.testObject; } + set { this.testObject = value; } + } + } + + public class TestModule : IHttpModule + { + private object testObject; + + public object TestObject + { + get { return this.testObject; } + set { this.testObject = value; } + } + + public void Init(HttpApplication context) + { + } + + public void Dispose() + { + } + } + + #endregion } diff --git a/test/Spring/Spring.Web.Tests/Context/Support/HttpApplicationConfigurerTests.xml b/test/Spring/Spring.Web.Tests/Context/Support/HttpApplicationConfigurerTests.xml index 8f62ca34..01f45185 100644 --- a/test/Spring/Spring.Web.Tests/Context/Support/HttpApplicationConfigurerTests.xml +++ b/test/Spring/Spring.Web.Tests/Context/Support/HttpApplicationConfigurerTests.xml @@ -1,26 +1,26 @@  - - + + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/Spring/Spring.Web.Tests/Context/Support/WebApplicationContextArgsTests.cs b/test/Spring/Spring.Web.Tests/Context/Support/WebApplicationContextArgsTests.cs index 7395eb54..6a11383f 100644 --- a/test/Spring/Spring.Web.Tests/Context/Support/WebApplicationContextArgsTests.cs +++ b/test/Spring/Spring.Web.Tests/Context/Support/WebApplicationContextArgsTests.cs @@ -1,15 +1,14 @@ using NUnit.Framework; -namespace Spring.Context.Support +namespace Spring.Context.Support; + +[TestFixture] +public class WebApplicationContextArgsTests { - [TestFixture] - public class WebApplicationContextArgsTests + [Test] + public void Default_CaseSensitivity_isFalse() { - [Test] - public void Default_CaseSensitivity_isFalse() - { - WebApplicationContextArgs args = new WebApplicationContextArgs(string.Empty, null, null, null); - Assert.False(args.CaseSensitive); - } + WebApplicationContextArgs args = new WebApplicationContextArgs(string.Empty, null, null, null); + Assert.False(args.CaseSensitive); } } diff --git a/test/Spring/Spring.Web.Tests/Context/Support/WebApplicationContextTests.cs b/test/Spring/Spring.Web.Tests/Context/Support/WebApplicationContextTests.cs index 98af12b6..86d6268c 100644 --- a/test/Spring/Spring.Web.Tests/Context/Support/WebApplicationContextTests.cs +++ b/test/Spring/Spring.Web.Tests/Context/Support/WebApplicationContextTests.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -28,66 +28,70 @@ using Spring.Threading; #endregion -namespace Spring.Context.Support +namespace Spring.Context.Support; + +/// +/// +/// +/// Erich Eichinger +[TestFixture] +public class WebApplicationContextTests : WebFormTestCase { - /// - /// - /// - /// Erich Eichinger - [TestFixture] - public class WebApplicationContextTests : WebFormTestCase + public WebApplicationContextTests() + : base("/Test", "/Spring/Context/Support/WebApplicationContextTests/") { - public WebApplicationContextTests() - : base("/Test", "/Spring/Context/Support/WebApplicationContextTests/") - {} - - [Test] - public void CanAccessContextFromNonWebThread() - { - Host.Execute(new TestAction(CanAccessContextFromNonWebThreadImpl)); - } - - public static void CanAccessContextFromNonWebThreadImpl() - { - IApplicationContext ctx; - - ctx = WebApplicationContext.GetRootContext(); - - AsyncTestMethod testMethod = new AsyncTestMethod(1, new AsyncTestMethod.TestMethod(DoBackgroundWork), ctx); - testMethod.Start(); - testMethod.AssertNoException(); - } - - private static object DoBackgroundWork(object[] args) - { - IApplicationContext ctx = (IApplicationContext) args[0]; - - object o; - o = ctx.GetObject("singletonObject"); Assert.IsNotNull(o); - o = ctx.GetObject("prototypeObject"); Assert.IsNotNull(o); - o = ctx.GetObject("applicationScopedObject"); Assert.IsNotNull(o); - try - { - o = ctx.GetObject("requestScopedObject"); Assert.IsNotNull(o); - Assert.Fail("shouldn't be allowed"); - } - catch(ObjectCreationException oce1) - { - Assert.IsTrue(-1 < oce1.Message.IndexOf("'request' scoped web singleton object 'requestScopedObject' requires a valid Request")); - } - - try - { - o = ctx.GetObject("sessionScopedObject"); Assert.IsNotNull(o); - Assert.Fail("shouldn't be allowed"); - } - catch (ObjectCreationException oce1) - { - Assert.IsTrue(-1 < oce1.Message.IndexOf("'session' scoped web singleton object 'sessionScopedObject' requires a valid Session")); - } - - return null; - } - } -} \ No newline at end of file + + [Test] + public void CanAccessContextFromNonWebThread() + { + Host.Execute(new TestAction(CanAccessContextFromNonWebThreadImpl)); + } + + public static void CanAccessContextFromNonWebThreadImpl() + { + IApplicationContext ctx; + + ctx = WebApplicationContext.GetRootContext(); + + AsyncTestMethod testMethod = new AsyncTestMethod(1, new AsyncTestMethod.TestMethod(DoBackgroundWork), ctx); + testMethod.Start(); + testMethod.AssertNoException(); + } + + private static object DoBackgroundWork(object[] args) + { + IApplicationContext ctx = (IApplicationContext) args[0]; + + object o; + o = ctx.GetObject("singletonObject"); + Assert.IsNotNull(o); + o = ctx.GetObject("prototypeObject"); + Assert.IsNotNull(o); + o = ctx.GetObject("applicationScopedObject"); + Assert.IsNotNull(o); + try + { + o = ctx.GetObject("requestScopedObject"); + Assert.IsNotNull(o); + Assert.Fail("shouldn't be allowed"); + } + catch (ObjectCreationException oce1) + { + Assert.IsTrue(-1 < oce1.Message.IndexOf("'request' scoped web singleton object 'requestScopedObject' requires a valid Request")); + } + + try + { + o = ctx.GetObject("sessionScopedObject"); + Assert.IsNotNull(o); + Assert.Fail("shouldn't be allowed"); + } + catch (ObjectCreationException oce1) + { + Assert.IsTrue(-1 < oce1.Message.IndexOf("'session' scoped web singleton object 'sessionScopedObject' requires a valid Session")); + } + + return null; + } +} diff --git a/test/Spring/Spring.Web.Tests/Context/Support/WebContextHandlerTests.cs b/test/Spring/Spring.Web.Tests/Context/Support/WebContextHandlerTests.cs index c7707d97..cdb5d371 100644 --- a/test/Spring/Spring.Web.Tests/Context/Support/WebContextHandlerTests.cs +++ b/test/Spring/Spring.Web.Tests/Context/Support/WebContextHandlerTests.cs @@ -25,45 +25,42 @@ using NUnit.Framework; #endregion +namespace Spring.Context.Support; - -namespace Spring.Context.Support +public class WebContextHandlerTests { - public class WebContextHandlerTests + [SetUp] + public void SetUp() { - [SetUp] - public void SetUp() - { - ContextRegistry.Clear(); - } + ContextRegistry.Clear(); + } - [TearDown] - public void TearDown() - { - ContextRegistry.Clear(); - } + [TearDown] + public void TearDown() + { + ContextRegistry.Clear(); + } - [Test] - public void should_return_registered_context_with_ContextRegistry() - { - const string xmlData = - @" + [Test] + public void should_return_registered_context_with_ContextRegistry() + { + const string xmlData = + @" "; - GenericApplicationContext expectedContext = new GenericApplicationContext(null, false, null); - ContextRegistry.RegisterContext(expectedContext); - WebContextHandler webContextHandler = new WebContextHandler(); - - Object actualContext = webContextHandler.Create(null, null, CreateConfigurationElement(xmlData)); + GenericApplicationContext expectedContext = new GenericApplicationContext(null, false, null); + ContextRegistry.RegisterContext(expectedContext); + WebContextHandler webContextHandler = new WebContextHandler(); - Assert.AreSame(expectedContext, actualContext); - } + Object actualContext = webContextHandler.Create(null, null, CreateConfigurationElement(xmlData)); - private XmlNode CreateConfigurationElement(string xmlData) - { - XmlDocument xmlDoc = new XmlDocument(); - xmlDoc.Load(new StringReader(xmlData)); - return xmlDoc.DocumentElement; - } + Assert.AreSame(expectedContext, actualContext); + } + + private XmlNode CreateConfigurationElement(string xmlData) + { + XmlDocument xmlDoc = new XmlDocument(); + xmlDoc.Load(new StringReader(xmlData)); + return xmlDoc.DocumentElement; } } diff --git a/test/Spring/Spring.Web.Tests/Context/Support/WebContextHandlerTests.xml b/test/Spring/Spring.Web.Tests/Context/Support/WebContextHandlerTests.xml index e0045462..3581a02b 100644 --- a/test/Spring/Spring.Web.Tests/Context/Support/WebContextHandlerTests.xml +++ b/test/Spring/Spring.Web.Tests/Context/Support/WebContextHandlerTests.xml @@ -1,7 +1,7 @@  - + \ No newline at end of file diff --git a/test/Spring/Spring.Web.Tests/Core/IO/WebResourceTests.cs b/test/Spring/Spring.Web.Tests/Core/IO/WebResourceTests.cs index bbd07005..3fda200b 100644 --- a/test/Spring/Spring.Web.Tests/Core/IO/WebResourceTests.cs +++ b/test/Spring/Spring.Web.Tests/Core/IO/WebResourceTests.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -25,32 +25,31 @@ using Spring.TestSupport; #endregion -namespace Spring.Core.IO +namespace Spring.Core.IO; + +/// +/// Unit tests for the WebResource class. +/// +/// Erich Eichinger +[TestFixture] +public class WebResourceTests : FileSystemResourceCommonTests { - /// - /// Unit tests for the WebResource class. - /// - /// Erich Eichinger - [TestFixture] - public class WebResourceTests : FileSystemResourceCommonTests + private VirtualEnvironmentMock testVirtualEnvironment; + + [OneTimeSetUp] + public void SetUpFixture() { - private VirtualEnvironmentMock testVirtualEnvironment; - - [OneTimeSetUp] - public void SetUpFixture() - { - testVirtualEnvironment = new VirtualEnvironmentMock("/some.request", "somepathinfo", null, "/", true); - } - - [OneTimeTearDown] - public void ShutDownFixture() - { - testVirtualEnvironment.Dispose(); - } - - protected override FileSystemResource CreateResourceInstance(string resourceName) - { - return new WebResource(resourceName); - } + testVirtualEnvironment = new VirtualEnvironmentMock("/some.request", "somepathinfo", null, "/", true); } -} \ No newline at end of file + + [OneTimeTearDown] + public void ShutDownFixture() + { + testVirtualEnvironment.Dispose(); + } + + protected override FileSystemResource CreateResourceInstance(string resourceName) + { + return new WebResource(resourceName); + } +} diff --git a/test/Spring/Spring.Web.Tests/Data/Spring/Context/Support/WebApplicationContextTests/Dummy.aspx b/test/Spring/Spring.Web.Tests/Data/Spring/Context/Support/WebApplicationContextTests/Dummy.aspx index 0a7c23bd..9495b4bb 100644 --- a/test/Spring/Spring.Web.Tests/Data/Spring/Context/Support/WebApplicationContextTests/Dummy.aspx +++ b/test/Spring/Spring.Web.Tests/Data/Spring/Context/Support/WebApplicationContextTests/Dummy.aspx @@ -1,13 +1,14 @@ <%@ Page language="c#" EnableSessionState="false" AutoEventWireup="false" Inherits="Spring.Web.UI.Page" %>OK \ No newline at end of file + protected override void OnLoad(EventArgs e) + { + base.OnLoad(e); + try + { + Session["disablesSession"] = "somevalue"; + NUnit.Framework.Assert.Fail("must not be able to access session"); + } + catch (HttpException) + { + } + } + OK \ No newline at end of file diff --git a/test/Spring/Spring.Web.Tests/Data/Spring/Context/Support/WebApplicationContextTests/Web.Config b/test/Spring/Spring.Web.Tests/Data/Spring/Context/Support/WebApplicationContextTests/Web.Config index a537a5aa..49dc3433 100644 --- a/test/Spring/Spring.Web.Tests/Data/Spring/Context/Support/WebApplicationContextTests/Web.Config +++ b/test/Spring/Spring.Web.Tests/Data/Spring/Context/Support/WebApplicationContextTests/Web.Config @@ -3,8 +3,8 @@ -
-
+
+
@@ -29,13 +29,13 @@ The following needs to be configured in order to enable Spring.NET Web Framework features --> - + - - + + @@ -43,11 +43,11 @@ - + - + diff --git a/test/Spring/Spring.Web.Tests/Data/Spring/Objects/Factory/Support/TestForm.aspx.cs b/test/Spring/Spring.Web.Tests/Data/Spring/Objects/Factory/Support/TestForm.aspx.cs index f5b6f198..1b10e0b3 100644 --- a/test/Spring/Spring.Web.Tests/Data/Spring/Objects/Factory/Support/TestForm.aspx.cs +++ b/test/Spring/Spring.Web.Tests/Data/Spring/Objects/Factory/Support/TestForm.aspx.cs @@ -1,19 +1,18 @@ using Microsoft.Extensions.Logging; -namespace Spring.Data.Objects.Factory.Support +namespace Spring.Data.Objects.Factory.Support; + +public class TestForm : Spring.Web.UI.Page { - public class TestForm : Spring.Web.UI.Page + private ILogger _log = LogManager.GetLogger(); + + public TestForm() { - private ILogger _log = LogManager.GetLogger(); + this.Load += new EventHandler(Page_Load); + } - public TestForm() - { - this.Load += new EventHandler(Page_Load); - } - - protected void Page_Load(object sender, EventArgs e) - { - _log.LogDebug("loaded page!"); - } + protected void Page_Load(object sender, EventArgs e) + { + _log.LogDebug("loaded page!"); } } diff --git a/test/Spring/Spring.Web.Tests/Data/Spring/Web/Support/LocalResourceManagerTests/App_LocalResources/WithResources.aspx.resx b/test/Spring/Spring.Web.Tests/Data/Spring/Web/Support/LocalResourceManagerTests/App_LocalResources/WithResources.aspx.resx index 96a3872d..bf6b5fc1 100644 --- a/test/Spring/Spring.Web.Tests/Data/Spring/Web/Support/LocalResourceManagerTests/App_LocalResources/WithResources.aspx.resx +++ b/test/Spring/Spring.Web.Tests/Data/Spring/Web/Support/LocalResourceManagerTests/App_LocalResources/WithResources.aspx.resx @@ -59,7 +59,8 @@ : using a System.ComponentModel.TypeConverter : and then encoded with base64 encoding. --> - + @@ -112,10 +113,14 @@ 2.0 - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + FromResource diff --git a/test/Spring/Spring.Web.Tests/Data/Spring/Web/Support/LocalResourceManagerTests/Web.Config b/test/Spring/Spring.Web.Tests/Data/Spring/Web/Support/LocalResourceManagerTests/Web.Config index 4b30b738..bfc1a87f 100644 --- a/test/Spring/Spring.Web.Tests/Data/Spring/Web/Support/LocalResourceManagerTests/Web.Config +++ b/test/Spring/Spring.Web.Tests/Data/Spring/Web/Support/LocalResourceManagerTests/Web.Config @@ -3,8 +3,8 @@ -
-
+
+
@@ -31,13 +31,13 @@ The following needs to be configured in order to enable Spring.NET Web Framework features --> - + - - + + @@ -46,7 +46,7 @@ - + diff --git a/test/Spring/Spring.Web.Tests/Data/Spring/Web/Support/LocalResourceManagerTests/WithoutResources.aspx b/test/Spring/Spring.Web.Tests/Data/Spring/Web/Support/LocalResourceManagerTests/WithoutResources.aspx index b223f099..e74cc14f 100644 --- a/test/Spring/Spring.Web.Tests/Data/Spring/Web/Support/LocalResourceManagerTests/WithoutResources.aspx +++ b/test/Spring/Spring.Web.Tests/Data/Spring/Web/Support/LocalResourceManagerTests/WithoutResources.aspx @@ -1,2 +1,2 @@ <%@ Page language="c#" EnableSessionState="ReadOnly" AutoEventWireup="false" Inherits="Spring.Web.UI.Page" %> -<%=this.GetMessage("OK")%> \ No newline at end of file +<%= this.GetMessage("OK") %> \ No newline at end of file diff --git a/test/Spring/Spring.Web.Tests/Data/Spring/Web/Support/PageHandlerFactoryTests/DisablesSession.aspx b/test/Spring/Spring.Web.Tests/Data/Spring/Web/Support/PageHandlerFactoryTests/DisablesSession.aspx index 0a7c23bd..9495b4bb 100644 --- a/test/Spring/Spring.Web.Tests/Data/Spring/Web/Support/PageHandlerFactoryTests/DisablesSession.aspx +++ b/test/Spring/Spring.Web.Tests/Data/Spring/Web/Support/PageHandlerFactoryTests/DisablesSession.aspx @@ -1,13 +1,14 @@ <%@ Page language="c#" EnableSessionState="false" AutoEventWireup="false" Inherits="Spring.Web.UI.Page" %>OK \ No newline at end of file + protected override void OnLoad(EventArgs e) + { + base.OnLoad(e); + try + { + Session["disablesSession"] = "somevalue"; + NUnit.Framework.Assert.Fail("must not be able to access session"); + } + catch (HttpException) + { + } + } + OK \ No newline at end of file diff --git a/test/Spring/Spring.Web.Tests/Data/Spring/Web/Support/PageHandlerFactoryTests/MaintainsSession1.aspx b/test/Spring/Spring.Web.Tests/Data/Spring/Web/Support/PageHandlerFactoryTests/MaintainsSession1.aspx index ca6ac839..1186242f 100644 --- a/test/Spring/Spring.Web.Tests/Data/Spring/Web/Support/PageHandlerFactoryTests/MaintainsSession1.aspx +++ b/test/Spring/Spring.Web.Tests/Data/Spring/Web/Support/PageHandlerFactoryTests/MaintainsSession1.aspx @@ -1,7 +1,7 @@ <%@ Page language="c#" AutoEventWireup="false" Inherits="Spring.Web.UI.Page" %>OK \ No newline at end of file + protected override void OnLoad(EventArgs e) + { + base.OnLoad(e); + Session["maintainsSession"] = "somevalue"; + } + OK \ No newline at end of file diff --git a/test/Spring/Spring.Web.Tests/Data/Spring/Web/Support/PageHandlerFactoryTests/MaintainsSession2.aspx b/test/Spring/Spring.Web.Tests/Data/Spring/Web/Support/PageHandlerFactoryTests/MaintainsSession2.aspx index 197bff68..08017a2d 100644 --- a/test/Spring/Spring.Web.Tests/Data/Spring/Web/Support/PageHandlerFactoryTests/MaintainsSession2.aspx +++ b/test/Spring/Spring.Web.Tests/Data/Spring/Web/Support/PageHandlerFactoryTests/MaintainsSession2.aspx @@ -1,7 +1,7 @@ <%@ Page language="c#" AutoEventWireup="false" Inherits="Spring.Web.UI.Page" %>OK \ No newline at end of file + protected override void OnLoad(EventArgs e) + { + base.OnLoad(e); + NUnit.Framework.Assert.AreEqual("somevalue", Session["maintainsSession"]); + } + OK \ No newline at end of file diff --git a/test/Spring/Spring.Web.Tests/Data/Spring/Web/Support/PageHandlerFactoryTests/ReadOnlySession.aspx b/test/Spring/Spring.Web.Tests/Data/Spring/Web/Support/PageHandlerFactoryTests/ReadOnlySession.aspx index 6f84395b..98f4356c 100644 --- a/test/Spring/Spring.Web.Tests/Data/Spring/Web/Support/PageHandlerFactoryTests/ReadOnlySession.aspx +++ b/test/Spring/Spring.Web.Tests/Data/Spring/Web/Support/PageHandlerFactoryTests/ReadOnlySession.aspx @@ -1,14 +1,15 @@ <%@ Page language="c#" EnableSessionState="ReadOnly" AutoEventWireup="false" Inherits="Spring.Web.UI.Page" %><%=Session.IsReadOnly?"OK":"NOK"%> \ No newline at end of file + protected override void OnLoad(EventArgs e) + { + base.OnLoad(e); + + try + { + Session["disablesSession"] = "somevalue"; + NUnit.Framework.Assert.Fail("must not be able to write to session"); + } + catch (HttpException) + { + } + } + <%= Session.IsReadOnly ? "OK" : "NOK" %> \ No newline at end of file diff --git a/test/Spring/Spring.Web.Tests/Data/Spring/Web/Support/PageHandlerFactoryTests/TransferAfterSetResult.aspx b/test/Spring/Spring.Web.Tests/Data/Spring/Web/Support/PageHandlerFactoryTests/TransferAfterSetResult.aspx index 2a669b6c..50481a32 100644 --- a/test/Spring/Spring.Web.Tests/Data/Spring/Web/Support/PageHandlerFactoryTests/TransferAfterSetResult.aspx +++ b/test/Spring/Spring.Web.Tests/Data/Spring/Web/Support/PageHandlerFactoryTests/TransferAfterSetResult.aspx @@ -1,9 +1,9 @@ <%@ Page language="c#" AutoEventWireup="false" Inherits="Spring.Web.UI.Page" ClassName="TransferAfterSetResult" %> diff --git a/test/Spring/Spring.Web.Tests/Data/Spring/Web/Support/PageHandlerFactoryTests/TransferAfterSetResultSave.aspx b/test/Spring/Spring.Web.Tests/Data/Spring/Web/Support/PageHandlerFactoryTests/TransferAfterSetResultSave.aspx index 6b18833f..a5a01d0c 100644 --- a/test/Spring/Spring.Web.Tests/Data/Spring/Web/Support/PageHandlerFactoryTests/TransferAfterSetResultSave.aspx +++ b/test/Spring/Spring.Web.Tests/Data/Spring/Web/Support/PageHandlerFactoryTests/TransferAfterSetResultSave.aspx @@ -1,12 +1,12 @@ <%@ Page language="c#" AutoEventWireup="false" EnableViewStateMac="false" Inherits="Spring.Web.UI.Page" %> <%@ Reference Page="TransferAfterSetResult.aspx" %> OK \ No newline at end of file diff --git a/test/Spring/Spring.Web.Tests/Globalization/Resolvers/DefaultWebCultureResolverTests.cs b/test/Spring/Spring.Web.Tests/Globalization/Resolvers/DefaultWebCultureResolverTests.cs index 529383a1..68425933 100644 --- a/test/Spring/Spring.Web.Tests/Globalization/Resolvers/DefaultWebCultureResolverTests.cs +++ b/test/Spring/Spring.Web.Tests/Globalization/Resolvers/DefaultWebCultureResolverTests.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -25,94 +25,93 @@ using NUnit.Framework; #endregion -namespace Spring.Globalization.Resolvers +namespace Spring.Globalization.Resolvers; + +/// +/// Tests DefaultWebCultureResolver behaviour. +/// +/// Erich Eichinger +[TestFixture] +public class DefaultWebCultureResolverTests { + #region TestDefaultWebCultureResolver utility class + /// - /// Tests DefaultWebCultureResolver behaviour. + /// Override GetRequestLanguage() to return test language instead of HttpRequest.UserLanguages[0] /// - /// Erich Eichinger - [TestFixture] - public class DefaultWebCultureResolverTests + public class TestDefaultWebCultureResolver : DefaultWebCultureResolver { - #region TestDefaultWebCultureResolver utility class + private string _requestLanguage; - /// - /// Override GetRequestLanguage() to return test language instead of HttpRequest.UserLanguages[0] - /// - public class TestDefaultWebCultureResolver : DefaultWebCultureResolver + // convenience setter method + public TestDefaultWebCultureResolver SetRequestLanguage(string requestLanguage) { - private string _requestLanguage; - - // convenience setter method - public TestDefaultWebCultureResolver SetRequestLanguage(string requestLanguage) - { - _requestLanguage = requestLanguage; - return this; - } - - // override to return our test language instead of HttpRequest.UserLanguages[0]! - protected override string GetRequestLanguage() - { - return _requestLanguage; - } + _requestLanguage = requestLanguage; + return this; } - #endregion - - private readonly CultureInfo EXPECTED_NEUTRALCULTURE = new CultureInfo("fr"); - - [OneTimeSetUp] - public void TestFixtureSetUp() + // override to return our test language instead of HttpRequest.UserLanguages[0]! + protected override string GetRequestLanguage() { - // ensure, uiCulture and culture are set to different cultures - CultureTestScope.Set(); - } - - [OneTimeTearDown] - public void TestFixtureTearDown() - { - CultureTestScope.Reset(); - } - - [Test] - public void DefaultCultureDefaultsToNull() - { - TestDefaultWebCultureResolver r = new TestDefaultWebCultureResolver(); - Assert.IsNull(r.DefaultCulture); - } - - [Test] - public void AlwaysReturnsDefaultCultureIfDefaultCultureIsSet() - { - TestDefaultWebCultureResolver r = new TestDefaultWebCultureResolver(); - r.DefaultCulture = EXPECTED_NEUTRALCULTURE; - - r.SetRequestLanguage(null); - Assert.AreEqual(EXPECTED_NEUTRALCULTURE, r.ResolveCulture()); - - r.SetRequestLanguage("de"); - Assert.AreEqual(EXPECTED_NEUTRALCULTURE, r.ResolveCulture()); - } - - [Test] - public void ReturnsRequestCultureIfNoDefaultCulture() - { - TestDefaultWebCultureResolver r = new TestDefaultWebCultureResolver(); - - r.SetRequestLanguage(EXPECTED_NEUTRALCULTURE.Name); - Assert.AreEqual(EXPECTED_NEUTRALCULTURE, r.ResolveCulture()); - } - - [Test] - public void ReturnsCurrentUICultureIfNoDefaultCultureIsSetAndNoOrInvalidRequestLanguage() - { - TestDefaultWebCultureResolver r = new TestDefaultWebCultureResolver(); - - r.SetRequestLanguage(null); - Assert.AreEqual(CultureInfo.CurrentUICulture, r.ResolveCulture()); - - r.SetRequestLanguage("invalid culture name"); - Assert.AreEqual(CultureInfo.CurrentUICulture, r.ResolveCulture()); + return _requestLanguage; } } -} \ No newline at end of file + + #endregion + + private readonly CultureInfo EXPECTED_NEUTRALCULTURE = new CultureInfo("fr"); + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + // ensure, uiCulture and culture are set to different cultures + CultureTestScope.Set(); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + CultureTestScope.Reset(); + } + + [Test] + public void DefaultCultureDefaultsToNull() + { + TestDefaultWebCultureResolver r = new TestDefaultWebCultureResolver(); + Assert.IsNull(r.DefaultCulture); + } + + [Test] + public void AlwaysReturnsDefaultCultureIfDefaultCultureIsSet() + { + TestDefaultWebCultureResolver r = new TestDefaultWebCultureResolver(); + r.DefaultCulture = EXPECTED_NEUTRALCULTURE; + + r.SetRequestLanguage(null); + Assert.AreEqual(EXPECTED_NEUTRALCULTURE, r.ResolveCulture()); + + r.SetRequestLanguage("de"); + Assert.AreEqual(EXPECTED_NEUTRALCULTURE, r.ResolveCulture()); + } + + [Test] + public void ReturnsRequestCultureIfNoDefaultCulture() + { + TestDefaultWebCultureResolver r = new TestDefaultWebCultureResolver(); + + r.SetRequestLanguage(EXPECTED_NEUTRALCULTURE.Name); + Assert.AreEqual(EXPECTED_NEUTRALCULTURE, r.ResolveCulture()); + } + + [Test] + public void ReturnsCurrentUICultureIfNoDefaultCultureIsSetAndNoOrInvalidRequestLanguage() + { + TestDefaultWebCultureResolver r = new TestDefaultWebCultureResolver(); + + r.SetRequestLanguage(null); + Assert.AreEqual(CultureInfo.CurrentUICulture, r.ResolveCulture()); + + r.SetRequestLanguage("invalid culture name"); + Assert.AreEqual(CultureInfo.CurrentUICulture, r.ResolveCulture()); + } +} diff --git a/test/Spring/Spring.Web.Tests/Objects/Factory/Support/WebObjectDefinitionFactoryTests.cs b/test/Spring/Spring.Web.Tests/Objects/Factory/Support/WebObjectDefinitionFactoryTests.cs index 45a70955..3d162b69 100644 --- a/test/Spring/Spring.Web.Tests/Objects/Factory/Support/WebObjectDefinitionFactoryTests.cs +++ b/test/Spring/Spring.Web.Tests/Objects/Factory/Support/WebObjectDefinitionFactoryTests.cs @@ -22,121 +22,120 @@ using NUnit.Framework; using NUnitAspEx; - using Spring.TestSupport; #endregion -namespace Spring.Objects.Factory.Support +namespace Spring.Objects.Factory.Support; + +/// +/// Unit tests for the WebObjectDefinitionFactory class. +/// +/// Erich Eichinger +[TestFixture] +public class WebObjectDefinitionFactoryTests : WebApplicationTests { - /// - /// Unit tests for the WebObjectDefinitionFactory class. - /// - /// Erich Eichinger - [TestFixture] - public class WebObjectDefinitionFactoryTests : WebApplicationTests + public WebObjectDefinitionFactoryTests() + : base("/Test", "/Spring/Objects/Factory/Support") { - public WebObjectDefinitionFactoryTests() - : base("/Test", "/Spring/Objects/Factory/Support") - {} + } - [Test] - public void CreateRootDefinition() + [Test] + public void CreateRootDefinition() + { + WebObjectDefinitionFactory factory = new WebObjectDefinitionFactory(); + IConfigurableObjectDefinition definition + = factory.CreateObjectDefinition( + typeof(TestObject).FullName, null, AppDomain.CurrentDomain); + Assert.IsNotNull(definition, "CreateObjectDefinition with no parent is returning null (it must never do so)."); + Assert.AreEqual(typeof(TestObject), definition.ObjectType); + Assert.AreEqual(0, definition.PropertyValues.PropertyValues.Count, + "Must not have any property values as none were passed in."); + Assert.AreEqual(0, definition.ConstructorArgumentValues.ArgumentCount, + "Must not have any ctor args as none were passed in."); + } + + [Test] + public void CreateChildDefinition() + { + WebObjectDefinitionFactory factory = new WebObjectDefinitionFactory(); + IConfigurableObjectDefinition definition + = factory.CreateObjectDefinition( + typeof(TestObject).FullName, "Aimee Mann", AppDomain.CurrentDomain); + Assert.IsNotNull(definition, "CreateObjectDefinition with no parent is returning null (it must never do so)."); + Assert.AreEqual(typeof(TestObject), definition.ObjectType); + Assert.AreEqual(0, definition.PropertyValues.PropertyValues.Count, + "Must not have any property values as none were passed in."); + Assert.AreEqual(0, definition.ConstructorArgumentValues.ArgumentCount, + "Must not have any ctor args as none were passed in."); + } + + [Test] + public void DoesNotResolveTypeNameToFullTypeInstanceIfAppDomainIsNull() + { + WebObjectDefinitionFactory factory = new WebObjectDefinitionFactory(); + IConfigurableObjectDefinition definition + = factory.CreateObjectDefinition( + typeof(TestObject).FullName, null, null); + Assert.IsNotNull(definition, "CreateObjectDefinition with no parent is returning null (it must never do so)."); + Assert.AreEqual(typeof(TestObject).FullName, definition.ObjectTypeName); + Assert.AreEqual(0, definition.PropertyValues.PropertyValues.Count, + "Must not have any property values as none were passed in."); + Assert.AreEqual(0, definition.ConstructorArgumentValues.ArgumentCount, + "Must not have any ctor args as none were passed in."); + } + + [Test] + public void ResolvesToPageRootDefinitionIfEndsWithASPX() + { + Host.Execute(new TestAction(ResolvesToPageRootDefinitionIfEndsWithASPXImpl)); + } + + public static void ResolvesToPageRootDefinitionIfEndsWithASPXImpl() + { + using (TestWebContext ctx = new TestWebContext("/Test", "testform.aspx")) { WebObjectDefinitionFactory factory = new WebObjectDefinitionFactory(); - IConfigurableObjectDefinition definition - = factory.CreateObjectDefinition( - typeof(TestObject).FullName, null, AppDomain.CurrentDomain); + IWebObjectDefinition definition + = (IWebObjectDefinition) factory.CreateObjectDefinition("/Test/testform.aspx", null, AppDomain.CurrentDomain); Assert.IsNotNull(definition, "CreateObjectDefinition with no parent is returning null (it must never do so)."); - Assert.AreEqual(typeof(TestObject), definition.ObjectType); - Assert.AreEqual(0, definition.PropertyValues.PropertyValues.Count, - "Must not have any property values as none were passed in."); - Assert.AreEqual(0, definition.ConstructorArgumentValues.ArgumentCount, - "Must not have any ctor args as none were passed in."); + Assert.IsTrue(definition.IsPage, ".aspx extension must result in a page instance"); + Assert.AreEqual(typeof(RootWebObjectDefinition), definition.GetType()); } + } - [Test] - public void CreateChildDefinition() + [Test] + public void ResolvesToPageChildDefinitionIfEndsWithASPX() + { + Host.Execute(new TestAction(ResolvesToPageChildDefinitionIfEndsWithASPXImpl)); + } + + public static void ResolvesToPageChildDefinitionIfEndsWithASPXImpl() + { + using (TestWebContext ctx = new TestWebContext("/Test", "testform.aspx")) { WebObjectDefinitionFactory factory = new WebObjectDefinitionFactory(); - IConfigurableObjectDefinition definition - = factory.CreateObjectDefinition( - typeof(TestObject).FullName, "Aimee Mann", AppDomain.CurrentDomain); - Assert.IsNotNull(definition, "CreateObjectDefinition with no parent is returning null (it must never do so)."); - Assert.AreEqual(typeof(TestObject), definition.ObjectType); - Assert.AreEqual(0, definition.PropertyValues.PropertyValues.Count, - "Must not have any property values as none were passed in."); - Assert.AreEqual(0, definition.ConstructorArgumentValues.ArgumentCount, - "Must not have any ctor args as none were passed in."); + IWebObjectDefinition definition + = (IWebObjectDefinition) factory.CreateObjectDefinition("/Test/testform.aspx", "parentdefinition", AppDomain.CurrentDomain); + Assert.IsNotNull(definition, "CreateObjectDefinition with parent is returning null (it must never do so)."); + Assert.IsTrue(definition.IsPage, ".aspx extension must result in a page instance"); + Assert.AreEqual(typeof(ChildWebObjectDefinition), definition.GetType()); } + } - [Test] - public void DoesNotResolveTypeNameToFullTypeInstanceIfAppDomainIsNull() + [Test] + public void ThrowsArgumentExceptionOnNonExistingPath() + { + Assert.Throws(() => Host.Execute(new TestAction(ThrowsArgumentExceptionOnNonExistingPathImpl))); + } + + public static void ThrowsArgumentExceptionOnNonExistingPathImpl() + { + using (TestWebContext ctx = new TestWebContext("/Test", "testform.aspx")) { WebObjectDefinitionFactory factory = new WebObjectDefinitionFactory(); - IConfigurableObjectDefinition definition - = factory.CreateObjectDefinition( - typeof(TestObject).FullName, null, null); - Assert.IsNotNull(definition, "CreateObjectDefinition with no parent is returning null (it must never do so)."); - Assert.AreEqual(typeof(TestObject).FullName, definition.ObjectTypeName); - Assert.AreEqual(0, definition.PropertyValues.PropertyValues.Count, - "Must not have any property values as none were passed in."); - Assert.AreEqual(0, definition.ConstructorArgumentValues.ArgumentCount, - "Must not have any ctor args as none were passed in."); - } - - [Test] - public void ResolvesToPageRootDefinitionIfEndsWithASPX() - { - Host.Execute(new TestAction(ResolvesToPageRootDefinitionIfEndsWithASPXImpl)); - } - - public static void ResolvesToPageRootDefinitionIfEndsWithASPXImpl() - { - using (TestWebContext ctx = new TestWebContext("/Test", "testform.aspx")) - { - WebObjectDefinitionFactory factory = new WebObjectDefinitionFactory(); - IWebObjectDefinition definition - = (IWebObjectDefinition)factory.CreateObjectDefinition("/Test/testform.aspx", null, AppDomain.CurrentDomain); - Assert.IsNotNull(definition, "CreateObjectDefinition with no parent is returning null (it must never do so)."); - Assert.IsTrue(definition.IsPage, ".aspx extension must result in a page instance"); - Assert.AreEqual(typeof(RootWebObjectDefinition), definition.GetType()); - } - } - - [Test] - public void ResolvesToPageChildDefinitionIfEndsWithASPX() - { - Host.Execute(new TestAction(ResolvesToPageChildDefinitionIfEndsWithASPXImpl)); - } - - public static void ResolvesToPageChildDefinitionIfEndsWithASPXImpl() - { - using (TestWebContext ctx = new TestWebContext("/Test", "testform.aspx")) - { - WebObjectDefinitionFactory factory = new WebObjectDefinitionFactory(); - IWebObjectDefinition definition - = (IWebObjectDefinition)factory.CreateObjectDefinition("/Test/testform.aspx", "parentdefinition", AppDomain.CurrentDomain); - Assert.IsNotNull(definition, "CreateObjectDefinition with parent is returning null (it must never do so)."); - Assert.IsTrue(definition.IsPage, ".aspx extension must result in a page instance"); - Assert.AreEqual(typeof(ChildWebObjectDefinition), definition.GetType()); - } - } - - [Test] - public void ThrowsArgumentExceptionOnNonExistingPath() - { - Assert.Throws(() => Host.Execute(new TestAction(ThrowsArgumentExceptionOnNonExistingPathImpl))); - } - - public static void ThrowsArgumentExceptionOnNonExistingPathImpl() - { - using (TestWebContext ctx = new TestWebContext("/Test", "testform.aspx")) - { - WebObjectDefinitionFactory factory = new WebObjectDefinitionFactory(); - IWebObjectDefinition definition - = (IWebObjectDefinition)factory.CreateObjectDefinition("/Test/DoesNotExist.aspx", "parentdefinition", AppDomain.CurrentDomain); - } + IWebObjectDefinition definition + = (IWebObjectDefinition) factory.CreateObjectDefinition("/Test/DoesNotExist.aspx", "parentdefinition", AppDomain.CurrentDomain); } } } diff --git a/test/Spring/Spring.Web.Tests/Objects/Factory/Support/WebObjectDefinitionTests.cs b/test/Spring/Spring.Web.Tests/Objects/Factory/Support/WebObjectDefinitionTests.cs index aa838e98..2ef97a0d 100644 --- a/test/Spring/Spring.Web.Tests/Objects/Factory/Support/WebObjectDefinitionTests.cs +++ b/test/Spring/Spring.Web.Tests/Objects/Factory/Support/WebObjectDefinitionTests.cs @@ -1,19 +1,19 @@ #region License -/* - * Copyright 2002-2010 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. +/* + * Copyright 2002-2010 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 @@ -21,36 +21,36 @@ using NUnit.Framework; using Spring.Objects.Factory.Config; -namespace Spring.Objects.Factory.Support -{ - /// - /// - /// Erich Eichinger - [TestFixture] - public class WebObjectDefinitionTests - { - [Test] - public void UnderstandsObjectScopeSingleton() - { - RootWebObjectDefinition rwod = new RootWebObjectDefinition(typeof(object), new ConstructorArgumentValues(), new MutablePropertyValues()); - rwod.IsSingleton = true; - Assert.IsFalse(rwod.IsPage); - Assert.IsTrue(rwod.IsSingleton); - Assert.IsFalse(rwod.IsPrototype); - Assert.AreEqual(ObjectScope.Singleton, ((IWebObjectDefinition)rwod).Scope); - Assert.AreEqual(ObjectScope.Application, ((IWebObjectDefinition)rwod).Scope); - } +namespace Spring.Objects.Factory.Support; - [Test] - public void UnderstandsObjectScopePrototype() - { - RootWebObjectDefinition rwod = new RootWebObjectDefinition(typeof(object), new ConstructorArgumentValues(), new MutablePropertyValues()); - rwod.IsSingleton = false; - Assert.IsFalse(rwod.IsPage); - Assert.IsFalse(rwod.IsSingleton); - Assert.IsTrue(rwod.IsPrototype); - Assert.AreEqual(ObjectScope.Prototype, ((IWebObjectDefinition)rwod).Scope); - } +/// +/// +/// Erich Eichinger +[TestFixture] +public class WebObjectDefinitionTests +{ + [Test] + public void UnderstandsObjectScopeSingleton() + { + RootWebObjectDefinition rwod = new RootWebObjectDefinition(typeof(object), new ConstructorArgumentValues(), new MutablePropertyValues()); + rwod.IsSingleton = true; + Assert.IsFalse(rwod.IsPage); + Assert.IsTrue(rwod.IsSingleton); + Assert.IsFalse(rwod.IsPrototype); + Assert.AreEqual(ObjectScope.Singleton, ((IWebObjectDefinition) rwod).Scope); + Assert.AreEqual(ObjectScope.Application, ((IWebObjectDefinition) rwod).Scope); + } + + [Test] + public void UnderstandsObjectScopePrototype() + { + RootWebObjectDefinition rwod = new RootWebObjectDefinition(typeof(object), new ConstructorArgumentValues(), new MutablePropertyValues()); + rwod.IsSingleton = false; + Assert.IsFalse(rwod.IsPage); + Assert.IsFalse(rwod.IsSingleton); + Assert.IsTrue(rwod.IsPrototype); + Assert.AreEqual(ObjectScope.Prototype, ((IWebObjectDefinition) rwod).Scope); + } // [Test] // public void UnderstandsObjectScopeForPages() @@ -61,5 +61,4 @@ namespace Spring.Objects.Factory.Support // Assert.IsTrue(rwod.IsPrototype); // Assert.AreEqual(ObjectScope.Prototype, ((IWebObjectDefinition)rwod).Scope); // } - } -} \ No newline at end of file +} diff --git a/test/Spring/Spring.Web.Tests/Objects/Factory/Support/WebObjectFactoryTests.cs b/test/Spring/Spring.Web.Tests/Objects/Factory/Support/WebObjectFactoryTests.cs index 27763e14..4d657d13 100644 --- a/test/Spring/Spring.Web.Tests/Objects/Factory/Support/WebObjectFactoryTests.cs +++ b/test/Spring/Spring.Web.Tests/Objects/Factory/Support/WebObjectFactoryTests.cs @@ -26,59 +26,58 @@ using Spring.TestSupport; #endregion -namespace Spring.Objects.Factory.Support +namespace Spring.Objects.Factory.Support; + +/// +/// Unit tests for the WebObjectFactory class. +/// +/// Rick Evans +[TestFixture] +public sealed class WebObjectFactoryTests { - /// - /// Unit tests for the WebObjectFactory class. - /// - /// Rick Evans - [TestFixture] - public sealed class WebObjectFactoryTests + [Test] + public void CanBeUsedOnNonWebThread() { - [Test] - public void CanBeUsedOnNonWebThread() + WebObjectFactory wof; + RootWebObjectDefinition rwod; + + // we need to create WOF within a valid HttpContext environment 'cause we will + // make use of 'request' and 'session' scope. + using (new VirtualEnvironmentMock("/somedir/some.file", null, null, "/", true)) { - WebObjectFactory wof; - RootWebObjectDefinition rwod; - - // we need to create WOF within a valid HttpContext environment 'cause we will - // make use of 'request' and 'session' scope. - using (new VirtualEnvironmentMock("/somedir/some.file", null, null, "/", true)) - { - wof = new WebObjectFactory("/somedir/", false); - } - - rwod = new RootWebObjectDefinition(typeof(object), new ConstructorArgumentValues(), new MutablePropertyValues()); - rwod.Scope = ObjectScope.Application.ToString(); - wof.RegisterObjectDefinition("applicationScopedObject", rwod); - - rwod = new RootWebObjectDefinition(typeof(object), new ConstructorArgumentValues(), new MutablePropertyValues()); - rwod.Scope = ObjectScope.Request.ToString(); - wof.RegisterObjectDefinition("requestScopedObject", rwod); - - rwod = new RootWebObjectDefinition(typeof(object), new ConstructorArgumentValues(), new MutablePropertyValues()); - rwod.Scope = ObjectScope.Session.ToString(); - wof.RegisterObjectDefinition("sessionScopedObject", rwod); - - object o; - o = wof.GetObject("applicationScopedObject"); - Assert.IsNotNull(o); - - AssertGetObjectThrows(typeof(ObjectCreationException), wof, "requestScopedObject"); - AssertGetObjectThrows(typeof(ObjectCreationException), wof, "sessionScopedObject"); + wof = new WebObjectFactory("/somedir/", false); } - private void AssertGetObjectThrows(Type exceptionType, WebObjectFactory wof, string objectName) + rwod = new RootWebObjectDefinition(typeof(object), new ConstructorArgumentValues(), new MutablePropertyValues()); + rwod.Scope = ObjectScope.Application.ToString(); + wof.RegisterObjectDefinition("applicationScopedObject", rwod); + + rwod = new RootWebObjectDefinition(typeof(object), new ConstructorArgumentValues(), new MutablePropertyValues()); + rwod.Scope = ObjectScope.Request.ToString(); + wof.RegisterObjectDefinition("requestScopedObject", rwod); + + rwod = new RootWebObjectDefinition(typeof(object), new ConstructorArgumentValues(), new MutablePropertyValues()); + rwod.Scope = ObjectScope.Session.ToString(); + wof.RegisterObjectDefinition("sessionScopedObject", rwod); + + object o; + o = wof.GetObject("applicationScopedObject"); + Assert.IsNotNull(o); + + AssertGetObjectThrows(typeof(ObjectCreationException), wof, "requestScopedObject"); + AssertGetObjectThrows(typeof(ObjectCreationException), wof, "sessionScopedObject"); + } + + private void AssertGetObjectThrows(Type exceptionType, WebObjectFactory wof, string objectName) + { + try { - try - { - wof.GetObject(objectName); - Assert.Fail("must not reach this line"); - } - catch (Exception ex) - { - Assert.AreEqual(exceptionType, ex.GetType()); - } + wof.GetObject(objectName); + Assert.Fail("must not reach this line"); + } + catch (Exception ex) + { + Assert.AreEqual(exceptionType, ex.GetType()); } } } diff --git a/test/Spring/Spring.Web.Tests/Objects/Factory/Support/WebObjectUtilsTests.cs b/test/Spring/Spring.Web.Tests/Objects/Factory/Support/WebObjectUtilsTests.cs index a6928bdd..eeb17117 100644 --- a/test/Spring/Spring.Web.Tests/Objects/Factory/Support/WebObjectUtilsTests.cs +++ b/test/Spring/Spring.Web.Tests/Objects/Factory/Support/WebObjectUtilsTests.cs @@ -20,36 +20,35 @@ using NUnit.Framework; -namespace Spring.Objects.Factory.Support +namespace Spring.Objects.Factory.Support; + +/// +/// +/// Erich Eichinger +[TestFixture] +public class WebObjectUtilsTests { - /// - /// - /// Erich Eichinger - [TestFixture] - public class WebObjectUtilsTests + [Test] + public void GetPageTypeWithNullPageName() { - [Test] - public void GetPageTypeWithNullPageName() - { - Assert.Throws(() => WebObjectUtils.GetPageType(null)); - } + Assert.Throws(() => WebObjectUtils.GetPageType(null)); + } - [Test] - public void GetPageTypeWithEmptyStringPageName() - { - Assert.Throws(() => WebObjectUtils.GetPageType(string.Empty)); - } + [Test] + public void GetPageTypeWithEmptyStringPageName() + { + Assert.Throws(() => WebObjectUtils.GetPageType(string.Empty)); + } - [Test] - public void GetPageTypeWithWhitespacedPageName() - { - Assert.Throws(() => WebObjectUtils.GetPageType(" ")); - } + [Test] + public void GetPageTypeWithWhitespacedPageName() + { + Assert.Throws(() => WebObjectUtils.GetPageType(" ")); + } - [Test] - public void CreatePageInstanceWhenNotRunningInServerContext() - { - Assert.Throws(() => WebObjectUtils.CreatePageInstance("foo.aspx")); - } + [Test] + public void CreatePageInstanceWhenNotRunningInServerContext() + { + Assert.Throws(() => WebObjectUtils.CreatePageInstance("foo.aspx")); } } diff --git a/test/Spring/Spring.Web.Tests/Objects/Factory/Xml/WebObjectDefinitionReaderTests.cs b/test/Spring/Spring.Web.Tests/Objects/Factory/Xml/WebObjectDefinitionReaderTests.cs index cfc92558..00c4c150 100644 --- a/test/Spring/Spring.Web.Tests/Objects/Factory/Xml/WebObjectDefinitionReaderTests.cs +++ b/test/Spring/Spring.Web.Tests/Objects/Factory/Xml/WebObjectDefinitionReaderTests.cs @@ -1,178 +1,177 @@ #region License -/* - * Copyright 2002-2010 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. +/* + * Copyright 2002-2010 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.Xml; using NUnit.Framework; - using Spring.Core.IO; using Spring.Objects.Factory.Support; using Spring.Objects.Factory.Xml; using Spring.TestSupport; -namespace Spring.Objects.Factory -{ - /// - /// - /// Erich Eichinger - [TestFixture] - public class WebObjectDefinitionReaderTests - { - public class TestWebObjectDefinitionReader : WebObjectDefinitionReader - { - public TestWebObjectDefinitionReader(string contextVirtualPath, IObjectDefinitionRegistry registry, XmlResolver resolver) - : base(contextVirtualPath, registry, resolver) - {} - } +namespace Spring.Objects.Factory; - [Test] - public void ControlDefinitionsGetMarkedAbstract() +/// +/// +/// Erich Eichinger +[TestFixture] +public class WebObjectDefinitionReaderTests +{ + public class TestWebObjectDefinitionReader : WebObjectDefinitionReader + { + public TestWebObjectDefinitionReader(string contextVirtualPath, IObjectDefinitionRegistry registry, XmlResolver resolver) + : base(contextVirtualPath, registry, resolver) { - const string CONTEXTPATH = "/ContextPath/"; - const string xml = - @" + } + } + + [Test] + public void ControlDefinitionsGetMarkedAbstract() + { + const string CONTEXTPATH = "/ContextPath/"; + const string xml = + @" "; - WebObjectFactory objectFactory = new WebObjectFactory(CONTEXTPATH, false); - TestWebObjectDefinitionReader reader = new TestWebObjectDefinitionReader(objectFactory.ContextPath, objectFactory, new XmlUrlResolver()); + WebObjectFactory objectFactory = new WebObjectFactory(CONTEXTPATH, false); + TestWebObjectDefinitionReader reader = new TestWebObjectDefinitionReader(objectFactory.ContextPath, objectFactory, new XmlUrlResolver()); - using (VirtualEnvironmentMock env = new VirtualEnvironmentMock(CONTEXTPATH + "test.aspx", null, null, CONTEXTPATH, true)) - { - env.VirtualPath2ArtifactsTable[CONTEXTPATH + "MyControl.ascx"] = typeof(Spring.Web.UI.UserControl); + using (VirtualEnvironmentMock env = new VirtualEnvironmentMock(CONTEXTPATH + "test.aspx", null, null, CONTEXTPATH, true)) + { + env.VirtualPath2ArtifactsTable[CONTEXTPATH + "MyControl.ascx"] = typeof(Spring.Web.UI.UserControl); - reader.LoadObjectDefinitions(new StringResource(xml)); - } - - Assert.IsTrue(objectFactory.ContainsObjectDefinition("Spring.Web.UI.UserControl")); - Assert.IsTrue(objectFactory.GetObjectDefinition("Spring.Web.UI.UserControl").IsAbstract); + reader.LoadObjectDefinitions(new StringResource(xml)); } - [Test] - public void ParsesPagePathIntoObjectNameIfNeitherIdNorNameAttributeSpecified() - { - const string CONTEXTPATH = "/ContextPath/"; + Assert.IsTrue(objectFactory.ContainsObjectDefinition("Spring.Web.UI.UserControl")); + Assert.IsTrue(objectFactory.GetObjectDefinition("Spring.Web.UI.UserControl").IsAbstract); + } - const string xml = - @" + [Test] + public void ParsesPagePathIntoObjectNameIfNeitherIdNorNameAttributeSpecified() + { + const string CONTEXTPATH = "/ContextPath/"; + + const string xml = + @" "; - WebObjectFactory objectFactory = new WebObjectFactory(CONTEXTPATH, false); - TestWebObjectDefinitionReader reader = new TestWebObjectDefinitionReader(objectFactory.ContextPath, objectFactory, new XmlUrlResolver()); + WebObjectFactory objectFactory = new WebObjectFactory(CONTEXTPATH, false); + TestWebObjectDefinitionReader reader = new TestWebObjectDefinitionReader(objectFactory.ContextPath, objectFactory, new XmlUrlResolver()); - using (VirtualEnvironmentMock env = new VirtualEnvironmentMock(CONTEXTPATH + "test.aspx", null, null, CONTEXTPATH, true)) - { - env.VirtualPath2ArtifactsTable[CONTEXTPATH + "MyPage.aspx"] = typeof (Spring.Web.UI.Page); - env.VirtualPath2ArtifactsTable[CONTEXTPATH + "MyControl.ascx"] = typeof (Spring.Web.UI.UserControl); + using (VirtualEnvironmentMock env = new VirtualEnvironmentMock(CONTEXTPATH + "test.aspx", null, null, CONTEXTPATH, true)) + { + env.VirtualPath2ArtifactsTable[CONTEXTPATH + "MyPage.aspx"] = typeof(Spring.Web.UI.Page); + env.VirtualPath2ArtifactsTable[CONTEXTPATH + "MyControl.ascx"] = typeof(Spring.Web.UI.UserControl); - reader.LoadObjectDefinitions(new StringResource(xml)); - } - - Assert.IsTrue(objectFactory.ContainsObjectDefinition("/MyPage.aspx")); - Assert.AreEqual(typeof(Spring.Web.UI.Page), objectFactory.GetType("/MyPage.aspx")); - Assert.IsTrue(objectFactory.ContainsObjectDefinition("Spring.Web.UI.UserControl")); + reader.LoadObjectDefinitions(new StringResource(xml)); } - [Test] - public void DoesNotGenerateObjectNameIfIdAttributeSpecified() - { - const string CONTEXTPATH = "/ContextPath/"; - const string xml = - @" + Assert.IsTrue(objectFactory.ContainsObjectDefinition("/MyPage.aspx")); + Assert.AreEqual(typeof(Spring.Web.UI.Page), objectFactory.GetType("/MyPage.aspx")); + Assert.IsTrue(objectFactory.ContainsObjectDefinition("Spring.Web.UI.UserControl")); + } + + [Test] + public void DoesNotGenerateObjectNameIfIdAttributeSpecified() + { + const string CONTEXTPATH = "/ContextPath/"; + const string xml = + @" "; - WebObjectFactory objectFactory = new WebObjectFactory(CONTEXTPATH, false); - TestWebObjectDefinitionReader reader = new TestWebObjectDefinitionReader(objectFactory.ContextPath, objectFactory, new XmlUrlResolver()); + WebObjectFactory objectFactory = new WebObjectFactory(CONTEXTPATH, false); + TestWebObjectDefinitionReader reader = new TestWebObjectDefinitionReader(objectFactory.ContextPath, objectFactory, new XmlUrlResolver()); - using (VirtualEnvironmentMock env = new VirtualEnvironmentMock(CONTEXTPATH + "test.aspx", null, null, CONTEXTPATH, true)) - { - env.VirtualPath2ArtifactsTable[CONTEXTPATH + "MyPage.aspx"] = typeof (Spring.Web.UI.Page); - env.VirtualPath2ArtifactsTable[CONTEXTPATH + "MyControl.ascx"] = typeof (Spring.Web.UI.UserControl); + using (VirtualEnvironmentMock env = new VirtualEnvironmentMock(CONTEXTPATH + "test.aspx", null, null, CONTEXTPATH, true)) + { + env.VirtualPath2ArtifactsTable[CONTEXTPATH + "MyPage.aspx"] = typeof(Spring.Web.UI.Page); + env.VirtualPath2ArtifactsTable[CONTEXTPATH + "MyControl.ascx"] = typeof(Spring.Web.UI.UserControl); - reader.LoadObjectDefinitions(new StringResource(xml)); - } - - Assert.IsTrue(objectFactory.ContainsObjectDefinition("mypage")); - Assert.AreEqual(typeof(Spring.Web.UI.Page), objectFactory.GetType("mypage")); - Assert.IsTrue(objectFactory.ContainsObjectDefinition("mycontrol")); + reader.LoadObjectDefinitions(new StringResource(xml)); } - [Test] - public void DoesNotGenerateObjectNameIfNameAttributeSpecified() - { - const string CONTEXTPATH = "/ContextPath/"; - const string xml = - @" + Assert.IsTrue(objectFactory.ContainsObjectDefinition("mypage")); + Assert.AreEqual(typeof(Spring.Web.UI.Page), objectFactory.GetType("mypage")); + Assert.IsTrue(objectFactory.ContainsObjectDefinition("mycontrol")); + } + + [Test] + public void DoesNotGenerateObjectNameIfNameAttributeSpecified() + { + const string CONTEXTPATH = "/ContextPath/"; + const string xml = + @" "; - WebObjectFactory objectFactory = new WebObjectFactory(CONTEXTPATH, false); - TestWebObjectDefinitionReader reader = new TestWebObjectDefinitionReader(objectFactory.ContextPath, objectFactory, new XmlUrlResolver()); + WebObjectFactory objectFactory = new WebObjectFactory(CONTEXTPATH, false); + TestWebObjectDefinitionReader reader = new TestWebObjectDefinitionReader(objectFactory.ContextPath, objectFactory, new XmlUrlResolver()); - using (VirtualEnvironmentMock env = new VirtualEnvironmentMock(CONTEXTPATH + "test.aspx", null, null, CONTEXTPATH, true)) - { - env.VirtualPath2ArtifactsTable[CONTEXTPATH + "MyPage.aspx"] = typeof(Spring.Web.UI.Page); - env.VirtualPath2ArtifactsTable[CONTEXTPATH + "MyControl.ascx"] = typeof(Spring.Web.UI.UserControl); + using (VirtualEnvironmentMock env = new VirtualEnvironmentMock(CONTEXTPATH + "test.aspx", null, null, CONTEXTPATH, true)) + { + env.VirtualPath2ArtifactsTable[CONTEXTPATH + "MyPage.aspx"] = typeof(Spring.Web.UI.Page); + env.VirtualPath2ArtifactsTable[CONTEXTPATH + "MyControl.ascx"] = typeof(Spring.Web.UI.UserControl); - reader.LoadObjectDefinitions(new StringResource(xml)); - } - - Assert.IsTrue(objectFactory.ContainsObjectDefinition("mypage")); - Assert.AreEqual(typeof(Spring.Web.UI.Page), objectFactory.GetType("mypage")); - Assert.IsTrue(objectFactory.ContainsObjectDefinition("mycontrol")); + reader.LoadObjectDefinitions(new StringResource(xml)); } - [Test] - public void DoesNotGenerateObjectNameIfIdAndNameAttributeSpecified() - { - const string CONTEXTPATH = "/"; - const string xml = - @" + Assert.IsTrue(objectFactory.ContainsObjectDefinition("mypage")); + Assert.AreEqual(typeof(Spring.Web.UI.Page), objectFactory.GetType("mypage")); + Assert.IsTrue(objectFactory.ContainsObjectDefinition("mycontrol")); + } + + [Test] + public void DoesNotGenerateObjectNameIfIdAndNameAttributeSpecified() + { + const string CONTEXTPATH = "/"; + const string xml = + @" "; - WebObjectFactory objectFactory = new WebObjectFactory(CONTEXTPATH, false); - TestWebObjectDefinitionReader reader = new TestWebObjectDefinitionReader(objectFactory.ContextPath, objectFactory, new XmlUrlResolver()); + WebObjectFactory objectFactory = new WebObjectFactory(CONTEXTPATH, false); + TestWebObjectDefinitionReader reader = new TestWebObjectDefinitionReader(objectFactory.ContextPath, objectFactory, new XmlUrlResolver()); - using (VirtualEnvironmentMock env = new VirtualEnvironmentMock(CONTEXTPATH + "test.aspx", null, null, CONTEXTPATH, true)) - { - env.VirtualPath2ArtifactsTable[CONTEXTPATH + "MyPage.aspx"] = typeof(Spring.Web.UI.Page); - env.VirtualPath2ArtifactsTable[CONTEXTPATH + "MyControl.ascx"] = typeof(Spring.Web.UI.UserControl); + using (VirtualEnvironmentMock env = new VirtualEnvironmentMock(CONTEXTPATH + "test.aspx", null, null, CONTEXTPATH, true)) + { + env.VirtualPath2ArtifactsTable[CONTEXTPATH + "MyPage.aspx"] = typeof(Spring.Web.UI.Page); + env.VirtualPath2ArtifactsTable[CONTEXTPATH + "MyControl.ascx"] = typeof(Spring.Web.UI.UserControl); - reader.LoadObjectDefinitions(new StringResource(xml)); - } - - Assert.IsTrue(objectFactory.ContainsObjectDefinition("mypage")); - Assert.IsTrue(objectFactory.ContainsObject("mypageAlias")); - Assert.IsTrue(objectFactory.ContainsObjectDefinition("mycontrol")); - Assert.IsTrue(objectFactory.ContainsObject("mycontrolAlias")); + reader.LoadObjectDefinitions(new StringResource(xml)); } + + Assert.IsTrue(objectFactory.ContainsObjectDefinition("mypage")); + Assert.IsTrue(objectFactory.ContainsObject("mypageAlias")); + Assert.IsTrue(objectFactory.ContainsObjectDefinition("mycontrol")); + Assert.IsTrue(objectFactory.ContainsObject("mycontrolAlias")); } } \ No newline at end of file diff --git a/test/Spring/Spring.Web.Tests/TestSupport/DictionaryModelPersistenceMedium.cs b/test/Spring/Spring.Web.Tests/TestSupport/DictionaryModelPersistenceMedium.cs index 05065750..f36ac8e8 100644 --- a/test/Spring/Spring.Web.Tests/TestSupport/DictionaryModelPersistenceMedium.cs +++ b/test/Spring/Spring.Web.Tests/TestSupport/DictionaryModelPersistenceMedium.cs @@ -2,20 +2,19 @@ using System.Collections; using System.Web.UI; using Spring.Web.UI; -namespace Spring.TestSupport +namespace Spring.TestSupport; + +public class DictionaryModelPersistenceMedium : IModelPersistenceMedium { - public class DictionaryModelPersistenceMedium : IModelPersistenceMedium + private Hashtable _storage = new Hashtable(); + + public object LoadFromMedium(Control context) { - private Hashtable _storage = new Hashtable(); - - public object LoadFromMedium(Control context) - { - return _storage[context]; - } - - public void SaveToMedium(Control context, object modelToSave) - { - _storage[context] = modelToSave; - } + return _storage[context]; } -} \ No newline at end of file + + public void SaveToMedium(Control context, object modelToSave) + { + _storage[context] = modelToSave; + } +} diff --git a/test/Spring/Spring.Web.Tests/TestSupport/NUnitAdapter.cs b/test/Spring/Spring.Web.Tests/TestSupport/NUnitAdapter.cs index eb7c316c..e88042f7 100644 --- a/test/Spring/Spring.Web.Tests/TestSupport/NUnitAdapter.cs +++ b/test/Spring/Spring.Web.Tests/TestSupport/NUnitAdapter.cs @@ -1,14 +1,15 @@ #region Copyright (c) 2002, 2005 by James Shore + /******************************************************************************************************************** ' ' Copyright (c) 2002, 2005 by James Shore ' -' Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated -' documentation files (the "Software"), to deal in the Software without restriction, including without limitation +' Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +' documentation files (the "Software"), to deal in the Software without restriction, including without limitation ' the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and ' to permit persons to whom the Software is furnished to do so, subject to the following conditions: ' -' The above copyright notice and this permission notice shall be included in all copies or substantial portions +' The above copyright notice and this permission notice shall be included in all copies or substantial portions ' of the Software. ' ' THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO @@ -18,270 +19,265 @@ ' DEALINGS IN THE SOFTWARE. ' '******************************************************************************************************************/ + #endregion #region Instructions + /******************************************************************************************************************** - * - * This file allows NUnitAsp to be used with NUnit. To use, copy this file + * + * This file allows NUnitAsp to be used with NUnit. To use, copy this file * into your test project. For additional information, see the NUnitAsp * documentation in your download package or visit * http://nunitasp.sourceforge.net. - * + * *******************************************************************************************************************/ + #endregion using NUnit.Extensions.Asp; using NUnit.Framework; -namespace Spring.TestSupport -{ - /// - /// Base class for NUnitAsp test fixtures. Extend this class to use NUnitAsp. - /// - [TestFixture] - public abstract class WebFormTestCase : WebApplicationTests - { - private bool setupCalled = false; +namespace Spring.TestSupport; - protected WebFormTestCase(string virtualPath, string relativePhysicalPath) : base(virtualPath, relativePhysicalPath) - {} - - /// - /// Do not call. For use by NUnit only. - /// - [SetUp] - public void MasterSetUp() - { - setupCalled = true; - HttpClient.Default = new HttpClient(); - SetUp(); - } - - /// - /// Executed before each test method is run. Override in subclasses to do subclass - /// set up. NOTE: The [SetUp] attribute cannot be used in subclasses because it is already - /// in use. - /// - protected virtual void SetUp() - { - } - - /// - /// Do not call. For use by NUnit only. - /// - [TearDown] - public void MasterTearDown() - { - TearDown(); - } - - /// - /// Executed after each test method is run. Override in subclasses to do subclass - /// clean up. NOTE: [TearDown] attribute cannot be used in subclasses because it is - /// already in use. - /// - protected virtual void TearDown() - { - } - - /// - /// The web form currently loaded by the browser. - /// - protected WebFormTester CurrentWebForm - { - get - { - AssertSetUp(); - return new WebFormTester(HttpClient.Default); - } - } - - /// - /// The web browser. - /// - protected HttpClient Browser - { - get - { - AssertSetUp(); - return HttpClient.Default; - } - } - - private void AssertSetUp() - { - if (!setupCalled) - { - Assert.Fail("A required setup method in WebFormTestCase was not called. This is probably because you used the [SetUp] attribute in a subclass of WebFormTestCase. That is not supported. Override the SetUp() method instead."); - } - } - } +/// +/// Base class for NUnitAsp test fixtures. Extend this class to use NUnitAsp. +/// +[TestFixture] +public abstract class WebFormTestCase : WebApplicationTests +{ + private bool setupCalled = false; + protected WebFormTestCase(string virtualPath, string relativePhysicalPath) : base(virtualPath, relativePhysicalPath) + { + } + /// + /// Do not call. For use by NUnit only. + /// + [SetUp] + public void MasterSetUp() + { + setupCalled = true; + HttpClient.Default = new HttpClient(); + SetUp(); + } + /// + /// Executed before each test method is run. Override in subclasses to do subclass + /// set up. NOTE: The [SetUp] attribute cannot be used in subclasses because it is already + /// in use. + /// + protected virtual void SetUp() + { + } + /// + /// Do not call. For use by NUnit only. + /// + [TearDown] + public void MasterTearDown() + { + TearDown(); + } + /// + /// Executed after each test method is run. Override in subclasses to do subclass + /// clean up. NOTE: [TearDown] attribute cannot be used in subclasses because it is + /// already in use. + /// + protected virtual void TearDown() + { + } + /// + /// The web form currently loaded by the browser. + /// + protected WebFormTester CurrentWebForm + { + get + { + AssertSetUp(); + return new WebFormTester(HttpClient.Default); + } + } + /// + /// The web browser. + /// + protected HttpClient Browser + { + get + { + AssertSetUp(); + return HttpClient.Default; + } + } + private void AssertSetUp() + { + if (!setupCalled) + { + Assert.Fail("A required setup method in WebFormTestCase was not called. This is probably because you used the [SetUp] attribute in a subclass of WebFormTestCase. That is not supported. Override the SetUp() method instead."); + } + } +} // Everything below this line is for backwards compatibility and may be deleted. - /// - /// For backwards compatibility; will be deprecated in the future. - /// This class provides convenience methods for common assertions. You - /// should use Assert and WebAssert methods instead. - /// - public class CompatibilityAdapter - { - /// - /// For backwards compatibility; will be deprecated in the future. - /// - public static void AssertTrue(bool condition) - { - Assert.IsTrue(condition); - } +/// +/// For backwards compatibility; will be deprecated in the future. +/// This class provides convenience methods for common assertions. You +/// should use Assert and WebAssert methods instead. +/// +public class CompatibilityAdapter +{ + /// + /// For backwards compatibility; will be deprecated in the future. + /// + public static void AssertTrue(bool condition) + { + Assert.IsTrue(condition); + } - /// - /// For backwards compatibility; will be deprecated in the future. - /// - public static void AssertTrue(string message, bool condition) - { - Assert.IsTrue(condition, message); - } + /// + /// For backwards compatibility; will be deprecated in the future. + /// + public static void AssertTrue(string message, bool condition) + { + Assert.IsTrue(condition, message); + } - /// - /// For backwards compatibility; will be deprecated in the future. - /// - public static void AssertEquals(object expected, object actual) - { - Assert.AreEqual(expected, actual); - } + /// + /// For backwards compatibility; will be deprecated in the future. + /// + public static void AssertEquals(object expected, object actual) + { + Assert.AreEqual(expected, actual); + } - /// - /// For backwards compatibility; will be deprecated in the future. - /// - public static void AssertEquals(string message, object expected, object actual) - { - Assert.AreEqual(expected, actual, message); - } + /// + /// For backwards compatibility; will be deprecated in the future. + /// + public static void AssertEquals(string message, object expected, object actual) + { + Assert.AreEqual(expected, actual, message); + } - /// - /// For backwards compatibility; will be deprecated in the future. - /// - public static void AssertNotNull(object o) - { - Assert.IsNotNull(o); - } + /// + /// For backwards compatibility; will be deprecated in the future. + /// + public static void AssertNotNull(object o) + { + Assert.IsNotNull(o); + } - /// - /// For backwards compatibility; will be deprecated in the future. - /// - public static void AssertNotNull(string message, object o) - { - Assert.IsNotNull(o, message); - } + /// + /// For backwards compatibility; will be deprecated in the future. + /// + public static void AssertNotNull(string message, object o) + { + Assert.IsNotNull(o, message); + } - /// - /// For backwards compatibility; will be deprecated in the future. - /// - public static void AssertNull(object o) - { - Assert.IsNull(o); - } + /// + /// For backwards compatibility; will be deprecated in the future. + /// + public static void AssertNull(object o) + { + Assert.IsNull(o); + } - /// - /// For backwards compatibility; will be deprecated in the future. - /// - public static void AssertNull(string message, object o) - { - Assert.IsNull(o, message); - } + /// + /// For backwards compatibility; will be deprecated in the future. + /// + public static void AssertNull(string message, object o) + { + Assert.IsNull(o, message); + } - /// - /// For backwards compatibility; will be deprecated in the future. - /// - public static void AssertSame(object expected, object actual) - { - Assert.AreSame(expected, actual); - } + /// + /// For backwards compatibility; will be deprecated in the future. + /// + public static void AssertSame(object expected, object actual) + { + Assert.AreSame(expected, actual); + } - /// - /// For backwards compatibility; will be deprecated in the future. - /// - public static void AssertSame(string message, object expected, object actual) - { - Assert.AreSame(expected, actual, message); - } + /// + /// For backwards compatibility; will be deprecated in the future. + /// + public static void AssertSame(string message, object expected, object actual) + { + Assert.AreSame(expected, actual, message); + } - /// - /// For backwards compatibility; will be deprecated in the future. - /// - public static void Fail(string message) - { - Assert.Fail(message); - } + /// + /// For backwards compatibility; will be deprecated in the future. + /// + public static void Fail(string message) + { + Assert.Fail(message); + } - /// - /// For backwards compatibility; will be deprecated in the future. - /// - public static void AssertVisibility(ControlTester tester, bool expectedVisibility) - { - if (expectedVisibility) WebAssert.Visible(tester); - else WebAssert.NotVisible(tester); - } + /// + /// For backwards compatibility; will be deprecated in the future. + /// + public static void AssertVisibility(ControlTester tester, bool expectedVisibility) + { + if (expectedVisibility) WebAssert.Visible(tester); + else WebAssert.NotVisible(tester); + } - /// - /// For backwards compatibility; will be deprecated in the future. - /// - public static void AssertEquals(string[] expected, string[] actual) - { - WebAssert.AreEqual(expected, actual); - } + /// + /// For backwards compatibility; will be deprecated in the future. + /// + public static void AssertEquals(string[] expected, string[] actual) + { + WebAssert.AreEqual(expected, actual); + } - /// - /// For backwards compatibility; will be deprecated in the future. - /// - public static void AssertEquals(string message, string[] expected, string[] actual) - { - WebAssert.AreEqual(expected, actual, message); - } + /// + /// For backwards compatibility; will be deprecated in the future. + /// + public static void AssertEquals(string message, string[] expected, string[] actual) + { + WebAssert.AreEqual(expected, actual, message); + } - /// - /// For backwards compatibility; will be deprecated in the future. - /// - //[CLSCompliant(false)] - public static void AssertEquals(string[][] expected, string[][] actual) - { - WebAssert.AreEqual(expected, actual); - } + /// + /// For backwards compatibility; will be deprecated in the future. + /// + //[CLSCompliant(false)] + public static void AssertEquals(string[][] expected, string[][] actual) + { + WebAssert.AreEqual(expected, actual); + } - /// - /// For backwards compatibility; will be deprecated in the future. - /// - //[CLSCompliant(false)] - public static void AssertEquals(string message, string[][] expected, string[][] actual) - { - WebAssert.AreEqual(expected, actual, message); - } + /// + /// For backwards compatibility; will be deprecated in the future. + /// + //[CLSCompliant(false)] + public static void AssertEquals(string message, string[][] expected, string[][] actual) + { + WebAssert.AreEqual(expected, actual, message); + } - /// - /// For backwards compatibility; will be deprecated in the future. - /// - //[CLSCompliant(false)] - public static void AssertEqualsIgnoreOrder(string message, string[][] expected, string[][] actual) - { - WebAssert.AreEqualIgnoringOrder(expected, actual, message); - } + /// + /// For backwards compatibility; will be deprecated in the future. + /// + //[CLSCompliant(false)] + public static void AssertEqualsIgnoreOrder(string message, string[][] expected, string[][] actual) + { + WebAssert.AreEqualIgnoringOrder(expected, actual, message); + } - /// - /// For backwards compatibility; will be deprecated in the future. - /// - //[CLSCompliant(false)] - public static void AssertSortOrder(string message, string[][] data, int column, bool isAscending, DataType type) - { - WebAssert.Sorted(data, column, isAscending, type, message); - } - } -} \ No newline at end of file + /// + /// For backwards compatibility; will be deprecated in the future. + /// + //[CLSCompliant(false)] + public static void AssertSortOrder(string message, string[][] data, int column, bool isAscending, DataType type) + { + WebAssert.Sorted(data, column, isAscending, type, message); + } +} diff --git a/test/Spring/Spring.Web.Tests/TestSupport/SessionMock.cs b/test/Spring/Spring.Web.Tests/TestSupport/SessionMock.cs index 802dadf9..5ce50f2e 100644 --- a/test/Spring/Spring.Web.Tests/TestSupport/SessionMock.cs +++ b/test/Spring/Spring.Web.Tests/TestSupport/SessionMock.cs @@ -3,81 +3,80 @@ using System.Web; using System.Web.SessionState; using Spring.Util; -namespace Spring.TestSupport +namespace Spring.TestSupport; + +/// +/// Test Session implementation +/// +public class SessionMock : Hashtable, ISessionState { - /// - /// Test Session implementation - /// - public class SessionMock : Hashtable, ISessionState + private bool _isCookieless; + private bool _isNewSession; + private int _lcid; + private SessionStateMode _mode; + private string _sessionID; + private int _codePage; + private HttpCookieMode _cookieMode; + + public SessionMock() : base(CaseInsensitiveHashCodeProvider.Default, CaseInsensitiveComparer.Default) { - private bool _isCookieless; - private bool _isNewSession; - private int _lcid; - private SessionStateMode _mode; - private string _sessionID; - private int _codePage; - private HttpCookieMode _cookieMode; + Reset(); + } - public SessionMock() : base(CaseInsensitiveHashCodeProvider.Default, CaseInsensitiveComparer.Default) - { - Reset(); - } + protected virtual void Reset() + { + _sessionID = Guid.NewGuid().ToString(); + _isNewSession = false; + _isCookieless = false; + _mode = SessionStateMode.InProc; + _codePage = -1; + _cookieMode = HttpCookieMode.AutoDetect; + } - protected virtual void Reset() - { - _sessionID = Guid.NewGuid().ToString(); - _isNewSession = false; - _isCookieless = false; - _mode = SessionStateMode.InProc; - _codePage = -1; - _cookieMode = HttpCookieMode.AutoDetect; - } + public void Abandon() + { + Reset(); + } - public void Abandon() - { - Reset(); - } + public bool IsCookieless + { + get { return _isCookieless; } + set { _isCookieless = value; } + } - public bool IsCookieless - { - get { return _isCookieless; } - set { _isCookieless = value; } - } + public bool IsNewSession + { + get { return _isNewSession; } + set { _isNewSession = value; } + } - public bool IsNewSession - { - get { return _isNewSession; } - set { _isNewSession = value; } - } + public int LCID + { + get { return _lcid; } + set { _lcid = value; } + } - public int LCID - { - get { return _lcid; } - set { _lcid = value; } - } + public SessionStateMode Mode + { + get { return _mode; } + set { _mode = value; } + } - public SessionStateMode Mode - { - get { return _mode; } - set { _mode = value; } - } + public string SessionID + { + get { return _sessionID; } + set { _sessionID = value; } + } - public string SessionID - { - get { return _sessionID; } - set { _sessionID = value; } - } + public int CodePage + { + get { return _codePage; } + set { _codePage = value; } + } - public int CodePage - { - get { return _codePage; } - set { _codePage = value; } - } - - public HttpCookieMode CookieMode - { - get { return _cookieMode; } - set { _cookieMode = value; } - } + public HttpCookieMode CookieMode + { + get { return _cookieMode; } + set { _cookieMode = value; } } } diff --git a/test/Spring/Spring.Web.Tests/TestSupport/TestPage.cs b/test/Spring/Spring.Web.Tests/TestSupport/TestPage.cs index b1fb519a..accb8db3 100644 --- a/test/Spring/Spring.Web.Tests/TestSupport/TestPage.cs +++ b/test/Spring/Spring.Web.Tests/TestSupport/TestPage.cs @@ -2,77 +2,76 @@ using System.Reflection; using System.Web; using System.Web.UI; using Spring.Collections; -using Page=Spring.Web.UI.Page; +using Page = Spring.Web.UI.Page; -namespace Spring.TestSupport +namespace Spring.TestSupport; + +public class TestPage : Page { - public class TestPage : Page + public TestPage() { - public TestPage() - { - this.SharedState = new CaseInsensitiveHashtable(); //CollectionsUtil.CreateCaseInsensitiveHashtable(); - } + this.SharedState = new CaseInsensitiveHashtable(); //CollectionsUtil.CreateCaseInsensitiveHashtable(); + } - public TestPage( HttpContext context ) - :this() - { - SetIntrinsics(context); - } + public TestPage(HttpContext context) + : this() + { + SetIntrinsics(context); + } - public virtual void SetIntrinsics(HttpContext context) - { - MethodInfo miSetIntrinsics = typeof(System.Web.UI.Page).GetMethod("SetIntrinsics",BindingFlags.Instance|BindingFlags.NonPublic, null, new Type[] { typeof(HttpContext) }, null); - miSetIntrinsics.Invoke(this, new object[] {context}); - } + public virtual void SetIntrinsics(HttpContext context) + { + MethodInfo miSetIntrinsics = typeof(System.Web.UI.Page).GetMethod("SetIntrinsics", BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[] { typeof(HttpContext) }, null); + miSetIntrinsics.Invoke(this, new object[] { context }); + } - public virtual void InitRecursive( Control namingContainer ) - { - MethodInfo miInitRecursive = typeof(System.Web.UI.Control).GetMethod("InitRecursive", BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[] { typeof(Control) }, null); - miInitRecursive.Invoke(this, new object[] {null}); - } + public virtual void InitRecursive(Control namingContainer) + { + MethodInfo miInitRecursive = typeof(System.Web.UI.Control).GetMethod("InitRecursive", BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[] { typeof(Control) }, null); + miInitRecursive.Invoke(this, new object[] { null }); + } - public new virtual void InitializeCulture() - { - base.InitializeCulture(); - } + public new virtual void InitializeCulture() + { + base.InitializeCulture(); + } - public override System.Web.SessionState.HttpSessionState Session + public override System.Web.SessionState.HttpSessionState Session + { + get { - get - { - return null; - } + return null; } + } // protected override IDictionary CreateValidatorParameters() // { // return null; // } - public new void SetResult(string resultName) - { - base.SetResult(resultName); - } + public new void SetResult(string resultName) + { + base.SetResult(resultName); + } - public string Render(string newLine) - { - StringWriter sw = new StringWriter(); - HtmlTextWriter writer = new HtmlTextWriter(sw, ""); - writer.NewLine = newLine; - base.Render(writer); - writer.Flush(); - writer.Close(); - string result = sw.GetStringBuilder().ToString(); - return result; - } + public string Render(string newLine) + { + StringWriter sw = new StringWriter(); + HtmlTextWriter writer = new HtmlTextWriter(sw, ""); + writer.NewLine = newLine; + base.Render(writer); + writer.Flush(); + writer.Close(); + string result = sw.GetStringBuilder().ToString(); + return result; + } - public new void SaveModelToPersistenceMedium(object model) - { - base.SaveModelToPersistenceMedium(model); - } + public new void SaveModelToPersistenceMedium(object model) + { + base.SaveModelToPersistenceMedium(model); + } - public new object LoadModelFromPersistenceMedium() - { - return base.LoadModelFromPersistenceMedium(); - } + public new object LoadModelFromPersistenceMedium() + { + return base.LoadModelFromPersistenceMedium(); } } diff --git a/test/Spring/Spring.Web.Tests/TestSupport/TestUserControl.cs b/test/Spring/Spring.Web.Tests/TestSupport/TestUserControl.cs index 730a3897..e1421506 100644 --- a/test/Spring/Spring.Web.Tests/TestSupport/TestUserControl.cs +++ b/test/Spring/Spring.Web.Tests/TestSupport/TestUserControl.cs @@ -1,52 +1,50 @@ - using System.Web.UI; -using UserControl=Spring.Web.UI.UserControl; +using UserControl = Spring.Web.UI.UserControl; -namespace Spring.TestSupport +namespace Spring.TestSupport; + +public class TestUserControl : UserControl { - public class TestUserControl : UserControl + private static int instanceCount = 0; + + public TestUserControl() + : this(string.Format("_ctl_{0}", instanceCount++), null) { - private static int instanceCount = 0; - - public TestUserControl() - :this(string.Format("_ctl_{0}", instanceCount++), null) - { - } - - public TestUserControl(string id) - :this(id, null) - { - } - - public TestUserControl(Control parent) - :this(null, parent) - { - } - - public TestUserControl(string id, Control parent) - { - this.ID = id; - if (parent != null) parent.Controls.Add(this); - } - - public new void SetResult(string name) - { - base.SetResult(name); - } - - public override string ToString() - { - return string.Format("{0}[{1}]", base.ToString(), this.ClientID); - } - - public new void SaveModelToPersistenceMedium(object model) - { - base.SaveModelToPersistenceMedium(model); - } - - public new object LoadModelFromPersistenceMedium() - { - return base.LoadModelFromPersistenceMedium(); - } } -} \ No newline at end of file + + public TestUserControl(string id) + : this(id, null) + { + } + + public TestUserControl(Control parent) + : this(null, parent) + { + } + + public TestUserControl(string id, Control parent) + { + this.ID = id; + if (parent != null) parent.Controls.Add(this); + } + + public new void SetResult(string name) + { + base.SetResult(name); + } + + public override string ToString() + { + return string.Format("{0}[{1}]", base.ToString(), this.ClientID); + } + + public new void SaveModelToPersistenceMedium(object model) + { + base.SaveModelToPersistenceMedium(model); + } + + public new object LoadModelFromPersistenceMedium() + { + return base.LoadModelFromPersistenceMedium(); + } +} diff --git a/test/Spring/Spring.Web.Tests/TestSupport/TestWebContext.cs b/test/Spring/Spring.Web.Tests/TestSupport/TestWebContext.cs index ca908a76..6868792e 100644 --- a/test/Spring/Spring.Web.Tests/TestSupport/TestWebContext.cs +++ b/test/Spring/Spring.Web.Tests/TestSupport/TestWebContext.cs @@ -27,75 +27,74 @@ using Spring.Expressions; #endregion -namespace Spring.TestSupport +namespace Spring.TestSupport; + +public class TestWebContext : IDisposable { - public class TestWebContext : IDisposable + private readonly TextWriter _out; + private readonly HttpWorkerRequest _wr; + [ThreadStatic] private static TestWebContext _wc; + + public static void Create(string virtualPath, string page) { - private readonly TextWriter _out; - private readonly HttpWorkerRequest _wr; - [ThreadStatic] - private static TestWebContext _wc; + _wc = new TestWebContext(virtualPath, page); + } - public static void Create(string virtualPath, string page) + public static void Release() + { + if (_wc != null) { - _wc = new TestWebContext(virtualPath, page); - } - - public static void Release() - { - if (_wc != null) - { - _wc.Dispose(); - } - } - - public TestWebContext(string virtualPath, string page) - { - _out = new StringWriter(); - HttpWorkerRequest wr; - AppDomain domain = Thread.GetDomain(); - - // are we running within a valid AspNet AppDomain? - string appPath = (string) domain.GetData(".appPath"); - if (appPath != null) - { - wr = new SimpleWorkerRequest(page, string.Empty, _out); - } - else - { - appPath = domain.BaseDirectory + "\\"; - wr = new SimpleWorkerRequest(virtualPath, appPath, page, string.Empty, _out); - } - HttpContext ctx = new HttpContext(wr); - HttpContext.Current = ctx; - HttpBrowserCapabilities browser = new HttpBrowserCapabilities(); - browser.Capabilities = new CaseInsensitiveHashtable(); //CollectionsUtil.CreateCaseInsensitiveHashtable(); - browser.Capabilities[string.Empty] = "Test User Agent"; // string.Empty is the key for "user agent" - - // avoids NullReferenceException when accessing HttpRequest.FilePath - object virtualPathObject = ExpressionEvaluator.GetValue(null, "T(System.Web.VirtualPath).Create('/')"); - object cachedPathData = ExpressionEvaluator.GetValue(null, "T(System.Web.CachedPathData).GetRootWebPathData()"); - ExpressionEvaluator.SetValue(cachedPathData, "_virtualPath", virtualPathObject); - ExpressionEvaluator.SetValue(cachedPathData, "_physicalPath", appPath); - - ctx.Request.Browser = browser; - string filePath = ctx.Request.FilePath; - _wr = wr; - } - - public HttpWorkerRequest HttpWorkerRequest - { - get { return _wr; } - } - - public TextWriter Out - { - get { return _out; } - } - - public void Dispose() - { - HttpContext.Current = null; + _wc.Dispose(); } } + + public TestWebContext(string virtualPath, string page) + { + _out = new StringWriter(); + HttpWorkerRequest wr; + AppDomain domain = Thread.GetDomain(); + + // are we running within a valid AspNet AppDomain? + string appPath = (string) domain.GetData(".appPath"); + if (appPath != null) + { + wr = new SimpleWorkerRequest(page, string.Empty, _out); + } + else + { + appPath = domain.BaseDirectory + "\\"; + wr = new SimpleWorkerRequest(virtualPath, appPath, page, string.Empty, _out); + } + + HttpContext ctx = new HttpContext(wr); + HttpContext.Current = ctx; + HttpBrowserCapabilities browser = new HttpBrowserCapabilities(); + browser.Capabilities = new CaseInsensitiveHashtable(); //CollectionsUtil.CreateCaseInsensitiveHashtable(); + browser.Capabilities[string.Empty] = "Test User Agent"; // string.Empty is the key for "user agent" + + // avoids NullReferenceException when accessing HttpRequest.FilePath + object virtualPathObject = ExpressionEvaluator.GetValue(null, "T(System.Web.VirtualPath).Create('/')"); + object cachedPathData = ExpressionEvaluator.GetValue(null, "T(System.Web.CachedPathData).GetRootWebPathData()"); + ExpressionEvaluator.SetValue(cachedPathData, "_virtualPath", virtualPathObject); + ExpressionEvaluator.SetValue(cachedPathData, "_physicalPath", appPath); + + ctx.Request.Browser = browser; + string filePath = ctx.Request.FilePath; + _wr = wr; + } + + public HttpWorkerRequest HttpWorkerRequest + { + get { return _wr; } + } + + public TextWriter Out + { + get { return _out; } + } + + public void Dispose() + { + HttpContext.Current = null; + } } diff --git a/test/Spring/Spring.Web.Tests/TestSupport/TestWebContextTests.cs b/test/Spring/Spring.Web.Tests/TestSupport/TestWebContextTests.cs index 9ff68b0a..a5907121 100644 --- a/test/Spring/Spring.Web.Tests/TestSupport/TestWebContextTests.cs +++ b/test/Spring/Spring.Web.Tests/TestSupport/TestWebContextTests.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -25,37 +25,36 @@ using Spring.Globalization; #endregion -namespace Spring.TestSupport +namespace Spring.TestSupport; + +/// +/// The base class for tests to run within a TestWebContext +/// +/// Erich Eichinger +public abstract class TestWebContextTests { - /// - /// The base class for tests to run within a TestWebContext - /// - /// Erich Eichinger - public abstract class TestWebContextTests + [SetUp] + public void SetUp() { - [SetUp] - public void SetUp() - { - // ensure, uiCulture and culture are set to different cultures - CultureTestScope.Set(); - TestWebContext.Create("/apppath", "testpage.aspx"); - DoSetUp(); - } - - [TearDown] - public void TearDown() - { - DoTearDown(); - TestWebContext.Release(); - CultureTestScope.Reset(); - } - - protected virtual void DoSetUp() - { - } - - protected void DoTearDown() - { - } + // ensure, uiCulture and culture are set to different cultures + CultureTestScope.Set(); + TestWebContext.Create("/apppath", "testpage.aspx"); + DoSetUp(); } -} \ No newline at end of file + + [TearDown] + public void TearDown() + { + DoTearDown(); + TestWebContext.Release(); + CultureTestScope.Reset(); + } + + protected virtual void DoSetUp() + { + } + + protected void DoTearDown() + { + } +} diff --git a/test/Spring/Spring.Web.Tests/TestSupport/VirtualEnvironmentMock.cs b/test/Spring/Spring.Web.Tests/TestSupport/VirtualEnvironmentMock.cs index eb4763b1..b422d722 100644 --- a/test/Spring/Spring.Web.Tests/TestSupport/VirtualEnvironmentMock.cs +++ b/test/Spring/Spring.Web.Tests/TestSupport/VirtualEnvironmentMock.cs @@ -5,296 +5,306 @@ using System.Web; using Spring.Collections; using Spring.Util; -namespace Spring.TestSupport +namespace Spring.TestSupport; + +/// +/// Test environment implementation. +/// +/// Erich Eichinger +public class VirtualEnvironmentMock : IVirtualEnvironment, IDisposable { - /// - /// Test environment implementation. - /// - /// Erich Eichinger - public class VirtualEnvironmentMock : IVirtualEnvironment, IDisposable + private readonly IVirtualEnvironment _prevEnvironment; + + private string _currentVirtualFilePath; + private string _pathInfo; + private HttpValueCollection _query; + private string _currentExecutionFilePath; + private readonly string _applicationVirtualPath; + private ISessionState _session = new SessionMock(); + private IDictionary _requestVariables = new CaseInsensitiveHashtable(); //CollectionsUtil.CreateCaseInsensitiveHashtable(); + private NameValueCollection requestParams = new NameValueCollection(); + private IDictionary virtualPath2ArtifactsTable = new CaseInsensitiveHashtable(); + + public VirtualEnvironmentMock(string currentVirtualFilePath, string pathInfo, string queryText, string applicationVirtualPath, bool autoInitialize) { - private readonly IVirtualEnvironment _prevEnvironment; - - private string _currentVirtualFilePath; - private string _pathInfo; - private HttpValueCollection _query; - private string _currentExecutionFilePath; - private readonly string _applicationVirtualPath; - private ISessionState _session = new SessionMock(); - private IDictionary _requestVariables = new CaseInsensitiveHashtable(); //CollectionsUtil.CreateCaseInsensitiveHashtable(); - private NameValueCollection requestParams = new NameValueCollection(); - private IDictionary virtualPath2ArtifactsTable = new CaseInsensitiveHashtable(); - - public VirtualEnvironmentMock(string currentVirtualFilePath, string pathInfo, string queryText, string applicationVirtualPath, bool autoInitialize) - { - _currentVirtualFilePath = currentVirtualFilePath; - _currentExecutionFilePath = currentVirtualFilePath; - _pathInfo = (pathInfo == null || pathInfo.Length == 0) ? "" : "/" + pathInfo.TrimStart('/'); // prevent null string and ensure '/' prefixed - _query = new HttpValueCollection(queryText); - _applicationVirtualPath = "/" + ("" + applicationVirtualPath).Trim('/'); - if (!_applicationVirtualPath.EndsWith("/")) _applicationVirtualPath = _applicationVirtualPath + "/"; + _currentVirtualFilePath = currentVirtualFilePath; + _currentExecutionFilePath = currentVirtualFilePath; + _pathInfo = (pathInfo == null || pathInfo.Length == 0) ? "" : "/" + pathInfo.TrimStart('/'); // prevent null string and ensure '/' prefixed + _query = new HttpValueCollection(queryText); + _applicationVirtualPath = "/" + ("" + applicationVirtualPath).Trim('/'); + if (!_applicationVirtualPath.EndsWith("/")) _applicationVirtualPath = _applicationVirtualPath + "/"; // if (!_currentVirtualFilePath.StartsWith(_applicationVirtualPath)) // { // throw new ArgumentException("currentVirtualFilePath must begin with applicationVirtualPath"); // } - _prevEnvironment = VirtualEnvironment.SetInstance(this); - if (autoInitialize) + _prevEnvironment = VirtualEnvironment.SetInstance(this); + if (autoInitialize) + { + VirtualEnvironment.SetInitialized(); + } + } + + public IDictionary VirtualPath2ArtifactsTable + { + get { return virtualPath2ArtifactsTable; } + } + + public string ApplicationVirtualPath + { + get { return _applicationVirtualPath; } + } + + public string CurrentVirtualPath + { + get { return _currentVirtualFilePath + _pathInfo; } + } + + public string CurrentVirtualPathAndQuery + { + get + { + string result = _currentVirtualFilePath + _pathInfo; + if (_query.Count > 0) { - VirtualEnvironment.SetInitialized(); - } - } - - public IDictionary VirtualPath2ArtifactsTable - { - get { return virtualPath2ArtifactsTable; } - } - - public string ApplicationVirtualPath - { - get { return _applicationVirtualPath; } - } - - public string CurrentVirtualPath - { - get { return _currentVirtualFilePath + _pathInfo; } - } - - public string CurrentVirtualPathAndQuery - { - get - { - string result = _currentVirtualFilePath + _pathInfo; - if (_query.Count > 0) - { - result = result + "?" + _query.ToString(); - } - return result; - } - } - - public string CurrentVirtualFilePath - { - get { return _currentVirtualFilePath; } - } - - public string CurrentExecutionFilePath - { - get { return this._currentExecutionFilePath; } - set { this._currentExecutionFilePath = value; } - } - - public NameValueCollection QueryString - { - get { return _query; } - } - - public string MapPath(string virtualPath) - { - string basePath = Path.GetDirectoryName(new Uri(GetType().Assembly.CodeBase).LocalPath); - string resultPath = WebUtils.CreateAbsolutePath(this.CurrentVirtualFilePath, virtualPath); - resultPath = basePath.TrimEnd('\\') + "\\" + resultPath.Replace('/', '\\').TrimStart('\\'); - return resultPath; - } - - public IDisposable RewritePath(string newVirtualPath, bool rebaseClientPath) - { - IDisposable ctx = new RewriteContext(CurrentVirtualPathAndQuery, false, this); - - int index = newVirtualPath.IndexOf('?'); - if (index >= 0) - { - string newQueryString = (index < (newVirtualPath.Length - 1)) ? newVirtualPath.Substring(index + 1) : string.Empty; - _query = new HttpValueCollection(newQueryString); - newVirtualPath = newVirtualPath.Substring(0, index); + result = result + "?" + _query.ToString(); } - _currentVirtualFilePath = newVirtualPath; + return result; + } + } - return ctx; + public string CurrentVirtualFilePath + { + get { return _currentVirtualFilePath; } + } + + public string CurrentExecutionFilePath + { + get { return this._currentExecutionFilePath; } + set { this._currentExecutionFilePath = value; } + } + + public NameValueCollection QueryString + { + get { return _query; } + } + + public string MapPath(string virtualPath) + { + string basePath = Path.GetDirectoryName(new Uri(GetType().Assembly.CodeBase).LocalPath); + string resultPath = WebUtils.CreateAbsolutePath(this.CurrentVirtualFilePath, virtualPath); + resultPath = basePath.TrimEnd('\\') + "\\" + resultPath.Replace('/', '\\').TrimStart('\\'); + return resultPath; + } + + public IDisposable RewritePath(string newVirtualPath, bool rebaseClientPath) + { + IDisposable ctx = new RewriteContext(CurrentVirtualPathAndQuery, false, this); + + int index = newVirtualPath.IndexOf('?'); + if (index >= 0) + { + string newQueryString = (index < (newVirtualPath.Length - 1)) ? newVirtualPath.Substring(index + 1) : string.Empty; + _query = new HttpValueCollection(newQueryString); + newVirtualPath = newVirtualPath.Substring(0, index); } - public Type GetCompiledType(string virtualPath) - { - object o = virtualPath2ArtifactsTable[virtualPath]; - if (o == null) - throw new FileNotFoundException(virtualPath); - else if (o is Type) - return (Type) o; - else - return o.GetType(); - } + _currentVirtualFilePath = newVirtualPath; - public object CreateInstanceFromVirtualPath(string virtualPath, Type requiredBaseType) - { - object o = virtualPath2ArtifactsTable[virtualPath]; - if (o == null) - throw new FileNotFoundException(virtualPath); - else if (o is Type) - return Activator.CreateInstance((Type)o); - else - return o; - } + return ctx; + } - public ISessionState Session - { - get { return _session; } - set { _session = value; } - } + public Type GetCompiledType(string virtualPath) + { + object o = virtualPath2ArtifactsTable[virtualPath]; + if (o == null) + throw new FileNotFoundException(virtualPath); + else if (o is Type) + return (Type) o; + else + return o.GetType(); + } - public IDictionary RequestVariables - { - get { return _requestVariables; } - set { _requestVariables = value; } - } + public object CreateInstanceFromVirtualPath(string virtualPath, Type requiredBaseType) + { + object o = virtualPath2ArtifactsTable[virtualPath]; + if (o == null) + throw new FileNotFoundException(virtualPath); + else if (o is Type) + return Activator.CreateInstance((Type) o); + else + return o; + } - public NameValueCollection RequestParams + public ISessionState Session + { + get { return _session; } + set { _session = value; } + } + + public IDictionary RequestVariables + { + get { return _requestVariables; } + set { _requestVariables = value; } + } + + public NameValueCollection RequestParams + { + get { return requestParams; } + } + + public void Dispose() + { + VirtualEnvironment.SetInstance(_prevEnvironment); + } + + private class RewriteContext : IDisposable + { + private string originalPath; + private bool rebaseClientPath; + private VirtualEnvironmentMock runtime; + + public RewriteContext(string originalPath, bool rebaseClientPath, VirtualEnvironmentMock runtime) { - get { return requestParams; } + this.originalPath = originalPath; + this.rebaseClientPath = rebaseClientPath; + this.runtime = runtime; } public void Dispose() { - VirtualEnvironment.SetInstance(_prevEnvironment); + if (originalPath != null) + { + this.runtime.RewritePath(originalPath, rebaseClientPath); + } + } + } + + private class HttpValueCollection : NameValueCollection + { + public HttpValueCollection(string queryText) + { + FillFromString(queryText, false, Encoding.UTF8); } - private class RewriteContext : IDisposable + public override string ToString() { - private string originalPath; - private bool rebaseClientPath; - private VirtualEnvironmentMock runtime; + return ToString(true); + } - public RewriteContext(string originalPath, bool rebaseClientPath, VirtualEnvironmentMock runtime) + private void FillFromString(string s, bool urlencoded, Encoding encoding) + { + int num = (s != null) ? s.Length : 0; + for (int i = 0; i < num; i++) { - this.originalPath = originalPath; - this.rebaseClientPath = rebaseClientPath; - this.runtime = runtime; - } - - public void Dispose() - { - if (originalPath != null) + int startIndex = i; + int num4 = -1; + while (i < num) { - this.runtime.RewritePath(originalPath, rebaseClientPath); + char ch = s[i]; + if (ch == '=') + { + if (num4 < 0) + { + num4 = i; + } + } + else if (ch == '&') + { + break; + } + + i++; + } + + string str = null; + string str2 = null; + if (num4 >= 0) + { + str = s.Substring(startIndex, num4 - startIndex); + str2 = s.Substring(num4 + 1, (i - num4) - 1); + } + else + { + str2 = s.Substring(startIndex, i - startIndex); + } + + if (urlencoded) + { + base.Add(HttpUtility.UrlDecode(str, encoding), HttpUtility.UrlDecode(str2, encoding)); + } + else + { + base.Add(str, str2); + } + + if ((i == (num - 1)) && (s[i] == '&')) + { + base.Add(null, string.Empty); } } } - private class HttpValueCollection : NameValueCollection + internal virtual string ToString(bool urlencoded) { - public HttpValueCollection(string queryText) + StringBuilder builder = new StringBuilder(); + int count = this.Count; + for (int i = 0; i < count; i++) { - FillFromString(queryText, false, Encoding.UTF8); - } - - public override string ToString() - { - return ToString(true); - } - - private void FillFromString(string s, bool urlencoded, Encoding encoding) - { - int num = (s != null) ? s.Length : 0; - for (int i = 0; i < num; i++) + string str3; + string key = this.GetKey(i); + if (urlencoded) { - int startIndex = i; - int num4 = -1; - while (i < num) - { - char ch = s[i]; - if (ch == '=') - { - if (num4 < 0) - { - num4 = i; - } - } - else if (ch == '&') - { - break; - } - i++; - } - string str = null; - string str2 = null; - if (num4 >= 0) - { - str = s.Substring(startIndex, num4 - startIndex); - str2 = s.Substring(num4 + 1, (i - num4) - 1); - } - else - { - str2 = s.Substring(startIndex, i - startIndex); - } - if (urlencoded) - { - base.Add(HttpUtility.UrlDecode(str, encoding), HttpUtility.UrlDecode(str2, encoding)); - } - else - { - base.Add(str, str2); - } - if ((i == (num - 1)) && (s[i] == '&')) - { - base.Add(null, string.Empty); - } + key = HttpUtility.UrlEncodeUnicode(key); } - } - internal virtual string ToString(bool urlencoded) - { - StringBuilder builder = new StringBuilder(); - int count = this.Count; - for (int i = 0; i < count; i++) + string str2 = ((key != null) && (key.Length > 0)) ? (key + "=") : ""; + ArrayList list = (ArrayList) base.BaseGet(i); + int num3 = (list != null) ? list.Count : 0; + if (i > 0) { - string str3; - string key = this.GetKey(i); + builder.Append('&'); + } + + if (num3 == 1) + { + builder.Append(str2); + str3 = (string) list[0]; if (urlencoded) { - key = HttpUtility.UrlEncodeUnicode(key); + str3 = HttpUtility.UrlEncodeUnicode(str3); } - string str2 = ((key != null) && (key.Length > 0)) ? (key + "=") : ""; - ArrayList list = (ArrayList)base.BaseGet(i); - int num3 = (list != null) ? list.Count : 0; - if (i > 0) - { - builder.Append('&'); - } - if (num3 == 1) + + builder.Append(str3); + } + else if (num3 == 0) + { + builder.Append(str2); + } + else + { + for (int j = 0; j < num3; j++) { + if (j > 0) + { + builder.Append('&'); + } + builder.Append(str2); - str3 = (string)list[0]; + str3 = (string) list[j]; if (urlencoded) { str3 = HttpUtility.UrlEncodeUnicode(str3); } + builder.Append(str3); } - else if (num3 == 0) - { - builder.Append(str2); - } - else - { - for (int j = 0; j < num3; j++) - { - if (j > 0) - { - builder.Append('&'); - } - builder.Append(str2); - str3 = (string)list[j]; - if (urlencoded) - { - str3 = HttpUtility.UrlEncodeUnicode(str3); - } - builder.Append(str3); - } - } } - return builder.ToString(); } + + return builder.ToString(); } } } diff --git a/test/Spring/Spring.Web.Tests/TestSupport/VoidDelegate.cs b/test/Spring/Spring.Web.Tests/TestSupport/VoidDelegate.cs index 55b6fb14..8ae33d3d 100644 --- a/test/Spring/Spring.Web.Tests/TestSupport/VoidDelegate.cs +++ b/test/Spring/Spring.Web.Tests/TestSupport/VoidDelegate.cs @@ -1,7 +1,6 @@ -namespace Spring.TestSupport -{ - /// - /// Signature of a method with no args and no return type - /// - internal delegate void VoidDelegate(); -} \ No newline at end of file +namespace Spring.TestSupport; + +/// +/// Signature of a method with no args and no return type +/// +internal delegate void VoidDelegate(); \ No newline at end of file diff --git a/test/Spring/Spring.Web.Tests/TestSupport/WebApplicationTests.cs b/test/Spring/Spring.Web.Tests/TestSupport/WebApplicationTests.cs index cee76a3f..cd2f5698 100644 --- a/test/Spring/Spring.Web.Tests/TestSupport/WebApplicationTests.cs +++ b/test/Spring/Spring.Web.Tests/TestSupport/WebApplicationTests.cs @@ -22,39 +22,37 @@ using NUnit.Framework; using NUnitAspEx; using NUnitAspEx.Core; -namespace Spring.TestSupport +namespace Spring.TestSupport; + +/// +/// +/// Erich Eichinger +public abstract class WebApplicationTests { - /// - /// - /// Erich Eichinger - public abstract class WebApplicationTests + private readonly string virtualPath; + private readonly string relativePhysicalPath; + private IAspFixtureHost host; + + public IAspFixtureHost Host { - private readonly string virtualPath; - private readonly string relativePhysicalPath; - private IAspFixtureHost host; - - public IAspFixtureHost Host - { - get { return host; } - } - - protected WebApplicationTests(string virtualPath, string relativePhysicalPath) - { - this.virtualPath = virtualPath; - this.relativePhysicalPath = relativePhysicalPath; - } - - [OneTimeSetUp] - public virtual void TestFixtureSetup() - { - host = AspFixtureHost.CreateInstance(virtualPath, relativePhysicalPath, this); - } - - [OneTimeTearDown] - public virtual void TestFixtureTearDown() - { - host = AspFixtureHost.ReleaseInstance(host); - } - + get { return host; } } -} \ No newline at end of file + + protected WebApplicationTests(string virtualPath, string relativePhysicalPath) + { + this.virtualPath = virtualPath; + this.relativePhysicalPath = relativePhysicalPath; + } + + [OneTimeSetUp] + public virtual void TestFixtureSetup() + { + host = AspFixtureHost.CreateInstance(virtualPath, relativePhysicalPath, this); + } + + [OneTimeTearDown] + public virtual void TestFixtureTearDown() + { + host = AspFixtureHost.ReleaseInstance(host); + } +} diff --git a/test/Spring/Spring.Web.Tests/Threading/HttpContextStorageTests.cs b/test/Spring/Spring.Web.Tests/Threading/HttpContextStorageTests.cs index 4ece932f..8a611492 100644 --- a/test/Spring/Spring.Web.Tests/Threading/HttpContextStorageTests.cs +++ b/test/Spring/Spring.Web.Tests/Threading/HttpContextStorageTests.cs @@ -25,28 +25,27 @@ using NUnit.Framework; #endregion -namespace Spring.Threading +namespace Spring.Threading; + +/// +/// Apply common thread-storage tests for +/// +/// Erich Eichinger +[TestFixture] +public class HttpContextStorageTests : CommonThreadStorageTests { - /// - /// Apply common thread-storage tests for - /// - /// Erich Eichinger - [TestFixture] - public class HttpContextStorageTests : CommonThreadStorageTests + protected override IThreadStorage CreateStorage() { - protected override IThreadStorage CreateStorage() - { - return new HttpContextStorage(); - } + return new HttpContextStorage(); + } - protected override void ThreadSetup() - { - HttpContext.Current = new HttpContext(new HttpRequest("/page.aspx", "http://localhost/page.aspx", null), new HttpResponse(new StringWriter())); - } + protected override void ThreadSetup() + { + HttpContext.Current = new HttpContext(new HttpRequest("/page.aspx", "http://localhost/page.aspx", null), new HttpResponse(new StringWriter())); + } - protected override void ThreadCleanup() - { - HttpContext.Current = null; - } + protected override void ThreadCleanup() + { + HttpContext.Current = null; } } diff --git a/test/Spring/Spring.Web.Tests/Threading/HybridContextStorageTests.cs b/test/Spring/Spring.Web.Tests/Threading/HybridContextStorageTests.cs index abaecc91..0c6efa75 100644 --- a/test/Spring/Spring.Web.Tests/Threading/HybridContextStorageTests.cs +++ b/test/Spring/Spring.Web.Tests/Threading/HybridContextStorageTests.cs @@ -25,28 +25,27 @@ using NUnit.Framework; #endregion -namespace Spring.Threading +namespace Spring.Threading; + +/// +/// Apply common thread-storage tests for +/// +/// Erich Eichinger +[TestFixture] +public class HybridContextStorageTests : CommonThreadStorageTests { - /// - /// Apply common thread-storage tests for - /// - /// Erich Eichinger - [TestFixture] - public class HybridContextStorageTests : CommonThreadStorageTests + protected override IThreadStorage CreateStorage() { - protected override IThreadStorage CreateStorage() - { - return new HybridContextStorage(); - } + return new HybridContextStorage(); + } - protected override void ThreadSetup() - { - HttpContext.Current = new HttpContext(new HttpRequest("/page.aspx", "http://localhost/page.aspx", null), new HttpResponse(new StringWriter())); - } + protected override void ThreadSetup() + { + HttpContext.Current = new HttpContext(new HttpRequest("/page.aspx", "http://localhost/page.aspx", null), new HttpResponse(new StringWriter())); + } - protected override void ThreadCleanup() - { - HttpContext.Current = null; - } + protected override void ThreadCleanup() + { + HttpContext.Current = null; } } diff --git a/test/Spring/Spring.Web.Tests/Util/WebDIPerformanceTests.cs b/test/Spring/Spring.Web.Tests/Util/WebDIPerformanceTests.cs index 5fe61826..256312b7 100644 --- a/test/Spring/Spring.Web.Tests/Util/WebDIPerformanceTests.cs +++ b/test/Spring/Spring.Web.Tests/Util/WebDIPerformanceTests.cs @@ -26,44 +26,67 @@ using NUnit.Framework; using Spring.Context; using Spring.Context.Support; using Spring.TestSupport; - using System.Collections; #endregion -namespace Spring.Util +namespace Spring.Util; + +[TestFixture] +public class WebDIPerformanceTests { - [TestFixture] - public class WebDIPerformanceTests + private DataView CreateDataSource() { - private DataView CreateDataSource() + DataTable dt = new DataTable(); + DataRow dr; + + dt.Columns.Add(new DataColumn("IntegerValue", typeof(Int32))); + dt.Columns.Add(new DataColumn("StringValue", typeof(string))); + dt.Columns.Add(new DataColumn("CurrencyValue", typeof(double))); + + for (int i = 0; i < 100; i++) { - DataTable dt = new DataTable(); - DataRow dr; + dr = dt.NewRow(); - dt.Columns.Add(new DataColumn("IntegerValue", typeof(Int32))); - dt.Columns.Add(new DataColumn("StringValue", typeof(string))); - dt.Columns.Add(new DataColumn("CurrencyValue", typeof(double))); + dr[0] = i; + dr[1] = "Item " + i; + dr[2] = 1.23 * (i + 1); - for (int i = 0; i < 100; i++) - { - dr = dt.NewRow(); - - dr[0] = i; - dr[1] = "Item " + i; - dr[2] = 1.23 * (i + 1); - - dt.Rows.Add(dr); - } - - DataView dv = new DataView(dt); - return dv; + dt.Rows.Add(dr); } - [Test, Explicit] - public void RunTestWithoutDI() + DataView dv = new DataView(dt); + return dv; + } + + [Test, Explicit] + public void RunTestWithoutDI() + { + DataView dv = CreateDataSource(); + + int runs = 1000; + + StopWatch watch = new StopWatch(); + using (watch.Start("Duration: {0}")) { - DataView dv = CreateDataSource(); + for (int i = 0; i < runs; i++) + { + DataGrid grid = new DataGrid(); + grid.DataSource = dv; + grid.DataBind(); + } + } + } + + [Test, Explicit] + public void RunTestWithDI() + { +// LogManager.Adapter = new Common.Logging.Simple.TraceLoggerFactoryAdapter(); + + DataView dv = CreateDataSource(); + using (TestWebContext wctx = new TestWebContext("/testpath", "testpage.aspx")) + { + IApplicationContext ctx = new WebApplicationContext(); int runs = 1000; @@ -73,78 +96,53 @@ namespace Spring.Util for (int i = 0; i < runs; i++) { DataGrid grid = new DataGrid(); + Spring.Web.Support.WebDependencyInjectionUtils.InjectDependenciesRecursive(ctx, grid); grid.DataSource = dv; grid.DataBind(); } } - } - [Test, Explicit] - public void RunTestWithDI() - { -// LogManager.Adapter = new Common.Logging.Simple.TraceLoggerFactoryAdapter(); - - DataView dv = CreateDataSource(); - using (TestWebContext wctx = new TestWebContext("/testpath", "testpage.aspx")) - { - IApplicationContext ctx = new WebApplicationContext(); - - int runs = 1000; - - StopWatch watch = new StopWatch(); - using (watch.Start("Duration: {0}")) - { - for (int i = 0; i < runs; i++) - { - DataGrid grid = new DataGrid(); - Spring.Web.Support.WebDependencyInjectionUtils.InjectDependenciesRecursive(ctx, grid); - grid.DataSource = dv; - grid.DataBind(); - } - } - - using (watch.Start("Duration: {0}")) - { - for (int i = 0; i < runs; i++) - { - DataGrid grid = new DataGrid(); - grid.DataSource = dv; - grid.DataBind(); - Spring.Web.Support.WebDependencyInjectionUtils.InjectDependenciesRecursive(ctx, grid); - } - } - } - } - - [Test, Explicit] - public void TestHashtableVsDictionary() - { - int runs = 10000000; - Hashtable ht = new Hashtable(); - Dictionary dict = new Dictionary(); - - for (int i = 0; i < 100000; i++) - { - ht.Add(i, new object()); - dict.Add(new object(), new object()); - } - - StopWatch watch = new StopWatch(); - using (watch.Start("Duration Hashtable: {0}")) + using (watch.Start("Duration: {0}")) { for (int i = 0; i < runs; i++) { - ht.ContainsKey(i); - } - } - - using (watch.Start("Duration Dictionary: {0}")) - { - for (int i = 0; i < runs; i++) - { - dict.ContainsKey(i); + DataGrid grid = new DataGrid(); + grid.DataSource = dv; + grid.DataBind(); + Spring.Web.Support.WebDependencyInjectionUtils.InjectDependenciesRecursive(ctx, grid); } } } } + + [Test, Explicit] + public void TestHashtableVsDictionary() + { + int runs = 10000000; + Hashtable ht = new Hashtable(); + Dictionary dict = new Dictionary(); + + for (int i = 0; i < 100000; i++) + { + ht.Add(i, new object()); + dict.Add(new object(), new object()); + } + + StopWatch watch = new StopWatch(); + using (watch.Start("Duration Hashtable: {0}")) + { + for (int i = 0; i < runs; i++) + { + ht.ContainsKey(i); + } + } + + using (watch.Start("Duration Dictionary: {0}")) + { + for (int i = 0; i < runs; i++) + { + dict.ContainsKey(i); + } + } + } } diff --git a/test/Spring/Spring.Web.Tests/Util/WebUtilsTests.cs b/test/Spring/Spring.Web.Tests/Util/WebUtilsTests.cs index 217bb01e..80cbdd61 100644 --- a/test/Spring/Spring.Web.Tests/Util/WebUtilsTests.cs +++ b/test/Spring/Spring.Web.Tests/Util/WebUtilsTests.cs @@ -21,257 +21,255 @@ #region Imports using NUnit.Framework; - using Spring.TestSupport; #endregion -namespace Spring.Util +namespace Spring.Util; + +/// +/// Unit tests for the WebUtilsTests class. +/// +/// Rick Evans +[TestFixture] +public sealed class WebUtilsTests { - /// - /// Unit tests for the WebUtilsTests class. - /// - /// Rick Evans - [TestFixture] - public sealed class WebUtilsTests + private const string ExpectedPageName = "foo"; + + [Test] + public void GetPageNameWithNullUrl() { - private const string ExpectedPageName = "foo"; + Assert.Throws(() => WebUtils.GetPageName(null)); + } - [Test] - public void GetPageNameWithNullUrl() - { - Assert.Throws(() => WebUtils.GetPageName(null)); - } + [Test] + public void GetPageNameWithEmptyUrl() + { + Assert.Throws(() => WebUtils.GetPageName(string.Empty)); + } - [Test] - public void GetPageNameWithEmptyUrl() - { - Assert.Throws(() => WebUtils.GetPageName(string.Empty)); - } + [Test] + public void GetPageNameWithWhitespacedUrl() + { + Assert.Throws(() => WebUtils.GetPageName(" ")); + } - [Test] - public void GetPageNameWithWhitespacedUrl() - { - Assert.Throws(() => WebUtils.GetPageName(" ")); - } + [Test] + public void GetPageNameSunnyDay() + { + string pageName = WebUtils.GetPageName("foo.aspx"); + Assert.AreEqual(ExpectedPageName, pageName); + pageName = WebUtils.GetPageName("~/foo.aspx"); + Assert.AreEqual(ExpectedPageName, pageName); + pageName = WebUtils.GetPageName("~/Bingo/foo.aspx"); + Assert.AreEqual(ExpectedPageName, pageName); + pageName = WebUtils.GetPageName("/Bingo/foo.aspx"); + Assert.AreEqual(ExpectedPageName, pageName); + pageName = WebUtils.GetPageName("Bingo/foo.aspx"); + Assert.AreEqual(ExpectedPageName, pageName); + pageName = WebUtils.GetPageName("~/Bingo/Rope/foo.aspx"); + Assert.AreEqual(ExpectedPageName, pageName); + pageName = WebUtils.GetPageName("/Bingo/Rope/foo.aspx"); + Assert.AreEqual(ExpectedPageName, pageName); + pageName = WebUtils.GetPageName("Bingo/Rope/foo.aspx"); + Assert.AreEqual(ExpectedPageName, pageName); + pageName = WebUtils.GetPageName("http://www.madeleine.org/Bingo/Rope/foo.aspx"); + Assert.AreEqual(ExpectedPageName, pageName); + } - [Test] - public void GetPageNameSunnyDay() - { - string pageName = WebUtils.GetPageName("foo.aspx"); - Assert.AreEqual(ExpectedPageName, pageName); - pageName = WebUtils.GetPageName("~/foo.aspx"); - Assert.AreEqual(ExpectedPageName, pageName); - pageName = WebUtils.GetPageName("~/Bingo/foo.aspx"); - Assert.AreEqual(ExpectedPageName, pageName); - pageName = WebUtils.GetPageName("/Bingo/foo.aspx"); - Assert.AreEqual(ExpectedPageName, pageName); - pageName = WebUtils.GetPageName("Bingo/foo.aspx"); - Assert.AreEqual(ExpectedPageName, pageName); - pageName = WebUtils.GetPageName("~/Bingo/Rope/foo.aspx"); - Assert.AreEqual(ExpectedPageName, pageName); - pageName = WebUtils.GetPageName("/Bingo/Rope/foo.aspx"); - Assert.AreEqual(ExpectedPageName, pageName); - pageName = WebUtils.GetPageName("Bingo/Rope/foo.aspx"); - Assert.AreEqual(ExpectedPageName, pageName); - pageName = WebUtils.GetPageName("http://www.madeleine.org/Bingo/Rope/foo.aspx"); - Assert.AreEqual(ExpectedPageName, pageName); - } + [Test] + public void GetPageNameWherePageHasOddExtension() + { + string pageName = WebUtils.GetPageName("foo.odd"); + Assert.AreEqual(ExpectedPageName, pageName); + } - [Test] - public void GetPageNameWherePageHasOddExtension() - { - string pageName = WebUtils.GetPageName("foo.odd"); - Assert.AreEqual(ExpectedPageName, pageName); - } + /// + /// Dont quite know how this would get mapped by IIS, but + /// WebUtils.GetPageName should return the page as-is in any case. + /// + [Test] + public void GetPageNameWherePageHasNoExtension() + { + string pageName = WebUtils.GetPageName("foo"); + Assert.AreEqual(ExpectedPageName, pageName); + pageName = WebUtils.GetPageName("http://www.madeleine.org/Bingo/Rope/foo"); + Assert.AreEqual(ExpectedPageName, pageName); + } - /// - /// Dont quite know how this would get mapped by IIS, but - /// WebUtils.GetPageName should return the page as-is in any case. - /// - [Test] - public void GetPageNameWherePageHasNoExtension() - { - string pageName = WebUtils.GetPageName("foo"); - Assert.AreEqual(ExpectedPageName, pageName); - pageName = WebUtils.GetPageName("http://www.madeleine.org/Bingo/Rope/foo"); - Assert.AreEqual(ExpectedPageName, pageName); - } + [Test] + public void CreateAbsolutePath_EmptyApplicationPathAndNullRelativePath_ReturnsRootPath() + { + Assert.AreEqual("/", WebUtils.CreateAbsolutePath("", null)); + } - [Test] - public void CreateAbsolutePath_EmptyApplicationPathAndNullRelativePath_ReturnsRootPath() - { - Assert.AreEqual("/", WebUtils.CreateAbsolutePath("", null)); - } + [Test] + public void CreateAbsolutePath_RootApplicationPathAndNullRelativePath_ReturnsRootPath() + { + Assert.AreEqual("/", WebUtils.CreateAbsolutePath("/", null)); + } - [Test] - public void CreateAbsolutePath_RootApplicationPathAndNullRelativePath_ReturnsRootPath() - { - Assert.AreEqual("/", WebUtils.CreateAbsolutePath("/", null)); - } + [Test] + public void CreateAbsolutePath_NullRelativePath_ReturnsApplicationPath() + { + Assert.AreEqual("/MyApp/", WebUtils.CreateAbsolutePath("/MyApp", null)); + } - [Test] - public void CreateAbsolutePath_NullRelativePath_ReturnsApplicationPath() - { - Assert.AreEqual("/MyApp/", WebUtils.CreateAbsolutePath("/MyApp", null)); - } + [Test] + public void CreateAbsolutePath_EmptyRelativePath_ReturnsApplicationPath() + { + Assert.AreEqual("/MyApp/", WebUtils.CreateAbsolutePath("/MyApp", string.Empty)); + } - [Test] - public void CreateAbsolutePath_EmptyRelativePath_ReturnsApplicationPath() - { - Assert.AreEqual("/MyApp/", WebUtils.CreateAbsolutePath("/MyApp", string.Empty)); - } + [Test] + public void CreateAbsolutePath_NullApplicationPath_ReturnsRelativePath() + { + Assert.AreEqual("/MyPath", WebUtils.CreateAbsolutePath(null, "/MyPath")); + } - [Test] - public void CreateAbsolutePath_NullApplicationPath_ReturnsRelativePath() - { - Assert.AreEqual("/MyPath", WebUtils.CreateAbsolutePath(null, "/MyPath")); - } + [Test] + public void CreateAbsolutePath_NullApplicationPathAndAppRootRelativePath_ReturnsRelativePath() + { + Assert.AreEqual("/MyPath", WebUtils.CreateAbsolutePath(null, "~/MyPath")); + } - [Test] - public void CreateAbsolutePath_NullApplicationPathAndAppRootRelativePath_ReturnsRelativePath() - { - Assert.AreEqual("/MyPath", WebUtils.CreateAbsolutePath(null, "~/MyPath")); - } + [Test] + public void CreateAbsolutePath_EmptyApplicationPath_ReturnsRelativePath() + { + Assert.AreEqual("/MyPath", WebUtils.CreateAbsolutePath(string.Empty, "/MyPath")); + } - [Test] - public void CreateAbsolutePath_EmptyApplicationPath_ReturnsRelativePath() - { - Assert.AreEqual("/MyPath", WebUtils.CreateAbsolutePath(string.Empty, "/MyPath")); - } + [Test] + public void CreateAbsolutePath_EmptyApplicationPathAndAppRootRelativePath_ReturnsRelativePath() + { + Assert.AreEqual("/MyPath", WebUtils.CreateAbsolutePath(string.Empty, "~/MyPath")); + } - [Test] - public void CreateAbsolutePath_EmptyApplicationPathAndAppRootRelativePath_ReturnsRelativePath() - { - Assert.AreEqual("/MyPath", WebUtils.CreateAbsolutePath(string.Empty, "~/MyPath")); - } + [Test] + public void CreateAbsolutePath_RootApplicationPath_ReturnsRelativePath() + { + Assert.AreEqual("/MyPath", WebUtils.CreateAbsolutePath("/", "/MyPath")); + } - [Test] - public void CreateAbsolutePath_RootApplicationPath_ReturnsRelativePath() - { - Assert.AreEqual("/MyPath", WebUtils.CreateAbsolutePath("/", "/MyPath")); - } + [Test] + public void CreateAbsolutePath_RootApplicationPathAndAppRootRelativePath_ReturnsRelativePath() + { + Assert.AreEqual("/MyPath", WebUtils.CreateAbsolutePath("/", "~/MyPath")); + } - [Test] - public void CreateAbsolutePath_RootApplicationPathAndAppRootRelativePath_ReturnsRelativePath() - { - Assert.AreEqual("/MyPath", WebUtils.CreateAbsolutePath("/", "~/MyPath")); - } + [Test] + public void CreateAbsolutePath_ApplicationPathAndRelativePath_ReturnsConcatenatedPath() + { + Assert.AreEqual("/MyApp/MyPath", WebUtils.CreateAbsolutePath("/MyApp", "MyPath")); + } - [Test] - public void CreateAbsolutePath_ApplicationPathAndRelativePath_ReturnsConcatenatedPath() - { - Assert.AreEqual("/MyApp/MyPath", WebUtils.CreateAbsolutePath("/MyApp", "MyPath")); - } + [Test] + public void CreateAbsolutePath_ApplicationPathAndAppRootRelativePath_ReturnsConcatenatedPath() + { + Assert.AreEqual("/MyApp/MyPath", WebUtils.CreateAbsolutePath("/MyApp", "~/MyPath")); + } - [Test] - public void CreateAbsolutePath_ApplicationPathAndAppRootRelativePath_ReturnsConcatenatedPath() - { - Assert.AreEqual("/MyApp/MyPath", WebUtils.CreateAbsolutePath("/MyApp", "~/MyPath")); - } + [Test] + public void CreateAbsolutePath_ApplicationPathWithTrailingSlashAndRelativePath_ReturnsConcatenatedPath() + { + Assert.AreEqual("/MyApp/MyPath", WebUtils.CreateAbsolutePath("/MyApp/", "MyPath")); + } - [Test] - public void CreateAbsolutePath_ApplicationPathWithTrailingSlashAndRelativePath_ReturnsConcatenatedPath() - { - Assert.AreEqual("/MyApp/MyPath", WebUtils.CreateAbsolutePath("/MyApp/", "MyPath")); - } + [Test] + public void CreateAbsolutePath_ApplicationPathWithTrailingSlashAndAppRootRelativePath_ReturnsConcatenatedPath() + { + Assert.AreEqual("/MyApp/MyPath", WebUtils.CreateAbsolutePath("/MyApp/", "~/MyPath")); + } - [Test] - public void CreateAbsolutePath_ApplicationPathWithTrailingSlashAndAppRootRelativePath_ReturnsConcatenatedPath() - { - Assert.AreEqual("/MyApp/MyPath", WebUtils.CreateAbsolutePath("/MyApp/", "~/MyPath")); - } + [Test] + public void CreateAbsolutePath_WhenRelativePathBeginsWithApplicationPath_ReturnsConcatenatedPath() + { + Assert.AreEqual("/MyApp/MyPath", WebUtils.CreateAbsolutePath("/MyApp", "/MyApp/MyPath")); + } - [Test] - public void CreateAbsolutePath_WhenRelativePathBeginsWithApplicationPath_ReturnsConcatenatedPath() - { - Assert.AreEqual("/MyApp/MyPath", WebUtils.CreateAbsolutePath("/MyApp", "/MyApp/MyPath")); - } + [Test] + public void CreateAbsolutePath_WhenRelativePathIsHttpQualifiedUrl_ReturnsRelativePath() + { + Assert.AreEqual("http://MyApp/MyPath", WebUtils.CreateAbsolutePath(null, "http://MyApp/MyPath")); + Assert.AreEqual("http://MyApp/MyPath", WebUtils.CreateAbsolutePath("/", "http://MyApp/MyPath")); + Assert.AreEqual("http://MyApp/MyPath", WebUtils.CreateAbsolutePath("/MyApp", "http://MyApp/MyPath")); + Assert.AreEqual("http://MyApp/MyPath", WebUtils.CreateAbsolutePath("/MyApp/", "http://MyApp/MyPath")); + } - [Test] - public void CreateAbsolutePath_WhenRelativePathIsHttpQualifiedUrl_ReturnsRelativePath() - { - Assert.AreEqual("http://MyApp/MyPath", WebUtils.CreateAbsolutePath(null, "http://MyApp/MyPath")); - Assert.AreEqual("http://MyApp/MyPath", WebUtils.CreateAbsolutePath("/", "http://MyApp/MyPath")); - Assert.AreEqual("http://MyApp/MyPath", WebUtils.CreateAbsolutePath("/MyApp", "http://MyApp/MyPath")); - Assert.AreEqual("http://MyApp/MyPath", WebUtils.CreateAbsolutePath("/MyApp/", "http://MyApp/MyPath")); - } + [Test] + public void CreateAbsolutePath_WhenRelativePathIsHttpsQualifiedUrl_ReturnsRelativePath() + { + Assert.AreEqual("https://MyApp/MyPath", WebUtils.CreateAbsolutePath(null, "https://MyApp/MyPath")); + Assert.AreEqual("https://MyApp/MyPath", WebUtils.CreateAbsolutePath("/", "https://MyApp/MyPath")); + Assert.AreEqual("https://MyApp/MyPath", WebUtils.CreateAbsolutePath("/MyApp", "https://MyApp/MyPath")); + Assert.AreEqual("https://MyApp/MyPath", WebUtils.CreateAbsolutePath("/MyApp/", "https://MyApp/MyPath")); + } - [Test] - public void CreateAbsolutePath_WhenRelativePathIsHttpsQualifiedUrl_ReturnsRelativePath() - { - Assert.AreEqual("https://MyApp/MyPath", WebUtils.CreateAbsolutePath(null, "https://MyApp/MyPath")); - Assert.AreEqual("https://MyApp/MyPath", WebUtils.CreateAbsolutePath("/", "https://MyApp/MyPath")); - Assert.AreEqual("https://MyApp/MyPath", WebUtils.CreateAbsolutePath("/MyApp", "https://MyApp/MyPath")); - Assert.AreEqual("https://MyApp/MyPath", WebUtils.CreateAbsolutePath("/MyApp/", "https://MyApp/MyPath")); - } + [Test] + public void CombineVirtualPathsDoesntAcceptNullRoot() + { + Assert.Throws(() => WebUtils.CombineVirtualPaths(null, string.Empty)); + } - [Test] - public void CombineVirtualPathsDoesntAcceptNullRoot() - { - Assert.Throws(() => WebUtils.CombineVirtualPaths(null, string.Empty)); - } + [Test] + public void CombineVirtualPathsDoesntAcceptEmptyRoot() + { + Assert.Throws(() => WebUtils.CombineVirtualPaths(string.Empty, string.Empty)); + } - [Test] - public void CombineVirtualPathsDoesntAcceptEmptyRoot() - { - Assert.Throws(() => WebUtils.CombineVirtualPaths(string.Empty, string.Empty)); - } - - [Test] - public void CombineVirtualPathsDoesntAcceptNonRootedRoot() - { - Assert.Throws(() => WebUtils.CombineVirtualPaths("mypath", string.Empty)); - } - - [Test] - public void CombineVirtualPathsInRootWeb() - { - // emulate root website context - using( new VirtualEnvironmentMock("/somedir/some.file", null, null, "/", true) ) - { - CombineVirtualPathsSuite( "/" ); - } - } - - [Test] - public void CombineVirtualPathsInChildWeb() - { - // emulate child website context - using( new VirtualEnvironmentMock("/somedir/some.file", null, null, "/myapp", true) ) - { - CombineVirtualPathsSuite( "/myapp/" ); - } - } - - private void CombineVirtualPathsSuite( string appPath ) - { - Assert.AreEqual("/myotherdir/mypath", WebUtils.CombineVirtualPaths("/myotherdir", "mypath")); - Assert.AreEqual("/mypath", WebUtils.CombineVirtualPaths("/irrelevantdir", "/mypath")); // note: that's the difference from CreateAbsolutePath() - Assert.AreEqual(appPath + "mypath", WebUtils.CombineVirtualPaths("/irrelevantdir", "~/mypath")); - Assert.AreEqual(appPath + "some/~/mypath", WebUtils.CombineVirtualPaths("/mydir", "~/some/~/mypath")); - Assert.AreEqual("/mydir/some/~/mypath", WebUtils.CombineVirtualPaths("/mydir", "some/~/mypath")); - Assert.AreEqual("/myotherdir/mypath/my.file", WebUtils.CombineVirtualPaths("/myotherdir/some.file", "mypath/my.file")); - Assert.AreEqual(appPath + "mypath/my.file", WebUtils.CombineVirtualPaths("/myotherdir/some.file", "~/mypath/my.file")); - } + [Test] + public void CombineVirtualPathsDoesntAcceptNonRootedRoot() + { + Assert.Throws(() => WebUtils.CombineVirtualPaths("mypath", string.Empty)); + } - [Test] - public void GetRelativePath() + [Test] + public void CombineVirtualPathsInRootWeb() + { + // emulate root website context + using (new VirtualEnvironmentMock("/somedir/some.file", null, null, "/", true)) { - // case-insensitive - Assert.AreEqual("/Mypath", WebUtils.GetRelativePath("/mydir/", "/myDir/Mypath")); - Assert.AreEqual("/mYpath", WebUtils.GetRelativePath("/Mydir", "/mYdir/mYpath")); - Assert.AreEqual("/myotherdir/mypath", WebUtils.GetRelativePath("/mydir", "/myotherdir/mypath")); - } - - [Test] - public void GetNormalizedVirtualPath() - { - Assert.AreEqual(null, WebUtils.GetNormalizedVirtualPath(null)); - Assert.AreEqual(String.Empty, WebUtils.GetNormalizedVirtualPath(String.Empty)); - Assert.AreEqual("~test.aspx", WebUtils.GetNormalizedVirtualPath("~test.aspx")); - Assert.AreEqual("/test.aspx", WebUtils.GetNormalizedVirtualPath("~/test.aspx")); - Assert.AreEqual("/Complex.Path/~/test.aspx", WebUtils.GetNormalizedVirtualPath("~/Complex.Path/~/test.aspx")); + CombineVirtualPathsSuite("/"); } } + + [Test] + public void CombineVirtualPathsInChildWeb() + { + // emulate child website context + using (new VirtualEnvironmentMock("/somedir/some.file", null, null, "/myapp", true)) + { + CombineVirtualPathsSuite("/myapp/"); + } + } + + private void CombineVirtualPathsSuite(string appPath) + { + Assert.AreEqual("/myotherdir/mypath", WebUtils.CombineVirtualPaths("/myotherdir", "mypath")); + Assert.AreEqual("/mypath", WebUtils.CombineVirtualPaths("/irrelevantdir", "/mypath")); // note: that's the difference from CreateAbsolutePath() + Assert.AreEqual(appPath + "mypath", WebUtils.CombineVirtualPaths("/irrelevantdir", "~/mypath")); + Assert.AreEqual(appPath + "some/~/mypath", WebUtils.CombineVirtualPaths("/mydir", "~/some/~/mypath")); + Assert.AreEqual("/mydir/some/~/mypath", WebUtils.CombineVirtualPaths("/mydir", "some/~/mypath")); + Assert.AreEqual("/myotherdir/mypath/my.file", WebUtils.CombineVirtualPaths("/myotherdir/some.file", "mypath/my.file")); + Assert.AreEqual(appPath + "mypath/my.file", WebUtils.CombineVirtualPaths("/myotherdir/some.file", "~/mypath/my.file")); + } + + [Test] + public void GetRelativePath() + { + // case-insensitive + Assert.AreEqual("/Mypath", WebUtils.GetRelativePath("/mydir/", "/myDir/Mypath")); + Assert.AreEqual("/mYpath", WebUtils.GetRelativePath("/Mydir", "/mYdir/mYpath")); + Assert.AreEqual("/myotherdir/mypath", WebUtils.GetRelativePath("/mydir", "/myotherdir/mypath")); + } + + [Test] + public void GetNormalizedVirtualPath() + { + Assert.AreEqual(null, WebUtils.GetNormalizedVirtualPath(null)); + Assert.AreEqual(String.Empty, WebUtils.GetNormalizedVirtualPath(String.Empty)); + Assert.AreEqual("~test.aspx", WebUtils.GetNormalizedVirtualPath("~test.aspx")); + Assert.AreEqual("/test.aspx", WebUtils.GetNormalizedVirtualPath("~/test.aspx")); + Assert.AreEqual("/Complex.Path/~/test.aspx", WebUtils.GetNormalizedVirtualPath("~/Complex.Path/~/test.aspx")); + } } diff --git a/test/Spring/Spring.Web.Tests/Web/Services/WebServiceExporterTests.cs b/test/Spring/Spring.Web.Tests/Web/Services/WebServiceExporterTests.cs index 583d81de..f330c28e 100644 --- a/test/Spring/Spring.Web.Tests/Web/Services/WebServiceExporterTests.cs +++ b/test/Spring/Spring.Web.Tests/Web/Services/WebServiceExporterTests.cs @@ -24,9 +24,7 @@ using System.Text; using System.Reflection; using System.Reflection.Emit; using System.Web.Services; - using NUnit.Framework; - using Spring.Util; using Spring.Core.IO; using Spring.Objects.Factory.Xml; @@ -34,296 +32,293 @@ using Spring.Objects.Factory; #endregion -namespace Spring.Web.Services -{ - /// - /// Unit tests for the WebServiceExporter class. - /// - /// Bruno Baia - [TestFixture] - public sealed class WebServiceExporterTests - { - WebServiceExporter wse = null; +namespace Spring.Web.Services; - [SetUp] - public void SetUp() - { - const string xml = - @" +/// +/// Unit tests for the WebServiceExporter class. +/// +/// Bruno Baia +[TestFixture] +public sealed class WebServiceExporterTests +{ + WebServiceExporter wse = null; + + [SetUp] + public void SetUp() + { + const string xml = + @" "; - Stream stream = new MemoryStream(Encoding.UTF8.GetBytes(xml)); - IObjectFactory objectFactory = new XmlObjectFactory(new InputStreamResource(stream, string.Empty)); + Stream stream = new MemoryStream(Encoding.UTF8.GetBytes(xml)); + IObjectFactory objectFactory = new XmlObjectFactory(new InputStreamResource(stream, string.Empty)); - wse = new WebServiceExporter(); - wse.ObjectFactory = objectFactory; - } - - [Test] - public void NullConfig() - { - wse.ObjectName = "NullConfig"; - Assert.Throws(() => wse.AfterPropertiesSet(), "The TargetName property is required."); - } - - [Test] - public void ProxiesTargetInterfaces() - { - wse.ObjectName = "ProxiesTargetInterfaces"; - wse.TargetName = "noDecoratedService"; - wse.AfterPropertiesSet(); - - Type proxyType = wse.GetExportedType(); - Assert.IsTrue(typeof(IService).IsAssignableFrom(proxyType)); - } - - [Test] - public void CreatesWebServiceAttributeWithNoDecoratedClassAndMinimalConfig() - { - wse.ObjectName = "CreatesWebServiceAttributeWithNoDecoratedClassAndMinimalConfig"; - wse.TargetName = "noDecoratedService"; - wse.AfterPropertiesSet(); - - Type proxyType = wse.GetExportedType(); - object[] attrs = proxyType.GetCustomAttributes(typeof(WebServiceAttribute), true); - Assert.IsNotEmpty(attrs); - Assert.AreEqual(1, attrs.Length); - - WebServiceAttribute wsa = attrs[0] as WebServiceAttribute; - Assert.AreEqual("CreatesWebServiceAttributeWithNoDecoratedClassAndMinimalConfig", wsa.Name); - Assert.AreEqual(string.Empty, wsa.Description); - Assert.AreEqual(WebServiceAttribute.DefaultNamespace, wsa.Namespace); - } - - [Test] - public void CreatesWebServiceAttributeWithNoDecoratedClassAndFullConfig() - { - wse.ObjectName = "CreatesWebServiceAttributeWithNoDecoratedClassAndFullConfig"; - wse.TargetName = "noDecoratedService"; - wse.Name = "My web service name"; - wse.Description = "My web service description"; - wse.Namespace = "http://www.springframework.net"; - wse.AfterPropertiesSet(); - - Type proxyType = wse.GetExportedType(); - object[] attrs = proxyType.GetCustomAttributes(typeof(WebServiceAttribute), true); - Assert.IsNotEmpty(attrs); - Assert.AreEqual(1, attrs.Length); - - WebServiceAttribute wsa = attrs[0] as WebServiceAttribute; - Assert.AreEqual(wse.Name, wsa.Name); - Assert.AreEqual(wse.Description, wsa.Description); - Assert.AreEqual(wse.Namespace, wsa.Namespace); - } - - [Test] - public void CreatesDefaultWebServiceBindingAttribute() - { - wse.ObjectName = "CreatesDefaultWebServiceBindingAttribute"; - wse.TargetName = "noDecoratedService"; - wse.AfterPropertiesSet(); - - Type proxyType = wse.GetExportedType(); - object[] attrs = proxyType.GetCustomAttributes(typeof(WebServiceBindingAttribute), true); - Assert.IsNotEmpty(attrs); - Assert.AreEqual(1, attrs.Length); - - WebServiceBindingAttribute wsba = attrs[0] as WebServiceBindingAttribute; - Assert.AreEqual(WsiProfiles.BasicProfile1_1, wsba.ConformsTo); - } - - [Test] - public void CreatesWebServiceBindingAttributeWithNoWsiProfile() - { - wse.ObjectName = "CreatesWebServiceBindingAttributeWithNoWsiProfile"; - wse.TargetName = "noDecoratedService"; - wse.WsiProfile = WsiProfiles.None; - wse.AfterPropertiesSet(); - - Type proxyType = wse.GetExportedType(); - object[] attrs = proxyType.GetCustomAttributes(typeof(WebServiceBindingAttribute), true); - Assert.IsNotEmpty(attrs); - Assert.AreEqual(1, attrs.Length); - - WebServiceBindingAttribute wsba = attrs[0] as WebServiceBindingAttribute; - Assert.AreEqual(WsiProfiles.None, wsba.ConformsTo); - } - - [Test] - public void UsesExistingWebServiceBindingAttributeWithDecoratedClass() - { - wse.ObjectName = "UsesExistingWebServiceBindingAttributeWithDecoratedClass"; - wse.TargetName = "decoratedService"; - wse.AfterPropertiesSet(); - - Type proxyType = wse.GetExportedType(); - object[] attrs = proxyType.GetCustomAttributes(typeof(WebServiceBindingAttribute), true); - Assert.IsNotEmpty(attrs); - Assert.AreEqual(1, attrs.Length); - - WebServiceBindingAttribute wsba = attrs[0] as WebServiceBindingAttribute; - Assert.AreEqual(WsiProfiles.None, wsba.ConformsTo); - } - - [Test] - public void CreatesDefaultWebMethodAttributeWithNoDecoratedMethod() - { - wse.ObjectName = "CreatesDefaultWebMethodAttributeWithNoDecoratedMethod"; - wse.TargetName = "noDecoratedService"; - wse.AfterPropertiesSet(); - - Type proxyType = wse.GetExportedType(); - MethodInfo method = proxyType.GetMethod("SomeMethod"); - Assert.IsNotNull(method); - - object[] attrs = method.GetCustomAttributes(typeof(WebMethodAttribute), true); - Assert.IsNotEmpty(attrs); - Assert.AreEqual(1, attrs.Length); - } - - [Test] - public void CreatesCustomWebMethodAttributeWithNoDecoratedMethod() - { - wse.ObjectName = "CreatesCustomWebMethodAttributeWithNoDecoratedMethod"; - wse.TargetName = "noDecoratedService"; - wse.MemberAttributes.Add("SomeMethod", new WebMethodAttribute(true)); // default value is false - wse.AfterPropertiesSet(); - - Type proxyType = wse.GetExportedType(); - MethodInfo method = proxyType.GetMethod("SomeMethod"); - Assert.IsNotNull(method); - - object[] attrs = method.GetCustomAttributes(typeof(WebMethodAttribute), true); - Assert.IsNotEmpty(attrs); - Assert.AreEqual(1, attrs.Length); - - WebMethodAttribute wma = attrs[0] as WebMethodAttribute; - Assert.AreEqual(true, wma.EnableSession); - } - - [Test] - public void OverridesExistingWebServiceAttributeWithDecoratedClass() - { - wse.ObjectName = "OverridesExistingWebServiceAttributeWithDecoratedClass"; - wse.TargetName = "decoratedService"; - wse.AfterPropertiesSet(); - - Type proxyType = wse.GetExportedType(); - object[] attrs = proxyType.GetCustomAttributes(typeof(WebServiceAttribute), true); - Assert.IsNotEmpty(attrs); - Assert.AreEqual(1, attrs.Length); - - WebServiceAttribute wsa = attrs[0] as WebServiceAttribute; - Assert.AreEqual("OverridesExistingWebServiceAttributeWithDecoratedClass", wsa.Name); - Assert.AreEqual(string.Empty, wsa.Description); - Assert.AreEqual(WebServiceAttribute.DefaultNamespace, wsa.Namespace); - } - - [Test] - public void UsesExistingWebMethodAttributeWithDecoratedMethod() - { - wse.ObjectName = "UsesExistingWebMethodAttributeWithDecoratedMethod"; - wse.TargetName = "decoratedService"; - wse.AfterPropertiesSet(); - - Type proxyType = wse.GetExportedType(); - MethodInfo method = proxyType.GetMethod("SomeMethod"); - Assert.IsNotNull(method); - - object[] attrs = method.GetCustomAttributes(typeof(WebMethodAttribute), true); - Assert.IsNotEmpty(attrs); - Assert.AreEqual(1, attrs.Length); - - WebMethodAttribute wma = attrs[0] as WebMethodAttribute; - Assert.AreEqual("SomeMethod description", wma.Description); - } - - // TODO : attributes override - [Test] - [Ignore("Attributes override not implemented.")] - public void OverridesExistingWebMethodAttributeWithDecoratedMethod() - { - wse.ObjectName = "OverridesExistingWebMethodAttributeWithDecoratedMethod"; - wse.TargetName = "decoratedService"; - wse.MemberAttributes.Add("SomeMethod", new WebMethodAttribute(true)); // default value is false - wse.AfterPropertiesSet(); - - Type proxyType = wse.GetExportedType(); - MethodInfo method = proxyType.GetMethod("SomeMethod"); - Assert.IsNotNull(method); - - object[] attrs = method.GetCustomAttributes(typeof(WebMethodAttribute), true); - Assert.IsNotEmpty(attrs); - Assert.AreEqual(1, attrs.Length); - - WebMethodAttribute wma = attrs[0] as WebMethodAttribute; - Assert.AreEqual(true, wma.EnableSession); - } - - - [Test] - public void AppliesCustomAttributeBuilderToType() - { - wse.ObjectName = "AppliesCustomAttributeBuilderToType"; - wse.TargetName = "noDecoratedService"; - wse.TypeAttributes = new CustomAttributeBuilder[] { - new CustomAttributeBuilder(typeof(WebServiceAttribute).GetConstructor(Type.EmptyTypes), ObjectUtils.EmptyObjects) }; - wse.AfterPropertiesSet(); - - Type proxyType = wse.GetExportedType(); - - object[] attrs = proxyType.GetCustomAttributes(typeof(WebServiceAttribute), true); - Assert.IsNotEmpty(attrs); - Assert.AreEqual(1, attrs.Length); - - WebServiceAttribute wsa = attrs[0] as WebServiceAttribute; - Assert.AreEqual("AppliesCustomAttributeBuilderToType", wsa.Name); - } - - [Test] - public void UseCustomWebServiceType() - { - wse.ObjectName = "UseCustomWebServiceType"; - wse.TargetName = "noDecoratedService"; - wse.WebServiceBaseType = typeof(CustomWebService); - wse.AfterPropertiesSet(); - - Type proxyType = wse.GetExportedType(); - Assert.IsTrue(typeof(CustomWebService).IsAssignableFrom(proxyType)); - } - - #region Test classes - - public interface IService - { - string SomeMethod(int param); - } - - public class NoDecoratedService : IService - { - public string SomeMethod(int param) - { - return param.ToString(); - } - } - - [WebService(Name = "Decorated service")] - [WebServiceBinding(ConformsTo=WsiProfiles.None)] - public class DecoratedService : IService - { - [WebMethod(Description="SomeMethod description")] - public string SomeMethod(int param) - { - return param.ToString(); - } - } - - public class CustomWebService : WebService - { - } - - #endregion + wse = new WebServiceExporter(); + wse.ObjectFactory = objectFactory; } + + [Test] + public void NullConfig() + { + wse.ObjectName = "NullConfig"; + Assert.Throws(() => wse.AfterPropertiesSet(), "The TargetName property is required."); + } + + [Test] + public void ProxiesTargetInterfaces() + { + wse.ObjectName = "ProxiesTargetInterfaces"; + wse.TargetName = "noDecoratedService"; + wse.AfterPropertiesSet(); + + Type proxyType = wse.GetExportedType(); + Assert.IsTrue(typeof(IService).IsAssignableFrom(proxyType)); + } + + [Test] + public void CreatesWebServiceAttributeWithNoDecoratedClassAndMinimalConfig() + { + wse.ObjectName = "CreatesWebServiceAttributeWithNoDecoratedClassAndMinimalConfig"; + wse.TargetName = "noDecoratedService"; + wse.AfterPropertiesSet(); + + Type proxyType = wse.GetExportedType(); + object[] attrs = proxyType.GetCustomAttributes(typeof(WebServiceAttribute), true); + Assert.IsNotEmpty(attrs); + Assert.AreEqual(1, attrs.Length); + + WebServiceAttribute wsa = attrs[0] as WebServiceAttribute; + Assert.AreEqual("CreatesWebServiceAttributeWithNoDecoratedClassAndMinimalConfig", wsa.Name); + Assert.AreEqual(string.Empty, wsa.Description); + Assert.AreEqual(WebServiceAttribute.DefaultNamespace, wsa.Namespace); + } + + [Test] + public void CreatesWebServiceAttributeWithNoDecoratedClassAndFullConfig() + { + wse.ObjectName = "CreatesWebServiceAttributeWithNoDecoratedClassAndFullConfig"; + wse.TargetName = "noDecoratedService"; + wse.Name = "My web service name"; + wse.Description = "My web service description"; + wse.Namespace = "http://www.springframework.net"; + wse.AfterPropertiesSet(); + + Type proxyType = wse.GetExportedType(); + object[] attrs = proxyType.GetCustomAttributes(typeof(WebServiceAttribute), true); + Assert.IsNotEmpty(attrs); + Assert.AreEqual(1, attrs.Length); + + WebServiceAttribute wsa = attrs[0] as WebServiceAttribute; + Assert.AreEqual(wse.Name, wsa.Name); + Assert.AreEqual(wse.Description, wsa.Description); + Assert.AreEqual(wse.Namespace, wsa.Namespace); + } + + [Test] + public void CreatesDefaultWebServiceBindingAttribute() + { + wse.ObjectName = "CreatesDefaultWebServiceBindingAttribute"; + wse.TargetName = "noDecoratedService"; + wse.AfterPropertiesSet(); + + Type proxyType = wse.GetExportedType(); + object[] attrs = proxyType.GetCustomAttributes(typeof(WebServiceBindingAttribute), true); + Assert.IsNotEmpty(attrs); + Assert.AreEqual(1, attrs.Length); + + WebServiceBindingAttribute wsba = attrs[0] as WebServiceBindingAttribute; + Assert.AreEqual(WsiProfiles.BasicProfile1_1, wsba.ConformsTo); + } + + [Test] + public void CreatesWebServiceBindingAttributeWithNoWsiProfile() + { + wse.ObjectName = "CreatesWebServiceBindingAttributeWithNoWsiProfile"; + wse.TargetName = "noDecoratedService"; + wse.WsiProfile = WsiProfiles.None; + wse.AfterPropertiesSet(); + + Type proxyType = wse.GetExportedType(); + object[] attrs = proxyType.GetCustomAttributes(typeof(WebServiceBindingAttribute), true); + Assert.IsNotEmpty(attrs); + Assert.AreEqual(1, attrs.Length); + + WebServiceBindingAttribute wsba = attrs[0] as WebServiceBindingAttribute; + Assert.AreEqual(WsiProfiles.None, wsba.ConformsTo); + } + + [Test] + public void UsesExistingWebServiceBindingAttributeWithDecoratedClass() + { + wse.ObjectName = "UsesExistingWebServiceBindingAttributeWithDecoratedClass"; + wse.TargetName = "decoratedService"; + wse.AfterPropertiesSet(); + + Type proxyType = wse.GetExportedType(); + object[] attrs = proxyType.GetCustomAttributes(typeof(WebServiceBindingAttribute), true); + Assert.IsNotEmpty(attrs); + Assert.AreEqual(1, attrs.Length); + + WebServiceBindingAttribute wsba = attrs[0] as WebServiceBindingAttribute; + Assert.AreEqual(WsiProfiles.None, wsba.ConformsTo); + } + + [Test] + public void CreatesDefaultWebMethodAttributeWithNoDecoratedMethod() + { + wse.ObjectName = "CreatesDefaultWebMethodAttributeWithNoDecoratedMethod"; + wse.TargetName = "noDecoratedService"; + wse.AfterPropertiesSet(); + + Type proxyType = wse.GetExportedType(); + MethodInfo method = proxyType.GetMethod("SomeMethod"); + Assert.IsNotNull(method); + + object[] attrs = method.GetCustomAttributes(typeof(WebMethodAttribute), true); + Assert.IsNotEmpty(attrs); + Assert.AreEqual(1, attrs.Length); + } + + [Test] + public void CreatesCustomWebMethodAttributeWithNoDecoratedMethod() + { + wse.ObjectName = "CreatesCustomWebMethodAttributeWithNoDecoratedMethod"; + wse.TargetName = "noDecoratedService"; + wse.MemberAttributes.Add("SomeMethod", new WebMethodAttribute(true)); // default value is false + wse.AfterPropertiesSet(); + + Type proxyType = wse.GetExportedType(); + MethodInfo method = proxyType.GetMethod("SomeMethod"); + Assert.IsNotNull(method); + + object[] attrs = method.GetCustomAttributes(typeof(WebMethodAttribute), true); + Assert.IsNotEmpty(attrs); + Assert.AreEqual(1, attrs.Length); + + WebMethodAttribute wma = attrs[0] as WebMethodAttribute; + Assert.AreEqual(true, wma.EnableSession); + } + + [Test] + public void OverridesExistingWebServiceAttributeWithDecoratedClass() + { + wse.ObjectName = "OverridesExistingWebServiceAttributeWithDecoratedClass"; + wse.TargetName = "decoratedService"; + wse.AfterPropertiesSet(); + + Type proxyType = wse.GetExportedType(); + object[] attrs = proxyType.GetCustomAttributes(typeof(WebServiceAttribute), true); + Assert.IsNotEmpty(attrs); + Assert.AreEqual(1, attrs.Length); + + WebServiceAttribute wsa = attrs[0] as WebServiceAttribute; + Assert.AreEqual("OverridesExistingWebServiceAttributeWithDecoratedClass", wsa.Name); + Assert.AreEqual(string.Empty, wsa.Description); + Assert.AreEqual(WebServiceAttribute.DefaultNamespace, wsa.Namespace); + } + + [Test] + public void UsesExistingWebMethodAttributeWithDecoratedMethod() + { + wse.ObjectName = "UsesExistingWebMethodAttributeWithDecoratedMethod"; + wse.TargetName = "decoratedService"; + wse.AfterPropertiesSet(); + + Type proxyType = wse.GetExportedType(); + MethodInfo method = proxyType.GetMethod("SomeMethod"); + Assert.IsNotNull(method); + + object[] attrs = method.GetCustomAttributes(typeof(WebMethodAttribute), true); + Assert.IsNotEmpty(attrs); + Assert.AreEqual(1, attrs.Length); + + WebMethodAttribute wma = attrs[0] as WebMethodAttribute; + Assert.AreEqual("SomeMethod description", wma.Description); + } + + // TODO : attributes override + [Test] + [Ignore("Attributes override not implemented.")] + public void OverridesExistingWebMethodAttributeWithDecoratedMethod() + { + wse.ObjectName = "OverridesExistingWebMethodAttributeWithDecoratedMethod"; + wse.TargetName = "decoratedService"; + wse.MemberAttributes.Add("SomeMethod", new WebMethodAttribute(true)); // default value is false + wse.AfterPropertiesSet(); + + Type proxyType = wse.GetExportedType(); + MethodInfo method = proxyType.GetMethod("SomeMethod"); + Assert.IsNotNull(method); + + object[] attrs = method.GetCustomAttributes(typeof(WebMethodAttribute), true); + Assert.IsNotEmpty(attrs); + Assert.AreEqual(1, attrs.Length); + + WebMethodAttribute wma = attrs[0] as WebMethodAttribute; + Assert.AreEqual(true, wma.EnableSession); + } + + [Test] + public void AppliesCustomAttributeBuilderToType() + { + wse.ObjectName = "AppliesCustomAttributeBuilderToType"; + wse.TargetName = "noDecoratedService"; + wse.TypeAttributes = new CustomAttributeBuilder[] { new CustomAttributeBuilder(typeof(WebServiceAttribute).GetConstructor(Type.EmptyTypes), ObjectUtils.EmptyObjects) }; + wse.AfterPropertiesSet(); + + Type proxyType = wse.GetExportedType(); + + object[] attrs = proxyType.GetCustomAttributes(typeof(WebServiceAttribute), true); + Assert.IsNotEmpty(attrs); + Assert.AreEqual(1, attrs.Length); + + WebServiceAttribute wsa = attrs[0] as WebServiceAttribute; + Assert.AreEqual("AppliesCustomAttributeBuilderToType", wsa.Name); + } + + [Test] + public void UseCustomWebServiceType() + { + wse.ObjectName = "UseCustomWebServiceType"; + wse.TargetName = "noDecoratedService"; + wse.WebServiceBaseType = typeof(CustomWebService); + wse.AfterPropertiesSet(); + + Type proxyType = wse.GetExportedType(); + Assert.IsTrue(typeof(CustomWebService).IsAssignableFrom(proxyType)); + } + + #region Test classes + + public interface IService + { + string SomeMethod(int param); + } + + public class NoDecoratedService : IService + { + public string SomeMethod(int param) + { + return param.ToString(); + } + } + + [WebService(Name = "Decorated service")] + [WebServiceBinding(ConformsTo = WsiProfiles.None)] + public class DecoratedService : IService + { + [WebMethod(Description = "SomeMethod description")] + public string SomeMethod(int param) + { + return param.ToString(); + } + } + + public class CustomWebService : WebService + { + } + + #endregion } diff --git a/test/Spring/Spring.Web.Tests/Web/Support/AbstractHandlerFactoryTests.cs b/test/Spring/Spring.Web.Tests/Web/Support/AbstractHandlerFactoryTests.cs index ee603dc6..02b268c4 100644 --- a/test/Spring/Spring.Web.Tests/Web/Support/AbstractHandlerFactoryTests.cs +++ b/test/Spring/Spring.Web.Tests/Web/Support/AbstractHandlerFactoryTests.cs @@ -19,179 +19,176 @@ #endregion using System.Web; - using FakeItEasy; - using NUnit.Framework; - using Spring.Context; using Spring.Objects.Factory.Support; -namespace Spring.Web.Support +namespace Spring.Web.Support; + +/// +/// +/// +/// Erich Eichinger +[TestFixture] +public class AbstractHandlerFactoryTests { - /// - /// - /// - /// Erich Eichinger - [TestFixture] - public class AbstractHandlerFactoryTests + #region TestFindWebObjectDefinition Helper + + private class TestFindWebObjectDefinitionHandlerFactory : AbstractHandlerFactory { - #region TestFindWebObjectDefinition Helper - - private class TestFindWebObjectDefinitionHandlerFactory : AbstractHandlerFactory + private class Type1 { - private class Type1 { } - - public void TestFindWebObjectDefinition() - { - NamedObjectDefinition nod; - - nod = Find( "/path/o1.ext", "/path/o1.ext" ); - Assert.AreEqual( typeof( Type1 ), nod.ObjectDefinition.ObjectType ); - Assert.AreEqual( "/path/o1.ext", nod.Name ); - - nod = Find( "/path/o1.ext", "/o1.ext" ); - Assert.IsNull( nod ); - - nod = Find( "/path/o1.ext", "/path/o1" ); - Assert.IsNull( nod ); - - nod = Find( "/path/o1.ext", "o1.ext" ); - Assert.AreEqual( typeof( Type1 ), nod.ObjectDefinition.ObjectType ); - Assert.AreEqual( "o1.ext", nod.Name ); - - nod = Find( "/path/o1.ext", "o1" ); - Assert.AreEqual( typeof( Type1 ), nod.ObjectDefinition.ObjectType ); - Assert.AreEqual( "o1", nod.Name ); - } - - private static NamedObjectDefinition Find( string url, string objectName ) - { - DefaultListableObjectFactory of = new DefaultListableObjectFactory(); - RootObjectDefinition rod = new RootObjectDefinition( typeof( Type1 ) ); - of.RegisterObjectDefinition( objectName, rod ); - - return FindWebObjectDefinition( url, of ); - } - - #region AbstractHandlerFactory implementations - - protected override IHttpHandler CreateHandlerInstance( IConfigurableApplicationContext appContext, HttpContext context, string requestType, string url, string physicalPath ) - { - throw new NotImplementedException(); - } - - #endregion } - #endregion TestFindWebObjectDefinition Helper - - [Test] - public void FindWebObjectDefinition() + public void TestFindWebObjectDefinition() { - TestFindWebObjectDefinitionHandlerFactory f = new TestFindWebObjectDefinitionHandlerFactory(); - f.TestFindWebObjectDefinition(); + NamedObjectDefinition nod; + + nod = Find("/path/o1.ext", "/path/o1.ext"); + Assert.AreEqual(typeof(Type1), nod.ObjectDefinition.ObjectType); + Assert.AreEqual("/path/o1.ext", nod.Name); + + nod = Find("/path/o1.ext", "/o1.ext"); + Assert.IsNull(nod); + + nod = Find("/path/o1.ext", "/path/o1"); + Assert.IsNull(nod); + + nod = Find("/path/o1.ext", "o1.ext"); + Assert.AreEqual(typeof(Type1), nod.ObjectDefinition.ObjectType); + Assert.AreEqual("o1.ext", nod.Name); + + nod = Find("/path/o1.ext", "o1"); + Assert.AreEqual(typeof(Type1), nod.ObjectDefinition.ObjectType); + Assert.AreEqual("o1", nod.Name); } - #region TestHandlerFactory - - public abstract class TestHandlerFactory : AbstractHandlerFactory + private static NamedObjectDefinition Find(string url, string objectName) { - public new IConfigurableApplicationContext GetCheckedApplicationContext(string virtualPath) - { - return base.GetCheckedApplicationContext(virtualPath); - } + DefaultListableObjectFactory of = new DefaultListableObjectFactory(); + RootObjectDefinition rod = new RootObjectDefinition(typeof(Type1)); + of.RegisterObjectDefinition(objectName, rod); - protected override IHttpHandler CreateHandlerInstance(IConfigurableApplicationContext appContext, HttpContext context, string requestType, string url, string physicalPath ) - { - return CreateHandlerInstanceStub(appContext, context, requestType, url, physicalPath); - } - - public abstract IHttpHandler CreateHandlerInstanceStub(IConfigurableApplicationContext appContext, HttpContext context, string requestType, string url, string physicalPath); - - protected override IApplicationContext GetContext( string virtualPath ) - { - return GetContextStub( virtualPath ); - } - - public abstract IApplicationContext GetContextStub( string virtualPath ); + return FindWebObjectDefinition(url, of); } + #region AbstractHandlerFactory implementations + + protected override IHttpHandler CreateHandlerInstance(IConfigurableApplicationContext appContext, HttpContext context, string requestType, string url, string physicalPath) + { + throw new NotImplementedException(); + } #endregion + } - [Test] - public void GetCheckedApplicationContextThrowsExceptionsOnNonConfigurableContexts() + #endregion TestFindWebObjectDefinition Helper + + [Test] + public void FindWebObjectDefinition() + { + TestFindWebObjectDefinitionHandlerFactory f = new TestFindWebObjectDefinitionHandlerFactory(); + f.TestFindWebObjectDefinition(); + } + + #region TestHandlerFactory + + public abstract class TestHandlerFactory : AbstractHandlerFactory + { + public new IConfigurableApplicationContext GetCheckedApplicationContext(string virtualPath) { - TestHandlerFactory f = A.Fake(options => options.CallsBaseMethods()); - IApplicationContext simpleAppContext = A.Fake(); - IConfigurableApplicationContext allowedAppContext = A.Fake(); - - A.CallTo(() => f.GetContextStub("/NullContext")).Returns(null); - A.CallTo(() => f.GetContextStub("/NonConfigurableContext")).Returns(simpleAppContext); - A.CallTo(() => f.GetContextStub("/AllowedContext")).Returns(allowedAppContext); - - // (context == null) -> ArgumentException - try - { - f.GetCheckedApplicationContext("/NullContext"); - Assert.Fail("should throw ArgumentException"); - } - catch (ArgumentException) - { - } - - // !(context is IConfigurableApplicationContext) -> InvalidOperationException - try - { - f.GetCheckedApplicationContext("/NonConfigurableContext"); - Assert.Fail("should throw InvalidOperationException"); - } - catch (InvalidOperationException) - { - } - - // (context is IConfigurableApplicationContext) -> OK - Assert.AreSame(allowedAppContext, f.GetCheckedApplicationContext("/AllowedContext")); + return base.GetCheckedApplicationContext(virtualPath); } - [Test] - public void CachesReusableHandlers() + protected override IHttpHandler CreateHandlerInstance(IConfigurableApplicationContext appContext, HttpContext context, string requestType, string url, string physicalPath) { - TestHandlerFactory f = A.Fake(options => options.CallsBaseMethods()); - IHttpHandler reusableHandler = A.Fake(); - IConfigurableApplicationContext appCtx = A.Fake(); - - // if (IHttpHandler.IsReusable == true) => always returns the same handler instance - // - CreateHandlerInstance() is only called once - A.CallTo(() => reusableHandler.IsReusable).Returns(true); - A.CallTo(() => f.GetContextStub("reusable")).Returns(appCtx); - A.CallTo(() => f.CreateHandlerInstanceStub(appCtx, null, null, "reusable", null)).Returns(reusableHandler); - - Assert.AreSame(reusableHandler, f.GetHandler(null, null, "reusable", null)); - Assert.AreSame(reusableHandler, f.GetHandler(null, null, "reusable", null)); + return CreateHandlerInstanceStub(appContext, context, requestType, url, physicalPath); } - [Test] - public void DoesntCacheNonReusableHandlers() + public abstract IHttpHandler CreateHandlerInstanceStub(IConfigurableApplicationContext appContext, HttpContext context, string requestType, string url, string physicalPath); + + protected override IApplicationContext GetContext(string virtualPath) { - TestHandlerFactory f = A.Fake(options => options.CallsBaseMethods()); - IHttpHandler nonReusableHandler = A.Fake(); - A.CallTo(() => nonReusableHandler.IsReusable).Returns(false); - IHttpHandler nonReusableHandler2 = A.Fake(); - A.CallTo(() => nonReusableHandler2.IsReusable).Returns(false); - IConfigurableApplicationContext appCtx = A.Fake(); - - // if (IHttpHandler.IsReusable == false) => always create new handler instance - // - CreateHandlerInstance() is called for each request - - A.CallTo(() => f.GetContextStub("notreusable")).Returns(appCtx); - A.CallTo(() => f.CreateHandlerInstanceStub(appCtx, null, null, "notreusable", null)) - .Returns(nonReusableHandler).Once() - .Then.Returns(nonReusableHandler2).Once(); - - Assert.AreSame(nonReusableHandler, f.GetHandler(null, null, "notreusable", null)); - Assert.AreSame(nonReusableHandler2, f.GetHandler(null, null, "notreusable", null)); + return GetContextStub(virtualPath); } + + public abstract IApplicationContext GetContextStub(string virtualPath); + } + + #endregion + + [Test] + public void GetCheckedApplicationContextThrowsExceptionsOnNonConfigurableContexts() + { + TestHandlerFactory f = A.Fake(options => options.CallsBaseMethods()); + IApplicationContext simpleAppContext = A.Fake(); + IConfigurableApplicationContext allowedAppContext = A.Fake(); + + A.CallTo(() => f.GetContextStub("/NullContext")).Returns(null); + A.CallTo(() => f.GetContextStub("/NonConfigurableContext")).Returns(simpleAppContext); + A.CallTo(() => f.GetContextStub("/AllowedContext")).Returns(allowedAppContext); + + // (context == null) -> ArgumentException + try + { + f.GetCheckedApplicationContext("/NullContext"); + Assert.Fail("should throw ArgumentException"); + } + catch (ArgumentException) + { + } + + // !(context is IConfigurableApplicationContext) -> InvalidOperationException + try + { + f.GetCheckedApplicationContext("/NonConfigurableContext"); + Assert.Fail("should throw InvalidOperationException"); + } + catch (InvalidOperationException) + { + } + + // (context is IConfigurableApplicationContext) -> OK + Assert.AreSame(allowedAppContext, f.GetCheckedApplicationContext("/AllowedContext")); + } + + [Test] + public void CachesReusableHandlers() + { + TestHandlerFactory f = A.Fake(options => options.CallsBaseMethods()); + IHttpHandler reusableHandler = A.Fake(); + IConfigurableApplicationContext appCtx = A.Fake(); + + // if (IHttpHandler.IsReusable == true) => always returns the same handler instance + // - CreateHandlerInstance() is only called once + A.CallTo(() => reusableHandler.IsReusable).Returns(true); + A.CallTo(() => f.GetContextStub("reusable")).Returns(appCtx); + A.CallTo(() => f.CreateHandlerInstanceStub(appCtx, null, null, "reusable", null)).Returns(reusableHandler); + + Assert.AreSame(reusableHandler, f.GetHandler(null, null, "reusable", null)); + Assert.AreSame(reusableHandler, f.GetHandler(null, null, "reusable", null)); + } + + [Test] + public void DoesntCacheNonReusableHandlers() + { + TestHandlerFactory f = A.Fake(options => options.CallsBaseMethods()); + IHttpHandler nonReusableHandler = A.Fake(); + A.CallTo(() => nonReusableHandler.IsReusable).Returns(false); + IHttpHandler nonReusableHandler2 = A.Fake(); + A.CallTo(() => nonReusableHandler2.IsReusable).Returns(false); + IConfigurableApplicationContext appCtx = A.Fake(); + + // if (IHttpHandler.IsReusable == false) => always create new handler instance + // - CreateHandlerInstance() is called for each request + + A.CallTo(() => f.GetContextStub("notreusable")).Returns(appCtx); + A.CallTo(() => f.CreateHandlerInstanceStub(appCtx, null, null, "notreusable", null)) + .Returns(nonReusableHandler).Once() + .Then.Returns(nonReusableHandler2).Once(); + + Assert.AreSame(nonReusableHandler, f.GetHandler(null, null, "notreusable", null)); + Assert.AreSame(nonReusableHandler2, f.GetHandler(null, null, "notreusable", null)); } } diff --git a/test/Spring/Spring.Web.Tests/Web/Support/ControlInterceptionTests.cs b/test/Spring/Spring.Web.Tests/Web/Support/ControlInterceptionTests.cs index e3678a28..9bc44108 100644 --- a/test/Spring/Spring.Web.Tests/Web/Support/ControlInterceptionTests.cs +++ b/test/Spring/Spring.Web.Tests/Web/Support/ControlInterceptionTests.cs @@ -28,106 +28,125 @@ using Spring.TestSupport; #endregion -namespace Spring.Web.Support +namespace Spring.Web.Support; + +/// +/// Unit tests for the ControlInterceptor class. +/// +/// Erich Eichinger +[TestFixture] +public class ControlInterceptionTests { - /// - /// Unit tests for the ControlInterceptor class. - /// - /// Erich Eichinger - [TestFixture] - public class ControlInterceptionTests + private const string RES_OBJECTS = + "assembly://Spring.Web.Tests/Spring.Web.Support/ControlInterceptionTests.objects.xml"; + + [SetUp] + public void SetUp() { - private const string RES_OBJECTS = - "assembly://Spring.Web.Tests/Spring.Web.Support/ControlInterceptionTests.objects.xml"; + string physDir = AppDomain.CurrentDomain.BaseDirectory + "\\"; + IApplicationContext appContext = + new XmlApplicationContext(AbstractApplicationContext.DefaultRootContextName, false, RES_OBJECTS); + ContextRegistry.RegisterContext(appContext); + appContext = new GenericApplicationContext("/controls/", false, appContext); + ContextRegistry.RegisterContext(appContext); + } - [SetUp] - public void SetUp() - { - string physDir = AppDomain.CurrentDomain.BaseDirectory + "\\"; - IApplicationContext appContext = - new XmlApplicationContext(AbstractApplicationContext.DefaultRootContextName, false, RES_OBJECTS); - ContextRegistry.RegisterContext(appContext); - appContext = new GenericApplicationContext("/controls/", false, appContext); - ContextRegistry.RegisterContext(appContext); - } + [TearDown] + public void TearDown() + { + ContextRegistry.Clear(); + } - [TearDown] - public void TearDown() - { - ContextRegistry.Clear(); - } + [Test] + public void ADDandADDATInjectDependencies() + { + Control ctl = GetRootControl(); - [Test] - public void ADDandADDATInjectDependencies() - { - Control ctl = GetRootControl(); + MockControl mock = new MockControl(); + ctl.Controls.Add(mock); + Assert.IsTrue(mock.GotIt); - MockControl mock = new MockControl(); - ctl.Controls.Add(mock); - Assert.IsTrue(mock.GotIt); + mock = new MockControl(); + ctl.Controls.AddAt(0, mock); + Assert.IsTrue(mock.GotIt); + } - mock = new MockControl(); - ctl.Controls.AddAt(0, mock); - Assert.IsTrue(mock.GotIt); - } + [Test] + public void HierarchyGetsInjectedAfterAttachToTree() + { + MockControl subControl = new MockControl(); + MockControl subSubControl = new MockControl(); + subControl.Controls.Add(subSubControl); - [Test] - public void HierarchyGetsInjectedAfterAttachToTree() - { - MockControl subControl = new MockControl(); - MockControl subSubControl = new MockControl(); - subControl.Controls.Add(subSubControl); + // DI occcurs *after* adding control(s) to rooted hierarchy + Assert.IsFalse(subControl.GotIt); + Assert.IsFalse(subSubControl.GotIt); - // DI occcurs *after* adding control(s) to rooted hierarchy - Assert.IsFalse(subControl.GotIt); - Assert.IsFalse(subSubControl.GotIt); + Control rootControl = GetRootControl(); + rootControl.Controls.Add(subControl); + Assert.IsTrue(subControl.GotIt); + Assert.IsTrue(subSubControl.GotIt); - Control rootControl = GetRootControl(); - rootControl.Controls.Add(subControl); - Assert.IsTrue(subControl.GotIt); - Assert.IsTrue(subSubControl.GotIt); + MockControl subSubSubControl = new MockControl(); + subSubControl.Controls.Add(subSubSubControl); + Assert.IsTrue(subSubSubControl.GotIt); + } - MockControl subSubSubControl = new MockControl(); - subSubControl.Controls.Add(subSubSubControl); - Assert.IsTrue(subSubSubControl.GotIt); - } + [Test] + public void DealsWithNoninheritableControlCollections() + { + Control rootControl = GetRootControl(); - [Test] - public void DealsWithNoninheritableControlCollections() - { - Control rootControl = GetRootControl(); + Control ctl = new ControlWithNoninheritableCollectionType(); + rootControl.Controls.Add(ctl); - Control ctl = new ControlWithNoninheritableCollectionType(); - rootControl.Controls.Add(ctl); + MockControl subControl = new MockControl(); + ctl.Controls.Add(subControl); + Assert.IsTrue(subControl.GotIt); - MockControl subControl = new MockControl(); - ctl.Controls.Add(subControl); - Assert.IsTrue(subControl.GotIt); + MockControl subControl2 = new MockControl(); + ctl.Controls.AddAt(0, subControl2); + Assert.IsTrue(subControl2.GotIt); + } - MockControl subControl2 = new MockControl(); - ctl.Controls.AddAt(0, subControl2); - Assert.IsTrue(subControl2.GotIt); - } + [Test] + public void DealsWithControlCollectionsHavingNonStandardConstructor() + { + Control rootControl = GetRootControl(); - [Test] - public void DealsWithControlCollectionsHavingNonStandardConstructor() - { - Control rootControl = GetRootControl(); + Control ctl = new ControlWithCollectionTypeHavingNonStandardConstructor(); + rootControl.Controls.Add(ctl); - Control ctl = new ControlWithCollectionTypeHavingNonStandardConstructor(); - rootControl.Controls.Add(ctl); + MockControl subControl = new MockControl(); + ctl.Controls.Add(subControl); + Assert.IsTrue(subControl.GotIt); - MockControl subControl = new MockControl(); - ctl.Controls.Add(subControl); - Assert.IsTrue(subControl.GotIt); + MockControl subControl2 = new MockControl(); + ctl.Controls.AddAt(0, subControl2); + Assert.IsTrue(subControl2.GotIt); + } - MockControl subControl2 = new MockControl(); - ctl.Controls.AddAt(0, subControl2); - Assert.IsTrue(subControl2.GotIt); - } + [Test] + public void DealsWithControlsImplementingISupportsWebDependencyInjection() + { + Control rootControl = GetRootControl(); - [Test] - public void DealsWithControlsImplementingISupportsWebDependencyInjection() + Control ctl = new ControlSupportingWebDI(); + rootControl.Controls.Add(ctl); + + MockControl subControl = new MockControl(); + ctl.Controls.Add(subControl); + Assert.IsTrue(subControl.GotIt); + + MockControl subControl2 = new MockControl(); + ctl.Controls.AddAt(0, subControl2); + Assert.IsTrue(subControl2.GotIt); + } + + [Test] + public void SetsApplicationContextOnIApplicationContextAware() + { + using (new TestWebContext("/", "context.aspx")) { Control rootControl = GetRootControl(); @@ -137,183 +156,163 @@ namespace Spring.Web.Support MockControl subControl = new MockControl(); ctl.Controls.Add(subControl); Assert.IsTrue(subControl.GotIt); + Assert.IsNotNull(subControl.ApplicationContext); + Assert.IsTrue(ContextRegistry.GetContext() == subControl.ApplicationContext); - MockControl subControl2 = new MockControl(); + // controls get AppContext from to their location (if any) + MockControl subControl2 = new MockControl("/controls"); ctl.Controls.AddAt(0, subControl2); Assert.IsTrue(subControl2.GotIt); - } - - [Test] - public void SetsApplicationContextOnIApplicationContextAware() - { - using (new TestWebContext("/", "context.aspx")) - { - Control rootControl = GetRootControl(); - - Control ctl = new ControlSupportingWebDI(); - rootControl.Controls.Add(ctl); - - MockControl subControl = new MockControl(); - ctl.Controls.Add(subControl); - Assert.IsTrue(subControl.GotIt); - Assert.IsNotNull(subControl.ApplicationContext); - Assert.IsTrue(ContextRegistry.GetContext() == subControl.ApplicationContext); - - // controls get AppContext from to their location (if any) - MockControl subControl2 = new MockControl("/controls"); - ctl.Controls.AddAt(0, subControl2); - Assert.IsTrue(subControl2.GotIt); - Assert.IsNotNull(subControl2.ApplicationContext); - Assert.IsTrue(ContextRegistry.GetContext("/controls/") == subControl2.ApplicationContext); - } - } - - private Control GetRootControl() - { - Page ctl = new Page(); - WebDependencyInjectionUtils.InjectDependenciesRecursive(ContextRegistry.GetContext(), ctl); - return ctl; + Assert.IsNotNull(subControl2.ApplicationContext); + Assert.IsTrue(ContextRegistry.GetContext("/controls/") == subControl2.ApplicationContext); } } - #region Test Support Classes - - public class MockControl : UserControl, IApplicationContextAware + private Control GetRootControl() { - private bool _gotIt = false; - private IApplicationContext _applicationContext; - private string _templateSourceDirectory = string.Empty; - - public MockControl() - { - } - - public MockControl(string _templateSourceDirectory) - { - this._templateSourceDirectory = _templateSourceDirectory; - } - - public bool GotIt - { - get { return this._gotIt; } - set - { - // ensure DI occurs only once - Assert.IsFalse(GotIt); - this._gotIt = value; - } - } - - public IApplicationContext ApplicationContext - { - get { return _applicationContext; } - set { _applicationContext = value; } - } - - public override string TemplateSourceDirectory - { - get { return _templateSourceDirectory; } - } + Page ctl = new Page(); + WebDependencyInjectionUtils.InjectDependenciesRecursive(ContextRegistry.GetContext(), ctl); + return ctl; } - - public class SimpleControl : Control - { - } - - internal class NoninheritableControlCollection : ControlCollection - { - public NoninheritableControlCollection(Control owner) - : base(owner) - { - } - } - - public class ControlCollectionWithNonStandardConstructor : ControlCollection - { - private int _someValue; - private string _someAdditionalParameter; - - public ControlCollectionWithNonStandardConstructor(Control owner, string someAdditionalParamater, int someValue) - : base(owner) - { - _someAdditionalParameter = someAdditionalParamater; - _someValue = someValue; - } - - public int SomeValue - { - get { return this._someValue; } - } - - public string SomeAdditionalParameter - { - get { return this._someAdditionalParameter; } - } - } - - public class ControlWithNoninheritableCollectionType : Control - { - protected override ControlCollection CreateControlCollection() - { - return new NoninheritableControlCollection(this); - } - } - - public class ControlWithCollectionTypeHavingNonStandardConstructor : Control - { - protected override ControlCollection CreateControlCollection() - { - return new ControlCollectionWithNonStandardConstructor(this, "someAdditionalParameter", 10); - } - } - - public class ControlSupportingWebDI : Control, ISupportsWebDependencyInjection - { - private IApplicationContext _defaultApplicationContext; - - public IApplicationContext DefaultApplicationContext - { - get { return this._defaultApplicationContext; } - set { this._defaultApplicationContext = value; } - } - - protected override void AddedControl(Control control, int index) - { - WebDependencyInjectionUtils.InjectDependenciesRecursive(_defaultApplicationContext, control); - base.AddedControl(control, index); - } - } - - #endregion Test Support Classes - - #region DI Templates // look at them using reflector - - internal class DIControlCollection : ControlCollection, ISupportsWebDependencyInjection - { - private IApplicationContext _defaultApplicationContext; - - public DIControlCollection(Control owner) : base(owner) - { - } - - IApplicationContext ISupportsWebDependencyInjection.DefaultApplicationContext - { - get { return _defaultApplicationContext; } - set { _defaultApplicationContext = value; } - } - - public override void Add(Control child) - { - child = WebDependencyInjectionUtils.InjectDependenciesRecursive(_defaultApplicationContext, child); - base.Add(child); - } - - public override void AddAt(int index, Control child) - { - child = WebDependencyInjectionUtils.InjectDependenciesRecursive(_defaultApplicationContext, child); - base.AddAt(index, child); - } - } - - #endregion } + +#region Test Support Classes + +public class MockControl : UserControl, IApplicationContextAware +{ + private bool _gotIt = false; + private IApplicationContext _applicationContext; + private string _templateSourceDirectory = string.Empty; + + public MockControl() + { + } + + public MockControl(string _templateSourceDirectory) + { + this._templateSourceDirectory = _templateSourceDirectory; + } + + public bool GotIt + { + get { return this._gotIt; } + set + { + // ensure DI occurs only once + Assert.IsFalse(GotIt); + this._gotIt = value; + } + } + + public IApplicationContext ApplicationContext + { + get { return _applicationContext; } + set { _applicationContext = value; } + } + + public override string TemplateSourceDirectory + { + get { return _templateSourceDirectory; } + } +} + +public class SimpleControl : Control +{ +} + +internal class NoninheritableControlCollection : ControlCollection +{ + public NoninheritableControlCollection(Control owner) + : base(owner) + { + } +} + +public class ControlCollectionWithNonStandardConstructor : ControlCollection +{ + private int _someValue; + private string _someAdditionalParameter; + + public ControlCollectionWithNonStandardConstructor(Control owner, string someAdditionalParamater, int someValue) + : base(owner) + { + _someAdditionalParameter = someAdditionalParamater; + _someValue = someValue; + } + + public int SomeValue + { + get { return this._someValue; } + } + + public string SomeAdditionalParameter + { + get { return this._someAdditionalParameter; } + } +} + +public class ControlWithNoninheritableCollectionType : Control +{ + protected override ControlCollection CreateControlCollection() + { + return new NoninheritableControlCollection(this); + } +} + +public class ControlWithCollectionTypeHavingNonStandardConstructor : Control +{ + protected override ControlCollection CreateControlCollection() + { + return new ControlCollectionWithNonStandardConstructor(this, "someAdditionalParameter", 10); + } +} + +public class ControlSupportingWebDI : Control, ISupportsWebDependencyInjection +{ + private IApplicationContext _defaultApplicationContext; + + public IApplicationContext DefaultApplicationContext + { + get { return this._defaultApplicationContext; } + set { this._defaultApplicationContext = value; } + } + + protected override void AddedControl(Control control, int index) + { + WebDependencyInjectionUtils.InjectDependenciesRecursive(_defaultApplicationContext, control); + base.AddedControl(control, index); + } +} + +#endregion Test Support Classes + +#region DI Templates // look at them using reflector + +internal class DIControlCollection : ControlCollection, ISupportsWebDependencyInjection +{ + private IApplicationContext _defaultApplicationContext; + + public DIControlCollection(Control owner) : base(owner) + { + } + + IApplicationContext ISupportsWebDependencyInjection.DefaultApplicationContext + { + get { return _defaultApplicationContext; } + set { _defaultApplicationContext = value; } + } + + public override void Add(Control child) + { + child = WebDependencyInjectionUtils.InjectDependenciesRecursive(_defaultApplicationContext, child); + base.Add(child); + } + + public override void AddAt(int index, Control child) + { + child = WebDependencyInjectionUtils.InjectDependenciesRecursive(_defaultApplicationContext, child); + base.AddAt(index, child); + } +} + +#endregion diff --git a/test/Spring/Spring.Web.Tests/Web/Support/ControlInterceptionTests.objects.xml b/test/Spring/Spring.Web.Tests/Web/Support/ControlInterceptionTests.objects.xml index ae4dccfa..091a68f1 100644 --- a/test/Spring/Spring.Web.Tests/Web/Support/ControlInterceptionTests.objects.xml +++ b/test/Spring/Spring.Web.Tests/Web/Support/ControlInterceptionTests.objects.xml @@ -2,8 +2,8 @@ - - - + + + \ No newline at end of file diff --git a/test/Spring/Spring.Web.Tests/Web/Support/HandlerMapTests.cs b/test/Spring/Spring.Web.Tests/Web/Support/HandlerMapTests.cs index 837cdaa9..e3157086 100644 --- a/test/Spring/Spring.Web.Tests/Web/Support/HandlerMapTests.cs +++ b/test/Spring/Spring.Web.Tests/Web/Support/HandlerMapTests.cs @@ -1,45 +1,43 @@ using NUnit.Framework; -namespace Spring.Web.Support +namespace Spring.Web.Support; + +[TestFixture] +public class HandlerMapTests { - [TestFixture] - public class HandlerMapTests + [Test] + public void CanMatch_EmbeddedLiteralsPattern() { - [Test] - public void CanMatch_EmbeddedLiteralsPattern() - { - HandlerMap map = new HandlerMap(); - map.Add("/*/test2/*", "theHandlerIWant"); + HandlerMap map = new HandlerMap(); + map.Add("/*/test2/*", "theHandlerIWant"); - HandlerMapEntry handler = map.MapPath("/test1/test2/default.aspx"); - - Assert.NotNull(handler); - Assert.AreEqual("theHandlerIWant", handler.HandlerObjectName); - } - - [Test] - public void CanMatch_ExactStringPatterns() - { - HandlerMap map = new HandlerMap(); - map.Add("/test1/test2/default.aspx", "theHandlerIWant"); - - HandlerMapEntry handler = map.MapPath("/test1/test2/default.aspx"); - - Assert.NotNull(handler); - Assert.AreEqual("theHandlerIWant", handler.HandlerObjectName); - } - - [Test] - public void CanMatch_LeadingLiteralsPattern() - { - HandlerMap map = new HandlerMap(); - map.Add("/test1/*", "theHandlerIWant"); - - HandlerMapEntry handler = map.MapPath("/test1/test2/default.aspx"); - - Assert.NotNull(handler); - Assert.AreEqual("theHandlerIWant", handler.HandlerObjectName); - } + HandlerMapEntry handler = map.MapPath("/test1/test2/default.aspx"); + Assert.NotNull(handler); + Assert.AreEqual("theHandlerIWant", handler.HandlerObjectName); } -} + + [Test] + public void CanMatch_ExactStringPatterns() + { + HandlerMap map = new HandlerMap(); + map.Add("/test1/test2/default.aspx", "theHandlerIWant"); + + HandlerMapEntry handler = map.MapPath("/test1/test2/default.aspx"); + + Assert.NotNull(handler); + Assert.AreEqual("theHandlerIWant", handler.HandlerObjectName); + } + + [Test] + public void CanMatch_LeadingLiteralsPattern() + { + HandlerMap map = new HandlerMap(); + map.Add("/test1/*", "theHandlerIWant"); + + HandlerMapEntry handler = map.MapPath("/test1/test2/default.aspx"); + + Assert.NotNull(handler); + Assert.AreEqual("theHandlerIWant", handler.HandlerObjectName); + } +} \ No newline at end of file diff --git a/test/Spring/Spring.Web.Tests/Web/Support/LocalResourceManagerTests.cs b/test/Spring/Spring.Web.Tests/Web/Support/LocalResourceManagerTests.cs index 0e0a24d9..659d3535 100644 --- a/test/Spring/Spring.Web.Tests/Web/Support/LocalResourceManagerTests.cs +++ b/test/Spring/Spring.Web.Tests/Web/Support/LocalResourceManagerTests.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -23,35 +23,35 @@ using NUnit.Framework; using NUnitAspEx.Client; using Spring.TestSupport; -namespace Spring.Web.Support +namespace Spring.Web.Support; + +/// +/// +/// +/// Erich Eichinger +[TestFixture] +[Ignore("Trouble with running under .NET 4.5")] +public class LocalResourceManagerTests : WebApplicationTests { - /// - /// - /// - /// Erich Eichinger - [TestFixture] - [Ignore("Trouble with running under .NET 4.5")] - public class LocalResourceManagerTests : WebApplicationTests + public LocalResourceManagerTests() + : base("/Test", "/Spring/Web/Support/LocalResourceManagerTests") { - public LocalResourceManagerTests() - : base("/Test", "/Spring/Web/Support/LocalResourceManagerTests") - {} + } - [Test] - public void ReturnsWithResources() - { - HttpWebClient client = Host.CreateWebClient(); - string result = client.GetPage("WithResources.aspx"); - Trace.Write(result); - Assert.AreEqual("FromResource", result); - } + [Test] + public void ReturnsWithResources() + { + HttpWebClient client = Host.CreateWebClient(); + string result = client.GetPage("WithResources.aspx"); + Trace.Write(result); + Assert.AreEqual("FromResource", result); + } - [Test] - public void ReturnsWithoutResources() - { - HttpWebClient client = Host.CreateWebClient(); - string result = client.GetPage("WithoutResources.aspx"); - Assert.AreEqual("OK", result); - } + [Test] + public void ReturnsWithoutResources() + { + HttpWebClient client = Host.CreateWebClient(); + string result = client.GetPage("WithoutResources.aspx"); + Assert.AreEqual("OK", result); } } diff --git a/test/Spring/Spring.Web.Tests/Web/Support/MimeMediaTypeTests.cs b/test/Spring/Spring.Web.Tests/Web/Support/MimeMediaTypeTests.cs index 33037bbc..ec9465d6 100644 --- a/test/Spring/Spring.Web.Tests/Web/Support/MimeMediaTypeTests.cs +++ b/test/Spring/Spring.Web.Tests/Web/Support/MimeMediaTypeTests.cs @@ -24,69 +24,99 @@ using NUnit.Framework; #endregion -namespace Spring.Web.Support +namespace Spring.Web.Support; + +/// +/// Tests the MediaType class according to http://www.iana.org/assignments/media-types/ +/// +/// Erich Eichinger +[TestFixture] +public class MimeMediaTypeTests { - /// - /// Tests the MediaType class according to http://www.iana.org/assignments/media-types/ - /// - /// Erich Eichinger - [TestFixture] - public class MimeMediaTypeTests + [Test] + public void CreateInstance() { - [Test] - public void CreateInstance() - { - Assert.AreEqual( MimeMediaType.Application.Octet, new MimeMediaType() ); - MimeMediaType mt = new MimeMediaType("ApPlicatioN"); - Assert.AreEqual("application", mt.ContentType); - Assert.AreEqual("*", mt.SubType); + Assert.AreEqual(MimeMediaType.Application.Octet, new MimeMediaType()); + MimeMediaType mt = new MimeMediaType("ApPlicatioN"); + Assert.AreEqual("application", mt.ContentType); + Assert.AreEqual("*", mt.SubType); - Assert.AreEqual("*", new MimeMediaType("ApPlicatioN", null).SubType); - Assert.AreEqual("*", new MimeMediaType("ApPlicatioN", "").SubType); - Assert.AreEqual("bla", new MimeMediaType("ApPlicatioN", "bla").SubType); + Assert.AreEqual("*", new MimeMediaType("ApPlicatioN", null).SubType); + Assert.AreEqual("*", new MimeMediaType("ApPlicatioN", "").SubType); + Assert.AreEqual("bla", new MimeMediaType("ApPlicatioN", "bla").SubType); + } + + [Test] + public void ToStringReturnsMimeTypeString() + { + Assert.AreEqual("application/subtype", new MimeMediaType("ApPlicatioN", "SubType").ToString()); + } + + [Test] + public void Parse() + { + MimeMediaType mt = MimeMediaType.Parse("text/html"); + Assert.AreEqual("text", mt.ContentType); + Assert.AreEqual("html", mt.SubType); + + try + { + mt = MimeMediaType.Parse(null); + Assert.Fail(); + } + catch (ArgumentNullException) + { + /* ok */ } - [Test] - public void ToStringReturnsMimeTypeString() + try { - Assert.AreEqual("application/subtype", new MimeMediaType("ApPlicatioN", "SubType").ToString()); + mt = MimeMediaType.Parse(""); + Assert.Fail(); + } + catch (ArgumentException) + { + /* ok */ } - [Test] - public void Parse() + try { - MimeMediaType mt = MimeMediaType.Parse("text/html"); - Assert.AreEqual("text", mt.ContentType); - Assert.AreEqual("html", mt.SubType); - - try { mt = MimeMediaType.Parse(null); Assert.Fail(); } - catch (ArgumentNullException) { /* ok */ } - try { mt = MimeMediaType.Parse(""); Assert.Fail(); } - catch (ArgumentException) { /* ok */ } - try { mt = MimeMediaType.Parse("aasdfaDF"); Assert.Fail(); } - catch (ArgumentException) { /* ok */ } - try { mt = MimeMediaType.Parse("*"); Assert.Fail(); } - catch (ArgumentException) { /* ok */ } + mt = MimeMediaType.Parse("aasdfaDF"); + Assert.Fail(); + } + catch (ArgumentException) + { + /* ok */ } - [Test] - public void Equals() + try { - MimeMediaType mt = MimeMediaType.Parse("text/html"); - Assert.AreEqual(MimeMediaType.Text.Html, mt); - Assert.AreEqual(MimeMediaType.Parse("text/html"), mt); - - Assert.AreNotEqual(MimeMediaType.Parse("text/xml"), mt); + mt = MimeMediaType.Parse("*"); + Assert.Fail(); } - - [Test] - public void GetHashcode() + catch (ArgumentException) { - MimeMediaType mt = MimeMediaType.Parse("text/html"); - Assert.AreEqual(MimeMediaType.Text.Html.GetHashCode(), mt.GetHashCode()); - Assert.AreEqual(MimeMediaType.Parse("text/html").GetHashCode(), mt.GetHashCode()); - - Assert.AreNotEqual(MimeMediaType.Parse("text/xml").GetHashCode(), mt.GetHashCode()); + /* ok */ } } + + [Test] + public void Equals() + { + MimeMediaType mt = MimeMediaType.Parse("text/html"); + Assert.AreEqual(MimeMediaType.Text.Html, mt); + Assert.AreEqual(MimeMediaType.Parse("text/html"), mt); + + Assert.AreNotEqual(MimeMediaType.Parse("text/xml"), mt); + } + + [Test] + public void GetHashcode() + { + MimeMediaType mt = MimeMediaType.Parse("text/html"); + Assert.AreEqual(MimeMediaType.Text.Html.GetHashCode(), mt.GetHashCode()); + Assert.AreEqual(MimeMediaType.Parse("text/html").GetHashCode(), mt.GetHashCode()); + + Assert.AreNotEqual(MimeMediaType.Parse("text/xml").GetHashCode(), mt.GetHashCode()); + } } diff --git a/test/Spring/Spring.Web.Tests/Web/Support/PageHandlerFactoryTests.cs b/test/Spring/Spring.Web.Tests/Web/Support/PageHandlerFactoryTests.cs index b3371144..14b92fd2 100644 --- a/test/Spring/Spring.Web.Tests/Web/Support/PageHandlerFactoryTests.cs +++ b/test/Spring/Spring.Web.Tests/Web/Support/PageHandlerFactoryTests.cs @@ -21,7 +21,6 @@ #region Imports using System.Web; - using NUnit.Framework; using NUnitAspEx; using NUnitAspEx.Client; @@ -29,83 +28,82 @@ using Spring.TestSupport; #endregion -namespace Spring.Web.Support +namespace Spring.Web.Support; + +/// +/// +/// +/// Erich Eichinger +[TestFixture] +public class PageHandlerFactoryTests : WebFormTestCase { - /// - /// - /// - /// Erich Eichinger - [TestFixture] - public class PageHandlerFactoryTests : WebFormTestCase + public PageHandlerFactoryTests() + : base("/Test", "/Spring/Web/Support/PageHandlerFactoryTests") { - public PageHandlerFactoryTests() - : base("/Test", "/Spring/Web/Support/PageHandlerFactoryTests") - {} + } - [Test] - public void DisablesSessions() - { - HttpWebClient client = Host.CreateWebClient(); - // a session-less page - checks, if session is correctly disabled - string result = client.GetPage("DisablesSession.aspx"); - Assert.AreEqual("OK", result); - } + [Test] + public void DisablesSessions() + { + HttpWebClient client = Host.CreateWebClient(); + // a session-less page - checks, if session is correctly disabled + string result = client.GetPage("DisablesSession.aspx"); + Assert.AreEqual("OK", result); + } - [Test, Explicit] - public void UsesReadonlySession() - { - HttpWebClient client = Host.CreateWebClient(); - string result = client.GetPage("ReadOnlySession.aspx"); - Assert.AreEqual("OK", result); - } + [Test, Explicit] + public void UsesReadonlySession() + { + HttpWebClient client = Host.CreateWebClient(); + string result = client.GetPage("ReadOnlySession.aspx"); + Assert.AreEqual("OK", result); + } - [Test] - public void MaintainsSession() - { - HttpWebClient client = Host.CreateWebClient(); - string result = client.GetPage("MaintainsSession1.aspx"); - Assert.AreEqual("OK", result); + [Test] + public void MaintainsSession() + { + HttpWebClient client = Host.CreateWebClient(); + string result = client.GetPage("MaintainsSession1.aspx"); + Assert.AreEqual("OK", result); // Assert.AreEqual("somevalue", AspTestContext.HttpContext.Session["maintainsSession"]); - // checks previously set session variable - result = client.GetPage("MaintainsSession2.aspx"); - Assert.AreEqual("OK", result); - } - - /// - /// Tests the behavior of the System.Web.PageHandlerFactory class - /// - [Test] - public void BCLPageHandlerFactoryBehavior() - { - Host.Execute(new TestAction(BCLPageHandlerFactoryBehaviorImpl)); - } + // checks previously set session variable + result = client.GetPage("MaintainsSession2.aspx"); + Assert.AreEqual("OK", result); + } - public static void BCLPageHandlerFactoryBehaviorImpl() + /// + /// Tests the behavior of the System.Web.PageHandlerFactory class + /// + [Test] + public void BCLPageHandlerFactoryBehavior() + { + Host.Execute(new TestAction(BCLPageHandlerFactoryBehaviorImpl)); + } + + public static void BCLPageHandlerFactoryBehaviorImpl() + { + using (TestWebContext ctx = new TestWebContext("/Test", "DoesNotExist.oaspx")) { - using (TestWebContext ctx = new TestWebContext("/Test", "DoesNotExist.oaspx")) + try { - try - { - IHttpHandlerFactory phf = (IHttpHandlerFactory)Activator.CreateInstance(typeof(System.Web.UI.Page).Assembly.GetType("System.Web.UI.PageHandlerFactory"), true); - phf.GetHandler(HttpContext.Current, "GET", ctx.HttpWorkerRequest.GetFilePath(), ctx.HttpWorkerRequest.GetFilePathTranslated()); - } - catch (HttpException e) - { - Assert.AreEqual(404, e.GetHttpCode()); - Assert.IsTrue(e.Message.IndexOf(ctx.HttpWorkerRequest.GetFilePath()) > 0); - } + IHttpHandlerFactory phf = (IHttpHandlerFactory) Activator.CreateInstance(typeof(System.Web.UI.Page).Assembly.GetType("System.Web.UI.PageHandlerFactory"), true); + phf.GetHandler(HttpContext.Current, "GET", ctx.HttpWorkerRequest.GetFilePath(), ctx.HttpWorkerRequest.GetFilePathTranslated()); + } + catch (HttpException e) + { + Assert.AreEqual(404, e.GetHttpCode()); + Assert.IsTrue(e.Message.IndexOf(ctx.HttpWorkerRequest.GetFilePath()) > 0); } } } +} - [TestFixture] - public class PageHandlerFactoryStandaloneTests +[TestFixture] +public class PageHandlerFactoryStandaloneTests +{ + [Test] + public void PageUsesReadonlySessionState() { - [Test] - public void PageUsesReadonlySessionState() - { - - } } } diff --git a/test/Spring/Spring.Web.Tests/Web/Support/ResultFactoryRegistryTests.cs b/test/Spring/Spring.Web.Tests/Web/Support/ResultFactoryRegistryTests.cs index bb4adf9b..fcc90663 100644 --- a/test/Spring/Spring.Web.Tests/Web/Support/ResultFactoryRegistryTests.cs +++ b/test/Spring/Spring.Web.Tests/Web/Support/ResultFactoryRegistryTests.cs @@ -19,77 +19,75 @@ #endregion using FakeItEasy; - using NUnit.Framework; -namespace Spring.Web.Support +namespace Spring.Web.Support; + +/// +/// +/// +/// Erich Eichinger +[TestFixture] +public class ResultFactoryRegistryTests { - /// - /// - /// - /// Erich Eichinger - [TestFixture] - public class ResultFactoryRegistryTests + [SetUp] + public void SetUp() { - [SetUp] - public void SetUp() + ResultFactoryRegistry.Reset(); + } + + [Test] + public void SetDefaultFactory() + { + IResultFactory resultFactory = A.Fake(); + + IResultFactory prevFactory = ResultFactoryRegistry.DefaultResultFactory; + Assert.AreSame(prevFactory, ResultFactoryRegistry.SetDefaultFactory(resultFactory)); + Assert.AreSame(resultFactory, ResultFactoryRegistry.DefaultResultFactory); + + // verify default factory is used for unknown result mode + A.CallTo(() => resultFactory.CreateResult(null, "resultText")).Returns(new Result()); + A.CallTo(() => resultFactory.CreateResult("resultMode", "resultText")).Returns(new Result()); + + ResultFactoryRegistry.CreateResult("resultText"); + ResultFactoryRegistry.CreateResult("resultMode:resultText"); + } + + [Test] + public void ResultModeValuesHavePredefinedFactories() + { + IResultFactory defaultFactory = A.Fake(); + ResultFactoryRegistry.SetDefaultFactory(defaultFactory); + + foreach (string resultMode in Enum.GetNames(typeof(ResultMode))) { - ResultFactoryRegistry.Reset(); - } - - [Test] - public void SetDefaultFactory() - { - IResultFactory resultFactory = A.Fake(); - - IResultFactory prevFactory = ResultFactoryRegistry.DefaultResultFactory; - Assert.AreSame(prevFactory, ResultFactoryRegistry.SetDefaultFactory(resultFactory)); - Assert.AreSame(resultFactory, ResultFactoryRegistry.DefaultResultFactory); - - // verify default factory is used for unknown result mode - A.CallTo(() => resultFactory.CreateResult(null, "resultText")).Returns(new Result()); - A.CallTo(() => resultFactory.CreateResult("resultMode", "resultText")).Returns(new Result()); - - ResultFactoryRegistry.CreateResult("resultText"); - ResultFactoryRegistry.CreateResult("resultMode:resultText"); - } - - [Test] - public void ResultModeValuesHavePredefinedFactories() - { - IResultFactory defaultFactory = A.Fake(); - ResultFactoryRegistry.SetDefaultFactory(defaultFactory); - - foreach (string resultMode in Enum.GetNames(typeof(ResultMode))) - { - Assert.IsNotNull(ResultFactoryRegistry.CreateResult(resultMode + ":resultText")); - } - } - - [Test] - public void SelectsFactoryByResultMode() - { - IResultFactory resultFactory = A.Fake(); - - ResultFactoryRegistry.RegisterResultMode("resultMode", resultFactory); - - Result result = new Result(); - - // verify factory registry does not allow nulls to be returned - A.CallTo(() => resultFactory.CreateResult("resultMode", "resultText")).Returns(result); - Assert.AreSame(result, ResultFactoryRegistry.CreateResult("resultMode:resultText")); - } - - [Test] - public void BailsOnNullReturnedFromFactory() - { - IResultFactory resultFactory = A.Fake(); - - ResultFactoryRegistry.RegisterResultMode("resultMode", resultFactory); - - // verify factory registry does not allow nulls to be returned - A.CallTo(() => resultFactory.CreateResult("resultMode", "resultText")).Returns(null); - Assert.Throws(() => ResultFactoryRegistry.CreateResult("resultMode:resultText")); + Assert.IsNotNull(ResultFactoryRegistry.CreateResult(resultMode + ":resultText")); } } -} + + [Test] + public void SelectsFactoryByResultMode() + { + IResultFactory resultFactory = A.Fake(); + + ResultFactoryRegistry.RegisterResultMode("resultMode", resultFactory); + + Result result = new Result(); + + // verify factory registry does not allow nulls to be returned + A.CallTo(() => resultFactory.CreateResult("resultMode", "resultText")).Returns(result); + Assert.AreSame(result, ResultFactoryRegistry.CreateResult("resultMode:resultText")); + } + + [Test] + public void BailsOnNullReturnedFromFactory() + { + IResultFactory resultFactory = A.Fake(); + + ResultFactoryRegistry.RegisterResultMode("resultMode", resultFactory); + + // verify factory registry does not allow nulls to be returned + A.CallTo(() => resultFactory.CreateResult("resultMode", "resultText")).Returns(null); + Assert.Throws(() => ResultFactoryRegistry.CreateResult("resultMode:resultText")); + } +} \ No newline at end of file diff --git a/test/Spring/Spring.Web.Tests/Web/Support/ResultTests.cs b/test/Spring/Spring.Web.Tests/Web/Support/ResultTests.cs index 255b831e..b33fbb0c 100644 --- a/test/Spring/Spring.Web.Tests/Web/Support/ResultTests.cs +++ b/test/Spring/Spring.Web.Tests/Web/Support/ResultTests.cs @@ -26,235 +26,235 @@ using Spring.Util; #endregion -namespace Spring.Web.Support +namespace Spring.Web.Support; + +/// +/// Unit tests for the Result class. +/// +/// Rick Evans +[TestFixture] +public sealed class ResultTests { - /// - /// Unit tests for the Result class. - /// - /// Rick Evans - [TestFixture] - public sealed class ResultTests - { - private const string ExpectedTargetPageName = "Foo.aspx"; + private const string ExpectedTargetPageName = "Foo.aspx"; - [Test] - public void DoesItDefaultToTheDefaultResultMode() - { - Result result = new Result(); - Assert.AreEqual(Result.DefaultResultMode, result.Mode, "Not defaulting to the default ResultMode."); - } + [Test] + public void DoesItDefaultToTheDefaultResultMode() + { + Result result = new Result(); + Assert.AreEqual(Result.DefaultResultMode, result.Mode, "Not defaulting to the default ResultMode."); + } - [Test] - public void DefaultsToTransferMode() - { - Assert.AreEqual(ResultMode.Transfer, Result.DefaultResultMode, - "Hey! Be sure to change the documentation since you've " + - "obviously gone and changed the default transfer mode."); - } + [Test] + public void DefaultsToTransferMode() + { + Assert.AreEqual(ResultMode.Transfer, Result.DefaultResultMode, + "Hey! Be sure to change the documentation since you've " + + "obviously gone and changed the default transfer mode."); + } - [Test] - public void InstantiationBailsWithNullResultString() - { - Assert.Throws(() => new Result(null)); - } + [Test] + public void InstantiationBailsWithNullResultString() + { + Assert.Throws(() => new Result(null)); + } - [Test] - public void InstantiationBailsWithEmptyResultString() - { - Assert.Throws(() => new Result(string.Empty)); - } + [Test] + public void InstantiationBailsWithEmptyResultString() + { + Assert.Throws(() => new Result(string.Empty)); + } - [Test] - public void InstantiationBailsWithAllWhitespaceResultString() - { - Assert.Throws(() => new Result(" \n\t ")); - } + [Test] + public void InstantiationBailsWithAllWhitespaceResultString() + { + Assert.Throws(() => new Result(" \n\t ")); + } - [Test] - public void WithNoResultModeAndNoParameters() - { - Result result = new Result(ExpectedTargetPageName); - Assert.AreEqual(Result.DefaultResultMode, result.Mode, "Not defaulting to the default ResultMode."); - Assert.IsNull(result.Parameters, - "No parameters were passed but the Parameters property appears to be set to a non-null value anyway."); - Assert.AreEqual(ExpectedTargetPageName, result.TargetPage, - "The TargetPage property is not being correctly extracted " + - "from the result string passed into the ctor."); - } + [Test] + public void WithNoResultModeAndNoParameters() + { + Result result = new Result(ExpectedTargetPageName); + Assert.AreEqual(Result.DefaultResultMode, result.Mode, "Not defaulting to the default ResultMode."); + Assert.IsNull(result.Parameters, + "No parameters were passed but the Parameters property appears to be set to a non-null value anyway."); + Assert.AreEqual(ExpectedTargetPageName, result.TargetPage, + "The TargetPage property is not being correctly extracted " + + "from the result string passed into the ctor."); + } - [Test] - public void WithWhitespacePageAndNoResultModeAndNoParameters() - { - Result result = new Result(" " + ExpectedTargetPageName + "\n"); - Assert.AreEqual(Result.DefaultResultMode, result.Mode, "Not defaulting to the default ResultMode."); - Assert.IsNull(result.Parameters, - "No parameters were passed but the Parameters property appears to be set to a non-null value anyway."); - Assert.AreEqual(ExpectedTargetPageName, result.TargetPage, - "The TargetPage property is not being correctly extracted " + - "from the result string passed into the ctor."); - } + [Test] + public void WithWhitespacePageAndNoResultModeAndNoParameters() + { + Result result = new Result(" " + ExpectedTargetPageName + "\n"); + Assert.AreEqual(Result.DefaultResultMode, result.Mode, "Not defaulting to the default ResultMode."); + Assert.IsNull(result.Parameters, + "No parameters were passed but the Parameters property appears to be set to a non-null value anyway."); + Assert.AreEqual(ExpectedTargetPageName, result.TargetPage, + "The TargetPage property is not being correctly extracted " + + "from the result string passed into the ctor."); + } - [Test] - public void WithTransferResultModeButNoParameters() - { - Result result = new Result("transfer:" + ExpectedTargetPageName); - Assert.AreEqual(ResultMode.Transfer, result.Mode, "Not extracting the correct ResultMode " + - "from the result string passed into the ctor."); - Assert.AreEqual(true, result.PreserveForm, "ResultMode.Transfer must result in PreserveForm being 'true'"); - Assert.IsNull(result.Parameters, - "No parameters were passed but the Parameters property appears to be set to a non-null value anyway."); - Assert.AreEqual(ExpectedTargetPageName, result.TargetPage, - "The TargetPage property is not being correctly extracted " + - "from the result string passed into the ctor."); - } + [Test] + public void WithTransferResultModeButNoParameters() + { + Result result = new Result("transfer:" + ExpectedTargetPageName); + Assert.AreEqual(ResultMode.Transfer, result.Mode, "Not extracting the correct ResultMode " + + "from the result string passed into the ctor."); + Assert.AreEqual(true, result.PreserveForm, "ResultMode.Transfer must result in PreserveForm being 'true'"); + Assert.IsNull(result.Parameters, + "No parameters were passed but the Parameters property appears to be set to a non-null value anyway."); + Assert.AreEqual(ExpectedTargetPageName, result.TargetPage, + "The TargetPage property is not being correctly extracted " + + "from the result string passed into the ctor."); + } - [Test] - public void WithTransferNoPreserveResultMode() - { - Result result = new Result( "transfernopreserve:" + ExpectedTargetPageName ); - Assert.AreEqual( ResultMode.TransferNoPreserve,result.Mode,"Not extracting the correct ResultMode " + - "from the result string passed into the ctor." ); - Assert.AreEqual( false,result.PreserveForm,"ResultMode.TransferNoPreserver must result in PreserveForm being 'false'" ); - } + [Test] + public void WithTransferNoPreserveResultMode() + { + Result result = new Result("transfernopreserve:" + ExpectedTargetPageName); + Assert.AreEqual(ResultMode.TransferNoPreserve, result.Mode, "Not extracting the correct ResultMode " + + "from the result string passed into the ctor."); + Assert.AreEqual(false, result.PreserveForm, "ResultMode.TransferNoPreserver must result in PreserveForm being 'false'"); + } - [Test] - public void WithWhitespacedRedirectResultMode() - { - Result result = new Result(" redirect:" + ExpectedTargetPageName); - Assert.AreEqual(ResultMode.Redirect, result.Mode, "Not extracting the correct ResultMode " + - "from the result string passed into the ctor."); - Assert.IsNull(result.Parameters, - "No parameters were passed but the Parameters property appears to be set to a non-null value anyway."); - Assert.AreEqual(ExpectedTargetPageName, result.TargetPage, - "The TargetPage property is not being correctly extracted " + - "from the result string passed into the ctor."); - } + [Test] + public void WithWhitespacedRedirectResultMode() + { + Result result = new Result(" redirect:" + ExpectedTargetPageName); + Assert.AreEqual(ResultMode.Redirect, result.Mode, "Not extracting the correct ResultMode " + + "from the result string passed into the ctor."); + Assert.IsNull(result.Parameters, + "No parameters were passed but the Parameters property appears to be set to a non-null value anyway."); + Assert.AreEqual(ExpectedTargetPageName, result.TargetPage, + "The TargetPage property is not being correctly extracted " + + "from the result string passed into the ctor."); + } - [Test] - public void WithRedirectResultMode() - { - Result result = new Result("redirect:" + ExpectedTargetPageName); - Assert.AreEqual(ResultMode.Redirect, result.Mode, "Not extracting the correct ResultMode " + - "from the result string passed into the ctor."); - Assert.IsTrue(result.EndResponse); - Assert.IsNull(result.Parameters, - "No parameters were passed but the Parameters property appears to be set to a non-null value anyway."); - Assert.AreEqual(ExpectedTargetPageName, result.TargetPage, - "The TargetPage property is not being correctly extracted " + - "from the result string passed into the ctor."); - } + [Test] + public void WithRedirectResultMode() + { + Result result = new Result("redirect:" + ExpectedTargetPageName); + Assert.AreEqual(ResultMode.Redirect, result.Mode, "Not extracting the correct ResultMode " + + "from the result string passed into the ctor."); + Assert.IsTrue(result.EndResponse); + Assert.IsNull(result.Parameters, + "No parameters were passed but the Parameters property appears to be set to a non-null value anyway."); + Assert.AreEqual(ExpectedTargetPageName, result.TargetPage, + "The TargetPage property is not being correctly extracted " + + "from the result string passed into the ctor."); + } - [Test] - public void WithRedirectNoAbortResultMode() - { - Result result = new Result("redirectnoabort:" + ExpectedTargetPageName); - Assert.AreEqual(ResultMode.RedirectNoAbort, result.Mode, "Not extracting the correct ResultMode " + - "from the result string passed into the ctor."); - Assert.IsFalse(result.EndResponse); - Assert.IsNull(result.Parameters, - "No parameters were passed but the Parameters property appears to be set to a non-null value anyway."); - Assert.AreEqual(ExpectedTargetPageName, result.TargetPage, - "The TargetPage property is not being correctly extracted " + - "from the result string passed into the ctor."); - } + [Test] + public void WithRedirectNoAbortResultMode() + { + Result result = new Result("redirectnoabort:" + ExpectedTargetPageName); + Assert.AreEqual(ResultMode.RedirectNoAbort, result.Mode, "Not extracting the correct ResultMode " + + "from the result string passed into the ctor."); + Assert.IsFalse(result.EndResponse); + Assert.IsNull(result.Parameters, + "No parameters were passed but the Parameters property appears to be set to a non-null value anyway."); + Assert.AreEqual(ExpectedTargetPageName, result.TargetPage, + "The TargetPage property is not being correctly extracted " + + "from the result string passed into the ctor."); + } - [Test] - public void WithRubbishResultMode() - { - // note the incorrect spelling of the result mode prefix... - Assert.Throws(() => new Result("redirct:" + ExpectedTargetPageName)); - } + [Test] + public void WithRubbishResultMode() + { + // note the incorrect spelling of the result mode prefix... + Assert.Throws(() => new Result("redirct:" + ExpectedTargetPageName)); + } - [Test] - public void WithResultModeAndEmptyParameterDelimiterOnly() - { - Result result = new Result("transfer:" + ExpectedTargetPageName + "?"); - Assert.AreEqual(ResultMode.Transfer, result.Mode, "Not extracting the correct ResultMode " + - "from the result string passed into the ctor."); - Assert.IsNull(result.Parameters, - "No parameters were passed (just the parameter delimiter) but the " + - "Parameters property appears to be set to a non-null value anyway."); - Assert.AreEqual(ExpectedTargetPageName, result.TargetPage, - "The TargetPage property is not being correctly extracted " + - "from the result string passed into the ctor."); - } + [Test] + public void WithResultModeAndEmptyParameterDelimiterOnly() + { + Result result = new Result("transfer:" + ExpectedTargetPageName + "?"); + Assert.AreEqual(ResultMode.Transfer, result.Mode, "Not extracting the correct ResultMode " + + "from the result string passed into the ctor."); + Assert.IsNull(result.Parameters, + "No parameters were passed (just the parameter delimiter) but the " + + "Parameters property appears to be set to a non-null value anyway."); + Assert.AreEqual(ExpectedTargetPageName, result.TargetPage, + "The TargetPage property is not being correctly extracted " + + "from the result string passed into the ctor."); + } - [Test] - public void WithResultModeAndWhitespaceParameterDelimiterOnly() - { - Result result = new Result("redirect:" + ExpectedTargetPageName + "? "); - Assert.AreEqual(ResultMode.Redirect, result.Mode, "Not extracting the correct ResultMode " + - "from the result string passed into the ctor."); - Assert.IsNull(result.Parameters, - "No parameters were passed (just the parameter delimiter) but the " + - "Parameters property appears to be set to a non-null value anyway."); - Assert.AreEqual(ExpectedTargetPageName, result.TargetPage, - "The TargetPage property is not being correctly extracted " + - "from the result string passed into the ctor."); - } + [Test] + public void WithResultModeAndWhitespaceParameterDelimiterOnly() + { + Result result = new Result("redirect:" + ExpectedTargetPageName + "? "); + Assert.AreEqual(ResultMode.Redirect, result.Mode, "Not extracting the correct ResultMode " + + "from the result string passed into the ctor."); + Assert.IsNull(result.Parameters, + "No parameters were passed (just the parameter delimiter) but the " + + "Parameters property appears to be set to a non-null value anyway."); + Assert.AreEqual(ExpectedTargetPageName, result.TargetPage, + "The TargetPage property is not being correctly extracted " + + "from the result string passed into the ctor."); + } - [Test] - public void WithNoResultModeAndWhitespaceParameterDelimiterOnly() - { - Result result = new Result(ExpectedTargetPageName + "? "); - Assert.AreEqual(Result.DefaultResultMode, result.Mode, "Not defaulting to the default ResultMode."); - Assert.IsNull(result.Parameters, - "No parameters were passed (just the parameter delimiter) but the " + - "Parameters property appears to be set to a non-null value anyway."); - Assert.AreEqual(ExpectedTargetPageName, result.TargetPage, - "The TargetPage property is not being correctly extracted " + - "from the result string passed into the ctor."); - } + [Test] + public void WithNoResultModeAndWhitespaceParameterDelimiterOnly() + { + Result result = new Result(ExpectedTargetPageName + "? "); + Assert.AreEqual(Result.DefaultResultMode, result.Mode, "Not defaulting to the default ResultMode."); + Assert.IsNull(result.Parameters, + "No parameters were passed (just the parameter delimiter) but the " + + "Parameters property appears to be set to a non-null value anyway."); + Assert.AreEqual(ExpectedTargetPageName, result.TargetPage, + "The TargetPage property is not being correctly extracted " + + "from the result string passed into the ctor."); + } - [Test] - public void WithNoResultModeAndOneParameter() - { - const string key = "id"; - const string value = "Nina Persson"; - Result result = new Result(ExpectedTargetPageName + "?" + key + "=" + value); - Assert.AreEqual(Result.DefaultResultMode, result.Mode, "Not defaulting to the default ResultMode."); - Assert.IsNotNull(result.Parameters, - "Parameters were passed but the Parameters property appears to be null (incorrectly)."); - Assert.AreEqual(1, result.Parameters.Count, - "Wrong number of query parameters parsed (only supplied one key-value pair)."); - Assert.IsTrue(result.Parameters.Contains(key), "The 'id' parameter is not being correctly extracted " + - "from the result string passed into the ctor."); - Assert.AreEqual(value, result.Parameters[key]); - Assert.AreEqual(ExpectedTargetPageName, result.TargetPage, - "The TargetPage property is not being correctly extracted " + - "from the result string passed into the ctor."); - } + [Test] + public void WithNoResultModeAndOneParameter() + { + const string key = "id"; + const string value = "Nina Persson"; + Result result = new Result(ExpectedTargetPageName + "?" + key + "=" + value); + Assert.AreEqual(Result.DefaultResultMode, result.Mode, "Not defaulting to the default ResultMode."); + Assert.IsNotNull(result.Parameters, + "Parameters were passed but the Parameters property appears to be null (incorrectly)."); + Assert.AreEqual(1, result.Parameters.Count, + "Wrong number of query parameters parsed (only supplied one key-value pair)."); + Assert.IsTrue(result.Parameters.Contains(key), "The 'id' parameter is not being correctly extracted " + + "from the result string passed into the ctor."); + Assert.AreEqual(value, result.Parameters[key]); + Assert.AreEqual(ExpectedTargetPageName, result.TargetPage, + "The TargetPage property is not being correctly extracted " + + "from the result string passed into the ctor."); + } - [Test] - public void WithTransferResultModeAndOneParameter() - { - const string key = "id"; - const string value = "Nina Persson"; - Result result = new Result("transfer:" + ExpectedTargetPageName + "?" + key + "=" + value); - Assert.AreEqual(ResultMode.Transfer, result.Mode, "Not extracting the correct ResultMode " + - "from the result string passed into the ctor."); - Assert.IsNotNull(result.Parameters, - "Parameters were passed but the Parameters property appears to be null (incorrectly)."); - Assert.AreEqual(1, result.Parameters.Count, - "Wrong number of query parameters parsed (only supplied one key-value pair)."); - Assert.IsTrue(result.Parameters.Contains(key), "The 'id' parameter is not being correctly extracted " + - "from the result string passed into the ctor."); - Assert.AreEqual(value, result.Parameters[key]); - Assert.AreEqual(ExpectedTargetPageName, result.TargetPage, - "The TargetPage property is not being correctly extracted " + - "from the result string passed into the ctor."); - } + [Test] + public void WithTransferResultModeAndOneParameter() + { + const string key = "id"; + const string value = "Nina Persson"; + Result result = new Result("transfer:" + ExpectedTargetPageName + "?" + key + "=" + value); + Assert.AreEqual(ResultMode.Transfer, result.Mode, "Not extracting the correct ResultMode " + + "from the result string passed into the ctor."); + Assert.IsNotNull(result.Parameters, + "Parameters were passed but the Parameters property appears to be null (incorrectly)."); + Assert.AreEqual(1, result.Parameters.Count, + "Wrong number of query parameters parsed (only supplied one key-value pair)."); + Assert.IsTrue(result.Parameters.Contains(key), "The 'id' parameter is not being correctly extracted " + + "from the result string passed into the ctor."); + Assert.AreEqual(value, result.Parameters[key]); + Assert.AreEqual(ExpectedTargetPageName, result.TargetPage, + "The TargetPage property is not being correctly extracted " + + "from the result string passed into the ctor."); + } - [Test] - [Ignore("How does one escape ampersands then?")] - public void ParametersHavingEmbeddedCharactersThatHaveToBeEscaped() - { - const string key = "id"; - const string value = "Nina Persson & The Cardigans"; // notice the use of the embedded '&'... - Result result = new Result(ExpectedTargetPageName + "?" + key + "=" + value); - Assert.AreEqual(Result.DefaultResultMode, result.Mode, "Not defaulting to the default ResultMode."); - Assert.IsNotNull(result.Parameters, - "Parameters were passed but the Parameters property appears to be null (incorrectly)."); + [Test] + [Ignore("How does one escape ampersands then?")] + public void ParametersHavingEmbeddedCharactersThatHaveToBeEscaped() + { + const string key = "id"; + const string value = "Nina Persson & The Cardigans"; // notice the use of the embedded '&'... + Result result = new Result(ExpectedTargetPageName + "?" + key + "=" + value); + Assert.AreEqual(Result.DefaultResultMode, result.Mode, "Not defaulting to the default ResultMode."); + Assert.IsNotNull(result.Parameters, + "Parameters were passed but the Parameters property appears to be null (incorrectly)."); // Assert.AreEqual(1, result.Parameters.Count, // "Wrong number of query parameters parsed (only supplied one key-value pair)."); // Assert.IsTrue(result.Parameters.Contains(key), "The 'id' parameter is not being correctly extracted " + @@ -263,114 +263,114 @@ namespace Spring.Web.Support // Assert.AreEqual(ExpectedTargetPageName, result.TargetPage, // "The TargetPage property is not being correctly extracted " + // "from the result string passed into the ctor."); - } + } - [Test] - public void WithTransferResultModeAndTwoParametersSplitUsingAmpersand() - { - const string pKey1 = "id"; - const string pValue1 = "Nina Persson"; - const string pKey2 = "verdict"; - const string pValue2 = "schwing"; - Result result = - new Result(ExpectedTargetPageName + "?" + pKey1 + "=" + pValue1 + "&" + pKey2 + "=" + pValue2); - Assert.AreEqual(ResultMode.Transfer, result.Mode, "Not extracting the correct ResultMode " + - "from the result string passed into the ctor."); - Assert.IsNotNull(result.Parameters, - "Parameters were passed but the Parameters property appears to be null (incorrectly)."); - Assert.AreEqual(2, result.Parameters.Count, - "Wrong number of query parameters parsed (supplied two key-value pairs)."); - Assert.IsTrue(result.Parameters.Contains(pKey1), "The 'id' parameter is not being correctly extracted " + - "from the result string passed into the ctor."); - Assert.AreEqual(pValue1, result.Parameters[pKey1]); - Assert.IsTrue(result.Parameters.Contains(pKey2), - "The 'verdict' parameter is not being correctly extracted " + - "from the result string passed into the ctor."); - Assert.AreEqual(pValue2, result.Parameters[pKey2]); - Assert.AreEqual(ExpectedTargetPageName, result.TargetPage, - "The TargetPage property is not being correctly extracted " + - "from the result string passed into the ctor."); - } + [Test] + public void WithTransferResultModeAndTwoParametersSplitUsingAmpersand() + { + const string pKey1 = "id"; + const string pValue1 = "Nina Persson"; + const string pKey2 = "verdict"; + const string pValue2 = "schwing"; + Result result = + new Result(ExpectedTargetPageName + "?" + pKey1 + "=" + pValue1 + "&" + pKey2 + "=" + pValue2); + Assert.AreEqual(ResultMode.Transfer, result.Mode, "Not extracting the correct ResultMode " + + "from the result string passed into the ctor."); + Assert.IsNotNull(result.Parameters, + "Parameters were passed but the Parameters property appears to be null (incorrectly)."); + Assert.AreEqual(2, result.Parameters.Count, + "Wrong number of query parameters parsed (supplied two key-value pairs)."); + Assert.IsTrue(result.Parameters.Contains(pKey1), "The 'id' parameter is not being correctly extracted " + + "from the result string passed into the ctor."); + Assert.AreEqual(pValue1, result.Parameters[pKey1]); + Assert.IsTrue(result.Parameters.Contains(pKey2), + "The 'verdict' parameter is not being correctly extracted " + + "from the result string passed into the ctor."); + Assert.AreEqual(pValue2, result.Parameters[pKey2]); + Assert.AreEqual(ExpectedTargetPageName, result.TargetPage, + "The TargetPage property is not being correctly extracted " + + "from the result string passed into the ctor."); + } - [Test] - public void WithWhitespacedPageAndTransferResultModeAndTwoParametersUsingAmpersands() - { - const string pKey1 = "id"; - const string pValue1 = "Nina Persson"; - const string pKey2 = "verdict"; - const string pValue2 = "schwing"; - Result result = - new Result("\n" + ExpectedTargetPageName + " ?" + pKey1 + "=" + pValue1 + "&" + pKey2 + "=" + pValue2); - Assert.AreEqual(ResultMode.Transfer, result.Mode, "Not extracting the correct ResultMode " + - "from the result string passed into the ctor."); - Assert.IsNotNull(result.Parameters, - "Parameters were passed but the Parameters property appears to be null (incorrectly)."); - Assert.AreEqual(2, result.Parameters.Count, - "Wrong number of query parameters parsed (supplied two key-value pairs)."); - Assert.IsTrue(result.Parameters.Contains(pKey1), "The 'id' parameter is not being correctly extracted " + - "from the result string passed into the ctor."); - Assert.AreEqual(pValue1, result.Parameters[pKey1]); - Assert.IsTrue(result.Parameters.Contains(pKey2), - "The 'verdict' parameter is not being correctly extracted " + - "from the result string passed into the ctor."); - Assert.AreEqual(pValue2, result.Parameters[pKey2]); - Assert.AreEqual(ExpectedTargetPageName, result.TargetPage, - "The TargetPage property is not being correctly extracted " + - "from the result string passed into the ctor."); - } + [Test] + public void WithWhitespacedPageAndTransferResultModeAndTwoParametersUsingAmpersands() + { + const string pKey1 = "id"; + const string pValue1 = "Nina Persson"; + const string pKey2 = "verdict"; + const string pValue2 = "schwing"; + Result result = + new Result("\n" + ExpectedTargetPageName + " ?" + pKey1 + "=" + pValue1 + "&" + pKey2 + "=" + pValue2); + Assert.AreEqual(ResultMode.Transfer, result.Mode, "Not extracting the correct ResultMode " + + "from the result string passed into the ctor."); + Assert.IsNotNull(result.Parameters, + "Parameters were passed but the Parameters property appears to be null (incorrectly)."); + Assert.AreEqual(2, result.Parameters.Count, + "Wrong number of query parameters parsed (supplied two key-value pairs)."); + Assert.IsTrue(result.Parameters.Contains(pKey1), "The 'id' parameter is not being correctly extracted " + + "from the result string passed into the ctor."); + Assert.AreEqual(pValue1, result.Parameters[pKey1]); + Assert.IsTrue(result.Parameters.Contains(pKey2), + "The 'verdict' parameter is not being correctly extracted " + + "from the result string passed into the ctor."); + Assert.AreEqual(pValue2, result.Parameters[pKey2]); + Assert.AreEqual(ExpectedTargetPageName, result.TargetPage, + "The TargetPage property is not being correctly extracted " + + "from the result string passed into the ctor."); + } - [Test] - public void WithWhitespacedPageAndTransferResultModeAndTwoParametersUsingCommas() - { - const string pKey1 = "id"; - const string pValue1 = "Nina Persson"; - const string pKey2 = "verdict"; - const string pValue2 = "schwing"; - Result result = - new Result("\n" + ExpectedTargetPageName + " ?" + pKey1 + "=" + pValue1 + "," + pKey2 + "=" + pValue2); - Assert.AreEqual(ResultMode.Transfer, result.Mode, "Not extracting the correct ResultMode " + - "from the result string passed into the ctor."); - Assert.IsNotNull(result.Parameters, - "Parameters were passed but the Parameters property appears to be null (incorrectly)."); - Assert.AreEqual(2, result.Parameters.Count, - "Wrong number of query parameters parsed (supplied two key-value pairs)."); - Assert.IsTrue(result.Parameters.Contains(pKey1), "The 'id' parameter is not being correctly extracted " + - "from the result string passed into the ctor."); - Assert.AreEqual(pValue1, result.Parameters[pKey1]); - Assert.IsTrue(result.Parameters.Contains(pKey2), - "The 'verdict' parameter is not being correctly extracted " + - "from the result string passed into the ctor."); - Assert.AreEqual(pValue2, result.Parameters[pKey2]); - Assert.AreEqual(ExpectedTargetPageName, result.TargetPage, - "The TargetPage property is not being correctly extracted " + - "from the result string passed into the ctor."); - } + [Test] + public void WithWhitespacedPageAndTransferResultModeAndTwoParametersUsingCommas() + { + const string pKey1 = "id"; + const string pValue1 = "Nina Persson"; + const string pKey2 = "verdict"; + const string pValue2 = "schwing"; + Result result = + new Result("\n" + ExpectedTargetPageName + " ?" + pKey1 + "=" + pValue1 + "," + pKey2 + "=" + pValue2); + Assert.AreEqual(ResultMode.Transfer, result.Mode, "Not extracting the correct ResultMode " + + "from the result string passed into the ctor."); + Assert.IsNotNull(result.Parameters, + "Parameters were passed but the Parameters property appears to be null (incorrectly)."); + Assert.AreEqual(2, result.Parameters.Count, + "Wrong number of query parameters parsed (supplied two key-value pairs)."); + Assert.IsTrue(result.Parameters.Contains(pKey1), "The 'id' parameter is not being correctly extracted " + + "from the result string passed into the ctor."); + Assert.AreEqual(pValue1, result.Parameters[pKey1]); + Assert.IsTrue(result.Parameters.Contains(pKey2), + "The 'verdict' parameter is not being correctly extracted " + + "from the result string passed into the ctor."); + Assert.AreEqual(pValue2, result.Parameters[pKey2]); + Assert.AreEqual(ExpectedTargetPageName, result.TargetPage, + "The TargetPage property is not being correctly extracted " + + "from the result string passed into the ctor."); + } - [Test] - public void TargetPageMayBeRuntimeExpression() - { - Result result = new Result("%{['var1']}"); - string resultUri = result.GetRedirectUri( MakeDictionary("var1", "val1") ); - Assert.AreEqual( "val1", resultUri ); - } + [Test] + public void TargetPageMayBeRuntimeExpression() + { + Result result = new Result("%{['var1']}"); + string resultUri = result.GetRedirectUri(MakeDictionary("var1", "val1")); + Assert.AreEqual("val1", resultUri); + } - [Test] - public void ParameterKeysAndValuesMayBeRuntimeExpression() - { - Result result = new Result("redirect:%{['var1']}?%{['var2']}=%{['var3']}"); - string resultUri = result.GetRedirectUri( MakeDictionary("var1", "val1", "var2", "val2", "var3", "val3") ); - Assert.AreEqual( "val1?val2=val3", resultUri ); - } + [Test] + public void ParameterKeysAndValuesMayBeRuntimeExpression() + { + Result result = new Result("redirect:%{['var1']}?%{['var2']}=%{['var3']}"); + string resultUri = result.GetRedirectUri(MakeDictionary("var1", "val1", "var2", "val2", "var3", "val3")); + Assert.AreEqual("val1?val2=val3", resultUri); + } - private IDictionary MakeDictionary( params object[] args) - { - AssertUtils.IsTrue(args.Length % 2 == 0); - Hashtable ht= new Hashtable(); - for(int i=0;i +/// +/// +/// Erich Eichinger +[TestFixture] +public class AbstractValidationControlTests { - /// - /// - /// - /// Erich Eichinger - [TestFixture] - public class AbstractValidationControlTests + [Test] + public void DefaultsToControlIDOrStringEmptyAsProviderName() { - [Test] - public void DefaultsToControlIDOrStringEmptyAsProviderName() - { - TestValidationControl vc; + TestValidationControl vc; - vc = new TestValidationControl(null); - Assert.AreEqual(string.Empty, vc.Provider); + vc = new TestValidationControl(null); + Assert.AreEqual(string.Empty, vc.Provider); - vc = new TestValidationControl(null); - vc.ID = "TestControl"; - Assert.AreEqual(vc.ID, vc.Provider); + vc = new TestValidationControl(null); + vc.ID = "TestControl"; + Assert.AreEqual(vc.ID, vc.Provider); - vc = new TestValidationControl(null); - vc.ID = "TestControl"; - vc.Provider = "TestProvider"; + vc = new TestValidationControl(null); + vc.ID = "TestControl"; + vc.Provider = "TestProvider"; - Assert.AreEqual("TestProvider", vc.Provider); - } - - [Test] - public void ResolvesAndRendersValidationErrorsUsingValidationContainer() - { - TestValidationControl vc = new TestValidationControl(); - vc.ID = "TestControl"; - - Page page = new Page(); - page.Controls.Add(vc); - page.ValidationErrors.AddError(vc.Provider, new ErrorMessage("msgId")); - StaticMessageSource msgSrc = new StaticMessageSource(); - msgSrc.AddMessage("msgId", CultureInfo.CurrentUICulture, "Resolved Message Text"); - page.MessageSource = msgSrc; - - vc.TestRender(null); - Assert.AreEqual("Resolved Message Text", vc.LastErrorsRendered[0]); - } - - [Test] - public void ResolvesAndRendersValidationErrorsUsingExplicitlySpecifiedErrorsAndMessageSource() - { - TestValidationControl vc = new TestValidationControl(); - vc.ID = "TestControl"; - - Page page = new Page(); - page.Controls.Add(vc); - - ValidationErrors errors = new ValidationErrors(); - errors.AddError(vc.Provider, new ErrorMessage("msgId")); - vc.ValidationErrors = errors; - - StaticMessageSource msgSrc = new StaticMessageSource(); - msgSrc.AddMessage("msgId", CultureInfo.CurrentUICulture, "Resolved Message Text"); - vc.MessageSource = msgSrc; - - vc.TestRender(null); - Assert.AreEqual("Resolved Message Text", vc.LastErrorsRendered[0]); - } - - [Test] - public void ThrowsIfCreateValidationErrorsRendererReturnsNull() - { - TestValidationControl vc = new TestValidationControl(null); - vc.ID = "TestControl"; - - Page page = new Page(); - page.Controls.Add(vc); - page.ValidationErrors.AddError(vc.Provider, new ErrorMessage("msgId")); - - try - { - vc.TestRender(null); - Assert.Fail(); - } - catch (ArgumentNullException ane) - { - Assert.AreEqual("Renderer", ane.ParamName); - } - } - - [Test] - public void NoExceptionWhenNoValidationContainer() - { - TestValidationControl vc = new TestValidationControl(); - Assert.IsFalse(vc.TheDesignMode); - Assert.IsNull(vc.TheMessageSource); - Assert.IsNull(vc.TheValidationContainer); - - vc.TestRender(null); - } - - [Test] - public void NoExceptionWhenNoErrors() - { - Page page = new Page(); - page.MessageSource = new StaticMessageSource(); - TestValidationControl vc = new TestValidationControl(); - page.Controls.Add(vc); - - // assert assumptions - Assert.IsFalse(vc.TheDesignMode); - Assert.AreSame(page, vc.TheValidationContainer); - Assert.AreSame( page.MessageSource, vc.TheMessageSource ); - Assert.AreEqual(0, page.ValidationErrors.GetResolvedErrors(vc.Provider, vc.TheMessageSource).Count); - - vc.TestRender(null); - } - - [Test] - public void ResolveValidationContainerToEnclosingParentRecursively() - { - // direct containment - UserControl uc = new UserControl(); - TestValidationControl vc = new TestValidationControl(); - uc.Controls.Add(vc); - Assert.AreSame(uc, vc.TheValidationContainer); - - // indirect containment - uc = new UserControl(); - vc = new TestValidationControl(); - Control inBetweenControl = new Panel(); - inBetweenControl.Controls.Add(vc); - uc.Controls.Add(inBetweenControl); - Assert.AreSame(uc, vc.TheValidationContainer); - } - - [Test] - public void ResolveValidationContainerToEnclosingPageRecursively() - { - // direct containment - Page page = new Page(); - TestValidationControl vc = new TestValidationControl(); - page.Controls.Add(vc); - Assert.AreSame(page, vc.TheValidationContainer); - - // indirect containment - page = new Page(); - vc = new TestValidationControl(); - Control inBetweenControl = new System.Web.UI.WebControls.Panel(); - inBetweenControl.Controls.Add(vc); - page.Controls.Add(inBetweenControl); - Assert.AreSame(page, vc.TheValidationContainer); - } - - [Test] - public void DefaultsToValidationContainerMessageSource() - { - IMessageSource messageSource = A.Fake(); - // IValidationContainer container = (IValidationContainer)mocks.DynamicMock(typeof(IValidationContainer)); - - Page page = new Page(); - page.MessageSource = messageSource; - TestValidationControl ctl = new TestValidationControl(); - page.Controls.Add(ctl); - - Assert.AreEqual(messageSource, ctl.TheMessageSource); - } - - [Test] - public void ReadsErrorsFromClosestValidationContainerByDefault() - { - // indirect containment - Spring.Web.UI.Page page = new Spring.Web.UI.Page(); - TestValidationControl vc = new TestValidationControl(); - Spring.Web.UI.UserControl inBetweenControl = new Spring.Web.UI.UserControl(); - inBetweenControl.Controls.Add(vc); - page.Controls.Add(inBetweenControl); - Assert.AreSame(inBetweenControl, vc.TheValidationContainer); - } - - [Test] - public void DoesNotReadErrorsFromCrossValidationContainerByDefault() - { - // containment tree: - // - // Page : IValidationContainer - // - outerVC - // - inBetweenControl1 : IValidationContainer - // - innerVC - - Spring.Web.UI.Page page = new Spring.Web.UI.Page(); - Spring.Web.UI.UserControl inBetweenControl1 = new Spring.Web.UI.UserControl(); - inBetweenControl1.ID = "InBetweenControl1"; - TestValidationControl innerVC = new TestValidationControl(); - inBetweenControl1.Controls.Add(innerVC); - page.Controls.Add(inBetweenControl1); - TestValidationControl outerVC = new TestValidationControl(); - page.Controls.Add(outerVC); - - inBetweenControl1.ValidationErrors.AddError("provider", new ErrorMessage("msg")); - - Assert.AreSame(inBetweenControl1, innerVC.TheValidationContainer); - Assert.AreSame(page, outerVC.TheValidationContainer); - Assert.AreEqual(1, innerVC.TheValidationContainer.ValidationErrors.GetErrors("provider").Count); - Assert.AreEqual(0, outerVC.TheValidationContainer.ValidationErrors.GetErrors("provider").Count); - } - - [Test] - public void CanReadErrorsFromCrossValidationContainerByDefault() - { - // containment tree: - // - // Page : IValidationContainer - // - outerVC - // - inBetweenControl1 : IValidationContainer - // - innerVC - - Spring.Web.UI.Page page = new Spring.Web.UI.Page(); - Spring.Web.UI.UserControl userControl = new Spring.Web.UI.UserControl(); - userControl.ID = "userControl"; - TestValidationControl innerVC = new TestValidationControl(); - userControl.Controls.Add(innerVC); - page.Controls.Add(userControl); - TestValidationControl outerVC = new TestValidationControl(); - page.Controls.Add(outerVC); - - userControl.ValidationErrors.AddError("provider", new ErrorMessage("msg")); - - Assert.AreSame(userControl, innerVC.TheValidationContainer); - Assert.AreSame(page, outerVC.TheValidationContainer); - Assert.AreEqual(1, innerVC.TheValidationContainer.ValidationErrors.GetErrors("provider").Count); - Assert.AreEqual(0, outerVC.TheValidationContainer.ValidationErrors.GetErrors("provider").Count); - - // test local-relative name resolution - outerVC.ValidationContainerName = "userControl"; - Assert.AreEqual(1, outerVC.TheValidationContainer.ValidationErrors.GetErrors("provider").Count); - - // test global name resolution - outerVC.ValidationContainerName = "::userControl"; - Assert.AreEqual(1, outerVC.TheValidationContainer.ValidationErrors.GetErrors("provider").Count); - } - - #region TestValidationControl - - private class TestValidationControl : AbstractValidationControl - { - public class CapturingRenderer : IValidationErrorsRenderer - { - public IList LastErrorsRendered; - private readonly IValidationErrorsRenderer _inner; - - public CapturingRenderer(IValidationErrorsRenderer inner) - { - _inner = inner; - } - - public void RenderErrors(Page page, HtmlTextWriter writer, IList errors) - { - LastErrorsRendered = errors; - if (_inner != null) - { - _inner.RenderErrors(page, writer, errors); - } - } - } - - private readonly IValidationErrorsRenderer _ver; - - public TestValidationControl() - : this(new CapturingRenderer(null)) - { } - - public TestValidationControl(IValidationErrorsRenderer renderer) - { - _ver =renderer; - } - - public void TestRender(HtmlTextWriter writer) - { - base.Render(writer); - } - - protected override IValidationErrorsRenderer CreateValidationErrorsRenderer() - { - return _ver; - } - - public IList LastErrorsRendered - { - get { return ((CapturingRenderer)_ver).LastErrorsRendered; } - } - - public IMessageSource TheMessageSource - { - get { return base.ResolveMessageSource(); } - } - - public IValidationContainer TheValidationContainer - { - get { return base.FindValidationContainer(); } - } - - public bool TheDesignMode - { - get { return base.DesignMode; } - } - } - - #endregion + Assert.AreEqual("TestProvider", vc.Provider); } + + [Test] + public void ResolvesAndRendersValidationErrorsUsingValidationContainer() + { + TestValidationControl vc = new TestValidationControl(); + vc.ID = "TestControl"; + + Page page = new Page(); + page.Controls.Add(vc); + page.ValidationErrors.AddError(vc.Provider, new ErrorMessage("msgId")); + StaticMessageSource msgSrc = new StaticMessageSource(); + msgSrc.AddMessage("msgId", CultureInfo.CurrentUICulture, "Resolved Message Text"); + page.MessageSource = msgSrc; + + vc.TestRender(null); + Assert.AreEqual("Resolved Message Text", vc.LastErrorsRendered[0]); + } + + [Test] + public void ResolvesAndRendersValidationErrorsUsingExplicitlySpecifiedErrorsAndMessageSource() + { + TestValidationControl vc = new TestValidationControl(); + vc.ID = "TestControl"; + + Page page = new Page(); + page.Controls.Add(vc); + + ValidationErrors errors = new ValidationErrors(); + errors.AddError(vc.Provider, new ErrorMessage("msgId")); + vc.ValidationErrors = errors; + + StaticMessageSource msgSrc = new StaticMessageSource(); + msgSrc.AddMessage("msgId", CultureInfo.CurrentUICulture, "Resolved Message Text"); + vc.MessageSource = msgSrc; + + vc.TestRender(null); + Assert.AreEqual("Resolved Message Text", vc.LastErrorsRendered[0]); + } + + [Test] + public void ThrowsIfCreateValidationErrorsRendererReturnsNull() + { + TestValidationControl vc = new TestValidationControl(null); + vc.ID = "TestControl"; + + Page page = new Page(); + page.Controls.Add(vc); + page.ValidationErrors.AddError(vc.Provider, new ErrorMessage("msgId")); + + try + { + vc.TestRender(null); + Assert.Fail(); + } + catch (ArgumentNullException ane) + { + Assert.AreEqual("Renderer", ane.ParamName); + } + } + + [Test] + public void NoExceptionWhenNoValidationContainer() + { + TestValidationControl vc = new TestValidationControl(); + Assert.IsFalse(vc.TheDesignMode); + Assert.IsNull(vc.TheMessageSource); + Assert.IsNull(vc.TheValidationContainer); + + vc.TestRender(null); + } + + [Test] + public void NoExceptionWhenNoErrors() + { + Page page = new Page(); + page.MessageSource = new StaticMessageSource(); + TestValidationControl vc = new TestValidationControl(); + page.Controls.Add(vc); + + // assert assumptions + Assert.IsFalse(vc.TheDesignMode); + Assert.AreSame(page, vc.TheValidationContainer); + Assert.AreSame(page.MessageSource, vc.TheMessageSource); + Assert.AreEqual(0, page.ValidationErrors.GetResolvedErrors(vc.Provider, vc.TheMessageSource).Count); + + vc.TestRender(null); + } + + [Test] + public void ResolveValidationContainerToEnclosingParentRecursively() + { + // direct containment + UserControl uc = new UserControl(); + TestValidationControl vc = new TestValidationControl(); + uc.Controls.Add(vc); + Assert.AreSame(uc, vc.TheValidationContainer); + + // indirect containment + uc = new UserControl(); + vc = new TestValidationControl(); + Control inBetweenControl = new Panel(); + inBetweenControl.Controls.Add(vc); + uc.Controls.Add(inBetweenControl); + Assert.AreSame(uc, vc.TheValidationContainer); + } + + [Test] + public void ResolveValidationContainerToEnclosingPageRecursively() + { + // direct containment + Page page = new Page(); + TestValidationControl vc = new TestValidationControl(); + page.Controls.Add(vc); + Assert.AreSame(page, vc.TheValidationContainer); + + // indirect containment + page = new Page(); + vc = new TestValidationControl(); + Control inBetweenControl = new System.Web.UI.WebControls.Panel(); + inBetweenControl.Controls.Add(vc); + page.Controls.Add(inBetweenControl); + Assert.AreSame(page, vc.TheValidationContainer); + } + + [Test] + public void DefaultsToValidationContainerMessageSource() + { + IMessageSource messageSource = A.Fake(); + // IValidationContainer container = (IValidationContainer)mocks.DynamicMock(typeof(IValidationContainer)); + + Page page = new Page(); + page.MessageSource = messageSource; + TestValidationControl ctl = new TestValidationControl(); + page.Controls.Add(ctl); + + Assert.AreEqual(messageSource, ctl.TheMessageSource); + } + + [Test] + public void ReadsErrorsFromClosestValidationContainerByDefault() + { + // indirect containment + Spring.Web.UI.Page page = new Spring.Web.UI.Page(); + TestValidationControl vc = new TestValidationControl(); + Spring.Web.UI.UserControl inBetweenControl = new Spring.Web.UI.UserControl(); + inBetweenControl.Controls.Add(vc); + page.Controls.Add(inBetweenControl); + Assert.AreSame(inBetweenControl, vc.TheValidationContainer); + } + + [Test] + public void DoesNotReadErrorsFromCrossValidationContainerByDefault() + { + // containment tree: + // + // Page : IValidationContainer + // - outerVC + // - inBetweenControl1 : IValidationContainer + // - innerVC + + Spring.Web.UI.Page page = new Spring.Web.UI.Page(); + Spring.Web.UI.UserControl inBetweenControl1 = new Spring.Web.UI.UserControl(); + inBetweenControl1.ID = "InBetweenControl1"; + TestValidationControl innerVC = new TestValidationControl(); + inBetweenControl1.Controls.Add(innerVC); + page.Controls.Add(inBetweenControl1); + TestValidationControl outerVC = new TestValidationControl(); + page.Controls.Add(outerVC); + + inBetweenControl1.ValidationErrors.AddError("provider", new ErrorMessage("msg")); + + Assert.AreSame(inBetweenControl1, innerVC.TheValidationContainer); + Assert.AreSame(page, outerVC.TheValidationContainer); + Assert.AreEqual(1, innerVC.TheValidationContainer.ValidationErrors.GetErrors("provider").Count); + Assert.AreEqual(0, outerVC.TheValidationContainer.ValidationErrors.GetErrors("provider").Count); + } + + [Test] + public void CanReadErrorsFromCrossValidationContainerByDefault() + { + // containment tree: + // + // Page : IValidationContainer + // - outerVC + // - inBetweenControl1 : IValidationContainer + // - innerVC + + Spring.Web.UI.Page page = new Spring.Web.UI.Page(); + Spring.Web.UI.UserControl userControl = new Spring.Web.UI.UserControl(); + userControl.ID = "userControl"; + TestValidationControl innerVC = new TestValidationControl(); + userControl.Controls.Add(innerVC); + page.Controls.Add(userControl); + TestValidationControl outerVC = new TestValidationControl(); + page.Controls.Add(outerVC); + + userControl.ValidationErrors.AddError("provider", new ErrorMessage("msg")); + + Assert.AreSame(userControl, innerVC.TheValidationContainer); + Assert.AreSame(page, outerVC.TheValidationContainer); + Assert.AreEqual(1, innerVC.TheValidationContainer.ValidationErrors.GetErrors("provider").Count); + Assert.AreEqual(0, outerVC.TheValidationContainer.ValidationErrors.GetErrors("provider").Count); + + // test local-relative name resolution + outerVC.ValidationContainerName = "userControl"; + Assert.AreEqual(1, outerVC.TheValidationContainer.ValidationErrors.GetErrors("provider").Count); + + // test global name resolution + outerVC.ValidationContainerName = "::userControl"; + Assert.AreEqual(1, outerVC.TheValidationContainer.ValidationErrors.GetErrors("provider").Count); + } + + #region TestValidationControl + + private class TestValidationControl : AbstractValidationControl + { + public class CapturingRenderer : IValidationErrorsRenderer + { + public IList LastErrorsRendered; + private readonly IValidationErrorsRenderer _inner; + + public CapturingRenderer(IValidationErrorsRenderer inner) + { + _inner = inner; + } + + public void RenderErrors(Page page, HtmlTextWriter writer, IList errors) + { + LastErrorsRendered = errors; + if (_inner != null) + { + _inner.RenderErrors(page, writer, errors); + } + } + } + + private readonly IValidationErrorsRenderer _ver; + + public TestValidationControl() + : this(new CapturingRenderer(null)) + { + } + + public TestValidationControl(IValidationErrorsRenderer renderer) + { + _ver = renderer; + } + + public void TestRender(HtmlTextWriter writer) + { + base.Render(writer); + } + + protected override IValidationErrorsRenderer CreateValidationErrorsRenderer() + { + return _ver; + } + + public IList LastErrorsRendered + { + get { return ((CapturingRenderer) _ver).LastErrorsRendered; } + } + + public IMessageSource TheMessageSource + { + get { return base.ResolveMessageSource(); } + } + + public IValidationContainer TheValidationContainer + { + get { return base.FindValidationContainer(); } + } + + public bool TheDesignMode + { + get { return base.DesignMode; } + } + } + + #endregion } diff --git a/test/Spring/Spring.Web.Tests/Web/UI/Controls/HeadTests.cs b/test/Spring/Spring.Web.Tests/Web/UI/Controls/HeadTests.cs index 2544bd4d..21d2eed5 100644 --- a/test/Spring/Spring.Web.Tests/Web/UI/Controls/HeadTests.cs +++ b/test/Spring/Spring.Web.Tests/Web/UI/Controls/HeadTests.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -28,132 +28,131 @@ using Spring.TestSupport; #endregion -namespace Spring.Web.UI.Controls +namespace Spring.Web.UI.Controls; + +/// +/// Tests behaviour of the <Head> server control +/// +/// Erich Eichinger +[TestFixture] +public class HeadTests { - /// - /// Tests behaviour of the <Head> server control - /// - /// Erich Eichinger - [TestFixture] - public class HeadTests + private const string CRLF = "\r\n"; + + [Test] + public void DontRenderHeadTagIfNestedWithinStandardHeadControl() { - private const string CRLF = "\r\n"; - - [Test] - public void DontRenderHeadTagIfNestedWithinStandardHeadControl() + using (new TestWebContext("/", "testpage.aspx")) { - using (new TestWebContext("/", "testpage.aspx")) - { - TestPage page = new TestPage(HttpContext.Current); - HtmlHead htmlHead = new HtmlHead(); - Head head = new Head(); - head.Controls.Add(new LiteralControl("literal child")); - htmlHead.Controls.Add(head); - page.Controls.Add(htmlHead); - - // initialize page to force head control initialization - page.InitRecursive(null); - string result = page.Render(string.Empty); - string expect = @"literal child"; - Assert.AreEqual(expect, result); - } - } - - [Test] - public void StyleBlockRendersTypeAttribute() - { - TestPage page = new TestPage(); + TestPage page = new TestPage(HttpContext.Current); + HtmlHead htmlHead = new HtmlHead(); Head head = new Head(); - page.Controls.Add(head); - - page.Styles.Add("stylename", "stylevalue"); - - string result = page.Render(string.Empty); - string expect = @""; - Assert.AreEqual(expect, result); - } - - [Test] - public void StyleFileRendersTypeAttributeAndUsesCssRootPath() - { - const string STYLESHEETPATH = "filepath"; - - using (new TestWebContext("/", "testpage.aspx")) - { - TestPage page = new TestPage(HttpContext.Current); - Head head = new Head(); - page.Controls.Add(head); - - page.CssRoot = "testcssroot"; - page.StyleFiles.Add("filename", STYLESHEETPATH); - - string result = page.Render(string.Empty); - string expect = string.Format(@"", STYLESHEETPATH); - Assert.AreEqual(expect, result); - } - } - - [Test] - public void ScriptBlockRendersTypeAttribute() - { - TestPage page = new TestPage(); - Head head = new Head(); - page.Controls.Add(head); - - page.RegisterHeadScriptBlock( "scriptname", "scriptcode" ); - - string result = page.Render(string.Empty); - string expect = @""; - Assert.AreEqual(expect, result); - } - - [Test] - public void ScriptEventRendersTypeAttribute() - { - TestPage page = new TestPage(); - Head head = new Head(); - page.Controls.Add(head); - - page.RegisterHeadScriptEvent("scriptname", "elementname", "eventname", "scriptcode"); - - string result = page.Render(string.Empty); - string expect = @""; - Assert.AreEqual(expect, result); - } - - [Test] - public void ScriptFileRendersTypeAttributeAndUsesScriptsRootPath() - { - const string SCRIPTFILEPATH = "filepath"; - - using (new TestWebContext("/", "testpage.aspx")) - { - TestPage page = new TestPage(HttpContext.Current); - Head head = new Head(); - page.Controls.Add(head); - - page.ScriptsRoot = "testscriptroot"; - page.RegisterHeadScriptFile("filename", SCRIPTFILEPATH); - - string result = page.Render(string.Empty); - string expect = string.Format(@"", SCRIPTFILEPATH); - Assert.AreEqual(expect, result); - } - } - - [Test] - public void RenderChildrenFirst() - { - TestPage page = new TestPage(); - Head head = new Head(); - page.Controls.Add(head); - head.Controls.Add(new LiteralControl("literal child")); - page.Styles.Add("stylename", "stylevalue"); + htmlHead.Controls.Add(head); + page.Controls.Add(htmlHead); + // initialize page to force head control initialization + page.InitRecursive(null); string result = page.Render(string.Empty); - string expect = @"literal child"; - Assert.AreEqual( expect, result); + string expect = @"literal child"; + Assert.AreEqual(expect, result); } } + + [Test] + public void StyleBlockRendersTypeAttribute() + { + TestPage page = new TestPage(); + Head head = new Head(); + page.Controls.Add(head); + + page.Styles.Add("stylename", "stylevalue"); + + string result = page.Render(string.Empty); + string expect = @""; + Assert.AreEqual(expect, result); + } + + [Test] + public void StyleFileRendersTypeAttributeAndUsesCssRootPath() + { + const string STYLESHEETPATH = "filepath"; + + using (new TestWebContext("/", "testpage.aspx")) + { + TestPage page = new TestPage(HttpContext.Current); + Head head = new Head(); + page.Controls.Add(head); + + page.CssRoot = "testcssroot"; + page.StyleFiles.Add("filename", STYLESHEETPATH); + + string result = page.Render(string.Empty); + string expect = string.Format(@"", STYLESHEETPATH); + Assert.AreEqual(expect, result); + } + } + + [Test] + public void ScriptBlockRendersTypeAttribute() + { + TestPage page = new TestPage(); + Head head = new Head(); + page.Controls.Add(head); + + page.RegisterHeadScriptBlock("scriptname", "scriptcode"); + + string result = page.Render(string.Empty); + string expect = @""; + Assert.AreEqual(expect, result); + } + + [Test] + public void ScriptEventRendersTypeAttribute() + { + TestPage page = new TestPage(); + Head head = new Head(); + page.Controls.Add(head); + + page.RegisterHeadScriptEvent("scriptname", "elementname", "eventname", "scriptcode"); + + string result = page.Render(string.Empty); + string expect = @""; + Assert.AreEqual(expect, result); + } + + [Test] + public void ScriptFileRendersTypeAttributeAndUsesScriptsRootPath() + { + const string SCRIPTFILEPATH = "filepath"; + + using (new TestWebContext("/", "testpage.aspx")) + { + TestPage page = new TestPage(HttpContext.Current); + Head head = new Head(); + page.Controls.Add(head); + + page.ScriptsRoot = "testscriptroot"; + page.RegisterHeadScriptFile("filename", SCRIPTFILEPATH); + + string result = page.Render(string.Empty); + string expect = string.Format(@"", SCRIPTFILEPATH); + Assert.AreEqual(expect, result); + } + } + + [Test] + public void RenderChildrenFirst() + { + TestPage page = new TestPage(); + Head head = new Head(); + page.Controls.Add(head); + + head.Controls.Add(new LiteralControl("literal child")); + page.Styles.Add("stylename", "stylevalue"); + + string result = page.Render(string.Empty); + string expect = @"literal child"; + Assert.AreEqual(expect, result); + } } \ No newline at end of file diff --git a/test/Spring/Spring.Web.Tests/Web/UI/Controls/ValidationErrorsTests.cs b/test/Spring/Spring.Web.Tests/Web/UI/Controls/ValidationErrorsTests.cs index 82433bd9..39d6ffe5 100644 --- a/test/Spring/Spring.Web.Tests/Web/UI/Controls/ValidationErrorsTests.cs +++ b/test/Spring/Spring.Web.Tests/Web/UI/Controls/ValidationErrorsTests.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -25,20 +25,19 @@ using Spring.Web.UI.Validation; #endregion -namespace Spring.Web.UI.Controls +namespace Spring.Web.UI.Controls; + +/// +/// +/// +/// Erich Eichinger +[TestFixture] +public class ValidationErrorsTests { - /// - /// - /// - /// Erich Eichinger - [TestFixture] - public class ValidationErrorsTests + [Test] + public void DefaultsToSpanValidationErrorsRenderer() { - [Test] - public void DefaultsToSpanValidationErrorsRenderer() - { - ValidationError vs = new ValidationError(); - Assert.AreEqual(typeof(SpanValidationErrorsRenderer), vs.Renderer.GetType()); - } + ValidationError vs = new ValidationError(); + Assert.AreEqual(typeof(SpanValidationErrorsRenderer), vs.Renderer.GetType()); } } \ No newline at end of file diff --git a/test/Spring/Spring.Web.Tests/Web/UI/Controls/ValidationSummaryTests.cs b/test/Spring/Spring.Web.Tests/Web/UI/Controls/ValidationSummaryTests.cs index 291aa93d..6dedc005 100644 --- a/test/Spring/Spring.Web.Tests/Web/UI/Controls/ValidationSummaryTests.cs +++ b/test/Spring/Spring.Web.Tests/Web/UI/Controls/ValidationSummaryTests.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -25,20 +25,19 @@ using Spring.Web.UI.Validation; #endregion -namespace Spring.Web.UI.Controls +namespace Spring.Web.UI.Controls; + +/// +/// +/// +/// Erich Eichinger +[TestFixture] +public class ValidationSummaryTests { - /// - /// - /// - /// Erich Eichinger - [TestFixture] - public class ValidationSummaryTests + [Test] + public void DefaultsToDivValidationErrorsRenderer() { - [Test] - public void DefaultsToDivValidationErrorsRenderer() - { - ValidationSummary vs = new ValidationSummary(); - Assert.AreEqual(typeof (DivValidationErrorsRenderer), vs.Renderer.GetType()); - } + ValidationSummary vs = new ValidationSummary(); + Assert.AreEqual(typeof(DivValidationErrorsRenderer), vs.Renderer.GetType()); } } \ No newline at end of file diff --git a/test/Spring/Spring.Web.Tests/Web/UI/PageTests.cs b/test/Spring/Spring.Web.Tests/Web/UI/PageTests.cs index e9ea1959..d5cdcf60 100644 --- a/test/Spring/Spring.Web.Tests/Web/UI/PageTests.cs +++ b/test/Spring/Spring.Web.Tests/Web/UI/PageTests.cs @@ -20,156 +20,152 @@ using System.Globalization; using System.Web; - using FakeItEasy; - using NUnit.Framework; - using Spring.Globalization.Resolvers; using Spring.Objects; using Spring.TestSupport; using Spring.Validation; using Spring.Web.Support; -namespace Spring.Web.UI +namespace Spring.Web.UI; + +/// +/// Unit tests for the Page class. +/// +/// Goran Milosavljevic +/// Erich Eichinger +[TestFixture] +public class PageTests : TestWebContextTests { - /// - /// Unit tests for the Page class. - /// - /// Goran Milosavljevic - /// Erich Eichinger - [TestFixture] - public class PageTests : TestWebContextTests + class MockValidator : System.Web.UI.WebControls.BaseValidator { - class MockValidator : System.Web.UI.WebControls.BaseValidator + public bool WasCalled = false; + + protected override bool ControlPropertiesValid() { - public bool WasCalled = false; - - protected override bool ControlPropertiesValid() - { - return true; - } - - protected override bool EvaluateIsValid() - { - WasCalled = true; - return true; - } + return true; } - [Test] - public void NoSharedStateAtConstruction() + protected override bool EvaluateIsValid() { - Page page = new Page(); - Assert.IsNull(page.SharedState); - } - - [Test] - public void CallsBaseValidateMethod() - { - Page child; - MockValidator mockValidator; - - child = new Page(); - mockValidator = new MockValidator(); - mockValidator.ValidationGroup = "theValidationGroup"; - child.Validators.Add( mockValidator ); - - child.Validate(mockValidator.ValidationGroup); - Assert.IsTrue(mockValidator.WasCalled); - - child = new Page(); - mockValidator = new MockValidator(); - child.Validators.Add( mockValidator ); - - child.Validate(); - Assert.IsTrue(mockValidator.WasCalled); - } - - [Test] - public void Validate() - { - Page page = new TestPage(HttpContext.Current); - IValidator[] validators = new IValidator[] {new RequiredValidator("Name", null), new ConditionValidator("Loan == 0", "Age > 21")}; - Contact contact = new Contact("Goran", 24, 0); - bool result = page.Validate(contact, validators); - Assert.IsTrue(result); - - contact = new Contact(null, 24, 0); - result = page.Validate(contact, validators); - Assert.IsFalse(result); - - contact = new Contact("Goran", 24, 1); - result = page.Validate(contact, validators); - Assert.IsFalse(result); - } - - [Test] - public void DefaultsToDefaultWebCultureResolver() - { - TestPage page = new TestPage(); - Assert.AreEqual( typeof(DefaultWebCultureResolver), page.CultureResolver.GetType() ); - } - - [Test] - public void AllowsNeutralUserCulture() - { - TestPage page = new TestPage(); - // DefaultWebCultureResolver does not allow culture to be set - page.CultureResolver = new DefaultCultureResolver(); - page.UserCulture = new CultureInfo("de"); - - page.InitializeCulture(); - Assert.AreEqual( page.UserCulture, Thread.CurrentThread.CurrentUICulture ); - Assert.AreEqual( CultureInfo.CreateSpecificCulture(page.UserCulture.Name), Thread.CurrentThread.CurrentCulture); - } - - [Test] - public void SetResultThrowsVerboseExceptionOnUnknownResultName() - { - string RESULTNAME = "nonexistant result"; - - TestPage page = new TestPage(); - try - { - page.SetResult(RESULTNAME); - Assert.Fail(); - } - catch(ArgumentException ae) - { - string expected = string.Format("No mapping found for the specified destination '{0}'.", RESULTNAME); - string msg = ae.Message.Substring(0, expected.Length); - Assert.AreEqual(expected, msg); - } - } - - [Test] - public void SetResultSelectsCorrectResult() - { - TestPage page = new TestPage(); - - Result theResult = A.Fake(); - - page.Results.Add( "theResult", theResult ); - page.SetResult("theResult"); - - A.CallTo(() => theResult.Navigate(page)).MustHaveHappened(); - } - - [Test] - public void NoNullModelPersistenceMediumAllowed() - { - TestPage tuc = new TestPage(); - Assert.Throws(() => tuc.ModelPersistenceMedium = null); - } - - [Test] - public void StoresAndLoadsModelUsingModelPersistenceMedium() - { - TestPage tuc = new TestPage(); - tuc.ModelPersistenceMedium = new DictionaryModelPersistenceMedium(); - tuc.SaveModelToPersistenceMedium( this ); - Assert.AreEqual(this, tuc.LoadModelFromPersistenceMedium()); + WasCalled = true; + return true; } } + + [Test] + public void NoSharedStateAtConstruction() + { + Page page = new Page(); + Assert.IsNull(page.SharedState); + } + + [Test] + public void CallsBaseValidateMethod() + { + Page child; + MockValidator mockValidator; + + child = new Page(); + mockValidator = new MockValidator(); + mockValidator.ValidationGroup = "theValidationGroup"; + child.Validators.Add(mockValidator); + + child.Validate(mockValidator.ValidationGroup); + Assert.IsTrue(mockValidator.WasCalled); + + child = new Page(); + mockValidator = new MockValidator(); + child.Validators.Add(mockValidator); + + child.Validate(); + Assert.IsTrue(mockValidator.WasCalled); + } + + [Test] + public void Validate() + { + Page page = new TestPage(HttpContext.Current); + IValidator[] validators = new IValidator[] { new RequiredValidator("Name", null), new ConditionValidator("Loan == 0", "Age > 21") }; + Contact contact = new Contact("Goran", 24, 0); + bool result = page.Validate(contact, validators); + Assert.IsTrue(result); + + contact = new Contact(null, 24, 0); + result = page.Validate(contact, validators); + Assert.IsFalse(result); + + contact = new Contact("Goran", 24, 1); + result = page.Validate(contact, validators); + Assert.IsFalse(result); + } + + [Test] + public void DefaultsToDefaultWebCultureResolver() + { + TestPage page = new TestPage(); + Assert.AreEqual(typeof(DefaultWebCultureResolver), page.CultureResolver.GetType()); + } + + [Test] + public void AllowsNeutralUserCulture() + { + TestPage page = new TestPage(); + // DefaultWebCultureResolver does not allow culture to be set + page.CultureResolver = new DefaultCultureResolver(); + page.UserCulture = new CultureInfo("de"); + + page.InitializeCulture(); + Assert.AreEqual(page.UserCulture, Thread.CurrentThread.CurrentUICulture); + Assert.AreEqual(CultureInfo.CreateSpecificCulture(page.UserCulture.Name), Thread.CurrentThread.CurrentCulture); + } + + [Test] + public void SetResultThrowsVerboseExceptionOnUnknownResultName() + { + string RESULTNAME = "nonexistant result"; + + TestPage page = new TestPage(); + try + { + page.SetResult(RESULTNAME); + Assert.Fail(); + } + catch (ArgumentException ae) + { + string expected = string.Format("No mapping found for the specified destination '{0}'.", RESULTNAME); + string msg = ae.Message.Substring(0, expected.Length); + Assert.AreEqual(expected, msg); + } + } + + [Test] + public void SetResultSelectsCorrectResult() + { + TestPage page = new TestPage(); + + Result theResult = A.Fake(); + + page.Results.Add("theResult", theResult); + page.SetResult("theResult"); + + A.CallTo(() => theResult.Navigate(page)).MustHaveHappened(); + } + + [Test] + public void NoNullModelPersistenceMediumAllowed() + { + TestPage tuc = new TestPage(); + Assert.Throws(() => tuc.ModelPersistenceMedium = null); + } + + [Test] + public void StoresAndLoadsModelUsingModelPersistenceMedium() + { + TestPage tuc = new TestPage(); + tuc.ModelPersistenceMedium = new DictionaryModelPersistenceMedium(); + tuc.SaveModelToPersistenceMedium(this); + Assert.AreEqual(this, tuc.LoadModelFromPersistenceMedium()); + } } diff --git a/test/Spring/Spring.Web.Tests/Web/UI/SessionModelPersistenceMediumTests.cs b/test/Spring/Spring.Web.Tests/Web/UI/SessionModelPersistenceMediumTests.cs index a38ec8f4..dbbbce6d 100644 --- a/test/Spring/Spring.Web.Tests/Web/UI/SessionModelPersistenceMediumTests.cs +++ b/test/Spring/Spring.Web.Tests/Web/UI/SessionModelPersistenceMediumTests.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright � 2002-2011 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. @@ -28,54 +28,53 @@ using Spring.TestSupport; #endregion -namespace Spring.Web.UI +namespace Spring.Web.UI; + +/// +/// +/// +/// Erich Eichinger +[TestFixture] +public class SessionModelPersistenceMediumTests { - /// - /// - /// - /// Erich Eichinger - [TestFixture] - public class SessionModelPersistenceMediumTests + private class TestSessionModelPersistenceMedium : SessionModelPersistenceMedium { - private class TestSessionModelPersistenceMedium : SessionModelPersistenceMedium + private Hashtable _sessionItems = new CaseInsensitiveHashtable(); + + public Hashtable SessionItems { - private Hashtable _sessionItems = new CaseInsensitiveHashtable(); - - public Hashtable SessionItems - { - get { return _sessionItems; } - } - - protected override object GetItem( System.Web.UI.Control context, string key ) - { - //return base.GetItem( context, key ); - return _sessionItems[key]; - } - - protected override void SetItem( System.Web.UI.Control context, string key, object item ) - { - //base.SetItem( context, key, item ); - _sessionItems[key] = item; - } - - protected override string GetKey( Control context ) - { - //return base.GetKey( context ); - return context.ID; - } + get { return _sessionItems; } } - [Test] - public void StoresAndRetrievesModelItem() + protected override object GetItem(System.Web.UI.Control context, string key) { - TestSessionModelPersistenceMedium pm = new TestSessionModelPersistenceMedium(); - Control tuc = new TestUserControl("TucID"); - pm.SaveToMedium( tuc, this ); - // ensure key was generated by GetKey() and Item was added to storage - Assert.AreEqual( this, pm.SessionItems["TucID"] ); + //return base.GetItem( context, key ); + return _sessionItems[key]; + } - // ensure key was generated by GetKey() and Item is retrieved from storage - Assert.AreEqual( this, pm.LoadFromMedium( tuc ) ); + protected override void SetItem(System.Web.UI.Control context, string key, object item) + { + //base.SetItem( context, key, item ); + _sessionItems[key] = item; + } + + protected override string GetKey(Control context) + { + //return base.GetKey( context ); + return context.ID; } } -} \ No newline at end of file + + [Test] + public void StoresAndRetrievesModelItem() + { + TestSessionModelPersistenceMedium pm = new TestSessionModelPersistenceMedium(); + Control tuc = new TestUserControl("TucID"); + pm.SaveToMedium(tuc, this); + // ensure key was generated by GetKey() and Item was added to storage + Assert.AreEqual(this, pm.SessionItems["TucID"]); + + // ensure key was generated by GetKey() and Item is retrieved from storage + Assert.AreEqual(this, pm.LoadFromMedium(tuc)); + } +} diff --git a/test/Spring/Spring.Web.Tests/Web/UI/UserControlTests.cs b/test/Spring/Spring.Web.Tests/Web/UI/UserControlTests.cs index 2c41c8ed..1e243c76 100644 --- a/test/Spring/Spring.Web.Tests/Web/UI/UserControlTests.cs +++ b/test/Spring/Spring.Web.Tests/Web/UI/UserControlTests.cs @@ -20,78 +20,73 @@ using System.Web; using System.Web.UI; - using FakeItEasy; - using NUnit.Framework; - using Spring.TestSupport; using Spring.Validation; using Spring.Web.Support; -namespace Spring.Web.UI +namespace Spring.Web.UI; + +/// +/// +/// +/// Erich Eichinger +[TestFixture] +public class UserControlTests : TestWebContextTests { - /// - /// - /// - /// Erich Eichinger - [TestFixture] - public class UserControlTests : TestWebContextTests + [Test] + public void SetResultSelectsCorrectResult() { - [Test] - public void SetResultSelectsCorrectResult() - { - TestUserControl uc = new TestUserControl(); - Result theResult = A.Fake(); + TestUserControl uc = new TestUserControl(); + Result theResult = A.Fake(); - uc.Results.Add("theResult", theResult); - uc.SetResult("theResult"); + uc.Results.Add("theResult", theResult); + uc.SetResult("theResult"); + } - } + [Test] + public void SetResultBubblesUpHierarchyUntilFirstMatch() + { + TestUserControl c1 = new TestUserControl(); + Control c11 = new Control(); + c1.Controls.Add(c11); + TestUserControl c111 = new TestUserControl(c11); + Result theResult = A.Fake(); - [Test] - public void SetResultBubblesUpHierarchyUntilFirstMatch() - { - TestUserControl c1 = new TestUserControl(); - Control c11 = new Control(); - c1.Controls.Add(c11); - TestUserControl c111 = new TestUserControl(c11); - Result theResult = A.Fake(); + c1.Results.Add("theResult", theResult); + c111.SetResult("theResult"); - c1.Results.Add("theResult", theResult); - c111.SetResult("theResult"); + // context is the control, that contains matching Result + A.CallTo(() => theResult.Navigate(c1)).MustHaveHappened(); + } - // context is the control, that contains matching Result - A.CallTo(() => theResult.Navigate(c1)).MustHaveHappened(); - } + [Test] + public void ValidateSetsDefaultVariables() + { + TestPage page = new TestPage(HttpContext.Current); + TestUserControl c1 = new TestUserControl(); + page.Controls.Add(c1); - [Test] - public void ValidateSetsDefaultVariables() - { - TestPage page = new TestPage(HttpContext.Current); - TestUserControl c1 = new TestUserControl(); - page.Controls.Add(c1); + ConditionValidator v1 = new ConditionValidator("#page == #this.Page", null); + ConditionValidator v2 = new ConditionValidator("#usercontrol == #this", null); - ConditionValidator v1 = new ConditionValidator("#page == #this.Page", null); - ConditionValidator v2 = new ConditionValidator("#usercontrol == #this", null); + Assert.IsTrue(c1.Validate(c1, v1, v2)); + } - Assert.IsTrue(c1.Validate(c1, v1, v2)); - } + [Test] + public void NoNullModelPersistenceMediumAllowed() + { + TestUserControl tuc = new TestUserControl(); + Assert.Throws(() => tuc.ModelPersistenceMedium = null); + } - [Test] - public void NoNullModelPersistenceMediumAllowed() - { - TestUserControl tuc = new TestUserControl(); - Assert.Throws(() => tuc.ModelPersistenceMedium = null); - } - - [Test] - public void StoresAndLoadsModelUsingModelPersistenceMedium() - { - TestUserControl tuc = new TestUserControl(); - tuc.ModelPersistenceMedium = new DictionaryModelPersistenceMedium(); - tuc.SaveModelToPersistenceMedium(this); - Assert.AreEqual(this, tuc.LoadModelFromPersistenceMedium()); - } + [Test] + public void StoresAndLoadsModelUsingModelPersistenceMedium() + { + TestUserControl tuc = new TestUserControl(); + tuc.ModelPersistenceMedium = new DictionaryModelPersistenceMedium(); + tuc.SaveModelToPersistenceMedium(this); + Assert.AreEqual(this, tuc.LoadModelFromPersistenceMedium()); } } diff --git a/test/Spring/Spring.Web.Tests/WebCompilerOptionsTests.cs b/test/Spring/Spring.Web.Tests/WebCompilerOptionsTests.cs index bc901f5b..d74e5eac 100644 --- a/test/Spring/Spring.Web.Tests/WebCompilerOptionsTests.cs +++ b/test/Spring/Spring.Web.Tests/WebCompilerOptionsTests.cs @@ -26,18 +26,17 @@ using Spring.Context.Support; #endregion -namespace Spring +namespace Spring; + +/// Test that the assembly is built with the correct DebugAttributes in release and debug builds. +/// +/// Mark Pollack +[TestFixture] +public sealed class WebCompilerOptionTests : CompilerOptionsTests { - /// Test that the assembly is built with the correct DebugAttributes in release and debug builds. - /// - /// Mark Pollack - [TestFixture] - public sealed class WebCompilerOptionTests : CompilerOptionsTests + [OneTimeSetUp] + public void FixtureSetUp() { - [OneTimeSetUp] - public void FixtureSetUp() - { - AssemblyToCheck = Assembly.GetAssembly(typeof (WebApplicationContext)); - } + AssemblyToCheck = Assembly.GetAssembly(typeof(WebApplicationContext)); } } \ No newline at end of file